[XFS] Fix merge failures

Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6

Conflicts:

	fs/xfs/linux-2.6/xfs_cred.h
	fs/xfs/linux-2.6/xfs_globals.h
	fs/xfs/linux-2.6/xfs_ioctl.c
	fs/xfs/xfs_vnodeops.h

Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 9b1f6ca..0a08126 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -6,7 +6,7 @@
 # To add a new book the only step required is to add the book to the
 # list of DOCBOOKS.
 
-DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml \
+DOCBOOKS := z8530book.xml mcabook.xml \
 	    kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
 	    procfs-guide.xml writing_usb_driver.xml networking.xml \
 	    kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
diff --git a/Documentation/DocBook/networking.tmpl b/Documentation/DocBook/networking.tmpl
index f24f9e8..627707a 100644
--- a/Documentation/DocBook/networking.tmpl
+++ b/Documentation/DocBook/networking.tmpl
@@ -98,9 +98,6 @@
 X!Enet/core/wireless.c
      </sect1>
 -->
-     <sect1><title>Synchronous PPP</title>
-!Edrivers/net/wan/syncppp.c
-     </sect1>
   </chapter>
 
 </book>
diff --git a/Documentation/DocBook/wanbook.tmpl b/Documentation/DocBook/wanbook.tmpl
deleted file mode 100644
index 8c93db1..0000000
--- a/Documentation/DocBook/wanbook.tmpl
+++ /dev/null
@@ -1,99 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
-	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
-
-<book id="WANGuide">
- <bookinfo>
-  <title>Synchronous PPP and Cisco HDLC Programming Guide</title>
-  
-  <authorgroup>
-   <author>
-    <firstname>Alan</firstname>
-    <surname>Cox</surname>
-    <affiliation>
-     <address>
-      <email>alan@lxorguk.ukuu.org.uk</email>
-     </address>
-    </affiliation>
-   </author>
-  </authorgroup>
-
-  <copyright>
-   <year>2000</year>
-   <holder>Alan Cox</holder>
-  </copyright>
-
-  <legalnotice>
-   <para>
-     This documentation is free software; you can redistribute
-     it and/or modify it under the terms of the GNU General Public
-     License as published by the Free Software Foundation; either
-     version 2 of the License, or (at your option) any later
-     version.
-   </para>
-      
-   <para>
-     This program is distributed in the hope that it will be
-     useful, but WITHOUT ANY WARRANTY; without even the implied
-     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-     See the GNU General Public License for more details.
-   </para>
-      
-   <para>
-     You 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
-   </para>
-      
-   <para>
-     For more details see the file COPYING in the source
-     distribution of Linux.
-   </para>
-  </legalnotice>
- </bookinfo>
-
-<toc></toc>
-
-  <chapter id="intro">
-      <title>Introduction</title>
-  <para>
-	The syncppp drivers in Linux provide a fairly complete 
-	implementation of Cisco HDLC and a minimal implementation of
-	PPP. The longer term goal is to switch the PPP layer to the
-	generic PPP interface that is new in Linux 2.3.x. The API should
-	remain unchanged when this is done, but support will then be
-	available for IPX, compression and other PPP features
-  </para>
-  </chapter>
-  <chapter id="bugs">
-     <title>Known Bugs And Assumptions</title>
-  <para>
-  <variablelist>
-    <varlistentry><term>PPP is minimal</term>
-    <listitem>
-    <para>
-	The current PPP implementation is very basic, although sufficient
-	for most wan usages.
-    </para>
-    </listitem></varlistentry>
-
-    <varlistentry><term>Cisco HDLC Quirks</term>
-    <listitem>
-    <para>
-	Currently we do not end all packets with the correct Cisco multicast
-	or unicast flags. Nothing appears to mind too much but this should
-	be corrected.
-    </para>
-    </listitem></varlistentry>
-  </variablelist>
-	
-  </para>
-  </chapter>
-
-  <chapter id="pubfunctions">
-     <title>Public Functions Provided</title>
-!Edrivers/net/wan/syncppp.c
-  </chapter>
-
-</book>
diff --git a/Documentation/RCU/rculist_nulls.txt b/Documentation/RCU/rculist_nulls.txt
new file mode 100644
index 0000000..239f542
--- /dev/null
+++ b/Documentation/RCU/rculist_nulls.txt
@@ -0,0 +1,167 @@
+Using hlist_nulls to protect read-mostly linked lists and
+objects using SLAB_DESTROY_BY_RCU allocations.
+
+Please read the basics in Documentation/RCU/listRCU.txt
+
+Using special makers (called 'nulls') is a convenient way
+to solve following problem :
+
+A typical RCU linked list managing objects which are
+allocated with SLAB_DESTROY_BY_RCU kmem_cache can
+use following algos :
+
+1) Lookup algo
+--------------
+rcu_read_lock()
+begin:
+obj = lockless_lookup(key);
+if (obj) {
+  if (!try_get_ref(obj)) // might fail for free objects
+    goto begin;
+  /*
+   * Because a writer could delete object, and a writer could
+   * reuse these object before the RCU grace period, we
+   * must check key after geting the reference on object
+   */
+  if (obj->key != key) { // not the object we expected
+     put_ref(obj);
+     goto begin;
+   }
+}
+rcu_read_unlock();
+
+Beware that lockless_lookup(key) cannot use traditional hlist_for_each_entry_rcu()
+but a version with an additional memory barrier (smp_rmb())
+
+lockless_lookup(key)
+{
+   struct hlist_node *node, *next;
+   for (pos = rcu_dereference((head)->first);
+          pos && ({ next = pos->next; smp_rmb(); prefetch(next); 1; }) &&
+          ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; });
+          pos = rcu_dereference(next))
+      if (obj->key == key)
+         return obj;
+   return NULL;
+
+And note the traditional hlist_for_each_entry_rcu() misses this smp_rmb() :
+
+   struct hlist_node *node;
+   for (pos = rcu_dereference((head)->first);
+		pos && ({ prefetch(pos->next); 1; }) &&
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; });
+		pos = rcu_dereference(pos->next))
+      if (obj->key == key)
+         return obj;
+   return NULL;
+}
+
+Quoting Corey Minyard :
+
+"If the object is moved from one list to another list in-between the
+ time the hash is calculated and the next field is accessed, and the
+ object has moved to the end of a new list, the traversal will not
+ complete properly on the list it should have, since the object will
+ be on the end of the new list and there's not a way to tell it's on a
+ new list and restart the list traversal.  I think that this can be
+ solved by pre-fetching the "next" field (with proper barriers) before
+ checking the key."
+
+2) Insert algo :
+----------------
+
+We need to make sure a reader cannot read the new 'obj->obj_next' value
+and previous value of 'obj->key'. Or else, an item could be deleted
+from a chain, and inserted into another chain. If new chain was empty
+before the move, 'next' pointer is NULL, and lockless reader can
+not detect it missed following items in original chain.
+
+/*
+ * Please note that new inserts are done at the head of list,
+ * not in the middle or end.
+ */
+obj = kmem_cache_alloc(...);
+lock_chain(); // typically a spin_lock()
+obj->key = key;
+atomic_inc(&obj->refcnt);
+/*
+ * we need to make sure obj->key is updated before obj->next
+ */
+smp_wmb();
+hlist_add_head_rcu(&obj->obj_node, list);
+unlock_chain(); // typically a spin_unlock()
+
+
+3) Remove algo
+--------------
+Nothing special here, we can use a standard RCU hlist deletion.
+But thanks to SLAB_DESTROY_BY_RCU, beware a deleted object can be reused
+very very fast (before the end of RCU grace period)
+
+if (put_last_reference_on(obj) {
+   lock_chain(); // typically a spin_lock()
+   hlist_del_init_rcu(&obj->obj_node);
+   unlock_chain(); // typically a spin_unlock()
+   kmem_cache_free(cachep, obj);
+}
+
+
+
+--------------------------------------------------------------------------
+With hlist_nulls we can avoid extra smp_rmb() in lockless_lookup()
+and extra smp_wmb() in insert function.
+
+For example, if we choose to store the slot number as the 'nulls'
+end-of-list marker for each slot of the hash table, we can detect
+a race (some writer did a delete and/or a move of an object
+to another chain) checking the final 'nulls' value if
+the lookup met the end of chain. If final 'nulls' value
+is not the slot number, then we must restart the lookup at
+the begining. If the object was moved to same chain,
+then the reader doesnt care : It might eventually
+scan the list again without harm.
+
+
+1) lookup algo
+
+ head = &table[slot];
+ rcu_read_lock();
+begin:
+ hlist_nulls_for_each_entry_rcu(obj, node, head, member) {
+   if (obj->key == key) {
+      if (!try_get_ref(obj)) // might fail for free objects
+         goto begin;
+      if (obj->key != key) { // not the object we expected
+         put_ref(obj);
+         goto begin;
+      }
+  goto out;
+ }
+/*
+ * if the nulls value we got at the end of this lookup is
+ * not the expected one, we must restart lookup.
+ * We probably met an item that was moved to another chain.
+ */
+ if (get_nulls_value(node) != slot)
+   goto begin;
+ obj = NULL;
+
+out:
+ rcu_read_unlock();
+
+2) Insert function :
+--------------------
+
+/*
+ * Please note that new inserts are done at the head of list,
+ * not in the middle or end.
+ */
+obj = kmem_cache_alloc(cachep);
+lock_chain(); // typically a spin_lock()
+obj->key = key;
+atomic_set(&obj->refcnt, 1);
+/*
+ * insert obj in RCU way (readers might be traversing chain)
+ */
+hlist_nulls_add_head_rcu(&obj->obj_node, list);
+unlock_chain(); // typically a spin_unlock()
diff --git a/Documentation/controllers/cpuacct.txt b/Documentation/controllers/cpuacct.txt
new file mode 100644
index 0000000..bb775fb
--- /dev/null
+++ b/Documentation/controllers/cpuacct.txt
@@ -0,0 +1,32 @@
+CPU Accounting Controller
+-------------------------
+
+The CPU accounting controller is used to group tasks using cgroups and
+account the CPU usage of these groups of tasks.
+
+The CPU accounting controller supports multi-hierarchy groups. An accounting
+group accumulates the CPU usage of all of its child groups and the tasks
+directly present in its group.
+
+Accounting groups can be created by first mounting the cgroup filesystem.
+
+# mkdir /cgroups
+# mount -t cgroup -ocpuacct none /cgroups
+
+With the above step, the initial or the parent accounting group
+becomes visible at /cgroups. At bootup, this group includes all the
+tasks in the system. /cgroups/tasks lists the tasks in this cgroup.
+/cgroups/cpuacct.usage gives the CPU time (in nanoseconds) obtained by
+this group which is essentially the CPU time obtained by all the tasks
+in the system.
+
+New accounting groups can be created under the parent group /cgroups.
+
+# cd /cgroups
+# mkdir g1
+# echo $$ > g1
+
+The above steps create a new group g1 and move the current shell
+process (bash) into it. CPU time consumed by this bash and its children
+can be obtained from g1/cpuacct.usage and the same is accumulated in
+/cgroups/cpuacct.usage also.
diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt
index 4f3f384..e3443dd 100644
--- a/Documentation/cpu-freq/user-guide.txt
+++ b/Documentation/cpu-freq/user-guide.txt
@@ -93,10 +93,8 @@
 1.5 SuperH
 ----------
 
-The following SuperH processors are supported by cpufreq:
-
-SH-3
-SH-4
+All SuperH processors supporting rate rounding through the clock
+framework are supported by cpufreq.
 
 1.6 Blackfin
 ------------
diff --git a/Documentation/credentials.txt b/Documentation/credentials.txt
new file mode 100644
index 0000000..df03169
--- /dev/null
+++ b/Documentation/credentials.txt
@@ -0,0 +1,582 @@
+			     ====================
+			     CREDENTIALS IN LINUX
+			     ====================
+
+By: David Howells <dhowells@redhat.com>
+
+Contents:
+
+ (*) Overview.
+
+ (*) Types of credentials.
+
+ (*) File markings.
+
+ (*) Task credentials.
+
+     - Immutable credentials.
+     - Accessing task credentials.
+     - Accessing another task's credentials.
+     - Altering credentials.
+     - Managing credentials.
+
+ (*) Open file credentials.
+
+ (*) Overriding the VFS's use of credentials.
+
+
+========
+OVERVIEW
+========
+
+There are several parts to the security check performed by Linux when one
+object acts upon another:
+
+ (1) Objects.
+
+     Objects are things in the system that may be acted upon directly by
+     userspace programs.  Linux has a variety of actionable objects, including:
+
+	- Tasks
+	- Files/inodes
+	- Sockets
+	- Message queues
+	- Shared memory segments
+	- Semaphores
+	- Keys
+
+     As a part of the description of all these objects there is a set of
+     credentials.  What's in the set depends on the type of object.
+
+ (2) Object ownership.
+
+     Amongst the credentials of most objects, there will be a subset that
+     indicates the ownership of that object.  This is used for resource
+     accounting and limitation (disk quotas and task rlimits for example).
+
+     In a standard UNIX filesystem, for instance, this will be defined by the
+     UID marked on the inode.
+
+ (3) The objective context.
+
+     Also amongst the credentials of those objects, there will be a subset that
+     indicates the 'objective context' of that object.  This may or may not be
+     the same set as in (2) - in standard UNIX files, for instance, this is the
+     defined by the UID and the GID marked on the inode.
+
+     The objective context is used as part of the security calculation that is
+     carried out when an object is acted upon.
+
+ (4) Subjects.
+
+     A subject is an object that is acting upon another object.
+
+     Most of the objects in the system are inactive: they don't act on other
+     objects within the system.  Processes/tasks are the obvious exception:
+     they do stuff; they access and manipulate things.
+
+     Objects other than tasks may under some circumstances also be subjects.
+     For instance an open file may send SIGIO to a task using the UID and EUID
+     given to it by a task that called fcntl(F_SETOWN) upon it.  In this case,
+     the file struct will have a subjective context too.
+
+ (5) The subjective context.
+
+     A subject has an additional interpretation of its credentials.  A subset
+     of its credentials forms the 'subjective context'.  The subjective context
+     is used as part of the security calculation that is carried out when a
+     subject acts.
+
+     A Linux task, for example, has the FSUID, FSGID and the supplementary
+     group list for when it is acting upon a file - which are quite separate
+     from the real UID and GID that normally form the objective context of the
+     task.
+
+ (6) Actions.
+
+     Linux has a number of actions available that a subject may perform upon an
+     object.  The set of actions available depends on the nature of the subject
+     and the object.
+
+     Actions include reading, writing, creating and deleting files; forking or
+     signalling and tracing tasks.
+
+ (7) Rules, access control lists and security calculations.
+
+     When a subject acts upon an object, a security calculation is made.  This
+     involves taking the subjective context, the objective context and the
+     action, and searching one or more sets of rules to see whether the subject
+     is granted or denied permission to act in the desired manner on the
+     object, given those contexts.
+
+     There are two main sources of rules:
+
+     (a) Discretionary access control (DAC):
+
+	 Sometimes the object will include sets of rules as part of its
+	 description.  This is an 'Access Control List' or 'ACL'.  A Linux
+	 file may supply more than one ACL.
+
+	 A traditional UNIX file, for example, includes a permissions mask that
+	 is an abbreviated ACL with three fixed classes of subject ('user',
+	 'group' and 'other'), each of which may be granted certain privileges
+	 ('read', 'write' and 'execute' - whatever those map to for the object
+	 in question).  UNIX file permissions do not allow the arbitrary
+	 specification of subjects, however, and so are of limited use.
+
+	 A Linux file might also sport a POSIX ACL.  This is a list of rules
+	 that grants various permissions to arbitrary subjects.
+
+     (b) Mandatory access control (MAC):
+
+	 The system as a whole may have one or more sets of rules that get
+	 applied to all subjects and objects, regardless of their source.
+	 SELinux and Smack are examples of this.
+
+	 In the case of SELinux and Smack, each object is given a label as part
+	 of its credentials.  When an action is requested, they take the
+	 subject label, the object label and the action and look for a rule
+	 that says that this action is either granted or denied.
+
+
+====================
+TYPES OF CREDENTIALS
+====================
+
+The Linux kernel supports the following types of credentials:
+
+ (1) Traditional UNIX credentials.
+
+	Real User ID
+	Real Group ID
+
+     The UID and GID are carried by most, if not all, Linux objects, even if in
+     some cases it has to be invented (FAT or CIFS files for example, which are
+     derived from Windows).  These (mostly) define the objective context of
+     that object, with tasks being slightly different in some cases.
+
+	Effective, Saved and FS User ID
+	Effective, Saved and FS Group ID
+	Supplementary groups
+
+     These are additional credentials used by tasks only.  Usually, an
+     EUID/EGID/GROUPS will be used as the subjective context, and real UID/GID
+     will be used as the objective.  For tasks, it should be noted that this is
+     not always true.
+
+ (2) Capabilities.
+
+	Set of permitted capabilities
+	Set of inheritable capabilities
+	Set of effective capabilities
+	Capability bounding set
+
+     These are only carried by tasks.  They indicate superior capabilities
+     granted piecemeal to a task that an ordinary task wouldn't otherwise have.
+     These are manipulated implicitly by changes to the traditional UNIX
+     credentials, but can also be manipulated directly by the capset() system
+     call.
+
+     The permitted capabilities are those caps that the process might grant
+     itself to its effective or permitted sets through capset().  This
+     inheritable set might also be so constrained.
+
+     The effective capabilities are the ones that a task is actually allowed to
+     make use of itself.
+
+     The inheritable capabilities are the ones that may get passed across
+     execve().
+
+     The bounding set limits the capabilities that may be inherited across
+     execve(), especially when a binary is executed that will execute as UID 0.
+
+ (3) Secure management flags (securebits).
+
+     These are only carried by tasks.  These govern the way the above
+     credentials are manipulated and inherited over certain operations such as
+     execve().  They aren't used directly as objective or subjective
+     credentials.
+
+ (4) Keys and keyrings.
+
+     These are only carried by tasks.  They carry and cache security tokens
+     that don't fit into the other standard UNIX credentials.  They are for
+     making such things as network filesystem keys available to the file
+     accesses performed by processes, without the necessity of ordinary
+     programs having to know about security details involved.
+
+     Keyrings are a special type of key.  They carry sets of other keys and can
+     be searched for the desired key.  Each process may subscribe to a number
+     of keyrings:
+
+	Per-thread keying
+	Per-process keyring
+	Per-session keyring
+
+     When a process accesses a key, if not already present, it will normally be
+     cached on one of these keyrings for future accesses to find.
+
+     For more information on using keys, see Documentation/keys.txt.
+
+ (5) LSM
+
+     The Linux Security Module allows extra controls to be placed over the
+     operations that a task may do.  Currently Linux supports two main
+     alternate LSM options: SELinux and Smack.
+
+     Both work by labelling the objects in a system and then applying sets of
+     rules (policies) that say what operations a task with one label may do to
+     an object with another label.
+
+ (6) AF_KEY
+
+     This is a socket-based approach to credential management for networking
+     stacks [RFC 2367].  It isn't discussed by this document as it doesn't
+     interact directly with task and file credentials; rather it keeps system
+     level credentials.
+
+
+When a file is opened, part of the opening task's subjective context is
+recorded in the file struct created.  This allows operations using that file
+struct to use those credentials instead of the subjective context of the task
+that issued the operation.  An example of this would be a file opened on a
+network filesystem where the credentials of the opened file should be presented
+to the server, regardless of who is actually doing a read or a write upon it.
+
+
+=============
+FILE MARKINGS
+=============
+
+Files on disk or obtained over the network may have annotations that form the
+objective security context of that file.  Depending on the type of filesystem,
+this may include one or more of the following:
+
+ (*) UNIX UID, GID, mode;
+
+ (*) Windows user ID;
+
+ (*) Access control list;
+
+ (*) LSM security label;
+
+ (*) UNIX exec privilege escalation bits (SUID/SGID);
+
+ (*) File capabilities exec privilege escalation bits.
+
+These are compared to the task's subjective security context, and certain
+operations allowed or disallowed as a result.  In the case of execve(), the
+privilege escalation bits come into play, and may allow the resulting process
+extra privileges, based on the annotations on the executable file.
+
+
+================
+TASK CREDENTIALS
+================
+
+In Linux, all of a task's credentials are held in (uid, gid) or through
+(groups, keys, LSM security) a refcounted structure of type 'struct cred'.
+Each task points to its credentials by a pointer called 'cred' in its
+task_struct.
+
+Once a set of credentials has been prepared and committed, it may not be
+changed, barring the following exceptions:
+
+ (1) its reference count may be changed;
+
+ (2) the reference count on the group_info struct it points to may be changed;
+
+ (3) the reference count on the security data it points to may be changed;
+
+ (4) the reference count on any keyrings it points to may be changed;
+
+ (5) any keyrings it points to may be revoked, expired or have their security
+     attributes changed; and
+
+ (6) the contents of any keyrings to which it points may be changed (the whole
+     point of keyrings being a shared set of credentials, modifiable by anyone
+     with appropriate access).
+
+To alter anything in the cred struct, the copy-and-replace principle must be
+adhered to.  First take a copy, then alter the copy and then use RCU to change
+the task pointer to make it point to the new copy.  There are wrappers to aid
+with this (see below).
+
+A task may only alter its _own_ credentials; it is no longer permitted for a
+task to alter another's credentials.  This means the capset() system call is no
+longer permitted to take any PID other than the one of the current process.
+Also keyctl_instantiate() and keyctl_negate() functions no longer permit
+attachment to process-specific keyrings in the requesting process as the
+instantiating process may need to create them.
+
+
+IMMUTABLE CREDENTIALS
+---------------------
+
+Once a set of credentials has been made public (by calling commit_creds() for
+example), it must be considered immutable, barring two exceptions:
+
+ (1) The reference count may be altered.
+
+ (2) Whilst the keyring subscriptions of a set of credentials may not be
+     changed, the keyrings subscribed to may have their contents altered.
+
+To catch accidental credential alteration at compile time, struct task_struct
+has _const_ pointers to its credential sets, as does struct file.  Furthermore,
+certain functions such as get_cred() and put_cred() operate on const pointers,
+thus rendering casts unnecessary, but require to temporarily ditch the const
+qualification to be able to alter the reference count.
+
+
+ACCESSING TASK CREDENTIALS
+--------------------------
+
+A task being able to alter only its own credentials permits the current process
+to read or replace its own credentials without the need for any form of locking
+- which simplifies things greatly.  It can just call:
+
+	const struct cred *current_cred()
+
+to get a pointer to its credentials structure, and it doesn't have to release
+it afterwards.
+
+There are convenience wrappers for retrieving specific aspects of a task's
+credentials (the value is simply returned in each case):
+
+	uid_t current_uid(void)		Current's real UID
+	gid_t current_gid(void)		Current's real GID
+	uid_t current_euid(void)	Current's effective UID
+	gid_t current_egid(void)	Current's effective GID
+	uid_t current_fsuid(void)	Current's file access UID
+	gid_t current_fsgid(void)	Current's file access GID
+	kernel_cap_t current_cap(void)	Current's effective capabilities
+	void *current_security(void)	Current's LSM security pointer
+	struct user_struct *current_user(void)  Current's user account
+
+There are also convenience wrappers for retrieving specific associated pairs of
+a task's credentials:
+
+	void current_uid_gid(uid_t *, gid_t *);
+	void current_euid_egid(uid_t *, gid_t *);
+	void current_fsuid_fsgid(uid_t *, gid_t *);
+
+which return these pairs of values through their arguments after retrieving
+them from the current task's credentials.
+
+
+In addition, there is a function for obtaining a reference on the current
+process's current set of credentials:
+
+	const struct cred *get_current_cred(void);
+
+and functions for getting references to one of the credentials that don't
+actually live in struct cred:
+
+	struct user_struct *get_current_user(void);
+	struct group_info *get_current_groups(void);
+
+which get references to the current process's user accounting structure and
+supplementary groups list respectively.
+
+Once a reference has been obtained, it must be released with put_cred(),
+free_uid() or put_group_info() as appropriate.
+
+
+ACCESSING ANOTHER TASK'S CREDENTIALS
+------------------------------------
+
+Whilst a task may access its own credentials without the need for locking, the
+same is not true of a task wanting to access another task's credentials.  It
+must use the RCU read lock and rcu_dereference().
+
+The rcu_dereference() is wrapped by:
+
+	const struct cred *__task_cred(struct task_struct *task);
+
+This should be used inside the RCU read lock, as in the following example:
+
+	void foo(struct task_struct *t, struct foo_data *f)
+	{
+		const struct cred *tcred;
+		...
+		rcu_read_lock();
+		tcred = __task_cred(t);
+		f->uid = tcred->uid;
+		f->gid = tcred->gid;
+		f->groups = get_group_info(tcred->groups);
+		rcu_read_unlock();
+		...
+	}
+
+A function need not get RCU read lock to use __task_cred() if it is holding a
+spinlock at the time as this implicitly holds the RCU read lock.
+
+Should it be necessary to hold another task's credentials for a long period of
+time, and possibly to sleep whilst doing so, then the caller should get a
+reference on them using:
+
+	const struct cred *get_task_cred(struct task_struct *task);
+
+This does all the RCU magic inside of it.  The caller must call put_cred() on
+the credentials so obtained when they're finished with.
+
+There are a couple of convenience functions to access bits of another task's
+credentials, hiding the RCU magic from the caller:
+
+	uid_t task_uid(task)		Task's real UID
+	uid_t task_euid(task)		Task's effective UID
+
+If the caller is holding a spinlock or the RCU read lock at the time anyway,
+then:
+
+	__task_cred(task)->uid
+	__task_cred(task)->euid
+
+should be used instead.  Similarly, if multiple aspects of a task's credentials
+need to be accessed, RCU read lock or a spinlock should be used, __task_cred()
+called, the result stored in a temporary pointer and then the credential
+aspects called from that before dropping the lock.  This prevents the
+potentially expensive RCU magic from being invoked multiple times.
+
+Should some other single aspect of another task's credentials need to be
+accessed, then this can be used:
+
+	task_cred_xxx(task, member)
+
+where 'member' is a non-pointer member of the cred struct.  For instance:
+
+	uid_t task_cred_xxx(task, suid);
+
+will retrieve 'struct cred::suid' from the task, doing the appropriate RCU
+magic.  This may not be used for pointer members as what they point to may
+disappear the moment the RCU read lock is dropped.
+
+
+ALTERING CREDENTIALS
+--------------------
+
+As previously mentioned, a task may only alter its own credentials, and may not
+alter those of another task.  This means that it doesn't need to use any
+locking to alter its own credentials.
+
+To alter the current process's credentials, a function should first prepare a
+new set of credentials by calling:
+
+	struct cred *prepare_creds(void);
+
+this locks current->cred_replace_mutex and then allocates and constructs a
+duplicate of the current process's credentials, returning with the mutex still
+held if successful.  It returns NULL if not successful (out of memory).
+
+The mutex prevents ptrace() from altering the ptrace state of a process whilst
+security checks on credentials construction and changing is taking place as
+the ptrace state may alter the outcome, particularly in the case of execve().
+
+The new credentials set should be altered appropriately, and any security
+checks and hooks done.  Both the current and the proposed sets of credentials
+are available for this purpose as current_cred() will return the current set
+still at this point.
+
+
+When the credential set is ready, it should be committed to the current process
+by calling:
+
+	int commit_creds(struct cred *new);
+
+This will alter various aspects of the credentials and the process, giving the
+LSM a chance to do likewise, then it will use rcu_assign_pointer() to actually
+commit the new credentials to current->cred, it will release
+current->cred_replace_mutex to allow ptrace() to take place, and it will notify
+the scheduler and others of the changes.
+
+This function is guaranteed to return 0, so that it can be tail-called at the
+end of such functions as sys_setresuid().
+
+Note that this function consumes the caller's reference to the new credentials.
+The caller should _not_ call put_cred() on the new credentials afterwards.
+
+Furthermore, once this function has been called on a new set of credentials,
+those credentials may _not_ be changed further.
+
+
+Should the security checks fail or some other error occur after prepare_creds()
+has been called, then the following function should be invoked:
+
+	void abort_creds(struct cred *new);
+
+This releases the lock on current->cred_replace_mutex that prepare_creds() got
+and then releases the new credentials.
+
+
+A typical credentials alteration function would look something like this:
+
+	int alter_suid(uid_t suid)
+	{
+		struct cred *new;
+		int ret;
+
+		new = prepare_creds();
+		if (!new)
+			return -ENOMEM;
+
+		new->suid = suid;
+		ret = security_alter_suid(new);
+		if (ret < 0) {
+			abort_creds(new);
+			return ret;
+		}
+
+		return commit_creds(new);
+	}
+
+
+MANAGING CREDENTIALS
+--------------------
+
+There are some functions to help manage credentials:
+
+ (*) void put_cred(const struct cred *cred);
+
+     This releases a reference to the given set of credentials.  If the
+     reference count reaches zero, the credentials will be scheduled for
+     destruction by the RCU system.
+
+ (*) const struct cred *get_cred(const struct cred *cred);
+
+     This gets a reference on a live set of credentials, returning a pointer to
+     that set of credentials.
+
+ (*) struct cred *get_new_cred(struct cred *cred);
+
+     This gets a reference on a set of credentials that is under construction
+     and is thus still mutable, returning a pointer to that set of credentials.
+
+
+=====================
+OPEN FILE CREDENTIALS
+=====================
+
+When a new file is opened, a reference is obtained on the opening task's
+credentials and this is attached to the file struct as 'f_cred' in place of
+'f_uid' and 'f_gid'.  Code that used to access file->f_uid and file->f_gid
+should now access file->f_cred->fsuid and file->f_cred->fsgid.
+
+It is safe to access f_cred without the use of RCU or locking because the
+pointer will not change over the lifetime of the file struct, and nor will the
+contents of the cred struct pointed to, barring the exceptions listed above
+(see the Task Credentials section).
+
+
+=======================================
+OVERRIDING THE VFS'S USE OF CREDENTIALS
+=======================================
+
+Under some circumstances it is desirable to override the credentials used by
+the VFS, and that can be done by calling into such as vfs_mkdir() with a
+different set of credentials.  This is done in the following places:
+
+ (*) sys_faccessat().
+
+ (*) do_coredump().
+
+ (*) nfs4recover.c.
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index c28a2ac..dc7c681 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -120,13 +120,6 @@
 
 ---------------------------
 
-What:   eepro100 network driver
-When:   January 2007
-Why:    replaced by the e100 driver
-Who:    Adrian Bunk <bunk@stusta.de>
-
----------------------------
-
 What:	Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
 	(temporary transition config option provided until then)
 	The transition config option will also be removed at the same time.
@@ -244,18 +237,6 @@
 
 ---------------------------
 
-What:	init_mm export
-When:	2.6.26
-Why:	Not used in-tree. The current out-of-tree users used it to
-	work around problems in the CPA code which should be resolved
-	by now. One usecase was described to provide verification code
-	of the CPA operation. That's a good idea in general, but such
-	code / infrastructure should be in the kernel and not in some
-	out-of-tree driver.
-Who:	Thomas Gleixner <tglx@linutronix.de>
-
-----------------------------
-
 What:	usedac i386 kernel parameter
 When:	2.6.27
 Why:	replaced by allowdac and no dac combination
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index bb1b0dd..71df353 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1339,10 +1339,13 @@
 
 Enables/Disables the NMI watchdog on x86 systems.  When the value is non-zero
 the NMI watchdog is enabled and will continuously test all online cpus to
-determine whether or not they are still functioning properly.
+determine whether or not they are still functioning properly. Currently,
+passing "nmi_watchdog=" parameter at boot time is required for this function
+to work.
 
-Because the NMI watchdog shares registers with oprofile, by disabling the NMI
-watchdog, oprofile may have more registers to utilize.
+If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel parameter), the
+NMI watchdog shares registers with oprofile. By disabling the NMI watchdog,
+oprofile may have more registers to utilize.
 
 msgmni
 ------
diff --git a/Documentation/ftrace.txt b/Documentation/ftrace.txt
index 9cc4d68..803b131 100644
--- a/Documentation/ftrace.txt
+++ b/Documentation/ftrace.txt
@@ -82,7 +82,7 @@
 		tracer is not adding more data, they will display
 		the same information every time they are read.
 
-  iter_ctrl: This file lets the user control the amount of data
+  trace_options: This file lets the user control the amount of data
 		that is displayed in one of the above output
 		files.
 
@@ -94,10 +94,10 @@
 		only be recorded if the latency is greater than
 		the value in this file. (in microseconds)
 
-  trace_entries: This sets or displays the number of bytes each CPU
+  buffer_size_kb: This sets or displays the number of kilobytes each CPU
 		buffer can hold. The tracer buffers are the same size
 		for each CPU. The displayed number is the size of the
-		 CPU buffer and not total size of all buffers. The
+		CPU buffer and not total size of all buffers. The
 		trace buffers are allocated in pages (blocks of memory
 		that the kernel uses for allocation, usually 4 KB in size).
 		If the last page allocated has room for more bytes
@@ -127,6 +127,8 @@
 		be traced. If a function exists in both set_ftrace_filter
 		and set_ftrace_notrace,	the function will _not_ be traced.
 
+  set_ftrace_pid: Have the function tracer only trace a single thread.
+
   available_filter_functions: This lists the functions that ftrace
 		has processed and can trace. These are the function
 		names that you can pass to "set_ftrace_filter" or
@@ -316,23 +318,23 @@
   The rest is the same as the 'trace' file.
 
 
-iter_ctrl
----------
+trace_options
+-------------
 
-The iter_ctrl file is used to control what gets printed in the trace
+The trace_options file is used to control what gets printed in the trace
 output. To see what is available, simply cat the file:
 
-  cat /debug/tracing/iter_ctrl
+  cat /debug/tracing/trace_options
   print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \
- noblock nostacktrace nosched-tree
+ noblock nostacktrace nosched-tree nouserstacktrace nosym-userobj
 
 To disable one of the options, echo in the option prepended with "no".
 
-  echo noprint-parent > /debug/tracing/iter_ctrl
+  echo noprint-parent > /debug/tracing/trace_options
 
 To enable an option, leave off the "no".
 
-  echo sym-offset > /debug/tracing/iter_ctrl
+  echo sym-offset > /debug/tracing/trace_options
 
 Here are the available options:
 
@@ -378,6 +380,20 @@
 		When a trace is recorded, so is the stack of functions.
 		This allows for back traces of trace sites.
 
+  userstacktrace - This option changes the trace.
+		   It records a stacktrace of the current userspace thread.
+
+  sym-userobj - when user stacktrace are enabled, look up which object the
+		address belongs to, and print a relative address
+		This is especially useful when ASLR is on, otherwise you don't
+		get a chance to resolve the address to object/file/line after the app is no
+		longer running
+
+		The lookup is performed when you read trace,trace_pipe,latency_trace. Example:
+
+		a.out-1623  [000] 40874.465068: /root/a.out[+0x480] <-/root/a.out[+0
+x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6]
+
   sched-tree - TBD (any users??)
 
 
@@ -1059,6 +1075,83 @@
 a search through /proc/mounts may be needed to find where the debugfs
 file-system is mounted.
 
+
+Single thread tracing
+---------------------
+
+By writing into /debug/tracing/set_ftrace_pid you can trace a
+single thread. For example:
+
+# cat /debug/tracing/set_ftrace_pid
+no pid
+# echo 3111 > /debug/tracing/set_ftrace_pid
+# cat /debug/tracing/set_ftrace_pid
+3111
+# echo function > /debug/tracing/current_tracer
+# cat /debug/tracing/trace | head
+ # tracer: function
+ #
+ #           TASK-PID    CPU#    TIMESTAMP  FUNCTION
+ #              | |       |          |         |
+     yum-updatesd-3111  [003]  1637.254676: finish_task_switch <-thread_return
+     yum-updatesd-3111  [003]  1637.254681: hrtimer_cancel <-schedule_hrtimeout_range
+     yum-updatesd-3111  [003]  1637.254682: hrtimer_try_to_cancel <-hrtimer_cancel
+     yum-updatesd-3111  [003]  1637.254683: lock_hrtimer_base <-hrtimer_try_to_cancel
+     yum-updatesd-3111  [003]  1637.254685: fget_light <-do_sys_poll
+     yum-updatesd-3111  [003]  1637.254686: pipe_poll <-do_sys_poll
+# echo -1 > /debug/tracing/set_ftrace_pid
+# cat /debug/tracing/trace |head
+ # tracer: function
+ #
+ #           TASK-PID    CPU#    TIMESTAMP  FUNCTION
+ #              | |       |          |         |
+ ##### CPU 3 buffer started ####
+     yum-updatesd-3111  [003]  1701.957688: free_poll_entry <-poll_freewait
+     yum-updatesd-3111  [003]  1701.957689: remove_wait_queue <-free_poll_entry
+     yum-updatesd-3111  [003]  1701.957691: fput <-free_poll_entry
+     yum-updatesd-3111  [003]  1701.957692: audit_syscall_exit <-sysret_audit
+     yum-updatesd-3111  [003]  1701.957693: path_put <-audit_syscall_exit
+
+If you want to trace a function when executing, you could use
+something like this simple program:
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int main (int argc, char **argv)
+{
+        if (argc < 1)
+                exit(-1);
+
+        if (fork() > 0) {
+                int fd, ffd;
+                char line[64];
+                int s;
+
+                ffd = open("/debug/tracing/current_tracer", O_WRONLY);
+                if (ffd < 0)
+                        exit(-1);
+                write(ffd, "nop", 3);
+
+                fd = open("/debug/tracing/set_ftrace_pid", O_WRONLY);
+                s = sprintf(line, "%d\n", getpid());
+                write(fd, line, s);
+
+                write(ffd, "function", 8);
+
+                close(fd);
+                close(ffd);
+
+                execvp(argv[1], argv+1);
+        }
+
+        return 0;
+}
+
 dynamic ftrace
 --------------
 
@@ -1158,7 +1251,11 @@
 
   <match>*<match> will not work.
 
- # echo hrtimer_* > /debug/tracing/set_ftrace_filter
+Note: It is better to use quotes to enclose the wild cards, otherwise
+  the shell may expand the parameters into names of files in the local
+  directory.
+
+ # echo 'hrtimer_*' > /debug/tracing/set_ftrace_filter
 
 Produces:
 
@@ -1213,7 +1310,7 @@
  # echo sys_nanosleep > /debug/tracing/set_ftrace_filter
  # cat /debug/tracing/set_ftrace_filter
 sys_nanosleep
- # echo hrtimer_* >> /debug/tracing/set_ftrace_filter
+ # echo 'hrtimer_*' >> /debug/tracing/set_ftrace_filter
  # cat /debug/tracing/set_ftrace_filter
 hrtimer_run_queues
 hrtimer_run_pending
@@ -1299,41 +1396,29 @@
 -------------
 
 Having too much or not enough data can be troublesome in diagnosing
-an issue in the kernel. The file trace_entries is used to modify
+an issue in the kernel. The file buffer_size_kb is used to modify
 the size of the internal trace buffers. The number listed
 is the number of entries that can be recorded per CPU. To know
 the full size, multiply the number of possible CPUS with the
 number of entries.
 
- # cat /debug/tracing/trace_entries
-65620
+ # cat /debug/tracing/buffer_size_kb
+1408 (units kilobytes)
 
 Note, to modify this, you must have tracing completely disabled. To do that,
 echo "nop" into the current_tracer. If the current_tracer is not set
 to "nop", an EINVAL error will be returned.
 
  # echo nop > /debug/tracing/current_tracer
- # echo 100000 > /debug/tracing/trace_entries
- # cat /debug/tracing/trace_entries
-100045
-
-
-Notice that we echoed in 100,000 but the size is 100,045. The entries
-are held in individual pages. It allocates the number of pages it takes
-to fulfill the request. If more entries may fit on the last page
-then they will be added.
-
- # echo 1 > /debug/tracing/trace_entries
- # cat /debug/tracing/trace_entries
-85
-
-This shows us that 85 entries can fit in a single page.
+ # echo 10000 > /debug/tracing/buffer_size_kb
+ # cat /debug/tracing/buffer_size_kb
+10000 (units kilobytes)
 
 The number of pages which will be allocated is limited to a percentage
 of available memory. Allocating too much will produce an error.
 
- # echo 1000000000000 > /debug/tracing/trace_entries
+ # echo 1000000000000 > /debug/tracing/buffer_size_kb
 -bash: echo: write error: Cannot allocate memory
- # cat /debug/tracing/trace_entries
+ # cat /debug/tracing/buffer_size_kb
 85
 
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 7a77533..51104f9 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -383,6 +383,20 @@
 	to prerequisites are referenced with $(src) (because they are not
 	generated files).
 
+    $(kecho)
+	echoing information to user in a rule is often a good practice
+	but when execution "make -s" one does not expect to see any output
+	except for warnings/errors.
+	To support this kbuild define $(kecho) which will echo out the
+	text following $(kecho) to stdout except if "make -s" is used.
+
+	Example:
+		#arch/blackfin/boot/Makefile
+		$(obj)/vmImage: $(obj)/vmlinux.gz
+			$(call if_changed,uimage)
+			@$(kecho) 'Kernel: $@ is ready'
+
+
 --- 3.11 $(CC) support functions
 
 	The kernel may be built with several different versions of
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index e0f346d..a2d8805 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -89,6 +89,7 @@
 	SPARC	Sparc architecture is enabled.
 	SWSUSP	Software suspend (hibernation) is enabled.
 	SUSPEND	System suspend states are enabled.
+	FTRACE	Function tracing enabled.
 	TS	Appropriate touchscreen support is enabled.
 	USB	USB support is enabled.
 	USBHID	USB Human Interface Device support is enabled.
@@ -220,14 +221,17 @@
 			Bits in debug_level correspond to a level in
 			ACPI_DEBUG_PRINT statements, e.g.,
 			    ACPI_DEBUG_PRINT((ACPI_DB_INFO, ...
-			See Documentation/acpi/debug.txt for more information
-			about debug layers and levels.
+			The debug_level mask defaults to "info".  See
+			Documentation/acpi/debug.txt for more information about
+			debug layers and levels.
 
+			Enable processor driver info messages:
+			    acpi.debug_layer=0x20000000
+			Enable PCI/PCI interrupt routing info messages:
+			    acpi.debug_layer=0x400000
 			Enable AML "Debug" output, i.e., stores to the Debug
 			object while interpreting AML:
 			    acpi.debug_layer=0xffffffff acpi.debug_level=0x2
-			Enable PCI/PCI interrupt routing info messages:
-			    acpi.debug_layer=0x400000 acpi.debug_level=0x4
 			Enable all messages related to ACPI hardware:
 			    acpi.debug_layer=0x2 acpi.debug_level=0xffffffff
 
@@ -750,6 +754,14 @@
 			parameter will force ia64_sal_cache_flush to call
 			ia64_pal_cache_flush instead of SAL_CACHE_FLUSH.
 
+	ftrace=[tracer]
+			[ftrace] will set and start the specified tracer
+			as early as possible in order to facilitate early
+			boot debugging.
+
+	ftrace_dump_on_oops
+			[ftrace] will dump the trace buffers on oops.
+
 	gamecon.map[2|3]=
 			[HW,JOY] Multisystem joystick and NES/SNES/PSX pad
 			support via parallel port (up to 5 devices per port)
@@ -811,6 +823,9 @@
 
 	hlt		[BUGS=ARM,SH]
 
+	hvc_iucv=	[S390] Number of z/VM IUCV Hypervisor console (HVC)
+			       back-ends. Valid parameters: 0..8
+
 	i8042.debug	[HW] Toggle i8042 debug mode
 	i8042.direct	[HW] Put keyboard port into non-translated mode
 	i8042.dumbkbd	[HW] Pretend that controller can only read data from
@@ -1393,7 +1408,20 @@
 			when a NMI is triggered.
 			Format: [state][,regs][,debounce][,die]
 
-	nmi_watchdog=	[KNL,BUGS=X86-32] Debugging features for SMP kernels
+	nmi_watchdog=	[KNL,BUGS=X86-32,X86-64] Debugging features for SMP kernels
+			Format: [panic,][num]
+			Valid num: 0,1,2
+			0 - turn nmi_watchdog off
+			1 - use the IO-APIC timer for the NMI watchdog
+			2 - use the local APIC for the NMI watchdog using
+			a performance counter. Note: This will use one performance
+			counter and the local APIC's performance vector.
+			When panic is specified panic when an NMI watchdog timeout occurs.
+			This is useful when you use a panic=... timeout and need the box
+			quickly up again.
+			Instead of 1 and 2 it is possible to use the following
+			symbolic names: lapic and ioapic
+			Example: nmi_watchdog=2 or nmi_watchdog=panic,lapic
 
 	no387		[BUGS=X86-32] Tells the kernel to use the 387 maths
 			emulation library even if a 387 maths coprocessor
@@ -1449,6 +1477,10 @@
 			instruction doesn't work correctly and not to
 			use it.
 
+	no_file_caps	Tells the kernel not to honor file capabilities.  The
+			only way then for a file to be executed with privilege
+			is to be setuid root or executed by root.
+
 	nohalt		[IA-64] Tells the kernel not to use the power saving
 			function PAL_HALT_LIGHT when idle. This increases
 			power-consumption. On the positive side, it reduces
@@ -1626,6 +1658,17 @@
 		nomsi		[MSI] If the PCI_MSI kernel config parameter is
 				enabled, this kernel boot option can be used to
 				disable the use of MSI interrupts system-wide.
+		noioapicquirk	[APIC] Disable all boot interrupt quirks.
+				Safety option to keep boot IRQs enabled. This
+				should never be necessary.
+		ioapicreroute	[APIC] Enable rerouting of boot IRQs to the
+				primary IO-APIC for bridges that cannot disable
+				boot IRQs. This fixes a source of spurious IRQs
+				when the system masks IRQs.
+		noioapicreroute	[APIC] Disable workaround that uses the
+				boot IRQ equivalent of an IRQ that connects to
+				a chipset where boot IRQs cannot be disabled.
+				The opposite of ioapicreroute.
 		biosirq		[X86-32] Use PCI BIOS calls to get the interrupt
 				routing table. These calls are known to be buggy
 				on several machines and they hang the machine
@@ -2165,6 +2208,9 @@
 	st=		[HW,SCSI] SCSI tape parameters (buffers, etc.)
 			See Documentation/scsi/st.txt.
 
+	stacktrace	[FTRACE]
+			Enabled the stack tracer on boot up.
+
 	sti=		[PARISC,HW]
 			Format: <num>
 			Set the STI (builtin display/keyboard on the HP-PARISC
@@ -2249,12 +2295,27 @@
 			See comment before function dc390_setup() in
 			drivers/scsi/tmscsim.c.
 
+	topology=	[S390]
+			Format: {off | on}
+			Specify if the kernel should make use of the cpu
+			topology informations if the hardware supports these.
+			The scheduler will make use of these informations and
+			e.g. base its process migration decisions on it.
+			Default is off.
+
 	tp720=		[HW,PS2]
 
 	trix=		[HW,OSS] MediaTrix AudioTrix Pro
 			Format:
 			<io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq>
 
+	tsc=		Disable clocksource-must-verify flag for TSC.
+			Format: <string>
+			[x86] reliable: mark tsc clocksource as reliable, this
+			disables clocksource verification at runtime.
+			Used to enable high-resolution timer mode on older
+			hardware, and in virtualized environment.
+
 	turbografx.map[2|3]=	[HW,JOY]
 			TurboGraFX parallel port interface
 			Format:
diff --git a/Documentation/markers.txt b/Documentation/markers.txt
index 089f613..d2b3d0e 100644
--- a/Documentation/markers.txt
+++ b/Documentation/markers.txt
@@ -51,11 +51,16 @@
 activated by calling marker_arm(). Marker deactivation can be done by calling
 marker_disarm() as many times as marker_arm() has been called. Removing a probe
 is done through marker_probe_unregister(); it will disarm the probe.
-marker_synchronize_unregister() must be called before the end of the module exit
-function to make sure there is no caller left using the probe. This, and the
-fact that preemption is disabled around the probe call, make sure that probe
-removal and module unload are safe. See the "Probe example" section below for a
-sample probe module.
+
+marker_synchronize_unregister() must be called between probe unregistration and
+the first occurrence of
+- the end of module exit function,
+  to make sure there is no caller left using the probe;
+- the free of any resource used by the probes,
+  to make sure the probes wont be accessing invalid data.
+This, and the fact that preemption is disabled around the probe call, make sure
+that probe removal and module unload are safe. See the "Probe example" section
+below for a sample probe module.
 
 The marker mechanism supports inserting multiple instances of the same marker.
 Markers can be put in inline functions, inlined static functions, and
@@ -70,6 +75,20 @@
 
 "Format mismatch for probe probe_name (format), marker (format)"
 
+Another way to use markers is to simply define the marker without generating any
+function call to actually call into the marker. This is useful in combination
+with tracepoint probes in a scheme like this :
+
+void probe_tracepoint_name(unsigned int arg1, struct task_struct *tsk);
+
+DEFINE_MARKER_TP(marker_eventname, tracepoint_name, probe_tracepoint_name,
+	"arg1 %u pid %d");
+
+notrace void probe_tracepoint_name(unsigned int arg1, struct task_struct *tsk)
+{
+	struct marker *marker = &GET_MARKER(kernel_irq_entry);
+	/* write data to trace buffers ... */
+}
 
 * Probe / marker example
 
diff --git a/Documentation/networking/README.ipw2200 b/Documentation/networking/README.ipw2200
index 4f2a40f..80c7285 100644
--- a/Documentation/networking/README.ipw2200
+++ b/Documentation/networking/README.ipw2200
@@ -147,7 +147,7 @@
 	driver.  If disabled, the driver will not attempt to scan 
 	for and associate to a network until it has been configured with 
 	one or more properties for the target network, for example configuring 
-	the network SSID.  Default is 1 (auto-associate)
+	the network SSID.  Default is 0 (do not auto-associate)
 	
 	Example: % modprobe ipw2200 associate=0
 
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 688dfe1..5ede747 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -194,6 +194,48 @@
 
 	The parameters are as follows:
 
+ad_select
+
+	Specifies the 802.3ad aggregation selection logic to use.  The
+	possible values and their effects are:
+
+	stable or 0
+
+		The active aggregator is chosen by largest aggregate
+		bandwidth.
+
+		Reselection of the active aggregator occurs only when all
+		slaves of the active aggregator are down or the active
+		aggregator has no slaves.
+
+		This is the default value.
+
+	bandwidth or 1
+
+		The active aggregator is chosen by largest aggregate
+		bandwidth.  Reselection occurs if:
+
+		- A slave is added to or removed from the bond
+
+		- Any slave's link state changes
+
+		- Any slave's 802.3ad association state changes
+
+		- The bond's adminstrative state changes to up
+
+	count or 2
+
+		The active aggregator is chosen by the largest number of
+		ports (slaves).  Reselection occurs as described under the
+		"bandwidth" setting, above.
+
+	The bandwidth and count selection policies permit failover of
+	802.3ad aggregations when partial failure of the active aggregator
+	occurs.  This keeps the aggregator with the highest availability
+	(either in bandwidth or in number of ports) active at all times.
+
+	This option was added in bonding version 3.4.0.
+
 arp_interval
 
 	Specifies the ARP link monitoring frequency in milliseconds.
@@ -551,6 +593,16 @@
 	affects only the active-backup mode.  This option was added for
 	bonding version 3.3.0.
 
+num_unsol_na
+
+	Specifies the number of unsolicited IPv6 Neighbor Advertisements
+	to be issued after a failover event.  One unsolicited NA is issued
+	immediately after the failover.
+
+	The valid range is 0 - 255; the default value is 1.  This option
+	affects only the active-backup mode.  This option was added for
+	bonding version 3.4.0.
+
 primary
 
 	A string (eth0, eth2, etc) specifying which slave is the
@@ -922,17 +974,19 @@
 NETMASK, NETWORK and BROADCAST) to match your network configuration.
 
 	For later versions of initscripts, such as that found with Fedora
-7 and Red Hat Enterprise Linux version 5 (or later), it is possible, and,
-indeed, preferable, to specify the bonding options in the ifcfg-bond0
+7 (or later) and Red Hat Enterprise Linux version 5 (or later), it is possible,
+and, indeed, preferable, to specify the bonding options in the ifcfg-bond0
 file, e.g. a line of the format:
 
-BONDING_OPTS="mode=active-backup arp_interval=60 arp_ip_target=+192.168.1.254"
+BONDING_OPTS="mode=active-backup arp_interval=60 arp_ip_target=192.168.1.254"
 
 	will configure the bond with the specified options.  The options
 specified in BONDING_OPTS are identical to the bonding module parameters
-except for the arp_ip_target field.  Each target should be included as a
-separate option and should be preceded by a '+' to indicate it should be
-added to the list of queried targets, e.g.,
+except for the arp_ip_target field when using versions of initscripts older
+than and 8.57 (Fedora 8) and 8.45.19 (Red Hat Enterprise Linux 5.2).  When
+using older versions each target should be included as a separate option and
+should be preceded by a '+' to indicate it should be added to the list of
+queried targets, e.g.,
 
 	arp_ip_target=+192.168.1.1 arp_ip_target=+192.168.1.2
 
@@ -940,7 +994,7 @@
 options via BONDING_OPTS, it is not necessary to edit /etc/modules.conf or
 /etc/modprobe.conf.
 
-	For older versions of initscripts that do not support
+	For even older versions of initscripts that do not support
 BONDING_OPTS, it is necessary to edit /etc/modules.conf (or
 /etc/modprobe.conf, depending upon your distro) to load the bonding module
 with your desired options when the bond0 interface is brought up.  The
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt
index 39131a3..7a3bb1a 100644
--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -57,6 +57,24 @@
 DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet
 size (application payload size) in bytes, see RFC 4340, section 14.
 
+DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
+supported by the endpoint (see include/linux/dccp.h for symbolic constants).
+The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
+
+DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same
+time, combining the operation of the next two socket options. This option is
+preferrable over the latter two, since often applications will use the same
+type of CCID for both directions; and mixed use of CCIDs is not currently well
+understood. This socket option takes as argument at least one uint8_t value, or
+an array of uint8_t values, which must match available CCIDS (see above). CCIDs
+must be registered on the socket before calling connect() or listen().
+
+DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets
+the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID.
+Please note that the getsockopt argument type here is `int', not uint8_t.
+
+DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
@@ -115,20 +133,12 @@
 	importance for retransmitted acknowledgments and feature negotiation,
 	data packets are never retransmitted. Analogue of tcp_retries2.
 
-send_ndp = 1
-	Whether or not to send NDP count options (sec. 7.7.2).
-
-send_ackvec = 1
-	Whether or not to send Ack Vector options (sec. 11.5).
-
-ack_ratio = 2
-	The default Ack Ratio (sec. 11.3) to use.
-
 tx_ccid = 2
-	Default CCID for the sender-receiver half-connection.
+	Default CCID for the sender-receiver half-connection. Depending on the
+	choice of CCID, the Send Ack Vector feature is enabled automatically.
 
 rx_ccid = 2
-	Default CCID for the receiver-sender half-connection.
+	Default CCID for the receiver-sender half-connection; see tx_ccid.
 
 seq_window = 100
 	The initial sequence window (sec. 7.5.2).
diff --git a/Documentation/networking/driver.txt b/Documentation/networking/driver.txt
index ea72d2e..03283da 100644
--- a/Documentation/networking/driver.txt
+++ b/Documentation/networking/driver.txt
@@ -13,7 +13,7 @@
 	static int drv_hard_start_xmit(struct sk_buff *skb,
 		   		       struct net_device *dev)
 	{
-		struct drv *dp = dev->priv;
+		struct drv *dp = netdev_priv(dev);
 
 		lock_tx(dp);
 		...
diff --git a/Documentation/networking/generic-hdlc.txt b/Documentation/networking/generic-hdlc.txt
index 31bc8b7..4eb3cc4 100644
--- a/Documentation/networking/generic-hdlc.txt
+++ b/Documentation/networking/generic-hdlc.txt
@@ -3,15 +3,15 @@
 
 
 Generic HDLC layer currently supports:
-1. Frame Relay (ANSI, CCITT, Cisco and no LMI).
+1. Frame Relay (ANSI, CCITT, Cisco and no LMI)
    - Normal (routed) and Ethernet-bridged (Ethernet device emulation)
      interfaces can share a single PVC.
    - ARP support (no InARP support in the kernel - there is an
      experimental InARP user-space daemon available on:
      http://www.kernel.org/pub/linux/utils/net/hdlc/).
-2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation.
-3. Cisco HDLC.
-4. PPP (uses syncppp.c).
+2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation
+3. Cisco HDLC
+4. PPP
 5. X.25 (uses X.25 routines).
 
 Generic HDLC is a protocol driver only - it needs a low-level driver
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index d849326..c771278 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -27,6 +27,12 @@
 	The advertised MSS depends on the first hop route MTU, but will
 	never be lower than this setting.
 
+rt_cache_rebuild_count - INTEGER
+	The per net-namespace route cache emergency rebuild threshold.
+	Any net-namespace having its route cache rebuilt due to
+	a hash bucket chain being too long more than this many times
+	will have its route caching disabled
+
 IP Fragmentation:
 
 ipfrag_high_thresh - INTEGER
diff --git a/Documentation/networking/mac80211_hwsim/README b/Documentation/networking/mac80211_hwsim/README
index 2ff8ccb..24ac91d 100644
--- a/Documentation/networking/mac80211_hwsim/README
+++ b/Documentation/networking/mac80211_hwsim/README
@@ -50,10 +50,6 @@
 care of WPA2-PSK authentication. In addition, hostapd is also
 processing access point side of association.
 
-Please note that the current Linux kernel does not enable AP mode, so a
-simple patch is needed to enable AP mode selection:
-http://johannes.sipsolutions.net/patches/kernel/all/LATEST/006-allow-ap-vlan-modes.patch
-
 
 # Build mac80211_hwsim as part of kernel configuration
 
@@ -65,3 +61,8 @@
 
 # Run wpa_supplicant (station) for wlan1
 wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf
+
+
+More test cases are available in hostap.git:
+git://w1.fi/srv/git/hostap.git and mac80211_hwsim/tests subdirectory
+(http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=tree;f=mac80211_hwsim/tests)
diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt
index d0f71fc..a2ab6a0 100644
--- a/Documentation/networking/netdevices.txt
+++ b/Documentation/networking/netdevices.txt
@@ -18,7 +18,7 @@
 alloc_etherdev, alloc_netdev.  These reserve extra space for driver
 private data which gets freed when the network device is freed. If
 separately allocated data is attached to the network device
-(dev->priv) then it is up to the module exit handler to free that.
+(netdev_priv(dev)) then it is up to the module exit handler to free that.
 
 MTU
 ===
diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt
index a96989a..dcf3164 100644
--- a/Documentation/networking/regulatory.txt
+++ b/Documentation/networking/regulatory.txt
@@ -131,11 +131,13 @@
 
 	r = zd_reg2alpha2(mac->regdomain, alpha2);
 	if (!r)
-		regulatory_hint(hw->wiphy, alpha2, NULL);
+		regulatory_hint(hw->wiphy, alpha2);
 
 Example code - drivers providing a built in regulatory domain:
 --------------------------------------------------------------
 
+[NOTE: This API is not currently available, it can be added when required]
+
 If you have regulatory information you can obtain from your
 driver and you *need* to use this we let you build a regulatory domain
 structure and pass it to the wireless core. To do this you should
@@ -167,7 +169,6 @@
 
 Then in some part of your code after your wiphy has been registered:
 
-	int r;
 	struct ieee80211_regdomain *rd;
 	int size_of_regd;
 	int num_rules = mydriver_jp_regdom.n_reg_rules;
@@ -178,17 +179,12 @@
 
 	rd = kzalloc(size_of_regd, GFP_KERNEL);
 	if (!rd)
-	return -ENOMEM;
+		return -ENOMEM;
 
 	memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain));
 
-	for (i=0; i < num_rules; i++) {
-		memcpy(&rd->reg_rules[i], &mydriver_jp_regdom.reg_rules[i],
-			sizeof(struct ieee80211_reg_rule));
-	}
-	r = regulatory_hint(hw->wiphy, NULL, rd);
-	if (r) {
-		kfree(rd);
-		return r;
-	}
-
+	for (i=0; i < num_rules; i++)
+		memcpy(&rd->reg_rules[i],
+		       &mydriver_jp_regdom.reg_rules[i],
+		       sizeof(struct ieee80211_reg_rule));
+	regulatory_struct_hint(rd);
diff --git a/Documentation/nmi_watchdog.txt b/Documentation/nmi_watchdog.txt
index 90aa453..bf9f80a 100644
--- a/Documentation/nmi_watchdog.txt
+++ b/Documentation/nmi_watchdog.txt
@@ -69,6 +69,11 @@
 On x86 nmi_watchdog is disabled by default so you have to enable it with
 a boot time parameter.
 
+It's possible to disable the NMI watchdog in run-time by writing "0" to
+/proc/sys/kernel/nmi_watchdog. Writing "1" to the same file will re-enable
+the NMI watchdog. Notice that you still need to use "nmi_watchdog=" parameter
+at boot time.
+
 NOTE: In kernels prior to 2.4.2-ac18 the NMI-oopser is enabled unconditionally
 on x86 SMP boxes.
 
diff --git a/Documentation/powerpc/dts-bindings/fsl/tsec.txt b/Documentation/powerpc/dts-bindings/fsl/tsec.txt
index cf55fa4..7fa4b27 100644
--- a/Documentation/powerpc/dts-bindings/fsl/tsec.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/tsec.txt
@@ -2,8 +2,8 @@
 
 The MDIO is a bus to which the PHY devices are connected.  For each
 device that exists on this bus, a child node should be created.  See
-the definition of the PHY node below for an example of how to define
-a PHY.
+the definition of the PHY node in booting-without-of.txt for an example
+of how to define a PHY.
 
 Required properties:
   - reg : Offset and length of the register set for the device
@@ -21,6 +21,14 @@
 		};
 	};
 
+* TBI Internal MDIO bus
+
+As of this writing, every tsec is associated with an internal TBI PHY.
+This PHY is accessed through the local MDIO bus.  These buses are defined
+similarly to the mdio buses, except they are compatible with "fsl,gianfar-tbi".
+The TBI PHYs underneath them are similar to normal PHYs, but the reg property
+is considered instructive, rather than descriptive.  The reg property should
+be chosen so it doesn't interfere with other PHYs on the bus.
 
 * Gianfar-compatible ethernet nodes
 
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt
index b65f079..4d3ee31 100644
--- a/Documentation/rfkill.txt
+++ b/Documentation/rfkill.txt
@@ -191,12 +191,20 @@
 	  to tell the devices registered with the rfkill class to change
 	  their state (i.e. translates the input layer event into real
 	  action).
+
 	* rfkill-input implements EPO by handling EV_SW SW_RFKILL_ALL 0
 	  (power off all transmitters) in a special way: it ignores any
 	  overrides and local state cache and forces all transmitters to the
 	  RFKILL_STATE_SOFT_BLOCKED state (including those which are already
-	  supposed to be BLOCKED).  Note that the opposite event (power on all
-	  transmitters) is handled normally.
+	  supposed to be BLOCKED).
+	* rfkill EPO will remain active until rfkill-input receives an
+	  EV_SW SW_RFKILL_ALL 1 event.  While the EPO is active, transmitters
+	  are locked in the blocked state (rfkill will refuse to unblock them).
+	* rfkill-input implements different policies that the user can
+	  select for handling EV_SW SW_RFKILL_ALL 1.  It will unlock rfkill,
+	  and either do nothing (leave transmitters blocked, but now unlocked),
+	  restore the transmitters to their state before the EPO, or unblock
+	  them all.
 
 Userspace uevent handler or kernel platform-specific drivers hooked to the
 rfkill notifier chain:
@@ -331,11 +339,9 @@
 correct event for your switch/button.  These events are emergency power-off
 events when they are trying to turn the transmitters off.  An example of an
 input device which SHOULD generate *_RFKILL_ALL events is the wireless-kill
-switch in a laptop which is NOT a hotkey, but a real switch that kills radios
-in hardware, even if the O.S. has gone to lunch.  An example of an input device
-which SHOULD NOT generate *_RFKILL_ALL events by default, is any sort of hot
-key that does nothing by itself, as well as any hot key that is type-specific
-(e.g. the one for WLAN).
+switch in a laptop which is NOT a hotkey, but a real sliding/rocker switch.
+An example of an input device which SHOULD NOT generate *_RFKILL_ALL events by
+default, is any sort of hot key that is type-specific (e.g. the one for WLAN).
 
 
 3.1 Guidelines for wireless device drivers
diff --git a/Documentation/scheduler/sched-arch.txt b/Documentation/scheduler/sched-arch.txt
index 941615a..d43dbcb 100644
--- a/Documentation/scheduler/sched-arch.txt
+++ b/Documentation/scheduler/sched-arch.txt
@@ -8,7 +8,7 @@
 By default, the switch_to arch function is called with the runqueue
 locked. This is usually not a problem unless switch_to may need to
 take the runqueue lock. This is usually due to a wake up operation in
-the context switch. See include/asm-ia64/system.h for an example.
+the context switch. See arch/ia64/include/asm/system.h for an example.
 
 To request the scheduler call switch_to with the runqueue unlocked,
 you must `#define __ARCH_WANT_UNLOCKED_CTXSW` in a header file
@@ -23,7 +23,7 @@
 introduce a significant interrupt latency by adding the line
 `#define __ARCH_WANT_INTERRUPTS_ON_CTXSW` in the same place as for
 unlocked context switches. This define also implies
-`__ARCH_WANT_UNLOCKED_CTXSW`. See include/asm-arm/system.h for an
+`__ARCH_WANT_UNLOCKED_CTXSW`. See arch/arm/include/asm/system.h for an
 example.
 
 
diff --git a/Documentation/scheduler/sched-design-CFS.txt b/Documentation/scheduler/sched-design-CFS.txt
index eb471c7..8398ca4 100644
--- a/Documentation/scheduler/sched-design-CFS.txt
+++ b/Documentation/scheduler/sched-design-CFS.txt
@@ -273,3 +273,24 @@
 
 	# #Launch gmplayer (or your favourite movie player)
 	# echo <movie_player_pid> > multimedia/tasks
+
+8. Implementation note: user namespaces
+
+User namespaces are intended to be hierarchical.  But they are currently
+only partially implemented.  Each of those has ramifications for CFS.
+
+First, since user namespaces are hierarchical, the /sys/kernel/uids
+presentation is inadequate.  Eventually we will likely want to use sysfs
+tagging to provide private views of /sys/kernel/uids within each user
+namespace.
+
+Second, the hierarchical nature is intended to support completely
+unprivileged use of user namespaces.  So if using user groups, then
+we want the users in a user namespace to be children of the user
+who created it.
+
+That is currently unimplemented.  So instead, every user in a new
+user namespace will receive 1024 shares just like any user in the
+initial user namespace.  Note that at the moment creation of a new
+user namespace requires each of CAP_SYS_ADMIN, CAP_SETUID, and
+CAP_SETGID.
diff --git a/Documentation/sh/kgdb.txt b/Documentation/sh/kgdb.txt
deleted file mode 100644
index 05b4ba8..0000000
--- a/Documentation/sh/kgdb.txt
+++ /dev/null
@@ -1,179 +0,0 @@
-
-This file describes the configuration and behavior of KGDB for the SH
-kernel. Based on a description from Henry Bell <henry.bell@st.com>, it
-has been modified to account for quirks in the current implementation.
-
-Version
-=======
-
-This version of KGDB was written for 2.4.xx kernels for the SH architecture.
-Further documentation is available from the linux-sh project website.
-
-
-Debugging Setup: Host
-======================
-
-The two machines will be connected together via a serial line - this
-should be a null modem cable i.e. with a twist.
-
-On your DEVELOPMENT machine, go to your kernel source directory and
-build the kernel, enabling KGDB support in the "kernel hacking" section.
-This includes the KGDB code, and also makes the kernel be compiled with
-the "-g" option set -- necessary for debugging.
-
-To install this new kernel, use the following installation procedure.
-
-Decide on which tty port you want the machines to communicate, then
-cable them up back-to-back using the null modem.  On the DEVELOPMENT
-machine, you may wish to create an initialization file called .gdbinit
-(in the kernel source directory or in your home directory) to execute 
-commonly-used commands at startup.
-
-A minimal .gdbinit might look like this:
-
-  file vmlinux
-  set remotebaud 115200
-  target remote /dev/ttyS0
-
-Change the "target" definition so that it specifies the tty port that
-you intend to use.  Change the "remotebaud" definition to match the
-data rate that you are going to use for the com line (115200 is the
-default). 
-
-Debugging Setup: Target
-========================
-
-By default, the KGDB stub will communicate with the host GDB using
-ttySC1 at 115200 baud, 8 databits, no parity; these defaults can be
-changed in the kernel configuration. As the kernel starts up, KGDB will
-initialize so that breakpoints, kernel segfaults, and so forth will
-generally enter the debugger.
-
-This behavior can be modified by including the "kgdb" option in the
-kernel command line; this option has the general form:
-
-  kgdb=<ttyspec>,<action>
-
-The <ttyspec> indicates the port to use, and can optionally specify
-baud, parity and databits -- e.g. "ttySC0,9600N8" or "ttySC1,19200".
-
-The <action> can be "halt" or "disabled".  The "halt" action enters the
-debugger via a breakpoint as soon as kgdb is initialized; the "disabled"
-action causes kgdb to ignore kernel segfaults and such until explicitly
-entered by a breakpoint in the code or by external action (sysrq or NMI). 
-
-(Both <ttyspec> and <action> can appear alone, w/o the separating comma.)
-
-For example, if you wish to debug early in kernel startup code, you
-might specify the halt option:
-
-  kgdb=halt
-
-Boot the TARGET machine, which will appear to hang. 
-
-On your DEVELOPMENT machine, cd to the source directory and run the gdb
-program.  (This is likely to be a cross GDB which runs on your host but
-is built for an SH target.) If everything is working correctly you
-should see gdb print out a few lines indicating that a breakpoint has
-been taken.  It will actually show a line of code in the target kernel
-inside the gdbstub activation code.
-
-NOTE: BE SURE TO TERMINATE OR SUSPEND any other host application which
-may be using the same serial port (for example, a terminal emulator you
-have been using to connect to the target boot code.)  Otherwise, data
-from the target may not all get to GDB!
-
-You can now use whatever gdb commands you like to set breakpoints.
-Enter "continue" to start your target machine executing again.  At this
-point the target system will run at full speed until it encounters
-your breakpoint or gets a segment violation in the kernel, or whatever.
-
-Serial Ports: KGDB, Console
-============================
-
-This version of KGDB may not gracefully handle conflict with other
-drivers in the kernel using the same port. If KGDB is configured on the
-same port (and with the same parameters) as the kernel console, or if
-CONFIG_SH_KGDB_CONSOLE is configured, things should be fine (though in
-some cases console messages may appear twice through GDB).  But if the
-KGDB port is not the kernel console and used by another serial driver
-which assumes different serial parameters (e.g. baud rate) KGDB may not
-recover.
-
-Also, when KGDB is entered via sysrq-g (requires CONFIG_KGDB_SYSRQ) and
-the kgdb port uses the same port as the console, detaching GDB will not
-restore the console to working order without the port being re-opened.
-
-Another serious consequence of this is that GDB currently CANNOT break
-into KGDB externally (e.g. via ^C or <BREAK>); unless a breakpoint or
-error is encountered, the only way to enter KGDB after the initial halt
-(see above) is via NMI (CONFIG_KGDB_NMI) or sysrq-g (CONFIG_KGDB_SYSRQ).
-
-Code is included for the basic Hitachi Solution Engine boards to allow
-the use of ttyS0 for KGDB if desired; this is less robust, but may be
-useful in some cases.  (This cannot be selected using the config file, 
-but only through the kernel command line, e.g. "kgdb=ttyS0", though the
-configured defaults for baud rate etc. still apply if not overridden.)
-
-If gdbstub Does Not Work
-========================
-
-If it doesn't work, you will have to troubleshoot it.  Do the easy
-things first like double checking your cabling and data rates.  You
-might try some non-kernel based programs to see if the back-to-back
-connection works properly.  Just something simple like cat /etc/hosts
-/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you
-if you can send data from one machine to the other.  There is no point
-in tearing out your hair in the kernel if the line doesn't work.
-
-If you need to debug the GDB/KGDB communication itself, the gdb commands
-"set debug remote 1" and "set debug serial 1" may be useful, but be
-warned: they produce a lot of output.
-
-Threads
-=======
-
-Each process in a target machine is seen as a gdb thread. gdb thread related
-commands (info threads, thread n) can be used. CONFIG_KGDB_THREAD must
-be defined for this to work.
-
-In this version, kgdb reports PID_MAX (32768) as the process ID for the
-idle process (pid 0), since GDB does not accept 0 as an ID.
-
-Detaching (exiting KGDB)
-=========================
-
-There are two ways to resume full-speed target execution: "continue" and
-"detach". With "continue", GDB inserts any specified breakpoints in the
-target code and resumes execution; the target is still in "gdb mode".
-If a breakpoint or other debug event (e.g. NMI) happens, the target
-halts and communicates with GDB again, which is waiting for it.
-
-With "detach", GDB does *not* insert any breakpoints; target execution
-is resumed and GDB stops communicating (does not wait for the target).
-In this case, the target is no longer in "gdb mode" -- for example,
-console messages no longer get sent separately to the KGDB port, or
-encapsulated for GDB.  If a debug event (e.g. NMI) occurs, the target
-will re-enter "gdb mode" and will display this fact on the console; you
-must give a new "target remote" command to gdb.
-
-NOTE: TO AVOID LOSSING CONSOLE MESSAGES IN CASE THE KERNEL CONSOLE AND
-KGDB USING THE SAME PORT, THE TARGET WAITS FOR ANY INPUT CHARACTER ON
-THE KGDB PORT AFTER A DETACH COMMAND.  For example, after the detach you
-could start a terminal emulator on the same host port and enter a <cr>;
-however, this program must then be terminated or suspended in order to
-use GBD again if KGDB is re-entered.
-
-
-Acknowledgements
-================
-
-This code was mostly generated by Henry Bell <henry.bell@st.com>;
-largely from KGDB by Amit S. Kale <akale@veritas.com> - extracts from
-code by Glenn Engel, Jim Kingdon, David Grothe <dave@gcom.com>, Tigran
-Aivazian <tigran@sco.com>, William Gatliff <bgat@open-widgets.com>, Ben
-Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com> are also
-included. 
-
-Jeremy Siegel
-<jsiegel@mvista.com>
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 394d7d3..841a936 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -757,6 +757,8 @@
     model	- force the model name
     position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF)
     probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)
+    probe_only	- Only probing and no codec initialization (default=off);
+		  Useful to check the initial codec status for debugging
     bdl_pos_adj	- Specifies the DMA IRQ timing delay in samples.
 		Passing -1 will make the driver to choose the appropriate
 		value based on the controller chip.
@@ -772,327 +774,23 @@
 
     This module supports multiple cards and autoprobe.
     
+    See Documentation/sound/alsa/HD-Audio.txt for more details about
+    HD-audio driver.
+
     Each codec may have a model table for different configurations.
     If your machine isn't listed there, the default (usually minimal)
     configuration is set up.  You can pass "model=<name>" option to
     specify a certain model in such a case.  There are different
-    models depending on the codec chip.
-
-	  Model name	Description
-	  ----------    -----------
-	ALC880
-	  3stack	3-jack in back and a headphone out
-	  3stack-digout	3-jack in back, a HP out and a SPDIF out
-	  5stack	5-jack in back, 2-jack in front
-	  5stack-digout	5-jack in back, 2-jack in front, a SPDIF out
-	  6stack	6-jack in back, 2-jack in front
-	  6stack-digout	6-jack with a SPDIF out
-	  w810		3-jack
-	  z71v		3-jack (HP shared SPDIF)
-	  asus		3-jack (ASUS Mobo)
-	  asus-w1v	ASUS W1V
-	  asus-dig	ASUS with SPDIF out
-	  asus-dig2	ASUS with SPDIF out (using GPIO2)
-	  uniwill	3-jack
-	  fujitsu	Fujitsu Laptops (Pi1536)
-	  F1734		2-jack
-	  lg		LG laptop (m1 express dual)
-	  lg-lw		LG LW20/LW25 laptop
-	  tcl		TCL S700
-	  clevo		Clevo laptops (m520G, m665n)
-	  medion	Medion Rim 2150
-	  test		for testing/debugging purpose, almost all controls can be
-			adjusted.  Appearing only when compiled with
-			$CONFIG_SND_DEBUG=y
-	  auto		auto-config reading BIOS (default)
-
-	ALC260
-	  hp		HP machines
-	  hp-3013	HP machines (3013-variant)
-	  hp-dc7600	HP DC7600
-	  fujitsu	Fujitsu S7020
-	  acer		Acer TravelMate
-	  will		Will laptops (PB V7900)
-	  replacer	Replacer 672V
-	  basic		fixed pin assignment (old default model)
-	  test		for testing/debugging purpose, almost all controls can
-			adjusted.  Appearing only when compiled with
-			$CONFIG_SND_DEBUG=y
-	  auto		auto-config reading BIOS (default)
-
-	ALC262
-	  fujitsu	Fujitsu Laptop
-	  hp-bpc	HP xw4400/6400/8400/9400 laptops
-	  hp-bpc-d7000	HP BPC D7000
-	  hp-tc-t5735	HP Thin Client T5735
-	  hp-rp5700	HP RP5700
-	  benq		Benq ED8
-	  benq-t31	Benq T31
-	  hippo		Hippo (ATI) with jack detection, Sony UX-90s
-	  hippo_1	Hippo (Benq) with jack detection
-	  sony-assamd	Sony ASSAMD
-	  toshiba-s06	Toshiba S06
-	  toshiba-rx1	Toshiba RX1
-	  ultra		Samsung Q1 Ultra Vista model
-	  lenovo-3000	Lenovo 3000 y410
-	  nec		NEC Versa S9100
-	  basic		fixed pin assignment w/o SPDIF
-	  auto		auto-config reading BIOS (default)
-
-	ALC267/268
-	  quanta-il1	Quanta IL1 mini-notebook
-	  3stack	3-stack model
-	  toshiba	Toshiba A205
-	  acer		Acer laptops
-	  acer-aspire	Acer Aspire One
-	  dell		Dell OEM laptops (Vostro 1200)
-	  zepto		Zepto laptops
-	  test		for testing/debugging purpose, almost all controls can
-			adjusted.  Appearing only when compiled with
-			$CONFIG_SND_DEBUG=y
-	  auto		auto-config reading BIOS (default)
-
-	ALC269
-	  basic		Basic preset
-	  quanta	Quanta FL1
-	  eeepc-p703	ASUS Eeepc P703 P900A
-	  eeepc-p901	ASUS Eeepc P901 S101
-
-	ALC662/663
-	  3stack-dig	3-stack (2-channel) with SPDIF
-	  3stack-6ch	 3-stack (6-channel)
-	  3stack-6ch-dig 3-stack (6-channel) with SPDIF
-	  6stack-dig	 6-stack with SPDIF
-	  lenovo-101e	 Lenovo laptop
-	  eeepc-p701	ASUS Eeepc P701
-	  eeepc-ep20	ASUS Eeepc EP20
-	  ecs		ECS/Foxconn mobo
-	  m51va		ASUS M51VA
-	  g71v		ASUS G71V
-	  h13		ASUS H13
-	  g50v		ASUS G50V
-	  asus-mode1	ASUS
-	  asus-mode2	ASUS
-	  asus-mode3	ASUS
-	  asus-mode4	ASUS
-	  asus-mode5	ASUS
-	  asus-mode6	ASUS
-	  auto		auto-config reading BIOS (default)
-
-	ALC882/885
-	  3stack-dig	3-jack with SPDIF I/O
-	  6stack-dig	6-jack digital with SPDIF I/O
-	  arima		Arima W820Di1
-	  targa		Targa T8, MSI-1049 T8
-	  asus-a7j	ASUS A7J
-	  asus-a7m	ASUS A7M
-	  macpro	MacPro support
-	  mbp3		Macbook Pro rev3
-	  imac24	iMac 24'' with jack detection
-	  w2jc		ASUS W2JC
-	  auto		auto-config reading BIOS (default)
-
-	ALC883/888
-	  3stack-dig	3-jack with SPDIF I/O
-	  6stack-dig	6-jack digital with SPDIF I/O
-	  3stack-6ch    3-jack 6-channel
-	  3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
-	  6stack-dig-demo  6-jack digital for Intel demo board
-	  acer		Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
-	  acer-aspire	Acer Aspire 9810
-	  medion	Medion Laptops
-	  medion-md2	Medion MD2
-	  targa-dig	Targa/MSI
-	  targa-2ch-dig	Targs/MSI with 2-channel
-	  laptop-eapd   3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
-	  lenovo-101e	Lenovo 101E
-	  lenovo-nb0763	Lenovo NB0763
-	  lenovo-ms7195-dig Lenovo MS7195
-	  lenovo-sky	Lenovo Sky
-	  haier-w66	Haier W66
-	  3stack-hp	HP machines with 3stack (Lucknow, Samba boards)
-	  6stack-dell	Dell machines with 6stack (Inspiron 530)
-	  mitac		Mitac 8252D
-	  clevo-m720	Clevo M720 laptop series
-	  fujitsu-pi2515 Fujitsu AMILO Pi2515
-	  3stack-6ch-intel Intel DG33* boards
-	  auto		auto-config reading BIOS (default)
-
-	ALC861/660
-	  3stack	3-jack
-	  3stack-dig	3-jack with SPDIF I/O
-	  6stack-dig	6-jack with SPDIF I/O
-	  3stack-660	3-jack (for ALC660)
-	  uniwill-m31	Uniwill M31 laptop
-	  toshiba	Toshiba laptop support
-	  asus		Asus laptop support
-	  asus-laptop	ASUS F2/F3 laptops
-	  auto		auto-config reading BIOS (default)
-
-	ALC861VD/660VD
-	  3stack	3-jack
-	  3stack-dig	3-jack with SPDIF OUT
-	  6stack-dig	6-jack with SPDIF OUT
-	  3stack-660	3-jack (for ALC660VD)
-	  3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD)
-	  lenovo	Lenovo 3000 C200
-	  dallas	Dallas laptops
-	  hp		HP TX1000
-	  auto		auto-config reading BIOS (default)
-
-	CMI9880
-	  minimal	3-jack in back
-	  min_fp	3-jack in back, 2-jack in front
-	  full		6-jack in back, 2-jack in front
-	  full_dig	6-jack in back, 2-jack in front, SPDIF I/O
-	  allout	5-jack in back, 2-jack in front, SPDIF out
-	  auto		auto-config reading BIOS (default)
-
-	AD1882 / AD1882A
-	  3stack	3-stack mode (default)
-	  6stack	6-stack mode
-
-	AD1884A / AD1883 / AD1984A / AD1984B
-	  desktop	3-stack desktop (default)
-	  laptop	laptop with HP jack sensing
-	  mobile	mobile devices with HP jack sensing
-	  thinkpad	Lenovo Thinkpad X300
-
-	AD1884
-	  N/A
-
-	AD1981
-	  basic		3-jack (default)
-	  hp		HP nx6320
-	  thinkpad	Lenovo Thinkpad T60/X60/Z60
-	  toshiba	Toshiba U205
-
-	AD1983
-	  N/A
-
-	AD1984
-	  basic		default configuration
-	  thinkpad	Lenovo Thinkpad T61/X61
-	  dell		Dell T3400
-
-	AD1986A
-	  6stack	6-jack, separate surrounds (default)
-	  3stack	3-stack, shared surrounds
-	  laptop	2-channel only (FSC V2060, Samsung M50)
-	  laptop-eapd	2-channel with EAPD (Samsung R65, ASUS A6J)
-	  laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100)
-	  ultra		2-channel with EAPD (Samsung Ultra tablet PC)
-
-	AD1988/AD1988B/AD1989A/AD1989B
-	  6stack	6-jack
-	  6stack-dig	ditto with SPDIF
-	  3stack	3-jack
-	  3stack-dig	ditto with SPDIF
-	  laptop	3-jack with hp-jack automute
-	  laptop-dig	ditto with SPDIF
-	  auto		auto-config reading BIOS (default)
-	
-	Conexant 5045
-	  laptop-hpsense    Laptop with HP sense (old model laptop)
-	  laptop-micsense   Laptop with Mic sense (old model fujitsu)
-	  laptop-hpmicsense Laptop with HP and Mic senses
-	  benq		Benq R55E
-	  test		for testing/debugging purpose, almost all controls
-			can be adjusted.  Appearing only when compiled with
-			$CONFIG_SND_DEBUG=y
-
-	Conexant 5047
-	  laptop	Basic Laptop config 
-	  laptop-hp	Laptop config for some HP models (subdevice 30A5)
-	  laptop-eapd	Laptop config with EAPD support
-	  test		for testing/debugging purpose, almost all controls
-			can be adjusted.  Appearing only when compiled with
-			$CONFIG_SND_DEBUG=y
-
-	Conexant 5051
-	  laptop	Basic Laptop config (default)
-	  hp		HP Spartan laptop
-
-	STAC9200
-	  ref		Reference board
-	  dell-d21	Dell (unknown)
-	  dell-d22	Dell (unknown)
-	  dell-d23	Dell (unknown)
-	  dell-m21	Dell Inspiron 630m, Dell Inspiron 640m
-	  dell-m22	Dell Latitude D620, Dell Latitude D820
-	  dell-m23	Dell XPS M1710, Dell Precision M90
-	  dell-m24	Dell Latitude 120L
-	  dell-m25	Dell Inspiron E1505n
-	  dell-m26	Dell Inspiron 1501
-	  dell-m27	Dell Inspiron E1705/9400
-	  gateway	Gateway laptops with EAPD control
-	  panasonic	Panasonic CF-74
-
-	STAC9205/9254
-	  ref		Reference board
-	  dell-m42	Dell (unknown)
-	  dell-m43	Dell Precision
-	  dell-m44	Dell Inspiron
-
-	STAC9220/9221
-	  ref		Reference board
-	  3stack	D945 3stack
-	  5stack	D945 5stack + SPDIF
-	  intel-mac-v1	Intel Mac Type 1
-	  intel-mac-v2	Intel Mac Type 2
-	  intel-mac-v3	Intel Mac Type 3
-	  intel-mac-v4	Intel Mac Type 4
-	  intel-mac-v5	Intel Mac Type 5
-	  intel-mac-auto Intel Mac (detect type according to subsystem id)
-	  macmini	Intel Mac Mini (equivalent with type 3)
-	  macbook	Intel Mac Book (eq. type 5)
-	  macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3)
-	  macbook-pro	Intel Mac Book Pro 2nd generation (eq. type 3)
-	  imac-intel	Intel iMac (eq. type 2)
-	  imac-intel-20	Intel iMac (newer version) (eq. type 3)
-	  dell-d81	Dell (unknown)
-	  dell-d82	Dell (unknown)
-	  dell-m81	Dell (unknown)
-	  dell-m82	Dell XPS M1210
-
-	STAC9202/9250/9251
-	  ref		Reference board, base config
-	  m2-2		Some Gateway MX series laptops
-	  m6		Some Gateway NX series laptops
-	  pa6		Gateway NX860 series
-
-	STAC9227/9228/9229/927x
-	  ref		Reference board
-	  ref-no-jd	Reference board without HP/Mic jack detection
-	  3stack	D965 3stack
-	  5stack	D965 5stack + SPDIF
-	  dell-3stack	Dell Dimension E520
-	  dell-bios	Fixes with Dell BIOS setup
-
-	STAC92HD71B*
-	  ref		Reference board
-	  dell-m4-1	Dell desktops
-	  dell-m4-2	Dell desktops
-	  dell-m4-3	Dell desktops
-
-	STAC92HD73*
-	  ref		Reference board
-	  no-jd		BIOS setup but without jack-detection
-	  dell-m6-amic	Dell desktops/laptops with analog mics
-	  dell-m6-dmic	Dell desktops/laptops with digital mics
-	  dell-m6	Dell desktops/laptops with both type of mics
-
-	STAC9872
-	  vaio		Setup for VAIO FE550G/SZ110
-	  vaio-ar Setup for VAIO AR
+    models depending on the codec chip.  The list of available models
+    is found in HD-Audio-Models.txt
 
     The model name "genric" is treated as a special case.  When this
     model is given, the driver uses the generic codec parser without
     "codec-patch".  It's sometimes good for testing and debugging.
 
     If the default configuration doesn't work and one of the above
-    matches with your device, report it together with the PCI
-    subsystem ID (output of "lspci -nv") to ALSA BTS or alsa-devel
+    matches with your device, report it together with alsa-info.sh
+    output (with --no-upload option) to kernel bugzilla or alsa-devel
     ML (see the section "Links and Addresses").
 
     power_save and power_save_controller options are for power-saving
@@ -1652,7 +1350,8 @@
     * AuzenTech X-Meridian
     * Bgears b-Enspirer
     * Club3D Theatron DTS
-    * HT-Omega Claro
+    * HT-Omega Claro (plus)
+    * HT-Omega Claro halo (XT)
     * Razer Barracuda AC-1
     * Sondigo Inferno
 
@@ -2409,8 +2108,11 @@
   ALSA project homepage
        http://www.alsa-project.org
 
-  ALSA Bug Tracking System
-       https://bugtrack.alsa-project.org/bugs/
+  Kernel Bugzilla
+       http://bugzilla.kernel.org/
 
   ALSA Developers ML
        mailto:alsa-devel@alsa-project.org
+
+  alsa-info.sh script
+       http://www.alsa-project.org/alsa-info.sh
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
new file mode 100644
index 0000000..4b7ac21
--- /dev/null
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -0,0 +1,348 @@
+  Model name	Description
+  ----------    -----------
+ALC880
+======
+  3stack	3-jack in back and a headphone out
+  3stack-digout	3-jack in back, a HP out and a SPDIF out
+  5stack	5-jack in back, 2-jack in front
+  5stack-digout	5-jack in back, 2-jack in front, a SPDIF out
+  6stack	6-jack in back, 2-jack in front
+  6stack-digout	6-jack with a SPDIF out
+  w810		3-jack
+  z71v		3-jack (HP shared SPDIF)
+  asus		3-jack (ASUS Mobo)
+  asus-w1v	ASUS W1V
+  asus-dig	ASUS with SPDIF out
+  asus-dig2	ASUS with SPDIF out (using GPIO2)
+  uniwill	3-jack
+  fujitsu	Fujitsu Laptops (Pi1536)
+  F1734		2-jack
+  lg		LG laptop (m1 express dual)
+  lg-lw		LG LW20/LW25 laptop
+  tcl		TCL S700
+  clevo		Clevo laptops (m520G, m665n)
+  medion	Medion Rim 2150
+  test		for testing/debugging purpose, almost all controls can be
+		adjusted.  Appearing only when compiled with
+		$CONFIG_SND_DEBUG=y
+  auto		auto-config reading BIOS (default)
+
+ALC260
+======
+  hp		HP machines
+  hp-3013	HP machines (3013-variant)
+  hp-dc7600	HP DC7600
+  fujitsu	Fujitsu S7020
+  acer		Acer TravelMate
+  will		Will laptops (PB V7900)
+  replacer	Replacer 672V
+  basic		fixed pin assignment (old default model)
+  test		for testing/debugging purpose, almost all controls can
+		adjusted.  Appearing only when compiled with
+		$CONFIG_SND_DEBUG=y
+  auto		auto-config reading BIOS (default)
+
+ALC262
+======
+  fujitsu	Fujitsu Laptop
+  hp-bpc	HP xw4400/6400/8400/9400 laptops
+  hp-bpc-d7000	HP BPC D7000
+  hp-tc-t5735	HP Thin Client T5735
+  hp-rp5700	HP RP5700
+  benq		Benq ED8
+  benq-t31	Benq T31
+  hippo		Hippo (ATI) with jack detection, Sony UX-90s
+  hippo_1	Hippo (Benq) with jack detection
+  sony-assamd	Sony ASSAMD
+  toshiba-s06	Toshiba S06
+  toshiba-rx1	Toshiba RX1
+  ultra		Samsung Q1 Ultra Vista model
+  lenovo-3000	Lenovo 3000 y410
+  nec		NEC Versa S9100
+  basic		fixed pin assignment w/o SPDIF
+  auto		auto-config reading BIOS (default)
+
+ALC267/268
+==========
+  quanta-il1	Quanta IL1 mini-notebook
+  3stack	3-stack model
+  toshiba	Toshiba A205
+  acer		Acer laptops
+  acer-dmic	Acer laptops with digital-mic
+  acer-aspire	Acer Aspire One
+  dell		Dell OEM laptops (Vostro 1200)
+  zepto		Zepto laptops
+  test		for testing/debugging purpose, almost all controls can
+		adjusted.  Appearing only when compiled with
+		$CONFIG_SND_DEBUG=y
+  auto		auto-config reading BIOS (default)
+
+ALC269
+======
+  basic		Basic preset
+  quanta	Quanta FL1
+  eeepc-p703	ASUS Eeepc P703 P900A
+  eeepc-p901	ASUS Eeepc P901 S101
+  fujitsu	FSC Amilo
+  auto		auto-config reading BIOS (default)
+
+ALC662/663
+==========
+  3stack-dig	3-stack (2-channel) with SPDIF
+  3stack-6ch	 3-stack (6-channel)
+  3stack-6ch-dig 3-stack (6-channel) with SPDIF
+  6stack-dig	 6-stack with SPDIF
+  lenovo-101e	 Lenovo laptop
+  eeepc-p701	ASUS Eeepc P701
+  eeepc-ep20	ASUS Eeepc EP20
+  ecs		ECS/Foxconn mobo
+  m51va		ASUS M51VA
+  g71v		ASUS G71V
+  h13		ASUS H13
+  g50v		ASUS G50V
+  asus-mode1	ASUS
+  asus-mode2	ASUS
+  asus-mode3	ASUS
+  asus-mode4	ASUS
+  asus-mode5	ASUS
+  asus-mode6	ASUS
+  auto		auto-config reading BIOS (default)
+
+ALC882/885
+==========
+  3stack-dig	3-jack with SPDIF I/O
+  6stack-dig	6-jack digital with SPDIF I/O
+  arima		Arima W820Di1
+  targa		Targa T8, MSI-1049 T8
+  asus-a7j	ASUS A7J
+  asus-a7m	ASUS A7M
+  macpro	MacPro support
+  mbp3		Macbook Pro rev3
+  imac24	iMac 24'' with jack detection
+  w2jc		ASUS W2JC
+  auto		auto-config reading BIOS (default)
+
+ALC883/888
+==========
+  3stack-dig	3-jack with SPDIF I/O
+  6stack-dig	6-jack digital with SPDIF I/O
+  3stack-6ch    3-jack 6-channel
+  3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
+  6stack-dig-demo  6-jack digital for Intel demo board
+  acer		Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
+  acer-aspire	Acer Aspire 9810
+  acer-aspire-4930g Acer Aspire 4930G
+  medion	Medion Laptops
+  medion-md2	Medion MD2
+  targa-dig	Targa/MSI
+  targa-2ch-dig	Targs/MSI with 2-channel
+  laptop-eapd   3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
+  lenovo-101e	Lenovo 101E
+  lenovo-nb0763	Lenovo NB0763
+  lenovo-ms7195-dig Lenovo MS7195
+  lenovo-sky	Lenovo Sky
+  haier-w66	Haier W66
+  3stack-hp	HP machines with 3stack (Lucknow, Samba boards)
+  6stack-dell	Dell machines with 6stack (Inspiron 530)
+  mitac		Mitac 8252D
+  clevo-m720	Clevo M720 laptop series
+  fujitsu-pi2515 Fujitsu AMILO Pi2515
+  fujitsu-xa3530 Fujitsu AMILO XA3530
+  3stack-6ch-intel Intel DG33* boards
+  auto		auto-config reading BIOS (default)
+
+ALC861/660
+==========
+  3stack	3-jack
+  3stack-dig	3-jack with SPDIF I/O
+  6stack-dig	6-jack with SPDIF I/O
+  3stack-660	3-jack (for ALC660)
+  uniwill-m31	Uniwill M31 laptop
+  toshiba	Toshiba laptop support
+  asus		Asus laptop support
+  asus-laptop	ASUS F2/F3 laptops
+  auto		auto-config reading BIOS (default)
+
+ALC861VD/660VD
+==============
+  3stack	3-jack
+  3stack-dig	3-jack with SPDIF OUT
+  6stack-dig	6-jack with SPDIF OUT
+  3stack-660	3-jack (for ALC660VD)
+  3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD)
+  lenovo	Lenovo 3000 C200
+  dallas	Dallas laptops
+  hp		HP TX1000
+  asus-v1s	ASUS V1Sn
+  auto		auto-config reading BIOS (default)
+
+CMI9880
+=======
+  minimal	3-jack in back
+  min_fp	3-jack in back, 2-jack in front
+  full		6-jack in back, 2-jack in front
+  full_dig	6-jack in back, 2-jack in front, SPDIF I/O
+  allout	5-jack in back, 2-jack in front, SPDIF out
+  auto		auto-config reading BIOS (default)
+
+AD1882 / AD1882A
+================
+  3stack	3-stack mode (default)
+  6stack	6-stack mode
+
+AD1884A / AD1883 / AD1984A / AD1984B
+====================================
+  desktop	3-stack desktop (default)
+  laptop	laptop with HP jack sensing
+  mobile	mobile devices with HP jack sensing
+  thinkpad	Lenovo Thinkpad X300
+
+AD1884
+======
+  N/A
+
+AD1981
+======
+  basic		3-jack (default)
+  hp		HP nx6320
+  thinkpad	Lenovo Thinkpad T60/X60/Z60
+  toshiba	Toshiba U205
+
+AD1983
+======
+  N/A
+
+AD1984
+======
+  basic		default configuration
+  thinkpad	Lenovo Thinkpad T61/X61
+  dell		Dell T3400
+
+AD1986A
+=======
+  6stack	6-jack, separate surrounds (default)
+  3stack	3-stack, shared surrounds
+  laptop	2-channel only (FSC V2060, Samsung M50)
+  laptop-eapd	2-channel with EAPD (ASUS A6J)
+  laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100)
+  ultra		2-channel with EAPD (Samsung Ultra tablet PC)
+  samsung	2-channel with EAPD (Samsung R65)
+
+AD1988/AD1988B/AD1989A/AD1989B
+==============================
+  6stack	6-jack
+  6stack-dig	ditto with SPDIF
+  3stack	3-jack
+  3stack-dig	ditto with SPDIF
+  laptop	3-jack with hp-jack automute
+  laptop-dig	ditto with SPDIF
+  auto		auto-config reading BIOS (default)
+
+Conexant 5045
+=============
+  laptop-hpsense    Laptop with HP sense (old model laptop)
+  laptop-micsense   Laptop with Mic sense (old model fujitsu)
+  laptop-hpmicsense Laptop with HP and Mic senses
+  benq		Benq R55E
+  test		for testing/debugging purpose, almost all controls
+		can be adjusted.  Appearing only when compiled with
+		$CONFIG_SND_DEBUG=y
+
+Conexant 5047
+=============
+  laptop	Basic Laptop config 
+  laptop-hp	Laptop config for some HP models (subdevice 30A5)
+  laptop-eapd	Laptop config with EAPD support
+  test		for testing/debugging purpose, almost all controls
+		can be adjusted.  Appearing only when compiled with
+		$CONFIG_SND_DEBUG=y
+
+Conexant 5051
+=============
+  laptop	Basic Laptop config (default)
+  hp		HP Spartan laptop
+
+STAC9200
+========
+  ref		Reference board
+  dell-d21	Dell (unknown)
+  dell-d22	Dell (unknown)
+  dell-d23	Dell (unknown)
+  dell-m21	Dell Inspiron 630m, Dell Inspiron 640m
+  dell-m22	Dell Latitude D620, Dell Latitude D820
+  dell-m23	Dell XPS M1710, Dell Precision M90
+  dell-m24	Dell Latitude 120L
+  dell-m25	Dell Inspiron E1505n
+  dell-m26	Dell Inspiron 1501
+  dell-m27	Dell Inspiron E1705/9400
+  gateway	Gateway laptops with EAPD control
+  panasonic	Panasonic CF-74
+
+STAC9205/9254
+=============
+  ref		Reference board
+  dell-m42	Dell (unknown)
+  dell-m43	Dell Precision
+  dell-m44	Dell Inspiron
+
+STAC9220/9221
+=============
+  ref		Reference board
+  3stack	D945 3stack
+  5stack	D945 5stack + SPDIF
+  intel-mac-v1	Intel Mac Type 1
+  intel-mac-v2	Intel Mac Type 2
+  intel-mac-v3	Intel Mac Type 3
+  intel-mac-v4	Intel Mac Type 4
+  intel-mac-v5	Intel Mac Type 5
+  intel-mac-auto Intel Mac (detect type according to subsystem id)
+  macmini	Intel Mac Mini (equivalent with type 3)
+  macbook	Intel Mac Book (eq. type 5)
+  macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3)
+  macbook-pro	Intel Mac Book Pro 2nd generation (eq. type 3)
+  imac-intel	Intel iMac (eq. type 2)
+  imac-intel-20	Intel iMac (newer version) (eq. type 3)
+  dell-d81	Dell (unknown)
+  dell-d82	Dell (unknown)
+  dell-m81	Dell (unknown)
+  dell-m82	Dell XPS M1210
+
+STAC9202/9250/9251
+==================
+  ref		Reference board, base config
+  m2-2		Some Gateway MX series laptops
+  m6		Some Gateway NX series laptops
+  pa6		Gateway NX860 series
+
+STAC9227/9228/9229/927x
+=======================
+  ref		Reference board
+  ref-no-jd	Reference board without HP/Mic jack detection
+  3stack	D965 3stack
+  5stack	D965 5stack + SPDIF
+  dell-3stack	Dell Dimension E520
+  dell-bios	Fixes with Dell BIOS setup
+
+STAC92HD71B*
+============
+  ref		Reference board
+  dell-m4-1	Dell desktops
+  dell-m4-2	Dell desktops
+  dell-m4-3	Dell desktops
+
+STAC92HD73*
+===========
+  ref		Reference board
+  no-jd		BIOS setup but without jack-detection
+  dell-m6-amic	Dell desktops/laptops with analog mics
+  dell-m6-dmic	Dell desktops/laptops with digital mics
+  dell-m6	Dell desktops/laptops with both type of mics
+
+STAC92HD83*
+===========
+  ref		Reference board
+
+STAC9872
+========
+  vaio		Setup for VAIO FE550G/SZ110
+  vaio-ar Setup for VAIO AR
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt
new file mode 100644
index 0000000..8d68fff
--- /dev/null
+++ b/Documentation/sound/alsa/HD-Audio.txt
@@ -0,0 +1,577 @@
+MORE NOTES ON HD-AUDIO DRIVER
+=============================
+					Takashi Iwai <tiwai@suse.de>
+
+
+GENERAL
+-------
+
+HD-audio is the new standard on-board audio component on modern PCs
+after AC97.  Although Linux has been supporting HD-audio since long
+time ago, there are often problems with new machines.  A part of the
+problem is broken BIOS, and the rest is the driver implementation.
+This document explains the brief trouble-shooting and debugging
+methods for the	HD-audio hardware.
+
+The HD-audio component consists of two parts: the controller chip and 
+the codec chips on the HD-audio bus.  Linux provides a single driver
+for all controllers, snd-hda-intel.  Although the driver name contains
+a word of a well-known harware vendor, it's not specific to it but for
+all controller chips by other companies.  Since the HD-audio
+controllers are supposed to be compatible, the single snd-hda-driver
+should work in most cases.  But, not surprisingly, there are known
+bugs and issues specific to each controller type.  The snd-hda-intel
+driver has a bunch of workarounds for these as described below.
+
+A controller may have multiple codecs.  Usually you have one audio
+codec and optionally one modem codec.  In theory, there might be
+multiple audio codecs, e.g. for analog and digital outputs, and the
+driver might not work properly because of conflict of mixer elements.
+This should be fixed in future if such hardware really exists.
+
+The snd-hda-intel driver has several different codec parsers depending
+on the codec.  It has a generic parser as a fallback, but this
+functionality is fairly limited until now.  Instead of the generic
+parser, usually the codec-specific parser (coded in patch_*.c) is used
+for the codec-specific implementations.  The details about the
+codec-specific problems are explained in the later sections.
+
+If you are interested in the deep debugging of HD-audio, read the
+HD-audio specification at first.  The specification is found on
+Intel's web page, for example:
+
+- http://www.intel.com/standards/hdaudio/
+
+
+HD-AUDIO CONTROLLER
+-------------------
+
+DMA-Position Problem
+~~~~~~~~~~~~~~~~~~~~
+The most common problem of the controller is the inaccurate DMA
+pointer reporting.  The DMA pointer for playback and capture can be
+read in two ways, either via a LPIB register or via a position-buffer
+map.  As default the driver tries to read from the io-mapped
+position-buffer, and falls back to LPIB if the position-buffer appears
+dead.  However, this detection isn't perfect on some devices.  In such
+a case, you can change the default method via `position_fix` option.
+
+`position_fix=1` means to use LPIB method explicitly.
+`position_fix=2` means to use the position-buffer.  0 is the default
+value, the automatic check and fallback to LPIB as described in the
+above.  If you get a problem of repeated sounds, this option might
+help.
+
+In addition to that, every controller is known to be broken regarding
+the wake-up timing.  It wakes up a few samples before actually
+processing the data on the buffer.  This caused a lot of problems, for
+example, with ALSA dmix or JACK.  Since 2.6.27 kernel, the driver puts
+an artificial delay to the wake up timing.  This delay is controlled
+via `bdl_pos_adj` option. 
+
+When `bdl_pos_adj` is a negative value (as default), it's assigned to
+an appropriate value depending on the controller chip.  For Intel
+chips, it'd be 1 while it'd be 32 for others.  Usually this works.
+Only in case it doesn't work and you get warning messages, you should
+change this parameter to other values.
+
+
+Codec-Probing Problem
+~~~~~~~~~~~~~~~~~~~~~
+A less often but a more severe problem is the codec probing.  When
+BIOS reports the available codec slots wrongly, the driver gets
+confused and tries to access the non-existing codec slot.  This often
+results in the total screw-up, and destructs the further communication
+with the codec chips.  The symptom appears usually as error messages
+like:
+------------------------------------------------------------------------
+  hda_intel: azx_get_response timeout, switching to polling mode:
+        last cmd=0x12345678
+  hda_intel: azx_get_response timeout, switching to single_cmd mode:
+        last cmd=0x12345678
+------------------------------------------------------------------------
+
+The first line is a warning, and this is usually relatively harmless.
+It means that the codec response isn't notified via an IRQ.  The
+driver uses explicit polling method to read the response.  It gives
+very slight CPU overhead, but you'd unlikely notice it.
+
+The second line is, however, a fatal error.  If this happens, usually
+it means that something is really wrong.  Most likely you are
+accessing a non-existing codec slot.
+
+Thus, if the second error message appears, try to narrow the probed
+codec slots via `probe_mask` option.  It's a bitmask, and each bit
+corresponds to the codec slot.  For example, to probe only the first
+slot, pass `probe_mask=1`.  For the first and the third slots, pass
+`probe_mask=5` (where 5 = 1 | 4), and so on.
+
+Since 2.6.29 kernel, the driver has a more robust probing method, so
+this error might happen rarely, though.
+
+
+Interrupt Handling
+~~~~~~~~~~~~~~~~~~
+In rare but some cases, the interrupt isn't properly handled as
+default.  You would notice this by the DMA transfer error reported by
+ALSA PCM core, for example.  Using MSI might help in such a case.
+Pass `enable_msi=1` option for enabling MSI.
+
+
+HD-AUDIO CODEC
+--------------
+
+Model Option
+~~~~~~~~~~~~
+The most common problem regarding the HD-audio driver is the
+unsupported codec features or the mismatched device configuration.
+Most of codec-specific code has several preset models, either to
+override the BIOS setup or to provide more comprehensive features.
+
+The driver checks PCI SSID and looks through the static configuration
+table until any matching entry is found.  If you have a new machine,
+you may see a message like below:
+------------------------------------------------------------------------
+    hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...
+------------------------------------------------------------------------
+Even if you see such a message, DON'T PANIC.  Take a deep breath and
+keep your towel.  First of all, it's an informational message, no
+warning, no error.  This means that the PCI SSID of your device isn't
+listed in the known preset model (white-)list.  But, this doesn't mean
+that the driver is broken.  Many codec-drivers provide the automatic
+configuration mechanism based on the BIOS setup.
+
+The HD-audio codec has usually "pin" widgets, and BIOS sets the default
+configuration of each pin, which indicates the location, the
+connection type, the jack color, etc.  The HD-audio driver can guess
+the right connection judging from these default configuration values.
+However -- some codec-support codes, such as patch_analog.c, don't
+support the automatic probing (yet as of 2.6.28).  And, BIOS is often,
+yes, pretty often broken.  It sets up wrong values and screws up the
+driver.
+
+The preset model is provided basically to overcome such a situation.
+When the matching preset model is found in the white-list, the driver
+assumes the static configuration of that preset and builds the mixer
+elements and PCM streams based on the static information.  Thus, if
+you have a newer machine with a slightly different PCI SSID from the
+existing one, you may have a good chance to re-use the same model.
+You can pass the `model` option to specify the preset model instead of
+PCI SSID look-up.
+
+What `model` option values are available depends on the codec chip.
+Check your codec chip from the codec proc file (see "Codec Proc-File"
+section below).  It will show the vendor/product name of your codec
+chip.  Then, see Documentation/sound/alsa/HD-Audio-Modelstxt file,
+the section of HD-audio driver.  You can find a list of codecs
+and `model` options belonging to each codec.  For example, for Realtek
+ALC262 codec chip, pass `model=ultra` for devices that are compatible
+with Samsung Q1 Ultra.
+
+Thus, the first thing you can do for any brand-new, unsupported and
+non-working HD-audio hardware is to check HD-audio codec and several
+different `model` option values.  If you have a luck, some of them
+might suit with your device well.
+
+Some codecs such as ALC880 have a special model option `model=test`.
+This configures the driver to provide as many mixer controls as
+possible for every single pin feature except for the unsolicited
+events (and maybe some other specials).  Adjust each mixer element and
+try the I/O in the way of trial-and-error until figuring out the whole
+I/O pin mappings.
+
+Note that `model=generic` has a special meaning.  It means to use the
+generic parser regardless of the codec.  Usually the codec-specific
+parser is much better than the generic parser (as now).  Thus this
+option is more about the debugging purpose.
+
+
+Speaker and Headphone Output
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+One of the most frequent (and obvious) bugs with HD-audio is the
+silent output from either or both of a built-in speaker and a
+headphone jack.  In general, you should try a headphone output at
+first.  A speaker output often requires more additional controls like
+the external amplifier bits.  Thus a headphone output has a slightly
+better chance.
+
+Before making a bug report, double-check whether the mixer is set up
+correctly.  The recent version of snd-hda-intel driver provides mostly
+"Master" volume control as well as "Front" volume (where Front
+indicates the front-channels).  In addition, there can be individual
+"Headphone" and "Speaker" controls.
+
+Ditto for the speaker output.  There can be "External Amplifier"
+switch on some codecs.  Turn on this if present.
+
+Another related problem is the automatic mute of speaker output by
+headphone plugging.  This feature is implemented in most cases, but
+not on every preset model or codec-support code.
+
+In anyway, try a different model option if you have such a problem.
+Some other models may match better and give you more matching
+functionality.  If none of the available models works, send a bug
+report.  See the bug report section for details.
+
+If you are masochistic enough to debug the driver problem, note the
+following:
+
+- The speaker (and the headphone, too) output often requires the
+  external amplifier.  This can be set usually via EAPD verb or a
+  certain GPIO.  If the codec pin supports EAPD, you have a better
+  chance via SET_EAPD_BTL verb (0x70c).  On others, GPIO pin (mostly
+  it's either GPIO0 or GPIO1) may turn on/off EAPD.
+- Some Realtek codecs require special vendor-specific coefficients to
+  turn on the amplifier.  See patch_realtek.c.
+- IDT codecs may have extra power-enable/disable controls on each
+  analog pin.  See patch_sigmatel.c.
+- Very rare but some devices don't accept the pin-detection verb until
+  triggered.  Issuing GET_PIN_SENSE verb (0xf09) may result in the
+  codec-communication stall.  Some examples are found in
+  patch_realtek.c.
+
+
+Capture Problems
+~~~~~~~~~~~~~~~~
+The capture problems are often because of missing setups of mixers.
+Thus, before submitting a bug report, make sure that you set up the
+mixer correctly.  For example, both "Capture Volume" and "Capture
+Switch" have to be set properly in addition to the right "Capture
+Source" or "Input Source" selection.  Some devices have "Mic Boost"
+volume or switch.
+
+When the PCM device is opened via "default" PCM (without pulse-audio
+plugin), you'll likely have "Digital Capture Volume" control as well.
+This is provided for the extra gain/attenuation of the signal in
+software, especially for the inputs without the hardware volume
+control such as digital microphones.  Unless really needed, this
+should be set to exactly 50%, corresponding to 0dB -- neither extra
+gain nor attenuation.  When you use "hw" PCM, i.e., a raw access PCM,
+this control will have no influence, though.
+
+It's known that some codecs / devices have fairly bad analog circuits,
+and the recorded sound contains a certain DC-offset.  This is no bug
+of the driver.
+
+Most of modern laptops have no analog CD-input connection.  Thus, the
+recording from CD input won't work in many cases although the driver
+provides it as the capture source.  Use CDDA instead.
+
+The automatic switching of the built-in and external mic per plugging
+is implemented on some codec models but not on every model.  Partly
+because of my laziness but mostly lack of testers.  Feel free to
+submit the improvement patch to the author.
+
+
+Direct Debugging
+~~~~~~~~~~~~~~~~
+If no model option gives you a better result, and you are a tough guy
+to fight against evil, try debugging via hitting the raw HD-audio
+codec verbs to the device.  Some tools are available: hda-emu and
+hda-analyzer.  The detailed description is found in the sections
+below.  You'd need to enable hwdep for using these tools.  See "Kernel
+Configuration" section.
+
+
+OTHER ISSUES
+------------
+
+Kernel Configuration
+~~~~~~~~~~~~~~~~~~~~
+In general, I recommend you to enable the sound debug option,
+`CONFIG_SND_DEBUG=y`, no matter whether you are debugging or not.
+This enables snd_printd() macro and others, and you'll get additional
+kernel messages at probing.
+
+In addition, you can enable `CONFIG_SND_DEBUG_VERBOSE=y`.  But this
+will give you far more messages.  Thus turn this on only when you are
+sure to want it.
+
+Don't forget to turn on the appropriate `CONFIG_SND_HDA_CODEC_*`
+options.  Note that each of them corresponds to the codec chip, not
+the controller chip.  Thus, even if lspci shows the Nvidia controller,
+you may need to choose the option for other vendors.  If you are
+unsure, just select all yes.
+
+`CONFIG_SND_HDA_HWDEP` is a useful option for debugging the driver.
+When this is enabled, the driver creates hardware-dependent devices
+(one per each codec), and you have a raw access to the device via
+these device files.  For example, `hwC0D2` will be created for the
+codec slot #2 of the first card (#0).  For debug-tools such as
+hda-verb and hda-analyzer, the hwdep device has to be enabled.
+Thus, it'd be better to turn this on always.
+
+`CONFIG_SND_HDA_RECONFIG` is a new option, and this depends on the
+hwdep option above.  When enabled, you'll have some sysfs files under
+the corresponding hwdep directory.  See "HD-audio reconfiguration"
+section below.
+
+`CONFIG_SND_HDA_POWER_SAVE` option enables the power-saving feature.
+See "Power-saving" section below.
+
+
+Codec Proc-File
+~~~~~~~~~~~~~~~
+The codec proc-file is a treasure-chest for debugging HD-audio.
+It shows most of useful information of each codec widget.
+
+The proc file is located in /proc/asound/card*/codec#*, one file per
+each codec slot.  You can know the codec vendor, product id and
+names, the type of each widget, capabilities and so on.
+This file, however, doesn't show the jack sensing state, so far.  This
+is because the jack-sensing might be depending on the trigger state.
+
+This file will be picked up by the debug tools, and also it can be fed
+to the emulator as the primary codec information.  See the debug tools
+section below.
+
+This proc file can be also used to check whether the generic parser is
+used.  When the generic parser is used, the vendor/product ID name
+will appear as "Realtek ID 0262", instead of "Realtek ALC262".
+
+
+HD-Audio Reconfiguration
+~~~~~~~~~~~~~~~~~~~~~~~~
+This is an experimental feature to allow you re-configure the HD-audio
+codec dynamically without reloading the driver.  The following sysfs
+files are available under each codec-hwdep device directory (e.g. 
+/sys/class/sound/hwC0D0):
+
+vendor_id::
+  Shows the 32bit codec vendor-id hex number.  You can change the
+  vendor-id value by writing to this file.
+subsystem_id::
+  Shows the 32bit codec subsystem-id hex number.  You can change the
+  subsystem-id value by writing to this file.
+revision_id::
+  Shows the 32bit codec revision-id hex number.  You can change the
+  revision-id value by writing to this file.
+afg::
+  Shows the AFG ID.  This is read-only.
+mfg::
+  Shows the MFG ID.  This is read-only.
+name::
+  Shows the codec name string.  Can be changed by writing to this
+  file.
+modelname::
+  Shows the currently set `model` option.  Can be changed by writing
+  to this file.
+init_verbs::
+  The extra verbs to execute at initialization.  You can add a verb by
+  writing to this file.  Pass tree numbers, nid, verb and parameter.
+hints::
+  Shows hint strings for codec parsers for any use.  Right now it's
+  not used.
+reconfig::
+  Triggers the codec re-configuration.  When any value is written to
+  this file, the driver re-initialize and parses the codec tree
+  again.  All the changes done by the sysfs entries above are taken
+  into account.
+clear::
+  Resets the codec, removes the mixer elements and PCM stuff of the
+  specified codec, and clear all init verbs and hints.
+
+
+Power-Saving
+~~~~~~~~~~~~
+The power-saving is a kind of auto-suspend of the device.  When the
+device is inactive for a certain time, the device is automatically
+turned off to save the power.  The time to go down is specified via
+`power_save` module option, and this option can be changed dynamically
+via sysfs.
+
+The power-saving won't work when the analog loopback is enabled on
+some codecs.  Make sure that you mute all unneeded signal routes when
+you want the power-saving.
+
+The power-saving feature might cause audible click noises at each
+power-down/up depending on the device.  Some of them might be
+solvable, but some are hard, I'm afraid.  Some distros such as
+openSUSE enables the power-saving feature automatically when the power
+cable is unplugged.  Thus, if you hear noises, suspect first the
+power-saving.  See /sys/module/snd_hda_intel/parameters/power_save to
+check the current value.  If it's non-zero, the feature is turned on.
+
+
+Development Tree
+~~~~~~~~~~~~~~~~
+The latest development codes for HD-audio are found on sound git tree:
+
+- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
+
+The master branch or for-next branches can be used as the main
+development branches in general while the HD-audio specific patches
+are committed in topic/hda branch.
+
+If you are using the latest Linus tree, it'd be better to pull the
+above GIT tree onto it.  If you are using the older kernels, an easy
+way to try the latest ALSA code is to build from the snapshot
+tarball.  There are daily tarballs and the latest snapshot tarball.
+All can be built just like normal alsa-driver release packages, that
+is, installed via the usual spells: configure, make and make
+install(-modules).  See INSTALL in the package.  The snapshot tarballs
+are found at:
+
+- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/
+
+
+Sending a Bug Report
+~~~~~~~~~~~~~~~~~~~~
+If any model or module options don't work for your device, it's time
+to send a bug report to the developers.  Give the following in your
+bug report:
+
+- Hardware vendor, product and model names
+- Kernel version (and ALSA-driver version if you built externally)
+- `alsa-info.sh` output; run with `--no-upload` option.  See the
+  section below about alsa-info
+
+If it's a regression, at best, send alsa-info outputs of both working
+and non-working kernels.  This is really helpful because we can
+compare the codec registers directly.
+
+Send a bug report either the followings:
+
+kernel-bugzilla::
+  http://bugme.linux-foundation.org/
+alsa-devel ML::
+  alsa-devel@alsa-project.org
+
+
+DEBUG TOOLS
+-----------
+
+This section describes some tools available for debugging HD-audio
+problems.
+
+alsa-info
+~~~~~~~~~
+The script `alsa-info.sh` is a very useful tool to gather the audio
+device information.  You can fetch the latest version from:
+
+- http://www.alsa-project.org/alsa-info.sh
+
+Run this script as root, and it will gather the important information
+such as the module lists, module parameters, proc file contents
+including the codec proc files, mixer outputs and the control
+elements.  As default, it will store the information onto a web server
+on alsa-project.org.  But, if you send a bug report, it'd be better to
+run with `--no-upload` option, and attach the generated file.
+
+There are some other useful options.  See `--help` option output for
+details.
+
+
+hda-verb
+~~~~~~~~
+hda-verb is a tiny program that allows you to access the HD-audio
+codec directly.  You can execute a raw HD-audio codec verb with this.
+This program accesses the hwdep device, thus you need to enable the
+kernel config `CONFIG_SND_HDA_HWDEP=y` beforehand.
+
+The hda-verb program takes four arguments: the hwdep device file, the
+widget NID, the verb and the parameter.  When you access to the codec
+on the slot 2 of the card 0, pass /dev/snd/hwC0D2 to the first
+argument, typically.  (However, the real path name depends on the
+system.)
+
+The second parameter is the widget number-id to access.  The third
+parameter can be either a hex/digit number or a string corresponding
+to a verb.  Similarly, the last parameter is the value to write, or
+can be a string for the parameter type.
+
+------------------------------------------------------------------------
+  % hda-verb /dev/snd/hwC0D0 0x12 0x701 2
+  nid = 0x12, verb = 0x701, param = 0x2
+  value = 0x0
+
+  % hda-verb /dev/snd/hwC0D0 0x0 PARAMETERS VENDOR_ID
+  nid = 0x0, verb = 0xf00, param = 0x0
+  value = 0x10ec0262
+
+  % hda-verb /dev/snd/hwC0D0 2 set_a 0xb080
+  nid = 0x2, verb = 0x300, param = 0xb080
+  value = 0x0
+------------------------------------------------------------------------
+
+Although you can issue any verbs with this program, the driver state
+won't be always updated.  For example, the volume values are usually
+cached in the driver, and thus changing the widget amp value directly
+via hda-verb won't change the mixer value.
+
+The hda-verb program is found in the ftp directory:
+
+- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/
+
+Also a git repository is available:
+
+- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-verb.git
+
+See README file in the tarball for more details about hda-verb
+program.
+
+
+hda-analyzer
+~~~~~~~~~~~~
+hda-analyzer provides a graphical interface to access the raw HD-audio
+control, based on pyGTK2 binding.  It's a more powerful version of
+hda-verb.  The program gives you an easy-to-use GUI stuff for showing
+the widget information and adjusting the amp values, as well as the
+proc-compatible output.
+
+The hda-analyzer is a part of alsa.git repository in
+alsa-project.org:
+
+- http://git.alsa-project.org/?p=alsa.git;a=tree;f=hda-analyzer
+
+
+Codecgraph
+~~~~~~~~~~
+Codecgraph is a utility program to generate a graph and visualizes the
+codec-node connection of a codec chip.  It's especially useful when
+you analyze or debug a codec without a proper datasheet.  The program
+parses the given codec proc file and converts to SVG via graphiz
+program.
+
+The tarball and GIT trees are found in the web page at:
+
+- http://helllabs.org/codecgraph/
+
+
+hda-emu
+~~~~~~~
+hda-emu is an HD-audio emulator.  The main purpose of this program is
+to debug an HD-audio codec without the real hardware.  Thus, it
+doesn't emulate the behavior with the real audio I/O, but it just
+dumps the codec register changes and the ALSA-driver internal changes
+at probing and operating the HD-audio driver.
+
+The program requires a codec proc-file to simulate.  Get a proc file
+for the target codec beforehand, or pick up an example codec from the
+codec proc collections in the tarball.  Then, run the program with the
+proc file, and the hda-emu program will start parsing the codec file
+and simulates the HD-audio driver:
+
+------------------------------------------------------------------------
+  % hda-emu codecs/stac9200-dell-d820-laptop
+  # Parsing..
+  hda_codec: Unknown model for STAC9200, using BIOS defaults
+  hda_codec: pin nid 08 bios pin config 40c003fa
+  ....
+------------------------------------------------------------------------
+
+The program gives you only a very dumb command-line interface.  You
+can get a proc-file dump at the current state, get a list of control
+(mixer) elements, set/get the control element value, simulate the PCM
+operation, the jack plugging simulation, etc.
+
+The package is found in:
+
+- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/
+
+A git repository is available:
+
+- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-emu.git
+
+See README file in the tarball for more details about hda-emu
+program.
diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt
index f738b29..bba2dbb 100644
--- a/Documentation/sound/alsa/Procfile.txt
+++ b/Documentation/sound/alsa/Procfile.txt
@@ -153,6 +153,16 @@
 	Shows the general codec information and the attribute of each
 	widget node.
 
+card*/eld#*
+	Available for HDMI or DisplayPort interfaces.
+	Shows ELD(EDID Like Data) info retrieved from the attached HDMI sink,
+	and describes its audio capabilities and configurations.
+
+	Some ELD fields may be modified by doing `echo name hex_value > eld#*`.
+	Only do this if you are sure the HDMI sink provided value is wrong.
+	And if that makes your HDMI audio work, please report to us so that we
+	can fix it in future kernel releases.
+
 
 Sequencer Information
 ---------------------
diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt
index f370e7d..bab7711 100644
--- a/Documentation/sound/alsa/soc/machine.txt
+++ b/Documentation/sound/alsa/soc/machine.txt
@@ -9,7 +9,7 @@
 the following struct:-
 
 /* SoC machine */
-struct snd_soc_machine {
+struct snd_soc_card {
 	char *name;
 
 	int (*probe)(struct platform_device *pdev);
@@ -67,10 +67,10 @@
 	.ops = &corgi_ops,
 };
 
-struct snd_soc_machine then sets up the machine with it's DAIs. e.g.
+struct snd_soc_card then sets up the machine with it's DAIs. e.g.
 
 /* corgi audio machine driver */
-static struct snd_soc_machine snd_soc_machine_corgi = {
+static struct snd_soc_card snd_soc_corgi = {
 	.name = "Corgi",
 	.dai_link = &corgi_dai,
 	.num_links = 1,
@@ -90,7 +90,7 @@
 
 /* corgi audio subsystem */
 static struct snd_soc_device corgi_snd_devdata = {
-	.machine = &snd_soc_machine_corgi,
+	.machine = &snd_soc_corgi,
 	.platform = &pxa2xx_soc_platform,
 	.codec_dev = &soc_codec_dev_wm8731,
 	.codec_data = &corgi_wm8731_setup,
diff --git a/Documentation/tracepoints.txt b/Documentation/tracepoints.txt
index 5d354e1..6f0a044 100644
--- a/Documentation/tracepoints.txt
+++ b/Documentation/tracepoints.txt
@@ -3,28 +3,30 @@
 			    Mathieu Desnoyers
 
 
-This document introduces Linux Kernel Tracepoints and their use. It provides
-examples of how to insert tracepoints in the kernel and connect probe functions
-to them and provides some examples of probe functions.
+This document introduces Linux Kernel Tracepoints and their use. It
+provides examples of how to insert tracepoints in the kernel and
+connect probe functions to them and provides some examples of probe
+functions.
 
 
 * Purpose of tracepoints
 
-A tracepoint placed in code provides a hook to call a function (probe) that you
-can provide at runtime. A tracepoint can be "on" (a probe is connected to it) or
-"off" (no probe is attached). When a tracepoint is "off" it has no effect,
-except for adding a tiny time penalty (checking a condition for a branch) and
-space penalty (adding a few bytes for the function call at the end of the
-instrumented function and adds a data structure in a separate section).  When a
-tracepoint is "on", the function you provide is called each time the tracepoint
-is executed, in the execution context of the caller. When the function provided
-ends its execution, it returns to the caller (continuing from the tracepoint
-site).
+A tracepoint placed in code provides a hook to call a function (probe)
+that you can provide at runtime. A tracepoint can be "on" (a probe is
+connected to it) or "off" (no probe is attached). When a tracepoint is
+"off" it has no effect, except for adding a tiny time penalty
+(checking a condition for a branch) and space penalty (adding a few
+bytes for the function call at the end of the instrumented function
+and adds a data structure in a separate section).  When a tracepoint
+is "on", the function you provide is called each time the tracepoint
+is executed, in the execution context of the caller. When the function
+provided ends its execution, it returns to the caller (continuing from
+the tracepoint site).
 
 You can put tracepoints at important locations in the code. They are
 lightweight hooks that can pass an arbitrary number of parameters,
-which prototypes are described in a tracepoint declaration placed in a header
-file.
+which prototypes are described in a tracepoint declaration placed in a
+header file.
 
 They can be used for tracing and performance accounting.
 
@@ -42,14 +44,16 @@
 
 #include <linux/tracepoint.h>
 
-DEFINE_TRACE(subsys_eventname,
-	TPPTOTO(int firstarg, struct task_struct *p),
+DECLARE_TRACE(subsys_eventname,
+	TPPROTO(int firstarg, struct task_struct *p),
 	TPARGS(firstarg, p));
 
 In subsys/file.c (where the tracing statement must be added) :
 
 #include <trace/subsys.h>
 
+DEFINE_TRACE(subsys_eventname);
+
 void somefct(void)
 {
 	...
@@ -61,31 +65,41 @@
 - subsys_eventname is an identifier unique to your event
     - subsys is the name of your subsystem.
     - eventname is the name of the event to trace.
-- TPPTOTO(int firstarg, struct task_struct *p) is the prototype of the function
-  called by this tracepoint.
-- TPARGS(firstarg, p) are the parameters names, same as found in the prototype.
 
-Connecting a function (probe) to a tracepoint is done by providing a probe
-(function to call) for the specific tracepoint through
+- TPPROTO(int firstarg, struct task_struct *p) is the prototype of the
+  function called by this tracepoint.
+
+- TPARGS(firstarg, p) are the parameters names, same as found in the
+  prototype.
+
+Connecting a function (probe) to a tracepoint is done by providing a
+probe (function to call) for the specific tracepoint through
 register_trace_subsys_eventname().  Removing a probe is done through
-unregister_trace_subsys_eventname(); it will remove the probe sure there is no
-caller left using the probe when it returns. Probe removal is preempt-safe
-because preemption is disabled around the probe call. See the "Probe example"
-section below for a sample probe module.
+unregister_trace_subsys_eventname(); it will remove the probe.
 
-The tracepoint mechanism supports inserting multiple instances of the same
-tracepoint, but a single definition must be made of a given tracepoint name over
-all the kernel to make sure no type conflict will occur. Name mangling of the
-tracepoints is done using the prototypes to make sure typing is correct.
-Verification of probe type correctness is done at the registration site by the
-compiler. Tracepoints can be put in inline functions, inlined static functions,
-and unrolled loops as well as regular functions.
+tracepoint_synchronize_unregister() must be called before the end of
+the module exit function to make sure there is no caller left using
+the probe. This, and the fact that preemption is disabled around the
+probe call, make sure that probe removal and module unload are safe.
+See the "Probe example" section below for a sample probe module.
 
-The naming scheme "subsys_event" is suggested here as a convention intended
-to limit collisions. Tracepoint names are global to the kernel: they are
-considered as being the same whether they are in the core kernel image or in
-modules.
+The tracepoint mechanism supports inserting multiple instances of the
+same tracepoint, but a single definition must be made of a given
+tracepoint name over all the kernel to make sure no type conflict will
+occur. Name mangling of the tracepoints is done using the prototypes
+to make sure typing is correct. Verification of probe type correctness
+is done at the registration site by the compiler. Tracepoints can be
+put in inline functions, inlined static functions, and unrolled loops
+as well as regular functions.
 
+The naming scheme "subsys_event" is suggested here as a convention
+intended to limit collisions. Tracepoint names are global to the
+kernel: they are considered as being the same whether they are in the
+core kernel image or in modules.
+
+If the tracepoint has to be used in kernel modules, an
+EXPORT_TRACEPOINT_SYMBOL_GPL() or EXPORT_TRACEPOINT_SYMBOL() can be
+used to export the defined tracepoints.
 
 * Probe / tracepoint example
 
diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt
index 83c0033..fcdc62b 100644
--- a/Documentation/x86/boot.txt
+++ b/Documentation/x86/boot.txt
@@ -349,7 +349,7 @@
 	3  SYSLINUX
 	4  EtherBoot
 	5  ELILO
-	7  GRuB
+	7  GRUB
 	8  U-BOOT
 	9  Xen
 	A  Gujin
@@ -537,8 +537,8 @@
 Offset/size:	0x248/4
 Protocol:	2.08+
 
-  If non-zero then this field contains the offset from the end of the
-  real-mode code to the payload.
+  If non-zero then this field contains the offset from the beginning
+  of the protected-mode code to the payload.
 
   The payload may be compressed. The format of both the compressed and
   uncompressed data should be determined using the standard magic
diff --git a/Documentation/x86/pat.txt b/Documentation/x86/pat.txt
index c93ff5f..cf08c9f 100644
--- a/Documentation/x86/pat.txt
+++ b/Documentation/x86/pat.txt
@@ -80,6 +80,30 @@
                        |          |            |                  |
 -------------------------------------------------------------------
 
+Advanced APIs for drivers
+-------------------------
+A. Exporting pages to users with remap_pfn_range, io_remap_pfn_range,
+vm_insert_pfn
+
+Drivers wanting to export some pages to userspace do it by using mmap
+interface and a combination of
+1) pgprot_noncached()
+2) io_remap_pfn_range() or remap_pfn_range() or vm_insert_pfn()
+
+With PAT support, a new API pgprot_writecombine is being added. So, drivers can
+continue to use the above sequence, with either pgprot_noncached() or
+pgprot_writecombine() in step 1, followed by step 2.
+
+In addition, step 2 internally tracks the region as UC or WC in memtype
+list in order to ensure no conflicting mapping.
+
+Note that this set of APIs only works with IO (non RAM) regions. If driver
+wants to export a RAM region, it has to do set_memory_uc() or set_memory_wc()
+as step 0 above and also track the usage of those pages and use set_memory_wb()
+before the page is freed to free pool.
+
+
+
 Notes:
 
 -- in the above table mean "Not suggested usage for the API". Some of the --'s
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
index f6d561a..34c1304 100644
--- a/Documentation/x86/x86_64/boot-options.txt
+++ b/Documentation/x86/x86_64/boot-options.txt
@@ -79,17 +79,6 @@
   Report when timer interrupts are lost because some code turned off
   interrupts for too long.
 
-  nmi_watchdog=NUMBER[,panic]
-  NUMBER can be:
-  0 don't use an NMI watchdog
-  1 use the IO-APIC timer for the NMI watchdog
-  2 use the local APIC for the NMI watchdog using a performance counter. Note
-  This will use one performance counter and the local APIC's performance
-  vector.
-  When panic is specified panic when an NMI watchdog timeout occurs.
-  This is useful when you use a panic=... timeout and need the box
-  quickly up again.
-
   nohpet
   Don't use the HPET timer.
 
diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt
index efce750..29b52b1 100644
--- a/Documentation/x86/x86_64/mm.txt
+++ b/Documentation/x86/x86_64/mm.txt
@@ -6,7 +6,7 @@
 0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm
 hole caused by [48:63] sign extension
 ffff800000000000 - ffff80ffffffffff (=40 bits) guard hole
-ffff810000000000 - ffffc0ffffffffff (=46 bits) direct mapping of all phys. memory
+ffff880000000000 - ffffc0ffffffffff (=57 TB) direct mapping of all phys. memory
 ffffc10000000000 - ffffc1ffffffffff (=40 bits) hole
 ffffc20000000000 - ffffe1ffffffffff (=45 bits) vmalloc/ioremap space
 ffffe20000000000 - ffffe2ffffffffff (=40 bits) virtual memory map (1TB)
diff --git a/MAINTAINERS b/MAINTAINERS
index c42a567..08d0ab7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -742,7 +742,7 @@
 P:	Nick Kossifidis
 M:	mickflemm@gmail.com
 P:	Luis R. Rodriguez
-M:	mcgrof@gmail.com
+M:	lrodriguez@atheros.com
 P:	Bob Copeland
 M:	me@bobcopeland.com
 L:	linux-wireless@vger.kernel.org
@@ -1607,11 +1607,6 @@
 W:	http://sourceforge.net/projects/acpi4asus
 S:	Maintained
 
-EEPRO100 NETWORK DRIVER
-P:	Andrey V. Savochkin
-M:	saw@saw.sw.com.sg
-S:	Maintained
-
 EFS FILESYSTEM
 W:	http://aeschi.ch.eu.org/efs/
 S:	Orphan
@@ -1849,7 +1844,7 @@
 M:	hskinnemoen@atmel.com
 S:	Supported
 
-GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS
+GENERIC HDLC (WAN) DRIVERS
 P:	Krzysztof Halasa
 M:	khc@pm.waw.pl
 W:	http://www.kernel.org/pub/linux/utils/net/hdlc/
@@ -2248,6 +2243,11 @@
 L:	linux-kernel@vger.kernel.org
 S:	Supported
 
+INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
+P:	Krzysztof Halasa
+M:	khc@pm.waw.pl
+S:	Maintained
+
 INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
 P:	Deepak Saxena
 M:	dsaxena@plexity.net
@@ -3614,16 +3614,26 @@
 W:	http://www.linux-ax25.org/
 S:	Maintained
 
-RTL818X WIRELESS DRIVER
-P:	Michael Wu
-M:	flamingice@sourmilk.net
-P:	Andrea Merello
-M:	andreamrl@tiscali.it
+RTL8180 WIRELESS DRIVER
+P:	John W. Linville
+M:	linville@tuxdriver.com
 L:	linux-wireless@vger.kernel.org
 W:	http://linuxwireless.org/
-T:	git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
+T:	git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-testing.git
 S:	Maintained
 
+RTL8187 WIRELESS DRIVER
+P:	 Herton Ronaldo Krzesinski
+M:      herton@mandriva.com.br
+P:      Hin-Tak Leung
+M       htl10@users.sourceforge.net
+P:      Larry Finger
+M:      Larry.Finger@lwfinger.net
+L:      linux-wireless@vger.kernel.org
+W:      http://linuxwireless.org/
+T:      git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-testing.git
+S:      Maintained
+
 S3 SAVAGE FRAMEBUFFER DRIVER
 P:	Antonino Daplas
 M:	adaplas@gmail.com
@@ -3913,6 +3923,18 @@
 L:	lm-sensors@lm-sensors.org
 S:	Maintained
 
+SMSC911x ETHERNET DRIVER
+P:	Steve Glendinning
+M:	steve.glendinning@smsc.com
+L:	netdev@vger.kernel.org
+S:	Supported
+
+SMSC9420 PCI ETHERNET DRIVER
+P:	Steve Glendinning
+M:	steve.glendinning@smsc.com
+L:	netdev@vger.kernel.org
+S:	Supported
+
 SMX UIO Interface
 P:	Ben Nizette
 M:	bn@niasdigital.com
@@ -3977,7 +3999,7 @@
 L:	alsa-devel@alsa-project.org (subscribers-only)
 S:	Maintained
 
-SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT
+SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
 P:	Liam Girdwood
 M:	lrg@slimlogic.co.uk
 P:	Mark Brown
@@ -4529,7 +4551,7 @@
 USB VIDEO CLASS
 P:	Laurent Pinchart
 M:	laurent.pinchart@skynet.be
-L:	linux-uvc-devel@lists.berlios.de
+L:	linux-uvc-devel@lists.berlios.de (subscribers-only)
 L:	video4linux-list@redhat.com
 W:	http://linux-uvc.berlios.de
 S:	Maintained
diff --git a/Makefile b/Makefile
index 4c8d797..09ff7d8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 28
-EXTRAVERSION = -rc9
+EXTRAVERSION =
 NAME = Erotic Pickled Herring
 
 # *DOCUMENTATION*
@@ -336,7 +336,7 @@
                    -I$(srctree)/arch/$(hdr-arch)/include               \
                    -include include/linux/autoconf.h
 
-KBUILD_CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
+KBUILD_CPPFLAGS := -D__KERNEL__
 
 KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
 		   -fno-strict-aliasing -fno-common \
@@ -439,7 +439,11 @@
 include $(srctree)/arch/$(SRCARCH)/Makefile
 export KBUILD_DEFCONFIG KBUILD_KCONFIG
 
-config %config: scripts_basic outputmakefile FORCE
+config: scripts_basic outputmakefile FORCE
+	$(Q)mkdir -p include/linux include/config
+	$(Q)$(MAKE) $(build)=scripts/kconfig $@
+
+%config: scripts_basic outputmakefile FORCE
 	$(Q)mkdir -p include/linux include/config
 	$(Q)$(MAKE) $(build)=scripts/kconfig $@
 
@@ -600,20 +604,25 @@
 MODLIB	= $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
 export MODLIB
 
-#
-#  INSTALL_MOD_STRIP, if defined, will cause modules to be
-#  stripped after they are installed.  If INSTALL_MOD_STRIP is '1', then
-#  the default option --strip-debug will be used.  Otherwise,
-#  INSTALL_MOD_STRIP will used as the options to the strip command.
+strip-symbols := $(srctree)/scripts/strip-symbols \
+		 $(wildcard $(srctree)/arch/$(ARCH)/scripts/strip-symbols)
 
+#
+# INSTALL_MOD_STRIP, if defined, will cause modules to be stripped while
+# they get installed.  If INSTALL_MOD_STRIP is '1', then the default
+# options (see below) will be used.  Otherwise, INSTALL_MOD_STRIP will
+# be used as the option(s) to the objcopy command.
 ifdef INSTALL_MOD_STRIP
 ifeq ($(INSTALL_MOD_STRIP),1)
-mod_strip_cmd = $(STRIP) --strip-debug
+mod_strip_cmd = $(OBJCOPY) --strip-debug
+ifeq ($(CONFIG_KALLSYMS_ALL),$(CONFIG_KALLSYMS_STRIP_GENERATED))
+mod_strip_cmd += --wildcard $(addprefix --strip-symbols ,$(strip-symbols))
+endif
 else
-mod_strip_cmd = $(STRIP) $(INSTALL_MOD_STRIP)
+mod_strip_cmd = $(OBJCOPY) $(INSTALL_MOD_STRIP)
 endif # INSTALL_MOD_STRIP=1
 else
-mod_strip_cmd = true
+mod_strip_cmd = false
 endif # INSTALL_MOD_STRIP
 export mod_strip_cmd
 
@@ -743,6 +752,7 @@
 endif
 
 kallsyms.o := .tmp_kallsyms$(last_kallsyms).o
+kallsyms.h := $(wildcard include/config/kallsyms/*.h) $(wildcard include/config/kallsyms/*/*.h)
 
 define verify_kallsyms
 	$(Q)$(if $($(quiet)cmd_sysmap),                                      \
@@ -767,24 +777,41 @@
 
 # Generate .S file with all kernel symbols
 quiet_cmd_kallsyms = KSYM    $@
-      cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \
-                     $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@
+      cmd_kallsyms = { test $* -eq 0 || $(NM) -n $<; } \
+		     | $(KALLSYMS) $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) >$@
 
-.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
+quiet_cmd_kstrip = STRIP   $@
+      cmd_kstrip = $(OBJCOPY) --wildcard $(addprefix --strip$(if $(CONFIG_RELOCATABLE),-unneeded)-symbols ,$(filter %/scripts/strip-symbols,$^)) $< $@
+
+$(foreach n,0 1 2 3,.tmp_kallsyms$(n).o): KBUILD_AFLAGS += -Wa,--strip-local-absolute
+$(foreach n,0 1 2 3,.tmp_kallsyms$(n).o): %.o: %.S scripts FORCE
 	$(call if_changed_dep,as_o_S)
 
-.tmp_kallsyms%.S: .tmp_vmlinux% $(KALLSYMS)
+ifeq ($(CONFIG_KALLSYMS_STRIP_GENERATED),y)
+strip-ext := .stripped
+endif
+
+.tmp_kallsyms%.S: .tmp_vmlinux%$(strip-ext) $(KALLSYMS) $(kallsyms.h)
 	$(call cmd,kallsyms)
 
+# make -jN seems to have problems with intermediate files, see bug #3330.
+.SECONDARY: $(foreach n,1 2 3,.tmp_vmlinux$(n).stripped)
+.tmp_vmlinux%.stripped: .tmp_vmlinux% $(strip-symbols) $(kallsyms.h)
+	$(call cmd,kstrip)
+
+ifneq ($(CONFIG_DEBUG_INFO),y)
+.tmp_vmlinux%: LDFLAGS_vmlinux += -S
+endif
 # .tmp_vmlinux1 must be complete except kallsyms, so update vmlinux version
-.tmp_vmlinux1: $(vmlinux-lds) $(vmlinux-all) FORCE
-	$(call if_changed_rule,ksym_ld)
+.tmp_vmlinux%: $(vmlinux-lds) $(vmlinux-all) FORCE
+	$(if $(filter 1,$*),$(call if_changed_rule,ksym_ld),$(call if_changed,vmlinux__))
 
-.tmp_vmlinux2: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms1.o FORCE
-	$(call if_changed,vmlinux__)
+.tmp_vmlinux0$(strip-ext):
+	$(Q)echo "placeholder" >$@
 
-.tmp_vmlinux3: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms2.o FORCE
-	$(call if_changed,vmlinux__)
+.tmp_vmlinux1: .tmp_kallsyms0.o
+.tmp_vmlinux2: .tmp_kallsyms1.o
+.tmp_vmlinux3: .tmp_kallsyms2.o
 
 # Needs to visit scripts/ before $(KALLSYMS) can be used.
 $(KALLSYMS): scripts ;
@@ -926,7 +953,7 @@
 # 2) Create the include2 directory, used for the second asm symlink
 prepare3: include/config/kernel.release
 ifneq ($(KBUILD_SRC),)
-	@echo '  Using $(srctree) as source for kernel'
+	@$(kecho) '  Using $(srctree) as source for kernel'
 	$(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \
 		echo "  $(srctree) is not clean, please run 'make mrproper'";\
 		echo "  in the '$(srctree)' directory.";\
@@ -983,7 +1010,7 @@
 # directory for generated filesas used by some architectures.
 define create-symlink
 	if [ ! -L include/asm ]; then                                      \
-			echo '  SYMLINK $@ -> include/asm-$(SRCARCH)';     \
+			$(kecho) '  SYMLINK $@ -> include/asm-$(SRCARCH)'; \
 			if [ ! -d include/asm-$(SRCARCH) ]; then           \
 				mkdir -p include/asm-$(SRCARCH);           \
 			fi;                                                \
@@ -1022,6 +1049,10 @@
 include/linux/utsrelease.h: include/config/kernel.release FORCE
 	$(call filechk,utsrelease.h)
 
+PHONY += headerdep
+headerdep:
+	$(Q)find include/ -name '*.h' | xargs --max-args 1 scripts/headerdep.pl
+
 # ---------------------------------------------------------------------------
 
 PHONY += depend dep
@@ -1096,7 +1127,7 @@
 PHONY += modules
 modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)
 	$(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order
-	@echo '  Building modules, stage 2.';
+	@$(kecho) '  Building modules, stage 2.';
 	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
 	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild
 
@@ -1270,7 +1301,8 @@
 	@echo  '  versioncheck    - Sanity check on version.h usage'
 	@echo  '  includecheck    - Check for duplicate included header files'
 	@echo  '  export_report   - List the usages of all exported symbols'
-	@echo  '  headers_check   - Sanity check on exported headers'; \
+	@echo  '  headers_check   - Sanity check on exported headers'
+	@echo  '  headerdep       - Detect inclusion cycles in headers'; \
 	 echo  ''
 	@echo  'Kernel packaging:'
 	@$(MAKE) $(build)=$(package-dir) help
@@ -1360,7 +1392,7 @@
 	$(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
 
 modules: $(module-dirs)
-	@echo '  Building modules, stage 2.';
+	@$(kecho) '  Building modules, stage 2.';
 	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
 
 PHONY += modules_install
@@ -1409,123 +1441,12 @@
 
 # Generate tags for editors
 # ---------------------------------------------------------------------------
+quiet_cmd_tags = GEN     $@
+      cmd_tags = $(CONFIG_SHELL) $(srctree)/scripts/tags.sh $@
 
-#We want __srctree to totally vanish out when KBUILD_OUTPUT is not set
-#(which is the most common case IMHO) to avoid unneeded clutter in the big tags file.
-#Adding $(srctree) adds about 20M on i386 to the size of the output file!
-
-ifeq ($(src),$(obj))
-__srctree =
-else
-__srctree = $(srctree)/
-endif
-
-ifeq ($(ALLSOURCE_ARCHS),)
-ifeq ($(ARCH),um)
-ALLINCLUDE_ARCHS := $(ARCH) $(SUBARCH)
-else
-ALLINCLUDE_ARCHS := $(SRCARCH)
-endif
-else
-#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behaviour.
-ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS)
-endif
-
-ALLSOURCE_ARCHS := $(SRCARCH)
-
-define find-sources
-        ( for arch in $(ALLSOURCE_ARCHS) ; do \
-	       find $(__srctree)arch/$${arch} $(RCS_FIND_IGNORE) \
-		    -wholename $(__srctree)arch/$${arch}/include/asm -type d -prune \
-	            -o -name $1 -print; \
-	  done ; \
-	  find $(__srctree)security/selinux/include $(RCS_FIND_IGNORE) \
-	       -name $1 -print; \
-	  find $(__srctree)include $(RCS_FIND_IGNORE) \
-	       \( -name config -o -name 'asm-*' \) -prune \
-	       -o -name $1 -print; \
-	  for arch in $(ALLINCLUDE_ARCHS) ; do \
-	       test -e $(__srctree)include/asm-$${arch} && \
-                 find $(__srctree)include/asm-$${arch} $(RCS_FIND_IGNORE) \
-	            -name $1 -print; \
-	       test -e $(__srctree)arch/$${arch}/include/asm && \
-	         find $(__srctree)arch/$${arch}/include/asm $(RCS_FIND_IGNORE) \
-	            -name $1 -print; \
-	  done ; \
-	  find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
-	       -name $1 -print; \
-	  find $(__srctree) $(RCS_FIND_IGNORE) \
-	       \( -name include -o -name arch -o -name '.tmp_*' \) -prune -o \
-	       -name $1 -print; \
-	  )
-endef
-
-define all-sources
-	$(call find-sources,'*.[chS]')
-endef
-define all-kconfigs
-	$(call find-sources,'Kconfig*')
-endef
-define all-defconfigs
-	$(call find-sources,'defconfig')
-endef
-
-define xtags
-	if $1 --version 2>&1 | grep -iq exuberant; then \
-	    $(all-sources) | xargs $1 -a \
-		-I __initdata,__exitdata,__acquires,__releases \
-		-I __read_mostly,____cacheline_aligned,____cacheline_aligned_in_smp,____cacheline_internodealigned_in_smp \
-		-I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \
-		--extra=+f --c-kinds=+px \
-		--regex-asm='/^ENTRY\(([^)]*)\).*/\1/'; \
-	    $(all-kconfigs) | xargs $1 -a \
-		--langdef=kconfig \
-		--language-force=kconfig \
-		--regex-kconfig='/^[[:blank:]]*(menu|)config[[:blank:]]+([[:alnum:]_]+)/\2/'; \
-	    $(all-defconfigs) | xargs -r $1 -a \
-		--langdef=dotconfig \
-		--language-force=dotconfig \
-		--regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'; \
-	elif $1 --version 2>&1 | grep -iq emacs; then \
-	    $(all-sources) | xargs $1 -a; \
-	    $(all-kconfigs) | xargs $1 -a \
-		--regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'; \
-	    $(all-defconfigs) | xargs -r $1 -a \
-		--regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'; \
-	else \
-	    $(all-sources) | xargs $1 -a; \
-	fi
-endef
-
-quiet_cmd_cscope-file = FILELST cscope.files
-      cmd_cscope-file = (echo \-k; echo \-q; $(all-sources)) > cscope.files
-
-quiet_cmd_cscope = MAKE    cscope.out
-      cmd_cscope = cscope -b -f cscope.out
-
-cscope: FORCE
-	$(call cmd,cscope-file)
-	$(call cmd,cscope)
-
-quiet_cmd_TAGS = MAKE   $@
-define cmd_TAGS
-	rm -f $@; \
-	$(call xtags,etags)
-endef
-
-TAGS: FORCE
-	$(call cmd,TAGS)
-
-quiet_cmd_tags = MAKE   $@
-define cmd_tags
-	rm -f $@; \
-	$(call xtags,ctags)
-endef
-
-tags: FORCE
+tags TAGS cscope: FORCE
 	$(call cmd,tags)
 
-
 # Scripts to check various things for consistency
 # ---------------------------------------------------------------------------
 
@@ -1604,7 +1525,11 @@
 	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
 
 # Modules
-/ %/: prepare scripts FORCE
+/: prepare scripts FORCE
+	$(cmd_crmodverdir)
+	$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
+	$(build)=$(build-dir)
+%/: prepare scripts FORCE
 	$(cmd_crmodverdir)
 	$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
 	$(build)=$(build-dir)
@@ -1638,7 +1563,7 @@
                   $(if $(KBUILD_MODULES),; rm -f $(MODVERDIR)/*)
 
 a_flags = -Wp,-MD,$(depfile) $(KBUILD_AFLAGS) $(AFLAGS_KERNEL) \
-	  $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
+	  $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(KBUILD_CPPFLAGS) \
 	  $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(basetarget).o)
 
 quiet_cmd_as_o_S = AS      $@
diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c
index 4b18cd9..6ff8886 100644
--- a/arch/alpha/kernel/asm-offsets.c
+++ b/arch/alpha/kernel/asm-offsets.c
@@ -19,15 +19,18 @@
 	BLANK();
 
         DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
-        DEFINE(TASK_UID, offsetof(struct task_struct, uid));
-        DEFINE(TASK_EUID, offsetof(struct task_struct, euid));
-        DEFINE(TASK_GID, offsetof(struct task_struct, gid));
-        DEFINE(TASK_EGID, offsetof(struct task_struct, egid));
+        DEFINE(TASK_CRED, offsetof(struct task_struct, cred));
         DEFINE(TASK_REAL_PARENT, offsetof(struct task_struct, real_parent));
         DEFINE(TASK_GROUP_LEADER, offsetof(struct task_struct, group_leader));
         DEFINE(TASK_TGID, offsetof(struct task_struct, tgid));
         BLANK();
 
+        DEFINE(CRED_UID,  offsetof(struct cred, uid));
+        DEFINE(CRED_EUID, offsetof(struct cred, euid));
+        DEFINE(CRED_GID,  offsetof(struct cred, gid));
+        DEFINE(CRED_EGID, offsetof(struct cred, egid));
+        BLANK();
+
 	DEFINE(SIZEOF_PT_REGS, sizeof(struct pt_regs));
 	DEFINE(PT_PTRACED, PT_PTRACED);
 	DEFINE(CLONE_VM, CLONE_VM);
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 5fc61e2..f77345b 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -850,8 +850,9 @@
 sys_getxuid:
 	.prologue 0
 	ldq	$2, TI_TASK($8)
-	ldl	$0, TASK_UID($2)
-	ldl	$1, TASK_EUID($2)
+	ldq	$3, TASK_CRED($2)
+	ldl	$0, CRED_UID($3)
+	ldl	$1, CRED_EUID($3)
 	stq	$1, 80($sp)
 	ret
 .end sys_getxuid
@@ -862,8 +863,9 @@
 sys_getxgid:
 	.prologue 0
 	ldq	$2, TI_TASK($8)
-	ldl	$0, TASK_GID($2)
-	ldl	$1, TASK_EGID($2)
+	ldq	$3, TASK_CRED($2)
+	ldl	$0, CRED_GID($3)
+	ldl	$1, CRED_EGID($3)
 	stq	$1, 80($sp)
 	ret
 .end sys_getxgid
diff --git a/arch/arm/mach-ixp4xx/fsg-setup.c b/arch/arm/mach-ixp4xx/fsg-setup.c
index e7c6386..5add22f 100644
--- a/arch/arm/mach-ixp4xx/fsg-setup.c
+++ b/arch/arm/mach-ixp4xx/fsg-setup.c
@@ -177,7 +177,6 @@
 
 static void __init fsg_init(void)
 {
-	DECLARE_MAC_BUF(mac_buf);
 	uint8_t __iomem *f;
 
 	ixp4xx_sys_init();
@@ -256,10 +255,10 @@
 #endif
 		iounmap(f);
 	}
-	printk(KERN_INFO "FSG: Using MAC address %s for port 0\n",
-	       print_mac(mac_buf, fsg_plat_eth[0].hwaddr));
-	printk(KERN_INFO "FSG: Using MAC address %s for port 1\n",
-	       print_mac(mac_buf, fsg_plat_eth[1].hwaddr));
+	printk(KERN_INFO "FSG: Using MAC address %pM for port 0\n",
+	       fsg_plat_eth[0].hwaddr);
+	printk(KERN_INFO "FSG: Using MAC address %pM for port 1\n",
+	       fsg_plat_eth[1].hwaddr);
 
 }
 
diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
index 1e52b95..0cbe6ce 100644
--- a/arch/arm/mach-ixp4xx/include/mach/qmgr.h
+++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
@@ -12,6 +12,8 @@
 #include <linux/io.h>
 #include <linux/kernel.h>
 
+#define DEBUG_QMGR	0
+
 #define HALF_QUEUES	32
 #define QUEUES		64	/* only 32 lower queues currently supported */
 #define MAX_QUEUE_LENGTH 4	/* in dwords */
@@ -61,22 +63,51 @@
 void qmgr_disable_irq(unsigned int queue);
 
 /* request_ and release_queue() must be called from non-IRQ context */
+
+#if DEBUG_QMGR
+extern char qmgr_queue_descs[QUEUES][32];
+
 int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
 		       unsigned int nearly_empty_watermark,
-		       unsigned int nearly_full_watermark);
+		       unsigned int nearly_full_watermark,
+		       const char *desc_format, const char* name);
+#else
+int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+			 unsigned int nearly_empty_watermark,
+			 unsigned int nearly_full_watermark);
+#define qmgr_request_queue(queue, len, nearly_empty_watermark,		\
+			   nearly_full_watermark, desc_format, name)	\
+	__qmgr_request_queue(queue, len, nearly_empty_watermark,	\
+			     nearly_full_watermark)
+#endif
+
 void qmgr_release_queue(unsigned int queue);
 
 
 static inline void qmgr_put_entry(unsigned int queue, u32 val)
 {
 	extern struct qmgr_regs __iomem *qmgr_regs;
+#if DEBUG_QMGR
+	BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+	printk(KERN_DEBUG "Queue %s(%i) put %X\n",
+	       qmgr_queue_descs[queue], queue, val);
+#endif
 	__raw_writel(val, &qmgr_regs->acc[queue][0]);
 }
 
 static inline u32 qmgr_get_entry(unsigned int queue)
 {
+	u32 val;
 	extern struct qmgr_regs __iomem *qmgr_regs;
-	return __raw_readl(&qmgr_regs->acc[queue][0]);
+	val = __raw_readl(&qmgr_regs->acc[queue][0]);
+#if DEBUG_QMGR
+	BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+	printk(KERN_DEBUG "Queue %s(%i) get %X\n",
+	       qmgr_queue_descs[queue], queue, val);
+#endif
+	return val;
 }
 
 static inline int qmgr_get_stat1(unsigned int queue)
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
index c6cb069..bfddc73 100644
--- a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
+++ b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
@@ -14,8 +14,6 @@
 #include <linux/module.h>
 #include <mach/qmgr.h>
 
-#define DEBUG		0
-
 struct qmgr_regs __iomem *qmgr_regs;
 static struct resource *mem_res;
 static spinlock_t qmgr_lock;
@@ -23,6 +21,10 @@
 static void (*irq_handlers[HALF_QUEUES])(void *pdev);
 static void *irq_pdevs[HALF_QUEUES];
 
+#if DEBUG_QMGR
+char qmgr_queue_descs[QUEUES][32];
+#endif
+
 void qmgr_set_irq(unsigned int queue, int src,
 		  void (*handler)(void *pdev), void *pdev)
 {
@@ -70,6 +72,7 @@
 	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 */
 	spin_unlock_irqrestore(&qmgr_lock, flags);
 }
 
@@ -81,9 +84,16 @@
 	mask[0] <<= 1;
 }
 
+#if DEBUG_QMGR
 int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
 		       unsigned int nearly_empty_watermark,
-		       unsigned int nearly_full_watermark)
+		       unsigned int nearly_full_watermark,
+		       const char *desc_format, const char* name)
+#else
+int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+			 unsigned int nearly_empty_watermark,
+			 unsigned int nearly_full_watermark)
+#endif
 {
 	u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
 	int err;
@@ -151,12 +161,13 @@
 	used_sram_bitmap[2] |= mask[2];
 	used_sram_bitmap[3] |= mask[3];
 	__raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
-	spin_unlock_irq(&qmgr_lock);
-
-#if DEBUG
-	printk(KERN_DEBUG "qmgr: requested queue %i, addr = 0x%02X\n",
-	       queue, addr);
+#if DEBUG_QMGR
+	snprintf(qmgr_queue_descs[queue], sizeof(qmgr_queue_descs[0]),
+		 desc_format, name);
+	printk(KERN_DEBUG "qmgr: requested queue %s(%i) addr = 0x%02X\n",
+	       qmgr_queue_descs[queue], queue, addr);
 #endif
+	spin_unlock_irq(&qmgr_lock);
 	return 0;
 
 err:
@@ -189,6 +200,11 @@
 	while (addr--)
 		shift_mask(mask);
 
+#if DEBUG_QMGR
+	printk(KERN_DEBUG "qmgr: releasing queue %s(%i)\n",
+	       qmgr_queue_descs[queue], queue);
+	qmgr_queue_descs[queue][0] = '\x0';
+#endif
 	__raw_writel(0, &qmgr_regs->sram[queue]);
 
 	used_sram_bitmap[0] &= ~mask[0];
@@ -199,9 +215,10 @@
 	spin_unlock_irq(&qmgr_lock);
 
 	module_put(THIS_MODULE);
-#if DEBUG
-	printk(KERN_DEBUG "qmgr: released queue %i\n", queue);
-#endif
+
+	while ((addr = qmgr_get_entry(queue)))
+		printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n",
+		       queue, addr);
 }
 
 static int qmgr_init(void)
@@ -272,5 +289,10 @@
 EXPORT_SYMBOL(qmgr_set_irq);
 EXPORT_SYMBOL(qmgr_enable_irq);
 EXPORT_SYMBOL(qmgr_disable_irq);
+#if DEBUG_QMGR
+EXPORT_SYMBOL(qmgr_queue_descs);
 EXPORT_SYMBOL(qmgr_request_queue);
+#else
+EXPORT_SYMBOL(__qmgr_request_queue);
+#endif
 EXPORT_SYMBOL(qmgr_release_queue);
diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c
index 0acd95e..921c947 100644
--- a/arch/arm/mach-ixp4xx/nas100d-setup.c
+++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
@@ -231,7 +231,6 @@
 
 static void __init nas100d_init(void)
 {
-	DECLARE_MAC_BUF(mac_buf);
 	uint8_t __iomem *f;
 	int i;
 
@@ -294,8 +293,8 @@
 #endif
 		iounmap(f);
 	}
-	printk(KERN_INFO "NAS100D: Using MAC address %s for port 0\n",
-	       print_mac(mac_buf, nas100d_plat_eth[0].hwaddr));
+	printk(KERN_INFO "NAS100D: Using MAC address %pM for port 0\n",
+	       nas100d_plat_eth[0].hwaddr);
 
 }
 
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
index bc9d920..ff6a08d 100644
--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
@@ -220,7 +220,6 @@
 
 static void __init nslu2_init(void)
 {
-	DECLARE_MAC_BUF(mac_buf);
 	uint8_t __iomem *f;
 	int i;
 
@@ -275,8 +274,8 @@
 #endif
 		iounmap(f);
 	}
-	printk(KERN_INFO "NSLU2: Using MAC address %s for port 0\n",
-	       print_mac(mac_buf, nslu2_plat_eth[0].hwaddr));
+	printk(KERN_INFO "NSLU2: Using MAC address %pM for port 0\n",
+	       nslu2_plat_eth[0].hwaddr);
 
 }
 
diff --git a/arch/arm/mach-pxa/include/mach/palmasoc.h b/arch/arm/mach-pxa/include/mach/palmasoc.h
new file mode 100644
index 0000000..6c4b1f7
--- /dev/null
+++ b/arch/arm/mach-pxa/include/mach/palmasoc.h
@@ -0,0 +1,13 @@
+#ifndef _INCLUDE_PALMASOC_H_
+#define _INCLUDE_PALMASOC_H_
+struct palm27x_asoc_info {
+	int	jack_gpio;
+};
+
+#ifdef CONFIG_SND_PXA2XX_SOC_PALM27X
+void __init palm27x_asoc_set_pdata(struct palm27x_asoc_info *data);
+#else
+static inline void palm27x_asoc_set_pdata(struct palm27x_asoc_info *data) {}
+#endif
+
+#endif
diff --git a/arch/blackfin/boot/Makefile b/arch/blackfin/boot/Makefile
index 522f3c1..e028d13 100644
--- a/arch/blackfin/boot/Makefile
+++ b/arch/blackfin/boot/Makefile
@@ -25,7 +25,7 @@
 
 $(obj)/vmImage: $(obj)/vmlinux.gz
 	$(call if_changed,uimage)
-	@echo 'Kernel: $@ is ready'
+	@$(kecho) 'Kernel: $@ is ready'
 
 install:
 	sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 6bd91ed..7fa8f61 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -99,7 +99,7 @@
 	bool
 	default y
 
-config SCHED_NO_NO_OMIT_FRAME_POINTER
+config SCHED_OMIT_FRAME_POINTER
 	bool
 	default y
 
diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
index 3d47839..e4d8fde 100644
--- a/arch/ia64/hp/sim/simeth.c
+++ b/arch/ia64/hp/sim/simeth.c
@@ -167,6 +167,15 @@
 	return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_RECV);
 }
 
+static const struct net_device_ops simeth_netdev_ops = {
+	.ndo_open		= simeth_open,
+	.ndo_stop		= simeth_close,
+	.ndo_start_xmit		= simeth_tx,
+	.ndo_get_stats		= simeth_get_stats,
+	.ndo_set_multicast_list	= set_multicast_list, /* not yet used */
+
+};
+
 /*
  * Function shared with module code, so cannot be in init section
  *
@@ -206,14 +215,10 @@
 
 	memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr));
 
-	local = dev->priv;
+	local = netdev_priv(dev);
 	local->simfd = fd; /* keep track of underlying file descriptor */
 
-	dev->open		= simeth_open;
-	dev->stop		= simeth_close;
-	dev->hard_start_xmit	= simeth_tx;
-	dev->get_stats		= simeth_get_stats;
-	dev->set_multicast_list = set_multicast_list; /* no yet used */
+	dev->netdev_ops = &simeth_netdev_ops;
 
 	err = register_netdev(dev);
 	if (err) {
@@ -325,7 +330,7 @@
 	 * we get DOWN then UP.
 	 */
 
-	local = dev->priv;
+	local = netdev_priv(dev);
 	/* now do it for real */
 	r = event == NETDEV_UP ?
 		netdev_attach(local->simfd, dev->irq, ntohl(ifa->ifa_local)):
@@ -380,7 +385,7 @@
 static int
 simeth_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct simeth_local *local = dev->priv;
+	struct simeth_local *local = netdev_priv(dev);
 
 #if 0
 	/* ensure we have at least ETH_ZLEN bytes (min frame size) */
@@ -443,7 +448,7 @@
 	int			len;
 	int			rcv_count = SIMETH_RECV_MAX;
 
-	local = dev->priv;
+	local = netdev_priv(dev);
 	/*
 	 * the loop concept has been borrowed from other drivers
 	 * looks to me like it's a throttling thing to avoid pushing to many
@@ -507,7 +512,7 @@
 static struct net_device_stats *
 simeth_get_stats(struct net_device *dev)
 {
-	struct simeth_local *local = dev->priv;
+	struct simeth_local *local = netdev_priv(dev);
 
 	return &local->stats;
 }
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index 5e92ae0..16ef61a 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -1767,25 +1767,24 @@
 asmlinkage long
 sys32_getgroups16 (int gidsetsize, short __user *grouplist)
 {
+	const struct cred *cred = current_cred();
 	int i;
 
 	if (gidsetsize < 0)
 		return -EINVAL;
 
-	get_group_info(current->group_info);
-	i = current->group_info->ngroups;
+	i = cred->group_info->ngroups;
 	if (gidsetsize) {
 		if (i > gidsetsize) {
 			i = -EINVAL;
 			goto out;
 		}
-		if (groups16_to_user(grouplist, current->group_info)) {
+		if (groups16_to_user(grouplist, cred->group_info)) {
 			i = -EFAULT;
 			goto out;
 		}
 	}
 out:
-	put_group_info(current->group_info);
 	return i;
 }
 
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
index fab1d21..f94aaa8 100644
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -158,7 +158,7 @@
 	ia64_mlogbuf_dump();
 	printk(KERN_ERR "OS_MCA: process [cpu %d, pid: %d, uid: %d, "
 		"iip: %p, psr: 0x%lx,paddr: 0x%lx](%s) encounters MCA.\n",
-		raw_smp_processor_id(), current->pid, current->uid,
+	       raw_smp_processor_id(), current->pid, current_uid(),
 		iip, ipsr, paddr, current->comm);
 
 	spin_lock(&mca_bh_lock);
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 6543a55..0e49975 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2220,8 +2220,8 @@
 	DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode));
 
 	inode->i_mode = S_IFCHR|S_IRUGO;
-	inode->i_uid  = current->fsuid;
-	inode->i_gid  = current->fsgid;
+	inode->i_uid  = current_fsuid();
+	inode->i_gid  = current_fsgid();
 
 	sprintf(name, "[%lu]", inode->i_ino);
 	this.name = name;
@@ -2399,22 +2399,33 @@
 static int
 pfm_bad_permissions(struct task_struct *task)
 {
+	const struct cred *tcred;
+	uid_t uid = current_uid();
+	gid_t gid = current_gid();
+	int ret;
+
+	rcu_read_lock();
+	tcred = __task_cred(task);
+
 	/* inspired by ptrace_attach() */
 	DPRINT(("cur: uid=%d gid=%d task: euid=%d suid=%d uid=%d egid=%d sgid=%d\n",
-		current->uid,
-		current->gid,
-		task->euid,
-		task->suid,
-		task->uid,
-		task->egid,
-		task->sgid));
+		uid,
+		gid,
+		tcred->euid,
+		tcred->suid,
+		tcred->uid,
+		tcred->egid,
+		tcred->sgid));
 
-	return ((current->uid != task->euid)
-	    || (current->uid != task->suid)
-	    || (current->uid != task->uid)
-	    || (current->gid != task->egid)
-	    || (current->gid != task->sgid)
-	    || (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE);
+	ret = ((uid != tcred->euid)
+	       || (uid != tcred->suid)
+	       || (uid != tcred->uid)
+	       || (gid != tcred->egid)
+	       || (gid != tcred->sgid)
+	       || (gid != tcred->gid)) && !capable(CAP_SYS_PTRACE);
+
+	rcu_read_unlock();
+	return ret;
 }
 
 static int
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index e12500a..e1821ca 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -229,7 +229,7 @@
 	si.si_errno = 0;
 	si.si_code = SI_KERNEL;
 	si.si_pid = task_pid_vnr(current);
-	si.si_uid = current->uid;
+	si.si_uid = current_uid();
 	si.si_addr = sc;
 	force_sig_info(SIGSEGV, &si, current);
 	return retval;
@@ -326,7 +326,7 @@
 	si.si_errno = 0;
 	si.si_code = SI_KERNEL;
 	si.si_pid = task_pid_vnr(current);
-	si.si_uid = current->uid;
+	si.si_uid = current_uid();
 	si.si_addr = addr;
 	force_sig_info(SIGSEGV, &si, current);
 	return 0;
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index dbaed4a..29047d5 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -273,7 +273,7 @@
 	bool
 	default y
 
-config SCHED_NO_NO_OMIT_FRAME_POINTER
+config SCHED_OMIT_FRAME_POINTER
         bool
         default y
 
diff --git a/arch/m68k/fpsp040/setox.S b/arch/m68k/fpsp040/setox.S
index 145af54..f1acf7e 100644
--- a/arch/m68k/fpsp040/setox.S
+++ b/arch/m68k/fpsp040/setox.S
@@ -36,9 +36,9 @@
 |	depending on their values, the program may run faster or slower --
 |	but no worse than 10% slower even in the extreme cases.
 |
-|	The program setoxm1 takes approximately ???/??? cycles for input
+|	The program setoxm1 takes approximately ??? / ??? cycles for input
 |	argument X, 0.25 <= |X| < 70log2. For |X| < 0.25, it takes
-|	approximately ???/??? cycles. For the less common arguments,
+|	approximately ??? / ??? cycles. For the less common arguments,
 |	depending on their values, the program may run faster or slower --
 |	but no worse than 10% slower even in the extreme cases.
 |
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
index c7b25b0..245d16d 100644
--- a/arch/m68k/mac/baboon.c
+++ b/arch/m68k/mac/baboon.c
@@ -18,11 +18,14 @@
 #include <asm/macints.h>
 #include <asm/mac_baboon.h>
 
-/* #define DEBUG_BABOON */
 /* #define DEBUG_IRQS */
 
+extern void mac_enable_irq(unsigned int);
+extern void mac_disable_irq(unsigned int);
+
 int baboon_present;
 static volatile struct baboon *baboon;
+static unsigned char baboon_disabled;
 
 #if 0
 extern int macide_ack_intr(struct ata_channel *);
@@ -88,34 +91,51 @@
 
 void __init baboon_register_interrupts(void)
 {
-	request_irq(IRQ_NUBUS_C, baboon_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
-		    "baboon", (void *) baboon);
+	baboon_disabled = 0;
+	request_irq(IRQ_NUBUS_C, baboon_irq, 0, "baboon", (void *)baboon);
 }
 
-void baboon_irq_enable(int irq) {
+/*
+ * The means for masking individual baboon interrupts remains a mystery, so
+ * enable the umbrella interrupt only when no baboon interrupt is disabled.
+ */
+
+void baboon_irq_enable(int irq)
+{
+	int irq_idx = IRQ_IDX(irq);
+
 #ifdef DEBUG_IRQUSE
 	printk("baboon_irq_enable(%d)\n", irq);
 #endif
-	/* FIXME: figure out how to mask and unmask baboon interrupt sources */
-	enable_irq(IRQ_NUBUS_C);
+
+	baboon_disabled &= ~(1 << irq_idx);
+	if (!baboon_disabled)
+		mac_enable_irq(IRQ_NUBUS_C);
 }
 
-void baboon_irq_disable(int irq) {
+void baboon_irq_disable(int irq)
+{
+	int irq_idx = IRQ_IDX(irq);
+
 #ifdef DEBUG_IRQUSE
 	printk("baboon_irq_disable(%d)\n", irq);
 #endif
-	disable_irq(IRQ_NUBUS_C);
+
+	baboon_disabled |= 1 << irq_idx;
+	if (baboon_disabled)
+		mac_disable_irq(IRQ_NUBUS_C);
 }
 
-void baboon_irq_clear(int irq) {
-	int irq_idx	= IRQ_IDX(irq);
+void baboon_irq_clear(int irq)
+{
+	int irq_idx = IRQ_IDX(irq);
 
 	baboon->mb_ifr &= ~(1 << irq_idx);
 }
 
 int baboon_irq_pending(int irq)
 {
-	int irq_idx	= IRQ_IDX(irq);
+	int irq_idx = IRQ_IDX(irq);
 
 	return baboon->mb_ifr & (1 << irq_idx);
 }
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index c45e184..8819b97 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -162,10 +162,7 @@
 	mach_init_IRQ = mac_init_IRQ;
 	mach_get_model = mac_get_model;
 	mach_gettimeoffset = mac_gettimeoffset;
-#warning move to adb/via init
-#if 0
 	mach_hwclk = mac_hwclk;
-#endif
 	mach_set_clock_mmss = mac_set_clock_mmss;
 	mach_reset = mac_reset;
 	mach_halt = mac_poweroff;
diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c
index 2165740..65dd77a 100644
--- a/arch/m68k/mac/debug.c
+++ b/arch/m68k/mac/debug.c
@@ -24,7 +24,6 @@
 #define BOOTINFO_COMPAT_1_0
 #include <asm/setup.h>
 #include <asm/bootinfo.h>
-#include <asm/machw.h>
 #include <asm/macints.h>
 
 extern unsigned long mac_videobase;
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index ecddac4..82e560c 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -127,7 +127,6 @@
 #include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/bootinfo.h>
-#include <asm/machw.h>
 #include <asm/macintosh.h>
 #include <asm/mac_via.h>
 #include <asm/mac_psc.h>
@@ -215,8 +214,8 @@
 
 /* #define DEBUG_MACINTS */
 
-static void mac_enable_irq(unsigned int irq);
-static void mac_disable_irq(unsigned int irq);
+void mac_enable_irq(unsigned int irq);
+void mac_disable_irq(unsigned int irq);
 
 static struct irq_controller mac_irq_controller = {
 	.name		= "mac",
@@ -275,7 +274,7 @@
  * These routines are just dispatchers to the VIA/OSS/PSC routines.
  */
 
-static void mac_enable_irq(unsigned int irq)
+void mac_enable_irq(unsigned int irq)
 {
 	int irq_src = IRQ_SRC(irq);
 
@@ -308,7 +307,7 @@
 	}
 }
 
-static void mac_disable_irq(unsigned int irq)
+void mac_disable_irq(unsigned int irq)
 {
 	int irq_src = IRQ_SRC(irq);
 
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index 56d1f56..a44c708 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -93,7 +93,7 @@
 #define cuda_write_pram NULL
 #endif
 
-#ifdef CONFIG_ADB_PMU68K
+#if 0 /* def CONFIG_ADB_PMU68K */
 static long pmu_read_time(void)
 {
 	struct adb_request req;
@@ -148,7 +148,7 @@
 #define pmu_write_pram NULL
 #endif
 
-#ifdef CONFIG_ADB_MACIISI
+#if 0 /* def CONFIG_ADB_MACIISI */
 extern int maciisi_request(struct adb_request *req,
 			void (*done)(struct adb_request *), int nbytes, ...);
 
@@ -717,13 +717,18 @@
 		unmktime(now, 0,
 			 &t->tm_year, &t->tm_mon, &t->tm_mday,
 			 &t->tm_hour, &t->tm_min, &t->tm_sec);
+#if 0
 		printk("mac_hwclk: read %04d-%02d-%-2d %02d:%02d:%02d\n",
-			t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+			t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
+			t->tm_hour, t->tm_min, t->tm_sec);
+#endif
 	} else { /* write */
+#if 0
 		printk("mac_hwclk: tried to write %04d-%02d-%-2d %02d:%02d:%02d\n",
-			t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+			t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
+			t->tm_hour, t->tm_min, t->tm_sec);
+#endif
 
-#if 0	/* it trashes my rtc */
 		now = mktime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
 			     t->tm_hour, t->tm_min, t->tm_sec);
 
@@ -742,7 +747,6 @@
 		case MAC_ADB_IISI:
 			maciisi_write_time(now);
 		}
-#endif
 	}
 	return 0;
 }
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
index 43d83e0..8426501 100644
--- a/arch/m68k/mac/oss.c
+++ b/arch/m68k/mac/oss.c
@@ -21,7 +21,6 @@
 #include <linux/init.h>
 
 #include <asm/bootinfo.h>
-#include <asm/machw.h>
 #include <asm/macintosh.h>
 #include <asm/macints.h>
 #include <asm/mac_via.h>
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index 1bdb03c..f01d418 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -32,15 +32,10 @@
 #include <asm/bootinfo.h>
 #include <asm/macintosh.h>
 #include <asm/macints.h>
-#include <asm/machw.h>
 #include <asm/mac_via.h>
 #include <asm/mac_psc.h>
 
 volatile __u8 *via1, *via2;
-#if 0
-/* See note in mac_via.h about how this is possibly not useful */
-volatile long *via_memory_bogon=(long *)&via_memory_bogon;
-#endif
 int rbv_present;
 int via_alt_mapping;
 EXPORT_SYMBOL(via_alt_mapping);
@@ -66,7 +61,7 @@
 #define MAC_CLOCK_LOW		(MAC_CLOCK_TICK&0xFF)
 #define MAC_CLOCK_HIGH		(MAC_CLOCK_TICK>>8)
 
-/* To disable a NuBus slot on Quadras we make the slot IRQ lines outputs, set
+/* To disable a NuBus slot on Quadras we make that slot IRQ line an output set
  * high. On RBV we just use the slot interrupt enable register. On Macs with
  * genuine VIA chips we must use nubus_disabled to keep track of disabled slot
  * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1
@@ -180,7 +175,7 @@
 	via1[vT1CH] = 0;
 	via1[vT2CL] = 0;
 	via1[vT2CH] = 0;
-	via1[vACR] &= 0x3F;
+	via1[vACR] &= ~0xC0; /* setup T1 timer with no PB7 output */
 	via1[vACR] &= ~0x03; /* disable port A & B latches */
 
 	/*
@@ -203,40 +198,41 @@
 
 	/* Everything below this point is VIA2/RBV only... */
 
-	if (oss_present) return;
+	if (oss_present)
+		return;
 
-#if 1
 	/* Some machines support an alternate IRQ mapping that spreads  */
 	/* Ethernet and Sound out to their own autolevel IRQs and moves */
 	/* VIA1 to level 6. A/UX uses this mapping and we do too.  Note */
 	/* that the IIfx emulates this alternate mapping using the OSS. */
 
-	switch(macintosh_config->ident) {
-		case MAC_MODEL_P475:
-		case MAC_MODEL_P475F:
-		case MAC_MODEL_P575:
-		case MAC_MODEL_Q605:
-		case MAC_MODEL_Q605_ACC:
-		case MAC_MODEL_C610:
-		case MAC_MODEL_Q610:
-		case MAC_MODEL_Q630:
-		case MAC_MODEL_C650:
-		case MAC_MODEL_Q650:
-		case MAC_MODEL_Q700:
-		case MAC_MODEL_Q800:
-		case MAC_MODEL_Q900:
-		case MAC_MODEL_Q950:
+	via_alt_mapping = 0;
+	if (macintosh_config->via_type == MAC_VIA_QUADRA)
+		switch (macintosh_config->ident) {
+		case MAC_MODEL_C660:
+		case MAC_MODEL_Q840:
+			/* not applicable */
+			break;
+		case MAC_MODEL_P588:
+		case MAC_MODEL_TV:
+		case MAC_MODEL_PB140:
+		case MAC_MODEL_PB145:
+		case MAC_MODEL_PB160:
+		case MAC_MODEL_PB165:
+		case MAC_MODEL_PB165C:
+		case MAC_MODEL_PB170:
+		case MAC_MODEL_PB180:
+		case MAC_MODEL_PB180C:
+		case MAC_MODEL_PB190:
+		case MAC_MODEL_PB520:
+			/* not yet tested */
+			break;
+		default:
 			via_alt_mapping = 1;
 			via1[vDirB] |= 0x40;
 			via1[vBufB] &= ~0x40;
 			break;
-		default:
-			via_alt_mapping = 0;
-			break;
-	}
-#else
-	via_alt_mapping = 0;
-#endif
+		}
 
 	/*
 	 * Now initialize VIA2. For RBV we just kill all interrupts;
@@ -252,14 +248,17 @@
 		via2[vT1CH] = 0;
 		via2[vT2CL] = 0;
 		via2[vT2CH] = 0;
-		via2[vACR] &= 0x3F;
+		via2[vACR] &= ~0xC0; /* setup T1 timer with no PB7 output */
 		via2[vACR] &= ~0x03; /* disable port A & B latches */
 	}
 
 	/*
-	 * Set vPCR for SCSI interrupts (but not on RBV)
+	 * Set vPCR for control line interrupts (but not on RBV)
 	 */
 	if (!rbv_present) {
+		/* For all VIA types, CA1 (SLOTS IRQ) and CB1 (ASC IRQ)
+		 * are made negative edge triggered here.
+		 */
 		if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
 			/* CB2 (IRQ) indep. input, positive edge */
 			/* CA2 (DRQ) indep. input, positive edge */
@@ -466,21 +465,6 @@
 		++irq_num;
 		irq_bit <<= 1;
 	} while (events >= irq_bit);
-
-#if 0 /* freakin' pmu is doing weird stuff */
-	if (!oss_present) {
-		/* This (still) seems to be necessary to get IDE
-		   working.  However, if you enable VBL interrupts,
-		   you're screwed... */
-		/* FIXME: should we check the SLOTIRQ bit before
-                   pulling this stunt? */
-		/* No, it won't be set. that's why we're doing this. */
-		via_irq_disable(IRQ_MAC_NUBUS);
-		via_irq_clear(IRQ_MAC_NUBUS);
-		m68k_handle_int(IRQ_MAC_NUBUS);
-		via_irq_enable(IRQ_MAC_NUBUS);
-	}
-#endif
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index f4af967..a5255e7 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -653,7 +653,7 @@
 	bool
 	default y
 
-config SCHED_NO_NO_OMIT_FRAME_POINTER
+config SCHED_OMIT_FRAME_POINTER
 	bool
 	default y
 
diff --git a/arch/mips/include/asm/byteorder.h b/arch/mips/include/asm/byteorder.h
index 2988d29..33790b9 100644
--- a/arch/mips/include/asm/byteorder.h
+++ b/arch/mips/include/asm/byteorder.h
@@ -50,9 +50,8 @@
 static inline __attribute_const__ __u64 __arch_swab64(__u64 x)
 {
 	__asm__(
-	"	dsbh	%0, %1			\n"
-	"	dshd	%0, %0			\n"
-	"	drotr	%0, %0, 32		\n"
+	"	dsbh	%0, %1\n"
+	"	dshd	%0, %0"
 	: "=r" (x)
 	: "r" (x));
 
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index a8eac16..d58f128 100644
--- a/arch/mips/include/asm/elf.h
+++ b/arch/mips/include/asm/elf.h
@@ -232,7 +232,7 @@
  */
 #ifdef __MIPSEB__
 #define ELF_DATA	ELFDATA2MSB
-#elif __MIPSEL__
+#elif defined(__MIPSEL__)
 #define ELF_DATA	ELFDATA2LSB
 #endif
 #define ELF_ARCH	EM_MIPS
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
index b0591ae..fd6e512 100644
--- a/arch/mips/kernel/kspd.c
+++ b/arch/mips/kernel/kspd.c
@@ -174,8 +174,8 @@
 
 static void sp_setfsuidgid( uid_t uid, gid_t gid)
 {
-	current->fsuid = uid;
-	current->fsgid = gid;
+	current->cred->fsuid = uid;
+	current->cred->fsgid = gid;
 
 	key_fsuid_changed(current);
 	key_fsgid_changed(current);
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index dc9eb72..5e77a3a 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -51,6 +51,7 @@
 	int retval;
 	struct task_struct *p;
 	struct thread_info *ti;
+	uid_t euid;
 
 	if (len < sizeof(new_mask))
 		return -EINVAL;
@@ -76,9 +77,9 @@
 	 */
 	get_task_struct(p);
 
+	euid = current_euid();
 	retval = -EPERM;
-	if ((current->euid != p->euid) && (current->euid != p->uid) &&
-			!capable(CAP_SYS_NICE)) {
+	if (euid != p->euid && euid != p->uid && !capable(CAP_SYS_NICE)) {
 		read_unlock(&tasklist_lock);
 		goto out_unlock;
 	}
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index a1b3da6..010b27e 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -1085,8 +1085,8 @@
 	v->load_addr = NULL;
 	v->len = 0;
 
-	v->uid = filp->f_uid;
-	v->gid = filp->f_gid;
+	v->uid = filp->f_cred->fsuid;
+	v->gid = filp->f_cred->fsgid;
 
 #ifdef CONFIG_MIPS_APSP_KSPD
 	/* get kspd to tell us when a syscall_exit happens */
diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h
index b72ec66..1f6fd4f 100644
--- a/arch/parisc/include/asm/tlbflush.h
+++ b/arch/parisc/include/asm/tlbflush.h
@@ -44,9 +44,12 @@
 {
 	BUG_ON(mm == &init_mm); /* Should never happen */
 
-#ifdef CONFIG_SMP
+#if 1 || defined(CONFIG_SMP)
 	flush_tlb_all();
 #else
+	/* FIXME: currently broken, causing space id and protection ids
+	 *  to go out of sync, resulting in faults on userspace accesses.
+	 */
 	if (mm) {
 		if (mm->context != 0)
 			free_sid(mm->context);
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 06213d1..f825442 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -182,7 +182,7 @@
 	si.si_errno = 0;
 	si.si_code = SI_KERNEL;
 	si.si_pid = task_pid_vnr(current);
-	si.si_uid = current->uid;
+	si.si_uid = current_uid();
 	si.si_addr = &frame->uc;
 	force_sig_info(SIGSEGV, &si, current);
 	return;
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 525c13a..79f25ce 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -141,7 +141,7 @@
 	bool
 	default y if PPC32
 
-config SCHED_NO_NO_OMIT_FRAME_POINTER
+config SCHED_OMIT_FRAME_POINTER
 	bool
 	default y
 
@@ -285,6 +285,10 @@
 config IOMMU_HELPER
 	def_bool PPC64
 
+config PPC_NEED_DMA_SYNC_OPS
+	def_bool y
+	depends on NOT_COHERENT_CACHE
+
 config HOTPLUG_CPU
 	bool "Support for enabling/disabling CPUs"
 	depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
@@ -322,7 +326,7 @@
 
 config CRASH_DUMP
 	bool "Build a kdump crash kernel"
-	depends on PPC_MULTIPLATFORM && PPC64 && RELOCATABLE
+	depends on (PPC64 && RELOCATABLE) || 6xx
 	help
 	  Build a kernel suitable for use as a kdump capture kernel.
 	  The same kernel binary can be used as production kernel and dump
@@ -401,23 +405,53 @@
 	depends on PPC64
 	default n
 
-config PPC_64K_PAGES
-	bool "64k page size"
-	depends on PPC64
-	select PPC_HAS_HASH_64K
+choice
+	prompt "Page size"
+	default PPC_4K_PAGES
 	help
-	  This option changes the kernel logical page size to 64k. On machines
-	  without processor support for 64k pages, the kernel will simulate
-	  them by loading each individual 4k page on demand transparently,
-	  while on hardware with such support, it will be used to map
-	  normal application pages.
+	  Select the kernel logical page size. Increasing the page size
+	  will reduce software overhead at each page boundary, allow
+	  hardware prefetch mechanisms to be more effective, and allow
+	  larger dma transfers increasing IO efficiency and reducing
+	  overhead. However the utilization of memory will increase.
+	  For example, each cached file will using a multiple of the
+	  page size to hold its contents and the difference between the
+	  end of file and the end of page is wasted.
+
+	  Some dedicated systems, such as software raid serving with
+	  accelerated calculations, have shown significant increases.
+
+	  If you configure a 64 bit kernel for 64k pages but the
+	  processor does not support them, then the kernel will simulate
+	  them with 4k pages, loading them on demand, but with the
+	  reduced software overhead and larger internal fragmentation.
+	  For the 32 bit kernel, a large page option will not be offered
+	  unless it is supported by the configured processor.
+
+	  If unsure, choose 4K_PAGES.
+
+config PPC_4K_PAGES
+	bool "4k page size"
+
+config PPC_16K_PAGES
+	bool "16k page size" if 44x
+
+config PPC_64K_PAGES
+	bool "64k page size" if 44x || PPC_STD_MMU_64
+	select PPC_HAS_HASH_64K if PPC_STD_MMU_64
+
+endchoice
 
 config FORCE_MAX_ZONEORDER
 	int "Maximum zone order"
-	range 9 64 if PPC_64K_PAGES
-	default "9" if PPC_64K_PAGES
-	range 13 64 if PPC64 && !PPC_64K_PAGES
-	default "13" if PPC64 && !PPC_64K_PAGES
+	range 9 64 if PPC_STD_MMU_64 && PPC_64K_PAGES
+	default "9" if PPC_STD_MMU_64 && PPC_64K_PAGES
+	range 13 64 if PPC_STD_MMU_64 && !PPC_64K_PAGES
+	default "13" if PPC_STD_MMU_64 && !PPC_64K_PAGES
+	range 9 64 if PPC_STD_MMU_32 && PPC_16K_PAGES
+	default "9" if PPC_STD_MMU_32 && PPC_16K_PAGES
+	range 7 64 if PPC_STD_MMU_32 && PPC_64K_PAGES
+	default "7" if PPC_STD_MMU_32 && PPC_64K_PAGES
 	range 11 64
 	default "11"
 	help
@@ -437,7 +471,7 @@
 
 config PPC_SUBPAGE_PROT
 	bool "Support setting protections for 4k subpages"
-	depends on PPC_64K_PAGES
+	depends on PPC_STD_MMU_64 && PPC_64K_PAGES
 	help
 	  This option adds support for a system call to allow user programs
 	  to set access permissions (read/write, readonly, or no access)
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 15eb278..08f7cc0 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -2,6 +2,15 @@
 
 source "lib/Kconfig.debug"
 
+config PRINT_STACK_DEPTH
+	int "Stack depth to print" if DEBUG_KERNEL
+	default 64
+	help
+	  This option allows you to set the stack depth that the kernel
+	  prints in stack traces. This can be useful if your display is
+	  too small and stack traces cause important information to
+	  scroll off the screen.
+
 config DEBUG_STACKOVERFLOW
 	bool "Check for stack overflows"
 	depends on DEBUG_KERNEL
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 1f06670..72d17f5 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -107,7 +107,6 @@
 # (We use all available options to help semi-broken compilers)
 KBUILD_CFLAGS += $(call cc-option,-mno-spe)
 KBUILD_CFLAGS += $(call cc-option,-mspe=no)
-KBUILD_CFLAGS += $(call cc-option,-mabi=no-spe)
 
 # Enable unit-at-a-time mode when possible. It shrinks the
 # kernel considerably.
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 3d3daa6..f328299 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -194,6 +194,7 @@
 image-$(CONFIG_PPC_IBM_CELL_BLADE)	+= zImage.pseries
 image-$(CONFIG_PPC_PS3)			+= dtbImage.ps3
 image-$(CONFIG_PPC_CELLEB)		+= zImage.pseries
+image-$(CONFIG_PPC_CELL_QPACE)		+= zImage.pseries
 image-$(CONFIG_PPC_CHRP)		+= zImage.chrp
 image-$(CONFIG_PPC_EFIKA)		+= zImage.chrp
 image-$(CONFIG_PPC_PMAC)		+= zImage.pmac
diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c
index 5d12336..a7e21a3 100644
--- a/arch/powerpc/boot/devtree.c
+++ b/arch/powerpc/boot/devtree.c
@@ -213,7 +213,7 @@
 		u32 range_addr[MAX_ADDR_CELLS];
 		u32 range_size[MAX_ADDR_CELLS];
 
-		copy_val(range_addr, ranges + i, naddr);
+		copy_val(range_addr, ranges + i, nregaddr);
 		copy_val(range_size, ranges + i + nregaddr + naddr, nsize);
 
 		if (compare_reg(reg, range_addr, range_size))
diff --git a/arch/powerpc/boot/dts/asp834x-redboot.dts b/arch/powerpc/boot/dts/asp834x-redboot.dts
index 6235fca..524af7e 100644
--- a/arch/powerpc/boot/dts/asp834x-redboot.dts
+++ b/arch/powerpc/boot/dts/asp834x-redboot.dts
@@ -199,8 +199,26 @@
 				reg = <0x2>;
 				device_type = "ethernet-phy";
 			};
+
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+
 		enet0: ethernet@24000 {
 			cell-index = <0>;
 			device_type = "network";
@@ -210,6 +228,7 @@
 			local-mac-address = [ 00 08 e5 11 32 33 ];
 			interrupts = <32 0x8 33 0x8 34 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 			linux,network-index = <0>;
 		};
@@ -223,6 +242,7 @@
 			local-mac-address = [ 00 08 e5 11 32 34 ];
 			interrupts = <35 0x8 36 0x8 37 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 			linux,network-index = <1>;
 		};
diff --git a/arch/powerpc/boot/dts/bamboo.dts b/arch/powerpc/boot/dts/bamboo.dts
index 6ce0cc2..aa68911 100644
--- a/arch/powerpc/boot/dts/bamboo.dts
+++ b/arch/powerpc/boot/dts/bamboo.dts
@@ -269,7 +269,8 @@
 			 * later cannot be changed. Chip supports a second
 			 * IO range but we don't use it for now
 			 */
-			ranges = <0x02000000 0x00000000 0xa0000000 0x00000000 0xa0000000 0x00000000 0x20000000
+			ranges = <0x02000000 0x00000000 0xa0000000 0x00000000 0xa0000000 0x00000000 0x40000000
+				  0x02000000 0x00000000 0x00000000 0x00000000 0xe0000000 0x00000000 0x00100000
 				  0x01000000 0x00000000 0x00000000 0x00000000 0xe8000000 0x00000000 0x00010000>;
 
 			/* Inbound 2GB range starting at 0 */
diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts
index 79fe412..8b5ba82 100644
--- a/arch/powerpc/boot/dts/canyonlands.dts
+++ b/arch/powerpc/boot/dts/canyonlands.dts
@@ -40,6 +40,7 @@
 			d-cache-size = <32768>;
 			dcr-controller;
 			dcr-access-method = "native";
+			next-level-cache = <&L2C0>;
 		};
 	};
 
@@ -104,6 +105,16 @@
 		dcr-reg = <0x00c 0x002>;
 	};
 
+	L2C0: l2c {
+		compatible = "ibm,l2-cache-460ex", "ibm,l2-cache";
+		dcr-reg = <0x020 0x008		/* Internal SRAM DCR's */
+			   0x030 0x008>;	/* L2 cache DCR's */
+		cache-line-size = <32>;		/* 32 bytes */
+		cache-size = <262144>;		/* L2, 256K */
+		interrupt-parent = <&UIC1>;
+		interrupts = <11 1>;
+	};
+
 	plb {
 		compatible = "ibm,plb-460ex", "ibm,plb4";
 		#address-cells = <2>;
@@ -343,6 +354,7 @@
 			 * later cannot be changed
 			 */
 			ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000
+				  0x02000000 0x00000000 0x00000000 0x0000000c 0x0ee00000 0x00000000 0x00100000
 				  0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>;
 
 			/* Inbound 2GB range starting at 0 */
@@ -373,6 +385,7 @@
 			 * later cannot be changed
 			 */
 			ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000
+				  0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000
 				  0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>;
 
 			/* Inbound 2GB range starting at 0 */
@@ -414,6 +427,7 @@
 			 * later cannot be changed
 			 */
 			ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000
+				  0x02000000 0x00000000 0x00000000 0x0000000f 0x00100000 0x00000000 0x00100000
 				  0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>;
 
 			/* Inbound 2GB range starting at 0 */
diff --git a/arch/powerpc/boot/dts/gef_sbc610.dts b/arch/powerpc/boot/dts/gef_sbc610.dts
index e48cfa7..9708b34 100644
--- a/arch/powerpc/boot/dts/gef_sbc610.dts
+++ b/arch/powerpc/boot/dts/gef_sbc610.dts
@@ -98,6 +98,12 @@
 			interrupt-parent = <&mpic>;
 
 		};
+		gef_gpio: gpio@7,14000 {
+			#gpio-cells = <2>;
+			compatible = "gef,sbc610-gpio";
+			reg = <0x7 0x14000 0x24>;
+			gpio-controller;
+		};
 	};
 
 	soc@fef00000 {
@@ -119,6 +125,11 @@
 			interrupt-parent = <&mpic>;
 			dfsrr;
 
+			rtc@51 {
+				compatible = "epson,rx8581";
+				reg = <0x00000051>;
+			};
+
 			eti@6b {
 				compatible = "dallas,ds1682";
 				reg = <0x6b>;
diff --git a/arch/powerpc/boot/dts/ksi8560.dts b/arch/powerpc/boot/dts/ksi8560.dts
index 4973758..3bfff47 100644
--- a/arch/powerpc/boot/dts/ksi8560.dts
+++ b/arch/powerpc/boot/dts/ksi8560.dts
@@ -141,8 +141,26 @@
 				reg = <0x2>;
 				device_type = "ethernet-phy";
 			};
+
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+
 		enet0: ethernet@24000 {
 			device_type = "network";
 			model = "TSEC";
@@ -152,6 +170,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&PHY1>;
 		};
 
@@ -164,6 +183,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&PHY2>;
 		};
 
diff --git a/arch/powerpc/boot/dts/kuroboxHD.dts b/arch/powerpc/boot/dts/kuroboxHD.dts
index 2e5a1a1..8d725d1 100644
--- a/arch/powerpc/boot/dts/kuroboxHD.dts
+++ b/arch/powerpc/boot/dts/kuroboxHD.dts
@@ -76,7 +76,6 @@
 			interrupt-parent = <&mpic>;
 
 			rtc@32 {
-				device_type = "rtc";
 				compatible = "ricoh,rs5c372a";
 				reg = <0x32>;
 			};
diff --git a/arch/powerpc/boot/dts/kuroboxHG.dts b/arch/powerpc/boot/dts/kuroboxHG.dts
index e4916e6..b13a11e 100644
--- a/arch/powerpc/boot/dts/kuroboxHG.dts
+++ b/arch/powerpc/boot/dts/kuroboxHG.dts
@@ -76,7 +76,6 @@
 			interrupt-parent = <&mpic>;
 
 			rtc@32 {
-				device_type = "rtc";
 				compatible = "ricoh,rs5c372a";
 				reg = <0x32>;
 			};
diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts
index 2cf9a87..3f7a5dc 100644
--- a/arch/powerpc/boot/dts/lite5200.dts
+++ b/arch/powerpc/boot/dts/lite5200.dts
@@ -130,7 +130,6 @@
 
 		rtc@800 {	// Real time clock
 			compatible = "fsl,mpc5200-rtc";
-			device_type = "rtc";
 			reg = <0x800 0x100>;
 			interrupts = <1 5 0 1 6 0>;
 			interrupt-parent = <&mpc5200_pic>;
diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts
index 7bd5b9c..63e3bb4 100644
--- a/arch/powerpc/boot/dts/lite5200b.dts
+++ b/arch/powerpc/boot/dts/lite5200b.dts
@@ -130,7 +130,6 @@
 
 		rtc@800 {	// Real time clock
 			compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
-			device_type = "rtc";
 			reg = <0x800 0x100>;
 			interrupts = <1 5 0 1 6 0>;
 			interrupt-parent = <&mpc5200_pic>;
diff --git a/arch/powerpc/boot/dts/motionpro.dts b/arch/powerpc/boot/dts/motionpro.dts
index 9e3c921..52ba6f9 100644
--- a/arch/powerpc/boot/dts/motionpro.dts
+++ b/arch/powerpc/boot/dts/motionpro.dts
@@ -248,7 +248,6 @@
 			fsl5200-clocking;
 
 			rtc@68 {
-				device_type = "rtc";
 				compatible = "dallas,ds1339";
 				reg = <0x68>;
 			};
diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts
index 5030317..d4df8b6 100644
--- a/arch/powerpc/boot/dts/mpc8313erdb.dts
+++ b/arch/powerpc/boot/dts/mpc8313erdb.dts
@@ -190,6 +190,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <37 0x8 36 0x8 35 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = < &tbi0 >;
 			phy-handle = < &phy1 >;
 			fsl,magic-packet;
 
@@ -210,6 +211,10 @@
 					reg = <0x4>;
 					device_type = "ethernet-phy";
 				};
+				tbi0: tbi-phy@11 {
+					reg = <0x11>;
+					device_type = "tbi-phy";
+				};
 			};
 		};
 
@@ -222,9 +227,24 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <34 0x8 33 0x8 32 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = < &tbi1 >;
 			phy-handle = < &phy4 >;
 			sleep = <&pmc 0x10000000>;
 			fsl,magic-packet;
+
+			mdio@25520 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,gianfar-tbi";
+				reg = <0x25520 0x20>;
+
+				tbi1: tbi-phy@11 {
+					reg = <0x11>;
+					device_type = "tbi-phy";
+				};
+			};
+
+
 		};
 
 		serial0: serial@4500 {
diff --git a/arch/powerpc/boot/dts/mpc8315erdb.dts b/arch/powerpc/boot/dts/mpc8315erdb.dts
index 6b85067..072c9b0 100644
--- a/arch/powerpc/boot/dts/mpc8315erdb.dts
+++ b/arch/powerpc/boot/dts/mpc8315erdb.dts
@@ -117,7 +117,6 @@
 			interrupt-parent = <&ipic>;
 			dfsrr;
 			rtc@68 {
-				device_type = "rtc";
 				compatible = "dallas,ds1339";
 				reg = <0x68>;
 			};
@@ -206,8 +205,25 @@
 				reg = <0x1>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+
 		enet0: ethernet@24000 {
 			cell-index = <0>;
 			device_type = "network";
@@ -217,6 +233,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <32 0x8 33 0x8 34 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = < &phy0 >;
 		};
 
@@ -229,6 +246,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 0x8 36 0x8 37 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = < &phy1 >;
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
index 4bdbaf4..b5eda94 100644
--- a/arch/powerpc/boot/dts/mpc8349emitx.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
@@ -85,7 +85,6 @@
 			dfsrr;
 
 			rtc@68 {
-				device_type = "rtc";
 				compatible = "dallas,ds1339";
 				reg = <0x68>;
 				interrupts = <18 0x8>;
@@ -184,6 +183,22 @@
 				reg = <0x1c>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -195,6 +210,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <32 0x8 33 0x8 34 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy1c>;
 			linux,network-index = <0>;
 		};
@@ -211,6 +227,7 @@
 			/* Vitesse 7385 isn't on the MDIO bus */
 			fixed-link = <1 1 1000 0 0>;
 			linux,network-index = <1>;
+			tbi-handle = <&tbi1>;
 		};
 
 		serial0: serial@4500 {
diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
index fa40647..c87a601 100644
--- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
@@ -83,7 +83,6 @@
 			dfsrr;
 
 			rtc@68 {
-				device_type = "rtc";
 				compatible = "dallas,ds1339";
 				reg = <0x68>;
 				interrupts = <18 0x8>;
@@ -163,6 +162,10 @@
 				reg = <0x1c>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -174,6 +177,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <32 0x8 33 0x8 34 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy1c>;
 			linux,network-index = <0>;
 		};
diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts
index c986c54..d9adba0 100644
--- a/arch/powerpc/boot/dts/mpc834x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc834x_mds.dts
@@ -185,8 +185,25 @@
 				reg = <0x1>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+
 		enet0: ethernet@24000 {
 			cell-index = <0>;
 			device_type = "network";
@@ -196,6 +213,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <32 0x8 33 0x8 34 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 			linux,network-index = <0>;
 		};
@@ -209,6 +227,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 0x8 36 0x8 37 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 			linux,network-index = <1>;
 		};
diff --git a/arch/powerpc/boot/dts/mpc8377_mds.dts b/arch/powerpc/boot/dts/mpc8377_mds.dts
index 0484561..1d14d70 100644
--- a/arch/powerpc/boot/dts/mpc8377_mds.dts
+++ b/arch/powerpc/boot/dts/mpc8377_mds.dts
@@ -193,8 +193,25 @@
 				reg = <0x3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+
 		enet0: ethernet@24000 {
 			cell-index = <0>;
 			device_type = "network";
@@ -205,6 +222,7 @@
 			interrupts = <32 0x8 33 0x8 34 0x8>;
 			phy-connection-type = "mii";
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -218,6 +236,7 @@
 			interrupts = <35 0x8 36 0x8 37 0x8>;
 			phy-connection-type = "mii";
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy3>;
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8377_rdb.dts b/arch/powerpc/boot/dts/mpc8377_rdb.dts
index 435ef3d..9413af3 100644
--- a/arch/powerpc/boot/dts/mpc8377_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8377_rdb.dts
@@ -117,7 +117,6 @@
 			interrupt-parent = <&ipic>;
 			dfsrr;
 			rtc@68 {
-				device_type = "rtc";
 				compatible = "dallas,ds1339";
 				reg = <0x68>;
 			};
@@ -211,8 +210,25 @@
 				reg = <0x2>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+
 		enet0: ethernet@24000 {
 			cell-index = <0>;
 			device_type = "network";
@@ -223,6 +239,7 @@
 			interrupts = <32 0x8 33 0x8 34 0x8>;
 			phy-connection-type = "mii";
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -237,6 +254,7 @@
 			phy-connection-type = "mii";
 			interrupt-parent = <&ipic>;
 			fixed-link = <1 1 1000 0 0>;
+			tbi-handle = <&tbi1>;
 		};
 
 		serial0: serial@4500 {
diff --git a/arch/powerpc/boot/dts/mpc8378_mds.dts b/arch/powerpc/boot/dts/mpc8378_mds.dts
index 67a08d2..b85fc02 100644
--- a/arch/powerpc/boot/dts/mpc8378_mds.dts
+++ b/arch/powerpc/boot/dts/mpc8378_mds.dts
@@ -232,8 +232,25 @@
 				reg = <0x3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+
 		enet0: ethernet@24000 {
 			cell-index = <0>;
 			device_type = "network";
@@ -244,6 +261,7 @@
 			interrupts = <32 0x8 33 0x8 34 0x8>;
 			phy-connection-type = "mii";
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -257,6 +275,7 @@
 			interrupts = <35 0x8 36 0x8 37 0x8>;
 			phy-connection-type = "mii";
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy3>;
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8378_rdb.dts b/arch/powerpc/boot/dts/mpc8378_rdb.dts
index b11e68f..23c10ce 100644
--- a/arch/powerpc/boot/dts/mpc8378_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8378_rdb.dts
@@ -117,7 +117,6 @@
 			interrupt-parent = <&ipic>;
 			dfsrr;
 			rtc@68 {
-				device_type = "rtc";
 				compatible = "dallas,ds1339";
 				reg = <0x68>;
 			};
@@ -211,8 +210,25 @@
 				reg = <0x2>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+
 		enet0: ethernet@24000 {
 			cell-index = <0>;
 			device_type = "network";
diff --git a/arch/powerpc/boot/dts/mpc8379_mds.dts b/arch/powerpc/boot/dts/mpc8379_mds.dts
index 323370a..acf06c4 100644
--- a/arch/powerpc/boot/dts/mpc8379_mds.dts
+++ b/arch/powerpc/boot/dts/mpc8379_mds.dts
@@ -232,6 +232,22 @@
 				reg = <0x3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -244,6 +260,7 @@
 			interrupts = <32 0x8 33 0x8 34 0x8>;
 			phy-connection-type = "mii";
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -257,6 +274,7 @@
 			interrupts = <35 0x8 36 0x8 37 0x8>;
 			phy-connection-type = "mii";
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy3>;
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8379_rdb.dts b/arch/powerpc/boot/dts/mpc8379_rdb.dts
index 337af6e..72cdc3c 100644
--- a/arch/powerpc/boot/dts/mpc8379_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8379_rdb.dts
@@ -117,7 +117,6 @@
 			interrupt-parent = <&ipic>;
 			dfsrr;
 			rtc@68 {
-				device_type = "rtc";
 				compatible = "dallas,ds1339";
 				reg = <0x68>;
 			};
@@ -211,6 +210,22 @@
 				reg = <0x2>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -223,6 +238,7 @@
 			interrupts = <32 0x8 33 0x8 34 0x8>;
 			phy-connection-type = "mii";
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -237,6 +253,7 @@
 			phy-connection-type = "mii";
 			interrupt-parent = <&ipic>;
 			fixed-link = <1 1 1000 0 0>;
+			tbi-handle = <&tbi1>;
 		};
 
 		serial0: serial@4500 {
diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
index 35db1e5..3c905df 100644
--- a/arch/powerpc/boot/dts/mpc8536ds.dts
+++ b/arch/powerpc/boot/dts/mpc8536ds.dts
@@ -155,6 +155,22 @@
 				reg = <1>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@26520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x26520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		usb@22000 {
@@ -186,6 +202,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy1>;
 			phy-connection-type = "rgmii-id";
 		};
@@ -199,6 +216,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <31 2 32 2 33 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy0>;
 			phy-connection-type = "rgmii-id";
 		};
diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts
index 9568bfa..79570ff 100644
--- a/arch/powerpc/boot/dts/mpc8540ads.dts
+++ b/arch/powerpc/boot/dts/mpc8540ads.dts
@@ -150,6 +150,34 @@
 				reg = <0x3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@26520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x26520 0x20>;
+
+			tbi2: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -161,6 +189,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 		};
 
@@ -173,6 +202,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
@@ -185,6 +215,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <41 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi2>;
 			phy-handle = <&phy3>;
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts
index 6480f4f..221036a 100644
--- a/arch/powerpc/boot/dts/mpc8541cds.dts
+++ b/arch/powerpc/boot/dts/mpc8541cds.dts
@@ -144,6 +144,22 @@
 				reg = <0x1>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -155,6 +171,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 		};
 
@@ -167,6 +184,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts
index f1fb207..b9da421 100644
--- a/arch/powerpc/boot/dts/mpc8544ds.dts
+++ b/arch/powerpc/boot/dts/mpc8544ds.dts
@@ -116,8 +116,26 @@
 				reg = <0x1>;
 				device_type = "ethernet-phy";
 			};
+
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
+		mdio@26520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x26520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+
 		dma@21300 {
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -169,6 +187,7 @@
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
 			phy-handle = <&phy0>;
+			tbi-handle = <&tbi0>;
 			phy-connection-type = "rgmii-id";
 		};
 
@@ -182,6 +201,7 @@
 			interrupts = <31 2 32 2 33 2>;
 			interrupt-parent = <&mpic>;
 			phy-handle = <&phy1>;
+			tbi-handle = <&tbi1>;
 			phy-connection-type = "rgmii-id";
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
index 431b496..df774a7 100644
--- a/arch/powerpc/boot/dts/mpc8548cds.dts
+++ b/arch/powerpc/boot/dts/mpc8548cds.dts
@@ -172,6 +172,46 @@
 				reg = <0x3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@26520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x26520 0x20>;
+
+			tbi2: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@27520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x27520 0x20>;
+
+			tbi3: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -183,6 +223,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 		};
 
@@ -195,6 +236,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
@@ -208,6 +250,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <31 2 32 2 33 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi2>;
 			phy-handle = <&phy2>;
 		};
 
@@ -220,6 +263,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <37 2 38 2 39 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi3>;
 			phy-handle = <&phy3>;
 		};
  */
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts
index d833a5c..053b01e 100644
--- a/arch/powerpc/boot/dts/mpc8555cds.dts
+++ b/arch/powerpc/boot/dts/mpc8555cds.dts
@@ -144,6 +144,22 @@
 				reg = <0x1>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -155,6 +171,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 		};
 
@@ -167,6 +184,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
index 4d1f2f2..11b1bcb 100644
--- a/arch/powerpc/boot/dts/mpc8560ads.dts
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -145,6 +145,22 @@
 				reg = <0x3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -156,6 +172,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 		};
 
@@ -168,6 +185,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts
index c80158f..1955bd9 100644
--- a/arch/powerpc/boot/dts/mpc8568mds.dts
+++ b/arch/powerpc/boot/dts/mpc8568mds.dts
@@ -179,6 +179,22 @@
 				reg = <0x3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -190,6 +206,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
  			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -202,6 +219,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
  			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy3>;
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8572ds.dts b/arch/powerpc/boot/dts/mpc8572ds.dts
index 5c69b2f..21459e1 100644
--- a/arch/powerpc/boot/dts/mpc8572ds.dts
+++ b/arch/powerpc/boot/dts/mpc8572ds.dts
@@ -63,6 +63,119 @@
 		device_type = "memory";
 	};
 
+	localbus@ffe05000 {
+		#address-cells = <2>;
+		#size-cells = <1>;
+		compatible = "fsl,mpc8572-elbc", "fsl,elbc", "simple-bus";
+		reg = <0 0xffe05000 0 0x1000>;
+		interrupts = <19 2>;
+		interrupt-parent = <&mpic>;
+
+		ranges = <0x0 0x0 0x0 0xe8000000 0x08000000
+			  0x1 0x0 0x0 0xe0000000 0x08000000
+			  0x2 0x0 0x0 0xffa00000 0x00040000
+			  0x3 0x0 0x0 0xffdf0000 0x00008000
+			  0x4 0x0 0x0 0xffa40000 0x00040000
+			  0x5 0x0 0x0 0xffa80000 0x00040000
+			  0x6 0x0 0x0 0xffac0000 0x00040000>;
+
+		nor@0,0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "cfi-flash";
+			reg = <0x0 0x0 0x8000000>;
+			bank-width = <2>;
+			device-width = <1>;
+
+			ramdisk@0 {
+				reg = <0x0 0x03000000>;
+				readl-only;
+			};
+
+			diagnostic@3000000 {
+				reg = <0x03000000 0x00e00000>;
+				read-only;
+			};
+
+			dink@3e00000 {
+				reg = <0x03e00000 0x00200000>;
+				read-only;
+			};
+
+			kernel@4000000 {
+				reg = <0x04000000 0x00400000>;
+				read-only;
+			};
+
+			jffs2@4400000 {
+				reg = <0x04400000 0x03b00000>;
+			};
+
+			dtb@7f00000 {
+				reg = <0x07f00000 0x00080000>;
+				read-only;
+			};
+
+			u-boot@7f80000 {
+				reg = <0x07f80000 0x00080000>;
+				read-only;
+			};
+		};
+
+		nand@2,0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,mpc8572-fcm-nand",
+				     "fsl,elbc-fcm-nand";
+			reg = <0x2 0x0 0x40000>;
+
+			u-boot@0 {
+				reg = <0x0 0x02000000>;
+				read-only;
+			};
+
+			jffs2@2000000 {
+				reg = <0x02000000 0x10000000>;
+			};
+
+			ramdisk@12000000 {
+				reg = <0x12000000 0x08000000>;
+				read-only;
+			};
+
+			kernel@1a000000 {
+				reg = <0x1a000000 0x04000000>;
+			};
+
+			dtb@1e000000 {
+				reg = <0x1e000000 0x01000000>;
+				read-only;
+			};
+
+			empty@1f000000 {
+				reg = <0x1f000000 0x21000000>;
+			};
+		};
+
+		nand@4,0 {
+			compatible = "fsl,mpc8572-fcm-nand",
+				     "fsl,elbc-fcm-nand";
+			reg = <0x4 0x0 0x40000>;
+		};
+
+		nand@5,0 {
+			compatible = "fsl,mpc8572-fcm-nand",
+				     "fsl,elbc-fcm-nand";
+			reg = <0x5 0x0 0x40000>;
+		};
+
+		nand@6,0 {
+			compatible = "fsl,mpc8572-fcm-nand",
+				     "fsl,elbc-fcm-nand";
+			reg = <0x6 0x0 0x40000>;
+		};
+	};
+
 	soc8572@ffe00000 {
 		#address-cells = <1>;
 		#size-cells = <1>;
@@ -225,6 +338,47 @@
 				interrupts = <10 1>;
 				reg = <0x3>;
 			};
+
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@26520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x26520 0x20>;
+
+			tbi2: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@27520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x27520 0x20>;
+
+			tbi3: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -236,6 +390,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 			phy-connection-type = "rgmii-id";
 		};
@@ -249,6 +404,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 			phy-connection-type = "rgmii-id";
 		};
@@ -262,6 +418,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <31 2 32 2 33 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi2>;
 			phy-handle = <&phy2>;
 			phy-connection-type = "rgmii-id";
 		};
@@ -275,6 +432,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <37 2 38 2 39 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi3>;
 			phy-handle = <&phy3>;
 			phy-connection-type = "rgmii-id";
 		};
diff --git a/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts b/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts
new file mode 100644
index 0000000..c114c4e
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts
@@ -0,0 +1,483 @@
+/*
+ * MPC8572 DS Core0 Device Tree Source in CAMP mode.
+ *
+ * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
+ * can be shared, all the other devices must be assigned to one core only.
+ * This dts file allows core0 to have memory, l2, i2c, dma1, global-util, eth0,
+ * eth1, crypto, pci0, pci1.
+ *
+ * Copyright 2007, 2008 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+/ {
+	model = "fsl,MPC8572DS";
+	compatible = "fsl,MPC8572DS", "fsl,MPC8572DS-CAMP";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	aliases {
+		ethernet0 = &enet0;
+		ethernet1 = &enet1;
+		serial0 = &serial0;
+		pci0 = &pci0;
+		pci1 = &pci1;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,8572@0 {
+			device_type = "cpu";
+			reg = <0x0>;
+			d-cache-line-size = <32>;	// 32 bytes
+			i-cache-line-size = <32>;	// 32 bytes
+			d-cache-size = <0x8000>;		// L1, 32K
+			i-cache-size = <0x8000>;		// L1, 32K
+			timebase-frequency = <0>;
+			bus-frequency = <0>;
+			clock-frequency = <0>;
+			next-level-cache = <&L2>;
+		};
+
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x0 0x0>;	// Filled by U-Boot
+	};
+
+	soc8572@ffe00000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "soc";
+		compatible = "simple-bus";
+		ranges = <0x0 0xffe00000 0x100000>;
+		reg = <0xffe00000 0x1000>;	// CCSRBAR & soc regs, remove once parse code for immrbase fixed
+		bus-frequency = <0>;		// Filled out by uboot.
+
+		memory-controller@2000 {
+			compatible = "fsl,mpc8572-memory-controller";
+			reg = <0x2000 0x1000>;
+			interrupt-parent = <&mpic>;
+			interrupts = <18 2>;
+		};
+
+		memory-controller@6000 {
+			compatible = "fsl,mpc8572-memory-controller";
+			reg = <0x6000 0x1000>;
+			interrupt-parent = <&mpic>;
+			interrupts = <18 2>;
+		};
+
+		L2: l2-cache-controller@20000 {
+			compatible = "fsl,mpc8572-l2-cache-controller";
+			reg = <0x20000 0x1000>;
+			cache-line-size = <32>;	// 32 bytes
+			cache-size = <0x80000>;	// L2, 512K
+			interrupt-parent = <&mpic>;
+			interrupts = <16 2>;
+		};
+
+		i2c@3000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <0>;
+			compatible = "fsl-i2c";
+			reg = <0x3000 0x100>;
+			interrupts = <43 2>;
+			interrupt-parent = <&mpic>;
+			dfsrr;
+		};
+
+		i2c@3100 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <1>;
+			compatible = "fsl-i2c";
+			reg = <0x3100 0x100>;
+			interrupts = <43 2>;
+			interrupt-parent = <&mpic>;
+			dfsrr;
+		};
+
+		dma@21300 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,mpc8572-dma", "fsl,eloplus-dma";
+			reg = <0x21300 0x4>;
+			ranges = <0x0 0x21100 0x200>;
+			cell-index = <0>;
+			dma-channel@0 {
+				compatible = "fsl,mpc8572-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x0 0x80>;
+				cell-index = <0>;
+				interrupt-parent = <&mpic>;
+				interrupts = <20 2>;
+			};
+			dma-channel@80 {
+				compatible = "fsl,mpc8572-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x80 0x80>;
+				cell-index = <1>;
+				interrupt-parent = <&mpic>;
+				interrupts = <21 2>;
+			};
+			dma-channel@100 {
+				compatible = "fsl,mpc8572-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x100 0x80>;
+				cell-index = <2>;
+				interrupt-parent = <&mpic>;
+				interrupts = <22 2>;
+			};
+			dma-channel@180 {
+				compatible = "fsl,mpc8572-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x180 0x80>;
+				cell-index = <3>;
+				interrupt-parent = <&mpic>;
+				interrupts = <23 2>;
+			};
+		};
+
+		mdio@24520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-mdio";
+			reg = <0x24520 0x20>;
+
+			phy0: ethernet-phy@0 {
+				interrupt-parent = <&mpic>;
+				interrupts = <10 1>;
+				reg = <0x0>;
+			};
+			phy1: ethernet-phy@1 {
+				interrupt-parent = <&mpic>;
+				interrupts = <10 1>;
+				reg = <0x1>;
+			};
+		};
+
+		enet0: ethernet@24000 {
+			cell-index = <0>;
+			device_type = "network";
+			model = "eTSEC";
+			compatible = "gianfar";
+			reg = <0x24000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <29 2 30 2 34 2>;
+			interrupt-parent = <&mpic>;
+			phy-handle = <&phy0>;
+			phy-connection-type = "rgmii-id";
+		};
+
+		enet1: ethernet@25000 {
+			cell-index = <1>;
+			device_type = "network";
+			model = "eTSEC";
+			compatible = "gianfar";
+			reg = <0x25000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <35 2 36 2 40 2>;
+			interrupt-parent = <&mpic>;
+			phy-handle = <&phy1>;
+			phy-connection-type = "rgmii-id";
+		};
+
+		serial0: serial@4500 {
+			cell-index = <0>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x4500 0x100>;
+			clock-frequency = <0>;
+		};
+
+		global-utilities@e0000 {	//global utilities block
+			compatible = "fsl,mpc8572-guts";
+			reg = <0xe0000 0x1000>;
+			fsl,has-rstcr;
+		};
+
+		crypto@30000 {
+			compatible = "fsl,sec3.0", "fsl,sec2.4", "fsl,sec2.2",
+				     "fsl,sec2.1", "fsl,sec2.0";
+			reg = <0x30000 0x10000>;
+			interrupts = <45 2 58 2>;
+			interrupt-parent = <&mpic>;
+			fsl,num-channels = <4>;
+			fsl,channel-fifo-len = <24>;
+			fsl,exec-units-mask = <0x9fe>;
+			fsl,descriptor-types-mask = <0x3ab0ebf>;
+		};
+
+		mpic: pic@40000 {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <0x40000 0x40000>;
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+			protected-sources = <
+			31 32 33 37 38 39       /* enet2 enet3 */
+			76 77 78 79 27 42	/* dma2 pci2 serial*/
+			0xe0 0xe1 0xe2 0xe3     /* msi */
+			0xe4 0xe5 0xe6 0xe7
+			>;
+		};
+	};
+
+	pci0: pcie@ffe08000 {
+		cell-index = <0>;
+		compatible = "fsl,mpc8548-pcie";
+		device_type = "pci";
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = <0xffe08000 0x1000>;
+		bus-range = <0 255>;
+		ranges = <0x2000000 0x0 0x80000000 0x80000000 0x0 0x20000000
+			  0x1000000 0x0 0x0 0xffc00000 0x0 0x10000>;
+		clock-frequency = <33333333>;
+		interrupt-parent = <&mpic>;
+		interrupts = <24 2>;
+		interrupt-map-mask = <0xff00 0x0 0x0 0x7>;
+		interrupt-map = <
+			/* IDSEL 0x11 func 0 - PCI slot 1 */
+			0x8800 0x0 0x0 0x1 &mpic 0x2 0x1
+			0x8800 0x0 0x0 0x2 &mpic 0x3 0x1
+			0x8800 0x0 0x0 0x3 &mpic 0x4 0x1
+			0x8800 0x0 0x0 0x4 &mpic 0x1 0x1
+
+			/* IDSEL 0x11 func 1 - PCI slot 1 */
+			0x8900 0x0 0x0 0x1 &mpic 0x2 0x1
+			0x8900 0x0 0x0 0x2 &mpic 0x3 0x1
+			0x8900 0x0 0x0 0x3 &mpic 0x4 0x1
+			0x8900 0x0 0x0 0x4 &mpic 0x1 0x1
+
+			/* IDSEL 0x11 func 2 - PCI slot 1 */
+			0x8a00 0x0 0x0 0x1 &mpic 0x2 0x1
+			0x8a00 0x0 0x0 0x2 &mpic 0x3 0x1
+			0x8a00 0x0 0x0 0x3 &mpic 0x4 0x1
+			0x8a00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+			/* IDSEL 0x11 func 3 - PCI slot 1 */
+			0x8b00 0x0 0x0 0x1 &mpic 0x2 0x1
+			0x8b00 0x0 0x0 0x2 &mpic 0x3 0x1
+			0x8b00 0x0 0x0 0x3 &mpic 0x4 0x1
+			0x8b00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+			/* IDSEL 0x11 func 4 - PCI slot 1 */
+			0x8c00 0x0 0x0 0x1 &mpic 0x2 0x1
+			0x8c00 0x0 0x0 0x2 &mpic 0x3 0x1
+			0x8c00 0x0 0x0 0x3 &mpic 0x4 0x1
+			0x8c00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+			/* IDSEL 0x11 func 5 - PCI slot 1 */
+			0x8d00 0x0 0x0 0x1 &mpic 0x2 0x1
+			0x8d00 0x0 0x0 0x2 &mpic 0x3 0x1
+			0x8d00 0x0 0x0 0x3 &mpic 0x4 0x1
+			0x8d00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+			/* IDSEL 0x11 func 6 - PCI slot 1 */
+			0x8e00 0x0 0x0 0x1 &mpic 0x2 0x1
+			0x8e00 0x0 0x0 0x2 &mpic 0x3 0x1
+			0x8e00 0x0 0x0 0x3 &mpic 0x4 0x1
+			0x8e00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+			/* IDSEL 0x11 func 7 - PCI slot 1 */
+			0x8f00 0x0 0x0 0x1 &mpic 0x2 0x1
+			0x8f00 0x0 0x0 0x2 &mpic 0x3 0x1
+			0x8f00 0x0 0x0 0x3 &mpic 0x4 0x1
+			0x8f00 0x0 0x0 0x4 &mpic 0x1 0x1
+
+			/* IDSEL 0x12 func 0 - PCI slot 2 */
+			0x9000 0x0 0x0 0x1 &mpic 0x3 0x1
+			0x9000 0x0 0x0 0x2 &mpic 0x4 0x1
+			0x9000 0x0 0x0 0x3 &mpic 0x1 0x1
+			0x9000 0x0 0x0 0x4 &mpic 0x2 0x1
+
+			/* IDSEL 0x12 func 1 - PCI slot 2 */
+			0x9100 0x0 0x0 0x1 &mpic 0x3 0x1
+			0x9100 0x0 0x0 0x2 &mpic 0x4 0x1
+			0x9100 0x0 0x0 0x3 &mpic 0x1 0x1
+			0x9100 0x0 0x0 0x4 &mpic 0x2 0x1
+
+			/* IDSEL 0x12 func 2 - PCI slot 2 */
+			0x9200 0x0 0x0 0x1 &mpic 0x3 0x1
+			0x9200 0x0 0x0 0x2 &mpic 0x4 0x1
+			0x9200 0x0 0x0 0x3 &mpic 0x1 0x1
+			0x9200 0x0 0x0 0x4 &mpic 0x2 0x1
+
+			/* IDSEL 0x12 func 3 - PCI slot 2 */
+			0x9300 0x0 0x0 0x1 &mpic 0x3 0x1
+			0x9300 0x0 0x0 0x2 &mpic 0x4 0x1
+			0x9300 0x0 0x0 0x3 &mpic 0x1 0x1
+			0x9300 0x0 0x0 0x4 &mpic 0x2 0x1
+
+			/* IDSEL 0x12 func 4 - PCI slot 2 */
+			0x9400 0x0 0x0 0x1 &mpic 0x3 0x1
+			0x9400 0x0 0x0 0x2 &mpic 0x4 0x1
+			0x9400 0x0 0x0 0x3 &mpic 0x1 0x1
+			0x9400 0x0 0x0 0x4 &mpic 0x2 0x1
+
+			/* IDSEL 0x12 func 5 - PCI slot 2 */
+			0x9500 0x0 0x0 0x1 &mpic 0x3 0x1
+			0x9500 0x0 0x0 0x2 &mpic 0x4 0x1
+			0x9500 0x0 0x0 0x3 &mpic 0x1 0x1
+			0x9500 0x0 0x0 0x4 &mpic 0x2 0x1
+
+			/* IDSEL 0x12 func 6 - PCI slot 2 */
+			0x9600 0x0 0x0 0x1 &mpic 0x3 0x1
+			0x9600 0x0 0x0 0x2 &mpic 0x4 0x1
+			0x9600 0x0 0x0 0x3 &mpic 0x1 0x1
+			0x9600 0x0 0x0 0x4 &mpic 0x2 0x1
+
+			/* IDSEL 0x12 func 7 - PCI slot 2 */
+			0x9700 0x0 0x0 0x1 &mpic 0x3 0x1
+			0x9700 0x0 0x0 0x2 &mpic 0x4 0x1
+			0x9700 0x0 0x0 0x3 &mpic 0x1 0x1
+			0x9700 0x0 0x0 0x4 &mpic 0x2 0x1
+
+			// IDSEL 0x1c  USB
+			0xe000 0x0 0x0 0x1 &i8259 0xc 0x2
+			0xe100 0x0 0x0 0x2 &i8259 0x9 0x2
+			0xe200 0x0 0x0 0x3 &i8259 0xa 0x2
+			0xe300 0x0 0x0 0x4 &i8259 0xb 0x2
+
+			// IDSEL 0x1d  Audio
+			0xe800 0x0 0x0 0x1 &i8259 0x6 0x2
+
+			// IDSEL 0x1e Legacy
+			0xf000 0x0 0x0 0x1 &i8259 0x7 0x2
+			0xf100 0x0 0x0 0x1 &i8259 0x7 0x2
+
+			// IDSEL 0x1f IDE/SATA
+			0xf800 0x0 0x0 0x1 &i8259 0xe 0x2
+			0xf900 0x0 0x0 0x1 &i8259 0x5 0x2
+
+			>;
+
+		pcie@0 {
+			reg = <0x0 0x0 0x0 0x0 0x0>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			ranges = <0x2000000 0x0 0x80000000
+				  0x2000000 0x0 0x80000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+			uli1575@0 {
+				reg = <0x0 0x0 0x0 0x0 0x0>;
+				#size-cells = <2>;
+				#address-cells = <3>;
+				ranges = <0x2000000 0x0 0x80000000
+					  0x2000000 0x0 0x80000000
+					  0x0 0x20000000
+
+					  0x1000000 0x0 0x0
+					  0x1000000 0x0 0x0
+					  0x0 0x100000>;
+				isa@1e {
+					device_type = "isa";
+					#interrupt-cells = <2>;
+					#size-cells = <1>;
+					#address-cells = <2>;
+					reg = <0xf000 0x0 0x0 0x0 0x0>;
+					ranges = <0x1 0x0 0x1000000 0x0 0x0
+						  0x1000>;
+					interrupt-parent = <&i8259>;
+
+					i8259: interrupt-controller@20 {
+						reg = <0x1 0x20 0x2
+						       0x1 0xa0 0x2
+						       0x1 0x4d0 0x2>;
+						interrupt-controller;
+						device_type = "interrupt-controller";
+						#address-cells = <0>;
+						#interrupt-cells = <2>;
+						compatible = "chrp,iic";
+						interrupts = <9 2>;
+						interrupt-parent = <&mpic>;
+					};
+
+					i8042@60 {
+						#size-cells = <0>;
+						#address-cells = <1>;
+						reg = <0x1 0x60 0x1 0x1 0x64 0x1>;
+						interrupts = <1 3 12 3>;
+						interrupt-parent =
+							<&i8259>;
+
+						keyboard@0 {
+							reg = <0x0>;
+							compatible = "pnpPNP,303";
+						};
+
+						mouse@1 {
+							reg = <0x1>;
+							compatible = "pnpPNP,f03";
+						};
+					};
+
+					rtc@70 {
+						compatible = "pnpPNP,b00";
+						reg = <0x1 0x70 0x2>;
+					};
+
+					gpio@400 {
+						reg = <0x1 0x400 0x80>;
+					};
+				};
+			};
+		};
+
+	};
+
+	pci1: pcie@ffe09000 {
+		cell-index = <1>;
+		compatible = "fsl,mpc8548-pcie";
+		device_type = "pci";
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = <0xffe09000 0x1000>;
+		bus-range = <0 255>;
+		ranges = <0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x20000000
+			  0x1000000 0x0 0x0 0xffc10000 0x0 0x10000>;
+		clock-frequency = <33333333>;
+		interrupt-parent = <&mpic>;
+		interrupts = <26 2>;
+		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+		interrupt-map = <
+			/* IDSEL 0x0 */
+			0000 0x0 0x0 0x1 &mpic 0x4 0x1
+			0000 0x0 0x0 0x2 &mpic 0x5 0x1
+			0000 0x0 0x0 0x3 &mpic 0x6 0x1
+			0000 0x0 0x0 0x4 &mpic 0x7 0x1
+			>;
+		pcie@0 {
+			reg = <0x0 0x0 0x0 0x0 0x0>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			ranges = <0x2000000 0x0 0xa0000000
+				  0x2000000 0x0 0xa0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts b/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts
new file mode 100644
index 0000000..04ecda1
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts
@@ -0,0 +1,234 @@
+/*
+ * MPC8572 DS Core1 Device Tree Source in CAMP mode.
+ *
+ * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
+ * can be shared, all the other devices must be assigned to one core only.
+ * This dts allows core1 to have l2, dma2, eth2, eth3, pci2, msi.
+ *
+ * Please note to add "-b 1" for core1's dts compiling.
+ *
+ * Copyright 2007, 2008 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+/ {
+	model = "fsl,MPC8572DS";
+	compatible = "fsl,MPC8572DS", "fsl,MPC8572DS-CAMP";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	aliases {
+		ethernet2 = &enet2;
+		ethernet3 = &enet3;
+		serial0 = &serial0;
+		pci2 = &pci2;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,8572@1 {
+			device_type = "cpu";
+			reg = <0x1>;
+			d-cache-line-size = <32>;	// 32 bytes
+			i-cache-line-size = <32>;	// 32 bytes
+			d-cache-size = <0x8000>;		// L1, 32K
+			i-cache-size = <0x8000>;		// L1, 32K
+			timebase-frequency = <0>;
+			bus-frequency = <0>;
+			clock-frequency = <0>;
+			next-level-cache = <&L2>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x0 0x0>;	// Filled by U-Boot
+	};
+
+	soc8572@ffe00000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "soc";
+		compatible = "simple-bus";
+		ranges = <0x0 0xffe00000 0x100000>;
+		reg = <0xffe00000 0x1000>;	// CCSRBAR & soc regs, remove once parse code for immrbase fixed
+		bus-frequency = <0>;		// Filled out by uboot.
+
+		L2: l2-cache-controller@20000 {
+			compatible = "fsl,mpc8572-l2-cache-controller";
+			reg = <0x20000 0x1000>;
+			cache-line-size = <32>; // 32 bytes
+			cache-size = <0x80000>; // L2, 512K
+			interrupt-parent = <&mpic>;
+		};
+
+		dma@c300 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,mpc8572-dma", "fsl,eloplus-dma";
+			reg = <0xc300 0x4>;
+			ranges = <0x0 0xc100 0x200>;
+			cell-index = <0>;
+			dma-channel@0 {
+				compatible = "fsl,mpc8572-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x0 0x80>;
+				cell-index = <0>;
+				interrupt-parent = <&mpic>;
+				interrupts = <76 2>;
+			};
+			dma-channel@80 {
+				compatible = "fsl,mpc8572-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x80 0x80>;
+				cell-index = <1>;
+				interrupt-parent = <&mpic>;
+				interrupts = <77 2>;
+			};
+			dma-channel@100 {
+				compatible = "fsl,mpc8572-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x100 0x80>;
+				cell-index = <2>;
+				interrupt-parent = <&mpic>;
+				interrupts = <78 2>;
+			};
+			dma-channel@180 {
+				compatible = "fsl,mpc8572-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x180 0x80>;
+				cell-index = <3>;
+				interrupt-parent = <&mpic>;
+				interrupts = <79 2>;
+			};
+		};
+
+		mdio@24520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-mdio";
+			reg = <0x24520 0x20>;
+
+			phy2: ethernet-phy@2 {
+				interrupt-parent = <&mpic>;
+				reg = <0x2>;
+			};
+			phy3: ethernet-phy@3 {
+				interrupt-parent = <&mpic>;
+				reg = <0x3>;
+			};
+		};
+
+		enet2: ethernet@26000 {
+			cell-index = <2>;
+			device_type = "network";
+			model = "eTSEC";
+			compatible = "gianfar";
+			reg = <0x26000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <31 2 32 2 33 2>;
+			interrupt-parent = <&mpic>;
+			phy-handle = <&phy2>;
+			phy-connection-type = "rgmii-id";
+		};
+
+		enet3: ethernet@27000 {
+			cell-index = <3>;
+			device_type = "network";
+			model = "eTSEC";
+			compatible = "gianfar";
+			reg = <0x27000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <37 2 38 2 39 2>;
+			interrupt-parent = <&mpic>;
+			phy-handle = <&phy3>;
+			phy-connection-type = "rgmii-id";
+		};
+
+		msi@41600 {
+			compatible = "fsl,mpc8572-msi", "fsl,mpic-msi";
+			reg = <0x41600 0x80>;
+			msi-available-ranges = <0 0x100>;
+			interrupts = <
+				0xe0 0
+				0xe1 0
+				0xe2 0
+				0xe3 0
+				0xe4 0
+				0xe5 0
+				0xe6 0
+				0xe7 0>;
+			interrupt-parent = <&mpic>;
+		};
+
+		serial0: serial@4600 {
+			cell-index = <1>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x4600 0x100>;
+			clock-frequency = <0>;
+		};
+
+		mpic: pic@40000 {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <0x40000 0x40000>;
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+			protected-sources = <
+			18 16 10 42 45 58	/* MEM L2 mdio serial crypto */
+			29 30 34 35 36 40	/* enet0 enet1 */
+			24 26 20 21 22 23	/* pcie0 pcie1 dma1 */
+			43			/* i2c */
+			0x1 0x2 0x3 0x4         /* pci slot */
+			0x9 0xa 0xb 0xc         /* usb */
+			0x6 0x7 0xe 0x5         /* Audio elgacy SATA */
+			>;
+		};
+	};
+
+	pci2: pcie@ffe0a000 {
+		cell-index = <2>;
+		compatible = "fsl,mpc8548-pcie";
+		device_type = "pci";
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = <0xffe0a000 0x1000>;
+		bus-range = <0 255>;
+		ranges = <0x2000000 0x0 0xc0000000 0xc0000000 0x0 0x20000000
+			  0x1000000 0x0 0x0 0xffc20000 0x0 0x10000>;
+		clock-frequency = <33333333>;
+		interrupt-parent = <&mpic>;
+		interrupts = <27 2>;
+		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+		interrupt-map = <
+			/* IDSEL 0x0 */
+			0000 0x0 0x0 0x1 &mpic 0x0 0x1
+			0000 0x0 0x0 0x2 &mpic 0x1 0x1
+			0000 0x0 0x0 0x3 &mpic 0x2 0x1
+			0000 0x0 0x0 0x4 &mpic 0x3 0x1
+			>;
+		pcie@0 {
+			reg = <0x0 0x0 0x0 0x0 0x0>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			ranges = <0x2000000 0x0 0xc0000000
+				  0x2000000 0x0 0xc0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
index d665e76..35d5e24 100644
--- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
+++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
@@ -205,8 +205,49 @@
 				reg = <3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@26520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x26520 0x20>;
+
+			tbi2: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@27520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x27520 0x20>;
+
+			tbi3: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+
 		enet0: ethernet@24000 {
 			cell-index = <0>;
 			device_type = "network";
@@ -216,6 +257,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30  2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 			phy-connection-type = "rgmii-id";
 		};
@@ -229,6 +271,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 			phy-connection-type = "rgmii-id";
 		};
@@ -242,6 +285,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <31 2 32 2 33 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi2>;
 			phy-handle = <&phy2>;
 			phy-connection-type = "rgmii-id";
 		};
@@ -255,6 +299,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <37 2 38 2 39 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi3>;
 			phy-handle = <&phy3>;
 			phy-connection-type = "rgmii-id";
 		};
diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm030.dts
index 7c1bb95..be2c11c 100644
--- a/arch/powerpc/boot/dts/pcm030.dts
+++ b/arch/powerpc/boot/dts/pcm030.dts
@@ -143,7 +143,6 @@
 
 		rtc@800 {	// Real time clock
 			compatible = "fsl,mpc5200b-rtc","fsl,mpc5200-rtc";
-			device_type = "rtc";
 			reg = <0x800 0x100>;
 			interrupts = <0x1 0x5 0x0 0x1 0x6 0x0>;
 			interrupt-parent = <&mpc5200_pic>;
@@ -301,7 +300,6 @@
 			interrupt-parent = <&mpc5200_pic>;
 			fsl5200-clocking;
 			rtc@51 {
-				device_type = "rtc";
 				compatible = "nxp,pcf8563";
 				reg = <0x51>;
 			};
diff --git a/arch/powerpc/boot/dts/sbc8349.dts b/arch/powerpc/boot/dts/sbc8349.dts
index 0f941f3..8d365a5 100644
--- a/arch/powerpc/boot/dts/sbc8349.dts
+++ b/arch/powerpc/boot/dts/sbc8349.dts
@@ -177,6 +177,22 @@
 				reg = <0x1a>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -188,6 +204,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <32 0x8 33 0x8 34 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 			linux,network-index = <0>;
 		};
@@ -201,6 +218,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 0x8 36 0x8 37 0x8>;
 			interrupt-parent = <&ipic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 			linux,network-index = <1>;
 		};
diff --git a/arch/powerpc/boot/dts/sbc8548.dts b/arch/powerpc/boot/dts/sbc8548.dts
index 333552b..2baf4a5 100644
--- a/arch/powerpc/boot/dts/sbc8548.dts
+++ b/arch/powerpc/boot/dts/sbc8548.dts
@@ -252,6 +252,22 @@
 				reg = <0x1a>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -263,6 +279,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 		};
 
@@ -275,6 +292,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
diff --git a/arch/powerpc/boot/dts/sbc8560.dts b/arch/powerpc/boot/dts/sbc8560.dts
index db3632e..01542f7 100644
--- a/arch/powerpc/boot/dts/sbc8560.dts
+++ b/arch/powerpc/boot/dts/sbc8560.dts
@@ -168,6 +168,22 @@
 				reg = <0x1c>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -179,6 +195,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 		};
 
@@ -191,6 +208,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
diff --git a/arch/powerpc/boot/dts/sbc8641d.dts b/arch/powerpc/boot/dts/sbc8641d.dts
index 9652456..36db981 100644
--- a/arch/powerpc/boot/dts/sbc8641d.dts
+++ b/arch/powerpc/boot/dts/sbc8641d.dts
@@ -222,6 +222,46 @@
 				reg = <2>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@26520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x26520 0x20>;
+
+			tbi2: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@27520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x27520 0x20>;
+
+			tbi3: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -233,6 +273,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30  2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy0>;
 			phy-connection-type = "rgmii-id";
 		};
@@ -246,6 +287,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 			phy-connection-type = "rgmii-id";
 		};
@@ -259,6 +301,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <31 2 32 2 33 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi2>;
 			phy-handle = <&phy2>;
 			phy-connection-type = "rgmii-id";
 		};
@@ -272,6 +315,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <37 2 38 2 39 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi3>;
 			phy-handle = <&phy3>;
 			phy-connection-type = "rgmii-id";
 		};
diff --git a/arch/powerpc/boot/dts/stx_gp3_8560.dts b/arch/powerpc/boot/dts/stx_gp3_8560.dts
index fcd1db6..fff33fe 100644
--- a/arch/powerpc/boot/dts/stx_gp3_8560.dts
+++ b/arch/powerpc/boot/dts/stx_gp3_8560.dts
@@ -142,6 +142,22 @@
 				reg = <4>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -153,6 +169,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -165,6 +182,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy4>;
 		};
 
diff --git a/arch/powerpc/boot/dts/tqm5200.dts b/arch/powerpc/boot/dts/tqm5200.dts
index 3008bf8..906302e 100644
--- a/arch/powerpc/boot/dts/tqm5200.dts
+++ b/arch/powerpc/boot/dts/tqm5200.dts
@@ -181,7 +181,6 @@
 			fsl5200-clocking;
 
 			 rtc@68 {
-				device_type = "rtc";
 				compatible = "dallas,ds1307";
 				reg = <0x68>;
 			};
diff --git a/arch/powerpc/boot/dts/tqm8540.dts b/arch/powerpc/boot/dts/tqm8540.dts
index e1d260b..a693f01 100644
--- a/arch/powerpc/boot/dts/tqm8540.dts
+++ b/arch/powerpc/boot/dts/tqm8540.dts
@@ -155,6 +155,34 @@
 				reg = <3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@26520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x26520 0x20>;
+
+			tbi2: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
diff --git a/arch/powerpc/boot/dts/tqm8541.dts b/arch/powerpc/boot/dts/tqm8541.dts
index d76441e..9e3f5f0d 100644
--- a/arch/powerpc/boot/dts/tqm8541.dts
+++ b/arch/powerpc/boot/dts/tqm8541.dts
@@ -154,6 +154,22 @@
 				reg = <3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -165,6 +181,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -177,6 +194,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
diff --git a/arch/powerpc/boot/dts/tqm8548-bigflash.dts b/arch/powerpc/boot/dts/tqm8548-bigflash.dts
index 4199e89..15086eb 100644
--- a/arch/powerpc/boot/dts/tqm8548-bigflash.dts
+++ b/arch/powerpc/boot/dts/tqm8548-bigflash.dts
@@ -179,6 +179,46 @@
 				reg = <5>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@26520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x26520 0x20>;
+
+			tbi2: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@27520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x27520 0x20>;
+
+			tbi3: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -190,6 +230,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -202,6 +243,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
@@ -214,6 +256,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <31 2 32 2 33 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi2>;
 			phy-handle = <&phy3>;
 		};
 
@@ -226,6 +269,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <37 2 38 2 39 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi3>;
 			phy-handle = <&phy4>;
 		};
 
diff --git a/arch/powerpc/boot/dts/tqm8548.dts b/arch/powerpc/boot/dts/tqm8548.dts
index 58ee418..b7b65f5 100644
--- a/arch/powerpc/boot/dts/tqm8548.dts
+++ b/arch/powerpc/boot/dts/tqm8548.dts
@@ -179,6 +179,46 @@
 				reg = <5>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@26520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x26520 0x20>;
+
+			tbi2: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@27520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x27520 0x20>;
+
+			tbi3: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -190,6 +230,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -202,6 +243,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
@@ -214,6 +256,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <31 2 32 2 33 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi2>;
 			phy-handle = <&phy3>;
 		};
 
@@ -226,6 +269,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <37 2 38 2 39 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi3>;
 			phy-handle = <&phy4>;
 		};
 
diff --git a/arch/powerpc/boot/dts/tqm8555.dts b/arch/powerpc/boot/dts/tqm8555.dts
index 6f7ea59..cf92b4e 100644
--- a/arch/powerpc/boot/dts/tqm8555.dts
+++ b/arch/powerpc/boot/dts/tqm8555.dts
@@ -154,6 +154,22 @@
 				reg = <3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -165,6 +181,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -177,6 +194,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
diff --git a/arch/powerpc/boot/dts/tqm8560.dts b/arch/powerpc/boot/dts/tqm8560.dts
index 3fe3520..9e1ab2d 100644
--- a/arch/powerpc/boot/dts/tqm8560.dts
+++ b/arch/powerpc/boot/dts/tqm8560.dts
@@ -156,6 +156,22 @@
 				reg = <3>;
 				device_type = "ethernet-phy";
 			};
+			tbi0: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
+		};
+
+		mdio@25520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-tbi";
+			reg = <0x25520 0x20>;
+
+			tbi1: tbi-phy@11 {
+				reg = <0x11>;
+				device_type = "tbi-phy";
+			};
 		};
 
 		enet0: ethernet@24000 {
@@ -167,6 +183,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <29 2 30 2 34 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi0>;
 			phy-handle = <&phy2>;
 		};
 
@@ -179,6 +196,7 @@
 			local-mac-address = [ 00 00 00 00 00 00 ];
 			interrupts = <35 2 36 2 40 2>;
 			interrupt-parent = <&mpic>;
+			tbi-handle = <&tbi1>;
 			phy-handle = <&phy1>;
 		};
 
diff --git a/arch/powerpc/boot/libfdt-wrapper.c b/arch/powerpc/boot/libfdt-wrapper.c
index 9276327..bb8b9b3 100644
--- a/arch/powerpc/boot/libfdt-wrapper.c
+++ b/arch/powerpc/boot/libfdt-wrapper.c
@@ -185,7 +185,7 @@
 
 	/* Make sure the dt blob is the right version and so forth */
 	fdt = blob;
-	bufsize = fdt_totalsize(fdt) + 4;
+	bufsize = fdt_totalsize(fdt) + EXPAND_GRANULARITY;
 	buf = malloc(bufsize);
 	if(!buf)
 		fatal("malloc failed. can't relocate the device tree\n\r");
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
index 07ccaf8..cd1ffa4 100644
--- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
@@ -1397,8 +1397,11 @@
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_INFINIBAND is not set
 # CONFIG_EDAC is not set
-CONFIG_RTC_LIB=m
-CONFIG_RTC_CLASS=m
+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
@@ -1424,6 +1427,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=y
 
 #
 # SPI RTC drivers
diff --git a/arch/powerpc/configs/ppc44x_defconfig b/arch/powerpc/configs/ppc44x_defconfig
index cfc94cf..034a1fb 100644
--- a/arch/powerpc/configs/ppc44x_defconfig
+++ b/arch/powerpc/configs/ppc44x_defconfig
@@ -267,7 +267,7 @@
 # CONFIG_PCIEPORTBUS is not set
 CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
-CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_LEGACY is not set
 # CONFIG_PCI_DEBUG is not set
 # CONFIG_PCCARD is not set
 # CONFIG_HOTPLUG_PCI is not set
@@ -354,7 +354,7 @@
 # CONFIG_IP_SCTP is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
+CONFIG_BRIDGE=m
 # CONFIG_NET_DSA is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_DECNET is not set
@@ -579,7 +579,7 @@
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
+CONFIG_TUN=m
 # CONFIG_VETH is not set
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
@@ -1001,11 +1001,11 @@
 # 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 also be needed;
 #
 
 #
-# may also be needed; see USB_STORAGE Help for more information
+# see USB_STORAGE Help for more information
 #
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -1418,6 +1418,6 @@
 # CONFIG_PPC_CLOCK is not set
 CONFIG_VIRTUALIZATION=y
 CONFIG_KVM=y
-CONFIG_KVM_BOOKE_HOST=y
+CONFIG_KVM_440=y
 # CONFIG_VIRTIO_PCI is not set
 # CONFIG_VIRTIO_BALLOON is not set
diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h
index f3fc733..499be5b 100644
--- a/arch/powerpc/include/asm/atomic.h
+++ b/arch/powerpc/include/asm/atomic.h
@@ -111,7 +111,7 @@
 	bne-	1b"
 	: "=&r" (t), "+m" (v->counter)
 	: "r" (&v->counter)
-	: "cc");
+	: "cc", "xer");
 }
 
 static __inline__ int atomic_inc_return(atomic_t *v)
@@ -128,7 +128,7 @@
 	ISYNC_ON_SMP
 	: "=&r" (t)
 	: "r" (&v->counter)
-	: "cc", "memory");
+	: "cc", "xer", "memory");
 
 	return t;
 }
@@ -155,7 +155,7 @@
 	bne-	1b"
 	: "=&r" (t), "+m" (v->counter)
 	: "r" (&v->counter)
-	: "cc");
+	: "cc", "xer");
 }
 
 static __inline__ int atomic_dec_return(atomic_t *v)
@@ -172,7 +172,7 @@
 	ISYNC_ON_SMP
 	: "=&r" (t)
 	: "r" (&v->counter)
-	: "cc", "memory");
+	: "cc", "xer", "memory");
 
 	return t;
 }
@@ -346,7 +346,7 @@
 	bne-	1b"
 	: "=&r" (t), "+m" (v->counter)
 	: "r" (&v->counter)
-	: "cc");
+	: "cc", "xer");
 }
 
 static __inline__ long atomic64_inc_return(atomic64_t *v)
@@ -362,7 +362,7 @@
 	ISYNC_ON_SMP
 	: "=&r" (t)
 	: "r" (&v->counter)
-	: "cc", "memory");
+	: "cc", "xer", "memory");
 
 	return t;
 }
@@ -388,7 +388,7 @@
 	bne-	1b"
 	: "=&r" (t), "+m" (v->counter)
 	: "r" (&v->counter)
-	: "cc");
+	: "cc", "xer");
 }
 
 static __inline__ long atomic64_dec_return(atomic64_t *v)
@@ -404,7 +404,7 @@
 	ISYNC_ON_SMP
 	: "=&r" (t)
 	: "r" (&v->counter)
-	: "cc", "memory");
+	: "cc", "xer", "memory");
 
 	return t;
 }
@@ -431,7 +431,7 @@
 	"\n\
 2:"	: "=&r" (t)
 	: "r" (&v->counter)
-	: "cc", "memory");
+	: "cc", "xer", "memory");
 
 	return t;
 }
diff --git a/arch/powerpc/include/asm/bug.h b/arch/powerpc/include/asm/bug.h
index e55d1f6..64e1fdc 100644
--- a/arch/powerpc/include/asm/bug.h
+++ b/arch/powerpc/include/asm/bug.h
@@ -3,6 +3,7 @@
 #ifdef __KERNEL__
 
 #include <asm/asm-compat.h>
+
 /*
  * Define an illegal instr to trap on the bug.
  * We don't use 0 because that marks the end of a function
@@ -14,6 +15,7 @@
 #ifdef CONFIG_BUG
 
 #ifdef __ASSEMBLY__
+#include <asm/asm-offsets.h>
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 .macro EMIT_BUG_ENTRY addr,file,line,flags
 	 .section __bug_table,"a"
@@ -26,7 +28,7 @@
 	 .previous
 .endm
 #else
- .macro EMIT_BUG_ENTRY addr,file,line,flags
+.macro EMIT_BUG_ENTRY addr,file,line,flags
 	 .section __bug_table,"a"
 5001:	 PPC_LONG \addr
 	 .short \flags
@@ -113,6 +115,13 @@
 #define HAVE_ARCH_BUG_ON
 #define HAVE_ARCH_WARN_ON
 #endif /* __ASSEMBLY __ */
+#else
+#ifdef __ASSEMBLY__
+.macro EMIT_BUG_ENTRY addr,file,line,flags
+.endm
+#else /* !__ASSEMBLY__ */
+#define _EMIT_BUG_ENTRY
+#endif
 #endif /* CONFIG_BUG */
 
 #include <asm-generic/bug.h>
diff --git a/arch/powerpc/include/asm/byteorder.h b/arch/powerpc/include/asm/byteorder.h
index b377522..d5de325 100644
--- a/arch/powerpc/include/asm/byteorder.h
+++ b/arch/powerpc/include/asm/byteorder.h
@@ -11,6 +11,8 @@
 #include <asm/types.h>
 #include <linux/compiler.h>
 
+#define __BIG_ENDIAN
+
 #ifdef __GNUC__
 #ifdef __KERNEL__
 
@@ -21,12 +23,19 @@
 	__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr));
 	return val;
 }
+#define __arch_swab16p ld_le16
 
 static __inline__ void st_le16(volatile __u16 *addr, const __u16 val)
 {
 	__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
 }
 
+static inline void __arch_swab16s(__u16 *addr)
+{
+	st_le16(addr, *addr);
+}
+#define __arch_swab16s __arch_swab16s
+
 static __inline__ __u32 ld_le32(const volatile __u32 *addr)
 {
 	__u32 val;
@@ -34,13 +43,20 @@
 	__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr));
 	return val;
 }
+#define __arch_swab32p ld_le32
 
 static __inline__ void st_le32(volatile __u32 *addr, const __u32 val)
 {
 	__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
 }
 
-static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 value)
+static inline void __arch_swab32s(__u32 *addr)
+{
+	st_le32(addr, *addr);
+}
+#define __arch_swab32s __arch_swab32s
+
+static inline __attribute_const__ __u16 __arch_swab16(__u16 value)
 {
 	__u16 result;
 
@@ -49,8 +65,9 @@
 	    : "r" (value), "0" (value >> 8));
 	return result;
 }
+#define __arch_swab16 __arch_swab16
 
-static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 value)
+static inline __attribute_const__ __u32 __arch_swab32(__u32 value)
 {
 	__u32 result;
 
@@ -61,29 +78,16 @@
 	    : "r" (value), "0" (value >> 24));
 	return result;
 }
-
-#define __arch__swab16(x) ___arch__swab16(x)
-#define __arch__swab32(x) ___arch__swab32(x)
-
-/* The same, but returns converted value from the location pointer by addr. */
-#define __arch__swab16p(addr) ld_le16(addr)
-#define __arch__swab32p(addr) ld_le32(addr)
-
-/* The same, but do the conversion in situ, ie. put the value back to addr. */
-#define __arch__swab16s(addr) st_le16(addr,*addr)
-#define __arch__swab32s(addr) st_le32(addr,*addr)
+#define __arch_swab32 __arch_swab32
 
 #endif /* __KERNEL__ */
 
-#ifndef __STRICT_ANSI__
-#define __BYTEORDER_HAS_U64__
 #ifndef __powerpc64__
 #define __SWAB_64_THRU_32__
 #endif /* __powerpc64__ */
-#endif /* __STRICT_ANSI__ */
 
 #endif /* __GNUC__ */
 
-#include <linux/byteorder/big_endian.h>
+#include <linux/byteorder.h>
 
 #endif /* _ASM_POWERPC_BYTEORDER_H */
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 1e94b07..4911104 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -82,6 +82,7 @@
 	char		*cpu_name;
 	unsigned long	cpu_features;		/* Kernel features */
 	unsigned int	cpu_user_features;	/* Userland features */
+	unsigned int	mmu_features;		/* MMU features */
 
 	/* cache line sizes */
 	unsigned int	icache_bsize;
@@ -144,17 +145,14 @@
 #define CPU_FTR_USE_TB			ASM_CONST(0x0000000000000040)
 #define CPU_FTR_L2CSR			ASM_CONST(0x0000000000000080)
 #define CPU_FTR_601			ASM_CONST(0x0000000000000100)
-#define CPU_FTR_HPTE_TABLE		ASM_CONST(0x0000000000000200)
 #define CPU_FTR_CAN_NAP			ASM_CONST(0x0000000000000400)
 #define CPU_FTR_L3CR			ASM_CONST(0x0000000000000800)
 #define CPU_FTR_L3_DISABLE_NAP		ASM_CONST(0x0000000000001000)
 #define CPU_FTR_NAP_DISABLE_L2_PR	ASM_CONST(0x0000000000002000)
 #define CPU_FTR_DUAL_PLL_750FX		ASM_CONST(0x0000000000004000)
 #define CPU_FTR_NO_DPM			ASM_CONST(0x0000000000008000)
-#define CPU_FTR_HAS_HIGH_BATS		ASM_CONST(0x0000000000010000)
 #define CPU_FTR_NEED_COHERENT		ASM_CONST(0x0000000000020000)
 #define CPU_FTR_NO_BTIC			ASM_CONST(0x0000000000040000)
-#define CPU_FTR_BIG_PHYS		ASM_CONST(0x0000000000080000)
 #define CPU_FTR_NODSISRALIGN		ASM_CONST(0x0000000000100000)
 #define CPU_FTR_PPC_LE			ASM_CONST(0x0000000000200000)
 #define CPU_FTR_REAL_LE			ASM_CONST(0x0000000000400000)
@@ -163,6 +161,8 @@
 #define CPU_FTR_SPE			ASM_CONST(0x0000000002000000)
 #define CPU_FTR_NEED_PAIRED_STWCX	ASM_CONST(0x0000000004000000)
 #define CPU_FTR_LWSYNC			ASM_CONST(0x0000000008000000)
+#define CPU_FTR_NOEXECUTE		ASM_CONST(0x0000000010000000)
+#define CPU_FTR_INDEXED_DCR		ASM_CONST(0x0000000020000000)
 
 /*
  * Add the 64-bit processor unique features in the top half of the word;
@@ -177,7 +177,6 @@
 #define CPU_FTR_SLB			LONG_ASM_CONST(0x0000000100000000)
 #define CPU_FTR_16M_PAGE		LONG_ASM_CONST(0x0000000200000000)
 #define CPU_FTR_TLBIEL			LONG_ASM_CONST(0x0000000400000000)
-#define CPU_FTR_NOEXECUTE		LONG_ASM_CONST(0x0000000800000000)
 #define CPU_FTR_IABR			LONG_ASM_CONST(0x0000002000000000)
 #define CPU_FTR_MMCRA			LONG_ASM_CONST(0x0000004000000000)
 #define CPU_FTR_CTRL			LONG_ASM_CONST(0x0000008000000000)
@@ -194,6 +193,7 @@
 #define CPU_FTR_VSX			LONG_ASM_CONST(0x0010000000000000)
 #define CPU_FTR_SAO			LONG_ASM_CONST(0x0020000000000000)
 #define CPU_FTR_CP_USE_DCBTZ		LONG_ASM_CONST(0x0040000000000000)
+#define CPU_FTR_UNALIGNED_LD_STD	LONG_ASM_CONST(0x0080000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -264,164 +264,159 @@
 		     !defined(CONFIG_POWER3) && !defined(CONFIG_POWER4) && \
 		     !defined(CONFIG_BOOKE))
 
-#define CPU_FTRS_PPC601	(CPU_FTR_COMMON | CPU_FTR_601 | CPU_FTR_HPTE_TABLE | \
+#define CPU_FTRS_PPC601	(CPU_FTR_COMMON | CPU_FTR_601 | \
 	CPU_FTR_COHERENT_ICACHE | CPU_FTR_UNIFIED_ID_CACHE)
 #define CPU_FTRS_603	(CPU_FTR_COMMON | \
 	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
 	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
 #define CPU_FTRS_604	(CPU_FTR_COMMON | \
-	    CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_PPC_LE)
+	    CPU_FTR_USE_TB | CPU_FTR_PPC_LE)
 #define CPU_FTRS_740_NOTAU	(CPU_FTR_COMMON | \
 	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
+	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
 #define CPU_FTRS_740	(CPU_FTR_COMMON | \
 	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
-	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+	    CPU_FTR_TAU | CPU_FTR_MAYBE_CAN_NAP | \
 	    CPU_FTR_PPC_LE)
 #define CPU_FTRS_750	(CPU_FTR_COMMON | \
 	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
-	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+	    CPU_FTR_TAU | CPU_FTR_MAYBE_CAN_NAP | \
 	    CPU_FTR_PPC_LE)
-#define CPU_FTRS_750CL	(CPU_FTRS_750 | CPU_FTR_HAS_HIGH_BATS)
+#define CPU_FTRS_750CL	(CPU_FTRS_750)
 #define CPU_FTRS_750FX1	(CPU_FTRS_750 | CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM)
 #define CPU_FTRS_750FX2	(CPU_FTRS_750 | CPU_FTR_NO_DPM)
-#define CPU_FTRS_750FX	(CPU_FTRS_750 | CPU_FTR_DUAL_PLL_750FX | \
-		CPU_FTR_HAS_HIGH_BATS)
+#define CPU_FTRS_750FX	(CPU_FTRS_750 | CPU_FTR_DUAL_PLL_750FX)
 #define CPU_FTRS_750GX	(CPU_FTRS_750FX)
 #define CPU_FTRS_7400_NOTAU	(CPU_FTR_COMMON | \
 	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
-	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \
+	    CPU_FTR_ALTIVEC_COMP | \
 	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
 #define CPU_FTRS_7400	(CPU_FTR_COMMON | \
 	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
-	    CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \
+	    CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | \
 	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
 #define CPU_FTRS_7450_20	(CPU_FTR_COMMON | \
 	    CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_L3CR | CPU_FTR_SPEC7450 | \
 	    CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX)
 #define CPU_FTRS_7450_21	(CPU_FTR_COMMON | \
 	    CPU_FTR_USE_TB | \
 	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_L3CR | CPU_FTR_SPEC7450 | \
 	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \
 	    CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX)
 #define CPU_FTRS_7450_23	(CPU_FTR_COMMON | \
 	    CPU_FTR_USE_TB | CPU_FTR_NEED_PAIRED_STWCX | \
 	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_L3CR | CPU_FTR_SPEC7450 | \
 	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
 #define CPU_FTRS_7455_1	(CPU_FTR_COMMON | \
 	    CPU_FTR_USE_TB | CPU_FTR_NEED_PAIRED_STWCX | \
 	    CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_HAS_HIGH_BATS | \
-	    CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
+	    CPU_FTR_SPEC7450 | CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
 #define CPU_FTRS_7455_20	(CPU_FTR_COMMON | \
 	    CPU_FTR_USE_TB | CPU_FTR_NEED_PAIRED_STWCX | \
 	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
+	    CPU_FTR_L3CR | CPU_FTR_SPEC7450 | \
 	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \
-	    CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
+	    CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
 #define CPU_FTRS_7455	(CPU_FTR_COMMON | \
 	    CPU_FTR_USE_TB | \
 	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_L3CR | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | \
 	    CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX)
 #define CPU_FTRS_7447_10	(CPU_FTR_COMMON | \
 	    CPU_FTR_USE_TB | \
 	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_L3CR | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | \
 	    CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC | CPU_FTR_PPC_LE | \
 	    CPU_FTR_NEED_PAIRED_STWCX)
 #define CPU_FTRS_7447	(CPU_FTR_COMMON | \
 	    CPU_FTR_USE_TB | \
 	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
-	    CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_L3CR | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | \
 	    CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX)
 #define CPU_FTRS_7447A	(CPU_FTR_COMMON | \
 	    CPU_FTR_USE_TB | \
 	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | \
 	    CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX)
 #define CPU_FTRS_7448	(CPU_FTR_COMMON | \
 	    CPU_FTR_USE_TB | \
 	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
-	    CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR | \
 	    CPU_FTR_PPC_LE | CPU_FTR_NEED_PAIRED_STWCX)
 #define CPU_FTRS_82XX	(CPU_FTR_COMMON | \
 	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB)
 #define CPU_FTRS_G2_LE	(CPU_FTR_COMMON | CPU_FTR_MAYBE_CAN_DOZE | \
-	    CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS)
+	    CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP)
 #define CPU_FTRS_E300	(CPU_FTR_MAYBE_CAN_DOZE | \
-	    CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | \
 	    CPU_FTR_COMMON)
 #define CPU_FTRS_E300C2	(CPU_FTR_MAYBE_CAN_DOZE | \
-	    CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
+	    CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | \
 	    CPU_FTR_COMMON | CPU_FTR_FPU_UNAVAILABLE)
-#define CPU_FTRS_CLASSIC32	(CPU_FTR_COMMON | \
-	    CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE)
+#define CPU_FTRS_CLASSIC32	(CPU_FTR_COMMON | CPU_FTR_USE_TB)
 #define CPU_FTRS_8XX	(CPU_FTR_USE_TB)
-#define CPU_FTRS_40X	(CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN)
-#define CPU_FTRS_44X	(CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN)
+#define CPU_FTRS_40X	(CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
+#define CPU_FTRS_44X	(CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
+#define CPU_FTRS_440x6	(CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE | \
+	    CPU_FTR_INDEXED_DCR)
 #define CPU_FTRS_E200	(CPU_FTR_USE_TB | CPU_FTR_SPE_COMP | \
 	    CPU_FTR_NODSISRALIGN | CPU_FTR_COHERENT_ICACHE | \
-	    CPU_FTR_UNIFIED_ID_CACHE)
+	    CPU_FTR_UNIFIED_ID_CACHE | CPU_FTR_NOEXECUTE)
 #define CPU_FTRS_E500	(CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
-	    CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN)
+	    CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN | \
+	    CPU_FTR_NOEXECUTE)
 #define CPU_FTRS_E500_2	(CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
-	    CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_BIG_PHYS | \
-	    CPU_FTR_NODSISRALIGN)
+	    CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | \
+	    CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
 #define CPU_FTRS_E500MC	(CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
-	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_BIG_PHYS | CPU_FTR_NODSISRALIGN | \
-	    CPU_FTR_L2CSR | CPU_FTR_LWSYNC)
+	    CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN | \
+	    CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE)
 #define CPU_FTRS_GENERIC_32	(CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
 
 /* 64-bit CPUs */
 #define CPU_FTRS_POWER3	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | CPU_FTR_PPC_LE)
+	    CPU_FTR_IABR | CPU_FTR_PPC_LE)
 #define CPU_FTRS_RS64	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | \
+	    CPU_FTR_IABR | \
 	    CPU_FTR_MMCRA | CPU_FTR_CTRL)
 #define CPU_FTRS_POWER4	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
+	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_MMCRA | CPU_FTR_CP_USE_DCBTZ)
 #define CPU_FTRS_PPC970	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
+	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA | \
 	    CPU_FTR_CP_USE_DCBTZ)
 #define CPU_FTRS_POWER5	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
+	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
 	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
 	    CPU_FTR_PURR)
 #define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
+	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
 	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
 	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
-	    CPU_FTR_DSCR)
+	    CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD)
 #define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
+	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
 	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
 	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
 	    CPU_FTR_DSCR | CPU_FTR_SAO)
 #define CPU_FTRS_CELL	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
+	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
 	    CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | \
-	    CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ)
+	    CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ | \
+	    CPU_FTR_UNALIGNED_LD_STD)
 #define CPU_FTRS_PA6T (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
+	    CPU_FTR_PPCAS_ARCH_V2 | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
 	    CPU_FTR_PURR | CPU_FTR_REAL_LE | CPU_FTR_NO_SLBIE_B)
-#define CPU_FTRS_COMPATIBLE	(CPU_FTR_USE_TB | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2)
+#define CPU_FTRS_COMPATIBLE	(CPU_FTR_USE_TB | CPU_FTR_PPCAS_ARCH_V2)
 
 #ifdef __powerpc64__
 #define CPU_FTRS_POSSIBLE	\
@@ -452,7 +447,7 @@
 	    CPU_FTRS_40X |
 #endif
 #ifdef CONFIG_44x
-	    CPU_FTRS_44X |
+	    CPU_FTRS_44X | CPU_FTRS_440x6 |
 #endif
 #ifdef CONFIG_E200
 	    CPU_FTRS_E200 |
@@ -492,7 +487,7 @@
 	    CPU_FTRS_40X &
 #endif
 #ifdef CONFIG_44x
-	    CPU_FTRS_44X &
+	    CPU_FTRS_44X & CPU_FTRS_440x6 &
 #endif
 #ifdef CONFIG_E200
 	    CPU_FTRS_E200 &
diff --git a/arch/powerpc/include/asm/dcr-native.h b/arch/powerpc/include/asm/dcr-native.h
index 72d2b72..7d2e623 100644
--- a/arch/powerpc/include/asm/dcr-native.h
+++ b/arch/powerpc/include/asm/dcr-native.h
@@ -23,6 +23,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/spinlock.h>
+#include <asm/cputable.h>
 
 typedef struct {
 	unsigned int base;
@@ -39,23 +40,45 @@
 #define dcr_read_native(host, dcr_n)		mfdcr(dcr_n + host.base)
 #define dcr_write_native(host, dcr_n, value)	mtdcr(dcr_n + host.base, value)
 
-/* Device Control Registers */
-void __mtdcr(int reg, unsigned int val);
-unsigned int __mfdcr(int reg);
+/* Table based DCR accessors */
+extern void __mtdcr(unsigned int reg, unsigned int val);
+extern unsigned int __mfdcr(unsigned int reg);
+
+/* mfdcrx/mtdcrx instruction based accessors. We hand code
+ * the opcodes in order not to depend on newer binutils
+ */
+static inline unsigned int mfdcrx(unsigned int reg)
+{
+	unsigned int ret;
+	asm volatile(".long 0x7c000206 | (%0 << 21) | (%1 << 16)"
+		     : "=r" (ret) : "r" (reg));
+	return ret;
+}
+
+static inline void mtdcrx(unsigned int reg, unsigned int val)
+{
+	asm volatile(".long 0x7c000306 | (%0 << 21) | (%1 << 16)"
+		     : : "r" (val), "r" (reg));
+}
+
 #define mfdcr(rn)						\
 	({unsigned int rval;					\
-	if (__builtin_constant_p(rn))				\
+	if (__builtin_constant_p(rn) && rn < 1024)		\
 		asm volatile("mfdcr %0," __stringify(rn)	\
 		              : "=r" (rval));			\
+	else if (likely(cpu_has_feature(CPU_FTR_INDEXED_DCR)))	\
+		rval = mfdcrx(rn);				\
 	else							\
 		rval = __mfdcr(rn);				\
 	rval;})
 
 #define mtdcr(rn, v)						\
 do {								\
-	if (__builtin_constant_p(rn))				\
+	if (__builtin_constant_p(rn) && rn < 1024)		\
 		asm volatile("mtdcr " __stringify(rn) ",%0"	\
 			      : : "r" (v)); 			\
+	else if (likely(cpu_has_feature(CPU_FTR_INDEXED_DCR)))	\
+		mtdcrx(rn, v);					\
 	else							\
 		__mtdcr(rn, v);					\
 } while (0)
@@ -69,8 +92,13 @@
 	unsigned int val;
 
 	spin_lock_irqsave(&dcr_ind_lock, flags);
-	__mtdcr(base_addr, reg);
-	val = __mfdcr(base_data);
+	if (cpu_has_feature(CPU_FTR_INDEXED_DCR)) {
+		mtdcrx(base_addr, reg);
+		val = mfdcrx(base_data);
+	} else {
+		__mtdcr(base_addr, reg);
+		val = __mfdcr(base_data);
+	}
 	spin_unlock_irqrestore(&dcr_ind_lock, flags);
 	return val;
 }
@@ -81,8 +109,13 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&dcr_ind_lock, flags);
-	__mtdcr(base_addr, reg);
-	__mtdcr(base_data, val);
+	if (cpu_has_feature(CPU_FTR_INDEXED_DCR)) {
+		mtdcrx(base_addr, reg);
+		mtdcrx(base_data, val);
+	} else {
+		__mtdcr(base_addr, reg);
+		__mtdcr(base_data, val);
+	}
 	spin_unlock_irqrestore(&dcr_ind_lock, flags);
 }
 
@@ -93,9 +126,15 @@
 	unsigned int val;
 
 	spin_lock_irqsave(&dcr_ind_lock, flags);
-	__mtdcr(base_addr, reg);
-	val = (__mfdcr(base_data) & ~clr) | set;
-	__mtdcr(base_data, val);
+	if (cpu_has_feature(CPU_FTR_INDEXED_DCR)) {
+		mtdcrx(base_addr, reg);
+		val = (mfdcrx(base_data) & ~clr) | set;
+		mtdcrx(base_data, val);
+	} else {
+		__mtdcr(base_addr, reg);
+		val = (__mfdcr(base_data) & ~clr) | set;
+		__mtdcr(base_data, val);
+	}
 	spin_unlock_irqrestore(&dcr_ind_lock, flags);
 }
 
diff --git a/arch/powerpc/include/asm/dcr.h b/arch/powerpc/include/asm/dcr.h
index d13fb68..9d6851c 100644
--- a/arch/powerpc/include/asm/dcr.h
+++ b/arch/powerpc/include/asm/dcr.h
@@ -68,9 +68,9 @@
  * additional helpers to read the DCR * base from the device-tree
  */
 struct device_node;
-extern unsigned int dcr_resource_start(struct device_node *np,
+extern unsigned int dcr_resource_start(const struct device_node *np,
 				       unsigned int index);
-extern unsigned int dcr_resource_len(struct device_node *np,
+extern unsigned int dcr_resource_len(const struct device_node *np,
 				     unsigned int index);
 #endif /* CONFIG_PPC_DCR */
 #endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h
index dfd504c..7d2277c 100644
--- a/arch/powerpc/include/asm/device.h
+++ b/arch/powerpc/include/asm/device.h
@@ -18,4 +18,16 @@
 	void			*dma_data;
 };
 
+static inline void dev_archdata_set_node(struct dev_archdata *ad,
+					 struct device_node *np)
+{
+	ad->of_node = np;
+}
+
+static inline struct device_node *
+dev_archdata_get_node(const struct dev_archdata *ad)
+{
+	return ad->of_node;
+}
+
 #endif /* _ASM_POWERPC_DEVICE_H */
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index fddb229..86cef7d 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -60,12 +60,6 @@
 				dma_addr_t *dma_handle, gfp_t flag);
 	void		(*free_coherent)(struct device *dev, size_t size,
 				void *vaddr, dma_addr_t dma_handle);
-	dma_addr_t	(*map_single)(struct device *dev, void *ptr,
-				size_t size, enum dma_data_direction direction,
-				struct dma_attrs *attrs);
-	void		(*unmap_single)(struct device *dev, dma_addr_t dma_addr,
-				size_t size, enum dma_data_direction direction,
-				struct dma_attrs *attrs);
 	int		(*map_sg)(struct device *dev, struct scatterlist *sg,
 				int nents, enum dma_data_direction direction,
 				struct dma_attrs *attrs);
@@ -82,6 +76,22 @@
 				dma_addr_t dma_address, size_t size,
 				enum dma_data_direction direction,
 				struct dma_attrs *attrs);
+#ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS
+	void            (*sync_single_range_for_cpu)(struct device *hwdev,
+				dma_addr_t dma_handle, unsigned long offset,
+				size_t size,
+				enum dma_data_direction direction);
+	void            (*sync_single_range_for_device)(struct device *hwdev,
+				dma_addr_t dma_handle, unsigned long offset,
+				size_t size,
+				enum dma_data_direction direction);
+	void            (*sync_sg_for_cpu)(struct device *hwdev,
+				struct scatterlist *sg, int nelems,
+				enum dma_data_direction direction);
+	void            (*sync_sg_for_device)(struct device *hwdev,
+				struct scatterlist *sg, int nelems,
+				enum dma_data_direction direction);
+#endif
 };
 
 /*
@@ -149,10 +159,9 @@
 }
 
 /*
- * TODO: map_/unmap_single will ideally go away, to be completely
- * replaced by map/unmap_page.   Until then, we allow dma_ops to have
- * one or the other, or both by checking to see if the specific
- * function requested exists; and if not, falling back on the other set.
+ * map_/unmap_single actually call through to map/unmap_page now that all the
+ * dma_mapping_ops have been converted over. We just have to get the page and
+ * offset to pass through to map_page
  */
 static inline dma_addr_t dma_map_single_attrs(struct device *dev,
 					      void *cpu_addr,
@@ -164,10 +173,6 @@
 
 	BUG_ON(!dma_ops);
 
-	if (dma_ops->map_single)
-		return dma_ops->map_single(dev, cpu_addr, size, direction,
-					   attrs);
-
 	return dma_ops->map_page(dev, virt_to_page(cpu_addr),
 				 (unsigned long)cpu_addr % PAGE_SIZE, size,
 				 direction, attrs);
@@ -183,11 +188,6 @@
 
 	BUG_ON(!dma_ops);
 
-	if (dma_ops->unmap_single) {
-		dma_ops->unmap_single(dev, dma_addr, size, direction, attrs);
-		return;
-	}
-
 	dma_ops->unmap_page(dev, dma_addr, size, direction, attrs);
 }
 
@@ -201,12 +201,7 @@
 
 	BUG_ON(!dma_ops);
 
-	if (dma_ops->map_page)
-		return dma_ops->map_page(dev, page, offset, size, direction,
-					 attrs);
-
-	return dma_ops->map_single(dev, page_address(page) + offset, size,
-				   direction, attrs);
+	return dma_ops->map_page(dev, page, offset, size, direction, attrs);
 }
 
 static inline void dma_unmap_page_attrs(struct device *dev,
@@ -219,12 +214,7 @@
 
 	BUG_ON(!dma_ops);
 
-	if (dma_ops->unmap_page) {
-		dma_ops->unmap_page(dev, dma_address, size, direction, attrs);
-		return;
-	}
-
-	dma_ops->unmap_single(dev, dma_address, size, direction, attrs);
+	dma_ops->unmap_page(dev, dma_address, size, direction, attrs);
 }
 
 static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
@@ -308,48 +298,108 @@
 	dma_unmap_sg_attrs(dev, sg, nhwentries, direction, NULL);
 }
 
+#ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS
 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_ON(direction == DMA_NONE);
-	__dma_sync(bus_to_virt(dma_handle), size, direction);
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	dma_ops->sync_single_range_for_cpu(dev, dma_handle, 0,
+					   size, direction);
 }
 
 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_ON(direction == DMA_NONE);
-	__dma_sync(bus_to_virt(dma_handle), size, direction);
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	dma_ops->sync_single_range_for_device(dev, dma_handle,
+					      0, size, direction);
 }
 
 static inline void dma_sync_sg_for_cpu(struct device *dev,
 		struct scatterlist *sgl, int nents,
 		enum dma_data_direction direction)
 {
-	struct scatterlist *sg;
-	int i;
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
-	BUG_ON(direction == DMA_NONE);
-
-	for_each_sg(sgl, sg, nents, i)
-		__dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
+	BUG_ON(!dma_ops);
+	dma_ops->sync_sg_for_cpu(dev, sgl, nents, direction);
 }
 
 static inline void dma_sync_sg_for_device(struct device *dev,
 		struct scatterlist *sgl, int nents,
 		enum dma_data_direction direction)
 {
-	struct scatterlist *sg;
-	int i;
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
-	BUG_ON(direction == DMA_NONE);
-
-	for_each_sg(sgl, sg, nents, i)
-		__dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
+	BUG_ON(!dma_ops);
+	dma_ops->sync_sg_for_device(dev, sgl, nents, direction);
 }
 
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+		dma_addr_t dma_handle, unsigned long offset, size_t size,
+		enum dma_data_direction direction)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	dma_ops->sync_single_range_for_cpu(dev, dma_handle,
+					   offset, size, direction);
+}
+
+static inline void dma_sync_single_range_for_device(struct device *dev,
+		dma_addr_t dma_handle, unsigned long offset, size_t size,
+		enum dma_data_direction direction)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+
+	BUG_ON(!dma_ops);
+	dma_ops->sync_single_range_for_device(dev, dma_handle, offset,
+					      size, direction);
+}
+#else /* CONFIG_PPC_NEED_DMA_SYNC_OPS */
+static inline void dma_sync_single_for_cpu(struct device *dev,
+		dma_addr_t dma_handle, size_t size,
+		enum dma_data_direction direction)
+{
+}
+
+static inline void dma_sync_single_for_device(struct device *dev,
+		dma_addr_t dma_handle, size_t size,
+		enum dma_data_direction direction)
+{
+}
+
+static inline void dma_sync_sg_for_cpu(struct device *dev,
+		struct scatterlist *sgl, int nents,
+		enum dma_data_direction direction)
+{
+}
+
+static inline void dma_sync_sg_for_device(struct device *dev,
+		struct scatterlist *sgl, int nents,
+		enum dma_data_direction direction)
+{
+}
+
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+		dma_addr_t dma_handle, unsigned long offset, size_t size,
+		enum dma_data_direction direction)
+{
+}
+
+static inline void dma_sync_single_range_for_device(struct device *dev,
+		dma_addr_t dma_handle, unsigned long offset, size_t size,
+		enum dma_data_direction direction)
+{
+}
+#endif
+
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
 #ifdef CONFIG_PPC64
@@ -382,22 +432,6 @@
 #endif
 }
 
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
-		dma_addr_t dma_handle, unsigned long offset, size_t size,
-		enum dma_data_direction direction)
-{
-	/* just sync everything for now */
-	dma_sync_single_for_cpu(dev, dma_handle, offset + size, direction);
-}
-
-static inline void dma_sync_single_range_for_device(struct device *dev,
-		dma_addr_t dma_handle, unsigned long offset, size_t size,
-		enum dma_data_direction direction)
-{
-	/* just sync everything for now */
-	dma_sync_single_for_device(dev, dma_handle, offset + size, direction);
-}
-
 static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
 		enum dma_data_direction direction)
 {
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index b886bec..66ea9b8 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -17,8 +17,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#ifndef _PPC64_EEH_H
-#define _PPC64_EEH_H
+#ifndef _POWERPC_EEH_H
+#define _POWERPC_EEH_H
 #ifdef __KERNEL__
 
 #include <linux/init.h>
@@ -110,6 +110,7 @@
 #define EEH_IO_ERROR_VALUE(size) (-1UL)
 #endif /* CONFIG_EEH */
 
+#ifdef CONFIG_PPC64
 /*
  * MMIO read/write operations with EEH support.
  */
@@ -207,5 +208,6 @@
 		eeh_check_failure(addr, *(u32*)buf);
 }
 
+#endif /* CONFIG_PPC64 */
 #endif /* __KERNEL__ */
-#endif /* _PPC64_EEH_H */
+#endif /* _POWERPC_EEH_H */
diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h
index d812929..cd46f02 100644
--- a/arch/powerpc/include/asm/elf.h
+++ b/arch/powerpc/include/asm/elf.h
@@ -267,7 +267,7 @@
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES
 struct linux_binprm;
 extern int arch_setup_additional_pages(struct linux_binprm *bprm,
-				       int executable_stack);
+				       int uses_interp);
 #define VDSO_AUX_ENT(a,b) NEW_AUX_ENT(a,b);
 
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h
index a102996..e4094a5 100644
--- a/arch/powerpc/include/asm/feature-fixups.h
+++ b/arch/powerpc/include/asm/feature-fixups.h
@@ -81,6 +81,36 @@
 #define ALT_FTR_SECTION_END_IFCLR(msk)	\
 	ALT_FTR_SECTION_END_NESTED_IFCLR(msk, 97)
 
+/* MMU feature dependent sections */
+#define BEGIN_MMU_FTR_SECTION_NESTED(label)	START_FTR_SECTION(label)
+#define BEGIN_MMU_FTR_SECTION			START_FTR_SECTION(97)
+
+#define END_MMU_FTR_SECTION_NESTED(msk, val, label) 		\
+	FTR_SECTION_ELSE_NESTED(label)				\
+	MAKE_FTR_SECTION_ENTRY(msk, val, label, __mmu_ftr_fixup)
+
+#define END_MMU_FTR_SECTION(msk, val)		\
+	END_MMU_FTR_SECTION_NESTED(msk, val, 97)
+
+#define END_MMU_FTR_SECTION_IFSET(msk)	END_MMU_FTR_SECTION((msk), (msk))
+#define END_MMU_FTR_SECTION_IFCLR(msk)	END_MMU_FTR_SECTION((msk), 0)
+
+/* MMU feature sections with alternatives, use BEGIN_FTR_SECTION to start */
+#define MMU_FTR_SECTION_ELSE_NESTED(label)	FTR_SECTION_ELSE_NESTED(label)
+#define MMU_FTR_SECTION_ELSE	MMU_FTR_SECTION_ELSE_NESTED(97)
+#define ALT_MMU_FTR_SECTION_END_NESTED(msk, val, label)	\
+	MAKE_FTR_SECTION_ENTRY(msk, val, label, __mmu_ftr_fixup)
+#define ALT_MMU_FTR_SECTION_END_NESTED_IFSET(msk, label)	\
+	ALT_MMU_FTR_SECTION_END_NESTED(msk, msk, label)
+#define ALT_MMU_FTR_SECTION_END_NESTED_IFCLR(msk, label)	\
+	ALT_MMU_FTR_SECTION_END_NESTED(msk, 0, label)
+#define ALT_MMU_FTR_SECTION_END(msk, val)	\
+	ALT_MMU_FTR_SECTION_END_NESTED(msk, val, 97)
+#define ALT_MMU_FTR_SECTION_END_IFSET(msk)	\
+	ALT_MMU_FTR_SECTION_END_NESTED_IFSET(msk, 97)
+#define ALT_MMU_FTR_SECTION_END_IFCLR(msk)	\
+	ALT_MMU_FTR_SECTION_END_NESTED_IFCLR(msk, 97)
+
 /* Firmware feature dependent sections */
 #define BEGIN_FW_FTR_SECTION_NESTED(label)	START_FTR_SECTION(label)
 #define BEGIN_FW_FTR_SECTION			START_FTR_SECTION(97)
diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h
index b298f7a..e5f2ae8 100644
--- a/arch/powerpc/include/asm/ftrace.h
+++ b/arch/powerpc/include/asm/ftrace.h
@@ -7,7 +7,19 @@
 
 #ifndef __ASSEMBLY__
 extern void _mcount(void);
-#endif
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+       /* reloction of mcount call site is the same as the address */
+       return addr;
+}
+
+struct dyn_arch_ftrace {
+	struct module *mod;
+};
+#endif /*  CONFIG_DYNAMIC_FTRACE */
+#endif /* __ASSEMBLY__ */
 
 #endif
 
diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h
index 91c5895..04e4a62 100644
--- a/arch/powerpc/include/asm/highmem.h
+++ b/arch/powerpc/include/asm/highmem.h
@@ -38,9 +38,24 @@
  * easily, subsequent pte tables have to be allocated in one physical
  * chunk of RAM.
  */
-#define LAST_PKMAP 	(1 << PTE_SHIFT)
-#define LAST_PKMAP_MASK (LAST_PKMAP-1)
+/*
+ * We use one full pte table with 4K pages. And with 16K/64K pages pte
+ * table covers enough memory (32MB and 512MB resp.) that both FIXMAP
+ * and PKMAP can be placed in single pte table. We use 1024 pages for
+ * PKMAP in case of 16K/64K pages.
+ */
+#ifdef CONFIG_PPC_4K_PAGES
+#define PKMAP_ORDER	PTE_SHIFT
+#else
+#define PKMAP_ORDER	10
+#endif
+#define LAST_PKMAP	(1 << PKMAP_ORDER)
+#ifndef CONFIG_PPC_4K_PAGES
+#define PKMAP_BASE	(FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1))
+#else
 #define PKMAP_BASE	((FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK)
+#endif
+#define LAST_PKMAP_MASK	(LAST_PKMAP-1)
 #define PKMAP_NR(virt)  ((virt-PKMAP_BASE) >> PAGE_SHIFT)
 #define PKMAP_ADDR(nr)  (PKMAP_BASE + ((nr) << PAGE_SHIFT))
 
@@ -85,7 +100,7 @@
 	BUG_ON(!pte_none(*(kmap_pte-idx)));
 #endif
 	__set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
-	flush_tlb_page(NULL, vaddr);
+	local_flush_tlb_page(NULL, vaddr);
 
 	return (void*) vaddr;
 }
@@ -113,7 +128,7 @@
 	 * this pte without first remap it
 	 */
 	pte_clear(&init_mm, vaddr, kmap_pte-idx);
-	flush_tlb_page(NULL, vaddr);
+	local_flush_tlb_page(NULL, vaddr);
 #endif
 	pagefault_enable();
 }
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 08266d2..494cd8b 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -713,13 +713,6 @@
  */
 #define page_to_phys(page)	((phys_addr_t)page_to_pfn(page) << PAGE_SHIFT)
 
-/* We do NOT want virtual merging, it would put too much pressure on
- * our iommu allocator. Instead, we want drivers to be smart enough
- * to coalesce sglists that happen to have been mapped in a contiguous
- * way by the iommu
- */
-#define BIO_VMERGE_BOUNDARY	0
-
 /*
  * 32 bits still uses virt_to_bus() for it's implementation of DMA
  * mappings se we have to keep it defined here. We also have some old
diff --git a/arch/powerpc/include/asm/kdump.h b/arch/powerpc/include/asm/kdump.h
index b07ebb9..5ebfe5d 100644
--- a/arch/powerpc/include/asm/kdump.h
+++ b/arch/powerpc/include/asm/kdump.h
@@ -1,6 +1,8 @@
 #ifndef _PPC64_KDUMP_H
 #define _PPC64_KDUMP_H
 
+#include <asm/page.h>
+
 /* Kdump kernel runs at 32 MB, change at your peril. */
 #define KDUMP_KERNELBASE	0x2000000
 
@@ -11,8 +13,19 @@
 
 #ifdef CONFIG_CRASH_DUMP
 
+/*
+ * On PPC64 translation is disabled during trampoline setup, so we use
+ * physical addresses. Though on PPC32 translation is already enabled,
+ * so we can't do the same. Luckily create_trampoline() creates relative
+ * branches, so we can just add the PAGE_OFFSET and don't worry about it.
+ */
+#ifdef __powerpc64__
 #define KDUMP_TRAMPOLINE_START	0x0100
 #define KDUMP_TRAMPOLINE_END	0x3000
+#else
+#define KDUMP_TRAMPOLINE_START	(0x0100 + PAGE_OFFSET)
+#define KDUMP_TRAMPOLINE_END	(0x3000 + PAGE_OFFSET)
+#endif /* __powerpc64__ */
 
 #define KDUMP_MIN_TCE_ENTRIES	2048
 
diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index 3736d9b..6dbffc9 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -33,12 +33,12 @@
 
 #ifndef __ASSEMBLY__
 #include <linux/cpumask.h>
+#include <asm/reg.h>
 
 typedef void (*crash_shutdown_t)(void);
 
 #ifdef CONFIG_KEXEC
 
-#ifdef __powerpc64__
 /*
  * This function is responsible for capturing register states if coming
  * via panic or invoking dump using sysrq-trigger.
@@ -48,6 +48,7 @@
 {
 	if (oldregs)
 		memcpy(newregs, oldregs, sizeof(*newregs));
+#ifdef __powerpc64__
 	else {
 		/* FIXME Merge this with xmon_save_regs ?? */
 		unsigned long tmp1, tmp2;
@@ -100,15 +101,11 @@
 			: "b" (newregs)
 			: "memory");
 	}
-}
 #else
-/*
- * Provide a dummy definition to avoid build failures. Will remain
- * empty till crash dump support is enabled.
- */
-static inline void crash_setup_regs(struct pt_regs *newregs,
-					struct pt_regs *oldregs) { }
-#endif /* !__powerpc64 __ */
+	else
+		ppc_save_regs(newregs);
+#endif /* __powerpc64__ */
+}
 
 extern void kexec_smp_wait(void);	/* get and clear naca physid, wait for
 					  master to copy new code to 0 */
diff --git a/arch/powerpc/include/asm/local.h b/arch/powerpc/include/asm/local.h
index 612d832..84b457a 100644
--- a/arch/powerpc/include/asm/local.h
+++ b/arch/powerpc/include/asm/local.h
@@ -67,7 +67,7 @@
 	bne-	1b"
 	: "=&r" (t)
 	: "r" (&(l->a.counter))
-	: "cc", "memory");
+	: "cc", "xer", "memory");
 
 	return t;
 }
@@ -94,7 +94,7 @@
 	bne-	1b"
 	: "=&r" (t)
 	: "r" (&(l->a.counter))
-	: "cc", "memory");
+	: "cc", "xer", "memory");
 
 	return t;
 }
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index 2fe268b..25aaa97 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -133,7 +133,8 @@
 //=============================================================================
 // CACHE_LINE_4-5 0x0180 - 0x027F Contains PMC interrupt data
 //=============================================================================
-	u8	pmc_save_area[256];	// PMC interrupt Area           x00-xFF
+	u32	page_ins;			// CMO Hint - # page ins by OS  x00-x04
+	u8	pmc_save_area[252];	// PMC interrupt Area           x04-xFF
 } __attribute__((__aligned__(0x400)));
 
 extern struct lppaca lppaca[];
diff --git a/arch/powerpc/include/asm/mmu-40x.h b/arch/powerpc/include/asm/mmu-40x.h
index 3d10867..776f415a 100644
--- a/arch/powerpc/include/asm/mmu-40x.h
+++ b/arch/powerpc/include/asm/mmu-40x.h
@@ -54,8 +54,9 @@
 #ifndef __ASSEMBLY__
 
 typedef struct {
-	unsigned long id;
-	unsigned long vdso_base;
+	unsigned int	id;
+	unsigned int	active;
+	unsigned long	vdso_base;
 } mm_context_t;
 
 #endif /* !__ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/mmu-44x.h b/arch/powerpc/include/asm/mmu-44x.h
index a825524..8a97cfb 100644
--- a/arch/powerpc/include/asm/mmu-44x.h
+++ b/arch/powerpc/include/asm/mmu-44x.h
@@ -4,6 +4,8 @@
  * PPC440 support
  */
 
+#include <asm/page.h>
+
 #define PPC44x_MMUCR_TID	0x000000ff
 #define PPC44x_MMUCR_STS	0x00010000
 
@@ -56,8 +58,9 @@
 extern unsigned int tlb_44x_hwater;
 
 typedef struct {
-	unsigned long id;
-	unsigned long vdso_base;
+	unsigned int	id;
+	unsigned int	active;
+	unsigned long	vdso_base;
 } mm_context_t;
 
 #endif /* !__ASSEMBLY__ */
@@ -73,4 +76,19 @@
 /* Size of the TLBs used for pinning in lowmem */
 #define PPC_PIN_SIZE	(1 << 28)	/* 256M */
 
+#if (PAGE_SHIFT == 12)
+#define PPC44x_TLBE_SIZE	PPC44x_TLB_4K
+#elif (PAGE_SHIFT == 14)
+#define PPC44x_TLBE_SIZE	PPC44x_TLB_16K
+#elif (PAGE_SHIFT == 16)
+#define PPC44x_TLBE_SIZE	PPC44x_TLB_64K
+#else
+#error "Unsupported PAGE_SIZE"
+#endif
+
+#define PPC44x_PGD_OFF_SHIFT	(32 - PGDIR_SHIFT + PGD_T_LOG2)
+#define PPC44x_PGD_OFF_MASK_BIT	(PGDIR_SHIFT - PGD_T_LOG2)
+#define PPC44x_PTE_ADD_SHIFT	(32 - PGDIR_SHIFT + PTE_SHIFT + PTE_T_LOG2)
+#define PPC44x_PTE_ADD_MASK_BIT	(32 - PTE_T_LOG2 - PTE_SHIFT)
+
 #endif /* _ASM_POWERPC_MMU_44X_H_ */
diff --git a/arch/powerpc/include/asm/mmu-8xx.h b/arch/powerpc/include/asm/mmu-8xx.h
index 9db877e..07865a3 100644
--- a/arch/powerpc/include/asm/mmu-8xx.h
+++ b/arch/powerpc/include/asm/mmu-8xx.h
@@ -137,7 +137,8 @@
 
 #ifndef __ASSEMBLY__
 typedef struct {
-	unsigned long id;
+	unsigned int id;
+	unsigned int active;
 	unsigned long vdso_base;
 } mm_context_t;
 #endif /* !__ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/mmu-fsl-booke.h b/arch/powerpc/include/asm/mmu-fsl-booke.h
index 925d93c..3f941c0 100644
--- a/arch/powerpc/include/asm/mmu-fsl-booke.h
+++ b/arch/powerpc/include/asm/mmu-fsl-booke.h
@@ -40,6 +40,8 @@
 #define MAS2_M		0x00000004
 #define MAS2_G		0x00000002
 #define MAS2_E		0x00000001
+#define MAS2_EPN_MASK(size)		(~0 << (2*(size) + 10))
+#define MAS2_VAL(addr, size, flags)	((addr) & MAS2_EPN_MASK(size) | (flags))
 
 #define MAS3_RPN	0xFFFFF000
 #define MAS3_U0		0x00000200
@@ -74,8 +76,9 @@
 #ifndef __ASSEMBLY__
 
 typedef struct {
-	unsigned long id;
-	unsigned long vdso_base;
+	unsigned int	id;
+	unsigned int	active;
+	unsigned long	vdso_base;
 } mm_context_t;
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index 4c0e1b4..6e76399 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -2,6 +2,63 @@
 #define _ASM_POWERPC_MMU_H_
 #ifdef __KERNEL__
 
+#include <asm/asm-compat.h>
+#include <asm/feature-fixups.h>
+
+/*
+ * MMU features bit definitions
+ */
+
+/*
+ * First half is MMU families
+ */
+#define MMU_FTR_HPTE_TABLE		ASM_CONST(0x00000001)
+#define MMU_FTR_TYPE_8xx		ASM_CONST(0x00000002)
+#define MMU_FTR_TYPE_40x		ASM_CONST(0x00000004)
+#define MMU_FTR_TYPE_44x		ASM_CONST(0x00000008)
+#define MMU_FTR_TYPE_FSL_E		ASM_CONST(0x00000010)
+
+/*
+ * This is individual features
+ */
+
+/* Enable use of high BAT registers */
+#define MMU_FTR_USE_HIGH_BATS		ASM_CONST(0x00010000)
+
+/* Enable >32-bit physical addresses on 32-bit processor, only used
+ * by CONFIG_6xx currently as BookE supports that from day 1
+ */
+#define MMU_FTR_BIG_PHYS		ASM_CONST(0x00020000)
+
+/* Enable use of broadcast TLB invalidations. We don't always set it
+ * on processors that support it due to other constraints with the
+ * use of such invalidations
+ */
+#define MMU_FTR_USE_TLBIVAX_BCAST	ASM_CONST(0x00040000)
+
+/* Enable use of tlbilx invalidate-by-PID variant.
+ */
+#define MMU_FTR_USE_TLBILX_PID		ASM_CONST(0x00080000)
+
+/* This indicates that the processor cannot handle multiple outstanding
+ * broadcast tlbivax or tlbsync. This makes the code use a spinlock
+ * around such invalidate forms.
+ */
+#define MMU_FTR_LOCK_BCAST_INVAL	ASM_CONST(0x00100000)
+
+#ifndef __ASSEMBLY__
+#include <asm/cputable.h>
+
+static inline int mmu_has_feature(unsigned long feature)
+{
+	return (cur_cpu_spec->mmu_features & feature);
+}
+
+extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup;
+
+#endif /* !__ASSEMBLY__ */
+
+
 #ifdef CONFIG_PPC64
 /* 64-bit classic hash table MMU */
 #  include <asm/mmu-hash64.h>
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index 6b993ef..ab4f192 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -2,237 +2,26 @@
 #define __ASM_POWERPC_MMU_CONTEXT_H
 #ifdef __KERNEL__
 
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <asm/mmu.h>	
 #include <asm/cputable.h>
 #include <asm-generic/mm_hooks.h>
-
-#ifndef CONFIG_PPC64
-#include <asm/atomic.h>
-#include <linux/bitops.h>
+#include <asm/cputhreads.h>
 
 /*
- * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs
- * (virtual segment identifiers) for each context.  Although the
- * hardware supports 24-bit VSIDs, and thus >1 million contexts,
- * we only use 32,768 of them.  That is ample, since there can be
- * at most around 30,000 tasks in the system anyway, and it means
- * that we can use a bitmap to indicate which contexts are in use.
- * Using a bitmap means that we entirely avoid all of the problems
- * that we used to have when the context number overflowed,
- * particularly on SMP systems.
- *  -- paulus.
+ * Most if the context management is out of line
  */
-
-/*
- * 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.  Note, if this
- * function is changed then arch/ppc/mm/hashtable.S will have to be
- * changed to correspond.
- */
-#define CTX_TO_VSID(ctx, va)	(((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \
-				 & 0xffffff)
-
-/*
-   The MPC8xx has only 16 contexts.  We rotate through them on each
-   task switch.  A better way would be to keep track of tasks that
-   own contexts, and implement an LRU usage.  That way very active
-   tasks don't always have to pay the TLB reload overhead.  The
-   kernel pages are mapped shared, so the kernel can run on behalf
-   of any task that makes a kernel entry.  Shared does not mean they
-   are not protected, just that the ASID comparison is not performed.
-        -- Dan
-
-   The IBM4xx 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.
-   	-- Dan
- */
-
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
-{
-}
-
-#ifdef CONFIG_8xx
-#define NO_CONTEXT      	16
-#define LAST_CONTEXT    	15
-#define FIRST_CONTEXT    	0
-
-#elif defined(CONFIG_4xx)
-#define NO_CONTEXT      	256
-#define LAST_CONTEXT    	255
-#define FIRST_CONTEXT    	1
-
-#elif defined(CONFIG_E200) || defined(CONFIG_E500)
-#define NO_CONTEXT      	256
-#define LAST_CONTEXT    	255
-#define FIRST_CONTEXT    	1
-
-#else
-
-/* PPC 6xx, 7xx CPUs */
-#define NO_CONTEXT      	((unsigned long) -1)
-#define LAST_CONTEXT    	32767
-#define FIRST_CONTEXT    	1
-#endif
-
-/*
- * Set the current MMU context.
- * On 32-bit PowerPCs (other than the 8xx embedded chips), this is done by
- * loading 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(unsigned long contextid, 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 unsigned long next_mmu_context;
-
-/*
- * If 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.
- */
-#if LAST_CONTEXT < 30000
-#define FEW_CONTEXTS	1
-extern atomic_t nr_free_contexts;
-extern struct mm_struct *context_mm[LAST_CONTEXT+1];
-extern void steal_context(void);
-#endif
-
-/*
- * Get a new mmu context for the address space described by `mm'.
- */
-static inline void get_mmu_context(struct mm_struct *mm)
-{
-	unsigned long ctx;
-
-	if (mm->context.id != NO_CONTEXT)
-		return;
-#ifdef FEW_CONTEXTS
-	while (atomic_dec_if_positive(&nr_free_contexts) < 0)
-		steal_context();
-#endif
-	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.id = ctx;
-#ifdef FEW_CONTEXTS
-	context_mm[ctx] = mm;
-#endif
-}
-
-/*
- * Set up the context for a new address space.
- */
-static inline int init_new_context(struct task_struct *t, struct mm_struct *mm)
-{
-	mm->context.id = NO_CONTEXT;
-	return 0;
-}
-
-/*
- * We're finished using the context for an address space.
- */
-static inline void destroy_context(struct mm_struct *mm)
-{
-	preempt_disable();
-	if (mm->context.id != NO_CONTEXT) {
-		clear_bit(mm->context.id, context_map);
-		mm->context.id = NO_CONTEXT;
-#ifdef FEW_CONTEXTS
-		atomic_inc(&nr_free_contexts);
-#endif
-	}
-	preempt_enable();
-}
-
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
-			     struct task_struct *tsk)
-{
-#ifdef CONFIG_ALTIVEC
-	if (cpu_has_feature(CPU_FTR_ALTIVEC))
-	asm volatile ("dssall;\n"
-#ifndef CONFIG_POWER4
-	 "sync;\n" /* G4 needs a sync here, G5 apparently not */
-#endif
-	 : : );
-#endif /* CONFIG_ALTIVEC */
-
-	tsk->thread.pgdir = next->pgd;
-
-	/* No need to flush userspace segments if the mm doesnt change */
-	if (prev == next)
-		return;
-
-	/* Setup new userspace context */
-	get_mmu_context(next);
-	set_context(next->context.id, next->pgd);
-}
-
-#define deactivate_mm(tsk,mm)	do { } while (0)
-
-/*
- * After we have set current->mm to a new value, this activates
- * the context for the new mm so we see the new mappings.
- */
-#define activate_mm(active_mm, mm)   switch_mm(active_mm, mm, current)
-
 extern void mmu_context_init(void);
-
-
-#else
-
-#include <linux/kernel.h>	
-#include <linux/mm.h>	
-#include <linux/sched.h>
-
-/*
- * Copyright (C) 2001 PPC 64 Team, IBM Corp
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-static inline void enter_lazy_tlb(struct mm_struct *mm,
-				  struct task_struct *tsk)
-{
-}
-
-/*
- * The proto-VSID space has 2^35 - 1 segments available for user mappings.
- * Each segment contains 2^28 bytes.  Each context maps 2^44 bytes,
- * so we can support 2^19-1 contexts (19 == 35 + 28 - 44).
- */
-#define NO_CONTEXT	0
-#define MAX_CONTEXT	((1UL << 19) - 1)
-
 extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
 extern void destroy_context(struct mm_struct *mm);
 
+extern void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next);
 extern void switch_stab(struct task_struct *tsk, struct mm_struct *mm);
 extern void switch_slb(struct task_struct *tsk, struct mm_struct *mm);
+extern void set_context(unsigned long id, pgd_t *pgd);
 
 /*
  * switch_mm is the entry point called from the architecture independent
@@ -241,22 +30,39 @@
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 			     struct task_struct *tsk)
 {
-	if (!cpu_isset(smp_processor_id(), next->cpu_vm_mask))
-		cpu_set(smp_processor_id(), next->cpu_vm_mask);
+	/* Mark this context has been used on the new CPU */
+	cpu_set(smp_processor_id(), next->cpu_vm_mask);
 
-	/* No need to flush userspace segments if the mm doesnt change */
+	/* 32-bit keeps track of the current PGDIR in the thread struct */
+#ifdef CONFIG_PPC32
+	tsk->thread.pgdir = next->pgd;
+#endif /* CONFIG_PPC32 */
+
+	/* Nothing else to do if we aren't actually switching */
 	if (prev == next)
 		return;
 
+	/* We must stop all altivec streams before changing the HW
+	 * context
+	 */
 #ifdef CONFIG_ALTIVEC
 	if (cpu_has_feature(CPU_FTR_ALTIVEC))
 		asm volatile ("dssall");
 #endif /* CONFIG_ALTIVEC */
 
+	/* The actual HW switching method differs between the various
+	 * sub architectures.
+	 */
+#ifdef CONFIG_PPC_STD_MMU_64
 	if (cpu_has_feature(CPU_FTR_SLB))
 		switch_slb(tsk, next);
 	else
 		switch_stab(tsk, next);
+#else
+	/* Out of line for now */
+	switch_mmu_context(prev, next);
+#endif
+
 }
 
 #define deactivate_mm(tsk,mm)	do { } while (0)
@@ -274,6 +80,11 @@
 	local_irq_restore(flags);
 }
 
-#endif /* CONFIG_PPC64 */
+/* We don't currently use enter_lazy_tlb() for anything */
+static inline void enter_lazy_tlb(struct mm_struct *mm,
+				  struct task_struct *tsk)
+{
+}
+
 #endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_MMU_CONTEXT_H */
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h
index e5f14b1..0845488 100644
--- a/arch/powerpc/include/asm/module.h
+++ b/arch/powerpc/include/asm/module.h
@@ -34,11 +34,19 @@
 #ifdef __powerpc64__
 	unsigned int stubs_section;	/* Index of stubs section in module */
 	unsigned int toc_section;	/* What section is the TOC? */
-#else
+#ifdef CONFIG_DYNAMIC_FTRACE
+	unsigned long toc;
+	unsigned long tramp;
+#endif
+
+#else /* powerpc64 */
 	/* Indices of PLT sections within module. */
 	unsigned int core_plt_section;
 	unsigned int init_plt_section;
+#ifdef CONFIG_DYNAMIC_FTRACE
+	unsigned long tramp;
 #endif
+#endif /* powerpc64 */
 
 	/* List of BUG addresses, source line numbers and filenames */
 	struct list_head bug_list;
@@ -68,6 +76,12 @@
 #    endif	/* MODULE */
 #endif
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+#    ifdef MODULE
+	asm(".section .ftrace.tramp,\"ax\",@nobits; .align 3; .previous");
+#    endif	/* MODULE */
+#endif
+
 
 struct exception_table_entry;
 void sort_ex_table(struct exception_table_entry *start,
diff --git a/arch/powerpc/include/asm/mpc52xx.h b/arch/powerpc/include/asm/mpc52xx.h
index 81ef10b..81a2393 100644
--- a/arch/powerpc/include/asm/mpc52xx.h
+++ b/arch/powerpc/include/asm/mpc52xx.h
@@ -239,6 +239,25 @@
 	u16 mclken_div_psc6;	/* CDM + 0x36  reg13 byte2,3 */
 };
 
+/* Interrupt controller Register set */
+struct mpc52xx_intr {
+	u32 per_mask;		/* INTR + 0x00 */
+	u32 per_pri1;		/* INTR + 0x04 */
+	u32 per_pri2;		/* INTR + 0x08 */
+	u32 per_pri3;		/* INTR + 0x0c */
+	u32 ctrl;		/* INTR + 0x10 */
+	u32 main_mask;		/* INTR + 0x14 */
+	u32 main_pri1;		/* INTR + 0x18 */
+	u32 main_pri2;		/* INTR + 0x1c */
+	u32 reserved1;		/* INTR + 0x20 */
+	u32 enc_status;		/* INTR + 0x24 */
+	u32 crit_status;	/* INTR + 0x28 */
+	u32 main_status;	/* INTR + 0x2c */
+	u32 per_status;		/* INTR + 0x30 */
+	u32 reserved2;		/* INTR + 0x34 */
+	u32 per_error;		/* INTR + 0x38 */
+};
+
 #endif /* __ASSEMBLY__ */
 
 
diff --git a/arch/powerpc/include/asm/mpc52xx_psc.h b/arch/powerpc/include/asm/mpc52xx_psc.h
index 8917ed6..a218da6 100644
--- a/arch/powerpc/include/asm/mpc52xx_psc.h
+++ b/arch/powerpc/include/asm/mpc52xx_psc.h
@@ -68,12 +68,20 @@
 #define MPC52xx_PSC_IMR_ORERR		0x1000
 #define MPC52xx_PSC_IMR_IPC		0x8000
 
-/* PSC input port change bit */
+/* PSC input port change bits */
 #define MPC52xx_PSC_CTS			0x01
 #define MPC52xx_PSC_DCD			0x02
 #define MPC52xx_PSC_D_CTS		0x10
 #define MPC52xx_PSC_D_DCD		0x20
 
+/* PSC acr bits */
+#define MPC52xx_PSC_IEC_CTS		0x01
+#define MPC52xx_PSC_IEC_DCD		0x02
+
+/* PSC output port bits */
+#define MPC52xx_PSC_OP_RTS		0x01
+#define MPC52xx_PSC_OP_RES		0x02
+
 /* PSC mode fields */
 #define MPC52xx_PSC_MODE_5_BITS			0x00
 #define MPC52xx_PSC_MODE_6_BITS			0x01
@@ -91,6 +99,7 @@
 #define MPC52xx_PSC_MODE_ONE_STOP_5_BITS	0x00
 #define MPC52xx_PSC_MODE_ONE_STOP		0x07
 #define MPC52xx_PSC_MODE_TWO_STOP		0x0f
+#define MPC52xx_PSC_MODE_TXCTS			0x10
 
 #define MPC52xx_PSC_RFNUM_MASK	0x01ff
 
diff --git a/arch/powerpc/include/asm/mutex.h b/arch/powerpc/include/asm/mutex.h
index 458c1f7..dabc01c 100644
--- a/arch/powerpc/include/asm/mutex.h
+++ b/arch/powerpc/include/asm/mutex.h
@@ -1,9 +1,134 @@
 /*
- * Pull in the generic implementation for the mutex fastpath.
- *
- * TODO: implement optimized primitives instead, or leave the generic
- * implementation in place, or pick the atomic_xchg() based generic
- * implementation. (see asm-generic/mutex-xchg.h for details)
+ * Optimised mutex implementation of include/asm-generic/mutex-dec.h algorithm
  */
+#ifndef _ASM_POWERPC_MUTEX_H
+#define _ASM_POWERPC_MUTEX_H
 
-#include <asm-generic/mutex-dec.h>
+static inline int __mutex_cmpxchg_lock(atomic_t *v, int old, int new)
+{
+	int t;
+
+	__asm__ __volatile__ (
+"1:	lwarx	%0,0,%1		# mutex trylock\n\
+	cmpw	0,%0,%2\n\
+	bne-	2f\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%3,0,%1\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	"\n\
+2:"
+	: "=&r" (t)
+	: "r" (&v->counter), "r" (old), "r" (new)
+	: "cc", "memory");
+
+	return t;
+}
+
+static inline int __mutex_dec_return_lock(atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%1		# mutex lock\n\
+	addic	%0,%0,-1\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%0,0,%1\n\
+	bne-	1b"
+	ISYNC_ON_SMP
+	: "=&r" (t)
+	: "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+static inline int __mutex_inc_return_unlock(atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+	LWSYNC_ON_SMP
+"1:	lwarx	%0,0,%1		# mutex unlock\n\
+	addic	%0,%0,1\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%0,0,%1 \n\
+	bne-	1b"
+	: "=&r" (t)
+	: "r" (&v->counter)
+	: "cc", "memory");
+
+	return t;
+}
+
+/**
+ *  __mutex_fastpath_lock - try to take the lock by moving the count
+ *                          from 1 to a 0 value
+ *  @count: pointer of type atomic_t
+ *  @fail_fn: function to call if the original value was not 1
+ *
+ * Change the count from 1 to a value lower than 1, and call <fail_fn> if
+ * it wasn't 1 originally. This function MUST leave the value lower than
+ * 1 even when the "1" assertion wasn't true.
+ */
+static inline void
+__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
+{
+	if (unlikely(__mutex_dec_return_lock(count) < 0))
+		fail_fn(count);
+}
+
+/**
+ *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
+ *                                 from 1 to a 0 value
+ *  @count: pointer of type atomic_t
+ *  @fail_fn: function to call if the original value was not 1
+ *
+ * Change the count from 1 to a value lower than 1, and call <fail_fn> if
+ * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
+ * or anything the slow path function returns.
+ */
+static inline int
+__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+{
+	if (unlikely(__mutex_dec_return_lock(count) < 0))
+		return fail_fn(count);
+	return 0;
+}
+
+/**
+ *  __mutex_fastpath_unlock - try to promote the count from 0 to 1
+ *  @count: pointer of type atomic_t
+ *  @fail_fn: function to call if the original value was not 0
+ *
+ * Try to promote the count from 0 to 1. If it wasn't 0, call <fail_fn>.
+ * In the failure case, this function is allowed to either set the value to
+ * 1, or to set it to a value lower than 1.
+ */
+static inline void
+__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
+{
+	if (unlikely(__mutex_inc_return_unlock(count) <= 0))
+		fail_fn(count);
+}
+
+#define __mutex_slowpath_needs_to_unlock()		1
+
+/**
+ * __mutex_fastpath_trylock - try to acquire the mutex, without waiting
+ *
+ *  @count: pointer of type atomic_t
+ *  @fail_fn: fallback function
+ *
+ * Change the count from 1 to 0, and return 1 (success), or if the count
+ * was not 1, then return 0 (failure).
+ */
+static inline int
+__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
+{
+	if (likely(__mutex_cmpxchg_lock(count, 1, 0) == 1))
+		return 1;
+	return 0;
+}
+
+#endif
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index c0b8d4a..197d569 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -19,12 +19,15 @@
 #include <asm/kdump.h>
 
 /*
- * On PPC32 page size is 4K. For PPC64 we support either 4K or 64K software
+ * On regular PPC32 page size is 4K (but we support 4K/16K/64K pages
+ * on PPC44x). For PPC64 we support either 4K or 64K software
  * page size. When using 64K pages however, whether we are really supporting
  * 64K pages in HW or not is irrelevant to those definitions.
  */
-#ifdef CONFIG_PPC_64K_PAGES
+#if defined(CONFIG_PPC_64K_PAGES)
 #define PAGE_SHIFT		16
+#elif defined(CONFIG_PPC_16K_PAGES)
+#define PAGE_SHIFT		14
 #else
 #define PAGE_SHIFT		12
 #endif
@@ -151,7 +154,7 @@
 /* 64k pages additionally define a bigger "real PTE" type that gathers
  * the "second half" part of the PTE for pseudo 64k pages
  */
-#ifdef CONFIG_PPC_64K_PAGES
+#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_PPC_STD_MMU_64)
 typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
 #else
 typedef struct { pte_t pte; } real_pte_t;
@@ -191,10 +194,10 @@
 #define pte_val(x)	(x)
 #define __pte(x)	(x)
 
-#ifdef CONFIG_PPC_64K_PAGES
+#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_PPC_STD_MMU_64)
 typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
 #else
-typedef unsigned long real_pte_t;
+typedef pte_t real_pte_t;
 #endif
 
 
diff --git a/arch/powerpc/include/asm/page_32.h b/arch/powerpc/include/asm/page_32.h
index d77072a..1458d95 100644
--- a/arch/powerpc/include/asm/page_32.h
+++ b/arch/powerpc/include/asm/page_32.h
@@ -19,6 +19,8 @@
 #define PTE_FLAGS_OFFSET	0
 #endif
 
+#define PTE_SHIFT	(PAGE_SHIFT - PTE_T_LOG2)	/* full page */
+
 #ifndef __ASSEMBLY__
 /*
  * The basic type of a PTE - 64 bits for those CPUs with > 32 bit
@@ -26,10 +28,8 @@
  */
 #ifdef CONFIG_PTE_64BIT
 typedef unsigned long long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 3)	/* 512 ptes per page */
 #else
 typedef unsigned long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 2)	/* 1024 ptes per page */
 #endif
 
 struct page;
@@ -39,6 +39,9 @@
 
 #include <asm-generic/page.h>
 
+#define PGD_T_LOG2	(__builtin_ffs(sizeof(pgd_t)) - 1)
+#define PTE_T_LOG2	(__builtin_ffs(sizeof(pte_t)) - 1)
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_PAGE_32_H */
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 9047af7..84007af 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -13,7 +13,6 @@
 
 struct device_node;
 
-extern unsigned int ppc_pci_flags;
 enum {
 	/* Force re-assigning all resources (ignore firmware
 	 * setup completely)
@@ -36,6 +35,31 @@
 	/* ... except for domain 0 */
 	PPC_PCI_COMPAT_DOMAIN_0		= 0x00000020,
 };
+#ifdef CONFIG_PCI
+extern unsigned int ppc_pci_flags;
+
+static inline void ppc_pci_set_flags(int flags)
+{
+	ppc_pci_flags = flags;
+}
+
+static inline void ppc_pci_add_flags(int flags)
+{
+	ppc_pci_flags |= flags;
+}
+
+static inline int ppc_pci_has_flag(int flag)
+{
+	return (ppc_pci_flags & flag);
+}
+#else
+static inline void ppc_pci_set_flags(int flags) { }
+static inline void ppc_pci_add_flags(int flags) { }
+static inline int ppc_pci_has_flag(int flag)
+{
+	return 0;
+}
+#endif
 
 
 /*
@@ -241,9 +265,6 @@
 
 /** Discover new pci devices under this bus, and add them */
 extern void pcibios_add_pci_devices(struct pci_bus *bus);
-extern void pcibios_fixup_new_pci_devices(struct pci_bus *bus);
-
-extern int pcibios_remove_root_bus(struct pci_controller *phb);
 
 static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
 {
@@ -290,6 +311,7 @@
 /* Allocate & free a PCI host bridge structure */
 extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
 extern void pcibios_free_controller(struct pci_controller *phb);
+extern void pcibios_setup_phb_resources(struct pci_controller *hose);
 
 #ifdef CONFIG_PCI
 extern unsigned long pci_address_to_pio(phys_addr_t address);
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 57a2a49..3548159 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -38,8 +38,8 @@
  * Set this to 1 if you want the kernel to re-assign all PCI
  * bus numbers (don't do that on ppc64 yet !)
  */
-#define pcibios_assign_all_busses()    	(ppc_pci_flags & \
-					 PPC_PCI_REASSIGN_ALL_BUS)
+#define pcibios_assign_all_busses() \
+	(ppc_pci_has_flag(PPC_PCI_REASSIGN_ALL_BUS))
 #define pcibios_scan_all_fns(a, b)	0
 
 static inline void pcibios_set_master(struct pci_dev *dev)
@@ -204,15 +204,14 @@
 	return root;
 }
 
-extern void pcibios_setup_new_device(struct pci_dev *dev);
-
 extern void pcibios_claim_one_bus(struct pci_bus *b);
 
-extern void pcibios_allocate_bus_resources(struct pci_bus *bus);
+extern void pcibios_finish_adding_to_bus(struct pci_bus *bus);
 
 extern void pcibios_resource_survey(void);
 
 extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
+extern int remove_phb_dynamic(struct pci_controller *phb);
 
 extern struct pci_dev *of_create_pci_dev(struct device_node *node,
 					struct pci_bus *bus, int devfn);
@@ -221,6 +220,7 @@
 				struct pci_dev *dev);
 
 extern void of_scan_bus(struct device_node *node, struct pci_bus *bus);
+extern void of_rescan_bus(struct device_node *node, struct pci_bus *bus);
 
 extern int pci_read_irq_line(struct pci_dev *dev);
 
@@ -235,9 +235,8 @@
 				 const struct resource *rsrc,
 				 resource_size_t *start, resource_size_t *end);
 
-extern void pcibios_do_bus_setup(struct pci_bus *bus);
-extern void pcibios_fixup_of_probed_bus(struct pci_bus *bus);
-
+extern void pcibios_setup_bus_devices(struct pci_bus *bus);
+extern void pcibios_setup_bus_self(struct pci_bus *bus);
 
 #endif	/* __KERNEL__ */
 #endif /* __ASM_POWERPC_PCI_H */
diff --git a/arch/powerpc/include/asm/pgalloc-32.h b/arch/powerpc/include/asm/pgalloc-32.h
index 58c0714..0815eb4 100644
--- a/arch/powerpc/include/asm/pgalloc-32.h
+++ b/arch/powerpc/include/asm/pgalloc-32.h
@@ -3,6 +3,8 @@
 
 #include <linux/threads.h>
 
+#define PTE_NONCACHE_NUM	0  /* dummy for now to share code w/ppc64 */
+
 extern void __bad_pte(pmd_t *pmd);
 
 extern pgd_t *pgd_alloc(struct mm_struct *mm);
@@ -33,10 +35,13 @@
 
 extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
 extern pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long addr);
-extern void pte_free_kernel(struct mm_struct *mm, pte_t *pte);
-extern void pte_free(struct mm_struct *mm, pgtable_t pte);
 
-#define __pte_free_tlb(tlb, pte)	pte_free((tlb)->mm, (pte))
+static inline void pgtable_free(pgtable_free_t pgf)
+{
+	void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
+
+	free_page((unsigned long)p);
+}
 
 #define check_pgt_cache()	do { } while (0)
 
diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h
index 812a1d8..afda2bd 100644
--- a/arch/powerpc/include/asm/pgalloc-64.h
+++ b/arch/powerpc/include/asm/pgalloc-64.h
@@ -7,7 +7,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/cpumask.h>
 #include <linux/percpu.h>
@@ -108,31 +107,6 @@
 	return page;
 }
 
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-	free_page((unsigned long)pte);
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)
-{
-	pgtable_page_dtor(ptepage);
-	__free_page(ptepage);
-}
-
-#define PGF_CACHENUM_MASK	0x7
-
-typedef struct pgtable_free {
-	unsigned long val;
-} pgtable_free_t;
-
-static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
-						unsigned long mask)
-{
-	BUG_ON(cachenum > PGF_CACHENUM_MASK);
-
-	return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum};
-}
-
 static inline void pgtable_free(pgtable_free_t pgf)
 {
 	void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
@@ -144,14 +118,6 @@
 		kmem_cache_free(pgtable_cache[cachenum], p);
 }
 
-extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
-
-#define __pte_free_tlb(tlb,ptepage)	\
-do { \
-	pgtable_page_dtor(ptepage); \
-	pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
-		PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1)); \
-} while (0)
 #define __pmd_free_tlb(tlb, pmd) 	\
 	pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
 		PMD_CACHE_NUM, PMD_TABLE_SIZE-1))
diff --git a/arch/powerpc/include/asm/pgalloc.h b/arch/powerpc/include/asm/pgalloc.h
index b4505ed..5d84802 100644
--- a/arch/powerpc/include/asm/pgalloc.h
+++ b/arch/powerpc/include/asm/pgalloc.h
@@ -2,11 +2,52 @@
 #define _ASM_POWERPC_PGALLOC_H
 #ifdef __KERNEL__
 
+#include <linux/mm.h>
+
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
+{
+	free_page((unsigned long)pte);
+}
+
+static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)
+{
+	pgtable_page_dtor(ptepage);
+	__free_page(ptepage);
+}
+
+typedef struct pgtable_free {
+	unsigned long val;
+} pgtable_free_t;
+
+#define PGF_CACHENUM_MASK	0x7
+
+static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
+						unsigned long mask)
+{
+	BUG_ON(cachenum > PGF_CACHENUM_MASK);
+
+	return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum};
+}
+
 #ifdef CONFIG_PPC64
 #include <asm/pgalloc-64.h>
 #else
 #include <asm/pgalloc-32.h>
 #endif
 
+extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
+
+#ifdef CONFIG_SMP
+#define __pte_free_tlb(tlb,ptepage)	\
+do { \
+	pgtable_page_dtor(ptepage); \
+	pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
+		PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1)); \
+} while (0)
+#else
+#define __pte_free_tlb(tlb, pte)	pte_free((tlb)->mm, (pte))
+#endif
+
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PGALLOC_H */
diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h
index 6ab7c67..f69a4d9 100644
--- a/arch/powerpc/include/asm/pgtable-ppc32.h
+++ b/arch/powerpc/include/asm/pgtable-ppc32.h
@@ -228,9 +228,10 @@
  *   - FILE *must* be in the bottom three bits because swap cache
  *     entries use the top 29 bits for TLB2.
  *
- *   - CACHE COHERENT bit (M) has no effect on PPC440 core, because it
- *     doesn't support SMP. So we can use this as software bit, like
- *     DIRTY.
+ *   - CACHE COHERENT bit (M) has no effect on original PPC440 cores,
+ *     because it doesn't support SMP. However, some later 460 variants
+ *     have -some- form of SMP support and so I keep the bit there for
+ *     future use
  *
  * With the PPC 44x Linux implementation, the 0-11th LSBs of the PTE are used
  * for memory protection related functions (see PTE structure in
@@ -436,20 +437,23 @@
 			 _PAGE_USER | _PAGE_ACCESSED | \
 			 _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | \
 			 _PAGE_EXEC | _PAGE_HWEXEC)
-/*
- * 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.
- */
 
-#ifdef CONFIG_44x
-#define _PAGE_BASE	(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_GUARDED)
+/*
+ * We define 2 sets of base prot bits, one for basic pages (ie,
+ * cacheable kernel and user pages) and one for non cacheable
+ * pages. We always set _PAGE_COHERENT when SMP is enabled or
+ * the processor might need it for DMA coherency.
+ */
+#if defined(CONFIG_SMP) || defined(CONFIG_PPC_STD_MMU)
+#define _PAGE_BASE	(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT)
 #else
 #define _PAGE_BASE	(_PAGE_PRESENT | _PAGE_ACCESSED)
 #endif
+#define _PAGE_BASE_NC	(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_NO_CACHE)
+
 #define _PAGE_WRENABLE	(_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE)
 #define _PAGE_KERNEL	(_PAGE_BASE | _PAGE_SHARED | _PAGE_WRENABLE)
+#define _PAGE_KERNEL_NC	(_PAGE_BASE_NC | _PAGE_SHARED | _PAGE_WRENABLE)
 
 #ifdef CONFIG_PPC_STD_MMU
 /* On standard PPC MMU, no user access implies kernel read/write access,
@@ -459,7 +463,7 @@
 #define _PAGE_KERNEL_RO	(_PAGE_BASE | _PAGE_SHARED)
 #endif
 
-#define _PAGE_IO	(_PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED)
+#define _PAGE_IO	(_PAGE_KERNEL_NC | _PAGE_GUARDED)
 #define _PAGE_RAM	(_PAGE_KERNEL | _PAGE_HWEXEC)
 
 #if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH) ||\
@@ -552,9 +556,6 @@
 static inline int pte_file(pte_t pte)		{ return pte_val(pte) & _PAGE_FILE; }
 static inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
 
-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_wrprotect(pte_t pte) {
 	pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
 static inline pte_t pte_mkclean(pte_t pte) {
@@ -693,10 +694,11 @@
 #endif
 }
 
+
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 			      pte_t *ptep, pte_t pte)
 {
-#if defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP)
+#if defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP) && defined(CONFIG_DEBUG_VM)
 	WARN_ON(pte_present(*ptep));
 #endif
 	__set_pte_at(mm, addr, ptep, pte);
@@ -760,16 +762,6 @@
 	__changed;							   \
 })
 
-/*
- * Macro to mark a page protection value as "uncacheable".
- */
-#define pgprot_noncached(prot)	(__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
-
-struct file;
-extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
-				     unsigned long size, pgprot_t vma_prot);
-#define __HAVE_PHYS_MEM_ACCESS_PROT
-
 #define __HAVE_ARCH_PTE_SAME
 #define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)
 
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index 4c0a8c6..b0f18be 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -100,7 +100,7 @@
 
 #define _PAGE_WRENABLE	(_PAGE_RW | _PAGE_DIRTY)
 
-/* __pgprot defined in arch/powerpc/incliude/asm/page.h */
+/* __pgprot defined in arch/powerpc/include/asm/page.h */
 #define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
 
 #define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER)
@@ -245,9 +245,6 @@
 static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
 static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; }
 
-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_wrprotect(pte_t pte) {
 	pte_val(pte) &= ~(_PAGE_RW); return pte; }
 static inline pte_t pte_mkclean(pte_t pte) {
@@ -405,16 +402,6 @@
 	__changed;							   \
 })
 
-/*
- * Macro to mark a page protection value as "uncacheable".
- */
-#define pgprot_noncached(prot)	(__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
-
-struct file;
-extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
-				     unsigned long size, pgprot_t vma_prot);
-#define __HAVE_PHYS_MEM_ACCESS_PROT
-
 #define __HAVE_ARCH_PTE_SAME
 #define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
 
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index dbb8ca1..07f55e6 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -16,6 +16,32 @@
 #endif
 
 #ifndef __ASSEMBLY__
+
+/*
+ * Macro to mark a page protection value as "uncacheable".
+ */
+
+#define _PAGE_CACHE_CTL	(_PAGE_COHERENT | _PAGE_GUARDED | _PAGE_NO_CACHE | \
+			 _PAGE_WRITETHRU)
+
+#define pgprot_noncached(prot)	  (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+				            _PAGE_NO_CACHE | _PAGE_GUARDED))
+
+#define pgprot_noncached_wc(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+				            _PAGE_NO_CACHE))
+
+#define pgprot_cached(prot)       (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+				            _PAGE_COHERENT))
+
+#define pgprot_cached_wthru(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+				            _PAGE_COHERENT | _PAGE_WRITETHRU))
+
+
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+				     unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index c4a029c..1a0d628 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -425,14 +425,14 @@
 #define fromreal(rd)	tovirt(rd,rd)
 
 #define tophys(rd,rs)				\
-0:	addis	rd,rs,-KERNELBASE@h;		\
+0:	addis	rd,rs,-PAGE_OFFSET@h;		\
 	.section ".vtop_fixup","aw";		\
 	.align  1;				\
 	.long   0b;				\
 	.previous
 
 #define tovirt(rd,rs)				\
-0:	addis	rd,rs,KERNELBASE@h;		\
+0:	addis	rd,rs,PAGE_OFFSET@h;		\
 	.section ".ptov_fixup","aw";		\
 	.align  1;				\
 	.long   0b;				\
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 101ed87..d346649 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -69,8 +69,6 @@
 
 #ifdef __KERNEL__
 
-extern int have_of;
-
 struct task_struct;
 void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp);
 void release_thread(struct task_struct *);
@@ -207,6 +205,11 @@
 #define INIT_SP_LIMIT \
 	(_ALIGN_UP(sizeof(init_thread_info), 16) + (unsigned long) &init_stack)
 
+#ifdef CONFIG_SPE
+#define SPEFSCR_INIT .spefscr = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE,
+#else
+#define SPEFSCR_INIT
+#endif
 
 #ifdef CONFIG_PPC32
 #define INIT_THREAD { \
@@ -215,6 +218,7 @@
 	.fs = KERNEL_DS, \
 	.pgdir = swapper_pg_dir, \
 	.fpexc_mode = MSR_FE0 | MSR_FE1, \
+	SPEFSCR_INIT \
 }
 #else
 #define INIT_THREAD  { \
diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
index eb3bd2e..6ff0418 100644
--- a/arch/powerpc/include/asm/prom.h
+++ b/arch/powerpc/include/asm/prom.h
@@ -253,6 +253,9 @@
 /* CPU OF node matching */
 struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
 
+/* cache lookup */
+struct device_node *of_find_next_cache_node(struct device_node *np);
+
 /* Get the MAC address */
 extern const void *of_get_mac_address(struct device_node *np);
 
diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h
index f9e34c4..cff30c0 100644
--- a/arch/powerpc/include/asm/ps3.h
+++ b/arch/powerpc/include/asm/ps3.h
@@ -305,30 +305,34 @@
 /* system bus routines */
 
 enum ps3_match_id {
-	PS3_MATCH_ID_EHCI           = 1,
-	PS3_MATCH_ID_OHCI           = 2,
-	PS3_MATCH_ID_GELIC          = 3,
-	PS3_MATCH_ID_AV_SETTINGS    = 4,
-	PS3_MATCH_ID_SYSTEM_MANAGER = 5,
-	PS3_MATCH_ID_STOR_DISK      = 6,
-	PS3_MATCH_ID_STOR_ROM       = 7,
-	PS3_MATCH_ID_STOR_FLASH     = 8,
-	PS3_MATCH_ID_SOUND          = 9,
-	PS3_MATCH_ID_GRAPHICS       = 10,
-	PS3_MATCH_ID_LPM            = 11,
+	PS3_MATCH_ID_EHCI		= 1,
+	PS3_MATCH_ID_OHCI		= 2,
+	PS3_MATCH_ID_GELIC		= 3,
+	PS3_MATCH_ID_AV_SETTINGS	= 4,
+	PS3_MATCH_ID_SYSTEM_MANAGER	= 5,
+	PS3_MATCH_ID_STOR_DISK		= 6,
+	PS3_MATCH_ID_STOR_ROM		= 7,
+	PS3_MATCH_ID_STOR_FLASH		= 8,
+	PS3_MATCH_ID_SOUND		= 9,
+	PS3_MATCH_ID_GPU		= 10,
+	PS3_MATCH_ID_LPM		= 11,
 };
 
-#define PS3_MODULE_ALIAS_EHCI           "ps3:1"
-#define PS3_MODULE_ALIAS_OHCI           "ps3:2"
-#define PS3_MODULE_ALIAS_GELIC          "ps3:3"
-#define PS3_MODULE_ALIAS_AV_SETTINGS    "ps3:4"
-#define PS3_MODULE_ALIAS_SYSTEM_MANAGER "ps3:5"
-#define PS3_MODULE_ALIAS_STOR_DISK      "ps3:6"
-#define PS3_MODULE_ALIAS_STOR_ROM       "ps3:7"
-#define PS3_MODULE_ALIAS_STOR_FLASH     "ps3:8"
-#define PS3_MODULE_ALIAS_SOUND          "ps3:9"
-#define PS3_MODULE_ALIAS_GRAPHICS       "ps3:10"
-#define PS3_MODULE_ALIAS_LPM            "ps3:11"
+enum ps3_match_sub_id {
+	PS3_MATCH_SUB_ID_GPU_FB		= 1,
+};
+
+#define PS3_MODULE_ALIAS_EHCI		"ps3:1:0"
+#define PS3_MODULE_ALIAS_OHCI		"ps3:2:0"
+#define PS3_MODULE_ALIAS_GELIC		"ps3:3:0"
+#define PS3_MODULE_ALIAS_AV_SETTINGS	"ps3:4:0"
+#define PS3_MODULE_ALIAS_SYSTEM_MANAGER	"ps3:5:0"
+#define PS3_MODULE_ALIAS_STOR_DISK	"ps3:6:0"
+#define PS3_MODULE_ALIAS_STOR_ROM	"ps3:7:0"
+#define PS3_MODULE_ALIAS_STOR_FLASH	"ps3:8:0"
+#define PS3_MODULE_ALIAS_SOUND		"ps3:9:0"
+#define PS3_MODULE_ALIAS_GPU_FB		"ps3:10:1"
+#define PS3_MODULE_ALIAS_LPM		"ps3:11:0"
 
 enum ps3_system_bus_device_type {
 	PS3_DEVICE_TYPE_IOC0 = 1,
@@ -337,11 +341,6 @@
 	PS3_DEVICE_TYPE_LPM,
 };
 
-enum ps3_match_sub_id {
-	/* for PS3_MATCH_ID_GRAPHICS */
-	PS3_MATCH_SUB_ID_FB		= 1,
-};
-
 /**
  * struct ps3_system_bus_device - a device on the system bus
  */
@@ -516,4 +515,7 @@
 u32 ps3_get_hw_thread_id(int cpu);
 u64 ps3_get_spe_id(void *arg);
 
+/* mutex synchronizing GPU accesses and video mode changes */
+extern struct mutex ps3_gpu_mutex;
+
 #endif
diff --git a/arch/powerpc/include/asm/ps3av.h b/arch/powerpc/include/asm/ps3av.h
index 5aa22cf..cd24ac1 100644
--- a/arch/powerpc/include/asm/ps3av.h
+++ b/arch/powerpc/include/asm/ps3av.h
@@ -740,8 +740,4 @@
 extern int ps3av_audio_mute_analog(int);
 extern int ps3av_dev_open(void);
 extern int ps3av_dev_close(void);
-extern void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data),
-				    void *flip_data);
-extern void ps3av_flip_ctl(int on);
-
 #endif	/* _ASM_POWERPC_PS3AV_H_ */
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index c6d1ab6..f484a34 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -783,6 +783,10 @@
 #define __get_SP()	({unsigned long sp; \
 			asm volatile("mr %0,1": "=r" (sp)); sp;})
 
+struct pt_regs;
+
+extern void ppc_save_regs(struct pt_regs *regs);
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_REG_H */
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 8eaa7b2..e0175be 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -168,6 +168,7 @@
 extern int rtas_get_sensor(int sensor, int index, int *state);
 extern int rtas_get_power_level(int powerdomain, int *level);
 extern int rtas_set_power_level(int powerdomain, int level, int *setlevel);
+extern bool rtas_indicator_present(int token, int *maxindex);
 extern int rtas_set_indicator(int indicator, int index, int new_value);
 extern int rtas_set_indicator_fast(int indicator, int index, int new_value);
 extern void rtas_progress(char *s, unsigned short hex);
diff --git a/arch/powerpc/include/asm/sfp-machine.h b/arch/powerpc/include/asm/sfp-machine.h
index ced34f1..3d9f831 100644
--- a/arch/powerpc/include/asm/sfp-machine.h
+++ b/arch/powerpc/include/asm/sfp-machine.h
@@ -82,7 +82,7 @@
 #define _FP_MUL_MEAT_S(R,X,Y)   _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
 #define _FP_MUL_MEAT_D(R,X,Y)   _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
 
-#define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_udiv(S,R,X,Y)
+#define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_udiv_norm(S,R,X,Y)
 #define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_2_udiv(D,R,X,Y)
 
 /* These macros define what NaN looks like. They're supposed to expand to
@@ -97,6 +97,20 @@
 
 #define _FP_KEEPNANFRACP 1
 
+#ifdef FP_EX_BOOKE_E500_SPE
+#define FP_EX_INEXACT		(1 << 21)
+#define FP_EX_INVALID		(1 << 20)
+#define FP_EX_DIVZERO		(1 << 19)
+#define FP_EX_UNDERFLOW		(1 << 18)
+#define FP_EX_OVERFLOW		(1 << 17)
+#define FP_INHIBIT_RESULTS	0
+
+#define __FPU_FPSCR	(current->thread.spefscr)
+#define __FPU_ENABLED_EXC		\
+({					\
+	(__FPU_FPSCR >> 2) & 0x1f;	\
+})
+#else
 /* Exception flags.  We use the bit positions of the appropriate bits
    in the FPSCR, which also correspond to the FE_* bits.  This makes
    everything easier ;-).  */
@@ -111,22 +125,6 @@
 #define FP_EX_DIVZERO         (1 << (31 - 5))
 #define FP_EX_INEXACT         (1 << (31 - 6))
 
-/* This macro appears to be called when both X and Y are NaNs, and
- * has to choose one and copy it to R. i386 goes for the larger of the
- * two, sparc64 just picks Y. I don't understand this at all so I'll
- * go with sparc64 because it's shorter :->   -- PMM
- */
-#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)		\
-  do {							\
-    R##_s = Y##_s;					\
-    _FP_FRAC_COPY_##wc(R,Y);				\
-    R##_c = FP_CLS_NAN;					\
-  } while (0)
-
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
 #define __FPU_FPSCR	(current->thread.fpscr.val)
 
 /* We only actually write to the destination register
@@ -137,6 +135,32 @@
 	(__FPU_FPSCR >> 3) & 0x1f;	\
 })
 
+#endif
+
+/*
+ * If one NaN is signaling and the other is not,
+ * we choose that one, otherwise we choose X.
+ */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
+  do {								\
+    if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)		\
+	&& !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))	\
+      {								\
+	R##_s = X##_s;						\
+	_FP_FRAC_COPY_##wc(R,X);				\
+      }								\
+    else							\
+      {								\
+	R##_s = Y##_s;						\
+	_FP_FRAC_COPY_##wc(R,Y);				\
+      }								\
+    R##_c = FP_CLS_NAN;						\
+  } while (0)
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
 #define __FPU_TRAP_P(bits) \
 	((__FPU_ENABLED_EXC & (bits)) != 0)
 
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 1866cec..c25f73d 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -81,6 +81,13 @@
 #define PPC_MSG_CALL_FUNC_SINGLE	2
 #define PPC_MSG_DEBUGGER_BREAK  3
 
+/*
+ * irq controllers that have dedicated ipis per message and don't
+ * need additional code in the action handler may use this
+ */
+extern int smp_request_message_ipi(int virq, int message);
+extern const char *smp_ipi_name[];
+
 void smp_init_iSeries(void);
 void smp_init_pSeries(void);
 void smp_init_cell(void);
diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h
index f56a843..3686436 100644
--- a/arch/powerpc/include/asm/spinlock.h
+++ b/arch/powerpc/include/asm/spinlock.h
@@ -277,7 +277,7 @@
 	bne-		1b"
 	: "=&r"(tmp)
 	: "r"(&rw->lock)
-	: "cr0", "memory");
+	: "cr0", "xer", "memory");
 }
 
 static inline void __raw_write_unlock(raw_rwlock_t *rw)
diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h
index 45963e8..28f6ddb 100644
--- a/arch/powerpc/include/asm/synch.h
+++ b/arch/powerpc/include/asm/synch.h
@@ -5,6 +5,10 @@
 #include <linux/stringify.h>
 #include <asm/feature-fixups.h>
 
+#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC)
+#define __SUBARCH_HAS_LWSYNC
+#endif
+
 #ifndef __ASSEMBLY__
 extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup;
 extern void do_lwsync_fixups(unsigned long value, void *fixup_start,
diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h
index d6648c1..2a4be19 100644
--- a/arch/powerpc/include/asm/system.h
+++ b/arch/powerpc/include/asm/system.h
@@ -23,15 +23,17 @@
  * read_barrier_depends() prevents data-dependent loads being reordered
  *	across this point (nop on PPC).
  *
- * We have to use the sync instructions for mb(), since lwsync doesn't
- * order loads with respect to previous stores.  Lwsync is fine for
- * rmb(), though. Note that rmb() actually uses a sync on 32-bit
- * architectures.
+ * *mb() variants without smp_ prefix must order all types of memory
+ * operations with one another. sync is the only instruction sufficient
+ * to do this.
  *
- * For wmb(), we use sync since wmb is used in drivers to order
- * stores to system memory with respect to writes to the device.
- * However, smp_wmb() can be a lighter-weight lwsync or eieio barrier
- * on SMP since it is only used to order updates to system memory.
+ * For the smp_ barriers, ordering is for cacheable memory operations
+ * only. We have to use the sync instruction for smp_mb(), since lwsync
+ * doesn't order loads with respect to previous stores.  Lwsync can be
+ * used for smp_rmb() and smp_wmb().
+ *
+ * However, on CPUs that don't support lwsync, lwsync actually maps to a
+ * heavy-weight sync, so smp_wmb() can be a lighter-weight eieio.
  */
 #define mb()   __asm__ __volatile__ ("sync" : : : "memory")
 #define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
@@ -45,14 +47,14 @@
 #ifdef CONFIG_SMP
 
 #ifdef __SUBARCH_HAS_LWSYNC
-#    define SMPWMB      lwsync
+#    define SMPWMB      LWSYNC
 #else
 #    define SMPWMB      eieio
 #endif
 
 #define smp_mb()	mb()
-#define smp_rmb()	rmb()
-#define smp_wmb()	__asm__ __volatile__ (__stringify(SMPWMB) : : :"memory")
+#define smp_rmb()	__asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory")
+#define smp_wmb()	__asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
 #define smp_read_barrier_depends()	read_barrier_depends()
 #else
 #define smp_mb()	barrier()
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index febd581..27ccb76 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -48,26 +48,6 @@
 extern unsigned long ppc_tb_freq;
 #define DEFAULT_TB_FREQ		125000000UL
 
-/*
- * By putting all of this stuff into a single struct we 
- * reduce the number of cache lines touched by do_gettimeofday.
- * Both by collecting all of the data in one cache line and
- * by touching only one TOC entry on ppc64.
- */
-struct gettimeofday_vars {
-	u64 tb_to_xs;
-	u64 stamp_xsec;
-	u64 tb_orig_stamp;
-};
-
-struct gettimeofday_struct {
-	unsigned long tb_ticks_per_sec;
-	struct gettimeofday_vars vars[2];
-	struct gettimeofday_vars * volatile varp;
-	unsigned      var_idx;
-	unsigned      tb_to_us;
-};
-
 struct div_result {
 	u64 result_high;
 	u64 result_low;
diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h
index a2c6bfd..abbe341 100644
--- a/arch/powerpc/include/asm/tlbflush.h
+++ b/arch/powerpc/include/asm/tlbflush.h
@@ -6,6 +6,9 @@
  *
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - local_flush_tlb_mm(mm) flushes the specified mm context on
+ *                           the local processor
+ *  - local_flush_tlb_page(vma, vmaddr) flushes one page on the local processor
  *  - flush_tlb_page_nohash(vma, vmaddr) flushes one page if SW loaded TLB
  *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *  - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
@@ -17,7 +20,7 @@
  */
 #ifdef __KERNEL__
 
-#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE)
+#ifdef CONFIG_PPC_MMU_NOHASH
 /*
  * TLB flushing for software loaded TLB chips
  *
@@ -28,63 +31,49 @@
 
 #include <linux/mm.h>
 
-extern void _tlbie(unsigned long address, unsigned int pid);
-extern void _tlbil_all(void);
-extern void _tlbil_pid(unsigned int pid);
-extern void _tlbil_va(unsigned long address, unsigned int pid);
+#define MMU_NO_CONTEXT      	((unsigned int)-1)
 
-#if defined(CONFIG_40x) || defined(CONFIG_8xx)
-#define _tlbia()	asm volatile ("tlbia; sync" : : : "memory")
-#else /* CONFIG_44x || CONFIG_FSL_BOOKE */
-extern void _tlbia(void);
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+			    unsigned long end);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+
+extern void local_flush_tlb_mm(struct mm_struct *mm);
+extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+
+#ifdef CONFIG_SMP
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+#else
+#define flush_tlb_mm(mm)		local_flush_tlb_mm(mm)
+#define flush_tlb_page(vma,addr)	local_flush_tlb_page(vma,addr)
 #endif
+#define flush_tlb_page_nohash(vma,addr)	flush_tlb_page(vma,addr)
 
-static inline void flush_tlb_mm(struct mm_struct *mm)
-{
-	_tlbil_pid(mm->context.id);
-}
+#elif defined(CONFIG_PPC_STD_MMU_32)
 
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-				  unsigned long vmaddr)
-{
-	_tlbil_va(vmaddr, vma ? vma->vm_mm->context.id : 0);
-}
-
-static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
-					 unsigned long vmaddr)
-{
-	flush_tlb_page(vma, vmaddr);
-}
-
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-				   unsigned long start, unsigned long end)
-{
-	_tlbil_pid(vma->vm_mm->context.id);
-}
-
-static inline void flush_tlb_kernel_range(unsigned long start,
-					  unsigned long end)
-{
-	_tlbil_pid(0);
-}
-
-#elif defined(CONFIG_PPC32)
 /*
- * TLB flushing for "classic" hash-MMMU 32-bit CPUs, 6xx, 7xx, 7xxx
+ * TLB flushing for "classic" hash-MMU 32-bit CPUs, 6xx, 7xx, 7xxx
  */
-extern void _tlbie(unsigned long address);
-extern void _tlbia(void);
-
 extern void flush_tlb_mm(struct mm_struct *mm);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
 extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr);
 extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			    unsigned long end);
 extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+static inline void local_flush_tlb_page(struct vm_area_struct *vma,
+					unsigned long vmaddr)
+{
+	flush_tlb_page(vma, vmaddr);
+}
+static inline void local_flush_tlb_mm(struct mm_struct *mm)
+{
+	flush_tlb_mm(mm);
+}
 
-#else
+#elif defined(CONFIG_PPC_STD_MMU_64)
+
 /*
- * TLB flushing for 64-bit has-MMU CPUs
+ * TLB flushing for 64-bit hash-MMU CPUs
  */
 
 #include <linux/percpu.h>
@@ -134,10 +123,19 @@
 extern void flush_hash_range(unsigned long number, int local);
 
 
+static inline void local_flush_tlb_mm(struct mm_struct *mm)
+{
+}
+
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
 }
 
+static inline void local_flush_tlb_page(struct vm_area_struct *vma,
+					unsigned long vmaddr)
+{
+}
+
 static inline void flush_tlb_page(struct vm_area_struct *vma,
 				  unsigned long vmaddr)
 {
@@ -162,7 +160,8 @@
 extern void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
 				     unsigned long end);
 
-
+#else
+#error Unsupported MMU type
 #endif
 
 #endif /*__KERNEL__ */
diff --git a/arch/powerpc/include/asm/vdso_datapage.h b/arch/powerpc/include/asm/vdso_datapage.h
index f013932..13c2c28 100644
--- a/arch/powerpc/include/asm/vdso_datapage.h
+++ b/arch/powerpc/include/asm/vdso_datapage.h
@@ -39,6 +39,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/unistd.h>
+#include <linux/time.h>
 
 #define SYSCALL_MAP_SIZE      ((__NR_syscalls + 31) / 32)
 
@@ -83,6 +84,7 @@
 	__u32 icache_log_block_size;		/* L1 i-cache log block size */
 	__s32 wtom_clock_sec;			/* Wall to monotonic clock */
 	__s32 wtom_clock_nsec;
+	struct timespec stamp_xtime;	/* xtime as at tb_orig_stamp */
    	__u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls  */
    	__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
 };
@@ -102,6 +104,7 @@
 	__u32 tz_dsttime;		/* Type of dst correction	0x5C */
 	__s32 wtom_clock_sec;			/* Wall to monotonic clock */
 	__s32 wtom_clock_nsec;
+	struct timespec stamp_xtime;	/* xtime as at tb_orig_stamp */
    	__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
 	__u32 dcache_block_size;	/* L1 d-cache block size     */
 	__u32 icache_block_size;	/* L1 i-cache block size     */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 92673b4..1308a86 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -17,6 +17,7 @@
 CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog
 CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog
 CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog
+CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog
 
 ifdef CONFIG_DYNAMIC_FTRACE
 # dynamic ftrace setup.
@@ -102,6 +103,10 @@
 
 obj-$(CONFIG_PPC64)		+= $(obj64-y)
 
+ifneq ($(CONFIG_XMON)$(CONFIG_KEXEC),)
+obj-y				+= ppc_save_regs.o
+endif
+
 extra-$(CONFIG_PPC_FPU)		+= fpu.o
 extra-$(CONFIG_PPC64)		+= entry_64.o
 
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 75c5dd0..661d07d 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -60,6 +60,7 @@
 {
 	DEFINE(THREAD, offsetof(struct task_struct, thread));
 	DEFINE(MM, offsetof(struct task_struct, mm));
+	DEFINE(MMCONTEXTID, offsetof(struct mm_struct, context.id));
 #ifdef CONFIG_PPC64
 	DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context));
 #else
@@ -306,6 +307,7 @@
 	DEFINE(CFG_SYSCALL_MAP32, offsetof(struct vdso_data, syscall_map_32));
 	DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec));
 	DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
+	DEFINE(STAMP_XTIME, offsetof(struct vdso_data, stamp_xtime));
 	DEFINE(CFG_ICACHE_BLOCKSZ, offsetof(struct vdso_data, icache_block_size));
 	DEFINE(CFG_DCACHE_BLOCKSZ, offsetof(struct vdso_data, dcache_block_size));
 	DEFINE(CFG_ICACHE_LOGBLOCKSZ, offsetof(struct vdso_data, icache_log_block_size));
@@ -378,6 +380,10 @@
 	DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
 	DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
 #endif
+#ifdef CONFIG_44x
+	DEFINE(PGD_T_LOG2, PGD_T_LOG2);
+	DEFINE(PTE_T_LOG2, PTE_T_LOG2);
+#endif
 
 	return 0;
 }
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 7e87195..923f87a 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -19,6 +19,7 @@
 #include <asm/oprofile_impl.h>
 #include <asm/cputable.h>
 #include <asm/prom.h>		/* for PTRRELOC on ARCH=ppc */
+#include <asm/mmu.h>
 
 struct cpu_spec* cur_cpu_spec = NULL;
 EXPORT_SYMBOL(cur_cpu_spec);
@@ -94,6 +95,7 @@
 		.cpu_name		= "POWER3 (630)",
 		.cpu_features		= CPU_FTRS_POWER3,
 		.cpu_user_features	= COMMON_USER_PPC64|PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -109,6 +111,7 @@
 		.cpu_name		= "POWER3 (630+)",
 		.cpu_features		= CPU_FTRS_POWER3,
 		.cpu_user_features	= COMMON_USER_PPC64|PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -124,6 +127,7 @@
 		.cpu_name		= "RS64-II (northstar)",
 		.cpu_features		= CPU_FTRS_RS64,
 		.cpu_user_features	= COMMON_USER_PPC64,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -139,6 +143,7 @@
 		.cpu_name		= "RS64-III (pulsar)",
 		.cpu_features		= CPU_FTRS_RS64,
 		.cpu_user_features	= COMMON_USER_PPC64,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -154,6 +159,7 @@
 		.cpu_name		= "RS64-III (icestar)",
 		.cpu_features		= CPU_FTRS_RS64,
 		.cpu_user_features	= COMMON_USER_PPC64,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -169,6 +175,7 @@
 		.cpu_name		= "RS64-IV (sstar)",
 		.cpu_features		= CPU_FTRS_RS64,
 		.cpu_user_features	= COMMON_USER_PPC64,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -184,6 +191,7 @@
 		.cpu_name		= "POWER4 (gp)",
 		.cpu_features		= CPU_FTRS_POWER4,
 		.cpu_user_features	= COMMON_USER_POWER4,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -199,6 +207,7 @@
 		.cpu_name		= "POWER4+ (gq)",
 		.cpu_features		= CPU_FTRS_POWER4,
 		.cpu_user_features	= COMMON_USER_POWER4,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -215,6 +224,7 @@
 		.cpu_features		= CPU_FTRS_PPC970,
 		.cpu_user_features	= COMMON_USER_POWER4 |
 			PPC_FEATURE_HAS_ALTIVEC_COMP,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -233,6 +243,7 @@
 		.cpu_features		= CPU_FTRS_PPC970,
 		.cpu_user_features	= COMMON_USER_POWER4 |
 			PPC_FEATURE_HAS_ALTIVEC_COMP,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -251,6 +262,7 @@
 		.cpu_features		= CPU_FTRS_PPC970,
 		.cpu_user_features	= COMMON_USER_POWER4 |
 			PPC_FEATURE_HAS_ALTIVEC_COMP,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -269,6 +281,7 @@
 		.cpu_features		= CPU_FTRS_PPC970,
 		.cpu_user_features	= COMMON_USER_POWER4 |
 			PPC_FEATURE_HAS_ALTIVEC_COMP,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -287,6 +300,7 @@
 		.cpu_features		= CPU_FTRS_PPC970,
 		.cpu_user_features	= COMMON_USER_POWER4 |
 			PPC_FEATURE_HAS_ALTIVEC_COMP,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 8,
@@ -303,6 +317,7 @@
 		.cpu_name		= "POWER5 (gr)",
 		.cpu_features		= CPU_FTRS_POWER5,
 		.cpu_user_features	= COMMON_USER_POWER5,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
@@ -323,6 +338,7 @@
 		.cpu_name		= "POWER5+ (gs)",
 		.cpu_features		= CPU_FTRS_POWER5,
 		.cpu_user_features	= COMMON_USER_POWER5_PLUS,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
@@ -339,6 +355,7 @@
 		.cpu_name		= "POWER5+ (gs)",
 		.cpu_features		= CPU_FTRS_POWER5,
 		.cpu_user_features	= COMMON_USER_POWER5_PLUS,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
@@ -356,6 +373,7 @@
 		.cpu_name		= "POWER5+",
 		.cpu_features		= CPU_FTRS_POWER5,
 		.cpu_user_features	= COMMON_USER_POWER5_PLUS,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.machine_check		= machine_check_generic,
@@ -369,6 +387,7 @@
 		.cpu_features		= CPU_FTRS_POWER6,
 		.cpu_user_features	= COMMON_USER_POWER6 |
 			PPC_FEATURE_POWER6_EXT,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
@@ -388,6 +407,7 @@
 		.cpu_name		= "POWER6 (architected)",
 		.cpu_features		= CPU_FTRS_POWER6,
 		.cpu_user_features	= COMMON_USER_POWER6,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.machine_check		= machine_check_generic,
@@ -400,6 +420,7 @@
 		.cpu_name		= "POWER7 (architected)",
 		.cpu_features		= CPU_FTRS_POWER7,
 		.cpu_user_features	= COMMON_USER_POWER7,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.machine_check		= machine_check_generic,
@@ -412,6 +433,7 @@
 		.cpu_name		= "POWER7 (raw)",
 		.cpu_features		= CPU_FTRS_POWER7,
 		.cpu_user_features	= COMMON_USER_POWER7,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
@@ -434,6 +456,7 @@
 		.cpu_user_features	= COMMON_USER_PPC64 |
 			PPC_FEATURE_CELL | PPC_FEATURE_HAS_ALTIVEC_COMP |
 			PPC_FEATURE_SMT,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 4,
@@ -449,6 +472,7 @@
 		.cpu_name		= "PA6T",
 		.cpu_features		= CPU_FTRS_PA6T,
 		.cpu_user_features	= COMMON_USER_PA6T,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 64,
 		.dcache_bsize		= 64,
 		.num_pmcs		= 6,
@@ -466,6 +490,7 @@
 		.cpu_name		= "POWER4 (compatible)",
 		.cpu_features		= CPU_FTRS_COMPATIBLE,
 		.cpu_user_features	= COMMON_USER_PPC64,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
@@ -483,6 +508,7 @@
 		.cpu_features		= CPU_FTRS_PPC601,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_601_INSTR |
 			PPC_FEATURE_UNIFIED_CACHE | PPC_FEATURE_NO_TB,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_generic,
@@ -494,6 +520,7 @@
 		.cpu_name		= "603",
 		.cpu_features		= CPU_FTRS_603,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= 0,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -506,6 +533,7 @@
 		.cpu_name		= "603e",
 		.cpu_features		= CPU_FTRS_603,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= 0,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -518,6 +546,7 @@
 		.cpu_name		= "603ev",
 		.cpu_features		= CPU_FTRS_603,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= 0,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -530,6 +559,7 @@
 		.cpu_name		= "604",
 		.cpu_features		= CPU_FTRS_604,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 2,
@@ -543,6 +573,7 @@
 		.cpu_name		= "604e",
 		.cpu_features		= CPU_FTRS_604,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -556,6 +587,7 @@
 		.cpu_name		= "604r",
 		.cpu_features		= CPU_FTRS_604,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -569,6 +601,7 @@
 		.cpu_name		= "604ev",
 		.cpu_features		= CPU_FTRS_604,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -582,6 +615,7 @@
 		.cpu_name		= "740/750",
 		.cpu_features		= CPU_FTRS_740_NOTAU,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -595,6 +629,7 @@
 		.cpu_name		= "750CX",
 		.cpu_features		= CPU_FTRS_750,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -608,6 +643,7 @@
 		.cpu_name		= "750CX",
 		.cpu_features		= CPU_FTRS_750,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -622,6 +658,7 @@
 		.cpu_name		= "750CXe",
 		.cpu_features		= CPU_FTRS_750,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -636,6 +673,7 @@
 		.cpu_name		= "750CXe",
 		.cpu_features		= CPU_FTRS_750,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -650,6 +688,7 @@
 		.cpu_name		= "750CL",
 		.cpu_features		= CPU_FTRS_750CL,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -664,6 +703,7 @@
 		.cpu_name		= "745/755",
 		.cpu_features		= CPU_FTRS_750,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -678,6 +718,7 @@
 		.cpu_name		= "750FX",
 		.cpu_features		= CPU_FTRS_750FX1,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -692,6 +733,7 @@
 		.cpu_name		= "750FX",
 		.cpu_features		= CPU_FTRS_750FX2,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -706,6 +748,7 @@
 		.cpu_name		= "750FX",
 		.cpu_features		= CPU_FTRS_750FX,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -720,6 +763,7 @@
 		.cpu_name		= "750GX",
 		.cpu_features		= CPU_FTRS_750GX,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -734,6 +778,7 @@
 		.cpu_name		= "740/750",
 		.cpu_features		= CPU_FTRS_740,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -749,6 +794,7 @@
 		.cpu_features		= CPU_FTRS_7400_NOTAU,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -764,6 +810,7 @@
 		.cpu_features		= CPU_FTRS_7400,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -779,6 +826,7 @@
 		.cpu_features		= CPU_FTRS_7400,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -794,6 +842,7 @@
 		.cpu_features		= CPU_FTRS_7450_20,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -811,6 +860,7 @@
 		.cpu_features		= CPU_FTRS_7450_21,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -828,6 +878,7 @@
 		.cpu_features		= CPU_FTRS_7450_23,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -845,6 +896,7 @@
 		.cpu_features		= CPU_FTRS_7455_1,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -862,6 +914,7 @@
 		.cpu_features		= CPU_FTRS_7455_20,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -879,6 +932,7 @@
 		.cpu_features		= CPU_FTRS_7455,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -896,6 +950,7 @@
 		.cpu_features		= CPU_FTRS_7447_10,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -913,6 +968,7 @@
 		.cpu_features		= CPU_FTRS_7447_10,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -929,6 +985,7 @@
 		.cpu_name		= "7447/7457",
 		.cpu_features		= CPU_FTRS_7447,
 		.cpu_user_features	= COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -946,6 +1003,7 @@
 		.cpu_features		= CPU_FTRS_7447A,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -963,6 +1021,7 @@
 		.cpu_features		= CPU_FTRS_7448,
 		.cpu_user_features	= COMMON_USER |
 			PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE,
+		.mmu_features		= MMU_FTR_HPTE_TABLE | MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 6,
@@ -979,6 +1038,7 @@
 		.cpu_name		= "82xx",
 		.cpu_features		= CPU_FTRS_82XX,
 		.cpu_user_features	= COMMON_USER,
+		.mmu_features		= 0,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -991,6 +1051,7 @@
 		.cpu_name		= "G2_LE",
 		.cpu_features		= CPU_FTRS_G2_LE,
 		.cpu_user_features	= COMMON_USER,
+		.mmu_features		= MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -1003,6 +1064,7 @@
 		.cpu_name		= "e300c1",
 		.cpu_features		= CPU_FTRS_E300,
 		.cpu_user_features	= COMMON_USER,
+		.mmu_features		= MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -1015,6 +1077,7 @@
 		.cpu_name		= "e300c2",
 		.cpu_features		= CPU_FTRS_E300C2,
 		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.mmu_features		= MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -1027,6 +1090,7 @@
 		.cpu_name		= "e300c3",
 		.cpu_features		= CPU_FTRS_E300,
 		.cpu_user_features	= COMMON_USER,
+		.mmu_features		= MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -1041,6 +1105,7 @@
 		.cpu_name		= "e300c4",
 		.cpu_features		= CPU_FTRS_E300,
 		.cpu_user_features	= COMMON_USER,
+		.mmu_features		= MMU_FTR_USE_HIGH_BATS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_603,
@@ -1056,6 +1121,7 @@
 		.cpu_name		= "(generic PPC)",
 		.cpu_features		= CPU_FTRS_CLASSIC32,
 		.cpu_user_features	= COMMON_USER,
+		.mmu_features		= MMU_FTR_HPTE_TABLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_generic,
@@ -1071,6 +1137,7 @@
 		 * if the 8xx code is there.... */
 		.cpu_features		= CPU_FTRS_8XX,
 		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.mmu_features		= MMU_FTR_TYPE_8xx,
 		.icache_bsize		= 16,
 		.dcache_bsize		= 16,
 		.platform		= "ppc823",
@@ -1083,6 +1150,7 @@
 		.cpu_name		= "403GC",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 16,
 		.dcache_bsize		= 16,
 		.machine_check		= machine_check_4xx,
@@ -1095,6 +1163,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 		 	PPC_FEATURE_HAS_MMU | PPC_FEATURE_NO_TB,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 16,
 		.dcache_bsize		= 16,
 		.machine_check		= machine_check_4xx,
@@ -1106,6 +1175,7 @@
 		.cpu_name		= "403G ??",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 16,
 		.dcache_bsize		= 16,
 		.machine_check		= machine_check_4xx,
@@ -1118,6 +1188,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1130,6 +1201,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1142,6 +1214,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1154,6 +1227,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1166,6 +1240,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1178,6 +1253,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1190,6 +1266,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1202,6 +1279,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1213,6 +1291,7 @@
 		.cpu_name		= "405LP",
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1225,6 +1304,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1237,6 +1317,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1249,6 +1330,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1261,6 +1343,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1273,6 +1356,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1286,6 +1370,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1298,6 +1383,7 @@
 		.cpu_features		= CPU_FTRS_40X,
 		.cpu_user_features	= PPC_FEATURE_32 |
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+		.mmu_features		= MMU_FTR_TYPE_40x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1312,6 +1398,7 @@
 		.cpu_name		= "440GR Rev. A",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1323,6 +1410,7 @@
 		.cpu_name		= "440EP Rev. A",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_440ep,
@@ -1335,6 +1423,7 @@
 		.cpu_name		= "440GR Rev. B",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1346,6 +1435,7 @@
 		.cpu_name		= "440EP Rev. C",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_440ep,
@@ -1358,6 +1448,7 @@
 		.cpu_name		= "440EP Rev. B",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_440ep,
@@ -1370,6 +1461,7 @@
 		.cpu_name		= "440GRX",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_440grx,
@@ -1382,6 +1474,7 @@
 		.cpu_name		= "440EPX",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_440epx,
@@ -1394,6 +1487,7 @@
 		.cpu_name		= "440GP Rev. B",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1405,6 +1499,7 @@
 		.cpu_name		= "440GP Rev. C",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1416,6 +1511,7 @@
 		.cpu_name		= "440GX Rev. A",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_440gx,
@@ -1428,6 +1524,7 @@
 		.cpu_name		= "440GX Rev. B",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_440gx,
@@ -1440,6 +1537,7 @@
 		.cpu_name		= "440GX Rev. C",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_440gx,
@@ -1452,6 +1550,7 @@
 		.cpu_name		= "440GX Rev. F",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_440gx,
@@ -1464,6 +1563,7 @@
 		.cpu_name		= "440SP Rev. A",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1475,6 +1575,7 @@
 		.cpu_name               = "440SPe Rev. A",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features      = COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize           = 32,
 		.dcache_bsize           = 32,
 		.cpu_setup		= __setup_cpu_440spe,
@@ -1487,6 +1588,7 @@
 		.cpu_name		= "440SPe Rev. B",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_440spe,
@@ -1499,6 +1601,7 @@
 		.cpu_name		= "440 in Virtex-5 FXT",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_440x5,
@@ -1509,8 +1612,9 @@
 		.pvr_mask		= 0xffff0002,
 		.pvr_value		= 0x13020002,
 		.cpu_name		= "460EX",
-		.cpu_features		= CPU_FTRS_44X,
+		.cpu_features		= CPU_FTRS_440x6,
 		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_460ex,
@@ -1521,8 +1625,9 @@
 		.pvr_mask		= 0xffff0002,
 		.pvr_value		= 0x13020000,
 		.cpu_name		= "460GT",
-		.cpu_features		= CPU_FTRS_44X,
+		.cpu_features		= CPU_FTRS_440x6,
 		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.cpu_setup		= __setup_cpu_460gt,
@@ -1535,6 +1640,7 @@
 		.cpu_name		= "(generic 44x PPC)",
 		.cpu_features		= CPU_FTRS_44X,
 		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_44x,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_4xx,
@@ -1551,6 +1657,7 @@
 		.cpu_user_features	= COMMON_USER_BOOKE |
 			PPC_FEATURE_HAS_EFP_SINGLE |
 			PPC_FEATURE_UNIFIED_CACHE,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_e200,
 		.platform		= "ppc5554",
@@ -1565,6 +1672,7 @@
 			PPC_FEATURE_HAS_SPE_COMP |
 			PPC_FEATURE_HAS_EFP_SINGLE_COMP |
 			PPC_FEATURE_UNIFIED_CACHE,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_e200,
 		.platform		= "ppc5554",
@@ -1577,6 +1685,7 @@
 		.cpu_user_features	= COMMON_USER_BOOKE |
 			PPC_FEATURE_HAS_EFP_SINGLE |
 			PPC_FEATURE_UNIFIED_CACHE,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_e200,
 		.platform		= "ppc5554",
@@ -1591,6 +1700,7 @@
 		.cpu_user_features	= COMMON_USER_BOOKE |
 			PPC_FEATURE_HAS_SPE_COMP |
 			PPC_FEATURE_HAS_EFP_SINGLE_COMP,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -1608,6 +1718,7 @@
 			PPC_FEATURE_HAS_SPE_COMP |
 			PPC_FEATURE_HAS_EFP_SINGLE_COMP |
 			PPC_FEATURE_HAS_EFP_DOUBLE_COMP,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
@@ -1622,6 +1733,7 @@
 		.cpu_name		= "e500mc",
 		.cpu_features		= CPU_FTRS_E500MC,
 		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS,
 		.icache_bsize		= 64,
 		.dcache_bsize		= 64,
 		.num_pmcs		= 4,
@@ -1638,6 +1750,7 @@
 		.cpu_user_features	= COMMON_USER_BOOKE |
 			PPC_FEATURE_HAS_SPE_COMP |
 			PPC_FEATURE_HAS_EFP_SINGLE_COMP,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.machine_check		= machine_check_e500,
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index 3a6eaa8..1c5c8a6 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -120,6 +120,26 @@
 {
 }
 
+#ifdef CONFIG_NOT_COHERENT_CACHE
+static inline void dma_direct_sync_sg(struct device *dev,
+		struct scatterlist *sgl, int nents,
+		enum dma_data_direction direction)
+{
+	struct scatterlist *sg;
+	int i;
+
+	for_each_sg(sgl, sg, nents, i)
+		__dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
+}
+
+static inline void dma_direct_sync_single_range(struct device *dev,
+		dma_addr_t dma_handle, unsigned long offset, size_t size,
+		enum dma_data_direction direction)
+{
+	__dma_sync(bus_to_virt(dma_handle+offset), size, direction);
+}
+#endif
+
 struct dma_mapping_ops dma_direct_ops = {
 	.alloc_coherent	= dma_direct_alloc_coherent,
 	.free_coherent	= dma_direct_free_coherent,
@@ -128,5 +148,11 @@
 	.dma_supported	= dma_direct_dma_supported,
 	.map_page	= dma_direct_map_page,
 	.unmap_page	= dma_direct_unmap_page,
+#ifdef CONFIG_NOT_COHERENT_CACHE
+	.sync_single_range_for_cpu 	= dma_direct_sync_single_range,
+	.sync_single_range_for_device 	= dma_direct_sync_single_range,
+	.sync_sg_for_cpu 		= dma_direct_sync_sg,
+	.sync_sg_for_device 		= dma_direct_sync_sg,
+#endif
 };
 EXPORT_SYMBOL(dma_direct_ops);
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 7ecc0d1..6f7eb7e 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -1162,39 +1162,17 @@
 #ifdef CONFIG_DYNAMIC_FTRACE
 _GLOBAL(mcount)
 _GLOBAL(_mcount)
-	stwu	r1,-48(r1)
-	stw	r3, 12(r1)
-	stw	r4, 16(r1)
-	stw	r5, 20(r1)
-	stw	r6, 24(r1)
-	mflr	r3
-	stw	r7, 28(r1)
-	mfcr	r5
-	stw	r8, 32(r1)
-	stw	r9, 36(r1)
-	stw	r10,40(r1)
-	stw	r3, 44(r1)
-	stw	r5, 8(r1)
-	subi	r3, r3, MCOUNT_INSN_SIZE
-	.globl mcount_call
-mcount_call:
-	bl	ftrace_stub
-	nop
-	lwz	r6, 8(r1)
-	lwz	r0, 44(r1)
-	lwz	r3, 12(r1)
+	/*
+	 * It is required that _mcount on PPC32 must preserve the
+	 * link register. But we have r0 to play with. We use r0
+	 * to push the return address back to the caller of mcount
+	 * into the ctr register, restore the link register and
+	 * then jump back using the ctr register.
+	 */
+	mflr	r0
 	mtctr	r0
-	lwz	r4, 16(r1)
-	mtcr	r6
-	lwz	r5, 20(r1)
-	lwz	r6, 24(r1)
-	lwz	r0, 52(r1)
-	lwz	r7, 28(r1)
-	lwz	r8, 32(r1)
+	lwz	r0, 4(r1)
 	mtlr	r0
-	lwz	r9, 36(r1)
-	lwz	r10,40(r1)
-	addi	r1, r1, 48
 	bctr
 
 _GLOBAL(ftrace_caller)
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index e0bcf93..383ed6e 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -894,18 +894,6 @@
 #ifdef CONFIG_DYNAMIC_FTRACE
 _GLOBAL(mcount)
 _GLOBAL(_mcount)
-	/* Taken from output of objdump from lib64/glibc */
-	mflr	r3
-	stdu	r1, -112(r1)
-	std	r3, 128(r1)
-	subi	r3, r3, MCOUNT_INSN_SIZE
-	.globl mcount_call
-mcount_call:
-	bl	ftrace_stub
-	nop
-	ld	r0, 128(r1)
-	mtlr	r0
-	addi	r1, r1, 112
 	blr
 
 _GLOBAL(ftrace_caller)
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index f4b006e..5355244 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -9,22 +9,30 @@
 
 #include <linux/spinlock.h>
 #include <linux/hardirq.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
 #include <linux/ftrace.h>
 #include <linux/percpu.h>
 #include <linux/init.h>
 #include <linux/list.h>
 
 #include <asm/cacheflush.h>
+#include <asm/code-patching.h>
 #include <asm/ftrace.h>
 
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt , ...)	do { } while (0)
+#endif
 
-static unsigned int ftrace_nop = 0x60000000;
+static unsigned int ftrace_nop = PPC_NOP_INSTR;
 
 #ifdef CONFIG_PPC32
 # define GET_ADDR(addr) addr
 #else
 /* PowerPC64's functions are data that points to the functions */
-# define GET_ADDR(addr) *(unsigned long *)addr
+# define GET_ADDR(addr) (*(unsigned long *)addr)
 #endif
 
 
@@ -33,12 +41,12 @@
 	return (int)(addr - ip);
 }
 
-unsigned char *ftrace_nop_replace(void)
+static unsigned char *ftrace_nop_replace(void)
 {
 	return (char *)&ftrace_nop;
 }
 
-unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
+static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
 {
 	static unsigned int op;
 
@@ -68,49 +76,422 @@
 # define _ASM_PTR	" .long "
 #endif
 
-int
+static int
 ftrace_modify_code(unsigned long ip, unsigned char *old_code,
 		   unsigned char *new_code)
 {
-	unsigned replaced;
-	unsigned old = *(unsigned *)old_code;
-	unsigned new = *(unsigned *)new_code;
-	int faulted = 0;
+	unsigned char replaced[MCOUNT_INSN_SIZE];
 
 	/*
 	 * Note: Due to modules and __init, code can
 	 *  disappear and change, we need to protect against faulting
-	 *  as well as code changing.
+	 *  as well as code changing. We do this by using the
+	 *  probe_kernel_* functions.
 	 *
 	 * No real locking needed, this code is run through
-	 * kstop_machine.
+	 * kstop_machine, or before SMP starts.
 	 */
-	asm volatile (
-		"1: lwz		%1, 0(%2)\n"
-		"   cmpw	%1, %5\n"
-		"   bne		2f\n"
-		"   stwu	%3, 0(%2)\n"
-		"2:\n"
-		".section .fixup, \"ax\"\n"
-		"3:	li %0, 1\n"
-		"	b 2b\n"
-		".previous\n"
-		".section __ex_table,\"a\"\n"
-		_ASM_ALIGN "\n"
-		_ASM_PTR "1b, 3b\n"
-		".previous"
-		: "=r"(faulted), "=r"(replaced)
-		: "r"(ip), "r"(new),
-		  "0"(faulted), "r"(old)
-		: "memory");
 
-	if (replaced != old && replaced != new)
-		faulted = 2;
+	/* read the text we want to modify */
+	if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
+		return -EFAULT;
 
-	if (!faulted)
-		flush_icache_range(ip, ip + 8);
+	/* Make sure it is what we expect it to be */
+	if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
+		return -EINVAL;
 
-	return faulted;
+	/* replace the text with the new text */
+	if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
+		return -EPERM;
+
+	flush_icache_range(ip, ip + 8);
+
+	return 0;
+}
+
+/*
+ * Helper functions that are the same for both PPC64 and PPC32.
+ */
+static int test_24bit_addr(unsigned long ip, unsigned long addr)
+{
+
+	/* use the create_branch to verify that this offset can be branched */
+	return create_branch((unsigned int *)ip, addr, 0);
+}
+
+static int is_bl_op(unsigned int op)
+{
+	return (op & 0xfc000003) == 0x48000001;
+}
+
+static unsigned long find_bl_target(unsigned long ip, unsigned int op)
+{
+	static int offset;
+
+	offset = (op & 0x03fffffc);
+	/* make it signed */
+	if (offset & 0x02000000)
+		offset |= 0xfe000000;
+
+	return ip + (long)offset;
+}
+
+#ifdef CONFIG_PPC64
+static int
+__ftrace_make_nop(struct module *mod,
+		  struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned int op;
+	unsigned int jmp[5];
+	unsigned long ptr;
+	unsigned long ip = rec->ip;
+	unsigned long tramp;
+	int offset;
+
+	/* read where this goes */
+	if (probe_kernel_read(&op, (void *)ip, sizeof(int)))
+		return -EFAULT;
+
+	/* Make sure that that this is still a 24bit jump */
+	if (!is_bl_op(op)) {
+		printk(KERN_ERR "Not expected bl: opcode is %x\n", op);
+		return -EINVAL;
+	}
+
+	/* lets find where the pointer goes */
+	tramp = find_bl_target(ip, op);
+
+	/*
+	 * On PPC64 the trampoline looks like:
+	 * 0x3d, 0x82, 0x00, 0x00,    addis   r12,r2, <high>
+	 * 0x39, 0x8c, 0x00, 0x00,    addi    r12,r12, <low>
+	 *   Where the bytes 2,3,6 and 7 make up the 32bit offset
+	 *   to the TOC that holds the pointer.
+	 *   to jump to.
+	 * 0xf8, 0x41, 0x00, 0x28,    std     r2,40(r1)
+	 * 0xe9, 0x6c, 0x00, 0x20,    ld      r11,32(r12)
+	 *   The actually address is 32 bytes from the offset
+	 *   into the TOC.
+	 * 0xe8, 0x4c, 0x00, 0x28,    ld      r2,40(r12)
+	 */
+
+	DEBUGP("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc);
+
+	/* Find where the trampoline jumps to */
+	if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
+		printk(KERN_ERR "Failed to read %lx\n", tramp);
+		return -EFAULT;
+	}
+
+	DEBUGP(" %08x %08x", jmp[0], jmp[1]);
+
+	/* verify that this is what we expect it to be */
+	if (((jmp[0] & 0xffff0000) != 0x3d820000) ||
+	    ((jmp[1] & 0xffff0000) != 0x398c0000) ||
+	    (jmp[2] != 0xf8410028) ||
+	    (jmp[3] != 0xe96c0020) ||
+	    (jmp[4] != 0xe84c0028)) {
+		printk(KERN_ERR "Not a trampoline\n");
+		return -EINVAL;
+	}
+
+	offset = (unsigned)((unsigned short)jmp[0]) << 16 |
+		(unsigned)((unsigned short)jmp[1]);
+
+	DEBUGP(" %x ", offset);
+
+	/* get the address this jumps too */
+	tramp = mod->arch.toc + offset + 32;
+	DEBUGP("toc: %lx", tramp);
+
+	if (probe_kernel_read(jmp, (void *)tramp, 8)) {
+		printk(KERN_ERR "Failed to read %lx\n", tramp);
+		return -EFAULT;
+	}
+
+	DEBUGP(" %08x %08x\n", jmp[0], jmp[1]);
+
+	ptr = ((unsigned long)jmp[0] << 32) + jmp[1];
+
+	/* This should match what was called */
+	if (ptr != GET_ADDR(addr)) {
+		printk(KERN_ERR "addr does not match %lx\n", ptr);
+		return -EINVAL;
+	}
+
+	/*
+	 * We want to nop the line, but the next line is
+	 *  0xe8, 0x41, 0x00, 0x28   ld r2,40(r1)
+	 * This needs to be turned to a nop too.
+	 */
+	if (probe_kernel_read(&op, (void *)(ip+4), MCOUNT_INSN_SIZE))
+		return -EFAULT;
+
+	if (op != 0xe8410028) {
+		printk(KERN_ERR "Next line is not ld! (%08x)\n", op);
+		return -EINVAL;
+	}
+
+	/*
+	 * Milton Miller pointed out that we can not blindly do nops.
+	 * If a task was preempted when calling a trace function,
+	 * the nops will remove the way to restore the TOC in r2
+	 * and the r2 TOC will get corrupted.
+	 */
+
+	/*
+	 * Replace:
+	 *   bl <tramp>  <==== will be replaced with "b 1f"
+	 *   ld r2,40(r1)
+	 *  1:
+	 */
+	op = 0x48000008;	/* b +8 */
+
+	if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))
+		return -EPERM;
+
+
+	flush_icache_range(ip, ip + 8);
+
+	return 0;
+}
+
+#else /* !PPC64 */
+static int
+__ftrace_make_nop(struct module *mod,
+		  struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned int op;
+	unsigned int jmp[4];
+	unsigned long ip = rec->ip;
+	unsigned long tramp;
+
+	if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
+		return -EFAULT;
+
+	/* Make sure that that this is still a 24bit jump */
+	if (!is_bl_op(op)) {
+		printk(KERN_ERR "Not expected bl: opcode is %x\n", op);
+		return -EINVAL;
+	}
+
+	/* lets find where the pointer goes */
+	tramp = find_bl_target(ip, op);
+
+	/*
+	 * On PPC32 the trampoline looks like:
+	 *  0x3d, 0x60, 0x00, 0x00  lis r11,sym@ha
+	 *  0x39, 0x6b, 0x00, 0x00  addi r11,r11,sym@l
+	 *  0x7d, 0x69, 0x03, 0xa6  mtctr r11
+	 *  0x4e, 0x80, 0x04, 0x20  bctr
+	 */
+
+	DEBUGP("ip:%lx jumps to %lx", ip, tramp);
+
+	/* Find where the trampoline jumps to */
+	if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
+		printk(KERN_ERR "Failed to read %lx\n", tramp);
+		return -EFAULT;
+	}
+
+	DEBUGP(" %08x %08x ", jmp[0], jmp[1]);
+
+	/* verify that this is what we expect it to be */
+	if (((jmp[0] & 0xffff0000) != 0x3d600000) ||
+	    ((jmp[1] & 0xffff0000) != 0x396b0000) ||
+	    (jmp[2] != 0x7d6903a6) ||
+	    (jmp[3] != 0x4e800420)) {
+		printk(KERN_ERR "Not a trampoline\n");
+		return -EINVAL;
+	}
+
+	tramp = (jmp[1] & 0xffff) |
+		((jmp[0] & 0xffff) << 16);
+	if (tramp & 0x8000)
+		tramp -= 0x10000;
+
+	DEBUGP(" %x ", tramp);
+
+	if (tramp != addr) {
+		printk(KERN_ERR
+		       "Trampoline location %08lx does not match addr\n",
+		       tramp);
+		return -EINVAL;
+	}
+
+	op = PPC_NOP_INSTR;
+
+	if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))
+		return -EPERM;
+
+	flush_icache_range(ip, ip + 8);
+
+	return 0;
+}
+#endif /* PPC64 */
+
+int ftrace_make_nop(struct module *mod,
+		    struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned char *old, *new;
+	unsigned long ip = rec->ip;
+
+	/*
+	 * If the calling address is more that 24 bits away,
+	 * then we had to use a trampoline to make the call.
+	 * Otherwise just update the call site.
+	 */
+	if (test_24bit_addr(ip, addr)) {
+		/* within range */
+		old = ftrace_call_replace(ip, addr);
+		new = ftrace_nop_replace();
+		return ftrace_modify_code(ip, old, new);
+	}
+
+	/*
+	 * Out of range jumps are called from modules.
+	 * We should either already have a pointer to the module
+	 * or it has been passed in.
+	 */
+	if (!rec->arch.mod) {
+		if (!mod) {
+			printk(KERN_ERR "No module loaded addr=%lx\n",
+			       addr);
+			return -EFAULT;
+		}
+		rec->arch.mod = mod;
+	} else if (mod) {
+		if (mod != rec->arch.mod) {
+			printk(KERN_ERR
+			       "Record mod %p not equal to passed in mod %p\n",
+			       rec->arch.mod, mod);
+			return -EINVAL;
+		}
+		/* nothing to do if mod == rec->arch.mod */
+	} else
+		mod = rec->arch.mod;
+
+	return __ftrace_make_nop(mod, rec, addr);
+
+}
+
+#ifdef CONFIG_PPC64
+static int
+__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned int op[2];
+	unsigned long ip = rec->ip;
+
+	/* read where this goes */
+	if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2))
+		return -EFAULT;
+
+	/*
+	 * It should be pointing to two nops or
+	 *  b +8; ld r2,40(r1)
+	 */
+	if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) &&
+	    ((op[0] != PPC_NOP_INSTR) || (op[1] != PPC_NOP_INSTR))) {
+		printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]);
+		return -EINVAL;
+	}
+
+	/* If we never set up a trampoline to ftrace_caller, then bail */
+	if (!rec->arch.mod->arch.tramp) {
+		printk(KERN_ERR "No ftrace trampoline\n");
+		return -EINVAL;
+	}
+
+	/* create the branch to the trampoline */
+	op[0] = create_branch((unsigned int *)ip,
+			      rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
+	if (!op[0]) {
+		printk(KERN_ERR "REL24 out of range!\n");
+		return -EINVAL;
+	}
+
+	/* ld r2,40(r1) */
+	op[1] = 0xe8410028;
+
+	DEBUGP("write to %lx\n", rec->ip);
+
+	if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2))
+		return -EPERM;
+
+	flush_icache_range(ip, ip + 8);
+
+	return 0;
+}
+#else
+static int
+__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned int op;
+	unsigned long ip = rec->ip;
+
+	/* read where this goes */
+	if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
+		return -EFAULT;
+
+	/* It should be pointing to a nop */
+	if (op != PPC_NOP_INSTR) {
+		printk(KERN_ERR "Expected NOP but have %x\n", op);
+		return -EINVAL;
+	}
+
+	/* If we never set up a trampoline to ftrace_caller, then bail */
+	if (!rec->arch.mod->arch.tramp) {
+		printk(KERN_ERR "No ftrace trampoline\n");
+		return -EINVAL;
+	}
+
+	/* create the branch to the trampoline */
+	op = create_branch((unsigned int *)ip,
+			   rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
+	if (!op) {
+		printk(KERN_ERR "REL24 out of range!\n");
+		return -EINVAL;
+	}
+
+	DEBUGP("write to %lx\n", rec->ip);
+
+	if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))
+		return -EPERM;
+
+	flush_icache_range(ip, ip + 8);
+
+	return 0;
+}
+#endif /* CONFIG_PPC64 */
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned char *old, *new;
+	unsigned long ip = rec->ip;
+
+	/*
+	 * If the calling address is more that 24 bits away,
+	 * then we had to use a trampoline to make the call.
+	 * Otherwise just update the call site.
+	 */
+	if (test_24bit_addr(ip, addr)) {
+		/* within range */
+		old = ftrace_nop_replace();
+		new = ftrace_call_replace(ip, addr);
+		return ftrace_modify_code(ip, old, new);
+	}
+
+	/*
+	 * Out of range jumps are called from modules.
+	 * Being that we are converting from nop, it had better
+	 * already have a module defined.
+	 */
+	if (!rec->arch.mod) {
+		printk(KERN_ERR "No module loaded\n");
+		return -EINVAL;
+	}
+
+	return __ftrace_make_call(rec, addr);
 }
 
 int ftrace_update_ftrace_func(ftrace_func_t func)
@@ -128,10 +509,10 @@
 
 int __init ftrace_dyn_arch_init(void *data)
 {
-	/* This is running in kstop_machine */
+	/* caller expects data to be zero */
+	unsigned long *p = data;
 
-	ftrace_mcount_set(data);
+	*p = 0;
 
 	return 0;
 }
-
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index 0c32682..a1c4cfd 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -31,6 +31,7 @@
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/ptrace.h>
+#include <asm/bug.h>
 
 /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */
 #define LOAD_BAT(n, reg, RA, RB)	\
@@ -182,7 +183,8 @@
 	bl	reloc_offset
 	mr	r26,r3
 	addis	r4,r3,KERNELBASE@h	/* current address of _start */
-	cmpwi	0,r4,0			/* are we already running at 0? */
+	lis	r5,PHYSICAL_START@h
+	cmplw	0,r4,r5			/* already running at PHYSICAL_START? */
 	bne	relocate_kernel
 /*
  * we now have the 1st 16M of ram mapped with the bats.
@@ -810,13 +812,13 @@
 
 /*
  * This code is jumped to from the startup code to copy
- * the kernel image to physical address 0.
+ * the kernel image to physical address PHYSICAL_START.
  */
 relocate_kernel:
 	addis	r9,r26,klimit@ha	/* fetch klimit */
 	lwz	r25,klimit@l(r9)
 	addis	r25,r25,-KERNELBASE@h
-	li	r3,0			/* Destination base address */
+	lis	r3,PHYSICAL_START@h	/* Destination base address */
 	li	r6,0			/* Destination offset */
 	li	r5,0x4000		/* # bytes of memory to copy */
 	bl	copy_and_flush		/* copy the first 0x4000 bytes */
@@ -989,12 +991,12 @@
 	LOAD_BAT(1,r3,r4,r5)
 	LOAD_BAT(2,r3,r4,r5)
 	LOAD_BAT(3,r3,r4,r5)
-BEGIN_FTR_SECTION
+BEGIN_MMU_FTR_SECTION
 	LOAD_BAT(4,r3,r4,r5)
 	LOAD_BAT(5,r3,r4,r5)
 	LOAD_BAT(6,r3,r4,r5)
 	LOAD_BAT(7,r3,r4,r5)
-END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
 	blr
 
 /*
@@ -1070,9 +1072,14 @@
 	RFI
 
 /*
+ * void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next);
+ *
  * Set up the segment registers for a new context.
  */
-_ENTRY(set_context)
+_ENTRY(switch_mmu_context)
+	lwz	r3,MMCONTEXTID(r4)
+	cmpwi	cr0,r3,0
+	blt-	4f
 	mulli	r3,r3,897	/* multiply context by skew factor */
 	rlwinm	r3,r3,4,8,27	/* VSID = (context & 0xfffff) << 4 */
 	addis	r3,r3,0x6000	/* Set Ks, Ku bits */
@@ -1083,6 +1090,7 @@
 	/* Context switch the PTE pointer for the Abatron BDI2000.
 	 * The PGDIR is passed as second argument.
 	 */
+	lwz	r4,MM_PGD(r4)
 	lis	r5, KERNELBASE@h
 	lwz	r5, 0xf0(r5)
 	stw	r4, 0x4(r5)
@@ -1098,6 +1106,9 @@
 	sync
 	isync
 	blr
+4:	trap
+	EMIT_BUG_ENTRY 4b,__FILE__,__LINE__,0
+	blr
 
 /*
  * An undocumented "feature" of 604e requires that the v bit
@@ -1131,7 +1142,7 @@
 	mtspr	SPRN_IBAT2L,r10
 	mtspr	SPRN_IBAT3U,r10
 	mtspr	SPRN_IBAT3L,r10
-BEGIN_FTR_SECTION
+BEGIN_MMU_FTR_SECTION
 	/* Here's a tweak: at this point, CPU setup have
 	 * not been called yet, so HIGH_BAT_EN may not be
 	 * set in HID0 for the 745x processors. However, it
@@ -1154,7 +1165,7 @@
 	mtspr	SPRN_IBAT6L,r10
 	mtspr	SPRN_IBAT7U,r10
 	mtspr	SPRN_IBAT7L,r10
-END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
 	blr
 
 flush_tlbs:
@@ -1178,11 +1189,11 @@
 
 /*
  * Use the first pair of BAT registers to map the 1st 16MB
- * of RAM to KERNELBASE.  From this point on we can't safely
+ * of RAM to PAGE_OFFSET.  From this point on we can't safely
  * call OF any more.
  */
 initial_bats:
-	lis	r11,KERNELBASE@h
+	lis	r11,PAGE_OFFSET@h
 	mfspr	r9,SPRN_PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
 	cmpwi	0,r9,1
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index f3a1ea9..b56fecc 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -69,6 +69,17 @@
 	li	r24,0		/* CPU number */
 
 /*
+ * In case the firmware didn't do it, we apply some workarounds
+ * that are good for all 440 core variants here
+ */
+	mfspr	r3,SPRN_CCR0
+	rlwinm	r3,r3,0,0,27	/* disable icache prefetch */
+	isync
+	mtspr	SPRN_CCR0,r3
+	isync
+	sync
+
+/*
  * Set up the initial MMU state
  *
  * We are still executing code at the virtual address
@@ -391,12 +402,14 @@
 	rlwimi	r13,r12,10,30,30
 
 	/* Load the PTE */
-	rlwinm 	r12, r10, 13, 19, 29	/* Compute pgdir/pmd offset */
+	/* Compute pgdir/pmd offset */
+	rlwinm  r12, r10, PPC44x_PGD_OFF_SHIFT, PPC44x_PGD_OFF_MASK_BIT, 29
 	lwzx	r11, r12, r11		/* Get pgd/pmd entry */
 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */
 	beq	2f			/* Bail if no table */
 
-	rlwimi	r12, r10, 23, 20, 28	/* Compute pte address */
+	/* Compute pte address */
+	rlwimi  r12, r10, PPC44x_PTE_ADD_SHIFT, PPC44x_PTE_ADD_MASK_BIT, 28
 	lwz	r11, 0(r12)		/* Get high word of pte entry */
 	lwz	r12, 4(r12)		/* Get low word of pte entry */
 
@@ -485,12 +498,14 @@
 	/* Make up the required permissions */
 	li	r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC
 
-	rlwinm	r12, r10, 13, 19, 29	/* Compute pgdir/pmd offset */
+	/* Compute pgdir/pmd offset */
+	rlwinm 	r12, r10, PPC44x_PGD_OFF_SHIFT, PPC44x_PGD_OFF_MASK_BIT, 29
 	lwzx	r11, r12, r11		/* Get pgd/pmd entry */
 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */
 	beq	2f			/* Bail if no table */
 
-	rlwimi	r12, r10, 23, 20, 28	/* Compute pte address */
+	/* Compute pte address */
+	rlwimi	r12, r10, PPC44x_PTE_ADD_SHIFT, PPC44x_PTE_ADD_MASK_BIT, 28
 	lwz	r11, 0(r12)		/* Get high word of pte entry */
 	lwz	r12, 4(r12)		/* Get low word of pte entry */
 
@@ -554,15 +569,16 @@
  */
 finish_tlb_load:
 	/* Combine RPN & ERPN an write WS 0 */
-	rlwimi	r11,r12,0,0,19
+	rlwimi	r11,r12,0,0,31-PAGE_SHIFT
 	tlbwe	r11,r13,PPC44x_TLB_XLAT
 
 	/*
 	 * Create WS1. This is the faulting address (EPN),
 	 * page size, and valid flag.
 	 */
-	li	r11,PPC44x_TLB_VALID | PPC44x_TLB_4K
-	rlwimi	r10,r11,0,20,31			/* Insert valid and page size*/
+	li	r11,PPC44x_TLB_VALID | PPC44x_TLBE_SIZE
+	/* Insert valid and page size */
+	rlwimi	r10,r11,0,PPC44x_PTE_ADD_MASK_BIT,31
 	tlbwe	r10,r13,PPC44x_TLB_PAGEID	/* Write PAGEID */
 
 	/* And WS 2 */
@@ -634,12 +650,12 @@
  * goes at the beginning of the data segment, which is page-aligned.
  */
 	.data
-	.align	12
+	.align	PAGE_SHIFT
 	.globl	sdata
 sdata:
 	.globl	empty_zero_page
 empty_zero_page:
-	.space	4096
+	.space	PAGE_SIZE
 
 /*
  * To support >32-bit physical addresses, we use an 8KB pgdir.
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 590304c..11b549ac 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -92,6 +92,7 @@
  * if needed
  */
 
+_ENTRY(__early_start)
 /* 1. Find the index of the entry we're executing in */
 	bl	invstr				/* Find our address */
 invstr:	mflr	r6				/* Make it accessible */
@@ -235,36 +236,40 @@
 	tlbivax 0,r9
 	TLBSYNC
 
+/* The mapping only needs to be cache-coherent on SMP */
+#ifdef CONFIG_SMP
+#define M_IF_SMP	MAS2_M
+#else
+#define M_IF_SMP	0
+#endif
+
 /* 6. Setup KERNELBASE mapping in TLB1[0] */
 	lis	r6,0x1000		/* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */
 	mtspr	SPRN_MAS0,r6
 	lis	r6,(MAS1_VALID|MAS1_IPROT)@h
 	ori	r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_64M))@l
 	mtspr	SPRN_MAS1,r6
-	li	r7,0
-	lis	r6,PAGE_OFFSET@h
-	ori	r6,r6,PAGE_OFFSET@l
-	rlwimi	r6,r7,0,20,31
+	lis	r6,MAS2_VAL(PAGE_OFFSET, BOOKE_PAGESZ_64M, M_IF_SMP)@h
+	ori	r6,r6,MAS2_VAL(PAGE_OFFSET, BOOKE_PAGESZ_64M, M_IF_SMP)@l
 	mtspr	SPRN_MAS2,r6
 	mtspr	SPRN_MAS3,r8
 	tlbwe
 
 /* 7. Jump to KERNELBASE mapping */
-	lis	r6,KERNELBASE@h
-	ori	r6,r6,KERNELBASE@l
-	rlwimi	r6,r7,0,20,31
+	lis	r6,(KERNELBASE & ~0xfff)@h
+	ori	r6,r6,(KERNELBASE & ~0xfff)@l
 	lis	r7,MSR_KERNEL@h
 	ori	r7,r7,MSR_KERNEL@l
 	bl	1f			/* Find our address */
 1:	mflr	r9
 	rlwimi	r6,r9,0,20,31
-	addi	r6,r6,24
+	addi	r6,r6,(2f - 1b)
 	mtspr	SPRN_SRR0,r6
 	mtspr	SPRN_SRR1,r7
 	rfi				/* start execution out of TLB1[0] entry */
 
 /* 8. Clear out the temp mapping */
-	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
+2:	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
 	rlwimi	r7,r5,16,4,15	/* Setup MAS0 = TLBSEL | ESEL(r5) */
 	mtspr	SPRN_MAS0,r7
 	tlbre
@@ -344,6 +349,15 @@
 	mtspr	SPRN_DBSR,r2
 #endif
 
+#ifdef CONFIG_SMP
+	/* Check to see if we're the second processor, and jump
+	 * to the secondary_start code if so
+	 */
+	mfspr	r24,SPRN_PIR
+	cmpwi	r24,0
+	bne	__secondary_start
+#endif
+
 	/*
 	 * This is where the main kernel code starts.
 	 */
@@ -685,12 +699,13 @@
 	/* SPE Floating Point Data */
 #ifdef CONFIG_SPE
 	EXCEPTION(0x2030, SPEFloatingPointData, SPEFloatingPointException, EXC_XFER_EE);
-#else
-	EXCEPTION(0x2040, SPEFloatingPointData, unknown_exception, EXC_XFER_EE)
-#endif /* CONFIG_SPE */
 
 	/* SPE Floating Point Round */
+	EXCEPTION(0x2050, SPEFloatingPointRound, SPEFloatingPointRoundException, EXC_XFER_EE)
+#else
+	EXCEPTION(0x2040, SPEFloatingPointData, unknown_exception, EXC_XFER_EE)
 	EXCEPTION(0x2050, SPEFloatingPointRound, unknown_exception, EXC_XFER_EE)
+#endif /* CONFIG_SPE */
 
 	/* Performance Monitor */
 	EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD)
@@ -735,6 +750,9 @@
 #else
 	rlwimi	r12, r11, 26, 27, 31	/* extract WIMGE from pte */
 #endif
+#ifdef CONFIG_SMP
+	ori	r12, r12, MAS2_M
+#endif
 	mtspr	SPRN_MAS2, r12
 
 	li	r10, (_PAGE_HWEXEC | _PAGE_PRESENT)
@@ -746,15 +764,15 @@
 	iseleq	r12, r12, r10
 	
 #ifdef CONFIG_PTE_64BIT
-2:	rlwimi	r12, r13, 24, 0, 7	/* grab RPN[32:39] */
+	rlwimi	r12, r13, 24, 0, 7	/* grab RPN[32:39] */
 	rlwimi	r12, r11, 24, 8, 19	/* grab RPN[40:51] */
 	mtspr	SPRN_MAS3, r12
-BEGIN_FTR_SECTION
+BEGIN_MMU_FTR_SECTION
 	srwi	r10, r13, 8		/* grab RPN[8:31] */
 	mtspr	SPRN_MAS7, r10
-END_FTR_SECTION_IFSET(CPU_FTR_BIG_PHYS)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS)
 #else
-2:	rlwimi	r11, r12, 0, 20, 31	/* Extract RPN from PTE and merge with perms */
+	rlwimi	r11, r12, 0, 20, 31	/* Extract RPN from PTE and merge with perms */
 	mtspr	SPRN_MAS3, r11
 #endif
 #ifdef CONFIG_E200
@@ -1037,6 +1055,63 @@
 
 	blr
 
+#ifdef CONFIG_SMP
+/* When we get here, r24 needs to hold the CPU # */
+	.globl __secondary_start
+__secondary_start:
+	lis	r3,__secondary_hold_acknowledge@h
+	ori	r3,r3,__secondary_hold_acknowledge@l
+	stw	r24,0(r3)
+
+	li	r3,0
+	mr	r4,r24		/* Why? */
+	bl	call_setup_cpu
+
+	lis	r3,tlbcam_index@ha
+	lwz	r3,tlbcam_index@l(r3)
+	mtctr	r3
+	li	r26,0		/* r26 safe? */
+
+	/* Load each CAM entry */
+1:	mr	r3,r26
+	bl	loadcam_entry
+	addi	r26,r26,1
+	bdnz	1b
+
+	/* get current_thread_info and current */
+	lis	r1,secondary_ti@ha
+	lwz	r1,secondary_ti@l(r1)
+	lwz	r2,TI_TASK(r1)
+
+	/* stack */
+	addi	r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
+	li	r0,0
+	stw	r0,0(r1)
+
+	/* ptr to current thread */
+	addi	r4,r2,THREAD	/* address of our thread_struct */
+	mtspr	SPRN_SPRG3,r4
+
+	/* Setup the defaults for TLB entries */
+	li	r4,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l
+	mtspr	SPRN_MAS4,r4
+
+	/* Jump to start_secondary */
+	lis	r4,MSR_KERNEL@h
+	ori	r4,r4,MSR_KERNEL@l
+	lis	r3,start_secondary@h
+	ori	r3,r3,start_secondary@l
+	mtspr	SPRN_SRR0,r3
+	mtspr	SPRN_SRR1,r4
+	sync
+	rfi
+	sync
+
+	.globl __secondary_hold_acknowledge
+__secondary_hold_acknowledge:
+	.long	-1
+#endif
+
 /*
  * We put a few things here that have to be page-aligned. This stuff
  * goes at the beginning of the data segment, which is page-aligned.
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 64299d2..6e3f624 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -47,7 +47,7 @@
 #include <asm/abs_addr.h>
 
 static struct device ibmebus_bus_device = { /* fake "parent" device */
-	.bus_id = "ibmebus",
+	.init_name = "ibmebus",
 };
 
 struct bus_type ibmebus_bus_type;
@@ -231,6 +231,7 @@
 	unsigned int irq = irq_find_mapping(NULL, ist);
 
 	free_irq(irq, dev_id);
+	irq_dispose_mapping(irq);
 }
 EXPORT_SYMBOL(ibmebus_free_irq);
 
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c
index 31982d0..88d9c1d 100644
--- a/arch/powerpc/kernel/idle.c
+++ b/arch/powerpc/kernel/idle.c
@@ -69,10 +69,15 @@
 				smp_mb();
 				local_irq_disable();
 
+				/* Don't trace irqs off for idle */
+				stop_critical_timings();
+
 				/* check again after disabling irqs */
 				if (!need_resched() && !cpu_should_die())
 					ppc_md.power_save();
 
+				start_critical_timings();
+
 				local_irq_enable();
 				set_thread_flag(TIF_POLLING_NRFLAG);
 
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
index ac2a21f..b3abebb 100644
--- a/arch/powerpc/kernel/machine_kexec.c
+++ b/arch/powerpc/kernel/machine_kexec.c
@@ -13,13 +13,17 @@
 #include <linux/reboot.h>
 #include <linux/threads.h>
 #include <linux/lmb.h>
+#include <linux/of.h>
 #include <asm/machdep.h>
 #include <asm/prom.h>
+#include <asm/sections.h>
 
 void machine_crash_shutdown(struct pt_regs *regs)
 {
 	if (ppc_md.machine_crash_shutdown)
 		ppc_md.machine_crash_shutdown(regs);
+	else
+		default_machine_crash_shutdown(regs);
 }
 
 /*
@@ -31,11 +35,8 @@
 {
 	if (ppc_md.machine_kexec_prepare)
 		return ppc_md.machine_kexec_prepare(image);
-	/*
-	 * Fail if platform doesn't provide its own machine_kexec_prepare
-	 * implementation.
-	 */
-	return -ENOSYS;
+	else
+		return default_machine_kexec_prepare(image);
 }
 
 void machine_kexec_cleanup(struct kimage *image)
@@ -52,13 +53,11 @@
 {
 	if (ppc_md.machine_kexec)
 		ppc_md.machine_kexec(image);
-	else {
-		/*
-		 * Fall back to normal restart if platform doesn't provide
-		 * its own kexec function, and user insist to kexec...
-		 */
-		machine_restart(NULL);
-	}
+	else
+		default_machine_kexec(image);
+
+	/* Fall back to normal restart if we're still alive. */
+	machine_restart(NULL);
 	for(;;);
 }
 
@@ -118,3 +117,71 @@
 {
 	return (start + size) > crashk_res.start && start <= crashk_res.end;
 }
+
+/* Values we need to export to the second kernel via the device tree. */
+static unsigned long kernel_end;
+static unsigned long crashk_size;
+
+static struct property kernel_end_prop = {
+	.name = "linux,kernel-end",
+	.length = sizeof(unsigned long),
+	.value = &kernel_end,
+};
+
+static struct property crashk_base_prop = {
+	.name = "linux,crashkernel-base",
+	.length = sizeof(unsigned long),
+	.value = &crashk_res.start,
+};
+
+static struct property crashk_size_prop = {
+	.name = "linux,crashkernel-size",
+	.length = sizeof(unsigned long),
+	.value = &crashk_size,
+};
+
+static void __init export_crashk_values(struct device_node *node)
+{
+	struct property *prop;
+
+	/* There might be existing crash kernel properties, but we can't
+	 * be sure what's in them, so remove them. */
+	prop = of_find_property(node, "linux,crashkernel-base", NULL);
+	if (prop)
+		prom_remove_property(node, prop);
+
+	prop = of_find_property(node, "linux,crashkernel-size", NULL);
+	if (prop)
+		prom_remove_property(node, prop);
+
+	if (crashk_res.start != 0) {
+		prom_add_property(node, &crashk_base_prop);
+		crashk_size = crashk_res.end - crashk_res.start + 1;
+		prom_add_property(node, &crashk_size_prop);
+	}
+}
+
+static int __init kexec_setup(void)
+{
+	struct device_node *node;
+	struct property *prop;
+
+	node = of_find_node_by_path("/chosen");
+	if (!node)
+		return -ENOENT;
+
+	/* remove any stale properties so ours can be found */
+	prop = of_find_property(node, kernel_end_prop.name, NULL);
+	if (prop)
+		prom_remove_property(node, prop);
+
+	/* information needed by userspace when using default_machine_kexec */
+	kernel_end = __pa(_end);
+	prom_add_property(node, &kernel_end_prop);
+
+	export_crashk_values(node);
+
+	of_node_put(node);
+	return 0;
+}
+late_initcall(kexec_setup);
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 3c4ca04..49e705f 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -289,7 +289,7 @@
 }
 
 /* Values we need to export to the second kernel via the device tree. */
-static unsigned long htab_base, kernel_end;
+static unsigned long htab_base;
 
 static struct property htab_base_prop = {
 	.name = "linux,htab-base",
@@ -303,25 +303,20 @@
 	.value = &htab_size_bytes,
 };
 
-static struct property kernel_end_prop = {
-	.name = "linux,kernel-end",
-	.length = sizeof(unsigned long),
-	.value = &kernel_end,
-};
-
-static void __init export_htab_values(void)
+static int __init export_htab_values(void)
 {
 	struct device_node *node;
 	struct property *prop;
 
+	/* On machines with no htab htab_address is NULL */
+	if (!htab_address)
+		return -ENODEV;
+
 	node = of_find_node_by_path("/chosen");
 	if (!node)
-		return;
+		return -ENODEV;
 
 	/* remove any stale propertys so ours can be found */
-	prop = of_find_property(node, kernel_end_prop.name, NULL);
-	if (prop)
-		prom_remove_property(node, prop);
 	prop = of_find_property(node, htab_base_prop.name, NULL);
 	if (prop)
 		prom_remove_property(node, prop);
@@ -329,68 +324,11 @@
 	if (prop)
 		prom_remove_property(node, prop);
 
-	/* information needed by userspace when using default_machine_kexec */
-	kernel_end = __pa(_end);
-	prom_add_property(node, &kernel_end_prop);
-
-	/* On machines with no htab htab_address is NULL */
-	if (NULL == htab_address)
-		goto out;
-
 	htab_base = __pa(htab_address);
 	prom_add_property(node, &htab_base_prop);
 	prom_add_property(node, &htab_size_prop);
 
- out:
 	of_node_put(node);
-}
-
-static struct property crashk_base_prop = {
-	.name = "linux,crashkernel-base",
-	.length = sizeof(unsigned long),
-	.value = &crashk_res.start,
-};
-
-static unsigned long crashk_size;
-
-static struct property crashk_size_prop = {
-	.name = "linux,crashkernel-size",
-	.length = sizeof(unsigned long),
-	.value = &crashk_size,
-};
-
-static void __init export_crashk_values(void)
-{
-	struct device_node *node;
-	struct property *prop;
-
-	node = of_find_node_by_path("/chosen");
-	if (!node)
-		return;
-
-	/* There might be existing crash kernel properties, but we can't
-	 * be sure what's in them, so remove them. */
-	prop = of_find_property(node, "linux,crashkernel-base", NULL);
-	if (prop)
-		prom_remove_property(node, prop);
-
-	prop = of_find_property(node, "linux,crashkernel-size", NULL);
-	if (prop)
-		prom_remove_property(node, prop);
-
-	if (crashk_res.start != 0) {
-		prom_add_property(node, &crashk_base_prop);
-		crashk_size = crashk_res.end - crashk_res.start + 1;
-		prom_add_property(node, &crashk_size_prop);
-	}
-
-	of_node_put(node);
-}
-
-static int __init kexec_setup(void)
-{
-	export_htab_values();
-	export_crashk_values();
 	return 0;
 }
-__initcall(kexec_setup);
+late_initcall(export_htab_values);
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 5c33bc1..15f28e0 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -29,6 +29,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/processor.h>
 #include <asm/kexec.h>
+#include <asm/bug.h>
 
 	.text
 
@@ -271,231 +272,6 @@
 
 #endif /* CONFIG_40x */
 
-/*
- * Flush MMU TLB
- */
-#ifndef CONFIG_FSL_BOOKE
-_GLOBAL(_tlbil_all)
-_GLOBAL(_tlbil_pid)
-#endif
-_GLOBAL(_tlbia)
-#if defined(CONFIG_40x)
-	sync			/* Flush to memory before changing mapping */
-	tlbia
-	isync			/* Flush shadow TLB */
-#elif defined(CONFIG_44x)
-	li	r3,0
-	sync
-
-	/* Load high watermark */
-	lis	r4,tlb_44x_hwater@ha
-	lwz	r5,tlb_44x_hwater@l(r4)
-
-1:	tlbwe	r3,r3,PPC44x_TLB_PAGEID
-	addi	r3,r3,1
-	cmpw	0,r3,r5
-	ble	1b
-
-	isync
-#elif defined(CONFIG_FSL_BOOKE)
-	/* Invalidate all entries in TLB0 */
-	li	r3, 0x04
-	tlbivax	0,3
-	/* Invalidate all entries in TLB1 */
-	li	r3, 0x0c
-	tlbivax	0,3
-	msync
-#ifdef CONFIG_SMP
-	tlbsync
-#endif /* CONFIG_SMP */
-#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */
-#if defined(CONFIG_SMP)
-	rlwinm	r8,r1,0,0,(31-THREAD_SHIFT)
-	lwz	r8,TI_CPU(r8)
-	oris	r8,r8,10
-	mfmsr	r10
-	SYNC
-	rlwinm	r0,r10,0,17,15		/* clear bit 16 (MSR_EE) */
-	rlwinm	r0,r0,0,28,26		/* clear DR */
-	mtmsr	r0
-	SYNC_601
-	isync
-	lis	r9,mmu_hash_lock@h
-	ori	r9,r9,mmu_hash_lock@l
-	tophys(r9,r9)
-10:	lwarx	r7,0,r9
-	cmpwi	0,r7,0
-	bne-	10b
-	stwcx.	r8,0,r9
-	bne-	10b
-	sync
-	tlbia
-	sync
-	TLBSYNC
-	li	r0,0
-	stw	r0,0(r9)		/* clear mmu_hash_lock */
-	mtmsr	r10
-	SYNC_601
-	isync
-#else /* CONFIG_SMP */
-	sync
-	tlbia
-	sync
-#endif /* CONFIG_SMP */
-#endif /* ! defined(CONFIG_40x) */
-	blr
-
-/*
- * Flush MMU TLB for a particular address
- */
-#ifndef CONFIG_FSL_BOOKE
-_GLOBAL(_tlbil_va)
-#endif
-_GLOBAL(_tlbie)
-#if defined(CONFIG_40x)
-	/* We run the search with interrupts disabled because we have to change
-	 * the PID and I don't want to preempt when that happens.
-	 */
-	mfmsr	r5
-	mfspr	r6,SPRN_PID
-	wrteei	0
-	mtspr	SPRN_PID,r4
-	tlbsx.	r3, 0, r3
-	mtspr	SPRN_PID,r6
-	wrtee	r5
-	bne	10f
-	sync
-	/* There are only 64 TLB entries, so r3 < 64, which means bit 25 is clear.
-	 * Since 25 is the V bit in the TLB_TAG, loading this value will invalidate
-	 * the TLB entry. */
-	tlbwe	r3, r3, TLB_TAG
-	isync
-10:
-
-#elif defined(CONFIG_44x)
-	mfspr	r5,SPRN_MMUCR
-	rlwimi	r5,r4,0,24,31			/* Set TID */
-
-	/* We have to run the search with interrupts disabled, even critical
-	 * and debug interrupts (in fact the only critical exceptions we have
-	 * are debug and machine check).  Otherwise  an interrupt which causes
-	 * a TLB miss can clobber the MMUCR between the mtspr and the tlbsx. */
-	mfmsr	r4
-	lis	r6,(MSR_EE|MSR_CE|MSR_ME|MSR_DE)@ha
-	addi	r6,r6,(MSR_EE|MSR_CE|MSR_ME|MSR_DE)@l
-	andc	r6,r4,r6
-	mtmsr	r6
-	mtspr	SPRN_MMUCR,r5
-	tlbsx.	r3, 0, r3
-	mtmsr	r4
-	bne	10f
-	sync
-	/* There are only 64 TLB entries, so r3 < 64,
-	 * which means bit 22, is clear.  Since 22 is
-	 * the V bit in the TLB_PAGEID, loading this
-	 * value will invalidate the TLB entry.
-	 */
-	tlbwe	r3, r3, PPC44x_TLB_PAGEID
-	isync
-10:
-#elif defined(CONFIG_FSL_BOOKE)
-	rlwinm	r4, r3, 0, 0, 19
-	ori	r5, r4, 0x08	/* TLBSEL = 1 */
-	tlbivax	0, r4
-	tlbivax	0, r5
-	msync
-#if defined(CONFIG_SMP)
-	tlbsync
-#endif /* CONFIG_SMP */
-#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */
-#if defined(CONFIG_SMP)
-	rlwinm	r8,r1,0,0,(31-THREAD_SHIFT)
-	lwz	r8,TI_CPU(r8)
-	oris	r8,r8,11
-	mfmsr	r10
-	SYNC
-	rlwinm	r0,r10,0,17,15		/* clear bit 16 (MSR_EE) */
-	rlwinm	r0,r0,0,28,26		/* clear DR */
-	mtmsr	r0
-	SYNC_601
-	isync
-	lis	r9,mmu_hash_lock@h
-	ori	r9,r9,mmu_hash_lock@l
-	tophys(r9,r9)
-10:	lwarx	r7,0,r9
-	cmpwi	0,r7,0
-	bne-	10b
-	stwcx.	r8,0,r9
-	bne-	10b
-	eieio
-	tlbie	r3
-	sync
-	TLBSYNC
-	li	r0,0
-	stw	r0,0(r9)		/* clear mmu_hash_lock */
-	mtmsr	r10
-	SYNC_601
-	isync
-#else /* CONFIG_SMP */
-	tlbie	r3
-	sync
-#endif /* CONFIG_SMP */
-#endif /* ! CONFIG_40x */
-	blr
-
-#if defined(CONFIG_FSL_BOOKE)
-/*
- * Flush MMU TLB, but only on the local processor (no broadcast)
- */
-_GLOBAL(_tlbil_all)
-#define MMUCSR0_TLBFI	(MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
-			 MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
-	li	r3,(MMUCSR0_TLBFI)@l
-	mtspr	SPRN_MMUCSR0, r3
-1:
-	mfspr	r3,SPRN_MMUCSR0
-	andi.	r3,r3,MMUCSR0_TLBFI@l
-	bne	1b
-	blr
-
-/*
- * Flush MMU TLB for a particular process id, but only on the local processor
- * (no broadcast)
- */
-_GLOBAL(_tlbil_pid)
-/* we currently do an invalidate all since we don't have per pid invalidate */
-	li	r3,(MMUCSR0_TLBFI)@l
-	mtspr	SPRN_MMUCSR0, r3
-1:
-	mfspr	r3,SPRN_MMUCSR0
-	andi.	r3,r3,MMUCSR0_TLBFI@l
-	bne	1b
-	msync
-	isync
-	blr
-
-/*
- * Flush MMU TLB for a particular address, but only on the local processor
- * (no broadcast)
- */
-_GLOBAL(_tlbil_va)
-	mfmsr	r10
-	wrteei	0
-	slwi	r4,r4,16
-	mtspr	SPRN_MAS6,r4		/* assume AS=0 for now */
-	tlbsx	0,r3
-	mfspr	r4,SPRN_MAS1		/* check valid */
-	andis.	r3,r4,MAS1_VALID@h
-	beq	1f
-	rlwinm	r4,r4,0,1,31
-	mtspr	SPRN_MAS1,r4
-	tlbwe
-	msync
-	isync
-1:	wrtee	r10
-	blr
-#endif /* CONFIG_FSL_BOOKE */
-
 
 /*
  * Flush instruction cache.
@@ -650,8 +426,8 @@
 BEGIN_FTR_SECTION
 	blr
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
 	mtctr	r4
 	mr	r6,r3
 0:	dcbst	0,r3				/* Write line to ram */
@@ -691,8 +467,8 @@
 	rlwinm	r0,r10,0,28,26			/* clear DR */
 	mtmsr	r0
 	isync
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
 	mtctr	r4
 	mr	r6,r3
 0:	dcbst	0,r3				/* Write line to ram */
@@ -716,7 +492,7 @@
  * void clear_pages(void *page, int order) ;
  */
 _GLOBAL(clear_pages)
-	li	r0,4096/L1_CACHE_BYTES
+	li	r0,PAGE_SIZE/L1_CACHE_BYTES
 	slw	r0,r0,r4
 	mtctr	r0
 #ifdef CONFIG_8xx
@@ -774,7 +550,7 @@
 	dcbt	r5,r4
 	li	r11,L1_CACHE_BYTES+4
 #endif /* MAX_COPY_PREFETCH */
-	li	r0,4096/L1_CACHE_BYTES - MAX_COPY_PREFETCH
+	li	r0,PAGE_SIZE/L1_CACHE_BYTES - MAX_COPY_PREFETCH
 	crclr	4*cr0+eq
 2:
 	mtctr	r0
diff --git a/arch/powerpc/kernel/module.c b/arch/powerpc/kernel/module.c
index 7ff2924..43e7e3a 100644
--- a/arch/powerpc/kernel/module.c
+++ b/arch/powerpc/kernel/module.c
@@ -78,6 +78,12 @@
 				  (void *)sect->sh_addr,
 				  (void *)sect->sh_addr + sect->sh_size);
 
+	sect = find_section(hdr, sechdrs, "__mmu_ftr_fixup");
+	if (sect != NULL)
+		do_feature_fixups(cur_cpu_spec->mmu_features,
+				  (void *)sect->sh_addr,
+				  (void *)sect->sh_addr + sect->sh_size);
+
 #ifdef CONFIG_PPC64
 	sect = find_section(hdr, sechdrs, "__fw_ftr_fixup");
 	if (sect != NULL)
diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c
index 2df91a0..f832773 100644
--- a/arch/powerpc/kernel/module_32.c
+++ b/arch/powerpc/kernel/module_32.c
@@ -22,6 +22,7 @@
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/ftrace.h>
 #include <linux/cache.h>
 #include <linux/bug.h>
 #include <linux/sort.h>
@@ -53,6 +54,9 @@
 			r_addend = rela[i].r_addend;
 		}
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+	_count_relocs++;	/* add one for ftrace_caller */
+#endif
 	return _count_relocs;
 }
 
@@ -306,5 +310,11 @@
 			return -ENOEXEC;
 		}
 	}
+#ifdef CONFIG_DYNAMIC_FTRACE
+	module->arch.tramp =
+		do_plt_call(module->module_core,
+			    (unsigned long)ftrace_caller,
+			    sechdrs, module);
+#endif
 	return 0;
 }
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
index 1af2377..8992b03 100644
--- a/arch/powerpc/kernel/module_64.c
+++ b/arch/powerpc/kernel/module_64.c
@@ -20,6 +20,7 @@
 #include <linux/moduleloader.h>
 #include <linux/err.h>
 #include <linux/vmalloc.h>
+#include <linux/ftrace.h>
 #include <linux/bug.h>
 #include <asm/module.h>
 #include <asm/firmware.h>
@@ -163,6 +164,11 @@
 		}
 	}
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+	/* make the trampoline to the ftrace_caller */
+	relocs++;
+#endif
+
 	DEBUGP("Looks like a total of %lu stubs, max\n", relocs);
 	return relocs * sizeof(struct ppc64_stub_entry);
 }
@@ -441,5 +447,12 @@
 		}
 	}
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+	me->arch.toc = my_r2(sechdrs, me);
+	me->arch.tramp = stub_for_addr(sechdrs,
+				       (unsigned long)ftrace_caller,
+				       me);
+#endif
+
 	return 0;
 }
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index f3c9cae..fa983a5 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -14,7 +14,6 @@
 {
 	static atomic_t bus_no_reg_magic;
 	struct device_node *node = dev->node;
-	char *name = dev->dev.bus_id;
 	const u32 *reg;
 	u64 addr;
 	int magic;
@@ -27,14 +26,12 @@
 	reg = of_get_property(node, "dcr-reg", NULL);
 	if (reg) {
 #ifdef CONFIG_PPC_DCR_NATIVE
-		snprintf(name, BUS_ID_SIZE, "d%x.%s",
-			 *reg, node->name);
+		dev_set_name(&dev->dev, "d%x.%s", *reg, node->name);
 #else /* CONFIG_PPC_DCR_NATIVE */
 		addr = of_translate_dcr_address(node, *reg, NULL);
 		if (addr != OF_BAD_ADDR) {
-			snprintf(name, BUS_ID_SIZE,
-				 "D%llx.%s", (unsigned long long)addr,
-				 node->name);
+			dev_set_name(&dev->dev, "D%llx.%s",
+				     (unsigned long long)addr, node->name);
 			return;
 		}
 #endif /* !CONFIG_PPC_DCR_NATIVE */
@@ -48,9 +45,8 @@
 	if (reg) {
 		addr = of_translate_address(node, reg);
 		if (addr != OF_BAD_ADDR) {
-			snprintf(name, BUS_ID_SIZE,
-				 "%llx.%s", (unsigned long long)addr,
-				 node->name);
+			dev_set_name(&dev->dev, "%llx.%s",
+				     (unsigned long long)addr, node->name);
 			return;
 		}
 	}
@@ -60,7 +56,7 @@
 	 * counter (and pray...)
 	 */
 	magic = atomic_add_return(1, &bus_no_reg_magic);
-	snprintf(name, BUS_ID_SIZE, "%s.%d", node->name, magic - 1);
+	dev_set_name(&dev->dev, "%s.%d", node->name, magic - 1);
 }
 
 struct of_device *of_device_alloc(struct device_node *np,
@@ -80,7 +76,7 @@
 	dev->dev.archdata.of_node = np;
 
 	if (bus_id)
-		strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
+		dev_set_name(&dev->dev, bus_id);
 	else
 		of_device_make_bus_id(dev);
 
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 48a3471..c744b32 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -37,6 +37,7 @@
 		.end_of_quantum = 0xfffffffffffffffful,
 		.slb_count = 64,
 		.vmxregs_in_use = 0,
+		.page_ins = 0,
 	},
 };
 
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index f36936d..2538030 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -37,13 +37,7 @@
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
 #include <asm/firmware.h>
-
-#ifdef DEBUG
-#include <asm/udbg.h>
-#define DBG(fmt...) printk(fmt)
-#else
-#define DBG(fmt...)
-#endif
+#include <asm/eeh.h>
 
 static DEFINE_SPINLOCK(hose_spinlock);
 
@@ -53,8 +47,9 @@
 /* ISA Memory physical address */
 resource_size_t isa_mem_base;
 
-/* Default PCI flags is 0 */
-unsigned int ppc_pci_flags;
+/* Default PCI flags is 0 on ppc32, modified at boot on ppc64 */
+unsigned int ppc_pci_flags = 0;
+
 
 static struct dma_mapping_ops *pci_dma_ops;
 
@@ -165,8 +160,6 @@
  */
 struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
 {
-	if (!have_of)
-		return NULL;
 	while(node) {
 		struct pci_controller *hose, *tmp;
 		list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
@@ -208,26 +201,6 @@
 	return str;
 }
 
-void __devinit pcibios_setup_new_device(struct pci_dev *dev)
-{
-	struct dev_archdata *sd = &dev->dev.archdata;
-
-	sd->of_node = pci_device_to_OF_node(dev);
-
-	DBG("PCI: device %s OF node: %s\n", pci_name(dev),
-	    sd->of_node ? sd->of_node->full_name : "<none>");
-
-	sd->dma_ops = pci_dma_ops;
-#ifdef CONFIG_PPC32
-	sd->dma_data = (void *)PCI_DRAM_OFFSET;
-#endif
-	set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
-
-	if (ppc_md.pci_dma_dev_setup)
-		ppc_md.pci_dma_dev_setup(dev);
-}
-EXPORT_SYMBOL(pcibios_setup_new_device);
-
 /*
  * Reads the interrupt pin to determine if interrupt is use by card.
  * If the interrupt is used, then gets the interrupt line from the
@@ -252,7 +225,7 @@
 		return -1;
 #endif
 
-	DBG("Try to map irq for %s...\n", pci_name(pci_dev));
+	pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev));
 
 #ifdef DEBUG
 	memset(&oirq, 0xff, sizeof(oirq));
@@ -276,26 +249,26 @@
 		    line == 0xff || line == 0) {
 			return -1;
 		}
-		DBG(" -> no map ! Using line %d (pin %d) from PCI config\n",
-		    line, pin);
+		pr_debug(" No map ! Using line %d (pin %d) from PCI config\n",
+			 line, pin);
 
 		virq = irq_create_mapping(NULL, line);
 		if (virq != NO_IRQ)
 			set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
 	} else {
-		DBG(" -> got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
-		    oirq.size, oirq.specifier[0], oirq.specifier[1],
+		pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
+			 oirq.size, oirq.specifier[0], oirq.specifier[1],
 		    oirq.controller->full_name);
 
 		virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
 					     oirq.size);
 	}
 	if(virq == NO_IRQ) {
-		DBG(" -> failed to map !\n");
+		pr_debug(" Failed to map !\n");
 		return -1;
 	}
 
-	DBG(" -> mapped to linux irq %d\n", virq);
+	pr_debug(" Mapped to linux irq %d\n", virq);
 
 	pci_dev->irq = virq;
 
@@ -397,13 +370,10 @@
 	}
 
 	/* XXX would be nice to have a way to ask for write-through */
-	prot |= _PAGE_NO_CACHE;
 	if (write_combine)
-		prot &= ~_PAGE_GUARDED;
+		return pgprot_noncached_wc(prot);
 	else
-		prot |= _PAGE_GUARDED;
-
-	return __pgprot(prot);
+		return pgprot_noncached(prot);
 }
 
 /*
@@ -414,19 +384,17 @@
 pgprot_t pci_phys_mem_access_prot(struct file *file,
 				  unsigned long pfn,
 				  unsigned long size,
-				  pgprot_t protection)
+				  pgprot_t prot)
 {
 	struct pci_dev *pdev = NULL;
 	struct resource *found = NULL;
-	unsigned long prot = pgprot_val(protection);
 	resource_size_t offset = ((resource_size_t)pfn) << PAGE_SHIFT;
 	int i;
 
 	if (page_is_ram(pfn))
-		return __pgprot(prot);
+		return prot;
 
-	prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
-
+	prot = pgprot_noncached(prot);
 	for_each_pci_dev(pdev) {
 		for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
 			struct resource *rp = &pdev->resource[i];
@@ -447,14 +415,14 @@
 	}
 	if (found) {
 		if (found->flags & IORESOURCE_PREFETCH)
-			prot &= ~_PAGE_GUARDED;
+			prot = pgprot_noncached_wc(prot);
 		pci_dev_put(pdev);
 	}
 
-	DBG("non-PCI map for %llx, prot: %lx\n",
-	    (unsigned long long)offset, prot);
+	pr_debug("PCI: Non-PCI map for %llx, prot: %lx\n",
+		 (unsigned long long)offset, pgprot_val(prot));
 
-	return __pgprot(prot);
+	return prot;
 }
 
 
@@ -610,8 +578,7 @@
 	pr_debug(" -> mapping phys %llx\n", (unsigned long long)offset);
 
 	vma->vm_pgoff = offset >> PAGE_SHIFT;
-	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
 			       vma->vm_end - vma->vm_start,
 			       vma->vm_page_prot);
@@ -853,15 +820,12 @@
 int pci_proc_domain(struct pci_bus *bus)
 {
 	struct pci_controller *hose = pci_bus_to_host(bus);
-#ifdef CONFIG_PPC64
-	return hose->buid != 0;
-#else
+
 	if (!(ppc_pci_flags & PPC_PCI_ENABLE_PROC_DOMAINS))
 		return 0;
 	if (ppc_pci_flags & PPC_PCI_COMPAT_DOMAIN_0)
 		return hose->global_number != 0;
 	return 1;
-#endif
 }
 
 void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
@@ -1083,27 +1047,50 @@
 	}
 }
 
-static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit pcibios_setup_bus_self(struct pci_bus *bus)
 {
-	struct pci_dev *dev = bus->self;
-
-	pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");
-
-	/* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
-	 * now differently between 32 and 64 bits.
-	 */
-	if (dev != NULL)
+	/* Fix up the bus resources for P2P bridges */
+	if (bus->self != NULL)
 		pcibios_fixup_bridge(bus);
 
-	/* Additional setup that is different between 32 and 64 bits for now */
-	pcibios_do_bus_setup(bus);
-
-	/* Platform specific bus fixups */
+	/* Platform specific bus fixups. This is currently only used
+	 * by fsl_pci and I'm hoping to get rid of it at some point
+	 */
 	if (ppc_md.pcibios_fixup_bus)
 		ppc_md.pcibios_fixup_bus(bus);
 
-	/* Read default IRQs and fixup if necessary */
+	/* Setup bus DMA mappings */
+	if (ppc_md.pci_dma_bus_setup)
+		ppc_md.pci_dma_bus_setup(bus);
+}
+
+void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	pr_debug("PCI: Fixup bus devices %d (%s)\n",
+		 bus->number, bus->self ? pci_name(bus->self) : "PHB");
+
 	list_for_each_entry(dev, &bus->devices, bus_list) {
+		struct dev_archdata *sd = &dev->dev.archdata;
+
+		/* Setup OF node pointer in archdata */
+		sd->of_node = pci_device_to_OF_node(dev);
+
+		/* Fixup NUMA node as it may not be setup yet by the generic
+		 * code and is needed by the DMA init
+		 */
+		set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
+
+		/* Hook up default DMA ops */
+		sd->dma_ops = pci_dma_ops;
+		sd->dma_data = (void *)PCI_DRAM_OFFSET;
+
+		/* Additional platform DMA/iommu setup */
+		if (ppc_md.pci_dma_dev_setup)
+			ppc_md.pci_dma_dev_setup(dev);
+
+		/* Read default IRQs and fixup if necessary */
 		pci_read_irq_line(dev);
 		if (ppc_md.pci_irq_fixup)
 			ppc_md.pci_irq_fixup(dev);
@@ -1113,23 +1100,20 @@
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
 	/* When called from the generic PCI probe, read PCI<->PCI bridge
-	 * bases before proceeding
+	 * bases. This is -not- called when generating the PCI tree from
+	 * the OF device-tree.
 	 */
 	if (bus->self != NULL)
 		pci_read_bridge_bases(bus);
-	__pcibios_fixup_bus(bus);
+
+	/* Now fixup the bus bus */
+	pcibios_setup_bus_self(bus);
+
+	/* Now fixup devices on that bus */
+	pcibios_setup_bus_devices(bus);
 }
 EXPORT_SYMBOL(pcibios_fixup_bus);
 
-/* When building a bus from the OF tree rather than probing, we need a
- * slightly different version of the fixup which doesn't read the
- * bridge bases using config space accesses
- */
-void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus)
-{
-	__pcibios_fixup_bus(bus);
-}
-
 static int skip_isa_ioresource_align(struct pci_dev *dev)
 {
 	if ((ppc_pci_flags & PPC_PCI_CAN_SKIP_ISA_ALIGN) &&
@@ -1198,10 +1182,10 @@
 	*pp = NULL;
 	for (p = res->child; p != NULL; p = p->sibling) {
 		p->parent = res;
-		DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n",
-		    p->name,
-		    (unsigned long long)p->start,
-		    (unsigned long long)p->end, res->name);
+		pr_debug("PCI: Reparented %s [%llx..%llx] under %s\n",
+			 p->name,
+			 (unsigned long long)p->start,
+			 (unsigned long long)p->end, res->name);
 	}
 	return 0;
 }
@@ -1245,9 +1229,12 @@
 	int i;
 	struct resource *res, *pr;
 
+	pr_debug("PCI: Allocating bus resources for %04x:%02x...\n",
+		 pci_domain_nr(bus), bus->number);
+
 	for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
 		if ((res = bus->resource[i]) == NULL || !res->flags
-		    || res->start > res->end)
+		    || res->start > res->end || res->parent)
 			continue;
 		if (bus->parent == NULL)
 			pr = (res->flags & IORESOURCE_IO) ?
@@ -1271,14 +1258,14 @@
 			}
 		}
 
-		DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx "
-		    "[0x%x], parent %p (%s)\n",
-		    bus->self ? pci_name(bus->self) : "PHB",
-		    bus->number, i,
-		    (unsigned long long)res->start,
-		    (unsigned long long)res->end,
-		    (unsigned int)res->flags,
-		    pr, (pr && pr->name) ? pr->name : "nil");
+		pr_debug("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx "
+			 "[0x%x], parent %p (%s)\n",
+			 bus->self ? pci_name(bus->self) : "PHB",
+			 bus->number, i,
+			 (unsigned long long)res->start,
+			 (unsigned long long)res->end,
+			 (unsigned int)res->flags,
+			 pr, (pr && pr->name) ? pr->name : "nil");
 
 		if (pr && !(pr->flags & IORESOURCE_UNSET)) {
 			if (request_resource(pr, res) == 0)
@@ -1305,11 +1292,11 @@
 {
 	struct resource *pr, *r = &dev->resource[idx];
 
-	DBG("PCI: Allocating %s: Resource %d: %016llx..%016llx [%x]\n",
-	    pci_name(dev), idx,
-	    (unsigned long long)r->start,
-	    (unsigned long long)r->end,
-	    (unsigned int)r->flags);
+	pr_debug("PCI: Allocating %s: Resource %d: %016llx..%016llx [%x]\n",
+		 pci_name(dev), idx,
+		 (unsigned long long)r->start,
+		 (unsigned long long)r->end,
+		 (unsigned int)r->flags);
 
 	pr = pci_find_parent_resource(dev, r);
 	if (!pr || (pr->flags & IORESOURCE_UNSET) ||
@@ -1317,10 +1304,11 @@
 		printk(KERN_WARNING "PCI: Cannot allocate resource region %d"
 		       " of device %s, will remap\n", idx, pci_name(dev));
 		if (pr)
-			DBG("PCI:  parent is %p: %016llx-%016llx [%x]\n", pr,
-			    (unsigned long long)pr->start,
-			    (unsigned long long)pr->end,
-			    (unsigned int)pr->flags);
+			pr_debug("PCI:  parent is %p: %016llx-%016llx [%x]\n",
+				 pr,
+				 (unsigned long long)pr->start,
+				 (unsigned long long)pr->end,
+				 (unsigned int)pr->flags);
 		/* We'll assign a new address later */
 		r->flags |= IORESOURCE_UNSET;
 		r->end -= r->start;
@@ -1358,7 +1346,8 @@
 			 * but keep it unregistered.
 			 */
 			u32 reg;
-			DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
+			pr_debug("PCI: Switching off ROM of %s\n",
+				 pci_name(dev));
 			r->flags &= ~IORESOURCE_ROM_ENABLE;
 			pci_read_config_dword(dev, dev->rom_base_reg, &reg);
 			pci_write_config_dword(dev, dev->rom_base_reg,
@@ -1383,7 +1372,7 @@
 	}
 
 	if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) {
-		DBG("PCI: Assigning unassigned resouces...\n");
+		pr_debug("PCI: Assigning unassigned resouces...\n");
 		pci_assign_unassigned_resources();
 	}
 
@@ -1393,9 +1382,11 @@
 }
 
 #ifdef CONFIG_HOTPLUG
-/* This is used by the pSeries hotplug driver to allocate resource
+
+/* This is used by the PCI hotplug driver to allocate resource
  * of newly plugged busses. We can try to consolidate with the
- * rest of the code later, for now, keep it as-is
+ * rest of the code later, for now, keep it as-is as our main
+ * resource allocation function doesn't deal with sub-trees yet.
  */
 void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
 {
@@ -1410,6 +1401,14 @@
 
 			if (r->parent || !r->start || !r->flags)
 				continue;
+
+			pr_debug("PCI: Claiming %s: "
+				 "Resource %d: %016llx..%016llx [%x]\n",
+				 pci_name(dev), i,
+				 (unsigned long long)r->start,
+				 (unsigned long long)r->end,
+				 (unsigned int)r->flags);
+
 			pci_claim_resource(dev, i);
 		}
 	}
@@ -1418,6 +1417,31 @@
 		pcibios_claim_one_bus(child_bus);
 }
 EXPORT_SYMBOL_GPL(pcibios_claim_one_bus);
+
+
+/* pcibios_finish_adding_to_bus
+ *
+ * This is to be called by the hotplug code after devices have been
+ * added to a bus, this include calling it for a PHB that is just
+ * being added
+ */
+void pcibios_finish_adding_to_bus(struct pci_bus *bus)
+{
+	pr_debug("PCI: Finishing adding to hotplug bus %04x:%02x\n",
+		 pci_domain_nr(bus), bus->number);
+
+	/* Allocate bus and devices resources */
+	pcibios_allocate_bus_resources(bus);
+	pcibios_claim_one_bus(bus);
+
+	/* Add new devices to global lists.  Register in proc, sysfs. */
+	pci_bus_add_devices(bus);
+
+	/* Fixup EEH */
+	eeh_add_device_tree_late(bus);
+}
+EXPORT_SYMBOL_GPL(pcibios_finish_adding_to_bus);
+
 #endif /* CONFIG_HOTPLUG */
 
 int pcibios_enable_device(struct pci_dev *dev, int mask)
@@ -1428,3 +1452,61 @@
 
 	return pci_enable_resources(dev, mask);
 }
+
+void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
+{
+	struct pci_bus *bus = hose->bus;
+	struct resource *res;
+	int i;
+
+	/* Hookup PHB IO resource */
+	bus->resource[0] = res = &hose->io_resource;
+
+	if (!res->flags) {
+		printk(KERN_WARNING "PCI: I/O resource not set for host"
+		       " bridge %s (domain %d)\n",
+		       hose->dn->full_name, hose->global_number);
+#ifdef CONFIG_PPC32
+		/* Workaround for lack of IO resource only on 32-bit */
+		res->start = (unsigned long)hose->io_base_virt - isa_io_base;
+		res->end = res->start + IO_SPACE_LIMIT;
+		res->flags = IORESOURCE_IO;
+#endif /* CONFIG_PPC32 */
+	}
+
+	pr_debug("PCI: PHB IO resource    = %016llx-%016llx [%lx]\n",
+		 (unsigned long long)res->start,
+		 (unsigned long long)res->end,
+		 (unsigned long)res->flags);
+
+	/* Hookup PHB Memory resources */
+	for (i = 0; i < 3; ++i) {
+		res = &hose->mem_resources[i];
+		if (!res->flags) {
+			if (i > 0)
+				continue;
+			printk(KERN_ERR "PCI: Memory resource 0 not set for "
+			       "host bridge %s (domain %d)\n",
+			       hose->dn->full_name, hose->global_number);
+#ifdef CONFIG_PPC32
+			/* Workaround for lack of MEM resource only on 32-bit */
+			res->start = hose->pci_mem_offset;
+			res->end = (resource_size_t)-1LL;
+			res->flags = IORESOURCE_MEM;
+#endif /* CONFIG_PPC32 */
+		}
+		bus->resource[i+1] = res;
+
+		pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", i,
+			 (unsigned long long)res->start,
+			 (unsigned long long)res->end,
+			 (unsigned long)res->flags);
+	}
+
+	pr_debug("PCI: PHB MEM offset     = %016llx\n",
+		 (unsigned long long)hose->pci_mem_offset);
+	pr_debug("PCI: PHB IO  offset     = %08lx\n",
+		 (unsigned long)hose->io_base_virt - _IO_BASE);
+
+}
+
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index 131b1df..132cd80 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -26,12 +26,6 @@
 
 #undef DEBUG
 
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
 unsigned long isa_io_base     = 0;
 unsigned long pci_dram_offset = 0;
 int pcibios_assign_bus_offset = 1;
@@ -272,17 +266,14 @@
 {
 	struct device_node *parent, *np;
 
-	if (!have_of)
-		return NULL;
-
-	DBG("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn);
+	pr_debug("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn);
 	parent = scan_OF_for_pci_bus(bus);
 	if (parent == NULL)
 		return NULL;
-	DBG(" parent is %s\n", parent ? parent->full_name : "<NULL>");
+	pr_debug(" parent is %s\n", parent ? parent->full_name : "<NULL>");
 	np = scan_OF_for_pci_dev(parent, devfn);
 	of_node_put(parent);
-	DBG(" result is %s\n", np ? np->full_name : "<NULL>");
+	pr_debug(" result is %s\n", np ? np->full_name : "<NULL>");
 
 	/* XXX most callers don't release the returned node
 	 * mostly because ppc64 doesn't increase the refcount,
@@ -315,8 +306,6 @@
 	struct pci_controller* hose;
 	struct pci_dev* dev = NULL;
 	
-	if (!have_of)
-		return -ENODEV;
 	/* Make sure it's really a PCI device */
 	hose = pci_find_hose_for_OF_device(node);
 	if (!hose || !hose->dn)
@@ -379,10 +368,41 @@
 }
 #endif /* CONFIG_PPC_OF */
 
+static void __devinit pcibios_scan_phb(struct pci_controller *hose)
+{
+	struct pci_bus *bus;
+	struct device_node *node = hose->dn;
+	unsigned long io_offset;
+	struct resource *res = &hose->io_resource;
+
+	pr_debug("PCI: Scanning PHB %s\n",
+		 node ? node->full_name : "<NO NAME>");
+
+	/* Create an empty bus for the toplevel */
+	bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
+	if (bus == NULL) {
+		printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
+		       hose->global_number);
+		return;
+	}
+	bus->secondary = hose->first_busno;
+	hose->bus = bus;
+
+	/* Fixup IO space offset */
+	io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
+	res->start = (res->start + io_offset) & 0xffffffffu;
+	res->end = (res->end + io_offset) & 0xffffffffu;
+
+	/* Wire up PHB bus resources */
+	pcibios_setup_phb_resources(hose);
+
+	/* Scan children */
+	hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+}
+
 static int __init pcibios_init(void)
 {
 	struct pci_controller *hose, *tmp;
-	struct pci_bus *bus;
 	int next_busno = 0;
 
 	printk(KERN_INFO "PCI: Probing PCI hardware\n");
@@ -395,12 +415,8 @@
 		if (pci_assign_all_buses)
 			hose->first_busno = next_busno;
 		hose->last_busno = 0xff;
-		bus = pci_scan_bus_parented(hose->parent, hose->first_busno,
-					    hose->ops, hose);
-		if (bus) {
-			pci_bus_add_devices(bus);
-			hose->last_busno = bus->subordinate;
-		}
+		pcibios_scan_phb(hose);
+		pci_bus_add_devices(hose->bus);
 		if (pci_assign_all_buses || next_busno <= hose->last_busno)
 			next_busno = hose->last_busno + pcibios_assign_bus_offset;
 	}
@@ -410,7 +426,7 @@
 	 * numbers vs. kernel bus numbers since we may have to
 	 * remap them.
 	 */
-	if (pci_assign_all_buses && have_of)
+	if (pci_assign_all_buses)
 		pcibios_make_OF_bus_map();
 
 	/* Call common code to handle resource allocation */
@@ -425,54 +441,6 @@
 
 subsys_initcall(pcibios_init);
 
-void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
-{
-	struct pci_controller *hose = (struct pci_controller *) bus->sysdata;
-	unsigned long io_offset;
-	struct resource *res;
-	int i;
-	struct pci_dev *dev;
-
-	/* Hookup PHB resources */
-	io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
-	if (bus->parent == NULL) {
-		/* This is a host bridge - fill in its resources */
-		hose->bus = bus;
-
-		bus->resource[0] = res = &hose->io_resource;
-		if (!res->flags) {
-			if (io_offset)
-				printk(KERN_ERR "I/O resource not set for host"
-				       " bridge %d\n", hose->global_number);
-			res->start = 0;
-			res->end = IO_SPACE_LIMIT;
-			res->flags = IORESOURCE_IO;
-		}
-		res->start = (res->start + io_offset) & 0xffffffffu;
-		res->end = (res->end + io_offset) & 0xffffffffu;
-
-		for (i = 0; i < 3; ++i) {
-			res = &hose->mem_resources[i];
-			if (!res->flags) {
-				if (i > 0)
-					continue;
-				printk(KERN_ERR "Memory resource not set for "
-				       "host bridge %d\n", hose->global_number);
-				res->start = hose->pci_mem_offset;
-				res->end = ~0U;
-				res->flags = IORESOURCE_MEM;
-			}
-			bus->resource[i+1] = res;
-		}
-	}
-
-	if (ppc_md.pci_dma_bus_setup)
-		ppc_md.pci_dma_bus_setup(bus);
-
-	list_for_each_entry(dev, &bus->devices, bus_list)
-		pcibios_setup_new_device(dev);
-}
-
 /* the next one is stolen from the alpha port... */
 void __init
 pcibios_update_irq(struct pci_dev *dev, int irq)
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 3502b91..39fadc6 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -32,13 +32,6 @@
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
 
-#ifdef DEBUG
-#include <asm/udbg.h>
-#define DBG(fmt...) printk(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
 unsigned long pci_probe_only = 1;
 
 /* pci_io_base -- the base address from which io bars are offsets.
@@ -102,7 +95,7 @@
 	addrs = of_get_property(node, "assigned-addresses", &proplen);
 	if (!addrs)
 		return;
-	DBG("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
+	pr_debug("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
 	for (; proplen >= 20; proplen -= 20, addrs += 5) {
 		flags = pci_parse_of_flags(addrs[0]);
 		if (!flags)
@@ -112,8 +105,9 @@
 		if (!size)
 			continue;
 		i = addrs[0] & 0xff;
-		DBG("  base: %llx, size: %llx, i: %x\n",
-		    (unsigned long long)base, (unsigned long long)size, i);
+		pr_debug("  base: %llx, size: %llx, i: %x\n",
+			 (unsigned long long)base,
+			 (unsigned long long)size, i);
 
 		if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
 			res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
@@ -144,7 +138,7 @@
 	if (type == NULL)
 		type = "";
 
-	DBG("    create device, devfn: %x, type: %s\n", devfn, type);
+	pr_debug("    create device, devfn: %x, type: %s\n", devfn, type);
 
 	dev->bus = bus;
 	dev->sysdata = node;
@@ -165,8 +159,8 @@
 	dev->class = get_int_prop(node, "class-code", 0);
 	dev->revision = get_int_prop(node, "revision-id", 0);
 
-	DBG("    class: 0x%x\n", dev->class);
-	DBG("    revision: 0x%x\n", dev->revision);
+	pr_debug("    class: 0x%x\n", dev->class);
+	pr_debug("    revision: 0x%x\n", dev->revision);
 
 	dev->current_state = 4;		/* unknown power state */
 	dev->error_state = pci_channel_io_normal;
@@ -187,7 +181,7 @@
 
 	pci_parse_of_addrs(node, dev);
 
-	DBG("    adding to system ...\n");
+	pr_debug("    adding to system ...\n");
 
 	pci_device_add(dev, bus);
 
@@ -195,19 +189,20 @@
 }
 EXPORT_SYMBOL(of_create_pci_dev);
 
-void __devinit of_scan_bus(struct device_node *node,
-			   struct pci_bus *bus)
+static void __devinit __of_scan_bus(struct device_node *node,
+				    struct pci_bus *bus, int rescan_existing)
 {
 	struct device_node *child;
 	const u32 *reg;
 	int reglen, devfn;
 	struct pci_dev *dev;
 
-	DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number);
+	pr_debug("of_scan_bus(%s) bus no %d... \n",
+		 node->full_name, bus->number);
 
 	/* Scan direct children */
 	for_each_child_of_node(node, child) {
-		DBG("  * %s\n", child->full_name);
+		pr_debug("  * %s\n", child->full_name);
 		reg = of_get_property(child, "reg", &reglen);
 		if (reg == NULL || reglen < 20)
 			continue;
@@ -217,11 +212,15 @@
 		dev = of_create_pci_dev(child, bus, devfn);
 		if (!dev)
 			continue;
-		DBG("    dev header type: %x\n", dev->hdr_type);
+		pr_debug("    dev header type: %x\n", dev->hdr_type);
 	}
 
-	/* Ally all fixups */
-	pcibios_fixup_of_probed_bus(bus);
+	/* Apply all fixups necessary. We don't fixup the bus "self"
+	 * for an existing bridge that is being rescanned
+	 */
+	if (!rescan_existing)
+		pcibios_setup_bus_self(bus);
+	pcibios_setup_bus_devices(bus);
 
 	/* Now scan child busses */
 	list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -233,7 +232,20 @@
 		}
 	}
 }
-EXPORT_SYMBOL(of_scan_bus);
+
+void __devinit of_scan_bus(struct device_node *node,
+			   struct pci_bus *bus)
+{
+	__of_scan_bus(node, bus, 0);
+}
+EXPORT_SYMBOL_GPL(of_scan_bus);
+
+void __devinit of_rescan_bus(struct device_node *node,
+			     struct pci_bus *bus)
+{
+	__of_scan_bus(node, bus, 1);
+}
+EXPORT_SYMBOL_GPL(of_rescan_bus);
 
 void __devinit of_scan_pci_bridge(struct device_node *node,
 				  struct pci_dev *dev)
@@ -245,7 +257,7 @@
 	unsigned int flags;
 	u64 size;
 
-	DBG("of_scan_pci_bridge(%s)\n", node->full_name);
+	pr_debug("of_scan_pci_bridge(%s)\n", node->full_name);
 
 	/* parse bus-range property */
 	busrange = of_get_property(node, "bus-range", &len);
@@ -309,12 +321,12 @@
 	}
 	sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
 		bus->number);
-	DBG("    bus name: %s\n", bus->name);
+	pr_debug("    bus name: %s\n", bus->name);
 
 	mode = PCI_PROBE_NORMAL;
 	if (ppc_md.pci_probe_mode)
 		mode = ppc_md.pci_probe_mode(bus);
-	DBG("    probe mode: %d\n", mode);
+	pr_debug("    probe mode: %d\n", mode);
 
 	if (mode == PCI_PROBE_DEVTREE)
 		of_scan_bus(node, bus);
@@ -327,9 +339,10 @@
 {
 	struct pci_bus *bus;
 	struct device_node *node = hose->dn;
-	int i, mode;
+	int mode;
 
-	DBG("PCI: Scanning PHB %s\n", node ? node->full_name : "<NO NAME>");
+	pr_debug("PCI: Scanning PHB %s\n",
+		 node ? node->full_name : "<NO NAME>");
 
 	/* Create an empty bus for the toplevel */
 	bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node);
@@ -345,26 +358,13 @@
 	pcibios_map_io_space(bus);
 
 	/* Wire up PHB bus resources */
-	DBG("PCI: PHB IO resource    = %016lx-%016lx [%lx]\n",
-	    hose->io_resource.start, hose->io_resource.end,
-	    hose->io_resource.flags);
-	bus->resource[0] = &hose->io_resource;
-	for (i = 0; i < 3; ++i) {
-		DBG("PCI: PHB MEM resource %d = %016lx-%016lx [%lx]\n", i,
-		    hose->mem_resources[i].start,
-		    hose->mem_resources[i].end,
-		    hose->mem_resources[i].flags);
-		bus->resource[i+1] = &hose->mem_resources[i];
-	}
-	DBG("PCI: PHB MEM offset     = %016lx\n", hose->pci_mem_offset);
-	DBG("PCI: PHB IO  offset     = %08lx\n",
-	    (unsigned long)hose->io_base_virt - _IO_BASE);
+	pcibios_setup_phb_resources(hose);
 
 	/* Get probe mode and perform scan */
 	mode = PCI_PROBE_NORMAL;
 	if (node && ppc_md.pci_probe_mode)
 		mode = ppc_md.pci_probe_mode(bus);
-	DBG("    probe mode: %d\n", mode);
+	pr_debug("    probe mode: %d\n", mode);
 	if (mode == PCI_PROBE_DEVTREE) {
 		bus->subordinate = hose->last_busno;
 		of_scan_bus(node, bus);
@@ -380,7 +380,7 @@
 
 	printk(KERN_INFO "PCI: Probing PCI hardware\n");
 
-	/* For now, override phys_mem_access_prot. If we need it,
+	/* For now, override phys_mem_access_prot. If we need it,g
 	 * later, we may move that initialization to each ppc_md
 	 */
 	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
@@ -388,6 +388,11 @@
 	if (pci_probe_only)
 		ppc_pci_flags |= PPC_PCI_PROBE_ONLY;
 
+	/* On ppc64, we always enable PCI domains and we keep domain 0
+	 * backward compatible in /proc for video cards
+	 */
+	ppc_pci_flags |= PPC_PCI_ENABLE_PROC_DOMAINS | PPC_PCI_COMPAT_DOMAIN_0;
+
 	/* Scan all of the recorded PCI controllers.  */
 	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
 		scan_phb(hose);
@@ -422,8 +427,8 @@
 	if (bus->self) {
 		struct resource *res = bus->resource[0];
 
-		DBG("IO unmapping for PCI-PCI bridge %s\n",
-		    pci_name(bus->self));
+		pr_debug("IO unmapping for PCI-PCI bridge %s\n",
+			 pci_name(bus->self));
 
 		__flush_hash_table_range(&init_mm, res->start + _IO_BASE,
 					 res->end + _IO_BASE + 1);
@@ -437,8 +442,8 @@
 	if (hose->io_base_alloc == 0)
 		return 0;
 
-	DBG("IO unmapping for PHB %s\n", hose->dn->full_name);
-	DBG("  alloc=0x%p\n", hose->io_base_alloc);
+	pr_debug("IO unmapping for PHB %s\n", hose->dn->full_name);
+	pr_debug("  alloc=0x%p\n", hose->io_base_alloc);
 
 	/* This is a PHB, we fully unmap the IO area */
 	vunmap(hose->io_base_alloc);
@@ -463,11 +468,11 @@
 	 * thus HPTEs will be faulted in when needed
 	 */
 	if (bus->self) {
-		DBG("IO mapping for PCI-PCI bridge %s\n",
-		    pci_name(bus->self));
-		DBG("  virt=0x%016lx...0x%016lx\n",
-		    bus->resource[0]->start + _IO_BASE,
-		    bus->resource[0]->end + _IO_BASE);
+		pr_debug("IO mapping for PCI-PCI bridge %s\n",
+			 pci_name(bus->self));
+		pr_debug("  virt=0x%016lx...0x%016lx\n",
+			 bus->resource[0]->start + _IO_BASE,
+			 bus->resource[0]->end + _IO_BASE);
 		return 0;
 	}
 
@@ -496,11 +501,11 @@
 	hose->io_base_virt = (void __iomem *)(area->addr +
 					      hose->io_base_phys - phys_page);
 
-	DBG("IO mapping for PHB %s\n", hose->dn->full_name);
-	DBG("  phys=0x%016lx, virt=0x%p (alloc=0x%p)\n",
-	    hose->io_base_phys, hose->io_base_virt, hose->io_base_alloc);
-	DBG("  size=0x%016lx (alloc=0x%016lx)\n",
-	    hose->pci_io_size, size_page);
+	pr_debug("IO mapping for PHB %s\n", hose->dn->full_name);
+	pr_debug("  phys=0x%016lx, virt=0x%p (alloc=0x%p)\n",
+		 hose->io_base_phys, hose->io_base_virt, hose->io_base_alloc);
+	pr_debug("  size=0x%016lx (alloc=0x%016lx)\n",
+		 hose->pci_io_size, size_page);
 
 	/* Establish the mapping */
 	if (__ioremap_at(phys_page, area->addr, size_page,
@@ -512,24 +517,13 @@
 	hose->io_resource.start += io_virt_offset;
 	hose->io_resource.end += io_virt_offset;
 
-	DBG("  hose->io_resource=0x%016lx...0x%016lx\n",
-	    hose->io_resource.start, hose->io_resource.end);
+	pr_debug("  hose->io_resource=0x%016lx...0x%016lx\n",
+		 hose->io_resource.start, hose->io_resource.end);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pcibios_map_io_space);
 
-void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
-{
-	struct pci_dev *dev;
-
-	if (ppc_md.pci_dma_bus_setup)
-		ppc_md.pci_dma_bus_setup(bus);
-
-	list_for_each_entry(dev, &bus->devices, bus_list)
-		pcibios_setup_new_device(dev);
-}
-
 unsigned long pci_address_to_pio(phys_addr_t address)
 {
 	struct pci_controller *hose, *tmp;
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 260089d..dcec132 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -116,12 +116,6 @@
 
 #ifndef CONFIG_PPC64
 EXPORT_SYMBOL(flush_instruction_cache);
-EXPORT_SYMBOL(flush_tlb_kernel_range);
-EXPORT_SYMBOL(flush_tlb_page);
-EXPORT_SYMBOL(_tlbie);
-#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE)
-EXPORT_SYMBOL(_tlbil_va);
-#endif
 #endif
 EXPORT_SYMBOL(__flush_icache_range);
 EXPORT_SYMBOL(flush_dcache_range);
@@ -174,8 +168,7 @@
 #endif
 
 #ifdef CONFIG_PPC32
-EXPORT_SYMBOL(next_mmu_context);
-EXPORT_SYMBOL(set_context);
+EXPORT_SYMBOL(switch_mmu_context);
 #endif
 
 #ifdef CONFIG_PPC_STD_MMU_32
diff --git a/arch/powerpc/xmon/setjmp.S b/arch/powerpc/kernel/ppc_save_regs.S
similarity index 98%
rename from arch/powerpc/xmon/setjmp.S
rename to arch/powerpc/kernel/ppc_save_regs.S
index 04c0b30..5113bd2 100644
--- a/arch/powerpc/xmon/setjmp.S
+++ b/arch/powerpc/kernel/ppc_save_regs.S
@@ -22,7 +22,7 @@
  * that will be different for 32-bit and 64-bit, because of the
  * different ABIs, though).
  */
-_GLOBAL(xmon_save_regs)
+_GLOBAL(ppc_save_regs)
 	PPC_STL	r0,0*SZL(r3)
 	PPC_STL	r2,2*SZL(r3)
 	PPC_STL	r3,3*SZL(r3)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 957bded..51b201d 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -467,6 +467,8 @@
 	{MSR_VEC,	"VEC"},
 	{MSR_VSX,	"VSX"},
 	{MSR_ME,	"ME"},
+	{MSR_CE,	"CE"},
+	{MSR_DE,	"DE"},
 	{MSR_IR,	"IR"},
 	{MSR_DR,	"DR"},
 	{0,		NULL}
@@ -998,7 +1000,7 @@
 	return 0;
 }
 
-static int kstack_depth_to_print = 64;
+static int kstack_depth_to_print = CONFIG_PRINT_STACK_DEPTH;
 
 void show_stack(struct task_struct *tsk, unsigned long *stack)
 {
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 3a2dc7e..6f73c73 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -1160,6 +1160,8 @@
 
 void __init early_init_devtree(void *params)
 {
+	unsigned long limit;
+
 	DBG(" -> early_init_devtree(%p)\n", params);
 
 	/* Setup flat device-tree pointer */
@@ -1200,7 +1202,19 @@
 	early_reserve_mem();
 	phyp_dump_reserve_mem();
 
-	lmb_enforce_memory_limit(memory_limit);
+	limit = memory_limit;
+	if (! limit) {
+		unsigned long memsize;
+
+		/* Ensure that total memory size is page-aligned, because
+		 * otherwise mark_bootmem() gets upset. */
+		lmb_analyze();
+		memsize = lmb_phys_mem_size();
+		if ((memsize & PAGE_MASK) != memsize)
+			limit = memsize & PAGE_MASK;
+	}
+	lmb_enforce_memory_limit(limit);
+
 	lmb_analyze();
 
 	DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
@@ -1271,6 +1285,37 @@
 EXPORT_SYMBOL(of_find_node_by_phandle);
 
 /**
+ *	of_find_next_cache_node - Find a node's subsidiary cache
+ *	@np:	node of type "cpu" or "cache"
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.  Caller should hold a reference
+ *	to np.
+ */
+struct device_node *of_find_next_cache_node(struct device_node *np)
+{
+	struct device_node *child;
+	const phandle *handle;
+
+	handle = of_get_property(np, "l2-cache", NULL);
+	if (!handle)
+		handle = of_get_property(np, "next-level-cache", NULL);
+
+	if (handle)
+		return of_find_node_by_phandle(*handle);
+
+	/* OF on pmac has nodes instead of properties named "l2-cache"
+	 * beneath CPU nodes.
+	 */
+	if (!strcmp(np->type, "cpu"))
+		for_each_child_of_node(np, child)
+			if (!strcmp(child->type, "cache"))
+				return child;
+
+	return NULL;
+}
+
+/**
  *	of_find_all_nodes - Get next node in global list
  *	@prev:	Previous node or NULL to start iteration
  *		of_node_put() will be called on it
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index a11d689..8c13355 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -734,10 +734,7 @@
 	if (flags & OF_IMAP_NO_PHANDLE) {
 		struct device_node *np;
 
-		for(np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
-			if (of_get_property(np, "interrupt-controller", NULL)
-			    == NULL)
-				continue;
+		for_each_node_with_property(np, "interrupt-controller") {
 			/* Skip /chosen/interrupt-controller */
 			if (strcmp(np->name, "chosen") == 0)
 				continue;
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 1f8505c..fdfe14c 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -566,6 +566,32 @@
 }
 EXPORT_SYMBOL(rtas_get_sensor);
 
+bool rtas_indicator_present(int token, int *maxindex)
+{
+	int proplen, count, i;
+	const struct indicator_elem {
+		u32 token;
+		u32 maxindex;
+	} *indicators;
+
+	indicators = of_get_property(rtas.dev, "rtas-indicators", &proplen);
+	if (!indicators)
+		return false;
+
+	count = proplen / sizeof(struct indicator_elem);
+
+	for (i = 0; i < count; i++) {
+		if (indicators[i].token != token)
+			continue;
+		if (maxindex)
+			*maxindex = indicators[i].maxindex;
+		return true;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL(rtas_indicator_present);
+
 int rtas_set_indicator(int indicator, int index, int new_value)
 {
 	int token = rtas_token("set-indicator");
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index 589a279..8869001 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -301,51 +301,3 @@
 #endif /* CONFIG_PPC32 */
 	}
 }
-
-/* RPA-specific bits for removing PHBs */
-int pcibios_remove_root_bus(struct pci_controller *phb)
-{
-	struct pci_bus *b = phb->bus;
-	struct resource *res;
-	int rc, i;
-
-	res = b->resource[0];
-	if (!res->flags) {
-		printk(KERN_ERR "%s: no IO resource for PHB %s\n", __func__,
-				b->name);
-		return 1;
-	}
-
-	rc = pcibios_unmap_io_space(b);
-	if (rc) {
-		printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
-			__func__, b->name);
-		return 1;
-	}
-
-	if (release_resource(res)) {
-		printk(KERN_ERR "%s: failed to release IO on bus %s\n",
-				__func__, b->name);
-		return 1;
-	}
-
-	for (i = 1; i < 3; ++i) {
-		res = b->resource[i];
-		if (!res->flags && i == 0) {
-			printk(KERN_ERR "%s: no MEM resource for PHB %s\n",
-				__func__, b->name);
-			return 1;
-		}
-		if (res->flags && release_resource(res)) {
-			printk(KERN_ERR
-			       "%s: failed to release IO %d on bus %s\n",
-				__func__, i, b->name);
-			return 1;
-		}
-	}
-
-	pcibios_free_controller(phb);
-
-	return 0;
-}
-EXPORT_SYMBOL(pcibios_remove_root_bus);
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index c1a2762..9e1ca74 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -38,6 +38,7 @@
 #include <asm/time.h>
 #include <asm/serial.h>
 #include <asm/udbg.h>
+#include <asm/mmu_context.h>
 
 #include "setup.h"
 
@@ -49,12 +50,12 @@
 EXPORT_SYMBOL_GPL(boot_cpuid);
 int boot_cpuid_phys;
 
+int smp_hw_index[NR_CPUS];
+
 unsigned long ISA_DMA_THRESHOLD;
 unsigned int DMA_MODE_READ;
 unsigned int DMA_MODE_WRITE;
 
-int have_of = 1;
-
 #ifdef CONFIG_VGA_CONSOLE
 unsigned long vgacon_remap_base;
 EXPORT_SYMBOL(vgacon_remap_base);
@@ -97,6 +98,10 @@
 			  PTRRELOC(&__start___ftr_fixup),
 			  PTRRELOC(&__stop___ftr_fixup));
 
+	do_feature_fixups(spec->mmu_features,
+			  PTRRELOC(&__start___mmu_ftr_fixup),
+			  PTRRELOC(&__stop___mmu_ftr_fixup));
+
 	do_lwsync_fixups(spec->cpu_features,
 			 PTRRELOC(&__start___lwsync_fixup),
 			 PTRRELOC(&__stop___lwsync_fixup));
@@ -121,6 +126,8 @@
 
 	probe_machine();
 
+	setup_kdump_trampoline();
+
 #ifdef CONFIG_6xx
 	if (cpu_has_feature(CPU_FTR_CAN_DOZE) ||
 	    cpu_has_feature(CPU_FTR_CAN_NAP))
@@ -326,4 +333,8 @@
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 
 	paging_init();
+
+	/* Initialize the MMU context management stuff */
+	mmu_context_init();
+
 }
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 169d74c..d8bd216 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -70,7 +70,6 @@
 #define DBG(fmt...)
 #endif
 
-int have_of = 1;
 int boot_cpuid = 0;
 u64 ppc64_pft_size;
 
@@ -362,6 +361,8 @@
 	 */
 	do_feature_fixups(cur_cpu_spec->cpu_features,
 			  &__start___ftr_fixup, &__stop___ftr_fixup);
+	do_feature_fixups(cur_cpu_spec->mmu_features,
+			  &__start___mmu_ftr_fixup, &__stop___mmu_ftr_fixup);
 	do_feature_fixups(powerpc_firmware_features,
 			  &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
 	do_lwsync_fixups(cur_cpu_spec->cpu_features,
@@ -606,8 +607,6 @@
 
 	for_each_possible_cpu(i) {
 		ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size);
-		if (!ptr)
-			panic("Cannot allocate cpu data for CPU %d\n", i);
 
 		paca[i].data_offset = ptr - __per_cpu_start;
 		memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
diff --git a/arch/powerpc/kernel/smp-tbsync.c b/arch/powerpc/kernel/smp-tbsync.c
index bc892e69..a5e5452 100644
--- a/arch/powerpc/kernel/smp-tbsync.c
+++ b/arch/powerpc/kernel/smp-tbsync.c
@@ -113,7 +113,7 @@
 {
 	int i, score, score2, old, min=0, max=5000, offset=1000;
 
-	printk("Synchronizing timebase\n");
+	pr_debug("Software timebase sync\n");
 
 	/* if this fails then this kernel won't work anyway... */
 	tbsync = kzalloc( sizeof(*tbsync), GFP_KERNEL );
@@ -123,13 +123,13 @@
 	while (!tbsync->ack)
 		barrier();
 
-	printk("Got ack\n");
+	pr_debug("Got ack\n");
 
 	/* binary search */
 	for (old = -1; old != offset ; offset = (min+max) / 2) {
 		score = start_contest(kSetAndTest, offset, NUM_ITER);
 
-		printk("score %d, offset %d\n", score, offset );
+		pr_debug("score %d, offset %d\n", score, offset );
 
 		if( score > 0 )
 			max = offset;
@@ -140,8 +140,8 @@
 	score = start_contest(kSetAndTest, min, NUM_ITER);
 	score2 = start_contest(kSetAndTest, max, NUM_ITER);
 
-	printk("Min %d (score %d), Max %d (score %d)\n",
-	       min, score, max, score2);
+	pr_debug("Min %d (score %d), Max %d (score %d)\n",
+		 min, score, max, score2);
 	score = abs(score);
 	score2 = abs(score2);
 	offset = (score < score2) ? min : max;
@@ -155,7 +155,7 @@
 		if (score2 <= score || score2 < 20)
 			break;
 	}
-	printk("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER );
+	pr_debug("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER );
 
 	/* exiting */
 	tbsync->cmd = kExit;
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index ff9f701..8ac3f72 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -57,7 +57,6 @@
 #define DBG(fmt...)
 #endif
 
-int smp_hw_index[NR_CPUS];
 struct thread_info *secondary_ti;
 
 cpumask_t cpu_possible_map = CPU_MASK_NONE;
@@ -123,6 +122,65 @@
 	}
 }
 
+static irqreturn_t call_function_action(int irq, void *data)
+{
+	generic_smp_call_function_interrupt();
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t reschedule_action(int irq, void *data)
+{
+	/* we just need the return path side effect of checking need_resched */
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t call_function_single_action(int irq, void *data)
+{
+	generic_smp_call_function_single_interrupt();
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t debug_ipi_action(int irq, void *data)
+{
+	smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
+	return IRQ_HANDLED;
+}
+
+static irq_handler_t smp_ipi_action[] = {
+	[PPC_MSG_CALL_FUNCTION] =  call_function_action,
+	[PPC_MSG_RESCHEDULE] = reschedule_action,
+	[PPC_MSG_CALL_FUNC_SINGLE] = call_function_single_action,
+	[PPC_MSG_DEBUGGER_BREAK] = debug_ipi_action,
+};
+
+const char *smp_ipi_name[] = {
+	[PPC_MSG_CALL_FUNCTION] =  "ipi call function",
+	[PPC_MSG_RESCHEDULE] = "ipi reschedule",
+	[PPC_MSG_CALL_FUNC_SINGLE] = "ipi call function single",
+	[PPC_MSG_DEBUGGER_BREAK] = "ipi debugger",
+};
+
+/* optional function to request ipi, for controllers with >= 4 ipis */
+int smp_request_message_ipi(int virq, int msg)
+{
+	int err;
+
+	if (msg < 0 || msg > PPC_MSG_DEBUGGER_BREAK) {
+		return -EINVAL;
+	}
+#if !defined(CONFIG_DEBUGGER) && !defined(CONFIG_KEXEC)
+	if (msg == PPC_MSG_DEBUGGER_BREAK) {
+		return 1;
+	}
+#endif
+	err = request_irq(virq, smp_ipi_action[msg], IRQF_DISABLED|IRQF_PERCPU,
+			  smp_ipi_name[msg], 0);
+	WARN(err < 0, "unable to request_irq %d for %s (rc %d)\n",
+		virq, smp_ipi_name[msg], err);
+
+	return err;
+}
+
 void smp_send_reschedule(int cpu)
 {
 	if (likely(smp_ops))
@@ -408,8 +466,7 @@
 static struct device_node *cpu_to_l2cache(int cpu)
 {
 	struct device_node *np;
-	const phandle *php;
-	phandle ph;
+	struct device_node *cache;
 
 	if (!cpu_present(cpu))
 		return NULL;
@@ -418,13 +475,11 @@
 	if (np == NULL)
 		return NULL;
 
-	php = of_get_property(np, "l2-cache", NULL);
-	if (php == NULL)
-		return NULL;
-	ph = *php;
+	cache = of_find_next_cache_node(np);
+
 	of_node_put(np);
 
-	return of_find_node_by_phandle(ph);
+	return cache;
 }
 
 /* Activate a secondary processor. */
diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c
index 77b7b34..560c961 100644
--- a/arch/powerpc/kernel/swsusp.c
+++ b/arch/powerpc/kernel/swsusp.c
@@ -34,6 +34,6 @@
 void restore_processor_state(void)
 {
 #ifdef CONFIG_PPC32
-	set_context(current->active_mm->context.id, current->active_mm->pgd);
+	switch_mmu_context(NULL, current->active_mm);
 #endif
 }
diff --git a/arch/powerpc/kernel/swsusp_32.S b/arch/powerpc/kernel/swsusp_32.S
index 77fc766..b47d8ce 100644
--- a/arch/powerpc/kernel/swsusp_32.S
+++ b/arch/powerpc/kernel/swsusp_32.S
@@ -5,7 +5,7 @@
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
-
+#include <asm/mmu.h>
 
 /*
  * Structure for storing CPU registers on the save area.
@@ -279,7 +279,7 @@
 	mtibatl	3,r4
 #endif
 
-BEGIN_FTR_SECTION
+BEGIN_MMU_FTR_SECTION
 	li	r4,0
 	mtspr	SPRN_DBAT4U,r4
 	mtspr	SPRN_DBAT4L,r4
@@ -297,7 +297,7 @@
 	mtspr	SPRN_IBAT6L,r4
 	mtspr	SPRN_IBAT7U,r4
 	mtspr	SPRN_IBAT7L,r4
-END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
 
 	/* Flush all TLBs */
 	lis	r4,0x1000
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 20885a3..0c64f10 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -566,7 +566,6 @@
 
 static struct cache_desc * __cpuinit create_cache_index_info(struct device_node *np, struct kobject *parent, int index, int level)
 {
-	const phandle *next_cache_phandle;
 	struct device_node *next_cache;
 	struct cache_desc *new, **end;
 
@@ -591,11 +590,7 @@
 	while (*end)
 		end = &(*end)->next;
 
-	next_cache_phandle = of_get_property(np, "l2-cache", NULL);
-	if (!next_cache_phandle)
-		goto out;
-
-	next_cache = of_find_node_by_phandle(*next_cache_phandle);
+	next_cache = of_find_next_cache_node(np);
 	if (!next_cache)
 		goto out;
 
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index e2ee66b..e1f3a51 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -164,8 +164,6 @@
 static unsigned tb_to_ns_shift __read_mostly;
 static unsigned long boot_tb __read_mostly;
 
-static struct gettimeofday_struct do_gtod;
-
 extern struct timezone sys_tz;
 static long timezone_offset;
 
@@ -415,31 +413,9 @@
 }
 EXPORT_SYMBOL(udelay);
 
-
-/*
- * There are two copies of tb_to_xs and stamp_xsec so that no
- * lock is needed to access and use these values in
- * do_gettimeofday.  We alternate the copies and as long as a
- * reasonable time elapses between changes, there will never
- * be inconsistent values.  ntpd has a minimum of one minute
- * between updates.
- */
 static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec,
 			       u64 new_tb_to_xs)
 {
-	unsigned temp_idx;
-	struct gettimeofday_vars *temp_varp;
-
-	temp_idx = (do_gtod.var_idx == 0);
-	temp_varp = &do_gtod.vars[temp_idx];
-
-	temp_varp->tb_to_xs = new_tb_to_xs;
-	temp_varp->tb_orig_stamp = new_tb_stamp;
-	temp_varp->stamp_xsec = new_stamp_xsec;
-	smp_mb();
-	do_gtod.varp = temp_varp;
-	do_gtod.var_idx = temp_idx;
-
 	/*
 	 * tb_update_count is used to allow the userspace gettimeofday code
 	 * to assure itself that it sees a consistent view of the tb_to_xs and
@@ -456,6 +432,7 @@
 	vdso_data->tb_to_xs = new_tb_to_xs;
 	vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec;
 	vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec;
+	vdso_data->stamp_xtime = xtime;
 	smp_wmb();
 	++(vdso_data->tb_update_count);
 }
@@ -514,9 +491,7 @@
 				tb_ticks_per_sec   = new_tb_ticks_per_sec;
 				calc_cputime_factors();
 				div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres );
-				do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
 				tb_to_xs = divres.result_low;
-				do_gtod.varp->tb_to_xs = tb_to_xs;
 				vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
 				vdso_data->tb_to_xs = tb_to_xs;
 			}
@@ -988,15 +963,6 @@
 		sys_tz.tz_dsttime = 0;
         }
 
-	do_gtod.varp = &do_gtod.vars[0];
-	do_gtod.var_idx = 0;
-	do_gtod.varp->tb_orig_stamp = tb_last_jiffy;
-	__get_cpu_var(last_jiffy) = tb_last_jiffy;
-	do_gtod.varp->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC;
-	do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
-	do_gtod.varp->tb_to_xs = tb_to_xs;
-	do_gtod.tb_to_us = tb_to_us;
-
 	vdso_data->tb_orig_stamp = tb_last_jiffy;
 	vdso_data->tb_update_count = 0;
 	vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index f5def6c..5457e95 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1160,37 +1160,85 @@
 #ifdef CONFIG_SPE
 void SPEFloatingPointException(struct pt_regs *regs)
 {
+	extern int do_spe_mathemu(struct pt_regs *regs);
 	unsigned long spefscr;
 	int fpexc_mode;
 	int code = 0;
+	int err;
+
+	preempt_disable();
+	if (regs->msr & MSR_SPE)
+		giveup_spe(current);
+	preempt_enable();
 
 	spefscr = current->thread.spefscr;
 	fpexc_mode = current->thread.fpexc_mode;
 
-	/* Hardware does not neccessarily set sticky
-	 * underflow/overflow/invalid flags */
 	if ((spefscr & SPEFSCR_FOVF) && (fpexc_mode & PR_FP_EXC_OVF)) {
 		code = FPE_FLTOVF;
-		spefscr |= SPEFSCR_FOVFS;
 	}
 	else if ((spefscr & SPEFSCR_FUNF) && (fpexc_mode & PR_FP_EXC_UND)) {
 		code = FPE_FLTUND;
-		spefscr |= SPEFSCR_FUNFS;
 	}
 	else if ((spefscr & SPEFSCR_FDBZ) && (fpexc_mode & PR_FP_EXC_DIV))
 		code = FPE_FLTDIV;
 	else if ((spefscr & SPEFSCR_FINV) && (fpexc_mode & PR_FP_EXC_INV)) {
 		code = FPE_FLTINV;
-		spefscr |= SPEFSCR_FINVS;
 	}
 	else if ((spefscr & (SPEFSCR_FG | SPEFSCR_FX)) && (fpexc_mode & PR_FP_EXC_RES))
 		code = FPE_FLTRES;
 
-	current->thread.spefscr = spefscr;
+	err = do_spe_mathemu(regs);
+	if (err == 0) {
+		regs->nip += 4;		/* skip emulated instruction */
+		emulate_single_step(regs);
+		return;
+	}
 
-	_exception(SIGFPE, regs, code, regs->nip);
+	if (err == -EFAULT) {
+		/* got an error reading the instruction */
+		_exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip);
+	} else if (err == -EINVAL) {
+		/* didn't recognize the instruction */
+		printk(KERN_ERR "unrecognized spe instruction "
+		       "in %s at %lx\n", current->comm, regs->nip);
+	} else {
+		_exception(SIGFPE, regs, code, regs->nip);
+	}
+
 	return;
 }
+
+void SPEFloatingPointRoundException(struct pt_regs *regs)
+{
+	extern int speround_handler(struct pt_regs *regs);
+	int err;
+
+	preempt_disable();
+	if (regs->msr & MSR_SPE)
+		giveup_spe(current);
+	preempt_enable();
+
+	regs->nip -= 4;
+	err = speround_handler(regs);
+	if (err == 0) {
+		regs->nip += 4;		/* skip emulated instruction */
+		emulate_single_step(regs);
+		return;
+	}
+
+	if (err == -EFAULT) {
+		/* got an error reading the instruction */
+		_exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip);
+	} else if (err == -EINVAL) {
+		/* didn't recognize the instruction */
+		printk(KERN_ERR "unrecognized spe instruction "
+		       "in %s at %lx\n", current->comm, regs->nip);
+	} else {
+		_exception(SIGFPE, regs, 0, regs->nip);
+		return;
+	}
+}
 #endif
 
 /*
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 65639a4..ad06d5c 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -184,8 +184,7 @@
  * This is called from binfmt_elf, we create the special vma for the
  * vDSO and insert it into the mm struct tree
  */
-int arch_setup_additional_pages(struct linux_binprm *bprm,
-				int executable_stack)
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
 	struct page **vdso_pagelist;
@@ -567,6 +566,11 @@
 		do_feature_fixups(cur_cpu_spec->cpu_features,
 				  start64, start64 + size64);
 
+	start64 = find_section64(v64->hdr, "__mmu_ftr_fixup", &size64);
+	if (start64)
+		do_feature_fixups(cur_cpu_spec->mmu_features,
+				  start64, start64 + size64);
+
 	start64 = find_section64(v64->hdr, "__fw_ftr_fixup", &size64);
 	if (start64)
 		do_feature_fixups(powerpc_firmware_features,
@@ -583,6 +587,11 @@
 		do_feature_fixups(cur_cpu_spec->cpu_features,
 				  start32, start32 + size32);
 
+	start32 = find_section32(v32->hdr, "__mmu_ftr_fixup", &size32);
+	if (start32)
+		do_feature_fixups(cur_cpu_spec->mmu_features,
+				  start32, start32 + size32);
+
 #ifdef CONFIG_PPC64
 	start32 = find_section32(v32->hdr, "__fw_ftr_fixup", &size32);
 	if (start32)
diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
index 72ca26d..ee038d4 100644
--- a/arch/powerpc/kernel/vdso32/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
@@ -16,6 +16,13 @@
 #include <asm/asm-offsets.h>
 #include <asm/unistd.h>
 
+/* Offset for the low 32-bit part of a field of long type */
+#ifdef CONFIG_PPC64
+#define LOPART	4
+#else
+#define LOPART	0
+#endif
+
 	.text
 /*
  * Exact prototype of gettimeofday
@@ -90,101 +97,53 @@
 
 	mflr	r12			/* r12 saves lr */
   .cfi_register lr,r12
-	mr	r10,r3			/* r10 saves id */
 	mr	r11,r4			/* r11 saves tp */
 	bl	__get_datapage@local	/* get data page */
 	mr	r9,r3			/* datapage ptr in r9 */
-	beq	cr1,50f			/* if monotonic -> jump there */
 
-	/*
-	 * CLOCK_REALTIME
-	 */
-
-	bl	__do_get_xsec@local	/* get xsec from tb & kernel */
-	bne-	98f			/* out of line -> do syscall */
-
-	/* seconds are xsec >> 20 */
-	rlwinm	r5,r4,12,20,31
-	rlwimi	r5,r3,12,0,19
-	stw	r5,TSPC32_TV_SEC(r11)
-
-	/* get remaining xsec and convert to nsec. we scale
-	 * up remaining xsec by 12 bits and get the top 32 bits
-	 * of the multiplication, then we multiply by 1000
-	 */
-	rlwinm	r5,r4,12,0,19
-	lis	r6,1000000@h
-	ori	r6,r6,1000000@l
-	mulhwu	r5,r5,r6
-	mulli	r5,r5,1000
-	stw	r5,TSPC32_TV_NSEC(r11)
-	mtlr	r12
-	crclr	cr0*4+so
-	li	r3,0
-	blr
+50:	bl	__do_get_tspec@local	/* get sec/nsec from tb & kernel */
+	bne	cr1,80f			/* not monotonic -> all done */
 
 	/*
 	 * CLOCK_MONOTONIC
 	 */
 
-50:	bl	__do_get_xsec@local	/* get xsec from tb & kernel */
-	bne-	98f			/* out of line -> do syscall */
-
-	/* seconds are xsec >> 20 */
-	rlwinm	r6,r4,12,20,31
-	rlwimi	r6,r3,12,0,19
-
-	/* get remaining xsec and convert to nsec. we scale
-	 * up remaining xsec by 12 bits and get the top 32 bits
-	 * of the multiplication, then we multiply by 1000
-	 */
-	rlwinm	r7,r4,12,0,19
-	lis	r5,1000000@h
-	ori	r5,r5,1000000@l
-	mulhwu	r7,r7,r5
-	mulli	r7,r7,1000
-
 	/* now we must fixup using wall to monotonic. We need to snapshot
 	 * that value and do the counter trick again. Fortunately, we still
 	 * have the counter value in r8 that was returned by __do_get_xsec.
-	 * At this point, r6,r7 contain our sec/nsec values, r3,r4 and r5
-	 * can be used
+	 * At this point, r3,r4 contain our sec/nsec values, r5 and r6
+	 * can be used, r7 contains NSEC_PER_SEC.
 	 */
 
-	lwz	r3,WTOM_CLOCK_SEC(r9)
-	lwz	r4,WTOM_CLOCK_NSEC(r9)
+	lwz	r5,WTOM_CLOCK_SEC(r9)
+	lwz	r6,WTOM_CLOCK_NSEC(r9)
 
-	/* We now have our result in r3,r4. We create a fake dependency
-	 * on that result and re-check the counter
+	/* We now have our offset in r5,r6. We create a fake dependency
+	 * on that value and re-check the counter
 	 */
-	or	r5,r4,r3
-	xor	r0,r5,r5
+	or	r0,r6,r5
+	xor	r0,r0,r0
 	add	r9,r9,r0
-#ifdef CONFIG_PPC64
-	lwz	r0,(CFG_TB_UPDATE_COUNT+4)(r9)
-#else
-	lwz	r0,(CFG_TB_UPDATE_COUNT)(r9)
-#endif
+	lwz	r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
         cmpl    cr0,r8,r0		/* check if updated */
 	bne-	50b
 
-	/* Calculate and store result. Note that this mimmics the C code,
+	/* Calculate and store result. Note that this mimics the C code,
 	 * which may cause funny results if nsec goes negative... is that
 	 * possible at all ?
 	 */
-	add	r3,r3,r6
-	add	r4,r4,r7
-	lis	r5,NSEC_PER_SEC@h
-	ori	r5,r5,NSEC_PER_SEC@l
-	cmpl	cr0,r4,r5
-	cmpli	cr1,r4,0
+	add	r3,r3,r5
+	add	r4,r4,r6
+	cmpw	cr0,r4,r7
+	cmpwi	cr1,r4,0
 	blt	1f
-	subf	r4,r5,r4
+	subf	r4,r7,r4
 	addi	r3,r3,1
-1:	bge	cr1,1f
+1:	bge	cr1,80f
 	addi	r3,r3,-1
-	add	r4,r4,r5
-1:	stw	r3,TSPC32_TV_SEC(r11)
+	add	r4,r4,r7
+
+80:	stw	r3,TSPC32_TV_SEC(r11)
 	stw	r4,TSPC32_TV_NSEC(r11)
 
 	mtlr	r12
@@ -195,10 +154,6 @@
 	/*
 	 * syscall fallback
 	 */
-98:
-	mtlr	r12
-	mr	r3,r10
-	mr	r4,r11
 99:
 	li	r0,__NR_clock_gettime
 	sc
@@ -254,11 +209,7 @@
 	/* Check for update count & load values. We use the low
 	 * order 32 bits of the update count
 	 */
-#ifdef CONFIG_PPC64
-1:	lwz	r8,(CFG_TB_UPDATE_COUNT+4)(r9)
-#else
-1:	lwz	r8,(CFG_TB_UPDATE_COUNT)(r9)
-#endif
+1:	lwz	r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
 	andi.	r0,r8,1			/* pending update ? loop */
 	bne-	1b
 	xor	r0,r8,r8		/* create dependency */
@@ -305,11 +256,7 @@
 	or	r6,r4,r3
 	xor	r0,r6,r6
 	add	r9,r9,r0
-#ifdef CONFIG_PPC64
-	lwz	r0,(CFG_TB_UPDATE_COUNT+4)(r9)
-#else
-	lwz	r0,(CFG_TB_UPDATE_COUNT)(r9)
-#endif
+	lwz	r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
         cmpl    cr0,r8,r0		/* check if updated */
 	bne-	1b
 
@@ -322,3 +269,98 @@
 	 */
 3:	blr
   .cfi_endproc
+
+/*
+ * This is the core of clock_gettime(), it returns the current
+ * time in seconds and nanoseconds in r3 and r4.
+ * It expects the datapage ptr in r9 and doesn't clobber it.
+ * It clobbers r0, r5, r6, r10 and returns NSEC_PER_SEC in r7.
+ * On return, r8 contains the counter value that can be reused.
+ * This clobbers cr0 but not any other cr field.
+ */
+__do_get_tspec:
+  .cfi_startproc
+	/* Check for update count & load values. We use the low
+	 * order 32 bits of the update count
+	 */
+1:	lwz	r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
+	andi.	r0,r8,1			/* pending update ? loop */
+	bne-	1b
+	xor	r0,r8,r8		/* create dependency */
+	add	r9,r9,r0
+
+	/* Load orig stamp (offset to TB) */
+	lwz	r5,CFG_TB_ORIG_STAMP(r9)
+	lwz	r6,(CFG_TB_ORIG_STAMP+4)(r9)
+
+	/* Get a stable TB value */
+2:	mftbu	r3
+	mftbl	r4
+	mftbu	r0
+	cmpl	cr0,r3,r0
+	bne-	2b
+
+	/* Subtract tb orig stamp and shift left 12 bits.
+	 */
+	subfc	r7,r6,r4
+	subfe	r0,r5,r3
+	slwi	r0,r0,12
+	rlwimi.	r0,r7,12,20,31
+	slwi	r7,r7,12
+
+	/* Load scale factor & do multiplication */
+	lwz	r5,CFG_TB_TO_XS(r9)	/* load values */
+	lwz	r6,(CFG_TB_TO_XS+4)(r9)
+	mulhwu	r3,r7,r6
+	mullw	r10,r7,r5
+	mulhwu	r4,r7,r5
+	addc	r10,r3,r10
+	li	r3,0
+
+	beq+	4f			/* skip high part computation if 0 */
+	mulhwu	r3,r0,r5
+	mullw	r7,r0,r5
+	mulhwu	r5,r0,r6
+	mullw	r6,r0,r6
+	adde	r4,r4,r7
+	addze	r3,r3
+	addc	r4,r4,r5
+	addze	r3,r3
+	addc	r10,r10,r6
+
+4:	addze	r4,r4			/* add in carry */
+	lis	r7,NSEC_PER_SEC@h
+	ori	r7,r7,NSEC_PER_SEC@l
+	mulhwu	r4,r4,r7		/* convert to nanoseconds */
+
+	/* At this point, we have seconds & nanoseconds since the xtime
+	 * stamp in r3+CA and r4.  Load & add the xtime stamp.
+	 */
+#ifdef CONFIG_PPC64
+	lwz	r5,STAMP_XTIME+TSPC64_TV_SEC+LOPART(r9)
+	lwz	r6,STAMP_XTIME+TSPC64_TV_NSEC+LOPART(r9)
+#else
+	lwz	r5,STAMP_XTIME+TSPC32_TV_SEC(r9)
+	lwz	r6,STAMP_XTIME+TSPC32_TV_NSEC(r9)
+#endif
+	add	r4,r4,r6
+	adde	r3,r3,r5
+
+	/* We now have our result in r3,r4. We create a fake dependency
+	 * on that result and re-check the counter
+	 */
+	or	r6,r4,r3
+	xor	r0,r6,r6
+	add	r9,r9,r0
+	lwz	r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
+        cmpl    cr0,r8,r0		/* check if updated */
+	bne-	1b
+
+	/* check for nanosecond overflow and adjust if necessary */
+	cmpw	r4,r7
+	bltlr				/* all done if no overflow */
+	subf	r4,r7,r4		/* adjust if overflow */
+	addi	r3,r3,1
+
+	blr
+  .cfi_endproc
diff --git a/arch/powerpc/kernel/vdso32/vdso32.lds.S b/arch/powerpc/kernel/vdso32/vdso32.lds.S
index be3b6a4..904ef13 100644
--- a/arch/powerpc/kernel/vdso32/vdso32.lds.S
+++ b/arch/powerpc/kernel/vdso32/vdso32.lds.S
@@ -34,6 +34,9 @@
 	__ftr_fixup	: { *(__ftr_fixup) }
 
 	. = ALIGN(8);
+	__mmu_ftr_fixup	: { *(__mmu_ftr_fixup) }
+
+	. = ALIGN(8);
 	__lwsync_fixup	: { *(__lwsync_fixup) }
 
 #ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S
index c6401f9..262cd58 100644
--- a/arch/powerpc/kernel/vdso64/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso64/gettimeofday.S
@@ -75,90 +75,49 @@
 
 	mflr	r12			/* r12 saves lr */
   .cfi_register lr,r12
-	mr	r10,r3			/* r10 saves id */
 	mr	r11,r4			/* r11 saves tp */
 	bl	V_LOCAL_FUNC(__get_datapage)	/* get data page */
-	beq	cr1,50f			/* if monotonic -> jump there */
-
-	/*
-	 * CLOCK_REALTIME
-	 */
-
-	bl	V_LOCAL_FUNC(__do_get_xsec)	/* get xsec from tb & kernel */
-
-	lis     r7,15			/* r7 = 1000000 = USEC_PER_SEC */
-	ori     r7,r7,16960
-	rldicl  r5,r4,44,20		/* r5 = sec = xsec / XSEC_PER_SEC */
-	rldicr  r6,r5,20,43		/* r6 = sec * XSEC_PER_SEC */
-	std	r5,TSPC64_TV_SEC(r11)	/* store sec in tv */
-	subf	r0,r6,r4		/* r0 = xsec = (xsec - r6) */
-	mulld   r0,r0,r7		/* usec = (xsec * USEC_PER_SEC) /
-					 * XSEC_PER_SEC
-					 */
-	rldicl  r0,r0,44,20
-	mulli	r0,r0,1000		/* nsec = usec * 1000 */
-	std	r0,TSPC64_TV_NSEC(r11)	/* store nsec in tp */
-
-	mtlr	r12
-	crclr	cr0*4+so
-	li	r3,0
-	blr
+50:	bl	V_LOCAL_FUNC(__do_get_tspec)	/* get time from tb & kernel */
+	bne	cr1,80f			/* if not monotonic, all done */
 
 	/*
 	 * CLOCK_MONOTONIC
 	 */
 
-50:	bl	V_LOCAL_FUNC(__do_get_xsec)	/* get xsec from tb & kernel */
-
-	lis     r7,15			/* r7 = 1000000 = USEC_PER_SEC */
-	ori     r7,r7,16960
-	rldicl  r5,r4,44,20		/* r5 = sec = xsec / XSEC_PER_SEC */
-	rldicr  r6,r5,20,43		/* r6 = sec * XSEC_PER_SEC */
-	subf	r0,r6,r4		/* r0 = xsec = (xsec - r6) */
-	mulld   r0,r0,r7		/* usec = (xsec * USEC_PER_SEC) /
-					 * XSEC_PER_SEC
-					 */
-	rldicl  r6,r0,44,20
-	mulli	r6,r6,1000		/* nsec = usec * 1000 */
-
 	/* now we must fixup using wall to monotonic. We need to snapshot
 	 * that value and do the counter trick again. Fortunately, we still
-	 * have the counter value in r8 that was returned by __do_get_xsec.
-	 * At this point, r5,r6 contain our sec/nsec values.
-	 * can be used
+	 * have the counter value in r8 that was returned by __do_get_tspec.
+	 * At this point, r4,r5 contain our sec/nsec values.
 	 */
 
-	lwa	r4,WTOM_CLOCK_SEC(r3)
-	lwa	r7,WTOM_CLOCK_NSEC(r3)
+	lwa	r6,WTOM_CLOCK_SEC(r3)
+	lwa	r9,WTOM_CLOCK_NSEC(r3)
 
-	/* We now have our result in r4,r7. We create a fake dependency
+	/* We now have our result in r6,r9. We create a fake dependency
 	 * on that result and re-check the counter
 	 */
-	or	r9,r4,r7
-	xor	r0,r9,r9
+	or	r0,r6,r9
+	xor	r0,r0,r0
 	add	r3,r3,r0
 	ld	r0,CFG_TB_UPDATE_COUNT(r3)
         cmpld   cr0,r0,r8		/* check if updated */
 	bne-	50b
 
-	/* Calculate and store result. Note that this mimmics the C code,
-	 * which may cause funny results if nsec goes negative... is that
-	 * possible at all ?
+	/* Add wall->monotonic offset and check for overflow or underflow.
 	 */
-	add	r4,r4,r5
-	add	r7,r7,r6
-	lis	r9,NSEC_PER_SEC@h
-	ori	r9,r9,NSEC_PER_SEC@l
-	cmpl	cr0,r7,r9
-	cmpli	cr1,r7,0
+	add	r4,r4,r6
+	add	r5,r5,r9
+	cmpd	cr0,r5,r7
+	cmpdi	cr1,r5,0
 	blt	1f
-	subf	r7,r9,r7
+	subf	r5,r7,r5
 	addi	r4,r4,1
-1:	bge	cr1,1f
+1:	bge	cr1,80f
 	addi	r4,r4,-1
-	add	r7,r7,r9
-1:	std	r4,TSPC64_TV_SEC(r11)
-	std	r7,TSPC64_TV_NSEC(r11)
+	add	r5,r5,r7
+
+80:	std	r4,TSPC64_TV_SEC(r11)
+	std	r5,TSPC64_TV_NSEC(r11)
 
 	mtlr	r12
 	crclr	cr0*4+so
@@ -168,10 +127,6 @@
 	/*
 	 * syscall fallback
 	 */
-98:
-	mtlr	r12
-	mr	r3,r10
-	mr	r4,r11
 99:
 	li	r0,__NR_clock_gettime
 	sc
@@ -253,3 +208,59 @@
 	blr
   .cfi_endproc
 V_FUNCTION_END(__do_get_xsec)
+
+/*
+ * This is the core of clock_gettime(), it returns the current
+ * time in seconds and nanoseconds in r4 and r5.
+ * It expects the datapage ptr in r3 and doesn't clobber it.
+ * It clobbers r0 and r6 and returns NSEC_PER_SEC in r7.
+ * On return, r8 contains the counter value that can be reused.
+ * This clobbers cr0 but not any other cr field.
+ */
+V_FUNCTION_BEGIN(__do_get_tspec)
+  .cfi_startproc
+	/* check for update count & load values */
+1:	ld	r8,CFG_TB_UPDATE_COUNT(r3)
+	andi.	r0,r8,1			/* pending update ? loop */
+	bne-	1b
+	xor	r0,r8,r8		/* create dependency */
+	add	r3,r3,r0
+
+	/* Get TB & offset it. We use the MFTB macro which will generate
+	 * workaround code for Cell.
+	 */
+	MFTB(r7)
+	ld	r9,CFG_TB_ORIG_STAMP(r3)
+	subf	r7,r9,r7
+
+	/* Scale result */
+	ld	r5,CFG_TB_TO_XS(r3)
+	sldi	r7,r7,12		/* compute time since stamp_xtime */
+	mulhdu	r6,r7,r5		/* in units of 2^-32 seconds */
+
+	/* Add stamp since epoch */
+	ld	r4,STAMP_XTIME+TSPC64_TV_SEC(r3)
+	ld	r5,STAMP_XTIME+TSPC64_TV_NSEC(r3)
+	or	r0,r4,r5
+	or	r0,r0,r6
+	xor	r0,r0,r0
+	add	r3,r3,r0
+	ld	r0,CFG_TB_UPDATE_COUNT(r3)
+	cmpld   r0,r8			/* check if updated */
+	bne-	1b			/* reload if so */
+
+	/* convert to seconds & nanoseconds and add to stamp */
+	lis	r7,NSEC_PER_SEC@h
+	ori	r7,r7,NSEC_PER_SEC@l
+	mulhwu	r0,r6,r7		/* compute nanoseconds and */
+	srdi	r6,r6,32		/* seconds since stamp_xtime */
+	clrldi	r0,r0,32
+	add	r5,r5,r0		/* add nanoseconds together */
+	cmpd	r5,r7			/* overflow? */
+	add	r4,r4,r6
+	bltlr				/* all done if no overflow */
+	subf	r5,r7,r5		/* if overflow, adjust */
+	addi	r4,r4,1
+	blr
+  .cfi_endproc
+V_FUNCTION_END(__do_get_tspec)
diff --git a/arch/powerpc/kernel/vdso64/vdso64.lds.S b/arch/powerpc/kernel/vdso64/vdso64.lds.S
index d0b2526..0e61540 100644
--- a/arch/powerpc/kernel/vdso64/vdso64.lds.S
+++ b/arch/powerpc/kernel/vdso64/vdso64.lds.S
@@ -35,6 +35,9 @@
 	__ftr_fixup	: { *(__ftr_fixup) }
 
 	. = ALIGN(8);
+	__mmu_ftr_fixup	: { *(__mmu_ftr_fixup) }
+
+	. = ALIGN(8);
 	__lwsync_fixup	: { *(__lwsync_fixup) }
 
 	. = ALIGN(8);
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index a11e6bc..94aa7b0 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -41,9 +41,9 @@
 static struct bus_type vio_bus_type;
 
 static struct vio_dev vio_bus_device  = { /* fake "parent" device */
-	.name = vio_bus_device.dev.bus_id,
+	.name = "vio",
 	.type = "",
-	.dev.bus_id = "vio",
+	.dev.init_name = "vio",
 	.dev.bus = &vio_bus_type,
 };
 
@@ -1216,7 +1216,7 @@
 
 	viodev->irq = irq_of_parse_and_map(of_node, 0);
 
-	snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
+	dev_set_name(&viodev->dev, "%x", *unit_address);
 	viodev->name = of_node->name;
 	viodev->type = of_node->type;
 	viodev->unit_address = *unit_address;
@@ -1243,7 +1243,7 @@
 	/* register with generic device framework */
 	if (device_register(&viodev->dev)) {
 		printk(KERN_ERR "%s: failed to register device %s\n",
-				__func__, viodev->dev.bus_id);
+				__func__, dev_name(&viodev->dev));
 		/* XXX free TCE table */
 		kfree(viodev);
 		return NULL;
@@ -1400,13 +1400,13 @@
 struct vio_dev *vio_find_node(struct device_node *vnode)
 {
 	const uint32_t *unit_address;
-	char kobj_name[BUS_ID_SIZE];
+	char kobj_name[20];
 
 	/* construct the kobject name from the device node */
 	unit_address = of_get_property(vnode, "reg", NULL);
 	if (!unit_address)
 		return NULL;
-	snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
+	snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address);
 
 	return vio_find_name(kobj_name);
 }
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 2412c05..47bf15c 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -152,6 +152,12 @@
 		__stop___ftr_fixup = .;
 	}
 	. = ALIGN(8);
+	__mmu_ftr_fixup : AT(ADDR(__mmu_ftr_fixup) - LOAD_OFFSET) {
+		__start___mmu_ftr_fixup = .;
+		*(__mmu_ftr_fixup)
+		__stop___mmu_ftr_fixup = .;
+	}
+	. = ALIGN(8);
 	__lwsync_fixup : AT(ADDR(__lwsync_fixup) - LOAD_OFFSET) {
 		__start___lwsync_fixup = .;
 		*(__lwsync_fixup)
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index fda9baa..8bef0ef 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -28,6 +28,7 @@
 #include <asm/uaccess.h>
 #include <asm/kvm_ppc.h>
 #include <asm/tlbflush.h>
+#include "../mm/mmu_decl.h"
 
 
 gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
@@ -330,7 +331,7 @@
 	/* XXX It would be nice to differentiate between heavyweight exit and
 	 * sched_out here, since we could avoid the TLB flush for heavyweight
 	 * exits. */
-	_tlbia();
+	_tlbil_all();
 }
 
 int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index d69912c..8db3527 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -6,6 +6,9 @@
 EXTRA_CFLAGS		+= -mno-minimal-toc
 endif
 
+CFLAGS_REMOVE_code-patching.o = -pg
+CFLAGS_REMOVE_feature-fixups.o = -pg
+
 obj-y			:= string.o alloc.o \
 			   checksum_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_PPC32)	+= div64.o copy_32.o crtsavres.o
diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S
index 25ec537..70693a5 100644
--- a/arch/powerpc/lib/copyuser_64.S
+++ b/arch/powerpc/lib/copyuser_64.S
@@ -26,11 +26,24 @@
 	andi.	r6,r6,7
 	PPC_MTOCRF	0x01,r5
 	blt	cr1,.Lshort_copy
+/* Below we want to nop out the bne if we're on a CPU that has the
+ * CPU_FTR_UNALIGNED_LD_STD bit set and the CPU_FTR_CP_USE_DCBTZ bit
+ * cleared.
+ * At the time of writing the only CPU that has this combination of bits
+ * set is Power6.
+ */
+BEGIN_FTR_SECTION
+	nop
+FTR_SECTION_ELSE
 	bne	.Ldst_unaligned
+ALT_FTR_SECTION_END(CPU_FTR_UNALIGNED_LD_STD | CPU_FTR_CP_USE_DCBTZ, \
+		    CPU_FTR_UNALIGNED_LD_STD)
 .Ldst_aligned:
-	andi.	r0,r4,7
 	addi	r3,r3,-16
+BEGIN_FTR_SECTION
+	andi.	r0,r4,7
 	bne	.Lsrc_unaligned
+END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 	srdi	r7,r5,4
 20:	ld	r9,0(r4)
 	addi	r4,r4,-8
@@ -138,7 +151,7 @@
 	PPC_MTOCRF	0x01,r6		/* put #bytes to 8B bdry into cr7 */
 	subf	r5,r6,r5
 	li	r7,0
-	cmpldi	r1,r5,16
+	cmpldi	cr1,r5,16
 	bf	cr7*4+3,1f
 35:	lbz	r0,0(r4)
 81:	stb	r0,0(r3)
diff --git a/arch/powerpc/lib/dma-noncoherent.c b/arch/powerpc/lib/dma-noncoherent.c
index 31734c0..b7dc4c1 100644
--- a/arch/powerpc/lib/dma-noncoherent.c
+++ b/arch/powerpc/lib/dma-noncoherent.c
@@ -77,26 +77,26 @@
  * the amount of RAM found at boot time.)  I would imagine that get_vm_area()
  * would have to initialise this each time prior to calling vm_region_alloc().
  */
-struct vm_region {
+struct ppc_vm_region {
 	struct list_head	vm_list;
 	unsigned long		vm_start;
 	unsigned long		vm_end;
 };
 
-static struct vm_region consistent_head = {
+static struct ppc_vm_region consistent_head = {
 	.vm_list	= LIST_HEAD_INIT(consistent_head.vm_list),
 	.vm_start	= CONSISTENT_BASE,
 	.vm_end		= CONSISTENT_END,
 };
 
-static struct vm_region *
-vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp)
+static struct ppc_vm_region *
+ppc_vm_region_alloc(struct ppc_vm_region *head, size_t size, gfp_t gfp)
 {
 	unsigned long addr = head->vm_start, end = head->vm_end - size;
 	unsigned long flags;
-	struct vm_region *c, *new;
+	struct ppc_vm_region *c, *new;
 
-	new = kmalloc(sizeof(struct vm_region), gfp);
+	new = kmalloc(sizeof(struct ppc_vm_region), gfp);
 	if (!new)
 		goto out;
 
@@ -130,9 +130,9 @@
 	return NULL;
 }
 
-static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr)
+static struct ppc_vm_region *ppc_vm_region_find(struct ppc_vm_region *head, unsigned long addr)
 {
-	struct vm_region *c;
+	struct ppc_vm_region *c;
 
 	list_for_each_entry(c, &head->vm_list, vm_list) {
 		if (c->vm_start == addr)
@@ -151,7 +151,7 @@
 __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
 {
 	struct page *page;
-	struct vm_region *c;
+	struct ppc_vm_region *c;
 	unsigned long order;
 	u64 mask = 0x00ffffff, limit; /* ISA default */
 
@@ -191,7 +191,7 @@
 	/*
 	 * Allocate a virtual address in the consistent mapping region.
 	 */
-	c = vm_region_alloc(&consistent_head, size,
+	c = ppc_vm_region_alloc(&consistent_head, size,
 			    gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
 	if (c) {
 		unsigned long vaddr = c->vm_start;
@@ -239,7 +239,7 @@
  */
 void __dma_free_coherent(size_t size, void *vaddr)
 {
-	struct vm_region *c;
+	struct ppc_vm_region *c;
 	unsigned long flags, addr;
 	pte_t *ptep;
 
@@ -247,7 +247,7 @@
 
 	spin_lock_irqsave(&consistent_lock, flags);
 
-	c = vm_region_find(&consistent_head, (unsigned long)vaddr);
+	c = ppc_vm_region_find(&consistent_head, (unsigned long)vaddr);
 	if (!c)
 		goto no_area;
 
@@ -320,7 +320,6 @@
 			ret = -ENOMEM;
 			break;
 		}
-		WARN_ON(!pmd_none(*pmd));
 
 		pte = pte_alloc_kernel(pmd, CONSISTENT_BASE);
 		if (!pte) {
diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S
index 3f13112..fe2d34e 100644
--- a/arch/powerpc/lib/memcpy_64.S
+++ b/arch/powerpc/lib/memcpy_64.S
@@ -18,11 +18,23 @@
 	andi.	r6,r6,7
 	dcbt	0,r4
 	blt	cr1,.Lshort_copy
+/* Below we want to nop out the bne if we're on a CPU that has the
+   CPU_FTR_UNALIGNED_LD_STD bit set and the CPU_FTR_CP_USE_DCBTZ bit
+   cleared.
+   At the time of writing the only CPU that has this combination of bits
+   set is Power6. */
+BEGIN_FTR_SECTION
+	nop
+FTR_SECTION_ELSE
 	bne	.Ldst_unaligned
+ALT_FTR_SECTION_END(CPU_FTR_UNALIGNED_LD_STD | CPU_FTR_CP_USE_DCBTZ, \
+                    CPU_FTR_UNALIGNED_LD_STD)
 .Ldst_aligned:
-	andi.	r0,r4,7
 	addi	r3,r3,-16
+BEGIN_FTR_SECTION
+	andi.	r0,r4,7
 	bne	.Lsrc_unaligned
+END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 	srdi	r7,r5,4
 	ld	r9,0(r4)
 	addi	r4,r4,-8
@@ -131,7 +143,7 @@
 	PPC_MTOCRF	0x01,r6		# put #bytes to 8B bdry into cr7
 	subf	r5,r6,r5
 	li	r7,0
-	cmpldi	r1,r5,16
+	cmpldi	cr1,r5,16
 	bf	cr7*4+3,1f
 	lbz	r0,0(r4)
 	stb	r0,0(r3)
diff --git a/arch/powerpc/math-emu/Makefile b/arch/powerpc/math-emu/Makefile
index 03aa98d..f9e506a 100644
--- a/arch/powerpc/math-emu/Makefile
+++ b/arch/powerpc/math-emu/Makefile
@@ -11,6 +11,8 @@
 					mcrfs.o mffs.o mtfsb0.o mtfsb1.o \
 					mtfsf.o mtfsfi.o stfiwx.o stfs.o
 
+obj-$(CONFIG_SPE)		+= math_efp.o
+
 CFLAGS_fabs.o = -fno-builtin-fabs
 CFLAGS_math.o = -fno-builtin-fabs
 
diff --git a/arch/powerpc/math-emu/fadd.c b/arch/powerpc/math-emu/fadd.c
index 04d3b4a..0158a16 100644
--- a/arch/powerpc/math-emu/fadd.c
+++ b/arch/powerpc/math-emu/fadd.c
@@ -13,7 +13,6 @@
 	FP_DECL_D(B);
 	FP_DECL_D(R);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p\n", __func__, frD, frA, frB);
diff --git a/arch/powerpc/math-emu/fcmpo.c b/arch/powerpc/math-emu/fcmpo.c
index b5dc449..5bce011 100644
--- a/arch/powerpc/math-emu/fcmpo.c
+++ b/arch/powerpc/math-emu/fcmpo.c
@@ -14,7 +14,6 @@
 	FP_DECL_EX;
 	int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) };
 	long cmp;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p (%08x) %d %p %p\n", __func__, ccr, *ccr, crfD, frA, frB);
@@ -29,7 +28,7 @@
 #endif
 
 	if (A_c == FP_CLS_NAN || B_c == FP_CLS_NAN)
-		ret |= EFLAG_VXVC;
+		FP_SET_EXCEPTION(EFLAG_VXVC);
 
 	FP_CMP_D(cmp, A, B, 2);
 	cmp = code[(cmp + 1) & 3];
@@ -44,5 +43,5 @@
 	printk("CR: %08x\n", *ccr);
 #endif
 
-	return ret;
+	return FP_CUR_EXCEPTIONS;
 }
diff --git a/arch/powerpc/math-emu/fdiv.c b/arch/powerpc/math-emu/fdiv.c
index 2db1509..a29239c 100644
--- a/arch/powerpc/math-emu/fdiv.c
+++ b/arch/powerpc/math-emu/fdiv.c
@@ -13,7 +13,6 @@
 	FP_DECL_D(B);
 	FP_DECL_D(R);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p\n", __func__, frD, frA, frB);
@@ -28,22 +27,22 @@
 #endif
 
 	if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) {
-		ret |= EFLAG_VXZDZ;
+		FP_SET_EXCEPTION(EFLAG_VXZDZ);
 #ifdef DEBUG
 		printk("%s: FPSCR_VXZDZ raised\n", __func__);
 #endif
 	}
 	if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) {
-		ret |= EFLAG_VXIDI;
+		FP_SET_EXCEPTION(EFLAG_VXIDI);
 #ifdef DEBUG
 		printk("%s: FPSCR_VXIDI raised\n", __func__);
 #endif
 	}
 
 	if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) {
-		ret |= EFLAG_DIVZERO;
+		FP_SET_EXCEPTION(EFLAG_DIVZERO);
 		if (__FPU_TRAP_P(EFLAG_DIVZERO))
-			return ret;
+			return FP_CUR_EXCEPTIONS;
 	}
 	FP_DIV_D(R, A, B);
 
diff --git a/arch/powerpc/math-emu/fdivs.c b/arch/powerpc/math-emu/fdivs.c
index 797f6a9..526bc26 100644
--- a/arch/powerpc/math-emu/fdivs.c
+++ b/arch/powerpc/math-emu/fdivs.c
@@ -14,7 +14,6 @@
 	FP_DECL_D(B);
 	FP_DECL_D(R);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p\n", __func__, frD, frA, frB);
@@ -29,22 +28,22 @@
 #endif
 
 	if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) {
-		ret |= EFLAG_VXZDZ;
+		FP_SET_EXCEPTION(EFLAG_VXZDZ);
 #ifdef DEBUG
 		printk("%s: FPSCR_VXZDZ raised\n", __func__);
 #endif
 	}
 	if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) {
-		ret |= EFLAG_VXIDI;
+		FP_SET_EXCEPTION(EFLAG_VXIDI);
 #ifdef DEBUG
 		printk("%s: FPSCR_VXIDI raised\n", __func__);
 #endif
 	}
 
 	if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) {
-		ret |= EFLAG_DIVZERO;
+		FP_SET_EXCEPTION(EFLAG_DIVZERO);
 		if (__FPU_TRAP_P(EFLAG_DIVZERO))
-			return ret;
+			return FP_CUR_EXCEPTIONS;
 	}
 
 	FP_DIV_D(R, A, B);
diff --git a/arch/powerpc/math-emu/fmadd.c b/arch/powerpc/math-emu/fmadd.c
index 925313a..8c3f20a 100644
--- a/arch/powerpc/math-emu/fmadd.c
+++ b/arch/powerpc/math-emu/fmadd.c
@@ -15,7 +15,6 @@
 	FP_DECL_D(C);
 	FP_DECL_D(T);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
@@ -33,12 +32,12 @@
 
 	if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
 	    (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
-                ret |= EFLAG_VXIMZ;
+                FP_SET_EXCEPTION(EFLAG_VXIMZ);
 
 	FP_MUL_D(T, A, C);
 
 	if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
-		ret |= EFLAG_VXISI;
+		FP_SET_EXCEPTION(EFLAG_VXISI);
 
 	FP_ADD_D(R, T, B);
 
diff --git a/arch/powerpc/math-emu/fmadds.c b/arch/powerpc/math-emu/fmadds.c
index aea80ef..794fb31 100644
--- a/arch/powerpc/math-emu/fmadds.c
+++ b/arch/powerpc/math-emu/fmadds.c
@@ -16,7 +16,6 @@
 	FP_DECL_D(C);
 	FP_DECL_D(T);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
@@ -34,12 +33,12 @@
 
 	if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
 	    (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
-                ret |= EFLAG_VXIMZ;
+                FP_SET_EXCEPTION(EFLAG_VXIMZ);
 
 	FP_MUL_D(T, A, C);
 
 	if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
-		ret |= EFLAG_VXISI;
+		FP_SET_EXCEPTION(EFLAG_VXISI);
 
 	FP_ADD_D(R, T, B);
 
diff --git a/arch/powerpc/math-emu/fmsub.c b/arch/powerpc/math-emu/fmsub.c
index a644d52..626f6fe 100644
--- a/arch/powerpc/math-emu/fmsub.c
+++ b/arch/powerpc/math-emu/fmsub.c
@@ -15,7 +15,6 @@
 	FP_DECL_D(C);
 	FP_DECL_D(T);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
@@ -33,7 +32,7 @@
 
 	if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
 	    (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
-		ret |= EFLAG_VXIMZ;
+		FP_SET_EXCEPTION(EFLAG_VXIMZ);
 
 	FP_MUL_D(T, A, C);
 
@@ -41,7 +40,7 @@
 		B_s ^= 1;
 
 	if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
-		ret |= EFLAG_VXISI;
+		FP_SET_EXCEPTION(EFLAG_VXISI);
 
 	FP_ADD_D(R, T, B);
 
diff --git a/arch/powerpc/math-emu/fmsubs.c b/arch/powerpc/math-emu/fmsubs.c
index 2fdeeb9..3425bc8 100644
--- a/arch/powerpc/math-emu/fmsubs.c
+++ b/arch/powerpc/math-emu/fmsubs.c
@@ -16,7 +16,6 @@
 	FP_DECL_D(C);
 	FP_DECL_D(T);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
@@ -34,7 +33,7 @@
 
 	if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
 	    (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
-		ret |= EFLAG_VXIMZ;
+		FP_SET_EXCEPTION(EFLAG_VXIMZ);
 
 	FP_MUL_D(T, A, C);
 
@@ -42,7 +41,7 @@
 		B_s ^= 1;
 
 	if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
-		ret |= EFLAG_VXISI;
+		FP_SET_EXCEPTION(EFLAG_VXISI);
 
 	FP_ADD_D(R, T, B);
 
diff --git a/arch/powerpc/math-emu/fmul.c b/arch/powerpc/math-emu/fmul.c
index 391fd17..2c19297 100644
--- a/arch/powerpc/math-emu/fmul.c
+++ b/arch/powerpc/math-emu/fmul.c
@@ -13,7 +13,6 @@
 	FP_DECL_D(B);
 	FP_DECL_D(R);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p\n", __func__, frD, frA, frB);
@@ -31,7 +30,7 @@
 
 	if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) ||
 	    (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF))
-		ret |= EFLAG_VXIMZ;
+		FP_SET_EXCEPTION(EFLAG_VXIMZ);
 
 	FP_MUL_D(R, A, B);
 
diff --git a/arch/powerpc/math-emu/fmuls.c b/arch/powerpc/math-emu/fmuls.c
index 2d3ec5f..f5ad5c9 100644
--- a/arch/powerpc/math-emu/fmuls.c
+++ b/arch/powerpc/math-emu/fmuls.c
@@ -14,7 +14,6 @@
 	FP_DECL_D(B);
 	FP_DECL_D(R);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p\n", __func__, frD, frA, frB);
@@ -32,7 +31,7 @@
 
 	if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) ||
 	    (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF))
-		ret |= EFLAG_VXIMZ;
+		FP_SET_EXCEPTION(EFLAG_VXIMZ);
 
 	FP_MUL_D(R, A, B);
 
diff --git a/arch/powerpc/math-emu/fnmadd.c b/arch/powerpc/math-emu/fnmadd.c
index 2497b86..e817bc5 100644
--- a/arch/powerpc/math-emu/fnmadd.c
+++ b/arch/powerpc/math-emu/fnmadd.c
@@ -15,7 +15,6 @@
 	FP_DECL_D(C);
 	FP_DECL_D(T);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
@@ -33,12 +32,12 @@
 
 	if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
 	    (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
-                ret |= EFLAG_VXIMZ;
+                FP_SET_EXCEPTION(EFLAG_VXIMZ);
 
 	FP_MUL_D(T, A, C);
 
 	if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
-		ret |= EFLAG_VXISI;
+		FP_SET_EXCEPTION(EFLAG_VXISI);
 
 	FP_ADD_D(R, T, B);
 
diff --git a/arch/powerpc/math-emu/fnmadds.c b/arch/powerpc/math-emu/fnmadds.c
index ee9d71e..4db4b7d 100644
--- a/arch/powerpc/math-emu/fnmadds.c
+++ b/arch/powerpc/math-emu/fnmadds.c
@@ -16,7 +16,6 @@
 	FP_DECL_D(C);
 	FP_DECL_D(T);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
@@ -34,12 +33,12 @@
 
 	if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
 	    (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
-                ret |= EFLAG_VXIMZ;
+                FP_SET_EXCEPTION(EFLAG_VXIMZ);
 
 	FP_MUL_D(T, A, C);
 
 	if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
-		ret |= EFLAG_VXISI;
+		FP_SET_EXCEPTION(EFLAG_VXISI);
 
 	FP_ADD_D(R, T, B);
 
diff --git a/arch/powerpc/math-emu/fnmsub.c b/arch/powerpc/math-emu/fnmsub.c
index 3885a77..f65979f 100644
--- a/arch/powerpc/math-emu/fnmsub.c
+++ b/arch/powerpc/math-emu/fnmsub.c
@@ -15,7 +15,6 @@
 	FP_DECL_D(C);
 	FP_DECL_D(T);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
@@ -33,7 +32,7 @@
 
 	if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
 	    (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
-		ret |= EFLAG_VXIMZ;
+		FP_SET_EXCEPTION(EFLAG_VXIMZ);
 
 	FP_MUL_D(T, A, C);
 
@@ -41,7 +40,7 @@
 		B_s ^= 1;
 
 	if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
-		ret |= EFLAG_VXISI;
+		FP_SET_EXCEPTION(EFLAG_VXISI);
 
 	FP_ADD_D(R, T, B);
 
diff --git a/arch/powerpc/math-emu/fnmsubs.c b/arch/powerpc/math-emu/fnmsubs.c
index f835dfe..9021dac 100644
--- a/arch/powerpc/math-emu/fnmsubs.c
+++ b/arch/powerpc/math-emu/fnmsubs.c
@@ -16,7 +16,6 @@
 	FP_DECL_D(C);
 	FP_DECL_D(T);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
@@ -34,7 +33,7 @@
 
 	if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
 	    (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
-		ret |= EFLAG_VXIMZ;
+		FP_SET_EXCEPTION(EFLAG_VXIMZ);
 
 	FP_MUL_D(T, A, C);
 
@@ -42,7 +41,7 @@
 		B_s ^= 1;
 
 	if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
-		ret |= EFLAG_VXISI;
+		FP_SET_EXCEPTION(EFLAG_VXISI);
 
 	FP_ADD_D(R, T, B);
 
diff --git a/arch/powerpc/math-emu/fsqrt.c b/arch/powerpc/math-emu/fsqrt.c
index 3e90072..a55fc7d 100644
--- a/arch/powerpc/math-emu/fsqrt.c
+++ b/arch/powerpc/math-emu/fsqrt.c
@@ -12,7 +12,6 @@
 	FP_DECL_D(B);
 	FP_DECL_D(R);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p %p\n", __func__, frD, frB);
@@ -25,9 +24,9 @@
 #endif
 
 	if (B_s && B_c != FP_CLS_ZERO)
-		ret |= EFLAG_VXSQRT;
+		FP_SET_EXCEPTION(EFLAG_VXSQRT);
 	if (B_c == FP_CLS_NAN)
-		ret |= EFLAG_VXSNAN;
+		FP_SET_EXCEPTION(EFLAG_VXSNAN);
 
 	FP_SQRT_D(R, B);
 
diff --git a/arch/powerpc/math-emu/fsqrts.c b/arch/powerpc/math-emu/fsqrts.c
index 2843be9..31dccbf 100644
--- a/arch/powerpc/math-emu/fsqrts.c
+++ b/arch/powerpc/math-emu/fsqrts.c
@@ -13,7 +13,6 @@
 	FP_DECL_D(B);
 	FP_DECL_D(R);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p %p\n", __func__, frD, frB);
@@ -26,9 +25,9 @@
 #endif
 
 	if (B_s && B_c != FP_CLS_ZERO)
-		ret |= EFLAG_VXSQRT;
+		FP_SET_EXCEPTION(EFLAG_VXSQRT);
 	if (B_c == FP_CLS_NAN)
-		ret |= EFLAG_VXSNAN;
+		FP_SET_EXCEPTION(EFLAG_VXSNAN);
 
 	FP_SQRT_D(R, B);
 
diff --git a/arch/powerpc/math-emu/fsub.c b/arch/powerpc/math-emu/fsub.c
index 78b0944..02c5dff 100644
--- a/arch/powerpc/math-emu/fsub.c
+++ b/arch/powerpc/math-emu/fsub.c
@@ -13,7 +13,6 @@
 	FP_DECL_D(B);
 	FP_DECL_D(R);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p\n", __func__, frD, frA, frB);
@@ -31,7 +30,7 @@
 		B_s ^= 1;
 
 	if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
-		ret |= EFLAG_VXISI;
+		FP_SET_EXCEPTION(EFLAG_VXISI);
 
 	FP_ADD_D(R, A, B);
 
diff --git a/arch/powerpc/math-emu/fsubs.c b/arch/powerpc/math-emu/fsubs.c
index d3bf908..5d9b18c 100644
--- a/arch/powerpc/math-emu/fsubs.c
+++ b/arch/powerpc/math-emu/fsubs.c
@@ -14,7 +14,6 @@
 	FP_DECL_D(B);
 	FP_DECL_D(R);
 	FP_DECL_EX;
-	int ret = 0;
 
 #ifdef DEBUG
 	printk("%s: %p %p %p\n", __func__, frD, frA, frB);
@@ -32,7 +31,7 @@
 		B_s ^= 1;
 
 	if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
-		ret |= EFLAG_VXISI;
+		FP_SET_EXCEPTION(EFLAG_VXISI);
 
 	FP_ADD_D(R, A, B);
 
diff --git a/arch/powerpc/math-emu/math_efp.c b/arch/powerpc/math-emu/math_efp.c
new file mode 100644
index 0000000..41f4ef3
--- /dev/null
+++ b/arch/powerpc/math-emu/math_efp.c
@@ -0,0 +1,720 @@
+/*
+ * arch/powerpc/math-emu/math_efp.c
+ *
+ * Copyright (C) 2006-2008 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Ebony Zhu,	<ebony.zhu@freescale.com>
+ *         Yu Liu,	<yu.liu@freescale.com>
+ *
+ * Derived from arch/alpha/math-emu/math.c
+ *              arch/powerpc/math-emu/math.c
+ *
+ * Description:
+ * This file is the exception handler to make E500 SPE instructions
+ * fully comply with IEEE-754 floating point standard.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/types.h>
+
+#include <asm/uaccess.h>
+#include <asm/reg.h>
+
+#define FP_EX_BOOKE_E500_SPE
+#include <asm/sfp-machine.h>
+
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+#include <math-emu/double.h>
+
+#define EFAPU		0x4
+
+#define VCT		0x4
+#define SPFP		0x6
+#define DPFP		0x7
+
+#define EFSADD		0x2c0
+#define EFSSUB		0x2c1
+#define EFSABS		0x2c4
+#define EFSNABS		0x2c5
+#define EFSNEG		0x2c6
+#define EFSMUL		0x2c8
+#define EFSDIV		0x2c9
+#define EFSCMPGT	0x2cc
+#define EFSCMPLT	0x2cd
+#define EFSCMPEQ	0x2ce
+#define EFSCFD		0x2cf
+#define EFSCFSI		0x2d1
+#define EFSCTUI		0x2d4
+#define EFSCTSI		0x2d5
+#define EFSCTUF		0x2d6
+#define EFSCTSF		0x2d7
+#define EFSCTUIZ	0x2d8
+#define EFSCTSIZ	0x2da
+
+#define EVFSADD		0x280
+#define EVFSSUB		0x281
+#define EVFSABS		0x284
+#define EVFSNABS	0x285
+#define EVFSNEG		0x286
+#define EVFSMUL		0x288
+#define EVFSDIV		0x289
+#define EVFSCMPGT	0x28c
+#define EVFSCMPLT	0x28d
+#define EVFSCMPEQ	0x28e
+#define EVFSCTUI	0x294
+#define EVFSCTSI	0x295
+#define EVFSCTUF	0x296
+#define EVFSCTSF	0x297
+#define EVFSCTUIZ	0x298
+#define EVFSCTSIZ	0x29a
+
+#define EFDADD		0x2e0
+#define EFDSUB		0x2e1
+#define EFDABS		0x2e4
+#define EFDNABS		0x2e5
+#define EFDNEG		0x2e6
+#define EFDMUL		0x2e8
+#define EFDDIV		0x2e9
+#define EFDCTUIDZ	0x2ea
+#define EFDCTSIDZ	0x2eb
+#define EFDCMPGT	0x2ec
+#define EFDCMPLT	0x2ed
+#define EFDCMPEQ	0x2ee
+#define EFDCFS		0x2ef
+#define EFDCTUI		0x2f4
+#define EFDCTSI		0x2f5
+#define EFDCTUF		0x2f6
+#define EFDCTSF		0x2f7
+#define EFDCTUIZ	0x2f8
+#define EFDCTSIZ	0x2fa
+
+#define AB	2
+#define XA	3
+#define XB	4
+#define XCR	5
+#define NOTYPE	0
+
+#define SIGN_BIT_S	(1UL << 31)
+#define SIGN_BIT_D	(1ULL << 63)
+#define FP_EX_MASK	(FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \
+			FP_EX_UNDERFLOW | FP_EX_OVERFLOW)
+
+union dw_union {
+	u64 dp[1];
+	u32 wp[2];
+};
+
+static unsigned long insn_type(unsigned long speinsn)
+{
+	unsigned long ret = NOTYPE;
+
+	switch (speinsn & 0x7ff) {
+	case EFSABS:	ret = XA;	break;
+	case EFSADD:	ret = AB;	break;
+	case EFSCFD:	ret = XB;	break;
+	case EFSCMPEQ:	ret = XCR;	break;
+	case EFSCMPGT:	ret = XCR;	break;
+	case EFSCMPLT:	ret = XCR;	break;
+	case EFSCTSF:	ret = XB;	break;
+	case EFSCTSI:	ret = XB;	break;
+	case EFSCTSIZ:	ret = XB;	break;
+	case EFSCTUF:	ret = XB;	break;
+	case EFSCTUI:	ret = XB;	break;
+	case EFSCTUIZ:	ret = XB;	break;
+	case EFSDIV:	ret = AB;	break;
+	case EFSMUL:	ret = AB;	break;
+	case EFSNABS:	ret = XA;	break;
+	case EFSNEG:	ret = XA;	break;
+	case EFSSUB:	ret = AB;	break;
+	case EFSCFSI:	ret = XB;	break;
+
+	case EVFSABS:	ret = XA;	break;
+	case EVFSADD:	ret = AB;	break;
+	case EVFSCMPEQ:	ret = XCR;	break;
+	case EVFSCMPGT:	ret = XCR;	break;
+	case EVFSCMPLT:	ret = XCR;	break;
+	case EVFSCTSF:	ret = XB;	break;
+	case EVFSCTSI:	ret = XB;	break;
+	case EVFSCTSIZ:	ret = XB;	break;
+	case EVFSCTUF:	ret = XB;	break;
+	case EVFSCTUI:	ret = XB;	break;
+	case EVFSCTUIZ:	ret = XB;	break;
+	case EVFSDIV:	ret = AB;	break;
+	case EVFSMUL:	ret = AB;	break;
+	case EVFSNABS:	ret = XA;	break;
+	case EVFSNEG:	ret = XA;	break;
+	case EVFSSUB:	ret = AB;	break;
+
+	case EFDABS:	ret = XA;	break;
+	case EFDADD:	ret = AB;	break;
+	case EFDCFS:	ret = XB;	break;
+	case EFDCMPEQ:	ret = XCR;	break;
+	case EFDCMPGT:	ret = XCR;	break;
+	case EFDCMPLT:	ret = XCR;	break;
+	case EFDCTSF:	ret = XB;	break;
+	case EFDCTSI:	ret = XB;	break;
+	case EFDCTSIDZ:	ret = XB;	break;
+	case EFDCTSIZ:	ret = XB;	break;
+	case EFDCTUF:	ret = XB;	break;
+	case EFDCTUI:	ret = XB;	break;
+	case EFDCTUIDZ:	ret = XB;	break;
+	case EFDCTUIZ:	ret = XB;	break;
+	case EFDDIV:	ret = AB;	break;
+	case EFDMUL:	ret = AB;	break;
+	case EFDNABS:	ret = XA;	break;
+	case EFDNEG:	ret = XA;	break;
+	case EFDSUB:	ret = AB;	break;
+
+	default:
+		printk(KERN_ERR "\nOoops! SPE instruction no type found.");
+		printk(KERN_ERR "\ninst code: %08lx\n", speinsn);
+	}
+
+	return ret;
+}
+
+int do_spe_mathemu(struct pt_regs *regs)
+{
+	FP_DECL_EX;
+	int IR, cmp;
+
+	unsigned long type, func, fc, fa, fb, src, speinsn;
+	union dw_union vc, va, vb;
+
+	if (get_user(speinsn, (unsigned int __user *) regs->nip))
+		return -EFAULT;
+	if ((speinsn >> 26) != EFAPU)
+		return -EINVAL;         /* not an spe instruction */
+
+	type = insn_type(speinsn);
+	if (type == NOTYPE)
+		return -ENOSYS;
+
+	func = speinsn & 0x7ff;
+	fc = (speinsn >> 21) & 0x1f;
+	fa = (speinsn >> 16) & 0x1f;
+	fb = (speinsn >> 11) & 0x1f;
+	src = (speinsn >> 5) & 0x7;
+
+	vc.wp[0] = current->thread.evr[fc];
+	vc.wp[1] = regs->gpr[fc];
+	va.wp[0] = current->thread.evr[fa];
+	va.wp[1] = regs->gpr[fa];
+	vb.wp[0] = current->thread.evr[fb];
+	vb.wp[1] = regs->gpr[fb];
+
+	__FPU_FPSCR = mfspr(SPRN_SPEFSCR);
+
+#ifdef DEBUG
+	printk("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR);
+	printk("vc: %08x  %08x\n", vc.wp[0], vc.wp[1]);
+	printk("va: %08x  %08x\n", va.wp[0], va.wp[1]);
+	printk("vb: %08x  %08x\n", vb.wp[0], vb.wp[1]);
+#endif
+
+	switch (src) {
+	case SPFP: {
+		FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+
+		switch (type) {
+		case AB:
+		case XCR:
+			FP_UNPACK_SP(SA, va.wp + 1);
+		case XB:
+			FP_UNPACK_SP(SB, vb.wp + 1);
+			break;
+		case XA:
+			FP_UNPACK_SP(SA, va.wp + 1);
+			break;
+		}
+
+#ifdef DEBUG
+		printk("SA: %ld %08lx %ld (%ld)\n", SA_s, SA_f, SA_e, SA_c);
+		printk("SB: %ld %08lx %ld (%ld)\n", SB_s, SB_f, SB_e, SB_c);
+#endif
+
+		switch (func) {
+		case EFSABS:
+			vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;
+			goto update_regs;
+
+		case EFSNABS:
+			vc.wp[1] = va.wp[1] | SIGN_BIT_S;
+			goto update_regs;
+
+		case EFSNEG:
+			vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;
+			goto update_regs;
+
+		case EFSADD:
+			FP_ADD_S(SR, SA, SB);
+			goto pack_s;
+
+		case EFSSUB:
+			FP_SUB_S(SR, SA, SB);
+			goto pack_s;
+
+		case EFSMUL:
+			FP_MUL_S(SR, SA, SB);
+			goto pack_s;
+
+		case EFSDIV:
+			FP_DIV_S(SR, SA, SB);
+			goto pack_s;
+
+		case EFSCMPEQ:
+			cmp = 0;
+			goto cmp_s;
+
+		case EFSCMPGT:
+			cmp = 1;
+			goto cmp_s;
+
+		case EFSCMPLT:
+			cmp = -1;
+			goto cmp_s;
+
+		case EFSCTSF:
+		case EFSCTUF:
+			if (!((vb.wp[1] >> 23) == 0xff && ((vb.wp[1] & 0x7fffff) > 0))) {
+				/* NaN */
+				if (((vb.wp[1] >> 23) & 0xff) == 0) {
+					/* denorm */
+					vc.wp[1] = 0x0;
+				} else if ((vb.wp[1] >> 31) == 0) {
+					/* positive normal */
+					vc.wp[1] = (func == EFSCTSF) ?
+						0x7fffffff : 0xffffffff;
+				} else { /* negative normal */
+					vc.wp[1] = (func == EFSCTSF) ?
+						0x80000000 : 0x0;
+				}
+			} else { /* rB is NaN */
+				vc.wp[1] = 0x0;
+			}
+			goto update_regs;
+
+		case EFSCFD: {
+			FP_DECL_D(DB);
+			FP_CLEAR_EXCEPTIONS;
+			FP_UNPACK_DP(DB, vb.dp);
+#ifdef DEBUG
+			printk("DB: %ld %08lx %08lx %ld (%ld)\n",
+					DB_s, DB_f1, DB_f0, DB_e, DB_c);
+#endif
+			FP_CONV(S, D, 1, 2, SR, DB);
+			goto pack_s;
+		}
+
+		case EFSCTSI:
+		case EFSCTSIZ:
+		case EFSCTUI:
+		case EFSCTUIZ:
+			if (func & 0x4) {
+				_FP_ROUND(1, SB);
+			} else {
+				_FP_ROUND_ZERO(1, SB);
+			}
+			FP_TO_INT_S(vc.wp[1], SB, 32, ((func & 0x3) != 0));
+			goto update_regs;
+
+		default:
+			goto illegal;
+		}
+		break;
+
+pack_s:
+#ifdef DEBUG
+		printk("SR: %ld %08lx %ld (%ld)\n", SR_s, SR_f, SR_e, SR_c);
+#endif
+		FP_PACK_SP(vc.wp + 1, SR);
+		goto update_regs;
+
+cmp_s:
+		FP_CMP_S(IR, SA, SB, 3);
+		if (IR == 3 && (FP_ISSIGNAN_S(SA) || FP_ISSIGNAN_S(SB)))
+			FP_SET_EXCEPTION(FP_EX_INVALID);
+		if (IR == cmp) {
+			IR = 0x4;
+		} else {
+			IR = 0;
+		}
+		goto update_ccr;
+	}
+
+	case DPFP: {
+		FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+
+		switch (type) {
+		case AB:
+		case XCR:
+			FP_UNPACK_DP(DA, va.dp);
+		case XB:
+			FP_UNPACK_DP(DB, vb.dp);
+			break;
+		case XA:
+			FP_UNPACK_DP(DA, va.dp);
+			break;
+		}
+
+#ifdef DEBUG
+		printk("DA: %ld %08lx %08lx %ld (%ld)\n",
+				DA_s, DA_f1, DA_f0, DA_e, DA_c);
+		printk("DB: %ld %08lx %08lx %ld (%ld)\n",
+				DB_s, DB_f1, DB_f0, DB_e, DB_c);
+#endif
+
+		switch (func) {
+		case EFDABS:
+			vc.dp[0] = va.dp[0] & ~SIGN_BIT_D;
+			goto update_regs;
+
+		case EFDNABS:
+			vc.dp[0] = va.dp[0] | SIGN_BIT_D;
+			goto update_regs;
+
+		case EFDNEG:
+			vc.dp[0] = va.dp[0] ^ SIGN_BIT_D;
+			goto update_regs;
+
+		case EFDADD:
+			FP_ADD_D(DR, DA, DB);
+			goto pack_d;
+
+		case EFDSUB:
+			FP_SUB_D(DR, DA, DB);
+			goto pack_d;
+
+		case EFDMUL:
+			FP_MUL_D(DR, DA, DB);
+			goto pack_d;
+
+		case EFDDIV:
+			FP_DIV_D(DR, DA, DB);
+			goto pack_d;
+
+		case EFDCMPEQ:
+			cmp = 0;
+			goto cmp_d;
+
+		case EFDCMPGT:
+			cmp = 1;
+			goto cmp_d;
+
+		case EFDCMPLT:
+			cmp = -1;
+			goto cmp_d;
+
+		case EFDCTSF:
+		case EFDCTUF:
+			if (!((vb.wp[0] >> 20) == 0x7ff &&
+			   ((vb.wp[0] & 0xfffff) > 0 || (vb.wp[1] > 0)))) {
+				/* not a NaN */
+				if (((vb.wp[0] >> 20) & 0x7ff) == 0) {
+					/* denorm */
+					vc.wp[1] = 0x0;
+				} else if ((vb.wp[0] >> 31) == 0) {
+					/* positive normal */
+					vc.wp[1] = (func == EFDCTSF) ?
+						0x7fffffff : 0xffffffff;
+				} else { /* negative normal */
+					vc.wp[1] = (func == EFDCTSF) ?
+						0x80000000 : 0x0;
+				}
+			} else { /* NaN */
+				vc.wp[1] = 0x0;
+			}
+			goto update_regs;
+
+		case EFDCFS: {
+			FP_DECL_S(SB);
+			FP_CLEAR_EXCEPTIONS;
+			FP_UNPACK_SP(SB, vb.wp + 1);
+#ifdef DEBUG
+			printk("SB: %ld %08lx %ld (%ld)\n",
+					SB_s, SB_f, SB_e, SB_c);
+#endif
+			FP_CONV(D, S, 2, 1, DR, SB);
+			goto pack_d;
+		}
+
+		case EFDCTUIDZ:
+		case EFDCTSIDZ:
+			_FP_ROUND_ZERO(2, DB);
+			FP_TO_INT_D(vc.dp[0], DB, 64, ((func & 0x1) == 0));
+			goto update_regs;
+
+		case EFDCTUI:
+		case EFDCTSI:
+		case EFDCTUIZ:
+		case EFDCTSIZ:
+			if (func & 0x4) {
+				_FP_ROUND(2, DB);
+			} else {
+				_FP_ROUND_ZERO(2, DB);
+			}
+			FP_TO_INT_D(vc.wp[1], DB, 32, ((func & 0x3) != 0));
+			goto update_regs;
+
+		default:
+			goto illegal;
+		}
+		break;
+
+pack_d:
+#ifdef DEBUG
+		printk("DR: %ld %08lx %08lx %ld (%ld)\n",
+				DR_s, DR_f1, DR_f0, DR_e, DR_c);
+#endif
+		FP_PACK_DP(vc.dp, DR);
+		goto update_regs;
+
+cmp_d:
+		FP_CMP_D(IR, DA, DB, 3);
+		if (IR == 3 && (FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB)))
+			FP_SET_EXCEPTION(FP_EX_INVALID);
+		if (IR == cmp) {
+			IR = 0x4;
+		} else {
+			IR = 0;
+		}
+		goto update_ccr;
+
+	}
+
+	case VCT: {
+		FP_DECL_S(SA0); FP_DECL_S(SB0); FP_DECL_S(SR0);
+		FP_DECL_S(SA1); FP_DECL_S(SB1); FP_DECL_S(SR1);
+		int IR0, IR1;
+
+		switch (type) {
+		case AB:
+		case XCR:
+			FP_UNPACK_SP(SA0, va.wp);
+			FP_UNPACK_SP(SA1, va.wp + 1);
+		case XB:
+			FP_UNPACK_SP(SB0, vb.wp);
+			FP_UNPACK_SP(SB1, vb.wp + 1);
+			break;
+		case XA:
+			FP_UNPACK_SP(SA0, va.wp);
+			FP_UNPACK_SP(SA1, va.wp + 1);
+			break;
+		}
+
+#ifdef DEBUG
+		printk("SA0: %ld %08lx %ld (%ld)\n", SA0_s, SA0_f, SA0_e, SA0_c);
+		printk("SA1: %ld %08lx %ld (%ld)\n", SA1_s, SA1_f, SA1_e, SA1_c);
+		printk("SB0: %ld %08lx %ld (%ld)\n", SB0_s, SB0_f, SB0_e, SB0_c);
+		printk("SB1: %ld %08lx %ld (%ld)\n", SB1_s, SB1_f, SB1_e, SB1_c);
+#endif
+
+		switch (func) {
+		case EVFSABS:
+			vc.wp[0] = va.wp[0] & ~SIGN_BIT_S;
+			vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;
+			goto update_regs;
+
+		case EVFSNABS:
+			vc.wp[0] = va.wp[0] | SIGN_BIT_S;
+			vc.wp[1] = va.wp[1] | SIGN_BIT_S;
+			goto update_regs;
+
+		case EVFSNEG:
+			vc.wp[0] = va.wp[0] ^ SIGN_BIT_S;
+			vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;
+			goto update_regs;
+
+		case EVFSADD:
+			FP_ADD_S(SR0, SA0, SB0);
+			FP_ADD_S(SR1, SA1, SB1);
+			goto pack_vs;
+
+		case EVFSSUB:
+			FP_SUB_S(SR0, SA0, SB0);
+			FP_SUB_S(SR1, SA1, SB1);
+			goto pack_vs;
+
+		case EVFSMUL:
+			FP_MUL_S(SR0, SA0, SB0);
+			FP_MUL_S(SR1, SA1, SB1);
+			goto pack_vs;
+
+		case EVFSDIV:
+			FP_DIV_S(SR0, SA0, SB0);
+			FP_DIV_S(SR1, SA1, SB1);
+			goto pack_vs;
+
+		case EVFSCMPEQ:
+			cmp = 0;
+			goto cmp_vs;
+
+		case EVFSCMPGT:
+			cmp = 1;
+			goto cmp_vs;
+
+		case EVFSCMPLT:
+			cmp = -1;
+			goto cmp_vs;
+
+		case EVFSCTSF:
+			__asm__ __volatile__ ("mtspr 512, %4\n"
+				"efsctsf %0, %2\n"
+				"efsctsf %1, %3\n"
+				: "=r" (vc.wp[0]), "=r" (vc.wp[1])
+				: "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0));
+			goto update_regs;
+
+		case EVFSCTUF:
+			__asm__ __volatile__ ("mtspr 512, %4\n"
+				"efsctuf %0, %2\n"
+				"efsctuf %1, %3\n"
+				: "=r" (vc.wp[0]), "=r" (vc.wp[1])
+				: "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0));
+			goto update_regs;
+
+		case EVFSCTUI:
+		case EVFSCTSI:
+		case EVFSCTUIZ:
+		case EVFSCTSIZ:
+			if (func & 0x4) {
+				_FP_ROUND(1, SB0);
+				_FP_ROUND(1, SB1);
+			} else {
+				_FP_ROUND_ZERO(1, SB0);
+				_FP_ROUND_ZERO(1, SB1);
+			}
+			FP_TO_INT_S(vc.wp[0], SB0, 32, ((func & 0x3) != 0));
+			FP_TO_INT_S(vc.wp[1], SB1, 32, ((func & 0x3) != 0));
+			goto update_regs;
+
+		default:
+			goto illegal;
+		}
+		break;
+
+pack_vs:
+#ifdef DEBUG
+		printk("SR0: %ld %08lx %ld (%ld)\n", SR0_s, SR0_f, SR0_e, SR0_c);
+		printk("SR1: %ld %08lx %ld (%ld)\n", SR1_s, SR1_f, SR1_e, SR1_c);
+#endif
+		FP_PACK_SP(vc.wp, SR0);
+		FP_PACK_SP(vc.wp + 1, SR1);
+		goto update_regs;
+
+cmp_vs:
+		{
+			int ch, cl;
+
+			FP_CMP_S(IR0, SA0, SB0, 3);
+			FP_CMP_S(IR1, SA1, SB1, 3);
+			if (IR0 == 3 && (FP_ISSIGNAN_S(SA0) || FP_ISSIGNAN_S(SB0)))
+				FP_SET_EXCEPTION(FP_EX_INVALID);
+			if (IR1 == 3 && (FP_ISSIGNAN_S(SA1) || FP_ISSIGNAN_S(SB1)))
+				FP_SET_EXCEPTION(FP_EX_INVALID);
+			ch = (IR0 == cmp) ? 1 : 0;
+			cl = (IR1 == cmp) ? 1 : 0;
+			IR = (ch << 3) | (cl << 2) | ((ch | cl) << 1) |
+				((ch & cl) << 0);
+			goto update_ccr;
+		}
+	}
+	default:
+		return -EINVAL;
+	}
+
+update_ccr:
+	regs->ccr &= ~(15 << ((7 - ((speinsn >> 23) & 0x7)) << 2));
+	regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2));
+
+update_regs:
+	__FPU_FPSCR &= ~FP_EX_MASK;
+	__FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK);
+	mtspr(SPRN_SPEFSCR, __FPU_FPSCR);
+
+	current->thread.evr[fc] = vc.wp[0];
+	regs->gpr[fc] = vc.wp[1];
+
+#ifdef DEBUG
+	printk("ccr = %08lx\n", regs->ccr);
+	printk("cur exceptions = %08x spefscr = %08lx\n",
+			FP_CUR_EXCEPTIONS, __FPU_FPSCR);
+	printk("vc: %08x  %08x\n", vc.wp[0], vc.wp[1]);
+	printk("va: %08x  %08x\n", va.wp[0], va.wp[1]);
+	printk("vb: %08x  %08x\n", vb.wp[0], vb.wp[1]);
+#endif
+
+	return 0;
+
+illegal:
+	printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn);
+	return -ENOSYS;
+}
+
+int speround_handler(struct pt_regs *regs)
+{
+	union dw_union fgpr;
+	int s_lo, s_hi;
+	unsigned long speinsn, type, fc;
+
+	if (get_user(speinsn, (unsigned int __user *) regs->nip))
+		return -EFAULT;
+	if ((speinsn >> 26) != 4)
+		return -EINVAL;         /* not an spe instruction */
+
+	type = insn_type(speinsn & 0x7ff);
+	if (type == XCR) return -ENOSYS;
+
+	fc = (speinsn >> 21) & 0x1f;
+	s_lo = regs->gpr[fc] & SIGN_BIT_S;
+	s_hi = current->thread.evr[fc] & SIGN_BIT_S;
+	fgpr.wp[0] = current->thread.evr[fc];
+	fgpr.wp[1] = regs->gpr[fc];
+
+	__FPU_FPSCR = mfspr(SPRN_SPEFSCR);
+
+	switch ((speinsn >> 5) & 0x7) {
+	/* Since SPE instructions on E500 core can handle round to nearest
+	 * and round toward zero with IEEE-754 complied, we just need
+	 * to handle round toward +Inf and round toward -Inf by software.
+	 */
+	case SPFP:
+		if ((FP_ROUNDMODE) == FP_RND_PINF) {
+			if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */
+		} else { /* round to -Inf */
+			if (s_lo) fgpr.wp[1]++; /* Z < 0, choose Z2 */
+		}
+		break;
+
+	case DPFP:
+		if (FP_ROUNDMODE == FP_RND_PINF) {
+			if (!s_hi) fgpr.dp[0]++; /* Z > 0, choose Z1 */
+		} else { /* round to -Inf */
+			if (s_hi) fgpr.dp[0]++; /* Z < 0, choose Z2 */
+		}
+		break;
+
+	case VCT:
+		if (FP_ROUNDMODE == FP_RND_PINF) {
+			if (!s_lo) fgpr.wp[1]++; /* Z_low > 0, choose Z1 */
+			if (!s_hi) fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */
+		} else { /* round to -Inf */
+			if (s_lo) fgpr.wp[1]++; /* Z_low < 0, choose Z2 */
+			if (s_hi) fgpr.wp[0]++; /* Z_high < 0, choose Z2 */
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	current->thread.evr[fc] = fgpr.wp[0];
+	regs->gpr[fc] = fgpr.wp[1];
+
+	return 0;
+}
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index e7392b4..953cc4a 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -6,17 +6,19 @@
 EXTRA_CFLAGS	+= -mno-minimal-toc
 endif
 
-obj-y				:= fault.o mem.o \
+obj-y				:= fault.o mem.o pgtable.o \
 				   init_$(CONFIG_WORD_SIZE).o \
-				   pgtable_$(CONFIG_WORD_SIZE).o \
-				   mmu_context_$(CONFIG_WORD_SIZE).o
+				   pgtable_$(CONFIG_WORD_SIZE).o
+obj-$(CONFIG_PPC_MMU_NOHASH)	+= mmu_context_nohash.o tlb_nohash.o \
+				   tlb_nohash_low.o
 hash-$(CONFIG_PPC_NATIVE)	:= hash_native_64.o
 obj-$(CONFIG_PPC64)		+= hash_utils_64.o \
 				   slb_low.o slb.o stab.o \
 				   gup.o mmap.o $(hash-y)
 obj-$(CONFIG_PPC_STD_MMU_32)	+= ppc_mmu_32.o
 obj-$(CONFIG_PPC_STD_MMU)	+= hash_low_$(CONFIG_WORD_SIZE).o \
-				   tlb_$(CONFIG_WORD_SIZE).o
+				   tlb_hash$(CONFIG_WORD_SIZE).o \
+				   mmu_context_hash$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_40x)		+= 40x_mmu.o
 obj-$(CONFIG_44x)		+= 44x_mmu.o
 obj-$(CONFIG_FSL_BOOKE)		+= fsl_booke_mmu.o
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 565b7a2..91c7b86 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -30,6 +30,7 @@
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 
+#include <asm/firmware.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
@@ -283,7 +284,7 @@
 				}
 				pte_update(ptep, 0, _PAGE_HWEXEC |
 					   _PAGE_ACCESSED);
-				_tlbie(address, mm->context.id);
+				local_flush_tlb_page(vma, address);
 				pte_unmap_unlock(ptep, ptl);
 				up_read(&mm->mmap_sem);
 				return 0;
@@ -318,9 +319,16 @@
 			goto do_sigbus;
 		BUG();
 	}
-	if (ret & VM_FAULT_MAJOR)
+	if (ret & VM_FAULT_MAJOR) {
 		current->maj_flt++;
-	else
+#ifdef CONFIG_PPC_SMLPAR
+		if (firmware_has_feature(FW_FEATURE_CMO)) {
+			preempt_disable();
+			get_lppaca()->page_ins += (1 << PAGE_FACTOR);
+			preempt_enable();
+		}
+#endif
+	} else
 		current->min_flt++;
 	up_read(&mm->mmap_sem);
 	return 0;
@@ -339,7 +347,7 @@
 	    && printk_ratelimit())
 		printk(KERN_CRIT "kernel tried to execute NX-protected"
 		       " page (%lx) - exploit attempt? (uid: %d)\n",
-		       address, current->uid);
+		       address, current_uid());
 
 	return SIGSEGV;
 
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
index 7bffb70..67850ec 100644
--- a/arch/powerpc/mm/hash_low_32.S
+++ b/arch/powerpc/mm/hash_low_32.S
@@ -36,36 +36,6 @@
 #endif /* CONFIG_SMP */
 
 /*
- * Sync CPUs with hash_page taking & releasing the hash
- * table lock
- */
-#ifdef CONFIG_SMP
-	.text
-_GLOBAL(hash_page_sync)
-	mfmsr   r10
-	rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
-	mtmsr   r0
-	lis	r8,mmu_hash_lock@h
-	ori	r8,r8,mmu_hash_lock@l
-	lis	r0,0x0fff
-	b	10f
-11:	lwz	r6,0(r8)
-	cmpwi	0,r6,0
-	bne	11b
-10:	lwarx	r6,0,r8
-	cmpwi	0,r6,0
-	bne-	11b
-	stwcx.	r0,0,r8
-	bne-	10b
-	isync
-	eieio
-	li	r0,0
-	stw	r0,0(r8)
-	mtmsr	r10
-	blr
-#endif /* CONFIG_SMP */
-
-/*
  * Load a PTE into the hash table, if possible.
  * The address is in r4, and r3 contains an access flag:
  * _PAGE_RW (0x400) if a write.
@@ -353,8 +323,8 @@
 	ori	r8,r8,0xe14		/* clear out reserved bits and M */
 	andc	r8,r5,r8		/* PP = user? (rw&dirty? 2: 3): 0 */
 BEGIN_FTR_SECTION
-	ori	r8,r8,_PAGE_COHERENT	/* set M (coherence required) */
-END_FTR_SECTION_IFSET(CPU_FTR_NEED_COHERENT)
+	rlwinm	r8,r8,0,~_PAGE_COHERENT	/* clear M (coherence not required) */
+END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
 #ifdef CONFIG_PTE_64BIT
 	/* Put the XPN bits into the PTE */
 	rlwimi	r8,r10,8,20,22
@@ -663,3 +633,80 @@
 	SYNC_601
 	isync
 	blr
+
+/*
+ * Flush an entry from the TLB
+ */
+_GLOBAL(_tlbie)
+#ifdef CONFIG_SMP
+	rlwinm	r8,r1,0,0,(31-THREAD_SHIFT)
+	lwz	r8,TI_CPU(r8)
+	oris	r8,r8,11
+	mfmsr	r10
+	SYNC
+	rlwinm	r0,r10,0,17,15		/* clear bit 16 (MSR_EE) */
+	rlwinm	r0,r0,0,28,26		/* clear DR */
+	mtmsr	r0
+	SYNC_601
+	isync
+	lis	r9,mmu_hash_lock@h
+	ori	r9,r9,mmu_hash_lock@l
+	tophys(r9,r9)
+10:	lwarx	r7,0,r9
+	cmpwi	0,r7,0
+	bne-	10b
+	stwcx.	r8,0,r9
+	bne-	10b
+	eieio
+	tlbie	r3
+	sync
+	TLBSYNC
+	li	r0,0
+	stw	r0,0(r9)		/* clear mmu_hash_lock */
+	mtmsr	r10
+	SYNC_601
+	isync
+#else /* CONFIG_SMP */
+	tlbie	r3
+	sync
+#endif /* CONFIG_SMP */
+	blr
+
+/*
+ * Flush the entire TLB. 603/603e only
+ */
+_GLOBAL(_tlbia)
+#if defined(CONFIG_SMP)
+	rlwinm	r8,r1,0,0,(31-THREAD_SHIFT)
+	lwz	r8,TI_CPU(r8)
+	oris	r8,r8,10
+	mfmsr	r10
+	SYNC
+	rlwinm	r0,r10,0,17,15		/* clear bit 16 (MSR_EE) */
+	rlwinm	r0,r0,0,28,26		/* clear DR */
+	mtmsr	r0
+	SYNC_601
+	isync
+	lis	r9,mmu_hash_lock@h
+	ori	r9,r9,mmu_hash_lock@l
+	tophys(r9,r9)
+10:	lwarx	r7,0,r9
+	cmpwi	0,r7,0
+	bne-	10b
+	stwcx.	r8,0,r9
+	bne-	10b
+	sync
+	tlbia
+	sync
+	TLBSYNC
+	li	r0,0
+	stw	r0,0(r9)		/* clear mmu_hash_lock */
+	mtmsr	r10
+	SYNC_601
+	isync
+#else /* CONFIG_SMP */
+	sync
+	tlbia
+	sync
+#endif /* CONFIG_SMP */
+	blr
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index f0c3b88..201c7a5 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -53,8 +53,7 @@
 
 /* Subtract one from array size because we don't need a cache for 4K since
  * is not a huge page size */
-#define huge_pgtable_cache(psize)	(pgtable_cache[HUGEPTE_CACHE_NUM \
-							+ psize-1])
+#define HUGE_PGTABLE_INDEX(psize)	(HUGEPTE_CACHE_NUM + psize - 1)
 #define HUGEPTE_CACHE_NAME(psize)	(huge_pgtable_cache_name[psize])
 
 static const char *huge_pgtable_cache_name[MMU_PAGE_COUNT] = {
@@ -113,7 +112,7 @@
 static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp,
 			   unsigned long address, unsigned int psize)
 {
-	pte_t *new = kmem_cache_zalloc(huge_pgtable_cache(psize),
+	pte_t *new = kmem_cache_zalloc(pgtable_cache[HUGE_PGTABLE_INDEX(psize)],
 				      GFP_KERNEL|__GFP_REPEAT);
 
 	if (! new)
@@ -121,7 +120,7 @@
 
 	spin_lock(&mm->page_table_lock);
 	if (!hugepd_none(*hpdp))
-		kmem_cache_free(huge_pgtable_cache(psize), new);
+		kmem_cache_free(pgtable_cache[HUGE_PGTABLE_INDEX(psize)], new);
 	else
 		hpdp->pd = (unsigned long)new | HUGEPD_OK;
 	spin_unlock(&mm->page_table_lock);
@@ -763,13 +762,14 @@
 
 	for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
 		if (mmu_huge_psizes[psize]) {
-			huge_pgtable_cache(psize) = kmem_cache_create(
-						HUGEPTE_CACHE_NAME(psize),
-						HUGEPTE_TABLE_SIZE(psize),
-						HUGEPTE_TABLE_SIZE(psize),
-						0,
-						NULL);
-			if (!huge_pgtable_cache(psize))
+			pgtable_cache[HUGE_PGTABLE_INDEX(psize)] =
+				kmem_cache_create(
+					HUGEPTE_CACHE_NAME(psize),
+					HUGEPTE_TABLE_SIZE(psize),
+					HUGEPTE_TABLE_SIZE(psize),
+					0,
+					NULL);
+			if (!pgtable_cache[HUGE_PGTABLE_INDEX(psize)])
 				panic("hugetlbpage_init(): could not create %s"\
 				      "\n", HUGEPTE_CACHE_NAME(psize));
 		}
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 388ceda..666a5e8 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -35,7 +35,6 @@
 #include <asm/pgalloc.h>
 #include <asm/prom.h>
 #include <asm/io.h>
-#include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
 #include <asm/smp.h>
@@ -49,7 +48,7 @@
 
 #if defined(CONFIG_KERNEL_START_BOOL) || defined(CONFIG_LOWMEM_SIZE_BOOL)
 /* The ammount of lowmem must be within 0xF0000000 - KERNELBASE. */
-#if (CONFIG_LOWMEM_SIZE > (0xF0000000 - KERNELBASE))
+#if (CONFIG_LOWMEM_SIZE > (0xF0000000 - PAGE_OFFSET))
 #error "You must adjust CONFIG_LOWMEM_SIZE or CONFIG_START_KERNEL"
 #endif
 #endif
@@ -180,9 +179,6 @@
 	if (ppc_md.progress)
 		ppc_md.progress("MMU:setio", 0x302);
 
-	/* Initialize the context management stuff */
-	mmu_context_init();
-
 	if (ppc_md.progress)
 		ppc_md.progress("MMU:exit", 0x211);
 
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index b9e1a1d..53b06eb 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -102,8 +102,8 @@
 		return ppc_md.phys_mem_access_prot(file, pfn, size, vma_prot);
 
 	if (!page_is_ram(pfn))
-		vma_prot = __pgprot(pgprot_val(vma_prot)
-				    | _PAGE_GUARDED | _PAGE_NO_CACHE);
+		vma_prot = pgprot_noncached(vma_prot);
+
 	return vma_prot;
 }
 EXPORT_SYMBOL(phys_mem_access_prot);
@@ -488,7 +488,7 @@
 		 * we invalidate the TLB here, thus avoiding dcbst
 		 * misbehaviour.
 		 */
-		_tlbie(address, 0 /* 8xx doesn't care about PID */);
+		_tlbil_va(address, 0 /* 8xx doesn't care about PID */);
 #endif
 		/* The _PAGE_USER test should really be _PAGE_EXEC, but
 		 * older glibc versions execute some code from no-exec
diff --git a/arch/powerpc/mm/mmu_context_32.c b/arch/powerpc/mm/mmu_context_32.c
deleted file mode 100644
index cc32ba4..0000000
--- a/arch/powerpc/mm/mmu_context_32.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * This file contains the routines for handling the MMU on those
- * PowerPC implementations where the MMU substantially follows the
- * architecture specification.  This includes the 6xx, 7xx, 7xxx,
- * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
- *  -- 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
- *
- *  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/mmu_context.h>
-#include <asm/tlbflush.h>
-
-unsigned long next_mmu_context;
-unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
-#ifdef FEW_CONTEXTS
-atomic_t nr_free_contexts;
-struct mm_struct *context_mm[LAST_CONTEXT+1];
-void steal_context(void);
-#endif /* FEW_CONTEXTS */
-
-/*
- * Initialize the context management stuff.
- */
-void __init
-mmu_context_init(void)
-{
-	/*
-	 * Some processors have too few contexts to reserve one for
-	 * init_mm, and require using context 0 for a normal task.
-	 * Other processors reserve the use of context zero for the kernel.
-	 * This code assumes FIRST_CONTEXT < 32.
-	 */
-	context_map[0] = (1 << FIRST_CONTEXT) - 1;
-	next_mmu_context = FIRST_CONTEXT;
-#ifdef FEW_CONTEXTS
-	atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1);
-#endif /* FEW_CONTEXTS */
-}
-
-#ifdef FEW_CONTEXTS
-/*
- * Steal a context from a task that has one at the moment.
- * This is only used on 8xx and 4xx and we presently assume that
- * they don't do SMP.  If they do then this will have to check
- * whether the MM we steal is in use.
- * We also assume that this is only used on systems that don't
- * use an MMU hash table - this is true for 8xx and 4xx.
- * 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 was motivated to do it.
- *  -- paulus
- */
-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);
-}
-#endif /* FEW_CONTEXTS */
diff --git a/arch/powerpc/mm/mmu_context_hash32.c b/arch/powerpc/mm/mmu_context_hash32.c
new file mode 100644
index 0000000..0dfba2b
--- /dev/null
+++ b/arch/powerpc/mm/mmu_context_hash32.c
@@ -0,0 +1,103 @@
+/*
+ * This file contains the routines for handling the MMU on those
+ * PowerPC implementations where the MMU substantially follows the
+ * architecture specification.  This includes the 6xx, 7xx, 7xxx,
+ * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
+ *  -- 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
+ *
+ *  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/mmu_context.h>
+#include <asm/tlbflush.h>
+
+/*
+ * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs
+ * (virtual segment identifiers) for each context.  Although the
+ * hardware supports 24-bit VSIDs, and thus >1 million contexts,
+ * we only use 32,768 of them.  That is ample, since there can be
+ * at most around 30,000 tasks in the system anyway, and it means
+ * that we can use a bitmap to indicate which contexts are in use.
+ * Using a bitmap means that we entirely avoid all of the problems
+ * that we used to have when the context number overflowed,
+ * particularly on SMP systems.
+ *  -- paulus.
+ */
+#define NO_CONTEXT      	((unsigned long) -1)
+#define LAST_CONTEXT    	32767
+#define FIRST_CONTEXT    	1
+
+/*
+ * 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.  Note, if this
+ * function is changed then arch/ppc/mm/hashtable.S will have to be
+ * changed to correspond.
+ *
+ *
+ * CTX_TO_VSID(ctx, va)	(((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \
+ *				 & 0xffffff)
+ */
+
+static unsigned long next_mmu_context;
+static unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
+
+
+/*
+ * Set up the context for a new address space.
+ */
+int init_new_context(struct task_struct *t, struct mm_struct *mm)
+{
+	unsigned long 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.id = ctx;
+
+	return 0;
+}
+
+/*
+ * We're finished using the context for an address space.
+ */
+void destroy_context(struct mm_struct *mm)
+{
+	preempt_disable();
+	if (mm->context.id != NO_CONTEXT) {
+		clear_bit(mm->context.id, context_map);
+		mm->context.id = NO_CONTEXT;
+	}
+	preempt_enable();
+}
+
+/*
+ * Initialize the context management stuff.
+ */
+void __init mmu_context_init(void)
+{
+	/* Reserve context 0 for kernel use */
+	context_map[0] = (1 << FIRST_CONTEXT) - 1;
+	next_mmu_context = FIRST_CONTEXT;
+}
diff --git a/arch/powerpc/mm/mmu_context_64.c b/arch/powerpc/mm/mmu_context_hash64.c
similarity index 85%
rename from arch/powerpc/mm/mmu_context_64.c
rename to arch/powerpc/mm/mmu_context_hash64.c
index 1db38ba..dbeb86a 100644
--- a/arch/powerpc/mm/mmu_context_64.c
+++ b/arch/powerpc/mm/mmu_context_hash64.c
@@ -24,6 +24,14 @@
 static DEFINE_SPINLOCK(mmu_context_lock);
 static DEFINE_IDR(mmu_context_idr);
 
+/*
+ * The proto-VSID space has 2^35 - 1 segments available for user mappings.
+ * Each segment contains 2^28 bytes.  Each context maps 2^44 bytes,
+ * so we can support 2^19-1 contexts (19 == 35 + 28 - 44).
+ */
+#define NO_CONTEXT	0
+#define MAX_CONTEXT	((1UL << 19) - 1)
+
 int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
 	int index;
diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c
new file mode 100644
index 0000000..52a0cfc
--- /dev/null
+++ b/arch/powerpc/mm/mmu_context_nohash.c
@@ -0,0 +1,397 @@
+/*
+ * This file contains the routines for handling the MMU on those
+ * PowerPC implementations where the MMU is not using the hash
+ * table, such as 8xx, 4xx, BookE's etc...
+ *
+ * Copyright 2008 Ben Herrenschmidt <benh@kernel.crashing.org>
+ *                IBM Corp.
+ *
+ *  Derived from previous arch/powerpc/mm/mmu_context.c
+ *  and arch/powerpc/include/asm/mmu_context.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.
+ *
+ * TODO:
+ *
+ *   - The global context lock will not scale very well
+ *   - The maps should be dynamically allocated to allow for processors
+ *     that support more PID bits at runtime
+ *   - Implement flush_tlb_mm() by making the context stale and picking
+ *     a new one
+ *   - More aggressively clear stale map bits and maybe find some way to
+ *     also clear mm->cpu_vm_mask bits when processes are migrated
+ */
+
+#undef DEBUG
+#define DEBUG_STEAL_ONLY
+#undef DEBUG_MAP_CONSISTENCY
+/*#define DEBUG_CLAMP_LAST_CONTEXT   15 */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/bootmem.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+
+static unsigned int first_context, last_context;
+static unsigned int next_context, nr_free_contexts;
+static unsigned long *context_map;
+static unsigned long *stale_map[NR_CPUS];
+static struct mm_struct **context_mm;
+static spinlock_t context_lock = SPIN_LOCK_UNLOCKED;
+
+#define CTX_MAP_SIZE	\
+	(sizeof(unsigned long) * (last_context / BITS_PER_LONG + 1))
+
+
+/* Steal a context from a task that has one at the moment.
+ *
+ * This is used when we are running out of available PID numbers
+ * on the processors.
+ *
+ * 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 was motivated to do it.
+ *  -- paulus
+ *
+ * For context stealing, we use a slightly different approach for
+ * SMP and UP. Basically, the UP one is simpler and doesn't use
+ * the stale map as we can just flush the local CPU
+ *  -- benh
+ */
+#ifdef CONFIG_SMP
+static unsigned int steal_context_smp(unsigned int id)
+{
+	struct mm_struct *mm;
+	unsigned int cpu, max;
+
+ again:
+	max = last_context - first_context;
+
+	/* Attempt to free next_context first and then loop until we manage */
+	while (max--) {
+		/* Pick up the victim mm */
+		mm = context_mm[id];
+
+		/* We have a candidate victim, check if it's active, on SMP
+		 * we cannot steal active contexts
+		 */
+		if (mm->context.active) {
+			id++;
+			if (id > last_context)
+				id = first_context;
+			continue;
+		}
+		pr_debug("[%d] steal context %d from mm @%p\n",
+			 smp_processor_id(), id, mm);
+
+		/* Mark this mm has having no context anymore */
+		mm->context.id = MMU_NO_CONTEXT;
+
+		/* Mark it stale on all CPUs that used this mm */
+		for_each_cpu_mask_nr(cpu, mm->cpu_vm_mask)
+			__set_bit(id, stale_map[cpu]);
+		return id;
+	}
+
+	/* This will happen if you have more CPUs than available contexts,
+	 * all we can do here is wait a bit and try again
+	 */
+	spin_unlock(&context_lock);
+	cpu_relax();
+	spin_lock(&context_lock);
+	goto again;
+}
+#endif  /* CONFIG_SMP */
+
+/* Note that this will also be called on SMP if all other CPUs are
+ * offlined, which means that it may be called for cpu != 0. For
+ * this to work, we somewhat assume that CPUs that are onlined
+ * come up with a fully clean TLB (or are cleaned when offlined)
+ */
+static unsigned int steal_context_up(unsigned int id)
+{
+	struct mm_struct *mm;
+	int cpu = smp_processor_id();
+
+	/* Pick up the victim mm */
+	mm = context_mm[id];
+
+	pr_debug("[%d] steal context %d from mm @%p\n", cpu, id, mm);
+
+	/* Mark this mm has having no context anymore */
+	mm->context.id = MMU_NO_CONTEXT;
+
+	/* Flush the TLB for that context */
+	local_flush_tlb_mm(mm);
+
+	/* XXX This clear should ultimately be part of local_flush_tlb_mm */
+	__clear_bit(id, stale_map[cpu]);
+
+	return id;
+}
+
+#ifdef DEBUG_MAP_CONSISTENCY
+static void context_check_map(void)
+{
+	unsigned int id, nrf, nact;
+
+	nrf = nact = 0;
+	for (id = first_context; id <= last_context; id++) {
+		int used = test_bit(id, context_map);
+		if (!used)
+			nrf++;
+		if (used != (context_mm[id] != NULL))
+			pr_err("MMU: Context %d is %s and MM is %p !\n",
+			       id, used ? "used" : "free", context_mm[id]);
+		if (context_mm[id] != NULL)
+			nact += context_mm[id]->context.active;
+	}
+	if (nrf != nr_free_contexts) {
+		pr_err("MMU: Free context count out of sync ! (%d vs %d)\n",
+		       nr_free_contexts, nrf);
+		nr_free_contexts = nrf;
+	}
+	if (nact > num_online_cpus())
+		pr_err("MMU: More active contexts than CPUs ! (%d vs %d)\n",
+		       nact, num_online_cpus());
+	if (first_context > 0 && !test_bit(0, context_map))
+		pr_err("MMU: Context 0 has been freed !!!\n");
+}
+#else
+static void context_check_map(void) { }
+#endif
+
+void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
+{
+	unsigned int id, cpu = smp_processor_id();
+	unsigned long *map;
+
+	/* No lockless fast path .. yet */
+	spin_lock(&context_lock);
+
+#ifndef DEBUG_STEAL_ONLY
+	pr_debug("[%d] activating context for mm @%p, active=%d, id=%d\n",
+		 cpu, next, next->context.active, next->context.id);
+#endif
+
+#ifdef CONFIG_SMP
+	/* Mark us active and the previous one not anymore */
+	next->context.active++;
+	if (prev) {
+#ifndef DEBUG_STEAL_ONLY
+		pr_debug(" old context %p active was: %d\n",
+			 prev, prev->context.active);
+#endif
+		WARN_ON(prev->context.active < 1);
+		prev->context.active--;
+	}
+#endif /* CONFIG_SMP */
+
+	/* If we already have a valid assigned context, skip all that */
+	id = next->context.id;
+	if (likely(id != MMU_NO_CONTEXT))
+		goto ctxt_ok;
+
+	/* We really don't have a context, let's try to acquire one */
+	id = next_context;
+	if (id > last_context)
+		id = first_context;
+	map = context_map;
+
+	/* No more free contexts, let's try to steal one */
+	if (nr_free_contexts == 0) {
+#ifdef CONFIG_SMP
+		if (num_online_cpus() > 1) {
+			id = steal_context_smp(id);
+			goto stolen;
+		}
+#endif /* CONFIG_SMP */
+		id = steal_context_up(id);
+		goto stolen;
+	}
+	nr_free_contexts--;
+
+	/* We know there's at least one free context, try to find it */
+	while (__test_and_set_bit(id, map)) {
+		id = find_next_zero_bit(map, last_context+1, id);
+		if (id > last_context)
+			id = first_context;
+	}
+ stolen:
+	next_context = id + 1;
+	context_mm[id] = next;
+	next->context.id = id;
+
+#ifndef DEBUG_STEAL_ONLY
+	pr_debug("[%d] picked up new id %d, nrf is now %d\n",
+		 cpu, id, nr_free_contexts);
+#endif
+
+	context_check_map();
+ ctxt_ok:
+
+	/* If that context got marked stale on this CPU, then flush the
+	 * local TLB for it and unmark it before we use it
+	 */
+	if (test_bit(id, stale_map[cpu])) {
+		pr_debug("[%d] flushing stale context %d for mm @%p !\n",
+			 cpu, id, next);
+		local_flush_tlb_mm(next);
+
+		/* XXX This clear should ultimately be part of local_flush_tlb_mm */
+		__clear_bit(id, stale_map[cpu]);
+	}
+
+	/* Flick the MMU and release lock */
+	set_context(id, next->pgd);
+	spin_unlock(&context_lock);
+}
+
+/*
+ * Set up the context for a new address space.
+ */
+int init_new_context(struct task_struct *t, struct mm_struct *mm)
+{
+	mm->context.id = MMU_NO_CONTEXT;
+	mm->context.active = 0;
+
+	return 0;
+}
+
+/*
+ * We're finished using the context for an address space.
+ */
+void destroy_context(struct mm_struct *mm)
+{
+	unsigned int id;
+
+	if (mm->context.id == MMU_NO_CONTEXT)
+		return;
+
+	WARN_ON(mm->context.active != 0);
+
+	spin_lock(&context_lock);
+	id = mm->context.id;
+	if (id != MMU_NO_CONTEXT) {
+		__clear_bit(id, context_map);
+		mm->context.id = MMU_NO_CONTEXT;
+#ifdef DEBUG_MAP_CONSISTENCY
+		mm->context.active = 0;
+		context_mm[id] = NULL;
+#endif
+		nr_free_contexts++;
+	}
+	spin_unlock(&context_lock);
+}
+
+#ifdef CONFIG_SMP
+
+static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
+					    unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned int)(long)hcpu;
+
+	/* We don't touch CPU 0 map, it's allocated at aboot and kept
+	 * around forever
+	 */
+	if (cpu == 0)
+		return NOTIFY_OK;
+
+	switch (action) {
+	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
+		pr_debug("MMU: Allocating stale context map for CPU %d\n", cpu);
+		stale_map[cpu] = kzalloc(CTX_MAP_SIZE, GFP_KERNEL);
+		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
+		pr_debug("MMU: Freeing stale context map for CPU %d\n", cpu);
+		kfree(stale_map[cpu]);
+		stale_map[cpu] = NULL;
+		break;
+#endif
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata mmu_context_cpu_nb = {
+	.notifier_call	= mmu_context_cpu_notify,
+};
+
+#endif /* CONFIG_SMP */
+
+/*
+ * Initialize the context management stuff.
+ */
+void __init mmu_context_init(void)
+{
+	/* Mark init_mm as being active on all possible CPUs since
+	 * we'll get called with prev == init_mm the first time
+	 * we schedule on a given CPU
+	 */
+	init_mm.context.active = NR_CPUS;
+
+	/*
+	 *   The MPC8xx has only 16 contexts.  We rotate through them on each
+	 * task switch.  A better way would be to keep track of tasks that
+	 * own contexts, and implement an LRU usage.  That way very active
+	 * tasks don't always have to pay the TLB reload overhead.  The
+	 * kernel pages are mapped shared, so the kernel can run on behalf
+	 * of any task that makes a kernel entry.  Shared does not mean they
+	 * are not protected, just that the ASID comparison is not performed.
+	 *      -- Dan
+	 *
+	 * The IBM4xx 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.
+	 * 	-- Dan
+	 */
+	if (mmu_has_feature(MMU_FTR_TYPE_8xx)) {
+		first_context = 0;
+		last_context = 15;
+	} else {
+		first_context = 1;
+		last_context = 255;
+	}
+
+#ifdef DEBUG_CLAMP_LAST_CONTEXT
+	last_context = DEBUG_CLAMP_LAST_CONTEXT;
+#endif
+	/*
+	 * Allocate the maps used by context management
+	 */
+	context_map = alloc_bootmem(CTX_MAP_SIZE);
+	context_mm = alloc_bootmem(sizeof(void *) * (last_context + 1));
+	stale_map[0] = alloc_bootmem(CTX_MAP_SIZE);
+
+#ifdef CONFIG_SMP
+	register_cpu_notifier(&mmu_context_cpu_nb);
+#endif
+
+	printk(KERN_INFO
+	       "MMU: Allocated %d bytes of context maps for %d contexts\n",
+	       2 * CTX_MAP_SIZE + (sizeof(void *) * (last_context + 1)),
+	       last_context - first_context + 1);
+
+	/*
+	 * Some processors have too few contexts to reserve one for
+	 * init_mm, and require using context 0 for a normal task.
+	 * Other processors reserve the use of context zero for the kernel.
+	 * This code assumes first_context < 32.
+	 */
+	context_map[0] = (1 << first_context) - 1;
+	next_context = first_context;
+	nr_free_contexts = last_context - first_context + 1;
+}
+
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index fab3cfa..4314b39 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -22,10 +22,58 @@
 #include <asm/tlbflush.h>
 #include <asm/mmu.h>
 
+#ifdef CONFIG_PPC_MMU_NOHASH
+
+/*
+ * On 40x and 8xx, we directly inline tlbia and tlbivax
+ */
+#if defined(CONFIG_40x) || defined(CONFIG_8xx)
+static inline void _tlbil_all(void)
+{
+	asm volatile ("sync; tlbia; isync" : : : "memory")
+}
+static inline void _tlbil_pid(unsigned int pid)
+{
+	asm volatile ("sync; tlbia; isync" : : : "memory")
+}
+#else /* CONFIG_40x || CONFIG_8xx */
+extern void _tlbil_all(void);
+extern void _tlbil_pid(unsigned int pid);
+#endif /* !(CONFIG_40x || CONFIG_8xx) */
+
+/*
+ * On 8xx, we directly inline tlbie, on others, it's extern
+ */
+#ifdef CONFIG_8xx
+static inline void _tlbil_va(unsigned long address, unsigned int pid)
+{
+	asm volatile ("tlbie %0; sync" : : "r" (address) : "memory")
+}
+#else /* CONFIG_8xx */
+extern void _tlbil_va(unsigned long address, unsigned int pid);
+#endif /* CONIFG_8xx */
+
+/*
+ * As of today, we don't support tlbivax broadcast on any
+ * implementation. When that becomes the case, this will be
+ * an extern.
+ */
+static inline void _tlbivax_bcast(unsigned long address, unsigned int pid)
+{
+	BUG();
+}
+
+#else /* CONFIG_PPC_MMU_NOHASH */
+
 extern void hash_preload(struct mm_struct *mm, unsigned long ea,
 			 unsigned long access, unsigned long trap);
 
 
+extern void _tlbie(unsigned long address);
+extern void _tlbia(void);
+
+#endif /* CONFIG_PPC_MMU_NOHASH */
+
 #ifdef CONFIG_PPC32
 extern void mapin_ram(void);
 extern int map_page(unsigned long va, phys_addr_t pa, int flags);
@@ -58,17 +106,14 @@
  * architectures.  -- Dan
  */
 #if defined(CONFIG_8xx)
-#define flush_HPTE(X, va, pg)	_tlbie(va, 0 /* 8xx doesn't care about PID */)
 #define MMU_init_hw()		do { } while(0)
 #define mmu_mapin_ram()		(0UL)
 
 #elif defined(CONFIG_4xx)
-#define flush_HPTE(pid, va, pg)	_tlbie(va, pid)
 extern void MMU_init_hw(void);
 extern unsigned long mmu_mapin_ram(void);
 
 #elif defined(CONFIG_FSL_BOOKE)
-#define flush_HPTE(pid, va, pg)	_tlbie(va, pid)
 extern void MMU_init_hw(void);
 extern unsigned long mmu_mapin_ram(void);
 extern void adjust_total_lowmem(void);
@@ -77,18 +122,4 @@
 /* anything 32-bit except 4xx or 8xx */
 extern void MMU_init_hw(void);
 extern unsigned long mmu_mapin_ram(void);
-
-/* Be careful....this needs to be updated if we ever encounter 603 SMPs,
- * which includes all new 82xx processors.  We need tlbie/tlbsync here
- * in that case (I think). -- Dan.
- */
-static inline void flush_HPTE(unsigned context, unsigned long va,
-			      unsigned long pdval)
-{
-	if ((Hash != 0) &&
-	    cpu_has_feature(CPU_FTR_HPTE_TABLE))
-		flush_hash_pages(0, va, pdval, 1);
-	else
-		_tlbie(va);
-}
 #endif
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
new file mode 100644
index 0000000..6d94116
--- /dev/null
+++ b/arch/powerpc/mm/pgtable.c
@@ -0,0 +1,117 @@
+/*
+ * This file contains common routines for dealing with free of page tables
+ *
+ *  Derived from arch/powerpc/mm/tlb_64.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
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  Dave Engebretsen <engebret@us.ibm.com>
+ *      Rework for PPC64 port.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the 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/mm.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+#include <linux/hardirq.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+#include <asm/tlb.h>
+
+static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
+static unsigned long pte_freelist_forced_free;
+
+struct pte_freelist_batch
+{
+	struct rcu_head	rcu;
+	unsigned int	index;
+	pgtable_free_t	tables[0];
+};
+
+#define PTE_FREELIST_SIZE \
+	((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \
+	  / sizeof(pgtable_free_t))
+
+static void pte_free_smp_sync(void *arg)
+{
+	/* Do nothing, just ensure we sync with all CPUs */
+}
+
+/* This is only called when we are critically out of memory
+ * (and fail to get a page in pte_free_tlb).
+ */
+static void pgtable_free_now(pgtable_free_t pgf)
+{
+	pte_freelist_forced_free++;
+
+	smp_call_function(pte_free_smp_sync, NULL, 1);
+
+	pgtable_free(pgf);
+}
+
+static void pte_free_rcu_callback(struct rcu_head *head)
+{
+	struct pte_freelist_batch *batch =
+		container_of(head, struct pte_freelist_batch, rcu);
+	unsigned int i;
+
+	for (i = 0; i < batch->index; i++)
+		pgtable_free(batch->tables[i]);
+
+	free_page((unsigned long)batch);
+}
+
+static void pte_free_submit(struct pte_freelist_batch *batch)
+{
+	INIT_RCU_HEAD(&batch->rcu);
+	call_rcu(&batch->rcu, pte_free_rcu_callback);
+}
+
+void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)
+{
+	/* This is safe since tlb_gather_mmu has disabled preemption */
+        cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id());
+	struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
+
+	if (atomic_read(&tlb->mm->mm_users) < 2 ||
+	    cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) {
+		pgtable_free(pgf);
+		return;
+	}
+
+	if (*batchp == NULL) {
+		*batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
+		if (*batchp == NULL) {
+			pgtable_free_now(pgf);
+			return;
+		}
+		(*batchp)->index = 0;
+	}
+	(*batchp)->tables[(*batchp)->index++] = pgf;
+	if ((*batchp)->index == PTE_FREELIST_SIZE) {
+		pte_free_submit(*batchp);
+		*batchp = NULL;
+	}
+}
+
+void pte_free_finish(void)
+{
+	/* This is safe since tlb_gather_mmu has disabled preemption */
+	struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
+
+	if (*batchp == NULL)
+		return;
+	pte_free_submit(*batchp);
+	*batchp = NULL;
+}
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index c31d6d2..38ff35f 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -48,10 +48,6 @@
 
 extern char etext[], _stext[];
 
-#ifdef CONFIG_SMP
-extern void hash_page_sync(void);
-#endif
-
 #ifdef HAVE_BATS
 extern phys_addr_t v_mapped_by_bats(unsigned long va);
 extern unsigned long p_mapped_by_bats(phys_addr_t pa);
@@ -72,24 +68,29 @@
 #define p_mapped_by_tlbcam(x)	(0UL)
 #endif /* HAVE_TLBCAM */
 
-#ifdef CONFIG_PTE_64BIT
-/* Some processors use an 8kB pgdir because they have 8-byte Linux PTEs. */
-#define PGDIR_ORDER	1
-#else
-#define PGDIR_ORDER	0
-#endif
+#define PGDIR_ORDER	(32 + PGD_T_LOG2 - PGDIR_SHIFT)
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	pgd_t *ret;
 
-	ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORDER);
+	/* pgdir take page or two with 4K pages and a page fraction otherwise */
+#ifndef CONFIG_PPC_4K_PAGES
+	ret = (pgd_t *)kzalloc(1 << PGDIR_ORDER, GFP_KERNEL);
+#else
+	ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
+			PGDIR_ORDER - PAGE_SHIFT);
+#endif
 	return ret;
 }
 
 void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-	free_pages((unsigned long)pgd, PGDIR_ORDER);
+#ifndef CONFIG_PPC_4K_PAGES
+	kfree((void *)pgd);
+#else
+	free_pages((unsigned long)pgd, PGDIR_ORDER - PAGE_SHIFT);
+#endif
 }
 
 __init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
@@ -125,23 +126,6 @@
 	return ptepage;
 }
 
-void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
-#ifdef CONFIG_SMP
-	hash_page_sync();
-#endif
-	free_page((unsigned long)pte);
-}
-
-void pte_free(struct mm_struct *mm, pgtable_t ptepage)
-{
-#ifdef CONFIG_SMP
-	hash_page_sync();
-#endif
-	pgtable_page_dtor(ptepage);
-	__free_page(ptepage);
-}
-
 void __iomem *
 ioremap(phys_addr_t addr, unsigned long size)
 {
@@ -194,6 +178,7 @@
 	if (p < 16*1024*1024)
 		p += _ISA_MEM_BASE;
 
+#ifndef CONFIG_CRASH_DUMP
 	/*
 	 * Don't allow anybody to remap normal RAM that we're using.
 	 * mem_init() sets high_memory so only do the check after that.
@@ -203,6 +188,7 @@
 		       (unsigned long long)p, __builtin_return_address(0));
 		return NULL;
 	}
+#endif
 
 	if (size == 0)
 		return NULL;
@@ -288,7 +274,7 @@
 }
 
 /*
- * Map in a big chunk of physical memory starting at KERNELBASE.
+ * Map in a big chunk of physical memory starting at PAGE_OFFSET.
  */
 void __init mapin_ram(void)
 {
@@ -297,7 +283,7 @@
 	int ktext;
 
 	s = mmu_mapin_ram();
-	v = KERNELBASE + s;
+	v = PAGE_OFFSET + s;
 	p = memstart_addr + s;
 	for (; s < total_lowmem; s += PAGE_SIZE) {
 		ktext = ((char *) v >= _stext && (char *) v < etext);
@@ -363,7 +349,11 @@
 		return -EINVAL;
 	set_pte_at(&init_mm, address, kpte, mk_pte(page, prot));
 	wmb();
-	flush_HPTE(0, address, pmd_val(*kpmd));
+#ifdef CONFIG_PPC_STD_MMU
+	flush_hash_pages(0, address, pmd_val(*kpmd), 1);
+#else
+	flush_tlb_page(NULL, address);
+#endif
 	pte_unmap(kpte);
 
 	return 0;
@@ -400,7 +390,7 @@
 #endif /* CONFIG_DEBUG_PAGEALLOC */
 
 static int fixmaps;
-unsigned long FIXADDR_TOP = 0xfffff000;
+unsigned long FIXADDR_TOP = (-PAGE_SIZE);
 EXPORT_SYMBOL(FIXADDR_TOP);
 
 void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index 6aa1208..45d9253 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -95,16 +95,16 @@
 			break;
 	}
 
-	setbat(2, KERNELBASE, 0, bl, _PAGE_RAM);
-	done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
+	setbat(2, PAGE_OFFSET, 0, bl, _PAGE_RAM);
+	done = (unsigned long)bat_addrs[2].limit - PAGE_OFFSET + 1;
 	if ((done < tot) && !bat_addrs[3].limit) {
 		/* use BAT3 to cover a bit more */
 		tot -= done;
 		for (bl = 128<<10; bl < max_size; bl <<= 1)
 			if (bl * 2 > tot)
 				break;
-		setbat(3, KERNELBASE+done, done, bl, _PAGE_RAM);
-		done = (unsigned long)bat_addrs[3].limit - KERNELBASE + 1;
+		setbat(3, PAGE_OFFSET+done, done, bl, _PAGE_RAM);
+		done = (unsigned long)bat_addrs[3].limit - PAGE_OFFSET + 1;
 	}
 
 	return done;
@@ -192,7 +192,7 @@
 	extern unsigned int hash_page[];
 	extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[];
 
-	if (!cpu_has_feature(CPU_FTR_HPTE_TABLE)) {
+	if (!mmu_has_feature(MMU_FTR_HPTE_TABLE)) {
 		/*
 		 * Put a blr (procedure return) instruction at the
 		 * start of hash_page, since we can still get DSI
diff --git a/arch/powerpc/mm/tlb_32.c b/arch/powerpc/mm/tlb_hash32.c
similarity index 96%
rename from arch/powerpc/mm/tlb_32.c
rename to arch/powerpc/mm/tlb_hash32.c
index f9a47fe..6519058 100644
--- a/arch/powerpc/mm/tlb_32.c
+++ b/arch/powerpc/mm/tlb_hash32.c
@@ -137,6 +137,7 @@
 	flush_range(&init_mm, start, end);
 	FINISH_FLUSH;
 }
+EXPORT_SYMBOL(flush_tlb_kernel_range);
 
 /*
  * Flush all the (user) entries for the address space described by mm.
@@ -160,6 +161,7 @@
 		flush_range(mp->vm_mm, mp->vm_start, mp->vm_end);
 	FINISH_FLUSH;
 }
+EXPORT_SYMBOL(flush_tlb_mm);
 
 void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 {
@@ -176,6 +178,7 @@
 		flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1);
 	FINISH_FLUSH;
 }
+EXPORT_SYMBOL(flush_tlb_page);
 
 /*
  * For each address in the range, find the pte for the address
@@ -188,3 +191,4 @@
 	flush_range(vma->vm_mm, start, end);
 	FINISH_FLUSH;
 }
+EXPORT_SYMBOL(flush_tlb_range);
diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_hash64.c
similarity index 74%
rename from arch/powerpc/mm/tlb_64.c
rename to arch/powerpc/mm/tlb_hash64.c
index be7dd42..c931bc7 100644
--- a/arch/powerpc/mm/tlb_64.c
+++ b/arch/powerpc/mm/tlb_hash64.c
@@ -37,81 +37,6 @@
  * arch/powerpc/include/asm/tlb.h file -- tgall
  */
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
-static unsigned long pte_freelist_forced_free;
-
-struct pte_freelist_batch
-{
-	struct rcu_head	rcu;
-	unsigned int	index;
-	pgtable_free_t	tables[0];
-};
-
-#define PTE_FREELIST_SIZE \
-	((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \
-	  / sizeof(pgtable_free_t))
-
-static void pte_free_smp_sync(void *arg)
-{
-	/* Do nothing, just ensure we sync with all CPUs */
-}
-
-/* This is only called when we are critically out of memory
- * (and fail to get a page in pte_free_tlb).
- */
-static void pgtable_free_now(pgtable_free_t pgf)
-{
-	pte_freelist_forced_free++;
-
-	smp_call_function(pte_free_smp_sync, NULL, 1);
-
-	pgtable_free(pgf);
-}
-
-static void pte_free_rcu_callback(struct rcu_head *head)
-{
-	struct pte_freelist_batch *batch =
-		container_of(head, struct pte_freelist_batch, rcu);
-	unsigned int i;
-
-	for (i = 0; i < batch->index; i++)
-		pgtable_free(batch->tables[i]);
-
-	free_page((unsigned long)batch);
-}
-
-static void pte_free_submit(struct pte_freelist_batch *batch)
-{
-	INIT_RCU_HEAD(&batch->rcu);
-	call_rcu(&batch->rcu, pte_free_rcu_callback);
-}
-
-void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)
-{
-	/* This is safe since tlb_gather_mmu has disabled preemption */
-        cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id());
-	struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
-
-	if (atomic_read(&tlb->mm->mm_users) < 2 ||
-	    cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) {
-		pgtable_free(pgf);
-		return;
-	}
-
-	if (*batchp == NULL) {
-		*batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
-		if (*batchp == NULL) {
-			pgtable_free_now(pgf);
-			return;
-		}
-		(*batchp)->index = 0;
-	}
-	(*batchp)->tables[(*batchp)->index++] = pgf;
-	if ((*batchp)->index == PTE_FREELIST_SIZE) {
-		pte_free_submit(*batchp);
-		*batchp = NULL;
-	}
-}
 
 /*
  * A linux PTE was changed and the corresponding hash table entry
@@ -229,17 +154,6 @@
 	batch->index = 0;
 }
 
-void pte_free_finish(void)
-{
-	/* This is safe since tlb_gather_mmu has disabled preemption */
-	struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
-
-	if (*batchp == NULL)
-		return;
-	pte_free_submit(*batchp);
-	*batchp = NULL;
-}
-
 /**
  * __flush_hash_table_range - Flush all HPTEs for a given address range
  *                            from the hash table (and the TLB). But keeps
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
new file mode 100644
index 0000000..803a64c
--- /dev/null
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -0,0 +1,209 @@
+/*
+ * This file contains the routines for TLB flushing.
+ * On machines where the MMU does not use a hash table to store virtual to
+ * physical translations (ie, SW loaded TLBs or Book3E compilant processors,
+ * this does -not- include 603 however which shares the implementation with
+ * hash based processors)
+ *
+ *  -- BenH
+ *
+ * Copyright 2008 Ben Herrenschmidt <benh@kernel.crashing.org>
+ *                IBM Corp.
+ *
+ *  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
+ *
+ *  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/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/preempt.h>
+#include <linux/spinlock.h>
+
+#include <asm/tlbflush.h>
+#include <asm/tlb.h>
+
+#include "mmu_decl.h"
+
+/*
+ * Base TLB flushing operations:
+ *
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
+ *  - flush_tlb_kernel_range(start, end) flushes kernel pages
+ *
+ *  - local_* variants of page and mm only apply to the current
+ *    processor
+ */
+
+/*
+ * These are the base non-SMP variants of page and mm flushing
+ */
+void local_flush_tlb_mm(struct mm_struct *mm)
+{
+	unsigned int pid;
+
+	preempt_disable();
+	pid = mm->context.id;
+	if (pid != MMU_NO_CONTEXT)
+		_tlbil_pid(pid);
+	preempt_enable();
+}
+EXPORT_SYMBOL(local_flush_tlb_mm);
+
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+	unsigned int pid;
+
+	preempt_disable();
+	pid = vma ? vma->vm_mm->context.id : 0;
+	if (pid != MMU_NO_CONTEXT)
+		_tlbil_va(vmaddr, pid);
+	preempt_enable();
+}
+EXPORT_SYMBOL(local_flush_tlb_page);
+
+
+/*
+ * And here are the SMP non-local implementations
+ */
+#ifdef CONFIG_SMP
+
+static DEFINE_SPINLOCK(tlbivax_lock);
+
+struct tlb_flush_param {
+	unsigned long addr;
+	unsigned int pid;
+};
+
+static void do_flush_tlb_mm_ipi(void *param)
+{
+	struct tlb_flush_param *p = param;
+
+	_tlbil_pid(p ? p->pid : 0);
+}
+
+static void do_flush_tlb_page_ipi(void *param)
+{
+	struct tlb_flush_param *p = param;
+
+	_tlbil_va(p->addr, p->pid);
+}
+
+
+/* Note on invalidations and PID:
+ *
+ * We snapshot the PID with preempt disabled. At this point, it can still
+ * change either because:
+ * - our context is being stolen (PID -> NO_CONTEXT) on another CPU
+ * - we are invaliating some target that isn't currently running here
+ *   and is concurrently acquiring a new PID on another CPU
+ * - some other CPU is re-acquiring a lost PID for this mm
+ * etc...
+ *
+ * However, this shouldn't be a problem as we only guarantee
+ * invalidation of TLB entries present prior to this call, so we
+ * don't care about the PID changing, and invalidating a stale PID
+ * is generally harmless.
+ */
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+	cpumask_t cpu_mask;
+	unsigned int pid;
+
+	preempt_disable();
+	pid = mm->context.id;
+	if (unlikely(pid == MMU_NO_CONTEXT))
+		goto no_context;
+	cpu_mask = mm->cpu_vm_mask;
+	cpu_clear(smp_processor_id(), cpu_mask);
+	if (!cpus_empty(cpu_mask)) {
+		struct tlb_flush_param p = { .pid = pid };
+		smp_call_function_mask(cpu_mask, do_flush_tlb_mm_ipi, &p, 1);
+	}
+	_tlbil_pid(pid);
+ no_context:
+	preempt_enable();
+}
+EXPORT_SYMBOL(flush_tlb_mm);
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+	cpumask_t cpu_mask;
+	unsigned int pid;
+
+	preempt_disable();
+	pid = vma ? vma->vm_mm->context.id : 0;
+	if (unlikely(pid == MMU_NO_CONTEXT))
+		goto bail;
+	cpu_mask = vma->vm_mm->cpu_vm_mask;
+	cpu_clear(smp_processor_id(), cpu_mask);
+	if (!cpus_empty(cpu_mask)) {
+		/* If broadcast tlbivax is supported, use it */
+		if (mmu_has_feature(MMU_FTR_USE_TLBIVAX_BCAST)) {
+			int lock = mmu_has_feature(MMU_FTR_LOCK_BCAST_INVAL);
+			if (lock)
+				spin_lock(&tlbivax_lock);
+			_tlbivax_bcast(vmaddr, pid);
+			if (lock)
+				spin_unlock(&tlbivax_lock);
+			goto bail;
+		} else {
+			struct tlb_flush_param p = { .pid = pid, .addr = vmaddr };
+			smp_call_function_mask(cpu_mask,
+					       do_flush_tlb_page_ipi, &p, 1);
+		}
+	}
+	_tlbil_va(vmaddr, pid);
+ bail:
+	preempt_enable();
+}
+EXPORT_SYMBOL(flush_tlb_page);
+
+#endif /* CONFIG_SMP */
+
+/*
+ * Flush kernel TLB entries in the given range
+ */
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+#ifdef CONFIG_SMP
+	preempt_disable();
+	smp_call_function(do_flush_tlb_mm_ipi, NULL, 1);
+	_tlbil_pid(0);
+	preempt_enable();
+#endif
+	_tlbil_pid(0);
+}
+EXPORT_SYMBOL(flush_tlb_kernel_range);
+
+/*
+ * Currently, for range flushing, we just do a full mm flush. This should
+ * be optimized based on a threshold on the size of the range, since
+ * some implementation can stack multiple tlbivax before a tlbsync but
+ * for now, we keep it that way
+ */
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+		     unsigned long end)
+
+{
+	flush_tlb_mm(vma->vm_mm);
+}
+EXPORT_SYMBOL(flush_tlb_range);
diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S
new file mode 100644
index 0000000..f900a39
--- /dev/null
+++ b/arch/powerpc/mm/tlb_nohash_low.S
@@ -0,0 +1,166 @@
+/*
+ * This file contains low-level functions for performing various
+ * types of TLB invalidations on various processors with no hash
+ * table.
+ *
+ * This file implements the following functions for all no-hash
+ * processors. Some aren't implemented for some variants. Some
+ * are inline in tlbflush.h
+ *
+ *	- tlbil_va
+ *	- tlbil_pid
+ *	- tlbil_all
+ *	- tlbivax_bcast (not yet)
+ *
+ * Code mostly moved over from misc_32.S
+ *
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Partially rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * Paul Mackerras, Kumar Gala and Benjamin Herrenschmidt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/mmu.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/processor.h>
+
+#if defined(CONFIG_40x)
+
+/*
+ * 40x implementation needs only tlbil_va
+ */
+_GLOBAL(_tlbil_va)
+	/* We run the search with interrupts disabled because we have to change
+	 * the PID and I don't want to preempt when that happens.
+	 */
+	mfmsr	r5
+	mfspr	r6,SPRN_PID
+	wrteei	0
+	mtspr	SPRN_PID,r4
+	tlbsx.	r3, 0, r3
+	mtspr	SPRN_PID,r6
+	wrtee	r5
+	bne	1f
+	sync
+	/* There are only 64 TLB entries, so r3 < 64, which means bit 25 is
+	 * clear. Since 25 is the V bit in the TLB_TAG, loading this value
+	 * will invalidate the TLB entry. */
+	tlbwe	r3, r3, TLB_TAG
+	isync
+1:	blr
+
+#elif defined(CONFIG_8xx)
+
+/*
+ * Nothing to do for 8xx, everything is inline
+ */
+
+#elif defined(CONFIG_44x)
+
+/*
+ * 440 implementation uses tlbsx/we for tlbil_va and a full sweep
+ * of the TLB for everything else.
+ */
+_GLOBAL(_tlbil_va)
+	mfspr	r5,SPRN_MMUCR
+	rlwimi	r5,r4,0,24,31			/* Set TID */
+
+	/* We have to run the search with interrupts disabled, otherwise
+	 * an interrupt which causes a TLB miss can clobber the MMUCR
+	 * between the mtspr and the tlbsx.
+	 *
+	 * Critical and Machine Check interrupts take care of saving
+	 * and restoring MMUCR, so only normal interrupts have to be
+	 * taken care of.
+	 */
+	mfmsr	r4
+	wrteei	0
+	mtspr	SPRN_MMUCR,r5
+	tlbsx.	r3, 0, r3
+	wrtee	r4
+	bne	1f
+	sync
+	/* There are only 64 TLB entries, so r3 < 64,
+	 * which means bit 22, is clear.  Since 22 is
+	 * the V bit in the TLB_PAGEID, loading this
+	 * value will invalidate the TLB entry.
+	 */
+	tlbwe	r3, r3, PPC44x_TLB_PAGEID
+	isync
+1:	blr
+
+_GLOBAL(_tlbil_all)
+_GLOBAL(_tlbil_pid)
+	li	r3,0
+	sync
+
+	/* Load high watermark */
+	lis	r4,tlb_44x_hwater@ha
+	lwz	r5,tlb_44x_hwater@l(r4)
+
+1:	tlbwe	r3,r3,PPC44x_TLB_PAGEID
+	addi	r3,r3,1
+	cmpw	0,r3,r5
+	ble	1b
+
+	isync
+	blr
+
+#elif defined(CONFIG_FSL_BOOKE)
+/*
+ * FSL BookE implementations. Currently _pid and _all are the
+ * same. This will change when tlbilx is actually supported and
+ * performs invalidate-by-PID. This change will be driven by
+ * mmu_features conditional
+ */
+
+/*
+ * Flush MMU TLB on the local processor
+ */
+_GLOBAL(_tlbil_pid)
+_GLOBAL(_tlbil_all)
+#define MMUCSR0_TLBFI	(MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
+			 MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
+	li	r3,(MMUCSR0_TLBFI)@l
+	mtspr	SPRN_MMUCSR0, r3
+1:
+	mfspr	r3,SPRN_MMUCSR0
+	andi.	r3,r3,MMUCSR0_TLBFI@l
+	bne	1b
+	msync
+	isync
+	blr
+
+/*
+ * Flush MMU TLB for a particular address, but only on the local processor
+ * (no broadcast)
+ */
+_GLOBAL(_tlbil_va)
+	mfmsr	r10
+	wrteei	0
+	slwi	r4,r4,16
+	mtspr	SPRN_MAS6,r4		/* assume AS=0 for now */
+	tlbsx	0,r3
+	mfspr	r4,SPRN_MAS1		/* check valid */
+	andis.	r3,r4,MAS1_VALID@h
+	beq	1f
+	rlwinm	r4,r4,0,1,31
+	mtspr	SPRN_MAS1,r4
+	tlbwe
+	msync
+	isync
+1:	wrtee	r10
+	blr
+#elif
+#error Unsupported processor type !
+#endif
diff --git a/arch/powerpc/platforms/40x/ep405.c b/arch/powerpc/platforms/40x/ep405.c
index ae2e7f6..4058fd1 100644
--- a/arch/powerpc/platforms/40x/ep405.c
+++ b/arch/powerpc/platforms/40x/ep405.c
@@ -100,7 +100,7 @@
 	/* Find & init the BCSR CPLD */
 	ep405_init_bcsr();
 
-	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+	ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC);
 }
 
 static int __init ep405_probe(void)
diff --git a/arch/powerpc/platforms/40x/kilauea.c b/arch/powerpc/platforms/40x/kilauea.c
index 1dd24ff..fd7d934 100644
--- a/arch/powerpc/platforms/40x/kilauea.c
+++ b/arch/powerpc/platforms/40x/kilauea.c
@@ -44,7 +44,7 @@
 	if (!of_flat_dt_is_compatible(root, "amcc,kilauea"))
 		return 0;
 
-	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+	ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC);
 
 	return 1;
 }
diff --git a/arch/powerpc/platforms/40x/ppc40x_simple.c b/arch/powerpc/platforms/40x/ppc40x_simple.c
index 4498a86..f40ac9b 100644
--- a/arch/powerpc/platforms/40x/ppc40x_simple.c
+++ b/arch/powerpc/platforms/40x/ppc40x_simple.c
@@ -61,7 +61,7 @@
 
 	for (i = 0; i < ARRAY_SIZE(board); i++) {
 		if (of_flat_dt_is_compatible(root, board[i])) {
-			ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+			ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC);
 			return 1;
 		}
 	}
diff --git a/arch/powerpc/platforms/44x/ebony.c b/arch/powerpc/platforms/44x/ebony.c
index a0e8fe4..88b9117 100644
--- a/arch/powerpc/platforms/44x/ebony.c
+++ b/arch/powerpc/platforms/44x/ebony.c
@@ -54,7 +54,7 @@
 	if (!of_flat_dt_is_compatible(root, "ibm,ebony"))
 		return 0;
 
-	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+	ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC);
 
 	return 1;
 }
diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c
index 2967126..76fdc51 100644
--- a/arch/powerpc/platforms/44x/ppc44x_simple.c
+++ b/arch/powerpc/platforms/44x/ppc44x_simple.c
@@ -69,7 +69,7 @@
 
 	for (i = 0; i < ARRAY_SIZE(board); i++) {
 		if (of_flat_dt_is_compatible(root, board[i])) {
-			ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+			ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC);
 			return 1;
 		}
 	}
diff --git a/arch/powerpc/platforms/44x/sam440ep.c b/arch/powerpc/platforms/44x/sam440ep.c
index 47f10e6..a78e8eb 100644
--- a/arch/powerpc/platforms/44x/sam440ep.c
+++ b/arch/powerpc/platforms/44x/sam440ep.c
@@ -51,7 +51,7 @@
 	if (!of_flat_dt_is_compatible(root, "acube,sam440ep"))
 		return 0;
 
-	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+	ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC);
 
 	return 1;
 }
diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c
index fe92e65..b5c753d 100644
--- a/arch/powerpc/platforms/52xx/lite5200_pm.c
+++ b/arch/powerpc/platforms/52xx/lite5200_pm.c
@@ -3,7 +3,6 @@
 #include <asm/io.h>
 #include <asm/time.h>
 #include <asm/mpc52xx.h>
-#include "mpc52xx_pic.h"
 
 /* defined in lite5200_sleep.S and only used here */
 extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar);
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
index b49a185..c3f2c21 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -375,7 +375,7 @@
 
 	pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name);
 
-	ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS;
+	ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS);
 
 	if (of_address_to_resource(node, 0, &rsrc) != 0) {
 		printk(KERN_ERR "Can't get %s resources\n", node->full_name);
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
index 8479394..72865e8 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
@@ -2,20 +2,100 @@
  *
  * Programmable Interrupt Controller functions for the Freescale MPC52xx.
  *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
  * Copyright (C) 2006 bplan GmbH
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 Montavista Software, Inc
  *
  * Based on the code from the 2.4 kernel by
  * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
  *
- * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
- * Copyright (C) 2003 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.
  *
  */
 
+/*
+ * This is the device driver for the MPC5200 interrupt controller.
+ *
+ * hardware overview
+ * -----------------
+ * The MPC5200 interrupt controller groups the all interrupt sources into
+ * three groups called 'critical', 'main', and 'peripheral'.  The critical
+ * group has 3 irqs, External IRQ0, slice timer 0 irq, and wake from deep
+ * sleep.  Main group include the other 3 external IRQs, slice timer 1, RTC,
+ * gpios, and the general purpose timers.  Peripheral group contains the
+ * remaining irq sources from all of the on-chip peripherals (PSCs, Ethernet,
+ * USB, DMA, etc).
+ *
+ * virqs
+ * -----
+ * The Linux IRQ subsystem requires that each irq source be assigned a
+ * system wide unique IRQ number starting at 1 (0 means no irq).  Since
+ * systems can have multiple interrupt controllers, the virtual IRQ (virq)
+ * infrastructure lets each interrupt controller to define a local set
+ * of IRQ numbers and the virq infrastructure maps those numbers into
+ * a unique range of the global IRQ# space.
+ *
+ * To define a range of virq numbers for this controller, this driver first
+ * assigns a number to each of the irq groups (called the level 1 or L1
+ * value).  Within each group individual irq sources are also assigned a
+ * number, as defined by the MPC5200 user guide, and refers to it as the
+ * level 2 or L2 value.  The virq number is determined by shifting up the
+ * L1 value by MPC52xx_IRQ_L1_OFFSET and ORing it with the L2 value.
+ *
+ * For example, the TMR0 interrupt is irq 9 in the main group.  The
+ * virq for TMR0 is calculated by ((1 << MPC52xx_IRQ_L1_OFFSET) | 9).
+ *
+ * The observant reader will also notice that this driver defines a 4th
+ * interrupt group called 'bestcomm'.  The bestcomm group isn't physically
+ * part of the MPC5200 interrupt controller, but it is used here to assign
+ * a separate virq number for each bestcomm task (since any of the 16
+ * bestcomm tasks can cause the bestcomm interrupt to be raised).  When a
+ * bestcomm interrupt occurs (peripheral group, irq 0) this driver determines
+ * which task needs servicing and returns the irq number for that task.  This
+ * allows drivers which use bestcomm to define their own interrupt handlers.
+ *
+ * irq_chip structures
+ * -------------------
+ * For actually manipulating IRQs (masking, enabling, clearing, etc) this
+ * driver defines four separate 'irq_chip' structures, one for the main
+ * group, one for the peripherals group, one for the bestcomm group and one
+ * for external interrupts.  The irq_chip structures provide the hooks needed
+ * to manipulate each IRQ source, and since each group is has a separate set
+ * of registers for controlling the irq, it makes sense to divide up the
+ * hooks along those lines.
+ *
+ * You'll notice that there is not an irq_chip for the critical group and
+ * you'll also notice that there is an irq_chip defined for external
+ * interrupts even though there is no external interrupt group.  The reason
+ * for this is that the four external interrupts are all managed with the same
+ * register even though one of the external IRQs is in the critical group and
+ * the other three are in the main group.  For this reason it makes sense for
+ * the 4 external irqs to be managed using a separate set of hooks.  The
+ * reason there is no crit irq_chip is that of the 3 irqs in the critical
+ * group, only external interrupt is actually support at this time by this
+ * driver and since external interrupt is the only one used, it can just
+ * be directed to make use of the external irq irq_chip.
+ *
+ * device tree bindings
+ * --------------------
+ * The device tree bindings for this controller reflect the two level
+ * organization of irqs in the device.  #interrupt-cells = <3> where the
+ * first cell is the group number [0..3], the second cell is the irq
+ * number in the group, and the third cell is the sense type (level/edge).
+ * For reference, the following is a list of the interrupt property values
+ * associated with external interrupt sources on the MPC5200 (just because
+ * it is non-obvious to determine what the interrupts property should be
+ * when reading the mpc5200 manual and it is a frequently asked question).
+ *
+ * External interrupts:
+ * <0 0 n>	external irq0, n is sense	(n=0: level high,
+ * <1 1 n>	external irq1, n is sense	 n=1: edge rising,
+ * <1 2 n>	external irq2, n is sense	 n=2: edge falling,
+ * <1 3 n>	external irq3, n is sense	 n=3: level low)
+ */
 #undef DEBUG
 
 #include <linux/interrupt.h>
@@ -24,11 +104,19 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/mpc52xx.h>
-#include "mpc52xx_pic.h"
 
-/*
- *
-*/
+/* HW IRQ mapping */
+#define MPC52xx_IRQ_L1_CRIT	(0)
+#define MPC52xx_IRQ_L1_MAIN	(1)
+#define MPC52xx_IRQ_L1_PERP	(2)
+#define MPC52xx_IRQ_L1_SDMA	(3)
+
+#define MPC52xx_IRQ_L1_OFFSET	(6)
+#define MPC52xx_IRQ_L1_MASK	(0x00c0)
+#define MPC52xx_IRQ_L2_MASK	(0x003f)
+
+#define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0)
+
 
 /* MPC5200 device tree match tables */
 static struct of_device_id mpc52xx_pic_ids[] __initdata = {
@@ -53,10 +141,7 @@
 	IRQ_TYPE_LEVEL_LOW,
 };
 
-/*
- *
-*/
-
+/* Utility functions */
 static inline void io_be_setbit(u32 __iomem *addr, int bitno)
 {
 	out_be32(addr, in_be32(addr) | (1 << bitno));
@@ -69,15 +154,14 @@
 
 /*
  * IRQ[0-3] interrupt irq_chip
-*/
-
+ */
 static void mpc52xx_extirq_mask(unsigned int virq)
 {
 	int irq;
 	int l2irq;
 
 	irq = irq_map[virq].hwirq;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
 
@@ -90,7 +174,7 @@
 	int l2irq;
 
 	irq = irq_map[virq].hwirq;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
 
@@ -103,7 +187,7 @@
 	int l2irq;
 
 	irq = irq_map[virq].hwirq;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
 
@@ -117,7 +201,7 @@
 	int l2irq;
 
 	irq = irq_map[virq].hwirq;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type);
 
@@ -156,15 +240,14 @@
 
 /*
  * Main interrupt irq_chip
-*/
-
+ */
 static void mpc52xx_main_mask(unsigned int virq)
 {
 	int irq;
 	int l2irq;
 
 	irq = irq_map[virq].hwirq;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
 
@@ -177,7 +260,7 @@
 	int l2irq;
 
 	irq = irq_map[virq].hwirq;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
 
@@ -193,15 +276,14 @@
 
 /*
  * Peripherals interrupt irq_chip
-*/
-
+ */
 static void mpc52xx_periph_mask(unsigned int virq)
 {
 	int irq;
 	int l2irq;
 
 	irq = irq_map[virq].hwirq;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
 
@@ -214,7 +296,7 @@
 	int l2irq;
 
 	irq = irq_map[virq].hwirq;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
 
@@ -230,15 +312,14 @@
 
 /*
  * SDMA interrupt irq_chip
-*/
-
+ */
 static void mpc52xx_sdma_mask(unsigned int virq)
 {
 	int irq;
 	int l2irq;
 
 	irq = irq_map[virq].hwirq;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
 
@@ -251,7 +332,7 @@
 	int l2irq;
 
 	irq = irq_map[virq].hwirq;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
 
@@ -264,7 +345,7 @@
 	int l2irq;
 
 	irq = irq_map[virq].hwirq;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
 
@@ -278,13 +359,12 @@
 	.ack = mpc52xx_sdma_ack,
 };
 
-/*
- * irq_host
-*/
-
+/**
+ * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property
+ */
 static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
-				 u32 * intspec, unsigned int intsize,
-				 irq_hw_number_t * out_hwirq,
+				 u32 *intspec, unsigned int intsize,
+				 irq_hw_number_t *out_hwirq,
 				 unsigned int *out_flags)
 {
 	int intrvect_l1;
@@ -299,10 +379,9 @@
 	intrvect_l2 = (int)intspec[1];
 	intrvect_type = (int)intspec[2];
 
-	intrvect_linux =
-	    (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK;
-	intrvect_linux |=
-	    (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK;
+	intrvect_linux = (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) &
+			 MPC52xx_IRQ_L1_MASK;
+	intrvect_linux |= intrvect_l2 & MPC52xx_IRQ_L2_MASK;
 
 	pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
 		 intrvect_l2);
@@ -313,11 +392,11 @@
 	return 0;
 }
 
-/*
- * this function retrieves the correct IRQ type out
- * of the MPC regs
- * Only externals IRQs needs this
-*/
+/**
+ * mpc52xx_irqx_gettype - determine the IRQ sense type (level/edge)
+ *
+ * Only external IRQs need this.
+ */
 static int mpc52xx_irqx_gettype(int irq)
 {
 	int type;
@@ -329,6 +408,9 @@
 	return mpc52xx_map_senses[type];
 }
 
+/**
+ * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure
+ */
 static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
 			       irq_hw_number_t irq)
 {
@@ -339,7 +421,7 @@
 	int type;
 
 	l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
-	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+	l2irq = irq & MPC52xx_IRQ_L2_MASK;
 
 	/*
 	 * Most of ours IRQs will be level low
@@ -379,8 +461,7 @@
 		break;
 
 	default:
-		pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq);
-		printk(KERN_ERR "Unknow IRQ!\n");
+		pr_err("%s: invalid virq requested (0x%x)\n", __func__, virq);
 		return -EINVAL;
 	}
 
@@ -406,10 +487,15 @@
 	.map = mpc52xx_irqhost_map,
 };
 
-/*
- * init (public)
-*/
-
+/**
+ * mpc52xx_init_irq - Initialize and register with the virq subsystem
+ *
+ * Hook for setting up IRQs on an mpc5200 system.  A pointer to this function
+ * is to be put into the machine definition structure.
+ *
+ * This function searches the device tree for an MPC5200 interrupt controller,
+ * initializes it, and registers it with the virq subsystem.
+ */
 void __init mpc52xx_init_irq(void)
 {
 	u32 intr_ctrl;
@@ -454,7 +540,6 @@
 	 * As last step, add an irq host to translate the real
 	 * hw irq information provided by the ofw to linux virq
 	 */
-
 	mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR,
 	                                 MPC52xx_IRQ_HIGHTESTHWIRQ,
 	                                 &mpc52xx_irqhost_ops, -1);
@@ -462,12 +547,38 @@
 	if (!mpc52xx_irqhost)
 		panic(__FILE__ ": Cannot allocate the IRQ host\n");
 
-	printk(KERN_INFO "MPC52xx PIC is up and running!\n");
+	irq_set_default_host(mpc52xx_irqhost);
+
+	pr_info("MPC52xx PIC is up and running!\n");
 }
 
-/*
- * get_irq (public)
-*/
+/**
+ * mpc52xx_get_irq - Get pending interrupt number hook function
+ *
+ * Called by the interupt handler to determine what IRQ handler needs to be
+ * executed.
+ *
+ * Status of pending interrupts is determined by reading the encoded status
+ * register.  The encoded status register has three fields; one for each of the
+ * types of interrupts defined by the controller - 'critical', 'main' and
+ * 'peripheral'.  This function reads the status register and returns the IRQ
+ * number associated with the highest priority pending interrupt.  'Critical'
+ * interrupts have the highest priority, followed by 'main' interrupts, and
+ * then 'peripheral'.
+ *
+ * The mpc5200 interrupt controller can be configured to boost the priority
+ * of individual 'peripheral' interrupts.  If this is the case then a special
+ * value will appear in either the crit or main fields indicating a high
+ * or medium priority peripheral irq has occurred.
+ *
+ * This function checks each of the 3 irq request fields and returns the
+ * first pending interrupt that it finds.
+ *
+ * This function also identifies a 4th type of interrupt; 'bestcomm'.  Each
+ * bestcomm DMA task can raise the bestcomm peripheral interrupt.  When this
+ * occurs at task-specific IRQ# is decoded so that each task can have its
+ * own IRQ handler.
+ */
 unsigned int mpc52xx_get_irq(void)
 {
 	u32 status;
@@ -478,25 +589,21 @@
 		irq = (status >> 8) & 0x3;
 		if (irq == 2)	/* high priority peripheral */
 			goto peripheral;
-		irq |=	(MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) &
-			MPC52xx_IRQ_L1_MASK;
+		irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET);
 	} else if (status & 0x00200000) {	/* main */
 		irq = (status >> 16) & 0x1f;
 		if (irq == 4)	/* low priority peripheral */
 			goto peripheral;
-		irq |=	(MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) &
-			MPC52xx_IRQ_L1_MASK;
+		irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET);
 	} else if (status & 0x20000000) {	/* peripheral */
 	      peripheral:
 		irq = (status >> 24) & 0x1f;
 		if (irq == 0) {	/* bestcomm */
 			status = in_be32(&sdma->IntPend);
 			irq = ffs(status) - 1;
-			irq |=	(MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) &
-				MPC52xx_IRQ_L1_MASK;
+			irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET);
 		} else {
-			irq |=	(MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) &
-				MPC52xx_IRQ_L1_MASK;
+			irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET);
 		}
 	}
 
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.h b/arch/powerpc/platforms/52xx/mpc52xx_pic.h
deleted file mode 100644
index 1a26bcd..0000000
--- a/arch/powerpc/platforms/52xx/mpc52xx_pic.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Header file for Freescale MPC52xx Interrupt controller
- *
- * Copyright (C) 2004-2005 Sylvain Munaut <tnt@246tNt.com>
- * Copyright (C) 2003 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 __POWERPC_SYSDEV_MPC52xx_PIC_H__
-#define __POWERPC_SYSDEV_MPC52xx_PIC_H__
-
-#include <asm/types.h>
-
-
-/* HW IRQ mapping */
-#define MPC52xx_IRQ_L1_CRIT	(0)
-#define MPC52xx_IRQ_L1_MAIN	(1)
-#define MPC52xx_IRQ_L1_PERP	(2)
-#define MPC52xx_IRQ_L1_SDMA	(3)
-
-#define MPC52xx_IRQ_L1_OFFSET   (6)
-#define MPC52xx_IRQ_L1_MASK     (0x00c0)
-
-#define MPC52xx_IRQ_L2_OFFSET   (0)
-#define MPC52xx_IRQ_L2_MASK     (0x003f)
-
-#define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0)
-
-
-/* Interrupt controller Register set */
-struct mpc52xx_intr {
-	u32 per_mask;		/* INTR + 0x00 */
-	u32 per_pri1;		/* INTR + 0x04 */
-	u32 per_pri2;		/* INTR + 0x08 */
-	u32 per_pri3;		/* INTR + 0x0c */
-	u32 ctrl;		/* INTR + 0x10 */
-	u32 main_mask;		/* INTR + 0x14 */
-	u32 main_pri1;		/* INTR + 0x18 */
-	u32 main_pri2;		/* INTR + 0x1c */
-	u32 reserved1;		/* INTR + 0x20 */
-	u32 enc_status;		/* INTR + 0x24 */
-	u32 crit_status;	/* INTR + 0x28 */
-	u32 main_status;	/* INTR + 0x2c */
-	u32 per_status;		/* INTR + 0x30 */
-	u32 reserved2;		/* INTR + 0x34 */
-	u32 per_error;		/* INTR + 0x38 */
-};
-
-#endif /* __POWERPC_SYSDEV_MPC52xx_PIC_H__ */
-
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c
index c72d330..a55b0b6 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c
@@ -5,9 +5,6 @@
 #include <asm/cacheflush.h>
 #include <asm/mpc52xx.h>
 
-#include "mpc52xx_pic.h"
-
-
 /* these are defined in mpc52xx_sleep.S, and only used here */
 extern void mpc52xx_deep_sleep(void __iomem *sram, void __iomem *sdram_regs,
 		struct mpc52xx_cdm __iomem *, struct mpc52xx_intr __iomem*);
diff --git a/arch/powerpc/platforms/82xx/pq2.c b/arch/powerpc/platforms/82xx/pq2.c
index 1b75902..9761a59 100644
--- a/arch/powerpc/platforms/82xx/pq2.c
+++ b/arch/powerpc/platforms/82xx/pq2.c
@@ -53,7 +53,7 @@
 	if (of_address_to_resource(np, 0, &r) || r.end - r.start < 0x10b)
 		goto err;
 
-	ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS;
+	ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS);
 
 	hose = pcibios_alloc_controller(np);
 	if (!hose)
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index cb3054e..f0798c0 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -1,6 +1,8 @@
 #
 # Makefile for the PowerPC 85xx linux kernel.
 #
+obj-$(CONFIG_SMP) += smp.o
+
 obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
 obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
 obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
index 613bf8c..a8301c8 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
@@ -63,6 +63,7 @@
 	struct device_node *cascade_node = NULL;
 	int cascade_irq;
 #endif
+	unsigned long root = of_get_flat_dt_root();
 
 	np = of_find_node_by_type(NULL, "open-pic");
 	if (np == NULL) {
@@ -76,11 +77,19 @@
 		return;
 	}
 
-	mpic = mpic_alloc(np, r.start,
+	if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) {
+		mpic = mpic_alloc(np, r.start,
+			MPIC_PRIMARY |
+			MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS,
+			0, 256, " OpenPIC  ");
+	} else {
+		mpic = mpic_alloc(np, r.start,
 			  MPIC_PRIMARY | MPIC_WANTS_RESET |
 			  MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
 			  MPIC_SINGLE_DEST_CPU,
 			0, 256, " OpenPIC  ");
+	}
+
 	BUG_ON(mpic == NULL);
 	of_node_put(np);
 
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 2494c51..658a36f 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -231,7 +231,7 @@
 
 static int __init board_fixups(void)
 {
-	char phy_id[BUS_ID_SIZE];
+	char phy_id[20];
 	char *compstrs[2] = {"fsl,gianfar-mdio", "fsl,ucc-mdio"};
 	struct device_node *mdio;
 	struct resource res;
@@ -241,13 +241,15 @@
 		mdio = of_find_compatible_node(NULL, NULL, compstrs[i]);
 
 		of_address_to_resource(mdio, 0, &res);
-		snprintf(phy_id, BUS_ID_SIZE, "%x:%02x", res.start, 1);
+		snprintf(phy_id, sizeof(phy_id), "%llx:%02x",
+			(unsigned long long)res.start, 1);
 
 		phy_register_fixup_for_id(phy_id, mpc8568_fixup_125_clock);
 		phy_register_fixup_for_id(phy_id, mpc8568_mds_phy_fixups);
 
 		/* Register a workaround for errata */
-		snprintf(phy_id, BUS_ID_SIZE, "%x:%02x", res.start, 7);
+		snprintf(phy_id, sizeof(phy_id), "%llx:%02x",
+			(unsigned long long)res.start, 7);
 		phy_register_fixup_for_id(phy_id, mpc8568_mds_phy_fixups);
 
 		of_node_put(mdio);
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
new file mode 100644
index 0000000..d652c71
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -0,0 +1,104 @@
+/*
+ * Author: Andy Fleming <afleming@freescale.com>
+ * 	   Kumar Gala <galak@kernel.crashing.org>
+ *
+ * Copyright 2006-2008 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+
+#include <asm/machdep.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/mpic.h>
+#include <asm/cacheflush.h>
+
+#include <sysdev/fsl_soc.h>
+
+extern volatile unsigned long __secondary_hold_acknowledge;
+extern void __early_start(void);
+
+#define BOOT_ENTRY_ADDR_UPPER	0
+#define BOOT_ENTRY_ADDR_LOWER	1
+#define BOOT_ENTRY_R3_UPPER	2
+#define BOOT_ENTRY_R3_LOWER	3
+#define BOOT_ENTRY_RESV		4
+#define BOOT_ENTRY_PIR		5
+#define BOOT_ENTRY_R6_UPPER	6
+#define BOOT_ENTRY_R6_LOWER	7
+#define NUM_BOOT_ENTRY		8
+#define SIZE_BOOT_ENTRY		(NUM_BOOT_ENTRY * sizeof(u32))
+
+static void __init
+smp_85xx_kick_cpu(int nr)
+{
+	unsigned long flags;
+	const u64 *cpu_rel_addr;
+	__iomem u32 *bptr_vaddr;
+	struct device_node *np;
+	int n = 0;
+
+	WARN_ON (nr < 0 || nr >= NR_CPUS);
+
+	pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr);
+
+	local_irq_save(flags);
+
+	np = of_get_cpu_node(nr, NULL);
+	cpu_rel_addr = of_get_property(np, "cpu-release-addr", NULL);
+
+	if (cpu_rel_addr == NULL) {
+		printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr);
+		return;
+	}
+
+	/* Map the spin table */
+	bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
+
+	out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr);
+	out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
+
+	/* Wait a bit for the CPU to ack. */
+	while ((__secondary_hold_acknowledge != nr) && (++n < 1000))
+		mdelay(1);
+
+	iounmap(bptr_vaddr);
+
+	local_irq_restore(flags);
+
+	pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
+}
+
+static void __init
+smp_85xx_setup_cpu(int cpu_nr)
+{
+	mpic_setup_this_cpu();
+
+	/* Clear any pending timer interrupts */
+	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+
+	/* Enable decrementer interrupt */
+	mtspr(SPRN_TCR, TCR_DIE);
+}
+
+struct smp_ops_t smp_85xx_ops = {
+	.message_pass = smp_mpic_message_pass,
+	.probe = smp_mpic_probe,
+	.kick_cpu = smp_85xx_kick_cpu,
+	.setup_cpu = smp_85xx_setup_cpu,
+};
+
+void __init
+mpc85xx_smp_init(void)
+{
+	smp_ops = &smp_85xx_ops;
+}
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index 77dd797..8e56939 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -34,6 +34,8 @@
 config GEF_SBC610
 	bool "GE Fanuc SBC610"
 	select DEFAULT_UIMAGE
+	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
 	select HAS_RAPIDIO
 	help
 	  This option enables support for GE Fanuc's SBC610.
diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile
index 4a56ff6..31e540c 100644
--- a/arch/powerpc/platforms/86xx/Makefile
+++ b/arch/powerpc/platforms/86xx/Makefile
@@ -7,4 +7,5 @@
 obj-$(CONFIG_MPC8641_HPCN)	+= mpc86xx_hpcn.o
 obj-$(CONFIG_SBC8641D)		+= sbc8641d.o
 obj-$(CONFIG_MPC8610_HPCD)	+= mpc8610_hpcd.o
-obj-$(CONFIG_GEF_SBC610)	+= gef_sbc610.o gef_pic.o
+gef-gpio-$(CONFIG_GPIOLIB)	+= gef_gpio.o
+obj-$(CONFIG_GEF_SBC610)	+= gef_sbc610.o gef_pic.o $(gef-gpio-y)
diff --git a/arch/powerpc/platforms/86xx/gef_gpio.c b/arch/powerpc/platforms/86xx/gef_gpio.c
new file mode 100644
index 0000000..85b2800
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/gef_gpio.c
@@ -0,0 +1,143 @@
+/*
+ * Driver for GE Fanuc's FPGA based GPIO pins
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ *
+ * 2008 (c) GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/* TODO
+ *
+ * Configuration of output modes (totem-pole/open-drain)
+ * Interrupt configuration - interrupts are always generated the FPGA relies on
+ * 	the I/O interrupt controllers mask to stop them propergating
+ */
+
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+
+#define GEF_GPIO_DIRECT		0x00
+#define GEF_GPIO_IN		0x04
+#define GEF_GPIO_OUT		0x08
+#define GEF_GPIO_TRIG		0x0C
+#define GEF_GPIO_POLAR_A	0x10
+#define GEF_GPIO_POLAR_B	0x14
+#define GEF_GPIO_INT_STAT	0x18
+#define GEF_GPIO_OVERRUN	0x1C
+#define GEF_GPIO_MODE		0x20
+
+#define NUM_GPIO 19
+
+static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value)
+{
+	unsigned int data;
+
+	data = ioread32be(reg);
+	/* value: 0=low; 1=high */
+	if (value & 0x1)
+		data = data | (0x1 << offset);
+	else
+		data = data & ~(0x1 << offset);
+
+	iowrite32be(data, reg);
+}
+
+
+static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
+{
+	unsigned int data;
+	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+	data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
+	data = data | (0x1 << offset);
+	iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
+
+	return 0;
+}
+
+static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+	unsigned int data;
+	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+	/* Set direction before switching to input */
+	_gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
+
+	data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
+	data = data & ~(0x1 << offset);
+	iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
+
+	return 0;
+}
+
+static int gef_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	unsigned int data;
+	int state = 0;
+	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+	data = ioread32be(mmchip->regs + GEF_GPIO_IN);
+	state = (int)((data >> offset) & 0x1);
+
+	return state;
+}
+
+static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+	_gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
+}
+
+static int __init gef_gpio_init(void)
+{
+	struct device_node *np;
+
+	for_each_compatible_node(np, NULL, "gef,sbc610-gpio") {
+		int retval;
+		struct of_mm_gpio_chip *gef_gpio_chip;
+
+		pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
+
+		/* Allocate chip structure */
+		gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
+		if (!gef_gpio_chip) {
+			pr_err("%s: Unable to allocate structure\n",
+				np->full_name);
+			continue;
+		}
+
+		/* Setup pointers to chip functions */
+		gef_gpio_chip->of_gc.gpio_cells = 2;
+		gef_gpio_chip->of_gc.gc.ngpio = NUM_GPIO;
+		gef_gpio_chip->of_gc.gc.direction_input = gef_gpio_dir_in;
+		gef_gpio_chip->of_gc.gc.direction_output = gef_gpio_dir_out;
+		gef_gpio_chip->of_gc.gc.get = gef_gpio_get;
+		gef_gpio_chip->of_gc.gc.set = gef_gpio_set;
+
+		/* This function adds a memory mapped GPIO chip */
+		retval = of_mm_gpiochip_add(np, gef_gpio_chip);
+		if (retval) {
+			kfree(gef_gpio_chip);
+			pr_err("%s: Unable to add GPIO\n", np->full_name);
+		}
+	}
+
+	return 0;
+};
+arch_initcall(gef_gpio_init);
+
+MODULE_DESCRIPTION("GE Fanuc I/O FPGA GPIO driver");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com");
+MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 548efa5..3d0c776 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -195,16 +195,24 @@
 
 config PPC_STD_MMU
 	bool
-	depends on 6xx || POWER3 || POWER4 || PPC64
+	depends on 6xx || PPC64
 	default y
 
 config PPC_STD_MMU_32
 	def_bool y
 	depends on PPC_STD_MMU && PPC32
 
+config PPC_STD_MMU_64
+	def_bool y
+	depends on PPC_STD_MMU && PPC64
+
+config PPC_MMU_NOHASH
+	def_bool y
+	depends on !PPC_STD_MMU
+
 config PPC_MM_SLICES
 	bool
-	default y if HUGETLB_PAGE || PPC_64K_PAGES
+	default y if HUGETLB_PAGE || (PPC_STD_MMU_64 && PPC_64K_PAGES)
 	default n
 
 config VIRT_CPU_ACCOUNTING
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index c14d7d8..5cc3279 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -2,13 +2,18 @@
 	bool
 	default n
 
-config PPC_CELL_NATIVE
+config PPC_CELL_COMMON
 	bool
 	select PPC_CELL
 	select PPC_DCR_MMIO
-	select PPC_OF_PLATFORM_PCI
 	select PPC_INDIRECT_IO
 	select PPC_NATIVE
+	select PPC_RTAS
+
+config PPC_CELL_NATIVE
+	bool
+	select PPC_CELL_COMMON
+	select PPC_OF_PLATFORM_PCI
 	select MPIC
 	select IBM_NEW_EMAC_EMAC4
 	select IBM_NEW_EMAC_RGMII
@@ -20,7 +25,6 @@
 	bool "IBM Cell Blade"
 	depends on PPC_MULTIPLATFORM && PPC64
 	select PPC_CELL_NATIVE
-	select PPC_RTAS
 	select MMIO_NVRAM
 	select PPC_UDBG_16550
 	select UDBG_RTAS_CONSOLE
@@ -28,16 +32,17 @@
 config PPC_CELLEB
 	bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
 	depends on PPC_MULTIPLATFORM && PPC64
-	select PPC_CELL
 	select PPC_CELL_NATIVE
-	select PPC_RTAS
-	select PPC_INDIRECT_IO
-	select PPC_OF_PLATFORM_PCI
 	select HAS_TXX9_SERIAL
 	select PPC_UDBG_BEAT
 	select USB_OHCI_BIG_ENDIAN_MMIO
 	select USB_EHCI_BIG_ENDIAN_MMIO
 
+config PPC_CELL_QPACE
+	bool "IBM Cell - QPACE"
+	depends on PPC_MULTIPLATFORM && PPC64
+	select PPC_CELL_COMMON
+
 menu "Cell Broadband Engine options"
 	depends on PPC_CELL
 
@@ -102,7 +107,7 @@
 config CBE_THERM
 	tristate "CBE thermal support"
 	default m
-	depends on CBE_RAS
+	depends on CBE_RAS && SPU_BASE
 
 config CBE_CPUFREQ
 	tristate "CBE frequency scaling"
@@ -136,5 +141,5 @@
 
 config OPROFILE_CELL
 	def_bool y
-	depends on PPC_CELL_NATIVE && (OPROFILE = m || OPROFILE = y)
+	depends on PPC_CELL_NATIVE && (OPROFILE = m || OPROFILE = y) && SPU_BASE
 
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 7fd8308..43eccb2 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -1,7 +1,7 @@
-obj-$(CONFIG_PPC_CELL_NATIVE)		+= interrupt.o iommu.o setup.o \
-					   cbe_regs.o spider-pic.o \
-					   pervasive.o pmu.o io-workarounds.o \
-					   spider-pci.o
+obj-$(CONFIG_PPC_CELL_COMMON)		+= cbe_regs.o interrupt.o pervasive.o
+
+obj-$(CONFIG_PPC_CELL_NATIVE)		+= iommu.o setup.o spider-pic.o \
+					   pmu.o io-workarounds.o spider-pci.o
 obj-$(CONFIG_CBE_RAS)			+= ras.o
 
 obj-$(CONFIG_CBE_THERM)			+= cbe_thermal.o
@@ -14,13 +14,12 @@
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_CELL_NATIVE)		+= smp.o
+obj-$(CONFIG_PPC_CELL_QPACE)		+= smp.o
 endif
 
 # needed only when building loadable spufs.ko
-spu-priv1-$(CONFIG_PPC_CELL_NATIVE)	+= spu_priv1_mmio.o
-
-spu-manage-$(CONFIG_PPC_CELLEB)		+= spu_manage.o
-spu-manage-$(CONFIG_PPC_CELL_NATIVE)	+= spu_manage.o
+spu-priv1-$(CONFIG_PPC_CELL_COMMON)	+= spu_priv1_mmio.o
+spu-manage-$(CONFIG_PPC_CELL_COMMON)	+= spu_manage.o
 
 obj-$(CONFIG_SPU_BASE)			+= spu_callbacks.o spu_base.o \
 					   spu_notify.o \
@@ -31,6 +30,8 @@
 
 obj-$(CONFIG_PCI_MSI)			+= axon_msi.o
 
+# qpace setup
+obj-$(CONFIG_PPC_CELL_QPACE)		+= qpace_setup.o
 
 # celleb stuff
 ifeq ($(CONFIG_PPC_CELLEB),y)
diff --git a/arch/powerpc/platforms/cell/celleb_setup.c b/arch/powerpc/platforms/cell/celleb_setup.c
index b11cb30..07c234f 100644
--- a/arch/powerpc/platforms/cell/celleb_setup.c
+++ b/arch/powerpc/platforms/cell/celleb_setup.c
@@ -45,7 +45,6 @@
 #include <asm/mmu.h>
 #include <asm/processor.h>
 #include <asm/io.h>
-#include <asm/kexec.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/cputable.h>
@@ -226,9 +225,6 @@
 	.pci_setup_phb		= celleb_setup_phb,
 #ifdef CONFIG_KEXEC
 	.kexec_cpu_down		= beat_kexec_cpu_down,
-	.machine_kexec		= default_machine_kexec,
-	.machine_kexec_prepare	= default_machine_kexec_prepare,
-	.machine_crash_shutdown	= default_machine_crash_shutdown,
 #endif
 };
 
@@ -248,9 +244,4 @@
 	.pci_probe_mode 	= celleb_pci_probe_mode,
 	.pci_setup_phb		= celleb_setup_phb,
 	.init_IRQ		= celleb_init_IRQ_native,
-#ifdef CONFIG_KEXEC
-	.machine_kexec		= default_machine_kexec,
-	.machine_kexec_prepare	= default_machine_kexec_prepare,
-	.machine_crash_shutdown	= default_machine_crash_shutdown,
-#endif
 };
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 3168272..86db4dd 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -1053,10 +1053,7 @@
 	}
 
 	/* We must have dma-ranges properties for fixed mapping to work */
-	for (np = NULL; (np = of_find_all_nodes(np));) {
-		if (of_find_property(np, "dma-ranges", NULL))
-			break;
-	}
+	np = of_find_node_with_property(NULL, "dma-ranges");
 	of_node_put(np);
 
 	if (!np) {
diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c
new file mode 100644
index 0000000..be84e6a
--- /dev/null
+++ b/arch/powerpc/platforms/cell/qpace_setup.c
@@ -0,0 +1,152 @@
+/*
+ *  linux/arch/powerpc/platforms/cell/qpace_setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Modified by PPC64 Team, IBM Corp
+ *  Modified by Cell Team, IBM Deutschland Entwicklung GmbH
+ *  Modified by Benjamin Krill <ben@codiert.org>, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/console.h>
+#include <linux/of_platform.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/kexec.h>
+#include <asm/pgtable.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/cputable.h>
+#include <asm/irq.h>
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
+#include <asm/udbg.h>
+#include <asm/cell-regs.h>
+
+#include "interrupt.h"
+#include "pervasive.h"
+#include "ras.h"
+#include "io-workarounds.h"
+
+static void qpace_show_cpuinfo(struct seq_file *m)
+{
+	struct device_node *root;
+	const char *model = "";
+
+	root = of_find_node_by_path("/");
+	if (root)
+		model = of_get_property(root, "model", NULL);
+	seq_printf(m, "machine\t\t: CHRP %s\n", model);
+	of_node_put(root);
+}
+
+static void qpace_progress(char *s, unsigned short hex)
+{
+	printk("*** %04x : %s\n", hex, s ? s : "");
+}
+
+static int __init qpace_publish_devices(void)
+{
+	int node;
+
+	/* Publish OF platform devices for southbridge IOs */
+	of_platform_bus_probe(NULL, NULL, NULL);
+
+	/* There is no device for the MIC memory controller, thus we create
+	 * a platform device for it to attach the EDAC driver to.
+	 */
+	for_each_online_node(node) {
+		if (cbe_get_cpu_mic_tm_regs(cbe_node_to_cpu(node)) == NULL)
+			continue;
+		platform_device_register_simple("cbe-mic", node, NULL, 0);
+	}
+
+	return 0;
+}
+machine_subsys_initcall(qpace, qpace_publish_devices);
+
+extern int qpace_notify(struct device *dev)
+{
+	/* set dma_ops for of_platform bus */
+	if (dev->bus && dev->bus->name
+			&& !strcmp(dev->bus->name, "of_platform"))
+		set_dma_ops(dev, &dma_direct_ops);
+
+	return 0;
+}
+
+static void __init qpace_setup_arch(void)
+{
+#ifdef CONFIG_SPU_BASE
+	spu_priv1_ops = &spu_priv1_mmio_ops;
+	spu_management_ops = &spu_management_of_ops;
+#endif
+
+	cbe_regs_init();
+
+#ifdef CONFIG_CBE_RAS
+	cbe_ras_init();
+#endif
+
+#ifdef CONFIG_SMP
+	smp_init_cell();
+#endif
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000;
+
+	cbe_pervasive_init();
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+
+	/* set notifier function */
+	platform_notify = &qpace_notify;
+}
+
+static int __init qpace_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (!of_flat_dt_is_compatible(root, "IBM,QPACE"))
+		return 0;
+
+	hpte_init_native();
+
+	return 1;
+}
+
+define_machine(qpace) {
+	.name			= "QPACE",
+	.probe			= qpace_probe,
+	.setup_arch		= qpace_setup_arch,
+	.show_cpuinfo		= qpace_show_cpuinfo,
+	.restart		= rtas_restart,
+	.power_off		= rtas_power_off,
+	.halt			= rtas_halt,
+	.get_boot_time		= rtas_get_boot_time,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= qpace_progress,
+	.init_IRQ		= iic_init_IRQ,
+#ifdef CONFIG_KEXEC
+	.machine_kexec		= default_machine_kexec,
+	.machine_kexec_prepare	= default_machine_kexec_prepare,
+	.machine_crash_shutdown	= default_machine_crash_shutdown,
+#endif
+};
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index ab721b5..5930536 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -35,7 +35,6 @@
 #include <asm/mmu.h>
 #include <asm/processor.h>
 #include <asm/io.h>
-#include <asm/kexec.h>
 #include <asm/pgtable.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
@@ -289,9 +288,4 @@
 	.progress		= cell_progress,
 	.init_IRQ       	= cell_init_irq,
 	.pci_setup_phb		= cell_setup_phb,
-#ifdef CONFIG_KEXEC
-	.machine_kexec		= default_machine_kexec,
-	.machine_kexec_prepare	= default_machine_kexec_prepare,
-	.machine_crash_shutdown	= default_machine_crash_shutdown,
-#endif
 };
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 1b26071..7106b63 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -273,12 +273,10 @@
 		return VM_FAULT_NOPAGE;
 
 	if (ctx->state == SPU_STATE_SAVED) {
-		vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-							& ~_PAGE_NO_CACHE);
+		vma->vm_page_prot = pgprot_cached(vma->vm_page_prot);
 		pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset);
 	} else {
-		vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-					     | _PAGE_NO_CACHE);
+		vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot);
 		pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT;
 	}
 	vm_insert_pfn(vma, address, pfn);
@@ -338,8 +336,7 @@
 		return -EINVAL;
 
 	vma->vm_flags |= VM_IO | VM_PFNMAP;
-	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-				     | _PAGE_NO_CACHE);
+	vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot);
 
 	vma->vm_ops = &spufs_mem_mmap_vmops;
 	return 0;
@@ -452,8 +449,7 @@
 		return -EINVAL;
 
 	vma->vm_flags |= VM_IO | VM_PFNMAP;
-	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
 	vma->vm_ops = &spufs_cntl_mmap_vmops;
 	return 0;
@@ -1155,8 +1151,7 @@
 		return -EINVAL;
 
 	vma->vm_flags |= VM_IO | VM_PFNMAP;
-	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
 	vma->vm_ops = &spufs_signal1_mmap_vmops;
 	return 0;
@@ -1292,8 +1287,7 @@
 		return -EINVAL;
 
 	vma->vm_flags |= VM_IO | VM_PFNMAP;
-	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
 	vma->vm_ops = &spufs_signal2_mmap_vmops;
 	return 0;
@@ -1414,8 +1408,7 @@
 		return -EINVAL;
 
 	vma->vm_flags |= VM_IO | VM_PFNMAP;
-	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
 	vma->vm_ops = &spufs_mss_mmap_vmops;
 	return 0;
@@ -1476,8 +1469,7 @@
 		return -EINVAL;
 
 	vma->vm_flags |= VM_IO | VM_PFNMAP;
-	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
 	vma->vm_ops = &spufs_psmap_mmap_vmops;
 	return 0;
@@ -1536,8 +1528,7 @@
 		return -EINVAL;
 
 	vma->vm_flags |= VM_IO | VM_PFNMAP;
-	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
-				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
 	vma->vm_ops = &spufs_mfc_mmap_vmops;
 	return 0;
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index cb85d23..6296bfd 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -95,8 +95,8 @@
 		goto out;
 
 	inode->i_mode = mode;
-	inode->i_uid = current->fsuid;
-	inode->i_gid = current->fsgid;
+	inode->i_uid = current_fsuid();
+	inode->i_gid = current_fsgid();
 	inode->i_blocks = 0;
 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 out:
@@ -323,7 +323,7 @@
 		goto out;
 	}
 
-	filp = dentry_open(dentry, mnt, O_RDONLY);
+	filp = dentry_open(dentry, mnt, O_RDONLY, current_cred());
 	if (IS_ERR(filp)) {
 		put_unused_fd(ret);
 		ret = PTR_ERR(filp);
@@ -562,7 +562,7 @@
 		goto out;
 	}
 
-	filp = dentry_open(dentry, mnt, O_RDONLY);
+	filp = dentry_open(dentry, mnt, O_RDONLY, current_cred());
 	if (IS_ERR(filp)) {
 		put_unused_fd(ret);
 		ret = PTR_ERR(filp);
diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c
index d3cde6b..f6b0c51 100644
--- a/arch/powerpc/platforms/chrp/pci.c
+++ b/arch/powerpc/platforms/chrp/pci.c
@@ -141,6 +141,7 @@
 		of_node_put(np);
 		return 0;
 	}
+	of_node_put(np);
 	Hydra = ioremap(r.start, r.end-r.start);
 	printk("Hydra Mac I/O at %llx\n", (unsigned long long)r.start);
 	printk("Hydra Feature_Control was %x",
@@ -198,7 +199,7 @@
 		printk ("RTAS supporting Pegasos OF not found, please upgrade"
 			" your firmware\n");
 	}
-	ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS;
+	ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS);
 	/* keep the reference to the root node */
 }
 
diff --git a/arch/powerpc/platforms/embedded6xx/c2k.c b/arch/powerpc/platforms/embedded6xx/c2k.c
index 32ba0fa..8cab573 100644
--- a/arch/powerpc/platforms/embedded6xx/c2k.c
+++ b/arch/powerpc/platforms/embedded6xx/c2k.c
@@ -20,7 +20,6 @@
 #include <linux/seq_file.h>
 #include <linux/time.h>
 #include <linux/of.h>
-#include <linux/kexec.h>
 
 #include <asm/machdep.h>
 #include <asm/prom.h>
@@ -147,9 +146,4 @@
 	.get_irq		= mv64x60_get_irq,
 	.restart		= c2k_restart,
 	.calibrate_decr		= generic_calibrate_decr,
-#ifdef CONFIG_KEXEC
-	.machine_kexec		= default_machine_kexec,
-	.machine_kexec_prepare	= default_machine_kexec_prepare,
-	.machine_crash_shutdown	= default_machine_crash_shutdown,
-#endif
 };
diff --git a/arch/powerpc/platforms/embedded6xx/prpmc2800.c b/arch/powerpc/platforms/embedded6xx/prpmc2800.c
index 4c485e9..670035f 100644
--- a/arch/powerpc/platforms/embedded6xx/prpmc2800.c
+++ b/arch/powerpc/platforms/embedded6xx/prpmc2800.c
@@ -19,7 +19,6 @@
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/time.h>
-#include <asm/kexec.h>
 
 #include <mm/mmu_decl.h>
 
@@ -155,9 +154,4 @@
 	.get_irq		= mv64x60_get_irq,
 	.restart		= prpmc2800_restart,
 	.calibrate_decr		= generic_calibrate_decr,
-#ifdef CONFIG_KEXEC
-	.machine_kexec		= default_machine_kexec,
-	.machine_kexec_prepare	= default_machine_kexec_prepare,
-	.machine_crash_shutdown	= default_machine_crash_shutdown,
-#endif
 };
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
index 45ffd8e..ed3753d 100644
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -9,6 +9,7 @@
 
 config VIODASD
 	tristate "iSeries Virtual I/O disk support"
+	depends on BLOCK
 	help
 	  If you are running on an iSeries system and you want to use
 	  virtual disks created and managed by OS/400, say Y.
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index d4c61c3..bfd60e4 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -50,7 +50,6 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#include <asm/kexec.h>
 #include <asm/pci-bridge.h>
 #include <asm/iommu.h>
 #include <asm/machdep.h>
@@ -335,9 +334,4 @@
       	.calibrate_decr		= generic_calibrate_decr,
 	.progress		= maple_progress,
 	.power_save		= power4_idle,
-#ifdef CONFIG_KEXEC
-	.machine_kexec		= default_machine_kexec,
-	.machine_kexec_prepare	= default_machine_kexec_prepare,
-	.machine_crash_shutdown	= default_machine_crash_shutdown,
-#endif
 };
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index 792d3ce..65c585b 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -310,7 +310,7 @@
  		_set_L3CR(save_l3cr);
 
 	/* Restore userland MMU context */
-	set_context(current->active_mm->context.id, current->active_mm->pgd);
+	switch_mmu_context(NULL, current->active_mm);
 
 #ifdef DEBUG_FREQ
 	printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index bcf50d7..54b7b76 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -729,7 +729,7 @@
 static int __init setup_uninorth(struct pci_controller *hose,
 				 struct resource *addr)
 {
-	ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS;
+	ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS);
 	has_uninorth = 1;
 	hose->ops = &macrisc_pci_ops;
 	hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000);
@@ -996,7 +996,7 @@
 	struct device_node *np, *root;
 	struct device_node *ht = NULL;
 
-	ppc_pci_flags = PPC_PCI_CAN_SKIP_ISA_ALIGN;
+	ppc_pci_set_flags(PPC_PCI_CAN_SKIP_ISA_ALIGN);
 
 	root = of_find_node_by_path("/");
 	if (root == NULL) {
@@ -1055,7 +1055,7 @@
 	 * some offset between bus number and domains for now when we
 	 * assign all busses should help for now
 	 */
-	if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_BUS)
+	if (ppc_pci_has_flag(PPC_PCI_REASSIGN_ALL_BUS))
 		pcibios_assign_bus_offset = 0x10;
 #endif
 }
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 82c14d2..9b78f53 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -60,7 +60,6 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#include <asm/kexec.h>
 #include <asm/pci-bridge.h>
 #include <asm/ohare.h>
 #include <asm/mediabay.h>
@@ -310,9 +309,7 @@
 	}
 
 	/* See if newworld or oldworld */
-	for (ic = NULL; (ic = of_find_all_nodes(ic)) != NULL; )
-		if (of_get_property(ic, "interrupt-controller", NULL))
-			break;
+	ic = of_find_node_with_property(NULL, "interrupt-controller");
 	if (ic) {
 		pmac_newworld = 1;
 		of_node_put(ic);
@@ -740,11 +737,6 @@
 	.pci_probe_mode		= pmac_pci_probe_mode,
 	.power_save		= power4_idle,
 	.enable_pmcs		= power4_enable_pmcs,
-#ifdef CONFIG_KEXEC
-	.machine_kexec		= default_machine_kexec,
-	.machine_kexec_prepare	= default_machine_kexec_prepare,
-	.machine_crash_shutdown	= default_machine_crash_shutdown,
-#endif
 #endif /* CONFIG_PPC64 */
 #ifdef CONFIG_PPC32
 	.pcibios_enable_device_hook = pmac_pci_enable_device_hook,
diff --git a/arch/powerpc/platforms/powermac/sleep.S b/arch/powerpc/platforms/powermac/sleep.S
index adee28d..1c2802f 100644
--- a/arch/powerpc/platforms/powermac/sleep.S
+++ b/arch/powerpc/platforms/powermac/sleep.S
@@ -17,6 +17,7 @@
 #include <asm/cache.h>
 #include <asm/thread_info.h>
 #include <asm/asm-offsets.h>
+#include <asm/mmu.h>
 
 #define MAGIC	0x4c617273	/* 'Lars' */
 
@@ -323,7 +324,7 @@
 	lwz	r4,SL_IBAT3+4(r1)
 	mtibatl	3,r4
 
-BEGIN_FTR_SECTION
+BEGIN_MMU_FTR_SECTION
 	li	r4,0
 	mtspr	SPRN_DBAT4U,r4
 	mtspr	SPRN_DBAT4L,r4
@@ -341,7 +342,7 @@
 	mtspr	SPRN_IBAT6L,r4
 	mtspr	SPRN_IBAT7U,r4
 	mtspr	SPRN_IBAT7L,r4
-END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
 
 	/* Flush all TLBs */
 	lis	r4,0x1000
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index 40f72c2..6b0711c 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -739,7 +739,7 @@
 
 		/* XXX should get this from reg properties */
 		for (i = 1; i < ncpus; ++i)
-			smp_hw_index[i] = i;
+			set_hard_smp_processor_id(i, i);
 	}
 #endif
 
diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c
index ffdd8e9..dbc124e 100644
--- a/arch/powerpc/platforms/ps3/device-init.c
+++ b/arch/powerpc/platforms/ps3/device-init.c
@@ -314,11 +314,17 @@
 
 	result = ps3_system_bus_device_register(&p->dev);
 
-	if (result)
+	if (result) {
 		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
 			__func__, __LINE__);
-
+		goto fail_device_register;
+	}
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
+	return 0;
+
+fail_device_register:
+	kfree(p);
+	pr_debug(" <- %s:%d fail\n", __func__, __LINE__);
 	return result;
 }
 
@@ -463,11 +469,17 @@
 
 	result = ps3_system_bus_device_register(&p->dev);
 
-	if (result)
+	if (result) {
 		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
 			__func__, __LINE__);
-
+		goto fail_device_register;
+	}
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
+	return 0;
+
+fail_device_register:
+	kfree(p);
+	pr_debug(" <- %s:%d failed\n", __func__, __LINE__);
 	return result;
 }
 
@@ -485,17 +497,24 @@
 	if (!p)
 		return -ENOMEM;
 
-	p->dev.match_id = PS3_MATCH_ID_GRAPHICS;
-	p->dev.match_sub_id = PS3_MATCH_SUB_ID_FB;
+	p->dev.match_id = PS3_MATCH_ID_GPU;
+	p->dev.match_sub_id = PS3_MATCH_SUB_ID_GPU_FB;
 	p->dev.dev_type = PS3_DEVICE_TYPE_IOC0;
 
 	result = ps3_system_bus_device_register(&p->dev);
 
-	if (result)
+	if (result) {
 		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
 			__func__, __LINE__);
+		goto fail_device_register;
+	}
 
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
+	return 0;
+
+fail_device_register:
+	kfree(p);
+	pr_debug(" <- %s:%d failed\n", __func__, __LINE__);
 	return result;
 }
 
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index 3a58ffa..a4d49dd 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -649,7 +649,7 @@
 {
 	int result;
 
-	pr_info(" -> %s:%d:\n", __func__, __LINE__);
+	DBG(" -> %s:%d:\n", __func__, __LINE__);
 
 	BUG_ON(!r);
 
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index 77bc330..35f3e85 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -23,7 +23,6 @@
 #include <linux/fs.h>
 #include <linux/root_dev.h>
 #include <linux/console.h>
-#include <linux/kexec.h>
 #include <linux/bootmem.h>
 
 #include <asm/machdep.h>
@@ -42,6 +41,10 @@
 #define DBG pr_debug
 #endif
 
+/* mutex synchronizing GPU accesses and video mode changes */
+DEFINE_MUTEX(ps3_gpu_mutex);
+EXPORT_SYMBOL_GPL(ps3_gpu_mutex);
+
 #if !defined(CONFIG_SMP)
 static void smp_send_stop(void) {}
 #endif
@@ -277,8 +280,5 @@
 	.halt				= ps3_halt,
 #if defined(CONFIG_KEXEC)
 	.kexec_cpu_down			= ps3_kexec_cpu_down,
-	.machine_kexec			= default_machine_kexec,
-	.machine_kexec_prepare		= default_machine_kexec_prepare,
-	.machine_crash_shutdown		= default_machine_crash_shutdown,
 #endif
 };
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
index 661e9f7..ee0d229 100644
--- a/arch/powerpc/platforms/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -31,7 +31,7 @@
 #include "platform.h"
 
 static struct device ps3_system_bus = {
-	.bus_id = "ps3_system",
+	.init_name = "ps3_system",
 };
 
 /* FIXME: need device usage counters! */
@@ -175,7 +175,7 @@
 		return ps3_open_hv_device_sb(dev);
 
 	case PS3_MATCH_ID_SOUND:
-	case PS3_MATCH_ID_GRAPHICS:
+	case PS3_MATCH_ID_GPU:
 		return ps3_open_hv_device_gpu(dev);
 
 	case PS3_MATCH_ID_AV_SETTINGS:
@@ -213,7 +213,7 @@
 		return ps3_close_hv_device_sb(dev);
 
 	case PS3_MATCH_ID_SOUND:
-	case PS3_MATCH_ID_GRAPHICS:
+	case PS3_MATCH_ID_GPU:
 		return ps3_close_hv_device_gpu(dev);
 
 	case PS3_MATCH_ID_AV_SETTINGS:
@@ -356,12 +356,12 @@
 	if (result)
 		pr_info("%s:%d: dev=%u.%u(%s), drv=%u.%u(%s): match\n",
 			__func__, __LINE__,
-			dev->match_id, dev->match_sub_id, dev->core.bus_id,
+			dev->match_id, dev->match_sub_id, dev_name(&dev->core),
 			drv->match_id, drv->match_sub_id, drv->core.name);
 	else
 		pr_debug("%s:%d: dev=%u.%u(%s), drv=%u.%u(%s): miss\n",
 			__func__, __LINE__,
-			dev->match_id, dev->match_sub_id, dev->core.bus_id,
+			dev->match_id, dev->match_sub_id, dev_name(&dev->core),
 			drv->match_id, drv->match_sub_id, drv->core.name);
 
 	return result;
@@ -383,9 +383,9 @@
 		result = drv->probe(dev);
 	else
 		pr_debug("%s:%d: %s no probe method\n", __func__, __LINE__,
-			dev->core.bus_id);
+			dev_name(&dev->core));
 
-	pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id);
+	pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev_name(&dev->core));
 	return result;
 }
 
@@ -407,7 +407,7 @@
 		dev_dbg(&dev->core, "%s:%d %s: no remove method\n",
 			__func__, __LINE__, drv->core.name);
 
-	pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id);
+	pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev_name(&dev->core));
 	return result;
 }
 
@@ -432,7 +432,7 @@
 	BUG_ON(!drv);
 
 	dev_dbg(&dev->core, "%s:%d: %s -> %s\n", __func__, __LINE__,
-		dev->core.bus_id, drv->core.name);
+		dev_name(&dev->core), drv->core.name);
 
 	if (drv->shutdown)
 		drv->shutdown(dev);
@@ -453,7 +453,8 @@
 {
 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
 
-	if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id))
+	if (add_uevent_var(env, "MODALIAS=ps3:%d:%d", dev->match_id,
+			   dev->match_sub_id))
 		return -ENOMEM;
 	return 0;
 }
@@ -462,7 +463,8 @@
 	char *buf)
 {
 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
-	int len = snprintf(buf, PAGE_SIZE, "ps3:%d\n", dev->match_id);
+	int len = snprintf(buf, PAGE_SIZE, "ps3:%d:%d\n", dev->match_id,
+			   dev->match_sub_id);
 
 	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
 }
@@ -742,22 +744,18 @@
 	switch (dev->dev_type) {
 	case PS3_DEVICE_TYPE_IOC0:
 		dev->core.archdata.dma_ops = &ps3_ioc0_dma_ops;
-		snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
-			"ioc0_%02x", ++dev_ioc0_count);
+		dev_set_name(&dev->core, "ioc0_%02x", ++dev_ioc0_count);
 		break;
 	case PS3_DEVICE_TYPE_SB:
 		dev->core.archdata.dma_ops = &ps3_sb_dma_ops;
-		snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
-			"sb_%02x", ++dev_sb_count);
+		dev_set_name(&dev->core, "sb_%02x", ++dev_sb_count);
 
 		break;
 	case PS3_DEVICE_TYPE_VUART:
-		snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
-			"vuart_%02x", ++dev_vuart_count);
+		dev_set_name(&dev->core, "vuart_%02x", ++dev_vuart_count);
 		break;
 	case PS3_DEVICE_TYPE_LPM:
-		snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
-			"lpm_%02x", ++dev_lpm_count);
+		dev_set_name(&dev->core, "lpm_%02x", ++dev_lpm_count);
 		break;
 	default:
 		BUG();
@@ -766,7 +764,7 @@
 	dev->core.archdata.of_node = NULL;
 	set_dev_node(&dev->core, 0);
 
-	pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
+	pr_debug("%s:%d add %s\n", __func__, __LINE__, dev_name(&dev->core));
 
 	result = device_register(&dev->core);
 	return result;
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 97619fd..ddc2a30 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -54,7 +54,7 @@
 
 config CMM
 	tristate "Collaborative memory management"
-	depends on PPC_SMLPAR
+	depends on PPC_SMLPAR && !CRASH_DUMP
 	default y
 	help
 	  Select this option, if you want to enable the kernel interface
diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c
index 5cd4d27..6567439 100644
--- a/arch/powerpc/platforms/pseries/cmm.c
+++ b/arch/powerpc/platforms/pseries/cmm.c
@@ -28,6 +28,7 @@
 #include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/oom.h>
+#include <linux/reboot.h>
 #include <linux/sched.h>
 #include <linux/stringify.h>
 #include <linux/swap.h>
@@ -384,6 +385,26 @@
 }
 
 /**
+ * cmm_reboot_notifier - Make sure pages are not still marked as "loaned"
+ *
+ **/
+static int cmm_reboot_notifier(struct notifier_block *nb,
+			       unsigned long action, void *unused)
+{
+	if (action == SYS_RESTART) {
+		if (cmm_thread_ptr)
+			kthread_stop(cmm_thread_ptr);
+		cmm_thread_ptr = NULL;
+		cmm_free_pages(loaned_pages);
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block cmm_reboot_nb = {
+	.notifier_call = cmm_reboot_notifier,
+};
+
+/**
  * cmm_init - Module initialization
  *
  * Return value:
@@ -399,9 +420,12 @@
 	if ((rc = register_oom_notifier(&cmm_oom_nb)) < 0)
 		return rc;
 
-	if ((rc = cmm_sysfs_register(&cmm_sysdev)))
+	if ((rc = register_reboot_notifier(&cmm_reboot_nb)))
 		goto out_oom_notifier;
 
+	if ((rc = cmm_sysfs_register(&cmm_sysdev)))
+		goto out_reboot_notifier;
+
 	if (cmm_disabled)
 		return rc;
 
@@ -415,6 +439,8 @@
 
 out_unregister_sysfs:
 	cmm_unregister_sysfs(&cmm_sysdev);
+out_reboot_notifier:
+	unregister_reboot_notifier(&cmm_reboot_nb);
 out_oom_notifier:
 	unregister_oom_notifier(&cmm_oom_nb);
 	return rc;
@@ -431,6 +457,7 @@
 	if (cmm_thread_ptr)
 		kthread_stop(cmm_thread_ptr);
 	unregister_oom_notifier(&cmm_oom_nb);
+	unregister_reboot_notifier(&cmm_reboot_nb);
 	cmm_free_pages(loaned_pages);
 	cmm_unregister_sysfs(&cmm_sysdev);
 }
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 54816d7..989d646 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -21,6 +21,8 @@
  * Please address comments and feedback to Linas Vepstas <linas@austin.ibm.com>
  */
 
+#undef DEBUG
+
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -488,10 +490,8 @@
 	if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
 	    pdn->eeh_mode & EEH_MODE_NOCHECK) {
 		ignored_check++;
-#ifdef DEBUG
-		printk ("EEH:ignored check (%x) for %s %s\n", 
-		        pdn->eeh_mode, pci_name (dev), dn->full_name);
-#endif
+		pr_debug("EEH: Ignored check (%x) for %s %s\n",
+			 pdn->eeh_mode, pci_name (dev), dn->full_name);
 		return 0;
 	}
 
@@ -1014,10 +1014,9 @@
 			eeh_subsystem_enabled = 1;
 			pdn->eeh_mode |= EEH_MODE_SUPPORTED;
 
-#ifdef DEBUG
-			printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n",
-			       dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr);
-#endif
+			pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n",
+				 dn->full_name, pdn->eeh_config_addr,
+				 pdn->eeh_pe_config_addr);
 		} else {
 
 			/* This device doesn't support EEH, but it may have an
@@ -1161,13 +1160,17 @@
 	if (!dev || !eeh_subsystem_enabled)
 		return;
 
-#ifdef DEBUG
-	printk(KERN_DEBUG "EEH: adding device %s\n", pci_name(dev));
-#endif
+	pr_debug("EEH: Adding device %s\n", pci_name(dev));
 
-	pci_dev_get (dev);
 	dn = pci_device_to_OF_node(dev);
 	pdn = PCI_DN(dn);
+	if (pdn->pcidev == dev) {
+		pr_debug("EEH: Already referenced !\n");
+		return;
+	}
+	WARN_ON(pdn->pcidev);
+
+	pci_dev_get (dev);
 	pdn->pcidev = dev;
 
 	pci_addr_cache_insert_device(dev);
@@ -1206,17 +1209,18 @@
 		return;
 
 	/* Unregister the device with the EEH/PCI address search system */
-#ifdef DEBUG
-	printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev));
-#endif
-	pci_addr_cache_remove_device(dev);
-	eeh_sysfs_remove_device(dev);
+	pr_debug("EEH: Removing device %s\n", pci_name(dev));
 
 	dn = pci_device_to_OF_node(dev);
-	if (PCI_DN(dn)->pcidev) {
-		PCI_DN(dn)->pcidev = NULL;
-		pci_dev_put (dev);
+	if (PCI_DN(dn)->pcidev == NULL) {
+		pr_debug("EEH: Not referenced !\n");
+		return;
 	}
+	PCI_DN(dn)->pcidev = NULL;
+	pci_dev_put (dev);
+
+	pci_addr_cache_remove_device(dev);
+	eeh_sysfs_remove_device(dev);
 }
 
 void eeh_remove_bus_device(struct pci_dev *dev)
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 1f03248..a20ead8 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -116,7 +116,7 @@
 		cpu_status = query_cpu_stopped(pcpu);
 		if (cpu_status == 0 || cpu_status == -1)
 			break;
-		msleep(200);
+		cpu_relax();
 	}
 	if (cpu_status != 0) {
 		printk("Querying DEAD? cpu %i (%i) shows %i\n",
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index 7190493..5e1ed3d 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -25,6 +25,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#undef DEBUG
+
 #include <linux/pci.h>
 #include <asm/pci-bridge.h>
 #include <asm/ppc-pci.h>
@@ -69,73 +71,24 @@
  * Remove all of the PCI devices under this bus both from the
  * linux pci device tree, and from the powerpc EEH address cache.
  */
-void
-pcibios_remove_pci_devices(struct pci_bus *bus)
+void pcibios_remove_pci_devices(struct pci_bus *bus)
 {
-	struct pci_dev *dev, *tmp;
-
-	list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
-		eeh_remove_bus_device(dev);
-		pci_remove_bus_device(dev);
-	}
-}
-EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
-
-/* Must be called before pci_bus_add_devices */
-void
-pcibios_fixup_new_pci_devices(struct pci_bus *bus)
-{
-	struct pci_dev *dev;
-
-	list_for_each_entry(dev, &bus->devices, bus_list) {
-		/* Skip already-added devices */
-		if (!dev->is_added) {
-			int i;
-
-			/* Fill device archdata and setup iommu table */
-			pcibios_setup_new_device(dev);
-
-			pci_read_irq_line(dev);
-			for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-				struct resource *r = &dev->resource[i];
-
-				if (r->parent || !r->start || !r->flags)
-					continue;
-				pci_claim_resource(dev, i);
-			}
-		}
-	}
-}
-EXPORT_SYMBOL_GPL(pcibios_fixup_new_pci_devices);
-
-static int
-pcibios_pci_config_bridge(struct pci_dev *dev)
-{
-	u8 sec_busno;
+ 	struct pci_dev *dev, *tmp;
 	struct pci_bus *child_bus;
 
-	/* Get busno of downstream bus */
-	pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
+	/* First go down child busses */
+	list_for_each_entry(child_bus, &bus->children, node)
+		pcibios_remove_pci_devices(child_bus);
 
-	/* Add to children of PCI bridge dev->bus */
-	child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
-	if (!child_bus) {
-		printk (KERN_ERR "%s: could not add second bus\n", __func__);
-		return -EIO;
-	}
-	sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
-
-	pci_scan_child_bus(child_bus);
-
-	/* Fixup new pci devices */
-	pcibios_fixup_new_pci_devices(child_bus);
-
-	/* Make the discovered devices available */
-	pci_bus_add_devices(child_bus);
-
-	eeh_add_device_tree_late(child_bus);
-	return 0;
+	pr_debug("PCI: Removing devices on bus %04x:%02x\n",
+		 pci_domain_nr(bus),  bus->number);
+	list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
+		pr_debug("     * Removing %s...\n", pci_name(dev));
+		eeh_remove_bus_device(dev);
+ 		pci_remove_bus_device(dev);
+ 	}
 }
+EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
 
 /**
  * pcibios_add_pci_devices - adds new pci devices to bus
@@ -147,10 +100,9 @@
  * is how this routine differs from other, similar pcibios
  * routines.)
  */
-void
-pcibios_add_pci_devices(struct pci_bus * bus)
+void pcibios_add_pci_devices(struct pci_bus * bus)
 {
-	int slotno, num, mode;
+	int slotno, num, mode, pass, max;
 	struct pci_dev *dev;
 	struct device_node *dn = pci_bus_to_OF_node(bus);
 
@@ -162,26 +114,23 @@
 
 	if (mode == PCI_PROBE_DEVTREE) {
 		/* use ofdt-based probe */
-		of_scan_bus(dn, bus);
-		if (!list_empty(&bus->devices)) {
-			pcibios_fixup_new_pci_devices(bus);
-			pci_bus_add_devices(bus);
-			eeh_add_device_tree_late(bus);
-		}
+		of_rescan_bus(dn, bus);
 	} else if (mode == PCI_PROBE_NORMAL) {
 		/* use legacy probe */
 		slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
 		num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
-		if (num) {
-			pcibios_fixup_new_pci_devices(bus);
-			pci_bus_add_devices(bus);
-			eeh_add_device_tree_late(bus);
+		if (!num)
+			return;
+		pcibios_setup_bus_devices(bus);
+		max = bus->secondary;
+		for (pass=0; pass < 2; pass++)
+			list_for_each_entry(dev, &bus->devices, bus_list) {
+			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+			    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+				max = pci_scan_bridge(bus, dev, max, pass);
 		}
-
-		list_for_each_entry(dev, &bus->devices, bus_list)
-			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
-				pcibios_pci_config_bridge(dev);
 	}
+	pcibios_finish_adding_to_bus(bus);
 }
 EXPORT_SYMBOL_GPL(pcibios_add_pci_devices);
 
@@ -190,6 +139,8 @@
 	struct pci_controller *phb;
 	int primary;
 
+	pr_debug("PCI: Initializing new hotplug PHB %s\n", dn->full_name);
+
 	primary = list_empty(&hose_list);
 	phb = pcibios_alloc_controller(dn);
 	if (!phb)
@@ -203,11 +154,59 @@
 		eeh_add_device_tree_early(dn);
 
 	scan_phb(phb);
-	pcibios_allocate_bus_resources(phb->bus);
-	pcibios_fixup_new_pci_devices(phb->bus);
-	pci_bus_add_devices(phb->bus);
-	eeh_add_device_tree_late(phb->bus);
+	pcibios_finish_adding_to_bus(phb->bus);
 
 	return phb;
 }
 EXPORT_SYMBOL_GPL(init_phb_dynamic);
+
+/* RPA-specific bits for removing PHBs */
+int remove_phb_dynamic(struct pci_controller *phb)
+{
+	struct pci_bus *b = phb->bus;
+	struct resource *res;
+	int rc, i;
+
+	pr_debug("PCI: Removing PHB %04x:%02x... \n",
+		 pci_domain_nr(b), b->number);
+
+	/* We cannot to remove a root bus that has children */
+	if (!(list_empty(&b->children) && list_empty(&b->devices)))
+		return -EBUSY;
+
+	/* We -know- there aren't any child devices anymore at this stage
+	 * and thus, we can safely unmap the IO space as it's not in use
+	 */
+	res = &phb->io_resource;
+	if (res->flags & IORESOURCE_IO) {
+		rc = pcibios_unmap_io_space(b);
+		if (rc) {
+			printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
+			       __func__, b->name);
+			return 1;
+		}
+	}
+
+	/* Unregister the bridge device from sysfs and remove the PCI bus */
+	device_unregister(b->bridge);
+	phb->bus = NULL;
+	pci_remove_bus(b);
+
+	/* Now release the IO resource */
+	if (res->flags & IORESOURCE_IO)
+		release_resource(res);
+
+	/* Release memory resources */
+	for (i = 0; i < 3; ++i) {
+		res = &phb->mem_resources[i];
+		if (!(res->flags & IORESOURCE_MEM))
+			continue;
+		release_resource(res);
+	}
+
+	/* Free pci_controller data structure */
+	pcibios_free_controller(phb);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(remove_phb_dynamic);
diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c
index edbc012..6cf35cd 100644
--- a/arch/powerpc/platforms/pseries/phyp_dump.c
+++ b/arch/powerpc/platforms/pseries/phyp_dump.c
@@ -130,6 +130,9 @@
 static void print_dump_header(const struct phyp_dump_header *ph)
 {
 #ifdef DEBUG
+	if (ph == NULL)
+		return;
+
 	printk(KERN_INFO "dump header:\n");
 	/* setup some ph->sections required */
 	printk(KERN_INFO "version = %d\n", ph->version);
@@ -411,6 +414,8 @@
 		of_node_put(rtas);
 	}
 
+	ibm_configure_kernel_dump = rtas_token("ibm,configure-kernel-dump");
+
 	print_dump_header(dump_header);
 	dump_area_length = init_dump_header(&phdr);
 	/* align down */
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index e190477..f7a6902 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -579,7 +579,7 @@
 	int i, j;
 	struct device_node *np;
 	u32 ilen;
-	const u32 *ireg, *isize;
+	const u32 *ireg;
 	u32 hcpuid;
 
 	/* Find the server numbers for the boot cpu. */
@@ -607,11 +607,6 @@
 		}
 	}
 
-	/* get the bit size of server numbers */
-	isize = of_get_property(np, "ibm,interrupt-server#-size", NULL);
-	if (isize)
-		interrupt_server_size = *isize;
-
 	of_node_put(np);
 }
 
@@ -682,6 +677,7 @@
 	struct device_node *np;
 	u32 indx = 0;
 	int found = 0;
+	const u32 *isize;
 
 	ppc64_boot_msg(0x20, "XICS Init");
 
@@ -701,6 +697,26 @@
 	if (found == 0)
 		return;
 
+	/* get the bit size of server numbers */
+	found = 0;
+
+	for_each_compatible_node(np, NULL, "ibm,ppc-xics") {
+		isize = of_get_property(np, "ibm,interrupt-server#-size", NULL);
+
+		if (!isize)
+			continue;
+
+		if (!found) {
+			interrupt_server_size = *isize;
+			found = 1;
+		} else if (*isize != interrupt_server_size) {
+			printk(KERN_WARNING "XICS: "
+			       "mismatched ibm,interrupt-server#-size\n");
+			interrupt_server_size = max(*isize,
+						    interrupt_server_size);
+		}
+	}
+
 	xics_update_irq_servers();
 	xics_init_host();
 
@@ -728,9 +744,18 @@
 /* Have the calling processor join or leave the specified global queue */
 static void xics_set_cpu_giq(unsigned int gserver, unsigned int join)
 {
-	int status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
-		(1UL << interrupt_server_size) - 1 - gserver, join);
-	WARN_ON(status < 0);
+	int index;
+	int status;
+
+	if (!rtas_indicator_present(GLOBAL_INTERRUPT_QUEUE, NULL))
+		return;
+
+	index = (1UL << interrupt_server_size) - 1 - gserver;
+
+	status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, index, join);
+
+	WARN(status < 0, "set-indicator(%d, %d, %u) returned %d\n",
+	     GLOBAL_INTERRUPT_QUEUE, index, join, status);
 }
 
 void xics_setup_cpu(void)
diff --git a/arch/powerpc/sysdev/bestcomm/ata.c b/arch/powerpc/sysdev/bestcomm/ata.c
index 1f5258f..901c9f9 100644
--- a/arch/powerpc/sysdev/bestcomm/ata.c
+++ b/arch/powerpc/sysdev/bestcomm/ata.c
@@ -61,6 +61,9 @@
 	struct bcom_ata_var *var;
 	struct bcom_ata_inc *inc;
 
+	/* Prefetch breaks ATA DMA.  Turn it off for ATA DMA */
+	bcom_disable_prefetch();
+
 	tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0);
 	if (!tsk)
 		return NULL;
diff --git a/arch/powerpc/sysdev/bestcomm/ata.h b/arch/powerpc/sysdev/bestcomm/ata.h
index 1098276..0b23718 100644
--- a/arch/powerpc/sysdev/bestcomm/ata.h
+++ b/arch/powerpc/sysdev/bestcomm/ata.h
@@ -16,22 +16,15 @@
 
 struct bcom_ata_bd {
 	u32	status;
-	u32	dst_pa;
 	u32	src_pa;
+	u32	dst_pa;
 };
 
-extern struct bcom_task *
-bcom_ata_init(int queue_len, int maxbufsize);
-
-extern void
-bcom_ata_rx_prepare(struct bcom_task *tsk);
-
-extern void
-bcom_ata_tx_prepare(struct bcom_task *tsk);
-
-extern void
-bcom_ata_reset_bd(struct bcom_task *tsk);
-
+extern struct bcom_task * bcom_ata_init(int queue_len, int maxbufsize);
+extern void bcom_ata_rx_prepare(struct bcom_task *tsk);
+extern void bcom_ata_tx_prepare(struct bcom_task *tsk);
+extern void bcom_ata_reset_bd(struct bcom_task *tsk);
+extern void bcom_ata_release(struct bcom_task *tsk);
 
 #endif /* __BESTCOMM_ATA_H__ */
 
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c
index 446c9ea..378ebd9 100644
--- a/arch/powerpc/sysdev/bestcomm/bestcomm.c
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c
@@ -279,7 +279,6 @@
 	int task;
 	phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa;
 	unsigned int tdt_size, ctx_size, var_size, fdt_size;
-	u16 regval;
 
 	/* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */
 	tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt);
@@ -331,10 +330,8 @@
 	out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
 
 	/* Disable COMM Bus Prefetch on the original 5200; it's broken */
-	if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) {
-		regval = in_be16(&bcom_eng->regs->PtdCntrl);
-		out_be16(&bcom_eng->regs->PtdCntrl,  regval | 1);
-	}
+	if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR)
+		bcom_disable_prefetch();
 
 	/* Init lock */
 	spin_lock_init(&bcom_eng->lock);
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/sysdev/bestcomm/bestcomm.h
index c960a8b..23a95f8 100644
--- a/arch/powerpc/sysdev/bestcomm/bestcomm.h
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h
@@ -16,8 +16,19 @@
 #ifndef __BESTCOMM_H__
 #define __BESTCOMM_H__
 
-struct bcom_bd; /* defined later on ... */
-
+/**
+ * struct bcom_bd - Structure describing a generic BestComm buffer descriptor
+ * @status: The current status of this buffer. Exact meaning depends on the
+ *          task type
+ * @data: An array of u32 extra data.  Size of array is task dependant.
+ *
+ * Note: Don't dereference a bcom_bd pointer as an array.  The size of the
+ *       bcom_bd is variable.  Use bcom_get_bd() instead.
+ */
+struct bcom_bd {
+	u32	status;
+	u32	data[0];	/* variable payload size */
+};
 
 /* ======================================================================== */
 /* Generic task management                                                   */
@@ -84,17 +95,6 @@
 /* BD based tasks helpers                                                   */
 /* ======================================================================== */
 
-/**
- * struct bcom_bd - Structure describing a generic BestComm buffer descriptor
- * @status: The current status of this buffer. Exact meaning depends on the
- *          task type
- * @data: An array of u32 whose meaning depends on the task type.
- */
-struct bcom_bd {
-	u32	status;
-	u32	data[1];	/* variable, but at least 1 */
-};
-
 #define BCOM_BD_READY	0x40000000ul
 
 /** _bcom_next_index - Get next input index.
@@ -140,15 +140,31 @@
 }
 
 /**
+ * bcom_get_bd - Get a BD from the queue
+ * @tsk: The BestComm task structure
+ * index: Index of the BD to fetch
+ */
+static inline struct bcom_bd
+*bcom_get_bd(struct bcom_task *tsk, unsigned int index)
+{
+	/* A cast to (void*) so the address can be incremented by the
+	 * real size instead of by sizeof(struct bcom_bd) */
+	return ((void *)tsk->bd) + (index * tsk->bd_size);
+}
+
+/**
  * bcom_buffer_done - Checks if a BestComm 
  * @tsk: The BestComm task structure
  */
 static inline int
 bcom_buffer_done(struct bcom_task *tsk)
 {
+	struct bcom_bd *bd;
 	if (bcom_queue_empty(tsk))
 		return 0;
-	return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY);
+
+	bd = bcom_get_bd(tsk, tsk->outdex);
+	return !(bd->status & BCOM_BD_READY);
 }
 
 /**
@@ -160,16 +176,21 @@
 static inline struct bcom_bd *
 bcom_prepare_next_buffer(struct bcom_task *tsk)
 {
-	tsk->bd[tsk->index].status = 0;	/* cleanup last status */
-	return &tsk->bd[tsk->index];
+	struct bcom_bd *bd;
+
+	bd = bcom_get_bd(tsk, tsk->index);
+	bd->status = 0;	/* cleanup last status */
+	return bd;
 }
 
 static inline void
 bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie)
 {
+	struct bcom_bd *bd = bcom_get_bd(tsk, tsk->index);
+
 	tsk->cookie[tsk->index] = cookie;
 	mb();	/* ensure the bd is really up-to-date */
-	tsk->bd[tsk->index].status |= BCOM_BD_READY;
+	bd->status |= BCOM_BD_READY;
 	tsk->index = _bcom_next_index(tsk);
 	if (tsk->flags & BCOM_FLAGS_ENABLE_TASK)
 		bcom_enable(tsk);
@@ -179,10 +200,12 @@
 bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd)
 {
 	void *cookie = tsk->cookie[tsk->outdex];
+	struct bcom_bd *bd = bcom_get_bd(tsk, tsk->outdex);
+
 	if (p_status)
-		*p_status = tsk->bd[tsk->outdex].status;
+		*p_status = bd->status;
 	if (p_bd)
-		*p_bd = &tsk->bd[tsk->outdex];
+		*p_bd = bd;
 	tsk->outdex = _bcom_next_outdex(tsk);
 	return cookie;
 }
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
index 866a291..eb0d1c8 100644
--- a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
@@ -198,8 +198,8 @@
 #define BCOM_IPR_SCTMR_1	2
 #define BCOM_IPR_FEC_RX		6
 #define BCOM_IPR_FEC_TX		5
-#define BCOM_IPR_ATA_RX		4
-#define BCOM_IPR_ATA_TX		3
+#define BCOM_IPR_ATA_RX		7
+#define BCOM_IPR_ATA_TX		7
 #define BCOM_IPR_SCPCI_RX	2
 #define BCOM_IPR_SCPCI_TX	2
 #define BCOM_IPR_PSC3_RX	2
@@ -241,6 +241,22 @@
 
 #define TASK_ENABLE             0x8000
 
+/**
+ * bcom_disable_prefetch - Hook to disable bus prefetching
+ *
+ * ATA DMA and the original MPC5200 need this due to silicon bugs.  At the
+ * moment disabling prefetch is a one-way street.  There is no mechanism
+ * in place to turn prefetch back on after it has been disabled.  There is
+ * no reason it couldn't be done, it would just be more complex to implement.
+ */
+static inline void bcom_disable_prefetch(void)
+{
+	u16 regval;
+
+	regval = in_be16(&bcom_eng->regs->PtdCntrl);
+	out_be16(&bcom_eng->regs->PtdCntrl, regval | 1);
+};
+
 static inline void
 bcom_enable_task(int task)
 {
diff --git a/arch/powerpc/sysdev/dcr-low.S b/arch/powerpc/sysdev/dcr-low.S
index 2078f39..d3098ef 100644
--- a/arch/powerpc/sysdev/dcr-low.S
+++ b/arch/powerpc/sysdev/dcr-low.S
@@ -11,14 +11,20 @@
 
 #include <asm/ppc_asm.h>
 #include <asm/processor.h>
+#include <asm/bug.h>
 
 #define DCR_ACCESS_PROLOG(table) \
+	cmpli	cr0,r3,1024;	 \
 	rlwinm  r3,r3,4,18,27;   \
 	lis     r5,table@h;      \
 	ori     r5,r5,table@l;   \
 	add     r3,r3,r5;        \
+	bge-	1f;		 \
 	mtctr   r3;              \
-	bctr
+	bctr;			 \
+1:	trap;			 \
+	EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0;	\
+	blr
 
 _GLOBAL(__mfdcr)
 	DCR_ACCESS_PROLOG(__mfdcr_table)
diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c
index a8ba998..bb44aa9 100644
--- a/arch/powerpc/sysdev/dcr.c
+++ b/arch/powerpc/sysdev/dcr.c
@@ -124,7 +124,8 @@
 
 #endif /* defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO) */
 
-unsigned int dcr_resource_start(struct device_node *np, unsigned int index)
+unsigned int dcr_resource_start(const struct device_node *np,
+				unsigned int index)
 {
 	unsigned int ds;
 	const u32 *dr = of_get_property(np, "dcr-reg", &ds);
@@ -136,7 +137,7 @@
 }
 EXPORT_SYMBOL_GPL(dcr_resource_start);
 
-unsigned int dcr_resource_len(struct device_node *np, unsigned int index)
+unsigned int dcr_resource_len(const struct device_node *np, unsigned int index)
 {
 	unsigned int ds;
 	const u32 *dr = of_get_property(np, "dcr-reg", &ds);
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 5b264eb..d5f9ae0 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -187,7 +187,7 @@
 		printk(KERN_WARNING "Can't get bus-range for %s, assume"
 			" bus 0\n", dev->full_name);
 
-	ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS;
+	ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS);
 	hose = pcibios_alloc_controller(dev);
 	if (!hose)
 		return -ENOMEM;
@@ -300,7 +300,7 @@
 		       " bus 0\n", dev->full_name);
 	}
 
-	ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS;
+	ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS);
 	hose = pcibios_alloc_controller(dev);
 	if (!hose)
 		return -ENOMEM;
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 26ecb96..115cb16 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -207,236 +207,51 @@
 arch_initcall(of_add_fixed_phys);
 #endif /* CONFIG_FIXED_PHY */
 
-static int gfar_mdio_of_init_one(struct device_node *np)
+#ifdef CONFIG_PPC_83xx
+static int __init mpc83xx_wdt_init(void)
 {
-	int k;
-	struct device_node *child = NULL;
-	struct gianfar_mdio_data mdio_data;
-	struct platform_device *mdio_dev;
-	struct resource res;
-	int ret;
-
-	memset(&res, 0, sizeof(res));
-	memset(&mdio_data, 0, sizeof(mdio_data));
-
-	ret = of_address_to_resource(np, 0, &res);
-	if (ret)
-		return ret;
-
-	/* The gianfar device will try to use the same ID created below to find
-	 * this bus, to coordinate register access (since they share).  */
-	mdio_dev = platform_device_register_simple("fsl-gianfar_mdio",
-			res.start&0xfffff, &res, 1);
-	if (IS_ERR(mdio_dev))
-		return PTR_ERR(mdio_dev);
-
-	for (k = 0; k < 32; k++)
-		mdio_data.irq[k] = PHY_POLL;
-
-	while ((child = of_get_next_child(np, child)) != NULL) {
-		int irq = irq_of_parse_and_map(child, 0);
-		if (irq != NO_IRQ) {
-			const u32 *id = of_get_property(child, "reg", NULL);
-			mdio_data.irq[*id] = irq;
-		}
-	}
-
-	ret = platform_device_add_data(mdio_dev, &mdio_data,
-				sizeof(struct gianfar_mdio_data));
-	if (ret)
-		platform_device_unregister(mdio_dev);
-
-	return ret;
-}
-
-static int __init gfar_mdio_of_init(void)
-{
-	struct device_node *np = NULL;
-
-	for_each_compatible_node(np, NULL, "fsl,gianfar-mdio")
-		gfar_mdio_of_init_one(np);
-
-	/* try the deprecated version */
-	for_each_compatible_node(np, "mdio", "gianfar");
-		gfar_mdio_of_init_one(np);
-
-	return 0;
-}
-
-arch_initcall(gfar_mdio_of_init);
-
-static const char *gfar_tx_intr = "tx";
-static const char *gfar_rx_intr = "rx";
-static const char *gfar_err_intr = "error";
-
-static int __init gfar_of_init(void)
-{
+	struct resource r;
 	struct device_node *np;
-	unsigned int i;
-	struct platform_device *gfar_dev;
-	struct resource res;
+	struct platform_device *dev;
+	u32 freq = fsl_get_sys_freq();
 	int ret;
 
-	for (np = NULL, i = 0;
-	     (np = of_find_compatible_node(np, "network", "gianfar")) != NULL;
-	     i++) {
-		struct resource r[4];
-		struct device_node *phy, *mdio;
-		struct gianfar_platform_data gfar_data;
-		const unsigned int *id;
-		const char *model;
-		const char *ctype;
-		const void *mac_addr;
-		const phandle *ph;
-		int n_res = 2;
+	np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt");
 
-		if (!of_device_is_available(np))
-			continue;
-
-		memset(r, 0, sizeof(r));
-		memset(&gfar_data, 0, sizeof(gfar_data));
-
-		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto err;
-
-		of_irq_to_resource(np, 0, &r[1]);
-
-		model = of_get_property(np, "model", NULL);
-
-		/* If we aren't the FEC we have multiple interrupts */
-		if (model && strcasecmp(model, "FEC")) {
-			r[1].name = gfar_tx_intr;
-
-			r[2].name = gfar_rx_intr;
-			of_irq_to_resource(np, 1, &r[2]);
-
-			r[3].name = gfar_err_intr;
-			of_irq_to_resource(np, 2, &r[3]);
-
-			n_res += 2;
-		}
-
-		gfar_dev =
-		    platform_device_register_simple("fsl-gianfar", i, &r[0],
-						    n_res);
-
-		if (IS_ERR(gfar_dev)) {
-			ret = PTR_ERR(gfar_dev);
-			goto err;
-		}
-
-		mac_addr = of_get_mac_address(np);
-		if (mac_addr)
-			memcpy(gfar_data.mac_addr, mac_addr, 6);
-
-		if (model && !strcasecmp(model, "TSEC"))
-			gfar_data.device_flags =
-			    FSL_GIANFAR_DEV_HAS_GIGABIT |
-			    FSL_GIANFAR_DEV_HAS_COALESCE |
-			    FSL_GIANFAR_DEV_HAS_RMON |
-			    FSL_GIANFAR_DEV_HAS_MULTI_INTR;
-		if (model && !strcasecmp(model, "eTSEC"))
-			gfar_data.device_flags =
-			    FSL_GIANFAR_DEV_HAS_GIGABIT |
-			    FSL_GIANFAR_DEV_HAS_COALESCE |
-			    FSL_GIANFAR_DEV_HAS_RMON |
-			    FSL_GIANFAR_DEV_HAS_MULTI_INTR |
-			    FSL_GIANFAR_DEV_HAS_CSUM |
-			    FSL_GIANFAR_DEV_HAS_VLAN |
-			    FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
-
-		ctype = of_get_property(np, "phy-connection-type", NULL);
-
-		/* We only care about rgmii-id.  The rest are autodetected */
-		if (ctype && !strcmp(ctype, "rgmii-id"))
-			gfar_data.interface = PHY_INTERFACE_MODE_RGMII_ID;
-		else
-			gfar_data.interface = PHY_INTERFACE_MODE_MII;
-
-		if (of_get_property(np, "fsl,magic-packet", NULL))
-			gfar_data.device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
-
-		ph = of_get_property(np, "phy-handle", NULL);
-		if (ph == NULL) {
-			u32 *fixed_link;
-
-			fixed_link = (u32 *)of_get_property(np, "fixed-link",
-							   NULL);
-			if (!fixed_link) {
-				ret = -ENODEV;
-				goto unreg;
-			}
-
-			snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "0");
-			gfar_data.phy_id = fixed_link[0];
-		} else {
-			phy = of_find_node_by_phandle(*ph);
-
-			if (phy == NULL) {
-				ret = -ENODEV;
-				goto unreg;
-			}
-
-			mdio = of_get_parent(phy);
-
-			id = of_get_property(phy, "reg", NULL);
-			ret = of_address_to_resource(mdio, 0, &res);
-			if (ret) {
-				of_node_put(phy);
-				of_node_put(mdio);
-				goto unreg;
-			}
-
-			gfar_data.phy_id = *id;
-			snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "%llx",
-				 (unsigned long long)res.start&0xfffff);
-
-			of_node_put(phy);
-			of_node_put(mdio);
-		}
-
-		/* Get MDIO bus controlled by this eTSEC, if any.  Normally only
-		 * eTSEC 1 will control an MDIO bus, not necessarily the same
-		 * bus that its PHY is on ('mdio' above), so we can't just use
-		 * that.  What we do is look for a gianfar mdio device that has
-		 * overlapping registers with this device.  That's really the
-		 * whole point, to find the device sharing our registers to
-		 * coordinate access with it.
-		 */
-		for_each_compatible_node(mdio, NULL, "fsl,gianfar-mdio") {
-			if (of_address_to_resource(mdio, 0, &res))
-				continue;
-
-			if (res.start >= r[0].start && res.end <= r[0].end) {
-				/* Get the ID the mdio bus platform device was
-				 * registered with.  gfar_data.bus_id is
-				 * different because it's for finding a PHY,
-				 * while this is for finding a MII bus.
-				 */
-				gfar_data.mdio_bus = res.start&0xfffff;
-				of_node_put(mdio);
-				break;
-			}
-		}
-
-		ret =
-		    platform_device_add_data(gfar_dev, &gfar_data,
-					     sizeof(struct
-						    gianfar_platform_data));
-		if (ret)
-			goto unreg;
+	if (!np) {
+		ret = -ENODEV;
+		goto nodev;
 	}
 
+	memset(&r, 0, sizeof(r));
+
+	ret = of_address_to_resource(np, 0, &r);
+	if (ret)
+		goto err;
+
+	dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1);
+	if (IS_ERR(dev)) {
+		ret = PTR_ERR(dev);
+		goto err;
+	}
+
+	ret = platform_device_add_data(dev, &freq, sizeof(freq));
+	if (ret)
+		goto unreg;
+
+	of_node_put(np);
 	return 0;
 
 unreg:
-	platform_device_unregister(gfar_dev);
+	platform_device_unregister(dev);
 err:
+	of_node_put(np);
+nodev:
 	return ret;
 }
 
-arch_initcall(gfar_of_init);
+arch_initcall(mpc83xx_wdt_init);
+#endif
 
 static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
 {
diff --git a/arch/powerpc/sysdev/grackle.c b/arch/powerpc/sysdev/grackle.c
index d502927..5da37c2 100644
--- a/arch/powerpc/sysdev/grackle.c
+++ b/arch/powerpc/sysdev/grackle.c
@@ -57,7 +57,7 @@
 {
 	setup_indirect_pci(hose, 0xfec00000, 0xfee00000, 0);
 	if (machine_is_compatible("PowerMac1,1"))
-		ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS;
+		ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS);
 	if (machine_is_compatible("AAPL,PowerBook1998"))
 		grackle_set_loop_snoop(hose, 1);
 #if 0	/* Disabled for now, HW problems ??? */
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 1890fb0..c82babb 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -661,17 +661,6 @@
 	(void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI));
 }
 
-#ifdef CONFIG_SMP
-static irqreturn_t mpic_ipi_action(int irq, void *data)
-{
-	long ipi = (long)data;
-
-	smp_message_recv(ipi);
-
-	return IRQ_HANDLED;
-}
-#endif /* CONFIG_SMP */
-
 /*
  * Linux descriptor level callbacks
  */
@@ -1548,13 +1537,7 @@
 void mpic_request_ipis(void)
 {
 	struct mpic *mpic = mpic_primary;
-	long i, err;
-	static char *ipi_names[] = {
-		"IPI0 (call function)",
-		"IPI1 (reschedule)",
-		"IPI2 (call function single)",
-		"IPI3 (debugger break)",
-	};
+	int i;
 	BUG_ON(mpic == NULL);
 
 	printk(KERN_INFO "mpic: requesting IPIs ... \n");
@@ -1563,17 +1546,10 @@
 		unsigned int vipi = irq_create_mapping(mpic->irqhost,
 						       mpic->ipi_vecs[0] + i);
 		if (vipi == NO_IRQ) {
-			printk(KERN_ERR "Failed to map IPI %ld\n", i);
-			break;
+			printk(KERN_ERR "Failed to map %s\n", smp_ipi_name[i]);
+			continue;
 		}
-		err = request_irq(vipi, mpic_ipi_action,
-				  IRQF_DISABLED|IRQF_PERCPU,
-				  ipi_names[i], (void *)i);
-		if (err) {
-			printk(KERN_ERR "Request of irq %d for IPI %ld failed\n",
-			       vipi, i);
-			break;
-		}
+		smp_request_message_ipi(vipi, i);
 	}
 }
 
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index d3e4d61..77fae5f 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -194,11 +194,41 @@
  * 4xx PCI 2.x part
  */
 
+static int __init ppc4xx_setup_one_pci_PMM(struct pci_controller	*hose,
+					   void __iomem			*reg,
+					   u64				plb_addr,
+					   u64				pci_addr,
+					   u64				size,
+					   unsigned int			flags,
+					   int				index)
+{
+	u32 ma, pcila, pciha;
+
+	if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) ||
+	    size < 0x1000 || (plb_addr & (size - 1)) != 0) {
+		printk(KERN_WARNING "%s: Resource out of range\n",
+		       hose->dn->full_name);
+		return -1;
+	}
+	ma = (0xffffffffu << ilog2(size)) | 1;
+	if (flags & IORESOURCE_PREFETCH)
+		ma |= 2;
+
+	pciha = RES_TO_U32_HIGH(pci_addr);
+	pcila = RES_TO_U32_LOW(pci_addr);
+
+	writel(plb_addr, reg + PCIL0_PMM0LA + (0x10 * index));
+	writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * index));
+	writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * index));
+	writel(ma, reg + PCIL0_PMM0MA + (0x10 * index));
+
+	return 0;
+}
+
 static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
 					     void __iomem *reg)
 {
-	u32 la, ma, pcila, pciha;
-	int i, j;
+	int i, j, found_isa_hole = 0;
 
 	/* Setup outbound memory windows */
 	for (i = j = 0; i < 3; i++) {
@@ -213,28 +243,29 @@
 			break;
 		}
 
-		/* Calculate register values */
-		la = res->start;
-		pciha = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset);
-		pcila = RES_TO_U32_LOW(res->start - hose->pci_mem_offset);
+		/* Configure the resource */
+		if (ppc4xx_setup_one_pci_PMM(hose, reg,
+					     res->start,
+					     res->start - hose->pci_mem_offset,
+					     res->end + 1 - res->start,
+					     res->flags,
+					     j) == 0) {
+			j++;
 
-		ma = res->end + 1 - res->start;
-		if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) {
-			printk(KERN_WARNING "%s: Resource out of range\n",
-			       hose->dn->full_name);
-			continue;
+			/* If the resource PCI address is 0 then we have our
+			 * ISA memory hole
+			 */
+			if (res->start == hose->pci_mem_offset)
+				found_isa_hole = 1;
 		}
-		ma = (0xffffffffu << ilog2(ma)) | 0x1;
-		if (res->flags & IORESOURCE_PREFETCH)
-			ma |= 0x2;
-
-		/* Program register values */
-		writel(la, reg + PCIL0_PMM0LA + (0x10 * j));
-		writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * j));
-		writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * j));
-		writel(ma, reg + PCIL0_PMM0MA + (0x10 * j));
-		j++;
 	}
+
+	/* Handle ISA memory hole if not already covered */
+	if (j <= 2 && !found_isa_hole && hose->isa_mem_size)
+		if (ppc4xx_setup_one_pci_PMM(hose, reg, hose->isa_mem_phys, 0,
+					     hose->isa_mem_size, 0, j) == 0)
+			printk(KERN_INFO "%s: Legacy ISA memory support enabled\n",
+			       hose->dn->full_name);
 }
 
 static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose,
@@ -352,11 +383,52 @@
  * 4xx PCI-X part
  */
 
+static int __init ppc4xx_setup_one_pcix_POM(struct pci_controller	*hose,
+					    void __iomem		*reg,
+					    u64				plb_addr,
+					    u64				pci_addr,
+					    u64				size,
+					    unsigned int		flags,
+					    int				index)
+{
+	u32 lah, lal, pciah, pcial, sa;
+
+	if (!is_power_of_2(size) || size < 0x1000 ||
+	    (plb_addr & (size - 1)) != 0) {
+		printk(KERN_WARNING "%s: Resource out of range\n",
+		       hose->dn->full_name);
+		return -1;
+	}
+
+	/* Calculate register values */
+	lah = RES_TO_U32_HIGH(plb_addr);
+	lal = RES_TO_U32_LOW(plb_addr);
+	pciah = RES_TO_U32_HIGH(pci_addr);
+	pcial = RES_TO_U32_LOW(pci_addr);
+	sa = (0xffffffffu << ilog2(size)) | 0x1;
+
+	/* Program register values */
+	if (index == 0) {
+		writel(lah, reg + PCIX0_POM0LAH);
+		writel(lal, reg + PCIX0_POM0LAL);
+		writel(pciah, reg + PCIX0_POM0PCIAH);
+		writel(pcial, reg + PCIX0_POM0PCIAL);
+		writel(sa, reg + PCIX0_POM0SA);
+	} else {
+		writel(lah, reg + PCIX0_POM1LAH);
+		writel(lal, reg + PCIX0_POM1LAL);
+		writel(pciah, reg + PCIX0_POM1PCIAH);
+		writel(pcial, reg + PCIX0_POM1PCIAL);
+		writel(sa, reg + PCIX0_POM1SA);
+	}
+
+	return 0;
+}
+
 static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
 					      void __iomem *reg)
 {
-	u32 lah, lal, pciah, pcial, sa;
-	int i, j;
+	int i, j, found_isa_hole = 0;
 
 	/* Setup outbound memory windows */
 	for (i = j = 0; i < 3; i++) {
@@ -371,36 +443,29 @@
 			break;
 		}
 
-		/* Calculate register values */
-		lah = RES_TO_U32_HIGH(res->start);
-		lal = RES_TO_U32_LOW(res->start);
-		pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset);
-		pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset);
-		sa = res->end + 1 - res->start;
-		if (!is_power_of_2(sa) || sa < 0x100000 ||
-		    sa > 0xffffffffu) {
-			printk(KERN_WARNING "%s: Resource out of range\n",
-			       hose->dn->full_name);
-			continue;
-		}
-		sa = (0xffffffffu << ilog2(sa)) | 0x1;
+		/* Configure the resource */
+		if (ppc4xx_setup_one_pcix_POM(hose, reg,
+					      res->start,
+					      res->start - hose->pci_mem_offset,
+					      res->end + 1 - res->start,
+					      res->flags,
+					      j) == 0) {
+			j++;
 
-		/* Program register values */
-		if (j == 0) {
-			writel(lah, reg + PCIX0_POM0LAH);
-			writel(lal, reg + PCIX0_POM0LAL);
-			writel(pciah, reg + PCIX0_POM0PCIAH);
-			writel(pcial, reg + PCIX0_POM0PCIAL);
-			writel(sa, reg + PCIX0_POM0SA);
-		} else {
-			writel(lah, reg + PCIX0_POM1LAH);
-			writel(lal, reg + PCIX0_POM1LAL);
-			writel(pciah, reg + PCIX0_POM1PCIAH);
-			writel(pcial, reg + PCIX0_POM1PCIAL);
-			writel(sa, reg + PCIX0_POM1SA);
+			/* If the resource PCI address is 0 then we have our
+			 * ISA memory hole
+			 */
+			if (res->start == hose->pci_mem_offset)
+				found_isa_hole = 1;
 		}
-		j++;
 	}
+
+	/* Handle ISA memory hole if not already covered */
+	if (j <= 1 && !found_isa_hole && hose->isa_mem_size)
+		if (ppc4xx_setup_one_pcix_POM(hose, reg, hose->isa_mem_phys, 0,
+					      hose->isa_mem_size, 0, j) == 0)
+			printk(KERN_INFO "%s: Legacy ISA memory support enabled\n",
+			       hose->dn->full_name);
 }
 
 static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose,
@@ -1317,12 +1382,72 @@
 	.write = ppc4xx_pciex_write_config,
 };
 
+static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port	*port,
+					     struct pci_controller	*hose,
+					     void __iomem		*mbase,
+					     u64			plb_addr,
+					     u64			pci_addr,
+					     u64			size,
+					     unsigned int		flags,
+					     int			index)
+{
+	u32 lah, lal, pciah, pcial, sa;
+
+	if (!is_power_of_2(size) ||
+	    (index < 2 && size < 0x100000) ||
+	    (index == 2 && size < 0x100) ||
+	    (plb_addr & (size - 1)) != 0) {
+		printk(KERN_WARNING "%s: Resource out of range\n",
+		       hose->dn->full_name);
+		return -1;
+	}
+
+	/* Calculate register values */
+	lah = RES_TO_U32_HIGH(plb_addr);
+	lal = RES_TO_U32_LOW(plb_addr);
+	pciah = RES_TO_U32_HIGH(pci_addr);
+	pcial = RES_TO_U32_LOW(pci_addr);
+	sa = (0xffffffffu << ilog2(size)) | 0x1;
+
+	/* Program register values */
+	switch (index) {
+	case 0:
+		out_le32(mbase + PECFG_POM0LAH, pciah);
+		out_le32(mbase + PECFG_POM0LAL, pcial);
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah);
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal);
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff);
+		/* Note that 3 here means enabled | single region */
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3);
+		break;
+	case 1:
+		out_le32(mbase + PECFG_POM1LAH, pciah);
+		out_le32(mbase + PECFG_POM1LAL, pcial);
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah);
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal);
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff);
+		/* Note that 3 here means enabled | single region */
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3);
+		break;
+	case 2:
+		out_le32(mbase + PECFG_POM2LAH, pciah);
+		out_le32(mbase + PECFG_POM2LAL, pcial);
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah);
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal);
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff);
+		/* Note that 3 here means enabled | IO space !!! */
+		dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, sa | 3);
+		break;
+	}
+
+	return 0;
+}
+
 static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port,
 					       struct pci_controller *hose,
 					       void __iomem *mbase)
 {
-	u32 lah, lal, pciah, pcial, sa;
-	int i, j;
+	int i, j, found_isa_hole = 0;
 
 	/* Setup outbound memory windows */
 	for (i = j = 0; i < 3; i++) {
@@ -1337,53 +1462,38 @@
 			break;
 		}
 
-		/* Calculate register values */
-		lah = RES_TO_U32_HIGH(res->start);
-		lal = RES_TO_U32_LOW(res->start);
-		pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset);
-		pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset);
-		sa = res->end + 1 - res->start;
-		if (!is_power_of_2(sa) || sa < 0x100000 ||
-		    sa > 0xffffffffu) {
-			printk(KERN_WARNING "%s: Resource out of range\n",
-			       port->node->full_name);
-			continue;
-		}
-		sa = (0xffffffffu << ilog2(sa)) | 0x1;
+		/* Configure the resource */
+		if (ppc4xx_setup_one_pciex_POM(port, hose, mbase,
+					       res->start,
+					       res->start - hose->pci_mem_offset,
+					       res->end + 1 - res->start,
+					       res->flags,
+					       j) == 0) {
+			j++;
 
-		/* Program register values */
-		switch (j) {
-		case 0:
-			out_le32(mbase + PECFG_POM0LAH, pciah);
-			out_le32(mbase + PECFG_POM0LAL, pcial);
-			dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah);
-			dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal);
-			dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff);
-			dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3);
-			break;
-		case 1:
-			out_le32(mbase + PECFG_POM1LAH, pciah);
-			out_le32(mbase + PECFG_POM1LAL, pcial);
-			dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah);
-			dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal);
-			dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff);
-			dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3);
-			break;
+			/* If the resource PCI address is 0 then we have our
+			 * ISA memory hole
+			 */
+			if (res->start == hose->pci_mem_offset)
+				found_isa_hole = 1;
 		}
-		j++;
 	}
 
-	/* Configure IO, always 64K starting at 0 */
-	if (hose->io_resource.flags & IORESOURCE_IO) {
-		lah = RES_TO_U32_HIGH(hose->io_base_phys);
-		lal = RES_TO_U32_LOW(hose->io_base_phys);
-		out_le32(mbase + PECFG_POM2LAH, 0);
-		out_le32(mbase + PECFG_POM2LAL, 0);
-		dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah);
-		dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal);
-		dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff);
-		dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0xffff0000 | 3);
-	}
+	/* Handle ISA memory hole if not already covered */
+	if (j <= 1 && !found_isa_hole && hose->isa_mem_size)
+		if (ppc4xx_setup_one_pciex_POM(port, hose, mbase,
+					       hose->isa_mem_phys, 0,
+					       hose->isa_mem_size, 0, j) == 0)
+			printk(KERN_INFO "%s: Legacy ISA memory support enabled\n",
+			       hose->dn->full_name);
+
+	/* Configure IO, always 64K starting at 0. We hard wire it to 64K !
+	 * Note also that it -has- to be region index 2 on this HW
+	 */
+	if (hose->io_resource.flags & IORESOURCE_IO)
+		ppc4xx_setup_one_pciex_POM(port, hose, mbase,
+					   hose->io_base_phys, 0,
+					   0x10000, IORESOURCE_IO, 2);
 }
 
 static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port,
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index b3b73ae..01bce37 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
+#include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/bootmem.h>
@@ -38,6 +39,8 @@
 static int qe_sdma_init(void);
 
 static DEFINE_SPINLOCK(qe_lock);
+DEFINE_SPINLOCK(cmxgcr_lock);
+EXPORT_SYMBOL(cmxgcr_lock);
 
 /* QE snum state */
 enum qe_snum_state {
diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c
index 1d78071..ebb442e 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc.c
@@ -18,6 +18,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/stddef.h>
+#include <linux/spinlock.h>
 #include <linux/module.h>
 
 #include <asm/irq.h>
@@ -26,9 +27,6 @@
 #include <asm/qe.h>
 #include <asm/ucc.h>
 
-DEFINE_SPINLOCK(cmxgcr_lock);
-EXPORT_SYMBOL(cmxgcr_lock);
-
 int ucc_set_qe_mux_mii_mng(unsigned int ucc_num)
 {
 	unsigned long flags;
diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile
index 51d9758..9cb03b7 100644
--- a/arch/powerpc/xmon/Makefile
+++ b/arch/powerpc/xmon/Makefile
@@ -4,7 +4,7 @@
 EXTRA_CFLAGS += -mno-minimal-toc
 endif
 
-obj-y			+= xmon.o setjmp.o start.o nonstdio.o
+obj-y			+= xmon.o start.o nonstdio.o
 
 ifdef CONFIG_XMON_DISASSEMBLY
 obj-y			+= ppc-dis.o ppc-opc.o
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 076368c..8dfad7d 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -41,6 +41,7 @@
 #include <asm/spu_priv1.h>
 #include <asm/firmware.h>
 #include <asm/setjmp.h>
+#include <asm/reg.h>
 
 #ifdef CONFIG_PPC64
 #include <asm/hvcall.h>
@@ -159,8 +160,6 @@
 extern void xmon_enter(void);
 extern void xmon_leave(void);
 
-extern void xmon_save_regs(struct pt_regs *);
-
 #ifdef CONFIG_PPC64
 #define REG		"%.16lx"
 #define REGS_PER_LINE	4
@@ -532,7 +531,7 @@
 	struct pt_regs regs;
 
 	if (excp == NULL) {
-		xmon_save_regs(&regs);
+		ppc_save_regs(&regs);
 		excp = &regs;
 	}
 
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 8116a33..8152fef 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -43,6 +43,9 @@
 config GENERIC_TIME
 	def_bool y
 
+config GENERIC_TIME_VSYSCALL
+	def_bool y
+
 config GENERIC_CLOCKEVENTS
 	def_bool y
 
@@ -66,10 +69,15 @@
 	bool
 	default y if KVM
 
+config VIRT_CPU_ACCOUNTING
+	def_bool y
+
 mainmenu "Linux Kernel Configuration"
 
 config S390
 	def_bool y
+	select USE_GENERIC_SMP_HELPERS if SMP
+	select HAVE_FUNCTION_TRACER
 	select HAVE_OPROFILE
 	select HAVE_KPROBES
 	select HAVE_KRETPROBES
@@ -225,6 +233,14 @@
 	  Class (z9 BC). The kernel will be slightly faster but will not
 	  work on older machines such as the z990, z890, z900, and z800.
 
+config MARCH_Z10
+	bool "IBM System z10"
+	help
+	  Select this to enable optimizations for IBM System z10. The
+	  kernel will be slightly faster but will not work on older
+	  machines such as the z990, z890, z900, z800, z9-109, z9-ec
+	  and z9-bc.
+
 endchoice
 
 config PACK_STACK
@@ -343,16 +359,6 @@
 
 	  If unsure, say Y.
 
-config QDIO_DEBUG
-	bool "Extended debugging information"
-	depends on QDIO
-	help
-	  Say Y here to get extended debugging output in
-	    /sys/kernel/debug/s390dbf/qdio...
-	  Warning: this option reduces the performance of the QDIO module.
-
-	  If unsure, say N.
-
 config CHSC_SCH
 	tristate "Support for CHSC subchannels"
 	help
@@ -466,22 +472,9 @@
 	  hypervisor. The ESSA instruction is used to do the states
 	  changes between a page that has content and the unused state.
 
-config VIRT_TIMER
-	bool "Virtual CPU timer support"
-	help
-	  This provides a kernel interface for virtual CPU timers.
-	  Default is disabled.
-
-config VIRT_CPU_ACCOUNTING
-	bool "Base user process accounting on virtual cpu timer"
-	depends on VIRT_TIMER
-	help
-	  Select this option to use CPU timer deltas to do user
-	  process accounting.
-
 config APPLDATA_BASE
 	bool "Linux - VM Monitor Stream, base infrastructure"
-	depends on PROC_FS && VIRT_TIMER=y
+	depends on PROC_FS
 	help
 	  This provides a kernel interface for creating and updating z/VM APPLDATA
 	  monitor records. The monitor records are updated at certain time
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 792a4e7..578c61f 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -34,6 +34,7 @@
 cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900)
 cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990)
 cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109)
+cflags-$(CONFIG_MARCH_Z10) += $(call cc-option,-march=z10)
 
 #KBUILD_IMAGE is necessary for make rpm
 KBUILD_IMAGE	:=arch/s390/boot/image
diff --git a/arch/s390/appldata/appldata.h b/arch/s390/appldata/appldata.h
index 17a2636..f0b23fc 100644
--- a/arch/s390/appldata/appldata.h
+++ b/arch/s390/appldata/appldata.h
@@ -26,10 +26,6 @@
 #define CTL_APPLDATA_NET_SUM	2125
 #define CTL_APPLDATA_PROC	2126
 
-#define P_INFO(x...)	printk(KERN_INFO MY_PRINT_NAME " info: " x)
-#define P_ERROR(x...)	printk(KERN_ERR MY_PRINT_NAME " error: " x)
-#define P_WARNING(x...)	printk(KERN_WARNING MY_PRINT_NAME " status: " x)
-
 struct appldata_ops {
 	struct list_head list;
 	struct ctl_table_header *sysctl_header;
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index a06a47c..27b70d8 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -10,6 +10,9 @@
  * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
+#define KMSG_COMPONENT	"appldata"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -32,7 +35,6 @@
 #include "appldata.h"
 
 
-#define MY_PRINT_NAME	"appldata"		/* for debug messages, etc. */
 #define APPLDATA_CPU_INTERVAL	10000		/* default (CPU) time for
 						   sampling interval in
 						   milliseconds */
@@ -390,8 +392,8 @@
 					(unsigned long) ops->data, ops->size,
 					ops->mod_lvl);
 		if (rc != 0) {
-			P_ERROR("START DIAG 0xDC for %s failed, "
-				"return code: %d\n", ops->name, rc);
+			pr_err("Starting the data collection for %s "
+			       "failed with rc=%d\n", ops->name, rc);
 			module_put(ops->owner);
 		} else
 			ops->active = 1;
@@ -401,8 +403,8 @@
 				(unsigned long) ops->data, ops->size,
 				ops->mod_lvl);
 		if (rc != 0)
-			P_ERROR("STOP DIAG 0xDC for %s failed, "
-				"return code: %d\n", ops->name, rc);
+			pr_err("Stopping the data collection for %s "
+			       "failed with rc=%d\n", ops->name, rc);
 		module_put(ops->owner);
 	}
 	spin_unlock(&appldata_ops_lock);
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
index 3b74655..fa741f8 100644
--- a/arch/s390/appldata/appldata_net_sum.c
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -67,7 +67,6 @@
 	int i;
 	struct appldata_net_sum_data *net_data;
 	struct net_device *dev;
-	struct net_device_stats *stats;
 	unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes, rx_errors,
 			tx_errors, rx_dropped, tx_dropped, collisions;
 
@@ -86,7 +85,8 @@
 	collisions = 0;
 	read_lock(&dev_base_lock);
 	for_each_netdev(&init_net, dev) {
-		stats = dev->get_stats(dev);
+		const struct net_device_stats *stats = dev_get_stats(dev);
+
 		rx_packets += stats->rx_packets;
 		tx_packets += stats->tx_packets;
 		rx_bytes   += stats->rx_bytes;
diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c
index eb44f9f..55c80ffd 100644
--- a/arch/s390/appldata/appldata_os.c
+++ b/arch/s390/appldata/appldata_os.c
@@ -9,6 +9,9 @@
  * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
+#define KMSG_COMPONENT	"appldata"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -22,7 +25,6 @@
 #include "appldata.h"
 
 
-#define MY_PRINT_NAME	"appldata_os"		/* for debug messages, etc. */
 #define LOAD_INT(x) ((x) >> FSHIFT)
 #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
 
@@ -143,21 +145,16 @@
 					   (unsigned long) ops.data, new_size,
 					   ops.mod_lvl);
 			if (rc != 0)
-				P_ERROR("os: START NEW DIAG 0xDC failed, "
-					"return code: %d, new size = %i\n", rc,
-					new_size);
+				pr_err("Starting a new OS data collection "
+				       "failed with rc=%d\n", rc);
 
 			rc = appldata_diag(APPLDATA_RECORD_OS_ID,
 					   APPLDATA_STOP_REC,
 					   (unsigned long) ops.data, ops.size,
 					   ops.mod_lvl);
 			if (rc != 0)
-				P_ERROR("os: STOP OLD DIAG 0xDC failed, "
-					"return code: %d, old size = %i\n", rc,
-					ops.size);
-			else
-				P_INFO("os: old record size = %i stopped\n",
-					ops.size);
+				pr_err("Stopping a faulty OS data "
+				       "collection failed with rc=%d\n", rc);
 		}
 		ops.size = new_size;
 	}
@@ -178,8 +175,8 @@
 	max_size = sizeof(struct appldata_os_data) +
 		   (NR_CPUS * sizeof(struct appldata_os_per_cpu));
 	if (max_size > APPLDATA_MAX_REC_SIZE) {
-		P_ERROR("Max. size of OS record = %i, bigger than maximum "
-			"record size (%i)\n", max_size, APPLDATA_MAX_REC_SIZE);
+		pr_err("Maximum OS record size %i exceeds the maximum "
+		       "record size %i\n", max_size, APPLDATA_MAX_REC_SIZE);
 		rc = -ENOMEM;
 		goto out;
 	}
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
index e33f32b..c42cd89 100644
--- a/arch/s390/crypto/aes_s390.c
+++ b/arch/s390/crypto/aes_s390.c
@@ -17,6 +17,9 @@
  *
  */
 
+#define KMSG_COMPONENT "aes_s390"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <crypto/aes.h>
 #include <crypto/algapi.h>
 #include <linux/err.h>
@@ -169,7 +172,8 @@
 			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
 
 	if (IS_ERR(sctx->fallback.cip)) {
-		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+		pr_err("Allocating AES fallback algorithm %s failed\n",
+		       name);
 		return PTR_ERR(sctx->fallback.blk);
 	}
 
@@ -349,7 +353,8 @@
 			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
 
 	if (IS_ERR(sctx->fallback.blk)) {
-		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+		pr_err("Allocating AES fallback algorithm %s failed\n",
+		       name);
 		return PTR_ERR(sctx->fallback.blk);
 	}
 
@@ -515,9 +520,8 @@
 
 	/* z9 109 and z9 BC/EC only support 128 bit key length */
 	if (keylen_flag == AES_KEYLEN_128)
-		printk(KERN_INFO
-		       "aes_s390: hardware acceleration only available for "
-		       "128 bit keys\n");
+		pr_info("AES hardware acceleration is only available for"
+			" 128-bit keys\n");
 
 	ret = crypto_register_alg(&aes_alg);
 	if (ret)
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c
index b9a1ce1..b1e892a 100644
--- a/arch/s390/hypfs/hypfs_diag.c
+++ b/arch/s390/hypfs/hypfs_diag.c
@@ -3,10 +3,13 @@
  *    Hypervisor filesystem for Linux on s390. Diag 204 and 224
  *    implementation.
  *
- *    Copyright (C) IBM Corp. 2006
+ *    Copyright IBM Corp. 2006, 2008
  *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "hypfs"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -527,13 +530,14 @@
 	int rc;
 
 	if (diag204_probe()) {
-		printk(KERN_ERR "hypfs: diag 204 not working.");
+		pr_err("The hardware system does not support hypfs\n");
 		return -ENODATA;
 	}
 	rc = diag224_get_name_table();
 	if (rc) {
 		diag204_free_buffer();
-		printk(KERN_ERR "hypfs: could not get name table.\n");
+		pr_err("The hardware system does not provide all "
+		       "functions required by hypfs\n");
 	}
 	return rc;
 }
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 3631380..9d4f8e6 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -2,10 +2,13 @@
  *  arch/s390/hypfs/inode.c
  *    Hypervisor filesystem for Linux on s390.
  *
- *    Copyright (C) IBM Corp. 2006
+ *    Copyright IBM Corp. 2006, 2008
  *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "hypfs"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -200,7 +203,7 @@
 	else
 		rc = hypfs_diag_create_files(sb, sb->s_root);
 	if (rc) {
-		printk(KERN_ERR "hypfs: Update failed\n");
+		pr_err("Updating the hypfs tree failed\n");
 		hypfs_delete_tree(sb->s_root);
 		goto out;
 	}
@@ -252,8 +255,7 @@
 			break;
 		case opt_err:
 		default:
-			printk(KERN_ERR "hypfs: Unrecognized mount option "
-			       "\"%s\" or missing value\n", str);
+			pr_err("%s is not a valid mount option\n", str);
 			return -EINVAL;
 		}
 	}
@@ -280,8 +282,8 @@
 	if (!sbi)
 		return -ENOMEM;
 	mutex_init(&sbi->lock);
-	sbi->uid = current->uid;
-	sbi->gid = current->gid;
+	sbi->uid = current_uid();
+	sbi->gid = current_gid();
 	sb->s_fs_info = sbi;
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -317,7 +319,7 @@
 	}
 	hypfs_update_update(sb);
 	sb->s_root = root_dentry;
-	printk(KERN_INFO "hypfs: Hypervisor filesystem mounted\n");
+	pr_info("Hypervisor filesystem mounted\n");
 	return 0;
 
 err_tree:
@@ -513,7 +515,7 @@
 	if (!MACHINE_IS_VM)
 		hypfs_diag_exit();
 fail_diag:
-	printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
+	pr_err("Initialization of hypfs failed with rc=%i\n", rc);
 	return rc;
 }
 
diff --git a/arch/s390/include/asm/auxvec.h b/arch/s390/include/asm/auxvec.h
index 0d34072..a1f153e 100644
--- a/arch/s390/include/asm/auxvec.h
+++ b/arch/s390/include/asm/auxvec.h
@@ -1,4 +1,6 @@
 #ifndef __ASMS390_AUXVEC_H
 #define __ASMS390_AUXVEC_H
 
+#define AT_SYSINFO_EHDR		33
+
 #endif
diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h
index 384e362..7efd0ab 100644
--- a/arch/s390/include/asm/bug.h
+++ b/arch/s390/include/asm/bug.h
@@ -47,7 +47,10 @@
 
 #endif /* CONFIG_DEBUG_BUGVERBOSE */
 
-#define BUG()	__EMIT_BUG(0)
+#define BUG() do {					\
+	__EMIT_BUG(0);					\
+	for (;;);					\
+} while (0)
 
 #define WARN_ON(x) ({					\
 	int __ret_warn_on = !!(x);			\
diff --git a/arch/s390/include/asm/byteorder.h b/arch/s390/include/asm/byteorder.h
index 1fe2492..8bcf277 100644
--- a/arch/s390/include/asm/byteorder.h
+++ b/arch/s390/include/asm/byteorder.h
@@ -11,32 +11,39 @@
 
 #include <asm/types.h>
 
-#ifdef __GNUC__
+#define __BIG_ENDIAN
+
+#ifndef __s390x__
+# define __SWAB_64_THRU_32__
+#endif
 
 #ifdef __s390x__
-static inline __u64 ___arch__swab64p(const __u64 *x)
+static inline __u64 __arch_swab64p(const __u64 *x)
 {
 	__u64 result;
 
 	asm volatile("lrvg %0,%1" : "=d" (result) : "m" (*x));
 	return result;
 }
+#define __arch_swab64p __arch_swab64p
 
-static inline __u64 ___arch__swab64(__u64 x)
+static inline __u64 __arch_swab64(__u64 x)
 {
 	__u64 result;
 
 	asm volatile("lrvgr %0,%1" : "=d" (result) : "d" (x));
 	return result;
 }
+#define __arch_swab64 __arch_swab64
 
-static inline void ___arch__swab64s(__u64 *x)
+static inline void __arch_swab64s(__u64 *x)
 {
-	*x = ___arch__swab64p(x);
+	*x = __arch_swab64p(x);
 }
+#define __arch_swab64s __arch_swab64s
 #endif /* __s390x__ */
 
-static inline __u32 ___arch__swab32p(const __u32 *x)
+static inline __u32 __arch_swab32p(const __u32 *x)
 {
 	__u32 result;
 	
@@ -53,25 +60,20 @@
 #endif /* __s390x__ */
 	return result;
 }
+#define __arch_swab32p __arch_swab32p
 
-static inline __u32 ___arch__swab32(__u32 x)
+#ifdef __s390x__
+static inline __u32 __arch_swab32(__u32 x)
 {
-#ifndef __s390x__
-	return ___arch__swab32p(&x);
-#else /* __s390x__ */
 	__u32 result;
 	
 	asm volatile("lrvr  %0,%1" : "=d" (result) : "d" (x));
 	return result;
+}
+#define __arch_swab32 __arch_swab32
 #endif /* __s390x__ */
-}
 
-static __inline__ void ___arch__swab32s(__u32 *x)
-{
-	*x = ___arch__swab32p(x);
-}
-
-static __inline__ __u16 ___arch__swab16p(const __u16 *x)
+static inline __u16 __arch_swab16p(const __u16 *x)
 {
 	__u16 result;
 	
@@ -86,40 +88,8 @@
 #endif /* __s390x__ */
 	return result;
 }
+#define __arch_swab16p __arch_swab16p
 
-static __inline__ __u16 ___arch__swab16(__u16 x)
-{
-	return ___arch__swab16p(&x);
-}
-
-static __inline__ void ___arch__swab16s(__u16 *x)
-{
-	*x = ___arch__swab16p(x);
-}
-
-#ifdef __s390x__
-#define __arch__swab64(x) ___arch__swab64(x)
-#define __arch__swab64p(x) ___arch__swab64p(x)
-#define __arch__swab64s(x) ___arch__swab64s(x)
-#endif /* __s390x__ */
-#define __arch__swab32(x) ___arch__swab32(x)
-#define __arch__swab16(x) ___arch__swab16(x)
-#define __arch__swab32p(x) ___arch__swab32p(x)
-#define __arch__swab16p(x) ___arch__swab16p(x)
-#define __arch__swab32s(x) ___arch__swab32s(x)
-#define __arch__swab16s(x) ___arch__swab16s(x)
-
-#ifndef __s390x__
-#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-#  define __BYTEORDER_HAS_U64__
-#  define __SWAB_64_THRU_32__
-#endif
-#else /* __s390x__ */
-#define __BYTEORDER_HAS_U64__
-#endif /* __s390x__ */
-
-#endif /* __GNUC__ */
-
-#include <linux/byteorder/big_endian.h>
+#include <linux/byteorder.h>
 
 #endif /* _S390_BYTEORDER_H */
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 261785a..d480f39 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -120,6 +120,10 @@
 #include <asm/system.h>		/* for save_access_regs */
 #include <asm/mmu_context.h>
 
+#include <asm/vdso.h>
+
+extern unsigned int vdso_enabled;
+
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
@@ -191,4 +195,16 @@
 	current->mm->context.noexec == 0;		\
 })
 
+#define ARCH_DLINFO							    \
+do {									    \
+	if (vdso_enabled)						    \
+		NEW_AUX_ENT(AT_SYSINFO_EHDR,				    \
+			    (unsigned long)current->mm->context.vdso_base); \
+} while (0)
+
+struct linux_binprm;
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+int arch_setup_additional_pages(struct linux_binprm *, int);
+
 #endif
diff --git a/arch/s390/include/asm/fcx.h b/arch/s390/include/asm/fcx.h
index 8be1f3a..ef61709 100644
--- a/arch/s390/include/asm/fcx.h
+++ b/arch/s390/include/asm/fcx.h
@@ -248,8 +248,8 @@
 #define TCCB_MAX_SIZE		(sizeof(struct tccb_tcah) + \
 				 TCCB_MAX_DCW * sizeof(struct dcw) + \
 				 sizeof(struct tccb_tcat))
-#define TCCB_SAC_DEFAULT	0xf901
-#define TCCB_SAC_INTRG		0xf902
+#define TCCB_SAC_DEFAULT	0x1ffe
+#define TCCB_SAC_INTRG		0x1fff
 
 /**
  * struct tccb_tcah - Transport-Command-Area Header (TCAH)
diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h
new file mode 100644
index 0000000..5a5bc75
--- /dev/null
+++ b/arch/s390/include/asm/ftrace.h
@@ -0,0 +1,8 @@
+#ifndef _ASM_S390_FTRACE_H
+#define _ASM_S390_FTRACE_H
+
+#ifndef __ASSEMBLY__
+extern void _mcount(void);
+#endif
+
+#endif /* _ASM_S390_FTRACE_H */
diff --git a/arch/s390/include/asm/isc.h b/arch/s390/include/asm/isc.h
index 34bb891..1420a11 100644
--- a/arch/s390/include/asm/isc.h
+++ b/arch/s390/include/asm/isc.h
@@ -17,6 +17,7 @@
 #define CHSC_SCH_ISC 7			/* CHSC subchannels */
 /* Adapter interrupts. */
 #define QDIO_AIRQ_ISC IO_SCH_ISC	/* I/O subchannel in qdio mode */
+#define AP_ISC 6			/* adjunct processor (crypto) devices */
 
 /* Functions for registration of I/O interruption subclasses */
 void isc_register(unsigned int isc);
diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h
index d2b4ff8..3b59216 100644
--- a/arch/s390/include/asm/mmu.h
+++ b/arch/s390/include/asm/mmu.h
@@ -6,6 +6,7 @@
 	struct list_head pgtable_list;
 	unsigned long asce_bits;
 	unsigned long asce_limit;
+	unsigned long vdso_base;
 	int noexec;
 	int has_pgste;	 /* The mmu context has extended page tables */
 	int alloc_pgste; /* cloned contexts will have extended page tables */
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 991ba93..32e8f6a 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -152,4 +152,6 @@
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
+#define __HAVE_ARCH_GATE_AREA 1
+
 #endif /* _S390_PAGE_H */
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index f5b2bf3..b2658b9 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -28,6 +28,8 @@
 
 static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
 {
+	typedef struct { char _[n]; } addrtype;
+
 	*s = val;
 	n = (n / 256) - 1;
 	asm volatile(
@@ -39,7 +41,8 @@
 		"0:	mvc	256(256,%0),0(%0)\n"
 		"	la	%0,256(%0)\n"
 		"	brct	%1,0b\n"
-		: "+a" (s), "+d" (n));
+		: "+a" (s), "+d" (n), "=m" (*(addrtype *) s)
+		: "m" (*(addrtype *) s));
 }
 
 static inline void crst_table_init(unsigned long *crst, unsigned long entry)
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 4af80af..066b995 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -13,6 +13,7 @@
 #ifndef __ASM_S390_PROCESSOR_H
 #define __ASM_S390_PROCESSOR_H
 
+#include <linux/linkage.h>
 #include <asm/ptrace.h>
 
 #ifdef __KERNEL__
@@ -258,7 +259,7 @@
  * Function to drop a processor into disabled wait state
  */
 
-static inline void disabled_wait(unsigned long code)
+static inline void ATTRIB_NORET disabled_wait(unsigned long code)
 {
         unsigned long ctl_buf;
         psw_t dw_psw;
@@ -322,6 +323,7 @@
 		: "=m" (ctl_buf)
 		: "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc", "0");
 #endif /* __s390x__ */
+	while (1);
 }
 
 /*
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h
index 4734c3f..27fc174 100644
--- a/arch/s390/include/asm/qdio.h
+++ b/arch/s390/include/asm/qdio.h
@@ -373,16 +373,16 @@
 #define QDIO_FLAG_SYNC_OUTPUT		0x02
 #define QDIO_FLAG_PCI_OUT		0x10
 
-extern int qdio_initialize(struct qdio_initialize *init_data);
-extern int qdio_allocate(struct qdio_initialize *init_data);
-extern int qdio_establish(struct qdio_initialize *init_data);
+extern int qdio_initialize(struct qdio_initialize *);
+extern int qdio_allocate(struct qdio_initialize *);
+extern int qdio_establish(struct qdio_initialize *);
 extern int qdio_activate(struct ccw_device *);
 
-extern int do_QDIO(struct ccw_device*, unsigned int flags,
-		   int q_nr, int qidx, int count);
-extern int qdio_cleanup(struct ccw_device*, int how);
-extern int qdio_shutdown(struct ccw_device*, int how);
+extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
+		   int q_nr, int bufnr, int count);
+extern int qdio_cleanup(struct ccw_device*, int);
+extern int qdio_shutdown(struct ccw_device*, int);
 extern int qdio_free(struct ccw_device *);
-extern struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev);
+extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*);
 
 #endif /* __QDIO_H__ */
diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h
index e16d56f..ec403d4 100644
--- a/arch/s390/include/asm/sigp.h
+++ b/arch/s390/include/asm/sigp.h
@@ -61,6 +61,7 @@
 {
 	ec_schedule=0,
 	ec_call_function,
+	ec_call_function_single,
 	ec_bit_last
 } ec_bit_sig;
 
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h
index ae89cf2..024b91e 100644
--- a/arch/s390/include/asm/smp.h
+++ b/arch/s390/include/asm/smp.h
@@ -91,8 +91,9 @@
 extern struct mutex smp_cpu_state_mutex;
 extern int smp_cpu_polarization[];
 
-extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *),
-	void *info, int wait);
+extern void arch_send_call_function_single_ipi(int cpu);
+extern void arch_send_call_function_ipi(cpumask_t mask);
+
 #endif
 
 #ifndef CONFIG_SMP
diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h
index 79d0134..ad93212 100644
--- a/arch/s390/include/asm/sysinfo.h
+++ b/arch/s390/include/asm/sysinfo.h
@@ -118,4 +118,15 @@
 	return r0;
 }
 
+/*
+ * Service level reporting interface.
+ */
+struct service_level {
+	struct list_head list;
+	void (*seq_print)(struct seq_file *, struct service_level *);
+};
+
+int register_service_level(struct service_level *);
+int unregister_service_level(struct service_level *);
+
 #endif /* __ASM_S390_SYSINFO_H */
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h
index 819e7d9..024ef42 100644
--- a/arch/s390/include/asm/system.h
+++ b/arch/s390/include/asm/system.h
@@ -12,6 +12,7 @@
 #define __ASM_SYSTEM_H
 
 #include <linux/kernel.h>
+#include <linux/errno.h>
 #include <asm/types.h>
 #include <asm/ptrace.h>
 #include <asm/setup.h>
@@ -98,13 +99,9 @@
 	prev = __switch_to(prev,next);					     \
 } while (0)
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 extern void account_vtime(struct task_struct *);
 extern void account_tick_vtime(struct task_struct *);
 extern void account_system_vtime(struct task_struct *);
-#else
-#define account_vtime(x) do { /* empty */ } while (0)
-#endif
 
 #ifdef CONFIG_PFAULT
 extern void pfault_irq_init(void);
@@ -413,8 +410,6 @@
 #define local_mcck_enable()  __set_psw_mask(psw_kernel_bits)
 #define local_mcck_disable() __set_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK)
 
-int stfle(unsigned long long *list, int doublewords);
-
 #ifdef CONFIG_SMP
 
 extern void smp_ctl_set_bit(int cr, int bit);
@@ -438,6 +433,23 @@
 	return S390_lowcore.stfl_fac_list;
 }
 
+static inline int __stfle(unsigned long long *list, int doublewords)
+{
+	typedef struct { unsigned long long _[doublewords]; } addrtype;
+	register unsigned long __nr asm("0") = doublewords - 1;
+
+	asm volatile(".insn s,0xb2b00000,%0" /* stfle */
+		     : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
+	return __nr + 1;
+}
+
+static inline int stfle(unsigned long long *list, int doublewords)
+{
+	if (!(stfl() & (1UL << 24)))
+		return -EOPNOTSUPP;
+	return __stfle(list, doublewords);
+}
+
 static inline unsigned short stap(void)
 {
 	unsigned short cpu_address;
diff --git a/arch/s390/include/asm/timer.h b/arch/s390/include/asm/timer.h
index d98d79e..61705d60 100644
--- a/arch/s390/include/asm/timer.h
+++ b/arch/s390/include/asm/timer.h
@@ -48,18 +48,9 @@
 extern void init_cpu_vtimer(void);
 extern void vtime_init(void);
 
-#ifdef CONFIG_VIRT_TIMER
-
 extern void vtime_start_cpu_timer(void);
 extern void vtime_stop_cpu_timer(void);
 
-#else
-
-static inline void vtime_start_cpu_timer(void) { }
-static inline void vtime_stop_cpu_timer(void) { }
-
-#endif /* CONFIG_VIRT_TIMER */
-
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_S390_TIMER_H */
diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h
new file mode 100644
index 0000000..a44f4fe
--- /dev/null
+++ b/arch/s390/include/asm/vdso.h
@@ -0,0 +1,39 @@
+#ifndef __S390_VDSO_H__
+#define __S390_VDSO_H__
+
+#ifdef __KERNEL__
+
+/* Default link addresses for the vDSOs */
+#define VDSO32_LBASE	0
+#define VDSO64_LBASE	0
+
+#define VDSO_VERSION_STRING	LINUX_2.6.26
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Note about this structure:
+ *
+ * NEVER USE THIS IN USERSPACE CODE DIRECTLY. The layout of this
+ * structure is supposed to be known only to the function in the vdso
+ * itself and may change without notice.
+ */
+
+struct vdso_data {
+	__u64 tb_update_count;		/* Timebase atomicity ctr	0x00 */
+	__u64 xtime_tod_stamp;		/* TOD clock for xtime		0x08 */
+	__u64 xtime_clock_sec;		/* Kernel time			0x10 */
+	__u64 xtime_clock_nsec;		/*				0x18 */
+	__u64 wtom_clock_sec;		/* Wall to monotonic clock	0x20 */
+	__u64 wtom_clock_nsec;		/*				0x28 */
+	__u32 tz_minuteswest;		/* Minutes west of Greenwich	0x30 */
+	__u32 tz_dsttime;		/* Type of dst correction	0x34 */
+};
+
+extern struct vdso_data *vdso_data;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* __S390_VDSO_H__ */
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 50f657e..3edc6c6 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -2,6 +2,11 @@
 # Makefile for the linux kernel.
 #
 
+ifdef CONFIG_FUNCTION_TRACER
+# Do not trace early boot code
+CFLAGS_REMOVE_early.o = -pg
+endif
+
 #
 # Passing null pointers is ok for smp code, since we access the lowcore here.
 #
@@ -12,9 +17,10 @@
 #
 CFLAGS_ptrace.o		+= -DUTS_MACHINE='"$(UTS_MACHINE)"'
 
-obj-y	:=  bitmap.o traps.o time.o process.o base.o early.o \
-            setup.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
+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
 
 obj-y	+= $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y	+= $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
@@ -30,12 +36,16 @@
 					compat_wrapper.o compat_exec_domain.o \
 					$(compat-obj-y)
 
-obj-$(CONFIG_VIRT_TIMER)	+= vtime.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
+obj-$(CONFIG_FUNCTION_TRACER)	+= mcount.o
 
 # Kexec part
 S390_KEXEC_OBJS := machine_kexec.o crash.o
 S390_KEXEC_OBJS += $(if $(CONFIG_64BIT),relocate_kernel64.o,relocate_kernel.o)
 obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)
 
+# vdso
+obj-$(CONFIG_64BIT)		+= vdso64/
+obj-$(CONFIG_32BIT)		+= vdso32/
+obj-$(CONFIG_COMPAT)		+= vdso32/
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 3d144e6..e641f60 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -6,6 +6,7 @@
 
 #include <linux/sched.h>
 #include <linux/kbuild.h>
+#include <asm/vdso.h>
 
 int main(void)
 {
@@ -38,5 +39,19 @@
 	DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
 	DEFINE(__SF_GPRS, offsetof(struct stack_frame, gprs));
 	DEFINE(__SF_EMPTY, offsetof(struct stack_frame, empty1));
+	BLANK();
+	/* timeval/timezone offsets for use by vdso */
+	DEFINE(__VDSO_UPD_COUNT, offsetof(struct vdso_data, tb_update_count));
+	DEFINE(__VDSO_XTIME_STAMP, offsetof(struct vdso_data, xtime_tod_stamp));
+	DEFINE(__VDSO_XTIME_SEC, offsetof(struct vdso_data, xtime_clock_sec));
+	DEFINE(__VDSO_XTIME_NSEC, offsetof(struct vdso_data, xtime_clock_nsec));
+	DEFINE(__VDSO_WTOM_SEC, offsetof(struct vdso_data, wtom_clock_sec));
+	DEFINE(__VDSO_WTOM_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
+	DEFINE(__VDSO_TIMEZONE, offsetof(struct vdso_data, tz_minuteswest));
+	/* constants used by the vdso */
+	DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
+	DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
+	DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC);
+
 	return 0;
 }
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 4646382..6cc87d8 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -148,9 +148,9 @@
 {
 	int retval;
 
-	if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
-	    !(retval = put_user(high2lowuid(current->euid), euid)))
-		retval = put_user(high2lowuid(current->suid), suid);
+	if (!(retval = put_user(high2lowuid(current->cred->uid), ruid)) &&
+	    !(retval = put_user(high2lowuid(current->cred->euid), euid)))
+		retval = put_user(high2lowuid(current->cred->suid), suid);
 
 	return retval;
 }
@@ -165,9 +165,9 @@
 {
 	int retval;
 
-	if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
-	    !(retval = put_user(high2lowgid(current->egid), egid)))
-		retval = put_user(high2lowgid(current->sgid), sgid);
+	if (!(retval = put_user(high2lowgid(current->cred->gid), rgid)) &&
+	    !(retval = put_user(high2lowgid(current->cred->egid), egid)))
+		retval = put_user(high2lowgid(current->cred->sgid), sgid);
 
 	return retval;
 }
@@ -217,20 +217,20 @@
 	if (gidsetsize < 0)
 		return -EINVAL;
 
-	get_group_info(current->group_info);
-	i = current->group_info->ngroups;
+	get_group_info(current->cred->group_info);
+	i = current->cred->group_info->ngroups;
 	if (gidsetsize) {
 		if (i > gidsetsize) {
 			i = -EINVAL;
 			goto out;
 		}
-		if (groups16_to_user(grouplist, current->group_info)) {
+		if (groups16_to_user(grouplist, current->cred->group_info)) {
 			i = -EFAULT;
 			goto out;
 		}
 	}
 out:
-	put_group_info(current->group_info);
+	put_group_info(current->cred->group_info);
 	return i;
 }
 
@@ -261,22 +261,22 @@
 
 asmlinkage long sys32_getuid16(void)
 {
-	return high2lowuid(current->uid);
+	return high2lowuid(current->cred->uid);
 }
 
 asmlinkage long sys32_geteuid16(void)
 {
-	return high2lowuid(current->euid);
+	return high2lowuid(current->cred->euid);
 }
 
 asmlinkage long sys32_getgid16(void)
 {
-	return high2lowgid(current->gid);
+	return high2lowgid(current->cred->gid);
 }
 
 asmlinkage long sys32_getegid16(void)
 {
-	return high2lowgid(current->egid);
+	return high2lowgid(current->cred->egid);
 }
 
 /*
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
index d8c1131..3e8b881 100644
--- a/arch/s390/kernel/cpcmd.c
+++ b/arch/s390/kernel/cpcmd.c
@@ -7,6 +7,9 @@
  *               Christian Borntraeger (cborntra@de.ibm.com),
  */
 
+#define KMSG_COMPONENT "cpcmd"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -104,8 +107,8 @@
 			(((unsigned long)response + rlen) >> 31)) {
 		lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
 		if (!lowbuf) {
-			printk(KERN_WARNING
-				"cpcmd: could not allocate response buffer\n");
+			pr_warning("The cpcmd kernel function failed to "
+				   "allocate a response buffer\n");
 			return -ENOMEM;
 		}
 		spin_lock_irqsave(&cpcmd_lock, flags);
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index d80fcd4..ba03fc0 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -10,6 +10,9 @@
  *    Bugreports to: <Linux390@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "s390dbf"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -388,7 +391,7 @@
 		debug_info_free(rc);
 	} while (1);
 
-        if(!rc || (mode == NO_AREAS))
+	if (mode == NO_AREAS)
                 goto out;
 
         for(i = 0; i < in->nr_areas; i++){
@@ -693,8 +696,8 @@
 	/* Since debugfs currently does not support uid/gid other than root, */
 	/* we do not allow gid/uid != 0 until we get support for that. */
 	if ((uid != 0) || (gid != 0))
-		printk(KERN_WARNING "debug: Warning - Currently only uid/gid "
-		       "= 0 are supported. Using root as owner now!");
+		pr_warning("Root becomes the owner of all s390dbf files "
+			   "in sysfs\n");
 	if (!initialized)
 		BUG();
 	mutex_lock(&debug_mutex);
@@ -709,7 +712,7 @@
 	debug_register_view(rc, &debug_pages_view);
 out:
         if (!rc){
-		printk(KERN_ERR "debug: debug_register failed for %s\n",name);
+		pr_err("Registering debug feature %s failed\n", name);
         }
 	mutex_unlock(&debug_mutex);
 	return rc;
@@ -763,8 +766,8 @@
 	if(pages_per_area > 0){
 		new_areas = debug_areas_alloc(pages_per_area, nr_areas);
 		if(!new_areas) {
-			printk(KERN_WARNING "debug: could not allocate memory "\
-					 "for pagenumber: %i\n",pages_per_area);
+			pr_info("Allocating memory for %i pages failed\n",
+				pages_per_area);
 			rc = -ENOMEM;
 			goto out;
 		}
@@ -780,8 +783,7 @@
 	memset(id->active_entries,0,sizeof(int)*id->nr_areas);
 	memset(id->active_pages, 0, sizeof(int)*id->nr_areas);
 	spin_unlock_irqrestore(&id->lock,flags);
-	printk(KERN_INFO "debug: %s: set new size (%i pages)\n"\
-			 ,id->name, pages_per_area);
+	pr_info("%s: set new size (%i pages)\n" ,id->name, pages_per_area);
 out:
 	return rc;
 }
@@ -800,10 +802,9 @@
 	spin_lock_irqsave(&id->lock,flags);
         if(new_level == DEBUG_OFF_LEVEL){
                 id->level = DEBUG_OFF_LEVEL;
-                printk(KERN_INFO "debug: %s: switched off\n",id->name);
+		pr_info("%s: switched off\n",id->name);
         } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
-                printk(KERN_INFO
-                        "debug: %s: level %i is out of range (%i - %i)\n",
+		pr_info("%s: level %i is out of range (%i - %i)\n",
                         id->name, new_level, 0, DEBUG_MAX_LEVEL);
         } else {
                 id->level = new_level;
@@ -1108,8 +1109,8 @@
 	pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry,
 				id , &debug_file_ops);
 	if (!pde){
-		printk(KERN_WARNING "debug: debugfs_create_file() failed!"\
-			" Cannot register view %s/%s\n", id->name,view->name);
+		pr_err("Registering view %s/%s failed due to out of "
+		       "memory\n", id->name,view->name);
 		rc = -1;
 		goto out;
 	}
@@ -1119,10 +1120,8 @@
 			break;
 	}
 	if (i == DEBUG_MAX_VIEWS) {
-		printk(KERN_WARNING "debug: cannot register view %s/%s\n",
-			id->name,view->name);
-		printk(KERN_WARNING 
-			"debug: maximum number of views reached (%i)!\n", i);
+		pr_err("Registering view %s/%s would exceed the maximum "
+		       "number of views %i\n", id->name, view->name, i);
 		debugfs_remove(pde);
 		rc = -1;
 	} else {
@@ -1303,7 +1302,8 @@
 		new_level = debug_get_uint(str);
 	}
 	if(new_level < 0) {
-		printk(KERN_INFO "debug: level `%s` is not valid\n", str);
+		pr_warning("%s is not a valid level for a debug "
+			   "feature\n", str);
 		rc = -EINVAL;
 	} else {
 		debug_set_level(id, new_level);
@@ -1380,7 +1380,8 @@
                 goto out;
         }
 
-        printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]);
+	pr_info("Flushing debug data failed because %c is not a valid "
+		 "area\n", input_buf[0]);
 
 out:
         *offset += user_len;
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 198ea18..55de521 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -109,13 +109,6 @@
  *    R15 - kernel stack pointer
  */
 
-	.macro	STORE_TIMER lc_offset
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-	stpt	\lc_offset
-#endif
-	.endm
-
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	.macro	UPDATE_VTIME lc_from,lc_to,lc_sum
 	lm	%r10,%r11,\lc_from
 	sl	%r10,\lc_to
@@ -128,7 +121,6 @@
 	al	%r10,BASED(.Lc_1)
 1:	stm	%r10,%r11,\lc_sum
 	.endm
-#endif
 
 	.macro	SAVE_ALL_BASE savearea
 	stm	%r12,%r15,\savearea
@@ -198,7 +190,7 @@
 	ni	\psworg+1,0xfd		# clear wait state bit
 	.endif
 	lm	%r0,%r15,SP_R0(%r15)	# load gprs 0-15 of user
-	STORE_TIMER __LC_EXIT_TIMER
+	stpt	__LC_EXIT_TIMER
 	lpsw	\psworg			# back to caller
 	.endm
 
@@ -247,20 +239,18 @@
 
 	.globl	system_call
 system_call:
-	STORE_TIMER __LC_SYNC_ENTER_TIMER
+	stpt	__LC_SYNC_ENTER_TIMER
 sysc_saveall:
 	SAVE_ALL_BASE __LC_SAVE_AREA
 	SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 	lh	%r7,0x8a	  # get svc number from lowcore
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 sysc_vtime:
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
 sysc_stime:
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 sysc_update:
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
-#endif
 sysc_do_svc:
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	ltr	%r7,%r7			# test for svc 0
@@ -436,7 +426,7 @@
 	basr	%r14,%r1
 	TRACE_IRQS_ON
 	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
-	b	BASED(sysc_return)
+	b	BASED(sysc_tracenogo)
 
 #
 # kernel_execve function needs to deal with pt_regs that is not
@@ -490,20 +480,18 @@
  * we just ignore the PER event (FIXME: is there anything we have to do
  * for LPSW?).
  */
-	STORE_TIMER __LC_SYNC_ENTER_TIMER
+	stpt	__LC_SYNC_ENTER_TIMER
 	SAVE_ALL_BASE __LC_SAVE_AREA
 	tm	__LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
 	bnz	BASED(pgm_per)		# got per exception -> special case
 	SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
 	bz	BASED(pgm_no_vtime)
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime:
-#endif
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	TRACE_IRQS_OFF
 	l	%r3,__LC_PGM_ILC	# load program interruption code
@@ -536,14 +524,12 @@
 pgm_per_std:
 	SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
 	bz	BASED(pgm_no_vtime2)
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime2:
-#endif
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	TRACE_IRQS_OFF
 	l	%r1,__TI_task(%r9)
@@ -565,11 +551,9 @@
 pgm_svcper:
 	SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
-#endif
 	lh	%r7,0x8a		# get svc number from lowcore
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	TRACE_IRQS_OFF
@@ -599,19 +583,17 @@
 
 	.globl io_int_handler
 io_int_handler:
-	STORE_TIMER __LC_ASYNC_ENTER_TIMER
+	stpt	__LC_ASYNC_ENTER_TIMER
 	stck	__LC_INT_CLOCK
 	SAVE_ALL_BASE __LC_SAVE_AREA+16
 	SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
 	CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
 	bz	BASED(io_no_vtime)
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
 io_no_vtime:
-#endif
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	TRACE_IRQS_OFF
 	l	%r1,BASED(.Ldo_IRQ)	# load address of do_IRQ
@@ -741,19 +723,17 @@
 
 	.globl	ext_int_handler
 ext_int_handler:
-	STORE_TIMER __LC_ASYNC_ENTER_TIMER
+	stpt	__LC_ASYNC_ENTER_TIMER
 	stck	__LC_INT_CLOCK
 	SAVE_ALL_BASE __LC_SAVE_AREA+16
 	SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
 	CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
 	bz	BASED(ext_no_vtime)
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
 ext_no_vtime:
-#endif
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	TRACE_IRQS_OFF
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
@@ -776,7 +756,6 @@
 	la	%r12,__LC_MCK_OLD_PSW
 	tm	__LC_MCCK_CODE,0x80	# system damage?
 	bo	BASED(mcck_int_main)	# yes -> rest of mcck code invalid
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	mvc	__LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER
 	mvc	__LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA
 	tm	__LC_MCCK_CODE+5,0x02	# stored cpu timer value valid?
@@ -793,9 +772,7 @@
 	la	%r14,__LC_LAST_UPDATE_TIMER
 0:	spt	0(%r14)
 	mvc	__LC_ASYNC_ENTER_TIMER(8),0(%r14)
-1:
-#endif
-	tm	__LC_MCCK_CODE+2,0x09	# mwp + ia of old psw valid?
+1:	tm	__LC_MCCK_CODE+2,0x09	# mwp + ia of old psw valid?
 	bno	BASED(mcck_int_main)	# no -> skip cleanup critical
 	tm	__LC_MCK_OLD_PSW+1,0x01	# test problem state bit
 	bnz	BASED(mcck_int_main)	# from user -> load async stack
@@ -812,7 +789,6 @@
 	be	BASED(0f)
 	l	%r15,__LC_PANIC_STACK	# load panic stack
 0:	CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	tm	__LC_MCCK_CODE+2,0x08	# mwp of old psw valid?
 	bno	BASED(mcck_no_vtime)	# no -> skip cleanup critical
 	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
@@ -821,7 +797,6 @@
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
 mcck_no_vtime:
-#endif
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	l	%r1,BASED(.Ls390_mcck)
@@ -843,16 +818,13 @@
 mcck_return:
 	mvc	__LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW
 	ni	__LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	mvc	__LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+52
 	tm	__LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
 	bno	BASED(0f)
 	lm	%r0,%r15,SP_R0(%r15)	# load gprs 0-15
 	stpt	__LC_EXIT_TIMER
 	lpsw	__LC_RETURN_MCCK_PSW	# back to caller
-0:
-#endif
-	lm	%r0,%r15,SP_R0(%r15)	# load gprs 0-15
+0:	lm	%r0,%r15,SP_R0(%r15)	# load gprs 0-15
 	lpsw	__LC_RETURN_MCCK_PSW	# back to caller
 
 	RESTORE_ALL __LC_RETURN_MCCK_PSW,0
@@ -976,13 +948,11 @@
 	b	BASED(1f)
 0:	la	%r12,__LC_SAVE_AREA+32
 1:
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	clc	__LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4)
 	bh	BASED(0f)
 	mvc	__LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER
 0:	clc	__LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8)
 	bhe	BASED(cleanup_vtime)
-#endif
 	clc	__LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn)
 	bh	BASED(0f)
 	mvc	__LC_SAVE_AREA(16),0(%r12)
@@ -993,7 +963,6 @@
 	l	%r12,__LC_SAVE_AREA+48	# argh
 	st	%r15,12(%r12)
 	lh	%r7,0x8a
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 cleanup_vtime:
 	clc	__LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12)
 	bhe	BASED(cleanup_stime)
@@ -1004,18 +973,15 @@
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 cleanup_update:
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
-#endif
 	mvc	__LC_RETURN_PSW+4(4),BASED(cleanup_table_system_call+4)
 	la	%r12,__LC_RETURN_PSW
 	br	%r14
 cleanup_system_call_insn:
 	.long	sysc_saveall + 0x80000000
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	.long	system_call + 0x80000000
 	.long	sysc_vtime + 0x80000000
 	.long	sysc_stime + 0x80000000
 	.long	sysc_update + 0x80000000
-#endif
 
 cleanup_sysc_return:
 	mvc	__LC_RETURN_PSW(4),0(%r12)
@@ -1026,11 +992,9 @@
 cleanup_sysc_leave:
 	clc	4(4,%r12),BASED(cleanup_sysc_leave_insn)
 	be	BASED(2f)
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	mvc	__LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
 	clc	4(4,%r12),BASED(cleanup_sysc_leave_insn+4)
 	be	BASED(2f)
-#endif
 	mvc	__LC_RETURN_PSW(8),SP_PSW(%r15)
 	c	%r12,BASED(.Lmck_old_psw)
 	bne	BASED(0f)
@@ -1043,9 +1007,7 @@
 	br	%r14
 cleanup_sysc_leave_insn:
 	.long	sysc_done - 4 + 0x80000000
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	.long	sysc_done - 8 + 0x80000000
-#endif
 
 cleanup_io_return:
 	mvc	__LC_RETURN_PSW(4),0(%r12)
@@ -1056,11 +1018,9 @@
 cleanup_io_leave:
 	clc	4(4,%r12),BASED(cleanup_io_leave_insn)
 	be	BASED(2f)
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	mvc	__LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
 	clc	4(4,%r12),BASED(cleanup_io_leave_insn+4)
 	be	BASED(2f)
-#endif
 	mvc	__LC_RETURN_PSW(8),SP_PSW(%r15)
 	c	%r12,BASED(.Lmck_old_psw)
 	bne	BASED(0f)
@@ -1073,9 +1033,7 @@
 	br	%r14
 cleanup_io_leave_insn:
 	.long	io_done - 4 + 0x80000000
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	.long	io_done - 8 + 0x80000000
-#endif
 
 /*
  * Integer constants
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 89c121a..16bb4fd 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -96,20 +96,12 @@
 #define LOCKDEP_SYS_EXIT
 #endif
 
-	.macro	STORE_TIMER lc_offset
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-	stpt	\lc_offset
-#endif
-	.endm
-
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	.macro	UPDATE_VTIME lc_from,lc_to,lc_sum
 	lg	%r10,\lc_from
 	slg	%r10,\lc_to
 	alg	%r10,\lc_sum
 	stg	%r10,\lc_sum
 	.endm
-#endif
 
 /*
  * Register usage in interrupt handlers:
@@ -186,7 +178,7 @@
 	ni	\psworg+1,0xfd		# clear wait state bit
 	.endif
 	lmg	%r0,%r15,SP_R0(%r15)	# load gprs 0-15 of user
-	STORE_TIMER __LC_EXIT_TIMER
+	stpt	__LC_EXIT_TIMER
 	lpswe	\psworg			# back to caller
 	.endm
 
@@ -233,20 +225,18 @@
 
 	.globl	system_call
 system_call:
-	STORE_TIMER __LC_SYNC_ENTER_TIMER
+	stpt	__LC_SYNC_ENTER_TIMER
 sysc_saveall:
 	SAVE_ALL_BASE __LC_SAVE_AREA
 	SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 	llgh	%r7,__LC_SVC_INT_CODE	# get svc number from lowcore
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 sysc_vtime:
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
 sysc_stime:
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 sysc_update:
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
-#endif
 sysc_do_svc:
 	lg	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	ltgr	%r7,%r7		# test for svc 0
@@ -417,7 +407,7 @@
 0:	brasl	%r14,schedule_tail
 	TRACE_IRQS_ON
 	stosm	24(%r15),0x03		# reenable interrupts
-	j	sysc_return
+	j	sysc_tracenogo
 
 #
 # kernel_execve function needs to deal with pt_regs that is not
@@ -469,20 +459,18 @@
  * we just ignore the PER event (FIXME: is there anything we have to do
  * for LPSW?).
  */
-	STORE_TIMER __LC_SYNC_ENTER_TIMER
+	stpt	__LC_SYNC_ENTER_TIMER
 	SAVE_ALL_BASE __LC_SAVE_AREA
 	tm	__LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
 	jnz	pgm_per 		 # got per exception -> special case
 	SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
 	jz	pgm_no_vtime
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime:
-#endif
 	lg	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	mvc	SP_ARGS(8,%r15),__LC_LAST_BREAK
 	TRACE_IRQS_OFF
@@ -516,14 +504,12 @@
 pgm_per_std:
 	SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
 	jz	pgm_no_vtime2
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime2:
-#endif
 	lg	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	TRACE_IRQS_OFF
 	lg	%r1,__TI_task(%r9)
@@ -545,11 +531,9 @@
 pgm_svcper:
 	SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
 	CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
-#endif
 	llgh	%r7,__LC_SVC_INT_CODE	# get svc number from lowcore
 	lg	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	lg	%r1,__TI_task(%r9)
@@ -575,19 +559,17 @@
  */
 	.globl io_int_handler
 io_int_handler:
-	STORE_TIMER __LC_ASYNC_ENTER_TIMER
+	stpt	__LC_ASYNC_ENTER_TIMER
 	stck	__LC_INT_CLOCK
 	SAVE_ALL_BASE __LC_SAVE_AREA+32
 	SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
 	CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
 	jz	io_no_vtime
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
 io_no_vtime:
-#endif
 	lg	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	TRACE_IRQS_OFF
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
@@ -739,19 +721,17 @@
  */
 	.globl	ext_int_handler
 ext_int_handler:
-	STORE_TIMER __LC_ASYNC_ENTER_TIMER
+	stpt	__LC_ASYNC_ENTER_TIMER
 	stck	__LC_INT_CLOCK
 	SAVE_ALL_BASE __LC_SAVE_AREA+32
 	SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
 	CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
 	jz	ext_no_vtime
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
 ext_no_vtime:
-#endif
 	lg	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	TRACE_IRQS_OFF
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
@@ -773,7 +753,6 @@
 	la	%r12,__LC_MCK_OLD_PSW
 	tm	__LC_MCCK_CODE,0x80	# system damage?
 	jo	mcck_int_main		# yes -> rest of mcck code invalid
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	la	%r14,4095
 	mvc	__LC_SAVE_AREA+104(8),__LC_ASYNC_ENTER_TIMER
 	mvc	__LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14)
@@ -791,9 +770,7 @@
 	la	%r14,__LC_LAST_UPDATE_TIMER
 0:	spt	0(%r14)
 	mvc	__LC_ASYNC_ENTER_TIMER(8),0(%r14)
-1:
-#endif
-	tm	__LC_MCCK_CODE+2,0x09	# mwp + ia of old psw valid?
+1:	tm	__LC_MCCK_CODE+2,0x09	# mwp + ia of old psw valid?
 	jno	mcck_int_main		# no -> skip cleanup critical
 	tm	__LC_MCK_OLD_PSW+1,0x01 # test problem state bit
 	jnz	mcck_int_main		# from user -> load kernel stack
@@ -809,7 +786,6 @@
 	jz	0f
 	lg	%r15,__LC_PANIC_STACK	# load panic stack
 0:	CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	tm	__LC_MCCK_CODE+2,0x08	# mwp of old psw valid?
 	jno	mcck_no_vtime		# no -> no timer update
 	tm	SP_PSW+1(%r15),0x01	# interrupting from user ?
@@ -818,7 +794,6 @@
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
 mcck_no_vtime:
-#endif
 	lg	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	brasl	%r14,s390_do_machine_check
@@ -839,14 +814,11 @@
 	mvc	__LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW
 	ni	__LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
 	lmg	%r0,%r15,SP_R0(%r15)	# load gprs 0-15
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	mvc	__LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+104
 	tm	__LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
 	jno	0f
 	stpt	__LC_EXIT_TIMER
-0:
-#endif
-	lpswe	__LC_RETURN_MCCK_PSW	# back to caller
+0:	lpswe	__LC_RETURN_MCCK_PSW	# back to caller
 
 /*
  * Restart interruption handler, kick starter for additional CPUs
@@ -964,13 +936,11 @@
 	j	1f
 0:	la	%r12,__LC_SAVE_AREA+64
 1:
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	clc	__LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8)
 	jh	0f
 	mvc	__LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER
 0:	clc	__LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16)
 	jhe	cleanup_vtime
-#endif
 	clc	__LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn)
 	jh	0f
 	mvc	__LC_SAVE_AREA(32),0(%r12)
@@ -981,7 +951,6 @@
 	lg	%r12,__LC_SAVE_AREA+96	# argh
 	stg	%r15,24(%r12)
 	llgh	%r7,__LC_SVC_INT_CODE
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 cleanup_vtime:
 	clc	__LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24)
 	jhe	cleanup_stime
@@ -992,18 +961,15 @@
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 cleanup_update:
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
-#endif
 	mvc	__LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8)
 	la	%r12,__LC_RETURN_PSW
 	br	%r14
 cleanup_system_call_insn:
 	.quad	sysc_saveall
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	.quad	system_call
 	.quad	sysc_vtime
 	.quad	sysc_stime
 	.quad	sysc_update
-#endif
 
 cleanup_sysc_return:
 	mvc	__LC_RETURN_PSW(8),0(%r12)
@@ -1014,11 +980,9 @@
 cleanup_sysc_leave:
 	clc	8(8,%r12),BASED(cleanup_sysc_leave_insn)
 	je	2f
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	mvc	__LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
 	clc	8(8,%r12),BASED(cleanup_sysc_leave_insn+8)
 	je	2f
-#endif
 	mvc	__LC_RETURN_PSW(16),SP_PSW(%r15)
 	cghi	%r12,__LC_MCK_OLD_PSW
 	jne	0f
@@ -1031,9 +995,7 @@
 	br	%r14
 cleanup_sysc_leave_insn:
 	.quad	sysc_done - 4
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	.quad	sysc_done - 8
-#endif
 
 cleanup_io_return:
 	mvc	__LC_RETURN_PSW(8),0(%r12)
@@ -1044,11 +1006,9 @@
 cleanup_io_leave:
 	clc	8(8,%r12),BASED(cleanup_io_leave_insn)
 	je	2f
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	mvc	__LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
 	clc	8(8,%r12),BASED(cleanup_io_leave_insn+8)
 	je	2f
-#endif
 	mvc	__LC_RETURN_PSW(16),SP_PSW(%r15)
 	cghi	%r12,__LC_MCK_OLD_PSW
 	jne	0f
@@ -1061,9 +1021,7 @@
 	br	%r14
 cleanup_io_leave_insn:
 	.quad	io_done - 4
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 	.quad	io_done - 8
-#endif
 
 /*
  * Integer constants
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index 83477c7..ec7e35f 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -461,6 +461,55 @@
 	.byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
 	.byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
 
+#
+# startup-code at 0x10000, running in absolute addressing mode
+# this is called either by the ipl loader or directly by PSW restart
+# or linload or SALIPL
+#
+	.org	0x10000
+startup:basr	%r13,0			# get base
+.LPG0:
+
+#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
+	.align 16
+1:	.long	0x000a0000,0x00000000
+2:
+#if defined(CONFIG_MARCH_Z10)
+	.short 0x9672, 0x2064, 0x2066, 0x2084, 0x2086, 0x2094, 0x2096
+#elif defined(CONFIG_MARCH_Z9_109)
+	.short 0x9672, 0x2064, 0x2066, 0x2084, 0x2086
+#elif defined(CONFIG_MARCH_Z990)
+	.short 0x9672, 0x2064, 0x2066
+#elif defined(CONFIG_MARCH_Z900)
+	.short 0x9672
+#endif
+3:	la	%r1,2(%r1)
+	brct	%r0,0b
+#endif
+
+	l	%r13,0f-.LPG0(%r13)
+	b	0(%r13)
+0:	.long	startup_continue
+
+#
+# params at 10400 (setup.h)
+#
+	.org	PARMAREA
+	.long	0,0			# IPL_DEVICE
+	.long	0,0			# INITRD_START
+	.long	0,0			# INITRD_SIZE
+
+	.org	COMMAND_LINE
+	.byte	"root=/dev/ram0 ro"
+	.byte	0
+
 #ifdef CONFIG_64BIT
 #include "head64.S"
 #else
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S
index a816e2d..db476d1 100644
--- a/arch/s390/kernel/head31.S
+++ b/arch/s390/kernel/head31.S
@@ -10,34 +10,13 @@
  *
  */
 
-#
-# startup-code at 0x10000, running in absolute addressing mode
-# this is called either by the ipl loader or directly by PSW restart
-# or linload or SALIPL
-#
-	.org	0x10000
-startup:basr	%r13,0			# get base
-.LPG0:	l	%r13,0f-.LPG0(%r13)
-	b	0(%r13)
-0:	.long	startup_continue
-
-#
-# params at 10400 (setup.h)
-#
-	.org	PARMAREA
-	.long	0,0			# IPL_DEVICE
-	.long	0,0			# INITRD_START
-	.long	0,0			# INITRD_SIZE
-
-	.org	COMMAND_LINE
-	.byte	"root=/dev/ram0 ro"
-	.byte	0
-
 	.org	0x11000
 
 startup_continue:
 	basr	%r13,0			# get base
-.LPG1:	mvi	__LC_AR_MODE_ID,0	# set ESA flag (mode 0)
+.LPG1:
+
+	mvi	__LC_AR_MODE_ID,0	# set ESA flag (mode 0)
 	lctl	%c0,%c15,.Lctl-.LPG1(%r13) # load control registers
 	l	%r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area
 					# move IPL device to lowcore
@@ -50,7 +29,6 @@
 	ahi	%r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE
 	st	%r15,__LC_KERNEL_STACK	# set end of kernel stack
 	ahi	%r15,-96
-	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
 #
 # Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
 # and create a kernel NSS if the SAVESYS= parm is defined
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index 1d06961..3ccd36b 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -10,29 +10,6 @@
  *
  */
 
-#
-# startup-code at 0x10000, running in absolute addressing mode
-# this is called either by the ipl loader or directly by PSW restart
-# or linload or SALIPL
-#
-	.org	0x10000
-startup:basr	%r13,0			# get base
-.LPG0:	l	%r13,0f-.LPG0(%r13)
-	b	0(%r13)
-0:	.long	startup_continue
-
-#
-# params at 10400 (setup.h)
-#
-	.org	PARMAREA
-	.quad	0			# IPL_DEVICE
-	.quad	0			# INITRD_START
-	.quad	0			# INITRD_SIZE
-
-	.org	COMMAND_LINE
-	.byte	"root=/dev/ram0 ro"
-	.byte	0
-
 	.org	0x11000
 
 startup_continue:
@@ -119,7 +96,6 @@
 	aghi	%r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE
 	stg	%r15,__LC_KERNEL_STACK	# set end of kernel stack
 	aghi	%r15,-160
-	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
 #
 # Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
 # and create a kernel NSS if the SAVESYS= parm is defined
diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S
new file mode 100644
index 0000000..397d131
--- /dev/null
+++ b/arch/s390/kernel/mcount.S
@@ -0,0 +1,56 @@
+/*
+ * Copyright IBM Corp. 2008
+ *
+ *   Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *
+ */
+
+#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,0(%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
+ftrace_stub:
+	br	%r14
+
+#else /* CONFIG_64BIT */
+
+.globl _mcount
+_mcount:
+	stmg	%r0,%r5,16(%r15)
+	stg	%r14,112(%r15)
+	lgr	%r1,%r15
+	aghi	%r15,-160
+	stg	%r1,0(%r15)
+	lgr	%r2,%r14
+	lg	%r3,168(%r15)
+	larl	%r14,ftrace_trace_function
+	lg	%r14,0(%r14)
+	basr	%r14,%r14
+	aghi	%r15,160
+	lmg	%r0,%r5,16(%r15)
+	lg	%r14,112(%r15)
+	br	%r14
+
+.globl ftrace_stub
+ftrace_stub:
+	br	%r14
+
+#endif /* CONFIG_64BIT */
diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c
new file mode 100644
index 0000000..82c1872
--- /dev/null
+++ b/arch/s390/kernel/processor.c
@@ -0,0 +1,98 @@
+/*
+ *  arch/s390/kernel/processor.c
+ *
+ *  Copyright IBM Corp. 2008
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#define KMSG_COMPONENT "cpu"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+
+#include <asm/elf.h>
+#include <asm/lowcore.h>
+#include <asm/param.h>
+
+void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo)
+{
+	pr_info("Processor %d started, address %d, identification %06X\n",
+		cpuinfo->cpu_nr, cpuinfo->cpu_addr, cpuinfo->cpu_id.ident);
+}
+
+/*
+ * show_cpuinfo - Get information on one CPU for use by procfs.
+ */
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+	static const char *hwcap_str[8] = {
+		"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
+		"edat"
+	};
+       struct cpuinfo_S390 *cpuinfo;
+       unsigned long n = (unsigned long) v - 1;
+       int i;
+
+       s390_adjust_jiffies();
+       preempt_disable();
+       if (!n) {
+	       seq_printf(m, "vendor_id       : IBM/S390\n"
+			  "# processors    : %i\n"
+			  "bogomips per cpu: %lu.%02lu\n",
+			  num_online_cpus(), loops_per_jiffy/(500000/HZ),
+			  (loops_per_jiffy/(5000/HZ))%100);
+	       seq_puts(m, "features\t: ");
+	       for (i = 0; i < 8; i++)
+		       if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
+			       seq_printf(m, "%s ", hwcap_str[i]);
+	       seq_puts(m, "\n");
+       }
+
+       if (cpu_online(n)) {
+#ifdef CONFIG_SMP
+	       if (smp_processor_id() == n)
+		       cpuinfo = &S390_lowcore.cpu_data;
+	       else
+		       cpuinfo = &lowcore_ptr[n]->cpu_data;
+#else
+	       cpuinfo = &S390_lowcore.cpu_data;
+#endif
+	       seq_printf(m, "processor %li: "
+			  "version = %02X,  "
+			  "identification = %06X,  "
+			  "machine = %04X\n",
+			  n, cpuinfo->cpu_id.version,
+			  cpuinfo->cpu_id.ident,
+			  cpuinfo->cpu_id.machine);
+       }
+       preempt_enable();
+       return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos < NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+const struct seq_operations cpuinfo_op = {
+	.start	= c_start,
+	.next	= c_next,
+	.stop	= c_stop,
+	.show	= show_cpuinfo,
+};
+
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 38ff2bc..75c496f 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -204,7 +204,6 @@
 static int
 peek_user(struct task_struct *child, addr_t addr, addr_t data)
 {
-	struct user *dummy = NULL;
 	addr_t tmp, mask;
 
 	/*
@@ -213,8 +212,8 @@
 	 */
 	mask = __ADDR_MASK;
 #ifdef CONFIG_64BIT
-	if (addr >= (addr_t) &dummy->regs.acrs &&
-	    addr < (addr_t) &dummy->regs.orig_gpr2)
+	if (addr >= (addr_t) &((struct user *) NULL)->regs.acrs &&
+	    addr < (addr_t) &((struct user *) NULL)->regs.orig_gpr2)
 		mask = 3;
 #endif
 	if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
@@ -312,7 +311,6 @@
 static int
 poke_user(struct task_struct *child, addr_t addr, addr_t data)
 {
-	struct user *dummy = NULL;
 	addr_t mask;
 
 	/*
@@ -321,8 +319,8 @@
 	 */
 	mask = __ADDR_MASK;
 #ifdef CONFIG_64BIT
-	if (addr >= (addr_t) &dummy->regs.acrs &&
-	    addr < (addr_t) &dummy->regs.orig_gpr2)
+	if (addr >= (addr_t) &((struct user *) NULL)->regs.acrs &&
+	    addr < (addr_t) &((struct user *) NULL)->regs.orig_gpr2)
 		mask = 3;
 #endif
 	if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
index 48238a1..46b90cb 100644
--- a/arch/s390/kernel/s390_ksyms.c
+++ b/arch/s390/kernel/s390_ksyms.c
@@ -14,6 +14,7 @@
 #include <asm/delay.h>
 #include <asm/pgalloc.h>
 #include <asm/setup.h>
+#include <asm/ftrace.h>
 #ifdef CONFIG_IP_MULTICAST
 #include <net/arp.h>
 #endif
@@ -43,3 +44,7 @@
 EXPORT_SYMBOL(console_mode);
 EXPORT_SYMBOL(console_devno);
 EXPORT_SYMBOL(console_irq);
+
+#ifdef CONFIG_FUNCTION_TRACER
+EXPORT_SYMBOL(_mcount);
+#endif
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 400b040..b7a1efd 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -14,6 +14,9 @@
  * This file handles the architecture-dependent parts of initialization
  */
 
+#define KMSG_COMPONENT "setup"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -32,7 +35,6 @@
 #include <linux/bootmem.h>
 #include <linux/root_dev.h>
 #include <linux/console.h>
-#include <linux/seq_file.h>
 #include <linux/kernel_stat.h>
 #include <linux/device.h>
 #include <linux/notifier.h>
@@ -291,8 +293,8 @@
 #endif
 EXPORT_SYMBOL_GPL(switch_amode);
 
-static void set_amode_and_uaccess(unsigned long user_amode,
-				  unsigned long user32_amode)
+static int set_amode_and_uaccess(unsigned long user_amode,
+				 unsigned long user32_amode)
 {
 	psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode |
 			PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
@@ -309,11 +311,11 @@
 			  PSW_MASK_MCHECK | PSW_DEFAULT_KEY;
 
 	if (MACHINE_HAS_MVCOS) {
-		printk("mvcos available.\n");
 		memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess));
+		return 1;
 	} else {
-		printk("mvcos not available.\n");
 		memcpy(&uaccess, &uaccess_pt, sizeof(uaccess));
+		return 0;
 	}
 }
 
@@ -328,9 +330,10 @@
 early_param("switch_amode", early_parse_switch_amode);
 
 #else /* CONFIG_S390_SWITCH_AMODE */
-static inline void set_amode_and_uaccess(unsigned long user_amode,
-					 unsigned long user32_amode)
+static inline int set_amode_and_uaccess(unsigned long user_amode,
+					unsigned long user32_amode)
 {
+	return 0;
 }
 #endif /* CONFIG_S390_SWITCH_AMODE */
 
@@ -355,11 +358,20 @@
 static void setup_addressing_mode(void)
 {
 	if (s390_noexec) {
-		printk("S390 execute protection active, ");
-		set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY);
+		if (set_amode_and_uaccess(PSW_ASC_SECONDARY,
+					  PSW32_ASC_SECONDARY))
+			pr_info("Execute protection active, "
+				"mvcos available\n");
+		else
+			pr_info("Execute protection active, "
+				"mvcos not available\n");
 	} else if (switch_amode) {
-		printk("S390 address spaces switched, ");
-		set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY);
+		if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY))
+			pr_info("Address spaces switched, "
+				"mvcos available\n");
+		else
+			pr_info("Address spaces switched, "
+				"mvcos not available\n");
 	}
 #ifdef CONFIG_TRACE_IRQFLAGS
 	sysc_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
@@ -572,15 +584,15 @@
 			start = PFN_PHYS(start_pfn) + bmap_size + PAGE_SIZE;
 
 			if (start + INITRD_SIZE > memory_end) {
-				printk("initrd extends beyond end of memory "
-				       "(0x%08lx > 0x%08lx)\n"
+				pr_err("initrd extends beyond end of "
+				       "memory (0x%08lx > 0x%08lx) "
 				       "disabling initrd\n",
 				       start + INITRD_SIZE, memory_end);
 				INITRD_START = INITRD_SIZE = 0;
 			} else {
-				printk("Moving initrd (0x%08lx -> 0x%08lx, "
-				       "size: %ld)\n",
-				       INITRD_START, start, INITRD_SIZE);
+				pr_info("Moving initrd (0x%08lx -> "
+					"0x%08lx, size: %ld)\n",
+					INITRD_START, start, INITRD_SIZE);
 				memmove((void *) start, (void *) INITRD_START,
 					INITRD_SIZE);
 				INITRD_START = start;
@@ -642,8 +654,9 @@
 			initrd_start = INITRD_START;
 			initrd_end = initrd_start + INITRD_SIZE;
 		} else {
-			printk("initrd extends beyond end of memory "
-			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+			pr_err("initrd extends beyond end of "
+			       "memory (0x%08lx > 0x%08lx) "
+			       "disabling initrd\n",
 			       initrd_start + INITRD_SIZE, memory_end);
 			initrd_start = initrd_end = 0;
 		}
@@ -651,23 +664,6 @@
 #endif
 }
 
-static int __init __stfle(unsigned long long *list, int doublewords)
-{
-	typedef struct { unsigned long long _[doublewords]; } addrtype;
-	register unsigned long __nr asm("0") = doublewords - 1;
-
-	asm volatile(".insn s,0xb2b00000,%0" /* stfle */
-		     : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
-	return __nr + 1;
-}
-
-int __init stfle(unsigned long long *list, int doublewords)
-{
-	if (!(stfl() & (1UL << 24)))
-		return -EOPNOTSUPP;
-	return __stfle(list, doublewords);
-}
-
 /*
  * Setup hardware capabilities.
  */
@@ -739,8 +735,13 @@
 		strcpy(elf_platform, "z990");
 		break;
 	case 0x2094:
+	case 0x2096:
 		strcpy(elf_platform, "z9-109");
 		break;
+	case 0x2097:
+	case 0x2098:
+		strcpy(elf_platform, "z10");
+		break;
 	}
 }
 
@@ -752,25 +753,34 @@
 void __init
 setup_arch(char **cmdline_p)
 {
+	/* set up preferred console */
+	add_preferred_console("ttyS", 0, NULL);
+
         /*
          * print what head.S has found out about the machine
          */
 #ifndef CONFIG_64BIT
-	printk((MACHINE_IS_VM) ?
-	       "We are running under VM (31 bit mode)\n" :
-	       "We are running native (31 bit mode)\n");
-	printk((MACHINE_HAS_IEEE) ?
-	       "This machine has an IEEE fpu\n" :
-	       "This machine has no IEEE fpu\n");
+	if (MACHINE_IS_VM)
+		pr_info("Linux is running as a z/VM "
+			"guest operating system in 31-bit mode\n");
+	else
+		pr_info("Linux is running natively in 31-bit mode\n");
+	if (MACHINE_HAS_IEEE)
+		pr_info("The hardware system has IEEE compatible "
+			"floating point units\n");
+	else
+		pr_info("The hardware system has no IEEE compatible "
+			"floating point units\n");
 #else /* CONFIG_64BIT */
 	if (MACHINE_IS_VM)
-		printk("We are running under VM (64 bit mode)\n");
+		pr_info("Linux is running as a z/VM "
+			"guest operating system in 64-bit mode\n");
 	else if (MACHINE_IS_KVM) {
-		printk("We are running under KVM (64 bit mode)\n");
+		pr_info("Linux is running under KVM in 64-bit mode\n");
 		add_preferred_console("hvc", 0, NULL);
 		s390_virtio_console_init();
 	} else
-		printk("We are running native (64 bit mode)\n");
+		pr_info("Linux is running natively in 64-bit mode\n");
 #endif /* CONFIG_64BIT */
 
 	/* Have one command line that is parsed and saved in /proc/cmdline */
@@ -818,90 +828,3 @@
 	/* Setup zfcpdump support */
 	setup_zfcpdump(console_devno);
 }
-
-void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo)
-{
-   printk(KERN_INFO "cpu %d "
-#ifdef CONFIG_SMP
-           "phys_idx=%d "
-#endif
-           "vers=%02X ident=%06X machine=%04X unused=%04X\n",
-           cpuinfo->cpu_nr,
-#ifdef CONFIG_SMP
-           cpuinfo->cpu_addr,
-#endif
-           cpuinfo->cpu_id.version,
-           cpuinfo->cpu_id.ident,
-           cpuinfo->cpu_id.machine,
-           cpuinfo->cpu_id.unused);
-}
-
-/*
- * show_cpuinfo - Get information on one CPU for use by procfs.
- */
-
-static int show_cpuinfo(struct seq_file *m, void *v)
-{
-	static const char *hwcap_str[8] = {
-		"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
-		"edat"
-	};
-        struct cpuinfo_S390 *cpuinfo;
-	unsigned long n = (unsigned long) v - 1;
-	int i;
-
-	s390_adjust_jiffies();
-	preempt_disable();
-	if (!n) {
-		seq_printf(m, "vendor_id       : IBM/S390\n"
-			       "# processors    : %i\n"
-			       "bogomips per cpu: %lu.%02lu\n",
-			       num_online_cpus(), loops_per_jiffy/(500000/HZ),
-			       (loops_per_jiffy/(5000/HZ))%100);
-		seq_puts(m, "features\t: ");
-		for (i = 0; i < 8; i++)
-			if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
-				seq_printf(m, "%s ", hwcap_str[i]);
-		seq_puts(m, "\n");
-	}
-
-	if (cpu_online(n)) {
-#ifdef CONFIG_SMP
-		if (smp_processor_id() == n)
-			cpuinfo = &S390_lowcore.cpu_data;
-		else
-			cpuinfo = &lowcore_ptr[n]->cpu_data;
-#else
-		cpuinfo = &S390_lowcore.cpu_data;
-#endif
-		seq_printf(m, "processor %li: "
-			       "version = %02X,  "
-			       "identification = %06X,  "
-			       "machine = %04X\n",
-			       n, cpuinfo->cpu_id.version,
-			       cpuinfo->cpu_id.ident,
-			       cpuinfo->cpu_id.machine);
-	}
-	preempt_enable();
-        return 0;
-}
-
-static void *c_start(struct seq_file *m, loff_t *pos)
-{
-	return *pos < NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL;
-}
-static void *c_next(struct seq_file *m, void *v, loff_t *pos)
-{
-	++*pos;
-	return c_start(m, pos);
-}
-static void c_stop(struct seq_file *m, void *v)
-{
-}
-const struct seq_operations cpuinfo_op = {
-	.start	= c_start,
-	.next	= c_next,
-	.stop	= c_stop,
-	.show	= show_cpuinfo,
-};
-
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index b559568..6fc7854 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -20,6 +20,9 @@
  * cpu_number_map in other architectures.
  */
 
+#define KMSG_COMPONENT "cpu"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/mm.h>
@@ -77,159 +80,6 @@
 
 static void smp_ext_bitcall(int, ec_bit_sig);
 
-/*
- * Structure and data for __smp_call_function_map(). This is designed to
- * minimise static memory requirements. It also looks cleaner.
- */
-static DEFINE_SPINLOCK(call_lock);
-
-struct call_data_struct {
-	void (*func) (void *info);
-	void *info;
-	cpumask_t started;
-	cpumask_t finished;
-	int wait;
-};
-
-static struct call_data_struct *call_data;
-
-/*
- * 'Call function' interrupt callback
- */
-static void do_call_function(void)
-{
-	void (*func) (void *info) = call_data->func;
-	void *info = call_data->info;
-	int wait = call_data->wait;
-
-	cpu_set(smp_processor_id(), call_data->started);
-	(*func)(info);
-	if (wait)
-		cpu_set(smp_processor_id(), call_data->finished);;
-}
-
-static void __smp_call_function_map(void (*func) (void *info), void *info,
-				    int wait, cpumask_t map)
-{
-	struct call_data_struct data;
-	int cpu, local = 0;
-
-	/*
-	 * Can deadlock when interrupts are disabled or if in wrong context.
-	 */
-	WARN_ON(irqs_disabled() || in_irq());
-
-	/*
-	 * Check for local function call. We have to have the same call order
-	 * as in on_each_cpu() because of machine_restart_smp().
-	 */
-	if (cpu_isset(smp_processor_id(), map)) {
-		local = 1;
-		cpu_clear(smp_processor_id(), map);
-	}
-
-	cpus_and(map, map, cpu_online_map);
-	if (cpus_empty(map))
-		goto out;
-
-	data.func = func;
-	data.info = info;
-	data.started = CPU_MASK_NONE;
-	data.wait = wait;
-	if (wait)
-		data.finished = CPU_MASK_NONE;
-
-	call_data = &data;
-
-	for_each_cpu_mask(cpu, map)
-		smp_ext_bitcall(cpu, ec_call_function);
-
-	/* Wait for response */
-	while (!cpus_equal(map, data.started))
-		cpu_relax();
-	if (wait)
-		while (!cpus_equal(map, data.finished))
-			cpu_relax();
-out:
-	if (local) {
-		local_irq_disable();
-		func(info);
-		local_irq_enable();
-	}
-}
-
-/*
- * smp_call_function:
- * @func: the function to run; this must be fast and non-blocking
- * @info: an arbitrary pointer to pass to the function
- * @wait: if true, wait (atomically) until function has completed on other CPUs
- *
- * Run a function on all other CPUs.
- *
- * You must not call this function with disabled interrupts, from a
- * hardware interrupt handler or from a bottom half.
- */
-int smp_call_function(void (*func) (void *info), void *info, int wait)
-{
-	cpumask_t map;
-
-	spin_lock(&call_lock);
-	map = cpu_online_map;
-	cpu_clear(smp_processor_id(), map);
-	__smp_call_function_map(func, info, wait, map);
-	spin_unlock(&call_lock);
-	return 0;
-}
-EXPORT_SYMBOL(smp_call_function);
-
-/*
- * smp_call_function_single:
- * @cpu: the CPU where func should run
- * @func: the function to run; this must be fast and non-blocking
- * @info: an arbitrary pointer to pass to the function
- * @wait: if true, wait (atomically) until function has completed on other CPUs
- *
- * Run a function on one processor.
- *
- * You must not call this function with disabled interrupts, from a
- * hardware interrupt handler or from a bottom half.
- */
-int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
-			     int wait)
-{
-	spin_lock(&call_lock);
-	__smp_call_function_map(func, info, wait, cpumask_of_cpu(cpu));
-	spin_unlock(&call_lock);
-	return 0;
-}
-EXPORT_SYMBOL(smp_call_function_single);
-
-/**
- * smp_call_function_mask(): Run a function on a set of other CPUs.
- * @mask: The set of cpus to run on.  Must not include the current cpu.
- * @func: The function to run. This must be fast and non-blocking.
- * @info: An arbitrary pointer to pass to the function.
- * @wait: If true, wait (atomically) until function has completed on other CPUs.
- *
- * Returns 0 on success, else a negative status code.
- *
- * If @wait is true, then returns once @func has returned; otherwise
- * it returns just before the target cpu calls @func.
- *
- * You must not call this function with disabled interrupts or from a
- * hardware interrupt handler or from a bottom half handler.
- */
-int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info,
-			   int wait)
-{
-	spin_lock(&call_lock);
-	cpu_clear(smp_processor_id(), mask);
-	__smp_call_function_map(func, info, wait, mask);
-	spin_unlock(&call_lock);
-	return 0;
-}
-EXPORT_SYMBOL(smp_call_function_mask);
-
 void smp_send_stop(void)
 {
 	int cpu, rc;
@@ -271,7 +121,10 @@
 	bits = xchg(&S390_lowcore.ext_call_fast, 0);
 
 	if (test_bit(ec_call_function, &bits))
-		do_call_function();
+		generic_smp_call_function_interrupt();
+
+	if (test_bit(ec_call_function_single, &bits))
+		generic_smp_call_function_single_interrupt();
 }
 
 /*
@@ -288,6 +141,19 @@
 		udelay(10);
 }
 
+void arch_send_call_function_ipi(cpumask_t mask)
+{
+	int cpu;
+
+	for_each_cpu_mask(cpu, mask)
+		smp_ext_bitcall(cpu, ec_call_function);
+}
+
+void arch_send_call_function_single_ipi(int cpu)
+{
+	smp_ext_bitcall(cpu, ec_call_function_single);
+}
+
 #ifndef CONFIG_64BIT
 /*
  * this function sends a 'purge tlb' signal to another CPU.
@@ -388,8 +254,8 @@
 	if (ipl_info.type != IPL_TYPE_FCP_DUMP)
 		return;
 	if (cpu >= NR_CPUS) {
-		printk(KERN_WARNING "Registers for cpu %i not saved since dump "
-		       "kernel was compiled with NR_CPUS=%i\n", cpu, NR_CPUS);
+		pr_warning("CPU %i exceeds the maximum %i and is excluded from "
+			   "the dump\n", cpu, NR_CPUS - 1);
 		return;
 	}
 	zfcpdump_save_areas[cpu] = kmalloc(sizeof(union save_area), GFP_KERNEL);
@@ -562,7 +428,7 @@
 	}
 out:
 	kfree(info);
-	printk(KERN_INFO "CPUs: %d configured, %d standby\n", c_cpus, s_cpus);
+	pr_info("%d configured CPUs, %d standby CPUs\n", c_cpus, s_cpus);
 	get_online_cpus();
 	__smp_rescan_cpus();
 	put_online_cpus();
@@ -578,19 +444,17 @@
 	preempt_disable();
 	/* Enable TOD clock interrupts on the secondary cpu. */
 	init_cpu_timer();
-#ifdef CONFIG_VIRT_TIMER
 	/* Enable cpu timer interrupts on the secondary cpu. */
 	init_cpu_vtimer();
-#endif
 	/* Enable pfault pseudo page faults on this cpu. */
 	pfault_init();
 
 	/* call cpu notifiers */
 	notify_cpu_starting(smp_processor_id());
 	/* Mark this cpu as online */
-	spin_lock(&call_lock);
+	ipi_call_lock();
 	cpu_set(smp_processor_id(), cpu_online_map);
-	spin_unlock(&call_lock);
+	ipi_call_unlock();
 	/* Switch on interrupts */
 	local_irq_enable();
 	/* Print info about this processor */
@@ -639,18 +503,15 @@
 
 		save_area = get_zeroed_page(GFP_KERNEL);
 		if (!save_area)
-			goto out_save_area;
+			goto out;
 		lowcore->extended_save_area_addr = (u32) save_area;
 	}
 #endif
 	lowcore_ptr[cpu] = lowcore;
 	return 0;
 
-#ifndef CONFIG_64BIT
-out_save_area:
-	free_page(panic_stack);
-#endif
 out:
+	free_page(panic_stack);
 	free_pages(async_stack, ASYNC_ORDER);
 	free_pages((unsigned long) lowcore, lc_order);
 	return -ENOMEM;
@@ -690,12 +551,8 @@
 
 	ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]),
 				   cpu, sigp_set_prefix);
-	if (ccode) {
-		printk("sigp_set_prefix failed for cpu %d "
-		       "with condition code %d\n",
-		       (int) cpu, (int) ccode);
+	if (ccode)
 		return -EIO;
-	}
 
 	idle = current_set[cpu];
 	cpu_lowcore = lowcore_ptr[cpu];
@@ -778,7 +635,7 @@
 	while (!smp_cpu_not_running(cpu))
 		cpu_relax();
 	smp_free_lowcore(cpu);
-	printk(KERN_INFO "Processor %d spun down\n", cpu);
+	pr_info("Processor %d stopped\n", cpu);
 }
 
 void cpu_die(void)
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index eccefbb..5be981a 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -12,6 +12,9 @@
  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
  */
 
+#define KMSG_COMPONENT "time"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -20,6 +23,8 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/cpu.h>
+#include <linux/stop_machine.h>
 #include <linux/time.h>
 #include <linux/sysdev.h>
 #include <linux/delay.h>
@@ -36,6 +41,7 @@
 #include <asm/delay.h>
 #include <asm/s390_ext.h>
 #include <asm/div64.h>
+#include <asm/vdso.h>
 #include <asm/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/timer.h>
@@ -223,6 +229,36 @@
 };
 
 
+void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
+{
+	if (clock != &clocksource_tod)
+		return;
+
+	/* Make userspace gettimeofday spin until we're done. */
+	++vdso_data->tb_update_count;
+	smp_wmb();
+	vdso_data->xtime_tod_stamp = clock->cycle_last;
+	vdso_data->xtime_clock_sec = xtime.tv_sec;
+	vdso_data->xtime_clock_nsec = xtime.tv_nsec;
+	vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec;
+	vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec;
+	smp_wmb();
+	++vdso_data->tb_update_count;
+}
+
+extern struct timezone sys_tz;
+
+void update_vsyscall_tz(void)
+{
+	/* Make userspace gettimeofday spin until we're done. */
+	++vdso_data->tb_update_count;
+	smp_wmb();
+	vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
+	vdso_data->tz_dsttime = sys_tz.tz_dsttime;
+	smp_wmb();
+	++vdso_data->tb_update_count;
+}
+
 /*
  * Initialize the TOD clock and the CPU timer of
  * the boot cpu.
@@ -253,10 +289,8 @@
 
 	/* Enable TOD clock interrupts on the boot cpu. */
 	init_cpu_timer();
-
-#ifdef CONFIG_VIRT_TIMER
+	/* Enable cpu timer interrupts on the boot cpu. */
 	vtime_init();
-#endif
 }
 
 /*
@@ -288,8 +322,8 @@
 	}
 	sched_clock_base_cc += delta;
 	if (adjust.offset != 0) {
-		printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n",
-		       adjust.offset);
+		pr_notice("The ETR interface has adjusted the clock "
+			  "by %li microseconds\n", adjust.offset);
 		adjust.modes = ADJ_OFFSET_SINGLESHOT;
 		do_adjtimex(&adjust);
 	}
@@ -360,6 +394,15 @@
 	atomic_set_mask(0x80000000, sw_ptr);
 }
 
+/* Single threaded workqueue used for etr and stp sync events */
+static struct workqueue_struct *time_sync_wq;
+
+static void __init time_init_wq(void)
+{
+	if (!time_sync_wq)
+		time_sync_wq = create_singlethread_workqueue("timesync");
+}
+
 /*
  * External Time Reference (ETR) code.
  */
@@ -425,6 +468,7 @@
 
 static void etr_timeout(unsigned long dummy);
 static void etr_work_fn(struct work_struct *work);
+static DEFINE_MUTEX(etr_work_mutex);
 static DECLARE_WORK(etr_work, etr_work_fn);
 
 /*
@@ -440,8 +484,8 @@
 		etr_tolec = get_clock();
 		set_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags);
 	} else if (etr_port0_online || etr_port1_online) {
-		printk(KERN_WARNING "Running on non ETR capable "
-		       "machine, only local mode available.\n");
+		pr_warning("The real or virtual hardware system does "
+			   "not provide an ETR interface\n");
 		etr_port0_online = etr_port1_online = 0;
 	}
 }
@@ -452,17 +496,18 @@
 
 	if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags))
 		return 0;
+	time_init_wq();
 	/* Check if this machine has the steai instruction. */
 	if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0)
 		etr_steai_available = 1;
 	setup_timer(&etr_timer, etr_timeout, 0UL);
 	if (etr_port0_online) {
 		set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
-		schedule_work(&etr_work);
+		queue_work(time_sync_wq, &etr_work);
 	}
 	if (etr_port1_online) {
 		set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
-		schedule_work(&etr_work);
+		queue_work(time_sync_wq, &etr_work);
 	}
 	return 0;
 }
@@ -489,7 +534,7 @@
 	if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags))
 		disable_sync_clock(NULL);
 	set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events);
-	schedule_work(&etr_work);
+	queue_work(time_sync_wq, &etr_work);
 }
 
 /*
@@ -505,7 +550,7 @@
 	if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags))
 		disable_sync_clock(NULL);
 	set_bit(ETR_EVENT_SYNC_CHECK, &etr_events);
-	schedule_work(&etr_work);
+	queue_work(time_sync_wq, &etr_work);
 }
 
 /*
@@ -529,13 +574,13 @@
 		 * Both ports are not up-to-date now.
 		 */
 		set_bit(ETR_EVENT_PORT_ALERT, &etr_events);
-	schedule_work(&etr_work);
+	queue_work(time_sync_wq, &etr_work);
 }
 
 static void etr_timeout(unsigned long dummy)
 {
 	set_bit(ETR_EVENT_UPDATE, &etr_events);
-	schedule_work(&etr_work);
+	queue_work(time_sync_wq, &etr_work);
 }
 
 /*
@@ -642,14 +687,16 @@
 }
 
 struct clock_sync_data {
+	atomic_t cpus;
 	int in_sync;
 	unsigned long long fixup_cc;
+	int etr_port;
+	struct etr_aib *etr_aib;
 };
 
-static void clock_sync_cpu_start(void *dummy)
+static void clock_sync_cpu(struct clock_sync_data *sync)
 {
-	struct clock_sync_data *sync = dummy;
-
+	atomic_dec(&sync->cpus);
 	enable_sync_clock();
 	/*
 	 * This looks like a busy wait loop but it isn't. etr_sync_cpus
@@ -675,39 +722,35 @@
 	fixup_clock_comparator(sync->fixup_cc);
 }
 
-static void clock_sync_cpu_end(void *dummy)
-{
-}
-
 /*
  * Sync the TOD clock using the port refered to by aibp. This port
  * has to be enabled and the other port has to be disabled. The
  * last eacr update has to be more than 1.6 seconds in the past.
  */
-static int etr_sync_clock(struct etr_aib *aib, int port)
+static int etr_sync_clock(void *data)
 {
-	struct etr_aib *sync_port;
-	struct clock_sync_data etr_sync;
+	static int first;
 	unsigned long long clock, old_clock, delay, delta;
-	int follows;
+	struct clock_sync_data *etr_sync;
+	struct etr_aib *sync_port, *aib;
+	int port;
 	int rc;
 
-	/* Check if the current aib is adjacent to the sync port aib. */
-	sync_port = (port == 0) ? &etr_port0 : &etr_port1;
-	follows = etr_aib_follows(sync_port, aib, port);
-	memcpy(sync_port, aib, sizeof(*aib));
-	if (!follows)
-		return -EAGAIN;
+	etr_sync = data;
 
-	/*
-	 * Catch all other cpus and make them wait until we have
-	 * successfully synced the clock. smp_call_function will
-	 * return after all other cpus are in etr_sync_cpu_start.
-	 */
-	memset(&etr_sync, 0, sizeof(etr_sync));
-	preempt_disable();
-	smp_call_function(clock_sync_cpu_start, &etr_sync, 0);
-	local_irq_disable();
+	if (xchg(&first, 1) == 1) {
+		/* Slave */
+		clock_sync_cpu(etr_sync);
+		return 0;
+	}
+
+	/* Wait until all other cpus entered the sync function. */
+	while (atomic_read(&etr_sync->cpus) != 0)
+		cpu_relax();
+
+	port = etr_sync->etr_port;
+	aib = etr_sync->etr_aib;
+	sync_port = (port == 0) ? &etr_port0 : &etr_port1;
 	enable_sync_clock();
 
 	/* Set clock to next OTE. */
@@ -724,16 +767,16 @@
 		delay = (unsigned long long)
 			(aib->edf2.etv - sync_port->edf2.etv) << 32;
 		delta = adjust_time(old_clock, clock, delay);
-		etr_sync.fixup_cc = delta;
+		etr_sync->fixup_cc = delta;
 		fixup_clock_comparator(delta);
 		/* Verify that the clock is properly set. */
 		if (!etr_aib_follows(sync_port, aib, port)) {
 			/* Didn't work. */
 			disable_sync_clock(NULL);
-			etr_sync.in_sync = -EAGAIN;
+			etr_sync->in_sync = -EAGAIN;
 			rc = -EAGAIN;
 		} else {
-			etr_sync.in_sync = 1;
+			etr_sync->in_sync = 1;
 			rc = 0;
 		}
 	} else {
@@ -741,12 +784,33 @@
 		__ctl_clear_bit(0, 29);
 		__ctl_clear_bit(14, 21);
 		disable_sync_clock(NULL);
-		etr_sync.in_sync = -EAGAIN;
+		etr_sync->in_sync = -EAGAIN;
 		rc = -EAGAIN;
 	}
-	local_irq_enable();
-	smp_call_function(clock_sync_cpu_end, NULL, 0);
-	preempt_enable();
+	xchg(&first, 0);
+	return rc;
+}
+
+static int etr_sync_clock_stop(struct etr_aib *aib, int port)
+{
+	struct clock_sync_data etr_sync;
+	struct etr_aib *sync_port;
+	int follows;
+	int rc;
+
+	/* Check if the current aib is adjacent to the sync port aib. */
+	sync_port = (port == 0) ? &etr_port0 : &etr_port1;
+	follows = etr_aib_follows(sync_port, aib, port);
+	memcpy(sync_port, aib, sizeof(*aib));
+	if (!follows)
+		return -EAGAIN;
+	memset(&etr_sync, 0, sizeof(etr_sync));
+	etr_sync.etr_aib = aib;
+	etr_sync.etr_port = port;
+	get_online_cpus();
+	atomic_set(&etr_sync.cpus, num_online_cpus() - 1);
+	rc = stop_machine(etr_sync_clock, &etr_sync, &cpu_online_map);
+	put_online_cpus();
 	return rc;
 }
 
@@ -903,7 +967,7 @@
 }
 
 /*
- * ETR tasklet. In this function you'll find the main logic. In
+ * ETR work. In this function you'll find the main logic. In
  * particular this is the only function that calls etr_update_eacr(),
  * it "controls" the etr control register.
  */
@@ -914,6 +978,9 @@
 	struct etr_aib aib;
 	int sync_port;
 
+	/* prevent multiple execution. */
+	mutex_lock(&etr_work_mutex);
+
 	/* Create working copy of etr_eacr. */
 	eacr = etr_eacr;
 
@@ -929,7 +996,7 @@
 		del_timer_sync(&etr_timer);
 		etr_update_eacr(eacr);
 		clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
-		return;
+		goto out_unlock;
 	}
 
 	/* Store aib to get the current ETR status word. */
@@ -1016,7 +1083,7 @@
 	    eacr.es || sync_port < 0) {
 		etr_update_eacr(eacr);
 		etr_set_tolec_timeout(now);
-		return;
+		goto out_unlock;
 	}
 
 	/*
@@ -1036,7 +1103,7 @@
 	etr_update_eacr(eacr);
 	set_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
 	if (now < etr_tolec + (1600000 << 12) ||
-	    etr_sync_clock(&aib, sync_port) != 0) {
+	    etr_sync_clock_stop(&aib, sync_port) != 0) {
 		/* Sync failed. Try again in 1/2 second. */
 		eacr.es = 0;
 		etr_update_eacr(eacr);
@@ -1044,6 +1111,8 @@
 		etr_set_sync_timeout();
 	} else
 		etr_set_tolec_timeout(now);
+out_unlock:
+	mutex_unlock(&etr_work_mutex);
 }
 
 /*
@@ -1125,13 +1194,13 @@
 			return count;	/* Nothing to do. */
 		etr_port0_online = value;
 		set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
-		schedule_work(&etr_work);
+		queue_work(time_sync_wq, &etr_work);
 	} else {
 		if (etr_port1_online == value)
 			return count;	/* Nothing to do. */
 		etr_port1_online = value;
 		set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
-		schedule_work(&etr_work);
+		queue_work(time_sync_wq, &etr_work);
 	}
 	return count;
 }
@@ -1332,6 +1401,7 @@
 static void *stp_page;
 
 static void stp_work_fn(struct work_struct *work);
+static DEFINE_MUTEX(stp_work_mutex);
 static DECLARE_WORK(stp_work, stp_work_fn);
 
 static int __init early_parse_stp(char *p)
@@ -1356,7 +1426,8 @@
 	if (rc == 0)
 		set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags);
 	else if (stp_online) {
-		printk(KERN_WARNING "Running on non STP capable machine.\n");
+		pr_warning("The real or virtual hardware system does "
+			   "not provide an STP interface\n");
 		free_bootmem((unsigned long) stp_page, PAGE_SIZE);
 		stp_page = NULL;
 		stp_online = 0;
@@ -1365,8 +1436,12 @@
 
 static int __init stp_init(void)
 {
-	if (test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags) && stp_online)
-		schedule_work(&stp_work);
+	if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags))
+		return 0;
+	time_init_wq();
+	if (!stp_online)
+		return 0;
+	queue_work(time_sync_wq, &stp_work);
 	return 0;
 }
 
@@ -1383,7 +1458,7 @@
 static void stp_timing_alert(struct stp_irq_parm *intparm)
 {
 	if (intparm->tsc || intparm->lac || intparm->tcpc)
-		schedule_work(&stp_work);
+		queue_work(time_sync_wq, &stp_work);
 }
 
 /*
@@ -1397,7 +1472,7 @@
 	if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags))
 		return;
 	disable_sync_clock(NULL);
-	schedule_work(&stp_work);
+	queue_work(time_sync_wq, &stp_work);
 }
 
 /*
@@ -1411,46 +1486,34 @@
 	if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags))
 		return;
 	disable_sync_clock(NULL);
-	schedule_work(&stp_work);
+	queue_work(time_sync_wq, &stp_work);
 }
 
-/*
- * STP tasklet. Check for the STP state and take over the clock
- * synchronization if the STP clock source is usable.
- */
-static void stp_work_fn(struct work_struct *work)
+
+static int stp_sync_clock(void *data)
 {
-	struct clock_sync_data stp_sync;
+	static int first;
 	unsigned long long old_clock, delta;
+	struct clock_sync_data *stp_sync;
 	int rc;
 
-	if (!stp_online) {
-		chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000);
-		return;
+	stp_sync = data;
+
+	if (xchg(&first, 1) == 1) {
+		/* Slave */
+		clock_sync_cpu(stp_sync);
+		return 0;
 	}
 
-	rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0);
-	if (rc)
-		return;
+	/* Wait until all other cpus entered the sync function. */
+	while (atomic_read(&stp_sync->cpus) != 0)
+		cpu_relax();
 
-	rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi));
-	if (rc || stp_info.c == 0)
-		return;
-
-	/*
-	 * Catch all other cpus and make them wait until we have
-	 * successfully synced the clock. smp_call_function will
-	 * return after all other cpus are in clock_sync_cpu_start.
-	 */
-	memset(&stp_sync, 0, sizeof(stp_sync));
-	preempt_disable();
-	smp_call_function(clock_sync_cpu_start, &stp_sync, 0);
-	local_irq_disable();
 	enable_sync_clock();
 
 	set_bit(CLOCK_SYNC_STP, &clock_sync_flags);
 	if (test_and_clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags))
-		schedule_work(&etr_work);
+		queue_work(time_sync_wq, &etr_work);
 
 	rc = 0;
 	if (stp_info.todoff[0] || stp_info.todoff[1] ||
@@ -1469,16 +1532,49 @@
 	}
 	if (rc) {
 		disable_sync_clock(NULL);
-		stp_sync.in_sync = -EAGAIN;
+		stp_sync->in_sync = -EAGAIN;
 		clear_bit(CLOCK_SYNC_STP, &clock_sync_flags);
 		if (etr_port0_online || etr_port1_online)
-			schedule_work(&etr_work);
+			queue_work(time_sync_wq, &etr_work);
 	} else
-		stp_sync.in_sync = 1;
+		stp_sync->in_sync = 1;
+	xchg(&first, 0);
+	return 0;
+}
 
-	local_irq_enable();
-	smp_call_function(clock_sync_cpu_end, NULL, 0);
-	preempt_enable();
+/*
+ * STP work. Check for the STP state and take over the clock
+ * synchronization if the STP clock source is usable.
+ */
+static void stp_work_fn(struct work_struct *work)
+{
+	struct clock_sync_data stp_sync;
+	int rc;
+
+	/* prevent multiple execution. */
+	mutex_lock(&stp_work_mutex);
+
+	if (!stp_online) {
+		chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000);
+		goto out_unlock;
+	}
+
+	rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0);
+	if (rc)
+		goto out_unlock;
+
+	rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi));
+	if (rc || stp_info.c == 0)
+		goto out_unlock;
+
+	memset(&stp_sync, 0, sizeof(stp_sync));
+	get_online_cpus();
+	atomic_set(&stp_sync.cpus, num_online_cpus() - 1);
+	stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map);
+	put_online_cpus();
+
+out_unlock:
+	mutex_unlock(&stp_work_mutex);
 }
 
 /*
@@ -1587,7 +1683,7 @@
 	if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags))
 		return -EOPNOTSUPP;
 	stp_online = value;
-	schedule_work(&stp_work);
+	queue_work(time_sync_wq, &stp_work);
 	return count;
 }
 
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index a947899..90e9ba1 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -3,6 +3,9 @@
  *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "cpu"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/init.h>
@@ -12,6 +15,7 @@
 #include <linux/workqueue.h>
 #include <linux/cpu.h>
 #include <linux/smp.h>
+#include <linux/cpuset.h>
 #include <asm/delay.h>
 #include <asm/s390_ext.h>
 #include <asm/sysinfo.h>
@@ -57,11 +61,11 @@
 	cpumask_t mask;
 };
 
+static int topology_enabled;
 static void topology_work_fn(struct work_struct *work);
 static struct tl_info *tl_info;
 static struct core_info core_info;
 static int machine_has_topology;
-static int machine_has_topology_irq;
 static struct timer_list topology_timer;
 static void set_topology_timer(void);
 static DECLARE_WORK(topology_work, topology_work_fn);
@@ -77,8 +81,8 @@
 	cpumask_t mask;
 
 	cpus_clear(mask);
-	if (!machine_has_topology)
-		return cpu_present_map;
+	if (!topology_enabled || !machine_has_topology)
+		return cpu_possible_map;
 	spin_lock_irqsave(&topology_lock, flags);
 	while (core) {
 		if (cpu_isset(cpu, core->mask)) {
@@ -168,7 +172,7 @@
 	int cpu;
 
 	mutex_lock(&smp_cpu_state_mutex);
-	for_each_present_cpu(cpu)
+	for_each_possible_cpu(cpu)
 		smp_cpu_polarization[cpu] = POLARIZATION_HRZ;
 	mutex_unlock(&smp_cpu_state_mutex);
 }
@@ -199,7 +203,7 @@
 		rc = ptf(PTF_HORIZONTAL);
 	if (rc)
 		return -EBUSY;
-	for_each_present_cpu(cpu)
+	for_each_possible_cpu(cpu)
 		smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN;
 	return rc;
 }
@@ -208,11 +212,11 @@
 {
 	int cpu;
 
-	for_each_present_cpu(cpu)
+	for_each_possible_cpu(cpu)
 		cpu_core_map[cpu] = cpu_coregroup_map(cpu);
 }
 
-void arch_update_cpu_topology(void)
+int arch_update_cpu_topology(void)
 {
 	struct tl_info *info = tl_info;
 	struct sys_device *sysdev;
@@ -221,7 +225,7 @@
 	if (!machine_has_topology) {
 		update_cpu_core_map();
 		topology_update_polarization_simple();
-		return;
+		return 0;
 	}
 	stsi(info, 15, 1, 2);
 	tl_to_cores(info);
@@ -230,11 +234,12 @@
 		sysdev = get_cpu_sysdev(cpu);
 		kobject_uevent(&sysdev->kobj, KOBJ_CHANGE);
 	}
+	return 1;
 }
 
 static void topology_work_fn(struct work_struct *work)
 {
-	arch_reinit_sched_domains();
+	rebuild_sched_domains();
 }
 
 void topology_schedule_update(void)
@@ -257,10 +262,14 @@
 	add_timer(&topology_timer);
 }
 
-static void topology_interrupt(__u16 code)
+static int __init early_parse_topology(char *p)
 {
-	schedule_work(&topology_work);
+	if (strncmp(p, "on", 2))
+		return 0;
+	topology_enabled = 1;
+	return 0;
 }
+early_param("topology", early_parse_topology);
 
 static int __init init_topology_update(void)
 {
@@ -272,14 +281,7 @@
 		goto out;
 	}
 	init_timer_deferrable(&topology_timer);
-	if (machine_has_topology_irq) {
-		rc = register_external_interrupt(0x2005, topology_interrupt);
-		if (rc)
-			goto out;
-		ctl_set_bit(0, 8);
-	}
-	else
-		set_topology_timer();
+	set_topology_timer();
 out:
 	update_cpu_core_map();
 	return rc;
@@ -300,9 +302,6 @@
 		return;
 	machine_has_topology = 1;
 
-	if (facility_bits & (1ULL << 51))
-		machine_has_topology_irq = 1;
-
 	tl_info = alloc_bootmem_pages(PAGE_SIZE);
 	info = tl_info;
 	stsi(info, 15, 1, 2);
@@ -311,7 +310,7 @@
 	for (i = 0; i < info->mnest - 2; i++)
 		nr_cores *= info->mag[NR_MAG - 3 - i];
 
-	printk(KERN_INFO "CPU topology:");
+	pr_info("The CPU configuration topology of the machine is:");
 	for (i = 0; i < NR_MAG; i++)
 		printk(" %d", info->mag[i]);
 	printk(" / %d\n", info->mnest);
@@ -326,5 +325,4 @@
 	return;
 error:
 	machine_has_topology = 0;
-	machine_has_topology_irq = 0;
 }
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
new file mode 100644
index 0000000..10a6cce
--- /dev/null
+++ b/arch/s390/kernel/vdso.c
@@ -0,0 +1,234 @@
+/*
+ * vdso setup for s390
+ *
+ *  Copyright IBM Corp. 2008
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/elf.h>
+#include <linux/security.h>
+#include <linux/bootmem.h>
+
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/sections.h>
+#include <asm/vdso.h>
+
+/* Max supported size for symbol names */
+#define MAX_SYMNAME	64
+
+#if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT)
+extern char vdso32_start, vdso32_end;
+static void *vdso32_kbase = &vdso32_start;
+static unsigned int vdso32_pages;
+static struct page **vdso32_pagelist;
+#endif
+
+#ifdef CONFIG_64BIT
+extern char vdso64_start, vdso64_end;
+static void *vdso64_kbase = &vdso64_start;
+static unsigned int vdso64_pages;
+static struct page **vdso64_pagelist;
+#endif /* CONFIG_64BIT */
+
+/*
+ * Should the kernel map a VDSO page into processes and pass its
+ * address down to glibc upon exec()?
+ */
+unsigned int __read_mostly vdso_enabled = 1;
+
+static int __init vdso_setup(char *s)
+{
+	vdso_enabled = simple_strtoul(s, NULL, 0);
+	return 1;
+}
+__setup("vdso=", vdso_setup);
+
+/*
+ * The vdso data page
+ */
+static union {
+	struct vdso_data	data;
+	u8			page[PAGE_SIZE];
+} vdso_data_store __attribute__((__section__(".data.page_aligned")));
+struct vdso_data *vdso_data = &vdso_data_store.data;
+
+/*
+ * This is called from binfmt_elf, we create the special vma for the
+ * vDSO and insert it into the mm struct tree
+ */
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+	struct mm_struct *mm = current->mm;
+	struct page **vdso_pagelist;
+	unsigned long vdso_pages;
+	unsigned long vdso_base;
+	int rc;
+
+	if (!vdso_enabled)
+		return 0;
+	/*
+	 * Only map the vdso for dynamically linked elf binaries.
+	 */
+	if (!uses_interp)
+		return 0;
+
+	vdso_base = mm->mmap_base;
+#ifdef CONFIG_64BIT
+	vdso_pagelist = vdso64_pagelist;
+	vdso_pages = vdso64_pages;
+#ifdef CONFIG_COMPAT
+	if (test_thread_flag(TIF_31BIT)) {
+		vdso_pagelist = vdso32_pagelist;
+		vdso_pages = vdso32_pages;
+	}
+#endif
+#else
+	vdso_pagelist = vdso32_pagelist;
+	vdso_pages = vdso32_pages;
+#endif
+
+	/*
+	 * vDSO has a problem and was disabled, just don't "enable" it for
+	 * the process
+	 */
+	if (vdso_pages == 0)
+		return 0;
+
+	current->mm->context.vdso_base = 0;
+
+	/*
+	 * pick a base address for the vDSO in process space. We try to put
+	 * it at vdso_base which is the "natural" base for it, but we might
+	 * fail and end up putting it elsewhere.
+	 */
+	down_write(&mm->mmap_sem);
+	vdso_base = get_unmapped_area(NULL, vdso_base,
+				      vdso_pages << PAGE_SHIFT, 0, 0);
+	if (IS_ERR_VALUE(vdso_base)) {
+		rc = vdso_base;
+		goto out_up;
+	}
+
+	/*
+	 * our vma flags don't have VM_WRITE so by default, the process
+	 * isn't allowed to write those pages.
+	 * gdb can break that with ptrace interface, and thus trigger COW
+	 * on those pages but it's then your responsibility to never do that
+	 * on the "data" page of the vDSO or you'll stop getting kernel
+	 * updates and your nice userland gettimeofday will be totally dead.
+	 * It's fine to use that for setting breakpoints in the vDSO code
+	 * pages though
+	 *
+	 * Make sure the vDSO gets into every core dump.
+	 * Dumping its contents makes post-mortem fully interpretable later
+	 * without matching up the same kernel and hardware config to see
+	 * what PC values meant.
+	 */
+	rc = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT,
+				     VM_READ|VM_EXEC|
+				     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+				     VM_ALWAYSDUMP,
+				     vdso_pagelist);
+	if (rc)
+		goto out_up;
+
+	/* Put vDSO base into mm struct */
+	current->mm->context.vdso_base = vdso_base;
+
+	up_write(&mm->mmap_sem);
+	return 0;
+
+out_up:
+	up_write(&mm->mmap_sem);
+	return rc;
+}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+	if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.vdso_base)
+		return "[vdso]";
+	return NULL;
+}
+
+static int __init vdso_init(void)
+{
+	int i;
+
+#if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT)
+	/* Calculate the size of the 32 bit vDSO */
+	vdso32_pages = ((&vdso32_end - &vdso32_start
+			 + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1;
+
+	/* Make sure pages are in the correct state */
+	vdso32_pagelist = kzalloc(sizeof(struct page *) * (vdso32_pages + 1),
+				  GFP_KERNEL);
+	BUG_ON(vdso32_pagelist == NULL);
+	for (i = 0; i < vdso32_pages - 1; i++) {
+		struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
+		ClearPageReserved(pg);
+		get_page(pg);
+		vdso32_pagelist[i] = pg;
+	}
+	vdso32_pagelist[vdso32_pages - 1] = virt_to_page(vdso_data);
+	vdso32_pagelist[vdso32_pages] = NULL;
+#endif
+
+#ifdef CONFIG_64BIT
+	/* Calculate the size of the 64 bit vDSO */
+	vdso64_pages = ((&vdso64_end - &vdso64_start
+			 + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1;
+
+	/* Make sure pages are in the correct state */
+	vdso64_pagelist = kzalloc(sizeof(struct page *) * (vdso64_pages + 1),
+				  GFP_KERNEL);
+	BUG_ON(vdso64_pagelist == NULL);
+	for (i = 0; i < vdso64_pages - 1; i++) {
+		struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE);
+		ClearPageReserved(pg);
+		get_page(pg);
+		vdso64_pagelist[i] = pg;
+	}
+	vdso64_pagelist[vdso64_pages - 1] = virt_to_page(vdso_data);
+	vdso64_pagelist[vdso64_pages] = NULL;
+#endif /* CONFIG_64BIT */
+
+	get_page(virt_to_page(vdso_data));
+
+	smp_wmb();
+
+	return 0;
+}
+arch_initcall(vdso_init);
+
+int in_gate_area_no_task(unsigned long addr)
+{
+	return 0;
+}
+
+int in_gate_area(struct task_struct *task, unsigned long addr)
+{
+	return 0;
+}
+
+struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+{
+	return NULL;
+}
diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile
new file mode 100644
index 0000000..ca78ad6
--- /dev/null
+++ b/arch/s390/kernel/vdso32/Makefile
@@ -0,0 +1,55 @@
+# List of files in the vdso, has to be asm only for now
+
+obj-vdso32 = gettimeofday.o clock_getres.o clock_gettime.o note.o
+
+# Build rules
+
+targets := $(obj-vdso32) vdso32.so vdso32.so.dbg
+obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
+
+KBUILD_AFLAGS_31 := $(filter-out -m64,$(KBUILD_AFLAGS))
+KBUILD_AFLAGS_31 += -m31 -s
+
+KBUILD_CFLAGS_31 := $(filter-out -m64,$(KBUILD_CFLAGS))
+KBUILD_CFLAGS_31 += -m31 -fPIC -shared -fno-common -fno-builtin
+KBUILD_CFLAGS_31 += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
+			$(call ld-option, -Wl$(comma)--hash-style=sysv)
+
+$(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_31)
+$(targets:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_31)
+
+obj-y += vdso32_wrapper.o
+extra-y += vdso32.lds
+CPPFLAGS_vdso32.lds += -P -C -U$(ARCH)
+
+# Force dependency (incbin is bad)
+$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so
+
+# link rule for the .so file, .lds has to be first
+$(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32)
+	$(call if_changed,vdso32ld)
+
+# strip rule for the .so file
+$(obj)/%.so: OBJCOPYFLAGS := -S
+$(obj)/%.so: $(obj)/%.so.dbg FORCE
+	$(call if_changed,objcopy)
+
+# assembly rules for the .S files
+$(obj-vdso32): %.o: %.S
+	$(call if_changed_dep,vdso32as)
+
+# actual build commands
+quiet_cmd_vdso32ld = VDSO32L $@
+      cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $^ -o $@
+quiet_cmd_vdso32as = VDSO32A $@
+      cmd_vdso32as = $(CC) $(a_flags) -c -o $@ $<
+
+# install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+      cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
+
+vdso32.so: $(obj)/vdso32.so.dbg
+	@mkdir -p $(MODLIB)/vdso
+	$(call cmd,vdso_install)
+
+vdso_install: vdso32.so
diff --git a/arch/s390/kernel/vdso32/clock_getres.S b/arch/s390/kernel/vdso32/clock_getres.S
new file mode 100644
index 0000000..9532c4e
--- /dev/null
+++ b/arch/s390/kernel/vdso32/clock_getres.S
@@ -0,0 +1,39 @@
+/*
+ * Userland implementation of clock_getres() for 32 bits processes in a
+ * s390 kernel for use in the vDSO
+ *
+ *  Copyright IBM Corp. 2008
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ */
+#include <asm/vdso.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+	.text
+	.align 4
+	.globl __kernel_clock_getres
+	.type  __kernel_clock_getres,@function
+__kernel_clock_getres:
+	.cfi_startproc
+	chi	%r2,CLOCK_REALTIME
+	je	0f
+	chi	%r2,CLOCK_MONOTONIC
+	jne	3f
+0:	ltr	%r3,%r3
+	jz	2f				/* res == NULL */
+	basr	%r1,0
+1:	l	%r0,4f-1b(%r1)
+	xc	0(4,%r3),0(%r3)			/* set tp->tv_sec to zero */
+	st	%r0,4(%r3)			/* store tp->tv_usec */
+2:	lhi	%r2,0
+	br	%r14
+3:	lhi	%r1,__NR_clock_getres		/* fallback to svc */
+	svc	0
+	br	%r14
+4:	.long	CLOCK_REALTIME_RES
+	.cfi_endproc
+	.size	__kernel_clock_getres,.-__kernel_clock_getres
diff --git a/arch/s390/kernel/vdso32/clock_gettime.S b/arch/s390/kernel/vdso32/clock_gettime.S
new file mode 100644
index 0000000..4a98909
--- /dev/null
+++ b/arch/s390/kernel/vdso32/clock_gettime.S
@@ -0,0 +1,128 @@
+/*
+ * Userland implementation of clock_gettime() for 32 bits processes in a
+ * s390 kernel for use in the vDSO
+ *
+ *  Copyright IBM Corp. 2008
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ */
+#include <asm/vdso.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+	.text
+	.align 4
+	.globl __kernel_clock_gettime
+	.type  __kernel_clock_gettime,@function
+__kernel_clock_gettime:
+	.cfi_startproc
+	basr	%r5,0
+0:	al	%r5,21f-0b(%r5)			/* get &_vdso_data */
+	chi	%r2,CLOCK_REALTIME
+	je	10f
+	chi	%r2,CLOCK_MONOTONIC
+	jne	19f
+
+	/* CLOCK_MONOTONIC */
+	ltr	%r3,%r3
+	jz	9f				/* tp == NULL */
+1:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
+	tml	%r4,0x0001			/* pending update ? loop */
+	jnz	1b
+	stck	24(%r15)			/* Store TOD clock */
+	lm	%r0,%r1,24(%r15)
+	s	%r0,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
+	sl	%r1,__VDSO_XTIME_STAMP+4(%r5)
+	brc	3,2f
+	ahi	%r0,-1
+2:	mhi	%r0,1000			/* cyc2ns(clock,cycle_delta) */
+	lr	%r2,%r0
+	lhi	%r0,1000
+	ltr	%r1,%r1
+	mr	%r0,%r0
+	jnm	3f
+	ahi	%r0,1000
+3:	alr	%r0,%r2
+	srdl	%r0,12
+	al	%r0,__VDSO_XTIME_NSEC(%r5)	/*  + xtime */
+	al	%r1,__VDSO_XTIME_NSEC+4(%r5)
+	brc	12,4f
+	ahi	%r0,1
+4:	l	%r2,__VDSO_XTIME_SEC+4(%r5)
+	al	%r0,__VDSO_WTOM_NSEC(%r5)	/*  + wall_to_monotonic */
+	al	%r1,__VDSO_WTOM_NSEC+4(%r5)
+	brc	12,5f
+	ahi	%r0,1
+5:	al	%r2,__VDSO_WTOM_SEC+4(%r5)
+	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
+	jne	1b
+	basr	%r5,0
+6:	ltr	%r0,%r0
+	jnz	7f
+	cl	%r1,20f-6b(%r5)
+	jl	8f
+7:	ahi	%r2,1
+	sl	%r1,20f-6b(%r5)
+	brc	3,6b
+	ahi	%r0,-1
+	j	6b
+8:	st	%r2,0(%r3)			/* store tp->tv_sec */
+	st	%r1,4(%r3)			/* store tp->tv_nsec */
+9:	lhi	%r2,0
+	br	%r14
+
+	/* CLOCK_REALTIME */
+10:	ltr	%r3,%r3				/* tp == NULL */
+	jz	18f
+11:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
+	tml	%r4,0x0001			/* pending update ? loop */
+	jnz	11b
+	stck	24(%r15)			/* Store TOD clock */
+	lm	%r0,%r1,24(%r15)
+	s	%r0,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
+	sl	%r1,__VDSO_XTIME_STAMP+4(%r5)
+	brc	3,12f
+	ahi	%r0,-1
+12:	mhi	%r0,1000			/* cyc2ns(clock,cycle_delta) */
+	lr	%r2,%r0
+	lhi	%r0,1000
+	ltr	%r1,%r1
+	mr	%r0,%r0
+	jnm	13f
+	ahi	%r0,1000
+13:	alr	%r0,%r2
+	srdl	%r0,12
+	al	%r0,__VDSO_XTIME_NSEC(%r5)	/*  + xtime */
+	al	%r1,__VDSO_XTIME_NSEC+4(%r5)
+	brc	12,14f
+	ahi	%r0,1
+14:	l	%r2,__VDSO_XTIME_SEC+4(%r5)
+	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
+	jne	11b
+	basr	%r5,0
+15:	ltr	%r0,%r0
+	jnz	16f
+	cl	%r1,20f-15b(%r5)
+	jl	17f
+16:	ahi	%r2,1
+	sl	%r1,20f-15b(%r5)
+	brc	3,15b
+	ahi	%r0,-1
+	j	15b
+17:	st	%r2,0(%r3)			/* store tp->tv_sec */
+	st	%r1,4(%r3)			/* store tp->tv_nsec */
+18:	lhi	%r2,0
+	br	%r14
+
+	/* Fallback to system call */
+19:	lhi	%r1,__NR_clock_gettime
+	svc	0
+	br	%r14
+
+20:	.long	1000000000
+21:	.long	_vdso_data - 0b
+	.cfi_endproc
+	.size	__kernel_clock_gettime,.-__kernel_clock_gettime
diff --git a/arch/s390/kernel/vdso32/gettimeofday.S b/arch/s390/kernel/vdso32/gettimeofday.S
new file mode 100644
index 0000000..c32f29c
--- /dev/null
+++ b/arch/s390/kernel/vdso32/gettimeofday.S
@@ -0,0 +1,82 @@
+/*
+ * Userland implementation of gettimeofday() for 32 bits processes in a
+ * s390 kernel for use in the vDSO
+ *
+ *  Copyright IBM Corp. 2008
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ */
+#include <asm/vdso.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+#include <asm/vdso.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+	.text
+	.align 4
+	.globl __kernel_gettimeofday
+	.type  __kernel_gettimeofday,@function
+__kernel_gettimeofday:
+	.cfi_startproc
+	basr	%r5,0
+0:	al	%r5,13f-0b(%r5)			/* get &_vdso_data */
+1:	ltr	%r3,%r3				/* check if tz is NULL */
+	je	2f
+	mvc	0(8,%r3),__VDSO_TIMEZONE(%r5)
+2:	ltr	%r2,%r2				/* check if tv is NULL */
+	je	10f
+	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
+	tml	%r4,0x0001			/* pending update ? loop */
+	jnz	1b
+	stck	24(%r15)			/* Store TOD clock */
+	lm	%r0,%r1,24(%r15)
+	s	%r0,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
+	sl	%r1,__VDSO_XTIME_STAMP+4(%r5)
+	brc	3,3f
+	ahi	%r0,-1
+3:	mhi	%r0,1000			/* cyc2ns(clock,cycle_delta) */
+	st	%r0,24(%r15)
+	lhi	%r0,1000
+	ltr	%r1,%r1
+	mr	%r0,%r0
+	jnm	4f
+	ahi	%r0,1000
+4:	al	%r0,24(%r15)
+	srdl	%r0,12
+	al	%r0,__VDSO_XTIME_NSEC(%r5)	/*  + xtime */
+	al	%r1,__VDSO_XTIME_NSEC+4(%r5)
+	brc	12,5f
+	ahi	%r0,1
+5:	mvc	24(4,%r15),__VDSO_XTIME_SEC+4(%r5)
+	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
+	jne	1b
+	l	%r4,24(%r15)			/* get tv_sec from stack */
+	basr	%r5,0
+6:	ltr	%r0,%r0
+	jnz	7f
+	cl	%r1,11f-6b(%r5)
+	jl	8f
+7:	ahi	%r4,1
+	sl	%r1,11f-6b(%r5)
+	brc	3,6b
+	ahi	%r0,-1
+	j	6b
+8:	st	%r4,0(%r2)			/* store tv->tv_sec */
+	ltr	%r1,%r1
+	m	%r0,12f-6b(%r5)
+	jnm	9f
+	al	%r0,12f-6b(%r5)
+9:	srl	%r0,6
+	st	%r0,4(%r2)			/* store tv->tv_usec */
+10:	slr	%r2,%r2
+	br	%r14
+11:	.long	1000000000
+12:	.long	274877907
+13:	.long	_vdso_data - 0b
+	.cfi_endproc
+	.size	__kernel_gettimeofday,.-__kernel_gettimeofday
diff --git a/arch/s390/kernel/vdso32/note.S b/arch/s390/kernel/vdso32/note.S
new file mode 100644
index 0000000..79a071e
--- /dev/null
+++ b/arch/s390/kernel/vdso32/note.S
@@ -0,0 +1,12 @@
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/elfnote.h>
+
+ELFNOTE_START(Linux, 0, "a")
+	.long LINUX_VERSION_CODE
+ELFNOTE_END
diff --git a/arch/s390/kernel/vdso32/vdso32.lds.S b/arch/s390/kernel/vdso32/vdso32.lds.S
new file mode 100644
index 0000000..a8c379f
--- /dev/null
+++ b/arch/s390/kernel/vdso32/vdso32.lds.S
@@ -0,0 +1,138 @@
+/*
+ * This is the infamous ld script for the 32 bits vdso
+ * library
+ */
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390")
+OUTPUT_ARCH(s390:31-bit)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = VDSO32_LBASE + SIZEOF_HEADERS;
+
+	.hash		: { *(.hash) }			:text
+	.gnu.hash	: { *(.gnu.hash) }
+	.dynsym		: { *(.dynsym) }
+	.dynstr		: { *(.dynstr) }
+	.gnu.version	: { *(.gnu.version) }
+	.gnu.version_d	: { *(.gnu.version_d) }
+	.gnu.version_r	: { *(.gnu.version_r) }
+
+	.note		: { *(.note.*) }		:text	:note
+
+	. = ALIGN(16);
+	.text		: {
+		*(.text .stub .text.* .gnu.linkonce.t.*)
+	} :text
+	PROVIDE(__etext = .);
+	PROVIDE(_etext = .);
+	PROVIDE(etext = .);
+
+	/*
+	 * Other stuff is appended to the text segment:
+	 */
+	.rodata		: { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+	.rodata1	: { *(.rodata1) }
+
+	.dynamic	: { *(.dynamic) }		:text	:dynamic
+
+	.eh_frame_hdr	: { *(.eh_frame_hdr) }		:text	:eh_frame_hdr
+	.eh_frame	: { KEEP (*(.eh_frame)) }	:text
+	.gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
+
+	.rela.dyn ALIGN(8) : { *(.rela.dyn) }
+	.got ALIGN(8)	: { *(.got .toc) }
+
+	_end = .;
+	PROVIDE(end = .);
+
+	/*
+	 * Stabs debugging sections are here too.
+	 */
+	.stab	       0 : { *(.stab) }
+	.stabstr       0 : { *(.stabstr) }
+	.stab.excl     0 : { *(.stab.excl) }
+	.stab.exclstr  0 : { *(.stab.exclstr) }
+	.stab.index    0 : { *(.stab.index) }
+	.stab.indexstr 0 : { *(.stab.indexstr) }
+	.comment       0 : { *(.comment) }
+
+	/*
+	 * DWARF debug sections.
+	 * Symbols in the DWARF debugging sections are relative to the
+	 * beginning of the section so we begin them at 0.
+	 */
+	/* DWARF 1 */
+	.debug		0 : { *(.debug) }
+	.line		0 : { *(.line) }
+	/* GNU DWARF 1 extensions */
+	.debug_srcinfo	0 : { *(.debug_srcinfo) }
+	.debug_sfnames	0 : { *(.debug_sfnames) }
+	/* DWARF 1.1 and DWARF 2 */
+	.debug_aranges	0 : { *(.debug_aranges) }
+	.debug_pubnames 0 : { *(.debug_pubnames) }
+	/* DWARF 2 */
+	.debug_info	0 : { *(.debug_info .gnu.linkonce.wi.*) }
+	.debug_abbrev	0 : { *(.debug_abbrev) }
+	.debug_line	0 : { *(.debug_line) }
+	.debug_frame	0 : { *(.debug_frame) }
+	.debug_str	0 : { *(.debug_str) }
+	.debug_loc	0 : { *(.debug_loc) }
+	.debug_macinfo	0 : { *(.debug_macinfo) }
+	/* SGI/MIPS DWARF 2 extensions */
+	.debug_weaknames 0 : { *(.debug_weaknames) }
+	.debug_funcnames 0 : { *(.debug_funcnames) }
+	.debug_typenames 0 : { *(.debug_typenames) }
+	.debug_varnames  0 : { *(.debug_varnames) }
+	/* DWARF 3 */
+	.debug_pubtypes 0 : { *(.debug_pubtypes) }
+	.debug_ranges	0 : { *(.debug_ranges) }
+	.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+
+	. = ALIGN(4096);
+	PROVIDE(_vdso_data = .);
+
+	/DISCARD/	: {
+		*(.note.GNU-stack)
+		*(.branch_lt)
+		*(.data .data.* .gnu.linkonce.d.* .sdata*)
+		*(.bss .sbss .dynbss .dynsbss)
+	}
+}
+
+/*
+ * Very old versions of ld do not recognize this name token; use the constant.
+ */
+#define PT_GNU_EH_FRAME	0x6474e550
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+	text		PT_LOAD FILEHDR PHDRS FLAGS(5);	/* PF_R|PF_X */
+	dynamic		PT_DYNAMIC FLAGS(4);		/* PF_R */
+	note		PT_NOTE FLAGS(4);		/* PF_R */
+	eh_frame_hdr	PT_GNU_EH_FRAME;
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+	VDSO_VERSION_STRING {
+	global:
+		/*
+		 * Has to be there for the kernel to find
+		 */
+		__kernel_gettimeofday;
+		__kernel_clock_gettime;
+		__kernel_clock_getres;
+
+	local: *;
+	};
+}
diff --git a/arch/s390/kernel/vdso32/vdso32_wrapper.S b/arch/s390/kernel/vdso32/vdso32_wrapper.S
new file mode 100644
index 0000000..61639a8
--- /dev/null
+++ b/arch/s390/kernel/vdso32/vdso32_wrapper.S
@@ -0,0 +1,13 @@
+#include <linux/init.h>
+#include <asm/page.h>
+
+	.section ".data.page_aligned"
+
+	.globl vdso32_start, vdso32_end
+	.balign PAGE_SIZE
+vdso32_start:
+	.incbin "arch/s390/kernel/vdso32/vdso32.so"
+	.balign PAGE_SIZE
+vdso32_end:
+
+	.previous
diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile
new file mode 100644
index 0000000..6fc8e82
--- /dev/null
+++ b/arch/s390/kernel/vdso64/Makefile
@@ -0,0 +1,55 @@
+# List of files in the vdso, has to be asm only for now
+
+obj-vdso64 = gettimeofday.o clock_getres.o clock_gettime.o note.o
+
+# Build rules
+
+targets := $(obj-vdso64) vdso64.so vdso64.so.dbg
+obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64))
+
+KBUILD_AFLAGS_64 := $(filter-out -m64,$(KBUILD_AFLAGS))
+KBUILD_AFLAGS_64 += -m64 -s
+
+KBUILD_CFLAGS_64 := $(filter-out -m64,$(KBUILD_CFLAGS))
+KBUILD_CFLAGS_64 += -m64 -fPIC -shared -fno-common -fno-builtin
+KBUILD_CFLAGS_64 += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
+			$(call ld-option, -Wl$(comma)--hash-style=sysv)
+
+$(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_64)
+$(targets:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_64)
+
+obj-y += vdso64_wrapper.o
+extra-y += vdso64.lds
+CPPFLAGS_vdso64.lds += -P -C -U$(ARCH)
+
+# Force dependency (incbin is bad)
+$(obj)/vdso64_wrapper.o : $(obj)/vdso64.so
+
+# link rule for the .so file, .lds has to be first
+$(obj)/vdso64.so.dbg: $(src)/vdso64.lds $(obj-vdso64)
+	$(call if_changed,vdso64ld)
+
+# strip rule for the .so file
+$(obj)/%.so: OBJCOPYFLAGS := -S
+$(obj)/%.so: $(obj)/%.so.dbg FORCE
+	$(call if_changed,objcopy)
+
+# assembly rules for the .S files
+$(obj-vdso64): %.o: %.S
+	$(call if_changed_dep,vdso64as)
+
+# actual build commands
+quiet_cmd_vdso64ld = VDSO64L $@
+      cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $^ -o $@
+quiet_cmd_vdso64as = VDSO64A $@
+      cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $<
+
+# install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+      cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
+
+vdso64.so: $(obj)/vdso64.so.dbg
+	@mkdir -p $(MODLIB)/vdso
+	$(call cmd,vdso_install)
+
+vdso_install: vdso64.so
diff --git a/arch/s390/kernel/vdso64/clock_getres.S b/arch/s390/kernel/vdso64/clock_getres.S
new file mode 100644
index 0000000..488e31a
--- /dev/null
+++ b/arch/s390/kernel/vdso64/clock_getres.S
@@ -0,0 +1,39 @@
+/*
+ * Userland implementation of clock_getres() for 64 bits processes in a
+ * s390 kernel for use in the vDSO
+ *
+ *  Copyright IBM Corp. 2008
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ */
+#include <asm/vdso.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+	.text
+	.align 4
+	.globl __kernel_clock_getres
+	.type  __kernel_clock_getres,@function
+__kernel_clock_getres:
+	.cfi_startproc
+	cghi	%r2,CLOCK_REALTIME
+	je	0f
+	cghi	%r2,CLOCK_MONOTONIC
+	jne	2f
+0:	ltgr	%r3,%r3
+	jz	1f				/* res == NULL */
+	larl	%r1,3f
+	lg	%r0,0(%r1)
+	xc	0(8,%r3),0(%r3)			/* set tp->tv_sec to zero */
+	stg	%r0,8(%r3)			/* store tp->tv_usec */
+1:	lghi	%r2,0
+	br	%r14
+2:	lghi	%r1,__NR_clock_getres		/* fallback to svc */
+	svc	0
+	br	%r14
+3:	.quad	CLOCK_REALTIME_RES
+	.cfi_endproc
+	.size	__kernel_clock_getres,.-__kernel_clock_getres
diff --git a/arch/s390/kernel/vdso64/clock_gettime.S b/arch/s390/kernel/vdso64/clock_gettime.S
new file mode 100644
index 0000000..738a410
--- /dev/null
+++ b/arch/s390/kernel/vdso64/clock_gettime.S
@@ -0,0 +1,89 @@
+/*
+ * Userland implementation of clock_gettime() for 64 bits processes in a
+ * s390 kernel for use in the vDSO
+ *
+ *  Copyright IBM Corp. 2008
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ */
+#include <asm/vdso.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+	.text
+	.align 4
+	.globl __kernel_clock_gettime
+	.type  __kernel_clock_gettime,@function
+__kernel_clock_gettime:
+	.cfi_startproc
+	larl	%r5,_vdso_data
+	cghi	%r2,CLOCK_REALTIME
+	je	4f
+	cghi	%r2,CLOCK_MONOTONIC
+	jne	9f
+
+	/* CLOCK_MONOTONIC */
+	ltgr	%r3,%r3
+	jz	3f				/* tp == NULL */
+0:	lg	%r4,__VDSO_UPD_COUNT(%r5)	/* load update counter */
+	tmll	%r4,0x0001			/* pending update ? loop */
+	jnz	0b
+	stck	48(%r15)			/* Store TOD clock */
+	lg	%r1,48(%r15)
+	sg	%r1,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
+	mghi	%r1,1000
+	srlg	%r1,%r1,12			/* cyc2ns(clock,cycle_delta) */
+	alg	%r1,__VDSO_XTIME_NSEC(%r5)	/*  + xtime */
+	lg	%r0,__VDSO_XTIME_SEC(%r5)
+	alg	%r1,__VDSO_WTOM_NSEC(%r5)	/*  + wall_to_monotonic */
+	alg	%r0,__VDSO_WTOM_SEC(%r5)
+	clg	%r4,__VDSO_UPD_COUNT(%r5)	/* check update counter */
+	jne	0b
+	larl	%r5,10f
+1:	clg	%r1,0(%r5)
+	jl	2f
+	slg	%r1,0(%r5)
+	aghi	%r0,1
+	j	1b
+2:	stg	%r0,0(%r3)			/* store tp->tv_sec */
+	stg	%r1,8(%r3)			/* store tp->tv_nsec */
+3:	lghi	%r2,0
+	br	%r14
+
+	/* CLOCK_REALTIME */
+4:	ltr	%r3,%r3				/* tp == NULL */
+	jz	8f
+5:	lg	%r4,__VDSO_UPD_COUNT(%r5)	/* load update counter */
+	tmll	%r4,0x0001			/* pending update ? loop */
+	jnz	5b
+	stck	48(%r15)			/* Store TOD clock */
+	lg	%r1,48(%r15)
+	sg	%r1,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
+	mghi	%r1,1000
+	srlg	%r1,%r1,12			/* cyc2ns(clock,cycle_delta) */
+	alg	%r1,__VDSO_XTIME_NSEC(%r5)	/*  + xtime */
+	lg	%r0,__VDSO_XTIME_SEC(%r5)
+	clg	%r4,__VDSO_UPD_COUNT(%r5)	/* check update counter */
+	jne	5b
+	larl	%r5,10f
+6:	clg	%r1,0(%r5)
+	jl	7f
+	slg	%r1,0(%r5)
+	aghi	%r0,1
+	j	6b
+7:	stg	%r0,0(%r3)			/* store tp->tv_sec */
+	stg	%r1,8(%r3)			/* store tp->tv_nsec */
+8:	lghi	%r2,0
+	br	%r14
+
+	/* Fallback to system call */
+9:	lghi	%r1,__NR_clock_gettime
+	svc	0
+	br	%r14
+
+10:	.quad	1000000000
+	.cfi_endproc
+	.size	__kernel_clock_gettime,.-__kernel_clock_gettime
diff --git a/arch/s390/kernel/vdso64/gettimeofday.S b/arch/s390/kernel/vdso64/gettimeofday.S
new file mode 100644
index 0000000..f873e75
--- /dev/null
+++ b/arch/s390/kernel/vdso64/gettimeofday.S
@@ -0,0 +1,56 @@
+/*
+ * Userland implementation of gettimeofday() for 64 bits processes in a
+ * s390 kernel for use in the vDSO
+ *
+ *  Copyright IBM Corp. 2008
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ */
+#include <asm/vdso.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+	.text
+	.align 4
+	.globl __kernel_gettimeofday
+	.type  __kernel_gettimeofday,@function
+__kernel_gettimeofday:
+	.cfi_startproc
+	larl	%r5,_vdso_data
+0:	ltgr	%r3,%r3				/* check if tz is NULL */
+	je	1f
+	mvc	0(8,%r3),__VDSO_TIMEZONE(%r5)
+1:	ltgr	%r2,%r2				/* check if tv is NULL */
+	je	4f
+	lg	%r4,__VDSO_UPD_COUNT(%r5)	/* load update counter */
+	tmll	%r4,0x0001			/* pending update ? loop */
+	jnz	0b
+	stck	48(%r15)			/* Store TOD clock */
+	lg	%r1,48(%r15)
+	sg	%r1,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
+	mghi	%r1,1000
+	srlg	%r1,%r1,12			/* cyc2ns(clock,cycle_delta) */
+	alg	%r1,__VDSO_XTIME_NSEC(%r5)	/*  + xtime.tv_nsec */
+	lg	%r0,__VDSO_XTIME_SEC(%r5)	/* xtime.tv_sec */
+	clg	%r4,__VDSO_UPD_COUNT(%r5)	/* check update counter */
+	jne	0b
+	larl	%r5,5f
+2:	clg	%r1,0(%r5)
+	jl	3f
+	slg	%r1,0(%r5)
+	aghi	%r0,1
+	j	2b
+3:	stg	%r0,0(%r2)			/* store tv->tv_sec */
+	slgr	%r0,%r0				/* tv_nsec -> tv_usec */
+	ml	%r0,8(%r5)
+	srlg	%r0,%r0,6
+	stg	%r0,8(%r2)			/* store tv->tv_usec */
+4:	lghi	%r2,0
+	br	%r14
+5:	.quad	1000000000
+	.long	274877907
+	.cfi_endproc
+	.size	__kernel_gettimeofday,.-__kernel_gettimeofday
diff --git a/arch/s390/kernel/vdso64/note.S b/arch/s390/kernel/vdso64/note.S
new file mode 100644
index 0000000..79a071e
--- /dev/null
+++ b/arch/s390/kernel/vdso64/note.S
@@ -0,0 +1,12 @@
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/elfnote.h>
+
+ELFNOTE_START(Linux, 0, "a")
+	.long LINUX_VERSION_CODE
+ELFNOTE_END
diff --git a/arch/s390/kernel/vdso64/vdso64.lds.S b/arch/s390/kernel/vdso64/vdso64.lds.S
new file mode 100644
index 0000000..9f5979d
--- /dev/null
+++ b/arch/s390/kernel/vdso64/vdso64.lds.S
@@ -0,0 +1,138 @@
+/*
+ * This is the infamous ld script for the 64 bits vdso
+ * library
+ */
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
+OUTPUT_ARCH(s390:64-bit)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = VDSO64_LBASE + SIZEOF_HEADERS;
+
+	.hash		: { *(.hash) }			:text
+	.gnu.hash	: { *(.gnu.hash) }
+	.dynsym		: { *(.dynsym) }
+	.dynstr		: { *(.dynstr) }
+	.gnu.version	: { *(.gnu.version) }
+	.gnu.version_d	: { *(.gnu.version_d) }
+	.gnu.version_r	: { *(.gnu.version_r) }
+
+	.note		: { *(.note.*) }		:text	:note
+
+	. = ALIGN(16);
+	.text		: {
+		*(.text .stub .text.* .gnu.linkonce.t.*)
+	} :text
+	PROVIDE(__etext = .);
+	PROVIDE(_etext = .);
+	PROVIDE(etext = .);
+
+	/*
+	 * Other stuff is appended to the text segment:
+	 */
+	.rodata		: { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+	.rodata1	: { *(.rodata1) }
+
+	.dynamic	: { *(.dynamic) }		:text	:dynamic
+
+	.eh_frame_hdr	: { *(.eh_frame_hdr) }		:text	:eh_frame_hdr
+	.eh_frame	: { KEEP (*(.eh_frame)) }	:text
+	.gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
+
+	.rela.dyn ALIGN(8) : { *(.rela.dyn) }
+	.got ALIGN(8)	: { *(.got .toc) }
+
+	_end = .;
+	PROVIDE(end = .);
+
+	/*
+	 * Stabs debugging sections are here too.
+	 */
+	.stab	       0 : { *(.stab) }
+	.stabstr       0 : { *(.stabstr) }
+	.stab.excl     0 : { *(.stab.excl) }
+	.stab.exclstr  0 : { *(.stab.exclstr) }
+	.stab.index    0 : { *(.stab.index) }
+	.stab.indexstr 0 : { *(.stab.indexstr) }
+	.comment       0 : { *(.comment) }
+
+	/*
+	 * DWARF debug sections.
+	 * Symbols in the DWARF debugging sections are relative to the
+	 * beginning of the section so we begin them at 0.
+	 */
+	/* DWARF 1 */
+	.debug		0 : { *(.debug) }
+	.line		0 : { *(.line) }
+	/* GNU DWARF 1 extensions */
+	.debug_srcinfo	0 : { *(.debug_srcinfo) }
+	.debug_sfnames	0 : { *(.debug_sfnames) }
+	/* DWARF 1.1 and DWARF 2 */
+	.debug_aranges	0 : { *(.debug_aranges) }
+	.debug_pubnames 0 : { *(.debug_pubnames) }
+	/* DWARF 2 */
+	.debug_info	0 : { *(.debug_info .gnu.linkonce.wi.*) }
+	.debug_abbrev	0 : { *(.debug_abbrev) }
+	.debug_line	0 : { *(.debug_line) }
+	.debug_frame	0 : { *(.debug_frame) }
+	.debug_str	0 : { *(.debug_str) }
+	.debug_loc	0 : { *(.debug_loc) }
+	.debug_macinfo	0 : { *(.debug_macinfo) }
+	/* SGI/MIPS DWARF 2 extensions */
+	.debug_weaknames 0 : { *(.debug_weaknames) }
+	.debug_funcnames 0 : { *(.debug_funcnames) }
+	.debug_typenames 0 : { *(.debug_typenames) }
+	.debug_varnames  0 : { *(.debug_varnames) }
+	/* DWARF 3 */
+	.debug_pubtypes 0 : { *(.debug_pubtypes) }
+	.debug_ranges	0 : { *(.debug_ranges) }
+	.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+
+	. = ALIGN(4096);
+	PROVIDE(_vdso_data = .);
+
+	/DISCARD/	: {
+		*(.note.GNU-stack)
+		*(.branch_lt)
+		*(.data .data.* .gnu.linkonce.d.* .sdata*)
+		*(.bss .sbss .dynbss .dynsbss)
+	}
+}
+
+/*
+ * Very old versions of ld do not recognize this name token; use the constant.
+ */
+#define PT_GNU_EH_FRAME	0x6474e550
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+	text		PT_LOAD FILEHDR PHDRS FLAGS(5);	/* PF_R|PF_X */
+	dynamic		PT_DYNAMIC FLAGS(4);		/* PF_R */
+	note		PT_NOTE FLAGS(4);		/* PF_R */
+	eh_frame_hdr	PT_GNU_EH_FRAME;
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+	VDSO_VERSION_STRING {
+	global:
+		/*
+		 * Has to be there for the kernel to find
+		 */
+		__kernel_gettimeofday;
+		__kernel_clock_gettime;
+		__kernel_clock_getres;
+
+	local: *;
+	};
+}
diff --git a/arch/s390/kernel/vdso64/vdso64_wrapper.S b/arch/s390/kernel/vdso64/vdso64_wrapper.S
new file mode 100644
index 0000000..d8e2ac1
--- /dev/null
+++ b/arch/s390/kernel/vdso64/vdso64_wrapper.S
@@ -0,0 +1,13 @@
+#include <linux/init.h>
+#include <asm/page.h>
+
+	.section ".data.page_aligned"
+
+	.globl vdso64_start, vdso64_end
+	.balign PAGE_SIZE
+vdso64_start:
+	.incbin "arch/s390/kernel/vdso64/vdso64.so"
+	.balign PAGE_SIZE
+vdso64_end:
+
+	.previous
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index 0fa5dc5..75a6e62 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -27,7 +27,6 @@
 static ext_int_info_t ext_int_info_timer;
 static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 /*
  * Update process times based on virtual cpu times stored by entry.S
  * to the lowcore fields user_timer, system_timer & steal_clock.
@@ -125,16 +124,6 @@
 	/* store expire time for this CPU timer */
 	__get_cpu_var(virt_cpu_timer).to_expire = expires;
 }
-#else
-static inline void set_vtimer(__u64 expires)
-{
-	S390_lowcore.last_update_timer = expires;
-	asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
-
-	/* store expire time for this CPU timer */
-	__get_cpu_var(virt_cpu_timer).to_expire = expires;
-}
-#endif
 
 void vtime_start_cpu_timer(void)
 {
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index 580fc64..5c84571 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -7,6 +7,9 @@
  * (C) IBM Corporation 2002-2004
  */
 
+#define KMSG_COMPONENT "extmem"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/spinlock.h>
@@ -24,19 +27,6 @@
 #include <asm/cpcmd.h>
 #include <asm/setup.h>
 
-#define DCSS_DEBUG	/* Debug messages on/off */
-
-#define DCSS_NAME "extmem"
-#ifdef DCSS_DEBUG
-#define PRINT_DEBUG(x...)	printk(KERN_DEBUG DCSS_NAME " debug:" x)
-#else
-#define PRINT_DEBUG(x...)   do {} while (0)
-#endif
-#define PRINT_INFO(x...)	printk(KERN_INFO DCSS_NAME " info:" x)
-#define PRINT_WARN(x...)	printk(KERN_WARNING DCSS_NAME " warning:" x)
-#define PRINT_ERR(x...)		printk(KERN_ERR DCSS_NAME " error:" x)
-
-
 #define DCSS_LOADSHR    0x00
 #define DCSS_LOADNSR    0x04
 #define DCSS_PURGESEG   0x08
@@ -286,7 +276,7 @@
 		goto out_free;
 	}
 	if (diag_cc > 1) {
-		PRINT_WARN ("segment_type: diag returned error %ld\n", vmrc);
+		pr_warning("Querying a DCSS type failed with rc=%ld\n", vmrc);
 		rc = dcss_diag_translate_rc (vmrc);
 		goto out_free;
 	}
@@ -368,7 +358,6 @@
  * -EIO     : could not perform query diagnose
  * -ENOENT  : no such segment
  * -ENOTSUPP: multi-part segment cannot be used with linux
- * -ENOSPC  : segment cannot be used (overlaps with storage)
  * -ENOMEM  : out of memory
  * 0 .. 6   : type of segment as defined in include/asm-s390/extmem.h
  */
@@ -480,9 +469,8 @@
 		goto out_resource;
 	}
 	if (diag_cc > 1) {
-		PRINT_WARN ("segment_load: could not load segment %s - "
-				"diag returned error (%ld)\n",
-				name, end_addr);
+		pr_warning("Loading DCSS %s failed with rc=%ld\n", name,
+			   end_addr);
 		rc = dcss_diag_translate_rc(end_addr);
 		dcss_diag(&purgeseg_scode, seg->dcss_name,
 				&dummy, &dummy);
@@ -496,15 +484,13 @@
 	*addr = seg->start_addr;
 	*end  = seg->end;
 	if (do_nonshared)
-		PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
-				"type %s in non-shared mode\n", name,
-				(void*)seg->start_addr, (void*)seg->end,
-				segtype_string[seg->vm_segtype]);
+		pr_info("DCSS %s of range %p to %p and type %s loaded as "
+			"exclusive-writable\n", name, (void*) seg->start_addr,
+			(void*) seg->end, segtype_string[seg->vm_segtype]);
 	else {
-		PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
-				"type %s in shared mode\n", name,
-				(void*)seg->start_addr, (void*)seg->end,
-				segtype_string[seg->vm_segtype]);
+		pr_info("DCSS %s of range %p to %p and type %s loaded in "
+			"shared access mode\n", name, (void*) seg->start_addr,
+			(void*) seg->end, segtype_string[seg->vm_segtype]);
 	}
 	goto out;
  out_resource:
@@ -593,14 +579,14 @@
 		goto out_unlock;
 	}
 	if (do_nonshared == seg->do_nonshared) {
-		PRINT_INFO ("segment_modify_shared: not reloading segment %s"
-				" - already in requested mode\n",name);
+		pr_info("DCSS %s is already in the requested access "
+			"mode\n", name);
 		rc = 0;
 		goto out_unlock;
 	}
 	if (atomic_read (&seg->ref_count) != 1) {
-		PRINT_WARN ("segment_modify_shared: not reloading segment %s - "
-				"segment is in use by other driver(s)\n",name);
+		pr_warning("DCSS %s is in use and cannot be reloaded\n",
+			   name);
 		rc = -EAGAIN;
 		goto out_unlock;
 	}
@@ -613,8 +599,8 @@
 			seg->res->flags |= IORESOURCE_READONLY;
 
 	if (request_resource(&iomem_resource, seg->res)) {
-		PRINT_WARN("segment_modify_shared: could not reload segment %s"
-			   " - overlapping resources\n", name);
+		pr_warning("DCSS %s overlaps with used memory resources "
+			   "and cannot be reloaded\n", name);
 		rc = -EBUSY;
 		kfree(seg->res);
 		goto out_del_mem;
@@ -632,9 +618,8 @@
 		goto out_del_res;
 	}
 	if (diag_cc > 1) {
-		PRINT_WARN ("segment_modify_shared: could not reload segment %s"
-				" - diag returned error (%ld)\n",
-				name, end_addr);
+		pr_warning("Reloading DCSS %s failed with rc=%ld\n", name,
+			   end_addr);
 		rc = dcss_diag_translate_rc(end_addr);
 		goto out_del_res;
 	}
@@ -673,8 +658,7 @@
 	mutex_lock(&dcss_lock);
 	seg = segment_by_name (name);
 	if (seg == NULL) {
-		PRINT_ERR ("could not find segment %s in segment_unload, "
-				"please report to linux390@de.ibm.com\n",name);
+		pr_err("Unloading unknown DCSS %s failed\n", name);
 		goto out_unlock;
 	}
 	if (atomic_dec_return(&seg->ref_count) != 0)
@@ -709,8 +693,7 @@
 	seg = segment_by_name (name);
 
 	if (seg == NULL) {
-		PRINT_ERR("could not find segment %s in segment_save, please "
-			  "report to linux390@de.ibm.com\n", name);
+		pr_err("Saving unknown DCSS %s failed\n", name);
 		goto out;
 	}
 
@@ -727,14 +710,14 @@
 	response = 0;
 	cpcmd(cmd1, NULL, 0, &response);
 	if (response) {
-		PRINT_ERR("segment_save: DEFSEG failed with response code %i\n",
-			  response);
+		pr_err("Saving a DCSS failed with DEFSEG response code "
+		       "%i\n", response);
 		goto out;
 	}
 	cpcmd(cmd2, NULL, 0, &response);
 	if (response) {
-		PRINT_ERR("segment_save: SAVESEG failed with response code %i\n",
-			  response);
+		pr_err("Saving a DCSS failed with SAVESEG response code "
+		       "%i\n", response);
 		goto out;
 	}
 out:
@@ -749,44 +732,41 @@
 {
 	switch (rc) {
 	case -ENOENT:
-		PRINT_WARN("cannot load/query segment %s, "
-			   "does not exist\n", seg_name);
+		pr_err("DCSS %s cannot be loaded or queried\n", seg_name);
 		break;
 	case -ENOSYS:
-		PRINT_WARN("cannot load/query segment %s, "
-			   "not running on VM\n", seg_name);
+		pr_err("DCSS %s cannot be loaded or queried without "
+		       "z/VM\n", seg_name);
 		break;
 	case -EIO:
-		PRINT_WARN("cannot load/query segment %s, "
-			   "hardware error\n", seg_name);
+		pr_err("Loading or querying DCSS %s resulted in a "
+		       "hardware error\n", seg_name);
 		break;
 	case -ENOTSUPP:
-		PRINT_WARN("cannot load/query segment %s, "
-			   "is a multi-part segment\n", seg_name);
+		pr_err("DCSS %s has multiple page ranges and cannot be "
+		       "loaded or queried\n", seg_name);
 		break;
 	case -ENOSPC:
-		PRINT_WARN("cannot load/query segment %s, "
-			   "overlaps with storage\n", seg_name);
+		pr_err("DCSS %s overlaps with used storage and cannot "
+		       "be loaded\n", seg_name);
 		break;
 	case -EBUSY:
-		PRINT_WARN("cannot load/query segment %s, "
-			   "overlaps with already loaded dcss\n", seg_name);
+		pr_err("%s needs used memory resources and cannot be "
+		       "loaded or queried\n", seg_name);
 		break;
 	case -EPERM:
-		PRINT_WARN("cannot load/query segment %s, "
-			   "already loaded in incompatible mode\n", seg_name);
+		pr_err("DCSS %s is already loaded in a different access "
+		       "mode\n", seg_name);
 		break;
 	case -ENOMEM:
-		PRINT_WARN("cannot load/query segment %s, "
-			   "out of memory\n", seg_name);
+		pr_err("There is not enough memory to load or query "
+		       "DCSS %s\n", seg_name);
 		break;
 	case -ERANGE:
-		PRINT_WARN("cannot load/query segment %s, "
-			   "exceeds kernel mapping range\n", seg_name);
+		pr_err("DCSS %s exceeds the kernel mapping range (%lu) "
+		       "and cannot be loaded\n", seg_name, VMEM_MAX_PHYS);
 		break;
 	default:
-		PRINT_WARN("cannot load/query segment %s, "
-			   "return value %i\n", seg_name, rc);
 		break;
 	}
 }
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 5c9cbfc..f32a519 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -13,6 +13,7 @@
 	select HAVE_OPROFILE
 	select HAVE_GENERIC_DMA_COHERENT
 	select HAVE_IOREMAP_PROT if MMU
+	select HAVE_ARCH_TRACEHOOK
 	help
 	  The SuperH is a RISC processor targeted for use in embedded systems
 	  and consumer electronics; it was also used in the Sega Dreamcast
@@ -23,8 +24,10 @@
 	def_bool !SUPERH64
 	select HAVE_KPROBES
 	select HAVE_KRETPROBES
-	select HAVE_ARCH_TRACEHOOK
 	select HAVE_FUNCTION_TRACER
+	select HAVE_FTRACE_MCOUNT_RECORD
+	select HAVE_DYNAMIC_FTRACE
+	select HAVE_ARCH_KGDB
 
 config SUPERH64
 	def_bool y if CPU_SH5
@@ -55,8 +58,6 @@
 
 config GENERIC_HARDIRQS_NO__DO_IRQ
 	def_bool y
-	depends on SUPERH32 && (!SH_DREAMCAST && !SH_SH4202_MICRODEV && \
-				!SH_7751_SYSTEMH && !HD64461)
 
 config GENERIC_IRQ_PROBE
 	def_bool y
@@ -85,10 +86,17 @@
 
 config SYS_SUPPORTS_PM
 	bool
+	depends on !SMP
+
+config ARCH_SUSPEND_POSSIBLE
+	def_bool n
+
+config ARCH_HIBERNATION_POSSIBLE
+	def_bool n
 
 config SYS_SUPPORTS_APM_EMULATION
 	bool
-	select SYS_SUPPORTS_PM
+	select ARCH_SUSPEND_POSSIBLE
 
 config SYS_SUPPORTS_SMP
 	bool
@@ -183,6 +191,11 @@
 
 # SH-2A Processor Support
 
+config CPU_SUBTYPE_SH7201
+	bool "Support SH7201 processor"
+	select CPU_SH2A
+	select CPU_HAS_FPU
+ 
 config CPU_SUBTYPE_SH7203
 	bool "Support SH7203 processor"
 	select CPU_SH2A
@@ -456,8 +469,12 @@
 	depends on CPU_FREQ
 	select CPU_FREQ_TABLE
 	help
-	  This adds the cpufreq driver for SuperH. At present, only
-	  the SH-4 is supported.
+	  This adds the cpufreq driver for SuperH. Any CPU that supports
+	  clock rate rounding through the clock framework can use this
+	  driver. While it will make the kernel slightly larger, this is
+	  harmless for CPUs that don't support rate rounding. The driver
+	  will also generate a notice in the boot log before disabling
+	  itself if the CPU in question is not capable of rate rounding.
 
 	  For details, take a look at <file:Documentation/cpu-freq>.
 
@@ -469,9 +486,6 @@
 
 endmenu
 
-config ISA_DMA_API
-	bool
-
 menu "Kernel features"
 
 source kernel/Kconfig.hz
@@ -688,49 +702,6 @@
          Dreamcast with a serial line terminal or a remote network
          connection.
 
-config CF_ENABLER
-	bool "Compact Flash Enabler support"
-	depends on SOLUTION_ENGINE || SH_SH03
-	---help---
-	  Compact Flash is a small, removable mass storage device introduced
-	  in 1994 originally as a PCMCIA device.  If you say `Y' here, you
-	  compile in support for Compact Flash devices directly connected to
-	  a SuperH processor.  A Compact Flash FAQ is available at
-	  <http://www.compactflash.org/faqs/faq.htm>.
-
-	  If your board has "Directly Connected" CompactFlash at area 5 or 6,
-	  you may want to enable this option.  Then, you can use CF as
-	  primary IDE drive (only tested for SanDisk).
-
-	  If in doubt, select 'N'.
-
-choice
-	prompt "Compact Flash Connection Area"
-	depends on CF_ENABLER
-	default CF_AREA6
-
-config CF_AREA5
-	bool "Area5"
-	help
-	  If your board has "Directly Connected" CompactFlash, You should
-	  select the area where your CF is connected to.
-
-	  - "Area5" if CompactFlash is connected to Area 5 (0x14000000)
-	  - "Area6" if it is connected to Area 6 (0x18000000)
-
-	  "Area6" will work for most boards.
-
-config CF_AREA6
-	bool "Area6"
-
-endchoice
-
-config CF_BASE_ADDR
-	hex
-	depends on CF_ENABLER
-	default "0xb8000000" if CF_AREA6
-	default "0xb4000000" if CF_AREA5
-
 source "arch/sh/drivers/pci/Kconfig"
 
 source "drivers/pci/Kconfig"
@@ -748,13 +719,11 @@
 endmenu
 
 menu "Power management options (EXPERIMENTAL)"
-depends on EXPERIMENTAL && SYS_SUPPORTS_PM
+depends on EXPERIMENTAL
 
-config ARCH_SUSPEND_POSSIBLE
-	def_bool y
-	depends on !SMP
+source "kernel/power/Kconfig"
 
-source kernel/power/Kconfig
+source "drivers/cpuidle/Kconfig"
 
 endmenu
 
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index e6d2c8b..0d62681 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -98,18 +98,29 @@
 	  for handling hard and soft interrupts.  This can help avoid
 	  overflowing the process kernel stacks.
 
-config SH_KGDB
-	bool "Include KGDB kernel debugger"
-	select FRAME_POINTER
-	select DEBUG_INFO
-	depends on CPU_SH3 || CPU_SH4
+config DUMP_CODE
+	bool "Show disassembly of nearby code in register dumps"
+	depends on DEBUG_KERNEL && SUPERH32
+	default y if DEBUG_BUGVERBOSE
+	default n
 	help
-	  Include in-kernel hooks for kgdb, the Linux kernel source level
-	  debugger.  See <http://kgdb.sourceforge.net/> for more information.
-	  Unless you are intending to debug the kernel, say N here.
+	  This prints out a code trace of the instructions leading up to
+	  the faulting instruction as a debugging aid. As this does grow
+	  the kernel in size a bit, most users will want to say N here.
 
-menu "KGDB configuration options"
-	depends on SH_KGDB
+	  Those looking for more verbose debugging output should say Y.
+
+config SH_NO_BSS_INIT
+	bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)"
+	depends on DEBUG_KERNEL
+	default n
+	help
+	  If running in painfully slow environments, such as an RTL
+	  simulation or from remote memory via SHdebug, where the memory
+	  can already be gauranteed to ber zeroed on boot, say Y.
+
+	  For all other cases, say N. If this option seems perplexing, or
+	  you aren't sure, say N.
 
 config MORE_COMPILE_OPTIONS
 	bool "Add any additional compile options"
@@ -122,85 +133,16 @@
 	string "Additional compile arguments"
 	depends on MORE_COMPILE_OPTIONS
 
-config KGDB_NMI
-	def_bool n
-	prompt "Enter KGDB on NMI"
-
-config SH_KGDB_CONSOLE
-	def_bool n
-	prompt "Console messages through GDB"
-	depends on !SERIAL_SH_SCI_CONSOLE && SERIAL_SH_SCI=y
-	select SERIAL_CORE_CONSOLE
-
-config KGDB_SYSRQ
-	def_bool y
-	prompt "Allow SysRq 'G' to enter KGDB"
-	depends on MAGIC_SYSRQ
-
-comment "Serial port setup"
-
-config KGDB_DEFPORT
-	int "Port number (ttySCn)"
-	default "1"
-
-config KGDB_DEFBAUD
-	int "Baud rate"
-	default "115200"
-
-choice
-	prompt "Parity"
-	depends on SH_KGDB
-	default KGDB_DEFPARITY_N
-
-config KGDB_DEFPARITY_N
-	bool "None"
-
-config KGDB_DEFPARITY_E
-	bool "Even"
-
-config KGDB_DEFPARITY_O
-	bool "Odd"
-
-endchoice
-
-choice
-	prompt "Data bits"
-	depends on SH_KGDB
-	default KGDB_DEFBITS_8
-
-config KGDB_DEFBITS_8
-	bool "8"
-
-config KGDB_DEFBITS_7
-	bool "7"
-
-endchoice
-
-endmenu
-
-if SUPERH64
-
-config SH64_PROC_ASIDS
-	bool "Debug: report ASIDs through /proc/asids"
-	depends on PROC_FS && MMU
-
 config SH64_SR_WATCH
 	bool "Debug: set SR.WATCH to enable hardware watchpoints and trace"
+	depends on SUPERH64
 
 config POOR_MANS_STRACE
 	bool "Debug: enable rudimentary strace facility"
+	depends on SUPERH64
 	help
 	  This option allows system calls to be traced to the console.  It also
 	  aids in detecting kernel stack underflow.  It is useful for debugging
 	  early-userland problems (e.g. init incurring fatal exceptions.)
 
-config SH_ALPHANUMERIC
-	bool "Enable debug outputs to on-board alphanumeric display"
-	depends on SH_CAYMAN
-
-config SH_NO_BSS_INIT
-	bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)"
-
-endif
-
 endmenu
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index c43eb0d..4067b0d 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -32,6 +32,7 @@
 	$(call cc-option,-mno-implicit-fp,-m4-nofpu)
 cflags-$(CONFIG_CPU_SH4A)		+= $(call cc-option,-m4a,) \
 					   $(call cc-option,-m4a-nofpu,)
+cflags-$(CONFIG_CPU_SH4AL_DSP)		+= $(call cc-option,-m4al,)
 cflags-$(CONFIG_CPU_SH5)		:= $(call cc-option,-m5-32media-nofpu,)
 
 ifeq ($(cflags-y),)
@@ -39,22 +40,16 @@
 # In the case where we are stuck with a compiler that has been uselessly
 # restricted to a particular ISA, a favourite default of newer GCCs when
 # extensive multilib targets are not provided, ensure we get the best fit
-# regarding FP generation. This is necessary to avoid references to FP
-# variants in libgcc where integer variants exist, which otherwise result
-# in link errors. This is intentionally stupid (albeit many orders of
-# magnitude less than GCC's default behaviour), as anything with a large
-# number of multilib targets better have been built correctly for
-# the target in mind.
+# regarding FP generation. This is intentionally stupid (albeit many
+# orders of magnitude less than GCC's default behaviour), as anything
+# with a large number of multilib targets better have been built
+# correctly for the target in mind.
 #
 cflags-y	+= $(shell $(CC) $(KBUILD_CFLAGS) -print-multi-lib | \
 		     grep nofpu | sed q | sed -e 's/^/-/;s/;.*$$//')
-endif
-
-cflags-$(CONFIG_CPU_BIG_ENDIAN)		+= -mb
-cflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= -ml
-
-cflags-y	+= $(call cc-option,-mno-fdpic)
-
+# At this point, anything goes.
+isaflags-y	:= $(call as-option,-Wa$(comma)-isa=any,)
+else
 #
 # -Wa,-isa= tuning implies -Wa,-dsp for the versions of binutils that
 # support it, while -Wa,-dsp by itself limits the range of usable opcodes
@@ -67,7 +62,12 @@
 
 isaflags-$(CONFIG_SH_DSP)		:= \
 	$(call as-option,-Wa$(comma)-isa=$(isa-y),-Wa$(comma)-dsp)
+endif
 
+cflags-$(CONFIG_CPU_BIG_ENDIAN)		+= -mb
+cflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= -ml
+
+cflags-y	+= $(call cc-option,-mno-fdpic)
 cflags-y	+= $(isaflags-y) -ffreestanding
 
 cflags-$(CONFIG_MORE_COMPILE_OPTIONS)	+= \
@@ -79,6 +79,9 @@
 # Give the various platforms the opportunity to set default image types
 defaultimage-$(CONFIG_SUPERH32)			:= zImage
 defaultimage-$(CONFIG_SH_SH7785LCR)		:= uImage
+defaultimage-$(CONFIG_SH_RSK)			:= uImage
+defaultimage-$(CONFIG_SH_7206_SOLUTION_ENGINE)	:= vmlinux
+defaultimage-$(CONFIG_SH_7619_SOLUTION_ENGINE)	:= vmlinux
 
 # Set some sensible Kbuild defaults
 KBUILD_DEFCONFIG	:= shx3_defconfig
@@ -132,6 +135,7 @@
 machdir-$(CONFIG_SH_TITAN)			+= mach-titan
 machdir-$(CONFIG_SH_LBOX_RE2)			+= mach-lboxre2
 machdir-$(CONFIG_SH_CAYMAN)			+= mach-cayman
+machdir-$(CONFIG_SH_RSK)			+= mach-rsk
 
 ifneq ($(machdir-y),)
 core-y	+= $(addprefix arch/sh/boards/, \
@@ -173,11 +177,8 @@
 KBUILD_CPPFLAGS		+= $(cflags-y)
 KBUILD_AFLAGS		+= $(cflags-y)
 
-LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
-
 libs-$(CONFIG_SUPERH32)		:= arch/sh/lib/	$(libs-y)
 libs-$(CONFIG_SUPERH64)		:= arch/sh/lib64/ $(libs-y)
-libs-y				+= $(LIBGCC)
 
 PHONY += maketools FORCE
 
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 50467f9..8619147 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -126,10 +126,12 @@
 	  Select RTS7751R2D if configuring for a Renesas Technology
 	  Sales SH-Graphics board.
 
-config SH_RSK7203
-	bool "RSK7203"
-	select GENERIC_GPIO
-	depends on CPU_SUBTYPE_SH7203
+config SH_RSK
+	bool "Renesas Starter Kit"
+	depends on CPU_SUBTYPE_SH7201 || CPU_SUBTYPE_SH7203
+	help
+	 Select this option if configuring for any of the RSK+ MCU
+	 evaluation platforms.
 
 config SH_SDK7780
 	bool "SDK7780R3"
@@ -253,6 +255,7 @@
 source "arch/sh/boards/mach-highlander/Kconfig"
 source "arch/sh/boards/mach-sdk7780/Kconfig"
 source "arch/sh/boards/mach-migor/Kconfig"
+source "arch/sh/boards/mach-rsk/Kconfig"
 
 if SH_MAGIC_PANEL_R2
 
diff --git a/arch/sh/boards/Makefile b/arch/sh/boards/Makefile
index d9efa39..269ae2b 100644
--- a/arch/sh/boards/Makefile
+++ b/arch/sh/boards/Makefile
@@ -3,7 +3,6 @@
 #
 obj-$(CONFIG_SH_AP325RXA)	+= board-ap325rxa.o
 obj-$(CONFIG_SH_MAGIC_PANEL_R2)	+= board-magicpanelr2.o
-obj-$(CONFIG_SH_RSK7203)	+= board-rsk7203.o
 obj-$(CONFIG_SH_SH7785LCR)	+= board-sh7785lcr.o
 obj-$(CONFIG_SH_SHMIN)		+= board-shmin.o
 obj-$(CONFIG_SH_EDOSK7760)	+= board-edosk7760.o
diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/board-ap325rxa.c
index 8881a64..1c67cba 100644
--- a/arch/sh/boards/board-ap325rxa.c
+++ b/arch/sh/boards/board-ap325rxa.c
@@ -197,6 +197,10 @@
 		.end	= 0xfe941fff,
 		.flags	= IORESOURCE_MEM,
 	},
+	[1] = {
+		.start	= 28,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 static struct platform_device lcdc_device = {
@@ -303,6 +307,7 @@
 
 static struct platform_device ceu_device = {
 	.name		= "sh_mobile_ceu",
+	.id             = 0, /* "ceu0" clock */
 	.num_resources	= ARRAY_SIZE(ceu_resources),
 	.resource	= ceu_resources,
 	.dev		= {
@@ -344,7 +349,6 @@
 	gpio_export(GPIO_PTF7, 0);
 
 	/* LCDC */
-	clk_always_enable("mstp200");
 	gpio_request(GPIO_FN_LCDD15, NULL);
 	gpio_request(GPIO_FN_LCDD14, NULL);
 	gpio_request(GPIO_FN_LCDD13, NULL);
@@ -375,7 +379,6 @@
 	gpio_direction_output(GPIO_PTS3, 1);
 
 	/* CEU */
-	clk_always_enable("mstp203");
 	gpio_request(GPIO_FN_VIO_CLK2, NULL);
 	gpio_request(GPIO_FN_VIO_VD2, NULL);
 	gpio_request(GPIO_FN_VIO_HD2, NULL);
diff --git a/arch/sh/boards/board-rsk7203.c b/arch/sh/boards/board-rsk7203.c
deleted file mode 100644
index 58266f0..0000000
--- a/arch/sh/boards/board-rsk7203.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Renesas Technology Europe RSK+ 7203 Support.
- *
- * Copyright (C) 2008 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/map.h>
-#include <linux/smc911x.h>
-#include <linux/gpio.h>
-#include <linux/leds.h>
-#include <asm/machvec.h>
-#include <asm/io.h>
-#include <cpu/sh7203.h>
-
-static struct smc911x_platdata smc911x_info = {
-	.flags		= SMC911X_USE_16BIT,
-	.irq_flags	= IRQF_TRIGGER_LOW,
-};
-
-static struct resource smc911x_resources[] = {
-	[0] = {
-		.start		= 0x24000000,
-		.end		= 0x24000000 + 0x100,
-		.flags		= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start		= 64,
-		.end		= 64,
-		.flags		= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device smc911x_device = {
-	.name		= "smc911x",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(smc911x_resources),
-	.resource	= smc911x_resources,
-	.dev		= {
-		.platform_data = &smc911x_info,
-	},
-};
-
-static const char *probes[] = { "cmdlinepart", NULL };
-
-static struct mtd_partition *parsed_partitions;
-
-static struct mtd_partition rsk7203_partitions[] = {
-	{
-		.name		= "Bootloader",
-		.offset		= 0x00000000,
-		.size		= 0x00040000,
-		.mask_flags	= MTD_WRITEABLE,
-	}, {
-		.name		= "Kernel",
-		.offset		= MTDPART_OFS_NXTBLK,
-		.size		= 0x001c0000,
-	}, {
-		.name		= "Flash_FS",
-		.offset		= MTDPART_OFS_NXTBLK,
-		.size		= MTDPART_SIZ_FULL,
-	}
-};
-
-static struct physmap_flash_data flash_data = {
-	.width		= 2,
-};
-
-static struct resource flash_resource = {
-	.start		= 0x20000000,
-	.end		= 0x20400000,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device flash_device = {
-	.name		= "physmap-flash",
-	.id		= -1,
-	.resource	= &flash_resource,
-	.num_resources	= 1,
-	.dev		= {
-		.platform_data = &flash_data,
-	},
-};
-
-static struct mtd_info *flash_mtd;
-
-static struct map_info rsk7203_flash_map = {
-	.name		= "RSK+ Flash",
-	.size		= 0x400000,
-	.bankwidth	= 2,
-};
-
-static void __init set_mtd_partitions(void)
-{
-	int nr_parts = 0;
-
-	simple_map_init(&rsk7203_flash_map);
-	flash_mtd = do_map_probe("cfi_probe", &rsk7203_flash_map);
-	nr_parts = parse_mtd_partitions(flash_mtd, probes,
-					&parsed_partitions, 0);
-	/* If there is no partition table, used the hard coded table */
-	if (nr_parts <= 0) {
-		flash_data.parts = rsk7203_partitions;
-		flash_data.nr_parts = ARRAY_SIZE(rsk7203_partitions);
-	} else {
-		flash_data.nr_parts = nr_parts;
-		flash_data.parts = parsed_partitions;
-	}
-}
-
-static struct gpio_led rsk7203_gpio_leds[] = {
-	{
-		.name			= "green",
-		.gpio			= GPIO_PE10,
-		.active_low		= 1,
-	}, {
-		.name			= "orange",
-		.default_trigger	= "nand-disk",
-		.gpio			= GPIO_PE12,
-		.active_low		= 1,
-	}, {
-		.name			= "red:timer",
-		.default_trigger	= "timer",
-		.gpio			= GPIO_PC14,
-		.active_low		= 1,
-	}, {
-		.name			= "red:heartbeat",
-		.default_trigger	= "heartbeat",
-		.gpio			= GPIO_PE11,
-		.active_low		= 1,
-	},
-};
-
-static struct gpio_led_platform_data rsk7203_gpio_leds_info = {
-	.leds		= rsk7203_gpio_leds,
-	.num_leds	= ARRAY_SIZE(rsk7203_gpio_leds),
-};
-
-static struct platform_device led_device = {
-	.name		= "leds-gpio",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &rsk7203_gpio_leds_info,
-	},
-};
-
-static struct platform_device *rsk7203_devices[] __initdata = {
-	&smc911x_device,
-	&flash_device,
-	&led_device,
-};
-
-static int __init rsk7203_devices_setup(void)
-{
-	/* Select pins for SCIF0 */
-	gpio_request(GPIO_FN_TXD0, NULL);
-	gpio_request(GPIO_FN_RXD0, NULL);
-
-	set_mtd_partitions();
-	return platform_add_devices(rsk7203_devices,
-				    ARRAY_SIZE(rsk7203_devices));
-}
-device_initcall(rsk7203_devices_setup);
-
-/*
- * The Machine Vector
- */
-static struct sh_machine_vector mv_rsk7203 __initmv = {
-	.mv_name        = "RSK+7203",
-};
diff --git a/arch/sh/boards/board-shmin.c b/arch/sh/boards/board-shmin.c
index 5cc0867..b1dcbbc 100644
--- a/arch/sh/boards/board-shmin.c
+++ b/arch/sh/boards/board-shmin.c
@@ -22,21 +22,13 @@
 	plat_irq_setup_pins(IRQ_MODE_IRQ);
 }
 
-static void __iomem *shmin_ioport_map(unsigned long port, unsigned int size)
+static void __init shmin_setup(char **cmdline_p)
 {
-	static int dummy;
-
-	if ((port & ~0x1f) == SHMIN_NE_BASE)
-		return (void __iomem *)(SHMIN_IO_BASE + port);
-
-	dummy = 0;
-
-	return &dummy;
-
+	__set_io_port_base(SHMIN_IO_BASE);
 }
 
 static struct sh_machine_vector mv_shmin __initmv = {
 	.mv_name	= "SHMIN",
+	.mv_setup	= shmin_setup,
 	.mv_init_irq	= init_shmin_irq,
-	.mv_ioport_map	= shmin_ioport_map,
 };
diff --git a/arch/sh/boards/mach-cayman/Makefile b/arch/sh/boards/mach-cayman/Makefile
index 489a8f8..cafe1ac 100644
--- a/arch/sh/boards/mach-cayman/Makefile
+++ b/arch/sh/boards/mach-cayman/Makefile
@@ -2,4 +2,3 @@
 # Makefile for the Hitachi Cayman specific parts of the kernel
 #
 obj-y := setup.o irq.o
-obj-$(CONFIG_HEARTBEAT)	+= led.o
diff --git a/arch/sh/boards/mach-cayman/irq.c b/arch/sh/boards/mach-cayman/irq.c
index ceb37ae..da62ad5 100644
--- a/arch/sh/boards/mach-cayman/irq.c
+++ b/arch/sh/boards/mach-cayman/irq.c
@@ -94,31 +94,11 @@
 	disable_cayman_irq(irq);
 }
 
-static void end_cayman_irq(unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_cayman_irq(irq);
-}
-
-static unsigned int startup_cayman_irq(unsigned int irq)
-{
-	enable_cayman_irq(irq);
-	return 0; /* never anything pending */
-}
-
-static void shutdown_cayman_irq(unsigned int irq)
-{
-	disable_cayman_irq(irq);
-}
-
-struct hw_interrupt_type cayman_irq_type = {
-	.typename	= "Cayman-IRQ",
-	.startup	= startup_cayman_irq,
-	.shutdown	= shutdown_cayman_irq,
-	.enable		= enable_cayman_irq,
-	.disable	= disable_cayman_irq,
-	.ack		= ack_cayman_irq,
-	.end		= end_cayman_irq,
+struct irq_chip cayman_irq_type = {
+	.name		= "Cayman-IRQ",
+	.unmask 	= enable_cayman_irq,
+	.mask		= disable_cayman_irq,
+	.mask_ack	= ack_cayman_irq,
 };
 
 int cayman_irq_demux(int evt)
@@ -187,8 +167,9 @@
 		return;
 	}
 
-	for (i=0; i<NR_EXT_IRQS; i++) {
-		irq_desc[START_EXT_IRQS + i].chip = &cayman_irq_type;
+	for (i = 0; i < NR_EXT_IRQS; i++) {
+		set_irq_chip_and_handler(START_EXT_IRQS + i, &cayman_irq_type,
+					 handle_level_irq);
 	}
 
 	/* Setup the SMSC interrupt */
diff --git a/arch/sh/boards/mach-cayman/led.c b/arch/sh/boards/mach-cayman/led.c
deleted file mode 100644
index a808eac..0000000
--- a/arch/sh/boards/mach-cayman/led.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * arch/sh/boards/cayman/led.c
- *
- * Copyright (C) 2002 Stuart Menefy <stuart.menefy@st.com>
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * Flash the LEDs
- */
-#include <asm/io.h>
-
-/*
-** It is supposed these functions to be used for a low level
-** debugging (via Cayman LEDs), hence to be available as soon
-** as possible.
-** Unfortunately Cayman LEDs relies on Cayman EPLD to be mapped
-** (this happen when IRQ are initialized... quite late).
-** These triky dependencies should be removed. Temporary, it
-** may be enough to NOP until EPLD is mapped.
-*/
-
-extern unsigned long epld_virt;
-
-#define LED_ADDR      (epld_virt + 0x008)
-#define HDSP2534_ADDR (epld_virt + 0x100)
-
-void mach_led(int position, int value)
-{
-	if (!epld_virt)
-		return;
-
-	if (value)
-		ctrl_outl(0, LED_ADDR);
-	else
-		ctrl_outl(1, LED_ADDR);
-
-}
-
-void mach_alphanum(int position, unsigned char value)
-{
-	if (!epld_virt)
-		return;
-
-	ctrl_outb(value, HDSP2534_ADDR + 0xe0 + (position << 2));
-}
-
-void mach_alphanum_brightness(int setting)
-{
-	ctrl_outb(setting & 7, HDSP2534_ADDR + 0xc0);
-}
diff --git a/arch/sh/boards/mach-dreamcast/irq.c b/arch/sh/boards/mach-dreamcast/irq.c
index 67bdc33..f55fc8e 100644
--- a/arch/sh/boards/mach-dreamcast/irq.c
+++ b/arch/sh/boards/mach-dreamcast/irq.c
@@ -10,106 +10,90 @@
  */
 
 #include <linux/irq.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/irq.h>
 #include <mach/sysasic.h>
 
-/* Dreamcast System ASIC Hardware Events -
-
-   The Dreamcast's System ASIC (a.k.a. Holly) is responsible for receiving
-   hardware events from system peripherals and triggering an SH7750 IRQ.
-   Hardware events can trigger IRQs 13, 11, or 9 depending on which bits are
-   set in the Event Mask Registers (EMRs).  When a hardware event is
-   triggered, it's corresponding bit in the Event Status Registers (ESRs)
-   is set, and that bit should be rewritten to the ESR to acknowledge that
-   event.
-
-   There are three 32-bit ESRs located at 0xa05f8900 - 0xa05f6908.  Event
-   types can be found in include/asm-sh/dreamcast/sysasic.h. There are three
-   groups of EMRs that parallel the ESRs.  Each EMR group corresponds to an
-   IRQ, so 0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928
-   triggers IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9.
-
-   In the kernel, these events are mapped to virtual IRQs so that drivers can
-   respond to them as they would a normal interrupt.  In order to keep this
-   mapping simple, the events are mapped as:
-
-   6900/6910 - Events  0-31, IRQ 13
-   6904/6924 - Events 32-63, IRQ 11
-   6908/6938 - Events 64-95, IRQ  9
-
-*/
+/*
+ * Dreamcast System ASIC Hardware Events -
+ *
+ * The Dreamcast's System ASIC (a.k.a. Holly) is responsible for receiving
+ * hardware events from system peripherals and triggering an SH7750 IRQ.
+ * Hardware events can trigger IRQs 13, 11, or 9 depending on which bits are
+ * set in the Event Mask Registers (EMRs).  When a hardware event is
+ * triggered, its corresponding bit in the Event Status Registers (ESRs)
+ * is set, and that bit should be rewritten to the ESR to acknowledge that
+ * event.
+ *
+ * There are three 32-bit ESRs located at 0xa05f6900 - 0xa05f6908.  Event
+ * types can be found in arch/sh/include/mach-dreamcast/mach/sysasic.h.
+ * There are three groups of EMRs that parallel the ESRs.  Each EMR group
+ * corresponds to an IRQ, so 0xa05f6910 - 0xa05f6918 triggers IRQ 13,
+ * 0xa05f6920 - 0xa05f6928 triggers IRQ 11, and 0xa05f6930 - 0xa05f6938
+ * triggers IRQ 9.
+ *
+ * In the kernel, these events are mapped to virtual IRQs so that drivers can
+ * respond to them as they would a normal interrupt.  In order to keep this
+ * mapping simple, the events are mapped as:
+ *
+ * 6900/6910 - Events  0-31, IRQ 13
+ * 6904/6924 - Events 32-63, IRQ 11
+ * 6908/6938 - Events 64-95, IRQ  9
+ *
+ */
 
 #define ESR_BASE 0x005f6900    /* Base event status register */
 #define EMR_BASE 0x005f6910    /* Base event mask register */
 
-/* Helps us determine the EMR group that this event belongs to: 0 = 0x6910,
-   1 = 0x6920, 2 = 0x6930; also determine the event offset */
+/*
+ * Helps us determine the EMR group that this event belongs to: 0 = 0x6910,
+ * 1 = 0x6920, 2 = 0x6930; also determine the event offset.
+ */
 #define LEVEL(event) (((event) - HW_EVENT_IRQ_BASE) / 32)
 
 /* Return the hardware event's bit positon within the EMR/ESR */
 #define EVENT_BIT(event) (((event) - HW_EVENT_IRQ_BASE) & 31)
 
-/* For each of these *_irq routines, the IRQ passed in is the virtual IRQ
-   (logically mapped to the corresponding bit for the hardware event). */
+/*
+ * For each of these *_irq routines, the IRQ passed in is the virtual IRQ
+ * (logically mapped to the corresponding bit for the hardware event).
+ */
 
 /* Disable the hardware event by masking its bit in its EMR */
 static inline void disable_systemasic_irq(unsigned int irq)
 {
-        __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
-        __u32 mask;
+	__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+	__u32 mask;
 
-        mask = inl(emr);
-        mask &= ~(1 << EVENT_BIT(irq));
-        outl(mask, emr);
+	mask = inl(emr);
+	mask &= ~(1 << EVENT_BIT(irq));
+	outl(mask, emr);
 }
 
 /* Enable the hardware event by setting its bit in its EMR */
 static inline void enable_systemasic_irq(unsigned int irq)
 {
-        __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
-        __u32 mask;
+	__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+	__u32 mask;
 
-        mask = inl(emr);
-        mask |= (1 << EVENT_BIT(irq));
-        outl(mask, emr);
+	mask = inl(emr);
+	mask |= (1 << EVENT_BIT(irq));
+	outl(mask, emr);
 }
 
 /* Acknowledge a hardware event by writing its bit back to its ESR */
-static void ack_systemasic_irq(unsigned int irq)
+static void mask_ack_systemasic_irq(unsigned int irq)
 {
-        __u32 esr = ESR_BASE + (LEVEL(irq) << 2);
-        disable_systemasic_irq(irq);
-        outl((1 << EVENT_BIT(irq)), esr);
+	__u32 esr = ESR_BASE + (LEVEL(irq) << 2);
+	disable_systemasic_irq(irq);
+	outl((1 << EVENT_BIT(irq)), esr);
 }
 
-/* After a IRQ has been ack'd and responded to, it needs to be renabled */
-static void end_systemasic_irq(unsigned int irq)
-{
-        if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-                enable_systemasic_irq(irq);
-}
-
-static unsigned int startup_systemasic_irq(unsigned int irq)
-{
-        enable_systemasic_irq(irq);
-
-        return 0;
-}
-
-static void shutdown_systemasic_irq(unsigned int irq)
-{
-        disable_systemasic_irq(irq);
-}
-
-struct hw_interrupt_type systemasic_int = {
-        .typename       = "System ASIC",
-        .startup        = startup_systemasic_irq,
-        .shutdown       = shutdown_systemasic_irq,
-        .enable         = enable_systemasic_irq,
-        .disable        = disable_systemasic_irq,
-        .ack            = ack_systemasic_irq,
-        .end            = end_systemasic_irq,
+struct irq_chip systemasic_int = {
+	.name		= "System ASIC",
+	.mask		= disable_systemasic_irq,
+	.mask_ack	= mask_ack_systemasic_irq,
+	.unmask		= enable_systemasic_irq,
 };
 
 /*
@@ -117,37 +101,37 @@
  */
 int systemasic_irq_demux(int irq)
 {
-        __u32 emr, esr, status, level;
-        __u32 j, bit;
+	__u32 emr, esr, status, level;
+	__u32 j, bit;
 
-        switch (irq) {
-                case 13:
-                        level = 0;
-                        break;
-                case 11:
-                        level = 1;
-                        break;
-                case  9:
-                        level = 2;
-                        break;
-                default:
-                        return irq;
-        }
-        emr = EMR_BASE + (level << 4) + (level << 2);
-        esr = ESR_BASE + (level << 2);
+	switch (irq) {
+	case 13:
+		level = 0;
+		break;
+	case 11:
+		level = 1;
+		break;
+	case  9:
+		level = 2;
+		break;
+	default:
+		return irq;
+	}
+	emr = EMR_BASE + (level << 4) + (level << 2);
+	esr = ESR_BASE + (level << 2);
 
-        /* Mask the ESR to filter any spurious, unwanted interrupts */
-        status = inl(esr);
-        status &= inl(emr);
+	/* Mask the ESR to filter any spurious, unwanted interrupts */
+	status = inl(esr);
+	status &= inl(emr);
 
-        /* Now scan and find the first set bit as the event to map */
-        for (bit = 1, j = 0; j < 32; bit <<= 1, j++) {
-                if (status & bit) {
-                        irq = HW_EVENT_IRQ_BASE + j + (level << 5);
-                        return irq;
-                }
-        }
+	/* Now scan and find the first set bit as the event to map */
+	for (bit = 1, j = 0; j < 32; bit <<= 1, j++) {
+		if (status & bit) {
+			irq = HW_EVENT_IRQ_BASE + j + (level << 5);
+			return irq;
+		}
+	}
 
-        /* Not reached */
-        return irq;
+	/* Not reached */
+	return irq;
 }
diff --git a/arch/sh/boards/mach-dreamcast/setup.c b/arch/sh/boards/mach-dreamcast/setup.c
index 7d944fc..d1bee48 100644
--- a/arch/sh/boards/mach-dreamcast/setup.c
+++ b/arch/sh/boards/mach-dreamcast/setup.c
@@ -28,7 +28,7 @@
 #include <asm/machvec.h>
 #include <mach/sysasic.h>
 
-extern struct hw_interrupt_type systemasic_int;
+extern struct irq_chip systemasic_int;
 extern void aica_time_init(void);
 extern int gapspci_init(void);
 extern int systemasic_irq_demux(int);
@@ -47,7 +47,8 @@
 
 	/* Assign all virtual IRQs to the System ASIC int. handler */
 	for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
-		irq_desc[i].chip = &systemasic_int;
+		set_irq_chip_and_handler(i, &systemasic_int,
+					 handle_level_irq);
 
 	board_time_init = aica_time_init;
 
diff --git a/arch/sh/boards/mach-edosk7705/Makefile b/arch/sh/boards/mach-edosk7705/Makefile
index 14bdd53..cd54acb 100644
--- a/arch/sh/boards/mach-edosk7705/Makefile
+++ b/arch/sh/boards/mach-edosk7705/Makefile
@@ -3,4 +3,3 @@
 #
 
 obj-y	 := setup.o io.o
-
diff --git a/arch/sh/boards/mach-edosk7705/io.c b/arch/sh/boards/mach-edosk7705/io.c
index 7d153e5..5b9c57c 100644
--- a/arch/sh/boards/mach-edosk7705/io.c
+++ b/arch/sh/boards/mach-edosk7705/io.c
@@ -10,28 +10,24 @@
 
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <mach/edosk7705.h>
 #include <asm/addrspace.h>
 
 #define SMC_IOADDR	0xA2000000
 
-#define maybebadio(name,port) \
-  printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
-	 #name, (port), (__u32) __builtin_return_address(0))
-
 /* Map the Ethernet addresses as if it is at 0x300 - 0x320 */
-unsigned long sh_edosk7705_isa_port2addr(unsigned long port)
+static unsigned long sh_edosk7705_isa_port2addr(unsigned long port)
 {
-     if (port >= 0x300 && port < 0x320) {
-	  /* SMC91C96 registers are 4 byte aligned rather than the
-	   * usual 2 byte!
-	   */
-	  return SMC_IOADDR + ( (port - 0x300) * 2);
-     }
+	/*
+	 * SMC91C96 registers are 4 byte aligned rather than the
+	 * usual 2 byte!
+	 */
+	if (port >= 0x300 && port < 0x320)
+		return SMC_IOADDR + ((port - 0x300) * 2);
 
-     maybebadio(sh_edosk7705_isa_port2addr, port);
-     return port;
+	maybebadio(port);
+	return port;
 }
 
 /* Trying to read / write bytes on odd-byte boundaries to the Ethernet
@@ -42,53 +38,34 @@
  */
 unsigned char sh_edosk7705_inb(unsigned long port)
 {
-	if (port >= 0x300 && port < 0x320 && port & 0x01) {
-		return (volatile unsigned char)(generic_inw(port -1) >> 8);
-	}
-	return *(volatile unsigned char *)sh_edosk7705_isa_port2addr(port);
-}
+	if (port >= 0x300 && port < 0x320 && port & 0x01)
+		return __raw_readw(port - 1) >> 8;
 
-unsigned int sh_edosk7705_inl(unsigned long port)
-{
-	return *(volatile unsigned long *)port;
+	return __raw_readb(sh_edosk7705_isa_port2addr(port));
 }
 
 void sh_edosk7705_outb(unsigned char value, unsigned long port)
 {
 	if (port >= 0x300 && port < 0x320 && port & 0x01) {
-		generic_outw(((unsigned short)value << 8), port -1);
+		__raw_writew(((unsigned short)value << 8), port - 1);
 		return;
 	}
-	*(volatile unsigned char *)sh_edosk7705_isa_port2addr(port) = value;
-}
 
-void sh_edosk7705_outl(unsigned int value, unsigned long port)
-{
-	*(volatile unsigned long *)port = value;
+	__raw_writeb(value, sh_edosk7705_isa_port2addr(port));
 }
 
 void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count)
 {
 	unsigned char *p = addr;
-	while (count--) *p++ = sh_edosk7705_inb(port);
-}
 
-void sh_edosk7705_insl(unsigned long port, void *addr, unsigned long count)
-{
-	unsigned long *p = (unsigned long*)addr;
 	while (count--)
-		*p++ = *(volatile unsigned long *)port;
+		*p++ = sh_edosk7705_inb(port);
 }
 
 void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count)
 {
-	unsigned char *p = (unsigned char*)addr;
-	while (count--) sh_edosk7705_outb(*p++, port);
-}
+	unsigned char *p = (unsigned char *)addr;
 
-void sh_edosk7705_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-	unsigned long *p = (unsigned long*)addr;
-	while (count--) sh_edosk7705_outl(*p++, port);
+	while (count--)
+		sh_edosk7705_outb(*p++, port);
 }
-
diff --git a/arch/sh/boards/mach-edosk7705/setup.c b/arch/sh/boards/mach-edosk7705/setup.c
index ab3f47b..d59225e 100644
--- a/arch/sh/boards/mach-edosk7705/setup.c
+++ b/arch/sh/boards/mach-edosk7705/setup.c
@@ -9,6 +9,7 @@
  * board by S. Dunn, 2003.
  */
 #include <linux/init.h>
+#include <linux/irq.h>
 #include <asm/machvec.h>
 #include <mach/edosk7705.h>
 
@@ -26,18 +27,10 @@
 	.mv_nr_irqs		= 80,
 
 	.mv_inb			= sh_edosk7705_inb,
-	.mv_inl			= sh_edosk7705_inl,
 	.mv_outb		= sh_edosk7705_outb,
-	.mv_outl		= sh_edosk7705_outl,
-
-	.mv_inl_p		= sh_edosk7705_inl,
-	.mv_outl_p		= sh_edosk7705_outl,
 
 	.mv_insb		= sh_edosk7705_insb,
-	.mv_insl		= sh_edosk7705_insl,
 	.mv_outsb		= sh_edosk7705_outsb,
-	.mv_outsl		= sh_edosk7705_outsl,
 
-	.mv_isa_port2addr	= sh_edosk7705_isa_port2addr,
 	.mv_init_irq		= sh_edosk7705_init_irq,
 };
diff --git a/arch/sh/boards/mach-hp6xx/pm.c b/arch/sh/boards/mach-hp6xx/pm.c
index 64af1f2..d936c1a 100644
--- a/arch/sh/boards/mach-hp6xx/pm.c
+++ b/arch/sh/boards/mach-hp6xx/pm.c
@@ -10,15 +10,91 @@
 #include <linux/suspend.h>
 #include <linux/errno.h>
 #include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/gfp.h>
 #include <asm/io.h>
 #include <asm/hd64461.h>
 #include <mach/hp6xx.h>
 #include <cpu/dac.h>
-#include <asm/pm.h>
+#include <asm/freq.h>
+#include <asm/watchdog.h>
+
+#define INTR_OFFSET	0x600
 
 #define STBCR		0xffffff82
 #define STBCR2		0xffffff88
 
+#define STBCR_STBY	0x80
+#define STBCR_MSTP2	0x04
+
+#define MCR		0xffffff68
+#define RTCNT		0xffffff70
+
+#define MCR_RMODE	2
+#define MCR_RFSH	4
+
+extern u8 wakeup_start;
+extern u8 wakeup_end;
+
+static void pm_enter(void)
+{
+	u8 stbcr, csr;
+	u16 frqcr, mcr;
+	u32 vbr_new, vbr_old;
+
+	set_bl_bit();
+
+	/* set wdt */
+	csr = sh_wdt_read_csr();
+	csr &= ~WTCSR_TME;
+	csr |= WTCSR_CKS_4096;
+	sh_wdt_write_csr(csr);
+	csr = sh_wdt_read_csr();
+	sh_wdt_write_cnt(0);
+
+	/* disable PLL1 */
+	frqcr = ctrl_inw(FRQCR);
+	frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY);
+	ctrl_outw(frqcr, FRQCR);
+
+	/* enable standby */
+	stbcr = ctrl_inb(STBCR);
+	ctrl_outb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR);
+
+	/* set self-refresh */
+	mcr = ctrl_inw(MCR);
+	ctrl_outw(mcr & ~MCR_RFSH, MCR);
+
+	/* set interrupt handler */
+	asm volatile("stc vbr, %0" : "=r" (vbr_old));
+	vbr_new = get_zeroed_page(GFP_ATOMIC);
+	udelay(50);
+	memcpy((void*)(vbr_new + INTR_OFFSET),
+	       &wakeup_start, &wakeup_end - &wakeup_start);
+	asm volatile("ldc %0, vbr" : : "r" (vbr_new));
+
+	ctrl_outw(0, RTCNT);
+	ctrl_outw(mcr | MCR_RFSH | MCR_RMODE, MCR);
+
+	cpu_sleep();
+
+	asm volatile("ldc %0, vbr" : : "r" (vbr_old));
+
+	free_page(vbr_new);
+
+	/* enable PLL1 */
+	frqcr = ctrl_inw(FRQCR);
+	frqcr |= FRQCR_PSTBY;
+	ctrl_outw(frqcr, FRQCR);
+	udelay(50);
+	frqcr |= FRQCR_PLLEN;
+	ctrl_outw(frqcr, FRQCR);
+
+	ctrl_outb(stbcr, STBCR);
+
+	clear_bl_bit();
+}
+
 static int hp6x0_pm_enter(suspend_state_t state)
 {
 	u8 stbcr, stbcr2;
diff --git a/arch/sh/boards/mach-microdev/Makefile b/arch/sh/boards/mach-microdev/Makefile
index 1387dd6c..4e3588e 100644
--- a/arch/sh/boards/mach-microdev/Makefile
+++ b/arch/sh/boards/mach-microdev/Makefile
@@ -2,7 +2,4 @@
 # Makefile for the SuperH MicroDev specific parts of the kernel
 #
 
-obj-y	 := setup.o irq.o io.o
-
-obj-$(CONFIG_HEARTBEAT)	+= led.o
-
+obj-y	 := setup.o irq.o io.o fdc37c93xapm.o
diff --git a/arch/sh/boards/mach-microdev/fdc37c93xapm.c b/arch/sh/boards/mach-microdev/fdc37c93xapm.c
new file mode 100644
index 0000000..458a7cf
--- /dev/null
+++ b/arch/sh/boards/mach-microdev/fdc37c93xapm.c
@@ -0,0 +1,160 @@
+/*
+ *
+ * Setup for the SMSC FDC37C93xAPM
+ *
+ * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
+ * Copyright (C) 2003, 2004 SuperH, Inc.
+ * Copyright (C) 2004, 2005 Paul Mundt
+ *
+ * SuperH SH4-202 MicroDev board support.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ */
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <mach/microdev.h>
+
+#define SMSC_CONFIG_PORT_ADDR	 (0x3F0)
+#define SMSC_INDEX_PORT_ADDR	 SMSC_CONFIG_PORT_ADDR
+#define SMSC_DATA_PORT_ADDR	 (SMSC_INDEX_PORT_ADDR + 1)
+
+#define SMSC_ENTER_CONFIG_KEY	 0x55
+#define SMSC_EXIT_CONFIG_KEY	 0xaa
+
+#define SMCS_LOGICAL_DEV_INDEX	 0x07	/* Logical Device Number */
+#define SMSC_DEVICE_ID_INDEX	 0x20	/* Device ID */
+#define SMSC_DEVICE_REV_INDEX	 0x21	/* Device Revision */
+#define SMSC_ACTIVATE_INDEX	 0x30	/* Activate */
+#define SMSC_PRIMARY_BASE_INDEX	 0x60	/* Primary Base Address */
+#define SMSC_SECONDARY_BASE_INDEX 0x62	/* Secondary Base Address */
+#define SMSC_PRIMARY_INT_INDEX	 0x70	/* Primary Interrupt Select */
+#define SMSC_SECONDARY_INT_INDEX 0x72	/* Secondary Interrupt Select */
+#define SMSC_HDCS0_INDEX	 0xf0	/* HDCS0 Address Decoder */
+#define SMSC_HDCS1_INDEX	 0xf1	/* HDCS1 Address Decoder */
+
+#define SMSC_IDE1_DEVICE	1	/* IDE #1 logical device */
+#define SMSC_IDE2_DEVICE	2	/* IDE #2 logical device */
+#define SMSC_PARALLEL_DEVICE	3	/* Parallel Port logical device */
+#define SMSC_SERIAL1_DEVICE	4	/* Serial #1 logical device */
+#define SMSC_SERIAL2_DEVICE	5	/* Serial #2 logical device */
+#define SMSC_KEYBOARD_DEVICE	7	/* Keyboard logical device */
+#define SMSC_CONFIG_REGISTERS	8	/* Configuration Registers (Aux I/O) */
+
+#define SMSC_READ_INDEXED(index) ({ \
+	outb((index), SMSC_INDEX_PORT_ADDR); \
+	inb(SMSC_DATA_PORT_ADDR); })
+#define SMSC_WRITE_INDEXED(val, index) ({ \
+	outb((index), SMSC_INDEX_PORT_ADDR); \
+	outb((val),   SMSC_DATA_PORT_ADDR); })
+
+#define	IDE1_PRIMARY_BASE	0x01f0	/* Task File Registe base for IDE #1 */
+#define	IDE1_SECONDARY_BASE	0x03f6	/* Miscellaneous AT registers for IDE #1 */
+#define	IDE2_PRIMARY_BASE	0x0170	/* Task File Registe base for IDE #2 */
+#define	IDE2_SECONDARY_BASE	0x0376	/* Miscellaneous AT registers for IDE #2 */
+
+#define SERIAL1_PRIMARY_BASE	0x03f8
+#define SERIAL2_PRIMARY_BASE	0x02f8
+
+#define	MSB(x)		( (x) >> 8 )
+#define	LSB(x)		( (x) & 0xff )
+
+	/* General-Purpose base address on CPU-board FPGA */
+#define	MICRODEV_FPGA_GP_BASE		0xa6100000ul
+
+static int __init smsc_superio_setup(void)
+{
+
+	unsigned char devid, devrev;
+
+		/* Initially the chip is in run state */
+		/* Put it into configuration state */
+	outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
+
+		/* Read device ID info */
+	devid  = SMSC_READ_INDEXED(SMSC_DEVICE_ID_INDEX);
+	devrev = SMSC_READ_INDEXED(SMSC_DEVICE_REV_INDEX);
+
+	if ((devid == 0x30) && (devrev == 0x01))
+		printk("SMSC FDC37C93xAPM SuperIO device detected\n");
+	else
+		return -ENODEV;
+
+		/* Select the keyboard device */
+	SMSC_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+		/* enable it */
+	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+		/* enable the interrupts */
+	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_KEYBOARD, SMSC_PRIMARY_INT_INDEX);
+	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_MOUSE, SMSC_SECONDARY_INT_INDEX);
+
+		/* Select the Serial #1 device */
+	SMSC_WRITE_INDEXED(SMSC_SERIAL1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+		/* enable it */
+	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+		/* program with port addresses */
+	SMSC_WRITE_INDEXED(MSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+	SMSC_WRITE_INDEXED(LSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+	SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX);
+		/* enable the interrupts */
+	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL1, SMSC_PRIMARY_INT_INDEX);
+
+		/* Select the Serial #2 device */
+	SMSC_WRITE_INDEXED(SMSC_SERIAL2_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+		/* enable it */
+	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+		/* program with port addresses */
+	SMSC_WRITE_INDEXED(MSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+	SMSC_WRITE_INDEXED(LSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+	SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX);
+		/* enable the interrupts */
+	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL2, SMSC_PRIMARY_INT_INDEX);
+
+		/* Select the IDE#1 device */
+	SMSC_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+		/* enable it */
+	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+		/* program with port addresses */
+	SMSC_WRITE_INDEXED(MSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+	SMSC_WRITE_INDEXED(LSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+	SMSC_WRITE_INDEXED(MSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0);
+	SMSC_WRITE_INDEXED(LSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1);
+	SMSC_WRITE_INDEXED(0x0c, SMSC_HDCS0_INDEX);
+	SMSC_WRITE_INDEXED(0x00, SMSC_HDCS1_INDEX);
+		/* select the interrupt */
+	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE1, SMSC_PRIMARY_INT_INDEX);
+
+		/* Select the IDE#2 device */
+	SMSC_WRITE_INDEXED(SMSC_IDE2_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+		/* enable it */
+	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+		/* program with port addresses */
+	SMSC_WRITE_INDEXED(MSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+	SMSC_WRITE_INDEXED(LSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+	SMSC_WRITE_INDEXED(MSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0);
+	SMSC_WRITE_INDEXED(LSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1);
+		/* select the interrupt */
+	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE2, SMSC_PRIMARY_INT_INDEX);
+
+		/* Select the configuration registers */
+	SMSC_WRITE_INDEXED(SMSC_CONFIG_REGISTERS, SMCS_LOGICAL_DEV_INDEX);
+		/* enable the appropriate GPIO pins for IDE functionality:
+		 * bit[0]   In/Out		1==input;  0==output
+		 * bit[1]   Polarity		1==invert; 0==no invert
+		 * bit[2]   Int Enb #1		1==Enable Combined IRQ #1; 0==disable
+		 * bit[3:4] Function Select	00==original; 01==Alternate Function #1
+		 */
+	SMSC_WRITE_INDEXED(0x00, 0xc2);	/* GP42 = nIDE1_OE */
+	SMSC_WRITE_INDEXED(0x01, 0xc5);	/* GP45 = IDE1_IRQ */
+	SMSC_WRITE_INDEXED(0x00, 0xc6);	/* GP46 = nIOROP */
+	SMSC_WRITE_INDEXED(0x00, 0xc7);	/* GP47 = nIOWOP */
+	SMSC_WRITE_INDEXED(0x08, 0xe8);	/* GP20 = nIDE2_OE */
+
+		/* Exit the configuration state */
+	outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
+
+	return 0;
+}
+device_initcall(smsc_superio_setup);
diff --git a/arch/sh/boards/mach-microdev/irq.c b/arch/sh/boards/mach-microdev/irq.c
index 702753c..b551963 100644
--- a/arch/sh/boards/mach-microdev/irq.c
+++ b/arch/sh/boards/mach-microdev/irq.c
@@ -67,27 +67,13 @@
 
 static void enable_microdev_irq(unsigned int irq);
 static void disable_microdev_irq(unsigned int irq);
-
-	/* shutdown is same as "disable" */
-#define shutdown_microdev_irq disable_microdev_irq
-
 static void mask_and_ack_microdev(unsigned int);
-static void end_microdev_irq(unsigned int irq);
 
-static unsigned int startup_microdev_irq(unsigned int irq)
-{
-	enable_microdev_irq(irq);
-	return 0;		/* never anything pending */
-}
-
-static struct hw_interrupt_type microdev_irq_type = {
-	.typename = "MicroDev-IRQ",
-	.startup = startup_microdev_irq,
-	.shutdown = shutdown_microdev_irq,
-	.enable = enable_microdev_irq,
-	.disable = disable_microdev_irq,
+static struct irq_chip microdev_irq_type = {
+	.name = "MicroDev-IRQ",
+	.unmask = enable_microdev_irq,
+	.mask = disable_microdev_irq,
 	.ack = mask_and_ack_microdev,
-	.end = end_microdev_irq
 };
 
 static void disable_microdev_irq(unsigned int irq)
@@ -130,11 +116,11 @@
 	ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG);
 }
 
-	/* This functions sets the desired irq handler to be a MicroDev type */
+/* This function sets the desired irq handler to be a MicroDev type */
 static void __init make_microdev_irq(unsigned int irq)
 {
 	disable_irq_nosync(irq);
-	irq_desc[irq].chip = &microdev_irq_type;
+	set_irq_chip_and_handler(irq, &microdev_irq_type, handle_level_irq);
 	disable_microdev_irq(irq);
 }
 
@@ -143,17 +129,11 @@
 	disable_microdev_irq(irq);
 }
 
-static void end_microdev_irq(unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_microdev_irq(irq);
-}
-
 extern void __init init_microdev_irq(void)
 {
 	int i;
 
-		/* disable interrupts on the FPGA INTC register */
+	/* disable interrupts on the FPGA INTC register */
 	ctrl_outl(~0ul, MICRODEV_FPGA_INTDSB_REG);
 
 	for (i = 0; i < NUM_EXTERNAL_IRQS; i++)
@@ -179,5 +159,3 @@
 	printk("FPGA_INTPRI[3..0] = %08x:%08x:%08x:%08x\n", *intprid, *intpric, *intprib, *intpria);
 	printk("-------------------------------------------------------------------------------\n");
 }
-
-
diff --git a/arch/sh/boards/mach-microdev/led.c b/arch/sh/boards/mach-microdev/led.c
deleted file mode 100644
index 36e54b4..0000000
--- a/arch/sh/boards/mach-microdev/led.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * linux/arch/sh/boards/superh/microdev/led.c
- *
- * Copyright (C) 2002 Stuart Menefy <stuart.menefy@st.com>
- * Copyright (C) 2003 Richard Curnow (Richard.Curnow@superh.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- */
-
-#include <asm/io.h>
-
-#define LED_REGISTER 0xa6104d20
-
-static void mach_led_d9(int value)
-{
-	unsigned long reg;
-	reg = ctrl_inl(LED_REGISTER);
-	reg &= ~1;
-	reg |= (value & 1);
-	ctrl_outl(reg, LED_REGISTER);
-	return;
-}
-
-static void mach_led_d10(int value)
-{
-	unsigned long reg;
-	reg = ctrl_inl(LED_REGISTER);
-	reg &= ~2;
-	reg |= ((value & 1) << 1);
-	ctrl_outl(reg, LED_REGISTER);
-	return;
-}
-
-
-#ifdef CONFIG_HEARTBEAT
-#include <linux/sched.h>
-
-static unsigned char banner_table[] = {
-	0x11, 0x01, 0x11, 0x01, 0x11, 0x03,
-	0x11, 0x01, 0x11, 0x01, 0x13, 0x03,
-	0x11, 0x01, 0x13, 0x01, 0x13, 0x01, 0x11, 0x03,
-	0x11, 0x03,
-	0x11, 0x01, 0x13, 0x01, 0x11, 0x03,
-	0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x07,
-	0x13, 0x01, 0x13, 0x03,
-	0x11, 0x01, 0x11, 0x03,
-	0x13, 0x01, 0x11, 0x01, 0x13, 0x01, 0x11, 0x03,
-	0x11, 0x01, 0x13, 0x01, 0x11, 0x03,
-	0x13, 0x01, 0x13, 0x01, 0x13, 0x03,
-	0x13, 0x01, 0x11, 0x01, 0x11, 0x03,
-	0x11, 0x03,
-	0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x13, 0x07,
-	0xff
-};
-
-static void banner(void)
-{
-	static int pos = 0;
-	static int count = 0;
-
-	if (count) {
-		count--;
-	} else {
-		int val = banner_table[pos];
-		if (val == 0xff) {
-			pos = 0;
-			val = banner_table[pos];
-		}
-		pos++;
-		mach_led_d10((val >> 4) & 1);
-		count = 10 * (val & 0xf);
-	}
-}
-
-/* From heartbeat_harp in the stboards directory */
-/* acts like an actual heart beat -- ie thump-thump-pause... */
-void microdev_heartbeat(void)
-{
-	static unsigned cnt = 0, period = 0, dist = 0;
-
-	if (cnt == 0 || cnt == dist)
-		mach_led_d9(1);
-	else if (cnt == 7 || cnt == dist+7)
-		mach_led_d9(0);
-
-	if (++cnt > period) {
-		cnt = 0;
-		/* The hyperbolic function below modifies the heartbeat period
-		 * length in dependency of the current (5min) load. It goes
-		 * through the points f(0)=126, f(1)=86, f(5)=51,
-		 * f(inf)->30. */
-		period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
-		dist = period / 4;
-	}
-
-	banner();
-}
-
-#endif
diff --git a/arch/sh/boards/mach-microdev/setup.c b/arch/sh/boards/mach-microdev/setup.c
index a9202fe..d1df2a4 100644
--- a/arch/sh/boards/mach-microdev/setup.c
+++ b/arch/sh/boards/mach-microdev/setup.c
@@ -17,70 +17,12 @@
 #include <mach/microdev.h>
 #include <asm/io.h>
 #include <asm/machvec.h>
-
-extern void microdev_heartbeat(void);
-
-
-/****************************************************************************/
-
-
-	/*
-	 * Setup for the SMSC FDC37C93xAPM
-	 */
-#define SMSC_CONFIG_PORT_ADDR	 (0x3F0)
-#define SMSC_INDEX_PORT_ADDR	 SMSC_CONFIG_PORT_ADDR
-#define SMSC_DATA_PORT_ADDR	 (SMSC_INDEX_PORT_ADDR + 1)
-
-#define SMSC_ENTER_CONFIG_KEY	 0x55
-#define SMSC_EXIT_CONFIG_KEY	 0xaa
-
-#define SMCS_LOGICAL_DEV_INDEX 	 0x07	/* Logical Device Number */
-#define SMSC_DEVICE_ID_INDEX	 0x20	/* Device ID */
-#define SMSC_DEVICE_REV_INDEX	 0x21	/* Device Revision */
-#define SMSC_ACTIVATE_INDEX	 0x30	/* Activate */
-#define SMSC_PRIMARY_BASE_INDEX	 0x60	/* Primary Base Address */
-#define SMSC_SECONDARY_BASE_INDEX 0x62	/* Secondary Base Address */
-#define SMSC_PRIMARY_INT_INDEX	 0x70	/* Primary Interrupt Select */
-#define SMSC_SECONDARY_INT_INDEX 0x72	/* Secondary Interrupt Select */
-#define SMSC_HDCS0_INDEX	 0xf0	/* HDCS0 Address Decoder */
-#define SMSC_HDCS1_INDEX	 0xf1	/* HDCS1 Address Decoder */
-
-#define SMSC_IDE1_DEVICE	1	/* IDE #1 logical device */
-#define SMSC_IDE2_DEVICE	2	/* IDE #2 logical device */
-#define SMSC_PARALLEL_DEVICE	3	/* Parallel Port logical device */
-#define SMSC_SERIAL1_DEVICE	4	/* Serial #1 logical device */
-#define SMSC_SERIAL2_DEVICE	5	/* Serial #2 logical device */
-#define SMSC_KEYBOARD_DEVICE	7	/* Keyboard logical device */
-#define SMSC_CONFIG_REGISTERS	8	/* Configuration Registers (Aux I/O) */
-
-#define SMSC_READ_INDEXED(index) ({ \
-	outb((index), SMSC_INDEX_PORT_ADDR); \
-	inb(SMSC_DATA_PORT_ADDR); })
-#define SMSC_WRITE_INDEXED(val, index) ({ \
-	outb((index), SMSC_INDEX_PORT_ADDR); \
-	outb((val),   SMSC_DATA_PORT_ADDR); })
-
-#define	IDE1_PRIMARY_BASE	0x01f0	/* Task File Registe base for IDE #1 */
-#define	IDE1_SECONDARY_BASE	0x03f6	/* Miscellaneous AT registers for IDE #1 */
-#define	IDE2_PRIMARY_BASE	0x0170	/* Task File Registe base for IDE #2 */
-#define	IDE2_SECONDARY_BASE	0x0376	/* Miscellaneous AT registers for IDE #2 */
-
-#define SERIAL1_PRIMARY_BASE	0x03f8
-#define SERIAL2_PRIMARY_BASE	0x02f8
-
-#define	MSB(x)		( (x) >> 8 )
-#define	LSB(x)		( (x) & 0xff )
-
-	/* General-Purpose base address on CPU-board FPGA */
-#define	MICRODEV_FPGA_GP_BASE		0xa6100000ul
-
-	/* assume a Keyboard Controller is present */
-int microdev_kbd_controller_present = 1;
+#include <asm/sizes.h>
 
 static struct resource smc91x_resources[] = {
 	[0] = {
 		.start		= 0x300,
-		.end		= 0x300 + 0x0001000 - 1,
+		.end		= 0x300 + SZ_4K - 1,
 		.flags		= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -97,7 +39,6 @@
 	.resource	= smc91x_resources,
 };
 
-#ifdef CONFIG_FB_S1D13XXX
 static struct s1d13xxxfb_regval s1d13806_initregs[] = {
 	{ S1DREG_MISC,			0x00 },
 	{ S1DREG_COM_DISP_MODE,		0x00 },
@@ -216,12 +157,12 @@
 static struct resource s1d13806_resources[] = {
 	[0] = {
 		.start		= 0x07200000,
-		.end		= 0x07200000 + 0x00200000 - 1,
+		.end		= 0x07200000 + SZ_2M - 1,
 		.flags		= IORESOURCE_MEM,
 	},
 	[1] = {
 		.start		= 0x07000000,
-		.end		= 0x07000000 + 0x00200000 - 1,
+		.end		= 0x07000000 + SZ_2M - 1,
 		.flags		= IORESOURCE_MEM,
 	},
 };
@@ -236,145 +177,24 @@
 		.platform_data	= &s1d13806_platform_data,
 	},
 };
-#endif
 
 static struct platform_device *microdev_devices[] __initdata = {
 	&smc91x_device,
-#ifdef CONFIG_FB_S1D13XXX
 	&s1d13806_device,
-#endif
 };
 
 static int __init microdev_devices_setup(void)
 {
 	return platform_add_devices(microdev_devices, ARRAY_SIZE(microdev_devices));
 }
-
-/*
- * Setup for the SMSC FDC37C93xAPM
- */
-static int __init smsc_superio_setup(void)
-{
-
-	unsigned char devid, devrev;
-
-		/* Initially the chip is in run state */
-		/* Put it into configuration state */
-	outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
-
-		/* Read device ID info */
-	devid  = SMSC_READ_INDEXED(SMSC_DEVICE_ID_INDEX);
-	devrev = SMSC_READ_INDEXED(SMSC_DEVICE_REV_INDEX);
-	if ( (devid==0x30) && (devrev==0x01) )
-	{
-  		printk("SMSC FDC37C93xAPM SuperIO device detected\n");
-	}
-	else
-	{		/* not the device identity we expected */
-		printk("Not detected a SMSC FDC37C93xAPM SuperIO device (devid=0x%02x, rev=0x%02x)\n",
-			devid, devrev);
-			/* inform the keyboard driver that we have no keyboard controller */
-		microdev_kbd_controller_present = 0;
-			/* little point in doing anything else in this functon */
-		return 0;
-	}
-
-		/* Select the keyboard device */
-	SMSC_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX);
-		/* enable it */
-	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
-		/* enable the interrupts */
-	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_KEYBOARD, SMSC_PRIMARY_INT_INDEX);
-	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_MOUSE, SMSC_SECONDARY_INT_INDEX);
-
-		/* Select the Serial #1 device */
-	SMSC_WRITE_INDEXED(SMSC_SERIAL1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
-		/* enable it */
-	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
-		/* program with port addresses */
-	SMSC_WRITE_INDEXED(MSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
-	SMSC_WRITE_INDEXED(LSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
-	SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX);
-		/* enable the interrupts */
-	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL1, SMSC_PRIMARY_INT_INDEX);
-
-		/* Select the Serial #2 device */
-	SMSC_WRITE_INDEXED(SMSC_SERIAL2_DEVICE, SMCS_LOGICAL_DEV_INDEX);
-		/* enable it */
-	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
-		/* program with port addresses */
-	SMSC_WRITE_INDEXED(MSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
-	SMSC_WRITE_INDEXED(LSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
-	SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX);
-		/* enable the interrupts */
-	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL2, SMSC_PRIMARY_INT_INDEX);
-
-		/* Select the IDE#1 device */
-	SMSC_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
-		/* enable it */
-	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
-		/* program with port addresses */
-	SMSC_WRITE_INDEXED(MSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
-	SMSC_WRITE_INDEXED(LSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
-	SMSC_WRITE_INDEXED(MSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0);
-	SMSC_WRITE_INDEXED(LSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1);
-	SMSC_WRITE_INDEXED(0x0c, SMSC_HDCS0_INDEX);
-	SMSC_WRITE_INDEXED(0x00, SMSC_HDCS1_INDEX);
-		/* select the interrupt */
-	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE1, SMSC_PRIMARY_INT_INDEX);
-
-		/* Select the IDE#2 device */
-	SMSC_WRITE_INDEXED(SMSC_IDE2_DEVICE, SMCS_LOGICAL_DEV_INDEX);
-		/* enable it */
-	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
-		/* program with port addresses */
-	SMSC_WRITE_INDEXED(MSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
-	SMSC_WRITE_INDEXED(LSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
-	SMSC_WRITE_INDEXED(MSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0);
-	SMSC_WRITE_INDEXED(LSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1);
-		/* select the interrupt */
-	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE2, SMSC_PRIMARY_INT_INDEX);
-
-		/* Select the configuration registers */
-	SMSC_WRITE_INDEXED(SMSC_CONFIG_REGISTERS, SMCS_LOGICAL_DEV_INDEX);
-		/* enable the appropriate GPIO pins for IDE functionality:
-		 * bit[0]   In/Out		1==input;  0==output
-		 * bit[1]   Polarity		1==invert; 0==no invert
-		 * bit[2]   Int Enb #1		1==Enable Combined IRQ #1; 0==disable
-		 * bit[3:4] Function Select	00==original; 01==Alternate Function #1
-		 */
-	SMSC_WRITE_INDEXED(0x00, 0xc2);	/* GP42 = nIDE1_OE */
-	SMSC_WRITE_INDEXED(0x01, 0xc5);	/* GP45 = IDE1_IRQ */
-	SMSC_WRITE_INDEXED(0x00, 0xc6);	/* GP46 = nIOROP */
-	SMSC_WRITE_INDEXED(0x00, 0xc7);	/* GP47 = nIOWOP */
-	SMSC_WRITE_INDEXED(0x08, 0xe8);	/* GP20 = nIDE2_OE */
-
-		/* Exit the configuration state */
-	outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
-
-	return 0;
-}
-
-static void __init microdev_setup(char **cmdline_p)
-{
-	int * const fpgaRevisionRegister = (int*)(MICRODEV_FPGA_GP_BASE + 0x8ul);
-	const int fpgaRevision = *fpgaRevisionRegister;
-	int * const CacheControlRegister = (int*)CCR;
-
-	device_initcall(microdev_devices_setup);
-	device_initcall(smsc_superio_setup);
-
-	printk("SuperH %s board (FPGA rev: 0x%0x, CCR: 0x%0x)\n",
-		get_system_type(), fpgaRevision, *CacheControlRegister);
-}
+device_initcall(microdev_devices_setup);
 
 /*
  * The Machine Vector
  */
 static struct sh_machine_vector mv_sh4202_microdev __initmv = {
 	.mv_name		= "SH4-202 MicroDev",
-	.mv_setup		= microdev_setup,
-	.mv_nr_irqs		= 72,		/* QQQ need to check this - use the MACRO */
+	.mv_nr_irqs		= 72,
 
 	.mv_inb			= microdev_inb,
 	.mv_inw			= microdev_inw,
@@ -398,8 +218,4 @@
 	.mv_outsl		= microdev_outsl,
 
 	.mv_init_irq		= init_microdev_irq,
-
-#ifdef CONFIG_HEARTBEAT
-	.mv_heartbeat		= microdev_heartbeat,
-#endif
 };
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 9752819..cc1408119 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -89,6 +89,7 @@
 
 static struct platform_device sh_keysc_device = {
 	.name           = "sh_keysc",
+	.id             = 0, /* "keysc0" clock */
 	.num_resources  = ARRAY_SIZE(sh_keysc_resources),
 	.resource       = sh_keysc_resources,
 	.dev	= {
@@ -261,6 +262,8 @@
 		.sys_bus_cfg = {
 			.ldmt2r = 0x06000a09,
 			.ldmt3r = 0x180e3418,
+			/* set 1s delay to encourage fsync() */
+			.deferred_io_msec = 1000,
 		},
 	}
 #endif
@@ -273,6 +276,10 @@
 		.end	= 0xfe941fff,
 		.flags	= IORESOURCE_MEM,
 	},
+	[1] = {
+		.start	= 28,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 static struct platform_device migor_lcdc_device = {
@@ -300,6 +307,7 @@
 	gpio_set_value(GPIO_PTT3, 0);
 	mdelay(10);
 	gpio_set_value(GPIO_PTT3, 1);
+	mdelay(10); /* wait to let chip come out of reset */
 }
 
 static void camera_power_off(void)
@@ -432,6 +440,7 @@
 
 static struct platform_device migor_ceu_device = {
 	.name		= "sh_mobile_ceu",
+	.id             = 0, /* "ceu0" clock */
 	.num_resources	= ARRAY_SIZE(migor_ceu_resources),
 	.resource	= migor_ceu_resources,
 	.dev	= {
@@ -479,7 +488,6 @@
 	ctrl_outl(0x00110080, BSC_CS4WCR);
 
 	/* KEYSC */
-	clk_always_enable("mstp214"); /* KEYSC */
 	gpio_request(GPIO_FN_KEYOUT0, NULL);
 	gpio_request(GPIO_FN_KEYOUT1, NULL);
 	gpio_request(GPIO_FN_KEYOUT2, NULL);
@@ -501,7 +509,6 @@
 	gpio_request(GPIO_FN_IRQ6, NULL);
 
 	/* LCD Panel */
-	clk_always_enable("mstp200"); /* LCDC */
 #ifdef CONFIG_SH_MIGOR_QVGA /* LCDC - QVGA - Enable SYS Interface signals */
 	gpio_request(GPIO_FN_LCDD17, NULL);
 	gpio_request(GPIO_FN_LCDD16, NULL);
@@ -554,7 +561,6 @@
 #endif
 
 	/* CEU */
-	clk_always_enable("mstp203"); /* CEU */
 	gpio_request(GPIO_FN_VIO_CLK2, NULL);
 	gpio_request(GPIO_FN_VIO_VD2, NULL);
 	gpio_request(GPIO_FN_VIO_HD2, NULL);
@@ -589,12 +595,3 @@
 	return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices));
 }
 __initcall(migor_devices_setup);
-
-static void __init migor_setup(char **cmdline_p)
-{
-}
-
-static struct sh_machine_vector mv_migor __initmv = {
-	.mv_name		= "Migo-R",
-	.mv_setup		= migor_setup,
-};
diff --git a/arch/sh/boards/mach-rsk/Kconfig b/arch/sh/boards/mach-rsk/Kconfig
new file mode 100644
index 0000000..bff095d
--- /dev/null
+++ b/arch/sh/boards/mach-rsk/Kconfig
@@ -0,0 +1,18 @@
+if SH_RSK
+
+choice
+	prompt "RSK+ options"
+	default SH_RSK7203
+
+config SH_RSK7201
+	bool "RSK7201"
+	depends on CPU_SUBTYPE_SH7201
+
+config SH_RSK7203
+	bool "RSK7203"
+	select GENERIC_GPIO
+	depends on CPU_SUBTYPE_SH7203
+
+endchoice
+
+endif
diff --git a/arch/sh/boards/mach-rsk/Makefile b/arch/sh/boards/mach-rsk/Makefile
new file mode 100644
index 0000000..498da75
--- /dev/null
+++ b/arch/sh/boards/mach-rsk/Makefile
@@ -0,0 +1,2 @@
+obj-y				:= setup.o
+obj-$(CONFIG_SH_RSK7203)	+= devices-rsk7203.o
diff --git a/arch/sh/boards/mach-rsk/devices-rsk7203.c b/arch/sh/boards/mach-rsk/devices-rsk7203.c
new file mode 100644
index 0000000..73f743b
--- /dev/null
+++ b/arch/sh/boards/mach-rsk/devices-rsk7203.c
@@ -0,0 +1,103 @@
+/*
+ * Renesas Technology Europe RSK+ 7203 Support.
+ *
+ * Copyright (C) 2008 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/map.h>
+#include <linux/smc911x.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include <cpu/sh7203.h>
+
+static struct smc911x_platdata smc911x_info = {
+	.flags		= SMC911X_USE_16BIT,
+	.irq_flags	= IRQF_TRIGGER_LOW,
+};
+
+static struct resource smc911x_resources[] = {
+	[0] = {
+		.start		= 0x24000000,
+		.end		= 0x24000000 + 0x100,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= 64,
+		.end		= 64,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc911x_device = {
+	.name		= "smc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smc911x_resources),
+	.resource	= smc911x_resources,
+	.dev		= {
+		.platform_data = &smc911x_info,
+	},
+};
+
+static struct gpio_led rsk7203_gpio_leds[] = {
+	{
+		.name			= "green",
+		.gpio			= GPIO_PE10,
+		.active_low		= 1,
+	}, {
+		.name			= "orange",
+		.default_trigger	= "nand-disk",
+		.gpio			= GPIO_PE12,
+		.active_low		= 1,
+	}, {
+		.name			= "red:timer",
+		.default_trigger	= "timer",
+		.gpio			= GPIO_PC14,
+		.active_low		= 1,
+	}, {
+		.name			= "red:heartbeat",
+		.default_trigger	= "heartbeat",
+		.gpio			= GPIO_PE11,
+		.active_low		= 1,
+	},
+};
+
+static struct gpio_led_platform_data rsk7203_gpio_leds_info = {
+	.leds		= rsk7203_gpio_leds,
+	.num_leds	= ARRAY_SIZE(rsk7203_gpio_leds),
+};
+
+static struct platform_device led_device = {
+	.name		= "leds-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &rsk7203_gpio_leds_info,
+	},
+};
+
+static struct platform_device *rsk7203_devices[] __initdata = {
+	&smc911x_device,
+	&led_device,
+};
+
+static int __init rsk7203_devices_setup(void)
+{
+	/* Select pins for SCIF0 */
+	gpio_request(GPIO_FN_TXD0, NULL);
+	gpio_request(GPIO_FN_RXD0, NULL);
+
+	return platform_add_devices(rsk7203_devices,
+				    ARRAY_SIZE(rsk7203_devices));
+}
+device_initcall(rsk7203_devices_setup);
diff --git a/arch/sh/boards/mach-rsk/setup.c b/arch/sh/boards/mach-rsk/setup.c
new file mode 100644
index 0000000..af64d03
--- /dev/null
+++ b/arch/sh/boards/mach-rsk/setup.c
@@ -0,0 +1,106 @@
+/*
+ * Renesas Technology Europe RSK+ Support.
+ *
+ * Copyright (C) 2008 Paul Mundt
+ * Copyright (C) 2008 Peter Griffin <pgriffin@mpc-data.co.uk>
+ *
+ * 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/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/map.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+
+static const char *probes[] = { "cmdlinepart", NULL };
+
+static struct mtd_partition *parsed_partitions;
+
+static struct mtd_partition rsk_partitions[] = {
+	{
+		.name		= "Bootloader",
+		.offset		= 0x00000000,
+		.size		= 0x00040000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "Kernel",
+		.offset		= MTDPART_OFS_NXTBLK,
+		.size		= 0x001c0000,
+	}, {
+		.name		= "Flash_FS",
+		.offset		= MTDPART_OFS_NXTBLK,
+		.size		= MTDPART_SIZ_FULL,
+	}
+};
+
+static struct physmap_flash_data flash_data = {
+	.width		= 2,
+};
+
+static struct resource flash_resource = {
+	.start		= 0x20000000,
+	.end		= 0x20400000,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device flash_device = {
+	.name		= "physmap-flash",
+	.id		= -1,
+	.resource	= &flash_resource,
+	.num_resources	= 1,
+	.dev		= {
+		.platform_data = &flash_data,
+	},
+};
+
+static struct mtd_info *flash_mtd;
+
+static struct map_info rsk_flash_map = {
+	.name		= "RSK+ Flash",
+	.size		= 0x400000,
+	.bankwidth	= 2,
+};
+
+static void __init set_mtd_partitions(void)
+{
+	int nr_parts = 0;
+
+	simple_map_init(&rsk_flash_map);
+	flash_mtd = do_map_probe("cfi_probe", &rsk_flash_map);
+	nr_parts = parse_mtd_partitions(flash_mtd, probes,
+					&parsed_partitions, 0);
+	/* If there is no partition table, used the hard coded table */
+	if (nr_parts <= 0) {
+		flash_data.parts = rsk_partitions;
+		flash_data.nr_parts = ARRAY_SIZE(rsk_partitions);
+	} else {
+		flash_data.nr_parts = nr_parts;
+		flash_data.parts = parsed_partitions;
+	}
+}
+
+static struct platform_device *rsk_devices[] __initdata = {
+	&flash_device,
+};
+
+static int __init rsk_devices_setup(void)
+{
+	set_mtd_partitions();
+	return platform_add_devices(rsk_devices,
+				    ARRAY_SIZE(rsk_devices));
+}
+device_initcall(rsk_devices_setup);
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_rsk __initmv = {
+	.mv_name        = "RSK+",
+};
diff --git a/arch/sh/boards/mach-se/7343/Makefile b/arch/sh/boards/mach-se/7343/Makefile
index 3024796..4c3666a 100644
--- a/arch/sh/boards/mach-se/7343/Makefile
+++ b/arch/sh/boards/mach-se/7343/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the 7343 SolutionEngine specific parts of the kernel
 #
 
-obj-y	 := setup.o io.o irq.o
+obj-y	 := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/7343/io.c b/arch/sh/boards/mach-se/7343/io.c
deleted file mode 100644
index 8741abc..0000000
--- a/arch/sh/boards/mach-se/7343/io.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * arch/sh/boards/se/7343/io.c
- *
- * I/O routine for SH-Mobile3AS 7343 SolutionEngine.
- *
- */
-#include <linux/kernel.h>
-#include <asm/io.h>
-#include <mach-se/mach/se7343.h>
-
-#define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a)
-
-struct iop {
-	unsigned long start, end;
-	unsigned long base;
-	struct iop *(*check) (struct iop * p, unsigned long port);
-	unsigned char (*inb) (struct iop * p, unsigned long port);
-	unsigned short (*inw) (struct iop * p, unsigned long port);
-	void (*outb) (struct iop * p, unsigned char value, unsigned long port);
-	void (*outw) (struct iop * p, unsigned short value, unsigned long port);
-};
-
-struct iop *
-simple_check(struct iop *p, unsigned long port)
-{
-	static int count;
-
-	if (count < 100)
-		count++;
-
-	port &= 0xFFFF;
-
-	if ((p->start <= port) && (port <= p->end))
-		return p;
-	else
-		badio(check, port);
-}
-
-struct iop *
-ide_check(struct iop *p, unsigned long port)
-{
-	if (((0x1f0 <= port) && (port <= 0x1f7)) || (port == 0x3f7))
-		return p;
-	return NULL;
-}
-
-unsigned char
-simple_inb(struct iop *p, unsigned long port)
-{
-	return *(unsigned char *) (p->base + port);
-}
-
-unsigned short
-simple_inw(struct iop *p, unsigned long port)
-{
-	return *(unsigned short *) (p->base + port);
-}
-
-void
-simple_outb(struct iop *p, unsigned char value, unsigned long port)
-{
-	*(unsigned char *) (p->base + port) = value;
-}
-
-void
-simple_outw(struct iop *p, unsigned short value, unsigned long port)
-{
-	*(unsigned short *) (p->base + port) = value;
-}
-
-unsigned char
-pcc_inb(struct iop *p, unsigned long port)
-{
-	unsigned long addr = p->base + port + 0x40000;
-	unsigned long v;
-
-	if (port & 1)
-		addr += 0x00400000;
-	v = *(volatile unsigned char *) addr;
-	return v;
-}
-
-void
-pcc_outb(struct iop *p, unsigned char value, unsigned long port)
-{
-	unsigned long addr = p->base + port + 0x40000;
-
-	if (port & 1)
-		addr += 0x00400000;
-	*(volatile unsigned char *) addr = value;
-}
-
-unsigned char
-bad_inb(struct iop *p, unsigned long port)
-{
-	badio(inb, port);
-}
-
-void
-bad_outb(struct iop *p, unsigned char value, unsigned long port)
-{
-	badio(inw, port);
-}
-
-#ifdef CONFIG_SMC91X
-/* MSTLANEX01 LAN at 0xb400:0000 */
-static struct iop laniop = {
-	.start = 0x00,
-	.end = 0x0F,
-	.base = 0x04000000,
-	.check = simple_check,
-	.inb = simple_inb,
-	.inw = simple_inw,
-	.outb = simple_outb,
-	.outw = simple_outw,
-};
-#endif
-
-#ifdef CONFIG_NE2000
-/* NE2000 pc card NIC */
-static struct iop neiop = {
-	.start = 0x280,
-	.end = 0x29f,
-	.base = 0xb0600000 + 0x80,	/* soft 0x280 -> hard 0x300 */
-	.check = simple_check,
-	.inb = pcc_inb,
-	.inw = simple_inw,
-	.outb = pcc_outb,
-	.outw = simple_outw,
-};
-#endif
-
-#ifdef CONFIG_IDE
-/* CF in CF slot */
-static struct iop cfiop = {
-	.base = 0xb0600000,
-	.check = ide_check,
-	.inb = pcc_inb,
-	.inw = simple_inw,
-	.outb = pcc_outb,
-	.outw = simple_outw,
-};
-#endif
-
-static __inline__ struct iop *
-port2iop(unsigned long port)
-{
-	if (0) ;
-#if defined(CONFIG_SMC91X)
-	else if (laniop.check(&laniop, port))
-		return &laniop;
-#endif
-#if defined(CONFIG_NE2000)
-	else if (neiop.check(&neiop, port))
-		return &neiop;
-#endif
-#if defined(CONFIG_IDE)
-	else if (cfiop.check(&cfiop, port))
-		return &cfiop;
-#endif
-	else
-		return NULL;
-}
-
-static inline void
-delay(void)
-{
-	ctrl_inw(0xac000000);
-	ctrl_inw(0xac000000);
-}
-
-unsigned char
-sh7343se_inb(unsigned long port)
-{
-	struct iop *p = port2iop(port);
-	return (p->inb) (p, port);
-}
-
-unsigned char
-sh7343se_inb_p(unsigned long port)
-{
-	unsigned char v = sh7343se_inb(port);
-	delay();
-	return v;
-}
-
-unsigned short
-sh7343se_inw(unsigned long port)
-{
-	struct iop *p = port2iop(port);
-	return (p->inw) (p, port);
-}
-
-unsigned int
-sh7343se_inl(unsigned long port)
-{
-	badio(inl, port);
-}
-
-void
-sh7343se_outb(unsigned char value, unsigned long port)
-{
-	struct iop *p = port2iop(port);
-	(p->outb) (p, value, port);
-}
-
-void
-sh7343se_outb_p(unsigned char value, unsigned long port)
-{
-	sh7343se_outb(value, port);
-	delay();
-}
-
-void
-sh7343se_outw(unsigned short value, unsigned long port)
-{
-	struct iop *p = port2iop(port);
-	(p->outw) (p, value, port);
-}
-
-void
-sh7343se_outl(unsigned int value, unsigned long port)
-{
-	badio(outl, port);
-}
-
-void
-sh7343se_insb(unsigned long port, void *addr, unsigned long count)
-{
-	unsigned char *a = addr;
-	struct iop *p = port2iop(port);
-	while (count--)
-		*a++ = (p->inb) (p, port);
-}
-
-void
-sh7343se_insw(unsigned long port, void *addr, unsigned long count)
-{
-	unsigned short *a = addr;
-	struct iop *p = port2iop(port);
-	while (count--)
-		*a++ = (p->inw) (p, port);
-}
-
-void
-sh7343se_insl(unsigned long port, void *addr, unsigned long count)
-{
-	badio(insl, port);
-}
-
-void
-sh7343se_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-	unsigned char *a = (unsigned char *) addr;
-	struct iop *p = port2iop(port);
-	while (count--)
-		(p->outb) (p, *a++, port);
-}
-
-void
-sh7343se_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-	unsigned short *a = (unsigned short *) addr;
-	struct iop *p = port2iop(port);
-	while (count--)
-		(p->outw) (p, *a++, port);
-}
-
-void
-sh7343se_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-	badio(outsw, port);
-}
diff --git a/arch/sh/boards/mach-se/7343/setup.c b/arch/sh/boards/mach-se/7343/setup.c
index 486f40b..4de56f3 100644
--- a/arch/sh/boards/mach-se/7343/setup.c
+++ b/arch/sh/boards/mach-se/7343/setup.c
@@ -1,36 +1,16 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/physmap.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+#include <linux/usb/isp116x.h>
+#include <linux/delay.h>
 #include <asm/machvec.h>
 #include <mach-se/mach/se7343.h>
 #include <asm/heartbeat.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
-static struct resource smc91x_resources[] = {
-	[0] = {
-		.start	= 0x10000000,
-		.end	= 0x1000000F,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		/*
-		 * shared with other devices via externel
-		 * interrupt controller in FPGA...
-		 */
-		.start	= SMC_IRQ,
-		.end	= SMC_IRQ,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device smc91x_device = {
-	.name		= "smc91x",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(smc91x_resources),
-	.resource	= smc91x_resources,
-};
-
 static struct resource heartbeat_resources[] = {
 	[0] = {
 		.start	= PA_LED,
@@ -94,10 +74,83 @@
 	.resource	= nor_flash_resources,
 };
 
+#define ST16C2550C_FLAGS (UPF_BOOT_AUTOCONF | UPF_IOREMAP)
+
+static struct plat_serial8250_port serial_platform_data[] = {
+	[0] = {
+		.iotype		= UPIO_MEM,
+		.mapbase	= 0x16000000,
+		.regshift	= 1,
+		.flags		= ST16C2550C_FLAGS,
+		.irq		= UARTA_IRQ,
+		.uartclk	= 7372800,
+	},
+	[1] = {
+		.iotype		= UPIO_MEM,
+		.mapbase	= 0x17000000,
+		.regshift	= 1,
+		.flags		= ST16C2550C_FLAGS,
+		.irq		= UARTB_IRQ,
+		.uartclk	= 7372800,
+	},
+	{ },
+};
+
+static struct platform_device uart_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= serial_platform_data,
+	},
+};
+
+static void isp116x_delay(struct device *dev, int delay)
+{
+	ndelay(delay);
+}
+
+static struct resource usb_resources[] = {
+	[0] = {
+		.start  = 0x11800000,
+		.end    = 0x11800001,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = 0x11800002,
+		.end    = 0x11800003,
+		.flags  = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start  = USB_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct isp116x_platform_data usb_platform_data = {
+	.sel15Kres		= 1,
+	.oc_enable		= 1,
+	.int_act_high		= 0,
+	.int_edge_triggered	= 0,
+	.remote_wakeup_enable	= 0,
+	.delay			= isp116x_delay,
+};
+
+static struct platform_device usb_device = {
+	.name			= "isp116x-hcd",
+	.id			= -1,
+	.num_resources  	= ARRAY_SIZE(usb_resources),
+	.resource       	= usb_resources,
+	.dev			= {
+		.platform_data	= &usb_platform_data,
+	},
+
+};
+
 static struct platform_device *sh7343se_platform_devices[] __initdata = {
-	&smc91x_device,
 	&heartbeat_device,
 	&nor_flash_device,
+	&uart_device,
+	&usb_device,
 };
 
 static int __init sh7343se_devices_setup(void)
@@ -126,27 +179,6 @@
 static struct sh_machine_vector mv_7343se __initmv = {
 	.mv_name = "SolutionEngine 7343",
 	.mv_setup = sh7343se_setup,
-	.mv_nr_irqs = 108,
-	.mv_inb = sh7343se_inb,
-	.mv_inw = sh7343se_inw,
-	.mv_inl = sh7343se_inl,
-	.mv_outb = sh7343se_outb,
-	.mv_outw = sh7343se_outw,
-	.mv_outl = sh7343se_outl,
-
-	.mv_inb_p = sh7343se_inb_p,
-	.mv_inw_p = sh7343se_inw,
-	.mv_inl_p = sh7343se_inl,
-	.mv_outb_p = sh7343se_outb_p,
-	.mv_outw_p = sh7343se_outw,
-	.mv_outl_p = sh7343se_outl,
-
-	.mv_insb = sh7343se_insb,
-	.mv_insw = sh7343se_insw,
-	.mv_insl = sh7343se_insl,
-	.mv_outsb = sh7343se_outsb,
-	.mv_outsw = sh7343se_outsw,
-	.mv_outsl = sh7343se_outsl,
-
+	.mv_nr_irqs = SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_NR,
 	.mv_init_irq = init_7343se_IRQ,
 };
diff --git a/arch/sh/boards/mach-se/770x/setup.c b/arch/sh/boards/mach-se/770x/setup.c
index 9123d96..527eb6b 100644
--- a/arch/sh/boards/mach-se/770x/setup.c
+++ b/arch/sh/boards/mach-se/770x/setup.c
@@ -8,8 +8,9 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <asm/machvec.h>
 #include <mach-se/mach/se.h>
+#include <mach-se/mach/mrshpc.h>
+#include <asm/machvec.h>
 #include <asm/io.h>
 #include <asm/smc37c93x.h>
 #include <asm/heartbeat.h>
@@ -175,6 +176,7 @@
 
 static int __init se_devices_setup(void)
 {
+	mrshpc_setup_windows();
 	return platform_add_devices(se_devices, ARRAY_SIZE(se_devices));
 }
 device_initcall(se_devices_setup);
diff --git a/arch/sh/boards/mach-se/7721/setup.c b/arch/sh/boards/mach-se/7721/setup.c
index d3fc80f..55af4c3 100644
--- a/arch/sh/boards/mach-se/7721/setup.c
+++ b/arch/sh/boards/mach-se/7721/setup.c
@@ -12,8 +12,9 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <asm/machvec.h>
 #include <mach-se/mach/se7721.h>
+#include <mach-se/mach/mrshpc.h>
+#include <asm/machvec.h>
 #include <asm/io.h>
 #include <asm/heartbeat.h>
 
@@ -74,8 +75,8 @@
 
 static int __init se7721_devices_setup(void)
 {
-	return platform_add_devices(se7721_devices,
-		ARRAY_SIZE(se7721_devices));
+	mrshpc_setup_windows();
+	return platform_add_devices(se7721_devices, ARRAY_SIZE(se7721_devices));
 }
 device_initcall(se7721_devices_setup);
 
diff --git a/arch/sh/boards/mach-se/7722/setup.c b/arch/sh/boards/mach-se/7722/setup.c
index fe6f965..af84904 100644
--- a/arch/sh/boards/mach-se/7722/setup.c
+++ b/arch/sh/boards/mach-se/7722/setup.c
@@ -15,9 +15,10 @@
 #include <linux/ata_platform.h>
 #include <linux/input.h>
 #include <linux/smc91x.h>
+#include <mach-se/mach/se7722.h>
+#include <mach-se/mach/mrshpc.h>
 #include <asm/machvec.h>
 #include <asm/clock.h>
-#include <mach-se/mach/se7722.h>
 #include <asm/io.h>
 #include <asm/heartbeat.h>
 #include <asm/sh_keysc.h>
@@ -130,6 +131,7 @@
 
 static struct platform_device sh_keysc_device = {
 	.name           = "sh_keysc",
+	.id             = 0, /* "keysc0" clock */
 	.num_resources  = ARRAY_SIZE(sh_keysc_resources),
 	.resource       = sh_keysc_resources,
 	.dev	= {
@@ -146,10 +148,8 @@
 
 static int __init se7722_devices_setup(void)
 {
-	clk_always_enable("mstp214"); /* KEYSC */
-
-	return platform_add_devices(se7722_devices,
-		ARRAY_SIZE(se7722_devices));
+	mrshpc_setup_windows();
+	return platform_add_devices(se7722_devices, ARRAY_SIZE(se7722_devices));
 }
 device_initcall(se7722_devices_setup);
 
diff --git a/arch/sh/boards/mach-sh03/setup.c b/arch/sh/boards/mach-sh03/setup.c
index 5771219..74cfb4b 100644
--- a/arch/sh/boards/mach-sh03/setup.c
+++ b/arch/sh/boards/mach-sh03/setup.c
@@ -9,6 +9,7 @@
 #include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/ata_platform.h>
 #include <asm/io.h>
 #include <asm/rtc.h>
 #include <mach-sh03/mach/io.h>
@@ -20,19 +21,6 @@
 	plat_irq_setup_pins(IRQ_MODE_IRQ);
 }
 
-extern void *cf_io_base;
-
-static void __iomem *sh03_ioport_map(unsigned long port, unsigned int size)
-{
-	if (PXSEG(port))
-		return (void __iomem *)port;
-	/* CompactFlash (IDE) */
-	if (((port >= 0x1f0) && (port <= 0x1f7)) || (port == 0x3f6))
-		return (void __iomem *)((unsigned long)cf_io_base + port);
-
-        return (void __iomem *)(port + PCI_IO_BASE);
-}
-
 /* arch/sh/boards/sh03/rtc.c */
 void sh03_time_init(void);
 
@@ -41,6 +29,30 @@
 	board_time_init = sh03_time_init;
 }
 
+static struct resource cf_ide_resources[] = {
+	[0] = {
+		.start  = 0x1f0,
+		.end    = 0x1f0 + 8,
+		.flags  = IORESOURCE_IO,
+	},
+	[1] = {
+		.start  = 0x1f0 + 0x206,
+		.end    = 0x1f0 +8 + 0x206 + 8,
+		.flags  = IORESOURCE_IO,
+	},
+	[2] = {
+		.start  = IRL2_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cf_ide_device = {
+	.name		= "pata_platform",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(cf_ide_resources),
+	.resource	= cf_ide_resources,
+};
+
 static struct resource heartbeat_resources[] = {
 	[0] = {
 		.start	= 0xa0800000,
@@ -58,10 +70,30 @@
 
 static struct platform_device *sh03_devices[] __initdata = {
 	&heartbeat_device,
+	&cf_ide_device,
 };
 
 static int __init sh03_devices_setup(void)
 {
+	pgprot_t prot;
+	unsigned long paddrbase;
+	void *cf_ide_base;
+
+	/* open I/O area window */
+	paddrbase = virt_to_phys((void *)PA_AREA5_IO);
+	prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16);
+	cf_ide_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
+	if (!cf_ide_base) {
+		printk("allocate_cf_area : can't open CF I/O window!\n");
+		return -ENOMEM;
+	}
+
+	/* IDE cmd address : 0x1f0-0x1f7 and 0x3f6 */
+	cf_ide_resources[0].start += (unsigned long)cf_ide_base;
+	cf_ide_resources[0].end   += (unsigned long)cf_ide_base;
+	cf_ide_resources[1].start += (unsigned long)cf_ide_base;
+	cf_ide_resources[1].end   += (unsigned long)cf_ide_base;
+
 	return platform_add_devices(sh03_devices, ARRAY_SIZE(sh03_devices));
 }
 __initcall(sh03_devices_setup);
@@ -70,6 +102,5 @@
 	.mv_name		= "Interface (CTP/PCI-SH03)",
 	.mv_setup		= sh03_setup,
 	.mv_nr_irqs		= 48,
-	.mv_ioport_map		= sh03_ioport_map,
 	.mv_init_irq		= init_sh03_IRQ,
 };
diff --git a/arch/sh/boards/mach-systemh/irq.c b/arch/sh/boards/mach-systemh/irq.c
index 53840687..986a0e7 100644
--- a/arch/sh/boards/mach-systemh/irq.c
+++ b/arch/sh/boards/mach-systemh/irq.c
@@ -12,8 +12,8 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <mach/systemh7751.h>
 #include <asm/smc37c93x.h>
 
@@ -24,35 +24,17 @@
 static unsigned long *systemh_irq_request_register = (unsigned long *)0xB3F10000;
 
 /* forward declaration */
-static unsigned int startup_systemh_irq(unsigned int irq);
-static void shutdown_systemh_irq(unsigned int irq);
 static void enable_systemh_irq(unsigned int irq);
 static void disable_systemh_irq(unsigned int irq);
 static void mask_and_ack_systemh(unsigned int);
-static void end_systemh_irq(unsigned int irq);
 
-/* hw_interrupt_type */
-static struct hw_interrupt_type systemh_irq_type = {
-	.typename = " SystemH Register",
-	.startup = startup_systemh_irq,
-	.shutdown = shutdown_systemh_irq,
-	.enable = enable_systemh_irq,
-	.disable = disable_systemh_irq,
+static struct irq_chip systemh_irq_type = {
+	.name = " SystemH Register",
+	.unmask = enable_systemh_irq,
+	.mask = disable_systemh_irq,
 	.ack = mask_and_ack_systemh,
-	.end = end_systemh_irq
 };
 
-static unsigned int startup_systemh_irq(unsigned int irq)
-{
-	enable_systemh_irq(irq);
-	return 0; /* never anything pending */
-}
-
-static void shutdown_systemh_irq(unsigned int irq)
-{
-	disable_systemh_irq(irq);
-}
-
 static void disable_systemh_irq(unsigned int irq)
 {
 	if (systemh_irq_mask_register) {
@@ -86,16 +68,9 @@
 	disable_systemh_irq(irq);
 }
 
-static void end_systemh_irq(unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_systemh_irq(irq);
-}
-
 void make_systemh_irq(unsigned int irq)
 {
 	disable_irq_nosync(irq);
-	irq_desc[irq].chip = &systemh_irq_type;
+	set_irq_chip_and_handler(irq, &systemh_irq_type, handle_level_irq);
 	disable_systemh_irq(irq);
 }
-
diff --git a/arch/sh/cchips/hd6446x/hd64461.c b/arch/sh/cchips/hd6446x/hd64461.c
index f1a4a07..27ceeb9 100644
--- a/arch/sh/cchips/hd6446x/hd64461.c
+++ b/arch/sh/cchips/hd6446x/hd64461.c
@@ -10,99 +10,49 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/irq.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/irq.h>
 #include <asm/hd64461.h>
 
 /* This belongs in cpu specific */
 #define INTC_ICR1 0xA4140010UL
 
-static void disable_hd64461_irq(unsigned int irq)
+static void hd64461_mask_irq(unsigned int irq)
 {
 	unsigned short nimr;
 	unsigned short mask = 1 << (irq - HD64461_IRQBASE);
 
-	nimr = inw(HD64461_NIMR);
+	nimr = __raw_readw(HD64461_NIMR);
 	nimr |= mask;
-	outw(nimr, HD64461_NIMR);
+	__raw_writew(nimr, HD64461_NIMR);
 }
 
-static void enable_hd64461_irq(unsigned int irq)
+static void hd64461_unmask_irq(unsigned int irq)
 {
 	unsigned short nimr;
 	unsigned short mask = 1 << (irq - HD64461_IRQBASE);
 
-	nimr = inw(HD64461_NIMR);
+	nimr = __raw_readw(HD64461_NIMR);
 	nimr &= ~mask;
-	outw(nimr, HD64461_NIMR);
+	__raw_writew(nimr, HD64461_NIMR);
 }
 
-static void mask_and_ack_hd64461(unsigned int irq)
+static void hd64461_mask_and_ack_irq(unsigned int irq)
 {
-	disable_hd64461_irq(irq);
+	hd64461_mask_irq(irq);
 #ifdef CONFIG_HD64461_ENABLER
 	if (irq == HD64461_IRQBASE + 13)
-		outb(0x00, HD64461_PCC1CSCR);
+		__raw_writeb(0x00, HD64461_PCC1CSCR);
 #endif
 }
 
-static void end_hd64461_irq(unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_hd64461_irq(irq);
-}
-
-static unsigned int startup_hd64461_irq(unsigned int irq)
-{
-	enable_hd64461_irq(irq);
-	return 0;
-}
-
-static void shutdown_hd64461_irq(unsigned int irq)
-{
-	disable_hd64461_irq(irq);
-}
-
-static struct hw_interrupt_type hd64461_irq_type = {
-	.typename	= "HD64461-IRQ",
-	.startup	= startup_hd64461_irq,
-	.shutdown	= shutdown_hd64461_irq,
-	.enable		= enable_hd64461_irq,
-	.disable	= disable_hd64461_irq,
-	.ack		= mask_and_ack_hd64461,
-	.end		= end_hd64461_irq,
+static struct irq_chip hd64461_irq_chip = {
+	.name		= "HD64461-IRQ",
+	.mask		= hd64461_mask_irq,
+	.mask_ack	= hd64461_mask_and_ack_irq,
+	.unmask		= hd64461_unmask_irq,
 };
 
-static irqreturn_t hd64461_interrupt(int irq, void *dev_id)
-{
-	printk(KERN_INFO
-	       "HD64461: spurious interrupt, nirr: 0x%x nimr: 0x%x\n",
-	       inw(HD64461_NIRR), inw(HD64461_NIMR));
-
-	return IRQ_NONE;
-}
-
-static struct {
-	int (*func) (int, void *);
-	void *dev;
-} hd64461_demux[HD64461_IRQ_NUM];
-
-void hd64461_register_irq_demux(int irq,
-				int (*demux) (int irq, void *dev), void *dev)
-{
-	hd64461_demux[irq - HD64461_IRQBASE].func = demux;
-	hd64461_demux[irq - HD64461_IRQBASE].dev = dev;
-}
-
-EXPORT_SYMBOL(hd64461_register_irq_demux);
-
-void hd64461_unregister_irq_demux(int irq)
-{
-	hd64461_demux[irq - HD64461_IRQBASE].func = 0;
-}
-
-EXPORT_SYMBOL(hd64461_unregister_irq_demux);
-
 int hd64461_irq_demux(int irq)
 {
 	if (irq == CONFIG_HD64461_IRQ) {
@@ -115,25 +65,11 @@
 		for (bit = 1, i = 0; i < 16; bit <<= 1, i++)
 			if (nirr & bit)
 				break;
-		if (i == 16)
-			irq = CONFIG_HD64461_IRQ;
-		else {
-			irq = HD64461_IRQBASE + i;
-			if (hd64461_demux[i].func != 0) {
-				irq = hd64461_demux[i].func(irq, hd64461_demux[i].dev);
-			}
-		}
+		irq = HD64461_IRQBASE + i;
 	}
 	return irq;
 }
 
-static struct irqaction irq0 = {
-	.handler = hd64461_interrupt,
-	.flags = IRQF_DISABLED,
-	.mask = CPU_MASK_NONE,
-	.name = "HD64461",
-};
-
 int __init setup_hd64461(void)
 {
 	int i;
@@ -146,22 +82,21 @@
 	       CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ, HD64461_IRQBASE,
 	       HD64461_IRQBASE + 15);
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7709)	/* Should be at processor specific part.. */
-	outw(0x2240, INTC_ICR1);
+/* Should be at processor specific part.. */
+#if defined(CONFIG_CPU_SUBTYPE_SH7709)
+	__raw_writew(0x2240, INTC_ICR1);
 #endif
-	outw(0xffff, HD64461_NIMR);
+	__raw_writew(0xffff, HD64461_NIMR);
 
 	/*  IRQ 80 -> 95 belongs to HD64461  */
-	for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) {
-		irq_desc[i].chip = &hd64461_irq_type;
-	}
-
-	setup_irq(CONFIG_HD64461_IRQ, &irq0);
+	for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++)
+		set_irq_chip_and_handler(i, &hd64461_irq_chip,
+					 handle_level_irq);
 
 #ifdef CONFIG_HD64461_ENABLER
 	printk(KERN_INFO "HD64461: enabling PCMCIA devices\n");
-	outb(0x4c, HD64461_PCC1CSCIER);
-	outb(0x00, HD64461_PCC1CSCR);
+	__raw_writeb(0x4c, HD64461_PCC1CSCIER);
+	__raw_writeb(0x00, HD64461_PCC1CSCR);
 #endif
 
 	return 0;
diff --git a/arch/sh/configs/edosk7705_defconfig b/arch/sh/configs/edosk7705_defconfig
new file mode 100644
index 0000000..8f4329f
--- /dev/null
+++ b/arch/sh/configs/edosk7705_defconfig
@@ -0,0 +1,438 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.28-rc6
+# Wed Dec 17 13:53:02 2008
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
+CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_GPIO is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_ARCH_SUSPEND_POSSIBLE is not set
+# CONFIG_ARCH_HIBERNATION_POSSIBLE is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+# CONFIG_EXPERIMENTAL is not set
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS 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_EMBEDDED=y
+# CONFIG_UID16 is not set
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PRINTK is not set
+# CONFIG_BUG is not set
+# CONFIG_ELF_CORE is not set
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+CONFIG_SHMEM=y
+# CONFIG_AIO is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# 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_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+# CONFIG_MODULES is not set
+# CONFIG_BLOCK is not set
+CONFIG_CLASSIC_RCU=y
+# CONFIG_FREEZER is not set
+
+#
+# System type
+#
+CONFIG_CPU_SH3=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7201 is not set
+# CONFIG_CPU_SUBTYPE_SH7203 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7263 is not set
+# CONFIG_CPU_SUBTYPE_MXG is not set
+CONFIG_CPU_SUBTYPE_SH7705=y
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7721 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7763 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH7366 is not set
+# CONFIG_CPU_SUBTYPE_SH5_101 is not set
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_29BIT=y
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_ENTRY_OFFSET=0x00001000
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+CONFIG_UNEVICTABLE_LRU=y
+
+#
+# Cache configuration
+#
+CONFIG_SH7705_CACHE_32KB=y
+# CONFIG_SH_DIRECT_MAPPED is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_ADC=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Board support
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+CONFIG_SH_EDOSK7705=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=31250000
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# 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_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_GUSA=y
+# CONFIG_GUSA_RB is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI 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 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK 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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_UNIX98_PTYS 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_I2C is not set
+# CONFIG_SPI 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_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_UIO is not set
+# CONFIG_STAGING is not set
+CONFIG_STAGING_EXCLUDE_BUILD=y
+
+#
+# File systems
+#
+# 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
+
+#
+# Pseudo filesystems
+#
+# CONFIG_PROC_FS is not set
+# CONFIG_SYSFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_MORE_COMPILE_OPTIONS is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# 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
diff --git a/arch/sh/configs/rsk7201_defconfig b/arch/sh/configs/rsk7201_defconfig
new file mode 100644
index 0000000..014c18c
--- /dev/null
+++ b/arch/sh/configs/rsk7201_defconfig
@@ -0,0 +1,703 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.28-rc6
+# Mon Dec  8 14:48:02 2008
+#
+CONFIG_SUPERH=y
+CONFIG_SUPERH32=y
+CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_GPIO is not set
+# CONFIG_GENERIC_TIME is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
+# CONFIG_ARCH_SUSPEND_POSSIBLE is not set
+# CONFIG_ARCH_HIBERNATION_POSSIBLE is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_NO_VIRT_TO_BUS=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_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC is not set
+CONFIG_LOG_BUF_SHIFT=14
+# 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=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+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=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS 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_AIO is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_SLAB is not set
+# CONFIG_SLUB is not set
+CONFIG_SLOB=y
+CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+# CONFIG_MODULE_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
+
+#
+# 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_CLASSIC_RCU=y
+# CONFIG_FREEZER is not set
+
+#
+# System type
+#
+CONFIG_CPU_SH2=y
+CONFIG_CPU_SH2A=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+CONFIG_CPU_SUBTYPE_SH7201=y
+# CONFIG_CPU_SUBTYPE_SH7203 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7263 is not set
+# CONFIG_CPU_SUBTYPE_MXG is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7720 is not set
+# CONFIG_CPU_SUBTYPE_SH7721 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_SH7723 is not set
+# CONFIG_CPU_SUBTYPE_SH7763 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+# CONFIG_CPU_SUBTYPE_SH7366 is not set
+# CONFIG_CPU_SUBTYPE_SH5_101 is not set
+# CONFIG_CPU_SUBTYPE_SH5_103 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_PAGE_OFFSET=0x00000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_29BIT=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_ENTRY_OFFSET=0x00001000
+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=y
+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=0
+CONFIG_NR_QUICK=2
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+CONFIG_CACHE_WRITEBACK=y
+# CONFIG_CACHE_WRITETHROUGH is not set
+# CONFIG_CACHE_OFF is not set
+
+#
+# Processor features
+#
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_SH_FPU=y
+CONFIG_CPU_HAS_FPU=y
+
+#
+# Board support
+#
+CONFIG_SH_RSK=y
+CONFIG_SH_RSK7201=y
+# CONFIG_SH_RSK7203 is not set
+
+#
+# Timer and clock configuration
+#
+# CONFIG_SH_CMT is not set
+CONFIG_SH_MTU2=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=40000000
+CONFIG_SH_CLK_MD=0
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+# CONFIG_SCHED_HRTICK is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_SECCOMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_GUSA=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=serial ignore_loglevel"
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# 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 (EXPERIMENTAL)
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+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 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_START=0x0
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=4
+# 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
+
+#
+# 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_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# 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
+
+#
+# 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_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 is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=8
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_UNIX98_PTYS 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 is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+# 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_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY 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
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+CONFIG_STAGING_EXCLUDE_BUILD=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# 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
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_XFS_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_SYSFS=y
+# CONFIG_TMPFS 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_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_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_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# 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=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# 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_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE 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
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=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_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/rsk7203_defconfig b/arch/sh/configs/rsk7203_defconfig
index 85b0ac4..dcdef31 100644
--- a/arch/sh/configs/rsk7203_defconfig
+++ b/arch/sh/configs/rsk7203_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27
-# Tue Oct 21 12:58:47 2008
+# Linux kernel version: 2.6.28-rc6
+# Mon Dec  8 14:35:03 2008
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
@@ -16,6 +16,8 @@
 CONFIG_GENERIC_GPIO=y
 # CONFIG_GENERIC_TIME is not set
 # CONFIG_GENERIC_CLOCKEVENTS is not set
+# CONFIG_ARCH_SUSPEND_POSSIBLE is not set
+# CONFIG_ARCH_HIBERNATION_POSSIBLE is not set
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -75,7 +77,6 @@
 CONFIG_EVENTFD=y
 CONFIG_AIO=y
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_PCI_QUIRKS=y
 # CONFIG_SLAB is not set
 # CONFIG_SLUB is not set
 CONFIG_SLOB=y
@@ -126,6 +127,7 @@
 CONFIG_CPU_SH2=y
 CONFIG_CPU_SH2A=y
 # CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7201 is not set
 CONFIG_CPU_SUBTYPE_SH7203=y
 # CONFIG_CPU_SUBTYPE_SH7206 is not set
 # CONFIG_CPU_SUBTYPE_SH7263 is not set
@@ -211,6 +213,8 @@
 #
 # Board support
 #
+CONFIG_SH_RSK=y
+# CONFIG_SH_RSK7201 is not set
 CONFIG_SH_RSK7203=y
 
 #
@@ -296,6 +300,14 @@
 CONFIG_BINFMT_SHARED_FLAT=y
 # CONFIG_HAVE_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
 CONFIG_NET=y
 
 #
@@ -477,6 +489,7 @@
 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
 
@@ -603,11 +616,11 @@
 # CONFIG_HWMON is not set
 CONFIG_THERMAL=y
 # CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
 
 #
 # Sonics Silicon Backplane
 #
-CONFIG_SSB_POSSIBLE=y
 # CONFIG_SSB is not set
 
 #
@@ -617,7 +630,11 @@
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_MFD_TMIO is not set
-# CONFIG_MFD_WM8400 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
 
 #
 # Multimedia devices
@@ -702,19 +719,22 @@
 CONFIG_USB_DEVICEFS=y
 CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND 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=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_ISP116X_HCD is not set
-# CONFIG_USB_ISP1760_HCD is not set
 # CONFIG_USB_SL811_HCD is not set
 CONFIG_USB_R8A66597_HCD=y
+# CONFIG_USB_HWA_HCD is not set
 
 #
 # USB Device Class drivers
@@ -725,11 +745,11 @@
 # 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 also be needed;
 #
 
 #
-# may also be needed; see USB_STORAGE Help for more information
+# see USB_STORAGE Help for more information
 #
 # CONFIG_USB_LIBUSUAL is not set
 
@@ -770,7 +790,22 @@
 # CONFIG_USB_GADGET is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
-# CONFIG_NEW_LEDS is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_GPIO=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
 # CONFIG_ACCESSIBILITY is not set
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
@@ -812,6 +847,7 @@
 # CONFIG_DMADEVICES is not set
 # CONFIG_UIO is not set
 # CONFIG_STAGING is not set
+CONFIG_STAGING_EXCLUDE_BUILD=y
 
 #
 # File systems
@@ -950,9 +986,14 @@
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_NOP_TRACER=y
-CONFIG_HAVE_FTRACE=y
-# CONFIG_FTRACE is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
diff --git a/arch/sh/configs/rts7751r2dplus_qemu_defconfig b/arch/sh/configs/rts7751r2dplus_qemu_defconfig
deleted file mode 100644
index ae8f630..0000000
--- a/arch/sh/configs/rts7751r2dplus_qemu_defconfig
+++ /dev/null
@@ -1,949 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27
-# Wed Oct 22 18:51:20 2008
-#
-CONFIG_SUPERH=y
-CONFIG_SUPERH32=y
-CONFIG_ARCH_DEFCONFIG="arch/sh/configs/shx3_defconfig"
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_BUG=y
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
-CONFIG_GENERIC_IRQ_PROBE=y
-# CONFIG_GENERIC_GPIO is not set
-CONFIG_GENERIC_TIME=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_SYS_SUPPORTS_PCI=y
-CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_HAVE_LATENCYTOP_SUPPORT=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_ARCH_NO_VIRT_TO_BUS=y
-CONFIG_IO_TRAPPED=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_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-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 is not set
-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 is not set
-# CONFIG_HOTPLUG is not set
-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_PCI_QUIRKS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
-# CONFIG_SLOB is not set
-CONFIG_PROFILING=y
-# CONFIG_MARKERS is not set
-CONFIG_OPROFILE=y
-CONFIG_HAVE_OPROFILE=y
-# CONFIG_KPROBES is not set
-CONFIG_HAVE_IOREMAP_PROT=y
-CONFIG_HAVE_KPROBES=y
-CONFIG_HAVE_KRETPROBES=y
-CONFIG_HAVE_ARCH_TRACEHOOK=y
-CONFIG_HAVE_CLK=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 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
-
-#
-# 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
-# CONFIG_FREEZER is not set
-
-#
-# System type
-#
-CONFIG_CPU_SH4=y
-# CONFIG_CPU_SUBTYPE_SH7619 is not set
-# CONFIG_CPU_SUBTYPE_SH7203 is not set
-# CONFIG_CPU_SUBTYPE_SH7206 is not set
-# CONFIG_CPU_SUBTYPE_SH7263 is not set
-# CONFIG_CPU_SUBTYPE_MXG is not set
-# CONFIG_CPU_SUBTYPE_SH7705 is not set
-# CONFIG_CPU_SUBTYPE_SH7706 is not set
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-# CONFIG_CPU_SUBTYPE_SH7708 is not set
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-# CONFIG_CPU_SUBTYPE_SH7710 is not set
-# CONFIG_CPU_SUBTYPE_SH7712 is not set
-# CONFIG_CPU_SUBTYPE_SH7720 is not set
-# CONFIG_CPU_SUBTYPE_SH7721 is not set
-# CONFIG_CPU_SUBTYPE_SH7750 is not set
-# CONFIG_CPU_SUBTYPE_SH7091 is not set
-# CONFIG_CPU_SUBTYPE_SH7750R is not set
-# CONFIG_CPU_SUBTYPE_SH7750S is not set
-# CONFIG_CPU_SUBTYPE_SH7751 is not set
-CONFIG_CPU_SUBTYPE_SH7751R=y
-# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-# CONFIG_CPU_SUBTYPE_SH7723 is not set
-# CONFIG_CPU_SUBTYPE_SH7763 is not set
-# CONFIG_CPU_SUBTYPE_SH7770 is not set
-# CONFIG_CPU_SUBTYPE_SH7780 is not set
-# CONFIG_CPU_SUBTYPE_SH7785 is not set
-# CONFIG_CPU_SUBTYPE_SHX3 is not set
-# CONFIG_CPU_SUBTYPE_SH7343 is not set
-# CONFIG_CPU_SUBTYPE_SH7722 is not set
-# CONFIG_CPU_SUBTYPE_SH7366 is not set
-# CONFIG_CPU_SUBTYPE_SH5_101 is not set
-# CONFIG_CPU_SUBTYPE_SH5_103 is not set
-
-#
-# Memory management options
-#
-CONFIG_QUICKLIST=y
-CONFIG_MMU=y
-CONFIG_PAGE_OFFSET=0x80000000
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x04000000
-CONFIG_29BIT=y
-CONFIG_VSYSCALL=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_ARCH_SPARSEMEM_ENABLE=y
-CONFIG_ARCH_SPARSEMEM_DEFAULT=y
-CONFIG_MAX_ACTIVE_REGIONS=1
-CONFIG_ARCH_POPULATES_NODE_MAP=y
-CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_PAGE_SIZE_4KB=y
-# CONFIG_PAGE_SIZE_8KB is not set
-# CONFIG_PAGE_SIZE_16KB is not set
-# CONFIG_PAGE_SIZE_64KB is not set
-CONFIG_ENTRY_OFFSET=0x00001000
-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=y
-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=0
-CONFIG_NR_QUICK=2
-CONFIG_UNEVICTABLE_LRU=y
-
-#
-# Cache configuration
-#
-# CONFIG_SH_DIRECT_MAPPED is not set
-CONFIG_CACHE_WRITEBACK=y
-# CONFIG_CACHE_WRITETHROUGH is not set
-# CONFIG_CACHE_OFF is not set
-
-#
-# Processor features
-#
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_CPU_BIG_ENDIAN is not set
-CONFIG_SH_FPU=y
-# CONFIG_SH_STORE_QUEUES is not set
-CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_SR_RB=y
-CONFIG_CPU_HAS_PTEA=y
-CONFIG_CPU_HAS_FPU=y
-
-#
-# Board support
-#
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-CONFIG_SH_RTS7751R2D=y
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_LBOX_RE2 is not set
-
-#
-# RTS7751R2D Board Revision
-#
-CONFIG_RTS7751R2D_PLUS=y
-# CONFIG_RTS7751R2D_1 is not set
-
-#
-# Timer and clock configuration
-#
-CONFIG_SH_TMU=y
-CONFIG_SH_TIMER_IRQ=16
-CONFIG_SH_PCLK_FREQ=60000000
-# CONFIG_NO_HZ is not set
-# CONFIG_HIGH_RES_TIMERS is not set
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# DMA support
-#
-# CONFIG_SH_DMA is not set
-
-#
-# Companion Chips
-#
-
-#
-# Additional SuperH Device Drivers
-#
-CONFIG_HEARTBEAT=y
-# CONFIG_PUSH_SWITCH is not set
-
-#
-# Kernel features
-#
-# 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_KEXEC is not set
-# CONFIG_CRASH_DUMP is not set
-CONFIG_SECCOMP=y
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
-CONFIG_GUSA=y
-# CONFIG_GUSA_RB is not set
-
-#
-# Boot options
-#
-CONFIG_ZERO_PAGE_OFFSET=0x00010000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-# CONFIG_UBC_WAKEUP is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1 earlyprintk=serial"
-
-#
-# Bus options
-#
-# CONFIG_PCI is not set
-# CONFIG_ARCH_SUPPORTS_MSI 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 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_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 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-# CONFIG_BLK_DEV_XIP is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_BLK_DEV_HD 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=y
-# CONFIG_ATA_NONSTANDARD is not set
-CONFIG_SATA_PMP=y
-CONFIG_ATA_SFF=y
-# CONFIG_SATA_MV is not set
-# CONFIG_PATA_PLATFORM is not set
-# CONFIG_MD 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 is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=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=y
-# CONFIG_SERIAL_8250_CONSOLE is not set
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=1
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# 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=y
-# CONFIG_SPI_DEBUG is not set
-CONFIG_SPI_MASTER=y
-
-#
-# SPI Master Controller Drivers
-#
-CONFIG_SPI_BITBANG=y
-# CONFIG_SPI_SH_SCI is not set
-
-#
-# SPI Protocol Masters
-#
-# CONFIG_SPI_AT25 is not set
-# CONFIG_SPI_SPIDEV is not set
-# CONFIG_SPI_TLE62X0 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_ADCXX is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_F71882FG is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM70 is not set
-# CONFIG_SENSORS_MAX1111 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
-
-#
-# Sonics Silicon Backplane
-#
-CONFIG_SSB_POSSIBLE=y
-# CONFIG_SSB is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_CORE is not set
-CONFIG_MFD_SM501=y
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_MFD_TMIO is not set
-# CONFIG_MFD_WM8400 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=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_SH_MOBILE_LCDC=m
-CONFIG_FB_SM501=y
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FB_METRONOME is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-
-#
-# Console display driver support
-#
-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 is not set
-# CONFIG_LOGO_LINUX_VGA16 is not set
-# CONFIG_LOGO_LINUX_CLUT224 is not set
-# CONFIG_LOGO_SUPERH_MONO is not set
-# CONFIG_LOGO_SUPERH_VGA16 is not set
-CONFIG_LOGO_SUPERH_CLUT224=y
-CONFIG_SOUND=y
-CONFIG_SOUND_OSS_CORE=y
-CONFIG_SND=m
-# 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_SPI=y
-CONFIG_SND_SUPERH=y
-# CONFIG_SND_SOC is not set
-CONFIG_SOUND_PRIME=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_COMPAT=y
-# 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_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
-
-#
-# 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=y
-# 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_SH is not set
-# CONFIG_DMADEVICES 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_DNOTIFY=y
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# 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_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_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_PROC_PAGE_MONITOR=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
-# CONFIG_HUGETLBFS 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=y
-# 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
-
-#
-# 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=y
-# 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
-
-#
-# Kernel hacking
-#
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-# 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_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 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_FRAME_POINTER 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_NOP_TRACER=y
-CONFIG_HAVE_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_BOOT_TRACER is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
-# CONFIG_SAMPLES is not set
-# CONFIG_SH_STANDARD_BIOS is not set
-CONFIG_EARLY_SCIF_CONSOLE=y
-CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000
-CONFIG_EARLY_PRINTK=y
-# CONFIG_DEBUG_BOOTMEM is not set
-# CONFIG_DEBUG_STACKOVERFLOW is not set
-# CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_4KSTACKS is not set
-# CONFIG_IRQSTACKS is not set
-# CONFIG_SH_KGDB 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_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
-#
-CONFIG_BITREVERSE=y
-# CONFIG_CRC_CCITT is not set
-# 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 is not set
-CONFIG_PLIST=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/se7343_defconfig b/arch/sh/configs/se7343_defconfig
index 075f42e..be246f3 100644
--- a/arch/sh/configs/se7343_defconfig
+++ b/arch/sh/configs/se7343_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27
-# Wed Oct 22 19:00:21 2008
+# Linux kernel version: 2.6.28-rc6
+# Thu Dec  4 16:40:25 2008
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
@@ -74,7 +74,6 @@
 # CONFIG_SHMEM is not set
 CONFIG_AIO=y
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_PCI_QUIRKS=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -127,6 +126,7 @@
 CONFIG_CPU_SH4A=y
 CONFIG_CPU_SH4AL_DSP=y
 # CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7201 is not set
 # CONFIG_CPU_SUBTYPE_SH7203 is not set
 # CONFIG_CPU_SUBTYPE_SH7206 is not set
 # CONFIG_CPU_SUBTYPE_SH7263 is not set
@@ -227,7 +227,7 @@
 #
 CONFIG_SH_TMU=y
 CONFIG_SH_TIMER_IRQ=16
-CONFIG_SH_PCLK_FREQ=27000000
+CONFIG_SH_PCLK_FREQ=33333333
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -274,7 +274,8 @@
 #
 CONFIG_ZERO_PAGE_OFFSET=0x00001000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
-# CONFIG_CMDLINE_BOOL is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,115200"
 
 #
 # Bus options
@@ -463,6 +464,7 @@
 # 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_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
@@ -519,23 +521,10 @@
 # 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_NET_ETHERNET is not set
 CONFIG_MII=y
-# CONFIG_AX88796 is not set
-# CONFIG_STNIC is not set
-CONFIG_SMC91X=y
-# CONFIG_SMC911X 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
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 
 #
 # Wireless LAN
@@ -543,6 +532,26 @@
 # 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=y
+# CONFIG_USB_NET_AX8817X is not set
+CONFIG_USB_NET_CDCETHER=y
+CONFIG_USB_NET_DM9601=y
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
@@ -597,13 +606,17 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_NR_UARTS=4
 CONFIG_SERIAL_SH_SCI_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
@@ -615,7 +628,51 @@
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
-# CONFIG_I2C 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_OCORES is not set
+CONFIG_I2C_SH_MOBILE=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_AT24 is not set
+# CONFIG_SENSORS_EEPROM 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 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 is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
@@ -623,11 +680,11 @@
 # 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
 
 #
@@ -637,7 +694,10 @@
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 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_REGULATOR is not set
 
 #
 # Multimedia devices
@@ -657,6 +717,16 @@
 # Multimedia drivers
 #
 # CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=y
+CONFIG_MEDIA_TUNER_TDA8290=y
+CONFIG_MEDIA_TUNER_TDA9887=y
+CONFIG_MEDIA_TUNER_TEA5761=y
+CONFIG_MEDIA_TUNER_TEA5767=y
+CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER_XC2028=y
+CONFIG_MEDIA_TUNER_XC5000=y
 CONFIG_VIDEO_V4L2=y
 CONFIG_VIDEO_V4L1=y
 CONFIG_VIDEO_CAPTURE_DRIVERS=y
@@ -665,8 +735,57 @@
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
 # CONFIG_VIDEO_VIVI is not set
 # CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
 # CONFIG_SOC_CAMERA is not set
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_GSPCA=m
+# CONFIG_USB_M5602 is not set
+# CONFIG_USB_GSPCA_CONEX is not set
+# CONFIG_USB_GSPCA_ETOMS is not set
+# CONFIG_USB_GSPCA_FINEPIX is not set
+# CONFIG_USB_GSPCA_MARS is not set
+# CONFIG_USB_GSPCA_OV519 is not set
+# CONFIG_USB_GSPCA_PAC207 is not set
+# CONFIG_USB_GSPCA_PAC7311 is not set
+# CONFIG_USB_GSPCA_SONIXB is not set
+# CONFIG_USB_GSPCA_SONIXJ is not set
+# CONFIG_USB_GSPCA_SPCA500 is not set
+# CONFIG_USB_GSPCA_SPCA501 is not set
+# CONFIG_USB_GSPCA_SPCA505 is not set
+# CONFIG_USB_GSPCA_SPCA506 is not set
+# CONFIG_USB_GSPCA_SPCA508 is not set
+# CONFIG_USB_GSPCA_SPCA561 is not set
+# CONFIG_USB_GSPCA_STK014 is not set
+# CONFIG_USB_GSPCA_SUNPLUS is not set
+# CONFIG_USB_GSPCA_T613 is not set
+# CONFIG_USB_GSPCA_TV8532 is not set
+# CONFIG_USB_GSPCA_VC032X is not set
+# CONFIG_USB_GSPCA_ZC3XX is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
 CONFIG_RADIO_ADAPTERS=y
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_SI470X is not set
+# CONFIG_USB_MR800 is not set
 # CONFIG_DAB is not set
 
 #
@@ -700,6 +819,7 @@
 CONFIG_FB_SH_MOBILE_LCDC=m
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
@@ -737,27 +857,147 @@
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
 CONFIG_SND_SUPERH=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
 # 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
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
 # CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
 
 #
 # Special HID drivers
 #
 CONFIG_HID_COMPAT=y
-# CONFIG_USB_SUPPORT is not set
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_BRIGHT=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DELL=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GYRATION=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_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_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 is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS 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_ISP116X_HCD=y
+# 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 information
+#
+# CONFIG_USB_STORAGE 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_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
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET 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_UIO 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
+CONFIG_STAGING_EXCLUDE_BUILD=y
 
 #
 # File systems
@@ -889,8 +1129,13 @@
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_LATENCYTOP is not set
-CONFIG_NOP_TRACER=y
-CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
 # CONFIG_DYNAMIC_PRINTK_DEBUG is not set
 # CONFIG_SAMPLES is not set
 # CONFIG_SH_STANDARD_BIOS is not set
diff --git a/arch/sh/drivers/dma/Makefile b/arch/sh/drivers/dma/Makefile
index 1ac812d..ab956ad 100644
--- a/arch/sh/drivers/dma/Makefile
+++ b/arch/sh/drivers/dma/Makefile
@@ -3,7 +3,6 @@
 #
 
 obj-$(CONFIG_SH_DMA_API)	+= dma-api.o dma-sysfs.o
-obj-$(CONFIG_ISA_DMA_API)	+= dma-isa.o
 obj-$(CONFIG_SH_DMA)		+= dma-sh.o
 obj-$(CONFIG_SH_DREAMCAST)	+= dma-pvr2.o dma-g2.o
 obj-$(CONFIG_SH_DMABRG)		+= dmabrg.o
diff --git a/arch/sh/drivers/dma/dma-isa.c b/arch/sh/drivers/dma/dma-isa.c
deleted file mode 100644
index 5fb044b..0000000
--- a/arch/sh/drivers/dma/dma-isa.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * arch/sh/drivers/dma/dma-isa.c
- *
- * Generic ISA DMA wrapper for SH DMA API
- *
- * Copyright (C) 2003, 2004  Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/dma.h>
-
-/*
- * This implements a small wrapper set to make code using the old ISA DMA API
- * work with the SH DMA API. Since most of the work in the new API happens
- * at ops->xfer() time, we simply use the various set_dma_xxx() routines to
- * fill in per-channel info, and then hand hand this off to ops->xfer() at
- * enable_dma() time.
- *
- * For channels that are doing on-demand data transfer via cascading, the
- * channel itself will still need to be configured through the new API. As
- * such, this code is meant for only the simplest of tasks (and shouldn't be
- * used in any new drivers at all).
- *
- * NOTE: ops->xfer() is the preferred way of doing things. However, there
- * are some users of the ISA DMA API that exist in common code that we
- * don't necessarily want to go out of our way to break, so we still
- * allow for some compatibility at that level. Any new code is strongly
- * advised to run far away from the ISA DMA API and use the SH DMA API
- * directly.
- */
-unsigned long claim_dma_lock(void)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&dma_spin_lock, flags);
-
-	return flags;
-}
-EXPORT_SYMBOL(claim_dma_lock);
-
-void release_dma_lock(unsigned long flags)
-{
-	spin_unlock_irqrestore(&dma_spin_lock, flags);
-}
-EXPORT_SYMBOL(release_dma_lock);
-
-void disable_dma(unsigned int chan)
-{
-	/* Nothing */
-}
-EXPORT_SYMBOL(disable_dma);
-
-void enable_dma(unsigned int chan)
-{
-	struct dma_info *info = get_dma_info(chan);
-	struct dma_channel *channel = &info->channels[chan];
-
-	info->ops->xfer(channel);
-}
-EXPORT_SYMBOL(enable_dma);
-
-void clear_dma_ff(unsigned int chan)
-{
-	/* Nothing */
-}
-EXPORT_SYMBOL(clear_dma_ff);
-
-void set_dma_mode(unsigned int chan, char mode)
-{
-	struct dma_info *info = get_dma_info(chan);
-	struct dma_channel *channel = &info->channels[chan];
-
-	channel->mode = mode;
-}
-EXPORT_SYMBOL(set_dma_mode);
-
-void set_dma_addr(unsigned int chan, unsigned int addr)
-{
-	struct dma_info *info = get_dma_info(chan);
-	struct dma_channel *channel = &info->channels[chan];
-
-	/*
-	 * Single address mode is the only thing supported through
-	 * this interface.
-	 */
-	if ((channel->mode & DMA_MODE_MASK) == DMA_MODE_READ) {
-		channel->sar = addr;
-	} else {
-		channel->dar = addr;
-	}
-}
-EXPORT_SYMBOL(set_dma_addr);
-
-void set_dma_count(unsigned int chan, unsigned int count)
-{
-	struct dma_info *info = get_dma_info(chan);
-	struct dma_channel *channel = &info->channels[chan];
-
-	channel->count = count;
-}
-EXPORT_SYMBOL(set_dma_count);
-
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
index b2ffe64..50887a5 100644
--- a/arch/sh/drivers/dma/dma-sh.c
+++ b/arch/sh/drivers/dma/dma-sh.c
@@ -205,7 +205,8 @@
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
     defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780)
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
 #define dmaor_read_reg()	ctrl_inw(DMAOR)
 #define dmaor_write_reg(data)	ctrl_outw(data, DMAOR)
 #else
diff --git a/arch/sh/drivers/dma/dma-sh.h b/arch/sh/drivers/dma/dma-sh.h
index b05af34..05fecd5 100644
--- a/arch/sh/drivers/dma/dma-sh.h
+++ b/arch/sh/drivers/dma/dma-sh.h
@@ -29,6 +29,7 @@
 #define RS_IN	0x00000200
 #define RS_OUT	0x00000300
 #define TS_BLK	0x00000040
+#define TM_BUR	0x00000020
 #define CHCR_DE 0x00000001
 #define CHCR_TE 0x00000002
 #define CHCR_IE 0x00000004
diff --git a/arch/sh/drivers/pci/ops-sh03.c b/arch/sh/drivers/pci/ops-sh03.c
index ebb58e6..e1703ff 100644
--- a/arch/sh/drivers/pci/ops-sh03.c
+++ b/arch/sh/drivers/pci/ops-sh03.c
@@ -18,7 +18,8 @@
  */
 int __init pcibios_init_platform(void)
 {
-   return 1;
+	__set_io_port_base(SH7751_PCI_IO_BASE);
+	return 1;
 }
 
 static struct resource sh7751_io_resource = {
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
index b2a2bfa..078dc44 100644
--- a/arch/sh/drivers/pci/pci-sh7780.c
+++ b/arch/sh/drivers/pci/pci-sh7780.c
@@ -123,16 +123,14 @@
 	 * Window0 = map->window0.size @ non-cached area base = SDRAM
 	 * Window1 = map->window1.size @ cached area base = SDRAM
 	 */
-	word = ((map->window0.size - 1) & 0x1ff00001) | 0x01;
-	pci_write_reg(0x07f00001, SH4_PCILSR0);
-	word = ((map->window1.size - 1) & 0x1ff00001) | 0x01;
+	word = (CONFIG_MEMORY_SIZE - 0x00100000) | 0x00000001;
+	pci_write_reg(word, SH4_PCILSR0);
 	pci_write_reg(0x00000001, SH4_PCILSR1);
 	/* Set the values on window 0 PCI config registers */
-	word = P2SEGADDR(map->window0.base);
-	pci_write_reg(0xa8000000, SH4_PCILAR0);
-	pci_write_reg(0x08000000, SH7780_PCIMBAR0);
+	word = (CONFIG_MEMORY_SIZE > 0x08000000) ? 0x10000000 : 0x08000000;
+	pci_write_reg(word | 0xa0000000, SH4_PCILAR0);
+	pci_write_reg(word, SH7780_PCIMBAR0);
 	/* Set the values on window 1 PCI config registers */
-	word = P2SEGADDR(map->window1.base);
 	pci_write_reg(0x00000000, SH4_PCILAR1);
 	pci_write_reg(0x00000000, SH7780_PCIMBAR1);
 
diff --git a/arch/sh/include/asm/addrspace.h b/arch/sh/include/asm/addrspace.h
index 2702d81..36736c7 100644
--- a/arch/sh/include/asm/addrspace.h
+++ b/arch/sh/include/asm/addrspace.h
@@ -49,5 +49,16 @@
 /* Check if an address can be reached in 29 bits */
 #define IS_29BIT(a)	(((unsigned long)(a)) < 0x20000000)
 
+#ifdef CONFIG_SH_STORE_QUEUES
+/*
+ * This is a special case for the SH-4 store queues, as pages for this
+ * space still need to be faulted in before it's possible to flush the
+ * store queue cache for writeout to the remapped region.
+ */
+#define P3_ADDR_MAX		(P4SEG_STORE_QUE + 0x04000000)
+#else
+#define P3_ADDR_MAX		P4SEG
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* __ASM_SH_ADDRSPACE_H */
diff --git a/arch/sh/include/asm/bitops-grb.h b/arch/sh/include/asm/bitops-grb.h
index a5907b9..e73af33 100644
--- a/arch/sh/include/asm/bitops-grb.h
+++ b/arch/sh/include/asm/bitops-grb.h
@@ -166,4 +166,7 @@
 
         return retval;
 }
+
+#include <asm-generic/bitops/non-atomic.h>
+
 #endif /* __ASM_SH_BITOPS_GRB_H */
diff --git a/arch/sh/include/asm/bitops-irq.h b/arch/sh/include/asm/bitops-irq.h
deleted file mode 100644
index 653a127..0000000
--- a/arch/sh/include/asm/bitops-irq.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef __ASM_SH_BITOPS_IRQ_H
-#define __ASM_SH_BITOPS_IRQ_H
-
-static inline void set_bit(int nr, volatile void *addr)
-{
-	int	mask;
-	volatile unsigned int *a = addr;
-	unsigned long flags;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	local_irq_save(flags);
-	*a |= mask;
-	local_irq_restore(flags);
-}
-
-static inline void clear_bit(int nr, volatile void *addr)
-{
-	int	mask;
-	volatile unsigned int *a = addr;
-	unsigned long flags;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	local_irq_save(flags);
-	*a &= ~mask;
-	local_irq_restore(flags);
-}
-
-static inline void change_bit(int nr, volatile void *addr)
-{
-	int	mask;
-	volatile unsigned int *a = addr;
-	unsigned long flags;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	local_irq_save(flags);
-	*a ^= mask;
-	local_irq_restore(flags);
-}
-
-static inline int test_and_set_bit(int nr, volatile void *addr)
-{
-	int	mask, retval;
-	volatile unsigned int *a = addr;
-	unsigned long flags;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	local_irq_save(flags);
-	retval = (mask & *a) != 0;
-	*a |= mask;
-	local_irq_restore(flags);
-
-	return retval;
-}
-
-static inline int test_and_clear_bit(int nr, volatile void *addr)
-{
-	int	mask, retval;
-	volatile unsigned int *a = addr;
-	unsigned long flags;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	local_irq_save(flags);
-	retval = (mask & *a) != 0;
-	*a &= ~mask;
-	local_irq_restore(flags);
-
-	return retval;
-}
-
-static inline int test_and_change_bit(int nr, volatile void *addr)
-{
-	int	mask, retval;
-	volatile unsigned int *a = addr;
-	unsigned long flags;
-
-	a += nr >> 5;
-	mask = 1 << (nr & 0x1f);
-	local_irq_save(flags);
-	retval = (mask & *a) != 0;
-	*a ^= mask;
-	local_irq_restore(flags);
-
-	return retval;
-}
-
-#endif /* __ASM_SH_BITOPS_IRQ_H */
diff --git a/arch/sh/include/asm/bitops-llsc.h b/arch/sh/include/asm/bitops-llsc.h
index 43b8e1a..1d2fc0b 100644
--- a/arch/sh/include/asm/bitops-llsc.h
+++ b/arch/sh/include/asm/bitops-llsc.h
@@ -141,4 +141,6 @@
 	return retval != 0;
 }
 
+#include <asm-generic/bitops/non-atomic.h>
+
 #endif /* __ASM_SH_BITOPS_LLSC_H */
diff --git a/arch/sh/include/asm/bitops-op32.h b/arch/sh/include/asm/bitops-op32.h
new file mode 100644
index 0000000..f0ae7e9
--- /dev/null
+++ b/arch/sh/include/asm/bitops-op32.h
@@ -0,0 +1,142 @@
+#ifndef __ASM_SH_BITOPS_OP32_H
+#define __ASM_SH_BITOPS_OP32_H
+
+/*
+ * The bit modifying instructions on SH-2A are only capable of working
+ * with a 3-bit immediate, which signifies the shift position for the bit
+ * being worked on.
+ */
+#if defined(__BIG_ENDIAN)
+#define BITOP_LE_SWIZZLE	((BITS_PER_LONG-1) & ~0x7)
+#define BYTE_NUMBER(nr)		((nr ^ BITOP_LE_SWIZZLE) / BITS_PER_BYTE)
+#define BYTE_OFFSET(nr)		((nr ^ BITOP_LE_SWIZZLE) % BITS_PER_BYTE)
+#else
+#define BYTE_NUMBER(nr)		((nr) / BITS_PER_BYTE)
+#define BYTE_OFFSET(nr)		((nr) % BITS_PER_BYTE)
+#endif
+
+#define IS_IMMEDIATE(nr)	(__builtin_constant_p(nr))
+
+static inline void __set_bit(int nr, volatile unsigned long *addr)
+{
+	if (IS_IMMEDIATE(nr)) {
+		__asm__ __volatile__ (
+			"bset.b %1, @(%O2,%0)		! __set_bit\n\t"
+			: "+r" (addr)
+			: "i" (BYTE_OFFSET(nr)), "i" (BYTE_NUMBER(nr))
+			: "t", "memory"
+		);
+	} else {
+		unsigned long mask = BIT_MASK(nr);
+		unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+		*p |= mask;
+	}
+}
+
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
+{
+	if (IS_IMMEDIATE(nr)) {
+		__asm__ __volatile__ (
+			"bclr.b %1, @(%O2,%0)		! __clear_bit\n\t"
+			: "+r" (addr)
+			: "i" (BYTE_OFFSET(nr)),
+			  "i" (BYTE_NUMBER(nr))
+			: "t", "memory"
+		);
+	} else {
+		unsigned long mask = BIT_MASK(nr);
+		unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+		*p &= ~mask;
+	}
+}
+
+/**
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to change
+ * @addr: the address to start counting from
+ *
+ * Unlike change_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static inline void __change_bit(int nr, volatile unsigned long *addr)
+{
+	if (IS_IMMEDIATE(nr)) {
+		__asm__ __volatile__ (
+			"bxor.b %1, @(%O2,%0)		! __change_bit\n\t"
+			: "+r" (addr)
+			: "i" (BYTE_OFFSET(nr)),
+			  "i" (BYTE_NUMBER(nr))
+			: "t", "memory"
+		);
+	} else {
+		unsigned long mask = BIT_MASK(nr);
+		unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+		*p ^= mask;
+	}
+}
+
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old | mask;
+	return (old & mask) != 0;
+}
+
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old & ~mask;
+	return (old & mask) != 0;
+}
+
+/* WARNING: non atomic and it can be reordered! */
+static inline int __test_and_change_bit(int nr,
+					    volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+	unsigned long old = *p;
+
+	*p = old ^ mask;
+	return (old & mask) != 0;
+}
+
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static inline int test_bit(int nr, const volatile unsigned long *addr)
+{
+	return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
+}
+
+#endif /* __ASM_SH_BITOPS_OP32_H */
diff --git a/arch/sh/include/asm/bitops.h b/arch/sh/include/asm/bitops.h
index 367930d..ebe595b 100644
--- a/arch/sh/include/asm/bitops.h
+++ b/arch/sh/include/asm/bitops.h
@@ -13,21 +13,22 @@
 
 #ifdef CONFIG_GUSA_RB
 #include <asm/bitops-grb.h>
+#elif defined(CONFIG_CPU_SH2A)
+#include <asm-generic/bitops/atomic.h>
+#include <asm/bitops-op32.h>
 #elif defined(CONFIG_CPU_SH4A)
 #include <asm/bitops-llsc.h>
 #else
-#include <asm/bitops-irq.h>
+#include <asm-generic/bitops/atomic.h>
+#include <asm-generic/bitops/non-atomic.h>
 #endif
 
-
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  */
 #define smp_mb__before_clear_bit()	barrier()
 #define smp_mb__after_clear_bit()	barrier()
 
-#include <asm-generic/bitops/non-atomic.h>
-
 #ifdef CONFIG_SUPERH32
 static inline unsigned long ffz(unsigned long word)
 {
diff --git a/arch/sh/include/asm/bugs.h b/arch/sh/include/asm/bugs.h
index 121b2ec..4924ff6 100644
--- a/arch/sh/include/asm/bugs.h
+++ b/arch/sh/include/asm/bugs.h
@@ -25,7 +25,7 @@
 	case CPU_SH7619:
 		*p++ = '2';
 		break;
-	case CPU_SH7203 ... CPU_MXG:
+	case CPU_SH7201 ... CPU_MXG:
 		*p++ = '2';
 		*p++ = 'a';
 		break;
diff --git a/arch/sh/include/asm/elf.h b/arch/sh/include/asm/elf.h
index 9eb9036..ccb1d93 100644
--- a/arch/sh/include/asm/elf.h
+++ b/arch/sh/include/asm/elf.h
@@ -108,13 +108,11 @@
 #define elf_check_fdpic(x)		((x)->e_flags & EF_SH_FDPIC)
 #define elf_check_const_displacement(x)	((x)->e_flags & EF_SH_PIC)
 
-#ifdef CONFIG_SUPERH32
 /*
  * Enable dump using regset.
  * This covers all of general/DSP/FPU regs.
  */
 #define CORE_DUMP_USE_REGSET
-#endif
 
 #define USE_ELF_CORE_DUMP
 #define ELF_FDPIC_CORE_EFLAGS	EF_SH_FDPIC
@@ -204,7 +202,7 @@
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES
 struct linux_binprm;
 extern int arch_setup_additional_pages(struct linux_binprm *bprm,
-				       int executable_stack);
+				       int uses_interp);
 
 extern unsigned int vdso_enabled;
 extern void __kernel_vsyscall;
diff --git a/arch/sh/include/asm/ftrace.h b/arch/sh/include/asm/ftrace.h
index 3aed362..8fea7d8 100644
--- a/arch/sh/include/asm/ftrace.h
+++ b/arch/sh/include/asm/ftrace.h
@@ -1,8 +1,34 @@
 #ifndef __ASM_SH_FTRACE_H
 #define __ASM_SH_FTRACE_H
 
+#ifdef CONFIG_FUNCTION_TRACER
+
+#define MCOUNT_INSN_SIZE	4 /* sizeof mcount call */
+
 #ifndef __ASSEMBLY__
 extern void mcount(void);
-#endif
+
+#define MCOUNT_ADDR		((long)(mcount))
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+#define CALLER_ADDR		((long)(ftrace_caller))
+#define STUB_ADDR		((long)(ftrace_stub))
+
+#define MCOUNT_INSN_OFFSET	((STUB_ADDR - CALLER_ADDR) >> 1)
+
+struct dyn_arch_ftrace {
+	/* No extra data needed on sh */
+};
+
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+	/* 'addr' is the memory table address. */
+	return addr;
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_FUNCTION_TRACER */
 
 #endif /* __ASM_SH_FTRACE_H */
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index 65eaae3..61f6dae 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -260,6 +260,10 @@
 
 		return (void __iomem *)P2SEGADDR(offset);
 	}
+
+	/* P4 above the store queues are always mapped. */
+	if (unlikely(offset >= P3_ADDR_MAX))
+		return (void __iomem *)P4SEGADDR(offset);
 #endif
 
 	return __ioremap(offset, size, flags);
diff --git a/arch/sh/include/asm/kgdb.h b/arch/sh/include/asm/kgdb.h
index 24e4207..72704ed 100644
--- a/arch/sh/include/asm/kgdb.h
+++ b/arch/sh/include/asm/kgdb.h
@@ -1,21 +1,7 @@
-/*
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * Based on original code by Glenn Engel, Jim Kingdon,
- * David Grothe <dave@gcom.com>, Tigran Aivazian, <tigran@sco.com> and
- * Amit S. Kale <akale@veritas.com>
- * 
- * Super-H port based on sh-stub.c (Ben Lee and Steve Chamberlain) by
- * Henry Bell <henry.bell@st.com>
- * 
- * Header file for low-level support for remote debug using GDB. 
- *
- */
+#ifndef __ASM_SH_KGDB_H
+#define __ASM_SH_KGDB_H
 
-#ifndef __KGDB_H
-#define __KGDB_H
-
+#include <asm/cacheflush.h>
 #include <asm/ptrace.h>
 
 /* Same as pt_regs but has vbr in place of syscall_nr */
@@ -30,40 +16,26 @@
         unsigned long vbr;
 };
 
+enum regnames {
+	GDB_R0, GDB_R1, GDB_R2, GDB_R3, GDB_R4, GDB_R5, GDB_R6, GDB_R7,
+	GDB_R8, GDB_R9, GDB_R10, GDB_R11, GDB_R12, GDB_R13, GDB_R14, GDB_R15,
+
+	GDB_PC, GDB_PR, GDB_SR, GDB_GBR, GDB_MACH, GDB_MACL, GDB_VBR,
+};
+
+#define NUMREGBYTES    ((GDB_VBR + 1) * 4)
+
+static inline void arch_kgdb_breakpoint(void)
+{
+	__asm__ __volatile__ ("trapa #0x3c\n");
+}
+
 /* State info */
-extern char kgdb_in_gdb_mode;
-extern int kgdb_nofault;	/* Ignore bus errors (in gdb mem access) */
 extern char in_nmi;		/* Debounce flag to prevent NMI reentry*/
 
-/* SCI */
-extern int kgdb_portnum;
-extern int kgdb_baud;
-extern char kgdb_parity;
-extern char kgdb_bits;
+#define BUFMAX                 2048
 
-/* Init and interface stuff */
-extern int kgdb_init(void);
-extern int (*kgdb_getchar)(void);
-extern void (*kgdb_putchar)(int);
+#define CACHE_FLUSH_IS_SAFE	1
+#define BREAK_INSTR_SIZE	2
 
-/* Trap functions */
-typedef void (kgdb_debug_hook_t)(struct pt_regs *regs);
-typedef void (kgdb_bus_error_hook_t)(void);
-extern kgdb_debug_hook_t  *kgdb_debug_hook;
-extern kgdb_bus_error_hook_t *kgdb_bus_err_hook;
-
-/* Console */
-struct console;
-void kgdb_console_write(struct console *co, const char *s, unsigned count);
-extern int kgdb_console_setup(struct console *, char *);
-
-/* Prototypes for jmp fns */
-#define _JBLEN 9
-typedef        int jmp_buf[_JBLEN];
-extern void    longjmp(jmp_buf __jmpb, int __retval);
-extern int     setjmp(jmp_buf __jmpb);
-
-/* Forced breakpoint */
-#define breakpoint()	__asm__ __volatile__("trapa   #0x3c")
-
-#endif
+#endif /* __ASM_SH_KGDB_H */
diff --git a/arch/sh/include/asm/machvec.h b/arch/sh/include/asm/machvec.h
index f1bae02..64b1c16 100644
--- a/arch/sh/include/asm/machvec.h
+++ b/arch/sh/include/asm/machvec.h
@@ -14,8 +14,6 @@
 #include <linux/time.h>
 #include <asm/machtypes.h>
 
-struct device;
-
 struct sh_machine_vector {
 	void (*mv_setup)(char **cmdline_p);
 	const char *mv_name;
@@ -45,9 +43,6 @@
 	int (*mv_irq_demux)(int irq);
 
 	void (*mv_init_irq)(void);
-	void (*mv_init_pci)(void);
-
-	void (*mv_heartbeat)(void);
 
 	void __iomem *(*mv_ioport_map)(unsigned long port, unsigned int size);
 	void (*mv_ioport_unmap)(void __iomem *);
diff --git a/arch/sh/include/asm/mmu_context.h b/arch/sh/include/asm/mmu_context.h
index 04c0c97..5d9157b 100644
--- a/arch/sh/include/asm/mmu_context.h
+++ b/arch/sh/include/asm/mmu_context.h
@@ -22,7 +22,7 @@
 #define MMU_CONTEXT_ASID_MASK		0x000000ff
 #define MMU_CONTEXT_VERSION_MASK	0xffffff00
 #define MMU_CONTEXT_FIRST_VERSION	0x00000100
-#define NO_CONTEXT			0
+#define NO_CONTEXT			0UL
 
 /* ASID is 8-bit value, so it can't be 0x100 */
 #define MMU_NO_ASID			0x100
@@ -130,7 +130,7 @@
 #define destroy_context(mm)		do { } while (0)
 #define set_asid(asid)			do { } while (0)
 #define get_asid()			(0)
-#define cpu_asid(cpu, mm)		({ (void)cpu; 0; })
+#define cpu_asid(cpu, mm)		({ (void)cpu; NO_CONTEXT; })
 #define switch_and_save_asid(asid)	(0)
 #define set_TTB(pgd)			do { } while (0)
 #define get_TTB()			(0)
diff --git a/arch/sh/include/asm/mutex-llsc.h b/arch/sh/include/asm/mutex-llsc.h
new file mode 100644
index 0000000..ee839ee
--- /dev/null
+++ b/arch/sh/include/asm/mutex-llsc.h
@@ -0,0 +1,112 @@
+/*
+ * arch/sh/include/asm/mutex-llsc.h
+ *
+ * SH-4A optimized mutex locking primitives
+ *
+ * Please look into asm-generic/mutex-xchg.h for a formal definition.
+ */
+#ifndef __ASM_SH_MUTEX_LLSC_H
+#define __ASM_SH_MUTEX_LLSC_H
+
+/*
+ * Attempting to lock a mutex on SH4A is done like in ARMv6+ architecure.
+ * with a bastardized atomic decrement (it is not a reliable atomic decrement
+ * but it satisfies the defined semantics for our purpose, while being
+ * smaller and faster than a real atomic decrement or atomic swap.
+ * The idea is to attempt  decrementing the lock value only once. If once
+ * decremented it isn't zero, or if its store-back fails due to a dispute
+ * on the exclusive store, we simply bail out immediately through the slow
+ * path where the lock will be reattempted until it succeeds.
+ */
+static inline void
+__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
+{
+	int __ex_flag, __res;
+
+	__asm__ __volatile__ (
+		"movli.l	@%2, %0	\n"
+		"add		#-1, %0	\n"
+		"movco.l	%0, @%2	\n"
+		"movt		%1	\n"
+		: "=&z" (__res), "=&r" (__ex_flag)
+		: "r" (&(count)->counter)
+		: "t");
+
+	__res |= !__ex_flag;
+	if (unlikely(__res != 0))
+		fail_fn(count);
+}
+
+static inline int
+__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+{
+	int __ex_flag, __res;
+
+	__asm__ __volatile__ (
+		"movli.l	@%2, %0	\n"
+		"add		#-1, %0	\n"
+		"movco.l	%0, @%2	\n"
+		"movt		%1	\n"
+		: "=&z" (__res), "=&r" (__ex_flag)
+		: "r" (&(count)->counter)
+		: "t");
+
+	__res |= !__ex_flag;
+	if (unlikely(__res != 0))
+		__res = fail_fn(count);
+
+	return __res;
+}
+
+static inline void
+__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
+{
+	int __ex_flag, __res;
+
+	__asm__ __volatile__ (
+		"movli.l	@%2, %0	\n\t"
+		"add		#1, %0	\n\t"
+		"movco.l	%0, @%2 \n\t"
+		"movt		%1	\n\t"
+		: "=&z" (__res), "=&r" (__ex_flag)
+		: "r" (&(count)->counter)
+		: "t");
+
+	__res |= !__ex_flag;
+	if (unlikely(__res <= 0))
+		fail_fn(count);
+}
+
+/*
+ * If the unlock was done on a contended lock, or if the unlock simply fails
+ * then the mutex remains locked.
+ */
+#define __mutex_slowpath_needs_to_unlock()	1
+
+/*
+ * For __mutex_fastpath_trylock we do an atomic decrement and check the
+ * result and put it in the __res variable.
+ */
+static inline int
+__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
+{
+	int __res, __orig;
+
+	__asm__ __volatile__ (
+		"1: movli.l	@%2, %0		\n\t"
+		"dt		%0		\n\t"
+		"movco.l	%0,@%2		\n\t"
+		"bf		1b		\n\t"
+		"cmp/eq		#0,%0		\n\t"
+		"bt		2f		\n\t"
+		"mov		#0, %1		\n\t"
+		"bf		3f		\n\t"
+		"2: mov		#1, %1		\n\t"
+		"3:				"
+		: "=&z" (__orig), "=&r" (__res)
+		: "r" (&count->counter)
+		: "t");
+
+	return __res;
+}
+#endif /* __ASM_SH_MUTEX_LLSC_H */
diff --git a/arch/sh/include/asm/mutex.h b/arch/sh/include/asm/mutex.h
index 458c1f7..d8e3771 100644
--- a/arch/sh/include/asm/mutex.h
+++ b/arch/sh/include/asm/mutex.h
@@ -5,5 +5,8 @@
  * implementation in place, or pick the atomic_xchg() based generic
  * implementation. (see asm-generic/mutex-xchg.h for details)
  */
-
+#if defined(CONFIG_CPU_SH4A)
+#include <asm/mutex-llsc.h>
+#else
 #include <asm-generic/mutex-dec.h>
+#endif
diff --git a/arch/sh/include/asm/pm.h b/arch/sh/include/asm/pm.h
deleted file mode 100644
index 56fdbd6..0000000
--- a/arch/sh/include/asm/pm.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright 2006 (c) Andriy Skulysh <askulysh@gmail.com>
- *
- */
-#ifndef __ASM_SH_PM_H
-#define __ASM_SH_PM_H
-
-extern u8 wakeup_start;
-extern u8 wakeup_end;
-
-void pm_enter(void);
-
-#endif
diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h
index 693364a..1ef4b24 100644
--- a/arch/sh/include/asm/processor.h
+++ b/arch/sh/include/asm/processor.h
@@ -18,7 +18,7 @@
 	CPU_SH7619,
 
 	/* SH-2A types */
-	CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_MXG,
+	CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_MXG,
 
 	/* SH-3 types */
 	CPU_SH7705, CPU_SH7706, CPU_SH7707,
@@ -82,6 +82,9 @@
 #define current_cpu_data cpu_data[smp_processor_id()]
 #define raw_current_cpu_data cpu_data[raw_smp_processor_id()]
 
+#define cpu_sleep()	__asm__ __volatile__ ("sleep" : : : "memory")
+#define cpu_relax()	barrier()
+
 /* Forward decl */
 struct seq_operations;
 
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h
index a46a020..d79063c 100644
--- a/arch/sh/include/asm/processor_32.h
+++ b/arch/sh/include/asm/processor_32.h
@@ -175,6 +175,15 @@
 
 void show_trace(struct task_struct *tsk, unsigned long *sp,
 		struct pt_regs *regs);
+
+#ifdef CONFIG_DUMP_CODE
+void show_code(struct pt_regs *regs);
+#else
+static inline void show_code(struct pt_regs *regs)
+{
+}
+#endif
+
 extern unsigned long get_wchan(struct task_struct *p);
 
 #define KSTK_EIP(tsk)  (task_pt_regs(tsk)->pc)
@@ -182,9 +191,6 @@
 
 #define user_stack_pointer(regs)	((regs)->regs[15])
 
-#define cpu_sleep()	__asm__ __volatile__ ("sleep" : : : "memory")
-#define cpu_relax()	barrier()
-
 #if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH3) || \
     defined(CONFIG_CPU_SH4)
 #define PREFETCH_STRIDE		L1_CACHE_BYTES
diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h
index b0b4824..803177f 100644
--- a/arch/sh/include/asm/processor_64.h
+++ b/arch/sh/include/asm/processor_64.h
@@ -226,9 +226,7 @@
 #define KSTK_EIP(tsk)  ((tsk)->thread.pc)
 #define KSTK_ESP(tsk)  ((tsk)->thread.sp)
 
-#define user_stack_pointer(regs)	((regs)->sp)
-
-#define cpu_relax()	barrier()
+#define user_stack_pointer(regs)	((regs)->regs[15])
 
 #endif	/* __ASSEMBLY__ */
 #endif /* __ASM_SH_PROCESSOR_64_H */
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h
index 3ad18e9..12912ab 100644
--- a/arch/sh/include/asm/ptrace.h
+++ b/arch/sh/include/asm/ptrace.h
@@ -86,6 +86,7 @@
 	unsigned long	re;
 	unsigned long	mod;
 };
+#endif
 
 #define PTRACE_GETREGS		12	/* General registers */
 #define PTRACE_SETREGS		13
@@ -100,7 +101,6 @@
 
 #define	PTRACE_GETDSPREGS	55	/* DSP registers */
 #define	PTRACE_SETDSPREGS	56
-#endif
 
 #ifdef __KERNEL__
 #include <asm/addrspace.h>
diff --git a/arch/sh/include/asm/sh_bios.h b/arch/sh/include/asm/sh_bios.h
index 0ca2619..d9c96d7 100644
--- a/arch/sh/include/asm/sh_bios.h
+++ b/arch/sh/include/asm/sh_bios.h
@@ -10,7 +10,6 @@
 
 extern void sh_bios_console_write(const char *buf, unsigned int len);
 extern void sh_bios_char_out(char ch);
-extern int sh_bios_in_gdb_mode(void);
 extern void sh_bios_gdb_detach(void);
 
 extern void sh_bios_get_node_addr(unsigned char *node_addr);
diff --git a/arch/sh/include/asm/string_64.h b/arch/sh/include/asm/string_64.h
index aa1fef2..7420071 100644
--- a/arch/sh/include/asm/string_64.h
+++ b/arch/sh/include/asm/string_64.h
@@ -1,17 +1,20 @@
 #ifndef __ASM_SH_STRING_64_H
 #define __ASM_SH_STRING_64_H
 
-/*
- * include/asm-sh/string_64.h
- *
- * Copyright (C) 2000, 2001  Paolo Alberelli
- *
- * 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.
- */
+#ifdef __KERNEL__
+
+#define __HAVE_ARCH_MEMSET
+extern void *memset(void *__s, int __c, size_t __count);
 
 #define __HAVE_ARCH_MEMCPY
 extern void *memcpy(void *dest, const void *src, size_t count);
 
+#define __HAVE_ARCH_STRLEN
+extern size_t strlen(const char *);
+
+#define __HAVE_ARCH_STRCPY
+extern char *strcpy(char *__dest, const char *__src);
+
+#endif /* __KERNEL__ */
+
 #endif /* __ASM_SH_STRING_64_H */
diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h
index 54773f2..05a868a 100644
--- a/arch/sh/include/asm/syscall_32.h
+++ b/arch/sh/include/asm/syscall_32.h
@@ -5,7 +5,7 @@
 #include <linux/sched.h>
 #include <asm/ptrace.h>
 
-/* The system call number is given by the user in %g1 */
+/* The system call number is given by the user in R3 */
 static inline long syscall_get_nr(struct task_struct *task,
 				  struct pt_regs *regs)
 {
diff --git a/arch/sh/include/asm/syscall_64.h b/arch/sh/include/asm/syscall_64.h
index bcaaa8c..e1143b9 100644
--- a/arch/sh/include/asm/syscall_64.h
+++ b/arch/sh/include/asm/syscall_64.h
@@ -1,6 +1,80 @@
 #ifndef __ASM_SH_SYSCALL_64_H
 #define __ASM_SH_SYSCALL_64_H
 
-#include <asm-generic/syscall.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+
+/* The system call number is given by the user in R9 */
+static inline long syscall_get_nr(struct task_struct *task,
+				  struct pt_regs *regs)
+{
+	return (regs->syscall_nr >= 0) ? regs->regs[9] : -1L;
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+				    struct pt_regs *regs)
+{
+	/*
+	 * XXX: This needs some thought. On SH we don't
+	 * save away the original R9 value anywhere.
+	 */
+}
+
+static inline bool syscall_has_error(struct pt_regs *regs)
+{
+	return (regs->sr & 0x1) ? true : false;
+}
+static inline void syscall_set_error(struct pt_regs *regs)
+{
+	regs->sr |= 0x1;
+}
+static inline void syscall_clear_error(struct pt_regs *regs)
+{
+	regs->sr &= ~0x1;
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+				     struct pt_regs *regs)
+{
+	return syscall_has_error(regs) ? regs->regs[9] : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+					    struct pt_regs *regs)
+{
+	return regs->regs[9];
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+					    struct pt_regs *regs,
+					    int error, long val)
+{
+	if (error) {
+		syscall_set_error(regs);
+		regs->regs[9] = -error;
+	} else {
+		syscall_clear_error(regs);
+		regs->regs[9] = val;
+	}
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 unsigned long *args)
+{
+	BUG_ON(i + n > 6);
+	memcpy(args, &regs->regs[2 + i], n * sizeof(args[0]));
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 const unsigned long *args)
+{
+	BUG_ON(i + n > 6);
+	memcpy(&regs->regs[2 + i], args, n * sizeof(args[0]));
+}
 
 #endif /* __ASM_SH_SYSCALL_64_H */
diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h
index 6160fe4..c9ec6af 100644
--- a/arch/sh/include/asm/system.h
+++ b/arch/sh/include/asm/system.h
@@ -175,6 +175,8 @@
 BUILD_TRAP_HANDLER(address_error);
 BUILD_TRAP_HANDLER(debug);
 BUILD_TRAP_HANDLER(bug);
+BUILD_TRAP_HANDLER(breakpoint);
+BUILD_TRAP_HANDLER(singlestep);
 BUILD_TRAP_HANDLER(fpu_error);
 BUILD_TRAP_HANDLER(fpu_state_restore);
 
diff --git a/arch/sh/include/asm/unaligned-sh4a.h b/arch/sh/include/asm/unaligned-sh4a.h
new file mode 100644
index 0000000..d8f8977
--- /dev/null
+++ b/arch/sh/include/asm/unaligned-sh4a.h
@@ -0,0 +1,258 @@
+#ifndef __ASM_SH_UNALIGNED_SH4A_H
+#define __ASM_SH_UNALIGNED_SH4A_H
+
+/*
+ * SH-4A has support for unaligned 32-bit loads, and 32-bit loads only.
+ * Support for 16 and 64-bit accesses are done through shifting and
+ * masking relative to the endianness. Unaligned stores are not supported
+ * by the instruction encoding, so these continue to use the packed
+ * struct.
+ *
+ * The same note as with the movli.l/movco.l pair applies here, as long
+ * as the load is gauranteed to be inlined, nothing else will hook in to
+ * r0 and we get the return value for free.
+ *
+ * NOTE: Due to the fact we require r0 encoding, care should be taken to
+ * avoid mixing these heavily with other r0 consumers, such as the atomic
+ * ops. Failure to adhere to this can result in the compiler running out
+ * of spill registers and blowing up when building at low optimization
+ * levels. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34777.
+ */
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+static __always_inline u32 __get_unaligned_cpu32(const u8 *p)
+{
+	unsigned long unaligned;
+
+	__asm__ __volatile__ (
+		"movua.l	@%1, %0\n\t"
+		 : "=z" (unaligned)
+		 : "r" (p)
+	);
+
+	return unaligned;
+}
+
+struct __una_u16 { u16 x __attribute__((packed)); };
+struct __una_u32 { u32 x __attribute__((packed)); };
+struct __una_u64 { u64 x __attribute__((packed)); };
+
+static inline u16 __get_unaligned_cpu16(const u8 *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return __get_unaligned_cpu32(p) & 0xffff;
+#else
+	return __get_unaligned_cpu32(p) >> 16;
+#endif
+}
+
+/*
+ * Even though movua.l supports auto-increment on the read side, it can
+ * only store to r0 due to instruction encoding constraints, so just let
+ * the compiler sort it out on its own.
+ */
+static inline u64 __get_unaligned_cpu64(const u8 *p)
+{
+#ifdef __LITTLE_ENDIAN
+	return (u64)__get_unaligned_cpu32(p + 4) << 32 |
+		    __get_unaligned_cpu32(p);
+#else
+	return (u64)__get_unaligned_cpu32(p) << 32 |
+		    __get_unaligned_cpu32(p + 4);
+#endif
+}
+
+static inline u16 get_unaligned_le16(const void *p)
+{
+	return le16_to_cpu(__get_unaligned_cpu16(p));
+}
+
+static inline u32 get_unaligned_le32(const void *p)
+{
+	return le32_to_cpu(__get_unaligned_cpu32(p));
+}
+
+static inline u64 get_unaligned_le64(const void *p)
+{
+	return le64_to_cpu(__get_unaligned_cpu64(p));
+}
+
+static inline u16 get_unaligned_be16(const void *p)
+{
+	return be16_to_cpu(__get_unaligned_cpu16(p));
+}
+
+static inline u32 get_unaligned_be32(const void *p)
+{
+	return be32_to_cpu(__get_unaligned_cpu32(p));
+}
+
+static inline u64 get_unaligned_be64(const void *p)
+{
+	return be64_to_cpu(__get_unaligned_cpu64(p));
+}
+
+static inline void __put_le16_noalign(u8 *p, u16 val)
+{
+	*p++ = val;
+	*p++ = val >> 8;
+}
+
+static inline void __put_le32_noalign(u8 *p, u32 val)
+{
+	__put_le16_noalign(p, val);
+	__put_le16_noalign(p + 2, val >> 16);
+}
+
+static inline void __put_le64_noalign(u8 *p, u64 val)
+{
+	__put_le32_noalign(p, val);
+	__put_le32_noalign(p + 4, val >> 32);
+}
+
+static inline void __put_be16_noalign(u8 *p, u16 val)
+{
+	*p++ = val >> 8;
+	*p++ = val;
+}
+
+static inline void __put_be32_noalign(u8 *p, u32 val)
+{
+	__put_be16_noalign(p, val >> 16);
+	__put_be16_noalign(p + 2, val);
+}
+
+static inline void __put_be64_noalign(u8 *p, u64 val)
+{
+	__put_be32_noalign(p, val >> 32);
+	__put_be32_noalign(p + 4, val);
+}
+
+static inline void put_unaligned_le16(u16 val, void *p)
+{
+#ifdef __LITTLE_ENDIAN
+	((struct __una_u16 *)p)->x = val;
+#else
+	__put_le16_noalign(p, val);
+#endif
+}
+
+static inline void put_unaligned_le32(u32 val, void *p)
+{
+#ifdef __LITTLE_ENDIAN
+	((struct __una_u32 *)p)->x = val;
+#else
+	__put_le32_noalign(p, val);
+#endif
+}
+
+static inline void put_unaligned_le64(u64 val, void *p)
+{
+#ifdef __LITTLE_ENDIAN
+	((struct __una_u64 *)p)->x = val;
+#else
+	__put_le64_noalign(p, val);
+#endif
+}
+
+static inline void put_unaligned_be16(u16 val, void *p)
+{
+#ifdef __BIG_ENDIAN
+	((struct __una_u16 *)p)->x = val;
+#else
+	__put_be16_noalign(p, val);
+#endif
+}
+
+static inline void put_unaligned_be32(u32 val, void *p)
+{
+#ifdef __BIG_ENDIAN
+	((struct __una_u32 *)p)->x = val;
+#else
+	__put_be32_noalign(p, val);
+#endif
+}
+
+static inline void put_unaligned_be64(u64 val, void *p)
+{
+#ifdef __BIG_ENDIAN
+	((struct __una_u64 *)p)->x = val;
+#else
+	__put_be64_noalign(p, val);
+#endif
+}
+
+/*
+ * Cause a link-time error if we try an unaligned access other than
+ * 1,2,4 or 8 bytes long
+ */
+extern void __bad_unaligned_access_size(void);
+
+#define __get_unaligned_le(ptr) ((__force typeof(*(ptr)))({			\
+	__builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr),			\
+	__builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)),	\
+	__builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)),	\
+	__builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)),	\
+	__bad_unaligned_access_size()))));					\
+	}))
+
+#define __get_unaligned_be(ptr) ((__force typeof(*(ptr)))({			\
+	__builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr),			\
+	__builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)),	\
+	__builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)),	\
+	__builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)),	\
+	__bad_unaligned_access_size()))));					\
+	}))
+
+#define __put_unaligned_le(val, ptr) ({					\
+	void *__gu_p = (ptr);						\
+	switch (sizeof(*(ptr))) {					\
+	case 1:								\
+		*(u8 *)__gu_p = (__force u8)(val);			\
+		break;							\
+	case 2:								\
+		put_unaligned_le16((__force u16)(val), __gu_p);		\
+		break;							\
+	case 4:								\
+		put_unaligned_le32((__force u32)(val), __gu_p);		\
+		break;							\
+	case 8:								\
+		put_unaligned_le64((__force u64)(val), __gu_p);		\
+		break;							\
+	default:							\
+		__bad_unaligned_access_size();				\
+		break;							\
+	}								\
+	(void)0; })
+
+#define __put_unaligned_be(val, ptr) ({					\
+	void *__gu_p = (ptr);						\
+	switch (sizeof(*(ptr))) {					\
+	case 1:								\
+		*(u8 *)__gu_p = (__force u8)(val);			\
+		break;							\
+	case 2:								\
+		put_unaligned_be16((__force u16)(val), __gu_p);		\
+		break;							\
+	case 4:								\
+		put_unaligned_be32((__force u32)(val), __gu_p);		\
+		break;							\
+	case 8:								\
+		put_unaligned_be64((__force u64)(val), __gu_p);		\
+		break;							\
+	default:							\
+		__bad_unaligned_access_size();				\
+		break;							\
+	}								\
+	(void)0; })
+
+#ifdef __LITTLE_ENDIAN
+# define get_unaligned __get_unaligned_le
+# define put_unaligned __put_unaligned_le
+#else
+# define get_unaligned __get_unaligned_be
+# define put_unaligned __put_unaligned_be
+#endif
+
+#endif /* __ASM_SH_UNALIGNED_SH4A_H */
diff --git a/arch/sh/include/asm/unaligned.h b/arch/sh/include/asm/unaligned.h
index c1641a0..8c0ad5e 100644
--- a/arch/sh/include/asm/unaligned.h
+++ b/arch/sh/include/asm/unaligned.h
@@ -1,7 +1,11 @@
 #ifndef _ASM_SH_UNALIGNED_H
 #define _ASM_SH_UNALIGNED_H
 
-/* SH can't handle unaligned accesses. */
+#ifdef CONFIG_CPU_SH4A
+/* SH-4A can handle unaligned loads in a relatively neutered fashion. */
+#include <asm/unaligned-sh4a.h>
+#else
+/* Otherwise, SH can't handle unaligned accesses. */
 #ifdef __LITTLE_ENDIAN__
 # include <linux/unaligned/le_struct.h>
 # include <linux/unaligned/be_byteshift.h>
@@ -15,5 +19,6 @@
 # define get_unaligned	__get_unaligned_be
 # define put_unaligned	__put_unaligned_be
 #endif
+#endif
 
 #endif /* _ASM_SH_UNALIGNED_H */
diff --git a/arch/sh/include/cpu-sh3/cpu/gpio.h b/arch/sh/include/cpu-sh3/cpu/gpio.h
index 4e53eb3..9a22b88 100644
--- a/arch/sh/include/cpu-sh3/cpu/gpio.h
+++ b/arch/sh/include/cpu-sh3/cpu/gpio.h
@@ -62,6 +62,20 @@
 #define PORT_PSELC	0xA4050128UL
 #define PORT_PSELD	0xA405012AUL
 
+#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
+
+/* Control registers */
+#define PORT_PACR       0xa4000100UL
+#define PORT_PBCR       0xa4000102UL
+#define PORT_PCCR       0xa4000104UL
+#define PORT_PFCR       0xa400010aUL
+
+/* Data registers */
+#define PORT_PADR       0xa4000120UL
+#define PORT_PBDR       0xa4000122UL
+#define PORT_PCDR       0xa4000124UL
+#define PORT_PFDR       0xa400012aUL
+
 #endif
 
 #endif
diff --git a/arch/sh/include/mach-common/mach/edosk7705.h b/arch/sh/include/mach-common/mach/edosk7705.h
index 5bdc9d9..efc43b32 100644
--- a/arch/sh/include/mach-common/mach/edosk7705.h
+++ b/arch/sh/include/mach-common/mach/edosk7705.h
@@ -1,30 +1,7 @@
-/*
- * include/asm-sh/edosk7705.h
- *
- * Modified version of io_se.h for the EDOSK7705 specific functions.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * IO functions for an Hitachi EDOSK7705 development board
- */
+#ifndef __ASM_SH_EDOSK7705_H
+#define __ASM_SH_EDOSK7705_H
 
-#ifndef __ASM_SH_EDOSK7705_IO_H
-#define __ASM_SH_EDOSK7705_IO_H
-
+#define __IO_PREFIX sh_edosk7705
 #include <asm/io_generic.h>
 
-extern unsigned char sh_edosk7705_inb(unsigned long port);
-extern unsigned int sh_edosk7705_inl(unsigned long port);
-
-extern void sh_edosk7705_outb(unsigned char value, unsigned long port);
-extern void sh_edosk7705_outl(unsigned int value, unsigned long port);
-
-extern void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count);
-extern void sh_edosk7705_insl(unsigned long port, void *addr, unsigned long count);
-extern void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void sh_edosk7705_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern unsigned long sh_edosk7705_isa_port2addr(unsigned long offset);
-
-#endif /* __ASM_SH_EDOSK7705_IO_H */
+#endif /* __ASM_SH_EDOSK7705_H */
diff --git a/arch/sh/include/mach-se/mach/mrshpc.h b/arch/sh/include/mach-se/mach/mrshpc.h
new file mode 100644
index 0000000..56287ee
--- /dev/null
+++ b/arch/sh/include/mach-se/mach/mrshpc.h
@@ -0,0 +1,52 @@
+#ifndef __MACH_SE_MRSHPC_H
+#define __MACH_SE_MRSHPC_H
+
+#include <linux/io.h>
+
+static inline void __init mrshpc_setup_windows(void)
+{
+	if ((__raw_readw(MRSHPC_CSR) & 0x000c) != 0)
+		return;	/* Not detected */
+
+	if ((__raw_readw(MRSHPC_CSR) & 0x0080) == 0) {
+		__raw_writew(0x0674, MRSHPC_CPWCR); /* Card Vcc is 3.3v? */
+	} else {
+		__raw_writew(0x0678, MRSHPC_CPWCR); /* Card Vcc is 5V */
+	}
+
+	/*
+	 *  PC-Card window open
+	 *  flag == COMMON/ATTRIBUTE/IO
+	 */
+	/* common window open */
+	__raw_writew(0x8a84, MRSHPC_MW0CR1);
+	if((__raw_readw(MRSHPC_CSR) & 0x4000) != 0)
+		/* common mode & bus width 16bit SWAP = 1*/
+		__raw_writew(0x0b00, MRSHPC_MW0CR2);
+	else
+		/* common mode & bus width 16bit SWAP = 0*/
+		__raw_writew(0x0300, MRSHPC_MW0CR2);
+
+	/* attribute window open */
+	__raw_writew(0x8a85, MRSHPC_MW1CR1);
+	if ((__raw_readw(MRSHPC_CSR) & 0x4000) != 0)
+		/* attribute mode & bus width 16bit SWAP = 1*/
+		__raw_writew(0x0a00, MRSHPC_MW1CR2);
+	else
+		/* attribute mode & bus width 16bit SWAP = 0*/
+		__raw_writew(0x0200, MRSHPC_MW1CR2);
+
+	/* I/O window open */
+	__raw_writew(0x8a86, MRSHPC_IOWCR1);
+	__raw_writew(0x0008, MRSHPC_CDCR);	 /* I/O card mode */
+	if ((__raw_readw(MRSHPC_CSR) & 0x4000) != 0)
+		__raw_writew(0x0a00, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 1*/
+	else
+		__raw_writew(0x0200, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 0*/
+
+	__raw_writew(0x2000, MRSHPC_ICR);
+	__raw_writeb(0x00, PA_MRSHPC_MW2 + 0x206);
+	__raw_writeb(0x42, PA_MRSHPC_MW2 + 0x200);
+}
+
+#endif /* __MACH_SE_MRSHPC_H */
diff --git a/arch/sh/include/mach-se/mach/se.h b/arch/sh/include/mach-se/mach/se.h
index eb23000..14be91c 100644
--- a/arch/sh/include/mach-se/mach/se.h
+++ b/arch/sh/include/mach-se/mach/se.h
@@ -68,6 +68,24 @@
 #define BCR_ILCRF	(PA_BCR + 10)
 #define BCR_ILCRG	(PA_BCR + 12)
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7709)
+#define INTC_IRR0       0xa4000004UL
+#define INTC_IRR1       0xa4000006UL
+#define INTC_IRR2       0xa4000008UL
+
+#define INTC_ICR0       0xfffffee0UL
+#define INTC_ICR1       0xa4000010UL
+#define INTC_ICR2       0xa4000012UL
+#define INTC_INTER      0xa4000014UL
+
+#define INTC_IPRC       0xa4000016UL
+#define INTC_IPRD       0xa4000018UL
+#define INTC_IPRE       0xa400001aUL
+
+#define IRQ0_IRQ        32
+#define IRQ1_IRQ        33
+#endif
+
 #if defined(CONFIG_CPU_SUBTYPE_SH7705)
 #define IRQ_STNIC	12
 #define IRQ_CFCARD	14
diff --git a/arch/sh/include/mach-se/mach/se7343.h b/arch/sh/include/mach-se/mach/se7343.h
index 9845846..749914b 100644
--- a/arch/sh/include/mach-se/mach/se7343.h
+++ b/arch/sh/include/mach-se/mach/se7343.h
@@ -118,9 +118,6 @@
 #define FPGA_IN		0xb1400000
 #define FPGA_OUT	0xb1400002
 
-#define __IO_PREFIX	sh7343se
-#include <asm/io_generic.h>
-
 #define IRQ0_IRQ        32
 #define IRQ1_IRQ        33
 #define IRQ4_IRQ        36
@@ -132,8 +129,10 @@
 #define SE7343_FPGA_IRQ_MRSHPC3	3
 #define SE7343_FPGA_IRQ_SMC	6	/* EXT_IRQ2 */
 #define SE7343_FPGA_IRQ_USB	8
+#define SE7343_FPGA_IRQ_UARTA	10
+#define SE7343_FPGA_IRQ_UARTB	11
 
-#define SE7343_FPGA_IRQ_NR	11
+#define SE7343_FPGA_IRQ_NR	12
 #define SE7343_FPGA_IRQ_BASE	120
 
 #define MRSHPC_IRQ3    	(SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC3)
@@ -142,6 +141,8 @@
 #define MRSHPC_IRQ0    	(SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC0)
 #define SMC_IRQ		(SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_SMC)
 #define USB_IRQ		(SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_USB)
+#define UARTA_IRQ	(SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_UARTA)
+#define UARTB_IRQ	(SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_UARTB)
 
 /* arch/sh/boards/se/7343/irq.c */
 void init_7343se_IRQ(void);
diff --git a/arch/sh/kernel/Makefile_32 b/arch/sh/kernel/Makefile_32
index 48edfb1..2e1b86e 100644
--- a/arch/sh/kernel/Makefile_32
+++ b/arch/sh/kernel/Makefile_32
@@ -4,25 +4,31 @@
 
 extra-y	:= head_32.o init_task.o vmlinux.lds
 
-obj-y	:= debugtraps.o io.o io_generic.o irq.o machvec.o process_32.o \
-	   ptrace_32.o setup.o signal_32.o sys_sh.o sys_sh32.o \
-	   syscalls_32.o time_32.o topology.o traps.o traps_32.o
+ifdef CONFIG_FUNCTION_TRACER
+# Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_ftrace.o = -pg
+endif
+
+obj-y	:= debugtraps.o idle.o io.o io_generic.o irq.o			\
+	   machvec.o process_32.o ptrace_32.o setup.o signal_32.o	\
+	   sys_sh.o sys_sh32.o syscalls_32.o time_32.o topology.o	\
+	   traps.o traps_32.o
 
 obj-y				+= cpu/ timers/
 obj-$(CONFIG_VSYSCALL)		+= vsyscall/
 obj-$(CONFIG_SMP)		+= smp.o
-obj-$(CONFIG_CF_ENABLER)	+= cf-enabler.o
 obj-$(CONFIG_SH_STANDARD_BIOS)	+= sh_bios.o
-obj-$(CONFIG_SH_KGDB)		+= kgdb_stub.o kgdb_jmp.o
+obj-$(CONFIG_KGDB)		+= kgdb.o
 obj-$(CONFIG_SH_CPU_FREQ)	+= cpufreq.o
 obj-$(CONFIG_MODULES)		+= sh_ksyms_32.o module.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
-obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_IO_TRAPPED)	+= io_trapped.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
+obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
+obj-$(CONFIG_DUMP_CODE)		+= disassemble.o
 
 EXTRA_CFLAGS += -Werror
diff --git a/arch/sh/kernel/Makefile_64 b/arch/sh/kernel/Makefile_64
index c97660b..fe425d7 100644
--- a/arch/sh/kernel/Makefile_64
+++ b/arch/sh/kernel/Makefile_64
@@ -1,21 +1,18 @@
 extra-y	:= head_64.o init_task.o vmlinux.lds
 
-obj-y	:= debugtraps.o io.o io_generic.o irq.o machvec.o process_64.o \
+obj-y	:= debugtraps.o idle.o io.o io_generic.o irq.o machvec.o process_64.o \
 	   ptrace_64.o setup.o signal_64.o sys_sh.o sys_sh64.o \
 	   syscalls_64.o time_64.o topology.o traps.o traps_64.o
 
 obj-y				+= cpu/ timers/
 obj-$(CONFIG_VSYSCALL)		+= vsyscall/
 obj-$(CONFIG_SMP)		+= smp.o
-obj-$(CONFIG_CF_ENABLER)	+= cf-enabler.o
 obj-$(CONFIG_SH_STANDARD_BIOS)	+= sh_bios.o
-obj-$(CONFIG_SH_KGDB)		+= kgdb_stub.o kgdb_jmp.o
 obj-$(CONFIG_SH_CPU_FREQ)	+= cpufreq.o
 obj-$(CONFIG_MODULES)		+= sh_ksyms_64.o module.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
-obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_IO_TRAPPED)	+= io_trapped.o
 obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c
deleted file mode 100644
index bea4033..0000000
--- a/arch/sh/kernel/cf-enabler.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/* $Id: cf-enabler.c,v 1.4 2004/02/22 22:44:36 kkojima Exp $
- *
- *  linux/drivers/block/cf-enabler.c
- *
- *  Copyright (C) 1999  Niibe Yutaka
- *  Copyright (C) 2000  Toshiharu Nozawa
- *  Copyright (C) 2001  A&D Co., Ltd.
- *
- *  Enable the CF configuration.
- */
-
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-/*
- * You can connect Compact Flash directly to the bus of SuperH.
- * This is the enabler for that.
- *
- * SIM: How generic is this really? It looks pretty board, or at
- * least SH sub-type, specific to me.
- * I know it doesn't work on the Overdrive!
- */
-
-/*
- * 0xB8000000 : Attribute
- * 0xB8001000 : Common Memory
- * 0xBA000000 : I/O
- */
-#if defined(CONFIG_CPU_SH4)
-/* SH4 can't access PCMCIA interface through P2 area.
- * we must remap it with appropriate attribute bit of the page set.
- * this part is based on Greg Banks' hd64465_ss.c implementation - Masahiro Abe */
-
-#if defined(CONFIG_CF_AREA6)
-#define slot_no 0
-#else
-#define slot_no 1
-#endif
-
-/* use this pointer to access to directly connected compact flash io area*/
-void *cf_io_base;
-
-static int __init allocate_cf_area(void)
-{
-	pgprot_t prot;
-	unsigned long paddrbase, psize;
-
-	/* open I/O area window */
-	paddrbase = virt_to_phys((void*)CONFIG_CF_BASE_ADDR);
-	psize = PAGE_SIZE;
-	prot = PAGE_KERNEL_PCC(slot_no, _PAGE_PCC_IO16);
-	cf_io_base = p3_ioremap(paddrbase, psize, prot.pgprot);
-	if (!cf_io_base) {
-		printk("allocate_cf_area : can't open CF I/O window!\n");
-		return -ENOMEM;
-	}
-/*	printk("p3_ioremap(paddr=0x%08lx, psize=0x%08lx, prot=0x%08lx)=0x%08lx\n",
-		paddrbase, psize, prot.pgprot, cf_io_base);*/
-
-	/* XXX : do we need attribute and common-memory area also? */
-
-	return 0;
-}
-#endif
-
-static int __init cf_init_default(void)
-{
-/* You must have enabled the card, and set the level interrupt
- * before reaching this point. Possibly in boot ROM or boot loader.
- */
-#if defined(CONFIG_CPU_SH4)
-	allocate_cf_area();
-#endif
-
-	return 0;
-}
-
-#if defined(CONFIG_SH_SOLUTION_ENGINE)
-#include <mach-se/mach/se.h>
-#elif defined(CONFIG_SH_7722_SOLUTION_ENGINE)
-#include <mach-se/mach/se7722.h>
-#elif defined(CONFIG_SH_7721_SOLUTION_ENGINE)
-#include <mach-se/mach/se7721.h>
-#endif
-
-/*
- * SolutionEngine Seriese
- *
- * about MS770xSE
- * 0xB8400000 : Common Memory
- * 0xB8500000 : Attribute
- * 0xB8600000 : I/O
- *
- * about MS7722SE
- * 0xB0400000 : Common Memory
- * 0xB0500000 : Attribute
- * 0xB0600000 : I/O
- */
-
-#if defined(CONFIG_SH_SOLUTION_ENGINE) || \
-    defined(CONFIG_SH_7722_SOLUTION_ENGINE) || \
-    defined(CONFIG_SH_7721_SOLUTION_ENGINE)
-static int __init cf_init_se(void)
-{
-	if ((ctrl_inw(MRSHPC_CSR) & 0x000c) != 0)
-		return 0;	/* Not detected */
-
-	if ((ctrl_inw(MRSHPC_CSR) & 0x0080) == 0) {
-		ctrl_outw(0x0674, MRSHPC_CPWCR); /* Card Vcc is 3.3v? */
-	} else {
-		ctrl_outw(0x0678, MRSHPC_CPWCR); /* Card Vcc is 5V */
-	}
-
-	/*
-	 *  PC-Card window open
-	 *  flag == COMMON/ATTRIBUTE/IO
-	 */
-	/* common window open */
-	ctrl_outw(0x8a84, MRSHPC_MW0CR1);
-	if((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
-		/* common mode & bus width 16bit SWAP = 1*/
-		ctrl_outw(0x0b00, MRSHPC_MW0CR2);
-	else
-		/* common mode & bus width 16bit SWAP = 0*/
-		ctrl_outw(0x0300, MRSHPC_MW0CR2);
-
-	/* attribute window open */
-	ctrl_outw(0x8a85, MRSHPC_MW1CR1);
-	if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
-		/* attribute mode & bus width 16bit SWAP = 1*/
-		ctrl_outw(0x0a00, MRSHPC_MW1CR2);
-	else
-		/* attribute mode & bus width 16bit SWAP = 0*/
-		ctrl_outw(0x0200, MRSHPC_MW1CR2);
-
-	/* I/O window open */
-	ctrl_outw(0x8a86, MRSHPC_IOWCR1);
-	ctrl_outw(0x0008, MRSHPC_CDCR);	 /* I/O card mode */
-	if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
-		ctrl_outw(0x0a00, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 1*/
-	else
-		ctrl_outw(0x0200, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 0*/
-
-	ctrl_outw(0x2000, MRSHPC_ICR);
-	ctrl_outb(0x00, PA_MRSHPC_MW2 + 0x206);
-	ctrl_outb(0x42, PA_MRSHPC_MW2 + 0x200);
-	return 0;
-}
-#else
-static int __init cf_init_se(void)
-{
-	return -1;
-}
-#endif
-
-static int __init cf_init(void)
-{
-	if (mach_is_se() || mach_is_7722se() || mach_is_7721se())
-		return cf_init_se();
-
-	return cf_init_default();
-}
-
-__initcall (cf_init);
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index b7e46d5..7b17137 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -117,6 +117,11 @@
 	unsigned long flags;
 	int ret;
 
+	if (!clk)
+		return -EINVAL;
+
+	clk_enable(clk->parent);
+
 	spin_lock_irqsave(&clock_lock, flags);
 	ret = __clk_enable(clk);
 	spin_unlock_irqrestore(&clock_lock, flags);
@@ -147,9 +152,14 @@
 {
 	unsigned long flags;
 
+	if (!clk)
+		return;
+
 	spin_lock_irqsave(&clock_lock, flags);
 	__clk_disable(clk);
 	spin_unlock_irqrestore(&clock_lock, flags);
+
+	clk_disable(clk->parent);
 }
 EXPORT_SYMBOL_GPL(clk_disable);
 
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 75fb03d..d29e69c 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -261,9 +261,11 @@
 	cache_init();
 
 	if (raw_smp_processor_id() == 0) {
+#ifdef CONFIG_MMU
 		shm_align_mask = max_t(unsigned long,
 				       current_cpu_data.dcache.way_size - 1,
 				       PAGE_SIZE - 1);
+#endif
 
 		/* Boot CPU sets the cache shape */
 		detect_cache_shape();
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile
index 428450c..45f85c7 100644
--- a/arch/sh/kernel/cpu/sh2a/Makefile
+++ b/arch/sh/kernel/cpu/sh2a/Makefile
@@ -8,9 +8,10 @@
 
 obj-$(CONFIG_SH_FPU)	+= fpu.o
 
-obj-$(CONFIG_CPU_SUBTYPE_SH7206)	+= setup-sh7206.o clock-sh7206.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7201)	+= setup-sh7201.o clock-sh7201.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7203)	+= setup-sh7203.o clock-sh7203.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7263)	+= setup-sh7203.o clock-sh7203.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7206)	+= setup-sh7206.o clock-sh7206.o
 obj-$(CONFIG_CPU_SUBTYPE_MXG)		+= setup-mxg.o clock-sh7206.o
 
 # Pinmux setup
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7201.c b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c
new file mode 100644
index 0000000..020a96f
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c
@@ -0,0 +1,85 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/clock-sh7201.c
+ *
+ * SH7201 support for the clock framework
+ *
+ *  Copyright (C) 2008 Peter Griffin  <pgriffin@mpc-data.co.uk>
+ *
+ * Based on clock-sh4.c
+ *  Copyright (C) 2005  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+const static int pll1rate[]={1,2,3,4,6,8};
+const static int pfc_divisors[]={1,2,3,4,6,8,12};
+#define ifc_divisors pfc_divisors
+
+#if (CONFIG_SH_CLK_MD == 0)
+#define PLL2 (4)
+#elif (CONFIG_SH_CLK_MD == 2)
+#define PLL2 (2)
+#elif (CONFIG_SH_CLK_MD == 3)
+#define PLL2 (1)
+#else
+#error "Illegal Clock Mode!"
+#endif
+
+static void master_clk_init(struct clk *clk)
+{
+	clk->rate = 10000000 * PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007];
+}
+
+static struct clk_ops sh7201_master_clk_ops = {
+	.init		= master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+	int idx = (ctrl_inw(FREQCR) & 0x0007);
+	clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops sh7201_module_clk_ops = {
+	.recalc		= module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+	int idx = (ctrl_inw(FREQCR) & 0x0007);
+	clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops sh7201_bus_clk_ops = {
+	.recalc		= bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+	int idx = ((ctrl_inw(FREQCR) >> 4) & 0x0007);
+	clk->rate = clk->parent->rate / ifc_divisors[idx];
+}
+
+static struct clk_ops sh7201_cpu_clk_ops = {
+	.recalc		= cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7201_clk_ops[] = {
+	&sh7201_master_clk_ops,
+	&sh7201_module_clk_ops,
+	&sh7201_bus_clk_ops,
+	&sh7201_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+	if (idx < ARRAY_SIZE(sh7201_clk_ops))
+		*ops = sh7201_clk_ops[idx];
+}
diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c
index 6e79132..e098e2f 100644
--- a/arch/sh/kernel/cpu/sh2a/probe.c
+++ b/arch/sh/kernel/cpu/sh2a/probe.c
@@ -18,16 +18,17 @@
 	/* All SH-2A CPUs have support for 16 and 32-bit opcodes.. */
 	boot_cpu_data.flags			|= CPU_HAS_OP32;
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7203)
+#if defined(CONFIG_CPU_SUBTYPE_SH7201)
+	boot_cpu_data.type			= CPU_SH7201;
+	boot_cpu_data.flags			|= CPU_HAS_FPU;
+#elif defined(CONFIG_CPU_SUBTYPE_SH7203)
 	boot_cpu_data.type			= CPU_SH7203;
-	/* SH7203 has an FPU.. */
 	boot_cpu_data.flags			|= CPU_HAS_FPU;
 #elif defined(CONFIG_CPU_SUBTYPE_SH7263)
 	boot_cpu_data.type			= CPU_SH7263;
 	boot_cpu_data.flags			|= CPU_HAS_FPU;
 #elif defined(CONFIG_CPU_SUBTYPE_SH7206)
 	boot_cpu_data.type			= CPU_SH7206;
-	/* While SH7206 has a DSP.. */
 	boot_cpu_data.flags			|= CPU_HAS_DSP;
 #elif defined(CONFIG_CPU_SUBTYPE_MXG)
 	boot_cpu_data.type			= CPU_MXG;
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
new file mode 100644
index 0000000..0631e42
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
@@ -0,0 +1,331 @@
+/*
+ *  SH7201 setup
+ *
+ *  Copyright (C) 2008  Peter Griffin pgriffin@mpc-data.co.uk
+ *
+ * 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_sci.h>
+
+enum {
+	UNUSED = 0,
+
+	/* interrupt sources */
+	IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+	PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
+	ADC_ADI,
+	MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D,
+	MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F,
+	MTU2_TGI1A, MTU2_TGI1B, MTU2_TCI1V, MTU2_TCI1U,
+	MTU2_TGI2A, MTU2_TGI2B, MTU2_TCI2V, MTU2_TCI2U,
+	MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D, MTU2_TCI3V,
+	MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D, MTU2_TCI4V,
+	MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W,
+	RTC_ARM, RTC_PRD, RTC_CUP,
+	WDT,
+	IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI, IIC30_TEI,
+	IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI, IIC31_TEI,
+	IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI, IIC32_TEI,
+
+	DMAC0_DMINT0, DMAC1_DMINT1,
+	DMAC2_DMINT2, DMAC3_DMINT3,
+
+	SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+	SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
+	SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+	SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
+	SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI,
+	SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI,
+	SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI,
+	SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI,
+
+	DMAC0_DMINTA, DMAC4_DMINT4, DMAC5_DMINT5, DMAC6_DMINT6,
+	DMAC7_DMINT7,
+
+	RCAN0_ERS, RCAN0_OVR,
+	RCAN0_SLE,
+	RCAN0_RM0, RCAN0_RM1,
+
+	RCAN1_ERS, RCAN1_OVR,
+	RCAN1_SLE,
+	RCAN1_RM0, RCAN1_RM1,
+
+	SSI0_SSII, SSI1_SSII,
+
+	TMR0_CMIA0, TMR0_CMIB0, TMR0_OVI0,
+	TMR1_CMIA1, TMR1_CMIB1, TMR1_OVI1,
+
+	/* interrupt groups */
+
+	IRQ, PINT, ADC,
+	MTU20_ABCD, MTU20_VEF, MTU21_AB, MTU21_VU, MTU22_AB, MTU22_VU,
+	MTU23_ABCD, MTU24_ABCD, MTU25_UVW,
+	RTC, IIC30, IIC31, IIC32,
+	SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
+	RCAN0, RCAN1, TMR0, TMR1
+
+};
+
+static struct intc_vect vectors[] __initdata = {
+	INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+	INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+	INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
+	INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
+	INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
+	INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
+	INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
+	INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
+
+	INTC_IRQ(ADC_ADI, 92),
+
+	INTC_IRQ(MTU2_TGI0A, 108), INTC_IRQ(MTU2_TGI0B, 109),
+	INTC_IRQ(MTU2_TGI0C, 110), INTC_IRQ(MTU2_TGI0D, 111),
+	INTC_IRQ(MTU2_TCI0V, 112),
+	INTC_IRQ(MTU2_TGI0E, 113), INTC_IRQ(MTU2_TGI0F, 114),
+
+	INTC_IRQ(MTU2_TGI1A, 116), INTC_IRQ(MTU2_TGI1B, 117),
+	INTC_IRQ(MTU2_TCI1V, 120), INTC_IRQ(MTU2_TCI1U, 121),
+
+	INTC_IRQ(MTU2_TGI2A, 124), INTC_IRQ(MTU2_TGI2B, 125),
+	INTC_IRQ(MTU2_TCI2V, 128), INTC_IRQ(MTU2_TCI2U, 129),
+
+	INTC_IRQ(MTU2_TGI3A, 132), INTC_IRQ(MTU2_TGI3B, 133),
+	INTC_IRQ(MTU2_TGI3C, 134), INTC_IRQ(MTU2_TGI3D, 135),
+	INTC_IRQ(MTU2_TCI3V, 136),
+
+	INTC_IRQ(MTU2_TGI4A, 140), INTC_IRQ(MTU2_TGI4B, 141),
+	INTC_IRQ(MTU2_TGI4C, 142), INTC_IRQ(MTU2_TGI4D, 143),
+	INTC_IRQ(MTU2_TCI4V, 144),
+
+	INTC_IRQ(MTU2_TGI5U, 148), INTC_IRQ(MTU2_TGI5V, 149),
+	INTC_IRQ(MTU2_TGI5W, 150),
+
+	INTC_IRQ(RTC_ARM, 152), INTC_IRQ(RTC_PRD, 153),
+	INTC_IRQ(RTC_CUP, 154), INTC_IRQ(WDT, 156),
+
+	INTC_IRQ(IIC30_STPI, 157), INTC_IRQ(IIC30_NAKI, 158),
+	INTC_IRQ(IIC30_RXI, 159), INTC_IRQ(IIC30_TXI, 160),
+	INTC_IRQ(IIC30_TEI, 161),
+
+	INTC_IRQ(IIC31_STPI, 164), INTC_IRQ(IIC31_NAKI, 165),
+	INTC_IRQ(IIC31_RXI, 166), INTC_IRQ(IIC31_TXI, 167),
+	INTC_IRQ(IIC31_TEI, 168),
+
+	INTC_IRQ(IIC32_STPI, 170), INTC_IRQ(IIC32_NAKI, 171),
+	INTC_IRQ(IIC32_RXI, 172), INTC_IRQ(IIC32_TXI, 173),
+	INTC_IRQ(IIC32_TEI, 174),
+
+	INTC_IRQ(DMAC0_DMINT0, 176), INTC_IRQ(DMAC1_DMINT1, 177),
+	INTC_IRQ(DMAC2_DMINT2, 178), INTC_IRQ(DMAC3_DMINT3, 179),
+
+	INTC_IRQ(SCIF0_BRI, 180), INTC_IRQ(SCIF0_ERI, 181),
+	INTC_IRQ(SCIF0_RXI, 182), INTC_IRQ(SCIF0_TXI, 183),
+	INTC_IRQ(SCIF1_BRI, 184), INTC_IRQ(SCIF1_ERI, 185),
+	INTC_IRQ(SCIF1_RXI, 186), INTC_IRQ(SCIF1_TXI, 187),
+	INTC_IRQ(SCIF2_BRI, 188), INTC_IRQ(SCIF2_ERI, 189),
+	INTC_IRQ(SCIF2_RXI, 190), INTC_IRQ(SCIF2_TXI, 191),
+	INTC_IRQ(SCIF3_BRI, 192), INTC_IRQ(SCIF3_ERI, 193),
+	INTC_IRQ(SCIF3_RXI, 194), INTC_IRQ(SCIF3_TXI, 195),
+	INTC_IRQ(SCIF4_BRI, 196), INTC_IRQ(SCIF4_ERI, 197),
+	INTC_IRQ(SCIF4_RXI, 198), INTC_IRQ(SCIF4_TXI, 199),
+	INTC_IRQ(SCIF5_BRI, 200), INTC_IRQ(SCIF5_ERI, 201),
+	INTC_IRQ(SCIF5_RXI, 202), INTC_IRQ(SCIF5_TXI, 203),
+	INTC_IRQ(SCIF6_BRI, 204), INTC_IRQ(SCIF6_ERI, 205),
+	INTC_IRQ(SCIF6_RXI, 206), INTC_IRQ(SCIF6_TXI, 207),
+	INTC_IRQ(SCIF7_BRI, 208), INTC_IRQ(SCIF7_ERI, 209),
+	INTC_IRQ(SCIF7_RXI, 210), INTC_IRQ(SCIF7_TXI, 211),
+
+	INTC_IRQ(DMAC0_DMINTA, 212), INTC_IRQ(DMAC4_DMINT4, 216),
+	INTC_IRQ(DMAC5_DMINT5, 217), INTC_IRQ(DMAC6_DMINT6, 218),
+	INTC_IRQ(DMAC7_DMINT7, 219),
+
+	INTC_IRQ(RCAN0_ERS, 228), INTC_IRQ(RCAN0_OVR, 229),
+	INTC_IRQ(RCAN0_SLE, 230),
+	INTC_IRQ(RCAN0_RM0, 231), INTC_IRQ(RCAN0_RM1, 232),
+
+	INTC_IRQ(RCAN1_ERS, 234), INTC_IRQ(RCAN1_OVR, 235),
+	INTC_IRQ(RCAN1_SLE, 236),
+	INTC_IRQ(RCAN1_RM0, 237), INTC_IRQ(RCAN1_RM1, 238),
+
+	INTC_IRQ(SSI0_SSII, 244), INTC_IRQ(SSI1_SSII, 245),
+
+	INTC_IRQ(TMR0_CMIA0, 246), INTC_IRQ(TMR0_CMIB0, 247),
+	INTC_IRQ(TMR0_OVI0, 248),
+
+	INTC_IRQ(TMR1_CMIA1, 252), INTC_IRQ(TMR1_CMIB1, 253),
+	INTC_IRQ(TMR1_OVI1, 254),
+
+};
+
+static struct intc_group groups[] __initdata = {
+	INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
+		   PINT4, PINT5, PINT6, PINT7),
+	INTC_GROUP(MTU20_ABCD, MTU2_TGI0A, MTU2_TGI0B, MTU2_TGI0C, MTU2_TGI0D),
+	INTC_GROUP(MTU20_VEF, MTU2_TCI0V, MTU2_TGI0E, MTU2_TGI0F),
+
+	INTC_GROUP(MTU21_AB, MTU2_TGI1A, MTU2_TGI1B),
+	INTC_GROUP(MTU21_VU, MTU2_TCI1V, MTU2_TCI1U),
+	INTC_GROUP(MTU22_AB, MTU2_TGI2A, MTU2_TGI2B),
+	INTC_GROUP(MTU22_VU, MTU2_TCI2V, MTU2_TCI2U),
+	INTC_GROUP(MTU23_ABCD, MTU2_TGI3A, MTU2_TGI3B, MTU2_TGI3C, MTU2_TGI3D),
+	INTC_GROUP(MTU24_ABCD, MTU2_TGI4A, MTU2_TGI4B, MTU2_TGI4C, MTU2_TGI4D),
+	INTC_GROUP(MTU25_UVW, MTU2_TGI5U, MTU2_TGI5V, MTU2_TGI5W),
+	INTC_GROUP(RTC, RTC_ARM, RTC_PRD, RTC_CUP ),
+
+	INTC_GROUP(IIC30, IIC30_STPI, IIC30_NAKI, IIC30_RXI, IIC30_TXI,
+		   IIC30_TEI),
+	INTC_GROUP(IIC31, IIC31_STPI, IIC31_NAKI, IIC31_RXI, IIC31_TXI,
+		   IIC31_TEI),
+	INTC_GROUP(IIC32, IIC32_STPI, IIC32_NAKI, IIC32_RXI, IIC32_TXI,
+		   IIC32_TEI),
+
+	INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+	INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
+	INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+	INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
+	INTC_GROUP(SCIF4, SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI),
+	INTC_GROUP(SCIF5, SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI),
+	INTC_GROUP(SCIF6, SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI),
+	INTC_GROUP(SCIF7, SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI),
+
+	INTC_GROUP(RCAN0, RCAN0_ERS, RCAN0_OVR, RCAN0_RM0, RCAN0_RM1,
+		   RCAN0_SLE),
+	INTC_GROUP(RCAN1, RCAN1_ERS, RCAN1_OVR, RCAN1_RM0, RCAN1_RM1,
+		   RCAN1_SLE),
+
+	INTC_GROUP(TMR0, TMR0_CMIA0, TMR0_CMIB0, TMR0_OVI0),
+	INTC_GROUP(TMR1, TMR1_CMIA1, TMR1_CMIB1, TMR1_OVI1),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+	{ 0xfffe9418, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+	{ 0xfffe941a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+	{ 0xfffe9420, 0, 16, 4, /* IPR05 */ { PINT, 0, ADC_ADI, 0 } },
+	{ 0xfffe9800, 0, 16, 4, /* IPR06 */ { 0, MTU20_ABCD, MTU20_VEF, MTU21_AB } },
+	{ 0xfffe9802, 0, 16, 4, /* IPR07 */ { MTU21_VU, MTU22_AB, MTU22_VU,  MTU23_ABCD } },
+	{ 0xfffe9804, 0, 16, 4, /* IPR08 */ { MTU2_TCI3V, MTU24_ABCD, MTU2_TCI4V, MTU25_UVW } },
+
+	{ 0xfffe9806, 0, 16, 4, /* IPR09 */ { RTC, WDT, IIC30, 0 } },
+	{ 0xfffe9808, 0, 16, 4, /* IPR10 */ { IIC31, IIC32, DMAC0_DMINT0, DMAC1_DMINT1 } },
+	{ 0xfffe980a, 0, 16, 4, /* IPR11 */ { DMAC2_DMINT2, DMAC3_DMINT3, SCIF0 , SCIF1 } },
+	{ 0xfffe980c, 0, 16, 4, /* IPR12 */ { SCIF2, SCIF3, SCIF4, SCIF5 } },
+	{ 0xfffe980e, 0, 16, 4, /* IPR13 */ { SCIF6, SCIF7, DMAC0_DMINTA, DMAC4_DMINT4  } },
+	{ 0xfffe9810, 0, 16, 4, /* IPR14 */ { DMAC5_DMINT5, DMAC6_DMINT6, DMAC7_DMINT7, 0 } },
+	{ 0xfffe9812, 0, 16, 4, /* IPR15 */ { 0, RCAN0, RCAN1, 0 } },
+	{ 0xfffe9814, 0, 16, 4, /* IPR16 */ { SSI0_SSII, SSI1_SSII, TMR0, TMR1 } },
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+	{ 0xfffe9408, 0, 16, /* PINTER */
+	  { 0, 0, 0, 0, 0, 0, 0, 0,
+	    PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7201", vectors, groups,
+			 mask_registers, prio_registers, NULL);
+
+static struct plat_sci_port sci_platform_data[] = {
+	{
+		.mapbase	= 0xfffe8000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 181, 182, 183, 180}
+	}, {
+		.mapbase	= 0xfffe8800,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 185, 186, 187, 184}
+	}, {
+		.mapbase	= 0xfffe9000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 189, 186, 187, 188}
+	}, {
+		.mapbase	= 0xfffe9800,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 193, 194, 195, 192}
+	}, {
+		.mapbase	= 0xfffea000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 196, 198, 199, 196}
+	}, {
+		.mapbase	= 0xfffea800,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 201, 202, 203, 200}
+	}, {
+		.mapbase	= 0xfffeb000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 205, 206, 207, 204}
+	}, {
+		.mapbase	= 0xfffeb800,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 209, 210, 211, 208}
+	}, {
+		.flags = 0,
+	}
+};
+
+static struct platform_device sci_device = {
+	.name		= "sh-sci",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= sci_platform_data,
+	},
+};
+
+static struct resource rtc_resources[] = {
+	[0] = {
+		.start	= 0xffff0800,
+		.end	= 0xffff2000 + 0x58 - 1,
+		.flags	= IORESOURCE_IO,
+	},
+	[1] = {
+		/* Period IRQ */
+		.start	= 153,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		/* Carry IRQ */
+		.start	= 154,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[3] = {
+		/* Alarm IRQ */
+		.start	= 152,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device rtc_device = {
+	.name		= "sh-rtc",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(rtc_resources),
+	.resource	= rtc_resources,
+};
+
+static struct platform_device *sh7201_devices[] __initdata = {
+	&sci_device,
+	&rtc_device,
+};
+
+static int __init sh7201_devices_setup(void)
+{
+	return platform_add_devices(sh7201_devices,
+				    ARRAY_SIZE(sh7201_devices));
+}
+__initcall(sh7201_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+	register_intc_controller(&intc_desc);
+}
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index 3fe482d..b4106d0 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -52,7 +52,7 @@
  *	syscall #
  *
  */
-#if defined(CONFIG_KGDB_NMI)
+#if defined(CONFIG_KGDB)
 NMI_VEC = 0x1c0			! Must catch early for debounce
 #endif
 
@@ -307,7 +307,7 @@
 6:	or	k0, k2			! Set the IMASK-bits
 	ldc	k2, ssr
 	!
-#if defined(CONFIG_KGDB_NMI)
+#if defined(CONFIG_KGDB)
 	! Clear in_nmi
 	mov.l	6f, k0
 	mov	#0, k1
@@ -320,7 +320,7 @@
 
 	.align	2
 5:	.long	0x00001000	! DSP
-#ifdef CONFIG_KGDB_NMI
+#ifdef CONFIG_KGDB
 6:	.long	in_nmi
 #endif
 7:	.long	0x30000000
@@ -376,9 +376,9 @@
 !
 	.balign 	512,0,512
 interrupt:
-	mov.l	2f, k2
 	mov.l	3f, k3
-#if defined(CONFIG_KGDB_NMI)
+#if defined(CONFIG_KGDB)
+	mov.l	2f, k2
 	! Debounce (filter nested NMI)
 	mov.l	@k2, k0
 	mov.l	5f, k1
@@ -390,16 +390,16 @@
 	rte
 	 nop
 	.align	2
+2:	.long	INTEVT
 5:	.long	NMI_VEC
 6:	.long	in_nmi
 0:
-#endif /* defined(CONFIG_KGDB_NMI) */
+#endif /* defined(CONFIG_KGDB) */
 	bra	handle_exception
 	 mov	#-1, k2		! interrupt exception marker
 
 	.align	2
 1:	.long	EXPEVT
-2:	.long	INTEVT
 3:	.long	ret_from_irq
 4:	.long	ret_from_exception
 
diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
index dac4297..e5a0de3 100644
--- a/arch/sh/kernel/cpu/sh3/ex.S
+++ b/arch/sh/kernel/cpu/sh3/ex.S
@@ -26,7 +26,7 @@
 #define	fpu_error_trap_handler		exception_error
 #endif
 
-#if !defined(CONFIG_KGDB_NMI)
+#if !defined(CONFIG_KGDB)
 #define kgdb_handle_exception		exception_error
 #endif
 
diff --git a/arch/sh/kernel/cpu/sh4/softfloat.c b/arch/sh/kernel/cpu/sh4/softfloat.c
index 2b747f3..42edf2e 100644
--- a/arch/sh/kernel/cpu/sh4/softfloat.c
+++ b/arch/sh/kernel/cpu/sh4/softfloat.c
@@ -37,6 +37,7 @@
  */
 #include <linux/kernel.h>
 #include <cpu/fpu.h>
+#include <asm/div64.h>
 
 #define LIT64( a ) a##LL
 
@@ -67,16 +68,16 @@
 extern void float_raise(unsigned int flags);	/* in fpu.c */
 extern int float_rounding_mode(void);	/* in fpu.c */
 
-inline bits64 extractFloat64Frac(float64 a);
-inline flag extractFloat64Sign(float64 a);
-inline int16 extractFloat64Exp(float64 a);
-inline int16 extractFloat32Exp(float32 a);
-inline flag extractFloat32Sign(float32 a);
-inline bits32 extractFloat32Frac(float32 a);
-inline float64 packFloat64(flag zSign, int16 zExp, bits64 zSig);
-inline void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr);
-inline float32 packFloat32(flag zSign, int16 zExp, bits32 zSig);
-inline void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr);
+bits64 extractFloat64Frac(float64 a);
+flag extractFloat64Sign(float64 a);
+int16 extractFloat64Exp(float64 a);
+int16 extractFloat32Exp(float32 a);
+flag extractFloat32Sign(float32 a);
+bits32 extractFloat32Frac(float32 a);
+float64 packFloat64(flag zSign, int16 zExp, bits64 zSig);
+void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr);
+float32 packFloat32(flag zSign, int16 zExp, bits32 zSig);
+void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr);
 float64 float64_sub(float64 a, float64 b);
 float32 float32_sub(float32 a, float32 b);
 float32 float32_add(float32 a, float32 b);
@@ -86,11 +87,11 @@
 float32 float32_mul(float32 a, float32 b);
 float64 float64_mul(float64 a, float64 b);
 float32 float64_to_float32(float64 a);
-inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
+void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
 		   bits64 * z1Ptr);
-inline void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
+void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
 		   bits64 * z1Ptr);
-inline void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr);
+void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr);
 
 static int8 countLeadingZeros32(bits32 a);
 static int8 countLeadingZeros64(bits64 a);
@@ -110,42 +111,42 @@
 static void normalizeFloat32Subnormal(bits32 aSig, int16 * zExpPtr,
 				      bits32 * zSigPtr);
 
-inline bits64 extractFloat64Frac(float64 a)
+bits64 extractFloat64Frac(float64 a)
 {
 	return a & LIT64(0x000FFFFFFFFFFFFF);
 }
 
-inline flag extractFloat64Sign(float64 a)
+flag extractFloat64Sign(float64 a)
 {
 	return a >> 63;
 }
 
-inline int16 extractFloat64Exp(float64 a)
+int16 extractFloat64Exp(float64 a)
 {
 	return (a >> 52) & 0x7FF;
 }
 
-inline int16 extractFloat32Exp(float32 a)
+int16 extractFloat32Exp(float32 a)
 {
 	return (a >> 23) & 0xFF;
 }
 
-inline flag extractFloat32Sign(float32 a)
+flag extractFloat32Sign(float32 a)
 {
 	return a >> 31;
 }
 
-inline bits32 extractFloat32Frac(float32 a)
+bits32 extractFloat32Frac(float32 a)
 {
 	return a & 0x007FFFFF;
 }
 
-inline float64 packFloat64(flag zSign, int16 zExp, bits64 zSig)
+float64 packFloat64(flag zSign, int16 zExp, bits64 zSig)
 {
 	return (((bits64) zSign) << 63) + (((bits64) zExp) << 52) + zSig;
 }
 
-inline void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr)
+void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr)
 {
 	bits64 z;
 
@@ -338,12 +339,12 @@
 
 }
 
-inline float32 packFloat32(flag zSign, int16 zExp, bits32 zSig)
+float32 packFloat32(flag zSign, int16 zExp, bits32 zSig)
 {
 	return (((bits32) zSign) << 31) + (((bits32) zExp) << 23) + zSig;
 }
 
-inline void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr)
+void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr)
 {
 	bits32 z;
 	if (count == 0) {
@@ -634,7 +635,7 @@
 	*zExpPtr = 1 - shiftCount;
 }
 
-inline void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
+void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
 		   bits64 * z1Ptr)
 {
 	bits64 z1;
@@ -644,7 +645,7 @@
 	*z0Ptr = a0 + b0 + (z1 < a1);
 }
 
-inline void
+void
 sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
        bits64 * z1Ptr)
 {
@@ -656,11 +657,14 @@
 {
 	bits64 b0, b1;
 	bits64 rem0, rem1, term0, term1;
-	bits64 z;
+	bits64 z, tmp;
 	if (b <= a0)
 		return LIT64(0xFFFFFFFFFFFFFFFF);
 	b0 = b >> 32;
-	z = (b0 << 32 <= a0) ? LIT64(0xFFFFFFFF00000000) : (a0 / b0) << 32;
+	tmp = a0;
+	do_div(tmp, b0);
+
+	z = (b0 << 32 <= a0) ? LIT64(0xFFFFFFFF00000000) : tmp << 32;
 	mul64To128(b, z, &term0, &term1);
 	sub128(a0, a1, term0, term1, &rem0, &rem1);
 	while (((sbits64) rem0) < 0) {
@@ -669,11 +673,13 @@
 		add128(rem0, rem1, b0, b1, &rem0, &rem1);
 	}
 	rem0 = (rem0 << 32) | (rem1 >> 32);
-	z |= (b0 << 32 <= rem0) ? 0xFFFFFFFF : rem0 / b0;
+	tmp = rem0;
+	do_div(tmp, b0);
+	z |= (b0 << 32 <= rem0) ? 0xFFFFFFFF : tmp;
 	return z;
 }
 
-inline void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr)
+void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr)
 {
 	bits32 aHigh, aLow, bHigh, bLow;
 	bits64 z0, zMiddleA, zMiddleB, z1;
@@ -769,7 +775,8 @@
 {
 	flag aSign, bSign, zSign;
 	int16 aExp, bExp, zExp;
-	bits32 aSig, bSig, zSig;
+	bits32 aSig, bSig;
+	uint64_t zSig;
 
 	aSig = extractFloat32Frac(a);
 	aExp = extractFloat32Exp(a);
@@ -804,11 +811,13 @@
 		aSig >>= 1;
 		++zExp;
 	}
-	zSig = (((bits64) aSig) << 32) / bSig;
+	zSig = (((bits64) aSig) << 32);
+	do_div(zSig, bSig);
+
 	if ((zSig & 0x3F) == 0) {
 		zSig |= (((bits64) bSig) * zSig != ((bits64) aSig) << 32);
 	}
-	return roundAndPackFloat32(zSign, zExp, zSig);
+	return roundAndPackFloat32(zSign, zExp, (bits32)zSig);
 
 }
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
index db91385..0e174af 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -229,7 +229,7 @@
 }
 
 /**
- * sh7722_find_divisors - find divisor for setting rate
+ * sh7722_find_div_index - find divisor for setting rate
  *
  * All sh7722 clocks use the same set of multipliers/divisors. This function
  * chooses correct divisor to set the rate of clock with parent clock that
@@ -238,7 +238,7 @@
  * @parent_rate: rate of parent clock
  * @rate: requested rate to be set
  */
-static int sh7722_find_divisors(unsigned long parent_rate, unsigned rate)
+static int sh7722_find_div_index(unsigned long parent_rate, unsigned rate)
 {
 	unsigned div2 = parent_rate * 2 / rate;
 	int index;
@@ -247,12 +247,12 @@
 		return -EINVAL;
 
 	for (index = 1; index < ARRAY_SIZE(divisors2); index++) {
-		if (div2 > divisors2[index] && div2 <= divisors2[index])
+		if (div2 > divisors2[index - 1] && div2 <= divisors2[index])
 			break;
 	}
 	if (index >= ARRAY_SIZE(divisors2))
 		index = ARRAY_SIZE(divisors2) - 1;
-	return divisors2[index];
+	return index;
 }
 
 static void sh7722_frqcr_recalc(struct clk *clk)
@@ -279,12 +279,12 @@
 		return -EINVAL;
 
 	/* look for multiplier/divisor pair */
-	div = sh7722_find_divisors(parent_rate, rate);
+	div = sh7722_find_div_index(parent_rate, rate);
 	if (div<0)
 		return div;
 
 	/* calculate new value of clock rate */
-	clk->rate = parent_rate * 2 / div;
+	clk->rate = parent_rate * 2 / divisors2[div];
 	frqcr = ctrl_inl(FRQCR);
 
 	/* FIXME: adjust as algo_id specifies */
@@ -353,7 +353,7 @@
 			int part_div;
 
 			if (likely(!err)) {
-				part_div = sh7722_find_divisors(parent_rate,
+				part_div = sh7722_find_div_index(parent_rate,
 								rate);
 				if (part_div > 0) {
 					part_ctx = sh7722_get_clk_context(
@@ -394,12 +394,12 @@
 	int div;
 
 	/* look for multiplier/divisor pair */
-	div = sh7722_find_divisors(parent_rate, rate);
+	div = sh7722_find_div_index(parent_rate, rate);
 	if (div < 0)
 		return clk->rate;
 
 	/* calculate new value of clock rate */
-	return parent_rate * 2 / div;
+	return parent_rate * 2 / divisors2[div];
 }
 
 static struct clk_ops sh7722_frqcr_clk_ops = {
@@ -421,7 +421,7 @@
 	int div;
 
 	r = ctrl_inl(clk->arch_flags);
-	div = sh7722_find_divisors(clk->parent->rate, rate);
+	div = sh7722_find_div_index(clk->parent->rate, rate);
 	if (div < 0)
 		return div;
 	r = (r & ~0xF) | div;
@@ -516,16 +516,19 @@
 static struct clk sh7722_umem_clock = {
 	.name = "umem_clk",
 	.ops = &sh7722_frqcr_clk_ops,
+	.flags = CLK_RATE_PROPAGATES,
 };
 
 static struct clk sh7722_sh_clock = {
 	.name = "sh_clk",
 	.ops = &sh7722_frqcr_clk_ops,
+	.flags = CLK_RATE_PROPAGATES,
 };
 
 static struct clk sh7722_peripheral_clock = {
 	.name = "peripheral_clk",
 	.ops = &sh7722_frqcr_clk_ops,
+	.flags = CLK_RATE_PROPAGATES,
 };
 
 static struct clk sh7722_sdram_clock = {
@@ -533,6 +536,11 @@
 	.ops = &sh7722_frqcr_clk_ops,
 };
 
+static struct clk sh7722_r_clock = {
+	.name = "r_clk",
+	.rate = 32768,
+	.flags = CLK_RATE_PROPAGATES,
+};
 
 #ifndef CONFIG_CPU_SUBTYPE_SH7343
 
@@ -567,12 +575,30 @@
 	.ops = &sh7722_video_clk_ops,
 };
 
-static int sh7722_mstpcr_start_stop(struct clk *clk, unsigned long reg,
-				    int enable)
+#define MSTPCR_ARCH_FLAGS(reg, bit) (((reg) << 8) | (bit))
+#define MSTPCR_ARCH_FLAGS_REG(value) ((value) >> 8)
+#define MSTPCR_ARCH_FLAGS_BIT(value) ((value) & 0xff)
+
+static int sh7722_mstpcr_start_stop(struct clk *clk, int enable)
 {
-	unsigned long bit = clk->arch_flags;
+	unsigned long bit = MSTPCR_ARCH_FLAGS_BIT(clk->arch_flags);
+	unsigned long reg;
 	unsigned long r;
 
+	switch(MSTPCR_ARCH_FLAGS_REG(clk->arch_flags)) {
+	case 0:
+		reg = MSTPCR0;
+		break;
+	case 1:
+		reg = MSTPCR1;
+		break;
+	case 2:
+		reg = MSTPCR2;
+		break;
+	default:
+		return -EINVAL;
+	}  
+
 	r = ctrl_inl(reg);
 
 	if (enable)
@@ -584,96 +610,175 @@
 	return 0;
 }
 
-static void sh7722_mstpcr0_enable(struct clk *clk)
+static void sh7722_mstpcr_enable(struct clk *clk)
 {
-	sh7722_mstpcr_start_stop(clk, MSTPCR0, 1);
+	sh7722_mstpcr_start_stop(clk, 1);
 }
 
-static void sh7722_mstpcr0_disable(struct clk *clk)
+static void sh7722_mstpcr_disable(struct clk *clk)
 {
-	sh7722_mstpcr_start_stop(clk, MSTPCR0, 0);
+	sh7722_mstpcr_start_stop(clk, 0);
 }
 
-static void sh7722_mstpcr1_enable(struct clk *clk)
+static void sh7722_mstpcr_recalc(struct clk *clk)
 {
-	sh7722_mstpcr_start_stop(clk, MSTPCR1, 1);
+	if (clk->parent)
+		clk->rate = clk->parent->rate;
 }
 
-static void sh7722_mstpcr1_disable(struct clk *clk)
-{
-	sh7722_mstpcr_start_stop(clk, MSTPCR1, 0);
-}
-
-static void sh7722_mstpcr2_enable(struct clk *clk)
-{
-	sh7722_mstpcr_start_stop(clk, MSTPCR2, 1);
-}
-
-static void sh7722_mstpcr2_disable(struct clk *clk)
-{
-	sh7722_mstpcr_start_stop(clk, MSTPCR2, 0);
-}
-
-static struct clk_ops sh7722_mstpcr0_clk_ops = {
-	.enable = sh7722_mstpcr0_enable,
-	.disable = sh7722_mstpcr0_disable,
+static struct clk_ops sh7722_mstpcr_clk_ops = {
+	.enable = sh7722_mstpcr_enable,
+	.disable = sh7722_mstpcr_disable,
+	.recalc = sh7722_mstpcr_recalc,
 };
 
-static struct clk_ops sh7722_mstpcr1_clk_ops = {
-	.enable = sh7722_mstpcr1_enable,
-	.disable = sh7722_mstpcr1_disable,
-};
-
-static struct clk_ops sh7722_mstpcr2_clk_ops = {
-	.enable = sh7722_mstpcr2_enable,
-	.disable = sh7722_mstpcr2_disable,
-};
-
-#define DECLARE_MSTPCRN(regnr, bitnr, bitstr)		\
-{							\
-	.name = "mstp" __stringify(regnr) bitstr,	\
-	.arch_flags = bitnr,				\
-	.ops = &sh7722_mstpcr ## regnr ## _clk_ops,	\
+#define MSTPCR(_name, _parent, regnr, bitnr) \
+{						\
+	.name = _name,				\
+	.arch_flags = MSTPCR_ARCH_FLAGS(regnr, bitnr),	\
+	.ops = (void *)_parent,		\
 }
 
-#define DECLARE_MSTPCR(regnr) \
-	DECLARE_MSTPCRN(regnr, 31, "31"), \
-	DECLARE_MSTPCRN(regnr, 30, "30"), \
-	DECLARE_MSTPCRN(regnr, 29, "29"), \
-	DECLARE_MSTPCRN(regnr, 28, "28"), \
-	DECLARE_MSTPCRN(regnr, 27, "27"), \
-	DECLARE_MSTPCRN(regnr, 26, "26"), \
-	DECLARE_MSTPCRN(regnr, 25, "25"), \
-	DECLARE_MSTPCRN(regnr, 24, "24"), \
-	DECLARE_MSTPCRN(regnr, 23, "23"), \
-	DECLARE_MSTPCRN(regnr, 22, "22"), \
-	DECLARE_MSTPCRN(regnr, 21, "21"), \
-	DECLARE_MSTPCRN(regnr, 20, "20"), \
-	DECLARE_MSTPCRN(regnr, 19, "19"), \
-	DECLARE_MSTPCRN(regnr, 18, "18"), \
-	DECLARE_MSTPCRN(regnr, 17, "17"), \
-	DECLARE_MSTPCRN(regnr, 16, "16"), \
-	DECLARE_MSTPCRN(regnr, 15, "15"), \
-	DECLARE_MSTPCRN(regnr, 14, "14"), \
-	DECLARE_MSTPCRN(regnr, 13, "13"), \
-	DECLARE_MSTPCRN(regnr, 12, "12"), \
-	DECLARE_MSTPCRN(regnr, 11, "11"), \
-	DECLARE_MSTPCRN(regnr, 10, "10"), \
-	DECLARE_MSTPCRN(regnr, 9, "09"), \
-	DECLARE_MSTPCRN(regnr, 8, "08"), \
-	DECLARE_MSTPCRN(regnr, 7, "07"), \
-	DECLARE_MSTPCRN(regnr, 6, "06"), \
-	DECLARE_MSTPCRN(regnr, 5, "05"), \
-	DECLARE_MSTPCRN(regnr, 4, "04"), \
-	DECLARE_MSTPCRN(regnr, 3, "03"), \
-	DECLARE_MSTPCRN(regnr, 2, "02"), \
-	DECLARE_MSTPCRN(regnr, 1, "01"), \
-	DECLARE_MSTPCRN(regnr, 0, "00")
-
-static struct clk sh7722_mstpcr[] = {
-	DECLARE_MSTPCR(0),
-	DECLARE_MSTPCR(1),
-	DECLARE_MSTPCR(2),
+static struct clk sh7722_mstpcr_clocks[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7722)
+	MSTPCR("uram0", "umem_clk", 0, 28),
+	MSTPCR("xymem0", "bus_clk", 0, 26),
+	MSTPCR("tmu0", "peripheral_clk", 0, 15),
+	MSTPCR("cmt0", "r_clk", 0, 14),
+	MSTPCR("rwdt0", "r_clk", 0, 13),
+	MSTPCR("flctl0", "peripheral_clk", 0, 10),
+	MSTPCR("scif0", "peripheral_clk", 0, 7),
+	MSTPCR("scif1", "peripheral_clk", 0, 6),
+	MSTPCR("scif2", "peripheral_clk", 0, 5),
+	MSTPCR("i2c0", "peripheral_clk", 1, 9),
+	MSTPCR("rtc0", "r_clk", 1, 8),
+	MSTPCR("sdhi0", "peripheral_clk", 2, 18),
+	MSTPCR("keysc0", "r_clk", 2, 14),
+	MSTPCR("usbf0", "peripheral_clk", 2, 11),
+	MSTPCR("2dg0", "bus_clk", 2, 9),
+	MSTPCR("siu0", "bus_clk", 2, 8),
+	MSTPCR("vou0", "bus_clk", 2, 5),
+	MSTPCR("jpu0", "bus_clk", 2, 6),
+	MSTPCR("beu0", "bus_clk", 2, 4),
+	MSTPCR("ceu0", "bus_clk", 2, 3),
+	MSTPCR("veu0", "bus_clk", 2, 2),
+	MSTPCR("vpu0", "bus_clk", 2, 1),
+	MSTPCR("lcdc0", "bus_clk", 2, 0),
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7723)
+	/* See page 60 of Datasheet V1.0: Overview -> Block Diagram */
+	MSTPCR("tlb0", "cpu_clk", 0, 31),
+	MSTPCR("ic0", "cpu_clk", 0, 30),
+	MSTPCR("oc0", "cpu_clk", 0, 29),
+	MSTPCR("l2c0", "sh_clk", 0, 28),
+	MSTPCR("ilmem0", "cpu_clk", 0, 27),
+	MSTPCR("fpu0", "cpu_clk", 0, 24),
+	MSTPCR("intc0", "cpu_clk", 0, 22),
+	MSTPCR("dmac0", "bus_clk", 0, 21),
+	MSTPCR("sh0", "sh_clk", 0, 20),
+	MSTPCR("hudi0", "peripheral_clk", 0, 19),
+	MSTPCR("ubc0", "cpu_clk", 0, 17),
+	MSTPCR("tmu0", "peripheral_clk", 0, 15),
+	MSTPCR("cmt0", "r_clk", 0, 14),
+	MSTPCR("rwdt0", "r_clk", 0, 13),
+	MSTPCR("dmac1", "bus_clk", 0, 12),
+	MSTPCR("tmu1", "peripheral_clk", 0, 11),
+	MSTPCR("flctl0", "peripheral_clk", 0, 10),
+	MSTPCR("scif0", "peripheral_clk", 0, 9),
+	MSTPCR("scif1", "peripheral_clk", 0, 8),
+	MSTPCR("scif2", "peripheral_clk", 0, 7),
+	MSTPCR("scif3", "bus_clk", 0, 6),
+	MSTPCR("scif4", "bus_clk", 0, 5),
+	MSTPCR("scif5", "bus_clk", 0, 4),
+	MSTPCR("msiof0", "bus_clk", 0, 2),
+	MSTPCR("msiof1", "bus_clk", 0, 1),
+	MSTPCR("meram0", "sh_clk", 0, 0),
+	MSTPCR("i2c0", "peripheral_clk", 1, 9),
+	MSTPCR("rtc0", "r_clk", 1, 8),
+	MSTPCR("atapi0", "sh_clk", 2, 28),
+	MSTPCR("adc0", "peripheral_clk", 2, 28),
+	MSTPCR("tpu0", "bus_clk", 2, 25),
+	MSTPCR("irda0", "peripheral_clk", 2, 24),
+	MSTPCR("tsif0", "bus_clk", 2, 22),
+	MSTPCR("icb0", "bus_clk", 2, 21),
+	MSTPCR("sdhi0", "bus_clk", 2, 18),
+	MSTPCR("sdhi1", "bus_clk", 2, 17),
+	MSTPCR("keysc0", "r_clk", 2, 14),
+	MSTPCR("usb0", "bus_clk", 2, 11),
+	MSTPCR("2dg0", "bus_clk", 2, 10),
+	MSTPCR("siu0", "bus_clk", 2, 8),
+	MSTPCR("veu1", "bus_clk", 2, 6),
+	MSTPCR("vou0", "bus_clk", 2, 5),
+	MSTPCR("beu0", "bus_clk", 2, 4),
+	MSTPCR("ceu0", "bus_clk", 2, 3),
+	MSTPCR("veu0", "bus_clk", 2, 2),
+	MSTPCR("vpu0", "bus_clk", 2, 1),
+	MSTPCR("lcdc0", "bus_clk", 2, 0),
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7343)
+	MSTPCR("uram0", "umem_clk", 0, 28),
+	MSTPCR("xymem0", "bus_clk", 0, 26),
+	MSTPCR("tmu0", "peripheral_clk", 0, 15),
+	MSTPCR("cmt0", "r_clk", 0, 14),
+	MSTPCR("rwdt0", "r_clk", 0, 13),
+	MSTPCR("scif0", "peripheral_clk", 0, 7),
+	MSTPCR("scif1", "peripheral_clk", 0, 6),
+	MSTPCR("scif2", "peripheral_clk", 0, 5),
+	MSTPCR("scif3", "peripheral_clk", 0, 4),
+	MSTPCR("i2c0", "peripheral_clk", 1, 9),
+	MSTPCR("i2c1", "peripheral_clk", 1, 8),
+	MSTPCR("sdhi0", "peripheral_clk", 2, 18),
+	MSTPCR("keysc0", "r_clk", 2, 14),
+	MSTPCR("usbf0", "peripheral_clk", 2, 11),
+	MSTPCR("siu0", "bus_clk", 2, 8),
+	MSTPCR("jpu0", "bus_clk", 2, 6),
+	MSTPCR("vou0", "bus_clk", 2, 5),
+	MSTPCR("beu0", "bus_clk", 2, 4),
+	MSTPCR("ceu0", "bus_clk", 2, 3),
+	MSTPCR("veu0", "bus_clk", 2, 2),
+	MSTPCR("vpu0", "bus_clk", 2, 1),
+	MSTPCR("lcdc0", "bus_clk", 2, 0),
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7366)
+	/* See page 52 of Datasheet V0.40: Overview -> Block Diagram */
+	MSTPCR("tlb0", "cpu_clk", 0, 31),
+	MSTPCR("ic0", "cpu_clk", 0, 30),
+	MSTPCR("oc0", "cpu_clk", 0, 29),
+	MSTPCR("rsmem0", "sh_clk", 0, 28),
+	MSTPCR("xymem0", "cpu_clk", 0, 26),
+	MSTPCR("intc30", "peripheral_clk", 0, 23),
+	MSTPCR("intc0", "peripheral_clk", 0, 22),
+	MSTPCR("dmac0", "bus_clk", 0, 21),
+	MSTPCR("sh0", "sh_clk", 0, 20),
+	MSTPCR("hudi0", "peripheral_clk", 0, 19),
+	MSTPCR("ubc0", "cpu_clk", 0, 17),
+	MSTPCR("tmu0", "peripheral_clk", 0, 15),
+	MSTPCR("cmt0", "r_clk", 0, 14),
+	MSTPCR("rwdt0", "r_clk", 0, 13),
+	MSTPCR("flctl0", "peripheral_clk", 0, 10),
+	MSTPCR("scif0", "peripheral_clk", 0, 7),
+	MSTPCR("scif1", "bus_clk", 0, 6),
+	MSTPCR("scif2", "bus_clk", 0, 5),
+	MSTPCR("msiof0", "peripheral_clk", 0, 2),
+	MSTPCR("sbr0", "peripheral_clk", 0, 1),
+	MSTPCR("i2c0", "peripheral_clk", 1, 9),
+	MSTPCR("icb0", "bus_clk", 2, 27),
+	MSTPCR("meram0", "sh_clk", 2, 26),
+	MSTPCR("dacc0", "peripheral_clk", 2, 24),
+	MSTPCR("dacy0", "peripheral_clk", 2, 23),
+	MSTPCR("tsif0", "bus_clk", 2, 22),
+	MSTPCR("sdhi0", "bus_clk", 2, 18),
+	MSTPCR("mmcif0", "bus_clk", 2, 17),
+	MSTPCR("usb0", "bus_clk", 2, 11),
+	MSTPCR("siu0", "bus_clk", 2, 8),
+	MSTPCR("veu1", "bus_clk", 2, 7),
+	MSTPCR("vou0", "bus_clk", 2, 5),
+	MSTPCR("beu0", "bus_clk", 2, 4),
+	MSTPCR("ceu0", "bus_clk", 2, 3),
+	MSTPCR("veu0", "bus_clk", 2, 2),
+	MSTPCR("vpu0", "bus_clk", 2, 1),
+	MSTPCR("lcdc0", "bus_clk", 2, 0),
+#endif
 };
 
 static struct clk *sh7722_clocks[] = {
@@ -710,21 +815,30 @@
 
 int __init arch_clk_init(void)
 {
-	struct clk *master;
+	struct clk *clk;
 	int i;
 
-	master = clk_get(NULL, "master_clk");
+	clk = clk_get(NULL, "master_clk");
 	for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) {
 		pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name);
-		sh7722_clocks[i]->parent = master;
+		sh7722_clocks[i]->parent = clk;
 		clk_register(sh7722_clocks[i]);
 	}
-	clk_put(master);
+	clk_put(clk);
 
-	for (i = 0; i < ARRAY_SIZE(sh7722_mstpcr); i++) {
-		pr_debug( "Registering mstpcr '%s'\n", sh7722_mstpcr[i].name);
-		clk_register(&sh7722_mstpcr[i]);
+	clk_register(&sh7722_r_clock);
+
+	for (i = 0; i < ARRAY_SIZE(sh7722_mstpcr_clocks); i++) {
+		pr_debug( "Registering mstpcr clock '%s'\n",
+			  sh7722_mstpcr_clocks[i].name);
+		clk = clk_get(NULL, (void *) sh7722_mstpcr_clocks[i].ops);
+		sh7722_mstpcr_clocks[i].parent = clk;
+		sh7722_mstpcr_clocks[i].ops = &sh7722_mstpcr_clk_ops;
+		clk_register(&sh7722_mstpcr_clocks[i]);
+		clk_put(clk);
 	}
 
+	clk_recalc_rate(&sh7722_r_clock); /* make sure rate gets propagated */
+
 	return 0;
 }
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
index 78881b4..0623e37 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
@@ -30,6 +30,7 @@
 
 static struct platform_device iic0_device = {
 	.name           = "i2c-sh_mobile",
+	.id             = 0, /* "i2c0" clock */
 	.num_resources  = ARRAY_SIZE(iic0_resources),
 	.resource       = iic0_resources,
 };
@@ -50,6 +51,7 @@
 
 static struct platform_device iic1_device = {
 	.name           = "i2c-sh_mobile",
+	.id             = 1, /* "i2c1" clock */
 	.num_resources  = ARRAY_SIZE(iic1_resources),
 	.resource       = iic1_resources,
 };
@@ -115,7 +117,22 @@
 		.mapbase	= 0xffe00000,
 		.flags		= UPF_BOOT_AUTOCONF,
 		.type		= PORT_SCIF,
-		.irqs		= { 80, 81, 83, 82 },
+		.irqs		= { 80, 80, 80, 80 },
+	}, {
+		.mapbase	= 0xffe10000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 81, 81, 81, 81 },
+	}, {
+		.mapbase	= 0xffe20000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 82, 82, 82, 82 },
+	}, {
+		.mapbase	= 0xffe30000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 83, 83, 83, 83 },
 	}, {
 		.flags = 0,
 	}
@@ -139,18 +156,10 @@
 
 static int __init sh7343_devices_setup(void)
 {
-	clk_always_enable("mstp031"); /* TLB */
-	clk_always_enable("mstp030"); /* IC */
-	clk_always_enable("mstp029"); /* OC */
-	clk_always_enable("mstp028"); /* URAM */
-	clk_always_enable("mstp026"); /* XYMEM */
-	clk_always_enable("mstp023"); /* INTC3 */
-	clk_always_enable("mstp022"); /* INTC */
-	clk_always_enable("mstp020"); /* SuperHyway */
-	clk_always_enable("mstp109"); /* I2C0 */
-	clk_always_enable("mstp108"); /* I2C1 */
-	clk_always_enable("mstp202"); /* VEU */
-	clk_always_enable("mstp201"); /* VPU */
+	clk_always_enable("uram0"); /* URAM */
+	clk_always_enable("xymem0"); /* XYMEM */
+	clk_always_enable("veu0"); /* VEU */
+	clk_always_enable("vpu0"); /* VPU */
 
 	platform_resource_setup_memory(&vpu_device, "vpu", 1 << 20);
 	platform_resource_setup_memory(&veu_device, "veu", 2 << 20);
@@ -171,7 +180,7 @@
 	MMC_ERR, MMC_TRAN, MMC_FSTAT, MMC_FRDY,
 	DMAC4, DMAC5, DMAC_DADERR,
 	KEYSC,
-	SCIF, SCIF1, SCIF2, SCIF3, SCIF4,
+	SCIF, SCIF1, SCIF2, SCIF3,
 	SIOF0, SIOF1, SIO,
 	FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
 	I2C0_ALI, I2C0_TACKI, I2C0_WAITI, I2C0_DTEI,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
index e17db39..839ae97 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
@@ -32,6 +32,7 @@
 
 static struct platform_device iic_device = {
 	.name           = "i2c-sh_mobile",
+	.id             = 0, /* "i2c0" clock */
 	.num_resources  = ARRAY_SIZE(iic_resources),
 	.resource       = iic_resources,
 };
@@ -176,19 +177,11 @@
 
 static int __init sh7366_devices_setup(void)
 {
-	clk_always_enable("mstp031"); /* TLB */
-	clk_always_enable("mstp030"); /* IC */
-	clk_always_enable("mstp029"); /* OC */
-	clk_always_enable("mstp028"); /* RSMEM */
-	clk_always_enable("mstp026"); /* XYMEM */
-	clk_always_enable("mstp023"); /* INTC3 */
-	clk_always_enable("mstp022"); /* INTC */
-	clk_always_enable("mstp020"); /* SuperHyway */
-	clk_always_enable("mstp109"); /* I2C */
-	clk_always_enable("mstp211"); /* USB */
-	clk_always_enable("mstp207"); /* VEU-2 */
-	clk_always_enable("mstp202"); /* VEU-1 */
-	clk_always_enable("mstp201"); /* VPU */
+	clk_always_enable("rsmem0"); /* RSMEM */
+	clk_always_enable("xymem0"); /* XYMEM */
+	clk_always_enable("veu1"); /* VEU-2 */
+	clk_always_enable("veu0"); /* VEU-1 */
+	clk_always_enable("vpu0"); /* VPU */
 
 	platform_resource_setup_memory(&vpu_device, "vpu", 2 << 20);
 	platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index ef77ee1..50cf683 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -62,7 +62,7 @@
 
 static struct platform_device usbf_device = {
 	.name		= "m66592_udc",
-	.id		= -1,
+	.id             = 0, /* "usbf0" clock */
 	.dev = {
 		.dma_mask		= NULL,
 		.coherent_dma_mask	= 0xffffffff,
@@ -87,6 +87,7 @@
 
 static struct platform_device iic_device = {
 	.name           = "i2c-sh_mobile",
+	.id             = 0, /* "i2c0" clock */
 	.num_resources  = ARRAY_SIZE(iic_resources),
 	.resource       = iic_resources,
 };
@@ -147,6 +148,34 @@
 	.num_resources	= ARRAY_SIZE(veu_resources),
 };
 
+static struct uio_info jpu_platform_data = {
+	.name = "JPU",
+	.version = "0",
+	.irq = 27,
+};
+
+static struct resource jpu_resources[] = {
+	[0] = {
+		.name	= "JPU",
+		.start	= 0xfea00000,
+		.end	= 0xfea102d0,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		/* place holder for contiguous memory */
+	},
+};
+
+static struct platform_device jpu_device = {
+	.name		= "uio_pdrv_genirq",
+	.id		= 2,
+	.dev = {
+		.platform_data	= &jpu_platform_data,
+	},
+	.resource	= jpu_resources,
+	.num_resources	= ARRAY_SIZE(jpu_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
 	{
 		.mapbase	= 0xffe00000,
@@ -186,24 +215,21 @@
 	&sci_device,
 	&vpu_device,
 	&veu_device,
+	&jpu_device,
 };
 
 static int __init sh7722_devices_setup(void)
 {
-	clk_always_enable("mstp031"); /* TLB */
-	clk_always_enable("mstp030"); /* IC */
-	clk_always_enable("mstp029"); /* OC */
-	clk_always_enable("mstp028"); /* URAM */
-	clk_always_enable("mstp026"); /* XYMEM */
-	clk_always_enable("mstp022"); /* INTC */
-	clk_always_enable("mstp020"); /* SuperHyway */
-	clk_always_enable("mstp109"); /* I2C */
-	clk_always_enable("mstp211"); /* USB */
-	clk_always_enable("mstp202"); /* VEU */
-	clk_always_enable("mstp201"); /* VPU */
+	clk_always_enable("uram0"); /* URAM */
+	clk_always_enable("xymem0"); /* XYMEM */
+	clk_always_enable("rtc0"); /* RTC */
+	clk_always_enable("veu0"); /* VEU */
+	clk_always_enable("vpu0"); /* VPU */
+	clk_always_enable("jpu0"); /* JPU */
 
 	platform_resource_setup_memory(&vpu_device, "vpu", 1 << 20);
 	platform_resource_setup_memory(&veu_device, "veu", 2 << 20);
+	platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20);
 
 	return platform_add_devices(sh7722_devices,
 				    ARRAY_SIZE(sh7722_devices));
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
index 6d9e697..849770d 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
@@ -215,6 +215,7 @@
 
 static struct platform_device iic_device = {
 	.name           = "i2c-sh_mobile",
+	.id             = 0, /* "i2c0" clock */
 	.num_resources  = ARRAY_SIZE(iic_resources),
 	.resource       = iic_resources,
 };
@@ -231,19 +232,11 @@
 
 static int __init sh7723_devices_setup(void)
 {
-	clk_always_enable("mstp031"); /* TLB */
-	clk_always_enable("mstp030"); /* IC */
-	clk_always_enable("mstp029"); /* OC */
-	clk_always_enable("mstp024"); /* FPU */
-	clk_always_enable("mstp022"); /* INTC */
-	clk_always_enable("mstp020"); /* SuperHyway */
-	clk_always_enable("mstp000"); /* MERAM */
-	clk_always_enable("mstp109"); /* I2C */
-	clk_always_enable("mstp108"); /* RTC */
-	clk_always_enable("mstp211"); /* USB */
-	clk_always_enable("mstp206"); /* VEU2H1 */
-	clk_always_enable("mstp202"); /* VEU2H0 */
-	clk_always_enable("mstp201"); /* VPU */
+	clk_always_enable("meram0"); /* MERAM */
+	clk_always_enable("rtc0"); /* RTC */
+	clk_always_enable("veu1"); /* VEU2H1 */
+	clk_always_enable("veu0"); /* VEU2H0 */
+	clk_always_enable("vpu0"); /* VPU */
 
 	platform_resource_setup_memory(&vpu_device, "vpu", 2 << 20);
 	platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20);
diff --git a/arch/sh/kernel/debugtraps.S b/arch/sh/kernel/debugtraps.S
index 13b6674..5917413 100644
--- a/arch/sh/kernel/debugtraps.S
+++ b/arch/sh/kernel/debugtraps.S
@@ -3,7 +3,7 @@
  *
  * Debug trap jump tables for SuperH
  *
- *  Copyright (C) 2006  Paul Mundt
+ *  Copyright (C) 2006 - 2008  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -12,12 +12,13 @@
 #include <linux/sys.h>
 #include <linux/linkage.h>
 
-#if !defined(CONFIG_SH_KGDB)
-#define kgdb_handle_exception	debug_trap_handler
+#if !defined(CONFIG_KGDB)
+#define breakpoint_trap_handler		debug_trap_handler
+#define singlestep_trap_handler		debug_trap_handler
 #endif
 
 #if !defined(CONFIG_SH_STANDARD_BIOS)
-#define sh_bios_handler		debug_trap_handler
+#define sh_bios_handler			debug_trap_handler
 #endif
 
 	.data
@@ -35,7 +36,7 @@
 	.long debug_trap_handler	/* 0x39 */
 	.long debug_trap_handler	/* 0x3a */
 	.long debug_trap_handler	/* 0x3b */
-	.long kgdb_handle_exception	/* 0x3c */
-	.long debug_trap_handler	/* 0x3d */
+	.long breakpoint_trap_handler	/* 0x3c */
+	.long singlestep_trap_handler	/* 0x3d */
 	.long bug_trap_handler		/* 0x3e */
 	.long sh_bios_handler		/* 0x3f */
diff --git a/arch/sh/kernel/disassemble.c b/arch/sh/kernel/disassemble.c
new file mode 100644
index 0000000..64d5d8d
--- /dev/null
+++ b/arch/sh/kernel/disassemble.c
@@ -0,0 +1,573 @@
+/*
+ * Disassemble SuperH instructions.
+ *
+ * Copyright (C) 1999 kaz Kojima
+ * Copyright (C) 2008 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+
+/*
+ * Format of an instruction in memory.
+ */
+typedef enum {
+	HEX_0, HEX_1, HEX_2, HEX_3, HEX_4, HEX_5, HEX_6, HEX_7,
+	HEX_8, HEX_9, HEX_A, HEX_B, HEX_C, HEX_D, HEX_E, HEX_F,
+	REG_N, REG_M, REG_NM, REG_B,
+	BRANCH_12, BRANCH_8,
+	DISP_8, DISP_4,
+	IMM_4, IMM_4BY2, IMM_4BY4, PCRELIMM_8BY2, PCRELIMM_8BY4,
+	IMM_8, IMM_8BY2, IMM_8BY4,
+} sh_nibble_type;
+
+typedef enum {
+	A_END, A_BDISP12, A_BDISP8,
+	A_DEC_M, A_DEC_N,
+	A_DISP_GBR, A_DISP_PC, A_DISP_REG_M, A_DISP_REG_N,
+	A_GBR,
+	A_IMM,
+	A_INC_M, A_INC_N,
+	A_IND_M, A_IND_N, A_IND_R0_REG_M, A_IND_R0_REG_N,
+	A_MACH, A_MACL,
+	A_PR, A_R0, A_R0_GBR, A_REG_M, A_REG_N, A_REG_B,
+	A_SR, A_VBR, A_SSR, A_SPC, A_SGR, A_DBR,
+	F_REG_N, F_REG_M, D_REG_N, D_REG_M,
+	X_REG_N, /* Only used for argument parsing */
+	X_REG_M, /* Only used for argument parsing */
+	DX_REG_N, DX_REG_M, V_REG_N, V_REG_M,
+	FD_REG_N,
+	XMTRX_M4,
+	F_FR0,
+	FPUL_N, FPUL_M, FPSCR_N, FPSCR_M,
+} sh_arg_type;
+
+static struct sh_opcode_info {
+	char *name;
+	sh_arg_type arg[7];
+	sh_nibble_type nibbles[4];
+} sh_table[] = {
+	{"add",{A_IMM,A_REG_N},{HEX_7,REG_N,IMM_8}},
+	{"add",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_C}},
+	{"addc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_E}},
+	{"addv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_F}},
+	{"and",{A_IMM,A_R0},{HEX_C,HEX_9,IMM_8}},
+	{"and",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_9}},
+	{"and.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_D,IMM_8}},
+	{"bra",{A_BDISP12},{HEX_A,BRANCH_12}},
+	{"bsr",{A_BDISP12},{HEX_B,BRANCH_12}},
+	{"bt",{A_BDISP8},{HEX_8,HEX_9,BRANCH_8}},
+	{"bf",{A_BDISP8},{HEX_8,HEX_B,BRANCH_8}},
+	{"bt.s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}},
+	{"bt/s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}},
+	{"bf.s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}},
+	{"bf/s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}},
+	{"clrmac",{0},{HEX_0,HEX_0,HEX_2,HEX_8}},
+	{"clrs",{0},{HEX_0,HEX_0,HEX_4,HEX_8}},
+	{"clrt",{0},{HEX_0,HEX_0,HEX_0,HEX_8}},
+	{"cmp/eq",{A_IMM,A_R0},{HEX_8,HEX_8,IMM_8}},
+	{"cmp/eq",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_0}},
+	{"cmp/ge",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_3}},
+	{"cmp/gt",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_7}},
+	{"cmp/hi",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_6}},
+	{"cmp/hs",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_2}},
+	{"cmp/pl",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_5}},
+	{"cmp/pz",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_1}},
+	{"cmp/str",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_C}},
+	{"div0s",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_7}},
+	{"div0u",{0},{HEX_0,HEX_0,HEX_1,HEX_9}},
+	{"div1",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_4}},
+	{"exts.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_E}},
+	{"exts.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_F}},
+	{"extu.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_C}},
+	{"extu.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_D}},
+	{"jmp",{A_IND_N},{HEX_4,REG_N,HEX_2,HEX_B}},
+	{"jsr",{A_IND_N},{HEX_4,REG_N,HEX_0,HEX_B}},
+	{"ldc",{A_REG_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_E}},
+	{"ldc",{A_REG_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_E}},
+	{"ldc",{A_REG_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_E}},
+	{"ldc",{A_REG_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_E}},
+	{"ldc",{A_REG_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_E}},
+	{"ldc",{A_REG_N,A_DBR},{HEX_4,REG_N,HEX_7,HEX_E}},
+	{"ldc",{A_REG_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_E}},
+	{"ldc.l",{A_INC_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_7}},
+	{"ldc.l",{A_INC_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_7}},
+	{"ldc.l",{A_INC_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_7}},
+	{"ldc.l",{A_INC_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_7}},
+	{"ldc.l",{A_INC_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_7}},
+	{"ldc.l",{A_INC_N,A_DBR},{HEX_4,REG_N,HEX_7,HEX_7}},
+	{"ldc.l",{A_INC_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_7}},
+	{"lds",{A_REG_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_A}},
+	{"lds",{A_REG_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_A}},
+	{"lds",{A_REG_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_A}},
+	{"lds",{A_REG_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_A}},
+	{"lds",{A_REG_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_A}},
+	{"lds.l",{A_INC_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_6}},
+	{"lds.l",{A_INC_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_6}},
+	{"lds.l",{A_INC_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_6}},
+	{"lds.l",{A_INC_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_6}},
+	{"lds.l",{A_INC_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_6}},
+	{"ldtlb",{0},{HEX_0,HEX_0,HEX_3,HEX_8}},
+	{"mac.w",{A_INC_M,A_INC_N},{HEX_4,REG_N,REG_M,HEX_F}},
+	{"mov",{A_IMM,A_REG_N},{HEX_E,REG_N,IMM_8}},
+	{"mov",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_3}},
+	{"mov.b",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_4}},
+	{"mov.b",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_4}},
+	{"mov.b",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_0}},
+	{"mov.b",{A_DISP_REG_M,A_R0},{HEX_8,HEX_4,REG_M,IMM_4}},
+	{"mov.b",{A_DISP_GBR,A_R0},{HEX_C,HEX_4,IMM_8}},
+	{"mov.b",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_C}},
+	{"mov.b",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_4}},
+	{"mov.b",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_0}},
+	{"mov.b",{A_R0,A_DISP_REG_M},{HEX_8,HEX_0,REG_M,IMM_4}},
+	{"mov.b",{A_R0,A_DISP_GBR},{HEX_C,HEX_0,IMM_8}},
+	{"mov.l",{ A_REG_M,A_DISP_REG_N},{HEX_1,REG_N,REG_M,IMM_4BY4}},
+	{"mov.l",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_6}},
+	{"mov.l",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_6}},
+	{"mov.l",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_2}},
+	{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_5,REG_N,REG_M,IMM_4BY4}},
+	{"mov.l",{A_DISP_GBR,A_R0},{HEX_C,HEX_6,IMM_8BY4}},
+	{"mov.l",{A_DISP_PC,A_REG_N},{HEX_D,REG_N,PCRELIMM_8BY4}},
+	{"mov.l",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_E}},
+	{"mov.l",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_6}},
+	{"mov.l",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_2}},
+	{"mov.l",{A_R0,A_DISP_GBR},{HEX_C,HEX_2,IMM_8BY4}},
+	{"mov.w",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_5}},
+	{"mov.w",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_5}},
+	{"mov.w",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_1}},
+	{"mov.w",{A_DISP_REG_M,A_R0},{HEX_8,HEX_5,REG_M,IMM_4BY2}},
+	{"mov.w",{A_DISP_GBR,A_R0},{HEX_C,HEX_5,IMM_8BY2}},
+	{"mov.w",{A_DISP_PC,A_REG_N},{HEX_9,REG_N,PCRELIMM_8BY2}},
+	{"mov.w",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_D}},
+	{"mov.w",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_5}},
+	{"mov.w",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_1}},
+	{"mov.w",{A_R0,A_DISP_REG_M},{HEX_8,HEX_1,REG_M,IMM_4BY2}},
+	{"mov.w",{A_R0,A_DISP_GBR},{HEX_C,HEX_1,IMM_8BY2}},
+	{"mova",{A_DISP_PC,A_R0},{HEX_C,HEX_7,PCRELIMM_8BY4}},
+	{"movca.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_C,HEX_3}},
+	{"movt",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_9}},
+	{"muls",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}},
+	{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}},
+	{"mulu",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}},
+	{"neg",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_B}},
+	{"negc",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_A}},
+	{"nop",{0},{HEX_0,HEX_0,HEX_0,HEX_9}},
+	{"not",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_7}},
+	{"ocbi",{A_IND_N},{HEX_0,REG_N,HEX_9,HEX_3}},
+	{"ocbp",{A_IND_N},{HEX_0,REG_N,HEX_A,HEX_3}},
+	{"ocbwb",{A_IND_N},{HEX_0,REG_N,HEX_B,HEX_3}},
+	{"or",{A_IMM,A_R0},{HEX_C,HEX_B,IMM_8}},
+	{"or",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_B}},
+	{"or.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_F,IMM_8}},
+	{"pref",{A_IND_N},{HEX_0,REG_N,HEX_8,HEX_3}},
+	{"rotcl",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_4}},
+	{"rotcr",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_5}},
+	{"rotl",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_4}},
+	{"rotr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_5}},
+	{"rte",{0},{HEX_0,HEX_0,HEX_2,HEX_B}},
+	{"rts",{0},{HEX_0,HEX_0,HEX_0,HEX_B}},
+	{"sets",{0},{HEX_0,HEX_0,HEX_5,HEX_8}},
+	{"sett",{0},{HEX_0,HEX_0,HEX_1,HEX_8}},
+	{"shad",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_C}},
+	{"shld",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_D}},
+	{"shal",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_0}},
+	{"shar",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_1}},
+	{"shll",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_0}},
+	{"shll16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_8}},
+	{"shll2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_8}},
+	{"shll8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_8}},
+	{"shlr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_1}},
+	{"shlr16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_9}},
+	{"shlr2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_9}},
+	{"shlr8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_9}},
+	{"sleep",{0},{HEX_0,HEX_0,HEX_1,HEX_B}},
+	{"stc",{A_SR,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_2}},
+	{"stc",{A_GBR,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_2}},
+	{"stc",{A_VBR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_2}},
+	{"stc",{A_SSR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_2}},
+	{"stc",{A_SPC,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_2}},
+	{"stc",{A_SGR,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_2}},
+	{"stc",{A_DBR,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_2}},
+	{"stc",{A_REG_B,A_REG_N},{HEX_0,REG_N,REG_B,HEX_2}},
+	{"stc.l",{A_SR,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_3}},
+	{"stc.l",{A_GBR,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_3}},
+	{"stc.l",{A_VBR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_3}},
+	{"stc.l",{A_SSR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_3}},
+	{"stc.l",{A_SPC,A_DEC_N},{HEX_4,REG_N,HEX_4,HEX_3}},
+	{"stc.l",{A_SGR,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_3}},
+	{"stc.l",{A_DBR,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_3}},
+	{"stc.l",{A_REG_B,A_DEC_N},{HEX_4,REG_N,REG_B,HEX_3}},
+	{"sts",{A_MACH,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_A}},
+	{"sts",{A_MACL,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_A}},
+	{"sts",{A_PR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_A}},
+	{"sts",{FPUL_M,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_A}},
+	{"sts",{FPSCR_M,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}},
+	{"sts.l",{A_MACH,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_2}},
+	{"sts.l",{A_MACL,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_2}},
+	{"sts.l",{A_PR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_2}},
+	{"sts.l",{FPUL_M,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_2}},
+	{"sts.l",{FPSCR_M,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}},
+	{"sub",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_8}},
+	{"subc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_A}},
+	{"subv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_B}},
+	{"swap.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_8}},
+	{"swap.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_9}},
+	{"tas.b",{A_IND_N},{HEX_4,REG_N,HEX_1,HEX_B}},
+	{"trapa",{A_IMM},{HEX_C,HEX_3,IMM_8}},
+	{"tst",{A_IMM,A_R0},{HEX_C,HEX_8,IMM_8}},
+	{"tst",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_8}},
+	{"tst.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_C,IMM_8}},
+	{"xor",{A_IMM,A_R0},{HEX_C,HEX_A,IMM_8}},
+	{"xor",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_A}},
+	{"xor.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_E,IMM_8}},
+	{"xtrct",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_D}},
+	{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}},
+	{"dt",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_0}},
+	{"dmuls.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_D}},
+	{"dmulu.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_5}},
+	{"mac.l",{A_INC_M,A_INC_N},{HEX_0,REG_N,REG_M,HEX_F}},
+	{"braf",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_3}},
+	{"bsrf",{A_REG_N},{HEX_0,REG_N,HEX_0,HEX_3}},
+	{"fabs",{FD_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}},
+	{"fadd",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_0}},
+	{"fadd",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_0}},
+	{"fcmp/eq",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_4}},
+	{"fcmp/eq",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_4}},
+	{"fcmp/gt",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_5}},
+	{"fcmp/gt",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_5}},
+	{"fcnvds",{D_REG_N,FPUL_M},{HEX_F,REG_N,HEX_B,HEX_D}},
+	{"fcnvsd",{FPUL_M,D_REG_N},{HEX_F,REG_N,HEX_A,HEX_D}},
+	{"fdiv",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_3}},
+	{"fdiv",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_3}},
+	{"fipr",{V_REG_M,V_REG_N},{HEX_F,REG_NM,HEX_E,HEX_D}},
+	{"fldi0",{F_REG_N},{HEX_F,REG_N,HEX_8,HEX_D}},
+	{"fldi1",{F_REG_N},{HEX_F,REG_N,HEX_9,HEX_D}},
+	{"flds",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_1,HEX_D}},
+	{"float",{FPUL_M,FD_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}},
+	{"fmac",{F_FR0,F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_E}},
+	{"fmov",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_C}},
+	{"fmov",{DX_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_C}},
+	{"fmov",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}},
+	{"fmov",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}},
+	{"fmov",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}},
+	{"fmov",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}},
+	{"fmov",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}},
+	{"fmov",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}},
+	{"fmov",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}},
+	{"fmov",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}},
+	{"fmov",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}},
+	{"fmov",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}},
+	{"fmov",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}},
+	{"fmov",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}},
+	{"fmov.d",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}},
+	{"fmov.d",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}},
+	{"fmov.d",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}},
+	{"fmov.d",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}},
+	{"fmov.d",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}},
+	{"fmov.d",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}},
+	{"fmov.s",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}},
+	{"fmov.s",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}},
+	{"fmov.s",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}},
+	{"fmov.s",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}},
+	{"fmov.s",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}},
+	{"fmov.s",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}},
+	{"fmul",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_2}},
+	{"fmul",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_2}},
+	{"fneg",{FD_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}},
+	{"frchg",{0},{HEX_F,HEX_B,HEX_F,HEX_D}},
+	{"fschg",{0},{HEX_F,HEX_3,HEX_F,HEX_D}},
+	{"fsqrt",{FD_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}},
+	{"fsts",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_0,HEX_D}},
+	{"fsub",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_1}},
+	{"fsub",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_1}},
+	{"ftrc",{FD_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}},
+	{"ftrv",{XMTRX_M4,V_REG_N},{HEX_F,REG_NM,HEX_F,HEX_D}},
+	{ 0 },
+};
+
+static void print_sh_insn(u32 memaddr, u16 insn)
+{
+	int relmask = ~0;
+	int nibs[4] = { (insn >> 12) & 0xf, (insn >> 8) & 0xf, (insn >> 4) & 0xf, insn & 0xf};
+	int lastsp;
+	struct sh_opcode_info *op = sh_table;
+
+	for (; op->name; op++) {
+		int n;
+		int imm = 0;
+		int rn = 0;
+		int rm = 0;
+		int rb = 0;
+		int disp_pc;
+		int disp_pc_addr = 0;
+
+		for (n = 0; n < 4; n++) {
+			int i = op->nibbles[n];
+
+			if (i < 16) {
+				if (nibs[n] == i)
+					continue;
+				goto fail;
+			}
+			switch (i) {
+			case BRANCH_8:
+				imm = (nibs[2] << 4) | (nibs[3]);
+				if (imm & 0x80)
+					imm |= ~0xff;
+				imm = ((char)imm) * 2 + 4 ;
+				goto ok;
+			case BRANCH_12:
+				imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]);
+				if (imm & 0x800)
+					imm |= ~0xfff;
+				imm = imm * 2 + 4;
+				goto ok;
+			case IMM_4:
+				imm = nibs[3];
+				goto ok;
+			case IMM_4BY2:
+				imm = nibs[3] <<1;
+				goto ok;
+			case IMM_4BY4:
+				imm = nibs[3] <<2;
+				goto ok;
+			case IMM_8:
+				imm = (nibs[2] << 4) | nibs[3];
+				goto ok;
+			case PCRELIMM_8BY2:
+				imm = ((nibs[2] << 4) | nibs[3]) <<1;
+				relmask = ~1;
+				goto ok;
+			case PCRELIMM_8BY4:
+				imm = ((nibs[2] << 4) | nibs[3]) <<2;
+				relmask = ~3;
+				goto ok;
+			case IMM_8BY2:
+				imm = ((nibs[2] << 4) | nibs[3]) <<1;
+				goto ok;
+			case IMM_8BY4:
+				imm = ((nibs[2] << 4) | nibs[3]) <<2;
+				goto ok;
+			case DISP_8:
+				imm = (nibs[2] << 4) | (nibs[3]);
+				goto ok;
+			case DISP_4:
+				imm = nibs[3];
+				goto ok;
+			case REG_N:
+				rn = nibs[n];
+				break;
+			case REG_M:
+				rm = nibs[n];
+				break;
+			case REG_NM:
+				rn = (nibs[n] & 0xc) >> 2;
+				rm = (nibs[n] & 0x3);
+				break;
+			case REG_B:
+				rb = nibs[n] & 0x07;
+				break;
+			default:
+				return;
+			}
+		}
+
+	ok:
+		printk("%-8s  ", op->name);
+		lastsp = (op->arg[0] == A_END);
+		disp_pc = 0;
+		for (n = 0; n < 6 && op->arg[n] != A_END; n++) {
+			if (n && op->arg[1] != A_END)
+				printk(", ");
+			switch (op->arg[n]) {
+			case A_IMM:
+				printk("#%d", (char)(imm));
+				break;
+			case A_R0:
+				printk("r0");
+				break;
+			case A_REG_N:
+				printk("r%d", rn);
+				break;
+			case A_INC_N:
+				printk("@r%d+", rn);
+				break;
+			case A_DEC_N:
+				printk("@-r%d", rn);
+				break;
+			case A_IND_N:
+				printk("@r%d", rn);
+				break;
+			case A_DISP_REG_N:
+				printk("@(%d,r%d)", imm, rn);
+				break;
+			case A_REG_M:
+				printk("r%d", rm);
+				break;
+			case A_INC_M:
+				printk("@r%d+", rm);
+				break;
+			case A_DEC_M:
+				printk("@-r%d", rm);
+				break;
+			case A_IND_M:
+				printk("@r%d", rm);
+				break;
+			case A_DISP_REG_M:
+				printk("@(%d,r%d)", imm, rm);
+				break;
+			case A_REG_B:
+				printk("r%d_bank", rb);
+				break;
+			case A_DISP_PC:
+				disp_pc = 1;
+				disp_pc_addr = imm + 4 + (memaddr & relmask);
+				printk("%08x <%pS>", disp_pc_addr,
+				       (void *)disp_pc_addr);
+				break;
+			case A_IND_R0_REG_N:
+				printk("@(r0,r%d)", rn);
+				break;
+			case A_IND_R0_REG_M:
+				printk("@(r0,r%d)", rm);
+				break;
+			case A_DISP_GBR:
+				printk("@(%d,gbr)",imm);
+				break;
+			case A_R0_GBR:
+				printk("@(r0,gbr)");
+				break;
+			case A_BDISP12:
+			case A_BDISP8:
+				printk("%08x", imm + memaddr);
+				break;
+			case A_SR:
+				printk("sr");
+				break;
+			case A_GBR:
+				printk("gbr");
+				break;
+			case A_VBR:
+				printk("vbr");
+				break;
+			case A_SSR:
+				printk("ssr");
+				break;
+			case A_SPC:
+				printk("spc");
+				break;
+			case A_MACH:
+				printk("mach");
+				break;
+			case A_MACL:
+				printk("macl");
+				break;
+			case A_PR:
+				printk("pr");
+				break;
+			case A_SGR:
+				printk("sgr");
+				break;
+			case A_DBR:
+				printk("dbr");
+				break;
+			case FD_REG_N:
+				if (0)
+					goto d_reg_n;
+			case F_REG_N:
+				printk("fr%d", rn);
+				break;
+			case F_REG_M:
+				printk("fr%d", rm);
+				break;
+			case DX_REG_N:
+				if (rn & 1) {
+					printk("xd%d", rn & ~1);
+					break;
+				}
+			d_reg_n:
+			case D_REG_N:
+				printk("dr%d", rn);
+				break;
+			case DX_REG_M:
+				if (rm & 1) {
+					printk("xd%d", rm & ~1);
+					break;
+				}
+			case D_REG_M:
+				printk("dr%d", rm);
+				break;
+			case FPSCR_M:
+			case FPSCR_N:
+				printk("fpscr");
+				break;
+			case FPUL_M:
+			case FPUL_N:
+				printk("fpul");
+				break;
+			case F_FR0:
+				printk("fr0");
+				break;
+			case V_REG_N:
+				printk("fv%d", rn*4);
+				break;
+			case V_REG_M:
+				printk("fv%d", rm*4);
+				break;
+			case XMTRX_M4:
+				printk("xmtrx");
+				break;
+			default:
+				return;
+			}
+		}
+
+		if (disp_pc && strcmp(op->name, "mova") != 0) {
+			u32 val;
+
+			if (relmask == ~1)
+				__get_user(val, (u16 *)disp_pc_addr);
+			else
+				__get_user(val, (u32 *)disp_pc_addr);
+
+			printk("  ! %08x <%pS>", val, (void *)val);
+		}
+
+		return;
+	fail:
+		;
+
+	}
+
+	printk(".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]);
+}
+
+void show_code(struct pt_regs *regs)
+{
+	unsigned short *pc = (unsigned short *)regs->pc;
+	long i;
+
+	if (regs->pc & 0x1)
+		return;
+
+	printk("Code:\n");
+
+	for (i = -3 ; i < 6 ; i++) {
+		unsigned short insn;
+
+		if (__get_user(insn, pc + i)) {
+			printk(" (Bad address in pc)\n");
+			break;
+		}
+
+		printk("%s%08lx:  ", (i ? "  ": "->"), (unsigned long)(pc + i));
+		print_sh_insn((unsigned long)(pc + i), insn);
+		printk("\n");
+	}
+
+	printk("\n");
+}
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index 5b7efc4..d62359c 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -308,15 +308,19 @@
 	mov.l	1f, r9
 	mov.l	@r9, r8		! Read from TRA (Trap Address) Register
 #endif
+
+	mov	#OFF_TRA, r10
+	add	r15, r10
+	mov.l	r8, @r10		! set TRA value to tra
+
 	/*
 	 * Check the trap type
 	 */
 	mov	#((0x20 << 2) - 1), r9
 	cmp/hi	r9, r8
 	bt/s	debug_trap		! it's a debug trap..
-	 mov	#OFF_TRA, r9
-	add	r15, r9
-	mov.l	r8, @r9			! set TRA value to tra
+	 nop
+
 #ifdef CONFIG_TRACE_IRQFLAGS
 	mov.l	5f, r10
 	jsr	@r10
@@ -371,47 +375,3 @@
 #endif
 7:	.long	do_syscall_trace_enter
 8:	.long	do_syscall_trace_leave
-
-#ifdef CONFIG_FUNCTION_TRACER
-	.align 2
-	.globl	_mcount
-	.type	_mcount,@function
-	.globl	mcount
-	.type	mcount,@function
-_mcount:
-mcount:
-	mov.l	r4, @-r15
-	mov.l	r5, @-r15
-	mov.l	r6, @-r15
-	mov.l	r7, @-r15
-	sts.l	pr, @-r15
-
-	mov.l	@(20,r15),r4
-	sts	pr, r5
-
-	mov.l	1f, r6
-	mov.l	ftrace_stub, r7	
-	cmp/eq	r6, r7
-	bt	skip_trace
-
-	mov.l	@r6, r6
-	jsr	@r6
-	 nop
-
-skip_trace:
-
-	lds.l	@r15+, pr
-	mov.l	@r15+, r7
-	mov.l	@r15+, r6
-	mov.l	@r15+, r5
-	rts
-	 mov.l	@r15+, r4
-
-	.align 2
-1:	.long	ftrace_trace_function
-
-	.globl	ftrace_stub
-ftrace_stub:
-	rts
-	 nop
-#endif /* CONFIG_FUNCTION_TRACER */
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c
new file mode 100644
index 0000000..4c32474
--- /dev/null
+++ b/arch/sh/kernel/ftrace.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2008 Matt Fleming <mjf@gentoo.org>
+ * Copyright (C) 2008 Paul Mundt <lethal@linux-sh.org>
+ *
+ * Code for replacing ftrace calls with jumps.
+ *
+ * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
+ *
+ * Thanks goes to Ingo Molnar, for suggesting the idea.
+ * Mathieu Desnoyers, for suggesting postponing the modifications.
+ * Arjan van de Ven, for keeping me straight, and explaining to me
+ * the dangers of modifying code on the run.
+ */
+#include <linux/uaccess.h>
+#include <linux/ftrace.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/ftrace.h>
+#include <asm/cacheflush.h>
+
+static unsigned char ftrace_nop[] = {
+	0x09, 0x00,		/* nop */
+	0x09, 0x00,		/* nop */
+};
+
+static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE];
+
+unsigned char *ftrace_nop_replace(void)
+{
+	return ftrace_nop;
+}
+
+static int is_sh_nop(unsigned char *ip)
+{
+	return strncmp(ip, ftrace_nop, sizeof(ftrace_nop));
+}
+
+unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
+{
+	/* Place the address in the memory table. */
+	if (addr == CALLER_ADDR)
+		__raw_writel(addr + MCOUNT_INSN_OFFSET, ftrace_replaced_code);
+	else
+		__raw_writel(addr, ftrace_replaced_code);
+
+	/*
+	 * No locking needed, this must be called via kstop_machine
+	 * which in essence is like running on a uniprocessor machine.
+	 */
+	return ftrace_replaced_code;
+}
+
+int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
+		       unsigned char *new_code)
+{
+	unsigned char replaced[MCOUNT_INSN_SIZE];
+
+	/*
+	 * Note: Due to modules and __init, 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.
+	 *
+	 * No real locking needed, this code is run through
+	 * kstop_machine, or before SMP starts.
+	 */
+
+	/*
+	 * If we're trying to nop out a call to a function, we instead
+	 * place a call to the address after the memory table.
+	 */
+	if (is_sh_nop(new_code) == 0)
+		__raw_writel(ip + MCOUNT_INSN_SIZE, (unsigned long)new_code);
+
+	/* read the text we want to modify */
+	if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
+		return -EFAULT;
+
+	/* Make sure it is what we expect it to be */
+	if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
+		return -EINVAL;
+
+	/* replace the text with the new text */
+	if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
+		return -EPERM;
+
+	flush_icache_range(ip, ip + MCOUNT_INSN_SIZE);
+
+	return 0;
+}
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+	unsigned long ip = (unsigned long)(&ftrace_call);
+	unsigned char old[MCOUNT_INSN_SIZE], *new;
+
+	memcpy(old, (unsigned char *)(ip + MCOUNT_INSN_OFFSET), MCOUNT_INSN_SIZE);
+	new = ftrace_call_replace(ip, (unsigned long)func);
+
+	return ftrace_modify_code(ip + MCOUNT_INSN_OFFSET, old, new);
+}
+
+int ftrace_make_nop(struct module *mod,
+		    struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned char *new, *old;
+	unsigned long ip = rec->ip;
+
+	old = ftrace_call_replace(ip, addr);
+	new = ftrace_nop_replace();
+
+	return ftrace_modify_code(rec->ip, old, new);
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned char *new, *old;
+	unsigned long ip = rec->ip;
+
+	old = ftrace_nop_replace();
+	new = ftrace_call_replace(ip, addr);
+
+	return ftrace_modify_code(rec->ip, old, new);
+}
+
+int __init ftrace_dyn_arch_init(void *data)
+{
+	/* The return code is retured via data */
+	__raw_writel(0, (unsigned long)data);
+
+	return 0;
+}
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S
index ae0a382..788605f 100644
--- a/arch/sh/kernel/head_32.S
+++ b/arch/sh/kernel/head_32.S
@@ -80,8 +80,14 @@
 	mov.l	7f, r0
 	ldc	r0, r7_bank	! ... and initial thread_info
 #endif
-	
-	!			Clear BSS area
+
+#ifndef CONFIG_SH_NO_BSS_INIT
+	/*
+	 * Don't clear BSS if running on slow platforms such as an RTL simulation,
+	 * remote memory via SHdebug link, etc.  For these the memory can be guaranteed
+	 * to be all zero on boot anyway.
+	 */
+				! Clear BSS area
 #ifdef CONFIG_SMP	
 	mov.l	3f, r0
 	cmp/eq	#0, r0		! skip clear if set to zero
@@ -97,6 +103,8 @@
 	 mov.l	r0,@-r2
 
 10:		
+#endif
+
 	!			Additional CPU initialization
 	mov.l	6f, r0
 	jsr	@r0
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
new file mode 100644
index 0000000..fe59ccf
--- /dev/null
+++ b/arch/sh/kernel/idle.c
@@ -0,0 +1,81 @@
+/*
+ * The idle loop for all SuperH platforms.
+ *
+ *  Copyright (C) 2002 - 2008  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/pm.h>
+#include <linux/tick.h>
+#include <linux/preempt.h>
+#include <linux/thread_info.h>
+#include <linux/irqflags.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+
+static int hlt_counter;
+void (*pm_idle)(void);
+void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
+
+static int __init nohlt_setup(char *__unused)
+{
+	hlt_counter = 1;
+	return 1;
+}
+__setup("nohlt", nohlt_setup);
+
+static int __init hlt_setup(char *__unused)
+{
+	hlt_counter = 0;
+	return 1;
+}
+__setup("hlt", hlt_setup);
+
+static void default_idle(void)
+{
+	if (!hlt_counter) {
+		clear_thread_flag(TIF_POLLING_NRFLAG);
+		smp_mb__after_clear_bit();
+		set_bl_bit();
+		stop_critical_timings();
+
+		while (!need_resched())
+			cpu_sleep();
+
+		start_critical_timings();
+		clear_bl_bit();
+		set_thread_flag(TIF_POLLING_NRFLAG);
+	} else
+		while (!need_resched())
+			cpu_relax();
+}
+
+void cpu_idle(void)
+{
+	set_thread_flag(TIF_POLLING_NRFLAG);
+
+	/* endless idle loop with no priority at all */
+	while (1) {
+		void (*idle)(void) = pm_idle;
+
+		if (!idle)
+			idle = default_idle;
+
+		tick_nohz_stop_sched_tick(1);
+		while (!need_resched())
+			idle();
+		tick_nohz_restart_sched_tick();
+
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+		check_pgt_cache();
+	}
+}
diff --git a/arch/sh/kernel/kgdb.c b/arch/sh/kernel/kgdb.c
new file mode 100644
index 0000000..7c747e7
--- /dev/null
+++ b/arch/sh/kernel/kgdb.c
@@ -0,0 +1,285 @@
+/*
+ * SuperH KGDB support
+ *
+ * Copyright (C) 2008  Paul Mundt
+ *
+ * Single stepping taken from the old stub by Henry Bell and Jeremy Siegel.
+ *
+ * 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/kgdb.h>
+#include <linux/kdebug.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/cacheflush.h>
+
+char in_nmi = 0;	/* Set during NMI to prevent re-entry */
+
+/* Macros for single step instruction identification */
+#define OPCODE_BT(op)		(((op) & 0xff00) == 0x8900)
+#define OPCODE_BF(op)		(((op) & 0xff00) == 0x8b00)
+#define OPCODE_BTF_DISP(op)	(((op) & 0x80) ? (((op) | 0xffffff80) << 1) : \
+				 (((op) & 0x7f ) << 1))
+#define OPCODE_BFS(op)		(((op) & 0xff00) == 0x8f00)
+#define OPCODE_BTS(op)		(((op) & 0xff00) == 0x8d00)
+#define OPCODE_BRA(op)		(((op) & 0xf000) == 0xa000)
+#define OPCODE_BRA_DISP(op)	(((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
+				 (((op) & 0x7ff) << 1))
+#define OPCODE_BRAF(op)		(((op) & 0xf0ff) == 0x0023)
+#define OPCODE_BRAF_REG(op)	(((op) & 0x0f00) >> 8)
+#define OPCODE_BSR(op)		(((op) & 0xf000) == 0xb000)
+#define OPCODE_BSR_DISP(op)	(((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
+				 (((op) & 0x7ff) << 1))
+#define OPCODE_BSRF(op)		(((op) & 0xf0ff) == 0x0003)
+#define OPCODE_BSRF_REG(op)	(((op) >> 8) & 0xf)
+#define OPCODE_JMP(op)		(((op) & 0xf0ff) == 0x402b)
+#define OPCODE_JMP_REG(op)	(((op) >> 8) & 0xf)
+#define OPCODE_JSR(op)		(((op) & 0xf0ff) == 0x400b)
+#define OPCODE_JSR_REG(op)	(((op) >> 8) & 0xf)
+#define OPCODE_RTS(op)		((op) == 0xb)
+#define OPCODE_RTE(op)		((op) == 0x2b)
+
+#define SR_T_BIT_MASK           0x1
+#define STEP_OPCODE             0xc33d
+
+/* Calculate the new address for after a step */
+static short *get_step_address(struct pt_regs *linux_regs)
+{
+	opcode_t op = __raw_readw(linux_regs->pc);
+	long addr;
+
+	/* BT */
+	if (OPCODE_BT(op)) {
+		if (linux_regs->sr & SR_T_BIT_MASK)
+			addr = linux_regs->pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = linux_regs->pc + 2;
+	}
+
+	/* BTS */
+	else if (OPCODE_BTS(op)) {
+		if (linux_regs->sr & SR_T_BIT_MASK)
+			addr = linux_regs->pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = linux_regs->pc + 4;	/* Not in delay slot */
+	}
+
+	/* BF */
+	else if (OPCODE_BF(op)) {
+		if (!(linux_regs->sr & SR_T_BIT_MASK))
+			addr = linux_regs->pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = linux_regs->pc + 2;
+	}
+
+	/* BFS */
+	else if (OPCODE_BFS(op)) {
+		if (!(linux_regs->sr & SR_T_BIT_MASK))
+			addr = linux_regs->pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = linux_regs->pc + 4;	/* Not in delay slot */
+	}
+
+	/* BRA */
+	else if (OPCODE_BRA(op))
+		addr = linux_regs->pc + 4 + OPCODE_BRA_DISP(op);
+
+	/* BRAF */
+	else if (OPCODE_BRAF(op))
+		addr = linux_regs->pc + 4
+		    + linux_regs->regs[OPCODE_BRAF_REG(op)];
+
+	/* BSR */
+	else if (OPCODE_BSR(op))
+		addr = linux_regs->pc + 4 + OPCODE_BSR_DISP(op);
+
+	/* BSRF */
+	else if (OPCODE_BSRF(op))
+		addr = linux_regs->pc + 4
+		    + linux_regs->regs[OPCODE_BSRF_REG(op)];
+
+	/* JMP */
+	else if (OPCODE_JMP(op))
+		addr = linux_regs->regs[OPCODE_JMP_REG(op)];
+
+	/* JSR */
+	else if (OPCODE_JSR(op))
+		addr = linux_regs->regs[OPCODE_JSR_REG(op)];
+
+	/* RTS */
+	else if (OPCODE_RTS(op))
+		addr = linux_regs->pr;
+
+	/* RTE */
+	else if (OPCODE_RTE(op))
+		addr = linux_regs->regs[15];
+
+	/* Other */
+	else
+		addr = linux_regs->pc + instruction_size(op);
+
+	flush_icache_range(addr, addr + instruction_size(op));
+	return (short *)addr;
+}
+
+/*
+ * Replace the instruction immediately after the current instruction
+ * (i.e. next in the expected flow of control) with a trap instruction,
+ * so that returning will cause only a single instruction to be executed.
+ * Note that this model is slightly broken for instructions with delay
+ * slots (e.g. B[TF]S, BSR, BRA etc), where both the branch and the
+ * instruction in the delay slot will be executed.
+ */
+
+static unsigned long stepped_address;
+static opcode_t stepped_opcode;
+
+static void do_single_step(struct pt_regs *linux_regs)
+{
+	/* Determine where the target instruction will send us to */
+	unsigned short *addr = get_step_address(linux_regs);
+
+	stepped_address = (int)addr;
+
+	/* Replace it */
+	stepped_opcode = __raw_readw((long)addr);
+	*addr = STEP_OPCODE;
+
+	/* Flush and return */
+	flush_icache_range((long)addr, (long)addr +
+			   instruction_size(stepped_opcode));
+}
+
+/* Undo a single step */
+static void undo_single_step(struct pt_regs *linux_regs)
+{
+	/* If we have stepped, put back the old instruction */
+	/* Use stepped_address in case we stopped elsewhere */
+	if (stepped_opcode != 0) {
+		__raw_writew(stepped_opcode, stepped_address);
+		flush_icache_range(stepped_address, stepped_address + 2);
+	}
+
+	stepped_opcode = 0;
+}
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		gdb_regs[GDB_R0 + i] = regs->regs[i];
+
+	gdb_regs[GDB_PC] = regs->pc;
+	gdb_regs[GDB_PR] = regs->pr;
+	gdb_regs[GDB_SR] = regs->sr;
+	gdb_regs[GDB_GBR] = regs->gbr;
+	gdb_regs[GDB_MACH] = regs->mach;
+	gdb_regs[GDB_MACL] = regs->macl;
+
+	__asm__ __volatile__ ("stc vbr, %0" : "=r" (gdb_regs[GDB_VBR]));
+}
+
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		regs->regs[GDB_R0 + i] = gdb_regs[GDB_R0 + i];
+
+	regs->pc = gdb_regs[GDB_PC];
+	regs->pr = gdb_regs[GDB_PR];
+	regs->sr = gdb_regs[GDB_SR];
+	regs->gbr = gdb_regs[GDB_GBR];
+	regs->mach = gdb_regs[GDB_MACH];
+	regs->macl = gdb_regs[GDB_MACL];
+
+	__asm__ __volatile__ ("ldc %0, vbr" : : "r" (gdb_regs[GDB_VBR]));
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+	gdb_regs[GDB_R15] = p->thread.sp;
+	gdb_regs[GDB_PC] = p->thread.pc;
+}
+
+int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
+			       char *remcomInBuffer, char *remcomOutBuffer,
+			       struct pt_regs *linux_regs)
+{
+	unsigned long addr;
+	char *ptr;
+
+	/* Undo any stepping we may have done */
+	undo_single_step(linux_regs);
+
+	switch (remcomInBuffer[0]) {
+	case 'c':
+	case 's':
+		/* try to read optional parameter, pc unchanged if no parm */
+		ptr = &remcomInBuffer[1];
+		if (kgdb_hex2long(&ptr, &addr))
+			linux_regs->pc = addr;
+	case 'D':
+	case 'k':
+		atomic_set(&kgdb_cpu_doing_single_step, -1);
+
+		if (remcomInBuffer[0] == 's') {
+			do_single_step(linux_regs);
+			kgdb_single_step = 1;
+
+			atomic_set(&kgdb_cpu_doing_single_step,
+				   raw_smp_processor_id());
+		}
+
+		return 0;
+	}
+
+	/* this means that we do not want to exit from the handler: */
+	return -1;
+}
+
+/*
+ * The primary entry points for the kgdb debug trap table entries.
+ */
+BUILD_TRAP_HANDLER(singlestep)
+{
+	unsigned long flags;
+	TRAP_HANDLER_DECL;
+
+	local_irq_save(flags);
+	regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
+	kgdb_handle_exception(vec >> 2, SIGTRAP, 0, regs);
+	local_irq_restore(flags);
+}
+
+
+BUILD_TRAP_HANDLER(breakpoint)
+{
+	unsigned long flags;
+	TRAP_HANDLER_DECL;
+
+	local_irq_save(flags);
+	kgdb_handle_exception(vec >> 2, SIGTRAP, 0, regs);
+	local_irq_restore(flags);
+}
+
+int kgdb_arch_init(void)
+{
+	return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+	/* Breakpoint instruction: trapa #0x3c */
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+	.gdb_bpt_instr		= { 0x3c, 0xc3 },
+#else
+	.gdb_bpt_instr		= { 0xc3, 0x3c },
+#endif
+};
diff --git a/arch/sh/kernel/kgdb_jmp.S b/arch/sh/kernel/kgdb_jmp.S
deleted file mode 100644
index 339bb1d..0000000
--- a/arch/sh/kernel/kgdb_jmp.S
+++ /dev/null
@@ -1,33 +0,0 @@
-#include <linux/linkage.h>
-
-ENTRY(setjmp)
-	add	#(9*4), r4
-	sts.l	pr, @-r4
-	mov.l	r15, @-r4
-	mov.l	r14, @-r4
-	mov.l	r13, @-r4
-	mov.l	r12, @-r4
-	mov.l	r11, @-r4
-	mov.l	r10, @-r4
-	mov.l	r9, @-r4
-	mov.l	r8, @-r4
-	rts
-	 mov	#0, r0
-
-ENTRY(longjmp)
-	mov.l	@r4+, r8
-	mov.l	@r4+, r9
-	mov.l	@r4+, r10
-	mov.l	@r4+, r11
-	mov.l	@r4+, r12
-	mov.l	@r4+, r13
-	mov.l	@r4+, r14
-	mov.l	@r4+, r15
-	lds.l	@r4+, pr
-	mov	r5, r0
-	tst	r0, r0
-	bf	1f
-	mov	#1, r0	! in case val==0
-1:	rts
-	 nop
-
diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c
deleted file mode 100644
index bf8ac4c..0000000
--- a/arch/sh/kernel/kgdb_stub.c
+++ /dev/null
@@ -1,1052 +0,0 @@
-/*
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * Contains extracts from code by Glenn Engel, Jim Kingdon,
- * David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>,
- * Amit S. Kale <akale@veritas.com>,  William Gatliff <bgat@open-widgets.com>,
- * Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>.
- *
- * This version by Henry Bell <henry.bell@st.com>
- * Minor modifications by Jeremy Siegel <jsiegel@mvista.com>
- *
- * Contains low-level support for remote debug using GDB.
- *
- * To enable debugger support, two things need to happen. A call to
- * set_debug_traps() is necessary in order to allow any breakpoints
- * or error conditions to be properly intercepted and reported to gdb.
- * A breakpoint also needs to be generated to begin communication.  This
- * is most easily accomplished by a call to breakpoint() which does
- * a trapa if the initialisation phase has been successfully completed.
- *
- * In this case, set_debug_traps() is not used to "take over" exceptions;
- * other kernel code is modified instead to enter the kgdb functions here
- * when appropriate (see entry.S for breakpoint traps and NMI interrupts,
- * see traps.c for kernel error exceptions).
- *
- * The following gdb commands are supported:
- *
- *    Command       Function                               Return value
- *
- *    g             return the value of the CPU registers  hex data or ENN
- *    G             set the value of the CPU registers     OK or ENN
- *
- *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
- *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
- *    XAA..AA,LLLL: Same, but data is binary (not hex)     OK or ENN
- *
- *    c             Resume at current address              SNN   ( signal NN)
- *    cAA..AA       Continue at address AA..AA             SNN
- *    CNN;          Resume at current address with signal  SNN
- *    CNN;AA..AA    Resume at address AA..AA with signal   SNN
- *
- *    s             Step one instruction                   SNN
- *    sAA..AA       Step one instruction from AA..AA       SNN
- *    SNN;          Step one instruction with signal       SNN
- *    SNNAA..AA     Step one instruction from AA..AA w/NN  SNN
- *
- *    k             kill (Detach GDB)
- *
- *    d             Toggle debug flag
- *    D             Detach GDB
- *
- *    Hct           Set thread t for operations,           OK or ENN
- *                  c = 'c' (step, cont), c = 'g' (other
- *                  operations)
- *
- *    qC            Query current thread ID                QCpid
- *    qfThreadInfo  Get list of current threads (first)    m<id>
- *    qsThreadInfo   "    "  "     "      "   (subsequent)
- *    qOffsets      Get section offsets                  Text=x;Data=y;Bss=z
- *
- *    TXX           Find if thread XX is alive             OK or ENN
- *    ?             What was the last sigval ?             SNN   (signal NN)
- *    O             Output to GDB console
- *
- * Remote communication protocol.
- *
- *    A debug packet whose contents are <data> is encapsulated for
- *    transmission in the form:
- *
- *       $ <data> # CSUM1 CSUM2
- *
- *       <data> must be ASCII alphanumeric and cannot include characters
- *       '$' or '#'.  If <data> starts with two characters followed by
- *       ':', then the existing stubs interpret this as a sequence number.
- *
- *       CSUM1 and CSUM2 are ascii hex representation of an 8-bit
- *       checksum of <data>, the most significant nibble is sent first.
- *       the hex digits 0-9,a-f are used.
- *
- *    Receiver responds with:
- *
- *       +       - if CSUM is correct and ready for next packet
- *       -       - if CSUM is incorrect
- *
- * Responses can be run-length encoded to save space.  A '*' means that
- * the next character is an ASCII encoding giving a repeat count which
- * stands for that many repetitions of the character preceding the '*'.
- * The encoding is n+29, yielding a printable character where n >=3
- * (which is where RLE starts to win).  Don't use an n > 126.
- *
- * So "0* " means the same as "0000".
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/module.h>
-#include <asm/system.h>
-#include <asm/cacheflush.h>
-#include <asm/current.h>
-#include <asm/signal.h>
-#include <asm/pgtable.h>
-#include <asm/ptrace.h>
-#include <asm/kgdb.h>
-#include <asm/io.h>
-
-/* Function pointers for linkage */
-kgdb_debug_hook_t *kgdb_debug_hook;
-kgdb_bus_error_hook_t *kgdb_bus_err_hook;
-
-int (*kgdb_getchar)(void);
-EXPORT_SYMBOL_GPL(kgdb_getchar);
-void (*kgdb_putchar)(int);
-EXPORT_SYMBOL_GPL(kgdb_putchar);
-
-static void put_debug_char(int c)
-{
-	if (!kgdb_putchar)
-		return;
-	(*kgdb_putchar)(c);
-}
-static int get_debug_char(void)
-{
-	if (!kgdb_getchar)
-		return -1;
-	return (*kgdb_getchar)();
-}
-
-/* Num chars in in/out bound buffers, register packets need NUMREGBYTES * 2 */
-#define BUFMAX 1024
-#define NUMREGBYTES (MAXREG*4)
-#define OUTBUFMAX (NUMREGBYTES*2+512)
-
-enum {
-	R0 = 0, R1,  R2,  R3,   R4,   R5,  R6, R7,
-	R8, R9, R10, R11, R12,  R13,  R14, R15,
-	PC, PR, GBR, VBR, MACH, MACL, SR,
-	/*  */
-	MAXREG
-};
-
-static unsigned int registers[MAXREG];
-struct kgdb_regs trap_registers;
-
-char kgdb_in_gdb_mode;
-char in_nmi;			/* Set during NMI to prevent reentry */
-int kgdb_nofault;		/* Boolean to ignore bus errs (i.e. in GDB) */
-
-/* Default values for SCI (can override via kernel args in setup.c) */
-#ifndef CONFIG_KGDB_DEFPORT
-#define CONFIG_KGDB_DEFPORT 1
-#endif
-
-#ifndef CONFIG_KGDB_DEFBAUD
-#define CONFIG_KGDB_DEFBAUD 115200
-#endif
-
-#if defined(CONFIG_KGDB_DEFPARITY_E)
-#define CONFIG_KGDB_DEFPARITY 'E'
-#elif defined(CONFIG_KGDB_DEFPARITY_O)
-#define CONFIG_KGDB_DEFPARITY 'O'
-#else /* CONFIG_KGDB_DEFPARITY_N */
-#define CONFIG_KGDB_DEFPARITY 'N'
-#endif
-
-#ifdef CONFIG_KGDB_DEFBITS_7
-#define CONFIG_KGDB_DEFBITS '7'
-#else /* CONFIG_KGDB_DEFBITS_8 */
-#define CONFIG_KGDB_DEFBITS '8'
-#endif
-
-/* SCI/UART settings, used in kgdb_console_setup() */
-int  kgdb_portnum = CONFIG_KGDB_DEFPORT;
-EXPORT_SYMBOL_GPL(kgdb_portnum);
-int  kgdb_baud = CONFIG_KGDB_DEFBAUD;
-EXPORT_SYMBOL_GPL(kgdb_baud);
-char kgdb_parity = CONFIG_KGDB_DEFPARITY;
-EXPORT_SYMBOL_GPL(kgdb_parity);
-char kgdb_bits = CONFIG_KGDB_DEFBITS;
-EXPORT_SYMBOL_GPL(kgdb_bits);
-
-/* Jump buffer for setjmp/longjmp */
-static jmp_buf rem_com_env;
-
-/* TRA differs sh3/4 */
-#if defined(CONFIG_CPU_SH3)
-#define TRA 0xffffffd0
-#elif defined(CONFIG_CPU_SH4)
-#define TRA 0xff000020
-#endif
-
-/* Macros for single step instruction identification */
-#define OPCODE_BT(op)         (((op) & 0xff00) == 0x8900)
-#define OPCODE_BF(op)         (((op) & 0xff00) == 0x8b00)
-#define OPCODE_BTF_DISP(op)   (((op) & 0x80) ? (((op) | 0xffffff80) << 1) : \
-			      (((op) & 0x7f ) << 1))
-#define OPCODE_BFS(op)        (((op) & 0xff00) == 0x8f00)
-#define OPCODE_BTS(op)        (((op) & 0xff00) == 0x8d00)
-#define OPCODE_BRA(op)        (((op) & 0xf000) == 0xa000)
-#define OPCODE_BRA_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
-			      (((op) & 0x7ff) << 1))
-#define OPCODE_BRAF(op)       (((op) & 0xf0ff) == 0x0023)
-#define OPCODE_BRAF_REG(op)   (((op) & 0x0f00) >> 8)
-#define OPCODE_BSR(op)        (((op) & 0xf000) == 0xb000)
-#define OPCODE_BSR_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
-			      (((op) & 0x7ff) << 1))
-#define OPCODE_BSRF(op)       (((op) & 0xf0ff) == 0x0003)
-#define OPCODE_BSRF_REG(op)   (((op) >> 8) & 0xf)
-#define OPCODE_JMP(op)        (((op) & 0xf0ff) == 0x402b)
-#define OPCODE_JMP_REG(op)    (((op) >> 8) & 0xf)
-#define OPCODE_JSR(op)        (((op) & 0xf0ff) == 0x400b)
-#define OPCODE_JSR_REG(op)    (((op) >> 8) & 0xf)
-#define OPCODE_RTS(op)        ((op) == 0xb)
-#define OPCODE_RTE(op)        ((op) == 0x2b)
-
-#define SR_T_BIT_MASK           0x1
-#define STEP_OPCODE             0xc320
-#define BIOS_CALL_TRAP          0x3f
-
-/* Exception codes as per SH-4 core manual */
-#define ADDRESS_ERROR_LOAD_VEC   7
-#define ADDRESS_ERROR_STORE_VEC  8
-#define TRAP_VEC                 11
-#define INVALID_INSN_VEC         12
-#define INVALID_SLOT_VEC         13
-#define NMI_VEC                  14
-#define USER_BREAK_VEC           15
-#define SERIAL_BREAK_VEC         58
-
-/* Misc static */
-static int stepped_address;
-static short stepped_opcode;
-static char in_buffer[BUFMAX];
-static char out_buffer[OUTBUFMAX];
-
-static void kgdb_to_gdb(const char *s);
-
-/* Convert ch to hex */
-static int hex(const char ch)
-{
-	if ((ch >= 'a') && (ch <= 'f'))
-		return (ch - 'a' + 10);
-	if ((ch >= '0') && (ch <= '9'))
-		return (ch - '0');
-	if ((ch >= 'A') && (ch <= 'F'))
-		return (ch - 'A' + 10);
-	return (-1);
-}
-
-/* Convert the memory pointed to by mem into hex, placing result in buf.
-   Returns a pointer to the last char put in buf (null) */
-static char *mem_to_hex(const char *mem, char *buf, const int count)
-{
-	int i;
-	int ch;
-	unsigned short s_val;
-	unsigned long l_val;
-
-	/* Check for 16 or 32 */
-	if (count == 2 && ((long) mem & 1) == 0) {
-		s_val = *(unsigned short *) mem;
-		mem = (char *) &s_val;
-	} else if (count == 4 && ((long) mem & 3) == 0) {
-		l_val = *(unsigned long *) mem;
-		mem = (char *) &l_val;
-	}
-	for (i = 0; i < count; i++) {
-		ch = *mem++;
-		buf = pack_hex_byte(buf, ch);
-	}
-	*buf = 0;
-	return (buf);
-}
-
-/* Convert the hex array pointed to by buf into binary, to be placed in mem.
-   Return a pointer to the character after the last byte written */
-static char *hex_to_mem(const char *buf, char *mem, const int count)
-{
-	int i;
-	unsigned char ch;
-
-	for (i = 0; i < count; i++) {
-		ch = hex(*buf++) << 4;
-		ch = ch + hex(*buf++);
-		*mem++ = ch;
-	}
-	return (mem);
-}
-
-/* While finding valid hex chars, convert to an integer, then return it */
-static int hex_to_int(char **ptr, int *int_value)
-{
-	int num_chars = 0;
-	int hex_value;
-
-	*int_value = 0;
-
-	while (**ptr) {
-		hex_value = hex(**ptr);
-		if (hex_value >= 0) {
-			*int_value = (*int_value << 4) | hex_value;
-			num_chars++;
-		} else
-			break;
-		(*ptr)++;
-	}
-	return num_chars;
-}
-
-/*  Copy the binary array pointed to by buf into mem.  Fix $, #,
-    and 0x7d escaped with 0x7d.  Return a pointer to the character
-    after the last byte written. */
-static char *ebin_to_mem(const char *buf, char *mem, int count)
-{
-	for (; count > 0; count--, buf++) {
-		if (*buf == 0x7d)
-			*mem++ = *(++buf) ^ 0x20;
-		else
-			*mem++ = *buf;
-	}
-	return mem;
-}
-
-/* Scan for the start char '$', read the packet and check the checksum */
-static void get_packet(char *buffer, int buflen)
-{
-	unsigned char checksum;
-	unsigned char xmitcsum;
-	int i;
-	int count;
-	char ch;
-
-	do {
-		/* Ignore everything until the start character */
-		while ((ch = get_debug_char()) != '$');
-
-		checksum = 0;
-		xmitcsum = -1;
-		count = 0;
-
-		/* Now, read until a # or end of buffer is found */
-		while (count < (buflen - 1)) {
-			ch = get_debug_char();
-
-			if (ch == '#')
-				break;
-
-			checksum = checksum + ch;
-			buffer[count] = ch;
-			count = count + 1;
-		}
-
-		buffer[count] = 0;
-
-		/* Continue to read checksum following # */
-		if (ch == '#') {
-			xmitcsum = hex(get_debug_char()) << 4;
-			xmitcsum += hex(get_debug_char());
-
-			/* Checksum */
-			if (checksum != xmitcsum)
-				put_debug_char('-');	/* Failed checksum */
-			else {
-				/* Ack successful transfer */
-				put_debug_char('+');
-
-				/* If a sequence char is present, reply
-				   the sequence ID */
-				if (buffer[2] == ':') {
-					put_debug_char(buffer[0]);
-					put_debug_char(buffer[1]);
-
-					/* Remove sequence chars from buffer */
-					count = strlen(buffer);
-					for (i = 3; i <= count; i++)
-						buffer[i - 3] = buffer[i];
-				}
-			}
-		}
-	}
-	while (checksum != xmitcsum);	/* Keep trying while we fail */
-}
-
-/* Send the packet in the buffer with run-length encoding */
-static void put_packet(char *buffer)
-{
-	int checksum;
-	char *src;
-	int runlen;
-	int encode;
-
-	do {
-		src = buffer;
-		put_debug_char('$');
-		checksum = 0;
-
-		/* Continue while we still have chars left */
-		while (*src) {
-			/* Check for runs up to 99 chars long */
-			for (runlen = 1; runlen < 99; runlen++) {
-				if (src[0] != src[runlen])
-					break;
-			}
-
-			if (runlen > 3) {
-				/* Got a useful amount, send encoding */
-				encode = runlen + ' ' - 4;
-				put_debug_char(*src);   checksum += *src;
-				put_debug_char('*');    checksum += '*';
-				put_debug_char(encode); checksum += encode;
-				src += runlen;
-			} else {
-				/* Otherwise just send the current char */
-				put_debug_char(*src);   checksum += *src;
-				src += 1;
-			}
-		}
-
-		/* '#' Separator, put high and low components of checksum */
-		put_debug_char('#');
-		put_debug_char(hex_asc_hi(checksum));
-		put_debug_char(hex_asc_lo(checksum));
-	}
-	while ((get_debug_char()) != '+');	/* While no ack */
-}
-
-/* A bus error has occurred - perform a longjmp to return execution and
-   allow handling of the error */
-static void kgdb_handle_bus_error(void)
-{
-	longjmp(rem_com_env, 1);
-}
-
-/* Translate SH-3/4 exception numbers to unix-like signal values */
-static int compute_signal(const int excep_code)
-{
-	int sigval;
-
-	switch (excep_code) {
-
-	case INVALID_INSN_VEC:
-	case INVALID_SLOT_VEC:
-		sigval = SIGILL;
-		break;
-	case ADDRESS_ERROR_LOAD_VEC:
-	case ADDRESS_ERROR_STORE_VEC:
-		sigval = SIGSEGV;
-		break;
-
-	case SERIAL_BREAK_VEC:
-	case NMI_VEC:
-		sigval = SIGINT;
-		break;
-
-	case USER_BREAK_VEC:
-	case TRAP_VEC:
-		sigval = SIGTRAP;
-		break;
-
-	default:
-		sigval = SIGBUS;	/* "software generated" */
-		break;
-	}
-
-	return (sigval);
-}
-
-/* Make a local copy of the registers passed into the handler (bletch) */
-static void kgdb_regs_to_gdb_regs(const struct kgdb_regs *regs,
-				  int *gdb_regs)
-{
-	gdb_regs[R0] = regs->regs[R0];
-	gdb_regs[R1] = regs->regs[R1];
-	gdb_regs[R2] = regs->regs[R2];
-	gdb_regs[R3] = regs->regs[R3];
-	gdb_regs[R4] = regs->regs[R4];
-	gdb_regs[R5] = regs->regs[R5];
-	gdb_regs[R6] = regs->regs[R6];
-	gdb_regs[R7] = regs->regs[R7];
-	gdb_regs[R8] = regs->regs[R8];
-	gdb_regs[R9] = regs->regs[R9];
-	gdb_regs[R10] = regs->regs[R10];
-	gdb_regs[R11] = regs->regs[R11];
-	gdb_regs[R12] = regs->regs[R12];
-	gdb_regs[R13] = regs->regs[R13];
-	gdb_regs[R14] = regs->regs[R14];
-	gdb_regs[R15] = regs->regs[R15];
-	gdb_regs[PC] = regs->pc;
-	gdb_regs[PR] = regs->pr;
-	gdb_regs[GBR] = regs->gbr;
-	gdb_regs[MACH] = regs->mach;
-	gdb_regs[MACL] = regs->macl;
-	gdb_regs[SR] = regs->sr;
-	gdb_regs[VBR] = regs->vbr;
-}
-
-/* Copy local gdb registers back to kgdb regs, for later copy to kernel */
-static void gdb_regs_to_kgdb_regs(const int *gdb_regs,
-				  struct kgdb_regs *regs)
-{
-	regs->regs[R0] = gdb_regs[R0];
-	regs->regs[R1] = gdb_regs[R1];
-	regs->regs[R2] = gdb_regs[R2];
-	regs->regs[R3] = gdb_regs[R3];
-	regs->regs[R4] = gdb_regs[R4];
-	regs->regs[R5] = gdb_regs[R5];
-	regs->regs[R6] = gdb_regs[R6];
-	regs->regs[R7] = gdb_regs[R7];
-	regs->regs[R8] = gdb_regs[R8];
-	regs->regs[R9] = gdb_regs[R9];
-	regs->regs[R10] = gdb_regs[R10];
-	regs->regs[R11] = gdb_regs[R11];
-	regs->regs[R12] = gdb_regs[R12];
-	regs->regs[R13] = gdb_regs[R13];
-	regs->regs[R14] = gdb_regs[R14];
-	regs->regs[R15] = gdb_regs[R15];
-	regs->pc = gdb_regs[PC];
-	regs->pr = gdb_regs[PR];
-	regs->gbr = gdb_regs[GBR];
-	regs->mach = gdb_regs[MACH];
-	regs->macl = gdb_regs[MACL];
-	regs->sr = gdb_regs[SR];
-	regs->vbr = gdb_regs[VBR];
-}
-
-/* Calculate the new address for after a step */
-static short *get_step_address(void)
-{
-	short op = *(short *) trap_registers.pc;
-	long addr;
-
-	/* BT */
-	if (OPCODE_BT(op)) {
-		if (trap_registers.sr & SR_T_BIT_MASK)
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 2;
-	}
-
-	/* BTS */
-	else if (OPCODE_BTS(op)) {
-		if (trap_registers.sr & SR_T_BIT_MASK)
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 4;	/* Not in delay slot */
-	}
-
-	/* BF */
-	else if (OPCODE_BF(op)) {
-		if (!(trap_registers.sr & SR_T_BIT_MASK))
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 2;
-	}
-
-	/* BFS */
-	else if (OPCODE_BFS(op)) {
-		if (!(trap_registers.sr & SR_T_BIT_MASK))
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 4;	/* Not in delay slot */
-	}
-
-	/* BRA */
-	else if (OPCODE_BRA(op))
-		addr = trap_registers.pc + 4 + OPCODE_BRA_DISP(op);
-
-	/* BRAF */
-	else if (OPCODE_BRAF(op))
-		addr = trap_registers.pc + 4
-		    + trap_registers.regs[OPCODE_BRAF_REG(op)];
-
-	/* BSR */
-	else if (OPCODE_BSR(op))
-		addr = trap_registers.pc + 4 + OPCODE_BSR_DISP(op);
-
-	/* BSRF */
-	else if (OPCODE_BSRF(op))
-		addr = trap_registers.pc + 4
-		    + trap_registers.regs[OPCODE_BSRF_REG(op)];
-
-	/* JMP */
-	else if (OPCODE_JMP(op))
-		addr = trap_registers.regs[OPCODE_JMP_REG(op)];
-
-	/* JSR */
-	else if (OPCODE_JSR(op))
-		addr = trap_registers.regs[OPCODE_JSR_REG(op)];
-
-	/* RTS */
-	else if (OPCODE_RTS(op))
-		addr = trap_registers.pr;
-
-	/* RTE */
-	else if (OPCODE_RTE(op))
-		addr = trap_registers.regs[15];
-
-	/* Other */
-	else
-		addr = trap_registers.pc + 2;
-
-	flush_icache_range(addr, addr + 2);
-	return (short *) addr;
-}
-
-/* Set up a single-step.  Replace the instruction immediately after the
-   current instruction (i.e. next in the expected flow of control) with a
-   trap instruction, so that returning will cause only a single instruction
-   to be executed. Note that this model is slightly broken for instructions
-   with delay slots (e.g. B[TF]S, BSR, BRA etc), where both the branch
-   and the instruction in the delay slot will be executed. */
-static void do_single_step(void)
-{
-	unsigned short *addr = 0;
-
-	/* Determine where the target instruction will send us to */
-	addr = get_step_address();
-	stepped_address = (int)addr;
-
-	/* Replace it */
-	stepped_opcode = *(short *)addr;
-	*addr = STEP_OPCODE;
-
-	/* Flush and return */
-	flush_icache_range((long) addr, (long) addr + 2);
-}
-
-/* Undo a single step */
-static void undo_single_step(void)
-{
-	/* If we have stepped, put back the old instruction */
-	/* Use stepped_address in case we stopped elsewhere */
-	if (stepped_opcode != 0) {
-		*(short*)stepped_address = stepped_opcode;
-		flush_icache_range(stepped_address, stepped_address + 2);
-	}
-	stepped_opcode = 0;
-}
-
-/* Send a signal message */
-static void send_signal_msg(const int signum)
-{
-	out_buffer[0] = 'S';
-	out_buffer[1] = hex_asc_hi(signum);
-	out_buffer[2] = hex_asc_lo(signum);
-	out_buffer[3] = 0;
-	put_packet(out_buffer);
-}
-
-/* Reply that all was well */
-static void send_ok_msg(void)
-{
-	strcpy(out_buffer, "OK");
-	put_packet(out_buffer);
-}
-
-/* Reply that an error occurred */
-static void send_err_msg(void)
-{
-	strcpy(out_buffer, "E01");
-	put_packet(out_buffer);
-}
-
-/* Empty message indicates unrecognised command */
-static void send_empty_msg(void)
-{
-	put_packet("");
-}
-
-/* Read memory due to 'm' message */
-static void read_mem_msg(void)
-{
-	char *ptr;
-	int addr;
-	int length;
-
-	/* Jmp, disable bus error handler */
-	if (setjmp(rem_com_env) == 0) {
-
-		kgdb_nofault = 1;
-
-		/* Walk through, have m<addr>,<length> */
-		ptr = &in_buffer[1];
-		if (hex_to_int(&ptr, &addr) && (*ptr++ == ','))
-			if (hex_to_int(&ptr, &length)) {
-				ptr = 0;
-				if (length * 2 > OUTBUFMAX)
-					length = OUTBUFMAX / 2;
-				mem_to_hex((char *) addr, out_buffer, length);
-			}
-		if (ptr)
-			send_err_msg();
-		else
-			put_packet(out_buffer);
-	} else
-		send_err_msg();
-
-	/* Restore bus error handler */
-	kgdb_nofault = 0;
-}
-
-/* Write memory due to 'M' or 'X' message */
-static void write_mem_msg(int binary)
-{
-	char *ptr;
-	int addr;
-	int length;
-
-	if (setjmp(rem_com_env) == 0) {
-
-		kgdb_nofault = 1;
-
-		/* Walk through, have M<addr>,<length>:<data> */
-		ptr = &in_buffer[1];
-		if (hex_to_int(&ptr, &addr) && (*ptr++ == ','))
-			if (hex_to_int(&ptr, &length) && (*ptr++ == ':')) {
-				if (binary)
-					ebin_to_mem(ptr, (char*)addr, length);
-				else
-					hex_to_mem(ptr, (char*)addr, length);
-				flush_icache_range(addr, addr + length);
-				ptr = 0;
-				send_ok_msg();
-			}
-		if (ptr)
-			send_err_msg();
-	} else
-		send_err_msg();
-
-	/* Restore bus error handler */
-	kgdb_nofault = 0;
-}
-
-/* Continue message  */
-static void continue_msg(void)
-{
-	/* Try to read optional parameter, PC unchanged if none */
-	char *ptr = &in_buffer[1];
-	int addr;
-
-	if (hex_to_int(&ptr, &addr))
-		trap_registers.pc = addr;
-}
-
-/* Continue message with signal */
-static void continue_with_sig_msg(void)
-{
-	int signal;
-	char *ptr = &in_buffer[1];
-	int addr;
-
-	/* Report limitation */
-	kgdb_to_gdb("Cannot force signal in kgdb, continuing anyway.\n");
-
-	/* Signal */
-	hex_to_int(&ptr, &signal);
-	if (*ptr == ';')
-		ptr++;
-
-	/* Optional address */
-	if (hex_to_int(&ptr, &addr))
-		trap_registers.pc = addr;
-}
-
-/* Step message */
-static void step_msg(void)
-{
-	continue_msg();
-	do_single_step();
-}
-
-/* Step message with signal */
-static void step_with_sig_msg(void)
-{
-	continue_with_sig_msg();
-	do_single_step();
-}
-
-/* Send register contents */
-static void send_regs_msg(void)
-{
-	kgdb_regs_to_gdb_regs(&trap_registers, registers);
-	mem_to_hex((char *) registers, out_buffer, NUMREGBYTES);
-	put_packet(out_buffer);
-}
-
-/* Set register contents - currently can't set other thread's registers */
-static void set_regs_msg(void)
-{
-	kgdb_regs_to_gdb_regs(&trap_registers, registers);
-	hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES);
-	gdb_regs_to_kgdb_regs(registers, &trap_registers);
-	send_ok_msg();
-}
-
-#ifdef CONFIG_SH_KGDB_CONSOLE
-/*
- * Bring up the ports..
- */
-static int __init kgdb_serial_setup(void)
-{
-	struct console dummy;
-	return kgdb_console_setup(&dummy, 0);
-}
-#else
-#define kgdb_serial_setup()	0
-#endif
-
-/* The command loop, read and act on requests */
-static void kgdb_command_loop(const int excep_code, const int trapa_value)
-{
-	int sigval;
-
-	/* Enter GDB mode (e.g. after detach) */
-	if (!kgdb_in_gdb_mode) {
-		/* Do serial setup, notify user, issue preemptive ack */
-		printk(KERN_NOTICE "KGDB: Waiting for GDB\n");
-		kgdb_in_gdb_mode = 1;
-		put_debug_char('+');
-	}
-
-	/* Reply to host that an exception has occurred */
-	sigval = compute_signal(excep_code);
-	send_signal_msg(sigval);
-
-	/* TRAP_VEC exception indicates a software trap inserted in place of
-	   code by GDB so back up PC by one instruction, as this instruction
-	   will later be replaced by its original one.  Do NOT do this for
-	   trap 0xff, since that indicates a compiled-in breakpoint which
-	   will not be replaced (and we would retake the trap forever) */
-	if ((excep_code == TRAP_VEC) && (trapa_value != (0x3c << 2)))
-		trap_registers.pc -= 2;
-
-	/* Undo any stepping we may have done */
-	undo_single_step();
-
-	while (1) {
-		out_buffer[0] = 0;
-		get_packet(in_buffer, BUFMAX);
-
-		/* Examine first char of buffer to see what we need to do */
-		switch (in_buffer[0]) {
-		case '?':	/* Send which signal we've received */
-			send_signal_msg(sigval);
-			break;
-
-		case 'g':	/* Return the values of the CPU registers */
-			send_regs_msg();
-			break;
-
-		case 'G':	/* Set the value of the CPU registers */
-			set_regs_msg();
-			break;
-
-		case 'm':	/* Read LLLL bytes address AA..AA */
-			read_mem_msg();
-			break;
-
-		case 'M':	/* Write LLLL bytes address AA..AA, ret OK */
-			write_mem_msg(0);	/* 0 = data in hex */
-			break;
-
-		case 'X':	/* Write LLLL bytes esc bin address AA..AA */
-			if (kgdb_bits == '8')
-				write_mem_msg(1); /* 1 = data in binary */
-			else
-				send_empty_msg();
-			break;
-
-		case 'C':	/* Continue, signum included, we ignore it */
-			continue_with_sig_msg();
-			return;
-
-		case 'c':	/* Continue at address AA..AA (optional) */
-			continue_msg();
-			return;
-
-		case 'S':	/* Step, signum included, we ignore it */
-			step_with_sig_msg();
-			return;
-
-		case 's':	/* Step one instruction from AA..AA */
-			step_msg();
-			return;
-
-		case 'k':	/* 'Kill the program' with a kernel ? */
-			break;
-
-		case 'D':	/* Detach from program, send reply OK */
-			kgdb_in_gdb_mode = 0;
-			send_ok_msg();
-			get_debug_char();
-			return;
-
-		default:
-			send_empty_msg();
-			break;
-		}
-	}
-}
-
-/* There has been an exception, most likely a breakpoint. */
-static void handle_exception(struct pt_regs *regs)
-{
-	int excep_code, vbr_val;
-	int count;
-	int trapa_value = ctrl_inl(TRA);
-
-	/* Copy kernel regs (from stack) */
-	for (count = 0; count < 16; count++)
-		trap_registers.regs[count] = regs->regs[count];
-	trap_registers.pc = regs->pc;
-	trap_registers.pr = regs->pr;
-	trap_registers.sr = regs->sr;
-	trap_registers.gbr = regs->gbr;
-	trap_registers.mach = regs->mach;
-	trap_registers.macl = regs->macl;
-
-	asm("stc vbr, %0":"=r"(vbr_val));
-	trap_registers.vbr = vbr_val;
-
-	/* Get excode for command loop call, user access */
-	asm("stc r2_bank, %0":"=r"(excep_code));
-
-	/* Act on the exception */
-	kgdb_command_loop(excep_code, trapa_value);
-
-	/* Copy back the (maybe modified) registers */
-	for (count = 0; count < 16; count++)
-		regs->regs[count] = trap_registers.regs[count];
-	regs->pc = trap_registers.pc;
-	regs->pr = trap_registers.pr;
-	regs->sr = trap_registers.sr;
-	regs->gbr = trap_registers.gbr;
-	regs->mach = trap_registers.mach;
-	regs->macl = trap_registers.macl;
-
-	vbr_val = trap_registers.vbr;
-	asm("ldc %0, vbr": :"r"(vbr_val));
-}
-
-asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
-				      unsigned long r6, unsigned long r7,
-				      struct pt_regs __regs)
-{
-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
-	handle_exception(regs);
-}
-
-/* Initialise the KGDB data structures and serial configuration */
-int __init kgdb_init(void)
-{
-	in_nmi = 0;
-	kgdb_nofault = 0;
-	stepped_opcode = 0;
-	kgdb_in_gdb_mode = 0;
-
-	if (kgdb_serial_setup() != 0) {
-		printk(KERN_NOTICE "KGDB: serial setup error\n");
-		return -1;
-	}
-
-	/* Init ptr to exception handler */
-	kgdb_debug_hook = handle_exception;
-	kgdb_bus_err_hook = kgdb_handle_bus_error;
-
-	/* Enter kgdb now if requested, or just report init done */
-	printk(KERN_NOTICE "KGDB: stub is initialized.\n");
-
-	return 0;
-}
-
-/* Make function available for "user messages"; console will use it too. */
-
-char gdbmsgbuf[BUFMAX];
-#define MAXOUT ((BUFMAX-2)/2)
-
-static void kgdb_msg_write(const char *s, unsigned count)
-{
-	int i;
-	int wcount;
-	char *bufptr;
-
-	/* 'O'utput */
-	gdbmsgbuf[0] = 'O';
-
-	/* Fill and send buffers... */
-	while (count > 0) {
-		bufptr = gdbmsgbuf + 1;
-
-		/* Calculate how many this time */
-		wcount = (count > MAXOUT) ? MAXOUT : count;
-
-		/* Pack in hex chars */
-		for (i = 0; i < wcount; i++)
-			bufptr = pack_hex_byte(bufptr, s[i]);
-		*bufptr = '\0';
-
-		/* Move up */
-		s += wcount;
-		count -= wcount;
-
-		/* Write packet */
-		put_packet(gdbmsgbuf);
-	}
-}
-
-static void kgdb_to_gdb(const char *s)
-{
-	kgdb_msg_write(s, strlen(s));
-}
-
-#ifdef CONFIG_SH_KGDB_CONSOLE
-void kgdb_console_write(struct console *co, const char *s, unsigned count)
-{
-	/* Bail if we're not talking to GDB */
-	if (!kgdb_in_gdb_mode)
-		return;
-
-	kgdb_msg_write(s, count);
-}
-#endif
-
-#ifdef CONFIG_KGDB_SYSRQ
-static void sysrq_handle_gdb(int key, struct tty_struct *tty)
-{
-	printk("Entering GDB stub\n");
-	breakpoint();
-}
-
-static struct sysrq_key_op sysrq_gdb_op = {
-        .handler        = sysrq_handle_gdb,
-        .help_msg       = "Gdb",
-        .action_msg     = "GDB",
-};
-
-static int gdb_register_sysrq(void)
-{
-	printk("Registering GDB sysrq handler\n");
-	register_sysrq_key('g', &sysrq_gdb_op);
-	return 0;
-}
-module_init(gdb_register_sysrq);
-#endif
diff --git a/arch/sh/kernel/pm.c b/arch/sh/kernel/pm.c
deleted file mode 100644
index 10ab62c..0000000
--- a/arch/sh/kernel/pm.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Generic Power Management Routine
- *
- * Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License.
- */
-#include <linux/suspend.h>
-#include <linux/delay.h>
-#include <linux/gfp.h>
-#include <asm/freq.h>
-#include <asm/io.h>
-#include <asm/watchdog.h>
-#include <asm/pm.h>
-
-#define INTR_OFFSET	0x600
-
-#define STBCR		0xffffff82
-#define STBCR2		0xffffff88
-
-#define STBCR_STBY	0x80
-#define STBCR_MSTP2	0x04
-
-#define MCR		0xffffff68
-#define RTCNT		0xffffff70
-
-#define MCR_RMODE	2
-#define MCR_RFSH	4
-
-void pm_enter(void)
-{
-	u8 stbcr, csr;
-	u16 frqcr, mcr;
-	u32 vbr_new, vbr_old;
-
-	set_bl_bit();
-
-	/* set wdt */
-	csr = sh_wdt_read_csr();
-	csr &= ~WTCSR_TME;
-	csr |= WTCSR_CKS_4096;
-	sh_wdt_write_csr(csr);
-	csr = sh_wdt_read_csr();
-	sh_wdt_write_cnt(0);
-
-	/* disable PLL1 */
-	frqcr = ctrl_inw(FRQCR);
-	frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY);
-	ctrl_outw(frqcr, FRQCR);
-
-	/* enable standby */
-	stbcr = ctrl_inb(STBCR);
-	ctrl_outb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR);
-
-	/* set self-refresh */
-	mcr = ctrl_inw(MCR);
-	ctrl_outw(mcr & ~MCR_RFSH, MCR);
-
-	/* set interrupt handler */
-	asm volatile("stc vbr, %0" : "=r" (vbr_old));
-	vbr_new = get_zeroed_page(GFP_ATOMIC);
-	udelay(50);
-	memcpy((void*)(vbr_new + INTR_OFFSET),
-	       &wakeup_start, &wakeup_end - &wakeup_start);
-	asm volatile("ldc %0, vbr" : : "r" (vbr_new));
-
-	ctrl_outw(0, RTCNT);
-	ctrl_outw(mcr | MCR_RFSH | MCR_RMODE, MCR);
-
-	cpu_sleep();
-
-	asm volatile("ldc %0, vbr" : : "r" (vbr_old));
-
-	free_page(vbr_new);
-
-	/* enable PLL1 */
-	frqcr = ctrl_inw(FRQCR);
-	frqcr |= FRQCR_PSTBY;
-	ctrl_outw(frqcr, FRQCR);
-	udelay(50);
-	frqcr |= FRQCR_PLLEN;
-	ctrl_outw(frqcr, FRQCR);
-
-	ctrl_outb(stbcr, STBCR);
-
-	clear_bl_bit();
-}
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index b965f02..ddafbbb 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -32,65 +32,8 @@
 #include <asm/fpu.h>
 #include <asm/syscalls.h>
 
-static int hlt_counter;
 int ubc_usercnt = 0;
 
-void (*pm_idle)(void);
-void (*pm_power_off)(void);
-EXPORT_SYMBOL(pm_power_off);
-
-static int __init nohlt_setup(char *__unused)
-{
-	hlt_counter = 1;
-	return 1;
-}
-__setup("nohlt", nohlt_setup);
-
-static int __init hlt_setup(char *__unused)
-{
-	hlt_counter = 0;
-	return 1;
-}
-__setup("hlt", hlt_setup);
-
-static void default_idle(void)
-{
-	if (!hlt_counter) {
-		clear_thread_flag(TIF_POLLING_NRFLAG);
-		smp_mb__after_clear_bit();
-		set_bl_bit();
-		while (!need_resched())
-			cpu_sleep();
-		clear_bl_bit();
-		set_thread_flag(TIF_POLLING_NRFLAG);
-	} else
-		while (!need_resched())
-			cpu_relax();
-}
-
-void cpu_idle(void)
-{
-	set_thread_flag(TIF_POLLING_NRFLAG);
-
-	/* endless idle loop with no priority at all */
-	while (1) {
-		void (*idle)(void) = pm_idle;
-
-		if (!idle)
-			idle = default_idle;
-
-		tick_nohz_stop_sched_tick(1);
-		while (!need_resched())
-			idle();
-		tick_nohz_restart_sched_tick();
-
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
-		check_pgt_cache();
-	}
-}
-
 void machine_restart(char * __unused)
 {
 	/* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
@@ -115,8 +58,8 @@
 void show_regs(struct pt_regs * regs)
 {
 	printk("\n");
-	printk("Pid : %d, Comm: %20s\n", task_pid_nr(current), current->comm);
-	printk("CPU : %d    %s  (%s %.*s)\n",
+	printk("Pid : %d, Comm: \t\t%s\n", task_pid_nr(current), current->comm);
+	printk("CPU : %d        \t\t%s  (%s %.*s)\n\n",
 	       smp_processor_id(), print_tainted(), init_utsname()->release,
 	       (int)strcspn(init_utsname()->version, " "),
 	       init_utsname()->version);
@@ -148,26 +91,16 @@
 	       regs->mach, regs->macl, regs->gbr, regs->pr);
 
 	show_trace(NULL, (unsigned long *)regs->regs[15], regs);
+	show_code(regs);
 }
 
 /*
  * Create a kernel thread
  */
-
-/*
- * This is the mechanism for creating a new kernel thread.
- *
- */
-extern void kernel_thread_helper(void);
-__asm__(".align 5\n"
-	"kernel_thread_helper:\n\t"
-	"jsr	@r5\n\t"
-	" nop\n\t"
-	"mov.l	1f, r1\n\t"
-	"jsr	@r1\n\t"
-	" mov	r0, r4\n\t"
-	".align 2\n\t"
-	"1:.long do_exit");
+ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+{
+	do_exit(fn(arg));
+}
 
 /* Don't use this in BL=1(cli).  Or else, CPU resets! */
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c
index b7aa092..a7e5f2e 100644
--- a/arch/sh/kernel/process_64.c
+++ b/arch/sh/kernel/process_64.c
@@ -23,7 +23,6 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/proc_fs.h>
 #include <linux/io.h>
 #include <asm/syscalls.h>
 #include <asm/uaccess.h>
@@ -33,56 +32,6 @@
 
 struct task_struct *last_task_used_math = NULL;
 
-static int hlt_counter = 1;
-
-#define HARD_IDLE_TIMEOUT (HZ / 3)
-
-static int __init nohlt_setup(char *__unused)
-{
-	hlt_counter = 1;
-	return 1;
-}
-
-static int __init hlt_setup(char *__unused)
-{
-	hlt_counter = 0;
-	return 1;
-}
-
-__setup("nohlt", nohlt_setup);
-__setup("hlt", hlt_setup);
-
-static inline void hlt(void)
-{
-	__asm__ __volatile__ ("sleep" : : : "memory");
-}
-
-/*
- * The idle loop on a uniprocessor SH..
- */
-void cpu_idle(void)
-{
-	/* endless idle loop with no priority at all */
-	while (1) {
-		if (hlt_counter) {
-			while (!need_resched())
-				cpu_relax();
-		} else {
-			local_irq_disable();
-			while (!need_resched()) {
-				local_irq_enable();
-				hlt();
-				local_irq_disable();
-			}
-			local_irq_enable();
-		}
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
-	}
-
-}
-
 void machine_restart(char * __unused)
 {
 	extern void phys_stext(void);
@@ -97,13 +46,6 @@
 
 void machine_power_off(void)
 {
-#if 0
-	/* Disable watchdog timer */
-	ctrl_outl(0xa5000000, WTCSR);
-	/* Configure deep standby on sleep */
-	ctrl_outl(0x03, STBCR);
-#endif
-
 	__asm__ __volatile__ (
 		"sleep\n\t"
 		"synci\n\t"
@@ -113,9 +55,6 @@
 	panic("Unexpected wakeup!\n");
 }
 
-void (*pm_power_off)(void) = machine_power_off;
-EXPORT_SYMBOL(pm_power_off);
-
 void show_regs(struct pt_regs * regs)
 {
 	unsigned long long ah, al, bh, bl, ch, cl;
@@ -365,18 +304,6 @@
 	}
 }
 
-struct task_struct * alloc_task_struct(void)
-{
-	/* Get task descriptor pages */
-	return (struct task_struct *)
-		__get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE));
-}
-
-void free_task_struct(struct task_struct *p)
-{
-	free_pages((unsigned long) p, get_order(THREAD_SIZE));
-}
-
 /*
  * Create a kernel thread
  */
@@ -662,41 +589,3 @@
 #endif
 	return pc;
 }
-
-/* Provide a /proc/asids file that lists out the
-   ASIDs currently associated with the processes.  (If the DM.PC register is
-   examined through the debug link, this shows ASID + PC.  To make use of this,
-   the PID->ASID relationship needs to be known.  This is primarily for
-   debugging.)
-   */
-
-#if defined(CONFIG_SH64_PROC_ASIDS)
-static int
-asids_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, void *data)
-{
-	int len=0;
-	struct task_struct *p;
-	read_lock(&tasklist_lock);
-	for_each_process(p) {
-		int pid = p->pid;
-
-		if (!pid)
-			continue;
-		if (p->mm)
-			len += sprintf(buf+len, "%5d : %02lx\n", pid,
-				       asid_cache(smp_processor_id()));
-		else
-			len += sprintf(buf+len, "%5d : (none)\n", pid);
-	}
-	read_unlock(&tasklist_lock);
-	*eof = 1;
-	return len;
-}
-
-static int __init register_proc_asids(void)
-{
-	create_proc_read_entry("asids", 0, NULL, asids_proc_info, NULL);
-	return 0;
-}
-__initcall(register_proc_asids);
-#endif
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c
index e15b099..6950974 100644
--- a/arch/sh/kernel/ptrace_64.c
+++ b/arch/sh/kernel/ptrace_64.c
@@ -2,7 +2,7 @@
  * arch/sh/kernel/ptrace_64.c
  *
  * Copyright (C) 2000, 2001  Paolo Alberelli
- * Copyright (C) 2003 - 2007  Paul Mundt
+ * Copyright (C) 2003 - 2008  Paul Mundt
  *
  * Started from SH3/4 version:
  *   SuperH version:   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
@@ -29,6 +29,8 @@
 #include <linux/audit.h>
 #include <linux/seccomp.h>
 #include <linux/tracehook.h>
+#include <linux/elf.h>
+#include <linux/regset.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -137,6 +139,165 @@
 	regs->sr &= ~SR_SSTEP;
 }
 
+static int genregs_get(struct task_struct *target,
+		       const struct user_regset *regset,
+		       unsigned int pos, unsigned int count,
+		       void *kbuf, void __user *ubuf)
+{
+	const struct pt_regs *regs = task_pt_regs(target);
+	int ret;
+
+	/* PC, SR, SYSCALL */
+	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				  &regs->pc,
+				  0, 3 * sizeof(unsigned long long));
+
+	/* R1 -> R63 */
+	if (!ret)
+		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					  regs->regs,
+					  offsetof(struct pt_regs, regs[0]),
+					  63 * sizeof(unsigned long long));
+	/* TR0 -> TR7 */
+	if (!ret)
+		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+					  regs->tregs,
+					  offsetof(struct pt_regs, tregs[0]),
+					  8 * sizeof(unsigned long long));
+
+	if (!ret)
+		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+					       sizeof(struct pt_regs), -1);
+
+	return ret;
+}
+
+static int genregs_set(struct task_struct *target,
+		       const struct user_regset *regset,
+		       unsigned int pos, unsigned int count,
+		       const void *kbuf, const void __user *ubuf)
+{
+	struct pt_regs *regs = task_pt_regs(target);
+	int ret;
+
+	/* PC, SR, SYSCALL */
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				 &regs->pc,
+				 0, 3 * sizeof(unsigned long long));
+
+	/* R1 -> R63 */
+	if (!ret && count > 0)
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					 regs->regs,
+					 offsetof(struct pt_regs, regs[0]),
+					 63 * sizeof(unsigned long long));
+
+	/* TR0 -> TR7 */
+	if (!ret && count > 0)
+		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+					 regs->tregs,
+					 offsetof(struct pt_regs, tregs[0]),
+					 8 * sizeof(unsigned long long));
+
+	if (!ret)
+		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+						sizeof(struct pt_regs), -1);
+
+	return ret;
+}
+
+#ifdef CONFIG_SH_FPU
+int fpregs_get(struct task_struct *target,
+	       const struct user_regset *regset,
+	       unsigned int pos, unsigned int count,
+	       void *kbuf, void __user *ubuf)
+{
+	int ret;
+
+	ret = init_fpu(target);
+	if (ret)
+		return ret;
+
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				   &target->thread.fpu.hard, 0, -1);
+}
+
+static int fpregs_set(struct task_struct *target,
+		       const struct user_regset *regset,
+		       unsigned int pos, unsigned int count,
+		       const void *kbuf, const void __user *ubuf)
+{
+	int ret;
+
+	ret = init_fpu(target);
+	if (ret)
+		return ret;
+
+	set_stopped_child_used_math(target);
+
+	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				  &target->thread.fpu.hard, 0, -1);
+}
+
+static int fpregs_active(struct task_struct *target,
+			 const struct user_regset *regset)
+{
+	return tsk_used_math(target) ? regset->n : 0;
+}
+#endif
+
+/*
+ * These are our native regset flavours.
+ */
+enum sh_regset {
+	REGSET_GENERAL,
+#ifdef CONFIG_SH_FPU
+	REGSET_FPU,
+#endif
+};
+
+static const struct user_regset sh_regsets[] = {
+	/*
+	 * Format is:
+	 *	PC, SR, SYSCALL,
+	 *	R1 --> R63,
+	 *	TR0 --> TR7,
+	 */
+	[REGSET_GENERAL] = {
+		.core_note_type	= NT_PRSTATUS,
+		.n		= ELF_NGREG,
+		.size		= sizeof(long long),
+		.align		= sizeof(long long),
+		.get		= genregs_get,
+		.set		= genregs_set,
+	},
+
+#ifdef CONFIG_SH_FPU
+	[REGSET_FPU] = {
+		.core_note_type	= NT_PRFPREG,
+		.n		= sizeof(struct user_fpu_struct) /
+				  sizeof(long long),
+		.size		= sizeof(long long),
+		.align		= sizeof(long long),
+		.get		= fpregs_get,
+		.set		= fpregs_set,
+		.active		= fpregs_active,
+	},
+#endif
+};
+
+static const struct user_regset_view user_sh64_native_view = {
+	.name		= "sh64",
+	.e_machine	= EM_SH,
+	.regsets	= sh_regsets,
+	.n		= ARRAY_SIZE(sh_regsets),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+	return &user_sh64_native_view;
+}
+
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
 	int ret;
@@ -195,10 +356,33 @@
 		}
 		break;
 
+	case PTRACE_GETREGS:
+		return copy_regset_to_user(child, &user_sh64_native_view,
+					   REGSET_GENERAL,
+					   0, sizeof(struct pt_regs),
+					   (void __user *)data);
+	case PTRACE_SETREGS:
+		return copy_regset_from_user(child, &user_sh64_native_view,
+					     REGSET_GENERAL,
+					     0, sizeof(struct pt_regs),
+					     (const void __user *)data);
+#ifdef CONFIG_SH_FPU
+	case PTRACE_GETFPREGS:
+		return copy_regset_to_user(child, &user_sh64_native_view,
+					   REGSET_FPU,
+					   0, sizeof(struct user_fpu_struct),
+					   (void __user *)data);
+	case PTRACE_SETFPREGS:
+		return copy_regset_from_user(child, &user_sh64_native_view,
+					     REGSET_FPU,
+					     0, sizeof(struct user_fpu_struct),
+					     (const void __user *)data);
+#endif
 	default:
 		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
+
 	return ret;
 }
 
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index e7152cc..5342475 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -417,6 +417,7 @@
 }
 
 static const char *cpu_name[] = {
+	[CPU_SH7201]	= "SH7201",
 	[CPU_SH7203]	= "SH7203",	[CPU_SH7263]	= "SH7263",
 	[CPU_SH7206]	= "SH7206",	[CPU_SH7619]	= "SH7619",
 	[CPU_SH7705]	= "SH7705",	[CPU_SH7706]	= "SH7706",
diff --git a/arch/sh/kernel/sh_bios.c b/arch/sh/kernel/sh_bios.c
index d1bcac4..c852f78 100644
--- a/arch/sh/kernel/sh_bios.c
+++ b/arch/sh/kernel/sh_bios.c
@@ -8,69 +8,50 @@
 #include <linux/module.h>
 #include <asm/sh_bios.h>
 
-#define BIOS_CALL_CONSOLE_WRITE     	0
-#define BIOS_CALL_READ_BLOCK     	1
+#define BIOS_CALL_CONSOLE_WRITE		0
 #define BIOS_CALL_ETH_NODE_ADDR		10
 #define BIOS_CALL_SHUTDOWN		11
-#define BIOS_CALL_CHAR_OUT     	    	0x1f  	/* TODO: hack */
-#define BIOS_CALL_GDB_GET_MODE_PTR     	0xfe
-#define BIOS_CALL_GDB_DETACH     	0xff
+#define BIOS_CALL_CHAR_OUT		0x1f	/* TODO: hack */
+#define BIOS_CALL_GDB_DETACH		0xff
 
-static __inline__ long sh_bios_call(long func, long arg0, long arg1, long arg2, long arg3)
+static inline long sh_bios_call(long func, long arg0, long arg1, long arg2,
+				    long arg3)
 {
-    register long r0 __asm__("r0") = func;
-    register long r4 __asm__("r4") = arg0;
-    register long r5 __asm__("r5") = arg1;
-    register long r6 __asm__("r6") = arg2;
-    register long r7 __asm__("r7") = arg3;
-    __asm__ __volatile__("trapa	#0x3f"
-	 : "=z" (r0)
-	 : "0" (r0), "r" (r4), "r" (r5), "r" (r6), "r" (r7)
-	 : "memory");
-    return r0;
-}
+	register long r0 __asm__("r0") = func;
+	register long r4 __asm__("r4") = arg0;
+	register long r5 __asm__("r5") = arg1;
+	register long r6 __asm__("r6") = arg2;
+	register long r7 __asm__("r7") = arg3;
 
+	__asm__ __volatile__("trapa	#0x3f":"=z"(r0)
+			     :"0"(r0), "r"(r4), "r"(r5), "r"(r6), "r"(r7)
+			     :"memory");
+	return r0;
+}
 
 void sh_bios_console_write(const char *buf, unsigned int len)
 {
-    sh_bios_call(BIOS_CALL_CONSOLE_WRITE, (long)buf, (long)len, 0, 0);
+	sh_bios_call(BIOS_CALL_CONSOLE_WRITE, (long)buf, (long)len, 0, 0);
 }
 
-
 void sh_bios_char_out(char ch)
 {
-    sh_bios_call(BIOS_CALL_CHAR_OUT, ch, 0, 0, 0);
-}
-
-
-int sh_bios_in_gdb_mode(void)
-{
-    static char queried = 0;
-    static char *gdb_mode_p = 0;
-
-    if (!queried)
-    {
-    	/* Query the gdb stub for address of its gdb mode variable */
-    	long r = sh_bios_call(BIOS_CALL_GDB_GET_MODE_PTR, 0, 0, 0, 0);
-	if (r != ~0)	/* BIOS returns -1 for unknown function */
-	    gdb_mode_p = (char *)r;
-	queried = 1;
-    }
-    return (gdb_mode_p != 0 ? *gdb_mode_p : 0);
+	sh_bios_call(BIOS_CALL_CHAR_OUT, ch, 0, 0, 0);
 }
 
 void sh_bios_gdb_detach(void)
 {
-    sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0);
+	sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0);
 }
-EXPORT_SYMBOL(sh_bios_gdb_detach);
+EXPORT_SYMBOL_GPL(sh_bios_gdb_detach);
 
-void sh_bios_get_node_addr (unsigned char *node_addr)
+void sh_bios_get_node_addr(unsigned char *node_addr)
 {
-    sh_bios_call(BIOS_CALL_ETH_NODE_ADDR, 0, (long)node_addr, 0, 0);
+	sh_bios_call(BIOS_CALL_ETH_NODE_ADDR, 0, (long)node_addr, 0, 0);
 }
+EXPORT_SYMBOL_GPL(sh_bios_get_node_addr);
 
 void sh_bios_shutdown(unsigned int how)
 {
-    sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0);
+	sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0);
 }
diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c
index 92ae5e6..528de29 100644
--- a/arch/sh/kernel/sh_ksyms_32.c
+++ b/arch/sh/kernel/sh_ksyms_32.c
@@ -52,16 +52,12 @@
 
 #define DECLARE_EXPORT(name)		\
 	extern void name(void);EXPORT_SYMBOL(name)
-#define MAYBE_DECLARE_EXPORT(name)	\
-	extern void name(void) __weak;EXPORT_SYMBOL(name)
 
-/* These symbols are generated by the compiler itself */
 DECLARE_EXPORT(__udivsi3);
 DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__lshrsi3);
 DECLARE_EXPORT(__ashrsi3);
 DECLARE_EXPORT(__ashlsi3);
-DECLARE_EXPORT(__ashrdi3);
-DECLARE_EXPORT(__ashldi3);
 DECLARE_EXPORT(__ashiftrt_r4_6);
 DECLARE_EXPORT(__ashiftrt_r4_7);
 DECLARE_EXPORT(__ashiftrt_r4_8);
@@ -79,8 +75,7 @@
 DECLARE_EXPORT(__ashiftrt_r4_24);
 DECLARE_EXPORT(__ashiftrt_r4_27);
 DECLARE_EXPORT(__ashiftrt_r4_30);
-DECLARE_EXPORT(__lshrsi3);
-DECLARE_EXPORT(__lshrdi3);
+DECLARE_EXPORT(__movstr);
 DECLARE_EXPORT(__movstrSI8);
 DECLARE_EXPORT(__movstrSI12);
 DECLARE_EXPORT(__movstrSI16);
@@ -95,31 +90,17 @@
 DECLARE_EXPORT(__movstrSI52);
 DECLARE_EXPORT(__movstrSI56);
 DECLARE_EXPORT(__movstrSI60);
-#if __GNUC__ == 4
-DECLARE_EXPORT(__movmem);
-#else
-DECLARE_EXPORT(__movstr);
-#endif
-
-#if __GNUC__ == 4
-DECLARE_EXPORT(__movmem_i4_even);
-DECLARE_EXPORT(__movmem_i4_odd);
-DECLARE_EXPORT(__movmemSI12_i4);
-
-#if (__GNUC_MINOR__ >= 2 || defined(__GNUC_STM_RELEASE__))
-/*
- * GCC >= 4.2 emits these for division, as do GCC 4.1.x versions of the ST
- * compiler which include backported patches.
- */
-DECLARE_EXPORT(__udiv_qrnnd_16);
-MAYBE_DECLARE_EXPORT(__sdivsi3_i4i);
-MAYBE_DECLARE_EXPORT(__udivsi3_i4i);
-#endif
-#else /* GCC 3.x */
 DECLARE_EXPORT(__movstr_i4_even);
 DECLARE_EXPORT(__movstr_i4_odd);
 DECLARE_EXPORT(__movstrSI12_i4);
-#endif /* __GNUC__ == 4 */
+DECLARE_EXPORT(__movmem_i4_even);
+DECLARE_EXPORT(__movmem_i4_odd);
+DECLARE_EXPORT(__movmemSI12_i4);
+DECLARE_EXPORT(__udiv_qrnnd_16);
+DECLARE_EXPORT(__sdivsi3_i4);
+DECLARE_EXPORT(__udivsi3_i4);
+DECLARE_EXPORT(__sdivsi3_i4i);
+DECLARE_EXPORT(__udivsi3_i4i);
 
 #if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \
 	defined(CONFIG_SH7705_CACHE_32KB))
diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c
index 9324d32..0d74d6b 100644
--- a/arch/sh/kernel/sh_ksyms_64.c
+++ b/arch/sh/kernel/sh_ksyms_64.c
@@ -65,15 +65,16 @@
 EXPORT_SYMBOL(__copy_user);
 EXPORT_SYMBOL(empty_zero_page);
 EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(__const_udelay);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strcpy);
 
 /* Ugh.  These come in from libgcc.a at link time. */
 #define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
 
 DECLARE_EXPORT(__sdivsi3);
-DECLARE_EXPORT(__sdivsi3_2);
-DECLARE_EXPORT(__muldi3);
 DECLARE_EXPORT(__udivsi3);
 DECLARE_EXPORT(__div_table);
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index 69d09c0..77c21bd 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -533,7 +533,6 @@
 {
 	int ret;
 
-
 	/* Set up the stack frame */
 	if (ka->sa.sa_flags & SA_SIGINFO)
 		ret = setup_rt_frame(sig, ka, info, oldset, regs);
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index ce3e851..b22fdfa 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -2,7 +2,7 @@
  * arch/sh/kernel/signal_64.c
  *
  * Copyright (C) 2000, 2001  Paolo Alberelli
- * Copyright (C) 2003  Paul Mundt
+ * Copyright (C) 2003 - 2008  Paul Mundt
  * Copyright (C) 2004  Richard Curnow
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -43,10 +43,38 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-static void
+static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 		sigset_t *oldset, struct pt_regs * regs);
 
+static inline void
+handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa)
+{
+	/* If we're not from a syscall, bail out */
+	if (regs->syscall_nr < 0)
+		return;
+
+	/* check for system call restart.. */
+	switch (regs->regs[REG_RET]) {
+		case -ERESTART_RESTARTBLOCK:
+		case -ERESTARTNOHAND:
+		no_system_call_restart:
+			regs->regs[REG_RET] = -EINTR;
+			regs->sr |= 1;
+			break;
+
+		case -ERESTARTSYS:
+			if (!(sa->sa_flags & SA_RESTART))
+				goto no_system_call_restart;
+		/* fallthrough */
+		case -ERESTARTNOINTR:
+			/* Decode syscall # */
+			regs->regs[REG_RET] = regs->syscall_nr;
+			regs->pc -= 4;
+			break;
+	}
+}
+
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -80,21 +108,23 @@
 		oldset = &current->blocked;
 
 	signr = get_signal_to_deliver(&info, &ka, regs, 0);
-
 	if (signr > 0) {
+		if (regs->sr & 1)
+			handle_syscall_restart(regs, &ka.sa);
+
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, &info, &ka, oldset, regs);
+		if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
+			/*
+			 * If a signal was successfully delivered, the
+			 * saved sigmask is in its frame, and we can
+			 * clear the TIF_RESTORE_SIGMASK flag.
+			 */
+			if (test_thread_flag(TIF_RESTORE_SIGMASK))
+				clear_thread_flag(TIF_RESTORE_SIGMASK);
 
-		/*
-		 * If a signal was successfully delivered, the saved sigmask
-		 * is in its frame, and we can clear the TIF_RESTORE_SIGMASK
-		 * flag.
-		 */
-		if (test_thread_flag(TIF_RESTORE_SIGMASK))
-			clear_thread_flag(TIF_RESTORE_SIGMASK);
-
-		tracehook_signal_handler(signr, &info, &ka, regs, 0);
-		return 1;
+			tracehook_signal_handler(signr, &info, &ka, regs, 0);
+			return 1;
+		}
 	}
 
 no_signal:
@@ -129,7 +159,6 @@
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
-
 asmlinkage int
 sys_sigsuspend(old_sigset_t mask,
 	       unsigned long r3, unsigned long r4, unsigned long r5,
@@ -235,20 +264,16 @@
 	return do_sigaltstack(uss, uoss, REF_REG_SP);
 }
 
-
 /*
  * Do a signal return; undo the signal stack.
  */
-
-struct sigframe
-{
+struct sigframe {
 	struct sigcontext sc;
 	unsigned long extramask[_NSIG_WORDS-1];
 	long long retcode[2];
 };
 
-struct rt_sigframe
-{
+struct rt_sigframe {
 	struct siginfo __user *pinfo;
 	void *puc;
 	struct siginfo info;
@@ -450,7 +475,6 @@
 /*
  * Set up a signal frame.
  */
-
 static int
 setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
 		 unsigned long mask)
@@ -504,8 +528,8 @@
 void sa_default_restorer(void);		/* See comments below */
 void sa_default_rt_restorer(void);	/* See comments below */
 
-static void setup_frame(int sig, struct k_sigaction *ka,
-			sigset_t *set, struct pt_regs *regs)
+static int setup_frame(int sig, struct k_sigaction *ka,
+		       sigset_t *set, struct pt_regs *regs)
 {
 	struct sigframe __user *frame;
 	int err = 0;
@@ -596,23 +620,21 @@
 
 	set_fs(USER_DS);
 
-#if DEBUG_SIG
 	/* Broken %016Lx */
-	printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
-		signal,
-		current->comm, current->pid, frame,
-		regs->pc >> 32, regs->pc & 0xffffffff,
-		DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
-#endif
+	pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
+		 signal, current->comm, current->pid, frame,
+		 regs->pc >> 32, regs->pc & 0xffffffff,
+		 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
 
-	return;
+	return 0;
 
 give_sigsegv:
 	force_sigsegv(sig, current);
+	return -EFAULT;
 }
 
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-			   sigset_t *set, struct pt_regs *regs)
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			  sigset_t *set, struct pt_regs *regs)
 {
 	struct rt_sigframe __user *frame;
 	int err = 0;
@@ -702,62 +724,46 @@
 
 	set_fs(USER_DS);
 
-#if DEBUG_SIG
-	/* Broken %016Lx */
-	printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
-		signal,
-		current->comm, current->pid, frame,
-		regs->pc >> 32, regs->pc & 0xffffffff,
-		DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
-#endif
+	pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
+		 signal, current->comm, current->pid, frame,
+		 regs->pc >> 32, regs->pc & 0xffffffff,
+		 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
 
-	return;
+	return 0;
 
 give_sigsegv:
 	force_sigsegv(sig, current);
+	return -EFAULT;
 }
 
 /*
  * OK, we're invoking a handler
  */
-
-static void
+static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 		sigset_t *oldset, struct pt_regs * regs)
 {
-	/* Are we from a system call? */
-	if (regs->syscall_nr >= 0) {
-		/* If so, check system call restarting.. */
-		switch (regs->regs[REG_RET]) {
-			case -ERESTART_RESTARTBLOCK:
-			case -ERESTARTNOHAND:
-			no_system_call_restart:
-				regs->regs[REG_RET] = -EINTR;
-				break;
-
-			case -ERESTARTSYS:
-				if (!(ka->sa.sa_flags & SA_RESTART))
-					goto no_system_call_restart;
-			/* fallthrough */
-			case -ERESTARTNOINTR:
-				/* Decode syscall # */
-				regs->regs[REG_RET] = regs->syscall_nr;
-				regs->pc -= 4;
-		}
-	}
+	int ret;
 
 	/* Set up the stack frame */
 	if (ka->sa.sa_flags & SA_SIGINFO)
-		setup_rt_frame(sig, ka, info, oldset, regs);
+		ret = setup_rt_frame(sig, ka, info, oldset, regs);
 	else
-		setup_frame(sig, ka, oldset, regs);
+		ret = setup_frame(sig, ka, oldset, regs);
 
-	spin_lock_irq(&current->sighand->siglock);
-	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked,sig);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+
+	if (ret == 0) {
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		if (!(ka->sa.sa_flags & SA_NODEFER))
+			sigaddset(&current->blocked,sig);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+
+	return ret;
 }
 
 asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
index 38f098c..58dfc02 100644
--- a/arch/sh/kernel/sys_sh.c
+++ b/arch/sh/kernel/sys_sh.c
@@ -22,102 +22,10 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/ipc.h>
-#include <asm/cacheflush.h>
 #include <asm/syscalls.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 
-unsigned long shm_align_mask = PAGE_SIZE - 1;	/* Sane caches */
-EXPORT_SYMBOL(shm_align_mask);
-
-#ifdef CONFIG_MMU
-/*
- * To avoid cache aliases, we map the shared page with same color.
- */
-#define COLOUR_ALIGN(addr, pgoff)				\
-	((((addr) + shm_align_mask) & ~shm_align_mask) +	\
-	 (((pgoff) << PAGE_SHIFT) & shm_align_mask))
-
-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
-	unsigned long len, unsigned long pgoff, unsigned long flags)
-{
-	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma;
-	unsigned long start_addr;
-	int do_colour_align;
-
-	if (flags & MAP_FIXED) {
-		/* We do not accept a shared mapping if it would violate
-		 * cache aliasing constraints.
-		 */
-		if ((flags & MAP_SHARED) && (addr & shm_align_mask))
-			return -EINVAL;
-		return addr;
-	}
-
-	if (unlikely(len > TASK_SIZE))
-		return -ENOMEM;
-
-	do_colour_align = 0;
-	if (filp || (flags & MAP_SHARED))
-		do_colour_align = 1;
-
-	if (addr) {
-		if (do_colour_align)
-			addr = COLOUR_ALIGN(addr, pgoff);
-		else
-			addr = PAGE_ALIGN(addr);
-
-		vma = find_vma(mm, addr);
-		if (TASK_SIZE - len >= addr &&
-		    (!vma || addr + len <= vma->vm_start))
-			return addr;
-	}
-
-	if (len > mm->cached_hole_size) {
-		start_addr = addr = mm->free_area_cache;
-	} else {
-	        mm->cached_hole_size = 0;
-		start_addr = addr = TASK_UNMAPPED_BASE;
-	}
-
-full_search:
-	if (do_colour_align)
-		addr = COLOUR_ALIGN(addr, pgoff);
-	else
-		addr = PAGE_ALIGN(mm->free_area_cache);
-
-	for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
-		/* At this point:  (!vma || addr < vma->vm_end). */
-		if (unlikely(TASK_SIZE - len < addr)) {
-			/*
-			 * Start a new search - just in case we missed
-			 * some holes.
-			 */
-			if (start_addr != TASK_UNMAPPED_BASE) {
-				start_addr = addr = TASK_UNMAPPED_BASE;
-				mm->cached_hole_size = 0;
-				goto full_search;
-			}
-			return -ENOMEM;
-		}
-		if (likely(!vma || addr + len <= vma->vm_start)) {
-			/*
-			 * Remember the place where we stopped the search:
-			 */
-			mm->free_area_cache = addr + len;
-			return addr;
-		}
-		if (addr + mm->cached_hole_size < vma->vm_start)
-		        mm->cached_hole_size = vma->vm_start - addr;
-
-		addr = vma->vm_end;
-		if (do_colour_align)
-			addr = COLOUR_ALIGN(addr, pgoff);
-	}
-}
-#endif /* CONFIG_MMU */
-
 static inline long
 do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
 	 unsigned long flags, int fd, unsigned long pgoff)
diff --git a/arch/sh/kernel/time_32.c b/arch/sh/kernel/time_32.c
index 23ca711..8457f83 100644
--- a/arch/sh/kernel/time_32.c
+++ b/arch/sh/kernel/time_32.c
@@ -125,11 +125,6 @@
 	if (current->pid)
 		profile_tick(CPU_PROFILING);
 
-#ifdef CONFIG_HEARTBEAT
-	if (sh_mv.mv_heartbeat != NULL)
-		sh_mv.mv_heartbeat();
-#endif
-
 	/*
 	 * Here we are in the timer irq handler. We just have irqs locally
 	 * disabled but we don't know if the timer_bh is running on the other
@@ -277,11 +272,4 @@
 		       ((sh_hpt_frequency + 500) / 1000) / 1000,
 		       ((sh_hpt_frequency + 500) / 1000) % 1000);
 
-#if defined(CONFIG_SH_KGDB)
-	/*
-	 * Set up kgdb as requested. We do it here because the serial
-	 * init uses the timer vars we just set up for figuring baud.
-	 */
-	kgdb_init();
-#endif
 }
diff --git a/arch/sh/kernel/time_64.c b/arch/sh/kernel/time_64.c
index bbb2af1..59d2a03 100644
--- a/arch/sh/kernel/time_64.c
+++ b/arch/sh/kernel/time_64.c
@@ -240,11 +240,6 @@
 
 	do_timer(1);
 
-#ifdef CONFIG_HEARTBEAT
-	if (sh_mv.mv_heartbeat != NULL)
-		sh_mv.mv_heartbeat();
-#endif
-
 	/*
 	 * If we have an externally synchronized Linux clock, then update
 	 * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c
index fe453c0..c3d237e 100644
--- a/arch/sh/kernel/timers/timer-mtu2.c
+++ b/arch/sh/kernel/timers/timer-mtu2.c
@@ -34,7 +34,12 @@
 #define MTU2_TIER_1	0xfffe4384
 #define MTU2_TSR_1	0xfffe4385
 #define MTU2_TCNT_1	0xfffe4386	/* 16-bit counter */
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7201)
+#define MTU2_TGRA_1	0xfffe4388
+#else
 #define MTU2_TGRA_1	0xfffe438a
+#endif
 
 #define STBCR3		0xfffe0408
 
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 1e5c74e..88807a2 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -28,17 +28,6 @@
 #include <asm/fpu.h>
 #include <asm/kprobes.h>
 
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-#define CHK_REMOTE_DEBUG(regs)			\
-{						\
-	if (kgdb_debug_hook && !user_mode(regs))\
-		(*kgdb_debug_hook)(regs);       \
-}
-#else
-#define CHK_REMOTE_DEBUG(regs)
-#endif
-
 #ifdef CONFIG_CPU_SH2
 # define TRAP_RESERVED_INST	4
 # define TRAP_ILLEGAL_SLOT_INST	6
@@ -94,7 +83,6 @@
 
 	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
 
-	CHK_REMOTE_DEBUG(regs);
 	print_modules();
 	show_regs(regs);
 
@@ -683,13 +671,12 @@
 	error_code = lookup_exception_vector();
 
 	local_irq_enable();
-	CHK_REMOTE_DEBUG(regs);
 	force_sig(SIGILL, tsk);
 	die_if_no_fixup("reserved instruction", regs, error_code);
 }
 
 #ifdef CONFIG_SH_FPU_EMU
-static int emulate_branch(unsigned short inst, struct pt_regs* regs)
+static int emulate_branch(unsigned short inst, struct pt_regs *regs)
 {
 	/*
 	 * bfs: 8fxx: PC+=d*2+4;
@@ -702,27 +689,32 @@
 	 * jsr: 4x0b: PC=Rn      after PR=PC+4;
 	 * rts: 000b: PC=PR;
 	 */
-	if ((inst & 0xfd00) == 0x8d00) {
+	if (((inst & 0xf000) == 0xb000)  ||	/* bsr */
+	    ((inst & 0xf0ff) == 0x0003)  ||	/* bsrf */
+	    ((inst & 0xf0ff) == 0x400b))	/* jsr */
+		regs->pr = regs->pc + 4;
+
+	if ((inst & 0xfd00) == 0x8d00) {	/* bfs, bts */
 		regs->pc += SH_PC_8BIT_OFFSET(inst);
 		return 0;
 	}
 
-	if ((inst & 0xe000) == 0xa000) {
+	if ((inst & 0xe000) == 0xa000) {	/* bra, bsr */
 		regs->pc += SH_PC_12BIT_OFFSET(inst);
 		return 0;
 	}
 
-	if ((inst & 0xf0df) == 0x0003) {
+	if ((inst & 0xf0df) == 0x0003) {	/* braf, bsrf */
 		regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
 		return 0;
 	}
 
-	if ((inst & 0xf0df) == 0x400b) {
+	if ((inst & 0xf0df) == 0x400b) {	/* jmp, jsr */
 		regs->pc = regs->regs[(inst & 0x0f00) >> 8];
 		return 0;
 	}
 
-	if ((inst & 0xffff) == 0x000b) {
+	if ((inst & 0xffff) == 0x000b) {	/* rts */
 		regs->pc = regs->pr;
 		return 0;
 	}
@@ -756,7 +748,6 @@
 	inst = lookup_exception_vector();
 
 	local_irq_enable();
-	CHK_REMOTE_DEBUG(regs);
 	force_sig(SIGILL, tsk);
 	die_if_no_fixup("illegal slot instruction", regs, inst);
 }
@@ -868,10 +859,7 @@
 	if (regs && user_mode(regs))
 		return;
 
-	printk("\nCall trace: ");
-#ifdef CONFIG_KALLSYMS
-	printk("\n");
-#endif
+	printk("\nCall trace:\n");
 
 	while (!kstack_end(sp)) {
 		addr = *sp++;
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c
index 95f4de0..3f7e415 100644
--- a/arch/sh/kernel/vsyscall/vsyscall.c
+++ b/arch/sh/kernel/vsyscall/vsyscall.c
@@ -59,8 +59,7 @@
 }
 
 /* Setup a VMA at program startup for the vsyscall page */
-int arch_setup_additional_pages(struct linux_binprm *bprm,
-				int executable_stack)
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long addr;
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
index 8596cc7..aaea580 100644
--- a/arch/sh/lib/Makefile
+++ b/arch/sh/lib/Makefile
@@ -5,12 +5,26 @@
 lib-y  = delay.o memset.o memmove.o memchr.o \
 	 checksum.o strlen.o div64.o div64-generic.o
 
+# Extracted from libgcc
+lib-y += movmem.o ashldi3.o ashrdi3.o lshrdi3.o \
+	 ashlsi3.o ashrsi3.o ashiftrt.o lshrsi3.o \
+	 udiv_qrnnd.o
+
+udivsi3-y			:= udivsi3_i4i-Os.o
+
+ifneq ($(CONFIG_CC_OPTIMIZE_FOR_SIZE),y)
+udivsi3-$(CONFIG_CPU_SH3)	:= udivsi3_i4i.o
+udivsi3-$(CONFIG_CPU_SH4)	:= udivsi3_i4i.o
+endif
+udivsi3-y			+= udivsi3.o
+
 obj-y				+= io.o
 
 memcpy-y			:= memcpy.o
 memcpy-$(CONFIG_CPU_SH4)	:= memcpy-sh4.o
 
 lib-$(CONFIG_MMU)		+= copy_page.o clear_page.o
-lib-y				+= $(memcpy-y)
+lib-$(CONFIG_FUNCTION_TRACER)	+= mcount.o
+lib-y				+= $(memcpy-y) $(udivsi3-y)
 
 EXTRA_CFLAGS += -Werror
diff --git a/arch/sh/lib/ashiftrt.S b/arch/sh/lib/ashiftrt.S
new file mode 100644
index 0000000..45ce865
--- /dev/null
+++ b/arch/sh/lib/ashiftrt.S
@@ -0,0 +1,149 @@
+/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+This file is free software; you can redistribute 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+!! libgcc routines for the Renesas / SuperH SH CPUs.
+!! Contributed by Steve Chamberlain.
+!! sac@cygnus.com
+
+!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines
+!! recoded in assembly by Toshiyasu Morita
+!! tm@netcom.com
+
+/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and
+   ELF local label prefixes by J"orn Rennecke
+   amylaar@cygnus.com  */
+
+	.global	__ashiftrt_r4_0
+	.global	__ashiftrt_r4_1
+	.global	__ashiftrt_r4_2
+	.global	__ashiftrt_r4_3
+	.global	__ashiftrt_r4_4
+	.global	__ashiftrt_r4_5
+	.global	__ashiftrt_r4_6
+	.global	__ashiftrt_r4_7
+	.global	__ashiftrt_r4_8
+	.global	__ashiftrt_r4_9
+	.global	__ashiftrt_r4_10
+	.global	__ashiftrt_r4_11
+	.global	__ashiftrt_r4_12
+	.global	__ashiftrt_r4_13
+	.global	__ashiftrt_r4_14
+	.global	__ashiftrt_r4_15
+	.global	__ashiftrt_r4_16
+	.global	__ashiftrt_r4_17
+	.global	__ashiftrt_r4_18
+	.global	__ashiftrt_r4_19
+	.global	__ashiftrt_r4_20
+	.global	__ashiftrt_r4_21
+	.global	__ashiftrt_r4_22
+	.global	__ashiftrt_r4_23
+	.global	__ashiftrt_r4_24
+	.global	__ashiftrt_r4_25
+	.global	__ashiftrt_r4_26
+	.global	__ashiftrt_r4_27
+	.global	__ashiftrt_r4_28
+	.global	__ashiftrt_r4_29
+	.global	__ashiftrt_r4_30
+	.global	__ashiftrt_r4_31
+	.global	__ashiftrt_r4_32
+
+	.align	1
+__ashiftrt_r4_32:
+__ashiftrt_r4_31:
+	rotcl	r4
+	rts
+	subc	r4,r4
+__ashiftrt_r4_30:
+	shar	r4
+__ashiftrt_r4_29:
+	shar	r4
+__ashiftrt_r4_28:
+	shar	r4
+__ashiftrt_r4_27:
+	shar	r4
+__ashiftrt_r4_26:
+	shar	r4
+__ashiftrt_r4_25:
+	shar	r4
+__ashiftrt_r4_24:
+	shlr16	r4
+	shlr8	r4
+	rts
+	exts.b	r4,r4
+__ashiftrt_r4_23:
+	shar	r4
+__ashiftrt_r4_22:
+	shar	r4
+__ashiftrt_r4_21:
+	shar	r4
+__ashiftrt_r4_20:
+	shar	r4
+__ashiftrt_r4_19:
+	shar	r4
+__ashiftrt_r4_18:
+	shar	r4
+__ashiftrt_r4_17:
+	shar	r4
+__ashiftrt_r4_16:
+	shlr16	r4
+	rts
+	exts.w	r4,r4
+__ashiftrt_r4_15:
+	shar	r4
+__ashiftrt_r4_14:
+	shar	r4
+__ashiftrt_r4_13:
+	shar	r4
+__ashiftrt_r4_12:
+	shar	r4
+__ashiftrt_r4_11:
+	shar	r4
+__ashiftrt_r4_10:
+	shar	r4
+__ashiftrt_r4_9:
+	shar	r4
+__ashiftrt_r4_8:
+	shar	r4
+__ashiftrt_r4_7:
+	shar	r4
+__ashiftrt_r4_6:
+	shar	r4
+__ashiftrt_r4_5:
+	shar	r4
+__ashiftrt_r4_4:
+	shar	r4
+__ashiftrt_r4_3:
+	shar	r4
+__ashiftrt_r4_2:
+	shar	r4
+__ashiftrt_r4_1:
+	rts
+	shar	r4
+__ashiftrt_r4_0:
+	rts
+	nop
diff --git a/arch/sh/lib/ashldi3.c b/arch/sh/lib/ashldi3.c
new file mode 100644
index 0000000..beb80f31
--- /dev/null
+++ b/arch/sh/lib/ashldi3.c
@@ -0,0 +1,29 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __ashldi3(long long u, word_type b)
+{
+	DWunion uu, w;
+	word_type bm;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+	bm = 32 - b;
+
+	if (bm <= 0) {
+		w.s.low = 0;
+		w.s.high = (unsigned int) uu.s.low << -bm;
+	} else {
+		const unsigned int carries = (unsigned int) uu.s.low >> bm;
+
+		w.s.low = (unsigned int) uu.s.low << b;
+		w.s.high = ((unsigned int) uu.s.high << b) | carries;
+	}
+
+	return w.ll;
+}
+
+EXPORT_SYMBOL(__ashldi3);
diff --git a/arch/sh/lib/ashlsi3.S b/arch/sh/lib/ashlsi3.S
new file mode 100644
index 0000000..bd47e9b
--- /dev/null
+++ b/arch/sh/lib/ashlsi3.S
@@ -0,0 +1,193 @@
+/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+This file is free software; you can redistribute 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+!! libgcc routines for the Renesas / SuperH SH CPUs.
+!! Contributed by Steve Chamberlain.
+!! sac@cygnus.com
+
+!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines
+!! recoded in assembly by Toshiyasu Morita
+!! tm@netcom.com
+
+/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and
+   ELF local label prefixes by J"orn Rennecke
+   amylaar@cygnus.com  */
+
+!
+! __ashlsi3
+!
+! Entry:
+!
+! r4: Value to shift
+! r5: Shifts
+!
+! Exit:
+!
+! r0: Result
+!
+! Destroys:
+!
+! (none)
+!
+	.global	__ashlsi3
+	
+	.align	2
+__ashlsi3:
+	mov	#31,r0
+	and	r0,r5
+	mova	ashlsi3_table,r0
+	mov.b	@(r0,r5),r5
+#ifdef __sh1__
+	add	r5,r0
+	jmp	@r0
+#else
+	braf	r5
+#endif
+	mov	r4,r0
+
+	.align	2
+ashlsi3_table:
+	.byte		ashlsi3_0-ashlsi3_table
+	.byte		ashlsi3_1-ashlsi3_table
+	.byte		ashlsi3_2-ashlsi3_table
+	.byte		ashlsi3_3-ashlsi3_table
+	.byte		ashlsi3_4-ashlsi3_table
+	.byte		ashlsi3_5-ashlsi3_table
+	.byte		ashlsi3_6-ashlsi3_table
+	.byte		ashlsi3_7-ashlsi3_table
+	.byte		ashlsi3_8-ashlsi3_table
+	.byte		ashlsi3_9-ashlsi3_table
+	.byte		ashlsi3_10-ashlsi3_table
+	.byte		ashlsi3_11-ashlsi3_table
+	.byte		ashlsi3_12-ashlsi3_table
+	.byte		ashlsi3_13-ashlsi3_table
+	.byte		ashlsi3_14-ashlsi3_table
+	.byte		ashlsi3_15-ashlsi3_table
+	.byte		ashlsi3_16-ashlsi3_table
+	.byte		ashlsi3_17-ashlsi3_table
+	.byte		ashlsi3_18-ashlsi3_table
+	.byte		ashlsi3_19-ashlsi3_table
+	.byte		ashlsi3_20-ashlsi3_table
+	.byte		ashlsi3_21-ashlsi3_table
+	.byte		ashlsi3_22-ashlsi3_table
+	.byte		ashlsi3_23-ashlsi3_table
+	.byte		ashlsi3_24-ashlsi3_table
+	.byte		ashlsi3_25-ashlsi3_table
+	.byte		ashlsi3_26-ashlsi3_table
+	.byte		ashlsi3_27-ashlsi3_table
+	.byte		ashlsi3_28-ashlsi3_table
+	.byte		ashlsi3_29-ashlsi3_table
+	.byte		ashlsi3_30-ashlsi3_table
+	.byte		ashlsi3_31-ashlsi3_table
+
+ashlsi3_6:
+	shll2	r0
+ashlsi3_4:
+	shll2	r0
+ashlsi3_2:
+	rts
+	shll2	r0
+
+ashlsi3_7:
+	shll2	r0
+ashlsi3_5:
+	shll2	r0
+ashlsi3_3:
+	shll2	r0
+ashlsi3_1:
+	rts
+	shll	r0
+
+ashlsi3_14:
+	shll2	r0
+ashlsi3_12:
+	shll2	r0
+ashlsi3_10:
+	shll2	r0
+ashlsi3_8:
+	rts
+	shll8	r0
+
+ashlsi3_15:
+	shll2	r0
+ashlsi3_13:
+	shll2	r0
+ashlsi3_11:
+	shll2	r0
+ashlsi3_9:
+	shll8	r0
+	rts
+	shll	r0
+
+ashlsi3_22:
+	shll2	r0
+ashlsi3_20:
+	shll2	r0
+ashlsi3_18:
+	shll2	r0
+ashlsi3_16:
+	rts
+	shll16	r0
+
+ashlsi3_23:
+	shll2	r0
+ashlsi3_21:
+	shll2	r0
+ashlsi3_19:
+	shll2	r0
+ashlsi3_17:
+	shll16	r0
+	rts
+	shll	r0
+
+ashlsi3_30:
+	shll2	r0
+ashlsi3_28:
+	shll2	r0
+ashlsi3_26:
+	shll2	r0
+ashlsi3_24:
+	shll16	r0
+	rts
+	shll8	r0
+
+ashlsi3_31:
+	shll2	r0
+ashlsi3_29:
+	shll2	r0
+ashlsi3_27:
+	shll2	r0
+ashlsi3_25:
+	shll16	r0
+	shll8	r0
+	rts
+	shll	r0
+
+ashlsi3_0:
+	rts
+	nop
diff --git a/arch/sh/lib/ashrdi3.c b/arch/sh/lib/ashrdi3.c
new file mode 100644
index 0000000..c884a91
--- /dev/null
+++ b/arch/sh/lib/ashrdi3.c
@@ -0,0 +1,31 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __ashrdi3(long long u, word_type b)
+{
+	DWunion uu, w;
+	word_type bm;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+	bm = 32 - b;
+
+	if (bm <= 0) {
+		/* w.s.high = 1..1 or 0..0 */
+		w.s.high =
+		    uu.s.high >> 31;
+		w.s.low = uu.s.high >> -bm;
+	} else {
+		const unsigned int carries = (unsigned int) uu.s.high << bm;
+
+		w.s.high = uu.s.high >> b;
+		w.s.low = ((unsigned int) uu.s.low >> b) | carries;
+	}
+
+	return w.ll;
+}
+
+EXPORT_SYMBOL(__ashrdi3);
diff --git a/arch/sh/lib/ashrsi3.S b/arch/sh/lib/ashrsi3.S
new file mode 100644
index 0000000..6f3cf46
--- /dev/null
+++ b/arch/sh/lib/ashrsi3.S
@@ -0,0 +1,185 @@
+/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+This file is free software; you can redistribute 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+!! libgcc routines for the Renesas / SuperH SH CPUs.
+!! Contributed by Steve Chamberlain.
+!! sac@cygnus.com
+
+!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines
+!! recoded in assembly by Toshiyasu Morita
+!! tm@netcom.com
+
+/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and
+   ELF local label prefixes by J"orn Rennecke
+   amylaar@cygnus.com  */
+
+!
+! __ashrsi3
+!
+! Entry:
+!
+! r4: Value to shift
+! r5: Shifts
+!
+! Exit:
+!
+! r0: Result
+!
+! Destroys:
+!
+! (none)
+!
+
+	.global	__ashrsi3
+	
+	.align	2
+__ashrsi3:
+	mov	#31,r0
+	and	r0,r5
+	mova	ashrsi3_table,r0
+	mov.b	@(r0,r5),r5
+#ifdef __sh1__
+	add	r5,r0
+	jmp	@r0
+#else
+	braf	r5
+#endif
+	mov	r4,r0
+
+	.align	2
+ashrsi3_table:
+	.byte		ashrsi3_0-ashrsi3_table
+	.byte		ashrsi3_1-ashrsi3_table
+	.byte		ashrsi3_2-ashrsi3_table
+	.byte		ashrsi3_3-ashrsi3_table
+	.byte		ashrsi3_4-ashrsi3_table
+	.byte		ashrsi3_5-ashrsi3_table
+	.byte		ashrsi3_6-ashrsi3_table
+	.byte		ashrsi3_7-ashrsi3_table
+	.byte		ashrsi3_8-ashrsi3_table
+	.byte		ashrsi3_9-ashrsi3_table
+	.byte		ashrsi3_10-ashrsi3_table
+	.byte		ashrsi3_11-ashrsi3_table
+	.byte		ashrsi3_12-ashrsi3_table
+	.byte		ashrsi3_13-ashrsi3_table
+	.byte		ashrsi3_14-ashrsi3_table
+	.byte		ashrsi3_15-ashrsi3_table
+	.byte		ashrsi3_16-ashrsi3_table
+	.byte		ashrsi3_17-ashrsi3_table
+	.byte		ashrsi3_18-ashrsi3_table
+	.byte		ashrsi3_19-ashrsi3_table
+	.byte		ashrsi3_20-ashrsi3_table
+	.byte		ashrsi3_21-ashrsi3_table
+	.byte		ashrsi3_22-ashrsi3_table
+	.byte		ashrsi3_23-ashrsi3_table
+	.byte		ashrsi3_24-ashrsi3_table
+	.byte		ashrsi3_25-ashrsi3_table
+	.byte		ashrsi3_26-ashrsi3_table
+	.byte		ashrsi3_27-ashrsi3_table
+	.byte		ashrsi3_28-ashrsi3_table
+	.byte		ashrsi3_29-ashrsi3_table
+	.byte		ashrsi3_30-ashrsi3_table
+	.byte		ashrsi3_31-ashrsi3_table
+
+ashrsi3_31:
+	rotcl	r0
+	rts
+	subc	r0,r0
+
+ashrsi3_30:
+	shar	r0
+ashrsi3_29:
+	shar	r0
+ashrsi3_28:
+	shar	r0
+ashrsi3_27:
+	shar	r0
+ashrsi3_26:
+	shar	r0
+ashrsi3_25:
+	shar	r0
+ashrsi3_24:
+	shlr16	r0
+	shlr8	r0
+	rts
+	exts.b	r0,r0
+
+ashrsi3_23:
+	shar	r0
+ashrsi3_22:
+	shar	r0
+ashrsi3_21:
+	shar	r0
+ashrsi3_20:
+	shar	r0
+ashrsi3_19:
+	shar	r0
+ashrsi3_18:
+	shar	r0
+ashrsi3_17:
+	shar	r0
+ashrsi3_16:
+	shlr16	r0
+	rts
+	exts.w	r0,r0
+
+ashrsi3_15:
+	shar	r0
+ashrsi3_14:
+	shar	r0
+ashrsi3_13:
+	shar	r0
+ashrsi3_12:
+	shar	r0
+ashrsi3_11:
+	shar	r0
+ashrsi3_10:
+	shar	r0
+ashrsi3_9:
+	shar	r0
+ashrsi3_8:
+	shar	r0
+ashrsi3_7:
+	shar	r0
+ashrsi3_6:
+	shar	r0
+ashrsi3_5:
+	shar	r0
+ashrsi3_4:
+	shar	r0
+ashrsi3_3:
+	shar	r0
+ashrsi3_2:
+	shar	r0
+ashrsi3_1:
+	rts
+	shar	r0
+
+ashrsi3_0:
+	rts
+	nop
diff --git a/arch/sh/lib/libgcc.h b/arch/sh/lib/libgcc.h
new file mode 100644
index 0000000..3f19d1c
--- /dev/null
+++ b/arch/sh/lib/libgcc.h
@@ -0,0 +1,26 @@
+#ifndef __ASM_LIBGCC_H
+#define __ASM_LIBGCC_H
+
+#include <asm/byteorder.h>
+
+typedef int word_type __attribute__ ((mode (__word__)));
+
+#ifdef __BIG_ENDIAN
+struct DWstruct {
+	int high, low;
+};
+#elif defined(__LITTLE_ENDIAN)
+struct DWstruct {
+	int low, high;
+};
+#else
+#error I feel sick.
+#endif
+
+typedef union
+{
+	struct DWstruct s;
+	long long ll;
+} DWunion;
+
+#endif /* __ASM_LIBGCC_H */
diff --git a/arch/sh/lib/lshrdi3.c b/arch/sh/lib/lshrdi3.c
new file mode 100644
index 0000000..dcf8d68
--- /dev/null
+++ b/arch/sh/lib/lshrdi3.c
@@ -0,0 +1,29 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __lshrdi3(long long u, word_type b)
+{
+	DWunion uu, w;
+	word_type bm;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+	bm = 32 - b;
+
+	if (bm <= 0) {
+		w.s.high = 0;
+		w.s.low = (unsigned int) uu.s.high >> -bm;
+	} else {
+		const unsigned int carries = (unsigned int) uu.s.high << bm;
+
+		w.s.high = (unsigned int) uu.s.high >> b;
+		w.s.low = ((unsigned int) uu.s.low >> b) | carries;
+	}
+
+	return w.ll;
+}
+
+EXPORT_SYMBOL(__lshrdi3);
diff --git a/arch/sh/lib/lshrsi3.S b/arch/sh/lib/lshrsi3.S
new file mode 100644
index 0000000..1e7aaa5
--- /dev/null
+++ b/arch/sh/lib/lshrsi3.S
@@ -0,0 +1,193 @@
+/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+This file is free software; you can redistribute 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+!! libgcc routines for the Renesas / SuperH SH CPUs.
+!! Contributed by Steve Chamberlain.
+!! sac@cygnus.com
+
+!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines
+!! recoded in assembly by Toshiyasu Morita
+!! tm@netcom.com
+
+/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and
+   ELF local label prefixes by J"orn Rennecke
+   amylaar@cygnus.com  */
+
+!
+! __lshrsi3
+!
+! Entry:
+!
+! r4: Value to shift
+! r5: Shifts
+!
+! Exit:
+!
+! r0: Result
+!
+! Destroys:
+!
+! (none)
+!
+	.global	__lshrsi3
+	
+	.align	2
+__lshrsi3:
+	mov	#31,r0
+	and	r0,r5
+	mova	lshrsi3_table,r0
+	mov.b	@(r0,r5),r5
+#ifdef __sh1__
+	add	r5,r0
+	jmp	@r0
+#else
+	braf	r5
+#endif
+	mov	r4,r0
+
+	.align	2
+lshrsi3_table:
+	.byte		lshrsi3_0-lshrsi3_table
+	.byte		lshrsi3_1-lshrsi3_table
+	.byte		lshrsi3_2-lshrsi3_table
+	.byte		lshrsi3_3-lshrsi3_table
+	.byte		lshrsi3_4-lshrsi3_table
+	.byte		lshrsi3_5-lshrsi3_table
+	.byte		lshrsi3_6-lshrsi3_table
+	.byte		lshrsi3_7-lshrsi3_table
+	.byte		lshrsi3_8-lshrsi3_table
+	.byte		lshrsi3_9-lshrsi3_table
+	.byte		lshrsi3_10-lshrsi3_table
+	.byte		lshrsi3_11-lshrsi3_table
+	.byte		lshrsi3_12-lshrsi3_table
+	.byte		lshrsi3_13-lshrsi3_table
+	.byte		lshrsi3_14-lshrsi3_table
+	.byte		lshrsi3_15-lshrsi3_table
+	.byte		lshrsi3_16-lshrsi3_table
+	.byte		lshrsi3_17-lshrsi3_table
+	.byte		lshrsi3_18-lshrsi3_table
+	.byte		lshrsi3_19-lshrsi3_table
+	.byte		lshrsi3_20-lshrsi3_table
+	.byte		lshrsi3_21-lshrsi3_table
+	.byte		lshrsi3_22-lshrsi3_table
+	.byte		lshrsi3_23-lshrsi3_table
+	.byte		lshrsi3_24-lshrsi3_table
+	.byte		lshrsi3_25-lshrsi3_table
+	.byte		lshrsi3_26-lshrsi3_table
+	.byte		lshrsi3_27-lshrsi3_table
+	.byte		lshrsi3_28-lshrsi3_table
+	.byte		lshrsi3_29-lshrsi3_table
+	.byte		lshrsi3_30-lshrsi3_table
+	.byte		lshrsi3_31-lshrsi3_table
+
+lshrsi3_6:
+	shlr2	r0
+lshrsi3_4:
+	shlr2	r0
+lshrsi3_2:
+	rts
+	shlr2	r0
+
+lshrsi3_7:
+	shlr2	r0
+lshrsi3_5:
+	shlr2	r0
+lshrsi3_3:
+	shlr2	r0
+lshrsi3_1:
+	rts
+	shlr	r0
+
+lshrsi3_14:
+	shlr2	r0
+lshrsi3_12:
+	shlr2	r0
+lshrsi3_10:
+	shlr2	r0
+lshrsi3_8:
+	rts
+	shlr8	r0
+
+lshrsi3_15:
+	shlr2	r0
+lshrsi3_13:
+	shlr2	r0
+lshrsi3_11:
+	shlr2	r0
+lshrsi3_9:
+	shlr8	r0
+	rts
+	shlr	r0
+
+lshrsi3_22:
+	shlr2	r0
+lshrsi3_20:
+	shlr2	r0
+lshrsi3_18:
+	shlr2	r0
+lshrsi3_16:
+	rts
+	shlr16	r0
+
+lshrsi3_23:
+	shlr2	r0
+lshrsi3_21:
+	shlr2	r0
+lshrsi3_19:
+	shlr2	r0
+lshrsi3_17:
+	shlr16	r0
+	rts
+	shlr	r0
+
+lshrsi3_30:
+	shlr2	r0
+lshrsi3_28:
+	shlr2	r0
+lshrsi3_26:
+	shlr2	r0
+lshrsi3_24:
+	shlr16	r0
+	rts
+	shlr8	r0
+
+lshrsi3_31:
+	shlr2	r0
+lshrsi3_29:
+	shlr2	r0
+lshrsi3_27:
+	shlr2	r0
+lshrsi3_25:
+	shlr16	r0
+	shlr8	r0
+	rts
+	shlr	r0
+
+lshrsi3_0:
+	rts
+	nop
diff --git a/arch/sh/lib/mcount.S b/arch/sh/lib/mcount.S
new file mode 100644
index 0000000..110fbfe
--- /dev/null
+++ b/arch/sh/lib/mcount.S
@@ -0,0 +1,90 @@
+/*
+ * arch/sh/lib/mcount.S
+ *
+ *  Copyright (C) 2008  Paul Mundt
+ *  Copyright (C) 2008  Matt Fleming
+ *
+ * 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 <asm/ftrace.h>
+
+#define MCOUNT_ENTER()		\
+	mov.l	r4, @-r15;	\
+	mov.l	r5, @-r15;	\
+	mov.l	r6, @-r15;	\
+	mov.l	r7, @-r15;	\
+	sts.l	pr, @-r15;	\
+				\
+	mov.l	@(20,r15),r4;	\
+	sts	pr, r5
+
+#define MCOUNT_LEAVE()		\
+	lds.l	@r15+, pr;	\
+	mov.l	@r15+, r7;	\
+	mov.l	@r15+, r6;	\
+	mov.l	@r15+, r5;	\
+	rts;			\
+	 mov.l	@r15+, r4
+
+	.align 2
+	.globl	_mcount
+	.type	_mcount,@function
+	.globl	mcount
+	.type	mcount,@function
+_mcount:
+mcount:
+	MCOUNT_ENTER()
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+	.globl	mcount_call
+mcount_call:
+	mov.l	.Lftrace_stub, r6
+#else
+	mov.l	.Lftrace_trace_function, r6
+	mov.l	ftrace_stub, r7
+	cmp/eq	r6, r7
+	bt	skip_trace
+	mov.l	@r6, r6
+#endif
+
+	jsr	@r6
+	 nop
+
+skip_trace:
+	MCOUNT_LEAVE()
+
+	.align 2
+.Lftrace_trace_function:
+	.long	ftrace_trace_function
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+	.globl ftrace_caller
+ftrace_caller:
+	MCOUNT_ENTER()
+
+	.globl ftrace_call
+ftrace_call:
+	mov.l	.Lftrace_stub, r6
+	jsr	@r6
+	 nop
+
+	MCOUNT_LEAVE()
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+/*
+ * NOTE: From here on the locations of the .Lftrace_stub label and
+ * ftrace_stub itself are fixed. Adding additional data here will skew
+ * the displacement for the memory table and break the block replacement.
+ * Place new labels either after the ftrace_stub body, or before
+ * ftrace_caller. You have been warned.
+ */
+	.align 2
+.Lftrace_stub:
+	.long	ftrace_stub
+
+	.globl	ftrace_stub
+ftrace_stub:
+	rts
+	 nop
diff --git a/arch/sh/lib/movmem.S b/arch/sh/lib/movmem.S
new file mode 100644
index 0000000..62075f6
--- /dev/null
+++ b/arch/sh/lib/movmem.S
@@ -0,0 +1,238 @@
+/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+This file is free software; you can redistribute 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+!! libgcc routines for the Renesas / SuperH SH CPUs.
+!! Contributed by Steve Chamberlain.
+!! sac@cygnus.com
+
+!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines
+!! recoded in assembly by Toshiyasu Morita
+!! tm@netcom.com
+
+/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and
+   ELF local label prefixes by J"orn Rennecke
+   amylaar@cygnus.com  */
+
+	.text
+	.balign	4
+	.global	__movmem
+	.global __movstr
+	.set __movstr, __movmem	
+	/* This would be a lot simpler if r6 contained the byte count
+	   minus 64, and we wouldn't be called here for a byte count of 64.  */
+__movmem:
+	sts.l	pr,@-r15
+	shll2	r6
+	bsr	__movmemSI52+2
+	mov.l	@(48,r5),r0
+	.balign	4
+movmem_loop: /* Reached with rts */
+	mov.l	@(60,r5),r0
+	add	#-64,r6
+	mov.l	r0,@(60,r4)
+	tst	r6,r6
+	mov.l	@(56,r5),r0
+	bt	movmem_done
+	mov.l	r0,@(56,r4)
+	cmp/pl	r6
+	mov.l	@(52,r5),r0
+	add	#64,r5
+	mov.l	r0,@(52,r4)
+	add	#64,r4
+	bt	__movmemSI52
+! done all the large groups, do the remainder
+! jump to movmem+
+	mova	__movmemSI4+4,r0
+	add	r6,r0
+	jmp	@r0
+movmem_done: ! share slot insn, works out aligned.
+	lds.l	@r15+,pr
+	mov.l	r0,@(56,r4)
+	mov.l	@(52,r5),r0
+	rts
+	mov.l	r0,@(52,r4)
+	.balign	4
+
+	.global	__movmemSI64
+	.global __movstrSI64
+	.set	__movstrSI64, __movmemSI64
+__movmemSI64:
+	mov.l	@(60,r5),r0
+	mov.l	r0,@(60,r4)
+	.global	__movmemSI60
+	.global __movstrSI60
+	.set	__movstrSI60, __movmemSI60
+__movmemSI60:
+	mov.l	@(56,r5),r0
+	mov.l	r0,@(56,r4)
+	.global	__movmemSI56
+	.global __movstrSI56
+	.set	__movstrSI56, __movmemSI56
+__movmemSI56:
+	mov.l	@(52,r5),r0
+	mov.l	r0,@(52,r4)
+	.global	__movmemSI52
+	.global __movstrSI52
+	.set	__movstrSI52, __movmemSI52
+__movmemSI52:
+	mov.l	@(48,r5),r0
+	mov.l	r0,@(48,r4)
+	.global	__movmemSI48
+	.global	__movstrSI48
+	.set	__movstrSI48, __movmemSI48
+__movmemSI48:
+	mov.l	@(44,r5),r0
+	mov.l	r0,@(44,r4)
+	.global	__movmemSI44
+	.global	__movstrSI44
+	.set	__movstrSI44, __movmemSI44
+__movmemSI44:
+	mov.l	@(40,r5),r0
+	mov.l	r0,@(40,r4)
+	.global	__movmemSI40
+	.global __movstrSI40
+	.set	__movstrSI40, __movmemSI40
+__movmemSI40:
+	mov.l	@(36,r5),r0
+	mov.l	r0,@(36,r4)
+	.global	__movmemSI36
+	.global	__movstrSI36
+	.set	__movstrSI36, __movmemSI36
+__movmemSI36:
+	mov.l	@(32,r5),r0
+	mov.l	r0,@(32,r4)
+	.global	__movmemSI32
+	.global	__movstrSI32
+	.set	__movstrSI32, __movmemSI32
+__movmemSI32:
+	mov.l	@(28,r5),r0
+	mov.l	r0,@(28,r4)
+	.global	__movmemSI28
+	.global	__movstrSI28
+	.set	__movstrSI28, __movmemSI28
+__movmemSI28:
+	mov.l	@(24,r5),r0
+	mov.l	r0,@(24,r4)
+	.global	__movmemSI24
+	.global	__movstrSI24
+	.set	__movstrSI24, __movmemSI24
+__movmemSI24:
+	mov.l	@(20,r5),r0
+	mov.l	r0,@(20,r4)
+	.global	__movmemSI20
+	.global	__movstrSI20
+	.set	__movstrSI20, __movmemSI20
+__movmemSI20:
+	mov.l	@(16,r5),r0
+	mov.l	r0,@(16,r4)
+	.global	__movmemSI16
+	.global	__movstrSI16
+	.set	__movstrSI16, __movmemSI16
+__movmemSI16:
+	mov.l	@(12,r5),r0
+	mov.l	r0,@(12,r4)
+	.global	__movmemSI12
+	.global	__movstrSI12
+	.set	__movstrSI12, __movmemSI12
+__movmemSI12:
+	mov.l	@(8,r5),r0
+	mov.l	r0,@(8,r4)
+	.global	__movmemSI8
+	.global	__movstrSI8
+	.set	__movstrSI8, __movmemSI8
+__movmemSI8:
+	mov.l	@(4,r5),r0
+	mov.l	r0,@(4,r4)
+	.global	__movmemSI4
+	.global	__movstrSI4
+	.set	__movstrSI4, __movmemSI4
+__movmemSI4:
+	mov.l	@(0,r5),r0
+	rts
+	mov.l	r0,@(0,r4)
+
+	.global	__movmem_i4_even
+	.global	__movstr_i4_even
+	.set	__movstr_i4_even, __movmem_i4_even
+
+	.global	__movmem_i4_odd
+	.global	__movstr_i4_odd
+	.set	__movstr_i4_odd, __movmem_i4_odd
+
+	.global	__movmemSI12_i4
+	.global	__movstrSI12_i4
+	.set	__movstrSI12_i4, __movmemSI12_i4
+
+	.p2align	5
+L_movmem_2mod4_end:
+	mov.l	r0,@(16,r4)
+	rts
+	mov.l	r1,@(20,r4)
+
+	.p2align	2
+
+__movmem_i4_even:
+	mov.l	@r5+,r0
+	bra	L_movmem_start_even
+	mov.l	@r5+,r1
+
+__movmem_i4_odd:
+	mov.l	@r5+,r1
+	add	#-4,r4
+	mov.l	@r5+,r2
+	mov.l	@r5+,r3
+	mov.l	r1,@(4,r4)
+	mov.l	r2,@(8,r4)
+
+L_movmem_loop:
+	mov.l	r3,@(12,r4)
+	dt	r6
+	mov.l	@r5+,r0
+	bt/s	L_movmem_2mod4_end
+	mov.l	@r5+,r1
+	add	#16,r4
+L_movmem_start_even:
+	mov.l	@r5+,r2
+	mov.l	@r5+,r3
+	mov.l	r0,@r4
+	dt	r6
+	mov.l	r1,@(4,r4)
+	bf/s	L_movmem_loop
+	mov.l	r2,@(8,r4)
+	rts
+	mov.l	r3,@(12,r4)
+
+	.p2align	4
+__movmemSI12_i4:
+	mov.l	@r5,r0
+	mov.l	@(4,r5),r1
+	mov.l	@(8,r5),r2
+	mov.l	r0,@r4
+	mov.l	r1,@(4,r4)
+	rts
+	mov.l	r2,@(8,r4)
diff --git a/arch/sh/lib/udiv_qrnnd.S b/arch/sh/lib/udiv_qrnnd.S
new file mode 100644
index 0000000..32b9a36
--- /dev/null
+++ b/arch/sh/lib/udiv_qrnnd.S
@@ -0,0 +1,81 @@
+/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+This file is free software; you can redistribute 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+!! libgcc routines for the Renesas / SuperH SH CPUs.
+!! Contributed by Steve Chamberlain.
+!! sac@cygnus.com
+
+!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines
+!! recoded in assembly by Toshiyasu Morita
+!! tm@netcom.com
+
+/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and
+   ELF local label prefixes by J"orn Rennecke
+   amylaar@cygnus.com  */
+
+	/* r0: rn r1: qn */ /* r0: n1 r4: n0 r5: d r6: d1 */ /* r2: __m */
+	/* n1 < d, but n1 might be larger than d1.  */
+	.global __udiv_qrnnd_16
+	.balign 8
+__udiv_qrnnd_16:
+	div0u
+	cmp/hi r6,r0
+	bt .Lots
+	.rept 16
+	div1 r6,r0 
+	.endr
+	extu.w r0,r1
+	bt 0f
+	add r6,r0
+0:	rotcl r1
+	mulu.w r1,r5
+	xtrct r4,r0
+	swap.w r0,r0
+	sts macl,r2
+	cmp/hs r2,r0
+	sub r2,r0
+	bt 0f
+	addc r5,r0
+	add #-1,r1
+	bt 0f
+1:	add #-1,r1
+	rts
+	add r5,r0
+	.balign 8
+.Lots:
+	sub r5,r0
+	swap.w r4,r1
+	xtrct r0,r1
+	clrt
+	mov r1,r0
+	addc r5,r0
+	mov #-1,r1
+	bf/s 1b
+	 shlr16 r1
+0:	rts
+	 nop
diff --git a/arch/sh/lib/udivsi3.S b/arch/sh/lib/udivsi3.S
new file mode 100644
index 0000000..72157ab
--- /dev/null
+++ b/arch/sh/lib/udivsi3.S
@@ -0,0 +1,87 @@
+/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005
+   Free Software Foundation, Inc.
+
+This file is free software; you can redistribute 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+!! libgcc routines for the Renesas / SuperH SH CPUs.
+!! Contributed by Steve Chamberlain.
+!! sac@cygnus.com
+
+	.balign 4
+	.global	__udivsi3
+	.type	__udivsi3, @function
+div8:
+	div1 r5,r4
+div7:
+	div1 r5,r4; div1 r5,r4; div1 r5,r4
+	div1 r5,r4; div1 r5,r4; div1 r5,r4; rts; div1 r5,r4
+
+divx4:
+	div1 r5,r4; rotcl r0
+	div1 r5,r4; rotcl r0
+	div1 r5,r4; rotcl r0
+	rts; div1 r5,r4
+
+__udivsi3:
+	sts.l pr,@-r15
+	extu.w r5,r0
+	cmp/eq r5,r0
+	bf/s large_divisor
+	div0u
+	swap.w r4,r0
+	shlr16 r4
+	bsr div8
+	shll16 r5
+	bsr div7
+	div1 r5,r4
+	xtrct r4,r0
+	xtrct r0,r4
+	bsr div8
+	swap.w r4,r4
+	bsr div7
+	div1 r5,r4
+	lds.l @r15+,pr
+	xtrct r4,r0
+	swap.w r0,r0
+	rotcl r0
+	rts
+	shlr16 r5
+
+large_divisor:
+	mov #0,r0
+	xtrct r4,r0
+	xtrct r0,r4
+	bsr divx4
+	rotcl r0
+	bsr divx4
+	rotcl r0
+	bsr divx4
+	rotcl r0
+	bsr divx4
+	rotcl r0
+	lds.l @r15+,pr
+	rts
+	rotcl r0
diff --git a/arch/sh/lib/udivsi3_i4i-Os.S b/arch/sh/lib/udivsi3_i4i-Os.S
new file mode 100644
index 0000000..4835553
--- /dev/null
+++ b/arch/sh/lib/udivsi3_i4i-Os.S
@@ -0,0 +1,149 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is free software; you can redistribute 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+/* Moderately Space-optimized libgcc routines for the Renesas SH /
+   STMicroelectronics ST40 CPUs.
+   Contributed by J"orn Rennecke joern.rennecke@st.com.  */
+
+/* Size: 186 bytes jointly for udivsi3_i4i and sdivsi3_i4i
+   sh4-200 run times:
+   udiv small divisor: 55 cycles
+   udiv large divisor: 52 cycles
+   sdiv small divisor, positive result: 59 cycles
+   sdiv large divisor, positive result: 56 cycles
+   sdiv small divisor, negative result: 65 cycles (*)
+   sdiv large divisor, negative result: 62 cycles (*)
+   (*): r2 is restored in the rts delay slot and has a lingering latency
+        of two more cycles.  */
+	.balign 4
+	.global	__udivsi3_i4i
+	.global	__udivsi3_i4
+	.set	__udivsi3_i4, __udivsi3_i4i
+	.type	__udivsi3_i4i, @function
+	.type	__sdivsi3_i4i, @function
+__udivsi3_i4i:
+	sts pr,r1
+	mov.l r4,@-r15
+	extu.w r5,r0
+	cmp/eq r5,r0
+	swap.w r4,r0
+	shlr16 r4
+	bf/s large_divisor
+	div0u
+	mov.l r5,@-r15
+	shll16 r5
+sdiv_small_divisor:
+	div1 r5,r4
+	bsr div6
+	div1 r5,r4
+	div1 r5,r4
+	bsr div6
+	div1 r5,r4
+	xtrct r4,r0
+	xtrct r0,r4
+	bsr div7
+	swap.w r4,r4
+	div1 r5,r4
+	bsr div7
+	div1 r5,r4
+	xtrct r4,r0
+	mov.l @r15+,r5
+	swap.w r0,r0
+	mov.l @r15+,r4
+	jmp @r1
+	rotcl r0
+div7:
+	div1 r5,r4
+div6:
+	            div1 r5,r4; div1 r5,r4; div1 r5,r4
+	div1 r5,r4; div1 r5,r4; rts;        div1 r5,r4
+
+divx3:
+	rotcl r0
+	div1 r5,r4
+	rotcl r0
+	div1 r5,r4
+	rotcl r0
+	rts
+	div1 r5,r4
+
+large_divisor:
+	mov.l r5,@-r15
+sdiv_large_divisor:
+	xor r4,r0
+	.rept 4
+	rotcl r0
+	bsr divx3
+	div1 r5,r4
+	.endr
+	mov.l @r15+,r5
+	mov.l @r15+,r4
+	jmp @r1
+	rotcl r0
+
+	.global	__sdivsi3_i4i
+	.global __sdivsi3_i4
+	.global __sdivsi3
+	.set	__sdivsi3_i4, __sdivsi3_i4i
+	.set	__sdivsi3, __sdivsi3_i4i
+__sdivsi3_i4i:
+	mov.l r4,@-r15
+	cmp/pz r5
+	mov.l r5,@-r15
+	bt/s pos_divisor
+	cmp/pz r4
+	neg r5,r5
+	extu.w r5,r0
+	bt/s neg_result
+	cmp/eq r5,r0
+	neg r4,r4
+pos_result:
+	swap.w r4,r0
+	bra sdiv_check_divisor
+	sts pr,r1
+pos_divisor:
+	extu.w r5,r0
+	bt/s pos_result
+	cmp/eq r5,r0
+	neg r4,r4
+neg_result:
+	mova negate_result,r0
+	;
+	mov r0,r1
+	swap.w r4,r0
+	lds r2,macl
+	sts pr,r2
+sdiv_check_divisor:
+	shlr16 r4
+	bf/s sdiv_large_divisor
+	div0u
+	bra sdiv_small_divisor
+	shll16 r5
+	.balign 4
+negate_result:
+	neg r0,r0
+	jmp @r2
+	sts macl,r2
diff --git a/arch/sh/lib/udivsi3_i4i.S b/arch/sh/lib/udivsi3_i4i.S
new file mode 100644
index 0000000..f1a79d9
--- /dev/null
+++ b/arch/sh/lib/udivsi3_i4i.S
@@ -0,0 +1,666 @@
+/* Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+This file is free software; you can redistribute 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+!! libgcc routines for the Renesas / SuperH SH CPUs.
+!! Contributed by Steve Chamberlain.
+!! sac@cygnus.com
+
+!! ashiftrt_r4_x, ___ashrsi3, ___ashlsi3, ___lshrsi3 routines
+!! recoded in assembly by Toshiyasu Morita
+!! tm@netcom.com
+
+/* SH2 optimizations for ___ashrsi3, ___ashlsi3, ___lshrsi3 and
+   ELF local label prefixes by J"orn Rennecke
+   amylaar@cygnus.com  */
+
+/* This code used shld, thus is not suitable for SH1 / SH2.  */
+
+/* Signed / unsigned division without use of FPU, optimized for SH4.
+   Uses a lookup table for divisors in the range -128 .. +128, and
+   div1 with case distinction for larger divisors in three more ranges.
+   The code is lumped together with the table to allow the use of mova.  */
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+#define L_LSB 0
+#define L_LSWMSB 1
+#define L_MSWLSB 2
+#else
+#define L_LSB 3
+#define L_LSWMSB 2
+#define L_MSWLSB 1
+#endif
+
+	.balign 4
+	.global	__udivsi3_i4i
+	.global	__udivsi3_i4
+	.set	__udivsi3_i4, __udivsi3_i4i
+	.type	__udivsi3_i4i, @function
+__udivsi3_i4i:
+	mov.w c128_w, r1
+	div0u
+	mov r4,r0
+	shlr8 r0
+	cmp/hi r1,r5
+	extu.w r5,r1
+	bf udiv_le128
+	cmp/eq r5,r1
+	bf udiv_ge64k
+	shlr r0
+	mov r5,r1
+	shll16 r5
+	mov.l r4,@-r15
+	div1 r5,r0
+	mov.l r1,@-r15
+	div1 r5,r0
+	div1 r5,r0
+	bra udiv_25
+	div1 r5,r0
+
+div_le128:
+	mova div_table_ix,r0
+	bra div_le128_2
+	mov.b @(r0,r5),r1
+udiv_le128:
+	mov.l r4,@-r15
+	mova div_table_ix,r0
+	mov.b @(r0,r5),r1
+	mov.l r5,@-r15
+div_le128_2:
+	mova div_table_inv,r0
+	mov.l @(r0,r1),r1
+	mov r5,r0
+	tst #0xfe,r0
+	mova div_table_clz,r0
+	dmulu.l r1,r4
+	mov.b @(r0,r5),r1
+	bt/s div_by_1
+	mov r4,r0
+	mov.l @r15+,r5
+	sts mach,r0
+	/* clrt */
+	addc r4,r0
+	mov.l @r15+,r4
+	rotcr r0
+	rts
+	shld r1,r0
+
+div_by_1_neg:
+	neg r4,r0
+div_by_1:
+	mov.l @r15+,r5
+	rts
+	mov.l @r15+,r4
+
+div_ge64k:
+	bt/s div_r8
+	div0u
+	shll8 r5
+	bra div_ge64k_2
+	div1 r5,r0
+udiv_ge64k:
+	cmp/hi r0,r5
+	mov r5,r1
+	bt udiv_r8
+	shll8 r5
+	mov.l r4,@-r15
+	div1 r5,r0
+	mov.l r1,@-r15
+div_ge64k_2:
+	div1 r5,r0
+	mov.l zero_l,r1
+	.rept 4
+	div1 r5,r0
+	.endr
+	mov.l r1,@-r15
+	div1 r5,r0
+	mov.w m256_w,r1
+	div1 r5,r0
+	mov.b r0,@(L_LSWMSB,r15)
+	xor r4,r0
+	and r1,r0
+	bra div_ge64k_end
+	xor r4,r0
+	
+div_r8:
+	shll16 r4
+	bra div_r8_2
+	shll8 r4
+udiv_r8:
+	mov.l r4,@-r15
+	shll16 r4
+	clrt
+	shll8 r4
+	mov.l r5,@-r15
+div_r8_2:
+	rotcl r4
+	mov r0,r1
+	div1 r5,r1
+	mov r4,r0
+	rotcl r0
+	mov r5,r4
+	div1 r5,r1
+	.rept 5
+	rotcl r0; div1 r5,r1
+	.endr
+	rotcl r0
+	mov.l @r15+,r5
+	div1 r4,r1
+	mov.l @r15+,r4
+	rts
+	rotcl r0
+
+	.global	__sdivsi3_i4i
+	.global __sdivsi3_i4
+	.global	__sdivsi3
+	.set	__sdivsi3_i4, __sdivsi3_i4i
+	.set	__sdivsi3, __sdivsi3_i4i
+	.type	__sdivsi3_i4i, @function
+	/* This is link-compatible with a __sdivsi3 call,
+	   but we effectively clobber only r1.  */
+__sdivsi3_i4i:
+	mov.l r4,@-r15
+	cmp/pz r5
+	mov.w c128_w, r1
+	bt/s pos_divisor
+	cmp/pz r4
+	mov.l r5,@-r15
+	neg r5,r5
+	bt/s neg_result
+	cmp/hi r1,r5
+	neg r4,r4
+pos_result:
+	extu.w r5,r0
+	bf div_le128
+	cmp/eq r5,r0
+	mov r4,r0
+	shlr8 r0
+	bf/s div_ge64k
+	cmp/hi r0,r5
+	div0u
+	shll16 r5
+	div1 r5,r0
+	div1 r5,r0
+	div1 r5,r0
+udiv_25:
+	mov.l zero_l,r1
+	div1 r5,r0
+	div1 r5,r0
+	mov.l r1,@-r15
+	.rept 3
+	div1 r5,r0
+	.endr
+	mov.b r0,@(L_MSWLSB,r15)
+	xtrct r4,r0
+	swap.w r0,r0
+	.rept 8
+	div1 r5,r0
+	.endr
+	mov.b r0,@(L_LSWMSB,r15)
+div_ge64k_end:
+	.rept 8
+	div1 r5,r0
+	.endr
+	mov.l @r15+,r4 ! zero-extension and swap using LS unit.
+	extu.b r0,r0
+	mov.l @r15+,r5
+	or r4,r0
+	mov.l @r15+,r4
+	rts
+	rotcl r0
+
+div_le128_neg:
+	tst #0xfe,r0
+	mova div_table_ix,r0
+	mov.b @(r0,r5),r1
+	mova div_table_inv,r0
+	bt/s div_by_1_neg
+	mov.l @(r0,r1),r1
+	mova div_table_clz,r0
+	dmulu.l r1,r4
+	mov.b @(r0,r5),r1
+	mov.l @r15+,r5
+	sts mach,r0
+	/* clrt */
+	addc r4,r0
+	mov.l @r15+,r4
+	rotcr r0
+	shld r1,r0
+	rts
+	neg r0,r0
+
+pos_divisor:
+	mov.l r5,@-r15
+	bt/s pos_result
+	cmp/hi r1,r5
+	neg r4,r4
+neg_result:
+	extu.w r5,r0
+	bf div_le128_neg
+	cmp/eq r5,r0
+	mov r4,r0
+	shlr8 r0
+	bf/s div_ge64k_neg
+	cmp/hi r0,r5
+	div0u
+	mov.l zero_l,r1
+	shll16 r5
+	div1 r5,r0
+	mov.l r1,@-r15
+	.rept 7
+	div1 r5,r0
+	.endr
+	mov.b r0,@(L_MSWLSB,r15)
+	xtrct r4,r0
+	swap.w r0,r0
+	.rept 8
+	div1 r5,r0
+	.endr
+	mov.b r0,@(L_LSWMSB,r15)
+div_ge64k_neg_end:
+	.rept 8
+	div1 r5,r0
+	.endr
+	mov.l @r15+,r4 ! zero-extension and swap using LS unit.
+	extu.b r0,r1
+	mov.l @r15+,r5
+	or r4,r1
+div_r8_neg_end:
+	mov.l @r15+,r4
+	rotcl r1
+	rts
+	neg r1,r0
+
+div_ge64k_neg:
+	bt/s div_r8_neg
+	div0u
+	shll8 r5
+	mov.l zero_l,r1
+	.rept 6
+	div1 r5,r0
+	.endr
+	mov.l r1,@-r15
+	div1 r5,r0
+	mov.w m256_w,r1
+	div1 r5,r0
+	mov.b r0,@(L_LSWMSB,r15)
+	xor r4,r0
+	and r1,r0
+	bra div_ge64k_neg_end
+	xor r4,r0
+
+c128_w:
+	.word 128
+
+div_r8_neg:
+	clrt
+	shll16 r4
+	mov r4,r1
+	shll8 r1
+	mov r5,r4
+	.rept 7
+	rotcl r1; div1 r5,r0
+	.endr
+	mov.l @r15+,r5
+	rotcl r1
+	bra div_r8_neg_end
+	div1 r4,r0
+
+m256_w:
+	.word 0xff00
+/* This table has been generated by divtab-sh4.c.  */
+	.balign 4
+div_table_clz:
+	.byte	0
+	.byte	1
+	.byte	0
+	.byte	-1
+	.byte	-1
+	.byte	-2
+	.byte	-2
+	.byte	-2
+	.byte	-2
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-3
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-4
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-5
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+	.byte	-6
+/* Lookup table translating positive divisor to index into table of
+   normalized inverse.  N.B. the '0' entry is also the last entry of the
+ previous table, and causes an unaligned access for division by zero.  */
+div_table_ix:
+	.byte	-6
+	.byte	-128
+	.byte	-128
+	.byte	0
+	.byte	-128
+	.byte	-64
+	.byte	0
+	.byte	64
+	.byte	-128
+	.byte	-96
+	.byte	-64
+	.byte	-32
+	.byte	0
+	.byte	32
+	.byte	64
+	.byte	96
+	.byte	-128
+	.byte	-112
+	.byte	-96
+	.byte	-80
+	.byte	-64
+	.byte	-48
+	.byte	-32
+	.byte	-16
+	.byte	0
+	.byte	16
+	.byte	32
+	.byte	48
+	.byte	64
+	.byte	80
+	.byte	96
+	.byte	112
+	.byte	-128
+	.byte	-120
+	.byte	-112
+	.byte	-104
+	.byte	-96
+	.byte	-88
+	.byte	-80
+	.byte	-72
+	.byte	-64
+	.byte	-56
+	.byte	-48
+	.byte	-40
+	.byte	-32
+	.byte	-24
+	.byte	-16
+	.byte	-8
+	.byte	0
+	.byte	8
+	.byte	16
+	.byte	24
+	.byte	32
+	.byte	40
+	.byte	48
+	.byte	56
+	.byte	64
+	.byte	72
+	.byte	80
+	.byte	88
+	.byte	96
+	.byte	104
+	.byte	112
+	.byte	120
+	.byte	-128
+	.byte	-124
+	.byte	-120
+	.byte	-116
+	.byte	-112
+	.byte	-108
+	.byte	-104
+	.byte	-100
+	.byte	-96
+	.byte	-92
+	.byte	-88
+	.byte	-84
+	.byte	-80
+	.byte	-76
+	.byte	-72
+	.byte	-68
+	.byte	-64
+	.byte	-60
+	.byte	-56
+	.byte	-52
+	.byte	-48
+	.byte	-44
+	.byte	-40
+	.byte	-36
+	.byte	-32
+	.byte	-28
+	.byte	-24
+	.byte	-20
+	.byte	-16
+	.byte	-12
+	.byte	-8
+	.byte	-4
+	.byte	0
+	.byte	4
+	.byte	8
+	.byte	12
+	.byte	16
+	.byte	20
+	.byte	24
+	.byte	28
+	.byte	32
+	.byte	36
+	.byte	40
+	.byte	44
+	.byte	48
+	.byte	52
+	.byte	56
+	.byte	60
+	.byte	64
+	.byte	68
+	.byte	72
+	.byte	76
+	.byte	80
+	.byte	84
+	.byte	88
+	.byte	92
+	.byte	96
+	.byte	100
+	.byte	104
+	.byte	108
+	.byte	112
+	.byte	116
+	.byte	120
+	.byte	124
+	.byte	-128
+/* 1/64 .. 1/127, normalized.  There is an implicit leading 1 in bit 32.  */
+	.balign 4
+zero_l:
+	.long	0x0
+	.long	0xF81F81F9
+	.long	0xF07C1F08
+	.long	0xE9131AC0
+	.long	0xE1E1E1E2
+	.long	0xDAE6076C
+	.long	0xD41D41D5
+	.long	0xCD856891
+	.long	0xC71C71C8
+	.long	0xC0E07039
+	.long	0xBACF914D
+	.long	0xB4E81B4F
+	.long	0xAF286BCB
+	.long	0xA98EF607
+	.long	0xA41A41A5
+	.long	0x9EC8E952
+	.long	0x9999999A
+	.long	0x948B0FCE
+	.long	0x8F9C18FA
+	.long	0x8ACB90F7
+	.long	0x86186187
+	.long	0x81818182
+	.long	0x7D05F418
+	.long	0x78A4C818
+	.long	0x745D1746
+	.long	0x702E05C1
+	.long	0x6C16C16D
+	.long	0x68168169
+	.long	0x642C8591
+	.long	0x60581606
+	.long	0x5C9882BA
+	.long	0x58ED2309
+div_table_inv:
+	.long	0x55555556
+	.long	0x51D07EAF
+	.long	0x4E5E0A73
+	.long	0x4AFD6A06
+	.long	0x47AE147B
+	.long	0x446F8657
+	.long	0x41414142
+	.long	0x3E22CBCF
+	.long	0x3B13B13C
+	.long	0x38138139
+	.long	0x3521CFB3
+	.long	0x323E34A3
+	.long	0x2F684BDB
+	.long	0x2C9FB4D9
+	.long	0x29E4129F
+	.long	0x27350B89
+	.long	0x24924925
+	.long	0x21FB7813
+	.long	0x1F7047DD
+	.long	0x1CF06ADB
+	.long	0x1A7B9612
+	.long	0x18118119
+	.long	0x15B1E5F8
+	.long	0x135C8114
+	.long	0x11111112
+	.long	0xECF56BF
+	.long	0xC9714FC
+	.long	0xA6810A7
+	.long	0x8421085
+	.long	0x624DD30
+	.long	0x4104105
+	.long	0x2040811
+	/* maximum error: 0.987342 scaled: 0.921875*/
diff --git a/arch/sh/lib64/Makefile b/arch/sh/lib64/Makefile
index 9950966..4bacb9e 100644
--- a/arch/sh/lib64/Makefile
+++ b/arch/sh/lib64/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the SH-5 specific library files..
 #
 # Copyright (C) 2000, 2001  Paolo Alberelli
-# Copyright (C) 2003  Paul Mundt
+# Copyright (C) 2003 - 2008  Paul Mundt
 #
 # This file is subject to the terms and conditions of the GNU General Public
 # License.  See the file "COPYING" in the main directory of this archive
@@ -10,6 +10,8 @@
 #
 
 # Panic should really be compiled as PIC
-lib-y  := udelay.o c-checksum.o dbg.o panic.o memcpy.o copy_user_memcpy.o \
-		copy_page.o clear_page.o
+lib-y  := udelay.o c-checksum.o dbg.o panic.o memcpy.o memset.o \
+	  copy_user_memcpy.o copy_page.o clear_page.o strcpy.o strlen.o
 
+# Extracted from libgcc
+lib-y	+= udivsi3.o udivdi3.o sdivsi3.o
diff --git a/arch/sh/lib64/c-checksum.c b/arch/sh/lib64/c-checksum.c
index 5c284e0..73c0877 100644
--- a/arch/sh/lib64/c-checksum.c
+++ b/arch/sh/lib64/c-checksum.c
@@ -35,7 +35,7 @@
 
 static inline unsigned short myfoldto16(unsigned long long x)
 {
-	/* Fold down to 32-bits so we don't loose in the typedef-less
+	/* Fold down to 32-bits so we don't lose in the typedef-less
 	   network stack.  */
 	/* 64 to 33 */
 	x = (x & 0xffffffff) + (x >> 32);
@@ -199,7 +199,7 @@
 	result = (__force u64) saddr + (__force u64) daddr +
 		 (__force u64) sum + ((len + proto) << 8);
 
-	/* Fold down to 32-bits so we don't loose in the typedef-less
+	/* Fold down to 32-bits so we don't lose in the typedef-less
 	   network stack.  */
 	/* 64 to 33 */
 	result = (result & 0xffffffff) + (result >> 32);
diff --git a/arch/sh/lib64/memcpy.S b/arch/sh/lib64/memcpy.S
new file mode 100644
index 0000000..dd300c3
--- /dev/null
+++ b/arch/sh/lib64/memcpy.S
@@ -0,0 +1,201 @@
+/* Cloned and hacked for uClibc by Paul Mundt, December 2003 */
+/* Modified by SuperH, Inc. September 2003 */
+!
+! Fast SH memcpy
+!
+! by Toshiyasu Morita (tm@netcom.com)
+! hacked by J"orn Rernnecke (joern.rennecke@superh.com) ("o for o-umlaut)
+! SH5 code Copyright 2002 SuperH Ltd.
+!
+! Entry: ARG0: destination pointer
+!        ARG1: source pointer
+!        ARG2: byte count
+!
+! Exit:  RESULT: destination pointer
+!        any other registers in the range r0-r7: trashed
+!
+! Notes: Usually one wants to do small reads and write a longword, but
+!        unfortunately it is difficult in some cases to concatanate bytes
+!        into a longword on the SH, so this does a longword read and small
+!        writes.
+!
+! This implementation makes two assumptions about how it is called:
+!
+! 1.: If the byte count is nonzero, the address of the last byte to be
+!     copied is unsigned greater than the address of the first byte to
+!     be copied.  This could be easily swapped for a signed comparison,
+!     but the algorithm used needs some comparison.
+!
+! 2.: When there are two or three bytes in the last word of an 11-or-more
+!     bytes memory chunk to b copied, the rest of the word can be read
+!     without side effects.
+!     This could be easily changed by increasing the minumum size of
+!     a fast memcpy and the amount subtracted from r7 before L_2l_loop be 2,
+!     however, this would cost a few extra cyles on average.
+!     For SHmedia, the assumption is that any quadword can be read in its
+!     enirety if at least one byte is included in the copy.
+!
+
+	.section .text..SHmedia32,"ax"
+	.globl	memcpy
+	.type	memcpy, @function
+	.align	5
+
+memcpy:
+
+#define LDUAQ(P,O,D0,D1) ldlo.q P,O,D0; ldhi.q P,O+7,D1
+#define STUAQ(P,O,D0,D1) stlo.q P,O,D0; sthi.q P,O+7,D1
+#define LDUAL(P,O,D0,D1) ldlo.l P,O,D0; ldhi.l P,O+3,D1
+#define STUAL(P,O,D0,D1) stlo.l P,O,D0; sthi.l P,O+3,D1
+
+	ld.b r3,0,r63
+	pta/l Large,tr0
+	movi 25,r0
+	bgeu/u r4,r0,tr0
+	nsb r4,r0
+	shlli r0,5,r0
+	movi (L1-L0+63*32 + 1) & 0xffff,r1
+	sub r1, r0, r0
+L0:	ptrel r0,tr0
+	add r2,r4,r5
+	ptabs r18,tr1
+	add r3,r4,r6
+	blink tr0,r63
+	
+/* Rearranged to make cut2 safe */
+	.balign 8
+L4_7:	/* 4..7 byte memcpy cntd. */
+	stlo.l r2, 0, r0
+	or r6, r7, r6
+	sthi.l r5, -1, r6
+	stlo.l r5, -4, r6
+	blink tr1,r63
+
+	.balign 8
+L1:	/* 0 byte memcpy */
+	nop
+	blink tr1,r63
+	nop
+	nop
+	nop
+	nop
+
+L2_3:	/* 2 or 3 byte memcpy cntd. */
+	st.b r5,-1,r6
+	blink tr1,r63
+
+	/* 1 byte memcpy */
+	ld.b r3,0,r0
+	st.b r2,0,r0
+	blink tr1,r63
+
+L8_15:	/* 8..15 byte memcpy cntd. */
+	stlo.q r2, 0, r0
+	or r6, r7, r6
+	sthi.q r5, -1, r6
+	stlo.q r5, -8, r6
+	blink tr1,r63
+	
+	/* 2 or 3 byte memcpy */
+	ld.b r3,0,r0
+	ld.b r2,0,r63
+	ld.b r3,1,r1
+	st.b r2,0,r0
+	pta/l L2_3,tr0
+	ld.b r6,-1,r6
+	st.b r2,1,r1
+	blink tr0, r63
+
+	/* 4 .. 7 byte memcpy */
+	LDUAL (r3, 0, r0, r1)
+	pta L4_7, tr0
+	ldlo.l r6, -4, r7
+	or r0, r1, r0
+	sthi.l r2, 3, r0
+	ldhi.l r6, -1, r6
+	blink tr0, r63
+
+	/* 8 .. 15 byte memcpy */
+	LDUAQ (r3, 0, r0, r1)
+	pta L8_15, tr0
+	ldlo.q r6, -8, r7
+	or r0, r1, r0
+	sthi.q r2, 7, r0
+	ldhi.q r6, -1, r6
+	blink tr0, r63
+
+	/* 16 .. 24 byte memcpy */
+	LDUAQ (r3, 0, r0, r1)
+	LDUAQ (r3, 8, r8, r9)
+	or r0, r1, r0
+	sthi.q r2, 7, r0
+	or r8, r9, r8
+	sthi.q r2, 15, r8
+	ldlo.q r6, -8, r7
+	ldhi.q r6, -1, r6
+	stlo.q r2, 8, r8
+	stlo.q r2, 0, r0
+	or r6, r7, r6
+	sthi.q r5, -1, r6
+	stlo.q r5, -8, r6
+	blink tr1,r63
+
+Large:
+	ld.b r2, 0, r63
+	pta/l  Loop_ua, tr1
+	ori r3, -8, r7
+	sub r2, r7, r22
+	sub r3, r2, r6
+	add r2, r4, r5
+	ldlo.q r3, 0, r0
+	addi r5, -16, r5
+	movi 64+8, r27 // could subtract r7 from that.
+	stlo.q r2, 0, r0
+	sthi.q r2, 7, r0
+	ldx.q r22, r6, r0
+	bgtu/l r27, r4, tr1
+
+	addi r5, -48, r27
+	pta/l Loop_line, tr0
+	addi r6, 64, r36
+	addi r6, -24, r19
+	addi r6, -16, r20
+	addi r6, -8, r21
+
+Loop_line:
+	ldx.q r22, r36, r63
+	alloco r22, 32
+	addi r22, 32, r22
+	ldx.q r22, r19, r23
+	sthi.q r22, -25, r0
+	ldx.q r22, r20, r24
+	ldx.q r22, r21, r25
+	stlo.q r22, -32, r0
+	ldx.q r22, r6,  r0
+	sthi.q r22, -17, r23
+	sthi.q r22,  -9, r24
+	sthi.q r22,  -1, r25
+	stlo.q r22, -24, r23
+	stlo.q r22, -16, r24
+	stlo.q r22,  -8, r25
+	bgeu r27, r22, tr0
+
+Loop_ua:
+	addi r22, 8, r22
+	sthi.q r22, -1, r0
+	stlo.q r22, -8, r0
+	ldx.q r22, r6, r0
+	bgtu/l r5, r22, tr1
+
+	add r3, r4, r7
+	ldlo.q r7, -8, r1
+	sthi.q r22, 7, r0
+	ldhi.q r7, -1, r7
+	ptabs r18,tr1
+	stlo.q r22, 0, r0
+	or r1, r7, r1
+	sthi.q r5, 15, r1
+	stlo.q r5, 8, r1
+	blink tr1, r63
+
+	.size memcpy,.-memcpy
diff --git a/arch/sh/lib64/memcpy.c b/arch/sh/lib64/memcpy.c
deleted file mode 100644
index fba436a..0000000
--- a/arch/sh/lib64/memcpy.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2002 Mark Debbage (Mark.Debbage@superh.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- */
-
-#include <linux/types.h>
-#include <asm/string.h>
-
-// This is a simplistic optimization of memcpy to increase the
-// granularity of access beyond one byte using aligned
-// loads and stores. This is not an optimal implementation
-// for SH-5 (especially with regard to prefetching and the cache),
-// and a better version should be provided later ...
-
-void *memcpy(void *dest, const void *src, size_t count)
-{
-	char *d = (char *) dest, *s = (char *) src;
-
-	if (count >= 32) {
-		int i = 8 - (((unsigned long) d) & 0x7);
-
-		if (i != 8)
-			while (i-- && count--) {
-				*d++ = *s++;
-			}
-
-		if (((((unsigned long) d) & 0x7) == 0) &&
-		    ((((unsigned long) s) & 0x7) == 0)) {
-			while (count >= 32) {
-				unsigned long long t1, t2, t3, t4;
-				t1 = *(unsigned long long *) (s);
-				t2 = *(unsigned long long *) (s + 8);
-				t3 = *(unsigned long long *) (s + 16);
-				t4 = *(unsigned long long *) (s + 24);
-				*(unsigned long long *) (d) = t1;
-				*(unsigned long long *) (d + 8) = t2;
-				*(unsigned long long *) (d + 16) = t3;
-				*(unsigned long long *) (d + 24) = t4;
-				d += 32;
-				s += 32;
-				count -= 32;
-			}
-			while (count >= 8) {
-				*(unsigned long long *) d =
-				    *(unsigned long long *) s;
-				d += 8;
-				s += 8;
-				count -= 8;
-			}
-		}
-
-		if (((((unsigned long) d) & 0x3) == 0) &&
-		    ((((unsigned long) s) & 0x3) == 0)) {
-			while (count >= 4) {
-				*(unsigned long *) d = *(unsigned long *) s;
-				d += 4;
-				s += 4;
-				count -= 4;
-			}
-		}
-
-		if (((((unsigned long) d) & 0x1) == 0) &&
-		    ((((unsigned long) s) & 0x1) == 0)) {
-			while (count >= 2) {
-				*(unsigned short *) d = *(unsigned short *) s;
-				d += 2;
-				s += 2;
-				count -= 2;
-			}
-		}
-	}
-
-	while (count--) {
-		*d++ = *s++;
-	}
-
-	return d;
-}
diff --git a/arch/sh/lib64/memset.S b/arch/sh/lib64/memset.S
new file mode 100644
index 0000000..2d37b04
--- /dev/null
+++ b/arch/sh/lib64/memset.S
@@ -0,0 +1,91 @@
+/* Cloned and hacked for uClibc by Paul Mundt, December 2003 */
+/* Modified by SuperH, Inc. September 2003 */
+!
+! Fast SH memset
+!
+! by Toshiyasu Morita (tm@netcom.com)
+!
+! SH5 code by J"orn Rennecke (joern.rennecke@superh.com)
+! Copyright 2002 SuperH Ltd.
+!
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define SHHI shlld
+#define SHLO shlrd
+#else
+#define SHHI shlrd
+#define SHLO shlld
+#endif
+
+	.section .text..SHmedia32,"ax"
+	.globl	memset
+	.type	memset, @function
+
+	.align 5
+
+memset:
+	pta/l multiquad, tr0
+	andi r2, 7, r22
+	ptabs r18, tr2
+	mshflo.b r3,r3,r3
+	add r4, r22, r23
+	mperm.w r3, r63, r3	// Fill pattern now in every byte of r3
+
+	movi 8, r9
+	bgtu/u r23, r9, tr0 // multiquad
+
+	beqi/u r4, 0, tr2       // Return with size 0 - ensures no mem accesses
+	ldlo.q r2, 0, r7
+	shlli r4, 2, r4
+	movi -1, r8
+	SHHI r8, r4, r8
+	SHHI r8, r4, r8
+	mcmv r7, r8, r3
+	stlo.q r2, 0, r3
+	blink tr2, r63
+
+multiquad:
+	pta/l lastquad, tr0
+	stlo.q r2, 0, r3
+	shlri r23, 3, r24
+	add r2, r4, r5
+	beqi/u r24, 1, tr0 // lastquad
+	pta/l loop, tr1
+	sub r2, r22, r25
+	andi r5, -8, r20   // calculate end address and
+	addi r20, -7*8, r8 // loop end address; This might overflow, so we need
+	                   // to use a different test before we start the loop
+	bge/u r24, r9, tr1 // loop
+	st.q r25, 8, r3
+	st.q r20, -8, r3
+	shlri r24, 1, r24
+	beqi/u r24, 1, tr0 // lastquad
+	st.q r25, 16, r3
+	st.q r20, -16, r3
+	beqi/u r24, 2, tr0 // lastquad
+	st.q r25, 24, r3
+	st.q r20, -24, r3
+lastquad:
+	sthi.q r5, -1, r3
+	blink tr2,r63
+
+loop:
+!!!	alloco r25, 32	// QQQ comment out for short-term fix to SHUK #3895.
+			// QQQ commenting out is locically correct, but sub-optimal
+			// QQQ Sean McGoogan - 4th April 2003.
+	st.q r25, 8, r3
+	st.q r25, 16, r3
+	st.q r25, 24, r3
+	st.q r25, 32, r3
+	addi r25, 32, r25
+	bgeu/l r8, r25, tr1 // loop
+
+	st.q r20, -40, r3
+	st.q r20, -32, r3
+	st.q r20, -24, r3
+	st.q r20, -16, r3
+	st.q r20, -8, r3
+	sthi.q r5, -1, r3
+	blink tr2,r63
+
+	.size	memset,.-memset
diff --git a/arch/sh/lib64/sdivsi3.S b/arch/sh/lib64/sdivsi3.S
new file mode 100644
index 0000000..6a800c6
--- /dev/null
+++ b/arch/sh/lib64/sdivsi3.S
@@ -0,0 +1,131 @@
+	.global	__sdivsi3
+	.section	.text..SHmedia32,"ax"
+	.align	2
+
+	/* inputs: r4,r5 */
+	/* clobbered: r1,r18,r19,r20,r21,r25,tr0 */
+	/* result in r0 */
+__sdivsi3:
+	ptb __div_table,tr0
+
+	nsb r5, r1
+	shlld r5, r1, r25    /* normalize; [-2 ..1, 1..2) in s2.62 */
+	shari r25, 58, r21   /* extract 5(6) bit index (s2.4 with hole -1..1) */
+	/* bubble */
+	gettr tr0,r20
+	ldx.ub r20, r21, r19 /* u0.8 */
+	shari r25, 32, r25   /* normalize to s2.30 */
+	shlli r21, 1, r21
+	muls.l r25, r19, r19 /* s2.38 */
+	ldx.w r20, r21, r21  /* s2.14 */
+	ptabs r18, tr0
+	shari r19, 24, r19   /* truncate to s2.14 */
+	sub r21, r19, r19    /* some 11 bit inverse in s1.14 */
+	muls.l r19, r19, r21 /* u0.28 */
+	sub r63, r1, r1
+	addi r1, 92, r1
+	muls.l r25, r21, r18 /* s2.58 */
+	shlli r19, 45, r19   /* multiply by two and convert to s2.58 */
+	/* bubble */
+	sub r19, r18, r18
+	shari r18, 28, r18   /* some 22 bit inverse in s1.30 */
+	muls.l r18, r25, r0  /* s2.60 */
+	muls.l r18, r4, r25 /* s32.30 */
+	/* bubble */
+	shari r0, 16, r19   /* s-16.44 */
+	muls.l r19, r18, r19 /* s-16.74 */
+	shari r25, 63, r0
+	shari r4, 14, r18   /* s19.-14 */
+	shari r19, 30, r19   /* s-16.44 */
+	muls.l r19, r18, r19 /* s15.30 */
+	xor r21, r0, r21    /* You could also use the constant 1 << 27. */
+	add r21, r25, r21
+	sub r21, r19, r21
+	shard r21, r1, r21
+	sub r21, r0, r0
+	blink tr0, r63
+	
+/* This table has been generated by divtab.c .
+Defects for bias -330:
+   Max defect: 6.081536e-07 at -1.000000e+00
+   Min defect: 2.849516e-08 at 1.030651e+00
+   Max 2nd step defect: 9.606539e-12 at -1.000000e+00
+   Min 2nd step defect: 0.000000e+00 at 0.000000e+00
+   Defect at 1: 1.238659e-07
+   Defect at -2: 1.061708e-07 */
+
+	.balign 2
+	.type	__div_table,@object
+	.size	__div_table,128
+/* negative division constants */
+	.word	-16638
+	.word	-17135
+	.word	-17737
+	.word	-18433
+	.word	-19103
+	.word	-19751
+	.word	-20583
+	.word	-21383
+	.word	-22343
+	.word	-23353
+	.word	-24407
+	.word	-25582
+	.word	-26863
+	.word	-28382
+	.word	-29965
+	.word	-31800
+/* negative division factors */
+	.byte	66
+	.byte	70
+	.byte	75
+	.byte	81
+	.byte	87
+	.byte	93
+	.byte	101
+	.byte	109
+	.byte	119
+	.byte	130
+	.byte	142
+	.byte	156
+	.byte	172
+	.byte	192
+	.byte	214
+	.byte	241
+	.skip 16
+	.global	__div_table
+__div_table:
+	.skip 16
+/* positive division factors */
+	.byte	241
+	.byte	214
+	.byte	192
+	.byte	172
+	.byte	156
+	.byte	142
+	.byte	130
+	.byte	119
+	.byte	109
+	.byte	101
+	.byte	93
+	.byte	87
+	.byte	81
+	.byte	75
+	.byte	70
+	.byte	66
+/* positive division constants */
+	.word	31801
+	.word	29966
+	.word	28383
+	.word	26864
+	.word	25583
+	.word	24408
+	.word	23354
+	.word	22344
+	.word	21384
+	.word	20584
+	.word	19752
+	.word	19104
+	.word	18434
+	.word	17738
+	.word	17136
+	.word	16639
diff --git a/arch/sh/lib64/strcpy.S b/arch/sh/lib64/strcpy.S
new file mode 100644
index 0000000..ea7c9c5
--- /dev/null
+++ b/arch/sh/lib64/strcpy.S
@@ -0,0 +1,97 @@
+/* Cloned and hacked for uClibc by Paul Mundt, December 2003 */
+/* Modified by SuperH, Inc. September 2003 */
+! Entry: arg0: destination
+!        arg1: source
+! Exit:  result: destination
+!
+! SH5 code Copyright 2002 SuperH Ltd.
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define SHHI shlld
+#define SHLO shlrd
+#else
+#define SHHI shlrd
+#define SHLO shlld
+#endif
+
+	.section .text..SHmedia32,"ax"
+	.globl	strcpy
+	.type	strcpy, @function
+	.align 5
+
+strcpy:
+
+	pta/l shortstring,tr1
+	ldlo.q r3,0,r4
+	ptabs r18,tr4
+	shlli r3,3,r7
+	addi r2, 8, r0
+	mcmpeq.b r4,r63,r6
+	SHHI r6,r7,r6
+	bnei/u r6,0,tr1 // shortstring
+	pta/l no_lddst, tr2
+	ori r3,-8,r23
+	sub r2, r23, r0
+	sub r3, r2, r21
+	addi r21, 8, r20
+	ldx.q r0, r21, r5
+	pta/l loop, tr0
+	ori r2,-8,r22
+	mcmpeq.b r5, r63, r6
+	bgt/u r22, r23, tr2 // no_lddst
+
+	// r22 < r23 :  Need to do a load from the destination.
+	// r22 == r23 : Doesn't actually need to load from destination,
+	//              but still can be handled here.
+	ldlo.q r2, 0, r9
+	movi -1, r8
+	SHLO r8, r7, r8
+	mcmv r4, r8, r9
+	stlo.q r2, 0, r9
+	beqi/l r6, 0, tr0 // loop
+
+	add r5, r63, r4
+	addi r0, 8, r0
+	blink tr1, r63 // shortstring
+no_lddst:
+	// r22 > r23: note that for r22 == r23 the sthi.q would clobber
+	//            bytes before the destination region.
+	stlo.q r2, 0, r4
+	SHHI r4, r7, r4
+	sthi.q r0, -1, r4
+	beqi/l r6, 0, tr0 // loop
+
+	add r5, r63, r4
+	addi r0, 8, r0
+shortstring:
+#if __BYTE_ORDER != __LITTLE_ENDIAN
+	pta/l shortstring2,tr1
+	byterev r4,r4
+#endif
+shortstring2:
+	st.b r0,-8,r4
+	andi r4,0xff,r5
+	shlri r4,8,r4
+	addi r0,1,r0
+	bnei/l r5,0,tr1
+	blink tr4,r63 // return
+	
+	.balign 8
+loop:
+	stlo.q r0, 0, r5
+	ldx.q r0, r20, r4
+	addi r0, 16, r0
+	sthi.q r0, -9, r5
+	mcmpeq.b r4, r63, r6
+	bnei/u r6, 0, tr1 // shortstring
+	ldx.q r0, r21, r5
+	stlo.q r0, -8, r4
+	sthi.q r0, -1, r4
+	mcmpeq.b r5, r63, r6
+	beqi/l r6, 0, tr0 // loop
+
+	add r5, r63, r4
+	addi r0, 8, r0
+	blink tr1, r63 // shortstring
+
+	.size	strcpy,.-strcpy
diff --git a/arch/sh/lib64/strlen.S b/arch/sh/lib64/strlen.S
new file mode 100644
index 0000000..cbc0d91
--- /dev/null
+++ b/arch/sh/lib64/strlen.S
@@ -0,0 +1,33 @@
+/*
+ * Simplistic strlen() implementation for SHmedia.
+ *
+ * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
+ */
+
+	.section .text..SHmedia32,"ax"
+	.globl	strlen
+	.type	strlen,@function
+
+	.balign 16
+strlen:
+	ptabs	r18, tr4
+
+	/*
+	 * Note: We could easily deal with the NULL case here with a simple
+	 * sanity check, though it seems that the behavior we want is to fault
+	 * in the event that r2 == NULL, so we don't bother.
+	 */
+/*	beqi    r2, 0, tr4 */	! Sanity check
+
+	movi	-1, r0
+	pta/l	loop, tr0
+loop:
+	ld.b	r2, 0, r1
+	addi	r2, 1, r2
+	addi	r0, 1, r0
+	bnei/l	r1, 0, tr0
+
+	or	r0, r63, r2
+	blink	tr4, r63
+
+	.size	strlen,.-strlen
diff --git a/arch/sh/lib64/udivdi3.S b/arch/sh/lib64/udivdi3.S
new file mode 100644
index 0000000..6895c02
--- /dev/null
+++ b/arch/sh/lib64/udivdi3.S
@@ -0,0 +1,120 @@
+	.section	.text..SHmedia32,"ax"
+	.align	2
+	.global	__udivdi3
+__udivdi3:
+	shlri r3,1,r4
+	nsb r4,r22
+	shlld r3,r22,r6
+	shlri r6,49,r5
+	movi 0xffffffffffffbaf1,r21 /* .l shift count 17.  */
+	sub r21,r5,r1
+	mmulfx.w r1,r1,r4
+	mshflo.w r1,r63,r1
+	sub r63,r22,r20 // r63 == 64 % 64
+	mmulfx.w r5,r4,r4
+	pta large_divisor,tr0
+	addi r20,32,r9
+	msub.w r1,r4,r1
+	madd.w r1,r1,r1
+	mmulfx.w r1,r1,r4
+	shlri r6,32,r7
+	bgt/u r9,r63,tr0 // large_divisor
+	mmulfx.w r5,r4,r4
+	shlri r2,32+14,r19
+	addi r22,-31,r0
+	msub.w r1,r4,r1
+
+	mulu.l r1,r7,r4
+	addi r1,-3,r5
+	mulu.l r5,r19,r5
+	sub r63,r4,r4 // Negate to make sure r1 ends up <= 1/r2
+	shlri r4,2,r4 /* chop off leading %0000000000000000 001.00000000000 - or, as
+	                 the case may be, %0000000000000000 000.11111111111, still */
+	muls.l r1,r4,r4 /* leaving at least one sign bit.  */
+	mulu.l r5,r3,r8
+	mshalds.l r1,r21,r1
+	shari r4,26,r4
+	shlld r8,r0,r8
+	add r1,r4,r1 // 31 bit unsigned reciprocal now in r1 (msb equiv. 0.5)
+	sub r2,r8,r2
+	/* Can do second step of 64 : 32 div now, using r1 and the rest in r2.  */
+
+	shlri r2,22,r21
+	mulu.l r21,r1,r21
+	shlld r5,r0,r8
+	addi r20,30-22,r0
+	shlrd r21,r0,r21
+	mulu.l r21,r3,r5
+	add r8,r21,r8
+	mcmpgt.l r21,r63,r21 // See Note 1
+	addi r20,30,r0
+	mshfhi.l r63,r21,r21
+	sub r2,r5,r2
+	andc r2,r21,r2
+
+	/* small divisor: need a third divide step */
+	mulu.l r2,r1,r7
+	ptabs r18,tr0
+	addi r2,1,r2
+	shlrd r7,r0,r7
+	mulu.l r7,r3,r5
+	add r8,r7,r8
+	sub r2,r3,r2
+	cmpgt r2,r5,r5
+	add r8,r5,r2
+	/* could test r3 here to check for divide by zero.  */
+	blink tr0,r63
+
+large_divisor:
+	mmulfx.w r5,r4,r4
+	shlrd r2,r9,r25
+	shlri r25,32,r8
+	msub.w r1,r4,r1
+
+	mulu.l r1,r7,r4
+	addi r1,-3,r5
+	mulu.l r5,r8,r5
+	sub r63,r4,r4 // Negate to make sure r1 ends up <= 1/r2
+	shlri r4,2,r4 /* chop off leading %0000000000000000 001.00000000000 - or, as
+	                 the case may be, %0000000000000000 000.11111111111, still */
+	muls.l r1,r4,r4 /* leaving at least one sign bit.  */
+	shlri r5,14-1,r8
+	mulu.l r8,r7,r5
+	mshalds.l r1,r21,r1
+	shari r4,26,r4
+	add r1,r4,r1 // 31 bit unsigned reciprocal now in r1 (msb equiv. 0.5)
+	sub r25,r5,r25
+	/* Can do second step of 64 : 32 div now, using r1 and the rest in r25.  */
+
+	shlri r25,22,r21
+	mulu.l r21,r1,r21
+	pta no_lo_adj,tr0
+	addi r22,32,r0
+	shlri r21,40,r21
+	mulu.l r21,r7,r5
+	add r8,r21,r8
+	shlld r2,r0,r2
+	sub r25,r5,r25
+	bgtu/u r7,r25,tr0 // no_lo_adj
+	addi r8,1,r8
+	sub r25,r7,r25
+no_lo_adj:
+	mextr4 r2,r25,r2
+
+	/* large_divisor: only needs a few adjustments.  */
+	mulu.l r8,r6,r5
+	ptabs r18,tr0
+	/* bubble */
+	cmpgtu r5,r2,r5
+	sub r8,r5,r2
+	blink tr0,r63
+	
+/* Note 1: To shift the result of the second divide stage so that the result
+   always fits into 32 bits, yet we still reduce the rest sufficiently
+   would require a lot of instructions to do the shifts just right.  Using
+   the full 64 bit shift result to multiply with the divisor would require
+   four extra instructions for the upper 32 bits (shift / mulu / shift / sub).
+   Fortunately, if the upper 32 bits of the shift result are nonzero, we
+   know that the rest after taking this partial result into account will
+   fit into 32 bits.  So we just clear the upper 32 bits of the rest if the
+   upper 32 bits of the partial result are nonzero.  */
diff --git a/arch/sh/lib64/udivsi3.S b/arch/sh/lib64/udivsi3.S
new file mode 100644
index 0000000..e68120e
--- /dev/null
+++ b/arch/sh/lib64/udivsi3.S
@@ -0,0 +1,59 @@
+	.global	__udivsi3
+	.section	.text..SHmedia32,"ax"
+	.align	2
+
+/*
+   inputs: r4,r5
+   clobbered: r18,r19,r20,r21,r22,r25,tr0
+   result in r0.
+ */
+__udivsi3:
+	addz.l r5,r63,r22
+	nsb r22,r0
+	shlld r22,r0,r25
+	shlri r25,48,r25
+	movi 0xffffffffffffbb0c,r20 /* shift count eqiv 76 */
+	sub r20,r25,r21
+	mmulfx.w r21,r21,r19
+	mshflo.w r21,r63,r21
+	ptabs r18,tr0
+	mmulfx.w r25,r19,r19
+	sub r20,r0,r0
+	/* bubble */
+	msub.w r21,r19,r19
+
+	/*
+	 * It would be nice for scheduling to do this add to r21 before
+	 * the msub.w, but we need a different value for r19 to keep
+	 * errors under control.
+	 */
+	addi r19,-2,r21
+	mulu.l r4,r21,r18
+	mmulfx.w r19,r19,r19
+	shlli r21,15,r21
+	shlrd r18,r0,r18
+	mulu.l r18,r22,r20
+	mmacnfx.wl r25,r19,r21
+	/* bubble */
+	sub r4,r20,r25
+
+	mulu.l r25,r21,r19
+	addi r0,14,r0
+	/* bubble */
+	shlrd r19,r0,r19
+	mulu.l r19,r22,r20
+	add r18,r19,r18
+	/* bubble */
+	sub.l r25,r20,r25
+
+	mulu.l r25,r21,r19
+	addz.l r25,r63,r25
+	sub r25,r22,r25
+	shlrd r19,r0,r19
+	mulu.l r19,r22,r20
+	addi r25,1,r25
+	add r18,r19,r18
+
+	cmpgt r25,r20,r25
+	add.l r18,r25,r0
+	blink tr0,r63
diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32
index f066e76..cb2f3f2 100644
--- a/arch/sh/mm/Makefile_32
+++ b/arch/sh/mm/Makefile_32
@@ -18,6 +18,7 @@
 mmu-$(CONFIG_MMU)	:= fault_32.o tlbflush_32.o ioremap_32.o
 
 obj-y			+= $(mmu-y)
+obj-$(CONFIG_DEBUG_FS)	+= asids-debugfs.o
 
 ifdef CONFIG_DEBUG_FS
 obj-$(CONFIG_CPU_SH4)	+= cache-debugfs.o
diff --git a/arch/sh/mm/Makefile_64 b/arch/sh/mm/Makefile_64
index 9481d0f..2863ffb 100644
--- a/arch/sh/mm/Makefile_64
+++ b/arch/sh/mm/Makefile_64
@@ -13,6 +13,7 @@
 endif
 
 obj-y			+= $(mmu-y)
+obj-$(CONFIG_DEBUG_FS)	+= asids-debugfs.o
 
 obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
 obj-$(CONFIG_NUMA)		+= numa.o
diff --git a/arch/sh/mm/asids-debugfs.c b/arch/sh/mm/asids-debugfs.c
new file mode 100644
index 0000000..8e912a1
--- /dev/null
+++ b/arch/sh/mm/asids-debugfs.c
@@ -0,0 +1,79 @@
+/*
+ * debugfs ops for process ASIDs
+ *
+ *  Copyright (C) 2000, 2001  Paolo Alberelli
+ *  Copyright (C) 2003 - 2008  Paul Mundt
+ *  Copyright (C) 2003, 2004  Richard Curnow
+ *
+ * Provides a debugfs file that lists out the ASIDs currently associated
+ * with the processes.
+ *
+ * In the SH-5 case, if the DM.PC register is examined through the debug
+ * link, this shows ASID + PC. To make use of this, the PID->ASID
+ * relationship needs to be known. This is primarily for debugging.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/mmu_context.h>
+
+static int asids_seq_show(struct seq_file *file, void *iter)
+{
+	struct task_struct *p;
+
+	read_lock(&tasklist_lock);
+
+	for_each_process(p) {
+		int pid = p->pid;
+
+		if (unlikely(!pid))
+			continue;
+
+		if (p->mm)
+			seq_printf(file, "%5d : %02lx\n", pid,
+				   cpu_asid(smp_processor_id(), p->mm));
+		else
+			seq_printf(file, "%5d : (none)\n", pid);
+	}
+
+	read_unlock(&tasklist_lock);
+
+	return 0;
+}
+
+static int asids_debugfs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, asids_seq_show, inode->i_private);
+}
+
+static const struct file_operations asids_debugfs_fops = {
+	.owner		= THIS_MODULE,
+	.open		= asids_debugfs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init asids_debugfs_init(void)
+{
+	struct dentry *asids_dentry;
+
+	asids_dentry = debugfs_create_file("asids", S_IRUSR, sh_debugfs_root,
+					   NULL, &asids_debugfs_fops);
+	if (!asids_dentry)
+		return -ENOMEM;
+	if (IS_ERR(asids_dentry))
+		return PTR_ERR(asids_dentry);
+
+	return 0;
+}
+module_init(asids_debugfs_init);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index 9f8ea3a..edcd5fb 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -42,6 +42,8 @@
 		return NULL;
 	}
 
+	split_page(pfn_to_page(virt_to_phys(ret) >> PAGE_SHIFT), order);
+
 	*dma_handle = virt_to_phys(ret);
 	return ret_nocache;
 }
@@ -51,10 +53,13 @@
 			 void *vaddr, dma_addr_t dma_handle)
 {
 	int order = get_order(size);
+	unsigned long pfn = dma_handle >> PAGE_SHIFT;
+	int k;
 
 	if (!dma_release_from_coherent(dev, order, vaddr)) {
 		WARN_ON(irqs_disabled());	/* for portability */
-		free_pages((unsigned long)phys_to_virt(dma_handle), order);
+		for (k = 0; k < (1 << order); k++)
+			__free_pages(pfn_to_page(pfn + k), 0);
 		iounmap(vaddr);
 	}
 }
diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c
index 898d477..31a33eb 100644
--- a/arch/sh/mm/fault_32.c
+++ b/arch/sh/mm/fault_32.c
@@ -20,7 +20,6 @@
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
-#include <asm/kgdb.h>
 
 /*
  * This routine handles page faults.  It determines the address,
@@ -265,17 +264,6 @@
 	return ret;
 }
 
-#ifdef CONFIG_SH_STORE_QUEUES
-/*
- * This is a special case for the SH-4 store queues, as pages for this
- * space still need to be faulted in before it's possible to flush the
- * store queue cache for writeout to the remapped region.
- */
-#define P3_ADDR_MAX		(P4SEG_STORE_QUE + 0x04000000)
-#else
-#define P3_ADDR_MAX		P4SEG
-#endif
-
 /*
  * Called with interrupts disabled.
  */
@@ -293,11 +281,6 @@
 	if (notify_page_fault(regs, lookup_exception_vector()))
 		goto out;
 
-#ifdef CONFIG_SH_KGDB
-	if (kgdb_nofault && kgdb_bus_err_hook)
-		kgdb_bus_err_hook();
-#endif
-
 	ret = 1;
 
 	/*
diff --git a/arch/sh/mm/ioremap_32.c b/arch/sh/mm/ioremap_32.c
index 882a32e..32946fb 100644
--- a/arch/sh/mm/ioremap_32.c
+++ b/arch/sh/mm/ioremap_32.c
@@ -116,9 +116,10 @@
 void __iounmap(void __iomem *addr)
 {
 	unsigned long vaddr = (unsigned long __force)addr;
+	unsigned long seg = PXSEG(vaddr);
 	struct vm_struct *p;
 
-	if (PXSEG(vaddr) < P3SEG || is_pci_memaddr(vaddr))
+	if (seg < P3SEG || seg >= P3_ADDR_MAX || is_pci_memaddr(vaddr))
 		return;
 
 #ifdef CONFIG_32BIT
diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c
index 8837d51..931f4d0 100644
--- a/arch/sh/mm/mmap.c
+++ b/arch/sh/mm/mmap.c
@@ -9,7 +9,101 @@
  */
 #include <linux/io.h>
 #include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/module.h>
 #include <asm/page.h>
+#include <asm/processor.h>
+
+#ifdef CONFIG_MMU
+unsigned long shm_align_mask = PAGE_SIZE - 1;	/* Sane caches */
+EXPORT_SYMBOL(shm_align_mask);
+
+/*
+ * To avoid cache aliases, we map the shared page with same color.
+ */
+#define COLOUR_ALIGN(addr, pgoff)				\
+	((((addr) + shm_align_mask) & ~shm_align_mask) +	\
+	 (((pgoff) << PAGE_SHIFT) & shm_align_mask))
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+	unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	unsigned long start_addr;
+	int do_colour_align;
+
+	if (flags & MAP_FIXED) {
+		/* We do not accept a shared mapping if it would violate
+		 * cache aliasing constraints.
+		 */
+		if ((flags & MAP_SHARED) && (addr & shm_align_mask))
+			return -EINVAL;
+		return addr;
+	}
+
+	if (unlikely(len > TASK_SIZE))
+		return -ENOMEM;
+
+	do_colour_align = 0;
+	if (filp || (flags & MAP_SHARED))
+		do_colour_align = 1;
+
+	if (addr) {
+		if (do_colour_align)
+			addr = COLOUR_ALIGN(addr, pgoff);
+		else
+			addr = PAGE_ALIGN(addr);
+
+		vma = find_vma(mm, addr);
+		if (TASK_SIZE - len >= addr &&
+		    (!vma || addr + len <= vma->vm_start))
+			return addr;
+	}
+
+	if (len > mm->cached_hole_size) {
+		start_addr = addr = mm->free_area_cache;
+	} else {
+	        mm->cached_hole_size = 0;
+		start_addr = addr = TASK_UNMAPPED_BASE;
+	}
+
+full_search:
+	if (do_colour_align)
+		addr = COLOUR_ALIGN(addr, pgoff);
+	else
+		addr = PAGE_ALIGN(mm->free_area_cache);
+
+	for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
+		/* At this point:  (!vma || addr < vma->vm_end). */
+		if (unlikely(TASK_SIZE - len < addr)) {
+			/*
+			 * Start a new search - just in case we missed
+			 * some holes.
+			 */
+			if (start_addr != TASK_UNMAPPED_BASE) {
+				start_addr = addr = TASK_UNMAPPED_BASE;
+				mm->cached_hole_size = 0;
+				goto full_search;
+			}
+			return -ENOMEM;
+		}
+		if (likely(!vma || addr + len <= vma->vm_start)) {
+			/*
+			 * Remember the place where we stopped the search:
+			 */
+			mm->free_area_cache = addr + len;
+			return addr;
+		}
+		if (addr + mm->cached_hole_size < vma->vm_start)
+		        mm->cached_hole_size = vma->vm_start - addr;
+
+		addr = vma->vm_end;
+		if (do_colour_align)
+			addr = COLOUR_ALIGN(addr, pgoff);
+	}
+}
+#endif /* CONFIG_MMU */
 
 /*
  * You really shouldn't be using read() or write() on /dev/mem.  This
diff --git a/arch/sh/oprofile/Makefile b/arch/sh/oprofile/Makefile
index 2efc2e7..8e6eec9 100644
--- a/arch/sh/oprofile/Makefile
+++ b/arch/sh/oprofile/Makefile
@@ -6,13 +6,8 @@
 		oprofilefs.o oprofile_stats.o \
 		timer_int.o )
 
-profdrvr-y				:= op_model_null.o
+oprofile-y	:= $(DRIVER_OBJS) common.o backtrace.o
 
-# SH7750-style performance counters exist across 7750/7750S and 7091.
-profdrvr-$(CONFIG_CPU_SUBTYPE_SH7750S)	:= op_model_sh7750.o
-profdrvr-$(CONFIG_CPU_SUBTYPE_SH7750)	:= op_model_sh7750.o
-profdrvr-$(CONFIG_CPU_SUBTYPE_SH7091)	:= op_model_sh7750.o
-
-oprofile-y				:= $(DRIVER_OBJS) $(profdrvr-y)
-
-EXTRA_CFLAGS += -Werror
+oprofile-$(CONFIG_CPU_SUBTYPE_SH7750S)	+= op_model_sh7750.o
+oprofile-$(CONFIG_CPU_SUBTYPE_SH7750)	+= op_model_sh7750.o
+oprofile-$(CONFIG_CPU_SUBTYPE_SH7091)	+= op_model_sh7750.o
diff --git a/arch/sh/oprofile/backtrace.c b/arch/sh/oprofile/backtrace.c
new file mode 100644
index 0000000..9499a29
--- /dev/null
+++ b/arch/sh/oprofile/backtrace.c
@@ -0,0 +1,114 @@
+/*
+ * SH specific backtracing code for oprofile
+ *
+ * Copyright 2007 STMicroelectronics Ltd.
+ *
+ * Author: Dave Peverley <dpeverley@mpc-data.co.uk>
+ *
+ * Based on ARM oprofile backtrace code by Richard Purdie and in turn, i386
+ * oprofile backtrace code by John Levon, David Smith
+ *
+ * This program is free software; you can 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/oprofile.h>
+#include <linux/sched.h>
+#include <linux/kallsyms.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+#include <asm/sections.h>
+
+/* Limit to stop backtracing too far. */
+static int backtrace_limit = 20;
+
+static unsigned long *
+user_backtrace(unsigned long *stackaddr, struct pt_regs *regs)
+{
+	unsigned long buf_stack;
+
+	/* Also check accessibility of address */
+	if (!access_ok(VERIFY_READ, stackaddr, sizeof(unsigned long)))
+		return NULL;
+
+	if (__copy_from_user_inatomic(&buf_stack, stackaddr, sizeof(unsigned long)))
+		return NULL;
+
+	/* Quick paranoia check */
+	if (buf_stack & 3)
+		return NULL;
+
+	oprofile_add_trace(buf_stack);
+
+	stackaddr++;
+
+	return stackaddr;
+}
+
+/*
+ * |             | /\ Higher addresses
+ * |             |
+ * --------------- stack base (address of current_thread_info)
+ * | thread info |
+ * .             .
+ * |    stack    |
+ * --------------- saved regs->regs[15] value if valid
+ * .             .
+ * --------------- struct pt_regs stored on stack (struct pt_regs *)
+ * |             |
+ * .             .
+ * |             |
+ * --------------- ???
+ * |             |
+ * |             | \/ Lower addresses
+ *
+ * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values
+ */
+static int valid_kernel_stack(unsigned long *stackaddr, struct pt_regs *regs)
+{
+	unsigned long stack = (unsigned long)regs;
+	unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
+
+	return ((unsigned long)stackaddr > stack) && ((unsigned long)stackaddr < stack_base);
+}
+
+static unsigned long *
+kernel_backtrace(unsigned long *stackaddr, struct pt_regs *regs)
+{
+	unsigned long addr;
+
+	/*
+	 * If not a valid kernel address, keep going till we find one
+	 * or the SP stops being a valid address.
+	 */
+	do {
+		addr = *stackaddr++;
+		oprofile_add_trace(addr);
+	} while (valid_kernel_stack(stackaddr, regs));
+
+	return stackaddr;
+}
+
+void sh_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+	unsigned long *stackaddr;
+
+	/*
+	 * Paranoia - clip max depth as we could get lost in the weeds.
+	 */
+	if (depth > backtrace_limit)
+		depth = backtrace_limit;
+
+	stackaddr = (unsigned long *)regs->regs[15];
+	if (!user_mode(regs)) {
+		while (depth-- && valid_kernel_stack(stackaddr, regs))
+			stackaddr = kernel_backtrace(stackaddr, regs);
+
+		return;
+	}
+
+	while (depth-- && (stackaddr != NULL))
+		stackaddr = user_backtrace(stackaddr, regs);
+}
diff --git a/arch/sh/oprofile/common.c b/arch/sh/oprofile/common.c
new file mode 100644
index 0000000..1d97d64
--- /dev/null
+++ b/arch/sh/oprofile/common.c
@@ -0,0 +1,150 @@
+/*
+ * arch/sh/oprofile/init.c
+ *
+ * Copyright (C) 2003 - 2008  Paul Mundt
+ *
+ * Based on arch/mips/oprofile/common.c:
+ *
+ *	Copyright (C) 2004, 2005 Ralf Baechle
+ *	Copyright (C) 2005 MIPS Technologies, 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/kernel.h>
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <asm/processor.h>
+#include "op_impl.h"
+
+extern struct op_sh_model op_model_sh7750_ops __weak;
+extern struct op_sh_model op_model_sh4a_ops __weak;
+
+static struct op_sh_model *model;
+
+static struct op_counter_config ctr[20];
+
+extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth);
+
+static int op_sh_setup(void)
+{
+	/* Pre-compute the values to stuff in the hardware registers.  */
+	model->reg_setup(ctr);
+
+	/* Configure the registers on all cpus.  */
+	on_each_cpu(model->cpu_setup, NULL, 1);
+
+        return 0;
+}
+
+static int op_sh_create_files(struct super_block *sb, struct dentry *root)
+{
+	int i, ret = 0;
+
+	for (i = 0; i < model->num_counters; i++) {
+		struct dentry *dir;
+		char buf[4];
+
+		snprintf(buf, sizeof(buf), "%d", i);
+		dir = oprofilefs_mkdir(sb, root, buf);
+
+		ret |= oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
+		ret |= oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
+		ret |= oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
+		ret |= oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
+
+		if (model->create_files)
+			ret |= model->create_files(sb, dir);
+		else
+			ret |= oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
+
+		/* Dummy entries */
+		ret |= oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
+	}
+
+	return ret;
+}
+
+static int op_sh_start(void)
+{
+	/* Enable performance monitoring for all counters.  */
+	on_each_cpu(model->cpu_start, NULL, 1);
+
+	return 0;
+}
+
+static void op_sh_stop(void)
+{
+	/* Disable performance monitoring for all counters.  */
+	on_each_cpu(model->cpu_stop, NULL, 1);
+}
+
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+	struct op_sh_model *lmodel = NULL;
+	int ret;
+
+	/*
+	 * Always assign the backtrace op. If the counter initialization
+	 * fails, we fall back to the timer which will still make use of
+	 * this.
+	 */
+	ops->backtrace = sh_backtrace;
+
+	switch (current_cpu_data.type) {
+	/* SH-4 types */
+	case CPU_SH7750:
+	case CPU_SH7750S:
+		lmodel = &op_model_sh7750_ops;
+		break;
+
+        /* SH-4A types */
+	case CPU_SH7763:
+	case CPU_SH7770:
+	case CPU_SH7780:
+	case CPU_SH7781:
+	case CPU_SH7785:
+	case CPU_SH7723:
+	case CPU_SHX3:
+		lmodel = &op_model_sh4a_ops;
+		break;
+
+	/* SH4AL-DSP types */
+	case CPU_SH7343:
+	case CPU_SH7722:
+	case CPU_SH7366:
+		lmodel = &op_model_sh4a_ops;
+		break;
+	}
+
+	if (!lmodel)
+		return -ENODEV;
+	if (!(current_cpu_data.flags & CPU_HAS_PERF_COUNTER))
+		return -ENODEV;
+
+	ret = lmodel->init();
+	if (unlikely(ret != 0))
+		return ret;
+
+	model = lmodel;
+
+	ops->setup		= op_sh_setup;
+	ops->create_files	= op_sh_create_files;
+	ops->start		= op_sh_start;
+	ops->stop		= op_sh_stop;
+	ops->cpu_type		= lmodel->cpu_type;
+
+	printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
+	       lmodel->cpu_type);
+
+	return 0;
+}
+
+void oprofile_arch_exit(void)
+{
+	if (model && model->exit)
+		model->exit();
+}
diff --git a/arch/sh/oprofile/op_impl.h b/arch/sh/oprofile/op_impl.h
new file mode 100644
index 0000000..4d50997
--- /dev/null
+++ b/arch/sh/oprofile/op_impl.h
@@ -0,0 +1,33 @@
+#ifndef __OP_IMPL_H
+#define __OP_IMPL_H
+
+/* Per-counter configuration as set via oprofilefs.  */
+struct op_counter_config {
+	unsigned long enabled;
+	unsigned long event;
+
+	unsigned long long count;
+
+	/* Dummy values for userspace tool compliance */
+	unsigned long kernel;
+	unsigned long user;
+	unsigned long unit_mask;
+};
+
+/* Per-architecture configury and hooks.  */
+struct op_sh_model {
+	void (*reg_setup)(struct op_counter_config *);
+	int (*create_files)(struct super_block *sb, struct dentry *dir);
+	void (*cpu_setup)(void *dummy);
+	int (*init)(void);
+	void (*exit)(void);
+	void (*cpu_start)(void *args);
+	void (*cpu_stop)(void *args);
+	char *cpu_type;
+	unsigned char num_counters;
+};
+
+/* arch/sh/oprofile/common.c */
+extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth);
+
+#endif /* __OP_IMPL_H */
diff --git a/arch/sh/oprofile/op_model_null.c b/arch/sh/oprofile/op_model_null.c
deleted file mode 100644
index a845b08..0000000
--- a/arch/sh/oprofile/op_model_null.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * arch/sh/oprofile/op_model_null.c
- *
- * Copyright (C) 2003  Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/kernel.h>
-#include <linux/oprofile.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-
-int __init oprofile_arch_init(struct oprofile_operations *ops)
-{
-	return -ENODEV;
-}
-
-void oprofile_arch_exit(void)
-{
-}
-
diff --git a/arch/sh/oprofile/op_model_sh7750.c b/arch/sh/oprofile/op_model_sh7750.c
index 008b3b0..c892c7c 100644
--- a/arch/sh/oprofile/op_model_sh7750.c
+++ b/arch/sh/oprofile/op_model_sh7750.c
@@ -3,7 +3,7 @@
  *
  * OProfile support for SH7750/SH7750S Performance Counters
  *
- * Copyright (C) 2003, 2004  Paul Mundt
+ * Copyright (C) 2003 - 2008  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -15,19 +15,16 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/fs.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include "op_impl.h"
 
 #define PM_CR_BASE	0xff000084	/* 16-bit */
 #define PM_CTR_BASE	0xff100004	/* 32-bit */
 
-#define PMCR1		(PM_CR_BASE  + 0x00)
-#define PMCR2		(PM_CR_BASE  + 0x04)
-#define PMCTR1H		(PM_CTR_BASE + 0x00)
-#define PMCTR1L		(PM_CTR_BASE + 0x04)
-#define PMCTR2H		(PM_CTR_BASE + 0x08)
-#define PMCTR2L		(PM_CTR_BASE + 0x0c)
+#define PMCR(n)		(PM_CR_BASE + ((n) * 0x04))
+#define PMCTRH(n)	(PM_CTR_BASE + 0x00 + ((n) * 0x08))
+#define PMCTRL(n)	(PM_CTR_BASE + 0x04 + ((n) * 0x08))
 
 #define PMCR_PMM_MASK	0x0000003f
 
@@ -36,25 +33,15 @@
 #define PMCR_PMST	0x00004000
 #define PMCR_PMEN	0x00008000
 
-#define PMCR_ENABLE	(PMCR_PMST | PMCR_PMEN)
+struct op_sh_model op_model_sh7750_ops;
 
-/*
- * SH7750/SH7750S have 2 perf counters
- */
 #define NR_CNTRS	2
 
-struct op_counter_config {
-	unsigned long enabled;
-	unsigned long event;
-	unsigned long count;
-
-	/* Dummy values for userspace tool compliance */
-	unsigned long kernel;
-	unsigned long user;
-	unsigned long unit_mask;
-};
-
-static struct op_counter_config ctr[NR_CNTRS];
+static struct sh7750_ppc_register_config {
+	unsigned int ctrl;
+	unsigned long cnt_hi;
+	unsigned long cnt_lo;
+} regcache[NR_CNTRS];
 
 /*
  * There are a number of events supported by each counter (33 in total).
@@ -116,12 +103,8 @@
 
 static u64 sh7750_read_counter(int counter)
 {
-	u32 hi, lo;
-
-	hi = (counter == 0) ? ctrl_inl(PMCTR1H) : ctrl_inl(PMCTR2H);
-	lo = (counter == 0) ? ctrl_inl(PMCTR1L) : ctrl_inl(PMCTR2L);
-
-	return (u64)((u64)(hi & 0xffff) << 32) | lo;
+	return (u64)((u64)(__raw_readl(PMCTRH(counter)) & 0xffff) << 32) |
+			   __raw_readl(PMCTRL(counter));
 }
 
 /*
@@ -170,11 +153,7 @@
 	 */
 	WARN_ON(val != 0);
 
-	if (counter == 0) {
-		ctrl_outw(ctrl_inw(PMCR1) | PMCR_PMCLR, PMCR1);
-	} else {
-		ctrl_outw(ctrl_inw(PMCR2) | PMCR_PMCLR, PMCR2);
-	}
+	__raw_writew(__raw_readw(PMCR(counter)) | PMCR_PMCLR, PMCR(counter));
 
 	return count;
 }
@@ -184,88 +163,93 @@
 	.write		= sh7750_write_count,
 };
 
-static int sh7750_perf_counter_create_files(struct super_block *sb, struct dentry *root)
+static int sh7750_ppc_create_files(struct super_block *sb, struct dentry *dir)
 {
-	int i;
-
-	for (i = 0; i < NR_CNTRS; i++) {
-		struct dentry *dir;
-		char buf[4];
-
-		snprintf(buf, sizeof(buf), "%d", i);
-		dir = oprofilefs_mkdir(sb, root, buf);
-
-		oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
-		oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
-		oprofilefs_create_file(sb, dir, "count", &count_fops);
-
-		/* Dummy entries */
-		oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
-		oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
-		oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
-	}
-
-	return 0;
+	return oprofilefs_create_file(sb, dir, "count", &count_fops);
 }
 
-static int sh7750_perf_counter_start(void)
+static void sh7750_ppc_reg_setup(struct op_counter_config *ctr)
 {
-	u16 pmcr;
+	unsigned int counters = op_model_sh7750_ops.num_counters;
+	int i;
 
-	/* Enable counter 1 */
-	if (ctr[0].enabled) {
-		pmcr = ctrl_inw(PMCR1);
-		WARN_ON(pmcr & PMCR_PMEN);
+	for (i = 0; i < counters; i++) {
+		regcache[i].ctrl	= 0;
+		regcache[i].cnt_hi	= 0;
+		regcache[i].cnt_lo	= 0;
 
-		pmcr &= ~PMCR_PMM_MASK;
-		pmcr |= ctr[0].event;
-		ctrl_outw(pmcr | PMCR_ENABLE, PMCR1);
+		if (!ctr[i].enabled)
+			continue;
+
+		regcache[i].ctrl |= ctr[i].event | PMCR_PMEN | PMCR_PMST;
+		regcache[i].cnt_hi = (unsigned long)((ctr->count >> 32) & 0xffff);
+		regcache[i].cnt_lo = (unsigned long)(ctr->count & 0xffffffff);
 	}
+}
 
-	/* Enable counter 2 */
-	if (ctr[1].enabled) {
-		pmcr = ctrl_inw(PMCR2);
-		WARN_ON(pmcr & PMCR_PMEN);
+static void sh7750_ppc_cpu_setup(void *args)
+{
+	unsigned int counters = op_model_sh7750_ops.num_counters;
+	int i;
 
-		pmcr &= ~PMCR_PMM_MASK;
-		pmcr |= ctr[1].event;
-		ctrl_outw(pmcr | PMCR_ENABLE, PMCR2);
+	for (i = 0; i < counters; i++) {
+		__raw_writew(0, PMCR(i));
+		__raw_writel(regcache[i].cnt_hi, PMCTRH(i));
+		__raw_writel(regcache[i].cnt_lo, PMCTRL(i));
 	}
+}
+
+static void sh7750_ppc_cpu_start(void *args)
+{
+	unsigned int counters = op_model_sh7750_ops.num_counters;
+	int i;
+
+	for (i = 0; i < counters; i++)
+		__raw_writew(regcache[i].ctrl, PMCR(i));
+}
+
+static void sh7750_ppc_cpu_stop(void *args)
+{
+	unsigned int counters = op_model_sh7750_ops.num_counters;
+	int i;
+
+	/* Disable the counters */
+	for (i = 0; i < counters; i++)
+		__raw_writew(__raw_readw(PMCR(i)) & ~PMCR_PMEN, PMCR(i));
+}
+
+static inline void sh7750_ppc_reset(void)
+{
+	unsigned int counters = op_model_sh7750_ops.num_counters;
+	int i;
+
+	/* Clear the counters */
+	for (i = 0; i < counters; i++)
+		__raw_writew(__raw_readw(PMCR(i)) | PMCR_PMCLR, PMCR(i));
+}
+
+static int sh7750_ppc_init(void)
+{
+	sh7750_ppc_reset();
 
 	return register_timer_hook(sh7750_timer_notify);
 }
 
-static void sh7750_perf_counter_stop(void)
+static void sh7750_ppc_exit(void)
 {
-	ctrl_outw(ctrl_inw(PMCR1) & ~PMCR_PMEN, PMCR1);
-	ctrl_outw(ctrl_inw(PMCR2) & ~PMCR_PMEN, PMCR2);
-
 	unregister_timer_hook(sh7750_timer_notify);
+
+	sh7750_ppc_reset();
 }
 
-static struct oprofile_operations sh7750_perf_counter_ops = {
-	.create_files	= sh7750_perf_counter_create_files,
-	.start		= sh7750_perf_counter_start,
-	.stop		= sh7750_perf_counter_stop,
+struct op_sh_model op_model_sh7750_ops = {
+	.cpu_type	= "sh/sh7750",
+	.num_counters	= NR_CNTRS,
+	.reg_setup	= sh7750_ppc_reg_setup,
+	.cpu_setup	= sh7750_ppc_cpu_setup,
+	.cpu_start	= sh7750_ppc_cpu_start,
+	.cpu_stop	= sh7750_ppc_cpu_stop,
+	.init		= sh7750_ppc_init,
+	.exit		= sh7750_ppc_exit,
+	.create_files	= sh7750_ppc_create_files,
 };
-
-int __init oprofile_arch_init(struct oprofile_operations *ops)
-{
-	if (!(current_cpu_data.flags & CPU_HAS_PERF_COUNTER))
-		return -ENODEV;
-
-	ops = &sh7750_perf_counter_ops;
-	ops->cpu_type = "sh/sh7750";
-
-	printk(KERN_INFO "oprofile: using SH-4 performance monitoring.\n");
-
-	/* Clear the counters */
-	ctrl_outw(ctrl_inw(PMCR1) | PMCR_PMCLR, PMCR1);
-	ctrl_outw(ctrl_inw(PMCR2) | PMCR_PMCLR, PMCR2);
-
-	return 0;
-}
-
-void oprofile_arch_exit(void)
-{
-}
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index d0c2928..284b7e8 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -8,6 +8,7 @@
 SE			SH_SOLUTION_ENGINE
 HIGHLANDER		SH_HIGHLANDER
 RTS7751R2D		SH_RTS7751R2D
+RSK			SH_RSK
 
 #
 # List of companion chips / MFDs.
@@ -46,6 +47,7 @@
 CAYMAN			SH_CAYMAN
 SDK7780			SH_SDK7780
 MIGOR			SH_MIGOR
+RSK7201			SH_RSK7201
 RSK7203			SH_RSK7203
 AP325RXA		SH_AP325RXA
 SH7763RDP		SH_SH7763RDP
diff --git a/arch/sparc/include/asm/device.h b/arch/sparc/include/asm/device.h
index 19790eb..3702e08 100644
--- a/arch/sparc/include/asm/device.h
+++ b/arch/sparc/include/asm/device.h
@@ -20,4 +20,16 @@
 	int			numa_node;
 };
 
+static inline void dev_archdata_set_node(struct dev_archdata *ad,
+					 struct device_node *np)
+{
+	ad->prom_node = np;
+}
+
+static inline struct device_node *
+dev_archdata_get_node(const struct dev_archdata *ad)
+{
+	return ad->prom_node;
+}
+
 #endif /* _ASM_SPARC_DEVICE_H */
diff --git a/arch/sparc64/kernel/idprom.c b/arch/sparc64/kernel/idprom.c
index 5b45a80..a62ff83 100644
--- a/arch/sparc64/kernel/idprom.c
+++ b/arch/sparc64/kernel/idprom.c
@@ -42,8 +42,5 @@
 			    idprom->id_cksum, calc_idprom_cksum(idprom));
 	}
 
-	printk("Ethernet address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       idprom->id_ethaddr[0], idprom->id_ethaddr[1],
-	       idprom->id_ethaddr[2], idprom->id_ethaddr[3],
-	       idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
+	printk("Ethernet address: %pM\n", idprom->id_ethaddr);
 }
diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
index d53ff52..b4a1522 100644
--- a/arch/um/drivers/daemon_kern.c
+++ b/arch/um/drivers/daemon_kern.c
@@ -22,7 +22,7 @@
 	struct daemon_data *dpri;
 	struct daemon_init *init = data;
 
-	pri = dev->priv;
+	pri = netdev_priv(dev);
 	dpri = (struct daemon_data *) pri->user;
 	dpri->sock_type = init->sock_type;
 	dpri->ctl_sock = init->ctl_sock;
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
index 8c4378a..ffc6416 100644
--- a/arch/um/drivers/mcast_kern.c
+++ b/arch/um/drivers/mcast_kern.c
@@ -28,7 +28,7 @@
 	struct mcast_data *dpri;
 	struct mcast_init *init = data;
 
-	pri = dev->priv;
+	pri = netdev_priv(dev);
 	dpri = (struct mcast_data *) pri->user;
 	dpri->addr = init->addr;
 	dpri->port = init->port;
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 8f44ebb..e14629c 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -161,7 +161,8 @@
 		goto out_kill;
 	}
 
-	file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY);
+	file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY,
+			   current_cred());
 	if (IS_ERR(file)) {
 		mconsole_reply(req, "Failed to open file", 1, 0);
 		goto out_kill;
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 5b4ca8d..fde510b 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -76,7 +76,7 @@
 
 static int uml_net_rx(struct net_device *dev)
 {
-	struct uml_net_private *lp = dev->priv;
+	struct uml_net_private *lp = netdev_priv(dev);
 	int pkt_len;
 	struct sk_buff *skb;
 
@@ -119,7 +119,7 @@
 static irqreturn_t uml_net_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
-	struct uml_net_private *lp = dev->priv;
+	struct uml_net_private *lp = netdev_priv(dev);
 	int err;
 
 	if (!netif_running(dev))
@@ -150,7 +150,7 @@
 
 static int uml_net_open(struct net_device *dev)
 {
-	struct uml_net_private *lp = dev->priv;
+	struct uml_net_private *lp = netdev_priv(dev);
 	int err;
 
 	if (lp->fd >= 0) {
@@ -195,7 +195,7 @@
 
 static int uml_net_close(struct net_device *dev)
 {
-	struct uml_net_private *lp = dev->priv;
+	struct uml_net_private *lp = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 
@@ -213,7 +213,7 @@
 
 static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct uml_net_private *lp = dev->priv;
+	struct uml_net_private *lp = netdev_priv(dev);
 	unsigned long flags;
 	int len;
 
@@ -250,7 +250,7 @@
 
 static struct net_device_stats *uml_net_get_stats(struct net_device *dev)
 {
-	struct uml_net_private *lp = dev->priv;
+	struct uml_net_private *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
@@ -267,7 +267,7 @@
 
 static int uml_net_set_mac(struct net_device *dev, void *addr)
 {
-	struct uml_net_private *lp = dev->priv;
+	struct uml_net_private *lp = netdev_priv(dev);
 	struct sockaddr *hwaddr = addr;
 
 	spin_lock_irq(&lp->lock);
@@ -368,7 +368,7 @@
 {
 	struct uml_net *device = dev->driver_data;
 	struct net_device *netdev = device->dev;
-	struct uml_net_private *lp = netdev->priv;
+	struct uml_net_private *lp = netdev_priv(netdev);
 
 	if (lp->remove != NULL)
 		(*lp->remove)(&lp->user);
@@ -418,14 +418,9 @@
 
 	setup_etheraddr(mac, device->mac, dev->name);
 
-	printk(KERN_INFO "Netdevice %d ", n);
-	printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
-	       device->mac[0], device->mac[1],
-	       device->mac[2], device->mac[3],
-	       device->mac[4], device->mac[5]);
-	printk(": ");
+	printk(KERN_INFO "Netdevice %d (%pM) : ", n, device->mac);
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	/* This points to the transport private data. It's still clear, but we
 	 * must memset it to 0 *now*. Let's help the drivers. */
 	memset(lp, 0, size);
@@ -735,7 +730,7 @@
 		return -ENODEV;
 
 	dev = device->dev;
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	if (lp->fd > 0)
 		return -EBUSY;
 	unregister_netdev(dev);
@@ -766,7 +761,7 @@
 	if (dev->open != uml_net_open)
 		return NOTIFY_DONE;
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 
 	proc = NULL;
 	switch (event) {
diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c
index 3a750dd..2860525 100644
--- a/arch/um/drivers/pcap_kern.c
+++ b/arch/um/drivers/pcap_kern.c
@@ -21,7 +21,7 @@
 	struct pcap_data *ppri;
 	struct pcap_init *init = data;
 
-	pri = dev->priv;
+	pri = netdev_priv(dev);
 	ppri = (struct pcap_data *) pri->user;
 	ppri->host_if = init->host_if;
 	ppri->promisc = init->promisc;
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
index d19faec..5ec1756 100644
--- a/arch/um/drivers/slip_kern.c
+++ b/arch/um/drivers/slip_kern.c
@@ -19,7 +19,7 @@
 	struct slip_data *spri;
 	struct slip_init *init = data;
 
-	private = dev->priv;
+	private = netdev_priv(dev);
 	spri = (struct slip_data *) private->user;
 
 	memset(spri->name, 0, sizeof(spri->name));
diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
index d987af2..f15a6e7 100644
--- a/arch/um/drivers/slirp_kern.c
+++ b/arch/um/drivers/slirp_kern.c
@@ -22,7 +22,7 @@
 	struct slirp_init *init = data;
 	int i;
 
-	private = dev->priv;
+	private = netdev_priv(dev);
 	spri = (struct slirp_data *) private->user;
 
 	spri->argw = init->argw;
diff --git a/arch/um/drivers/vde_kern.c b/arch/um/drivers/vde_kern.c
index add7e72..1b852bf 100644
--- a/arch/um/drivers/vde_kern.c
+++ b/arch/um/drivers/vde_kern.c
@@ -19,7 +19,7 @@
 	struct uml_net_private *pri;
 	struct vde_data *vpri;
 
-	pri = dev->priv;
+	pri = netdev_priv(dev);
 	vpri = (struct vde_data *) pri->user;
 
 	vpri->vde_switch = init->vde_switch;
diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
index 046a131..7f6f9a7 100644
--- a/arch/um/os-Linux/drivers/ethertap_kern.c
+++ b/arch/um/os-Linux/drivers/ethertap_kern.c
@@ -22,7 +22,7 @@
 	struct ethertap_data *epri;
 	struct ethertap_init *init = data;
 
-	pri = dev->priv;
+	pri = netdev_priv(dev);
 	epri = (struct ethertap_data *) pri->user;
 	epri->dev_name = init->dev_name;
 	epri->gate_addr = init->gate_addr;
diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c
index 6b9e33d..4048800 100644
--- a/arch/um/os-Linux/drivers/tuntap_kern.c
+++ b/arch/um/os-Linux/drivers/tuntap_kern.c
@@ -21,7 +21,7 @@
 	struct tuntap_data *tpri;
 	struct tuntap_init *init = data;
 
-	pri = dev->priv;
+	pri = netdev_priv(dev);
 	tpri = (struct tuntap_data *) pri->user;
 	tpri->dev_name = init->dev_name;
 	tpri->fixed_config = (init->dev_name != NULL);
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ac22bb7..98a0ed5 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -19,6 +19,8 @@
 config X86
 	def_bool y
 	select HAVE_AOUT if X86_32
+	select HAVE_READQ
+	select HAVE_WRITEQ
 	select HAVE_UNSTABLE_SCHED_CLOCK
 	select HAVE_IDE
 	select HAVE_OPROFILE
@@ -29,11 +31,14 @@
 	select HAVE_FTRACE_MCOUNT_RECORD
 	select HAVE_DYNAMIC_FTRACE
 	select HAVE_FUNCTION_TRACER
+	select HAVE_FUNCTION_GRAPH_TRACER
+	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
 	select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
 	select HAVE_ARCH_KGDB if !X86_VOYAGER
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_GENERIC_DMA_COHERENT if X86_32
 	select HAVE_EFFICIENT_UNALIGNED_ACCESS
+	select USER_STACKTRACE_SUPPORT
 
 config ARCH_DEFCONFIG
 	string
@@ -87,6 +92,10 @@
 config GENERIC_BUG
 	def_bool y
 	depends on BUG
+	select GENERIC_BUG_RELATIVE_POINTERS if X86_64
+
+config GENERIC_BUG_RELATIVE_POINTERS
+	bool
 
 config GENERIC_HWEIGHT
 	def_bool y
@@ -242,21 +251,13 @@
 	def_bool y
 	depends on X86_MPPARSE || X86_VOYAGER
 
-if ACPI
 config X86_MPPARSE
-	def_bool y
-	bool "Enable MPS table"
+	bool "Enable MPS table" if ACPI
+	default y
 	depends on X86_LOCAL_APIC
 	help
 	  For old smp systems that do not have proper acpi support. Newer systems
 	  (esp with 64bit cpus) with acpi support, MADT and DSDT will override it
-endif
-
-if !ACPI
-config X86_MPPARSE
-	def_bool y
-	depends on X86_LOCAL_APIC
-endif
 
 choice
 	prompt "Subarchitecture Type"
@@ -367,10 +368,10 @@
 	  as R-8610-(G).
 	  If you don't have one of these chips, you should say N here.
 
-config SCHED_NO_NO_OMIT_FRAME_POINTER
+config SCHED_OMIT_FRAME_POINTER
 	def_bool y
 	prompt "Single-depth WCHAN output"
-	depends on X86_32
+	depends on X86
 	help
 	  Calculate simpler /proc/<PID>/wchan values. If this option
 	  is disabled then wchan values will recurse back to the
@@ -465,10 +466,6 @@
 	def_bool y
 	depends on X86_GENERICARCH
 
-config ES7000_CLUSTERED_APIC
-	def_bool y
-	depends on SMP && X86_ES7000 && MPENTIUMIII
-
 source "arch/x86/Kconfig.cpu"
 
 config HPET_TIMER
@@ -569,7 +566,7 @@
 
 # need this always selected by IOMMU for the VIA workaround
 config SWIOTLB
-	bool
+	def_bool y if X86_64
 	help
 	  Support for software bounce buffers used on x86-64 systems
 	  which don't have a hardware IOMMU (e.g. the current generation
@@ -660,6 +657,30 @@
 	def_bool y
 	depends on X86_32 && X86_VISWS
 
+config X86_REROUTE_FOR_BROKEN_BOOT_IRQS
+	bool "Reroute for broken boot IRQs"
+	default n
+	depends on X86_IO_APIC
+	help
+	  This option enables a workaround that fixes a source of
+	  spurious interrupts. This is recommended when threaded
+	  interrupt handling is used on systems where the generation of
+	  superfluous "boot interrupts" cannot be disabled.
+
+	  Some chipsets generate a legacy INTx "boot IRQ" when the IRQ
+	  entry in the chipset's IO-APIC is masked (as, e.g. the RT
+	  kernel does during interrupt handling). On chipsets where this
+	  boot IRQ generation cannot be disabled, this workaround keeps
+	  the original IRQ line masked so that only the equivalent "boot
+	  IRQ" is delivered to the CPUs. The workaround also tells the
+	  kernel to set up the IRQ handler on the boot IRQ line. In this
+	  way only one interrupt is delivered to the kernel. Otherwise
+	  the spurious second interrupt may cause the kernel to bring
+	  down (vital) interrupt lines.
+
+	  Only affects "broken" chipsets. Interrupt sharing may be
+	  increased on these systems.
+
 config X86_MCE
 	bool "Machine Check Exception"
 	depends on !X86_VOYAGER
@@ -956,24 +977,37 @@
 config ARCH_PHYS_ADDR_T_64BIT
        def_bool X86_64 || X86_PAE
 
+config DIRECT_GBPAGES
+	bool "Enable 1GB pages for kernel pagetables" if EMBEDDED
+	default y
+	depends on X86_64
+	help
+	  Allow the kernel linear mapping to use 1GB pages on CPUs that
+	  support it. This can improve the kernel's performance a tiny bit by
+	  reducing TLB pressure. If in doubt, say "Y".
+
 # Common NUMA Features
 config NUMA
-	bool "Numa Memory Allocation and Scheduler Support (EXPERIMENTAL)"
+	bool "Numa Memory Allocation and Scheduler Support"
 	depends on SMP
 	depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || X86_BIGSMP || X86_SUMMIT && ACPI) && EXPERIMENTAL)
 	default n if X86_PC
 	default y if (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP)
 	help
 	  Enable NUMA (Non Uniform Memory Access) support.
+
 	  The kernel will try to allocate memory used by a CPU on the
 	  local memory controller of the CPU and add some more
 	  NUMA awareness to the kernel.
 
-	  For 32-bit this is currently highly experimental and should be only
-	  used for kernel development. It might also cause boot failures.
-	  For 64-bit this is recommended on all multiprocessor Opteron systems.
-	  If the system is EM64T, you should say N unless your system is
-	  EM64T NUMA.
+	  For 64-bit this is recommended if the system is Intel Core i7
+	  (or later), AMD Opteron, or EM64T NUMA.
+
+	  For 32-bit this is only needed on (rare) 32-bit-only platforms
+	  that support NUMA topologies, such as NUMAQ / Summit, or if you
+	  boot a 32-bit kernel on a 64-bit NUMA platform.
+
+	  Otherwise, you should say N.
 
 comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI"
 	depends on X86_32 && X86_SUMMIT && (!HIGHMEM64G || !ACPI)
@@ -1493,6 +1527,10 @@
 	def_bool y
 	depends on X86_64 || (X86_32 && HIGHMEM)
 
+config ARCH_ENABLE_MEMORY_HOTREMOVE
+	def_bool y
+	depends on MEMORY_HOTPLUG
+
 config HAVE_ARCH_EARLY_PFN_TO_NID
 	def_bool X86_64
 	depends on NUMA
@@ -1632,13 +1670,6 @@
 	  many of the newer IBM Thinkpads.  If you experience hangs when you
 	  suspend, try setting this to Y.  Otherwise, say N.
 
-config APM_REAL_MODE_POWER_OFF
-	bool "Use real mode APM BIOS call to power off"
-	help
-	  Use real mode APM BIOS calls to switch off the computer. This is
-	  a work-around for a number of buggy BIOSes. Switch this option on if
-	  your computer crashes instead of powering off properly.
-
 endif # APM
 
 source "arch/x86/kernel/cpu/cpufreq/Kconfig"
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index b815664..85a7857 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -515,6 +515,7 @@
 config X86_DS
 	def_bool X86_PTRACE_BTS
 	depends on X86_DEBUGCTLMSR
+	select HAVE_HW_BRANCH_TRACER
 
 config X86_PTRACE_BTS
 	bool "Branch Trace Store"
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 2a3dfbd..10d6cc3 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -114,18 +114,6 @@
 	  data. This is recommended so that we can catch kernel bugs sooner.
 	  If in doubt, say "Y".
 
-config DIRECT_GBPAGES
-	bool "Enable gbpages-mapped kernel pagetables"
-	depends on DEBUG_KERNEL && EXPERIMENTAL && X86_64
-	help
-	  Enable gigabyte pages support (if the CPU supports it). This can
-	  improve the kernel's performance a tiny bit by reducing TLB
-	  pressure.
-
-	  This is experimental code.
-
-	  If in doubt, say "N".
-
 config DEBUG_RODATA_TEST
 	bool "Testcase for the DEBUG_RODATA feature"
 	depends on DEBUG_RODATA
@@ -186,14 +174,10 @@
 	  Add a simple leak tracer to the IOMMU code. This is useful when you
 	  are debugging a buggy device driver that leaks IOMMU mappings.
 
-config MMIOTRACE_HOOKS
-	bool
-
 config MMIOTRACE
 	bool "Memory mapped IO tracing"
 	depends on DEBUG_KERNEL && PCI
 	select TRACING
-	select MMIOTRACE_HOOKS
 	help
 	  Mmiotrace traces Memory Mapped I/O access and is meant for
 	  debugging and reverse engineering. It is called from the ioremap
@@ -307,10 +291,10 @@
 	  developers have marked 'inline'. Doing so takes away freedom from gcc to
 	  do what it thinks is best, which is desirable for the gcc 3.x series of
 	  compilers. The gcc 4.x series have a rewritten inlining algorithm and
-	  disabling this option will generate a smaller kernel there. Hopefully
-	  this algorithm is so good that allowing gcc4 to make the decision can
-	  become the default in the future, until then this option is there to
-	  test gcc for this.
+	  enabling this option will generate a smaller kernel there. Hopefully
+	  this algorithm is so good that allowing gcc 4.x and above to make the
+	  decision will become the default in the future. Until then this option
+	  is there to test gcc for this.
 
 	  If unsure, say N.
 
diff --git a/arch/x86/boot/video-vga.c b/arch/x86/boot/video-vga.c
index b939cb4..5d4742e 100644
--- a/arch/x86/boot/video-vga.c
+++ b/arch/x86/boot/video-vga.c
@@ -34,7 +34,7 @@
 	{ VIDEO_80x25,  80, 25, 0 },
 };
 
-__videocard video_vga;
+static __videocard video_vga;
 
 /* Set basic 80x25 mode */
 static u8 vga_set_basic_mode(void)
@@ -259,7 +259,7 @@
 	return mode_count[adapter];
 }
 
-__videocard video_vga = {
+static __videocard video_vga = {
 	.card_name	= "VGA",
 	.probe		= vga_probe,
 	.set_mode	= vga_set_mode,
diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c
index 83598b2..3bef2c1 100644
--- a/arch/x86/boot/video.c
+++ b/arch/x86/boot/video.c
@@ -226,7 +226,7 @@
 
 #ifdef CONFIG_VIDEO_RETAIN
 /* Save screen content to the heap */
-struct saved_screen {
+static struct saved_screen {
 	int x, y;
 	int curx, cury;
 	u16 *data;
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index 13b8c86..b30a08e 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -77,7 +77,7 @@
 CONFIG_AUDITSYSCALL=y
 CONFIG_AUDIT_TREE=y
 # CONFIG_IKCONFIG is not set
-CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_BUF_SHIFT=18
 CONFIG_CGROUPS=y
 # CONFIG_CGROUP_DEBUG is not set
 CONFIG_CGROUP_NS=y
@@ -298,7 +298,7 @@
 CONFIG_CRASH_DUMP=y
 # CONFIG_KEXEC_JUMP is not set
 CONFIG_PHYSICAL_START=0x1000000
-CONFIG_RELOCATABLE=y
+# CONFIG_RELOCATABLE is not set
 CONFIG_PHYSICAL_ALIGN=0x200000
 CONFIG_HOTPLUG_CPU=y
 # CONFIG_COMPAT_VDSO is not set
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index f0a03d7..0e7dbc0 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -77,7 +77,7 @@
 CONFIG_AUDITSYSCALL=y
 CONFIG_AUDIT_TREE=y
 # CONFIG_IKCONFIG is not set
-CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_BUF_SHIFT=18
 CONFIG_CGROUPS=y
 # CONFIG_CGROUP_DEBUG is not set
 CONFIG_CGROUP_NS=y
@@ -298,7 +298,7 @@
 CONFIG_KEXEC=y
 CONFIG_CRASH_DUMP=y
 CONFIG_PHYSICAL_START=0x1000000
-CONFIG_RELOCATABLE=y
+# CONFIG_RELOCATABLE is not set
 CONFIG_PHYSICAL_ALIGN=0x200000
 CONFIG_HOTPLUG_CPU=y
 # CONFIG_COMPAT_VDSO is not set
diff --git a/arch/x86/crypto/crc32c-intel.c b/arch/x86/crypto/crc32c-intel.c
index 070afc5..b9d0026 100644
--- a/arch/x86/crypto/crc32c-intel.c
+++ b/arch/x86/crypto/crc32c-intel.c
@@ -6,13 +6,22 @@
  * Intel(R) 64 and IA-32 Architectures Software Developer's Manual
  * Volume 2A: Instruction Set Reference, A-M
  *
- * Copyright (c) 2008 Austin Zhang <austin_zhang@linux.intel.com>
- * Copyright (c) 2008 Kent Liu <kent.liu@intel.com>
+ * Copyright (C) 2008 Intel Corporation
+ * Authors: Austin Zhang <austin_zhang@linux.intel.com>
+ *          Kent Liu <kent.liu@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.
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  *
  */
 #include <linux/init.h>
@@ -75,99 +84,92 @@
  * If your algorithm starts with ~0, then XOR with ~0 before you set
  * the seed.
  */
-static int crc32c_intel_setkey(struct crypto_ahash *hash, const u8 *key,
+static int crc32c_intel_setkey(struct crypto_shash *hash, const u8 *key,
 			unsigned int keylen)
 {
-	u32 *mctx = crypto_ahash_ctx(hash);
+	u32 *mctx = crypto_shash_ctx(hash);
 
 	if (keylen != sizeof(u32)) {
-		crypto_ahash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
 		return -EINVAL;
 	}
 	*mctx = le32_to_cpup((__le32 *)key);
 	return 0;
 }
 
-static int crc32c_intel_init(struct ahash_request *req)
+static int crc32c_intel_init(struct shash_desc *desc)
 {
-	u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
-	u32 *crcp = ahash_request_ctx(req);
+	u32 *mctx = crypto_shash_ctx(desc->tfm);
+	u32 *crcp = shash_desc_ctx(desc);
 
 	*crcp = *mctx;
 
 	return 0;
 }
 
-static int crc32c_intel_update(struct ahash_request *req)
+static int crc32c_intel_update(struct shash_desc *desc, const u8 *data,
+			       unsigned int len)
 {
-	struct crypto_hash_walk walk;
-	u32 *crcp = ahash_request_ctx(req);
-	u32 crc = *crcp;
-	int nbytes;
+	u32 *crcp = shash_desc_ctx(desc);
 
-	for (nbytes = crypto_hash_walk_first(req, &walk); nbytes;
-	   nbytes = crypto_hash_walk_done(&walk, 0))
-	crc = crc32c_intel_le_hw(crc, walk.data, nbytes);
-
-	*crcp = crc;
+	*crcp = crc32c_intel_le_hw(*crcp, data, len);
 	return 0;
 }
 
-static int crc32c_intel_final(struct ahash_request *req)
+static int __crc32c_intel_finup(u32 *crcp, const u8 *data, unsigned int len,
+				u8 *out)
 {
-	u32 *crcp = ahash_request_ctx(req);
-
-	*(__le32 *)req->result = ~cpu_to_le32p(crcp);
+	*(__le32 *)out = ~cpu_to_le32(crc32c_intel_le_hw(*crcp, data, len));
 	return 0;
 }
 
-static int crc32c_intel_digest(struct ahash_request *req)
+static int crc32c_intel_finup(struct shash_desc *desc, const u8 *data,
+			      unsigned int len, u8 *out)
 {
-	struct crypto_hash_walk walk;
-	u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
-	u32 crc = *mctx;
-	int nbytes;
+	return __crc32c_intel_finup(shash_desc_ctx(desc), data, len, out);
+}
 
-	for (nbytes = crypto_hash_walk_first(req, &walk); nbytes;
-	   nbytes = crypto_hash_walk_done(&walk, 0))
-		crc = crc32c_intel_le_hw(crc, walk.data, nbytes);
+static int crc32c_intel_final(struct shash_desc *desc, u8 *out)
+{
+	u32 *crcp = shash_desc_ctx(desc);
 
-	*(__le32 *)req->result = ~cpu_to_le32(crc);
+	*(__le32 *)out = ~cpu_to_le32p(crcp);
 	return 0;
 }
 
+static int crc32c_intel_digest(struct shash_desc *desc, const u8 *data,
+			       unsigned int len, u8 *out)
+{
+	return __crc32c_intel_finup(crypto_shash_ctx(desc->tfm), data, len,
+				    out);
+}
+
 static int crc32c_intel_cra_init(struct crypto_tfm *tfm)
 {
 	u32 *key = crypto_tfm_ctx(tfm);
 
 	*key = ~0;
 
-	tfm->crt_ahash.reqsize = sizeof(u32);
-
 	return 0;
 }
 
-static struct crypto_alg alg = {
-	.cra_name               =       "crc32c",
-	.cra_driver_name        =       "crc32c-intel",
-	.cra_priority           =       200,
-	.cra_flags              =       CRYPTO_ALG_TYPE_AHASH,
-	.cra_blocksize          =       CHKSUM_BLOCK_SIZE,
-	.cra_alignmask          =       3,
-	.cra_ctxsize            =       sizeof(u32),
-	.cra_module             =       THIS_MODULE,
-	.cra_list               =       LIST_HEAD_INIT(alg.cra_list),
-	.cra_init               =       crc32c_intel_cra_init,
-	.cra_type               =       &crypto_ahash_type,
-	.cra_u                  =       {
-		.ahash = {
-			.digestsize    =       CHKSUM_DIGEST_SIZE,
-			.setkey        =       crc32c_intel_setkey,
-			.init          =       crc32c_intel_init,
-			.update        =       crc32c_intel_update,
-			.final         =       crc32c_intel_final,
-			.digest        =       crc32c_intel_digest,
-		}
+static struct shash_alg alg = {
+	.setkey			=	crc32c_intel_setkey,
+	.init			=	crc32c_intel_init,
+	.update			=	crc32c_intel_update,
+	.final			=	crc32c_intel_final,
+	.finup			=	crc32c_intel_finup,
+	.digest			=	crc32c_intel_digest,
+	.descsize		=	sizeof(u32),
+	.digestsize		=	CHKSUM_DIGEST_SIZE,
+	.base			=	{
+		.cra_name		=	"crc32c",
+		.cra_driver_name	=	"crc32c-intel",
+		.cra_priority		=	200,
+		.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
+		.cra_ctxsize		=	sizeof(u32),
+		.cra_module		=	THIS_MODULE,
+		.cra_init		=	crc32c_intel_cra_init,
 	}
 };
 
@@ -175,14 +177,14 @@
 static int __init crc32c_intel_mod_init(void)
 {
 	if (cpu_has_xmm4_2)
-		return crypto_register_alg(&alg);
+		return crypto_register_shash(&alg);
 	else
 		return -ENODEV;
 }
 
 static void __exit crc32c_intel_mod_fini(void)
 {
-	crypto_unregister_alg(&alg);
+	crypto_unregister_shash(&alg);
 }
 
 module_init(crc32c_intel_mod_init);
@@ -194,4 +196,3 @@
 
 MODULE_ALIAS("crc32c");
 MODULE_ALIAS("crc32c-intel");
-
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index 127ec3f..2a4d073 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -327,7 +327,7 @@
 	current->mm->cached_hole_size = 0;
 
 	current->mm->mmap = NULL;
-	compute_creds(bprm);
+	install_exec_creds(bprm);
 	current->flags &= ~PF_FORKNOEXEC;
 
 	if (N_MAGIC(ex) == OMAGIC) {
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 4bc02b2..b195f85 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -32,6 +32,8 @@
 #include <asm/proto.h>
 #include <asm/vdso.h>
 
+#include <asm/sigframe.h>
+
 #define DEBUG_SIG 0
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -41,7 +43,6 @@
 			 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
 			 X86_EFLAGS_CF)
 
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
 
 int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
@@ -173,47 +174,28 @@
 /*
  * Do a signal return; undo the signal stack.
  */
-
-struct sigframe
-{
-	u32 pretcode;
-	int sig;
-	struct sigcontext_ia32 sc;
-	struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */
-	unsigned int extramask[_COMPAT_NSIG_WORDS-1];
-	char retcode[8];
-	/* fp state follows here */
-};
-
-struct rt_sigframe
-{
-	u32 pretcode;
-	int sig;
-	u32 pinfo;
-	u32 puc;
-	compat_siginfo_t info;
-	struct ucontext_ia32 uc;
-	char retcode[8];
-	/* fp state follows here */
-};
-
-#define COPY(x)		{ 		\
-	unsigned int reg;		\
-	err |= __get_user(reg, &sc->x);	\
-	regs->x = reg;			\
+#define COPY(x)			{		\
+	err |= __get_user(regs->x, &sc->x);	\
 }
 
-#define RELOAD_SEG(seg,mask)						\
-	{ unsigned int cur;						\
-	  unsigned short pre;						\
-	  err |= __get_user(pre, &sc->seg);				\
-	  savesegment(seg, cur);					\
-	  pre |= mask;							\
-	  if (pre != cur) loadsegment(seg, pre); }
+#define COPY_SEG_CPL3(seg)	{			\
+		unsigned short tmp;			\
+		err |= __get_user(tmp, &sc->seg);	\
+		regs->seg = tmp | 3;			\
+}
+
+#define RELOAD_SEG(seg)		{		\
+	unsigned int cur, pre;			\
+	err |= __get_user(pre, &sc->seg);	\
+	savesegment(seg, cur);			\
+	pre |= 3;				\
+	if (pre != cur)				\
+		loadsegment(seg, pre);		\
+}
 
 static int ia32_restore_sigcontext(struct pt_regs *regs,
 				   struct sigcontext_ia32 __user *sc,
-				   unsigned int *peax)
+				   unsigned int *pax)
 {
 	unsigned int tmpflags, gs, oldgs, err = 0;
 	void __user *buf;
@@ -240,18 +222,16 @@
 	if (gs != oldgs)
 		load_gs_index(gs);
 
-	RELOAD_SEG(fs, 3);
-	RELOAD_SEG(ds, 3);
-	RELOAD_SEG(es, 3);
+	RELOAD_SEG(fs);
+	RELOAD_SEG(ds);
+	RELOAD_SEG(es);
 
 	COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
 	COPY(dx); COPY(cx); COPY(ip);
 	/* Don't touch extended registers */
 
-	err |= __get_user(regs->cs, &sc->cs);
-	regs->cs |= 3;
-	err |= __get_user(regs->ss, &sc->ss);
-	regs->ss |= 3;
+	COPY_SEG_CPL3(cs);
+	COPY_SEG_CPL3(ss);
 
 	err |= __get_user(tmpflags, &sc->flags);
 	regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
@@ -262,15 +242,13 @@
 	buf = compat_ptr(tmp);
 	err |= restore_i387_xstate_ia32(buf);
 
-	err |= __get_user(tmp, &sc->ax);
-	*peax = tmp;
-
+	err |= __get_user(*pax, &sc->ax);
 	return err;
 }
 
 asmlinkage long sys32_sigreturn(struct pt_regs *regs)
 {
-	struct sigframe __user *frame = (struct sigframe __user *)(regs->sp-8);
+	struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
 	sigset_t set;
 	unsigned int ax;
 
@@ -300,12 +278,12 @@
 
 asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
 {
-	struct rt_sigframe __user *frame;
+	struct rt_sigframe_ia32 __user *frame;
 	sigset_t set;
 	unsigned int ax;
 	struct pt_regs tregs;
 
-	frame = (struct rt_sigframe __user *)(regs->sp - 4);
+	frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
 
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
@@ -359,20 +337,15 @@
 	err |= __put_user(regs->dx, &sc->dx);
 	err |= __put_user(regs->cx, &sc->cx);
 	err |= __put_user(regs->ax, &sc->ax);
-	err |= __put_user(regs->cs, &sc->cs);
-	err |= __put_user(regs->ss, &sc->ss);
 	err |= __put_user(current->thread.trap_no, &sc->trapno);
 	err |= __put_user(current->thread.error_code, &sc->err);
 	err |= __put_user(regs->ip, &sc->ip);
+	err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs);
 	err |= __put_user(regs->flags, &sc->flags);
 	err |= __put_user(regs->sp, &sc->sp_at_signal);
+	err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
 
-	tmp = save_i387_xstate_ia32(fpstate);
-	if (tmp < 0)
-		err = -EFAULT;
-	else
-		err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
-					&sc->fpstate);
+	err |= __put_user(ptr_to_compat(fpstate), &sc->fpstate);
 
 	/* non-iBCS2 extensions.. */
 	err |= __put_user(mask, &sc->oldmask);
@@ -400,7 +373,7 @@
 	}
 
 	/* This is the legacy signal stack switching. */
-	else if ((regs->ss & 0xffff) != __USER_DS &&
+	else if ((regs->ss & 0xffff) != __USER32_DS &&
 		!(ka->sa.sa_flags & SA_RESTORER) &&
 		 ka->sa.sa_restorer)
 		sp = (unsigned long) ka->sa.sa_restorer;
@@ -408,6 +381,8 @@
 	if (used_math()) {
 		sp = sp - sig_xstate_ia32_size;
 		*fpstate = (struct _fpstate_ia32 *) sp;
+		if (save_i387_xstate_ia32(*fpstate) < 0)
+			return (void __user *) -1L;
 	}
 
 	sp -= frame_size;
@@ -420,7 +395,7 @@
 int ia32_setup_frame(int sig, struct k_sigaction *ka,
 		     compat_sigset_t *set, struct pt_regs *regs)
 {
-	struct sigframe __user *frame;
+	struct sigframe_ia32 __user *frame;
 	void __user *restorer;
 	int err = 0;
 	void __user *fpstate = NULL;
@@ -430,12 +405,10 @@
 		u16 poplmovl;
 		u32 val;
 		u16 int80;
-		u16 pad;
 	} __attribute__((packed)) code = {
 		0xb858,		 /* popl %eax ; movl $...,%eax */
 		__NR_ia32_sigreturn,
 		0x80cd,		/* int $0x80 */
-		0,
 	};
 
 	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
@@ -471,7 +444,7 @@
 	 * These are actually not used anymore, but left because some
 	 * gdb versions depend on them as a marker.
 	 */
-	err |= __copy_to_user(frame->retcode, &code, 8);
+	err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode);
 	if (err)
 		return -EFAULT;
 
@@ -501,7 +474,7 @@
 int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 			compat_sigset_t *set, struct pt_regs *regs)
 {
-	struct rt_sigframe __user *frame;
+	struct rt_sigframe_ia32 __user *frame;
 	void __user *restorer;
 	int err = 0;
 	void __user *fpstate = NULL;
@@ -511,8 +484,7 @@
 		u8 movl;
 		u32 val;
 		u16 int80;
-		u16 pad;
-		u8  pad2;
+		u8  pad;
 	} __attribute__((packed)) code = {
 		0xb8,
 		__NR_ia32_rt_sigreturn,
@@ -559,7 +531,7 @@
 	 * Not actually used anymore, but left because some gdb
 	 * versions need it.
 	 */
-	err |= __copy_to_user(frame->retcode, &code, 8);
+	err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode);
 	if (err)
 		return -EFAULT;
 
@@ -572,11 +544,6 @@
 	regs->dx = (unsigned long) &frame->info;
 	regs->cx = (unsigned long) &frame->uc;
 
-	/* Make -mregparm=3 work */
-	regs->ax = sig;
-	regs->dx = (unsigned long) &frame->info;
-	regs->cx = (unsigned long) &frame->uc;
-
 	loadsegment(ds, __USER32_DS);
 	loadsegment(es, __USER32_DS);
 
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 3b1510b..25caa07 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -193,6 +193,7 @@
 static inline void lapic_shutdown(void) { }
 #define local_apic_timer_c2_ok		1
 static inline void init_apic_mappings(void) { }
+static inline void disable_local_APIC(void) { }
 
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
diff --git a/arch/x86/include/asm/bigsmp/apic.h b/arch/x86/include/asm/bigsmp/apic.h
index 1d9543b..ce547f2 100644
--- a/arch/x86/include/asm/bigsmp/apic.h
+++ b/arch/x86/include/asm/bigsmp/apic.h
@@ -24,8 +24,6 @@
 #define INT_DELIVERY_MODE	(dest_Fixed)
 #define INT_DEST_MODE		(0)    /* phys delivery to target proc */
 #define NO_BALANCE_IRQ		(0)
-#define WAKE_SECONDARY_VIA_INIT
-
 
 static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
 {
diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h
index 3600103..9fa9dcd 100644
--- a/arch/x86/include/asm/bitops.h
+++ b/arch/x86/include/asm/bitops.h
@@ -168,7 +168,15 @@
  */
 static inline void change_bit(int nr, volatile unsigned long *addr)
 {
-	asm volatile(LOCK_PREFIX "btc %1,%0" : ADDR : "Ir" (nr));
+	if (IS_IMMEDIATE(nr)) {
+		asm volatile(LOCK_PREFIX "xorb %1,%0"
+			: CONST_MASK_ADDR(nr, addr)
+			: "iq" ((u8)CONST_MASK(nr)));
+	} else {
+		asm volatile(LOCK_PREFIX "btc %1,%0"
+			: BITOP_ADDR(addr)
+			: "Ir" (nr));
+	}
 }
 
 /**
diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
index 3def206..d9cf1cd 100644
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -9,7 +9,7 @@
 #ifdef CONFIG_X86_32
 # define __BUG_C0	"2:\t.long 1b, %c0\n"
 #else
-# define __BUG_C0	"2:\t.quad 1b, %c0\n"
+# define __BUG_C0	"2:\t.long 1b - 2b, %c0 - 2b\n"
 #endif
 
 #define BUG()							\
diff --git a/arch/x86/include/asm/byteorder.h b/arch/x86/include/asm/byteorder.h
index e02ae2d..f110ad4 100644
--- a/arch/x86/include/asm/byteorder.h
+++ b/arch/x86/include/asm/byteorder.h
@@ -4,26 +4,33 @@
 #include <asm/types.h>
 #include <linux/compiler.h>
 
-#ifdef __GNUC__
+#define __LITTLE_ENDIAN
 
-#ifdef __i386__
-
-static inline __attribute_const__ __u32 ___arch__swab32(__u32 x)
+static inline __attribute_const__ __u32 __arch_swab32(__u32 val)
 {
-#ifdef CONFIG_X86_BSWAP
-	asm("bswap %0" : "=r" (x) : "0" (x));
-#else
+#ifdef __i386__
+# ifdef CONFIG_X86_BSWAP
+	asm("bswap %0" : "=r" (val) : "0" (val));
+# else
 	asm("xchgb %b0,%h0\n\t"	/* swap lower bytes	*/
 	    "rorl $16,%0\n\t"	/* swap words		*/
 	    "xchgb %b0,%h0"	/* swap higher bytes	*/
-	    : "=q" (x)
-	    : "0" (x));
-#endif
-	return x;
-}
+	    : "=q" (val)
+	    : "0" (val));
+# endif
 
-static inline __attribute_const__ __u64 ___arch__swab64(__u64 val)
+#else /* __i386__ */
+	asm("bswapl %0"
+	    : "=r" (val)
+	    : "0" (val));
+#endif
+	return val;
+}
+#define __arch_swab32 __arch_swab32
+
+static inline __attribute_const__ __u64 __arch_swab64(__u64 val)
 {
+#ifdef __i386__
 	union {
 		struct {
 			__u32 a;
@@ -32,50 +39,27 @@
 		__u64 u;
 	} v;
 	v.u = val;
-#ifdef CONFIG_X86_BSWAP
+# ifdef CONFIG_X86_BSWAP
 	asm("bswapl %0 ; bswapl %1 ; xchgl %0,%1"
 	    : "=r" (v.s.a), "=r" (v.s.b)
 	    : "0" (v.s.a), "1" (v.s.b));
-#else
-	v.s.a = ___arch__swab32(v.s.a);
-	v.s.b = ___arch__swab32(v.s.b);
+# else
+	v.s.a = __arch_swab32(v.s.a);
+	v.s.b = __arch_swab32(v.s.b);
 	asm("xchgl %0,%1"
 	    : "=r" (v.s.a), "=r" (v.s.b)
 	    : "0" (v.s.a), "1" (v.s.b));
-#endif
+# endif
 	return v.u;
-}
-
 #else /* __i386__ */
-
-static inline __attribute_const__ __u64 ___arch__swab64(__u64 x)
-{
 	asm("bswapq %0"
-	    : "=r" (x)
-	    : "0" (x));
-	return x;
-}
-
-static inline __attribute_const__ __u32 ___arch__swab32(__u32 x)
-{
-	asm("bswapl %0"
-	    : "=r" (x)
-	    : "0" (x));
-	return x;
-}
-
+	    : "=r" (val)
+	    : "0" (val));
+	return val;
 #endif
+}
+#define __arch_swab64 __arch_swab64
 
-/* Do not define swab16.  Gcc is smart enough to recognize "C" version and
-   convert it into rotation or exhange.  */
-
-#define __arch__swab64(x) ___arch__swab64(x)
-#define __arch__swab32(x) ___arch__swab32(x)
-
-#define __BYTEORDER_HAS_U64__
-
-#endif /* __GNUC__ */
-
-#include <linux/byteorder/little_endian.h>
+#include <linux/byteorder.h>
 
 #endif /* _ASM_X86_BYTEORDER_H */
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index cfdf8c2..ea408dc 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -80,7 +80,6 @@
 #define X86_FEATURE_UP		(3*32+ 9) /* smp kernel running on up */
 #define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* "" FXSAVE leaks FOP/FIP/FOP */
 #define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */
-#define X86_FEATURE_NOPL	(3*32+20) /* The NOPL (0F 1F) instructions */
 #define X86_FEATURE_PEBS	(3*32+12) /* Precise-Event Based Sampling */
 #define X86_FEATURE_BTS		(3*32+13) /* Branch Trace Store */
 #define X86_FEATURE_SYSCALL32	(3*32+14) /* "" syscall in ia32 userspace */
@@ -92,6 +91,8 @@
 #define X86_FEATURE_NOPL	(3*32+20) /* The NOPL (0F 1F) instructions */
 #define X86_FEATURE_AMDC1E	(3*32+21) /* AMD C1E detected */
 #define X86_FEATURE_XTOPOLOGY	(3*32+22) /* cpu topology enum extensions */
+#define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */
+#define X86_FEATURE_NONSTOP_TSC	(3*32+24) /* TSC does not stop in C states */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
 #define X86_FEATURE_XMM3	(4*32+ 0) /* "pni" SSE-3 */
@@ -117,6 +118,7 @@
 #define X86_FEATURE_XSAVE	(4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
 #define X86_FEATURE_OSXSAVE	(4*32+27) /* "" XSAVE enabled in the OS */
 #define X86_FEATURE_AVX		(4*32+28) /* Advanced Vector Extensions */
+#define X86_FEATURE_HYPERVISOR	(4*32+31) /* Running on a hypervisor */
 
 /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
 #define X86_FEATURE_XSTORE	(5*32+ 2) /* "rng" RNG present (xstore) */
@@ -237,6 +239,7 @@
 #define cpu_has_xmm4_2		boot_cpu_has(X86_FEATURE_XMM4_2)
 #define cpu_has_x2apic		boot_cpu_has(X86_FEATURE_X2APIC)
 #define cpu_has_xsave		boot_cpu_has(X86_FEATURE_XSAVE)
+#define cpu_has_hypervisor	boot_cpu_has(X86_FEATURE_HYPERVISOR)
 
 #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
 # define cpu_has_invlpg		1
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index 097794f..dc22c07 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -71,12 +71,10 @@
 /* Make sure we keep the same behaviour */
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
-#ifdef CONFIG_X86_64
 	struct dma_mapping_ops *ops = get_dma_ops(dev);
 	if (ops->mapping_error)
 		return ops->mapping_error(dev, dma_addr);
 
-#endif
 	return (dma_addr == bad_dma_address);
 }
 
diff --git a/arch/x86/include/asm/ds.h b/arch/x86/include/asm/ds.h
index a950084..a8f672b 100644
--- a/arch/x86/include/asm/ds.h
+++ b/arch/x86/include/asm/ds.h
@@ -6,14 +6,13 @@
  * precise-event based sampling (PEBS).
  *
  * It manages:
- * - per-thread and per-cpu allocation of BTS and PEBS
- * - buffer memory allocation (optional)
- * - buffer overflow handling
+ * - DS and BTS hardware configuration
+ * - buffer overflow handling (to be done)
  * - buffer access
  *
- * It assumes:
- * - get_task_struct on all parameter tasks
- * - current is allowed to trace parameter tasks
+ * It does not do:
+ * - security checking (is the caller allowed to trace the task)
+ * - buffer allocation (memory accounting)
  *
  *
  * Copyright (C) 2007-2008 Intel Corporation.
@@ -26,11 +25,51 @@
 
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/err.h>
 
 
 #ifdef CONFIG_X86_DS
 
 struct task_struct;
+struct ds_context;
+struct ds_tracer;
+struct bts_tracer;
+struct pebs_tracer;
+
+typedef void (*bts_ovfl_callback_t)(struct bts_tracer *);
+typedef void (*pebs_ovfl_callback_t)(struct pebs_tracer *);
+
+
+/*
+ * A list of features plus corresponding macros to talk about them in
+ * the ds_request function's flags parameter.
+ *
+ * We use the enum to index an array of corresponding control bits;
+ * we use the macro to index a flags bit-vector.
+ */
+enum ds_feature {
+	dsf_bts = 0,
+	dsf_bts_kernel,
+#define BTS_KERNEL (1 << dsf_bts_kernel)
+	/* trace kernel-mode branches */
+
+	dsf_bts_user,
+#define BTS_USER (1 << dsf_bts_user)
+	/* trace user-mode branches */
+
+	dsf_bts_overflow,
+	dsf_bts_max,
+	dsf_pebs = dsf_bts_max,
+
+	dsf_pebs_max,
+	dsf_ctl_max = dsf_pebs_max,
+	dsf_bts_timestamps = dsf_ctl_max,
+#define BTS_TIMESTAMPS (1 << dsf_bts_timestamps)
+	/* add timestamps into BTS trace */
+
+#define BTS_USER_FLAGS (BTS_KERNEL | BTS_USER | BTS_TIMESTAMPS)
+};
+
 
 /*
  * Request BTS or PEBS
@@ -38,163 +77,169 @@
  * Due to alignement constraints, the actual buffer may be slightly
  * smaller than the requested or provided buffer.
  *
- * Returns 0 on success; -Eerrno otherwise
+ * Returns a pointer to a tracer structure on success, or
+ * ERR_PTR(errcode) on failure.
+ *
+ * The interrupt threshold is independent from the overflow callback
+ * to allow users to use their own overflow interrupt handling mechanism.
  *
  * task: the task to request recording for;
  *       NULL for per-cpu recording on the current cpu
  * base: the base pointer for the (non-pageable) buffer;
- *       NULL if buffer allocation requested
- * size: the size of the requested or provided buffer
+ * size: the size of the provided buffer in bytes
  * ovfl: pointer to a function to be called on buffer overflow;
  *       NULL if cyclic buffer requested
+ * th: the interrupt threshold in records from the end of the buffer;
+ *     -1 if no interrupt threshold is requested.
+ * flags: a bit-mask of the above flags
  */
-typedef void (*ds_ovfl_callback_t)(struct task_struct *);
-extern int ds_request_bts(struct task_struct *task, void *base, size_t size,
-			  ds_ovfl_callback_t ovfl);
-extern int ds_request_pebs(struct task_struct *task, void *base, size_t size,
-			   ds_ovfl_callback_t ovfl);
+extern struct bts_tracer *ds_request_bts(struct task_struct *task,
+					 void *base, size_t size,
+					 bts_ovfl_callback_t ovfl,
+					 size_t th, unsigned int flags);
+extern struct pebs_tracer *ds_request_pebs(struct task_struct *task,
+					   void *base, size_t size,
+					   pebs_ovfl_callback_t ovfl,
+					   size_t th, unsigned int flags);
 
 /*
  * Release BTS or PEBS resources
+ * Suspend and resume BTS or PEBS tracing
  *
- * Frees buffers allocated on ds_request.
- *
- * Returns 0 on success; -Eerrno otherwise
- *
- * task: the task to release resources for;
- *       NULL to release resources for the current cpu
+ * tracer: the tracer handle returned from ds_request_~()
  */
-extern int ds_release_bts(struct task_struct *task);
-extern int ds_release_pebs(struct task_struct *task);
+extern void ds_release_bts(struct bts_tracer *tracer);
+extern void ds_suspend_bts(struct bts_tracer *tracer);
+extern void ds_resume_bts(struct bts_tracer *tracer);
+extern void ds_release_pebs(struct pebs_tracer *tracer);
+extern void ds_suspend_pebs(struct pebs_tracer *tracer);
+extern void ds_resume_pebs(struct pebs_tracer *tracer);
+
 
 /*
- * Return the (array) index of the write pointer.
- * (assuming an array of BTS/PEBS records)
+ * The raw DS buffer state as it is used for BTS and PEBS recording.
  *
- * Returns -Eerrno on error
- *
- * task: the task to access;
- *       NULL to access the current cpu
- * pos (out): if not NULL, will hold the result
+ * This is the low-level, arch-dependent interface for working
+ * directly on the raw trace data.
  */
-extern int ds_get_bts_index(struct task_struct *task, size_t *pos);
-extern int ds_get_pebs_index(struct task_struct *task, size_t *pos);
+struct ds_trace {
+	/* the number of bts/pebs records */
+	size_t n;
+	/* the size of a bts/pebs record in bytes */
+	size_t size;
+	/* pointers into the raw buffer:
+	   - to the first entry */
+	void *begin;
+	/* - one beyond the last entry */
+	void *end;
+	/* - one beyond the newest entry */
+	void *top;
+	/* - the interrupt threshold */
+	void *ith;
+	/* flags given on ds_request() */
+	unsigned int flags;
+};
 
 /*
- * Return the (array) index one record beyond the end of the array.
- * (assuming an array of BTS/PEBS records)
- *
- * Returns -Eerrno on error
- *
- * task: the task to access;
- *       NULL to access the current cpu
- * pos (out): if not NULL, will hold the result
+ * An arch-independent view on branch trace data.
  */
-extern int ds_get_bts_end(struct task_struct *task, size_t *pos);
-extern int ds_get_pebs_end(struct task_struct *task, size_t *pos);
+enum bts_qualifier {
+	bts_invalid,
+#define BTS_INVALID bts_invalid
+
+	bts_branch,
+#define BTS_BRANCH bts_branch
+
+	bts_task_arrives,
+#define BTS_TASK_ARRIVES bts_task_arrives
+
+	bts_task_departs,
+#define BTS_TASK_DEPARTS bts_task_departs
+
+	bts_qual_bit_size = 4,
+	bts_qual_max = (1 << bts_qual_bit_size),
+};
+
+struct bts_struct {
+	__u64 qualifier;
+	union {
+		/* BTS_BRANCH */
+		struct {
+			__u64 from;
+			__u64 to;
+		} lbr;
+		/* BTS_TASK_ARRIVES or BTS_TASK_DEPARTS */
+		struct {
+			__u64 jiffies;
+			pid_t pid;
+		} timestamp;
+	} variant;
+};
+
 
 /*
- * Provide a pointer to the BTS/PEBS record at parameter index.
- * (assuming an array of BTS/PEBS records)
+ * The BTS state.
  *
- * The pointer points directly into the buffer. The user is
- * responsible for copying the record.
- *
- * Returns the size of a single record on success; -Eerrno on error
- *
- * task: the task to access;
- *       NULL to access the current cpu
- * index: the index of the requested record
- * record (out): pointer to the requested record
+ * This gives access to the raw DS state and adds functions to provide
+ * an arch-independent view of the BTS data.
  */
-extern int ds_access_bts(struct task_struct *task,
-			 size_t index, const void **record);
-extern int ds_access_pebs(struct task_struct *task,
-			  size_t index, const void **record);
+struct bts_trace {
+	struct ds_trace ds;
+
+	int (*read)(struct bts_tracer *tracer, const void *at,
+		    struct bts_struct *out);
+	int (*write)(struct bts_tracer *tracer, const struct bts_struct *in);
+};
+
 
 /*
- * Write one or more BTS/PEBS records at the write pointer index and
- * advance the write pointer.
+ * The PEBS state.
  *
- * If size is not a multiple of the record size, trailing bytes are
- * zeroed out.
- *
- * May result in one or more overflow notifications.
- *
- * If called during overflow handling, that is, with index >=
- * interrupt threshold, the write will wrap around.
- *
- * An overflow notification is given if and when the interrupt
- * threshold is reached during or after the write.
- *
- * Returns the number of bytes written or -Eerrno.
- *
- * task: the task to access;
- *       NULL to access the current cpu
- * buffer: the buffer to write
- * size: the size of the buffer
+ * This gives access to the raw DS state and the PEBS-specific counter
+ * reset value.
  */
-extern int ds_write_bts(struct task_struct *task,
-			const void *buffer, size_t size);
-extern int ds_write_pebs(struct task_struct *task,
-			 const void *buffer, size_t size);
+struct pebs_trace {
+	struct ds_trace ds;
+
+	/* the PEBS reset value */
+	unsigned long long reset_value;
+};
+
 
 /*
- * Same as ds_write_bts/pebs, but omit ownership checks.
+ * Read the BTS or PEBS trace.
  *
- * This is needed to have some other task than the owner of the
- * BTS/PEBS buffer or the parameter task itself write into the
- * respective buffer.
+ * Returns a view on the trace collected for the parameter tracer.
+ *
+ * The view remains valid as long as the traced task is not running or
+ * the tracer is suspended.
+ * Writes into the trace buffer are not reflected.
+ *
+ * tracer: the tracer handle returned from ds_request_~()
  */
-extern int ds_unchecked_write_bts(struct task_struct *task,
-				  const void *buffer, size_t size);
-extern int ds_unchecked_write_pebs(struct task_struct *task,
-				   const void *buffer, size_t size);
+extern const struct bts_trace *ds_read_bts(struct bts_tracer *tracer);
+extern const struct pebs_trace *ds_read_pebs(struct pebs_tracer *tracer);
+
 
 /*
  * Reset the write pointer of the BTS/PEBS buffer.
  *
  * Returns 0 on success; -Eerrno on error
  *
- * task: the task to access;
- *       NULL to access the current cpu
+ * tracer: the tracer handle returned from ds_request_~()
  */
-extern int ds_reset_bts(struct task_struct *task);
-extern int ds_reset_pebs(struct task_struct *task);
-
-/*
- * Clear the BTS/PEBS buffer and reset the write pointer.
- * The entire buffer will be zeroed out.
- *
- * Returns 0 on success; -Eerrno on error
- *
- * task: the task to access;
- *       NULL to access the current cpu
- */
-extern int ds_clear_bts(struct task_struct *task);
-extern int ds_clear_pebs(struct task_struct *task);
-
-/*
- * Provide the PEBS counter reset value.
- *
- * Returns 0 on success; -Eerrno on error
- *
- * task: the task to access;
- *       NULL to access the current cpu
- * value (out): the counter reset value
- */
-extern int ds_get_pebs_reset(struct task_struct *task, u64 *value);
+extern int ds_reset_bts(struct bts_tracer *tracer);
+extern int ds_reset_pebs(struct pebs_tracer *tracer);
 
 /*
  * Set the PEBS counter reset value.
  *
  * Returns 0 on success; -Eerrno on error
  *
- * task: the task to access;
- *       NULL to access the current cpu
+ * tracer: the tracer handle returned from ds_request_pebs()
  * value: the new counter reset value
  */
-extern int ds_set_pebs_reset(struct task_struct *task, u64 value);
+extern int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value);
 
 /*
  * Initialization
@@ -202,39 +247,26 @@
 struct cpuinfo_x86;
 extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *);
 
-
+/*
+ * Context switch work
+ */
+extern void ds_switch_to(struct task_struct *prev, struct task_struct *next);
 
 /*
- * The DS context - part of struct thread_struct.
+ * Task clone/init and cleanup work
  */
-struct ds_context {
-	/* pointer to the DS configuration; goes into MSR_IA32_DS_AREA */
-	unsigned char *ds;
-	/* the owner of the BTS and PEBS configuration, respectively */
-	struct task_struct *owner[2];
-	/* buffer overflow notification function for BTS and PEBS */
-	ds_ovfl_callback_t callback[2];
-	/* the original buffer address */
-	void *buffer[2];
-	/* the number of allocated pages for on-request allocated buffers */
-	unsigned int pages[2];
-	/* use count */
-	unsigned long count;
-	/* a pointer to the context location inside the thread_struct
-	 * or the per_cpu context array */
-	struct ds_context **this;
-	/* a pointer to the task owning this context, or NULL, if the
-	 * context is owned by a cpu */
-	struct task_struct *task;
-};
-
-/* called by exit_thread() to free leftover contexts */
-extern void ds_free(struct ds_context *context);
+extern void ds_copy_thread(struct task_struct *tsk, struct task_struct *father);
+extern void ds_exit_thread(struct task_struct *tsk);
 
 #else /* CONFIG_X86_DS */
 
 struct cpuinfo_x86;
 static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {}
+static inline void ds_switch_to(struct task_struct *prev,
+				struct task_struct *next) {}
+static inline void ds_copy_thread(struct task_struct *tsk,
+				  struct task_struct *father) {}
+static inline void ds_exit_thread(struct task_struct *tsk) {}
 
 #endif /* CONFIG_X86_DS */
 #endif /* _ASM_X86_DS_H */
diff --git a/arch/x86/include/asm/dwarf2.h b/arch/x86/include/asm/dwarf2.h
index 804b6e6..3afc5e8 100644
--- a/arch/x86/include/asm/dwarf2.h
+++ b/arch/x86/include/asm/dwarf2.h
@@ -6,56 +6,91 @@
 #endif
 
 /*
-   Macros for dwarf2 CFI unwind table entries.
-   See "as.info" for details on these pseudo ops. Unfortunately
-   they are only supported in very new binutils, so define them
-   away for older version.
+ * Macros for dwarf2 CFI unwind table entries.
+ * See "as.info" for details on these pseudo ops. Unfortunately
+ * they are only supported in very new binutils, so define them
+ * away for older version.
  */
 
 #ifdef CONFIG_AS_CFI
 
-#define CFI_STARTPROC .cfi_startproc
-#define CFI_ENDPROC .cfi_endproc
-#define CFI_DEF_CFA .cfi_def_cfa
-#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register
-#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
-#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset
-#define CFI_OFFSET .cfi_offset
-#define CFI_REL_OFFSET .cfi_rel_offset
-#define CFI_REGISTER .cfi_register
-#define CFI_RESTORE .cfi_restore
-#define CFI_REMEMBER_STATE .cfi_remember_state
-#define CFI_RESTORE_STATE .cfi_restore_state
-#define CFI_UNDEFINED .cfi_undefined
+#define CFI_STARTPROC		.cfi_startproc
+#define CFI_ENDPROC		.cfi_endproc
+#define CFI_DEF_CFA		.cfi_def_cfa
+#define CFI_DEF_CFA_REGISTER	.cfi_def_cfa_register
+#define CFI_DEF_CFA_OFFSET	.cfi_def_cfa_offset
+#define CFI_ADJUST_CFA_OFFSET	.cfi_adjust_cfa_offset
+#define CFI_OFFSET		.cfi_offset
+#define CFI_REL_OFFSET		.cfi_rel_offset
+#define CFI_REGISTER		.cfi_register
+#define CFI_RESTORE		.cfi_restore
+#define CFI_REMEMBER_STATE	.cfi_remember_state
+#define CFI_RESTORE_STATE	.cfi_restore_state
+#define CFI_UNDEFINED		.cfi_undefined
 
 #ifdef CONFIG_AS_CFI_SIGNAL_FRAME
-#define CFI_SIGNAL_FRAME .cfi_signal_frame
+#define CFI_SIGNAL_FRAME	.cfi_signal_frame
 #else
 #define CFI_SIGNAL_FRAME
 #endif
 
 #else
 
-/* Due to the structure of pre-exisiting code, don't use assembler line
-   comment character # to ignore the arguments. Instead, use a dummy macro. */
+/*
+ * Due to the structure of pre-exisiting code, don't use assembler line
+ * comment character # to ignore the arguments. Instead, use a dummy macro.
+ */
 .macro cfi_ignore a=0, b=0, c=0, d=0
 .endm
 
-#define CFI_STARTPROC	cfi_ignore
-#define CFI_ENDPROC	cfi_ignore
-#define CFI_DEF_CFA	cfi_ignore
+#define CFI_STARTPROC		cfi_ignore
+#define CFI_ENDPROC		cfi_ignore
+#define CFI_DEF_CFA		cfi_ignore
 #define CFI_DEF_CFA_REGISTER	cfi_ignore
 #define CFI_DEF_CFA_OFFSET	cfi_ignore
 #define CFI_ADJUST_CFA_OFFSET	cfi_ignore
-#define CFI_OFFSET	cfi_ignore
-#define CFI_REL_OFFSET	cfi_ignore
-#define CFI_REGISTER	cfi_ignore
-#define CFI_RESTORE	cfi_ignore
-#define CFI_REMEMBER_STATE cfi_ignore
-#define CFI_RESTORE_STATE cfi_ignore
-#define CFI_UNDEFINED cfi_ignore
-#define CFI_SIGNAL_FRAME cfi_ignore
+#define CFI_OFFSET		cfi_ignore
+#define CFI_REL_OFFSET		cfi_ignore
+#define CFI_REGISTER		cfi_ignore
+#define CFI_RESTORE		cfi_ignore
+#define CFI_REMEMBER_STATE	cfi_ignore
+#define CFI_RESTORE_STATE	cfi_ignore
+#define CFI_UNDEFINED		cfi_ignore
+#define CFI_SIGNAL_FRAME	cfi_ignore
 
 #endif
 
+/*
+ * An attempt to make CFI annotations more or less
+ * correct and shorter. It is implied that you know
+ * what you're doing if you use them.
+ */
+#ifdef __ASSEMBLY__
+#ifdef CONFIG_X86_64
+	.macro pushq_cfi reg
+	pushq \reg
+	CFI_ADJUST_CFA_OFFSET 8
+	.endm
+
+	.macro popq_cfi reg
+	popq \reg
+	CFI_ADJUST_CFA_OFFSET -8
+	.endm
+
+	.macro movq_cfi reg offset=0
+	movq %\reg, \offset(%rsp)
+	CFI_REL_OFFSET \reg, \offset
+	.endm
+
+	.macro movq_cfi_restore offset reg
+	movq \offset(%rsp), %\reg
+	CFI_RESTORE \reg
+	.endm
+#else /*!CONFIG_X86_64*/
+
+	/* 32bit defenitions are missed yet */
+
+#endif /*!CONFIG_X86_64*/
+#endif /*__ASSEMBLY__*/
+
 #endif /* _ASM_X86_DWARF2_H */
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 40ca1be..f51a3dd 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -325,7 +325,7 @@
 
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
 extern int arch_setup_additional_pages(struct linux_binprm *bprm,
-				       int executable_stack);
+				       int uses_interp);
 
 extern int syscall32_setup_pages(struct linux_binprm *, int exstack);
 #define compat_arch_setup_additional_pages	syscall32_setup_pages
diff --git a/arch/x86/include/asm/emergency-restart.h b/arch/x86/include/asm/emergency-restart.h
index 94826cf..cc70c1c 100644
--- a/arch/x86/include/asm/emergency-restart.h
+++ b/arch/x86/include/asm/emergency-restart.h
@@ -8,7 +8,9 @@
 	BOOT_BIOS = 'b',
 #endif
 	BOOT_ACPI = 'a',
-	BOOT_EFI = 'e'
+	BOOT_EFI = 'e',
+	BOOT_CF9 = 'p',
+	BOOT_CF9_COND = 'q',
 };
 
 extern enum reboot_type reboot_type;
diff --git a/arch/x86/include/asm/es7000/apic.h b/arch/x86/include/asm/es7000/apic.h
index 380f0b4..e24ef87 100644
--- a/arch/x86/include/asm/es7000/apic.h
+++ b/arch/x86/include/asm/es7000/apic.h
@@ -9,31 +9,27 @@
 	        return (1);
 }
 
-static inline cpumask_t target_cpus(void)
+static inline cpumask_t target_cpus_cluster(void)
 {
-#if defined CONFIG_ES7000_CLUSTERED_APIC
 	return CPU_MASK_ALL;
-#else
-	return cpumask_of_cpu(smp_processor_id());
-#endif
 }
 
-#if defined CONFIG_ES7000_CLUSTERED_APIC
-#define APIC_DFR_VALUE		(APIC_DFR_CLUSTER)
-#define INT_DELIVERY_MODE	(dest_LowestPrio)
-#define INT_DEST_MODE		(1)    /* logical delivery broadcast to all procs */
-#define NO_BALANCE_IRQ		(1)
-#undef  WAKE_SECONDARY_VIA_INIT
-#define WAKE_SECONDARY_VIA_MIP
-#else
+static inline cpumask_t target_cpus(void)
+{
+	return cpumask_of_cpu(smp_processor_id());
+}
+
+#define APIC_DFR_VALUE_CLUSTER		(APIC_DFR_CLUSTER)
+#define INT_DELIVERY_MODE_CLUSTER	(dest_LowestPrio)
+#define INT_DEST_MODE_CLUSTER		(1) /* logical delivery broadcast to all procs */
+#define NO_BALANCE_IRQ_CLUSTER		(1)
+
 #define APIC_DFR_VALUE		(APIC_DFR_FLAT)
 #define INT_DELIVERY_MODE	(dest_Fixed)
 #define INT_DEST_MODE		(0)    /* phys delivery to target procs */
 #define NO_BALANCE_IRQ		(0)
 #undef  APIC_DEST_LOGICAL
 #define APIC_DEST_LOGICAL	0x0
-#define WAKE_SECONDARY_VIA_INIT
-#endif
 
 static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
 {
@@ -60,6 +56,16 @@
  * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
  * document number 292116).  So here it goes...
  */
+static inline void init_apic_ldr_cluster(void)
+{
+	unsigned long val;
+	int cpu = smp_processor_id();
+
+	apic_write(APIC_DFR, APIC_DFR_VALUE_CLUSTER);
+	val = calculate_ldr(cpu);
+	apic_write(APIC_LDR, val);
+}
+
 static inline void init_apic_ldr(void)
 {
 	unsigned long val;
@@ -70,10 +76,6 @@
 	apic_write(APIC_LDR, val);
 }
 
-#ifndef CONFIG_X86_GENERICARCH
-extern void enable_apic_mode(void);
-#endif
-
 extern int apic_version [MAX_APICS];
 static inline void setup_apic_routing(void)
 {
@@ -144,7 +146,7 @@
 	return (1);
 }
 
-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
+static inline unsigned int cpu_mask_to_apicid_cluster(cpumask_t cpumask)
 {
 	int num_bits_set;
 	int cpus_found = 0;
@@ -154,11 +156,7 @@
 	num_bits_set = cpus_weight(cpumask);
 	/* Return id to all */
 	if (num_bits_set == NR_CPUS)
-#if defined CONFIG_ES7000_CLUSTERED_APIC
 		return 0xFF;
-#else
-		return cpu_to_logical_apicid(0);
-#endif
 	/*
 	 * The cpus in the mask must all be on the apic cluster.  If are not
 	 * on the same apicid cluster return default value of TARGET_CPUS.
@@ -171,11 +169,40 @@
 			if (apicid_cluster(apicid) !=
 					apicid_cluster(new_apicid)){
 				printk ("%s: Not a valid mask!\n", __func__);
-#if defined CONFIG_ES7000_CLUSTERED_APIC
 				return 0xFF;
-#else
+			}
+			apicid = new_apicid;
+			cpus_found++;
+		}
+		cpu++;
+	}
+	return apicid;
+}
+
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
+{
+	int num_bits_set;
+	int cpus_found = 0;
+	int cpu;
+	int apicid;
+
+	num_bits_set = cpus_weight(cpumask);
+	/* Return id to all */
+	if (num_bits_set == NR_CPUS)
+		return cpu_to_logical_apicid(0);
+	/*
+	 * The cpus in the mask must all be on the apic cluster.  If are not
+	 * on the same apicid cluster return default value of TARGET_CPUS.
+	 */
+	cpu = first_cpu(cpumask);
+	apicid = cpu_to_logical_apicid(cpu);
+	while (cpus_found < num_bits_set) {
+		if (cpu_isset(cpu, cpumask)) {
+			int new_apicid = cpu_to_logical_apicid(cpu);
+			if (apicid_cluster(apicid) !=
+					apicid_cluster(new_apicid)){
+				printk ("%s: Not a valid mask!\n", __func__);
 				return cpu_to_logical_apicid(0);
-#endif
 			}
 			apicid = new_apicid;
 			cpus_found++;
diff --git a/arch/x86/include/asm/es7000/wakecpu.h b/arch/x86/include/asm/es7000/wakecpu.h
index 3984934..78f0daa 100644
--- a/arch/x86/include/asm/es7000/wakecpu.h
+++ b/arch/x86/include/asm/es7000/wakecpu.h
@@ -1,36 +1,12 @@
 #ifndef __ASM_ES7000_WAKECPU_H
 #define __ASM_ES7000_WAKECPU_H
 
-/*
- * This file copes with machines that wakeup secondary CPUs by the
- * INIT, INIT, STARTUP sequence.
- */
-
-#ifdef CONFIG_ES7000_CLUSTERED_APIC
-#define WAKE_SECONDARY_VIA_MIP
-#else
-#define WAKE_SECONDARY_VIA_INIT
-#endif
-
-#ifdef WAKE_SECONDARY_VIA_MIP
-extern int es7000_start_cpu(int cpu, unsigned long eip);
-static inline int
-wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
-{
-	int boot_error = 0;
-	boot_error = es7000_start_cpu(phys_apicid, start_eip);
-	return boot_error;
-}
-#endif
-
-#define TRAMPOLINE_LOW phys_to_virt(0x467)
-#define TRAMPOLINE_HIGH phys_to_virt(0x469)
-
-#define boot_cpu_apicid boot_cpu_physical_apicid
+#define TRAMPOLINE_PHYS_LOW	0x467
+#define TRAMPOLINE_PHYS_HIGH	0x469
 
 static inline void wait_for_init_deassert(atomic_t *deassert)
 {
-#ifdef WAKE_SECONDARY_VIA_INIT
+#ifndef CONFIG_ES7000_CLUSTERED_APIC
 	while (!atomic_read(deassert))
 		cpu_relax();
 #endif
@@ -50,9 +26,12 @@
 {
 }
 
-#define inquire_remote_apic(apicid) do {		\
-		if (apic_verbosity >= APIC_DEBUG)	\
-			__inquire_remote_apic(apicid);	\
-	} while (0)
+extern void __inquire_remote_apic(int apicid);
+
+static inline void inquire_remote_apic(int apicid)
+{
+	if (apic_verbosity >= APIC_DEBUG)
+		__inquire_remote_apic(apicid);
+}
 
 #endif /* __ASM_MACH_WAKECPU_H */
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index 9e8bc29..b55b4a7 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -1,6 +1,33 @@
 #ifndef _ASM_X86_FTRACE_H
 #define _ASM_X86_FTRACE_H
 
+#ifdef __ASSEMBLY__
+
+	.macro MCOUNT_SAVE_FRAME
+	/* taken from glibc */
+	subq $0x38, %rsp
+	movq %rax, (%rsp)
+	movq %rcx, 8(%rsp)
+	movq %rdx, 16(%rsp)
+	movq %rsi, 24(%rsp)
+	movq %rdi, 32(%rsp)
+	movq %r8, 40(%rsp)
+	movq %r9, 48(%rsp)
+	.endm
+
+	.macro MCOUNT_RESTORE_FRAME
+	movq 48(%rsp), %r9
+	movq 40(%rsp), %r8
+	movq 32(%rsp), %rdi
+	movq 24(%rsp), %rsi
+	movq 16(%rsp), %rdx
+	movq 8(%rsp), %rcx
+	movq (%rsp), %rax
+	addq $0x38, %rsp
+	.endm
+
+#endif
+
 #ifdef CONFIG_FUNCTION_TRACER
 #define MCOUNT_ADDR		((long)(mcount))
 #define MCOUNT_INSN_SIZE	5 /* sizeof mcount call */
@@ -17,8 +44,40 @@
 	 */
 	return addr - 1;
 }
-#endif
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+struct dyn_arch_ftrace {
+	/* No extra data needed for x86 */
+};
+
+#endif /*  CONFIG_DYNAMIC_FTRACE */
+#endif /* __ASSEMBLY__ */
 #endif /* CONFIG_FUNCTION_TRACER */
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Stack of return addresses for functions
+ * of a thread.
+ * Used in struct thread_info
+ */
+struct ftrace_ret_stack {
+	unsigned long ret;
+	unsigned long func;
+	unsigned long long calltime;
+};
+
+/*
+ * Primary handler of a function return.
+ * It relays on ftrace_return_to_handler.
+ * Defined in entry_32/64.S
+ */
+extern void return_to_handler(void);
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
 #endif /* _ASM_X86_FTRACE_H */
diff --git a/arch/x86/include/asm/gart.h b/arch/x86/include/asm/gart.h
index 7425226..6cfdafa 100644
--- a/arch/x86/include/asm/gart.h
+++ b/arch/x86/include/asm/gart.h
@@ -29,6 +29,39 @@
 #define AMD64_GARTCACHECTL	0x9c
 #define AMD64_GARTEN		(1<<0)
 
+#ifdef CONFIG_GART_IOMMU
+extern int gart_iommu_aperture;
+extern int gart_iommu_aperture_allowed;
+extern int gart_iommu_aperture_disabled;
+
+extern void early_gart_iommu_check(void);
+extern void gart_iommu_init(void);
+extern void gart_iommu_shutdown(void);
+extern void __init gart_parse_options(char *);
+extern void gart_iommu_hole_init(void);
+
+#else
+#define gart_iommu_aperture            0
+#define gart_iommu_aperture_allowed    0
+#define gart_iommu_aperture_disabled   1
+
+static inline void early_gart_iommu_check(void)
+{
+}
+static inline void gart_iommu_init(void)
+{
+}
+static inline void gart_iommu_shutdown(void)
+{
+}
+static inline void gart_parse_options(char *options)
+{
+}
+static inline void gart_iommu_hole_init(void)
+{
+}
+#endif
+
 extern int agp_amd64_init(void);
 
 static inline void enable_gart_translation(struct pci_dev *dev, u64 addr)
diff --git a/arch/x86/include/asm/genapic_32.h b/arch/x86/include/asm/genapic_32.h
index 5cbd4fc..0ac17d3 100644
--- a/arch/x86/include/asm/genapic_32.h
+++ b/arch/x86/include/asm/genapic_32.h
@@ -2,6 +2,7 @@
 #define _ASM_X86_GENAPIC_32_H
 
 #include <asm/mpspec.h>
+#include <asm/atomic.h>
 
 /*
  * Generic APIC driver interface.
@@ -65,6 +66,14 @@
 	void (*send_IPI_allbutself)(int vector);
 	void (*send_IPI_all)(int vector);
 #endif
+	int (*wakeup_cpu)(int apicid, unsigned long start_eip);
+	int trampoline_phys_low;
+	int trampoline_phys_high;
+	void (*wait_for_init_deassert)(atomic_t *deassert);
+	void (*smp_callin_clear_local_apic)(void);
+	void (*store_NMI_vector)(unsigned short *high, unsigned short *low);
+	void (*restore_NMI_vector)(unsigned short *high, unsigned short *low);
+	void (*inquire_remote_apic)(int apicid);
 };
 
 #define APICFUNC(x) .x = x,
@@ -105,16 +114,24 @@
 	APICFUNC(get_apic_id)				\
 	.apic_id_mask = APIC_ID_MASK,			\
 	APICFUNC(cpu_mask_to_apicid)			\
-	APICFUNC(vector_allocation_domain)			\
+	APICFUNC(vector_allocation_domain)		\
 	APICFUNC(acpi_madt_oem_check)			\
 	IPIFUNC(send_IPI_mask)				\
 	IPIFUNC(send_IPI_allbutself)			\
 	IPIFUNC(send_IPI_all)				\
 	APICFUNC(enable_apic_mode)			\
 	APICFUNC(phys_pkg_id)				\
+	.trampoline_phys_low = TRAMPOLINE_PHYS_LOW,		\
+	.trampoline_phys_high = TRAMPOLINE_PHYS_HIGH,		\
+	APICFUNC(wait_for_init_deassert)		\
+	APICFUNC(smp_callin_clear_local_apic)		\
+	APICFUNC(store_NMI_vector)			\
+	APICFUNC(restore_NMI_vector)			\
+	APICFUNC(inquire_remote_apic)			\
 }
 
 extern struct genapic *genapic;
+extern void es7000_update_genapic_to_cluster(void);
 
 enum uv_system_type {UV_NONE, UV_LEGACY_APIC, UV_X2APIC, UV_NON_UNIQUE_APIC};
 #define get_uv_system_type()		UV_NONE
diff --git a/arch/x86/include/asm/genapic_64.h b/arch/x86/include/asm/genapic_64.h
index 13c4e96..2cae011 100644
--- a/arch/x86/include/asm/genapic_64.h
+++ b/arch/x86/include/asm/genapic_64.h
@@ -32,6 +32,8 @@
 	unsigned int (*get_apic_id)(unsigned long x);
 	unsigned long (*set_apic_id)(unsigned int id);
 	unsigned long apic_id_mask;
+	/* wakeup_secondary_cpu */
+	int (*wakeup_cpu)(int apicid, unsigned long start_eip);
 };
 
 extern struct genapic *genapic;
diff --git a/arch/x86/include/asm/hardirq_32.h b/arch/x86/include/asm/hardirq_32.h
index 5ca135e..cf7954d 100644
--- a/arch/x86/include/asm/hardirq_32.h
+++ b/arch/x86/include/asm/hardirq_32.h
@@ -22,6 +22,8 @@
 #define __ARCH_IRQ_STAT
 #define __IRQ_STAT(cpu, member) (per_cpu(irq_stat, cpu).member)
 
+#define inc_irq_stat(member)	(__get_cpu_var(irq_stat).member++)
+
 void ack_bad_irq(unsigned int irq);
 #include <linux/irq_cpustat.h>
 
diff --git a/arch/x86/include/asm/hardirq_64.h b/arch/x86/include/asm/hardirq_64.h
index 1ba381f..b5a6b5d 100644
--- a/arch/x86/include/asm/hardirq_64.h
+++ b/arch/x86/include/asm/hardirq_64.h
@@ -11,6 +11,8 @@
 
 #define __ARCH_IRQ_STAT 1
 
+#define inc_irq_stat(member)	add_pda(member, 1)
+
 #define local_softirq_pending() read_pda(__softirq_pending)
 
 #define __ARCH_SET_SOFTIRQ_PENDING 1
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index b97aecb..8de644b 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -109,9 +109,7 @@
 #endif
 #endif
 
-#ifdef CONFIG_X86_32
-extern void (*const interrupt[NR_VECTORS])(void);
-#endif
+extern void (*__initconst interrupt[NR_VECTORS-FIRST_EXTERNAL_VECTOR])(void);
 
 typedef int vector_irq_t[NR_VECTORS];
 DECLARE_PER_CPU(vector_irq_t, vector_irq);
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h
new file mode 100644
index 0000000..369f5c5
--- /dev/null
+++ b/arch/x86/include/asm/hypervisor.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008, VMware, 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef ASM_X86__HYPERVISOR_H
+#define ASM_X86__HYPERVISOR_H
+
+extern unsigned long get_hypervisor_tsc_freq(void);
+extern void init_hypervisor(struct cpuinfo_x86 *c);
+
+#endif
diff --git a/arch/x86/include/asm/ia32.h b/arch/x86/include/asm/ia32.h
index 97989c0..50ca486 100644
--- a/arch/x86/include/asm/ia32.h
+++ b/arch/x86/include/asm/ia32.h
@@ -129,24 +129,6 @@
 	} _sifields;
 } compat_siginfo_t;
 
-struct sigframe32 {
-	u32 pretcode;
-	int sig;
-	struct sigcontext_ia32 sc;
-	struct _fpstate_ia32 fpstate;
-	unsigned int extramask[_COMPAT_NSIG_WORDS-1];
-};
-
-struct rt_sigframe32 {
-	u32 pretcode;
-	int sig;
-	u32 pinfo;
-	u32 puc;
-	compat_siginfo_t info;
-	struct ucontext_ia32 uc;
-	struct _fpstate_ia32 fpstate;
-};
-
 struct ustat32 {
 	__u32			f_tfree;
 	compat_ino_t		f_tinode;
diff --git a/arch/x86/include/asm/idle.h b/arch/x86/include/asm/idle.h
index 44c89c3..38d8737 100644
--- a/arch/x86/include/asm/idle.h
+++ b/arch/x86/include/asm/idle.h
@@ -8,8 +8,13 @@
 void idle_notifier_register(struct notifier_block *n);
 void idle_notifier_unregister(struct notifier_block *n);
 
+#ifdef CONFIG_X86_64
 void enter_idle(void);
 void exit_idle(void);
+#else /* !CONFIG_X86_64 */
+static inline void enter_idle(void) { }
+static inline void exit_idle(void) { }
+#endif /* CONFIG_X86_64 */
 
 void c1e_remove_cpu(int cpu);
 
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index ac2abc8..05cfed4 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -4,6 +4,7 @@
 #define ARCH_HAS_IOREMAP_WC
 
 #include <linux/compiler.h>
+#include <asm-generic/int-ll64.h>
 
 #define build_mmio_read(name, size, type, reg, barrier) \
 static inline type name(const volatile void __iomem *addr) \
@@ -45,21 +46,39 @@
 #define mmiowb() barrier()
 
 #ifdef CONFIG_X86_64
+
 build_mmio_read(readq, "q", unsigned long, "=r", :"memory")
-build_mmio_read(__readq, "q", unsigned long, "=r", )
 build_mmio_write(writeq, "q", unsigned long, "r", :"memory")
-build_mmio_write(__writeq, "q", unsigned long, "r", )
 
-#define readq_relaxed(a) __readq(a)
-#define __raw_readq __readq
-#define __raw_writeq writeq
+#else
 
-/* Let people know we have them */
-#define readq readq
-#define writeq writeq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+	const volatile u32 __iomem *p = addr;
+	u32 low, high;
+
+	low = readl(p);
+	high = readl(p + 1);
+
+	return low + ((u64)high << 32);
+}
+
+static inline void writeq(__u64 val, volatile void __iomem *addr)
+{
+	writel(val, addr);
+	writel(val >> 32, addr+4);
+}
+
 #endif
 
-extern int iommu_bio_merge;
+#define readq_relaxed(a)	readq(a)
+
+#define __raw_readq(a)		readq(a)
+#define __raw_writeq(val, addr)	writeq(val, addr)
+
+/* Let people know that we have them */
+#define readq			readq
+#define writeq			writeq
 
 #ifdef CONFIG_X86_32
 # include "io_32.h"
diff --git a/arch/x86/include/asm/io_64.h b/arch/x86/include/asm/io_64.h
index fea325a..563c162 100644
--- a/arch/x86/include/asm/io_64.h
+++ b/arch/x86/include/asm/io_64.h
@@ -232,8 +232,6 @@
 
 #define flush_write_buffers()
 
-#define BIO_VMERGE_BOUNDARY iommu_bio_merge
-
 /*
  * Convert a virtual cached pointer to an uncached pointer
  */
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 6afd993..e475e00 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -156,11 +156,21 @@
 /* 1 if "noapic" boot option passed */
 extern int skip_ioapic_setup;
 
+/* 1 if "noapic" boot option passed */
+extern int noioapicquirk;
+
+/* -1 if "noapic" boot option passed */
+extern int noioapicreroute;
+
 /* 1 if the timer IRQ uses the '8259A Virtual Wire' mode */
 extern int timer_through_8259;
 
 static inline void disable_ioapic_setup(void)
 {
+#ifdef CONFIG_PCI
+	noioapicquirk = 1;
+	noioapicreroute = -1;
+#endif
 	skip_ioapic_setup = 1;
 }
 
diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h
index 0b500c5..295b131 100644
--- a/arch/x86/include/asm/iommu.h
+++ b/arch/x86/include/asm/iommu.h
@@ -12,37 +12,4 @@
 /* 10 seconds */
 #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
 
-#ifdef CONFIG_GART_IOMMU
-extern int gart_iommu_aperture;
-extern int gart_iommu_aperture_allowed;
-extern int gart_iommu_aperture_disabled;
-
-extern void early_gart_iommu_check(void);
-extern void gart_iommu_init(void);
-extern void gart_iommu_shutdown(void);
-extern void __init gart_parse_options(char *);
-extern void gart_iommu_hole_init(void);
-
-#else
-#define gart_iommu_aperture            0
-#define gart_iommu_aperture_allowed    0
-#define gart_iommu_aperture_disabled   1
-
-static inline void early_gart_iommu_check(void)
-{
-}
-static inline void gart_iommu_init(void)
-{
-}
-static inline void gart_iommu_shutdown(void)
-{
-}
-static inline void gart_parse_options(char *options)
-{
-}
-static inline void gart_iommu_hole_init(void)
-{
-}
-#endif
-
 #endif /* _ASM_X86_IOMMU_H */
diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h
index bae0eda..28e409f 100644
--- a/arch/x86/include/asm/irq.h
+++ b/arch/x86/include/asm/irq.h
@@ -31,10 +31,6 @@
 # endif
 #endif
 
-#ifdef CONFIG_IRQBALANCE
-extern int irqbalance_disable(char *str);
-#endif
-
 #ifdef CONFIG_HOTPLUG_CPU
 #include <linux/cpumask.h>
 extern void fixup_irqs(cpumask_t map);
diff --git a/arch/x86/include/asm/irq_regs_32.h b/arch/x86/include/asm/irq_regs_32.h
index af2f02d..86afd74 100644
--- a/arch/x86/include/asm/irq_regs_32.h
+++ b/arch/x86/include/asm/irq_regs_32.h
@@ -9,6 +9,8 @@
 
 #include <asm/percpu.h>
 
+#define ARCH_HAS_OWN_IRQ_REGS
+
 DECLARE_PER_CPU(struct pt_regs *, irq_regs);
 
 static inline struct pt_regs *get_irq_regs(void)
diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h
index a1f2277..c61d8b2 100644
--- a/arch/x86/include/asm/kexec.h
+++ b/arch/x86/include/asm/kexec.h
@@ -5,21 +5,8 @@
 # define PA_CONTROL_PAGE	0
 # define VA_CONTROL_PAGE	1
 # define PA_PGD			2
-# define VA_PGD			3
-# define PA_PTE_0		4
-# define VA_PTE_0		5
-# define PA_PTE_1		6
-# define VA_PTE_1		7
-# define PA_SWAP_PAGE		8
-# ifdef CONFIG_X86_PAE
-#  define PA_PMD_0		9
-#  define VA_PMD_0		10
-#  define PA_PMD_1		11
-#  define VA_PMD_1		12
-#  define PAGES_NR		13
-# else
-#  define PAGES_NR		9
-# endif
+# define PA_SWAP_PAGE		3
+# define PAGES_NR		4
 #else
 # define PA_CONTROL_PAGE	0
 # define VA_CONTROL_PAGE	1
@@ -170,6 +157,20 @@
 		unsigned long start_address) ATTRIB_NORET;
 #endif
 
+#ifdef CONFIG_X86_32
+#define ARCH_HAS_KIMAGE_ARCH
+
+struct kimage_arch {
+	pgd_t *pgd;
+#ifdef CONFIG_X86_PAE
+	pmd_t *pmd0;
+	pmd_t *pmd1;
+#endif
+	pte_t *pte0;
+	pte_t *pte1;
+};
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_X86_KEXEC_H */
diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h
index f61ee8f..5d98d0b 100644
--- a/arch/x86/include/asm/linkage.h
+++ b/arch/x86/include/asm/linkage.h
@@ -57,5 +57,65 @@
 #define __ALIGN_STR ".align 16,0x90"
 #endif
 
+/*
+ * to check ENTRY_X86/END_X86 and
+ * KPROBE_ENTRY_X86/KPROBE_END_X86
+ * unbalanced-missed-mixed appearance
+ */
+#define __set_entry_x86		.set ENTRY_X86_IN, 0
+#define __unset_entry_x86	.set ENTRY_X86_IN, 1
+#define __set_kprobe_x86	.set KPROBE_X86_IN, 0
+#define __unset_kprobe_x86	.set KPROBE_X86_IN, 1
+
+#define __macro_err_x86 .error "ENTRY_X86/KPROBE_X86 unbalanced,missed,mixed"
+
+#define __check_entry_x86	\
+	.ifdef ENTRY_X86_IN;	\
+	.ifeq ENTRY_X86_IN;	\
+	__macro_err_x86;	\
+	.abort;			\
+	.endif;			\
+	.endif
+
+#define __check_kprobe_x86	\
+	.ifdef KPROBE_X86_IN;	\
+	.ifeq KPROBE_X86_IN;	\
+	__macro_err_x86;	\
+	.abort;			\
+	.endif;			\
+	.endif
+
+#define __check_entry_kprobe_x86	\
+	__check_entry_x86;		\
+	__check_kprobe_x86
+
+#define ENTRY_KPROBE_FINAL_X86 __check_entry_kprobe_x86
+
+#define ENTRY_X86(name)			\
+	__check_entry_kprobe_x86;	\
+	__set_entry_x86;		\
+	.globl name;			\
+	__ALIGN;			\
+	name:
+
+#define END_X86(name)			\
+	__unset_entry_x86;		\
+	__check_entry_kprobe_x86;	\
+	.size name, .-name
+
+#define KPROBE_ENTRY_X86(name)		\
+	__check_entry_kprobe_x86;	\
+	__set_kprobe_x86;		\
+	.pushsection .kprobes.text, "ax"; \
+	.globl name;			\
+	__ALIGN;			\
+	name:
+
+#define KPROBE_END_X86(name)		\
+	__unset_kprobe_x86;		\
+	__check_entry_kprobe_x86;	\
+	.size name, .-name;		\
+	.popsection
+
 #endif /* _ASM_X86_LINKAGE_H */
 
diff --git a/arch/x86/include/asm/mach-default/mach_apic.h b/arch/x86/include/asm/mach-default/mach_apic.h
index ff3a6c2..6cb3a46 100644
--- a/arch/x86/include/asm/mach-default/mach_apic.h
+++ b/arch/x86/include/asm/mach-default/mach_apic.h
@@ -32,11 +32,13 @@
 #define vector_allocation_domain    (genapic->vector_allocation_domain)
 #define read_apic_id()  (GET_APIC_ID(apic_read(APIC_ID)))
 #define send_IPI_self (genapic->send_IPI_self)
+#define wakeup_secondary_cpu (genapic->wakeup_cpu)
 extern void setup_apic_routing(void);
 #else
 #define INT_DELIVERY_MODE dest_LowestPrio
 #define INT_DEST_MODE 1     /* logical delivery broadcast to all procs */
 #define TARGET_CPUS (target_cpus())
+#define wakeup_secondary_cpu wakeup_secondary_cpu_via_init
 /*
  * Set up the logical destination ID.
  *
diff --git a/arch/x86/include/asm/mach-default/mach_wakecpu.h b/arch/x86/include/asm/mach-default/mach_wakecpu.h
index 9d80db9..ceb0136 100644
--- a/arch/x86/include/asm/mach-default/mach_wakecpu.h
+++ b/arch/x86/include/asm/mach-default/mach_wakecpu.h
@@ -1,17 +1,8 @@
 #ifndef _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H
 #define _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H
 
-/* 
- * This file copes with machines that wakeup secondary CPUs by the
- * INIT, INIT, STARTUP sequence.
- */
-
-#define WAKE_SECONDARY_VIA_INIT
-
-#define TRAMPOLINE_LOW phys_to_virt(0x467)
-#define TRAMPOLINE_HIGH phys_to_virt(0x469)
-
-#define boot_cpu_apicid boot_cpu_physical_apicid
+#define TRAMPOLINE_PHYS_LOW (0x467)
+#define TRAMPOLINE_PHYS_HIGH (0x469)
 
 static inline void wait_for_init_deassert(atomic_t *deassert)
 {
@@ -33,9 +24,12 @@
 {
 }
 
-#define inquire_remote_apic(apicid) do {		\
-		if (apic_verbosity >= APIC_DEBUG)	\
-			__inquire_remote_apic(apicid);	\
-	} while (0)
+extern void __inquire_remote_apic(int apicid);
+
+static inline void inquire_remote_apic(int apicid)
+{
+	if (apic_verbosity >= APIC_DEBUG)
+		__inquire_remote_apic(apicid);
+}
 
 #endif /* _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H */
diff --git a/arch/x86/include/asm/mach-default/smpboot_hooks.h b/arch/x86/include/asm/mach-default/smpboot_hooks.h
index dbab36d..23bf521 100644
--- a/arch/x86/include/asm/mach-default/smpboot_hooks.h
+++ b/arch/x86/include/asm/mach-default/smpboot_hooks.h
@@ -13,9 +13,11 @@
 	CMOS_WRITE(0xa, 0xf);
 	local_flush_tlb();
 	pr_debug("1.\n");
-	*((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
+	*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) =
+								 start_eip >> 4;
 	pr_debug("2.\n");
-	*((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
+	*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) =
+							 start_eip & 0xf;
 	pr_debug("3.\n");
 }
 
@@ -32,7 +34,7 @@
 	 */
 	CMOS_WRITE(0, 0xf);
 
-	*((volatile long *) phys_to_virt(0x467)) = 0;
+	*((volatile long *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0;
 }
 
 static inline void __init smpboot_setup_io_apic(void)
diff --git a/arch/x86/include/asm/mach-generic/mach_apic.h b/arch/x86/include/asm/mach-generic/mach_apic.h
index 5180bd7..e430f47 100644
--- a/arch/x86/include/asm/mach-generic/mach_apic.h
+++ b/arch/x86/include/asm/mach-generic/mach_apic.h
@@ -27,6 +27,7 @@
 #define vector_allocation_domain (genapic->vector_allocation_domain)
 #define enable_apic_mode (genapic->enable_apic_mode)
 #define phys_pkg_id (genapic->phys_pkg_id)
+#define wakeup_secondary_cpu (genapic->wakeup_cpu)
 
 extern void generic_bigsmp_probe(void);
 
diff --git a/arch/x86/include/asm/mach-generic/mach_wakecpu.h b/arch/x86/include/asm/mach-generic/mach_wakecpu.h
new file mode 100644
index 0000000..1ab16b1
--- /dev/null
+++ b/arch/x86/include/asm/mach-generic/mach_wakecpu.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_X86_MACH_GENERIC_MACH_WAKECPU_H
+#define _ASM_X86_MACH_GENERIC_MACH_WAKECPU_H
+
+#define TRAMPOLINE_PHYS_LOW (genapic->trampoline_phys_low)
+#define TRAMPOLINE_PHYS_HIGH (genapic->trampoline_phys_high)
+#define wait_for_init_deassert (genapic->wait_for_init_deassert)
+#define smp_callin_clear_local_apic (genapic->smp_callin_clear_local_apic)
+#define store_NMI_vector (genapic->store_NMI_vector)
+#define restore_NMI_vector (genapic->restore_NMI_vector)
+#define inquire_remote_apic (genapic->inquire_remote_apic)
+
+#endif /* _ASM_X86_MACH_GENERIC_MACH_APIC_H */
diff --git a/arch/x86/include/asm/mmu_context_32.h b/arch/x86/include/asm/mmu_context_32.h
index 8e10015..7e98ce1 100644
--- a/arch/x86/include/asm/mmu_context_32.h
+++ b/arch/x86/include/asm/mmu_context_32.h
@@ -4,9 +4,8 @@
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
 #ifdef CONFIG_SMP
-	unsigned cpu = smp_processor_id();
-	if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
-		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_LAZY;
+	if (x86_read_percpu(cpu_tlbstate.state) == TLBSTATE_OK)
+		x86_write_percpu(cpu_tlbstate.state, TLBSTATE_LAZY);
 #endif
 }
 
@@ -20,8 +19,8 @@
 		/* stop flush ipis for the previous mm */
 		cpu_clear(cpu, prev->cpu_vm_mask);
 #ifdef CONFIG_SMP
-		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
-		per_cpu(cpu_tlbstate, cpu).active_mm = next;
+		x86_write_percpu(cpu_tlbstate.state, TLBSTATE_OK);
+		x86_write_percpu(cpu_tlbstate.active_mm, next);
 #endif
 		cpu_set(cpu, next->cpu_vm_mask);
 
@@ -36,8 +35,8 @@
 	}
 #ifdef CONFIG_SMP
 	else {
-		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
-		BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);
+		x86_write_percpu(cpu_tlbstate.state, TLBSTATE_OK);
+		BUG_ON(x86_read_percpu(cpu_tlbstate.active_mm) != next);
 
 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
 			/* We were in lazy tlb mode and leave_mm disabled
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index e38859d..cb58643 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -85,7 +85,9 @@
 /* AMD64 MSRs. Not complete. See the architecture manual for a more
    complete list. */
 
+#define MSR_AMD64_PATCH_LEVEL		0x0000008b
 #define MSR_AMD64_NB_CFG		0xc001001f
+#define MSR_AMD64_PATCH_LOADER		0xc0010020
 #define MSR_AMD64_IBSFETCHCTL		0xc0011030
 #define MSR_AMD64_IBSFETCHLINAD		0xc0011031
 #define MSR_AMD64_IBSFETCHPHYSAD	0xc0011032
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index c2a812e..638bf62 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -22,10 +22,10 @@
 }
 
 /*
- * i386 calling convention returns 64-bit value in edx:eax, while
- * x86_64 returns at rax. Also, the "A" constraint does not really
- * mean rdx:rax in x86_64, so we need specialized behaviour for each
- * architecture
+ * both i386 and x86_64 returns 64-bit value in edx:eax, but gcc's "A"
+ * constraint has different meanings. For i386, "A" means exactly
+ * edx:eax, while for x86_64 it doesn't mean rdx:rax or edx:eax. Instead,
+ * it means rax *or* rdx.
  */
 #ifdef CONFIG_X86_64
 #define DECLARE_ARGS(val, low, high)	unsigned low, high
@@ -85,7 +85,8 @@
 	asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory");
 }
 
-static inline int native_write_msr_safe(unsigned int msr,
+/* Can be uninlined because referenced by paravirt */
+notrace static inline int native_write_msr_safe(unsigned int msr,
 					unsigned low, unsigned high)
 {
 	int err;
@@ -181,10 +182,10 @@
 }
 
 #define rdtscl(low)						\
-	((low) = (u32)native_read_tsc())
+	((low) = (u32)__native_read_tsc())
 
 #define rdtscll(val)						\
-	((val) = native_read_tsc())
+	((val) = __native_read_tsc())
 
 #define rdpmc(counter, low, high)			\
 do {							\
diff --git a/arch/x86/include/asm/numaq/wakecpu.h b/arch/x86/include/asm/numaq/wakecpu.h
index c577bda..6f499df 100644
--- a/arch/x86/include/asm/numaq/wakecpu.h
+++ b/arch/x86/include/asm/numaq/wakecpu.h
@@ -3,12 +3,8 @@
 
 /* This file copes with machines that wakeup secondary CPUs by NMIs */
 
-#define WAKE_SECONDARY_VIA_NMI
-
-#define TRAMPOLINE_LOW phys_to_virt(0x8)
-#define TRAMPOLINE_HIGH phys_to_virt(0xa)
-
-#define boot_cpu_apicid boot_cpu_logical_apicid
+#define TRAMPOLINE_PHYS_LOW (0x8)
+#define TRAMPOLINE_PHYS_HIGH (0xa)
 
 /* We don't do anything here because we use NMI's to boot instead */
 static inline void wait_for_init_deassert(atomic_t *deassert)
@@ -27,17 +23,23 @@
 static inline void store_NMI_vector(unsigned short *high, unsigned short *low)
 {
 	printk("Storing NMI vector\n");
-	*high = *((volatile unsigned short *) TRAMPOLINE_HIGH);
-	*low = *((volatile unsigned short *) TRAMPOLINE_LOW);
+	*high =
+	  *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH));
+	*low =
+	  *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW));
 }
 
 static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
 {
 	printk("Restoring NMI vector\n");
-	*((volatile unsigned short *) TRAMPOLINE_HIGH) = *high;
-	*((volatile unsigned short *) TRAMPOLINE_LOW) = *low;
+	*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) =
+								 *high;
+	*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) =
+								 *low;
 }
 
-#define inquire_remote_apic(apicid) {}
+static inline void inquire_remote_apic(int apicid)
+{
+}
 
 #endif /* __ASM_NUMAQ_WAKECPU_H */
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 875b38e..6477812 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -19,6 +19,8 @@
 };
 
 extern int pci_routeirq;
+extern int noioapicquirk;
+extern int noioapicreroute;
 
 /* scan a bus after allocating a pci_sysdata for it */
 extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops,
diff --git a/arch/x86/include/asm/pgtable-2level.h b/arch/x86/include/asm/pgtable-2level.h
index b17edfd..e0d199f 100644
--- a/arch/x86/include/asm/pgtable-2level.h
+++ b/arch/x86/include/asm/pgtable-2level.h
@@ -56,23 +56,55 @@
 #define pte_none(x)		(!(x).pte_low)
 
 /*
- * Bits 0, 6 and 7 are taken, split up the 29 bits of offset
- * into this range:
+ * Bits _PAGE_BIT_PRESENT, _PAGE_BIT_FILE and _PAGE_BIT_PROTNONE are taken,
+ * split up the 29 bits of offset into this range:
  */
 #define PTE_FILE_MAX_BITS	29
+#define PTE_FILE_SHIFT1		(_PAGE_BIT_PRESENT + 1)
+#if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE
+#define PTE_FILE_SHIFT2		(_PAGE_BIT_FILE + 1)
+#define PTE_FILE_SHIFT3		(_PAGE_BIT_PROTNONE + 1)
+#else
+#define PTE_FILE_SHIFT2		(_PAGE_BIT_PROTNONE + 1)
+#define PTE_FILE_SHIFT3		(_PAGE_BIT_FILE + 1)
+#endif
+#define PTE_FILE_BITS1		(PTE_FILE_SHIFT2 - PTE_FILE_SHIFT1 - 1)
+#define PTE_FILE_BITS2		(PTE_FILE_SHIFT3 - PTE_FILE_SHIFT2 - 1)
 
 #define pte_to_pgoff(pte)						\
-	((((pte).pte_low >> 1) & 0x1f) + (((pte).pte_low >> 8) << 5))
+	((((pte).pte_low >> PTE_FILE_SHIFT1)				\
+	  & ((1U << PTE_FILE_BITS1) - 1))				\
+	 + ((((pte).pte_low >> PTE_FILE_SHIFT2)				\
+	     & ((1U << PTE_FILE_BITS2) - 1)) << PTE_FILE_BITS1)		\
+	 + (((pte).pte_low >> PTE_FILE_SHIFT3)				\
+	    << (PTE_FILE_BITS1 + PTE_FILE_BITS2)))
 
 #define pgoff_to_pte(off)						\
-	((pte_t) { .pte_low = (((off) & 0x1f) << 1) +			\
-			(((off) >> 5) << 8) + _PAGE_FILE })
+	((pte_t) { .pte_low =						\
+	 (((off) & ((1U << PTE_FILE_BITS1) - 1)) << PTE_FILE_SHIFT1)	\
+	 + ((((off) >> PTE_FILE_BITS1) & ((1U << PTE_FILE_BITS2) - 1))	\
+	    << PTE_FILE_SHIFT2)						\
+	 + (((off) >> (PTE_FILE_BITS1 + PTE_FILE_BITS2))		\
+	    << PTE_FILE_SHIFT3)						\
+	 + _PAGE_FILE })
 
 /* Encode and de-code a swap entry */
-#define __swp_type(x)			(((x).val >> 1) & 0x1f)
-#define __swp_offset(x)			((x).val >> 8)
-#define __swp_entry(type, offset)				\
-	((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
+#if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE
+#define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1)
+#define SWP_OFFSET_SHIFT (_PAGE_BIT_PROTNONE + 1)
+#else
+#define SWP_TYPE_BITS (_PAGE_BIT_PROTNONE - _PAGE_BIT_PRESENT - 1)
+#define SWP_OFFSET_SHIFT (_PAGE_BIT_FILE + 1)
+#endif
+
+#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS)
+
+#define __swp_type(x)			(((x).val >> (_PAGE_BIT_PRESENT + 1)) \
+					 & ((1U << SWP_TYPE_BITS) - 1))
+#define __swp_offset(x)			((x).val >> SWP_OFFSET_SHIFT)
+#define __swp_entry(type, offset)	((swp_entry_t) { \
+					 ((type) << (_PAGE_BIT_PRESENT + 1)) \
+					 | ((offset) << SWP_OFFSET_SHIFT) })
 #define __pte_to_swp_entry(pte)		((swp_entry_t) { (pte).pte_low })
 #define __swp_entry_to_pte(x)		((pte_t) { .pte = (x).val })
 
diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h
index 52597ae..447da43 100644
--- a/arch/x86/include/asm/pgtable-3level.h
+++ b/arch/x86/include/asm/pgtable-3level.h
@@ -166,6 +166,7 @@
 #define PTE_FILE_MAX_BITS       32
 
 /* Encode and de-code a swap entry */
+#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > 5)
 #define __swp_type(x)			(((x).val) & 0x1f)
 #define __swp_offset(x)			((x).val >> 5)
 #define __swp_entry(type, offset)	((swp_entry_t){(type) | (offset) << 5})
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index c012f3b..83e69f4 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -10,7 +10,6 @@
 #define _PAGE_BIT_PCD		4	/* page cache disabled */
 #define _PAGE_BIT_ACCESSED	5	/* was accessed (raised by CPU) */
 #define _PAGE_BIT_DIRTY		6	/* was written to (raised by CPU) */
-#define _PAGE_BIT_FILE		6
 #define _PAGE_BIT_PSE		7	/* 4 MB (or 2MB) page */
 #define _PAGE_BIT_PAT		7	/* on 4KB pages */
 #define _PAGE_BIT_GLOBAL	8	/* Global TLB entry PPro+ */
@@ -22,6 +21,12 @@
 #define _PAGE_BIT_CPA_TEST	_PAGE_BIT_UNUSED1
 #define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
 
+/* If _PAGE_BIT_PRESENT is clear, we use these: */
+/* - if the user mapped it with PROT_NONE; pte_present gives true */
+#define _PAGE_BIT_PROTNONE	_PAGE_BIT_GLOBAL
+/* - set: nonlinear file mapping, saved PTE; unset:swap */
+#define _PAGE_BIT_FILE		_PAGE_BIT_DIRTY
+
 #define _PAGE_PRESENT	(_AT(pteval_t, 1) << _PAGE_BIT_PRESENT)
 #define _PAGE_RW	(_AT(pteval_t, 1) << _PAGE_BIT_RW)
 #define _PAGE_USER	(_AT(pteval_t, 1) << _PAGE_BIT_USER)
@@ -46,11 +51,8 @@
 #define _PAGE_NX	(_AT(pteval_t, 0))
 #endif
 
-/* If _PAGE_PRESENT is clear, we use these: */
-#define _PAGE_FILE	_PAGE_DIRTY	/* nonlinear file mapping,
-					 * saved PTE; unset:swap */
-#define _PAGE_PROTNONE	_PAGE_PSE	/* if the user mapped it with PROT_NONE;
-					   pte_present gives true */
+#define _PAGE_FILE	(_AT(pteval_t, 1) << _PAGE_BIT_FILE)
+#define _PAGE_PROTNONE	(_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE)
 
 #define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER |	\
 			 _PAGE_ACCESSED | _PAGE_DIRTY)
@@ -158,8 +160,19 @@
 #define PGD_IDENT_ATTR	 0x001		/* PRESENT (no other attributes) */
 #endif
 
+/*
+ * Macro to mark a page protection value as UC-
+ */
+#define pgprot_noncached(prot)					\
+	((boot_cpu_data.x86 > 3)				\
+	 ? (__pgprot(pgprot_val(prot) | _PAGE_CACHE_UC_MINUS))	\
+	 : (prot))
+
 #ifndef __ASSEMBLY__
 
+#define pgprot_writecombine	pgprot_writecombine
+extern pgprot_t pgprot_writecombine(pgprot_t prot);
+
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
@@ -329,6 +342,9 @@
 #define canon_pgprot(p) __pgprot(pgprot_val(p) & __supported_pte_mask)
 
 #ifndef __ASSEMBLY__
+/* Indicate that x86 has its own track and untrack pfn vma functions */
+#define __HAVE_PFNMAP_TRACKING
+
 #define __HAVE_PHYS_MEM_ACCESS_PROT
 struct file;
 pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h
index f9d5889..72b020d 100644
--- a/arch/x86/include/asm/pgtable_32.h
+++ b/arch/x86/include/asm/pgtable_32.h
@@ -101,15 +101,6 @@
 #endif
 
 /*
- * Macro to mark a page protection value as "uncacheable".
- * On processors which do not support it, this is a no-op.
- */
-#define pgprot_noncached(prot)					\
-	((boot_cpu_data.x86 > 3)				\
-	 ? (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT))	\
-	 : (prot))
-
-/*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h
index 545a0e0..ba09289 100644
--- a/arch/x86/include/asm/pgtable_64.h
+++ b/arch/x86/include/asm/pgtable_64.h
@@ -146,7 +146,7 @@
 #define PGDIR_MASK	(~(PGDIR_SIZE - 1))
 
 
-#define MAXMEM		 _AC(0x00003fffffffffff, UL)
+#define MAXMEM		 _AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL)
 #define VMALLOC_START    _AC(0xffffc20000000000, UL)
 #define VMALLOC_END      _AC(0xffffe1ffffffffff, UL)
 #define VMEMMAP_START	 _AC(0xffffe20000000000, UL)
@@ -177,12 +177,6 @@
 #define pages_to_mb(x)	((x) >> (20 - PAGE_SHIFT))   /* FIXME: is this right? */
 
 /*
- * Macro to mark a page protection value as "uncacheable".
- */
-#define pgprot_noncached(prot)					\
-	(__pgprot(pgprot_val((prot)) | _PAGE_PCD | _PAGE_PWT))
-
-/*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
@@ -250,10 +244,22 @@
 extern int direct_gbpages;
 
 /* Encode and de-code a swap entry */
-#define __swp_type(x)			(((x).val >> 1) & 0x3f)
-#define __swp_offset(x)			((x).val >> 8)
-#define __swp_entry(type, offset)	((swp_entry_t) { ((type) << 1) | \
-							 ((offset) << 8) })
+#if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE
+#define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1)
+#define SWP_OFFSET_SHIFT (_PAGE_BIT_PROTNONE + 1)
+#else
+#define SWP_TYPE_BITS (_PAGE_BIT_PROTNONE - _PAGE_BIT_PRESENT - 1)
+#define SWP_OFFSET_SHIFT (_PAGE_BIT_FILE + 1)
+#endif
+
+#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS)
+
+#define __swp_type(x)			(((x).val >> (_PAGE_BIT_PRESENT + 1)) \
+					 & ((1U << SWP_TYPE_BITS) - 1))
+#define __swp_offset(x)			((x).val >> SWP_OFFSET_SHIFT)
+#define __swp_entry(type, offset)	((swp_entry_t) { \
+					 ((type) << (_PAGE_BIT_PRESENT + 1)) \
+					 | ((offset) << SWP_OFFSET_SHIFT) })
 #define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val((pte)) })
 #define __swp_entry_to_pte(x)		((pte_t) { .pte = (x).val })
 
diff --git a/arch/x86/include/asm/prctl.h b/arch/x86/include/asm/prctl.h
index fe68114..a889464 100644
--- a/arch/x86/include/asm/prctl.h
+++ b/arch/x86/include/asm/prctl.h
@@ -6,5 +6,8 @@
 #define ARCH_GET_FS 0x1003
 #define ARCH_GET_GS 0x1004
 
+#ifdef CONFIG_X86_64
+extern long sys_arch_prctl(int, unsigned long);
+#endif /* CONFIG_X86_64 */
 
 #endif /* _ASM_X86_PRCTL_H */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 5ca01e3..091cd88 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -110,6 +110,7 @@
 	/* Index into per_cpu list: */
 	u16			cpu_index;
 #endif
+	unsigned int		x86_hyper_vendor;
 } __attribute__((__aligned__(SMP_CACHE_BYTES)));
 
 #define X86_VENDOR_INTEL	0
@@ -123,6 +124,9 @@
 
 #define X86_VENDOR_UNKNOWN	0xff
 
+#define X86_HYPER_VENDOR_NONE  0
+#define X86_HYPER_VENDOR_VMWARE 1
+
 /*
  * capabilities of CPUs
  */
@@ -752,6 +756,19 @@
 extern void cpu_init(void);
 extern void init_gdt(int cpu);
 
+static inline unsigned long get_debugctlmsr(void)
+{
+    unsigned long debugctlmsr = 0;
+
+#ifndef CONFIG_X86_DEBUGCTLMSR
+	if (boot_cpu_data.x86 < 6)
+		return 0;
+#endif
+	rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
+
+    return debugctlmsr;
+}
+
 static inline void update_debugctlmsr(unsigned long debugctlmsr)
 {
 #ifndef CONFIG_X86_DEBUGCTLMSR
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index eefb059..6d34d95 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -6,7 +6,6 @@
 #include <asm/processor-flags.h>
 
 #ifdef __KERNEL__
-#include <asm/ds.h>		/* the DS BTS struct is used for ptrace too */
 #include <asm/segment.h>
 #endif
 
@@ -128,34 +127,6 @@
 #endif /* !__i386__ */
 
 
-#ifdef CONFIG_X86_PTRACE_BTS
-/* a branch trace record entry
- *
- * In order to unify the interface between various processor versions,
- * we use the below data structure for all processors.
- */
-enum bts_qualifier {
-	BTS_INVALID = 0,
-	BTS_BRANCH,
-	BTS_TASK_ARRIVES,
-	BTS_TASK_DEPARTS
-};
-
-struct bts_struct {
-	__u64 qualifier;
-	union {
-		/* BTS_BRANCH */
-		struct {
-			__u64 from_ip;
-			__u64 to_ip;
-		} lbr;
-		/* BTS_TASK_ARRIVES or
-		   BTS_TASK_DEPARTS */
-		__u64 jiffies;
-	} variant;
-};
-#endif /* CONFIG_X86_PTRACE_BTS */
-
 #ifdef __KERNEL__
 
 #include <linux/init.h>
@@ -163,13 +134,6 @@
 struct cpuinfo_x86;
 struct task_struct;
 
-#ifdef CONFIG_X86_PTRACE_BTS
-extern void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *);
-extern void ptrace_bts_take_timestamp(struct task_struct *, enum bts_qualifier);
-#else
-#define ptrace_bts_init_intel(config) do {} while (0)
-#endif /* CONFIG_X86_PTRACE_BTS */
-
 extern unsigned long profile_pc(struct pt_regs *regs);
 
 extern unsigned long
@@ -271,6 +235,13 @@
 extern int do_set_thread_area(struct task_struct *p, int idx,
 			      struct user_desc __user *info, int can_allocate);
 
+extern void x86_ptrace_untrace(struct task_struct *);
+extern void x86_ptrace_fork(struct task_struct *child,
+			    unsigned long clone_flags);
+
+#define arch_ptrace_untrace(tsk) x86_ptrace_untrace(tsk)
+#define arch_ptrace_fork(child, flags) x86_ptrace_fork(child, flags)
+
 #endif /* __KERNEL__ */
 
 #endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h
index df77103..562d4fd 100644
--- a/arch/x86/include/asm/reboot.h
+++ b/arch/x86/include/asm/reboot.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_X86_REBOOT_H
 #define _ASM_X86_REBOOT_H
 
+#include <linux/kdebug.h>
+
 struct pt_regs;
 
 struct machine_ops {
@@ -18,4 +20,7 @@
 void native_machine_shutdown(void);
 void machine_real_restart(const unsigned char *code, int length);
 
+typedef void (*nmi_shootdown_cb)(int, struct die_args*);
+void nmi_shootdown_cpus(nmi_shootdown_cb callback);
+
 #endif /* _ASM_X86_REBOOT_H */
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index f12d372..4fcd53f 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -8,6 +8,10 @@
 /* Interrupt control for vSMPowered x86_64 systems */
 void vsmp_init(void);
 
+
+void setup_bios_corruption_check(void);
+
+
 #ifdef CONFIG_X86_VISWS
 extern void visws_early_detect(void);
 extern int is_visws_box(void);
@@ -16,6 +20,8 @@
 static inline int is_visws_box(void) { return 0; }
 #endif
 
+extern int wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip);
+extern int wakeup_secondary_cpu_via_init(int apicid, unsigned long start_eip);
 /*
  * Any setup quirks to be performed?
  */
@@ -39,6 +45,7 @@
 	void (*smp_read_mpc_oem)(struct mp_config_oemtable *oemtable,
                                     unsigned short oemsize);
 	int (*setup_ioapic_ids)(void);
+	int (*update_genapic)(void);
 };
 
 extern struct x86_quirks *x86_quirks;
diff --git a/arch/x86/include/asm/sigframe.h b/arch/x86/include/asm/sigframe.h
new file mode 100644
index 0000000..4e0fe26
--- /dev/null
+++ b/arch/x86/include/asm/sigframe.h
@@ -0,0 +1,70 @@
+#ifndef _ASM_X86_SIGFRAME_H
+#define _ASM_X86_SIGFRAME_H
+
+#include <asm/sigcontext.h>
+#include <asm/siginfo.h>
+#include <asm/ucontext.h>
+
+#ifdef CONFIG_X86_32
+#define sigframe_ia32		sigframe
+#define rt_sigframe_ia32	rt_sigframe
+#define sigcontext_ia32		sigcontext
+#define _fpstate_ia32		_fpstate
+#define ucontext_ia32		ucontext
+#else /* !CONFIG_X86_32 */
+
+#ifdef CONFIG_IA32_EMULATION
+#include <asm/ia32.h>
+#endif /* CONFIG_IA32_EMULATION */
+
+#endif /* CONFIG_X86_32 */
+
+#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
+struct sigframe_ia32 {
+	u32 pretcode;
+	int sig;
+	struct sigcontext_ia32 sc;
+	/*
+	 * fpstate is unused. fpstate is moved/allocated after
+	 * retcode[] below. This movement allows to have the FP state and the
+	 * future state extensions (xsave) stay together.
+	 * And at the same time retaining the unused fpstate, prevents changing
+	 * the offset of extramask[] in the sigframe and thus prevent any
+	 * legacy application accessing/modifying it.
+	 */
+	struct _fpstate_ia32 fpstate_unused;
+#ifdef CONFIG_IA32_EMULATION
+	unsigned int extramask[_COMPAT_NSIG_WORDS-1];
+#else /* !CONFIG_IA32_EMULATION */
+	unsigned long extramask[_NSIG_WORDS-1];
+#endif /* CONFIG_IA32_EMULATION */
+	char retcode[8];
+	/* fp state follows here */
+};
+
+struct rt_sigframe_ia32 {
+	u32 pretcode;
+	int sig;
+	u32 pinfo;
+	u32 puc;
+#ifdef CONFIG_IA32_EMULATION
+	compat_siginfo_t info;
+#else /* !CONFIG_IA32_EMULATION */
+	struct siginfo info;
+#endif /* CONFIG_IA32_EMULATION */
+	struct ucontext_ia32 uc;
+	char retcode[8];
+	/* fp state follows here */
+};
+#endif /* defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) */
+
+#ifdef CONFIG_X86_64
+struct rt_sigframe {
+	char __user *pretcode;
+	struct ucontext uc;
+	struct siginfo info;
+	/* fp state follows here */
+};
+#endif /* CONFIG_X86_64 */
+
+#endif /* _ASM_X86_SIGFRAME_H */
diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
index 96ac44f..7761a5d 100644
--- a/arch/x86/include/asm/signal.h
+++ b/arch/x86/include/asm/signal.h
@@ -121,6 +121,10 @@
 
 #ifndef __ASSEMBLY__
 
+# ifdef __KERNEL__
+extern void do_notify_resume(struct pt_regs *, void *, __u32);
+# endif /* __KERNEL__ */
+
 #ifdef __i386__
 # ifdef __KERNEL__
 struct old_sigaction {
@@ -141,8 +145,6 @@
 	struct sigaction sa;
 };
 
-extern void do_notify_resume(struct pt_regs *, void *, __u32);
-
 # else /* __KERNEL__ */
 /* Here we must cater to libcs that poke about in kernel headers.  */
 
diff --git a/arch/x86/include/asm/sparsemem.h b/arch/x86/include/asm/sparsemem.h
index be44f7d..e3cc3c0 100644
--- a/arch/x86/include/asm/sparsemem.h
+++ b/arch/x86/include/asm/sparsemem.h
@@ -27,7 +27,7 @@
 #else /* CONFIG_X86_32 */
 # define SECTION_SIZE_BITS	27 /* matt - 128 is convenient right now */
 # define MAX_PHYSADDR_BITS	44
-# define MAX_PHYSMEM_BITS	44
+# define MAX_PHYSMEM_BITS	44 /* Can be max 45 bits */
 #endif
 
 #endif /* CONFIG_SPARSEMEM */
diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h
index 87803da..9c6797c 100644
--- a/arch/x86/include/asm/syscalls.h
+++ b/arch/x86/include/asm/syscalls.h
@@ -19,6 +19,13 @@
 /* kernel/ioport.c */
 asmlinkage long sys_ioperm(unsigned long, unsigned long, int);
 
+/* kernel/ldt.c */
+asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
+
+/* kernel/tls.c */
+asmlinkage int sys_set_thread_area(struct user_desc __user *);
+asmlinkage int sys_get_thread_area(struct user_desc __user *);
+
 /* X86_32 only */
 #ifdef CONFIG_X86_32
 /* kernel/process_32.c */
@@ -33,14 +40,11 @@
 			     struct old_sigaction __user *);
 asmlinkage int sys_sigaltstack(unsigned long);
 asmlinkage unsigned long sys_sigreturn(unsigned long);
-asmlinkage int sys_rt_sigreturn(unsigned long);
+asmlinkage int sys_rt_sigreturn(struct pt_regs);
 
 /* kernel/ioport.c */
 asmlinkage long sys_iopl(unsigned long);
 
-/* kernel/ldt.c */
-asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
-
 /* kernel/sys_i386_32.c */
 asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long,
 			  unsigned long, unsigned long, unsigned long);
@@ -54,10 +58,6 @@
 struct oldold_utsname;
 asmlinkage int sys_olduname(struct oldold_utsname __user *);
 
-/* kernel/tls.c */
-asmlinkage int sys_set_thread_area(struct user_desc __user *);
-asmlinkage int sys_get_thread_area(struct user_desc __user *);
-
 /* kernel/vm86_32.c */
 asmlinkage int sys_vm86old(struct pt_regs);
 asmlinkage int sys_vm86(struct pt_regs);
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h
index 2ed3f0f..8e626ea 100644
--- a/arch/x86/include/asm/system.h
+++ b/arch/x86/include/asm/system.h
@@ -17,12 +17,12 @@
 # define AT_VECTOR_SIZE_ARCH 1
 #endif
 
-#ifdef CONFIG_X86_32
-
 struct task_struct; /* one of the stranger aspects of C forward declarations */
 struct task_struct *__switch_to(struct task_struct *prev,
 				struct task_struct *next);
 
+#ifdef CONFIG_X86_32
+
 /*
  * Saving eflags is important. It switches not only IOPL between tasks,
  * it also protects other tasks from NT leaking through sysenter etc.
@@ -314,6 +314,8 @@
 
 void default_idle(void);
 
+void stop_this_cpu(void *dummy);
+
 /*
  * Force strict CPU ordering.
  * And yes, this is required on UP too when we're talking
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index e44d379..9878964 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -20,11 +20,13 @@
 struct task_struct;
 struct exec_domain;
 #include <asm/processor.h>
+#include <asm/ftrace.h>
+#include <asm/atomic.h>
 
 struct thread_info {
 	struct task_struct	*task;		/* main task structure */
 	struct exec_domain	*exec_domain;	/* execution domain */
-	unsigned long		flags;		/* low level flags */
+	__u32			flags;		/* low level flags */
 	__u32			status;		/* thread synchronous flags */
 	__u32			cpu;		/* current CPU */
 	int			preempt_count;	/* 0 => preemptable,
@@ -91,7 +93,6 @@
 #define TIF_FORCED_TF		24	/* true if TF in eflags artificially */
 #define TIF_DEBUGCTLMSR		25	/* uses thread_struct.debugctlmsr */
 #define TIF_DS_AREA_MSR		26      /* uses thread_struct.ds_area_msr */
-#define TIF_BTS_TRACE_TS	27      /* record scheduling event timestamps */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
@@ -113,7 +114,6 @@
 #define _TIF_FORCED_TF		(1 << TIF_FORCED_TF)
 #define _TIF_DEBUGCTLMSR	(1 << TIF_DEBUGCTLMSR)
 #define _TIF_DS_AREA_MSR	(1 << TIF_DS_AREA_MSR)
-#define _TIF_BTS_TRACE_TS	(1 << TIF_BTS_TRACE_TS)
 
 /* work to do in syscall_trace_enter() */
 #define _TIF_WORK_SYSCALL_ENTRY	\
@@ -139,8 +139,7 @@
 
 /* flags to check in __switch_to() */
 #define _TIF_WORK_CTXSW							\
-	(_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_BTS_TRACE_TS| \
-								_TIF_NOTSC)
+	(_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_NOTSC)
 
 #define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW
 #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG)
diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h
index fa0d79f..780ba0a 100644
--- a/arch/x86/include/asm/trampoline.h
+++ b/arch/x86/include/asm/trampoline.h
@@ -3,6 +3,7 @@
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_X86_TRAMPOLINE
 /*
  * Trampoline 80x86 program as an array.
  */
@@ -13,8 +14,14 @@
 extern unsigned long init_rsp;
 extern unsigned long initial_code;
 
+#define TRAMPOLINE_SIZE roundup(trampoline_end - trampoline_data, PAGE_SIZE)
 #define TRAMPOLINE_BASE 0x6000
+
 extern unsigned long setup_trampoline(void);
+extern void __init reserve_trampoline_memory(void);
+#else
+static inline void reserve_trampoline_memory(void) {};
+#endif /* CONFIG_X86_TRAMPOLINE */
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 45dee28..2ee0a3b 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -46,6 +46,10 @@
 dotraplinkage void do_invalid_TSS(struct pt_regs *, long);
 dotraplinkage void do_segment_not_present(struct pt_regs *, long);
 dotraplinkage void do_stack_segment(struct pt_regs *, long);
+#ifdef CONFIG_X86_64
+dotraplinkage void do_double_fault(struct pt_regs *, long);
+asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *);
+#endif
 dotraplinkage void do_general_protection(struct pt_regs *, long);
 dotraplinkage void do_page_fault(struct pt_regs *, unsigned long);
 dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *, long);
@@ -72,10 +76,13 @@
 extern int panic_on_unrecovered_nmi;
 extern int kstack_depth_to_print;
 
-#ifdef CONFIG_X86_32
 void math_error(void __user *);
-unsigned long patch_espfix_desc(unsigned long, unsigned long);
 asmlinkage void math_emulate(long);
+#ifdef CONFIG_X86_32
+unsigned long patch_espfix_desc(unsigned long, unsigned long);
+#else
+asmlinkage void smp_thermal_interrupt(void);
+asmlinkage void mce_threshold_interrupt(void);
 #endif
 
 #endif /* _ASM_X86_TRAPS_H */
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 9cd83a8..38ae163 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -34,8 +34,6 @@
 
 static __always_inline cycles_t vget_cycles(void)
 {
-	cycles_t cycles;
-
 	/*
 	 * We only do VDSOs on TSC capable CPUs, so this shouldnt
 	 * access boot_cpu_data (which is not VDSO-safe):
@@ -44,11 +42,7 @@
 	if (!cpu_has_tsc)
 		return 0;
 #endif
-	rdtsc_barrier();
-	cycles = (cycles_t)__native_read_tsc();
-	rdtsc_barrier();
-
-	return cycles;
+	return (cycles_t)__native_read_tsc();
 }
 
 extern void tsc_init(void);
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 35c5492..580c3ee 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -350,14 +350,14 @@
 
 #define __put_user_nocheck(x, ptr, size)			\
 ({								\
-	long __pu_err;						\
+	int __pu_err;						\
 	__put_user_size((x), (ptr), (size), __pu_err, -EFAULT);	\
 	__pu_err;						\
 })
 
 #define __get_user_nocheck(x, ptr, size)				\
 ({									\
-	long __gu_err;							\
+	int __gu_err;							\
 	unsigned long __gu_val;						\
 	__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT);	\
 	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
diff --git a/arch/x86/include/asm/uv/bios.h b/arch/x86/include/asm/uv/bios.h
index d931d3b..7ed17ff 100644
--- a/arch/x86/include/asm/uv/bios.h
+++ b/arch/x86/include/asm/uv/bios.h
@@ -32,13 +32,18 @@
 enum uv_bios_cmd {
 	UV_BIOS_COMMON,
 	UV_BIOS_GET_SN_INFO,
-	UV_BIOS_FREQ_BASE
+	UV_BIOS_FREQ_BASE,
+	UV_BIOS_WATCHLIST_ALLOC,
+	UV_BIOS_WATCHLIST_FREE,
+	UV_BIOS_MEMPROTECT,
+	UV_BIOS_GET_PARTITION_ADDR
 };
 
 /*
  * Status values returned from a BIOS call.
  */
 enum {
+	BIOS_STATUS_MORE_PASSES		=  1,
 	BIOS_STATUS_SUCCESS		=  0,
 	BIOS_STATUS_UNIMPLEMENTED	= -ENOSYS,
 	BIOS_STATUS_EINVAL		= -EINVAL,
@@ -71,6 +76,21 @@
 	};
 };
 
+union uv_watchlist_u {
+	u64	val;
+	struct {
+		u64	blade	: 16,
+			size	: 32,
+			filler	: 16;
+	};
+};
+
+enum uv_memprotect {
+	UV_MEMPROT_RESTRICT_ACCESS,
+	UV_MEMPROT_ALLOW_AMO,
+	UV_MEMPROT_ALLOW_RW
+};
+
 /*
  * bios calls have 6 parameters
  */
@@ -80,14 +100,20 @@
 
 extern s64 uv_bios_get_sn_info(int, int *, long *, long *, long *);
 extern s64 uv_bios_freq_base(u64, u64 *);
+extern int uv_bios_mq_watchlist_alloc(int, unsigned long, unsigned int,
+					unsigned long *);
+extern int uv_bios_mq_watchlist_free(int, int);
+extern s64 uv_bios_change_memprotect(u64, u64, enum uv_memprotect);
+extern s64 uv_bios_reserved_page_pa(u64, u64 *, u64 *, u64 *);
 
 extern void uv_bios_init(void);
 
+extern unsigned long sn_rtc_cycles_per_second;
 extern int uv_type;
 extern long sn_partition_id;
-extern long uv_coherency_id;
-extern long uv_region_size;
-#define partition_coherence_id()	(uv_coherency_id)
+extern long sn_coherency_id;
+extern long sn_region_size;
+#define partition_coherence_id()	(sn_coherency_id)
 
 extern struct kobject *sgi_uv_kobj;	/* /sys/firmware/sgi_uv */
 
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h
index 7a57826..777327e 100644
--- a/arch/x86/include/asm/uv/uv_hub.h
+++ b/arch/x86/include/asm/uv/uv_hub.h
@@ -113,25 +113,37 @@
  */
 #define UV_MAX_NASID_VALUE	(UV_MAX_NUMALINK_NODES * 2)
 
+struct uv_scir_s {
+	struct timer_list timer;
+	unsigned long	offset;
+	unsigned long	last;
+	unsigned long	idle_on;
+	unsigned long	idle_off;
+	unsigned char	state;
+	unsigned char	enabled;
+};
+
 /*
  * The following defines attributes of the HUB chip. These attributes are
  * frequently referenced and are kept in the per-cpu data areas of each cpu.
  * They are kept together in a struct to minimize cache misses.
  */
 struct uv_hub_info_s {
-	unsigned long	global_mmr_base;
-	unsigned long	gpa_mask;
-	unsigned long	gnode_upper;
-	unsigned long	lowmem_remap_top;
-	unsigned long	lowmem_remap_base;
-	unsigned short	pnode;
-	unsigned short	pnode_mask;
-	unsigned short	coherency_domain_number;
-	unsigned short	numa_blade_id;
-	unsigned char	blade_processor_id;
-	unsigned char	m_val;
-	unsigned char	n_val;
+	unsigned long		global_mmr_base;
+	unsigned long		gpa_mask;
+	unsigned long		gnode_upper;
+	unsigned long		lowmem_remap_top;
+	unsigned long		lowmem_remap_base;
+	unsigned short		pnode;
+	unsigned short		pnode_mask;
+	unsigned short		coherency_domain_number;
+	unsigned short		numa_blade_id;
+	unsigned char		blade_processor_id;
+	unsigned char		m_val;
+	unsigned char		n_val;
+	struct uv_scir_s	scir;
 };
+
 DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
 #define uv_hub_info 		(&__get_cpu_var(__uv_hub_info))
 #define uv_cpu_hub_info(cpu)	(&per_cpu(__uv_hub_info, cpu))
@@ -163,6 +175,30 @@
 
 #define UV_APIC_PNODE_SHIFT	6
 
+/* Local Bus from cpu's perspective */
+#define LOCAL_BUS_BASE		0x1c00000
+#define LOCAL_BUS_SIZE		(4 * 1024 * 1024)
+
+/*
+ * System Controller Interface Reg
+ *
+ * Note there are NO leds on a UV system.  This register is only
+ * used by the system controller to monitor system-wide operation.
+ * There are 64 regs per node.  With Nahelem cpus (2 cores per node,
+ * 8 cpus per core, 2 threads per cpu) there are 32 cpu threads on
+ * a node.
+ *
+ * The window is located at top of ACPI MMR space
+ */
+#define SCIR_WINDOW_COUNT	64
+#define SCIR_LOCAL_MMR_BASE	(LOCAL_BUS_BASE + \
+				 LOCAL_BUS_SIZE - \
+				 SCIR_WINDOW_COUNT)
+
+#define SCIR_CPU_HEARTBEAT	0x01	/* timer interrupt */
+#define SCIR_CPU_ACTIVITY	0x02	/* not idle */
+#define SCIR_CPU_HB_INTERVAL	(HZ)	/* once per second */
+
 /*
  * Macros for converting between kernel virtual addresses, socket local physical
  * addresses, and UV global physical addresses.
@@ -174,7 +210,7 @@
 static inline unsigned long uv_soc_phys_ram_to_gpa(unsigned long paddr)
 {
 	if (paddr < uv_hub_info->lowmem_remap_top)
-		paddr += uv_hub_info->lowmem_remap_base;
+		paddr |= uv_hub_info->lowmem_remap_base;
 	return paddr | uv_hub_info->gnode_upper;
 }
 
@@ -182,19 +218,7 @@
 /* socket virtual --> UV global physical address */
 static inline unsigned long uv_gpa(void *v)
 {
-	return __pa(v) | uv_hub_info->gnode_upper;
-}
-
-/* socket virtual --> UV global physical address */
-static inline void *uv_vgpa(void *v)
-{
-	return (void *)uv_gpa(v);
-}
-
-/* UV global physical address --> socket virtual */
-static inline void *uv_va(unsigned long gpa)
-{
-	return __va(gpa & uv_hub_info->gpa_mask);
+	return uv_soc_phys_ram_to_gpa(__pa(v));
 }
 
 /* pnode, offset --> socket virtual */
@@ -277,6 +301,16 @@
 	*uv_local_mmr_address(offset) = val;
 }
 
+static inline unsigned char uv_read_local_mmr8(unsigned long offset)
+{
+	return *((unsigned char *)uv_local_mmr_address(offset));
+}
+
+static inline void uv_write_local_mmr8(unsigned long offset, unsigned char val)
+{
+	*((unsigned char *)uv_local_mmr_address(offset)) = val;
+}
+
 /*
  * Structures and definitions for converting between cpu, node, pnode, and blade
  * numbers.
@@ -351,5 +385,20 @@
 	return uv_possible_blades;
 }
 
-#endif /* _ASM_X86_UV_UV_HUB_H */
+/* Update SCIR state */
+static inline void uv_set_scir_bits(unsigned char value)
+{
+	if (uv_hub_info->scir.state != value) {
+		uv_hub_info->scir.state = value;
+		uv_write_local_mmr8(uv_hub_info->scir.offset, value);
+	}
+}
+static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
+{
+	if (uv_cpu_hub_info(cpu)->scir.state != value) {
+		uv_cpu_hub_info(cpu)->scir.state = value;
+		uv_write_local_mmr8(uv_cpu_hub_info(cpu)->scir.offset, value);
+	}
+}
 
+#endif /* _ASM_X86_UV_UV_HUB_H */
diff --git a/arch/x86/include/asm/vmware.h b/arch/x86/include/asm/vmware.h
new file mode 100644
index 0000000..c11b7e1
--- /dev/null
+++ b/arch/x86/include/asm/vmware.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008, VMware, 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef ASM_X86__VMWARE_H
+#define ASM_X86__VMWARE_H
+
+extern unsigned long vmware_get_tsc_khz(void);
+extern int vmware_platform(void);
+extern void vmware_set_feature_bits(struct cpuinfo_x86 *c);
+
+#endif
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h
index 3f6000d..5e79ca6 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -33,8 +33,14 @@
 #ifndef _ASM_X86_XEN_HYPERCALL_H
 #define _ASM_X86_XEN_HYPERCALL_H
 
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/types.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
 
 #include <xen/interface/xen.h>
 #include <xen/interface/sched.h>
diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h
index a38d25a..81fbd73 100644
--- a/arch/x86/include/asm/xen/hypervisor.h
+++ b/arch/x86/include/asm/xen/hypervisor.h
@@ -33,39 +33,10 @@
 #ifndef _ASM_X86_XEN_HYPERVISOR_H
 #define _ASM_X86_XEN_HYPERVISOR_H
 
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <xen/interface/xen.h>
-#include <xen/interface/version.h>
-
-#include <asm/ptrace.h>
-#include <asm/page.h>
-#include <asm/desc.h>
-#if defined(__i386__)
-#  ifdef CONFIG_X86_PAE
-#   include <asm-generic/pgtable-nopud.h>
-#  else
-#   include <asm-generic/pgtable-nopmd.h>
-#  endif
-#endif
-#include <asm/xen/hypercall.h>
-
 /* arch/i386/kernel/setup.c */
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
 
-/* arch/i386/mach-xen/evtchn.c */
-/* Force a proper event-channel callback from Xen. */
-extern void force_evtchn_callback(void);
-
-/* Turn jiffies into Xen system time. */
-u64 jiffies_to_st(unsigned long jiffies);
-
-
-#define MULTI_UVMFLAGS_INDEX 3
-#define MULTI_UVMDOMID_INDEX 4
-
 enum xen_domain_type {
 	XEN_NATIVE,
 	XEN_PV_DOMAIN,
@@ -74,9 +45,15 @@
 
 extern enum xen_domain_type xen_domain_type;
 
+#ifdef CONFIG_XEN
 #define xen_domain()		(xen_domain_type != XEN_NATIVE)
-#define xen_pv_domain()		(xen_domain_type == XEN_PV_DOMAIN)
+#else
+#define xen_domain()		(0)
+#endif
+
+#define xen_pv_domain()		(xen_domain() && xen_domain_type == XEN_PV_DOMAIN)
+#define xen_hvm_domain()	(xen_domain() && xen_domain_type == XEN_HVM_DOMAIN)
+
 #define xen_initial_domain()	(xen_pv_domain() && xen_start_info->flags & SIF_INITDOMAIN)
-#define xen_hvm_domain()	(xen_domain_type == XEN_HVM_DOMAIN)
 
 #endif /* _ASM_X86_XEN_HYPERVISOR_H */
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index bc62899..7ef617e 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -1,11 +1,16 @@
 #ifndef _ASM_X86_XEN_PAGE_H
 #define _ASM_X86_XEN_PAGE_H
 
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
 #include <linux/pfn.h>
 
 #include <asm/uaccess.h>
+#include <asm/page.h>
 #include <asm/pgtable.h>
 
+#include <xen/interface/xen.h>
 #include <xen/features.h>
 
 /* Xen machine address */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index b62a766..88dd768 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -12,6 +12,7 @@
 CFLAGS_REMOVE_rtc.o = -pg
 CFLAGS_REMOVE_paravirt-spinlocks.o = -pg
 CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_early_printk.o = -pg
 endif
 
 #
@@ -23,9 +24,9 @@
 CFLAGS_hpet.o		:= $(nostackp)
 CFLAGS_tsc.o		:= $(nostackp)
 
-obj-y			:= process_$(BITS).o signal_$(BITS).o entry_$(BITS).o
+obj-y			:= process_$(BITS).o signal.o entry_$(BITS).o
 obj-y			+= traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
-obj-y			+= time_$(BITS).o ioport.o ldt.o
+obj-y			+= time_$(BITS).o ioport.o ldt.o dumpstack.o
 obj-y			+= setup.o i8259.o irqinit_$(BITS).o setup_percpu.o
 obj-$(CONFIG_X86_VISWS)	+= visws_quirks.o
 obj-$(CONFIG_X86_32)	+= probe_roms_32.o
@@ -65,6 +66,7 @@
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
 obj-$(CONFIG_X86_REBOOTFIXUPS)	+= reboot_fixups_32.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec_$(BITS).o
 obj-$(CONFIG_KEXEC)		+= relocate_kernel_$(BITS).o crash.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump_$(BITS).o
@@ -105,6 +107,8 @@
 microcode-$(CONFIG_MICROCODE_AMD)	+= microcode_amd.o
 obj-$(CONFIG_MICROCODE)			+= microcode.o
 
+obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
+
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 4c51a2f..65d0b72 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1360,6 +1360,17 @@
 			disable_acpi();
 		}
 	}
+
+	/*
+	 * ACPI supports both logical (e.g. Hyper-Threading) and physical
+	 * processors, where MPS only supports physical.
+	 */
+	if (acpi_lapic && acpi_ioapic)
+		printk(KERN_INFO "Using ACPI (MADT) for SMP configuration "
+		       "information\n");
+	else if (acpi_lapic)
+		printk(KERN_INFO "Using ACPI for processor (LAPIC) "
+		       "configuration information\n");
 #endif
 	return;
 }
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 0a60d60..2e2da71 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -24,6 +24,7 @@
 #include <linux/iommu-helper.h>
 #include <asm/proto.h>
 #include <asm/iommu.h>
+#include <asm/gart.h>
 #include <asm/amd_iommu_types.h>
 #include <asm/amd_iommu.h>
 
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c
index c6cc228..c625800 100644
--- a/arch/x86/kernel/amd_iommu_init.c
+++ b/arch/x86/kernel/amd_iommu_init.c
@@ -28,6 +28,7 @@
 #include <asm/amd_iommu_types.h>
 #include <asm/amd_iommu.h>
 #include <asm/iommu.h>
+#include <asm/gart.h>
 
 /*
  * definitions for the ACPI scanning code
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index 9a32b37..676debf 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -1,8 +1,9 @@
 /*
  * Firmware replacement code.
  *
- * Work around broken BIOSes that don't set an aperture or only set the
- * aperture in the AGP bridge.
+ * Work around broken BIOSes that don't set an aperture, only set the
+ * aperture in the AGP bridge, or set too small aperture.
+ *
  * If all fails map the aperture over some low memory.  This is cheaper than
  * doing bounce buffering. The memory is lost. This is done at early boot
  * because only the bootmem allocator can allocate 32+MB.
diff --git a/arch/x86/kernel/apic.c b/arch/x86/kernel/apic.c
index 16f9487..b5229af 100644
--- a/arch/x86/kernel/apic.c
+++ b/arch/x86/kernel/apic.c
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/dmi.h>
 #include <linux/dmar.h>
+#include <linux/ftrace.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -441,6 +442,7 @@
 		v = apic_read(APIC_LVTT);
 		v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
 		apic_write(APIC_LVTT, v);
+		apic_write(APIC_TMICT, 0xffffffff);
 		break;
 	case CLOCK_EVT_MODE_RESUME:
 		/* Nothing to do here */
@@ -559,13 +561,13 @@
 	} else {
 		res = (((u64)deltapm) *  mult) >> 22;
 		do_div(res, 1000000);
-		printk(KERN_WARNING "APIC calibration not consistent "
+		pr_warning("APIC calibration not consistent "
 			"with PM Timer: %ldms instead of 100ms\n",
 			(long)res);
 		/* Correct the lapic counter value */
 		res = (((u64)(*delta)) * pm_100ms);
 		do_div(res, deltapm);
-		printk(KERN_INFO "APIC delta adjusted to PM-Timer: "
+		pr_info("APIC delta adjusted to PM-Timer: "
 			"%lu (%ld)\n", (unsigned long)res, *delta);
 		*delta = (long)res;
 	}
@@ -645,8 +647,7 @@
 	 */
 	if (calibration_result < (1000000 / HZ)) {
 		local_irq_enable();
-		printk(KERN_WARNING
-		       "APIC frequency too slow, disabling apic timer\n");
+		pr_warning("APIC frequency too slow, disabling apic timer\n");
 		return -1;
 	}
 
@@ -672,13 +673,9 @@
 		while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
 			cpu_relax();
 
-		local_irq_disable();
-
 		/* Stop the lapic timer */
 		lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt);
 
-		local_irq_enable();
-
 		/* Jiffies delta */
 		deltaj = lapic_cal_j2 - lapic_cal_j1;
 		apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj);
@@ -692,8 +689,7 @@
 		local_irq_enable();
 
 	if (levt->features & CLOCK_EVT_FEAT_DUMMY) {
-		printk(KERN_WARNING
-		       "APIC timer disabled due to verification failure.\n");
+		pr_warning("APIC timer disabled due to verification failure.\n");
 			return -1;
 	}
 
@@ -714,7 +710,7 @@
 	 * broadcast mechanism is used. On UP systems simply ignore it.
 	 */
 	if (disable_apic_timer) {
-		printk(KERN_INFO "Disabling APIC timer\n");
+		pr_info("Disabling APIC timer\n");
 		/* No broadcast on UP ! */
 		if (num_possible_cpus() > 1) {
 			lapic_clockevent.mult = 1;
@@ -741,7 +737,7 @@
 	if (nmi_watchdog != NMI_IO_APIC)
 		lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
 	else
-		printk(KERN_WARNING "APIC timer registered as dummy,"
+		pr_warning("APIC timer registered as dummy,"
 			" due to nmi_watchdog=%d!\n", nmi_watchdog);
 
 	/* Setup the lapic or request the broadcast */
@@ -773,8 +769,7 @@
 	 * spurious.
 	 */
 	if (!evt->event_handler) {
-		printk(KERN_WARNING
-		       "Spurious LAPIC timer interrupt on cpu %d\n", cpu);
+		pr_warning("Spurious LAPIC timer interrupt on cpu %d\n", cpu);
 		/* Switch it off */
 		lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt);
 		return;
@@ -783,11 +778,7 @@
 	/*
 	 * the NMI deadlock-detector uses this.
 	 */
-#ifdef CONFIG_X86_64
-	add_pda(apic_timer_irqs, 1);
-#else
-	per_cpu(irq_stat, cpu).apic_timer_irqs++;
-#endif
+	inc_irq_stat(apic_timer_irqs);
 
 	evt->event_handler(evt);
 }
@@ -800,7 +791,7 @@
  * [ if a single-CPU system runs an SMP kernel then we call the local
  *   interrupt as well. Thus we cannot inline the local irq ... ]
  */
-void smp_apic_timer_interrupt(struct pt_regs *regs)
+void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
@@ -814,9 +805,7 @@
 	 * Besides, if we don't timer interrupts ignore the global
 	 * interrupt lock, which is the WrongThing (tm) to do.
 	 */
-#ifdef CONFIG_X86_64
 	exit_idle();
-#endif
 	irq_enter();
 	local_apic_timer_interrupt();
 	irq_exit();
@@ -1093,7 +1082,7 @@
 	unsigned int oldvalue, value, maxlvt;
 
 	if (!lapic_is_integrated()) {
-		printk(KERN_INFO "No ESR for 82489DX.\n");
+		pr_info("No ESR for 82489DX.\n");
 		return;
 	}
 
@@ -1104,7 +1093,7 @@
 		 * ESR disabled - we can't do anything useful with the
 		 * errors anyway - mbligh
 		 */
-		printk(KERN_INFO "Leaving ESR disabled.\n");
+		pr_info("Leaving ESR disabled.\n");
 		return;
 	}
 
@@ -1298,7 +1287,7 @@
 	rdmsr(MSR_IA32_APICBASE, msr, msr2);
 
 	if (msr & X2APIC_ENABLE) {
-		printk("x2apic enabled by BIOS, switching to x2apic ops\n");
+		pr_info("x2apic enabled by BIOS, switching to x2apic ops\n");
 		x2apic_preenabled = x2apic = 1;
 		apic_ops = &x2apic_ops;
 	}
@@ -1310,7 +1299,7 @@
 
 	rdmsr(MSR_IA32_APICBASE, msr, msr2);
 	if (!(msr & X2APIC_ENABLE)) {
-		printk("Enabling x2apic\n");
+		pr_info("Enabling x2apic\n");
 		wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
 	}
 }
@@ -1325,9 +1314,8 @@
 		return;
 
 	if (!x2apic_preenabled && disable_x2apic) {
-		printk(KERN_INFO
-		       "Skipped enabling x2apic and Interrupt-remapping "
-		       "because of nox2apic\n");
+		pr_info("Skipped enabling x2apic and Interrupt-remapping "
+			"because of nox2apic\n");
 		return;
 	}
 
@@ -1335,22 +1323,19 @@
 		panic("Bios already enabled x2apic, can't enforce nox2apic");
 
 	if (!x2apic_preenabled && skip_ioapic_setup) {
-		printk(KERN_INFO
-		       "Skipped enabling x2apic and Interrupt-remapping "
-		       "because of skipping io-apic setup\n");
+		pr_info("Skipped enabling x2apic and Interrupt-remapping "
+			"because of skipping io-apic setup\n");
 		return;
 	}
 
 	ret = dmar_table_init();
 	if (ret) {
-		printk(KERN_INFO
-		       "dmar_table_init() failed with %d:\n", ret);
+		pr_info("dmar_table_init() failed with %d:\n", ret);
 
 		if (x2apic_preenabled)
 			panic("x2apic enabled by bios. But IR enabling failed");
 		else
-			printk(KERN_INFO
-			       "Not enabling x2apic,Intr-remapping\n");
+			pr_info("Not enabling x2apic,Intr-remapping\n");
 		return;
 	}
 
@@ -1359,7 +1344,7 @@
 
 	ret = save_mask_IO_APIC_setup();
 	if (ret) {
-		printk(KERN_INFO "Saving IO-APIC state failed: %d\n", ret);
+		pr_info("Saving IO-APIC state failed: %d\n", ret);
 		goto end;
 	}
 
@@ -1394,14 +1379,11 @@
 
 	if (!ret) {
 		if (!x2apic_preenabled)
-			printk(KERN_INFO
-			       "Enabled x2apic and interrupt-remapping\n");
+			pr_info("Enabled x2apic and interrupt-remapping\n");
 		else
-			printk(KERN_INFO
-			       "Enabled Interrupt-remapping\n");
+			pr_info("Enabled Interrupt-remapping\n");
 	} else
-		printk(KERN_ERR
-		       "Failed to enable Interrupt-remapping and x2apic\n");
+		pr_err("Failed to enable Interrupt-remapping and x2apic\n");
 #else
 	if (!cpu_has_x2apic)
 		return;
@@ -1410,8 +1392,8 @@
 		panic("x2apic enabled prior OS handover,"
 		      " enable CONFIG_INTR_REMAP");
 
-	printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping "
-	       " and x2apic\n");
+	pr_info("Enable CONFIG_INTR_REMAP for enabling intr-remapping "
+		" and x2apic\n");
 #endif
 
 	return;
@@ -1428,7 +1410,7 @@
 static int __init detect_init_APIC(void)
 {
 	if (!cpu_has_apic) {
-		printk(KERN_INFO "No local APIC present\n");
+		pr_info("No local APIC present\n");
 		return -1;
 	}
 
@@ -1469,8 +1451,8 @@
 		 * "lapic" specified.
 		 */
 		if (!force_enable_local_apic) {
-			printk(KERN_INFO "Local APIC disabled by BIOS -- "
-			       "you can enable it with \"lapic\"\n");
+			pr_info("Local APIC disabled by BIOS -- "
+				"you can enable it with \"lapic\"\n");
 			return -1;
 		}
 		/*
@@ -1480,8 +1462,7 @@
 		 */
 		rdmsr(MSR_IA32_APICBASE, l, h);
 		if (!(l & MSR_IA32_APICBASE_ENABLE)) {
-			printk(KERN_INFO
-			       "Local APIC disabled by BIOS -- reenabling.\n");
+			pr_info("Local APIC disabled by BIOS -- reenabling.\n");
 			l &= ~MSR_IA32_APICBASE_BASE;
 			l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
 			wrmsr(MSR_IA32_APICBASE, l, h);
@@ -1494,7 +1475,7 @@
 	 */
 	features = cpuid_edx(1);
 	if (!(features & (1 << X86_FEATURE_APIC))) {
-		printk(KERN_WARNING "Could not enable APIC!\n");
+		pr_warning("Could not enable APIC!\n");
 		return -1;
 	}
 	set_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC);
@@ -1505,14 +1486,14 @@
 	if (l & MSR_IA32_APICBASE_ENABLE)
 		mp_lapic_addr = l & MSR_IA32_APICBASE_BASE;
 
-	printk(KERN_INFO "Found and enabled local APIC!\n");
+	pr_info("Found and enabled local APIC!\n");
 
 	apic_pm_activate();
 
 	return 0;
 
 no_apic:
-	printk(KERN_INFO "No local APIC present or hardware disabled\n");
+	pr_info("No local APIC present or hardware disabled\n");
 	return -1;
 }
 #endif
@@ -1588,12 +1569,12 @@
 {
 #ifdef CONFIG_X86_64
 	if (disable_apic) {
-		printk(KERN_INFO "Apic disabled\n");
+		pr_info("Apic disabled\n");
 		return -1;
 	}
 	if (!cpu_has_apic) {
 		disable_apic = 1;
-		printk(KERN_INFO "Apic disabled by BIOS\n");
+		pr_info("Apic disabled by BIOS\n");
 		return -1;
 	}
 #else
@@ -1605,8 +1586,8 @@
 	 */
 	if (!cpu_has_apic &&
 	    APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
-		printk(KERN_ERR "BIOS bug, local APIC 0x%x not detected!...\n",
-		       boot_cpu_physical_apicid);
+		pr_err("BIOS bug, local APIC 0x%x not detected!...\n",
+			boot_cpu_physical_apicid);
 		clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC);
 		return -1;
 	}
@@ -1682,9 +1663,7 @@
 {
 	u32 v;
 
-#ifdef CONFIG_X86_64
 	exit_idle();
-#endif
 	irq_enter();
 	/*
 	 * Check if this really is a spurious interrupt and ACK it
@@ -1695,14 +1674,11 @@
 	if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
 		ack_APIC_irq();
 
-#ifdef CONFIG_X86_64
-	add_pda(irq_spurious_count, 1);
-#else
+	inc_irq_stat(irq_spurious_count);
+
 	/* see sw-dev-man vol 3, chapter 7.4.13.5 */
-	printk(KERN_INFO "spurious APIC interrupt on CPU#%d, "
-	       "should never happen.\n", smp_processor_id());
-	__get_cpu_var(irq_stat).irq_spurious_count++;
-#endif
+	pr_info("spurious APIC interrupt on CPU#%d, "
+		"should never happen.\n", smp_processor_id());
 	irq_exit();
 }
 
@@ -1713,9 +1689,7 @@
 {
 	u32 v, v1;
 
-#ifdef CONFIG_X86_64
 	exit_idle();
-#endif
 	irq_enter();
 	/* First tickle the hardware, only then report what went on. -- REW */
 	v = apic_read(APIC_ESR);
@@ -1724,17 +1698,18 @@
 	ack_APIC_irq();
 	atomic_inc(&irq_err_count);
 
-	/* Here is what the APIC error bits mean:
-	   0: Send CS error
-	   1: Receive CS error
-	   2: Send accept error
-	   3: Receive accept error
-	   4: Reserved
-	   5: Send illegal vector
-	   6: Received illegal vector
-	   7: Illegal register address
-	*/
-	printk(KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
+	/*
+	 * Here is what the APIC error bits mean:
+	 * 0: Send CS error
+	 * 1: Receive CS error
+	 * 2: Send accept error
+	 * 3: Receive accept error
+	 * 4: Reserved
+	 * 5: Send illegal vector
+	 * 6: Received illegal vector
+	 * 7: Illegal register address
+	 */
+	pr_debug("APIC error on CPU%d: %02x(%02x)\n",
 		smp_processor_id(), v , v1);
 	irq_exit();
 }
@@ -1838,15 +1813,15 @@
 	 * Validate version
 	 */
 	if (version == 0x0) {
-		printk(KERN_WARNING "BIOS bug, APIC version is 0 for CPU#%d! "
-				"fixing up to 0x10. (tell your hw vendor)\n",
-				version);
+		pr_warning("BIOS bug, APIC version is 0 for CPU#%d! "
+			"fixing up to 0x10. (tell your hw vendor)\n",
+			version);
 		version = 0x10;
 	}
 	apic_version[apicid] = version;
 
 	if (num_processors >= NR_CPUS) {
-		printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached."
+		pr_warning("WARNING: NR_CPUS limit of %i reached."
 			"  Processor ignored.\n", NR_CPUS);
 		return;
 	}
@@ -2209,7 +2184,7 @@
 	else if (strcmp("verbose", arg) == 0)
 		apic_verbosity = APIC_VERBOSE;
 	else {
-		printk(KERN_WARNING "APIC Verbosity level %s not recognised"
+		pr_warning("APIC Verbosity level %s not recognised"
 			" use apic=verbose or apic=debug\n", arg);
 		return -EINVAL;
 	}
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 5145a6e..3a26525 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -391,11 +391,7 @@
 #else
 static int power_off = 1;
 #endif
-#ifdef CONFIG_APM_REAL_MODE_POWER_OFF
-static int realmode_power_off = 1;
-#else
 static int realmode_power_off;
-#endif
 #ifdef CONFIG_APM_ALLOW_INTS
 static int allow_ints = 1;
 #else
diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c
index 6649d09..ee4df08 100644
--- a/arch/x86/kernel/asm-offsets_32.c
+++ b/arch/x86/kernel/asm-offsets_32.c
@@ -11,7 +11,7 @@
 #include <linux/suspend.h>
 #include <linux/kbuild.h>
 #include <asm/ucontext.h>
-#include "sigframe.h"
+#include <asm/sigframe.h>
 #include <asm/pgtable.h>
 #include <asm/fixmap.h>
 #include <asm/processor.h>
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
index 7fcf63d..1d41d3f 100644
--- a/arch/x86/kernel/asm-offsets_64.c
+++ b/arch/x86/kernel/asm-offsets_64.c
@@ -20,6 +20,8 @@
 
 #include <xen/interface/xen.h>
 
+#include <asm/sigframe.h>
+
 #define __NO_STUBS 1
 #undef __SYSCALL
 #undef _ASM_X86_UNISTD_64_H
@@ -87,7 +89,7 @@
 	BLANK();
 #undef ENTRY
 	DEFINE(IA32_RT_SIGFRAME_sigcontext,
-	       offsetof (struct rt_sigframe32, uc.uc_mcontext));
+	       offsetof (struct rt_sigframe_ia32, uc.uc_mcontext));
 	BLANK();
 #endif
 	DEFINE(pbe_address, offsetof(struct pbe, address));
diff --git a/arch/x86/kernel/bios_uv.c b/arch/x86/kernel/bios_uv.c
index f0dfe6f..2a0a2a3 100644
--- a/arch/x86/kernel/bios_uv.c
+++ b/arch/x86/kernel/bios_uv.c
@@ -69,10 +69,10 @@
 
 long sn_partition_id;
 EXPORT_SYMBOL_GPL(sn_partition_id);
-long uv_coherency_id;
-EXPORT_SYMBOL_GPL(uv_coherency_id);
-long uv_region_size;
-EXPORT_SYMBOL_GPL(uv_region_size);
+long sn_coherency_id;
+EXPORT_SYMBOL_GPL(sn_coherency_id);
+long sn_region_size;
+EXPORT_SYMBOL_GPL(sn_region_size);
 int uv_type;
 
 
@@ -100,6 +100,56 @@
 	return ret;
 }
 
+int
+uv_bios_mq_watchlist_alloc(int blade, unsigned long addr, unsigned int mq_size,
+			   unsigned long *intr_mmr_offset)
+{
+	union uv_watchlist_u size_blade;
+	u64 watchlist;
+	s64 ret;
+
+	size_blade.size = mq_size;
+	size_blade.blade = blade;
+
+	/*
+	 * bios returns watchlist number or negative error number.
+	 */
+	ret = (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_ALLOC, addr,
+			size_blade.val, (u64)intr_mmr_offset,
+			(u64)&watchlist, 0);
+	if (ret < BIOS_STATUS_SUCCESS)
+		return ret;
+
+	return watchlist;
+}
+EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_alloc);
+
+int
+uv_bios_mq_watchlist_free(int blade, int watchlist_num)
+{
+	return (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_FREE,
+				blade, watchlist_num, 0, 0, 0);
+}
+EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_free);
+
+s64
+uv_bios_change_memprotect(u64 paddr, u64 len, enum uv_memprotect perms)
+{
+	return uv_bios_call_irqsave(UV_BIOS_MEMPROTECT, paddr, len,
+					perms, 0, 0);
+}
+EXPORT_SYMBOL_GPL(uv_bios_change_memprotect);
+
+s64
+uv_bios_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len)
+{
+	s64 ret;
+
+	ret = uv_bios_call_irqsave(UV_BIOS_GET_PARTITION_ADDR, (u64)cookie,
+					(u64)addr, buf, (u64)len, 0);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(uv_bios_reserved_page_pa);
 
 s64 uv_bios_freq_base(u64 clock_type, u64 *ticks_per_second)
 {
diff --git a/arch/x86/kernel/check.c b/arch/x86/kernel/check.c
new file mode 100644
index 0000000..2ac0ab7
--- /dev/null
+++ b/arch/x86/kernel/check.c
@@ -0,0 +1,161 @@
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/workqueue.h>
+#include <asm/e820.h>
+#include <asm/proto.h>
+
+/*
+ * Some BIOSes seem to corrupt the low 64k of memory during events
+ * like suspend/resume and unplugging an HDMI cable.  Reserve all
+ * remaining free memory in that area and fill it with a distinct
+ * pattern.
+ */
+#define MAX_SCAN_AREAS	8
+
+static int __read_mostly memory_corruption_check = -1;
+
+static unsigned __read_mostly corruption_check_size = 64*1024;
+static unsigned __read_mostly corruption_check_period = 60; /* seconds */
+
+static struct e820entry scan_areas[MAX_SCAN_AREAS];
+static int num_scan_areas;
+
+
+static __init int set_corruption_check(char *arg)
+{
+	char *end;
+
+	memory_corruption_check = simple_strtol(arg, &end, 10);
+
+	return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check", set_corruption_check);
+
+static __init int set_corruption_check_period(char *arg)
+{
+	char *end;
+
+	corruption_check_period = simple_strtoul(arg, &end, 10);
+
+	return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_period", set_corruption_check_period);
+
+static __init int set_corruption_check_size(char *arg)
+{
+	char *end;
+	unsigned size;
+
+	size = memparse(arg, &end);
+
+	if (*end == '\0')
+		corruption_check_size = size;
+
+	return (size == corruption_check_size) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_size", set_corruption_check_size);
+
+
+void __init setup_bios_corruption_check(void)
+{
+	u64 addr = PAGE_SIZE;	/* assume first page is reserved anyway */
+
+	if (memory_corruption_check == -1) {
+		memory_corruption_check =
+#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+			1
+#else
+			0
+#endif
+			;
+	}
+
+	if (corruption_check_size == 0)
+		memory_corruption_check = 0;
+
+	if (!memory_corruption_check)
+		return;
+
+	corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
+
+	while (addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
+		u64 size;
+		addr = find_e820_area_size(addr, &size, PAGE_SIZE);
+
+		if (addr == 0)
+			break;
+
+		if ((addr + size) > corruption_check_size)
+			size = corruption_check_size - addr;
+
+		if (size == 0)
+			break;
+
+		e820_update_range(addr, size, E820_RAM, E820_RESERVED);
+		scan_areas[num_scan_areas].addr = addr;
+		scan_areas[num_scan_areas].size = size;
+		num_scan_areas++;
+
+		/* Assume we've already mapped this early memory */
+		memset(__va(addr), 0, size);
+
+		addr += size;
+	}
+
+	printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
+	       num_scan_areas);
+	update_e820();
+}
+
+
+void check_for_bios_corruption(void)
+{
+	int i;
+	int corruption = 0;
+
+	if (!memory_corruption_check)
+		return;
+
+	for (i = 0; i < num_scan_areas; i++) {
+		unsigned long *addr = __va(scan_areas[i].addr);
+		unsigned long size = scan_areas[i].size;
+
+		for (; size; addr++, size -= sizeof(unsigned long)) {
+			if (!*addr)
+				continue;
+			printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
+			       addr, __pa(addr), *addr);
+			corruption = 1;
+			*addr = 0;
+		}
+	}
+
+	WARN_ONCE(corruption, KERN_ERR "Memory corruption detected in low memory\n");
+}
+
+static void check_corruption(struct work_struct *dummy);
+static DECLARE_DELAYED_WORK(bios_check_work, check_corruption);
+
+static void check_corruption(struct work_struct *dummy)
+{
+	check_for_bios_corruption();
+	schedule_delayed_work(&bios_check_work,
+		round_jiffies_relative(corruption_check_period*HZ)); 
+}
+
+static int start_periodic_check_for_corruption(void)
+{
+	if (!memory_corruption_check || corruption_check_period == 0)
+		return 0;
+
+	printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
+	       corruption_check_period);
+
+	/* First time we run the checks right away */
+	schedule_delayed_work(&bios_check_work, 0);
+	return 0;
+}
+
+module_init(start_periodic_check_for_corruption);
+
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 82ec607..82db7f4 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -2,8 +2,14 @@
 # Makefile for x86-compatible CPU details and quirks
 #
 
+# Don't trace early stages of a secondary CPU boot
+ifdef CONFIG_FUNCTION_TRACER
+CFLAGS_REMOVE_common.o = -pg
+endif
+
 obj-y			:= intel_cacheinfo.o addon_cpuid_features.o
 obj-y			+= proc.o capflags.o powerflags.o common.o
+obj-y			+= vmware.o hypervisor.o
 
 obj-$(CONFIG_X86_32)	+= bugs.o cmpxchg.o
 obj-$(CONFIG_X86_64)	+= bugs_64.o
diff --git a/arch/x86/kernel/cpu/addon_cpuid_features.c b/arch/x86/kernel/cpu/addon_cpuid_features.c
index ef8f831..2cf2363 100644
--- a/arch/x86/kernel/cpu/addon_cpuid_features.c
+++ b/arch/x86/kernel/cpu/addon_cpuid_features.c
@@ -120,9 +120,17 @@
 	c->cpu_core_id = phys_pkg_id(c->initial_apicid, ht_mask_width)
 						 & core_select_mask;
 	c->phys_proc_id = phys_pkg_id(c->initial_apicid, core_plus_mask_width);
+	/*
+	 * Reinit the apicid, now that we have extended initial_apicid.
+	 */
+	c->apicid = phys_pkg_id(c->initial_apicid, 0);
 #else
 	c->cpu_core_id = phys_pkg_id(ht_mask_width) & core_select_mask;
 	c->phys_proc_id = phys_pkg_id(core_plus_mask_width);
+	/*
+	 * Reinit the apicid, now that we have extended initial_apicid.
+	 */
+	c->apicid = phys_pkg_id(0);
 #endif
 	c->x86_max_cores = (core_level_siblings / smp_num_siblings);
 
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 8f1e31d..7c878f6 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -283,9 +283,14 @@
 {
 	early_init_amd_mc(c);
 
-	/* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
-	if (c->x86_power & (1<<8))
+	/*
+	 * c->x86_power is 8000_0007 edx. Bit 8 is TSC runs at constant rate
+	 * with P/T states and does not stop in deep C-states
+	 */
+	if (c->x86_power & (1 << 8)) {
 		set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+		set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC);
+	}
 
 #ifdef CONFIG_X86_64
 	set_cpu_cap(c, X86_FEATURE_SYSCALL32);
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index b9c9ea0..42e0853 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -36,6 +36,7 @@
 #include <asm/proto.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
+#include <asm/hypervisor.h>
 
 #include "cpu.h"
 
@@ -703,6 +704,7 @@
 	detect_ht(c);
 #endif
 
+	init_hypervisor(c);
 	/*
 	 * On SMP, boot_cpu_data holds the common feature set between
 	 * all CPUs; so make sure that we indicate which features are
@@ -862,7 +864,7 @@
 
 struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
 
-char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss;
+static char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss;
 
 void __cpuinit pda_init(int cpu)
 {
@@ -903,8 +905,8 @@
 	}
 }
 
-char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ +
-			   DEBUG_STKSZ] __page_aligned_bss;
+static char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ +
+				  DEBUG_STKSZ] __page_aligned_bss;
 
 extern asmlinkage void ignore_sysret(void);
 
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index 8e48c5d..88ea02d 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -33,6 +33,7 @@
 #include <linux/cpufreq.h>
 #include <linux/compiler.h>
 #include <linux/dmi.h>
+#include <linux/ftrace.h>
 
 #include <linux/acpi.h>
 #include <acpi/processor.h>
@@ -391,6 +392,7 @@
 	unsigned int next_perf_state = 0; /* Index into perf table */
 	unsigned int i;
 	int result = 0;
+	struct power_trace it;
 
 	dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
 
@@ -427,6 +429,8 @@
 		}
 	}
 
+	trace_power_mark(&it, POWER_PSTATE, next_perf_state);
+
 	switch (data->cpu_feature) {
 	case SYSTEM_INTEL_MSR_CAPABLE:
 		cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c
new file mode 100644
index 0000000..fb5b86a
--- /dev/null
+++ b/arch/x86/kernel/cpu/hypervisor.c
@@ -0,0 +1,58 @@
+/*
+ * Common hypervisor code
+ *
+ * Copyright (C) 2008, VMware, Inc.
+ * Author : Alok N Kataria <akataria@vmware.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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <asm/processor.h>
+#include <asm/vmware.h>
+#include <asm/hypervisor.h>
+
+static inline void __cpuinit
+detect_hypervisor_vendor(struct cpuinfo_x86 *c)
+{
+	if (vmware_platform()) {
+		c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE;
+	} else {
+		c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE;
+	}
+}
+
+unsigned long get_hypervisor_tsc_freq(void)
+{
+	if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE)
+		return vmware_get_tsc_khz();
+	return 0;
+}
+
+static inline void __cpuinit
+hypervisor_set_feature_bits(struct cpuinfo_x86 *c)
+{
+	if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) {
+		vmware_set_feature_bits(c);
+		return;
+	}
+}
+
+void __cpuinit init_hypervisor(struct cpuinfo_x86 *c)
+{
+	detect_hypervisor_vendor(c);
+	hypervisor_set_feature_bits(c);
+}
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index cce0b61..8ea6929 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -11,7 +11,6 @@
 #include <asm/pgtable.h>
 #include <asm/msr.h>
 #include <asm/uaccess.h>
-#include <asm/ptrace.h>
 #include <asm/ds.h>
 #include <asm/bugs.h>
 
@@ -41,6 +40,16 @@
 	if (c->x86 == 15 && c->x86_cache_alignment == 64)
 		c->x86_cache_alignment = 128;
 #endif
+
+	/*
+	 * c->x86_power is 8000_0007 edx. Bit 8 is TSC runs at constant rate
+	 * with P/T states and does not stop in deep C-states
+	 */
+	if (c->x86_power & (1 << 8)) {
+		set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+		set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC);
+	}
+
 }
 
 #ifdef CONFIG_X86_32
@@ -242,6 +251,13 @@
 
 	intel_workarounds(c);
 
+	/*
+	 * Detect the extended topology information if available. This
+	 * will reinitialise the initial_apicid which will be used
+	 * in init_intel_cacheinfo()
+	 */
+	detect_extended_topology(c);
+
 	l2 = init_intel_cacheinfo(c);
 	if (c->cpuid_level > 9) {
 		unsigned eax = cpuid_eax(10);
@@ -307,13 +323,8 @@
 		set_cpu_cap(c, X86_FEATURE_P4);
 	if (c->x86 == 6)
 		set_cpu_cap(c, X86_FEATURE_P3);
-
-	if (cpu_has_bts)
-		ptrace_bts_init_intel(c);
-
 #endif
 
-	detect_extended_topology(c);
 	if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) {
 		/*
 		 * let's use the legacy cpuid vector 0x1 and 0x4 for topology
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 3f46afb..68b5d86 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -644,20 +644,17 @@
 	return show_shared_cpu_map_func(leaf, 1, buf);
 }
 
-static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) {
-	switch(this_leaf->eax.split.type) {
-	    case CACHE_TYPE_DATA:
+static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf)
+{
+	switch (this_leaf->eax.split.type) {
+	case CACHE_TYPE_DATA:
 		return sprintf(buf, "Data\n");
-		break;
-	    case CACHE_TYPE_INST:
+	case CACHE_TYPE_INST:
 		return sprintf(buf, "Instruction\n");
-		break;
-	    case CACHE_TYPE_UNIFIED:
+	case CACHE_TYPE_UNIFIED:
 		return sprintf(buf, "Unified\n");
-		break;
-	    default:
+	default:
 		return sprintf(buf, "Unknown\n");
-		break;
 	}
 }
 
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c
index 5eb390a..748c8f9 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c
@@ -237,7 +237,7 @@
 		}
 	}
 out:
-	add_pda(irq_threshold_count, 1);
+	inc_irq_stat(irq_threshold_count);
 	irq_exit();
 }
 
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel_64.c b/arch/x86/kernel/cpu/mcheck/mce_intel_64.c
index c17eaf5..4b48f25 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_intel_64.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_intel_64.c
@@ -26,7 +26,7 @@
 	if (therm_throt_process(msr_val & 1))
 		mce_log_therm_throt_event(smp_processor_id(), msr_val);
 
-	add_pda(irq_thermal_count, 1);
+	inc_irq_stat(irq_thermal_count);
 	irq_exit();
 }
 
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index c78c048..1159e26 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -803,6 +803,7 @@
 }
 
 static struct res_range __initdata range[RANGE_NUM];
+static int __initdata nr_range;
 
 #ifdef CONFIG_MTRR_SANITIZER
 
@@ -1206,40 +1207,44 @@
 #define PSHIFT		(PAGE_SHIFT - 10)
 
 static struct mtrr_cleanup_result __initdata result[NUM_RESULT];
-static struct res_range __initdata range_new[RANGE_NUM];
 static unsigned long __initdata min_loss_pfn[RANGE_NUM];
 
-static int __init mtrr_cleanup(unsigned address_bits)
+static void __init print_out_mtrr_range_state(void)
 {
-	unsigned long extra_remove_base, extra_remove_size;
-	unsigned long base, size, def, dummy;
-	mtrr_type type;
-	int nr_range, nr_range_new;
-	u64 chunk_size, gran_size;
-	unsigned long range_sums, range_sums_new;
-	int index_good;
-	int num_reg_good;
 	int i;
+	char start_factor = 'K', size_factor = 'K';
+	unsigned long start_base, size_base;
+	mtrr_type type;
 
+	for (i = 0; i < num_var_ranges; i++) {
+
+		size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10);
+		if (!size_base)
+			continue;
+
+		size_base = to_size_factor(size_base, &size_factor),
+		start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10);
+		start_base = to_size_factor(start_base, &start_factor),
+		type = range_state[i].type;
+
+		printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n",
+			i, start_base, start_factor,
+			size_base, size_factor,
+			(type == MTRR_TYPE_UNCACHABLE) ? "UC" :
+			    ((type == MTRR_TYPE_WRPROT) ? "WP" :
+			     ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other"))
+			);
+	}
+}
+
+static int __init mtrr_need_cleanup(void)
+{
+	int i;
+	mtrr_type type;
+	unsigned long size;
 	/* extra one for all 0 */
 	int num[MTRR_NUM_TYPES + 1];
 
-	if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
-		return 0;
-	rdmsr(MTRRdefType_MSR, def, dummy);
-	def &= 0xff;
-	if (def != MTRR_TYPE_UNCACHABLE)
-		return 0;
-
-	/* get it and store it aside */
-	memset(range_state, 0, sizeof(range_state));
-	for (i = 0; i < num_var_ranges; i++) {
-		mtrr_if->get(i, &base, &size, &type);
-		range_state[i].base_pfn = base;
-		range_state[i].size_pfn = size;
-		range_state[i].type = type;
-	}
-
 	/* check entries number */
 	memset(num, 0, sizeof(num));
 	for (i = 0; i < num_var_ranges; i++) {
@@ -1263,29 +1268,133 @@
 		num_var_ranges - num[MTRR_NUM_TYPES])
 		return 0;
 
+	return 1;
+}
+
+static unsigned long __initdata range_sums;
+static void __init mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
+					 unsigned long extra_remove_base,
+					 unsigned long extra_remove_size,
+					 int i)
+{
+	int num_reg;
+	static struct res_range range_new[RANGE_NUM];
+	static int nr_range_new;
+	unsigned long range_sums_new;
+
+	/* convert ranges to var ranges state */
+	num_reg = x86_setup_var_mtrrs(range, nr_range,
+						chunk_size, gran_size);
+
+	/* we got new setting in range_state, check it */
+	memset(range_new, 0, sizeof(range_new));
+	nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
+				extra_remove_base, extra_remove_size);
+	range_sums_new = sum_ranges(range_new, nr_range_new);
+
+	result[i].chunk_sizek = chunk_size >> 10;
+	result[i].gran_sizek = gran_size >> 10;
+	result[i].num_reg = num_reg;
+	if (range_sums < range_sums_new) {
+		result[i].lose_cover_sizek =
+			(range_sums_new - range_sums) << PSHIFT;
+		result[i].bad = 1;
+	} else
+		result[i].lose_cover_sizek =
+			(range_sums - range_sums_new) << PSHIFT;
+
+	/* double check it */
+	if (!result[i].bad && !result[i].lose_cover_sizek) {
+		if (nr_range_new != nr_range ||
+			memcmp(range, range_new, sizeof(range)))
+				result[i].bad = 1;
+	}
+
+	if (!result[i].bad && (range_sums - range_sums_new <
+				min_loss_pfn[num_reg])) {
+		min_loss_pfn[num_reg] =
+			range_sums - range_sums_new;
+	}
+}
+
+static void __init mtrr_print_out_one_result(int i)
+{
+	char gran_factor, chunk_factor, lose_factor;
+	unsigned long gran_base, chunk_base, lose_base;
+
+	gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
+	chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
+	lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
+	printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
+			result[i].bad ? "*BAD*" : " ",
+			gran_base, gran_factor, chunk_base, chunk_factor);
+	printk(KERN_CONT "num_reg: %d  \tlose cover RAM: %s%ld%c\n",
+			result[i].num_reg, result[i].bad ? "-" : "",
+			lose_base, lose_factor);
+}
+
+static int __init mtrr_search_optimal_index(void)
+{
+	int i;
+	int num_reg_good;
+	int index_good;
+
+	if (nr_mtrr_spare_reg >= num_var_ranges)
+		nr_mtrr_spare_reg = num_var_ranges - 1;
+	num_reg_good = -1;
+	for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
+		if (!min_loss_pfn[i])
+			num_reg_good = i;
+	}
+
+	index_good = -1;
+	if (num_reg_good != -1) {
+		for (i = 0; i < NUM_RESULT; i++) {
+			if (!result[i].bad &&
+			    result[i].num_reg == num_reg_good &&
+			    !result[i].lose_cover_sizek) {
+				index_good = i;
+				break;
+			}
+		}
+	}
+
+	return index_good;
+}
+
+
+static int __init mtrr_cleanup(unsigned address_bits)
+{
+	unsigned long extra_remove_base, extra_remove_size;
+	unsigned long base, size, def, dummy;
+	mtrr_type type;
+	u64 chunk_size, gran_size;
+	int index_good;
+	int i;
+
+	if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
+		return 0;
+	rdmsr(MTRRdefType_MSR, def, dummy);
+	def &= 0xff;
+	if (def != MTRR_TYPE_UNCACHABLE)
+		return 0;
+
+	/* get it and store it aside */
+	memset(range_state, 0, sizeof(range_state));
+	for (i = 0; i < num_var_ranges; i++) {
+		mtrr_if->get(i, &base, &size, &type);
+		range_state[i].base_pfn = base;
+		range_state[i].size_pfn = size;
+		range_state[i].type = type;
+	}
+
+	/* check if we need handle it and can handle it */
+	if (!mtrr_need_cleanup())
+		return 0;
+
 	/* print original var MTRRs at first, for debugging: */
 	printk(KERN_DEBUG "original variable MTRRs\n");
-	for (i = 0; i < num_var_ranges; i++) {
-		char start_factor = 'K', size_factor = 'K';
-		unsigned long start_base, size_base;
-
-		size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10);
-		if (!size_base)
-			continue;
-
-		size_base = to_size_factor(size_base, &size_factor),
-		start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10);
-		start_base = to_size_factor(start_base, &start_factor),
-		type = range_state[i].type;
-
-		printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n",
-			i, start_base, start_factor,
-			size_base, size_factor,
-			(type == MTRR_TYPE_UNCACHABLE) ? "UC" :
-			    ((type == MTRR_TYPE_WRPROT) ? "WP" :
-			     ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other"))
-			);
-	}
+	print_out_mtrr_range_state();
 
 	memset(range, 0, sizeof(range));
 	extra_remove_size = 0;
@@ -1309,176 +1418,64 @@
 	       range_sums >> (20 - PAGE_SHIFT));
 
 	if (mtrr_chunk_size && mtrr_gran_size) {
-		int num_reg;
-		char gran_factor, chunk_factor, lose_factor;
-		unsigned long gran_base, chunk_base, lose_base;
-
-		debug_print++;
-		/* convert ranges to var ranges state */
-		num_reg = x86_setup_var_mtrrs(range, nr_range, mtrr_chunk_size,
-					      mtrr_gran_size);
-
-		/* we got new setting in range_state, check it */
-		memset(range_new, 0, sizeof(range_new));
-		nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
-						      extra_remove_base,
-						      extra_remove_size);
-		range_sums_new = sum_ranges(range_new, nr_range_new);
-
 		i = 0;
-		result[i].chunk_sizek = mtrr_chunk_size >> 10;
-		result[i].gran_sizek = mtrr_gran_size >> 10;
-		result[i].num_reg = num_reg;
-		if (range_sums < range_sums_new) {
-			result[i].lose_cover_sizek =
-				(range_sums_new - range_sums) << PSHIFT;
-			result[i].bad = 1;
-		} else
-			result[i].lose_cover_sizek =
-				(range_sums - range_sums_new) << PSHIFT;
+		mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size,
+				      extra_remove_base, extra_remove_size, i);
 
-		gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
-		chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
-		lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
-		printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
-			 result[i].bad?"*BAD*":" ",
-			 gran_base, gran_factor, chunk_base, chunk_factor);
-		printk(KERN_CONT "num_reg: %d  \tlose cover RAM: %s%ld%c\n",
-			 result[i].num_reg, result[i].bad?"-":"",
-			 lose_base, lose_factor);
+		mtrr_print_out_one_result(i);
+
 		if (!result[i].bad) {
 			set_var_mtrr_all(address_bits);
 			return 1;
 		}
 		printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, "
 		       "will find optimal one\n");
-		debug_print--;
-		memset(result, 0, sizeof(result[0]));
 	}
 
 	i = 0;
 	memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn));
 	memset(result, 0, sizeof(result));
 	for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) {
-		char gran_factor;
-		unsigned long gran_base;
-
-		if (debug_print)
-			gran_base = to_size_factor(gran_size >> 10, &gran_factor);
 
 		for (chunk_size = gran_size; chunk_size < (1ULL<<32);
 		     chunk_size <<= 1) {
-			int num_reg;
 
-			if (debug_print) {
-				char chunk_factor;
-				unsigned long chunk_base;
-
-				chunk_base = to_size_factor(chunk_size>>10, &chunk_factor),
-				printk(KERN_INFO "\n");
-				printk(KERN_INFO "gran_size: %ld%c   chunk_size: %ld%c \n",
-				       gran_base, gran_factor, chunk_base, chunk_factor);
-			}
 			if (i >= NUM_RESULT)
 				continue;
 
-			/* convert ranges to var ranges state */
-			num_reg = x86_setup_var_mtrrs(range, nr_range,
-							 chunk_size, gran_size);
-
-			/* we got new setting in range_state, check it */
-			memset(range_new, 0, sizeof(range_new));
-			nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
-					 extra_remove_base, extra_remove_size);
-			range_sums_new = sum_ranges(range_new, nr_range_new);
-
-			result[i].chunk_sizek = chunk_size >> 10;
-			result[i].gran_sizek = gran_size >> 10;
-			result[i].num_reg = num_reg;
-			if (range_sums < range_sums_new) {
-				result[i].lose_cover_sizek =
-					(range_sums_new - range_sums) << PSHIFT;
-				result[i].bad = 1;
-			} else
-				result[i].lose_cover_sizek =
-					(range_sums - range_sums_new) << PSHIFT;
-
-			/* double check it */
-			if (!result[i].bad && !result[i].lose_cover_sizek) {
-				if (nr_range_new != nr_range ||
-					memcmp(range, range_new, sizeof(range)))
-						result[i].bad = 1;
+			mtrr_calc_range_state(chunk_size, gran_size,
+				      extra_remove_base, extra_remove_size, i);
+			if (debug_print) {
+				mtrr_print_out_one_result(i);
+				printk(KERN_INFO "\n");
 			}
 
-			if (!result[i].bad && (range_sums - range_sums_new <
-					       min_loss_pfn[num_reg])) {
-				min_loss_pfn[num_reg] =
-					range_sums - range_sums_new;
-			}
 			i++;
 		}
 	}
 
-	/* print out all */
-	for (i = 0; i < NUM_RESULT; i++) {
-		char gran_factor, chunk_factor, lose_factor;
-		unsigned long gran_base, chunk_base, lose_base;
-
-		gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
-		chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
-		lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
-		printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
-			 result[i].bad?"*BAD*":" ",
-			 gran_base, gran_factor, chunk_base, chunk_factor);
-		printk(KERN_CONT "num_reg: %d  \tlose cover RAM: %s%ld%c\n",
-			 result[i].num_reg, result[i].bad?"-":"",
-			 lose_base, lose_factor);
-	}
-
 	/* try to find the optimal index */
-	if (nr_mtrr_spare_reg >= num_var_ranges)
-		nr_mtrr_spare_reg = num_var_ranges - 1;
-	num_reg_good = -1;
-	for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
-		if (!min_loss_pfn[i])
-			num_reg_good = i;
-	}
-
-	index_good = -1;
-	if (num_reg_good != -1) {
-		for (i = 0; i < NUM_RESULT; i++) {
-			if (!result[i].bad &&
-			    result[i].num_reg == num_reg_good &&
-			    !result[i].lose_cover_sizek) {
-				index_good = i;
-				break;
-			}
-		}
-	}
+	index_good = mtrr_search_optimal_index();
 
 	if (index_good != -1) {
-		char gran_factor, chunk_factor, lose_factor;
-		unsigned long gran_base, chunk_base, lose_base;
-
 		printk(KERN_INFO "Found optimal setting for mtrr clean up\n");
 		i = index_good;
-		gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
-		chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
-		lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
-		printk(KERN_INFO "gran_size: %ld%c \tchunk_size: %ld%c \t",
-			 gran_base, gran_factor, chunk_base, chunk_factor);
-		printk(KERN_CONT "num_reg: %d  \tlose RAM: %ld%c\n",
-			 result[i].num_reg, lose_base, lose_factor);
+		mtrr_print_out_one_result(i);
+
 		/* convert ranges to var ranges state */
 		chunk_size = result[i].chunk_sizek;
 		chunk_size <<= 10;
 		gran_size = result[i].gran_sizek;
 		gran_size <<= 10;
-		debug_print++;
 		x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
-		debug_print--;
 		set_var_mtrr_all(address_bits);
+		printk(KERN_DEBUG "New variable MTRRs\n");
+		print_out_mtrr_range_state();
 		return 1;
+	} else {
+		/* print out all */
+		for (i = 0; i < NUM_RESULT; i++)
+			mtrr_print_out_one_result(i);
 	}
 
 	printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n");
@@ -1562,7 +1559,6 @@
 {
 	unsigned long i, base, size, highest_pfn = 0, def, dummy;
 	mtrr_type type;
-	int nr_range;
 	u64 total_trim_size;
 
 	/* extra one for all 0 */
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
new file mode 100644
index 0000000..284c399
--- /dev/null
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -0,0 +1,112 @@
+/*
+ * VMware Detection code.
+ *
+ * Copyright (C) 2008, VMware, Inc.
+ * Author : Alok N Kataria <akataria@vmware.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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/dmi.h>
+#include <asm/div64.h>
+#include <asm/vmware.h>
+
+#define CPUID_VMWARE_INFO_LEAF	0x40000000
+#define VMWARE_HYPERVISOR_MAGIC	0x564D5868
+#define VMWARE_HYPERVISOR_PORT	0x5658
+
+#define VMWARE_PORT_CMD_GETVERSION	10
+#define VMWARE_PORT_CMD_GETHZ		45
+
+#define VMWARE_PORT(cmd, eax, ebx, ecx, edx)				\
+	__asm__("inl (%%dx)" :						\
+			"=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) :	\
+			"0"(VMWARE_HYPERVISOR_MAGIC),			\
+			"1"(VMWARE_PORT_CMD_##cmd),			\
+			"2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) :	\
+			"memory");
+
+static inline int __vmware_platform(void)
+{
+	uint32_t eax, ebx, ecx, edx;
+	VMWARE_PORT(GETVERSION, eax, ebx, ecx, edx);
+	return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC;
+}
+
+static unsigned long __vmware_get_tsc_khz(void)
+{
+        uint64_t tsc_hz;
+        uint32_t eax, ebx, ecx, edx;
+
+        VMWARE_PORT(GETHZ, eax, ebx, ecx, edx);
+
+        if (ebx == UINT_MAX)
+                return 0;
+        tsc_hz = eax | (((uint64_t)ebx) << 32);
+        do_div(tsc_hz, 1000);
+        BUG_ON(tsc_hz >> 32);
+        return tsc_hz;
+}
+
+/*
+ * While checking the dmi string infomation, just checking the product
+ * serial key should be enough, as this will always have a VMware
+ * specific string when running under VMware hypervisor.
+ */
+int vmware_platform(void)
+{
+	if (cpu_has_hypervisor) {
+		unsigned int eax, ebx, ecx, edx;
+		char hyper_vendor_id[13];
+
+		cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &ebx, &ecx, &edx);
+		memcpy(hyper_vendor_id + 0, &ebx, 4);
+		memcpy(hyper_vendor_id + 4, &ecx, 4);
+		memcpy(hyper_vendor_id + 8, &edx, 4);
+		hyper_vendor_id[12] = '\0';
+		if (!strcmp(hyper_vendor_id, "VMwareVMware"))
+			return 1;
+	} else if (dmi_available && dmi_name_in_serial("VMware") &&
+		   __vmware_platform())
+		return 1;
+
+	return 0;
+}
+
+unsigned long vmware_get_tsc_khz(void)
+{
+	BUG_ON(!vmware_platform());
+	return __vmware_get_tsc_khz();
+}
+
+/*
+ * VMware hypervisor takes care of exporting a reliable TSC to the guest.
+ * Still, due to timing difference when running on virtual cpus, the TSC can
+ * be marked as unstable in some cases. For example, the TSC sync check at
+ * bootup can fail due to a marginal offset between vcpus' TSCs (though the
+ * TSCs do not drift from each other).  Also, the ACPI PM timer clocksource
+ * is not suitable as a watchdog when running on a hypervisor because the
+ * kernel may miss a wrap of the counter if the vcpu is descheduled for a
+ * long time. To skip these checks at runtime we set these capability bits,
+ * so that the kernel could just trust the hypervisor with providing a
+ * reliable virtual TSC that is suitable for timekeeping.
+ */
+void __cpuinit vmware_set_feature_bits(struct cpuinfo_x86 *c)
+{
+	set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+	set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE);
+}
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 2685538..d84a852 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -29,34 +29,17 @@
 
 #include <mach_ipi.h>
 
-/* This keeps a track of which one is crashing cpu. */
-static int crashing_cpu;
 
 #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
-static atomic_t waiting_for_crash_ipi;
 
-static int crash_nmi_callback(struct notifier_block *self,
-			unsigned long val, void *data)
+static void kdump_nmi_callback(int cpu, struct die_args *args)
 {
 	struct pt_regs *regs;
 #ifdef CONFIG_X86_32
 	struct pt_regs fixed_regs;
 #endif
-	int cpu;
 
-	if (val != DIE_NMI_IPI)
-		return NOTIFY_OK;
-
-	regs = ((struct die_args *)data)->regs;
-	cpu = raw_smp_processor_id();
-
-	/* Don't do anything if this handler is invoked on crashing cpu.
-	 * Otherwise, system will completely hang. Crashing cpu can get
-	 * an NMI if system was initially booted with nmi_watchdog parameter.
-	 */
-	if (cpu == crashing_cpu)
-		return NOTIFY_STOP;
-	local_irq_disable();
+	regs = args->regs;
 
 #ifdef CONFIG_X86_32
 	if (!user_mode_vm(regs)) {
@@ -65,54 +48,19 @@
 	}
 #endif
 	crash_save_cpu(regs, cpu);
-	disable_local_APIC();
-	atomic_dec(&waiting_for_crash_ipi);
-	/* Assume hlt works */
-	halt();
-	for (;;)
-		cpu_relax();
 
-	return 1;
-}
-
-static void smp_send_nmi_allbutself(void)
-{
-	cpumask_t mask = cpu_online_map;
-	cpu_clear(safe_smp_processor_id(), mask);
-	if (!cpus_empty(mask))
-		send_IPI_mask(mask, NMI_VECTOR);
-}
-
-static struct notifier_block crash_nmi_nb = {
-	.notifier_call = crash_nmi_callback,
-};
-
-static void nmi_shootdown_cpus(void)
-{
-	unsigned long msecs;
-
-	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
-	/* Would it be better to replace the trap vector here? */
-	if (register_die_notifier(&crash_nmi_nb))
-		return;		/* return what? */
-	/* Ensure the new callback function is set before sending
-	 * out the NMI
-	 */
-	wmb();
-
-	smp_send_nmi_allbutself();
-
-	msecs = 1000; /* Wait at most a second for the other cpus to stop */
-	while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
-		mdelay(1);
-		msecs--;
-	}
-
-	/* Leave the nmi callback set */
 	disable_local_APIC();
 }
+
+static void kdump_nmi_shootdown_cpus(void)
+{
+	nmi_shootdown_cpus(kdump_nmi_callback);
+
+	disable_local_APIC();
+}
+
 #else
-static void nmi_shootdown_cpus(void)
+static void kdump_nmi_shootdown_cpus(void)
 {
 	/* There are no cpus to shootdown */
 }
@@ -131,9 +79,7 @@
 	/* The kernel is broken so disable interrupts */
 	local_irq_disable();
 
-	/* Make a note of crashing cpu. Will be used in NMI callback.*/
-	crashing_cpu = safe_smp_processor_id();
-	nmi_shootdown_cpus();
+	kdump_nmi_shootdown_cpus();
 	lapic_shutdown();
 #if defined(CONFIG_X86_IO_APIC)
 	disable_IO_APIC();
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c
index a2d1176..da91701 100644
--- a/arch/x86/kernel/ds.c
+++ b/arch/x86/kernel/ds.c
@@ -6,14 +6,13 @@
  * precise-event based sampling (PEBS).
  *
  * It manages:
- * - per-thread and per-cpu allocation of BTS and PEBS
- * - buffer memory allocation (optional)
- * - buffer overflow handling
+ * - DS and BTS hardware configuration
+ * - buffer overflow handling (to be done)
  * - buffer access
  *
- * It assumes:
- * - get_task_struct on all parameter tasks
- * - current is allowed to trace parameter tasks
+ * It does not do:
+ * - security checking (is the caller allowed to trace the task)
+ * - buffer allocation (memory accounting)
  *
  *
  * Copyright (C) 2007-2008 Intel Corporation.
@@ -28,22 +27,69 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/kernel.h>
 
 
 /*
  * The configuration for a particular DS hardware implementation.
  */
 struct ds_configuration {
-	/* the size of the DS structure in bytes */
-	unsigned char  sizeof_ds;
-	/* the size of one pointer-typed field in the DS structure in bytes;
-	   this covers the first 8 fields related to buffer management. */
+	/* the name of the configuration */
+	const char *name;
+	/* the size of one pointer-typed field in the DS structure and
+	   in the BTS and PEBS buffers in bytes;
+	   this covers the first 8 DS fields related to buffer management. */
 	unsigned char  sizeof_field;
 	/* the size of a BTS/PEBS record in bytes */
 	unsigned char  sizeof_rec[2];
+	/* a series of bit-masks to control various features indexed
+	 * by enum ds_feature */
+	unsigned long ctl[dsf_ctl_max];
 };
-static struct ds_configuration ds_cfg;
+static DEFINE_PER_CPU(struct ds_configuration, ds_cfg_array);
 
+#define ds_cfg per_cpu(ds_cfg_array, smp_processor_id())
+
+#define MAX_SIZEOF_DS (12 * 8)	/* maximal size of a DS configuration */
+#define MAX_SIZEOF_BTS (3 * 8)	/* maximal size of a BTS record */
+#define DS_ALIGNMENT (1 << 3)	/* BTS and PEBS buffer alignment */
+
+#define BTS_CONTROL \
+ (ds_cfg.ctl[dsf_bts] | ds_cfg.ctl[dsf_bts_kernel] | ds_cfg.ctl[dsf_bts_user] |\
+  ds_cfg.ctl[dsf_bts_overflow])
+
+
+/*
+ * A BTS or PEBS tracer.
+ *
+ * This holds the configuration of the tracer and serves as a handle
+ * to identify tracers.
+ */
+struct ds_tracer {
+	/* the DS context (partially) owned by this tracer */
+	struct ds_context *context;
+	/* the buffer provided on ds_request() and its size in bytes */
+	void *buffer;
+	size_t size;
+};
+
+struct bts_tracer {
+	/* the common DS part */
+	struct ds_tracer ds;
+	/* the trace including the DS configuration */
+	struct bts_trace trace;
+	/* buffer overflow notification function */
+	bts_ovfl_callback_t ovfl;
+};
+
+struct pebs_tracer {
+	/* the common DS part */
+	struct ds_tracer ds;
+	/* the trace including the DS configuration */
+	struct pebs_trace trace;
+	/* buffer overflow notification function */
+	pebs_ovfl_callback_t ovfl;
+};
 
 /*
  * Debug Store (DS) save area configuration (see Intel64 and IA32
@@ -109,32 +155,9 @@
 
 
 /*
- * Locking is done only for allocating BTS or PEBS resources and for
- * guarding context and buffer memory allocation.
- *
- * Most functions require the current task to own the ds context part
- * they are going to access. All the locking is done when validating
- * access to the context.
+ * Locking is done only for allocating BTS or PEBS resources.
  */
-static spinlock_t ds_lock = __SPIN_LOCK_UNLOCKED(ds_lock);
-
-/*
- * Validate that the current task is allowed to access the BTS/PEBS
- * buffer of the parameter task.
- *
- * Returns 0, if access is granted; -Eerrno, otherwise.
- */
-static inline int ds_validate_access(struct ds_context *context,
-				     enum ds_qualifier qual)
-{
-	if (!context)
-		return -EPERM;
-
-	if (context->owner[qual] == current)
-		return 0;
-
-	return -EPERM;
-}
+static DEFINE_SPINLOCK(ds_lock);
 
 
 /*
@@ -150,27 +173,32 @@
  *   >0  number of per-thread tracers
  *   <0  number of per-cpu tracers
  *
- * The below functions to get and put tracers and to check the
- * allocation type require the ds_lock to be held by the caller.
- *
  * Tracers essentially gives the number of ds contexts for a certain
  * type of allocation.
  */
-static long tracers;
+static atomic_t tracers = ATOMIC_INIT(0);
 
 static inline void get_tracer(struct task_struct *task)
 {
-	tracers += (task ? 1 : -1);
+	if (task)
+		atomic_inc(&tracers);
+	else
+		atomic_dec(&tracers);
 }
 
 static inline void put_tracer(struct task_struct *task)
 {
-	tracers -= (task ? 1 : -1);
+	if (task)
+		atomic_dec(&tracers);
+	else
+		atomic_inc(&tracers);
 }
 
 static inline int check_tracer(struct task_struct *task)
 {
-	return (task ? (tracers >= 0) : (tracers <= 0));
+	return task ?
+		(atomic_read(&tracers) >= 0) :
+		(atomic_read(&tracers) <= 0);
 }
 
 
@@ -183,99 +211,70 @@
  *
  * Contexts are use-counted. They are allocated on first access and
  * deallocated when the last user puts the context.
- *
- * We distinguish between an allocating and a non-allocating get of a
- * context:
- * - the allocating get is used for requesting BTS/PEBS resources. It
- *   requires the caller to hold the global ds_lock.
- * - the non-allocating get is used for all other cases. A
- *   non-existing context indicates an error. It acquires and releases
- *   the ds_lock itself for obtaining the context.
- *
- * A context and its DS configuration are allocated and deallocated
- * together. A context always has a DS configuration of the
- * appropriate size.
  */
-static DEFINE_PER_CPU(struct ds_context *, system_context);
+struct ds_context {
+	/* pointer to the DS configuration; goes into MSR_IA32_DS_AREA */
+	unsigned char ds[MAX_SIZEOF_DS];
+	/* the owner of the BTS and PEBS configuration, respectively */
+	struct bts_tracer *bts_master;
+	struct pebs_tracer *pebs_master;
+	/* use count */
+	unsigned long count;
+	/* a pointer to the context location inside the thread_struct
+	 * or the per_cpu context array */
+	struct ds_context **this;
+	/* a pointer to the task owning this context, or NULL, if the
+	 * context is owned by a cpu */
+	struct task_struct *task;
+};
 
-#define this_system_context per_cpu(system_context, smp_processor_id())
+static DEFINE_PER_CPU(struct ds_context *, system_context_array);
 
-/*
- * Returns the pointer to the parameter task's context or to the
- * system-wide context, if task is NULL.
- *
- * Increases the use count of the returned context, if not NULL.
- */
+#define system_context per_cpu(system_context_array, smp_processor_id())
+
+
 static inline struct ds_context *ds_get_context(struct task_struct *task)
 {
-	struct ds_context *context;
+	struct ds_context **p_context =
+		(task ? &task->thread.ds_ctx : &system_context);
+	struct ds_context *context = NULL;
+	struct ds_context *new_context = NULL;
 	unsigned long irq;
 
+	/* Chances are small that we already have a context. */
+	new_context = kzalloc(sizeof(*new_context), GFP_KERNEL);
+	if (!new_context)
+		return NULL;
+
 	spin_lock_irqsave(&ds_lock, irq);
 
-	context = (task ? task->thread.ds_ctx : this_system_context);
-	if (context)
-		context->count++;
-
-	spin_unlock_irqrestore(&ds_lock, irq);
-
-	return context;
-}
-
-/*
- * Same as ds_get_context, but allocates the context and it's DS
- * structure, if necessary; returns NULL; if out of memory.
- */
-static inline struct ds_context *ds_alloc_context(struct task_struct *task)
-{
-	struct ds_context **p_context =
-		(task ? &task->thread.ds_ctx : &this_system_context);
-	struct ds_context *context = *p_context;
-	unsigned long irq;
-
+	context = *p_context;
 	if (!context) {
-		context = kzalloc(sizeof(*context), GFP_KERNEL);
-		if (!context)
-			return NULL;
+		context = new_context;
 
-		context->ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL);
-		if (!context->ds) {
-			kfree(context);
-			return NULL;
-		}
+		context->this = p_context;
+		context->task = task;
+		context->count = 0;
 
-		spin_lock_irqsave(&ds_lock, irq);
+		if (task)
+			set_tsk_thread_flag(task, TIF_DS_AREA_MSR);
 
-		if (*p_context) {
-			kfree(context->ds);
-			kfree(context);
+		if (!task || (task == current))
+			wrmsrl(MSR_IA32_DS_AREA, (unsigned long)context->ds);
 
-			context = *p_context;
-		} else {
-			*p_context = context;
-
-			context->this = p_context;
-			context->task = task;
-
-			if (task)
-				set_tsk_thread_flag(task, TIF_DS_AREA_MSR);
-
-			if (!task || (task == current))
-				wrmsrl(MSR_IA32_DS_AREA,
-				       (unsigned long)context->ds);
-		}
-		spin_unlock_irqrestore(&ds_lock, irq);
+		*p_context = context;
 	}
 
 	context->count++;
 
+	spin_unlock_irqrestore(&ds_lock, irq);
+
+	if (context != new_context)
+		kfree(new_context);
+
 	return context;
 }
 
-/*
- * Decreases the use count of the parameter context, if not NULL.
- * Deallocates the context, if the use count reaches zero.
- */
 static inline void ds_put_context(struct ds_context *context)
 {
 	unsigned long irq;
@@ -285,8 +284,10 @@
 
 	spin_lock_irqsave(&ds_lock, irq);
 
-	if (--context->count)
-		goto out;
+	if (--context->count) {
+		spin_unlock_irqrestore(&ds_lock, irq);
+		return;
+	}
 
 	*(context->this) = NULL;
 
@@ -296,361 +297,53 @@
 	if (!context->task || (context->task == current))
 		wrmsrl(MSR_IA32_DS_AREA, 0);
 
-	put_tracer(context->task);
-
-	/* free any leftover buffers from tracers that did not
-	 * deallocate them properly. */
-	kfree(context->buffer[ds_bts]);
-	kfree(context->buffer[ds_pebs]);
-	kfree(context->ds);
-	kfree(context);
- out:
 	spin_unlock_irqrestore(&ds_lock, irq);
+
+	kfree(context);
 }
 
 
 /*
- * Handle a buffer overflow
+ * Call the tracer's callback on a buffer overflow.
  *
- * task: the task whose buffers are overflowing;
- *       NULL for a buffer overflow on the current cpu
  * context: the ds context
  * qual: the buffer type
  */
-static void ds_overflow(struct task_struct *task, struct ds_context *context,
-			enum ds_qualifier qual)
+static void ds_overflow(struct ds_context *context, enum ds_qualifier qual)
 {
-	if (!context)
-		return;
-
-	if (context->callback[qual])
-		(*context->callback[qual])(task);
-
-	/* todo: do some more overflow handling */
+	switch (qual) {
+	case ds_bts:
+		if (context->bts_master &&
+		    context->bts_master->ovfl)
+			context->bts_master->ovfl(context->bts_master);
+		break;
+	case ds_pebs:
+		if (context->pebs_master &&
+		    context->pebs_master->ovfl)
+			context->pebs_master->ovfl(context->pebs_master);
+		break;
+	}
 }
 
 
 /*
- * Allocate a non-pageable buffer of the parameter size.
- * Checks the memory and the locked memory rlimit.
+ * Write raw data into the BTS or PEBS buffer.
  *
- * Returns the buffer, if successful;
- *         NULL, if out of memory or rlimit exceeded.
+ * The remainder of any partially written record is zeroed out.
  *
- * size: the requested buffer size in bytes
- * pages (out): if not NULL, contains the number of pages reserved
+ * context: the DS context
+ * qual: the buffer type
+ * record: the data to write
+ * size: the size of the data
  */
-static inline void *ds_allocate_buffer(size_t size, unsigned int *pages)
+static int ds_write(struct ds_context *context, enum ds_qualifier qual,
+		    const void *record, size_t size)
 {
-	unsigned long rlim, vm, pgsz;
-	void *buffer;
-
-	pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;
-
-	rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
-	vm   = current->mm->total_vm  + pgsz;
-	if (rlim < vm)
-		return NULL;
-
-	rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
-	vm   = current->mm->locked_vm  + pgsz;
-	if (rlim < vm)
-		return NULL;
-
-	buffer = kzalloc(size, GFP_KERNEL);
-	if (!buffer)
-		return NULL;
-
-	current->mm->total_vm  += pgsz;
-	current->mm->locked_vm += pgsz;
-
-	if (pages)
-		*pages = pgsz;
-
-	return buffer;
-}
-
-static int ds_request(struct task_struct *task, void *base, size_t size,
-		      ds_ovfl_callback_t ovfl, enum ds_qualifier qual)
-{
-	struct ds_context *context;
-	unsigned long buffer, adj;
-	const unsigned long alignment = (1 << 3);
-	unsigned long irq;
-	int error = 0;
-
-	if (!ds_cfg.sizeof_ds)
-		return -EOPNOTSUPP;
-
-	/* we require some space to do alignment adjustments below */
-	if (size < (alignment + ds_cfg.sizeof_rec[qual]))
-		return -EINVAL;
-
-	/* buffer overflow notification is not yet implemented */
-	if (ovfl)
-		return -EOPNOTSUPP;
-
-
-	context = ds_alloc_context(task);
-	if (!context)
-		return -ENOMEM;
-
-	spin_lock_irqsave(&ds_lock, irq);
-
-	error = -EPERM;
-	if (!check_tracer(task))
-		goto out_unlock;
-
-	get_tracer(task);
-
-	error = -EALREADY;
-	if (context->owner[qual] == current)
-		goto out_put_tracer;
-	error = -EPERM;
-	if (context->owner[qual] != NULL)
-		goto out_put_tracer;
-	context->owner[qual] = current;
-
-	spin_unlock_irqrestore(&ds_lock, irq);
-
-
-	error = -ENOMEM;
-	if (!base) {
-		base = ds_allocate_buffer(size, &context->pages[qual]);
-		if (!base)
-			goto out_release;
-
-		context->buffer[qual]   = base;
-	}
-	error = 0;
-
-	context->callback[qual] = ovfl;
-
-	/* adjust the buffer address and size to meet alignment
-	 * constraints:
-	 * - buffer is double-word aligned
-	 * - size is multiple of record size
-	 *
-	 * We checked the size at the very beginning; we have enough
-	 * space to do the adjustment.
-	 */
-	buffer = (unsigned long)base;
-
-	adj = ALIGN(buffer, alignment) - buffer;
-	buffer += adj;
-	size   -= adj;
-
-	size /= ds_cfg.sizeof_rec[qual];
-	size *= ds_cfg.sizeof_rec[qual];
-
-	ds_set(context->ds, qual, ds_buffer_base, buffer);
-	ds_set(context->ds, qual, ds_index, buffer);
-	ds_set(context->ds, qual, ds_absolute_maximum, buffer + size);
-
-	if (ovfl) {
-		/* todo: select a suitable interrupt threshold */
-	} else
-		ds_set(context->ds, qual,
-		       ds_interrupt_threshold, buffer + size + 1);
-
-	/* we keep the context until ds_release */
-	return error;
-
- out_release:
-	context->owner[qual] = NULL;
-	ds_put_context(context);
-	put_tracer(task);
-	return error;
-
- out_put_tracer:
-	spin_unlock_irqrestore(&ds_lock, irq);
-	ds_put_context(context);
-	put_tracer(task);
-	return error;
-
- out_unlock:
-	spin_unlock_irqrestore(&ds_lock, irq);
-	ds_put_context(context);
-	return error;
-}
-
-int ds_request_bts(struct task_struct *task, void *base, size_t size,
-		   ds_ovfl_callback_t ovfl)
-{
-	return ds_request(task, base, size, ovfl, ds_bts);
-}
-
-int ds_request_pebs(struct task_struct *task, void *base, size_t size,
-		    ds_ovfl_callback_t ovfl)
-{
-	return ds_request(task, base, size, ovfl, ds_pebs);
-}
-
-static int ds_release(struct task_struct *task, enum ds_qualifier qual)
-{
-	struct ds_context *context;
-	int error;
-
-	context = ds_get_context(task);
-	error = ds_validate_access(context, qual);
-	if (error < 0)
-		goto out;
-
-	kfree(context->buffer[qual]);
-	context->buffer[qual] = NULL;
-
-	current->mm->total_vm  -= context->pages[qual];
-	current->mm->locked_vm -= context->pages[qual];
-	context->pages[qual] = 0;
-	context->owner[qual] = NULL;
-
-	/*
-	 * we put the context twice:
-	 *   once for the ds_get_context
-	 *   once for the corresponding ds_request
-	 */
-	ds_put_context(context);
- out:
-	ds_put_context(context);
-	return error;
-}
-
-int ds_release_bts(struct task_struct *task)
-{
-	return ds_release(task, ds_bts);
-}
-
-int ds_release_pebs(struct task_struct *task)
-{
-	return ds_release(task, ds_pebs);
-}
-
-static int ds_get_index(struct task_struct *task, size_t *pos,
-			enum ds_qualifier qual)
-{
-	struct ds_context *context;
-	unsigned long base, index;
-	int error;
-
-	context = ds_get_context(task);
-	error = ds_validate_access(context, qual);
-	if (error < 0)
-		goto out;
-
-	base  = ds_get(context->ds, qual, ds_buffer_base);
-	index = ds_get(context->ds, qual, ds_index);
-
-	error = ((index - base) / ds_cfg.sizeof_rec[qual]);
-	if (pos)
-		*pos = error;
- out:
-	ds_put_context(context);
-	return error;
-}
-
-int ds_get_bts_index(struct task_struct *task, size_t *pos)
-{
-	return ds_get_index(task, pos, ds_bts);
-}
-
-int ds_get_pebs_index(struct task_struct *task, size_t *pos)
-{
-	return ds_get_index(task, pos, ds_pebs);
-}
-
-static int ds_get_end(struct task_struct *task, size_t *pos,
-		      enum ds_qualifier qual)
-{
-	struct ds_context *context;
-	unsigned long base, end;
-	int error;
-
-	context = ds_get_context(task);
-	error = ds_validate_access(context, qual);
-	if (error < 0)
-		goto out;
-
-	base = ds_get(context->ds, qual, ds_buffer_base);
-	end  = ds_get(context->ds, qual, ds_absolute_maximum);
-
-	error = ((end - base) / ds_cfg.sizeof_rec[qual]);
-	if (pos)
-		*pos = error;
- out:
-	ds_put_context(context);
-	return error;
-}
-
-int ds_get_bts_end(struct task_struct *task, size_t *pos)
-{
-	return ds_get_end(task, pos, ds_bts);
-}
-
-int ds_get_pebs_end(struct task_struct *task, size_t *pos)
-{
-	return ds_get_end(task, pos, ds_pebs);
-}
-
-static int ds_access(struct task_struct *task, size_t index,
-		     const void **record, enum ds_qualifier qual)
-{
-	struct ds_context *context;
-	unsigned long base, idx;
-	int error;
+	int bytes_written = 0;
 
 	if (!record)
 		return -EINVAL;
 
-	context = ds_get_context(task);
-	error = ds_validate_access(context, qual);
-	if (error < 0)
-		goto out;
-
-	base = ds_get(context->ds, qual, ds_buffer_base);
-	idx = base + (index * ds_cfg.sizeof_rec[qual]);
-
-	error = -EINVAL;
-	if (idx > ds_get(context->ds, qual, ds_absolute_maximum))
-		goto out;
-
-	*record = (const void *)idx;
-	error = ds_cfg.sizeof_rec[qual];
- out:
-	ds_put_context(context);
-	return error;
-}
-
-int ds_access_bts(struct task_struct *task, size_t index, const void **record)
-{
-	return ds_access(task, index, record, ds_bts);
-}
-
-int ds_access_pebs(struct task_struct *task, size_t index, const void **record)
-{
-	return ds_access(task, index, record, ds_pebs);
-}
-
-static int ds_write(struct task_struct *task, const void *record, size_t size,
-		    enum ds_qualifier qual, int force)
-{
-	struct ds_context *context;
-	int error;
-
-	if (!record)
-		return -EINVAL;
-
-	error = -EPERM;
-	context = ds_get_context(task);
-	if (!context)
-		goto out;
-
-	if (!force) {
-		error = ds_validate_access(context, qual);
-		if (error < 0)
-			goto out;
-	}
-
-	error = 0;
 	while (size) {
 		unsigned long base, index, end, write_end, int_th;
 		unsigned long write_size, adj_write_size;
@@ -678,14 +371,14 @@
 			write_end = end;
 
 		if (write_end <= index)
-			goto out;
+			break;
 
 		write_size = min((unsigned long) size, write_end - index);
 		memcpy((void *)index, record, write_size);
 
 		record = (const char *)record + write_size;
-		size  -= write_size;
-		error += write_size;
+		size -= write_size;
+		bytes_written += write_size;
 
 		adj_write_size = write_size / ds_cfg.sizeof_rec[qual];
 		adj_write_size *= ds_cfg.sizeof_rec[qual];
@@ -700,146 +393,555 @@
 		ds_set(context->ds, qual, ds_index, index);
 
 		if (index >= int_th)
-			ds_overflow(task, context, qual);
+			ds_overflow(context, qual);
 	}
 
- out:
-	ds_put_context(context);
-	return error;
+	return bytes_written;
 }
 
-int ds_write_bts(struct task_struct *task, const void *record, size_t size)
+
+/*
+ * Branch Trace Store (BTS) uses the following format. Different
+ * architectures vary in the size of those fields.
+ * - source linear address
+ * - destination linear address
+ * - flags
+ *
+ * Later architectures use 64bit pointers throughout, whereas earlier
+ * architectures use 32bit pointers in 32bit mode.
+ *
+ * We compute the base address for the first 8 fields based on:
+ * - the field size stored in the DS configuration
+ * - the relative field position
+ *
+ * In order to store additional information in the BTS buffer, we use
+ * a special source address to indicate that the record requires
+ * special interpretation.
+ *
+ * Netburst indicated via a bit in the flags field whether the branch
+ * was predicted; this is ignored.
+ *
+ * We use two levels of abstraction:
+ * - the raw data level defined here
+ * - an arch-independent level defined in ds.h
+ */
+
+enum bts_field {
+	bts_from,
+	bts_to,
+	bts_flags,
+
+	bts_qual = bts_from,
+	bts_jiffies = bts_to,
+	bts_pid = bts_flags,
+
+	bts_qual_mask = (bts_qual_max - 1),
+	bts_escape = ((unsigned long)-1 & ~bts_qual_mask)
+};
+
+static inline unsigned long bts_get(const char *base, enum bts_field field)
 {
-	return ds_write(task, record, size, ds_bts, /* force = */ 0);
+	base += (ds_cfg.sizeof_field * field);
+	return *(unsigned long *)base;
 }
 
-int ds_write_pebs(struct task_struct *task, const void *record, size_t size)
+static inline void bts_set(char *base, enum bts_field field, unsigned long val)
 {
-	return ds_write(task, record, size, ds_pebs, /* force = */ 0);
+	base += (ds_cfg.sizeof_field * field);;
+	(*(unsigned long *)base) = val;
 }
 
-int ds_unchecked_write_bts(struct task_struct *task,
-			   const void *record, size_t size)
+
+/*
+ * The raw BTS data is architecture dependent.
+ *
+ * For higher-level users, we give an arch-independent view.
+ * - ds.h defines struct bts_struct
+ * - bts_read translates one raw bts record into a bts_struct
+ * - bts_write translates one bts_struct into the raw format and
+ *   writes it into the top of the parameter tracer's buffer.
+ *
+ * return: bytes read/written on success; -Eerrno, otherwise
+ */
+static int bts_read(struct bts_tracer *tracer, const void *at,
+		    struct bts_struct *out)
 {
-	return ds_write(task, record, size, ds_bts, /* force = */ 1);
-}
-
-int ds_unchecked_write_pebs(struct task_struct *task,
-			    const void *record, size_t size)
-{
-	return ds_write(task, record, size, ds_pebs, /* force = */ 1);
-}
-
-static int ds_reset_or_clear(struct task_struct *task,
-			     enum ds_qualifier qual, int clear)
-{
-	struct ds_context *context;
-	unsigned long base, end;
-	int error;
-
-	context = ds_get_context(task);
-	error = ds_validate_access(context, qual);
-	if (error < 0)
-		goto out;
-
-	base = ds_get(context->ds, qual, ds_buffer_base);
-	end  = ds_get(context->ds, qual, ds_absolute_maximum);
-
-	if (clear)
-		memset((void *)base, 0, end - base);
-
-	ds_set(context->ds, qual, ds_index, base);
-
-	error = 0;
- out:
-	ds_put_context(context);
-	return error;
-}
-
-int ds_reset_bts(struct task_struct *task)
-{
-	return ds_reset_or_clear(task, ds_bts, /* clear = */ 0);
-}
-
-int ds_reset_pebs(struct task_struct *task)
-{
-	return ds_reset_or_clear(task, ds_pebs, /* clear = */ 0);
-}
-
-int ds_clear_bts(struct task_struct *task)
-{
-	return ds_reset_or_clear(task, ds_bts, /* clear = */ 1);
-}
-
-int ds_clear_pebs(struct task_struct *task)
-{
-	return ds_reset_or_clear(task, ds_pebs, /* clear = */ 1);
-}
-
-int ds_get_pebs_reset(struct task_struct *task, u64 *value)
-{
-	struct ds_context *context;
-	int error;
-
-	if (!value)
+	if (!tracer)
 		return -EINVAL;
 
-	context = ds_get_context(task);
-	error = ds_validate_access(context, ds_pebs);
-	if (error < 0)
-		goto out;
+	if (at < tracer->trace.ds.begin)
+		return -EINVAL;
 
-	*value = *(u64 *)(context->ds + (ds_cfg.sizeof_field * 8));
+	if (tracer->trace.ds.end < (at + tracer->trace.ds.size))
+		return -EINVAL;
 
-	error = 0;
- out:
-	ds_put_context(context);
-	return error;
+	memset(out, 0, sizeof(*out));
+	if ((bts_get(at, bts_qual) & ~bts_qual_mask) == bts_escape) {
+		out->qualifier = (bts_get(at, bts_qual) & bts_qual_mask);
+		out->variant.timestamp.jiffies = bts_get(at, bts_jiffies);
+		out->variant.timestamp.pid = bts_get(at, bts_pid);
+	} else {
+		out->qualifier = bts_branch;
+		out->variant.lbr.from = bts_get(at, bts_from);
+		out->variant.lbr.to   = bts_get(at, bts_to);
+
+		if (!out->variant.lbr.from && !out->variant.lbr.to)
+			out->qualifier = bts_invalid;
+	}
+
+	return ds_cfg.sizeof_rec[ds_bts];
 }
 
-int ds_set_pebs_reset(struct task_struct *task, u64 value)
+static int bts_write(struct bts_tracer *tracer, const struct bts_struct *in)
+{
+	unsigned char raw[MAX_SIZEOF_BTS];
+
+	if (!tracer)
+		return -EINVAL;
+
+	if (MAX_SIZEOF_BTS < ds_cfg.sizeof_rec[ds_bts])
+		return -EOVERFLOW;
+
+	switch (in->qualifier) {
+	case bts_invalid:
+		bts_set(raw, bts_from, 0);
+		bts_set(raw, bts_to, 0);
+		bts_set(raw, bts_flags, 0);
+		break;
+	case bts_branch:
+		bts_set(raw, bts_from, in->variant.lbr.from);
+		bts_set(raw, bts_to,   in->variant.lbr.to);
+		bts_set(raw, bts_flags, 0);
+		break;
+	case bts_task_arrives:
+	case bts_task_departs:
+		bts_set(raw, bts_qual, (bts_escape | in->qualifier));
+		bts_set(raw, bts_jiffies, in->variant.timestamp.jiffies);
+		bts_set(raw, bts_pid, in->variant.timestamp.pid);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ds_write(tracer->ds.context, ds_bts, raw,
+			ds_cfg.sizeof_rec[ds_bts]);
+}
+
+
+static void ds_write_config(struct ds_context *context,
+			    struct ds_trace *cfg, enum ds_qualifier qual)
+{
+	unsigned char *ds = context->ds;
+
+	ds_set(ds, qual, ds_buffer_base, (unsigned long)cfg->begin);
+	ds_set(ds, qual, ds_index, (unsigned long)cfg->top);
+	ds_set(ds, qual, ds_absolute_maximum, (unsigned long)cfg->end);
+	ds_set(ds, qual, ds_interrupt_threshold, (unsigned long)cfg->ith);
+}
+
+static void ds_read_config(struct ds_context *context,
+			   struct ds_trace *cfg, enum ds_qualifier qual)
+{
+	unsigned char *ds = context->ds;
+
+	cfg->begin = (void *)ds_get(ds, qual, ds_buffer_base);
+	cfg->top = (void *)ds_get(ds, qual, ds_index);
+	cfg->end = (void *)ds_get(ds, qual, ds_absolute_maximum);
+	cfg->ith = (void *)ds_get(ds, qual, ds_interrupt_threshold);
+}
+
+static void ds_init_ds_trace(struct ds_trace *trace, enum ds_qualifier qual,
+			     void *base, size_t size, size_t ith,
+			     unsigned int flags) {
+	unsigned long buffer, adj;
+
+	/* adjust the buffer address and size to meet alignment
+	 * constraints:
+	 * - buffer is double-word aligned
+	 * - size is multiple of record size
+	 *
+	 * We checked the size at the very beginning; we have enough
+	 * space to do the adjustment.
+	 */
+	buffer = (unsigned long)base;
+
+	adj = ALIGN(buffer, DS_ALIGNMENT) - buffer;
+	buffer += adj;
+	size   -= adj;
+
+	trace->n = size / ds_cfg.sizeof_rec[qual];
+	trace->size = ds_cfg.sizeof_rec[qual];
+
+	size = (trace->n * trace->size);
+
+	trace->begin = (void *)buffer;
+	trace->top = trace->begin;
+	trace->end = (void *)(buffer + size);
+	/* The value for 'no threshold' is -1, which will set the
+	 * threshold outside of the buffer, just like we want it.
+	 */
+	trace->ith = (void *)(buffer + size - ith);
+
+	trace->flags = flags;
+}
+
+
+static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace,
+		      enum ds_qualifier qual, struct task_struct *task,
+		      void *base, size_t size, size_t th, unsigned int flags)
 {
 	struct ds_context *context;
 	int error;
 
-	context = ds_get_context(task);
-	error = ds_validate_access(context, ds_pebs);
-	if (error < 0)
+	error = -EINVAL;
+	if (!base)
 		goto out;
 
-	*(u64 *)(context->ds + (ds_cfg.sizeof_field * 8)) = value;
+	/* we require some space to do alignment adjustments below */
+	error = -EINVAL;
+	if (size < (DS_ALIGNMENT + ds_cfg.sizeof_rec[qual]))
+		goto out;
+
+	if (th != (size_t)-1) {
+		th *= ds_cfg.sizeof_rec[qual];
+
+		error = -EINVAL;
+		if (size <= th)
+			goto out;
+	}
+
+	tracer->buffer = base;
+	tracer->size = size;
+
+	error = -ENOMEM;
+	context = ds_get_context(task);
+	if (!context)
+		goto out;
+	tracer->context = context;
+
+	ds_init_ds_trace(trace, qual, base, size, th, flags);
 
 	error = 0;
  out:
-	ds_put_context(context);
 	return error;
 }
 
-static const struct ds_configuration ds_cfg_var = {
-	.sizeof_ds    = sizeof(long) * 12,
-	.sizeof_field = sizeof(long),
-	.sizeof_rec[ds_bts]   = sizeof(long) * 3,
+struct bts_tracer *ds_request_bts(struct task_struct *task,
+				  void *base, size_t size,
+				  bts_ovfl_callback_t ovfl, size_t th,
+				  unsigned int flags)
+{
+	struct bts_tracer *tracer;
+	unsigned long irq;
+	int error;
+
+	error = -EOPNOTSUPP;
+	if (!ds_cfg.ctl[dsf_bts])
+		goto out;
+
+	/* buffer overflow notification is not yet implemented */
+	error = -EOPNOTSUPP;
+	if (ovfl)
+		goto out;
+
+	error = -ENOMEM;
+	tracer = kzalloc(sizeof(*tracer), GFP_KERNEL);
+	if (!tracer)
+		goto out;
+	tracer->ovfl = ovfl;
+
+	error = ds_request(&tracer->ds, &tracer->trace.ds,
+			   ds_bts, task, base, size, th, flags);
+	if (error < 0)
+		goto out_tracer;
+
+
+	spin_lock_irqsave(&ds_lock, irq);
+
+	error = -EPERM;
+	if (!check_tracer(task))
+		goto out_unlock;
+	get_tracer(task);
+
+	error = -EPERM;
+	if (tracer->ds.context->bts_master)
+		goto out_put_tracer;
+	tracer->ds.context->bts_master = tracer;
+
+	spin_unlock_irqrestore(&ds_lock, irq);
+
+
+	tracer->trace.read  = bts_read;
+	tracer->trace.write = bts_write;
+
+	ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_bts);
+	ds_resume_bts(tracer);
+
+	return tracer;
+
+ out_put_tracer:
+	put_tracer(task);
+ out_unlock:
+	spin_unlock_irqrestore(&ds_lock, irq);
+	ds_put_context(tracer->ds.context);
+ out_tracer:
+	kfree(tracer);
+ out:
+	return ERR_PTR(error);
+}
+
+struct pebs_tracer *ds_request_pebs(struct task_struct *task,
+				    void *base, size_t size,
+				    pebs_ovfl_callback_t ovfl, size_t th,
+				    unsigned int flags)
+{
+	struct pebs_tracer *tracer;
+	unsigned long irq;
+	int error;
+
+	/* buffer overflow notification is not yet implemented */
+	error = -EOPNOTSUPP;
+	if (ovfl)
+		goto out;
+
+	error = -ENOMEM;
+	tracer = kzalloc(sizeof(*tracer), GFP_KERNEL);
+	if (!tracer)
+		goto out;
+	tracer->ovfl = ovfl;
+
+	error = ds_request(&tracer->ds, &tracer->trace.ds,
+			   ds_pebs, task, base, size, th, flags);
+	if (error < 0)
+		goto out_tracer;
+
+	spin_lock_irqsave(&ds_lock, irq);
+
+	error = -EPERM;
+	if (!check_tracer(task))
+		goto out_unlock;
+	get_tracer(task);
+
+	error = -EPERM;
+	if (tracer->ds.context->pebs_master)
+		goto out_put_tracer;
+	tracer->ds.context->pebs_master = tracer;
+
+	spin_unlock_irqrestore(&ds_lock, irq);
+
+	ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_bts);
+	ds_resume_pebs(tracer);
+
+	return tracer;
+
+ out_put_tracer:
+	put_tracer(task);
+ out_unlock:
+	spin_unlock_irqrestore(&ds_lock, irq);
+	ds_put_context(tracer->ds.context);
+ out_tracer:
+	kfree(tracer);
+ out:
+	return ERR_PTR(error);
+}
+
+void ds_release_bts(struct bts_tracer *tracer)
+{
+	if (!tracer)
+		return;
+
+	ds_suspend_bts(tracer);
+
+	WARN_ON_ONCE(tracer->ds.context->bts_master != tracer);
+	tracer->ds.context->bts_master = NULL;
+
+	put_tracer(tracer->ds.context->task);
+	ds_put_context(tracer->ds.context);
+
+	kfree(tracer);
+}
+
+void ds_suspend_bts(struct bts_tracer *tracer)
+{
+	struct task_struct *task;
+
+	if (!tracer)
+		return;
+
+	task = tracer->ds.context->task;
+
+	if (!task || (task == current))
+		update_debugctlmsr(get_debugctlmsr() & ~BTS_CONTROL);
+
+	if (task) {
+		task->thread.debugctlmsr &= ~BTS_CONTROL;
+
+		if (!task->thread.debugctlmsr)
+			clear_tsk_thread_flag(task, TIF_DEBUGCTLMSR);
+	}
+}
+
+void ds_resume_bts(struct bts_tracer *tracer)
+{
+	struct task_struct *task;
+	unsigned long control;
+
+	if (!tracer)
+		return;
+
+	task = tracer->ds.context->task;
+
+	control = ds_cfg.ctl[dsf_bts];
+	if (!(tracer->trace.ds.flags & BTS_KERNEL))
+		control |= ds_cfg.ctl[dsf_bts_kernel];
+	if (!(tracer->trace.ds.flags & BTS_USER))
+		control |= ds_cfg.ctl[dsf_bts_user];
+
+	if (task) {
+		task->thread.debugctlmsr |= control;
+		set_tsk_thread_flag(task, TIF_DEBUGCTLMSR);
+	}
+
+	if (!task || (task == current))
+		update_debugctlmsr(get_debugctlmsr() | control);
+}
+
+void ds_release_pebs(struct pebs_tracer *tracer)
+{
+	if (!tracer)
+		return;
+
+	ds_suspend_pebs(tracer);
+
+	WARN_ON_ONCE(tracer->ds.context->pebs_master != tracer);
+	tracer->ds.context->pebs_master = NULL;
+
+	put_tracer(tracer->ds.context->task);
+	ds_put_context(tracer->ds.context);
+
+	kfree(tracer);
+}
+
+void ds_suspend_pebs(struct pebs_tracer *tracer)
+{
+
+}
+
+void ds_resume_pebs(struct pebs_tracer *tracer)
+{
+
+}
+
+const struct bts_trace *ds_read_bts(struct bts_tracer *tracer)
+{
+	if (!tracer)
+		return NULL;
+
+	ds_read_config(tracer->ds.context, &tracer->trace.ds, ds_bts);
+	return &tracer->trace;
+}
+
+const struct pebs_trace *ds_read_pebs(struct pebs_tracer *tracer)
+{
+	if (!tracer)
+		return NULL;
+
+	ds_read_config(tracer->ds.context, &tracer->trace.ds, ds_pebs);
+	tracer->trace.reset_value =
+		*(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8));
+
+	return &tracer->trace;
+}
+
+int ds_reset_bts(struct bts_tracer *tracer)
+{
+	if (!tracer)
+		return -EINVAL;
+
+	tracer->trace.ds.top = tracer->trace.ds.begin;
+
+	ds_set(tracer->ds.context->ds, ds_bts, ds_index,
+	       (unsigned long)tracer->trace.ds.top);
+
+	return 0;
+}
+
+int ds_reset_pebs(struct pebs_tracer *tracer)
+{
+	if (!tracer)
+		return -EINVAL;
+
+	tracer->trace.ds.top = tracer->trace.ds.begin;
+
+	ds_set(tracer->ds.context->ds, ds_bts, ds_index,
+	       (unsigned long)tracer->trace.ds.top);
+
+	return 0;
+}
+
+int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value)
+{
+	if (!tracer)
+		return -EINVAL;
+
+	*(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8)) = value;
+
+	return 0;
+}
+
+static const struct ds_configuration ds_cfg_netburst = {
+	.name = "netburst",
+	.ctl[dsf_bts]		= (1 << 2) | (1 << 3),
+	.ctl[dsf_bts_kernel]	= (1 << 5),
+	.ctl[dsf_bts_user]	= (1 << 6),
+
+	.sizeof_field		= sizeof(long),
+	.sizeof_rec[ds_bts]	= sizeof(long) * 3,
 #ifdef __i386__
-	.sizeof_rec[ds_pebs]  = sizeof(long) * 10
+	.sizeof_rec[ds_pebs]	= sizeof(long) * 10,
 #else
-	.sizeof_rec[ds_pebs]  = sizeof(long) * 18
+	.sizeof_rec[ds_pebs]	= sizeof(long) * 18,
 #endif
 };
-static const struct ds_configuration ds_cfg_64 = {
-	.sizeof_ds    = 8 * 12,
-	.sizeof_field = 8,
-	.sizeof_rec[ds_bts]   = 8 * 3,
+static const struct ds_configuration ds_cfg_pentium_m = {
+	.name = "pentium m",
+	.ctl[dsf_bts]		= (1 << 6) | (1 << 7),
+
+	.sizeof_field		= sizeof(long),
+	.sizeof_rec[ds_bts]	= sizeof(long) * 3,
 #ifdef __i386__
-	.sizeof_rec[ds_pebs]  = 8 * 10
+	.sizeof_rec[ds_pebs]	= sizeof(long) * 10,
 #else
-	.sizeof_rec[ds_pebs]  = 8 * 18
+	.sizeof_rec[ds_pebs]	= sizeof(long) * 18,
 #endif
 };
+static const struct ds_configuration ds_cfg_core2 = {
+	.name = "core 2",
+	.ctl[dsf_bts]		= (1 << 6) | (1 << 7),
+	.ctl[dsf_bts_kernel]	= (1 << 9),
+	.ctl[dsf_bts_user]	= (1 << 10),
+
+	.sizeof_field		= 8,
+	.sizeof_rec[ds_bts]	= 8 * 3,
+	.sizeof_rec[ds_pebs]	= 8 * 18,
+};
 
-static inline void
+static void
 ds_configure(const struct ds_configuration *cfg)
 {
+	memset(&ds_cfg, 0, sizeof(ds_cfg));
 	ds_cfg = *cfg;
+
+	printk(KERN_INFO "[ds] using %s configuration\n", ds_cfg.name);
+
+	if (!cpu_has_bts) {
+		ds_cfg.ctl[dsf_bts] = 0;
+		printk(KERN_INFO "[ds] bts not available\n");
+	}
+	if (!cpu_has_pebs)
+		printk(KERN_INFO "[ds] pebs not available\n");
+
+	WARN_ON_ONCE(MAX_SIZEOF_DS < (12 * ds_cfg.sizeof_field));
 }
 
 void __cpuinit ds_init_intel(struct cpuinfo_x86 *c)
@@ -847,16 +949,15 @@
 	switch (c->x86) {
 	case 0x6:
 		switch (c->x86_model) {
+		case 0 ... 0xC:
+			/* sorry, don't know about them */
+			break;
 		case 0xD:
 		case 0xE: /* Pentium M */
-			ds_configure(&ds_cfg_var);
+			ds_configure(&ds_cfg_pentium_m);
 			break;
-		case 0xF: /* Core2 */
-		case 0x1C: /* Atom */
-			ds_configure(&ds_cfg_64);
-			break;
-		default:
-			/* sorry, don't know about them */
+		default: /* Core2, Atom, ... */
+			ds_configure(&ds_cfg_core2);
 			break;
 		}
 		break;
@@ -865,7 +966,7 @@
 		case 0x0:
 		case 0x1:
 		case 0x2: /* Netburst */
-			ds_configure(&ds_cfg_var);
+			ds_configure(&ds_cfg_netburst);
 			break;
 		default:
 			/* sorry, don't know about them */
@@ -878,12 +979,52 @@
 	}
 }
 
-void ds_free(struct ds_context *context)
+/*
+ * Change the DS configuration from tracing prev to tracing next.
+ */
+void ds_switch_to(struct task_struct *prev, struct task_struct *next)
 {
-	/* This is called when the task owning the parameter context
-	 * is dying. There should not be any user of that context left
-	 * to disturb us, anymore. */
-	unsigned long leftovers = context->count;
-	while (leftovers--)
-		ds_put_context(context);
+	struct ds_context *prev_ctx = prev->thread.ds_ctx;
+	struct ds_context *next_ctx = next->thread.ds_ctx;
+
+	if (prev_ctx) {
+		update_debugctlmsr(0);
+
+		if (prev_ctx->bts_master &&
+		    (prev_ctx->bts_master->trace.ds.flags & BTS_TIMESTAMPS)) {
+			struct bts_struct ts = {
+				.qualifier = bts_task_departs,
+				.variant.timestamp.jiffies = jiffies_64,
+				.variant.timestamp.pid = prev->pid
+			};
+			bts_write(prev_ctx->bts_master, &ts);
+		}
+	}
+
+	if (next_ctx) {
+		if (next_ctx->bts_master &&
+		    (next_ctx->bts_master->trace.ds.flags & BTS_TIMESTAMPS)) {
+			struct bts_struct ts = {
+				.qualifier = bts_task_arrives,
+				.variant.timestamp.jiffies = jiffies_64,
+				.variant.timestamp.pid = next->pid
+			};
+			bts_write(next_ctx->bts_master, &ts);
+		}
+
+		wrmsrl(MSR_IA32_DS_AREA, (unsigned long)next_ctx->ds);
+	}
+
+	update_debugctlmsr(next->thread.debugctlmsr);
+}
+
+void ds_copy_thread(struct task_struct *tsk, struct task_struct *father)
+{
+	clear_tsk_thread_flag(tsk, TIF_DS_AREA_MSR);
+	tsk->thread.ds_ctx = NULL;
+}
+
+void ds_exit_thread(struct task_struct *tsk)
+{
+	WARN_ON(tsk->thread.ds_ctx);
 }
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
new file mode 100644
index 0000000..6b1f6f6
--- /dev/null
+++ b/arch/x86/kernel/dumpstack.c
@@ -0,0 +1,351 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ */
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/hardirq.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/kexec.h>
+#include <linux/bug.h>
+#include <linux/nmi.h>
+#include <linux/sysfs.h>
+
+#include <asm/stacktrace.h>
+
+#include "dumpstack.h"
+
+int panic_on_unrecovered_nmi;
+unsigned int code_bytes = 64;
+int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
+static int die_counter;
+
+void printk_address(unsigned long address, int reliable)
+{
+	printk(" [<%p>] %s%pS\n", (void *) address,
+			reliable ? "" : "? ", (void *) address);
+}
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+static void
+print_ftrace_graph_addr(unsigned long addr, void *data,
+			const struct stacktrace_ops *ops,
+			struct thread_info *tinfo, int *graph)
+{
+	struct task_struct *task = tinfo->task;
+	unsigned long ret_addr;
+	int index = task->curr_ret_stack;
+
+	if (addr != (unsigned long)return_to_handler)
+		return;
+
+	if (!task->ret_stack || index < *graph)
+		return;
+
+	index -= *graph;
+	ret_addr = task->ret_stack[index].ret;
+
+	ops->address(data, ret_addr, 1);
+
+	(*graph)++;
+}
+#else
+static inline void
+print_ftrace_graph_addr(unsigned long addr, void *data,
+			const struct stacktrace_ops *ops,
+			struct thread_info *tinfo, int *graph)
+{ }
+#endif
+
+/*
+ * x86-64 can have up to three kernel stacks:
+ * process stack
+ * interrupt stack
+ * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
+ */
+
+static inline int valid_stack_ptr(struct thread_info *tinfo,
+			void *p, unsigned int size, void *end)
+{
+	void *t = tinfo;
+	if (end) {
+		if (p < end && p >= (end-THREAD_SIZE))
+			return 1;
+		else
+			return 0;
+	}
+	return p > t && p < t + THREAD_SIZE - size;
+}
+
+unsigned long
+print_context_stack(struct thread_info *tinfo,
+		unsigned long *stack, unsigned long bp,
+		const struct stacktrace_ops *ops, void *data,
+		unsigned long *end, int *graph)
+{
+	struct stack_frame *frame = (struct stack_frame *)bp;
+
+	while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
+		unsigned long addr;
+
+		addr = *stack;
+		if (__kernel_text_address(addr)) {
+			if ((unsigned long) stack == bp + sizeof(long)) {
+				ops->address(data, addr, 1);
+				frame = frame->next_frame;
+				bp = (unsigned long) frame;
+			} else {
+				ops->address(data, addr, bp == 0);
+			}
+			print_ftrace_graph_addr(addr, data, ops, tinfo, graph);
+		}
+		stack++;
+	}
+	return bp;
+}
+
+
+static void
+print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+	printk(data);
+	print_symbol(msg, symbol);
+	printk("\n");
+}
+
+static void print_trace_warning(void *data, char *msg)
+{
+	printk("%s%s\n", (char *)data, msg);
+}
+
+static int print_trace_stack(void *data, char *name)
+{
+	printk("%s <%s> ", (char *)data, name);
+	return 0;
+}
+
+/*
+ * Print one address/symbol entries per line.
+ */
+static void print_trace_address(void *data, unsigned long addr, int reliable)
+{
+	touch_nmi_watchdog();
+	printk(data);
+	printk_address(addr, reliable);
+}
+
+static const struct stacktrace_ops print_trace_ops = {
+	.warning = print_trace_warning,
+	.warning_symbol = print_trace_warning_symbol,
+	.stack = print_trace_stack,
+	.address = print_trace_address,
+};
+
+void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *stack, unsigned long bp, char *log_lvl)
+{
+	printk("%sCall Trace:\n", log_lvl);
+	dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
+}
+
+void show_trace(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *stack, unsigned long bp)
+{
+	show_trace_log_lvl(task, regs, stack, bp, "");
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+	show_stack_log_lvl(task, NULL, sp, 0, "");
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+	unsigned long bp = 0;
+	unsigned long stack;
+
+#ifdef CONFIG_FRAME_POINTER
+	if (!bp)
+		get_bp(bp);
+#endif
+
+	printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+		current->pid, current->comm, print_tainted(),
+		init_utsname()->release,
+		(int)strcspn(init_utsname()->version, " "),
+		init_utsname()->version);
+	show_trace(NULL, NULL, &stack, bp);
+}
+EXPORT_SYMBOL(dump_stack);
+
+static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
+static int die_owner = -1;
+static unsigned int die_nest_count;
+
+unsigned __kprobes long oops_begin(void)
+{
+	int cpu;
+	unsigned long flags;
+
+	oops_enter();
+
+	/* racy, but better than risking deadlock. */
+	raw_local_irq_save(flags);
+	cpu = smp_processor_id();
+	if (!__raw_spin_trylock(&die_lock)) {
+		if (cpu == die_owner)
+			/* nested oops. should stop eventually */;
+		else
+			__raw_spin_lock(&die_lock);
+	}
+	die_nest_count++;
+	die_owner = cpu;
+	console_verbose();
+	bust_spinlocks(1);
+	return flags;
+}
+
+void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
+{
+	if (regs && kexec_should_crash(current))
+		crash_kexec(regs);
+
+	bust_spinlocks(0);
+	die_owner = -1;
+	add_taint(TAINT_DIE);
+	die_nest_count--;
+	if (!die_nest_count)
+		/* Nest count reaches zero, release the lock. */
+		__raw_spin_unlock(&die_lock);
+	raw_local_irq_restore(flags);
+	oops_exit();
+
+	if (!signr)
+		return;
+	if (in_interrupt())
+		panic("Fatal exception in interrupt");
+	if (panic_on_oops)
+		panic("Fatal exception");
+	do_exit(signr);
+}
+
+int __kprobes __die(const char *str, struct pt_regs *regs, long err)
+{
+#ifdef CONFIG_X86_32
+	unsigned short ss;
+	unsigned long sp;
+#endif
+	printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+	printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+	printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+	printk("DEBUG_PAGEALLOC");
+#endif
+	printk("\n");
+	sysfs_printk_last_file();
+	if (notify_die(DIE_OOPS, str, regs, err,
+			current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+		return 1;
+
+	show_registers(regs);
+#ifdef CONFIG_X86_32
+	sp = (unsigned long) (&regs->sp);
+	savesegment(ss, ss);
+	if (user_mode(regs)) {
+		sp = regs->sp;
+		ss = regs->ss & 0xffff;
+	}
+	printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
+	print_symbol("%s", regs->ip);
+	printk(" SS:ESP %04x:%08lx\n", ss, sp);
+#else
+	/* Executive summary in case the oops scrolled away */
+	printk(KERN_ALERT "RIP ");
+	printk_address(regs->ip, 1);
+	printk(" RSP <%016lx>\n", regs->sp);
+#endif
+	return 0;
+}
+
+/*
+ * This is gone through when something in the kernel has done something bad
+ * and is about to be terminated:
+ */
+void die(const char *str, struct pt_regs *regs, long err)
+{
+	unsigned long flags = oops_begin();
+	int sig = SIGSEGV;
+
+	if (!user_mode_vm(regs))
+		report_bug(regs->ip, regs);
+
+	if (__die(str, regs, err))
+		sig = 0;
+	oops_end(flags, regs, sig);
+}
+
+void notrace __kprobes
+die_nmi(char *str, struct pt_regs *regs, int do_panic)
+{
+	unsigned long flags;
+
+	if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+		return;
+
+	/*
+	 * We are in trouble anyway, lets at least try
+	 * to get a message out.
+	 */
+	flags = oops_begin();
+	printk(KERN_EMERG "%s", str);
+	printk(" on CPU%d, ip %08lx, registers:\n",
+		smp_processor_id(), regs->ip);
+	show_registers(regs);
+	oops_end(flags, regs, 0);
+	if (do_panic || panic_on_oops)
+		panic("Non maskable interrupt");
+	nmi_exit();
+	local_irq_enable();
+	do_exit(SIGBUS);
+}
+
+static int __init oops_setup(char *s)
+{
+	if (!s)
+		return -EINVAL;
+	if (!strcmp(s, "panic"))
+		panic_on_oops = 1;
+	return 0;
+}
+early_param("oops", oops_setup);
+
+static int __init kstack_setup(char *s)
+{
+	if (!s)
+		return -EINVAL;
+	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+	return 0;
+}
+early_param("kstack", kstack_setup);
+
+static int __init code_bytes_setup(char *s)
+{
+	code_bytes = simple_strtoul(s, NULL, 0);
+	if (code_bytes > 8192)
+		code_bytes = 8192;
+
+	return 1;
+}
+__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/dumpstack.h b/arch/x86/kernel/dumpstack.h
new file mode 100644
index 0000000..da87590b
--- /dev/null
+++ b/arch/x86/kernel/dumpstack.h
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ */
+
+#ifndef DUMPSTACK_H
+#define DUMPSTACK_H
+
+#ifdef CONFIG_X86_32
+#define STACKSLOTS_PER_LINE 8
+#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
+#else
+#define STACKSLOTS_PER_LINE 4
+#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
+#endif
+
+extern unsigned long
+print_context_stack(struct thread_info *tinfo,
+		unsigned long *stack, unsigned long bp,
+		const struct stacktrace_ops *ops, void *data,
+		unsigned long *end, int *graph);
+
+extern void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *stack, unsigned long bp, char *log_lvl);
+
+extern void
+show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+		unsigned long *sp, unsigned long bp, char *log_lvl);
+
+extern unsigned int code_bytes;
+extern int kstack_depth_to_print;
+
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+	struct stack_frame *next_frame;
+	unsigned long return_address;
+};
+#endif
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index b361475..d593cd1 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -17,69 +17,14 @@
 
 #include <asm/stacktrace.h>
 
-#define STACKSLOTS_PER_LINE 8
-#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
-
-int panic_on_unrecovered_nmi;
-int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
-static unsigned int code_bytes = 64;
-static int die_counter;
-
-void printk_address(unsigned long address, int reliable)
-{
-	printk(" [<%p>] %s%pS\n", (void *) address,
-			reliable ? "" : "? ", (void *) address);
-}
-
-static inline int valid_stack_ptr(struct thread_info *tinfo,
-			void *p, unsigned int size, void *end)
-{
-	void *t = tinfo;
-	if (end) {
-		if (p < end && p >= (end-THREAD_SIZE))
-			return 1;
-		else
-			return 0;
-	}
-	return p > t && p < t + THREAD_SIZE - size;
-}
-
-/* The form of the top of the frame on the stack */
-struct stack_frame {
-	struct stack_frame *next_frame;
-	unsigned long return_address;
-};
-
-static inline unsigned long
-print_context_stack(struct thread_info *tinfo,
-		unsigned long *stack, unsigned long bp,
-		const struct stacktrace_ops *ops, void *data,
-		unsigned long *end)
-{
-	struct stack_frame *frame = (struct stack_frame *)bp;
-
-	while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
-		unsigned long addr;
-
-		addr = *stack;
-		if (__kernel_text_address(addr)) {
-			if ((unsigned long) stack == bp + sizeof(long)) {
-				ops->address(data, addr, 1);
-				frame = frame->next_frame;
-				bp = (unsigned long) frame;
-			} else {
-				ops->address(data, addr, bp == 0);
-			}
-		}
-		stack++;
-	}
-	return bp;
-}
+#include "dumpstack.h"
 
 void dump_trace(struct task_struct *task, struct pt_regs *regs,
 		unsigned long *stack, unsigned long bp,
 		const struct stacktrace_ops *ops, void *data)
 {
+	int graph = 0;
+
 	if (!task)
 		task = current;
 
@@ -107,7 +52,8 @@
 
 		context = (struct thread_info *)
 			((unsigned long)stack & (~(THREAD_SIZE - 1)));
-		bp = print_context_stack(context, stack, bp, ops, data, NULL);
+		bp = print_context_stack(context, stack, bp, ops,
+					 data, NULL, &graph);
 
 		stack = (unsigned long *)context->previous_esp;
 		if (!stack)
@@ -119,57 +65,7 @@
 }
 EXPORT_SYMBOL(dump_trace);
 
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
-	printk(data);
-	print_symbol(msg, symbol);
-	printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
-	printk("%s%s\n", (char *)data, msg);
-}
-
-static int print_trace_stack(void *data, char *name)
-{
-	printk("%s <%s> ", (char *)data, name);
-	return 0;
-}
-
-/*
- * Print one address/symbol entries per line.
- */
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
-	touch_nmi_watchdog();
-	printk(data);
-	printk_address(addr, reliable);
-}
-
-static const struct stacktrace_ops print_trace_ops = {
-	.warning = print_trace_warning,
-	.warning_symbol = print_trace_warning_symbol,
-	.stack = print_trace_stack,
-	.address = print_trace_address,
-};
-
-static void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
-		unsigned long *stack, unsigned long bp, char *log_lvl)
-{
-	printk("%sCall Trace:\n", log_lvl);
-	dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
-}
-
-void show_trace(struct task_struct *task, struct pt_regs *regs,
-		unsigned long *stack, unsigned long bp)
-{
-	show_trace_log_lvl(task, regs, stack, bp, "");
-}
-
-static void
+void
 show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
 		unsigned long *sp, unsigned long bp, char *log_lvl)
 {
@@ -196,33 +92,6 @@
 	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
 
-void show_stack(struct task_struct *task, unsigned long *sp)
-{
-	show_stack_log_lvl(task, NULL, sp, 0, "");
-}
-
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
-	unsigned long bp = 0;
-	unsigned long stack;
-
-#ifdef CONFIG_FRAME_POINTER
-	if (!bp)
-		get_bp(bp);
-#endif
-
-	printk("Pid: %d, comm: %.20s %s %s %.*s\n",
-		current->pid, current->comm, print_tainted(),
-		init_utsname()->release,
-		(int)strcspn(init_utsname()->version, " "),
-		init_utsname()->version);
-	show_trace(NULL, NULL, &stack, bp);
-}
-
-EXPORT_SYMBOL(dump_stack);
 
 void show_registers(struct pt_regs *regs)
 {
@@ -283,167 +152,3 @@
 	return ud2 == 0x0b0f;
 }
 
-static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
-static int die_owner = -1;
-static unsigned int die_nest_count;
-
-unsigned __kprobes long oops_begin(void)
-{
-	unsigned long flags;
-
-	oops_enter();
-
-	if (die_owner != raw_smp_processor_id()) {
-		console_verbose();
-		raw_local_irq_save(flags);
-		__raw_spin_lock(&die_lock);
-		die_owner = smp_processor_id();
-		die_nest_count = 0;
-		bust_spinlocks(1);
-	} else {
-		raw_local_irq_save(flags);
-	}
-	die_nest_count++;
-	return flags;
-}
-
-void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
-{
-	bust_spinlocks(0);
-	die_owner = -1;
-	add_taint(TAINT_DIE);
-	__raw_spin_unlock(&die_lock);
-	raw_local_irq_restore(flags);
-
-	if (!regs)
-		return;
-
-	if (kexec_should_crash(current))
-		crash_kexec(regs);
-	if (in_interrupt())
-		panic("Fatal exception in interrupt");
-	if (panic_on_oops)
-		panic("Fatal exception");
-	oops_exit();
-	do_exit(signr);
-}
-
-int __kprobes __die(const char *str, struct pt_regs *regs, long err)
-{
-	unsigned short ss;
-	unsigned long sp;
-
-	printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
-	printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
-	printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
-	printk("DEBUG_PAGEALLOC");
-#endif
-	printk("\n");
-	sysfs_printk_last_file();
-	if (notify_die(DIE_OOPS, str, regs, err,
-			current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
-		return 1;
-
-	show_registers(regs);
-	/* Executive summary in case the oops scrolled away */
-	sp = (unsigned long) (&regs->sp);
-	savesegment(ss, ss);
-	if (user_mode(regs)) {
-		sp = regs->sp;
-		ss = regs->ss & 0xffff;
-	}
-	printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
-	print_symbol("%s", regs->ip);
-	printk(" SS:ESP %04x:%08lx\n", ss, sp);
-	return 0;
-}
-
-/*
- * This is gone through when something in the kernel has done something bad
- * and is about to be terminated:
- */
-void die(const char *str, struct pt_regs *regs, long err)
-{
-	unsigned long flags = oops_begin();
-
-	if (die_nest_count < 3) {
-		report_bug(regs->ip, regs);
-
-		if (__die(str, regs, err))
-			regs = NULL;
-	} else {
-		printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
-	}
-
-	oops_end(flags, regs, SIGSEGV);
-}
-
-static DEFINE_SPINLOCK(nmi_print_lock);
-
-void notrace __kprobes
-die_nmi(char *str, struct pt_regs *regs, int do_panic)
-{
-	if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
-		return;
-
-	spin_lock(&nmi_print_lock);
-	/*
-	* We are in trouble anyway, lets at least try
-	* to get a message out:
-	*/
-	bust_spinlocks(1);
-	printk(KERN_EMERG "%s", str);
-	printk(" on CPU%d, ip %08lx, registers:\n",
-		smp_processor_id(), regs->ip);
-	show_registers(regs);
-	if (do_panic)
-		panic("Non maskable interrupt");
-	console_silent();
-	spin_unlock(&nmi_print_lock);
-
-	/*
-	 * If we are in kernel we are probably nested up pretty bad
-	 * and might aswell get out now while we still can:
-	 */
-	if (!user_mode_vm(regs)) {
-		current->thread.trap_no = 2;
-		crash_kexec(regs);
-	}
-
-	bust_spinlocks(0);
-	do_exit(SIGSEGV);
-}
-
-static int __init oops_setup(char *s)
-{
-	if (!s)
-		return -EINVAL;
-	if (!strcmp(s, "panic"))
-		panic_on_oops = 1;
-	return 0;
-}
-early_param("oops", oops_setup);
-
-static int __init kstack_setup(char *s)
-{
-	if (!s)
-		return -EINVAL;
-	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
-	return 0;
-}
-early_param("kstack", kstack_setup);
-
-static int __init code_bytes_setup(char *s)
-{
-	code_bytes = simple_strtoul(s, NULL, 0);
-	if (code_bytes > 8192)
-		code_bytes = 8192;
-
-	return 1;
-}
-__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 96a5db7..c302d07 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -17,19 +17,7 @@
 
 #include <asm/stacktrace.h>
 
-#define STACKSLOTS_PER_LINE 4
-#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
-
-int panic_on_unrecovered_nmi;
-int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
-static unsigned int code_bytes = 64;
-static int die_counter;
-
-void printk_address(unsigned long address, int reliable)
-{
-	printk(" [<%p>] %s%pS\n", (void *) address,
-			reliable ? "" : "? ", (void *) address);
-}
+#include "dumpstack.h"
 
 static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
 					unsigned *usedp, char **idp)
@@ -113,51 +101,6 @@
  * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
  */
 
-static inline int valid_stack_ptr(struct thread_info *tinfo,
-			void *p, unsigned int size, void *end)
-{
-	void *t = tinfo;
-	if (end) {
-		if (p < end && p >= (end-THREAD_SIZE))
-			return 1;
-		else
-			return 0;
-	}
-	return p > t && p < t + THREAD_SIZE - size;
-}
-
-/* The form of the top of the frame on the stack */
-struct stack_frame {
-	struct stack_frame *next_frame;
-	unsigned long return_address;
-};
-
-static inline unsigned long
-print_context_stack(struct thread_info *tinfo,
-		unsigned long *stack, unsigned long bp,
-		const struct stacktrace_ops *ops, void *data,
-		unsigned long *end)
-{
-	struct stack_frame *frame = (struct stack_frame *)bp;
-
-	while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
-		unsigned long addr;
-
-		addr = *stack;
-		if (__kernel_text_address(addr)) {
-			if ((unsigned long) stack == bp + sizeof(long)) {
-				ops->address(data, addr, 1);
-				frame = frame->next_frame;
-				bp = (unsigned long) frame;
-			} else {
-				ops->address(data, addr, bp == 0);
-			}
-		}
-		stack++;
-	}
-	return bp;
-}
-
 void dump_trace(struct task_struct *task, struct pt_regs *regs,
 		unsigned long *stack, unsigned long bp,
 		const struct stacktrace_ops *ops, void *data)
@@ -166,6 +109,7 @@
 	unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
 	unsigned used = 0;
 	struct thread_info *tinfo;
+	int graph = 0;
 
 	if (!task)
 		task = current;
@@ -206,7 +150,7 @@
 				break;
 
 			bp = print_context_stack(tinfo, stack, bp, ops,
-							data, estack_end);
+						 data, estack_end, &graph);
 			ops->stack(data, "<EOE>");
 			/*
 			 * We link to the next stack via the
@@ -225,7 +169,7 @@
 				if (ops->stack(data, "IRQ") < 0)
 					break;
 				bp = print_context_stack(tinfo, stack, bp,
-						ops, data, irqstack_end);
+					ops, data, irqstack_end, &graph);
 				/*
 				 * We link to the next stack (which would be
 				 * the process stack normally) the last
@@ -243,62 +187,12 @@
 	/*
 	 * This handles the process stack:
 	 */
-	bp = print_context_stack(tinfo, stack, bp, ops, data, NULL);
+	bp = print_context_stack(tinfo, stack, bp, ops, data, NULL, &graph);
 	put_cpu();
 }
 EXPORT_SYMBOL(dump_trace);
 
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
-	printk(data);
-	print_symbol(msg, symbol);
-	printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
-	printk("%s%s\n", (char *)data, msg);
-}
-
-static int print_trace_stack(void *data, char *name)
-{
-	printk("%s <%s> ", (char *)data, name);
-	return 0;
-}
-
-/*
- * Print one address/symbol entries per line.
- */
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
-	touch_nmi_watchdog();
-	printk(data);
-	printk_address(addr, reliable);
-}
-
-static const struct stacktrace_ops print_trace_ops = {
-	.warning = print_trace_warning,
-	.warning_symbol = print_trace_warning_symbol,
-	.stack = print_trace_stack,
-	.address = print_trace_address,
-};
-
-static void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
-		unsigned long *stack, unsigned long bp, char *log_lvl)
-{
-	printk("%sCall Trace:\n", log_lvl);
-	dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
-}
-
-void show_trace(struct task_struct *task, struct pt_regs *regs,
-		unsigned long *stack, unsigned long bp)
-{
-	show_trace_log_lvl(task, regs, stack, bp, "");
-}
-
-static void
+void
 show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
 		unsigned long *sp, unsigned long bp, char *log_lvl)
 {
@@ -342,33 +236,6 @@
 	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
 
-void show_stack(struct task_struct *task, unsigned long *sp)
-{
-	show_stack_log_lvl(task, NULL, sp, 0, "");
-}
-
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
-	unsigned long bp = 0;
-	unsigned long stack;
-
-#ifdef CONFIG_FRAME_POINTER
-	if (!bp)
-		get_bp(bp);
-#endif
-
-	printk("Pid: %d, comm: %.20s %s %s %.*s\n",
-		current->pid, current->comm, print_tainted(),
-		init_utsname()->release,
-		(int)strcspn(init_utsname()->version, " "),
-		init_utsname()->version);
-	show_trace(NULL, NULL, &stack, bp);
-}
-EXPORT_SYMBOL(dump_stack);
-
 void show_registers(struct pt_regs *regs)
 {
 	int i;
@@ -429,147 +296,3 @@
 	return ud2 == 0x0b0f;
 }
 
-static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
-static int die_owner = -1;
-static unsigned int die_nest_count;
-
-unsigned __kprobes long oops_begin(void)
-{
-	int cpu;
-	unsigned long flags;
-
-	oops_enter();
-
-	/* racy, but better than risking deadlock. */
-	raw_local_irq_save(flags);
-	cpu = smp_processor_id();
-	if (!__raw_spin_trylock(&die_lock)) {
-		if (cpu == die_owner)
-			/* nested oops. should stop eventually */;
-		else
-			__raw_spin_lock(&die_lock);
-	}
-	die_nest_count++;
-	die_owner = cpu;
-	console_verbose();
-	bust_spinlocks(1);
-	return flags;
-}
-
-void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
-{
-	die_owner = -1;
-	bust_spinlocks(0);
-	die_nest_count--;
-	if (!die_nest_count)
-		/* Nest count reaches zero, release the lock. */
-		__raw_spin_unlock(&die_lock);
-	raw_local_irq_restore(flags);
-	if (!regs) {
-		oops_exit();
-		return;
-	}
-	if (in_interrupt())
-		panic("Fatal exception in interrupt");
-	if (panic_on_oops)
-		panic("Fatal exception");
-	oops_exit();
-	do_exit(signr);
-}
-
-int __kprobes __die(const char *str, struct pt_regs *regs, long err)
-{
-	printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
-	printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
-	printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
-	printk("DEBUG_PAGEALLOC");
-#endif
-	printk("\n");
-	sysfs_printk_last_file();
-	if (notify_die(DIE_OOPS, str, regs, err,
-			current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
-		return 1;
-
-	show_registers(regs);
-	add_taint(TAINT_DIE);
-	/* Executive summary in case the oops scrolled away */
-	printk(KERN_ALERT "RIP ");
-	printk_address(regs->ip, 1);
-	printk(" RSP <%016lx>\n", regs->sp);
-	if (kexec_should_crash(current))
-		crash_kexec(regs);
-	return 0;
-}
-
-void die(const char *str, struct pt_regs *regs, long err)
-{
-	unsigned long flags = oops_begin();
-
-	if (!user_mode(regs))
-		report_bug(regs->ip, regs);
-
-	if (__die(str, regs, err))
-		regs = NULL;
-	oops_end(flags, regs, SIGSEGV);
-}
-
-notrace __kprobes void
-die_nmi(char *str, struct pt_regs *regs, int do_panic)
-{
-	unsigned long flags;
-
-	if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
-		return;
-
-	flags = oops_begin();
-	/*
-	 * We are in trouble anyway, lets at least try
-	 * to get a message out.
-	 */
-	printk(KERN_EMERG "%s", str);
-	printk(" on CPU%d, ip %08lx, registers:\n",
-		smp_processor_id(), regs->ip);
-	show_registers(regs);
-	if (kexec_should_crash(current))
-		crash_kexec(regs);
-	if (do_panic || panic_on_oops)
-		panic("Non maskable interrupt");
-	oops_end(flags, NULL, SIGBUS);
-	nmi_exit();
-	local_irq_enable();
-	do_exit(SIGBUS);
-}
-
-static int __init oops_setup(char *s)
-{
-	if (!s)
-		return -EINVAL;
-	if (!strcmp(s, "panic"))
-		panic_on_oops = 1;
-	return 0;
-}
-early_param("oops", oops_setup);
-
-static int __init kstack_setup(char *s)
-{
-	if (!s)
-		return -EINVAL;
-	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
-	return 0;
-}
-early_param("kstack", kstack_setup);
-
-static int __init code_bytes_setup(char *s)
-{
-	code_bytes = simple_strtoul(s, NULL, 0);
-	if (code_bytes > 8192)
-		code_bytes = 8192;
-
-	return 1;
-}
-__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 7aafeb5..65a1394 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -677,22 +677,6 @@
 };
 static struct early_res early_res[MAX_EARLY_RES] __initdata = {
 	{ 0, PAGE_SIZE, "BIOS data page" },	/* BIOS data page */
-#if defined(CONFIG_X86_64) && defined(CONFIG_X86_TRAMPOLINE)
-	{ TRAMPOLINE_BASE, TRAMPOLINE_BASE + 2 * PAGE_SIZE, "TRAMPOLINE" },
-#endif
-#if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
-	/*
-	 * But first pinch a few for the stack/trampoline stuff
-	 * FIXME: Don't need the extra page at 4K, but need to fix
-	 * trampoline before removing it. (see the GDT stuff)
-	 */
-	{ PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE" },
-	/*
-	 * Has to be in very low memory so we can execute
-	 * real-mode AP code.
-	 */
-	{ TRAMPOLINE_BASE, TRAMPOLINE_BASE + PAGE_SIZE, "TRAMPOLINE" },
-#endif
 	{}
 };
 
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index 1b894b7..744aa7f 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -17,6 +17,7 @@
 #include <asm/io_apic.h>
 #include <asm/apic.h>
 #include <asm/iommu.h>
+#include <asm/gart.h>
 
 static void __init fix_hypertransport_config(int num, int slot, int func)
 {
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index 34ad997..23b138e 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -875,49 +875,6 @@
 };
 #endif
 
-/* Console interface to a host file on AMD's SimNow! */
-
-static int simnow_fd;
-
-enum {
-	MAGIC1 = 0xBACCD00A,
-	MAGIC2 = 0xCA110000,
-	XOPEN = 5,
-	XWRITE = 4,
-};
-
-static noinline long simnow(long cmd, long a, long b, long c)
-{
-	long ret;
-
-	asm volatile("cpuid" :
-		     "=a" (ret) :
-		     "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2));
-	return ret;
-}
-
-static void __init simnow_init(char *str)
-{
-	char *fn = "klog";
-
-	if (*str == '=')
-		fn = ++str;
-	/* error ignored */
-	simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644);
-}
-
-static void simnow_write(struct console *con, const char *s, unsigned n)
-{
-	simnow(XWRITE, simnow_fd, (unsigned long)s, n);
-}
-
-static struct console simnow_console = {
-	.name =		"simnow",
-	.write =	simnow_write,
-	.flags =	CON_PRINTBUFFER,
-	.index =	-1,
-};
-
 /* Direct interface for emergencies */
 static struct console *early_console = &early_vga_console;
 static int __initdata early_console_initialized;
@@ -960,10 +917,6 @@
 		max_ypos = boot_params.screen_info.orig_video_lines;
 		current_ypos = boot_params.screen_info.orig_y;
 		early_console = &early_vga_console;
-	} else if (!strncmp(buf, "simnow", 6)) {
-		simnow_init(buf + 6);
-		early_console = &simnow_console;
-		keep_early = 1;
 #ifdef CONFIG_EARLY_PRINTK_DBGP
 	} else if (!strncmp(buf, "dbgp", 4)) {
 		if (early_dbgp_init(buf+4) < 0)
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 28b597e..d6f0490 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -619,28 +619,37 @@
 27:;
 
 /*
- * Build the entry stubs and pointer table with
- * some assembler magic.
+ * Build the entry stubs and pointer table with some assembler magic.
+ * We pack 7 stubs into a single 32-byte chunk, which will fit in a
+ * single cache line on all modern x86 implementations.
  */
-.section .rodata,"a"
+.section .init.rodata,"a"
 ENTRY(interrupt)
 .text
-
+	.p2align 5
+	.p2align CONFIG_X86_L1_CACHE_SHIFT
 ENTRY(irq_entries_start)
 	RING0_INT_FRAME
-vector=0
-.rept NR_VECTORS
-	ALIGN
- .if vector
+vector=FIRST_EXTERNAL_VECTOR
+.rept (NR_VECTORS-FIRST_EXTERNAL_VECTOR+6)/7
+	.balign 32
+  .rept	7
+    .if vector < NR_VECTORS
+      .if vector <> FIRST_EXTERNAL_VECTOR
 	CFI_ADJUST_CFA_OFFSET -4
- .endif
-1:	pushl $~(vector)
+      .endif
+1:	pushl $(~vector+0x80)	/* Note: always in signed byte range */
 	CFI_ADJUST_CFA_OFFSET 4
-	jmp common_interrupt
- .previous
+      .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6
+	jmp 2f
+      .endif
+      .previous
 	.long 1b
- .text
+      .text
 vector=vector+1
+    .endif
+  .endr
+2:	jmp common_interrupt
 .endr
 END(irq_entries_start)
 
@@ -652,8 +661,9 @@
  * the CPU automatically disables interrupts when executing an IRQ vector,
  * so IRQ-flags tracing has to follow that:
  */
-	ALIGN
+	.p2align CONFIG_X86_L1_CACHE_SHIFT
 common_interrupt:
+	addl $-0x80,(%esp)	/* Adjust vector into the [-256,-1] range */
 	SAVE_ALL
 	TRACE_IRQS_OFF
 	movl %esp,%eax
@@ -678,65 +688,6 @@
 /* The include is where all of the SMP etc. interrupts come from */
 #include "entry_arch.h"
 
-KPROBE_ENTRY(page_fault)
-	RING0_EC_FRAME
-	pushl $do_page_fault
-	CFI_ADJUST_CFA_OFFSET 4
-	ALIGN
-error_code:
-	/* the function address is in %fs's slot on the stack */
-	pushl %es
-	CFI_ADJUST_CFA_OFFSET 4
-	/*CFI_REL_OFFSET es, 0*/
-	pushl %ds
-	CFI_ADJUST_CFA_OFFSET 4
-	/*CFI_REL_OFFSET ds, 0*/
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
-	CFI_REL_OFFSET eax, 0
-	pushl %ebp
-	CFI_ADJUST_CFA_OFFSET 4
-	CFI_REL_OFFSET ebp, 0
-	pushl %edi
-	CFI_ADJUST_CFA_OFFSET 4
-	CFI_REL_OFFSET edi, 0
-	pushl %esi
-	CFI_ADJUST_CFA_OFFSET 4
-	CFI_REL_OFFSET esi, 0
-	pushl %edx
-	CFI_ADJUST_CFA_OFFSET 4
-	CFI_REL_OFFSET edx, 0
-	pushl %ecx
-	CFI_ADJUST_CFA_OFFSET 4
-	CFI_REL_OFFSET ecx, 0
-	pushl %ebx
-	CFI_ADJUST_CFA_OFFSET 4
-	CFI_REL_OFFSET ebx, 0
-	cld
-	pushl %fs
-	CFI_ADJUST_CFA_OFFSET 4
-	/*CFI_REL_OFFSET fs, 0*/
-	movl $(__KERNEL_PERCPU), %ecx
-	movl %ecx, %fs
-	UNWIND_ESPFIX_STACK
-	popl %ecx
-	CFI_ADJUST_CFA_OFFSET -4
-	/*CFI_REGISTER es, ecx*/
-	movl PT_FS(%esp), %edi		# get the function address
-	movl PT_ORIG_EAX(%esp), %edx	# get the error code
-	movl $-1, PT_ORIG_EAX(%esp)	# no syscall to restart
-	mov  %ecx, PT_FS(%esp)
-	/*CFI_REL_OFFSET fs, ES*/
-	movl $(__USER_DS), %ecx
-	movl %ecx, %ds
-	movl %ecx, %es
-	TRACE_IRQS_OFF
-	movl %esp,%eax			# pt_regs pointer
-	call *%edi
-	jmp ret_from_exception
-	CFI_ENDPROC
-KPROBE_END(page_fault)
-
 ENTRY(coprocessor_error)
 	RING0_INT_FRAME
 	pushl $0
@@ -767,140 +718,6 @@
 	CFI_ENDPROC
 END(device_not_available)
 
-/*
- * Debug traps and NMI can happen at the one SYSENTER instruction
- * that sets up the real kernel stack. Check here, since we can't
- * allow the wrong stack to be used.
- *
- * "TSS_sysenter_sp0+12" is because the NMI/debug handler will have
- * already pushed 3 words if it hits on the sysenter instruction:
- * eflags, cs and eip.
- *
- * We just load the right stack, and push the three (known) values
- * by hand onto the new stack - while updating the return eip past
- * the instruction that would have done it for sysenter.
- */
-#define FIX_STACK(offset, ok, label)		\
-	cmpw $__KERNEL_CS,4(%esp);		\
-	jne ok;					\
-label:						\
-	movl TSS_sysenter_sp0+offset(%esp),%esp;	\
-	CFI_DEF_CFA esp, 0;			\
-	CFI_UNDEFINED eip;			\
-	pushfl;					\
-	CFI_ADJUST_CFA_OFFSET 4;		\
-	pushl $__KERNEL_CS;			\
-	CFI_ADJUST_CFA_OFFSET 4;		\
-	pushl $sysenter_past_esp;		\
-	CFI_ADJUST_CFA_OFFSET 4;		\
-	CFI_REL_OFFSET eip, 0
-
-KPROBE_ENTRY(debug)
-	RING0_INT_FRAME
-	cmpl $ia32_sysenter_target,(%esp)
-	jne debug_stack_correct
-	FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
-debug_stack_correct:
-	pushl $-1			# mark this as an int
-	CFI_ADJUST_CFA_OFFSET 4
-	SAVE_ALL
-	TRACE_IRQS_OFF
-	xorl %edx,%edx			# error code 0
-	movl %esp,%eax			# pt_regs pointer
-	call do_debug
-	jmp ret_from_exception
-	CFI_ENDPROC
-KPROBE_END(debug)
-
-/*
- * NMI is doubly nasty. It can happen _while_ we're handling
- * a debug fault, and the debug fault hasn't yet been able to
- * clear up the stack. So we first check whether we got  an
- * NMI on the sysenter entry path, but after that we need to
- * check whether we got an NMI on the debug path where the debug
- * fault happened on the sysenter path.
- */
-KPROBE_ENTRY(nmi)
-	RING0_INT_FRAME
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
-	movl %ss, %eax
-	cmpw $__ESPFIX_SS, %ax
-	popl %eax
-	CFI_ADJUST_CFA_OFFSET -4
-	je nmi_espfix_stack
-	cmpl $ia32_sysenter_target,(%esp)
-	je nmi_stack_fixup
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
-	movl %esp,%eax
-	/* Do not access memory above the end of our stack page,
-	 * it might not exist.
-	 */
-	andl $(THREAD_SIZE-1),%eax
-	cmpl $(THREAD_SIZE-20),%eax
-	popl %eax
-	CFI_ADJUST_CFA_OFFSET -4
-	jae nmi_stack_correct
-	cmpl $ia32_sysenter_target,12(%esp)
-	je nmi_debug_stack_check
-nmi_stack_correct:
-	/* We have a RING0_INT_FRAME here */
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
-	SAVE_ALL
-	TRACE_IRQS_OFF
-	xorl %edx,%edx		# zero error code
-	movl %esp,%eax		# pt_regs pointer
-	call do_nmi
-	jmp restore_nocheck_notrace
-	CFI_ENDPROC
-
-nmi_stack_fixup:
-	RING0_INT_FRAME
-	FIX_STACK(12,nmi_stack_correct, 1)
-	jmp nmi_stack_correct
-
-nmi_debug_stack_check:
-	/* We have a RING0_INT_FRAME here */
-	cmpw $__KERNEL_CS,16(%esp)
-	jne nmi_stack_correct
-	cmpl $debug,(%esp)
-	jb nmi_stack_correct
-	cmpl $debug_esp_fix_insn,(%esp)
-	ja nmi_stack_correct
-	FIX_STACK(24,nmi_stack_correct, 1)
-	jmp nmi_stack_correct
-
-nmi_espfix_stack:
-	/* We have a RING0_INT_FRAME here.
-	 *
-	 * create the pointer to lss back
-	 */
-	pushl %ss
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl %esp
-	CFI_ADJUST_CFA_OFFSET 4
-	addw $4, (%esp)
-	/* copy the iret frame of 12 bytes */
-	.rept 3
-	pushl 16(%esp)
-	CFI_ADJUST_CFA_OFFSET 4
-	.endr
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
-	SAVE_ALL
-	TRACE_IRQS_OFF
-	FIXUP_ESPFIX_STACK		# %eax == %esp
-	xorl %edx,%edx			# zero error code
-	call do_nmi
-	RESTORE_REGS
-	lss 12+4(%esp), %esp		# back to espfix stack
-	CFI_ADJUST_CFA_OFFSET -24
-	jmp irq_return
-	CFI_ENDPROC
-KPROBE_END(nmi)
-
 #ifdef CONFIG_PARAVIRT
 ENTRY(native_iret)
 	iret
@@ -916,19 +733,6 @@
 END(native_irq_enable_sysexit)
 #endif
 
-KPROBE_ENTRY(int3)
-	RING0_INT_FRAME
-	pushl $-1			# mark this as an int
-	CFI_ADJUST_CFA_OFFSET 4
-	SAVE_ALL
-	TRACE_IRQS_OFF
-	xorl %edx,%edx		# zero error code
-	movl %esp,%eax		# pt_regs pointer
-	call do_int3
-	jmp ret_from_exception
-	CFI_ENDPROC
-KPROBE_END(int3)
-
 ENTRY(overflow)
 	RING0_INT_FRAME
 	pushl $0
@@ -993,14 +797,6 @@
 	CFI_ENDPROC
 END(stack_segment)
 
-KPROBE_ENTRY(general_protection)
-	RING0_EC_FRAME
-	pushl $do_general_protection
-	CFI_ADJUST_CFA_OFFSET 4
-	jmp error_code
-	CFI_ENDPROC
-KPROBE_END(general_protection)
-
 ENTRY(alignment_check)
 	RING0_EC_FRAME
 	pushl $do_alignment_check
@@ -1051,6 +847,7 @@
 	push %eax
 	CFI_ADJUST_CFA_OFFSET 4
 	call do_exit
+	ud2			# padding for call trace
 	CFI_ENDPROC
 ENDPROC(kernel_thread_helper)
 
@@ -1157,6 +954,9 @@
 END(mcount)
 
 ENTRY(ftrace_caller)
+	cmpl $0, function_trace_stop
+	jne  ftrace_stub
+
 	pushl %eax
 	pushl %ecx
 	pushl %edx
@@ -1171,6 +971,11 @@
 	popl %edx
 	popl %ecx
 	popl %eax
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+.globl ftrace_graph_call
+ftrace_graph_call:
+	jmp ftrace_stub
+#endif
 
 .globl ftrace_stub
 ftrace_stub:
@@ -1180,8 +985,18 @@
 #else /* ! CONFIG_DYNAMIC_FTRACE */
 
 ENTRY(mcount)
+	cmpl $0, function_trace_stop
+	jne  ftrace_stub
+
 	cmpl $ftrace_stub, ftrace_trace_function
 	jnz trace
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	cmpl $ftrace_stub, ftrace_graph_return
+	jnz ftrace_graph_caller
+
+	cmpl $ftrace_graph_entry_stub, ftrace_graph_entry
+	jnz ftrace_graph_caller
+#endif
 .globl ftrace_stub
 ftrace_stub:
 	ret
@@ -1200,13 +1015,268 @@
 	popl %edx
 	popl %ecx
 	popl %eax
-
 	jmp ftrace_stub
 END(mcount)
 #endif /* CONFIG_DYNAMIC_FTRACE */
 #endif /* CONFIG_FUNCTION_TRACER */
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ENTRY(ftrace_graph_caller)
+	cmpl $0, function_trace_stop
+	jne ftrace_stub
+
+	pushl %eax
+	pushl %ecx
+	pushl %edx
+	movl 0xc(%esp), %edx
+	lea 0x4(%ebp), %eax
+	subl $MCOUNT_INSN_SIZE, %edx
+	call prepare_ftrace_return
+	popl %edx
+	popl %ecx
+	popl %eax
+	ret
+END(ftrace_graph_caller)
+
+.globl return_to_handler
+return_to_handler:
+	pushl $0
+	pushl %eax
+	pushl %ecx
+	pushl %edx
+	call ftrace_return_to_handler
+	movl %eax, 0xc(%esp)
+	popl %edx
+	popl %ecx
+	popl %eax
+	ret
+#endif
+
 .section .rodata,"a"
 #include "syscall_table_32.S"
 
 syscall_table_size=(.-sys_call_table)
+
+/*
+ * Some functions should be protected against kprobes
+ */
+	.pushsection .kprobes.text, "ax"
+
+ENTRY(page_fault)
+	RING0_EC_FRAME
+	pushl $do_page_fault
+	CFI_ADJUST_CFA_OFFSET 4
+	ALIGN
+error_code:
+	/* the function address is in %fs's slot on the stack */
+	pushl %es
+	CFI_ADJUST_CFA_OFFSET 4
+	/*CFI_REL_OFFSET es, 0*/
+	pushl %ds
+	CFI_ADJUST_CFA_OFFSET 4
+	/*CFI_REL_OFFSET ds, 0*/
+	pushl %eax
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET eax, 0
+	pushl %ebp
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET ebp, 0
+	pushl %edi
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET edi, 0
+	pushl %esi
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET esi, 0
+	pushl %edx
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET edx, 0
+	pushl %ecx
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET ecx, 0
+	pushl %ebx
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET ebx, 0
+	cld
+	pushl %fs
+	CFI_ADJUST_CFA_OFFSET 4
+	/*CFI_REL_OFFSET fs, 0*/
+	movl $(__KERNEL_PERCPU), %ecx
+	movl %ecx, %fs
+	UNWIND_ESPFIX_STACK
+	popl %ecx
+	CFI_ADJUST_CFA_OFFSET -4
+	/*CFI_REGISTER es, ecx*/
+	movl PT_FS(%esp), %edi		# get the function address
+	movl PT_ORIG_EAX(%esp), %edx	# get the error code
+	movl $-1, PT_ORIG_EAX(%esp)	# no syscall to restart
+	mov  %ecx, PT_FS(%esp)
+	/*CFI_REL_OFFSET fs, ES*/
+	movl $(__USER_DS), %ecx
+	movl %ecx, %ds
+	movl %ecx, %es
+	TRACE_IRQS_OFF
+	movl %esp,%eax			# pt_regs pointer
+	call *%edi
+	jmp ret_from_exception
+	CFI_ENDPROC
+END(page_fault)
+
+/*
+ * Debug traps and NMI can happen at the one SYSENTER instruction
+ * that sets up the real kernel stack. Check here, since we can't
+ * allow the wrong stack to be used.
+ *
+ * "TSS_sysenter_sp0+12" is because the NMI/debug handler will have
+ * already pushed 3 words if it hits on the sysenter instruction:
+ * eflags, cs and eip.
+ *
+ * We just load the right stack, and push the three (known) values
+ * by hand onto the new stack - while updating the return eip past
+ * the instruction that would have done it for sysenter.
+ */
+#define FIX_STACK(offset, ok, label)		\
+	cmpw $__KERNEL_CS,4(%esp);		\
+	jne ok;					\
+label:						\
+	movl TSS_sysenter_sp0+offset(%esp),%esp;	\
+	CFI_DEF_CFA esp, 0;			\
+	CFI_UNDEFINED eip;			\
+	pushfl;					\
+	CFI_ADJUST_CFA_OFFSET 4;		\
+	pushl $__KERNEL_CS;			\
+	CFI_ADJUST_CFA_OFFSET 4;		\
+	pushl $sysenter_past_esp;		\
+	CFI_ADJUST_CFA_OFFSET 4;		\
+	CFI_REL_OFFSET eip, 0
+
+ENTRY(debug)
+	RING0_INT_FRAME
+	cmpl $ia32_sysenter_target,(%esp)
+	jne debug_stack_correct
+	FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
+debug_stack_correct:
+	pushl $-1			# mark this as an int
+	CFI_ADJUST_CFA_OFFSET 4
+	SAVE_ALL
+	TRACE_IRQS_OFF
+	xorl %edx,%edx			# error code 0
+	movl %esp,%eax			# pt_regs pointer
+	call do_debug
+	jmp ret_from_exception
+	CFI_ENDPROC
+END(debug)
+
+/*
+ * NMI is doubly nasty. It can happen _while_ we're handling
+ * a debug fault, and the debug fault hasn't yet been able to
+ * clear up the stack. So we first check whether we got  an
+ * NMI on the sysenter entry path, but after that we need to
+ * check whether we got an NMI on the debug path where the debug
+ * fault happened on the sysenter path.
+ */
+ENTRY(nmi)
+	RING0_INT_FRAME
+	pushl %eax
+	CFI_ADJUST_CFA_OFFSET 4
+	movl %ss, %eax
+	cmpw $__ESPFIX_SS, %ax
+	popl %eax
+	CFI_ADJUST_CFA_OFFSET -4
+	je nmi_espfix_stack
+	cmpl $ia32_sysenter_target,(%esp)
+	je nmi_stack_fixup
+	pushl %eax
+	CFI_ADJUST_CFA_OFFSET 4
+	movl %esp,%eax
+	/* Do not access memory above the end of our stack page,
+	 * it might not exist.
+	 */
+	andl $(THREAD_SIZE-1),%eax
+	cmpl $(THREAD_SIZE-20),%eax
+	popl %eax
+	CFI_ADJUST_CFA_OFFSET -4
+	jae nmi_stack_correct
+	cmpl $ia32_sysenter_target,12(%esp)
+	je nmi_debug_stack_check
+nmi_stack_correct:
+	/* We have a RING0_INT_FRAME here */
+	pushl %eax
+	CFI_ADJUST_CFA_OFFSET 4
+	SAVE_ALL
+	TRACE_IRQS_OFF
+	xorl %edx,%edx		# zero error code
+	movl %esp,%eax		# pt_regs pointer
+	call do_nmi
+	jmp restore_nocheck_notrace
+	CFI_ENDPROC
+
+nmi_stack_fixup:
+	RING0_INT_FRAME
+	FIX_STACK(12,nmi_stack_correct, 1)
+	jmp nmi_stack_correct
+
+nmi_debug_stack_check:
+	/* We have a RING0_INT_FRAME here */
+	cmpw $__KERNEL_CS,16(%esp)
+	jne nmi_stack_correct
+	cmpl $debug,(%esp)
+	jb nmi_stack_correct
+	cmpl $debug_esp_fix_insn,(%esp)
+	ja nmi_stack_correct
+	FIX_STACK(24,nmi_stack_correct, 1)
+	jmp nmi_stack_correct
+
+nmi_espfix_stack:
+	/* We have a RING0_INT_FRAME here.
+	 *
+	 * create the pointer to lss back
+	 */
+	pushl %ss
+	CFI_ADJUST_CFA_OFFSET 4
+	pushl %esp
+	CFI_ADJUST_CFA_OFFSET 4
+	addw $4, (%esp)
+	/* copy the iret frame of 12 bytes */
+	.rept 3
+	pushl 16(%esp)
+	CFI_ADJUST_CFA_OFFSET 4
+	.endr
+	pushl %eax
+	CFI_ADJUST_CFA_OFFSET 4
+	SAVE_ALL
+	TRACE_IRQS_OFF
+	FIXUP_ESPFIX_STACK		# %eax == %esp
+	xorl %edx,%edx			# zero error code
+	call do_nmi
+	RESTORE_REGS
+	lss 12+4(%esp), %esp		# back to espfix stack
+	CFI_ADJUST_CFA_OFFSET -24
+	jmp irq_return
+	CFI_ENDPROC
+END(nmi)
+
+ENTRY(int3)
+	RING0_INT_FRAME
+	pushl $-1			# mark this as an int
+	CFI_ADJUST_CFA_OFFSET 4
+	SAVE_ALL
+	TRACE_IRQS_OFF
+	xorl %edx,%edx		# zero error code
+	movl %esp,%eax		# pt_regs pointer
+	call do_int3
+	jmp ret_from_exception
+	CFI_ENDPROC
+END(int3)
+
+ENTRY(general_protection)
+	RING0_EC_FRAME
+	pushl $do_general_protection
+	CFI_ADJUST_CFA_OFFSET 4
+	jmp error_code
+	CFI_ENDPROC
+END(general_protection)
+
+/*
+ * End of kprobes section
+ */
+	.popsection
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index b86f332..e28c7a9 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -11,15 +11,15 @@
  *
  * NOTE: This code handles signal-recognition, which happens every time
  * after an interrupt and after each system call.
- * 
- * Normal syscalls and interrupts don't save a full stack frame, this is 
+ *
+ * Normal syscalls and interrupts don't save a full stack frame, this is
  * only done for syscall tracing, signals or fork/exec et.al.
- * 
- * A note on terminology:	 
- * - top of stack: Architecture defined interrupt frame from SS to RIP 
- * at the top of the kernel process stack.	
+ *
+ * A note on terminology:
+ * - top of stack: Architecture defined interrupt frame from SS to RIP
+ * at the top of the kernel process stack.
  * - partial stack frame: partially saved registers upto R11.
- * - full stack frame: Like partial stack frame, but all register saved. 
+ * - full stack frame: Like partial stack frame, but all register saved.
  *
  * Some macro usage:
  * - CFI macros are used to generate dwarf2 unwind information for better
@@ -60,7 +60,6 @@
 #define __AUDIT_ARCH_LE	   0x40000000
 
 	.code64
-
 #ifdef CONFIG_FUNCTION_TRACER
 #ifdef CONFIG_DYNAMIC_FTRACE
 ENTRY(mcount)
@@ -68,16 +67,10 @@
 END(mcount)
 
 ENTRY(ftrace_caller)
+	cmpl $0, function_trace_stop
+	jne  ftrace_stub
 
-	/* taken from glibc */
-	subq $0x38, %rsp
-	movq %rax, (%rsp)
-	movq %rcx, 8(%rsp)
-	movq %rdx, 16(%rsp)
-	movq %rsi, 24(%rsp)
-	movq %rdi, 32(%rsp)
-	movq %r8, 40(%rsp)
-	movq %r9, 48(%rsp)
+	MCOUNT_SAVE_FRAME
 
 	movq 0x38(%rsp), %rdi
 	movq 8(%rbp), %rsi
@@ -87,14 +80,13 @@
 ftrace_call:
 	call ftrace_stub
 
-	movq 48(%rsp), %r9
-	movq 40(%rsp), %r8
-	movq 32(%rsp), %rdi
-	movq 24(%rsp), %rsi
-	movq 16(%rsp), %rdx
-	movq 8(%rsp), %rcx
-	movq (%rsp), %rax
-	addq $0x38, %rsp
+	MCOUNT_RESTORE_FRAME
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+.globl ftrace_graph_call
+ftrace_graph_call:
+	jmp ftrace_stub
+#endif
 
 .globl ftrace_stub
 ftrace_stub:
@@ -103,22 +95,26 @@
 
 #else /* ! CONFIG_DYNAMIC_FTRACE */
 ENTRY(mcount)
+	cmpl $0, function_trace_stop
+	jne  ftrace_stub
+
 	cmpq $ftrace_stub, ftrace_trace_function
 	jnz trace
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	cmpq $ftrace_stub, ftrace_graph_return
+	jnz ftrace_graph_caller
+
+	cmpq $ftrace_graph_entry_stub, ftrace_graph_entry
+	jnz ftrace_graph_caller
+#endif
+
 .globl ftrace_stub
 ftrace_stub:
 	retq
 
 trace:
-	/* taken from glibc */
-	subq $0x38, %rsp
-	movq %rax, (%rsp)
-	movq %rcx, 8(%rsp)
-	movq %rdx, 16(%rsp)
-	movq %rsi, 24(%rsp)
-	movq %rdi, 32(%rsp)
-	movq %r8, 40(%rsp)
-	movq %r9, 48(%rsp)
+	MCOUNT_SAVE_FRAME
 
 	movq 0x38(%rsp), %rdi
 	movq 8(%rbp), %rsi
@@ -126,6 +122,51 @@
 
 	call   *ftrace_trace_function
 
+	MCOUNT_RESTORE_FRAME
+
+	jmp ftrace_stub
+END(mcount)
+#endif /* CONFIG_DYNAMIC_FTRACE */
+#endif /* CONFIG_FUNCTION_TRACER */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ENTRY(ftrace_graph_caller)
+	cmpl $0, function_trace_stop
+	jne ftrace_stub
+
+	MCOUNT_SAVE_FRAME
+
+	leaq 8(%rbp), %rdi
+	movq 0x38(%rsp), %rsi
+	subq $MCOUNT_INSN_SIZE, %rsi
+
+	call	prepare_ftrace_return
+
+	MCOUNT_RESTORE_FRAME
+
+	retq
+END(ftrace_graph_caller)
+
+
+.globl return_to_handler
+return_to_handler:
+	subq  $80, %rsp
+
+	movq %rax, (%rsp)
+	movq %rcx, 8(%rsp)
+	movq %rdx, 16(%rsp)
+	movq %rsi, 24(%rsp)
+	movq %rdi, 32(%rsp)
+	movq %r8, 40(%rsp)
+	movq %r9, 48(%rsp)
+	movq %r10, 56(%rsp)
+	movq %r11, 64(%rsp)
+
+	call ftrace_return_to_handler
+
+	movq %rax, 72(%rsp)
+	movq 64(%rsp), %r11
+	movq 56(%rsp), %r10
 	movq 48(%rsp), %r9
 	movq 40(%rsp), %r8
 	movq 32(%rsp), %rdi
@@ -133,16 +174,14 @@
 	movq 16(%rsp), %rdx
 	movq 8(%rsp), %rcx
 	movq (%rsp), %rax
-	addq $0x38, %rsp
+	addq $72, %rsp
+	retq
+#endif
 
-	jmp ftrace_stub
-END(mcount)
-#endif /* CONFIG_DYNAMIC_FTRACE */
-#endif /* CONFIG_FUNCTION_TRACER */
 
 #ifndef CONFIG_PREEMPT
 #define retint_kernel retint_restore_args
-#endif	
+#endif
 
 #ifdef CONFIG_PARAVIRT
 ENTRY(native_usergs_sysret64)
@@ -161,29 +200,29 @@
 .endm
 
 /*
- * C code is not supposed to know about undefined top of stack. Every time 
- * a C function with an pt_regs argument is called from the SYSCALL based 
+ * C code is not supposed to know about undefined top of stack. Every time
+ * a C function with an pt_regs argument is called from the SYSCALL based
  * fast path FIXUP_TOP_OF_STACK is needed.
  * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
  * manipulation.
- */        	
-		
-	/* %rsp:at FRAMEEND */ 
-	.macro FIXUP_TOP_OF_STACK tmp
-	movq	%gs:pda_oldrsp,\tmp
-	movq  	\tmp,RSP(%rsp)
-	movq    $__USER_DS,SS(%rsp)
-	movq    $__USER_CS,CS(%rsp)
-	movq 	$-1,RCX(%rsp)
-	movq	R11(%rsp),\tmp  /* get eflags */
-	movq	\tmp,EFLAGS(%rsp)
+ */
+
+	/* %rsp:at FRAMEEND */
+	.macro FIXUP_TOP_OF_STACK tmp offset=0
+	movq %gs:pda_oldrsp,\tmp
+	movq \tmp,RSP+\offset(%rsp)
+	movq $__USER_DS,SS+\offset(%rsp)
+	movq $__USER_CS,CS+\offset(%rsp)
+	movq $-1,RCX+\offset(%rsp)
+	movq R11+\offset(%rsp),\tmp  /* get eflags */
+	movq \tmp,EFLAGS+\offset(%rsp)
 	.endm
 
-	.macro RESTORE_TOP_OF_STACK tmp,offset=0
-	movq   RSP-\offset(%rsp),\tmp
-	movq   \tmp,%gs:pda_oldrsp
-	movq   EFLAGS-\offset(%rsp),\tmp
-	movq   \tmp,R11-\offset(%rsp)
+	.macro RESTORE_TOP_OF_STACK tmp offset=0
+	movq RSP+\offset(%rsp),\tmp
+	movq \tmp,%gs:pda_oldrsp
+	movq EFLAGS+\offset(%rsp),\tmp
+	movq \tmp,R11+\offset(%rsp)
 	.endm
 
 	.macro FAKE_STACK_FRAME child_rip
@@ -195,7 +234,7 @@
 	pushq %rax /* rsp */
 	CFI_ADJUST_CFA_OFFSET	8
 	CFI_REL_OFFSET	rsp,0
-	pushq $(1<<9) /* eflags - interrupts on */
+	pushq $X86_EFLAGS_IF /* eflags - interrupts on */
 	CFI_ADJUST_CFA_OFFSET	8
 	/*CFI_REL_OFFSET	rflags,0*/
 	pushq $__KERNEL_CS /* cs */
@@ -213,62 +252,184 @@
 	CFI_ADJUST_CFA_OFFSET	-(6*8)
 	.endm
 
-	.macro	CFI_DEFAULT_STACK start=1
-	.if \start
-	CFI_STARTPROC	simple
-	CFI_SIGNAL_FRAME
-	CFI_DEF_CFA	rsp,SS+8
-	.else
-	CFI_DEF_CFA_OFFSET SS+8
-	.endif
-	CFI_REL_OFFSET	r15,R15
-	CFI_REL_OFFSET	r14,R14
-	CFI_REL_OFFSET	r13,R13
-	CFI_REL_OFFSET	r12,R12
-	CFI_REL_OFFSET	rbp,RBP
-	CFI_REL_OFFSET	rbx,RBX
-	CFI_REL_OFFSET	r11,R11
-	CFI_REL_OFFSET	r10,R10
-	CFI_REL_OFFSET	r9,R9
-	CFI_REL_OFFSET	r8,R8
-	CFI_REL_OFFSET	rax,RAX
-	CFI_REL_OFFSET	rcx,RCX
-	CFI_REL_OFFSET	rdx,RDX
-	CFI_REL_OFFSET	rsi,RSI
-	CFI_REL_OFFSET	rdi,RDI
-	CFI_REL_OFFSET	rip,RIP
-	/*CFI_REL_OFFSET	cs,CS*/
-	/*CFI_REL_OFFSET	rflags,EFLAGS*/
-	CFI_REL_OFFSET	rsp,RSP
-	/*CFI_REL_OFFSET	ss,SS*/
-	.endm
 /*
- * A newly forked process directly context switches into this.
- */ 	
-/* rdi:	prev */	
+ * initial frame state for interrupts (and exceptions without error code)
+ */
+	.macro EMPTY_FRAME start=1 offset=0
+	.if \start
+	CFI_STARTPROC simple
+	CFI_SIGNAL_FRAME
+	CFI_DEF_CFA rsp,8+\offset
+	.else
+	CFI_DEF_CFA_OFFSET 8+\offset
+	.endif
+	.endm
+
+/*
+ * initial frame state for interrupts (and exceptions without error code)
+ */
+	.macro INTR_FRAME start=1 offset=0
+	EMPTY_FRAME \start, SS+8+\offset-RIP
+	/*CFI_REL_OFFSET ss, SS+\offset-RIP*/
+	CFI_REL_OFFSET rsp, RSP+\offset-RIP
+	/*CFI_REL_OFFSET rflags, EFLAGS+\offset-RIP*/
+	/*CFI_REL_OFFSET cs, CS+\offset-RIP*/
+	CFI_REL_OFFSET rip, RIP+\offset-RIP
+	.endm
+
+/*
+ * initial frame state for exceptions with error code (and interrupts
+ * with vector already pushed)
+ */
+	.macro XCPT_FRAME start=1 offset=0
+	INTR_FRAME \start, RIP+\offset-ORIG_RAX
+	/*CFI_REL_OFFSET orig_rax, ORIG_RAX-ORIG_RAX*/
+	.endm
+
+/*
+ * frame that enables calling into C.
+ */
+	.macro PARTIAL_FRAME start=1 offset=0
+	XCPT_FRAME \start, ORIG_RAX+\offset-ARGOFFSET
+	CFI_REL_OFFSET rdi, RDI+\offset-ARGOFFSET
+	CFI_REL_OFFSET rsi, RSI+\offset-ARGOFFSET
+	CFI_REL_OFFSET rdx, RDX+\offset-ARGOFFSET
+	CFI_REL_OFFSET rcx, RCX+\offset-ARGOFFSET
+	CFI_REL_OFFSET rax, RAX+\offset-ARGOFFSET
+	CFI_REL_OFFSET r8, R8+\offset-ARGOFFSET
+	CFI_REL_OFFSET r9, R9+\offset-ARGOFFSET
+	CFI_REL_OFFSET r10, R10+\offset-ARGOFFSET
+	CFI_REL_OFFSET r11, R11+\offset-ARGOFFSET
+	.endm
+
+/*
+ * frame that enables passing a complete pt_regs to a C function.
+ */
+	.macro DEFAULT_FRAME start=1 offset=0
+	PARTIAL_FRAME \start, R11+\offset-R15
+	CFI_REL_OFFSET rbx, RBX+\offset
+	CFI_REL_OFFSET rbp, RBP+\offset
+	CFI_REL_OFFSET r12, R12+\offset
+	CFI_REL_OFFSET r13, R13+\offset
+	CFI_REL_OFFSET r14, R14+\offset
+	CFI_REL_OFFSET r15, R15+\offset
+	.endm
+
+/* save partial stack frame */
+ENTRY(save_args)
+	XCPT_FRAME
+	cld
+	movq_cfi rdi, RDI+16-ARGOFFSET
+	movq_cfi rsi, RSI+16-ARGOFFSET
+	movq_cfi rdx, RDX+16-ARGOFFSET
+	movq_cfi rcx, RCX+16-ARGOFFSET
+	movq_cfi rax, RAX+16-ARGOFFSET
+	movq_cfi  r8,  R8+16-ARGOFFSET
+	movq_cfi  r9,  R9+16-ARGOFFSET
+	movq_cfi r10, R10+16-ARGOFFSET
+	movq_cfi r11, R11+16-ARGOFFSET
+
+	leaq -ARGOFFSET+16(%rsp),%rdi	/* arg1 for handler */
+	movq_cfi rbp, 8		/* push %rbp */
+	leaq 8(%rsp), %rbp		/* mov %rsp, %ebp */
+	testl $3, CS(%rdi)
+	je 1f
+	SWAPGS
+	/*
+	 * irqcount is used to check if a CPU is already on an interrupt stack
+	 * or not. While this is essentially redundant with preempt_count it is
+	 * a little cheaper to use a separate counter in the PDA (short of
+	 * moving irq_enter into assembly, which would be too much work)
+	 */
+1:	incl %gs:pda_irqcount
+	jne 2f
+	popq_cfi %rax			/* move return address... */
+	mov %gs:pda_irqstackptr,%rsp
+	EMPTY_FRAME 0
+	pushq_cfi %rax			/* ... to the new stack */
+	/*
+	 * We entered an interrupt context - irqs are off:
+	 */
+2:	TRACE_IRQS_OFF
+	ret
+	CFI_ENDPROC
+END(save_args)
+
+ENTRY(save_rest)
+	PARTIAL_FRAME 1 REST_SKIP+8
+	movq 5*8+16(%rsp), %r11	/* save return address */
+	movq_cfi rbx, RBX+16
+	movq_cfi rbp, RBP+16
+	movq_cfi r12, R12+16
+	movq_cfi r13, R13+16
+	movq_cfi r14, R14+16
+	movq_cfi r15, R15+16
+	movq %r11, 8(%rsp)	/* return address */
+	FIXUP_TOP_OF_STACK %r11, 16
+	ret
+	CFI_ENDPROC
+END(save_rest)
+
+/* save complete stack frame */
+ENTRY(save_paranoid)
+	XCPT_FRAME 1 RDI+8
+	cld
+	movq_cfi rdi, RDI+8
+	movq_cfi rsi, RSI+8
+	movq_cfi rdx, RDX+8
+	movq_cfi rcx, RCX+8
+	movq_cfi rax, RAX+8
+	movq_cfi r8, R8+8
+	movq_cfi r9, R9+8
+	movq_cfi r10, R10+8
+	movq_cfi r11, R11+8
+	movq_cfi rbx, RBX+8
+	movq_cfi rbp, RBP+8
+	movq_cfi r12, R12+8
+	movq_cfi r13, R13+8
+	movq_cfi r14, R14+8
+	movq_cfi r15, R15+8
+	movl $1,%ebx
+	movl $MSR_GS_BASE,%ecx
+	rdmsr
+	testl %edx,%edx
+	js 1f	/* negative -> in kernel */
+	SWAPGS
+	xorl %ebx,%ebx
+1:	ret
+	CFI_ENDPROC
+END(save_paranoid)
+
+/*
+ * A newly forked process directly context switches into this address.
+ *
+ * rdi: prev task we switched from
+ */
 ENTRY(ret_from_fork)
-	CFI_DEFAULT_STACK
+	DEFAULT_FRAME
+
 	push kernel_eflags(%rip)
 	CFI_ADJUST_CFA_OFFSET 8
-	popf				# reset kernel eflags
+	popf					# reset kernel eflags
 	CFI_ADJUST_CFA_OFFSET -8
-	call schedule_tail
+
+	call schedule_tail			# rdi: 'prev' task parameter
+
 	GET_THREAD_INFO(%rcx)
-	testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%rcx)
-	jnz rff_trace
-rff_action:	
+
+	CFI_REMEMBER_STATE
 	RESTORE_REST
-	testl $3,CS-ARGOFFSET(%rsp)	# from kernel_thread?
+
+	testl $3, CS-ARGOFFSET(%rsp)		# from kernel_thread?
 	je   int_ret_from_sys_call
-	testl $_TIF_IA32,TI_flags(%rcx)
+
+	testl $_TIF_IA32, TI_flags(%rcx)	# 32-bit compat task needs IRET
 	jnz  int_ret_from_sys_call
-	RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
-	jmp ret_from_sys_call
-rff_trace:
-	movq %rsp,%rdi
-	call syscall_trace_leave
-	GET_THREAD_INFO(%rcx)	
-	jmp rff_action
+
+	RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET
+	jmp ret_from_sys_call			# go to the SYSRET fastpath
+
+	CFI_RESTORE_STATE
 	CFI_ENDPROC
 END(ret_from_fork)
 
@@ -278,20 +439,20 @@
  * SYSCALL does not save anything on the stack and does not change the
  * stack pointer.
  */
-		
+
 /*
- * Register setup:	
+ * Register setup:
  * rax  system call number
  * rdi  arg0
- * rcx  return address for syscall/sysret, C arg3 
+ * rcx  return address for syscall/sysret, C arg3
  * rsi  arg1
- * rdx  arg2	
+ * rdx  arg2
  * r10  arg3 	(--> moved to rcx for C)
  * r8   arg4
  * r9   arg5
  * r11  eflags for syscall/sysret, temporary for C
- * r12-r15,rbp,rbx saved by C code, not touched. 		
- * 
+ * r12-r15,rbp,rbx saved by C code, not touched.
+ *
  * Interrupts are off on entry.
  * Only called from user space.
  *
@@ -301,7 +462,7 @@
  * When user can change the frames always force IRET. That is because
  * it deals with uncanonical addresses better. SYSRET has trouble
  * with them due to bugs in both AMD and Intel CPUs.
- */ 			 		
+ */
 
 ENTRY(system_call)
 	CFI_STARTPROC	simple
@@ -317,7 +478,7 @@
 	 */
 ENTRY(system_call_after_swapgs)
 
-	movq	%rsp,%gs:pda_oldrsp 
+	movq	%rsp,%gs:pda_oldrsp
 	movq	%gs:pda_kernelstack,%rsp
 	/*
 	 * No need to follow this irqs off/on section - it's straight
@@ -325,7 +486,7 @@
 	 */
 	ENABLE_INTERRUPTS(CLBR_NONE)
 	SAVE_ARGS 8,1
-	movq  %rax,ORIG_RAX-ARGOFFSET(%rsp) 
+	movq  %rax,ORIG_RAX-ARGOFFSET(%rsp)
 	movq  %rcx,RIP-ARGOFFSET(%rsp)
 	CFI_REL_OFFSET rip,RIP-ARGOFFSET
 	GET_THREAD_INFO(%rcx)
@@ -339,19 +500,19 @@
 	movq %rax,RAX-ARGOFFSET(%rsp)
 /*
  * Syscall return path ending with SYSRET (fast path)
- * Has incomplete stack frame and undefined top of stack. 
- */		
+ * Has incomplete stack frame and undefined top of stack.
+ */
 ret_from_sys_call:
 	movl $_TIF_ALLWORK_MASK,%edi
 	/* edi:	flagmask */
-sysret_check:		
+sysret_check:
 	LOCKDEP_SYS_EXIT
 	GET_THREAD_INFO(%rcx)
 	DISABLE_INTERRUPTS(CLBR_NONE)
 	TRACE_IRQS_OFF
 	movl TI_flags(%rcx),%edx
 	andl %edi,%edx
-	jnz  sysret_careful 
+	jnz  sysret_careful
 	CFI_REMEMBER_STATE
 	/*
 	 * sysretq will re-enable interrupts:
@@ -366,7 +527,7 @@
 
 	CFI_RESTORE_STATE
 	/* Handle reschedules */
-	/* edx:	work, edi: workmask */	
+	/* edx:	work, edi: workmask */
 sysret_careful:
 	bt $TIF_NEED_RESCHED,%edx
 	jnc sysret_signal
@@ -379,7 +540,7 @@
 	CFI_ADJUST_CFA_OFFSET -8
 	jmp sysret_check
 
-	/* Handle a signal */ 
+	/* Handle a signal */
 sysret_signal:
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
@@ -388,17 +549,20 @@
 	jc sysret_audit
 #endif
 	/* edx:	work flags (arg3) */
-	leaq do_notify_resume(%rip),%rax
 	leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
 	xorl %esi,%esi # oldset -> arg2
-	call ptregscall_common
+	SAVE_REST
+	FIXUP_TOP_OF_STACK %r11
+	call do_notify_resume
+	RESTORE_TOP_OF_STACK %r11
+	RESTORE_REST
 	movl $_TIF_WORK_MASK,%edi
 	/* Use IRET because user could have changed frame. This
 	   works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
 	DISABLE_INTERRUPTS(CLBR_NONE)
 	TRACE_IRQS_OFF
 	jmp int_with_check
-	
+
 badsys:
 	movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
 	jmp ret_from_sys_call
@@ -437,7 +601,7 @@
 #endif	/* CONFIG_AUDITSYSCALL */
 
 	/* Do syscall tracing */
-tracesys:			 
+tracesys:
 #ifdef CONFIG_AUDITSYSCALL
 	testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%rcx)
 	jz auditsys
@@ -460,8 +624,8 @@
 	call *sys_call_table(,%rax,8)
 	movq %rax,RAX-ARGOFFSET(%rsp)
 	/* Use IRET because user could have changed frame */
-		
-/* 
+
+/*
  * Syscall return path ending with IRET.
  * Has correct top of stack, but partial stack frame.
  */
@@ -505,18 +669,18 @@
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
 	SAVE_REST
-	/* Check for syscall exit trace */	
+	/* Check for syscall exit trace */
 	testl $_TIF_WORK_SYSCALL_EXIT,%edx
 	jz int_signal
 	pushq %rdi
 	CFI_ADJUST_CFA_OFFSET 8
-	leaq 8(%rsp),%rdi	# &ptregs -> arg1	
+	leaq 8(%rsp),%rdi	# &ptregs -> arg1
 	call syscall_trace_leave
 	popq %rdi
 	CFI_ADJUST_CFA_OFFSET -8
 	andl $~(_TIF_WORK_SYSCALL_EXIT|_TIF_SYSCALL_EMU),%edi
 	jmp int_restore_rest
-	
+
 int_signal:
 	testl $_TIF_DO_NOTIFY_MASK,%edx
 	jz 1f
@@ -531,22 +695,24 @@
 	jmp int_with_check
 	CFI_ENDPROC
 END(system_call)
-		
-/* 
+
+/*
  * Certain special system calls that need to save a complete full stack frame.
- */ 								
-	
+ */
 	.macro PTREGSCALL label,func,arg
-	.globl \label
-\label:
-	leaq	\func(%rip),%rax
-	leaq    -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
-	jmp	ptregscall_common
+ENTRY(\label)
+	PARTIAL_FRAME 1 8		/* offset 8: return address */
+	subq $REST_SKIP, %rsp
+	CFI_ADJUST_CFA_OFFSET REST_SKIP
+	call save_rest
+	DEFAULT_FRAME 0 8		/* offset 8: return address */
+	leaq 8(%rsp), \arg	/* pt_regs pointer */
+	call \func
+	jmp ptregscall_common
+	CFI_ENDPROC
 END(\label)
 	.endm
 
-	CFI_STARTPROC
-
 	PTREGSCALL stub_clone, sys_clone, %r8
 	PTREGSCALL stub_fork, sys_fork, %rdi
 	PTREGSCALL stub_vfork, sys_vfork, %rdi
@@ -554,25 +720,18 @@
 	PTREGSCALL stub_iopl, sys_iopl, %rsi
 
 ENTRY(ptregscall_common)
-	popq %r11
-	CFI_ADJUST_CFA_OFFSET -8
-	CFI_REGISTER rip, r11
-	SAVE_REST
-	movq %r11, %r15
-	CFI_REGISTER rip, r15
-	FIXUP_TOP_OF_STACK %r11
-	call *%rax
-	RESTORE_TOP_OF_STACK %r11
-	movq %r15, %r11
-	CFI_REGISTER rip, r11
-	RESTORE_REST
-	pushq %r11
-	CFI_ADJUST_CFA_OFFSET 8
-	CFI_REL_OFFSET rip, 0
-	ret
+	DEFAULT_FRAME 1 8	/* offset 8: return address */
+	RESTORE_TOP_OF_STACK %r11, 8
+	movq_cfi_restore R15+8, r15
+	movq_cfi_restore R14+8, r14
+	movq_cfi_restore R13+8, r13
+	movq_cfi_restore R12+8, r12
+	movq_cfi_restore RBP+8, rbp
+	movq_cfi_restore RBX+8, rbx
+	ret $REST_SKIP		/* pop extended registers */
 	CFI_ENDPROC
 END(ptregscall_common)
-	
+
 ENTRY(stub_execve)
 	CFI_STARTPROC
 	popq %r11
@@ -588,11 +747,11 @@
 	jmp int_ret_from_sys_call
 	CFI_ENDPROC
 END(stub_execve)
-	
+
 /*
  * sigreturn is special because it needs to restore all registers on return.
  * This cannot be done with SYSRET, so use the IRET return path instead.
- */                
+ */
 ENTRY(stub_rt_sigreturn)
 	CFI_STARTPROC
 	addq $8, %rsp
@@ -608,70 +767,70 @@
 END(stub_rt_sigreturn)
 
 /*
- * initial frame state for interrupts and exceptions
+ * Build the entry stubs and pointer table with some assembler magic.
+ * We pack 7 stubs into a single 32-byte chunk, which will fit in a
+ * single cache line on all modern x86 implementations.
  */
-	.macro _frame ref
-	CFI_STARTPROC simple
-	CFI_SIGNAL_FRAME
-	CFI_DEF_CFA rsp,SS+8-\ref
-	/*CFI_REL_OFFSET ss,SS-\ref*/
-	CFI_REL_OFFSET rsp,RSP-\ref
-	/*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
-	/*CFI_REL_OFFSET cs,CS-\ref*/
-	CFI_REL_OFFSET rip,RIP-\ref
-	.endm
+	.section .init.rodata,"a"
+ENTRY(interrupt)
+	.text
+	.p2align 5
+	.p2align CONFIG_X86_L1_CACHE_SHIFT
+ENTRY(irq_entries_start)
+	INTR_FRAME
+vector=FIRST_EXTERNAL_VECTOR
+.rept (NR_VECTORS-FIRST_EXTERNAL_VECTOR+6)/7
+	.balign 32
+  .rept	7
+    .if vector < NR_VECTORS
+      .if vector <> FIRST_EXTERNAL_VECTOR
+	CFI_ADJUST_CFA_OFFSET -8
+      .endif
+1:	pushq $(~vector+0x80)	/* Note: always in signed byte range */
+	CFI_ADJUST_CFA_OFFSET 8
+      .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6
+	jmp 2f
+      .endif
+      .previous
+	.quad 1b
+      .text
+vector=vector+1
+    .endif
+  .endr
+2:	jmp common_interrupt
+.endr
+	CFI_ENDPROC
+END(irq_entries_start)
 
-/* initial frame state for interrupts (and exceptions without error code) */
-#define INTR_FRAME _frame RIP
-/* initial frame state for exceptions with error code (and interrupts with
-   vector already pushed) */
-#define XCPT_FRAME _frame ORIG_RAX
+.previous
+END(interrupt)
+.previous
 
-/* 
+/*
  * Interrupt entry/exit.
  *
  * Interrupt entry points save only callee clobbered registers in fast path.
- *	
- * Entry runs with interrupts off.	
- */ 
+ *
+ * Entry runs with interrupts off.
+ */
 
-/* 0(%rsp): interrupt number */ 
+/* 0(%rsp): ~(interrupt number) */
 	.macro interrupt func
-	cld
-	SAVE_ARGS
-	leaq -ARGOFFSET(%rsp),%rdi	# arg1 for handler
-	pushq %rbp
-	/*
-	 * Save rbp twice: One is for marking the stack frame, as usual, and the
-	 * other, to fill pt_regs properly. This is because bx comes right
-	 * before the last saved register in that structure, and not bp. If the
-	 * base pointer were in the place bx is today, this would not be needed.
-	 */
-	movq %rbp, -8(%rsp)
-	CFI_ADJUST_CFA_OFFSET	8
-	CFI_REL_OFFSET		rbp, 0
-	movq %rsp,%rbp
-	CFI_DEF_CFA_REGISTER	rbp
-	testl $3,CS(%rdi)
-	je 1f
-	SWAPGS
-	/* irqcount is used to check if a CPU is already on an interrupt
-	   stack or not. While this is essentially redundant with preempt_count
-	   it is a little cheaper to use a separate counter in the PDA
-	   (short of moving irq_enter into assembly, which would be too
-	    much work) */
-1:	incl	%gs:pda_irqcount
-	cmoveq %gs:pda_irqstackptr,%rsp
-	push    %rbp			# backlink for old unwinder
-	/*
-	 * We entered an interrupt context - irqs are off:
-	 */
-	TRACE_IRQS_OFF
+	subq $10*8, %rsp
+	CFI_ADJUST_CFA_OFFSET 10*8
+	call save_args
+	PARTIAL_FRAME 0
 	call \func
 	.endm
 
-ENTRY(common_interrupt)
+	/*
+	 * The interrupt stubs push (~vector+0x80) onto the stack and
+	 * then jump to common_interrupt.
+	 */
+	.p2align CONFIG_X86_L1_CACHE_SHIFT
+common_interrupt:
 	XCPT_FRAME
+	addq $-0x80,(%rsp)		/* Adjust vector to [-256,-1] range */
 	interrupt do_IRQ
 	/* 0(%rsp): oldrsp-ARGOFFSET */
 ret_from_intr:
@@ -685,12 +844,12 @@
 	GET_THREAD_INFO(%rcx)
 	testl $3,CS-ARGOFFSET(%rsp)
 	je retint_kernel
-	
+
 	/* Interrupt came from user space */
 	/*
 	 * Has a correct top of stack, but a partial stack frame
 	 * %rcx: thread info. Interrupts off.
-	 */		
+	 */
 retint_with_reschedule:
 	movl $_TIF_WORK_MASK,%edi
 retint_check:
@@ -763,20 +922,20 @@
 	pushq %rdi
 	CFI_ADJUST_CFA_OFFSET	8
 	call  schedule
-	popq %rdi		
+	popq %rdi
 	CFI_ADJUST_CFA_OFFSET	-8
 	GET_THREAD_INFO(%rcx)
 	DISABLE_INTERRUPTS(CLBR_NONE)
 	TRACE_IRQS_OFF
 	jmp retint_check
-	
+
 retint_signal:
 	testl $_TIF_DO_NOTIFY_MASK,%edx
 	jz    retint_swapgs
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
 	SAVE_REST
-	movq $-1,ORIG_RAX(%rsp) 			
+	movq $-1,ORIG_RAX(%rsp)
 	xorl %esi,%esi		# oldset
 	movq %rsp,%rdi		# &pt_regs
 	call do_notify_resume
@@ -798,324 +957,211 @@
 	jnc  retint_restore_args
 	call preempt_schedule_irq
 	jmp exit_intr
-#endif	
+#endif
 
 	CFI_ENDPROC
 END(common_interrupt)
-	
+
 /*
  * APIC interrupts.
- */		
-	.macro apicinterrupt num,func
+ */
+.macro apicinterrupt num sym do_sym
+ENTRY(\sym)
 	INTR_FRAME
 	pushq $~(\num)
 	CFI_ADJUST_CFA_OFFSET 8
-	interrupt \func
+	interrupt \do_sym
 	jmp ret_from_intr
 	CFI_ENDPROC
-	.endm
+END(\sym)
+.endm
 
-ENTRY(thermal_interrupt)
-	apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
-END(thermal_interrupt)
-
-ENTRY(threshold_interrupt)
-	apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
-END(threshold_interrupt)
-
-#ifdef CONFIG_SMP	
-ENTRY(reschedule_interrupt)
-	apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
-END(reschedule_interrupt)
-
-	.macro INVALIDATE_ENTRY num
-ENTRY(invalidate_interrupt\num)
-	apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt	
-END(invalidate_interrupt\num)
-	.endm
-
-	INVALIDATE_ENTRY 0
-	INVALIDATE_ENTRY 1
-	INVALIDATE_ENTRY 2
-	INVALIDATE_ENTRY 3
-	INVALIDATE_ENTRY 4
-	INVALIDATE_ENTRY 5
-	INVALIDATE_ENTRY 6
-	INVALIDATE_ENTRY 7
-
-ENTRY(call_function_interrupt)
-	apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
-END(call_function_interrupt)
-ENTRY(call_function_single_interrupt)
-	apicinterrupt CALL_FUNCTION_SINGLE_VECTOR,smp_call_function_single_interrupt
-END(call_function_single_interrupt)
-ENTRY(irq_move_cleanup_interrupt)
-	apicinterrupt IRQ_MOVE_CLEANUP_VECTOR,smp_irq_move_cleanup_interrupt
-END(irq_move_cleanup_interrupt)
+#ifdef CONFIG_SMP
+apicinterrupt IRQ_MOVE_CLEANUP_VECTOR \
+	irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt
 #endif
 
-ENTRY(apic_timer_interrupt)
-	apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
-END(apic_timer_interrupt)
+apicinterrupt UV_BAU_MESSAGE \
+	uv_bau_message_intr1 uv_bau_message_interrupt
+apicinterrupt LOCAL_TIMER_VECTOR \
+	apic_timer_interrupt smp_apic_timer_interrupt
 
-ENTRY(uv_bau_message_intr1)
-	apicinterrupt 220,uv_bau_message_interrupt
-END(uv_bau_message_intr1)
+#ifdef CONFIG_SMP
+apicinterrupt INVALIDATE_TLB_VECTOR_START+0 \
+	invalidate_interrupt0 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+1 \
+	invalidate_interrupt1 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+2 \
+	invalidate_interrupt2 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+3 \
+	invalidate_interrupt3 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+4 \
+	invalidate_interrupt4 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+5 \
+	invalidate_interrupt5 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+6 \
+	invalidate_interrupt6 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+7 \
+	invalidate_interrupt7 smp_invalidate_interrupt
+#endif
 
-ENTRY(error_interrupt)
-	apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
-END(error_interrupt)
+apicinterrupt THRESHOLD_APIC_VECTOR \
+	threshold_interrupt mce_threshold_interrupt
+apicinterrupt THERMAL_APIC_VECTOR \
+	thermal_interrupt smp_thermal_interrupt
 
-ENTRY(spurious_interrupt)
-	apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
-END(spurious_interrupt)
-				
+#ifdef CONFIG_SMP
+apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \
+	call_function_single_interrupt smp_call_function_single_interrupt
+apicinterrupt CALL_FUNCTION_VECTOR \
+	call_function_interrupt smp_call_function_interrupt
+apicinterrupt RESCHEDULE_VECTOR \
+	reschedule_interrupt smp_reschedule_interrupt
+#endif
+
+apicinterrupt ERROR_APIC_VECTOR \
+	error_interrupt smp_error_interrupt
+apicinterrupt SPURIOUS_APIC_VECTOR \
+	spurious_interrupt smp_spurious_interrupt
+
 /*
  * Exception entry points.
- */ 		
-	.macro zeroentry sym
+ */
+.macro zeroentry sym do_sym
+ENTRY(\sym)
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
-	pushq $0	/* push error code/oldrax */ 
-	CFI_ADJUST_CFA_OFFSET 8
-	pushq %rax	/* push real oldrax to the rdi slot */ 
-	CFI_ADJUST_CFA_OFFSET 8
-	CFI_REL_OFFSET rax,0
-	leaq  \sym(%rip),%rax
-	jmp error_entry
+	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
+	subq $15*8,%rsp
+	CFI_ADJUST_CFA_OFFSET 15*8
+	call error_entry
+	DEFAULT_FRAME 0
+	movq %rsp,%rdi		/* pt_regs pointer */
+	xorl %esi,%esi		/* no error code */
+	call \do_sym
+	jmp error_exit		/* %ebx: no swapgs flag */
 	CFI_ENDPROC
-	.endm	
+END(\sym)
+.endm
 
-	.macro errorentry sym
+.macro paranoidzeroentry sym do_sym
+ENTRY(\sym)
+	INTR_FRAME
+	PARAVIRT_ADJUST_EXCEPTION_FRAME
+	pushq $-1		/* ORIG_RAX: no syscall to restart */
+	CFI_ADJUST_CFA_OFFSET 8
+	subq $15*8, %rsp
+	call save_paranoid
+	TRACE_IRQS_OFF
+	movq %rsp,%rdi		/* pt_regs pointer */
+	xorl %esi,%esi		/* no error code */
+	call \do_sym
+	jmp paranoid_exit	/* %ebx: no swapgs flag */
+	CFI_ENDPROC
+END(\sym)
+.endm
+
+.macro paranoidzeroentry_ist sym do_sym ist
+ENTRY(\sym)
+	INTR_FRAME
+	PARAVIRT_ADJUST_EXCEPTION_FRAME
+	pushq $-1		/* ORIG_RAX: no syscall to restart */
+	CFI_ADJUST_CFA_OFFSET 8
+	subq $15*8, %rsp
+	call save_paranoid
+	TRACE_IRQS_OFF
+	movq %rsp,%rdi		/* pt_regs pointer */
+	xorl %esi,%esi		/* no error code */
+	movq %gs:pda_data_offset, %rbp
+	subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
+	call \do_sym
+	addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
+	jmp paranoid_exit	/* %ebx: no swapgs flag */
+	CFI_ENDPROC
+END(\sym)
+.endm
+
+.macro errorentry sym do_sym
+ENTRY(\sym)
 	XCPT_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
-	pushq %rax
-	CFI_ADJUST_CFA_OFFSET 8
-	CFI_REL_OFFSET rax,0
-	leaq  \sym(%rip),%rax
-	jmp error_entry
+	subq $15*8,%rsp
+	CFI_ADJUST_CFA_OFFSET 15*8
+	call error_entry
+	DEFAULT_FRAME 0
+	movq %rsp,%rdi			/* pt_regs pointer */
+	movq ORIG_RAX(%rsp),%rsi	/* get error code */
+	movq $-1,ORIG_RAX(%rsp)		/* no syscall to restart */
+	call \do_sym
+	jmp error_exit			/* %ebx: no swapgs flag */
 	CFI_ENDPROC
-	.endm
+END(\sym)
+.endm
 
 	/* error code is on the stack already */
-	/* handle NMI like exceptions that can happen everywhere */
-	.macro paranoidentry sym, ist=0, irqtrace=1
-	SAVE_ALL
-	cld
-	movl $1,%ebx
-	movl  $MSR_GS_BASE,%ecx
-	rdmsr
-	testl %edx,%edx
-	js    1f
-	SWAPGS
-	xorl  %ebx,%ebx
-1:
-	.if \ist
-	movq	%gs:pda_data_offset, %rbp
-	.endif
-	.if \irqtrace
+.macro paranoiderrorentry sym do_sym
+ENTRY(\sym)
+	XCPT_FRAME
+	PARAVIRT_ADJUST_EXCEPTION_FRAME
+	subq $15*8,%rsp
+	CFI_ADJUST_CFA_OFFSET 15*8
+	call save_paranoid
+	DEFAULT_FRAME 0
 	TRACE_IRQS_OFF
-	.endif
-	movq %rsp,%rdi
-	movq ORIG_RAX(%rsp),%rsi
-	movq $-1,ORIG_RAX(%rsp)
-	.if \ist
-	subq	$EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
-	.endif
-	call \sym
-	.if \ist
-	addq	$EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
-	.endif
-	DISABLE_INTERRUPTS(CLBR_NONE)
-	.if \irqtrace
-	TRACE_IRQS_OFF
-	.endif
-	.endm
-
-	/*
- 	 * "Paranoid" exit path from exception stack.
-  	 * Paranoid because this is used by NMIs and cannot take
-	 * any kernel state for granted.
-	 * We don't do kernel preemption checks here, because only
-	 * NMI should be common and it does not enable IRQs and
-	 * cannot get reschedule ticks.
-	 *
-	 * "trace" is 0 for the NMI handler only, because irq-tracing
-	 * is fundamentally NMI-unsafe. (we cannot change the soft and
-	 * hard flags at once, atomically)
-	 */
-	.macro paranoidexit trace=1
-	/* ebx:	no swapgs flag */
-paranoid_exit\trace:
-	testl %ebx,%ebx				/* swapgs needed? */
-	jnz paranoid_restore\trace
-	testl $3,CS(%rsp)
-	jnz   paranoid_userspace\trace
-paranoid_swapgs\trace:
-	.if \trace
-	TRACE_IRQS_IRETQ 0
-	.endif
-	SWAPGS_UNSAFE_STACK
-paranoid_restore\trace:
-	RESTORE_ALL 8
-	jmp irq_return
-paranoid_userspace\trace:
-	GET_THREAD_INFO(%rcx)
-	movl TI_flags(%rcx),%ebx
-	andl $_TIF_WORK_MASK,%ebx
-	jz paranoid_swapgs\trace
-	movq %rsp,%rdi			/* &pt_regs */
-	call sync_regs
-	movq %rax,%rsp			/* switch stack for scheduling */
-	testl $_TIF_NEED_RESCHED,%ebx
-	jnz paranoid_schedule\trace
-	movl %ebx,%edx			/* arg3: thread flags */
-	.if \trace
-	TRACE_IRQS_ON
-	.endif
-	ENABLE_INTERRUPTS(CLBR_NONE)
-	xorl %esi,%esi 			/* arg2: oldset */
-	movq %rsp,%rdi 			/* arg1: &pt_regs */
-	call do_notify_resume
-	DISABLE_INTERRUPTS(CLBR_NONE)
-	.if \trace
-	TRACE_IRQS_OFF
-	.endif
-	jmp paranoid_userspace\trace
-paranoid_schedule\trace:
-	.if \trace
-	TRACE_IRQS_ON
-	.endif
-	ENABLE_INTERRUPTS(CLBR_ANY)
-	call schedule
-	DISABLE_INTERRUPTS(CLBR_ANY)
-	.if \trace
-	TRACE_IRQS_OFF
-	.endif
-	jmp paranoid_userspace\trace
+	movq %rsp,%rdi			/* pt_regs pointer */
+	movq ORIG_RAX(%rsp),%rsi	/* get error code */
+	movq $-1,ORIG_RAX(%rsp)		/* no syscall to restart */
+	call \do_sym
+	jmp paranoid_exit		/* %ebx: no swapgs flag */
 	CFI_ENDPROC
-	.endm
+END(\sym)
+.endm
 
-/*
- * Exception entry point. This expects an error code/orig_rax on the stack
- * and the exception handler in %rax.	
- */ 		  				
-KPROBE_ENTRY(error_entry)
-	_frame RDI
-	CFI_REL_OFFSET rax,0
-	/* rdi slot contains rax, oldrax contains error code */
-	cld	
-	subq  $14*8,%rsp
-	CFI_ADJUST_CFA_OFFSET	(14*8)
-	movq %rsi,13*8(%rsp)
-	CFI_REL_OFFSET	rsi,RSI
-	movq 14*8(%rsp),%rsi	/* load rax from rdi slot */
-	CFI_REGISTER	rax,rsi
-	movq %rdx,12*8(%rsp)
-	CFI_REL_OFFSET	rdx,RDX
-	movq %rcx,11*8(%rsp)
-	CFI_REL_OFFSET	rcx,RCX
-	movq %rsi,10*8(%rsp)	/* store rax */ 
-	CFI_REL_OFFSET	rax,RAX
-	movq %r8, 9*8(%rsp)
-	CFI_REL_OFFSET	r8,R8
-	movq %r9, 8*8(%rsp)
-	CFI_REL_OFFSET	r9,R9
-	movq %r10,7*8(%rsp)
-	CFI_REL_OFFSET	r10,R10
-	movq %r11,6*8(%rsp)
-	CFI_REL_OFFSET	r11,R11
-	movq %rbx,5*8(%rsp) 
-	CFI_REL_OFFSET	rbx,RBX
-	movq %rbp,4*8(%rsp) 
-	CFI_REL_OFFSET	rbp,RBP
-	movq %r12,3*8(%rsp) 
-	CFI_REL_OFFSET	r12,R12
-	movq %r13,2*8(%rsp) 
-	CFI_REL_OFFSET	r13,R13
-	movq %r14,1*8(%rsp) 
-	CFI_REL_OFFSET	r14,R14
-	movq %r15,(%rsp) 
-	CFI_REL_OFFSET	r15,R15
-	xorl %ebx,%ebx	
-	testl $3,CS(%rsp)
-	je  error_kernelspace
-error_swapgs:	
-	SWAPGS
-error_sti:
-	TRACE_IRQS_OFF
-	movq %rdi,RDI(%rsp) 	
-	CFI_REL_OFFSET	rdi,RDI
-	movq %rsp,%rdi
-	movq ORIG_RAX(%rsp),%rsi	/* get error code */ 
-	movq $-1,ORIG_RAX(%rsp)
-	call *%rax
-	/* ebx:	no swapgs flag (1: don't need swapgs, 0: need it) */
-error_exit:
-	movl %ebx,%eax
-	RESTORE_REST
-	DISABLE_INTERRUPTS(CLBR_NONE)
-	TRACE_IRQS_OFF
-	GET_THREAD_INFO(%rcx)	
-	testl %eax,%eax
-	jne  retint_kernel
-	LOCKDEP_SYS_EXIT_IRQ
-	movl  TI_flags(%rcx),%edx
-	movl  $_TIF_WORK_MASK,%edi
-	andl  %edi,%edx
-	jnz  retint_careful
-	jmp retint_swapgs
-	CFI_ENDPROC
+zeroentry divide_error do_divide_error
+zeroentry overflow do_overflow
+zeroentry bounds do_bounds
+zeroentry invalid_op do_invalid_op
+zeroentry device_not_available do_device_not_available
+paranoiderrorentry double_fault do_double_fault
+zeroentry coprocessor_segment_overrun do_coprocessor_segment_overrun
+errorentry invalid_TSS do_invalid_TSS
+errorentry segment_not_present do_segment_not_present
+zeroentry spurious_interrupt_bug do_spurious_interrupt_bug
+zeroentry coprocessor_error do_coprocessor_error
+errorentry alignment_check do_alignment_check
+zeroentry simd_coprocessor_error do_simd_coprocessor_error
 
-error_kernelspace:
-	incl %ebx
-       /* There are two places in the kernel that can potentially fault with
-          usergs. Handle them here. The exception handlers after
-	   iret run with kernel gs again, so don't set the user space flag.
-	   B stepping K8s sometimes report an truncated RIP for IRET 
-	   exceptions returning to compat mode. Check for these here too. */
-	leaq irq_return(%rip),%rcx
-	cmpq %rcx,RIP(%rsp)
-	je   error_swapgs
-	movl %ecx,%ecx	/* zero extend */
-	cmpq %rcx,RIP(%rsp)
-	je   error_swapgs
-	cmpq $gs_change,RIP(%rsp)
-        je   error_swapgs
-	jmp  error_sti
-KPROBE_END(error_entry)
-	
-       /* Reload gs selector with exception handling */
-       /* edi:  new selector */ 
+	/* Reload gs selector with exception handling */
+	/* edi:  new selector */
 ENTRY(native_load_gs_index)
 	CFI_STARTPROC
 	pushf
 	CFI_ADJUST_CFA_OFFSET 8
 	DISABLE_INTERRUPTS(CLBR_ANY | ~(CLBR_RDI))
-        SWAPGS
-gs_change:     
-        movl %edi,%gs   
+	SWAPGS
+gs_change:
+	movl %edi,%gs
 2:	mfence		/* workaround */
 	SWAPGS
-        popf
+	popf
 	CFI_ADJUST_CFA_OFFSET -8
-        ret
+	ret
 	CFI_ENDPROC
-ENDPROC(native_load_gs_index)
-       
-        .section __ex_table,"a"
-        .align 8
-        .quad gs_change,bad_gs
-        .previous
-        .section .fixup,"ax"
+END(native_load_gs_index)
+
+	.section __ex_table,"a"
+	.align 8
+	.quad gs_change,bad_gs
+	.previous
+	.section .fixup,"ax"
 	/* running with kernelgs */
-bad_gs: 
+bad_gs:
 	SWAPGS			/* switch back to user gs */
 	xorl %eax,%eax
-        movl %eax,%gs
-        jmp  2b
-        .previous       
-	
+	movl %eax,%gs
+	jmp  2b
+	.previous
+
 /*
  * Create a kernel thread.
  *
@@ -1138,7 +1184,7 @@
 
 	xorl %r8d,%r8d
 	xorl %r9d,%r9d
-	
+
 	# clone now
 	call do_fork
 	movq %rax,RAX(%rsp)
@@ -1149,15 +1195,15 @@
 	 * so internally to the x86_64 port you can rely on kernel_thread()
 	 * not to reschedule the child before returning, this avoids the need
 	 * of hacks for example to fork off the per-CPU idle tasks.
-         * [Hopefully no generic code relies on the reschedule -AK]	
+	 * [Hopefully no generic code relies on the reschedule -AK]
 	 */
 	RESTORE_ALL
 	UNFAKE_STACK_FRAME
 	ret
 	CFI_ENDPROC
-ENDPROC(kernel_thread)
-	
-child_rip:
+END(kernel_thread)
+
+ENTRY(child_rip)
 	pushq $0		# fake return address
 	CFI_STARTPROC
 	/*
@@ -1170,8 +1216,9 @@
 	# exit
 	mov %eax, %edi
 	call do_exit
+	ud2			# padding for call trace
 	CFI_ENDPROC
-ENDPROC(child_rip)
+END(child_rip)
 
 /*
  * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
@@ -1191,10 +1238,10 @@
 ENTRY(kernel_execve)
 	CFI_STARTPROC
 	FAKE_STACK_FRAME $0
-	SAVE_ALL	
+	SAVE_ALL
 	movq %rsp,%rcx
 	call sys_execve
-	movq %rax, RAX(%rsp)	
+	movq %rax, RAX(%rsp)
 	RESTORE_REST
 	testq %rax,%rax
 	je int_ret_from_sys_call
@@ -1202,129 +1249,7 @@
 	UNFAKE_STACK_FRAME
 	ret
 	CFI_ENDPROC
-ENDPROC(kernel_execve)
-
-KPROBE_ENTRY(page_fault)
-	errorentry do_page_fault
-KPROBE_END(page_fault)
-
-ENTRY(coprocessor_error)
-	zeroentry do_coprocessor_error
-END(coprocessor_error)
-
-ENTRY(simd_coprocessor_error)
-	zeroentry do_simd_coprocessor_error	
-END(simd_coprocessor_error)
-
-ENTRY(device_not_available)
-	zeroentry do_device_not_available
-END(device_not_available)
-
-	/* runs on exception stack */
-KPROBE_ENTRY(debug)
- 	INTR_FRAME
-	PARAVIRT_ADJUST_EXCEPTION_FRAME
-	pushq $0
-	CFI_ADJUST_CFA_OFFSET 8		
-	paranoidentry do_debug, DEBUG_STACK
-	paranoidexit
-KPROBE_END(debug)
-
-	/* runs on exception stack */	
-KPROBE_ENTRY(nmi)
-	INTR_FRAME
-	PARAVIRT_ADJUST_EXCEPTION_FRAME
-	pushq $-1
-	CFI_ADJUST_CFA_OFFSET 8
-	paranoidentry do_nmi, 0, 0
-#ifdef CONFIG_TRACE_IRQFLAGS
-	paranoidexit 0
-#else
-	jmp paranoid_exit1
- 	CFI_ENDPROC
-#endif
-KPROBE_END(nmi)
-
-KPROBE_ENTRY(int3)
- 	INTR_FRAME
-	PARAVIRT_ADJUST_EXCEPTION_FRAME
- 	pushq $0
- 	CFI_ADJUST_CFA_OFFSET 8
- 	paranoidentry do_int3, DEBUG_STACK
- 	jmp paranoid_exit1
- 	CFI_ENDPROC
-KPROBE_END(int3)
-
-ENTRY(overflow)
-	zeroentry do_overflow
-END(overflow)
-
-ENTRY(bounds)
-	zeroentry do_bounds
-END(bounds)
-
-ENTRY(invalid_op)
-	zeroentry do_invalid_op	
-END(invalid_op)
-
-ENTRY(coprocessor_segment_overrun)
-	zeroentry do_coprocessor_segment_overrun
-END(coprocessor_segment_overrun)
-
-	/* runs on exception stack */
-ENTRY(double_fault)
-	XCPT_FRAME
-	PARAVIRT_ADJUST_EXCEPTION_FRAME
-	paranoidentry do_double_fault
-	jmp paranoid_exit1
-	CFI_ENDPROC
-END(double_fault)
-
-ENTRY(invalid_TSS)
-	errorentry do_invalid_TSS
-END(invalid_TSS)
-
-ENTRY(segment_not_present)
-	errorentry do_segment_not_present
-END(segment_not_present)
-
-	/* runs on exception stack */
-ENTRY(stack_segment)
-	XCPT_FRAME
-	PARAVIRT_ADJUST_EXCEPTION_FRAME
-	paranoidentry do_stack_segment
-	jmp paranoid_exit1
-	CFI_ENDPROC
-END(stack_segment)
-
-KPROBE_ENTRY(general_protection)
-	errorentry do_general_protection
-KPROBE_END(general_protection)
-
-ENTRY(alignment_check)
-	errorentry do_alignment_check
-END(alignment_check)
-
-ENTRY(divide_error)
-	zeroentry do_divide_error
-END(divide_error)
-
-ENTRY(spurious_interrupt_bug)
-	zeroentry do_spurious_interrupt_bug
-END(spurious_interrupt_bug)
-
-#ifdef CONFIG_X86_MCE
-	/* runs on exception stack */
-ENTRY(machine_check)
-	INTR_FRAME
-	PARAVIRT_ADJUST_EXCEPTION_FRAME
-	pushq $0
-	CFI_ADJUST_CFA_OFFSET 8	
-	paranoidentry do_machine_check
-	jmp paranoid_exit1
-	CFI_ENDPROC
-END(machine_check)
-#endif
+END(kernel_execve)
 
 /* Call softirq on interrupt stack. Interrupts are off. */
 ENTRY(call_softirq)
@@ -1344,40 +1269,33 @@
 	decl %gs:pda_irqcount
 	ret
 	CFI_ENDPROC
-ENDPROC(call_softirq)
-
-KPROBE_ENTRY(ignore_sysret)
-	CFI_STARTPROC
-	mov $-ENOSYS,%eax
-	sysret
-	CFI_ENDPROC
-ENDPROC(ignore_sysret)
+END(call_softirq)
 
 #ifdef CONFIG_XEN
-ENTRY(xen_hypervisor_callback)
-	zeroentry xen_do_hypervisor_callback
-END(xen_hypervisor_callback)
+zeroentry xen_hypervisor_callback xen_do_hypervisor_callback
 
 /*
-# A note on the "critical region" in our callback handler.
-# We want to avoid stacking callback handlers due to events occurring
-# during handling of the last event. To do this, we keep events disabled
-# until we've done all processing. HOWEVER, we must enable events before
-# popping the stack frame (can't be done atomically) and so it would still
-# be possible to get enough handler activations to overflow the stack.
-# Although unlikely, bugs of that kind are hard to track down, so we'd
-# like to avoid the possibility.
-# So, on entry to the handler we detect whether we interrupted an
-# existing activation in its critical region -- if so, we pop the current
-# activation and restart the handler using the previous one.
-*/
+ * A note on the "critical region" in our callback handler.
+ * We want to avoid stacking callback handlers due to events occurring
+ * during handling of the last event. To do this, we keep events disabled
+ * until we've done all processing. HOWEVER, we must enable events before
+ * popping the stack frame (can't be done atomically) and so it would still
+ * be possible to get enough handler activations to overflow the stack.
+ * Although unlikely, bugs of that kind are hard to track down, so we'd
+ * like to avoid the possibility.
+ * So, on entry to the handler we detect whether we interrupted an
+ * existing activation in its critical region -- if so, we pop the current
+ * activation and restart the handler using the previous one.
+ */
 ENTRY(xen_do_hypervisor_callback)   # do_hypervisor_callback(struct *pt_regs)
 	CFI_STARTPROC
-/* Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will
-   see the correct pointer to the pt_regs */
+/*
+ * Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will
+ * see the correct pointer to the pt_regs
+ */
 	movq %rdi, %rsp            # we don't return, adjust the stack frame
 	CFI_ENDPROC
-	CFI_DEFAULT_STACK
+	DEFAULT_FRAME
 11:	incl %gs:pda_irqcount
 	movq %rsp,%rbp
 	CFI_DEF_CFA_REGISTER rbp
@@ -1392,23 +1310,26 @@
 END(do_hypervisor_callback)
 
 /*
-# Hypervisor uses this for application faults while it executes.
-# We get here for two reasons:
-#  1. Fault while reloading DS, ES, FS or GS
-#  2. Fault while executing IRET
-# Category 1 we do not need to fix up as Xen has already reloaded all segment
-# registers that could be reloaded and zeroed the others.
-# Category 2 we fix up by killing the current process. We cannot use the
-# normal Linux return path in this case because if we use the IRET hypercall
-# to pop the stack frame we end up in an infinite loop of failsafe callbacks.
-# We distinguish between categories by comparing each saved segment register
-# with its current contents: any discrepancy means we in category 1.
-*/
+ * Hypervisor uses this for application faults while it executes.
+ * We get here for two reasons:
+ *  1. Fault while reloading DS, ES, FS or GS
+ *  2. Fault while executing IRET
+ * Category 1 we do not need to fix up as Xen has already reloaded all segment
+ * registers that could be reloaded and zeroed the others.
+ * Category 2 we fix up by killing the current process. We cannot use the
+ * normal Linux return path in this case because if we use the IRET hypercall
+ * to pop the stack frame we end up in an infinite loop of failsafe callbacks.
+ * We distinguish between categories by comparing each saved segment register
+ * with its current contents: any discrepancy means we in category 1.
+ */
 ENTRY(xen_failsafe_callback)
-	framesz = (RIP-0x30)	/* workaround buggy gas */
-	_frame framesz
-	CFI_REL_OFFSET rcx, 0
-	CFI_REL_OFFSET r11, 8
+	INTR_FRAME 1 (6*8)
+	/*CFI_REL_OFFSET gs,GS*/
+	/*CFI_REL_OFFSET fs,FS*/
+	/*CFI_REL_OFFSET es,ES*/
+	/*CFI_REL_OFFSET ds,DS*/
+	CFI_REL_OFFSET r11,8
+	CFI_REL_OFFSET rcx,0
 	movw %ds,%cx
 	cmpw %cx,0x10(%rsp)
 	CFI_REMEMBER_STATE
@@ -1429,12 +1350,9 @@
 	CFI_RESTORE r11
 	addq $0x30,%rsp
 	CFI_ADJUST_CFA_OFFSET -0x30
-	pushq $0
-	CFI_ADJUST_CFA_OFFSET 8
-	pushq %r11
-	CFI_ADJUST_CFA_OFFSET 8
-	pushq %rcx
-	CFI_ADJUST_CFA_OFFSET 8
+	pushq_cfi $0	/* RIP */
+	pushq_cfi %r11
+	pushq_cfi %rcx
 	jmp general_protection
 	CFI_RESTORE_STATE
 1:	/* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */
@@ -1444,11 +1362,223 @@
 	CFI_RESTORE r11
 	addq $0x30,%rsp
 	CFI_ADJUST_CFA_OFFSET -0x30
-	pushq $0
-	CFI_ADJUST_CFA_OFFSET 8
+	pushq_cfi $0
 	SAVE_ALL
 	jmp error_exit
 	CFI_ENDPROC
 END(xen_failsafe_callback)
 
 #endif /* CONFIG_XEN */
+
+/*
+ * Some functions should be protected against kprobes
+ */
+	.pushsection .kprobes.text, "ax"
+
+paranoidzeroentry_ist debug do_debug DEBUG_STACK
+paranoidzeroentry_ist int3 do_int3 DEBUG_STACK
+paranoiderrorentry stack_segment do_stack_segment
+errorentry general_protection do_general_protection
+errorentry page_fault do_page_fault
+#ifdef CONFIG_X86_MCE
+paranoidzeroentry machine_check do_machine_check
+#endif
+
+	/*
+	 * "Paranoid" exit path from exception stack.
+	 * Paranoid because this is used by NMIs and cannot take
+	 * any kernel state for granted.
+	 * We don't do kernel preemption checks here, because only
+	 * NMI should be common and it does not enable IRQs and
+	 * cannot get reschedule ticks.
+	 *
+	 * "trace" is 0 for the NMI handler only, because irq-tracing
+	 * is fundamentally NMI-unsafe. (we cannot change the soft and
+	 * hard flags at once, atomically)
+	 */
+
+	/* ebx:	no swapgs flag */
+ENTRY(paranoid_exit)
+	INTR_FRAME
+	DISABLE_INTERRUPTS(CLBR_NONE)
+	TRACE_IRQS_OFF
+	testl %ebx,%ebx				/* swapgs needed? */
+	jnz paranoid_restore
+	testl $3,CS(%rsp)
+	jnz   paranoid_userspace
+paranoid_swapgs:
+	TRACE_IRQS_IRETQ 0
+	SWAPGS_UNSAFE_STACK
+paranoid_restore:
+	RESTORE_ALL 8
+	jmp irq_return
+paranoid_userspace:
+	GET_THREAD_INFO(%rcx)
+	movl TI_flags(%rcx),%ebx
+	andl $_TIF_WORK_MASK,%ebx
+	jz paranoid_swapgs
+	movq %rsp,%rdi			/* &pt_regs */
+	call sync_regs
+	movq %rax,%rsp			/* switch stack for scheduling */
+	testl $_TIF_NEED_RESCHED,%ebx
+	jnz paranoid_schedule
+	movl %ebx,%edx			/* arg3: thread flags */
+	TRACE_IRQS_ON
+	ENABLE_INTERRUPTS(CLBR_NONE)
+	xorl %esi,%esi 			/* arg2: oldset */
+	movq %rsp,%rdi 			/* arg1: &pt_regs */
+	call do_notify_resume
+	DISABLE_INTERRUPTS(CLBR_NONE)
+	TRACE_IRQS_OFF
+	jmp paranoid_userspace
+paranoid_schedule:
+	TRACE_IRQS_ON
+	ENABLE_INTERRUPTS(CLBR_ANY)
+	call schedule
+	DISABLE_INTERRUPTS(CLBR_ANY)
+	TRACE_IRQS_OFF
+	jmp paranoid_userspace
+	CFI_ENDPROC
+END(paranoid_exit)
+
+/*
+ * Exception entry point. This expects an error code/orig_rax on the stack.
+ * returns in "no swapgs flag" in %ebx.
+ */
+ENTRY(error_entry)
+	XCPT_FRAME
+	CFI_ADJUST_CFA_OFFSET 15*8
+	/* oldrax contains error code */
+	cld
+	movq_cfi rdi, RDI+8
+	movq_cfi rsi, RSI+8
+	movq_cfi rdx, RDX+8
+	movq_cfi rcx, RCX+8
+	movq_cfi rax, RAX+8
+	movq_cfi  r8,  R8+8
+	movq_cfi  r9,  R9+8
+	movq_cfi r10, R10+8
+	movq_cfi r11, R11+8
+	movq_cfi rbx, RBX+8
+	movq_cfi rbp, RBP+8
+	movq_cfi r12, R12+8
+	movq_cfi r13, R13+8
+	movq_cfi r14, R14+8
+	movq_cfi r15, R15+8
+	xorl %ebx,%ebx
+	testl $3,CS+8(%rsp)
+	je error_kernelspace
+error_swapgs:
+	SWAPGS
+error_sti:
+	TRACE_IRQS_OFF
+	ret
+	CFI_ENDPROC
+
+/*
+ * There are two places in the kernel that can potentially fault with
+ * usergs. Handle them here. The exception handlers after iret run with
+ * kernel gs again, so don't set the user space flag. B stepping K8s
+ * sometimes report an truncated RIP for IRET exceptions returning to
+ * compat mode. Check for these here too.
+ */
+error_kernelspace:
+	incl %ebx
+	leaq irq_return(%rip),%rcx
+	cmpq %rcx,RIP+8(%rsp)
+	je error_swapgs
+	movl %ecx,%ecx	/* zero extend */
+	cmpq %rcx,RIP+8(%rsp)
+	je error_swapgs
+	cmpq $gs_change,RIP+8(%rsp)
+	je error_swapgs
+	jmp error_sti
+END(error_entry)
+
+
+/* ebx:	no swapgs flag (1: don't need swapgs, 0: need it) */
+ENTRY(error_exit)
+	DEFAULT_FRAME
+	movl %ebx,%eax
+	RESTORE_REST
+	DISABLE_INTERRUPTS(CLBR_NONE)
+	TRACE_IRQS_OFF
+	GET_THREAD_INFO(%rcx)
+	testl %eax,%eax
+	jne retint_kernel
+	LOCKDEP_SYS_EXIT_IRQ
+	movl TI_flags(%rcx),%edx
+	movl $_TIF_WORK_MASK,%edi
+	andl %edi,%edx
+	jnz retint_careful
+	jmp retint_swapgs
+	CFI_ENDPROC
+END(error_exit)
+
+
+	/* runs on exception stack */
+ENTRY(nmi)
+	INTR_FRAME
+	PARAVIRT_ADJUST_EXCEPTION_FRAME
+	pushq_cfi $-1
+	subq $15*8, %rsp
+	CFI_ADJUST_CFA_OFFSET 15*8
+	call save_paranoid
+	DEFAULT_FRAME 0
+	/* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
+	movq %rsp,%rdi
+	movq $-1,%rsi
+	call do_nmi
+#ifdef CONFIG_TRACE_IRQFLAGS
+	/* paranoidexit; without TRACE_IRQS_OFF */
+	/* ebx:	no swapgs flag */
+	DISABLE_INTERRUPTS(CLBR_NONE)
+	testl %ebx,%ebx				/* swapgs needed? */
+	jnz nmi_restore
+	testl $3,CS(%rsp)
+	jnz nmi_userspace
+nmi_swapgs:
+	SWAPGS_UNSAFE_STACK
+nmi_restore:
+	RESTORE_ALL 8
+	jmp irq_return
+nmi_userspace:
+	GET_THREAD_INFO(%rcx)
+	movl TI_flags(%rcx),%ebx
+	andl $_TIF_WORK_MASK,%ebx
+	jz nmi_swapgs
+	movq %rsp,%rdi			/* &pt_regs */
+	call sync_regs
+	movq %rax,%rsp			/* switch stack for scheduling */
+	testl $_TIF_NEED_RESCHED,%ebx
+	jnz nmi_schedule
+	movl %ebx,%edx			/* arg3: thread flags */
+	ENABLE_INTERRUPTS(CLBR_NONE)
+	xorl %esi,%esi 			/* arg2: oldset */
+	movq %rsp,%rdi 			/* arg1: &pt_regs */
+	call do_notify_resume
+	DISABLE_INTERRUPTS(CLBR_NONE)
+	jmp nmi_userspace
+nmi_schedule:
+	ENABLE_INTERRUPTS(CLBR_ANY)
+	call schedule
+	DISABLE_INTERRUPTS(CLBR_ANY)
+	jmp nmi_userspace
+	CFI_ENDPROC
+#else
+	jmp paranoid_exit
+	CFI_ENDPROC
+#endif
+END(nmi)
+
+ENTRY(ignore_sysret)
+	CFI_STARTPROC
+	mov $-ENOSYS,%eax
+	sysret
+	CFI_ENDPROC
+END(ignore_sysret)
+
+/*
+ * End of kprobes section
+ */
+	.popsection
diff --git a/arch/x86/kernel/es7000_32.c b/arch/x86/kernel/es7000_32.c
index 0aa2c44..53699c9 100644
--- a/arch/x86/kernel/es7000_32.c
+++ b/arch/x86/kernel/es7000_32.c
@@ -38,8 +38,11 @@
 #include <asm/io.h>
 #include <asm/nmi.h>
 #include <asm/smp.h>
+#include <asm/atomic.h>
 #include <asm/apicdef.h>
 #include <mach_mpparse.h>
+#include <asm/genapic.h>
+#include <asm/setup.h>
 
 /*
  * ES7000 chipsets
@@ -161,6 +164,43 @@
 	return gsi;
 }
 
+static int wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip)
+{
+	unsigned long vect = 0, psaival = 0;
+
+	if (psai == NULL)
+		return -1;
+
+	vect = ((unsigned long)__pa(eip)/0x1000) << 16;
+	psaival = (0x1000000 | vect | cpu);
+
+	while (*psai & 0x1000000)
+		;
+
+	*psai = psaival;
+
+	return 0;
+}
+
+static void noop_wait_for_deassert(atomic_t *deassert_not_used)
+{
+}
+
+static int __init es7000_update_genapic(void)
+{
+	genapic->wakeup_cpu = wakeup_secondary_cpu_via_mip;
+
+	/* MPENTIUMIII */
+	if (boot_cpu_data.x86 == 6 &&
+	    (boot_cpu_data.x86_model >= 7 || boot_cpu_data.x86_model <= 11)) {
+		es7000_update_genapic_to_cluster();
+		genapic->wait_for_init_deassert = noop_wait_for_deassert;
+		genapic->wakeup_cpu = wakeup_secondary_cpu_via_mip;
+	}
+
+	return 0;
+}
+
 void __init
 setup_unisys(void)
 {
@@ -176,6 +216,8 @@
 	else
 		es7000_plat = ES7000_CLASSIC;
 	ioapic_renumber_irq = es7000_rename_gsi;
+
+	x86_quirks->update_genapic = es7000_update_genapic;
 }
 
 /*
@@ -317,26 +359,6 @@
 	return status;
 }
 
-int
-es7000_start_cpu(int cpu, unsigned long eip)
-{
-	unsigned long vect = 0, psaival = 0;
-
-	if (psai == NULL)
-		return -1;
-
-	vect = ((unsigned long)__pa(eip)/0x1000) << 16;
-	psaival = (0x1000000 | vect | cpu);
-
-	while (*psai & 0x1000000)
-                ;
-
-	*psai = psaival;
-
-	return 0;
-
-}
-
 void __init
 es7000_sw_apic(void)
 {
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 50ea0ac..1b43086 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -14,14 +14,17 @@
 #include <linux/uaccess.h>
 #include <linux/ftrace.h>
 #include <linux/percpu.h>
+#include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/list.h>
 
 #include <asm/ftrace.h>
+#include <linux/ftrace.h>
 #include <asm/nops.h>
+#include <asm/nmi.h>
 
 
-static unsigned char ftrace_nop[MCOUNT_INSN_SIZE];
+#ifdef CONFIG_DYNAMIC_FTRACE
 
 union ftrace_code_union {
 	char code[MCOUNT_INSN_SIZE];
@@ -31,18 +34,12 @@
 	} __attribute__((packed));
 };
 
-
 static int ftrace_calc_offset(long ip, long addr)
 {
 	return (int)(addr - ip);
 }
 
-unsigned char *ftrace_nop_replace(void)
-{
-	return ftrace_nop;
-}
-
-unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
+static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
 {
 	static union ftrace_code_union calc;
 
@@ -56,7 +53,142 @@
 	return calc.code;
 }
 
-int
+/*
+ * Modifying code must take extra care. On an SMP machine, if
+ * the code being modified is also being executed on another CPU
+ * that CPU will have undefined results and possibly take a GPF.
+ * We use kstop_machine to stop other CPUS from exectuing code.
+ * But this does not stop NMIs from happening. We still need
+ * to protect against that. We separate out the modification of
+ * the code to take care of this.
+ *
+ * Two buffers are added: An IP buffer and a "code" buffer.
+ *
+ * 1) Put the instruction pointer into the IP buffer
+ *    and the new code into the "code" buffer.
+ * 2) Set a flag that says we are modifying code
+ * 3) Wait for any running NMIs to finish.
+ * 4) Write the code
+ * 5) clear the flag.
+ * 6) Wait for any running NMIs to finish.
+ *
+ * If an NMI is executed, the first thing it does is to call
+ * "ftrace_nmi_enter". This will check if the flag is set to write
+ * and if it is, it will write what is in the IP and "code" buffers.
+ *
+ * The trick is, it does not matter if everyone is writing the same
+ * content to the code location. Also, if a CPU is executing code
+ * it is OK to write to that code location if the contents being written
+ * are the same as what exists.
+ */
+
+static atomic_t in_nmi = ATOMIC_INIT(0);
+static int mod_code_status;		/* holds return value of text write */
+static int mod_code_write;		/* set when NMI should do the write */
+static void *mod_code_ip;		/* holds the IP to write to */
+static void *mod_code_newcode;		/* holds the text to write to the IP */
+
+static unsigned nmi_wait_count;
+static atomic_t nmi_update_count = ATOMIC_INIT(0);
+
+int ftrace_arch_read_dyn_info(char *buf, int size)
+{
+	int r;
+
+	r = snprintf(buf, size, "%u %u",
+		     nmi_wait_count,
+		     atomic_read(&nmi_update_count));
+	return r;
+}
+
+static void ftrace_mod_code(void)
+{
+	/*
+	 * Yes, more than one CPU process can be writing to mod_code_status.
+	 *    (and the code itself)
+	 * But if one were to fail, then they all should, and if one were
+	 * to succeed, then they all should.
+	 */
+	mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
+					     MCOUNT_INSN_SIZE);
+}
+
+void ftrace_nmi_enter(void)
+{
+	atomic_inc(&in_nmi);
+	/* Must have in_nmi seen before reading write flag */
+	smp_mb();
+	if (mod_code_write) {
+		ftrace_mod_code();
+		atomic_inc(&nmi_update_count);
+	}
+}
+
+void ftrace_nmi_exit(void)
+{
+	/* Finish all executions before clearing in_nmi */
+	smp_wmb();
+	atomic_dec(&in_nmi);
+}
+
+static void wait_for_nmi(void)
+{
+	int waited = 0;
+
+	while (atomic_read(&in_nmi)) {
+		waited = 1;
+		cpu_relax();
+	}
+
+	if (waited)
+		nmi_wait_count++;
+}
+
+static int
+do_ftrace_mod_code(unsigned long ip, void *new_code)
+{
+	mod_code_ip = (void *)ip;
+	mod_code_newcode = new_code;
+
+	/* The buffers need to be visible before we let NMIs write them */
+	smp_wmb();
+
+	mod_code_write = 1;
+
+	/* Make sure write bit is visible before we wait on NMIs */
+	smp_mb();
+
+	wait_for_nmi();
+
+	/* Make sure all running NMIs have finished before we write the code */
+	smp_mb();
+
+	ftrace_mod_code();
+
+	/* Make sure the write happens before clearing the bit */
+	smp_wmb();
+
+	mod_code_write = 0;
+
+	/* make sure NMIs see the cleared bit */
+	smp_mb();
+
+	wait_for_nmi();
+
+	return mod_code_status;
+}
+
+
+
+
+static unsigned char ftrace_nop[MCOUNT_INSN_SIZE];
+
+static unsigned char *ftrace_nop_replace(void)
+{
+	return ftrace_nop;
+}
+
+static int
 ftrace_modify_code(unsigned long ip, unsigned char *old_code,
 		   unsigned char *new_code)
 {
@@ -81,7 +213,7 @@
 		return -EINVAL;
 
 	/* replace the text with the new text */
-	if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
+	if (do_ftrace_mod_code(ip, new_code))
 		return -EPERM;
 
 	sync_core();
@@ -89,6 +221,29 @@
 	return 0;
 }
 
+int ftrace_make_nop(struct module *mod,
+		    struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned char *new, *old;
+	unsigned long ip = rec->ip;
+
+	old = ftrace_call_replace(ip, addr);
+	new = ftrace_nop_replace();
+
+	return ftrace_modify_code(rec->ip, old, new);
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned char *new, *old;
+	unsigned long ip = rec->ip;
+
+	old = ftrace_nop_replace();
+	new = ftrace_call_replace(ip, addr);
+
+	return ftrace_modify_code(rec->ip, old, new);
+}
+
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
 	unsigned long ip = (unsigned long)(&ftrace_call);
@@ -165,3 +320,218 @@
 
 	return 0;
 }
+#endif
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+extern void ftrace_graph_call(void);
+
+static int ftrace_mod_jmp(unsigned long ip,
+			  int old_offset, int new_offset)
+{
+	unsigned char code[MCOUNT_INSN_SIZE];
+
+	if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE))
+		return -EFAULT;
+
+	if (code[0] != 0xe9 || old_offset != *(int *)(&code[1]))
+		return -EINVAL;
+
+	*(int *)(&code[1]) = new_offset;
+
+	if (do_ftrace_mod_code(ip, &code))
+		return -EPERM;
+
+	return 0;
+}
+
+int ftrace_enable_ftrace_graph_caller(void)
+{
+	unsigned long ip = (unsigned long)(&ftrace_graph_call);
+	int old_offset, new_offset;
+
+	old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE);
+	new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE);
+
+	return ftrace_mod_jmp(ip, old_offset, new_offset);
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+	unsigned long ip = (unsigned long)(&ftrace_graph_call);
+	int old_offset, new_offset;
+
+	old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE);
+	new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE);
+
+	return ftrace_mod_jmp(ip, old_offset, new_offset);
+}
+
+#else /* CONFIG_DYNAMIC_FTRACE */
+
+/*
+ * These functions are picked from those used on
+ * this page for dynamic ftrace. They have been
+ * simplified to ignore all traces in NMI context.
+ */
+static atomic_t in_nmi;
+
+void ftrace_nmi_enter(void)
+{
+	atomic_inc(&in_nmi);
+}
+
+void ftrace_nmi_exit(void)
+{
+	atomic_dec(&in_nmi);
+}
+
+#endif /* !CONFIG_DYNAMIC_FTRACE */
+
+/* Add a function return address to the trace stack on thread info.*/
+static int push_return_trace(unsigned long ret, unsigned long long time,
+				unsigned long func, int *depth)
+{
+	int index;
+
+	if (!current->ret_stack)
+		return -EBUSY;
+
+	/* The return trace stack is full */
+	if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
+		atomic_inc(&current->trace_overrun);
+		return -EBUSY;
+	}
+
+	index = ++current->curr_ret_stack;
+	barrier();
+	current->ret_stack[index].ret = ret;
+	current->ret_stack[index].func = func;
+	current->ret_stack[index].calltime = time;
+	*depth = index;
+
+	return 0;
+}
+
+/* Retrieve a function return address to the trace stack on thread info.*/
+static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
+{
+	int index;
+
+	index = current->curr_ret_stack;
+
+	if (unlikely(index < 0)) {
+		ftrace_graph_stop();
+		WARN_ON(1);
+		/* Might as well panic, otherwise we have no where to go */
+		*ret = (unsigned long)panic;
+		return;
+	}
+
+	*ret = current->ret_stack[index].ret;
+	trace->func = current->ret_stack[index].func;
+	trace->calltime = current->ret_stack[index].calltime;
+	trace->overrun = atomic_read(&current->trace_overrun);
+	trace->depth = index;
+	barrier();
+	current->curr_ret_stack--;
+
+}
+
+/*
+ * Send the trace to the ring-buffer.
+ * @return the original return address.
+ */
+unsigned long ftrace_return_to_handler(void)
+{
+	struct ftrace_graph_ret trace;
+	unsigned long ret;
+
+	pop_return_trace(&trace, &ret);
+	trace.rettime = cpu_clock(raw_smp_processor_id());
+	ftrace_graph_return(&trace);
+
+	if (unlikely(!ret)) {
+		ftrace_graph_stop();
+		WARN_ON(1);
+		/* Might as well panic. What else to do? */
+		ret = (unsigned long)panic;
+	}
+
+	return ret;
+}
+
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in current thread info.
+ */
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
+{
+	unsigned long old;
+	unsigned long long calltime;
+	int faulted;
+	struct ftrace_graph_ent trace;
+	unsigned long return_hooker = (unsigned long)
+				&return_to_handler;
+
+	/* Nmi's are currently unsupported */
+	if (unlikely(atomic_read(&in_nmi)))
+		return;
+
+	if (unlikely(atomic_read(&current->tracing_graph_pause)))
+		return;
+
+	/*
+	 * Protect against fault, even if it shouldn't
+	 * happen. This tool is too much intrusive to
+	 * ignore such a protection.
+	 */
+	asm volatile(
+		"1: " _ASM_MOV " (%[parent_old]), %[old]\n"
+		"2: " _ASM_MOV " %[return_hooker], (%[parent_replaced])\n"
+		"   movl $0, %[faulted]\n"
+
+		".section .fixup, \"ax\"\n"
+		"3: movl $1, %[faulted]\n"
+		".previous\n"
+
+		_ASM_EXTABLE(1b, 3b)
+		_ASM_EXTABLE(2b, 3b)
+
+		: [parent_replaced] "=r" (parent), [old] "=r" (old),
+		  [faulted] "=r" (faulted)
+		: [parent_old] "0" (parent), [return_hooker] "r" (return_hooker)
+		: "memory"
+	);
+
+	if (unlikely(faulted)) {
+		ftrace_graph_stop();
+		WARN_ON(1);
+		return;
+	}
+
+	if (unlikely(!__kernel_text_address(old))) {
+		ftrace_graph_stop();
+		*parent = old;
+		WARN_ON(1);
+		return;
+	}
+
+	calltime = cpu_clock(raw_smp_processor_id());
+
+	if (push_return_trace(old, calltime,
+				self_addr, &trace.depth) == -EBUSY) {
+		*parent = old;
+		return;
+	}
+
+	trace.func = self_addr;
+
+	/* Only trace if the calling function expects to */
+	if (!ftrace_graph_entry(&trace)) {
+		current->curr_ret_stack--;
+		*parent = old;
+	}
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
diff --git a/arch/x86/kernel/genapic_64.c b/arch/x86/kernel/genapic_64.c
index 6c9bfc9..2bced78 100644
--- a/arch/x86/kernel/genapic_64.c
+++ b/arch/x86/kernel/genapic_64.c
@@ -21,6 +21,7 @@
 #include <asm/smp.h>
 #include <asm/ipi.h>
 #include <asm/genapic.h>
+#include <asm/setup.h>
 
 extern struct genapic apic_flat;
 extern struct genapic apic_physflat;
@@ -53,6 +54,9 @@
 			genapic = &apic_physflat;
 		printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
 	}
+
+	if (x86_quirks->update_genapic)
+		x86_quirks->update_genapic();
 }
 
 /* Same for both flat and physical. */
diff --git a/arch/x86/kernel/genx2apic_uv_x.c b/arch/x86/kernel/genx2apic_uv_x.c
index 2c7dbdb..dece172 100644
--- a/arch/x86/kernel/genx2apic_uv_x.c
+++ b/arch/x86/kernel/genx2apic_uv_x.c
@@ -10,6 +10,7 @@
 
 #include <linux/kernel.h>
 #include <linux/threads.h>
+#include <linux/cpu.h>
 #include <linux/cpumask.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
@@ -17,6 +18,9 @@
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/hardirq.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <asm/current.h>
 #include <asm/smp.h>
 #include <asm/ipi.h>
 #include <asm/genapic.h>
@@ -356,6 +360,103 @@
 }
 
 /*
+ * percpu heartbeat timer
+ */
+static void uv_heartbeat(unsigned long ignored)
+{
+	struct timer_list *timer = &uv_hub_info->scir.timer;
+	unsigned char bits = uv_hub_info->scir.state;
+
+	/* flip heartbeat bit */
+	bits ^= SCIR_CPU_HEARTBEAT;
+
+	/* is this cpu idle? */
+	if (idle_cpu(raw_smp_processor_id()))
+		bits &= ~SCIR_CPU_ACTIVITY;
+	else
+		bits |= SCIR_CPU_ACTIVITY;
+
+	/* update system controller interface reg */
+	uv_set_scir_bits(bits);
+
+	/* enable next timer period */
+	mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL);
+}
+
+static void __cpuinit uv_heartbeat_enable(int cpu)
+{
+	if (!uv_cpu_hub_info(cpu)->scir.enabled) {
+		struct timer_list *timer = &uv_cpu_hub_info(cpu)->scir.timer;
+
+		uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY);
+		setup_timer(timer, uv_heartbeat, cpu);
+		timer->expires = jiffies + SCIR_CPU_HB_INTERVAL;
+		add_timer_on(timer, cpu);
+		uv_cpu_hub_info(cpu)->scir.enabled = 1;
+	}
+
+	/* check boot cpu */
+	if (!uv_cpu_hub_info(0)->scir.enabled)
+		uv_heartbeat_enable(0);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void __cpuinit uv_heartbeat_disable(int cpu)
+{
+	if (uv_cpu_hub_info(cpu)->scir.enabled) {
+		uv_cpu_hub_info(cpu)->scir.enabled = 0;
+		del_timer(&uv_cpu_hub_info(cpu)->scir.timer);
+	}
+	uv_set_cpu_scir_bits(cpu, 0xff);
+}
+
+/*
+ * cpu hotplug notifier
+ */
+static __cpuinit int uv_scir_cpu_notify(struct notifier_block *self,
+				       unsigned long action, void *hcpu)
+{
+	long cpu = (long)hcpu;
+
+	switch (action) {
+	case CPU_ONLINE:
+		uv_heartbeat_enable(cpu);
+		break;
+	case CPU_DOWN_PREPARE:
+		uv_heartbeat_disable(cpu);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static __init void uv_scir_register_cpu_notifier(void)
+{
+	hotcpu_notifier(uv_scir_cpu_notify, 0);
+}
+
+#else /* !CONFIG_HOTPLUG_CPU */
+
+static __init void uv_scir_register_cpu_notifier(void)
+{
+}
+
+static __init int uv_init_heartbeat(void)
+{
+	int cpu;
+
+	if (is_uv_system())
+		for_each_online_cpu(cpu)
+			uv_heartbeat_enable(cpu);
+	return 0;
+}
+
+late_initcall(uv_init_heartbeat);
+
+#endif /* !CONFIG_HOTPLUG_CPU */
+
+/*
  * Called on each cpu to initialize the per_cpu UV data area.
  * 	ZZZ hotplug not supported yet
  */
@@ -428,7 +529,7 @@
 
 	uv_bios_init();
 	uv_bios_get_sn_info(0, &uv_type, &sn_partition_id,
-			    &uv_coherency_id, &uv_region_size);
+			    &sn_coherency_id, &sn_region_size);
 	uv_rtc_init();
 
 	for_each_present_cpu(cpu) {
@@ -439,8 +540,7 @@
 		uv_blade_info[blade].nr_possible_cpus++;
 
 		uv_cpu_hub_info(cpu)->lowmem_remap_base = lowmem_redir_base;
-		uv_cpu_hub_info(cpu)->lowmem_remap_top =
-					lowmem_redir_base + lowmem_redir_size;
+		uv_cpu_hub_info(cpu)->lowmem_remap_top = lowmem_redir_size;
 		uv_cpu_hub_info(cpu)->m_val = m_val;
 		uv_cpu_hub_info(cpu)->n_val = m_val;
 		uv_cpu_hub_info(cpu)->numa_blade_id = blade;
@@ -450,7 +550,8 @@
 		uv_cpu_hub_info(cpu)->gpa_mask = (1 << (m_val + n_val)) - 1;
 		uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper;
 		uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base;
-		uv_cpu_hub_info(cpu)->coherency_domain_number = uv_coherency_id;
+		uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id;
+		uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu;
 		uv_node_to_blade[nid] = blade;
 		uv_cpu_to_blade[cpu] = blade;
 		max_pnode = max(pnode, max_pnode);
@@ -467,4 +568,6 @@
 	map_mmioh_high(max_pnode);
 
 	uv_cpu_init();
+	uv_scir_register_cpu_notifier();
+	proc_mkdir("sgi_uv", NULL);
 }
diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c
index 1dcb0f1..3e66bd3 100644
--- a/arch/x86/kernel/head.c
+++ b/arch/x86/kernel/head.c
@@ -35,7 +35,6 @@
 
 	/* start of EBDA area */
 	ebda_addr = get_bios_ebda();
-	printk(KERN_INFO "BIOS EBDA/lowmem at: %08x/%08x\n", ebda_addr, lowmem);
 
 	/* Fixup: bios puts an EBDA in the top 64K segment */
 	/* of conventional memory, but does not adjust lowmem. */
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index fa1d25d..ac108d1 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -12,9 +12,12 @@
 #include <asm/sections.h>
 #include <asm/e820.h>
 #include <asm/bios_ebda.h>
+#include <asm/trampoline.h>
 
 void __init i386_start_kernel(void)
 {
+	reserve_trampoline_memory();
+
 	reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS");
 
 #ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index d16084f..388e05a 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -24,6 +24,7 @@
 #include <asm/kdebug.h>
 #include <asm/e820.h>
 #include <asm/bios_ebda.h>
+#include <asm/trampoline.h>
 
 /* boot cpu pda */
 static struct x8664_pda _boot_cpu_pda __read_mostly;
@@ -120,6 +121,8 @@
 {
 	copy_bootdata(__va(real_mode_data));
 
+	reserve_trampoline_memory();
+
 	reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS");
 
 #ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 067d8de..3f0a3ed 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -33,7 +33,9 @@
  * HPET address is set in acpi/boot.c, when an ACPI entry exists
  */
 unsigned long				hpet_address;
-unsigned long				hpet_num_timers;
+#ifdef CONFIG_PCI_MSI
+static unsigned long			hpet_num_timers;
+#endif
 static void __iomem			*hpet_virt_address;
 
 struct hpet_dev {
diff --git a/arch/x86/kernel/init_task.c b/arch/x86/kernel/init_task.c
index a4f93b4..d399180 100644
--- a/arch/x86/kernel/init_task.c
+++ b/arch/x86/kernel/init_task.c
@@ -14,7 +14,6 @@
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct mm_struct init_mm = INIT_MM(init_mm);
-EXPORT_UNUSED_SYMBOL(init_mm); /* will be removed in 2.6.26 */
 
 /*
  * Initial thread structure.
diff --git a/arch/x86/kernel/io_apic.c b/arch/x86/kernel/io_apic.c
index 9043251..679e7bb 100644
--- a/arch/x86/kernel/io_apic.c
+++ b/arch/x86/kernel/io_apic.c
@@ -2216,10 +2216,9 @@
 asmlinkage void smp_irq_move_cleanup_interrupt(void)
 {
 	unsigned vector, me;
+
 	ack_APIC_irq();
-#ifdef CONFIG_X86_64
 	exit_idle();
-#endif
 	irq_enter();
 
 	me = smp_processor_id();
diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c
index 60eb84e..1df869e 100644
--- a/arch/x86/kernel/irq_64.c
+++ b/arch/x86/kernel/irq_64.c
@@ -13,12 +13,12 @@
 #include <linux/seq_file.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/ftrace.h>
 #include <asm/uaccess.h>
 #include <asm/io_apic.h>
 #include <asm/idle.h>
 #include <asm/smp.h>
 
-#ifdef CONFIG_DEBUG_STACKOVERFLOW
 /*
  * Probabilistic stack overflow check:
  *
@@ -28,26 +28,25 @@
  */
 static inline void stack_overflow_check(struct pt_regs *regs)
 {
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
 	u64 curbase = (u64)task_stack_page(current);
-	static unsigned long warned = -60*HZ;
 
-	if (regs->sp >= curbase && regs->sp <= curbase + THREAD_SIZE &&
-	    regs->sp <  curbase + sizeof(struct thread_info) + 128 &&
-	    time_after(jiffies, warned + 60*HZ)) {
-		printk("do_IRQ: %s near stack overflow (cur:%Lx,sp:%lx)\n",
-		       current->comm, curbase, regs->sp);
-		show_stack(NULL,NULL);
-		warned = jiffies;
-	}
-}
+	WARN_ONCE(regs->sp >= curbase &&
+		  regs->sp <= curbase + THREAD_SIZE &&
+		  regs->sp <  curbase + sizeof(struct thread_info) +
+					sizeof(struct pt_regs) + 128,
+
+		  "do_IRQ: %s near stack overflow (cur:%Lx,sp:%lx)\n",
+			current->comm, curbase, regs->sp);
 #endif
+}
 
 /*
  * do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
-asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
+asmlinkage unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 	struct irq_desc *desc;
@@ -60,9 +59,7 @@
 	irq_enter();
 	irq = __get_cpu_var(vector_irq)[vector];
 
-#ifdef CONFIG_DEBUG_STACKOVERFLOW
 	stack_overflow_check(regs);
-#endif
 
 	desc = irq_to_desc(irq);
 	if (likely(desc))
diff --git a/arch/x86/kernel/irqinit_32.c b/arch/x86/kernel/irqinit_32.c
index 845aa98..607db63 100644
--- a/arch/x86/kernel/irqinit_32.c
+++ b/arch/x86/kernel/irqinit_32.c
@@ -129,7 +129,7 @@
 	for (i =  FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
 		/* SYSCALL_VECTOR was reserved in trap_init. */
 		if (i != SYSCALL_VECTOR)
-			set_intr_gate(i, interrupt[i]);
+			set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]);
 	}
 
 
diff --git a/arch/x86/kernel/irqinit_64.c b/arch/x86/kernel/irqinit_64.c
index ff02353..8670b3c 100644
--- a/arch/x86/kernel/irqinit_64.c
+++ b/arch/x86/kernel/irqinit_64.c
@@ -24,41 +24,6 @@
 #include <asm/i8259.h>
 
 /*
- * Common place to define all x86 IRQ vectors
- *
- * This builds up the IRQ handler stubs using some ugly macros in irq.h
- *
- * These macros create the low-level assembly IRQ routines that save
- * register context and call do_IRQ(). do_IRQ() then does all the
- * operations that are needed to keep the AT (or SMP IOAPIC)
- * interrupt-controller happy.
- */
-
-#define IRQ_NAME2(nr) nr##_interrupt(void)
-#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
-
-/*
- *	SMP has a few special interrupts for IPI messages
- */
-
-#define BUILD_IRQ(nr)				\
-	asmlinkage void IRQ_NAME(nr);		\
-	asm("\n.text\n.p2align\n"		\
-	    "IRQ" #nr "_interrupt:\n\t"		\
-	    "push $~(" #nr ") ; "		\
-	    "jmp common_interrupt\n"		\
-	    ".previous");
-
-#define BI(x,y) \
-	BUILD_IRQ(x##y)
-
-#define BUILD_16_IRQS(x) \
-	BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
-	BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
-	BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
-	BI(x,c) BI(x,d) BI(x,e) BI(x,f)
-
-/*
  * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
  * (these are usually mapped to vectors 0x30-0x3f)
  */
@@ -73,37 +38,6 @@
  *
  * (these are usually mapped into the 0x30-0xff vector range)
  */
-				      BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
-BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
-BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
-BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
-
-#undef BUILD_16_IRQS
-#undef BI
-
-
-#define IRQ(x,y) \
-	IRQ##x##y##_interrupt
-
-#define IRQLIST_16(x) \
-	IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
-	IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
-	IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
-	IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
-
-/* for the irq vectors */
-static void (*__initdata interrupt[NR_VECTORS - FIRST_EXTERNAL_VECTOR])(void) = {
-					  IRQLIST_16(0x2), IRQLIST_16(0x3),
-	IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
-	IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
-	IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
-};
-
-#undef IRQ
-#undef IRQLIST_16
-
-
-
 
 /*
  * IRQ2 is cascade interrupt to second interrupt controller
diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c
index 7a38574..37f4200 100644
--- a/arch/x86/kernel/machine_kexec_32.c
+++ b/arch/x86/kernel/machine_kexec_32.c
@@ -13,6 +13,7 @@
 #include <linux/numa.h>
 #include <linux/ftrace.h>
 #include <linux/suspend.h>
+#include <linux/gfp.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -25,15 +26,6 @@
 #include <asm/system.h>
 #include <asm/cacheflush.h>
 
-#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
-static u32 kexec_pgd[1024] PAGE_ALIGNED;
-#ifdef CONFIG_X86_PAE
-static u32 kexec_pmd0[1024] PAGE_ALIGNED;
-static u32 kexec_pmd1[1024] PAGE_ALIGNED;
-#endif
-static u32 kexec_pte0[1024] PAGE_ALIGNED;
-static u32 kexec_pte1[1024] PAGE_ALIGNED;
-
 static void set_idt(void *newidt, __u16 limit)
 {
 	struct desc_ptr curidt;
@@ -76,6 +68,76 @@
 #undef __STR
 }
 
+static void machine_kexec_free_page_tables(struct kimage *image)
+{
+	free_page((unsigned long)image->arch.pgd);
+#ifdef CONFIG_X86_PAE
+	free_page((unsigned long)image->arch.pmd0);
+	free_page((unsigned long)image->arch.pmd1);
+#endif
+	free_page((unsigned long)image->arch.pte0);
+	free_page((unsigned long)image->arch.pte1);
+}
+
+static int machine_kexec_alloc_page_tables(struct kimage *image)
+{
+	image->arch.pgd = (pgd_t *)get_zeroed_page(GFP_KERNEL);
+#ifdef CONFIG_X86_PAE
+	image->arch.pmd0 = (pmd_t *)get_zeroed_page(GFP_KERNEL);
+	image->arch.pmd1 = (pmd_t *)get_zeroed_page(GFP_KERNEL);
+#endif
+	image->arch.pte0 = (pte_t *)get_zeroed_page(GFP_KERNEL);
+	image->arch.pte1 = (pte_t *)get_zeroed_page(GFP_KERNEL);
+	if (!image->arch.pgd ||
+#ifdef CONFIG_X86_PAE
+	    !image->arch.pmd0 || !image->arch.pmd1 ||
+#endif
+	    !image->arch.pte0 || !image->arch.pte1) {
+		machine_kexec_free_page_tables(image);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void machine_kexec_page_table_set_one(
+	pgd_t *pgd, pmd_t *pmd, pte_t *pte,
+	unsigned long vaddr, unsigned long paddr)
+{
+	pud_t *pud;
+
+	pgd += pgd_index(vaddr);
+#ifdef CONFIG_X86_PAE
+	if (!(pgd_val(*pgd) & _PAGE_PRESENT))
+		set_pgd(pgd, __pgd(__pa(pmd) | _PAGE_PRESENT));
+#endif
+	pud = pud_offset(pgd, vaddr);
+	pmd = pmd_offset(pud, vaddr);
+	if (!(pmd_val(*pmd) & _PAGE_PRESENT))
+		set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE));
+	pte = pte_offset_kernel(pmd, vaddr);
+	set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL_EXEC));
+}
+
+static void machine_kexec_prepare_page_tables(struct kimage *image)
+{
+	void *control_page;
+	pmd_t *pmd = 0;
+
+	control_page = page_address(image->control_code_page);
+#ifdef CONFIG_X86_PAE
+	pmd = image->arch.pmd0;
+#endif
+	machine_kexec_page_table_set_one(
+		image->arch.pgd, pmd, image->arch.pte0,
+		(unsigned long)control_page, __pa(control_page));
+#ifdef CONFIG_X86_PAE
+	pmd = image->arch.pmd1;
+#endif
+	machine_kexec_page_table_set_one(
+		image->arch.pgd, pmd, image->arch.pte1,
+		__pa(control_page), __pa(control_page));
+}
+
 /*
  * A architecture hook called to validate the
  * proposed image and prepare the control pages
@@ -87,12 +149,20 @@
  * reboot code buffer to allow us to avoid allocations
  * later.
  *
- * Make control page executable.
+ * - Make control page executable.
+ * - Allocate page tables
+ * - Setup page tables
  */
 int machine_kexec_prepare(struct kimage *image)
 {
+	int error;
+
 	if (nx_enabled)
 		set_pages_x(image->control_code_page, 1);
+	error = machine_kexec_alloc_page_tables(image);
+	if (error)
+		return error;
+	machine_kexec_prepare_page_tables(image);
 	return 0;
 }
 
@@ -104,6 +174,7 @@
 {
 	if (nx_enabled)
 		set_pages_nx(image->control_code_page, 1);
+	machine_kexec_free_page_tables(image);
 }
 
 /*
@@ -150,18 +221,7 @@
 	relocate_kernel_ptr = control_page;
 	page_list[PA_CONTROL_PAGE] = __pa(control_page);
 	page_list[VA_CONTROL_PAGE] = (unsigned long)control_page;
-	page_list[PA_PGD] = __pa(kexec_pgd);
-	page_list[VA_PGD] = (unsigned long)kexec_pgd;
-#ifdef CONFIG_X86_PAE
-	page_list[PA_PMD_0] = __pa(kexec_pmd0);
-	page_list[VA_PMD_0] = (unsigned long)kexec_pmd0;
-	page_list[PA_PMD_1] = __pa(kexec_pmd1);
-	page_list[VA_PMD_1] = (unsigned long)kexec_pmd1;
-#endif
-	page_list[PA_PTE_0] = __pa(kexec_pte0);
-	page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
-	page_list[PA_PTE_1] = __pa(kexec_pte1);
-	page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
+	page_list[PA_PGD] = __pa(image->arch.pgd);
 
 	if (image->type == KEXEC_TYPE_DEFAULT)
 		page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page)
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index 5f8e5d7..c25fdb3 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -10,7 +10,7 @@
  *  This driver allows to upgrade microcode on AMD
  *  family 0x10 and 0x11 processors.
  *
- *  Licensed unter the terms of the GNU General Public
+ *  Licensed under the terms of the GNU General Public
  *  License version 2. See file COPYING for details.
 */
 
@@ -32,9 +32,9 @@
 #include <linux/platform_device.h>
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
+#include <linux/uaccess.h>
 
 #include <asm/msr.h>
-#include <asm/uaccess.h>
 #include <asm/processor.h>
 #include <asm/microcode.h>
 
@@ -47,43 +47,38 @@
 #define UCODE_UCODE_TYPE           0x00000001
 
 struct equiv_cpu_entry {
-	unsigned int installed_cpu;
-	unsigned int fixed_errata_mask;
-	unsigned int fixed_errata_compare;
-	unsigned int equiv_cpu;
-};
+	u32	installed_cpu;
+	u32	fixed_errata_mask;
+	u32	fixed_errata_compare;
+	u16	equiv_cpu;
+	u16	res;
+} __attribute__((packed));
 
 struct microcode_header_amd {
-	unsigned int  data_code;
-	unsigned int  patch_id;
-	unsigned char mc_patch_data_id[2];
-	unsigned char mc_patch_data_len;
-	unsigned char init_flag;
-	unsigned int  mc_patch_data_checksum;
-	unsigned int  nb_dev_id;
-	unsigned int  sb_dev_id;
-	unsigned char processor_rev_id[2];
-	unsigned char nb_rev_id;
-	unsigned char sb_rev_id;
-	unsigned char bios_api_rev;
-	unsigned char reserved1[3];
-	unsigned int  match_reg[8];
-};
+	u32	data_code;
+	u32	patch_id;
+	u16	mc_patch_data_id;
+	u8	mc_patch_data_len;
+	u8	init_flag;
+	u32	mc_patch_data_checksum;
+	u32	nb_dev_id;
+	u32	sb_dev_id;
+	u16	processor_rev_id;
+	u8	nb_rev_id;
+	u8	sb_rev_id;
+	u8	bios_api_rev;
+	u8	reserved1[3];
+	u32	match_reg[8];
+} __attribute__((packed));
 
 struct microcode_amd {
 	struct microcode_header_amd hdr;
 	unsigned int mpb[0];
 };
 
-#define UCODE_MAX_SIZE          (2048)
-#define DEFAULT_UCODE_DATASIZE	(896)
-#define MC_HEADER_SIZE		(sizeof(struct microcode_header_amd))
-#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
-#define DWSIZE			(sizeof(u32))
-/* For now we support a fixed ucode total size only */
-#define get_totalsize(mc) \
-	((((struct microcode_amd *)mc)->hdr.mc_patch_data_len * 28) \
-	 + MC_HEADER_SIZE)
+#define UCODE_MAX_SIZE			2048
+#define UCODE_CONTAINER_SECTION_HDR	8
+#define UCODE_CONTAINER_HEADER_SIZE	12
 
 /* serialize access to the physical write */
 static DEFINE_SPINLOCK(microcode_update_lock);
@@ -93,31 +88,24 @@
 static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
 {
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
+	u32 dummy;
 
 	memset(csig, 0, sizeof(*csig));
-
 	if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
-		printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n",
-		       cpu);
+		printk(KERN_WARNING "microcode: CPU%d: AMD CPU family 0x%x not "
+		       "supported\n", cpu, c->x86);
 		return -1;
 	}
-
-	asm volatile("movl %1, %%ecx; rdmsr"
-		     : "=a" (csig->rev)
-		     : "i" (0x0000008B) : "ecx");
-
-	printk(KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n",
-		csig->rev);
-
+	rdmsr(MSR_AMD64_PATCH_LEVEL, csig->rev, dummy);
+	printk(KERN_INFO "microcode: CPU%d: patch_level=0x%x\n", cpu, csig->rev);
 	return 0;
 }
 
 static int get_matching_microcode(int cpu, void *mc, int rev)
 {
 	struct microcode_header_amd *mc_header = mc;
-	struct pci_dev *nb_pci_dev, *sb_pci_dev;
 	unsigned int current_cpu_id;
-	unsigned int equiv_cpu_id = 0x00;
+	u16 equiv_cpu_id = 0;
 	unsigned int i = 0;
 
 	BUG_ON(equiv_cpu_table == NULL);
@@ -132,57 +120,25 @@
 	}
 
 	if (!equiv_cpu_id) {
-		printk(KERN_ERR "microcode: CPU%d cpu_id "
-		       "not found in equivalent cpu table \n", cpu);
+		printk(KERN_WARNING "microcode: CPU%d: cpu revision "
+		       "not listed in equivalent cpu table\n", cpu);
 		return 0;
 	}
 
-	if ((mc_header->processor_rev_id[0]) != (equiv_cpu_id & 0xff)) {
-		printk(KERN_ERR
-			"microcode: CPU%d patch does not match "
-			"(patch is %x, cpu extended is %x) \n",
-			cpu, mc_header->processor_rev_id[0],
-			(equiv_cpu_id & 0xff));
+	if (mc_header->processor_rev_id != equiv_cpu_id) {
+		printk(KERN_ERR	"microcode: CPU%d: patch mismatch "
+		       "(processor_rev_id: %x, equiv_cpu_id: %x)\n",
+		       cpu, mc_header->processor_rev_id, equiv_cpu_id);
 		return 0;
 	}
 
-	if ((mc_header->processor_rev_id[1]) != ((equiv_cpu_id >> 16) & 0xff)) {
-		printk(KERN_ERR "microcode: CPU%d patch does not match "
-			"(patch is %x, cpu base id is %x) \n",
-			cpu, mc_header->processor_rev_id[1],
-			((equiv_cpu_id >> 16) & 0xff));
-
+	/* ucode might be chipset specific -- currently we don't support this */
+	if (mc_header->nb_dev_id || mc_header->sb_dev_id) {
+		printk(KERN_ERR "microcode: CPU%d: loading of chipset "
+		       "specific code not yet supported\n", cpu);
 		return 0;
 	}
 
-	/* ucode may be northbridge specific */
-	if (mc_header->nb_dev_id) {
-		nb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
-					    (mc_header->nb_dev_id & 0xff),
-					    NULL);
-		if ((!nb_pci_dev) ||
-		    (mc_header->nb_rev_id != nb_pci_dev->revision)) {
-			printk(KERN_ERR "microcode: CPU%d NB mismatch \n", cpu);
-			pci_dev_put(nb_pci_dev);
-			return 0;
-		}
-		pci_dev_put(nb_pci_dev);
-	}
-
-	/* ucode may be southbridge specific */
-	if (mc_header->sb_dev_id) {
-		sb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
-					    (mc_header->sb_dev_id & 0xff),
-					    NULL);
-		if ((!sb_pci_dev) ||
-		    (mc_header->sb_rev_id != sb_pci_dev->revision)) {
-			printk(KERN_ERR "microcode: CPU%d SB mismatch \n", cpu);
-			pci_dev_put(sb_pci_dev);
-			return 0;
-		}
-		pci_dev_put(sb_pci_dev);
-	}
-
 	if (mc_header->patch_id <= rev)
 		return 0;
 
@@ -192,12 +148,10 @@
 static void apply_microcode_amd(int cpu)
 {
 	unsigned long flags;
-	unsigned int eax, edx;
-	unsigned int rev;
+	u32 rev, dummy;
 	int cpu_num = raw_smp_processor_id();
 	struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
 	struct microcode_amd *mc_amd = uci->mc;
-	unsigned long addr;
 
 	/* We should bind the task to the CPU */
 	BUG_ON(cpu_num != cpu);
@@ -206,42 +160,34 @@
 		return;
 
 	spin_lock_irqsave(&microcode_update_lock, flags);
-
-	addr = (unsigned long)&mc_amd->hdr.data_code;
-	edx = (unsigned int)(((unsigned long)upper_32_bits(addr)));
-	eax = (unsigned int)(((unsigned long)lower_32_bits(addr)));
-
-	asm volatile("movl %0, %%ecx; wrmsr" :
-		     : "i" (0xc0010020), "a" (eax), "d" (edx) : "ecx");
-
+	wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code);
 	/* get patch id after patching */
-	asm volatile("movl %1, %%ecx; rdmsr"
-		     : "=a" (rev)
-		     : "i" (0x0000008B) : "ecx");
-
+	rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
 	spin_unlock_irqrestore(&microcode_update_lock, flags);
 
 	/* check current patch id and patch's id for match */
 	if (rev != mc_amd->hdr.patch_id) {
-		printk(KERN_ERR "microcode: CPU%d update from revision "
-		       "0x%x to 0x%x failed\n", cpu_num,
-		       mc_amd->hdr.patch_id, rev);
+		printk(KERN_ERR "microcode: CPU%d: update failed "
+		       "(for patch_level=0x%x)\n", cpu, mc_amd->hdr.patch_id);
 		return;
 	}
 
-	printk(KERN_INFO "microcode: CPU%d updated from revision "
-	       "0x%x to 0x%x \n",
-	       cpu_num, uci->cpu_sig.rev, mc_amd->hdr.patch_id);
+	printk(KERN_INFO "microcode: CPU%d: updated (new patch_level=0x%x)\n",
+	       cpu, rev);
 
 	uci->cpu_sig.rev = rev;
 }
 
-static void * get_next_ucode(u8 *buf, unsigned int size,
-			int (*get_ucode_data)(void *, const void *, size_t),
-			unsigned int *mc_size)
+static int get_ucode_data(void *to, const u8 *from, size_t n)
+{
+	memcpy(to, from, n);
+	return 0;
+}
+
+static void *get_next_ucode(const u8 *buf, unsigned int size,
+			    unsigned int *mc_size)
 {
 	unsigned int total_size;
-#define UCODE_CONTAINER_SECTION_HDR	8
 	u8 section_hdr[UCODE_CONTAINER_SECTION_HDR];
 	void *mc;
 
@@ -249,39 +195,37 @@
 		return NULL;
 
 	if (section_hdr[0] != UCODE_UCODE_TYPE) {
-		printk(KERN_ERR "microcode: error! "
-		       "Wrong microcode payload type field\n");
+		printk(KERN_ERR "microcode: error: invalid type field in "
+		       "container file section header\n");
 		return NULL;
 	}
 
 	total_size = (unsigned long) (section_hdr[4] + (section_hdr[5] << 8));
 
-	printk(KERN_INFO "microcode: size %u, total_size %u\n",
-		size, total_size);
+	printk(KERN_DEBUG "microcode: size %u, total_size %u\n",
+	       size, total_size);
 
 	if (total_size > size || total_size > UCODE_MAX_SIZE) {
-		printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+		printk(KERN_ERR "microcode: error: size mismatch\n");
 		return NULL;
 	}
 
 	mc = vmalloc(UCODE_MAX_SIZE);
 	if (mc) {
 		memset(mc, 0, UCODE_MAX_SIZE);
-		if (get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, total_size)) {
+		if (get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR,
+				   total_size)) {
 			vfree(mc);
 			mc = NULL;
 		} else
 			*mc_size = total_size + UCODE_CONTAINER_SECTION_HDR;
 	}
-#undef UCODE_CONTAINER_SECTION_HDR
 	return mc;
 }
 
 
-static int install_equiv_cpu_table(u8 *buf,
-		int (*get_ucode_data)(void *, const void *, size_t))
+static int install_equiv_cpu_table(const u8 *buf)
 {
-#define UCODE_CONTAINER_HEADER_SIZE	12
 	u8 *container_hdr[UCODE_CONTAINER_HEADER_SIZE];
 	unsigned int *buf_pos = (unsigned int *)container_hdr;
 	unsigned long size;
@@ -292,14 +236,15 @@
 	size = buf_pos[2];
 
 	if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE || !size) {
-		printk(KERN_ERR "microcode: error! "
-		       "Wrong microcode equivalnet cpu table\n");
+		printk(KERN_ERR "microcode: error: invalid type field in "
+		       "container file section header\n");
 		return 0;
 	}
 
 	equiv_cpu_table = (struct equiv_cpu_entry *) vmalloc(size);
 	if (!equiv_cpu_table) {
-		printk(KERN_ERR "microcode: error, can't allocate memory for equiv CPU table\n");
+		printk(KERN_ERR "microcode: failed to allocate "
+		       "equivalent CPU table\n");
 		return 0;
 	}
 
@@ -310,7 +255,6 @@
 	}
 
 	return size + UCODE_CONTAINER_HEADER_SIZE; /* add header length */
-#undef UCODE_CONTAINER_HEADER_SIZE
 }
 
 static void free_equiv_cpu_table(void)
@@ -321,18 +265,20 @@
 	}
 }
 
-static int generic_load_microcode(int cpu, void *data, size_t size,
-		int (*get_ucode_data)(void *, const void *, size_t))
+static int generic_load_microcode(int cpu, const u8 *data, size_t size)
 {
 	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-	u8 *ucode_ptr = data, *new_mc = NULL, *mc;
+	const u8 *ucode_ptr = data;
+	void *new_mc = NULL;
+	void *mc;
 	int new_rev = uci->cpu_sig.rev;
 	unsigned int leftover;
 	unsigned long offset;
 
-	offset = install_equiv_cpu_table(ucode_ptr, get_ucode_data);
+	offset = install_equiv_cpu_table(ucode_ptr);
 	if (!offset) {
-		printk(KERN_ERR "microcode: installing equivalent cpu table failed\n");
+		printk(KERN_ERR "microcode: failed to create "
+		       "equivalent cpu table\n");
 		return -EINVAL;
 	}
 
@@ -343,7 +289,7 @@
 		unsigned int uninitialized_var(mc_size);
 		struct microcode_header_amd *mc_header;
 
-		mc = get_next_ucode(ucode_ptr, leftover, get_ucode_data, &mc_size);
+		mc = get_next_ucode(ucode_ptr, leftover, &mc_size);
 		if (!mc)
 			break;
 
@@ -353,7 +299,7 @@
 				vfree(new_mc);
 			new_rev = mc_header->patch_id;
 			new_mc  = mc;
-		} else 
+		} else
 			vfree(mc);
 
 		ucode_ptr += mc_size;
@@ -365,9 +311,9 @@
 			if (uci->mc)
 				vfree(uci->mc);
 			uci->mc = new_mc;
-			pr_debug("microcode: CPU%d found a matching microcode update with"
-				" version 0x%x (current=0x%x)\n",
-				cpu, new_rev, uci->cpu_sig.rev);
+			pr_debug("microcode: CPU%d found a matching microcode "
+				 "update with version 0x%x (current=0x%x)\n",
+				 cpu, new_rev, uci->cpu_sig.rev);
 		} else
 			vfree(new_mc);
 	}
@@ -377,12 +323,6 @@
 	return (int)leftover;
 }
 
-static int get_ucode_fw(void *to, const void *from, size_t n)
-{
-	memcpy(to, from, n);
-	return 0;
-}
-
 static int request_microcode_fw(int cpu, struct device *device)
 {
 	const char *fw_name = "amd-ucode/microcode_amd.bin";
@@ -394,12 +334,11 @@
 
 	ret = request_firmware(&firmware, fw_name, device);
 	if (ret) {
-		printk(KERN_ERR "microcode: ucode data file %s load failed\n", fw_name);
+		printk(KERN_ERR "microcode: failed to load file %s\n", fw_name);
 		return ret;
 	}
 
-	ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
-			&get_ucode_fw);
+	ret = generic_load_microcode(cpu, firmware->data, firmware->size);
 
 	release_firmware(firmware);
 
@@ -408,8 +347,8 @@
 
 static int request_microcode_user(int cpu, const void __user *buf, size_t size)
 {
-	printk(KERN_WARNING "microcode: AMD microcode update via /dev/cpu/microcode"
-			"is not supported\n");
+	printk(KERN_INFO "microcode: AMD microcode update via "
+	       "/dev/cpu/microcode not supported\n");
 	return -1;
 }
 
@@ -433,3 +372,4 @@
 {
 	return &microcode_amd_ops;
 }
+
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
index c4b5b24..c9b721b 100644
--- a/arch/x86/kernel/microcode_core.c
+++ b/arch/x86/kernel/microcode_core.c
@@ -99,7 +99,7 @@
 
 #define MICROCODE_VERSION 	"2.00"
 
-struct microcode_ops *microcode_ops;
+static struct microcode_ops *microcode_ops;
 
 /* no concurrent ->write()s are allowed on /dev/cpu/microcode */
 static DEFINE_MUTEX(microcode_mutex);
@@ -203,7 +203,7 @@
 #endif
 
 /* fake device for request_firmware */
-struct platform_device *microcode_pdev;
+static struct platform_device *microcode_pdev;
 
 static ssize_t reload_store(struct sys_device *dev,
 			    struct sysdev_attribute *attr,
@@ -328,7 +328,7 @@
 	return 0;
 }
 
-void microcode_update_cpu(int cpu)
+static void microcode_update_cpu(int cpu)
 {
 	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 	int err = 0;
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
index a8e6279..b7f4c92 100644
--- a/arch/x86/kernel/microcode_intel.c
+++ b/arch/x86/kernel/microcode_intel.c
@@ -471,7 +471,7 @@
 	uci->mc = NULL;
 }
 
-struct microcode_ops microcode_intel_ops = {
+static struct microcode_ops microcode_intel_ops = {
 	.request_microcode_user		  = request_microcode_user,
 	.request_microcode_fw             = request_microcode_fw,
 	.collect_cpu_info                 = collect_cpu_info,
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index 0f4c1fd..45e3b69 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -586,26 +586,23 @@
 {
 	struct intel_mp_floating *mpf = mpf_found;
 
+	if (!mpf)
+		return;
+
+	if (acpi_lapic && early)
+		return;
+
+	/*
+	 * MPS doesn't support hyperthreading, aka only have
+	 * thread 0 apic id in MPS table
+	 */
+	if (acpi_lapic && acpi_ioapic)
+		return;
+
 	if (x86_quirks->mach_get_smp_config) {
 		if (x86_quirks->mach_get_smp_config(early))
 			return;
 	}
-	if (acpi_lapic && early)
-		return;
-	/*
-	 * ACPI supports both logical (e.g. Hyper-Threading) and physical
-	 * processors, where MPS only supports physical.
-	 */
-	if (acpi_lapic && acpi_ioapic) {
-		printk(KERN_INFO "Using ACPI (MADT) for SMP configuration "
-		       "information\n");
-		return;
-	} else if (acpi_lapic)
-		printk(KERN_INFO "Using ACPI for processor (LAPIC) "
-		       "configuration information\n");
-
-	if (!mpf)
-		return;
 
 	printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n",
 	       mpf->mpf_specification);
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index 2c97f07..8bd1bf9 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -131,6 +131,11 @@
 	atomic_dec(&nmi_active);
 }
 
+static void __acpi_nmi_disable(void *__unused)
+{
+	apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
+}
+
 int __init check_nmi_watchdog(void)
 {
 	unsigned int *prev_nmi_count;
@@ -179,8 +184,12 @@
 	kfree(prev_nmi_count);
 	return 0;
 error:
-	if (nmi_watchdog == NMI_IO_APIC && !timer_through_8259)
-		disable_8259A_irq(0);
+	if (nmi_watchdog == NMI_IO_APIC) {
+		if (!timer_through_8259)
+			disable_8259A_irq(0);
+		on_each_cpu(__acpi_nmi_disable, NULL, 1);
+	}
+
 #ifdef CONFIG_X86_32
 	timer_ack = 0;
 #endif
@@ -199,12 +208,17 @@
 		++str;
 	}
 
-	get_option(&str, &nmi);
+	if (!strncmp(str, "lapic", 5))
+		nmi_watchdog = NMI_LOCAL_APIC;
+	else if (!strncmp(str, "ioapic", 6))
+		nmi_watchdog = NMI_IO_APIC;
+	else {
+		get_option(&str, &nmi);
+		if (nmi >= NMI_INVALID)
+			return 0;
+		nmi_watchdog = nmi;
+	}
 
-	if (nmi >= NMI_INVALID)
-		return 0;
-
-	nmi_watchdog = nmi;
 	return 1;
 }
 __setup("nmi_watchdog=", setup_nmi_watchdog);
@@ -285,11 +299,6 @@
 		on_each_cpu(__acpi_nmi_enable, NULL, 1);
 }
 
-static void __acpi_nmi_disable(void *__unused)
-{
-	apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
-}
-
 /*
  * Disable timer based NMIs on all CPUs:
  */
@@ -340,6 +349,8 @@
 		return;
 	if (nmi_watchdog == NMI_LOCAL_APIC)
 		lapic_watchdog_stop();
+	else
+		__acpi_nmi_disable(NULL);
 	__get_cpu_var(wd_enabled) = 0;
 	atomic_dec(&nmi_active);
 }
@@ -465,6 +476,24 @@
 
 #ifdef CONFIG_SYSCTL
 
+static void enable_ioapic_nmi_watchdog_single(void *unused)
+{
+	__get_cpu_var(wd_enabled) = 1;
+	atomic_inc(&nmi_active);
+	__acpi_nmi_enable(NULL);
+}
+
+static void enable_ioapic_nmi_watchdog(void)
+{
+	on_each_cpu(enable_ioapic_nmi_watchdog_single, NULL, 1);
+	touch_nmi_watchdog();
+}
+
+static void disable_ioapic_nmi_watchdog(void)
+{
+	on_each_cpu(stop_apic_nmi_watchdog, NULL, 1);
+}
+
 static int __init setup_unknown_nmi_panic(char *str)
 {
 	unknown_nmi_panic = 1;
@@ -507,6 +536,11 @@
 			enable_lapic_nmi_watchdog();
 		else
 			disable_lapic_nmi_watchdog();
+	} else if (nmi_watchdog == NMI_IO_APIC) {
+		if (nmi_watchdog_enabled)
+			enable_ioapic_nmi_watchdog();
+		else
+			disable_ioapic_nmi_watchdog();
 	} else {
 		printk(KERN_WARNING
 			"NMI watchdog doesn't know what hardware to touch\n");
diff --git a/arch/x86/kernel/numaq_32.c b/arch/x86/kernel/numaq_32.c
index 4caff39..0deea37 100644
--- a/arch/x86/kernel/numaq_32.c
+++ b/arch/x86/kernel/numaq_32.c
@@ -31,7 +31,7 @@
 #include <asm/numaq.h>
 #include <asm/topology.h>
 #include <asm/processor.h>
-#include <asm/mpspec.h>
+#include <asm/genapic.h>
 #include <asm/e820.h>
 #include <asm/setup.h>
 
@@ -235,6 +235,13 @@
 	return 1;
 }
 
+static int __init numaq_update_genapic(void)
+{
+	genapic->wakeup_cpu = wakeup_secondary_cpu_via_nmi;
+
+	return 0;
+}
+
 static struct x86_quirks numaq_x86_quirks __initdata = {
 	.arch_pre_time_init	= numaq_pre_time_init,
 	.arch_time_init		= NULL,
@@ -250,6 +257,7 @@
 	.mpc_oem_pci_bus	= mpc_oem_pci_bus,
 	.smp_read_mpc_oem	= smp_read_mpc_oem,
 	.setup_ioapic_ids	= numaq_setup_ioapic_ids,
+	.update_genapic		= numaq_update_genapic,
 };
 
 void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 1926248..7a3dfce 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -6,6 +6,7 @@
 #include <asm/proto.h>
 #include <asm/dma.h>
 #include <asm/iommu.h>
+#include <asm/gart.h>
 #include <asm/calgary.h>
 #include <asm/amd_iommu.h>
 
@@ -30,11 +31,6 @@
 /* Set this to 1 if there is a HW IOMMU in the system */
 int iommu_detected __read_mostly = 0;
 
-/* This tells the BIO block layer to assume merging. Default to off
-   because we cannot guarantee merging later. */
-int iommu_bio_merge __read_mostly = 0;
-EXPORT_SYMBOL(iommu_bio_merge);
-
 dma_addr_t bad_dma_address __read_mostly = 0;
 EXPORT_SYMBOL(bad_dma_address);
 
@@ -188,7 +184,6 @@
 		}
 
 		if (!strncmp(p, "biomerge", 8)) {
-			iommu_bio_merge = 4096;
 			iommu_merge = 1;
 			force_iommu = 1;
 		}
@@ -300,8 +295,8 @@
 static __devinit void via_no_dac(struct pci_dev *dev)
 {
 	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) {
-		printk(KERN_INFO "PCI: VIA PCI bridge detected."
-				 "Disabling DAC.\n");
+		printk(KERN_INFO
+			"PCI: VIA PCI bridge detected. Disabling DAC.\n");
 		forbid_dac = 1;
 	}
 }
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index c622772..e68bb9e 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -1,13 +1,16 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <asm/idle.h>
 #include <linux/smp.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/pm.h>
 #include <linux/clockchips.h>
+#include <linux/ftrace.h>
 #include <asm/system.h>
+#include <asm/apic.h>
 
 unsigned long idle_halt;
 EXPORT_SYMBOL(idle_halt);
@@ -100,6 +103,9 @@
 void default_idle(void)
 {
 	if (hlt_use_halt()) {
+		struct power_trace it;
+
+		trace_power_start(&it, POWER_CSTATE, 1);
 		current_thread_info()->status &= ~TS_POLLING;
 		/*
 		 * TS_POLLING-cleared state must be visible before we
@@ -112,6 +118,7 @@
 		else
 			local_irq_enable();
 		current_thread_info()->status |= TS_POLLING;
+		trace_power_end(&it);
 	} else {
 		local_irq_enable();
 		/* loop is done by the caller */
@@ -122,6 +129,21 @@
 EXPORT_SYMBOL(default_idle);
 #endif
 
+void stop_this_cpu(void *dummy)
+{
+	local_irq_disable();
+	/*
+	 * Remove this CPU:
+	 */
+	cpu_clear(smp_processor_id(), cpu_online_map);
+	disable_local_APIC();
+
+	for (;;) {
+		if (hlt_works(smp_processor_id()))
+			halt();
+	}
+}
+
 static void do_nothing(void *unused)
 {
 }
@@ -154,24 +176,31 @@
  */
 void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
 {
+	struct power_trace it;
+
+	trace_power_start(&it, POWER_CSTATE, (ax>>4)+1);
 	if (!need_resched()) {
 		__monitor((void *)&current_thread_info()->flags, 0, 0);
 		smp_mb();
 		if (!need_resched())
 			__mwait(ax, cx);
 	}
+	trace_power_end(&it);
 }
 
 /* Default MONITOR/MWAIT with no hints, used for default C1 state */
 static void mwait_idle(void)
 {
+	struct power_trace it;
 	if (!need_resched()) {
+		trace_power_start(&it, POWER_CSTATE, 1);
 		__monitor((void *)&current_thread_info()->flags, 0, 0);
 		smp_mb();
 		if (!need_resched())
 			__sti_mwait(0, 0);
 		else
 			local_irq_enable();
+		trace_power_end(&it);
 	} else
 		local_irq_enable();
 }
@@ -183,9 +212,13 @@
  */
 static void poll_idle(void)
 {
+	struct power_trace it;
+
+	trace_power_start(&it, POWER_CSTATE, 0);
 	local_irq_enable();
 	while (!need_resched())
 		cpu_relax();
+	trace_power_end(&it);
 }
 
 /*
@@ -270,7 +303,7 @@
 		rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi);
 		if (lo & K8_INTP_C1E_ACTIVE_MASK) {
 			c1e_detected = 1;
-			if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
+			if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
 				mark_tsc_unstable("TSC halt in AMD C1E");
 			printk(KERN_INFO "System has AMD C1E enabled\n");
 			set_cpu_cap(&boot_cpu_data, X86_FEATURE_AMDC1E);
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 0a1302f..3ba155d 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -38,6 +38,7 @@
 #include <linux/percpu.h>
 #include <linux/prctl.h>
 #include <linux/dmi.h>
+#include <linux/ftrace.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -59,6 +60,7 @@
 #include <asm/idle.h>
 #include <asm/syscalls.h>
 #include <asm/smp.h>
+#include <asm/ds.h>
 
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
@@ -250,14 +252,8 @@
 		tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
 		put_cpu();
 	}
-#ifdef CONFIG_X86_DS
-	/* Free any DS contexts that have not been properly released. */
-	if (unlikely(current->thread.ds_ctx)) {
-		/* we clear debugctl to make sure DS is not used. */
-		update_debugctlmsr(0);
-		ds_free(current->thread.ds_ctx);
-	}
-#endif /* CONFIG_X86_DS */
+
+	ds_exit_thread(current);
 }
 
 void flush_thread(void)
@@ -339,6 +335,12 @@
 		kfree(p->thread.io_bitmap_ptr);
 		p->thread.io_bitmap_max = 0;
 	}
+
+	ds_copy_thread(p, current);
+
+	clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
+	p->thread.debugctlmsr = 0;
+
 	return err;
 }
 
@@ -419,48 +421,19 @@
 	return 0;
 }
 
-#ifdef CONFIG_X86_DS
-static int update_debugctl(struct thread_struct *prev,
-			struct thread_struct *next, unsigned long debugctl)
-{
-	unsigned long ds_prev = 0;
-	unsigned long ds_next = 0;
-
-	if (prev->ds_ctx)
-		ds_prev = (unsigned long)prev->ds_ctx->ds;
-	if (next->ds_ctx)
-		ds_next = (unsigned long)next->ds_ctx->ds;
-
-	if (ds_next != ds_prev) {
-		/* we clear debugctl to make sure DS
-		 * is not in use when we change it */
-		debugctl = 0;
-		update_debugctlmsr(0);
-		wrmsr(MSR_IA32_DS_AREA, ds_next, 0);
-	}
-	return debugctl;
-}
-#else
-static int update_debugctl(struct thread_struct *prev,
-			struct thread_struct *next, unsigned long debugctl)
-{
-	return debugctl;
-}
-#endif /* CONFIG_X86_DS */
-
 static noinline void
 __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
 		 struct tss_struct *tss)
 {
 	struct thread_struct *prev, *next;
-	unsigned long debugctl;
 
 	prev = &prev_p->thread;
 	next = &next_p->thread;
 
-	debugctl = update_debugctl(prev, next, prev->debugctlmsr);
-
-	if (next->debugctlmsr != debugctl)
+	if (test_tsk_thread_flag(next_p, TIF_DS_AREA_MSR) ||
+	    test_tsk_thread_flag(prev_p, TIF_DS_AREA_MSR))
+		ds_switch_to(prev_p, next_p);
+	else if (next->debugctlmsr != prev->debugctlmsr)
 		update_debugctlmsr(next->debugctlmsr);
 
 	if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
@@ -482,15 +455,6 @@
 			hard_enable_TSC();
 	}
 
-#ifdef CONFIG_X86_PTRACE_BTS
-	if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS))
-		ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS);
-
-	if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS))
-		ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES);
-#endif /* CONFIG_X86_PTRACE_BTS */
-
-
 	if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) {
 		/*
 		 * Disable the bitmap via an invalid offset. We still cache
@@ -548,7 +512,8 @@
  * the task-switch, and shows up in ret_from_fork in entry.S,
  * for example.
  */
-struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
+__notrace_funcgraph struct task_struct *
+__switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 {
 	struct thread_struct *prev = &prev_p->thread,
 				 *next = &next_p->thread;
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index c958120f..416fb92 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -39,6 +39,7 @@
 #include <linux/prctl.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include <linux/ftrace.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -52,6 +53,7 @@
 #include <asm/ia32.h>
 #include <asm/idle.h>
 #include <asm/syscalls.h>
+#include <asm/ds.h>
 
 asmlinkage extern void ret_from_fork(void);
 
@@ -235,14 +237,8 @@
 		t->io_bitmap_max = 0;
 		put_cpu();
 	}
-#ifdef CONFIG_X86_DS
-	/* Free any DS contexts that have not been properly released. */
-	if (unlikely(t->ds_ctx)) {
-		/* we clear debugctl to make sure DS is not used. */
-		update_debugctlmsr(0);
-		ds_free(t->ds_ctx);
-	}
-#endif /* CONFIG_X86_DS */
+
+	ds_exit_thread(current);
 }
 
 void flush_thread(void)
@@ -372,6 +368,12 @@
 		if (err)
 			goto out;
 	}
+
+	ds_copy_thread(p, me);
+
+	clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
+	p->thread.debugctlmsr = 0;
+
 	err = 0;
 out:
 	if (err && p->thread.io_bitmap_ptr) {
@@ -470,35 +472,14 @@
 				    struct tss_struct *tss)
 {
 	struct thread_struct *prev, *next;
-	unsigned long debugctl;
 
 	prev = &prev_p->thread,
 	next = &next_p->thread;
 
-	debugctl = prev->debugctlmsr;
-
-#ifdef CONFIG_X86_DS
-	{
-		unsigned long ds_prev = 0, ds_next = 0;
-
-		if (prev->ds_ctx)
-			ds_prev = (unsigned long)prev->ds_ctx->ds;
-		if (next->ds_ctx)
-			ds_next = (unsigned long)next->ds_ctx->ds;
-
-		if (ds_next != ds_prev) {
-			/*
-			 * We clear debugctl to make sure DS
-			 * is not in use when we change it:
-			 */
-			debugctl = 0;
-			update_debugctlmsr(0);
-			wrmsrl(MSR_IA32_DS_AREA, ds_next);
-		}
-	}
-#endif /* CONFIG_X86_DS */
-
-	if (next->debugctlmsr != debugctl)
+	if (test_tsk_thread_flag(next_p, TIF_DS_AREA_MSR) ||
+	    test_tsk_thread_flag(prev_p, TIF_DS_AREA_MSR))
+		ds_switch_to(prev_p, next_p);
+	else if (next->debugctlmsr != prev->debugctlmsr)
 		update_debugctlmsr(next->debugctlmsr);
 
 	if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
@@ -533,14 +514,6 @@
 		 */
 		memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
 	}
-
-#ifdef CONFIG_X86_PTRACE_BTS
-	if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS))
-		ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS);
-
-	if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS))
-		ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES);
-#endif /* CONFIG_X86_PTRACE_BTS */
 }
 
 /*
@@ -551,8 +524,9 @@
  * - could test fs/gs bitsliced
  *
  * Kprobes not supported here. Set the probe on schedule instead.
+ * Function graph tracer not supported too.
  */
-struct task_struct *
+__notrace_funcgraph struct task_struct *
 __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 {
 	struct thread_struct *prev = &prev_p->thread;
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 0a6d8c1..0a5df5f 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -581,158 +581,91 @@
 }
 
 #ifdef CONFIG_X86_PTRACE_BTS
-/*
- * The configuration for a particular BTS hardware implementation.
- */
-struct bts_configuration {
-	/* the size of a BTS record in bytes; at most BTS_MAX_RECORD_SIZE */
-	unsigned char  sizeof_bts;
-	/* the size of a field in the BTS record in bytes */
-	unsigned char  sizeof_field;
-	/* a bitmask to enable/disable BTS in DEBUGCTL MSR */
-	unsigned long debugctl_mask;
-};
-static struct bts_configuration bts_cfg;
-
-#define BTS_MAX_RECORD_SIZE (8 * 3)
-
-
-/*
- * Branch Trace Store (BTS) uses the following format. Different
- * architectures vary in the size of those fields.
- * - source linear address
- * - destination linear address
- * - flags
- *
- * Later architectures use 64bit pointers throughout, whereas earlier
- * architectures use 32bit pointers in 32bit mode.
- *
- * We compute the base address for the first 8 fields based on:
- * - the field size stored in the DS configuration
- * - the relative field position
- *
- * In order to store additional information in the BTS buffer, we use
- * a special source address to indicate that the record requires
- * special interpretation.
- *
- * Netburst indicated via a bit in the flags field whether the branch
- * was predicted; this is ignored.
- */
-
-enum bts_field {
-	bts_from = 0,
-	bts_to,
-	bts_flags,
-
-	bts_escape = (unsigned long)-1,
-	bts_qual = bts_to,
-	bts_jiffies = bts_flags
-};
-
-static inline unsigned long bts_get(const char *base, enum bts_field field)
-{
-	base += (bts_cfg.sizeof_field * field);
-	return *(unsigned long *)base;
-}
-
-static inline void bts_set(char *base, enum bts_field field, unsigned long val)
-{
-	base += (bts_cfg.sizeof_field * field);;
-	(*(unsigned long *)base) = val;
-}
-
-/*
- * Translate a BTS record from the raw format into the bts_struct format
- *
- * out (out): bts_struct interpretation
- * raw: raw BTS record
- */
-static void ptrace_bts_translate_record(struct bts_struct *out, const void *raw)
-{
-	memset(out, 0, sizeof(*out));
-	if (bts_get(raw, bts_from) == bts_escape) {
-		out->qualifier       = bts_get(raw, bts_qual);
-		out->variant.jiffies = bts_get(raw, bts_jiffies);
-	} else {
-		out->qualifier = BTS_BRANCH;
-		out->variant.lbr.from_ip = bts_get(raw, bts_from);
-		out->variant.lbr.to_ip   = bts_get(raw, bts_to);
-	}
-}
-
 static int ptrace_bts_read_record(struct task_struct *child, size_t index,
 				  struct bts_struct __user *out)
 {
-	struct bts_struct ret;
-	const void *bts_record;
-	size_t bts_index, bts_end;
+	const struct bts_trace *trace;
+	struct bts_struct bts;
+	const unsigned char *at;
 	int error;
 
-	error = ds_get_bts_end(child, &bts_end);
+	trace = ds_read_bts(child->bts);
+	if (!trace)
+		return -EPERM;
+
+	at = trace->ds.top - ((index + 1) * trace->ds.size);
+	if ((void *)at < trace->ds.begin)
+		at += (trace->ds.n * trace->ds.size);
+
+	if (!trace->read)
+		return -EOPNOTSUPP;
+
+	error = trace->read(child->bts, at, &bts);
 	if (error < 0)
 		return error;
 
-	if (bts_end <= index)
-		return -EINVAL;
-
-	error = ds_get_bts_index(child, &bts_index);
-	if (error < 0)
-		return error;
-
-	/* translate the ptrace bts index into the ds bts index */
-	bts_index += bts_end - (index + 1);
-	if (bts_end <= bts_index)
-		bts_index -= bts_end;
-
-	error = ds_access_bts(child, bts_index, &bts_record);
-	if (error < 0)
-		return error;
-
-	ptrace_bts_translate_record(&ret, bts_record);
-
-	if (copy_to_user(out, &ret, sizeof(ret)))
+	if (copy_to_user(out, &bts, sizeof(bts)))
 		return -EFAULT;
 
-	return sizeof(ret);
+	return sizeof(bts);
 }
 
 static int ptrace_bts_drain(struct task_struct *child,
 			    long size,
 			    struct bts_struct __user *out)
 {
-	struct bts_struct ret;
-	const unsigned char *raw;
-	size_t end, i;
-	int error;
+	const struct bts_trace *trace;
+	const unsigned char *at;
+	int error, drained = 0;
 
-	error = ds_get_bts_index(child, &end);
-	if (error < 0)
-		return error;
+	trace = ds_read_bts(child->bts);
+	if (!trace)
+		return -EPERM;
 
-	if (size < (end * sizeof(struct bts_struct)))
+	if (!trace->read)
+		return -EOPNOTSUPP;
+
+	if (size < (trace->ds.top - trace->ds.begin))
 		return -EIO;
 
-	error = ds_access_bts(child, 0, (const void **)&raw);
-	if (error < 0)
-		return error;
+	for (at = trace->ds.begin; (void *)at < trace->ds.top;
+	     out++, drained++, at += trace->ds.size) {
+		struct bts_struct bts;
+		int error;
 
-	for (i = 0; i < end; i++, out++, raw += bts_cfg.sizeof_bts) {
-		ptrace_bts_translate_record(&ret, raw);
+		error = trace->read(child->bts, at, &bts);
+		if (error < 0)
+			return error;
 
-		if (copy_to_user(out, &ret, sizeof(ret)))
+		if (copy_to_user(out, &bts, sizeof(bts)))
 			return -EFAULT;
 	}
 
-	error = ds_clear_bts(child);
+	memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size);
+
+	error = ds_reset_bts(child->bts);
 	if (error < 0)
 		return error;
 
-	return end;
+	return drained;
 }
 
-static void ptrace_bts_ovfl(struct task_struct *child)
+static int ptrace_bts_allocate_buffer(struct task_struct *child, size_t size)
 {
-	send_sig(child->thread.bts_ovfl_signal, child, 0);
+	child->bts_buffer = alloc_locked_buffer(size);
+	if (!child->bts_buffer)
+		return -ENOMEM;
+
+	child->bts_size = size;
+
+	return 0;
+}
+
+static void ptrace_bts_free_buffer(struct task_struct *child)
+{
+	free_locked_buffer(child->bts_buffer, child->bts_size);
+	child->bts_buffer = NULL;
+	child->bts_size = 0;
 }
 
 static int ptrace_bts_config(struct task_struct *child,
@@ -740,114 +673,86 @@
 			     const struct ptrace_bts_config __user *ucfg)
 {
 	struct ptrace_bts_config cfg;
-	int error = 0;
+	unsigned int flags = 0;
 
-	error = -EOPNOTSUPP;
-	if (!bts_cfg.sizeof_bts)
-		goto errout;
-
-	error = -EIO;
 	if (cfg_size < sizeof(cfg))
-		goto errout;
+		return -EIO;
 
-	error = -EFAULT;
 	if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
-		goto errout;
+		return -EFAULT;
 
-	error = -EINVAL;
-	if ((cfg.flags & PTRACE_BTS_O_SIGNAL) &&
-	    !(cfg.flags & PTRACE_BTS_O_ALLOC))
-		goto errout;
-
-	if (cfg.flags & PTRACE_BTS_O_ALLOC) {
-		ds_ovfl_callback_t ovfl = NULL;
-		unsigned int sig = 0;
-
-		/* we ignore the error in case we were not tracing child */
-		(void)ds_release_bts(child);
-
-		if (cfg.flags & PTRACE_BTS_O_SIGNAL) {
-			if (!cfg.signal)
-				goto errout;
-
-			sig  = cfg.signal;
-			ovfl = ptrace_bts_ovfl;
-		}
-
-		error = ds_request_bts(child, /* base = */ NULL, cfg.size, ovfl);
-		if (error < 0)
-			goto errout;
-
-		child->thread.bts_ovfl_signal = sig;
+	if (child->bts) {
+		ds_release_bts(child->bts);
+		child->bts = NULL;
 	}
 
-	error = -EINVAL;
-	if (!child->thread.ds_ctx && cfg.flags)
-		goto errout;
+	if (cfg.flags & PTRACE_BTS_O_SIGNAL) {
+		if (!cfg.signal)
+			return -EINVAL;
+
+		return -EOPNOTSUPP;
+
+		child->thread.bts_ovfl_signal = cfg.signal;
+	}
+
+	if ((cfg.flags & PTRACE_BTS_O_ALLOC) &&
+	    (cfg.size != child->bts_size)) {
+		int error;
+
+		ptrace_bts_free_buffer(child);
+
+		error = ptrace_bts_allocate_buffer(child, cfg.size);
+		if (error < 0)
+			return error;
+	}
 
 	if (cfg.flags & PTRACE_BTS_O_TRACE)
-		child->thread.debugctlmsr |= bts_cfg.debugctl_mask;
-	else
-		child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
+		flags |= BTS_USER;
 
 	if (cfg.flags & PTRACE_BTS_O_SCHED)
-		set_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
-	else
-		clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
+		flags |= BTS_TIMESTAMPS;
 
-	error = sizeof(cfg);
+	child->bts = ds_request_bts(child, child->bts_buffer, child->bts_size,
+				    /* ovfl = */ NULL, /* th = */ (size_t)-1,
+				    flags);
+	if (IS_ERR(child->bts)) {
+		int error = PTR_ERR(child->bts);
 
-out:
-	if (child->thread.debugctlmsr)
-		set_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
-	else
-		clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
+		ptrace_bts_free_buffer(child);
+		child->bts = NULL;
 
-	return error;
+		return error;
+	}
 
-errout:
-	child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
-	clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
-	goto out;
+	return sizeof(cfg);
 }
 
 static int ptrace_bts_status(struct task_struct *child,
 			     long cfg_size,
 			     struct ptrace_bts_config __user *ucfg)
 {
+	const struct bts_trace *trace;
 	struct ptrace_bts_config cfg;
-	size_t end;
-	const void *base, *max;
-	int error;
 
 	if (cfg_size < sizeof(cfg))
 		return -EIO;
 
-	error = ds_get_bts_end(child, &end);
-	if (error < 0)
-		return error;
-
-	error = ds_access_bts(child, /* index = */ 0, &base);
-	if (error < 0)
-		return error;
-
-	error = ds_access_bts(child, /* index = */ end, &max);
-	if (error < 0)
-		return error;
+	trace = ds_read_bts(child->bts);
+	if (!trace)
+		return -EPERM;
 
 	memset(&cfg, 0, sizeof(cfg));
-	cfg.size = (max - base);
+	cfg.size = trace->ds.end - trace->ds.begin;
 	cfg.signal = child->thread.bts_ovfl_signal;
 	cfg.bts_size = sizeof(struct bts_struct);
 
 	if (cfg.signal)
 		cfg.flags |= PTRACE_BTS_O_SIGNAL;
 
-	if (test_tsk_thread_flag(child, TIF_DEBUGCTLMSR) &&
-	    child->thread.debugctlmsr & bts_cfg.debugctl_mask)
+	if (trace->ds.flags & BTS_USER)
 		cfg.flags |= PTRACE_BTS_O_TRACE;
 
-	if (test_tsk_thread_flag(child, TIF_BTS_TRACE_TS))
+	if (trace->ds.flags & BTS_TIMESTAMPS)
 		cfg.flags |= PTRACE_BTS_O_SCHED;
 
 	if (copy_to_user(ucfg, &cfg, sizeof(cfg)))
@@ -856,111 +761,78 @@
 	return sizeof(cfg);
 }
 
-static int ptrace_bts_write_record(struct task_struct *child,
-				   const struct bts_struct *in)
+static int ptrace_bts_clear(struct task_struct *child)
 {
-	unsigned char bts_record[BTS_MAX_RECORD_SIZE];
+	const struct bts_trace *trace;
 
-	BUG_ON(BTS_MAX_RECORD_SIZE < bts_cfg.sizeof_bts);
+	trace = ds_read_bts(child->bts);
+	if (!trace)
+		return -EPERM;
 
-	memset(bts_record, 0, bts_cfg.sizeof_bts);
-	switch (in->qualifier) {
-	case BTS_INVALID:
-		break;
+	memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size);
 
-	case BTS_BRANCH:
-		bts_set(bts_record, bts_from, in->variant.lbr.from_ip);
-		bts_set(bts_record, bts_to,   in->variant.lbr.to_ip);
-		break;
-
-	case BTS_TASK_ARRIVES:
-	case BTS_TASK_DEPARTS:
-		bts_set(bts_record, bts_from,    bts_escape);
-		bts_set(bts_record, bts_qual,    in->qualifier);
-		bts_set(bts_record, bts_jiffies, in->variant.jiffies);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	/* The writing task will be the switched-to task on a context
-	 * switch. It needs to write into the switched-from task's BTS
-	 * buffer. */
-	return ds_unchecked_write_bts(child, bts_record, bts_cfg.sizeof_bts);
+	return ds_reset_bts(child->bts);
 }
 
-void ptrace_bts_take_timestamp(struct task_struct *tsk,
-			       enum bts_qualifier qualifier)
+static int ptrace_bts_size(struct task_struct *child)
 {
-	struct bts_struct rec = {
-		.qualifier = qualifier,
-		.variant.jiffies = jiffies_64
-	};
+	const struct bts_trace *trace;
 
-	ptrace_bts_write_record(tsk, &rec);
+	trace = ds_read_bts(child->bts);
+	if (!trace)
+		return -EPERM;
+
+	return (trace->ds.top - trace->ds.begin) / trace->ds.size;
 }
 
-static const struct bts_configuration bts_cfg_netburst = {
-	.sizeof_bts    = sizeof(long) * 3,
-	.sizeof_field  = sizeof(long),
-	.debugctl_mask = (1<<2)|(1<<3)|(1<<5)
-};
-
-static const struct bts_configuration bts_cfg_pentium_m = {
-	.sizeof_bts    = sizeof(long) * 3,
-	.sizeof_field  = sizeof(long),
-	.debugctl_mask = (1<<6)|(1<<7)
-};
-
-static const struct bts_configuration bts_cfg_core2 = {
-	.sizeof_bts    = 8 * 3,
-	.sizeof_field  = 8,
-	.debugctl_mask = (1<<6)|(1<<7)|(1<<9)
-};
-
-static inline void bts_configure(const struct bts_configuration *cfg)
+static void ptrace_bts_fork(struct task_struct *tsk)
 {
-	bts_cfg = *cfg;
+	tsk->bts = NULL;
+	tsk->bts_buffer = NULL;
+	tsk->bts_size = 0;
+	tsk->thread.bts_ovfl_signal = 0;
 }
 
-void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *c)
+static void ptrace_bts_untrace(struct task_struct *child)
 {
-	switch (c->x86) {
-	case 0x6:
-		switch (c->x86_model) {
-		case 0xD:
-		case 0xE: /* Pentium M */
-			bts_configure(&bts_cfg_pentium_m);
-			break;
-		case 0xF: /* Core2 */
-        case 0x1C: /* Atom */
-			bts_configure(&bts_cfg_core2);
-			break;
-		default:
-			/* sorry, don't know about them */
-			break;
-		}
-		break;
-	case 0xF:
-		switch (c->x86_model) {
-		case 0x0:
-		case 0x1:
-		case 0x2: /* Netburst */
-			bts_configure(&bts_cfg_netburst);
-			break;
-		default:
-			/* sorry, don't know about them */
-			break;
-		}
-		break;
-	default:
-		/* sorry, don't know about them */
-		break;
+	if (unlikely(child->bts)) {
+		ds_release_bts(child->bts);
+		child->bts = NULL;
+
+		/* We cannot update total_vm and locked_vm since
+		   child's mm is already gone. But we can reclaim the
+		   memory. */
+		kfree(child->bts_buffer);
+		child->bts_buffer = NULL;
+		child->bts_size = 0;
 	}
 }
+
+static void ptrace_bts_detach(struct task_struct *child)
+{
+	if (unlikely(child->bts)) {
+		ds_release_bts(child->bts);
+		child->bts = NULL;
+
+		ptrace_bts_free_buffer(child);
+	}
+}
+#else
+static inline void ptrace_bts_fork(struct task_struct *tsk) {}
+static inline void ptrace_bts_detach(struct task_struct *child) {}
+static inline void ptrace_bts_untrace(struct task_struct *child) {}
 #endif /* CONFIG_X86_PTRACE_BTS */
 
+void x86_ptrace_fork(struct task_struct *child, unsigned long clone_flags)
+{
+	ptrace_bts_fork(child);
+}
+
+void x86_ptrace_untrace(struct task_struct *child)
+{
+	ptrace_bts_untrace(child);
+}
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -972,15 +844,7 @@
 #ifdef TIF_SYSCALL_EMU
 	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
 #endif
-#ifdef CONFIG_X86_PTRACE_BTS
-	(void)ds_release_bts(child);
-
-	child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
-	if (!child->thread.debugctlmsr)
-		clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
-
-	clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
-#endif /* CONFIG_X86_PTRACE_BTS */
+	ptrace_bts_detach(child);
 }
 
 #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
@@ -1112,7 +976,7 @@
 		break;
 
 	case PTRACE_BTS_SIZE:
-		ret = ds_get_bts_index(child, /* pos = */ NULL);
+		ret = ptrace_bts_size(child);
 		break;
 
 	case PTRACE_BTS_GET:
@@ -1121,7 +985,7 @@
 		break;
 
 	case PTRACE_BTS_CLEAR:
-		ret = ds_clear_bts(child);
+		ret = ptrace_bts_clear(child);
 		break;
 
 	case PTRACE_BTS_DRAIN:
@@ -1384,6 +1248,14 @@
 
 	case PTRACE_GET_THREAD_AREA:
 	case PTRACE_SET_THREAD_AREA:
+#ifdef CONFIG_X86_PTRACE_BTS
+	case PTRACE_BTS_CONFIG:
+	case PTRACE_BTS_STATUS:
+	case PTRACE_BTS_SIZE:
+	case PTRACE_BTS_GET:
+	case PTRACE_BTS_CLEAR:
+	case PTRACE_BTS_DRAIN:
+#endif /* CONFIG_X86_PTRACE_BTS */
 		return arch_ptrace(child, request, addr, data);
 
 	default:
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index cc5a254..61f718d 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -21,6 +21,9 @@
 # include <asm/iommu.h>
 #endif
 
+#include <mach_ipi.h>
+
+
 /*
  * Power off function, if any
  */
@@ -36,7 +39,10 @@
 static int reboot_cpu = -1;
 #endif
 
-/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old]
+/* This is set by the PCI code if either type 1 or type 2 PCI is detected */
+bool port_cf9_safe = false;
+
+/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
    warm   Don't set the cold reboot flag
    cold   Set the cold reboot flag
    bios   Reboot by jumping through the BIOS (only for X86_32)
@@ -45,6 +51,7 @@
    kbd    Use the keyboard controller. cold reset (default)
    acpi   Use the RESET_REG in the FADT
    efi    Use efi reset_system runtime service
+   pci    Use the so-called "PCI reset register", CF9
    force  Avoid anything that could hang.
  */
 static int __init reboot_setup(char *str)
@@ -79,6 +86,7 @@
 		case 'k':
 		case 't':
 		case 'e':
+		case 'p':
 			reboot_type = *str;
 			break;
 
@@ -404,12 +412,27 @@
 			reboot_type = BOOT_KBD;
 			break;
 
-
 		case BOOT_EFI:
 			if (efi_enabled)
-				efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD,
+				efi.reset_system(reboot_mode ?
+						 EFI_RESET_WARM :
+						 EFI_RESET_COLD,
 						 EFI_SUCCESS, 0, NULL);
+			reboot_type = BOOT_KBD;
+			break;
 
+		case BOOT_CF9:
+			port_cf9_safe = true;
+			/* fall through */
+
+		case BOOT_CF9_COND:
+			if (port_cf9_safe) {
+				u8 cf9 = inb(0xcf9) & ~6;
+				outb(cf9|2, 0xcf9); /* Request hard reset */
+				udelay(50);
+				outb(cf9|6, 0xcf9); /* Actually do the reset */
+				udelay(50);
+			}
 			reboot_type = BOOT_KBD;
 			break;
 		}
@@ -470,6 +493,11 @@
 
 static void native_machine_halt(void)
 {
+	/* stop other cpus and apics */
+	machine_shutdown();
+
+	/* stop this cpu */
+	stop_this_cpu(NULL);
 }
 
 static void native_machine_power_off(void)
@@ -523,3 +551,95 @@
 	machine_ops.crash_shutdown(regs);
 }
 #endif
+
+
+#if defined(CONFIG_SMP)
+
+/* This keeps a track of which one is crashing cpu. */
+static int crashing_cpu;
+static nmi_shootdown_cb shootdown_callback;
+
+static atomic_t waiting_for_crash_ipi;
+
+static int crash_nmi_callback(struct notifier_block *self,
+			unsigned long val, void *data)
+{
+	int cpu;
+
+	if (val != DIE_NMI_IPI)
+		return NOTIFY_OK;
+
+	cpu = raw_smp_processor_id();
+
+	/* Don't do anything if this handler is invoked on crashing cpu.
+	 * Otherwise, system will completely hang. Crashing cpu can get
+	 * an NMI if system was initially booted with nmi_watchdog parameter.
+	 */
+	if (cpu == crashing_cpu)
+		return NOTIFY_STOP;
+	local_irq_disable();
+
+	shootdown_callback(cpu, (struct die_args *)data);
+
+	atomic_dec(&waiting_for_crash_ipi);
+	/* Assume hlt works */
+	halt();
+	for (;;)
+		cpu_relax();
+
+	return 1;
+}
+
+static void smp_send_nmi_allbutself(void)
+{
+	cpumask_t mask = cpu_online_map;
+	cpu_clear(safe_smp_processor_id(), mask);
+	if (!cpus_empty(mask))
+		send_IPI_mask(mask, NMI_VECTOR);
+}
+
+static struct notifier_block crash_nmi_nb = {
+	.notifier_call = crash_nmi_callback,
+};
+
+/* Halt all other CPUs, calling the specified function on each of them
+ *
+ * This function can be used to halt all other CPUs on crash
+ * or emergency reboot time. The function passed as parameter
+ * will be called inside a NMI handler on all CPUs.
+ */
+void nmi_shootdown_cpus(nmi_shootdown_cb callback)
+{
+	unsigned long msecs;
+	local_irq_disable();
+
+	/* Make a note of crashing cpu. Will be used in NMI callback.*/
+	crashing_cpu = safe_smp_processor_id();
+
+	shootdown_callback = callback;
+
+	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+	/* Would it be better to replace the trap vector here? */
+	if (register_die_notifier(&crash_nmi_nb))
+		return;		/* return what? */
+	/* Ensure the new callback function is set before sending
+	 * out the NMI
+	 */
+	wmb();
+
+	smp_send_nmi_allbutself();
+
+	msecs = 1000; /* Wait at most a second for the other cpus to stop */
+	while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
+		mdelay(1);
+		msecs--;
+	}
+
+	/* Leave the nmi callback set */
+}
+#else /* !CONFIG_SMP */
+void nmi_shootdown_cpus(nmi_shootdown_cb callback)
+{
+	/* No other CPUs to shoot down */
+}
+#endif
diff --git a/arch/x86/kernel/relocate_kernel_32.S b/arch/x86/kernel/relocate_kernel_32.S
index 6f50664..a160f31 100644
--- a/arch/x86/kernel/relocate_kernel_32.S
+++ b/arch/x86/kernel/relocate_kernel_32.S
@@ -10,15 +10,12 @@
 #include <asm/page.h>
 #include <asm/kexec.h>
 #include <asm/processor-flags.h>
-#include <asm/pgtable.h>
 
 /*
  * Must be relocatable PIC code callable as a C function
  */
 
 #define PTR(x) (x << 2)
-#define PAGE_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define PAE_PGD_ATTR (_PAGE_PRESENT)
 
 /* control_page + KEXEC_CONTROL_CODE_MAX_SIZE
  * ~ control_page + PAGE_SIZE are used as data storage and stack for
@@ -39,7 +36,6 @@
 #define CP_PA_BACKUP_PAGES_MAP	DATA(0x1c)
 
 	.text
-	.align PAGE_SIZE
 	.globl relocate_kernel
 relocate_kernel:
 	/* Save the CPU context, used for jumping back */
@@ -60,117 +56,6 @@
 	movl	%cr4, %eax
 	movl	%eax, CR4(%edi)
 
-#ifdef CONFIG_X86_PAE
-	/* map the control page at its virtual address */
-
-	movl	PTR(VA_PGD)(%ebp), %edi
-	movl	PTR(VA_CONTROL_PAGE)(%ebp), %eax
-	andl	$0xc0000000, %eax
-	shrl	$27, %eax
-	addl	%edi, %eax
-
-	movl	PTR(PA_PMD_0)(%ebp), %edx
-	orl	$PAE_PGD_ATTR, %edx
-	movl	%edx, (%eax)
-
-	movl	PTR(VA_PMD_0)(%ebp), %edi
-	movl	PTR(VA_CONTROL_PAGE)(%ebp), %eax
-	andl	$0x3fe00000, %eax
-	shrl	$18, %eax
-	addl	%edi, %eax
-
-	movl	PTR(PA_PTE_0)(%ebp), %edx
-	orl	$PAGE_ATTR, %edx
-	movl	%edx, (%eax)
-
-	movl	PTR(VA_PTE_0)(%ebp), %edi
-	movl	PTR(VA_CONTROL_PAGE)(%ebp), %eax
-	andl	$0x001ff000, %eax
-	shrl	$9, %eax
-	addl	%edi, %eax
-
-	movl	PTR(PA_CONTROL_PAGE)(%ebp), %edx
-	orl	$PAGE_ATTR, %edx
-	movl	%edx, (%eax)
-
-	/* identity map the control page at its physical address */
-
-	movl	PTR(VA_PGD)(%ebp), %edi
-	movl	PTR(PA_CONTROL_PAGE)(%ebp), %eax
-	andl	$0xc0000000, %eax
-	shrl	$27, %eax
-	addl	%edi, %eax
-
-	movl	PTR(PA_PMD_1)(%ebp), %edx
-	orl	$PAE_PGD_ATTR, %edx
-	movl	%edx, (%eax)
-
-	movl	PTR(VA_PMD_1)(%ebp), %edi
-	movl	PTR(PA_CONTROL_PAGE)(%ebp), %eax
-	andl	$0x3fe00000, %eax
-	shrl	$18, %eax
-	addl	%edi, %eax
-
-	movl	PTR(PA_PTE_1)(%ebp), %edx
-	orl	$PAGE_ATTR, %edx
-	movl	%edx, (%eax)
-
-	movl	PTR(VA_PTE_1)(%ebp), %edi
-	movl	PTR(PA_CONTROL_PAGE)(%ebp), %eax
-	andl	$0x001ff000, %eax
-	shrl	$9, %eax
-	addl	%edi, %eax
-
-	movl	PTR(PA_CONTROL_PAGE)(%ebp), %edx
-	orl	$PAGE_ATTR, %edx
-	movl	%edx, (%eax)
-#else
-	/* map the control page at its virtual address */
-
-	movl	PTR(VA_PGD)(%ebp), %edi
-	movl	PTR(VA_CONTROL_PAGE)(%ebp), %eax
-	andl	$0xffc00000, %eax
-	shrl	$20, %eax
-	addl	%edi, %eax
-
-	movl	PTR(PA_PTE_0)(%ebp), %edx
-	orl	$PAGE_ATTR, %edx
-	movl	%edx, (%eax)
-
-	movl	PTR(VA_PTE_0)(%ebp), %edi
-	movl	PTR(VA_CONTROL_PAGE)(%ebp), %eax
-	andl	$0x003ff000, %eax
-	shrl	$10, %eax
-	addl	%edi, %eax
-
-	movl	PTR(PA_CONTROL_PAGE)(%ebp), %edx
-	orl	$PAGE_ATTR, %edx
-	movl	%edx, (%eax)
-
-	/* identity map the control page at its physical address */
-
-	movl	PTR(VA_PGD)(%ebp), %edi
-	movl	PTR(PA_CONTROL_PAGE)(%ebp), %eax
-	andl	$0xffc00000, %eax
-	shrl	$20, %eax
-	addl	%edi, %eax
-
-	movl	PTR(PA_PTE_1)(%ebp), %edx
-	orl	$PAGE_ATTR, %edx
-	movl	%edx, (%eax)
-
-	movl	PTR(VA_PTE_1)(%ebp), %edi
-	movl	PTR(PA_CONTROL_PAGE)(%ebp), %eax
-	andl	$0x003ff000, %eax
-	shrl	$10, %eax
-	addl	%edi, %eax
-
-	movl	PTR(PA_CONTROL_PAGE)(%ebp), %edx
-	orl	$PAGE_ATTR, %edx
-	movl	%edx, (%eax)
-#endif
-
-relocate_new_kernel:
 	/* read the arguments and say goodbye to the stack */
 	movl  20+4(%esp), %ebx /* page_list */
 	movl  20+8(%esp), %ebp /* list of pages */
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index bdec76e..08e02e8 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -93,11 +93,13 @@
 #include <asm/desc.h>
 #include <asm/dma.h>
 #include <asm/iommu.h>
+#include <asm/gart.h>
 #include <asm/mmu_context.h>
 #include <asm/proto.h>
 
 #include <mach_apic.h>
 #include <asm/paravirt.h>
+#include <asm/hypervisor.h>
 
 #include <asm/percpu.h>
 #include <asm/topology.h>
@@ -448,6 +450,7 @@
  * @size: Size of the crashkernel memory to reserve.
  * Returns the base address on success, and -1ULL on failure.
  */
+static
 unsigned long long __init find_and_reserve_crashkernel(unsigned long long size)
 {
 	const unsigned long long alignment = 16<<20; 	/* 16M */
@@ -583,161 +586,24 @@
 early_param("elfcorehdr", setup_elfcorehdr);
 #endif
 
-static struct x86_quirks default_x86_quirks __initdata;
+static int __init default_update_genapic(void)
+{
+#ifdef CONFIG_X86_SMP
+# if defined(CONFIG_X86_GENERICARCH) || defined(CONFIG_X86_64)
+	genapic->wakeup_cpu = wakeup_secondary_cpu_via_init;
+# endif
+#endif
+
+	return 0;
+}
+
+static struct x86_quirks default_x86_quirks __initdata = {
+	.update_genapic         = default_update_genapic,
+};
 
 struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
 
-/*
- * Some BIOSes seem to corrupt the low 64k of memory during events
- * like suspend/resume and unplugging an HDMI cable.  Reserve all
- * remaining free memory in that area and fill it with a distinct
- * pattern.
- */
-#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
-#define MAX_SCAN_AREAS	8
-
-static int __read_mostly memory_corruption_check = -1;
-
-static unsigned __read_mostly corruption_check_size = 64*1024;
-static unsigned __read_mostly corruption_check_period = 60; /* seconds */
-
-static struct e820entry scan_areas[MAX_SCAN_AREAS];
-static int num_scan_areas;
-
-
-static int set_corruption_check(char *arg)
-{
-	char *end;
-
-	memory_corruption_check = simple_strtol(arg, &end, 10);
-
-	return (*end == 0) ? 0 : -EINVAL;
-}
-early_param("memory_corruption_check", set_corruption_check);
-
-static int set_corruption_check_period(char *arg)
-{
-	char *end;
-
-	corruption_check_period = simple_strtoul(arg, &end, 10);
-
-	return (*end == 0) ? 0 : -EINVAL;
-}
-early_param("memory_corruption_check_period", set_corruption_check_period);
-
-static int set_corruption_check_size(char *arg)
-{
-	char *end;
-	unsigned size;
-
-	size = memparse(arg, &end);
-
-	if (*end == '\0')
-		corruption_check_size = size;
-
-	return (size == corruption_check_size) ? 0 : -EINVAL;
-}
-early_param("memory_corruption_check_size", set_corruption_check_size);
-
-
-static void __init setup_bios_corruption_check(void)
-{
-	u64 addr = PAGE_SIZE;	/* assume first page is reserved anyway */
-
-	if (memory_corruption_check == -1) {
-		memory_corruption_check =
-#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
-			1
-#else
-			0
-#endif
-			;
-	}
-
-	if (corruption_check_size == 0)
-		memory_corruption_check = 0;
-
-	if (!memory_corruption_check)
-		return;
-
-	corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
-
-	while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
-		u64 size;
-		addr = find_e820_area_size(addr, &size, PAGE_SIZE);
-
-		if (addr == 0)
-			break;
-
-		if ((addr + size) > corruption_check_size)
-			size = corruption_check_size - addr;
-
-		if (size == 0)
-			break;
-
-		e820_update_range(addr, size, E820_RAM, E820_RESERVED);
-		scan_areas[num_scan_areas].addr = addr;
-		scan_areas[num_scan_areas].size = size;
-		num_scan_areas++;
-
-		/* Assume we've already mapped this early memory */
-		memset(__va(addr), 0, size);
-
-		addr += size;
-	}
-
-	printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
-	       num_scan_areas);
-	update_e820();
-}
-
-static struct timer_list periodic_check_timer;
-
-void check_for_bios_corruption(void)
-{
-	int i;
-	int corruption = 0;
-
-	if (!memory_corruption_check)
-		return;
-
-	for(i = 0; i < num_scan_areas; i++) {
-		unsigned long *addr = __va(scan_areas[i].addr);
-		unsigned long size = scan_areas[i].size;
-
-		for(; size; addr++, size -= sizeof(unsigned long)) {
-			if (!*addr)
-				continue;
-			printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
-			       addr, __pa(addr), *addr);
-			corruption = 1;
-			*addr = 0;
-		}
-	}
-
-	WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n");
-}
-
-static void periodic_check_for_corruption(unsigned long data)
-{
-	check_for_bios_corruption();
-	mod_timer(&periodic_check_timer, round_jiffies(jiffies + corruption_check_period*HZ));
-}
-
-void start_periodic_check_for_corruption(void)
-{
-	if (!memory_corruption_check || corruption_check_period == 0)
-		return;
-
-	printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
-	       corruption_check_period);
-
-	init_timer(&periodic_check_timer);
-	periodic_check_timer.function = &periodic_check_for_corruption;
-	periodic_check_for_corruption(0);
-}
-#endif
-
+#ifdef CONFIG_X86_RESERVE_LOW_64K
 static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
 {
 	printk(KERN_NOTICE
@@ -749,6 +615,7 @@
 
 	return 0;
 }
+#endif
 
 /* List of systems that have known low memory corruption BIOS problems */
 static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
@@ -907,6 +774,12 @@
 
 	dmi_check_system(bad_bios_dmi_table);
 
+	/*
+	 * VMware detection requires dmi to be available, so this
+	 * needs to be done after dmi_scan_machine, for the BP.
+	 */
+	init_hypervisor(&boot_cpu_data);
+
 #ifdef CONFIG_X86_32
 	probe_roms();
 #endif
diff --git a/arch/x86/kernel/sigframe.h b/arch/x86/kernel/sigframe.h
deleted file mode 100644
index cc673aa..0000000
--- a/arch/x86/kernel/sigframe.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifdef CONFIG_X86_32
-struct sigframe {
-	char __user *pretcode;
-	int sig;
-	struct sigcontext sc;
-	/*
-	 * fpstate is unused. fpstate is moved/allocated after
-	 * retcode[] below. This movement allows to have the FP state and the
-	 * future state extensions (xsave) stay together.
-	 * And at the same time retaining the unused fpstate, prevents changing
-	 * the offset of extramask[] in the sigframe and thus prevent any
-	 * legacy application accessing/modifying it.
-	 */
-	struct _fpstate fpstate_unused;
-	unsigned long extramask[_NSIG_WORDS-1];
-	char retcode[8];
-	/* fp state follows here */
-};
-
-struct rt_sigframe {
-	char __user *pretcode;
-	int sig;
-	struct siginfo __user *pinfo;
-	void __user *puc;
-	struct siginfo info;
-	struct ucontext uc;
-	char retcode[8];
-	/* fp state follows here */
-};
-#else
-struct rt_sigframe {
-	char __user *pretcode;
-	struct ucontext uc;
-	struct siginfo info;
-	/* fp state follows here */
-};
-
-int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-		sigset_t *set, struct pt_regs *regs);
-int ia32_setup_frame(int sig, struct k_sigaction *ka,
-		sigset_t *set, struct pt_regs *regs);
-#endif
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal.c
similarity index 73%
rename from arch/x86/kernel/signal_32.c
rename to arch/x86/kernel/signal.c
index d6dd057..89bb766 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal.c
@@ -1,36 +1,41 @@
 /*
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
  *
  *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
+ *  2000-2002   x86-64 support by Andi Kleen
  */
-#include <linux/list.h>
 
-#include <linux/personality.h>
-#include <linux/binfmts.h>
-#include <linux/suspend.h>
-#include <linux/kernel.h>
-#include <linux/ptrace.h>
-#include <linux/signal.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/errno.h>
 #include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/tracehook.h>
-#include <linux/elf.h>
-#include <linux/smp.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/tracehook.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/personality.h>
+#include <linux/uaccess.h>
 
 #include <asm/processor.h>
 #include <asm/ucontext.h>
-#include <asm/uaccess.h>
 #include <asm/i387.h>
 #include <asm/vdso.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>
 #include <asm/syscalls.h>
 
-#include "sigframe.h"
+#include <asm/sigframe.h>
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
@@ -45,74 +50,6 @@
 # define FIX_EFLAGS	__FIX_EFLAGS
 #endif
 
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int
-sys_sigsuspend(int history0, int history1, old_sigset_t mask)
-{
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
-	current->saved_sigmask = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	set_restore_sigmask();
-
-	return -ERESTARTNOHAND;
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction __user *act,
-	      struct old_sigaction __user *oact)
-{
-	struct k_sigaction new_ka, old_ka;
-	int ret;
-
-	if (act) {
-		old_sigset_t mask;
-
-		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
-		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
-		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
-			return -EFAULT;
-
-		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
-		__get_user(mask, &act->sa_mask);
-		siginitset(&new_ka.sa.sa_mask, mask);
-	}
-
-	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
-	if (!ret && oact) {
-		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
-		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
-		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
-			return -EFAULT;
-
-		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
-		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
-	}
-
-	return ret;
-}
-
-asmlinkage int sys_sigaltstack(unsigned long bx)
-{
-	/*
-	 * This is needed to make gcc realize it doesn't own the
-	 * "struct pt_regs"
-	 */
-	struct pt_regs *regs = (struct pt_regs *)&bx;
-	const stack_t __user *uss = (const stack_t __user *)bx;
-	stack_t __user *uoss = (stack_t __user *)regs->cx;
-
-	return do_sigaltstack(uss, uoss, regs->sp);
-}
-
 #define COPY(x)			{		\
 	err |= __get_user(regs->x, &sc->x);	\
 }
@@ -123,7 +60,7 @@
 		regs->seg = tmp;			\
 }
 
-#define COPY_SEG_STRICT(seg)	{			\
+#define COPY_SEG_CPL3(seg)	{			\
 		unsigned short tmp;			\
 		err |= __get_user(tmp, &sc->seg);	\
 		regs->seg = tmp | 3;			\
@@ -135,9 +72,6 @@
 		loadsegment(seg, tmp);			\
 }
 
-/*
- * Do a signal return; undo the signal stack.
- */
 static int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
 		   unsigned long *pax)
@@ -149,14 +83,36 @@
 	/* Always make any pending restarted system calls return -EINTR */
 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
+#ifdef CONFIG_X86_32
 	GET_SEG(gs);
 	COPY_SEG(fs);
 	COPY_SEG(es);
 	COPY_SEG(ds);
+#endif /* CONFIG_X86_32 */
+
 	COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
 	COPY(dx); COPY(cx); COPY(ip);
-	COPY_SEG_STRICT(cs);
-	COPY_SEG_STRICT(ss);
+
+#ifdef CONFIG_X86_64
+	COPY(r8);
+	COPY(r9);
+	COPY(r10);
+	COPY(r11);
+	COPY(r12);
+	COPY(r13);
+	COPY(r14);
+	COPY(r15);
+#endif /* CONFIG_X86_64 */
+
+#ifdef CONFIG_X86_32
+	COPY_SEG_CPL3(cs);
+	COPY_SEG_CPL3(ss);
+#else /* !CONFIG_X86_32 */
+	/* Kernel saves and restores only the CS segment register on signals,
+	 * which is the bare minimum needed to allow mixed 32/64-bit code.
+	 * App's signal handler can save/restore other segments if needed. */
+	COPY_SEG_CPL3(cs);
+#endif /* CONFIG_X86_32 */
 
 	err |= __get_user(tmpflags, &sc->flags);
 	regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
@@ -169,102 +125,24 @@
 	return err;
 }
 
-asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
-{
-	struct sigframe __user *frame;
-	struct pt_regs *regs;
-	unsigned long ax;
-	sigset_t set;
-
-	regs = (struct pt_regs *) &__unused;
-	frame = (struct sigframe __user *)(regs->sp - 8);
-
-	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-		goto badframe;
-	if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1
-		&& __copy_from_user(&set.sig[1], &frame->extramask,
-				    sizeof(frame->extramask))))
-		goto badframe;
-
-	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	if (restore_sigcontext(regs, &frame->sc, &ax))
-		goto badframe;
-	return ax;
-
-badframe:
-	if (show_unhandled_signals && printk_ratelimit()) {
-		printk("%s%s[%d] bad frame in sigreturn frame:"
-			"%p ip:%lx sp:%lx oeax:%lx",
-		    task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG,
-		    current->comm, task_pid_nr(current), frame, regs->ip,
-		    regs->sp, regs->orig_ax);
-		print_vma_addr(" in ", regs->ip);
-		printk(KERN_CONT "\n");
-	}
-
-	force_sig(SIGSEGV, current);
-
-	return 0;
-}
-
-static long do_rt_sigreturn(struct pt_regs *regs)
-{
-	struct rt_sigframe __user *frame;
-	unsigned long ax;
-	sigset_t set;
-
-	frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
-	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-		goto badframe;
-	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
-		goto badframe;
-
-	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
-		goto badframe;
-
-	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
-		goto badframe;
-
-	return ax;
-
-badframe:
-	signal_fault(regs, frame, "rt_sigreturn");
-	return 0;
-}
-
-asmlinkage int sys_rt_sigreturn(unsigned long __unused)
-{
-	struct pt_regs *regs = (struct pt_regs *)&__unused;
-
-	return do_rt_sigreturn(regs);
-}
-
-/*
- * Set up a signal frame.
- */
 static int
 setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
 		 struct pt_regs *regs, unsigned long mask)
 {
-	int tmp, err = 0;
+	int err = 0;
 
+#ifdef CONFIG_X86_32
+	{
+		unsigned int tmp;
+
+		savesegment(gs, tmp);
+		err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
+	}
 	err |= __put_user(regs->fs, (unsigned int __user *)&sc->fs);
-	savesegment(gs, tmp);
-	err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
-
 	err |= __put_user(regs->es, (unsigned int __user *)&sc->es);
 	err |= __put_user(regs->ds, (unsigned int __user *)&sc->ds);
+#endif /* CONFIG_X86_32 */
+
 	err |= __put_user(regs->di, &sc->di);
 	err |= __put_user(regs->si, &sc->si);
 	err |= __put_user(regs->bp, &sc->bp);
@@ -273,19 +151,33 @@
 	err |= __put_user(regs->dx, &sc->dx);
 	err |= __put_user(regs->cx, &sc->cx);
 	err |= __put_user(regs->ax, &sc->ax);
+#ifdef CONFIG_X86_64
+	err |= __put_user(regs->r8, &sc->r8);
+	err |= __put_user(regs->r9, &sc->r9);
+	err |= __put_user(regs->r10, &sc->r10);
+	err |= __put_user(regs->r11, &sc->r11);
+	err |= __put_user(regs->r12, &sc->r12);
+	err |= __put_user(regs->r13, &sc->r13);
+	err |= __put_user(regs->r14, &sc->r14);
+	err |= __put_user(regs->r15, &sc->r15);
+#endif /* CONFIG_X86_64 */
+
 	err |= __put_user(current->thread.trap_no, &sc->trapno);
 	err |= __put_user(current->thread.error_code, &sc->err);
 	err |= __put_user(regs->ip, &sc->ip);
+#ifdef CONFIG_X86_32
 	err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs);
 	err |= __put_user(regs->flags, &sc->flags);
 	err |= __put_user(regs->sp, &sc->sp_at_signal);
 	err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
+#else /* !CONFIG_X86_32 */
+	err |= __put_user(regs->flags, &sc->flags);
+	err |= __put_user(regs->cs, &sc->cs);
+	err |= __put_user(0, &sc->gs);
+	err |= __put_user(0, &sc->fs);
+#endif /* CONFIG_X86_32 */
 
-	tmp = save_i387_xstate(fpstate);
-	if (tmp < 0)
-		err = 1;
-	else
-		err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
+	err |= __put_user(fpstate, &sc->fpstate);
 
 	/* non-iBCS2 extensions.. */
 	err |= __put_user(mask, &sc->oldmask);
@@ -295,6 +187,32 @@
 }
 
 /*
+ * Set up a signal frame.
+ */
+#ifdef CONFIG_X86_32
+static const struct {
+	u16 poplmovl;
+	u32 val;
+	u16 int80;
+} __attribute__((packed)) retcode = {
+	0xb858,		/* popl %eax; movl $..., %eax */
+	__NR_sigreturn,
+	0x80cd,		/* int $0x80 */
+};
+
+static const struct {
+	u8  movl;
+	u32 val;
+	u16 int80;
+	u8  pad;
+} __attribute__((packed)) rt_retcode = {
+	0xb8,		/* movl $..., %eax */
+	__NR_rt_sigreturn,
+	0x80cd,		/* int $0x80 */
+	0
+};
+
+/*
  * Determine which stack to use..
  */
 static inline void __user *
@@ -328,6 +246,8 @@
 	if (used_math()) {
 		sp = sp - sig_xstate_size;
 		*fpstate = (struct _fpstate *) sp;
+		if (save_i387_xstate(*fpstate) < 0)
+			return (void __user *)-1L;
 	}
 
 	sp -= frame_size;
@@ -383,9 +303,7 @@
 	 * reasons and because gdb uses it as a signature to notice
 	 * signal handler stack frames.
 	 */
-	err |= __put_user(0xb858, (short __user *)(frame->retcode+0));
-	err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2));
-	err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
+	err |= __put_user(*((u64 *)&retcode), (u64 *)frame->retcode);
 
 	if (err)
 		return -EFAULT;
@@ -454,9 +372,7 @@
 	 * reasons and because gdb uses it as a signature to notice
 	 * signal handler stack frames.
 	 */
-	err |= __put_user(0xb8, (char __user *)(frame->retcode+0));
-	err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1));
-	err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
+	err |= __put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
 
 	if (err)
 		return -EFAULT;
@@ -475,23 +391,293 @@
 
 	return 0;
 }
+#else /* !CONFIG_X86_32 */
+/*
+ * Determine which stack to use..
+ */
+static void __user *
+get_stack(struct k_sigaction *ka, unsigned long sp, unsigned long size)
+{
+	/* Default to using normal stack - redzone*/
+	sp -= 128;
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (sas_ss_flags(sp) == 0)
+			sp = current->sas_ss_sp + current->sas_ss_size;
+	}
+
+	return (void __user *)round_down(sp - size, 64);
+}
+
+static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			    sigset_t *set, struct pt_regs *regs)
+{
+	struct rt_sigframe __user *frame;
+	void __user *fp = NULL;
+	int err = 0;
+	struct task_struct *me = current;
+
+	if (used_math()) {
+		fp = get_stack(ka, regs->sp, sig_xstate_size);
+		frame = (void __user *)round_down(
+			(unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
+
+		if (save_i387_xstate(fp) < 0)
+			return -EFAULT;
+	} else
+		frame = get_stack(ka, regs->sp, sizeof(struct rt_sigframe)) - 8;
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		return -EFAULT;
+
+	if (ka->sa.sa_flags & SA_SIGINFO) {
+		if (copy_siginfo_to_user(&frame->info, info))
+			return -EFAULT;
+	}
+
+	/* Create the ucontext.  */
+	if (cpu_has_xsave)
+		err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
+	else
+		err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->sp),
+			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	/* x86-64 should always use SA_RESTORER. */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
+	} else {
+		/* could use a vstub here */
+		return -EFAULT;
+	}
+
+	if (err)
+		return -EFAULT;
+
+	/* Set up registers for signal handler */
+	regs->di = sig;
+	/* In case the signal handler was declared without prototypes */
+	regs->ax = 0;
+
+	/* This also works for non SA_SIGINFO handlers because they expect the
+	   next argument after the signal number on the stack. */
+	regs->si = (unsigned long)&frame->info;
+	regs->dx = (unsigned long)&frame->uc;
+	regs->ip = (unsigned long) ka->sa.sa_handler;
+
+	regs->sp = (unsigned long)frame;
+
+	/* Set up the CS register to run signal handlers in 64-bit mode,
+	   even if the handler happens to be interrupting 32-bit code. */
+	regs->cs = __USER_CS;
+
+	return 0;
+}
+#endif /* CONFIG_X86_32 */
+
+#ifdef CONFIG_X86_32
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int
+sys_sigsuspend(int history0, int history1, old_sigset_t mask)
+{
+	mask &= _BLOCKABLE;
+	spin_lock_irq(&current->sighand->siglock);
+	current->saved_sigmask = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_restore_sigmask();
+
+	return -ERESTARTNOHAND;
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction __user *act,
+	      struct old_sigaction __user *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	if (act) {
+		old_sigset_t mask;
+
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+			return -EFAULT;
+
+		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		__get_user(mask, &act->sa_mask);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+			return -EFAULT;
+
+		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+	return ret;
+}
+#endif /* CONFIG_X86_32 */
+
+#ifdef CONFIG_X86_32
+asmlinkage int sys_sigaltstack(unsigned long bx)
+{
+	/*
+	 * This is needed to make gcc realize it doesn't own the
+	 * "struct pt_regs"
+	 */
+	struct pt_regs *regs = (struct pt_regs *)&bx;
+	const stack_t __user *uss = (const stack_t __user *)bx;
+	stack_t __user *uoss = (stack_t __user *)regs->cx;
+
+	return do_sigaltstack(uss, uoss, regs->sp);
+}
+#else /* !CONFIG_X86_32 */
+asmlinkage long
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+		struct pt_regs *regs)
+{
+	return do_sigaltstack(uss, uoss, regs->sp);
+}
+#endif /* CONFIG_X86_32 */
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+#ifdef CONFIG_X86_32
+asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
+{
+	struct sigframe __user *frame;
+	struct pt_regs *regs;
+	unsigned long ax;
+	sigset_t set;
+
+	regs = (struct pt_regs *) &__unused;
+	frame = (struct sigframe __user *)(regs->sp - 8);
+
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1
+		&& __copy_from_user(&set.sig[1], &frame->extramask,
+				    sizeof(frame->extramask))))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if (restore_sigcontext(regs, &frame->sc, &ax))
+		goto badframe;
+	return ax;
+
+badframe:
+	signal_fault(regs, frame, "sigreturn");
+
+	return 0;
+}
+#endif /* CONFIG_X86_32 */
+
+static long do_rt_sigreturn(struct pt_regs *regs)
+{
+	struct rt_sigframe __user *frame;
+	unsigned long ax;
+	sigset_t set;
+
+	frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
+		goto badframe;
+
+	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
+		goto badframe;
+
+	return ax;
+
+badframe:
+	signal_fault(regs, frame, "rt_sigreturn");
+	return 0;
+}
+
+#ifdef CONFIG_X86_32
+asmlinkage int sys_rt_sigreturn(struct pt_regs regs)
+{
+	return do_rt_sigreturn(&regs);
+}
+#else /* !CONFIG_X86_32 */
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+{
+	return do_rt_sigreturn(regs);
+}
+#endif /* CONFIG_X86_32 */
 
 /*
  * OK, we're invoking a handler:
  */
 static int signr_convert(int sig)
 {
+#ifdef CONFIG_X86_32
 	struct thread_info *info = current_thread_info();
 
 	if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32)
 		return info->exec_domain->signal_invmap[sig];
+#endif /* CONFIG_X86_32 */
 	return sig;
 }
 
+#ifdef CONFIG_X86_32
+
 #define is_ia32	1
 #define ia32_setup_frame	__setup_frame
 #define ia32_setup_rt_frame	__setup_rt_frame
 
+#else /* !CONFIG_X86_32 */
+
+#ifdef CONFIG_IA32_EMULATION
+#define is_ia32	test_thread_flag(TIF_IA32)
+#else /* !CONFIG_IA32_EMULATION */
+#define is_ia32	0
+#endif /* CONFIG_IA32_EMULATION */
+
+int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+		sigset_t *set, struct pt_regs *regs);
+int ia32_setup_frame(int sig, struct k_sigaction *ka,
+		sigset_t *set, struct pt_regs *regs);
+
+#endif /* CONFIG_X86_32 */
+
 static int
 setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	       sigset_t *set, struct pt_regs *regs)
@@ -592,7 +778,13 @@
 	return 0;
 }
 
+#ifdef CONFIG_X86_32
 #define NR_restart_syscall	__NR_restart_syscall
+#else /* !CONFIG_X86_32 */
+#define NR_restart_syscall	\
+	test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall
+#endif /* CONFIG_X86_32 */
+
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -704,8 +896,9 @@
 	struct task_struct *me = current;
 
 	if (show_unhandled_signals && printk_ratelimit()) {
-		printk(KERN_INFO
+		printk("%s"
 		       "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+		       task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG,
 		       me->comm, me->pid, where, frame,
 		       regs->ip, regs->sp, regs->orig_ax);
 		print_vma_addr(" in ", regs->ip);
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
deleted file mode 100644
index a5c9627..0000000
--- a/arch/x86/kernel/signal_64.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
- *
- *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
- *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
- *  2000-2002   x86-64 support by Andi Kleen
- */
-
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/wait.h>
-#include <linux/ptrace.h>
-#include <linux/tracehook.h>
-#include <linux/unistd.h>
-#include <linux/stddef.h>
-#include <linux/personality.h>
-#include <linux/compiler.h>
-#include <linux/uaccess.h>
-
-#include <asm/processor.h>
-#include <asm/ucontext.h>
-#include <asm/i387.h>
-#include <asm/proto.h>
-#include <asm/ia32_unistd.h>
-#include <asm/mce.h>
-#include <asm/syscall.h>
-#include <asm/syscalls.h>
-#include "sigframe.h"
-
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
-#define __FIX_EFLAGS	(X86_EFLAGS_AC | X86_EFLAGS_OF | \
-			 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
-			 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
-			 X86_EFLAGS_CF)
-
-#ifdef CONFIG_X86_32
-# define FIX_EFLAGS	(__FIX_EFLAGS | X86_EFLAGS_RF)
-#else
-# define FIX_EFLAGS	__FIX_EFLAGS
-#endif
-
-asmlinkage long
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
-		struct pt_regs *regs)
-{
-	return do_sigaltstack(uss, uoss, regs->sp);
-}
-
-#define COPY(x)			{		\
-	err |= __get_user(regs->x, &sc->x);	\
-}
-
-#define COPY_SEG_STRICT(seg)	{			\
-		unsigned short tmp;			\
-		err |= __get_user(tmp, &sc->seg);	\
-		regs->seg = tmp | 3;			\
-}
-
-/*
- * Do a signal return; undo the signal stack.
- */
-static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
-		   unsigned long *pax)
-{
-	void __user *buf;
-	unsigned int tmpflags;
-	unsigned int err = 0;
-
-	/* Always make any pending restarted system calls return -EINTR */
-	current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
-	COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
-	COPY(dx); COPY(cx); COPY(ip);
-	COPY(r8);
-	COPY(r9);
-	COPY(r10);
-	COPY(r11);
-	COPY(r12);
-	COPY(r13);
-	COPY(r14);
-	COPY(r15);
-
-	/* Kernel saves and restores only the CS segment register on signals,
-	 * which is the bare minimum needed to allow mixed 32/64-bit code.
-	 * App's signal handler can save/restore other segments if needed. */
-	COPY_SEG_STRICT(cs);
-
-	err |= __get_user(tmpflags, &sc->flags);
-	regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
-	regs->orig_ax = -1;		/* disable syscall checks */
-
-	err |= __get_user(buf, &sc->fpstate);
-	err |= restore_i387_xstate(buf);
-
-	err |= __get_user(*pax, &sc->ax);
-	return err;
-}
-
-static long do_rt_sigreturn(struct pt_regs *regs)
-{
-	struct rt_sigframe __user *frame;
-	unsigned long ax;
-	sigset_t set;
-
-	frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
-	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-		goto badframe;
-	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
-		goto badframe;
-
-	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
-		goto badframe;
-
-	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
-		goto badframe;
-
-	return ax;
-
-badframe:
-	signal_fault(regs, frame, "rt_sigreturn");
-	return 0;
-}
-
-asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
-{
-	return do_rt_sigreturn(regs);
-}
-
-/*
- * Set up a signal frame.
- */
-
-static inline int
-setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
-		unsigned long mask, struct task_struct *me)
-{
-	int err = 0;
-
-	err |= __put_user(regs->cs, &sc->cs);
-	err |= __put_user(0, &sc->gs);
-	err |= __put_user(0, &sc->fs);
-
-	err |= __put_user(regs->di, &sc->di);
-	err |= __put_user(regs->si, &sc->si);
-	err |= __put_user(regs->bp, &sc->bp);
-	err |= __put_user(regs->sp, &sc->sp);
-	err |= __put_user(regs->bx, &sc->bx);
-	err |= __put_user(regs->dx, &sc->dx);
-	err |= __put_user(regs->cx, &sc->cx);
-	err |= __put_user(regs->ax, &sc->ax);
-	err |= __put_user(regs->r8, &sc->r8);
-	err |= __put_user(regs->r9, &sc->r9);
-	err |= __put_user(regs->r10, &sc->r10);
-	err |= __put_user(regs->r11, &sc->r11);
-	err |= __put_user(regs->r12, &sc->r12);
-	err |= __put_user(regs->r13, &sc->r13);
-	err |= __put_user(regs->r14, &sc->r14);
-	err |= __put_user(regs->r15, &sc->r15);
-	err |= __put_user(me->thread.trap_no, &sc->trapno);
-	err |= __put_user(me->thread.error_code, &sc->err);
-	err |= __put_user(regs->ip, &sc->ip);
-	err |= __put_user(regs->flags, &sc->flags);
-	err |= __put_user(mask, &sc->oldmask);
-	err |= __put_user(me->thread.cr2, &sc->cr2);
-
-	return err;
-}
-
-/*
- * Determine which stack to use..
- */
-
-static void __user *
-get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
-{
-	unsigned long sp;
-
-	/* Default to using normal stack - redzone*/
-	sp = regs->sp - 128;
-
-	/* This is the X/Open sanctioned signal stack switching.  */
-	if (ka->sa.sa_flags & SA_ONSTACK) {
-		if (sas_ss_flags(sp) == 0)
-			sp = current->sas_ss_sp + current->sas_ss_size;
-	}
-
-	return (void __user *)round_down(sp - size, 64);
-}
-
-static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-			    sigset_t *set, struct pt_regs *regs)
-{
-	struct rt_sigframe __user *frame;
-	void __user *fp = NULL;
-	int err = 0;
-	struct task_struct *me = current;
-
-	if (used_math()) {
-		fp = get_stack(ka, regs, sig_xstate_size);
-		frame = (void __user *)round_down(
-			(unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
-
-		if (save_i387_xstate(fp) < 0)
-			return -EFAULT;
-	} else
-		frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
-
-	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		return -EFAULT;
-
-	if (ka->sa.sa_flags & SA_SIGINFO) {
-		if (copy_siginfo_to_user(&frame->info, info))
-			return -EFAULT;
-	}
-
-	/* Create the ucontext.  */
-	if (cpu_has_xsave)
-		err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
-	else
-		err |= __put_user(0, &frame->uc.uc_flags);
-	err |= __put_user(0, &frame->uc.uc_link);
-	err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-	err |= __put_user(sas_ss_flags(regs->sp),
-			  &frame->uc.uc_stack.ss_flags);
-	err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
-	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me);
-	err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate);
-	if (sizeof(*set) == 16) {
-		__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
-		__put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
-	} else
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
-
-	/* Set up to return from userspace.  If provided, use a stub
-	   already in userspace.  */
-	/* x86-64 should always use SA_RESTORER. */
-	if (ka->sa.sa_flags & SA_RESTORER) {
-		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
-	} else {
-		/* could use a vstub here */
-		return -EFAULT;
-	}
-
-	if (err)
-		return -EFAULT;
-
-	/* Set up registers for signal handler */
-	regs->di = sig;
-	/* In case the signal handler was declared without prototypes */
-	regs->ax = 0;
-
-	/* This also works for non SA_SIGINFO handlers because they expect the
-	   next argument after the signal number on the stack. */
-	regs->si = (unsigned long)&frame->info;
-	regs->dx = (unsigned long)&frame->uc;
-	regs->ip = (unsigned long) ka->sa.sa_handler;
-
-	regs->sp = (unsigned long)frame;
-
-	/* Set up the CS register to run signal handlers in 64-bit mode,
-	   even if the handler happens to be interrupting 32-bit code. */
-	regs->cs = __USER_CS;
-
-	return 0;
-}
-
-/*
- * OK, we're invoking a handler
- */
-static int signr_convert(int sig)
-{
-	return sig;
-}
-
-#ifdef CONFIG_IA32_EMULATION
-#define is_ia32	test_thread_flag(TIF_IA32)
-#else
-#define is_ia32	0
-#endif
-
-static int
-setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-	       sigset_t *set, struct pt_regs *regs)
-{
-	int usig = signr_convert(sig);
-	int ret;
-
-	/* Set up the stack frame */
-	if (is_ia32) {
-		if (ka->sa.sa_flags & SA_SIGINFO)
-			ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
-		else
-			ret = ia32_setup_frame(usig, ka, set, regs);
-	} else
-		ret = __setup_rt_frame(sig, ka, info, set, regs);
-
-	if (ret) {
-		force_sigsegv(sig, current);
-		return -EFAULT;
-	}
-
-	return ret;
-}
-
-static int
-handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
-	      sigset_t *oldset, struct pt_regs *regs)
-{
-	int ret;
-
-	/* Are we from a system call? */
-	if (syscall_get_nr(current, regs) >= 0) {
-		/* If so, check system call restarting.. */
-		switch (syscall_get_error(current, regs)) {
-		case -ERESTART_RESTARTBLOCK:
-		case -ERESTARTNOHAND:
-			regs->ax = -EINTR;
-			break;
-
-		case -ERESTARTSYS:
-			if (!(ka->sa.sa_flags & SA_RESTART)) {
-				regs->ax = -EINTR;
-				break;
-			}
-		/* fallthrough */
-		case -ERESTARTNOINTR:
-			regs->ax = regs->orig_ax;
-			regs->ip -= 2;
-			break;
-		}
-	}
-
-	/*
-	 * If TF is set due to a debugger (TIF_FORCED_TF), clear the TF
-	 * flag so that register information in the sigcontext is correct.
-	 */
-	if (unlikely(regs->flags & X86_EFLAGS_TF) &&
-	    likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
-		regs->flags &= ~X86_EFLAGS_TF;
-
-	ret = setup_rt_frame(sig, ka, info, oldset, regs);
-
-	if (ret)
-		return ret;
-
-#ifdef CONFIG_X86_64
-	/*
-	 * This has nothing to do with segment registers,
-	 * despite the name.  This magic affects uaccess.h
-	 * macros' behavior.  Reset it to the normal setting.
-	 */
-	set_fs(USER_DS);
-#endif
-
-	/*
-	 * Clear the direction flag as per the ABI for function entry.
-	 */
-	regs->flags &= ~X86_EFLAGS_DF;
-
-	/*
-	 * Clear TF when entering the signal handler, but
-	 * notify any tracer that was single-stepping it.
-	 * The tracer may want to single-step inside the
-	 * handler too.
-	 */
-	regs->flags &= ~X86_EFLAGS_TF;
-
-	spin_lock_irq(&current->sighand->siglock);
-	sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-	if (!(ka->sa.sa_flags & SA_NODEFER))
-		sigaddset(&current->blocked, sig);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	tracehook_signal_handler(sig, info, ka, regs,
-				 test_thread_flag(TIF_SINGLESTEP));
-
-	return 0;
-}
-
-#define NR_restart_syscall	\
-	test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- */
-static void do_signal(struct pt_regs *regs)
-{
-	struct k_sigaction ka;
-	siginfo_t info;
-	int signr;
-	sigset_t *oldset;
-
-	/*
-	 * We want the common case to go fast, which is why we may in certain
-	 * cases get here from kernel mode. Just return without doing anything
-	 * if so.
-	 * X86_32: vm86 regs switched out by assembly code before reaching
-	 * here, so testing against kernel CS suffices.
-	 */
-	if (!user_mode(regs))
-		return;
-
-	if (current_thread_info()->status & TS_RESTORE_SIGMASK)
-		oldset = &current->saved_sigmask;
-	else
-		oldset = &current->blocked;
-
-	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-	if (signr > 0) {
-		/*
-		 * Re-enable any watchpoints before delivering the
-		 * signal to user space. The processor register will
-		 * have been cleared if the watchpoint triggered
-		 * inside the kernel.
-		 */
-		if (current->thread.debugreg7)
-			set_debugreg(current->thread.debugreg7, 7);
-
-		/* Whee! Actually deliver the signal.  */
-		if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
-			/*
-			 * A signal was successfully delivered; the saved
-			 * sigmask will have been stored in the signal frame,
-			 * and will be restored by sigreturn, so we can simply
-			 * clear the TS_RESTORE_SIGMASK flag.
-			 */
-			current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
-		}
-		return;
-	}
-
-	/* Did we come from a system call? */
-	if (syscall_get_nr(current, regs) >= 0) {
-		/* Restart the system call - no handlers present */
-		switch (syscall_get_error(current, regs)) {
-		case -ERESTARTNOHAND:
-		case -ERESTARTSYS:
-		case -ERESTARTNOINTR:
-			regs->ax = regs->orig_ax;
-			regs->ip -= 2;
-			break;
-
-		case -ERESTART_RESTARTBLOCK:
-			regs->ax = NR_restart_syscall;
-			regs->ip -= 2;
-			break;
-		}
-	}
-
-	/*
-	 * If there's no signal to deliver, we just put the saved sigmask
-	 * back.
-	 */
-	if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
-		current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
-		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
-	}
-}
-
-/*
- * notification of userspace execution resumption
- * - triggered by the TIF_WORK_MASK flags
- */
-void
-do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
-{
-#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
-	/* notify userspace of pending MCEs */
-	if (thread_info_flags & _TIF_MCE_NOTIFY)
-		mce_notify_user();
-#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
-
-	/* deal with pending signal delivery */
-	if (thread_info_flags & _TIF_SIGPENDING)
-		do_signal(regs);
-
-	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
-		clear_thread_flag(TIF_NOTIFY_RESUME);
-		tracehook_notify_resume(regs);
-	}
-
-#ifdef CONFIG_X86_32
-	clear_thread_flag(TIF_IRET);
-#endif /* CONFIG_X86_32 */
-}
-
-void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
-{
-	struct task_struct *me = current;
-
-	if (show_unhandled_signals && printk_ratelimit()) {
-		printk(KERN_INFO
-		       "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
-		       me->comm, me->pid, where, frame,
-		       regs->ip, regs->sp, regs->orig_ax);
-		print_vma_addr(" in ", regs->ip);
-		printk(KERN_CONT "\n");
-	}
-
-	force_sig(SIGSEGV, me);
-}
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 18f9b19..7e558db 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -140,19 +140,6 @@
 		send_IPI_mask(mask, CALL_FUNCTION_VECTOR);
 }
 
-static void stop_this_cpu(void *dummy)
-{
-	local_irq_disable();
-	/*
-	 * Remove this CPU:
-	 */
-	cpu_clear(smp_processor_id(), cpu_online_map);
-	disable_local_APIC();
-	if (hlt_works(smp_processor_id()))
-		for (;;) halt();
-	for (;;);
-}
-
 /*
  * this function calls the 'stop' function on all other CPUs in the system.
  */
@@ -178,11 +165,7 @@
 void smp_reschedule_interrupt(struct pt_regs *regs)
 {
 	ack_APIC_irq();
-#ifdef CONFIG_X86_32
-	__get_cpu_var(irq_stat).irq_resched_count++;
-#else
-	add_pda(irq_resched_count, 1);
-#endif
+	inc_irq_stat(irq_resched_count);
 }
 
 void smp_call_function_interrupt(struct pt_regs *regs)
@@ -190,11 +173,7 @@
 	ack_APIC_irq();
 	irq_enter();
 	generic_smp_call_function_interrupt();
-#ifdef CONFIG_X86_32
-	__get_cpu_var(irq_stat).irq_call_count++;
-#else
-	add_pda(irq_call_count, 1);
-#endif
+	inc_irq_stat(irq_call_count);
 	irq_exit();
 }
 
@@ -203,11 +182,7 @@
 	ack_APIC_irq();
 	irq_enter();
 	generic_smp_call_function_single_interrupt();
-#ifdef CONFIG_X86_32
-	__get_cpu_var(irq_stat).irq_call_count++;
-#else
-	add_pda(irq_call_count, 1);
-#endif
+	inc_irq_stat(irq_call_count);
 	irq_exit();
 }
 
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index f71f96f..f8500c9 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -62,6 +62,7 @@
 #include <asm/mtrr.h>
 #include <asm/vmi.h>
 #include <asm/genapic.h>
+#include <asm/setup.h>
 #include <linux/mc146818rtc.h>
 
 #include <mach_apic.h>
@@ -287,7 +288,7 @@
 /*
  * Activate a secondary processor.
  */
-static void __cpuinit start_secondary(void *unused)
+notrace static void __cpuinit start_secondary(void *unused)
 {
 	/*
 	 * Don't put *anything* before cpu_init(), SMP booting is too
@@ -534,7 +535,7 @@
 	pr_debug("Before bogocount - setting activated=1.\n");
 }
 
-static inline void __inquire_remote_apic(int apicid)
+void __inquire_remote_apic(int apicid)
 {
 	unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
 	char *names[] = { "ID", "VERSION", "SPIV" };
@@ -573,14 +574,13 @@
 	}
 }
 
-#ifdef WAKE_SECONDARY_VIA_NMI
 /*
  * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal
  * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
  * won't ... remember to clear down the APIC, etc later.
  */
-static int __devinit
-wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
+int __devinit
+wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip)
 {
 	unsigned long send_status, accept_status = 0;
 	int maxlvt;
@@ -597,7 +597,7 @@
 	 * Give the other CPU some time to accept the IPI.
 	 */
 	udelay(200);
-	if (APIC_INTEGRATED(apic_version[phys_apicid])) {
+	if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
 		maxlvt = lapic_get_maxlvt();
 		if (maxlvt > 3)			/* Due to the Pentium erratum 3AP.  */
 			apic_write(APIC_ESR, 0);
@@ -612,11 +612,9 @@
 
 	return (send_status | accept_status);
 }
-#endif	/* WAKE_SECONDARY_VIA_NMI */
 
-#ifdef WAKE_SECONDARY_VIA_INIT
-static int __devinit
-wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
+int __devinit
+wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
 {
 	unsigned long send_status, accept_status = 0;
 	int maxlvt, num_starts, j;
@@ -735,7 +733,6 @@
 
 	return (send_status | accept_status);
 }
-#endif	/* WAKE_SECONDARY_VIA_INIT */
 
 struct create_idle {
 	struct work_struct work;
@@ -1084,8 +1081,10 @@
 #endif
 
 	if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) {
-		printk(KERN_WARNING "weird, boot CPU (#%d) not listed"
-				    "by the BIOS.\n", hard_smp_processor_id());
+		printk(KERN_WARNING
+			"weird, boot CPU (#%d) not listed by the BIOS.\n",
+			hard_smp_processor_id());
+
 		physid_set(hard_smp_processor_id(), phys_cpu_present_map);
 	}
 
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c
index a03e7f6..10786af 100644
--- a/arch/x86/kernel/stacktrace.c
+++ b/arch/x86/kernel/stacktrace.c
@@ -6,6 +6,7 @@
 #include <linux/sched.h>
 #include <linux/stacktrace.h>
 #include <linux/module.h>
+#include <linux/uaccess.h>
 #include <asm/stacktrace.h>
 
 static void save_stack_warning(void *data, char *msg)
@@ -83,3 +84,66 @@
 		trace->entries[trace->nr_entries++] = ULONG_MAX;
 }
 EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
+
+/* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */
+
+struct stack_frame {
+	const void __user	*next_fp;
+	unsigned long		ret_addr;
+};
+
+static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
+{
+	int ret;
+
+	if (!access_ok(VERIFY_READ, fp, sizeof(*frame)))
+		return 0;
+
+	ret = 1;
+	pagefault_disable();
+	if (__copy_from_user_inatomic(frame, fp, sizeof(*frame)))
+		ret = 0;
+	pagefault_enable();
+
+	return ret;
+}
+
+static inline void __save_stack_trace_user(struct stack_trace *trace)
+{
+	const struct pt_regs *regs = task_pt_regs(current);
+	const void __user *fp = (const void __user *)regs->bp;
+
+	if (trace->nr_entries < trace->max_entries)
+		trace->entries[trace->nr_entries++] = regs->ip;
+
+	while (trace->nr_entries < trace->max_entries) {
+		struct stack_frame frame;
+
+		frame.next_fp = NULL;
+		frame.ret_addr = 0;
+		if (!copy_stack_frame(fp, &frame))
+			break;
+		if ((unsigned long)fp < regs->sp)
+			break;
+		if (frame.ret_addr) {
+			trace->entries[trace->nr_entries++] =
+				frame.ret_addr;
+		}
+		if (fp == frame.next_fp)
+			break;
+		fp = frame.next_fp;
+	}
+}
+
+void save_stack_trace_user(struct stack_trace *trace)
+{
+	/*
+	 * Trace user stack if we are not a kernel thread
+	 */
+	if (current->mm) {
+		__save_stack_trace_user(trace);
+	}
+	if (trace->nr_entries < trace->max_entries)
+		trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
+
diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c
index 77b400f..65309e4 100644
--- a/arch/x86/kernel/time_32.c
+++ b/arch/x86/kernel/time_32.c
@@ -75,7 +75,7 @@
 irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
 	/* Keep nmi watchdog up to date */
-	per_cpu(irq_stat, smp_processor_id()).irq0_irqs++;
+	inc_irq_stat(irq0_irqs);
 
 #ifdef CONFIG_X86_IO_APIC
 	if (timer_ack) {
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c
index cb19d65..891e7a7 100644
--- a/arch/x86/kernel/time_64.c
+++ b/arch/x86/kernel/time_64.c
@@ -49,9 +49,9 @@
 }
 EXPORT_SYMBOL(profile_pc);
 
-irqreturn_t timer_interrupt(int irq, void *dev_id)
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
-	add_pda(irq0_irqs, 1);
+	inc_irq_stat(irq0_irqs);
 
 	global_clock_event->event_handler(global_clock_event);
 
@@ -80,6 +80,8 @@
 			break;
 	no_ctr_free = (i == 4);
 	if (no_ctr_free) {
+		WARN(1, KERN_WARNING "Warning: AMD perfctrs busy ... "
+		     "cpu_khz value may be incorrect.\n");
 		i = 3;
 		rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
 		wrmsrl(MSR_K7_EVNTSEL3, 0);
diff --git a/arch/x86/kernel/tlb_32.c b/arch/x86/kernel/tlb_32.c
index f4049f3..8da059f 100644
--- a/arch/x86/kernel/tlb_32.c
+++ b/arch/x86/kernel/tlb_32.c
@@ -34,9 +34,8 @@
  */
 void leave_mm(int cpu)
 {
-	if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
-		BUG();
-	cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask);
+	BUG_ON(x86_read_percpu(cpu_tlbstate.state) == TLBSTATE_OK);
+	cpu_clear(cpu, x86_read_percpu(cpu_tlbstate.active_mm)->cpu_vm_mask);
 	load_cr3(swapper_pg_dir);
 }
 EXPORT_SYMBOL_GPL(leave_mm);
@@ -104,8 +103,8 @@
 		 * BUG();
 		 */
 
-	if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) {
-		if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) {
+	if (flush_mm == x86_read_percpu(cpu_tlbstate.active_mm)) {
+		if (x86_read_percpu(cpu_tlbstate.state) == TLBSTATE_OK) {
 			if (flush_va == TLB_FLUSH_ALL)
 				local_flush_tlb();
 			else
@@ -119,7 +118,7 @@
 	smp_mb__after_clear_bit();
 out:
 	put_cpu_no_resched();
-	__get_cpu_var(irq_stat).irq_tlb_count++;
+	inc_irq_stat(irq_tlb_count);
 }
 
 void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm,
@@ -238,7 +237,7 @@
 	unsigned long cpu = smp_processor_id();
 
 	__flush_tlb_all();
-	if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY)
+	if (x86_read_percpu(cpu_tlbstate.state) == TLBSTATE_LAZY)
 		leave_mm(cpu);
 }
 
diff --git a/arch/x86/kernel/tlb_64.c b/arch/x86/kernel/tlb_64.c
index 8f919ca..29887d7 100644
--- a/arch/x86/kernel/tlb_64.c
+++ b/arch/x86/kernel/tlb_64.c
@@ -154,7 +154,7 @@
 out:
 	ack_APIC_irq();
 	cpu_clear(cpu, f->flush_cpumask);
-	add_pda(irq_tlb_count, 1);
+	inc_irq_stat(irq_tlb_count);
 }
 
 void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm,
diff --git a/arch/x86/kernel/tlb_uv.c b/arch/x86/kernel/tlb_uv.c
index 04431f3..6a00e5f 100644
--- a/arch/x86/kernel/tlb_uv.c
+++ b/arch/x86/kernel/tlb_uv.c
@@ -566,14 +566,10 @@
 	if (!is_uv_system())
 		return 0;
 
-	if (!proc_mkdir("sgi_uv", NULL))
-		return -EINVAL;
-
 	proc_uv_ptc = create_proc_entry(UV_PTC_BASENAME, 0444, NULL);
 	if (!proc_uv_ptc) {
 		printk(KERN_ERR "unable to create %s proc entry\n",
 		       UV_PTC_BASENAME);
-		remove_proc_entry("sgi_uv", NULL);
 		return -EINVAL;
 	}
 	proc_uv_ptc->proc_fops = &proc_uv_ptc_operations;
diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c
index 1106fac..808031a 100644
--- a/arch/x86/kernel/trampoline.c
+++ b/arch/x86/kernel/trampoline.c
@@ -1,10 +1,26 @@
 #include <linux/io.h>
 
 #include <asm/trampoline.h>
+#include <asm/e820.h>
 
 /* ready for x86_64 and x86 */
 unsigned char *trampoline_base = __va(TRAMPOLINE_BASE);
 
+void __init reserve_trampoline_memory(void)
+{
+#ifdef CONFIG_X86_32
+	/*
+	 * But first pinch a few for the stack/trampoline stuff
+	 * FIXME: Don't need the extra page at 4K, but need to fix
+	 * trampoline before removing it. (see the GDT stuff)
+	 */
+	reserve_early(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE");
+#endif
+	/* Has to be in very low memory so we can execute real-mode AP code. */
+	reserve_early(TRAMPOLINE_BASE, TRAMPOLINE_BASE + TRAMPOLINE_SIZE,
+			"TRAMPOLINE");
+}
+
 /*
  * Currently trivial. Write the real->protected mode
  * bootstrap into the page concerned. The caller
@@ -12,7 +28,6 @@
  */
 unsigned long setup_trampoline(void)
 {
-	memcpy(trampoline_base, trampoline_data,
-	       trampoline_end - trampoline_data);
+	memcpy(trampoline_base, trampoline_data, TRAMPOLINE_SIZE);
 	return virt_to_phys(trampoline_base);
 }
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 04d242a..141907a 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -481,11 +481,7 @@
 {
 	nmi_enter();
 
-#ifdef CONFIG_X86_32
-	{ int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); }
-#else
-	add_pda(__nmi_count, 1);
-#endif
+	inc_irq_stat(__nmi_count);
 
 	if (!ignore_nmis)
 		default_do_nmi(regs);
@@ -664,7 +660,7 @@
 {
 	struct task_struct *task;
 	siginfo_t info;
-	unsigned short cwd, swd;
+	unsigned short cwd, swd, err;
 
 	/*
 	 * Save the info for the exception handler and clear the error.
@@ -675,7 +671,6 @@
 	task->thread.error_code = 0;
 	info.si_signo = SIGFPE;
 	info.si_errno = 0;
-	info.si_code = __SI_FAULT;
 	info.si_addr = ip;
 	/*
 	 * (~cwd & swd) will mask out exceptions that are not set to unmasked
@@ -689,34 +684,31 @@
 	 */
 	cwd = get_fpu_cwd(task);
 	swd = get_fpu_swd(task);
-	switch (swd & ~cwd & 0x3f) {
-	case 0x000: /* No unmasked exception */
+
+	err = swd & ~cwd & 0x3f;
+
 #ifdef CONFIG_X86_32
+	if (!err)
 		return;
 #endif
-	default: /* Multiple exceptions */
-		break;
-	case 0x001: /* Invalid Op */
+
+	if (err & 0x001) {	/* Invalid op */
 		/*
 		 * swd & 0x240 == 0x040: Stack Underflow
 		 * swd & 0x240 == 0x240: Stack Overflow
 		 * User must clear the SF bit (0x40) if set
 		 */
 		info.si_code = FPE_FLTINV;
-		break;
-	case 0x002: /* Denormalize */
-	case 0x010: /* Underflow */
-		info.si_code = FPE_FLTUND;
-		break;
-	case 0x004: /* Zero Divide */
+	} else if (err & 0x004) { /* Divide by Zero */
 		info.si_code = FPE_FLTDIV;
-		break;
-	case 0x008: /* Overflow */
+	} else if (err & 0x008) { /* Overflow */
 		info.si_code = FPE_FLTOVF;
-		break;
-	case 0x020: /* Precision */
+	} else if (err & 0x012) { /* Denormal, Underflow */
+		info.si_code = FPE_FLTUND;
+	} else if (err & 0x020) { /* Precision */
 		info.si_code = FPE_FLTRES;
-		break;
+	} else {
+		info.si_code = __SI_FAULT|SI_KERNEL; /* WTF? */
 	}
 	force_sig_info(SIGFPE, &info, task);
 }
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 424093b..599e581 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -15,6 +15,7 @@
 #include <asm/vgtod.h>
 #include <asm/time.h>
 #include <asm/delay.h>
+#include <asm/hypervisor.h>
 
 unsigned int cpu_khz;           /* TSC clocks / usec, not used here */
 EXPORT_SYMBOL(cpu_khz);
@@ -31,6 +32,7 @@
    erroneous rdtsc usage on !cpu_has_tsc processors */
 static int tsc_disabled = -1;
 
+static int tsc_clocksource_reliable;
 /*
  * Scheduler clock - returns current time in nanosec units.
  */
@@ -98,6 +100,15 @@
 
 __setup("notsc", notsc_setup);
 
+static int __init tsc_setup(char *str)
+{
+	if (!strcmp(str, "reliable"))
+		tsc_clocksource_reliable = 1;
+	return 1;
+}
+
+__setup("tsc=", tsc_setup);
+
 #define MAX_RETRIES     5
 #define SMI_TRESHOLD    50000
 
@@ -352,9 +363,15 @@
 {
 	u64 tsc1, tsc2, delta, ref1, ref2;
 	unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX;
-	unsigned long flags, latch, ms, fast_calibrate;
+	unsigned long flags, latch, ms, fast_calibrate, tsc_khz;
 	int hpet = is_hpet_enabled(), i, loopmin;
 
+	tsc_khz = get_hypervisor_tsc_freq();
+	if (tsc_khz) {
+		printk(KERN_INFO "TSC: Frequency read from the hypervisor\n");
+		return tsc_khz;
+	}
+
 	local_irq_save(flags);
 	fast_calibrate = quick_pit_calibrate();
 	local_irq_restore(flags);
@@ -731,24 +748,21 @@
 	{}
 };
 
-/*
- * Geode_LX - the OLPC CPU has a possibly a very reliable TSC
- */
-#ifdef CONFIG_MGEODE_LX
-/* RTSC counts during suspend */
-#define RTSC_SUSP 0x100
-
-static void __init check_geode_tsc_reliable(void)
+static void __init check_system_tsc_reliable(void)
 {
+#ifdef CONFIG_MGEODE_LX
+	/* RTSC counts during suspend */
+#define RTSC_SUSP 0x100
 	unsigned long res_low, res_high;
 
 	rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high);
+	/* Geode_LX - the OLPC CPU has a possibly a very reliable TSC */
 	if (res_low & RTSC_SUSP)
-		clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
-}
-#else
-static inline void check_geode_tsc_reliable(void) { }
+		tsc_clocksource_reliable = 1;
 #endif
+	if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE))
+		tsc_clocksource_reliable = 1;
+}
 
 /*
  * Make an educated guess if the TSC is trustworthy and synchronized
@@ -783,6 +797,8 @@
 {
 	clocksource_tsc.mult = clocksource_khz2mult(tsc_khz,
 			clocksource_tsc.shift);
+	if (tsc_clocksource_reliable)
+		clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
 	/* lower the rating if we already know its unstable: */
 	if (check_tsc_unstable()) {
 		clocksource_tsc.rating = 0;
@@ -843,7 +859,7 @@
 	if (unsynchronized_tsc())
 		mark_tsc_unstable("TSCs unsynchronized");
 
-	check_geode_tsc_reliable();
+	check_system_tsc_reliable();
 	init_tsc_clocksource();
 }
 
diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c
index 1c0dfbc..bf36328 100644
--- a/arch/x86/kernel/tsc_sync.c
+++ b/arch/x86/kernel/tsc_sync.c
@@ -112,6 +112,12 @@
 	if (unsynchronized_tsc())
 		return;
 
+	if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) {
+		printk(KERN_INFO
+		       "Skipping synchronization checks as TSC is reliable.\n");
+		return;
+	}
+
 	printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:",
 			  smp_processor_id(), cpu);
 
@@ -165,7 +171,7 @@
 {
 	int cpus = 2;
 
-	if (unsynchronized_tsc())
+	if (unsynchronized_tsc() || boot_cpu_has(X86_FEATURE_TSC_RELIABLE))
 		return;
 
 	/*
diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c
index 22fd657..23206ba 100644
--- a/arch/x86/kernel/vmi_32.c
+++ b/arch/x86/kernel/vmi_32.c
@@ -266,109 +266,6 @@
 {
 }
 
-#ifdef CONFIG_DEBUG_PAGE_TYPE
-
-#ifdef CONFIG_X86_PAE
-#define MAX_BOOT_PTS (2048+4+1)
-#else
-#define MAX_BOOT_PTS (1024+1)
-#endif
-
-/*
- * During boot, mem_map is not yet available in paging_init, so stash
- * all the boot page allocations here.
- */
-static struct {
-	u32 pfn;
-	int type;
-} boot_page_allocations[MAX_BOOT_PTS];
-static int num_boot_page_allocations;
-static int boot_allocations_applied;
-
-void vmi_apply_boot_page_allocations(void)
-{
-	int i;
-	BUG_ON(!mem_map);
-	for (i = 0; i < num_boot_page_allocations; i++) {
-		struct page *page = pfn_to_page(boot_page_allocations[i].pfn);
-		page->type = boot_page_allocations[i].type;
-		page->type = boot_page_allocations[i].type &
-				~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE);
-	}
-	boot_allocations_applied = 1;
-}
-
-static void record_page_type(u32 pfn, int type)
-{
-	BUG_ON(num_boot_page_allocations >= MAX_BOOT_PTS);
-	boot_page_allocations[num_boot_page_allocations].pfn = pfn;
-	boot_page_allocations[num_boot_page_allocations].type = type;
-	num_boot_page_allocations++;
-}
-
-static void check_zeroed_page(u32 pfn, int type, struct page *page)
-{
-	u32 *ptr;
-	int i;
-	int limit = PAGE_SIZE / sizeof(int);
-
-	if (page_address(page))
-		ptr = (u32 *)page_address(page);
-	else
-		ptr = (u32 *)__va(pfn << PAGE_SHIFT);
-	/*
-	 * When cloning the root in non-PAE mode, only the userspace
-	 * pdes need to be zeroed.
-	 */
-	if (type & VMI_PAGE_CLONE)
-		limit = KERNEL_PGD_BOUNDARY;
-	for (i = 0; i < limit; i++)
-		BUG_ON(ptr[i]);
-}
-
-/*
- * We stash the page type into struct page so we can verify the page
- * types are used properly.
- */
-static void vmi_set_page_type(u32 pfn, int type)
-{
-	/* PAE can have multiple roots per page - don't track */
-	if (PTRS_PER_PMD > 1 && (type & VMI_PAGE_PDP))
-		return;
-
-	if (boot_allocations_applied) {
-		struct page *page = pfn_to_page(pfn);
-		if (type != VMI_PAGE_NORMAL)
-			BUG_ON(page->type);
-		else
-			BUG_ON(page->type == VMI_PAGE_NORMAL);
-		page->type = type & ~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE);
-		if (type & VMI_PAGE_ZEROED)
-			check_zeroed_page(pfn, type, page);
-	} else {
-		record_page_type(pfn, type);
-	}
-}
-
-static void vmi_check_page_type(u32 pfn, int type)
-{
-	/* PAE can have multiple roots per page - skip checks */
-	if (PTRS_PER_PMD > 1 && (type & VMI_PAGE_PDP))
-		return;
-
-	type &= ~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE);
-	if (boot_allocations_applied) {
-		struct page *page = pfn_to_page(pfn);
-		BUG_ON((page->type ^ type) & VMI_PAGE_PAE);
-		BUG_ON(type == VMI_PAGE_NORMAL && page->type);
-		BUG_ON((type & page->type) == 0);
-	}
-}
-#else
-#define vmi_set_page_type(p,t) do { } while (0)
-#define vmi_check_page_type(p,t) do { } while (0)
-#endif
-
 #ifdef CONFIG_HIGHPTE
 static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type)
 {
@@ -395,7 +292,6 @@
 
 static void vmi_allocate_pte(struct mm_struct *mm, unsigned long pfn)
 {
-	vmi_set_page_type(pfn, VMI_PAGE_L1);
 	vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0);
 }
 
@@ -406,27 +302,22 @@
 	 * It is called only for swapper_pg_dir, which already has
 	 * data on it.
 	 */
- 	vmi_set_page_type(pfn, VMI_PAGE_L2);
 	vmi_ops.allocate_page(pfn, VMI_PAGE_L2, 0, 0, 0);
 }
 
 static void vmi_allocate_pmd_clone(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count)
 {
- 	vmi_set_page_type(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE);
-	vmi_check_page_type(clonepfn, VMI_PAGE_L2);
 	vmi_ops.allocate_page(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE, clonepfn, start, count);
 }
 
 static void vmi_release_pte(unsigned long pfn)
 {
 	vmi_ops.release_page(pfn, VMI_PAGE_L1);
-	vmi_set_page_type(pfn, VMI_PAGE_NORMAL);
 }
 
 static void vmi_release_pmd(unsigned long pfn)
 {
 	vmi_ops.release_page(pfn, VMI_PAGE_L2);
-	vmi_set_page_type(pfn, VMI_PAGE_NORMAL);
 }
 
 /*
@@ -450,26 +341,22 @@
 
 static void vmi_update_pte(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-	vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE);
 	vmi_ops.update_pte(ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
 }
 
 static void vmi_update_pte_defer(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-	vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE);
 	vmi_ops.update_pte(ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 0));
 }
 
 static void vmi_set_pte(pte_t *ptep, pte_t pte)
 {
 	/* XXX because of set_pmd_pte, this can be called on PT or PD layers */
-	vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE | VMI_PAGE_PD);
 	vmi_ops.set_pte(pte, ptep, VMI_PAGE_PT);
 }
 
 static void vmi_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
 {
-	vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE);
 	vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
 }
 
@@ -477,10 +364,8 @@
 {
 #ifdef CONFIG_X86_PAE
 	const pte_t pte = { .pte = pmdval.pmd };
-	vmi_check_page_type(__pa(pmdp) >> PAGE_SHIFT, VMI_PAGE_PMD);
 #else
 	const pte_t pte = { pmdval.pud.pgd.pgd };
-	vmi_check_page_type(__pa(pmdp) >> PAGE_SHIFT, VMI_PAGE_PGD);
 #endif
 	vmi_ops.set_pte(pte, (pte_t *)pmdp, VMI_PAGE_PD);
 }
@@ -502,7 +387,6 @@
 
 static void vmi_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
 {
-	vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE);
 	vmi_ops.set_pte(pte, ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 1));
 }
 
@@ -510,21 +394,18 @@
 {
 	/* Um, eww */
 	const pte_t pte = { .pte = pudval.pgd.pgd };
-	vmi_check_page_type(__pa(pudp) >> PAGE_SHIFT, VMI_PAGE_PGD);
 	vmi_ops.set_pte(pte, (pte_t *)pudp, VMI_PAGE_PDP);
 }
 
 static void vmi_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	const pte_t pte = { .pte = 0 };
-	vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE);
 	vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
 }
 
 static void vmi_pmd_clear(pmd_t *pmd)
 {
 	const pte_t pte = { .pte = 0 };
-	vmi_check_page_type(__pa(pmd) >> PAGE_SHIFT, VMI_PAGE_PMD);
 	vmi_ops.set_pte(pte, (pte_t *)pmd, VMI_PAGE_PD);
 }
 #endif
diff --git a/arch/x86/kernel/vmlinux_32.lds.S b/arch/x86/kernel/vmlinux_32.lds.S
index a9b8560..82c6755 100644
--- a/arch/x86/kernel/vmlinux_32.lds.S
+++ b/arch/x86/kernel/vmlinux_32.lds.S
@@ -44,6 +44,7 @@
 	SCHED_TEXT
 	LOCK_TEXT
 	KPROBES_TEXT
+	IRQENTRY_TEXT
 	*(.fixup)
 	*(.gnu.warning)
   	_etext = .;			/* End of text section */
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S
index 46e0544..1a614c0 100644
--- a/arch/x86/kernel/vmlinux_64.lds.S
+++ b/arch/x86/kernel/vmlinux_64.lds.S
@@ -35,6 +35,7 @@
 	SCHED_TEXT
 	LOCK_TEXT
 	KPROBES_TEXT
+	IRQENTRY_TEXT
 	*(.fixup)
 	*(.gnu.warning)
 	_etext = .;		/* End of text section */
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index 0b8b669..44153af 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -17,6 +17,9 @@
  *  want per guest time just set the kernel.vsyscall64 sysctl to 0.
  */
 
+/* Disable profiling for userspace code: */
+#define DISABLE_BRANCH_PROFILING
+
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -128,7 +131,16 @@
 			gettimeofday(tv,NULL);
 			return;
 		}
+
+		/*
+		 * Surround the RDTSC by barriers, to make sure it's not
+		 * speculated to outside the seqlock critical section and
+		 * does not cause time warps:
+		 */
+		rdtsc_barrier();
 		now = vread();
+		rdtsc_barrier();
+
 		base = __vsyscall_gtod_data.clock.cycle_last;
 		mask = __vsyscall_gtod_data.clock.mask;
 		mult = __vsyscall_gtod_data.clock.mult;
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index a5d8e1a..50a7792 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -590,7 +590,8 @@
 		 * 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[vector]);
+			set_intr_gate(vector,
+				      interrupt[vector-FIRST_EXTERNAL_VECTOR]);
 			set_irq_chip_and_handler_name(i, &lguest_irq_controller,
 						      handle_level_irq,
 						      "level");
diff --git a/arch/x86/mach-generic/bigsmp.c b/arch/x86/mach-generic/bigsmp.c
index 3c3b471..3624a36 100644
--- a/arch/x86/mach-generic/bigsmp.c
+++ b/arch/x86/mach-generic/bigsmp.c
@@ -17,6 +17,7 @@
 #include <asm/bigsmp/apic.h>
 #include <asm/bigsmp/ipi.h>
 #include <asm/mach-default/mach_mpparse.h>
+#include <asm/mach-default/mach_wakecpu.h>
 
 static int dmi_bigsmp; /* can be set by dmi scanners */
 
diff --git a/arch/x86/mach-generic/default.c b/arch/x86/mach-generic/default.c
index 9e835a1..e63a4a7 100644
--- a/arch/x86/mach-generic/default.c
+++ b/arch/x86/mach-generic/default.c
@@ -16,6 +16,7 @@
 #include <asm/mach-default/mach_apic.h>
 #include <asm/mach-default/mach_ipi.h>
 #include <asm/mach-default/mach_mpparse.h>
+#include <asm/mach-default/mach_wakecpu.h>
 
 /* should be called last. */
 static int probe_default(void)
diff --git a/arch/x86/mach-generic/es7000.c b/arch/x86/mach-generic/es7000.c
index 28459ca..7b4e6d0 100644
--- a/arch/x86/mach-generic/es7000.c
+++ b/arch/x86/mach-generic/es7000.c
@@ -16,7 +16,19 @@
 #include <asm/es7000/apic.h>
 #include <asm/es7000/ipi.h>
 #include <asm/es7000/mpparse.h>
-#include <asm/es7000/wakecpu.h>
+#include <asm/mach-default/mach_wakecpu.h>
+
+void __init es7000_update_genapic_to_cluster(void)
+{
+	genapic->target_cpus = target_cpus_cluster;
+	genapic->int_delivery_mode = INT_DELIVERY_MODE_CLUSTER;
+	genapic->int_dest_mode = INT_DEST_MODE_CLUSTER;
+	genapic->no_balance_irq = NO_BALANCE_IRQ_CLUSTER;
+
+	genapic->init_apic_ldr = init_apic_ldr_cluster;
+
+	genapic->cpu_mask_to_apicid = cpu_mask_to_apicid_cluster;
+}
 
 static int probe_es7000(void)
 {
diff --git a/arch/x86/mach-generic/probe.c b/arch/x86/mach-generic/probe.c
index 5a7e461..c346d9d 100644
--- a/arch/x86/mach-generic/probe.c
+++ b/arch/x86/mach-generic/probe.c
@@ -15,6 +15,7 @@
 #include <asm/mpspec.h>
 #include <asm/apicdef.h>
 #include <asm/genapic.h>
+#include <asm/setup.h>
 
 extern struct genapic apic_numaq;
 extern struct genapic apic_summit;
@@ -57,6 +58,9 @@
 		}
 	}
 
+	if (x86_quirks->update_genapic)
+		x86_quirks->update_genapic();
+
 	/* Parsed again by __setup for debug/verbose */
 	return 0;
 }
@@ -72,12 +76,15 @@
 	 * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support
 	 */
 
-	if (!cmdline_apic && genapic == &apic_default)
+	if (!cmdline_apic && genapic == &apic_default) {
 		if (apic_bigsmp.probe()) {
 			genapic = &apic_bigsmp;
+			if (x86_quirks->update_genapic)
+				x86_quirks->update_genapic();
 			printk(KERN_INFO "Overriding APIC driver with %s\n",
 			       genapic->name);
 		}
+	}
 #endif
 }
 
@@ -94,6 +101,9 @@
 		/* Not visible without early console */
 		if (!apic_probe[i])
 			panic("Didn't find an APIC driver");
+
+		if (x86_quirks->update_genapic)
+			x86_quirks->update_genapic();
 	}
 	printk(KERN_INFO "Using APIC driver %s\n", genapic->name);
 }
@@ -108,6 +118,8 @@
 		if (apic_probe[i]->mps_oem_check(mpc, oem, productid)) {
 			if (!cmdline_apic) {
 				genapic = apic_probe[i];
+				if (x86_quirks->update_genapic)
+					x86_quirks->update_genapic();
 				printk(KERN_INFO "Switched to APIC driver `%s'.\n",
 				       genapic->name);
 			}
@@ -124,6 +136,8 @@
 		if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) {
 			if (!cmdline_apic) {
 				genapic = apic_probe[i];
+				if (x86_quirks->update_genapic)
+					x86_quirks->update_genapic();
 				printk(KERN_INFO "Switched to APIC driver `%s'.\n",
 				       genapic->name);
 			}
diff --git a/arch/x86/mach-generic/summit.c b/arch/x86/mach-generic/summit.c
index 6272b5e..2c6d234 100644
--- a/arch/x86/mach-generic/summit.c
+++ b/arch/x86/mach-generic/summit.c
@@ -16,6 +16,7 @@
 #include <asm/summit/apic.h>
 #include <asm/summit/ipi.h>
 #include <asm/summit/mpparse.h>
+#include <asm/mach-default/mach_wakecpu.h>
 
 static int probe_summit(void)
 {
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index fea4565..d8cc96a2 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -8,9 +8,8 @@
 
 obj-$(CONFIG_HIGHMEM)		+= highmem_32.o
 
-obj-$(CONFIG_MMIOTRACE_HOOKS)	+= kmmio.o
 obj-$(CONFIG_MMIOTRACE)		+= mmiotrace.o
-mmiotrace-y			:= pf_in.o mmio-mod.o
+mmiotrace-y			:= kmmio.o pf_in.o mmio-mod.o
 obj-$(CONFIG_MMIOTRACE_TEST)	+= testmmiotrace.o
 
 obj-$(CONFIG_NUMA)		+= numa_$(BITS).o
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 31e8730..57ec8c8 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -53,7 +53,7 @@
 
 static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr)
 {
-#ifdef CONFIG_MMIOTRACE_HOOKS
+#ifdef CONFIG_MMIOTRACE
 	if (unlikely(is_kmmio_active()))
 		if (kmmio_handler(regs, addr) == 1)
 			return -1;
@@ -393,7 +393,7 @@
 		if (pte && pte_present(*pte) && !pte_exec(*pte))
 			printk(KERN_CRIT "kernel tried to execute "
 				"NX-protected page - exploit attempt? "
-				"(uid: %d)\n", current->uid);
+				"(uid: %d)\n", current_uid());
 	}
 #endif
 
@@ -413,6 +413,7 @@
 				 unsigned long error_code)
 {
 	unsigned long flags = oops_begin();
+	int sig = SIGKILL;
 	struct task_struct *tsk;
 
 	printk(KERN_ALERT "%s: Corrupted page table at address %lx\n",
@@ -423,8 +424,8 @@
 	tsk->thread.trap_no = 14;
 	tsk->thread.error_code = error_code;
 	if (__die("Bad pagetable", regs, error_code))
-		regs = NULL;
-	oops_end(flags, regs, SIGKILL);
+		sig = 0;
+	oops_end(flags, regs, sig);
 }
 #endif
 
@@ -590,6 +591,7 @@
 	int fault;
 #ifdef CONFIG_X86_64
 	unsigned long flags;
+	int sig;
 #endif
 
 	tsk = current;
@@ -849,11 +851,12 @@
 	bust_spinlocks(0);
 	do_exit(SIGKILL);
 #else
+	sig = SIGKILL;
 	if (__die("Oops", regs, error_code))
-		regs = NULL;
+		sig = 0;
 	/* Executive summary in case the body of the oops scrolled away */
 	printk(KERN_EMERG "CR2: %016lx\n", address);
-	oops_end(flags, regs, SIGKILL);
+	oops_end(flags, regs, sig);
 #endif
 
 /*
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index c483f42..800e1d9 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -67,7 +67,7 @@
 
 static int __initdata after_init_bootmem;
 
-static __init void *alloc_low_page(unsigned long *phys)
+static __init void *alloc_low_page(void)
 {
 	unsigned long pfn = table_end++;
 	void *adr;
@@ -77,7 +77,6 @@
 
 	adr = __va(pfn * PAGE_SIZE);
 	memset(adr, 0, PAGE_SIZE);
-	*phys  = pfn * PAGE_SIZE;
 	return adr;
 }
 
@@ -92,16 +91,17 @@
 	pmd_t *pmd_table;
 
 #ifdef CONFIG_X86_PAE
-	unsigned long phys;
 	if (!(pgd_val(*pgd) & _PAGE_PRESENT)) {
 		if (after_init_bootmem)
 			pmd_table = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
 		else
-			pmd_table = (pmd_t *)alloc_low_page(&phys);
+			pmd_table = (pmd_t *)alloc_low_page();
 		paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT);
 		set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
 		pud = pud_offset(pgd, 0);
 		BUG_ON(pmd_table != pmd_offset(pud, 0));
+
+		return pmd_table;
 	}
 #endif
 	pud = pud_offset(pgd, 0);
@@ -126,10 +126,8 @@
 			if (!page_table)
 				page_table =
 				(pte_t *)alloc_bootmem_low_pages(PAGE_SIZE);
-		} else {
-			unsigned long phys;
-			page_table = (pte_t *)alloc_low_page(&phys);
-		}
+		} else
+			page_table = (pte_t *)alloc_low_page();
 
 		paravirt_alloc_pte(&init_mm, __pa(page_table) >> PAGE_SHIFT);
 		set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
@@ -969,8 +967,6 @@
 	int codesize, reservedpages, datasize, initsize;
 	int tmp;
 
-	start_periodic_check_for_corruption();
-
 #ifdef CONFIG_FLATMEM
 	BUG_ON(!mem_map);
 #endif
@@ -1040,11 +1036,25 @@
 		(unsigned long)&_text, (unsigned long)&_etext,
 		((unsigned long)&_etext - (unsigned long)&_text) >> 10);
 
+	/*
+	 * Check boundaries twice: Some fundamental inconsistencies can
+	 * be detected at build time already.
+	 */
+#define __FIXADDR_TOP (-PAGE_SIZE)
+#ifdef CONFIG_HIGHMEM
+	BUILD_BUG_ON(PKMAP_BASE + LAST_PKMAP*PAGE_SIZE	> FIXADDR_START);
+	BUILD_BUG_ON(VMALLOC_END			> PKMAP_BASE);
+#endif
+#define high_memory (-128UL << 20)
+	BUILD_BUG_ON(VMALLOC_START			>= VMALLOC_END);
+#undef high_memory
+#undef __FIXADDR_TOP
+
 #ifdef CONFIG_HIGHMEM
 	BUG_ON(PKMAP_BASE + LAST_PKMAP*PAGE_SIZE	> FIXADDR_START);
 	BUG_ON(VMALLOC_END				> PKMAP_BASE);
 #endif
-	BUG_ON(VMALLOC_START				> VMALLOC_END);
+	BUG_ON(VMALLOC_START				>= VMALLOC_END);
 	BUG_ON((unsigned long)high_memory		> VMALLOC_START);
 
 	if (boot_cpu_data.wp_works_ok < 0)
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 9db01db..9f7a0d2 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -902,8 +902,6 @@
 	long codesize, reservedpages, datasize, initsize;
 	unsigned long absent_pages;
 
-	start_periodic_check_for_corruption();
-
 	pci_iommu_alloc();
 
 	/* clear_bss() already clear the empty_zero_page */
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index d4c4307..bd85d42 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -223,7 +223,8 @@
 	 * Check if the request spans more than any BAR in the iomem resource
 	 * tree.
 	 */
-	WARN_ON(iomem_map_sanity_check(phys_addr, size));
+	WARN_ONCE(iomem_map_sanity_check(phys_addr, size),
+		  KERN_INFO "Info: mapping multiple BARs. Your kernel is fine.");
 
 	/*
 	 * Don't allow anybody to remap normal RAM that we're using..
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index eb1bf00..85cbd3c 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -596,6 +596,242 @@
 	free_memtype(addr, addr + size);
 }
 
+/*
+ * Internal interface to reserve a range of physical memory with prot.
+ * Reserved non RAM regions only and after successful reserve_memtype,
+ * this func also keeps identity mapping (if any) in sync with this new prot.
+ */
+static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t vma_prot)
+{
+	int is_ram = 0;
+	int id_sz, ret;
+	unsigned long flags;
+	unsigned long want_flags = (pgprot_val(vma_prot) & _PAGE_CACHE_MASK);
+
+	is_ram = pagerange_is_ram(paddr, paddr + size);
+
+	if (is_ram != 0) {
+		/*
+		 * For mapping RAM pages, drivers need to call
+		 * set_memory_[uc|wc|wb] directly, for reserve and free, before
+		 * setting up the PTE.
+		 */
+		WARN_ON_ONCE(1);
+		return 0;
+	}
+
+	ret = reserve_memtype(paddr, paddr + size, want_flags, &flags);
+	if (ret)
+		return ret;
+
+	if (flags != want_flags) {
+		free_memtype(paddr, paddr + size);
+		printk(KERN_ERR
+		"%s:%d map pfn expected mapping type %s for %Lx-%Lx, got %s\n",
+			current->comm, current->pid,
+			cattr_name(want_flags),
+			(unsigned long long)paddr,
+			(unsigned long long)(paddr + size),
+			cattr_name(flags));
+		return -EINVAL;
+	}
+
+	/* Need to keep identity mapping in sync */
+	if (paddr >= __pa(high_memory))
+		return 0;
+
+	id_sz = (__pa(high_memory) < paddr + size) ?
+				__pa(high_memory) - paddr :
+				size;
+
+	if (ioremap_change_attr((unsigned long)__va(paddr), id_sz, flags) < 0) {
+		free_memtype(paddr, paddr + size);
+		printk(KERN_ERR
+			"%s:%d reserve_pfn_range ioremap_change_attr failed %s "
+			"for %Lx-%Lx\n",
+			current->comm, current->pid,
+			cattr_name(flags),
+			(unsigned long long)paddr,
+			(unsigned long long)(paddr + size));
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * Internal interface to free a range of physical memory.
+ * Frees non RAM regions only.
+ */
+static void free_pfn_range(u64 paddr, unsigned long size)
+{
+	int is_ram;
+
+	is_ram = pagerange_is_ram(paddr, paddr + size);
+	if (is_ram == 0)
+		free_memtype(paddr, paddr + size);
+}
+
+/*
+ * track_pfn_vma_copy is called when vma that is covering the pfnmap gets
+ * copied through copy_page_range().
+ *
+ * If the vma has a linear pfn mapping for the entire range, we get the prot
+ * from pte and reserve the entire vma range with single reserve_pfn_range call.
+ * Otherwise, we reserve the entire vma range, my ging through the PTEs page
+ * by page to get physical address and protection.
+ */
+int track_pfn_vma_copy(struct vm_area_struct *vma)
+{
+	int retval = 0;
+	unsigned long i, j;
+	resource_size_t paddr;
+	unsigned long prot;
+	unsigned long vma_start = vma->vm_start;
+	unsigned long vma_end = vma->vm_end;
+	unsigned long vma_size = vma_end - vma_start;
+
+	if (!pat_enabled)
+		return 0;
+
+	if (is_linear_pfn_mapping(vma)) {
+		/*
+		 * reserve the whole chunk covered by vma. We need the
+		 * starting address and protection from pte.
+		 */
+		if (follow_phys(vma, vma_start, 0, &prot, &paddr)) {
+			WARN_ON_ONCE(1);
+			return -EINVAL;
+		}
+		return reserve_pfn_range(paddr, vma_size, __pgprot(prot));
+	}
+
+	/* reserve entire vma page by page, using pfn and prot from pte */
+	for (i = 0; i < vma_size; i += PAGE_SIZE) {
+		if (follow_phys(vma, vma_start + i, 0, &prot, &paddr))
+			continue;
+
+		retval = reserve_pfn_range(paddr, PAGE_SIZE, __pgprot(prot));
+		if (retval)
+			goto cleanup_ret;
+	}
+	return 0;
+
+cleanup_ret:
+	/* Reserve error: Cleanup partial reservation and return error */
+	for (j = 0; j < i; j += PAGE_SIZE) {
+		if (follow_phys(vma, vma_start + j, 0, &prot, &paddr))
+			continue;
+
+		free_pfn_range(paddr, PAGE_SIZE);
+	}
+
+	return retval;
+}
+
+/*
+ * track_pfn_vma_new is called when a _new_ pfn mapping is being established
+ * for physical range indicated by pfn and size.
+ *
+ * prot is passed in as a parameter for the new mapping. If the vma has a
+ * linear pfn mapping for the entire range reserve the entire vma range with
+ * single reserve_pfn_range call.
+ * Otherwise, we look t the pfn and size and reserve only the specified range
+ * page by page.
+ *
+ * Note that this function can be called with caller trying to map only a
+ * subrange/page inside the vma.
+ */
+int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t prot,
+			unsigned long pfn, unsigned long size)
+{
+	int retval = 0;
+	unsigned long i, j;
+	resource_size_t base_paddr;
+	resource_size_t paddr;
+	unsigned long vma_start = vma->vm_start;
+	unsigned long vma_end = vma->vm_end;
+	unsigned long vma_size = vma_end - vma_start;
+
+	if (!pat_enabled)
+		return 0;
+
+	if (is_linear_pfn_mapping(vma)) {
+		/* reserve the whole chunk starting from vm_pgoff */
+		paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT;
+		return reserve_pfn_range(paddr, vma_size, prot);
+	}
+
+	/* reserve page by page using pfn and size */
+	base_paddr = (resource_size_t)pfn << PAGE_SHIFT;
+	for (i = 0; i < size; i += PAGE_SIZE) {
+		paddr = base_paddr + i;
+		retval = reserve_pfn_range(paddr, PAGE_SIZE, prot);
+		if (retval)
+			goto cleanup_ret;
+	}
+	return 0;
+
+cleanup_ret:
+	/* Reserve error: Cleanup partial reservation and return error */
+	for (j = 0; j < i; j += PAGE_SIZE) {
+		paddr = base_paddr + j;
+		free_pfn_range(paddr, PAGE_SIZE);
+	}
+
+	return retval;
+}
+
+/*
+ * untrack_pfn_vma is called while unmapping a pfnmap for a region.
+ * untrack can be called for a specific region indicated by pfn and size or
+ * can be for the entire vma (in which case size can be zero).
+ */
+void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn,
+			unsigned long size)
+{
+	unsigned long i;
+	resource_size_t paddr;
+	unsigned long prot;
+	unsigned long vma_start = vma->vm_start;
+	unsigned long vma_end = vma->vm_end;
+	unsigned long vma_size = vma_end - vma_start;
+
+	if (!pat_enabled)
+		return;
+
+	if (is_linear_pfn_mapping(vma)) {
+		/* free the whole chunk starting from vm_pgoff */
+		paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT;
+		free_pfn_range(paddr, vma_size);
+		return;
+	}
+
+	if (size != 0 && size != vma_size) {
+		/* free page by page, using pfn and size */
+		paddr = (resource_size_t)pfn << PAGE_SHIFT;
+		for (i = 0; i < size; i += PAGE_SIZE) {
+			paddr = paddr + i;
+			free_pfn_range(paddr, PAGE_SIZE);
+		}
+	} else {
+		/* free entire vma, page by page, using the pfn from pte */
+		for (i = 0; i < vma_size; i += PAGE_SIZE) {
+			if (follow_phys(vma, vma_start + i, 0, &prot, &paddr))
+				continue;
+
+			free_pfn_range(paddr, PAGE_SIZE);
+		}
+	}
+}
+
+pgprot_t pgprot_writecombine(pgprot_t prot)
+{
+	if (pat_enabled)
+		return __pgprot(pgprot_val(prot) | _PAGE_CACHE_WC);
+	else
+		return pgprot_noncached(prot);
+}
+
 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_X86_PAT)
 
 /* get Nth element of the linked list */
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index b67732b..bb1a01f 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -23,6 +23,12 @@
 unsigned int pci_early_dump_regs;
 static int pci_bf_sort;
 int pci_routeirq;
+int noioapicquirk;
+#ifdef CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS
+int noioapicreroute = 0;
+#else
+int noioapicreroute = 1;
+#endif
 int pcibios_last_bus = -1;
 unsigned long pirq_table_addr;
 struct pci_bus *pci_root_bus;
@@ -519,6 +525,17 @@
 	} else if (!strcmp(str, "skip_isa_align")) {
 		pci_probe |= PCI_CAN_SKIP_ISA_ALIGN;
 		return NULL;
+	} else if (!strcmp(str, "noioapicquirk")) {
+		noioapicquirk = 1;
+		return NULL;
+	} else if (!strcmp(str, "ioapicreroute")) {
+		if (noioapicreroute != -1)
+			noioapicreroute = 0;
+		return NULL;
+	} else if (!strcmp(str, "noioapicreroute")) {
+		if (noioapicreroute != -1)
+			noioapicreroute = 1;
+		return NULL;
 	}
 	return str;
 }
diff --git a/arch/x86/pci/direct.c b/arch/x86/pci/direct.c
index 9915293..9a5af6c 100644
--- a/arch/x86/pci/direct.c
+++ b/arch/x86/pci/direct.c
@@ -173,7 +173,7 @@
 
 #undef PCI_CONF2_ADDRESS
 
-static struct pci_raw_ops pci_direct_conf2 = {
+struct pci_raw_ops pci_direct_conf2 = {
 	.read =		pci_conf2_read,
 	.write =	pci_conf2_write,
 };
@@ -289,6 +289,7 @@
 
 	if (pci_check_type1()) {
 		raw_pci_ops = &pci_direct_conf1;
+		port_cf9_safe = true;
 		return 1;
 	}
 	release_resource(region);
@@ -305,6 +306,7 @@
 
 	if (pci_check_type2()) {
 		raw_pci_ops = &pci_direct_conf2;
+		port_cf9_safe = true;
 		return 2;
 	}
 
diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h
index 15b9cf6b..1959018 100644
--- a/arch/x86/pci/pci.h
+++ b/arch/x86/pci/pci.h
@@ -96,6 +96,7 @@
 extern struct pci_raw_ops *raw_pci_ext_ops;
 
 extern struct pci_raw_ops pci_direct_conf1;
+extern bool port_cf9_safe;
 
 /* arch_initcall level */
 extern int pci_direct_probe(void);
diff --git a/arch/x86/scripts/strip-symbols b/arch/x86/scripts/strip-symbols
new file mode 100644
index 0000000..a2f1ccb
--- /dev/null
+++ b/arch/x86/scripts/strip-symbols
@@ -0,0 +1 @@
+__cpu_vendor_dev_X86_VENDOR_*
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c
index 1ef0f90..d9d3582 100644
--- a/arch/x86/vdso/vclock_gettime.c
+++ b/arch/x86/vdso/vclock_gettime.c
@@ -9,6 +9,9 @@
  * Also alternative() doesn't work.
  */
 
+/* Disable profiling for userspace code: */
+#define DISABLE_BRANCH_PROFILING
+
 #include <linux/kernel.h>
 #include <linux/posix-timers.h>
 #include <linux/time.h>
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index 513f330..1241f11 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -310,7 +310,7 @@
 }
 
 /* Setup a VMA at program startup for the vsyscall page */
-int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long addr;
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 257ba4a..9c98cc6 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -98,7 +98,7 @@
 
 /* Setup a VMA at program startup for the vsyscall page.
    Not called for compat tasks */
-int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long addr;
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 5e4686d..bea2152 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -28,6 +28,7 @@
 #include <linux/console.h>
 
 #include <xen/interface/xen.h>
+#include <xen/interface/version.h>
 #include <xen/interface/physdev.h>
 #include <xen/interface/vcpu.h>
 #include <xen/features.h>
@@ -793,7 +794,7 @@
 
 	ret = 0;
 
-	switch(msr) {
+	switch (msr) {
 #ifdef CONFIG_X86_64
 		unsigned which;
 		u64 base;
@@ -1453,7 +1454,7 @@
 
 	ident_pte = 0;
 	pfn = 0;
-	for(pmdidx = 0; pmdidx < PTRS_PER_PMD && pfn < max_pfn; pmdidx++) {
+	for (pmdidx = 0; pmdidx < PTRS_PER_PMD && pfn < max_pfn; pmdidx++) {
 		pte_t *pte_page;
 
 		/* Reuse or allocate a page of ptes */
@@ -1471,7 +1472,7 @@
 		}
 
 		/* Install mappings */
-		for(pteidx = 0; pteidx < PTRS_PER_PTE; pteidx++, pfn++) {
+		for (pteidx = 0; pteidx < PTRS_PER_PTE; pteidx++, pfn++) {
 			pte_t pte;
 
 			if (pfn > max_pfn_mapped)
@@ -1485,7 +1486,7 @@
 		}
 	}
 
-	for(pteidx = 0; pteidx < ident_pte; pteidx += PTRS_PER_PTE)
+	for (pteidx = 0; pteidx < ident_pte; pteidx += PTRS_PER_PTE)
 		set_page_prot(&level1_ident_pgt[pteidx], PAGE_KERNEL_RO);
 
 	set_page_prot(pmd, PAGE_KERNEL_RO);
@@ -1499,7 +1500,7 @@
 
 	/* All levels are converted the same way, so just treat them
 	   as ptes. */
-	for(i = 0; i < PTRS_PER_PTE; i++)
+	for (i = 0; i < PTRS_PER_PTE; i++)
 		pte[i] = xen_make_pte(pte[i].pte);
 }
 
@@ -1514,7 +1515,8 @@
  * of the physical mapping once some sort of allocator has been set
  * up.
  */
-static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn)
+static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
+						unsigned long max_pfn)
 {
 	pud_t *l3;
 	pmd_t *l2;
@@ -1577,7 +1579,8 @@
 #else	/* !CONFIG_X86_64 */
 static pmd_t level2_kernel_pgt[PTRS_PER_PMD] __page_aligned_bss;
 
-static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn)
+static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
+						unsigned long max_pfn)
 {
 	pmd_t *kernel_pmd;
 
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 636ef4c..773d68d 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -154,13 +154,13 @@
 {
 	unsigned pfn, idx;
 
-	for(pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn += P2M_ENTRIES_PER_PAGE) {
+	for (pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn += P2M_ENTRIES_PER_PAGE) {
 		unsigned topidx = p2m_top_index(pfn);
 
 		p2m_top_mfn[topidx] = virt_to_mfn(p2m_top[topidx]);
 	}
 
-	for(idx = 0; idx < ARRAY_SIZE(p2m_top_mfn_list); idx++) {
+	for (idx = 0; idx < ARRAY_SIZE(p2m_top_mfn_list); idx++) {
 		unsigned topidx = idx * P2M_ENTRIES_PER_PAGE;
 		p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]);
 	}
@@ -179,7 +179,7 @@
 	unsigned long max_pfn = min(MAX_DOMAIN_PAGES, xen_start_info->nr_pages);
 	unsigned pfn;
 
-	for(pfn = 0; pfn < max_pfn; pfn += P2M_ENTRIES_PER_PAGE) {
+	for (pfn = 0; pfn < max_pfn; pfn += P2M_ENTRIES_PER_PAGE) {
 		unsigned topidx = p2m_top_index(pfn);
 
 		p2m_top[topidx] = &mfn_list[pfn];
@@ -207,7 +207,7 @@
 	p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
 	BUG_ON(p == NULL);
 
-	for(i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
+	for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
 		p[i] = INVALID_P2M_ENTRY;
 
 	if (cmpxchg(pp, p2m_missing, p) != p2m_missing)
@@ -407,7 +407,8 @@
 		preempt_enable();
 }
 
-pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+pte_t xen_ptep_modify_prot_start(struct mm_struct *mm,
+				 unsigned long addr, pte_t *ptep)
 {
 	/* Just return the pte as-is.  We preserve the bits on commit */
 	return *ptep;
@@ -878,7 +879,8 @@
 
 		if (user_pgd) {
 			xen_pin_page(mm, virt_to_page(user_pgd), PT_PGD);
-			xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(user_pgd)));
+			xen_do_pin(MMUEXT_PIN_L4_TABLE,
+				   PFN_DOWN(__pa(user_pgd)));
 		}
 	}
 #else /* CONFIG_X86_32 */
@@ -993,7 +995,8 @@
 		pgd_t *user_pgd = xen_get_user_pgd(pgd);
 
 		if (user_pgd) {
-			xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(user_pgd)));
+			xen_do_pin(MMUEXT_UNPIN_TABLE,
+				   PFN_DOWN(__pa(user_pgd)));
 			xen_unpin_page(mm, virt_to_page(user_pgd), PT_PGD);
 		}
 	}
diff --git a/arch/x86/xen/multicalls.c b/arch/x86/xen/multicalls.c
index 8ea8a0d..c738644 100644
--- a/arch/x86/xen/multicalls.c
+++ b/arch/x86/xen/multicalls.c
@@ -154,7 +154,7 @@
 			       ret, smp_processor_id());
 			dump_stack();
 			for (i = 0; i < b->mcidx; i++) {
-				printk("  call %2d/%d: op=%lu arg=[%lx] result=%ld\n",
+				printk(KERN_DEBUG "  call %2d/%d: op=%lu arg=[%lx] result=%ld\n",
 				       i+1, b->mcidx,
 				       b->debug[i].op,
 				       b->debug[i].args[0],
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index d679010..15c6c68 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -28,6 +28,9 @@
 /* These are code, but not functions.  Defined in entry.S */
 extern const char xen_hypervisor_callback[];
 extern const char xen_failsafe_callback[];
+extern void xen_sysenter_target(void);
+extern void xen_syscall_target(void);
+extern void xen_syscall32_target(void);
 
 
 /**
@@ -110,7 +113,6 @@
 
 void __cpuinit xen_enable_sysenter(void)
 {
-	extern void xen_sysenter_target(void);
 	int ret;
 	unsigned sysenter_feature;
 
@@ -132,8 +134,6 @@
 {
 #ifdef CONFIG_X86_64
 	int ret;
-	extern void xen_syscall_target(void);
-	extern void xen_syscall32_target(void);
 
 	ret = register_callback(CALLBACKTYPE_syscall, xen_syscall_target);
 	if (ret != 0) {
@@ -160,7 +160,8 @@
 	HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
 
 	if (!xen_feature(XENFEAT_auto_translated_physmap))
-		HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_pae_extended_cr3);
+		HYPERVISOR_vm_assist(VMASST_CMD_enable,
+				     VMASST_TYPE_pae_extended_cr3);
 
 	if (register_callback(CALLBACKTYPE_event, xen_hypervisor_callback) ||
 	    register_callback(CALLBACKTYPE_failsafe, xen_failsafe_callback))
diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c
index 11a20ad..64f057d 100644
--- a/arch/xtensa/platforms/iss/network.c
+++ b/arch/xtensa/platforms/iss/network.c
@@ -365,7 +365,7 @@
 
 static int iss_net_rx(struct net_device *dev)
 {
-	struct iss_net_private *lp = dev->priv;
+	struct iss_net_private *lp = netdev_priv(dev);
 	int pkt_len;
 	struct sk_buff *skb;
 
@@ -456,7 +456,7 @@
 
 static int iss_net_open(struct net_device *dev)
 {
-	struct iss_net_private *lp = dev->priv;
+	struct iss_net_private *lp = netdev_priv(dev);
 	char addr[sizeof "255.255.255.255\0"];
 	int err;
 
@@ -496,7 +496,7 @@
 
 static int iss_net_close(struct net_device *dev)
 {
-	struct iss_net_private *lp = dev->priv;
+	struct iss_net_private *lp = netdev_priv(dev);
 printk("iss_net_close!\n");
 	netif_stop_queue(dev);
 	spin_lock(&lp->lock);
@@ -515,7 +515,7 @@
 
 static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct iss_net_private *lp = dev->priv;
+	struct iss_net_private *lp = netdev_priv(dev);
 	unsigned long flags;
 	int len;
 
@@ -551,7 +551,7 @@
 
 static struct net_device_stats *iss_net_get_stats(struct net_device *dev)
 {
-	struct iss_net_private *lp = dev->priv;
+	struct iss_net_private *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
@@ -578,7 +578,7 @@
 static int iss_net_set_mac(struct net_device *dev, void *addr)
 {
 #if 0
-	struct iss_net_private *lp = dev->priv;
+	struct iss_net_private *lp = netdev_priv(dev);
 	struct sockaddr *hwaddr = addr;
 
 	spin_lock(&lp->lock);
@@ -592,7 +592,7 @@
 static int iss_net_change_mtu(struct net_device *dev, int new_mtu)
 {
 #if 0
-	struct iss_net_private *lp = dev->priv;
+	struct iss_net_private *lp = netdev_priv(dev);
 	int err = 0;
 
 	spin_lock(&lp->lock);
@@ -636,7 +636,7 @@
 
 	/* Initialize private element. */
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	*lp = ((struct iss_net_private) {
 		.device_list		= LIST_HEAD_INIT(lp->device_list),
 		.opened_list		= LIST_HEAD_INIT(lp->opened_list),
@@ -660,10 +660,7 @@
 
 	printk(KERN_INFO "Netdevice %d ", index);
 	if (lp->have_mac)
-		printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
-				lp->mac[0], lp->mac[1],
-				lp->mac[2], lp->mac[3],
-				lp->mac[4], lp->mac[5]);
+		printk("(%pM) ", lp->mac);
 	printk(": ");
 
 	/* sysfs register */
diff --git a/block/Kconfig b/block/Kconfig
index 1ab7c15..290b219 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -47,6 +47,7 @@
 	depends on SYSFS
 	select RELAY
 	select DEBUG_FS
+	select TRACEPOINTS
 	help
 	  Say Y here if you want to be able to trace the block layer actions
 	  on a given queue. Tracing allows you to see any traffic happening
diff --git a/block/blk-core.c b/block/blk-core.c
index c36aa98..561e8a1 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -28,9 +28,23 @@
 #include <linux/task_io_accounting_ops.h>
 #include <linux/blktrace_api.h>
 #include <linux/fault-inject.h>
+#include <trace/block.h>
 
 #include "blk.h"
 
+DEFINE_TRACE(block_plug);
+DEFINE_TRACE(block_unplug_io);
+DEFINE_TRACE(block_unplug_timer);
+DEFINE_TRACE(block_getrq);
+DEFINE_TRACE(block_sleeprq);
+DEFINE_TRACE(block_rq_requeue);
+DEFINE_TRACE(block_bio_backmerge);
+DEFINE_TRACE(block_bio_frontmerge);
+DEFINE_TRACE(block_bio_queue);
+DEFINE_TRACE(block_rq_complete);
+DEFINE_TRACE(block_remap);	/* Also used in drivers/md/dm.c */
+EXPORT_TRACEPOINT_SYMBOL_GPL(block_remap);
+
 static int __make_request(struct request_queue *q, struct bio *bio);
 
 /*
@@ -205,7 +219,7 @@
 
 	if (!queue_flag_test_and_set(QUEUE_FLAG_PLUGGED, q)) {
 		mod_timer(&q->unplug_timer, jiffies + q->unplug_delay);
-		blk_add_trace_generic(q, NULL, 0, BLK_TA_PLUG);
+		trace_block_plug(q);
 	}
 }
 EXPORT_SYMBOL(blk_plug_device);
@@ -292,9 +306,7 @@
 	struct request_queue *q =
 		container_of(work, struct request_queue, unplug_work);
 
-	blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL,
-				q->rq.count[READ] + q->rq.count[WRITE]);
-
+	trace_block_unplug_io(q);
 	q->unplug_fn(q);
 }
 
@@ -302,9 +314,7 @@
 {
 	struct request_queue *q = (struct request_queue *)data;
 
-	blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_TIMER, NULL,
-				q->rq.count[READ] + q->rq.count[WRITE]);
-
+	trace_block_unplug_timer(q);
 	kblockd_schedule_work(q, &q->unplug_work);
 }
 
@@ -314,9 +324,7 @@
 	 * devices don't necessarily have an ->unplug_fn defined
 	 */
 	if (q->unplug_fn) {
-		blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL,
-					q->rq.count[READ] + q->rq.count[WRITE]);
-
+		trace_block_unplug_io(q);
 		q->unplug_fn(q);
 	}
 }
@@ -822,7 +830,7 @@
 	if (ioc_batching(q, ioc))
 		ioc->nr_batch_requests--;
 
-	blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ);
+	trace_block_getrq(q, bio, rw);
 out:
 	return rq;
 }
@@ -848,7 +856,7 @@
 		prepare_to_wait_exclusive(&rl->wait[rw], &wait,
 				TASK_UNINTERRUPTIBLE);
 
-		blk_add_trace_generic(q, bio, rw, BLK_TA_SLEEPRQ);
+		trace_block_sleeprq(q, bio, rw);
 
 		__generic_unplug_device(q);
 		spin_unlock_irq(q->queue_lock);
@@ -928,7 +936,7 @@
 {
 	blk_delete_timer(rq);
 	blk_clear_rq_complete(rq);
-	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
+	trace_block_rq_requeue(q, rq);
 
 	if (blk_rq_tagged(rq))
 		blk_queue_end_tag(q, rq);
@@ -1167,7 +1175,7 @@
 		if (!ll_back_merge_fn(q, req, bio))
 			break;
 
-		blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
+		trace_block_bio_backmerge(q, bio);
 
 		req->biotail->bi_next = bio;
 		req->biotail = bio;
@@ -1186,7 +1194,7 @@
 		if (!ll_front_merge_fn(q, req, bio))
 			break;
 
-		blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
+		trace_block_bio_frontmerge(q, bio);
 
 		bio->bi_next = req->bio;
 		req->bio = bio;
@@ -1269,7 +1277,7 @@
 		bio->bi_sector += p->start_sect;
 		bio->bi_bdev = bdev->bd_contains;
 
-		blk_add_trace_remap(bdev_get_queue(bio->bi_bdev), bio,
+		trace_block_remap(bdev_get_queue(bio->bi_bdev), bio,
 				    bdev->bd_dev, bio->bi_sector,
 				    bio->bi_sector - p->start_sect);
 	}
@@ -1441,10 +1449,10 @@
 			goto end_io;
 
 		if (old_sector != -1)
-			blk_add_trace_remap(q, bio, old_dev, bio->bi_sector,
+			trace_block_remap(q, bio, old_dev, bio->bi_sector,
 					    old_sector);
 
-		blk_add_trace_bio(q, bio, BLK_TA_QUEUE);
+		trace_block_bio_queue(q, bio);
 
 		old_sector = bio->bi_sector;
 		old_dev = bio->bi_bdev->bd_dev;
@@ -1678,7 +1686,7 @@
 	int total_bytes, bio_nbytes, next_idx = 0;
 	struct bio *bio;
 
-	blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE);
+	trace_block_rq_complete(req->q, req);
 
 	/*
 	 * for a REQ_TYPE_BLOCK_PC request, we want to carry any eventual
diff --git a/block/blktrace.c b/block/blktrace.c
index 85049a7..b0a2cae 100644
--- a/block/blktrace.c
+++ b/block/blktrace.c
@@ -23,10 +23,18 @@
 #include <linux/mutex.h>
 #include <linux/debugfs.h>
 #include <linux/time.h>
+#include <trace/block.h>
 #include <asm/uaccess.h>
 
 static unsigned int blktrace_seq __read_mostly = 1;
 
+/* Global reference count of probes */
+static DEFINE_MUTEX(blk_probe_mutex);
+static atomic_t blk_probes_ref = ATOMIC_INIT(0);
+
+static int blk_register_tracepoints(void);
+static void blk_unregister_tracepoints(void);
+
 /*
  * Send out a notify message.
  */
@@ -119,7 +127,7 @@
  * The worker for the various blk_add_trace*() types. Fills out a
  * blk_io_trace structure and places it in a per-cpu subbuffer.
  */
-void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
+static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
 		     int rw, u32 what, int error, int pdu_len, void *pdu_data)
 {
 	struct task_struct *tsk = current;
@@ -177,8 +185,6 @@
 	local_irq_restore(flags);
 }
 
-EXPORT_SYMBOL_GPL(__blk_add_trace);
-
 static struct dentry *blk_tree_root;
 static DEFINE_MUTEX(blk_tree_mutex);
 static unsigned int root_users;
@@ -237,6 +243,10 @@
 	free_percpu(bt->sequence);
 	free_percpu(bt->msg_data);
 	kfree(bt);
+	mutex_lock(&blk_probe_mutex);
+	if (atomic_dec_and_test(&blk_probes_ref))
+		blk_unregister_tracepoints();
+	mutex_unlock(&blk_probe_mutex);
 }
 
 int blk_trace_remove(struct request_queue *q)
@@ -428,6 +438,14 @@
 	bt->pid = buts->pid;
 	bt->trace_state = Blktrace_setup;
 
+	mutex_lock(&blk_probe_mutex);
+	if (atomic_add_return(1, &blk_probes_ref) == 1) {
+		ret = blk_register_tracepoints();
+		if (ret)
+			goto probe_err;
+	}
+	mutex_unlock(&blk_probe_mutex);
+
 	ret = -EBUSY;
 	old_bt = xchg(&q->blk_trace, bt);
 	if (old_bt) {
@@ -436,6 +454,9 @@
 	}
 
 	return 0;
+probe_err:
+	atomic_dec(&blk_probes_ref);
+	mutex_unlock(&blk_probe_mutex);
 err:
 	if (dir)
 		blk_remove_tree(dir);
@@ -562,3 +583,308 @@
 		blk_trace_remove(q);
 	}
 }
+
+/*
+ * blktrace probes
+ */
+
+/**
+ * blk_add_trace_rq - Add a trace for a request oriented action
+ * @q:		queue the io is for
+ * @rq:		the source request
+ * @what:	the action
+ *
+ * Description:
+ *     Records an action against a request. Will log the bio offset + size.
+ *
+ **/
+static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
+				    u32 what)
+{
+	struct blk_trace *bt = q->blk_trace;
+	int rw = rq->cmd_flags & 0x03;
+
+	if (likely(!bt))
+		return;
+
+	if (blk_discard_rq(rq))
+		rw |= (1 << BIO_RW_DISCARD);
+
+	if (blk_pc_request(rq)) {
+		what |= BLK_TC_ACT(BLK_TC_PC);
+		__blk_add_trace(bt, 0, rq->data_len, rw, what, rq->errors,
+				sizeof(rq->cmd), rq->cmd);
+	} else  {
+		what |= BLK_TC_ACT(BLK_TC_FS);
+		__blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9,
+				rw, what, rq->errors, 0, NULL);
+	}
+}
+
+static void blk_add_trace_rq_abort(struct request_queue *q, struct request *rq)
+{
+	blk_add_trace_rq(q, rq, BLK_TA_ABORT);
+}
+
+static void blk_add_trace_rq_insert(struct request_queue *q, struct request *rq)
+{
+	blk_add_trace_rq(q, rq, BLK_TA_INSERT);
+}
+
+static void blk_add_trace_rq_issue(struct request_queue *q, struct request *rq)
+{
+	blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
+}
+
+static void blk_add_trace_rq_requeue(struct request_queue *q, struct request *rq)
+{
+	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
+}
+
+static void blk_add_trace_rq_complete(struct request_queue *q, struct request *rq)
+{
+	blk_add_trace_rq(q, rq, BLK_TA_COMPLETE);
+}
+
+/**
+ * blk_add_trace_bio - Add a trace for a bio oriented action
+ * @q:		queue the io is for
+ * @bio:	the source bio
+ * @what:	the action
+ *
+ * Description:
+ *     Records an action against a bio. Will log the bio offset + size.
+ *
+ **/
+static void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
+				     u32 what)
+{
+	struct blk_trace *bt = q->blk_trace;
+
+	if (likely(!bt))
+		return;
+
+	__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what,
+			!bio_flagged(bio, BIO_UPTODATE), 0, NULL);
+}
+
+static void blk_add_trace_bio_bounce(struct request_queue *q, struct bio *bio)
+{
+	blk_add_trace_bio(q, bio, BLK_TA_BOUNCE);
+}
+
+static void blk_add_trace_bio_complete(struct request_queue *q, struct bio *bio)
+{
+	blk_add_trace_bio(q, bio, BLK_TA_COMPLETE);
+}
+
+static void blk_add_trace_bio_backmerge(struct request_queue *q, struct bio *bio)
+{
+	blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
+}
+
+static void blk_add_trace_bio_frontmerge(struct request_queue *q, struct bio *bio)
+{
+	blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
+}
+
+static void blk_add_trace_bio_queue(struct request_queue *q, struct bio *bio)
+{
+	blk_add_trace_bio(q, bio, BLK_TA_QUEUE);
+}
+
+static void blk_add_trace_getrq(struct request_queue *q, struct bio *bio, int rw)
+{
+	if (bio)
+		blk_add_trace_bio(q, bio, BLK_TA_GETRQ);
+	else {
+		struct blk_trace *bt = q->blk_trace;
+
+		if (bt)
+			__blk_add_trace(bt, 0, 0, rw, BLK_TA_GETRQ, 0, 0, NULL);
+	}
+}
+
+
+static void blk_add_trace_sleeprq(struct request_queue *q, struct bio *bio, int rw)
+{
+	if (bio)
+		blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ);
+	else {
+		struct blk_trace *bt = q->blk_trace;
+
+		if (bt)
+			__blk_add_trace(bt, 0, 0, rw, BLK_TA_SLEEPRQ, 0, 0, NULL);
+	}
+}
+
+static void blk_add_trace_plug(struct request_queue *q)
+{
+	struct blk_trace *bt = q->blk_trace;
+
+	if (bt)
+		__blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL);
+}
+
+static void blk_add_trace_unplug_io(struct request_queue *q)
+{
+	struct blk_trace *bt = q->blk_trace;
+
+	if (bt) {
+		unsigned int pdu = q->rq.count[READ] + q->rq.count[WRITE];
+		__be64 rpdu = cpu_to_be64(pdu);
+
+		__blk_add_trace(bt, 0, 0, 0, BLK_TA_UNPLUG_IO, 0,
+				sizeof(rpdu), &rpdu);
+	}
+}
+
+static void blk_add_trace_unplug_timer(struct request_queue *q)
+{
+	struct blk_trace *bt = q->blk_trace;
+
+	if (bt) {
+		unsigned int pdu = q->rq.count[READ] + q->rq.count[WRITE];
+		__be64 rpdu = cpu_to_be64(pdu);
+
+		__blk_add_trace(bt, 0, 0, 0, BLK_TA_UNPLUG_TIMER, 0,
+				sizeof(rpdu), &rpdu);
+	}
+}
+
+static void blk_add_trace_split(struct request_queue *q, struct bio *bio,
+				unsigned int pdu)
+{
+	struct blk_trace *bt = q->blk_trace;
+
+	if (bt) {
+		__be64 rpdu = cpu_to_be64(pdu);
+
+		__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw,
+				BLK_TA_SPLIT, !bio_flagged(bio, BIO_UPTODATE),
+				sizeof(rpdu), &rpdu);
+	}
+}
+
+/**
+ * blk_add_trace_remap - Add a trace for a remap operation
+ * @q:		queue the io is for
+ * @bio:	the source bio
+ * @dev:	target device
+ * @from:	source sector
+ * @to:		target sector
+ *
+ * Description:
+ *     Device mapper or raid target sometimes need to split a bio because
+ *     it spans a stripe (or similar). Add a trace for that action.
+ *
+ **/
+static void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
+				       dev_t dev, sector_t from, sector_t to)
+{
+	struct blk_trace *bt = q->blk_trace;
+	struct blk_io_trace_remap r;
+
+	if (likely(!bt))
+		return;
+
+	r.device = cpu_to_be32(dev);
+	r.device_from = cpu_to_be32(bio->bi_bdev->bd_dev);
+	r.sector = cpu_to_be64(to);
+
+	__blk_add_trace(bt, from, bio->bi_size, bio->bi_rw, BLK_TA_REMAP,
+			!bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r);
+}
+
+/**
+ * blk_add_driver_data - Add binary message with driver-specific data
+ * @q:		queue the io is for
+ * @rq:		io request
+ * @data:	driver-specific data
+ * @len:	length of driver-specific data
+ *
+ * Description:
+ *     Some drivers might want to write driver-specific data per request.
+ *
+ **/
+void blk_add_driver_data(struct request_queue *q,
+			 struct request *rq,
+			 void *data, size_t len)
+{
+	struct blk_trace *bt = q->blk_trace;
+
+	if (likely(!bt))
+		return;
+
+	if (blk_pc_request(rq))
+		__blk_add_trace(bt, 0, rq->data_len, 0, BLK_TA_DRV_DATA,
+				rq->errors, len, data);
+	else
+		__blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9,
+				0, BLK_TA_DRV_DATA, rq->errors, len, data);
+}
+EXPORT_SYMBOL_GPL(blk_add_driver_data);
+
+static int blk_register_tracepoints(void)
+{
+	int ret;
+
+	ret = register_trace_block_rq_abort(blk_add_trace_rq_abort);
+	WARN_ON(ret);
+	ret = register_trace_block_rq_insert(blk_add_trace_rq_insert);
+	WARN_ON(ret);
+	ret = register_trace_block_rq_issue(blk_add_trace_rq_issue);
+	WARN_ON(ret);
+	ret = register_trace_block_rq_requeue(blk_add_trace_rq_requeue);
+	WARN_ON(ret);
+	ret = register_trace_block_rq_complete(blk_add_trace_rq_complete);
+	WARN_ON(ret);
+	ret = register_trace_block_bio_bounce(blk_add_trace_bio_bounce);
+	WARN_ON(ret);
+	ret = register_trace_block_bio_complete(blk_add_trace_bio_complete);
+	WARN_ON(ret);
+	ret = register_trace_block_bio_backmerge(blk_add_trace_bio_backmerge);
+	WARN_ON(ret);
+	ret = register_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge);
+	WARN_ON(ret);
+	ret = register_trace_block_bio_queue(blk_add_trace_bio_queue);
+	WARN_ON(ret);
+	ret = register_trace_block_getrq(blk_add_trace_getrq);
+	WARN_ON(ret);
+	ret = register_trace_block_sleeprq(blk_add_trace_sleeprq);
+	WARN_ON(ret);
+	ret = register_trace_block_plug(blk_add_trace_plug);
+	WARN_ON(ret);
+	ret = register_trace_block_unplug_timer(blk_add_trace_unplug_timer);
+	WARN_ON(ret);
+	ret = register_trace_block_unplug_io(blk_add_trace_unplug_io);
+	WARN_ON(ret);
+	ret = register_trace_block_split(blk_add_trace_split);
+	WARN_ON(ret);
+	ret = register_trace_block_remap(blk_add_trace_remap);
+	WARN_ON(ret);
+	return 0;
+}
+
+static void blk_unregister_tracepoints(void)
+{
+	unregister_trace_block_remap(blk_add_trace_remap);
+	unregister_trace_block_split(blk_add_trace_split);
+	unregister_trace_block_unplug_io(blk_add_trace_unplug_io);
+	unregister_trace_block_unplug_timer(blk_add_trace_unplug_timer);
+	unregister_trace_block_plug(blk_add_trace_plug);
+	unregister_trace_block_sleeprq(blk_add_trace_sleeprq);
+	unregister_trace_block_getrq(blk_add_trace_getrq);
+	unregister_trace_block_bio_queue(blk_add_trace_bio_queue);
+	unregister_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge);
+	unregister_trace_block_bio_backmerge(blk_add_trace_bio_backmerge);
+	unregister_trace_block_bio_complete(blk_add_trace_bio_complete);
+	unregister_trace_block_bio_bounce(blk_add_trace_bio_bounce);
+	unregister_trace_block_rq_complete(blk_add_trace_rq_complete);
+	unregister_trace_block_rq_requeue(blk_add_trace_rq_requeue);
+	unregister_trace_block_rq_issue(blk_add_trace_rq_issue);
+	unregister_trace_block_rq_insert(blk_add_trace_rq_insert);
+	unregister_trace_block_rq_abort(blk_add_trace_rq_abort);
+
+	tracepoint_synchronize_unregister();
+}
diff --git a/block/elevator.c b/block/elevator.c
index a6951f7..86836dd 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -33,6 +33,7 @@
 #include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/blktrace_api.h>
+#include <trace/block.h>
 #include <linux/hash.h>
 #include <linux/uaccess.h>
 
@@ -41,6 +42,8 @@
 static DEFINE_SPINLOCK(elv_list_lock);
 static LIST_HEAD(elv_list);
 
+DEFINE_TRACE(block_rq_abort);
+
 /*
  * Merge hash stuff.
  */
@@ -52,6 +55,9 @@
 #define rq_hash_key(rq)		((rq)->sector + (rq)->nr_sectors)
 #define ELV_ON_HASH(rq)		(!hlist_unhashed(&(rq)->hash))
 
+DEFINE_TRACE(block_rq_insert);
+DEFINE_TRACE(block_rq_issue);
+
 /*
  * Query io scheduler to see if the current process issuing bio may be
  * merged with rq.
@@ -586,7 +592,7 @@
 	unsigned ordseq;
 	int unplug_it = 1;
 
-	blk_add_trace_rq(q, rq, BLK_TA_INSERT);
+	trace_block_rq_insert(q, rq);
 
 	rq->q = q;
 
@@ -772,7 +778,7 @@
 			 * not be passed by new incoming requests
 			 */
 			rq->cmd_flags |= REQ_STARTED;
-			blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
+			trace_block_rq_issue(q, rq);
 		}
 
 		if (!q->boundary_rq || q->boundary_rq == rq) {
@@ -914,7 +920,7 @@
 	while (!list_empty(&q->queue_head)) {
 		rq = list_entry_rq(q->queue_head.next);
 		rq->cmd_flags |= REQ_QUIET;
-		blk_add_trace_rq(q, rq, BLK_TA_ABORT);
+		trace_block_rq_abort(q, rq);
 		__blk_end_request(rq, -EIO, blk_rq_bytes(rq));
 	}
 }
diff --git a/crypto/Kconfig b/crypto/Kconfig
index dc20a34b..8dde4fc 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -102,6 +102,7 @@
 	tristate "Null algorithms"
 	select CRYPTO_ALGAPI
 	select CRYPTO_BLKCIPHER
+	select CRYPTO_HASH
 	help
 	  These are 'Null' algorithms, used by IPsec, which do nothing.
 
@@ -256,12 +257,10 @@
 config CRYPTO_CRC32C
 	tristate "CRC32c CRC algorithm"
 	select CRYPTO_HASH
-	select LIBCRC32C
 	help
 	  Castagnoli, et al Cyclic Redundancy-Check Algorithm.  Used
 	  by iSCSI for header and data digests and by others.
-	  See Castagnoli93.  This implementation uses lib/libcrc32c.
-	  Module will be crc32c.
+	  See Castagnoli93.  Module will be crc32c.
 
 config CRYPTO_CRC32C_INTEL
 	tristate "CRC32c INTEL hardware acceleration"
@@ -277,19 +276,19 @@
 
 config CRYPTO_MD4
 	tristate "MD4 digest algorithm"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  MD4 message digest algorithm (RFC1320).
 
 config CRYPTO_MD5
 	tristate "MD5 digest algorithm"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  MD5 message digest algorithm (RFC1321).
 
 config CRYPTO_MICHAEL_MIC
 	tristate "Michael MIC keyed digest algorithm"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  Michael MIC is used for message integrity protection in TKIP
 	  (IEEE 802.11i). This algorithm is required for TKIP, but it
@@ -298,7 +297,7 @@
 
 config CRYPTO_RMD128
 	tristate "RIPEMD-128 digest algorithm"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  RIPEMD-128 (ISO/IEC 10118-3:2004).
 
@@ -311,7 +310,7 @@
 
 config CRYPTO_RMD160
 	tristate "RIPEMD-160 digest algorithm"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  RIPEMD-160 (ISO/IEC 10118-3:2004).
 
@@ -328,7 +327,7 @@
 
 config CRYPTO_RMD256
 	tristate "RIPEMD-256 digest algorithm"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  RIPEMD-256 is an optional extension of RIPEMD-128 with a
 	  256 bit hash. It is intended for applications that require
@@ -340,7 +339,7 @@
 
 config CRYPTO_RMD320
 	tristate "RIPEMD-320 digest algorithm"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  RIPEMD-320 is an optional extension of RIPEMD-160 with a
 	  320 bit hash. It is intended for applications that require
@@ -352,13 +351,13 @@
 
 config CRYPTO_SHA1
 	tristate "SHA1 digest algorithm"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
 
 config CRYPTO_SHA256
 	tristate "SHA224 and SHA256 digest algorithm"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  SHA256 secure hash standard (DFIPS 180-2).
 
@@ -370,7 +369,7 @@
 
 config CRYPTO_SHA512
 	tristate "SHA384 and SHA512 digest algorithms"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  SHA512 secure hash standard (DFIPS 180-2).
 
@@ -382,7 +381,7 @@
 
 config CRYPTO_TGR192
 	tristate "Tiger digest algorithms"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  Tiger hash algorithm 192, 160 and 128-bit hashes
 
@@ -395,7 +394,7 @@
 
 config CRYPTO_WP512
 	tristate "Whirlpool digest algorithms"
-	select CRYPTO_ALGAPI
+	select CRYPTO_HASH
 	help
 	  Whirlpool hash algorithm 512, 384 and 256-bit hashes
 
diff --git a/crypto/Makefile b/crypto/Makefile
index cd4a4ed..46b08bf 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -22,6 +22,7 @@
 
 crypto_hash-objs := hash.o
 crypto_hash-objs += ahash.o
+crypto_hash-objs += shash.o
 obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o
 
 cryptomgr-objs := algboss.o testmgr.o
diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c
index 136dc98..b8b66ec 100644
--- a/crypto/aes_generic.c
+++ b/crypto/aes_generic.c
@@ -60,103 +60,1069 @@
 	return x >> (n << 3);
 }
 
-static u8 pow_tab[256] __initdata;
-static u8 log_tab[256] __initdata;
-static u8 sbx_tab[256] __initdata;
-static u8 isb_tab[256] __initdata;
-static u32 rco_tab[10];
+static const u32 rco_tab[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 };
 
-u32 crypto_ft_tab[4][256];
-u32 crypto_fl_tab[4][256];
-u32 crypto_it_tab[4][256];
-u32 crypto_il_tab[4][256];
+const u32 crypto_ft_tab[4][256] = {
+	{
+		0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6,
+		0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591,
+		0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56,
+		0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec,
+		0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
+		0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb,
+		0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45,
+		0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b,
+		0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c,
+		0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
+		0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9,
+		0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a,
+		0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d,
+		0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f,
+		0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+		0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea,
+		0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34,
+		0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b,
+		0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d,
+		0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
+		0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1,
+		0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6,
+		0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972,
+		0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,
+		0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
+		0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511,
+		0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe,
+		0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b,
+		0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05,
+		0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+		0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142,
+		0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf,
+		0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3,
+		0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e,
+		0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
+		0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6,
+		0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3,
+		0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b,
+		0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428,
+		0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
+		0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14,
+		0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8,
+		0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4,
+		0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2,
+		0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+		0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949,
+		0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf,
+		0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810,
+		0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c,
+		0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
+		0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e,
+		0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f,
+		0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc,
+		0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c,
+		0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
+		0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27,
+		0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122,
+		0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433,
+		0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9,
+		0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+		0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a,
+		0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0,
+		0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e,
+		0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c,
+	}, {
+		0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d,
+		0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154,
+		0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d,
+		0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a,
+		0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87,
+		0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b,
+		0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea,
+		0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b,
+		0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a,
+		0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f,
+		0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908,
+		0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f,
+		0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e,
+		0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5,
+		0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,
+		0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f,
+		0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e,
+		0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb,
+		0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce,
+		0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397,
+		0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c,
+		0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed,
+		0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b,
+		0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a,
+		0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16,
+		0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194,
+		0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81,
+		0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3,
+		0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a,
+		0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
+		0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263,
+		0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d,
+		0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f,
+		0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39,
+		0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47,
+		0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695,
+		0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f,
+		0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83,
+		0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c,
+		0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76,
+		0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e,
+		0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4,
+		0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6,
+		0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b,
+		0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7,
+		0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0,
+		0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25,
+		0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018,
+		0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72,
+		0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751,
+		0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21,
+		0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85,
+		0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa,
+		0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12,
+		0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0,
+		0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9,
+		0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233,
+		0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7,
+		0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920,
+		0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
+		0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17,
+		0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8,
+		0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11,
+		0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a,
+	}, {
+		0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b,
+		0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5,
+		0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b,
+		0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76,
+		0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d,
+		0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0,
+		0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf,
+		0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0,
+		0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26,
+		0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc,
+		0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1,
+		0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15,
+		0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3,
+		0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a,
+		0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,
+		0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75,
+		0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a,
+		0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0,
+		0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3,
+		0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784,
+		0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced,
+		0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b,
+		0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39,
+		0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf,
+		0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb,
+		0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485,
+		0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f,
+		0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8,
+		0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f,
+		0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
+		0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321,
+		0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2,
+		0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec,
+		0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917,
+		0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d,
+		0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573,
+		0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc,
+		0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388,
+		0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14,
+		0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db,
+		0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a,
+		0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c,
+		0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662,
+		0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79,
+		0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d,
+		0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9,
+		0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea,
+		0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808,
+		0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e,
+		0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6,
+		0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f,
+		0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a,
+		0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66,
+		0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e,
+		0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9,
+		0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e,
+		0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311,
+		0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794,
+		0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9,
+		0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
+		0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d,
+		0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868,
+		0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f,
+		0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16,
+	}, {
+		0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b,
+		0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5,
+		0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b,
+		0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676,
+		0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d,
+		0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0,
+		0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf,
+		0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0,
+		0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626,
+		0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc,
+		0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1,
+		0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515,
+		0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3,
+		0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a,
+		0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,
+		0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575,
+		0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a,
+		0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0,
+		0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3,
+		0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484,
+		0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded,
+		0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b,
+		0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939,
+		0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf,
+		0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb,
+		0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585,
+		0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f,
+		0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8,
+		0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f,
+		0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
+		0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121,
+		0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2,
+		0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec,
+		0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717,
+		0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d,
+		0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373,
+		0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc,
+		0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888,
+		0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414,
+		0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb,
+		0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a,
+		0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c,
+		0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262,
+		0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979,
+		0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d,
+		0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9,
+		0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea,
+		0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808,
+		0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e,
+		0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6,
+		0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f,
+		0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a,
+		0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666,
+		0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e,
+		0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9,
+		0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e,
+		0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111,
+		0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494,
+		0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9,
+		0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
+		0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d,
+		0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868,
+		0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f,
+		0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616,
+	}
+};
+
+const u32 crypto_fl_tab[4][256] = {
+	{
+		0x00000063, 0x0000007c, 0x00000077, 0x0000007b,
+		0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5,
+		0x00000030, 0x00000001, 0x00000067, 0x0000002b,
+		0x000000fe, 0x000000d7, 0x000000ab, 0x00000076,
+		0x000000ca, 0x00000082, 0x000000c9, 0x0000007d,
+		0x000000fa, 0x00000059, 0x00000047, 0x000000f0,
+		0x000000ad, 0x000000d4, 0x000000a2, 0x000000af,
+		0x0000009c, 0x000000a4, 0x00000072, 0x000000c0,
+		0x000000b7, 0x000000fd, 0x00000093, 0x00000026,
+		0x00000036, 0x0000003f, 0x000000f7, 0x000000cc,
+		0x00000034, 0x000000a5, 0x000000e5, 0x000000f1,
+		0x00000071, 0x000000d8, 0x00000031, 0x00000015,
+		0x00000004, 0x000000c7, 0x00000023, 0x000000c3,
+		0x00000018, 0x00000096, 0x00000005, 0x0000009a,
+		0x00000007, 0x00000012, 0x00000080, 0x000000e2,
+		0x000000eb, 0x00000027, 0x000000b2, 0x00000075,
+		0x00000009, 0x00000083, 0x0000002c, 0x0000001a,
+		0x0000001b, 0x0000006e, 0x0000005a, 0x000000a0,
+		0x00000052, 0x0000003b, 0x000000d6, 0x000000b3,
+		0x00000029, 0x000000e3, 0x0000002f, 0x00000084,
+		0x00000053, 0x000000d1, 0x00000000, 0x000000ed,
+		0x00000020, 0x000000fc, 0x000000b1, 0x0000005b,
+		0x0000006a, 0x000000cb, 0x000000be, 0x00000039,
+		0x0000004a, 0x0000004c, 0x00000058, 0x000000cf,
+		0x000000d0, 0x000000ef, 0x000000aa, 0x000000fb,
+		0x00000043, 0x0000004d, 0x00000033, 0x00000085,
+		0x00000045, 0x000000f9, 0x00000002, 0x0000007f,
+		0x00000050, 0x0000003c, 0x0000009f, 0x000000a8,
+		0x00000051, 0x000000a3, 0x00000040, 0x0000008f,
+		0x00000092, 0x0000009d, 0x00000038, 0x000000f5,
+		0x000000bc, 0x000000b6, 0x000000da, 0x00000021,
+		0x00000010, 0x000000ff, 0x000000f3, 0x000000d2,
+		0x000000cd, 0x0000000c, 0x00000013, 0x000000ec,
+		0x0000005f, 0x00000097, 0x00000044, 0x00000017,
+		0x000000c4, 0x000000a7, 0x0000007e, 0x0000003d,
+		0x00000064, 0x0000005d, 0x00000019, 0x00000073,
+		0x00000060, 0x00000081, 0x0000004f, 0x000000dc,
+		0x00000022, 0x0000002a, 0x00000090, 0x00000088,
+		0x00000046, 0x000000ee, 0x000000b8, 0x00000014,
+		0x000000de, 0x0000005e, 0x0000000b, 0x000000db,
+		0x000000e0, 0x00000032, 0x0000003a, 0x0000000a,
+		0x00000049, 0x00000006, 0x00000024, 0x0000005c,
+		0x000000c2, 0x000000d3, 0x000000ac, 0x00000062,
+		0x00000091, 0x00000095, 0x000000e4, 0x00000079,
+		0x000000e7, 0x000000c8, 0x00000037, 0x0000006d,
+		0x0000008d, 0x000000d5, 0x0000004e, 0x000000a9,
+		0x0000006c, 0x00000056, 0x000000f4, 0x000000ea,
+		0x00000065, 0x0000007a, 0x000000ae, 0x00000008,
+		0x000000ba, 0x00000078, 0x00000025, 0x0000002e,
+		0x0000001c, 0x000000a6, 0x000000b4, 0x000000c6,
+		0x000000e8, 0x000000dd, 0x00000074, 0x0000001f,
+		0x0000004b, 0x000000bd, 0x0000008b, 0x0000008a,
+		0x00000070, 0x0000003e, 0x000000b5, 0x00000066,
+		0x00000048, 0x00000003, 0x000000f6, 0x0000000e,
+		0x00000061, 0x00000035, 0x00000057, 0x000000b9,
+		0x00000086, 0x000000c1, 0x0000001d, 0x0000009e,
+		0x000000e1, 0x000000f8, 0x00000098, 0x00000011,
+		0x00000069, 0x000000d9, 0x0000008e, 0x00000094,
+		0x0000009b, 0x0000001e, 0x00000087, 0x000000e9,
+		0x000000ce, 0x00000055, 0x00000028, 0x000000df,
+		0x0000008c, 0x000000a1, 0x00000089, 0x0000000d,
+		0x000000bf, 0x000000e6, 0x00000042, 0x00000068,
+		0x00000041, 0x00000099, 0x0000002d, 0x0000000f,
+		0x000000b0, 0x00000054, 0x000000bb, 0x00000016,
+	}, {
+		0x00006300, 0x00007c00, 0x00007700, 0x00007b00,
+		0x0000f200, 0x00006b00, 0x00006f00, 0x0000c500,
+		0x00003000, 0x00000100, 0x00006700, 0x00002b00,
+		0x0000fe00, 0x0000d700, 0x0000ab00, 0x00007600,
+		0x0000ca00, 0x00008200, 0x0000c900, 0x00007d00,
+		0x0000fa00, 0x00005900, 0x00004700, 0x0000f000,
+		0x0000ad00, 0x0000d400, 0x0000a200, 0x0000af00,
+		0x00009c00, 0x0000a400, 0x00007200, 0x0000c000,
+		0x0000b700, 0x0000fd00, 0x00009300, 0x00002600,
+		0x00003600, 0x00003f00, 0x0000f700, 0x0000cc00,
+		0x00003400, 0x0000a500, 0x0000e500, 0x0000f100,
+		0x00007100, 0x0000d800, 0x00003100, 0x00001500,
+		0x00000400, 0x0000c700, 0x00002300, 0x0000c300,
+		0x00001800, 0x00009600, 0x00000500, 0x00009a00,
+		0x00000700, 0x00001200, 0x00008000, 0x0000e200,
+		0x0000eb00, 0x00002700, 0x0000b200, 0x00007500,
+		0x00000900, 0x00008300, 0x00002c00, 0x00001a00,
+		0x00001b00, 0x00006e00, 0x00005a00, 0x0000a000,
+		0x00005200, 0x00003b00, 0x0000d600, 0x0000b300,
+		0x00002900, 0x0000e300, 0x00002f00, 0x00008400,
+		0x00005300, 0x0000d100, 0x00000000, 0x0000ed00,
+		0x00002000, 0x0000fc00, 0x0000b100, 0x00005b00,
+		0x00006a00, 0x0000cb00, 0x0000be00, 0x00003900,
+		0x00004a00, 0x00004c00, 0x00005800, 0x0000cf00,
+		0x0000d000, 0x0000ef00, 0x0000aa00, 0x0000fb00,
+		0x00004300, 0x00004d00, 0x00003300, 0x00008500,
+		0x00004500, 0x0000f900, 0x00000200, 0x00007f00,
+		0x00005000, 0x00003c00, 0x00009f00, 0x0000a800,
+		0x00005100, 0x0000a300, 0x00004000, 0x00008f00,
+		0x00009200, 0x00009d00, 0x00003800, 0x0000f500,
+		0x0000bc00, 0x0000b600, 0x0000da00, 0x00002100,
+		0x00001000, 0x0000ff00, 0x0000f300, 0x0000d200,
+		0x0000cd00, 0x00000c00, 0x00001300, 0x0000ec00,
+		0x00005f00, 0x00009700, 0x00004400, 0x00001700,
+		0x0000c400, 0x0000a700, 0x00007e00, 0x00003d00,
+		0x00006400, 0x00005d00, 0x00001900, 0x00007300,
+		0x00006000, 0x00008100, 0x00004f00, 0x0000dc00,
+		0x00002200, 0x00002a00, 0x00009000, 0x00008800,
+		0x00004600, 0x0000ee00, 0x0000b800, 0x00001400,
+		0x0000de00, 0x00005e00, 0x00000b00, 0x0000db00,
+		0x0000e000, 0x00003200, 0x00003a00, 0x00000a00,
+		0x00004900, 0x00000600, 0x00002400, 0x00005c00,
+		0x0000c200, 0x0000d300, 0x0000ac00, 0x00006200,
+		0x00009100, 0x00009500, 0x0000e400, 0x00007900,
+		0x0000e700, 0x0000c800, 0x00003700, 0x00006d00,
+		0x00008d00, 0x0000d500, 0x00004e00, 0x0000a900,
+		0x00006c00, 0x00005600, 0x0000f400, 0x0000ea00,
+		0x00006500, 0x00007a00, 0x0000ae00, 0x00000800,
+		0x0000ba00, 0x00007800, 0x00002500, 0x00002e00,
+		0x00001c00, 0x0000a600, 0x0000b400, 0x0000c600,
+		0x0000e800, 0x0000dd00, 0x00007400, 0x00001f00,
+		0x00004b00, 0x0000bd00, 0x00008b00, 0x00008a00,
+		0x00007000, 0x00003e00, 0x0000b500, 0x00006600,
+		0x00004800, 0x00000300, 0x0000f600, 0x00000e00,
+		0x00006100, 0x00003500, 0x00005700, 0x0000b900,
+		0x00008600, 0x0000c100, 0x00001d00, 0x00009e00,
+		0x0000e100, 0x0000f800, 0x00009800, 0x00001100,
+		0x00006900, 0x0000d900, 0x00008e00, 0x00009400,
+		0x00009b00, 0x00001e00, 0x00008700, 0x0000e900,
+		0x0000ce00, 0x00005500, 0x00002800, 0x0000df00,
+		0x00008c00, 0x0000a100, 0x00008900, 0x00000d00,
+		0x0000bf00, 0x0000e600, 0x00004200, 0x00006800,
+		0x00004100, 0x00009900, 0x00002d00, 0x00000f00,
+		0x0000b000, 0x00005400, 0x0000bb00, 0x00001600,
+	}, {
+		0x00630000, 0x007c0000, 0x00770000, 0x007b0000,
+		0x00f20000, 0x006b0000, 0x006f0000, 0x00c50000,
+		0x00300000, 0x00010000, 0x00670000, 0x002b0000,
+		0x00fe0000, 0x00d70000, 0x00ab0000, 0x00760000,
+		0x00ca0000, 0x00820000, 0x00c90000, 0x007d0000,
+		0x00fa0000, 0x00590000, 0x00470000, 0x00f00000,
+		0x00ad0000, 0x00d40000, 0x00a20000, 0x00af0000,
+		0x009c0000, 0x00a40000, 0x00720000, 0x00c00000,
+		0x00b70000, 0x00fd0000, 0x00930000, 0x00260000,
+		0x00360000, 0x003f0000, 0x00f70000, 0x00cc0000,
+		0x00340000, 0x00a50000, 0x00e50000, 0x00f10000,
+		0x00710000, 0x00d80000, 0x00310000, 0x00150000,
+		0x00040000, 0x00c70000, 0x00230000, 0x00c30000,
+		0x00180000, 0x00960000, 0x00050000, 0x009a0000,
+		0x00070000, 0x00120000, 0x00800000, 0x00e20000,
+		0x00eb0000, 0x00270000, 0x00b20000, 0x00750000,
+		0x00090000, 0x00830000, 0x002c0000, 0x001a0000,
+		0x001b0000, 0x006e0000, 0x005a0000, 0x00a00000,
+		0x00520000, 0x003b0000, 0x00d60000, 0x00b30000,
+		0x00290000, 0x00e30000, 0x002f0000, 0x00840000,
+		0x00530000, 0x00d10000, 0x00000000, 0x00ed0000,
+		0x00200000, 0x00fc0000, 0x00b10000, 0x005b0000,
+		0x006a0000, 0x00cb0000, 0x00be0000, 0x00390000,
+		0x004a0000, 0x004c0000, 0x00580000, 0x00cf0000,
+		0x00d00000, 0x00ef0000, 0x00aa0000, 0x00fb0000,
+		0x00430000, 0x004d0000, 0x00330000, 0x00850000,
+		0x00450000, 0x00f90000, 0x00020000, 0x007f0000,
+		0x00500000, 0x003c0000, 0x009f0000, 0x00a80000,
+		0x00510000, 0x00a30000, 0x00400000, 0x008f0000,
+		0x00920000, 0x009d0000, 0x00380000, 0x00f50000,
+		0x00bc0000, 0x00b60000, 0x00da0000, 0x00210000,
+		0x00100000, 0x00ff0000, 0x00f30000, 0x00d20000,
+		0x00cd0000, 0x000c0000, 0x00130000, 0x00ec0000,
+		0x005f0000, 0x00970000, 0x00440000, 0x00170000,
+		0x00c40000, 0x00a70000, 0x007e0000, 0x003d0000,
+		0x00640000, 0x005d0000, 0x00190000, 0x00730000,
+		0x00600000, 0x00810000, 0x004f0000, 0x00dc0000,
+		0x00220000, 0x002a0000, 0x00900000, 0x00880000,
+		0x00460000, 0x00ee0000, 0x00b80000, 0x00140000,
+		0x00de0000, 0x005e0000, 0x000b0000, 0x00db0000,
+		0x00e00000, 0x00320000, 0x003a0000, 0x000a0000,
+		0x00490000, 0x00060000, 0x00240000, 0x005c0000,
+		0x00c20000, 0x00d30000, 0x00ac0000, 0x00620000,
+		0x00910000, 0x00950000, 0x00e40000, 0x00790000,
+		0x00e70000, 0x00c80000, 0x00370000, 0x006d0000,
+		0x008d0000, 0x00d50000, 0x004e0000, 0x00a90000,
+		0x006c0000, 0x00560000, 0x00f40000, 0x00ea0000,
+		0x00650000, 0x007a0000, 0x00ae0000, 0x00080000,
+		0x00ba0000, 0x00780000, 0x00250000, 0x002e0000,
+		0x001c0000, 0x00a60000, 0x00b40000, 0x00c60000,
+		0x00e80000, 0x00dd0000, 0x00740000, 0x001f0000,
+		0x004b0000, 0x00bd0000, 0x008b0000, 0x008a0000,
+		0x00700000, 0x003e0000, 0x00b50000, 0x00660000,
+		0x00480000, 0x00030000, 0x00f60000, 0x000e0000,
+		0x00610000, 0x00350000, 0x00570000, 0x00b90000,
+		0x00860000, 0x00c10000, 0x001d0000, 0x009e0000,
+		0x00e10000, 0x00f80000, 0x00980000, 0x00110000,
+		0x00690000, 0x00d90000, 0x008e0000, 0x00940000,
+		0x009b0000, 0x001e0000, 0x00870000, 0x00e90000,
+		0x00ce0000, 0x00550000, 0x00280000, 0x00df0000,
+		0x008c0000, 0x00a10000, 0x00890000, 0x000d0000,
+		0x00bf0000, 0x00e60000, 0x00420000, 0x00680000,
+		0x00410000, 0x00990000, 0x002d0000, 0x000f0000,
+		0x00b00000, 0x00540000, 0x00bb0000, 0x00160000,
+	}, {
+		0x63000000, 0x7c000000, 0x77000000, 0x7b000000,
+		0xf2000000, 0x6b000000, 0x6f000000, 0xc5000000,
+		0x30000000, 0x01000000, 0x67000000, 0x2b000000,
+		0xfe000000, 0xd7000000, 0xab000000, 0x76000000,
+		0xca000000, 0x82000000, 0xc9000000, 0x7d000000,
+		0xfa000000, 0x59000000, 0x47000000, 0xf0000000,
+		0xad000000, 0xd4000000, 0xa2000000, 0xaf000000,
+		0x9c000000, 0xa4000000, 0x72000000, 0xc0000000,
+		0xb7000000, 0xfd000000, 0x93000000, 0x26000000,
+		0x36000000, 0x3f000000, 0xf7000000, 0xcc000000,
+		0x34000000, 0xa5000000, 0xe5000000, 0xf1000000,
+		0x71000000, 0xd8000000, 0x31000000, 0x15000000,
+		0x04000000, 0xc7000000, 0x23000000, 0xc3000000,
+		0x18000000, 0x96000000, 0x05000000, 0x9a000000,
+		0x07000000, 0x12000000, 0x80000000, 0xe2000000,
+		0xeb000000, 0x27000000, 0xb2000000, 0x75000000,
+		0x09000000, 0x83000000, 0x2c000000, 0x1a000000,
+		0x1b000000, 0x6e000000, 0x5a000000, 0xa0000000,
+		0x52000000, 0x3b000000, 0xd6000000, 0xb3000000,
+		0x29000000, 0xe3000000, 0x2f000000, 0x84000000,
+		0x53000000, 0xd1000000, 0x00000000, 0xed000000,
+		0x20000000, 0xfc000000, 0xb1000000, 0x5b000000,
+		0x6a000000, 0xcb000000, 0xbe000000, 0x39000000,
+		0x4a000000, 0x4c000000, 0x58000000, 0xcf000000,
+		0xd0000000, 0xef000000, 0xaa000000, 0xfb000000,
+		0x43000000, 0x4d000000, 0x33000000, 0x85000000,
+		0x45000000, 0xf9000000, 0x02000000, 0x7f000000,
+		0x50000000, 0x3c000000, 0x9f000000, 0xa8000000,
+		0x51000000, 0xa3000000, 0x40000000, 0x8f000000,
+		0x92000000, 0x9d000000, 0x38000000, 0xf5000000,
+		0xbc000000, 0xb6000000, 0xda000000, 0x21000000,
+		0x10000000, 0xff000000, 0xf3000000, 0xd2000000,
+		0xcd000000, 0x0c000000, 0x13000000, 0xec000000,
+		0x5f000000, 0x97000000, 0x44000000, 0x17000000,
+		0xc4000000, 0xa7000000, 0x7e000000, 0x3d000000,
+		0x64000000, 0x5d000000, 0x19000000, 0x73000000,
+		0x60000000, 0x81000000, 0x4f000000, 0xdc000000,
+		0x22000000, 0x2a000000, 0x90000000, 0x88000000,
+		0x46000000, 0xee000000, 0xb8000000, 0x14000000,
+		0xde000000, 0x5e000000, 0x0b000000, 0xdb000000,
+		0xe0000000, 0x32000000, 0x3a000000, 0x0a000000,
+		0x49000000, 0x06000000, 0x24000000, 0x5c000000,
+		0xc2000000, 0xd3000000, 0xac000000, 0x62000000,
+		0x91000000, 0x95000000, 0xe4000000, 0x79000000,
+		0xe7000000, 0xc8000000, 0x37000000, 0x6d000000,
+		0x8d000000, 0xd5000000, 0x4e000000, 0xa9000000,
+		0x6c000000, 0x56000000, 0xf4000000, 0xea000000,
+		0x65000000, 0x7a000000, 0xae000000, 0x08000000,
+		0xba000000, 0x78000000, 0x25000000, 0x2e000000,
+		0x1c000000, 0xa6000000, 0xb4000000, 0xc6000000,
+		0xe8000000, 0xdd000000, 0x74000000, 0x1f000000,
+		0x4b000000, 0xbd000000, 0x8b000000, 0x8a000000,
+		0x70000000, 0x3e000000, 0xb5000000, 0x66000000,
+		0x48000000, 0x03000000, 0xf6000000, 0x0e000000,
+		0x61000000, 0x35000000, 0x57000000, 0xb9000000,
+		0x86000000, 0xc1000000, 0x1d000000, 0x9e000000,
+		0xe1000000, 0xf8000000, 0x98000000, 0x11000000,
+		0x69000000, 0xd9000000, 0x8e000000, 0x94000000,
+		0x9b000000, 0x1e000000, 0x87000000, 0xe9000000,
+		0xce000000, 0x55000000, 0x28000000, 0xdf000000,
+		0x8c000000, 0xa1000000, 0x89000000, 0x0d000000,
+		0xbf000000, 0xe6000000, 0x42000000, 0x68000000,
+		0x41000000, 0x99000000, 0x2d000000, 0x0f000000,
+		0xb0000000, 0x54000000, 0xbb000000, 0x16000000,
+	}
+};
+
+const u32 crypto_it_tab[4][256] = {
+	{
+		0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a,
+		0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b,
+		0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5,
+		0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5,
+		0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d,
+		0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b,
+		0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295,
+		0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e,
+		0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927,
+		0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
+		0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362,
+		0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9,
+		0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52,
+		0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566,
+		0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
+		0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed,
+		0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e,
+		0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4,
+		0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4,
+		0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd,
+		0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d,
+		0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060,
+		0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967,
+		0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879,
+		0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000,
+		0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c,
+		0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36,
+		0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624,
+		0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b,
+		0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
+		0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12,
+		0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14,
+		0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3,
+		0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b,
+		0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8,
+		0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684,
+		0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7,
+		0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177,
+		0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947,
+		0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
+		0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498,
+		0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f,
+		0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54,
+		0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382,
+		0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
+		0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb,
+		0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83,
+		0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef,
+		0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029,
+		0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
+		0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733,
+		0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117,
+		0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4,
+		0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546,
+		0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb,
+		0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d,
+		0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb,
+		0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a,
+		0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773,
+		0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
+		0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2,
+		0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff,
+		0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664,
+		0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0,
+	}, {
+		0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96,
+		0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x03e34b93,
+		0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525,
+		0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f,
+		0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1,
+		0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6,
+		0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da,
+		0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44,
+		0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd,
+		0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4,
+		0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245,
+		0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994,
+		0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7,
+		0xd373ab23, 0x024b72e2, 0x8f1fe357, 0xab55662a,
+		0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5,
+		0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c,
+		0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1,
+		0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a,
+		0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475,
+		0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51,
+		0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46,
+		0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff,
+		0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777,
+		0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db,
+		0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000,
+		0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e,
+		0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627,
+		0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a,
+		0x670a0cb1, 0xe757930f, 0x96eeb4d2, 0x919b1b9e,
+		0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16,
+		0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d,
+		0x0d090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8,
+		0x19f15785, 0x0775af4c, 0xdd99eebb, 0x607fa3fd,
+		0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34,
+		0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863,
+		0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420,
+		0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d,
+		0x2f9e1d4b, 0x30b2dcf3, 0x52860dec, 0xe3c177d0,
+		0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722,
+		0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef,
+		0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836,
+		0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4,
+		0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462,
+		0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5,
+		0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3,
+		0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b,
+		0x7826cd09, 0x18596ef4, 0xb79aec01, 0x9a4f83a8,
+		0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6,
+		0x9be7bad9, 0x366f4ace, 0x099fead4, 0x7cb029d6,
+		0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0,
+		0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315,
+		0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f,
+		0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x0496e4df,
+		0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f,
+		0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e,
+		0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13,
+		0x61d79a8c, 0x0ca1377a, 0x14f8598e, 0x3c13eb89,
+		0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c,
+		0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf,
+		0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886,
+		0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f,
+		0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41,
+		0x01a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490,
+		0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042,
+	}, {
+		0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e,
+		0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303,
+		0x302055fa, 0x76adf66d, 0xcc889176, 0x02f5254c,
+		0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3,
+		0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0,
+		0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9,
+		0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59,
+		0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8,
+		0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71,
+		0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a,
+		0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f,
+		0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b,
+		0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8,
+		0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab,
+		0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508,
+		0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82,
+		0xcf8a2b1c, 0x79a792b4, 0x07f3f0f2, 0x694ea1e2,
+		0xda65cdf4, 0x0506d5be, 0x34d11f62, 0xa6c48afe,
+		0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb,
+		0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110,
+		0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd,
+		0x5491b58d, 0xc471055d, 0x06046fd4, 0x5060ff15,
+		0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e,
+		0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee,
+		0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000,
+		0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72,
+		0x0efdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739,
+		0x0f0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e,
+		0x0a0cb167, 0x57930fe7, 0xeeb4d296, 0x9b1b9e91,
+		0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a,
+		0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17,
+		0x090e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9,
+		0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60,
+		0x01f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e,
+		0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1,
+		0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011,
+		0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1,
+		0x9e1d4b2f, 0xb2dcf330, 0x860dec52, 0xc177d0e3,
+		0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264,
+		0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90,
+		0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b,
+		0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf,
+		0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246,
+		0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af,
+		0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312,
+		0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb,
+		0x26cd0978, 0x596ef418, 0x9aec01b7, 0x4f83a89a,
+		0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8,
+		0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c,
+		0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066,
+		0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8,
+		0x04f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6,
+		0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04,
+		0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51,
+		0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41,
+		0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347,
+		0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c,
+		0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1,
+		0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37,
+		0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db,
+		0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40,
+		0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0x0dff4195,
+		0xa8397101, 0x0c08deb3, 0xb4d89ce4, 0x566490c1,
+		0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257,
+	}, {
+		0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27,
+		0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3,
+		0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02,
+		0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362,
+		0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe,
+		0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3,
+		0x03e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952,
+		0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9,
+		0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9,
+		0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace,
+		0x63184adf, 0xe582311a, 0x97603351, 0x62457f53,
+		0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08,
+		0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b,
+		0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55,
+		0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837,
+		0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216,
+		0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269,
+		0x65cdf4da, 0x06d5be05, 0xd11f6234, 0xc48afea6,
+		0x349d532e, 0xa2a055f3, 0x0532e18a, 0xa475ebf6,
+		0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e,
+		0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6,
+		0x91b58d54, 0x71055dc4, 0x046fd406, 0x60ff1550,
+		0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9,
+		0xb0bd42e8, 0x07888b89, 0xe7385b19, 0x79dbeec8,
+		0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000,
+		0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a,
+		0xfdfbff0e, 0x0f563885, 0x3d1ed5ae, 0x3627392d,
+		0x0a64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36,
+		0x0cb1670a, 0x930fe757, 0xb4d296ee, 0x1b9e919b,
+		0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12,
+		0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b,
+		0x0e0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e,
+		0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f,
+		0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb,
+		0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4,
+		0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6,
+		0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129,
+		0x1d4b2f9e, 0xdcf330b2, 0x0dec5286, 0x77d0e3c1,
+		0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9,
+		0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033,
+		0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4,
+		0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad,
+		0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e,
+		0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3,
+		0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225,
+		0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b,
+		0xcd097826, 0x6ef41859, 0xec01b79a, 0x83a89a4f,
+		0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815,
+		0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0,
+		0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2,
+		0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7,
+		0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691,
+		0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496,
+		0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165,
+		0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b,
+		0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6,
+		0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13,
+		0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147,
+		0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7,
+		0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44,
+		0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3,
+		0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d,
+		0x397101a8, 0x08deb30c, 0xd89ce4b4, 0x6490c156,
+		0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8,
+	}
+};
+
+const u32 crypto_il_tab[4][256] = {
+	{
+		0x00000052, 0x00000009, 0x0000006a, 0x000000d5,
+		0x00000030, 0x00000036, 0x000000a5, 0x00000038,
+		0x000000bf, 0x00000040, 0x000000a3, 0x0000009e,
+		0x00000081, 0x000000f3, 0x000000d7, 0x000000fb,
+		0x0000007c, 0x000000e3, 0x00000039, 0x00000082,
+		0x0000009b, 0x0000002f, 0x000000ff, 0x00000087,
+		0x00000034, 0x0000008e, 0x00000043, 0x00000044,
+		0x000000c4, 0x000000de, 0x000000e9, 0x000000cb,
+		0x00000054, 0x0000007b, 0x00000094, 0x00000032,
+		0x000000a6, 0x000000c2, 0x00000023, 0x0000003d,
+		0x000000ee, 0x0000004c, 0x00000095, 0x0000000b,
+		0x00000042, 0x000000fa, 0x000000c3, 0x0000004e,
+		0x00000008, 0x0000002e, 0x000000a1, 0x00000066,
+		0x00000028, 0x000000d9, 0x00000024, 0x000000b2,
+		0x00000076, 0x0000005b, 0x000000a2, 0x00000049,
+		0x0000006d, 0x0000008b, 0x000000d1, 0x00000025,
+		0x00000072, 0x000000f8, 0x000000f6, 0x00000064,
+		0x00000086, 0x00000068, 0x00000098, 0x00000016,
+		0x000000d4, 0x000000a4, 0x0000005c, 0x000000cc,
+		0x0000005d, 0x00000065, 0x000000b6, 0x00000092,
+		0x0000006c, 0x00000070, 0x00000048, 0x00000050,
+		0x000000fd, 0x000000ed, 0x000000b9, 0x000000da,
+		0x0000005e, 0x00000015, 0x00000046, 0x00000057,
+		0x000000a7, 0x0000008d, 0x0000009d, 0x00000084,
+		0x00000090, 0x000000d8, 0x000000ab, 0x00000000,
+		0x0000008c, 0x000000bc, 0x000000d3, 0x0000000a,
+		0x000000f7, 0x000000e4, 0x00000058, 0x00000005,
+		0x000000b8, 0x000000b3, 0x00000045, 0x00000006,
+		0x000000d0, 0x0000002c, 0x0000001e, 0x0000008f,
+		0x000000ca, 0x0000003f, 0x0000000f, 0x00000002,
+		0x000000c1, 0x000000af, 0x000000bd, 0x00000003,
+		0x00000001, 0x00000013, 0x0000008a, 0x0000006b,
+		0x0000003a, 0x00000091, 0x00000011, 0x00000041,
+		0x0000004f, 0x00000067, 0x000000dc, 0x000000ea,
+		0x00000097, 0x000000f2, 0x000000cf, 0x000000ce,
+		0x000000f0, 0x000000b4, 0x000000e6, 0x00000073,
+		0x00000096, 0x000000ac, 0x00000074, 0x00000022,
+		0x000000e7, 0x000000ad, 0x00000035, 0x00000085,
+		0x000000e2, 0x000000f9, 0x00000037, 0x000000e8,
+		0x0000001c, 0x00000075, 0x000000df, 0x0000006e,
+		0x00000047, 0x000000f1, 0x0000001a, 0x00000071,
+		0x0000001d, 0x00000029, 0x000000c5, 0x00000089,
+		0x0000006f, 0x000000b7, 0x00000062, 0x0000000e,
+		0x000000aa, 0x00000018, 0x000000be, 0x0000001b,
+		0x000000fc, 0x00000056, 0x0000003e, 0x0000004b,
+		0x000000c6, 0x000000d2, 0x00000079, 0x00000020,
+		0x0000009a, 0x000000db, 0x000000c0, 0x000000fe,
+		0x00000078, 0x000000cd, 0x0000005a, 0x000000f4,
+		0x0000001f, 0x000000dd, 0x000000a8, 0x00000033,
+		0x00000088, 0x00000007, 0x000000c7, 0x00000031,
+		0x000000b1, 0x00000012, 0x00000010, 0x00000059,
+		0x00000027, 0x00000080, 0x000000ec, 0x0000005f,
+		0x00000060, 0x00000051, 0x0000007f, 0x000000a9,
+		0x00000019, 0x000000b5, 0x0000004a, 0x0000000d,
+		0x0000002d, 0x000000e5, 0x0000007a, 0x0000009f,
+		0x00000093, 0x000000c9, 0x0000009c, 0x000000ef,
+		0x000000a0, 0x000000e0, 0x0000003b, 0x0000004d,
+		0x000000ae, 0x0000002a, 0x000000f5, 0x000000b0,
+		0x000000c8, 0x000000eb, 0x000000bb, 0x0000003c,
+		0x00000083, 0x00000053, 0x00000099, 0x00000061,
+		0x00000017, 0x0000002b, 0x00000004, 0x0000007e,
+		0x000000ba, 0x00000077, 0x000000d6, 0x00000026,
+		0x000000e1, 0x00000069, 0x00000014, 0x00000063,
+		0x00000055, 0x00000021, 0x0000000c, 0x0000007d,
+	}, {
+		0x00005200, 0x00000900, 0x00006a00, 0x0000d500,
+		0x00003000, 0x00003600, 0x0000a500, 0x00003800,
+		0x0000bf00, 0x00004000, 0x0000a300, 0x00009e00,
+		0x00008100, 0x0000f300, 0x0000d700, 0x0000fb00,
+		0x00007c00, 0x0000e300, 0x00003900, 0x00008200,
+		0x00009b00, 0x00002f00, 0x0000ff00, 0x00008700,
+		0x00003400, 0x00008e00, 0x00004300, 0x00004400,
+		0x0000c400, 0x0000de00, 0x0000e900, 0x0000cb00,
+		0x00005400, 0x00007b00, 0x00009400, 0x00003200,
+		0x0000a600, 0x0000c200, 0x00002300, 0x00003d00,
+		0x0000ee00, 0x00004c00, 0x00009500, 0x00000b00,
+		0x00004200, 0x0000fa00, 0x0000c300, 0x00004e00,
+		0x00000800, 0x00002e00, 0x0000a100, 0x00006600,
+		0x00002800, 0x0000d900, 0x00002400, 0x0000b200,
+		0x00007600, 0x00005b00, 0x0000a200, 0x00004900,
+		0x00006d00, 0x00008b00, 0x0000d100, 0x00002500,
+		0x00007200, 0x0000f800, 0x0000f600, 0x00006400,
+		0x00008600, 0x00006800, 0x00009800, 0x00001600,
+		0x0000d400, 0x0000a400, 0x00005c00, 0x0000cc00,
+		0x00005d00, 0x00006500, 0x0000b600, 0x00009200,
+		0x00006c00, 0x00007000, 0x00004800, 0x00005000,
+		0x0000fd00, 0x0000ed00, 0x0000b900, 0x0000da00,
+		0x00005e00, 0x00001500, 0x00004600, 0x00005700,
+		0x0000a700, 0x00008d00, 0x00009d00, 0x00008400,
+		0x00009000, 0x0000d800, 0x0000ab00, 0x00000000,
+		0x00008c00, 0x0000bc00, 0x0000d300, 0x00000a00,
+		0x0000f700, 0x0000e400, 0x00005800, 0x00000500,
+		0x0000b800, 0x0000b300, 0x00004500, 0x00000600,
+		0x0000d000, 0x00002c00, 0x00001e00, 0x00008f00,
+		0x0000ca00, 0x00003f00, 0x00000f00, 0x00000200,
+		0x0000c100, 0x0000af00, 0x0000bd00, 0x00000300,
+		0x00000100, 0x00001300, 0x00008a00, 0x00006b00,
+		0x00003a00, 0x00009100, 0x00001100, 0x00004100,
+		0x00004f00, 0x00006700, 0x0000dc00, 0x0000ea00,
+		0x00009700, 0x0000f200, 0x0000cf00, 0x0000ce00,
+		0x0000f000, 0x0000b400, 0x0000e600, 0x00007300,
+		0x00009600, 0x0000ac00, 0x00007400, 0x00002200,
+		0x0000e700, 0x0000ad00, 0x00003500, 0x00008500,
+		0x0000e200, 0x0000f900, 0x00003700, 0x0000e800,
+		0x00001c00, 0x00007500, 0x0000df00, 0x00006e00,
+		0x00004700, 0x0000f100, 0x00001a00, 0x00007100,
+		0x00001d00, 0x00002900, 0x0000c500, 0x00008900,
+		0x00006f00, 0x0000b700, 0x00006200, 0x00000e00,
+		0x0000aa00, 0x00001800, 0x0000be00, 0x00001b00,
+		0x0000fc00, 0x00005600, 0x00003e00, 0x00004b00,
+		0x0000c600, 0x0000d200, 0x00007900, 0x00002000,
+		0x00009a00, 0x0000db00, 0x0000c000, 0x0000fe00,
+		0x00007800, 0x0000cd00, 0x00005a00, 0x0000f400,
+		0x00001f00, 0x0000dd00, 0x0000a800, 0x00003300,
+		0x00008800, 0x00000700, 0x0000c700, 0x00003100,
+		0x0000b100, 0x00001200, 0x00001000, 0x00005900,
+		0x00002700, 0x00008000, 0x0000ec00, 0x00005f00,
+		0x00006000, 0x00005100, 0x00007f00, 0x0000a900,
+		0x00001900, 0x0000b500, 0x00004a00, 0x00000d00,
+		0x00002d00, 0x0000e500, 0x00007a00, 0x00009f00,
+		0x00009300, 0x0000c900, 0x00009c00, 0x0000ef00,
+		0x0000a000, 0x0000e000, 0x00003b00, 0x00004d00,
+		0x0000ae00, 0x00002a00, 0x0000f500, 0x0000b000,
+		0x0000c800, 0x0000eb00, 0x0000bb00, 0x00003c00,
+		0x00008300, 0x00005300, 0x00009900, 0x00006100,
+		0x00001700, 0x00002b00, 0x00000400, 0x00007e00,
+		0x0000ba00, 0x00007700, 0x0000d600, 0x00002600,
+		0x0000e100, 0x00006900, 0x00001400, 0x00006300,
+		0x00005500, 0x00002100, 0x00000c00, 0x00007d00,
+	}, {
+		0x00520000, 0x00090000, 0x006a0000, 0x00d50000,
+		0x00300000, 0x00360000, 0x00a50000, 0x00380000,
+		0x00bf0000, 0x00400000, 0x00a30000, 0x009e0000,
+		0x00810000, 0x00f30000, 0x00d70000, 0x00fb0000,
+		0x007c0000, 0x00e30000, 0x00390000, 0x00820000,
+		0x009b0000, 0x002f0000, 0x00ff0000, 0x00870000,
+		0x00340000, 0x008e0000, 0x00430000, 0x00440000,
+		0x00c40000, 0x00de0000, 0x00e90000, 0x00cb0000,
+		0x00540000, 0x007b0000, 0x00940000, 0x00320000,
+		0x00a60000, 0x00c20000, 0x00230000, 0x003d0000,
+		0x00ee0000, 0x004c0000, 0x00950000, 0x000b0000,
+		0x00420000, 0x00fa0000, 0x00c30000, 0x004e0000,
+		0x00080000, 0x002e0000, 0x00a10000, 0x00660000,
+		0x00280000, 0x00d90000, 0x00240000, 0x00b20000,
+		0x00760000, 0x005b0000, 0x00a20000, 0x00490000,
+		0x006d0000, 0x008b0000, 0x00d10000, 0x00250000,
+		0x00720000, 0x00f80000, 0x00f60000, 0x00640000,
+		0x00860000, 0x00680000, 0x00980000, 0x00160000,
+		0x00d40000, 0x00a40000, 0x005c0000, 0x00cc0000,
+		0x005d0000, 0x00650000, 0x00b60000, 0x00920000,
+		0x006c0000, 0x00700000, 0x00480000, 0x00500000,
+		0x00fd0000, 0x00ed0000, 0x00b90000, 0x00da0000,
+		0x005e0000, 0x00150000, 0x00460000, 0x00570000,
+		0x00a70000, 0x008d0000, 0x009d0000, 0x00840000,
+		0x00900000, 0x00d80000, 0x00ab0000, 0x00000000,
+		0x008c0000, 0x00bc0000, 0x00d30000, 0x000a0000,
+		0x00f70000, 0x00e40000, 0x00580000, 0x00050000,
+		0x00b80000, 0x00b30000, 0x00450000, 0x00060000,
+		0x00d00000, 0x002c0000, 0x001e0000, 0x008f0000,
+		0x00ca0000, 0x003f0000, 0x000f0000, 0x00020000,
+		0x00c10000, 0x00af0000, 0x00bd0000, 0x00030000,
+		0x00010000, 0x00130000, 0x008a0000, 0x006b0000,
+		0x003a0000, 0x00910000, 0x00110000, 0x00410000,
+		0x004f0000, 0x00670000, 0x00dc0000, 0x00ea0000,
+		0x00970000, 0x00f20000, 0x00cf0000, 0x00ce0000,
+		0x00f00000, 0x00b40000, 0x00e60000, 0x00730000,
+		0x00960000, 0x00ac0000, 0x00740000, 0x00220000,
+		0x00e70000, 0x00ad0000, 0x00350000, 0x00850000,
+		0x00e20000, 0x00f90000, 0x00370000, 0x00e80000,
+		0x001c0000, 0x00750000, 0x00df0000, 0x006e0000,
+		0x00470000, 0x00f10000, 0x001a0000, 0x00710000,
+		0x001d0000, 0x00290000, 0x00c50000, 0x00890000,
+		0x006f0000, 0x00b70000, 0x00620000, 0x000e0000,
+		0x00aa0000, 0x00180000, 0x00be0000, 0x001b0000,
+		0x00fc0000, 0x00560000, 0x003e0000, 0x004b0000,
+		0x00c60000, 0x00d20000, 0x00790000, 0x00200000,
+		0x009a0000, 0x00db0000, 0x00c00000, 0x00fe0000,
+		0x00780000, 0x00cd0000, 0x005a0000, 0x00f40000,
+		0x001f0000, 0x00dd0000, 0x00a80000, 0x00330000,
+		0x00880000, 0x00070000, 0x00c70000, 0x00310000,
+		0x00b10000, 0x00120000, 0x00100000, 0x00590000,
+		0x00270000, 0x00800000, 0x00ec0000, 0x005f0000,
+		0x00600000, 0x00510000, 0x007f0000, 0x00a90000,
+		0x00190000, 0x00b50000, 0x004a0000, 0x000d0000,
+		0x002d0000, 0x00e50000, 0x007a0000, 0x009f0000,
+		0x00930000, 0x00c90000, 0x009c0000, 0x00ef0000,
+		0x00a00000, 0x00e00000, 0x003b0000, 0x004d0000,
+		0x00ae0000, 0x002a0000, 0x00f50000, 0x00b00000,
+		0x00c80000, 0x00eb0000, 0x00bb0000, 0x003c0000,
+		0x00830000, 0x00530000, 0x00990000, 0x00610000,
+		0x00170000, 0x002b0000, 0x00040000, 0x007e0000,
+		0x00ba0000, 0x00770000, 0x00d60000, 0x00260000,
+		0x00e10000, 0x00690000, 0x00140000, 0x00630000,
+		0x00550000, 0x00210000, 0x000c0000, 0x007d0000,
+	}, {
+		0x52000000, 0x09000000, 0x6a000000, 0xd5000000,
+		0x30000000, 0x36000000, 0xa5000000, 0x38000000,
+		0xbf000000, 0x40000000, 0xa3000000, 0x9e000000,
+		0x81000000, 0xf3000000, 0xd7000000, 0xfb000000,
+		0x7c000000, 0xe3000000, 0x39000000, 0x82000000,
+		0x9b000000, 0x2f000000, 0xff000000, 0x87000000,
+		0x34000000, 0x8e000000, 0x43000000, 0x44000000,
+		0xc4000000, 0xde000000, 0xe9000000, 0xcb000000,
+		0x54000000, 0x7b000000, 0x94000000, 0x32000000,
+		0xa6000000, 0xc2000000, 0x23000000, 0x3d000000,
+		0xee000000, 0x4c000000, 0x95000000, 0x0b000000,
+		0x42000000, 0xfa000000, 0xc3000000, 0x4e000000,
+		0x08000000, 0x2e000000, 0xa1000000, 0x66000000,
+		0x28000000, 0xd9000000, 0x24000000, 0xb2000000,
+		0x76000000, 0x5b000000, 0xa2000000, 0x49000000,
+		0x6d000000, 0x8b000000, 0xd1000000, 0x25000000,
+		0x72000000, 0xf8000000, 0xf6000000, 0x64000000,
+		0x86000000, 0x68000000, 0x98000000, 0x16000000,
+		0xd4000000, 0xa4000000, 0x5c000000, 0xcc000000,
+		0x5d000000, 0x65000000, 0xb6000000, 0x92000000,
+		0x6c000000, 0x70000000, 0x48000000, 0x50000000,
+		0xfd000000, 0xed000000, 0xb9000000, 0xda000000,
+		0x5e000000, 0x15000000, 0x46000000, 0x57000000,
+		0xa7000000, 0x8d000000, 0x9d000000, 0x84000000,
+		0x90000000, 0xd8000000, 0xab000000, 0x00000000,
+		0x8c000000, 0xbc000000, 0xd3000000, 0x0a000000,
+		0xf7000000, 0xe4000000, 0x58000000, 0x05000000,
+		0xb8000000, 0xb3000000, 0x45000000, 0x06000000,
+		0xd0000000, 0x2c000000, 0x1e000000, 0x8f000000,
+		0xca000000, 0x3f000000, 0x0f000000, 0x02000000,
+		0xc1000000, 0xaf000000, 0xbd000000, 0x03000000,
+		0x01000000, 0x13000000, 0x8a000000, 0x6b000000,
+		0x3a000000, 0x91000000, 0x11000000, 0x41000000,
+		0x4f000000, 0x67000000, 0xdc000000, 0xea000000,
+		0x97000000, 0xf2000000, 0xcf000000, 0xce000000,
+		0xf0000000, 0xb4000000, 0xe6000000, 0x73000000,
+		0x96000000, 0xac000000, 0x74000000, 0x22000000,
+		0xe7000000, 0xad000000, 0x35000000, 0x85000000,
+		0xe2000000, 0xf9000000, 0x37000000, 0xe8000000,
+		0x1c000000, 0x75000000, 0xdf000000, 0x6e000000,
+		0x47000000, 0xf1000000, 0x1a000000, 0x71000000,
+		0x1d000000, 0x29000000, 0xc5000000, 0x89000000,
+		0x6f000000, 0xb7000000, 0x62000000, 0x0e000000,
+		0xaa000000, 0x18000000, 0xbe000000, 0x1b000000,
+		0xfc000000, 0x56000000, 0x3e000000, 0x4b000000,
+		0xc6000000, 0xd2000000, 0x79000000, 0x20000000,
+		0x9a000000, 0xdb000000, 0xc0000000, 0xfe000000,
+		0x78000000, 0xcd000000, 0x5a000000, 0xf4000000,
+		0x1f000000, 0xdd000000, 0xa8000000, 0x33000000,
+		0x88000000, 0x07000000, 0xc7000000, 0x31000000,
+		0xb1000000, 0x12000000, 0x10000000, 0x59000000,
+		0x27000000, 0x80000000, 0xec000000, 0x5f000000,
+		0x60000000, 0x51000000, 0x7f000000, 0xa9000000,
+		0x19000000, 0xb5000000, 0x4a000000, 0x0d000000,
+		0x2d000000, 0xe5000000, 0x7a000000, 0x9f000000,
+		0x93000000, 0xc9000000, 0x9c000000, 0xef000000,
+		0xa0000000, 0xe0000000, 0x3b000000, 0x4d000000,
+		0xae000000, 0x2a000000, 0xf5000000, 0xb0000000,
+		0xc8000000, 0xeb000000, 0xbb000000, 0x3c000000,
+		0x83000000, 0x53000000, 0x99000000, 0x61000000,
+		0x17000000, 0x2b000000, 0x04000000, 0x7e000000,
+		0xba000000, 0x77000000, 0xd6000000, 0x26000000,
+		0xe1000000, 0x69000000, 0x14000000, 0x63000000,
+		0x55000000, 0x21000000, 0x0c000000, 0x7d000000,
+	}
+};
 
 EXPORT_SYMBOL_GPL(crypto_ft_tab);
 EXPORT_SYMBOL_GPL(crypto_fl_tab);
 EXPORT_SYMBOL_GPL(crypto_it_tab);
 EXPORT_SYMBOL_GPL(crypto_il_tab);
 
-static inline u8 __init f_mult(u8 a, u8 b)
-{
-	u8 aa = log_tab[a], cc = aa + log_tab[b];
-
-	return pow_tab[cc + (cc < aa ? 1 : 0)];
-}
-
-#define ff_mult(a, b)	(a && b ? f_mult(a, b) : 0)
-
-static void __init gen_tabs(void)
-{
-	u32 i, t;
-	u8 p, q;
-
-	/*
-	 * log and power tables for GF(2**8) finite field with
-	 * 0x011b as modular polynomial - the simplest primitive
-	 * root is 0x03, used here to generate the tables
-	 */
-
-	for (i = 0, p = 1; i < 256; ++i) {
-		pow_tab[i] = (u8) p;
-		log_tab[p] = (u8) i;
-
-		p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0);
-	}
-
-	log_tab[1] = 0;
-
-	for (i = 0, p = 1; i < 10; ++i) {
-		rco_tab[i] = p;
-
-		p = (p << 1) ^ (p & 0x80 ? 0x01b : 0);
-	}
-
-	for (i = 0; i < 256; ++i) {
-		p = (i ? pow_tab[255 - log_tab[i]] : 0);
-		q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2));
-		p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2));
-		sbx_tab[i] = p;
-		isb_tab[p] = (u8) i;
-	}
-
-	for (i = 0; i < 256; ++i) {
-		p = sbx_tab[i];
-
-		t = p;
-		crypto_fl_tab[0][i] = t;
-		crypto_fl_tab[1][i] = rol32(t, 8);
-		crypto_fl_tab[2][i] = rol32(t, 16);
-		crypto_fl_tab[3][i] = rol32(t, 24);
-
-		t = ((u32) ff_mult(2, p)) |
-		    ((u32) p << 8) |
-		    ((u32) p << 16) | ((u32) ff_mult(3, p) << 24);
-
-		crypto_ft_tab[0][i] = t;
-		crypto_ft_tab[1][i] = rol32(t, 8);
-		crypto_ft_tab[2][i] = rol32(t, 16);
-		crypto_ft_tab[3][i] = rol32(t, 24);
-
-		p = isb_tab[i];
-
-		t = p;
-		crypto_il_tab[0][i] = t;
-		crypto_il_tab[1][i] = rol32(t, 8);
-		crypto_il_tab[2][i] = rol32(t, 16);
-		crypto_il_tab[3][i] = rol32(t, 24);
-
-		t = ((u32) ff_mult(14, p)) |
-		    ((u32) ff_mult(9, p) << 8) |
-		    ((u32) ff_mult(13, p) << 16) |
-		    ((u32) ff_mult(11, p) << 24);
-
-		crypto_it_tab[0][i] = t;
-		crypto_it_tab[1][i] = rol32(t, 8);
-		crypto_it_tab[2][i] = rol32(t, 16);
-		crypto_it_tab[3][i] = rol32(t, 24);
-	}
-}
-
 /* initialise the key schedule from the user supplied key */
 
 #define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
@@ -491,7 +1457,6 @@
 
 static int __init aes_init(void)
 {
-	gen_tabs();
 	return crypto_register_alg(&aes_alg);
 }
 
diff --git a/crypto/ahash.c b/crypto/ahash.c
index 27128f2..ba5292d 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -112,6 +112,22 @@
 }
 EXPORT_SYMBOL_GPL(crypto_hash_walk_first);
 
+int crypto_hash_walk_first_compat(struct hash_desc *hdesc,
+				  struct crypto_hash_walk *walk,
+				  struct scatterlist *sg, unsigned int len)
+{
+	walk->total = len;
+
+	if (!walk->total)
+		return 0;
+
+	walk->alignmask = crypto_hash_alignmask(hdesc->tfm);
+	walk->sg = sg;
+	walk->flags = hdesc->flags;
+
+	return hash_walk_new_entry(walk);
+}
+
 static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key,
 				unsigned int keylen)
 {
@@ -146,6 +162,26 @@
 	return ahash->setkey(tfm, key, keylen);
 }
 
+static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key,
+			  unsigned int keylen)
+{
+	return -ENOSYS;
+}
+
+int crypto_ahash_import(struct ahash_request *req, const u8 *in)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct ahash_alg *alg = crypto_ahash_alg(tfm);
+
+	memcpy(ahash_request_ctx(req), in, crypto_ahash_reqsize(tfm));
+
+	if (alg->reinit)
+		alg->reinit(req);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_ahash_import);
+
 static unsigned int crypto_ahash_ctxsize(struct crypto_alg *alg, u32 type,
 					u32 mask)
 {
@@ -164,7 +200,7 @@
 	crt->update = alg->update;
 	crt->final  = alg->final;
 	crt->digest = alg->digest;
-	crt->setkey = ahash_setkey;
+	crt->setkey = alg->setkey ? ahash_setkey : ahash_nosetkey;
 	crt->digestsize = alg->digestsize;
 
 	return 0;
diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c
index 72db0fd..0fac8ff 100644
--- a/crypto/ansi_cprng.c
+++ b/crypto/ansi_cprng.c
@@ -161,7 +161,7 @@
 	/*
 	 * Now update our DT value
 	 */
-	for (i = 0; i < DEFAULT_BLK_SZ; i++) {
+	for (i = DEFAULT_BLK_SZ - 1; i >= 0; i--) {
 		ctx->DT[i] += 1;
 		if (ctx->DT[i] != 0)
 			break;
@@ -223,9 +223,10 @@
 	}
 
 	/*
-	 * Copy up to the next whole block size
+	 * Copy any data less than an entire block
 	 */
 	if (byte_count < DEFAULT_BLK_SZ) {
+empty_rbuf:
 		for (; ctx->rand_data_valid < DEFAULT_BLK_SZ;
 			ctx->rand_data_valid++) {
 			*ptr = ctx->rand_data[ctx->rand_data_valid];
@@ -240,18 +241,22 @@
 	 * Now copy whole blocks
 	 */
 	for (; byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) {
-		if (_get_more_prng_bytes(ctx) < 0) {
-			memset(buf, 0, nbytes);
-			err = -EINVAL;
-			goto done;
+		if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
+			if (_get_more_prng_bytes(ctx) < 0) {
+				memset(buf, 0, nbytes);
+				err = -EINVAL;
+				goto done;
+			}
 		}
+		if (ctx->rand_data_valid > 0)
+			goto empty_rbuf;
 		memcpy(ptr, ctx->rand_data, DEFAULT_BLK_SZ);
 		ctx->rand_data_valid += DEFAULT_BLK_SZ;
 		ptr += DEFAULT_BLK_SZ;
 	}
 
 	/*
-	 * Now copy any extra partial data
+	 * Now go back and get any remaining partial block
 	 */
 	if (byte_count)
 		goto remainder;
@@ -349,15 +354,25 @@
 	return get_prng_bytes(rdata, dlen, prng);
 }
 
+/*
+ *  This is the cprng_registered reset method the seed value is
+ *  interpreted as the tuple { V KEY DT}
+ *  V and KEY are required during reset, and DT is optional, detected
+ *  as being present by testing the length of the seed
+ */
 static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
 {
 	struct prng_context *prng = crypto_rng_ctx(tfm);
-	u8 *key = seed + DEFAULT_PRNG_KSZ;
+	u8 *key = seed + DEFAULT_BLK_SZ;
+	u8 *dt = NULL;
 
 	if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ)
 		return -EINVAL;
 
-	reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, NULL);
+	if (slen >= (2 * DEFAULT_BLK_SZ + DEFAULT_PRNG_KSZ))
+		dt = key + DEFAULT_PRNG_KSZ;
+
+	reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, dt);
 
 	if (prng->flags & PRNG_NEED_RESET)
 		return -EINVAL;
@@ -379,7 +394,7 @@
 		.rng = {
 			.rng_make_random	= cprng_get_random,
 			.rng_reset		= cprng_reset,
-			.seedsize = DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ,
+			.seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ,
 		}
 	}
 };
diff --git a/crypto/api.c b/crypto/api.c
index 0444d24..9975a7b 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -300,8 +300,8 @@
 	const struct crypto_type *type = tfm->__crt_alg->cra_type;
 
 	if (type) {
-		if (type->exit)
-			type->exit(tfm);
+		if (tfm->exit)
+			tfm->exit(tfm);
 		return;
 	}
 
@@ -379,17 +379,16 @@
 	if (err)
 		goto out_free_tfm;
 
-	if (alg->cra_init && (err = alg->cra_init(tfm))) {
-		if (err == -EAGAIN)
-			crypto_shoot_alg(alg);
+	if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm)))
 		goto cra_init_failed;
-	}
 
 	goto out;
 
 cra_init_failed:
 	crypto_exit_ops(tfm);
 out_free_tfm:
+	if (err == -EAGAIN)
+		crypto_shoot_alg(alg);
 	kfree(tfm);
 out_err:
 	tfm = ERR_PTR(err);
@@ -404,6 +403,9 @@
  *	@type: Type of algorithm
  *	@mask: Mask for type comparison
  *
+ *	This function should not be used by new algorithm types.
+ *	Plesae use crypto_alloc_tfm instead.
+ *
  *	crypto_alloc_base() will first attempt to locate an already loaded
  *	algorithm.  If that fails and the kernel supports dynamically loadable
  *	modules, it will then attempt to load a module of the same name or
@@ -450,6 +452,111 @@
 	return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_base);
+
+struct crypto_tfm *crypto_create_tfm(struct crypto_alg *alg,
+				     const struct crypto_type *frontend)
+{
+	char *mem;
+	struct crypto_tfm *tfm = NULL;
+	unsigned int tfmsize;
+	unsigned int total;
+	int err = -ENOMEM;
+
+	tfmsize = frontend->tfmsize;
+	total = tfmsize + sizeof(*tfm) + frontend->extsize(alg, frontend);
+
+	mem = kzalloc(total, GFP_KERNEL);
+	if (mem == NULL)
+		goto out_err;
+
+	tfm = (struct crypto_tfm *)(mem + tfmsize);
+	tfm->__crt_alg = alg;
+
+	err = frontend->init_tfm(tfm, frontend);
+	if (err)
+		goto out_free_tfm;
+
+	if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm)))
+		goto cra_init_failed;
+
+	goto out;
+
+cra_init_failed:
+	crypto_exit_ops(tfm);
+out_free_tfm:
+	if (err == -EAGAIN)
+		crypto_shoot_alg(alg);
+	kfree(mem);
+out_err:
+	tfm = ERR_PTR(err);
+out:
+	return tfm;
+}
+EXPORT_SYMBOL_GPL(crypto_create_tfm);
+
+/*
+ *	crypto_alloc_tfm - Locate algorithm and allocate transform
+ *	@alg_name: Name of algorithm
+ *	@frontend: Frontend algorithm type
+ *	@type: Type of algorithm
+ *	@mask: Mask for type comparison
+ *
+ *	crypto_alloc_tfm() will first attempt to locate an already loaded
+ *	algorithm.  If that fails and the kernel supports dynamically loadable
+ *	modules, it will then attempt to load a module of the same name or
+ *	alias.  If that fails it will send a query to any loaded crypto manager
+ *	to construct an algorithm on the fly.  A refcount is grabbed on the
+ *	algorithm which is then associated with the new transform.
+ *
+ *	The returned transform is of a non-determinate type.  Most people
+ *	should use one of the more specific allocation functions such as
+ *	crypto_alloc_blkcipher.
+ *
+ *	In case of error the return value is an error pointer.
+ */
+struct crypto_tfm *crypto_alloc_tfm(const char *alg_name,
+				    const struct crypto_type *frontend,
+				    u32 type, u32 mask)
+{
+	struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask);
+	struct crypto_tfm *tfm;
+	int err;
+
+	type &= frontend->maskclear;
+	mask &= frontend->maskclear;
+	type |= frontend->type;
+	mask |= frontend->maskset;
+
+	lookup = frontend->lookup ?: crypto_alg_mod_lookup;
+
+	for (;;) {
+		struct crypto_alg *alg;
+
+		alg = lookup(alg_name, type, mask);
+		if (IS_ERR(alg)) {
+			err = PTR_ERR(alg);
+			goto err;
+		}
+
+		tfm = crypto_create_tfm(alg, frontend);
+		if (!IS_ERR(tfm))
+			return tfm;
+
+		crypto_mod_put(alg);
+		err = PTR_ERR(tfm);
+
+err:
+		if (err != -EAGAIN)
+			break;
+		if (signal_pending(current)) {
+			err = -EINTR;
+			break;
+		}
+	}
+
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
  
 /*
  *	crypto_free_tfm - Free crypto transform
@@ -469,7 +576,7 @@
 	alg = tfm->__crt_alg;
 	size = sizeof(*tfm) + alg->cra_ctxsize;
 
-	if (alg->cra_exit)
+	if (!tfm->exit && alg->cra_exit)
 		alg->cra_exit(tfm);
 	crypto_exit_ops(tfm);
 	crypto_mod_put(alg);
diff --git a/crypto/authenc.c b/crypto/authenc.c
index fd9f06c..40b6e9e 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -11,6 +11,7 @@
  */
 
 #include <crypto/aead.h>
+#include <crypto/internal/hash.h>
 #include <crypto/internal/skcipher.h>
 #include <crypto/authenc.h>
 #include <crypto/scatterwalk.h>
@@ -431,6 +432,8 @@
 	inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize;
 	inst->alg.cra_aead.maxauthsize = auth->cra_type == &crypto_hash_type ?
 					 auth->cra_hash.digestsize :
+					 auth->cra_type ?
+					 __crypto_shash_alg(auth)->digestsize :
 					 auth->cra_digest.dia_digestsize;
 
 	inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx);
diff --git a/crypto/camellia.c b/crypto/camellia.c
index 493fee7..964635d 100644
--- a/crypto/camellia.c
+++ b/crypto/camellia.c
@@ -35,6 +35,8 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
+#include <asm/unaligned.h>
 
 static const u32 camellia_sp1110[256] = {
 	0x70707000,0x82828200,0x2c2c2c00,0xececec00,
@@ -335,20 +337,6 @@
 /*
  *  macros
  */
-#define GETU32(v, pt) \
-    do { \
-	/* latest breed of gcc is clever enough to use move */ \
-	memcpy(&(v), (pt), 4); \
-	(v) = be32_to_cpu(v); \
-    } while(0)
-
-/* rotation right shift 1byte */
-#define ROR8(x) (((x) >> 8) + ((x) << 24))
-/* rotation left shift 1bit */
-#define ROL1(x) (((x) << 1) + ((x) >> 31))
-/* rotation left shift 1byte */
-#define ROL8(x) (((x) << 8) + ((x) >> 24))
-
 #define ROLDQ(ll, lr, rl, rr, w0, w1, bits)		\
     do {						\
 	w0 = ll;					\
@@ -383,7 +371,7 @@
 	   ^ camellia_sp3033[(u8)(il >> 8)]			\
 	   ^ camellia_sp4404[(u8)(il     )];			\
 	yl ^= yr;						\
-	yr = ROR8(yr);						\
+	yr = ror32(yr, 8);					\
 	yr ^= yl;						\
     } while(0)
 
@@ -405,7 +393,7 @@
 	subL[7] ^= subL[1]; subR[7] ^= subR[1];
 	subL[1] ^= subR[1] & ~subR[9];
 	dw = subL[1] & subL[9],
-		subR[1] ^= ROL1(dw); /* modified for FLinv(kl2) */
+		subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl2) */
 	/* round 8 */
 	subL[11] ^= subL[1]; subR[11] ^= subR[1];
 	/* round 10 */
@@ -414,7 +402,7 @@
 	subL[15] ^= subL[1]; subR[15] ^= subR[1];
 	subL[1] ^= subR[1] & ~subR[17];
 	dw = subL[1] & subL[17],
-		subR[1] ^= ROL1(dw); /* modified for FLinv(kl4) */
+		subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl4) */
 	/* round 14 */
 	subL[19] ^= subL[1]; subR[19] ^= subR[1];
 	/* round 16 */
@@ -430,7 +418,7 @@
 	} else {
 		subL[1] ^= subR[1] & ~subR[25];
 		dw = subL[1] & subL[25],
-			subR[1] ^= ROL1(dw); /* modified for FLinv(kl6) */
+			subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl6) */
 		/* round 20 */
 		subL[27] ^= subL[1]; subR[27] ^= subR[1];
 		/* round 22 */
@@ -450,7 +438,7 @@
 		subL[26] ^= kw4l; subR[26] ^= kw4r;
 		kw4l ^= kw4r & ~subR[24];
 		dw = kw4l & subL[24],
-			kw4r ^= ROL1(dw); /* modified for FL(kl5) */
+			kw4r ^= rol32(dw, 1); /* modified for FL(kl5) */
 	}
 	/* round 17 */
 	subL[22] ^= kw4l; subR[22] ^= kw4r;
@@ -460,7 +448,7 @@
 	subL[18] ^= kw4l; subR[18] ^= kw4r;
 	kw4l ^= kw4r & ~subR[16];
 	dw = kw4l & subL[16],
-		kw4r ^= ROL1(dw); /* modified for FL(kl3) */
+		kw4r ^= rol32(dw, 1); /* modified for FL(kl3) */
 	/* round 11 */
 	subL[14] ^= kw4l; subR[14] ^= kw4r;
 	/* round 9 */
@@ -469,7 +457,7 @@
 	subL[10] ^= kw4l; subR[10] ^= kw4r;
 	kw4l ^= kw4r & ~subR[8];
 	dw = kw4l & subL[8],
-		kw4r ^= ROL1(dw); /* modified for FL(kl1) */
+		kw4r ^= rol32(dw, 1); /* modified for FL(kl1) */
 	/* round 5 */
 	subL[6] ^= kw4l; subR[6] ^= kw4r;
 	/* round 3 */
@@ -494,7 +482,7 @@
 	SUBKEY_R(6) = subR[5] ^ subR[7];
 	tl = subL[10] ^ (subR[10] & ~subR[8]);
 	dw = tl & subL[8],  /* FL(kl1) */
-		tr = subR[10] ^ ROL1(dw);
+		tr = subR[10] ^ rol32(dw, 1);
 	SUBKEY_L(7) = subL[6] ^ tl; /* round 6 */
 	SUBKEY_R(7) = subR[6] ^ tr;
 	SUBKEY_L(8) = subL[8];       /* FL(kl1) */
@@ -503,7 +491,7 @@
 	SUBKEY_R(9) = subR[9];
 	tl = subL[7] ^ (subR[7] & ~subR[9]);
 	dw = tl & subL[9],  /* FLinv(kl2) */
-		tr = subR[7] ^ ROL1(dw);
+		tr = subR[7] ^ rol32(dw, 1);
 	SUBKEY_L(10) = tl ^ subL[11]; /* round 7 */
 	SUBKEY_R(10) = tr ^ subR[11];
 	SUBKEY_L(11) = subL[10] ^ subL[12]; /* round 8 */
@@ -516,7 +504,7 @@
 	SUBKEY_R(14) = subR[13] ^ subR[15];
 	tl = subL[18] ^ (subR[18] & ~subR[16]);
 	dw = tl & subL[16], /* FL(kl3) */
-		tr = subR[18] ^ ROL1(dw);
+		tr = subR[18] ^ rol32(dw, 1);
 	SUBKEY_L(15) = subL[14] ^ tl; /* round 12 */
 	SUBKEY_R(15) = subR[14] ^ tr;
 	SUBKEY_L(16) = subL[16];     /* FL(kl3) */
@@ -525,7 +513,7 @@
 	SUBKEY_R(17) = subR[17];
 	tl = subL[15] ^ (subR[15] & ~subR[17]);
 	dw = tl & subL[17], /* FLinv(kl4) */
-		tr = subR[15] ^ ROL1(dw);
+		tr = subR[15] ^ rol32(dw, 1);
 	SUBKEY_L(18) = tl ^ subL[19]; /* round 13 */
 	SUBKEY_R(18) = tr ^ subR[19];
 	SUBKEY_L(19) = subL[18] ^ subL[20]; /* round 14 */
@@ -544,7 +532,7 @@
 	} else {
 		tl = subL[26] ^ (subR[26] & ~subR[24]);
 		dw = tl & subL[24], /* FL(kl5) */
-			tr = subR[26] ^ ROL1(dw);
+			tr = subR[26] ^ rol32(dw, 1);
 		SUBKEY_L(23) = subL[22] ^ tl; /* round 18 */
 		SUBKEY_R(23) = subR[22] ^ tr;
 		SUBKEY_L(24) = subL[24];     /* FL(kl5) */
@@ -553,7 +541,7 @@
 		SUBKEY_R(25) = subR[25];
 		tl = subL[23] ^ (subR[23] & ~subR[25]);
 		dw = tl & subL[25], /* FLinv(kl6) */
-			tr = subR[23] ^ ROL1(dw);
+			tr = subR[23] ^ rol32(dw, 1);
 		SUBKEY_L(26) = tl ^ subL[27]; /* round 19 */
 		SUBKEY_R(26) = tr ^ subR[27];
 		SUBKEY_L(27) = subL[26] ^ subL[28]; /* round 20 */
@@ -573,17 +561,17 @@
 	/* apply the inverse of the last half of P-function */
 	i = 2;
 	do {
-		dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = ROL8(dw);/* round 1 */
+		dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = rol32(dw, 8);/* round 1 */
 		SUBKEY_R(i + 0) = SUBKEY_L(i + 0) ^ dw; SUBKEY_L(i + 0) = dw;
-		dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = ROL8(dw);/* round 2 */
+		dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = rol32(dw, 8);/* round 2 */
 		SUBKEY_R(i + 1) = SUBKEY_L(i + 1) ^ dw; SUBKEY_L(i + 1) = dw;
-		dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = ROL8(dw);/* round 3 */
+		dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = rol32(dw, 8);/* round 3 */
 		SUBKEY_R(i + 2) = SUBKEY_L(i + 2) ^ dw; SUBKEY_L(i + 2) = dw;
-		dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = ROL8(dw);/* round 4 */
+		dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = rol32(dw, 8);/* round 4 */
 		SUBKEY_R(i + 3) = SUBKEY_L(i + 3) ^ dw; SUBKEY_L(i + 3) = dw;
-		dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = ROL8(dw);/* round 5 */
+		dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = rol32(dw, 8);/* round 5 */
 		SUBKEY_R(i + 4) = SUBKEY_L(i + 4) ^ dw; SUBKEY_L(i + 4) = dw;
-		dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = ROL8(dw);/* round 6 */
+		dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = rol32(dw, 8);/* round 6 */
 		SUBKEY_R(i + 5) = SUBKEY_L(i + 5) ^ dw; SUBKEY_L(i + 5) = dw;
 		i += 8;
 	} while (i < max);
@@ -599,10 +587,10 @@
 	/**
 	 *  k == kll || klr || krl || krr (|| is concatenation)
 	 */
-	GETU32(kll, key     );
-	GETU32(klr, key +  4);
-	GETU32(krl, key +  8);
-	GETU32(krr, key + 12);
+	kll = get_unaligned_be32(key);
+	klr = get_unaligned_be32(key + 4);
+	krl = get_unaligned_be32(key + 8);
+	krr = get_unaligned_be32(key + 12);
 
 	/* generate KL dependent subkeys */
 	/* kw1 */
@@ -707,14 +695,14 @@
 	 *  key = (kll || klr || krl || krr || krll || krlr || krrl || krrr)
 	 *  (|| is concatenation)
 	 */
-	GETU32(kll,  key     );
-	GETU32(klr,  key +  4);
-	GETU32(krl,  key +  8);
-	GETU32(krr,  key + 12);
-	GETU32(krll, key + 16);
-	GETU32(krlr, key + 20);
-	GETU32(krrl, key + 24);
-	GETU32(krrr, key + 28);
+	kll = get_unaligned_be32(key);
+	klr = get_unaligned_be32(key + 4);
+	krl = get_unaligned_be32(key + 8);
+	krr = get_unaligned_be32(key + 12);
+	krll = get_unaligned_be32(key + 16);
+	krlr = get_unaligned_be32(key + 20);
+	krrl = get_unaligned_be32(key + 24);
+	krrr = get_unaligned_be32(key + 28);
 
 	/* generate KL dependent subkeys */
 	/* kw1 */
@@ -870,13 +858,13 @@
 	t0 &= ll;							\
 	t2 |= rr;							\
 	rl ^= t2;							\
-	lr ^= ROL1(t0);							\
+	lr ^= rol32(t0, 1);						\
 	t3 = krl;							\
 	t1 = klr;							\
 	t3 &= rl;							\
 	t1 |= lr;							\
 	ll ^= t1;							\
-	rr ^= ROL1(t3);							\
+	rr ^= rol32(t3, 1);						\
     } while(0)
 
 #define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir)		\
@@ -892,7 +880,7 @@
 	il ^= kl;							\
 	ir ^= il ^ kr;							\
 	yl ^= ir;							\
-	yr ^= ROR8(il) ^ ir;						\
+	yr ^= ror32(il, 8) ^ ir;						\
     } while(0)
 
 /* max = 24: 128bit encrypt, max = 32: 256bit encrypt */
diff --git a/crypto/crc32c.c b/crypto/crc32c.c
index a882d9e..973bc2c 100644
--- a/crypto/crc32c.c
+++ b/crypto/crc32c.c
@@ -3,8 +3,29 @@
  *
  * CRC32C chksum
  *
- * This module file is a wrapper to invoke the lib/crc32c routines.
+ *@Article{castagnoli-crc,
+ * author =       { Guy Castagnoli and Stefan Braeuer and Martin Herrman},
+ * title =        {{Optimization of Cyclic Redundancy-Check Codes with 24
+ *                 and 32 Parity Bits}},
+ * journal =      IEEE Transactions on Communication,
+ * year =         {1993},
+ * volume =       {41},
+ * number =       {6},
+ * pages =        {},
+ * month =        {June},
+ *}
+ * Used by the iSCSI driver, possibly others, and derived from the
+ * the iscsi-crc.c module of the linux-iscsi driver at
+ * http://linux-iscsi.sourceforge.net.
  *
+ * Following the example of lib/crc32, this function is intended to be
+ * flexible and useful for all users.  Modules that currently have their
+ * own crc32c, but hopefully may be able to use this one are:
+ *  net/sctp (please add all your doco to here if you change to
+ *            use this one!)
+ *  <endoflist>
+ *
+ * Copyright (c) 2004 Cisco Systems, Inc.
  * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -18,27 +39,121 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/string.h>
-#include <linux/crc32c.h>
 #include <linux/kernel.h>
 
 #define CHKSUM_BLOCK_SIZE	1
 #define CHKSUM_DIGEST_SIZE	4
 
 struct chksum_ctx {
-	u32 crc;
 	u32 key;
 };
 
+struct chksum_desc_ctx {
+	u32 crc;
+};
+
+/*
+ * This is the CRC-32C table
+ * Generated with:
+ * width = 32 bits
+ * poly = 0x1EDC6F41
+ * reflect input bytes = true
+ * reflect output bytes = true
+ */
+
+static const u32 crc32c_table[256] = {
+	0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
+	0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
+	0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
+	0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
+	0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
+	0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
+	0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
+	0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
+	0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
+	0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
+	0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
+	0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
+	0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
+	0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
+	0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
+	0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
+	0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
+	0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
+	0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
+	0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
+	0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
+	0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
+	0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
+	0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
+	0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
+	0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
+	0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
+	0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
+	0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
+	0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
+	0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
+	0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
+	0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
+	0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
+	0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
+	0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
+	0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
+	0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
+	0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
+	0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
+	0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
+	0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
+	0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
+	0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
+	0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
+	0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
+	0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
+	0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
+	0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
+	0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
+	0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
+	0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
+	0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
+	0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
+	0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
+	0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
+	0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
+	0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
+	0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
+	0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
+	0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
+	0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
+	0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
+	0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
+};
+
+/*
+ * Steps through buffer one byte at at time, calculates reflected
+ * crc using table.
+ */
+
+static u32 crc32c(u32 crc, const u8 *data, unsigned int length)
+{
+	while (length--)
+		crc = crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8);
+
+	return crc;
+}
+
 /*
  * Steps through buffer one byte at at time, calculates reflected 
  * crc using table.
  */
 
-static void chksum_init(struct crypto_tfm *tfm)
+static int chksum_init(struct shash_desc *desc)
 {
-	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 
-	mctx->crc = mctx->key;
+	ctx->crc = mctx->key;
+
+	return 0;
 }
 
 /*
@@ -46,35 +161,59 @@
  * If your algorithm starts with ~0, then XOR with ~0 before you set
  * the seed.
  */
-static int chksum_setkey(struct crypto_tfm *tfm, const u8 *key,
+static int chksum_setkey(struct crypto_shash *tfm, const u8 *key,
 			 unsigned int keylen)
 {
-	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct chksum_ctx *mctx = crypto_shash_ctx(tfm);
 
-	if (keylen != sizeof(mctx->crc)) {
-		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+	if (keylen != sizeof(mctx->key)) {
+		crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
 		return -EINVAL;
 	}
 	mctx->key = le32_to_cpu(*(__le32 *)key);
 	return 0;
 }
 
-static void chksum_update(struct crypto_tfm *tfm, const u8 *data,
-			  unsigned int length)
+static int chksum_update(struct shash_desc *desc, const u8 *data,
+			 unsigned int length)
 {
-	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 
-	mctx->crc = crc32c(mctx->crc, data, length);
+	ctx->crc = crc32c(ctx->crc, data, length);
+	return 0;
 }
 
-static void chksum_final(struct crypto_tfm *tfm, u8 *out)
+static int chksum_final(struct shash_desc *desc, u8 *out)
 {
-	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
-	
-	*(__le32 *)out = ~cpu_to_le32(mctx->crc);
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+	*(__le32 *)out = ~cpu_to_le32p(&ctx->crc);
+	return 0;
 }
 
-static int crc32c_cra_init_old(struct crypto_tfm *tfm)
+static int __chksum_finup(u32 *crcp, const u8 *data, unsigned int len, u8 *out)
+{
+	*(__le32 *)out = ~cpu_to_le32(crc32c(*crcp, data, len));
+	return 0;
+}
+
+static int chksum_finup(struct shash_desc *desc, const u8 *data,
+			unsigned int len, u8 *out)
+{
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+	return __chksum_finup(&ctx->crc, data, len, out);
+}
+
+static int chksum_digest(struct shash_desc *desc, const u8 *data,
+			 unsigned int length, u8 *out)
+{
+	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
+
+	return __chksum_finup(&mctx->key, data, length, out);
+}
+
+static int crc32c_cra_init(struct crypto_tfm *tfm)
 {
 	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
 
@@ -82,144 +221,35 @@
 	return 0;
 }
 
-static struct crypto_alg old_alg = {
-	.cra_name	=	"crc32c",
-	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	=	CHKSUM_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct chksum_ctx),
-	.cra_module	=	THIS_MODULE,
-	.cra_list	=	LIST_HEAD_INIT(old_alg.cra_list),
-	.cra_init	=	crc32c_cra_init_old,
-	.cra_u		=	{
-		.digest = {
-			 .dia_digestsize=	CHKSUM_DIGEST_SIZE,
-			 .dia_setkey	=	chksum_setkey,
-			 .dia_init   	= 	chksum_init,
-			 .dia_update 	=	chksum_update,
-			 .dia_final  	=	chksum_final
-		 }
-	}
-};
-
-/*
- * Setting the seed allows arbitrary accumulators and flexible XOR policy
- * If your algorithm starts with ~0, then XOR with ~0 before you set
- * the seed.
- */
-static int crc32c_setkey(struct crypto_ahash *hash, const u8 *key,
-			 unsigned int keylen)
-{
-	u32 *mctx = crypto_ahash_ctx(hash);
-
-	if (keylen != sizeof(u32)) {
-		crypto_ahash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
-		return -EINVAL;
-	}
-	*mctx = le32_to_cpup((__le32 *)key);
-	return 0;
-}
-
-static int crc32c_init(struct ahash_request *req)
-{
-	u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
-	u32 *crcp = ahash_request_ctx(req);
-
-	*crcp = *mctx;
-	return 0;
-}
-
-static int crc32c_update(struct ahash_request *req)
-{
-	struct crypto_hash_walk walk;
-	u32 *crcp = ahash_request_ctx(req);
-	u32 crc = *crcp;
-	int nbytes;
-
-	for (nbytes = crypto_hash_walk_first(req, &walk); nbytes;
-	     nbytes = crypto_hash_walk_done(&walk, 0))
-		crc = crc32c(crc, walk.data, nbytes);
-
-	*crcp = crc;
-	return 0;
-}
-
-static int crc32c_final(struct ahash_request *req)
-{
-	u32 *crcp = ahash_request_ctx(req);
-	
-	*(__le32 *)req->result = ~cpu_to_le32p(crcp);
-	return 0;
-}
-
-static int crc32c_digest(struct ahash_request *req)
-{
-	struct crypto_hash_walk walk;
-	u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
-	u32 crc = *mctx;
-	int nbytes;
-
-	for (nbytes = crypto_hash_walk_first(req, &walk); nbytes;
-	     nbytes = crypto_hash_walk_done(&walk, 0))
-		crc = crc32c(crc, walk.data, nbytes);
-
-	*(__le32 *)req->result = ~cpu_to_le32(crc);
-	return 0;
-}
-
-static int crc32c_cra_init(struct crypto_tfm *tfm)
-{
-	u32 *key = crypto_tfm_ctx(tfm);
-
-	*key = ~0;
-
-	tfm->crt_ahash.reqsize = sizeof(u32);
-
-	return 0;
-}
-
-static struct crypto_alg alg = {
-	.cra_name		=	"crc32c",
-	.cra_driver_name	=	"crc32c-generic",
-	.cra_priority		=	100,
-	.cra_flags		=	CRYPTO_ALG_TYPE_AHASH,
-	.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
-	.cra_alignmask		=	3,
-	.cra_ctxsize		=	sizeof(u32),
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(alg.cra_list),
-	.cra_init		=	crc32c_cra_init,
-	.cra_type		=	&crypto_ahash_type,
-	.cra_u			=	{
-		.ahash = {
-			 .digestsize	=	CHKSUM_DIGEST_SIZE,
-			 .setkey	=	crc32c_setkey,
-			 .init   	= 	crc32c_init,
-			 .update 	=	crc32c_update,
-			 .final  	=	crc32c_final,
-			 .digest  	=	crc32c_digest,
-		 }
+static struct shash_alg alg = {
+	.digestsize		=	CHKSUM_DIGEST_SIZE,
+	.setkey			=	chksum_setkey,
+	.init   		= 	chksum_init,
+	.update 		=	chksum_update,
+	.final  		=	chksum_final,
+	.finup  		=	chksum_finup,
+	.digest  		=	chksum_digest,
+	.descsize		=	sizeof(struct chksum_desc_ctx),
+	.base			=	{
+		.cra_name		=	"crc32c",
+		.cra_driver_name	=	"crc32c-generic",
+		.cra_priority		=	100,
+		.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
+		.cra_alignmask		=	3,
+		.cra_ctxsize		=	sizeof(struct chksum_ctx),
+		.cra_module		=	THIS_MODULE,
+		.cra_init		=	crc32c_cra_init,
 	}
 };
 
 static int __init crc32c_mod_init(void)
 {
-	int err;
-
-	err = crypto_register_alg(&old_alg);
-	if (err)
-		return err;
-
-	err = crypto_register_alg(&alg);
-	if (err)
-		crypto_unregister_alg(&old_alg);
-
-	return err;
+	return crypto_register_shash(&alg);
 }
 
 static void __exit crc32c_mod_fini(void)
 {
-	crypto_unregister_alg(&alg);
-	crypto_unregister_alg(&old_alg);
+	crypto_unregister_shash(&alg);
 }
 
 module_init(crc32c_mod_init);
diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c
index 1f7d530..cb71c91 100644
--- a/crypto/crypto_null.c
+++ b/crypto/crypto_null.c
@@ -17,6 +17,7 @@
  *
  */
 
+#include <crypto/internal/hash.h>
 #include <crypto/internal/skcipher.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -38,15 +39,31 @@
 	return 0;
 }
 
-static void null_init(struct crypto_tfm *tfm)
-{ }
+static int null_init(struct shash_desc *desc)
+{
+	return 0;
+}
 
-static void null_update(struct crypto_tfm *tfm, const u8 *data,
-			unsigned int len)
-{ }
+static int null_update(struct shash_desc *desc, const u8 *data,
+		       unsigned int len)
+{
+	return 0;
+}
 
-static void null_final(struct crypto_tfm *tfm, u8 *out)
-{ }
+static int null_final(struct shash_desc *desc, u8 *out)
+{
+	return 0;
+}
+
+static int null_digest(struct shash_desc *desc, const u8 *data,
+		       unsigned int len, u8 *out)
+{
+	return 0;
+}
+
+static int null_hash_setkey(struct crypto_shash *tfm, const u8 *key,
+			    unsigned int keylen)
+{ return 0; }
 
 static int null_setkey(struct crypto_tfm *tfm, const u8 *key,
 		       unsigned int keylen)
@@ -89,19 +106,20 @@
 	.coa_decompress		=	null_compress } }
 };
 
-static struct crypto_alg digest_null = {
-	.cra_name		=	"digest_null",
-	.cra_flags		=	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize		=	NULL_BLOCK_SIZE,
-	.cra_ctxsize		=	0,
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=       LIST_HEAD_INIT(digest_null.cra_list),	
-	.cra_u			=	{ .digest = {
-	.dia_digestsize		=	NULL_DIGEST_SIZE,
-	.dia_setkey   		=	null_setkey,
-	.dia_init   		=	null_init,
-	.dia_update 		=	null_update,
-	.dia_final  		=	null_final } }
+static struct shash_alg digest_null = {
+	.digestsize		=	NULL_DIGEST_SIZE,
+	.setkey   		=	null_hash_setkey,
+	.init   		=	null_init,
+	.update 		=	null_update,
+	.finup 			=	null_digest,
+	.digest 		=	null_digest,
+	.final  		=	null_final,
+	.base			=	{
+		.cra_name		=	"digest_null",
+		.cra_flags		=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize		=	NULL_BLOCK_SIZE,
+		.cra_module		=	THIS_MODULE,
+	}
 };
 
 static struct crypto_alg cipher_null = {
@@ -154,7 +172,7 @@
 	if (ret < 0)
 		goto out_unregister_cipher;
 
-	ret = crypto_register_alg(&digest_null);
+	ret = crypto_register_shash(&digest_null);
 	if (ret < 0)
 		goto out_unregister_skcipher;
 
@@ -166,7 +184,7 @@
 	return ret;
 
 out_unregister_digest:
-	crypto_unregister_alg(&digest_null);
+	crypto_unregister_shash(&digest_null);
 out_unregister_skcipher:
 	crypto_unregister_alg(&skcipher_null);
 out_unregister_cipher:
@@ -177,7 +195,7 @@
 static void __exit crypto_null_mod_fini(void)
 {
 	crypto_unregister_alg(&compress_null);
-	crypto_unregister_alg(&digest_null);
+	crypto_unregister_shash(&digest_null);
 	crypto_unregister_alg(&skcipher_null);
 	crypto_unregister_alg(&cipher_null);
 }
diff --git a/crypto/des_generic.c b/crypto/des_generic.c
index 5d0e458..5bd3ee3 100644
--- a/crypto/des_generic.c
+++ b/crypto/des_generic.c
@@ -868,9 +868,10 @@
 	u32 *flags = &tfm->crt_flags;
 
 	if (unlikely(!((K[0] ^ K[2]) | (K[1] ^ K[3])) ||
-		     !((K[2] ^ K[4]) | (K[3] ^ K[5]))))
+		     !((K[2] ^ K[4]) | (K[3] ^ K[5]))) &&
+		     (*flags & CRYPTO_TFM_REQ_WEAK_KEY))
 	{
-		*flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
+		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
 		return -EINVAL;
 	}
 
diff --git a/crypto/fcrypt.c b/crypto/fcrypt.c
index 1302f4c..b82d61f 100644
--- a/crypto/fcrypt.c
+++ b/crypto/fcrypt.c
@@ -73,7 +73,7 @@
  * /afs/transarc.com/public/afsps/afs.rel31b.export-src/rxkad/sboxes.h
  */
 #undef Z
-#define Z(x) __constant_cpu_to_be32(x << 3)
+#define Z(x) cpu_to_be32(x << 3)
 static const __be32 sbox0[256] = {
 	Z(0xea), Z(0x7f), Z(0xb2), Z(0x64), Z(0x9d), Z(0xb0), Z(0xd9), Z(0x11),
 	Z(0xcd), Z(0x86), Z(0x86), Z(0x91), Z(0x0a), Z(0xb2), Z(0x93), Z(0x06),
@@ -110,7 +110,7 @@
 };
 
 #undef Z
-#define Z(x) __constant_cpu_to_be32((x << 27) | (x >> 5))
+#define Z(x) cpu_to_be32((x << 27) | (x >> 5))
 static const __be32 sbox1[256] = {
 	Z(0x77), Z(0x14), Z(0xa6), Z(0xfe), Z(0xb2), Z(0x5e), Z(0x8c), Z(0x3e),
 	Z(0x67), Z(0x6c), Z(0xa1), Z(0x0d), Z(0xc2), Z(0xa2), Z(0xc1), Z(0x85),
@@ -147,7 +147,7 @@
 };
 
 #undef Z
-#define Z(x) __constant_cpu_to_be32(x << 11)
+#define Z(x) cpu_to_be32(x << 11)
 static const __be32 sbox2[256] = {
 	Z(0xf0), Z(0x37), Z(0x24), Z(0x53), Z(0x2a), Z(0x03), Z(0x83), Z(0x86),
 	Z(0xd1), Z(0xec), Z(0x50), Z(0xf0), Z(0x42), Z(0x78), Z(0x2f), Z(0x6d),
@@ -184,7 +184,7 @@
 };
 
 #undef Z
-#define Z(x) __constant_cpu_to_be32(x << 19)
+#define Z(x) cpu_to_be32(x << 19)
 static const __be32 sbox3[256] = {
 	Z(0xa9), Z(0x2a), Z(0x48), Z(0x51), Z(0x84), Z(0x7e), Z(0x49), Z(0xe2),
 	Z(0xb5), Z(0xb7), Z(0x42), Z(0x33), Z(0x7d), Z(0x5d), Z(0xa6), Z(0x12),
diff --git a/crypto/hmac.c b/crypto/hmac.c
index 7ff2d6a..0ad39c3 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -16,7 +16,7 @@
  *
  */
 
-#include <crypto/algapi.h>
+#include <crypto/internal/hash.h>
 #include <crypto/scatterwalk.h>
 #include <linux/err.h>
 #include <linux/init.h>
@@ -238,9 +238,11 @@
 		return ERR_CAST(alg);
 
 	inst = ERR_PTR(-EINVAL);
-	ds = (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
-	     CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize :
-				    alg->cra_digest.dia_digestsize;
+	ds = alg->cra_type == &crypto_hash_type ?
+	     alg->cra_hash.digestsize :
+	     alg->cra_type ?
+	     __crypto_shash_alg(alg)->digestsize :
+	     alg->cra_digest.dia_digestsize;
 	if (ds > alg->cra_blocksize)
 		goto out_put_alg;
 
diff --git a/crypto/internal.h b/crypto/internal.h
index 8ef72d7..3c19a27 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -109,6 +109,8 @@
 void crypto_shoot_alg(struct crypto_alg *alg);
 struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
 				      u32 mask);
+struct crypto_tfm *crypto_create_tfm(struct crypto_alg *alg,
+				     const struct crypto_type *frontend);
 
 int crypto_register_instance(struct crypto_template *tmpl,
 			     struct crypto_instance *inst);
diff --git a/crypto/md4.c b/crypto/md4.c
index 3c19aa0..7fca1f59 100644
--- a/crypto/md4.c
+++ b/crypto/md4.c
@@ -20,8 +20,8 @@
  * (at your option) any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
-#include <linux/crypto.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/types.h>
@@ -58,7 +58,7 @@
 {
 	return x ^ y ^ z;
 }
-                        
+
 #define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
 #define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (u32)0x5A827999,s))
 #define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (u32)0x6ED9EBA1,s))
@@ -148,24 +148,26 @@
 
 static inline void md4_transform_helper(struct md4_ctx *ctx)
 {
-	le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32));
+	le32_to_cpu_array(ctx->block, ARRAY_SIZE(ctx->block));
 	md4_transform(ctx->hash, ctx->block);
 }
 
-static void md4_init(struct crypto_tfm *tfm)
+static int md4_init(struct shash_desc *desc)
 {
-	struct md4_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct md4_ctx *mctx = shash_desc_ctx(desc);
 
 	mctx->hash[0] = 0x67452301;
 	mctx->hash[1] = 0xefcdab89;
 	mctx->hash[2] = 0x98badcfe;
 	mctx->hash[3] = 0x10325476;
 	mctx->byte_count = 0;
+
+	return 0;
 }
 
-static void md4_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
+static int md4_update(struct shash_desc *desc, const u8 *data, unsigned int len)
 {
-	struct md4_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct md4_ctx *mctx = shash_desc_ctx(desc);
 	const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
 
 	mctx->byte_count += len;
@@ -173,7 +175,7 @@
 	if (avail > len) {
 		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
 		       data, len);
-		return;
+		return 0;
 	}
 
 	memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
@@ -191,11 +193,13 @@
 	}
 
 	memcpy(mctx->block, data, len);
+
+	return 0;
 }
 
-static void md4_final(struct crypto_tfm *tfm, u8 *out)
+static int md4_final(struct shash_desc *desc, u8 *out)
 {
-	struct md4_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct md4_ctx *mctx = shash_desc_ctx(desc);
 	const unsigned int offset = mctx->byte_count & 0x3f;
 	char *p = (char *)mctx->block + offset;
 	int padding = 56 - (offset + 1);
@@ -214,33 +218,35 @@
 	le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
 	                  sizeof(u64)) / sizeof(u32));
 	md4_transform(mctx->hash, mctx->block);
-	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
+	cpu_to_le32_array(mctx->hash, ARRAY_SIZE(mctx->hash));
 	memcpy(out, mctx->hash, sizeof(mctx->hash));
 	memset(mctx, 0, sizeof(*mctx));
+
+	return 0;
 }
 
-static struct crypto_alg alg = {
-	.cra_name	=	"md4",
-	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	=	MD4_HMAC_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct md4_ctx),
-	.cra_module	=	THIS_MODULE,
-	.cra_list       =       LIST_HEAD_INIT(alg.cra_list),	
-	.cra_u		=	{ .digest = {
-	.dia_digestsize	=	MD4_DIGEST_SIZE,
-	.dia_init   	= 	md4_init,
-	.dia_update 	=	md4_update,
-	.dia_final  	=	md4_final } }
+static struct shash_alg alg = {
+	.digestsize	=	MD4_DIGEST_SIZE,
+	.init		=	md4_init,
+	.update		=	md4_update,
+	.final		=	md4_final,
+	.descsize	=	sizeof(struct md4_ctx),
+	.base		=	{
+		.cra_name	=	"md4",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	MD4_HMAC_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
 static int __init md4_mod_init(void)
 {
-	return crypto_register_alg(&alg);
+	return crypto_register_shash(&alg);
 }
 
 static void __exit md4_mod_fini(void)
 {
-	crypto_unregister_alg(&alg);
+	crypto_unregister_shash(&alg);
 }
 
 module_init(md4_mod_init);
diff --git a/crypto/md5.c b/crypto/md5.c
index 39268f3..83eb529 100644
--- a/crypto/md5.c
+++ b/crypto/md5.c
@@ -15,10 +15,10 @@
  * any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/string.h>
-#include <linux/crypto.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
 
@@ -147,20 +147,22 @@
 	md5_transform(ctx->hash, ctx->block);
 }
 
-static void md5_init(struct crypto_tfm *tfm)
+static int md5_init(struct shash_desc *desc)
 {
-	struct md5_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct md5_ctx *mctx = shash_desc_ctx(desc);
 
 	mctx->hash[0] = 0x67452301;
 	mctx->hash[1] = 0xefcdab89;
 	mctx->hash[2] = 0x98badcfe;
 	mctx->hash[3] = 0x10325476;
 	mctx->byte_count = 0;
+
+	return 0;
 }
 
-static void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
+static int md5_update(struct shash_desc *desc, const u8 *data, unsigned int len)
 {
-	struct md5_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct md5_ctx *mctx = shash_desc_ctx(desc);
 	const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
 
 	mctx->byte_count += len;
@@ -168,7 +170,7 @@
 	if (avail > len) {
 		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
 		       data, len);
-		return;
+		return 0;
 	}
 
 	memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
@@ -186,11 +188,13 @@
 	}
 
 	memcpy(mctx->block, data, len);
+
+	return 0;
 }
 
-static void md5_final(struct crypto_tfm *tfm, u8 *out)
+static int md5_final(struct shash_desc *desc, u8 *out)
 {
-	struct md5_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct md5_ctx *mctx = shash_desc_ctx(desc);
 	const unsigned int offset = mctx->byte_count & 0x3f;
 	char *p = (char *)mctx->block + offset;
 	int padding = 56 - (offset + 1);
@@ -212,30 +216,32 @@
 	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
 	memcpy(out, mctx->hash, sizeof(mctx->hash));
 	memset(mctx, 0, sizeof(*mctx));
+
+	return 0;
 }
 
-static struct crypto_alg alg = {
-	.cra_name	=	"md5",
-	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	=	MD5_HMAC_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct md5_ctx),
-	.cra_module	=	THIS_MODULE,
-	.cra_list	=	LIST_HEAD_INIT(alg.cra_list),
-	.cra_u		=	{ .digest = {
-	.dia_digestsize	=	MD5_DIGEST_SIZE,
-	.dia_init   	= 	md5_init,
-	.dia_update 	=	md5_update,
-	.dia_final  	=	md5_final } }
+static struct shash_alg alg = {
+	.digestsize	=	MD5_DIGEST_SIZE,
+	.init		=	md5_init,
+	.update		=	md5_update,
+	.final		=	md5_final,
+	.descsize	=	sizeof(struct md5_ctx),
+	.base		=	{
+		.cra_name	=	"md5",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	MD5_HMAC_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
 static int __init md5_mod_init(void)
 {
-	return crypto_register_alg(&alg);
+	return crypto_register_shash(&alg);
 }
 
 static void __exit md5_mod_fini(void)
 {
-	crypto_unregister_alg(&alg);
+	crypto_unregister_shash(&alg);
 }
 
 module_init(md5_mod_init);
diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c
index 9e917b8..079b761 100644
--- a/crypto/michael_mic.c
+++ b/crypto/michael_mic.c
@@ -9,23 +9,25 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#include <crypto/internal/hash.h>
 #include <asm/byteorder.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/string.h>
-#include <linux/crypto.h>
 #include <linux/types.h>
 
 
 struct michael_mic_ctx {
+	u32 l, r;
+};
+
+struct michael_mic_desc_ctx {
 	u8 pending[4];
 	size_t pending_len;
 
 	u32 l, r;
 };
 
-
 static inline u32 xswap(u32 val)
 {
 	return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
@@ -45,17 +47,22 @@
 } while (0)
 
 
-static void michael_init(struct crypto_tfm *tfm)
+static int michael_init(struct shash_desc *desc)
 {
-	struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc);
+	struct michael_mic_ctx *ctx = crypto_shash_ctx(desc->tfm);
 	mctx->pending_len = 0;
+	mctx->l = ctx->l;
+	mctx->r = ctx->r;
+
+	return 0;
 }
 
 
-static void michael_update(struct crypto_tfm *tfm, const u8 *data,
+static int michael_update(struct shash_desc *desc, const u8 *data,
 			   unsigned int len)
 {
-	struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc);
 	const __le32 *src;
 
 	if (mctx->pending_len) {
@@ -68,7 +75,7 @@
 		len -= flen;
 
 		if (mctx->pending_len < 4)
-			return;
+			return 0;
 
 		src = (const __le32 *)mctx->pending;
 		mctx->l ^= le32_to_cpup(src);
@@ -88,12 +95,14 @@
 		mctx->pending_len = len;
 		memcpy(mctx->pending, src, len);
 	}
+
+	return 0;
 }
 
 
-static void michael_final(struct crypto_tfm *tfm, u8 *out)
+static int michael_final(struct shash_desc *desc, u8 *out)
 {
-	struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc);
 	u8 *data = mctx->pending;
 	__le32 *dst = (__le32 *)out;
 
@@ -119,17 +128,20 @@
 
 	dst[0] = cpu_to_le32(mctx->l);
 	dst[1] = cpu_to_le32(mctx->r);
+
+	return 0;
 }
 
 
-static int michael_setkey(struct crypto_tfm *tfm, const u8 *key,
+static int michael_setkey(struct crypto_shash *tfm, const u8 *key,
 			  unsigned int keylen)
 {
-	struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
+	struct michael_mic_ctx *mctx = crypto_shash_ctx(tfm);
+
 	const __le32 *data = (const __le32 *)key;
 
 	if (keylen != 8) {
-		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
 		return -EINVAL;
 	}
 
@@ -138,33 +150,31 @@
 	return 0;
 }
 
-
-static struct crypto_alg michael_mic_alg = {
-	.cra_name	= "michael_mic",
-	.cra_flags	= CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	= 8,
-	.cra_ctxsize	= sizeof(struct michael_mic_ctx),
-	.cra_module	= THIS_MODULE,
-	.cra_alignmask	= 3,
-	.cra_list	= LIST_HEAD_INIT(michael_mic_alg.cra_list),
-	.cra_u		= { .digest = {
-	.dia_digestsize	= 8,
-	.dia_init	= michael_init,
-	.dia_update	= michael_update,
-	.dia_final	= michael_final,
-	.dia_setkey	= michael_setkey } }
+static struct shash_alg alg = {
+	.digestsize		=	8,
+	.setkey			=	michael_setkey,
+	.init			=	michael_init,
+	.update			=	michael_update,
+	.final			=	michael_final,
+	.descsize		=	sizeof(struct michael_mic_desc_ctx),
+	.base			=	{
+		.cra_name		=	"michael_mic",
+		.cra_blocksize		=	8,
+		.cra_alignmask		=	3,
+		.cra_ctxsize		=	sizeof(struct michael_mic_ctx),
+		.cra_module		=	THIS_MODULE,
+	}
 };
 
-
 static int __init michael_mic_init(void)
 {
-	return crypto_register_alg(&michael_mic_alg);
+	return crypto_register_shash(&alg);
 }
 
 
 static void __exit michael_mic_exit(void)
 {
-	crypto_unregister_alg(&michael_mic_alg);
+	crypto_unregister_shash(&alg);
 }
 
 
diff --git a/crypto/proc.c b/crypto/proc.c
index 37a13d0..5dc07e4 100644
--- a/crypto/proc.c
+++ b/crypto/proc.c
@@ -94,6 +94,17 @@
 	seq_printf(m, "selftest     : %s\n",
 		   (alg->cra_flags & CRYPTO_ALG_TESTED) ?
 		   "passed" : "unknown");
+
+	if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
+		seq_printf(m, "type         : larval\n");
+		seq_printf(m, "flags        : 0x%x\n", alg->cra_flags);
+		goto out;
+	}
+
+	if (alg->cra_type && alg->cra_type->show) {
+		alg->cra_type->show(m, alg);
+		goto out;
+	}
 	
 	switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) {
 	case CRYPTO_ALG_TYPE_CIPHER:
@@ -115,16 +126,11 @@
 		seq_printf(m, "type         : compression\n");
 		break;
 	default:
-		if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
-			seq_printf(m, "type         : larval\n");
-			seq_printf(m, "flags        : 0x%x\n", alg->cra_flags);
-		} else if (alg->cra_type && alg->cra_type->show)
-			alg->cra_type->show(m, alg);
-		else
-			seq_printf(m, "type         : unknown\n");
+		seq_printf(m, "type         : unknown\n");
 		break;
 	}
 
+out:
 	seq_putc(m, '\n');
 	return 0;
 }
diff --git a/crypto/rmd128.c b/crypto/rmd128.c
index 5de6fa2..1ceb673 100644
--- a/crypto/rmd128.c
+++ b/crypto/rmd128.c
@@ -13,11 +13,10 @@
  * any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/crypto.h>
-#include <linux/cryptohash.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
 
@@ -218,9 +217,9 @@
 	return;
 }
 
-static void rmd128_init(struct crypto_tfm *tfm)
+static int rmd128_init(struct shash_desc *desc)
 {
-	struct rmd128_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd128_ctx *rctx = shash_desc_ctx(desc);
 
 	rctx->byte_count = 0;
 
@@ -230,12 +229,14 @@
 	rctx->state[3] = RMD_H3;
 
 	memset(rctx->buffer, 0, sizeof(rctx->buffer));
+
+	return 0;
 }
 
-static void rmd128_update(struct crypto_tfm *tfm, const u8 *data,
-			  unsigned int len)
+static int rmd128_update(struct shash_desc *desc, const u8 *data,
+			 unsigned int len)
 {
-	struct rmd128_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd128_ctx *rctx = shash_desc_ctx(desc);
 	const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f);
 
 	rctx->byte_count += len;
@@ -244,7 +245,7 @@
 	if (avail > len) {
 		memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
 		       data, len);
-		return;
+		goto out;
 	}
 
 	memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
@@ -262,12 +263,15 @@
 	}
 
 	memcpy(rctx->buffer, data, len);
+
+out:
+	return 0;
 }
 
 /* Add padding and return the message digest. */
-static void rmd128_final(struct crypto_tfm *tfm, u8 *out)
+static int rmd128_final(struct shash_desc *desc, u8 *out)
 {
-	struct rmd128_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd128_ctx *rctx = shash_desc_ctx(desc);
 	u32 i, index, padlen;
 	__le64 bits;
 	__le32 *dst = (__le32 *)out;
@@ -278,10 +282,10 @@
 	/* Pad out to 56 mod 64 */
 	index = rctx->byte_count & 0x3f;
 	padlen = (index < 56) ? (56 - index) : ((64+56) - index);
-	rmd128_update(tfm, padding, padlen);
+	rmd128_update(desc, padding, padlen);
 
 	/* Append length */
-	rmd128_update(tfm, (const u8 *)&bits, sizeof(bits));
+	rmd128_update(desc, (const u8 *)&bits, sizeof(bits));
 
 	/* Store state in digest */
 	for (i = 0; i < 4; i++)
@@ -289,31 +293,32 @@
 
 	/* Wipe context */
 	memset(rctx, 0, sizeof(*rctx));
+
+	return 0;
 }
 
-static struct crypto_alg alg = {
-	.cra_name	 =	"rmd128",
-	.cra_driver_name =	"rmd128",
-	.cra_flags	 =	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	 =	RMD128_BLOCK_SIZE,
-	.cra_ctxsize	 =	sizeof(struct rmd128_ctx),
-	.cra_module	 =	THIS_MODULE,
-	.cra_list	 =	LIST_HEAD_INIT(alg.cra_list),
-	.cra_u		 =	{ .digest = {
-	.dia_digestsize	 =	RMD128_DIGEST_SIZE,
-	.dia_init	 =	rmd128_init,
-	.dia_update	 =	rmd128_update,
-	.dia_final	 =	rmd128_final } }
+static struct shash_alg alg = {
+	.digestsize	=	RMD128_DIGEST_SIZE,
+	.init		=	rmd128_init,
+	.update		=	rmd128_update,
+	.final		=	rmd128_final,
+	.descsize	=	sizeof(struct rmd128_ctx),
+	.base		=	{
+		.cra_name	 =	"rmd128",
+		.cra_flags	 =	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	 =	RMD128_BLOCK_SIZE,
+		.cra_module	 =	THIS_MODULE,
+	}
 };
 
 static int __init rmd128_mod_init(void)
 {
-	return crypto_register_alg(&alg);
+	return crypto_register_shash(&alg);
 }
 
 static void __exit rmd128_mod_fini(void)
 {
-	crypto_unregister_alg(&alg);
+	crypto_unregister_shash(&alg);
 }
 
 module_init(rmd128_mod_init);
@@ -321,5 +326,3 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("RIPEMD-128 Message Digest");
-
-MODULE_ALIAS("rmd128");
diff --git a/crypto/rmd160.c b/crypto/rmd160.c
index f001ec7..472261f 100644
--- a/crypto/rmd160.c
+++ b/crypto/rmd160.c
@@ -13,11 +13,10 @@
  * any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/crypto.h>
-#include <linux/cryptohash.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
 
@@ -261,9 +260,9 @@
 	return;
 }
 
-static void rmd160_init(struct crypto_tfm *tfm)
+static int rmd160_init(struct shash_desc *desc)
 {
-	struct rmd160_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd160_ctx *rctx = shash_desc_ctx(desc);
 
 	rctx->byte_count = 0;
 
@@ -274,12 +273,14 @@
 	rctx->state[4] = RMD_H4;
 
 	memset(rctx->buffer, 0, sizeof(rctx->buffer));
+
+	return 0;
 }
 
-static void rmd160_update(struct crypto_tfm *tfm, const u8 *data,
-			  unsigned int len)
+static int rmd160_update(struct shash_desc *desc, const u8 *data,
+			 unsigned int len)
 {
-	struct rmd160_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd160_ctx *rctx = shash_desc_ctx(desc);
 	const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f);
 
 	rctx->byte_count += len;
@@ -288,7 +289,7 @@
 	if (avail > len) {
 		memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
 		       data, len);
-		return;
+		goto out;
 	}
 
 	memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
@@ -306,12 +307,15 @@
 	}
 
 	memcpy(rctx->buffer, data, len);
+
+out:
+	return 0;
 }
 
 /* Add padding and return the message digest. */
-static void rmd160_final(struct crypto_tfm *tfm, u8 *out)
+static int rmd160_final(struct shash_desc *desc, u8 *out)
 {
-	struct rmd160_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd160_ctx *rctx = shash_desc_ctx(desc);
 	u32 i, index, padlen;
 	__le64 bits;
 	__le32 *dst = (__le32 *)out;
@@ -322,10 +326,10 @@
 	/* Pad out to 56 mod 64 */
 	index = rctx->byte_count & 0x3f;
 	padlen = (index < 56) ? (56 - index) : ((64+56) - index);
-	rmd160_update(tfm, padding, padlen);
+	rmd160_update(desc, padding, padlen);
 
 	/* Append length */
-	rmd160_update(tfm, (const u8 *)&bits, sizeof(bits));
+	rmd160_update(desc, (const u8 *)&bits, sizeof(bits));
 
 	/* Store state in digest */
 	for (i = 0; i < 5; i++)
@@ -333,31 +337,32 @@
 
 	/* Wipe context */
 	memset(rctx, 0, sizeof(*rctx));
+
+	return 0;
 }
 
-static struct crypto_alg alg = {
-	.cra_name	 =	"rmd160",
-	.cra_driver_name =	"rmd160",
-	.cra_flags	 =	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	 =	RMD160_BLOCK_SIZE,
-	.cra_ctxsize	 =	sizeof(struct rmd160_ctx),
-	.cra_module	 =	THIS_MODULE,
-	.cra_list	 =	LIST_HEAD_INIT(alg.cra_list),
-	.cra_u		 =	{ .digest = {
-	.dia_digestsize	 =	RMD160_DIGEST_SIZE,
-	.dia_init	 =	rmd160_init,
-	.dia_update	 =	rmd160_update,
-	.dia_final	 =	rmd160_final } }
+static struct shash_alg alg = {
+	.digestsize	=	RMD160_DIGEST_SIZE,
+	.init		=	rmd160_init,
+	.update		=	rmd160_update,
+	.final		=	rmd160_final,
+	.descsize	=	sizeof(struct rmd160_ctx),
+	.base		=	{
+		.cra_name	 =	"rmd160",
+		.cra_flags	 =	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	 =	RMD160_BLOCK_SIZE,
+		.cra_module	 =	THIS_MODULE,
+	}
 };
 
 static int __init rmd160_mod_init(void)
 {
-	return crypto_register_alg(&alg);
+	return crypto_register_shash(&alg);
 }
 
 static void __exit rmd160_mod_fini(void)
 {
-	crypto_unregister_alg(&alg);
+	crypto_unregister_shash(&alg);
 }
 
 module_init(rmd160_mod_init);
@@ -365,5 +370,3 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("RIPEMD-160 Message Digest");
-
-MODULE_ALIAS("rmd160");
diff --git a/crypto/rmd256.c b/crypto/rmd256.c
index e3de5b4..72eafa8 100644
--- a/crypto/rmd256.c
+++ b/crypto/rmd256.c
@@ -13,11 +13,10 @@
  * any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/crypto.h>
-#include <linux/cryptohash.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
 
@@ -233,9 +232,9 @@
 	return;
 }
 
-static void rmd256_init(struct crypto_tfm *tfm)
+static int rmd256_init(struct shash_desc *desc)
 {
-	struct rmd256_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd256_ctx *rctx = shash_desc_ctx(desc);
 
 	rctx->byte_count = 0;
 
@@ -249,12 +248,14 @@
 	rctx->state[7] = RMD_H8;
 
 	memset(rctx->buffer, 0, sizeof(rctx->buffer));
+
+	return 0;
 }
 
-static void rmd256_update(struct crypto_tfm *tfm, const u8 *data,
-			  unsigned int len)
+static int rmd256_update(struct shash_desc *desc, const u8 *data,
+			 unsigned int len)
 {
-	struct rmd256_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd256_ctx *rctx = shash_desc_ctx(desc);
 	const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f);
 
 	rctx->byte_count += len;
@@ -263,7 +264,7 @@
 	if (avail > len) {
 		memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
 		       data, len);
-		return;
+		goto out;
 	}
 
 	memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
@@ -281,12 +282,15 @@
 	}
 
 	memcpy(rctx->buffer, data, len);
+
+out:
+	return 0;
 }
 
 /* Add padding and return the message digest. */
-static void rmd256_final(struct crypto_tfm *tfm, u8 *out)
+static int rmd256_final(struct shash_desc *desc, u8 *out)
 {
-	struct rmd256_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd256_ctx *rctx = shash_desc_ctx(desc);
 	u32 i, index, padlen;
 	__le64 bits;
 	__le32 *dst = (__le32 *)out;
@@ -297,10 +301,10 @@
 	/* Pad out to 56 mod 64 */
 	index = rctx->byte_count & 0x3f;
 	padlen = (index < 56) ? (56 - index) : ((64+56) - index);
-	rmd256_update(tfm, padding, padlen);
+	rmd256_update(desc, padding, padlen);
 
 	/* Append length */
-	rmd256_update(tfm, (const u8 *)&bits, sizeof(bits));
+	rmd256_update(desc, (const u8 *)&bits, sizeof(bits));
 
 	/* Store state in digest */
 	for (i = 0; i < 8; i++)
@@ -308,31 +312,32 @@
 
 	/* Wipe context */
 	memset(rctx, 0, sizeof(*rctx));
+
+	return 0;
 }
 
-static struct crypto_alg alg = {
-	.cra_name	 =	"rmd256",
-	.cra_driver_name =	"rmd256",
-	.cra_flags	 =	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	 =	RMD256_BLOCK_SIZE,
-	.cra_ctxsize	 =	sizeof(struct rmd256_ctx),
-	.cra_module	 =	THIS_MODULE,
-	.cra_list	 =	LIST_HEAD_INIT(alg.cra_list),
-	.cra_u		 =	{ .digest = {
-	.dia_digestsize	 =	RMD256_DIGEST_SIZE,
-	.dia_init	 =	rmd256_init,
-	.dia_update	 =	rmd256_update,
-	.dia_final	 =	rmd256_final } }
+static struct shash_alg alg = {
+	.digestsize	=	RMD256_DIGEST_SIZE,
+	.init		=	rmd256_init,
+	.update		=	rmd256_update,
+	.final		=	rmd256_final,
+	.descsize	=	sizeof(struct rmd256_ctx),
+	.base		=	{
+		.cra_name	 =	"rmd256",
+		.cra_flags	 =	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	 =	RMD256_BLOCK_SIZE,
+		.cra_module	 =	THIS_MODULE,
+	}
 };
 
 static int __init rmd256_mod_init(void)
 {
-	return crypto_register_alg(&alg);
+	return crypto_register_shash(&alg);
 }
 
 static void __exit rmd256_mod_fini(void)
 {
-	crypto_unregister_alg(&alg);
+	crypto_unregister_shash(&alg);
 }
 
 module_init(rmd256_mod_init);
@@ -340,5 +345,3 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("RIPEMD-256 Message Digest");
-
-MODULE_ALIAS("rmd256");
diff --git a/crypto/rmd320.c b/crypto/rmd320.c
index b143d66..86becab 100644
--- a/crypto/rmd320.c
+++ b/crypto/rmd320.c
@@ -13,11 +13,10 @@
  * any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/crypto.h>
-#include <linux/cryptohash.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
 
@@ -280,9 +279,9 @@
 	return;
 }
 
-static void rmd320_init(struct crypto_tfm *tfm)
+static int rmd320_init(struct shash_desc *desc)
 {
-	struct rmd320_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd320_ctx *rctx = shash_desc_ctx(desc);
 
 	rctx->byte_count = 0;
 
@@ -298,12 +297,14 @@
 	rctx->state[9] = RMD_H9;
 
 	memset(rctx->buffer, 0, sizeof(rctx->buffer));
+
+	return 0;
 }
 
-static void rmd320_update(struct crypto_tfm *tfm, const u8 *data,
-			  unsigned int len)
+static int rmd320_update(struct shash_desc *desc, const u8 *data,
+			 unsigned int len)
 {
-	struct rmd320_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd320_ctx *rctx = shash_desc_ctx(desc);
 	const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f);
 
 	rctx->byte_count += len;
@@ -312,7 +313,7 @@
 	if (avail > len) {
 		memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
 		       data, len);
-		return;
+		goto out;
 	}
 
 	memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
@@ -330,12 +331,15 @@
 	}
 
 	memcpy(rctx->buffer, data, len);
+
+out:
+	return 0;
 }
 
 /* Add padding and return the message digest. */
-static void rmd320_final(struct crypto_tfm *tfm, u8 *out)
+static int rmd320_final(struct shash_desc *desc, u8 *out)
 {
-	struct rmd320_ctx *rctx = crypto_tfm_ctx(tfm);
+	struct rmd320_ctx *rctx = shash_desc_ctx(desc);
 	u32 i, index, padlen;
 	__le64 bits;
 	__le32 *dst = (__le32 *)out;
@@ -346,10 +350,10 @@
 	/* Pad out to 56 mod 64 */
 	index = rctx->byte_count & 0x3f;
 	padlen = (index < 56) ? (56 - index) : ((64+56) - index);
-	rmd320_update(tfm, padding, padlen);
+	rmd320_update(desc, padding, padlen);
 
 	/* Append length */
-	rmd320_update(tfm, (const u8 *)&bits, sizeof(bits));
+	rmd320_update(desc, (const u8 *)&bits, sizeof(bits));
 
 	/* Store state in digest */
 	for (i = 0; i < 10; i++)
@@ -357,31 +361,32 @@
 
 	/* Wipe context */
 	memset(rctx, 0, sizeof(*rctx));
+
+	return 0;
 }
 
-static struct crypto_alg alg = {
-	.cra_name	 =	"rmd320",
-	.cra_driver_name =	"rmd320",
-	.cra_flags	 =	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	 =	RMD320_BLOCK_SIZE,
-	.cra_ctxsize	 =	sizeof(struct rmd320_ctx),
-	.cra_module	 =	THIS_MODULE,
-	.cra_list	 =	LIST_HEAD_INIT(alg.cra_list),
-	.cra_u		 =	{ .digest = {
-	.dia_digestsize	 =	RMD320_DIGEST_SIZE,
-	.dia_init	 =	rmd320_init,
-	.dia_update	 =	rmd320_update,
-	.dia_final	 =	rmd320_final } }
+static struct shash_alg alg = {
+	.digestsize	=	RMD320_DIGEST_SIZE,
+	.init		=	rmd320_init,
+	.update		=	rmd320_update,
+	.final		=	rmd320_final,
+	.descsize	=	sizeof(struct rmd320_ctx),
+	.base		=	{
+		.cra_name	 =	"rmd320",
+		.cra_flags	 =	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	 =	RMD320_BLOCK_SIZE,
+		.cra_module	 =	THIS_MODULE,
+	}
 };
 
 static int __init rmd320_mod_init(void)
 {
-	return crypto_register_alg(&alg);
+	return crypto_register_shash(&alg);
 }
 
 static void __exit rmd320_mod_fini(void)
 {
-	crypto_unregister_alg(&alg);
+	crypto_unregister_shash(&alg);
 }
 
 module_init(rmd320_mod_init);
@@ -389,5 +394,3 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("RIPEMD-320 Message Digest");
-
-MODULE_ALIAS("rmd320");
diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c
index b07d559..eac10c1 100644
--- a/crypto/salsa20_generic.c
+++ b/crypto/salsa20_generic.c
@@ -24,6 +24,7 @@
 #include <linux/errno.h>
 #include <linux/crypto.h>
 #include <linux/types.h>
+#include <linux/bitops.h>
 #include <crypto/algapi.h>
 #include <asm/byteorder.h>
 
@@ -42,10 +43,6 @@
 Public domain.
 */
 
-#define ROTATE(v,n) (((v) << (n)) | ((v) >> (32 - (n))))
-#define XOR(v,w) ((v) ^ (w))
-#define PLUS(v,w) (((v) + (w)))
-#define PLUSONE(v) (PLUS((v),1))
 #define U32TO8_LITTLE(p, v) \
 	{ (p)[0] = (v >>  0) & 0xff; (p)[1] = (v >>  8) & 0xff; \
 	  (p)[2] = (v >> 16) & 0xff; (p)[3] = (v >> 24) & 0xff; }
@@ -65,41 +62,41 @@
 
 	memcpy(x, input, sizeof(x));
 	for (i = 20; i > 0; i -= 2) {
-		x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 0],x[12]), 7));
-		x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[ 4],x[ 0]), 9));
-		x[12] = XOR(x[12],ROTATE(PLUS(x[ 8],x[ 4]),13));
-		x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[12],x[ 8]),18));
-		x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 5],x[ 1]), 7));
-		x[13] = XOR(x[13],ROTATE(PLUS(x[ 9],x[ 5]), 9));
-		x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[13],x[ 9]),13));
-		x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 1],x[13]),18));
-		x[14] = XOR(x[14],ROTATE(PLUS(x[10],x[ 6]), 7));
-		x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[14],x[10]), 9));
-		x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 2],x[14]),13));
-		x[10] = XOR(x[10],ROTATE(PLUS(x[ 6],x[ 2]),18));
-		x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[15],x[11]), 7));
-		x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 3],x[15]), 9));
-		x[11] = XOR(x[11],ROTATE(PLUS(x[ 7],x[ 3]),13));
-		x[15] = XOR(x[15],ROTATE(PLUS(x[11],x[ 7]),18));
-		x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[ 0],x[ 3]), 7));
-		x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[ 1],x[ 0]), 9));
-		x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[ 2],x[ 1]),13));
-		x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[ 3],x[ 2]),18));
-		x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 5],x[ 4]), 7));
-		x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 6],x[ 5]), 9));
-		x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 7],x[ 6]),13));
-		x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 4],x[ 7]),18));
-		x[11] = XOR(x[11],ROTATE(PLUS(x[10],x[ 9]), 7));
-		x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[11],x[10]), 9));
-		x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 8],x[11]),13));
-		x[10] = XOR(x[10],ROTATE(PLUS(x[ 9],x[ 8]),18));
-		x[12] = XOR(x[12],ROTATE(PLUS(x[15],x[14]), 7));
-		x[13] = XOR(x[13],ROTATE(PLUS(x[12],x[15]), 9));
-		x[14] = XOR(x[14],ROTATE(PLUS(x[13],x[12]),13));
-		x[15] = XOR(x[15],ROTATE(PLUS(x[14],x[13]),18));
+		x[ 4] ^= rol32((x[ 0] + x[12]),  7);
+		x[ 8] ^= rol32((x[ 4] + x[ 0]),  9);
+		x[12] ^= rol32((x[ 8] + x[ 4]), 13);
+		x[ 0] ^= rol32((x[12] + x[ 8]), 18);
+		x[ 9] ^= rol32((x[ 5] + x[ 1]),  7);
+		x[13] ^= rol32((x[ 9] + x[ 5]),  9);
+		x[ 1] ^= rol32((x[13] + x[ 9]), 13);
+		x[ 5] ^= rol32((x[ 1] + x[13]), 18);
+		x[14] ^= rol32((x[10] + x[ 6]),  7);
+		x[ 2] ^= rol32((x[14] + x[10]),  9);
+		x[ 6] ^= rol32((x[ 2] + x[14]), 13);
+		x[10] ^= rol32((x[ 6] + x[ 2]), 18);
+		x[ 3] ^= rol32((x[15] + x[11]),  7);
+		x[ 7] ^= rol32((x[ 3] + x[15]),  9);
+		x[11] ^= rol32((x[ 7] + x[ 3]), 13);
+		x[15] ^= rol32((x[11] + x[ 7]), 18);
+		x[ 1] ^= rol32((x[ 0] + x[ 3]),  7);
+		x[ 2] ^= rol32((x[ 1] + x[ 0]),  9);
+		x[ 3] ^= rol32((x[ 2] + x[ 1]), 13);
+		x[ 0] ^= rol32((x[ 3] + x[ 2]), 18);
+		x[ 6] ^= rol32((x[ 5] + x[ 4]),  7);
+		x[ 7] ^= rol32((x[ 6] + x[ 5]),  9);
+		x[ 4] ^= rol32((x[ 7] + x[ 6]), 13);
+		x[ 5] ^= rol32((x[ 4] + x[ 7]), 18);
+		x[11] ^= rol32((x[10] + x[ 9]),  7);
+		x[ 8] ^= rol32((x[11] + x[10]),  9);
+		x[ 9] ^= rol32((x[ 8] + x[11]), 13);
+		x[10] ^= rol32((x[ 9] + x[ 8]), 18);
+		x[12] ^= rol32((x[15] + x[14]),  7);
+		x[13] ^= rol32((x[12] + x[15]),  9);
+		x[14] ^= rol32((x[13] + x[12]), 13);
+		x[15] ^= rol32((x[14] + x[13]), 18);
 	}
 	for (i = 0; i < 16; ++i)
-		x[i] = PLUS(x[i],input[i]);
+		x[i] += input[i];
 	for (i = 0; i < 16; ++i)
 		U32TO8_LITTLE(output + 4 * i,x[i]);
 }
@@ -150,9 +147,9 @@
 	while (bytes) {
 		salsa20_wordtobyte(buf, ctx->input);
 
-		ctx->input[8] = PLUSONE(ctx->input[8]);
+		ctx->input[8]++;
 		if (!ctx->input[8])
-			ctx->input[9] = PLUSONE(ctx->input[9]);
+			ctx->input[9]++;
 
 		if (bytes <= 64) {
 			crypto_xor(dst, buf, bytes);
diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c
index c7c6899..9efef20 100644
--- a/crypto/sha1_generic.c
+++ b/crypto/sha1_generic.c
@@ -16,10 +16,10 @@
  * any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/crypto.h>
 #include <linux/cryptohash.h>
 #include <linux/types.h>
 #include <crypto/sha.h>
@@ -31,9 +31,10 @@
         u8 buffer[64];
 };
 
-static void sha1_init(struct crypto_tfm *tfm)
+static int sha1_init(struct shash_desc *desc)
 {
-	struct sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+	struct sha1_ctx *sctx = shash_desc_ctx(desc);
+
 	static const struct sha1_ctx initstate = {
 	  0,
 	  { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 },
@@ -41,12 +42,14 @@
 	};
 
 	*sctx = initstate;
+
+	return 0;
 }
 
-static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
+static int sha1_update(struct shash_desc *desc, const u8 *data,
 			unsigned int len)
 {
-	struct sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+	struct sha1_ctx *sctx = shash_desc_ctx(desc);
 	unsigned int partial, done;
 	const u8 *src;
 
@@ -74,13 +77,15 @@
 		partial = 0;
 	}
 	memcpy(sctx->buffer + partial, src, len - done);
+
+	return 0;
 }
 
 
 /* Add padding and return the message digest. */
-static void sha1_final(struct crypto_tfm *tfm, u8 *out)
+static int sha1_final(struct shash_desc *desc, u8 *out)
 {
-	struct sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+	struct sha1_ctx *sctx = shash_desc_ctx(desc);
 	__be32 *dst = (__be32 *)out;
 	u32 i, index, padlen;
 	__be64 bits;
@@ -91,10 +96,10 @@
 	/* Pad out to 56 mod 64 */
 	index = sctx->count & 0x3f;
 	padlen = (index < 56) ? (56 - index) : ((64+56) - index);
-	sha1_update(tfm, padding, padlen);
+	sha1_update(desc, padding, padlen);
 
 	/* Append length */
-	sha1_update(tfm, (const u8 *)&bits, sizeof(bits));
+	sha1_update(desc, (const u8 *)&bits, sizeof(bits));
 
 	/* Store state in digest */
 	for (i = 0; i < 5; i++)
@@ -102,32 +107,33 @@
 
 	/* Wipe context */
 	memset(sctx, 0, sizeof *sctx);
+
+	return 0;
 }
 
-static struct crypto_alg alg = {
-	.cra_name	=	"sha1",
-	.cra_driver_name=	"sha1-generic",
-	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	=	SHA1_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct sha1_ctx),
-	.cra_module	=	THIS_MODULE,
-	.cra_alignmask	=	3,
-	.cra_list       =       LIST_HEAD_INIT(alg.cra_list),
-	.cra_u		=	{ .digest = {
-	.dia_digestsize	=	SHA1_DIGEST_SIZE,
-	.dia_init   	= 	sha1_init,
-	.dia_update 	=	sha1_update,
-	.dia_final  	=	sha1_final } }
+static struct shash_alg alg = {
+	.digestsize	=	SHA1_DIGEST_SIZE,
+	.init		=	sha1_init,
+	.update		=	sha1_update,
+	.final		=	sha1_final,
+	.descsize	=	sizeof(struct sha1_ctx),
+	.base		=	{
+		.cra_name	=	"sha1",
+		.cra_driver_name=	"sha1-generic",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	SHA1_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
 static int __init sha1_generic_mod_init(void)
 {
-	return crypto_register_alg(&alg);
+	return crypto_register_shash(&alg);
 }
 
 static void __exit sha1_generic_mod_fini(void)
 {
-	crypto_unregister_alg(&alg);
+	crypto_unregister_shash(&alg);
 }
 
 module_init(sha1_generic_mod_init);
diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c
index 5a8dd47..caa3542 100644
--- a/crypto/sha256_generic.c
+++ b/crypto/sha256_generic.c
@@ -17,10 +17,10 @@
  * any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/crypto.h>
 #include <linux/types.h>
 #include <crypto/sha.h>
 #include <asm/byteorder.h>
@@ -69,7 +69,7 @@
 	/* now blend */
 	for (i = 16; i < 64; i++)
 		BLEND_OP(i, W);
-    
+
 	/* load the state into our registers */
 	a=state[0];  b=state[1];  c=state[2];  d=state[3];
 	e=state[4];  f=state[5];  g=state[6];  h=state[7];
@@ -220,9 +220,9 @@
 }
 
 
-static void sha224_init(struct crypto_tfm *tfm)
+static int sha224_init(struct shash_desc *desc)
 {
-	struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
+	struct sha256_ctx *sctx = shash_desc_ctx(desc);
 	sctx->state[0] = SHA224_H0;
 	sctx->state[1] = SHA224_H1;
 	sctx->state[2] = SHA224_H2;
@@ -233,11 +233,13 @@
 	sctx->state[7] = SHA224_H7;
 	sctx->count[0] = 0;
 	sctx->count[1] = 0;
+
+	return 0;
 }
 
-static void sha256_init(struct crypto_tfm *tfm)
+static int sha256_init(struct shash_desc *desc)
 {
-	struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
+	struct sha256_ctx *sctx = shash_desc_ctx(desc);
 	sctx->state[0] = SHA256_H0;
 	sctx->state[1] = SHA256_H1;
 	sctx->state[2] = SHA256_H2;
@@ -247,12 +249,14 @@
 	sctx->state[6] = SHA256_H6;
 	sctx->state[7] = SHA256_H7;
 	sctx->count[0] = sctx->count[1] = 0;
+
+	return 0;
 }
 
-static void sha256_update(struct crypto_tfm *tfm, const u8 *data,
+static int sha256_update(struct shash_desc *desc, const u8 *data,
 			  unsigned int len)
 {
-	struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
+	struct sha256_ctx *sctx = shash_desc_ctx(desc);
 	unsigned int i, index, part_len;
 
 	/* Compute number of bytes mod 128 */
@@ -277,14 +281,16 @@
 	} else {
 		i = 0;
 	}
-	
+
 	/* Buffer remaining input */
 	memcpy(&sctx->buf[index], &data[i], len-i);
+
+	return 0;
 }
 
-static void sha256_final(struct crypto_tfm *tfm, u8 *out)
+static int sha256_final(struct shash_desc *desc, u8 *out)
 {
-	struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
+	struct sha256_ctx *sctx = shash_desc_ctx(desc);
 	__be32 *dst = (__be32 *)out;
 	__be32 bits[2];
 	unsigned int index, pad_len;
@@ -298,10 +304,10 @@
 	/* Pad out to 56 mod 64. */
 	index = (sctx->count[0] >> 3) & 0x3f;
 	pad_len = (index < 56) ? (56 - index) : ((64+56) - index);
-	sha256_update(tfm, padding, pad_len);
+	sha256_update(desc, padding, pad_len);
 
 	/* Append length (before padding) */
-	sha256_update(tfm, (const u8 *)bits, sizeof(bits));
+	sha256_update(desc, (const u8 *)bits, sizeof(bits));
 
 	/* Store state in digest */
 	for (i = 0; i < 8; i++)
@@ -309,71 +315,73 @@
 
 	/* Zeroize sensitive information. */
 	memset(sctx, 0, sizeof(*sctx));
+
+	return 0;
 }
 
-static void sha224_final(struct crypto_tfm *tfm, u8 *hash)
+static int sha224_final(struct shash_desc *desc, u8 *hash)
 {
 	u8 D[SHA256_DIGEST_SIZE];
 
-	sha256_final(tfm, D);
+	sha256_final(desc, D);
 
 	memcpy(hash, D, SHA224_DIGEST_SIZE);
 	memset(D, 0, SHA256_DIGEST_SIZE);
+
+	return 0;
 }
 
-static struct crypto_alg sha256 = {
-	.cra_name	=	"sha256",
-	.cra_driver_name=	"sha256-generic",
-	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	=	SHA256_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct sha256_ctx),
-	.cra_module	=	THIS_MODULE,
-	.cra_alignmask	=	3,
-	.cra_list	=	LIST_HEAD_INIT(sha256.cra_list),
-	.cra_u		=	{ .digest = {
-	.dia_digestsize	=	SHA256_DIGEST_SIZE,
-	.dia_init	=	sha256_init,
-	.dia_update	=	sha256_update,
-	.dia_final	=	sha256_final } }
+static struct shash_alg sha256 = {
+	.digestsize	=	SHA256_DIGEST_SIZE,
+	.init		=	sha256_init,
+	.update		=	sha256_update,
+	.final		=	sha256_final,
+	.descsize	=	sizeof(struct sha256_ctx),
+	.base		=	{
+		.cra_name	=	"sha256",
+		.cra_driver_name=	"sha256-generic",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	SHA256_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
-static struct crypto_alg sha224 = {
-	.cra_name	= "sha224",
-	.cra_driver_name = "sha224-generic",
-	.cra_flags	= CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	= SHA224_BLOCK_SIZE,
-	.cra_ctxsize	= sizeof(struct sha256_ctx),
-	.cra_module	= THIS_MODULE,
-	.cra_alignmask	= 3,
-	.cra_list	= LIST_HEAD_INIT(sha224.cra_list),
-	.cra_u		= { .digest = {
-	.dia_digestsize = SHA224_DIGEST_SIZE,
-	.dia_init	= sha224_init,
-	.dia_update	= sha256_update,
-	.dia_final	= sha224_final } }
+static struct shash_alg sha224 = {
+	.digestsize	=	SHA224_DIGEST_SIZE,
+	.init		=	sha224_init,
+	.update		=	sha256_update,
+	.final		=	sha224_final,
+	.descsize	=	sizeof(struct sha256_ctx),
+	.base		=	{
+		.cra_name	=	"sha224",
+		.cra_driver_name=	"sha224-generic",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	SHA224_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
 static int __init sha256_generic_mod_init(void)
 {
 	int ret = 0;
 
-	ret = crypto_register_alg(&sha224);
+	ret = crypto_register_shash(&sha224);
 
 	if (ret < 0)
 		return ret;
 
-	ret = crypto_register_alg(&sha256);
+	ret = crypto_register_shash(&sha256);
 
 	if (ret < 0)
-		crypto_unregister_alg(&sha224);
+		crypto_unregister_shash(&sha224);
 
 	return ret;
 }
 
 static void __exit sha256_generic_mod_fini(void)
 {
-	crypto_unregister_alg(&sha224);
-	crypto_unregister_alg(&sha256);
+	crypto_unregister_shash(&sha224);
+	crypto_unregister_shash(&sha256);
 }
 
 module_init(sha256_generic_mod_init);
diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c
index bc36861..3bea38d 100644
--- a/crypto/sha512_generic.c
+++ b/crypto/sha512_generic.c
@@ -10,7 +10,7 @@
  * later version.
  *
  */
-
+#include <crypto/internal/hash.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mm.h>
@@ -18,16 +18,17 @@
 #include <linux/crypto.h>
 #include <linux/types.h>
 #include <crypto/sha.h>
-
+#include <linux/percpu.h>
 #include <asm/byteorder.h>
 
 struct sha512_ctx {
 	u64 state[8];
 	u32 count[4];
 	u8 buf[128];
-	u64 W[80];
 };
 
+static DEFINE_PER_CPU(u64[80], msg_schedule);
+
 static inline u64 Ch(u64 x, u64 y, u64 z)
 {
         return z ^ (x & (y ^ z));
@@ -89,11 +90,12 @@
 }
 
 static void
-sha512_transform(u64 *state, u64 *W, const u8 *input)
+sha512_transform(u64 *state, const u8 *input)
 {
 	u64 a, b, c, d, e, f, g, h, t1, t2;
 
 	int i;
+	u64 *W = get_cpu_var(msg_schedule);
 
 	/* load the input */
         for (i = 0; i < 16; i++)
@@ -132,12 +134,14 @@
 
 	/* erase our data */
 	a = b = c = d = e = f = g = h = t1 = t2 = 0;
+	memset(W, 0, sizeof(__get_cpu_var(msg_schedule)));
+	put_cpu_var(msg_schedule);
 }
 
-static void
-sha512_init(struct crypto_tfm *tfm)
+static int
+sha512_init(struct shash_desc *desc)
 {
-	struct sha512_ctx *sctx = crypto_tfm_ctx(tfm);
+	struct sha512_ctx *sctx = shash_desc_ctx(desc);
 	sctx->state[0] = SHA512_H0;
 	sctx->state[1] = SHA512_H1;
 	sctx->state[2] = SHA512_H2;
@@ -147,12 +151,14 @@
 	sctx->state[6] = SHA512_H6;
 	sctx->state[7] = SHA512_H7;
 	sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0;
+
+	return 0;
 }
 
-static void
-sha384_init(struct crypto_tfm *tfm)
+static int
+sha384_init(struct shash_desc *desc)
 {
-	struct sha512_ctx *sctx = crypto_tfm_ctx(tfm);
+	struct sha512_ctx *sctx = shash_desc_ctx(desc);
 	sctx->state[0] = SHA384_H0;
 	sctx->state[1] = SHA384_H1;
 	sctx->state[2] = SHA384_H2;
@@ -162,12 +168,14 @@
 	sctx->state[6] = SHA384_H6;
 	sctx->state[7] = SHA384_H7;
         sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0;
+
+	return 0;
 }
 
-static void
-sha512_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
+static int
+sha512_update(struct shash_desc *desc, const u8 *data, unsigned int len)
 {
-	struct sha512_ctx *sctx = crypto_tfm_ctx(tfm);
+	struct sha512_ctx *sctx = shash_desc_ctx(desc);
 
 	unsigned int i, index, part_len;
 
@@ -187,10 +195,10 @@
 	/* Transform as many times as possible. */
 	if (len >= part_len) {
 		memcpy(&sctx->buf[index], data, part_len);
-		sha512_transform(sctx->state, sctx->W, sctx->buf);
+		sha512_transform(sctx->state, sctx->buf);
 
 		for (i = part_len; i + 127 < len; i+=128)
-			sha512_transform(sctx->state, sctx->W, &data[i]);
+			sha512_transform(sctx->state, &data[i]);
 
 		index = 0;
 	} else {
@@ -200,14 +208,13 @@
 	/* Buffer remaining input */
 	memcpy(&sctx->buf[index], &data[i], len - i);
 
-	/* erase our data */
-	memset(sctx->W, 0, sizeof(sctx->W));
+	return 0;
 }
 
-static void
-sha512_final(struct crypto_tfm *tfm, u8 *hash)
+static int
+sha512_final(struct shash_desc *desc, u8 *hash)
 {
-	struct sha512_ctx *sctx = crypto_tfm_ctx(tfm);
+	struct sha512_ctx *sctx = shash_desc_ctx(desc);
         static u8 padding[128] = { 0x80, };
 	__be64 *dst = (__be64 *)hash;
 	__be32 bits[4];
@@ -223,10 +230,10 @@
 	/* Pad out to 112 mod 128. */
 	index = (sctx->count[0] >> 3) & 0x7f;
 	pad_len = (index < 112) ? (112 - index) : ((128+112) - index);
-	sha512_update(tfm, padding, pad_len);
+	sha512_update(desc, padding, pad_len);
 
 	/* Append length (before padding) */
-	sha512_update(tfm, (const u8 *)bits, sizeof(bits));
+	sha512_update(desc, (const u8 *)bits, sizeof(bits));
 
 	/* Store state in digest */
 	for (i = 0; i < 8; i++)
@@ -234,66 +241,66 @@
 
 	/* Zeroize sensitive information. */
 	memset(sctx, 0, sizeof(struct sha512_ctx));
+
+	return 0;
 }
 
-static void sha384_final(struct crypto_tfm *tfm, u8 *hash)
+static int sha384_final(struct shash_desc *desc, u8 *hash)
 {
-        u8 D[64];
+	u8 D[64];
 
-	sha512_final(tfm, D);
+	sha512_final(desc, D);
 
-        memcpy(hash, D, 48);
-        memset(D, 0, 64);
+	memcpy(hash, D, 48);
+	memset(D, 0, 64);
+
+	return 0;
 }
 
-static struct crypto_alg sha512 = {
-        .cra_name       = "sha512",
-        .cra_flags      = CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize  = SHA512_BLOCK_SIZE,
-        .cra_ctxsize    = sizeof(struct sha512_ctx),
-        .cra_module     = THIS_MODULE,
-	.cra_alignmask	= 3,
-        .cra_list       = LIST_HEAD_INIT(sha512.cra_list),
-        .cra_u          = { .digest = {
-                                .dia_digestsize = SHA512_DIGEST_SIZE,
-                                .dia_init       = sha512_init,
-                                .dia_update     = sha512_update,
-                                .dia_final      = sha512_final }
-        }
+static struct shash_alg sha512 = {
+	.digestsize	=	SHA512_DIGEST_SIZE,
+	.init		=	sha512_init,
+	.update		=	sha512_update,
+	.final		=	sha512_final,
+	.descsize	=	sizeof(struct sha512_ctx),
+	.base		=	{
+		.cra_name	=	"sha512",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	SHA512_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
-static struct crypto_alg sha384 = {
-        .cra_name       = "sha384",
-        .cra_flags      = CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize  = SHA384_BLOCK_SIZE,
-        .cra_ctxsize    = sizeof(struct sha512_ctx),
-	.cra_alignmask	= 3,
-        .cra_module     = THIS_MODULE,
-        .cra_list       = LIST_HEAD_INIT(sha384.cra_list),
-        .cra_u          = { .digest = {
-                                .dia_digestsize = SHA384_DIGEST_SIZE,
-                                .dia_init       = sha384_init,
-                                .dia_update     = sha512_update,
-                                .dia_final      = sha384_final }
-        }
+static struct shash_alg sha384 = {
+	.digestsize	=	SHA384_DIGEST_SIZE,
+	.init		=	sha384_init,
+	.update		=	sha512_update,
+	.final		=	sha384_final,
+	.descsize	=	sizeof(struct sha512_ctx),
+	.base		=	{
+		.cra_name	=	"sha384",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	SHA384_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
 static int __init sha512_generic_mod_init(void)
 {
         int ret = 0;
 
-        if ((ret = crypto_register_alg(&sha384)) < 0)
+        if ((ret = crypto_register_shash(&sha384)) < 0)
                 goto out;
-        if ((ret = crypto_register_alg(&sha512)) < 0)
-                crypto_unregister_alg(&sha384);
+        if ((ret = crypto_register_shash(&sha512)) < 0)
+                crypto_unregister_shash(&sha384);
 out:
         return ret;
 }
 
 static void __exit sha512_generic_mod_fini(void)
 {
-        crypto_unregister_alg(&sha384);
-        crypto_unregister_alg(&sha512);
+        crypto_unregister_shash(&sha384);
+        crypto_unregister_shash(&sha512);
 }
 
 module_init(sha512_generic_mod_init);
diff --git a/crypto/shash.c b/crypto/shash.c
new file mode 100644
index 0000000..c9df367
--- /dev/null
+++ b/crypto/shash.c
@@ -0,0 +1,508 @@
+/*
+ * Synchronous Cryptographic Hash operations.
+ *
+ * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/scatterwalk.h>
+#include <crypto/internal/hash.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+
+static const struct crypto_type crypto_shash_type;
+
+static inline struct crypto_shash *__crypto_shash_cast(struct crypto_tfm *tfm)
+{
+	return container_of(tfm, struct crypto_shash, base);
+}
+
+#include "internal.h"
+
+static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
+				  unsigned int keylen)
+{
+	struct shash_alg *shash = crypto_shash_alg(tfm);
+	unsigned long alignmask = crypto_shash_alignmask(tfm);
+	unsigned long absize;
+	u8 *buffer, *alignbuffer;
+	int err;
+
+	absize = keylen + (alignmask & ~(CRYPTO_MINALIGN - 1));
+	buffer = kmalloc(absize, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+	memcpy(alignbuffer, key, keylen);
+	err = shash->setkey(tfm, alignbuffer, keylen);
+	memset(alignbuffer, 0, keylen);
+	kfree(buffer);
+	return err;
+}
+
+int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key,
+			unsigned int keylen)
+{
+	struct shash_alg *shash = crypto_shash_alg(tfm);
+	unsigned long alignmask = crypto_shash_alignmask(tfm);
+
+	if (!shash->setkey)
+		return -ENOSYS;
+
+	if ((unsigned long)key & alignmask)
+		return shash_setkey_unaligned(tfm, key, keylen);
+
+	return shash->setkey(tfm, key, keylen);
+}
+EXPORT_SYMBOL_GPL(crypto_shash_setkey);
+
+static inline unsigned int shash_align_buffer_size(unsigned len,
+						   unsigned long mask)
+{
+	return len + (mask & ~(__alignof__(u8 __attribute__ ((aligned))) - 1));
+}
+
+static int shash_update_unaligned(struct shash_desc *desc, const u8 *data,
+				  unsigned int len)
+{
+	struct crypto_shash *tfm = desc->tfm;
+	struct shash_alg *shash = crypto_shash_alg(tfm);
+	unsigned long alignmask = crypto_shash_alignmask(tfm);
+	unsigned int unaligned_len = alignmask + 1 -
+				     ((unsigned long)data & alignmask);
+	u8 buf[shash_align_buffer_size(unaligned_len, alignmask)]
+		__attribute__ ((aligned));
+
+	memcpy(buf, data, unaligned_len);
+
+	return shash->update(desc, buf, unaligned_len) ?:
+	       shash->update(desc, data + unaligned_len, len - unaligned_len);
+}
+
+int crypto_shash_update(struct shash_desc *desc, const u8 *data,
+			unsigned int len)
+{
+	struct crypto_shash *tfm = desc->tfm;
+	struct shash_alg *shash = crypto_shash_alg(tfm);
+	unsigned long alignmask = crypto_shash_alignmask(tfm);
+
+	if ((unsigned long)data & alignmask)
+		return shash_update_unaligned(desc, data, len);
+
+	return shash->update(desc, data, len);
+}
+EXPORT_SYMBOL_GPL(crypto_shash_update);
+
+static int shash_final_unaligned(struct shash_desc *desc, u8 *out)
+{
+	struct crypto_shash *tfm = desc->tfm;
+	unsigned long alignmask = crypto_shash_alignmask(tfm);
+	struct shash_alg *shash = crypto_shash_alg(tfm);
+	unsigned int ds = crypto_shash_digestsize(tfm);
+	u8 buf[shash_align_buffer_size(ds, alignmask)]
+		__attribute__ ((aligned));
+	int err;
+
+	err = shash->final(desc, buf);
+	memcpy(out, buf, ds);
+	return err;
+}
+
+int crypto_shash_final(struct shash_desc *desc, u8 *out)
+{
+	struct crypto_shash *tfm = desc->tfm;
+	struct shash_alg *shash = crypto_shash_alg(tfm);
+	unsigned long alignmask = crypto_shash_alignmask(tfm);
+
+	if ((unsigned long)out & alignmask)
+		return shash_final_unaligned(desc, out);
+
+	return shash->final(desc, out);
+}
+EXPORT_SYMBOL_GPL(crypto_shash_final);
+
+static int shash_finup_unaligned(struct shash_desc *desc, const u8 *data,
+				 unsigned int len, u8 *out)
+{
+	return crypto_shash_update(desc, data, len) ?:
+	       crypto_shash_final(desc, out);
+}
+
+int crypto_shash_finup(struct shash_desc *desc, const u8 *data,
+		       unsigned int len, u8 *out)
+{
+	struct crypto_shash *tfm = desc->tfm;
+	struct shash_alg *shash = crypto_shash_alg(tfm);
+	unsigned long alignmask = crypto_shash_alignmask(tfm);
+
+	if (((unsigned long)data | (unsigned long)out) & alignmask ||
+	    !shash->finup)
+		return shash_finup_unaligned(desc, data, len, out);
+
+	return shash->finup(desc, data, len, out);
+}
+EXPORT_SYMBOL_GPL(crypto_shash_finup);
+
+static int shash_digest_unaligned(struct shash_desc *desc, const u8 *data,
+				  unsigned int len, u8 *out)
+{
+	return crypto_shash_init(desc) ?:
+	       crypto_shash_update(desc, data, len) ?:
+	       crypto_shash_final(desc, out);
+}
+
+int crypto_shash_digest(struct shash_desc *desc, const u8 *data,
+			unsigned int len, u8 *out)
+{
+	struct crypto_shash *tfm = desc->tfm;
+	struct shash_alg *shash = crypto_shash_alg(tfm);
+	unsigned long alignmask = crypto_shash_alignmask(tfm);
+
+	if (((unsigned long)data | (unsigned long)out) & alignmask ||
+	    !shash->digest)
+		return shash_digest_unaligned(desc, data, len, out);
+
+	return shash->digest(desc, data, len, out);
+}
+EXPORT_SYMBOL_GPL(crypto_shash_digest);
+
+int crypto_shash_import(struct shash_desc *desc, const u8 *in)
+{
+	struct crypto_shash *tfm = desc->tfm;
+	struct shash_alg *alg = crypto_shash_alg(tfm);
+
+	memcpy(shash_desc_ctx(desc), in, crypto_shash_descsize(tfm));
+
+	if (alg->reinit)
+		alg->reinit(desc);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_shash_import);
+
+static int shash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
+			      unsigned int keylen)
+{
+	struct crypto_shash **ctx = crypto_ahash_ctx(tfm);
+
+	return crypto_shash_setkey(*ctx, key, keylen);
+}
+
+static int shash_async_init(struct ahash_request *req)
+{
+	struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
+	struct shash_desc *desc = ahash_request_ctx(req);
+
+	desc->tfm = *ctx;
+	desc->flags = req->base.flags;
+
+	return crypto_shash_init(desc);
+}
+
+static int shash_async_update(struct ahash_request *req)
+{
+	struct shash_desc *desc = ahash_request_ctx(req);
+	struct crypto_hash_walk walk;
+	int nbytes;
+
+	for (nbytes = crypto_hash_walk_first(req, &walk); nbytes > 0;
+	     nbytes = crypto_hash_walk_done(&walk, nbytes))
+		nbytes = crypto_shash_update(desc, walk.data, nbytes);
+
+	return nbytes;
+}
+
+static int shash_async_final(struct ahash_request *req)
+{
+	return crypto_shash_final(ahash_request_ctx(req), req->result);
+}
+
+static int shash_async_digest(struct ahash_request *req)
+{
+	struct scatterlist *sg = req->src;
+	unsigned int offset = sg->offset;
+	unsigned int nbytes = req->nbytes;
+	int err;
+
+	if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) {
+		struct crypto_shash **ctx =
+			crypto_ahash_ctx(crypto_ahash_reqtfm(req));
+		struct shash_desc *desc = ahash_request_ctx(req);
+		void *data;
+
+		desc->tfm = *ctx;
+		desc->flags = req->base.flags;
+
+		data = crypto_kmap(sg_page(sg), 0);
+		err = crypto_shash_digest(desc, data + offset, nbytes,
+					  req->result);
+		crypto_kunmap(data, 0);
+		crypto_yield(desc->flags);
+		goto out;
+	}
+
+	err = shash_async_init(req);
+	if (err)
+		goto out;
+
+	err = shash_async_update(req);
+	if (err)
+		goto out;
+
+	err = shash_async_final(req);
+
+out:
+	return err;
+}
+
+static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm)
+{
+	struct crypto_shash **ctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_shash(*ctx);
+}
+
+static int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
+{
+	struct crypto_alg *calg = tfm->__crt_alg;
+	struct shash_alg *alg = __crypto_shash_alg(calg);
+	struct ahash_tfm *crt = &tfm->crt_ahash;
+	struct crypto_shash **ctx = crypto_tfm_ctx(tfm);
+	struct crypto_shash *shash;
+
+	if (!crypto_mod_get(calg))
+		return -EAGAIN;
+
+	shash = __crypto_shash_cast(crypto_create_tfm(
+		calg, &crypto_shash_type));
+	if (IS_ERR(shash)) {
+		crypto_mod_put(calg);
+		return PTR_ERR(shash);
+	}
+
+	*ctx = shash;
+	tfm->exit = crypto_exit_shash_ops_async;
+
+	crt->init = shash_async_init;
+	crt->update = shash_async_update;
+	crt->final  = shash_async_final;
+	crt->digest = shash_async_digest;
+	crt->setkey = shash_async_setkey;
+
+	crt->digestsize = alg->digestsize;
+	crt->reqsize = sizeof(struct shash_desc) + crypto_shash_descsize(shash);
+
+	return 0;
+}
+
+static int shash_compat_setkey(struct crypto_hash *tfm, const u8 *key,
+			       unsigned int keylen)
+{
+	struct shash_desc *desc = crypto_hash_ctx(tfm);
+
+	return crypto_shash_setkey(desc->tfm, key, keylen);
+}
+
+static int shash_compat_init(struct hash_desc *hdesc)
+{
+	struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm);
+
+	desc->flags = hdesc->flags;
+
+	return crypto_shash_init(desc);
+}
+
+static int shash_compat_update(struct hash_desc *hdesc, struct scatterlist *sg,
+			       unsigned int len)
+{
+	struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm);
+	struct crypto_hash_walk walk;
+	int nbytes;
+
+	for (nbytes = crypto_hash_walk_first_compat(hdesc, &walk, sg, len);
+	     nbytes > 0; nbytes = crypto_hash_walk_done(&walk, nbytes))
+		nbytes = crypto_shash_update(desc, walk.data, nbytes);
+
+	return nbytes;
+}
+
+static int shash_compat_final(struct hash_desc *hdesc, u8 *out)
+{
+	return crypto_shash_final(crypto_hash_ctx(hdesc->tfm), out);
+}
+
+static int shash_compat_digest(struct hash_desc *hdesc, struct scatterlist *sg,
+			       unsigned int nbytes, u8 *out)
+{
+	unsigned int offset = sg->offset;
+	int err;
+
+	if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) {
+		struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm);
+		void *data;
+
+		desc->flags = hdesc->flags;
+
+		data = crypto_kmap(sg_page(sg), 0);
+		err = crypto_shash_digest(desc, data + offset, nbytes, out);
+		crypto_kunmap(data, 0);
+		crypto_yield(desc->flags);
+		goto out;
+	}
+
+	err = shash_compat_init(hdesc);
+	if (err)
+		goto out;
+
+	err = shash_compat_update(hdesc, sg, nbytes);
+	if (err)
+		goto out;
+
+	err = shash_compat_final(hdesc, out);
+
+out:
+	return err;
+}
+
+static void crypto_exit_shash_ops_compat(struct crypto_tfm *tfm)
+{
+	struct shash_desc *desc= crypto_tfm_ctx(tfm);
+
+	crypto_free_shash(desc->tfm);
+}
+
+static int crypto_init_shash_ops_compat(struct crypto_tfm *tfm)
+{
+	struct hash_tfm *crt = &tfm->crt_hash;
+	struct crypto_alg *calg = tfm->__crt_alg;
+	struct shash_alg *alg = __crypto_shash_alg(calg);
+	struct shash_desc *desc = crypto_tfm_ctx(tfm);
+	struct crypto_shash *shash;
+
+	shash = __crypto_shash_cast(crypto_create_tfm(
+		calg, &crypto_shash_type));
+	if (IS_ERR(shash))
+		return PTR_ERR(shash);
+
+	desc->tfm = shash;
+	tfm->exit = crypto_exit_shash_ops_compat;
+
+	crt->init = shash_compat_init;
+	crt->update = shash_compat_update;
+	crt->final  = shash_compat_final;
+	crt->digest = shash_compat_digest;
+	crt->setkey = shash_compat_setkey;
+
+	crt->digestsize = alg->digestsize;
+
+	return 0;
+}
+
+static int crypto_init_shash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+	switch (mask & CRYPTO_ALG_TYPE_MASK) {
+	case CRYPTO_ALG_TYPE_HASH_MASK:
+		return crypto_init_shash_ops_compat(tfm);
+	case CRYPTO_ALG_TYPE_AHASH_MASK:
+		return crypto_init_shash_ops_async(tfm);
+	}
+
+	return -EINVAL;
+}
+
+static unsigned int crypto_shash_ctxsize(struct crypto_alg *alg, u32 type,
+					 u32 mask)
+{
+	struct shash_alg *salg = __crypto_shash_alg(alg);
+
+	switch (mask & CRYPTO_ALG_TYPE_MASK) {
+	case CRYPTO_ALG_TYPE_HASH_MASK:
+		return sizeof(struct shash_desc) + salg->descsize;
+	case CRYPTO_ALG_TYPE_AHASH_MASK:
+		return sizeof(struct crypto_shash *);
+	}
+
+	return 0;
+}
+
+static int crypto_shash_init_tfm(struct crypto_tfm *tfm,
+				 const struct crypto_type *frontend)
+{
+	if (frontend->type != CRYPTO_ALG_TYPE_SHASH)
+		return -EINVAL;
+	return 0;
+}
+
+static unsigned int crypto_shash_extsize(struct crypto_alg *alg,
+					 const struct crypto_type *frontend)
+{
+	return alg->cra_ctxsize;
+}
+
+static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg)
+	__attribute__ ((unused));
+static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg)
+{
+	struct shash_alg *salg = __crypto_shash_alg(alg);
+
+	seq_printf(m, "type         : shash\n");
+	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
+	seq_printf(m, "digestsize   : %u\n", salg->digestsize);
+	seq_printf(m, "descsize     : %u\n", salg->descsize);
+}
+
+static const struct crypto_type crypto_shash_type = {
+	.ctxsize = crypto_shash_ctxsize,
+	.extsize = crypto_shash_extsize,
+	.init = crypto_init_shash_ops,
+	.init_tfm = crypto_shash_init_tfm,
+#ifdef CONFIG_PROC_FS
+	.show = crypto_shash_show,
+#endif
+	.maskclear = ~CRYPTO_ALG_TYPE_MASK,
+	.maskset = CRYPTO_ALG_TYPE_MASK,
+	.type = CRYPTO_ALG_TYPE_SHASH,
+	.tfmsize = offsetof(struct crypto_shash, base),
+};
+
+struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type,
+					u32 mask)
+{
+	return __crypto_shash_cast(
+		crypto_alloc_tfm(alg_name, &crypto_shash_type, type, mask));
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_shash);
+
+int crypto_register_shash(struct shash_alg *alg)
+{
+	struct crypto_alg *base = &alg->base;
+
+	if (alg->digestsize > PAGE_SIZE / 8 ||
+	    alg->descsize > PAGE_SIZE / 8)
+		return -EINVAL;
+
+	base->cra_type = &crypto_shash_type;
+	base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
+	base->cra_flags |= CRYPTO_ALG_TYPE_SHASH;
+
+	return crypto_register_alg(base);
+}
+EXPORT_SYMBOL_GPL(crypto_register_shash);
+
+int crypto_unregister_shash(struct shash_alg *alg)
+{
+	return crypto_unregister_alg(&alg->base);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_shash);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Synchronous cryptographic hash type");
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index b828c6c..a75f11f 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -843,6 +843,14 @@
 			goto out;
 		}
 
+		if (dlen != ctemplate[i].outlen) {
+			printk(KERN_ERR "alg: comp: Compression test %d "
+			       "failed for %s: output len = %d\n", i + 1, algo,
+			       dlen);
+			ret = -EINVAL;
+			goto out;
+		}
+
 		if (memcmp(result, ctemplate[i].output, dlen)) {
 			printk(KERN_ERR "alg: comp: Compression test %d "
 			       "failed for %s\n", i + 1, algo);
@@ -853,7 +861,7 @@
 	}
 
 	for (i = 0; i < dtcount; i++) {
-		int ilen, ret, dlen = COMP_BUF_SIZE;
+		int ilen, dlen = COMP_BUF_SIZE;
 
 		memset(result, 0, sizeof (result));
 
@@ -867,6 +875,14 @@
 			goto out;
 		}
 
+		if (dlen != dtemplate[i].outlen) {
+			printk(KERN_ERR "alg: comp: Decompression test %d "
+			       "failed for %s: output len = %d\n", i + 1, algo,
+			       dlen);
+			ret = -EINVAL;
+			goto out;
+		}
+
 		if (memcmp(result, dtemplate[i].output, dlen)) {
 			printk(KERN_ERR "alg: comp: Decompression test %d "
 			       "failed for %s\n", i + 1, algo);
@@ -1010,6 +1026,55 @@
 	return err;
 }
 
+static int alg_test_crc32c(const struct alg_test_desc *desc,
+			   const char *driver, u32 type, u32 mask)
+{
+	struct crypto_shash *tfm;
+	u32 val;
+	int err;
+
+	err = alg_test_hash(desc, driver, type, mask);
+	if (err)
+		goto out;
+
+	tfm = crypto_alloc_shash(driver, type, mask);
+	if (IS_ERR(tfm)) {
+		printk(KERN_ERR "alg: crc32c: Failed to load transform for %s: "
+		       "%ld\n", driver, PTR_ERR(tfm));
+		err = PTR_ERR(tfm);
+		goto out;
+	}
+
+	do {
+		struct {
+			struct shash_desc shash;
+			char ctx[crypto_shash_descsize(tfm)];
+		} sdesc;
+
+		sdesc.shash.tfm = tfm;
+		sdesc.shash.flags = 0;
+
+		*(u32 *)sdesc.ctx = le32_to_cpu(420553207);
+		err = crypto_shash_final(&sdesc.shash, (u8 *)&val);
+		if (err) {
+			printk(KERN_ERR "alg: crc32c: Operation failed for "
+			       "%s: %d\n", driver, err);
+			break;
+		}
+
+		if (val != ~420553207) {
+			printk(KERN_ERR "alg: crc32c: Test failed for %s: "
+			       "%d\n", driver, val);
+			err = -EINVAL;
+		}
+	} while (0);
+
+	crypto_free_shash(tfm);
+
+out:
+	return err;
+}
+
 /* Please keep this list sorted by algorithm name. */
 static const struct alg_test_desc alg_test_descs[] = {
 	{
@@ -1134,7 +1199,7 @@
 		}
 	}, {
 		.alg = "crc32c",
-		.test = alg_test_hash,
+		.test = alg_test_crc32c,
 		.suite = {
 			.hash = {
 				.vecs = crc32c_tv_template,
@@ -1801,6 +1866,7 @@
 int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
 {
 	int i;
+	int rc;
 
 	if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) {
 		char nalg[CRYPTO_MAX_ALG_NAME];
@@ -1820,8 +1886,12 @@
 	if (i < 0)
 		goto notest;
 
-	return alg_test_descs[i].test(alg_test_descs + i, driver,
+	rc = alg_test_descs[i].test(alg_test_descs + i, driver,
 				      type, mask);
+	if (fips_enabled && rc)
+		panic("%s: %s alg self test failed in fips mode!\n", driver, alg);
+
+	return rc;
 
 notest:
 	printk(KERN_INFO "alg: No test for %s (%s)\n", alg, driver);
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index dee94d9..132953e 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -8349,7 +8349,7 @@
 
 /*
  * Deflate test vectors (null-terminated strings).
- * Params: winbits=11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL.
+ * Params: winbits=-11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL.
  */
 #define DEFLATE_COMP_TEST_VECTORS 2
 #define DEFLATE_DECOMP_TEST_VECTORS 2
diff --git a/crypto/tgr192.c b/crypto/tgr192.c
index a92414f..cbca4f2 100644
--- a/crypto/tgr192.c
+++ b/crypto/tgr192.c
@@ -21,11 +21,11 @@
  * (at your option) any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <asm/byteorder.h>
-#include <linux/crypto.h>
 #include <linux/types.h>
 
 #define TGR192_DIGEST_SIZE 24
@@ -495,24 +495,26 @@
 	tctx->c = c;
 }
 
-static void tgr192_init(struct crypto_tfm *tfm)
+static int tgr192_init(struct shash_desc *desc)
 {
-	struct tgr192_ctx *tctx = crypto_tfm_ctx(tfm);
+	struct tgr192_ctx *tctx = shash_desc_ctx(desc);
 
 	tctx->a = 0x0123456789abcdefULL;
 	tctx->b = 0xfedcba9876543210ULL;
 	tctx->c = 0xf096a5b4c3b2e187ULL;
 	tctx->nblocks = 0;
 	tctx->count = 0;
+
+	return 0;
 }
 
 
 /* Update the message digest with the contents
  * of INBUF with length INLEN. */
-static void tgr192_update(struct crypto_tfm *tfm, const u8 *inbuf,
+static int tgr192_update(struct shash_desc *desc, const u8 *inbuf,
 			  unsigned int len)
 {
-	struct tgr192_ctx *tctx = crypto_tfm_ctx(tfm);
+	struct tgr192_ctx *tctx = shash_desc_ctx(desc);
 
 	if (tctx->count == 64) {	/* flush the buffer */
 		tgr192_transform(tctx, tctx->hash);
@@ -520,15 +522,15 @@
 		tctx->nblocks++;
 	}
 	if (!inbuf) {
-		return;
+		return 0;
 	}
 	if (tctx->count) {
 		for (; len && tctx->count < 64; len--) {
 			tctx->hash[tctx->count++] = *inbuf++;
 		}
-		tgr192_update(tfm, NULL, 0);
+		tgr192_update(desc, NULL, 0);
 		if (!len) {
-			return;
+			return 0;
 		}
 
 	}
@@ -543,20 +545,22 @@
 	for (; len && tctx->count < 64; len--) {
 		tctx->hash[tctx->count++] = *inbuf++;
 	}
+
+	return 0;
 }
 
 
 
 /* The routine terminates the computation */
-static void tgr192_final(struct crypto_tfm *tfm, u8 * out)
+static int tgr192_final(struct shash_desc *desc, u8 * out)
 {
-	struct tgr192_ctx *tctx = crypto_tfm_ctx(tfm);
+	struct tgr192_ctx *tctx = shash_desc_ctx(desc);
 	__be64 *dst = (__be64 *)out;
 	__be64 *be64p;
 	__le32 *le32p;
 	u32 t, msb, lsb;
 
-	tgr192_update(tfm, NULL, 0); /* flush */ ;
+	tgr192_update(desc, NULL, 0); /* flush */ ;
 
 	msb = 0;
 	t = tctx->nblocks;
@@ -584,7 +588,7 @@
 		while (tctx->count < 64) {
 			tctx->hash[tctx->count++] = 0;
 		}
-		tgr192_update(tfm, NULL, 0); /* flush */ ;
+		tgr192_update(desc, NULL, 0); /* flush */ ;
 		memset(tctx->hash, 0, 56);    /* fill next block with zeroes */
 	}
 	/* append the 64 bit count */
@@ -598,91 +602,94 @@
 	dst[0] = be64p[0] = cpu_to_be64(tctx->a);
 	dst[1] = be64p[1] = cpu_to_be64(tctx->b);
 	dst[2] = be64p[2] = cpu_to_be64(tctx->c);
+
+	return 0;
 }
 
-static void tgr160_final(struct crypto_tfm *tfm, u8 * out)
+static int tgr160_final(struct shash_desc *desc, u8 * out)
 {
 	u8 D[64];
 
-	tgr192_final(tfm, D);
+	tgr192_final(desc, D);
 	memcpy(out, D, TGR160_DIGEST_SIZE);
 	memset(D, 0, TGR192_DIGEST_SIZE);
+
+	return 0;
 }
 
-static void tgr128_final(struct crypto_tfm *tfm, u8 * out)
+static int tgr128_final(struct shash_desc *desc, u8 * out)
 {
 	u8 D[64];
 
-	tgr192_final(tfm, D);
+	tgr192_final(desc, D);
 	memcpy(out, D, TGR128_DIGEST_SIZE);
 	memset(D, 0, TGR192_DIGEST_SIZE);
+
+	return 0;
 }
 
-static struct crypto_alg tgr192 = {
-	.cra_name = "tgr192",
-	.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize = TGR192_BLOCK_SIZE,
-	.cra_ctxsize = sizeof(struct tgr192_ctx),
-	.cra_module = THIS_MODULE,
-	.cra_alignmask = 7,
-	.cra_list = LIST_HEAD_INIT(tgr192.cra_list),
-	.cra_u = {.digest = {
-			     .dia_digestsize = TGR192_DIGEST_SIZE,
-			     .dia_init = tgr192_init,
-			     .dia_update = tgr192_update,
-			     .dia_final = tgr192_final}}
+static struct shash_alg tgr192 = {
+	.digestsize	=	TGR192_DIGEST_SIZE,
+	.init		=	tgr192_init,
+	.update		=	tgr192_update,
+	.final		=	tgr192_final,
+	.descsize	=	sizeof(struct tgr192_ctx),
+	.base		=	{
+		.cra_name	=	"tgr192",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	TGR192_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
-static struct crypto_alg tgr160 = {
-	.cra_name = "tgr160",
-	.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize = TGR192_BLOCK_SIZE,
-	.cra_ctxsize = sizeof(struct tgr192_ctx),
-	.cra_module = THIS_MODULE,
-	.cra_alignmask = 7,
-	.cra_list = LIST_HEAD_INIT(tgr160.cra_list),
-	.cra_u = {.digest = {
-			     .dia_digestsize = TGR160_DIGEST_SIZE,
-			     .dia_init = tgr192_init,
-			     .dia_update = tgr192_update,
-			     .dia_final = tgr160_final}}
+static struct shash_alg tgr160 = {
+	.digestsize	=	TGR160_DIGEST_SIZE,
+	.init		=	tgr192_init,
+	.update		=	tgr192_update,
+	.final		=	tgr160_final,
+	.descsize	=	sizeof(struct tgr192_ctx),
+	.base		=	{
+		.cra_name	=	"tgr160",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	TGR192_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
-static struct crypto_alg tgr128 = {
-	.cra_name = "tgr128",
-	.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize = TGR192_BLOCK_SIZE,
-	.cra_ctxsize = sizeof(struct tgr192_ctx),
-	.cra_module = THIS_MODULE,
-	.cra_alignmask = 7,
-	.cra_list = LIST_HEAD_INIT(tgr128.cra_list),
-	.cra_u = {.digest = {
-			     .dia_digestsize = TGR128_DIGEST_SIZE,
-			     .dia_init = tgr192_init,
-			     .dia_update = tgr192_update,
-			     .dia_final = tgr128_final}}
+static struct shash_alg tgr128 = {
+	.digestsize	=	TGR128_DIGEST_SIZE,
+	.init		=	tgr192_init,
+	.update		=	tgr192_update,
+	.final		=	tgr128_final,
+	.descsize	=	sizeof(struct tgr192_ctx),
+	.base		=	{
+		.cra_name	=	"tgr128",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	TGR192_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
 static int __init tgr192_mod_init(void)
 {
 	int ret = 0;
 
-	ret = crypto_register_alg(&tgr192);
+	ret = crypto_register_shash(&tgr192);
 
 	if (ret < 0) {
 		goto out;
 	}
 
-	ret = crypto_register_alg(&tgr160);
+	ret = crypto_register_shash(&tgr160);
 	if (ret < 0) {
-		crypto_unregister_alg(&tgr192);
+		crypto_unregister_shash(&tgr192);
 		goto out;
 	}
 
-	ret = crypto_register_alg(&tgr128);
+	ret = crypto_register_shash(&tgr128);
 	if (ret < 0) {
-		crypto_unregister_alg(&tgr192);
-		crypto_unregister_alg(&tgr160);
+		crypto_unregister_shash(&tgr192);
+		crypto_unregister_shash(&tgr160);
 	}
       out:
 	return ret;
@@ -690,9 +697,9 @@
 
 static void __exit tgr192_mod_fini(void)
 {
-	crypto_unregister_alg(&tgr192);
-	crypto_unregister_alg(&tgr160);
-	crypto_unregister_alg(&tgr128);
+	crypto_unregister_shash(&tgr192);
+	crypto_unregister_shash(&tgr160);
+	crypto_unregister_shash(&tgr128);
 }
 
 MODULE_ALIAS("tgr160");
diff --git a/crypto/wp512.c b/crypto/wp512.c
index bff2856..7234272 100644
--- a/crypto/wp512.c
+++ b/crypto/wp512.c
@@ -19,11 +19,11 @@
  * (at your option) any later version.
  *
  */
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <asm/byteorder.h>
-#include <linux/crypto.h>
 #include <linux/types.h>
 
 #define WP512_DIGEST_SIZE 64
@@ -980,8 +980,8 @@
 
 }
 
-static void wp512_init(struct crypto_tfm *tfm) {
-	struct wp512_ctx *wctx = crypto_tfm_ctx(tfm);
+static int wp512_init(struct shash_desc *desc) {
+	struct wp512_ctx *wctx = shash_desc_ctx(desc);
 	int i;
 
 	memset(wctx->bitLength, 0, 32);
@@ -990,12 +990,14 @@
 	for (i = 0; i < 8; i++) {
 		wctx->hash[i] = 0L;
 	}
+
+	return 0;
 }
 
-static void wp512_update(struct crypto_tfm *tfm, const u8 *source,
+static int wp512_update(struct shash_desc *desc, const u8 *source,
 			 unsigned int len)
 {
-	struct wp512_ctx *wctx = crypto_tfm_ctx(tfm);
+	struct wp512_ctx *wctx = shash_desc_ctx(desc);
 	int sourcePos    = 0;
 	unsigned int bits_len = len * 8; // convert to number of bits
 	int sourceGap    = (8 - ((int)bits_len & 7)) & 7;
@@ -1051,11 +1053,12 @@
 	wctx->bufferBits   = bufferBits;
 	wctx->bufferPos    = bufferPos;
 
+	return 0;
 }
 
-static void wp512_final(struct crypto_tfm *tfm, u8 *out)
+static int wp512_final(struct shash_desc *desc, u8 *out)
 {
-	struct wp512_ctx *wctx = crypto_tfm_ctx(tfm);
+	struct wp512_ctx *wctx = shash_desc_ctx(desc);
 	int i;
    	u8 *buffer      = wctx->buffer;
    	u8 *bitLength   = wctx->bitLength;
@@ -1084,89 +1087,95 @@
 		digest[i] = cpu_to_be64(wctx->hash[i]);
    	wctx->bufferBits   = bufferBits;
    	wctx->bufferPos    = bufferPos;
+
+	return 0;
 }
 
-static void wp384_final(struct crypto_tfm *tfm, u8 *out)
+static int wp384_final(struct shash_desc *desc, u8 *out)
 {
 	u8 D[64];
 
-	wp512_final(tfm, D);
+	wp512_final(desc, D);
 	memcpy (out, D, WP384_DIGEST_SIZE);
 	memset (D, 0, WP512_DIGEST_SIZE);
+
+	return 0;
 }
 
-static void wp256_final(struct crypto_tfm *tfm, u8 *out)
+static int wp256_final(struct shash_desc *desc, u8 *out)
 {
 	u8 D[64];
 
-	wp512_final(tfm, D);
+	wp512_final(desc, D);
 	memcpy (out, D, WP256_DIGEST_SIZE);
 	memset (D, 0, WP512_DIGEST_SIZE);
+
+	return 0;
 }
 
-static struct crypto_alg wp512 = {
-	.cra_name	=	"wp512",
-	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	=	WP512_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct wp512_ctx),
-	.cra_module	=	THIS_MODULE,
-	.cra_list       =       LIST_HEAD_INIT(wp512.cra_list),	
-	.cra_u		=	{ .digest = {
-	.dia_digestsize	=	WP512_DIGEST_SIZE,
-	.dia_init   	= 	wp512_init,
-	.dia_update 	=	wp512_update,
-	.dia_final  	=	wp512_final } }
+static struct shash_alg wp512 = {
+	.digestsize	=	WP512_DIGEST_SIZE,
+	.init		=	wp512_init,
+	.update		=	wp512_update,
+	.final		=	wp512_final,
+	.descsize	=	sizeof(struct wp512_ctx),
+	.base		=	{
+		.cra_name	=	"wp512",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	WP512_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
-static struct crypto_alg wp384 = {
-	.cra_name	=	"wp384",
-	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	=	WP512_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct wp512_ctx),
-	.cra_module	=	THIS_MODULE,
-	.cra_list       =       LIST_HEAD_INIT(wp384.cra_list),	
-	.cra_u		=	{ .digest = {
-	.dia_digestsize	=	WP384_DIGEST_SIZE,
-	.dia_init   	= 	wp512_init,
-	.dia_update 	=	wp512_update,
-	.dia_final  	=	wp384_final } }
+static struct shash_alg wp384 = {
+	.digestsize	=	WP384_DIGEST_SIZE,
+	.init		=	wp512_init,
+	.update		=	wp512_update,
+	.final		=	wp384_final,
+	.descsize	=	sizeof(struct wp512_ctx),
+	.base		=	{
+		.cra_name	=	"wp384",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	WP512_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
-static struct crypto_alg wp256 = {
-	.cra_name	=	"wp256",
-	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	=	WP512_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct wp512_ctx),
-	.cra_module	=	THIS_MODULE,
-	.cra_list       =       LIST_HEAD_INIT(wp256.cra_list),	
-	.cra_u		=	{ .digest = {
-	.dia_digestsize	=	WP256_DIGEST_SIZE,
-	.dia_init   	= 	wp512_init,
-	.dia_update 	=	wp512_update,
-	.dia_final  	=	wp256_final } }
+static struct shash_alg wp256 = {
+	.digestsize	=	WP256_DIGEST_SIZE,
+	.init		=	wp512_init,
+	.update		=	wp512_update,
+	.final		=	wp256_final,
+	.descsize	=	sizeof(struct wp512_ctx),
+	.base		=	{
+		.cra_name	=	"wp256",
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	WP512_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
 };
 
 static int __init wp512_mod_init(void)
 {
 	int ret = 0;
 
-	ret = crypto_register_alg(&wp512);
+	ret = crypto_register_shash(&wp512);
 
 	if (ret < 0)
 		goto out;
 
-	ret = crypto_register_alg(&wp384);
+	ret = crypto_register_shash(&wp384);
 	if (ret < 0)
 	{
-		crypto_unregister_alg(&wp512);
+		crypto_unregister_shash(&wp512);
 		goto out;
 	}
 
-	ret = crypto_register_alg(&wp256);
+	ret = crypto_register_shash(&wp256);
 	if (ret < 0)
 	{
-		crypto_unregister_alg(&wp512);
-		crypto_unregister_alg(&wp384);
+		crypto_unregister_shash(&wp512);
+		crypto_unregister_shash(&wp384);
 	}
 out:
 	return ret;
@@ -1174,9 +1183,9 @@
 
 static void __exit wp512_mod_fini(void)
 {
-	crypto_unregister_alg(&wp512);
-	crypto_unregister_alg(&wp384);
-	crypto_unregister_alg(&wp256);
+	crypto_unregister_shash(&wp512);
+	crypto_unregister_shash(&wp384);
+	crypto_unregister_shash(&wp256);
 }
 
 MODULE_ALIAS("wp384");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 7edf6d9..765fd1c 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -688,14 +688,6 @@
 	if (acpi_disabled)
 		return;
 
-	/*
-	 * ACPI CA initializes acpi_dbg_level to non-zero, which means
-	 * we get debug output merely by turning on CONFIG_ACPI_DEBUG.
-	 * Turn it off so we don't get output unless the user specifies
-	 * acpi.debug_level.
-	 */
-	acpi_dbg_level = 0;
-
 	printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION);
 
 	/* enable workarounds, unless strict ACPI spec. compliance */
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 11acaee..bf79d83 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -384,6 +384,27 @@
 	return irq;
 }
 
+#ifdef CONFIG_X86_IO_APIC
+extern int noioapicquirk;
+
+static int bridge_has_boot_interrupt_variant(struct pci_bus *bus)
+{
+	struct pci_bus *bus_it;
+
+	for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) {
+		if (!bus_it->self)
+			return 0;
+
+		printk(KERN_INFO "vendor=%04x device=%04x\n", bus_it->self->vendor,
+				bus_it->self->device);
+
+		if (bus_it->self->irq_reroute_variant)
+			return bus_it->self->irq_reroute_variant;
+	}
+	return 0;
+}
+#endif /* CONFIG_X86_IO_APIC */
+
 /*
  * acpi_pci_irq_lookup
  * success: return IRQ >= 0
@@ -413,6 +434,41 @@
 	}
 
 	ret = func(entry, triggering, polarity, link);
+
+#ifdef CONFIG_X86_IO_APIC
+	/*
+	 * Some chipsets (e.g. intel 6700PXH) generate a legacy INTx when the
+	 * IRQ entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel
+	 * does during interrupt handling). When this INTx generation cannot be
+	 * disabled, we reroute these interrupts to their legacy equivalent to
+	 * get rid of spurious interrupts.
+	 */
+        if (!noioapicquirk) {
+		switch (bridge_has_boot_interrupt_variant(bus)) {
+		case 0:
+			/* no rerouting necessary */
+			break;
+
+		case INTEL_IRQ_REROUTE_VARIANT:
+			/*
+			 * Remap according to INTx routing table in 6700PXH
+			 * specs, intel order number 302628-002, section
+			 * 2.15.2. Other chipsets (80332, ...) have the same
+			 * mapping and are handled here as well.
+			 */
+			printk(KERN_INFO "pci irq %d -> rerouted to legacy "
+					 "irq %d\n", ret, (ret % 4) + 16);
+			ret = (ret % 4) + 16;
+			break;
+
+		default:
+			printk(KERN_INFO "not rerouting irq %d to legacy irq: "
+					 "unknown mapping\n", ret);
+			break;
+		}
+	}
+#endif /* CONFIG_X86_IO_APIC */
+
 	return ret;
 }
 
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 5f8d746..38aca04 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -374,15 +374,15 @@
 {
 	switch (boot_cpu_data.x86_vendor) {
 	case X86_VENDOR_AMD:
+	case X86_VENDOR_INTEL:
 		/*
 		 * AMD Fam10h TSC will tick in all
 		 * C/P/S0/S1 states when this bit is set.
 		 */
-		if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
+		if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
 			return 0;
+
 		/*FALL THROUGH*/
-	case X86_VENDOR_INTEL:
-		/* Several cases known where TSC halts in C2 too */
 	default:
 		return state > ACPI_STATE_C1;
 	}
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 670551b..17ed5ac 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -64,7 +64,7 @@
 
 /* Debug switch - layer (component) mask */
 
-u32 acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS;
+u32 acpi_dbg_layer = 0;
 u32 acpi_gbl_nesting_level = 0;
 
 /* Debugger globals */
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 421b7c7..1a7be96 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -456,7 +456,8 @@
 
 config PATA_MPC52xx
 	tristate "Freescale MPC52xx SoC internal IDE"
-	depends on PPC_MPC52xx
+	depends on PPC_MPC52xx && PPC_BESTCOMM
+	select PPC_BESTCOMM_ATA
 	help
 	  This option enables support for integrated IDE controller
 	  of the Freescale MPC52xx SoC.
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index a9e8273..50ae6d1 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -6,6 +6,9 @@
  * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
  * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
  *
+ * UDMA support based on patches by Freescale (Bernard Kuhn, John Rigby),
+ * Domen Puncer and Tim Yamin.
+ *
  * 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.
@@ -17,28 +20,46 @@
 #include <linux/delay.h>
 #include <linux/libata.h>
 #include <linux/of_platform.h>
+#include <linux/types.h>
 
-#include <asm/types.h>
+#include <asm/cacheflush.h>
 #include <asm/prom.h>
 #include <asm/mpc52xx.h>
 
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/bestcomm_priv.h>
+#include <sysdev/bestcomm/ata.h>
 
 #define DRV_NAME	"mpc52xx_ata"
-#define DRV_VERSION	"0.1.2"
-
 
 /* Private structures used by the driver */
 struct mpc52xx_ata_timings {
 	u32	pio1;
 	u32	pio2;
+	u32	mdma1;
+	u32	mdma2;
+	u32	udma1;
+	u32	udma2;
+	u32	udma3;
+	u32	udma4;
+	u32	udma5;
+	int	using_udma;
 };
 
 struct mpc52xx_ata_priv {
 	unsigned int			ipb_period;
-	struct mpc52xx_ata __iomem *	ata_regs;
+	struct mpc52xx_ata __iomem	*ata_regs;
+	phys_addr_t			ata_regs_pa;
 	int				ata_irq;
 	struct mpc52xx_ata_timings	timings[2];
 	int				csel;
+
+	/* DMA */
+	struct bcom_task		*dmatsk;
+	const struct udmaspec		*udmaspec;
+	const struct mdmaspec		*mdmaspec;
+	int 				mpc52xx_ata_dma_last_write;
+	int				waiting_for_dma;
 };
 
 
@@ -53,6 +74,107 @@
 
 #define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c)))
 
+/* ======================================================================== */
+
+/* ATAPI-4 MDMA specs (in clocks) */
+struct mdmaspec {
+	u32 t0M;
+	u32 td;
+	u32 th;
+	u32 tj;
+	u32 tkw;
+	u32 tm;
+	u32 tn;
+};
+
+static const struct mdmaspec mdmaspec66[3] = {
+	{ .t0M = 32, .td = 15, .th = 2, .tj = 2, .tkw = 15, .tm = 4, .tn = 1 },
+	{ .t0M = 10, .td = 6,  .th = 1, .tj = 1, .tkw = 4,  .tm = 2, .tn = 1 },
+	{ .t0M = 8,  .td = 5,  .th = 1, .tj = 1, .tkw = 2,  .tm = 2, .tn = 1 },
+};
+
+static const struct mdmaspec mdmaspec132[3] = {
+	{ .t0M = 64, .td = 29, .th = 3, .tj = 3, .tkw = 29, .tm = 7, .tn = 2 },
+	{ .t0M = 20, .td = 11, .th = 2, .tj = 1, .tkw = 7,  .tm = 4, .tn = 1 },
+	{ .t0M = 16, .td = 10, .th = 2, .tj = 1, .tkw = 4,  .tm = 4, .tn = 1 },
+};
+
+/* ATAPI-4 UDMA specs (in clocks) */
+struct udmaspec {
+	u32 tcyc;
+	u32 t2cyc;
+	u32 tds;
+	u32 tdh;
+	u32 tdvs;
+	u32 tdvh;
+	u32 tfs;
+	u32 tli;
+	u32 tmli;
+	u32 taz;
+	u32 tzah;
+	u32 tenv;
+	u32 tsr;
+	u32 trfs;
+	u32 trp;
+	u32 tack;
+	u32 tss;
+};
+
+static const struct udmaspec udmaspec66[6] = {
+	{ .tcyc = 8,  .t2cyc = 16, .tds  = 1,  .tdh  = 1, .tdvs = 5,  .tdvh = 1,
+	  .tfs  = 16, .tli   = 10, .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 3,  .trfs  = 5,  .trp  = 11, .tack = 2, .tss  = 4,
+	},
+	{ .tcyc = 5,  .t2cyc = 11, .tds  = 1,  .tdh  = 1, .tdvs = 4,  .tdvh = 1,
+	  .tfs  = 14, .tli   = 10, .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 5,  .trp  = 9,  .tack = 2, .tss  = 4,
+	},
+	{ .tcyc = 4,  .t2cyc = 8,  .tds  = 1,  .tdh  = 1, .tdvs = 3,  .tdvh = 1,
+	  .tfs  = 12, .tli   = 10, .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 4,  .trp  = 7,  .tack = 2, .tss  = 4,
+	},
+	{ .tcyc = 3,  .t2cyc = 6,  .tds  = 1,  .tdh  = 1, .tdvs = 2,  .tdvh = 1,
+	  .tfs  = 9,  .tli   = 7,  .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 4,  .trp  = 7,  .tack = 2, .tss  = 4,
+	},
+	{ .tcyc = 2,  .t2cyc = 4,  .tds  = 1,  .tdh  = 1, .tdvs = 1,  .tdvh = 1,
+	  .tfs  = 8,  .tli   = 8,  .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 4,  .trp  = 7,  .tack = 2, .tss  = 4,
+	},
+	{ .tcyc = 2,  .t2cyc = 2,  .tds  = 1,  .tdh  = 1, .tdvs = 1,  .tdvh = 1,
+	  .tfs  = 6,  .tli   = 5,  .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 4,  .trp  = 6,  .tack = 2, .tss  = 4,
+	},
+};
+
+static const struct udmaspec udmaspec132[6] = {
+	{ .tcyc = 15, .t2cyc = 31, .tds  = 2,  .tdh  = 1, .tdvs = 10, .tdvh = 1,
+	  .tfs  = 30, .tli   = 20, .tmli = 3,  .taz  = 2, .tzah = 3,  .tenv = 3,
+	  .tsr  = 7,  .trfs  = 10, .trp  = 22, .tack = 3, .tss  = 7,
+	},
+	{ .tcyc = 10, .t2cyc = 21, .tds  = 2,  .tdh  = 1, .tdvs = 7,  .tdvh = 1,
+	  .tfs  = 27, .tli   = 20, .tmli = 3,  .taz  = 2, .tzah = 3,  .tenv = 3,
+	  .tsr  = 4,  .trfs  = 10, .trp  = 17, .tack = 3, .tss  = 7,
+	},
+	{ .tcyc = 6,  .t2cyc = 12, .tds  = 1,  .tdh  = 1, .tdvs = 5,  .tdvh = 1,
+	  .tfs  = 23, .tli   = 20, .tmli = 3,  .taz  = 2, .tzah = 3,  .tenv = 3,
+	  .tsr  = 3,  .trfs  = 8,  .trp  = 14, .tack = 3, .tss  = 7,
+	},
+	{ .tcyc = 7,  .t2cyc = 12, .tds  = 1,  .tdh  = 1, .tdvs = 3,  .tdvh = 1,
+	  .tfs  = 15, .tli   = 13, .tmli = 3,  .taz  = 2, .tzah = 3,  .tenv = 3,
+	  .tsr  = 3,  .trfs  = 8,  .trp  = 14, .tack = 3, .tss  = 7,
+	},
+	{ .tcyc = 2,  .t2cyc = 5,  .tds  = 0,  .tdh  = 0, .tdvs = 1,  .tdvh = 1,
+	  .tfs  = 16, .tli   = 14, .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 7,  .trp  = 13, .tack = 2, .tss  = 6,
+	},
+	{ .tcyc = 3,  .t2cyc = 6,  .tds  = 1,  .tdh  = 1, .tdvs = 1,  .tdvh = 1,
+	  .tfs  = 12, .tli   = 10, .tmli = 3,  .taz  = 2, .tzah = 3,  .tenv = 3,
+	  .tsr  = 3,  .trfs  = 7,  .trp  = 12, .tack = 3, .tss  = 7,
+	},
+};
+
+/* ======================================================================== */
 
 /* Bit definitions inside the registers */
 #define MPC52xx_ATA_HOSTCONF_SMR	0x80000000UL /* State machine reset */
@@ -66,6 +188,7 @@
 #define MPC52xx_ATA_HOSTSTAT_WERR	0x01000000UL /* Write Error */
 
 #define MPC52xx_ATA_FIFOSTAT_EMPTY	0x01 /* FIFO Empty */
+#define MPC52xx_ATA_FIFOSTAT_ERROR	0x40 /* FIFO Error */
 
 #define MPC52xx_ATA_DMAMODE_WRITE	0x01 /* Write DMA */
 #define MPC52xx_ATA_DMAMODE_READ	0x02 /* Read DMA */
@@ -75,6 +198,8 @@
 #define MPC52xx_ATA_DMAMODE_FR		0x20 /* FIFO Reset */
 #define MPC52xx_ATA_DMAMODE_HUT		0x40 /* Host UDMA burst terminate */
 
+#define MAX_DMA_BUFFERS 128
+#define MAX_DMA_BUFFER_SIZE 0x20000u
 
 /* Structure of the hardware registers */
 struct mpc52xx_ata {
@@ -140,7 +265,6 @@
 
 
 /* MPC52xx low level hw control */
-
 static int
 mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio)
 {
@@ -148,7 +272,7 @@
 	unsigned int ipb_period = priv->ipb_period;
 	unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta;
 
-	if ((pio<0) || (pio>4))
+	if ((pio < 0) || (pio > 4))
 		return -EINVAL;
 
 	t0	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]);
@@ -165,6 +289,43 @@
 	return 0;
 }
 
+static int
+mpc52xx_ata_compute_mdma_timings(struct mpc52xx_ata_priv *priv, int dev,
+				 int speed)
+{
+	struct mpc52xx_ata_timings *t = &priv->timings[dev];
+	const struct mdmaspec *s = &priv->mdmaspec[speed];
+
+	if (speed < 0 || speed > 2)
+		return -EINVAL;
+
+	t->mdma1 = (s->t0M << 24) | (s->td << 16) | (s->tkw << 8) | (s->tm);
+	t->mdma2 = (s->th << 24) | (s->tj << 16) | (s->tn << 8);
+	t->using_udma = 0;
+
+	return 0;
+}
+
+static int
+mpc52xx_ata_compute_udma_timings(struct mpc52xx_ata_priv *priv, int dev,
+				 int speed)
+{
+	struct mpc52xx_ata_timings *t = &priv->timings[dev];
+	const struct udmaspec *s = &priv->udmaspec[speed];
+
+	if (speed < 0 || speed > 2)
+		return -EINVAL;
+
+	t->udma1 = (s->t2cyc << 24) | (s->tcyc << 16) | (s->tds << 8) | s->tdh;
+	t->udma2 = (s->tdvs << 24) | (s->tdvh << 16) | (s->tfs << 8) | s->tli;
+	t->udma3 = (s->tmli << 24) | (s->taz << 16) | (s->tenv << 8) | s->tsr;
+	t->udma4 = (s->tss << 24) | (s->trfs << 16) | (s->trp << 8) | s->tack;
+	t->udma5 = (s->tzah << 24);
+	t->using_udma = 1;
+
+	return 0;
+}
+
 static void
 mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device)
 {
@@ -173,14 +334,13 @@
 
 	out_be32(&regs->pio1,  timing->pio1);
 	out_be32(&regs->pio2,  timing->pio2);
-	out_be32(&regs->mdma1, 0);
-	out_be32(&regs->mdma2, 0);
-	out_be32(&regs->udma1, 0);
-	out_be32(&regs->udma2, 0);
-	out_be32(&regs->udma3, 0);
-	out_be32(&regs->udma4, 0);
-	out_be32(&regs->udma5, 0);
-
+	out_be32(&regs->mdma1, timing->mdma1);
+	out_be32(&regs->mdma2, timing->mdma2);
+	out_be32(&regs->udma1, timing->udma1);
+	out_be32(&regs->udma2, timing->udma2);
+	out_be32(&regs->udma3, timing->udma3);
+	out_be32(&regs->udma4, timing->udma4);
+	out_be32(&regs->udma5, timing->udma5);
 	priv->csel = device;
 }
 
@@ -208,7 +368,7 @@
 
 	/* Set the time slot to 1us */
 	tslot = CALC_CLKCYC(priv->ipb_period, 1000000);
-	out_be32(&regs->share_cnt, tslot << 16 );
+	out_be32(&regs->share_cnt, tslot << 16);
 
 	/* Init timings to PIO0 */
 	memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));
@@ -237,13 +397,37 @@
 	rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio);
 
 	if (rv) {
-		printk(KERN_ERR DRV_NAME
-			": Trying to select invalid PIO mode %d\n", pio);
+		dev_err(ap->dev, "error: invalid PIO mode: %d\n", pio);
 		return;
 	}
 
 	mpc52xx_ata_apply_timings(priv, adev->devno);
 }
+
+static void
+mpc52xx_ata_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+	int rv;
+
+	if (adev->dma_mode >= XFER_UDMA_0) {
+		int dma = adev->dma_mode - XFER_UDMA_0;
+		rv = mpc52xx_ata_compute_udma_timings(priv, adev->devno, dma);
+	} else {
+		int dma = adev->dma_mode - XFER_MW_DMA_0;
+		rv = mpc52xx_ata_compute_mdma_timings(priv, adev->devno, dma);
+	}
+
+	if (rv) {
+		dev_alert(ap->dev,
+			"Trying to select invalid DMA mode %d\n",
+			adev->dma_mode);
+		return;
+	}
+
+	mpc52xx_ata_apply_timings(priv, adev->devno);
+}
+
 static void
 mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device)
 {
@@ -252,7 +436,173 @@
 	if (device != priv->csel)
 		mpc52xx_ata_apply_timings(priv, device);
 
-	ata_sff_dev_select(ap,device);
+	ata_sff_dev_select(ap, device);
+}
+
+static int
+mpc52xx_ata_build_dmatable(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+	struct bcom_ata_bd *bd;
+	unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE), si;
+	struct scatterlist *sg;
+	int count = 0;
+
+	if (read)
+		bcom_ata_rx_prepare(priv->dmatsk);
+	else
+		bcom_ata_tx_prepare(priv->dmatsk);
+
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
+		dma_addr_t cur_addr = sg_dma_address(sg);
+		u32 cur_len = sg_dma_len(sg);
+
+		while (cur_len) {
+			unsigned int tc = min(cur_len, MAX_DMA_BUFFER_SIZE);
+			bd = (struct bcom_ata_bd *)
+				bcom_prepare_next_buffer(priv->dmatsk);
+
+			if (read) {
+				bd->status = tc;
+				bd->src_pa = (__force u32) priv->ata_regs_pa +
+					offsetof(struct mpc52xx_ata, fifo_data);
+				bd->dst_pa = (__force u32) cur_addr;
+			} else {
+				bd->status = tc;
+				bd->src_pa = (__force u32) cur_addr;
+				bd->dst_pa = (__force u32) priv->ata_regs_pa +
+					offsetof(struct mpc52xx_ata, fifo_data);
+			}
+
+			bcom_submit_next_buffer(priv->dmatsk, NULL);
+
+			cur_addr += tc;
+			cur_len -= tc;
+			count++;
+
+			if (count > MAX_DMA_BUFFERS) {
+				dev_alert(ap->dev, "dma table"
+					"too small\n");
+				goto use_pio_instead;
+			}
+		}
+	}
+	return 1;
+
+ use_pio_instead:
+	bcom_ata_reset_bd(priv->dmatsk);
+	return 0;
+}
+
+static void
+mpc52xx_bmdma_setup(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+	struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+
+	unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 dma_mode;
+
+	if (!mpc52xx_ata_build_dmatable(qc))
+		dev_alert(ap->dev, "%s: %i, return 1?\n",
+			__func__, __LINE__);
+
+	/* Check FIFO is OK... */
+	if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR)
+		dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+			__func__, in_8(&priv->ata_regs->fifo_status));
+
+	if (read) {
+		dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ |
+				MPC52xx_ATA_DMAMODE_FE;
+
+		/* Setup FIFO if direction changed */
+		if (priv->mpc52xx_ata_dma_last_write != 0) {
+			priv->mpc52xx_ata_dma_last_write = 0;
+
+			/* Configure FIFO with granularity to 7 */
+			out_8(&regs->fifo_control, 7);
+			out_be16(&regs->fifo_alarm, 128);
+
+			/* Set FIFO Reset bit (FR) */
+			out_8(&regs->dma_mode, MPC52xx_ATA_DMAMODE_FR);
+		}
+	} else {
+		dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE;
+
+		/* Setup FIFO if direction changed */
+		if (priv->mpc52xx_ata_dma_last_write != 1) {
+			priv->mpc52xx_ata_dma_last_write = 1;
+
+			/* Configure FIFO with granularity to 4 */
+			out_8(&regs->fifo_control, 4);
+			out_be16(&regs->fifo_alarm, 128);
+		}
+	}
+
+	if (priv->timings[qc->dev->devno].using_udma)
+		dma_mode |= MPC52xx_ATA_DMAMODE_UDMA;
+
+	out_8(&regs->dma_mode, dma_mode);
+	priv->waiting_for_dma = ATA_DMA_ACTIVE;
+
+	ata_wait_idle(ap);
+	ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+static void
+mpc52xx_bmdma_start(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+	bcom_set_task_auto_start(priv->dmatsk->tasknum, priv->dmatsk->tasknum);
+	bcom_enable(priv->dmatsk);
+}
+
+static void
+mpc52xx_bmdma_stop(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+	bcom_disable(priv->dmatsk);
+	bcom_ata_reset_bd(priv->dmatsk);
+	priv->waiting_for_dma = 0;
+
+	/* Check FIFO is OK... */
+	if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR)
+		dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+			__func__, in_8(&priv->ata_regs->fifo_status));
+}
+
+static u8
+mpc52xx_bmdma_status(struct ata_port *ap)
+{
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+	/* Check FIFO is OK... */
+	if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) {
+		dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+			__func__, in_8(&priv->ata_regs->fifo_status));
+		return priv->waiting_for_dma | ATA_DMA_ERR;
+	}
+
+	return priv->waiting_for_dma;
+}
+
+static irqreturn_t
+mpc52xx_ata_task_irq(int irq, void *vpriv)
+{
+	struct mpc52xx_ata_priv *priv = vpriv;
+	while (bcom_buffer_done(priv->dmatsk))
+		bcom_retrieve_buffer(priv->dmatsk, NULL, NULL);
+
+	priv->waiting_for_dma |= ATA_DMA_INTR;
+
+	return IRQ_HANDLED;
 }
 
 static struct scsi_host_template mpc52xx_ata_sht = {
@@ -262,14 +612,18 @@
 static struct ata_port_operations mpc52xx_ata_port_ops = {
 	.inherits		= &ata_sff_port_ops,
 	.sff_dev_select		= mpc52xx_ata_dev_select,
-	.cable_detect		= ata_cable_40wire,
 	.set_piomode		= mpc52xx_ata_set_piomode,
-	.post_internal_cmd	= ATA_OP_NULL,
+	.set_dmamode		= mpc52xx_ata_set_dmamode,
+	.bmdma_setup		= mpc52xx_bmdma_setup,
+	.bmdma_start		= mpc52xx_bmdma_start,
+	.bmdma_stop		= mpc52xx_bmdma_stop,
+	.bmdma_status		= mpc52xx_bmdma_status,
+	.qc_prep		= ata_noop_qc_prep,
 };
 
 static int __devinit
 mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
-		     unsigned long raw_ata_regs)
+		     unsigned long raw_ata_regs, int mwdma_mask, int udma_mask)
 {
 	struct ata_host *host;
 	struct ata_port *ap;
@@ -281,9 +635,9 @@
 
 	ap = host->ports[0];
 	ap->flags		|= ATA_FLAG_SLAVE_POSS;
-	ap->pio_mask		= 0x1f;	/* Up to PIO4 */
-	ap->mwdma_mask		= 0x00;	/* No MWDMA   */
-	ap->udma_mask		= 0x00;	/* No UDMA    */
+	ap->pio_mask		= ATA_PIO4;
+	ap->mwdma_mask		= mwdma_mask;
+	ap->udma_mask		= udma_mask;
 	ap->ops			= &mpc52xx_ata_port_ops;
 	host->private_data	= priv;
 
@@ -330,89 +684,139 @@
 {
 	unsigned int ipb_freq;
 	struct resource res_mem;
-	int ata_irq;
+	int ata_irq = 0;
 	struct mpc52xx_ata __iomem *ata_regs;
-	struct mpc52xx_ata_priv *priv;
-	int rv;
+	struct mpc52xx_ata_priv *priv = NULL;
+	int rv, ret, task_irq = 0;
+	int mwdma_mask = 0, udma_mask = 0;
+	const __be32 *prop;
+	int proplen;
+	struct bcom_task *dmatsk = NULL;
 
 	/* Get ipb frequency */
 	ipb_freq = mpc52xx_find_ipb_freq(op->node);
 	if (!ipb_freq) {
-		printk(KERN_ERR DRV_NAME ": "
-			"Unable to find IPB Bus frequency\n" );
+		dev_err(&op->dev, "could not determine IPB bus frequency\n");
 		return -ENODEV;
 	}
 
-	/* Get IRQ and register */
+	/* Get device base address from device tree, request the region
+	 * and ioremap it. */
 	rv = of_address_to_resource(op->node, 0, &res_mem);
 	if (rv) {
-		printk(KERN_ERR DRV_NAME ": "
-			"Error while parsing device node resource\n" );
+		dev_err(&op->dev, "could not determine device base address\n");
 		return rv;
 	}
 
-	ata_irq = irq_of_parse_and_map(op->node, 0);
-	if (ata_irq == NO_IRQ) {
-		printk(KERN_ERR DRV_NAME ": "
-			"Error while mapping the irq\n");
-		return -EINVAL;
-	}
-
-	/* Request mem region */
 	if (!devm_request_mem_region(&op->dev, res_mem.start,
-				     sizeof(struct mpc52xx_ata), DRV_NAME)) {
-		printk(KERN_ERR DRV_NAME ": "
-			"Error while requesting mem region\n");
-		rv = -EBUSY;
-		goto err;
+				     sizeof(*ata_regs), DRV_NAME)) {
+		dev_err(&op->dev, "error requesting register region\n");
+		return -EBUSY;
 	}
 
-	/* Remap registers */
-	ata_regs = devm_ioremap(&op->dev, res_mem.start,
-				sizeof(struct mpc52xx_ata));
+	ata_regs = devm_ioremap(&op->dev, res_mem.start, sizeof(*ata_regs));
 	if (!ata_regs) {
-		printk(KERN_ERR DRV_NAME ": "
-			"Error while mapping register set\n");
+		dev_err(&op->dev, "error mapping device registers\n");
 		rv = -ENOMEM;
 		goto err;
 	}
 
+	/*
+	 * By default, all DMA modes are disabled for the MPC5200.  Some
+	 * boards don't have the required signals routed to make DMA work.
+	 * Also, the MPC5200B has a silicon bug that causes data corruption
+	 * with UDMA if it is used at the same time as the LocalPlus bus.
+	 *
+	 * Instead of trying to guess what modes are usable, check the
+	 * ATA device tree node to find out what DMA modes work on the board.
+	 * UDMA/MWDMA modes can also be forced by adding "libata.force=<mode>"
+	 * to the kernel boot parameters.
+	 *
+	 * The MPC5200 ATA controller supports MWDMA modes 0, 1 and 2 and
+	 * UDMA modes 0, 1 and 2.
+	 */
+	prop = of_get_property(op->node, "mwdma-mode", &proplen);
+	if ((prop) && (proplen >= 4))
+		mwdma_mask = 0x7 & ((1 << (*prop + 1)) - 1);
+	prop = of_get_property(op->node, "udma-mode", &proplen);
+	if ((prop) && (proplen >= 4))
+		udma_mask = 0x7 & ((1 << (*prop + 1)) - 1);
+
+	ata_irq = irq_of_parse_and_map(op->node, 0);
+	if (ata_irq == NO_IRQ) {
+		dev_err(&op->dev, "error mapping irq\n");
+		return -EINVAL;
+	}
+
 	/* Prepare our private structure */
-	priv = devm_kzalloc(&op->dev, sizeof(struct mpc52xx_ata_priv),
-			    GFP_ATOMIC);
+	priv = devm_kzalloc(&op->dev, sizeof(*priv), GFP_ATOMIC);
 	if (!priv) {
-		printk(KERN_ERR DRV_NAME ": "
-			"Error while allocating private structure\n");
+		dev_err(&op->dev, "error allocating private structure\n");
 		rv = -ENOMEM;
 		goto err;
 	}
 
 	priv->ipb_period = 1000000000 / (ipb_freq / 1000);
 	priv->ata_regs = ata_regs;
+	priv->ata_regs_pa = res_mem.start;
 	priv->ata_irq = ata_irq;
 	priv->csel = -1;
+	priv->mpc52xx_ata_dma_last_write = -1;
+
+	if (ipb_freq/1000000 == 66) {
+		priv->mdmaspec = mdmaspec66;
+		priv->udmaspec = udmaspec66;
+	} else {
+		priv->mdmaspec = mdmaspec132;
+		priv->udmaspec = udmaspec132;
+	}
+
+	/* Allocate a BestComm task for DMA */
+	dmatsk = bcom_ata_init(MAX_DMA_BUFFERS, MAX_DMA_BUFFER_SIZE);
+	if (!dmatsk) {
+		dev_err(&op->dev, "bestcomm initialization failed\n");
+		rv = -ENOMEM;
+		goto err;
+	}
+
+	task_irq = bcom_get_task_irq(dmatsk);
+	ret = request_irq(task_irq, &mpc52xx_ata_task_irq, IRQF_DISABLED,
+				"ATA task", priv);
+	if (ret) {
+		dev_err(&op->dev, "error requesting DMA IRQ\n");
+		goto err;
+	}
+	priv->dmatsk = dmatsk;
 
 	/* Init the hw */
 	rv = mpc52xx_ata_hw_init(priv);
 	if (rv) {
-		printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+		dev_err(&op->dev, "error initializing hardware\n");
 		goto err;
 	}
 
 	/* Register ourselves to libata */
-	rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start);
+	rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start,
+				  mwdma_mask, udma_mask);
 	if (rv) {
-		printk(KERN_ERR DRV_NAME ": "
-			"Error while registering to ATA layer\n");
-		return rv;
+		dev_err(&op->dev, "error registering with ATA layer\n");
+		goto err;
 	}
 
-	/* Done */
 	return 0;
 
-	/* Error path */
-err:
-	irq_dispose_mapping(ata_irq);
+ err:
+	devm_release_mem_region(&op->dev, res_mem.start, sizeof(*ata_regs));
+	if (ata_irq)
+		irq_dispose_mapping(ata_irq);
+	if (task_irq)
+		irq_dispose_mapping(task_irq);
+	if (dmatsk)
+		bcom_ata_release(dmatsk);
+	if (ata_regs)
+		devm_iounmap(&op->dev, ata_regs);
+	if (priv)
+		devm_kfree(&op->dev, priv);
 	return rv;
 }
 
@@ -420,10 +824,23 @@
 mpc52xx_ata_remove(struct of_device *op)
 {
 	struct mpc52xx_ata_priv *priv;
+	int task_irq;
 
+	/* Deregister the ATA interface */
 	priv = mpc52xx_ata_remove_one(&op->dev);
+
+	/* Clean up DMA */
+	task_irq = bcom_get_task_irq(priv->dmatsk);
+	irq_dispose_mapping(task_irq);
+	bcom_ata_release(priv->dmatsk);
 	irq_dispose_mapping(priv->ata_irq);
 
+	/* Clear up IO allocations */
+	devm_iounmap(&op->dev, priv->ata_regs);
+	devm_release_mem_region(&op->dev, priv->ata_regs_pa,
+				sizeof(*priv->ata_regs));
+	devm_kfree(&op->dev, priv);
+
 	return 0;
 }
 
@@ -447,7 +864,7 @@
 
 	rv = mpc52xx_ata_hw_init(priv);
 	if (rv) {
-		printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+		dev_err(host->dev, "error initializing hardware\n");
 		return rv;
 	}
 
@@ -507,5 +924,4 @@
 MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match);
-MODULE_VERSION(DRV_VERSION);
 
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index f197a19..191b85e 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -391,4 +391,10 @@
 	  Support for the S/UNI-Ultra and S/UNI-622 found in the ForeRunner
 	  HE cards.  This driver provides carrier detection some statistics.
 
+config ATM_SOLOS
+	tristate "Solos ADSL2+ PCI Multiport card driver"
+	depends on PCI
+	help
+	  Support for the Solos multiport ADSL2+ card.
+
 endif # ATM
diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile
index 0bfb317..62c3cc1 100644
--- a/drivers/atm/Makefile
+++ b/drivers/atm/Makefile
@@ -12,6 +12,7 @@
 obj-$(CONFIG_ATM_FORE200E)	+= fore_200e.o
 obj-$(CONFIG_ATM_ENI)		+= eni.o suni.o
 obj-$(CONFIG_ATM_IDT77252)	+= idt77252.o
+obj-$(CONFIG_ATM_SOLOS)		+= solos-pci.o
 
 ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
   obj-$(CONFIG_ATM_NICSTAR)	+= suni.o
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
new file mode 100644
index 0000000..72fc0f7
--- /dev/null
+++ b/drivers/atm/solos-pci.c
@@ -0,0 +1,790 @@
+/*
+ * Driver for the Solos PCI ADSL2+ card, designed to support Linux by
+ *  Traverse Technologies -- http://www.traverse.com.au/
+ *  Xrio Limited          -- http://www.xrio.com/
+ *
+ *
+ * Copyright © 2008 Traverse Technologies
+ * Copyright © 2008 Intel Corporation
+ *
+ * Authors: Nathan Williams <nathan@traverse.com.au>
+ *          David Woodhouse <dwmw2@infradead.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.
+ */
+
+#define DEBUG
+#define VERBOSE_DEBUG
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/atm.h>
+#include <linux/atmdev.h>
+#include <linux/skbuff.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <linux/kobject.h>
+
+#define VERSION "0.04"
+#define PTAG "solos-pci"
+
+#define CONFIG_RAM_SIZE	128
+#define FLAGS_ADDR	0x7C
+#define IRQ_EN_ADDR	0x78
+#define FPGA_VER	0x74
+#define IRQ_CLEAR	0x70
+#define BUG_FLAG	0x6C
+
+#define DATA_RAM_SIZE	32768
+#define BUF_SIZE	4096
+
+#define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2)
+#define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE)
+
+static int debug = 0;
+static int atmdebug = 0;
+
+struct pkt_hdr {
+	__le16 size;
+	__le16 vpi;
+	__le16 vci;
+	__le16 type;
+};
+
+#define PKT_DATA	0
+#define PKT_COMMAND	1
+#define PKT_POPEN	3
+#define PKT_PCLOSE	4
+
+struct solos_card {
+	void __iomem *config_regs;
+	void __iomem *buffers;
+	int nr_ports;
+	struct pci_dev *dev;
+	struct atm_dev *atmdev[4];
+	struct tasklet_struct tlet;
+	spinlock_t tx_lock;
+	spinlock_t tx_queue_lock;
+	spinlock_t cli_queue_lock;
+	struct sk_buff_head tx_queue[4];
+	struct sk_buff_head cli_queue[4];
+};
+
+#define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data)
+
+MODULE_AUTHOR("Traverse Technologies <support@traverse.com.au>");
+MODULE_DESCRIPTION("Solos PCI driver");
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(debug, "Enable Loopback");
+MODULE_PARM_DESC(atmdebug, "Print ATM data");
+module_param(debug, int, 0444);
+module_param(atmdebug, int, 0444);
+
+static int opens;
+
+static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
+		       struct atm_vcc *vcc);
+static int fpga_tx(struct solos_card *);
+static irqreturn_t solos_irq(int irq, void *dev_id);
+static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci);
+static int list_vccs(int vci);
+static int atm_init(struct solos_card *);
+static void atm_remove(struct solos_card *);
+static int send_command(struct solos_card *card, int dev, const char *buf, size_t size);
+static void solos_bh(unsigned long);
+static int print_buffer(struct sk_buff *buf);
+
+static inline void solos_pop(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+        if (vcc->pop)
+                vcc->pop(vcc, skb);
+        else
+                dev_kfree_skb_any(skb);
+}
+
+static ssize_t console_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev);
+	struct solos_card *card = atmdev->dev_data;
+	struct sk_buff *skb;
+
+	spin_lock(&card->cli_queue_lock);
+	skb = skb_dequeue(&card->cli_queue[SOLOS_CHAN(atmdev)]);
+	spin_unlock(&card->cli_queue_lock);
+	if(skb == NULL)
+		return sprintf(buf, "No data.\n");
+
+	memcpy(buf, skb->data, skb->len);
+	dev_dbg(&card->dev->dev, "len: %d\n", skb->len);
+
+	kfree_skb(skb);
+	return skb->len;
+}
+
+static int send_command(struct solos_card *card, int dev, const char *buf, size_t size)
+{
+	struct sk_buff *skb;
+	struct pkt_hdr *header;
+
+//	dev_dbg(&card->dev->dev, "size: %d\n", size);
+
+	if (size > (BUF_SIZE - sizeof(*header))) {
+		dev_dbg(&card->dev->dev, "Command is too big.  Dropping request\n");
+		return 0;
+	}
+	skb = alloc_skb(size + sizeof(*header), GFP_ATOMIC);
+	if (!skb) {
+		dev_warn(&card->dev->dev, "Failed to allocate sk_buff in send_command()\n");
+		return 0;
+	}
+
+	header = (void *)skb_put(skb, sizeof(*header));
+
+	header->size = cpu_to_le16(size);
+	header->vpi = cpu_to_le16(0);
+	header->vci = cpu_to_le16(0);
+	header->type = cpu_to_le16(PKT_COMMAND);
+
+	memcpy(skb_put(skb, size), buf, size);
+
+	fpga_queue(card, dev, skb, NULL);
+
+	return 0;
+}
+
+static ssize_t console_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev);
+	struct solos_card *card = atmdev->dev_data;
+	int err;
+
+	err = send_command(card, SOLOS_CHAN(atmdev), buf, count);
+
+	return err?:count;
+}
+
+static DEVICE_ATTR(console, 0644, console_show, console_store);
+
+static irqreturn_t solos_irq(int irq, void *dev_id)
+{
+	struct solos_card *card = dev_id;
+	int handled = 1;
+
+	//ACK IRQ
+	iowrite32(0, card->config_regs + IRQ_CLEAR);
+	//Disable IRQs from FPGA
+	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
+
+	/* If we only do it when the device is open, we lose console
+	   messages */
+	if (1 || opens)
+		tasklet_schedule(&card->tlet);
+
+	//Enable IRQs from FPGA
+	iowrite32(1, card->config_regs + IRQ_EN_ADDR);
+	return IRQ_RETVAL(handled);
+}
+
+void solos_bh(unsigned long card_arg)
+{
+	struct solos_card *card = (void *)card_arg;
+	int port;
+	uint32_t card_flags;
+	uint32_t tx_mask;
+	uint32_t rx_done = 0;
+
+	card_flags = ioread32(card->config_regs + FLAGS_ADDR);
+
+	/* The TX bits are set if the channel is busy; clear if not. We want to
+	   invoke fpga_tx() unless _all_ the bits for active channels are set */
+	tx_mask = (1 << card->nr_ports) - 1;
+	if ((card_flags & tx_mask) != tx_mask)
+		fpga_tx(card);
+
+	for (port = 0; port < card->nr_ports; port++) {
+		if (card_flags & (0x10 << port)) {
+			struct pkt_hdr header;
+			struct sk_buff *skb;
+			struct atm_vcc *vcc;
+			int size;
+
+			rx_done |= 0x10 << port;
+
+			memcpy_fromio(&header, RX_BUF(card, port), sizeof(header));
+
+			size = le16_to_cpu(header.size);
+
+			skb = alloc_skb(size, GFP_ATOMIC);
+			if (!skb) {
+				if (net_ratelimit())
+					dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n");
+				continue;
+			}
+
+			memcpy_fromio(skb_put(skb, size),
+				      RX_BUF(card, port) + sizeof(header),
+				      size);
+
+			if (atmdebug) {
+				dev_info(&card->dev->dev, "Received: device %d\n", port);
+				dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n",
+					 size, le16_to_cpu(header.vpi),
+					 le16_to_cpu(header.vci));
+				print_buffer(skb);
+			}
+
+			switch (le16_to_cpu(header.type)) {
+			case PKT_DATA:
+				vcc = find_vcc(card->atmdev[port], le16_to_cpu(header.vpi),
+					       le16_to_cpu(header.vci));
+				if (!vcc) {
+					if (net_ratelimit())
+						dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n",
+							 le16_to_cpu(header.vci), le16_to_cpu(header.vpi),
+							 port);
+					continue;
+				}
+				atm_charge(vcc, skb->truesize);
+				vcc->push(vcc, skb);
+				atomic_inc(&vcc->stats->rx);
+				break;
+
+			case PKT_COMMAND:
+			default: /* FIXME: Not really, surely? */
+				spin_lock(&card->cli_queue_lock);
+				if (skb_queue_len(&card->cli_queue[port]) > 10) {
+					if (net_ratelimit())
+						dev_warn(&card->dev->dev, "Dropping console response on port %d\n",
+							 port);
+				} else
+					skb_queue_tail(&card->cli_queue[port], skb);
+				spin_unlock(&card->cli_queue_lock);
+				break;
+			}
+		}
+	}
+	if (rx_done)
+		iowrite32(rx_done, card->config_regs + FLAGS_ADDR);
+
+	return;
+}
+
+static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci)
+{
+	struct hlist_head *head;
+	struct atm_vcc *vcc = NULL;
+	struct hlist_node *node;
+	struct sock *s;
+
+	read_lock(&vcc_sklist_lock);
+	head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)];
+	sk_for_each(s, node, head) {
+		vcc = atm_sk(s);
+		if (vcc->dev == dev && vcc->vci == vci &&
+		    vcc->vpi == vpi && vcc->qos.rxtp.traffic_class != ATM_NONE)
+			goto out;
+	}
+	vcc = NULL;
+ out:
+	read_unlock(&vcc_sklist_lock);
+	return vcc;
+}
+
+static int list_vccs(int vci)
+{
+	struct hlist_head *head;
+	struct atm_vcc *vcc;
+	struct hlist_node *node;
+	struct sock *s;
+	int num_found = 0;
+	int i;
+
+	read_lock(&vcc_sklist_lock);
+	if (vci != 0){
+		head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)];
+		sk_for_each(s, node, head) {
+			num_found ++;
+			vcc = atm_sk(s);
+			printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n",
+			       vcc->dev->number,
+			       vcc->vpi,
+			       vcc->vci);
+		}
+	} else {
+		for(i=0; i<32; i++){
+			head = &vcc_hash[i];
+			sk_for_each(s, node, head) {
+				num_found ++;
+				vcc = atm_sk(s);
+				printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n",
+				       vcc->dev->number,
+				       vcc->vpi,
+				       vcc->vci);
+			}
+		}
+	}
+	read_unlock(&vcc_sklist_lock);
+	return num_found;
+}
+
+
+static int popen(struct atm_vcc *vcc)
+{
+	struct solos_card *card = vcc->dev->dev_data;
+	struct sk_buff *skb;
+	struct pkt_hdr *header;
+
+	skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
+	if (!skb && net_ratelimit()) {
+		dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n");
+		return -ENOMEM;
+	}
+	header = (void *)skb_put(skb, sizeof(*header));
+
+	header->size = cpu_to_le16(sizeof(*header));
+	header->vpi = cpu_to_le16(vcc->vpi);
+	header->vci = cpu_to_le16(vcc->vci);
+	header->type = cpu_to_le16(PKT_POPEN);
+
+	fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL);
+
+//	dev_dbg(&card->dev->dev, "Open for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev));
+	set_bit(ATM_VF_ADDR, &vcc->flags); // accept the vpi / vci
+	set_bit(ATM_VF_READY, &vcc->flags);
+	list_vccs(0);
+
+	if (!opens)
+		iowrite32(1, card->config_regs + IRQ_EN_ADDR);
+
+	opens++; //count open PVCs
+
+	return 0;
+}
+
+static void pclose(struct atm_vcc *vcc)
+{
+	struct solos_card *card = vcc->dev->dev_data;
+	struct sk_buff *skb;
+	struct pkt_hdr *header;
+
+	skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
+	if (!skb) {
+		dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n");
+		return;
+	}
+	header = (void *)skb_put(skb, sizeof(*header));
+
+	header->size = cpu_to_le16(sizeof(*header));
+	header->vpi = cpu_to_le16(vcc->vpi);
+	header->vci = cpu_to_le16(vcc->vci);
+	header->type = cpu_to_le16(PKT_PCLOSE);
+
+	fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL);
+
+//	dev_dbg(&card->dev->dev, "Close for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev));
+	if (!--opens)
+		iowrite32(0, card->config_regs + IRQ_EN_ADDR);
+
+	clear_bit(ATM_VF_ADDR, &vcc->flags);
+	clear_bit(ATM_VF_READY, &vcc->flags);
+
+	return;
+}
+
+static int print_buffer(struct sk_buff *buf)
+{
+	int len,i;
+	char msg[500];
+	char item[10];
+
+	len = buf->len;
+	for (i = 0; i < len; i++){
+		if(i % 8 == 0)
+			sprintf(msg, "%02X: ", i);
+
+		sprintf(item,"%02X ",*(buf->data + i));
+		strcat(msg, item);
+		if(i % 8 == 7) {
+			sprintf(item, "\n");
+			strcat(msg, item);
+			printk(KERN_DEBUG "%s", msg);
+		}
+	}
+	if (i % 8 != 0) {
+		sprintf(item, "\n");
+		strcat(msg, item);
+		printk(KERN_DEBUG "%s", msg);
+	}
+	printk(KERN_DEBUG "\n");
+
+	return 0;
+}
+
+static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
+		       struct atm_vcc *vcc)
+{
+	int old_len;
+
+	*(void **)skb->cb = vcc;
+
+	spin_lock(&card->tx_queue_lock);
+	old_len = skb_queue_len(&card->tx_queue[port]);
+	skb_queue_tail(&card->tx_queue[port], skb);
+	spin_unlock(&card->tx_queue_lock);
+
+	/* If TX might need to be started, do so */
+	if (!old_len)
+		fpga_tx(card);
+}
+
+static int fpga_tx(struct solos_card *card)
+{
+	uint32_t tx_pending;
+	uint32_t tx_started = 0;
+	struct sk_buff *skb;
+	struct atm_vcc *vcc;
+	unsigned char port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->tx_lock, flags);
+
+	tx_pending = ioread32(card->config_regs + FLAGS_ADDR);
+
+	dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending);
+
+	for (port = 0; port < card->nr_ports; port++) {
+		if (!(tx_pending & (1 << port))) {
+
+			spin_lock(&card->tx_queue_lock);
+			skb = skb_dequeue(&card->tx_queue[port]);
+			spin_unlock(&card->tx_queue_lock);
+
+			if (!skb)
+				continue;
+
+			if (atmdebug) {
+				dev_info(&card->dev->dev, "Transmitted: port %d\n",
+					 port);
+				print_buffer(skb);
+			}
+			memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
+
+			vcc = *(void **)skb->cb;
+
+			if (vcc) {
+				atomic_inc(&vcc->stats->tx);
+				solos_pop(vcc, skb);
+			} else
+				dev_kfree_skb_irq(skb);
+
+			tx_started |= 1 << port; //Set TX full flag
+		}
+	}
+	if (tx_started)
+		iowrite32(tx_started, card->config_regs + FLAGS_ADDR);
+
+	spin_unlock_irqrestore(&card->tx_lock, flags);
+	return 0;
+}
+
+static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+	struct solos_card *card = vcc->dev->dev_data;
+	struct sk_buff *skb2 = NULL;
+	struct pkt_hdr *header;
+
+	//dev_dbg(&card->dev->dev, "psend called.\n");
+	//dev_dbg(&card->dev->dev, "dev,vpi,vci = %d,%d,%d\n",SOLOS_CHAN(vcc->dev),vcc->vpi,vcc->vci);
+
+	if (debug) {
+		skb2 = atm_alloc_charge(vcc, skb->len, GFP_ATOMIC);
+		if (skb2) {
+			memcpy(skb2->data, skb->data, skb->len);
+			skb_put(skb2, skb->len);
+			vcc->push(vcc, skb2);
+			atomic_inc(&vcc->stats->rx);
+		}
+		atomic_inc(&vcc->stats->tx);
+		solos_pop(vcc, skb);
+		return 0;
+	}
+
+	if (skb->len > (BUF_SIZE - sizeof(*header))) {
+		dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n");
+		solos_pop(vcc, skb);
+		return 0;
+	}
+
+	if (!skb_clone_writable(skb, sizeof(*header))) {
+		int expand_by = 0;
+		int ret;
+
+		if (skb_headroom(skb) < sizeof(*header))
+			expand_by = sizeof(*header) - skb_headroom(skb);
+
+		ret = pskb_expand_head(skb, expand_by, 0, GFP_ATOMIC);
+		if (ret) {
+			solos_pop(vcc, skb);
+			return ret;
+		}
+	}
+
+	header = (void *)skb_push(skb, sizeof(*header));
+
+	header->size = cpu_to_le16(skb->len);
+	header->vpi = cpu_to_le16(vcc->vpi);
+	header->vci = cpu_to_le16(vcc->vci);
+	header->type = cpu_to_le16(PKT_DATA);
+
+	fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, vcc);
+
+	return 0;
+}
+
+static struct atmdev_ops fpga_ops = {
+	.open =		popen,
+	.close =	pclose,
+	.ioctl =	NULL,
+	.getsockopt =	NULL,
+	.setsockopt =	NULL,
+	.send =		psend,
+	.send_oam =	NULL,
+	.phy_put =	NULL,
+	.phy_get =	NULL,
+	.change_qos =	NULL,
+	.proc_read =	NULL,
+	.owner =	THIS_MODULE
+};
+
+static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	int err, i;
+	uint16_t fpga_ver;
+	uint8_t major_ver, minor_ver;
+	uint32_t data32;
+	struct solos_card *card;
+
+	if (debug)
+		return 0;
+
+	card = kzalloc(sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	card->dev = dev;
+
+	err = pci_enable_device(dev);
+	if (err) {
+		dev_warn(&dev->dev,  "Failed to enable PCI device\n");
+		goto out;
+	}
+
+	err = pci_request_regions(dev, "solos");
+	if (err) {
+		dev_warn(&dev->dev, "Failed to request regions\n");
+		goto out;
+	}
+
+	card->config_regs = pci_iomap(dev, 0, CONFIG_RAM_SIZE);
+	if (!card->config_regs) {
+		dev_warn(&dev->dev, "Failed to ioremap config registers\n");
+		goto out_release_regions;
+	}
+	card->buffers = pci_iomap(dev, 1, DATA_RAM_SIZE);
+	if (!card->buffers) {
+		dev_warn(&dev->dev, "Failed to ioremap data buffers\n");
+		goto out_unmap_config;
+	}
+
+//	for(i=0;i<64 ;i+=4){
+//		data32=ioread32(card->buffers + i);
+//		dev_dbg(&card->dev->dev, "%08lX\n",(unsigned long)data32);
+//	}
+
+	//Fill Config Mem with zeros
+	for(i = 0; i < 128; i += 4)
+		iowrite32(0, card->config_regs + i);
+
+	//Set RX empty flags
+	iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
+
+	data32 = ioread32(card->config_regs + FPGA_VER);
+	fpga_ver = (data32 & 0x0000FFFF);
+	major_ver = ((data32 & 0xFF000000) >> 24);
+	minor_ver = ((data32 & 0x00FF0000) >> 16);
+	dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
+		 major_ver, minor_ver, fpga_ver);
+
+	card->nr_ports = 2; /* FIXME: Detect daughterboard */
+
+	err = atm_init(card);
+	if (err)
+		goto out_unmap_both;
+
+	pci_set_drvdata(dev, card);
+	tasklet_init(&card->tlet, solos_bh, (unsigned long)card);
+	spin_lock_init(&card->tx_lock);
+	spin_lock_init(&card->tx_queue_lock);
+	spin_lock_init(&card->cli_queue_lock);
+/*
+	// Set Loopback mode
+	data32 = 0x00010000;
+	iowrite32(data32,card->config_regs + FLAGS_ADDR);
+*/
+/*
+	// Fill Buffers with zeros
+	for (i = 0; i < BUF_SIZE * 8; i += 4)
+		iowrite32(0, card->buffers + i);
+*/
+/*
+	for(i = 0; i < (BUF_SIZE * 1); i += 4)
+		iowrite32(0x12345678, card->buffers + i + (0*BUF_SIZE));
+	for(i = 0; i < (BUF_SIZE * 1); i += 4)
+		iowrite32(0xabcdef98, card->buffers + i + (1*BUF_SIZE));
+
+	// Read Config Memory
+	printk(KERN_DEBUG "Reading Config MEM\n");
+	i = 0;
+	for(i = 0; i < 16; i++) {
+		data32=ioread32(card->buffers + i*(BUF_SIZE/2));
+		printk(KERN_ALERT "Addr: %lX Data: %08lX\n",
+		       (unsigned long)(addr_start + i*(BUF_SIZE/2)),
+		       (unsigned long)data32);
+	}
+*/
+	//dev_dbg(&card->dev->dev, "Requesting IRQ: %d\n",dev->irq);
+	err = request_irq(dev->irq, solos_irq, IRQF_DISABLED|IRQF_SHARED,
+			  "solos-pci", card);
+	if (err)
+		dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq);
+
+	// Enable IRQs
+	iowrite32(1, card->config_regs + IRQ_EN_ADDR);
+
+	return 0;
+
+ out_unmap_both:
+	pci_iounmap(dev, card->config_regs);
+ out_unmap_config:
+	pci_iounmap(dev, card->buffers);
+ out_release_regions:
+	pci_release_regions(dev);
+ out:
+	return err;
+}
+
+static int atm_init(struct solos_card *card)
+{
+	int i;
+
+	opens = 0;
+
+	for (i = 0; i < card->nr_ports; i++) {
+		skb_queue_head_init(&card->tx_queue[i]);
+		skb_queue_head_init(&card->cli_queue[i]);
+
+		card->atmdev[i] = atm_dev_register("solos-pci", &fpga_ops, -1, NULL);
+		if (!card->atmdev[i]) {
+			dev_err(&card->dev->dev, "Could not register ATM device %d\n", i);
+			atm_remove(card);
+			return -ENODEV;
+		}
+		if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_console))
+			dev_err(&card->dev->dev, "Could not register console for ATM device %d\n", i);
+
+		dev_info(&card->dev->dev, "Registered ATM device %d\n", card->atmdev[i]->number);
+
+		card->atmdev[i]->ci_range.vpi_bits = 8;
+		card->atmdev[i]->ci_range.vci_bits = 16;
+		card->atmdev[i]->dev_data = card;
+		card->atmdev[i]->phy_data = (void *)(unsigned long)i;
+	}
+	return 0;
+}
+
+static void atm_remove(struct solos_card *card)
+{
+	int i;
+
+	for (i = 0; i < card->nr_ports; i++) {
+		if (card->atmdev[i]) {
+			dev_info(&card->dev->dev, "Unregistering ATM device %d\n", card->atmdev[i]->number);
+			atm_dev_deregister(card->atmdev[i]);
+		}
+	}
+}
+
+static void fpga_remove(struct pci_dev *dev)
+{
+	struct solos_card *card = pci_get_drvdata(dev);
+
+	if (debug)
+		return;
+
+	atm_remove(card);
+
+	dev_vdbg(&dev->dev, "Freeing IRQ\n");
+	// Disable IRQs from FPGA
+	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
+	free_irq(dev->irq, card);
+	tasklet_kill(&card->tlet);
+
+	//	iowrite32(0x01,pciregs);
+	dev_vdbg(&dev->dev, "Unmapping PCI resource\n");
+	pci_iounmap(dev, card->buffers);
+	pci_iounmap(dev, card->config_regs);
+
+	dev_vdbg(&dev->dev, "Releasing PCI Region\n");
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+
+	pci_set_drvdata(dev, NULL);
+	kfree(card);
+//	dev_dbg(&card->dev->dev, "fpga_remove\n");
+	return;
+}
+
+static struct pci_device_id fpga_pci_tbl[] __devinitdata = {
+	{ 0x10ee, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci,fpga_pci_tbl);
+
+static struct pci_driver fpga_driver = {
+	.name =		"solos",
+	.id_table =	fpga_pci_tbl,
+	.probe =	fpga_probe,
+	.remove =	fpga_remove,
+};
+
+
+static int __init solos_pci_init(void)
+{
+	printk(KERN_INFO "Solos PCI Driver Version %s\n", VERSION);
+	return pci_register_driver(&fpga_driver);
+}
+
+static void __exit solos_pci_exit(void)
+{
+	pci_unregister_driver(&fpga_driver);
+	printk(KERN_INFO "Solos PCI Driver %s Unloaded\n", VERSION);
+}
+
+module_init(solos_pci_init);
+module_exit(solos_pci_exit);
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index 93f3690..c237527 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -200,4 +200,3 @@
 int is_aoe_netif(struct net_device *ifp);
 int set_aoe_iflist(const char __user *str, size_t size);
 
-unsigned long long mac_addr(char addr[6]);
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 1747dd2..2307a27 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -37,7 +37,7 @@
 
 	if (t == NULL)
 		return snprintf(page, PAGE_SIZE, "none\n");
-	return snprintf(page, PAGE_SIZE, "%012llx\n", mac_addr(t->addr));
+	return snprintf(page, PAGE_SIZE, "%pm\n", t->addr);
 }
 static ssize_t aoedisk_show_netif(struct device *dev,
 				  struct device_attribute *attr, char *page)
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 71ff78c9..45c5a33 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -349,11 +349,9 @@
 	ah = (struct aoe_atahdr *) (h+1);
 
 	snprintf(buf, sizeof buf,
-		"%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x "
-		"s=%012llx d=%012llx nout=%d\n",
+		"%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x s=%pm d=%pm nout=%d\n",
 		"retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n,
-		mac_addr(h->src),
-		mac_addr(h->dst), t->nout);
+		h->src, h->dst, t->nout);
 	aoechr_error(buf);
 
 	f->tag = n;
@@ -544,10 +542,10 @@
 				printk(KERN_INFO
 					"aoe: e%ld.%d: "
 					"too many lost jumbo on "
-					"%s:%012llx - "
+					"%s:%pm - "
 					"falling back to %d frames.\n",
 					d->aoemajor, d->aoeminor,
-					ifp->nd->name, mac_addr(t->addr),
+					ifp->nd->name, t->addr,
 					DEFAULTBCNT);
 				ifp->maxbcnt = 0;
 			}
@@ -672,8 +670,8 @@
 
 	if (d->ssize != ssize)
 		printk(KERN_INFO
-			"aoe: %012llx e%ld.%d v%04x has %llu sectors\n",
-			mac_addr(t->addr),
+			"aoe: %pm e%ld.%d v%04x has %llu sectors\n",
+			t->addr,
 			d->aoemajor, d->aoeminor,
 			d->fw_ver, (long long)ssize);
 	d->ssize = ssize;
@@ -775,8 +773,8 @@
 	n = get_unaligned_be32(&hin->tag);
 	t = gettgt(d, hin->src);
 	if (t == NULL) {
-		printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n",
-			d->aoemajor, d->aoeminor, mac_addr(hin->src));
+		printk(KERN_INFO "aoe: can't find target e%ld.%d:%pm\n",
+			d->aoemajor, d->aoeminor, hin->src);
 		spin_unlock_irqrestore(&d->lock, flags);
 		return;
 	}
@@ -1036,10 +1034,10 @@
 		n = n ? n * 512 : DEFAULTBCNT;
 		if (n != ifp->maxbcnt) {
 			printk(KERN_INFO
-				"aoe: e%ld.%d: setting %d%s%s:%012llx\n",
+				"aoe: e%ld.%d: setting %d%s%s:%pm\n",
 				d->aoemajor, d->aoeminor, n,
 				" byte data frames on ", ifp->nd->name,
-				mac_addr(t->addr));
+				t->addr);
 			ifp->maxbcnt = n;
 		}
 	}
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index 9157d64..30de5b1 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -83,17 +83,6 @@
 	return 0;
 }
 
-unsigned long long
-mac_addr(char addr[6])
-{
-	__be64 n = 0;
-	char *p = (char *) &n;
-
-	memcpy(p + 2, addr, 6);	/* (sizeof addr != 6) */
-
-	return (unsigned long long) __be64_to_cpu(n);
-}
-
 void
 aoenet_xmit(struct sk_buff_head *queue)
 {
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 5c4ee70..fb06ed6 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -936,8 +936,10 @@
 {
 	int err;
 	struct loop_func_table *xfer;
+	uid_t uid = current_uid();
 
-	if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid &&
+	if (lo->lo_encrypt_key_size &&
+	    lo->lo_key_owner != uid &&
 	    !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	if (lo->lo_state != Lo_bound)
@@ -992,7 +994,7 @@
 	if (info->lo_encrypt_key_size) {
 		memcpy(lo->lo_encrypt_key, info->lo_encrypt_key,
 		       info->lo_encrypt_key_size);
-		lo->lo_key_owner = current->uid;
+		lo->lo_key_owner = uid;
 	}	
 
 	return 0;
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 7cb4029..1164837 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -2,26 +2,6 @@
 menu "Bluetooth device drivers"
 	depends on BT
 
-config BT_HCIUSB
-	tristate "HCI USB driver (old version)"
-	depends on USB && BT_HCIBTUSB=n
-	help
-	  Bluetooth HCI USB driver.
-	  This driver is required if you want to use Bluetooth devices with
-	  USB interface.
-
-	  Say Y here to compile support for Bluetooth USB devices into the
-	  kernel or say M to compile it as module (hci_usb).
-
-config BT_HCIUSB_SCO
-	bool "SCO (voice) support"
-	depends on BT_HCIUSB
-	help
-	  This option enables the SCO support in the HCI USB driver. You need this
-	  to transmit voice data with your Bluetooth USB device.
-
-	  Say Y here to compile support for SCO over HCI USB.
-
 config BT_HCIBTUSB
 	tristate "HCI USB driver"
 	depends on USB
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 77444af..16930f9 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -2,7 +2,6 @@
 # Makefile for the Linux Bluetooth HCI device drivers.
 #
 
-obj-$(CONFIG_BT_HCIUSB)		+= hci_usb.o
 obj-$(CONFIG_BT_HCIVHCI)	+= hci_vhci.o
 obj-$(CONFIG_BT_HCIUART)	+= hci_uart.o
 obj-$(CONFIG_BT_HCIBCM203X)	+= bcm203x.o
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index ee40201..eafd4af 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -37,11 +37,6 @@
 
 #include <net/bluetooth/bluetooth.h>
 
-#ifndef CONFIG_BT_HCIBCM203X_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define VERSION "1.2"
 
 static struct usb_device_id bcm203x_table[] = {
@@ -199,7 +194,7 @@
 		return -EIO;
 	}
 
-	BT_DBG("minidrv data %p size %d", firmware->data, firmware->size);
+	BT_DBG("minidrv data %p size %zu", firmware->data, firmware->size);
 
 	size = max_t(uint, firmware->size, 4096);
 
@@ -227,7 +222,7 @@
 		return -EIO;
 	}
 
-	BT_DBG("firmware data %p size %d", firmware->data, firmware->size);
+	BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
 
 	data->fw_data = kmalloc(firmware->size, GFP_KERNEL);
 	if (!data->fw_data) {
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 90a0946..d3f14be 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -38,11 +38,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef CONFIG_BT_HCIBFUSB_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define VERSION "1.2"
 
 static struct usb_driver bfusb_driver;
@@ -221,7 +216,7 @@
 	struct sk_buff *skb;
 	int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
 
-	BT_DBG("bfusb %p urb %p", bfusb, urb);
+	BT_DBG("bfusb %p urb %p", data, urb);
 
 	if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
 		return -ENOMEM;
@@ -354,7 +349,7 @@
 	int count = urb->actual_length;
 	int err, hdr, len;
 
-	BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
+	BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len);
 
 	read_lock(&data->lock);
 
@@ -691,7 +686,7 @@
 		goto error;
 	}
 
-	BT_DBG("firmware data %p size %d", firmware->data, firmware->size);
+	BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
 
 	if (bfusb_load_firmware(data, firmware->data, firmware->size) < 0) {
 		BT_ERR("Firmware loading failed");
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index b936d8c..c115285 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -35,11 +35,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef CONFIG_BT_HCIBPA10X_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define VERSION "0.10"
 
 static struct usb_device_id bpa10x_table[] = {
@@ -489,6 +484,8 @@
 
 	hdev->owner = THIS_MODULE;
 
+	set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+
 	err = hci_register_dev(hdev);
 	if (err < 0) {
 		hci_free_dev(hdev);
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index b3e4d07..ff195c2 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -502,15 +502,15 @@
 
 		memset(b, 0, sizeof(b));
 		memcpy(b, ptr + 2, 2);
-		size = simple_strtol(b, NULL, 16);
+		size = simple_strtoul(b, NULL, 16);
 
 		memset(b, 0, sizeof(b));
 		memcpy(b, ptr + 4, 8);
-		addr = simple_strtol(b, NULL, 16);
+		addr = simple_strtoul(b, NULL, 16);
 
 		memset(b, 0, sizeof(b));
 		memcpy(b, ptr + (size * 2) + 2, 2);
-		fcs = simple_strtol(b, NULL, 16);
+		fcs = simple_strtoul(b, NULL, 16);
 
 		memset(b, 0, sizeof(b));
 		for (tmp = 0, i = 0; i < size; i++) {
@@ -530,7 +530,7 @@
 			memset(b, 0, sizeof(b));
 			for (i = 0; i < (size - 4) / 2; i++) {
 				memcpy(b, ptr + (i * 4) + 12, 4);
-				tmp = simple_strtol(b, NULL, 16);
+				tmp = simple_strtoul(b, NULL, 16);
 				bt3c_put(iobase, tmp);
 			}
 		}
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
index cda6c7c..7e29827 100644
--- a/drivers/bluetooth/btsdio.c
+++ b/drivers/bluetooth/btsdio.c
@@ -37,11 +37,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef CONFIG_BT_HCIBTSDIO_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define VERSION "0.1"
 
 static const struct sdio_device_id btsdio_table[] = {
@@ -91,6 +86,7 @@
 
 	err = sdio_writesb(data->func, REG_TDAT, skb->data, skb->len);
 	if (err < 0) {
+		skb_pull(skb, 4);
 		sdio_writeb(data->func, 0x01, REG_PC_WRT, NULL);
 		return err;
 	}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index af472e0..b5fbda6 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -35,31 +35,25 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-//#define CONFIG_BT_HCIBTUSB_DEBUG
-#ifndef CONFIG_BT_HCIBTUSB_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
-#define VERSION "0.3"
+#define VERSION "0.4"
 
 static int ignore_dga;
 static int ignore_csr;
 static int ignore_sniffer;
 static int disable_scofix;
 static int force_scofix;
-static int reset;
+
+static int reset = 1;
 
 static struct usb_driver btusb_driver;
 
 #define BTUSB_IGNORE		0x01
-#define BTUSB_RESET		0x02
-#define BTUSB_DIGIANSWER	0x04
-#define BTUSB_CSR		0x08
-#define BTUSB_SNIFFER		0x10
-#define BTUSB_BCM92035		0x20
-#define BTUSB_BROKEN_ISOC	0x40
-#define BTUSB_WRONG_SCO_MTU	0x80
+#define BTUSB_DIGIANSWER	0x02
+#define BTUSB_CSR		0x04
+#define BTUSB_SNIFFER		0x08
+#define BTUSB_BCM92035		0x10
+#define BTUSB_BROKEN_ISOC	0x20
+#define BTUSB_WRONG_SCO_MTU	0x40
 
 static struct usb_device_id btusb_table[] = {
 	/* Generic Bluetooth USB device */
@@ -79,7 +73,7 @@
 	{ USB_DEVICE(0x0bdb, 0x1002) },
 
 	/* Canyon CN-BTU1 with HID interfaces */
-	{ USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_RESET },
+	{ USB_DEVICE(0x0c10, 0x0000) },
 
 	{ }	/* Terminating entry */
 };
@@ -94,52 +88,37 @@
 	{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
 
 	/* Broadcom BCM2035 */
-	{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
 
 	/* Broadcom BCM2045 */
-	{ USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-
-	/* Broadcom BCM2046 */
-	{ USB_DEVICE(0x0a5c, 0x2146), .driver_info = BTUSB_RESET },
-	{ USB_DEVICE(0x0a5c, 0x2151), .driver_info = BTUSB_RESET },
-
-	/* Apple MacBook Pro with Broadcom chip */
-	{ USB_DEVICE(0x05ac, 0x820f), .driver_info = BTUSB_RESET },
+	{ USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_WRONG_SCO_MTU },
 
 	/* IBM/Lenovo ThinkPad with Broadcom chip */
-	{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-
-	/* Targus ACB10US */
-	{ USB_DEVICE(0x0a5c, 0x2100), .driver_info = BTUSB_RESET },
-	{ USB_DEVICE(0x0a5c, 0x2154), .driver_info = BTUSB_RESET },
-
-	/* ANYCOM Bluetooth USB-200 and USB-250 */
-	{ USB_DEVICE(0x0a5c, 0x2111), .driver_info = BTUSB_RESET },
+	{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_WRONG_SCO_MTU },
 
 	/* HP laptop with Broadcom chip */
-	{ USB_DEVICE(0x03f0, 0x171d), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x03f0, 0x171d), .driver_info = BTUSB_WRONG_SCO_MTU },
 
 	/* Dell laptop with Broadcom chip */
-	{ USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_WRONG_SCO_MTU },
 
-	/* Dell Wireless 370 */
-	{ USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
+	/* Dell Wireless 370 and 410 devices */
+	{ USB_DEVICE(0x413c, 0x8152), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_WRONG_SCO_MTU },
 
-	/* Dell Wireless 410 */
-	{ USB_DEVICE(0x413c, 0x8152), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
+	/* Belkin F8T012 and F8T013 devices */
+	{ USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_WRONG_SCO_MTU },
 
-	/* Microsoft Wireless Transceiver for Bluetooth 2.0 */
-	{ USB_DEVICE(0x045e, 0x009c), .driver_info = BTUSB_RESET },
+	/* Asus WL-BTD202 device */
+	{ USB_DEVICE(0x0b05, 0x1715), .driver_info = BTUSB_WRONG_SCO_MTU },
 
 	/* Kensington Bluetooth USB adapter */
-	{ USB_DEVICE(0x047d, 0x105d), .driver_info = BTUSB_RESET },
-	{ USB_DEVICE(0x047d, 0x105e), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-
-	/* ISSC Bluetooth Adapter v3.1 */
-	{ USB_DEVICE(0x1131, 0x1001), .driver_info = BTUSB_RESET },
+	{ USB_DEVICE(0x047d, 0x105e), .driver_info = BTUSB_WRONG_SCO_MTU },
 
 	/* RTX Telecom based adapters with buggy SCO support */
 	{ USB_DEVICE(0x0400, 0x0807), .driver_info = BTUSB_BROKEN_ISOC },
@@ -148,13 +127,6 @@
 	/* CONWISE Technology based adapters with buggy SCO support */
 	{ USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC },
 
-	/* Belkin F8T012 and F8T013 devices */
-	{ USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-
-	/* Belkin F8T016 device */
-	{ USB_DEVICE(0x050d, 0x016a), .driver_info = BTUSB_RESET },
-
 	/* Digianswer devices */
 	{ USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
 	{ USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },
@@ -197,7 +169,10 @@
 	struct usb_endpoint_descriptor *isoc_tx_ep;
 	struct usb_endpoint_descriptor *isoc_rx_ep;
 
+	__u8 cmdreq_type;
+
 	int isoc_altsetting;
+	int suspend_count;
 };
 
 static void btusb_intr_complete(struct urb *urb)
@@ -236,7 +211,7 @@
 	}
 }
 
-static int btusb_submit_intr_urb(struct hci_dev *hdev)
+static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
 {
 	struct btusb_data *data = hdev->driver_data;
 	struct urb *urb;
@@ -249,13 +224,13 @@
 	if (!data->intr_ep)
 		return -ENODEV;
 
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	urb = usb_alloc_urb(0, mem_flags);
 	if (!urb)
 		return -ENOMEM;
 
 	size = le16_to_cpu(data->intr_ep->wMaxPacketSize);
 
-	buf = kmalloc(size, GFP_ATOMIC);
+	buf = kmalloc(size, mem_flags);
 	if (!buf) {
 		usb_free_urb(urb);
 		return -ENOMEM;
@@ -271,7 +246,7 @@
 
 	usb_anchor_urb(urb, &data->intr_anchor);
 
-	err = usb_submit_urb(urb, GFP_ATOMIC);
+	err = usb_submit_urb(urb, mem_flags);
 	if (err < 0) {
 		BT_ERR("%s urb %p submission failed (%d)",
 						hdev->name, urb, -err);
@@ -319,7 +294,7 @@
 	}
 }
 
-static int btusb_submit_bulk_urb(struct hci_dev *hdev)
+static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
 {
 	struct btusb_data *data = hdev->driver_data;
 	struct urb *urb;
@@ -332,13 +307,13 @@
 	if (!data->bulk_rx_ep)
 		return -ENODEV;
 
-	urb = usb_alloc_urb(0, GFP_KERNEL);
+	urb = usb_alloc_urb(0, mem_flags);
 	if (!urb)
 		return -ENOMEM;
 
 	size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize);
 
-	buf = kmalloc(size, GFP_KERNEL);
+	buf = kmalloc(size, mem_flags);
 	if (!buf) {
 		usb_free_urb(urb);
 		return -ENOMEM;
@@ -353,7 +328,7 @@
 
 	usb_anchor_urb(urb, &data->bulk_anchor);
 
-	err = usb_submit_urb(urb, GFP_KERNEL);
+	err = usb_submit_urb(urb, mem_flags);
 	if (err < 0) {
 		BT_ERR("%s urb %p submission failed (%d)",
 						hdev->name, urb, -err);
@@ -430,7 +405,7 @@
 	urb->number_of_packets = i;
 }
 
-static int btusb_submit_isoc_urb(struct hci_dev *hdev)
+static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
 {
 	struct btusb_data *data = hdev->driver_data;
 	struct urb *urb;
@@ -443,14 +418,14 @@
 	if (!data->isoc_rx_ep)
 		return -ENODEV;
 
-	urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL);
+	urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, mem_flags);
 	if (!urb)
 		return -ENOMEM;
 
 	size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) *
 						BTUSB_MAX_ISOC_FRAMES;
 
-	buf = kmalloc(size, GFP_KERNEL);
+	buf = kmalloc(size, mem_flags);
 	if (!buf) {
 		usb_free_urb(urb);
 		return -ENOMEM;
@@ -473,7 +448,7 @@
 
 	usb_anchor_urb(urb, &data->isoc_anchor);
 
-	err = usb_submit_urb(urb, GFP_KERNEL);
+	err = usb_submit_urb(urb, mem_flags);
 	if (err < 0) {
 		BT_ERR("%s urb %p submission failed (%d)",
 						hdev->name, urb, -err);
@@ -520,7 +495,7 @@
 	if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
 		return 0;
 
-	err = btusb_submit_intr_urb(hdev);
+	err = btusb_submit_intr_urb(hdev, GFP_KERNEL);
 	if (err < 0) {
 		clear_bit(BTUSB_INTR_RUNNING, &data->flags);
 		clear_bit(HCI_RUNNING, &hdev->flags);
@@ -589,7 +564,7 @@
 			return -ENOMEM;
 		}
 
-		dr->bRequestType = USB_TYPE_CLASS;
+		dr->bRequestType = data->cmdreq_type;
 		dr->bRequest     = 0;
 		dr->wIndex       = 0;
 		dr->wValue       = 0;
@@ -680,8 +655,19 @@
 
 	BT_DBG("%s evt %d", hdev->name, evt);
 
-	if (evt == HCI_NOTIFY_CONN_ADD || evt == HCI_NOTIFY_CONN_DEL)
-		schedule_work(&data->work);
+	if (hdev->conn_hash.acl_num > 0) {
+		if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) {
+			if (btusb_submit_bulk_urb(hdev, GFP_ATOMIC) < 0)
+				clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+			else
+				btusb_submit_bulk_urb(hdev, GFP_ATOMIC);
+		}
+	} else {
+		clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+		usb_unlink_anchored_urbs(&data->bulk_anchor);
+	}
+
+	schedule_work(&data->work);
 }
 
 static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting)
@@ -732,18 +718,6 @@
 	struct btusb_data *data = container_of(work, struct btusb_data, work);
 	struct hci_dev *hdev = data->hdev;
 
-	if (hdev->conn_hash.acl_num > 0) {
-		if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) {
-			if (btusb_submit_bulk_urb(hdev) < 0)
-				clear_bit(BTUSB_BULK_RUNNING, &data->flags);
-			else
-				btusb_submit_bulk_urb(hdev);
-		}
-	} else {
-		clear_bit(BTUSB_BULK_RUNNING, &data->flags);
-		usb_kill_anchored_urbs(&data->bulk_anchor);
-	}
-
 	if (hdev->conn_hash.sco_num > 0) {
 		if (data->isoc_altsetting != 2) {
 			clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
@@ -754,10 +728,10 @@
 		}
 
 		if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
-			if (btusb_submit_isoc_urb(hdev) < 0)
+			if (btusb_submit_isoc_urb(hdev, GFP_KERNEL) < 0)
 				clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
 			else
-				btusb_submit_isoc_urb(hdev);
+				btusb_submit_isoc_urb(hdev, GFP_KERNEL);
 		}
 	} else {
 		clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
@@ -828,6 +802,8 @@
 		return -ENODEV;
 	}
 
+	data->cmdreq_type = USB_TYPE_CLASS;
+
 	data->udev = interface_to_usbdev(intf);
 	data->intf = intf;
 
@@ -862,11 +838,11 @@
 
 	hdev->owner = THIS_MODULE;
 
-	/* interface numbers are hardcoded in the spec */
+	/* Interface numbers are hardcoded in the specification */
 	data->isoc = usb_ifnum_to_if(data->udev, 1);
 
-	if (reset || id->driver_info & BTUSB_RESET)
-		set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
+	if (!reset)
+		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
 
 	if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) {
 		if (!disable_scofix)
@@ -876,9 +852,23 @@
 	if (id->driver_info & BTUSB_BROKEN_ISOC)
 		data->isoc = NULL;
 
+	if (id->driver_info & BTUSB_DIGIANSWER) {
+		data->cmdreq_type = USB_TYPE_VENDOR;
+		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+	}
+
+	if (id->driver_info & BTUSB_CSR) {
+		struct usb_device *udev = data->udev;
+
+		/* Old firmware would otherwise execute USB reset */
+		if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117)
+			set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+	}
+
 	if (id->driver_info & BTUSB_SNIFFER) {
 		struct usb_device *udev = data->udev;
 
+		/* New sniffer firmware has crippled HCI interface */
 		if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997)
 			set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
 
@@ -949,10 +939,71 @@
 	hci_free_dev(hdev);
 }
 
+static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct btusb_data *data = usb_get_intfdata(intf);
+
+	BT_DBG("intf %p", intf);
+
+	if (data->suspend_count++)
+		return 0;
+
+	cancel_work_sync(&data->work);
+
+	usb_kill_anchored_urbs(&data->tx_anchor);
+
+	usb_kill_anchored_urbs(&data->isoc_anchor);
+	usb_kill_anchored_urbs(&data->bulk_anchor);
+	usb_kill_anchored_urbs(&data->intr_anchor);
+
+	return 0;
+}
+
+static int btusb_resume(struct usb_interface *intf)
+{
+	struct btusb_data *data = usb_get_intfdata(intf);
+	struct hci_dev *hdev = data->hdev;
+	int err;
+
+	BT_DBG("intf %p", intf);
+
+	if (--data->suspend_count)
+		return 0;
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
+
+	if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) {
+		err = btusb_submit_intr_urb(hdev, GFP_NOIO);
+		if (err < 0) {
+			clear_bit(BTUSB_INTR_RUNNING, &data->flags);
+			return err;
+		}
+	}
+
+	if (test_bit(BTUSB_BULK_RUNNING, &data->flags)) {
+		if (btusb_submit_bulk_urb(hdev, GFP_NOIO) < 0)
+			clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+		else
+			btusb_submit_bulk_urb(hdev, GFP_NOIO);
+	}
+
+	if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
+		if (btusb_submit_isoc_urb(hdev, GFP_NOIO) < 0)
+			clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
+		else
+			btusb_submit_isoc_urb(hdev, GFP_NOIO);
+	}
+
+	return 0;
+}
+
 static struct usb_driver btusb_driver = {
 	.name		= "btusb",
 	.probe		= btusb_probe,
 	.disconnect	= btusb_disconnect,
+	.suspend	= btusb_suspend,
+	.resume		= btusb_resume,
 	.id_table	= btusb_table,
 };
 
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 7938062..894b2cb 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -47,11 +47,6 @@
 
 #include "hci_uart.h"
 
-#ifndef CONFIG_BT_HCIUART_DEBUG
-#undef  BT_DBG
-#define BT_DBG( A... )
-#endif
-
 #define VERSION "0.3"
 
 static int txcrc = 1;
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index bfbae14..b0fafb0 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -46,11 +46,6 @@
 
 #include "hci_uart.h"
 
-#ifndef CONFIG_BT_HCIUART_DEBUG
-#undef  BT_DBG
-#define BT_DBG( A... )
-#endif
-
 #define VERSION "1.2"
 
 struct h4_struct {
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 4426bb5..af761dc 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -46,11 +46,6 @@
 
 #include "hci_uart.h"
 
-#ifndef CONFIG_BT_HCIUART_DEBUG
-#undef  BT_DBG
-#define BT_DBG( A... )
-#endif
-
 #define VERSION "2.2"
 
 static int reset = 0;
@@ -399,8 +394,8 @@
 
 	hdev->owner = THIS_MODULE;
 
-	if (reset)
-		set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
+	if (!reset)
+		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
 
 	if (hci_register_dev(hdev) < 0) {
 		BT_ERR("Can't register HCI device");
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
deleted file mode 100644
index 3c45392..0000000
--- a/drivers/bluetooth/hci_usb.c
+++ /dev/null
@@ -1,1136 +0,0 @@
-/* 
-   HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.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;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * Bluetooth HCI USB driver.
- * Based on original USB Bluetooth driver for Linux kernel
- *    Copyright (c) 2000 Greg Kroah-Hartman        <greg@kroah.com>
- *    Copyright (c) 2000 Mark Douglas Corner       <mcorner@umich.edu>
- *
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/unistd.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/skbuff.h>
-
-#include <linux/usb.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-#include "hci_usb.h"
-
-#ifndef CONFIG_BT_HCIUSB_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
-#ifndef CONFIG_BT_HCIUSB_ZERO_PACKET
-#undef  URB_ZERO_PACKET
-#define URB_ZERO_PACKET 0
-#endif
-
-static int ignore_dga;
-static int ignore_csr;
-static int ignore_sniffer;
-static int disable_scofix;
-static int force_scofix;
-static int reset;
-
-#ifdef CONFIG_BT_HCIUSB_SCO
-static int isoc = 2;
-#endif
-
-#define VERSION "2.10"
-
-static struct usb_driver hci_usb_driver; 
-
-static struct usb_device_id bluetooth_ids[] = {
-	/* Generic Bluetooth USB device */
-	{ USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
-
-	/* AVM BlueFRITZ! USB v2.0 */
-	{ USB_DEVICE(0x057c, 0x3800) },
-
-	/* Bluetooth Ultraport Module from IBM */
-	{ USB_DEVICE(0x04bf, 0x030a) },
-
-	/* ALPS Modules with non-standard id */
-	{ USB_DEVICE(0x044e, 0x3001) },
-	{ USB_DEVICE(0x044e, 0x3002) },
-
-	/* Ericsson with non-standard id */
-	{ USB_DEVICE(0x0bdb, 0x1002) },
-
-	/* Canyon CN-BTU1 with HID interfaces */
-	{ USB_DEVICE(0x0c10, 0x0000), .driver_info = HCI_RESET },
-
-	{ }	/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, bluetooth_ids);
-
-static struct usb_device_id blacklist_ids[] = {
-	/* CSR BlueCore devices */
-	{ USB_DEVICE(0x0a12, 0x0001), .driver_info = HCI_CSR },
-
-	/* Broadcom BCM2033 without firmware */
-	{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
-
-	/* Broadcom BCM2035 */
-	{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 },
-
-	/* Broadcom BCM2045 */
-	{ USB_DEVICE(0x0a5c, 0x2039), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-
-	/* IBM/Lenovo ThinkPad with Broadcom chip */
-	{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-
-	/* Targus ACB10US */
-	{ USB_DEVICE(0x0a5c, 0x2100), .driver_info = HCI_RESET },
-
-	/* ANYCOM Bluetooth USB-200 and USB-250 */
-	{ USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET },
-
-	/* HP laptop with Broadcom chip */
-	{ USB_DEVICE(0x03f0, 0x171d), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-
-	/* Dell laptop with Broadcom chip */
-	{ USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-	/* Dell Wireless 370 */
-	{ USB_DEVICE(0x413c, 0x8156), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-	/* Dell Wireless 410 */
-	{ USB_DEVICE(0x413c, 0x8152), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-
-	/* Broadcom 2046 */
-	{ USB_DEVICE(0x0a5c, 0x2151), .driver_info = HCI_RESET },
-
-	/* Microsoft Wireless Transceiver for Bluetooth 2.0 */
-	{ USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET },
-
-	/* Kensington Bluetooth USB adapter */
-	{ USB_DEVICE(0x047d, 0x105d), .driver_info = HCI_RESET },
-	{ USB_DEVICE(0x047d, 0x105e), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-
-	/* ISSC Bluetooth Adapter v3.1 */
-	{ USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET },
-
-	/* RTX Telecom based adapters with buggy SCO support */
-	{ USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC },
-	{ USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC },
-
-	/* CONWISE Technology based adapters with buggy SCO support */
-	{ USB_DEVICE(0x0e5e, 0x6622), .driver_info = HCI_BROKEN_ISOC },
-
-	/* Belkin F8T012 and F8T013 devices */
-	{ USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
-
-	/* Digianswer devices */
-	{ USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER },
-	{ USB_DEVICE(0x08fd, 0x0002), .driver_info = HCI_IGNORE },
-
-	/* CSR BlueCore Bluetooth Sniffer */
-	{ USB_DEVICE(0x0a12, 0x0002), .driver_info = HCI_SNIFFER },
-
-	/* Frontline ComProbe Bluetooth Sniffer */
-	{ USB_DEVICE(0x16d3, 0x0002), .driver_info = HCI_SNIFFER },
-
-	{ }	/* Terminating entry */
-};
-
-static struct _urb *_urb_alloc(int isoc, gfp_t gfp)
-{
-	struct _urb *_urb = kmalloc(sizeof(struct _urb) +
-				sizeof(struct usb_iso_packet_descriptor) * isoc, gfp);
-	if (_urb) {
-		memset(_urb, 0, sizeof(*_urb));
-		usb_init_urb(&_urb->urb);
-	}
-	return _urb;
-}
-
-static struct _urb *_urb_dequeue(struct _urb_queue *q)
-{
-	struct _urb *_urb = NULL;
-	unsigned long flags;
-	spin_lock_irqsave(&q->lock, flags);
-	{
-		struct list_head *head = &q->head;
-		struct list_head *next = head->next;
-		if (next != head) {
-			_urb = list_entry(next, struct _urb, list);
-			list_del(next); _urb->queue = NULL;
-		}
-	}
-	spin_unlock_irqrestore(&q->lock, flags);
-	return _urb;
-}
-
-static void hci_usb_rx_complete(struct urb *urb);
-static void hci_usb_tx_complete(struct urb *urb);
-
-#define __pending_tx(husb, type)  (&husb->pending_tx[type-1])
-#define __pending_q(husb, type)   (&husb->pending_q[type-1])
-#define __completed_q(husb, type) (&husb->completed_q[type-1])
-#define __transmit_q(husb, type)  (&husb->transmit_q[type-1])
-
-static inline struct _urb *__get_completed(struct hci_usb *husb, int type)
-{
-	return _urb_dequeue(__completed_q(husb, type)); 
-}
-
-#ifdef CONFIG_BT_HCIUSB_SCO
-static void __fill_isoc_desc(struct urb *urb, int len, int mtu)
-{
-	int offset = 0, i;
-
-	BT_DBG("len %d mtu %d", len, mtu);
-
-	for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) {
-		urb->iso_frame_desc[i].offset = offset;
-		urb->iso_frame_desc[i].length = mtu;
-		BT_DBG("desc %d offset %d len %d", i, offset, mtu);
-	}
-	if (len && i < HCI_MAX_ISOC_FRAMES) {
-		urb->iso_frame_desc[i].offset = offset;
-		urb->iso_frame_desc[i].length = len;
-		BT_DBG("desc %d offset %d len %d", i, offset, len);
-		i++;
-	}
-	urb->number_of_packets = i;
-}
-#endif
-
-static int hci_usb_intr_rx_submit(struct hci_usb *husb)
-{
-	struct _urb *_urb;
-	struct urb *urb;
-	int err, pipe, interval, size;
-	void *buf;
-
-	BT_DBG("%s", husb->hdev->name);
-
-	size = le16_to_cpu(husb->intr_in_ep->desc.wMaxPacketSize);
-
-	buf = kmalloc(size, GFP_ATOMIC);
-	if (!buf)
-		return -ENOMEM;
-
-	_urb = _urb_alloc(0, GFP_ATOMIC);
-	if (!_urb) {
-		kfree(buf);
-		return -ENOMEM;
-	}
-	_urb->type = HCI_EVENT_PKT;
-	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-
-	urb = &_urb->urb;
-	pipe     = usb_rcvintpipe(husb->udev, husb->intr_in_ep->desc.bEndpointAddress);
-	interval = husb->intr_in_ep->desc.bInterval;
-	usb_fill_int_urb(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval);
-	
-	err = usb_submit_urb(urb, GFP_ATOMIC);
-	if (err) {
-		BT_ERR("%s intr rx submit failed urb %p err %d",
-				husb->hdev->name, urb, err);
-		_urb_unlink(_urb);
-		kfree(_urb);
-		kfree(buf);
-	}
-	return err;
-}
-
-static int hci_usb_bulk_rx_submit(struct hci_usb *husb)
-{
-	struct _urb *_urb;
-	struct urb *urb;
-	int err, pipe, size = HCI_MAX_FRAME_SIZE;
-	void *buf;
-
-	buf = kmalloc(size, GFP_ATOMIC);
-	if (!buf)
-		return -ENOMEM;
-
-	_urb = _urb_alloc(0, GFP_ATOMIC);
-	if (!_urb) {
-		kfree(buf);
-		return -ENOMEM;
-	}
-	_urb->type = HCI_ACLDATA_PKT;
-	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-
-	urb  = &_urb->urb;
-	pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->desc.bEndpointAddress);
-	usb_fill_bulk_urb(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb);
-	urb->transfer_flags = 0;
-
-	BT_DBG("%s urb %p", husb->hdev->name, urb);
-
-	err = usb_submit_urb(urb, GFP_ATOMIC);
-	if (err) {
-		BT_ERR("%s bulk rx submit failed urb %p err %d",
-				husb->hdev->name, urb, err);
-		_urb_unlink(_urb);
-		kfree(_urb);
-		kfree(buf);
-	}
-	return err;
-}
-
-#ifdef CONFIG_BT_HCIUSB_SCO
-static int hci_usb_isoc_rx_submit(struct hci_usb *husb)
-{
-	struct _urb *_urb;
-	struct urb *urb;
-	int err, mtu, size;
-	void *buf;
-
-	mtu  = le16_to_cpu(husb->isoc_in_ep->desc.wMaxPacketSize);
-	size = mtu * HCI_MAX_ISOC_FRAMES;
-
-	buf = kmalloc(size, GFP_ATOMIC);
-	if (!buf)
-		return -ENOMEM;
-
-	_urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
-	if (!_urb) {
-		kfree(buf);
-		return -ENOMEM;
-	}
-	_urb->type = HCI_SCODATA_PKT;
-	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-
-	urb = &_urb->urb;
-
-	urb->context  = husb;
-	urb->dev      = husb->udev;
-	urb->pipe     = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->desc.bEndpointAddress);
-	urb->complete = hci_usb_rx_complete;
-
-	urb->interval = husb->isoc_in_ep->desc.bInterval;
-
-	urb->transfer_buffer_length = size;
-	urb->transfer_buffer = buf;
-	urb->transfer_flags  = URB_ISO_ASAP;
-
-	__fill_isoc_desc(urb, size, mtu);
-
-	BT_DBG("%s urb %p", husb->hdev->name, urb);
-
-	err = usb_submit_urb(urb, GFP_ATOMIC);
-	if (err) {
-		BT_ERR("%s isoc rx submit failed urb %p err %d",
-				husb->hdev->name, urb, err);
-		_urb_unlink(_urb);
-		kfree(_urb);
-		kfree(buf);
-	}
-	return err;
-}
-#endif
-
-/* Initialize device */
-static int hci_usb_open(struct hci_dev *hdev)
-{
-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-	int i, err;
-	unsigned long flags;
-
-	BT_DBG("%s", hdev->name);
-
-	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
-		return 0;
-
-	write_lock_irqsave(&husb->completion_lock, flags);
-
-	err = hci_usb_intr_rx_submit(husb);
-	if (!err) {
-		for (i = 0; i < HCI_MAX_BULK_RX; i++)
-			hci_usb_bulk_rx_submit(husb);
-
-#ifdef CONFIG_BT_HCIUSB_SCO
-		if (husb->isoc_iface)
-			for (i = 0; i < HCI_MAX_ISOC_RX; i++)
-				hci_usb_isoc_rx_submit(husb);
-#endif
-	} else {
-		clear_bit(HCI_RUNNING, &hdev->flags);
-	}
-
-	write_unlock_irqrestore(&husb->completion_lock, flags);
-	return err;
-}
-
-/* Reset device */
-static int hci_usb_flush(struct hci_dev *hdev)
-{
-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-	int i;
-
-	BT_DBG("%s", hdev->name);
-
-	for (i = 0; i < 4; i++)
-		skb_queue_purge(&husb->transmit_q[i]);
-	return 0;
-}
-
-static void hci_usb_unlink_urbs(struct hci_usb *husb)
-{
-	int i;
-
-	BT_DBG("%s", husb->hdev->name);
-
-	for (i = 0; i < 4; i++) {
-		struct _urb *_urb;
-		struct urb *urb;
-
-		/* Kill pending requests */
-		while ((_urb = _urb_dequeue(&husb->pending_q[i]))) {
-			urb = &_urb->urb;
-			BT_DBG("%s unlinking _urb %p type %d urb %p", 
-					husb->hdev->name, _urb, _urb->type, urb);
-			usb_kill_urb(urb);
-			_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-		}
-
-		/* Release completed requests */
-		while ((_urb = _urb_dequeue(&husb->completed_q[i]))) {
-			urb = &_urb->urb;
-			BT_DBG("%s freeing _urb %p type %d urb %p",
-					husb->hdev->name, _urb, _urb->type, urb);
-			kfree(urb->setup_packet);
-			kfree(urb->transfer_buffer);
-			kfree(_urb);
-		}
-	}
-}
-
-/* Close device */
-static int hci_usb_close(struct hci_dev *hdev)
-{
-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-	unsigned long flags;
-
-	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-		return 0;
-
-	BT_DBG("%s", hdev->name);
-
-	/* Synchronize with completion handlers */
-	write_lock_irqsave(&husb->completion_lock, flags);
-	write_unlock_irqrestore(&husb->completion_lock, flags);
-
-	hci_usb_unlink_urbs(husb);
-	hci_usb_flush(hdev);
-	return 0;
-}
-
-static int __tx_submit(struct hci_usb *husb, struct _urb *_urb)
-{
-	struct urb *urb = &_urb->urb;
-	int err;
-
-	BT_DBG("%s urb %p type %d", husb->hdev->name, urb, _urb->type);
-
-	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-	err = usb_submit_urb(urb, GFP_ATOMIC);
-	if (err) {
-		BT_ERR("%s tx submit failed urb %p type %d err %d",
-				husb->hdev->name, urb, _urb->type, err);
-		_urb_unlink(_urb);
-		_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-	} else
-		atomic_inc(__pending_tx(husb, _urb->type));
-
-	return err;
-}
-
-static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
-{
-	struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type);
-	struct usb_ctrlrequest *dr;
-	struct urb *urb;
-
-	if (!_urb) {
-		_urb = _urb_alloc(0, GFP_ATOMIC);
-		if (!_urb)
-			return -ENOMEM;
-		_urb->type = bt_cb(skb)->pkt_type;
-
-		dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
-		if (!dr) {
-			kfree(_urb);
-			return -ENOMEM;
-		}
-	} else
-		dr = (void *) _urb->urb.setup_packet;
-
-	dr->bRequestType = husb->ctrl_req;
-	dr->bRequest = 0;
-	dr->wIndex   = 0;
-	dr->wValue   = 0;
-	dr->wLength  = __cpu_to_le16(skb->len);
-
-	urb = &_urb->urb;
-	usb_fill_control_urb(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0),
-		(void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb);
-
-	BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len);
-	
-	_urb->priv = skb;
-	return __tx_submit(husb, _urb);
-}
-
-static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
-{
-	struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type);
-	struct urb *urb;
-	int pipe;
-
-	if (!_urb) {
-		_urb = _urb_alloc(0, GFP_ATOMIC);
-		if (!_urb)
-			return -ENOMEM;
-		_urb->type = bt_cb(skb)->pkt_type;
-	}
-
-	urb  = &_urb->urb;
-	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->desc.bEndpointAddress);
-	usb_fill_bulk_urb(urb, husb->udev, pipe, skb->data, skb->len, 
-			hci_usb_tx_complete, husb);
-	urb->transfer_flags = URB_ZERO_PACKET;
-
-	BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len);
-
-	_urb->priv = skb;
-	return __tx_submit(husb, _urb);
-}
-
-#ifdef CONFIG_BT_HCIUSB_SCO
-static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
-{
-	struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type);
-	struct urb *urb;
-
-	if (!_urb) {
-		_urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
-		if (!_urb)
-			return -ENOMEM;
-		_urb->type = bt_cb(skb)->pkt_type;
-	}
-
-	BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len);
-
-	urb = &_urb->urb;
-
-	urb->context  = husb;
-	urb->dev      = husb->udev;
-	urb->pipe     = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->desc.bEndpointAddress);
-	urb->complete = hci_usb_tx_complete;
-	urb->transfer_flags = URB_ISO_ASAP;
-
-	urb->interval = husb->isoc_out_ep->desc.bInterval;
-
-	urb->transfer_buffer = skb->data;
-	urb->transfer_buffer_length = skb->len;
-
-	__fill_isoc_desc(urb, skb->len, le16_to_cpu(husb->isoc_out_ep->desc.wMaxPacketSize));
-
-	_urb->priv = skb;
-	return __tx_submit(husb, _urb);
-}
-#endif
-
-static void hci_usb_tx_process(struct hci_usb *husb)
-{
-	struct sk_buff_head *q;
-	struct sk_buff *skb;
-
-	BT_DBG("%s", husb->hdev->name);
-
-	do {
-		clear_bit(HCI_USB_TX_WAKEUP, &husb->state);
-
-		/* Process command queue */
-		q = __transmit_q(husb, HCI_COMMAND_PKT);
-		if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) &&
-				(skb = skb_dequeue(q))) {
-			if (hci_usb_send_ctrl(husb, skb) < 0)
-				skb_queue_head(q, skb);
-		}
-
-#ifdef CONFIG_BT_HCIUSB_SCO
-		/* Process SCO queue */
-		q = __transmit_q(husb, HCI_SCODATA_PKT);
-		if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX &&
-				(skb = skb_dequeue(q))) {
-			if (hci_usb_send_isoc(husb, skb) < 0)
-				skb_queue_head(q, skb);
-		}
-#endif
-
-		/* Process ACL queue */
-		q = __transmit_q(husb, HCI_ACLDATA_PKT);
-		while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX &&
-				(skb = skb_dequeue(q))) {
-			if (hci_usb_send_bulk(husb, skb) < 0) {
-				skb_queue_head(q, skb);
-				break;
-			}
-		}
-	} while(test_bit(HCI_USB_TX_WAKEUP, &husb->state));
-}
-
-static inline void hci_usb_tx_wakeup(struct hci_usb *husb)
-{
-	/* Serialize TX queue processing to avoid data reordering */
-	if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) {
-		hci_usb_tx_process(husb);
-		clear_bit(HCI_USB_TX_PROCESS, &husb->state);
-	} else
-		set_bit(HCI_USB_TX_WAKEUP, &husb->state);
-}
-
-/* Send frames from HCI layer */
-static int hci_usb_send_frame(struct sk_buff *skb)
-{
-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-	struct hci_usb *husb;
-
-	if (!hdev) {
-		BT_ERR("frame for uknown device (hdev=NULL)");
-		return -ENODEV;
-	}
-
-	if (!test_bit(HCI_RUNNING, &hdev->flags))
-		return -EBUSY;
-
-	BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
-
-	husb = (struct hci_usb *) hdev->driver_data;
-
-	switch (bt_cb(skb)->pkt_type) {
-	case HCI_COMMAND_PKT:
-		hdev->stat.cmd_tx++;
-		break;
-
-	case HCI_ACLDATA_PKT:
-		hdev->stat.acl_tx++;
-		break;
-
-#ifdef CONFIG_BT_HCIUSB_SCO
-	case HCI_SCODATA_PKT:
-		hdev->stat.sco_tx++;
-		break;
-#endif
-
-	default:
-		kfree_skb(skb);
-		return 0;
-	}
-
-	read_lock(&husb->completion_lock);
-
-	skb_queue_tail(__transmit_q(husb, bt_cb(skb)->pkt_type), skb);
-	hci_usb_tx_wakeup(husb);
-
-	read_unlock(&husb->completion_lock);
-	return 0;
-}
-
-static void hci_usb_rx_complete(struct urb *urb)
-{
-	struct _urb *_urb = container_of(urb, struct _urb, urb);
-	struct hci_usb *husb = (void *) urb->context;
-	struct hci_dev *hdev = husb->hdev;
-	int err, count = urb->actual_length;
-
-	BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,
-			_urb->type, urb->status, count, urb->transfer_flags);
-
-	read_lock(&husb->completion_lock);
-
-	if (!test_bit(HCI_RUNNING, &hdev->flags))
-		goto unlock;
-
-	if (urb->status || !count)
-		goto resubmit;
-
-	if (_urb->type == HCI_SCODATA_PKT) {
-#ifdef CONFIG_BT_HCIUSB_SCO
-		int i;
-		for (i=0; i < urb->number_of_packets; i++) {
-			BT_DBG("desc %d status %d offset %d len %d", i,
-					urb->iso_frame_desc[i].status,
-					urb->iso_frame_desc[i].offset,
-					urb->iso_frame_desc[i].actual_length);
-	
-			if (!urb->iso_frame_desc[i].status) {
-				husb->hdev->stat.byte_rx += urb->iso_frame_desc[i].actual_length;
-				hci_recv_fragment(husb->hdev, _urb->type, 
-					urb->transfer_buffer + urb->iso_frame_desc[i].offset,
-					urb->iso_frame_desc[i].actual_length);
-			}
-		}
-#else
-		;
-#endif
-	} else {
-		husb->hdev->stat.byte_rx += count;
-		err = hci_recv_fragment(husb->hdev, _urb->type, urb->transfer_buffer, count);
-		if (err < 0) { 
-			BT_ERR("%s corrupted packet: type %d count %d",
-					husb->hdev->name, _urb->type, count);
-			hdev->stat.err_rx++;
-		}
-	}
-
-resubmit:
-	urb->dev = husb->udev;
-	err = usb_submit_urb(urb, GFP_ATOMIC);
-	BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,
-			_urb->type, err);
-
-unlock:
-	read_unlock(&husb->completion_lock);
-}
-
-static void hci_usb_tx_complete(struct urb *urb)
-{
-	struct _urb *_urb = container_of(urb, struct _urb, urb);
-	struct hci_usb *husb = (void *) urb->context;
-	struct hci_dev *hdev = husb->hdev;
-
-	BT_DBG("%s urb %p status %d flags %x", hdev->name, urb,
-			urb->status, urb->transfer_flags);
-
-	atomic_dec(__pending_tx(husb, _urb->type));
-
-	urb->transfer_buffer = NULL;
-	kfree_skb((struct sk_buff *) _urb->priv);
-
-	if (!test_bit(HCI_RUNNING, &hdev->flags))
-		return;
-
-	if (!urb->status)
-		hdev->stat.byte_tx += urb->transfer_buffer_length;
-	else
-		hdev->stat.err_tx++;
-
-	read_lock(&husb->completion_lock);
-
-	_urb_unlink(_urb);
-	_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-
-	hci_usb_tx_wakeup(husb);
-
-	read_unlock(&husb->completion_lock);
-}
-
-static void hci_usb_destruct(struct hci_dev *hdev)
-{
-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-
-	BT_DBG("%s", hdev->name);
-
-	kfree(husb);
-}
-
-static void hci_usb_notify(struct hci_dev *hdev, unsigned int evt)
-{
-	BT_DBG("%s evt %d", hdev->name, evt);
-}
-
-static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct usb_host_endpoint *bulk_out_ep = NULL;
-	struct usb_host_endpoint *bulk_in_ep = NULL;
-	struct usb_host_endpoint *intr_in_ep = NULL;
-	struct usb_host_endpoint  *ep;
-	struct usb_host_interface *uif;
-	struct usb_interface *isoc_iface;
-	struct hci_usb *husb;
-	struct hci_dev *hdev;
-	int i, e, size, isoc_ifnum, isoc_alts;
-
-	BT_DBG("udev %p intf %p", udev, intf);
-
-	if (!id->driver_info) {
-		const struct usb_device_id *match;
-		match = usb_match_id(intf, blacklist_ids);
-		if (match)
-			id = match;
-	}
-
-	if (id->driver_info & HCI_IGNORE)
-		return -ENODEV;
-
-	if (ignore_dga && id->driver_info & HCI_DIGIANSWER)
-		return -ENODEV;
-
-	if (ignore_csr && id->driver_info & HCI_CSR)
-		return -ENODEV;
-
-	if (ignore_sniffer && id->driver_info & HCI_SNIFFER)
-		return -ENODEV;
-
-	if (intf->cur_altsetting->desc.bInterfaceNumber > 0)
-		return -ENODEV;
-
-	/* Find endpoints that we need */
-	uif = intf->cur_altsetting;
-	for (e = 0; e < uif->desc.bNumEndpoints; e++) {
-		ep = &uif->endpoint[e];
-
-		switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-		case USB_ENDPOINT_XFER_INT:
-			if (ep->desc.bEndpointAddress & USB_DIR_IN)
-				intr_in_ep = ep;
-			break;
-
-		case USB_ENDPOINT_XFER_BULK:
-			if (ep->desc.bEndpointAddress & USB_DIR_IN)
-				bulk_in_ep  = ep;
-			else
-				bulk_out_ep = ep;
-			break;
-		}
-	}
-
-	if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) {
-		BT_DBG("Bulk endpoints not found");
-		goto done;
-	}
-
-	if (!(husb = kzalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
-		BT_ERR("Can't allocate: control structure");
-		goto done;
-	}
-
-	husb->udev = udev;
-	husb->bulk_out_ep = bulk_out_ep;
-	husb->bulk_in_ep  = bulk_in_ep;
-	husb->intr_in_ep  = intr_in_ep;
-
-	if (id->driver_info & HCI_DIGIANSWER)
-		husb->ctrl_req = USB_TYPE_VENDOR;
-	else
-		husb->ctrl_req = USB_TYPE_CLASS;
-
-	/* Find isochronous endpoints that we can use */
-	size = 0; 
-	isoc_iface = NULL;
-	isoc_alts  = 0;
-	isoc_ifnum = 1;
-
-#ifdef CONFIG_BT_HCIUSB_SCO
-	if (isoc && !(id->driver_info & (HCI_BROKEN_ISOC | HCI_SNIFFER)))
-		isoc_iface = usb_ifnum_to_if(udev, isoc_ifnum);
-
-	if (isoc_iface) {
-		int a;
-		struct usb_host_endpoint *isoc_out_ep = NULL;
-		struct usb_host_endpoint *isoc_in_ep = NULL;
-
-		for (a = 0; a < isoc_iface->num_altsetting; a++) {
-			uif = &isoc_iface->altsetting[a];
-			for (e = 0; e < uif->desc.bNumEndpoints; e++) {
-				ep = &uif->endpoint[e];
-
-				switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-				case USB_ENDPOINT_XFER_ISOC:
-					if (le16_to_cpu(ep->desc.wMaxPacketSize) < size ||
-							uif->desc.bAlternateSetting != isoc)
-						break;
-					size = le16_to_cpu(ep->desc.wMaxPacketSize);
-
-					isoc_alts = uif->desc.bAlternateSetting;
-
-					if (ep->desc.bEndpointAddress & USB_DIR_IN)
-						isoc_in_ep  = ep;
-					else
-						isoc_out_ep = ep;
-					break;
-				}
-			}
-		}
-
-		if (!isoc_in_ep || !isoc_out_ep)
-			BT_DBG("Isoc endpoints not found");
-		else {
-			BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);
-			if (usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb) != 0)
-				BT_ERR("Can't claim isoc interface");
-			else if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
-				BT_ERR("Can't set isoc interface settings");
-				husb->isoc_iface = isoc_iface;
-				usb_driver_release_interface(&hci_usb_driver, isoc_iface);
-				husb->isoc_iface = NULL;
-			} else {
-				husb->isoc_iface  = isoc_iface;
-				husb->isoc_in_ep  = isoc_in_ep;
-				husb->isoc_out_ep = isoc_out_ep;
-			}
-		}
-	}
-#endif
-
-	rwlock_init(&husb->completion_lock);
-
-	for (i = 0; i < 4; i++) {
-		skb_queue_head_init(&husb->transmit_q[i]);
-		_urb_queue_init(&husb->pending_q[i]);
-		_urb_queue_init(&husb->completed_q[i]);
-	}
-
-	/* Initialize and register HCI device */
-	hdev = hci_alloc_dev();
-	if (!hdev) {
-		BT_ERR("Can't allocate HCI device");
-		goto probe_error;
-	}
-
-	husb->hdev = hdev;
-
-	hdev->type = HCI_USB;
-	hdev->driver_data = husb;
-	SET_HCIDEV_DEV(hdev, &intf->dev);
-
-	hdev->open     = hci_usb_open;
-	hdev->close    = hci_usb_close;
-	hdev->flush    = hci_usb_flush;
-	hdev->send     = hci_usb_send_frame;
-	hdev->destruct = hci_usb_destruct;
-	hdev->notify   = hci_usb_notify;
-
-	hdev->owner = THIS_MODULE;
-
-	if (reset || id->driver_info & HCI_RESET)
-		set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
-
-	if (force_scofix || id->driver_info & HCI_WRONG_SCO_MTU) {
-		if (!disable_scofix)
-			set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks);
-	}
-
-	if (id->driver_info & HCI_SNIFFER) {
-		if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997)
-			set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
-	}
-
-	if (id->driver_info & HCI_BCM92035) {
-		unsigned char cmd[] = { 0x3b, 0xfc, 0x01, 0x00 };
-		struct sk_buff *skb;
-
-		skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
-		if (skb) {
-			memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
-			skb_queue_tail(&hdev->driver_init, skb);
-		}
-	}
-
-	if (hci_register_dev(hdev) < 0) {
-		BT_ERR("Can't register HCI device");
-		hci_free_dev(hdev);
-		goto probe_error;
-	}
-
-	usb_set_intfdata(intf, husb);
-	return 0;
-
-probe_error:
-	if (husb->isoc_iface)
-		usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface);
-	kfree(husb);
-
-done:
-	return -EIO;
-}
-
-static void hci_usb_disconnect(struct usb_interface *intf)
-{
-	struct hci_usb *husb = usb_get_intfdata(intf);
-	struct hci_dev *hdev;
-
-	if (!husb || intf == husb->isoc_iface)
-		return;
-
-	usb_set_intfdata(intf, NULL);
-	hdev = husb->hdev;
-
-	BT_DBG("%s", hdev->name);
-
-	hci_usb_close(hdev);
-
-	if (husb->isoc_iface)
-		usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface);
-
-	if (hci_unregister_dev(hdev) < 0)
-		BT_ERR("Can't unregister HCI device %s", hdev->name);
-
-	hci_free_dev(hdev);
-}
-
-static int hci_usb_suspend(struct usb_interface *intf, pm_message_t message)
-{
-	struct hci_usb *husb = usb_get_intfdata(intf);
-	struct list_head killed;
-	unsigned long flags;
-	int i;
-
-	if (!husb || intf == husb->isoc_iface)
-		return 0;
-
-	hci_suspend_dev(husb->hdev);
-
-	INIT_LIST_HEAD(&killed);
-
-	for (i = 0; i < 4; i++) {
-		struct _urb_queue *q = &husb->pending_q[i];
-		struct _urb *_urb, *_tmp;
-
-		while ((_urb = _urb_dequeue(q))) {
-			/* reset queue since _urb_dequeue sets it to NULL */
-			_urb->queue = q;
-			usb_kill_urb(&_urb->urb);
-			list_add(&_urb->list, &killed);
-		}
-
-		spin_lock_irqsave(&q->lock, flags);
-
-		list_for_each_entry_safe(_urb, _tmp, &killed, list) {
-			list_move_tail(&_urb->list, &q->head);
-		}
-
-		spin_unlock_irqrestore(&q->lock, flags);
-	}
-
-	return 0;
-}
-
-static int hci_usb_resume(struct usb_interface *intf)
-{
-	struct hci_usb *husb = usb_get_intfdata(intf);
-	unsigned long flags;
-	int i, err = 0;
-
-	if (!husb || intf == husb->isoc_iface)
-		return 0;
-	
-	for (i = 0; i < 4; i++) {
-		struct _urb_queue *q = &husb->pending_q[i];
-		struct _urb *_urb;
-
-		spin_lock_irqsave(&q->lock, flags);
-
-		list_for_each_entry(_urb, &q->head, list) {
-			err = usb_submit_urb(&_urb->urb, GFP_ATOMIC);
-			if (err)
-				break;
-		}
-
-		spin_unlock_irqrestore(&q->lock, flags);
-
-		if (err)
-			return -EIO;
-	}
-
-	hci_resume_dev(husb->hdev);
-
-	return 0;
-}
-
-static struct usb_driver hci_usb_driver = {
-	.name		= "hci_usb",
-	.probe		= hci_usb_probe,
-	.disconnect	= hci_usb_disconnect,
-	.suspend	= hci_usb_suspend,
-	.resume		= hci_usb_resume,
-	.id_table	= bluetooth_ids,
-};
-
-static int __init hci_usb_init(void)
-{
-	int err;
-
-	BT_INFO("HCI USB driver ver %s", VERSION);
-
-	if ((err = usb_register(&hci_usb_driver)) < 0)
-		BT_ERR("Failed to register HCI USB driver");
-
-	return err;
-}
-
-static void __exit hci_usb_exit(void)
-{
-	usb_deregister(&hci_usb_driver);
-}
-
-module_init(hci_usb_init);
-module_exit(hci_usb_exit);
-
-module_param(ignore_dga, bool, 0644);
-MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001");
-
-module_param(ignore_csr, bool, 0644);
-MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001");
-
-module_param(ignore_sniffer, bool, 0644);
-MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002");
-
-module_param(disable_scofix, bool, 0644);
-MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size");
-
-module_param(force_scofix, bool, 0644);
-MODULE_PARM_DESC(force_scofix, "Force fixup of wrong SCO buffers size");
-
-module_param(reset, bool, 0644);
-MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
-
-#ifdef CONFIG_BT_HCIUSB_SCO
-module_param(isoc, int, 0644);
-MODULE_PARM_DESC(isoc, "Set isochronous transfers for SCO over HCI support");
-#endif
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h
deleted file mode 100644
index 8e65991..0000000
--- a/drivers/bluetooth/hci_usb.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/* 
-   HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.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;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
-#define HCI_DEV_CLASS		0xe0	/* Wireless class */
-#define HCI_DEV_SUBCLASS	0x01	/* RF subclass */
-#define HCI_DEV_PROTOCOL	0x01	/* Bluetooth programming protocol */
-
-#define HCI_IGNORE		0x01
-#define HCI_RESET		0x02
-#define HCI_DIGIANSWER		0x04
-#define HCI_CSR			0x08
-#define HCI_SNIFFER		0x10
-#define HCI_BCM92035		0x20
-#define HCI_BROKEN_ISOC		0x40
-#define HCI_WRONG_SCO_MTU	0x80
-
-#define HCI_MAX_IFACE_NUM	3
-
-#define HCI_MAX_BULK_TX		4
-#define HCI_MAX_BULK_RX		1
-
-#define HCI_MAX_ISOC_RX		2
-#define HCI_MAX_ISOC_TX		2
-
-#define HCI_MAX_ISOC_FRAMES	10
-
-struct _urb_queue {
-	struct list_head head;
-	spinlock_t       lock;
-};
-
-struct _urb {
-	struct list_head  list;
-	struct _urb_queue *queue;
-	int               type;
-	void              *priv;
-	struct urb        urb;
-};
-
-static inline void _urb_queue_init(struct _urb_queue *q)
-{
-	INIT_LIST_HEAD(&q->head);
-	spin_lock_init(&q->lock);
-}
-
-static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&q->lock, flags);
-	/* _urb_unlink needs to know which spinlock to use, thus smp_mb(). */
-	_urb->queue = q; smp_mb(); list_add(&_urb->list, &q->head);
-	spin_unlock_irqrestore(&q->lock, flags);
-}
-
-static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&q->lock, flags);
-	/* _urb_unlink needs to know which spinlock to use, thus smp_mb(). */
-	_urb->queue = q; smp_mb(); list_add_tail(&_urb->list, &q->head);
-	spin_unlock_irqrestore(&q->lock, flags);
-}
-
-static inline void _urb_unlink(struct _urb *_urb)
-{
-	struct _urb_queue *q;
-	unsigned long flags;
-
-	smp_mb();
-	q = _urb->queue;
-	/* If q is NULL, it will die at easy-to-debug NULL pointer dereference.
-	   No need to BUG(). */
-	spin_lock_irqsave(&q->lock, flags);
-	list_del(&_urb->list); _urb->queue = NULL;
-	spin_unlock_irqrestore(&q->lock, flags);
-}
-
-struct hci_usb {
-	struct hci_dev		*hdev;
-
-	unsigned long		state;
-
-	struct usb_device	*udev;
-
-	struct usb_host_endpoint	*bulk_in_ep;
-	struct usb_host_endpoint	*bulk_out_ep;
-	struct usb_host_endpoint	*intr_in_ep;
-
-	struct usb_interface		*isoc_iface;
-	struct usb_host_endpoint	*isoc_out_ep;
-	struct usb_host_endpoint	*isoc_in_ep;
-
-	__u8			ctrl_req;
-
-	struct sk_buff_head	transmit_q[4];
-
-	rwlock_t		completion_lock;
-
-	atomic_t		pending_tx[4];		/* Number of pending requests */
-	struct _urb_queue	pending_q[4];		/* Pending requests */
-	struct _urb_queue	completed_q[4];		/* Completed requests */
-};
-
-/* States  */
-#define HCI_USB_TX_PROCESS	1
-#define HCI_USB_TX_WAKEUP	2
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 7320a71..0bbefba 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -40,11 +40,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef CONFIG_BT_HCIVHCI_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define VERSION "1.2"
 
 static int minor = MISC_DYNAMIC_MINOR;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 43d6ba8..c602b54 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -622,6 +622,16 @@
 	help
 	  Toshiba's Cell Reference Set Beat Console device driver
 
+config HVC_IUCV
+	bool "z/VM IUCV Hypervisor console support (VM only)"
+	depends on S390
+	select HVC_DRIVER
+	select IUCV
+	default y
+	help
+	  This driver provides a Hypervisor console (HVC) back-end to access
+	  a Linux (console) terminal via a z/VM IUCV communication path.
+
 config HVC_XEN
 	bool "Xen Hypervisor Console support"
 	depends on XEN
@@ -631,6 +641,12 @@
 	help
 	  Xen virtual console device driver
 
+config HVC_UDBG
+       bool "udbg based fake hypervisor console"
+       depends on PPC && EXPERIMENTAL
+       select HVC_DRIVER
+       default n
+
 config VIRTIO_CONSOLE
 	tristate "Virtio console"
 	depends on VIRTIO
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 438f713..9caf5b5 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -50,6 +50,8 @@
 obj-$(CONFIG_HVC_DRIVER)	+= hvc_console.o
 obj-$(CONFIG_HVC_IRQ)		+= hvc_irq.o
 obj-$(CONFIG_HVC_XEN)		+= hvc_xen.o
+obj-$(CONFIG_HVC_IUCV)		+= hvc_iucv.o
+obj-$(CONFIG_HVC_UDBG)		+= hvc_udbg.o
 obj-$(CONFIG_VIRTIO_CONSOLE)	+= virtio_console.o
 obj-$(CONFIG_RAW_DRIVER)	+= raw.o
 obj-$(CONFIG_SGI_SNSC)		+= snsc.o snsc_event.o
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 456f54d..977dfb1 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -60,6 +60,8 @@
 	unsigned bsr_num;      /* bsr id number for its type */
 	int      bsr_minor;
 
+	struct list_head bsr_list;
+
 	dev_t    bsr_dev;
 	struct cdev bsr_cdev;
 	struct device *bsr_device;
@@ -67,8 +69,8 @@
 
 };
 
-static unsigned num_bsr_devs;
-static struct bsr_dev *bsr_devs;
+static unsigned total_bsr_devs;
+static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs);
 static struct class *bsr_class;
 static int bsr_major;
 
@@ -146,24 +148,25 @@
 
 static void bsr_cleanup_devs(void)
 {
-	int i;
-	for (i=0 ; i < num_bsr_devs; i++) {
-		struct bsr_dev *cur = bsr_devs + i;
+	struct bsr_dev *cur, *n;
+
+	list_for_each_entry_safe(cur, n, &bsr_devs, bsr_list) {
 		if (cur->bsr_device) {
 			cdev_del(&cur->bsr_cdev);
 			device_del(cur->bsr_device);
 		}
+		list_del(&cur->bsr_list);
+		kfree(cur);
 	}
-
-	kfree(bsr_devs);
 }
 
-static int bsr_create_devs(struct device_node *bn)
+static int bsr_add_node(struct device_node *bn)
 {
-	int bsr_stride_len, bsr_bytes_len;
+	int bsr_stride_len, bsr_bytes_len, num_bsr_devs;
 	const u32 *bsr_stride;
 	const u32 *bsr_bytes;
 	unsigned i;
+	int ret = -ENODEV;
 
 	bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len);
 	bsr_bytes  = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len);
@@ -171,35 +174,36 @@
 	if (!bsr_stride || !bsr_bytes ||
 	    (bsr_stride_len != bsr_bytes_len)) {
 		printk(KERN_ERR "bsr of-node has missing/incorrect property\n");
-		return -ENODEV;
+		return ret;
 	}
 
 	num_bsr_devs = bsr_bytes_len / sizeof(u32);
 
-	/* only a warning, its informational since we'll fail and exit */
-	WARN_ON(num_bsr_devs > BSR_MAX_DEVS);
-
-	bsr_devs = kzalloc(sizeof(struct bsr_dev) * num_bsr_devs, GFP_KERNEL);
-	if (!bsr_devs)
-		return -ENOMEM;
-
 	for (i = 0 ; i < num_bsr_devs; i++) {
-		struct bsr_dev *cur = bsr_devs + i;
+		struct bsr_dev *cur = kzalloc(sizeof(struct bsr_dev),
+					      GFP_KERNEL);
 		struct resource res;
 		int result;
 
-		result = of_address_to_resource(bn, i, &res);
-		if (result < 0) {
-			printk(KERN_ERR "bsr of-node has invalid reg property\n");
+		if (!cur) {
+			printk(KERN_ERR "Unable to alloc bsr dev\n");
+			ret = -ENOMEM;
 			goto out_err;
 		}
 
-		cur->bsr_minor  = i;
+		result = of_address_to_resource(bn, i, &res);
+		if (result < 0) {
+			printk(KERN_ERR "bsr of-node has invalid reg property, skipping\n");
+			kfree(cur);
+			continue;
+		}
+
+		cur->bsr_minor  = i + total_bsr_devs;
 		cur->bsr_addr   = res.start;
 		cur->bsr_len    = res.end - res.start + 1;
 		cur->bsr_bytes  = bsr_bytes[i];
 		cur->bsr_stride = bsr_stride[i];
-		cur->bsr_dev    = MKDEV(bsr_major, i);
+		cur->bsr_dev    = MKDEV(bsr_major, i + total_bsr_devs);
 
 		switch(cur->bsr_bytes) {
 		case 8:
@@ -220,14 +224,15 @@
 		}
 
 		cur->bsr_num = bsr_types[cur->bsr_type];
-		bsr_types[cur->bsr_type] = cur->bsr_num + 1;
 		snprintf(cur->bsr_name, 32, "bsr%d_%d",
 			 cur->bsr_bytes, cur->bsr_num);
 
 		cdev_init(&cur->bsr_cdev, &bsr_fops);
 		result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1);
-		if (result)
+		if (result) {
+			kfree(cur);
 			goto out_err;
+		}
 
 		cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev,
 						cur, cur->bsr_name);
@@ -235,16 +240,37 @@
 			printk(KERN_ERR "device_create failed for %s\n",
 			       cur->bsr_name);
 			cdev_del(&cur->bsr_cdev);
+			kfree(cur);
 			goto out_err;
 		}
+
+		bsr_types[cur->bsr_type] = cur->bsr_num + 1;
+		list_add_tail(&cur->bsr_list, &bsr_devs);
 	}
 
+	total_bsr_devs += num_bsr_devs;
+
 	return 0;
 
  out_err:
 
 	bsr_cleanup_devs();
-	return -ENODEV;
+	return ret;
+}
+
+static int bsr_create_devs(struct device_node *bn)
+{
+	int ret;
+
+	while (bn) {
+		ret = bsr_add_node(bn);
+		if (ret) {
+			of_node_put(bn);
+			return ret;
+		}
+		bn = of_find_compatible_node(bn, NULL, "ibm,bsr");
+	}
+	return 0;
 }
 
 static int __init bsr_init(void)
@@ -254,7 +280,7 @@
 	int ret = -ENODEV;
 	int result;
 
-	np = of_find_compatible_node(NULL, "ibm,bsr", "ibm,bsr");
+	np = of_find_compatible_node(NULL, NULL, "ibm,bsr");
 	if (!np)
 		goto out_err;
 
@@ -272,10 +298,10 @@
 		goto out_err_2;
 	}
 
-	if ((ret = bsr_create_devs(np)) < 0)
+	if ((ret = bsr_create_devs(np)) < 0) {
+		np = NULL;
 		goto out_err_3;
-
-	of_node_put(np);
+	}
 
 	return 0;
 
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 5b819b1..fb57f67 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -642,8 +642,11 @@
 				/* Handle the SysRq Hack */
 				/* XXX should support a sequence */
 				if (buf[i] == '\x0f') {	/* ^O */
-					sysrq_pressed = 1;
-					continue;
+					/* if ^O is pressed again, reset
+					 * sysrq_pressed and flip ^O char */
+					sysrq_pressed = !sysrq_pressed;
+					if (sysrq_pressed)
+						continue;
 				} else if (sysrq_pressed) {
 					handle_sysrq(buf[i], tty);
 					sysrq_pressed = 0;
@@ -689,10 +692,8 @@
  */
 void hvc_resize(struct hvc_struct *hp, struct winsize ws)
 {
-	if ((hp->ws.ws_row != ws.ws_row) || (hp->ws.ws_col != ws.ws_col)) {
-		hp->ws = ws;
-		schedule_work(&hp->tty_resize);
-	}
+	hp->ws = ws;
+	schedule_work(&hp->tty_resize);
 }
 
 /*
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
index 8297dbc..3c85d78 100644
--- a/drivers/char/hvc_console.h
+++ b/drivers/char/hvc_console.h
@@ -48,7 +48,7 @@
 	spinlock_t lock;
 	int index;
 	struct tty_struct *tty;
-	unsigned int count;
+	int count;
 	int do_wakeup;
 	char *outbuf;
 	int outbuf_size;
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index b74a2f8..449727b 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -575,8 +575,10 @@
 		 * of console adapters.
 		 */
 		if ((num_found >= MAX_NR_HVC_CONSOLES) ||
-				(num_found >= VTTY_PORTS))
+				(num_found >= VTTY_PORTS)) {
+			of_node_put(vty);
 			break;
+		}
 
 		vtermno = of_get_property(vty, "reg", NULL);
 		if (!vtermno)
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c
new file mode 100644
index 0000000..5ea7d77
--- /dev/null
+++ b/drivers/char/hvc_iucv.c
@@ -0,0 +1,850 @@
+/*
+ * hvc_iucv.c - z/VM IUCV back-end for the Hypervisor Console (HVC)
+ *
+ * This back-end for HVC provides terminal access via
+ * z/VM IUCV communication paths.
+ *
+ * Copyright IBM Corp. 2008.
+ *
+ * Author(s):	Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ */
+#define KMSG_COMPONENT		"hvc_iucv"
+
+#include <linux/types.h>
+#include <asm/ebcdic.h>
+#include <linux/mempool.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <net/iucv/iucv.h>
+
+#include "hvc_console.h"
+
+
+/* HVC backend for z/VM IUCV */
+#define HVC_IUCV_MAGIC		0xc9e4c3e5
+#define MAX_HVC_IUCV_LINES	HVC_ALLOC_TTY_ADAPTERS
+#define MEMPOOL_MIN_NR		(PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4)
+
+/* IUCV TTY message  */
+#define MSG_VERSION		0x02	/* Message version */
+#define MSG_TYPE_ERROR		0x01	/* Error message */
+#define MSG_TYPE_TERMENV	0x02	/* Terminal environment variable */
+#define MSG_TYPE_TERMIOS	0x04	/* Terminal IO struct update */
+#define MSG_TYPE_WINSIZE	0x08	/* Terminal window size update */
+#define MSG_TYPE_DATA		0x10	/* Terminal data */
+
+#define MSG_SIZE(s)		((s) + offsetof(struct iucv_tty_msg, data))
+struct iucv_tty_msg {
+	u8	version;		/* Message version */
+	u8	type;			/* Message type */
+#define MSG_MAX_DATALEN		(~(u16)0)
+	u16	datalen;		/* Payload length */
+	u8	data[];			/* Payload buffer */
+} __attribute__((packed));
+
+enum iucv_state_t {
+	IUCV_DISCONN	= 0,
+	IUCV_CONNECTED	= 1,
+	IUCV_SEVERED	= 2,
+};
+
+enum tty_state_t {
+	TTY_CLOSED	= 0,
+	TTY_OPENED	= 1,
+};
+
+struct hvc_iucv_private {
+	struct hvc_struct	*hvc; /* HVC console struct reference */
+	u8			srv_name[8];	/* IUCV service name (ebcdic) */
+	enum iucv_state_t	iucv_state;	/* IUCV connection status */
+	enum tty_state_t	tty_state;	/* TTY status */
+	struct iucv_path	*path;		/* IUCV path pointer */
+	spinlock_t		lock;		/* hvc_iucv_private lock */
+	struct list_head	tty_outqueue;	/* outgoing IUCV messages */
+	struct list_head	tty_inqueue;	/* incoming IUCV messages */
+};
+
+struct iucv_tty_buffer {
+	struct list_head	list;	/* list pointer */
+	struct iucv_message	msg;	/* store an incoming IUCV message */
+	size_t			offset;	/* data buffer offset */
+	struct iucv_tty_msg	*mbuf;	/* buffer to store input/output data */
+};
+
+/* IUCV callback handler */
+static	int hvc_iucv_path_pending(struct iucv_path *, u8[8], u8[16]);
+static void hvc_iucv_path_severed(struct iucv_path *, u8[16]);
+static void hvc_iucv_msg_pending(struct iucv_path *, struct iucv_message *);
+static void hvc_iucv_msg_complete(struct iucv_path *, struct iucv_message *);
+
+
+/* Kernel module parameters */
+static unsigned long hvc_iucv_devices;
+
+/* Array of allocated hvc iucv tty lines... */
+static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES];
+
+/* Kmem cache and mempool for iucv_tty_buffer elements */
+static struct kmem_cache *hvc_iucv_buffer_cache;
+static mempool_t *hvc_iucv_mempool;
+
+/* IUCV handler callback functions */
+static struct iucv_handler hvc_iucv_handler = {
+	.path_pending  = hvc_iucv_path_pending,
+	.path_severed  = hvc_iucv_path_severed,
+	.message_complete = hvc_iucv_msg_complete,
+	.message_pending  = hvc_iucv_msg_pending,
+};
+
+
+/**
+ * hvc_iucv_get_private() - Return a struct hvc_iucv_private instance.
+ * @num:	The HVC virtual terminal number (vtermno)
+ *
+ * This function returns the struct hvc_iucv_private instance that corresponds
+ * to the HVC virtual terminal number specified as parameter @num.
+ */
+struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
+{
+	if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices))
+		return NULL;
+	return hvc_iucv_table[num - HVC_IUCV_MAGIC];
+}
+
+/**
+ * alloc_tty_buffer() - Returns a new struct iucv_tty_buffer element.
+ * @size:	Size of the internal buffer used to store data.
+ * @flags:	Memory allocation flags passed to mempool.
+ *
+ * This function allocates a new struct iucv_tty_buffer element and, optionally,
+ * allocates an internal data buffer with the specified size @size.
+ * Note: The total message size arises from the internal buffer size and the
+ *	 members of the iucv_tty_msg structure.
+ *
+ * The function returns NULL if memory allocation has failed.
+ */
+static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags)
+{
+	struct iucv_tty_buffer *bufp;
+
+	bufp = mempool_alloc(hvc_iucv_mempool, flags);
+	if (!bufp)
+		return NULL;
+	memset(bufp, 0, sizeof(struct iucv_tty_buffer));
+
+	if (size > 0) {
+		bufp->msg.length = MSG_SIZE(size);
+		bufp->mbuf = kmalloc(bufp->msg.length, flags);
+		if (!bufp->mbuf) {
+			mempool_free(bufp, hvc_iucv_mempool);
+			return NULL;
+		}
+		bufp->mbuf->version = MSG_VERSION;
+		bufp->mbuf->type    = MSG_TYPE_DATA;
+		bufp->mbuf->datalen = (u16) size;
+	}
+	return bufp;
+}
+
+/**
+ * destroy_tty_buffer() - destroy struct iucv_tty_buffer element.
+ * @bufp:	Pointer to a struct iucv_tty_buffer element, SHALL NOT be NULL.
+ *
+ * The destroy_tty_buffer() function frees the internal data buffer and returns
+ * the struct iucv_tty_buffer element back to the mempool for freeing.
+ */
+static void destroy_tty_buffer(struct iucv_tty_buffer *bufp)
+{
+	kfree(bufp->mbuf);
+	mempool_free(bufp, hvc_iucv_mempool);
+}
+
+/**
+ * destroy_tty_buffer_list() - call destroy_tty_buffer() for each list element.
+ * @list:	List head pointer to a list containing struct iucv_tty_buffer
+ *		elements.
+ *
+ * Calls destroy_tty_buffer() for each struct iucv_tty_buffer element in the
+ * list @list.
+ */
+static void destroy_tty_buffer_list(struct list_head *list)
+{
+	struct iucv_tty_buffer *ent, *next;
+
+	list_for_each_entry_safe(ent, next, list, list) {
+		list_del(&ent->list);
+		destroy_tty_buffer(ent);
+	}
+}
+
+/**
+ * hvc_iucv_write() - Receive IUCV message write data to HVC console buffer.
+ * @priv:		Pointer to hvc_iucv_private structure.
+ * @buf:		HVC console buffer for writing received terminal data.
+ * @count:		HVC console buffer size.
+ * @has_more_data:	Pointer to an int variable.
+ *
+ * The function picks up pending messages from the input queue and receives
+ * the message data that is then written to the specified buffer @buf.
+ * If the buffer size @count is less than the data message size, then the
+ * message is kept on the input queue and @has_more_data is set to 1.
+ * If the message data has been entirely written, the message is removed from
+ * the input queue.
+ *
+ * The function returns the number of bytes written to the terminal, zero if
+ * there are no pending data messages available or if there is no established
+ * IUCV path.
+ * If the IUCV path has been severed, then -EPIPE is returned to cause a
+ * hang up (that is issued by the HVC console layer).
+ */
+static int hvc_iucv_write(struct hvc_iucv_private *priv,
+			  char *buf, int count, int *has_more_data)
+{
+	struct iucv_tty_buffer *rb;
+	int written;
+	int rc;
+
+	/* Immediately return if there is no IUCV connection */
+	if (priv->iucv_state == IUCV_DISCONN)
+		return 0;
+
+	/* If the IUCV path has been severed, return -EPIPE to inform the
+	 * hvc console layer to hang up the tty device. */
+	if (priv->iucv_state == IUCV_SEVERED)
+		return -EPIPE;
+
+	/* check if there are pending messages */
+	if (list_empty(&priv->tty_inqueue))
+		return 0;
+
+	/* receive a iucv message and flip data to the tty (ldisc) */
+	rb = list_first_entry(&priv->tty_inqueue, struct iucv_tty_buffer, list);
+
+	written = 0;
+	if (!rb->mbuf) { /* message not yet received ... */
+		/* allocate mem to store msg data; if no memory is available
+		 * then leave the buffer on the list and re-try later */
+		rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC);
+		if (!rb->mbuf)
+			return -ENOMEM;
+
+		rc = __iucv_message_receive(priv->path, &rb->msg, 0,
+					    rb->mbuf, rb->msg.length, NULL);
+		switch (rc) {
+		case 0: /* Successful	    */
+			break;
+		case 2:	/* No message found */
+		case 9: /* Message purged   */
+			break;
+		default:
+			written = -EIO;
+		}
+		/* remove buffer if an error has occured or received data
+		 * is not correct */
+		if (rc || (rb->mbuf->version != MSG_VERSION) ||
+			  (rb->msg.length    != MSG_SIZE(rb->mbuf->datalen)))
+			goto out_remove_buffer;
+	}
+
+	switch (rb->mbuf->type) {
+	case MSG_TYPE_DATA:
+		written = min_t(int, rb->mbuf->datalen - rb->offset, count);
+		memcpy(buf, rb->mbuf->data + rb->offset, written);
+		if (written < (rb->mbuf->datalen - rb->offset)) {
+			rb->offset += written;
+			*has_more_data = 1;
+			goto out_written;
+		}
+		break;
+
+	case MSG_TYPE_WINSIZE:
+		if (rb->mbuf->datalen != sizeof(struct winsize))
+			break;
+		hvc_resize(priv->hvc, *((struct winsize *)rb->mbuf->data));
+		break;
+
+	case MSG_TYPE_ERROR:	/* ignored ... */
+	case MSG_TYPE_TERMENV:	/* ignored ... */
+	case MSG_TYPE_TERMIOS:	/* ignored ... */
+		break;
+	}
+
+out_remove_buffer:
+	list_del(&rb->list);
+	destroy_tty_buffer(rb);
+	*has_more_data = !list_empty(&priv->tty_inqueue);
+
+out_written:
+	return written;
+}
+
+/**
+ * hvc_iucv_get_chars() - HVC get_chars operation.
+ * @vtermno:	HVC virtual terminal number.
+ * @buf:	Pointer to a buffer to store data
+ * @count:	Size of buffer available for writing
+ *
+ * The hvc_console thread calls this method to read characters from
+ * the terminal backend. If an IUCV communication path has been established,
+ * pending IUCV messages are received and data is copied into buffer @buf
+ * up to @count bytes.
+ *
+ * Locking:	The routine gets called under an irqsave() spinlock; and
+ *		the routine locks the struct hvc_iucv_private->lock to call
+ *		helper functions.
+ */
+static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count)
+{
+	struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno);
+	int written;
+	int has_more_data;
+
+	if (count <= 0)
+		return 0;
+
+	if (!priv)
+		return -ENODEV;
+
+	spin_lock(&priv->lock);
+	has_more_data = 0;
+	written = hvc_iucv_write(priv, buf, count, &has_more_data);
+	spin_unlock(&priv->lock);
+
+	/* if there are still messages on the queue... schedule another run */
+	if (has_more_data)
+		hvc_kick();
+
+	return written;
+}
+
+/**
+ * hvc_iucv_send() - Send an IUCV message containing terminal data.
+ * @priv:	Pointer to struct hvc_iucv_private instance.
+ * @buf:	Buffer containing data to send.
+ * @size:	Size of buffer and amount of data to send.
+ *
+ * If an IUCV communication path is established, the function copies the buffer
+ * data to a newly allocated struct iucv_tty_buffer element, sends the data and
+ * puts the element to the outqueue.
+ *
+ * If there is no IUCV communication path established, the function returns 0.
+ * If an existing IUCV communicaton path has been severed, the function returns
+ * -EPIPE (can be passed to HVC layer to cause a tty hangup).
+ */
+static int hvc_iucv_send(struct hvc_iucv_private *priv, const char *buf,
+			 int count)
+{
+	struct iucv_tty_buffer *sb;
+	int rc;
+	u16 len;
+
+	if (priv->iucv_state == IUCV_SEVERED)
+		return -EPIPE;
+
+	if (priv->iucv_state == IUCV_DISCONN)
+		return 0;
+
+	len = min_t(u16, MSG_MAX_DATALEN, count);
+
+	/* allocate internal buffer to store msg data and also compute total
+	 * message length */
+	sb = alloc_tty_buffer(len, GFP_ATOMIC);
+	if (!sb)
+		return -ENOMEM;
+
+	sb->mbuf->datalen = len;
+	memcpy(sb->mbuf->data, buf, len);
+
+	list_add_tail(&sb->list, &priv->tty_outqueue);
+
+	rc = __iucv_message_send(priv->path, &sb->msg, 0, 0,
+				 (void *) sb->mbuf, sb->msg.length);
+	if (rc) {
+		list_del(&sb->list);
+		destroy_tty_buffer(sb);
+		len = 0;
+	}
+
+	return len;
+}
+
+/**
+ * hvc_iucv_put_chars() - HVC put_chars operation.
+ * @vtermno:	HVC virtual terminal number.
+ * @buf:	Pointer to an buffer to read data from
+ * @count:	Size of buffer available for reading
+ *
+ * The hvc_console thread calls this method to write characters from
+ * to the terminal backend.
+ * The function calls hvc_iucv_send() under the lock of the
+ * struct hvc_iucv_private instance that corresponds to the tty @vtermno.
+ *
+ * Locking:	The method gets called under an irqsave() spinlock; and
+ *		locks struct hvc_iucv_private->lock.
+ */
+static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count)
+{
+	struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno);
+	int sent;
+
+	if (count <= 0)
+		return 0;
+
+	if (!priv)
+		return -ENODEV;
+
+	spin_lock(&priv->lock);
+	sent = hvc_iucv_send(priv, buf, count);
+	spin_unlock(&priv->lock);
+
+	return sent;
+}
+
+/**
+ * hvc_iucv_notifier_add() - HVC notifier for opening a TTY for the first time.
+ * @hp:	Pointer to the HVC device (struct hvc_struct)
+ * @id:	Additional data (originally passed to hvc_alloc): the index of an struct
+ *	hvc_iucv_private instance.
+ *
+ * The function sets the tty state to TTY_OPEN for the struct hvc_iucv_private
+ * instance that is derived from @id. Always returns 0.
+ *
+ * Locking:	struct hvc_iucv_private->lock, spin_lock_bh
+ */
+static int hvc_iucv_notifier_add(struct hvc_struct *hp, int id)
+{
+	struct hvc_iucv_private *priv;
+
+	priv = hvc_iucv_get_private(id);
+	if (!priv)
+		return 0;
+
+	spin_lock_bh(&priv->lock);
+	priv->tty_state = TTY_OPENED;
+	spin_unlock_bh(&priv->lock);
+
+	return 0;
+}
+
+/**
+ * hvc_iucv_cleanup() - Clean up function if the tty portion is finally closed.
+ * @priv:	Pointer to the struct hvc_iucv_private instance.
+ *
+ * The functions severs the established IUCV communication path (if any), and
+ * destroy struct iucv_tty_buffer elements from the in- and outqueue. Finally,
+ * the functions resets the states to TTY_CLOSED and IUCV_DISCONN.
+ */
+static void hvc_iucv_cleanup(struct hvc_iucv_private *priv)
+{
+	destroy_tty_buffer_list(&priv->tty_outqueue);
+	destroy_tty_buffer_list(&priv->tty_inqueue);
+
+	priv->tty_state = TTY_CLOSED;
+	priv->iucv_state = IUCV_DISCONN;
+}
+
+/**
+ * hvc_iucv_notifier_hangup() - HVC notifier for tty hangups.
+ * @hp: Pointer to the HVC device (struct hvc_struct)
+ * @id: Additional data (originally passed to hvc_alloc): the index of an struct
+ *	hvc_iucv_private instance.
+ *
+ * This routine notifies the HVC backend that a tty hangup (carrier loss,
+ * virtual or otherwise) has occured.
+ *
+ * The HVC backend for z/VM IUCV ignores virtual hangups (vhangup()), to keep
+ * an existing IUCV communication path established.
+ * (Background: vhangup() is called from user space (by getty or login) to
+ *		disable writing to the tty by other applications).
+ *
+ * If the tty has been opened (e.g. getty) and an established IUCV path has been
+ * severed (we caused the tty hangup in that case), then the functions invokes
+ * hvc_iucv_cleanup() to clean up.
+ *
+ * Locking:	struct hvc_iucv_private->lock
+ */
+static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)
+{
+	struct hvc_iucv_private *priv;
+
+	priv = hvc_iucv_get_private(id);
+	if (!priv)
+		return;
+
+	spin_lock_bh(&priv->lock);
+	/* NOTE: If the hangup was scheduled by ourself (from the iucv
+	 *	 path_servered callback [IUCV_SEVERED]), then we have to
+	 *	 finally clean up the tty backend structure and set state to
+	 *	 TTY_CLOSED.
+	 *
+	 *	 If the tty was hung up otherwise (e.g. vhangup()), then we
+	 *	 ignore this hangup and keep an established IUCV path open...
+	 *	 (...the reason is that we are not able to connect back to the
+	 *	 client if we disconnect on hang up) */
+	priv->tty_state = TTY_CLOSED;
+
+	if (priv->iucv_state == IUCV_SEVERED)
+		hvc_iucv_cleanup(priv);
+	spin_unlock_bh(&priv->lock);
+}
+
+/**
+ * hvc_iucv_notifier_del() - HVC notifier for closing a TTY for the last time.
+ * @hp:		Pointer to the HVC device (struct hvc_struct)
+ * @id:		Additional data (originally passed to hvc_alloc):
+ *		the index of an struct hvc_iucv_private instance.
+ *
+ * This routine notifies the HVC backend that the last tty device file
+ * descriptor has been closed.
+ * The function calls hvc_iucv_cleanup() to clean up the struct hvc_iucv_private
+ * instance.
+ *
+ * Locking:	struct hvc_iucv_private->lock
+ */
+static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
+{
+	struct hvc_iucv_private *priv;
+	struct iucv_path	*path;
+
+	priv = hvc_iucv_get_private(id);
+	if (!priv)
+		return;
+
+	spin_lock_bh(&priv->lock);
+	path = priv->path;		/* save reference to IUCV path */
+	priv->path = NULL;
+	hvc_iucv_cleanup(priv);
+	spin_unlock_bh(&priv->lock);
+
+	/* sever IUCV path outside of priv->lock due to lock ordering of:
+	 * priv->lock <--> iucv_table_lock */
+	if (path) {
+		iucv_path_sever(path, NULL);
+		iucv_path_free(path);
+	}
+}
+
+/**
+ * hvc_iucv_path_pending() - IUCV handler to process a connection request.
+ * @path:	Pending path (struct iucv_path)
+ * @ipvmid:	Originator z/VM system identifier
+ * @ipuser:	User specified data for this path
+ *		(AF_IUCV: port/service name and originator port)
+ *
+ * The function uses the @ipuser data to check to determine if the pending
+ * path belongs to a terminal managed by this HVC backend.
+ * If the check is successful, then an additional check is done to ensure
+ * that a terminal cannot be accessed multiple times (only one connection
+ * to a terminal is allowed). In that particular case, the pending path is
+ * severed. If it is the first connection, the pending path is accepted and
+ * associated to the struct hvc_iucv_private. The iucv state is updated to
+ * reflect that a communication path has been established.
+ *
+ * Returns 0 if the path belongs to a terminal managed by the this HVC backend;
+ * otherwise returns -ENODEV in order to dispatch this path to other handlers.
+ *
+ * Locking:	struct hvc_iucv_private->lock
+ */
+static	int hvc_iucv_path_pending(struct iucv_path *path,
+				  u8 ipvmid[8], u8 ipuser[16])
+{
+	struct hvc_iucv_private *priv;
+	u8 nuser_data[16];
+	int i, rc;
+
+	priv = NULL;
+	for (i = 0; i < hvc_iucv_devices; i++)
+		if (hvc_iucv_table[i] &&
+		    (0 == memcmp(hvc_iucv_table[i]->srv_name, ipuser, 8))) {
+			priv = hvc_iucv_table[i];
+			break;
+		}
+
+	if (!priv)
+		return -ENODEV;
+
+	spin_lock(&priv->lock);
+
+	/* If the terminal is already connected or being severed, then sever
+	 * this path to enforce that there is only ONE established communication
+	 * path per terminal. */
+	if (priv->iucv_state != IUCV_DISCONN) {
+		iucv_path_sever(path, ipuser);
+		iucv_path_free(path);
+		goto out_path_handled;
+	}
+
+	/* accept path */
+	memcpy(nuser_data, ipuser + 8, 8);  /* remote service (for af_iucv) */
+	memcpy(nuser_data + 8, ipuser, 8);  /* local service  (for af_iucv) */
+	path->msglim = 0xffff;		    /* IUCV MSGLIMIT */
+	path->flags &= ~IUCV_IPRMDATA;	    /* TODO: use IUCV_IPRMDATA */
+	rc = iucv_path_accept(path, &hvc_iucv_handler, nuser_data, priv);
+	if (rc) {
+		iucv_path_sever(path, ipuser);
+		iucv_path_free(path);
+		goto out_path_handled;
+	}
+	priv->path = path;
+	priv->iucv_state = IUCV_CONNECTED;
+
+out_path_handled:
+	spin_unlock(&priv->lock);
+	return 0;
+}
+
+/**
+ * hvc_iucv_path_severed() - IUCV handler to process a path sever.
+ * @path:	Pending path (struct iucv_path)
+ * @ipuser:	User specified data for this path
+ *		(AF_IUCV: port/service name and originator port)
+ *
+ * The function also severs the path (as required by the IUCV protocol) and
+ * sets the iucv state to IUCV_SEVERED for the associated struct
+ * hvc_iucv_private instance. Later, the IUCV_SEVERED state triggers a tty
+ * hangup (hvc_iucv_get_chars() / hvc_iucv_write()).
+ *
+ * If tty portion of the HVC is closed then clean up the outqueue in addition.
+ *
+ * Locking:	struct hvc_iucv_private->lock
+ */
+static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
+{
+	struct hvc_iucv_private *priv = path->private;
+
+	spin_lock(&priv->lock);
+	priv->iucv_state = IUCV_SEVERED;
+
+	/* NOTE: If the tty has not yet been opened by a getty program
+	 *	 (e.g. to see console messages), then cleanup the
+	 *	 hvc_iucv_private structure to allow re-connects.
+	 *
+	 *	 If the tty has been opened, the get_chars() callback returns
+	 *	 -EPIPE to signal the hvc console layer to hang up the tty. */
+	priv->path = NULL;
+	if (priv->tty_state == TTY_CLOSED)
+		hvc_iucv_cleanup(priv);
+	spin_unlock(&priv->lock);
+
+	/* finally sever path (outside of priv->lock due to lock ordering) */
+	iucv_path_sever(path, ipuser);
+	iucv_path_free(path);
+}
+
+/**
+ * hvc_iucv_msg_pending() - IUCV handler to process an incoming IUCV message.
+ * @path:	Pending path (struct iucv_path)
+ * @msg:	Pointer to the IUCV message
+ *
+ * The function stores an incoming message on the input queue for later
+ * processing (by hvc_iucv_get_chars() / hvc_iucv_write()).
+ * However, if the tty has not yet been opened, the message is rejected.
+ *
+ * Locking:	struct hvc_iucv_private->lock
+ */
+static void hvc_iucv_msg_pending(struct iucv_path *path,
+				 struct iucv_message *msg)
+{
+	struct hvc_iucv_private *priv = path->private;
+	struct iucv_tty_buffer *rb;
+
+	spin_lock(&priv->lock);
+
+	/* reject messages if tty has not yet been opened */
+	if (priv->tty_state == TTY_CLOSED) {
+		iucv_message_reject(path, msg);
+		goto unlock_return;
+	}
+
+	/* allocate buffer an empty buffer element */
+	rb = alloc_tty_buffer(0, GFP_ATOMIC);
+	if (!rb) {
+		iucv_message_reject(path, msg);
+		goto unlock_return;	/* -ENOMEM */
+	}
+	rb->msg = *msg;
+
+	list_add_tail(&rb->list, &priv->tty_inqueue);
+
+	hvc_kick();	/* wakup hvc console thread */
+
+unlock_return:
+	spin_unlock(&priv->lock);
+}
+
+/**
+ * hvc_iucv_msg_complete() - IUCV handler to process message completion
+ * @path:	Pending path (struct iucv_path)
+ * @msg:	Pointer to the IUCV message
+ *
+ * The function is called upon completion of message delivery and the
+ * message is removed from the outqueue. Additional delivery information
+ * can be found in msg->audit: rejected messages (0x040000 (IPADRJCT)) and
+ * purged messages (0x010000 (IPADPGNR)).
+ *
+ * Locking:	struct hvc_iucv_private->lock
+ */
+static void hvc_iucv_msg_complete(struct iucv_path *path,
+				  struct iucv_message *msg)
+{
+	struct hvc_iucv_private *priv = path->private;
+	struct iucv_tty_buffer	*ent, *next;
+	LIST_HEAD(list_remove);
+
+	spin_lock(&priv->lock);
+	list_for_each_entry_safe(ent, next, &priv->tty_outqueue, list)
+		if (ent->msg.id == msg->id) {
+			list_move(&ent->list, &list_remove);
+			break;
+		}
+	spin_unlock(&priv->lock);
+	destroy_tty_buffer_list(&list_remove);
+}
+
+
+/* HVC operations */
+static struct hv_ops hvc_iucv_ops = {
+	.get_chars = hvc_iucv_get_chars,
+	.put_chars = hvc_iucv_put_chars,
+	.notifier_add = hvc_iucv_notifier_add,
+	.notifier_del = hvc_iucv_notifier_del,
+	.notifier_hangup = hvc_iucv_notifier_hangup,
+};
+
+/**
+ * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
+ * @id:	hvc_iucv_table index
+ *
+ * This function allocates a new hvc_iucv_private struct and put the
+ * instance into hvc_iucv_table at index @id.
+ * Returns 0 on success; otherwise non-zero.
+ */
+static int __init hvc_iucv_alloc(int id)
+{
+	struct hvc_iucv_private *priv;
+	char name[9];
+	int rc;
+
+	priv = kzalloc(sizeof(struct hvc_iucv_private), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	spin_lock_init(&priv->lock);
+	INIT_LIST_HEAD(&priv->tty_outqueue);
+	INIT_LIST_HEAD(&priv->tty_inqueue);
+
+	/* Finally allocate hvc */
+	priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id,
+			      HVC_IUCV_MAGIC + id, &hvc_iucv_ops, PAGE_SIZE);
+	if (IS_ERR(priv->hvc)) {
+		rc = PTR_ERR(priv->hvc);
+		kfree(priv);
+		return rc;
+	}
+
+	/* setup iucv related information */
+	snprintf(name, 9, "ihvc%-4d", id);
+	memcpy(priv->srv_name, name, 8);
+	ASCEBC(priv->srv_name, 8);
+
+	hvc_iucv_table[id] = priv;
+	return 0;
+}
+
+/**
+ * hvc_iucv_init() - Initialization of HVC backend for z/VM IUCV
+ */
+static int __init hvc_iucv_init(void)
+{
+	int rc, i;
+
+	if (!MACHINE_IS_VM) {
+		pr_warning("The z/VM IUCV Hypervisor console cannot be "
+			   "used without z/VM.\n");
+		return -ENODEV;
+	}
+
+	if (!hvc_iucv_devices)
+		return -ENODEV;
+
+	if (hvc_iucv_devices > MAX_HVC_IUCV_LINES)
+		return -EINVAL;
+
+	hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT,
+					   sizeof(struct iucv_tty_buffer),
+					   0, 0, NULL);
+	if (!hvc_iucv_buffer_cache) {
+		pr_err("Not enough memory for driver initialization "
+			"(rs=%d).\n", 1);
+		return -ENOMEM;
+	}
+
+	hvc_iucv_mempool = mempool_create_slab_pool(MEMPOOL_MIN_NR,
+						    hvc_iucv_buffer_cache);
+	if (!hvc_iucv_mempool) {
+		pr_err("Not enough memory for driver initialization "
+			"(rs=%d).\n", 2);
+		kmem_cache_destroy(hvc_iucv_buffer_cache);
+		return -ENOMEM;
+	}
+
+	/* allocate hvc_iucv_private structs */
+	for (i = 0; i < hvc_iucv_devices; i++) {
+		rc = hvc_iucv_alloc(i);
+		if (rc) {
+			pr_err("Could not create new z/VM IUCV HVC backend "
+				"rc=%d.\n", rc);
+			goto out_error_hvc;
+		}
+	}
+
+	/* register IUCV callback handler */
+	rc = iucv_register(&hvc_iucv_handler, 0);
+	if (rc) {
+		pr_err("Could not register iucv handler (rc=%d).\n", rc);
+		goto out_error_iucv;
+	}
+
+	return 0;
+
+out_error_iucv:
+	iucv_unregister(&hvc_iucv_handler, 0);
+out_error_hvc:
+	for (i = 0; i < hvc_iucv_devices; i++)
+		if (hvc_iucv_table[i]) {
+			if (hvc_iucv_table[i]->hvc)
+				hvc_remove(hvc_iucv_table[i]->hvc);
+			kfree(hvc_iucv_table[i]);
+		}
+	mempool_destroy(hvc_iucv_mempool);
+	kmem_cache_destroy(hvc_iucv_buffer_cache);
+	return rc;
+}
+
+/**
+ * hvc_iucv_console_init() - Early console initialization
+ */
+static	int __init hvc_iucv_console_init(void)
+{
+	if (!MACHINE_IS_VM || !hvc_iucv_devices)
+		return -ENODEV;
+	return hvc_instantiate(HVC_IUCV_MAGIC, 0, &hvc_iucv_ops);
+}
+
+/**
+ * hvc_iucv_config() - Parsing of hvc_iucv=  kernel command line parameter
+ * @val:	Parameter value (numeric)
+ */
+static	int __init hvc_iucv_config(char *val)
+{
+	 return strict_strtoul(val, 10, &hvc_iucv_devices);
+}
+
+
+module_init(hvc_iucv_init);
+console_initcall(hvc_iucv_console_init);
+__setup("hvc_iucv=", hvc_iucv_config);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("HVC back-end for z/VM IUCV.");
+MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>");
diff --git a/drivers/char/hvc_udbg.c b/drivers/char/hvc_udbg.c
new file mode 100644
index 0000000..bd63ba8
--- /dev/null
+++ b/drivers/char/hvc_udbg.c
@@ -0,0 +1,96 @@
+/*
+ * udbg interface to hvc_console.c
+ *
+ * (C) Copyright David Gibson, IBM Corporation 2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/irq.h>
+
+#include <asm/udbg.h>
+
+#include "hvc_console.h"
+
+struct hvc_struct *hvc_udbg_dev;
+
+static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		udbg_putc(buf[i]);
+
+	return i;
+}
+
+static int hvc_udbg_get(uint32_t vtermno, char *buf, int count)
+{
+	int i, c;
+
+	if (!udbg_getc_poll)
+		return 0;
+
+	for (i = 0; i < count; i++) {
+		if ((c = udbg_getc_poll()) == -1)
+			break;
+		buf[i] = c;
+	}
+
+	return i;
+}
+
+static struct hv_ops hvc_udbg_ops = {
+	.get_chars = hvc_udbg_get,
+	.put_chars = hvc_udbg_put,
+};
+
+static int __init hvc_udbg_init(void)
+{
+	struct hvc_struct *hp;
+
+	BUG_ON(hvc_udbg_dev);
+
+	hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16);
+	if (IS_ERR(hp))
+		return PTR_ERR(hp);
+
+	hvc_udbg_dev = hp;
+
+	return 0;
+}
+module_init(hvc_udbg_init);
+
+static void __exit hvc_udbg_exit(void)
+{
+	if (hvc_udbg_dev)
+		hvc_remove(hvc_udbg_dev);
+}
+module_exit(hvc_udbg_exit);
+
+static int __init hvc_udbg_console_init(void)
+{
+	hvc_instantiate(0, 0, &hvc_udbg_ops);
+	add_preferred_console("hvc", 0, NULL);
+
+	return 0;
+}
+console_initcall(hvc_udbg_console_init);
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index 019e0b5..bd62dc8 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -153,8 +153,10 @@
 		/* We have statically defined space for only a certain number
 		 * of console adapters.
 		 */
-		if (num_found >= MAX_NR_HVC_CONSOLES)
+		if (num_found >= MAX_NR_HVC_CONSOLES) {
+			of_node_put(vty);
 			break;
+		}
 
 		vtermno = of_get_property(vty, "reg", NULL);
 		if (!vtermno)
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 473d9b1..6e6eb44 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -269,7 +269,7 @@
 	unsigned int index;
 
 	struct tty_struct *tty;
-	unsigned int open_count;
+	int open_count;
 
 	/*
 	 * Used to tell the driver kernel_thread what operations need to take
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index 59c6f9a..af05528 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -75,7 +75,7 @@
 	spinlock_t lock;
 	int index;
 	struct tty_struct *tty;
-	unsigned int count;
+	int count;
 	uint8_t throttle_buf[128];
 	uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
 	/* inbuf is for packet reassembly. leave a little room for leftovers. */
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 8054ee8..88cee40 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -32,9 +32,10 @@
  * 		added changelog
  * 	1.2	Erik Gilling: Cobalt Networks support
  * 		Tim Hockin: general cleanup, Cobalt support
+ * 	1.3	Wim Van Sebroeck: convert PRINT_PROC to seq_file
  */
 
-#define NVRAM_VERSION	"1.2"
+#define NVRAM_VERSION	"1.3"
 
 #include <linux/module.h>
 #include <linux/smp_lock.h>
@@ -46,7 +47,7 @@
 /* select machine configuration */
 #if defined(CONFIG_ATARI)
 #  define MACH ATARI
-#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)  /* and others?? */
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)  /* and ?? */
 #  define MACH PC
 #else
 #  error Cannot build nvram driver for this machine configuration.
@@ -106,10 +107,11 @@
 #include <linux/mc146818rtc.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
 
-#include <asm/io.h>
-#include <asm/uaccess.h>
 #include <asm/system.h>
 
 static DEFINE_SPINLOCK(nvram_state_lock);
@@ -122,8 +124,8 @@
 static void mach_set_checksum(void);
 
 #ifdef CONFIG_PROC_FS
-static int mach_proc_infos(unsigned char *contents, char *buffer, int *len,
-    off_t *begin, off_t offset, int size);
+static void mach_proc_infos(unsigned char *contents, struct seq_file *seq,
+								void *offset);
 #endif
 
 /*
@@ -133,18 +135,17 @@
  *
  * It is worth noting that these functions all access bytes of general
  * purpose memory in the NVRAM - that is to say, they all add the
- * NVRAM_FIRST_BYTE offset.  Pass them offsets into NVRAM as if you did not 
+ * NVRAM_FIRST_BYTE offset.  Pass them offsets into NVRAM as if you did not
  * know about the RTC cruft.
  */
 
-unsigned char
-__nvram_read_byte(int i)
+unsigned char __nvram_read_byte(int i)
 {
 	return CMOS_READ(NVRAM_FIRST_BYTE + i);
 }
+EXPORT_SYMBOL(__nvram_read_byte);
 
-unsigned char
-nvram_read_byte(int i)
+unsigned char nvram_read_byte(int i)
 {
 	unsigned long flags;
 	unsigned char c;
@@ -154,16 +155,16 @@
 	spin_unlock_irqrestore(&rtc_lock, flags);
 	return c;
 }
+EXPORT_SYMBOL(nvram_read_byte);
 
 /* This races nicely with trying to read with checksum checking (nvram_read) */
-void
-__nvram_write_byte(unsigned char c, int i)
+void __nvram_write_byte(unsigned char c, int i)
 {
 	CMOS_WRITE(c, NVRAM_FIRST_BYTE + i);
 }
+EXPORT_SYMBOL(__nvram_write_byte);
 
-void
-nvram_write_byte(unsigned char c, int i)
+void nvram_write_byte(unsigned char c, int i)
 {
 	unsigned long flags;
 
@@ -171,15 +172,15 @@
 	__nvram_write_byte(c, i);
 	spin_unlock_irqrestore(&rtc_lock, flags);
 }
+EXPORT_SYMBOL(nvram_write_byte);
 
-int
-__nvram_check_checksum(void)
+int __nvram_check_checksum(void)
 {
 	return mach_check_checksum();
 }
+EXPORT_SYMBOL(__nvram_check_checksum);
 
-int
-nvram_check_checksum(void)
+int nvram_check_checksum(void)
 {
 	unsigned long flags;
 	int rv;
@@ -189,16 +190,15 @@
 	spin_unlock_irqrestore(&rtc_lock, flags);
 	return rv;
 }
+EXPORT_SYMBOL(nvram_check_checksum);
 
-static void
-__nvram_set_checksum(void)
+static void __nvram_set_checksum(void)
 {
 	mach_set_checksum();
 }
 
 #if 0
-void
-nvram_set_checksum(void)
+void nvram_set_checksum(void)
 {
 	unsigned long flags;
 
@@ -212,7 +212,7 @@
  * The are the file operation function for user access to /dev/nvram
  */
 
-static loff_t nvram_llseek(struct file *file,loff_t offset, int origin )
+static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
 {
 	lock_kernel();
 	switch (origin) {
@@ -230,8 +230,8 @@
 	return (offset >= 0) ? (file->f_pos = offset) : -EINVAL;
 }
 
-static ssize_t
-nvram_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+static ssize_t nvram_read(struct file *file, char __user *buf,
+						size_t count, loff_t *ppos)
 {
 	unsigned char contents[NVRAM_BYTES];
 	unsigned i = *ppos;
@@ -254,13 +254,13 @@
 
 	return tmp - contents;
 
-      checksum_err:
+checksum_err:
 	spin_unlock_irq(&rtc_lock);
 	return -EIO;
 }
 
-static ssize_t
-nvram_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+static ssize_t nvram_write(struct file *file, const char __user *buf,
+						size_t count, loff_t *ppos)
 {
 	unsigned char contents[NVRAM_BYTES];
 	unsigned i = *ppos;
@@ -287,14 +287,13 @@
 
 	return tmp - contents;
 
-      checksum_err:
+checksum_err:
 	spin_unlock_irq(&rtc_lock);
 	return -EIO;
 }
 
-static int
-nvram_ioctl(struct inode *inode, struct file *file,
-    unsigned int cmd, unsigned long arg)
+static int nvram_ioctl(struct inode *inode, struct file *file,
+					unsigned int cmd, unsigned long arg)
 {
 	int i;
 
@@ -315,7 +314,7 @@
 		return 0;
 
 	case NVRAM_SETCKS:
-		/* just set checksum, contents unchanged (maybe useful after 
+		/* just set checksum, contents unchanged (maybe useful after
 		 * checksum garbaged somehow...) */
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
@@ -330,8 +329,7 @@
 	}
 }
 
-static int
-nvram_open(struct inode *inode, struct file *file)
+static int nvram_open(struct inode *inode, struct file *file)
 {
 	lock_kernel();
 	spin_lock(&nvram_state_lock);
@@ -356,8 +354,7 @@
 	return 0;
 }
 
-static int
-nvram_release(struct inode *inode, struct file *file)
+static int nvram_release(struct inode *inode, struct file *file)
 {
 	spin_lock(&nvram_state_lock);
 
@@ -375,48 +372,47 @@
 }
 
 #ifndef CONFIG_PROC_FS
-static int
-nvram_read_proc(char *buffer, char **start, off_t offset,
-    int size, int *eof, void *data)
+static int nvram_add_proc_fs(void)
 {
 	return 0;
 }
+
 #else
 
-static int
-nvram_read_proc(char *buffer, char **start, off_t offset,
-    int size, int *eof, void *data)
+static int nvram_proc_read(struct seq_file *seq, void *offset)
 {
 	unsigned char contents[NVRAM_BYTES];
-	int i, len = 0;
-	off_t begin = 0;
+	int i = 0;
 
 	spin_lock_irq(&rtc_lock);
 	for (i = 0; i < NVRAM_BYTES; ++i)
 		contents[i] = __nvram_read_byte(i);
 	spin_unlock_irq(&rtc_lock);
 
-	*eof = mach_proc_infos(contents, buffer, &len, &begin, offset, size);
+	mach_proc_infos(contents, seq, offset);
 
-	if (offset >= begin + len)
-		return 0;
-	*start = buffer + (offset - begin);
-	return (size < begin + len - offset) ? size : begin + len - offset;
-
+	return 0;
 }
 
-/* This macro frees the machine specific function from bounds checking and
- * this like that... */
-#define PRINT_PROC(fmt,args...)					\
-	do {							\
-		*len += sprintf(buffer+*len, fmt, ##args);	\
-		if (*begin + *len > offset + size)		\
-			return 0;				\
-		if (*begin + *len < offset) {			\
-			*begin += *len;				\
-			*len = 0;				\
-		}						\
-	} while(0)
+static int nvram_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, nvram_proc_read, NULL);
+}
+
+static const struct file_operations nvram_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= nvram_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int nvram_add_proc_fs(void)
+{
+	if (!proc_create("driver/nvram", 0, NULL, &nvram_proc_fops))
+		return -ENOMEM;
+	return 0;
+}
 
 #endif /* CONFIG_PROC_FS */
 
@@ -436,8 +432,7 @@
 	&nvram_fops
 };
 
-static int __init
-nvram_init(void)
+static int __init nvram_init(void)
 {
 	int ret;
 
@@ -451,23 +446,21 @@
 		    NVRAM_MINOR);
 		goto out;
 	}
-	if (!create_proc_read_entry("driver/nvram", 0, NULL, nvram_read_proc,
-		NULL)) {
+	ret = nvram_add_proc_fs();
+	if (ret) {
 		printk(KERN_ERR "nvram: can't create /proc/driver/nvram\n");
-		ret = -ENOMEM;
 		goto outmisc;
 	}
 	ret = 0;
 	printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "\n");
-      out:
+out:
 	return ret;
-      outmisc:
+outmisc:
 	misc_deregister(&nvram_dev);
 	goto out;
 }
 
-static void __exit
-nvram_cleanup_module(void)
+static void __exit nvram_cleanup_module(void)
 {
 	remove_proc_entry("driver/nvram", NULL);
 	misc_deregister(&nvram_dev);
@@ -482,8 +475,7 @@
 
 #if MACH == PC
 
-static int
-pc_check_checksum(void)
+static int pc_check_checksum(void)
 {
 	int i;
 	unsigned short sum = 0;
@@ -493,11 +485,10 @@
 		sum += __nvram_read_byte(i);
 	expect = __nvram_read_byte(PC_CKS_LOC)<<8 |
 	    __nvram_read_byte(PC_CKS_LOC+1);
-	return ((sum & 0xffff) == expect);
+	return (sum & 0xffff) == expect;
 }
 
-static void
-pc_set_checksum(void)
+static void pc_set_checksum(void)
 {
 	int i;
 	unsigned short sum = 0;
@@ -522,9 +513,8 @@
 	"monochrome",
 };
 
-static int
-pc_proc_infos(unsigned char *nvram, char *buffer, int *len,
-    off_t *begin, off_t offset, int size)
+static void pc_proc_infos(unsigned char *nvram, struct seq_file *seq,
+								void *offset)
 {
 	int checksum;
 	int type;
@@ -533,56 +523,57 @@
 	checksum = __nvram_check_checksum();
 	spin_unlock_irq(&rtc_lock);
 
-	PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not ");
+	seq_printf(seq, "Checksum status: %svalid\n", checksum ? "" : "not ");
 
-	PRINT_PROC("# floppies     : %d\n",
+	seq_printf(seq, "# floppies     : %d\n",
 	    (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0);
-	PRINT_PROC("Floppy 0 type  : ");
+	seq_printf(seq, "Floppy 0 type  : ");
 	type = nvram[2] >> 4;
 	if (type < ARRAY_SIZE(floppy_types))
-		PRINT_PROC("%s\n", floppy_types[type]);
+		seq_printf(seq, "%s\n", floppy_types[type]);
 	else
-		PRINT_PROC("%d (unknown)\n", type);
-	PRINT_PROC("Floppy 1 type  : ");
+		seq_printf(seq, "%d (unknown)\n", type);
+	seq_printf(seq, "Floppy 1 type  : ");
 	type = nvram[2] & 0x0f;
 	if (type < ARRAY_SIZE(floppy_types))
-		PRINT_PROC("%s\n", floppy_types[type]);
+		seq_printf(seq, "%s\n", floppy_types[type]);
 	else
-		PRINT_PROC("%d (unknown)\n", type);
+		seq_printf(seq, "%d (unknown)\n", type);
 
-	PRINT_PROC("HD 0 type      : ");
+	seq_printf(seq, "HD 0 type      : ");
 	type = nvram[4] >> 4;
 	if (type)
-		PRINT_PROC("%02x\n", type == 0x0f ? nvram[11] : type);
+		seq_printf(seq, "%02x\n", type == 0x0f ? nvram[11] : type);
 	else
-		PRINT_PROC("none\n");
+		seq_printf(seq, "none\n");
 
-	PRINT_PROC("HD 1 type      : ");
+	seq_printf(seq, "HD 1 type      : ");
 	type = nvram[4] & 0x0f;
 	if (type)
-		PRINT_PROC("%02x\n", type == 0x0f ? nvram[12] : type);
+		seq_printf(seq, "%02x\n", type == 0x0f ? nvram[12] : type);
 	else
-		PRINT_PROC("none\n");
+		seq_printf(seq, "none\n");
 
-	PRINT_PROC("HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+	seq_printf(seq, "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
 	    nvram[18] | (nvram[19] << 8),
 	    nvram[20], nvram[25],
 	    nvram[21] | (nvram[22] << 8), nvram[23] | (nvram[24] << 8));
-	PRINT_PROC("HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+	seq_printf(seq, "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
 	    nvram[39] | (nvram[40] << 8),
 	    nvram[41], nvram[46],
 	    nvram[42] | (nvram[43] << 8), nvram[44] | (nvram[45] << 8));
 
-	PRINT_PROC("DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8));
-	PRINT_PROC("Extended memory: %d kB (configured), %d kB (tested)\n",
+	seq_printf(seq, "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8));
+	seq_printf(seq, "Extended memory: %d kB (configured), %d kB (tested)\n",
 	    nvram[9] | (nvram[10] << 8), nvram[34] | (nvram[35] << 8));
 
-	PRINT_PROC("Gfx adapter    : %s\n", gfx_types[(nvram[6] >> 4) & 3]);
+	seq_printf(seq, "Gfx adapter    : %s\n",
+	    gfx_types[(nvram[6] >> 4) & 3]);
 
-	PRINT_PROC("FPU            : %sinstalled\n",
+	seq_printf(seq, "FPU            : %sinstalled\n",
 	    (nvram[6] & 2) ? "" : "not ");
 
-	return 1;
+	return;
 }
 #endif
 
@@ -590,20 +581,18 @@
 
 #if MACH == ATARI
 
-static int
-atari_check_checksum(void)
+static int atari_check_checksum(void)
 {
 	int i;
 	unsigned char sum = 0;
 
 	for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
 		sum += __nvram_read_byte(i);
-	return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff) &&
-	    __nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff));
+	return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff)) &&
+	    (__nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff));
 }
 
-static void
-atari_set_checksum(void)
+static void atari_set_checksum(void)
 {
 	int i;
 	unsigned char sum = 0;
@@ -654,82 +643,75 @@
 	"2", "4", "16", "256", "65536", "??", "??", "??"
 };
 
-static int
-atari_proc_infos(unsigned char *nvram, char *buffer, int *len,
-    off_t *begin, off_t offset, int size)
+static void atari_proc_infos(unsigned char *nvram, struct seq_file *seq,
+								void *offset)
 {
 	int checksum = nvram_check_checksum();
 	int i;
 	unsigned vmode;
 
-	PRINT_PROC("Checksum status  : %svalid\n", checksum ? "" : "not ");
+	seq_printf(seq, "Checksum status  : %svalid\n", checksum ? "" : "not ");
 
-	PRINT_PROC("Boot preference  : ");
+	seq_printf(seq, "Boot preference  : ");
 	for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i) {
 		if (nvram[1] == boot_prefs[i].val) {
-			PRINT_PROC("%s\n", boot_prefs[i].name);
+			seq_printf(seq, "%s\n", boot_prefs[i].name);
 			break;
 		}
 	}
 	if (i < 0)
-		PRINT_PROC("0x%02x (undefined)\n", nvram[1]);
+		seq_printf(seq, "0x%02x (undefined)\n", nvram[1]);
 
-	PRINT_PROC("SCSI arbitration : %s\n",
+	seq_printf(seq, "SCSI arbitration : %s\n",
 	    (nvram[16] & 0x80) ? "on" : "off");
-	PRINT_PROC("SCSI host ID     : ");
+	seq_printf(seq, "SCSI host ID     : ");
 	if (nvram[16] & 0x80)
-		PRINT_PROC("%d\n", nvram[16] & 7);
+		seq_printf(seq, "%d\n", nvram[16] & 7);
 	else
-		PRINT_PROC("n/a\n");
+		seq_printf(seq, "n/a\n");
 
 	/* the following entries are defined only for the Falcon */
 	if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
-		return 1;
+		return;
 
-	PRINT_PROC("OS language      : ");
+	seq_printf(seq, "OS language      : ");
 	if (nvram[6] < ARRAY_SIZE(languages))
-		PRINT_PROC("%s\n", languages[nvram[6]]);
+		seq_printf(seq, "%s\n", languages[nvram[6]]);
 	else
-		PRINT_PROC("%u (undefined)\n", nvram[6]);
-	PRINT_PROC("Keyboard language: ");
+		seq_printf(seq, "%u (undefined)\n", nvram[6]);
+	seq_printf(seq, "Keyboard language: ");
 	if (nvram[7] < ARRAY_SIZE(languages))
-		PRINT_PROC("%s\n", languages[nvram[7]]);
+		seq_printf(seq, "%s\n", languages[nvram[7]]);
 	else
-		PRINT_PROC("%u (undefined)\n", nvram[7]);
-	PRINT_PROC("Date format      : ");
-	PRINT_PROC(dateformat[nvram[8] & 7],
+		seq_printf(seq, "%u (undefined)\n", nvram[7]);
+	seq_printf(seq, "Date format      : ");
+	seq_printf(seq, dateformat[nvram[8] & 7],
 	    nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/');
-	PRINT_PROC(", %dh clock\n", nvram[8] & 16 ? 24 : 12);
-	PRINT_PROC("Boot delay       : ");
+	seq_printf(seq, ", %dh clock\n", nvram[8] & 16 ? 24 : 12);
+	seq_printf(seq, "Boot delay       : ");
 	if (nvram[10] == 0)
-		PRINT_PROC("default");
+		seq_printf(seq, "default");
 	else
-		PRINT_PROC("%ds%s\n", nvram[10],
+		seq_printf(seq, "%ds%s\n", nvram[10],
 		    nvram[10] < 8 ? ", no memory test" : "");
 
 	vmode = (nvram[14] << 8) || nvram[15];
-	PRINT_PROC("Video mode       : %s colors, %d columns, %s %s monitor\n",
+	seq_printf(seq,
+	    "Video mode       : %s colors, %d columns, %s %s monitor\n",
 	    colors[vmode & 7],
 	    vmode & 8 ? 80 : 40,
 	    vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC");
-	PRINT_PROC("                   %soverscan, compat. mode %s%s\n",
+	seq_printf(seq, "                   %soverscan, compat. mode %s%s\n",
 	    vmode & 64 ? "" : "no ",
 	    vmode & 128 ? "on" : "off",
 	    vmode & 256 ?
 	    (vmode & 16 ? ", line doubling" : ", half screen") : "");
 
-	return 1;
+	return;
 }
 #endif
 
 #endif /* MACH == ATARI */
 
 MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(__nvram_read_byte);
-EXPORT_SYMBOL(nvram_read_byte);
-EXPORT_SYMBOL(__nvram_write_byte);
-EXPORT_SYMBOL(nvram_write_byte);
-EXPORT_SYMBOL(__nvram_check_checksum);
-EXPORT_SYMBOL(nvram_check_checksum);
 MODULE_ALIAS_MISCDEV(NVRAM_MINOR);
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index ce0d9da..94966ed 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -274,6 +274,22 @@
 	.enable_mask	= SYSRQ_ENABLE_DUMP,
 };
 
+#ifdef CONFIG_TRACING
+#include <linux/ftrace.h>
+
+static void sysrq_ftrace_dump(int key, struct tty_struct *tty)
+{
+	ftrace_dump();
+}
+static struct sysrq_key_op sysrq_ftrace_dump_op = {
+	.handler	= sysrq_ftrace_dump,
+	.help_msg	= "dumpZ-ftrace-buffer",
+	.action_msg	= "Dump ftrace buffer",
+	.enable_mask	= SYSRQ_ENABLE_DUMP,
+};
+#else
+#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)0)
+#endif
 
 static void sysrq_handle_showmem(int key, struct tty_struct *tty)
 {
@@ -406,7 +422,7 @@
 	NULL,				/* x */
 	/* y: May be registered on sparc64 for global register dump */
 	NULL,				/* y */
-	NULL				/* z */
+	&sysrq_ftrace_dump_op,		/* z */
 };
 
 /* key2index calculation, -1 on invalid index */
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
index 5787249..34ab6d7 100644
--- a/drivers/char/tty_audit.c
+++ b/drivers/char/tty_audit.c
@@ -67,6 +67,29 @@
 		tty_audit_buf_free(buf);
 }
 
+static void tty_audit_log(const char *description, struct task_struct *tsk,
+			  uid_t loginuid, unsigned sessionid, int major,
+			  int minor, unsigned char *data, size_t size)
+{
+	struct audit_buffer *ab;
+
+	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
+	if (ab) {
+		char name[sizeof(tsk->comm)];
+		uid_t uid = task_uid(tsk);
+
+		audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
+				 "major=%d minor=%d comm=", description,
+				 tsk->pid, uid, loginuid, sessionid,
+				 major, minor);
+		get_task_comm(name, tsk);
+		audit_log_untrustedstring(ab, name);
+		audit_log_format(ab, " data=");
+		audit_log_n_hex(ab, data, size);
+		audit_log_end(ab);
+	}
+}
+
 /**
  *	tty_audit_buf_push	-	Push buffered data out
  *
@@ -77,25 +100,12 @@
 			       unsigned int sessionid,
 			       struct tty_audit_buf *buf)
 {
-	struct audit_buffer *ab;
-
 	if (buf->valid == 0)
 		return;
 	if (audit_enabled == 0)
 		return;
-	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
-	if (ab) {
-		char name[sizeof(tsk->comm)];
-
-		audit_log_format(ab, "tty pid=%u uid=%u auid=%u ses=%u "
-				 "major=%d minor=%d comm=", tsk->pid, tsk->uid,
-				 loginuid, sessionid, buf->major, buf->minor);
-		get_task_comm(name, tsk);
-		audit_log_untrustedstring(ab, name);
-		audit_log_format(ab, " data=");
-		audit_log_n_hex(ab, buf->data, buf->valid);
-		audit_log_end(ab);
-	}
+	tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
+		      buf->data, buf->valid);
 	buf->valid = 0;
 }
 
@@ -150,6 +160,42 @@
 }
 
 /**
+ *	tty_audit_tiocsti	-	Log TIOCSTI
+ */
+void tty_audit_tiocsti(struct tty_struct *tty, char ch)
+{
+	struct tty_audit_buf *buf;
+	int major, minor, should_audit;
+
+	spin_lock_irq(&current->sighand->siglock);
+	should_audit = current->signal->audit_tty;
+	buf = current->signal->tty_audit_buf;
+	if (buf)
+		atomic_inc(&buf->count);
+	spin_unlock_irq(&current->sighand->siglock);
+
+	major = tty->driver->major;
+	minor = tty->driver->minor_start + tty->index;
+	if (buf) {
+		mutex_lock(&buf->mutex);
+		if (buf->major == major && buf->minor == minor)
+			tty_audit_buf_push_current(buf);
+		mutex_unlock(&buf->mutex);
+		tty_audit_buf_put(buf);
+	}
+
+	if (should_audit && audit_enabled) {
+		uid_t auid;
+		unsigned int sessionid;
+
+		auid = audit_get_loginuid(current);
+		sessionid = audit_get_sessionid(current);
+		tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
+			      minor, &ch, 1);
+	}
+}
+
+/**
  *	tty_audit_push_task	-	Flush task's pending audit data
  */
 void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 1412a8d..db15f9b 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2018,6 +2018,7 @@
 		return -EPERM;
 	if (get_user(ch, p))
 		return -EFAULT;
+	tty_audit_tiocsti(tty, ch);
 	ld = tty_ldisc_ref_wait(tty);
 	ld->ops->receive_buf(tty, &ch, &mbz, 1);
 	tty_ldisc_deref(ld);
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 5c9f67f..c5afc98 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -106,6 +106,7 @@
 	struct proc_event *ev;
 	__u8 buffer[CN_PROC_MSG_SIZE];
 	struct timespec ts;
+	const struct cred *cred;
 
 	if (atomic_read(&proc_event_num_listeners) < 1)
 		return;
@@ -115,14 +116,19 @@
 	ev->what = which_id;
 	ev->event_data.id.process_pid = task->pid;
 	ev->event_data.id.process_tgid = task->tgid;
+	rcu_read_lock();
+	cred = __task_cred(task);
 	if (which_id == PROC_EVENT_UID) {
-	 	ev->event_data.id.r.ruid = task->uid;
-	 	ev->event_data.id.e.euid = task->euid;
+		ev->event_data.id.r.ruid = cred->uid;
+		ev->event_data.id.e.euid = cred->euid;
 	} else if (which_id == PROC_EVENT_GID) {
-	   	ev->event_data.id.r.rgid = task->gid;
-	   	ev->event_data.id.e.egid = task->egid;
-	} else
+		ev->event_data.id.r.rgid = cred->gid;
+		ev->event_data.id.e.egid = cred->egid;
+	} else {
+		rcu_read_unlock();
 	     	return;
+	}
+	rcu_read_unlock();
 	get_seq(&msg->seq, &ev->cpu);
 	ktime_get_ts(&ts); /* get high res monotonic timestamp */
 	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index 4d22b21..0c79fe7 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -38,9 +38,6 @@
 
 #include <asm/kmap_types.h>
 
-#undef dprintk
-
-#define HIFN_TEST
 //#define HIFN_DEBUG
 
 #ifdef HIFN_DEBUG
@@ -363,14 +360,14 @@
 #define HIFN_NAMESIZE			32
 #define HIFN_MAX_RESULT_ORDER		5
 
-#define	HIFN_D_CMD_RSIZE		24*4
-#define	HIFN_D_SRC_RSIZE		80*4
-#define	HIFN_D_DST_RSIZE		80*4
-#define	HIFN_D_RES_RSIZE		24*4
+#define	HIFN_D_CMD_RSIZE		24*1
+#define	HIFN_D_SRC_RSIZE		80*1
+#define	HIFN_D_DST_RSIZE		80*1
+#define	HIFN_D_RES_RSIZE		24*1
 
 #define HIFN_D_DST_DALIGN		4
 
-#define HIFN_QUEUE_LENGTH		HIFN_D_CMD_RSIZE-1
+#define HIFN_QUEUE_LENGTH		(HIFN_D_CMD_RSIZE - 1)
 
 #define AES_MIN_KEY_SIZE		16
 #define AES_MAX_KEY_SIZE		32
@@ -406,8 +403,6 @@
 	u8			command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND];
 	u8			result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT];
 
-	u64			test_src, test_dst;
-
 	/*
 	 *  Our current positions for insertion and removal from the descriptor
 	 *  rings.
@@ -434,9 +429,6 @@
 	struct pci_dev		*pdev;
 	void __iomem		*bar[3];
 
-	unsigned long		result_mem;
-	dma_addr_t		dst;
-
 	void			*desc_virt;
 	dma_addr_t		desc_dma;
 
@@ -446,8 +438,6 @@
 
 	spinlock_t		lock;
 
-	void 			*priv;
-
 	u32			flags;
 	int			active, started;
 	struct delayed_work	work;
@@ -657,12 +647,17 @@
 
 struct hifn_context
 {
-	u8			key[HIFN_MAX_CRYPT_KEY_LENGTH], *iv;
+	u8			key[HIFN_MAX_CRYPT_KEY_LENGTH];
 	struct hifn_device	*dev;
-	unsigned int		keysize, ivsize;
+	unsigned int		keysize;
+};
+
+struct hifn_request_context
+{
+	u8			*iv;
+	unsigned int		ivsize;
 	u8			op, type, mode, unused;
 	struct ablkcipher_walk	walk;
-	atomic_t		sg_num;
 };
 
 #define crypto_alg_to_hifn(a)	container_of(a, struct hifn_crypto_alg, alg)
@@ -1168,7 +1163,8 @@
 }
 
 static int hifn_setup_cmd_desc(struct hifn_device *dev,
-		struct hifn_context *ctx, void *priv, unsigned int nbytes)
+		struct hifn_context *ctx, struct hifn_request_context *rctx,
+		void *priv, unsigned int nbytes)
 {
 	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
 	int cmd_len, sa_idx;
@@ -1179,7 +1175,7 @@
 	buf_pos = buf = dma->command_bufs[dma->cmdi];
 
 	mask = 0;
-	switch (ctx->op) {
+	switch (rctx->op) {
 		case ACRYPTO_OP_DECRYPT:
 			mask = HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE;
 			break;
@@ -1196,15 +1192,15 @@
 	buf_pos += hifn_setup_base_command(dev, buf_pos, nbytes,
 			nbytes, mask, dev->snum);
 
-	if (ctx->op == ACRYPTO_OP_ENCRYPT || ctx->op == ACRYPTO_OP_DECRYPT) {
+	if (rctx->op == ACRYPTO_OP_ENCRYPT || rctx->op == ACRYPTO_OP_DECRYPT) {
 		u16 md = 0;
 
 		if (ctx->keysize)
 			md |= HIFN_CRYPT_CMD_NEW_KEY;
-		if (ctx->iv && ctx->mode != ACRYPTO_MODE_ECB)
+		if (rctx->iv && rctx->mode != ACRYPTO_MODE_ECB)
 			md |= HIFN_CRYPT_CMD_NEW_IV;
 
-		switch (ctx->mode) {
+		switch (rctx->mode) {
 			case ACRYPTO_MODE_ECB:
 				md |= HIFN_CRYPT_CMD_MODE_ECB;
 				break;
@@ -1221,7 +1217,7 @@
 				goto err_out;
 		}
 
-		switch (ctx->type) {
+		switch (rctx->type) {
 			case ACRYPTO_TYPE_AES_128:
 				if (ctx->keysize != 16)
 					goto err_out;
@@ -1256,17 +1252,18 @@
 
 		buf_pos += hifn_setup_crypto_command(dev, buf_pos,
 				nbytes, nbytes, ctx->key, ctx->keysize,
-				ctx->iv, ctx->ivsize, md);
+				rctx->iv, rctx->ivsize, md);
 	}
 
 	dev->sa[sa_idx] = priv;
+	dev->started++;
 
 	cmd_len = buf_pos - buf;
 	dma->cmdr[dma->cmdi].l = __cpu_to_le32(cmd_len | HIFN_D_VALID |
 			HIFN_D_LAST | HIFN_D_MASKDONEIRQ);
 
 	if (++dma->cmdi == HIFN_D_CMD_RSIZE) {
-		dma->cmdr[dma->cmdi].l = __cpu_to_le32(HIFN_MAX_COMMAND |
+		dma->cmdr[dma->cmdi].l = __cpu_to_le32(
 			HIFN_D_VALID | HIFN_D_LAST |
 			HIFN_D_MASKDONEIRQ | HIFN_D_JUMP);
 		dma->cmdi = 0;
@@ -1284,7 +1281,7 @@
 }
 
 static int hifn_setup_src_desc(struct hifn_device *dev, struct page *page,
-		unsigned int offset, unsigned int size)
+		unsigned int offset, unsigned int size, int last)
 {
 	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
 	int idx;
@@ -1296,12 +1293,12 @@
 
 	dma->srcr[idx].p = __cpu_to_le32(addr);
 	dma->srcr[idx].l = __cpu_to_le32(size | HIFN_D_VALID |
-			HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+			HIFN_D_MASKDONEIRQ | (last ? HIFN_D_LAST : 0));
 
 	if (++idx == HIFN_D_SRC_RSIZE) {
 		dma->srcr[idx].l = __cpu_to_le32(HIFN_D_VALID |
-				HIFN_D_JUMP |
-				HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+				HIFN_D_JUMP | HIFN_D_MASKDONEIRQ |
+				(last ? HIFN_D_LAST : 0));
 		idx = 0;
 	}
 
@@ -1342,7 +1339,7 @@
 }
 
 static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page,
-		unsigned offset, unsigned size)
+		unsigned offset, unsigned size, int last)
 {
 	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
 	int idx;
@@ -1353,12 +1350,12 @@
 	idx = dma->dsti;
 	dma->dstr[idx].p = __cpu_to_le32(addr);
 	dma->dstr[idx].l = __cpu_to_le32(size |	HIFN_D_VALID |
-			HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+			HIFN_D_MASKDONEIRQ | (last ? HIFN_D_LAST : 0));
 
 	if (++idx == HIFN_D_DST_RSIZE) {
 		dma->dstr[idx].l = __cpu_to_le32(HIFN_D_VALID |
 				HIFN_D_JUMP | HIFN_D_MASKDONEIRQ |
-				HIFN_D_LAST);
+				(last ? HIFN_D_LAST : 0));
 		idx = 0;
 	}
 	dma->dsti = idx;
@@ -1370,16 +1367,52 @@
 	}
 }
 
-static int hifn_setup_dma(struct hifn_device *dev, struct page *spage, unsigned int soff,
-		struct page *dpage, unsigned int doff, unsigned int nbytes, void *priv,
-		struct hifn_context *ctx)
+static int hifn_setup_dma(struct hifn_device *dev,
+		struct hifn_context *ctx, struct hifn_request_context *rctx,
+		struct scatterlist *src, struct scatterlist *dst,
+		unsigned int nbytes, void *priv)
 {
-	dprintk("%s: spage: %p, soffset: %u, dpage: %p, doffset: %u, nbytes: %u, priv: %p, ctx: %p.\n",
-			dev->name, spage, soff, dpage, doff, nbytes, priv, ctx);
+	struct scatterlist *t;
+	struct page *spage, *dpage;
+	unsigned int soff, doff;
+	unsigned int n, len;
 
-	hifn_setup_src_desc(dev, spage, soff, nbytes);
-	hifn_setup_cmd_desc(dev, ctx, priv, nbytes);
-	hifn_setup_dst_desc(dev, dpage, doff, nbytes);
+	n = nbytes;
+	while (n) {
+		spage = sg_page(src);
+		soff = src->offset;
+		len = min(src->length, n);
+
+		hifn_setup_src_desc(dev, spage, soff, len, n - len == 0);
+
+		src++;
+		n -= len;
+	}
+
+	t = &rctx->walk.cache[0];
+	n = nbytes;
+	while (n) {
+		if (t->length && rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
+			BUG_ON(!sg_page(t));
+			dpage = sg_page(t);
+			doff = 0;
+			len = t->length;
+		} else {
+			BUG_ON(!sg_page(dst));
+			dpage = sg_page(dst);
+			doff = dst->offset;
+			len = dst->length;
+		}
+		len = min(len, n);
+
+		hifn_setup_dst_desc(dev, dpage, doff, len, n - len == 0);
+
+		dst++;
+		t++;
+		n -= len;
+	}
+
+	hifn_setup_cmd_desc(dev, ctx, rctx, priv, nbytes);
 	hifn_setup_res_desc(dev);
 	return 0;
 }
@@ -1424,32 +1457,26 @@
 	w->num = 0;
 }
 
-static int ablkcipher_add(void *daddr, unsigned int *drestp, struct scatterlist *src,
+static int ablkcipher_add(unsigned int *drestp, struct scatterlist *dst,
 		unsigned int size, unsigned int *nbytesp)
 {
 	unsigned int copy, drest = *drestp, nbytes = *nbytesp;
 	int idx = 0;
-	void *saddr;
 
 	if (drest < size || size > nbytes)
 		return -EINVAL;
 
 	while (size) {
-		copy = min(drest, min(size, src->length));
-
-		saddr = kmap_atomic(sg_page(src), KM_SOFTIRQ1);
-		memcpy(daddr, saddr + src->offset, copy);
-		kunmap_atomic(saddr, KM_SOFTIRQ1);
+		copy = min(drest, min(size, dst->length));
 
 		size -= copy;
 		drest -= copy;
 		nbytes -= copy;
-		daddr += copy;
 
 		dprintk("%s: copy: %u, size: %u, drest: %u, nbytes: %u.\n",
 				__func__, copy, size, drest, nbytes);
 
-		src++;
+		dst++;
 		idx++;
 	}
 
@@ -1462,8 +1489,7 @@
 static int ablkcipher_walk(struct ablkcipher_request *req,
 		struct ablkcipher_walk *w)
 {
-	struct scatterlist *src, *dst, *t;
-	void *daddr;
+	struct scatterlist *dst, *t;
 	unsigned int nbytes = req->nbytes, offset, copy, diff;
 	int idx, tidx, err;
 
@@ -1473,26 +1499,22 @@
 		if (idx >= w->num && (w->flags & ASYNC_FLAGS_MISALIGNED))
 			return -EINVAL;
 
-		src = &req->src[idx];
 		dst = &req->dst[idx];
 
-		dprintk("\n%s: slen: %u, dlen: %u, soff: %u, doff: %u, offset: %u, "
-				"nbytes: %u.\n",
-				__func__, src->length, dst->length, src->offset,
-				dst->offset, offset, nbytes);
+		dprintk("\n%s: dlen: %u, doff: %u, offset: %u, nbytes: %u.\n",
+			__func__, dst->length, dst->offset, offset, nbytes);
 
 		if (!IS_ALIGNED(dst->offset, HIFN_D_DST_DALIGN) ||
 		    !IS_ALIGNED(dst->length, HIFN_D_DST_DALIGN) ||
 		    offset) {
-			unsigned slen = min(src->length - offset, nbytes);
+			unsigned slen = min(dst->length - offset, nbytes);
 			unsigned dlen = PAGE_SIZE;
 
 			t = &w->cache[idx];
 
-			daddr = kmap_atomic(sg_page(t), KM_SOFTIRQ0);
-			err = ablkcipher_add(daddr, &dlen, src, slen, &nbytes);
+			err = ablkcipher_add(&dlen, dst, slen, &nbytes);
 			if (err < 0)
-				goto err_out_unmap;
+				return err;
 
 			idx += err;
 
@@ -1528,21 +1550,19 @@
 			} else {
 				copy += diff + nbytes;
 
-				src = &req->src[idx];
+				dst = &req->dst[idx];
 
-				err = ablkcipher_add(daddr + slen, &dlen, src, nbytes, &nbytes);
+				err = ablkcipher_add(&dlen, dst, nbytes, &nbytes);
 				if (err < 0)
-					goto err_out_unmap;
+					return err;
 
 				idx += err;
 			}
 
 			t->length = copy;
 			t->offset = offset;
-
-			kunmap_atomic(daddr, KM_SOFTIRQ0);
 		} else {
-			nbytes -= min(src->length, nbytes);
+			nbytes -= min(dst->length, nbytes);
 			idx++;
 		}
 
@@ -1550,26 +1570,22 @@
 	}
 
 	return tidx;
-
-err_out_unmap:
-	kunmap_atomic(daddr, KM_SOFTIRQ0);
-	return err;
 }
 
 static int hifn_setup_session(struct ablkcipher_request *req)
 {
 	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct hifn_request_context *rctx = ablkcipher_request_ctx(req);
 	struct hifn_device *dev = ctx->dev;
-	struct page *spage, *dpage;
-	unsigned long soff, doff, dlen, flags;
-	unsigned int nbytes = req->nbytes, idx = 0, len;
+	unsigned long dlen, flags;
+	unsigned int nbytes = req->nbytes, idx = 0;
 	int err = -EINVAL, sg_num;
-	struct scatterlist *src, *dst, *t;
+	struct scatterlist *dst;
 
-	if (ctx->iv && !ctx->ivsize && ctx->mode != ACRYPTO_MODE_ECB)
+	if (rctx->iv && !rctx->ivsize && rctx->mode != ACRYPTO_MODE_ECB)
 		goto err_out_exit;
 
-	ctx->walk.flags = 0;
+	rctx->walk.flags = 0;
 
 	while (nbytes) {
 		dst = &req->dst[idx];
@@ -1577,27 +1593,23 @@
 
 		if (!IS_ALIGNED(dst->offset, HIFN_D_DST_DALIGN) ||
 		    !IS_ALIGNED(dlen, HIFN_D_DST_DALIGN))
-			ctx->walk.flags |= ASYNC_FLAGS_MISALIGNED;
+			rctx->walk.flags |= ASYNC_FLAGS_MISALIGNED;
 
 		nbytes -= dlen;
 		idx++;
 	}
 
-	if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
-		err = ablkcipher_walk_init(&ctx->walk, idx, GFP_ATOMIC);
+	if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
+		err = ablkcipher_walk_init(&rctx->walk, idx, GFP_ATOMIC);
 		if (err < 0)
 			return err;
 	}
 
-	nbytes = req->nbytes;
-	idx = 0;
-
-	sg_num = ablkcipher_walk(req, &ctx->walk);
+	sg_num = ablkcipher_walk(req, &rctx->walk);
 	if (sg_num < 0) {
 		err = sg_num;
 		goto err_out_exit;
 	}
-	atomic_set(&ctx->sg_num, sg_num);
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->started + sg_num > HIFN_QUEUE_LENGTH) {
@@ -1605,37 +1617,11 @@
 		goto err_out;
 	}
 
+	err = hifn_setup_dma(dev, ctx, rctx, req->src, req->dst, req->nbytes, req);
+	if (err)
+		goto err_out;
+
 	dev->snum++;
-	dev->started += sg_num;
-
-	while (nbytes) {
-		src = &req->src[idx];
-		dst = &req->dst[idx];
-		t = &ctx->walk.cache[idx];
-
-		if (t->length) {
-			spage = dpage = sg_page(t);
-			soff = doff = 0;
-			len = t->length;
-		} else {
-			spage = sg_page(src);
-			soff = src->offset;
-
-			dpage = sg_page(dst);
-			doff = dst->offset;
-
-			len = dst->length;
-		}
-
-		idx++;
-
-		err = hifn_setup_dma(dev, spage, soff, dpage, doff, nbytes,
-				req, ctx);
-		if (err)
-			goto err_out;
-
-		nbytes -= min(len, nbytes);
-	}
 
 	dev->active = HIFN_DEFAULT_ACTIVE_NUM;
 	spin_unlock_irqrestore(&dev->lock, flags);
@@ -1645,12 +1631,13 @@
 err_out:
 	spin_unlock_irqrestore(&dev->lock, flags);
 err_out_exit:
-	if (err)
-		dprintk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, "
+	if (err) {
+		printk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, "
 				"type: %u, err: %d.\n",
-			dev->name, ctx->iv, ctx->ivsize,
+			dev->name, rctx->iv, rctx->ivsize,
 			ctx->key, ctx->keysize,
-			ctx->mode, ctx->op, ctx->type, err);
+			rctx->mode, rctx->op, rctx->type, err);
+	}
 
 	return err;
 }
@@ -1660,31 +1647,33 @@
 	int n, err;
 	u8 src[16];
 	struct hifn_context ctx;
+	struct hifn_request_context rctx;
 	u8 fips_aes_ecb_from_zero[16] = {
 		0x66, 0xE9, 0x4B, 0xD4,
 		0xEF, 0x8A, 0x2C, 0x3B,
 		0x88, 0x4C, 0xFA, 0x59,
 		0xCA, 0x34, 0x2B, 0x2E};
+	struct scatterlist sg;
 
 	memset(src, 0, sizeof(src));
 	memset(ctx.key, 0, sizeof(ctx.key));
 
 	ctx.dev = dev;
 	ctx.keysize = 16;
-	ctx.ivsize = 0;
-	ctx.iv = NULL;
-	ctx.op = (encdec)?ACRYPTO_OP_ENCRYPT:ACRYPTO_OP_DECRYPT;
-	ctx.mode = ACRYPTO_MODE_ECB;
-	ctx.type = ACRYPTO_TYPE_AES_128;
-	atomic_set(&ctx.sg_num, 1);
+	rctx.ivsize = 0;
+	rctx.iv = NULL;
+	rctx.op = (encdec)?ACRYPTO_OP_ENCRYPT:ACRYPTO_OP_DECRYPT;
+	rctx.mode = ACRYPTO_MODE_ECB;
+	rctx.type = ACRYPTO_TYPE_AES_128;
+	rctx.walk.cache[0].length = 0;
 
-	err = hifn_setup_dma(dev,
-			virt_to_page(src), offset_in_page(src),
-			virt_to_page(src), offset_in_page(src),
-			sizeof(src), NULL, &ctx);
+	sg_init_one(&sg, &src, sizeof(src));
+
+	err = hifn_setup_dma(dev, &ctx, &rctx, &sg, &sg, sizeof(src), NULL);
 	if (err)
 		goto err_out;
 
+	dev->started = 0;
 	msleep(200);
 
 	dprintk("%s: decoded: ", dev->name);
@@ -1711,6 +1700,7 @@
 {
 	int err;
 
+	dev->started = dev->active = 0;
 	hifn_reset_dma(dev, 1);
 
 	err = hifn_enable_crypto(dev);
@@ -1764,90 +1754,65 @@
 	return idx;
 }
 
+static inline void hifn_complete_sa(struct hifn_device *dev, int i)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->sa[i] = NULL;
+	dev->started--;
+	if (dev->started < 0)
+		printk("%s: started: %d.\n", __func__, dev->started);
+	spin_unlock_irqrestore(&dev->lock, flags);
+	BUG_ON(dev->started < 0);
+}
+
 static void hifn_process_ready(struct ablkcipher_request *req, int error)
 {
-	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
-	struct hifn_device *dev;
+	struct hifn_request_context *rctx = ablkcipher_request_ctx(req);
 
-	dprintk("%s: req: %p, ctx: %p.\n", __func__, req, ctx);
-
-	dev = ctx->dev;
-	dprintk("%s: req: %p, started: %d, sg_num: %d.\n",
-		__func__, req, dev->started, atomic_read(&ctx->sg_num));
-
-	if (--dev->started < 0)
-		BUG();
-
-	if (atomic_dec_and_test(&ctx->sg_num)) {
+	if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
 		unsigned int nbytes = req->nbytes;
 		int idx = 0, err;
 		struct scatterlist *dst, *t;
 		void *saddr;
 
-		if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
-			while (nbytes) {
-				t = &ctx->walk.cache[idx];
-				dst = &req->dst[idx];
+		while (nbytes) {
+			t = &rctx->walk.cache[idx];
+			dst = &req->dst[idx];
 
-				dprintk("\n%s: sg_page(t): %p, t->length: %u, "
-					"sg_page(dst): %p, dst->length: %u, "
-					"nbytes: %u.\n",
-					__func__, sg_page(t), t->length,
-					sg_page(dst), dst->length, nbytes);
+			dprintk("\n%s: sg_page(t): %p, t->length: %u, "
+				"sg_page(dst): %p, dst->length: %u, "
+				"nbytes: %u.\n",
+				__func__, sg_page(t), t->length,
+				sg_page(dst), dst->length, nbytes);
 
-				if (!t->length) {
-					nbytes -= min(dst->length, nbytes);
-					idx++;
-					continue;
-				}
-
-				saddr = kmap_atomic(sg_page(t), KM_IRQ1);
-
-				err = ablkcipher_get(saddr, &t->length, t->offset,
-						dst, nbytes, &nbytes);
-				if (err < 0) {
-					kunmap_atomic(saddr, KM_IRQ1);
-					break;
-				}
-
-				idx += err;
-				kunmap_atomic(saddr, KM_IRQ1);
+			if (!t->length) {
+				nbytes -= min(dst->length, nbytes);
+				idx++;
+				continue;
 			}
 
-			ablkcipher_walk_exit(&ctx->walk);
+			saddr = kmap_atomic(sg_page(t), KM_SOFTIRQ0);
+
+			err = ablkcipher_get(saddr, &t->length, t->offset,
+					dst, nbytes, &nbytes);
+			if (err < 0) {
+				kunmap_atomic(saddr, KM_SOFTIRQ0);
+				break;
+			}
+
+			idx += err;
+			kunmap_atomic(saddr, KM_SOFTIRQ0);
 		}
 
-		req->base.complete(&req->base, error);
+		ablkcipher_walk_exit(&rctx->walk);
 	}
+
+	req->base.complete(&req->base, error);
 }
 
-static void hifn_check_for_completion(struct hifn_device *dev, int error)
-{
-	int i;
-	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
-
-	for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
-		struct hifn_desc *d = &dma->resr[i];
-
-		if (!(d->l & __cpu_to_le32(HIFN_D_VALID)) && dev->sa[i]) {
-			dev->success++;
-			dev->reset = 0;
-			hifn_process_ready(dev->sa[i], error);
-			dev->sa[i] = NULL;
-		}
-
-		if (d->l & __cpu_to_le32(HIFN_D_DESTOVER | HIFN_D_OVER))
-			if (printk_ratelimit())
-				printk("%s: overflow detected [d: %u, o: %u] "
-						"at %d resr: l: %08x, p: %08x.\n",
-					dev->name,
-					!!(d->l & __cpu_to_le32(HIFN_D_DESTOVER)),
-					!!(d->l & __cpu_to_le32(HIFN_D_OVER)),
-					i, d->l, d->p);
-	}
-}
-
-static void hifn_clear_rings(struct hifn_device *dev)
+static void hifn_clear_rings(struct hifn_device *dev, int error)
 {
 	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
 	int i, u;
@@ -1864,21 +1829,26 @@
 		if (dma->resr[i].l & __cpu_to_le32(HIFN_D_VALID))
 			break;
 
-		if (i != HIFN_D_RES_RSIZE)
-			u--;
+		if (dev->sa[i]) {
+			dev->success++;
+			dev->reset = 0;
+			hifn_process_ready(dev->sa[i], error);
+			hifn_complete_sa(dev, i);
+		}
 
-		if (++i == (HIFN_D_RES_RSIZE + 1))
+		if (++i == HIFN_D_RES_RSIZE)
 			i = 0;
+		u--;
 	}
 	dma->resk = i; dma->resu = u;
 
 	i = dma->srck; u = dma->srcu;
 	while (u != 0) {
-		if (i == HIFN_D_SRC_RSIZE)
-			i = 0;
 		if (dma->srcr[i].l & __cpu_to_le32(HIFN_D_VALID))
 			break;
-		i++, u--;
+		if (++i == HIFN_D_SRC_RSIZE)
+			i = 0;
+		u--;
 	}
 	dma->srck = i; dma->srcu = u;
 
@@ -1886,20 +1856,19 @@
 	while (u != 0) {
 		if (dma->cmdr[i].l & __cpu_to_le32(HIFN_D_VALID))
 			break;
-		if (i != HIFN_D_CMD_RSIZE)
-			u--;
-		if (++i == (HIFN_D_CMD_RSIZE + 1))
+		if (++i == HIFN_D_CMD_RSIZE)
 			i = 0;
+		u--;
 	}
 	dma->cmdk = i; dma->cmdu = u;
 
 	i = dma->dstk; u = dma->dstu;
 	while (u != 0) {
-		if (i == HIFN_D_DST_RSIZE)
-			i = 0;
 		if (dma->dstr[i].l & __cpu_to_le32(HIFN_D_VALID))
 			break;
-		i++, u--;
+		if (++i == HIFN_D_DST_RSIZE)
+			i = 0;
+		u--;
 	}
 	dma->dstk = i; dma->dstu = u;
 
@@ -1944,30 +1913,39 @@
 	} else
 		dev->active--;
 
-	if (dev->prev_success == dev->success && dev->started)
+	if ((dev->prev_success == dev->success) && dev->started)
 		reset = 1;
 	dev->prev_success = dev->success;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	if (reset) {
-		dprintk("%s: r: %08x, active: %d, started: %d, "
-				"success: %lu: reset: %d.\n",
-			dev->name, r, dev->active, dev->started,
-			dev->success, reset);
-
 		if (++dev->reset >= 5) {
-			dprintk("%s: really hard reset.\n", dev->name);
+			int i;
+			struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+
+			printk("%s: r: %08x, active: %d, started: %d, "
+				"success: %lu: qlen: %u/%u, reset: %d.\n",
+				dev->name, r, dev->active, dev->started,
+				dev->success, dev->queue.qlen, dev->queue.max_qlen,
+				reset);
+
+			printk("%s: res: ", __func__);
+			for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
+				printk("%x.%p ", dma->resr[i].l, dev->sa[i]);
+				if (dev->sa[i]) {
+					hifn_process_ready(dev->sa[i], -ENODEV);
+					hifn_complete_sa(dev, i);
+				}
+			}
+			printk("\n");
+
 			hifn_reset_dma(dev, 1);
 			hifn_stop_device(dev);
 			hifn_start_device(dev);
 			dev->reset = 0;
 		}
 
-		spin_lock_irqsave(&dev->lock, flags);
-		hifn_check_for_completion(dev, -EBUSY);
-		hifn_clear_rings(dev);
-		dev->started = 0;
-		spin_unlock_irqrestore(&dev->lock, flags);
+		tasklet_schedule(&dev->tasklet);
 	}
 
 	schedule_delayed_work(&dev->work, HZ);
@@ -1984,8 +1962,8 @@
 	dprintk("%s: 1 dmacsr: %08x, dmareg: %08x, res: %08x [%d], "
 			"i: %d.%d.%d.%d, u: %d.%d.%d.%d.\n",
 		dev->name, dmacsr, dev->dmareg, dmacsr & dev->dmareg, dma->cmdi,
-		dma->cmdu, dma->srcu, dma->dstu, dma->resu,
-		dma->cmdi, dma->srci, dma->dsti, dma->resi);
+		dma->cmdi, dma->srci, dma->dsti, dma->resi,
+		dma->cmdu, dma->srcu, dma->dstu, dma->resu);
 
 	if ((dmacsr & dev->dmareg) == 0)
 		return IRQ_NONE;
@@ -2002,11 +1980,10 @@
 	if (restart) {
 		u32 puisr = hifn_read_0(dev, HIFN_0_PUISR);
 
-		if (printk_ratelimit())
-			printk("%s: overflow: r: %d, d: %d, puisr: %08x, d: %u.\n",
-				dev->name, !!(dmacsr & HIFN_DMACSR_R_OVER),
-				!!(dmacsr & HIFN_DMACSR_D_OVER),
-				puisr, !!(puisr & HIFN_PUISR_DSTOVER));
+		printk(KERN_WARNING "%s: overflow: r: %d, d: %d, puisr: %08x, d: %u.\n",
+			dev->name, !!(dmacsr & HIFN_DMACSR_R_OVER),
+			!!(dmacsr & HIFN_DMACSR_D_OVER),
+			puisr, !!(puisr & HIFN_PUISR_DSTOVER));
 		if (!!(puisr & HIFN_PUISR_DSTOVER))
 			hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER);
 		hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & (HIFN_DMACSR_R_OVER |
@@ -2016,12 +1993,11 @@
 	restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT |
 			HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT);
 	if (restart) {
-		if (printk_ratelimit())
-			printk("%s: abort: c: %d, s: %d, d: %d, r: %d.\n",
-				dev->name, !!(dmacsr & HIFN_DMACSR_C_ABORT),
-				!!(dmacsr & HIFN_DMACSR_S_ABORT),
-				!!(dmacsr & HIFN_DMACSR_D_ABORT),
-				!!(dmacsr & HIFN_DMACSR_R_ABORT));
+		printk(KERN_WARNING "%s: abort: c: %d, s: %d, d: %d, r: %d.\n",
+			dev->name, !!(dmacsr & HIFN_DMACSR_C_ABORT),
+			!!(dmacsr & HIFN_DMACSR_S_ABORT),
+			!!(dmacsr & HIFN_DMACSR_D_ABORT),
+			!!(dmacsr & HIFN_DMACSR_R_ABORT));
 		hifn_reset_dma(dev, 1);
 		hifn_init_dma(dev);
 		hifn_init_registers(dev);
@@ -2034,7 +2010,6 @@
 	}
 
 	tasklet_schedule(&dev->tasklet);
-	hifn_clear_rings(dev);
 
 	return IRQ_HANDLED;
 }
@@ -2048,21 +2023,25 @@
 	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
 	int i;
 
-	spin_lock_irqsave(&dev->lock, flags);
 	for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
 		struct hifn_desc *d = &dma->resr[i];
 
 		if (dev->sa[i]) {
 			hifn_process_ready(dev->sa[i],
 				(d->l & __cpu_to_le32(HIFN_D_VALID))?-ENODEV:0);
+			hifn_complete_sa(dev, i);
 		}
 	}
 
+	spin_lock_irqsave(&dev->lock, flags);
 	while ((async_req = crypto_dequeue_request(&dev->queue))) {
 		ctx = crypto_tfm_ctx(async_req->tfm);
 		req = container_of(async_req, struct ablkcipher_request, base);
+		spin_unlock_irqrestore(&dev->lock, flags);
 
 		hifn_process_ready(req, -ENODEV);
+
+		spin_lock_irqsave(&dev->lock, flags);
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
 }
@@ -2121,6 +2100,7 @@
 		u8 type, u8 mode)
 {
 	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct hifn_request_context *rctx = ablkcipher_request_ctx(req);
 	unsigned ivsize;
 
 	ivsize = crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(req));
@@ -2141,11 +2121,11 @@
 			type = ACRYPTO_TYPE_AES_256;
 	}
 
-	ctx->op = op;
-	ctx->mode = mode;
-	ctx->type = type;
-	ctx->iv = req->info;
-	ctx->ivsize = ivsize;
+	rctx->op = op;
+	rctx->mode = mode;
+	rctx->type = type;
+	rctx->iv = req->info;
+	rctx->ivsize = ivsize;
 
 	/*
 	 * HEAVY TODO: needs to kick Herbert XU to write documentation.
@@ -2158,7 +2138,7 @@
 
 static int hifn_process_queue(struct hifn_device *dev)
 {
-	struct crypto_async_request *async_req;
+	struct crypto_async_request *async_req, *backlog;
 	struct hifn_context *ctx;
 	struct ablkcipher_request *req;
 	unsigned long flags;
@@ -2166,12 +2146,16 @@
 
 	while (dev->started < HIFN_QUEUE_LENGTH) {
 		spin_lock_irqsave(&dev->lock, flags);
+		backlog = crypto_get_backlog(&dev->queue);
 		async_req = crypto_dequeue_request(&dev->queue);
 		spin_unlock_irqrestore(&dev->lock, flags);
 
 		if (!async_req)
 			break;
 
+		if (backlog)
+			backlog->complete(backlog, -EINPROGRESS);
+
 		ctx = crypto_tfm_ctx(async_req->tfm);
 		req = container_of(async_req, struct ablkcipher_request, base);
 
@@ -2496,7 +2480,7 @@
 	struct hifn_context *ctx = crypto_tfm_ctx(tfm);
 
 	ctx->dev = ha->dev;
-
+	tfm->crt_ablkcipher.reqsize = sizeof(struct hifn_request_context);
 	return 0;
 }
 
@@ -2574,7 +2558,10 @@
 	 * (like dev->success), but they are used in process
 	 * context or update is atomic (like setting dev->sa[i] to NULL).
 	 */
-	hifn_check_for_completion(dev, 0);
+	hifn_clear_rings(dev, 0);
+
+	if (dev->started < HIFN_QUEUE_LENGTH &&	dev->queue.qlen)
+		hifn_process_queue(dev);
 }
 
 static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -2631,22 +2618,11 @@
 			goto err_out_unmap_bars;
 	}
 
-	dev->result_mem = __get_free_pages(GFP_KERNEL, HIFN_MAX_RESULT_ORDER);
-	if (!dev->result_mem) {
-		dprintk("Failed to allocate %d pages for result_mem.\n",
-				HIFN_MAX_RESULT_ORDER);
-		goto err_out_unmap_bars;
-	}
-	memset((void *)dev->result_mem, 0, PAGE_SIZE*(1<<HIFN_MAX_RESULT_ORDER));
-
-	dev->dst = pci_map_single(pdev, (void *)dev->result_mem,
-			PAGE_SIZE << HIFN_MAX_RESULT_ORDER, PCI_DMA_FROMDEVICE);
-
 	dev->desc_virt = pci_alloc_consistent(pdev, sizeof(struct hifn_dma),
 			&dev->desc_dma);
 	if (!dev->desc_virt) {
 		dprintk("Failed to allocate descriptor rings.\n");
-		goto err_out_free_result_pages;
+		goto err_out_unmap_bars;
 	}
 	memset(dev->desc_virt, 0, sizeof(struct hifn_dma));
 
@@ -2706,11 +2682,6 @@
 	pci_free_consistent(pdev, sizeof(struct hifn_dma),
 			dev->desc_virt, dev->desc_dma);
 
-err_out_free_result_pages:
-	pci_unmap_single(pdev, dev->dst, PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
-			PCI_DMA_FROMDEVICE);
-	free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
-
 err_out_unmap_bars:
 	for (i=0; i<3; ++i)
 		if (dev->bar[i])
@@ -2748,10 +2719,6 @@
 
 		pci_free_consistent(pdev, sizeof(struct hifn_dma),
 				dev->desc_virt, dev->desc_dma);
-		pci_unmap_single(pdev, dev->dst,
-				PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
-				PCI_DMA_FROMDEVICE);
-		free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
 		for (i=0; i<3; ++i)
 			if (dev->bar[i])
 				iounmap(dev->bar[i]);
@@ -2782,6 +2749,11 @@
 	unsigned int freq;
 	int err;
 
+	if (sizeof(dma_addr_t) > 4) {
+		printk(KERN_INFO "HIFN supports only 32-bit addresses.\n");
+		return -EINVAL;
+	}
+
 	if (strncmp(hifn_pll_ref, "ext", 3) &&
 	    strncmp(hifn_pll_ref, "pci", 3)) {
 		printk(KERN_ERR "hifn795x: invalid hifn_pll_ref clock, "
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index bf2917d..856b3cc 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -15,6 +15,8 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <linux/smp.h>
 #include <asm/byteorder.h>
 #include <asm/i387.h>
 #include "padlock.h"
@@ -49,6 +51,8 @@
 	u32 *D;
 };
 
+static DEFINE_PER_CPU(struct cword *, last_cword);
+
 /* Tells whether the ACE is capable to generate
    the extended key for a given key_len. */
 static inline int
@@ -89,6 +93,7 @@
 	const __le32 *key = (const __le32 *)in_key;
 	u32 *flags = &tfm->crt_flags;
 	struct crypto_aes_ctx gen_aes;
+	int cpu;
 
 	if (key_len % 8) {
 		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
@@ -118,7 +123,7 @@
 
 	/* Don't generate extended keys if the hardware can do it. */
 	if (aes_hw_extkey_available(key_len))
-		return 0;
+		goto ok;
 
 	ctx->D = ctx->d_data;
 	ctx->cword.encrypt.keygen = 1;
@@ -131,15 +136,30 @@
 
 	memcpy(ctx->E, gen_aes.key_enc, AES_MAX_KEYLENGTH);
 	memcpy(ctx->D, gen_aes.key_dec, AES_MAX_KEYLENGTH);
+
+ok:
+	for_each_online_cpu(cpu)
+		if (&ctx->cword.encrypt == per_cpu(last_cword, cpu) ||
+		    &ctx->cword.decrypt == per_cpu(last_cword, cpu))
+			per_cpu(last_cword, cpu) = NULL;
+
 	return 0;
 }
 
 /* ====== Encryption/decryption routines ====== */
 
 /* These are the real call to PadLock. */
-static inline void padlock_reset_key(void)
+static inline void padlock_reset_key(struct cword *cword)
 {
-	asm volatile ("pushfl; popfl");
+	int cpu = raw_smp_processor_id();
+
+	if (cword != per_cpu(last_cword, cpu))
+		asm volatile ("pushfl; popfl");
+}
+
+static inline void padlock_store_cword(struct cword *cword)
+{
+	per_cpu(last_cword, raw_smp_processor_id()) = cword;
 }
 
 /*
@@ -149,7 +169,7 @@
  */
 
 static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key,
-				  void *control_word)
+				  struct cword *control_word)
 {
 	asm volatile (".byte 0xf3,0x0f,0xa7,0xc8"	/* rep xcryptecb */
 		      : "+S"(input), "+D"(output)
@@ -213,22 +233,24 @@
 {
 	struct aes_ctx *ctx = aes_ctx(tfm);
 	int ts_state;
-	padlock_reset_key();
 
+	padlock_reset_key(&ctx->cword.encrypt);
 	ts_state = irq_ts_save();
 	aes_crypt(in, out, ctx->E, &ctx->cword.encrypt);
 	irq_ts_restore(ts_state);
+	padlock_store_cword(&ctx->cword.encrypt);
 }
 
 static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 	struct aes_ctx *ctx = aes_ctx(tfm);
 	int ts_state;
-	padlock_reset_key();
 
+	padlock_reset_key(&ctx->cword.encrypt);
 	ts_state = irq_ts_save();
 	aes_crypt(in, out, ctx->D, &ctx->cword.decrypt);
 	irq_ts_restore(ts_state);
+	padlock_store_cword(&ctx->cword.encrypt);
 }
 
 static struct crypto_alg aes_alg = {
@@ -261,7 +283,7 @@
 	int err;
 	int ts_state;
 
-	padlock_reset_key();
+	padlock_reset_key(&ctx->cword.encrypt);
 
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
@@ -276,6 +298,8 @@
 	}
 	irq_ts_restore(ts_state);
 
+	padlock_store_cword(&ctx->cword.encrypt);
+
 	return err;
 }
 
@@ -288,7 +312,7 @@
 	int err;
 	int ts_state;
 
-	padlock_reset_key();
+	padlock_reset_key(&ctx->cword.decrypt);
 
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
@@ -302,6 +326,9 @@
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 	}
 	irq_ts_restore(ts_state);
+
+	padlock_store_cword(&ctx->cword.encrypt);
+
 	return err;
 }
 
@@ -336,7 +363,7 @@
 	int err;
 	int ts_state;
 
-	padlock_reset_key();
+	padlock_reset_key(&ctx->cword.encrypt);
 
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
@@ -353,6 +380,8 @@
 	}
 	irq_ts_restore(ts_state);
 
+	padlock_store_cword(&ctx->cword.decrypt);
+
 	return err;
 }
 
@@ -365,7 +394,7 @@
 	int err;
 	int ts_state;
 
-	padlock_reset_key();
+	padlock_reset_key(&ctx->cword.encrypt);
 
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
@@ -380,6 +409,9 @@
 	}
 
 	irq_ts_restore(ts_state);
+
+	padlock_store_cword(&ctx->cword.encrypt);
+
 	return err;
 }
 
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 2460766..a3918c1 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -127,7 +127,6 @@
 
 	/* request callback tasklet */
 	struct tasklet_struct done_task;
-	struct tasklet_struct error_task;
 
 	/* list of registered algorithms */
 	struct list_head alg_list;
@@ -138,6 +137,7 @@
 
 /* .features flag */
 #define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001
+#define TALITOS_FTR_HW_AUTH_CHECK 0x00000002
 
 /*
  * map virtual single (contiguous) pointer to h/w descriptor pointer
@@ -184,6 +184,11 @@
 	setbits32(priv->reg + TALITOS_CCCR_LO(ch), TALITOS_CCCR_LO_CDWE |
 		  TALITOS_CCCR_LO_CDIE);
 
+	/* and ICCR writeback, if available */
+	if (priv->features & TALITOS_FTR_HW_AUTH_CHECK)
+		setbits32(priv->reg + TALITOS_CCCR_LO(ch),
+		          TALITOS_CCCR_LO_IWSE);
+
 	return 0;
 }
 
@@ -239,6 +244,11 @@
 	setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT);
 	setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);
 
+	/* disable integrity check error interrupts (use writeback instead) */
+	if (priv->features & TALITOS_FTR_HW_AUTH_CHECK)
+		setbits32(priv->reg + TALITOS_MDEUICR_LO,
+		          TALITOS_MDEUICR_LO_ICE);
+
 	return 0;
 }
 
@@ -370,6 +380,12 @@
 
 	for (ch = 0; ch < priv->num_channels; ch++)
 		flush_channel(dev, ch, 0, 0);
+
+	/* At this point, all completed channels have been processed.
+	 * Unmask done interrupts for channels completed later on.
+	 */
+	setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT);
+	setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);
 }
 
 /*
@@ -469,16 +485,13 @@
 /*
  * recover from error interrupts
  */
-static void talitos_error(unsigned long data)
+static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
 {
 	struct device *dev = (struct device *)data;
 	struct talitos_private *priv = dev_get_drvdata(dev);
 	unsigned int timeout = TALITOS_TIMEOUT;
 	int ch, error, reset_dev = 0, reset_ch = 0;
-	u32 isr, isr_lo, v, v_lo;
-
-	isr = in_be32(priv->reg + TALITOS_ISR);
-	isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);
+	u32 v, v_lo;
 
 	for (ch = 0; ch < priv->num_channels; ch++) {
 		/* skip channels without errors */
@@ -560,16 +573,19 @@
 
 	isr = in_be32(priv->reg + TALITOS_ISR);
 	isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);
-
-	/* ack */
+	/* Acknowledge interrupt */
 	out_be32(priv->reg + TALITOS_ICR, isr);
 	out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);
 
 	if (unlikely((isr & ~TALITOS_ISR_CHDONE) || isr_lo))
-		talitos_error((unsigned long)data);
+		talitos_error((unsigned long)data, isr, isr_lo);
 	else
-		if (likely(isr & TALITOS_ISR_CHDONE))
+		if (likely(isr & TALITOS_ISR_CHDONE)) {
+			/* mask further done interrupts. */
+			clrbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_DONE);
+			/* done_task will unmask done interrupts at exit */
 			tasklet_schedule(&priv->done_task);
+		}
 
 	return (isr || isr_lo) ? IRQ_HANDLED : IRQ_NONE;
 }
@@ -802,7 +818,7 @@
 	aead_request_complete(areq, err);
 }
 
-static void ipsec_esp_decrypt_done(struct device *dev,
+static void ipsec_esp_decrypt_swauth_done(struct device *dev,
 				   struct talitos_desc *desc, void *context,
 				   int err)
 {
@@ -834,6 +850,27 @@
 	aead_request_complete(req, err);
 }
 
+static void ipsec_esp_decrypt_hwauth_done(struct device *dev,
+				   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);
+
+	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;
+
+	kfree(edesc);
+
+	aead_request_complete(req, err);
+}
+
 /*
  * convert scatterlist to SEC h/w link table format
  * stop at cryptlen bytes
@@ -887,6 +924,7 @@
 	unsigned int authsize = ctx->authsize;
 	unsigned int ivsize;
 	int sg_count, ret;
+	int sg_link_tbl_len;
 
 	/* hmac key */
 	map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key,
@@ -924,33 +962,19 @@
 	if (sg_count == 1) {
 		desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src));
 	} else {
-		sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen,
+		sg_link_tbl_len = cryptlen;
+
+		if ((edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV) &&
+			(edesc->desc.hdr & DESC_HDR_MODE0_ENCRYPT) == 0) {
+			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) {
-			struct talitos_ptr *link_tbl_ptr =
-				&edesc->link_tbl[sg_count-1];
-			struct scatterlist *sg;
-			struct talitos_private *priv = dev_get_drvdata(dev);
-
 			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);
-			/* If necessary for this SEC revision,
-			 * add a link table entry for ICV.
-			 */
-			if ((priv->features &
-			     TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT) &&
-			    (edesc->desc.hdr & DESC_HDR_MODE0_ENCRYPT) == 0) {
-				link_tbl_ptr->j_extent = 0;
-				link_tbl_ptr++;
-				link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN;
-				link_tbl_ptr->len = cpu_to_be16(authsize);
-				sg = sg_last(areq->src, edesc->src_nents ? : 1);
-				link_tbl_ptr->ptr = cpu_to_be32(
-						(char *)sg_dma_address(sg)
-						+ sg->length - authsize);
-			}
 		} else {
 			/* Only one segment now, so no link tbl needed */
 			desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src));
@@ -975,13 +999,9 @@
 		desc->ptr[5].ptr = cpu_to_be32((struct talitos_ptr *)
 					       edesc->dma_link_tbl +
 					       edesc->src_nents + 1);
-		if (areq->src == areq->dst) {
-			memcpy(link_tbl_ptr, &edesc->link_tbl[0],
-			       edesc->src_nents * sizeof(struct talitos_ptr));
-		} else {
-			sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen,
-						  link_tbl_ptr);
-		}
+		sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen,
+					  link_tbl_ptr);
+
 		/* Add an entry to the link table for ICV data */
 		link_tbl_ptr += sg_count - 1;
 		link_tbl_ptr->j_extent = 0;
@@ -1106,11 +1126,14 @@
 	return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_encrypt_done);
 }
 
+
+
 static int aead_authenc_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 scatterlist *sg;
 	void *icvdata;
@@ -1122,22 +1145,39 @@
 	if (IS_ERR(edesc))
 		return PTR_ERR(edesc);
 
-	/* 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];
+	if ((priv->features & TALITOS_FTR_HW_AUTH_CHECK) &&
+	    (((!edesc->src_nents && !edesc->dst_nents) ||
+		priv->features & TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT))) {
 
-	sg = sg_last(req->src, edesc->src_nents ? : 1);
+		/* decrypt and check the ICV */
+		edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND |
+				  DESC_HDR_MODE1_MDEU_CICV;
 
-	memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize,
-	       ctx->authsize);
+		/* reset integrity check result bits */
+		edesc->desc.hdr_lo = 0;
 
-	/* decrypt */
-	edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
+		return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_hwauth_done);
 
-	return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_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);
+	}
 }
 
 static int aead_authenc_givencrypt(
@@ -1391,7 +1431,6 @@
 	}
 
 	tasklet_kill(&priv->done_task);
-	tasklet_kill(&priv->error_task);
 
 	iounmap(priv->reg);
 
@@ -1451,10 +1490,9 @@
 
 	priv->ofdev = ofdev;
 
-	INIT_LIST_HEAD(&priv->alg_list);
-
 	tasklet_init(&priv->done_task, talitos_done, (unsigned long)dev);
-	tasklet_init(&priv->error_task, talitos_error, (unsigned long)dev);
+
+	INIT_LIST_HEAD(&priv->alg_list);
 
 	priv->irq = irq_of_parse_and_map(np, 0);
 
@@ -1508,6 +1546,9 @@
 	if (of_device_is_compatible(np, "fsl,sec3.0"))
 		priv->features |= TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT;
 
+	if (of_device_is_compatible(np, "fsl,sec2.1"))
+		priv->features |= TALITOS_FTR_HW_AUTH_CHECK;
+
 	priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,
 				  GFP_KERNEL);
 	priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,
@@ -1551,7 +1592,7 @@
 		goto err_out;
 	}
 	for (i = 0; i < priv->num_channels; i++)
-		atomic_set(&priv->submit_count[i], -priv->chfifo_len);
+		atomic_set(&priv->submit_count[i], -(priv->chfifo_len - 1));
 
 	priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
 	priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h
index c48a405..575981f 100644
--- a/drivers/crypto/talitos.h
+++ b/drivers/crypto/talitos.h
@@ -37,7 +37,8 @@
 #define TALITOS_MCR_LO			0x1038
 #define   TALITOS_MCR_SWR		0x1     /* s/w reset */
 #define TALITOS_IMR			0x1008  /* interrupt mask register */
-#define   TALITOS_IMR_INIT		0x10fff /* enable channel IRQs */
+#define   TALITOS_IMR_INIT		0x100ff /* enable channel IRQs */
+#define   TALITOS_IMR_DONE		0x00055 /* done IRQs */
 #define TALITOS_IMR_LO			0x100C
 #define   TALITOS_IMR_LO_INIT		0x20000 /* allow RNGU error IRQs */
 #define TALITOS_ISR			0x1010  /* interrupt status register */
@@ -55,6 +56,7 @@
 #define   TALITOS_CCCR_CONT		0x2    /* channel continue */
 #define   TALITOS_CCCR_RESET		0x1    /* channel reset */
 #define TALITOS_CCCR_LO(ch)		(ch * TALITOS_CH_STRIDE + 0x110c)
+#define   TALITOS_CCCR_LO_IWSE		0x80   /* chan. ICCR writeback enab. */
 #define   TALITOS_CCCR_LO_CDWE		0x10   /* chan. done writeback enab. */
 #define   TALITOS_CCCR_LO_NT		0x4    /* notification type */
 #define   TALITOS_CCCR_LO_CDIE		0x2    /* channel done IRQ enable */
@@ -102,6 +104,9 @@
 #define TALITOS_AESUISR_LO		0x4034
 #define TALITOS_MDEUISR			0x6030 /* message digest unit */
 #define TALITOS_MDEUISR_LO		0x6034
+#define TALITOS_MDEUICR			0x6038 /* interrupt control */
+#define TALITOS_MDEUICR_LO		0x603c
+#define   TALITOS_MDEUICR_LO_ICE	0x4000 /* integrity check IRQ enable */
 #define TALITOS_AFEUISR			0x8030 /* arc4 unit */
 #define TALITOS_AFEUISR_LO		0x8034
 #define TALITOS_RNGUISR			0xa030 /* random number unit */
@@ -129,31 +134,34 @@
  */
 
 /* written back when done */
-#define DESC_HDR_DONE			__constant_cpu_to_be32(0xff000000)
+#define DESC_HDR_DONE			cpu_to_be32(0xff000000)
+#define DESC_HDR_LO_ICCR1_MASK		cpu_to_be32(0x00180000)
+#define DESC_HDR_LO_ICCR1_PASS		cpu_to_be32(0x00080000)
+#define DESC_HDR_LO_ICCR1_FAIL		cpu_to_be32(0x00100000)
 
 /* primary execution unit select */
-#define	DESC_HDR_SEL0_MASK		__constant_cpu_to_be32(0xf0000000)
-#define	DESC_HDR_SEL0_AFEU		__constant_cpu_to_be32(0x10000000)
-#define	DESC_HDR_SEL0_DEU		__constant_cpu_to_be32(0x20000000)
-#define	DESC_HDR_SEL0_MDEUA		__constant_cpu_to_be32(0x30000000)
-#define	DESC_HDR_SEL0_MDEUB		__constant_cpu_to_be32(0xb0000000)
-#define	DESC_HDR_SEL0_RNG		__constant_cpu_to_be32(0x40000000)
-#define	DESC_HDR_SEL0_PKEU		__constant_cpu_to_be32(0x50000000)
-#define	DESC_HDR_SEL0_AESU		__constant_cpu_to_be32(0x60000000)
-#define	DESC_HDR_SEL0_KEU		__constant_cpu_to_be32(0x70000000)
-#define	DESC_HDR_SEL0_CRCU		__constant_cpu_to_be32(0x80000000)
+#define	DESC_HDR_SEL0_MASK		cpu_to_be32(0xf0000000)
+#define	DESC_HDR_SEL0_AFEU		cpu_to_be32(0x10000000)
+#define	DESC_HDR_SEL0_DEU		cpu_to_be32(0x20000000)
+#define	DESC_HDR_SEL0_MDEUA		cpu_to_be32(0x30000000)
+#define	DESC_HDR_SEL0_MDEUB		cpu_to_be32(0xb0000000)
+#define	DESC_HDR_SEL0_RNG		cpu_to_be32(0x40000000)
+#define	DESC_HDR_SEL0_PKEU		cpu_to_be32(0x50000000)
+#define	DESC_HDR_SEL0_AESU		cpu_to_be32(0x60000000)
+#define	DESC_HDR_SEL0_KEU		cpu_to_be32(0x70000000)
+#define	DESC_HDR_SEL0_CRCU		cpu_to_be32(0x80000000)
 
 /* primary execution unit mode (MODE0) and derivatives */
-#define	DESC_HDR_MODE0_ENCRYPT		__constant_cpu_to_be32(0x00100000)
-#define	DESC_HDR_MODE0_AESU_CBC		__constant_cpu_to_be32(0x00200000)
-#define	DESC_HDR_MODE0_DEU_CBC		__constant_cpu_to_be32(0x00400000)
-#define	DESC_HDR_MODE0_DEU_3DES		__constant_cpu_to_be32(0x00200000)
-#define	DESC_HDR_MODE0_MDEU_INIT	__constant_cpu_to_be32(0x01000000)
-#define	DESC_HDR_MODE0_MDEU_HMAC	__constant_cpu_to_be32(0x00800000)
-#define	DESC_HDR_MODE0_MDEU_PAD		__constant_cpu_to_be32(0x00400000)
-#define	DESC_HDR_MODE0_MDEU_MD5		__constant_cpu_to_be32(0x00200000)
-#define	DESC_HDR_MODE0_MDEU_SHA256	__constant_cpu_to_be32(0x00100000)
-#define	DESC_HDR_MODE0_MDEU_SHA1	__constant_cpu_to_be32(0x00000000)
+#define	DESC_HDR_MODE0_ENCRYPT		cpu_to_be32(0x00100000)
+#define	DESC_HDR_MODE0_AESU_CBC		cpu_to_be32(0x00200000)
+#define	DESC_HDR_MODE0_DEU_CBC		cpu_to_be32(0x00400000)
+#define	DESC_HDR_MODE0_DEU_3DES		cpu_to_be32(0x00200000)
+#define	DESC_HDR_MODE0_MDEU_INIT	cpu_to_be32(0x01000000)
+#define	DESC_HDR_MODE0_MDEU_HMAC	cpu_to_be32(0x00800000)
+#define	DESC_HDR_MODE0_MDEU_PAD		cpu_to_be32(0x00400000)
+#define	DESC_HDR_MODE0_MDEU_MD5		cpu_to_be32(0x00200000)
+#define	DESC_HDR_MODE0_MDEU_SHA256	cpu_to_be32(0x00100000)
+#define	DESC_HDR_MODE0_MDEU_SHA1	cpu_to_be32(0x00000000)
 #define	DESC_HDR_MODE0_MDEU_MD5_HMAC	(DESC_HDR_MODE0_MDEU_MD5 | \
 					 DESC_HDR_MODE0_MDEU_HMAC)
 #define	DESC_HDR_MODE0_MDEU_SHA256_HMAC	(DESC_HDR_MODE0_MDEU_SHA256 | \
@@ -162,18 +170,19 @@
 					 DESC_HDR_MODE0_MDEU_HMAC)
 
 /* secondary execution unit select (SEL1) */
-#define	DESC_HDR_SEL1_MASK		__constant_cpu_to_be32(0x000f0000)
-#define	DESC_HDR_SEL1_MDEUA		__constant_cpu_to_be32(0x00030000)
-#define	DESC_HDR_SEL1_MDEUB		__constant_cpu_to_be32(0x000b0000)
-#define	DESC_HDR_SEL1_CRCU		__constant_cpu_to_be32(0x00080000)
+#define	DESC_HDR_SEL1_MASK		cpu_to_be32(0x000f0000)
+#define	DESC_HDR_SEL1_MDEUA		cpu_to_be32(0x00030000)
+#define	DESC_HDR_SEL1_MDEUB		cpu_to_be32(0x000b0000)
+#define	DESC_HDR_SEL1_CRCU		cpu_to_be32(0x00080000)
 
 /* secondary execution unit mode (MODE1) and derivatives */
-#define	DESC_HDR_MODE1_MDEU_INIT	__constant_cpu_to_be32(0x00001000)
-#define	DESC_HDR_MODE1_MDEU_HMAC	__constant_cpu_to_be32(0x00000800)
-#define	DESC_HDR_MODE1_MDEU_PAD		__constant_cpu_to_be32(0x00000400)
-#define	DESC_HDR_MODE1_MDEU_MD5		__constant_cpu_to_be32(0x00000200)
-#define	DESC_HDR_MODE1_MDEU_SHA256	__constant_cpu_to_be32(0x00000100)
-#define	DESC_HDR_MODE1_MDEU_SHA1	__constant_cpu_to_be32(0x00000000)
+#define	DESC_HDR_MODE1_MDEU_CICV	cpu_to_be32(0x00004000)
+#define	DESC_HDR_MODE1_MDEU_INIT	cpu_to_be32(0x00001000)
+#define	DESC_HDR_MODE1_MDEU_HMAC	cpu_to_be32(0x00000800)
+#define	DESC_HDR_MODE1_MDEU_PAD		cpu_to_be32(0x00000400)
+#define	DESC_HDR_MODE1_MDEU_MD5		cpu_to_be32(0x00000200)
+#define	DESC_HDR_MODE1_MDEU_SHA256	cpu_to_be32(0x00000100)
+#define	DESC_HDR_MODE1_MDEU_SHA1	cpu_to_be32(0x00000000)
 #define	DESC_HDR_MODE1_MDEU_MD5_HMAC	(DESC_HDR_MODE1_MDEU_MD5 | \
 					 DESC_HDR_MODE1_MDEU_HMAC)
 #define	DESC_HDR_MODE1_MDEU_SHA256_HMAC	(DESC_HDR_MODE1_MDEU_SHA256 | \
@@ -182,16 +191,16 @@
 					 DESC_HDR_MODE1_MDEU_HMAC)
 
 /* direction of overall data flow (DIR) */
-#define	DESC_HDR_DIR_INBOUND		__constant_cpu_to_be32(0x00000002)
+#define	DESC_HDR_DIR_INBOUND		cpu_to_be32(0x00000002)
 
 /* request done notification (DN) */
-#define	DESC_HDR_DONE_NOTIFY		__constant_cpu_to_be32(0x00000001)
+#define	DESC_HDR_DONE_NOTIFY		cpu_to_be32(0x00000001)
 
 /* descriptor types */
-#define DESC_HDR_TYPE_AESU_CTR_NONSNOOP		__constant_cpu_to_be32(0 << 3)
-#define DESC_HDR_TYPE_IPSEC_ESP			__constant_cpu_to_be32(1 << 3)
-#define DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU	__constant_cpu_to_be32(2 << 3)
-#define DESC_HDR_TYPE_HMAC_SNOOP_NO_AFEU	__constant_cpu_to_be32(4 << 3)
+#define DESC_HDR_TYPE_AESU_CTR_NONSNOOP		cpu_to_be32(0 << 3)
+#define DESC_HDR_TYPE_IPSEC_ESP			cpu_to_be32(1 << 3)
+#define DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU	cpu_to_be32(2 << 3)
+#define DESC_HDR_TYPE_HMAC_SNOOP_NO_AFEU	cpu_to_be32(4 << 3)
 
 /* link table extent field bits */
 #define DESC_PTR_LNKTBL_JUMP			0x80
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index e0dbd38..e2667a8 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -161,7 +161,7 @@
 
 config EDAC_CELL
 	tristate "Cell Broadband Engine memory controller"
-	depends on EDAC_MM_EDAC && PPC_CELL_NATIVE
+	depends on EDAC_MM_EDAC && PPC_CELL_COMMON
 	help
 	  Support for error detection and correction on the
 	  Cell Broadband Engine internal memory controller
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index 5fcd3d8..4041e91 100644
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -394,6 +394,12 @@
 
 	mutex_lock(&device_ctls_mutex);
 
+	/* If we are being removed, bail out immediately */
+	if (edac_dev->op_state == OP_OFFLINE) {
+		mutex_unlock(&device_ctls_mutex);
+		return;
+	}
+
 	/* Only poll controllers that are running polled and have a check */
 	if ((edac_dev->op_state == OP_RUNNING_POLL) &&
 		(edac_dev->edac_check != NULL)) {
@@ -585,14 +591,14 @@
 	/* mark this instance as OFFLINE */
 	edac_dev->op_state = OP_OFFLINE;
 
-	/* clear workq processing on this instance */
-	edac_device_workq_teardown(edac_dev);
-
 	/* deregister from global list */
 	del_edac_device_from_global_list(edac_dev);
 
 	mutex_unlock(&device_ctls_mutex);
 
+	/* clear workq processing on this instance */
+	edac_device_workq_teardown(edac_dev);
+
 	/* Tear down the sysfs entries for this instance */
 	edac_device_remove_sysfs(edac_dev);
 
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 8daf479..4a597d8 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -467,6 +467,17 @@
 }
 EXPORT_SYMBOL(dmi_get_system_info);
 
+/**
+ *	dmi_name_in_serial - 	Check if string is in the DMI product serial
+ *				information.
+ */
+int dmi_name_in_serial(const char *str)
+{
+	int f = DMI_PRODUCT_SERIAL;
+	if (dmi_ident[f] && strstr(dmi_ident[f], str))
+		return 1;
+	return 0;
+}
 
 /**
  *	dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information.
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index 4353414..3ab3e4a 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -284,15 +284,12 @@
 		/*
 		 * IPV4
 		 */
-		str += sprintf(buf, NIPQUAD_FMT, ip[12],
-			       ip[13], ip[14], ip[15]);
+		str += sprintf(buf, "%pI4", ip + 12);
 	} else {
 		/*
 		 * IPv6
 		 */
-		str += sprintf(str, NIP6_FMT, ntohs(ip[0]), ntohs(ip[1]),
-			       ntohs(ip[2]), ntohs(ip[3]), ntohs(ip[4]),
-			       ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7]));
+		str += sprintf(str, "%pI6", ip);
 	}
 	str += sprintf(str, "\n");
 	return str - buf;
diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c
index 99be114..8289e16 100644
--- a/drivers/gpu/drm/radeon/radeon_irq.c
+++ b/drivers/gpu/drm/radeon/radeon_irq.c
@@ -44,7 +44,7 @@
 	else
 		dev_priv->irq_enable_reg &= ~mask;
 
-	if (!dev->irq_enabled)
+	if (dev->irq_enabled)
 		RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
 }
 
@@ -57,7 +57,7 @@
 	else
 		dev_priv->r500_disp_irq_reg &= ~mask;
 
-	if (!dev->irq_enabled)
+	if (dev->irq_enabled)
 		RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
 }
 
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 3384a71..6c3d60b 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -160,9 +160,39 @@
 
 static void activate_ch(struct sh_mobile_i2c_data *pd)
 {
+	unsigned long i2c_clk;
+	u_int32_t num;
+	u_int32_t denom;
+	u_int32_t tmp;
+
 	/* Make sure the clock is enabled */
 	clk_enable(pd->clk);
 
+	/* Get clock rate after clock is enabled */
+	i2c_clk = clk_get_rate(pd->clk);
+
+	/* Calculate the value for iccl. From the data sheet:
+	 * iccl = (p clock / transfer rate) * (L / (L + H))
+	 * where L and H are the SCL low/high ratio (5/4 in this case).
+	 * We also round off the result.
+	 */
+	num = i2c_clk * 5;
+	denom = NORMAL_SPEED * 9;
+	tmp = num * 10 / denom;
+	if (tmp % 10 >= 5)
+		pd->iccl = (u_int8_t)((num/denom) + 1);
+	else
+		pd->iccl = (u_int8_t)(num/denom);
+
+	/* Calculate the value for icch. From the data sheet:
+	   icch = (p clock / transfer rate) * (H / (L + H)) */
+	num = i2c_clk * 4;
+	tmp = num * 10 / denom;
+	if (tmp % 10 >= 5)
+		pd->icch = (u_int8_t)((num/denom) + 1);
+	else
+		pd->icch = (u_int8_t)(num/denom);
+
 	/* Enable channel and configure rx ack */
 	iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd));
 
@@ -459,40 +489,6 @@
 	.master_xfer	= sh_mobile_i2c_xfer,
 };
 
-static void sh_mobile_i2c_setup_channel(struct platform_device *dev)
-{
-	struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
-	unsigned long peripheral_clk = clk_get_rate(pd->clk);
-	u_int32_t num;
-	u_int32_t denom;
-	u_int32_t tmp;
-
-	spin_lock_init(&pd->lock);
-	init_waitqueue_head(&pd->wait);
-
-	/* Calculate the value for iccl. From the data sheet:
-	 * iccl = (p clock / transfer rate) * (L / (L + H))
-	 * where L and H are the SCL low/high ratio (5/4 in this case).
-	 * We also round off the result.
-	 */
-	num = peripheral_clk * 5;
-	denom = NORMAL_SPEED * 9;
-	tmp = num * 10 / denom;
-	if (tmp % 10 >= 5)
-		pd->iccl = (u_int8_t)((num/denom) + 1);
-	else
-		pd->iccl = (u_int8_t)(num/denom);
-
-	/* Calculate the value for icch. From the data sheet:
-	   icch = (p clock / transfer rate) * (H / (L + H)) */
-	num = peripheral_clk * 4;
-	tmp = num * 10 / denom;
-	if (tmp % 10 >= 5)
-		pd->icch = (u_int8_t)((num/denom) + 1);
-	else
-		pd->icch = (u_int8_t)(num/denom);
-}
-
 static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
 {
 	struct resource *res;
@@ -533,6 +529,7 @@
 	struct sh_mobile_i2c_data *pd;
 	struct i2c_adapter *adap;
 	struct resource *res;
+	char clk_name[8];
 	int size;
 	int ret;
 
@@ -542,9 +539,10 @@
 		return -ENOMEM;
 	}
 
-	pd->clk = clk_get(&dev->dev, "peripheral_clk");
+	snprintf(clk_name, sizeof(clk_name), "i2c%d", dev->id);
+	pd->clk = clk_get(&dev->dev, clk_name);
 	if (IS_ERR(pd->clk)) {
-		dev_err(&dev->dev, "cannot get peripheral clock\n");
+		dev_err(&dev->dev, "cannot get clock \"%s\"\n", clk_name);
 		ret = PTR_ERR(pd->clk);
 		goto err;
 	}
@@ -586,7 +584,8 @@
 
 	strlcpy(adap->name, dev->name, sizeof(adap->name));
 
-	sh_mobile_i2c_setup_channel(dev);
+	spin_lock_init(&pd->lock);
+	init_waitqueue_head(&pd->wait);
 
 	ret = i2c_add_numbered_adapter(adap);
 	if (ret < 0) {
diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
index 53f079c..d8ede85 100644
--- a/drivers/ide/cs5530.c
+++ b/drivers/ide/cs5530.c
@@ -81,11 +81,12 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 	ide_drive_t *mate = ide_get_pair_dev(drive);
-	u16 *mateid = mate->id;
+	u16 *mateid;
 	u8 mask = hwif->ultra_mask;
 
 	if (mate == NULL)
 		goto out;
+	mateid = mate->id;
 
 	if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
 		if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c
index 43f97cc..3c60064 100644
--- a/drivers/ide/macide.c
+++ b/drivers/ide/macide.c
@@ -18,7 +18,6 @@
 #include <linux/delay.h>
 #include <linux/ide.h>
 
-#include <asm/machw.h>
 #include <asm/macintosh.h>
 #include <asm/macints.h>
 #include <asm/mac_baboon.h>
diff --git a/drivers/ide/sc1200.c b/drivers/ide/sc1200.c
index f1a8758..ec7f766 100644
--- a/drivers/ide/sc1200.c
+++ b/drivers/ide/sc1200.c
@@ -104,11 +104,12 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 	ide_drive_t *mate = ide_get_pair_dev(drive);
-	u16 *mateid = mate->id;
+	u16 *mateid;
 	u8 mask = hwif->ultra_mask;
 
 	if (mate == NULL)
 		goto out;
+	mateid = mate->id;
 
 	if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
 		if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 09a2bec..d98b05b 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -41,6 +41,8 @@
 #include <net/neighbour.h>
 #include <net/route.h>
 #include <net/netevent.h>
+#include <net/addrconf.h>
+#include <net/ip6_route.h>
 #include <rdma/ib_addr.h>
 
 MODULE_AUTHOR("Sean Hefty");
@@ -49,8 +51,8 @@
 
 struct addr_req {
 	struct list_head list;
-	struct sockaddr src_addr;
-	struct sockaddr dst_addr;
+	struct sockaddr_storage src_addr;
+	struct sockaddr_storage dst_addr;
 	struct rdma_dev_addr *addr;
 	struct rdma_addr_client *client;
 	void *context;
@@ -113,15 +115,32 @@
 int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
 {
 	struct net_device *dev;
-	__be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
-	int ret;
+	int ret = -EADDRNOTAVAIL;
 
-	dev = ip_dev_find(&init_net, ip);
-	if (!dev)
-		return -EADDRNOTAVAIL;
+	switch (addr->sa_family) {
+	case AF_INET:
+		dev = ip_dev_find(&init_net,
+			((struct sockaddr_in *) addr)->sin_addr.s_addr);
 
-	ret = rdma_copy_addr(dev_addr, dev, NULL);
-	dev_put(dev);
+		if (!dev)
+			return ret;
+
+		ret = rdma_copy_addr(dev_addr, dev, NULL);
+		dev_put(dev);
+		break;
+	case AF_INET6:
+		for_each_netdev(&init_net, dev) {
+			if (ipv6_chk_addr(&init_net,
+					  &((struct sockaddr_in6 *) addr)->sin6_addr,
+					  dev, 1)) {
+				ret = rdma_copy_addr(dev_addr, dev, NULL);
+				break;
+			}
+		}
+		break;
+	default:
+		break;
+	}
 	return ret;
 }
 EXPORT_SYMBOL(rdma_translate_ip);
@@ -156,22 +175,37 @@
 	mutex_unlock(&lock);
 }
 
-static void addr_send_arp(struct sockaddr_in *dst_in)
+static void addr_send_arp(struct sockaddr *dst_in)
 {
 	struct rtable *rt;
 	struct flowi fl;
-	__be32 dst_ip = dst_in->sin_addr.s_addr;
+	struct dst_entry *dst;
 
 	memset(&fl, 0, sizeof fl);
-	fl.nl_u.ip4_u.daddr = dst_ip;
-	if (ip_route_output_key(&init_net, &rt, &fl))
-		return;
+	if (dst_in->sa_family == AF_INET)  {
+		fl.nl_u.ip4_u.daddr =
+			((struct sockaddr_in *) dst_in)->sin_addr.s_addr;
 
-	neigh_event_send(rt->u.dst.neighbour, NULL);
-	ip_rt_put(rt);
+		if (ip_route_output_key(&init_net, &rt, &fl))
+			return;
+
+		neigh_event_send(rt->u.dst.neighbour, NULL);
+		ip_rt_put(rt);
+
+	} else {
+		fl.nl_u.ip6_u.daddr =
+			((struct sockaddr_in6 *) dst_in)->sin6_addr;
+
+		dst = ip6_route_output(&init_net, NULL, &fl);
+		if (!dst)
+			return;
+
+		neigh_event_send(dst->neighbour, NULL);
+		dst_release(dst);
+	}
 }
 
-static int addr_resolve_remote(struct sockaddr_in *src_in,
+static int addr4_resolve_remote(struct sockaddr_in *src_in,
 			       struct sockaddr_in *dst_in,
 			       struct rdma_dev_addr *addr)
 {
@@ -220,10 +254,51 @@
 	return ret;
 }
 
+static int addr6_resolve_remote(struct sockaddr_in6 *src_in,
+			       struct sockaddr_in6 *dst_in,
+			       struct rdma_dev_addr *addr)
+{
+	struct flowi fl;
+	struct neighbour *neigh;
+	struct dst_entry *dst;
+	int ret = -ENODATA;
+
+	memset(&fl, 0, sizeof fl);
+	fl.nl_u.ip6_u.daddr = dst_in->sin6_addr;
+	fl.nl_u.ip6_u.saddr = src_in->sin6_addr;
+
+	dst = ip6_route_output(&init_net, NULL, &fl);
+	if (!dst)
+		return ret;
+
+	if (dst->dev->flags & IFF_NOARP) {
+		ret = rdma_copy_addr(addr, dst->dev, NULL);
+	} else {
+		neigh = dst->neighbour;
+		if (neigh && (neigh->nud_state & NUD_VALID))
+			ret = rdma_copy_addr(addr, neigh->dev, neigh->ha);
+	}
+
+	dst_release(dst);
+	return ret;
+}
+
+static int addr_resolve_remote(struct sockaddr *src_in,
+				struct sockaddr *dst_in,
+				struct rdma_dev_addr *addr)
+{
+	if (src_in->sa_family == AF_INET) {
+		return addr4_resolve_remote((struct sockaddr_in *) src_in,
+			(struct sockaddr_in *) dst_in, addr);
+	} else
+		return addr6_resolve_remote((struct sockaddr_in6 *) src_in,
+			(struct sockaddr_in6 *) dst_in, addr);
+}
+
 static void process_req(struct work_struct *work)
 {
 	struct addr_req *req, *temp_req;
-	struct sockaddr_in *src_in, *dst_in;
+	struct sockaddr *src_in, *dst_in;
 	struct list_head done_list;
 
 	INIT_LIST_HEAD(&done_list);
@@ -231,8 +306,8 @@
 	mutex_lock(&lock);
 	list_for_each_entry_safe(req, temp_req, &req_list, list) {
 		if (req->status == -ENODATA) {
-			src_in = (struct sockaddr_in *) &req->src_addr;
-			dst_in = (struct sockaddr_in *) &req->dst_addr;
+			src_in = (struct sockaddr *) &req->src_addr;
+			dst_in = (struct sockaddr *) &req->dst_addr;
 			req->status = addr_resolve_remote(src_in, dst_in,
 							  req->addr);
 			if (req->status && time_after_eq(jiffies, req->timeout))
@@ -251,41 +326,72 @@
 
 	list_for_each_entry_safe(req, temp_req, &done_list, list) {
 		list_del(&req->list);
-		req->callback(req->status, &req->src_addr, req->addr,
-			      req->context);
+		req->callback(req->status, (struct sockaddr *) &req->src_addr,
+			req->addr, req->context);
 		put_client(req->client);
 		kfree(req);
 	}
 }
 
-static int addr_resolve_local(struct sockaddr_in *src_in,
-			      struct sockaddr_in *dst_in,
+static int addr_resolve_local(struct sockaddr *src_in,
+			      struct sockaddr *dst_in,
 			      struct rdma_dev_addr *addr)
 {
 	struct net_device *dev;
-	__be32 src_ip = src_in->sin_addr.s_addr;
-	__be32 dst_ip = dst_in->sin_addr.s_addr;
 	int ret;
 
-	dev = ip_dev_find(&init_net, dst_ip);
-	if (!dev)
-		return -EADDRNOTAVAIL;
+	if (dst_in->sa_family == AF_INET) {
+		__be32 src_ip = ((struct sockaddr_in *) src_in)->sin_addr.s_addr;
+		__be32 dst_ip = ((struct sockaddr_in *) dst_in)->sin_addr.s_addr;
 
-	if (ipv4_is_zeronet(src_ip)) {
-		src_in->sin_family = dst_in->sin_family;
-		src_in->sin_addr.s_addr = dst_ip;
-		ret = rdma_copy_addr(addr, dev, dev->dev_addr);
-	} else if (ipv4_is_loopback(src_ip)) {
-		ret = rdma_translate_ip((struct sockaddr *)dst_in, addr);
-		if (!ret)
-			memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
+		dev = ip_dev_find(&init_net, dst_ip);
+		if (!dev)
+			return -EADDRNOTAVAIL;
+
+		if (ipv4_is_zeronet(src_ip)) {
+			src_in->sa_family = dst_in->sa_family;
+			((struct sockaddr_in *) src_in)->sin_addr.s_addr = dst_ip;
+			ret = rdma_copy_addr(addr, dev, dev->dev_addr);
+		} else if (ipv4_is_loopback(src_ip)) {
+			ret = rdma_translate_ip(dst_in, addr);
+			if (!ret)
+				memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
+		} else {
+			ret = rdma_translate_ip(src_in, addr);
+			if (!ret)
+				memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
+		}
+		dev_put(dev);
 	} else {
-		ret = rdma_translate_ip((struct sockaddr *)src_in, addr);
-		if (!ret)
-			memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
+		struct in6_addr *a;
+
+		for_each_netdev(&init_net, dev)
+			if (ipv6_chk_addr(&init_net,
+					  &((struct sockaddr_in6 *) addr)->sin6_addr,
+					  dev, 1))
+				break;
+
+		if (!dev)
+			return -EADDRNOTAVAIL;
+
+		a = &((struct sockaddr_in6 *) src_in)->sin6_addr;
+
+		if (ipv6_addr_any(a)) {
+			src_in->sa_family = dst_in->sa_family;
+			((struct sockaddr_in6 *) src_in)->sin6_addr =
+				((struct sockaddr_in6 *) dst_in)->sin6_addr;
+			ret = rdma_copy_addr(addr, dev, dev->dev_addr);
+		} else if (ipv6_addr_loopback(a)) {
+			ret = rdma_translate_ip(dst_in, addr);
+			if (!ret)
+				memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
+		} else  {
+			ret = rdma_translate_ip(src_in, addr);
+			if (!ret)
+				memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
+		}
 	}
 
-	dev_put(dev);
 	return ret;
 }
 
@@ -296,7 +402,7 @@
 				     struct rdma_dev_addr *addr, void *context),
 		    void *context)
 {
-	struct sockaddr_in *src_in, *dst_in;
+	struct sockaddr *src_in, *dst_in;
 	struct addr_req *req;
 	int ret = 0;
 
@@ -313,8 +419,8 @@
 	req->client = client;
 	atomic_inc(&client->refcount);
 
-	src_in = (struct sockaddr_in *) &req->src_addr;
-	dst_in = (struct sockaddr_in *) &req->dst_addr;
+	src_in = (struct sockaddr *) &req->src_addr;
+	dst_in = (struct sockaddr *) &req->dst_addr;
 
 	req->status = addr_resolve_local(src_in, dst_in, addr);
 	if (req->status == -EADDRNOTAVAIL)
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index d951896..2a2e508 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -42,6 +42,7 @@
 #include <linux/inetdevice.h>
 
 #include <net/tcp.h>
+#include <net/ipv6.h>
 
 #include <rdma/rdma_cm.h>
 #include <rdma/rdma_cm_ib.h>
@@ -636,7 +637,12 @@
 
 static inline int cma_loopback_addr(struct sockaddr *addr)
 {
-	return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr);
+	if (addr->sa_family == AF_INET)
+		return ipv4_is_loopback(
+			((struct sockaddr_in *) addr)->sin_addr.s_addr);
+	else
+		return ipv6_addr_loopback(
+			&((struct sockaddr_in6 *) addr)->sin6_addr);
 }
 
 static inline int cma_any_addr(struct sockaddr *addr)
@@ -1467,10 +1473,10 @@
 
 static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af)
 {
-	struct sockaddr_in addr_in;
+	struct sockaddr_storage addr_in;
 
 	memset(&addr_in, 0, sizeof addr_in);
-	addr_in.sin_family = af;
+	addr_in.ss_family = af;
 	return rdma_bind_addr(id, (struct sockaddr *) &addr_in);
 }
 
@@ -2073,7 +2079,7 @@
 	struct rdma_id_private *id_priv;
 	int ret;
 
-	if (addr->sa_family != AF_INET)
+	if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
 		return -EAFNOSUPPORT;
 
 	id_priv = container_of(id, struct rdma_id_private, id);
@@ -2113,31 +2119,59 @@
 static int cma_format_hdr(void *hdr, enum rdma_port_space ps,
 			  struct rdma_route *route)
 {
-	struct sockaddr_in *src4, *dst4;
 	struct cma_hdr *cma_hdr;
 	struct sdp_hh *sdp_hdr;
 
-	src4 = (struct sockaddr_in *) &route->addr.src_addr;
-	dst4 = (struct sockaddr_in *) &route->addr.dst_addr;
+	if (route->addr.src_addr.ss_family == AF_INET) {
+		struct sockaddr_in *src4, *dst4;
 
-	switch (ps) {
-	case RDMA_PS_SDP:
-		sdp_hdr = hdr;
-		if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
-			return -EINVAL;
-		sdp_set_ip_ver(sdp_hdr, 4);
-		sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
-		sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
-		sdp_hdr->port = src4->sin_port;
-		break;
-	default:
-		cma_hdr = hdr;
-		cma_hdr->cma_version = CMA_VERSION;
-		cma_set_ip_ver(cma_hdr, 4);
-		cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
-		cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
-		cma_hdr->port = src4->sin_port;
-		break;
+		src4 = (struct sockaddr_in *) &route->addr.src_addr;
+		dst4 = (struct sockaddr_in *) &route->addr.dst_addr;
+
+		switch (ps) {
+		case RDMA_PS_SDP:
+			sdp_hdr = hdr;
+			if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
+				return -EINVAL;
+			sdp_set_ip_ver(sdp_hdr, 4);
+			sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
+			sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
+			sdp_hdr->port = src4->sin_port;
+			break;
+		default:
+			cma_hdr = hdr;
+			cma_hdr->cma_version = CMA_VERSION;
+			cma_set_ip_ver(cma_hdr, 4);
+			cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
+			cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
+			cma_hdr->port = src4->sin_port;
+			break;
+		}
+	} else {
+		struct sockaddr_in6 *src6, *dst6;
+
+		src6 = (struct sockaddr_in6 *) &route->addr.src_addr;
+		dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr;
+
+		switch (ps) {
+		case RDMA_PS_SDP:
+			sdp_hdr = hdr;
+			if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
+				return -EINVAL;
+			sdp_set_ip_ver(sdp_hdr, 6);
+			sdp_hdr->src_addr.ip6 = src6->sin6_addr;
+			sdp_hdr->dst_addr.ip6 = dst6->sin6_addr;
+			sdp_hdr->port = src6->sin6_port;
+			break;
+		default:
+			cma_hdr = hdr;
+			cma_hdr->cma_version = CMA_VERSION;
+			cma_set_ip_ver(cma_hdr, 6);
+			cma_hdr->src_addr.ip6 = src6->sin6_addr;
+			cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
+			cma_hdr->port = src6->sin6_port;
+			break;
+		}
 	}
 	return 0;
 }
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 4d10421..4f4d1bb 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -262,15 +262,7 @@
 	if (ret)
 		return ret;
 
-	return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-		       be16_to_cpu(((__be16 *) gid.raw)[0]),
-		       be16_to_cpu(((__be16 *) gid.raw)[1]),
-		       be16_to_cpu(((__be16 *) gid.raw)[2]),
-		       be16_to_cpu(((__be16 *) gid.raw)[3]),
-		       be16_to_cpu(((__be16 *) gid.raw)[4]),
-		       be16_to_cpu(((__be16 *) gid.raw)[5]),
-		       be16_to_cpu(((__be16 *) gid.raw)[6]),
-		       be16_to_cpu(((__be16 *) gid.raw)[7]));
+	return sprintf(buf, "%pI6\n", gid.raw);
 }
 
 static ssize_t show_port_pkey(struct ib_port *p, struct port_attribute *attr,
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index 69580e2..5119d65 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -653,7 +653,7 @@
 static int c2_pseudo_up(struct net_device *netdev)
 {
 	struct in_device *ind;
-	struct c2_dev *c2dev = netdev->priv;
+	struct c2_dev *c2dev = netdev->ml_priv;
 
 	ind = in_dev_get(netdev);
 	if (!ind)
@@ -678,7 +678,7 @@
 static int c2_pseudo_down(struct net_device *netdev)
 {
 	struct in_device *ind;
-	struct c2_dev *c2dev = netdev->priv;
+	struct c2_dev *c2dev = netdev->ml_priv;
 
 	ind = in_dev_get(netdev);
 	if (!ind)
@@ -746,14 +746,14 @@
 	/* change ethxxx to iwxxx */
 	strcpy(name, "iw");
 	strcat(name, &c2dev->netdev->name[3]);
-	netdev = alloc_netdev(sizeof(*netdev), name, setup);
+	netdev = alloc_netdev(0, name, setup);
 	if (!netdev) {
 		printk(KERN_ERR PFX "%s -  etherdev alloc failed",
 			__func__);
 		return NULL;
 	}
 
-	netdev->priv = c2dev;
+	netdev->ml_priv = c2dev;
 
 	SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
 
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 7fc35cf..c825142 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -175,6 +175,13 @@
 	unsigned int next_wqe_idx;   /* Idx to first wqe to be flushed */
 };
 
+/* function to calculate the next index for the qmap */
+static inline unsigned int next_index(unsigned int cur_index, unsigned int limit)
+{
+	unsigned int temp = cur_index + 1;
+	return (temp == limit) ? 0 : temp;
+}
+
 struct ehca_qp {
 	union {
 		struct ib_qp ib_qp;
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
index 49660df..523e733 100644
--- a/drivers/infiniband/hw/ehca/ehca_eq.c
+++ b/drivers/infiniband/hw/ehca/ehca_eq.c
@@ -113,7 +113,7 @@
 			if (h_ret != H_SUCCESS || vpage)
 				goto create_eq_exit2;
 		} else {
-			if (h_ret != H_PAGE_REGISTERED || !vpage)
+			if (h_ret != H_PAGE_REGISTERED)
 				goto create_eq_exit2;
 		}
 	}
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index bec7e02..3b77b67 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -717,6 +717,7 @@
 	const u64 *handle;
 	struct ib_pd *ibpd;
 	int ret, i, eq_size;
+	unsigned long flags;
 
 	handle = of_get_property(dev->node, "ibm,hca-handle", NULL);
 	if (!handle) {
@@ -830,9 +831,9 @@
 		ehca_err(&shca->ib_device,
 			 "Cannot create device attributes  ret=%d", ret);
 
-	spin_lock(&shca_list_lock);
+	spin_lock_irqsave(&shca_list_lock, flags);
 	list_add(&shca->shca_list, &shca_list);
-	spin_unlock(&shca_list_lock);
+	spin_unlock_irqrestore(&shca_list_lock, flags);
 
 	return 0;
 
@@ -878,6 +879,7 @@
 static int __devexit ehca_remove(struct of_device *dev)
 {
 	struct ehca_shca *shca = dev->dev.driver_data;
+	unsigned long flags;
 	int ret;
 
 	sysfs_remove_group(&dev->dev.kobj, &ehca_dev_attr_grp);
@@ -915,9 +917,9 @@
 
 	ib_dealloc_device(&shca->ib_device);
 
-	spin_lock(&shca_list_lock);
+	spin_lock_irqsave(&shca_list_lock, flags);
 	list_del(&shca->shca_list);
-	spin_unlock(&shca_list_lock);
+	spin_unlock_irqrestore(&shca_list_lock, flags);
 
 	return ret;
 }
@@ -975,6 +977,7 @@
 			     unsigned long action, void *data)
 {
 	static unsigned long ehca_dmem_warn_time;
+	unsigned long flags;
 
 	switch (action) {
 	case MEM_CANCEL_OFFLINE:
@@ -985,12 +988,12 @@
 	case MEM_GOING_ONLINE:
 	case MEM_GOING_OFFLINE:
 		/* only ok if no hca is attached to the lpar */
-		spin_lock(&shca_list_lock);
+		spin_lock_irqsave(&shca_list_lock, flags);
 		if (list_empty(&shca_list)) {
-			spin_unlock(&shca_list_lock);
+			spin_unlock_irqrestore(&shca_list_lock, flags);
 			return NOTIFY_OK;
 		} else {
-			spin_unlock(&shca_list_lock);
+			spin_unlock_irqrestore(&shca_list_lock, flags);
 			if (printk_timed_ratelimit(&ehca_dmem_warn_time,
 						   30 * 1000))
 				ehca_gen_err("DMEM operations are not allowed"
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index cadbf0c..f161cf1 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -1138,14 +1138,14 @@
 		return -EFAULT;
 	}
 
-	tail_idx = (qmap->tail + 1) % qmap->entries;
+	tail_idx = next_index(qmap->tail, qmap->entries);
 	wqe_idx = q_ofs / ipz_queue->qe_size;
 
 	/* check all processed wqes, whether a cqe is requested or not */
 	while (tail_idx != wqe_idx) {
 		if (qmap->map[tail_idx].cqe_req)
 			qmap->left_to_poll++;
-		tail_idx = (tail_idx + 1) % qmap->entries;
+		tail_idx = next_index(tail_idx, qmap->entries);
 	}
 	/* save index in queue, where we have to start flushing */
 	qmap->next_wqe_idx = wqe_idx;
@@ -1195,14 +1195,14 @@
 	} else {
 		spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
 		my_qp->sq_map.left_to_poll = 0;
-		my_qp->sq_map.next_wqe_idx = (my_qp->sq_map.tail + 1) %
-						my_qp->sq_map.entries;
+		my_qp->sq_map.next_wqe_idx = next_index(my_qp->sq_map.tail,
+							my_qp->sq_map.entries);
 		spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
 
 		spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
 		my_qp->rq_map.left_to_poll = 0;
-		my_qp->rq_map.next_wqe_idx = (my_qp->rq_map.tail + 1) %
-						my_qp->rq_map.entries;
+		my_qp->rq_map.next_wqe_idx = next_index(my_qp->rq_map.tail,
+							my_qp->rq_map.entries);
 		spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags);
 	}
 
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index 00a648f..c711268 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -726,13 +726,13 @@
 		 * set left_to_poll to 0 because in error state, we will not
 		 * get any additional CQEs
 		 */
-		my_qp->sq_map.next_wqe_idx = (my_qp->sq_map.tail + 1) %
-						my_qp->sq_map.entries;
+		my_qp->sq_map.next_wqe_idx = next_index(my_qp->sq_map.tail,
+							my_qp->sq_map.entries);
 		my_qp->sq_map.left_to_poll = 0;
 		ehca_add_to_err_list(my_qp, 1);
 
-		my_qp->rq_map.next_wqe_idx = (my_qp->rq_map.tail + 1) %
-						my_qp->rq_map.entries;
+		my_qp->rq_map.next_wqe_idx = next_index(my_qp->rq_map.tail,
+							my_qp->rq_map.entries);
 		my_qp->rq_map.left_to_poll = 0;
 		if (HAS_RQ(my_qp))
 			ehca_add_to_err_list(my_qp, 0);
@@ -860,9 +860,8 @@
 
 		/* mark as reported and advance next_wqe pointer */
 		qmap_entry->reported = 1;
-		qmap->next_wqe_idx++;
-		if (qmap->next_wqe_idx == qmap->entries)
-			qmap->next_wqe_idx = 0;
+		qmap->next_wqe_idx = next_index(qmap->next_wqe_idx,
+						qmap->entries);
 		qmap_entry = &qmap->map[qmap->next_wqe_idx];
 
 		wc++; nr++;
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index ad0aab6..69c0ce3 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -661,6 +661,8 @@
 static void __devexit cleanup_device(struct ipath_devdata *dd)
 {
 	int port;
+	struct ipath_portdata **tmp;
+	unsigned long flags;
 
 	if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {
 		/* can't do anything more with chip; needs re-init */
@@ -742,20 +744,21 @@
 
 	/*
 	 * free any resources still in use (usually just kernel ports)
-	 * at unload; we do for portcnt, not cfgports, because cfgports
-	 * could have changed while we were loaded.
+	 * at unload; we do for portcnt, because that's what we allocate.
+	 * We acquire lock to be really paranoid that ipath_pd isn't being
+	 * accessed from some interrupt-related code (that should not happen,
+	 * but best to be sure).
 	 */
+	spin_lock_irqsave(&dd->ipath_uctxt_lock, flags);
+	tmp = dd->ipath_pd;
+	dd->ipath_pd = NULL;
+	spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
 	for (port = 0; port < dd->ipath_portcnt; port++) {
-		struct ipath_portdata *pd = dd->ipath_pd[port];
-		dd->ipath_pd[port] = NULL;
+		struct ipath_portdata *pd = tmp[port];
+		tmp[port] = NULL; /* debugging paranoia */
 		ipath_free_pddata(dd, pd);
 	}
-	kfree(dd->ipath_pd);
-	/*
-	 * debuggability, in case some cleanup path tries to use it
-	 * after this
-	 */
-	dd->ipath_pd = NULL;
+	kfree(tmp);
 }
 
 static void __devexit ipath_remove_one(struct pci_dev *pdev)
@@ -2586,6 +2589,7 @@
 {
 	int ret, i;
 	struct ipath_devdata *dd = ipath_lookup(unit);
+	unsigned long flags;
 
 	if (!dd) {
 		ret = -ENODEV;
@@ -2611,18 +2615,21 @@
 		goto bail;
 	}
 
+	spin_lock_irqsave(&dd->ipath_uctxt_lock, flags);
 	if (dd->ipath_pd)
 		for (i = 1; i < dd->ipath_cfgports; i++) {
-			if (dd->ipath_pd[i] && dd->ipath_pd[i]->port_cnt) {
-				ipath_dbg("unit %u port %d is in use "
-					  "(PID %u cmd %s), can't reset\n",
-					  unit, i,
-					  pid_nr(dd->ipath_pd[i]->port_pid),
-					  dd->ipath_pd[i]->port_comm);
-				ret = -EBUSY;
-				goto bail;
-			}
+			if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt)
+				continue;
+			spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
+			ipath_dbg("unit %u port %d is in use "
+				  "(PID %u cmd %s), can't reset\n",
+				  unit, i,
+				  pid_nr(dd->ipath_pd[i]->port_pid),
+				  dd->ipath_pd[i]->port_comm);
+			ret = -EBUSY;
+			goto bail;
 		}
+	spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
 
 	if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
 		teardown_sdma(dd);
@@ -2656,9 +2663,12 @@
 {
 	int i, sub, any = 0;
 	struct pid *pid;
+	unsigned long flags;
 
 	if (!dd->ipath_pd)
 		return 0;
+
+	spin_lock_irqsave(&dd->ipath_uctxt_lock, flags);
 	for (i = 1; i < dd->ipath_cfgports; i++) {
 		if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt)
 			continue;
@@ -2682,6 +2692,7 @@
 			any++;
 		}
 	}
+	spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
 	return any;
 }
 
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 1af1f3a..239d4e8 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -223,8 +223,13 @@
 			(unsigned long long) kinfo->spi_subport_rcvhdr_base);
 	}
 
-	kinfo->spi_pioindex = (kinfo->spi_piobufbase - dd->ipath_piobufbase) /
-		dd->ipath_palign;
+	/*
+	 * All user buffers are 2KB buffers.  If we ever support
+	 * giving 4KB buffers to user processes, this will need some
+	 * work.
+	 */
+	kinfo->spi_pioindex = (kinfo->spi_piobufbase -
+		(dd->ipath_piobufbase & 0xffffffff)) / dd->ipath_palign;
 	kinfo->spi_pioalign = dd->ipath_palign;
 
 	kinfo->spi_qpair = IPATH_KD_QP;
@@ -2041,7 +2046,9 @@
 	struct ipath_filedata *fd;
 	struct ipath_portdata *pd;
 	struct ipath_devdata *dd;
+	unsigned long flags;
 	unsigned port;
+	struct pid *pid;
 
 	ipath_cdbg(VERBOSE, "close on dev %lx, private data %p\n",
 		   (long)in->i_rdev, fp->private_data);
@@ -2074,14 +2081,13 @@
 		mutex_unlock(&ipath_mutex);
 		goto bail;
 	}
+	/* early; no interrupt users after this */
+	spin_lock_irqsave(&dd->ipath_uctxt_lock, flags);
 	port = pd->port_port;
-
-	if (pd->port_hdrqfull) {
-		ipath_cdbg(PROC, "%s[%u] had %u rcvhdrqfull errors "
-			   "during run\n", pd->port_comm, pid_nr(pd->port_pid),
-			   pd->port_hdrqfull);
-		pd->port_hdrqfull = 0;
-	}
+	dd->ipath_pd[port] = NULL;
+	pid = pd->port_pid;
+	pd->port_pid = NULL;
+	spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
 
 	if (pd->port_rcvwait_to || pd->port_piowait_to
 	    || pd->port_rcvnowait || pd->port_pionowait) {
@@ -2138,13 +2144,11 @@
 			unlock_expected_tids(pd);
 		ipath_stats.sps_ports--;
 		ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n",
-			   pd->port_comm, pid_nr(pd->port_pid),
+			   pd->port_comm, pid_nr(pid),
 			   dd->ipath_unit, port);
 	}
 
-	put_pid(pd->port_pid);
-	pd->port_pid = NULL;
-	dd->ipath_pd[pd->port_port] = NULL; /* before releasing mutex */
+	put_pid(pid);
 	mutex_unlock(&ipath_mutex);
 	ipath_free_pddata(dd, pd); /* after releasing the mutex */
 
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index 8bb5170..53912c3 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -86,7 +86,7 @@
 	*dentry = NULL;
 	mutex_lock(&parent->d_inode->i_mutex);
 	*dentry = lookup_one_len(name, parent, strlen(name));
-	if (!IS_ERR(dentry))
+	if (!IS_ERR(*dentry))
 		error = ipathfs_mknod(parent->d_inode, *dentry,
 				      mode, fops, data);
 	else
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index 421cc2a..fbf8c53 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -721,6 +721,12 @@
 				 INFINIPATH_HWE_SERDESPLLFAILED);
 	}
 
+	dd->ibdeltainprog = 1;
+	dd->ibsymsnap =
+	     ipath_read_creg32(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
+	dd->iblnkerrsnap =
+	     ipath_read_creg32(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
+
 	val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
 	config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1);
 
@@ -810,6 +816,36 @@
 {
 	u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
 
+	if (dd->ibsymdelta || dd->iblnkerrdelta ||
+	    dd->ibdeltainprog) {
+		u64 diagc;
+		/* enable counter writes */
+		diagc = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwdiagctrl);
+		ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl,
+				 diagc | INFINIPATH_DC_COUNTERWREN);
+
+		if (dd->ibsymdelta || dd->ibdeltainprog) {
+			val = ipath_read_creg32(dd,
+					dd->ipath_cregs->cr_ibsymbolerrcnt);
+			if (dd->ibdeltainprog)
+				val -= val - dd->ibsymsnap;
+			val -= dd->ibsymdelta;
+			ipath_write_creg(dd,
+				  dd->ipath_cregs->cr_ibsymbolerrcnt, val);
+		}
+		if (dd->iblnkerrdelta || dd->ibdeltainprog) {
+			val = ipath_read_creg32(dd,
+					dd->ipath_cregs->cr_iblinkerrrecovcnt);
+			if (dd->ibdeltainprog)
+				val -= val - dd->iblnkerrsnap;
+			val -= dd->iblnkerrdelta;
+			ipath_write_creg(dd,
+				   dd->ipath_cregs->cr_iblinkerrrecovcnt, val);
+	     }
+
+	     /* and disable counter writes */
+	     ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl, diagc);
+	}
 	val |= INFINIPATH_SERDC0_TXIDLE;
 	ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n",
 		  (unsigned long long) val);
@@ -1749,6 +1785,31 @@
 
 static int ipath_pe_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
 {
+	if (ibup) {
+		if (dd->ibdeltainprog) {
+			dd->ibdeltainprog = 0;
+			dd->ibsymdelta +=
+				ipath_read_creg32(dd,
+				  dd->ipath_cregs->cr_ibsymbolerrcnt) -
+				dd->ibsymsnap;
+			dd->iblnkerrdelta +=
+				ipath_read_creg32(dd,
+				  dd->ipath_cregs->cr_iblinkerrrecovcnt) -
+				dd->iblnkerrsnap;
+		}
+	} else {
+		dd->ipath_lli_counter = 0;
+		if (!dd->ibdeltainprog) {
+			dd->ibdeltainprog = 1;
+			dd->ibsymsnap =
+				ipath_read_creg32(dd,
+				  dd->ipath_cregs->cr_ibsymbolerrcnt);
+			dd->iblnkerrsnap =
+				ipath_read_creg32(dd,
+				  dd->ipath_cregs->cr_iblinkerrrecovcnt);
+		}
+	}
+
 	ipath_setup_pe_setextled(dd, ipath_ib_linkstate(dd, ibcs),
 		ipath_ib_linktrstate(dd, ibcs));
 	return 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_iba7220.c b/drivers/infiniband/hw/ipath/ipath_iba7220.c
index 9839e20..b2a9d4c 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba7220.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba7220.c
@@ -951,6 +951,12 @@
 				 INFINIPATH_HWE_SERDESPLLFAILED);
 	}
 
+	dd->ibdeltainprog = 1;
+	dd->ibsymsnap =
+	     ipath_read_creg32(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
+	dd->iblnkerrsnap =
+	     ipath_read_creg32(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
+
 	if (!dd->ipath_ibcddrctrl) {
 		/* not on re-init after reset */
 		dd->ipath_ibcddrctrl =
@@ -1084,6 +1090,37 @@
 static void ipath_7220_quiet_serdes(struct ipath_devdata *dd)
 {
 	u64 val;
+	if (dd->ibsymdelta || dd->iblnkerrdelta ||
+	    dd->ibdeltainprog) {
+		u64 diagc;
+		/* enable counter writes */
+		diagc = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwdiagctrl);
+		ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl,
+				 diagc | INFINIPATH_DC_COUNTERWREN);
+
+		if (dd->ibsymdelta || dd->ibdeltainprog) {
+			val = ipath_read_creg32(dd,
+					dd->ipath_cregs->cr_ibsymbolerrcnt);
+			if (dd->ibdeltainprog)
+				val -= val - dd->ibsymsnap;
+			val -= dd->ibsymdelta;
+			ipath_write_creg(dd,
+				  dd->ipath_cregs->cr_ibsymbolerrcnt, val);
+		}
+		if (dd->iblnkerrdelta || dd->ibdeltainprog) {
+			val = ipath_read_creg32(dd,
+					dd->ipath_cregs->cr_iblinkerrrecovcnt);
+			if (dd->ibdeltainprog)
+				val -= val - dd->iblnkerrsnap;
+			val -= dd->iblnkerrdelta;
+			ipath_write_creg(dd,
+				   dd->ipath_cregs->cr_iblinkerrrecovcnt, val);
+	     }
+
+	     /* and disable counter writes */
+	     ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl, diagc);
+	}
+
 	dd->ipath_flags &= ~IPATH_IB_AUTONEG_INPROG;
 	wake_up(&dd->ipath_autoneg_wait);
 	cancel_delayed_work(&dd->ipath_autoneg_work);
@@ -2325,7 +2362,7 @@
 
 static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
 {
-	int ret = 0;
+	int ret = 0, symadj = 0;
 	u32 ltstate = ipath_ib_linkstate(dd, ibcs);
 
 	dd->ipath_link_width_active =
@@ -2368,6 +2405,13 @@
 			ipath_dbg("DDR negotiation try, %u/%u\n",
 				dd->ipath_autoneg_tries,
 				IPATH_AUTONEG_TRIES);
+			if (!dd->ibdeltainprog) {
+				dd->ibdeltainprog = 1;
+				dd->ibsymsnap = ipath_read_creg32(dd,
+					dd->ipath_cregs->cr_ibsymbolerrcnt);
+				dd->iblnkerrsnap = ipath_read_creg32(dd,
+					dd->ipath_cregs->cr_iblinkerrrecovcnt);
+			}
 			try_auto_neg(dd);
 			ret = 1; /* no other IB status change processing */
 		} else if ((dd->ipath_flags & IPATH_IB_AUTONEG_INPROG)
@@ -2388,6 +2432,7 @@
 				set_speed_fast(dd,
 					dd->ipath_link_speed_enabled);
 				wake_up(&dd->ipath_autoneg_wait);
+				symadj = 1;
 			} else if (dd->ipath_flags & IPATH_IB_AUTONEG_FAILED) {
 				/*
 				 * clear autoneg failure flag, and do setup
@@ -2403,22 +2448,28 @@
 					IBA7220_IBC_IBTA_1_2_MASK;
 				ipath_write_kreg(dd,
 					IPATH_KREG_OFFSET(IBNCModeCtrl), 0);
+				symadj = 1;
 			}
 		}
 		/*
-		 * if we are in 1X, and are in autoneg width, it
-		 * could be due to an xgxs problem, so if we haven't
+		 * if we are in 1X on rev1 only, and are in autoneg width,
+		 * it could be due to an xgxs problem, so if we haven't
 		 * already tried, try twice to get to 4X; if we
 		 * tried, and couldn't, report it, since it will
 		 * probably not be what is desired.
 		 */
-		if ((dd->ipath_link_width_enabled & (IB_WIDTH_1X |
+		if (dd->ipath_minrev == 1 &&
+		    (dd->ipath_link_width_enabled & (IB_WIDTH_1X |
 			IB_WIDTH_4X)) == (IB_WIDTH_1X | IB_WIDTH_4X)
 			&& dd->ipath_link_width_active == IB_WIDTH_1X
 			&& dd->ipath_x1_fix_tries < 3) {
-			if (++dd->ipath_x1_fix_tries == 3)
+		     if (++dd->ipath_x1_fix_tries == 3) {
 				dev_info(&dd->pcidev->dev,
 					"IB link is in 1X mode\n");
+				if (!(dd->ipath_flags &
+				      IPATH_IB_AUTONEG_INPROG))
+					symadj = 1;
+		     }
 			else {
 				ipath_cdbg(VERBOSE, "IB 1X in "
 					"auto-width, try %u to be "
@@ -2429,7 +2480,8 @@
 				dd->ipath_f_xgxs_reset(dd);
 				ret = 1; /* skip other processing */
 			}
-		}
+		} else if (!(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG))
+			symadj = 1;
 
 		if (!ret) {
 			dd->delay_mult = rate_to_delay
@@ -2440,6 +2492,25 @@
 		}
 	}
 
+	if (symadj) {
+		if (dd->ibdeltainprog) {
+			dd->ibdeltainprog = 0;
+			dd->ibsymdelta += ipath_read_creg32(dd,
+				dd->ipath_cregs->cr_ibsymbolerrcnt) -
+				dd->ibsymsnap;
+			dd->iblnkerrdelta += ipath_read_creg32(dd,
+				dd->ipath_cregs->cr_iblinkerrrecovcnt) -
+				dd->iblnkerrsnap;
+		}
+	} else if (!ibup && !dd->ibdeltainprog
+		   && !(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG)) {
+		dd->ibdeltainprog = 1;
+		dd->ibsymsnap =	ipath_read_creg32(dd,
+				     dd->ipath_cregs->cr_ibsymbolerrcnt);
+		dd->iblnkerrsnap = ipath_read_creg32(dd,
+				     dd->ipath_cregs->cr_iblinkerrrecovcnt);
+	}
+
 	if (!ret)
 		ipath_setup_7220_setextled(dd, ipath_ib_linkstate(dd, ibcs),
 			ltstate);
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index 3e5baa4..64aeefb 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -229,6 +229,7 @@
 	spin_lock_init(&dd->ipath_kernel_tid_lock);
 	spin_lock_init(&dd->ipath_user_tid_lock);
 	spin_lock_init(&dd->ipath_sendctrl_lock);
+	spin_lock_init(&dd->ipath_uctxt_lock);
 	spin_lock_init(&dd->ipath_sdma_lock);
 	spin_lock_init(&dd->ipath_gpio_lock);
 	spin_lock_init(&dd->ipath_eep_st_lock);
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 0bd8bcb..6ba4861 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -355,6 +355,19 @@
 	/* errors masked because they occur too fast */
 	ipath_err_t ipath_maskederrs;
 	u64 ipath_lastlinkrecov; /* link recoveries at last ACTIVE */
+	/* these 5 fields are used to establish deltas for IB Symbol
+	 * errors and linkrecovery errors. They can be reported on
+	 * some chips during link negotiation prior to INIT, and with
+	 * DDR when faking DDR negotiations with non-IBTA switches.
+	 * The chip counters are adjusted at driver unload if there is
+	 * a non-zero delta.
+	 */
+	u64 ibdeltainprog;
+	u64 ibsymdelta;
+	u64 ibsymsnap;
+	u64 iblnkerrdelta;
+	u64 iblnkerrsnap;
+
 	/* time in jiffies at which to re-enable maskederrs */
 	unsigned long ipath_unmasktime;
 	/* count of egrfull errors, combined for all ports */
@@ -464,6 +477,8 @@
 	spinlock_t ipath_kernel_tid_lock;
 	spinlock_t ipath_user_tid_lock;
 	spinlock_t ipath_sendctrl_lock;
+	/* around ipath_pd and (user ports) port_cnt use (intr vs free) */
+	spinlock_t ipath_uctxt_lock;
 
 	/*
 	 * IPATH_STATUS_*,
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
index 8f32b17..c0e933f 100644
--- a/drivers/infiniband/hw/ipath/ipath_keys.c
+++ b/drivers/infiniband/hw/ipath/ipath_keys.c
@@ -132,6 +132,7 @@
 	 * (see ipath_get_dma_mr and ipath_dma.c).
 	 */
 	if (sge->lkey == 0) {
+		/* always a kernel port, no locking needed */
 		struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
 
 		if (pd->user) {
@@ -211,6 +212,7 @@
 	 * (see ipath_get_dma_mr and ipath_dma.c).
 	 */
 	if (rkey == 0) {
+		/* always a kernel port, no locking needed */
 		struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
 
 		if (pd->user) {
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
index be4fc9a..17a1231 100644
--- a/drivers/infiniband/hw/ipath/ipath_mad.c
+++ b/drivers/infiniband/hw/ipath/ipath_mad.c
@@ -348,6 +348,7 @@
  */
 static int get_pkeys(struct ipath_devdata *dd, u16 * pkeys)
 {
+	/* always a kernel port, no locking needed */
 	struct ipath_portdata *pd = dd->ipath_pd[0];
 
 	memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys));
@@ -730,6 +731,7 @@
 	int i;
 	int changed = 0;
 
+	/* always a kernel port, no locking needed */
 	pd = dd->ipath_pd[0];
 
 	for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) {
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 4715911..3a5a89b 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -745,6 +745,7 @@
 	struct ipath_swqe *swq = NULL;
 	struct ipath_ibdev *dev;
 	size_t sz;
+	size_t sg_list_sz;
 	struct ib_qp *ret;
 
 	if (init_attr->create_flags) {
@@ -789,19 +790,31 @@
 			goto bail;
 		}
 		sz = sizeof(*qp);
+		sg_list_sz = 0;
 		if (init_attr->srq) {
 			struct ipath_srq *srq = to_isrq(init_attr->srq);
 
-			sz += sizeof(*qp->r_sg_list) *
-				srq->rq.max_sge;
-		} else
-			sz += sizeof(*qp->r_sg_list) *
-				init_attr->cap.max_recv_sge;
-		qp = kmalloc(sz, GFP_KERNEL);
+			if (srq->rq.max_sge > 1)
+				sg_list_sz = sizeof(*qp->r_sg_list) *
+					(srq->rq.max_sge - 1);
+		} else if (init_attr->cap.max_recv_sge > 1)
+			sg_list_sz = sizeof(*qp->r_sg_list) *
+				(init_attr->cap.max_recv_sge - 1);
+		qp = kmalloc(sz + sg_list_sz, GFP_KERNEL);
 		if (!qp) {
 			ret = ERR_PTR(-ENOMEM);
 			goto bail_swq;
 		}
+		if (sg_list_sz && (init_attr->qp_type == IB_QPT_UD ||
+		    init_attr->qp_type == IB_QPT_SMI ||
+		    init_attr->qp_type == IB_QPT_GSI)) {
+			qp->r_ud_sg_list = kmalloc(sg_list_sz, GFP_KERNEL);
+			if (!qp->r_ud_sg_list) {
+				ret = ERR_PTR(-ENOMEM);
+				goto bail_qp;
+			}
+		} else
+			qp->r_ud_sg_list = NULL;
 		if (init_attr->srq) {
 			sz = 0;
 			qp->r_rq.size = 0;
@@ -818,7 +831,7 @@
 					      qp->r_rq.size * sz);
 			if (!qp->r_rq.wq) {
 				ret = ERR_PTR(-ENOMEM);
-				goto bail_qp;
+				goto bail_sg_list;
 			}
 		}
 
@@ -848,7 +861,7 @@
 		if (err) {
 			ret = ERR_PTR(err);
 			vfree(qp->r_rq.wq);
-			goto bail_qp;
+			goto bail_sg_list;
 		}
 		qp->ip = NULL;
 		qp->s_tx = NULL;
@@ -925,6 +938,8 @@
 		vfree(qp->r_rq.wq);
 	ipath_free_qp(&dev->qp_table, qp);
 	free_qpn(&dev->qp_table, qp->ibqp.qp_num);
+bail_sg_list:
+	kfree(qp->r_ud_sg_list);
 bail_qp:
 	kfree(qp);
 bail_swq:
@@ -989,6 +1004,7 @@
 		kref_put(&qp->ip->ref, ipath_release_mmap_info);
 	else
 		vfree(qp->r_rq.wq);
+	kfree(qp->r_ud_sg_list);
 	vfree(qp->s_wq);
 	kfree(qp);
 	return 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index 7b93cda..9170710 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -573,9 +573,8 @@
 		ohdr->u.rc.reth.length = cpu_to_be32(qp->s_len);
 		qp->s_state = OP(RDMA_READ_REQUEST);
 		hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
-		bth2 = qp->s_psn++ & IPATH_PSN_MASK;
-		if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
-			qp->s_next_psn = qp->s_psn;
+		bth2 = qp->s_psn & IPATH_PSN_MASK;
+		qp->s_psn = wqe->lpsn + 1;
 		ss = NULL;
 		len = 0;
 		qp->s_cur++;
diff --git a/drivers/infiniband/hw/ipath/ipath_sdma.c b/drivers/infiniband/hw/ipath/ipath_sdma.c
index 284c9bc..8e255ad 100644
--- a/drivers/infiniband/hw/ipath/ipath_sdma.c
+++ b/drivers/infiniband/hw/ipath/ipath_sdma.c
@@ -698,10 +698,8 @@
 
 	addr = dma_map_single(&dd->pcidev->dev, tx->txreq.map_addr,
 			      tx->map_len, DMA_TO_DEVICE);
-	if (dma_mapping_error(&dd->pcidev->dev, addr)) {
-		ret = -EIO;
-		goto unlock;
-	}
+	if (dma_mapping_error(&dd->pcidev->dev, addr))
+		goto ioerr;
 
 	dwoffset = tx->map_len >> 2;
 	make_sdma_desc(dd, sdmadesc, (u64) addr, dwoffset, 0);
@@ -741,6 +739,8 @@
 		dw = (len + 3) >> 2;
 		addr = dma_map_single(&dd->pcidev->dev, sge->vaddr, dw << 2,
 				      DMA_TO_DEVICE);
+		if (dma_mapping_error(&dd->pcidev->dev, addr))
+			goto unmap;
 		make_sdma_desc(dd, sdmadesc, (u64) addr, dw, dwoffset);
 		/* SDmaUseLargeBuf has to be set in every descriptor */
 		if (tx->txreq.flags & IPATH_SDMA_TXREQ_F_USELARGEBUF)
@@ -798,7 +798,18 @@
 	list_add_tail(&tx->txreq.list, &dd->ipath_sdma_activelist);
 	if (tx->txreq.flags & IPATH_SDMA_TXREQ_F_VL15)
 		vl15_watchdog_enq(dd);
+	goto unlock;
 
+unmap:
+	while (tail != dd->ipath_sdma_descq_tail) {
+		if (!tail)
+			tail = dd->ipath_sdma_descq_cnt - 1;
+		else
+			tail--;
+		unmap_desc(dd, tail);
+	}
+ioerr:
+	ret = -EIO;
 unlock:
 	spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
 fail:
diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
index c8e3d65..f63e143 100644
--- a/drivers/infiniband/hw/ipath/ipath_stats.c
+++ b/drivers/infiniband/hw/ipath/ipath_stats.c
@@ -112,6 +112,14 @@
 			dd->ipath_lastrpkts = val;
 		}
 		val64 = dd->ipath_rpkts;
+	} else if (creg == dd->ipath_cregs->cr_ibsymbolerrcnt) {
+		if (dd->ibdeltainprog)
+			val64 -= val64 - dd->ibsymsnap;
+		val64 -= dd->ibsymdelta;
+	} else if (creg == dd->ipath_cregs->cr_iblinkerrrecovcnt) {
+		if (dd->ibdeltainprog)
+			val64 -= val64 - dd->iblnkerrsnap;
+		val64 -= dd->iblnkerrdelta;
 	} else
 		val64 = (u64) val;
 
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index 729446f..91c74cc 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -70,8 +70,6 @@
 		goto done;
 	}
 
-	rsge.sg_list = NULL;
-
 	/*
 	 * Check that the qkey matches (except for QP0, see 9.6.1.4.1).
 	 * Qkeys with the high order bit set mean use the
@@ -115,21 +113,6 @@
 		rq = &qp->r_rq;
 	}
 
-	if (rq->max_sge > 1) {
-		/*
-		 * XXX We could use GFP_KERNEL if ipath_do_send()
-		 * was always called from the tasklet instead of
-		 * from ipath_post_send().
-		 */
-		rsge.sg_list = kmalloc((rq->max_sge - 1) *
-					sizeof(struct ipath_sge),
-				       GFP_ATOMIC);
-		if (!rsge.sg_list) {
-			dev->n_pkt_drops++;
-			goto drop;
-		}
-	}
-
 	/*
 	 * Get the next work request entry to find where to put the data.
 	 * Note that it is safe to drop the lock after changing rq->tail
@@ -147,6 +130,7 @@
 		goto drop;
 	}
 	wqe = get_rwqe_ptr(rq, tail);
+	rsge.sg_list = qp->r_ud_sg_list;
 	if (!ipath_init_sge(qp, wqe, &rlen, &rsge)) {
 		spin_unlock_irqrestore(&rq->lock, flags);
 		dev->n_pkt_drops++;
@@ -242,7 +226,6 @@
 	ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
 		       swqe->wr.send_flags & IB_SEND_SOLICITED);
 drop:
-	kfree(rsge.sg_list);
 	if (atomic_dec_and_test(&qp->refcount))
 		wake_up(&qp->wait);
 done:;
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index eabc424..cdf0e6a 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -1852,7 +1852,7 @@
 }
 
 /**
- * ipath_get_pkey - return the indexed PKEY from the port 0 PKEY table
+ * ipath_get_pkey - return the indexed PKEY from the port PKEY table
  * @dd: the infinipath device
  * @index: the PKEY index
  */
@@ -1860,6 +1860,7 @@
 {
 	unsigned ret;
 
+	/* always a kernel port, no locking needed */
 	if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys))
 		ret = 0;
 	else
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index 9d12ae8..11e3f61 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -431,6 +431,7 @@
 	u32 s_lsn;		/* limit sequence number (credit) */
 	struct ipath_swqe *s_wq;	/* send work queue */
 	struct ipath_swqe *s_wqe;
+	struct ipath_sge *r_ud_sg_list;
 	struct ipath_rq r_rq;		/* receive work queue */
 	struct ipath_sge r_sg_list[0];	/* verified SGEs */
 };
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 1830849..8415ecc 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -222,7 +222,7 @@
 	}
 
 	err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar,
-			    cq->db.dma, &cq->mcq, 0);
+			    cq->db.dma, &cq->mcq, vector, 0);
 	if (err)
 		goto err_dbmap;
 
@@ -325,15 +325,17 @@
 
 static void mlx4_ib_cq_resize_copy_cqes(struct mlx4_ib_cq *cq)
 {
-	struct mlx4_cqe *cqe;
+	struct mlx4_cqe *cqe, *new_cqe;
 	int i;
 
 	i = cq->mcq.cons_index;
 	cqe = get_cqe(cq, i & cq->ibcq.cqe);
 	while ((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) != MLX4_CQE_OPCODE_RESIZE) {
-		memcpy(get_cqe_from_buf(&cq->resize_buf->buf,
-					(i + 1) & cq->resize_buf->cqe),
-			get_cqe(cq, i & cq->ibcq.cqe), sizeof(struct mlx4_cqe));
+		new_cqe = get_cqe_from_buf(&cq->resize_buf->buf,
+					   (i + 1) & cq->resize_buf->cqe);
+		memcpy(new_cqe, get_cqe(cq, i & cq->ibcq.cqe), sizeof(struct mlx4_cqe));
+		new_cqe->owner_sr_opcode = (cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK) |
+			(((i + 1) & (cq->resize_buf->cqe + 1)) ? MLX4_CQE_OWNER_MASK : 0);
 		cqe = get_cqe(cq, ++i & cq->ibcq.cqe);
 	}
 	++cq->mcq.cons_index;
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 2e80f8f..dcefe1f 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -578,7 +578,7 @@
 	mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
 		ibdev->num_ports++;
 	ibdev->ib_dev.phys_port_cnt     = ibdev->num_ports;
-	ibdev->ib_dev.num_comp_vectors	= 1;
+	ibdev->ib_dev.num_comp_vectors	= dev->caps.num_comp_vectors;
 	ibdev->ib_dev.dma_device	= &dev->pdev->dev;
 
 	ibdev->ib_dev.uverbs_abi_ver	= MLX4_IB_UVERBS_ABI_VERSION;
diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c
index 3f5f948..d4c8105 100644
--- a/drivers/infiniband/hw/mthca/mthca_mcg.c
+++ b/drivers/infiniband/hw/mthca/mthca_mcg.c
@@ -87,17 +87,7 @@
 	}
 
 	if (0)
-		mthca_dbg(dev, "Hash for %04x:%04x:%04x:%04x:"
-			  "%04x:%04x:%04x:%04x is %04x\n",
-			  be16_to_cpu(((__be16 *) gid)[0]),
-			  be16_to_cpu(((__be16 *) gid)[1]),
-			  be16_to_cpu(((__be16 *) gid)[2]),
-			  be16_to_cpu(((__be16 *) gid)[3]),
-			  be16_to_cpu(((__be16 *) gid)[4]),
-			  be16_to_cpu(((__be16 *) gid)[5]),
-			  be16_to_cpu(((__be16 *) gid)[6]),
-			  be16_to_cpu(((__be16 *) gid)[7]),
-			  *hash);
+		mthca_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash);
 
 	*index = *hash;
 	*prev  = -1;
@@ -264,16 +254,7 @@
 		goto out;
 
 	if (index == -1) {
-		mthca_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
-			  "not found\n",
-			  be16_to_cpu(((__be16 *) gid->raw)[0]),
-			  be16_to_cpu(((__be16 *) gid->raw)[1]),
-			  be16_to_cpu(((__be16 *) gid->raw)[2]),
-			  be16_to_cpu(((__be16 *) gid->raw)[3]),
-			  be16_to_cpu(((__be16 *) gid->raw)[4]),
-			  be16_to_cpu(((__be16 *) gid->raw)[5]),
-			  be16_to_cpu(((__be16 *) gid->raw)[6]),
-			  be16_to_cpu(((__be16 *) gid->raw)[7]));
+		mthca_err(dev, "MGID %pI6 not found\n", gid->raw);
 		err = -EINVAL;
 		goto out;
 	}
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index aa1dc41..b9611ad 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -142,14 +142,9 @@
 	struct nes_device *nesdev;
 	struct net_device *netdev;
 	struct nes_vnic *nesvnic;
-	unsigned int addr;
-	unsigned int mask;
 
-	addr = ntohl(ifa->ifa_address);
-	mask = ntohl(ifa->ifa_mask);
-	nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address " NIPQUAD_FMT
-		  ", netmask " NIPQUAD_FMT ".\n",
-		  HIPQUAD(addr), HIPQUAD(mask));
+	nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %pI4, netmask %pI4.\n",
+		  &ifa->ifa_address, &ifa->ifa_mask);
 	list_for_each_entry(nesdev, &nes_dev_list, list) {
 		nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p. (%s)\n",
 				nesdev, nesdev->netdev[0]->name);
@@ -360,10 +355,8 @@
  */
 static void nes_print_macaddr(struct net_device *netdev)
 {
-	DECLARE_MAC_BUF(mac);
-
-	nes_debug(NES_DBG_INIT, "%s: %s, IRQ %u\n",
-		  netdev->name, print_mac(mac, netdev->dev_addr), netdev->irq);
+	nes_debug(NES_DBG_INIT, "%s: %pM, IRQ %u\n",
+		  netdev->name, netdev->dev_addr, netdev->irq);
 }
 
 /**
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index 1595dc7..13a5bb1 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -137,14 +137,18 @@
 
 #ifdef CONFIG_INFINIBAND_NES_DEBUG
 #define nes_debug(level, fmt, args...) \
+do { \
 	if (level & nes_debug_level) \
-		printk(KERN_ERR PFX "%s[%u]: " fmt, __func__, __LINE__, ##args)
+		printk(KERN_ERR PFX "%s[%u]: " fmt, __func__, __LINE__, ##args); \
+} while (0)
 
-#define assert(expr)                                                \
-if (!(expr)) {                                                       \
-	printk(KERN_ERR PFX "Assertion failed! %s, %s, %s, line %d\n",  \
-		   #expr, __FILE__, __func__, __LINE__);                \
-}
+#define assert(expr) \
+do { \
+	if (!(expr)) { \
+		printk(KERN_ERR PFX "Assertion failed! %s, %s, %s, line %d\n", \
+			   #expr, __FILE__, __func__, __LINE__); \
+	} \
+} while (0)
 
 #define NES_EVENT_TIMEOUT   1200000
 #else
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 2caf9da..a812db2 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -86,15 +86,14 @@
 	struct nes_cm_node *);
 static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *,
 	struct nes_cm_node *);
-static void mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *,
+static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *,
 	struct sk_buff *);
 static int mini_cm_dealloc_core(struct nes_cm_core *);
 static int mini_cm_get(struct nes_cm_core *);
 static int mini_cm_set(struct nes_cm_core *, u32, u32);
 
-static struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
+static void form_cm_frame(struct sk_buff *, struct nes_cm_node *,
 	void *, u32, void *, u32, u8);
-static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node);
 static int add_ref_cm_node(struct nes_cm_node *);
 static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
 
@@ -251,7 +250,7 @@
  * form_cm_frame - get a free packet and build empty frame Use
  * node info to build.
  */
-static struct sk_buff *form_cm_frame(struct sk_buff *skb,
+static void form_cm_frame(struct sk_buff *skb,
 	struct nes_cm_node *cm_node, void *options, u32 optionsize,
 	void *data, u32 datasize, u8 flags)
 {
@@ -339,7 +338,6 @@
 	skb_shinfo(skb)->nr_frags = 0;
 	cm_packets_created++;
 
-	return skb;
 }
 
 
@@ -356,7 +354,6 @@
 
 	nes_debug(NES_DBG_CM, "State         : %u \n",  core->state);
 
-	nes_debug(NES_DBG_CM, "Tx Free cnt   : %u \n", skb_queue_len(&core->tx_free_list));
 	nes_debug(NES_DBG_CM, "Listen Nodes  : %u \n", atomic_read(&core->listen_node_cnt));
 	nes_debug(NES_DBG_CM, "Active Nodes  : %u \n", atomic_read(&core->node_cnt));
 
@@ -381,8 +378,6 @@
 	int ret = 0;
 	u32 was_timer_set;
 
-	if (!cm_node)
-		return -EINVAL;
 	new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
 	if (!new_send)
 		return -1;
@@ -459,13 +454,23 @@
 	int ret = NETDEV_TX_OK;
 	enum nes_cm_node_state last_state;
 
+	struct list_head timer_list;
+	INIT_LIST_HEAD(&timer_list);
 	spin_lock_irqsave(&cm_core->ht_lock, flags);
 
 	list_for_each_safe(list_node, list_core_temp,
-		&cm_core->connected_nodes) {
+				&cm_core->connected_nodes) {
 		cm_node = container_of(list_node, struct nes_cm_node, list);
-		add_ref_cm_node(cm_node);
-		spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+		if (!list_empty(&cm_node->recv_list) || (cm_node->send_entry)) {
+			add_ref_cm_node(cm_node);
+			list_add(&cm_node->timer_entry, &timer_list);
+		}
+	}
+	spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+	list_for_each_safe(list_node, list_core_temp, &timer_list) {
+		cm_node = container_of(list_node, struct nes_cm_node,
+					timer_entry);
 		spin_lock_irqsave(&cm_node->recv_list_lock, flags);
 		list_for_each_safe(list_core, list_node_temp,
 			&cm_node->recv_list) {
@@ -519,7 +524,7 @@
 		do {
 			send_entry = cm_node->send_entry;
 			if (!send_entry)
-				continue;
+				break;
 			if (time_after(send_entry->timetosend, jiffies)) {
 				if (cm_node->state != NES_CM_STATE_TSA) {
 					if ((nexttimeout >
@@ -528,18 +533,18 @@
 						nexttimeout =
 							send_entry->timetosend;
 						settimer = 1;
-						continue;
+						break;
 					}
 				} else {
 					free_retrans_entry(cm_node);
-					continue;
+					break;
 				}
 			}
 
 			if ((cm_node->state == NES_CM_STATE_TSA) ||
 				(cm_node->state == NES_CM_STATE_CLOSED)) {
 				free_retrans_entry(cm_node);
-				continue;
+				break;
 			}
 
 			if (!send_entry->retranscount ||
@@ -557,7 +562,7 @@
 						NES_CM_EVENT_ABORTED);
 				spin_lock_irqsave(&cm_node->retrans_list_lock,
 					flags);
-				continue;
+				break;
 			}
 			atomic_inc(&send_entry->skb->users);
 			cm_packets_retrans++;
@@ -583,7 +588,7 @@
 				send_entry->retrycount--;
 				nexttimeout = jiffies + NES_SHORT_TIME;
 				settimer = 1;
-				continue;
+				break;
 			} else {
 				cm_packets_sent++;
 			}
@@ -615,14 +620,12 @@
 
 		spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
 		rem_ref_cm_node(cm_node->cm_core, cm_node);
-		spin_lock_irqsave(&cm_core->ht_lock, flags);
 		if (ret != NETDEV_TX_OK) {
 			nes_debug(NES_DBG_CM, "rexmit failed for cm_node=%p\n",
 				cm_node);
 			break;
 		}
 	}
-	spin_unlock_irqrestore(&cm_core->ht_lock, flags);
 
 	if (settimer) {
 		if (!timer_pending(&cm_core->tcp_timer)) {
@@ -683,7 +686,7 @@
 	optionssize += 1;
 
 	if (!skb)
-		skb = get_free_pkt(cm_node);
+		skb = dev_alloc_skb(MAX_CM_BUFFER);
 	if (!skb) {
 		nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
 		return -1;
@@ -708,7 +711,7 @@
 	int flags = SET_RST | SET_ACK;
 
 	if (!skb)
-		skb = get_free_pkt(cm_node);
+		skb = dev_alloc_skb(MAX_CM_BUFFER);
 	if (!skb) {
 		nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
 		return -1;
@@ -729,7 +732,7 @@
 	int ret;
 
 	if (!skb)
-		skb = get_free_pkt(cm_node);
+		skb = dev_alloc_skb(MAX_CM_BUFFER);
 
 	if (!skb) {
 		nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
@@ -752,7 +755,7 @@
 
 	/* if we didn't get a frame get one */
 	if (!skb)
-		skb = get_free_pkt(cm_node);
+		skb = dev_alloc_skb(MAX_CM_BUFFER);
 
 	if (!skb) {
 		nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
@@ -767,64 +770,20 @@
 
 
 /**
- * get_free_pkt
- */
-static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node)
-{
-	struct sk_buff *skb, *new_skb;
-
-	/* check to see if we need to repopulate the free tx pkt queue */
-	if (skb_queue_len(&cm_node->cm_core->tx_free_list) < NES_CM_FREE_PKT_LO_WATERMARK) {
-		while (skb_queue_len(&cm_node->cm_core->tx_free_list) <
-				cm_node->cm_core->free_tx_pkt_max) {
-			/* replace the frame we took, we won't get it back */
-			new_skb = dev_alloc_skb(cm_node->cm_core->mtu);
-			BUG_ON(!new_skb);
-			/* add a replacement frame to the free tx list head */
-			skb_queue_head(&cm_node->cm_core->tx_free_list, new_skb);
-		}
-	}
-
-	skb = skb_dequeue(&cm_node->cm_core->tx_free_list);
-
-	return skb;
-}
-
-
-/**
- * make_hashkey - generate hash key from node tuple
- */
-static inline int make_hashkey(u16 loc_port, nes_addr_t loc_addr, u16 rem_port,
-		nes_addr_t rem_addr)
-{
-	u32 hashkey = 0;
-
-	hashkey = loc_addr + rem_addr + loc_port + rem_port;
-	hashkey = (hashkey % NES_CM_HASHTABLE_SIZE);
-
-	return hashkey;
-}
-
-
-/**
  * find_node - find a cm node that matches the reference cm node
  */
 static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
 		u16 rem_port, nes_addr_t rem_addr, u16 loc_port, nes_addr_t loc_addr)
 {
 	unsigned long flags;
-	u32 hashkey;
 	struct list_head *hte;
 	struct nes_cm_node *cm_node;
 
-	/* make a hash index key for this packet */
-	hashkey = make_hashkey(loc_port, loc_addr, rem_port, rem_addr);
-
 	/* get a handle on the hte */
 	hte = &cm_core->connected_nodes;
 
-	nes_debug(NES_DBG_CM, "Searching for an owner node: " NIPQUAD_FMT ":%x from core %p->%p\n",
-		  HIPQUAD(loc_addr), loc_port, cm_core, hte);
+	nes_debug(NES_DBG_CM, "Searching for an owner node: %pI4:%x from core %p->%p\n",
+		  &loc_addr, loc_port, cm_core, hte);
 
 	/* walk list and find cm_node associated with this session ID */
 	spin_lock_irqsave(&cm_core->ht_lock, flags);
@@ -873,8 +832,8 @@
 	}
 	spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
 
-	nes_debug(NES_DBG_CM, "Unable to find listener for " NIPQUAD_FMT ":%x\n",
-		  HIPQUAD(dst_addr), dst_port);
+	nes_debug(NES_DBG_CM, "Unable to find listener for %pI4:%x\n",
+		  &dst_addr, dst_port);
 
 	/* no listener */
 	return NULL;
@@ -887,7 +846,6 @@
 static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
 {
 	unsigned long flags;
-	u32 hashkey;
 	struct list_head *hte;
 
 	if (!cm_node || !cm_core)
@@ -896,11 +854,6 @@
 	nes_debug(NES_DBG_CM, "Adding Node %p to Active Connection HT\n",
 		cm_node);
 
-	/* first, make an index into our hash table */
-	hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr,
-			cm_node->rem_port, cm_node->rem_addr);
-	cm_node->hashkey = hashkey;
-
 	spin_lock_irqsave(&cm_core->ht_lock, flags);
 
 	/* get a handle on the hash table element (list head for this slot) */
@@ -925,28 +878,36 @@
 	struct list_head *list_pos = NULL;
 	struct list_head *list_temp = NULL;
 	struct nes_cm_node *cm_node = NULL;
+	struct list_head reset_list;
 
 	nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, "
 		"refcnt=%d\n", listener, free_hanging_nodes,
 		atomic_read(&listener->ref_count));
 	/* free non-accelerated child nodes for this listener */
+	INIT_LIST_HEAD(&reset_list);
 	if (free_hanging_nodes) {
 		spin_lock_irqsave(&cm_core->ht_lock, flags);
 		list_for_each_safe(list_pos, list_temp,
-			&g_cm_core->connected_nodes) {
+				   &g_cm_core->connected_nodes) {
 			cm_node = container_of(list_pos, struct nes_cm_node,
 				list);
 			if ((cm_node->listener == listener) &&
-				(!cm_node->accelerated)) {
-				cleanup_retrans_entry(cm_node);
-				spin_unlock_irqrestore(&cm_core->ht_lock,
-					flags);
-				send_reset(cm_node, NULL);
-				spin_lock_irqsave(&cm_core->ht_lock, flags);
+			    (!cm_node->accelerated)) {
+				add_ref_cm_node(cm_node);
+				list_add(&cm_node->reset_entry, &reset_list);
 			}
 		}
 		spin_unlock_irqrestore(&cm_core->ht_lock, flags);
 	}
+
+	list_for_each_safe(list_pos, list_temp, &reset_list) {
+		cm_node = container_of(list_pos, struct nes_cm_node,
+					reset_entry);
+		cleanup_retrans_entry(cm_node);
+		send_reset(cm_node, NULL);
+		rem_ref_cm_node(cm_node->cm_core, cm_node);
+	}
+
 	spin_lock_irqsave(&cm_core->listen_list_lock, flags);
 	if (!atomic_dec_return(&listener->ref_count)) {
 		list_del(&listener->list);
@@ -1027,7 +988,6 @@
 	struct flowi fl;
 	struct neighbour *neigh;
 	int rc = -1;
-	DECLARE_MAC_BUF(mac);
 
 	memset(&fl, 0, sizeof fl);
 	fl.nl_u.ip4_u.daddr = htonl(dst_ip);
@@ -1041,8 +1001,8 @@
 	if (neigh) {
 		if (neigh->nud_state & NUD_VALID) {
 			nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X"
-				  " is %s, Gateway is 0x%08X \n", dst_ip,
-				  print_mac(mac, neigh->ha), ntohl(rt->rt_gateway));
+				  " is %pM, Gateway is 0x%08X \n", dst_ip,
+				  neigh->ha, ntohl(rt->rt_gateway));
 			nes_manage_arp_cache(nesvnic->netdev, neigh->ha,
 					     dst_ip, NES_ARP_ADD);
 			rc = nes_arp_table(nesvnic->nesdev, dst_ip, NULL,
@@ -1071,7 +1031,6 @@
 	int arpindex = 0;
 	struct nes_device *nesdev;
 	struct nes_adapter *nesadapter;
-	DECLARE_MAC_BUF(mac);
 
 	/* create an hte and cm_node for this instance */
 	cm_node = kzalloc(sizeof(*cm_node), GFP_ATOMIC);
@@ -1084,10 +1043,9 @@
 	cm_node->loc_port = cm_info->loc_port;
 	cm_node->rem_port = cm_info->rem_port;
 	cm_node->send_write0 = send_first;
-	nes_debug(NES_DBG_CM, "Make node addresses : loc = " NIPQUAD_FMT
-			":%x, rem = " NIPQUAD_FMT ":%x\n",
-			HIPQUAD(cm_node->loc_addr), cm_node->loc_port,
-			HIPQUAD(cm_node->rem_addr), cm_node->rem_port);
+	nes_debug(NES_DBG_CM, "Make node addresses : loc = %pI4:%x, rem = %pI4:%x\n",
+		  &cm_node->loc_addr, cm_node->loc_port,
+		  &cm_node->rem_addr, cm_node->rem_port);
 	cm_node->listener = listener;
 	cm_node->netdev = nesvnic->netdev;
 	cm_node->cm_id = cm_info->cm_id;
@@ -1126,7 +1084,10 @@
 
 	cm_node->loopbackpartner = NULL;
 	/* get the mac addr for the remote node */
-	arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
+	if (ipv4_is_loopback(htonl(cm_node->rem_addr)))
+		arpindex = nes_arp_table(nesdev, ntohl(nesvnic->local_ipaddr), NULL, NES_ARP_RESOLVE);
+	else
+		arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
 	if (arpindex < 0) {
 		arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr);
 		if (arpindex < 0) {
@@ -1137,8 +1098,8 @@
 
 	/* copy the mac addr to node context */
 	memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN);
-	nes_debug(NES_DBG_CM, "Remote mac addr from arp table: %s\n",
-		  print_mac(mac, cm_node->rem_mac));
+	nes_debug(NES_DBG_CM, "Remote mac addr from arp table: %pM\n",
+		  cm_node->rem_mac);
 
 	add_hte_node(cm_core, cm_node);
 	atomic_inc(&cm_nodes_created);
@@ -1306,7 +1267,6 @@
 static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 	struct tcphdr *tcph)
 {
-	atomic_inc(&cm_resets_recvd);
 	nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "
 		"refcnt=%d\n", cm_node, cm_node->state,
 		atomic_read(&cm_node->ref_count));
@@ -1344,6 +1304,7 @@
 {
 
 	int	reset = 0;	/* whether to send reset in case of err.. */
+	int	passive_state;
 	atomic_inc(&cm_resets_recvd);
 	nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u."
 			" refcnt=%d\n", cm_node, cm_node->state,
@@ -1357,7 +1318,14 @@
 			cm_node->listener, cm_node->state);
 		active_open_err(cm_node, skb, reset);
 		break;
-	/* For PASSIVE open states, remove the cm_node event */
+	case NES_CM_STATE_MPAREQ_RCVD:
+		passive_state = atomic_add_return(1, &cm_node->passive_state);
+		if (passive_state ==  NES_SEND_RESET_EVENT)
+			create_event(cm_node, NES_CM_EVENT_RESET);
+		cleanup_retrans_entry(cm_node);
+		cm_node->state = NES_CM_STATE_CLOSED;
+		dev_kfree_skb_any(skb);
+		break;
 	case NES_CM_STATE_ESTABLISHED:
 	case NES_CM_STATE_SYN_RCVD:
 	case NES_CM_STATE_LISTENING:
@@ -1365,7 +1333,14 @@
 		passive_open_err(cm_node, skb, reset);
 		break;
 	case NES_CM_STATE_TSA:
+		active_open_err(cm_node, skb, reset);
+		break;
+	case NES_CM_STATE_CLOSED:
+		cleanup_retrans_entry(cm_node);
+		drop_packet(skb);
+		break;
 	default:
+		drop_packet(skb);
 		break;
 	}
 }
@@ -1394,6 +1369,9 @@
 		dev_kfree_skb_any(skb);
 		if (type == NES_CM_EVENT_CONNECTED)
 			cm_node->state = NES_CM_STATE_TSA;
+		else
+			atomic_set(&cm_node->passive_state,
+					NES_PASSIVE_STATE_INDICATED);
 		create_event(cm_node, type);
 
 	}
@@ -1474,7 +1452,7 @@
 	int optionsize;
 
 	optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
-	skb_pull(skb, tcph->doff << 2);
+	skb_trim(skb, 0);
 	inc_sequence = ntohl(tcph->seq);
 
 	switch (cm_node->state) {
@@ -1507,6 +1485,10 @@
 		cm_node->state = NES_CM_STATE_SYN_RCVD;
 		send_syn(cm_node, 1, skb);
 		break;
+	case NES_CM_STATE_CLOSED:
+		cleanup_retrans_entry(cm_node);
+		send_reset(cm_node, skb);
+		break;
 	case NES_CM_STATE_TSA:
 	case NES_CM_STATE_ESTABLISHED:
 	case NES_CM_STATE_FIN_WAIT1:
@@ -1515,7 +1497,6 @@
 	case NES_CM_STATE_LAST_ACK:
 	case NES_CM_STATE_CLOSING:
 	case NES_CM_STATE_UNKNOWN:
-	case NES_CM_STATE_CLOSED:
 	default:
 		drop_packet(skb);
 		break;
@@ -1531,7 +1512,7 @@
 	int optionsize;
 
 	optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
-	skb_pull(skb, tcph->doff << 2);
+	skb_trim(skb, 0);
 	inc_sequence = ntohl(tcph->seq);
 	switch (cm_node->state) {
 	case NES_CM_STATE_SYN_SENT:
@@ -1555,6 +1536,12 @@
 		/* passive open, so should not be here */
 		passive_open_err(cm_node, skb, 1);
 		break;
+	case NES_CM_STATE_LISTENING:
+	case NES_CM_STATE_CLOSED:
+		cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+		cleanup_retrans_entry(cm_node);
+		send_reset(cm_node, skb);
+		break;
 	case NES_CM_STATE_ESTABLISHED:
 	case NES_CM_STATE_FIN_WAIT1:
 	case NES_CM_STATE_FIN_WAIT2:
@@ -1562,7 +1549,6 @@
 	case NES_CM_STATE_TSA:
 	case NES_CM_STATE_CLOSING:
 	case NES_CM_STATE_UNKNOWN:
-	case NES_CM_STATE_CLOSED:
 	case NES_CM_STATE_MPAREQ_SENT:
 	default:
 		drop_packet(skb);
@@ -1577,6 +1563,13 @@
 	u32 inc_sequence;
 	u32 rem_seq_ack;
 	u32 rem_seq;
+	int ret;
+	int optionsize;
+	u32 temp_seq = cm_node->tcp_cntxt.loc_seq_num;
+
+	optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+	cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+
 	if (check_seq(cm_node, tcph, skb))
 		return;
 
@@ -1589,7 +1582,18 @@
 	switch (cm_node->state) {
 	case NES_CM_STATE_SYN_RCVD:
 		/* Passive OPEN */
+		ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 1);
+		if (ret)
+			break;
 		cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
+		cm_node->tcp_cntxt.loc_seq_num = temp_seq;
+		if (cm_node->tcp_cntxt.rem_ack_num !=
+		    cm_node->tcp_cntxt.loc_seq_num) {
+			nes_debug(NES_DBG_CM, "rem_ack_num != loc_seq_num\n");
+			cleanup_retrans_entry(cm_node);
+			send_reset(cm_node, skb);
+			return;
+		}
 		cm_node->state = NES_CM_STATE_ESTABLISHED;
 		if (datasize) {
 			cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
@@ -1621,11 +1625,15 @@
 			dev_kfree_skb_any(skb);
 		}
 		break;
+	case NES_CM_STATE_LISTENING:
+	case NES_CM_STATE_CLOSED:
+		cleanup_retrans_entry(cm_node);
+		send_reset(cm_node, skb);
+		break;
 	case NES_CM_STATE_FIN_WAIT1:
 	case NES_CM_STATE_SYN_SENT:
 	case NES_CM_STATE_FIN_WAIT2:
 	case NES_CM_STATE_TSA:
-	case NES_CM_STATE_CLOSED:
 	case NES_CM_STATE_MPAREQ_RCVD:
 	case NES_CM_STATE_LAST_ACK:
 	case NES_CM_STATE_CLOSING:
@@ -1648,9 +1656,9 @@
 			nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n",
 				__func__, cm_node);
 			if (passive)
-				passive_open_err(cm_node, skb, 0);
+				passive_open_err(cm_node, skb, 1);
 			else
-				active_open_err(cm_node, skb, 0);
+				active_open_err(cm_node, skb, 1);
 			return 1;
 		}
 	}
@@ -1970,6 +1978,7 @@
 	struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
 {
 	int ret = 0;
+	int passive_state;
 
 	nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n",
 		__func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state);
@@ -1977,9 +1986,13 @@
 	if (cm_node->tcp_cntxt.client)
 		return ret;
 	cleanup_retrans_entry(cm_node);
-	cm_node->state = NES_CM_STATE_CLOSED;
 
-	ret = send_reset(cm_node, NULL);
+	passive_state = atomic_add_return(1, &cm_node->passive_state);
+	cm_node->state = NES_CM_STATE_CLOSED;
+	if (passive_state == NES_SEND_RESET_EVENT)
+		rem_ref_cm_node(cm_core, cm_node);
+	else
+		ret = send_reset(cm_node, NULL);
 	return ret;
 }
 
@@ -2037,7 +2050,7 @@
  * recv_pkt - recv an ETHERNET packet, and process it through CM
  * node state machine
  */
-static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
+static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
 	struct nes_vnic *nesvnic, struct sk_buff *skb)
 {
 	struct nes_cm_node *cm_node = NULL;
@@ -2045,33 +2058,24 @@
 	struct iphdr *iph;
 	struct tcphdr *tcph;
 	struct nes_cm_info nfo;
+	int skb_handled = 1;
 
 	if (!skb)
-		return;
+		return 0;
 	if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
-		dev_kfree_skb_any(skb);
-		return;
+		return 0;
 	}
 
 	iph = (struct iphdr *)skb->data;
 	tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr));
-	skb_reset_network_header(skb);
-	skb_set_transport_header(skb, sizeof(*tcph));
-	if (!tcph) {
-		dev_kfree_skb_any(skb);
-		return;
-	}
-	skb->len = ntohs(iph->tot_len);
 
 	nfo.loc_addr = ntohl(iph->daddr);
 	nfo.loc_port = ntohs(tcph->dest);
 	nfo.rem_addr = ntohl(iph->saddr);
 	nfo.rem_port = ntohs(tcph->source);
 
-	nes_debug(NES_DBG_CM, "Received packet: dest=" NIPQUAD_FMT
-		  ":0x%04X src=" NIPQUAD_FMT ":0x%04X\n",
-		  NIPQUAD(iph->daddr), tcph->dest,
-		  NIPQUAD(iph->saddr), tcph->source);
+	nes_debug(NES_DBG_CM, "Received packet: dest=%pI4:0x%04X src=%pI4:0x%04X\n",
+		  &iph->daddr, tcph->dest, &iph->saddr, tcph->source);
 
 	do {
 		cm_node = find_node(cm_core,
@@ -2082,23 +2086,21 @@
 			/* Only type of packet accepted are for */
 			/* the PASSIVE open (syn only) */
 			if ((!tcph->syn) || (tcph->ack)) {
-				cm_packets_dropped++;
+				skb_handled = 0;
 				break;
 			}
 			listener = find_listener(cm_core, nfo.loc_addr,
 				nfo.loc_port,
 				NES_CM_LISTENER_ACTIVE_STATE);
-			if (listener) {
-				nfo.cm_id = listener->cm_id;
-				nfo.conn_type = listener->conn_type;
-			} else {
-				nes_debug(NES_DBG_CM, "Unable to find listener "
-					"for the pkt\n");
-				cm_packets_dropped++;
-				dev_kfree_skb_any(skb);
+			if (!listener) {
+				nfo.cm_id = NULL;
+				nfo.conn_type = 0;
+				nes_debug(NES_DBG_CM, "Unable to find listener for the pkt\n");
+				skb_handled = 0;
 				break;
 			}
-
+			nfo.cm_id = listener->cm_id;
+			nfo.conn_type = listener->conn_type;
 			cm_node = make_cm_node(cm_core, nesvnic, &nfo,
 				listener);
 			if (!cm_node) {
@@ -2124,9 +2126,13 @@
 			dev_kfree_skb_any(skb);
 			break;
 		}
+		skb_reset_network_header(skb);
+		skb_set_transport_header(skb, sizeof(*tcph));
+		skb->len = ntohs(iph->tot_len);
 		process_packet(cm_node, skb, cm_core);
 		rem_ref_cm_node(cm_core, cm_node);
 	} while (0);
+	return skb_handled;
 }
 
 
@@ -2135,10 +2141,7 @@
  */
 static struct nes_cm_core *nes_cm_alloc_core(void)
 {
-	int i;
-
 	struct nes_cm_core *cm_core;
-	struct sk_buff *skb = NULL;
 
 	/* setup the CM core */
 	/* alloc top level core control structure */
@@ -2156,19 +2159,6 @@
 
 	atomic_set(&cm_core->events_posted, 0);
 
-	/* init the packet lists */
-	skb_queue_head_init(&cm_core->tx_free_list);
-
-	for (i = 0; i < NES_CM_DEFAULT_FRAME_CNT; i++) {
-		skb = dev_alloc_skb(cm_core->mtu);
-		if (!skb) {
-			kfree(cm_core);
-			return NULL;
-		}
-		/* add 'raw' skb to free frame list */
-		skb_queue_head(&cm_core->tx_free_list, skb);
-	}
-
 	cm_core->api = &nes_cm_api;
 
 	spin_lock_init(&cm_core->ht_lock);
@@ -2397,7 +2387,6 @@
 			atomic_inc(&cm_disconnects);
 			cm_event.event = IW_CM_EVENT_DISCONNECT;
 			if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) {
-				issued_disconnect_reset = 1;
 				cm_event.status = IW_CM_EVENT_STATUS_RESET;
 				nes_debug(NES_DBG_CM, "Generating a CM "
 					"Disconnect Event (status reset) for "
@@ -2547,6 +2536,7 @@
 	struct nes_v4_quad nes_quad;
 	u32 crc_value;
 	int ret;
+	int passive_state;
 
 	ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
 	if (!ibqp)
@@ -2714,8 +2704,6 @@
 			conn_param->private_data_len +
 			sizeof(struct ietf_mpa_frame));
 
-	attr.qp_state = IB_QPS_RTS;
-	nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
 
 	/* notify OF layer that accept event was successfull */
 	cm_id->add_ref(cm_id);
@@ -2728,6 +2716,8 @@
 	cm_event.private_data = NULL;
 	cm_event.private_data_len = 0;
 	ret = cm_id->event_handler(cm_id, &cm_event);
+	attr.qp_state = IB_QPS_RTS;
+	nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
 	if (cm_node->loopbackpartner) {
 		cm_node->loopbackpartner->mpa_frame_size =
 			nesqp->private_data_len;
@@ -2740,6 +2730,9 @@
 		printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
 			"ret=%d\n", __func__, __LINE__, ret);
 
+	passive_state = atomic_add_return(1, &cm_node->passive_state);
+	if (passive_state == NES_SEND_RESET_EVENT)
+		create_event(cm_node, NES_CM_EVENT_RESET);
 	return 0;
 }
 
@@ -2943,15 +2936,16 @@
  */
 int nes_cm_recv(struct sk_buff *skb, struct net_device *netdevice)
 {
+	int rc = 0;
 	cm_packets_received++;
 	if ((g_cm_core) && (g_cm_core->api)) {
-		g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb);
+		rc = g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb);
 	} else {
 		nes_debug(NES_DBG_CM, "Unable to process packet for CM,"
 				" cm is not setup properly.\n");
 	}
 
-	return 0;
+	return rc;
 }
 
 
@@ -3222,6 +3216,18 @@
 	cm_event.private_data_len = 0;
 
 	ret = cm_id->event_handler(cm_id, &cm_event);
+	cm_id->add_ref(cm_id);
+	atomic_inc(&cm_closes);
+	cm_event.event = IW_CM_EVENT_CLOSE;
+	cm_event.status = IW_CM_EVENT_STATUS_OK;
+	cm_event.provider_data = cm_id->provider_data;
+	cm_event.local_addr = cm_id->local_addr;
+	cm_event.remote_addr = cm_id->remote_addr;
+	cm_event.private_data = NULL;
+	cm_event.private_data_len = 0;
+	nes_debug(NES_DBG_CM, "NODE %p Generating CLOSE\n", event->cm_node);
+	ret = cm_id->event_handler(cm_id, &cm_event);
+
 	nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
 
 
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
index 367b3d2..fafa350 100644
--- a/drivers/infiniband/hw/nes/nes_cm.h
+++ b/drivers/infiniband/hw/nes/nes_cm.h
@@ -76,6 +76,10 @@
 	NES_TIMER_TYPE_CLOSE,
 };
 
+#define NES_PASSIVE_STATE_INDICATED	0
+#define NES_DO_NOT_SEND_RESET_EVENT	1
+#define NES_SEND_RESET_EVENT		2
+
 #define MAX_NES_IFS 4
 
 #define SET_ACK 1
@@ -161,6 +165,8 @@
 
 #define NES_CM_DEF_SEQ2      0x18ed5740
 #define NES_CM_DEF_LOCAL_ID2 0xb807
+#define	MAX_CM_BUFFER	512
+
 
 typedef u32 nes_addr_t;
 
@@ -254,8 +260,6 @@
 
 /* per connection node and node state information */
 struct nes_cm_node {
-	u32                       hashkey;
-
 	nes_addr_t                loc_addr, rem_addr;
 	u16                       loc_port, rem_port;
 
@@ -292,7 +296,10 @@
 	int                       apbvt_set;
 	int                       accept_pend;
 	int			freed;
+	struct list_head	timer_entry;
+	struct list_head	reset_entry;
 	struct nes_qp		*nesqp;
+	atomic_t 		passive_state;
 };
 
 /* structure for client or CM to fill when making CM api calls. */
@@ -350,7 +357,6 @@
 	u32                     mtu;
 	u32                     free_tx_pkt_max;
 	u32                     rx_pkt_posted;
-	struct sk_buff_head     tx_free_list;
 	atomic_t                ht_node_cnt;
 	struct list_head        connected_nodes;
 	/* struct list_head hashtable[NES_CM_HASHTABLE_SIZE]; */
@@ -390,7 +396,7 @@
 			struct nes_cm_node *);
 	int (*reject)(struct nes_cm_core *, struct ietf_mpa_frame *,
 			struct nes_cm_node *);
-	void (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *,
+	int (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *,
 			struct sk_buff *);
 	int (*destroy_cm_core)(struct nes_cm_core *);
 	int (*get)(struct nes_cm_core *);
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 7c49cc8..5d139db 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -2541,7 +2541,7 @@
 {
 	struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
 
-	netif_rx_schedule(nesdev->netdev[nesvnic->netdev_index], &nesvnic->napi);
+	netif_rx_schedule(&nesvnic->napi);
 }
 
 
@@ -2700,27 +2700,33 @@
 							pkt_type, (pkt_type & NES_PKT_TYPE_APBVT_MASK)); */
 
 				if ((pkt_type & NES_PKT_TYPE_APBVT_MASK) == NES_PKT_TYPE_APBVT_BITS) {
-					nes_cm_recv(rx_skb, nesvnic->netdev);
+					if (nes_cm_recv(rx_skb, nesvnic->netdev))
+						rx_skb = NULL;
+				}
+				if (rx_skb == NULL)
+					goto skip_rx_indicate0;
+
+
+				if ((cqe_misc & NES_NIC_CQE_TAG_VALID) &&
+				    (nesvnic->vlan_grp != NULL)) {
+					vlan_tag = (u16)(le32_to_cpu(
+							cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX])
+							>> 16);
+					nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
+							nesvnic->netdev->name, vlan_tag);
+					if (nes_use_lro)
+						lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb,
+								nesvnic->vlan_grp, vlan_tag, NULL);
+					else
+						nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
 				} else {
-					if ((cqe_misc & NES_NIC_CQE_TAG_VALID) && (nesvnic->vlan_grp != NULL)) {
-						vlan_tag = (u16)(le32_to_cpu(
-								cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX])
-								>> 16);
-						nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
-								nesvnic->netdev->name, vlan_tag);
-						if (nes_use_lro)
-							lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb,
-									nesvnic->vlan_grp, vlan_tag, NULL);
-						else
-							nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
-					} else {
-						if (nes_use_lro)
-							lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL);
-						else
-							nes_netif_rx(rx_skb);
-					}
+					if (nes_use_lro)
+						lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL);
+					else
+						nes_netif_rx(rx_skb);
 				}
 
+skip_rx_indicate0:
 				nesvnic->netdev->last_rx = jiffies;
 				/* nesvnic->netstats.rx_packets++; */
 				/* nesvnic->netstats.rx_bytes += rx_pkt_size; */
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 7303586..57a47cf 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -99,7 +99,6 @@
 static int nes_netdev_poll(struct napi_struct *napi, int budget)
 {
 	struct nes_vnic *nesvnic = container_of(napi, struct nes_vnic, napi);
-	struct net_device *netdev = nesvnic->netdev;
 	struct nes_device *nesdev = nesvnic->nesdev;
 	struct nes_hw_nic_cq *nescq = &nesvnic->nic_cq;
 
@@ -112,7 +111,7 @@
 	nes_nic_ce_handler(nesdev, nescq);
 
 	if (nescq->cqes_pending == 0) {
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 		/* clear out completed cqes and arm */
 		nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
 				nescq->cq_number | (nescq->cqe_allocs_pending << 16));
@@ -797,14 +796,13 @@
 	int i;
 	u32 macaddr_low;
 	u16 macaddr_high;
-	DECLARE_MAC_BUF(mac);
 
 	if (!is_valid_ether_addr(mac_addr->sa_data))
 		return -EADDRNOTAVAIL;
 
 	memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len);
-	printk(PFX "%s: Address length = %d, Address = %s\n",
-	       __func__, netdev->addr_len, print_mac(mac, mac_addr->sa_data));
+	printk(PFX "%s: Address length = %d, Address = %pM\n",
+	       __func__, netdev->addr_len, mac_addr->sa_data);
 	macaddr_high  = ((u16)netdev->dev_addr[0]) << 8;
 	macaddr_high += (u16)netdev->dev_addr[1];
 	macaddr_low   = ((u32)netdev->dev_addr[2]) << 24;
@@ -909,9 +907,8 @@
 			if (mc_index >= max_pft_entries_avaiable)
 				break;
 			if (multicast_addr) {
-				DECLARE_MAC_BUF(mac);
-				nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %s to register 0x%04X nic_idx=%d\n",
-					  print_mac(mac, multicast_addr->dmi_addr),
+				nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %pM to register 0x%04X nic_idx=%d\n",
+					  multicast_addr->dmi_addr,
 					  perfect_filter_register_address+(mc_index * 8),
 					  mc_nic_index);
 				macaddr_high  = ((u16)multicast_addr->dmi_addr[0]) << 8;
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c
index fb8cbd7..aa9b734 100644
--- a/drivers/infiniband/hw/nes/nes_utils.c
+++ b/drivers/infiniband/hw/nes/nes_utils.c
@@ -540,11 +540,14 @@
 
 	if (!list_empty(&nesdev->cqp_avail_reqs)) {
 		spin_lock_irqsave(&nesdev->cqp.lock, flags);
-		cqp_request = list_entry(nesdev->cqp_avail_reqs.next,
+		if (!list_empty(&nesdev->cqp_avail_reqs)) {
+			cqp_request = list_entry(nesdev->cqp_avail_reqs.next,
 				struct nes_cqp_request, list);
-		list_del_init(&cqp_request->list);
+			list_del_init(&cqp_request->list);
+		}
 		spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
-	} else {
+	}
+	if (cqp_request == NULL) {
 		cqp_request = kzalloc(sizeof(struct nes_cqp_request), GFP_KERNEL);
 		if (cqp_request) {
 			cqp_request->dynamic = 1;
@@ -679,9 +682,8 @@
 
 	/* DELETE or RESOLVE */
 	if (arp_index == nesadapter->arp_table_size) {
-		nes_debug(NES_DBG_NETDEV, "MAC for " NIPQUAD_FMT " not in ARP table - cannot %s\n",
-			  HIPQUAD(ip_addr),
-			  action == NES_ARP_RESOLVE ? "resolve" : "delete");
+		nes_debug(NES_DBG_NETDEV, "MAC for %pI4 not in ARP table - cannot %s\n",
+			  &ip_addr, action == NES_ARP_RESOLVE ? "resolve" : "delete");
 		return -1;
 	}
 
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index d36c9a0..4fdb7245 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -1695,13 +1695,8 @@
 			/* use 4k pbl */
 			nes_debug(NES_DBG_CQ, "pbl_entries=%u, use a 4k PBL\n", pbl_entries);
 			if (nesadapter->free_4kpbl == 0) {
-				if (cqp_request->dynamic) {
-					spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-					kfree(cqp_request);
-				} else {
-					list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
-					spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-				}
+				spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+				nes_free_cqp_request(nesdev, cqp_request);
 				if (!context)
 					pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
 							nescq->hw_cq.cq_pbase);
@@ -1717,13 +1712,8 @@
 			/* use 256 byte pbl */
 			nes_debug(NES_DBG_CQ, "pbl_entries=%u, use a 256 byte PBL\n", pbl_entries);
 			if (nesadapter->free_256pbl == 0) {
-				if (cqp_request->dynamic) {
-					spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-					kfree(cqp_request);
-				} else {
-					list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
-					spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-				}
+				spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+				nes_free_cqp_request(nesdev, cqp_request);
 				if (!context)
 					pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
 							nescq->hw_cq.cq_pbase);
@@ -1928,13 +1918,8 @@
 			/* Two level PBL */
 			if ((pbl_count+1) > nesadapter->free_4kpbl) {
 				nes_debug(NES_DBG_MR, "Out of 4KB Pbls for two level request.\n");
-				if (cqp_request->dynamic) {
-					spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-					kfree(cqp_request);
-				} else {
-					list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
-					spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-				}
+				spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+				nes_free_cqp_request(nesdev, cqp_request);
 				return -ENOMEM;
 			} else {
 				nesadapter->free_4kpbl -= pbl_count+1;
@@ -1942,13 +1927,8 @@
 		} else if (residual_page_count > 32) {
 			if (pbl_count > nesadapter->free_4kpbl) {
 				nes_debug(NES_DBG_MR, "Out of 4KB Pbls.\n");
-				if (cqp_request->dynamic) {
-					spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-					kfree(cqp_request);
-				} else {
-					list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
-					spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-				}
+				spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+				nes_free_cqp_request(nesdev, cqp_request);
 				return -ENOMEM;
 			} else {
 				nesadapter->free_4kpbl -= pbl_count;
@@ -1956,13 +1936,8 @@
 		} else {
 			if (pbl_count > nesadapter->free_256pbl) {
 				nes_debug(NES_DBG_MR, "Out of 256B Pbls.\n");
-				if (cqp_request->dynamic) {
-					spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-					kfree(cqp_request);
-				} else {
-					list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
-					spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-				}
+				spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+				nes_free_cqp_request(nesdev, cqp_request);
 				return -ENOMEM;
 			} else {
 				nesadapter->free_256pbl -= pbl_count;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index e0c7dfa..753a983 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -732,29 +732,6 @@
 	do { (void) (priv); } while (0)
 #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */
 
-
-#define IPOIB_GID_FMT		"%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:" \
-				"%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x"
-
-#define IPOIB_GID_RAW_ARG(gid)	((u8 *)(gid))[0], \
-				((u8 *)(gid))[1], \
-				((u8 *)(gid))[2], \
-				((u8 *)(gid))[3], \
-				((u8 *)(gid))[4], \
-				((u8 *)(gid))[5], \
-				((u8 *)(gid))[6], \
-				((u8 *)(gid))[7], \
-				((u8 *)(gid))[8], \
-				((u8 *)(gid))[9], \
-				((u8 *)(gid))[10],\
-				((u8 *)(gid))[11],\
-				((u8 *)(gid))[12],\
-				((u8 *)(gid))[13],\
-				((u8 *)(gid))[14],\
-				((u8 *)(gid))[15]
-
-#define IPOIB_GID_ARG(gid)	IPOIB_GID_RAW_ARG((gid).raw)
-
 #define IPOIB_QPN(ha) (be32_to_cpup((__be32 *) ha) & 0xffffff)
 
 #endif /* _IPOIB_H */
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 7b14c2c..47d588b 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -1128,8 +1128,8 @@
 		goto err_send_cm;
 	}
 
-	ipoib_dbg(priv, "Request connection 0x%x for gid " IPOIB_GID_FMT " qpn 0x%x\n",
-		  p->qp->qp_num, IPOIB_GID_ARG(pathrec->dgid), qpn);
+	ipoib_dbg(priv, "Request connection 0x%x for gid %pI6 qpn 0x%x\n",
+		  p->qp->qp_num, pathrec->dgid.raw, qpn);
 
 	return 0;
 
@@ -1276,8 +1276,8 @@
 	if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
 		list_move(&tx->list, &priv->cm.reap_list);
 		queue_work(ipoib_workqueue, &priv->cm.reap_task);
-		ipoib_dbg(priv, "Reap connection for gid " IPOIB_GID_FMT "\n",
-			  IPOIB_GID_ARG(tx->neigh->dgid));
+		ipoib_dbg(priv, "Reap connection for gid %pI6\n",
+			  tx->neigh->dgid.raw);
 		tx->neigh = NULL;
 	}
 }
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 28eb6f0..a192581 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -446,11 +446,11 @@
 		if (dev->features & NETIF_F_LRO)
 			lro_flush_all(&priv->lro.lro_mgr);
 
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		if (unlikely(ib_req_notify_cq(priv->recv_cq,
 					      IB_CQ_NEXT_COMP |
 					      IB_CQ_REPORT_MISSED_EVENTS)) &&
-		    netif_rx_reschedule(dev, napi))
+		    netif_rx_reschedule(napi))
 			goto poll_more;
 	}
 
@@ -462,7 +462,7 @@
 	struct net_device *dev = dev_ptr;
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 
-	netif_rx_schedule(dev, &priv->napi);
+	netif_rx_schedule(&priv->napi);
 }
 
 static void drain_tx_cq(struct net_device *dev)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 85257f6..19e06bc 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -360,9 +360,9 @@
 	spin_lock_irq(&priv->lock);
 
 	list_for_each_entry_safe(path, tp, &priv->path_list, list) {
-		ipoib_dbg(priv, "mark path LID 0x%04x GID " IPOIB_GID_FMT " invalid\n",
+		ipoib_dbg(priv, "mark path LID 0x%04x GID %pI6 invalid\n",
 			be16_to_cpu(path->pathrec.dlid),
-			IPOIB_GID_ARG(path->pathrec.dgid));
+			path->pathrec.dgid.raw);
 		path->valid =  0;
 	}
 
@@ -414,11 +414,11 @@
 	unsigned long flags;
 
 	if (!status)
-		ipoib_dbg(priv, "PathRec LID 0x%04x for GID " IPOIB_GID_FMT "\n",
-			  be16_to_cpu(pathrec->dlid), IPOIB_GID_ARG(pathrec->dgid));
+		ipoib_dbg(priv, "PathRec LID 0x%04x for GID %pI6\n",
+			  be16_to_cpu(pathrec->dlid), pathrec->dgid.raw);
 	else
-		ipoib_dbg(priv, "PathRec status %d for GID " IPOIB_GID_FMT "\n",
-			  status, IPOIB_GID_ARG(path->pathrec.dgid));
+		ipoib_dbg(priv, "PathRec status %d for GID %pI6\n",
+			  status, path->pathrec.dgid.raw);
 
 	skb_queue_head_init(&skqueue);
 
@@ -528,8 +528,8 @@
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 
-	ipoib_dbg(priv, "Start path record lookup for " IPOIB_GID_FMT "\n",
-		  IPOIB_GID_ARG(path->pathrec.dgid));
+	ipoib_dbg(priv, "Start path record lookup for %pI6\n",
+		  path->pathrec.dgid.raw);
 
 	init_completion(&path->done);
 
@@ -766,12 +766,11 @@
 
 			if ((be16_to_cpup((__be16 *) skb->data) != ETH_P_ARP) &&
 			    (be16_to_cpup((__be16 *) skb->data) != ETH_P_RARP)) {
-				ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x "
-					   IPOIB_GID_FMT "\n",
+				ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x %pI6\n",
 					   skb->dst ? "neigh" : "dst",
 					   be16_to_cpup((__be16 *) skb->data),
 					   IPOIB_QPN(phdr->hwaddr),
-					   IPOIB_GID_RAW_ARG(phdr->hwaddr + 4));
+					   phdr->hwaddr + 4);
 				dev_kfree_skb_any(skb);
 				++dev->stats.tx_dropped;
 				return NETDEV_TX_OK;
@@ -847,9 +846,9 @@
 	else
 		return;
 	ipoib_dbg(priv,
-		  "neigh_cleanup for %06x " IPOIB_GID_FMT "\n",
+		  "neigh_cleanup for %06x %pI6\n",
 		  IPOIB_QPN(n->ha),
-		  IPOIB_GID_RAW_ARG(n->ha + 4));
+		  n->ha + 4);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index d9d1223..a2eb3b9 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -71,9 +71,8 @@
 	struct ipoib_neigh *neigh, *tmp;
 	int tx_dropped = 0;
 
-	ipoib_dbg_mcast(netdev_priv(dev),
-			"deleting multicast group " IPOIB_GID_FMT "\n",
-			IPOIB_GID_ARG(mcast->mcmember.mgid));
+	ipoib_dbg_mcast(netdev_priv(dev), "deleting multicast group %pI6\n",
+			mcast->mcmember.mgid.raw);
 
 	spin_lock_irq(&priv->lock);
 
@@ -205,9 +204,8 @@
 
 	if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
 		if (test_and_set_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) {
-			ipoib_warn(priv, "multicast group " IPOIB_GID_FMT
-				   " already attached\n",
-				   IPOIB_GID_ARG(mcast->mcmember.mgid));
+			ipoib_warn(priv, "multicast group %pI6 already attached\n",
+				   mcast->mcmember.mgid.raw);
 
 			return 0;
 		}
@@ -215,9 +213,8 @@
 		ret = ipoib_mcast_attach(dev, be16_to_cpu(mcast->mcmember.mlid),
 					 &mcast->mcmember.mgid, set_qkey);
 		if (ret < 0) {
-			ipoib_warn(priv, "couldn't attach QP to multicast group "
-				   IPOIB_GID_FMT "\n",
-				   IPOIB_GID_ARG(mcast->mcmember.mgid));
+			ipoib_warn(priv, "couldn't attach QP to multicast group %pI6\n",
+				   mcast->mcmember.mgid.raw);
 
 			clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags);
 			return ret;
@@ -248,9 +245,8 @@
 			mcast->ah = ah;
 			spin_unlock_irq(&priv->lock);
 
-			ipoib_dbg_mcast(priv, "MGID " IPOIB_GID_FMT
-					" AV %p, LID 0x%04x, SL %d\n",
-					IPOIB_GID_ARG(mcast->mcmember.mgid),
+			ipoib_dbg_mcast(priv, "MGID %pI6 AV %p, LID 0x%04x, SL %d\n",
+					mcast->mcmember.mgid.raw,
 					mcast->ah->ah,
 					be16_to_cpu(mcast->mcmember.mlid),
 					mcast->mcmember.sl);
@@ -295,9 +291,8 @@
 
 	if (status) {
 		if (mcast->logcount++ < 20)
-			ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for "
-					IPOIB_GID_FMT ", status %d\n",
-					IPOIB_GID_ARG(mcast->mcmember.mgid), status);
+			ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for %pI6, status %d\n",
+					mcast->mcmember.mgid.raw, status);
 
 		/* Flush out any queued packets */
 		netif_tx_lock_bh(dev);
@@ -356,9 +351,8 @@
 		ipoib_warn(priv, "ib_sa_join_multicast failed (ret = %d)\n",
 			   ret);
 	} else {
-		ipoib_dbg_mcast(priv, "no multicast record for " IPOIB_GID_FMT
-				", starting join\n",
-				IPOIB_GID_ARG(mcast->mcmember.mgid));
+		ipoib_dbg_mcast(priv, "no multicast record for %pI6, starting join\n",
+				mcast->mcmember.mgid.raw);
 	}
 
 	return ret;
@@ -386,9 +380,8 @@
 	struct net_device *dev = mcast->dev;
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 
-	ipoib_dbg_mcast(priv, "join completion for " IPOIB_GID_FMT
-			" (status %d)\n",
-			IPOIB_GID_ARG(mcast->mcmember.mgid), status);
+	ipoib_dbg_mcast(priv, "join completion for %pI6 (status %d)\n",
+			mcast->mcmember.mgid.raw, status);
 
 	/* We trap for port events ourselves. */
 	if (status == -ENETRESET)
@@ -417,15 +410,11 @@
 
 	if (mcast->logcount++ < 20) {
 		if (status == -ETIMEDOUT) {
-			ipoib_dbg_mcast(priv, "multicast join failed for " IPOIB_GID_FMT
-					", status %d\n",
-					IPOIB_GID_ARG(mcast->mcmember.mgid),
-					status);
+			ipoib_dbg_mcast(priv, "multicast join failed for %pI6, status %d\n",
+					mcast->mcmember.mgid.raw, status);
 		} else {
-			ipoib_warn(priv, "multicast join failed for "
-				   IPOIB_GID_FMT ", status %d\n",
-				   IPOIB_GID_ARG(mcast->mcmember.mgid),
-				   status);
+			ipoib_warn(priv, "multicast join failed for %pI6, status %d\n",
+				   mcast->mcmember.mgid.raw, status);
 		}
 	}
 
@@ -457,8 +446,7 @@
 	ib_sa_comp_mask comp_mask;
 	int ret = 0;
 
-	ipoib_dbg_mcast(priv, "joining MGID " IPOIB_GID_FMT "\n",
-			IPOIB_GID_ARG(mcast->mcmember.mgid));
+	ipoib_dbg_mcast(priv, "joining MGID %pI6\n", mcast->mcmember.mgid.raw);
 
 	rec.mgid     = mcast->mcmember.mgid;
 	rec.port_gid = priv->local_gid;
@@ -643,8 +631,8 @@
 		ib_sa_free_multicast(mcast->mc);
 
 	if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) {
-		ipoib_dbg_mcast(priv, "leaving MGID " IPOIB_GID_FMT "\n",
-				IPOIB_GID_ARG(mcast->mcmember.mgid));
+		ipoib_dbg_mcast(priv, "leaving MGID %pI6\n",
+				mcast->mcmember.mgid.raw);
 
 		/* Remove ourselves from the multicast group */
 		ret = ib_detach_mcast(priv->qp, &mcast->mcmember.mgid,
@@ -675,8 +663,8 @@
 	mcast = __ipoib_mcast_find(dev, mgid);
 	if (!mcast) {
 		/* Let's create a new send only group now */
-		ipoib_dbg_mcast(priv, "setting up send only multicast group for "
-				IPOIB_GID_FMT "\n", IPOIB_GID_RAW_ARG(mgid));
+		ipoib_dbg_mcast(priv, "setting up send only multicast group for %pI6\n",
+				mgid);
 
 		mcast = ipoib_mcast_alloc(dev, 0);
 		if (!mcast) {
@@ -809,14 +797,14 @@
 			/* ignore group which is directly joined by userspace */
 			if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) &&
 			    !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) {
-				ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid "
-						IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid));
+				ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid %pI6\n",
+						mgid.raw);
 				continue;
 			}
 
 			/* Not found or send-only group, let's add a new entry */
-			ipoib_dbg_mcast(priv, "adding multicast entry for mgid "
-					IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid));
+			ipoib_dbg_mcast(priv, "adding multicast entry for mgid %pI6\n",
+					mgid.raw);
 
 			nmcast = ipoib_mcast_alloc(dev, 0);
 			if (!nmcast) {
@@ -849,8 +837,8 @@
 	list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) {
 		if (!test_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags) &&
 		    !test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
-			ipoib_dbg_mcast(priv, "deleting multicast group " IPOIB_GID_FMT "\n",
-					IPOIB_GID_ARG(mcast->mcmember.mgid));
+			ipoib_dbg_mcast(priv, "deleting multicast group %pI6\n",
+					mcast->mcmember.mgid.raw);
 
 			rb_erase(&mcast->rb_node, &priv->multicast_tree);
 
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 81a8262..8611195 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -252,6 +252,9 @@
 	wait_queue_head_t	     wait;          /* waitq for conn/disconn  */
 	atomic_t                     post_recv_buf_count; /* posted rx count   */
 	atomic_t                     post_send_buf_count; /* posted tx count   */
+	atomic_t                     unexpected_pdu_count;/* count of received *
+							   * unexpected pdus   *
+							   * not yet retired   */
 	char 			     name[ISER_OBJECT_NAME_SIZE];
 	struct iser_page_vec         *page_vec;     /* represents SG to fmr maps*
 						     * maps serialized as tx is*/
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index cdd2831..ed1aff2 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -183,14 +183,8 @@
 	struct iser_regd_buf *regd_data;
 	struct iser_dto      *recv_dto = NULL;
 	struct iser_device  *device = iser_conn->ib_conn->device;
-	int rx_data_size, err = 0;
-
-	rx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO);
-	if (rx_desc == NULL) {
-		iser_err("Failed to alloc desc for post recv\n");
-		return -ENOMEM;
-	}
-	rx_desc->type = ISCSI_RX;
+	int rx_data_size, err;
+	int posts, outstanding_unexp_pdus;
 
 	/* for the login sequence we must support rx of upto 8K; login is done
 	 * after conn create/bind (connect) and conn stop/bind (reconnect),
@@ -201,46 +195,80 @@
 	else /* FIXME till user space sets conn->max_recv_dlength correctly */
 		rx_data_size = 128;
 
-	rx_desc->data = kmalloc(rx_data_size, GFP_NOIO);
-	if (rx_desc->data == NULL) {
-		iser_err("Failed to alloc data buf for post recv\n");
-		err = -ENOMEM;
-		goto post_rx_kmalloc_failure;
+	outstanding_unexp_pdus =
+		atomic_xchg(&iser_conn->ib_conn->unexpected_pdu_count, 0);
+
+	/*
+	 * in addition to the response buffer, replace those consumed by
+	 * unexpected pdus.
+	 */
+	for (posts = 0; posts < 1 + outstanding_unexp_pdus; posts++) {
+		rx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO);
+		if (rx_desc == NULL) {
+			iser_err("Failed to alloc desc for post recv %d\n",
+				 posts);
+			err = -ENOMEM;
+			goto post_rx_cache_alloc_failure;
+		}
+		rx_desc->type = ISCSI_RX;
+		rx_desc->data = kmalloc(rx_data_size, GFP_NOIO);
+		if (rx_desc->data == NULL) {
+			iser_err("Failed to alloc data buf for post recv %d\n",
+				 posts);
+			err = -ENOMEM;
+			goto post_rx_kmalloc_failure;
+		}
+
+		recv_dto = &rx_desc->dto;
+		recv_dto->ib_conn = iser_conn->ib_conn;
+		recv_dto->regd_vector_len = 0;
+
+		regd_hdr = &rx_desc->hdr_regd_buf;
+		memset(regd_hdr, 0, sizeof(struct iser_regd_buf));
+		regd_hdr->device  = device;
+		regd_hdr->virt_addr  = rx_desc; /* == &rx_desc->iser_header */
+		regd_hdr->data_size  = ISER_TOTAL_HEADERS_LEN;
+
+		iser_reg_single(device, regd_hdr, DMA_FROM_DEVICE);
+
+		iser_dto_add_regd_buff(recv_dto, regd_hdr, 0, 0);
+
+		regd_data = &rx_desc->data_regd_buf;
+		memset(regd_data, 0, sizeof(struct iser_regd_buf));
+		regd_data->device  = device;
+		regd_data->virt_addr  = rx_desc->data;
+		regd_data->data_size  = rx_data_size;
+
+		iser_reg_single(device, regd_data, DMA_FROM_DEVICE);
+
+		iser_dto_add_regd_buff(recv_dto, regd_data, 0, 0);
+
+		err = iser_post_recv(rx_desc);
+		if (err) {
+			iser_err("Failed iser_post_recv for post %d\n", posts);
+			goto post_rx_post_recv_failure;
+		}
 	}
+	/* all posts successful */
+	return 0;
 
-	recv_dto = &rx_desc->dto;
-	recv_dto->ib_conn = iser_conn->ib_conn;
-	recv_dto->regd_vector_len = 0;
-
-	regd_hdr = &rx_desc->hdr_regd_buf;
-	memset(regd_hdr, 0, sizeof(struct iser_regd_buf));
-	regd_hdr->device  = device;
-	regd_hdr->virt_addr  = rx_desc; /* == &rx_desc->iser_header */
-	regd_hdr->data_size  = ISER_TOTAL_HEADERS_LEN;
-
-	iser_reg_single(device, regd_hdr, DMA_FROM_DEVICE);
-
-	iser_dto_add_regd_buff(recv_dto, regd_hdr, 0, 0);
-
-	regd_data = &rx_desc->data_regd_buf;
-	memset(regd_data, 0, sizeof(struct iser_regd_buf));
-	regd_data->device  = device;
-	regd_data->virt_addr  = rx_desc->data;
-	regd_data->data_size  = rx_data_size;
-
-	iser_reg_single(device, regd_data, DMA_FROM_DEVICE);
-
-	iser_dto_add_regd_buff(recv_dto, regd_data, 0, 0);
-
-	err = iser_post_recv(rx_desc);
-	if (!err)
-		return 0;
-
-	/* iser_post_recv failed */
+post_rx_post_recv_failure:
 	iser_dto_buffs_release(recv_dto);
 	kfree(rx_desc->data);
 post_rx_kmalloc_failure:
 	kmem_cache_free(ig.desc_cache, rx_desc);
+post_rx_cache_alloc_failure:
+	if (posts > 0) {
+		/*
+		 * response buffer posted, but did not replace all unexpected
+		 * pdu recv bufs. Ignore error, retry occurs next send
+		 */
+		outstanding_unexp_pdus -= (posts - 1);
+		err = 0;
+	}
+	atomic_add(outstanding_unexp_pdus,
+		   &iser_conn->ib_conn->unexpected_pdu_count);
+
 	return err;
 }
 
@@ -274,8 +302,10 @@
 	struct iscsi_iser_conn *iser_conn = conn->dd_data;
 
 	int i;
-	/* no need to keep it in a var, we are after login so if this should
-	 * be negotiated, by now the result should be available here */
+	/*
+	 * FIXME this value should be declared to the target during login with
+	 * the MaxOutstandingUnexpectedPDUs key when supported
+	 */
 	int initial_post_recv_bufs_num = ISER_MAX_RX_MISC_PDUS;
 
 	iser_dbg("Initially post: %d\n", initial_post_recv_bufs_num);
@@ -478,6 +508,7 @@
 	int err = 0;
 	struct iser_regd_buf *regd_buf;
 	struct iser_device *device;
+	unsigned char opcode;
 
 	if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
 		iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
@@ -512,10 +543,15 @@
 				       data_seg_len);
 	}
 
-	if (iser_post_receive_control(conn) != 0) {
-		iser_err("post_rcv_buff failed!\n");
-		err = -ENOMEM;
-		goto send_control_error;
+	opcode = task->hdr->opcode & ISCSI_OPCODE_MASK;
+
+	/* post recv buffer for response if one is expected */
+	if (!(opcode == ISCSI_OP_NOOP_OUT && task->hdr->itt == RESERVED_ITT)) {
+		if (iser_post_receive_control(conn) != 0) {
+			iser_err("post_rcv_buff failed!\n");
+			err = -ENOMEM;
+			goto send_control_error;
+		}
 	}
 
 	err = iser_post_send(mdesc);
@@ -586,6 +622,20 @@
 	 * parallel to the execution of iser_conn_term. So the code that waits *
 	 * for the posted rx bufs refcount to become zero handles everything   */
 	atomic_dec(&conn->ib_conn->post_recv_buf_count);
+
+	/*
+	 * if an unexpected PDU was received then the recv wr consumed must
+	 * be replaced, this is done in the next send of a control-type PDU
+	 */
+	if (opcode == ISCSI_OP_NOOP_IN && hdr->itt == RESERVED_ITT) {
+		/* nop-in with itt = 0xffffffff */
+		atomic_inc(&conn->ib_conn->unexpected_pdu_count);
+	}
+	else if (opcode == ISCSI_OP_ASYNC_EVENT) {
+		/* asyncronous message */
+		atomic_inc(&conn->ib_conn->unexpected_pdu_count);
+	}
+	/* a reject PDU consumes the recv buf posted for the response */
 }
 
 void iser_snd_completion(struct iser_desc *tx_desc)
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 26ff621..319b188 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -498,6 +498,7 @@
 	init_waitqueue_head(&ib_conn->wait);
 	atomic_set(&ib_conn->post_recv_buf_count, 0);
 	atomic_set(&ib_conn->post_send_buf_count, 0);
+	atomic_set(&ib_conn->unexpected_pdu_count, 0);
 	atomic_set(&ib_conn->refcount, 1);
 	INIT_LIST_HEAD(&ib_conn->conn_list);
 	spin_lock_init(&ib_conn->lock);
@@ -515,14 +516,14 @@
 	struct sockaddr *src, *dst;
 	int err = 0;
 
-	sprintf(ib_conn->name,"%d.%d.%d.%d:%d",
-		NIPQUAD(dst_addr->sin_addr.s_addr), dst_addr->sin_port);
+	sprintf(ib_conn->name, "%pI4:%d",
+		&dst_addr->sin_addr.s_addr, dst_addr->sin_port);
 
 	/* the device is known only --after-- address resolution */
 	ib_conn->device = NULL;
 
-	iser_err("connecting to: %d.%d.%d.%d, port 0x%x\n",
-		 NIPQUAD(dst_addr->sin_addr), dst_addr->sin_port);
+	iser_err("connecting to: %pI4, port 0x%x\n",
+		 &dst_addr->sin_addr, dst_addr->sin_port);
 
 	ib_conn->state = ISER_CONN_PENDING;
 
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 5b8b533..7c13db8 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1514,15 +1514,7 @@
 	    target->state == SRP_TARGET_REMOVED)
 		return -ENODEV;
 
-	return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[0]),
-		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[1]),
-		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[2]),
-		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[3]),
-		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[4]),
-		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[5]),
-		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[6]),
-		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
+	return sprintf(buf, "%pI6\n", target->path.dgid.raw);
 }
 
 static ssize_t show_orig_dgid(struct device *dev,
@@ -1534,15 +1526,7 @@
 	    target->state == SRP_TARGET_REMOVED)
 		return -ENODEV;
 
-	return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-		       be16_to_cpu(target->orig_dgid[0]),
-		       be16_to_cpu(target->orig_dgid[1]),
-		       be16_to_cpu(target->orig_dgid[2]),
-		       be16_to_cpu(target->orig_dgid[3]),
-		       be16_to_cpu(target->orig_dgid[4]),
-		       be16_to_cpu(target->orig_dgid[5]),
-		       be16_to_cpu(target->orig_dgid[6]),
-		       be16_to_cpu(target->orig_dgid[7]));
+	return sprintf(buf, "%pI6\n", target->orig_dgid);
 }
 
 static ssize_t show_zero_req_lim(struct device *dev,
@@ -1883,19 +1867,12 @@
 
 	shost_printk(KERN_DEBUG, target->scsi_host, PFX
 		     "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
-		     "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+		     "service_id %016llx dgid %pI6\n",
 	       (unsigned long long) be64_to_cpu(target->id_ext),
 	       (unsigned long long) be64_to_cpu(target->ioc_guid),
 	       be16_to_cpu(target->path.pkey),
 	       (unsigned long long) be64_to_cpu(target->service_id),
-	       (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[0]),
-	       (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[2]),
-	       (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[4]),
-	       (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[6]),
-	       (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[8]),
-	       (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[10]),
-	       (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[12]),
-	       (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[14]));
+	       target->path.dgid.raw);
 
 	ret = srp_create_target_ib(target);
 	if (ret)
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
index c600ab7..5c8a1bc 100644
--- a/drivers/input/keyboard/sh_keysc.c
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <asm/sh_keysc.h>
 
@@ -39,6 +40,7 @@
 
 struct sh_keysc_priv {
 	void __iomem *iomem_base;
+	struct clk *clk;
 	unsigned long last_keys;
 	struct input_dev *input;
 	struct sh_keysc_info pdata;
@@ -125,6 +127,7 @@
 	struct sh_keysc_info *pdata;
 	struct resource *res;
 	struct input_dev *input;
+	char clk_name[8];
 	int i, k;
 	int irq, error;
 
@@ -165,11 +168,19 @@
 		goto err1;
 	}
 
+	snprintf(clk_name, sizeof(clk_name), "keysc%d", pdev->id);
+	priv->clk = clk_get(&pdev->dev, clk_name);
+	if (IS_ERR(priv->clk)) {
+		dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+		error = PTR_ERR(priv->clk);
+		goto err2;
+	}
+
 	priv->input = input_allocate_device();
 	if (!priv->input) {
 		dev_err(&pdev->dev, "failed to allocate input device\n");
 		error = -ENOMEM;
-		goto err2;
+		goto err3;
 	}
 
 	input = priv->input;
@@ -187,7 +198,7 @@
 	error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
 	if (error) {
 		dev_err(&pdev->dev, "failed to request IRQ\n");
-		goto err3;
+		goto err4;
 	}
 
 	for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
@@ -199,18 +210,22 @@
 	error = input_register_device(input);
 	if (error) {
 		dev_err(&pdev->dev, "failed to register input device\n");
-		goto err4;
+		goto err5;
 	}
 
+	clk_enable(priv->clk);
+
 	iowrite16((sh_keysc_mode[pdata->mode].kymd << 8) |
 		  pdata->scan_timing, priv->iomem_base + KYCR1_OFFS);
 	iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
 	iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS);
 	return 0;
- err4:
+ err5:
 	free_irq(irq, pdev);
- err3:
+ err4:
 	input_free_device(input);
+ err3:
+	clk_put(priv->clk);
  err2:
 	iounmap(priv->iomem_base);
  err1:
@@ -230,6 +245,9 @@
 	free_irq(platform_get_irq(pdev, 0), pdev);
 	iounmap(priv->iomem_base);
 
+	clk_disable(priv->clk);
+	clk_put(priv->clk);
+
 	platform_set_drvdata(pdev, NULL);
 	kfree(priv);
 	return 0;
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
index 550e80f..0aa66ec 100644
--- a/drivers/isdn/capi/capifs.c
+++ b/drivers/isdn/capi/capifs.c
@@ -156,8 +156,8 @@
 	if (!inode)
 		return;
 	inode->i_ino = number+2;
-	inode->i_uid = config.setuid ? config.uid : current->fsuid;
-	inode->i_gid = config.setgid ? config.gid : current->fsgid;
+	inode->i_uid = config.setuid ? config.uid : current_fsuid();
+	inode->i_gid = config.setgid ? config.gid : current_fsgid();
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	init_special_inode(inode, S_IFCHR|config.mode, device);
 	//inode->i_op = &capifs_file_inode_operations;
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c
index c2bd97d..2a4ce96 100644
--- a/drivers/isdn/gigaset/asyncdata.c
+++ b/drivers/isdn/gigaset/asyncdata.c
@@ -17,8 +17,6 @@
 #include <linux/crc-ccitt.h>
 #include <linux/bitrev.h>
 
-//#define GIG_M10x_STUFF_VOICE_DATA
-
 /* check if byte must be stuffed/escaped
  * I'm not sure which data should be encoded.
  * Therefore I will go the hard way and decode every value
@@ -147,19 +145,17 @@
 			}
 byte_stuff:
 			c ^= PPP_TRANS;
-#ifdef CONFIG_GIGASET_DEBUG
 			if (unlikely(!muststuff(c)))
 				gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c);
-#endif
 		} else if (unlikely(c == PPP_FLAG)) {
 			if (unlikely(inputstate & INS_skip_frame)) {
-				if (!(inputstate & INS_have_data)) { /* 7E 7E */
 #ifdef CONFIG_GIGASET_DEBUG
+				if (!(inputstate & INS_have_data)) { /* 7E 7E */
 					++bcs->emptycount;
-#endif
 				} else
 					gig_dbg(DEBUG_HDLC,
 					    "7e----------------------------");
+#endif
 
 				/* end of frame */
 				error = 1;
@@ -226,11 +222,9 @@
 			}
 
 			break;
-#ifdef CONFIG_GIGASET_DEBUG
 		} else if (unlikely(muststuff(c))) {
 			/* Should not happen. Possible after ZDLE=1<CR><LF>. */
 			gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
-#endif
 		}
 
 		/* add character */
@@ -394,20 +388,16 @@
 					inbuf->inputstate &= ~INS_DLE_char;
 					switch (c) {
 					case 'X': /*begin of command*/
-#ifdef CONFIG_GIGASET_DEBUG
 						if (inbuf->inputstate & INS_command)
-							dev_err(cs->dev,
+							dev_warn(cs->dev,
 					"received <DLE> 'X' in command mode\n");
-#endif
 						inbuf->inputstate |=
 							INS_command | INS_DLE_command;
 						break;
 					case '.': /*end of command*/
-#ifdef CONFIG_GIGASET_DEBUG
 						if (!(inbuf->inputstate & INS_command))
-							dev_err(cs->dev,
+							dev_warn(cs->dev,
 					"received <DLE> '.' in hdlc mode\n");
-#endif
 						inbuf->inputstate &= cs->dle ?
 							~(INS_DLE_command|INS_command)
 							: ~INS_DLE_command;
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 3f11910..18dd8aa 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -2067,7 +2067,7 @@
 
 	bcs->hw.bas = ubc = kmalloc(sizeof(struct bas_bc_state), GFP_KERNEL);
 	if (!ubc) {
-		err("could not allocate bas_bc_state");
+		pr_err("out of memory\n");
 		return 0;
 	}
 
@@ -2081,7 +2081,7 @@
 	ubc->isooutdone = ubc->isooutfree = ubc->isooutovfl = NULL;
 	ubc->numsub = 0;
 	if (!(ubc->isooutbuf = kmalloc(sizeof(struct isowbuf_t), GFP_KERNEL))) {
-		err("could not allocate isochronous output buffer");
+		pr_err("out of memory\n");
 		kfree(ubc);
 		bcs->hw.bas = NULL;
 		return 0;
@@ -2136,8 +2136,10 @@
 	struct bas_cardstate *ucs;
 
 	cs->hw.bas = ucs = kmalloc(sizeof *ucs, GFP_KERNEL);
-	if (!ucs)
+	if (!ucs) {
+		pr_err("out of memory\n");
 		return 0;
+	}
 
 	ucs->urb_cmd_in = NULL;
 	ucs->urb_cmd_out = NULL;
@@ -2503,12 +2505,11 @@
 	/* register this driver with the USB subsystem */
 	result = usb_register(&gigaset_usb_driver);
 	if (result < 0) {
-		err("usb_register failed (error %d)", -result);
+		pr_err("error %d registering USB driver\n", -result);
 		goto error;
 	}
 
-	info(DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	pr_info(DRIVER_DESC "\n");
 	return 0;
 
 error:
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 9d3ce77..0048ce9 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -580,7 +580,7 @@
 	} else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
 		skb_reserve(bcs->skb, HW_HDR_LEN);
 	else {
-		warn("could not allocate skb");
+		pr_err("out of memory\n");
 		bcs->inputstate |= INS_skip_frame;
 	}
 
@@ -634,20 +634,20 @@
 
 	gig_dbg(DEBUG_INIT, "allocating cs");
 	if (!(cs = alloc_cs(drv))) {
-		err("maximum number of devices exceeded");
+		pr_err("maximum number of devices exceeded\n");
 		return NULL;
 	}
 
 	gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
 	cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
 	if (!cs->bcs) {
-		err("out of memory");
+		pr_err("out of memory\n");
 		goto error;
 	}
 	gig_dbg(DEBUG_INIT, "allocating inbuf");
 	cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
 	if (!cs->inbuf) {
-		err("out of memory");
+		pr_err("out of memory\n");
 		goto error;
 	}
 
@@ -690,7 +690,7 @@
 	for (i = 0; i < channels; ++i) {
 		gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
 		if (!gigaset_initbcs(cs->bcs + i, cs, i)) {
-			err("could not allocate channel %d data", i);
+			pr_err("could not allocate channel %d data\n", i);
 			goto error;
 		}
 	}
@@ -720,17 +720,15 @@
 
 	gig_dbg(DEBUG_INIT, "setting up iif");
 	if (!gigaset_register_to_LL(cs, modulename)) {
-		err("register_isdn failed");
+		pr_err("error registering ISDN device\n");
 		goto error;
 	}
 
 	make_valid(cs, VALID_ID);
 	++cs->cs_init;
 	gig_dbg(DEBUG_INIT, "setting up hw");
-	if (!cs->ops->initcshw(cs)) {
-		err("could not allocate device specific data");
+	if (!cs->ops->initcshw(cs))
 		goto error;
-	}
 
 	++cs->cs_init;
 
@@ -836,7 +834,7 @@
 	for (i = 0; i < cs->channels; ++i) {
 		gigaset_freebcs(cs->bcs + i);
 		if (!gigaset_initbcs(cs->bcs + i, cs, i))
-			break;			//FIXME error handling
+			pr_err("could not allocate channel %d data\n", i);
 	}
 
 	if (cs->waiting) {
@@ -1120,8 +1118,7 @@
 	if (gigaset_debuglevel == 1)
 		gigaset_debuglevel = DEBUG_DEFAULT;
 
-	info(DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	pr_info(DRIVER_DESC "\n");
 	return 0;
 }
 
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index 5cbf64d8..e582a48 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -203,15 +203,6 @@
 	{EV_TIMEOUT,  120,121, -1,                  0, 0, {ACT_FAILVER, ACT_INIT}},
 	{RSP_ERROR,   120,121, -1,                  0, 0, {ACT_FAILVER, ACT_INIT}},
 	{RSP_OK,      121,121, -1,                  0, 0, {ACT_GOTVER,  ACT_INIT}},
-#if 0
-	{EV_TIMEOUT,  120,121, -1,                130, 5, {ACT_FAILVER},   "^SGCI=1\r"},
-	{RSP_ERROR,   120,121, -1,                130, 5, {ACT_FAILVER},   "^SGCI=1\r"},
-	{RSP_OK,      121,121, -1,                130, 5, {ACT_GOTVER},    "^SGCI=1\r"},
-
-	{RSP_OK,      130,130, -1,                  0, 0, {ACT_INIT}},
-	{RSP_ERROR,   130,130, -1,                  0, 0, {ACT_FAILINIT}},
-	{EV_TIMEOUT,  130,130, -1,                  0, 0, {ACT_FAILINIT}},
-#endif
 
 	/* leave dle mode */
 	{RSP_INIT,      0,  0,SEQ_DLE0,           201, 5, {0},             "^SDLE=0\r"},
@@ -260,10 +251,6 @@
 	{RSP_INIT,      0,  0,SEQ_NOCID,            0, 0, {ACT_ABORTCID}},
 
 	/* reset */
-#if 0
-	{RSP_INIT,      0,  0,SEQ_SHUTDOWN,       503, 5, {0},             "^SGCI=0\r"},
-	{RSP_OK,      503,503, -1,                504, 5, {0},             "Z\r"},
-#endif
 	{RSP_INIT,      0,  0,SEQ_SHUTDOWN,       504, 5, {0},             "Z\r"},
 	{RSP_OK,      504,504, -1,                  0, 0, {ACT_SDOWN}},
 	{RSP_ERROR,   501,599, -1,                  0, 0, {ACT_FAILSDOWN}},
@@ -391,24 +378,6 @@
 };
 
 
-#if 0
-static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME
-{
-	/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
-
-	{RSP_ANY,      -1, -1, -1,                 -1,-1, ACT_WARN,         NULL},
-	{RSP_LAST,0,0,0,0,0,0}
-};
-
-static struct reply_t tab_cid[] = /* no dle mode */ //FIXME
-{
-	/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
-
-	{RSP_ANY,      -1, -1, -1,                 -1,-1, ACT_WARN,         NULL},
-	{RSP_LAST,0,0,0,0,0,0}
-};
-#endif
-
 static const struct resp_type_t resp_type[] =
 {
 	/*{"",		RSP_EMPTY,	RT_NOTHING},*/
@@ -665,13 +634,8 @@
 					dev_err(cs->dev, "out of memory\n");
 				++curarg;
 			}
-#ifdef CONFIG_GIGASET_DEBUG
-			if (!event->ptr)
-				gig_dbg(DEBUG_CMD, "string==NULL");
-			else
-				gig_dbg(DEBUG_CMD, "string==%s",
-					(char *) event->ptr);
-#endif
+			gig_dbg(DEBUG_CMD, "string==%s",
+				event->ptr ? (char *) event->ptr : "NULL");
 			break;
 		case RT_ZCAU:
 			event->parameter = -1;
@@ -697,9 +661,7 @@
 				++curarg;
 			} else
 				event->parameter = -1;
-#ifdef CONFIG_GIGASET_DEBUG
 			gig_dbg(DEBUG_CMD, "parameter==%d", event->parameter);
-#endif
 			break;
 		}
 
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 0037529..747178f 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -16,6 +16,9 @@
 #ifndef GIGASET_H
 #define GIGASET_H
 
+/* define global prefix for pr_ macros in linux/kernel.h */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/compiler.h>
 #include <linux/types.h>
@@ -97,23 +100,6 @@
 					 activated */
 };
 
-/* Kernel message macros for situations where dev_printk and friends cannot be
- * used for lack of reliable access to a device structure.
- * linux/usb.h already contains these but in an obsolete form which clutters
- * the log needlessly, and according to the USB maintainer those should be
- * removed rather than fixed anyway.
- */
-#undef err
-#undef info
-#undef warn
-
-#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \
-	format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \
-	format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING KBUILD_MODNAME ": " \
-	format "\n" , ## arg)
-
 #ifdef CONFIG_GIGASET_DEBUG
 
 #define gig_dbg(level, format, arg...) \
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index 3c127a8..69a702f 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -42,7 +42,7 @@
 	unsigned skblen;
 
 	if (!(cs = gigaset_get_cs_by_id(driverID))) {
-		err("%s: invalid driver ID (%d)", __func__, driverID);
+		pr_err("%s: invalid driver ID (%d)\n", __func__, driverID);
 		return -ENODEV;
 	}
 	if (channel < 0 || channel >= cs->channels) {
@@ -119,7 +119,7 @@
 	gigaset_debugdrivers();
 
 	if (!cs) {
-		err("%s: invalid driver ID (%d)", __func__, cntrl->driver);
+		pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver);
 		return -ENODEV;
 	}
 
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index 521951a..311e7ca 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -107,7 +107,7 @@
 		return -EBUSY;
 
 	if (!cs->connected) {
-		err("not connected!");
+		pr_err("%s: not connected\n", __func__);
 		return -ENODEV;
 	}
 
@@ -143,9 +143,6 @@
 	.set_termios =		if_set_termios,
 	.throttle =		if_throttle,
 	.unthrottle =		if_unthrottle,
-#if 0
-	.break_ctl =		serial_break,
-#endif
 	.tiocmget =		if_tiocmget,
 	.tiocmset =		if_tiocmset,
 };
@@ -188,7 +185,7 @@
 
 	cs = (struct cardstate *) tty->driver_data;
 	if (!cs) {
-		err("cs==NULL in %s", __func__);
+		pr_err("%s: no cardstate\n", __func__);
 		return;
 	}
 
@@ -222,7 +219,7 @@
 
 	cs = (struct cardstate *) tty->driver_data;
 	if (!cs) {
-		err("cs==NULL in %s", __func__);
+		pr_err("%s: no cardstate\n", __func__);
 		return -ENODEV;
 	}
 
@@ -297,7 +294,7 @@
 
 	cs = (struct cardstate *) tty->driver_data;
 	if (!cs) {
-		err("cs==NULL in %s", __func__);
+		pr_err("%s: no cardstate\n", __func__);
 		return -ENODEV;
 	}
 
@@ -323,7 +320,7 @@
 
 	cs = (struct cardstate *) tty->driver_data;
 	if (!cs) {
-		err("cs==NULL in %s", __func__);
+		pr_err("%s: no cardstate\n", __func__);
 		return -ENODEV;
 	}
 
@@ -354,7 +351,7 @@
 
 	cs = (struct cardstate *) tty->driver_data;
 	if (!cs) {
-		err("cs==NULL in %s", __func__);
+		pr_err("%s: no cardstate\n", __func__);
 		return -ENODEV;
 	}
 
@@ -388,7 +385,7 @@
 
 	cs = (struct cardstate *) tty->driver_data;
 	if (!cs) {
-		err("cs==NULL in %s", __func__);
+		pr_err("%s: no cardstate\n", __func__);
 		return -ENODEV;
 	}
 
@@ -420,7 +417,7 @@
 
 	cs = (struct cardstate *) tty->driver_data;
 	if (!cs) {
-		err("cs==NULL in %s", __func__);
+		pr_err("%s: no cardstate\n", __func__);
 		return -ENODEV;
 	}
 
@@ -451,7 +448,7 @@
 
 	cs = (struct cardstate *) tty->driver_data;
 	if (!cs) {
-		err("cs==NULL in %s", __func__);
+		pr_err("%s: no cardstate\n", __func__);
 		return;
 	}
 
@@ -474,7 +471,7 @@
 
 	cs = (struct cardstate *) tty->driver_data;
 	if (!cs) {
-		err("cs==NULL in %s", __func__);
+		pr_err("%s: no cardstate\n", __func__);
 		return;
 	}
 
@@ -501,7 +498,7 @@
 
 	cs = (struct cardstate *) tty->driver_data;
 	if (!cs) {
-		err("cs==NULL in %s", __func__);
+		pr_err("%s: no cardstate\n", __func__);
 		return;
 	}
 
@@ -565,29 +562,6 @@
 
 	cs->ops->set_line_ctrl(cs, cflag);
 
-#if 0
-	//FIXME this hangs M101 [ts 2005-03-09]
-	//FIXME do we need this?
-	/*
-	 * Set flow control: well, I do not really now how to handle DTR/RTS.
-	 * Just do what we have seen with SniffUSB on Win98.
-	 */
-	/* Drop DTR/RTS if no flow control otherwise assert */
-	gig_dbg(DEBUG_IF, "%u: control_state %x",
-		cs->minor_index, control_state);
-	new_state = control_state;
-	if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
-		new_state |= TIOCM_DTR | TIOCM_RTS;
-	else
-		new_state &= ~(TIOCM_DTR | TIOCM_RTS);
-	if (new_state != control_state) {
-		gig_dbg(DEBUG_IF, "%u: new_state %x",
-			cs->minor_index, new_state);
-		gigaset_set_modem_ctrl(cs, control_state, new_state);
-		control_state = new_state;
-	}
-#endif
-
 	/* save off the modified port settings */
 	cs->control_state = control_state;
 
@@ -701,7 +675,7 @@
 
 	ret = tty_register_driver(tty);
 	if (ret < 0) {
-		warn("failed to register tty driver (error %d)", ret);
+		pr_err("error %d registering tty driver\n", ret);
 		goto error;
 	}
 	gig_dbg(DEBUG_IF, "tty driver initialized");
@@ -709,7 +683,7 @@
 	return;
 
 enomem:
-	warn("could not allocate tty structures");
+	pr_err("out of memory\n");
 error:
 	if (drv->tty)
 		put_tty_driver(drv->tty);
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index fbce522..b171e75 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -88,11 +88,9 @@
 			__func__);
 		return 0;
 	}
-#ifdef CONFIG_GIGASET_DEBUG
 	gig_dbg(DEBUG_ISO,
 		"%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
 		__func__, iwb->data[iwb->write], iwb->wbits);
-#endif
 	return 1;
 }
 
@@ -173,13 +171,13 @@
 		__func__, read, write, limit);
 #ifdef CONFIG_GIGASET_DEBUG
 	if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) {
-		err("invalid size %d", size);
+		pr_err("invalid size %d\n", size);
 		return -EINVAL;
 	}
 	src = iwb->read;
 	if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
 		     (read < src && limit >= src))) {
-		err("isoc write buffer frame reservation violated");
+		pr_err("isoc write buffer frame reservation violated\n");
 		return -EFAULT;
 	}
 #endif
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index 07052ed..ac245e7 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -16,7 +16,6 @@
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/tty.h>
-#include <linux/poll.h>
 #include <linux/completion.h>
 
 /* Version Information */
@@ -408,7 +407,7 @@
 	int rc;
 
 	if (!(cs->hw.ser = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL))) {
-		err("%s: out of memory!", __func__);
+		pr_err("out of memory\n");
 		return 0;
 	}
 
@@ -416,7 +415,7 @@
 	cs->hw.ser->dev.id = cs->minor_index;
 	cs->hw.ser->dev.dev.release = gigaset_device_release;
 	if ((rc = platform_device_register(&cs->hw.ser->dev)) != 0) {
-		err("error %d registering platform device", rc);
+		pr_err("error %d registering platform device\n", rc);
 		kfree(cs->hw.ser);
 		cs->hw.ser = NULL;
 		return 0;
@@ -514,11 +513,10 @@
 
 	gig_dbg(DEBUG_INIT, "Starting HLL for Gigaset M101");
 
-	info(DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	pr_info(DRIVER_DESC "\n");
 
 	if (!driver) {
-		err("%s: no driver structure", __func__);
+		pr_err("%s: no driver structure\n", __func__);
 		return -ENODEV;
 	}
 
@@ -571,11 +569,10 @@
 	}
 
 	/* prevent other callers from entering ldisc methods */
-	/* FIXME: should use the tty state flags */
 	tty->disc_data = NULL;
 
 	if (!cs->hw.ser)
-		err("%s: no hw cardstate", __func__);
+		pr_err("%s: no hw cardstate\n", __func__);
 	else {
 		/* wait for running methods to finish */
 		if (!atomic_dec_and_test(&cs->hw.ser->refcnt))
@@ -673,18 +670,6 @@
 }
 
 /*
- * Poll on the tty.
- * Unused, always return zero.
- *
- * FIXME: should probably return an exception - especially on hangup
- */
-static unsigned int
-gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
-{
-	return 0;
-}
-
-/*
  * Called by the tty driver when a block of data has been received.
  * Will not be re-entered while running but other ldisc functions
  * may be called in parallel.
@@ -773,7 +758,6 @@
 	.read		= gigaset_tty_read,
 	.write		= gigaset_tty_write,
 	.ioctl		= gigaset_tty_ioctl,
-	.poll		= gigaset_tty_poll,
 	.receive_buf	= gigaset_tty_receive,
 	.write_wakeup	= gigaset_tty_wakeup,
 };
@@ -788,7 +772,7 @@
 
 	gig_dbg(DEBUG_INIT, "%s", __func__);
 	if ((rc = platform_driver_register(&device_driver)) != 0) {
-		err("error %d registering platform driver", rc);
+		pr_err("error %d registering platform driver\n", rc);
 		return rc;
 	}
 
@@ -799,7 +783,7 @@
 		goto error;
 
 	if ((rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc)) != 0) {
-		err("error %d registering line discipline", rc);
+		pr_err("error %d registering line discipline\n", rc);
 		goto error;
 	}
 
@@ -826,7 +810,7 @@
 	}
 
 	if ((rc = tty_unregister_ldisc(N_GIGASET_M101)) != 0)
-		err("error %d unregistering line discipline", rc);
+		pr_err("error %d unregistering line discipline\n", rc);
 
 	platform_driver_unregister(&device_driver);
 }
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index 4661830..fba61f6 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -407,7 +407,7 @@
 	spin_lock_irqsave(&cs->lock, flags);
 	if (!cs->connected) {
 		spin_unlock_irqrestore(&cs->lock, flags);
-		err("%s: disconnected", __func__);
+		pr_err("%s: disconnected\n", __func__);
 		return;
 	}
 	r = usb_submit_urb(urb, GFP_ATOMIC);
@@ -440,7 +440,7 @@
 
 	spin_lock_irqsave(&cs->lock, flags);
 	if (!cs->connected) {
-		err("%s: not connected", __func__);
+		pr_err("%s: disconnected\n", __func__);
 	} else {
 		cs->hw.usb->busy = 0;
 		tasklet_schedule(&cs->write_tasklet);
@@ -612,8 +612,10 @@
 
 	cs->hw.usb = ucs =
 		kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL);
-	if (!ucs)
+	if (!ucs) {
+		pr_err("out of memory\n");
 		return 0;
+	}
 
 	ucs->bchars[0] = 0;
 	ucs->bchars[1] = 0;
@@ -936,13 +938,11 @@
 	/* register this driver with the USB subsystem */
 	result = usb_register(&gigaset_usb_driver);
 	if (result < 0) {
-		err("usb_gigaset: usb_register failed (error %d)",
-		    -result);
+		pr_err("error %d registering USB driver\n", -result);
 		goto error;
 	}
 
-	info(DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	pr_info(DRIVER_DESC "\n");
 	return 0;
 
 error:
diff --git a/drivers/isdn/hardware/eicon/di.c b/drivers/isdn/hardware/eicon/di.c
index 10760b3..b029d13 100644
--- a/drivers/isdn/hardware/eicon/di.c
+++ b/drivers/isdn/hardware/eicon/di.c
@@ -353,13 +353,13 @@
 /*------------------------------------------------------------------*/
 /* return code handler                                              */
 /*------------------------------------------------------------------*/
-byte isdn_rc(ADAPTER * a,
-             byte Rc,
-             byte Id,
-             byte Ch,
-             word Ref,
-             dword extended_info_type,
-             dword extended_info)
+static byte isdn_rc(ADAPTER *a,
+		    byte Rc,
+		    byte Id,
+		    byte Ch,
+		    word Ref,
+		    dword extended_info_type,
+		    dword extended_info)
 {
   ENTITY  * this;
   byte e_no;
@@ -555,13 +555,13 @@
 /*------------------------------------------------------------------*/
 /* indication handler                                               */
 /*------------------------------------------------------------------*/
-byte isdn_ind(ADAPTER * a,
-              byte Ind,
-              byte Id,
-              byte Ch,
-              PBUFFER * RBuffer,
-              byte MInd,
-              word MLength)
+static byte isdn_ind(ADAPTER *a,
+		     byte Ind,
+		     byte Id,
+		     byte Ch,
+		     PBUFFER *RBuffer,
+		     byte MInd,
+		     word MLength)
 {
   ENTITY  * this;
   word clength;
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
index 599fed8..4cc94f2 100644
--- a/drivers/isdn/hardware/eicon/message.c
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -592,7 +592,7 @@
 /* api_parse function, check the format of api messages             */
 /*------------------------------------------------------------------*/
 
-word api_parse(byte   * msg, word length, byte * format, API_PARSE * parms)
+static word api_parse(byte *msg, word length, byte *format, API_PARSE *parms)
 {
   word i;
   word p;
@@ -631,7 +631,7 @@
   return false;
 }
 
-void api_save_msg(API_PARSE   *in, byte *format, API_SAVE   *out)
+static void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out)
 {
   word i, j, n = 0;
   byte   *p;
@@ -663,7 +663,7 @@
   out->parms[i].length = 0;
 }
 
-void api_load_msg(API_SAVE   *in, API_PARSE   *out)
+static void api_load_msg(API_SAVE *in, API_PARSE *out)
 {
   word i;
 
@@ -3414,7 +3414,8 @@
   return false;
 }
 
-byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+			     PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word command;
   word i;
@@ -3742,7 +3743,8 @@
 }
 
 
-byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+static byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+			     PLCI *plci, APPL *appl, API_PARSE *msg)
 {
   word indication;
 
@@ -4074,7 +4076,8 @@
 }
 
 
-void control_rc(PLCI   * plci, byte req, byte rc, byte ch, byte global_req, byte nl_rc)
+static void control_rc(PLCI *plci, byte req, byte rc, byte ch, byte global_req,
+		       byte nl_rc)
 {
   dword Id;
   dword rId;
@@ -4740,7 +4743,7 @@
   }
 }
 
-void data_rc(PLCI   * plci, byte ch)
+static void data_rc(PLCI *plci, byte ch)
 {
   dword Id;
   DIVA_CAPI_ADAPTER   * a;
@@ -4776,7 +4779,7 @@
   }
 }
 
-void data_ack(PLCI   * plci, byte ch)
+static void data_ack(PLCI *plci, byte ch)
 {
   dword Id;
   DIVA_CAPI_ADAPTER   * a;
@@ -4802,7 +4805,7 @@
   }
 }
 
-void sig_ind(PLCI   * plci)
+static void sig_ind(PLCI *plci)
 {
   dword x_Id;
   dword Id;
@@ -6170,7 +6173,7 @@
 }
 
 
-void SendInfo(PLCI   * plci, dword Id, byte   * * parms, byte iesent)
+static void SendInfo(PLCI *plci, dword Id, byte **parms, byte iesent)
 {
   word i;
   word j;
@@ -6346,7 +6349,8 @@
 }
 
 
-byte SendMultiIE(PLCI   * plci, dword Id, byte   * * parms, byte ie_type, dword info_mask, byte setupParse)
+static byte SendMultiIE(PLCI *plci, dword Id, byte **parms, byte ie_type,
+			dword info_mask, byte setupParse)
 {
   word i;
   word j;
@@ -6465,7 +6469,7 @@
     }
 };
 
-void nl_ind(PLCI   * plci)
+static void nl_ind(PLCI *plci)
 {
   byte ch;
   word ncci;
@@ -7247,7 +7251,7 @@
 /* find a free PLCI                                                 */
 /*------------------------------------------------------------------*/
 
-word get_plci(DIVA_CAPI_ADAPTER   * a)
+static word get_plci(DIVA_CAPI_ADAPTER *a)
 {
   word i,j;
   PLCI   * plci;
@@ -7406,7 +7410,7 @@
 /* put a unstructured data into the buffer                          */
 /*------------------------------------------------------------------*/
 
-void add_d(PLCI   * plci, word length, byte   * p)
+static void add_d(PLCI *plci, word length, byte *p)
 {
   word i;
 
@@ -7424,7 +7428,7 @@
 /* parameter buffer                                                 */
 /*------------------------------------------------------------------*/
 
-void add_ai(PLCI   * plci, API_PARSE * ai)
+static void add_ai(PLCI *plci, API_PARSE *ai)
 {
   word i;
     API_PARSE ai_parms[5];
@@ -7445,7 +7449,8 @@
 /* put parameter for b1 protocol in the parameter buffer            */
 /*------------------------------------------------------------------*/
 
-word add_b1(PLCI   * plci, API_PARSE * bp, word b_channel_info, word b1_facilities)
+static word add_b1(PLCI *plci, API_PARSE *bp, word b_channel_info,
+		   word b1_facilities)
 {
     API_PARSE bp_parms[8];
     API_PARSE mdm_cfg[9];
@@ -7909,7 +7914,7 @@
 /* put parameter for b2 and B3  protocol in the parameter buffer    */
 /*------------------------------------------------------------------*/
 
-word add_b23(PLCI   * plci, API_PARSE * bp)
+static word add_b23(PLCI *plci, API_PARSE *bp)
 {
   word i, fax_control_bits;
   byte pos, len;
@@ -8706,7 +8711,7 @@
 /* send a request for the network layer entity                      */
 /*------------------------------------------------------------------*/
 
-void nl_req_ncci(PLCI   * plci, byte req, byte ncci)
+static void nl_req_ncci(PLCI *plci, byte req, byte ncci)
 {
   if(!plci) return;
   if(plci->adapter->adapter_disabled) return;
@@ -8728,7 +8733,7 @@
   plci->req_in_start = plci->req_in;
 }
 
-void send_req(PLCI   * plci)
+static void send_req(PLCI *plci)
 {
   ENTITY   * e;
   word l;
@@ -8863,7 +8868,7 @@
   }
 }
 
-void listen_check(DIVA_CAPI_ADAPTER   * a)
+static void listen_check(DIVA_CAPI_ADAPTER *a)
 {
   word i,j;
   PLCI   * plci;
@@ -8906,7 +8911,7 @@
 /* functions for all parameters sent in INDs                        */
 /*------------------------------------------------------------------*/
 
-void IndParse(PLCI   * plci, word * parms_id, byte   ** parms, byte multiIEsize)
+static void IndParse(PLCI *plci, word *parms_id, byte **parms, byte multiIEsize)
 {
   word ploc;            /* points to current location within packet */
   byte w;
@@ -8991,7 +8996,7 @@
 /* try to match a cip from received BC and HLC                      */
 /*------------------------------------------------------------------*/
 
-byte ie_compare(byte   * ie1, byte * ie2)
+static byte ie_compare(byte *ie1, byte *ie2)
 {
   word i;
   if(!ie1 || ! ie2) return false;
@@ -9000,7 +9005,7 @@
   return true;
 }
 
-word find_cip(DIVA_CAPI_ADAPTER   * a, byte   * bc, byte   * hlc)
+static word find_cip(DIVA_CAPI_ADAPTER *a, byte *bc, byte *hlc)
 {
   word i;
   word j;
@@ -9068,7 +9073,7 @@
 /* voice and codec features                                         */
 /*------------------------------------------------------------------*/
 
-void SetVoiceChannel(PLCI   *plci, byte   *chi, DIVA_CAPI_ADAPTER   * a)
+static void SetVoiceChannel(PLCI *plci, byte *chi, DIVA_CAPI_ADAPTER *a)
 {
   byte voice_chi[] = "\x02\x18\x01";
   byte channel;
@@ -9086,7 +9091,7 @@
   }
 }
 
-void VoiceChannelOff(PLCI   *plci)
+static void VoiceChannelOff(PLCI *plci)
 {
   dbug(1,dprintf("ExtDevOFF"));
   add_p(plci,FTY,"\x02\x01\x08");             /* B Off */
@@ -9099,7 +9104,8 @@
 }
 
 
-word AdvCodecSupport(DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, byte hook_listen)
+static word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl,
+			    byte hook_listen)
 {
   word j;
   PLCI   *splci;
@@ -9195,7 +9201,7 @@
 }
 
 
-void CodecIdCheck(DIVA_CAPI_ADAPTER   *a, PLCI   *plci)
+static void CodecIdCheck(DIVA_CAPI_ADAPTER *a, PLCI *plci)
 {
 
   dbug(1,dprintf("CodecIdCheck"));
diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h
index a33d87a..7bbf730 100644
--- a/drivers/isdn/hardware/mISDN/hfc_multi.h
+++ b/drivers/isdn/hardware/mISDN/hfc_multi.h
@@ -162,8 +162,8 @@
 	void		(*write_fifo)(struct hfc_multi *hc, u_char *data,
 				int len);
 	u_long		pci_origmembase, plx_origmembase, dsp_origmembase;
-	u_char		*pci_membase; /* PCI memory (MUST BE BYTE POINTER) */
-	u_char		*plx_membase; /* PLX memory */
+	void __iomem	*pci_membase; /* PCI memory */
+	void __iomem	*plx_membase; /* PLX memory */
 	u_char		*dsp_membase; /* DSP on PLX */
 	u_long		pci_iobase; /* PCI IO */
 	struct hfcm_hw	hw;	/* remember data of write-only-registers */
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 1eac03f..c63e2f4 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -171,9 +171,8 @@
 static int interrupt_registered;
 
 static struct hfc_multi *syncmaster;
-int plxsd_master; /* if we have a master card (yet) */
+static int plxsd_master; /* if we have a master card (yet) */
 static spinlock_t plx_lock; /* may not acquire other lock inside */
-EXPORT_SYMBOL(plx_lock);
 
 #define	TYP_E1		1
 #define	TYP_4S		4
@@ -422,7 +421,7 @@
 #endif
 
 /* write fifo data (REGIO) */
-void
+static void
 write_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
 {
 	outb(A_FIFO_DATA0, (hc->pci_iobase)+4);
@@ -443,7 +442,7 @@
 	}
 }
 /* write fifo data (PCIMEM) */
-void
+static void
 write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len)
 {
 	while (len>>2) {
@@ -465,7 +464,7 @@
 	}
 }
 /* read fifo data (REGIO) */
-void
+static void
 read_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
 {
 	outb(A_FIFO_DATA0, (hc->pci_iobase)+4);
@@ -487,7 +486,7 @@
 }
 
 /* read fifo data (PCIMEM) */
-void
+static void
 read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len)
 {
 	while (len>>2) {
@@ -706,7 +705,7 @@
 }
 
 
-void
+static void
 vpm_init(struct hfc_multi *wc)
 {
 	unsigned char reg;
@@ -789,7 +788,8 @@
 	}
 }
 
-void
+#ifdef UNUSED
+static void
 vpm_check(struct hfc_multi *hctmp)
 {
 	unsigned char gpi2;
@@ -799,6 +799,7 @@
 	if ((gpi2 & 0x3) != 0x3)
 		printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2);
 }
+#endif /* UNUSED */
 
 
 /*
@@ -812,7 +813,7 @@
  *
  */
 
-void
+static void
 vpm_echocan_on(struct hfc_multi *hc, int ch, int taps)
 {
 	unsigned int timeslot;
@@ -844,7 +845,7 @@
 	vpm_out(hc, unit, timeslot, 0x7e);
 }
 
-void
+static void
 vpm_echocan_off(struct hfc_multi *hc, int ch)
 {
 	unsigned int timeslot;
@@ -887,8 +888,9 @@
 static inline void
 hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm)
 {
-	struct hfc_multi *hc, *next, *pcmmaster = 0;
-	u_int *plx_acc_32, pv;
+	struct hfc_multi *hc, *next, *pcmmaster = NULL;
+	void __iomem *plx_acc_32;
+	u_int pv;
 	u_long flags;
 
 	spin_lock_irqsave(&HFClock, flags);
@@ -916,7 +918,7 @@
 	/* Disable sync of all cards */
 	list_for_each_entry_safe(hc, next, &HFClist, list) {
 		if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
-			plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+			plx_acc_32 = hc->plx_membase + PLX_GPIOC;
 			pv = readl(plx_acc_32);
 			pv &= ~PLX_SYNC_O_EN;
 			writel(pv, plx_acc_32);
@@ -938,7 +940,7 @@
 			printk(KERN_DEBUG "id=%d (0x%p) = syncronized with "
 				"interface.\n", hc->id, hc);
 		/* Enable new sync master */
-		plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+		plx_acc_32 = hc->plx_membase + PLX_GPIOC;
 		pv = readl(plx_acc_32);
 		pv |= PLX_SYNC_O_EN;
 		writel(pv, plx_acc_32);
@@ -968,7 +970,7 @@
 					    "QUARTZ is automatically "
 					    "enabled by HFC-%dS\n", hc->type);
 			}
-			plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+			plx_acc_32 = hc->plx_membase + PLX_GPIOC;
 			pv = readl(plx_acc_32);
 			pv |= PLX_SYNC_O_EN;
 			writel(pv, plx_acc_32);
@@ -1013,7 +1015,8 @@
 static void
 release_io_hfcmulti(struct hfc_multi *hc)
 {
-	u_int	*plx_acc_32, pv;
+	void __iomem *plx_acc_32;
+	u_int	pv;
 	u_long	plx_flags;
 
 	if (debug & DEBUG_HFCMULTI_INIT)
@@ -1033,7 +1036,7 @@
 			printk(KERN_DEBUG "%s: release PLXSD card %d\n",
 			    __func__, hc->id + 1);
 		spin_lock_irqsave(&plx_lock, plx_flags);
-		plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+		plx_acc_32 = hc->plx_membase + PLX_GPIOC;
 		writel(PLX_GPIOC_INIT, plx_acc_32);
 		pv = readl(plx_acc_32);
 		/* Termination off */
@@ -1055,9 +1058,9 @@
 	test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */
 	pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0);
 	if (hc->pci_membase)
-		iounmap((void *)hc->pci_membase);
+		iounmap(hc->pci_membase);
 	if (hc->plx_membase)
-		iounmap((void *)hc->plx_membase);
+		iounmap(hc->plx_membase);
 	if (hc->pci_iobase)
 		release_region(hc->pci_iobase, 8);
 
@@ -1080,7 +1083,8 @@
 	u_long			flags, val, val2 = 0, rev;
 	int			i, err = 0;
 	u_char			r_conf_en, rval;
-	u_int			*plx_acc_32, pv;
+	void __iomem		*plx_acc_32;
+	u_int			pv;
 	u_long			plx_flags, hfc_flags;
 	int			plx_count;
 	struct hfc_multi	*pos, *next, *plx_last_hc;
@@ -1154,7 +1158,7 @@
 			printk(KERN_DEBUG "%s: initializing PLXSD card %d\n",
 			    __func__, hc->id + 1);
 		spin_lock_irqsave(&plx_lock, plx_flags);
-		plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+		plx_acc_32 = hc->plx_membase + PLX_GPIOC;
 		writel(PLX_GPIOC_INIT, plx_acc_32);
 		pv = readl(plx_acc_32);
 		/* The first and the last cards are terminating the PCM bus */
@@ -1190,8 +1194,7 @@
 					"we disable termination\n",
 				    __func__, plx_last_hc->id + 1);
 			spin_lock_irqsave(&plx_lock, plx_flags);
-			plx_acc_32 = (u_int *)(plx_last_hc->plx_membase
-					+ PLX_GPIOC);
+			plx_acc_32 = plx_last_hc->plx_membase + PLX_GPIOC;
 			pv = readl(plx_acc_32);
 			pv &= ~PLX_TERM_ON;
 			writel(pv, plx_acc_32);
@@ -1240,7 +1243,7 @@
 	/* Speech Design PLX bridge pcm and sync mode */
 	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
 		spin_lock_irqsave(&plx_lock, plx_flags);
-		plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+		plx_acc_32 = hc->plx_membase + PLX_GPIOC;
 		pv = readl(plx_acc_32);
 		/* Connect PCM */
 		if (hc->hw.r_pcm_md0 & V_PCM_MD) {
@@ -1352,8 +1355,7 @@
 			/* retry with master clock */
 			if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
 				spin_lock_irqsave(&plx_lock, plx_flags);
-				plx_acc_32 = (u_int *)(hc->plx_membase +
-					PLX_GPIOC);
+				plx_acc_32 = hc->plx_membase + PLX_GPIOC;
 				pv = readl(plx_acc_32);
 				pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N;
 				pv |= PLX_SYNC_O_EN;
@@ -1389,7 +1391,7 @@
 		if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip))
 			plxsd_master = 1;
 		spin_lock_irqsave(&plx_lock, plx_flags);
-		plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+		plx_acc_32 = hc->plx_membase + PLX_GPIOC;
 		pv = readl(plx_acc_32);
 		pv |=  PLX_DSP_RES_N;
 		writel(pv, plx_acc_32);
@@ -2586,7 +2588,8 @@
 	struct dchannel		*dch;
 	u_char			r_irq_statech, status, r_irq_misc, r_irq_oview;
 	int			i;
-	u_short			*plx_acc, wval;
+	void __iomem		*plx_acc;
+	u_short			wval;
 	u_char			e1_syncsta, temp;
 	u_long			flags;
 
@@ -2606,7 +2609,7 @@
 
 	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
 		spin_lock_irqsave(&plx_lock, flags);
-		plx_acc = (u_short *)(hc->plx_membase + PLX_INTCSR);
+		plx_acc = hc->plx_membase + PLX_INTCSR;
 		wval = readw(plx_acc);
 		spin_unlock_irqrestore(&plx_lock, flags);
 		if (!(wval & PLX_INTCSR_LINTI1_STATUS))
@@ -4091,7 +4094,7 @@
 {
 	int	err = -EIO;
 	u_long	flags;
-	u_short	*plx_acc;
+	void	__iomem *plx_acc;
 	u_long	plx_flags;
 
 	if (debug & DEBUG_HFCMULTI_INIT)
@@ -4113,7 +4116,7 @@
 
 	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
 		spin_lock_irqsave(&plx_lock, plx_flags);
-		plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR);
+		plx_acc = hc->plx_membase + PLX_INTCSR;
 		writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE),
 			plx_acc); /* enable PCI & LINT1 irq */
 		spin_unlock_irqrestore(&plx_lock, plx_flags);
@@ -4162,7 +4165,7 @@
 error:
 	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
 		spin_lock_irqsave(&plx_lock, plx_flags);
-		plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR);
+		plx_acc = hc->plx_membase + PLX_INTCSR;
 		writew(0x00, plx_acc); /*disable IRQs*/
 		spin_unlock_irqrestore(&plx_lock, plx_flags);
 	}
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
index 3f2a0a2..7ee5bd9 100644
--- a/drivers/isdn/hysdn/hysdn_net.c
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -76,7 +76,7 @@
 net_open(struct net_device *dev)
 {
 	struct in_device *in_dev;
-	hysdn_card *card = dev->priv;
+	hysdn_card *card = dev->ml_priv;
 	int i;
 
 	netif_start_queue(dev);	/* start tx-queueing */
@@ -159,7 +159,7 @@
 	spin_unlock_irq(&lp->lock);
 
 	if (lp->sk_count <= 3) {
-		schedule_work(&((hysdn_card *) dev->priv)->irq_queue);
+		schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue);
 	}
 	return (0);		/* success */
 }				/* net_send_packet */
@@ -295,7 +295,7 @@
 		kfree(dev);
 		return (i);
 	}
-	dev->priv = card;	/* remember pointer to own data structure */
+	dev->ml_priv = card;	/* remember pointer to own data structure */
 	card->netif = dev;	/* setup the local pointer */
 
 	if (card->debug_flags & LOG_NET_INIT)
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 484299b..8f9f491 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -246,7 +246,8 @@
 	}
 	if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
 		hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x",
-			     filep->f_uid, filep->f_gid, filep->f_mode);
+			     filep->f_cred->fsuid, filep->f_cred->fsgid,
+			     filep->f_mode);
 
 	if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
 		/* write only access -> write boot file or conf line */
@@ -331,7 +332,8 @@
 	}
 	if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
 		hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x",
-			     filep->f_uid, filep->f_gid, filep->f_mode);
+			     filep->f_cred->fsuid, filep->f_cred->fsgid,
+			     filep->f_mode);
 
 	if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
 		/* write only access -> write boot file or conf line */
diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c
index 0193b6f..46048e5 100644
--- a/drivers/isdn/i4l/isdn_concap.c
+++ b/drivers/isdn/i4l/isdn_concap.c
@@ -42,7 +42,7 @@
 static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
 {
 	struct net_device *ndev = concap -> net_dev;
-	isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev;
+	isdn_net_dev *nd = ((isdn_net_local *) netdev_priv(ndev))->netdev;
 	isdn_net_local *lp = isdn_net_get_locked_lp(nd);
 
 	IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
@@ -61,7 +61,7 @@
 static int isdn_concap_dl_connect_req(struct concap_proto *concap)
 {
 	struct net_device *ndev = concap -> net_dev;
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
 	int ret;
 	IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name);
 
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 1bfc55d..023ea11 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -120,7 +120,7 @@
 		return 0;
 
 	if (lp->master)
-		nd = ((isdn_net_local *) lp->master->priv)->netdev;
+		nd = ISDN_MASTER_PRIV(lp)->netdev;
 	else
 		nd = lp->netdev;
 	
@@ -213,9 +213,9 @@
 {
 #ifdef CONFIG_ISDN_X25
 	struct concap_device_ops * dops =
-		( (isdn_net_local *) dev->priv ) -> dops;
+		((isdn_net_local *) netdev_priv(dev))->dops;
 	struct concap_proto * cprot =
-		( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
+		((isdn_net_local *) netdev_priv(dev))->netdev->cprot;
 #endif
 #ifdef CONFIG_ISDN_X25
 	if( cprot && cprot -> pops && dops )
@@ -250,11 +250,11 @@
 	}
 
 	/* If this interface has slaves, start them also */
-
-	if ((p = (((isdn_net_local *) dev->priv)->slave))) {
+	p = MASTER_TO_SLAVE(dev);
+	if (p) {
 		while (p) {
 			isdn_net_reset(p);
-			p = (((isdn_net_local *) p->priv)->slave);
+			p = MASTER_TO_SLAVE(p);
 		}
 	}
 	isdn_lock_drivers();
@@ -483,7 +483,7 @@
 							isdn_net_ciscohdlck_connected(lp);
 						if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
 							if (lp->master) { /* is lp a slave? */
-								isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev;
+								isdn_net_dev *nd = ISDN_MASTER_PRIV(lp)->netdev;
 								isdn_net_add_to_bundle(nd, lp);
 							}
 						}
@@ -823,7 +823,7 @@
 void
 isdn_net_hangup(struct net_device *d)
 {
-	isdn_net_local *lp = (isdn_net_local *) d->priv;
+	isdn_net_local *lp = (isdn_net_local *) netdev_priv(d);
 	isdn_ctrl cmd;
 #ifdef CONFIG_ISDN_X25
 	struct concap_proto *cprot = lp->netdev->cprot;
@@ -832,7 +832,7 @@
 
 	if (lp->flags & ISDN_NET_CONNECTED) {
 		if (lp->slave != NULL) {
-			isdn_net_local *slp = (isdn_net_local *)lp->slave->priv;
+			isdn_net_local *slp = ISDN_SLAVE_PRIV(lp);
 			if (slp->flags & ISDN_NET_CONNECTED) {
 				printk(KERN_INFO
 					"isdn_net: hang up slave %s before %s\n",
@@ -865,8 +865,8 @@
 }
 
 typedef struct {
-	unsigned short source;
-	unsigned short dest;
+	__be16 source;
+	__be16 dest;
 } ip_ports;
 
 static void
@@ -890,15 +890,15 @@
 		proto = ETH_P_IP;
 		switch (lp->p_encap) {
 			case ISDN_NET_ENCAP_IPTYP:
-				proto = ntohs(*(unsigned short *) &buf[0]);
+				proto = ntohs(*(__be16 *)&buf[0]);
 				p = &buf[2];
 				break;
 			case ISDN_NET_ENCAP_ETHER:
-				proto = ntohs(*(unsigned short *) &buf[12]);
+				proto = ntohs(*(__be16 *)&buf[12]);
 				p = &buf[14];
 				break;
 			case ISDN_NET_ENCAP_CISCOHDLC:
-				proto = ntohs(*(unsigned short *) &buf[2]);
+				proto = ntohs(*(__be16 *)&buf[2]);
 				p = &buf[4];
 				break;
 #ifdef CONFIG_ISDN_PPP
@@ -942,18 +942,12 @@
 					strcpy(addinfo, " IDP");
 					break;
 			}
-			printk(KERN_INFO
-				"OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
-
-			       p[12], p[13], p[14], p[15],
-			       p[16], p[17], p[18], p[19],
-			       addinfo);
+			printk(KERN_INFO "OPEN: %pI4 -> %pI4%s\n",
+			       p + 12, p + 16, addinfo);
 			break;
 		case ETH_P_ARP:
-			printk(KERN_INFO
-				"OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
-			       p[14], p[15], p[16], p[17],
-			       p[24], p[25], p[26], p[27]);
+			printk(KERN_INFO "OPEN: ARP %pI4 -> *.*.*.* ?%pI4\n",
+			       p + 14, p + 24);
 			break;
 	}
 }
@@ -1054,10 +1048,10 @@
 {
 	isdn_net_dev *nd;
 	isdn_net_local *slp;
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
 	int retv = 0;
 
-	if (((isdn_net_local *) (ndev->priv))->master) {
+	if (((isdn_net_local *) netdev_priv(ndev))->master) {
 		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
 		dev_kfree_skb(skb);
 		return 0;
@@ -1069,7 +1063,7 @@
 		return isdn_ppp_xmit(skb, ndev);
 	}
 #endif
-	nd = ((isdn_net_local *) ndev->priv)->netdev;
+	nd = ((isdn_net_local *) netdev_priv(ndev))->netdev;
 	lp = isdn_net_get_locked_lp(nd);
 	if (!lp) {
 		printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
@@ -1096,9 +1090,9 @@
 			} else {
 				/* subsequent overload: if slavedelay exceeded, start dialing */
 				if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) {
-					slp = lp->slave->priv;
+					slp = ISDN_SLAVE_PRIV(lp);
 					if (!(slp->flags & ISDN_NET_CONNECTED)) {
-						isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
+						isdn_net_force_dial_lp(ISDN_SLAVE_PRIV(lp));
 					}
 				}
 			}
@@ -1118,7 +1112,7 @@
 static void
 isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
 {
-	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
 	if (!skb)
 		return;
 	if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
@@ -1133,7 +1127,7 @@
 
 static void isdn_net_tx_timeout(struct net_device * ndev)
 {
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
 
 	printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
 	if (!lp->dialstate){
@@ -1167,7 +1161,7 @@
 static int
 isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
 #ifdef CONFIG_ISDN_X25
 	struct concap_proto * cprot = lp -> netdev -> cprot;
 /* At this point hard_start_xmit() passes control to the encapsulation
@@ -1316,7 +1310,7 @@
 	struct net_device *p;
 #ifdef CONFIG_ISDN_X25
 	struct concap_proto * cprot =
-		( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
+		((isdn_net_local *) netdev_priv(dev))->netdev->cprot;
 	/* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */
 #endif
 
@@ -1324,17 +1318,18 @@
 	if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
 #endif
 	netif_stop_queue(dev);
-	if ((p = (((isdn_net_local *) dev->priv)->slave))) {
+	p = MASTER_TO_SLAVE(dev);
+	if (p) {
 		/* If this interface has slaves, stop them also */
 		while (p) {
 #ifdef CONFIG_ISDN_X25
-			cprot = ( (isdn_net_local *) p->priv )
+			cprot = ((isdn_net_local *) netdev_priv(p))
 				-> netdev -> cprot;
 			if( cprot && cprot -> pops )
 				cprot -> pops -> close( cprot );
 #endif
 			isdn_net_hangup(p);
-			p = (((isdn_net_local *) p->priv)->slave);
+			p = MASTER_TO_SLAVE(p);
 		}
 	}
 	isdn_net_hangup(dev);
@@ -1348,7 +1343,7 @@
 static struct net_device_stats *
 isdn_net_get_stats(struct net_device *dev)
 {
-	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
 	return &lp->stats;
 }
 
@@ -1361,7 +1356,7 @@
  *      This is normal practice and works for any 'now in use' protocol.
  */
 
-static unsigned short
+static __be16
 isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ethhdr *eth;
@@ -1427,7 +1422,7 @@
 static int
 isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
 	unsigned long len = 0;
 	unsigned long expires = 0;
 	int tmp = 0;
@@ -1539,15 +1534,16 @@
 	p = skb_put(skb, 4 + 14);
 
 	/* cisco header */
-	p += put_u8 (p, CISCO_ADDR_UNICAST);
-	p += put_u8 (p, CISCO_CTRL);
-	p += put_u16(p, CISCO_TYPE_SLARP);
+	*(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
+	*(u8 *)(p + 1) = CISCO_CTRL;
+	*(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
 
 	/* slarp keepalive */
-	p += put_u32(p, CISCO_SLARP_KEEPALIVE);
-	p += put_u32(p, lp->cisco_myseq);
-	p += put_u32(p, lp->cisco_yourseq);
-	p += put_u16(p, 0xffff); // reliablity, always 0xffff
+	*(__be32 *)(p +  4) = cpu_to_be32(CISCO_SLARP_KEEPALIVE);
+	*(__be32 *)(p +  8) = cpu_to_be32(lp->cisco_myseq);
+	*(__be32 *)(p + 12) = cpu_to_be32(lp->cisco_yourseq);
+	*(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliablity, always 0xffff
+	p += 18;
 
 	isdn_net_write_super(lp, skb);
 
@@ -1569,15 +1565,16 @@
 	p = skb_put(skb, 4 + 14);
 
 	/* cisco header */
-	p += put_u8 (p, CISCO_ADDR_UNICAST);
-	p += put_u8 (p, CISCO_CTRL);
-	p += put_u16(p, CISCO_TYPE_SLARP);
+	*(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
+	*(u8 *)(p + 1) = CISCO_CTRL;
+	*(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
 
 	/* slarp request */
-	p += put_u32(p, CISCO_SLARP_REQUEST);
-	p += put_u32(p, 0); // address
-	p += put_u32(p, 0); // netmask
-	p += put_u16(p, 0); // unused
+	*(__be32 *)(p +  4) = cpu_to_be32(CISCO_SLARP_REQUEST);
+	*(__be32 *)(p +  8) = cpu_to_be32(0); // address
+	*(__be32 *)(p + 12) = cpu_to_be32(0); // netmask
+	*(__be16 *)(p + 16) = cpu_to_be16(0); // unused
+	p += 18;
 
 	isdn_net_write_super(lp, skb);
 }
@@ -1634,18 +1631,17 @@
 	p = skb_put(skb, 4 + 14);
 
 	/* cisco header */
-	p += put_u8 (p, CISCO_ADDR_UNICAST);
-	p += put_u8 (p, CISCO_CTRL);
-	p += put_u16(p, CISCO_TYPE_SLARP);
+	*(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
+	*(u8 *)(p + 1) = CISCO_CTRL;
+	*(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
 
 	/* slarp reply, send own ip/netmask; if values are nonsense remote
 	 * should think we are unable to provide it with an address via SLARP */
-	p += put_u32(p, CISCO_SLARP_REPLY);
-	*(__be32 *)p = addr;	// address
-	p += 4;
-	*(__be32 *)p = mask;	// netmask
-	p += 4;
-	p += put_u16(p, 0);	// unused
+	*(__be32 *)(p +  4) = cpu_to_be32(CISCO_SLARP_REPLY);
+	*(__be32 *)(p +  8) = addr; // address
+	*(__be32 *)(p + 12) = mask; // netmask
+	*(__be16 *)(p + 16) = cpu_to_be16(0); // unused
+	p += 18;
 
 	isdn_net_write_super(lp, skb);
 }
@@ -1656,44 +1652,39 @@
 	unsigned char *p;
 	int period;
 	u32 code;
-	u32 my_seq, addr;
-	u32 your_seq, mask;
-	u32 local;
+	u32 my_seq;
+	u32 your_seq;
+	__be32 local;
+	__be32 *addr, *mask;
 	u16 unused;
 
 	if (skb->len < 14)
 		return;
 
 	p = skb->data;
-	p += get_u32(p, &code);
-	
+	code = be32_to_cpup((__be32 *)p);
+	p += 4;
+
 	switch (code) {
 	case CISCO_SLARP_REQUEST:
 		lp->cisco_yourseq = 0;
 		isdn_net_ciscohdlck_slarp_send_reply(lp);
 		break;
 	case CISCO_SLARP_REPLY:
-		addr = ntohl(*(u32 *)p);
-		mask = ntohl(*(u32 *)(p+4));
-		if (mask != 0xfffffffc)
+		addr = (__be32 *)p;
+		mask = (__be32 *)(p + 4);
+		if (*mask != cpu_to_be32(0xfffffffc))
 			goto slarp_reply_out;
-		if ((addr & 3) == 0 || (addr & 3) == 3)
+		if ((*addr & cpu_to_be32(3)) == cpu_to_be32(0) ||
+		    (*addr & cpu_to_be32(3)) == cpu_to_be32(3))
 			goto slarp_reply_out;
-		local = addr ^ 3;
-		printk(KERN_INFO "%s: got slarp reply: "
-			"remote ip: %d.%d.%d.%d, "
-			"local ip: %d.%d.%d.%d "
-			"mask: %d.%d.%d.%d\n",
-		       lp->netdev->dev->name,
-		       HIPQUAD(addr),
-		       HIPQUAD(local),
-		       HIPQUAD(mask));
+		local = *addr ^ cpu_to_be32(3);
+		printk(KERN_INFO "%s: got slarp reply: remote ip: %pI4, local ip: %pI4 mask: %pI4\n",
+		       lp->netdev->dev->name, addr, &local, mask);
 		break;
   slarp_reply_out:
-		 printk(KERN_INFO "%s: got invalid slarp "
-				 "reply (%d.%d.%d.%d/%d.%d.%d.%d) "
-				 "- ignored\n", lp->netdev->dev->name,
-				 HIPQUAD(addr), HIPQUAD(mask));
+		printk(KERN_INFO "%s: got invalid slarp reply (%pI4/%pI4) - ignored\n",
+		       lp->netdev->dev->name, addr, mask);
 		break;
 	case CISCO_SLARP_KEEPALIVE:
 		period = (int)((jiffies - lp->cisco_last_slarp_in
@@ -1707,9 +1698,10 @@
 				lp->cisco_keepalive_period);
 		}
 		lp->cisco_last_slarp_in = jiffies;
-		p += get_u32(p, &my_seq);
-		p += get_u32(p, &your_seq);
-		p += get_u16(p, &unused);
+		my_seq = be32_to_cpup((__be32 *)(p + 0));
+		your_seq = be32_to_cpup((__be32 *)(p + 4));
+		unused = be16_to_cpup((__be16 *)(p + 8));
+		p += 10;
 		lp->cisco_yourseq = my_seq;
 		lp->cisco_mineseen = your_seq;
 		break;
@@ -1728,9 +1720,10 @@
 		goto out_free;
 
 	p = skb->data;
-	p += get_u8 (p, &addr);
-	p += get_u8 (p, &ctrl);
-	p += get_u16(p, &type);
+	addr = *(u8 *)(p + 0);
+	ctrl = *(u8 *)(p + 1);
+	type = be16_to_cpup((__be16 *)(p + 2));
+	p += 4;
 	skb_pull(skb, 4);
 	
 	if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) {
@@ -1771,7 +1764,7 @@
 static void
 isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
 {
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
 	isdn_net_local *olp = lp;	/* original 'lp' */
 #ifdef CONFIG_ISDN_X25
 	struct concap_proto *cprot = lp -> netdev -> cprot;
@@ -1785,7 +1778,7 @@
 		 * handle master's statistics and hangup-timeout
 		 */
 		ndev = lp->master;
-		lp = (isdn_net_local *) ndev->priv;
+		lp = (isdn_net_local *) netdev_priv(ndev);
 		lp->stats.rx_packets++;
 		lp->stats.rx_bytes += skb->len;
 	}
@@ -1825,7 +1818,7 @@
 			/* IP with type field */
 			olp->huptimer = 0;
 			lp->huptimer = 0;
-			skb->protocol = *(unsigned short *) &(skb->data[0]);
+			skb->protocol = *(__be16 *)&(skb->data[0]);
 			skb_pull(skb, 2);
 			if (*(unsigned short *) skb->data == 0xFFFF)
 				skb->protocol = htons(ETH_P_802_3);
@@ -1886,7 +1879,7 @@
 			   unsigned short type,
 			   const void *daddr, const void *saddr, unsigned plen)
 {
-	isdn_net_local *lp = dev->priv;
+	isdn_net_local *lp = netdev_priv(dev);
 	unsigned char *p;
 	ushort len = 0;
 
@@ -1907,20 +1900,21 @@
 			break;
 		case ISDN_NET_ENCAP_IPTYP:
 			/* ethernet type field */
-			*((ushort *) skb_push(skb, 2)) = htons(type);
+			*((__be16 *)skb_push(skb, 2)) = htons(type);
 			len = 2;
 			break;
 		case ISDN_NET_ENCAP_UIHDLC:
 			/* HDLC with UI-Frames (for ispa with -h1 option) */
-			*((ushort *) skb_push(skb, 2)) = htons(0x0103);
+			*((__be16 *)skb_push(skb, 2)) = htons(0x0103);
 			len = 2;
 			break;
 		case ISDN_NET_ENCAP_CISCOHDLC:
 		case ISDN_NET_ENCAP_CISCOHDLCK:
 			p = skb_push(skb, 4);
-			p += put_u8 (p, CISCO_ADDR_UNICAST);
-			p += put_u8 (p, CISCO_CTRL);
-			p += put_u16(p, type);
+			*(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
+			*(u8 *)(p + 1) = CISCO_CTRL;
+			*(__be16 *)(p + 2) = cpu_to_be16(type);
+			p += 4;
 			len = 4;
 			break;
 #ifdef CONFIG_ISDN_X25
@@ -1942,7 +1936,7 @@
 isdn_net_rebuild_header(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
-	isdn_net_local *lp = dev->priv;
+	isdn_net_local *lp = netdev_priv(dev);
 	int ret = 0;
 
 	if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
@@ -1972,7 +1966,7 @@
 static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
 {
 	const struct net_device *dev = neigh->dev;
-	isdn_net_local *lp = dev->priv;
+	isdn_net_local *lp = netdev_priv(dev);
 
 	if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
 		return eth_header_cache(neigh, hh);
@@ -1983,9 +1977,9 @@
 				     const struct net_device *dev,
 				     const unsigned char *haddr)
 {
-	isdn_net_local *lp = dev->priv;
+	isdn_net_local *lp = netdev_priv(dev);
 	if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
-		return eth_header_cache_update(hh, dev, haddr);
+		eth_header_cache_update(hh, dev, haddr);
 }
 
 static const struct header_ops isdn_header_ops = {
@@ -2298,16 +2292,16 @@
 				 * it's master and parent slave is online. If not, reject the call.
 				 */
 				if (lp->master) {
-					isdn_net_local *mlp = (isdn_net_local *) lp->master->priv;
+					isdn_net_local *mlp = ISDN_MASTER_PRIV(lp);
 					printk(KERN_DEBUG "ICALLslv: %s\n", p->dev->name);
 					printk(KERN_DEBUG "master=%s\n", lp->master->name);
 					if (mlp->flags & ISDN_NET_CONNECTED) {
 						printk(KERN_DEBUG "master online\n");
 						/* Master is online, find parent-slave (master if first slave) */
 						while (mlp->slave) {
-							if ((isdn_net_local *) mlp->slave->priv == lp)
+							if (ISDN_SLAVE_PRIV(mlp) == lp)
 								break;
-							mlp = (isdn_net_local *) mlp->slave->priv;
+							mlp = ISDN_SLAVE_PRIV(mlp);
 						}
 					} else
 						printk(KERN_DEBUG "master offline\n");
@@ -2519,7 +2513,7 @@
  */
 static void _isdn_setup(struct net_device *dev)
 {
-	isdn_net_local *lp = dev->priv;
+	isdn_net_local *lp = netdev_priv(dev);
 
 	dev->flags = IFF_NOARP | IFF_POINTOPOINT;
 	lp->p_encap = ISDN_NET_ENCAP_RAWIP;
@@ -2575,20 +2569,20 @@
 		kfree(netdev);
 		return NULL;
 	}
-	netdev->local = netdev->dev->priv;
+	netdev->local = netdev_priv(netdev->dev);
 	netdev->dev->init = isdn_net_init;
 	if (master) {
 		/* Device shall be a slave */
-		struct net_device *p = (((isdn_net_local *) master->priv)->slave);
+		struct net_device *p = MASTER_TO_SLAVE(master);
 		struct net_device *q = master;
 
 		netdev->local->master = master;
 		/* Put device at end of slave-chain */
 		while (p) {
 			q = p;
-			p = (((isdn_net_local *) p->priv)->slave);
+			p = MASTER_TO_SLAVE(p);
 		}
-		((isdn_net_local *) q->priv)->slave = netdev->dev;
+		MASTER_TO_SLAVE(q) = netdev->dev;
 	} else {
 		/* Device shall be a master */
 		/*
@@ -3086,7 +3080,7 @@
 		/* If this interface has slaves, do a hangup for them also. */
 		while (q) {
 			isdn_net_hangup(q);
-			q = (((isdn_net_local *) q->priv)->slave);
+			q = MASTER_TO_SLAVE(q);
 		}
 		isdn_net_hangup(p->dev);
 		return 0;
@@ -3116,8 +3110,10 @@
 		isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
 	if (p->local->master) {
 		/* It's a slave-device, so update master's slave-pointer if necessary */
-		if (((isdn_net_local *) (p->local->master->priv))->slave == p->dev)
-			((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave;
+		if (((isdn_net_local *) ISDN_MASTER_PRIV(p->local))->slave ==
+		    p->dev)
+			((isdn_net_local *)ISDN_MASTER_PRIV(p->local))->slave =
+				p->local->slave;
 	} else {
 		/* Unregister only if it's a master-device */
 		unregister_netdev(p->dev);
diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
index be49497..74032d0 100644
--- a/drivers/isdn/i4l/isdn_net.h
+++ b/drivers/isdn/i4l/isdn_net.h
@@ -56,6 +56,11 @@
 
 #define ISDN_NET_MAX_QUEUE_LENGTH 2
 
+#define ISDN_MASTER_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->master))
+#define ISDN_SLAVE_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->slave))
+#define MASTER_TO_SLAVE(master)	\
+			(((isdn_net_local *) netdev_priv(master))->slave)
+
 /*
  * is this particular channel busy?
  */
@@ -126,7 +131,7 @@
 	unsigned long flags;
 
 	if (lp->master)
-		master_lp = (isdn_net_local *) lp->master->priv;
+		master_lp = ISDN_MASTER_PRIV(lp);
 
 //	printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
 //		__func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue);
@@ -145,46 +150,3 @@
 	spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
 }
 
-static inline int
-put_u8(unsigned char *p, u8 x)
-{
-	*p = x;
-	return 1;
-}
-
-static inline int
-put_u16(unsigned char *p, u16 x)
-{
-	*((u16 *)p) = htons(x);
-	return 2;
-}
-
-static inline int
-put_u32(unsigned char *p, u32 x)
-{
-	*((u32 *)p) = htonl(x);
-	return 4;
-}
-
-static inline int
-get_u8(unsigned char *p, u8 *x)
-{
-	*x = *p;
-	return 1;
-}
-
-static inline int
-get_u16(unsigned char *p, u16 *x)
-{
-	*x = ntohs(*((u16 *)p));
-	return 2;
-}
-
-static inline int
-get_u32(unsigned char *p, u32 *x)
-{
-	*x = ntohl(*((u32 *)p));
-	return 4;
-}
-
-
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 77c280e..a3551dd 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -1040,7 +1040,7 @@
 	is = ippp_table[slot];
  	
  	if (lp->master) { // FIXME?
-		mlp = (isdn_net_local *) lp->master->priv;
+		mlp = ISDN_MASTER_PRIV(lp);
  		slot = mlp->ppp_slot;
  		if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
  			printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
@@ -1223,7 +1223,7 @@
 	struct ippp_struct *ipt,*ipts;
 	int slot, retval = 0;
 
-	mlp = (isdn_net_local *) (netdev->priv);
+	mlp = (isdn_net_local *) netdev_priv(netdev);
 	nd = mlp->netdev;       /* get master lp */
 
 	slot = mlp->ppp_slot;
@@ -1289,10 +1289,10 @@
 	*skb_push(skb, 4) = 1; /* indicate outbound */
 
 	{
-		u_int16_t *p = (u_int16_t *) skb->data;
+		__be16 *p = (__be16 *)skb->data;
 
 		p++;
-		*p   = htons(proto);
+		*p = htons(proto);
 	}
 
 	if (ipt->pass_filter
@@ -1487,10 +1487,10 @@
 	*skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */
 
 	{
-		u_int16_t *p = (u_int16_t *) skb->data;
+		__be16 *p = (__be16 *)skb->data;
 
 		p++;
-		*p   = htons(proto);
+		*p = htons(proto);
 	}
 	
 	drop |= is->pass_filter
@@ -1810,14 +1810,14 @@
    
    	if( !short_seq )
 	{
-		seq = ntohl(*(u32*)skb->data) & MP_LONGSEQ_MASK;
+		seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK;
 		skb_push(skb,1);
 	}
 	else
 	{
 		/* convert 12-bit short seq number to 24-bit long one 
 	 	*/
-		seq = ntohs(*(u16*)skb->data) & MP_SHORTSEQ_MASK;
+		seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK;
 	
 		/* check for seqence wrap */
 		if( !(seq &  MP_SHORTSEQ_MAXBIT) && 
@@ -2013,7 +2013,7 @@
 {
 	struct ppp_stats __user *res = ifr->ifr_data;
 	struct ppp_stats t;
-	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
 
 	if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats)))
 		return -EFAULT;
@@ -2052,7 +2052,7 @@
 {
 	int error=0;
 	int len;
-	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
 
 
 	if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
@@ -2119,7 +2119,7 @@
 
 	sdev = lp->slave;
 	while (sdev) {
-		isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
+		isdn_net_local *mlp = (isdn_net_local *) netdev_priv(sdev);
 		if (!(mlp->flags & ISDN_NET_CONNECTED))
 			break;
 		sdev = mlp->slave;
@@ -2127,7 +2127,7 @@
 	if (!sdev)
 		return 2;
 
-	isdn_net_dial_req((isdn_net_local *) sdev->priv);
+	isdn_net_dial_req((isdn_net_local *) netdev_priv(sdev));
 	return 0;
 #else
 	return -1;
@@ -2150,10 +2150,10 @@
 
 	sdev = lp->slave;
 	while (sdev) {
-		isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
+		isdn_net_local *mlp = (isdn_net_local *) netdev_priv(sdev);
 
 		if (mlp->slave) { /* find last connected link in chain */
-			isdn_net_local *nlp = (isdn_net_local *) mlp->slave->priv;
+			isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp);
 
 			if (!(nlp->flags & ISDN_NET_CONNECTED))
 				break;
@@ -2688,7 +2688,7 @@
 	isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
 
 	if(lp->master) {
-		int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		int slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
 		if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
 			printk(KERN_ERR "%s: slot(%d) out of range\n",
 				__func__, slot);
@@ -2875,7 +2875,7 @@
 	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
 
 	if (lp->master) {
-		slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
 		if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
 			printk(KERN_ERR "%s: slot(%d) out of range\n",
 				__func__, slot);
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
index 3306817..751665c4 100644
--- a/drivers/isdn/mISDN/core.c
+++ b/drivers/isdn/mISDN/core.c
@@ -26,12 +26,12 @@
 module_param(debug, uint, S_IRUGO | S_IWUSR);
 
 static LIST_HEAD(devices);
-DEFINE_RWLOCK(device_lock);
+static DEFINE_RWLOCK(device_lock);
 static u64		device_ids;
 #define MAX_DEVICE_ID	63
 
 static LIST_HEAD(Bprotocols);
-DEFINE_RWLOCK(bp_lock);
+static DEFINE_RWLOCK(bp_lock);
 
 struct mISDNdevice
 *get_mdevice(u_int id)
@@ -192,7 +192,7 @@
 }
 EXPORT_SYMBOL(mISDN_unregister_Bprotocol);
 
-int
+static int
 mISDNInit(void)
 {
 	int	err;
@@ -224,7 +224,7 @@
 	return err;
 }
 
-void mISDN_cleanup(void)
+static void mISDN_cleanup(void)
 {
 	misdn_sock_cleanup();
 	mISDN_timer_cleanup();
diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c
index 1c2dd56..de3795e 100644
--- a/drivers/isdn/mISDN/dsp_audio.c
+++ b/drivers/isdn/mISDN/dsp_audio.c
@@ -30,7 +30,7 @@
 /* alaw -> ulaw */
 u8 dsp_audio_alaw_to_ulaw[256];
 /* ulaw -> alaw */
-u8 dsp_audio_ulaw_to_alaw[256];
+static u8 dsp_audio_ulaw_to_alaw[256];
 u8 dsp_silence;
 
 
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index c2f51cc..c884511 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -1540,11 +1540,13 @@
 	schedule_work(&dsp->workq);
 }
 
-u32	samplecount;
+static u32	samplecount;
 struct timer_list dsp_spl_tl;
 u32	dsp_spl_jiffies; /* calculate the next time to fire */
-u32	dsp_start_jiffies; /* jiffies at the time, the calculation begins */
-struct timeval dsp_start_tv; /* time at start of calculation */
+#ifdef UNUSED
+static u32	dsp_start_jiffies; /* jiffies at the time, the calculation begins */
+#endif /* UNUSED */
+static struct timeval dsp_start_tv; /* time at start of calculation */
 
 void
 dsp_cmx_send(void *arg)
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c
index 2f10ed8..1dc21d8 100644
--- a/drivers/isdn/mISDN/dsp_core.c
+++ b/drivers/isdn/mISDN/dsp_core.c
@@ -161,7 +161,7 @@
 #include "core.h"
 #include "dsp.h"
 
-const char *mISDN_dsp_revision = "2.0";
+static const char *mISDN_dsp_revision = "2.0";
 
 static int debug;
 static int options;
@@ -631,7 +631,6 @@
 	int			ret = 0;
 	u8			*digits;
 	int			cont;
-	struct			sk_buff *nskb;
 	u_long			flags;
 
 	hh = mISDN_HEAD_P(skb);
@@ -690,6 +689,7 @@
 			digits = dsp_dtmf_goertzel_decode(dsp, skb->data,
 				skb->len, (dsp_options&DSP_OPT_ULAW)?1:0);
 			while (*digits) {
+				struct sk_buff *nskb;
 				if (dsp_debug & DEBUG_DSP_DTMF)
 					printk(KERN_DEBUG "%s: digit"
 					    "(%c) to layer %s\n",
diff --git a/drivers/isdn/mISDN/dsp_hwec.c b/drivers/isdn/mISDN/dsp_hwec.c
index eb892d9..806a997 100644
--- a/drivers/isdn/mISDN/dsp_hwec.c
+++ b/drivers/isdn/mISDN/dsp_hwec.c
@@ -43,7 +43,7 @@
 	.free = NULL,
 	.process_tx = NULL,
 	.process_rx = NULL,
-	.num_args = sizeof(args) / sizeof(struct mISDN_dsp_element_arg),
+	.num_args = ARRAY_SIZE(args),
 	.args = args,
 };
 struct mISDN_dsp_element *dsp_hwec = &dsp_hwec_p;
diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c
index 850260a..5ee6651 100644
--- a/drivers/isdn/mISDN/dsp_pipeline.c
+++ b/drivers/isdn/mISDN/dsp_pipeline.c
@@ -249,7 +249,7 @@
 		name = strsep(&tok, "(");
 		args = strsep(&tok, ")");
 		if (args && !*args)
-			args = 0;
+			args = NULL;
 
 		list_for_each_entry_safe(entry, n, &dsp_elements, list)
 			if (!strcmp(entry->elem->name, name)) {
diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c
index 23dd0dd..7a9af66 100644
--- a/drivers/isdn/mISDN/dsp_tones.c
+++ b/drivers/isdn/mISDN/dsp_tones.c
@@ -231,120 +231,120 @@
  * tone sequence definition *
  ****************************/
 
-struct pattern {
+static struct pattern {
 	int tone;
 	u8 *data[10];
 	u32 *siz[10];
 	u32 seq[10];
 } pattern[] = {
 	{TONE_GERMAN_DIALTONE,
-	{DATA_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{1900, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_OLDDIALTONE,
-	{DATA_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{1998, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_AMERICAN_DIALTONE,
-	{DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_DIALPBX,
-	{DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0},
-	{SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0},
+	{DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL},
+	{SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL},
 	{2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_OLDDIALPBX,
-	{DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0},
-	{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0},
+	{DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL},
+	{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL},
 	{2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
 
 	{TONE_AMERICAN_DIALPBX,
-	{DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, 0, 0, 0, 0},
-	{SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, 0, 0, 0, 0},
+	{DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL, NULL},
+	{SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL, NULL},
 	{2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_RINGING,
-	{DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_OLDRINGING,
-	{DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{8000, 40000, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_AMERICAN_RINGING,
-	{DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_RINGPBX,
-	{DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0},
-	{SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0},
+	{DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
 	{4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_OLDRINGPBX,
-	{DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0},
-	{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0},
+	{DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
 	{4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_AMERICAN_RINGPBX,
-	{DATA_RI, DATA_S, DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0},
-	{SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0},
+	{DATA_RI, DATA_S, DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
 	{4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_BUSY,
-	{DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_OLDBUSY,
-	{DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_AMERICAN_BUSY,
-	{DATA_BU, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_BU, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_BU, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_BU, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_HANGUP,
-	{DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_OLDHANGUP,
-	{DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_AMERICAN_HANGUP,
-	{DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_SPECIAL_INFO,
-	{DATA_S1, DATA_S2, DATA_S3, DATA_S, 0, 0, 0, 0, 0, 0},
-	{SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, 0, 0, 0, 0, 0, 0},
+	{DATA_S1, DATA_S2, DATA_S3, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
 	{2666, 2666, 2666, 8002, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_GASSENBESETZT,
-	{DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0},
-	{SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0},
+	{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{2000, 2000, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 	{TONE_GERMAN_AUFSCHALTTON,
-	{DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0},
-	{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0},
+	{DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
+	{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
 	{1000, 5000, 1000, 17000, 0, 0, 0, 0, 0, 0} },
 
 	{0,
-	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
 	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 };
 
@@ -467,7 +467,7 @@
 
 	/* set next tone */
 	if (pat->data[index] == DATA_S)
-		dsp_tone_hw_message(dsp, 0, 0);
+		dsp_tone_hw_message(dsp, NULL, 0);
 	else
 		dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index]));
 	/* set timer */
diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c
index a2dc457..2ec4b28 100644
--- a/drivers/isdn/mISDN/l1oip_codec.c
+++ b/drivers/isdn/mISDN/l1oip_codec.c
@@ -49,6 +49,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mISDNif.h>
 #include "core.h"
+#include "l1oip.h"
 
 /* definitions of codec. don't use calculations, code may run slower. */
 
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index e42150a..0884dd6 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -469,7 +469,7 @@
 static void
 l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len)
 {
-	u32			id;
+	u32			packet_id;
 	u8			channel;
 	u8			remotecodec;
 	u16			timebase;
@@ -508,7 +508,7 @@
 	}
 
 	/* get id flag */
-	id = (*buf>>4)&1;
+	packet_id = (*buf>>4)&1;
 
 	/* check coding */
 	remotecodec = (*buf) & 0x0f;
@@ -520,11 +520,11 @@
 	buf++;
 	len--;
 
-	/* check id */
-	if (id) {
+	/* check packet_id */
+	if (packet_id) {
 		if (!hc->id) {
 			printk(KERN_WARNING "%s: packet error - packet has id "
-				"0x%x, but we have not\n", __func__, id);
+				"0x%x, but we have not\n", __func__, packet_id);
 			return;
 		}
 		if (len < 4) {
@@ -532,16 +532,16 @@
 				"short for ID value\n", __func__);
 			return;
 		}
-		id = (*buf++) << 24;
-		id += (*buf++) << 16;
-		id += (*buf++) << 8;
-		id += (*buf++);
+		packet_id = (*buf++) << 24;
+		packet_id += (*buf++) << 16;
+		packet_id += (*buf++) << 8;
+		packet_id += (*buf++);
 		len -= 4;
 
-		if (id != hc->id) {
+		if (packet_id != hc->id) {
 			printk(KERN_WARNING "%s: packet error - ID mismatch, "
 				"got 0x%x, we 0x%x\n",
-				__func__, id, hc->id);
+				__func__, packet_id, hc->id);
 			return;
 		}
 	} else {
diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c
index fced1a2..b73e952 100644
--- a/drivers/isdn/mISDN/layer1.c
+++ b/drivers/isdn/mISDN/layer1.c
@@ -18,10 +18,11 @@
 
 #include <linux/module.h>
 #include <linux/mISDNhw.h>
+#include "core.h"
 #include "layer1.h"
 #include "fsm.h"
 
-static int *debug;
+static u_int *debug;
 
 struct layer1 {
 	u_long			Flags;
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c
index a7915a1..d6e2863 100644
--- a/drivers/isdn/mISDN/layer2.c
+++ b/drivers/isdn/mISDN/layer2.c
@@ -15,10 +15,12 @@
  *
  */
 
+#include <linux/mISDNif.h>
+#include "core.h"
 #include "fsm.h"
 #include "layer2.h"
 
-static int *debug;
+static u_int *debug;
 
 static
 struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL};
@@ -465,7 +467,7 @@
 	    data[0] == RNR : (data[0] & 0xf) == RNR;
 }
 
-int
+static int
 iframe_error(struct layer2 *l2, struct sk_buff *skb)
 {
 	u_int	i;
@@ -483,7 +485,7 @@
 	return 0;
 }
 
-int
+static int
 super_error(struct layer2 *l2, struct sk_buff *skb)
 {
 	if (skb->len != l2addrsize(l2) +
@@ -492,7 +494,7 @@
 	return 0;
 }
 
-int
+static int
 unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp)
 {
 	int rsp = (*skb->data & 0x2) >> 1;
@@ -505,7 +507,7 @@
 	return 0;
 }
 
-int
+static int
 UI_error(struct layer2 *l2, struct sk_buff *skb)
 {
 	int rsp = *skb->data & 0x2;
@@ -518,7 +520,7 @@
 	return 0;
 }
 
-int
+static int
 FRMR_error(struct layer2 *l2, struct sk_buff *skb)
 {
 	u_int	headers = l2addrsize(l2) + 1;
@@ -1065,7 +1067,7 @@
 	}
 }
 
-void
+static void
 enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf)
 {
 	struct sk_buff *skb;
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index e5a20f9..37a2de1 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -18,7 +18,7 @@
 #include <linux/mISDNif.h>
 #include "core.h"
 
-static int	*debug;
+static u_int	*debug;
 
 static struct proto mISDN_proto = {
 	.name		= "misdn",
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c
index 54cfddc..d55b14a 100644
--- a/drivers/isdn/mISDN/stack.c
+++ b/drivers/isdn/mISDN/stack.c
@@ -36,7 +36,7 @@
 	}
 }
 
-int
+static int
 mISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb)
 {
 	_queue_message(ch->st, skb);
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c
index 6fbae42..5c43d19 100644
--- a/drivers/isdn/mISDN/tei.c
+++ b/drivers/isdn/mISDN/tei.c
@@ -393,7 +393,7 @@
 	return 0;
 }
 
-unsigned int
+static unsigned int
 random_ri(void)
 {
 	u16 x;
@@ -1287,7 +1287,7 @@
 	if (!mgr)
 		return -ENOMEM;
 	INIT_LIST_HEAD(&mgr->layer2);
-	mgr->lock = __RW_LOCK_UNLOCKED(mgr->lock);
+	rwlock_init(&mgr->lock);
 	skb_queue_head_init(&mgr->sendq);
 	mgr->nextid = 1;
 	mgr->lastid = MISDN_ID_NONE;
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c
index 875fabe..f2b3218 100644
--- a/drivers/isdn/mISDN/timerdev.c
+++ b/drivers/isdn/mISDN/timerdev.c
@@ -23,8 +23,9 @@
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/mISDNif.h>
+#include "core.h"
 
-static int	*debug;
+static u_int	*debug;
 
 
 struct mISDNtimerdev {
@@ -85,7 +86,7 @@
 }
 
 static ssize_t
-mISDN_read(struct file *filep, char *buf, size_t count, loff_t *off)
+mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off)
 {
 	struct mISDNtimerdev	*dev = filep->private_data;
 	struct mISDNtimer	*timer;
@@ -115,7 +116,7 @@
 		timer = (struct mISDNtimer *)dev->expired.next;
 		list_del(&timer->list);
 		spin_unlock_irqrestore(&dev->lock, flags);
-		if (put_user(timer->id, (int *)buf))
+		if (put_user(timer->id, (int __user *)buf))
 			ret = -EFAULT;
 		else
 			ret = sizeof(int);
@@ -274,7 +275,7 @@
 };
 
 int
-mISDN_inittimer(int *deb)
+mISDN_inittimer(u_int *deb)
 {
 	int	err;
 
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 741a93a..62dd1fd 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -23,7 +23,6 @@
 #else
 #include <asm/macintosh.h>
 #include <asm/macints.h>
-#include <asm/machw.h>
 #include <asm/mac_via.h>
 #endif
 #include <asm/io.h>
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
index 6e6dd17..817f37a 100644
--- a/drivers/macintosh/via-macii.c
+++ b/drivers/macintosh/via-macii.c
@@ -33,7 +33,6 @@
 #include <linux/init.h>
 #include <asm/macintosh.h>
 #include <asm/macints.h>
-#include <asm/machw.h>
 #include <asm/mac_via.h>
 #include <asm/system.h>
 
diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c
index 2dc7880..4d686c0 100644
--- a/drivers/macintosh/via-maciisi.c
+++ b/drivers/macintosh/via-maciisi.c
@@ -24,7 +24,6 @@
 #include <linux/interrupt.h>
 #include <asm/macintosh.h>
 #include <asm/macints.h>
-#include <asm/machw.h>
 #include <asm/mac_via.h>
 
 static volatile unsigned char *via;
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index d524dc2..b40fb9b 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -1814,7 +1814,7 @@
  		_set_L2CR(save_l2cr);
 	
 	/* Restore userland MMU context */
-	set_context(current->active_mm->context.id, current->active_mm->pgd);
+	switch_mmu_context(NULL, current->active_mm);
 
 	/* Power things up */
 	pmu_unlock();
@@ -1903,7 +1903,7 @@
  		_set_L3CR(save_l3cr);
 	
 	/* Restore userland MMU context */
-	set_context(current->active_mm->context.id, current->active_mm->pgd);
+	switch_mmu_context(NULL, current->active_mm);
 
 	/* Tell PMU we are ready */
 	pmu_unlock();
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index b64741c..fb9fa61 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -35,7 +35,6 @@
 
 #include <asm/macintosh.h>
 #include <asm/macints.h>
-#include <asm/machw.h>
 #include <asm/mac_via.h>
 
 #include <asm/pgtable.h>
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 7f2be4b..7847e98 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -87,11 +87,12 @@
 		return NULL;
 	}
 
-	len = i2c_smbus_read_word_data(&sat->i2c, 9);
-	if (len < 0) {
+	err = i2c_smbus_read_word_data(&sat->i2c, 9);
+	if (err < 0) {
 		printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n");
 		return NULL;
 	}
+	len = err;
 	if (len == 0) {
 		printk(KERN_ERR "smu_sat_get_sdb_part no partition %x\n", id);
 		return NULL;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index c99e4728..343094c 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -21,6 +21,7 @@
 #include <linux/idr.h>
 #include <linux/hdreg.h>
 #include <linux/blktrace_api.h>
+#include <trace/block.h>
 
 #define DM_MSG_PREFIX "core"
 
@@ -51,6 +52,8 @@
 	union map_info info;
 };
 
+DEFINE_TRACE(block_bio_complete);
+
 union map_info *dm_get_mapinfo(struct bio *bio)
 {
 	if (bio && bio->bi_private)
@@ -504,8 +507,7 @@
 		end_io_acct(io);
 
 		if (io->error != DM_ENDIO_REQUEUE) {
-			blk_add_trace_bio(io->md->queue, io->bio,
-					  BLK_TA_COMPLETE);
+			trace_block_bio_complete(io->md->queue, io->bio);
 
 			bio_endio(io->bio, io->error);
 		}
@@ -598,7 +600,7 @@
 	if (r == DM_MAPIO_REMAPPED) {
 		/* the bio has been remapped so dispatch it */
 
-		blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone,
+		trace_block_remap(bdev_get_queue(clone->bi_bdev), clone,
 				    tio->io->bio->bi_bdev->bd_dev,
 				    clone->bi_sector, sector);
 
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index 73dc2ee..b34301d 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -9,11 +9,11 @@
 	select DVB_STV0297 if !DVB_FE_CUSTOMISE
 	select DVB_BCM3510 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
 	select DVB_S5H1420 if !DVB_FE_CUSTOMISE
 	select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
 	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
 	select DVB_CX24123 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Support for the digital TV receiver chip made by B2C2 Inc. included in
 	  Technisats PCI cards and USB boxes.
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index a127a41..5cded37 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -628,12 +628,14 @@
 	}
 
 	/* try the cable dvb (stv0297) */
+	fc->fc_i2c_adap[0].no_base_addr = 1;
 	fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
 	if (fc->fe != NULL) {
 		fc->dev_type = FC_CABLE;
 		fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
 		goto fe_found;
 	}
+	fc->fc_i2c_adap[0].no_base_addr = 0;
 
 	/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
 	fc->fe = dvb_attach(mt312_attach,
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 43a112e..f13783f 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -47,9 +47,13 @@
 	int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */
 		ret;
 
-	r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
 	ret = flexcop_i2c_operation(i2c->fc, &r100);
 	if (ret != 0) {
+		deb_i2c("Retrying operation\n");
+		r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
+		ret = flexcop_i2c_operation(i2c->fc, &r100);
+	}
+	if (ret != 0) {
 		deb_i2c("read failed. %d\n", ret);
 		return ret;
 	}
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 5f79c8d..676413a 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -270,7 +270,7 @@
 	/* do the MAC address reading after initializing the dvb_adapter */
 	if (fc->get_mac_addr(fc, 0) == 0) {
 		u8 *b = fc->dvb_adapter.proposed_mac;
-		info("MAC address = %02x:%02x:%02x:%02x:%02x:%02x", b[0],b[1],b[2],b[3],b[4],b[5]);
+		info("MAC address = %pM", b);
 		flexcop_set_mac_filter(fc,b);
 		flexcop_mac_filter_ctrl(fc,1);
 	} else
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index 7e9c090..27edb0e 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -8,7 +8,7 @@
 	select DVB_OR51211 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Support for PCI cards based on the Bt8xx PCI bridge. Examples are
 	  the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index aa3db57..29e8f15 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -917,9 +917,7 @@
 	}
 	memset(&state->mac_address, '\0', 8);
 	memcpy(&state->mac_address, &state->rxbuffer, 6);
-	dprintk(verbose, DST_ERROR, 1, "MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]",
-		state->mac_address[0], state->mac_address[1], state->mac_address[2],
-		state->mac_address[4], state->mac_address[5], state->mac_address[6]);
+	dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address);
 
 	return 0;
 }
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index c1d92f8..a21ce9e 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -697,8 +697,7 @@
 	};
 
 	dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
-	dev_info(&dm1105dvb->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
-			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+	dev_info(&dm1105dvb->pdev->dev, "MAC %pM\n", mac);
 }
 
 static int __devinit dm1105_probe(struct pci_dev *pdev,
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index c93019c..03fd9dd 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -345,7 +345,7 @@
  */
 static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 {
-	struct dvb_net_priv *priv = dev->priv;
+	struct dvb_net_priv *priv = netdev_priv(dev);
 	unsigned long skipped = 0L;
 	const u8 *ts, *ts_end, *from_where = NULL;
 	u8 ts_remain = 0, how_much = 0, new_ts = 1;
@@ -460,8 +460,8 @@
 						/* Drop partly decoded SNDU, reset state, resync on PUSI. */
 						if (priv->ule_skb) {
 							dev_kfree_skb( priv->ule_skb );
-							((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-							((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+							priv->stats.rx_errors++;
+							priv->stats.rx_frame_errors++;
 						}
 						reset_ule(priv);
 						priv->need_pusi = 1;
@@ -573,7 +573,7 @@
 			if (priv->ule_skb == NULL) {
 				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
 				       dev->name);
-				((struct dvb_net_priv *)dev->priv)->stats.rx_dropped++;
+				priv->stats.rx_dropped++;
 				return;
 			}
 
@@ -800,7 +800,8 @@
 {
 	u8 *eth;
 	struct sk_buff *skb;
-	struct net_device_stats *stats = &(((struct dvb_net_priv *) dev->priv)->stats);
+	struct net_device_stats *stats =
+		&((struct dvb_net_priv *) netdev_priv(dev))->stats;
 	int snap = 0;
 
 	/* note: pkt_len includes a 32bit checksum */
@@ -917,7 +918,7 @@
 		   struct dmx_section_filter **secfilter,
 		   u8 *mac, u8 *mac_mask)
 {
-	struct dvb_net_priv *priv = dev->priv;
+	struct dvb_net_priv *priv = netdev_priv(dev);
 	int ret;
 
 	*secfilter=NULL;
@@ -961,7 +962,7 @@
 static int dvb_net_feed_start(struct net_device *dev)
 {
 	int ret = 0, i;
-	struct dvb_net_priv *priv = dev->priv;
+	struct dvb_net_priv *priv = netdev_priv(dev);
 	struct dmx_demux *demux = priv->demux;
 	unsigned char *mac = (unsigned char *) dev->dev_addr;
 
@@ -1060,7 +1061,7 @@
 
 static int dvb_net_feed_stop(struct net_device *dev)
 {
-	struct dvb_net_priv *priv = dev->priv;
+	struct dvb_net_priv *priv = netdev_priv(dev);
 	int i, ret = 0;
 
 	dprintk("%s\n", __func__);
@@ -1113,7 +1114,7 @@
 
 static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc)
 {
-	struct dvb_net_priv *priv = dev->priv;
+	struct dvb_net_priv *priv = netdev_priv(dev);
 
 	if (priv->multi_num == DVB_NET_MULTICAST_MAX)
 		return -ENOMEM;
@@ -1165,7 +1166,7 @@
 
 static void dvb_net_set_multicast_list (struct net_device *dev)
 {
-	struct dvb_net_priv *priv = dev->priv;
+	struct dvb_net_priv *priv = netdev_priv(dev);
 	schedule_work(&priv->set_multicast_list_wq);
 }
 
@@ -1185,7 +1186,7 @@
 
 static int dvb_net_set_mac (struct net_device *dev, void *p)
 {
-	struct dvb_net_priv *priv = dev->priv;
+	struct dvb_net_priv *priv = netdev_priv(dev);
 	struct sockaddr *addr=p;
 
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
@@ -1199,7 +1200,7 @@
 
 static int dvb_net_open(struct net_device *dev)
 {
-	struct dvb_net_priv *priv = dev->priv;
+	struct dvb_net_priv *priv = netdev_priv(dev);
 
 	priv->in_use++;
 	dvb_net_feed_start(dev);
@@ -1209,7 +1210,7 @@
 
 static int dvb_net_stop(struct net_device *dev)
 {
-	struct dvb_net_priv *priv = dev->priv;
+	struct dvb_net_priv *priv = netdev_priv(dev);
 
 	priv->in_use--;
 	return dvb_net_feed_stop(dev);
@@ -1217,7 +1218,7 @@
 
 static struct net_device_stats * dvb_net_get_stats(struct net_device *dev)
 {
-	return &((struct dvb_net_priv*) dev->priv)->stats;
+	return &((struct dvb_net_priv *) netdev_priv(dev))->stats;
 }
 
 static const struct header_ops dvb_header_ops = {
@@ -1287,7 +1288,7 @@
 
 	dvbnet->device[if_num] = net;
 
-	priv = net->priv;
+	priv = netdev_priv(net);
 	priv->net = net;
 	priv->demux = dvbnet->demux;
 	priv->pid = pid;
@@ -1320,7 +1321,7 @@
 
 	if (!dvbnet->state[num])
 		return -EINVAL;
-	priv = net->priv;
+	priv = netdev_priv(net);
 	if (priv->in_use)
 		return -EBUSY;
 
@@ -1376,7 +1377,7 @@
 
 		netdev = dvbnet->device[dvbnetif->if_num];
 
-		priv_data = netdev->priv;
+		priv_data = netdev_priv(netdev);
 		dvbnetif->pid=priv_data->pid;
 		dvbnetif->feedtype=priv_data->feedtype;
 		break;
@@ -1427,7 +1428,7 @@
 
 		netdev = dvbnet->device[dvbnetif->if_num];
 
-		priv_data = netdev->priv;
+		priv_data = netdev_priv(netdev);
 		dvbnetif->pid=priv_data->pid;
 		break;
 	}
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 62b68c2..49f7b20 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -24,8 +24,8 @@
 	tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
 	depends on DVB_USB
 	select DVB_DIB3000MC
-	select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
 	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
 
@@ -34,7 +34,7 @@
 	depends on DVB_USB
 	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_DIB3000MB
-	select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
 	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
@@ -55,7 +55,7 @@
 	tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
 	depends on DVB_USB
 	select DVB_DIB3000MC
-	select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Support for USB2.0 DVB-T receivers based on reference designs made by
 	  DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
@@ -73,11 +73,11 @@
 	select DVB_DIB7000M
 	select DVB_DIB3000MC
 	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
 	select DVB_TUNER_DIB0070
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+	select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMIZE
+	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
+	select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
 	  USB bridge is also present in devices having the DiB7700 DVB-T-USB
@@ -95,7 +95,7 @@
 	depends on DVB_USB
 	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_DIB3000MC
-	select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
 
@@ -107,11 +107,11 @@
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
 	select DVB_DIB7000P if !DVB_FE_CUSTOMISE
 	select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+	select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
+	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to support the Conexant USB2.0 hybrid reference design.
 	  Currently, only DVB and ATSC modes are supported, analog mode
@@ -124,9 +124,9 @@
 	tristate "Uli m920x DVB-T USB2.0 support"
 	depends on DVB_USB
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
+	select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
 	  Currently, only devices with a product id of
@@ -137,7 +137,7 @@
 	tristate "Genesys Logic GL861 USB2.0 support"
 	depends on DVB_USB
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
 	  receiver with USB ID 0db0:5581.
@@ -146,7 +146,7 @@
 	tristate "Alcor Micro AU6610 USB2.0 support"
 	depends on DVB_USB
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
 
@@ -198,8 +198,8 @@
 	tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
 	depends on DVB_USB
 	select DVB_DIB3000MC
-	select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
 	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
 
@@ -235,8 +235,8 @@
 config DVB_USB_AF9005
 	tristate "Afatech AF9005 DVB-T USB1.1 support"
 	depends on DVB_USB && EXPERIMENTAL
-	select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMIZE
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
 	  and the TerraTec Cinergy T USB XE (Rev.1)
@@ -284,7 +284,7 @@
 	tristate "AME DTV-5100 USB2.0 DVB-T support"
 	depends on DVB_USB
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
 
@@ -293,9 +293,9 @@
 	depends on DVB_USB && EXPERIMENTAL
 	select DVB_AF9013
 	select DVB_PLL              if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MT2060   if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_QT1010   if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MT2060   if !MEDIA_TUNER_CUSTOMIZE
+	select MEDIA_TUNER_QT1010   if !MEDIA_TUNER_CUSTOMIZE
+	select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMIZE
+	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
 	help
 	  Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index f28d3ae..3917327 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -446,13 +446,13 @@
 		== NULL ? -ENODEV : 0;
 }
 
-#define DEFAULT_RC_INTERVAL 150
+#define DEFAULT_RC_INTERVAL 50
 
 static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
 
 /* Number of keypresses to ignore before start repeating */
-#define RC_REPEAT_DELAY 2
-#define RC_REPEAT_DELAY_V1_20 5
+#define RC_REPEAT_DELAY 6
+#define RC_REPEAT_DELAY_V1_20 10
 
 
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
index ce8cd0c..8a7d87b 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -91,10 +91,7 @@
 
 	if (adap->dev->props.read_mac_address) {
 		if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
-			info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",adap->dvb_adap.proposed_mac[0],
-					adap->dvb_adap.proposed_mac[1], adap->dvb_adap.proposed_mac[2],
-					adap->dvb_adap.proposed_mac[3], adap->dvb_adap.proposed_mac[4],
-					adap->dvb_adap.proposed_mac[5]);
+			info("MAC address: %pM",adap->dvb_adap.proposed_mac);
 		else
 			err("MAC address reading failed.");
 	}
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index a9653c6..d101b30 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -560,8 +560,7 @@
 	mac[4] = (val >> 8) & 0xff;
 	mac[5] = (val >> 0) & 0xff;
 
-	dev_info(&pluto->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
-			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+	dev_info(&pluto->pdev->dev, "MAC %pM\n", mac);
 }
 
 static int __devinit pluto_read_serial(struct pluto *pluto)
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 867027c..401a04e 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -106,7 +106,7 @@
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
 	select VIDEO_IR
 	help
 	  Support for simple SAA7146 based DVB cards
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 47102c2..057fd7e1 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -759,7 +759,7 @@
 
 config VIDEO_SH_MOBILE_CEU
 	tristate "SuperH Mobile CEU Interface driver"
-	depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA
+	depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
 	select VIDEOBUF_DMA_CONTIG
 	---help---
 	  This is a v4l2 driver for the SuperH Mobile CEU Interface
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index e6ca401..0ea85a0 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -831,7 +831,7 @@
 {
 	int ret = -ENOIOCTLCMD;
 
-	if (!file->f_op->ioctl)
+	if (!file->f_op->ioctl && !file->f_op->unlocked_ioctl)
 		return ret;
 
 	switch (cmd) {
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
index ef48565..8940b53 100644
--- a/drivers/media/video/cx18/Kconfig
+++ b/drivers/media/video/cx18/Kconfig
@@ -9,7 +9,7 @@
 	select VIDEO_CX2341X
 	select VIDEO_CS5345
 	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
 	---help---
 	  This is a video4linux driver for Conexant cx23418 based
 	  PCI combo video recorder devices.
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index 8c1b7fa4..00f1e2e 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -11,16 +11,16 @@
 	select VIDEO_CX25840
 	select VIDEO_CX2341X
 	select DVB_DIB7000P if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE
 	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
 	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
+	select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMIZE
 	select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
-	select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
 	---help---
 	  This is a video4linux driver for Conexant 23885 based
 	  TV cards.
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 0b9e5fa..b0f8375 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -56,12 +56,12 @@
 	select DVB_NXT200X if !DVB_FE_CUSTOMISE
 	select DVB_CX24123 if !DVB_FE_CUSTOMISE
 	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
 	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_STV0288 if !DVB_FE_CUSTOMISE
 	select DVB_STB6000 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
 	---help---
 	  This adds support for DVB/ATSC cards based on the
 	  Conexant 2388x chip.
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 610f535..4ea1f1e 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -549,10 +549,11 @@
 static void em28xx_config_i2c(struct em28xx *dev)
 {
 	struct v4l2_routing route;
+	int zero = 0;
 
 	route.input = INPUT(dev->ctl_input)->vmux;
 	route.output = 0;
-	em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
+	em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, &zero);
 	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 	em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
 }
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 748a87e..02a6e9e 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -1264,10 +1264,10 @@
 	struct gspca_dev *gspca_dev = priv;
 	int ret;
 
-	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-		return -ERESTARTSYS;
 	if (!gspca_dev->sd_desc->set_jcomp)
 		return -EINVAL;
+	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+		return -ERESTARTSYS;
 	ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
 	mutex_unlock(&gspca_dev->usb_lock);
 	return ret;
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
index 19eb274..854c2a8 100644
--- a/drivers/media/video/pvrusb2/Kconfig
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -42,7 +42,7 @@
 	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
 	select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
 	select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
-	select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
 	select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
 	---help---
 
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 7021bbf..fc2164e 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -34,9 +34,9 @@
 	select DVB_NXT200X if !DVB_FE_CUSTOMISE
 	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
 	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
-	select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
+	select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
 	---help---
 	  This adds support for DVB cards based on the
 	  Philips saa7134 chip.
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 2407607..536b1a9 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -31,6 +31,7 @@
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
+#include <linux/clk.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
@@ -89,6 +90,7 @@
 
 	unsigned int irq;
 	void __iomem *base;
+	struct clk *clk;
 	unsigned long video_limit;
 
 	/* lock used to protect videobuf */
@@ -309,6 +311,8 @@
 	if (ret)
 		goto err;
 
+	clk_enable(pcdev->clk);
+
 	ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
 	while (ceu_read(pcdev, CSTSR) & 1)
 		msleep(1);
@@ -342,6 +346,8 @@
 	}
 	spin_unlock_irqrestore(&pcdev->lock, flags);
 
+	clk_disable(pcdev->clk);
+
 	icd->ops->release(icd);
 
 	dev_info(&icd->dev,
@@ -550,6 +556,7 @@
 	struct sh_mobile_ceu_dev *pcdev;
 	struct resource *res;
 	void __iomem *base;
+	char clk_name[8];
 	unsigned int irq;
 	int err = 0;
 
@@ -615,6 +622,14 @@
 		goto exit_release_mem;
 	}
 
+	snprintf(clk_name, sizeof(clk_name), "ceu%d", pdev->id);
+	pcdev->clk = clk_get(&pdev->dev, clk_name);
+	if (IS_ERR(pcdev->clk)) {
+		dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+		err = PTR_ERR(pcdev->clk);
+		goto exit_free_irq;
+	}
+
 	pcdev->ici.priv = pcdev;
 	pcdev->ici.dev.parent = &pdev->dev;
 	pcdev->ici.nr = pdev->id;
@@ -623,10 +638,12 @@
 
 	err = soc_camera_host_register(&pcdev->ici);
 	if (err)
-		goto exit_free_irq;
+		goto exit_free_clk;
 
 	return 0;
 
+exit_free_clk:
+	clk_put(pcdev->clk);
 exit_free_irq:
 	free_irq(pcdev->irq, pcdev);
 exit_release_mem:
@@ -645,6 +662,7 @@
 	struct sh_mobile_ceu_dev *pcdev = platform_get_drvdata(pdev);
 
 	soc_camera_host_unregister(&pcdev->ici);
+	clk_put(pcdev->clk);
 	free_irq(pcdev->irq, pcdev);
 	if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
 		dma_release_declared_memory(&pdev->dev);
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index 603ffd0..a13f6ee 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -815,7 +815,7 @@
  * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue
  */
 {
-	struct mpt_lan_priv *priv = dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 	
 	if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
 		if (priority) {
@@ -834,7 +834,7 @@
 static int
 mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
 {
-	struct mpt_lan_priv *priv = dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 
 	skb->protocol = mpt_lan_type_trans(skb, dev);
 
@@ -866,7 +866,7 @@
 static int
 mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg)
 {
-	struct mpt_lan_priv *priv = dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
 	struct sk_buff *skb, *old_skb;
 	unsigned long flags;
@@ -921,7 +921,7 @@
 mpt_lan_receive_post_free(struct net_device *dev,
 			  LANReceivePostReply_t *pRecvRep)
 {
-	struct mpt_lan_priv *priv = dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
 	unsigned long flags;
 	struct sk_buff *skb;
@@ -976,7 +976,7 @@
 mpt_lan_receive_post_reply(struct net_device *dev,
 			   LANReceivePostReply_t *pRecvRep)
 {
-	struct mpt_lan_priv *priv = dev->priv;
+	struct mpt_lan_priv *priv = netdev_priv(dev);
 	MPT_ADAPTER *mpt_dev = priv->mpt_dev;
 	struct sk_buff *skb, *old_skb;
 	unsigned long flags;
@@ -1427,11 +1427,9 @@
 		printk(KERN_INFO MYNAM ": %s: Fusion MPT LAN device "
 		       "registered as '%s'\n", ioc->name, dev->name);
 		printk(KERN_INFO MYNAM ": %s/%s: "
-		       "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+		       "LanAddr = %pM\n",
 		       IOC_AND_NETDEV_NAMES_s_s(dev),
-		       dev->dev_addr[0], dev->dev_addr[1],
-		       dev->dev_addr[2], dev->dev_addr[3],
-		       dev->dev_addr[4], dev->dev_addr[5]);
+		       dev->dev_addr);
 	
 		ioc->netdev = dev;
 
@@ -1516,9 +1514,8 @@
 
 		printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n",
 				NETDEV_PTR_TO_IOC_NAME_s(dev));
-		printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
-				fch->saddr[0], fch->saddr[1], fch->saddr[2],
-				fch->saddr[3], fch->saddr[4], fch->saddr[5]);
+		printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %pM\n",
+				fch->saddr);
 	}
 
 	if (*fch->daddr & 1) {
@@ -1537,7 +1534,6 @@
 
 	fcllc = (struct fcllc *)skb->data;
 
-
 	/* Strip the SNAP header from ARP packets since we don't
 	 * pass them through to the 802.2/SNAP layers.
 	 */
diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h
index 33927ee..c171afa 100644
--- a/drivers/message/fusion/mptlan.h
+++ b/drivers/message/fusion/mptlan.h
@@ -122,7 +122,7 @@
 #define dlprintk(x)
 #endif
 
-#define NETDEV_TO_LANPRIV_PTR(d)	((struct mpt_lan_priv *)(d)->priv)
+#define NETDEV_TO_LANPRIV_PTR(d)	((struct mpt_lan_priv *)netdev_priv(d))
 #define NETDEV_PTR_TO_IOC_NAME_s(d)	(NETDEV_TO_LANPRIV_PTR(d)->mpt_dev->name)
 #define IOC_AND_NETDEV_NAMES_s_s(d)	NETDEV_PTR_TO_IOC_NAME_s(d), (d)->name
 
diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c
index 533923f..73b0ca0 100644
--- a/drivers/misc/sgi-gru/gruprocfs.c
+++ b/drivers/misc/sgi-gru/gruprocfs.c
@@ -317,7 +317,6 @@
 {
 	struct proc_entry *p;
 
-	proc_mkdir("sgi_uv", NULL);
 	proc_gru = proc_mkdir("sgi_uv/gru", NULL);
 
 	for (p = proc_files; p->name; p++)
diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h
index ed1722e..7b4cbd5 100644
--- a/drivers/misc/sgi-xp/xp.h
+++ b/drivers/misc/sgi-xp/xp.h
@@ -194,9 +194,10 @@
 	xpGruSendMqError,	/* 59: gru send message queue related error */
 
 	xpBadChannelNumber,	/* 60: invalid channel number */
-	xpBadMsgType,		/* 60: invalid message type */
+	xpBadMsgType,		/* 61: invalid message type */
+	xpBiosError,		/* 62: BIOS error */
 
-	xpUnknownReason		/* 61: unknown reason - must be last in enum */
+	xpUnknownReason		/* 63: unknown reason - must be last in enum */
 };
 
 /*
@@ -345,6 +346,8 @@
 extern enum xp_retval (*xp_remote_memcpy) (unsigned long, const unsigned long,
 		       size_t);
 extern int (*xp_cpu_to_nasid) (int);
+extern enum xp_retval (*xp_expand_memprotect) (unsigned long, unsigned long);
+extern enum xp_retval (*xp_restrict_memprotect) (unsigned long, unsigned long);
 
 extern u64 xp_nofault_PIOR_target;
 extern int xp_nofault_PIOR(void *);
diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c
index 66a1d19..9a2e771 100644
--- a/drivers/misc/sgi-xp/xp_main.c
+++ b/drivers/misc/sgi-xp/xp_main.c
@@ -51,6 +51,13 @@
 int (*xp_cpu_to_nasid) (int cpuid);
 EXPORT_SYMBOL_GPL(xp_cpu_to_nasid);
 
+enum xp_retval (*xp_expand_memprotect) (unsigned long phys_addr,
+					unsigned long size);
+EXPORT_SYMBOL_GPL(xp_expand_memprotect);
+enum xp_retval (*xp_restrict_memprotect) (unsigned long phys_addr,
+					  unsigned long size);
+EXPORT_SYMBOL_GPL(xp_restrict_memprotect);
+
 /*
  * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level
  * users of XPC.
diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c
index 1440134..fb3ec9d 100644
--- a/drivers/misc/sgi-xp/xp_sn2.c
+++ b/drivers/misc/sgi-xp/xp_sn2.c
@@ -120,6 +120,38 @@
 	return cpuid_to_nasid(cpuid);
 }
 
+static enum xp_retval
+xp_expand_memprotect_sn2(unsigned long phys_addr, unsigned long size)
+{
+	u64 nasid_array = 0;
+	int ret;
+
+	ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_1,
+				   &nasid_array);
+	if (ret != 0) {
+		dev_err(xp, "sn_change_memprotect(,, "
+			"SN_MEMPROT_ACCESS_CLASS_1,) failed ret=%d\n", ret);
+		return xpSalError;
+	}
+	return xpSuccess;
+}
+
+static enum xp_retval
+xp_restrict_memprotect_sn2(unsigned long phys_addr, unsigned long size)
+{
+	u64 nasid_array = 0;
+	int ret;
+
+	ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_0,
+				   &nasid_array);
+	if (ret != 0) {
+		dev_err(xp, "sn_change_memprotect(,, "
+			"SN_MEMPROT_ACCESS_CLASS_0,) failed ret=%d\n", ret);
+		return xpSalError;
+	}
+	return xpSuccess;
+}
+
 enum xp_retval
 xp_init_sn2(void)
 {
@@ -132,6 +164,8 @@
 	xp_pa = xp_pa_sn2;
 	xp_remote_memcpy = xp_remote_memcpy_sn2;
 	xp_cpu_to_nasid = xp_cpu_to_nasid_sn2;
+	xp_expand_memprotect = xp_expand_memprotect_sn2;
+	xp_restrict_memprotect = xp_restrict_memprotect_sn2;
 
 	return xp_register_nofault_code_sn2();
 }
diff --git a/drivers/misc/sgi-xp/xp_uv.c b/drivers/misc/sgi-xp/xp_uv.c
index d9f7ce2..d238576 100644
--- a/drivers/misc/sgi-xp/xp_uv.c
+++ b/drivers/misc/sgi-xp/xp_uv.c
@@ -15,6 +15,11 @@
 
 #include <linux/device.h>
 #include <asm/uv/uv_hub.h>
+#if defined CONFIG_X86_64
+#include <asm/uv/bios.h>
+#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#include <asm/sn/sn_sal.h>
+#endif
 #include "../sgi-gru/grukservices.h"
 #include "xp.h"
 
@@ -49,18 +54,79 @@
 	return UV_PNODE_TO_NASID(uv_cpu_to_pnode(cpuid));
 }
 
+static enum xp_retval
+xp_expand_memprotect_uv(unsigned long phys_addr, unsigned long size)
+{
+	int ret;
+
+#if defined CONFIG_X86_64
+	ret = uv_bios_change_memprotect(phys_addr, size, UV_MEMPROT_ALLOW_RW);
+	if (ret != BIOS_STATUS_SUCCESS) {
+		dev_err(xp, "uv_bios_change_memprotect(,, "
+			"UV_MEMPROT_ALLOW_RW) failed, ret=%d\n", ret);
+		return xpBiosError;
+	}
+
+#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+	u64 nasid_array;
+
+	ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_1,
+				   &nasid_array);
+	if (ret != 0) {
+		dev_err(xp, "sn_change_memprotect(,, "
+			"SN_MEMPROT_ACCESS_CLASS_1,) failed ret=%d\n", ret);
+		return xpSalError;
+	}
+#else
+	#error not a supported configuration
+#endif
+	return xpSuccess;
+}
+
+static enum xp_retval
+xp_restrict_memprotect_uv(unsigned long phys_addr, unsigned long size)
+{
+	int ret;
+
+#if defined CONFIG_X86_64
+	ret = uv_bios_change_memprotect(phys_addr, size,
+					UV_MEMPROT_RESTRICT_ACCESS);
+	if (ret != BIOS_STATUS_SUCCESS) {
+		dev_err(xp, "uv_bios_change_memprotect(,, "
+			"UV_MEMPROT_RESTRICT_ACCESS) failed, ret=%d\n", ret);
+		return xpBiosError;
+	}
+
+#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+	u64 nasid_array;
+
+	ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_0,
+				   &nasid_array);
+	if (ret != 0) {
+		dev_err(xp, "sn_change_memprotect(,, "
+			"SN_MEMPROT_ACCESS_CLASS_0,) failed ret=%d\n", ret);
+		return xpSalError;
+	}
+#else
+	#error not a supported configuration
+#endif
+	return xpSuccess;
+}
+
 enum xp_retval
 xp_init_uv(void)
 {
 	BUG_ON(!is_uv());
 
 	xp_max_npartitions = XP_MAX_NPARTITIONS_UV;
-	xp_partition_id = 0;	/* !!! not correct value */
-	xp_region_size = 0;	/* !!! not correct value */
+	xp_partition_id = sn_partition_id;
+	xp_region_size = sn_region_size;
 
 	xp_pa = xp_pa_uv;
 	xp_remote_memcpy = xp_remote_memcpy_uv;
 	xp_cpu_to_nasid = xp_cpu_to_nasid_uv;
+	xp_expand_memprotect = xp_expand_memprotect_uv;
+	xp_restrict_memprotect = xp_restrict_memprotect_uv;
 
 	return xpSuccess;
 }
diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h
index 619208d..a5bd658 100644
--- a/drivers/misc/sgi-xp/xpc.h
+++ b/drivers/misc/sgi-xp/xpc.h
@@ -181,6 +181,18 @@
 				  xpc_nasid_mask_nlongs))
 
 /*
+ * Info pertinent to a GRU message queue using a watch list for irq generation.
+ */
+struct xpc_gru_mq_uv {
+	void *address;		/* address of GRU message queue */
+	unsigned int order;	/* size of GRU message queue as a power of 2 */
+	int irq;		/* irq raised when message is received in mq */
+	int mmr_blade;		/* blade where watchlist was allocated from */
+	unsigned long mmr_offset; /* offset of irq mmr located on mmr_blade */
+	int watchlist_num;	/* number of watchlist allocatd by BIOS */
+};
+
+/*
  * The activate_mq is used to send/receive GRU messages that affect XPC's
  * heartbeat, partition active state, and channel state. This is UV only.
  */
diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c
index b4882cc..73b7fb8 100644
--- a/drivers/misc/sgi-xp/xpc_sn2.c
+++ b/drivers/misc/sgi-xp/xpc_sn2.c
@@ -553,22 +553,17 @@
 static enum xp_retval
 xpc_allow_amo_ops_sn2(struct amo *amos_page)
 {
-	u64 nasid_array = 0;
-	int ret;
+	enum xp_retval ret = xpSuccess;
 
 	/*
 	 * On SHUB 1.1, we cannot call sn_change_memprotect() since the BIST
 	 * collides with memory operations. On those systems we call
 	 * xpc_allow_amo_ops_shub_wars_1_1_sn2() instead.
 	 */
-	if (!enable_shub_wars_1_1()) {
-		ret = sn_change_memprotect(ia64_tpa((u64)amos_page), PAGE_SIZE,
-					   SN_MEMPROT_ACCESS_CLASS_1,
-					   &nasid_array);
-		if (ret != 0)
-			return xpSalError;
-	}
-	return xpSuccess;
+	if (!enable_shub_wars_1_1())
+		ret = xp_expand_memprotect(ia64_tpa((u64)amos_page), PAGE_SIZE);
+
+	return ret;
 }
 
 /*
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index 1ac694c..91a55b1 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -18,7 +18,15 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/err.h>
 #include <asm/uv/uv_hub.h>
+#if defined CONFIG_X86_64
+#include <asm/uv/bios.h>
+#include <asm/uv/uv_irq.h>
+#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#include <asm/sn/intr.h>
+#include <asm/sn/sn_sal.h>
+#endif
 #include "../sgi-gru/gru.h"
 #include "../sgi-gru/grukservices.h"
 #include "xpc.h"
@@ -27,15 +35,17 @@
 static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV);
 
 #define XPC_ACTIVATE_MSG_SIZE_UV	(1 * GRU_CACHE_LINE_BYTES)
+#define XPC_ACTIVATE_MQ_SIZE_UV		(4 * XP_MAX_NPARTITIONS_UV * \
+					 XPC_ACTIVATE_MSG_SIZE_UV)
+#define XPC_ACTIVATE_IRQ_NAME		"xpc_activate"
+
 #define XPC_NOTIFY_MSG_SIZE_UV		(2 * GRU_CACHE_LINE_BYTES)
+#define XPC_NOTIFY_MQ_SIZE_UV		(4 * XP_MAX_NPARTITIONS_UV * \
+					 XPC_NOTIFY_MSG_SIZE_UV)
+#define XPC_NOTIFY_IRQ_NAME		"xpc_notify"
 
-#define XPC_ACTIVATE_MQ_SIZE_UV	(4 * XP_MAX_NPARTITIONS_UV * \
-				 XPC_ACTIVATE_MSG_SIZE_UV)
-#define XPC_NOTIFY_MQ_SIZE_UV	(4 * XP_MAX_NPARTITIONS_UV * \
-				 XPC_NOTIFY_MSG_SIZE_UV)
-
-static void *xpc_activate_mq_uv;
-static void *xpc_notify_mq_uv;
+static struct xpc_gru_mq_uv *xpc_activate_mq_uv;
+static struct xpc_gru_mq_uv *xpc_notify_mq_uv;
 
 static int
 xpc_setup_partitions_sn_uv(void)
@@ -52,62 +62,209 @@
 	return 0;
 }
 
-static void *
-xpc_create_gru_mq_uv(unsigned int mq_size, int cpuid, unsigned int irq,
-		     irq_handler_t irq_handler)
+static int
+xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
 {
-	int ret;
-	int nid;
-	int mq_order;
-	struct page *page;
-	void *mq;
-
-	nid = cpu_to_node(cpuid);
-	mq_order = get_order(mq_size);
-	page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
-				mq_order);
-	if (page == NULL) {
-		dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
-			"bytes of memory on nid=%d for GRU mq\n", mq_size, nid);
-		return NULL;
+#if defined CONFIG_X86_64
+	mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset);
+	if (mq->irq < 0) {
+		dev_err(xpc_part, "uv_setup_irq() returned error=%d\n",
+			mq->irq);
 	}
 
-	mq = page_address(page);
-	ret = gru_create_message_queue(mq, mq_size);
-	if (ret != 0) {
-		dev_err(xpc_part, "gru_create_message_queue() returned "
-			"error=%d\n", ret);
-		free_pages((unsigned long)mq, mq_order);
-		return NULL;
-	}
+#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+	int mmr_pnode;
+	unsigned long mmr_value;
 
-	/* !!! Need to do some other things to set up IRQ */
+	if (strcmp(irq_name, XPC_ACTIVATE_IRQ_NAME) == 0)
+		mq->irq = SGI_XPC_ACTIVATE;
+	else if (strcmp(irq_name, XPC_NOTIFY_IRQ_NAME) == 0)
+		mq->irq = SGI_XPC_NOTIFY;
+	else
+		return -EINVAL;
 
-	ret = request_irq(irq, irq_handler, 0, "xpc", NULL);
-	if (ret != 0) {
-		dev_err(xpc_part, "request_irq(irq=%d) returned error=%d\n",
-			irq, ret);
-		free_pages((unsigned long)mq, mq_order);
-		return NULL;
-	}
+	mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
+	mmr_value = (unsigned long)cpu_physical_id(cpu) << 32 | mq->irq;
 
-	/* !!! enable generation of irq when GRU mq op occurs to this mq */
+	uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mmr_value);
+#else
+	#error not a supported configuration
+#endif
 
-	/* ??? allow other partitions to access GRU mq? */
-
-	return mq;
+	return 0;
 }
 
 static void
-xpc_destroy_gru_mq_uv(void *mq, unsigned int mq_size, unsigned int irq)
+xpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq)
 {
-	/* ??? disallow other partitions to access GRU mq? */
+#if defined CONFIG_X86_64
+	uv_teardown_irq(mq->irq, mq->mmr_blade, mq->mmr_offset);
 
-	/* !!! disable generation of irq when GRU mq op occurs to this mq */
+#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+	int mmr_pnode;
+	unsigned long mmr_value;
 
-	free_irq(irq, NULL);
+	mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
+	mmr_value = 1UL << 16;
 
-	free_pages((unsigned long)mq, get_order(mq_size));
+	uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mmr_value);
+#else
+	#error not a supported configuration
+#endif
+}
+
+static int
+xpc_gru_mq_watchlist_alloc_uv(struct xpc_gru_mq_uv *mq)
+{
+	int ret;
+
+#if defined CONFIG_X86_64
+	ret = uv_bios_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address),
+					 mq->order, &mq->mmr_offset);
+	if (ret < 0) {
+		dev_err(xpc_part, "uv_bios_mq_watchlist_alloc() failed, "
+			"ret=%d\n", ret);
+		return ret;
+	}
+#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+	ret = sn_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address),
+				    mq->order, &mq->mmr_offset);
+	if (ret < 0) {
+		dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n",
+			ret);
+		return -EBUSY;
+	}
+#else
+	#error not a supported configuration
+#endif
+
+	mq->watchlist_num = ret;
+	return 0;
+}
+
+static void
+xpc_gru_mq_watchlist_free_uv(struct xpc_gru_mq_uv *mq)
+{
+	int ret;
+
+#if defined CONFIG_X86_64
+	ret = uv_bios_mq_watchlist_free(mq->mmr_blade, mq->watchlist_num);
+	BUG_ON(ret != BIOS_STATUS_SUCCESS);
+#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+	ret = sn_mq_watchlist_free(mq->mmr_blade, mq->watchlist_num);
+	BUG_ON(ret != SALRET_OK);
+#else
+	#error not a supported configuration
+#endif
+}
+
+static struct xpc_gru_mq_uv *
+xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
+		     irq_handler_t irq_handler)
+{
+	enum xp_retval xp_ret;
+	int ret;
+	int nid;
+	int pg_order;
+	struct page *page;
+	struct xpc_gru_mq_uv *mq;
+
+	mq = kmalloc(sizeof(struct xpc_gru_mq_uv), GFP_KERNEL);
+	if (mq == NULL) {
+		dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to kmalloc() "
+			"a xpc_gru_mq_uv structure\n");
+		ret = -ENOMEM;
+		goto out_1;
+	}
+
+	pg_order = get_order(mq_size);
+	mq->order = pg_order + PAGE_SHIFT;
+	mq_size = 1UL << mq->order;
+
+	mq->mmr_blade = uv_cpu_to_blade_id(cpu);
+
+	nid = cpu_to_node(cpu);
+	page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+				pg_order);
+	if (page == NULL) {
+		dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
+			"bytes of memory on nid=%d for GRU mq\n", mq_size, nid);
+		ret = -ENOMEM;
+		goto out_2;
+	}
+	mq->address = page_address(page);
+
+	ret = gru_create_message_queue(mq->address, mq_size);
+	if (ret != 0) {
+		dev_err(xpc_part, "gru_create_message_queue() returned "
+			"error=%d\n", ret);
+		ret = -EINVAL;
+		goto out_3;
+	}
+
+	/* enable generation of irq when GRU mq operation occurs to this mq */
+	ret = xpc_gru_mq_watchlist_alloc_uv(mq);
+	if (ret != 0)
+		goto out_3;
+
+	ret = xpc_get_gru_mq_irq_uv(mq, cpu, irq_name);
+	if (ret != 0)
+		goto out_4;
+
+	ret = request_irq(mq->irq, irq_handler, 0, irq_name, NULL);
+	if (ret != 0) {
+		dev_err(xpc_part, "request_irq(irq=%d) returned error=%d\n",
+			mq->irq, ret);
+		goto out_5;
+	}
+
+	/* allow other partitions to access this GRU mq */
+	xp_ret = xp_expand_memprotect(xp_pa(mq->address), mq_size);
+	if (xp_ret != xpSuccess) {
+		ret = -EACCES;
+		goto out_6;
+	}
+
+	return mq;
+
+	/* something went wrong */
+out_6:
+	free_irq(mq->irq, NULL);
+out_5:
+	xpc_release_gru_mq_irq_uv(mq);
+out_4:
+	xpc_gru_mq_watchlist_free_uv(mq);
+out_3:
+	free_pages((unsigned long)mq->address, pg_order);
+out_2:
+	kfree(mq);
+out_1:
+	return ERR_PTR(ret);
+}
+
+static void
+xpc_destroy_gru_mq_uv(struct xpc_gru_mq_uv *mq)
+{
+	unsigned int mq_size;
+	int pg_order;
+	int ret;
+
+	/* disallow other partitions to access GRU mq */
+	mq_size = 1UL << mq->order;
+	ret = xp_restrict_memprotect(xp_pa(mq->address), mq_size);
+	BUG_ON(ret != xpSuccess);
+
+	/* unregister irq handler and release mq irq/vector mapping */
+	free_irq(mq->irq, NULL);
+	xpc_release_gru_mq_irq_uv(mq);
+
+	/* disable generation of irq when GRU mq op occurs to this mq */
+	xpc_gru_mq_watchlist_free_uv(mq);
+
+	pg_order = mq->order - PAGE_SHIFT;
+	free_pages((unsigned long)mq->address, pg_order);
+
+	kfree(mq);
 }
 
 static enum xp_retval
@@ -402,7 +559,10 @@
 	struct xpc_partition *part;
 	int wakeup_hb_checker = 0;
 
-	while ((msg_hdr = gru_get_next_message(xpc_activate_mq_uv)) != NULL) {
+	while (1) {
+		msg_hdr = gru_get_next_message(xpc_activate_mq_uv->address);
+		if (msg_hdr == NULL)
+			break;
 
 		partid = msg_hdr->partid;
 		if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) {
@@ -418,7 +578,7 @@
 			}
 		}
 
-		gru_free_message(xpc_activate_mq_uv, msg_hdr);
+		gru_free_message(xpc_activate_mq_uv->address, msg_hdr);
 	}
 
 	if (wakeup_hb_checker)
@@ -482,7 +642,7 @@
 	struct xpc_partition_uv *part_uv = &part->sn.uv;
 
 	/*
-	 * !!! Make our side think that the remote parition sent an activate
+	 * !!! Make our side think that the remote partition sent an activate
 	 * !!! message our way by doing what the activate IRQ handler would
 	 * !!! do had one really been sent.
 	 */
@@ -500,14 +660,39 @@
 xpc_get_partition_rsvd_page_pa_uv(void *buf, u64 *cookie, unsigned long *rp_pa,
 				  size_t *len)
 {
-	/* !!! call the UV version of sn_partition_reserved_page_pa() */
-	return xpUnsupported;
+	s64 status;
+	enum xp_retval ret;
+
+#if defined CONFIG_X86_64
+	status = uv_bios_reserved_page_pa((u64)buf, cookie, (u64 *)rp_pa,
+					  (u64 *)len);
+	if (status == BIOS_STATUS_SUCCESS)
+		ret = xpSuccess;
+	else if (status == BIOS_STATUS_MORE_PASSES)
+		ret = xpNeedMoreInfo;
+	else
+		ret = xpBiosError;
+
+#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+	status = sn_partition_reserved_page_pa((u64)buf, cookie, rp_pa, len);
+	if (status == SALRET_OK)
+		ret = xpSuccess;
+	else if (status == SALRET_MORE_PASSES)
+		ret = xpNeedMoreInfo;
+	else
+		ret = xpSalError;
+
+#else
+	#error not a supported configuration
+#endif
+
+	return ret;
 }
 
 static int
 xpc_setup_rsvd_page_sn_uv(struct xpc_rsvd_page *rp)
 {
-	rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq_uv);
+	rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq_uv->address);
 	return 0;
 }
 
@@ -1411,22 +1596,18 @@
 		return -E2BIG;
 	}
 
-	/* ??? The cpuid argument's value is 0, is that what we want? */
-	/* !!! The irq argument's value isn't correct. */
-	xpc_activate_mq_uv = xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, 0, 0,
+	xpc_activate_mq_uv = xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, 0,
+						  XPC_ACTIVATE_IRQ_NAME,
 						  xpc_handle_activate_IRQ_uv);
-	if (xpc_activate_mq_uv == NULL)
-		return -ENOMEM;
+	if (IS_ERR(xpc_activate_mq_uv))
+		return PTR_ERR(xpc_activate_mq_uv);
 
-	/* ??? The cpuid argument's value is 0, is that what we want? */
-	/* !!! The irq argument's value isn't correct. */
-	xpc_notify_mq_uv = xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, 0, 0,
+	xpc_notify_mq_uv = xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, 0,
+						XPC_NOTIFY_IRQ_NAME,
 						xpc_handle_notify_IRQ_uv);
-	if (xpc_notify_mq_uv == NULL) {
-		/* !!! The irq argument's value isn't correct. */
-		xpc_destroy_gru_mq_uv(xpc_activate_mq_uv,
-				      XPC_ACTIVATE_MQ_SIZE_UV, 0);
-		return -ENOMEM;
+	if (IS_ERR(xpc_notify_mq_uv)) {
+		xpc_destroy_gru_mq_uv(xpc_activate_mq_uv);
+		return PTR_ERR(xpc_notify_mq_uv);
 	}
 
 	return 0;
@@ -1435,9 +1616,6 @@
 void
 xpc_exit_uv(void)
 {
-	/* !!! The irq argument's value isn't correct. */
-	xpc_destroy_gru_mq_uv(xpc_notify_mq_uv, XPC_NOTIFY_MQ_SIZE_UV, 0);
-
-	/* !!! The irq argument's value isn't correct. */
-	xpc_destroy_gru_mq_uv(xpc_activate_mq_uv, XPC_ACTIVATE_MQ_SIZE_UV, 0);
+	xpc_destroy_gru_mq_uv(xpc_notify_mq_uv);
+	xpc_destroy_gru_mq_uv(xpc_activate_mq_uv);
 }
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c
index 71513b3a..8e6aa95 100644
--- a/drivers/misc/sgi-xp/xpnet.c
+++ b/drivers/misc/sgi-xp/xpnet.c
@@ -153,8 +153,7 @@
 	struct sk_buff *skb;
 	void *dst;
 	enum xp_retval ret;
-	struct xpnet_dev_private *priv =
-	    (struct xpnet_dev_private *)xpnet_device->priv;
+	struct xpnet_dev_private *priv = netdev_priv(xpnet_device);
 
 	if (!XPNET_VALID_MSG(msg)) {
 		/*
@@ -368,9 +367,7 @@
 static struct net_device_stats *
 xpnet_dev_get_stats(struct net_device *dev)
 {
-	struct xpnet_dev_private *priv;
-
-	priv = (struct xpnet_dev_private *)dev->priv;
+	struct xpnet_dev_private *priv = netdev_priv(dev);
 
 	return &priv->stats;
 }
@@ -456,7 +453,7 @@
 	struct xpnet_pending_msg *queued_msg;
 	u64 start_addr, end_addr;
 	short dest_partid;
-	struct xpnet_dev_private *priv = (struct xpnet_dev_private *)dev->priv;
+	struct xpnet_dev_private *priv = netdev_priv(dev);
 	u16 embedded_bytes = 0;
 
 	dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p "
@@ -541,9 +538,7 @@
 static void
 xpnet_dev_tx_timeout(struct net_device *dev)
 {
-	struct xpnet_dev_private *priv;
-
-	priv = (struct xpnet_dev_private *)dev->priv;
+	struct xpnet_dev_private *priv = netdev_priv(dev);
 
 	priv->stats.tx_errors++;
 	return;
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 7d15e7c..3d1318a 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -297,8 +297,8 @@
 	if (el_debug)
 		printk(KERN_DEBUG "%s", version);
 
-	memset(dev->priv, 0, sizeof(struct net_local));
 	lp = netdev_priv(dev);
+	memset(lp, 0, sizeof(struct net_local));
 	spin_lock_init(&lp->lock);
 
 	/*
@@ -725,7 +725,6 @@
 		insb(DATAPORT, skb_put(skb, pkt_len), pkt_len);
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
-		dev->last_rx = jiffies;
 		dev->stats.rx_packets++;
 		dev->stats.rx_bytes += pkt_len;
 	}
diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h
index cfec64e..f40b049 100644
--- a/drivers/net/3c501.h
+++ b/drivers/net/3c501.h
@@ -23,7 +23,7 @@
 static int el_debug = EL_DEBUG;
 
 /*
- *	Board-specific info in dev->priv.
+ *	Board-specific info in netdev_priv(dev).
  */
 
 struct net_local
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 900b0ff..c092c39 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -168,6 +168,21 @@
 }
 #endif
 
+static const struct net_device_ops el2_netdev_ops = {
+	.ndo_open		= el2_open,
+	.ndo_stop		= el2_close,
+
+	.ndo_start_xmit		= eip_start_xmit,
+	.ndo_tx_timeout		= eip_tx_timeout,
+	.ndo_get_stats		= eip_get_stats,
+	.ndo_set_multicast_list = eip_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller 	= eip_poll,
+#endif
+};
+
 /* Probe for the Etherlink II card at I/O port base IOADDR,
    returning non-zero on success.  If found, set the station
    address and memory parameters in DEVICE. */
@@ -177,7 +192,6 @@
     int i, iobase_reg, membase_reg, saved_406, wordlength, retval;
     static unsigned version_printed;
     unsigned long vendor_id;
-    DECLARE_MAC_BUF(mac);
 
     if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME))
 	return -EBUSY;
@@ -228,7 +242,7 @@
     /* Retrieve and print the ethernet address. */
     for (i = 0; i < 6; i++)
 	dev->dev_addr[i] = inb(ioaddr + i);
-    printk("%s", print_mac(mac, dev->dev_addr));
+    printk("%pM", dev->dev_addr);
 
     /* Map the 8390 back into the window. */
     outb(ECNTRL_THIN, ioaddr + 0x406);
@@ -336,8 +350,7 @@
 
     ei_status.saved_irq = dev->irq;
 
-    dev->open = &el2_open;
-    dev->stop = &el2_close;
+    dev->netdev_ops = &el2_netdev_ops;
     dev->ethtool_ops = &netdev_ethtool_ops;
 #ifdef CONFIG_NET_POLL_CONTROLLER
     dev->poll_controller = eip_poll;
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index a424869..6124605 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -203,10 +203,10 @@
 static inline void outb_control(unsigned char val, struct net_device *dev)
 {
 	outb(val, dev->base_addr + PORT_CONTROL);
-	((elp_device *)(dev->priv))->hcr_val = val;
+	((elp_device *)(netdev_priv(dev)))->hcr_val = val;
 }
 
-#define HCR_VAL(x)   (((elp_device *)((x)->priv))->hcr_val)
+#define HCR_VAL(x)   (((elp_device *)(netdev_priv(x)))->hcr_val)
 
 static inline void outb_command(unsigned char val, unsigned int base_addr)
 {
@@ -247,7 +247,7 @@
 
 static inline void set_hsf(struct net_device *dev, int hsf)
 {
-	elp_device *adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&adapter->lock, flags);
@@ -260,7 +260,7 @@
 static inline void adapter_reset(struct net_device *dev)
 {
 	unsigned long timeout;
-	elp_device *adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 	unsigned char orig_hcr = adapter->hcr_val;
 
 	outb_control(0, dev);
@@ -293,7 +293,7 @@
  */
 static inline void check_3c505_dma(struct net_device *dev)
 {
-	elp_device *adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 	if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) {
 		unsigned long flags, f;
 		printk(KERN_ERR "%s: DMA %s timed out, %d bytes left\n", dev->name, adapter->current_dma.direction ? "download" : "upload", get_dma_residue(dev->dma));
@@ -340,7 +340,7 @@
 /* Check to see if the receiver needs restarting, and kick it if so */
 static inline void prime_rx(struct net_device *dev)
 {
-	elp_device *adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 	while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) {
 		if (!start_receive(dev, &adapter->itx_pcb))
 			break;
@@ -375,7 +375,7 @@
 {
 	int i;
 	unsigned long timeout;
-	elp_device *adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 	unsigned long flags;
 
 	check_3c505_dma(dev);
@@ -463,7 +463,7 @@
 	unsigned long timeout;
 	unsigned long flags;
 
-	elp_device *adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 
 	set_hsf(dev, 0);
 
@@ -543,7 +543,7 @@
 static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
 {
 	bool status;
-	elp_device *adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 
 	if (elp_debug >= 3)
 		printk(KERN_DEBUG "%s: restarting receiver\n", dev->name);
@@ -571,7 +571,7 @@
 static void receive_packet(struct net_device *dev, int len)
 {
 	int rlen;
-	elp_device *adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 	void *target;
 	struct sk_buff *skb;
 	unsigned long flags;
@@ -638,13 +638,10 @@
 	int len;
 	int dlen;
 	int icount = 0;
-	struct net_device *dev;
-	elp_device *adapter;
+	struct net_device *dev = dev_id;
+	elp_device *adapter = netdev_priv(dev);
 	unsigned long timeout;
 
-	dev = dev_id;
-	adapter = (elp_device *) dev->priv;
-
 	spin_lock(&adapter->lock);
 
 	do {
@@ -672,7 +669,6 @@
 					skb->protocol = eth_type_trans(skb,dev);
 					dev->stats.rx_bytes += skb->len;
 					netif_rx(skb);
-					dev->last_rx = jiffies;
 				}
 			}
 			adapter->dmaing = 0;
@@ -838,11 +834,9 @@
 
 static int elp_open(struct net_device *dev)
 {
-	elp_device *adapter;
+	elp_device *adapter = netdev_priv(dev);
 	int retval;
 
-	adapter = dev->priv;
-
 	if (elp_debug >= 3)
 		printk(KERN_DEBUG "%s: request to open device\n", dev->name);
 
@@ -971,7 +965,7 @@
 
 static bool send_packet(struct net_device *dev, struct sk_buff *skb)
 {
-	elp_device *adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 	unsigned long target;
 	unsigned long flags;
 
@@ -1062,7 +1056,7 @@
 static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	unsigned long flags;
-	elp_device *adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 
 	spin_lock_irqsave(&adapter->lock, flags);
 	check_3c505_dma(dev);
@@ -1104,7 +1098,7 @@
 
 static struct net_device_stats *elp_get_stats(struct net_device *dev)
 {
-	elp_device *adapter = (elp_device *) dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 
 	if (elp_debug >= 3)
 		printk(KERN_DEBUG "%s: request for stats\n", dev->name);
@@ -1166,9 +1160,7 @@
 
 static int elp_close(struct net_device *dev)
 {
-	elp_device *adapter;
-
-	adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 
 	if (elp_debug >= 3)
 		printk(KERN_DEBUG "%s: request to close device\n", dev->name);
@@ -1209,7 +1201,7 @@
 
 static void elp_set_mc_list(struct net_device *dev)
 {
-	elp_device *adapter = (elp_device *) dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 	struct dev_mc_list *dmi = dev->mc_list;
 	int i;
 	unsigned long flags;
@@ -1380,12 +1372,11 @@
 
 static int __init elplus_setup(struct net_device *dev)
 {
-	elp_device *adapter = dev->priv;
+	elp_device *adapter = netdev_priv(dev);
 	int i, tries, tries1, okay;
 	unsigned long timeout;
 	unsigned long cookie = 0;
 	int err = -ENODEV;
-	DECLARE_MAC_BUF(mac);
 
 	/*
 	 *  setup adapter structure
@@ -1522,9 +1513,9 @@
 	 * print remainder of startup message
 	 */
 	printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, "
-	       "addr %s, ",
+	       "addr %pM, ",
 	       dev->name, dev->base_addr, dev->irq, dev->dma,
-	       print_mac(mac, dev->dev_addr));
+	       dev->dev_addr);
 
 	/*
 	 * read more information from the adapter
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 030c147..423e65d 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -357,7 +357,6 @@
 	static unsigned char init_ID_done, version_printed;
 	int i, irq, irqval, retval;
 	struct net_local *lp;
-	DECLARE_MAC_BUF(mac);
 
 	if (init_ID_done == 0) {
 		ushort lrs_state = 0xff;
@@ -405,7 +404,7 @@
 	outb(0x01, ioaddr + MISC_CTRL);
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(ioaddr + i);
-	printk(" %s", print_mac(mac, dev->dev_addr));
+	printk(" %pM", dev->dev_addr);
 
 	if (mem_start)
 		net_debug = mem_start & 7;
@@ -866,7 +865,6 @@
 
 			skb->protocol=eth_type_trans(skb,dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += pkt_len;
 		}
@@ -938,14 +936,3 @@
 }
 #endif /* MODULE */
 MODULE_LICENSE("GPL");
-
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c 3c507.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  tab-width: 4
- *  c-indent-level: 4
- * End:
- */
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index c7a4f3b..535c234 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -541,7 +541,6 @@
 {
 	struct el3_private *lp = netdev_priv(dev);
 	int err;
-	DECLARE_MAC_BUF(mac);
 	const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
 
 	spin_lock_init(&lp->lock);
@@ -575,9 +574,9 @@
 	}
 
 	printk(KERN_INFO "%s: 3c5x9 found at %#3.3lx, %s port, "
-	       "address %s, IRQ %d.\n",
+	       "address %pM, IRQ %d.\n",
 	       dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)],
-	       print_mac(mac, dev->dev_addr), dev->irq);
+	       dev->dev_addr, dev->irq);
 
 	if (el3_debug > 0)
 		printk(KERN_INFO "%s", version);
@@ -1075,7 +1074,6 @@
 				outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
 				skb->protocol = eth_type_trans(skb,dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				dev->stats.rx_bytes += pkt_len;
 				dev->stats.rx_packets++;
 				continue;
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index a0f8b6e..39ac122 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -570,7 +570,6 @@
 	unsigned int eeprom[0x40], checksum = 0;	/* EEPROM contents */
 	int i;
 	int irq;
-	DECLARE_MAC_BUF(mac);
 
 #ifdef __ISAPNP__
 	if (idev) {
@@ -636,7 +635,7 @@
 	checksum = (checksum ^ (checksum >> 8)) & 0xff;
 	if (checksum != 0x00)
 		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
-	printk(" %s", print_mac(mac, dev->dev_addr));
+	printk(" %pM", dev->dev_addr);
 	if (eeprom[16] == 0x11c7) {	/* Corkscrew */
 		if (request_dma(dev->dma, "3c515")) {
 			printk(", DMA %d allocation failed", dev->dma);
@@ -1302,7 +1301,6 @@
 				outw(RxDiscard, ioaddr + EL3_CMD);	/* Pop top Rx packet. */
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += pkt_len;
 				/* Wait a limited time to go to next packet. */
@@ -1389,7 +1387,6 @@
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 		}
 		entry = (++vp->cur_rx) % RX_RING_SIZE;
@@ -1580,11 +1577,3 @@
 	}
 }
 #endif				/* MODULE */
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c515.c"
- *  c-indent-level: 4
- *  tab-width: 4
- * End:
- */
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index e2ce41d..ff41e1f 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -308,7 +308,7 @@
 
 static int __init check586(struct net_device *dev, unsigned long where, unsigned size)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 	char *iscp_addrs[2];
 	int i = 0;
 
@@ -347,9 +347,9 @@
  * set iscp at the right place, called by elmc_probe and open586.
  */
 
-void alloc586(struct net_device *dev)
+static void alloc586(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	elmc_id_reset586();
 	DELAY(2);
@@ -383,7 +383,6 @@
 {
 	int len = 0;
 	struct net_device *dev = d;
-	DECLARE_MAC_BUF(mac);
 
 	if (dev == NULL)
 		return len;
@@ -398,8 +397,8 @@
 	len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ?
 		       "External" : "Internal");
 	len += sprintf(buf + len, "Device: %s\n", dev->name);
-	len += sprintf(buf + len, "Hardware Address: %s\n",
-		       print_mac(mac, dev->dev_addr));
+	len += sprintf(buf + len, "Hardware Address: %pM\n",
+		       dev->dev_addr);
 
 	return len;
 }				/* elmc_getinfo() */
@@ -416,8 +415,7 @@
 	int i = 0;
 	unsigned int size = 0;
 	int retval;
-	struct priv *pr = dev->priv;
-	DECLARE_MAC_BUF(mac);
+	struct priv *pr = netdev_priv(dev);
 
 	if (MCA_bus == 0) {
 		return -ENODEV;
@@ -543,8 +541,8 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(dev->base_addr + i);
 
-	printk(KERN_INFO "%s: hardware address %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: hardware address %pM\n",
+	       dev->name, dev->dev_addr);
 
 	dev->open = &elmc_open;
 	dev->stop = &elmc_close;
@@ -578,13 +576,14 @@
 	return retval;
 }
 
+#ifdef MODULE
 static void cleanup_card(struct net_device *dev)
 {
-	mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL);
+	mca_set_adapter_procfn(((struct priv *)netdev_priv(dev))->slot,
+				NULL, NULL);
 	release_region(dev->base_addr, ELMC_IO_EXTENT);
 }
-
-#ifndef MODULE
+#else
 struct net_device * __init elmc_probe(int unit)
 {
 	struct net_device *dev = alloc_etherdev(sizeof(struct priv));
@@ -616,7 +615,7 @@
 	void *ptr;
 	unsigned long s;
 	int i, result = 0;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 	volatile struct configure_cmd_struct *cfg_cmd;
 	volatile struct iasetup_cmd_struct *ias_cmd;
 	volatile struct tdr_cmd_struct *tdr_cmd;
@@ -852,7 +851,7 @@
 	volatile struct rfd_struct *rfd = (struct rfd_struct *) ptr;
 	volatile struct rbd_struct *rbd;
 	int i;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	memset((char *) rfd, 0, sizeof(struct rfd_struct) * p->num_recv_buffs);
 	p->rfd_first = rfd;
@@ -913,7 +912,7 @@
 	}
 	/* reading ELMC_CTRL also clears the INT bit. */
 
-	p = (struct priv *) dev->priv;
+	p = netdev_priv(dev);
 
 	while ((stat = p->scb->status & STAT_MASK))
 	{
@@ -969,7 +968,7 @@
 	unsigned short totlen;
 	struct sk_buff *skb;
 	struct rbd_struct *rbd;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	for (; (status = p->rfd_top->status) & STAT_COMPL;) {
 		rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
@@ -985,7 +984,6 @@
 					skb_copy_to_linear_data(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen);
 					skb->protocol = eth_type_trans(skb, dev);
 					netif_rx(skb);
-					dev->last_rx = jiffies;
 					dev->stats.rx_packets++;
 					dev->stats.rx_bytes += totlen;
 				} else {
@@ -1013,7 +1011,7 @@
 
 static void elmc_rnr_int(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	dev->stats.rx_errors++;
 
@@ -1036,7 +1034,7 @@
 static void elmc_xmt_int(struct net_device *dev)
 {
 	int status;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	status = p->xmit_cmds[p->xmit_last]->cmd_status;
 	if (!(status & STAT_COMPL)) {
@@ -1079,7 +1077,7 @@
 
 static void startrecv586(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	p->scb->rfa_offset = make16(p->rfd_first);
 	p->scb->cmd = RUC_START;
@@ -1093,7 +1091,7 @@
 
 static void elmc_timeout(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 	/* COMMAND-UNIT active? */
 	if (p->scb->status & CU_ACTIVE) {
 #ifdef DEBUG
@@ -1129,7 +1127,7 @@
 #ifndef NO_NOPCOMMANDS
 	int next_nop;
 #endif
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 
@@ -1200,7 +1198,7 @@
 
 static struct net_device_stats *elmc_get_stats(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 	unsigned short crc, aln, rsc, ovrn;
 
 	crc = p->scb->crc_errs;	/* get error-statistic from the ni82586 */
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index abc84f7..2df3af3 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -335,7 +335,6 @@
 		"82586 initialisation failure",
 		"Adapter list configuration error"
 	};
-	DECLARE_MAC_BUF(mac);
 
 	/* Time to play MCA games */
 
@@ -405,7 +404,7 @@
 		dev->dev_addr[i] = mca_read_pos(slot,3);
 	}
 
-	printk("%s: Address %s", dev->name, print_mac(mac, dev->dev_addr));
+	printk("%s: Address %pM", dev->name, dev->dev_addr);
 
 	mca_write_pos(slot, 6, 0);
 	mca_write_pos(slot, 7, 0);
@@ -1187,7 +1186,6 @@
 			}
 
 			skb->protocol=eth_type_trans(skb,dev);
-			dev->last_rx = jiffies;
  			dev->stats.rx_packets++;
  			dev->stats.rx_bytes += length;
 			netif_rx(skb);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 9ba295d..665e7fd 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -803,7 +803,7 @@
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
-	if (dev && dev->priv) {
+	if (dev && netdev_priv(dev)) {
 		if (netif_running(dev)) {
 			netif_device_detach(dev);
 			vortex_down(dev, 1);
@@ -1013,7 +1013,6 @@
 	const char *print_name = "3c59x";
 	struct pci_dev *pdev = NULL;
 	struct eisa_device *edev = NULL;
-	DECLARE_MAC_BUF(mac);
 
 	if (!printed_version) {
 		printk (version);
@@ -1026,7 +1025,7 @@
 		}
 
 		if ((edev = DEVICE_EISA(gendev))) {
-			print_name = edev->dev.bus_id;
+			print_name = dev_name(&edev->dev);
 		}
 	}
 
@@ -1206,7 +1205,7 @@
 		((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 	if (print_info)
-		printk(" %s", print_mac(mac, dev->dev_addr));
+		printk(" %pM", dev->dev_addr);
 	/* Unfortunately an all zero eeprom passes the checksum and this
 	   gets found in the wild in failure cases. Crypto is hard 8) */
 	if (!is_valid_ether_addr(dev->dev_addr)) {
@@ -2447,7 +2446,6 @@
 				iowrite16(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				/* Wait a limited time to go to next packet. */
 				for (i = 200; i >= 0; i--)
@@ -2530,7 +2528,6 @@
 				}
 			}
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 		}
 		entry = (++vp->cur_rx) % RX_RING_SIZE;
@@ -2886,7 +2883,7 @@
 		strcpy(info->bus_info, pci_name(VORTEX_PCI(vp)));
 	} else {
 		if (VORTEX_EISA(vp))
-			sprintf(info->bus_info, vp->gendev->bus_id);
+			sprintf(info->bus_info, dev_name(vp->gendev));
 		else
 			sprintf(info->bus_info, "EISA 0x%lx %d",
 					dev->base_addr, dev->irq);
@@ -3217,7 +3214,7 @@
 #endif
 
 	if (compaq_net_device) {
-		vp = compaq_net_device->priv;
+		vp = netdev_priv(compaq_net_device);
 		ioaddr = ioport_map(compaq_net_device->base_addr,
 		                    VORTEX_TOTAL_SIZE);
 
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index ad6b8a5..7a331ac 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -336,7 +336,6 @@
                                          len);
                         skb->protocol = eth_type_trans (skb, dev);
 			netif_rx (skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += len;
                 }
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 9ba1f0b..dd7ac82 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -457,7 +457,6 @@
 
 	cp->dev->stats.rx_packets++;
 	cp->dev->stats.rx_bytes += skb->len;
-	cp->dev->last_rx = jiffies;
 
 #if CP_VLAN_TAG_USED
 	if (cp->vlgrp && (desc->opts2 & cpu_to_le32(RxVlanTagged))) {
@@ -605,7 +604,7 @@
 
 		spin_lock_irqsave(&cp->lock, flags);
 		cpw16_f(IntrMask, cp_intr_mask);
-		__netif_rx_complete(dev, napi);
+		__netif_rx_complete(napi);
 		spin_unlock_irqrestore(&cp->lock, flags);
 	}
 
@@ -642,9 +641,9 @@
 	}
 
 	if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
-		if (netif_rx_schedule_prep(dev, &cp->napi)) {
+		if (netif_rx_schedule_prep(&cp->napi)) {
 			cpw16_f(IntrMask, cp_norx_intr_mask);
-			__netif_rx_schedule(dev, &cp->napi);
+			__netif_rx_schedule(&cp->napi);
 		}
 
 	if (status & (TxOK | TxErr | TxEmpty | SWInt))
@@ -1818,6 +1817,26 @@
 	pci_set_power_state (cp->pdev, PCI_D3hot);
 }
 
+static const struct net_device_ops cp_netdev_ops = {
+	.ndo_open		= cp_open,
+	.ndo_stop		= cp_close,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_multicast_list	= cp_set_rx_mode,
+	.ndo_get_stats		= cp_get_stats,
+	.ndo_do_ioctl		= cp_ioctl,
+	.ndo_start_xmit		= cp_start_xmit,
+	.ndo_tx_timeout		= cp_tx_timeout,
+#if CP_VLAN_TAG_USED
+	.ndo_vlan_rx_register	= cp_vlan_rx_register,
+#endif
+#ifdef BROKEN
+	.ndo_change_mtu		= cp_change_mtu,
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= cp_poll_controller,
+#endif
+};
+
 static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct net_device *dev;
@@ -1826,7 +1845,6 @@
 	void __iomem *regs;
 	resource_size_t pciaddr;
 	unsigned int addr_len, i, pci_using_dac;
-	DECLARE_MAC_BUF(mac);
 
 #ifndef MODULE
 	static int version_printed;
@@ -1931,26 +1949,13 @@
 		    cpu_to_le16(read_eeprom (regs, i + 7, addr_len));
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
-	dev->open = cp_open;
-	dev->stop = cp_close;
-	dev->set_multicast_list = cp_set_rx_mode;
-	dev->hard_start_xmit = cp_start_xmit;
-	dev->get_stats = cp_get_stats;
-	dev->do_ioctl = cp_ioctl;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = cp_poll_controller;
-#endif
+	dev->netdev_ops = &cp_netdev_ops;
 	netif_napi_add(dev, &cp->napi, cp_rx_poll, 16);
-#ifdef BROKEN
-	dev->change_mtu = cp_change_mtu;
-#endif
 	dev->ethtool_ops = &cp_ethtool_ops;
-	dev->tx_timeout = cp_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
 #if CP_VLAN_TAG_USED
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-	dev->vlan_rx_register = cp_vlan_rx_register;
 #endif
 
 	if (pci_using_dac)
@@ -1967,10 +1972,10 @@
 		goto err_out_iomap;
 
 	printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, "
-		"%s, IRQ %d\n",
+		"%pM, IRQ %d\n",
 		dev->name,
 		dev->base_addr,
-		print_mac(mac, dev->dev_addr),
+		dev->dev_addr,
 		dev->irq);
 
 	pci_set_drvdata(pdev, dev);
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 63f906b..fe370f8 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -741,8 +741,7 @@
 }
 
 
-static int __devinit rtl8139_init_board (struct pci_dev *pdev,
-					 struct net_device **dev_out)
+static __devinit struct net_device * rtl8139_init_board (struct pci_dev *pdev)
 {
 	void __iomem *ioaddr;
 	struct net_device *dev;
@@ -756,13 +755,11 @@
 
 	assert (pdev != NULL);
 
-	*dev_out = NULL;
-
 	/* dev and priv zeroed in alloc_etherdev */
 	dev = alloc_etherdev (sizeof (*tp));
 	if (dev == NULL) {
 		dev_err(&pdev->dev, "Unable to alloc new net device\n");
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	}
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -906,16 +903,29 @@
 
 	rtl8139_chip_reset (ioaddr);
 
-	*dev_out = dev;
-	return 0;
+	return dev;
 
 err_out:
 	__rtl8139_cleanup_dev (dev);
 	if (disable_dev_on_err)
 		pci_disable_device (pdev);
-	return rc;
+	return ERR_PTR(rc);
 }
 
+static const struct net_device_ops rtl8139_netdev_ops = {
+	.ndo_open		= rtl8139_open,
+	.ndo_stop		= rtl8139_close,
+	.ndo_get_stats		= rtl8139_get_stats,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_start_xmit		= rtl8139_start_xmit,
+	.ndo_set_multicast_list	= rtl8139_set_rx_mode,
+	.ndo_do_ioctl		= netdev_ioctl,
+	.ndo_tx_timeout		= rtl8139_tx_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= rtl8139_poll_controller,
+#endif
+
+};
 
 static int __devinit rtl8139_init_one (struct pci_dev *pdev,
 				       const struct pci_device_id *ent)
@@ -925,7 +935,6 @@
 	int i, addr_len, option;
 	void __iomem *ioaddr;
 	static int board_idx = -1;
-	DECLARE_MAC_BUF(mac);
 
 	assert (pdev != NULL);
 	assert (ent != NULL);
@@ -959,9 +968,9 @@
 		use_io = 1;
 	}
 
-	i = rtl8139_init_board (pdev, &dev);
-	if (i < 0)
-		return i;
+	dev = rtl8139_init_board (pdev);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
 
 	assert (dev != NULL);
 	tp = netdev_priv(dev);
@@ -977,19 +986,10 @@
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	/* The Rtl8139-specific entries in the device structure. */
-	dev->open = rtl8139_open;
-	dev->hard_start_xmit = rtl8139_start_xmit;
-	netif_napi_add(dev, &tp->napi, rtl8139_poll, 64);
-	dev->stop = rtl8139_close;
-	dev->get_stats = rtl8139_get_stats;
-	dev->set_multicast_list = rtl8139_set_rx_mode;
-	dev->do_ioctl = netdev_ioctl;
+	dev->netdev_ops = &rtl8139_netdev_ops;
 	dev->ethtool_ops = &rtl8139_ethtool_ops;
-	dev->tx_timeout = rtl8139_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = rtl8139_poll_controller;
-#endif
+	netif_napi_add(dev, &tp->napi, rtl8139_poll, 64);
 
 	/* note: the hardware is not capable of sg/csum/highdma, however
 	 * through the use of skb_copy_and_csum_dev we enable these
@@ -1024,11 +1024,11 @@
 	pci_set_drvdata (pdev, dev);
 
 	printk (KERN_INFO "%s: %s at 0x%lx, "
-		"%s, IRQ %d\n",
+		"%pM, IRQ %d\n",
 		dev->name,
 		board_info[ent->driver_data].name,
 		dev->base_addr,
-		print_mac(mac, dev->dev_addr),
+		dev->dev_addr,
 		dev->irq);
 
 	printk (KERN_DEBUG "%s:  Identified 8139 chip type '%s'\n",
@@ -2026,7 +2026,6 @@
 
 			skb->protocol = eth_type_trans (skb, dev);
 
-			dev->last_rx = jiffies;
 			dev->stats.rx_bytes += pkt_size;
 			dev->stats.rx_packets++;
 
@@ -2129,7 +2128,7 @@
 		 */
 		spin_lock_irqsave(&tp->lock, flags);
 		RTL_W16_F(IntrMask, rtl8139_intr_mask);
-		__netif_rx_complete(dev, napi);
+		__netif_rx_complete(napi);
 		spin_unlock_irqrestore(&tp->lock, flags);
 	}
 	spin_unlock(&tp->rx_lock);
@@ -2179,9 +2178,9 @@
 	/* Receive packets are processed by poll routine.
 	   If not running start it now. */
 	if (status & RxAckBits){
-		if (netif_rx_schedule_prep(dev, &tp->napi)) {
+		if (netif_rx_schedule_prep(&tp->napi)) {
 			RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
-			__netif_rx_schedule(dev, &tp->napi);
+			__netif_rx_schedule(&tp->napi);
 		}
 	}
 
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index da292e6..b273596 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -457,7 +457,7 @@
 
 static void i596_display_data(struct net_device *dev)
 {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = dev->ml_priv;
 	struct i596_cmd *cmd;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
@@ -527,7 +527,7 @@
 
 static inline void init_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = dev->ml_priv;
 	int i;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
@@ -578,7 +578,7 @@
 
 static inline void remove_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = dev->ml_priv;
 	struct i596_rbd *rbd;
 	int i;
 
@@ -592,7 +592,7 @@
 
 static void rebuild_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = dev->ml_priv;
 	int i;
 
 	/* Ensure rx frame/buffer descriptors are tidy */
@@ -611,7 +611,7 @@
 
 static int init_i596_mem(struct net_device *dev)
 {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = dev->ml_priv;
 #if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT)
 	short ioaddr = dev->base_addr;
 #endif
@@ -764,7 +764,7 @@
 
 static inline int i596_rx(struct net_device *dev)
 {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = dev->ml_priv;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
 	int frames = 0;
@@ -841,7 +841,6 @@
 						pkt_len);
 #endif
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes+=pkt_len;
 			}
@@ -959,7 +958,7 @@
 
 static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
 {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = dev->ml_priv;
 	int ioaddr = dev->base_addr;
 	unsigned long flags;
 
@@ -1029,7 +1028,7 @@
 
 static void i596_tx_timeout (struct net_device *dev)
 {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = dev->ml_priv;
 	int ioaddr = dev->base_addr;
 
 	/* Transmitter timeout, serious problems. */
@@ -1058,7 +1057,7 @@
 
 static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = dev->ml_priv;
 	struct tx_cmd *tx_cmd;
 	struct i596_tbd *tbd;
 	short length = skb->len;
@@ -1116,12 +1115,8 @@
 
 static void print_eth(unsigned char *add, char *str)
 {
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
-
-	printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n",
-	       add, print_mac(mac, add + 6), print_mac(mac2, add),
-	       add[12], add[13], str);
+	printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n",
+	       add, add + 6, add, add[12], add[13], str);
 }
 
 static int io = 0x300;
@@ -1244,9 +1239,9 @@
 	dev->tx_timeout = i596_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
-	dev->priv = (void *)(dev->mem_start);
+	dev->ml_priv = (void *)(dev->mem_start);
 
-	lp = dev->priv;
+	lp = dev->ml_priv;
 	DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%zd bytes), "
 			"lp->scb at 0x%08lx\n",
 			dev->name, (unsigned long)lp,
@@ -1307,7 +1302,7 @@
 	}
 
 	ioaddr = dev->base_addr;
-	lp = dev->priv;
+	lp = dev->ml_priv;
 
 	spin_lock (&lp->lock);
 
@@ -1450,7 +1445,7 @@
 
 static int i596_close(struct net_device *dev)
 {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = dev->ml_priv;
 	unsigned long flags;
 
 	netif_stop_queue(dev);
@@ -1500,7 +1495,7 @@
 
 static void set_multicast_list(struct net_device *dev)
 {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = dev->ml_priv;
 	int config = 0, cnt;
 
 	DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
@@ -1544,7 +1539,6 @@
 		struct dev_mc_list *dmi;
 		unsigned char *cp;
 		struct mc_cmd *cmd;
-		DECLARE_MAC_BUF(mac);
 
 		if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out"))
 			return;
@@ -1555,8 +1549,8 @@
 		for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {
 			memcpy(cp, dmi->dmi_addr, 6);
 			if (i596_debug > 1)
-				DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %s\n",
-						dev->name, print_mac(mac, cp)));
+				DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %pM\n",
+						dev->name, cp));
 		}
 		i596_add_cmd(dev, &cmd->cmd);
 	}
@@ -1604,9 +1598,3 @@
 }
 
 #endif				/* MODULE */
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 82596.c"
- * End:
- */
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index f72a2e8..fbe609a 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -17,6 +17,30 @@
 }
 EXPORT_SYMBOL(ei_close);
 
+int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	return __ei_start_xmit(skb, dev);
+}
+EXPORT_SYMBOL(ei_start_xmit);
+
+struct net_device_stats *ei_get_stats(struct net_device *dev)
+{
+	return __ei_get_stats(dev);
+}
+EXPORT_SYMBOL(ei_get_stats);
+
+void ei_set_multicast_list(struct net_device *dev)
+{
+	__ei_set_multicast_list(dev);
+}
+EXPORT_SYMBOL(ei_set_multicast_list);
+
+void ei_tx_timeout(struct net_device *dev)
+{
+	__ei_tx_timeout(dev);
+}
+EXPORT_SYMBOL(ei_tx_timeout);
+
 irqreturn_t ei_interrupt(int irq, void *dev_id)
 {
 	return __ei_interrupt(irq, dev_id);
@@ -31,9 +55,33 @@
 EXPORT_SYMBOL(ei_poll);
 #endif
 
+const struct net_device_ops ei_netdev_ops = {
+	.ndo_open		= ei_open,
+	.ndo_stop		= ei_close,
+	.ndo_start_xmit		= ei_start_xmit,
+	.ndo_tx_timeout		= ei_tx_timeout,
+	.ndo_get_stats		= ei_get_stats,
+	.ndo_set_multicast_list = ei_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= ei_poll,
+#endif
+};
+EXPORT_SYMBOL(ei_netdev_ops);
+
 struct net_device *__alloc_ei_netdev(int size)
 {
-	return ____alloc_ei_netdev(size);
+	struct net_device *dev = ____alloc_ei_netdev(size);
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
+	if (dev) {
+		dev->hard_start_xmit = ei_start_xmit;
+		dev->get_stats	= ei_get_stats;
+		dev->set_multicast_list = ei_set_multicast_list;
+		dev->tx_timeout = ei_tx_timeout;
+	}
+#endif
+	return dev;
 }
 EXPORT_SYMBOL(__alloc_ei_netdev);
 
diff --git a/drivers/net/8390.h b/drivers/net/8390.h
index 8e209f5..3c61d6d 100644
--- a/drivers/net/8390.h
+++ b/drivers/net/8390.h
@@ -33,11 +33,19 @@
 extern void eip_poll(struct net_device *dev);
 #endif
 
+
 /* Without I/O delay - non ISA or later chips */
 extern void NS8390_init(struct net_device *dev, int startp);
 extern int ei_open(struct net_device *dev);
 extern int ei_close(struct net_device *dev);
 extern irqreturn_t ei_interrupt(int irq, void *dev_id);
+extern void ei_tx_timeout(struct net_device *dev);
+extern int ei_start_xmit(struct sk_buff *skb, struct net_device *dev);
+extern void ei_set_multicast_list(struct net_device *dev);
+extern struct net_device_stats *ei_get_stats(struct net_device *dev);
+
+extern const struct net_device_ops ei_netdev_ops;
+
 extern struct net_device *__alloc_ei_netdev(int size);
 static inline struct net_device *alloc_ei_netdev(void)
 {
@@ -49,6 +57,13 @@
 extern int eip_open(struct net_device *dev);
 extern int eip_close(struct net_device *dev);
 extern irqreturn_t eip_interrupt(int irq, void *dev_id);
+extern void eip_tx_timeout(struct net_device *dev);
+extern int eip_start_xmit(struct sk_buff *skb, struct net_device *dev);
+extern void eip_set_multicast_list(struct net_device *dev);
+extern struct net_device_stats *eip_get_stats(struct net_device *dev);
+
+extern const struct net_device_ops eip_netdev_ops;
+
 extern struct net_device *__alloc_eip_netdev(int size);
 static inline struct net_device *alloc_eip_netdev(void)
 {
diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c
index 4c6eea4..ee70b35 100644
--- a/drivers/net/8390p.c
+++ b/drivers/net/8390p.c
@@ -22,6 +22,30 @@
 }
 EXPORT_SYMBOL(eip_close);
 
+int eip_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	return __ei_start_xmit(skb, dev);
+}
+EXPORT_SYMBOL(eip_start_xmit);
+
+struct net_device_stats *eip_get_stats(struct net_device *dev)
+{
+	return __ei_get_stats(dev);
+}
+EXPORT_SYMBOL(eip_get_stats);
+
+void eip_set_multicast_list(struct net_device *dev)
+{
+	__ei_set_multicast_list(dev);
+}
+EXPORT_SYMBOL(eip_set_multicast_list);
+
+void eip_tx_timeout(struct net_device *dev)
+{
+	__ei_tx_timeout(dev);
+}
+EXPORT_SYMBOL(eip_tx_timeout);
+
 irqreturn_t eip_interrupt(int irq, void *dev_id)
 {
 	return __ei_interrupt(irq, dev_id);
@@ -36,9 +60,33 @@
 EXPORT_SYMBOL(eip_poll);
 #endif
 
+const struct net_device_ops eip_netdev_ops = {
+	.ndo_open		= eip_open,
+	.ndo_stop		= eip_close,
+	.ndo_start_xmit		= eip_start_xmit,
+	.ndo_tx_timeout		= eip_tx_timeout,
+	.ndo_get_stats		= eip_get_stats,
+	.ndo_set_multicast_list = eip_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= eip_poll,
+#endif
+};
+EXPORT_SYMBOL(eip_netdev_ops);
+
 struct net_device *__alloc_eip_netdev(int size)
 {
-	return ____alloc_ei_netdev(size);
+	struct net_device *dev = ____alloc_ei_netdev(size);
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
+	if (dev) {
+		dev->hard_start_xmit = eip_start_xmit;
+		dev->get_stats	= eip_get_stats;
+		dev->set_multicast_list = eip_set_multicast_list;
+		dev->tx_timeout = eip_tx_timeout;
+	}
+#endif
+	return dev;
 }
 EXPORT_SYMBOL(__alloc_eip_netdev);
 
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 231eeaf..72a9212 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -61,6 +61,7 @@
 config BONDING
 	tristate "Bonding driver support"
 	depends on INET
+	depends on IPV6 || IPV6=n
 	---help---
 	  Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
 	  Channels together. This is called 'Etherchannel' by Cisco,
@@ -978,6 +979,20 @@
 	  called smc911x.  If you want to compile it as a module, say M 
 	  here and read <file:Documentation/kbuild/modules.txt>
 
+config SMSC911X
+	tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
+	depends on ARM || SUPERH
+	select CRC32
+	select MII
+	select PHYLIB
+	---help---
+	  Say Y here if you want support for SMSC LAN911x and LAN921x families
+	  of ethernet controllers.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/networking/net-modules.txt>. The module
+	  will be called smsc911x.
+
 config NET_VENDOR_RACAL
 	bool "Racal-Interlan (Micom) NI cards"
 	depends on ISA
@@ -1414,19 +1429,6 @@
 	depends on NET_PCI && PCI && MIPS
 	select PHYLIB
 
-config EEPRO100
-	tristate "EtherExpressPro/100 support (eepro100, original Becker driver)"
-	depends on NET_PCI && PCI
-	select MII
-	help
-	  If you have an Intel EtherExpress PRO/100 PCI network (Ethernet)
-	  card, say Y and read the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called eepro100.
-
-
 config E100
 	tristate "Intel(R) PRO/100+ support"
 	depends on NET_PCI && PCI
@@ -1636,6 +1638,22 @@
 	  More specific information and updates are available from
 	  <http://www.scyld.com/network/epic100.html>.
 
+config SMSC9420
+	tristate "SMSC LAN9420 PCI ethernet adapter support"
+	depends on NET_PCI && PCI
+	select CRC32
+	select PHYLIB
+	select SMSC_PHY
+	help
+	  This is a driver for SMSC's LAN9420 PCI ethernet adapter.
+	  Say Y if you want it compiled into the kernel,
+	  and read the Ethernet-HOWTO, available from
+	  <http://www.linuxdoc.org/docs.html#howto>.
+
+	  This driver is also available as a module. The module will be
+	  called smsc9420.  If you want to compile it as a module, say M
+	  here and read <file:Documentation/kbuild/modules.txt>
+
 config SUNDANCE
 	tristate "Sundance Alta support"
 	depends on NET_PCI && PCI
@@ -1981,10 +1999,10 @@
 	  will be called ipg.  This is recommended.
 
 config IGB
-       tristate "Intel(R) 82575 PCI-Express Gigabit Ethernet support"
+       tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"
        depends on PCI
        ---help---
-         This driver supports Intel(R) 82575 gigabit ethernet family of
+         This driver supports Intel(R) 82575/82576 gigabit ethernet family of
          adapters.  For more information on how to identify your adapter, go
          to the Adapter & Driver ID Guide at:
 
@@ -2276,10 +2294,6 @@
 	bool "Magic Packet detection support"
 	depends on UCC_GETH
 
-config UGETH_FILTERING
-	bool "Mac address filtering support"
-	depends on UCC_GETH
-
 config UGETH_TX_ON_DEMAND
 	bool "Transmit on Demand support"
 	depends on UCC_GETH
@@ -2450,6 +2464,16 @@
 	  driver.  DCA is a method for warming the CPU cache before data
 	  is used, with the intent of lessening the impact of cache misses.
 
+config IXGBE_DCB
+	bool "Data Center Bridging (DCB) Support"
+	default n
+	depends on IXGBE && DCB
+	---help---
+	  Say Y here if you want to use Data Center Bridging (DCB) in the
+	  driver.
+
+	  If unsure, say N.
+
 config IXGB
 	tristate "Intel(R) PRO/10GbE support"
 	depends on PCI
@@ -2626,7 +2650,7 @@
 	default "128"
 
 config FDDI
-	bool "FDDI driver support"
+	tristate "FDDI driver support"
 	depends on (PCI || EISA || TC)
 	help
 	  Fiber Distributed Data Interface is a high speed local area network
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 017383a..e5c34b4 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -53,10 +53,10 @@
 obj-$(CONFIG_TYPHOON) += typhoon.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
 obj-$(CONFIG_PCNET32) += pcnet32.o
-obj-$(CONFIG_EEPRO100) += eepro100.o
 obj-$(CONFIG_E100) += e100.o
 obj-$(CONFIG_TLAN) += tlan.o
 obj-$(CONFIG_EPIC100) += epic100.o
+obj-$(CONFIG_SMSC9420) += smsc9420.o
 obj-$(CONFIG_SIS190) += sis190.o
 obj-$(CONFIG_SIS900) += sis900.o
 obj-$(CONFIG_R6040) += r6040.o
@@ -98,7 +98,7 @@
 obj-$(CONFIG_NET) += Space.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
 obj-$(CONFIG_NET_SB1000) += sb1000.o
-obj-$(CONFIG_MAC8390) += mac8390.o
+obj-$(CONFIG_MAC8390) += mac8390.o 8390.o
 obj-$(CONFIG_APNE) += apne.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
 obj-$(CONFIG_HP100) += hp100.o
@@ -125,7 +125,7 @@
 obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
 obj-$(CONFIG_B44) += b44.o
 obj-$(CONFIG_FORCEDETH) += forcedeth.o
-obj-$(CONFIG_NE_H8300) += ne-h8300.o
+obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
 obj-$(CONFIG_AX88796) += ax88796.o
 
 obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
@@ -191,7 +191,7 @@
 obj-$(CONFIG_LP486E) += lp486e.o
 
 obj-$(CONFIG_ETH16I) += eth16i.o
-obj-$(CONFIG_ZORRO8390) += zorro8390.o
+obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
 obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
 obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
 obj-$(CONFIG_EQUALIZER) += eql.o
@@ -203,7 +203,7 @@
 obj-$(CONFIG_DECLANCE) += declance.o
 obj-$(CONFIG_ATARILANCE) += atarilance.o
 obj-$(CONFIG_A2065) += a2065.o
-obj-$(CONFIG_HYDRA) += hydra.o
+obj-$(CONFIG_HYDRA) += hydra.o 8390.o
 obj-$(CONFIG_ARIADNE) += ariadne.o
 obj-$(CONFIG_CS89x0) += cs89x0.o
 obj-$(CONFIG_MACSONIC) += macsonic.o
@@ -220,6 +220,7 @@
 obj-$(CONFIG_MYRI10GE) += myri10ge/
 obj-$(CONFIG_SMC91X) += smc91x.o
 obj-$(CONFIG_SMC911X) += smc911x.o
+obj-$(CONFIG_SMSC911X) += smsc911x.o
 obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
 obj-$(CONFIG_DM9000) += dm9000.o
 obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 9c08374..7a60bdd 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -324,7 +324,6 @@
 					 len);
 			skb->protocol = eth_type_trans (skb, dev);
 			netif_rx (skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += len;
 		}
@@ -710,7 +709,6 @@
 	unsigned long board, base_addr, mem_start;
 	struct resource *r1, *r2;
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	board = z->resource.start;
 	base_addr = board+A2065_LANCE;
@@ -787,8 +785,7 @@
 	zorro_set_drvdata(z, dev);
 
 	printk(KERN_INFO "%s: A2065 at 0x%08lx, Ethernet Address "
-	       "%s\n", dev->name, board,
-	       print_mac(mac, dev->dev_addr));
+	       "%pM\n", dev->name, board, dev->dev_addr);
 
 	return 0;
 }
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index b144863..071a851 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -146,7 +146,6 @@
 static int __init ac_probe1(int ioaddr, struct net_device *dev)
 {
 	int i, retval;
-	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -171,8 +170,8 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
 
-	printk(KERN_DEBUG "AC3200 in EISA slot %d, node %s",
-	       ioaddr/0x1000, print_mac(mac, dev->dev_addr));
+	printk(KERN_DEBUG "AC3200 in EISA slot %d, node %pM",
+	       ioaddr/0x1000, dev->dev_addr);
 #if 0
 	/* Check the vendor ID/prefix. Redundant after checking the EISA ID */
 	if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 66de80b..517fce4 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -450,6 +450,20 @@
 
 static void ace_watchdog(struct net_device *dev);
 
+static const struct net_device_ops ace_netdev_ops = {
+	.ndo_open		= ace_open,
+	.ndo_stop		= ace_close,
+	.ndo_tx_timeout		= ace_watchdog,
+	.ndo_get_stats		= ace_get_stats,
+	.ndo_start_xmit		= ace_start_xmit,
+	.ndo_set_multicast_list	= ace_set_multicast_list,
+	.ndo_set_mac_address	= ace_set_mac_addr,
+	.ndo_change_mtu		= ace_change_mtu,
+#if ACENIC_DO_VLAN
+	.ndo_vlan_rx_register	= ace_vlan_rx_register,
+#endif
+};
+
 static int __devinit acenic_probe_one(struct pci_dev *pdev,
 		const struct pci_device_id *id)
 {
@@ -466,27 +480,19 @@
 
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	ap = dev->priv;
+	ap = netdev_priv(dev);
 	ap->pdev = pdev;
 	ap->name = pci_name(pdev);
 
 	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 #if ACENIC_DO_VLAN
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-	dev->vlan_rx_register = ace_vlan_rx_register;
 #endif
 
-	dev->tx_timeout = &ace_watchdog;
 	dev->watchdog_timeo = 5*HZ;
 
-	dev->open = &ace_open;
-	dev->stop = &ace_close;
-	dev->hard_start_xmit = &ace_start_xmit;
-	dev->get_stats = &ace_get_stats;
-	dev->set_multicast_list = &ace_set_multicast_list;
+	dev->netdev_ops = &ace_netdev_ops;
 	SET_ETHTOOL_OPS(dev, &ace_ethtool_ops);
-	dev->set_mac_address = &ace_set_mac_addr;
-	dev->change_mtu = &ace_change_mtu;
 
 	/* we only display this string ONCE */
 	if (!boards_found)
@@ -892,7 +898,6 @@
 	int board_idx, ecode = 0;
 	short i;
 	unsigned char cache_size;
-	DECLARE_MAC_BUF(mac);
 
 	ap = netdev_priv(dev);
 	regs = ap->regs;
@@ -1019,7 +1024,7 @@
 	dev->dev_addr[4] = (mac2 >> 8) & 0xff;
 	dev->dev_addr[5] = mac2 & 0xff;
 
-	printk("MAC: %s\n", print_mac(mac, dev->dev_addr));
+	printk("MAC: %pM\n", dev->dev_addr);
 
 	/*
 	 * Looks like this is necessary to deal with on all architectures,
@@ -2034,7 +2039,6 @@
 #endif
 			netif_rx(skb);
 
-		dev->last_rx = jiffies;
 		dev->stats.rx_packets++;
 		dev->stats.rx_bytes += retdesc->size;
 
@@ -3220,10 +3224,3 @@
 	       ap->name, offset);
 	goto out;
 }
-
-
-/*
- * Local variables:
- * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h   -c -o acenic.o acenic.c"
- * End:
- */
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 07a6697..187ac6e 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -809,7 +809,6 @@
 			lp->coal_conf.rx_packets++;
 			lp->coal_conf.rx_bytes += pkt_len;
 			num_rx_pkt++;
-			dev->last_rx = jiffies;
 
 		err_next_pkt:
 			lp->rx_ring[rx_index].buff_phy_addr
@@ -832,7 +831,7 @@
 	if (rx_pkt_limit > 0) {
 		/* Receive descriptor is empty now */
 		spin_lock_irqsave(&lp->lock, flags);
-		__netif_rx_complete(dev, napi);
+		__netif_rx_complete(napi);
 		writel(VAL0|RINTEN0, mmio + INTEN0);
 		writel(VAL2 | RDMD0, mmio + CMD0);
 		spin_unlock_irqrestore(&lp->lock, flags);
@@ -1171,11 +1170,11 @@
 
 	/* Check if Receive Interrupt has occurred. */
 	if (intr0 & RINT0) {
-		if (netif_rx_schedule_prep(dev, &lp->napi)) {
+		if (netif_rx_schedule_prep(&lp->napi)) {
 			/* Disable receive interupts */
 			writel(RINTEN0, mmio + INTEN0);
 			/* Schedule a polling routine */
-			__netif_rx_schedule(dev, &lp->napi);
+			__netif_rx_schedule(&lp->napi);
 		} else if (intren0 & RINTEN0) {
 			printk("************Driver bug! \
 				interrupt while in poll\n");
@@ -1821,7 +1820,6 @@
 	unsigned long reg_addr,reg_len;
 	struct amd8111e_priv* lp;
 	struct net_device* dev;
-	DECLARE_MAC_BUF(mac);
 
 	err = pci_enable_device(pdev);
 	if(err){
@@ -1963,8 +1961,8 @@
     	chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28;
 	printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n",
 	       dev->name,MODULE_VERS);
-	printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %s\n",
-	       dev->name, chip_version, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %pM\n",
+	       dev->name, chip_version, dev->dev_addr);
 	if (lp->ext_phy_id)
 		printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n",
 		       dev->name, lp->ext_phy_id, lp->ext_phy_addr);
diff --git a/drivers/net/apne.c b/drivers/net/apne.c
index 867f6ff..1437f5d 100644
--- a/drivers/net/apne.c
+++ b/drivers/net/apne.c
@@ -78,9 +78,6 @@
 struct net_device * __init apne_probe(int unit);
 static int apne_probe1(struct net_device *dev, int ioaddr);
 
-static int apne_open(struct net_device *dev);
-static int apne_close(struct net_device *dev);
-
 static void apne_reset_8390(struct net_device *dev);
 static void apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 			  int ring_page);
@@ -207,7 +204,6 @@
     int neX000, ctron;
 #endif
     static unsigned version_printed;
-    DECLARE_MAC_BUF(mac);
 
     if (ei_debug  &&  version_printed++ == 0)
 	printk(version);
@@ -315,6 +311,7 @@
 
     dev->base_addr = ioaddr;
     dev->irq = IRQ_AMIGA_PORTS;
+    dev->netdev_ops = &ei_netdev_ops;
 
     /* Install the Interrupt handler */
     i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
@@ -323,7 +320,7 @@
     for(i = 0; i < ETHER_ADDR_LEN; i++)
 	dev->dev_addr[i] = SA_prom[i];
 
-    printk(" %s\n", print_mac(mac, dev->dev_addr));
+    printk(" %pM\n", dev->dev_addr);
 
     printk("%s: %s found.\n", dev->name, name);
 
@@ -338,11 +335,7 @@
     ei_status.block_input = &apne_block_input;
     ei_status.block_output = &apne_block_output;
     ei_status.get_8390_hdr = &apne_get_8390_hdr;
-    dev->open = &apne_open;
-    dev->stop = &apne_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-    dev->poll_controller = ei_poll;
-#endif
+
     NS8390_init(dev, 0);
 
     pcmcia_ack_int(pcmcia_get_intreq());		/* ack PCMCIA int req */
@@ -353,22 +346,6 @@
     return 0;
 }
 
-static int
-apne_open(struct net_device *dev)
-{
-    ei_open(dev);
-    return 0;
-}
-
-static int
-apne_close(struct net_device *dev)
-{
-    if (ei_debug > 1)
-	printk("%s: Shutting down ethercard.\n", dev->name);
-    ei_close(dev);
-    return 0;
-}
-
 /* Hard reset the card.  This used to pause for the same period that a
    8390 reset command required, but that shouldn't be necessary. */
 static void
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 735fc94..54819a3 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -851,7 +851,6 @@
 
         /* Send packet to a higher place. */
         netif_rx(skb);
-	dev->last_rx = jiffies;
 }
 
 static void cops_timeout(struct net_device *dev)
@@ -1025,11 +1024,3 @@
 module_init(cops_module_init);
 module_exit(cops_module_exit);
 #endif /* MODULE */
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c"
- *  c-basic-offset: 4
- *  c-file-offsets: ((substatement-open . 0))
- * End:
- */
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index 1071144..9a0be9b 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -108,7 +108,7 @@
  */
 static struct net_device_stats *ipddp_get_stats(struct net_device *dev)
 {
-        return dev->priv;
+	return netdev_priv(dev);
 }
 
 /*
@@ -170,8 +170,8 @@
 
         skb->protocol = htons(ETH_P_ATALK);     /* Protocol has changed */
 
-	((struct net_device_stats *) dev->priv)->tx_packets++;
-        ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
+	((struct net_device_stats *) netdev_priv(dev))->tx_packets++;
+	((struct net_device_stats *) netdev_priv(dev))->tx_bytes += skb->len;
 
         if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
                 dev_kfree_skb(skb);
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index fef5560..dc4d496 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -726,7 +726,8 @@
 	int dnode, snode, llaptype, len; 
 	int sklen;
 	struct sk_buff *skb;
-	struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats;
+	struct ltpc_private *ltpc_priv = netdev_priv(dev);
+	struct net_device_stats *stats = &ltpc_priv->stats;
 	struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf;
 
 	if (ltc->command != LT_RCVLAP) {
@@ -783,7 +784,6 @@
 
 	/* toss it onwards */
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 	return 0;
 }
 
@@ -823,7 +823,8 @@
 {
 	struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr;
 	/* we'll keep the localtalk node address in dev->pa_addr */
-	struct atalk_addr *aa = &((struct ltpc_private *)dev->priv)->my_addr;
+	struct ltpc_private *ltpc_priv = netdev_priv(dev);
+	struct atalk_addr *aa = &ltpc_priv->my_addr;
 	struct lt_init c;
 	int ltflags;
 
@@ -904,7 +905,8 @@
 	 * and skb->len is the length of the ddp data + ddp header
 	 */
 
-	struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats;
+	struct ltpc_private *ltpc_priv = netdev_priv(dev);
+	struct net_device_stats *stats = &ltpc_priv->stats;
 
 	int i;
 	struct lt_sendlap cbuf;
@@ -943,7 +945,8 @@
 
 static struct net_device_stats *ltpc_get_stats(struct net_device *dev)
 {
-	struct net_device_stats *stats = &((struct ltpc_private *) dev->priv)->stats;
+	struct ltpc_private *ltpc_priv = netdev_priv(dev);
+	struct net_device_stats *stats = &ltpc_priv->stats;
 	return stats;
 }
 
diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c
index e0a18e7..3ff9aff 100644
--- a/drivers/net/arcnet/arc-rawmode.c
+++ b/drivers/net/arcnet/arc-rawmode.c
@@ -87,7 +87,7 @@
 static void rx(struct net_device *dev, int bufnum,
 	       struct archdr *pkthdr, int length)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct sk_buff *skb;
 	struct archdr *pkt = pkthdr;
 	int ofs;
@@ -125,7 +125,6 @@
 	skb->protocol = __constant_htons(ETH_P_ARCNET);
 ;
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 }
 
 
@@ -168,7 +167,7 @@
 static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
 		      int bufnum)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct arc_hardware *hard = &pkt->hard;
 	int ofs;
 
diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c
index 8c8d6c4..e3082a9 100644
--- a/drivers/net/arcnet/arc-rimi.c
+++ b/drivers/net/arcnet/arc-rimi.c
@@ -194,7 +194,7 @@
 
 	/* initialize the rest of the device structure. */
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	lp->card_name = "RIM I";
 	lp->hw.command = arcrimi_command;
 	lp->hw.status = arcrimi_status;
@@ -260,7 +260,7 @@
  */
 static int arcrimi_reset(struct net_device *dev, int really_reset)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->mem_start + 0x800;
 
 	BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS());
@@ -281,7 +281,7 @@
 
 static void arcrimi_setmask(struct net_device *dev, int mask)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->mem_start + 0x800;
 
 	AINTMASK(mask);
@@ -289,7 +289,7 @@
 
 static int arcrimi_status(struct net_device *dev)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->mem_start + 0x800;
 
 	return ASTATUS();
@@ -297,7 +297,7 @@
 
 static void arcrimi_command(struct net_device *dev, int cmd)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->mem_start + 0x800;
 
 	ACOMMAND(cmd);
@@ -306,7 +306,7 @@
 static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset,
 				 void *buf, int count)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
 	TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count));
 }
@@ -315,7 +315,7 @@
 static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset,
 				   void *buf, int count)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
 	TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
 }
@@ -361,7 +361,7 @@
 static void __exit arc_rimi_exit(void)
 {
 	struct net_device *dev = my_dev;
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 
 	unregister_netdev(dev);
 	iounmap(lp->mem_start);
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index a5b0769..6b53e5e 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -181,7 +181,7 @@
 static void arcnet_dump_packet(struct net_device *dev, int bufnum,
 			       char *desc, int take_arcnet_lock)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int i, length;
 	unsigned long flags = 0;
 	static uint8_t buf[512];
@@ -247,7 +247,7 @@
  */
 static void release_arcbuf(struct net_device *dev, int bufnum)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int i;
 
 	lp->buf_queue[lp->first_free_buf++] = bufnum;
@@ -269,7 +269,7 @@
  */
 static int get_arcbuf(struct net_device *dev)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int buf = -1, i;
 
 	if (!atomic_dec_and_test(&lp->buf_lock)) {
@@ -357,7 +357,7 @@
 	dev = alloc_netdev(sizeof(struct arcnet_local),
 			   name && *name ? name : "arc%d", arcdev_setup);
 	if(dev) {
-		struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+		struct arcnet_local *lp = netdev_priv(dev);
 		spin_lock_init(&lp->lock);
 	}
 
@@ -374,7 +374,7 @@
  */
 static int arcnet_open(struct net_device *dev)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int count, newmtu, error;
 
 	BUGMSG(D_INIT,"opened.");
@@ -474,7 +474,7 @@
 /* The inverse routine to arcnet_open - shuts down the card. */
 static int arcnet_close(struct net_device *dev)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 
@@ -556,7 +556,7 @@
 static int arcnet_rebuild_header(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int status = 0;		/* default is failure */
 	unsigned short type;
 	uint8_t daddr=0;
@@ -603,7 +603,7 @@
 /* Called by the kernel in order to transmit a packet. */
 static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct archdr *pkt;
 	struct arc_rfc1201 *soft;
 	struct ArcProto *proto;
@@ -693,7 +693,7 @@
  */
 static int go_tx(struct net_device *dev)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 
 	BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, next_tx=%d, cur_tx=%d\n",
 	       ASTATUS(), lp->intmask, lp->next_tx, lp->cur_tx);
@@ -723,7 +723,7 @@
 static void arcnet_timeout(struct net_device *dev)
 {
 	unsigned long flags;
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int status = ASTATUS();
 	char *msg;
 
@@ -771,8 +771,8 @@
 	BUGMSG(D_DURING, "\n");
 
 	BUGMSG(D_DURING, "in arcnet_interrupt\n");
-	
-	lp = dev->priv;
+
+	lp = netdev_priv(dev);
 	BUG_ON(!lp);
 		
 	spin_lock(&lp->lock);
@@ -1010,7 +1010,7 @@
  */
 static void arcnet_rx(struct net_device *dev, int bufnum)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct archdr pkt;
 	struct arc_rfc1201 *soft;
 	int length, ofs;
@@ -1074,7 +1074,7 @@
  */
 static struct net_device_stats *arcnet_get_stats(struct net_device *dev)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	return &lp->stats;
 }
 
@@ -1091,7 +1091,7 @@
 static int null_build_header(struct sk_buff *skb, struct net_device *dev,
 			     unsigned short type, uint8_t daddr)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 
 	BUGMSG(D_PROTO,
 	       "tx: can't build header for encap %02Xh; load a protocol driver.\n",
@@ -1106,7 +1106,7 @@
 static int null_prepare_tx(struct net_device *dev, struct archdr *pkt,
 			   int length, int bufnum)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct arc_hardware newpkt;
 
 	BUGMSG(D_PROTO, "tx: no encap for this host; load a protocol driver.\n");
diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c
index 02cb8f1..30580bb 100644
--- a/drivers/net/arcnet/capmode.c
+++ b/drivers/net/arcnet/capmode.c
@@ -61,7 +61,7 @@
 };
 
 
-void arcnet_cap_init(void)
+static void arcnet_cap_init(void)
 {
 	int count;
 
@@ -103,7 +103,7 @@
 static void rx(struct net_device *dev, int bufnum,
 	       struct archdr *pkthdr, int length)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct sk_buff *skb;
 	struct archdr *pkt = pkthdr;
 	char *pktbuf, *pkthdrbuf;
@@ -151,7 +151,6 @@
 	skb->protocol = __constant_htons(ETH_P_ARCNET);
 ;
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 }
 
 
@@ -198,7 +197,7 @@
 static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
 		      int bufnum)
 {
-	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct arc_hardware *hard = &pkt->hard;
 	int ofs;
 
@@ -250,7 +249,7 @@
 
 static int ack_tx(struct net_device *dev, int acked)
 {
-  struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+  struct arcnet_local *lp = netdev_priv(dev);
   struct sk_buff *ackskb;
   struct archdr *ackpkt;
   int length=sizeof(struct arc_cap);
diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c
index 9289e61..ea53a94 100644
--- a/drivers/net/arcnet/com20020-isa.c
+++ b/drivers/net/arcnet/com20020-isa.c
@@ -52,7 +52,7 @@
 {
 	int ioaddr;
 	unsigned long airqmask;
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int err;
 
 	BUGLVL(D_NORMAL) printk(VERSION);
@@ -151,7 +151,7 @@
 	if (node && node != 0xff)
 		dev->dev_addr[0] = node;
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	lp->backplane = backplane;
 	lp->clockp = clockp & 7;
 	lp->clockm = clockm & 3;
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c
index b8c0fa6..8b51f63 100644
--- a/drivers/net/arcnet/com20020-pci.c
+++ b/drivers/net/arcnet/com20020-pci.c
@@ -72,7 +72,7 @@
 	dev = alloc_arcdev(device);
 	if (!dev)
 		return -ENOMEM;
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 
 	pci_set_drvdata(pdev, dev);
 
diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c
index 70124a9..1036883 100644
--- a/drivers/net/arcnet/com20020.c
+++ b/drivers/net/arcnet/com20020.c
@@ -89,7 +89,7 @@
 int com20020_check(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr, status;
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 
 	ARCRESET0;
 	mdelay(RESETtime);
@@ -159,7 +159,7 @@
 
 	/* Initialize the rest of the device structure. */
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 
 	lp->hw.owner = THIS_MODULE;
 	lp->hw.command = com20020_command;
@@ -233,7 +233,7 @@
  */
 static int com20020_reset(struct net_device *dev, int really_reset)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	u_int ioaddr = dev->base_addr;
 	u_char inbyte;
 
@@ -300,7 +300,7 @@
 
 static void com20020_close(struct net_device *dev)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	/* disable transmitter */
@@ -317,7 +317,7 @@
  */
 static void com20020_set_mc_list(struct net_device *dev)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) {	/* Enable promiscuous mode */
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
index 6599f10..89de29b 100644
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -248,7 +248,7 @@
 		return -EBUSY;
 	}
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	lp->card_name = "COM90xx I/O";
 	lp->hw.command = com90io_command;
 	lp->hw.status = com90io_status;
@@ -290,7 +290,7 @@
  */
 static int com90io_reset(struct net_device *dev, int really_reset)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	short ioaddr = dev->base_addr;
 
 	BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS());
diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c
index 0d45553..d762fe4 100644
--- a/drivers/net/arcnet/com90xx.c
+++ b/drivers/net/arcnet/com90xx.c
@@ -468,7 +468,7 @@
 		release_mem_region(shmem, MIRROR_SIZE);
 		return -ENOMEM;
 	}
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	/* find the real shared memory start/end points, including mirrors */
 
 	/* guess the actual size of one "memory mirror" - the number of
@@ -583,9 +583,9 @@
  *
  * However, it does make sure the card is in a defined state.
  */
-int com90xx_reset(struct net_device *dev, int really_reset)
+static int com90xx_reset(struct net_device *dev, int really_reset)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	short ioaddr = dev->base_addr;
 
 	BUGMSG(D_INIT, "Resetting (status=%02Xh)\n", ASTATUS());
@@ -621,7 +621,7 @@
 static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset,
 				 void *buf, int count)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
 	TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count));
 }
@@ -630,7 +630,7 @@
 static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset,
 				   void *buf, int count)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
 	TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
 }
@@ -656,7 +656,7 @@
 
 	for (count = 0; count < numcards; count++) {
 		dev = cards[count];
-		lp = dev->priv;
+		lp = netdev_priv(dev);
 
 		unregister_netdev(dev);
 		free_irq(dev->irq, dev);
diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c
index dab185b..49d39a9 100644
--- a/drivers/net/arcnet/rfc1051.c
+++ b/drivers/net/arcnet/rfc1051.c
@@ -88,7 +88,7 @@
  */
 static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct archdr *pkt = (struct archdr *) skb->data;
 	struct arc_rfc1051 *soft = &pkt->soft.rfc1051;
 	int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;
@@ -125,7 +125,7 @@
 static void rx(struct net_device *dev, int bufnum,
 	       struct archdr *pkthdr, int length)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct sk_buff *skb;
 	struct archdr *pkt = pkthdr;
 	int ofs;
@@ -159,7 +159,6 @@
 
 	skb->protocol = type_trans(skb, dev);
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 }
 
 
@@ -169,7 +168,7 @@
 static int build_header(struct sk_buff *skb, struct net_device *dev,
 			unsigned short type, uint8_t daddr)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;
 	struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size);
 	struct arc_rfc1051 *soft = &pkt->soft.rfc1051;
@@ -220,7 +219,7 @@
 static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
 		      int bufnum)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct arc_hardware *hard = &pkt->hard;
 	int ofs;
 
diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c
index 6d6d95c..2303d3a 100644
--- a/drivers/net/arcnet/rfc1201.c
+++ b/drivers/net/arcnet/rfc1201.c
@@ -92,7 +92,7 @@
 {
 	struct archdr *pkt = (struct archdr *) skb->data;
 	struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
 
 	/* Pull off the arcnet header. */
@@ -134,7 +134,7 @@
 static void rx(struct net_device *dev, int bufnum,
 	       struct archdr *pkthdr, int length)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct sk_buff *skb;
 	struct archdr *pkt = pkthdr;
 	struct arc_rfc1201 *soft = &pkthdr->soft.rfc1201;
@@ -230,7 +230,6 @@
 
 		skb->protocol = type_trans(skb, dev);
 		netif_rx(skb);
-		dev->last_rx = jiffies;
 	} else {		/* split packet */
 		/*
 		 * NOTE: MSDOS ARP packet correction should only need to apply to
@@ -366,7 +365,6 @@
 
 			skb->protocol = type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 		}
 	}
 }
@@ -376,7 +374,7 @@
 static int build_header(struct sk_buff *skb, struct net_device *dev,
 			unsigned short type, uint8_t daddr)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
 	struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size);
 	struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
@@ -443,7 +441,7 @@
 static void load_pkt(struct net_device *dev, struct arc_hardware *hard,
 		     struct arc_rfc1201 *soft, int softlen, int bufnum)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	int ofs;
 
 	/* assume length <= XMTU: someone should have handled that by now. */
@@ -476,7 +474,7 @@
 static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
 		      int bufnum)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	const int maxsegsize = XMTU - RFC1201_HDR_SIZE;
 	struct Outgoing *out;
 
@@ -511,7 +509,7 @@
 
 static int continue_tx(struct net_device *dev, int bufnum)
 {
-	struct arcnet_local *lp = dev->priv;
+	struct arcnet_local *lp = netdev_priv(dev);
 	struct Outgoing *out = &lp->outgoing;
 	struct arc_hardware *hard = &out->pkt->hard;
 	struct arc_rfc1201 *soft = &out->pkt->soft.rfc1201, *newsoft;
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 29e53eb..e1d72e0 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -165,7 +165,6 @@
     struct net_device *dev;
     struct ariadne_private *priv;
     int err;
-    DECLARE_MAC_BUF(mac);
 
     r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960");
     if (!r1)
@@ -215,9 +214,8 @@
     }
     zorro_set_drvdata(z, dev);
 
-    printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address "
-	   "%s\n", dev->name, board,
-	   print_mac(mac, dev->dev_addr));
+    printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address %pM\n",
+           dev->name, board, dev->dev_addr);
 
     return 0;
 }
@@ -613,14 +611,10 @@
 
 #if 0
 {
-    DECLARE_MAC_BUF(mac);
-    DECLARE_MAC_BUF(mac2);
-
-    printk(KERN_DEBUG "TX pkt type 0x%04x from %s to %s "
+    printk(KERN_DEBUG "TX pkt type 0x%04x from %pM to %pM "
 	   " data 0x%08x len %d\n",
 	   ((u_short *)skb->data)[6],
-	   print_mac(mac, ((const u8 *)skb->data)+6),
-	   print_mac(mac, (const u8 *)skb->data),
+	   skb->data + 6, skb->data,
 	   (int)skb->data, (int)skb->len);
 }
 #endif
@@ -743,25 +737,22 @@
 	    skb->protocol=eth_type_trans(skb,dev);
 #if 0
 {
-	    DECLARE_MAC_BUF(mac);
-
 	    printk(KERN_DEBUG "RX pkt type 0x%04x from ",
 		   ((u_short *)skb->data)[6]);
 	    {
 		u_char *ptr = &((u_char *)skb->data)[6];
-		printk("%s", print_mac(mac, ptr));
+		printk("%pM", ptr);
 	    }
 	    printk(" to ");
 	    {
 		u_char *ptr = (u_char *)skb->data;
-		printk("%s", print_mac(mac, ptr));
+		printk("%pM", ptr);
 	    }
 	    printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
 }
 #endif
 
 	    netif_rx(skb);
-	    dev->last_rx = jiffies;
 	    dev->stats.rx_packets++;
 	    dev->stats.rx_bytes += pkt_len;
 	}
diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig
index 8eda6ee..2895db1 100644
--- a/drivers/net/arm/Kconfig
+++ b/drivers/net/arm/Kconfig
@@ -40,6 +40,14 @@
 	  If you wish to compile a kernel for the AT91RM9200 and enable
 	  ethernet support, then you should always answer Y to this.
 
+config ARM_KS8695_ETHER
+	tristate "KS8695 Ethernet support"
+	depends on ARM && ARCH_KS8695
+	select MII
+	help
+	  If you wish to compile a kernel for the KS8695 and want to
+	  use the internal ethernet then you should answer Y to this.
+
 config EP93XX_ETH
 	tristate "EP93xx Ethernet support"
 	depends on ARM && ARCH_EP93XX
@@ -51,7 +59,7 @@
 config IXP4XX_ETH
 	tristate "Intel IXP4xx Ethernet support"
 	depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
-	select MII
+	select PHYLIB
 	help
 	  Say Y here if you want to use built-in Ethernet ports
 	  on IXP4xx processor.
diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile
index 7c812ac..c69c0cd 100644
--- a/drivers/net/arm/Makefile
+++ b/drivers/net/arm/Makefile
@@ -4,9 +4,10 @@
 #
 
 obj-$(CONFIG_ARM_AM79C961A)	+= am79c961a.o
-obj-$(CONFIG_ARM_ETHERH)	+= etherh.o
+obj-$(CONFIG_ARM_ETHERH)	+= etherh.o ../8390.o
 obj-$(CONFIG_ARM_ETHER3)	+= ether3.o
 obj-$(CONFIG_ARM_ETHER1)	+= ether1.o
 obj-$(CONFIG_ARM_AT91_ETHER)	+= at91_ether.o
+obj-$(CONFIG_ARM_KS8695_ETHER)	+= ks8695net.o
 obj-$(CONFIG_EP93XX_ETH)	+= ep93xx_eth.o
 obj-$(CONFIG_IXP4XX_ETH)	+= ixp4xx_eth.o
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index aa4a524..0c628a9 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -532,7 +532,6 @@
 			am_writeword(dev, hdraddr + 2, RMD_OWN);
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			priv->stats.rx_bytes += len;
 			priv->stats.rx_packets ++;
 		} else {
@@ -745,10 +744,8 @@
 
 	ret = register_netdev(dev);
 	if (ret == 0) {
-		DECLARE_MAC_BUF(mac);
-
-		printk(KERN_INFO "%s: ether address %s\n",
-		       dev->name, print_mac(mac, dev->dev_addr));
+		printk(KERN_INFO "%s: ether address %pM\n",
+		       dev->name, dev->dev_addr);
 		return 0;
 	}
 
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 6f431a8..442938d 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -485,7 +485,6 @@
 static int set_mac_address(struct net_device *dev, void* addr)
 {
 	struct sockaddr *address = addr;
-	DECLARE_MAC_BUF(mac);
 
 	if (!is_valid_ether_addr(address->sa_data))
 		return -EADDRNOTAVAIL;
@@ -493,8 +492,8 @@
 	memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
 	update_mac_address(dev);
 
-	printk("%s: Setting MAC address to %s\n", dev->name,
-	       print_mac(mac, dev->dev_addr));
+	printk("%s: Setting MAC address to %pM\n", dev->name,
+	       dev->dev_addr);
 
 	return 0;
 }
@@ -894,7 +893,6 @@
 			memcpy(skb_put(skb, pktlen), p_recv, pktlen);
 
 			skb->protocol = eth_type_trans(skb, dev);
-			dev->last_rx = jiffies;
 			dev->stats.rx_bytes += pktlen;
 			netif_rx(skb);
 		}
@@ -978,7 +976,6 @@
 	struct at91_private *lp;
 	unsigned int val;
 	int res;
-	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof(struct at91_private));
 	if (!dev)
@@ -1084,11 +1081,11 @@
 		gpio_request(lp->board_data.phy_irq_pin, "ethernet_phy");
 
 	/* Display ethernet banner */
-	printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%s)\n",
+	printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%pM)\n",
 	       dev->name, (uint) dev->base_addr, dev->irq,
 	       at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
 	       at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
-	       print_mac(mac, dev->dev_addr));
+	       dev->dev_addr);
 	if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
 		printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
 	else if (phy_type == MII_LXT971A_ID)
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index 1267444..6ecc600 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -259,8 +259,6 @@
 			skb_put(skb, length);
 			skb->protocol = eth_type_trans(skb, dev);
 
-			dev->last_rx = jiffies;
-
 			netif_receive_skb(skb);
 
 			ep->stats.rx_packets++;
@@ -300,7 +298,7 @@
 		int more = 0;
 
 		spin_lock_irq(&ep->rx_lock);
-		__netif_rx_complete(dev, napi);
+		__netif_rx_complete(napi);
 		wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
 		if (ep93xx_have_more_rx(ep)) {
 			wrl(ep, REG_INTEN, REG_INTEN_TX);
@@ -417,9 +415,9 @@
 
 	if (status & REG_INTSTS_RX) {
 		spin_lock(&ep->rx_lock);
-		if (likely(netif_rx_schedule_prep(dev, &ep->napi))) {
+		if (likely(netif_rx_schedule_prep(&ep->napi))) {
 			wrl(ep, REG_INTEN, REG_INTEN_TX);
-			__netif_rx_schedule(dev, &ep->napi);
+			__netif_rx_schedule(&ep->napi);
 		}
 		spin_unlock(&ep->rx_lock);
 	}
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index 3bb9e29..e380de4 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -996,7 +996,6 @@
 {
 	struct net_device *dev;
 	int i, ret = 0;
-	DECLARE_MAC_BUF(mac);
 
 	ether1_banner();
 
@@ -1044,8 +1043,8 @@
 	if (ret)
 		goto free;
 
-	printk(KERN_INFO "%s: ether1 in slot %d, %s\n",
-		dev->name, ec->slot_no, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: ether1 in slot %d, %pM\n",
+		dev->name, ec->slot_no, dev->dev_addr);
     
 	ecard_set_drvdata(ec, dev);
 	return 0;
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 67e96ae..21a7bef 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -776,7 +776,6 @@
 	const struct ether3_data *data = id->data;
 	struct net_device *dev;
 	int bus_type, ret;
-	DECLARE_MAC_BUF(mac);
 
 	ether3_banner();
 
@@ -859,8 +858,8 @@
 	if (ret)
 		goto free;
 
-	printk("%s: %s in slot %d, %s\n",
-	       dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr));
+	printk("%s: %s in slot %d, %pM\n",
+	       dev->name, data->name, ec->slot_no, dev->dev_addr);
 
 	ecard_set_drvdata(ec, dev);
 	return 0;
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index 5c5f1e4..6278606 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -637,6 +637,21 @@
 	.get_drvinfo	= etherh_get_drvinfo,
 };
 
+static const struct net_device_ops etherh_netdev_ops = {
+	.ndo_open		= etherh_open,
+	.ndo_stop		= etherh_close,
+	.ndo_set_config		= etherh_set_config,
+	.ndo_start_xmit		= ei_start_xmit,
+	.ndo_tx_timeout		= ei_tx_timeout,
+	.ndo_get_stats		= ei_get_stats,
+	.ndo_set_multicast_list = ei_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= ei_poll,
+#endif
+};
+
 static u32 etherh_regoffsets[16];
 static u32 etherm_regoffsets[16];
 
@@ -648,7 +663,6 @@
 	struct net_device *dev;
 	struct etherh_priv *eh;
 	int ret;
-	DECLARE_MAC_BUF(mac);
 
 	etherh_banner();
 
@@ -664,9 +678,7 @@
 
 	SET_NETDEV_DEV(dev, &ec->dev);
 
-	dev->open		= etherh_open;
-	dev->stop		= etherh_close;
-	dev->set_config		= etherh_set_config;
+	dev->netdev_ops		= &etherh_netdev_ops;
 	dev->irq		= ec->irq;
 	dev->ethtool_ops	= &etherh_ethtool_ops;
 
@@ -746,8 +758,8 @@
 	if (ret)
 		goto free;
 
-	printk(KERN_INFO "%s: %s in slot %d, %s\n",
-		dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: %s in slot %d, %pM\n",
+		dev->name, data->name, ec->slot_no, dev->dev_addr);
 
 	ecard_set_drvdata(ec, dev);
 
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
index e2d702b..26af411 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -30,12 +30,11 @@
 #include <linux/etherdevice.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
-#include <linux/mii.h>
+#include <linux/phy.h>
 #include <linux/platform_device.h>
 #include <mach/npe.h>
 #include <mach/qmgr.h>
 
-#define DEBUG_QUEUES		0
 #define DEBUG_DESC		0
 #define DEBUG_RX		0
 #define DEBUG_TX		0
@@ -59,7 +58,6 @@
 #define NAPI_WEIGHT		16
 #define MDIO_INTERVAL		(3 * HZ)
 #define MAX_MDIO_RETRIES	100 /* microseconds, typically 30 cycles */
-#define MAX_MII_RESET_RETRIES	100 /* mdio_read() cycles, typically 4 */
 #define MAX_CLOSE_WAIT		1000 /* microseconds, typically 2-3 cycles */
 
 #define NPE_ID(port_id)		((port_id) >> 4)
@@ -164,15 +162,14 @@
 	struct npe *npe;
 	struct net_device *netdev;
 	struct napi_struct napi;
-	struct net_device_stats stat;
-	struct mii_if_info mii;
-	struct delayed_work mdio_thread;
+	struct phy_device *phydev;
 	struct eth_plat_info *plat;
 	buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS];
 	struct desc *desc_tab;	/* coherent */
 	u32 desc_tab_phys;
 	int id;			/* logical port ID */
-	u16 mii_bmcr;
+	int speed, duplex;
+	u8 firmware[4];
 };
 
 /* NPE message structure */
@@ -243,19 +240,20 @@
 
 static spinlock_t mdio_lock;
 static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */
+struct mii_bus *mdio_bus;
 static int ports_open;
 static struct port *npe_port_tab[MAX_NPES];
 static struct dma_pool *dma_pool;
 
 
-static u16 mdio_cmd(struct net_device *dev, int phy_id, int location,
-		    int write, u16 cmd)
+static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location,
+			   int write, u16 cmd)
 {
 	int cycles = 0;
 
 	if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {
-		printk(KERN_ERR "%s: MII not ready to transmit\n", dev->name);
-		return 0;
+		printk(KERN_ERR "%s: MII not ready to transmit\n", bus->name);
+		return -1;
 	}
 
 	if (write) {
@@ -274,107 +272,119 @@
 	}
 
 	if (cycles == MAX_MDIO_RETRIES) {
-		printk(KERN_ERR "%s: MII write failed\n", dev->name);
-		return 0;
+		printk(KERN_ERR "%s #%i: MII write failed\n", bus->name,
+		       phy_id);
+		return -1;
 	}
 
 #if DEBUG_MDIO
-	printk(KERN_DEBUG "%s: mdio_cmd() took %i cycles\n", dev->name,
-	       cycles);
+	printk(KERN_DEBUG "%s #%i: mdio_%s() took %i cycles\n", bus->name,
+	       phy_id, write ? "write" : "read", cycles);
 #endif
 
 	if (write)
 		return 0;
 
 	if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {
-		printk(KERN_ERR "%s: MII read failed\n", dev->name);
-		return 0;
+#if DEBUG_MDIO
+		printk(KERN_DEBUG "%s #%i: MII read failed\n", bus->name,
+		       phy_id);
+#endif
+		return 0xFFFF; /* don't return error */
 	}
 
 	return (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |
-		(__raw_readl(&mdio_regs->mdio_status[1]) << 8);
+		((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8);
 }
 
-static int mdio_read(struct net_device *dev, int phy_id, int location)
+static int ixp4xx_mdio_read(struct mii_bus *bus, int phy_id, int location)
 {
 	unsigned long flags;
-	u16 val;
+	int ret;
 
 	spin_lock_irqsave(&mdio_lock, flags);
-	val = mdio_cmd(dev, phy_id, location, 0, 0);
+	ret = ixp4xx_mdio_cmd(bus, phy_id, location, 0, 0);
 	spin_unlock_irqrestore(&mdio_lock, flags);
-	return val;
+#if DEBUG_MDIO
+	printk(KERN_DEBUG "%s #%i: MII read [%i] -> 0x%X\n", bus->name,
+	       phy_id, location, ret);
+#endif
+	return ret;
 }
 
-static void mdio_write(struct net_device *dev, int phy_id, int location,
-		       int val)
+static int ixp4xx_mdio_write(struct mii_bus *bus, int phy_id, int location,
+			     u16 val)
 {
 	unsigned long flags;
+	int ret;
 
 	spin_lock_irqsave(&mdio_lock, flags);
-	mdio_cmd(dev, phy_id, location, 1, val);
+	ret = ixp4xx_mdio_cmd(bus, phy_id, location, 1, val);
 	spin_unlock_irqrestore(&mdio_lock, flags);
+#if DEBUG_MDIO
+	printk(KERN_DEBUG "%s #%i: MII read [%i] <- 0x%X, err = %i\n",
+	       bus->name, phy_id, location, val, ret);
+#endif
+	return ret;
 }
 
-static void phy_reset(struct net_device *dev, int phy_id)
+static int ixp4xx_mdio_register(void)
+{
+	int err;
+
+	if (!(mdio_bus = mdiobus_alloc()))
+		return -ENOMEM;
+
+	/* All MII PHY accesses use NPE-B Ethernet registers */
+	spin_lock_init(&mdio_lock);
+	mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
+	__raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
+
+	mdio_bus->name = "IXP4xx MII Bus";
+	mdio_bus->read = &ixp4xx_mdio_read;
+	mdio_bus->write = &ixp4xx_mdio_write;
+	strcpy(mdio_bus->id, "0");
+
+	if ((err = mdiobus_register(mdio_bus)))
+		mdiobus_free(mdio_bus);
+	return err;
+}
+
+static void ixp4xx_mdio_remove(void)
+{
+	mdiobus_unregister(mdio_bus);
+	mdiobus_free(mdio_bus);
+}
+
+
+static void ixp4xx_adjust_link(struct net_device *dev)
 {
 	struct port *port = netdev_priv(dev);
-	int cycles = 0;
+	struct phy_device *phydev = port->phydev;
 
-	mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr | BMCR_RESET);
-
-	while (cycles < MAX_MII_RESET_RETRIES) {
-		if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) {
-#if DEBUG_MDIO
-			printk(KERN_DEBUG "%s: phy_reset() took %i cycles\n",
-			       dev->name, cycles);
-#endif
-			return;
+	if (!phydev->link) {
+		if (port->speed) {
+			port->speed = 0;
+			printk(KERN_INFO "%s: link down\n", dev->name);
 		}
-		udelay(1);
-		cycles++;
+		return;
 	}
 
-	printk(KERN_ERR "%s: MII reset failed\n", dev->name);
-}
+	if (port->speed == phydev->speed && port->duplex == phydev->duplex)
+		return;
 
-static void eth_set_duplex(struct port *port)
-{
-	if (port->mii.full_duplex)
+	port->speed = phydev->speed;
+	port->duplex = phydev->duplex;
+
+	if (port->duplex)
 		__raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
 			     &port->regs->tx_control[0]);
 	else
 		__raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
 			     &port->regs->tx_control[0]);
-}
 
-
-static void phy_check_media(struct port *port, int init)
-{
-	if (mii_check_media(&port->mii, 1, init))
-		eth_set_duplex(port);
-	if (port->mii.force_media) { /* mii_check_media() doesn't work */
-		struct net_device *dev = port->netdev;
-		int cur_link = mii_link_ok(&port->mii);
-		int prev_link = netif_carrier_ok(dev);
-
-		if (!prev_link && cur_link) {
-			printk(KERN_INFO "%s: link up\n", dev->name);
-			netif_carrier_on(dev);
-		} else if (prev_link && !cur_link) {
-			printk(KERN_INFO "%s: link down\n", dev->name);
-			netif_carrier_off(dev);
-		}
-	}
-}
-
-
-static void mdio_thread(struct work_struct *work)
-{
-	struct port *port = container_of(work, struct port, mdio_thread.work);
-
-	phy_check_media(port, 0);
-	schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL);
+	printk(KERN_INFO "%s: link up, speed %u Mb/s, %s duplex\n",
+	       dev->name, port->speed, port->duplex ? "full" : "half");
 }
 
 
@@ -412,47 +422,13 @@
 #endif
 }
 
-static inline void debug_queue(unsigned int queue, int is_get, u32 phys)
-{
-#if DEBUG_QUEUES
-	static struct {
-		int queue;
-		char *name;
-	} names[] = {
-		{ TX_QUEUE(0x10), "TX#0 " },
-		{ TX_QUEUE(0x20), "TX#1 " },
-		{ TX_QUEUE(0x00), "TX#2 " },
-		{ RXFREE_QUEUE(0x10), "RX-free#0 " },
-		{ RXFREE_QUEUE(0x20), "RX-free#1 " },
-		{ RXFREE_QUEUE(0x00), "RX-free#2 " },
-		{ TXDONE_QUEUE, "TX-done " },
-	};
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(names); i++)
-		if (names[i].queue == queue)
-			break;
-
-	printk(KERN_DEBUG "Queue %i %s%s %X\n", queue,
-	       i < ARRAY_SIZE(names) ? names[i].name : "",
-	       is_get ? "->" : "<-", phys);
-#endif
-}
-
-static inline u32 queue_get_entry(unsigned int queue)
-{
-	u32 phys = qmgr_get_entry(queue);
-	debug_queue(queue, 1, phys);
-	return phys;
-}
-
 static inline int queue_get_desc(unsigned int queue, struct port *port,
 				 int is_tx)
 {
 	u32 phys, tab_phys, n_desc;
 	struct desc *tab;
 
-	if (!(phys = queue_get_entry(queue)))
+	if (!(phys = qmgr_get_entry(queue)))
 		return -1;
 
 	phys &= ~0x1F; /* mask out non-address bits */
@@ -468,7 +444,6 @@
 static inline void queue_put_desc(unsigned int queue, u32 phys,
 				  struct desc *desc)
 {
-	debug_queue(queue, 0, phys);
 	debug_desc(phys, desc);
 	BUG_ON(phys & 0x1F);
 	qmgr_put_entry(queue, phys);
@@ -498,7 +473,7 @@
 	printk(KERN_DEBUG "%s: eth_rx_irq\n", dev->name);
 #endif
 	qmgr_disable_irq(port->plat->rxq);
-	netif_rx_schedule(dev, &port->napi);
+	netif_rx_schedule(&port->napi);
 }
 
 static int eth_poll(struct napi_struct *napi, int budget)
@@ -526,7 +501,7 @@
 			printk(KERN_DEBUG "%s: eth_poll netif_rx_complete\n",
 			       dev->name);
 #endif
-			netif_rx_complete(dev, napi);
+			netif_rx_complete(napi);
 			qmgr_enable_irq(rxq);
 			if (!qmgr_stat_empty(rxq) &&
 			    netif_rx_reschedule(dev, napi)) {
@@ -562,7 +537,7 @@
 #endif
 
 		if (!skb) {
-			port->stat.rx_dropped++;
+			dev->stats.rx_dropped++;
 			/* put the desc back on RX-ready queue */
 			desc->buf_len = MAX_MRU;
 			desc->pkt_len = 0;
@@ -588,9 +563,8 @@
 		debug_pkt(dev, "eth_poll", skb->data, skb->len);
 
 		skb->protocol = eth_type_trans(skb, dev);
-		dev->last_rx = jiffies;
-		port->stat.rx_packets++;
-		port->stat.rx_bytes += skb->len;
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += skb->len;
 		netif_receive_skb(skb);
 
 		/* put the new buffer on RX-free queue */
@@ -618,7 +592,7 @@
 #if DEBUG_TX
 	printk(KERN_DEBUG DRV_NAME ": eth_txdone_irq\n");
 #endif
-	while ((phys = queue_get_entry(TXDONE_QUEUE)) != 0) {
+	while ((phys = qmgr_get_entry(TXDONE_QUEUE)) != 0) {
 		u32 npe_id, n_desc;
 		struct port *port;
 		struct desc *desc;
@@ -635,8 +609,8 @@
 		debug_desc(phys, desc);
 
 		if (port->tx_buff_tab[n_desc]) { /* not the draining packet */
-			port->stat.tx_packets++;
-			port->stat.tx_bytes += desc->pkt_len;
+			port->netdev->stats.tx_packets++;
+			port->netdev->stats.tx_bytes += desc->pkt_len;
 
 			dma_unmap_tx(port, desc);
 #if DEBUG_TX
@@ -674,7 +648,7 @@
 
 	if (unlikely(skb->len > MAX_MRU)) {
 		dev_kfree_skb(skb);
-		port->stat.tx_errors++;
+		dev->stats.tx_errors++;
 		return NETDEV_TX_OK;
 	}
 
@@ -690,7 +664,7 @@
 	bytes = ALIGN(offset + len, 4);
 	if (!(mem = kmalloc(bytes, GFP_ATOMIC))) {
 		dev_kfree_skb(skb);
-		port->stat.tx_dropped++;
+		dev->stats.tx_dropped++;
 		return NETDEV_TX_OK;
 	}
 	memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
@@ -704,7 +678,7 @@
 #else
 		kfree(mem);
 #endif
-		port->stat.tx_dropped++;
+		dev->stats.tx_dropped++;
 		return NETDEV_TX_OK;
 	}
 
@@ -747,12 +721,6 @@
 }
 
 
-static struct net_device_stats *eth_stats(struct net_device *dev)
-{
-	struct port *port = netdev_priv(dev);
-	return &port->stat;
-}
-
 static void eth_set_mcast_list(struct net_device *dev)
 {
 	struct port *port = netdev_priv(dev);
@@ -786,41 +754,80 @@
 static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
 {
 	struct port *port = netdev_priv(dev);
-	unsigned int duplex_chg;
-	int err;
 
 	if (!netif_running(dev))
 		return -EINVAL;
-	err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg);
-	if (duplex_chg)
-		eth_set_duplex(port);
-	return err;
+	return phy_mii_ioctl(port->phydev, if_mii(req), cmd);
 }
 
+/* ethtool support */
+
+static void ixp4xx_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
+{
+	struct port *port = netdev_priv(dev);
+	strcpy(info->driver, DRV_NAME);
+	snprintf(info->fw_version, sizeof(info->fw_version), "%u:%u:%u:%u",
+		 port->firmware[0], port->firmware[1],
+		 port->firmware[2], port->firmware[3]);
+	strcpy(info->bus_info, "internal");
+}
+
+static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct port *port = netdev_priv(dev);
+	return phy_ethtool_gset(port->phydev, cmd);
+}
+
+static int ixp4xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct port *port = netdev_priv(dev);
+	return phy_ethtool_sset(port->phydev, cmd);
+}
+
+static int ixp4xx_nway_reset(struct net_device *dev)
+{
+	struct port *port = netdev_priv(dev);
+	return phy_start_aneg(port->phydev);
+}
+
+static struct ethtool_ops ixp4xx_ethtool_ops = {
+	.get_drvinfo = ixp4xx_get_drvinfo,
+	.get_settings = ixp4xx_get_settings,
+	.set_settings = ixp4xx_set_settings,
+	.nway_reset = ixp4xx_nway_reset,
+	.get_link = ethtool_op_get_link,
+};
+
 
 static int request_queues(struct port *port)
 {
 	int err;
 
-	err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0);
+	err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0,
+			    "%s:RX-free", port->netdev->name);
 	if (err)
 		return err;
 
-	err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0);
+	err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0,
+			    "%s:RX", port->netdev->name);
 	if (err)
 		goto rel_rxfree;
 
-	err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0);
+	err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0,
+			    "%s:TX", port->netdev->name);
 	if (err)
 		goto rel_rx;
 
-	err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0);
+	err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0,
+			    "%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);
+		err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0,
+				    "%s:TX-done", DRV_NAME);
 		if (err)
 			goto rel_txready;
 	}
@@ -944,10 +951,12 @@
 			       npe_name(npe));
 			return -EIO;
 		}
+		port->firmware[0] = msg.byte4;
+		port->firmware[1] = msg.byte5;
+		port->firmware[2] = msg.byte6;
+		port->firmware[3] = msg.byte7;
 	}
 
-	mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr);
-
 	memset(&msg, 0, sizeof(msg));
 	msg.cmd = NPE_VLAN_SETRXQOSENTRY;
 	msg.eth_id = port->id;
@@ -985,6 +994,9 @@
 		return err;
 	}
 
+	port->speed = 0;	/* force "link up" message */
+	phy_start(port->phydev);
+
 	for (i = 0; i < ETH_ALEN; i++)
 		__raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]);
 	__raw_writel(0x08, &port->regs->random_seed);
@@ -1012,10 +1024,8 @@
 	__raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);
 
 	napi_enable(&port->napi);
-	phy_check_media(port, 1);
 	eth_set_mcast_list(dev);
 	netif_start_queue(dev);
-	schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL);
 
 	qmgr_set_irq(port->plat->rxq, QUEUE_IRQ_SRC_NOT_EMPTY,
 		     eth_rx_irq, dev);
@@ -1026,7 +1036,7 @@
 	}
 	ports_open++;
 	/* we may already have RX data, enables IRQ */
-	netif_rx_schedule(dev, &port->napi);
+	netif_rx_schedule(&port->napi);
 	return 0;
 }
 
@@ -1106,25 +1116,31 @@
 		printk(KERN_CRIT "%s: unable to disable loopback\n",
 		       dev->name);
 
-	port->mii_bmcr = mdio_read(dev, port->plat->phy, MII_BMCR) &
-		~(BMCR_RESET | BMCR_PDOWN); /* may have been altered */
-	mdio_write(dev, port->plat->phy, MII_BMCR,
-		   port->mii_bmcr | BMCR_PDOWN);
+	phy_stop(port->phydev);
 
 	if (!ports_open)
 		qmgr_disable_irq(TXDONE_QUEUE);
-	cancel_rearming_delayed_work(&port->mdio_thread);
 	destroy_queues(port);
 	release_queues(port);
 	return 0;
 }
 
+static const struct net_device_ops ixp4xx_netdev_ops = {
+	.ndo_open = eth_open,
+	.ndo_stop = eth_close,
+	.ndo_start_xmit = eth_xmit,
+	.ndo_set_multicast_list = eth_set_mcast_list,
+	.ndo_do_ioctl = eth_ioctl,
+
+};
+
 static int __devinit eth_init_one(struct platform_device *pdev)
 {
 	struct port *port;
 	struct net_device *dev;
 	struct eth_plat_info *plat = pdev->dev.platform_data;
 	u32 regs_phys;
+	char phy_id[BUS_ID_SIZE];
 	int err;
 
 	if (!(dev = alloc_etherdev(sizeof(struct port))))
@@ -1153,12 +1169,8 @@
 		goto err_free;
 	}
 
-	dev->open = eth_open;
-	dev->hard_start_xmit = eth_xmit;
-	dev->stop = eth_close;
-	dev->get_stats = eth_stats;
-	dev->do_ioctl = eth_ioctl;
-	dev->set_multicast_list = eth_set_mcast_list;
+	dev->netdev_ops = &ixp4xx_netdev_ops;
+	dev->ethtool_ops = &ixp4xx_ethtool_ops;
 	dev->tx_queue_len = 100;
 
 	netif_napi_add(dev, &port->napi, eth_poll, NAPI_WEIGHT);
@@ -1191,22 +1203,19 @@
 	__raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
 	udelay(50);
 
-	port->mii.dev = dev;
-	port->mii.mdio_read = mdio_read;
-	port->mii.mdio_write = mdio_write;
-	port->mii.phy_id = plat->phy;
-	port->mii.phy_id_mask = 0x1F;
-	port->mii.reg_num_mask = 0x1F;
+	snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, "0", plat->phy);
+	port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,
+				   PHY_INTERFACE_MODE_MII);
+	if (IS_ERR(port->phydev)) {
+		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+		return PTR_ERR(port->phydev);
+	}
+
+	port->phydev->irq = PHY_POLL;
 
 	printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
 	       npe_name(port->npe));
 
-	phy_reset(dev, plat->phy);
-	port->mii_bmcr = mdio_read(dev, plat->phy, MII_BMCR) &
-		~(BMCR_RESET | BMCR_PDOWN);
-	mdio_write(dev, plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN);
-
-	INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread);
 	return 0;
 
 err_unreg:
@@ -1232,7 +1241,7 @@
 	return 0;
 }
 
-static struct platform_driver drv = {
+static struct platform_driver ixp4xx_eth_driver = {
 	.driver.name	= DRV_NAME,
 	.probe		= eth_init_one,
 	.remove		= eth_remove_one,
@@ -1240,20 +1249,19 @@
 
 static int __init eth_init_module(void)
 {
+	int err;
 	if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
 		return -ENOSYS;
 
-	/* All MII PHY accesses use NPE-B Ethernet registers */
-	spin_lock_init(&mdio_lock);
-	mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
-	__raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
-
-	return platform_driver_register(&drv);
+	if ((err = ixp4xx_mdio_register()))
+		return err;
+	return platform_driver_register(&ixp4xx_eth_driver);
 }
 
 static void __exit eth_cleanup_module(void)
 {
-	platform_driver_unregister(&drv);
+	platform_driver_unregister(&ixp4xx_eth_driver);
+	ixp4xx_mdio_remove();
 }
 
 MODULE_AUTHOR("Krzysztof Halasa");
diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c
new file mode 100644
index 0000000..592daee
--- /dev/null
+++ b/drivers/net/arm/ks8695net.c
@@ -0,0 +1,1676 @@
+/*
+ * Micrel KS8695 (Centaur) Ethernet.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * General Public License for more details.
+ *
+ * Copyright 2008 Simtec Electronics
+ *		  Daniel Silverstone <dsilvers@simtec.co.uk>
+ *		  Vincent Sanders <vince@simtec.co.uk>
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+#include <mach/regs-switch.h>
+#include <mach/regs-misc.h>
+
+#include "ks8695net.h"
+
+#define MODULENAME	"ks8695_ether"
+#define MODULEVERSION	"1.01"
+
+/*
+ * Transmit and device reset timeout, default 5 seconds.
+ */
+static int watchdog = 5000;
+
+/* Hardware structures */
+
+/**
+ *	struct rx_ring_desc - Receive descriptor ring element
+ *	@status: The status of the descriptor element (E.g. who owns it)
+ *	@length: The number of bytes in the block pointed to by data_ptr
+ *	@data_ptr: The physical address of the data block to receive into
+ *	@next_desc: The physical address of the next descriptor element.
+ */
+struct rx_ring_desc {
+	__le32	status;
+	__le32	length;
+	__le32	data_ptr;
+	__le32	next_desc;
+};
+
+/**
+ *	struct tx_ring_desc - Transmit descriptor ring element
+ *	@owner: Who owns the descriptor
+ *	@status: The number of bytes in the block pointed to by data_ptr
+ *	@data_ptr: The physical address of the data block to receive into
+ *	@next_desc: The physical address of the next descriptor element.
+ */
+struct tx_ring_desc {
+	__le32	owner;
+	__le32	status;
+	__le32	data_ptr;
+	__le32	next_desc;
+};
+
+/**
+ *	struct ks8695_skbuff - sk_buff wrapper for rx/tx rings.
+ *	@skb: The buffer in the ring
+ *	@dma_ptr: The mapped DMA pointer of the buffer
+ *	@length: The number of bytes mapped to dma_ptr
+ */
+struct ks8695_skbuff {
+	struct sk_buff	*skb;
+	dma_addr_t	dma_ptr;
+	u32		length;
+};
+
+/* Private device structure */
+
+#define MAX_TX_DESC 8
+#define MAX_TX_DESC_MASK 0x7
+#define MAX_RX_DESC 16
+#define MAX_RX_DESC_MASK 0xf
+
+#define MAX_RXBUF_SIZE 0x700
+
+#define TX_RING_DMA_SIZE (sizeof(struct tx_ring_desc) * MAX_TX_DESC)
+#define RX_RING_DMA_SIZE (sizeof(struct rx_ring_desc) * MAX_RX_DESC)
+#define RING_DMA_SIZE (TX_RING_DMA_SIZE + RX_RING_DMA_SIZE)
+
+/**
+ *	enum ks8695_dtype - Device type
+ *	@KS8695_DTYPE_WAN: This device is a WAN interface
+ *	@KS8695_DTYPE_LAN: This device is a LAN interface
+ *	@KS8695_DTYPE_HPNA: This device is an HPNA interface
+ */
+enum ks8695_dtype {
+	KS8695_DTYPE_WAN,
+	KS8695_DTYPE_LAN,
+	KS8695_DTYPE_HPNA,
+};
+
+/**
+ *	struct ks8695_priv - Private data for the KS8695 Ethernet
+ *	@in_suspend: Flag to indicate if we're suspending/resuming
+ *	@ndev: The net_device for this interface
+ *	@dev: The platform device object for this interface
+ *	@dtype: The type of this device
+ *	@io_regs: The ioremapped registers for this interface
+ *	@rx_irq_name: The textual name of the RX IRQ from the platform data
+ *	@tx_irq_name: The textual name of the TX IRQ from the platform data
+ *	@link_irq_name: The textual name of the link IRQ from the
+ *			platform data if available
+ *	@rx_irq: The IRQ number for the RX IRQ
+ *	@tx_irq: The IRQ number for the TX IRQ
+ *	@link_irq: The IRQ number for the link IRQ if available
+ *	@regs_req: The resource request for the registers region
+ *	@phyiface_req: The resource request for the phy/switch region
+ *		       if available
+ *	@phyiface_regs: The ioremapped registers for the phy/switch if available
+ *	@ring_base: The base pointer of the dma coherent memory for the rings
+ *	@ring_base_dma: The DMA mapped equivalent of ring_base
+ *	@tx_ring: The pointer in ring_base of the TX ring
+ *	@tx_ring_used: The number of slots in the TX ring which are occupied
+ *	@tx_ring_next_slot: The next slot to fill in the TX ring
+ *	@tx_ring_dma: The DMA mapped equivalent of tx_ring
+ *	@tx_buffers: The sk_buff mappings for the TX ring
+ *	@txq_lock: A lock to protect the tx_buffers tx_ring_used etc variables
+ *	@rx_ring: The pointer in ring_base of the RX ring
+ *	@rx_ring_dma: The DMA mapped equivalent of rx_ring
+ *	@rx_buffers: The sk_buff mappings for the RX ring
+ *	@next_rx_desc_read: The next RX descriptor to read from on IRQ
+ *	@msg_enable: The flags for which messages to emit
+ */
+struct ks8695_priv {
+	int in_suspend;
+	struct net_device *ndev;
+	struct device *dev;
+	enum ks8695_dtype dtype;
+	void __iomem *io_regs;
+
+	const char *rx_irq_name, *tx_irq_name, *link_irq_name;
+	int rx_irq, tx_irq, link_irq;
+
+	struct resource *regs_req, *phyiface_req;
+	void __iomem *phyiface_regs;
+
+	void *ring_base;
+	dma_addr_t ring_base_dma;
+
+	struct tx_ring_desc *tx_ring;
+	int tx_ring_used;
+	int tx_ring_next_slot;
+	dma_addr_t tx_ring_dma;
+	struct ks8695_skbuff tx_buffers[MAX_TX_DESC];
+	spinlock_t txq_lock;
+
+	struct rx_ring_desc *rx_ring;
+	dma_addr_t rx_ring_dma;
+	struct ks8695_skbuff rx_buffers[MAX_RX_DESC];
+	int next_rx_desc_read;
+
+	int msg_enable;
+};
+
+/* Register access */
+
+/**
+ *	ks8695_readreg - Read from a KS8695 ethernet register
+ *	@ksp: The device to read from
+ *	@reg: The register to read
+ */
+static inline u32
+ks8695_readreg(struct ks8695_priv *ksp, int reg)
+{
+	return readl(ksp->io_regs + reg);
+}
+
+/**
+ *	ks8695_writereg - Write to a KS8695 ethernet register
+ *	@ksp: The device to write to
+ *	@reg: The register to write
+ *	@value: The value to write to the register
+ */
+static inline void
+ks8695_writereg(struct ks8695_priv *ksp, int reg, u32 value)
+{
+	writel(value, ksp->io_regs + reg);
+}
+
+/* Utility functions */
+
+/**
+ *	ks8695_port_type - Retrieve port-type as user-friendly string
+ *	@ksp: The device to return the type for
+ *
+ *	Returns a string indicating which of the WAN, LAN or HPNA
+ *	ports this device is likely to represent.
+ */
+static const char *
+ks8695_port_type(struct ks8695_priv *ksp)
+{
+	switch (ksp->dtype) {
+	case KS8695_DTYPE_LAN:
+		return "LAN";
+	case KS8695_DTYPE_WAN:
+		return "WAN";
+	case KS8695_DTYPE_HPNA:
+		return "HPNA";
+	}
+
+	return "UNKNOWN";
+}
+
+/**
+ *	ks8695_update_mac - Update the MAC registers in the device
+ *	@ksp: The device to update
+ *
+ *	Updates the MAC registers in the KS8695 device from the address in the
+ *	net_device structure associated with this interface.
+ */
+static void
+ks8695_update_mac(struct ks8695_priv *ksp)
+{
+	/* Update the HW with the MAC from the net_device */
+	struct net_device *ndev = ksp->ndev;
+	u32 machigh, maclow;
+
+	maclow	= ((ndev->dev_addr[2] << 24) | (ndev->dev_addr[3] << 16) |
+		   (ndev->dev_addr[4] <<  8) | (ndev->dev_addr[5] <<  0));
+	machigh = ((ndev->dev_addr[0] <<  8) | (ndev->dev_addr[1] <<  0));
+
+	ks8695_writereg(ksp, KS8695_MAL, maclow);
+	ks8695_writereg(ksp, KS8695_MAH, machigh);
+
+}
+
+/**
+ *	ks8695_refill_rxbuffers - Re-fill the RX buffer ring
+ *	@ksp: The device to refill
+ *
+ *	Iterates the RX ring of the device looking for empty slots.
+ *	For each empty slot, we allocate and map a new SKB and give it
+ *	to the hardware.
+ *	This can be called from interrupt context safely.
+ */
+static void
+ks8695_refill_rxbuffers(struct ks8695_priv *ksp)
+{
+	/* Run around the RX ring, filling in any missing sk_buff's */
+	int buff_n;
+
+	for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) {
+		if (!ksp->rx_buffers[buff_n].skb) {
+			struct sk_buff *skb = dev_alloc_skb(MAX_RXBUF_SIZE);
+			dma_addr_t mapping;
+
+			ksp->rx_buffers[buff_n].skb = skb;
+			if (skb == NULL) {
+				/* Failed to allocate one, perhaps
+				 * we'll try again later.
+				 */
+				break;
+			}
+
+			mapping = dma_map_single(ksp->dev, skb->data,
+						 MAX_RXBUF_SIZE,
+						 DMA_FROM_DEVICE);
+			if (unlikely(dma_mapping_error(ksp->dev, mapping))) {
+				/* Failed to DMA map this SKB, try later */
+				dev_kfree_skb_irq(skb);
+				ksp->rx_buffers[buff_n].skb = NULL;
+				break;
+			}
+			ksp->rx_buffers[buff_n].dma_ptr = mapping;
+			skb->dev = ksp->ndev;
+			ksp->rx_buffers[buff_n].length = MAX_RXBUF_SIZE;
+
+			/* Record this into the DMA ring */
+			ksp->rx_ring[buff_n].data_ptr = cpu_to_le32(mapping);
+			ksp->rx_ring[buff_n].length =
+				cpu_to_le32(MAX_RXBUF_SIZE);
+
+			wmb();
+
+			/* And give ownership over to the hardware */
+			ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN);
+		}
+	}
+}
+
+/* Maximum number of multicast addresses which the KS8695 HW supports */
+#define KS8695_NR_ADDRESSES	16
+
+/**
+ *	ks8695_init_partial_multicast - Init the mcast addr registers
+ *	@ksp: The device to initialise
+ *	@addr: The multicast address list to use
+ *	@nr_addr: The number of addresses in the list
+ *
+ *	This routine is a helper for ks8695_set_multicast - it writes
+ *	the additional-address registers in the KS8695 ethernet device
+ *	and cleans up any others left behind.
+ */
+static void
+ks8695_init_partial_multicast(struct ks8695_priv *ksp,
+			      struct dev_mc_list *addr,
+			      int nr_addr)
+{
+	u32 low, high;
+	int i;
+
+	for (i = 0; i < nr_addr; i++, addr = addr->next) {
+		/* Ran out of addresses? */
+		if (!addr)
+			break;
+		/* Ran out of space in chip? */
+		BUG_ON(i == KS8695_NR_ADDRESSES);
+
+		low = (addr->dmi_addr[2] << 24) | (addr->dmi_addr[3] << 16) |
+			(addr->dmi_addr[4] << 8) | (addr->dmi_addr[5]);
+		high = (addr->dmi_addr[0] << 8) | (addr->dmi_addr[1]);
+
+		ks8695_writereg(ksp, KS8695_AAL_(i), low);
+		ks8695_writereg(ksp, KS8695_AAH_(i), AAH_E | high);
+	}
+
+	/* Clear the remaining Additional Station Addresses */
+	for (; i < KS8695_NR_ADDRESSES; i++) {
+		ks8695_writereg(ksp, KS8695_AAL_(i), 0);
+		ks8695_writereg(ksp, KS8695_AAH_(i), 0);
+	}
+}
+
+/* Interrupt handling */
+
+/**
+ *	ks8695_tx_irq - Transmit IRQ handler
+ *	@irq: The IRQ which went off (ignored)
+ *	@dev_id: The net_device for the interrupt
+ *
+ *	Process the TX ring, clearing out any transmitted slots.
+ *	Allows the net_device to pass us new packets once slots are
+ *	freed.
+ */
+static irqreturn_t
+ks8695_tx_irq(int irq, void *dev_id)
+{
+	struct net_device *ndev = (struct net_device *)dev_id;
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	int buff_n;
+
+	for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) {
+		if (ksp->tx_buffers[buff_n].skb &&
+		    !(ksp->tx_ring[buff_n].owner & cpu_to_le32(TDES_OWN))) {
+			rmb();
+			/* An SKB which is not owned by HW is present */
+			/* Update the stats for the net_device */
+			ndev->stats.tx_packets++;
+			ndev->stats.tx_bytes += ksp->tx_buffers[buff_n].length;
+
+			/* Free the packet from the ring */
+			ksp->tx_ring[buff_n].data_ptr = 0;
+
+			/* Free the sk_buff */
+			dma_unmap_single(ksp->dev,
+					 ksp->tx_buffers[buff_n].dma_ptr,
+					 ksp->tx_buffers[buff_n].length,
+					 DMA_TO_DEVICE);
+			dev_kfree_skb_irq(ksp->tx_buffers[buff_n].skb);
+			ksp->tx_buffers[buff_n].skb = NULL;
+			ksp->tx_ring_used--;
+		}
+	}
+
+	netif_wake_queue(ndev);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ *	ks8695_rx_irq - Receive IRQ handler
+ *	@irq: The IRQ which went off (ignored)
+ *	@dev_id: The net_device for the interrupt
+ *
+ *	Process the RX ring, passing any received packets up to the
+ *	host.  If we received anything other than errors, we then
+ *	refill the ring.
+ */
+static irqreturn_t
+ks8695_rx_irq(int irq, void *dev_id)
+{
+	struct net_device *ndev = (struct net_device *)dev_id;
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	struct sk_buff *skb;
+	int buff_n;
+	u32 flags;
+	int pktlen;
+	int last_rx_processed = -1;
+
+	buff_n = ksp->next_rx_desc_read;
+	do {
+		if (ksp->rx_buffers[buff_n].skb &&
+		    !(ksp->rx_ring[buff_n].status & cpu_to_le32(RDES_OWN))) {
+			rmb();
+			flags = le32_to_cpu(ksp->rx_ring[buff_n].status);
+			/* Found an SKB which we own, this means we
+			 * received a packet
+			 */
+			if ((flags & (RDES_FS | RDES_LS)) !=
+			    (RDES_FS | RDES_LS)) {
+				/* This packet is not the first and
+				 * the last segment.  Therefore it is
+				 * a "spanning" packet and we can't
+				 * handle it
+				 */
+				goto rx_failure;
+			}
+
+			if (flags & (RDES_ES | RDES_RE)) {
+				/* It's an error packet */
+				ndev->stats.rx_errors++;
+				if (flags & RDES_TL)
+					ndev->stats.rx_length_errors++;
+				if (flags & RDES_RF)
+					ndev->stats.rx_length_errors++;
+				if (flags & RDES_CE)
+					ndev->stats.rx_crc_errors++;
+				if (flags & RDES_RE)
+					ndev->stats.rx_missed_errors++;
+
+				goto rx_failure;
+			}
+
+			pktlen = flags & RDES_FLEN;
+			pktlen -= 4; /* Drop the CRC */
+
+			/* Retrieve the sk_buff */
+			skb = ksp->rx_buffers[buff_n].skb;
+
+			/* Clear it from the ring */
+			ksp->rx_buffers[buff_n].skb = NULL;
+			ksp->rx_ring[buff_n].data_ptr = 0;
+
+			/* Unmap the SKB */
+			dma_unmap_single(ksp->dev,
+					 ksp->rx_buffers[buff_n].dma_ptr,
+					 ksp->rx_buffers[buff_n].length,
+					 DMA_FROM_DEVICE);
+
+			/* Relinquish the SKB to the network layer */
+			skb_put(skb, pktlen);
+			skb->protocol = eth_type_trans(skb, ndev);
+			netif_rx(skb);
+
+			/* Record stats */
+			ndev->last_rx = jiffies;
+			ndev->stats.rx_packets++;
+			ndev->stats.rx_bytes += pktlen;
+			goto rx_finished;
+
+rx_failure:
+			/* This ring entry is an error, but we can
+			 * re-use the skb
+			 */
+			/* Give the ring entry back to the hardware */
+			ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN);
+rx_finished:
+			/* And note this as processed so we can start
+			 * from here next time
+			 */
+			last_rx_processed = buff_n;
+		} else {
+			/* Ran out of things to process, stop now */
+			break;
+		}
+		buff_n = (buff_n + 1) & MAX_RX_DESC_MASK;
+	} while (buff_n != ksp->next_rx_desc_read);
+
+	/* And note which RX descriptor we last did anything with */
+	if (likely(last_rx_processed != -1))
+		ksp->next_rx_desc_read =
+			(last_rx_processed + 1) & MAX_RX_DESC_MASK;
+
+	/* And refill the buffers */
+	ks8695_refill_rxbuffers(ksp);
+
+	/* Kick the RX DMA engine, in case it became suspended */
+	ks8695_writereg(ksp, KS8695_DRSC, 0);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ *	ks8695_link_irq - Link change IRQ handler
+ *	@irq: The IRQ which went off (ignored)
+ *	@dev_id: The net_device for the interrupt
+ *
+ *	The WAN interface can generate an IRQ when the link changes,
+ *	report this to the net layer and the user.
+ */
+static irqreturn_t
+ks8695_link_irq(int irq, void *dev_id)
+{
+	struct net_device *ndev = (struct net_device *)dev_id;
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	u32 ctrl;
+
+	ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+	if (ctrl & WMC_WLS) {
+		netif_carrier_on(ndev);
+		if (netif_msg_link(ksp))
+			dev_info(ksp->dev,
+				 "%s: Link is now up (10%sMbps/%s-duplex)\n",
+				 ndev->name,
+				 (ctrl & WMC_WSS) ? "0" : "",
+				 (ctrl & WMC_WDS) ? "Full" : "Half");
+	} else {
+		netif_carrier_off(ndev);
+		if (netif_msg_link(ksp))
+			dev_info(ksp->dev, "%s: Link is now down.\n",
+				 ndev->name);
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+/* KS8695 Device functions */
+
+/**
+ *	ks8695_reset - Reset a KS8695 ethernet interface
+ *	@ksp: The interface to reset
+ *
+ *	Perform an engine reset of the interface and re-program it
+ *	with sensible defaults.
+ */
+static void
+ks8695_reset(struct ks8695_priv *ksp)
+{
+	int reset_timeout = watchdog;
+	/* Issue the reset via the TX DMA control register */
+	ks8695_writereg(ksp, KS8695_DTXC, DTXC_TRST);
+	while (reset_timeout--) {
+		if (!(ks8695_readreg(ksp, KS8695_DTXC) & DTXC_TRST))
+			break;
+		msleep(1);
+	}
+
+	if (reset_timeout == 0) {
+		dev_crit(ksp->dev,
+			 "Timeout waiting for DMA engines to reset\n");
+		/* And blithely carry on */
+	}
+
+	/* Definitely wait long enough before attempting to program
+	 * the engines
+	 */
+	msleep(10);
+
+	/* RX: unicast and broadcast */
+	ks8695_writereg(ksp, KS8695_DRXC, DRXC_RU | DRXC_RB);
+	/* TX: pad and add CRC */
+	ks8695_writereg(ksp, KS8695_DTXC, DTXC_TEP | DTXC_TAC);
+}
+
+/**
+ *	ks8695_shutdown - Shut down a KS8695 ethernet interface
+ *	@ksp: The interface to shut down
+ *
+ *	This disables packet RX/TX, cleans up IRQs, drains the rings,
+ *	and basically places the interface into a clean shutdown
+ *	state.
+ */
+static void
+ks8695_shutdown(struct ks8695_priv *ksp)
+{
+	u32 ctrl;
+	int buff_n;
+
+	/* Disable packet transmission */
+	ctrl = ks8695_readreg(ksp, KS8695_DTXC);
+	ks8695_writereg(ksp, KS8695_DTXC, ctrl & ~DTXC_TE);
+
+	/* Disable packet reception */
+	ctrl = ks8695_readreg(ksp, KS8695_DRXC);
+	ks8695_writereg(ksp, KS8695_DRXC, ctrl & ~DRXC_RE);
+
+	/* Release the IRQs */
+	free_irq(ksp->rx_irq, ksp->ndev);
+	free_irq(ksp->tx_irq, ksp->ndev);
+	if (ksp->link_irq != -1)
+		free_irq(ksp->link_irq, ksp->ndev);
+
+	/* Throw away any pending TX packets */
+	for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) {
+		if (ksp->tx_buffers[buff_n].skb) {
+			/* Remove this SKB from the TX ring */
+			ksp->tx_ring[buff_n].owner = 0;
+			ksp->tx_ring[buff_n].status = 0;
+			ksp->tx_ring[buff_n].data_ptr = 0;
+
+			/* Unmap and bin this SKB */
+			dma_unmap_single(ksp->dev,
+					 ksp->tx_buffers[buff_n].dma_ptr,
+					 ksp->tx_buffers[buff_n].length,
+					 DMA_TO_DEVICE);
+			dev_kfree_skb_irq(ksp->tx_buffers[buff_n].skb);
+			ksp->tx_buffers[buff_n].skb = NULL;
+		}
+	}
+
+	/* Purge the RX buffers */
+	for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) {
+		if (ksp->rx_buffers[buff_n].skb) {
+			/* Remove the SKB from the RX ring */
+			ksp->rx_ring[buff_n].status = 0;
+			ksp->rx_ring[buff_n].data_ptr = 0;
+
+			/* Unmap and bin the SKB */
+			dma_unmap_single(ksp->dev,
+					 ksp->rx_buffers[buff_n].dma_ptr,
+					 ksp->rx_buffers[buff_n].length,
+					 DMA_FROM_DEVICE);
+			dev_kfree_skb_irq(ksp->rx_buffers[buff_n].skb);
+			ksp->rx_buffers[buff_n].skb = NULL;
+		}
+	}
+}
+
+
+/**
+ *	ks8695_setup_irq - IRQ setup helper function
+ *	@irq: The IRQ number to claim
+ *	@irq_name: The name to give the IRQ claimant
+ *	@handler: The function to call to handle the IRQ
+ *	@ndev: The net_device to pass in as the dev_id argument to the handler
+ *
+ *	Return 0 on success.
+ */
+static int
+ks8695_setup_irq(int irq, const char *irq_name,
+		 irq_handler_t handler, struct net_device *ndev)
+{
+	int ret;
+
+	ret = request_irq(irq, handler, IRQF_SHARED, irq_name, ndev);
+
+	if (ret) {
+		dev_err(&ndev->dev, "failure to request IRQ %d\n", irq);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ *	ks8695_init_net - Initialise a KS8695 ethernet interface
+ *	@ksp: The interface to initialise
+ *
+ *	This routine fills the RX ring, initialises the DMA engines,
+ *	allocates the IRQs and then starts the packet TX and RX
+ *	engines.
+ */
+static int
+ks8695_init_net(struct ks8695_priv *ksp)
+{
+	int ret;
+	u32 ctrl;
+
+	ks8695_refill_rxbuffers(ksp);
+
+	/* Initialise the DMA engines */
+	ks8695_writereg(ksp, KS8695_RDLB, (u32) ksp->rx_ring_dma);
+	ks8695_writereg(ksp, KS8695_TDLB, (u32) ksp->tx_ring_dma);
+
+	/* Request the IRQs */
+	ret = ks8695_setup_irq(ksp->rx_irq, ksp->rx_irq_name,
+			       ks8695_rx_irq, ksp->ndev);
+	if (ret)
+		return ret;
+	ret = ks8695_setup_irq(ksp->tx_irq, ksp->tx_irq_name,
+			       ks8695_tx_irq, ksp->ndev);
+	if (ret)
+		return ret;
+	if (ksp->link_irq != -1) {
+		ret = ks8695_setup_irq(ksp->link_irq, ksp->link_irq_name,
+				       ks8695_link_irq, ksp->ndev);
+		if (ret)
+			return ret;
+	}
+
+	/* Set up the ring indices */
+	ksp->next_rx_desc_read = 0;
+	ksp->tx_ring_next_slot = 0;
+	ksp->tx_ring_used = 0;
+
+	/* Bring up transmission */
+	ctrl = ks8695_readreg(ksp, KS8695_DTXC);
+	/* Enable packet transmission */
+	ks8695_writereg(ksp, KS8695_DTXC, ctrl | DTXC_TE);
+
+	/* Bring up the reception */
+	ctrl = ks8695_readreg(ksp, KS8695_DRXC);
+	/* Enable packet reception */
+	ks8695_writereg(ksp, KS8695_DRXC, ctrl | DRXC_RE);
+	/* And start the DMA engine */
+	ks8695_writereg(ksp, KS8695_DRSC, 0);
+
+	/* All done */
+	return 0;
+}
+
+/**
+ *	ks8695_release_device - HW resource release for KS8695 e-net
+ *	@ksp: The device to be freed
+ *
+ *	This unallocates io memory regions, dma-coherent regions etc
+ *	which were allocated in ks8695_probe.
+ */
+static void
+ks8695_release_device(struct ks8695_priv *ksp)
+{
+	/* Unmap the registers */
+	iounmap(ksp->io_regs);
+	if (ksp->phyiface_regs)
+		iounmap(ksp->phyiface_regs);
+
+	/* And release the request */
+	release_resource(ksp->regs_req);
+	kfree(ksp->regs_req);
+	if (ksp->phyiface_req) {
+		release_resource(ksp->phyiface_req);
+		kfree(ksp->phyiface_req);
+	}
+
+	/* Free the ring buffers */
+	dma_free_coherent(ksp->dev, RING_DMA_SIZE,
+			  ksp->ring_base, ksp->ring_base_dma);
+}
+
+/* Ethtool support */
+
+/**
+ *	ks8695_get_msglevel - Get the messages enabled for emission
+ *	@ndev: The network device to read from
+ */
+static u32
+ks8695_get_msglevel(struct net_device *ndev)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+
+	return ksp->msg_enable;
+}
+
+/**
+ *	ks8695_set_msglevel - Set the messages enabled for emission
+ *	@ndev: The network device to configure
+ *	@value: The messages to set for emission
+ */
+static void
+ks8695_set_msglevel(struct net_device *ndev, u32 value)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+
+	ksp->msg_enable = value;
+}
+
+/**
+ *	ks8695_get_settings - Get device-specific settings.
+ *	@ndev: The network device to read settings from
+ *	@cmd: The ethtool structure to read into
+ */
+static int
+ks8695_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	u32 ctrl;
+
+	/* All ports on the KS8695 support these... */
+	cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+			  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+			  SUPPORTED_TP | SUPPORTED_MII);
+	cmd->transceiver = XCVR_INTERNAL;
+
+	/* Port specific extras */
+	switch (ksp->dtype) {
+	case KS8695_DTYPE_HPNA:
+		cmd->phy_address = 0;
+		/* not supported for HPNA */
+		cmd->autoneg = AUTONEG_DISABLE;
+
+		/* BUG: Erm, dtype hpna implies no phy regs */
+		/*
+		ctrl = readl(KS8695_MISC_VA + KS8695_HMC);
+		cmd->speed = (ctrl & HMC_HSS) ? SPEED_100 : SPEED_10;
+		cmd->duplex = (ctrl & HMC_HDS) ? DUPLEX_FULL : DUPLEX_HALF;
+		*/
+		return -EOPNOTSUPP;
+	case KS8695_DTYPE_WAN:
+		cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+		cmd->port = PORT_MII;
+		cmd->supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause);
+		cmd->phy_address = 0;
+
+		ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+		if ((ctrl & WMC_WAND) == 0) {
+			/* auto-negotiation is enabled */
+			cmd->advertising |= ADVERTISED_Autoneg;
+			if (ctrl & WMC_WANA100F)
+				cmd->advertising |= ADVERTISED_100baseT_Full;
+			if (ctrl & WMC_WANA100H)
+				cmd->advertising |= ADVERTISED_100baseT_Half;
+			if (ctrl & WMC_WANA10F)
+				cmd->advertising |= ADVERTISED_10baseT_Full;
+			if (ctrl & WMC_WANA10H)
+				cmd->advertising |= ADVERTISED_10baseT_Half;
+			if (ctrl & WMC_WANAP)
+				cmd->advertising |= ADVERTISED_Pause;
+			cmd->autoneg = AUTONEG_ENABLE;
+
+			cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10;
+			cmd->duplex = (ctrl & WMC_WDS) ?
+				DUPLEX_FULL : DUPLEX_HALF;
+		} else {
+			/* auto-negotiation is disabled */
+			cmd->autoneg = AUTONEG_DISABLE;
+
+			cmd->speed = (ctrl & WMC_WANF100) ?
+				SPEED_100 : SPEED_10;
+			cmd->duplex = (ctrl & WMC_WANFF) ?
+				DUPLEX_FULL : DUPLEX_HALF;
+		}
+		break;
+	case KS8695_DTYPE_LAN:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+/**
+ *	ks8695_set_settings - Set device-specific settings.
+ *	@ndev: The network device to configure
+ *	@cmd: The settings to configure
+ */
+static int
+ks8695_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	u32 ctrl;
+
+	if ((cmd->speed != SPEED_10) && (cmd->speed != SPEED_100))
+		return -EINVAL;
+	if ((cmd->duplex != DUPLEX_HALF) && (cmd->duplex != DUPLEX_FULL))
+		return -EINVAL;
+	if (cmd->port != PORT_MII)
+		return -EINVAL;
+	if (cmd->transceiver != XCVR_INTERNAL)
+		return -EINVAL;
+	if ((cmd->autoneg != AUTONEG_DISABLE) &&
+	    (cmd->autoneg != AUTONEG_ENABLE))
+		return -EINVAL;
+
+	if (cmd->autoneg == AUTONEG_ENABLE) {
+		if ((cmd->advertising & (ADVERTISED_10baseT_Half |
+				ADVERTISED_10baseT_Full |
+				ADVERTISED_100baseT_Half |
+				ADVERTISED_100baseT_Full)) == 0)
+			return -EINVAL;
+
+		switch (ksp->dtype) {
+		case KS8695_DTYPE_HPNA:
+			/* HPNA does not support auto-negotiation. */
+			return -EINVAL;
+		case KS8695_DTYPE_WAN:
+			ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+
+			ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H |
+				  WMC_WANA10F | WMC_WANA10H);
+			if (cmd->advertising & ADVERTISED_100baseT_Full)
+				ctrl |= WMC_WANA100F;
+			if (cmd->advertising & ADVERTISED_100baseT_Half)
+				ctrl |= WMC_WANA100H;
+			if (cmd->advertising & ADVERTISED_10baseT_Full)
+				ctrl |= WMC_WANA10F;
+			if (cmd->advertising & ADVERTISED_10baseT_Half)
+				ctrl |= WMC_WANA10H;
+
+			/* force a re-negotiation */
+			ctrl |= WMC_WANR;
+			writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
+			break;
+		case KS8695_DTYPE_LAN:
+			return -EOPNOTSUPP;
+		}
+
+	} else {
+		switch (ksp->dtype) {
+		case KS8695_DTYPE_HPNA:
+			/* BUG: dtype_hpna implies no phy registers */
+			/*
+			ctrl = __raw_readl(KS8695_MISC_VA + KS8695_HMC);
+
+			ctrl &= ~(HMC_HSS | HMC_HDS);
+			if (cmd->speed == SPEED_100)
+				ctrl |= HMC_HSS;
+			if (cmd->duplex == DUPLEX_FULL)
+				ctrl |= HMC_HDS;
+
+			__raw_writel(ctrl, KS8695_MISC_VA + KS8695_HMC);
+			*/
+			return -EOPNOTSUPP;
+		case KS8695_DTYPE_WAN:
+			ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+
+			/* disable auto-negotiation */
+			ctrl |= WMC_WAND;
+			ctrl &= ~(WMC_WANF100 | WMC_WANFF);
+
+			if (cmd->speed == SPEED_100)
+				ctrl |= WMC_WANF100;
+			if (cmd->duplex == DUPLEX_FULL)
+				ctrl |= WMC_WANFF;
+
+			writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
+			break;
+		case KS8695_DTYPE_LAN:
+			return -EOPNOTSUPP;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *	ks8695_nwayreset - Restart the autonegotiation on the port.
+ *	@ndev: The network device to restart autoneotiation on
+ */
+static int
+ks8695_nwayreset(struct net_device *ndev)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	u32 ctrl;
+
+	switch (ksp->dtype) {
+	case KS8695_DTYPE_HPNA:
+		/* No phy means no autonegotiation on hpna */
+		return -EINVAL;
+	case KS8695_DTYPE_WAN:
+		ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+
+		if ((ctrl & WMC_WAND) == 0)
+			writel(ctrl | WMC_WANR,
+			       ksp->phyiface_regs + KS8695_WMC);
+		else
+			/* auto-negotiation not enabled */
+			return -EINVAL;
+		break;
+	case KS8695_DTYPE_LAN:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+/**
+ *	ks8695_get_link - Retrieve link status of network interface
+ *	@ndev: The network interface to retrive the link status of.
+ */
+static u32
+ks8695_get_link(struct net_device *ndev)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	u32 ctrl;
+
+	switch (ksp->dtype) {
+	case KS8695_DTYPE_HPNA:
+		/* HPNA always has link */
+		return 1;
+	case KS8695_DTYPE_WAN:
+		/* WAN we can read the PHY for */
+		ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+		return ctrl & WMC_WLS;
+	case KS8695_DTYPE_LAN:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+/**
+ *	ks8695_get_pause - Retrieve network pause/flow-control advertising
+ *	@ndev: The device to retrieve settings from
+ *	@param: The structure to fill out with the information
+ */
+static void
+ks8695_get_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	u32 ctrl;
+
+	switch (ksp->dtype) {
+	case KS8695_DTYPE_HPNA:
+		/* No phy link on hpna to configure */
+		return;
+	case KS8695_DTYPE_WAN:
+		ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+
+		/* advertise Pause */
+		param->autoneg = (ctrl & WMC_WANAP);
+
+		/* current Rx Flow-control */
+		ctrl = ks8695_readreg(ksp, KS8695_DRXC);
+		param->rx_pause = (ctrl & DRXC_RFCE);
+
+		/* current Tx Flow-control */
+		ctrl = ks8695_readreg(ksp, KS8695_DTXC);
+		param->tx_pause = (ctrl & DTXC_TFCE);
+		break;
+	case KS8695_DTYPE_LAN:
+		/* The LAN's "phy" is a direct-attached switch */
+		return;
+	}
+}
+
+/**
+ *	ks8695_set_pause - Configure pause/flow-control
+ *	@ndev: The device to configure
+ *	@param: The pause parameters to set
+ *
+ *	TODO: Implement this
+ */
+static int
+ks8695_set_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
+{
+	return -EOPNOTSUPP;
+}
+
+/**
+ *	ks8695_get_drvinfo - Retrieve driver information
+ *	@ndev: The network device to retrieve info about
+ *	@info: The info structure to fill out.
+ */
+static void
+ks8695_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, MODULENAME, sizeof(info->driver));
+	strlcpy(info->version, MODULEVERSION, sizeof(info->version));
+	strlcpy(info->bus_info, ndev->dev.parent->bus_id,
+		sizeof(info->bus_info));
+}
+
+static struct ethtool_ops ks8695_ethtool_ops = {
+	.get_msglevel	= ks8695_get_msglevel,
+	.set_msglevel	= ks8695_set_msglevel,
+	.get_settings	= ks8695_get_settings,
+	.set_settings	= ks8695_set_settings,
+	.nway_reset	= ks8695_nwayreset,
+	.get_link	= ks8695_get_link,
+	.get_pauseparam = ks8695_get_pause,
+	.set_pauseparam = ks8695_set_pause,
+	.get_drvinfo	= ks8695_get_drvinfo,
+};
+
+/* Network device interface functions */
+
+/**
+ *	ks8695_set_mac - Update MAC in net dev and HW
+ *	@ndev: The network device to update
+ *	@addr: The new MAC address to set
+ */
+static int
+ks8695_set_mac(struct net_device *ndev, void *addr)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	struct sockaddr *address = addr;
+
+	if (!is_valid_ether_addr(address->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(ndev->dev_addr, address->sa_data, ndev->addr_len);
+
+	ks8695_update_mac(ksp);
+
+	dev_dbg(ksp->dev, "%s: Updated MAC address to %pM\n",
+		ndev->name, ndev->dev_addr);
+
+	return 0;
+}
+
+/**
+ *	ks8695_set_multicast - Set up the multicast behaviour of the interface
+ *	@ndev: The net_device to configure
+ *
+ *	This routine, called by the net layer, configures promiscuity
+ *	and multicast reception behaviour for the interface.
+ */
+static void
+ks8695_set_multicast(struct net_device *ndev)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	u32 ctrl;
+
+	ctrl = ks8695_readreg(ksp, KS8695_DRXC);
+
+	if (ndev->flags & IFF_PROMISC) {
+		/* enable promiscuous mode */
+		ctrl |= DRXC_RA;
+	} else if (ndev->flags & ~IFF_PROMISC) {
+		/* disable promiscuous mode */
+		ctrl &= ~DRXC_RA;
+	}
+
+	if (ndev->flags & IFF_ALLMULTI) {
+		/* enable all multicast mode */
+		ctrl |= DRXC_RM;
+	} else if (ndev->mc_count > KS8695_NR_ADDRESSES) {
+		/* more specific multicast addresses than can be
+		 * handled in hardware
+		 */
+		ctrl |= DRXC_RM;
+	} else {
+		/* enable specific multicasts */
+		ctrl &= ~DRXC_RM;
+		ks8695_init_partial_multicast(ksp, ndev->mc_list,
+					      ndev->mc_count);
+	}
+
+	ks8695_writereg(ksp, KS8695_DRXC, ctrl);
+}
+
+/**
+ *	ks8695_timeout - Handle a network tx/rx timeout.
+ *	@ndev: The net_device which timed out.
+ *
+ *	A network transaction timed out, reset the device.
+ */
+static void
+ks8695_timeout(struct net_device *ndev)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+
+	netif_stop_queue(ndev);
+	ks8695_shutdown(ksp);
+
+	ks8695_reset(ksp);
+
+	ks8695_update_mac(ksp);
+
+	/* We ignore the return from this since it managed to init
+	 * before it probably will be okay to init again.
+	 */
+	ks8695_init_net(ksp);
+
+	/* Reconfigure promiscuity etc */
+	ks8695_set_multicast(ndev);
+
+	/* And start the TX queue once more */
+	netif_start_queue(ndev);
+}
+
+/**
+ *	ks8695_start_xmit - Start a packet transmission
+ *	@skb: The packet to transmit
+ *	@ndev: The network device to send the packet on
+ *
+ *	This routine, called by the net layer, takes ownership of the
+ *	sk_buff and adds it to the TX ring. It then kicks the TX DMA
+ *	engine to ensure transmission begins.
+ */
+static int
+ks8695_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	int buff_n;
+	dma_addr_t dmap;
+
+	spin_lock_irq(&ksp->txq_lock);
+
+	if (ksp->tx_ring_used == MAX_TX_DESC) {
+		/* Somehow we got entered when we have no room */
+		spin_unlock_irq(&ksp->txq_lock);
+		return NETDEV_TX_BUSY;
+	}
+
+	buff_n = ksp->tx_ring_next_slot;
+
+	BUG_ON(ksp->tx_buffers[buff_n].skb);
+
+	dmap = dma_map_single(ksp->dev, skb->data, skb->len, DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(ksp->dev, dmap))) {
+		/* Failed to DMA map this SKB, give it back for now */
+		spin_unlock_irq(&ksp->txq_lock);
+		dev_dbg(ksp->dev, "%s: Could not map DMA memory for "\
+			"transmission, trying later\n", ndev->name);
+		return NETDEV_TX_BUSY;
+	}
+
+	ksp->tx_buffers[buff_n].dma_ptr = dmap;
+	/* Mapped okay, store the buffer pointer and length for later */
+	ksp->tx_buffers[buff_n].skb = skb;
+	ksp->tx_buffers[buff_n].length = skb->len;
+
+	/* Fill out the TX descriptor */
+	ksp->tx_ring[buff_n].data_ptr =
+		cpu_to_le32(ksp->tx_buffers[buff_n].dma_ptr);
+	ksp->tx_ring[buff_n].status =
+		cpu_to_le32(TDES_IC | TDES_FS | TDES_LS |
+			    (skb->len & TDES_TBS));
+
+	wmb();
+
+	/* Hand it over to the hardware */
+	ksp->tx_ring[buff_n].owner = cpu_to_le32(TDES_OWN);
+
+	if (++ksp->tx_ring_used == MAX_TX_DESC)
+		netif_stop_queue(ndev);
+
+	ndev->trans_start = jiffies;
+
+	/* Kick the TX DMA in case it decided to go IDLE */
+	ks8695_writereg(ksp, KS8695_DTSC, 0);
+
+	/* And update the next ring slot */
+	ksp->tx_ring_next_slot = (buff_n + 1) & MAX_TX_DESC_MASK;
+
+	spin_unlock_irq(&ksp->txq_lock);
+	return NETDEV_TX_OK;
+}
+
+/**
+ *	ks8695_stop - Stop (shutdown) a KS8695 ethernet interface
+ *	@ndev: The net_device to stop
+ *
+ *	This disables the TX queue and cleans up a KS8695 ethernet
+ *	device.
+ */
+static int
+ks8695_stop(struct net_device *ndev)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+
+	netif_stop_queue(ndev);
+	netif_carrier_off(ndev);
+
+	ks8695_shutdown(ksp);
+
+	return 0;
+}
+
+/**
+ *	ks8695_open - Open (bring up) a KS8695 ethernet interface
+ *	@ndev: The net_device to open
+ *
+ *	This resets, configures the MAC, initialises the RX ring and
+ *	DMA engines and starts the TX queue for a KS8695 ethernet
+ *	device.
+ */
+static int
+ks8695_open(struct net_device *ndev)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	int ret;
+
+	if (!is_valid_ether_addr(ndev->dev_addr))
+		return -EADDRNOTAVAIL;
+
+	ks8695_reset(ksp);
+
+	ks8695_update_mac(ksp);
+
+	ret = ks8695_init_net(ksp);
+	if (ret) {
+		ks8695_shutdown(ksp);
+		return ret;
+	}
+
+	netif_start_queue(ndev);
+
+	return 0;
+}
+
+/* Platform device driver */
+
+/**
+ *	ks8695_init_switch - Init LAN switch to known good defaults.
+ *	@ksp: The device to initialise
+ *
+ *	This initialises the LAN switch in the KS8695 to a known-good
+ *	set of defaults.
+ */
+static void __devinit
+ks8695_init_switch(struct ks8695_priv *ksp)
+{
+	u32 ctrl;
+
+	/* Default value for SEC0 according to datasheet */
+	ctrl = 0x40819e00;
+
+	/* LED0 = Speed	 LED1 = Link/Activity */
+	ctrl &= ~(SEC0_LLED1S | SEC0_LLED0S);
+	ctrl |= (LLED0S_LINK | LLED1S_LINK_ACTIVITY);
+
+	/* Enable Switch */
+	ctrl |= SEC0_ENABLE;
+
+	writel(ctrl, ksp->phyiface_regs + KS8695_SEC0);
+
+	/* Defaults for SEC1 */
+	writel(0x9400100, ksp->phyiface_regs + KS8695_SEC1);
+}
+
+/**
+ *	ks8695_init_wan_phy - Initialise the WAN PHY to sensible defaults
+ *	@ksp: The device to initialise
+ *
+ *	This initialises a KS8695's WAN phy to sensible values for
+ *	autonegotiation etc.
+ */
+static void __devinit
+ks8695_init_wan_phy(struct ks8695_priv *ksp)
+{
+	u32 ctrl;
+
+	/* Support auto-negotiation */
+	ctrl = (WMC_WANAP | WMC_WANA100F | WMC_WANA100H |
+		WMC_WANA10F | WMC_WANA10H);
+
+	/* LED0 = Activity , LED1 = Link */
+	ctrl |= (WLED0S_ACTIVITY | WLED1S_LINK);
+
+	/* Restart Auto-negotiation */
+	ctrl |= WMC_WANR;
+
+	writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
+
+	writel(0, ksp->phyiface_regs + KS8695_WPPM);
+	writel(0, ksp->phyiface_regs + KS8695_PPS);
+}
+
+static const struct net_device_ops ks8695_netdev_ops = {
+	.ndo_open		= ks8695_open,
+	.ndo_stop		= ks8695_stop,
+	.ndo_start_xmit		= ks8695_start_xmit,
+	.ndo_tx_timeout		= ks8695_timeout,
+	.ndo_set_mac_address	= ks8695_set_mac,
+	.ndo_set_multicast_list	= ks8695_set_multicast,
+};
+
+/**
+ *	ks8695_probe - Probe and initialise a KS8695 ethernet interface
+ *	@pdev: The platform device to probe
+ *
+ *	Initialise a KS8695 ethernet device from platform data.
+ *
+ *	This driver requires at least one IORESOURCE_MEM for the
+ *	registers and two IORESOURCE_IRQ for the RX and TX IRQs
+ *	respectively. It can optionally take an additional
+ *	IORESOURCE_MEM for the switch or phy in the case of the lan or
+ *	wan ports, and an IORESOURCE_IRQ for the link IRQ for the wan
+ *	port.
+ */
+static int __devinit
+ks8695_probe(struct platform_device *pdev)
+{
+	struct ks8695_priv *ksp;
+	struct net_device *ndev;
+	struct resource *regs_res, *phyiface_res;
+	struct resource *rxirq_res, *txirq_res, *linkirq_res;
+	int ret = 0;
+	int buff_n;
+	u32 machigh, maclow;
+
+	/* Initialise a net_device */
+	ndev = alloc_etherdev(sizeof(struct ks8695_priv));
+	if (!ndev) {
+		dev_err(&pdev->dev, "could not allocate device.\n");
+		return -ENOMEM;
+	}
+
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+
+	dev_dbg(&pdev->dev, "ks8695_probe() called\n");
+
+	/* Configure our private structure a little */
+	ksp = netdev_priv(ndev);
+	memset(ksp, 0, sizeof(struct ks8695_priv));
+
+	ksp->dev = &pdev->dev;
+	ksp->ndev = ndev;
+	ksp->msg_enable = NETIF_MSG_LINK;
+
+	/* Retrieve resources */
+	regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	phyiface_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+	rxirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	txirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+	linkirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+
+	if (!(regs_res && rxirq_res && txirq_res)) {
+		dev_err(ksp->dev, "insufficient resources\n");
+		ret = -ENOENT;
+		goto failure;
+	}
+
+	ksp->regs_req = request_mem_region(regs_res->start,
+					   resource_size(regs_res),
+					   pdev->name);
+
+	if (!ksp->regs_req) {
+		dev_err(ksp->dev, "cannot claim register space\n");
+		ret = -EIO;
+		goto failure;
+	}
+
+	ksp->io_regs = ioremap(regs_res->start, resource_size(regs_res));
+
+	if (!ksp->io_regs) {
+		dev_err(ksp->dev, "failed to ioremap registers\n");
+		ret = -EINVAL;
+		goto failure;
+	}
+
+	if (phyiface_res) {
+		ksp->phyiface_req =
+			request_mem_region(phyiface_res->start,
+					   resource_size(phyiface_res),
+					   phyiface_res->name);
+
+		if (!ksp->phyiface_req) {
+			dev_err(ksp->dev,
+				"cannot claim switch register space\n");
+			ret = -EIO;
+			goto failure;
+		}
+
+		ksp->phyiface_regs = ioremap(phyiface_res->start,
+					     resource_size(phyiface_res));
+
+		if (!ksp->phyiface_regs) {
+			dev_err(ksp->dev,
+				"failed to ioremap switch registers\n");
+			ret = -EINVAL;
+			goto failure;
+		}
+	}
+
+	ksp->rx_irq = rxirq_res->start;
+	ksp->rx_irq_name = rxirq_res->name ? rxirq_res->name : "Ethernet RX";
+	ksp->tx_irq = txirq_res->start;
+	ksp->tx_irq_name = txirq_res->name ? txirq_res->name : "Ethernet TX";
+	ksp->link_irq = (linkirq_res ? linkirq_res->start : -1);
+	ksp->link_irq_name = (linkirq_res && linkirq_res->name) ?
+		linkirq_res->name : "Ethernet Link";
+
+	/* driver system setup */
+	ndev->netdev_ops = &ks8695_netdev_ops;
+	SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
+	ndev->watchdog_timeo	 = msecs_to_jiffies(watchdog);
+
+	/* Retrieve the default MAC addr from the chip. */
+	/* The bootloader should have left it in there for us. */
+
+	machigh = ks8695_readreg(ksp, KS8695_MAH);
+	maclow = ks8695_readreg(ksp, KS8695_MAL);
+
+	ndev->dev_addr[0] = (machigh >> 8) & 0xFF;
+	ndev->dev_addr[1] = machigh & 0xFF;
+	ndev->dev_addr[2] = (maclow >> 24) & 0xFF;
+	ndev->dev_addr[3] = (maclow >> 16) & 0xFF;
+	ndev->dev_addr[4] = (maclow >> 8) & 0xFF;
+	ndev->dev_addr[5] = maclow & 0xFF;
+
+	if (!is_valid_ether_addr(ndev->dev_addr))
+		dev_warn(ksp->dev, "%s: Invalid ethernet MAC address. Please "
+			 "set using ifconfig\n", ndev->name);
+
+	/* In order to be efficient memory-wise, we allocate both
+	 * rings in one go.
+	 */
+	ksp->ring_base = dma_alloc_coherent(&pdev->dev, RING_DMA_SIZE,
+					    &ksp->ring_base_dma, GFP_KERNEL);
+	if (!ksp->ring_base) {
+		ret = -ENOMEM;
+		goto failure;
+	}
+
+	/* Specify the TX DMA ring buffer */
+	ksp->tx_ring = ksp->ring_base;
+	ksp->tx_ring_dma = ksp->ring_base_dma;
+
+	/* And initialise the queue's lock */
+	spin_lock_init(&ksp->txq_lock);
+
+	/* Specify the RX DMA ring buffer */
+	ksp->rx_ring = ksp->ring_base + TX_RING_DMA_SIZE;
+	ksp->rx_ring_dma = ksp->ring_base_dma + TX_RING_DMA_SIZE;
+
+	/* Zero the descriptor rings */
+	memset(ksp->tx_ring, 0, TX_RING_DMA_SIZE);
+	memset(ksp->rx_ring, 0, RX_RING_DMA_SIZE);
+
+	/* Build the rings */
+	for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) {
+		ksp->tx_ring[buff_n].next_desc =
+			cpu_to_le32(ksp->tx_ring_dma +
+				    (sizeof(struct tx_ring_desc) *
+				     ((buff_n + 1) & MAX_TX_DESC_MASK)));
+	}
+
+	for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) {
+		ksp->rx_ring[buff_n].next_desc =
+			cpu_to_le32(ksp->rx_ring_dma +
+				    (sizeof(struct rx_ring_desc) *
+				     ((buff_n + 1) & MAX_RX_DESC_MASK)));
+	}
+
+	/* Initialise the port (physically) */
+	if (ksp->phyiface_regs && ksp->link_irq == -1) {
+		ks8695_init_switch(ksp);
+		ksp->dtype = KS8695_DTYPE_LAN;
+	} else if (ksp->phyiface_regs && ksp->link_irq != -1) {
+		ks8695_init_wan_phy(ksp);
+		ksp->dtype = KS8695_DTYPE_WAN;
+	} else {
+		/* No initialisation since HPNA does not have a PHY */
+		ksp->dtype = KS8695_DTYPE_HPNA;
+	}
+
+	/* And bring up the net_device with the net core */
+	platform_set_drvdata(pdev, ndev);
+	ret = register_netdev(ndev);
+
+	if (ret == 0) {
+		dev_info(ksp->dev, "ks8695 ethernet (%s) MAC: %pM\n",
+			 ks8695_port_type(ksp), ndev->dev_addr);
+	} else {
+		/* Report the failure to register the net_device */
+		dev_err(ksp->dev, "ks8695net: failed to register netdev.\n");
+		goto failure;
+	}
+
+	/* All is well */
+	return 0;
+
+	/* Error exit path */
+failure:
+	ks8695_release_device(ksp);
+	free_netdev(ndev);
+
+	return ret;
+}
+
+/**
+ *	ks8695_drv_suspend - Suspend a KS8695 ethernet platform device.
+ *	@pdev: The device to suspend
+ *	@state: The suspend state
+ *
+ *	This routine detaches and shuts down a KS8695 ethernet device.
+ */
+static int
+ks8695_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+
+	ksp->in_suspend = 1;
+
+	if (netif_running(ndev)) {
+		netif_device_detach(ndev);
+		ks8695_shutdown(ksp);
+	}
+
+	return 0;
+}
+
+/**
+ *	ks8695_drv_resume - Resume a KS8695 ethernet platform device.
+ *	@pdev: The device to resume
+ *
+ *	This routine re-initialises and re-attaches a KS8695 ethernet
+ *	device.
+ */
+static int
+ks8695_drv_resume(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+
+	if (netif_running(ndev)) {
+		ks8695_reset(ksp);
+		ks8695_init_net(ksp);
+		ks8695_set_multicast(ndev);
+		netif_device_attach(ndev);
+	}
+
+	ksp->in_suspend = 0;
+
+	return 0;
+}
+
+/**
+ *	ks8695_drv_remove - Remove a KS8695 net device on driver unload.
+ *	@pdev: The platform device to remove
+ *
+ *	This unregisters and releases a KS8695 ethernet device.
+ */
+static int __devexit
+ks8695_drv_remove(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	unregister_netdev(ndev);
+	ks8695_release_device(ksp);
+	free_netdev(ndev);
+
+	dev_dbg(&pdev->dev, "released and freed device\n");
+	return 0;
+}
+
+static struct platform_driver ks8695_driver = {
+	.driver = {
+		.name	= MODULENAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ks8695_probe,
+	.remove		= __devexit_p(ks8695_drv_remove),
+	.suspend	= ks8695_drv_suspend,
+	.resume		= ks8695_drv_resume,
+};
+
+/* Module interface */
+
+static int __init
+ks8695_init(void)
+{
+	printk(KERN_INFO "%s Ethernet driver, V%s\n",
+	       MODULENAME, MODULEVERSION);
+
+	return platform_driver_register(&ks8695_driver);
+}
+
+static void __exit
+ks8695_cleanup(void)
+{
+	platform_driver_unregister(&ks8695_driver);
+}
+
+module_init(ks8695_init);
+module_exit(ks8695_cleanup);
+
+MODULE_AUTHOR("Simtec Electronics")
+MODULE_DESCRIPTION("Micrel KS8695 (Centaur) Ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" MODULENAME);
+
+module_param(watchdog, int, 0400);
+MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
diff --git a/drivers/net/arm/ks8695net.h b/drivers/net/arm/ks8695net.h
new file mode 100644
index 0000000..80eff6e
--- /dev/null
+++ b/drivers/net/arm/ks8695net.h
@@ -0,0 +1,107 @@
+/*
+ * Micrel KS8695 (Centaur) Ethernet.
+ *
+ * Copyright 2008 Simtec Electronics
+ *		  Daniel Silverstone <dsilvers@simtec.co.uk>
+ *		  Vincent Sanders <vince@simtec.co.uk>
+ */
+
+#ifndef KS8695NET_H
+#define KS8695NET_H
+
+/* Receive descriptor flags */
+#define RDES_OWN	(1 << 31)	/* Ownership */
+#define RDES_FS		(1 << 30)	/* First Descriptor */
+#define RDES_LS		(1 << 29)	/* Last Descriptor */
+#define RDES_IPE	(1 << 28)	/* IP Checksum error */
+#define RDES_TCPE	(1 << 27)	/* TCP Checksum error */
+#define RDES_UDPE	(1 << 26)	/* UDP Checksum error */
+#define RDES_ES		(1 << 25)	/* Error summary */
+#define RDES_MF		(1 << 24)	/* Multicast Frame */
+#define RDES_RE		(1 << 19)	/* MII Error reported */
+#define RDES_TL		(1 << 18)	/* Frame too Long */
+#define RDES_RF		(1 << 17)	/* Runt Frame */
+#define RDES_CE		(1 << 16)	/* CRC error */
+#define RDES_FT		(1 << 15)	/* Frame Type */
+#define RDES_FLEN	(0x7ff)		/* Frame Length */
+
+#define RDES_RER	(1 << 25)	/* Receive End of Ring */
+#define RDES_RBS	(0x7ff)		/* Receive Buffer Size */
+
+/* Transmit descriptor flags */
+
+#define TDES_OWN	(1 << 31)	/* Ownership */
+
+#define TDES_IC		(1 << 31)	/* Interrupt on Completion */
+#define TDES_FS		(1 << 30)	/* First Segment */
+#define TDES_LS		(1 << 29)	/* Last Segment */
+#define TDES_IPCKG	(1 << 28)	/* IP Checksum generate */
+#define TDES_TCPCKG	(1 << 27)	/* TCP Checksum generate */
+#define TDES_UDPCKG	(1 << 26)	/* UDP Checksum generate */
+#define TDES_TER	(1 << 25)	/* Transmit End of Ring */
+#define TDES_TBS	(0x7ff)		/* Transmit Buffer Size */
+
+/*
+ * Network controller register offsets
+ */
+#define KS8695_DTXC		(0x00)		/* DMA Transmit Control */
+#define KS8695_DRXC		(0x04)		/* DMA Receive Control */
+#define KS8695_DTSC		(0x08)		/* DMA Transmit Start Command */
+#define KS8695_DRSC		(0x0c)		/* DMA Receive Start Command */
+#define KS8695_TDLB		(0x10)		/* Transmit Descriptor List
+						 * Base Address
+						 */
+#define KS8695_RDLB		(0x14)		/* Receive Descriptor List
+						 * Base Address
+						 */
+#define KS8695_MAL		(0x18)		/* MAC Station Address Low */
+#define KS8695_MAH		(0x1c)		/* MAC Station Address High */
+#define KS8695_AAL_(n)		(0x80 + ((n)*8))	/* MAC Additional
+							 * Station Address
+							 * (0..15) Low
+							 */
+#define KS8695_AAH_(n)		(0x84 + ((n)*8))	/* MAC Additional
+							 * Station Address
+							 * (0..15) High
+							 */
+
+
+/* DMA Transmit Control Register */
+#define DTXC_TRST		(1    << 31)	/* Soft Reset */
+#define DTXC_TBS		(0x3f << 24)	/* Transmit Burst Size */
+#define DTXC_TUCG		(1    << 18)	/* Transmit UDP
+						 * Checksum Generate
+						 */
+#define DTXC_TTCG		(1    << 17)	/* Transmit TCP
+						 * Checksum Generate
+						 */
+#define DTXC_TICG		(1    << 16)	/* Transmit IP
+						 * Checksum Generate
+						 */
+#define DTXC_TFCE		(1    <<  9)	/* Transmit Flow
+						 * Control Enable
+						 */
+#define DTXC_TLB		(1    <<  8)	/* Loopback mode */
+#define DTXC_TEP		(1    <<  2)	/* Transmit Enable Padding */
+#define DTXC_TAC		(1    <<  1)	/* Transmit Add CRC */
+#define DTXC_TE			(1    <<  0)	/* TX Enable */
+
+/* DMA Receive Control Register */
+#define DRXC_RBS		(0x3f << 24)	/* Receive Burst Size */
+#define DRXC_RUCC		(1    << 18)	/* Receive UDP Checksum check */
+#define DRXC_RTCG		(1    << 17)	/* Receive TCP Checksum check */
+#define DRXC_RICG		(1    << 16)	/* Receive IP Checksum check */
+#define DRXC_RFCE		(1    <<  9)	/* Receive Flow Control
+						 * Enable
+						 */
+#define DRXC_RB			(1    <<  6)	/* Receive Broadcast */
+#define DRXC_RM			(1    <<  5)	/* Receive Multicast */
+#define DRXC_RU			(1    <<  4)	/* Receive Unicast */
+#define DRXC_RERR		(1    <<  3)	/* Receive Error Frame */
+#define DRXC_RA			(1    <<  2)	/* Receive All */
+#define DRXC_RE			(1    <<  0)	/* RX Enable */
+
+/* Additional Station Address High */
+#define AAH_E			(1    << 31)	/* Address Enabled */
+
+#endif /* KS8695NET_H */
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 7e874d4..72ea6e3 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -265,7 +265,6 @@
 	unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
 	int slot, ret = -ENODEV;
 	struct net_local *lp = netdev_priv(dev);
-	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -397,7 +396,7 @@
 			dev->dev_addr[i] = val;
 		}
 	}
-	printk("%s", print_mac(mac, dev->dev_addr));
+	printk("%pM", dev->dev_addr);
 
 	/* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals,
 	   rather than 150 ohm shielded twisted pair compensation.
@@ -768,7 +767,6 @@
 			insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);
 			skb->protocol=eth_type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += pkt_len;
 		}
@@ -901,15 +899,3 @@
 module_exit(at1700_module_exit);
 #endif /* MODULE */
 MODULE_LICENSE("GPL");
-
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c"
- *  alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c"
- *  tab-width: 4
- *  c-basic-offset: 4
- *  c-indent-level: 4
- * End:
- */
-
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index 0860cc280..2d81f6a 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -466,7 +466,6 @@
 	int 					i;
 	static int 				did_version;
 	unsigned short			save1, save2;
-	DECLARE_MAC_BUF(mac);
 
 	PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
 				  (long)memaddr, (long)ioaddr ));
@@ -521,7 +520,7 @@
 	return( 0 );
 
   probe_ok:
-	lp = (struct lance_private *)dev->priv;
+	lp = netdev_priv(dev);
 	MEM = (struct lance_memory *)memaddr;
 	IO = lp->iobase = (struct lance_ioreg *)ioaddr;
 	dev->base_addr = (unsigned long)ioaddr; /* informational only */
@@ -595,7 +594,7 @@
 		i = IO->mem;
 		break;
 	}
-	printk("%s\n", print_mac(mac, dev->dev_addr));
+	printk("%pM\n", dev->dev_addr);
 	if (lp->cardtype == OLD_RIEBL) {
 		printk( "%s: Warning: This is a default ethernet address!\n",
 				dev->name );
@@ -640,8 +639,8 @@
 
 
 static int lance_open( struct net_device *dev )
-
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{
+	struct lance_private *lp = netdev_priv(dev);
 	struct lance_ioreg	 *IO = lp->iobase;
 	int i;
 
@@ -681,8 +680,8 @@
 /* Initialize the LANCE Rx and Tx rings. */
 
 static void lance_init_ring( struct net_device *dev )
-
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{
+	struct lance_private *lp = netdev_priv(dev);
 	int i;
 	unsigned offset;
 
@@ -730,7 +729,7 @@
 
 static void lance_tx_timeout (struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = netdev_priv(dev);
 	struct lance_ioreg	 *IO = lp->iobase;
 
 	AREG = CSR0;
@@ -772,14 +771,12 @@
 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
 
 static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
-
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{
+	struct lance_private *lp = netdev_priv(dev);
 	struct lance_ioreg	 *IO = lp->iobase;
 	int entry, len;
 	struct lance_tx_head *head;
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
 
 	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
 				  dev->name, DREG ));
@@ -802,12 +799,10 @@
 
 	/* Fill in a Tx ring entry */
 	if (lance_debug >= 3) {
-		printk( "%s: TX pkt type 0x%04x from "
-				"%s to %s"
+		printk( "%s: TX pkt type 0x%04x from %pM to %pM"
 				" data at 0x%08x len %d\n",
 				dev->name, ((u_short *)skb->data)[6],
-				print_mac(mac, &skb->data[6]),
-				print_mac(mac2, skb->data),
+				&skb->data[6], skb->data,
 				(int)skb->data, (int)skb->len );
 	}
 
@@ -865,7 +860,7 @@
 		return IRQ_NONE;
 	}
 
-	lp = (struct lance_private *)dev->priv;
+	lp = netdev_priv(dev);
 	IO = lp->iobase;
 	spin_lock (&lp->devlock);
 
@@ -965,8 +960,8 @@
 
 
 static int lance_rx( struct net_device *dev )
-
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{
+	struct lance_private *lp = netdev_priv(dev);
 	int entry = lp->cur_rx & RX_RING_MOD_MASK;
 	int i;
 
@@ -1019,14 +1014,12 @@
 
 				if (lance_debug >= 3) {
 					u_char *data = PKTBUF_ADDR(head);
-					DECLARE_MAC_BUF(mac);
-					DECLARE_MAC_BUF(mac2);
 
-					printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s "
+					printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %pM to %pM "
 						   "data %02x %02x %02x %02x %02x %02x %02x %02x "
 						   "len %d\n",
 						   dev->name, ((u_short *)data)[6],
-						   print_mac(mac, &data[6]), print_mac(mac2, data),
+						   &data[6], data,
 						   data[15], data[16], data[17], data[18],
 						   data[19], data[20], data[21], data[22],
 						   pkt_len);
@@ -1037,7 +1030,6 @@
 				lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len );
 				skb->protocol = eth_type_trans( skb, dev );
 				netif_rx( skb );
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += pkt_len;
 			}
@@ -1057,8 +1049,8 @@
 
 
 static int lance_close( struct net_device *dev )
-
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{
+	struct lance_private *lp = netdev_priv(dev);
 	struct lance_ioreg	 *IO = lp->iobase;
 
 	netif_stop_queue (dev);
@@ -1084,8 +1076,8 @@
  */
 
 static void set_multicast_list( struct net_device *dev )
-
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{
+	struct lance_private *lp = netdev_priv(dev);
 	struct lance_ioreg	 *IO = lp->iobase;
 
 	if (netif_running(dev))
@@ -1126,8 +1118,8 @@
 /* This is needed for old RieblCards and possible for new RieblCards */
 
 static int lance_set_mac_address( struct net_device *dev, void *addr )
-
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
+{
+	struct lance_private *lp = netdev_priv(dev);
 	struct sockaddr *saddr = addr;
 	int i;
 
diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c
index 9b60352..bb9094d 100644
--- a/drivers/net/atl1e/atl1e_main.c
+++ b/drivers/net/atl1e/atl1e_main.c
@@ -1326,9 +1326,9 @@
 			AT_WRITE_REG(hw, REG_IMR,
 				     IMR_NORMAL_MASK & ~ISR_RX_EVENT);
 			AT_WRITE_FLUSH(hw);
-			if (likely(netif_rx_schedule_prep(netdev,
+			if (likely(netif_rx_schedule_prep(
 				   &adapter->napi)))
-				__netif_rx_schedule(netdev, &adapter->napi);
+				__netif_rx_schedule(&adapter->napi);
 		}
 	} while (--max_ints > 0);
 	/* re-enable Interrupt*/
@@ -1460,7 +1460,6 @@
 				netif_receive_skb(skb);
 			}
 
-			netdev->last_rx = jiffies;
 skip_pkt:
 	/* skip current packet whether it's ok or not. */
 			rx_page->read_offset +=
@@ -1502,7 +1501,6 @@
 {
 	struct atl1e_adapter *adapter =
 			container_of(napi, struct atl1e_adapter, napi);
-	struct net_device *netdev  = adapter->netdev;
 	struct pci_dev    *pdev    = adapter->pdev;
 	u32 imr_data;
 	int work_done = 0;
@@ -1516,7 +1514,7 @@
 	/* If no Tx and not enough Rx work done, exit the polling mode */
 	if (work_done < budget) {
 quit_polling:
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 		imr_data = AT_READ_REG(&adapter->hw, REG_IMR);
 		AT_WRITE_REG(&adapter->hw, REG_IMR, imr_data | ISR_RX_EVENT);
 		/* test debug */
@@ -2254,26 +2252,33 @@
 	atl1e_suspend(pdev, PMSG_SUSPEND);
 }
 
+static const struct net_device_ops atl1e_netdev_ops = {
+	.ndo_open		= atl1e_open,
+	.ndo_stop		= atl1e_close,
+	.ndo_start_xmit		= atl1e_xmit_frame,
+	.ndo_get_stats		= atl1e_get_stats,
+	.ndo_set_multicast_list	= atl1e_set_multi,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= atl1e_set_mac_addr,
+	.ndo_change_mtu		= atl1e_change_mtu,
+	.ndo_do_ioctl		= atl1e_ioctl,
+	.ndo_tx_timeout		= atl1e_tx_timeout,
+	.ndo_vlan_rx_register	= atl1e_vlan_rx_register,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= atl1e_netpoll,
+#endif
+
+};
+
 static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev)
 {
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 	pci_set_drvdata(pdev, netdev);
 
 	netdev->irq  = pdev->irq;
-	netdev->open = &atl1e_open;
-	netdev->stop = &atl1e_close;
-	netdev->hard_start_xmit = &atl1e_xmit_frame;
-	netdev->get_stats = &atl1e_get_stats;
-	netdev->set_multicast_list = &atl1e_set_multi;
-	netdev->set_mac_address = &atl1e_set_mac_addr;
-	netdev->change_mtu = &atl1e_change_mtu;
-	netdev->do_ioctl = &atl1e_ioctl;
-	netdev->tx_timeout = &atl1e_tx_timeout;
+	netdev->netdev_ops = &atl1e_netdev_ops;
+
 	netdev->watchdog_timeo = AT_TX_WATCHDOG;
-	netdev->vlan_rx_register = atl1e_vlan_rx_register;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	netdev->poll_controller = atl1e_netpoll;
-#endif
 	atl1e_set_ethtool_ops(netdev);
 
 	netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
@@ -2488,7 +2493,7 @@
 atl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct atl1e_adapter *adapter = netdev->priv;
+	struct atl1e_adapter *adapter = netdev_priv(netdev);
 
 	netif_device_detach(netdev);
 
@@ -2511,7 +2516,7 @@
 static pci_ers_result_t atl1e_io_slot_reset(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct atl1e_adapter *adapter = netdev->priv;
+	struct atl1e_adapter *adapter = netdev_priv(netdev);
 
 	if (pci_enable_device(pdev)) {
 		dev_err(&pdev->dev,
@@ -2539,7 +2544,7 @@
 static void atl1e_io_resume(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct atl1e_adapter *adapter = netdev->priv;
+	struct atl1e_adapter *adapter = netdev_priv(netdev);
 
 	if (netif_running(netdev)) {
 		if (atl1e_up(adapter)) {
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index aef403d..c0ceee0 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -195,7 +195,7 @@
  * value exists, a default value is used.  The final value is stored
  * in a variable in the adapter structure.
  */
-void __devinit atl1_check_options(struct atl1_adapter *adapter)
+static void __devinit atl1_check_options(struct atl1_adapter *adapter)
 {
 	struct pci_dev *pdev = adapter->pdev;
 	int bd = adapter->bd_number;
@@ -523,7 +523,7 @@
  * Reads the adapter's MAC address from the EEPROM
  * hw - Struct containing variables accessed by shared code
  */
-s32 atl1_read_mac_addr(struct atl1_hw *hw)
+static s32 atl1_read_mac_addr(struct atl1_hw *hw)
 {
 	u16 i;
 
@@ -1390,7 +1390,8 @@
 	/* auto-neg, insert timer to re-config phy */
 	if (!adapter->phy_timer_pending) {
 		adapter->phy_timer_pending = true;
-		mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ);
+		mod_timer(&adapter->phy_config_timer,
+			  round_jiffies(jiffies + 3 * HZ));
 	}
 
 	return 0;
@@ -1662,6 +1663,7 @@
 
 static void atl1_inc_smb(struct atl1_adapter *adapter)
 {
+	struct net_device *netdev = adapter->netdev;
 	struct stats_msg_block *smb = adapter->smb.smb;
 
 	/* Fill out the OS statistics structure */
@@ -1704,30 +1706,30 @@
 	adapter->soft_stats.tx_trunc += smb->tx_trunc;
 	adapter->soft_stats.tx_pause += smb->tx_pause;
 
-	adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets;
-	adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets;
-	adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes;
-	adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes;
-	adapter->net_stats.multicast = adapter->soft_stats.multicast;
-	adapter->net_stats.collisions = adapter->soft_stats.collisions;
-	adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors;
-	adapter->net_stats.rx_over_errors =
+	netdev->stats.rx_packets = adapter->soft_stats.rx_packets;
+	netdev->stats.tx_packets = adapter->soft_stats.tx_packets;
+	netdev->stats.rx_bytes = adapter->soft_stats.rx_bytes;
+	netdev->stats.tx_bytes = adapter->soft_stats.tx_bytes;
+	netdev->stats.multicast = adapter->soft_stats.multicast;
+	netdev->stats.collisions = adapter->soft_stats.collisions;
+	netdev->stats.rx_errors = adapter->soft_stats.rx_errors;
+	netdev->stats.rx_over_errors =
 		adapter->soft_stats.rx_missed_errors;
-	adapter->net_stats.rx_length_errors =
+	netdev->stats.rx_length_errors =
 		adapter->soft_stats.rx_length_errors;
-	adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors;
-	adapter->net_stats.rx_frame_errors =
+	netdev->stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors;
+	netdev->stats.rx_frame_errors =
 		adapter->soft_stats.rx_frame_errors;
-	adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors;
-	adapter->net_stats.rx_missed_errors =
+	netdev->stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors;
+	netdev->stats.rx_missed_errors =
 		adapter->soft_stats.rx_missed_errors;
-	adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors;
-	adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors;
-	adapter->net_stats.tx_aborted_errors =
+	netdev->stats.tx_errors = adapter->soft_stats.tx_errors;
+	netdev->stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors;
+	netdev->stats.tx_aborted_errors =
 		adapter->soft_stats.tx_aborted_errors;
-	adapter->net_stats.tx_window_errors =
+	netdev->stats.tx_window_errors =
 		adapter->soft_stats.tx_window_errors;
-	adapter->net_stats.tx_carrier_errors =
+	netdev->stats.tx_carrier_errors =
 		adapter->soft_stats.tx_carrier_errors;
 }
 
@@ -1860,7 +1862,7 @@
 				       adapter->rx_buffer_len + NET_IP_ALIGN);
 		if (unlikely(!skb)) {
 			/* Better luck next round */
-			adapter->net_stats.rx_dropped++;
+			adapter->netdev->stats.rx_dropped++;
 			break;
 		}
 
@@ -2026,8 +2028,6 @@
 		buffer_info->skb = NULL;
 		buffer_info->alloced = 0;
 		rrd->xsz.valid = 0;
-
-		adapter->netdev->last_rx = jiffies;
 	}
 
 	atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean);
@@ -2524,17 +2524,6 @@
 	return IRQ_HANDLED;
 }
 
-/*
- * atl1_watchdog - Timer Call-back
- * @data: pointer to netdev cast into an unsigned long
- */
-static void atl1_watchdog(unsigned long data)
-{
-	struct atl1_adapter *adapter = (struct atl1_adapter *)data;
-
-	/* Reset the timer */
-	mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
-}
 
 /*
  * atl1_phy_config - Timer Call-back
@@ -2607,7 +2596,6 @@
 	if (unlikely(err))
 		goto err_up;
 
-	mod_timer(&adapter->watchdog_timer, jiffies);
 	atlx_irq_enable(adapter);
 	atl1_check_link(adapter);
 	netif_start_queue(netdev);
@@ -2625,7 +2613,6 @@
 	struct net_device *netdev = adapter->netdev;
 
 	netif_stop_queue(netdev);
-	del_timer_sync(&adapter->watchdog_timer);
 	del_timer_sync(&adapter->phy_config_timer);
 	adapter->phy_timer_pending = false;
 
@@ -2893,6 +2880,22 @@
 }
 #endif
 
+static const struct net_device_ops atl1_netdev_ops = {
+	.ndo_open		= atl1_open,
+	.ndo_stop		= atl1_close,
+	.ndo_start_xmit		= atl1_xmit_frame,
+	.ndo_set_multicast_list	= atlx_set_multi,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= atl1_set_mac,
+	.ndo_change_mtu		= atl1_change_mtu,
+	.ndo_do_ioctl		= atlx_ioctl,
+	.ndo_tx_timeout		= atlx_tx_timeout,
+	.ndo_vlan_rx_register	= atlx_vlan_rx_register,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= atl1_poll_controller,
+#endif
+};
+
 /*
  * atl1_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -2980,20 +2983,8 @@
 	adapter->mii.phy_id_mask = 0x1f;
 	adapter->mii.reg_num_mask = 0x1f;
 
-	netdev->open = &atl1_open;
-	netdev->stop = &atl1_close;
-	netdev->hard_start_xmit = &atl1_xmit_frame;
-	netdev->get_stats = &atlx_get_stats;
-	netdev->set_multicast_list = &atlx_set_multi;
-	netdev->set_mac_address = &atl1_set_mac;
-	netdev->change_mtu = &atl1_change_mtu;
-	netdev->do_ioctl = &atlx_ioctl;
-	netdev->tx_timeout = &atlx_tx_timeout;
+	netdev->netdev_ops = &atl1_netdev_ops;
 	netdev->watchdog_timeo = 5 * HZ;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	netdev->poll_controller = atl1_poll_controller;
-#endif
-	netdev->vlan_rx_register = atlx_vlan_rx_register;
 
 	netdev->ethtool_ops = &atl1_ethtool_ops;
 	adapter->bd_number = cards_found;
@@ -3049,13 +3040,8 @@
 	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
 
-	init_timer(&adapter->watchdog_timer);
-	adapter->watchdog_timer.function = &atl1_watchdog;
-	adapter->watchdog_timer.data = (unsigned long)adapter;
-
-	init_timer(&adapter->phy_config_timer);
-	adapter->phy_config_timer.function = &atl1_phy_config;
-	adapter->phy_config_timer.data = (unsigned long)adapter;
+	setup_timer(&adapter->phy_config_timer, &atl1_phy_config,
+		    (unsigned long)adapter);
 	adapter->phy_timer_pending = false;
 
 	INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task);
@@ -3173,8 +3159,6 @@
 	{"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)},
 	{"rx_errors", ATL1_STAT(soft_stats.rx_errors)},
 	{"tx_errors", ATL1_STAT(soft_stats.tx_errors)},
-	{"rx_dropped", ATL1_STAT(net_stats.rx_dropped)},
-	{"tx_dropped", ATL1_STAT(net_stats.tx_dropped)},
 	{"multicast", ATL1_STAT(soft_stats.multicast)},
 	{"collisions", ATL1_STAT(soft_stats.collisions)},
 	{"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)},
diff --git a/drivers/net/atlx/atl1.h b/drivers/net/atlx/atl1.h
index ffa73fc..146372f 100644
--- a/drivers/net/atlx/atl1.h
+++ b/drivers/net/atlx/atl1.h
@@ -754,7 +754,7 @@
 struct atl1_adapter {
 	struct net_device *netdev;
 	struct pci_dev *pdev;
-	struct net_device_stats net_stats;
+
 	struct atl1_sft_stats soft_stats;
 	struct vlan_group *vlgrp;
 	u32 rx_buffer_len;
@@ -765,7 +765,7 @@
 	struct work_struct tx_timeout_task;
 	struct work_struct link_chg_task;
 	struct work_struct pcie_dma_to_rst_task;
-	struct timer_list watchdog_timer;
+
 	struct timer_list phy_config_timer;
 	bool phy_timer_pending;
 
diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c
index 8571e8c..bc39449 100644
--- a/drivers/net/atlx/atl2.c
+++ b/drivers/net/atlx/atl2.c
@@ -418,7 +418,7 @@
 				 * Check that some rx space is free. If not,
 				 * free one and mark stats->rx_dropped++.
 				 */
-				adapter->net_stats.rx_dropped++;
+				netdev->stats.rx_dropped++;
 				break;
 			}
 			skb_reserve(skb, NET_IP_ALIGN);
@@ -435,20 +435,19 @@
 			} else
 #endif
 			netif_rx(skb);
-			adapter->net_stats.rx_bytes += rx_size;
-			adapter->net_stats.rx_packets++;
-			netdev->last_rx = jiffies;
+			netdev->stats.rx_bytes += rx_size;
+			netdev->stats.rx_packets++;
 		} else {
-			adapter->net_stats.rx_errors++;
+			netdev->stats.rx_errors++;
 
 			if (rxd->status.ok && rxd->status.pkt_size <= 60)
-				adapter->net_stats.rx_length_errors++;
+				netdev->stats.rx_length_errors++;
 			if (rxd->status.mcast)
-				adapter->net_stats.multicast++;
+				netdev->stats.multicast++;
 			if (rxd->status.crc)
-				adapter->net_stats.rx_crc_errors++;
+				netdev->stats.rx_crc_errors++;
 			if (rxd->status.align)
-				adapter->net_stats.rx_frame_errors++;
+				netdev->stats.rx_frame_errors++;
 		}
 
 		/* advance write ptr */
@@ -463,6 +462,7 @@
 
 static void atl2_intr_tx(struct atl2_adapter *adapter)
 {
+	struct net_device *netdev = adapter->netdev;
 	u32 txd_read_ptr;
 	u32 txs_write_ptr;
 	struct tx_pkt_status *txs;
@@ -522,20 +522,20 @@
 
 		/* tx statistics: */
 		if (txs->ok) {
-			adapter->net_stats.tx_bytes += txs->pkt_size;
-			adapter->net_stats.tx_packets++;
+			netdev->stats.tx_bytes += txs->pkt_size;
+			netdev->stats.tx_packets++;
 		}
 		else
-			adapter->net_stats.tx_errors++;
+			netdev->stats.tx_errors++;
 
 		if (txs->defer)
-			adapter->net_stats.collisions++;
+			netdev->stats.collisions++;
 		if (txs->abort_col)
-			adapter->net_stats.tx_aborted_errors++;
+			netdev->stats.tx_aborted_errors++;
 		if (txs->late_col)
-			adapter->net_stats.tx_window_errors++;
+			netdev->stats.tx_window_errors++;
 		if (txs->underun)
-			adapter->net_stats.tx_fifo_errors++;
+			netdev->stats.tx_fifo_errors++;
 	} while (1);
 
 	if (free_hole) {
@@ -621,7 +621,7 @@
 
 	/* link event */
 	if (status & (ISR_PHY | ISR_MANUAL)) {
-		adapter->net_stats.tx_carrier_errors++;
+		adapter->netdev->stats.tx_carrier_errors++;
 		atl2_check_for_link(adapter);
 	}
 
@@ -644,7 +644,6 @@
 	int flags, err = 0;
 
 	flags = IRQF_SHARED;
-#ifdef CONFIG_PCI_MSI
 	adapter->have_msi = true;
 	err = pci_enable_msi(adapter->pdev);
 	if (err)
@@ -652,7 +651,6 @@
 
 	if (adapter->have_msi)
 		flags &= ~IRQF_SHARED;
-#endif
 
 	return request_irq(adapter->pdev->irq, &atl2_intr, flags, netdev->name,
 		netdev);
@@ -723,7 +721,7 @@
 
 	clear_bit(__ATL2_DOWN, &adapter->flags);
 
-	mod_timer(&adapter->watchdog_timer, jiffies + 4*HZ);
+	mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 4*HZ));
 
 	val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL);
 	ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL,
@@ -900,19 +898,6 @@
 }
 
 /*
- * atl2_get_stats - Get System Network Statistics
- * @netdev: network interface device structure
- *
- * Returns the address of the device statistics structure.
- * The statistics are actually updated from the timer callback.
- */
-static struct net_device_stats *atl2_get_stats(struct net_device *netdev)
-{
-	struct atl2_adapter *adapter = netdev_priv(netdev);
-	return &adapter->net_stats;
-}
-
-/*
  * atl2_change_mtu - Change the Maximum Transfer Unit
  * @netdev: network interface device structure
  * @new_mtu: new value for maximum frame size
@@ -1050,18 +1035,21 @@
 static void atl2_watchdog(unsigned long data)
 {
 	struct atl2_adapter *adapter = (struct atl2_adapter *) data;
-	u32 drop_rxd, drop_rxs;
-	unsigned long flags;
 
 	if (!test_bit(__ATL2_DOWN, &adapter->flags)) {
+		u32 drop_rxd, drop_rxs;
+		unsigned long flags;
+
 		spin_lock_irqsave(&adapter->stats_lock, flags);
 		drop_rxd = ATL2_READ_REG(&adapter->hw, REG_STS_RXD_OV);
 		drop_rxs = ATL2_READ_REG(&adapter->hw, REG_STS_RXS_OV);
-		adapter->net_stats.rx_over_errors += (drop_rxd+drop_rxs);
 		spin_unlock_irqrestore(&adapter->stats_lock, flags);
 
+		adapter->netdev->stats.rx_over_errors += drop_rxd + drop_rxs;
+
 		/* Reset the timer */
-		mod_timer(&adapter->watchdog_timer, jiffies + 4 * HZ);
+		mod_timer(&adapter->watchdog_timer,
+			  round_jiffies(jiffies + 4 * HZ));
 	}
 }
 
@@ -1265,7 +1253,8 @@
 	 * (if interval smaller than 5 seconds, something strange) */
 	if (!test_bit(__ATL2_DOWN, &adapter->flags)) {
 		if (!test_and_set_bit(0, &adapter->cfg_phy))
-			mod_timer(&adapter->phy_config_timer, jiffies + 5 * HZ);
+			mod_timer(&adapter->phy_config_timer,
+				  round_jiffies(jiffies + 5 * HZ));
 	}
 
 	return 0;
@@ -1320,6 +1309,23 @@
 }
 #endif
 
+
+static const struct net_device_ops atl2_netdev_ops = {
+	.ndo_open		= atl2_open,
+	.ndo_stop		= atl2_close,
+	.ndo_start_xmit		= atl2_xmit_frame,
+	.ndo_set_multicast_list	= atl2_set_multi,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= atl2_set_mac,
+	.ndo_change_mtu		= atl2_change_mtu,
+	.ndo_do_ioctl		= atl2_ioctl,
+	.ndo_tx_timeout		= atl2_tx_timeout,
+	.ndo_vlan_rx_register	= atl2_vlan_rx_register,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= atl2_poll_controller,
+#endif
+};
+
 /*
  * atl2_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -1393,26 +1399,9 @@
 
 	atl2_setup_pcicmd(pdev);
 
-	netdev->open = &atl2_open;
-	netdev->stop = &atl2_close;
-	netdev->hard_start_xmit = &atl2_xmit_frame;
-	netdev->get_stats = &atl2_get_stats;
-	netdev->set_multicast_list = &atl2_set_multi;
-	netdev->set_mac_address = &atl2_set_mac;
-	netdev->change_mtu = &atl2_change_mtu;
-	netdev->do_ioctl = &atl2_ioctl;
+	netdev->netdev_ops = &atl2_netdev_ops;
 	atl2_set_ethtool_ops(netdev);
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	netdev->poll_controller = atl2_poll_controller;
-#endif
-#ifdef HAVE_TX_TIMEOUT
-	netdev->tx_timeout = &atl2_tx_timeout;
 	netdev->watchdog_timeo = 5 * HZ;
-#endif
-#ifdef NETIF_F_HW_VLAN_TX
-	netdev->vlan_rx_register = atl2_vlan_rx_register;
-#endif
 	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
 
 	netdev->mem_start = mmio_start;
diff --git a/drivers/net/atlx/atl2.h b/drivers/net/atlx/atl2.h
index 09974df..d918bbe 100644
--- a/drivers/net/atlx/atl2.h
+++ b/drivers/net/atlx/atl2.h
@@ -453,7 +453,6 @@
 	/* OS defined structs */
 	struct net_device *netdev;
 	struct pci_dev *pdev;
-	struct net_device_stats net_stats;
 #ifdef NETIF_F_HW_VLAN_TX
 	struct vlan_group *vlgrp;
 #endif
diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c
index 3cc9d10..3dc0142 100644
--- a/drivers/net/atlx/atlx.c
+++ b/drivers/net/atlx/atlx.c
@@ -182,19 +182,6 @@
 }
 
 /*
- * atlx_get_stats - Get System Network Statistics
- * @netdev: network interface device structure
- *
- * Returns the address of the device statistics structure.
- * The statistics are actually updated from the timer callback.
- */
-static struct net_device_stats *atlx_get_stats(struct net_device *netdev)
-{
-	struct atlx_adapter *adapter = netdev_priv(netdev);
-	return &adapter->net_stats;
-}
-
-/*
  * atlx_tx_timeout - Respond to a Tx Hang
  * @netdev: network interface device structure
  */
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index c10cd80..ea493ce 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -248,7 +248,6 @@
 	struct net_local *lp;
 	int saved_ctrl_reg, status, i;
 	int res;
-	DECLARE_MAC_BUF(mac);
 
 	outb(0xff, ioaddr + PAR_DATA);
 	/* Save the original value of the Control register, in case we guessed
@@ -324,8 +323,8 @@
 #endif
 
 	printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, "
-	       "SAPROM %s.\n",
-	       dev->name, dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr));
+	       "SAPROM %pM.\n",
+	       dev->name, dev->base_addr, dev->irq, dev->dev_addr);
 
 	/* Reset the ethernet hardware and activate the printer pass-through. */
 	write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX);
@@ -421,7 +420,7 @@
    registers that "should" only need to be set once at boot, so that
    there is non-reboot way to recover if something goes wrong.
 
-   This is an attachable device: if there is no dev->priv entry then it wasn't
+   This is an attachable device: if there is no private entry then it wasn't
    probed for at boot-time, and we need to probe for it again.
    */
 static int net_open(struct net_device *dev)
@@ -803,21 +802,22 @@
 
 static void read_block(long ioaddr, int length, unsigned char *p, int data_mode)
 {
-
 	if (data_mode <= 3) { /* Mode 0 or 1 */
 		outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
 		outb(length == 8  ?  RdAddr | HNib | MAR  :  RdAddr | MAR,
 			 ioaddr + PAR_DATA);
 		if (data_mode <= 1) { /* Mode 0 or 1 */
-			do  *p++ = read_byte_mode0(ioaddr);  while (--length > 0);
-		} else	/* Mode 2 or 3 */
-			do  *p++ = read_byte_mode2(ioaddr);  while (--length > 0);
-	} else if (data_mode <= 5)
-		do      *p++ = read_byte_mode4(ioaddr);  while (--length > 0);
-	else
-		do      *p++ = read_byte_mode6(ioaddr);  while (--length > 0);
+			do { *p++ = read_byte_mode0(ioaddr); } while (--length > 0);
+		} else { /* Mode 2 or 3 */
+			do { *p++ = read_byte_mode2(ioaddr); } while (--length > 0);
+		}
+	} else if (data_mode <= 5) {
+		do { *p++ = read_byte_mode4(ioaddr); } while (--length > 0);
+	} else {
+		do { *p++ = read_byte_mode6(ioaddr); } while (--length > 0);
+	}
 
-    outb(EOC+HNib+MAR, ioaddr + PAR_DATA);
+	outb(EOC+HNib+MAR, ioaddr + PAR_DATA);
 	outb(Ctrl_SelData, ioaddr + PAR_CONTROL);
 }
 
@@ -913,7 +913,8 @@
 	struct net_device *next_dev;
 
 	while (root_atp_dev) {
-		next_dev = ((struct net_local *)root_atp_dev->priv)->next_module;
+		struct net_local *atp_local = netdev_priv(root_atp_dev);
+		next_dev = atp_local->next_module;
 		unregister_netdev(root_atp_dev);
 		/* No need to release_region(), since we never snarf it. */
 		free_netdev(root_atp_dev);
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 019b13c..9c875bb 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -193,7 +193,7 @@
  */
 static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 	volatile u32 *const mii_control_reg = &aup->mac->mii_control;
 	volatile u32 *const mii_data_reg = &aup->mac->mii_data;
 	u32 timedout = 20;
@@ -228,7 +228,7 @@
 static void au1000_mdio_write(struct net_device *dev, int phy_addr,
 			      int reg, u16 value)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 	volatile u32 *const mii_control_reg = &aup->mac->mii_control;
 	volatile u32 *const mii_data_reg = &aup->mac->mii_data;
 	u32 timedout = 20;
@@ -283,7 +283,7 @@
 
 static int mii_probe (struct net_device *dev)
 {
-	struct au1000_private *const aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *const aup = netdev_priv(dev);
 	struct phy_device *phydev = NULL;
 
 #if defined(AU1XXX_PHY_STATIC_CONFIG)
@@ -353,7 +353,6 @@
 	}
 
 	/* now we are supposed to have a proper phydev, to attach to... */
-	BUG_ON(!phydev);
 	BUG_ON(phydev->attached_dev);
 
 	phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0,
@@ -415,7 +414,7 @@
 
 static void enable_rx_tx(struct net_device *dev)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 
 	if (au1000_debug > 4)
 		printk(KERN_INFO "%s: enable_rx_tx\n", dev->name);
@@ -426,7 +425,7 @@
 
 static void hard_stop(struct net_device *dev)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 
 	if (au1000_debug > 4)
 		printk(KERN_INFO "%s: hard stop\n", dev->name);
@@ -438,7 +437,7 @@
 static void enable_mac(struct net_device *dev, int force_reset)
 {
 	unsigned long flags;
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 
 	spin_lock_irqsave(&aup->lock, flags);
 
@@ -457,7 +456,7 @@
 
 static void reset_mac_unlocked(struct net_device *dev)
 {
-	struct au1000_private *const aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *const aup = netdev_priv(dev);
 	int i;
 
 	hard_stop(dev);
@@ -483,7 +482,7 @@
 
 static void reset_mac(struct net_device *dev)
 {
-	struct au1000_private *const aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *const aup = netdev_priv(dev);
 	unsigned long flags;
 
 	if (au1000_debug > 4)
@@ -572,7 +571,7 @@
 
 static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct au1000_private *aup = (struct au1000_private *)dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 
 	if (aup->phy_dev)
 		return phy_ethtool_gset(aup->phy_dev, cmd);
@@ -582,7 +581,7 @@
 
 static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct au1000_private *aup = (struct au1000_private *)dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
@@ -596,7 +595,7 @@
 static void
 au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct au1000_private *aup = (struct au1000_private *)dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
@@ -652,7 +651,7 @@
 	printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n",
 		dev->name, base, irq);
 
-	aup = dev->priv;
+	aup = netdev_priv(dev);
 
 	spin_lock_init(&aup->lock);
 
@@ -817,7 +816,7 @@
  */
 static int au1000_init(struct net_device *dev)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 	unsigned long flags;
 	int i;
 	u32 control;
@@ -868,7 +867,7 @@
 static void
 au1000_adjust_link(struct net_device *dev)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 	struct phy_device *phydev = aup->phy_dev;
 	unsigned long flags;
 
@@ -947,7 +946,7 @@
 static int au1000_open(struct net_device *dev)
 {
 	int retval;
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 
 	if (au1000_debug > 4)
 		printk("%s: open: dev=%p\n", dev->name, dev);
@@ -982,7 +981,7 @@
 static int au1000_close(struct net_device *dev)
 {
 	unsigned long flags;
-	struct au1000_private *const aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *const aup = netdev_priv(dev);
 
 	if (au1000_debug > 4)
 		printk("%s: close: dev=%p\n", dev->name, dev);
@@ -1013,7 +1012,7 @@
 	for (i = 0; i < num_ifs; i++) {
 		dev = iflist[i].dev;
 		if (dev) {
-			aup = (struct au1000_private *) dev->priv;
+			aup = netdev_priv(dev);
 			unregister_netdev(dev);
 			mdiobus_unregister(aup->mii_bus);
 			mdiobus_free(aup->mii_bus);
@@ -1035,7 +1034,7 @@
 
 static void update_tx_stats(struct net_device *dev, u32 status)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 	struct net_device_stats *ps = &dev->stats;
 
 	if (status & TX_FRAME_ABORTED) {
@@ -1064,7 +1063,7 @@
  */
 static void au1000_tx_ack(struct net_device *dev)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 	volatile tx_dma_t *ptxd;
 
 	ptxd = aup->tx_dma_ring[aup->tx_tail];
@@ -1091,7 +1090,7 @@
  */
 static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 	struct net_device_stats *ps = &dev->stats;
 	volatile tx_dma_t *ptxd;
 	u32 buff_stat;
@@ -1145,7 +1144,7 @@
 
 static inline void update_rx_stats(struct net_device *dev, u32 status)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 	struct net_device_stats *ps = &dev->stats;
 
 	ps->rx_packets++;
@@ -1173,7 +1172,7 @@
  */
 static int au1000_rx(struct net_device *dev)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 	struct sk_buff *skb;
 	volatile rx_dma_t *prxd;
 	u32 buff_stat, status;
@@ -1240,7 +1239,6 @@
 		/* next descriptor */
 		prxd = aup->rx_dma_ring[aup->rx_head];
 		buff_stat = prxd->buff_stat;
-		dev->last_rx = jiffies;
 	}
 	return 0;
 }
@@ -1276,7 +1274,7 @@
 
 static void set_rx_mode(struct net_device *dev)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 
 	if (au1000_debug > 4)
 		printk("%s: set_rx_mode: flags=%x\n", dev->name, dev->flags);
@@ -1308,7 +1306,7 @@
 
 static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct au1000_private *aup = (struct au1000_private *)dev->priv;
+	struct au1000_private *aup = netdev_priv(dev);
 
 	if (!netif_running(dev)) return -EINVAL;
 
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 9a314d8..337488e 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -758,13 +758,10 @@
 #endif
 	ax_NS8390_init(dev, 0);
 
-	if (first_init) {
-		DECLARE_MAC_BUF(mac);
-
-		dev_info(&ax->dev->dev, "%dbit, irq %d, %lx, MAC: %s\n",
+	if (first_init)
+		dev_info(&ax->dev->dev, "%dbit, irq %d, %lx, MAC: %pM\n",
 			 ei_status.word16 ? 16:8, dev->irq, dev->base_addr,
-			 print_mac(mac, dev->dev_addr));
-	}
+			 dev->dev_addr);
 
 	ret = register_netdev(dev);
 	if (ret)
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index c3bda5c..0e7470a 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -829,7 +829,6 @@
 		skb->ip_summed = CHECKSUM_NONE;
 		skb->protocol = eth_type_trans(skb, bp->dev);
 		netif_receive_skb(skb);
-		bp->dev->last_rx = jiffies;
 		received++;
 		budget--;
 	next_pkt:
@@ -847,7 +846,6 @@
 static int b44_poll(struct napi_struct *napi, int budget)
 {
 	struct b44 *bp = container_of(napi, struct b44, napi);
-	struct net_device *netdev = bp->dev;
 	int work_done;
 
 	spin_lock_irq(&bp->lock);
@@ -876,7 +874,7 @@
 	}
 
 	if (work_done < budget) {
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 		b44_enable_ints(bp);
 	}
 
@@ -908,13 +906,13 @@
 			goto irq_ack;
 		}
 
-		if (netif_rx_schedule_prep(dev, &bp->napi)) {
+		if (netif_rx_schedule_prep(&bp->napi)) {
 			/* NOTE: These writes are posted by the readback of
 			 *       the ISTAT register below.
 			 */
 			bp->istat = istat;
 			__b44_disable_ints(bp);
-			__netif_rx_schedule(dev, &bp->napi);
+			__netif_rx_schedule(&bp->napi);
 		} else {
 			printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
 			       dev->name);
@@ -2117,7 +2115,6 @@
 	struct net_device *dev;
 	struct b44 *bp;
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	instance++;
 
@@ -2213,8 +2210,8 @@
 	 */
 	b44_chip_reset(bp, B44_CHIP_RESET_FULL);
 
-	printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %pM\n",
+	       dev->name, dev->dev_addr);
 
 	return 0;
 
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index b458d60..78e31aa 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -741,7 +741,6 @@
 	blackfin_dcache_invalidate_range((unsigned long)skb->head,
 					 (unsigned long)skb->tail);
 
-	dev->last_rx = jiffies;
 	skb->protocol = eth_type_trans(skb, dev);
 #if defined(BFIN_MAC_CSUM_OFFLOAD)
 	skb->csum = current_rx_ptr->status.ip_payload_csum;
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index a42bd19..8a546a3 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -716,13 +716,11 @@
 			skb_put(skb, nb);
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			++dev->stats.rx_packets;
 			dev->stats.rx_bytes += nb;
 		} else {
 			++dev->stats.rx_dropped;
 		}
-		dev->last_rx = jiffies;
 		if ((skb = bp->rx_bufs[i]) == NULL) {
 			bp->rx_bufs[i] = skb = dev_alloc_skb(RX_BUFLEN+2);
 			if (skb != NULL)
@@ -1258,7 +1256,6 @@
 	unsigned char addr[6];
 	struct net_device *dev;
 	int is_bmac_plus = ((int)match->data) != 0;
-	DECLARE_MAC_BUF(mac);
 
 	if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
 		printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
@@ -1368,8 +1365,8 @@
 		goto err_out_irq2;
 	}
 
-	printk(KERN_INFO "%s: BMAC%s at %s",
-	       dev->name, (is_bmac_plus ? "+" : ""), print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: BMAC%s at %pM",
+	       dev->name, (is_bmac_plus ? "+" : ""), dev->dev_addr);
 	XXDEBUG((", base_addr=%#0lx", dev->base_addr));
 	printk("\n");
 
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 9e8222f..d4a3dac 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -57,8 +57,8 @@
 
 #define DRV_MODULE_NAME		"bnx2"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.8.1"
-#define DRV_MODULE_RELDATE	"Oct 7, 2008"
+#define DRV_MODULE_VERSION	"1.9.0"
+#define DRV_MODULE_RELDATE	"Dec 16, 2008"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -89,6 +89,7 @@
 	BCM5709,
 	BCM5709S,
 	BCM5716,
+	BCM5716S,
 } board_t;
 
 /* indexed by board_t, above */
@@ -105,6 +106,7 @@
 	{ "Broadcom NetXtreme II BCM5709 1000Base-T" },
 	{ "Broadcom NetXtreme II BCM5709 1000Base-SX" },
 	{ "Broadcom NetXtreme II BCM5716 1000Base-T" },
+	{ "Broadcom NetXtreme II BCM5716 1000Base-SX" },
 	};
 
 static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = {
@@ -128,6 +130,8 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
 	{ PCI_VENDOR_ID_BROADCOM, 0x163b,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 },
+	{ PCI_VENDOR_ID_BROADCOM, 0x163c,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716S },
 	{ 0, }
 };
 
@@ -1652,7 +1656,7 @@
 		 * exchanging base pages plus 3 next pages and
 		 * normally completes in about 120 msec.
 		 */
-		bp->current_interval = SERDES_AN_TIMEOUT;
+		bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
 		bp->serdes_an_pending = 1;
 		mod_timer(&bp->timer, jiffies + bp->current_interval);
 	} else {
@@ -2274,7 +2278,7 @@
 		return 0;
 
 	/* wait for an acknowledgement. */
-	for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {
+	for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
 		msleep(10);
 
 		val = bnx2_shmem_rd(bp, BNX2_FW_MB);
@@ -3000,7 +3004,6 @@
 #endif
 			netif_receive_skb(skb);
 
-		bp->dev->last_rx = jiffies;
 		rx_pkt++;
 
 next_rx:
@@ -3040,7 +3043,6 @@
 {
 	struct bnx2_napi *bnapi = dev_instance;
 	struct bnx2 *bp = bnapi->bp;
-	struct net_device *dev = bp->dev;
 
 	prefetch(bnapi->status_blk.msi);
 	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
@@ -3051,7 +3053,7 @@
 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
 		return IRQ_HANDLED;
 
-	netif_rx_schedule(dev, &bnapi->napi);
+	netif_rx_schedule(&bnapi->napi);
 
 	return IRQ_HANDLED;
 }
@@ -3061,7 +3063,6 @@
 {
 	struct bnx2_napi *bnapi = dev_instance;
 	struct bnx2 *bp = bnapi->bp;
-	struct net_device *dev = bp->dev;
 
 	prefetch(bnapi->status_blk.msi);
 
@@ -3069,7 +3070,7 @@
 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
 		return IRQ_HANDLED;
 
-	netif_rx_schedule(dev, &bnapi->napi);
+	netif_rx_schedule(&bnapi->napi);
 
 	return IRQ_HANDLED;
 }
@@ -3079,7 +3080,6 @@
 {
 	struct bnx2_napi *bnapi = dev_instance;
 	struct bnx2 *bp = bnapi->bp;
-	struct net_device *dev = bp->dev;
 	struct status_block *sblk = bnapi->status_blk.msi;
 
 	/* When using INTx, it is possible for the interrupt to arrive
@@ -3106,9 +3106,9 @@
 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
 		return IRQ_HANDLED;
 
-	if (netif_rx_schedule_prep(dev, &bnapi->napi)) {
+	if (netif_rx_schedule_prep(&bnapi->napi)) {
 		bnapi->last_status_idx = sblk->status_idx;
-		__netif_rx_schedule(dev, &bnapi->napi);
+		__netif_rx_schedule(&bnapi->napi);
 	}
 
 	return IRQ_HANDLED;
@@ -3218,7 +3218,7 @@
 		rmb();
 		if (likely(!bnx2_has_fast_work(bnapi))) {
 
-			netif_rx_complete(bp->dev, napi);
+			netif_rx_complete(napi);
 			REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
 			       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
 			       bnapi->last_status_idx);
@@ -3251,7 +3251,7 @@
 
 		rmb();
 		if (likely(!bnx2_has_work(bnapi))) {
-			netif_rx_complete(bp->dev, napi);
+			netif_rx_complete(napi);
 			if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
 				REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
 				       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
@@ -4493,7 +4493,7 @@
 static int
 bnx2_init_chip(struct bnx2 *bp)
 {
-	u32 val;
+	u32 val, mtu;
 	int rc, i;
 
 	/* Make sure the interrupt is not active. */
@@ -4585,11 +4585,19 @@
 	REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
 
 	/* Program the MTU.  Also include 4 bytes for CRC32. */
-	val = bp->dev->mtu + ETH_HLEN + 4;
+	mtu = bp->dev->mtu;
+	val = mtu + ETH_HLEN + ETH_FCS_LEN;
 	if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
 		val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
 	REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
 
+	if (mtu < 1500)
+		mtu = 1500;
+
+	bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
+	bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
+	bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
+
 	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
 		bp->bnx2_napi[i].last_status_idx = 0;
 
@@ -5719,7 +5727,7 @@
 		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 		if (bmcr & BMCR_ANENABLE) {
 			bnx2_enable_forced_2g5(bp);
-			bp->current_interval = SERDES_FORCED_TIMEOUT;
+			bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
 		} else {
 			bnx2_disable_forced_2g5(bp);
 			bp->serdes_an_pending = 2;
@@ -5816,6 +5824,8 @@
 {
 	int i, rc;
 	struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
+	struct net_device *dev = bp->dev;
+	const int len = sizeof(bp->irq_tbl[0].name);
 
 	bnx2_setup_msix_tbl(bp);
 	REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
@@ -5826,7 +5836,7 @@
 		msix_ent[i].entry = i;
 		msix_ent[i].vector = 0;
 
-		strcpy(bp->irq_tbl[i].name, bp->dev->name);
+		snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
 		bp->irq_tbl[i].handler = bnx2_msi_1shot;
 	}
 
@@ -6173,7 +6183,7 @@
 {
 	struct bnx2 *bp = netdev_priv(dev);
 	struct statistics_block *stats_blk = bp->stats_blk;
-	struct net_device_stats *net_stats = &bp->net_stats;
+	struct net_device_stats *net_stats = &dev->stats;
 
 	if (bp->stats_blk == NULL) {
 		return net_stats;
@@ -6540,7 +6550,7 @@
 
 		spin_lock_bh(&bp->phy_lock);
 
-		bp->current_interval = SERDES_AN_TIMEOUT;
+		bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
 		bp->serdes_an_pending = 1;
 		mod_timer(&bp->timer, jiffies + bp->current_interval);
 	}
@@ -7615,7 +7625,8 @@
 
 	if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
 	    (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
-	    (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
+	    (CHIP_ID(bp) == CHIP_ID_5708_B1) ||
+	    !(REG_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
 		bp->flags |= BNX2_FLAG_NO_WOL;
 		bp->wol = 0;
 	}
@@ -7724,6 +7735,25 @@
 	}
 }
 
+static const struct net_device_ops bnx2_netdev_ops = {
+	.ndo_open		= bnx2_open,
+	.ndo_start_xmit		= bnx2_start_xmit,
+	.ndo_stop		= bnx2_close,
+	.ndo_get_stats		= bnx2_get_stats,
+	.ndo_set_rx_mode	= bnx2_set_rx_mode,
+	.ndo_do_ioctl		= bnx2_ioctl,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= bnx2_change_mac_addr,
+	.ndo_change_mtu		= bnx2_change_mtu,
+	.ndo_tx_timeout		= bnx2_tx_timeout,
+#ifdef BCM_VLAN
+	.ndo_vlan_rx_register	= bnx2_vlan_rx_register,
+#endif
+#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+	.ndo_poll_controller	= poll_bnx2,
+#endif
+};
+
 static int __devinit
 bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -7732,7 +7762,6 @@
 	struct bnx2 *bp;
 	int rc;
 	char str[40];
-	DECLARE_MAC_BUF(mac);
 
 	if (version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -7749,28 +7778,13 @@
 		return rc;
 	}
 
-	dev->open = bnx2_open;
-	dev->hard_start_xmit = bnx2_start_xmit;
-	dev->stop = bnx2_close;
-	dev->get_stats = bnx2_get_stats;
-	dev->set_rx_mode = bnx2_set_rx_mode;
-	dev->do_ioctl = bnx2_ioctl;
-	dev->set_mac_address = bnx2_change_mac_addr;
-	dev->change_mtu = bnx2_change_mtu;
-	dev->tx_timeout = bnx2_tx_timeout;
+	dev->netdev_ops = &bnx2_netdev_ops;
 	dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef BCM_VLAN
-	dev->vlan_rx_register = bnx2_vlan_rx_register;
-#endif
 	dev->ethtool_ops = &bnx2_ethtool_ops;
 
 	bp = netdev_priv(dev);
 	bnx2_init_napi(bp);
 
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
-	dev->poll_controller = poll_bnx2;
-#endif
-
 	pci_set_drvdata(pdev, dev);
 
 	memcpy(dev->dev_addr, bp->mac_addr, 6);
@@ -7799,14 +7813,14 @@
 	}
 
 	printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
-		"IRQ %d, node addr %s\n",
+		"IRQ %d, node addr %pM\n",
 		dev->name,
 		board_info[ent->driver_data].name,
 		((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
 		((CHIP_ID(bp) & 0x0ff0) >> 4),
 		bnx2_bus_string(bp, str),
 		dev->base_addr,
-		bp->pdev->irq, print_mac(mac, dev->dev_addr));
+		bp->pdev->irq, dev->dev_addr);
 
 	return 0;
 }
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 0b032c3..900641a 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -4202,7 +4202,14 @@
 
 #define BNX2_RBUF_CONFIG				0x0020000c
 #define BNX2_RBUF_CONFIG_XOFF_TRIP			 (0x3ffL<<0)
+#define BNX2_RBUF_CONFIG_XOFF_TRIP_VAL(mtu)		 \
+	((((mtu) - 1500) * 31 / 1000) + 54)
 #define BNX2_RBUF_CONFIG_XON_TRIP			 (0x3ffL<<16)
+#define BNX2_RBUF_CONFIG_XON_TRIP_VAL(mtu)		 \
+	((((mtu) - 1500) * 39 / 1000) + 66)
+#define BNX2_RBUF_CONFIG_VAL(mtu)			 \
+	(BNX2_RBUF_CONFIG_XOFF_TRIP_VAL(mtu) |		 \
+	(BNX2_RBUF_CONFIG_XON_TRIP_VAL(mtu) << 16))
 
 #define BNX2_RBUF_FW_BUF_ALLOC				0x00200010
 #define BNX2_RBUF_FW_BUF_ALLOC_VALUE			 (0x1ffL<<7)
@@ -4224,11 +4231,25 @@
 
 #define BNX2_RBUF_CONFIG2				0x0020001c
 #define BNX2_RBUF_CONFIG2_MAC_DROP_TRIP			 (0x3ffL<<0)
+#define BNX2_RBUF_CONFIG2_MAC_DROP_TRIP_VAL(mtu)	 \
+	((((mtu) - 1500) * 4 / 1000) + 5)
 #define BNX2_RBUF_CONFIG2_MAC_KEEP_TRIP			 (0x3ffL<<16)
+#define BNX2_RBUF_CONFIG2_MAC_KEEP_TRIP_VAL(mtu)	 \
+	((((mtu) - 1500) * 2 / 100) + 30)
+#define BNX2_RBUF_CONFIG2_VAL(mtu)			 \
+	(BNX2_RBUF_CONFIG2_MAC_DROP_TRIP_VAL(mtu) |	 \
+	(BNX2_RBUF_CONFIG2_MAC_KEEP_TRIP_VAL(mtu) << 16))
 
 #define BNX2_RBUF_CONFIG3				0x00200020
 #define BNX2_RBUF_CONFIG3_CU_DROP_TRIP			 (0x3ffL<<0)
+#define BNX2_RBUF_CONFIG3_CU_DROP_TRIP_VAL(mtu)		 \
+	((((mtu) - 1500) * 12 / 1000) + 18)
 #define BNX2_RBUF_CONFIG3_CU_KEEP_TRIP			 (0x3ffL<<16)
+#define BNX2_RBUF_CONFIG3_CU_KEEP_TRIP_VAL(mtu)		 \
+	((((mtu) - 1500) * 2 / 100) + 30)
+#define BNX2_RBUF_CONFIG3_VAL(mtu)			 \
+	(BNX2_RBUF_CONFIG3_CU_DROP_TRIP_VAL(mtu) |	 \
+	(BNX2_RBUF_CONFIG3_CU_KEEP_TRIP_VAL(mtu) << 16))
 
 #define BNX2_RBUF_PKT_DATA				0x00208000
 #define BNX2_RBUF_CLIST_DATA				0x00210000
@@ -6606,7 +6627,7 @@
 	irq_handler_t	handler;
 	unsigned int	vector;
 	u8		requested;
-	char		name[16];
+	char		name[IFNAMSIZ + 2];
 };
 
 struct bnx2_tx_ring_info {
@@ -6661,8 +6682,6 @@
 	struct bnx2_tx_ring_info	tx_ring;
 };
 
-#define BNX2_TIMER_INTERVAL			HZ
-
 struct bnx2 {
 	/* Fields used in the tx and intr/napi performance paths are grouped */
 	/* together in the beginning of the structure. */
@@ -6710,7 +6729,11 @@
 
 	/* End of fields used in the performance code paths. */
 
-	int			current_interval;
+	unsigned int		current_interval;
+#define BNX2_TIMER_INTERVAL		HZ
+#define BNX2_SERDES_AN_TIMEOUT		(HZ / 3)
+#define BNX2_SERDES_FORCED_TIMEOUT	(HZ / 10)
+
 	struct			timer_list timer;
 	struct work_struct	reset_task;
 
@@ -6825,9 +6848,6 @@
 	u8			flow_ctrl;	/* actual flow ctrl settings */
 						/* may be different from     */
 						/* req_flow_ctrl if autoneg  */
-#define FLOW_CTRL_TX		1
-#define FLOW_CTRL_RX		2
-
 	u32			advertising;
 
 	u8			req_flow_ctrl;	/* flow ctrl advertisement */
@@ -6842,8 +6862,6 @@
 #define PHY_LOOPBACK		2
 
 	u8			serdes_an_pending;
-#define SERDES_AN_TIMEOUT	(HZ / 3)
-#define SERDES_FORCED_TIMEOUT	(HZ / 10)
 
 	u8			mac_addr[8];
 
@@ -6854,8 +6872,6 @@
 	int			pm_cap;
 	int			pcix_cap;
 
-	struct net_device_stats net_stats;
-
 	struct flash_spec	*flash_info;
 	u32			flash_size;
 
@@ -6944,14 +6960,14 @@
 /* This value (in milliseconds) determines the frequency of the driver
  * issuing the PULSE message code.  The firmware monitors this periodic
  * pulse to determine when to switch to an OS-absent mode. */
-#define DRV_PULSE_PERIOD_MS                 250
+#define BNX2_DRV_PULSE_PERIOD_MS                 250
 
 /* This value (in milliseconds) determines how long the driver should
  * wait for an acknowledgement from the firmware before timing out.  Once
  * the firmware has timed out, the driver will assume there is no firmware
  * running and there won't be any firmware-driver synchronization during a
  * driver reset. */
-#define FW_ACK_TIME_OUT_MS                  1000
+#define BNX2_FW_ACK_TIME_OUT_MS                  1000
 
 
 #define BNX2_DRV_RESET_SIGNATURE		0x00000000
diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c
index 4ce7fe9..67de94f 100644
--- a/drivers/net/bnx2x_link.c
+++ b/drivers/net/bnx2x_link.c
@@ -289,7 +289,7 @@
 		/* pause enable/disable */
 		bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
 			       EMAC_RX_MODE_FLOW_EN);
-		if (vars->flow_ctrl & FLOW_CTRL_RX)
+		if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
 			bnx2x_bits_en(bp, emac_base +
 				    EMAC_REG_EMAC_RX_MODE,
 				    EMAC_RX_MODE_FLOW_EN);
@@ -297,7 +297,7 @@
 		bnx2x_bits_dis(bp,  emac_base + EMAC_REG_EMAC_TX_MODE,
 			     (EMAC_TX_MODE_EXT_PAUSE_EN |
 			      EMAC_TX_MODE_FLOW_EN));
-		if (vars->flow_ctrl & FLOW_CTRL_TX)
+		if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
 			bnx2x_bits_en(bp, emac_base +
 				    EMAC_REG_EMAC_TX_MODE,
 				   (EMAC_TX_MODE_EXT_PAUSE_EN |
@@ -333,7 +333,7 @@
 	/* enable the NIG in/out to the emac */
 	REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
 	val = 0;
-	if (vars->flow_ctrl & FLOW_CTRL_TX)
+	if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
 		val = 1;
 
 	REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
@@ -396,7 +396,7 @@
 
 	/* tx control */
 	val = 0xc0;
-	if (vars->flow_ctrl & FLOW_CTRL_TX)
+	if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
 		val |= 0x800000;
 	wb_data[0] = val;
 	wb_data[1] = 0;
@@ -423,7 +423,7 @@
 
 	/* rx control set to don't strip crc */
 	val = 0x14;
-	if (vars->flow_ctrl & FLOW_CTRL_RX)
+	if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
 		val |= 0x20;
 	wb_data[0] = val;
 	wb_data[1] = 0;
@@ -460,7 +460,7 @@
 	REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
 	REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
 	val = 0;
-	if (vars->flow_ctrl & FLOW_CTRL_TX)
+	if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
 		val = 1;
 	REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
 	REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
@@ -580,14 +580,14 @@
 		}
 
 		if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
-			vars->flow_ctrl |= FLOW_CTRL_TX;
+			vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
 		else
-			vars->flow_ctrl &= ~FLOW_CTRL_TX;
+			vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
 
 		if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
-			vars->flow_ctrl |= FLOW_CTRL_RX;
+			vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
 		else
-			vars->flow_ctrl &= ~FLOW_CTRL_RX;
+			vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
 
 		if (vars->phy_flags & PHY_XGXS_FLAG) {
 			if (vars->line_speed &&
@@ -618,7 +618,7 @@
 
 		vars->line_speed = 0;
 		vars->duplex = DUPLEX_FULL;
-		vars->flow_ctrl = FLOW_CTRL_NONE;
+		vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 
 		/* indicate no mac active */
 		vars->mac_type = MAC_TYPE_NONE;
@@ -691,7 +691,7 @@
 		return -EINVAL;
 	}
 
-	if (flow_ctrl & FLOW_CTRL_RX ||
+	if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
 	    line_speed == SPEED_10 ||
 	    line_speed == SPEED_100 ||
 	    line_speed == SPEED_1000 ||
@@ -1300,8 +1300,8 @@
 	 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
 
 	switch (params->req_flow_ctrl) {
-	case FLOW_CTRL_AUTO:
-		if (params->req_fc_auto_adv == FLOW_CTRL_BOTH) {
+	case BNX2X_FLOW_CTRL_AUTO:
+		if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
 			*ieee_fc |=
 			     MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
 		} else {
@@ -1309,17 +1309,17 @@
 		       MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
 		}
 		break;
-	case FLOW_CTRL_TX:
+	case BNX2X_FLOW_CTRL_TX:
 		*ieee_fc |=
 		       MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
 		break;
 
-	case FLOW_CTRL_RX:
-	case FLOW_CTRL_BOTH:
+	case BNX2X_FLOW_CTRL_RX:
+	case BNX2X_FLOW_CTRL_BOTH:
 		*ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
 		break;
 
-	case FLOW_CTRL_NONE:
+	case BNX2X_FLOW_CTRL_NONE:
 	default:
 		*ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
 		break;
@@ -1463,18 +1463,18 @@
 {						/*  LD	    LP	 */
 	switch (pause_result) { 		/* ASYM P ASYM P */
 	case 0xb:       			/*   1  0   1  1 */
-		vars->flow_ctrl = FLOW_CTRL_TX;
+		vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
 		break;
 
 	case 0xe:       			/*   1  1   1  0 */
-		vars->flow_ctrl = FLOW_CTRL_RX;
+		vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
 		break;
 
 	case 0x5:       			/*   0  1   0  1 */
 	case 0x7:       			/*   0  1   1  1 */
 	case 0xd:       			/*   1  1   0  1 */
 	case 0xf:       			/*   1  1   1  1 */
-		vars->flow_ctrl = FLOW_CTRL_BOTH;
+		vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
 		break;
 
 	default:
@@ -1531,7 +1531,7 @@
 		DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
 		   pause_result);
 		bnx2x_pause_resolve(vars, pause_result);
-		if (vars->flow_ctrl == FLOW_CTRL_NONE &&
+		if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
 		     ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
 			bnx2x_cl45_read(bp, port,
 				      ext_phy_type,
@@ -1567,10 +1567,10 @@
 	u16 lp_pause;   /* link partner */
 	u16 pause_result;
 
-	vars->flow_ctrl = FLOW_CTRL_NONE;
+	vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 
 	/* resolve from gp_status in case of AN complete and not sgmii */
-	if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) &&
+	if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
 	    (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
 	    (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
 	    (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
@@ -1591,11 +1591,11 @@
 				 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
 		DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
 		bnx2x_pause_resolve(vars, pause_result);
-	} else if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) &&
+	} else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
 		   (bnx2x_ext_phy_resove_fc(params, vars))) {
 		return;
 	} else {
-		if (params->req_flow_ctrl == FLOW_CTRL_AUTO)
+		if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
 			vars->flow_ctrl = params->req_fc_auto_adv;
 		else
 			vars->flow_ctrl = params->req_flow_ctrl;
@@ -1728,11 +1728,11 @@
 				LINK_STATUS_PARALLEL_DETECTION_USED;
 
 		}
-		if (vars->flow_ctrl & FLOW_CTRL_TX)
+		if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
 			vars->link_status |=
 				LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
 
-		if (vars->flow_ctrl & FLOW_CTRL_RX)
+		if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
 			vars->link_status |=
 				LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
 
@@ -1742,7 +1742,7 @@
 		vars->phy_link_up = 0;
 
 		vars->duplex = DUPLEX_FULL;
-		vars->flow_ctrl = FLOW_CTRL_NONE;
+		vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 		vars->autoneg = AUTO_NEG_DISABLED;
 		vars->mac_type = MAC_TYPE_NONE;
 	}
@@ -3924,7 +3924,7 @@
 	vars->link_up = 0;
 	vars->line_speed = 0;
 	vars->duplex = DUPLEX_FULL;
-	vars->flow_ctrl = FLOW_CTRL_NONE;
+	vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 	vars->mac_type = MAC_TYPE_NONE;
 
 	if (params->switch_cfg ==  SWITCH_CFG_1G)
@@ -3946,12 +3946,12 @@
 		vars->link_up = 1;
 		vars->line_speed = SPEED_10000;
 		vars->duplex = DUPLEX_FULL;
-		vars->flow_ctrl = FLOW_CTRL_NONE;
+		vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 		vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
 		/* enable on E1.5 FPGA */
 		if (CHIP_IS_E1H(bp)) {
 			vars->flow_ctrl |=
-				(FLOW_CTRL_TX | FLOW_CTRL_RX);
+				(BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX);
 			vars->link_status |=
 					(LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
 					 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
@@ -3974,7 +3974,7 @@
 		vars->link_up = 1;
 		vars->line_speed = SPEED_10000;
 		vars->duplex = DUPLEX_FULL;
-		vars->flow_ctrl = FLOW_CTRL_NONE;
+		vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 		vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
 
 		bnx2x_bmac_enable(params, vars, 0);
@@ -3994,7 +3994,7 @@
 		vars->link_up = 1;
 		vars->line_speed = SPEED_10000;
 		vars->duplex = DUPLEX_FULL;
-		vars->flow_ctrl = FLOW_CTRL_NONE;
+		vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 		vars->mac_type = MAC_TYPE_BMAC;
 
 		vars->phy_flags = PHY_XGXS_FLAG;
@@ -4009,7 +4009,7 @@
 		vars->link_up = 1;
 		vars->line_speed = SPEED_1000;
 		vars->duplex = DUPLEX_FULL;
-		vars->flow_ctrl = FLOW_CTRL_NONE;
+		vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 		vars->mac_type = MAC_TYPE_EMAC;
 
 		vars->phy_flags = PHY_XGXS_FLAG;
@@ -4026,7 +4026,7 @@
 		vars->link_up = 1;
 		vars->line_speed = SPEED_10000;
 		vars->duplex = DUPLEX_FULL;
-		vars->flow_ctrl = FLOW_CTRL_NONE;
+		vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 
 		vars->phy_flags = PHY_XGXS_FLAG;
 
diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h
index 86d54a1..47cb585 100644
--- a/drivers/net/bnx2x_link.h
+++ b/drivers/net/bnx2x_link.h
@@ -26,11 +26,11 @@
 
 
 
-#define FLOW_CTRL_AUTO		PORT_FEATURE_FLOW_CONTROL_AUTO
-#define FLOW_CTRL_TX		PORT_FEATURE_FLOW_CONTROL_TX
-#define FLOW_CTRL_RX		PORT_FEATURE_FLOW_CONTROL_RX
-#define FLOW_CTRL_BOTH		PORT_FEATURE_FLOW_CONTROL_BOTH
-#define FLOW_CTRL_NONE		PORT_FEATURE_FLOW_CONTROL_NONE
+#define BNX2X_FLOW_CTRL_AUTO		PORT_FEATURE_FLOW_CONTROL_AUTO
+#define BNX2X_FLOW_CTRL_TX		PORT_FEATURE_FLOW_CONTROL_TX
+#define BNX2X_FLOW_CTRL_RX		PORT_FEATURE_FLOW_CONTROL_RX
+#define BNX2X_FLOW_CTRL_BOTH		PORT_FEATURE_FLOW_CONTROL_BOTH
+#define BNX2X_FLOW_CTRL_NONE		PORT_FEATURE_FLOW_CONTROL_NONE
 
 #define SPEED_AUTO_NEG	    0
 #define SPEED_12000		12000
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 600210d..ef8103b 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -1328,7 +1328,6 @@
 			dev_kfree_skb(skb);
 		}
 
-		bp->dev->last_rx = jiffies;
 
 		/* put new skb in bin */
 		fp->tpa_pool[queue].skb = new_skb;
@@ -1557,7 +1556,6 @@
 #endif
 			netif_receive_skb(skb);
 
-		bp->dev->last_rx = jiffies;
 
 next_rx:
 		rx_buf->skb = NULL;
@@ -1594,7 +1592,6 @@
 {
 	struct bnx2x_fastpath *fp = fp_cookie;
 	struct bnx2x *bp = fp->bp;
-	struct net_device *dev = bp->dev;
 	int index = FP_IDX(fp);
 
 	/* Return here if interrupt is disabled */
@@ -1617,7 +1614,7 @@
 	prefetch(&fp->status_blk->c_status_block.status_block_index);
 	prefetch(&fp->status_blk->u_status_block.status_block_index);
 
-	netif_rx_schedule(dev, &bnx2x_fp(bp, index, napi));
+	netif_rx_schedule(&bnx2x_fp(bp, index, napi));
 
 	return IRQ_HANDLED;
 }
@@ -1656,7 +1653,7 @@
 		prefetch(&fp->status_blk->c_status_block.status_block_index);
 		prefetch(&fp->status_blk->u_status_block.status_block_index);
 
-		netif_rx_schedule(dev, &bnx2x_fp(bp, 0, napi));
+		netif_rx_schedule(&bnx2x_fp(bp, 0, napi));
 
 		status &= ~mask;
 	}
@@ -1923,10 +1920,10 @@
 		else
 			printk("half duplex");
 
-		if (bp->link_vars.flow_ctrl != FLOW_CTRL_NONE) {
-			if (bp->link_vars.flow_ctrl & FLOW_CTRL_RX) {
+		if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) {
+			if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) {
 				printk(", receive ");
-				if (bp->link_vars.flow_ctrl & FLOW_CTRL_TX)
+				if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
 					printk("& transmit ");
 			} else {
 				printk(", transmit ");
@@ -1950,11 +1947,11 @@
 		/* It is recommended to turn off RX FC for jumbo frames
 		   for better performance */
 		if (IS_E1HMF(bp))
-			bp->link_params.req_fc_auto_adv = FLOW_CTRL_BOTH;
+			bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH;
 		else if (bp->dev->mtu > 5000)
-			bp->link_params.req_fc_auto_adv = FLOW_CTRL_TX;
+			bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_TX;
 		else
-			bp->link_params.req_fc_auto_adv = FLOW_CTRL_BOTH;
+			bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH;
 
 		bnx2x_acquire_phy_lock(bp);
 		rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars);
@@ -7364,9 +7361,9 @@
 
 	bp->link_params.req_flow_ctrl = (bp->port.link_config &
 					 PORT_FEATURE_FLOW_CONTROL_MASK);
-	if ((bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) &&
+	if ((bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
 	    !(bp->port.supported & SUPPORTED_Autoneg))
-		bp->link_params.req_flow_ctrl = FLOW_CTRL_NONE;
+		bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 
 	BNX2X_DEV_INFO("req_line_speed %d  req_duplex %d  req_flow_ctrl 0x%x"
 		       "  advertising 0x%x\n",
@@ -8355,13 +8352,13 @@
 {
 	struct bnx2x *bp = netdev_priv(dev);
 
-	epause->autoneg = (bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) &&
+	epause->autoneg = (bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
 			  (bp->link_params.req_line_speed == SPEED_AUTO_NEG);
 
-	epause->rx_pause = ((bp->link_vars.flow_ctrl & FLOW_CTRL_RX) ==
-			    FLOW_CTRL_RX);
-	epause->tx_pause = ((bp->link_vars.flow_ctrl & FLOW_CTRL_TX) ==
-			    FLOW_CTRL_TX);
+	epause->rx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) ==
+			    BNX2X_FLOW_CTRL_RX);
+	epause->tx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) ==
+			    BNX2X_FLOW_CTRL_TX);
 
 	DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
 	   DP_LEVEL "  autoneg %d  rx_pause %d  tx_pause %d\n",
@@ -8380,16 +8377,16 @@
 	   DP_LEVEL "  autoneg %d  rx_pause %d  tx_pause %d\n",
 	   epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
 
-	bp->link_params.req_flow_ctrl = FLOW_CTRL_AUTO;
+	bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
 
 	if (epause->rx_pause)
-		bp->link_params.req_flow_ctrl |= FLOW_CTRL_RX;
+		bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_RX;
 
 	if (epause->tx_pause)
-		bp->link_params.req_flow_ctrl |= FLOW_CTRL_TX;
+		bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_TX;
 
-	if (bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO)
-		bp->link_params.req_flow_ctrl = FLOW_CTRL_NONE;
+	if (bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
+		bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 
 	if (epause->autoneg) {
 		if (!(bp->port.supported & SUPPORTED_Autoneg)) {
@@ -8398,7 +8395,7 @@
 		}
 
 		if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
-			bp->link_params.req_flow_ctrl = FLOW_CTRL_AUTO;
+			bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
 	}
 
 	DP(NETIF_MSG_LINK,
@@ -8769,7 +8766,6 @@
 	rc = 0;
 
 test_loopback_rx_exit:
-	bp->dev->last_rx = jiffies;
 
 	fp->rx_bd_cons = NEXT_RX_IDX(fp->rx_bd_cons);
 	fp->rx_bd_prod = NEXT_RX_IDX(fp->rx_bd_prod);
@@ -9287,7 +9283,7 @@
 #ifdef BNX2X_STOP_ON_ERROR
 poll_panic:
 #endif
-		netif_rx_complete(bp->dev, napi);
+		netif_rx_complete(napi);
 
 		bnx2x_ack_sb(bp, FP_SB_ID(fp), USTORM_ID,
 			     le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1);
@@ -9853,11 +9849,8 @@
 			     mclist && (i < dev->mc_count);
 			     i++, mclist = mclist->next) {
 
-				DP(NETIF_MSG_IFUP, "Adding mcast MAC: "
-				   "%02x:%02x:%02x:%02x:%02x:%02x\n",
-				   mclist->dmi_addr[0], mclist->dmi_addr[1],
-				   mclist->dmi_addr[2], mclist->dmi_addr[3],
-				   mclist->dmi_addr[4], mclist->dmi_addr[5]);
+				DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
+				   mclist->dmi_addr);
 
 				crc = crc32c_le(0, mclist->dmi_addr, ETH_ALEN);
 				bit = (crc >> 24) & 0xff;
@@ -10008,6 +10001,25 @@
 }
 #endif
 
+static const struct net_device_ops bnx2x_netdev_ops = {
+	.ndo_open		= bnx2x_open,
+	.ndo_stop		= bnx2x_close,
+	.ndo_start_xmit		= bnx2x_start_xmit,
+	.ndo_set_multicast_list = bnx2x_set_rx_mode,
+	.ndo_set_mac_address	= bnx2x_change_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= bnx2x_ioctl,
+	.ndo_change_mtu		= bnx2x_change_mtu,
+	.ndo_tx_timeout		= bnx2x_tx_timeout,
+#ifdef BCM_VLAN
+	.ndo_vlan_rx_register	= bnx2x_vlan_rx_register,
+#endif
+#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+	.ndo_poll_controller	= poll_bnx2x,
+#endif
+};
+
+
 static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
 				    struct net_device *dev)
 {
@@ -10092,8 +10104,7 @@
 
 	dev->irq = pdev->irq;
 
-	bp->regview = ioremap_nocache(dev->base_addr,
-				      pci_resource_len(pdev, 0));
+	bp->regview = pci_ioremap_bar(pdev, 0);
 	if (!bp->regview) {
 		printk(KERN_ERR PFX "Cannot map register space, aborting\n");
 		rc = -ENOMEM;
@@ -10119,23 +10130,10 @@
 	REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0 + BP_PORT(bp)*16, 0);
 	REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0 + BP_PORT(bp)*16, 0);
 
-	dev->hard_start_xmit = bnx2x_start_xmit;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
+	dev->netdev_ops = &bnx2x_netdev_ops;
 	dev->ethtool_ops = &bnx2x_ethtool_ops;
-	dev->open = bnx2x_open;
-	dev->stop = bnx2x_close;
-	dev->set_multicast_list = bnx2x_set_rx_mode;
-	dev->set_mac_address = bnx2x_change_mac_addr;
-	dev->do_ioctl = bnx2x_ioctl;
-	dev->change_mtu = bnx2x_change_mtu;
-	dev->tx_timeout = bnx2x_tx_timeout;
-#ifdef BCM_VLAN
-	dev->vlan_rx_register = bnx2x_vlan_rx_register;
-#endif
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
-	dev->poll_controller = poll_bnx2x;
-#endif
 	dev->features |= NETIF_F_SG;
 	dev->features |= NETIF_F_HW_CSUM;
 	if (bp->flags & USING_DAC_FLAG)
@@ -10194,7 +10192,6 @@
 	struct net_device *dev = NULL;
 	struct bnx2x *bp;
 	int rc;
-	DECLARE_MAC_BUF(mac);
 
 	if (version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -10238,7 +10235,7 @@
 	       bnx2x_get_pcie_width(bp),
 	       (bnx2x_get_pcie_speed(bp) == 2) ? "5GHz (Gen2)" : "2.5GHz",
 	       dev->base_addr, bp->pdev->irq);
-	printk(KERN_CONT "node addr %s\n", print_mac(mac, dev->dev_addr));
+	printk(KERN_CONT "node addr %pM\n", dev->dev_addr);
 	return 0;
 
 init_one_exit:
diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile
index 5cdae2b..6f9c6fa 100644
--- a/drivers/net/bonding/Makefile
+++ b/drivers/net/bonding/Makefile
@@ -6,3 +6,6 @@
 
 bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o
 
+ipv6-$(subst m,y,$(CONFIG_IPV6)) += bond_ipv6.o
+bonding-objs += $(ipv6-y)
+
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 6106660..8c2e5ab 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -20,13 +20,12 @@
  *
  */
 
-//#define BONDING_DEBUG 1
-
 #include <linux/skbuff.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
+#include <linux/etherdevice.h>
 #include <linux/if_bonding.h>
 #include <linux/pkt_sched.h>
 #include <net/net_namespace.h>
@@ -96,33 +95,7 @@
 static u16 ad_ticks_per_sec;
 static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000;
 
-// ================= 3AD api to bonding and kernel code ==================
-static u16 __get_link_speed(struct port *port);
-static u8 __get_duplex(struct port *port);
-static inline void __initialize_port_locks(struct port *port);
-//conversions
-static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
-
-
-// ================= ad code helper functions ==================
-//needed by ad_rx_machine(...)
-static void __record_pdu(struct lacpdu *lacpdu, struct port *port);
-static void __record_default(struct port *port);
-static void __update_selected(struct lacpdu *lacpdu, struct port *port);
-static void __update_default_selected(struct port *port);
-static void __choose_matched(struct lacpdu *lacpdu, struct port *port);
-static void __update_ntt(struct lacpdu *lacpdu, struct port *port);
-
-//needed for ad_mux_machine(..)
-static void __attach_bond_to_agg(struct port *port);
-static void __detach_bond_from_agg(struct port *port);
-static int __agg_ports_are_ready(struct aggregator *aggregator);
-static void __set_agg_ports_ready(struct aggregator *aggregator, int val);
-
-//needed for ad_agg_selection_logic(...)
-static u32 __get_agg_bandwidth(struct aggregator *aggregator);
-static struct aggregator *__get_active_agg(struct aggregator *aggregator);
-
+static const u8 lacpdu_mcast_addr[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
 
 // ================= main 802.3ad protocol functions ==================
 static int ad_lacpdu_send(struct port *port);
@@ -136,7 +109,6 @@
 static void ad_clear_agg(struct aggregator *aggregator);
 static void ad_initialize_agg(struct aggregator *aggregator);
 static void ad_initialize_port(struct port *port, int lacp_fast);
-static void ad_initialize_lacpdu(struct lacpdu *Lacpdu);
 static void ad_enable_collecting_distributing(struct port *port);
 static void ad_disable_collecting_distributing(struct port *port);
 static void ad_marker_info_received(struct bond_marker *marker_info, struct port *port);
@@ -236,6 +208,17 @@
 	return &(SLAVE_AD_INFO(slave->next).aggregator);
 }
 
+/*
+ * __agg_has_partner
+ *
+ * Return nonzero if aggregator has a partner (denoted by a non-zero ether
+ * address for the partner).  Return 0 if not.
+ */
+static inline int __agg_has_partner(struct aggregator *agg)
+{
+	return !is_zero_ether_addr(agg->partner_system.mac_addr_value);
+}
+
 /**
  * __disable_port - disable the port's slave
  * @port: the port we're looking at
@@ -274,14 +257,14 @@
  * __get_agg_selection_mode - get the aggregator selection mode
  * @port: the port we're looking at
  *
- * Get the aggregator selection mode. Can be %BANDWIDTH or %COUNT.
+ * Get the aggregator selection mode. Can be %STABLE, %BANDWIDTH or %COUNT.
  */
 static inline u32 __get_agg_selection_mode(struct port *port)
 {
 	struct bonding *bond = __get_bond_by_port(port);
 
 	if (bond == NULL) {
-		return AD_BANDWIDTH;
+		return BOND_AD_STABLE;
 	}
 
 	return BOND_AD_INFO(bond).agg_select_mode;
@@ -369,7 +352,7 @@
 		}
 	}
 
-	dprintk("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed);
+	pr_debug("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed);
 	return speed;
 }
 
@@ -395,12 +378,12 @@
 		switch (slave->duplex) {
 		case DUPLEX_FULL:
 			retval=0x1;
-			dprintk("Port %d Received status full duplex update from adapter\n", port->actor_port_number);
+			pr_debug("Port %d Received status full duplex update from adapter\n", port->actor_port_number);
 			break;
 		case DUPLEX_HALF:
 		default:
 			retval=0x0;
-			dprintk("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number);
+			pr_debug("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number);
 			break;
 		}
 	}
@@ -473,33 +456,25 @@
  */
 static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
 {
-	// validate lacpdu and port
 	if (lacpdu && port) {
+		struct port_params *partner = &port->partner_oper;
+
 		// record the new parameter values for the partner operational
-		port->partner_oper_port_number = ntohs(lacpdu->actor_port);
-		port->partner_oper_port_priority = ntohs(lacpdu->actor_port_priority);
-		port->partner_oper_system = lacpdu->actor_system;
-		port->partner_oper_system_priority = ntohs(lacpdu->actor_system_priority);
-		port->partner_oper_key = ntohs(lacpdu->actor_key);
-		// zero partener's lase states
-		port->partner_oper_port_state = 0;
-		port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY);
-		port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_TIMEOUT);
-		port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_AGGREGATION);
-		port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION);
-		port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_COLLECTING);
-		port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_DISTRIBUTING);
-		port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_DEFAULTED);
-		port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_EXPIRED);
+		partner->port_number = ntohs(lacpdu->actor_port);
+		partner->port_priority = ntohs(lacpdu->actor_port_priority);
+		partner->system = lacpdu->actor_system;
+		partner->system_priority = ntohs(lacpdu->actor_system_priority);
+		partner->key = ntohs(lacpdu->actor_key);
+		partner->port_state = lacpdu->actor_state;
 
 		// set actor_oper_port_state.defaulted to FALSE
 		port->actor_oper_port_state &= ~AD_STATE_DEFAULTED;
 
 		// set the partner sync. to on if the partner is sync. and the port is matched
 		if ((port->sm_vars & AD_PORT_MATCHED) && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) {
-			port->partner_oper_port_state |= AD_STATE_SYNCHRONIZATION;
+			partner->port_state |= AD_STATE_SYNCHRONIZATION;
 		} else {
-			port->partner_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
+			partner->port_state &= ~AD_STATE_SYNCHRONIZATION;
 		}
 	}
 }
@@ -514,15 +489,10 @@
  */
 static void __record_default(struct port *port)
 {
-	// validate the port
 	if (port) {
 		// record the partner admin parameters
-		port->partner_oper_port_number = port->partner_admin_port_number;
-		port->partner_oper_port_priority = port->partner_admin_port_priority;
-		port->partner_oper_system = port->partner_admin_system;
-		port->partner_oper_system_priority = port->partner_admin_system_priority;
-		port->partner_oper_key = port->partner_admin_key;
-		port->partner_oper_port_state = port->partner_admin_port_state;
+		memcpy(&port->partner_oper, &port->partner_admin,
+		       sizeof(struct port_params));
 
 		// set actor_oper_port_state.defaulted to true
 		port->actor_oper_port_state |= AD_STATE_DEFAULTED;
@@ -544,16 +514,16 @@
  */
 static void __update_selected(struct lacpdu *lacpdu, struct port *port)
 {
-	// validate lacpdu and port
 	if (lacpdu && port) {
+		const struct port_params *partner = &port->partner_oper;
+
 		// check if any parameter is different
-		if ((ntohs(lacpdu->actor_port) != port->partner_oper_port_number) ||
-		    (ntohs(lacpdu->actor_port_priority) != port->partner_oper_port_priority) ||
-		    MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) ||
-		    (ntohs(lacpdu->actor_system_priority) != port->partner_oper_system_priority) ||
-		    (ntohs(lacpdu->actor_key) != port->partner_oper_key) ||
-		    ((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION))
-		   ) {
+		if (ntohs(lacpdu->actor_port) != partner->port_number
+		    || ntohs(lacpdu->actor_port_priority) != partner->port_priority
+		    || MAC_ADDRESS_COMPARE(&lacpdu->actor_system, &partner->system)
+		    || ntohs(lacpdu->actor_system_priority) != partner->system_priority
+		    || ntohs(lacpdu->actor_key) != partner->key
+		    || (lacpdu->actor_state & AD_STATE_AGGREGATION) != (partner->port_state & AD_STATE_AGGREGATION)) {
 			// update the state machine Selected variable
 			port->sm_vars &= ~AD_PORT_SELECTED;
 		}
@@ -574,16 +544,18 @@
  */
 static void __update_default_selected(struct port *port)
 {
-	// validate the port
 	if (port) {
+		const struct port_params *admin = &port->partner_admin;
+		const struct port_params *oper = &port->partner_oper;
+
 		// check if any parameter is different
-		if ((port->partner_admin_port_number != port->partner_oper_port_number) ||
-		    (port->partner_admin_port_priority != port->partner_oper_port_priority) ||
-		    MAC_ADDRESS_COMPARE(&(port->partner_admin_system), &(port->partner_oper_system)) ||
-		    (port->partner_admin_system_priority != port->partner_oper_system_priority) ||
-		    (port->partner_admin_key != port->partner_oper_key) ||
-		    ((port->partner_admin_port_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION))
-		   ) {
+		if (admin->port_number != oper->port_number
+		    || admin->port_priority != oper->port_priority
+		    || MAC_ADDRESS_COMPARE(&admin->system, &oper->system)
+		    || admin->system_priority != oper->system_priority
+		    || admin->key != oper->key
+		    || (admin->port_state & AD_STATE_AGGREGATION)
+			!= (oper->port_state & AD_STATE_AGGREGATION)) {
 			// update the state machine Selected variable
 			port->sm_vars &= ~AD_PORT_SELECTED;
 		}
@@ -658,8 +630,8 @@
 		    ((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) ||
 		    ((lacpdu->partner_state & AD_STATE_AGGREGATION) != (port->actor_oper_port_state & AD_STATE_AGGREGATION))
 		   ) {
-			// set ntt to be TRUE
-			port->ntt = 1;
+
+			port->ntt = true;
 		}
 	}
 }
@@ -798,6 +770,7 @@
 static inline void __update_lacpdu_from_port(struct port *port)
 {
 	struct lacpdu *lacpdu = &port->lacpdu;
+	const struct port_params *partner = &port->partner_oper;
 
 	/* update current actual Actor parameters */
 	/* lacpdu->subtype                   initialized
@@ -818,12 +791,12 @@
 	 * lacpdu->partner_information_length initialized
 	 */
 
-	lacpdu->partner_system_priority = htons(port->partner_oper_system_priority);
-	lacpdu->partner_system = port->partner_oper_system;
-	lacpdu->partner_key = htons(port->partner_oper_key);
-	lacpdu->partner_port_priority = htons(port->partner_oper_port_priority);
-	lacpdu->partner_port = htons(port->partner_oper_port_number);
-	lacpdu->partner_state = port->partner_oper_port_state;
+	lacpdu->partner_system_priority = htons(partner->system_priority);
+	lacpdu->partner_system = partner->system;
+	lacpdu->partner_key = htons(partner->key);
+	lacpdu->partner_port_priority = htons(partner->port_priority);
+	lacpdu->partner_port = htons(partner->port_number);
+	lacpdu->partner_state = partner->port_state;
 
 	/* lacpdu->reserved_3_2              initialized
 	 * lacpdu->tlv_type_collector_info   initialized
@@ -853,7 +826,6 @@
 	struct sk_buff *skb;
 	struct lacpdu_header *lacpdu_header;
 	int length = sizeof(struct lacpdu_header);
-	struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR;
 
 	skb = dev_alloc_skb(length);
 	if (!skb) {
@@ -868,11 +840,11 @@
 
 	lacpdu_header = (struct lacpdu_header *)skb_put(skb, length);
 
-	lacpdu_header->ad_header.destination_address = lacpdu_multicast_address;
-	/* Note: source addres is set to be the member's PERMANENT address, because we use it
-	   to identify loopback lacpdus in receive. */
-	lacpdu_header->ad_header.source_address = *((struct mac_addr *)(slave->perm_hwaddr));
-	lacpdu_header->ad_header.length_type = PKT_TYPE_LACPDU;
+	memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
+	/* Note: source addres is set to be the member's PERMANENT address,
+	   because we use it to identify loopback lacpdus in receive. */
+	memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
+	lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU;
 
 	lacpdu_header->lacpdu = port->lacpdu; // struct copy
 
@@ -895,7 +867,6 @@
 	struct sk_buff *skb;
 	struct bond_marker_header *marker_header;
 	int length = sizeof(struct bond_marker_header);
-	struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR;
 
 	skb = dev_alloc_skb(length + 16);
 	if (!skb) {
@@ -911,11 +882,11 @@
 
 	marker_header = (struct bond_marker_header *)skb_put(skb, length);
 
-	marker_header->ad_header.destination_address = lacpdu_multicast_address;
-	/* Note: source addres is set to be the member's PERMANENT address, because we use it
-	   to identify loopback MARKERs in receive. */
-	marker_header->ad_header.source_address = *((struct mac_addr *)(slave->perm_hwaddr));
-	marker_header->ad_header.length_type = PKT_TYPE_LACPDU;
+	memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
+	/* Note: source addres is set to be the member's PERMANENT address,
+	   because we use it to identify loopback MARKERs in receive. */
+	memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
+	marker_header->hdr.h_proto = PKT_TYPE_LACPDU;
 
 	marker_header->marker = *marker; // struct copy
 
@@ -972,7 +943,7 @@
 			break;
 		case AD_MUX_ATTACHED:
 			// check also if agg_select_timer expired(so the edable port will take place only after this timer)
-			if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper_port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) {
+			if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) {
 				port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING;// next state
 			} else if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) {	  // if UNSELECTED or STANDBY
 				port->sm_vars &= ~AD_PORT_READY_N;
@@ -984,7 +955,7 @@
 			break;
 		case AD_MUX_COLLECTING_DISTRIBUTING:
 			if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY) ||
-			    !(port->partner_oper_port_state & AD_STATE_SYNCHRONIZATION)
+			    !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION)
 			   ) {
 				port->sm_mux_state = AD_MUX_ATTACHED;// next state
 
@@ -1007,7 +978,7 @@
 
 	// check if the state machine was changed
 	if (port->sm_mux_state != last_state) {
-		dprintk("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state);
+		pr_debug("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state);
 		switch (port->sm_mux_state) {
 		case AD_MUX_DETACHED:
 			__detach_bond_from_agg(port);
@@ -1015,7 +986,7 @@
 			ad_disable_collecting_distributing(port);
 			port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
 			port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING;
-			port->ntt = 1;
+			port->ntt = true;
 			break;
 		case AD_MUX_WAITING:
 			port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0);
@@ -1026,13 +997,13 @@
 			port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
 			port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING;
 			ad_disable_collecting_distributing(port);
-			port->ntt = 1;
+			port->ntt = true;
 			break;
 		case AD_MUX_COLLECTING_DISTRIBUTING:
 			port->actor_oper_port_state |= AD_STATE_COLLECTING;
 			port->actor_oper_port_state |= AD_STATE_DISTRIBUTING;
 			ad_enable_collecting_distributing(port);
-			port->ntt = 1;
+			port->ntt = true;
 			break;
 		default:    //to silence the compiler
 			break;
@@ -1106,7 +1077,7 @@
 
 	// check if the State machine was changed or new lacpdu arrived
 	if ((port->sm_rx_state != last_state) || (lacpdu)) {
-		dprintk("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state);
+		pr_debug("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state);
 		switch (port->sm_rx_state) {
 		case AD_RX_INITIALIZE:
 			if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) {
@@ -1128,7 +1099,7 @@
 		case AD_RX_LACP_DISABLED:
 			port->sm_vars &= ~AD_PORT_SELECTED;
 			__record_default(port);
-			port->partner_oper_port_state &= ~AD_STATE_AGGREGATION;
+			port->partner_oper.port_state &= ~AD_STATE_AGGREGATION;
 			port->sm_vars |= AD_PORT_MATCHED;
 			port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
 			break;
@@ -1136,9 +1107,9 @@
 			//Reset of the Synchronization flag. (Standard 43.4.12)
 			//This reset cause to disable this port in the COLLECTING_DISTRIBUTING state of the
 			//mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port.
-			port->partner_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
+			port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION;
 			port->sm_vars &= ~AD_PORT_MATCHED;
-			port->partner_oper_port_state |= AD_SHORT_TIMEOUT;
+			port->partner_oper.port_state |= AD_SHORT_TIMEOUT;
 			port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
 			port->actor_oper_port_state |= AD_STATE_EXPIRED;
 			break;
@@ -1191,11 +1162,13 @@
 		// check if there is something to send
 		if (port->ntt && (port->sm_vars & AD_PORT_LACP_ENABLED)) {
 			__update_lacpdu_from_port(port);
-			// send the lacpdu
+
 			if (ad_lacpdu_send(port) >= 0) {
-				dprintk("Sent LACPDU on port %d\n", port->actor_port_number);
-				// mark ntt as false, so it will not be sent again until demanded
-				port->ntt = 0;
+				pr_debug("Sent LACPDU on port %d\n", port->actor_port_number);
+
+				/* mark ntt as false, so it will not be sent again until
+				   demanded */
+				port->ntt = false;
 			}
 		}
 		// restart tx timer(to verify that we will not exceed AD_MAX_TX_IN_SECOND
@@ -1218,7 +1191,7 @@
 
 	// check if port was reinitialized
 	if (((port->sm_vars & AD_PORT_BEGIN) || !(port->sm_vars & AD_PORT_LACP_ENABLED) || !port->is_enabled) ||
-	    (!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper_port_state & AD_STATE_LACP_ACTIVITY))
+	    (!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper.port_state & AD_STATE_LACP_ACTIVITY))
 	   ) {
 		port->sm_periodic_state = AD_NO_PERIODIC;	     // next state
 	}
@@ -1232,12 +1205,12 @@
 			// If not expired, check if there is some new timeout parameter from the partner state
 			switch (port->sm_periodic_state) {
 			case AD_FAST_PERIODIC:
-				if (!(port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) {
+				if (!(port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) {
 					port->sm_periodic_state = AD_SLOW_PERIODIC;  // next state
 				}
 				break;
 			case AD_SLOW_PERIODIC:
-				if ((port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) {
+				if ((port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) {
 					// stop current timer
 					port->sm_periodic_timer_counter = 0;
 					port->sm_periodic_state = AD_PERIODIC_TX;	 // next state
@@ -1253,7 +1226,7 @@
 			port->sm_periodic_state = AD_FAST_PERIODIC;	 // next state
 			break;
 		case AD_PERIODIC_TX:
-			if (!(port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) {
+			if (!(port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) {
 				port->sm_periodic_state = AD_SLOW_PERIODIC;  // next state
 			} else {
 				port->sm_periodic_state = AD_FAST_PERIODIC;  // next state
@@ -1266,7 +1239,7 @@
 
 	// check if the state machine was changed
 	if (port->sm_periodic_state != last_state) {
-		dprintk("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state);
+		pr_debug("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state);
 		switch (port->sm_periodic_state) {
 		case AD_NO_PERIODIC:
 			port->sm_periodic_timer_counter = 0;	   // zero timer
@@ -1278,7 +1251,7 @@
 			port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_SLOW_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle
 			break;
 		case AD_PERIODIC_TX:
-			port->ntt = 1;
+			port->ntt = true;
 			break;
 		default:    //to silence the compiler
 			break;
@@ -1323,7 +1296,7 @@
 				port->next_port_in_aggregator=NULL;
 				port->actor_port_aggregator_identifier=0;
 
-				dprintk("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier);
+				pr_debug("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier);
 				// if the aggregator is empty, clear its parameters, and set it ready to be attached
 				if (!temp_aggregator->lag_ports) {
 					ad_clear_agg(temp_aggregator);
@@ -1352,11 +1325,11 @@
 		}
 		// check if current aggregator suits us
 		if (((aggregator->actor_oper_aggregator_key == port->actor_oper_port_key) && // if all parameters match AND
-		     !MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(port->partner_oper_system)) &&
-		     (aggregator->partner_system_priority == port->partner_oper_system_priority) &&
-		     (aggregator->partner_oper_aggregator_key == port->partner_oper_key)
+		     !MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(port->partner_oper.system)) &&
+		     (aggregator->partner_system_priority == port->partner_oper.system_priority) &&
+		     (aggregator->partner_oper_aggregator_key == port->partner_oper.key)
 		    ) &&
-		    ((MAC_ADDRESS_COMPARE(&(port->partner_oper_system), &(null_mac_addr)) && // partner answers
+		    ((MAC_ADDRESS_COMPARE(&(port->partner_oper.system), &(null_mac_addr)) && // partner answers
 		      !aggregator->is_individual)  // but is not individual OR
 		    )
 		   ) {
@@ -1366,7 +1339,7 @@
 			port->next_port_in_aggregator=aggregator->lag_ports;
 			port->aggregator->num_of_ports++;
 			aggregator->lag_ports=port;
-			dprintk("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
+			pr_debug("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
 
 			// mark this port as selected
 			port->sm_vars |= AD_PORT_SELECTED;
@@ -1385,16 +1358,16 @@
 			// update the new aggregator's parameters
 			// if port was responsed from the end-user
 			if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS) {// if port is full duplex
-				port->aggregator->is_individual = 0;
+				port->aggregator->is_individual = false;
 			} else {
-				port->aggregator->is_individual = 1;
+				port->aggregator->is_individual = true;
 			}
 
 			port->aggregator->actor_admin_aggregator_key = port->actor_admin_port_key;
 			port->aggregator->actor_oper_aggregator_key = port->actor_oper_port_key;
-			port->aggregator->partner_system=port->partner_oper_system;
-			port->aggregator->partner_system_priority = port->partner_oper_system_priority;
-			port->aggregator->partner_oper_aggregator_key = port->partner_oper_key;
+			port->aggregator->partner_system=port->partner_oper.system;
+			port->aggregator->partner_system_priority = port->partner_oper.system_priority;
+			port->aggregator->partner_oper_aggregator_key = port->partner_oper.key;
 			port->aggregator->receive_state = 1;
 			port->aggregator->transmit_state = 1;
 			port->aggregator->lag_ports = port;
@@ -1403,7 +1376,7 @@
 			// mark this port as selected
 			port->sm_vars |= AD_PORT_SELECTED;
 
-			dprintk("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
+			pr_debug("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
 		} else {
 			printk(KERN_ERR DRV_NAME ": %s: Port %d (on %s) did not find a suitable aggregator\n",
 			       port->slave->dev->master->name,
@@ -1414,9 +1387,82 @@
 	// else set ready=FALSE in all aggregator's ports
 	__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
 
-	if (!__check_agg_selection_timer(port) && (aggregator = __get_first_agg(port))) {
-		ad_agg_selection_logic(aggregator);
+	aggregator = __get_first_agg(port);
+	ad_agg_selection_logic(aggregator);
+}
+
+/*
+ * Decide if "agg" is a better choice for the new active aggregator that
+ * the current best, according to the ad_select policy.
+ */
+static struct aggregator *ad_agg_selection_test(struct aggregator *best,
+						struct aggregator *curr)
+{
+	/*
+	 * 0. If no best, select current.
+	 *
+	 * 1. If the current agg is not individual, and the best is
+	 *    individual, select current.
+	 *
+	 * 2. If current agg is individual and the best is not, keep best.
+	 *
+	 * 3. Therefore, current and best are both individual or both not
+	 *    individual, so:
+	 *
+	 * 3a. If current agg partner replied, and best agg partner did not,
+	 *     select current.
+	 *
+	 * 3b. If current agg partner did not reply and best agg partner
+	 *     did reply, keep best.
+	 *
+	 * 4.  Therefore, current and best both have partner replies or
+	 *     both do not, so perform selection policy:
+	 *
+	 * BOND_AD_COUNT: Select by count of ports.  If count is equal,
+	 *     select by bandwidth.
+	 *
+	 * BOND_AD_STABLE, BOND_AD_BANDWIDTH: Select by bandwidth.
+	 */
+	if (!best)
+		return curr;
+
+	if (!curr->is_individual && best->is_individual)
+		return curr;
+
+	if (curr->is_individual && !best->is_individual)
+		return best;
+
+	if (__agg_has_partner(curr) && !__agg_has_partner(best))
+		return curr;
+
+	if (!__agg_has_partner(curr) && __agg_has_partner(best))
+		return best;
+
+	switch (__get_agg_selection_mode(curr->lag_ports)) {
+	case BOND_AD_COUNT:
+		if (curr->num_of_ports > best->num_of_ports)
+			return curr;
+
+		if (curr->num_of_ports < best->num_of_ports)
+			return best;
+
+		/*FALLTHROUGH*/
+	case BOND_AD_STABLE:
+	case BOND_AD_BANDWIDTH:
+		if (__get_agg_bandwidth(curr) > __get_agg_bandwidth(best))
+			return curr;
+
+		break;
+
+	default:
+		printk(KERN_WARNING DRV_NAME
+		       ": %s: Impossible agg select mode %d\n",
+		       curr->slave->dev->master->name,
+		       __get_agg_selection_mode(curr->lag_ports));
+		break;
 	}
+
+	return best;
 }
 
 /**
@@ -1424,156 +1470,138 @@
  * @aggregator: the aggregator we're looking at
  *
  * It is assumed that only one aggregator may be selected for a team.
- * The logic of this function is to select (at first time) the aggregator with
- * the most ports attached to it, and to reselect the active aggregator only if
- * the previous aggregator has no more ports related to it.
+ *
+ * The logic of this function is to select the aggregator according to
+ * the ad_select policy:
+ *
+ * BOND_AD_STABLE: select the aggregator with the most ports attached to
+ * it, and to reselect the active aggregator only if the previous
+ * aggregator has no more ports related to it.
+ *
+ * BOND_AD_BANDWIDTH: select the aggregator with the highest total
+ * bandwidth, and reselect whenever a link state change takes place or the
+ * set of slaves in the bond changes.
+ *
+ * BOND_AD_COUNT: select the aggregator with largest number of ports
+ * (slaves), and reselect whenever a link state change takes place or the
+ * set of slaves in the bond changes.
  *
  * FIXME: this function MUST be called with the first agg in the bond, or
  * __get_active_agg() won't work correctly. This function should be better
  * called with the bond itself, and retrieve the first agg from it.
  */
-static void ad_agg_selection_logic(struct aggregator *aggregator)
+static void ad_agg_selection_logic(struct aggregator *agg)
 {
-	struct aggregator *best_aggregator = NULL, *active_aggregator = NULL;
-	struct aggregator *last_active_aggregator = NULL, *origin_aggregator;
+	struct aggregator *best, *active, *origin;
 	struct port *port;
-	u16 num_of_aggs=0;
 
-	origin_aggregator = aggregator;
+	origin = agg;
 
-	//get current active aggregator
-	last_active_aggregator = __get_active_agg(aggregator);
+	active = __get_active_agg(agg);
+	best = active;
 
-	// search for the aggregator with the most ports attached to it.
 	do {
-		// count how many candidate lag's we have
-		if (aggregator->lag_ports) {
-			num_of_aggs++;
-		}
-		if (aggregator->is_active && !aggregator->is_individual &&   // if current aggregator is the active aggregator
-		    MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr))) {   // and partner answers to 802.3ad PDUs
-			if (aggregator->num_of_ports) {	// if any ports attached to the current aggregator
-				best_aggregator=NULL;	 // disregard the best aggregator that was chosen by now
-				break;		 // stop the selection of other aggregator if there are any ports attached to this active aggregator
-			} else { // no ports attached to this active aggregator
-				aggregator->is_active = 0; // mark this aggregator as not active anymore
-			}
-		}
-		if (aggregator->num_of_ports) {	// if any ports attached
-			if (best_aggregator) {	// if there is a candidte aggregator
-				//The reasons for choosing new best aggregator:
-				// 1. if current agg is NOT individual and the best agg chosen so far is individual OR
-				// current and best aggs are both individual or both not individual, AND
-				// 2a.  current agg partner reply but best agg partner do not reply OR
-				// 2b.  current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply AND
-				//      current has more ports/bandwidth, or same amount of ports but current has faster ports, THEN
-				//      current agg become best agg so far
+		agg->is_active = 0;
 
-				//if current agg is NOT individual and the best agg chosen so far is individual change best_aggregator
-				if (!aggregator->is_individual && best_aggregator->is_individual) {
-					best_aggregator=aggregator;
-				}
-				// current and best aggs are both individual or both not individual
-				else if ((aggregator->is_individual && best_aggregator->is_individual) ||
-					 (!aggregator->is_individual && !best_aggregator->is_individual)) {
-					//  current and best aggs are both individual or both not individual AND
-					//  current agg partner reply but best agg partner do not reply
-					if ((MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) &&
-					     !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) {
-						best_aggregator=aggregator;
-					}
-					//  current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply
-					else if (! (!MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) &&
-						    MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) {
-						if ((__get_agg_selection_mode(aggregator->lag_ports) == AD_BANDWIDTH)&&
-						    (__get_agg_bandwidth(aggregator) > __get_agg_bandwidth(best_aggregator))) {
-							best_aggregator=aggregator;
-						} else if (__get_agg_selection_mode(aggregator->lag_ports) == AD_COUNT) {
-							if (((aggregator->num_of_ports > best_aggregator->num_of_ports) &&
-							     (aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS))||
-							    ((aggregator->num_of_ports == best_aggregator->num_of_ports) &&
-							     ((u16)(aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS) >
-							      (u16)(best_aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS)))) {
-								best_aggregator=aggregator;
-							}
-						}
-					}
-				}
-			} else {
-				best_aggregator=aggregator;
-			}
-		}
-		aggregator->is_active = 0; // mark all aggregators as not active anymore
-	} while ((aggregator = __get_next_agg(aggregator)));
+		if (agg->num_of_ports)
+			best = ad_agg_selection_test(best, agg);
 
-	// if we have new aggregator selected, don't replace the old aggregator if it has an answering partner,
-	// or if both old aggregator and new aggregator don't have answering partner
-	if (best_aggregator) {
-		if (last_active_aggregator && last_active_aggregator->lag_ports && last_active_aggregator->lag_ports->is_enabled &&
-		    (MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) ||   // partner answers OR
-		     (!MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) &&	// both old and new
-		      !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr))))     // partner do not answer
-		   ) {
-			// if new aggregator has link, and old aggregator does not, replace old aggregator.(do nothing)
-			// -> don't replace otherwise.
-			if (!(!last_active_aggregator->actor_oper_aggregator_key && best_aggregator->actor_oper_aggregator_key)) {
-				best_aggregator=NULL;
-				last_active_aggregator->is_active = 1; // don't replace good old aggregator
+	} while ((agg = __get_next_agg(agg)));
 
+	if (best &&
+	    __get_agg_selection_mode(best->lag_ports) == BOND_AD_STABLE) {
+		/*
+		 * For the STABLE policy, don't replace the old active
+		 * aggregator if it's still active (it has an answering
+		 * partner) or if both the best and active don't have an
+		 * answering partner.
+		 */
+		if (active && active->lag_ports &&
+		    active->lag_ports->is_enabled &&
+		    (__agg_has_partner(active) ||
+		     (!__agg_has_partner(active) && !__agg_has_partner(best)))) {
+			if (!(!active->actor_oper_aggregator_key &&
+			      best->actor_oper_aggregator_key)) {
+				best = NULL;
+				active->is_active = 1;
 			}
 		}
 	}
 
-	// if there is new best aggregator, activate it
-	if (best_aggregator) {
-		for (aggregator = __get_first_agg(best_aggregator->lag_ports);
-		    aggregator;
-		    aggregator = __get_next_agg(aggregator)) {
+	if (best && (best == active)) {
+		best = NULL;
+		active->is_active = 1;
+	}
 
-			dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n",
-					aggregator->aggregator_identifier, aggregator->num_of_ports,
-					aggregator->actor_oper_aggregator_key, aggregator->partner_oper_aggregator_key,
-					aggregator->is_individual, aggregator->is_active);
+	// if there is new best aggregator, activate it
+	if (best) {
+		pr_debug("best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
+		       best->aggregator_identifier, best->num_of_ports,
+		       best->actor_oper_aggregator_key,
+		       best->partner_oper_aggregator_key,
+		       best->is_individual, best->is_active);
+		pr_debug("best ports %p slave %p %s\n",
+		       best->lag_ports, best->slave,
+		       best->slave ? best->slave->dev->name : "NULL");
+
+		for (agg = __get_first_agg(best->lag_ports); agg;
+		     agg = __get_next_agg(agg)) {
+
+			pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
+				agg->aggregator_identifier, agg->num_of_ports,
+				agg->actor_oper_aggregator_key,
+				agg->partner_oper_aggregator_key,
+				agg->is_individual, agg->is_active);
 		}
 
 		// check if any partner replys
-		if (best_aggregator->is_individual) {
-			printk(KERN_WARNING DRV_NAME ": %s: Warning: No 802.3ad response from "
-			       "the link partner for any adapters in the bond\n",
-			       best_aggregator->slave->dev->master->name);
+		if (best->is_individual) {
+			printk(KERN_WARNING DRV_NAME ": %s: Warning: No 802.3ad"
+			       " response from the link partner for any"
+			       " adapters in the bond\n",
+			       best->slave->dev->master->name);
 		}
 
-		// check if there are more than one aggregator
-		if (num_of_aggs > 1) {
-			dprintk("Warning: More than one Link Aggregation Group was "
-				"found in the bond. Only one group will function in the bond\n");
-		}
-
-		best_aggregator->is_active = 1;
-		dprintk("LAG %d choosed as the active LAG\n", best_aggregator->aggregator_identifier);
-		dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n",
-				best_aggregator->aggregator_identifier, best_aggregator->num_of_ports,
-				best_aggregator->actor_oper_aggregator_key, best_aggregator->partner_oper_aggregator_key,
-				best_aggregator->is_individual, best_aggregator->is_active);
+		best->is_active = 1;
+		pr_debug("LAG %d chosen as the active LAG\n",
+			best->aggregator_identifier);
+		pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
+			best->aggregator_identifier, best->num_of_ports,
+			best->actor_oper_aggregator_key,
+			best->partner_oper_aggregator_key,
+			best->is_individual, best->is_active);
 
 		// disable the ports that were related to the former active_aggregator
-		if (last_active_aggregator) {
-			for (port=last_active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
+		if (active) {
+			for (port = active->lag_ports; port;
+			     port = port->next_port_in_aggregator) {
 				__disable_port(port);
 			}
 		}
 	}
 
-	// if the selected aggregator is of join individuals(partner_system is NULL), enable their ports
-	active_aggregator = __get_active_agg(origin_aggregator);
+	/*
+	 * if the selected aggregator is of join individuals
+	 * (partner_system is NULL), enable their ports
+	 */
+	active = __get_active_agg(origin);
 
-	if (active_aggregator) {
-		if (!MAC_ADDRESS_COMPARE(&(active_aggregator->partner_system), &(null_mac_addr))) {
-			for (port=active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
+	if (active) {
+		if (!__agg_has_partner(active)) {
+			for (port = active->lag_ports; port;
+			     port = port->next_port_in_aggregator) {
 				__enable_port(port);
 			}
 		}
 	}
+
+	if (origin->slave) {
+		struct bonding *bond;
+
+		bond = bond_get_bond_by_slave(origin->slave);
+		if (bond)
+			bond_3ad_set_carrier(bond);
+	}
 }
 
 /**
@@ -1584,7 +1612,7 @@
 static void ad_clear_agg(struct aggregator *aggregator)
 {
 	if (aggregator) {
-		aggregator->is_individual = 0;
+		aggregator->is_individual = false;
 		aggregator->actor_admin_aggregator_key = 0;
 		aggregator->actor_oper_aggregator_key = 0;
 		aggregator->partner_system = null_mac_addr;
@@ -1595,7 +1623,7 @@
 		aggregator->lag_ports = NULL;
 		aggregator->is_active = 0;
 		aggregator->num_of_ports = 0;
-		dprintk("LAG %d was cleared\n", aggregator->aggregator_identifier);
+		pr_debug("LAG %d was cleared\n", aggregator->aggregator_identifier);
 	}
 }
 
@@ -1623,13 +1651,32 @@
  */
 static void ad_initialize_port(struct port *port, int lacp_fast)
 {
+	static const struct port_params tmpl = {
+		.system_priority = 0xffff,
+		.key             = 1,
+		.port_number     = 1,
+		.port_priority   = 0xff,
+		.port_state      = 1,
+	};
+	static const struct lacpdu lacpdu = {
+		.subtype		= 0x01,
+		.version_number = 0x01,
+		.tlv_type_actor_info = 0x01,
+		.actor_information_length = 0x14,
+		.tlv_type_partner_info = 0x02,
+		.partner_information_length = 0x14,
+		.tlv_type_collector_info = 0x03,
+		.collector_information_length = 0x10,
+		.collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY),
+	};
+
 	if (port) {
 		port->actor_port_number = 1;
 		port->actor_port_priority = 0xff;
 		port->actor_system = null_mac_addr;
 		port->actor_system_priority = 0xffff;
 		port->actor_port_aggregator_identifier = 0;
-		port->ntt = 0;
+		port->ntt = false;
 		port->actor_admin_port_key = 1;
 		port->actor_oper_port_key  = 1;
 		port->actor_admin_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY;
@@ -1639,19 +1686,10 @@
 			port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT;
 		}
 
-		port->partner_admin_system = null_mac_addr;
-		port->partner_oper_system  = null_mac_addr;
-		port->partner_admin_system_priority = 0xffff;
-		port->partner_oper_system_priority  = 0xffff;
-		port->partner_admin_key = 1;
-		port->partner_oper_key  = 1;
-		port->partner_admin_port_number = 1;
-		port->partner_oper_port_number  = 1;
-		port->partner_admin_port_priority = 0xff;
-		port->partner_oper_port_priority  = 0xff;
-		port->partner_admin_port_state = 1;
-		port->partner_oper_port_state  = 1;
-		port->is_enabled = 1;
+		memcpy(&port->partner_admin, &tmpl, sizeof(tmpl));
+		memcpy(&port->partner_oper, &tmpl, sizeof(tmpl));
+
+		port->is_enabled = true;
 		// ****** private parameters ******
 		port->sm_vars = 0x3;
 		port->sm_rx_state = 0;
@@ -1667,7 +1705,7 @@
 		port->next_port_in_aggregator = NULL;
 		port->transaction_id = 0;
 
-		ad_initialize_lacpdu(&(port->lacpdu));
+		memcpy(&port->lacpdu, &lacpdu, sizeof(lacpdu));
 	}
 }
 
@@ -1680,7 +1718,7 @@
 static void ad_enable_collecting_distributing(struct port *port)
 {
 	if (port->aggregator->is_active) {
-		dprintk("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
+		pr_debug("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
 		__enable_port(port);
 	}
 }
@@ -1693,7 +1731,7 @@
 static void ad_disable_collecting_distributing(struct port *port)
 {
 	if (port->aggregator && MAC_ADDRESS_COMPARE(&(port->aggregator->partner_system), &(null_mac_addr))) {
-		dprintk("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
+		pr_debug("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
 		__disable_port(port);
 	}
 }
@@ -1731,7 +1769,7 @@
 
 	// send the marker information
 	if (ad_marker_send(port, &marker) >= 0) {
-		dprintk("Sent Marker Information on port %d\n", port->actor_port_number);
+		pr_debug("Sent Marker Information on port %d\n", port->actor_port_number);
 	}
 }
 #endif
@@ -1755,7 +1793,7 @@
 	// send the marker response
 
 	if (ad_marker_send(port, &marker) >= 0) {
-		dprintk("Sent Marker Response on port %d\n", port->actor_port_number);
+		pr_debug("Sent Marker Response on port %d\n", port->actor_port_number);
 	}
 }
 
@@ -1776,53 +1814,6 @@
 	// DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW
 }
 
-/**
- * ad_initialize_lacpdu - initialize a given lacpdu structure
- * @lacpdu: lacpdu structure to initialize
- *
- */
-static void ad_initialize_lacpdu(struct lacpdu *lacpdu)
-{
-	u16 index;
-
-	// initialize lacpdu data
-	lacpdu->subtype = 0x01;
-	lacpdu->version_number = 0x01;
-	lacpdu->tlv_type_actor_info = 0x01;
-	lacpdu->actor_information_length = 0x14;
-	// lacpdu->actor_system_priority    updated on send
-	// lacpdu->actor_system             updated on send
-	// lacpdu->actor_key                updated on send
-	// lacpdu->actor_port_priority      updated on send
-	// lacpdu->actor_port               updated on send
-	// lacpdu->actor_state              updated on send
-	lacpdu->tlv_type_partner_info = 0x02;
-	lacpdu->partner_information_length = 0x14;
-	for (index=0; index<=2; index++) {
-		lacpdu->reserved_3_1[index]=0;
-	}
-	// lacpdu->partner_system_priority  updated on send
-	// lacpdu->partner_system           updated on send
-	// lacpdu->partner_key              updated on send
-	// lacpdu->partner_port_priority    updated on send
-	// lacpdu->partner_port             updated on send
-	// lacpdu->partner_state            updated on send
-	for (index=0; index<=2; index++) {
-		lacpdu->reserved_3_2[index]=0;
-	}
-	lacpdu->tlv_type_collector_info = 0x03;
-	lacpdu->collector_information_length= 0x10;
-	lacpdu->collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY);
-	for (index=0; index<=11; index++) {
-		lacpdu->reserved_12[index]=0;
-	}
-	lacpdu->tlv_type_terminator = 0x00;
-	lacpdu->terminator_length = 0;
-	for (index=0; index<=49; index++) {
-		lacpdu->reserved_50[index]=0;
-	}
-}
-
 //////////////////////////////////////////////////////////////////////////////////////
 // ================= AD exported functions to the main bonding code ==================
 //////////////////////////////////////////////////////////////////////////////////////
@@ -1830,6 +1821,19 @@
 // Check aggregators status in team every T seconds
 #define AD_AGGREGATOR_SELECTION_TIMER  8
 
+/*
+ * bond_3ad_initiate_agg_selection(struct bonding *bond)
+ *
+ * Set the aggregation selection timer, to initiate an agg selection in
+ * the very near future.  Called during first initialization, and during
+ * any down to up transitions of the bond.
+ */
+void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout)
+{
+	BOND_AD_INFO(bond).agg_select_timer = timeout;
+	BOND_AD_INFO(bond).agg_select_mode = bond->params.ad_select;
+}
+
 static u16 aggregator_identifier;
 
 /**
@@ -1854,9 +1858,9 @@
 		// initialize how many times this module is called in one second(should be about every 100ms)
 		ad_ticks_per_sec = tick_resolution;
 
-		// initialize the aggregator selection timer(to activate an aggregation selection after initialize)
-		BOND_AD_INFO(bond).agg_select_timer = (AD_AGGREGATOR_SELECTION_TIMER * ad_ticks_per_sec);
-		BOND_AD_INFO(bond).agg_select_mode = AD_BANDWIDTH;
+		bond_3ad_initiate_agg_selection(bond,
+						AD_AGGREGATOR_SELECTION_TIMER *
+						ad_ticks_per_sec);
 	}
 }
 
@@ -1956,7 +1960,7 @@
 		return;
 	}
 
-	dprintk("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier);
+	pr_debug("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier);
 
 	/* Tell the partner that this port is not suitable for aggregation */
 	port->actor_oper_port_state &= ~AD_STATE_AGGREGATION;
@@ -1980,7 +1984,7 @@
 			// if new aggregator found, copy the aggregator's parameters
 			// and connect the related lag_ports to the new aggregator
 			if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) {
-				dprintk("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier);
+				pr_debug("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier);
 
 				if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) {
 					printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n",
@@ -2031,7 +2035,7 @@
 		}
 	}
 
-	dprintk("Unbinding port %d\n", port->actor_port_number);
+	pr_debug("Unbinding port %d\n", port->actor_port_number);
 	// find the aggregator that this port is connected to
 	temp_aggregator = __get_first_agg(port);
 	for (; temp_aggregator; temp_aggregator = __get_next_agg(temp_aggregator)) {
@@ -2162,7 +2166,7 @@
 
 		switch (lacpdu->subtype) {
 		case AD_TYPE_LACPDU:
-			dprintk("Received LACPDU on port %d\n", port->actor_port_number);
+			pr_debug("Received LACPDU on port %d\n", port->actor_port_number);
 			ad_rx_machine(lacpdu, port);
 			break;
 
@@ -2171,17 +2175,17 @@
 
 			switch (((struct bond_marker *)lacpdu)->tlv_type) {
 			case AD_MARKER_INFORMATION_SUBTYPE:
-				dprintk("Received Marker Information on port %d\n", port->actor_port_number);
+				pr_debug("Received Marker Information on port %d\n", port->actor_port_number);
 				ad_marker_info_received((struct bond_marker *)lacpdu, port);
 				break;
 
 			case AD_MARKER_RESPONSE_SUBTYPE:
-				dprintk("Received Marker Response on port %d\n", port->actor_port_number);
+				pr_debug("Received Marker Response on port %d\n", port->actor_port_number);
 				ad_marker_response_received((struct bond_marker *)lacpdu, port);
 				break;
 
 			default:
-				dprintk("Received an unknown Marker subtype on slot %d\n", port->actor_port_number);
+				pr_debug("Received an unknown Marker subtype on slot %d\n", port->actor_port_number);
 			}
 		}
 	}
@@ -2209,7 +2213,7 @@
 
 	port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS;
 	port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1);
-	dprintk("Port %d changed speed\n", port->actor_port_number);
+	pr_debug("Port %d changed speed\n", port->actor_port_number);
 	// there is no need to reselect a new aggregator, just signal the
 	// state machines to reinitialize
 	port->sm_vars |= AD_PORT_BEGIN;
@@ -2237,7 +2241,7 @@
 
 	port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
 	port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port);
-	dprintk("Port %d changed duplex\n", port->actor_port_number);
+	pr_debug("Port %d changed duplex\n", port->actor_port_number);
 	// there is no need to reselect a new aggregator, just signal the
 	// state machines to reinitialize
 	port->sm_vars |= AD_PORT_BEGIN;
@@ -2267,14 +2271,14 @@
 	// on link down we are zeroing duplex and speed since some of the adaptors(ce1000.lan) report full duplex/speed instead of N/A(duplex) / 0(speed)
 	// on link up we are forcing recheck on the duplex and speed since some of he adaptors(ce1000.lan) report
 	if (link == BOND_LINK_UP) {
-		port->is_enabled = 1;
+		port->is_enabled = true;
 		port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
 		port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port);
 		port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS;
 		port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1);
 	} else {
 		/* link has failed */
-		port->is_enabled = 0;
+		port->is_enabled = false;
 		port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
 		port->actor_oper_port_key= (port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS);
 	}
@@ -2346,7 +2350,7 @@
 int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
 {
 	struct slave *slave, *start_at;
-	struct bonding *bond = dev->priv;
+	struct bonding *bond = netdev_priv(dev);
 	int slave_agg_no;
 	int slaves_in_agg;
 	int agg_id;
@@ -2426,7 +2430,7 @@
 
 int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev)
 {
-	struct bonding *bond = dev->priv;
+	struct bonding *bond = netdev_priv(dev);
 	struct slave *slave = NULL;
 	int ret = NET_RX_DROP;
 
@@ -2437,7 +2441,8 @@
 		goto out;
 
 	read_lock(&bond->lock);
-	slave = bond_get_slave_by_dev((struct bonding *)dev->priv, orig_dev);
+	slave = bond_get_slave_by_dev((struct bonding *)netdev_priv(dev),
+					orig_dev);
 	if (!slave)
 		goto out_unlock;
 
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index b5ee45f..8a83eb2 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -33,7 +33,6 @@
 #define AD_TIMER_INTERVAL       100 /*msec*/
 
 #define MULTICAST_LACPDU_ADDR    {0x01, 0x80, 0xC2, 0x00, 0x00, 0x02}
-#define AD_MULTICAST_LACPDU_ADDR    {MULTICAST_LACPDU_ADDR}
 
 #define AD_LACP_SLOW 0
 #define AD_LACP_FAST 1
@@ -42,10 +41,11 @@
 	u8 mac_addr_value[ETH_ALEN];
 } mac_addr_t;
 
-typedef enum {
-	AD_BANDWIDTH = 0,
-	AD_COUNT
-} agg_selection_t;
+enum {
+	BOND_AD_STABLE = 0,
+	BOND_AD_BANDWIDTH = 1,
+	BOND_AD_COUNT = 2,
+};
 
 // rx machine states(43.4.11 in the 802.3ad standard)
 typedef enum {
@@ -105,12 +105,6 @@
 
 #pragma pack(1)
 
-typedef struct ad_header {
-	struct mac_addr destination_address;
-	struct mac_addr source_address;
-	__be16 length_type;
-} ad_header_t;
-
 // Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard)
 typedef struct lacpdu {
 	u8 subtype;		     // = LACP(= 0x01)
@@ -143,7 +137,7 @@
 } lacpdu_t;
 
 typedef struct lacpdu_header {
-	struct ad_header ad_header;
+	struct ethhdr hdr;
 	struct lacpdu lacpdu;
 } lacpdu_header_t;
 
@@ -164,7 +158,7 @@
 } bond_marker_t;
 
 typedef struct bond_marker_header {
-	struct ad_header ad_header;
+	struct ethhdr hdr;
 	struct bond_marker marker;
 } bond_marker_header_t;
 
@@ -183,7 +177,7 @@
 typedef struct aggregator {
 	struct mac_addr aggregator_mac_address;
 	u16 aggregator_identifier;
-	u16 is_individual;		 // BOOLEAN
+	bool is_individual;
 	u16 actor_admin_aggregator_key;
 	u16 actor_oper_aggregator_key;
 	struct mac_addr partner_system;
@@ -198,6 +192,15 @@
 	u16 num_of_ports;
 } aggregator_t;
 
+struct port_params {
+	struct mac_addr system;
+	u16 system_priority;
+	u16 key;
+	u16 port_number;
+	u16 port_priority;
+	u16 port_state;
+};
+
 // port structure(43.4.6 in the 802.3ad standard)
 typedef struct port {
 	u16 actor_port_number;
@@ -205,24 +208,17 @@
 	struct mac_addr actor_system;	       // This parameter is added here although it is not specified in the standard, just for simplification
 	u16 actor_system_priority;	 // This parameter is added here although it is not specified in the standard, just for simplification
 	u16 actor_port_aggregator_identifier;
-	u16 ntt;			 // BOOLEAN
+	bool ntt;
 	u16 actor_admin_port_key;
 	u16 actor_oper_port_key;
 	u8 actor_admin_port_state;
 	u8 actor_oper_port_state;
-	struct mac_addr partner_admin_system;
-	struct mac_addr partner_oper_system;
-	u16 partner_admin_system_priority;
-	u16 partner_oper_system_priority;
-	u16 partner_admin_key;
-	u16 partner_oper_key;
-	u16 partner_admin_port_number;
-	u16 partner_oper_port_number;
-	u16 partner_admin_port_priority;
-	u16 partner_oper_port_priority;
-	u8 partner_admin_port_state;
-	u8 partner_oper_port_state;
-	u16 is_enabled;	      // BOOLEAN
+
+	struct port_params partner_admin;
+	struct port_params partner_oper;
+
+	bool is_enabled;
+
 	// ****** PRIVATE PARAMETERS ******
 	u16 sm_vars;	      // all state machines variables for this port
 	rx_states_t sm_rx_state;	// state machine rx state
@@ -241,10 +237,10 @@
 } port_t;
 
 // system structure
-typedef struct ad_system {
+struct ad_system {
 	u16 sys_priority;
 	struct mac_addr sys_mac_addr;
-} ad_system_t;
+};
 
 #ifdef __ia64__
 #pragma pack()
@@ -255,7 +251,7 @@
 #define SLAVE_AD_INFO(slave) ((slave)->ad_info)
 
 struct ad_bond_info {
-	ad_system_t system;	    // 802.3ad system structure
+	struct ad_system system;	    /* 802.3ad system structure */
 	u32 agg_select_timer;	    // Timer to select aggregator after all adapter's hand shakes
 	u32 agg_select_mode;	    // Mode of selection of active aggregator(bandwidth/count)
 	int lacp_fast;		/* whether fast periodic tx should be
@@ -277,6 +273,7 @@
 int  bond_3ad_bind_slave(struct slave *slave);
 void bond_3ad_unbind_slave(struct slave *slave);
 void bond_3ad_state_machine_handler(struct work_struct *);
+void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout);
 void bond_3ad_adapter_speed_changed(struct slave *slave);
 void bond_3ad_adapter_duplex_changed(struct slave *slave);
 void bond_3ad_handle_link_change(struct slave *slave, char link);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 87437c7..27fb7f5 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -20,8 +20,6 @@
  *
  */
 
-//#define BONDING_DEBUG 1
-
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -346,30 +344,37 @@
 
 static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype, struct net_device *orig_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond;
 	struct arp_pkt *arp = (struct arp_pkt *)skb->data;
 	int res = NET_RX_DROP;
 
 	if (dev_net(bond_dev) != &init_net)
 		goto out;
 
-	if (!(bond_dev->flags & IFF_MASTER))
+	while (bond_dev->priv_flags & IFF_802_1Q_VLAN)
+		bond_dev = vlan_dev_real_dev(bond_dev);
+
+	if (!(bond_dev->priv_flags & IFF_BONDING) ||
+	    !(bond_dev->flags & IFF_MASTER))
 		goto out;
 
 	if (!arp) {
-		dprintk("Packet has no ARP data\n");
+		pr_debug("Packet has no ARP data\n");
 		goto out;
 	}
 
 	if (skb->len < sizeof(struct arp_pkt)) {
-		dprintk("Packet is too small to be an ARP\n");
+		pr_debug("Packet is too small to be an ARP\n");
 		goto out;
 	}
 
 	if (arp->op_code == htons(ARPOP_REPLY)) {
 		/* update rx hash table for this ARP */
+		printk("rar: update orig %s bond_dev %s\n", orig_dev->name,
+		       bond_dev->name);
+		bond = netdev_priv(bond_dev);
 		rlb_update_entry_from_arp(bond, arp);
-		dprintk("Server received an ARP Reply from client\n");
+		pr_debug("Server received an ARP Reply from client\n");
 	}
 
 	res = NET_RX_SUCCESS;
@@ -723,7 +728,7 @@
 		if (tx_slave) {
 			memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN);
 		}
-		dprintk("Server sent ARP Reply packet\n");
+		pr_debug("Server sent ARP Reply packet\n");
 	} else if (arp->op_code == htons(ARPOP_REQUEST)) {
 		/* Create an entry in the rx_hashtbl for this client as a
 		 * place holder.
@@ -743,7 +748,7 @@
 		 * updated with their assigned mac.
 		 */
 		rlb_req_update_subnet_clients(bond, arp->ip_src);
-		dprintk("Server sent ARP Request packet\n");
+		pr_debug("Server sent ARP Request packet\n");
 	}
 
 	return tx_slave;
@@ -818,7 +823,7 @@
 
 	/*initialize packet type*/
 	pk_type->type = __constant_htons(ETH_P_ARP);
-	pk_type->dev = bond->dev;
+	pk_type->dev = NULL;
 	pk_type->func = rlb_arp_recv;
 
 	/* register to receive ARPs */
@@ -1211,11 +1216,6 @@
 	}
 
 	bond_for_each_slave(bond, slave, i) {
-		if (slave->dev->set_mac_address == NULL) {
-			res = -EOPNOTSUPP;
-			goto unwind;
-		}
-
 		/* save net_device's current hw address */
 		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
 
@@ -1224,9 +1224,8 @@
 		/* restore net_device's hw address */
 		memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
 
-		if (res) {
+		if (res)
 			goto unwind;
-		}
 	}
 
 	return 0;
@@ -1285,7 +1284,7 @@
 
 int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct ethhdr *eth_data;
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 	struct slave *tx_slave = NULL;
@@ -1706,7 +1705,7 @@
  */
 int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct sockaddr *sa = addr;
 	struct slave *slave, *swap_slave;
 	int res;
diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c
new file mode 100644
index 0000000..0d73bf5
--- /dev/null
+++ b/drivers/net/bonding/bond_ipv6.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright(c) 2008 Hewlett-Packard Development Company, L.P.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/if_vlan.h>
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+#include "bonding.h"
+
+/*
+ * Assign bond->master_ipv6 to the next IPv6 address in the list, or
+ * zero it out if there are none.
+ */
+static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr)
+{
+	struct inet6_dev *idev;
+	struct inet6_ifaddr *ifa;
+
+	if (!dev)
+		return;
+
+	idev = in6_dev_get(dev);
+	if (!idev)
+		return;
+
+	read_lock_bh(&idev->lock);
+	ifa = idev->addr_list;
+	if (ifa)
+		ipv6_addr_copy(addr, &ifa->addr);
+	else
+		ipv6_addr_set(addr, 0, 0, 0, 0);
+
+	read_unlock_bh(&idev->lock);
+
+	in6_dev_put(idev);
+}
+
+static void bond_na_send(struct net_device *slave_dev,
+			 struct in6_addr *daddr,
+			 int router,
+			 unsigned short vlan_id)
+{
+	struct in6_addr mcaddr;
+	struct icmp6hdr icmp6h = {
+		.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
+	};
+	struct sk_buff *skb;
+
+	icmp6h.icmp6_router = router;
+	icmp6h.icmp6_solicited = 0;
+	icmp6h.icmp6_override = 1;
+
+	addrconf_addr_solict_mult(daddr, &mcaddr);
+
+	pr_debug("ipv6 na on slave %s: dest %pI6, src %pI6\n",
+	       slave_dev->name, &mcaddr, daddr);
+
+	skb = ndisc_build_skb(slave_dev, &mcaddr, daddr, &icmp6h, daddr,
+			      ND_OPT_TARGET_LL_ADDR);
+
+	if (!skb) {
+		printk(KERN_ERR DRV_NAME ": NA packet allocation failed\n");
+		return;
+	}
+
+	if (vlan_id) {
+		skb = vlan_put_tag(skb, vlan_id);
+		if (!skb) {
+			printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n");
+			return;
+		}
+	}
+
+	ndisc_send_skb(skb, slave_dev, NULL, &mcaddr, daddr, &icmp6h);
+}
+
+/*
+ * Kick out an unsolicited Neighbor Advertisement for an IPv6 address on
+ * the bonding master.  This will help the switch learn our address
+ * if in active-backup mode.
+ *
+ * Caller must hold curr_slave_lock for read or better
+ */
+void bond_send_unsolicited_na(struct bonding *bond)
+{
+	struct slave *slave = bond->curr_active_slave;
+	struct vlan_entry *vlan;
+	struct inet6_dev *idev;
+	int is_router;
+
+	pr_debug("bond_send_unsol_na: bond %s slave %s\n", bond->dev->name,
+				slave ? slave->dev->name : "NULL");
+
+	if (!slave || !bond->send_unsol_na ||
+	    test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
+		return;
+
+	bond->send_unsol_na--;
+
+	idev = in6_dev_get(bond->dev);
+	if (!idev)
+		return;
+
+	is_router = !!idev->cnf.forwarding;
+
+	in6_dev_put(idev);
+
+	if (!ipv6_addr_any(&bond->master_ipv6))
+		bond_na_send(slave->dev, &bond->master_ipv6, is_router, 0);
+
+	list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+		if (!ipv6_addr_any(&vlan->vlan_ipv6)) {
+			bond_na_send(slave->dev, &vlan->vlan_ipv6, is_router,
+				     vlan->vlan_id);
+		}
+	}
+}
+
+/*
+ * bond_inet6addr_event: handle inet6addr notifier chain events.
+ *
+ * We keep track of device IPv6 addresses primarily to use as source
+ * addresses in NS probes.
+ *
+ * We track one IPv6 for the main device (if it has one).
+ */
+static int bond_inet6addr_event(struct notifier_block *this,
+				unsigned long event,
+				void *ptr)
+{
+	struct inet6_ifaddr *ifa = ptr;
+	struct net_device *vlan_dev, *event_dev = ifa->idev->dev;
+	struct bonding *bond;
+	struct vlan_entry *vlan;
+
+	if (dev_net(event_dev) != &init_net)
+		return NOTIFY_DONE;
+
+	list_for_each_entry(bond, &bond_dev_list, bond_list) {
+		if (bond->dev == event_dev) {
+			switch (event) {
+			case NETDEV_UP:
+				if (ipv6_addr_any(&bond->master_ipv6))
+					ipv6_addr_copy(&bond->master_ipv6,
+						       &ifa->addr);
+				return NOTIFY_OK;
+			case NETDEV_DOWN:
+				if (ipv6_addr_equal(&bond->master_ipv6,
+						    &ifa->addr))
+					bond_glean_dev_ipv6(bond->dev,
+							    &bond->master_ipv6);
+				return NOTIFY_OK;
+			default:
+				return NOTIFY_DONE;
+			}
+		}
+
+		list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+			vlan_dev = vlan_group_get_device(bond->vlgrp,
+							 vlan->vlan_id);
+			if (vlan_dev == event_dev) {
+				switch (event) {
+				case NETDEV_UP:
+					if (ipv6_addr_any(&vlan->vlan_ipv6))
+						ipv6_addr_copy(&vlan->vlan_ipv6,
+							       &ifa->addr);
+					return NOTIFY_OK;
+				case NETDEV_DOWN:
+					if (ipv6_addr_equal(&vlan->vlan_ipv6,
+							    &ifa->addr))
+						bond_glean_dev_ipv6(vlan_dev,
+								    &vlan->vlan_ipv6);
+					return NOTIFY_OK;
+				default:
+					return NOTIFY_DONE;
+				}
+			}
+		}
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block bond_inet6addr_notifier = {
+	.notifier_call = bond_inet6addr_event,
+};
+
+void bond_register_ipv6_notifier(void)
+{
+	register_inet6addr_notifier(&bond_inet6addr_notifier);
+}
+
+void bond_unregister_ipv6_notifier(void)
+{
+	unregister_inet6addr_notifier(&bond_inet6addr_notifier);
+}
+
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a3efba5..460c2ca 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -31,8 +31,6 @@
  *
  */
 
-//#define BONDING_DEBUG 1
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -89,6 +87,7 @@
 
 static int max_bonds	= BOND_DEFAULT_MAX_BONDS;
 static int num_grat_arp = 1;
+static int num_unsol_na = 1;
 static int miimon	= BOND_LINK_MON_INTERV;
 static int updelay	= 0;
 static int downdelay	= 0;
@@ -96,6 +95,7 @@
 static char *mode	= NULL;
 static char *primary	= NULL;
 static char *lacp_rate	= NULL;
+static char *ad_select  = NULL;
 static char *xmit_hash_policy = NULL;
 static int arp_interval = BOND_LINK_ARP_INTERV;
 static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
@@ -107,6 +107,8 @@
 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
 module_param(num_grat_arp, int, 0644);
 MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event");
+module_param(num_unsol_na, int, 0644);
+MODULE_PARM_DESC(num_unsol_na, "Number of unsolicited IPv6 Neighbor Advertisements packets to send on failover event");
 module_param(miimon, int, 0);
 MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
 module_param(updelay, int, 0);
@@ -127,6 +129,8 @@
 module_param(lacp_rate, charp, 0);
 MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner "
 			    "(slow/fast)");
+module_param(ad_select, charp, 0);
+MODULE_PARM_DESC(ad_select, "803.ad aggregation selection logic: stable (0, default), bandwidth (1), count (2)");
 module_param(xmit_hash_policy, charp, 0);
 MODULE_PARM_DESC(xmit_hash_policy, "XOR hashing method: 0 for layer 2 (default)"
 				   ", 1 for layer 3+4");
@@ -150,7 +154,6 @@
 static struct proc_dir_entry *bond_proc_dir = NULL;
 #endif
 
-extern struct rw_semaphore bonding_rwsem;
 static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
 static int arp_ip_count	= 0;
 static int bond_mode	= BOND_MODE_ROUNDROBIN;
@@ -158,13 +161,13 @@
 static int lacp_fast	= 0;
 
 
-struct bond_parm_tbl bond_lacp_tbl[] = {
+const struct bond_parm_tbl bond_lacp_tbl[] = {
 {	"slow",		AD_LACP_SLOW},
 {	"fast",		AD_LACP_FAST},
 {	NULL,		-1},
 };
 
-struct bond_parm_tbl bond_mode_tbl[] = {
+const struct bond_parm_tbl bond_mode_tbl[] = {
 {	"balance-rr",		BOND_MODE_ROUNDROBIN},
 {	"active-backup",	BOND_MODE_ACTIVEBACKUP},
 {	"balance-xor",		BOND_MODE_XOR},
@@ -175,14 +178,14 @@
 {	NULL,			-1},
 };
 
-struct bond_parm_tbl xmit_hashtype_tbl[] = {
+const struct bond_parm_tbl xmit_hashtype_tbl[] = {
 {	"layer2",		BOND_XMIT_POLICY_LAYER2},
 {	"layer3+4",		BOND_XMIT_POLICY_LAYER34},
 {	"layer2+3",		BOND_XMIT_POLICY_LAYER23},
 {	NULL,			-1},
 };
 
-struct bond_parm_tbl arp_validate_tbl[] = {
+const struct bond_parm_tbl arp_validate_tbl[] = {
 {	"none",			BOND_ARP_VALIDATE_NONE},
 {	"active",		BOND_ARP_VALIDATE_ACTIVE},
 {	"backup",		BOND_ARP_VALIDATE_BACKUP},
@@ -190,13 +193,20 @@
 {	NULL,			-1},
 };
 
-struct bond_parm_tbl fail_over_mac_tbl[] = {
+const struct bond_parm_tbl fail_over_mac_tbl[] = {
 {	"none",			BOND_FOM_NONE},
 {	"active",		BOND_FOM_ACTIVE},
 {	"follow",		BOND_FOM_FOLLOW},
 {	NULL,			-1},
 };
 
+struct bond_parm_tbl ad_select_tbl[] = {
+{	"stable",	BOND_AD_STABLE},
+{	"bandwidth",	BOND_AD_BANDWIDTH},
+{	"count",	BOND_AD_COUNT},
+{	NULL,		-1},
+};
+
 /*-------------------------- Forward declarations ---------------------------*/
 
 static void bond_send_gratuitous_arp(struct bonding *bond);
@@ -206,24 +216,20 @@
 
 static const char *bond_mode_name(int mode)
 {
-	switch (mode) {
-	case BOND_MODE_ROUNDROBIN :
-		return "load balancing (round-robin)";
-	case BOND_MODE_ACTIVEBACKUP :
-		return "fault-tolerance (active-backup)";
-	case BOND_MODE_XOR :
-		return "load balancing (xor)";
-	case BOND_MODE_BROADCAST :
-		return "fault-tolerance (broadcast)";
-	case BOND_MODE_8023AD:
-		return "IEEE 802.3ad Dynamic link aggregation";
-	case BOND_MODE_TLB:
-		return "transmit load balancing";
-	case BOND_MODE_ALB:
-		return "adaptive load balancing";
-	default:
+	static const char *names[] = {
+		[BOND_MODE_ROUNDROBIN] = "load balancing (round-robin)",
+		[BOND_MODE_ACTIVEBACKUP] = "fault-tolerance (active-backup)",
+		[BOND_MODE_XOR] = "load balancing (xor)",
+		[BOND_MODE_BROADCAST] = "fault-tolerance (broadcast)",
+		[BOND_MODE_8023AD]= "IEEE 802.3ad Dynamic link aggregation",
+		[BOND_MODE_TLB] = "transmit load balancing",
+		[BOND_MODE_ALB] = "adaptive load balancing",
+	};
+
+	if (mode < 0 || mode > BOND_MODE_ALB)
 		return "unknown";
-	}
+
+	return names[mode];
 }
 
 /*---------------------------------- VLAN -----------------------------------*/
@@ -239,17 +245,16 @@
 {
 	struct vlan_entry *vlan;
 
-	dprintk("bond: %s, vlan id %d\n",
+	pr_debug("bond: %s, vlan id %d\n",
 		(bond ? bond->dev->name: "None"), vlan_id);
 
-	vlan = kmalloc(sizeof(struct vlan_entry), GFP_KERNEL);
+	vlan = kzalloc(sizeof(struct vlan_entry), GFP_KERNEL);
 	if (!vlan) {
 		return -ENOMEM;
 	}
 
 	INIT_LIST_HEAD(&vlan->vlan_list);
 	vlan->vlan_id = vlan_id;
-	vlan->vlan_ip = 0;
 
 	write_lock_bh(&bond->lock);
 
@@ -257,7 +262,7 @@
 
 	write_unlock_bh(&bond->lock);
 
-	dprintk("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name);
+	pr_debug("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name);
 
 	return 0;
 }
@@ -274,7 +279,7 @@
 	struct vlan_entry *vlan;
 	int res = -ENODEV;
 
-	dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id);
+	pr_debug("bond: %s, vlan id %d\n", bond->dev->name, vlan_id);
 
 	write_lock_bh(&bond->lock);
 
@@ -282,12 +287,10 @@
 		if (vlan->vlan_id == vlan_id) {
 			list_del(&vlan->vlan_list);
 
-			if ((bond->params.mode == BOND_MODE_TLB) ||
-			    (bond->params.mode == BOND_MODE_ALB)) {
+			if (bond_is_lb(bond))
 				bond_alb_clear_vlan(bond, vlan_id);
-			}
 
-			dprintk("removed VLAN ID %d from bond %s\n", vlan_id,
+			pr_debug("removed VLAN ID %d from bond %s\n", vlan_id,
 				bond->dev->name);
 
 			kfree(vlan);
@@ -307,7 +310,7 @@
 		}
 	}
 
-	dprintk("couldn't find VLAN ID %d in bond %s\n", vlan_id,
+	pr_debug("couldn't find VLAN ID %d in bond %s\n", vlan_id,
 		bond->dev->name);
 
 out:
@@ -331,13 +334,13 @@
 
 	bond_for_each_slave(bond, slave, i) {
 		if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) {
-			dprintk("found VLAN challenged slave - %s\n",
+			pr_debug("found VLAN challenged slave - %s\n",
 				slave->dev->name);
 			return 1;
 		}
 	}
 
-	dprintk("no VLAN challenged slaves found\n");
+	pr_debug("no VLAN challenged slaves found\n");
 	return 0;
 }
 
@@ -442,7 +445,7 @@
  */
 static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group *grp)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave;
 	int i;
 
@@ -450,10 +453,11 @@
 
 	bond_for_each_slave(bond, slave, i) {
 		struct net_device *slave_dev = slave->dev;
+		const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
 
 		if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
-		    slave_dev->vlan_rx_register) {
-			slave_dev->vlan_rx_register(slave_dev, grp);
+		    slave_ops->ndo_vlan_rx_register) {
+			slave_ops->ndo_vlan_rx_register(slave_dev, grp);
 		}
 	}
 }
@@ -465,16 +469,17 @@
  */
 static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave;
 	int i, res;
 
 	bond_for_each_slave(bond, slave, i) {
 		struct net_device *slave_dev = slave->dev;
+		const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
 
 		if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) &&
-		    slave_dev->vlan_rx_add_vid) {
-			slave_dev->vlan_rx_add_vid(slave_dev, vid);
+		    slave_ops->ndo_vlan_rx_add_vid) {
+			slave_ops->ndo_vlan_rx_add_vid(slave_dev, vid);
 		}
 	}
 
@@ -493,21 +498,22 @@
  */
 static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave;
 	struct net_device *vlan_dev;
 	int i, res;
 
 	bond_for_each_slave(bond, slave, i) {
 		struct net_device *slave_dev = slave->dev;
+		const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
 
 		if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) &&
-		    slave_dev->vlan_rx_kill_vid) {
+		    slave_ops->ndo_vlan_rx_kill_vid) {
 			/* Save and then restore vlan_dev in the grp array,
 			 * since the slave's driver might clear it.
 			 */
 			vlan_dev = vlan_group_get_device(bond->vlgrp, vid);
-			slave_dev->vlan_rx_kill_vid(slave_dev, vid);
+			slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vid);
 			vlan_group_set_device(bond->vlgrp, vid, vlan_dev);
 		}
 	}
@@ -523,26 +529,23 @@
 static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev)
 {
 	struct vlan_entry *vlan;
+	const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
 
 	write_lock_bh(&bond->lock);
 
-	if (list_empty(&bond->vlan_list)) {
+	if (list_empty(&bond->vlan_list))
 		goto out;
-	}
 
 	if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
-	    slave_dev->vlan_rx_register) {
-		slave_dev->vlan_rx_register(slave_dev, bond->vlgrp);
-	}
+	    slave_ops->ndo_vlan_rx_register)
+		slave_ops->ndo_vlan_rx_register(slave_dev, bond->vlgrp);
 
 	if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
-	    !(slave_dev->vlan_rx_add_vid)) {
+	    !(slave_ops->ndo_vlan_rx_add_vid))
 		goto out;
-	}
 
-	list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-		slave_dev->vlan_rx_add_vid(slave_dev, vlan->vlan_id);
-	}
+	list_for_each_entry(vlan, &bond->vlan_list, vlan_list)
+		slave_ops->ndo_vlan_rx_add_vid(slave_dev, vlan->vlan_id);
 
 out:
 	write_unlock_bh(&bond->lock);
@@ -550,34 +553,32 @@
 
 static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *slave_dev)
 {
+	const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
 	struct vlan_entry *vlan;
 	struct net_device *vlan_dev;
 
 	write_lock_bh(&bond->lock);
 
-	if (list_empty(&bond->vlan_list)) {
+	if (list_empty(&bond->vlan_list))
 		goto out;
-	}
 
 	if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
-	    !(slave_dev->vlan_rx_kill_vid)) {
+	    !(slave_ops->ndo_vlan_rx_kill_vid))
 		goto unreg;
-	}
 
 	list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
 		/* Save and then restore vlan_dev in the grp array,
 		 * since the slave's driver might clear it.
 		 */
 		vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
-		slave_dev->vlan_rx_kill_vid(slave_dev, vlan->vlan_id);
+		slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vlan->vlan_id);
 		vlan_group_set_device(bond->vlgrp, vlan->vlan_id, vlan_dev);
 	}
 
 unreg:
 	if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
-	    slave_dev->vlan_rx_register) {
-		slave_dev->vlan_rx_register(slave_dev, NULL);
-	}
+	    slave_ops->ndo_vlan_rx_register)
+		slave_ops->ndo_vlan_rx_register(slave_dev, NULL);
 
 out:
 	write_unlock_bh(&bond->lock);
@@ -686,15 +687,15 @@
  */
 static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_dev, int reporting)
 {
+	const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
 	static int (* ioctl)(struct net_device *, struct ifreq *, int);
 	struct ifreq ifr;
 	struct mii_ioctl_data *mii;
 
-	if (bond->params.use_carrier) {
+	if (bond->params.use_carrier)
 		return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0;
-	}
 
-	ioctl = slave_dev->do_ioctl;
+	ioctl = slave_ops->ndo_do_ioctl;
 	if (ioctl) {
 		/* TODO: set pointer to correct ioctl on a per team member */
 		/*       bases to make this more efficient. that is, once  */
@@ -927,7 +928,7 @@
  */
 static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct dev_mc_list *dmi;
 
 	for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) {
@@ -1164,10 +1165,8 @@
 				bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
 			}
 
-			if ((bond->params.mode == BOND_MODE_TLB) ||
-			    (bond->params.mode == BOND_MODE_ALB)) {
+			if (bond_is_lb(bond))
 				bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
-			}
 		} else {
 			if (USES_PRIMARY(bond->params.mode)) {
 				printk(KERN_INFO DRV_NAME
@@ -1182,8 +1181,7 @@
 		bond_mc_swap(bond, new_active, old_active);
 	}
 
-	if ((bond->params.mode == BOND_MODE_TLB) ||
-	    (bond->params.mode == BOND_MODE_ALB)) {
+	if (bond_is_lb(bond)) {
 		bond_alb_handle_active_change(bond, new_active);
 		if (old_active)
 			bond_set_slave_inactive_flags(old_active);
@@ -1208,6 +1206,9 @@
 			bond->send_grat_arp = bond->params.num_grat_arp;
 			bond_send_gratuitous_arp(bond);
 
+			bond->send_unsol_na = bond->params.num_unsol_na;
+			bond_send_unsolicited_na(bond);
+
 			write_unlock_bh(&bond->curr_slave_lock);
 			read_unlock(&bond->lock);
 
@@ -1315,9 +1316,9 @@
 static int bond_sethwaddr(struct net_device *bond_dev,
 			  struct net_device *slave_dev)
 {
-	dprintk("bond_dev=%p\n", bond_dev);
-	dprintk("slave_dev=%p\n", slave_dev);
-	dprintk("slave_dev->addr_len=%d\n", slave_dev->addr_len);
+	pr_debug("bond_dev=%p\n", bond_dev);
+	pr_debug("slave_dev=%p\n", slave_dev);
+	pr_debug("slave_dev->addr_len=%d\n", slave_dev->addr_len);
 	memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len);
 	return 0;
 }
@@ -1364,14 +1365,12 @@
 	return 0;
 }
 
-
 static void bond_setup_by_slave(struct net_device *bond_dev,
 				struct net_device *slave_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 
-	bond_dev->neigh_setup           = slave_dev->neigh_setup;
-	bond_dev->header_ops		= slave_dev->header_ops;
+	bond_dev->header_ops	    = slave_dev->header_ops;
 
 	bond_dev->type		    = slave_dev->type;
 	bond_dev->hard_header_len   = slave_dev->hard_header_len;
@@ -1385,7 +1384,8 @@
 /* enslave device <slave> to bond device <master> */
 int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
+	const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
 	struct slave *new_slave = NULL;
 	struct dev_mc_list *dmi;
 	struct sockaddr addr;
@@ -1394,7 +1394,7 @@
 	int res = 0;
 
 	if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL &&
-		slave_dev->do_ioctl == NULL) {
+		slave_ops->ndo_do_ioctl == NULL) {
 		printk(KERN_WARNING DRV_NAME
 		       ": %s: Warning: no link monitoring support for %s\n",
 		       bond_dev->name, slave_dev->name);
@@ -1409,14 +1409,14 @@
 
 	/* already enslaved */
 	if (slave_dev->flags & IFF_SLAVE) {
-		dprintk("Error, Device was already enslaved\n");
+		pr_debug("Error, Device was already enslaved\n");
 		return -EBUSY;
 	}
 
 	/* vlan challenged mutual exclusion */
 	/* no need to lock since we're protected by rtnl_lock */
 	if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
-		dprintk("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
+		pr_debug("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
 		if (!list_empty(&bond->vlan_list)) {
 			printk(KERN_ERR DRV_NAME
 			       ": %s: Error: cannot enslave VLAN "
@@ -1434,7 +1434,7 @@
 			bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
 		}
 	} else {
-		dprintk("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
+		pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
 		if (bond->slave_cnt == 0) {
 			/* First slave, and it is not VLAN challenged,
 			 * so remove the block of adding VLANs over the bond.
@@ -1476,7 +1476,7 @@
 			goto err_undo_flags;
 	}
 
-	if (slave_dev->set_mac_address == NULL) {
+	if (slave_ops->ndo_set_mac_address == NULL) {
 		if (bond->slave_cnt == 0) {
 			printk(KERN_WARNING DRV_NAME
 			       ": %s: Warning: The first slave device "
@@ -1522,28 +1522,27 @@
 		addr.sa_family = slave_dev->type;
 		res = dev_set_mac_address(slave_dev, &addr);
 		if (res) {
-			dprintk("Error %d calling set_mac_address\n", res);
+			pr_debug("Error %d calling set_mac_address\n", res);
 			goto err_free;
 		}
 	}
 
 	res = netdev_set_master(slave_dev, bond_dev);
 	if (res) {
-		dprintk("Error %d calling netdev_set_master\n", res);
+		pr_debug("Error %d calling netdev_set_master\n", res);
 		goto err_restore_mac;
 	}
 	/* open the slave since the application closed it */
 	res = dev_open(slave_dev);
 	if (res) {
-		dprintk("Openning slave %s failed\n", slave_dev->name);
+		pr_debug("Openning slave %s failed\n", slave_dev->name);
 		goto err_unset_master;
 	}
 
 	new_slave->dev = slave_dev;
 	slave_dev->priv_flags |= IFF_BONDING;
 
-	if ((bond->params.mode == BOND_MODE_TLB) ||
-	    (bond->params.mode == BOND_MODE_ALB)) {
+	if (bond_is_lb(bond)) {
 		/* bond_alb_init_slave() must be called before all other stages since
 		 * it might fail and we do not want to have to undo everything
 		 */
@@ -1641,18 +1640,18 @@
 	if (!bond->params.miimon ||
 	    (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS)) {
 		if (bond->params.updelay) {
-			dprintk("Initial state of slave_dev is "
+			pr_debug("Initial state of slave_dev is "
 				"BOND_LINK_BACK\n");
 			new_slave->link  = BOND_LINK_BACK;
 			new_slave->delay = bond->params.updelay;
 		} else {
-			dprintk("Initial state of slave_dev is "
+			pr_debug("Initial state of slave_dev is "
 				"BOND_LINK_UP\n");
 			new_slave->link  = BOND_LINK_UP;
 		}
 		new_slave->jiffies = jiffies;
 	} else {
-		dprintk("Initial state of slave_dev is "
+		pr_debug("Initial state of slave_dev is "
 			"BOND_LINK_DOWN\n");
 		new_slave->link  = BOND_LINK_DOWN;
 	}
@@ -1713,7 +1712,7 @@
 		bond_set_slave_inactive_flags(new_slave);
 		break;
 	default:
-		dprintk("This slave is always active in trunk mode\n");
+		pr_debug("This slave is always active in trunk mode\n");
 
 		/* always active in trunk mode */
 		new_slave->state = BOND_STATE_ACTIVE;
@@ -1787,11 +1786,10 @@
  */
 int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave, *oldcurrent;
 	struct sockaddr addr;
 	int mac_addr_differ;
-	DECLARE_MAC_BUF(mac);
 
 	/* slave is not a slave or master is not master of this slave */
 	if (!(slave_dev->flags & IFF_SLAVE) ||
@@ -1820,11 +1818,11 @@
 		if (!mac_addr_differ && (bond->slave_cnt > 1))
 			printk(KERN_WARNING DRV_NAME
 			       ": %s: Warning: the permanent HWaddr of %s - "
-			       "%s - is still in use by %s. "
+			       "%pM - is still in use by %s. "
 			       "Set the HWaddr of %s to a different address "
 			       "to avoid conflicts.\n",
 			       bond_dev->name, slave_dev->name,
-			       print_mac(mac, slave->perm_hwaddr),
+			       slave->perm_hwaddr,
 			       bond_dev->name, slave_dev->name);
 	}
 
@@ -1860,8 +1858,7 @@
 		bond_change_active_slave(bond, NULL);
 	}
 
-	if ((bond->params.mode == BOND_MODE_TLB) ||
-	    (bond->params.mode == BOND_MODE_ALB)) {
+	if (bond_is_lb(bond)) {
 		/* Must be called only after the slave has been
 		 * detached from the list and the curr_active_slave
 		 * has been cleared (if our_slave == old_current),
@@ -1981,7 +1978,7 @@
 
 static void bond_destructor(struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 
 	if (bond->wq)
 		destroy_workqueue(bond->wq);
@@ -1999,7 +1996,7 @@
 */
 int  bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	int ret;
 
 	ret = bond_release(bond_dev, slave_dev);
@@ -2016,7 +2013,7 @@
  */
 static int bond_release_all(struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave;
 	struct net_device *slave_dev;
 	struct sockaddr addr;
@@ -2050,8 +2047,7 @@
 		 */
 		write_unlock_bh(&bond->lock);
 
-		if ((bond->params.mode == BOND_MODE_TLB) ||
-		    (bond->params.mode == BOND_MODE_ALB)) {
+		if (bond_is_lb(bond)) {
 			/* must be called only after the slave
 			 * has been detached from the list
 			 */
@@ -2147,7 +2143,7 @@
  */
 static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_device *slave_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *old_active = NULL;
 	struct slave *new_active = NULL;
 	int res = 0;
@@ -2196,7 +2192,7 @@
 
 static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 
 	info->bond_mode = bond->params.mode;
 	info->miimon = bond->params.miimon;
@@ -2210,7 +2206,7 @@
 
 static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave;
 	int i, found = 0;
 
@@ -2378,8 +2374,7 @@
 			if (bond->params.mode == BOND_MODE_8023AD)
 				bond_3ad_handle_link_change(slave, BOND_LINK_UP);
 
-			if ((bond->params.mode == BOND_MODE_TLB) ||
-			    (bond->params.mode == BOND_MODE_ALB))
+			if (bond_is_lb(bond))
 				bond_alb_handle_link_change(bond, slave,
 							    BOND_LINK_UP);
 
@@ -2464,6 +2459,12 @@
 		read_unlock(&bond->curr_slave_lock);
 	}
 
+	if (bond->send_unsol_na) {
+		read_lock(&bond->curr_slave_lock);
+		bond_send_unsolicited_na(bond);
+		read_unlock(&bond->curr_slave_lock);
+	}
+
 	if (bond_miimon_inspect(bond)) {
 		read_unlock(&bond->lock);
 		rtnl_lock();
@@ -2532,7 +2533,7 @@
 {
 	struct sk_buff *skb;
 
-	dprintk("arp %d on slave %s: dst %x src %x vid %d\n", arp_op,
+	pr_debug("arp %d on slave %s: dst %x src %x vid %d\n", arp_op,
 	       slave_dev->name, dest_ip, src_ip, vlan_id);
 	       
 	skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip,
@@ -2565,9 +2566,9 @@
 	for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) {
 		if (!targets[i])
 			continue;
-		dprintk("basa: target %x\n", targets[i]);
+		pr_debug("basa: target %x\n", targets[i]);
 		if (list_empty(&bond->vlan_list)) {
-			dprintk("basa: empty vlan: arp_send\n");
+			pr_debug("basa: empty vlan: arp_send\n");
 			bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
 				      bond->master_ip, 0);
 			continue;
@@ -2586,8 +2587,8 @@
 		if (rv) {
 			if (net_ratelimit()) {
 				printk(KERN_WARNING DRV_NAME
-			     ": %s: no route to arp_ip_target %u.%u.%u.%u\n",
-				       bond->dev->name, NIPQUAD(fl.fl4_dst));
+			     ": %s: no route to arp_ip_target %pI4\n",
+				       bond->dev->name, &fl.fl4_dst);
 			}
 			continue;
 		}
@@ -2597,7 +2598,7 @@
 		 */
 		if (rt->u.dst.dev == bond->dev) {
 			ip_rt_put(rt);
-			dprintk("basa: rtdev == bond->dev: arp_send\n");
+			pr_debug("basa: rtdev == bond->dev: arp_send\n");
 			bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
 				      bond->master_ip, 0);
 			continue;
@@ -2608,7 +2609,7 @@
 			vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
 			if (vlan_dev == rt->u.dst.dev) {
 				vlan_id = vlan->vlan_id;
-				dprintk("basa: vlan match on %s %d\n",
+				pr_debug("basa: vlan match on %s %d\n",
 				       vlan_dev->name, vlan_id);
 				break;
 			}
@@ -2623,8 +2624,8 @@
 
 		if (net_ratelimit()) {
 			printk(KERN_WARNING DRV_NAME
-	       ": %s: no path to arp_ip_target %u.%u.%u.%u via rt.dev %s\n",
-			       bond->dev->name, NIPQUAD(fl.fl4_dst),
+	       ": %s: no path to arp_ip_target %pI4 via rt.dev %s\n",
+			       bond->dev->name, &fl.fl4_dst,
 			       rt->u.dst.dev ? rt->u.dst.dev->name : "NULL");
 		}
 		ip_rt_put(rt);
@@ -2643,7 +2644,7 @@
 	struct vlan_entry *vlan;
 	struct net_device *vlan_dev;
 
-	dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name,
+	pr_debug("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name,
 				slave ? slave->dev->name : "NULL");
 
 	if (!slave || !bond->send_grat_arp ||
@@ -2673,10 +2674,8 @@
 
 	targets = bond->params.arp_targets;
 	for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
-		dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] "
-			"%u.%u.%u.%u bhti(tip) %d\n",
-		       NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]),
-		       bond_has_this_ip(bond, tip));
+		pr_debug("bva: sip %pI4 tip %pI4 t[%d] %pI4 bhti(tip) %d\n",
+			&sip, &tip, i, &targets[i], bond_has_this_ip(bond, tip));
 		if (sip == targets[i]) {
 			if (bond_has_this_ip(bond, tip))
 				slave->last_arp_rx = jiffies;
@@ -2699,10 +2698,10 @@
 	if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
 		goto out;
 
-	bond = dev->priv;
+	bond = netdev_priv(dev);
 	read_lock(&bond->lock);
 
-	dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n",
+	pr_debug("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n",
 		bond->dev->name, skb->dev ? skb->dev->name : "NULL",
 		orig_dev ? orig_dev->name : "NULL");
 
@@ -2728,10 +2727,10 @@
 	arp_ptr += 4 + dev->addr_len;
 	memcpy(&tip, arp_ptr, 4);
 
-	dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u"
-		" tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name,
-		slave->state, bond->params.arp_validate,
-		slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip));
+	pr_debug("bond_arp_rcv: %s %s/%d av %d sv %d sip %pI4 tip %pI4\n",
+		bond->dev->name, slave->dev->name, slave->state,
+		bond->params.arp_validate, slave_do_arp_validate(bond, slave),
+		&sip, &tip);
 
 	/*
 	 * Backup slaves won't see the ARP reply, but do come through
@@ -3161,6 +3160,12 @@
 		read_unlock(&bond->curr_slave_lock);
 	}
 
+	if (bond->send_unsol_na) {
+		read_lock(&bond->curr_slave_lock);
+		bond_send_unsolicited_na(bond);
+		read_unlock(&bond->curr_slave_lock);
+	}
+
 	if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
 		read_unlock(&bond->lock);
 		rtnl_lock();
@@ -3239,7 +3244,6 @@
 	struct bonding *bond = seq->private;
 	struct slave *curr;
 	int i;
-	u32 target;
 
 	read_lock(&bond->curr_slave_lock);
 	curr = bond->curr_active_slave;
@@ -3293,8 +3297,7 @@
 				continue;
 			if (printed)
 				seq_printf(seq, ",");
-			target = ntohl(bond->params.arp_targets[i]);
-			seq_printf(seq, " %d.%d.%d.%d", HIPQUAD(target));
+			seq_printf(seq, " %pI4", &bond->params.arp_targets[i]);
 			printed = 1;
 		}
 		seq_printf(seq, "\n");
@@ -3302,11 +3305,12 @@
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		struct ad_info ad_info;
-		DECLARE_MAC_BUF(mac);
 
 		seq_puts(seq, "\n802.3ad info\n");
 		seq_printf(seq, "LACP rate: %s\n",
 			   (bond->params.lacp_fast) ? "fast" : "slow");
+		seq_printf(seq, "Aggregator selection policy (ad_select): %s\n",
+			   ad_select_tbl[bond->params.ad_select].modename);
 
 		if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
 			seq_printf(seq, "bond %s has no active aggregator\n",
@@ -3322,8 +3326,8 @@
 				   ad_info.actor_key);
 			seq_printf(seq, "\tPartner Key: %d\n",
 				   ad_info.partner_key);
-			seq_printf(seq, "\tPartner Mac Address: %s\n",
-				   print_mac(mac, ad_info.partner_system));
+			seq_printf(seq, "\tPartner Mac Address: %pM\n",
+				   ad_info.partner_system);
 		}
 	}
 }
@@ -3331,7 +3335,6 @@
 static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave)
 {
 	struct bonding *bond = seq->private;
-	DECLARE_MAC_BUF(mac);
 
 	seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
 	seq_printf(seq, "MII Status: %s\n",
@@ -3339,9 +3342,7 @@
 	seq_printf(seq, "Link Failure Count: %u\n",
 		   slave->link_failure_count);
 
-	seq_printf(seq,
-		   "Permanent HW addr: %s\n",
-		   print_mac(mac, slave->perm_hwaddr));
+	seq_printf(seq, "Permanent HW addr: %pM\n", slave->perm_hwaddr);
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		const struct aggregator *agg
@@ -3506,7 +3507,7 @@
 
 static int bond_master_netdev_event(unsigned long event, struct net_device *bond_dev)
 {
-	struct bonding *event_bond = bond_dev->priv;
+	struct bonding *event_bond = netdev_priv(bond_dev);
 
 	switch (event) {
 	case NETDEV_CHANGENAME:
@@ -3524,7 +3525,7 @@
 static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev)
 {
 	struct net_device *bond_dev = slave_dev->master;
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 
 	switch (event) {
 	case NETDEV_UNREGISTER:
@@ -3591,7 +3592,7 @@
 	if (dev_net(event_dev) != &init_net)
 		return NOTIFY_DONE;
 
-	dprintk("event_dev: %s, event: %lx\n",
+	pr_debug("event_dev: %s, event: %lx\n",
 		(event_dev ? event_dev->name : "None"),
 		event);
 
@@ -3599,12 +3600,12 @@
 		return NOTIFY_DONE;
 
 	if (event_dev->flags & IFF_MASTER) {
-		dprintk("IFF_MASTER\n");
+		pr_debug("IFF_MASTER\n");
 		return bond_master_netdev_event(event, event_dev);
 	}
 
 	if (event_dev->flags & IFF_SLAVE) {
-		dprintk("IFF_SLAVE\n");
+		pr_debug("IFF_SLAVE\n");
 		return bond_slave_netdev_event(event, event_dev);
 	}
 
@@ -3775,12 +3776,11 @@
 
 static int bond_open(struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 
 	bond->kill_timers = 0;
 
-	if ((bond->params.mode == BOND_MODE_TLB) ||
-	    (bond->params.mode == BOND_MODE_ALB)) {
+	if (bond_is_lb(bond)) {
 		/* bond_alb_initialize must be called before the timer
 		 * is started.
 		 */
@@ -3816,6 +3816,7 @@
 		queue_delayed_work(bond->wq, &bond->ad_work, 0);
 		/* register to receive LACPDUs */
 		bond_register_lacpdu(bond);
+		bond_3ad_initiate_agg_selection(bond, 1);
 	}
 
 	return 0;
@@ -3823,7 +3824,7 @@
 
 static int bond_close(struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		/* Unregister the receive of LACPDUs */
@@ -3836,6 +3837,7 @@
 	write_lock_bh(&bond->lock);
 
 	bond->send_grat_arp = 0;
+	bond->send_unsol_na = 0;
 
 	/* signal timers not to re-arm */
 	bond->kill_timers = 1;
@@ -3863,8 +3865,7 @@
 	}
 
 
-	if ((bond->params.mode == BOND_MODE_TLB) ||
-	    (bond->params.mode == BOND_MODE_ALB)) {
+	if (bond_is_lb(bond)) {
 		/* Must be called only after all
 		 * slaves have been released
 		 */
@@ -3876,8 +3877,8 @@
 
 static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
-	struct net_device_stats *stats = &(bond->stats), *sstats;
+	struct bonding *bond = netdev_priv(bond_dev);
+	struct net_device_stats *stats = &bond->stats;
 	struct net_device_stats local_stats;
 	struct slave *slave;
 	int i;
@@ -3887,7 +3888,8 @@
 	read_lock_bh(&bond->lock);
 
 	bond_for_each_slave(bond, slave, i) {
-		sstats = slave->dev->get_stats(slave->dev);
+		const struct net_device_stats *sstats = dev_get_stats(slave->dev);
+
 		local_stats.rx_packets += sstats->rx_packets;
 		local_stats.rx_bytes += sstats->rx_bytes;
 		local_stats.rx_errors += sstats->rx_errors;
@@ -3932,7 +3934,7 @@
 	struct mii_ioctl_data *mii = NULL;
 	int res = 0;
 
-	dprintk("bond_ioctl: master=%s, cmd=%d\n",
+	pr_debug("bond_ioctl: master=%s, cmd=%d\n",
 		bond_dev->name, cmd);
 
 	switch (cmd) {
@@ -3954,7 +3956,7 @@
 		}
 
 		if (mii->reg_num == 1) {
-			struct bonding *bond = bond_dev->priv;
+			struct bonding *bond = netdev_priv(bond_dev);
 			mii->val_out = 0;
 			read_lock(&bond->lock);
 			read_lock(&bond->curr_slave_lock);
@@ -4010,12 +4012,12 @@
 	down_write(&(bonding_rwsem));
 	slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave);
 
-	dprintk("slave_dev=%p: \n", slave_dev);
+	pr_debug("slave_dev=%p: \n", slave_dev);
 
 	if (!slave_dev) {
 		res = -ENODEV;
 	} else {
-		dprintk("slave_dev->name=%s: \n", slave_dev->name);
+		pr_debug("slave_dev->name=%s: \n", slave_dev->name);
 		switch (cmd) {
 		case BOND_ENSLAVE_OLD:
 		case SIOCBONDENSLAVE:
@@ -4046,7 +4048,7 @@
 
 static void bond_set_multicast_list(struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct dev_mc_list *dmi;
 
 	/*
@@ -4102,17 +4104,31 @@
 	read_unlock(&bond->lock);
 }
 
+static int bond_neigh_setup(struct net_device *dev, struct neigh_parms *parms)
+{
+	struct bonding *bond = netdev_priv(dev);
+	struct slave *slave = bond->first_slave;
+
+	if (slave) {
+		const struct net_device_ops *slave_ops
+			= slave->dev->netdev_ops;
+		if (slave_ops->ndo_neigh_setup)
+			return slave_ops->ndo_neigh_setup(dev, parms);
+	}
+	return 0;
+}
+
 /*
  * Change the MTU of all of a master's slaves to match the master
  */
 static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave, *stop_at;
 	int res = 0;
 	int i;
 
-	dprintk("bond=%p, name=%s, new_mtu=%d\n", bond,
+	pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond,
 		(bond_dev ? bond_dev->name : "None"), new_mtu);
 
 	/* Can't hold bond->lock with bh disabled here since
@@ -4131,7 +4147,7 @@
 	 */
 
 	bond_for_each_slave(bond, slave, i) {
-		dprintk("s %p s->p %p c_m %p\n", slave,
+		pr_debug("s %p s->p %p c_m %p\n", slave,
 			slave->prev, slave->dev->change_mtu);
 
 		res = dev_set_mtu(slave->dev, new_mtu);
@@ -4145,7 +4161,7 @@
 			 * means changing their mtu from timer context, which
 			 * is probably not a good idea.
 			 */
-			dprintk("err %d %s\n", res, slave->dev->name);
+			pr_debug("err %d %s\n", res, slave->dev->name);
 			goto unwind;
 		}
 	}
@@ -4162,7 +4178,7 @@
 
 		tmp_res = dev_set_mtu(slave->dev, bond_dev->mtu);
 		if (tmp_res) {
-			dprintk("unwind err %d dev %s\n", tmp_res,
+			pr_debug("unwind err %d dev %s\n", tmp_res,
 				slave->dev->name);
 		}
 	}
@@ -4179,13 +4195,17 @@
  */
 static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct sockaddr *sa = addr, tmp_sa;
 	struct slave *slave, *stop_at;
 	int res = 0;
 	int i;
 
-	dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
+	if (bond->params.mode == BOND_MODE_ALB)
+		return bond_alb_set_mac_address(bond_dev, addr);
+
+
+	pr_debug("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
 
 	/*
 	 * If fail_over_mac is set to active, do nothing and return
@@ -4214,11 +4234,12 @@
 	 */
 
 	bond_for_each_slave(bond, slave, i) {
-		dprintk("slave %p %s\n", slave, slave->dev->name);
+		const struct net_device_ops *slave_ops = slave->dev->netdev_ops;
+		pr_debug("slave %p %s\n", slave, slave->dev->name);
 
-		if (slave->dev->set_mac_address == NULL) {
+		if (slave_ops->ndo_set_mac_address == NULL) {
 			res = -EOPNOTSUPP;
-			dprintk("EOPNOTSUPP %s\n", slave->dev->name);
+			pr_debug("EOPNOTSUPP %s\n", slave->dev->name);
 			goto unwind;
 		}
 
@@ -4230,7 +4251,7 @@
 			 * breakage anyway until ARP finish
 			 * updating, so...
 			 */
-			dprintk("err %d %s\n", res, slave->dev->name);
+			pr_debug("err %d %s\n", res, slave->dev->name);
 			goto unwind;
 		}
 	}
@@ -4250,7 +4271,7 @@
 
 		tmp_res = dev_set_mac_address(slave->dev, &tmp_sa);
 		if (tmp_res) {
-			dprintk("unwind err %d dev %s\n", tmp_res,
+			pr_debug("unwind err %d dev %s\n", tmp_res,
 				slave->dev->name);
 		}
 	}
@@ -4260,7 +4281,7 @@
 
 static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave, *start_at;
 	int i, slave_no, res = 1;
 
@@ -4309,7 +4330,7 @@
  */
 static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	int res = 1;
 
 	read_lock(&bond->lock);
@@ -4341,7 +4362,7 @@
  */
 static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave, *start_at;
 	int slave_no;
 	int i;
@@ -4387,7 +4408,7 @@
  */
 static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave, *start_at;
 	struct net_device *tx_dev = NULL;
 	int i;
@@ -4463,6 +4484,35 @@
 	}
 }
 
+static int bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	const struct bonding *bond = netdev_priv(dev);
+
+	switch (bond->params.mode) {
+	case BOND_MODE_ROUNDROBIN:
+		return bond_xmit_roundrobin(skb, dev);
+	case BOND_MODE_ACTIVEBACKUP:
+		return bond_xmit_activebackup(skb, dev);
+	case BOND_MODE_XOR:
+		return bond_xmit_xor(skb, dev);
+	case BOND_MODE_BROADCAST:
+		return bond_xmit_broadcast(skb, dev);
+	case BOND_MODE_8023AD:
+		return bond_3ad_xmit_xor(skb, dev);
+	case BOND_MODE_ALB:
+	case BOND_MODE_TLB:
+		return bond_alb_xmit(skb, dev);
+	default:
+		/* Should never happen, mode already checked */
+		printk(KERN_ERR DRV_NAME ": %s: Error: Unknown bonding mode %d\n",
+		     dev->name, bond->params.mode);
+		WARN_ON_ONCE(1);
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+}
+
+
 /*
  * set bond mode specific net device operations
  */
@@ -4472,29 +4522,22 @@
 
 	switch (mode) {
 	case BOND_MODE_ROUNDROBIN:
-		bond_dev->hard_start_xmit = bond_xmit_roundrobin;
 		break;
 	case BOND_MODE_ACTIVEBACKUP:
-		bond_dev->hard_start_xmit = bond_xmit_activebackup;
 		break;
 	case BOND_MODE_XOR:
-		bond_dev->hard_start_xmit = bond_xmit_xor;
 		bond_set_xmit_hash_policy(bond);
 		break;
 	case BOND_MODE_BROADCAST:
-		bond_dev->hard_start_xmit = bond_xmit_broadcast;
 		break;
 	case BOND_MODE_8023AD:
 		bond_set_master_3ad_flags(bond);
-		bond_dev->hard_start_xmit = bond_3ad_xmit_xor;
 		bond_set_xmit_hash_policy(bond);
 		break;
 	case BOND_MODE_ALB:
 		bond_set_master_alb_flags(bond);
 		/* FALLTHRU */
 	case BOND_MODE_TLB:
-		bond_dev->hard_start_xmit = bond_alb_xmit;
-		bond_dev->set_mac_address = bond_alb_set_mac_address;
 		break;
 	default:
 		/* Should never happen, mode already checked */
@@ -4524,15 +4567,30 @@
 	.get_flags		= ethtool_op_get_flags,
 };
 
+static const struct net_device_ops bond_netdev_ops = {
+	.ndo_open		= bond_open,
+	.ndo_stop		= bond_close,
+	.ndo_start_xmit		= bond_start_xmit,
+	.ndo_get_stats		= bond_get_stats,
+	.ndo_do_ioctl		= bond_do_ioctl,
+	.ndo_set_multicast_list	= bond_set_multicast_list,
+	.ndo_change_mtu		= bond_change_mtu,
+	.ndo_set_mac_address 	= bond_set_mac_address,
+	.ndo_neigh_setup	= bond_neigh_setup,
+	.ndo_vlan_rx_register	= bond_vlan_rx_register,
+	.ndo_vlan_rx_add_vid 	= bond_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= bond_vlan_rx_kill_vid,
+};
+
 /*
  * Does not allocate but creates a /proc entry.
  * Allowed to fail.
  */
 static int bond_init(struct net_device *bond_dev, struct bond_params *params)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 
-	dprintk("Begin bond_init for %s\n", bond_dev->name);
+	pr_debug("Begin bond_init for %s\n", bond_dev->name);
 
 	/* initialize rwlocks */
 	rwlock_init(&bond->lock);
@@ -4551,20 +4609,13 @@
 	bond->primary_slave = NULL;
 	bond->dev = bond_dev;
 	bond->send_grat_arp = 0;
+	bond->send_unsol_na = 0;
 	bond->setup_by_slave = 0;
 	INIT_LIST_HEAD(&bond->vlan_list);
 
 	/* Initialize the device entry points */
-	bond_dev->open = bond_open;
-	bond_dev->stop = bond_close;
-	bond_dev->get_stats = bond_get_stats;
-	bond_dev->do_ioctl = bond_do_ioctl;
+	bond_dev->netdev_ops = &bond_netdev_ops;
 	bond_dev->ethtool_ops = &bond_ethtool_ops;
-	bond_dev->set_multicast_list = bond_set_multicast_list;
-	bond_dev->change_mtu = bond_change_mtu;
-	bond_dev->set_mac_address = bond_set_mac_address;
-	bond_dev->validate_addr = NULL;
-
 	bond_set_mode_ops(bond, bond->params.mode);
 
 	bond_dev->destructor = bond_destructor;
@@ -4573,6 +4624,8 @@
 	bond_dev->tx_queue_len = 0;
 	bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
 	bond_dev->priv_flags |= IFF_BONDING;
+	if (bond->params.arp_interval)
+		bond_dev->priv_flags |= IFF_MASTER_ARPMON;
 
 	/* At first, we block adding VLANs. That's the only way to
 	 * prevent problems that occur when adding VLANs over an
@@ -4591,9 +4644,6 @@
 	 * when there are slaves that are not hw accel
 	 * capable
 	 */
-	bond_dev->vlan_rx_register = bond_vlan_rx_register;
-	bond_dev->vlan_rx_add_vid  = bond_vlan_rx_add_vid;
-	bond_dev->vlan_rx_kill_vid = bond_vlan_rx_kill_vid;
 	bond_dev->features |= (NETIF_F_HW_VLAN_TX |
 			       NETIF_F_HW_VLAN_RX |
 			       NETIF_F_HW_VLAN_FILTER);
@@ -4632,7 +4682,7 @@
  */
 static void bond_deinit(struct net_device *bond_dev)
 {
-	struct bonding *bond = bond_dev->priv;
+	struct bonding *bond = netdev_priv(bond_dev);
 
 	list_del(&bond->bond_list);
 
@@ -4672,7 +4722,7 @@
  * some mode names are substrings of other names, and calls from sysfs
  * may have whitespace in the name (trailing newlines, for example).
  */
-int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl)
+int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl)
 {
 	int mode = -1, i, rv;
 	char *p, modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, };
@@ -4751,6 +4801,23 @@
 		}
 	}
 
+	if (ad_select) {
+		params->ad_select = bond_parse_parm(ad_select, ad_select_tbl);
+		if (params->ad_select == -1) {
+			printk(KERN_ERR DRV_NAME
+			       ": Error: Invalid ad_select \"%s\"\n",
+			       ad_select == NULL ? "NULL" : ad_select);
+			return -EINVAL;
+		}
+
+		if (bond_mode != BOND_MODE_8023AD) {
+			printk(KERN_WARNING DRV_NAME
+			       ": ad_select param only affects 802.3ad mode\n");
+		}
+	} else {
+		params->ad_select = BOND_AD_STABLE;
+	}
+
 	if (max_bonds < 0 || max_bonds > INT_MAX) {
 		printk(KERN_WARNING DRV_NAME
 		       ": Warning: max_bonds (%d) not in range %d-%d, so it "
@@ -4798,6 +4865,13 @@
 		num_grat_arp = 1;
 	}
 
+	if (num_unsol_na < 0 || num_unsol_na > 255) {
+		printk(KERN_WARNING DRV_NAME
+		       ": Warning: num_unsol_na (%d) not in range 0-255 so it "
+		       "was reset to 1 \n", num_unsol_na);
+		num_unsol_na = 1;
+	}
+
 	/* reset values for 802.3ad */
 	if (bond_mode == BOND_MODE_8023AD) {
 		if (!miimon) {
@@ -4999,6 +5073,7 @@
 	params->xmit_policy = xmit_hashtype;
 	params->miimon = miimon;
 	params->num_grat_arp = num_grat_arp;
+	params->num_unsol_na = num_unsol_na;
 	params->arp_interval = arp_interval;
 	params->arp_validate = arp_validate_value;
 	params->updelay = updelay;
@@ -5099,7 +5174,7 @@
 
 	up_write(&bonding_rwsem);
 	rtnl_unlock(); /* allows sysfs registration of net device */
-	res = bond_create_sysfs_entry(bond_dev->priv);
+	res = bond_create_sysfs_entry(netdev_priv(bond_dev));
 	if (res < 0) {
 		rtnl_lock();
 		down_write(&bonding_rwsem);
@@ -5151,6 +5226,7 @@
 
 	register_netdevice_notifier(&bond_netdev_notifier);
 	register_inetaddr_notifier(&bond_inetaddr_notifier);
+	bond_register_ipv6_notifier();
 
 	goto out;
 err:
@@ -5173,6 +5249,7 @@
 {
 	unregister_netdevice_notifier(&bond_netdev_notifier);
 	unregister_inetaddr_notifier(&bond_inetaddr_notifier);
+	bond_unregister_ipv6_notifier();
 
 	bond_destroy_sysfs();
 
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 3bdb473..18cf478 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -36,22 +36,13 @@
 #include <linux/rtnetlink.h>
 #include <net/net_namespace.h>
 
-/* #define BONDING_DEBUG 1 */
 #include "bonding.h"
+
 #define to_dev(obj)	container_of(obj,struct device,kobj)
-#define to_bond(cd)	((struct bonding *)(to_net_dev(cd)->priv))
+#define to_bond(cd)	((struct bonding *)(netdev_priv(to_net_dev(cd))))
 
 /*---------------------------- Declarations -------------------------------*/
 
-
-extern struct list_head bond_dev_list;
-extern struct bond_params bonding_defaults;
-extern struct bond_parm_tbl bond_mode_tbl[];
-extern struct bond_parm_tbl bond_lacp_tbl[];
-extern struct bond_parm_tbl xmit_hashtype_tbl[];
-extern struct bond_parm_tbl arp_validate_tbl[];
-extern struct bond_parm_tbl fail_over_mac_tbl[];
-
 static int expected_refcount = -1;
 /*--------------------------- Data Structures -----------------------------*/
 
@@ -316,18 +307,12 @@
 
 		/* Set the slave's MTU to match the bond */
 		original_mtu = dev->mtu;
-		if (dev->mtu != bond->dev->mtu) {
-			if (dev->change_mtu) {
-				res = dev->change_mtu(dev,
-						      bond->dev->mtu);
-				if (res) {
-					ret = res;
-					goto out;
-				}
-			} else {
-				dev->mtu = bond->dev->mtu;
-			}
+		res = dev_set_mtu(dev, bond->dev->mtu);
+		if (res) {
+			ret = res;
+			goto out;
 		}
+
 		res = bond_enslave(bond->dev, dev);
 		bond_for_each_slave(bond, slave, i)
 			if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0)
@@ -356,11 +341,7 @@
 				goto out;
 			}
 			/* set the slave MTU to the default */
-			if (dev->change_mtu) {
-				dev->change_mtu(dev, original_mtu);
-			} else {
-				dev->mtu = original_mtu;
-			}
+			dev_set_mtu(dev, original_mtu);
 		}
 		else {
 			printk(KERN_ERR DRV_NAME ": unable to remove non-existent slave %s for bond %s.\n",
@@ -620,6 +601,8 @@
 	       ": %s: Setting ARP monitoring interval to %d.\n",
 	       bond->dev->name, new_value);
 	bond->params.arp_interval = new_value;
+	if (bond->params.arp_interval)
+		bond->dev->priv_flags |= IFF_MASTER_ARPMON;
 	if (bond->params.miimon) {
 		printk(KERN_INFO DRV_NAME
 		       ": %s: ARP monitoring cannot be used with MII monitoring. "
@@ -672,8 +655,8 @@
 
 	for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
 		if (bond->params.arp_targets[i])
-			res += sprintf(buf + res, "%u.%u.%u.%u ",
-			       NIPQUAD(bond->params.arp_targets[i]));
+			res += sprintf(buf + res, "%pI4 ",
+				       &bond->params.arp_targets[i]);
 	}
 	if (res)
 		buf[res-1] = '\n'; /* eat the leftover space */
@@ -695,8 +678,8 @@
 	if (buf[0] == '+') {
 		if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
 			printk(KERN_ERR DRV_NAME
-			       ": %s: invalid ARP target %u.%u.%u.%u specified for addition\n",
- 			       bond->dev->name, NIPQUAD(newtarget));
+			       ": %s: invalid ARP target %pI4 specified for addition\n",
+			       bond->dev->name, &newtarget);
 			ret = -EINVAL;
 			goto out;
 		}
@@ -704,8 +687,8 @@
 		for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) {
 			if (targets[i] == newtarget) { /* duplicate */
 				printk(KERN_ERR DRV_NAME
-				       ": %s: ARP target %u.%u.%u.%u is already present\n",
-				       bond->dev->name, NIPQUAD(newtarget));
+				       ": %s: ARP target %pI4 is already present\n",
+				       bond->dev->name, &newtarget);
 				if (done)
 					targets[i] = 0;
 				ret = -EINVAL;
@@ -713,8 +696,8 @@
 			}
 			if (targets[i] == 0 && !done) {
 				printk(KERN_INFO DRV_NAME
-				       ": %s: adding ARP target %d.%d.%d.%d.\n",
-				       bond->dev->name, NIPQUAD(newtarget));
+				       ": %s: adding ARP target %pI4.\n",
+				       bond->dev->name, &newtarget);
 				done = 1;
 				targets[i] = newtarget;
 			}
@@ -731,8 +714,8 @@
 	else if (buf[0] == '-')	{
 		if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
 			printk(KERN_ERR DRV_NAME
-			       ": %s: invalid ARP target %d.%d.%d.%d specified for removal\n",
-			       bond->dev->name, NIPQUAD(newtarget));
+			       ": %s: invalid ARP target %pI4 specified for removal\n",
+			       bond->dev->name, &newtarget);
 			ret = -EINVAL;
 			goto out;
 		}
@@ -740,16 +723,16 @@
 		for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) {
 			if (targets[i] == newtarget) {
 				printk(KERN_INFO DRV_NAME
-				       ": %s: removing ARP target %d.%d.%d.%d.\n",
-				       bond->dev->name, NIPQUAD(newtarget));
+				       ": %s: removing ARP target %pI4.\n",
+				       bond->dev->name, &newtarget);
 				targets[i] = 0;
 				done = 1;
 			}
 		}
 		if (!done) {
 			printk(KERN_INFO DRV_NAME
-			       ": %s: unable to remove nonexistent ARP target %d.%d.%d.%d.\n",
-			       bond->dev->name, NIPQUAD(newtarget));
+			       ": %s: unable to remove nonexistent ARP target %pI4.\n",
+			       bond->dev->name, &newtarget);
 			ret = -EINVAL;
 			goto out;
 		}
@@ -942,6 +925,53 @@
 }
 static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
 
+static ssize_t bonding_show_ad_select(struct device *d,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	struct bonding *bond = to_bond(d);
+
+	return sprintf(buf, "%s %d\n",
+		ad_select_tbl[bond->params.ad_select].modename,
+		bond->params.ad_select);
+}
+
+
+static ssize_t bonding_store_ad_select(struct device *d,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	int new_value, ret = count;
+	struct bonding *bond = to_bond(d);
+
+	if (bond->dev->flags & IFF_UP) {
+		printk(KERN_ERR DRV_NAME
+		       ": %s: Unable to update ad_select because interface "
+		       "is up.\n", bond->dev->name);
+		ret = -EPERM;
+		goto out;
+	}
+
+	new_value = bond_parse_parm(buf, ad_select_tbl);
+
+	if (new_value != -1) {
+		bond->params.ad_select = new_value;
+		printk(KERN_INFO DRV_NAME
+		       ": %s: Setting ad_select to %s (%d).\n",
+		       bond->dev->name, ad_select_tbl[new_value].modename,
+		       new_value);
+	} else {
+		printk(KERN_ERR DRV_NAME
+		       ": %s: Ignoring invalid ad_select value %.*s.\n",
+		       bond->dev->name, (int)strlen(buf) - 1, buf);
+		ret = -EINVAL;
+	}
+out:
+	return ret;
+}
+
+static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_store_ad_select);
+
 /*
  * Show and set the number of grat ARP to send after a failover event.
  */
@@ -981,6 +1011,47 @@
 	return ret;
 }
 static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp);
+
+/*
+ * Show and set the number of unsolicted NA's to send after a failover event.
+ */
+static ssize_t bonding_show_n_unsol_na(struct device *d,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct bonding *bond = to_bond(d);
+
+	return sprintf(buf, "%d\n", bond->params.num_unsol_na);
+}
+
+static ssize_t bonding_store_n_unsol_na(struct device *d,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int new_value, ret = count;
+	struct bonding *bond = to_bond(d);
+
+	if (sscanf(buf, "%d", &new_value) != 1) {
+		printk(KERN_ERR DRV_NAME
+		       ": %s: no num_unsol_na value specified.\n",
+		       bond->dev->name);
+		ret = -EINVAL;
+		goto out;
+	}
+	if (new_value < 0 || new_value > 255) {
+		printk(KERN_ERR DRV_NAME
+		       ": %s: Invalid num_unsol_na value %d not in range 0-255; rejected.\n",
+		       bond->dev->name, new_value);
+		ret = -EINVAL;
+		goto out;
+	} else {
+		bond->params.num_unsol_na = new_value;
+	}
+out:
+	return ret;
+}
+static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, bonding_show_n_unsol_na, bonding_store_n_unsol_na);
+
 /*
  * Show and set the MII monitor interval.  There are two tricky bits
  * here.  First, if MII monitoring is activated, then we must disable
@@ -1039,6 +1110,7 @@
 			       "ARP monitoring. Disabling ARP monitoring...\n",
 			       bond->dev->name);
 			bond->params.arp_interval = 0;
+			bond->dev->priv_flags &= ~IFF_MASTER_ARPMON;
 			if (bond->params.arp_validate) {
 				bond_unregister_arp(bond);
 				bond->params.arp_validate =
@@ -1391,13 +1463,11 @@
 {
 	int count = 0;
 	struct bonding *bond = to_bond(d);
-	DECLARE_MAC_BUF(mac);
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		struct ad_info ad_info;
 		if (!bond_3ad_get_active_agg_info(bond, &ad_info)) {
-			count = sprintf(buf,"%s\n",
-					print_mac(mac, ad_info.partner_system));
+			count = sprintf(buf, "%pM\n", ad_info.partner_system);
 		}
 	}
 
@@ -1417,8 +1487,10 @@
 	&dev_attr_downdelay.attr,
 	&dev_attr_updelay.attr,
 	&dev_attr_lacp_rate.attr,
+	&dev_attr_ad_select.attr,
 	&dev_attr_xmit_hash_policy.attr,
 	&dev_attr_num_grat_arp.attr,
+	&dev_attr_num_unsol_na.attr,
 	&dev_attr_miimon.attr,
 	&dev_attr_primary.attr,
 	&dev_attr_use_carrier.attr,
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index ffb668d..ca849d2 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -19,23 +19,18 @@
 #include <linux/proc_fs.h>
 #include <linux/if_bonding.h>
 #include <linux/kobject.h>
+#include <linux/in6.h>
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION	"3.3.0"
-#define DRV_RELDATE	"June 10, 2008"
+#define DRV_VERSION	"3.5.0"
+#define DRV_RELDATE	"November 4, 2008"
 #define DRV_NAME	"bonding"
 #define DRV_DESCRIPTION	"Ethernet Channel Bonding Driver"
 
 #define BOND_MAX_ARP_TARGETS	16
 
-#ifdef BONDING_DEBUG
-#define dprintk(fmt, args...) \
-	printk(KERN_DEBUG     \
-	       DRV_NAME ": %s() %d: " fmt, __func__, __LINE__ , ## args )
-#else
-#define dprintk(fmt, args...)
-#endif /* BONDING_DEBUG */
+extern struct list_head bond_dev_list;
 
 #define IS_UP(dev)					   \
 	      ((((dev)->flags & IFF_UP) == IFF_UP)	&& \
@@ -126,6 +121,7 @@
 	int xmit_policy;
 	int miimon;
 	int num_grat_arp;
+	int num_unsol_na;
 	int arp_interval;
 	int arp_validate;
 	int use_carrier;
@@ -133,6 +129,7 @@
 	int updelay;
 	int downdelay;
 	int lacp_fast;
+	int ad_select;
 	char primary[IFNAMSIZ];
 	__be32 arp_targets[BOND_MAX_ARP_TARGETS];
 };
@@ -148,6 +145,9 @@
 	struct list_head vlan_list;
 	__be32 vlan_ip;
 	unsigned short vlan_id;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	struct in6_addr vlan_ipv6;
+#endif
 };
 
 struct slave {
@@ -195,6 +195,7 @@
 	rwlock_t curr_slave_lock;
 	s8       kill_timers;
 	s8	 send_grat_arp;
+	s8	 send_unsol_na;
 	s8	 setup_by_slave;
 	struct   net_device_stats stats;
 #ifdef CONFIG_PROC_FS
@@ -218,6 +219,9 @@
 	struct   delayed_work arp_work;
 	struct   delayed_work alb_work;
 	struct   delayed_work ad_work;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	struct   in6_addr master_ipv6;
+#endif
 };
 
 /**
@@ -245,7 +249,13 @@
 		return NULL;
 	}
 
-	return (struct bonding *)slave->dev->master->priv;
+	return (struct bonding *)netdev_priv(slave->dev->master);
+}
+
+static inline bool bond_is_lb(const struct bonding *bond)
+{
+	return bond->params.mode == BOND_MODE_TLB
+		|| bond->params.mode == BOND_MODE_ALB;
 }
 
 #define BOND_FOM_NONE			0
@@ -275,7 +285,7 @@
 
 static inline void bond_set_slave_inactive_flags(struct slave *slave)
 {
-	struct bonding *bond = slave->dev->master->priv;
+	struct bonding *bond = netdev_priv(slave->dev->master);
 	if (bond->params.mode != BOND_MODE_TLB &&
 	    bond->params.mode != BOND_MODE_ALB)
 		slave->state = BOND_STATE_BACKUP;
@@ -327,7 +337,7 @@
 void bond_loadbalance_arp_mon(struct work_struct *);
 void bond_activebackup_arp_mon(struct work_struct *);
 void bond_set_mode_ops(struct bonding *bond, int mode);
-int bond_parse_parm(const char *mode_arg, struct bond_parm_tbl *tbl);
+int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl);
 void bond_select_active_slave(struct bonding *bond);
 void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
 void bond_register_arp(struct bonding *);
@@ -335,11 +345,35 @@
 
 /* exported from bond_main.c */
 extern struct list_head bond_dev_list;
-extern struct bond_parm_tbl bond_lacp_tbl[];
-extern struct bond_parm_tbl bond_mode_tbl[];
-extern struct bond_parm_tbl xmit_hashtype_tbl[];
-extern struct bond_parm_tbl arp_validate_tbl[];
-extern struct bond_parm_tbl fail_over_mac_tbl[];
+extern const struct bond_parm_tbl bond_lacp_tbl[];
+extern const struct bond_parm_tbl bond_mode_tbl[];
+extern const struct bond_parm_tbl xmit_hashtype_tbl[];
+extern const struct bond_parm_tbl arp_validate_tbl[];
+extern const struct bond_parm_tbl fail_over_mac_tbl[];
+extern struct bond_params bonding_defaults;
+extern struct bond_parm_tbl ad_select_tbl[];
+
+/* exported from bond_sysfs.c */
+extern struct rw_semaphore bonding_rwsem;
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+void bond_send_unsolicited_na(struct bonding *bond);
+void bond_register_ipv6_notifier(void);
+void bond_unregister_ipv6_notifier(void);
+#else
+static inline void bond_send_unsolicited_na(struct bonding *bond)
+{
+	return;
+}
+static inline void bond_register_ipv6_notifier(void)
+{
+	return;
+}
+static inline void bond_unregister_ipv6_notifier(void)
+{
+	return;
+}
+#endif
 
 #endif /* _LINUX_BONDING_H */
 
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index 103f0f1..a10c1d7 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -128,26 +128,30 @@
 	return NETDEV_TX_OK;
 }
 
+static const struct net_device_ops vcan_netdev_ops = {
+	.ndo_start_xmit = vcan_tx,
+};
+
 static void vcan_setup(struct net_device *dev)
 {
-	dev->type              = ARPHRD_CAN;
-	dev->mtu               = sizeof(struct can_frame);
-	dev->hard_header_len   = 0;
-	dev->addr_len          = 0;
-	dev->tx_queue_len      = 0;
-	dev->flags             = IFF_NOARP;
+	dev->type		= ARPHRD_CAN;
+	dev->mtu		= sizeof(struct can_frame);
+	dev->hard_header_len	= 0;
+	dev->addr_len		= 0;
+	dev->tx_queue_len	= 0;
+	dev->flags		= IFF_NOARP;
 
 	/* set flags according to driver capabilities */
 	if (echo)
 		dev->flags |= IFF_ECHO;
 
-	dev->hard_start_xmit   = vcan_tx;
-	dev->destructor        = free_netdev;
+	dev->netdev_ops		= &vcan_netdev_ops;
+	dev->destructor		= free_netdev;
 }
 
 static struct rtnl_link_ops vcan_link_ops __read_mostly = {
-       .kind           = "vcan",
-       .setup          = vcan_setup,
+	.kind	= "vcan",
+	.setup	= vcan_setup,
 };
 
 static __init int vcan_init_module(void)
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 86909cf..321f43d 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2347,7 +2347,7 @@
 	drops = 0;
 	while (1) {
 		struct cas_rx_comp *rxc = rxcs + entry;
-		struct sk_buff *skb;
+		struct sk_buff *uninitialized_var(skb);
 		int type, len;
 		u64 words[4];
 		int i, dring;
@@ -2405,7 +2405,6 @@
 		cp->net_stats[ring].rx_packets++;
 		cp->net_stats[ring].rx_bytes += len;
 		spin_unlock(&cp->stat_lock[ring]);
-		cp->dev->last_rx = jiffies;
 
 	next:
 		npackets++;
@@ -2507,7 +2506,7 @@
 	if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
 #ifdef USE_NAPI
 		cas_mask_intr(cp);
-		netif_rx_schedule(dev, &cp->napi);
+		netif_rx_schedule(&cp->napi);
 #else
 		cas_rx_ringN(cp, ring, 0);
 #endif
@@ -2558,7 +2557,7 @@
 	if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
 #ifdef USE_NAPI
 		cas_mask_intr(cp);
-		netif_rx_schedule(dev, &cp->napi);
+		netif_rx_schedule(&cp->napi);
 #else
 		cas_rx_ringN(cp, 1, 0);
 #endif
@@ -2614,7 +2613,7 @@
 	if (status & INTR_RX_DONE) {
 #ifdef USE_NAPI
 		cas_mask_intr(cp);
-		netif_rx_schedule(dev, &cp->napi);
+		netif_rx_schedule(&cp->napi);
 #else
 		cas_rx_ringN(cp, 0, 0);
 #endif
@@ -2692,7 +2691,7 @@
 #endif
 	spin_unlock_irqrestore(&cp->lock, flags);
 	if (enable_intr) {
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		cas_unmask_intr(cp);
 	}
 	return credits;
@@ -4988,7 +4987,6 @@
 	int i, err, pci_using_dac;
 	u16 pci_cmd;
 	u8 orig_cacheline_size = 0, cas_cacheline_size = 0;
-	DECLARE_MAC_BUF(mac);
 
 	if (cas_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -5201,12 +5199,12 @@
 
 	i = readl(cp->regs + REG_BIM_CFG);
 	printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) "
-	       "Ethernet[%d] %s\n",  dev->name,
+	       "Ethernet[%d] %pM\n",  dev->name,
 	       (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
 	       (i & BIM_CFG_32BIT) ? "32" : "64",
 	       (i & BIM_CFG_66MHZ) ? "66" : "33",
 	       (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq,
-	       print_mac(mac, dev->dev_addr));
+	       dev->dev_addr);
 
 	pci_set_drvdata(pdev, dev);
 	cp->hw_running = 1;
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 638c9a2..9b6011e 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -120,7 +120,7 @@
  */
 static void t1_set_rxmode(struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct cmac *mac = adapter->port[dev->if_port].mac;
 	struct t1_rx_mode rm;
 
@@ -252,7 +252,7 @@
 static int cxgb_open(struct net_device *dev)
 {
 	int err;
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	int other_ports = adapter->open_device_map & PORT_MASK;
 
 	napi_enable(&adapter->napi);
@@ -272,7 +272,7 @@
 
 static int cxgb_close(struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct port_info *p = &adapter->port[dev->if_port];
 	struct cmac *mac = p->mac;
 
@@ -298,7 +298,7 @@
 
 static struct net_device_stats *t1_get_stats(struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct port_info *p = &adapter->port[dev->if_port];
 	struct net_device_stats *ns = &p->netstats;
 	const struct cmac_statistics *pstats;
@@ -346,14 +346,14 @@
 
 static u32 get_msglevel(struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	return adapter->msg_enable;
 }
 
 static void set_msglevel(struct net_device *dev, u32 val)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	adapter->msg_enable = val;
 }
@@ -434,7 +434,7 @@
 
 static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
@@ -461,7 +461,7 @@
 static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
 		      u64 *data)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct cmac *mac = adapter->port[dev->if_port].mac;
 	const struct cmac_statistics *s;
 	const struct sge_intr_counts *t;
@@ -552,7 +552,7 @@
 static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
 		     void *buf)
 {
-	struct adapter *ap = dev->priv;
+	struct adapter *ap = dev->ml_priv;
 
 	/*
 	 * Version scheme: bits 0..9: chip version, bits 10..15: chip revision
@@ -574,7 +574,7 @@
 
 static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct port_info *p = &adapter->port[dev->if_port];
 
 	cmd->supported = p->link_config.supported;
@@ -634,7 +634,7 @@
 
 static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct port_info *p = &adapter->port[dev->if_port];
 	struct link_config *lc = &p->link_config;
 
@@ -669,7 +669,7 @@
 static void get_pauseparam(struct net_device *dev,
 			   struct ethtool_pauseparam *epause)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct port_info *p = &adapter->port[dev->if_port];
 
 	epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
@@ -680,7 +680,7 @@
 static int set_pauseparam(struct net_device *dev,
 			  struct ethtool_pauseparam *epause)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct port_info *p = &adapter->port[dev->if_port];
 	struct link_config *lc = &p->link_config;
 
@@ -709,14 +709,14 @@
 
 static u32 get_rx_csum(struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	return (adapter->flags & RX_CSUM_ENABLED) != 0;
 }
 
 static int set_rx_csum(struct net_device *dev, u32 data)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	if (data)
 		adapter->flags |= RX_CSUM_ENABLED;
@@ -727,7 +727,7 @@
 
 static int set_tso(struct net_device *dev, u32 value)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	if (!(adapter->flags & TSO_CAPABLE))
 		return value ? -EOPNOTSUPP : 0;
@@ -736,7 +736,7 @@
 
 static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0;
 
 	e->rx_max_pending = MAX_RX_BUFFERS;
@@ -752,7 +752,7 @@
 
 static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0;
 
 	if (e->rx_pending > MAX_RX_BUFFERS || e->rx_mini_pending ||
@@ -776,7 +776,7 @@
 
 static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs;
 	adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
@@ -787,7 +787,7 @@
 
 static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	c->rx_coalesce_usecs = adapter->params.sge.rx_coalesce_usecs;
 	c->rate_sample_interval = adapter->params.sge.sample_interval_usecs;
@@ -797,7 +797,7 @@
 
 static int get_eeprom_len(struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	return t1_is_asic(adapter) ? EEPROM_SIZE : 0;
 }
@@ -810,7 +810,7 @@
 {
 	int i;
 	u8 buf[EEPROM_SIZE] __attribute__((aligned(4)));
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	e->magic = EEPROM_MAGIC(adapter);
 	for (i = e->offset & ~3; i < e->offset + e->len; i += sizeof(u32))
@@ -848,7 +848,7 @@
 
 static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct mii_ioctl_data *data = if_mii(req);
 
 	switch (cmd) {
@@ -887,7 +887,7 @@
 static int t1_change_mtu(struct net_device *dev, int new_mtu)
 {
 	int ret;
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct cmac *mac = adapter->port[dev->if_port].mac;
 
 	if (!mac->ops->set_mtu)
@@ -902,7 +902,7 @@
 
 static int t1_set_mac_addr(struct net_device *dev, void *p)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct cmac *mac = adapter->port[dev->if_port].mac;
 	struct sockaddr *addr = p;
 
@@ -915,10 +915,10 @@
 }
 
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-static void vlan_rx_register(struct net_device *dev,
+static void t1_vlan_rx_register(struct net_device *dev,
 				   struct vlan_group *grp)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	spin_lock_irq(&adapter->async_lock);
 	adapter->vlan_grp = grp;
@@ -931,7 +931,7 @@
 static void t1_netpoll(struct net_device *dev)
 {
 	unsigned long flags;
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 
 	local_irq_save(flags);
 	t1_interrupt(adapter->pdev->irq, adapter);
@@ -1010,6 +1010,24 @@
 		 adapter->name);
 }
 
+static const struct net_device_ops cxgb_netdev_ops = {
+	.ndo_open		= cxgb_open,
+	.ndo_stop		= cxgb_close,
+	.ndo_start_xmit		= t1_start_xmit,
+	.ndo_get_stats		= t1_get_stats,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_multicast_list	= t1_set_rxmode,
+	.ndo_do_ioctl		= t1_ioctl,
+	.ndo_change_mtu		= t1_change_mtu,
+	.ndo_set_mac_address	= t1_set_mac_addr,
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+	.ndo_vlan_rx_register	= t1_vlan_rx_register,
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= t1_netpoll,
+#endif
+};
+
 static int __devinit init_one(struct pci_dev *pdev,
 			      const struct pci_device_id *ent)
 {
@@ -1077,7 +1095,7 @@
 		SET_NETDEV_DEV(netdev, &pdev->dev);
 
 		if (!adapter) {
-			adapter = netdev->priv;
+			adapter = netdev_priv(netdev);
 			adapter->pdev = pdev;
 			adapter->port[0].dev = netdev;  /* so we don't leak it */
 
@@ -1118,7 +1136,7 @@
 		netdev->if_port = i;
 		netdev->mem_start = mmio_start;
 		netdev->mem_end = mmio_start + mmio_len - 1;
-		netdev->priv = adapter;
+		netdev->ml_priv = adapter;
 		netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 		netdev->features |= NETIF_F_LLTX;
 
@@ -1130,7 +1148,6 @@
 			adapter->flags |= VLAN_ACCEL_CAPABLE;
 			netdev->features |=
 				NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-			netdev->vlan_rx_register = vlan_rx_register;
 #endif
 
 			/* T204: disable TSO */
@@ -1140,19 +1157,10 @@
 			}
 		}
 
-		netdev->open = cxgb_open;
-		netdev->stop = cxgb_close;
-		netdev->hard_start_xmit = t1_start_xmit;
+		netdev->netdev_ops = &cxgb_netdev_ops;
 		netdev->hard_header_len += (adapter->flags & TSO_CAPABLE) ?
 			sizeof(struct cpl_tx_pkt_lso) : sizeof(struct cpl_tx_pkt);
-		netdev->get_stats = t1_get_stats;
-		netdev->set_multicast_list = t1_set_rxmode;
-		netdev->do_ioctl = t1_ioctl;
-		netdev->change_mtu = t1_change_mtu;
-		netdev->set_mac_address = t1_set_mac_addr;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-		netdev->poll_controller = t1_netpoll;
-#endif
+
 		netif_napi_add(netdev, &adapter->napi, t1_poll, 64);
 
 		SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops);
@@ -1382,7 +1390,7 @@
 static void __devexit remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	int i;
 
 	for_each_port(adapter, i) {
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 7092df5..d984b79 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1381,7 +1381,6 @@
 	st = per_cpu_ptr(sge->port_stats[p->iff], smp_processor_id());
 
 	skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev);
-	skb->dev->last_rx = jiffies;
 	if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff &&
 	    skb->protocol == htons(ETH_P_IP) &&
 	    (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) {
@@ -1610,11 +1609,10 @@
 int t1_poll(struct napi_struct *napi, int budget)
 {
 	struct adapter *adapter = container_of(napi, struct adapter, napi);
-	struct net_device *dev = adapter->port[0].dev;
 	int work_done = process_responses(adapter, budget);
 
 	if (likely(work_done < budget)) {
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		writel(adapter->sge->respQ.cidx,
 		       adapter->regs + A_SG_SLEEPING);
 	}
@@ -1628,13 +1626,11 @@
 	int handled;
 
 	if (likely(responses_pending(adapter))) {
-		struct net_device *dev = sge->netdev;
-
 		writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
 
 		if (napi_schedule_prep(&adapter->napi)) {
 			if (process_pure_responses(adapter))
-				__netif_rx_schedule(dev, &adapter->napi);
+				__netif_rx_schedule(&adapter->napi);
 			else {
 				/* no data, no NAPI needed */
 				writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
@@ -1782,7 +1778,7 @@
  */
 int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = dev->ml_priv;
 	struct sge *sge = adapter->sge;
 	struct sge_port_stats *st = per_cpu_ptr(sge->port_stats[dev->if_port],
 						smp_processor_id());
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index 017a536..f665487 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -428,7 +428,7 @@
 			printk(KERN_WARNING "%s: rx: polling, but no queue\n",
 			       priv->dev->name);
 		spin_unlock(&priv->rx_lock);
-		netif_rx_complete(priv->dev, napi);
+		netif_rx_complete(napi);
 		return 0;
 	}
 
@@ -514,7 +514,7 @@
 	if (processed == 0) {
 		/* we ran out of packets to read,
 		 * revert to interrupt-driven mode */
-		netif_rx_complete(priv->dev, napi);
+		netif_rx_complete(napi);
 		cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1);
 		return 0;
 	}
@@ -536,7 +536,7 @@
 	}
 
 	spin_unlock(&priv->rx_lock);
-	netif_rx_complete(priv->dev, napi);
+	netif_rx_complete(napi);
 	netif_tx_stop_all_queues(priv->dev);
 	napi_disable(&priv->napi);
 
@@ -802,9 +802,9 @@
 
 	if (status & MAC_INT_RX) {
 		queue = (status >> 8) & 7;
-		if (netif_rx_schedule_prep(dev, &priv->napi)) {
+		if (netif_rx_schedule_prep(&priv->napi)) {
 			cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue);
-			__netif_rx_schedule(dev, &priv->napi);
+			__netif_rx_schedule(&priv->napi);
 		}
 	}
 
@@ -1103,7 +1103,6 @@
 	struct cpmac_priv *priv;
 	struct net_device *dev;
 	struct plat_cpmac_data *pdata;
-	DECLARE_MAC_BUF(mac);
 
 	pdata = pdev->dev.platform_data;
 
@@ -1180,8 +1179,8 @@
 	if (netif_msg_probe(priv)) {
 		printk(KERN_INFO
 		       "cpmac: device %s (regs: %p, irq: %d, phy: %s, "
-		       "mac: %s)\n", dev->name, (void *)mem->start, dev->irq,
-		       priv->phy_name, print_mac(mac, dev->dev_addr));
+		       "mac: %pM)\n", dev->name, (void *)mem->start, dev->irq,
+		       priv->phy_name, dev->dev_addr);
 	}
 	return 0;
 
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 7e8a631..c9806c5 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -419,7 +419,6 @@
 {
 	struct net_local *np = netdev_priv(dev);
 	struct sockaddr *addr = p;
-	DECLARE_MAC_BUF(mac);
 
 	spin_lock(&np->lock); /* preemption protection */
 
@@ -440,8 +439,7 @@
 
 	/* show it in the log as well */
 
-	printk(KERN_INFO "%s: changed MAC to %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: changed MAC to %pM\n", dev->name, dev->dev_addr);
 
 	spin_unlock(&np->lock);
 
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 7107620..d548a45 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -521,7 +521,6 @@
 	unsigned rev_type = 0;
 	int eeprom_buff[CHKSUM_LEN];
 	int retval;
-	DECLARE_MAC_BUF(mac);
 
 	/* Initialize the device structure. */
 	if (!modular) {
@@ -846,7 +845,7 @@
 	}
 
 	/* print the ethernet address. */
-	printk(", MAC %s", print_mac(mac, dev->dev_addr));
+	printk(", MAC %pM", dev->dev_addr);
 
 	dev->open		= net_open;
 	dev->stop		= net_close;
@@ -1025,14 +1024,13 @@
 	}
         skb->protocol=eth_type_trans(skb,dev);
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 	lp->stats.rx_packets++;
 	lp->stats.rx_bytes += length;
 }
 
 #endif	/* ALLOW_DMA */
 
-void  __init reset_chip(struct net_device *dev)
+static void __init reset_chip(struct net_device *dev)
 {
 #if !defined(CONFIG_MACH_MX31ADS)
 #if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01)
@@ -1719,7 +1717,6 @@
 
         skb->protocol=eth_type_trans(skb,dev);
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 	lp->stats.rx_packets++;
 	lp->stats.rx_bytes += length;
 }
@@ -1817,11 +1814,10 @@
 
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
-	if (net_debug) {
-		DECLARE_MAC_BUF(mac);
-		printk("%s: Setting MAC address to %s.\n",
-		       dev->name, print_mac(mac, dev->dev_addr));
-	}
+	if (net_debug)
+		printk("%s: Setting MAC address to %pM.\n",
+		       dev->name, dev->dev_addr);
+
 	/* set the Ethernet address */
 	for (i=0; i < ETH_ALEN/2; i++)
 		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index bc8e241..5b346f9 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -63,6 +63,7 @@
 	struct link_config link_config;
 	struct net_device_stats netstats;
 	int activity;
+	__be32 iscsi_ipv4addr;
 };
 
 enum {				/* adapter flags */
@@ -196,6 +197,7 @@
 	int lro_frag_len;
 	void *lro_va;
 	struct net_device *netdev;
+	struct netdev_queue *tx_q;	/* associated netdev TX queue */
 	unsigned long txq_stopped;	/* which Tx queues are stopped */
 	struct timer_list tx_reclaim_timer;	/* reclaims TX buffers */
 	unsigned long port_stats[SGE_PSTAT_MAX];
@@ -294,7 +296,8 @@
 void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p);
 int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
 		      int irq_vec_idx, const struct qset_params *p,
-		      int ntxq, struct net_device *dev);
+		      int ntxq, struct net_device *dev,
+		      struct netdev_queue *netdevq);
 int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
 		unsigned char *data);
 irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index e312d31..db4f4f5 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -714,7 +714,7 @@
 int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data);
 int t3_seeprom_wp(struct adapter *adapter, int enable);
 int t3_get_tp_version(struct adapter *adapter, u32 *vers);
-int t3_check_tpsram_version(struct adapter *adapter, int *must_load);
+int t3_check_tpsram_version(struct adapter *adapter);
 int t3_check_tpsram(struct adapter *adapter, const u8 *tp_ram,
 		    unsigned int size);
 int t3_set_proto_sram(struct adapter *adap, const u8 *data);
@@ -722,7 +722,7 @@
 		  unsigned int nwords, u32 *data, int byte_oriented);
 int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
 int t3_get_fw_version(struct adapter *adapter, u32 *vers);
-int t3_check_fw_version(struct adapter *adapter, int *must_load);
+int t3_check_fw_version(struct adapter *adapter);
 int t3_init_hw(struct adapter *adapter, u32 fw_params);
 void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
 void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
index 1d8d46e..369fe71 100644
--- a/drivers/net/cxgb3/cxgb3_ctl_defs.h
+++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h
@@ -57,6 +57,9 @@
 	RDMA_GET_MIB		= 19,
 
 	GET_RX_PAGE_INFO	= 50,
+	GET_ISCSI_IPV4ADDR	= 51,
+
+	GET_EMBEDDED_INFO	= 70,
 };
 
 /*
@@ -86,6 +89,12 @@
 	u16 vlan_tag;
 };
 
+/* Structure used to request a port's iSCSI IPv4 address */
+struct iscsi_ipv4addr {
+	struct net_device *dev;	/* the net_device */
+	__be32 ipv4addr;	/* the return iSCSI IPv4 address */
+};
+
 struct pci_dev;
 
 /*
@@ -169,4 +178,12 @@
 	unsigned int page_size;  /* Page size, should be a power of 2 */
 	unsigned int num;        /* Number of pages */
 };
+
+/*
+ * Structure used to get firmware and protocol engine versions.
+ */
+struct ch_embedded_info {
+	u32 fw_vers;
+	u32 tp_vers;
+};
 #endif				/* _CXGB3_OFFLOAD_CTL_DEFS_H */
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 2c341f8..2847f94 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -494,6 +494,36 @@
 }
 
 /**
+ *	set_qset_lro - Turn a queue set's LRO capability on and off
+ *	@dev: the device the qset is attached to
+ *	@qset_idx: the queue set index
+ *	@val: the LRO switch
+ *
+ *	Sets LRO on or off for a particular queue set.
+ *	the device's features flag is updated to reflect the LRO
+ *	capability when all queues belonging to the device are
+ *	in the same state.
+ */
+static void set_qset_lro(struct net_device *dev, int qset_idx, int val)
+{
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
+	int i, lro_on = 1;
+
+	adapter->params.sge.qset[qset_idx].lro = !!val;
+	adapter->sge.qs[qset_idx].lro_enabled = !!val;
+
+	/* let ethtool report LRO on only if all queues are LRO enabled */
+	for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; ++i)
+		lro_on &= adapter->params.sge.qset[i].lro;
+
+	if (lro_on)
+		dev->features |= NETIF_F_LRO;
+	else
+		dev->features &= ~NETIF_F_LRO;
+}
+
+/**
  *	setup_sge_qsets - configure SGE Tx/Rx/response queues
  *	@adap: the adapter
  *
@@ -516,12 +546,12 @@
 		pi->qs = &adap->sge.qs[pi->first_qset];
 		for (j = pi->first_qset; j < pi->first_qset + pi->nqsets;
 		     ++j, ++qset_idx) {
-			if (!pi->rx_csum_offload)
-				adap->params.sge.qset[qset_idx].lro = 0;
+			set_qset_lro(dev, qset_idx, pi->rx_csum_offload);
 			err = t3_sge_alloc_qset(adap, qset_idx, 1,
 				(adap->flags & USING_MSIX) ? qset_idx + 1 :
 							     irq_idx,
-				&adap->params.sge.qset[qset_idx], ntxq, dev);
+				&adap->params.sge.qset[qset_idx], ntxq, dev,
+				netdev_get_tx_queue(dev, j));
 			if (err) {
 				t3_stop_sge_timers(adap);
 				t3_free_sge_resources(adap);
@@ -824,8 +854,8 @@
 	return err;
 }
 
-#define FW_FNAME "t3fw-%d.%d.%d.bin"
-#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
+#define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin"
+#define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin"
 
 static int upgrade_fw(struct adapter *adap)
 {
@@ -928,21 +958,22 @@
 static int cxgb_up(struct adapter *adap)
 {
 	int err;
-	int must_load;
 
 	if (!(adap->flags & FULL_INIT_DONE)) {
-		err = t3_check_fw_version(adap, &must_load);
+		err = t3_check_fw_version(adap);
 		if (err == -EINVAL) {
 			err = upgrade_fw(adap);
-			if (err && must_load)
-				goto out;
+			CH_WARN(adap, "FW upgrade to %d.%d.%d %s\n",
+				FW_VERSION_MAJOR, FW_VERSION_MINOR,
+				FW_VERSION_MICRO, err ? "failed" : "succeeded");
 		}
 
-		err = t3_check_tpsram_version(adap, &must_load);
+		err = t3_check_tpsram_version(adap);
 		if (err == -EINVAL) {
 			err = update_tpsram(adap);
-			if (err && must_load)
-				goto out;
+			CH_WARN(adap, "TP upgrade to %d.%d.%d %s\n",
+				TP_VERSION_MAJOR, TP_VERSION_MINOR,
+				TP_VERSION_MICRO, err ? "failed" : "succeeded");
 		}
 
 		/*
@@ -1136,9 +1167,10 @@
 			       "Could not initialize offload capabilities\n");
 	}
 
+	dev->real_num_tx_queues = pi->nqsets;
 	link_start(dev);
 	t3_port_intr_enable(adapter, pi->port_id);
-	netif_start_queue(dev);
+	netif_tx_start_all_queues(dev);
 	if (!other_ports)
 		schedule_chk_task(adapter);
 
@@ -1151,7 +1183,7 @@
 	struct adapter *adapter = pi->adapter;
 
 	t3_port_intr_disable(adapter, pi->port_id);
-	netif_stop_queue(dev);
+	netif_tx_stop_all_queues(dev);
 	pi->phy.ops->power_down(&pi->phy, 1);
 	netif_carrier_off(dev);
 	t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
@@ -1634,13 +1666,10 @@
 
 	p->rx_csum_offload = data;
 	if (!data) {
-		struct adapter *adap = p->adapter;
 		int i;
 
-		for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
-			adap->params.sge.qset[i].lro = 0;
-			adap->sge.qs[i].lro_enabled = 0;
-		}
+		for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
+			set_qset_lro(dev, i, 0);
 	}
 	return 0;
 }
@@ -1795,6 +1824,25 @@
 	memset(&wol->sopass, 0, sizeof(wol->sopass));
 }
 
+static int cxgb3_set_flags(struct net_device *dev, u32 data)
+{
+	struct port_info *pi = netdev_priv(dev);
+	int i;
+
+	if (data & ETH_FLAG_LRO) {
+		if (!pi->rx_csum_offload)
+			return -EINVAL;
+
+		for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++)
+			set_qset_lro(dev, i, 1);
+
+	} else
+		for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++)
+			set_qset_lro(dev, i, 0);
+
+	return 0;
+}
+
 static const struct ethtool_ops cxgb_ethtool_ops = {
 	.get_settings = get_settings,
 	.set_settings = set_settings,
@@ -1824,6 +1872,8 @@
 	.get_regs = get_regs,
 	.get_wol = get_wol,
 	.set_tso = ethtool_op_set_tso,
+	.get_flags = ethtool_op_get_flags,
+	.set_flags = cxgb3_set_flags,
 };
 
 static int in_range(int val, int lo, int hi)
@@ -1940,11 +1990,9 @@
 				}
 			}
 		}
-		if (t.lro >= 0) {
-			struct sge_qset *qs = &adapter->sge.qs[t.qset_idx];
-			q->lro = t.lro;
-			qs->lro_enabled = t.lro;
-		}
+		if (t.lro >= 0)
+			set_qset_lro(dev, t.qset_idx, t.lro);
+
 		break;
 	}
 	case CHELSIO_GET_QSET_PARAMS:{
@@ -2783,6 +2831,22 @@
 	}
 }
 
+static const struct net_device_ops cxgb_netdev_ops = {
+	.ndo_open		= cxgb_open,
+	.ndo_stop		= cxgb_close,
+	.ndo_start_xmit		= t3_eth_xmit,
+	.ndo_get_stats		= cxgb_get_stats,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_multicast_list	= cxgb_set_rxmode,
+	.ndo_do_ioctl		= cxgb_ioctl,
+	.ndo_change_mtu		= cxgb_change_mtu,
+	.ndo_set_mac_address	= cxgb_set_mac_addr,
+	.ndo_vlan_rx_register	= vlan_rx_register,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= cxgb_netpoll,
+#endif
+};
+
 static int __devinit init_one(struct pci_dev *pdev,
 			      const struct pci_device_id *ent)
 {
@@ -2871,7 +2935,7 @@
 	for (i = 0; i < ai->nports; ++i) {
 		struct net_device *netdev;
 
-		netdev = alloc_etherdev(sizeof(struct port_info));
+		netdev = alloc_etherdev_mq(sizeof(struct port_info), SGE_QSETS);
 		if (!netdev) {
 			err = -ENOMEM;
 			goto out_free_dev;
@@ -2885,6 +2949,7 @@
 		pi->rx_csum_offload = 1;
 		pi->port_id = i;
 		netif_carrier_off(netdev);
+		netif_tx_stop_all_queues(netdev);
 		netdev->irq = pdev->irq;
 		netdev->mem_start = mmio_start;
 		netdev->mem_end = mmio_start + mmio_len - 1;
@@ -2894,20 +2959,7 @@
 			netdev->features |= NETIF_F_HIGHDMA;
 
 		netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-		netdev->vlan_rx_register = vlan_rx_register;
-
-		netdev->open = cxgb_open;
-		netdev->stop = cxgb_close;
-		netdev->hard_start_xmit = t3_eth_xmit;
-		netdev->get_stats = cxgb_get_stats;
-		netdev->set_multicast_list = cxgb_set_rxmode;
-		netdev->do_ioctl = cxgb_ioctl;
-		netdev->change_mtu = cxgb_change_mtu;
-		netdev->set_mac_address = cxgb_set_mac_addr;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-		netdev->poll_controller = cxgb_netpoll;
-#endif
-
+		netdev->netdev_ops = &cxgb_netdev_ops;
 		SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
 	}
 
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index 265aa8a..2d7f69a 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -182,7 +182,9 @@
 static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
 			      void *data)
 {
+	int i;
 	int ret = 0;
+	unsigned int val = 0;
 	struct ulp_iscsi_info *uiip = data;
 
 	switch (req) {
@@ -191,32 +193,55 @@
 		uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT);
 		uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT);
 		uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK);
+
+		val = t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ);
+		for (i = 0; i < 4; i++, val >>= 8)
+			uiip->pgsz_factor[i] = val & 0xFF;
+
+		val = t3_read_reg(adapter, A_TP_PARA_REG7);
+		uiip->max_txsz =
+		uiip->max_rxsz = min((val >> S_PMMAXXFERLEN0)&M_PMMAXXFERLEN0,
+				     (val >> S_PMMAXXFERLEN1)&M_PMMAXXFERLEN1);
 		/*
 		 * On tx, the iscsi pdu has to be <= tx page size and has to
 		 * fit into the Tx PM FIFO.
 		 */
-		uiip->max_txsz = min(adapter->params.tp.tx_pg_size,
-				     t3_read_reg(adapter, A_PM1_TX_CFG) >> 17);
-		/* on rx, the iscsi pdu has to be < rx page size and the
-		   whole pdu + cpl headers has to fit into one sge buffer */
-		uiip->max_rxsz = min_t(unsigned int,
-				       adapter->params.tp.rx_pg_size,
-				       (adapter->sge.qs[0].fl[1].buf_size -
-					sizeof(struct cpl_rx_data) * 2 -
-					sizeof(struct cpl_rx_data_ddp)));
+		val = min(adapter->params.tp.tx_pg_size,
+			  t3_read_reg(adapter, A_PM1_TX_CFG) >> 17);
+		uiip->max_txsz = min(val, uiip->max_txsz);
+
+		/* set MaxRxData to 16224 */
+		val = t3_read_reg(adapter, A_TP_PARA_REG2);
+		if ((val >> S_MAXRXDATA) != 0x3f60) {
+			val &= (M_RXCOALESCESIZE << S_RXCOALESCESIZE);
+			val |= V_MAXRXDATA(0x3f60);
+			printk(KERN_INFO
+				"%s, iscsi set MaxRxData to 16224 (0x%x).\n",
+				adapter->name, val);
+			t3_write_reg(adapter, A_TP_PARA_REG2, val);
+		}
+
+		/*
+		 * on rx, the iscsi pdu has to be < rx page size and the
+		 * the max rx data length programmed in TP
+		 */
+		val = min(adapter->params.tp.rx_pg_size,
+			  ((t3_read_reg(adapter, A_TP_PARA_REG2)) >>
+				S_MAXRXDATA) & M_MAXRXDATA);
+		uiip->max_rxsz = min(val, uiip->max_rxsz);
 		break;
 	case ULP_ISCSI_SET_PARAMS:
 		t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask);
-		/* set MaxRxData and MaxCoalesceSize to 16224 */
-		t3_write_reg(adapter, A_TP_PARA_REG2, 0x3f603f60);
 		/* program the ddp page sizes */
-		{
-			int i;
-			unsigned int val = 0;
-			for (i = 0; i < 4; i++)
-				val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i);
-			if (val)
-				t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val);
+		for (i = 0; i < 4; i++)
+			val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i);
+		if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) {
+			printk(KERN_INFO
+				"%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u.\n",
+				adapter->name, val, uiip->pgsz_factor[0],
+				uiip->pgsz_factor[1], uiip->pgsz_factor[2],
+				uiip->pgsz_factor[3]);
+			t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val);
 		}
 		break;
 	default:
@@ -407,6 +432,21 @@
 		rx_page_info->page_size = tp->rx_pg_size;
 		rx_page_info->num = tp->rx_num_pgs;
 		break;
+	case GET_ISCSI_IPV4ADDR: {
+		struct iscsi_ipv4addr *p = data;
+		struct port_info *pi = netdev_priv(p->dev);
+		p->ipv4addr = pi->iscsi_ipv4addr;
+		break;
+	}
+	case GET_EMBEDDED_INFO: {
+		struct ch_embedded_info *e = data;
+
+		spin_lock(&adapter->stats_lock);
+		t3_get_fw_version(adapter, &e->fw_vers);
+		t3_get_tp_version(adapter, &e->tp_vers);
+		spin_unlock(&adapter->stats_lock);
+		break;
+	}
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index c6480be..6c641a8 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -36,6 +36,7 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/dma-mapping.h>
+#include <net/arp.h>
 #include "common.h"
 #include "regs.h"
 #include "sge_defs.h"
@@ -549,16 +550,15 @@
 
 	if (!p)
 		return NULL;
-	if (sw_size) {
+	if (sw_size && metadata) {
 		s = kcalloc(nelem, sw_size, GFP_KERNEL);
 
 		if (!s) {
 			dma_free_coherent(&pdev->dev, len, p, *phys);
 			return NULL;
 		}
-	}
-	if (metadata)
 		*(void **)metadata = s;
+	}
 	memset(p, 0, len);
 	return p;
 }
@@ -1121,10 +1121,10 @@
 			 htonl(V_WR_TID(q->token)));
 }
 
-static inline void t3_stop_queue(struct net_device *dev, struct sge_qset *qs,
-				 struct sge_txq *q)
+static inline void t3_stop_tx_queue(struct netdev_queue *txq,
+				    struct sge_qset *qs, struct sge_txq *q)
 {
-	netif_stop_queue(dev);
+	netif_tx_stop_queue(txq);
 	set_bit(TXQ_ETH, &qs->txq_stopped);
 	q->stops++;
 }
@@ -1138,11 +1138,13 @@
  */
 int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	int qidx;
 	unsigned int ndesc, pidx, credits, gen, compl;
 	const struct port_info *pi = netdev_priv(dev);
 	struct adapter *adap = pi->adapter;
-	struct sge_qset *qs = pi->qs;
-	struct sge_txq *q = &qs->txq[TXQ_ETH];
+	struct netdev_queue *txq;
+	struct sge_qset *qs;
+	struct sge_txq *q;
 
 	/*
 	 * The chip min packet length is 9 octets but play safe and reject
@@ -1153,6 +1155,11 @@
 		return NETDEV_TX_OK;
 	}
 
+	qidx = skb_get_queue_mapping(skb);
+	qs = &pi->qs[qidx];
+	q = &qs->txq[TXQ_ETH];
+	txq = netdev_get_tx_queue(dev, qidx);
+
 	spin_lock(&q->lock);
 	reclaim_completed_tx(adap, q);
 
@@ -1160,7 +1167,7 @@
 	ndesc = calc_tx_descs(skb);
 
 	if (unlikely(credits < ndesc)) {
-		t3_stop_queue(dev, qs, q);
+		t3_stop_tx_queue(txq, qs, q);
 		dev_err(&adap->pdev->dev,
 			"%s: Tx ring %u full while queue awake!\n",
 			dev->name, q->cntxt_id & 7);
@@ -1170,12 +1177,12 @@
 
 	q->in_use += ndesc;
 	if (unlikely(credits - ndesc < q->stop_thres)) {
-		t3_stop_queue(dev, qs, q);
+		t3_stop_tx_queue(txq, qs, q);
 
 		if (should_restart_tx(q) &&
 		    test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
 			q->restarts++;
-			netif_wake_queue(dev);
+			netif_tx_wake_queue(txq);
 		}
 	}
 
@@ -1839,7 +1846,7 @@
 	    test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
 		qs->txq[TXQ_ETH].restarts++;
 		if (netif_running(qs->netdev))
-			netif_wake_queue(qs->netdev);
+			netif_tx_wake_queue(qs->tx_q);
 	}
 
 	if (test_bit(TXQ_OFLD, &qs->txq_stopped) &&
@@ -1857,6 +1864,54 @@
 }
 
 /**
+ *	cxgb3_arp_process - process an ARP request probing a private IP address
+ *	@adapter: the adapter
+ *	@skb: the skbuff containing the ARP request
+ *
+ *	Check if the ARP request is probing the private IP address
+ *	dedicated to iSCSI, generate an ARP reply if so.
+ */
+static void cxgb3_arp_process(struct adapter *adapter, struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+	struct port_info *pi;
+	struct arphdr *arp;
+	unsigned char *arp_ptr;
+	unsigned char *sha;
+	__be32 sip, tip;
+
+	if (!dev)
+		return;
+
+	skb_reset_network_header(skb);
+	arp = arp_hdr(skb);
+
+	if (arp->ar_op != htons(ARPOP_REQUEST))
+		return;
+
+	arp_ptr = (unsigned char *)(arp + 1);
+	sha = arp_ptr;
+	arp_ptr += dev->addr_len;
+	memcpy(&sip, arp_ptr, sizeof(sip));
+	arp_ptr += sizeof(sip);
+	arp_ptr += dev->addr_len;
+	memcpy(&tip, arp_ptr, sizeof(tip));
+
+	pi = netdev_priv(dev);
+	if (tip != pi->iscsi_ipv4addr)
+		return;
+
+	arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
+		 dev->dev_addr, sha);
+
+}
+
+static inline int is_arp(struct sk_buff *skb)
+{
+	return skb->protocol == htons(ETH_P_ARP);
+}
+
+/**
  *	rx_eth - process an ingress ethernet packet
  *	@adap: the adapter
  *	@rq: the response queue that received the packet
@@ -1876,11 +1931,10 @@
 
 	skb_pull(skb, sizeof(*p) + pad);
 	skb->protocol = eth_type_trans(skb, adap->port[p->iff]);
-	skb->dev->last_rx = jiffies;
 	pi = netdev_priv(skb->dev);
 	if (pi->rx_csum_offload && p->csum_valid && p->csum == htons(0xffff) &&
 	    !p->fragment) {
-		rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
+		qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	} else
 		skb->ip_summed = CHECKSUM_NONE;
@@ -1895,16 +1949,28 @@
 							     grp,
 							     ntohs(p->vlan),
 							     p);
-			else
+			else {
+				if (unlikely(pi->iscsi_ipv4addr &&
+				    is_arp(skb))) {
+					unsigned short vtag = ntohs(p->vlan) &
+								VLAN_VID_MASK;
+					skb->dev = vlan_group_get_device(grp,
+									 vtag);
+					cxgb3_arp_process(adap, skb);
+				}
 				__vlan_hwaccel_rx(skb, grp, ntohs(p->vlan),
 					  	  rq->polling);
+			}
 		else
 			dev_kfree_skb_any(skb);
 	} else if (rq->polling) {
 		if (lro)
 			lro_receive_skb(&qs->lro_mgr, skb, p);
-		else
+		else {
+			if (unlikely(pi->iscsi_ipv4addr && is_arp(skb)))
+				cxgb3_arp_process(adap, skb);
 			netif_receive_skb(skb);
+		}
 	} else
 		netif_rx(skb);
 }
@@ -2308,7 +2374,7 @@
 
 static inline int is_pure_response(const struct rsp_desc *r)
 {
-	u32 n = ntohl(r->flags) & (F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID);
+	__be32 n = r->flags & htonl(F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID);
 
 	return (n | r->len_cq) == 0;
 }
@@ -2826,6 +2892,7 @@
  *	@p: configuration parameters for this queue set
  *	@ntxq: number of Tx queues for the queue set
  *	@netdev: net device associated with this queue set
+ *	@netdevq: net device TX queue associated with this queue set
  *
  *	Allocate resources and initialize an SGE queue set.  A queue set
  *	comprises a response queue, two Rx free-buffer queues, and up to 3
@@ -2834,7 +2901,8 @@
  */
 int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
 		      int irq_vec_idx, const struct qset_params *p,
-		      int ntxq, struct net_device *dev)
+		      int ntxq, struct net_device *dev,
+		      struct netdev_queue *netdevq)
 {
 	int i, avail, ret = -ENOMEM;
 	struct sge_qset *q = &adapter->sge.qs[id];
@@ -2970,6 +3038,7 @@
 
 	q->adap = adapter;
 	q->netdev = dev;
+	q->tx_q = netdevq;
 	t3_update_qset_coalesce(q, p);
 
 	init_lro_mgr(q, lro_mgr);
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 9a0898b..2d14330 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -925,11 +925,10 @@
 /**
  *	t3_check_tpsram_version - read the tp sram version
  *	@adapter: the adapter
- *	@must_load: set to 1 if loading a new microcode image is required
  *
  *	Reads the protocol sram version from flash.
  */
-int t3_check_tpsram_version(struct adapter *adapter, int *must_load)
+int t3_check_tpsram_version(struct adapter *adapter)
 {
 	int ret;
 	u32 vers;
@@ -938,7 +937,6 @@
 	if (adapter->params.rev == T3_REV_A)
 		return 0;
 
-	*must_load = 1;
 
 	ret = t3_get_tp_version(adapter, &vers);
 	if (ret)
@@ -949,13 +947,7 @@
 
 	if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR)
 		return 0;
-
-	if (major != TP_VERSION_MAJOR)
-		CH_ERR(adapter, "found wrong TP version (%u.%u), "
-		       "driver needs version %d.%d\n", major, minor,
-		       TP_VERSION_MAJOR, TP_VERSION_MINOR);
 	else {
-		*must_load = 0;
 		CH_ERR(adapter, "found wrong TP version (%u.%u), "
 		       "driver compiled for version %d.%d\n", major, minor,
 		       TP_VERSION_MAJOR, TP_VERSION_MINOR);
@@ -1012,18 +1004,16 @@
 /**
  *	t3_check_fw_version - check if the FW is compatible with this driver
  *	@adapter: the adapter
- *	@must_load: set to 1 if loading a new FW image is required
-
+ *
  *	Checks if an adapter's FW is compatible with the driver.  Returns 0
  *	if the versions are compatible, a negative error otherwise.
  */
-int t3_check_fw_version(struct adapter *adapter, int *must_load)
+int t3_check_fw_version(struct adapter *adapter)
 {
 	int ret;
 	u32 vers;
 	unsigned int type, major, minor;
 
-	*must_load = 1;
 	ret = t3_get_fw_version(adapter, &vers);
 	if (ret)
 		return ret;
@@ -1035,17 +1025,11 @@
 	if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR &&
 	    minor == FW_VERSION_MINOR)
 		return 0;
-
-	if (major != FW_VERSION_MAJOR)
-		CH_ERR(adapter, "found wrong FW version(%u.%u), "
-		       "driver needs version %u.%u\n", major, minor,
-		       FW_VERSION_MAJOR, FW_VERSION_MINOR);
-	else if (minor < FW_VERSION_MINOR) {
-		*must_load = 0;
+	else if (major != FW_VERSION_MAJOR || minor < FW_VERSION_MINOR)
 		CH_WARN(adapter, "found old FW minor version(%u.%u), "
 		        "driver compiled for version %u.%u\n", major, minor,
 			FW_VERSION_MAJOR, FW_VERSION_MINOR);
-	} else {
+	else {
 		CH_WARN(adapter, "found newer FW version(%u.%u), "
 		        "driver compiled for version %u.%u\n", major, minor,
 			FW_VERSION_MAJOR, FW_VERSION_MINOR);
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index bb8698a..b1b25c3 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -35,7 +35,7 @@
 #define DRV_DESC "Chelsio T3 Network Driver"
 #define DRV_NAME "cxgb3"
 /* Driver version */
-#define DRV_VERSION "1.1.0-ko"
+#define DRV_VERSION "1.1.1-ko"
 
 /* Firmware version */
 #define FW_VERSION_MAJOR 7
diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c
index 33f956b..d071309 100644
--- a/drivers/net/cxgb3/vsc8211.c
+++ b/drivers/net/cxgb3/vsc8211.c
@@ -262,6 +262,7 @@
 	return 0;
 }
 
+#ifdef UNUSED
 /*
  * Enable/disable auto MDI/MDI-X in forced link speed mode.
  */
@@ -301,6 +302,7 @@
 		err = vsc8211_set_automdi(phy, 1);
 	return err;
 }
+#endif /* UNUSED */
 
 static int vsc8211_power_down(struct cphy *cphy, int enable)
 {
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index cb849b0..970f820 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -369,7 +369,6 @@
 	netif_rx(skb);
 
 	/* update stats */
-	dev->last_rx = jiffies;
 	dev->stats.rx_packets++; /* count all receives */
 	dev->stats.rx_bytes += size; /* count all received bytes */
 
@@ -384,7 +383,6 @@
 	int	i;
 	struct net_device *dev;
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(0);
 	if (!dev)
@@ -439,7 +437,7 @@
 		goto out1;
 	}
 
-	printk(", Ethernet Address: %s\n", print_mac(mac, dev->dev_addr));
+	printk(", Ethernet Address: %pM\n", dev->dev_addr);
 
 	dev->open = de600_open;
 	dev->stop = de600_close;
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index d454e14..bdfa894 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -686,7 +686,6 @@
 			PRINTK(("Read %d bytes\n", size));
 			skb->protocol=eth_type_trans(skb,dev);
 			netif_rx(skb); /* deliver it "upstairs" */
-			dev->last_rx = jiffies;
 			/* count all receives */
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += size;
@@ -800,7 +799,6 @@
 	struct net_device *dev;
 	int err = -ENOMEM;
 	int i;
-	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(0);
 	if (!dev)
@@ -853,7 +851,7 @@
 		dev->broadcast[i] = 0xff;
 	}
 
-	printk(", Ethernet Address: %s", print_mac(mac, dev->dev_addr));
+	printk(", Ethernet Address: %pM", dev->dev_addr);
 
 	printk(" (%dk RAM,",
 		(nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64);
@@ -876,10 +874,7 @@
 	if (de620_debug) {
 		printk("\nEEPROM contents:\n");
 		printk("RAM_Size = 0x%02X\n", nic_data.RAM_Size);
-		printk("NodeID = %02X:%02X:%02X:%02X:%02X:%02X\n",
-			nic_data.NodeID[0], nic_data.NodeID[1],
-			nic_data.NodeID[2], nic_data.NodeID[3],
-			nic_data.NodeID[4], nic_data.NodeID[5]);
+		printk("NodeID = %pM\n", nic_data.NodeID);
 		printk("Model = %d\n", nic_data.Model);
 		printk("Media = %d\n", nic_data.Media);
 		printk("SCR = 0x%02x\n", nic_data.SCR);
@@ -1008,20 +1003,3 @@
 }
 #endif /* MODULE */
 MODULE_LICENSE("GPL");
-
-
-/*
- * (add '-DMODULE' when compiling as loadable module)
- *
- * compile-command:
- *	gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O2 \
- *	 -fomit-frame-pointer -m486 \
- *	-I/usr/src/linux/include -I../../net/inet -c de620.c
-*/
-/*
- * Local variables:
- *  kernel-compile-command: "gcc -D__KERNEL__ -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de620.c"
- *  module-compile-command: "gcc -D__KERNEL__ -DMODULE -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de620.c"
- *  compile-command: "gcc -D__KERNEL__ -DMODULE -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de620.c"
- * End:
- */
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 3e35064..7ce3053 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -622,7 +622,6 @@
 
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 		}
 
@@ -1023,7 +1022,6 @@
 	int i, ret;
 	unsigned long esar_base;
 	unsigned char *esar;
-	DECLARE_MAC_BUF(mac);
 
 	if (dec_lance_debug && version_printed++ == 0)
 		printk(version);
@@ -1035,7 +1033,7 @@
 		dev = root_lance_dev;
 		while (dev) {
 			i++;
-			lp = (struct lance_private *)dev->priv;
+			lp = netdev_priv(dev);
 			dev = lp->next;
 		}
 		snprintf(name, sizeof(name), fmt, i);
@@ -1223,8 +1221,7 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = esar[i * 4];
 
-	printk(", addr = %s, irq = %d\n",
-	       print_mac(mac, dev->dev_addr), dev->irq);
+	printk(", addr = %pM, irq = %d\n", dev->dev_addr, dev->irq);
 
 	dev->open = &lance_open;
 	dev->stop = &lance_close;
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index c062aac..6445cedd 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -477,6 +477,15 @@
 	}
 }
 
+static const struct net_device_ops dfx_netdev_ops = {
+	.ndo_open		= dfx_open,
+	.ndo_stop		= dfx_close,
+	.ndo_start_xmit		= dfx_xmt_queue_pkt,
+	.ndo_get_stats		= dfx_ctl_get_stats,
+	.ndo_set_multicast_list	= dfx_ctl_set_multicast_list,
+	.ndo_set_mac_address	= dfx_ctl_set_mac_address,
+};
+
 /*
  * ================
  * = dfx_register =
@@ -511,7 +520,7 @@
 	int dfx_bus_pci = DFX_BUS_PCI(bdev);
 	int dfx_bus_tc = DFX_BUS_TC(bdev);
 	int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
-	char *print_name = bdev->bus_id;
+	const char *print_name = dev_name(bdev);
 	struct net_device *dev;
 	DFX_board_t	  *bp;			/* board pointer */
 	resource_size_t bar_start = 0;		/* pointer to port */
@@ -573,13 +582,7 @@
 	}
 
 	/* Initialize new device structure */
-
-	dev->get_stats			= dfx_ctl_get_stats;
-	dev->open			= dfx_open;
-	dev->stop			= dfx_close;
-	dev->hard_start_xmit		= dfx_xmt_queue_pkt;
-	dev->set_multicast_list		= dfx_ctl_set_multicast_list;
-	dev->set_mac_address		= dfx_ctl_set_mac_address;
+	dev->netdev_ops			= &dfx_netdev_ops;
 
 	if (dfx_bus_pci)
 		pci_set_master(to_pci_dev(bdev));
@@ -3103,7 +3106,6 @@
 					netif_rx(skb);
 
 					/* Update the rcv counters */
-					bp->dev->last_rx = jiffies;
 					bp->rcv_total_frames++;
 					if (*(p_buff + RCV_BUFF_K_DA) & 0x01)
 						bp->rcv_multicast_frames++;
@@ -3741,10 +3743,3 @@
 MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver "
 		   DRV_VERSION " " DRV_RELDATE);
 MODULE_LICENSE("GPL");
-
-
-/*
- * Local variables:
- * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -c defxx.c"
- * End:
- */
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index ace39ec..e4cef49 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -573,7 +573,6 @@
 	s16 nicsr;
 	u_long ioaddr;
 	u_long mem_start;
-	DECLARE_MAC_BUF(mac);
 
 	/*
 	 * We are now supposed to enter this function with the
@@ -601,7 +600,7 @@
 		return -ENXIO;
 	}
 
-	lp = (struct depca_private *) dev->priv;
+	lp = netdev_priv(dev);
 	mem_start = lp->mem_start;
 
 	if (!mem_start || lp->adapter < DEPCA || lp->adapter >=unknown)
@@ -633,7 +632,7 @@
 
 	printk(", h/w address ");
 	status = get_hw_addr(dev);
-	printk("%s", print_mac(mac, dev->dev_addr));
+	printk("%pM", dev->dev_addr);
 	if (status != 0) {
 		printk("      which has an Ethernet PROM CRC error.\n");
 		return -ENXIO;
@@ -821,7 +820,7 @@
 
 static int depca_open(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	u_long ioaddr = dev->base_addr;
 	s16 nicsr;
 	int status = 0;
@@ -866,7 +865,7 @@
 /* Initialize the lance Rx and Tx descriptor rings. */
 static void depca_init_ring(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	u_int i;
 	u_long offset;
 
@@ -924,7 +923,7 @@
 */
 static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	u_long ioaddr = dev->base_addr;
 	int status = 0;
 
@@ -972,7 +971,7 @@
 		return IRQ_NONE;
 	}
 
-	lp = (struct depca_private *) dev->priv;
+	lp = netdev_priv(dev);
 	ioaddr = dev->base_addr;
 
 	spin_lock(&lp->lock);
@@ -1010,7 +1009,7 @@
 /* Called with lp->lock held */
 static int depca_rx(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	int i, entry;
 	s32 status;
 
@@ -1057,7 +1056,6 @@
 					/*
 					   ** Update stats
 					 */
-					dev->last_rx = jiffies;
 					dev->stats.rx_packets++;
 					dev->stats.rx_bytes += pkt_len;
 					for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) {
@@ -1108,7 +1106,7 @@
 */
 static int depca_tx(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	int entry;
 	s32 status;
 	u_long ioaddr = dev->base_addr;
@@ -1149,7 +1147,7 @@
 
 static int depca_close(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	s16 nicsr;
 	u_long ioaddr = dev->base_addr;
 
@@ -1185,7 +1183,7 @@
 
 static void LoadCSRs(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	u_long ioaddr = dev->base_addr;
 
 	outw(CSR1, DEPCA_ADDR);	/* initialisation block address LSW */
@@ -1202,7 +1200,7 @@
 
 static int InitRestartDepca(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	u_long ioaddr = dev->base_addr;
 	int i, status = 0;
 
@@ -1234,7 +1232,7 @@
 */
 static void set_multicast_list(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	u_long ioaddr = dev->base_addr;
 
 	netif_stop_queue(dev);
@@ -1263,7 +1261,7 @@
 */
 static void SetMulticastFilter(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
@@ -1431,7 +1429,7 @@
 
 	dev->irq = irq;
 	dev->base_addr = iobase;
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	lp->depca_bus = DEPCA_BUS_MCA;
 	lp->adapter = depca_mca_adapter_type[mdev->index];
 	lp->mem_start = mem_start;
@@ -1534,7 +1532,7 @@
 	dev->base_addr = ioaddr;
 	dev->irq = irq;		/* Use whatever value the user gave
 				 * us, and 0 if he didn't. */
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	lp->depca_bus = DEPCA_BUS_ISA;
 	lp->adapter = adapter;
 	lp->mem_start = mem_start;
@@ -1558,6 +1556,7 @@
 #ifdef CONFIG_EISA
 static int __init depca_eisa_probe (struct device *device)
 {
+	enum depca_type adapter = unknown;
 	struct eisa_device *edev;
 	struct net_device *dev;
 	struct depca_private *lp;
@@ -1576,11 +1575,15 @@
 	 * the EISA configuration structures (yet... :-), just rely on
 	 * the ISA probing to sort it out... */
 
-	depca_shmem_probe (&mem_start);
+	adapter = depca_shmem_probe (&mem_start);
+	if (adapter == unknown) {
+		status = -ENODEV;
+		goto out_free;
+	}
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	lp->depca_bus = DEPCA_BUS_EISA;
 	lp->adapter = edev->id.driver_data;
 	lp->mem_start = mem_start;
@@ -1605,7 +1608,7 @@
 	int bus;
 
 	dev  = device->driver_data;
-	lp   = dev->priv;
+	lp   = netdev_priv(dev);
 
 	unregister_netdev (dev);
 	iounmap (lp->sh_mem);
@@ -1747,7 +1750,7 @@
 static int __init get_hw_addr(struct net_device *dev)
 {
 	u_long ioaddr = dev->base_addr;
-	struct depca_private *lp = dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	int i, k, tmp, status = 0;
 	u_short j, x, chksum;
 
@@ -1782,7 +1785,7 @@
 */
 static int load_packet(struct net_device *dev, struct sk_buff *skb)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	int i, entry, end, len, status = 0;
 
 	entry = lp->tx_new;	/* Ring around buffer number. */
@@ -1837,11 +1840,10 @@
 
 static void depca_dbg_open(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	u_long ioaddr = dev->base_addr;
 	struct depca_init *p = &lp->init_block;
 	int i;
-	DECLARE_MAC_BUF(mac);
 
 	if (depca_debug > 1) {
 		/* Do not copy the shadow init block into shared memory */
@@ -1880,7 +1882,7 @@
 		printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
 		printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start);
 		printk("        mode: 0x%4.4x\n", p->mode);
-		printk("        physical address: %s\n", print_mac(mac, p->phys_addr));
+		printk("        physical address: %pM\n", p->phys_addr);
 		printk("        multicast hash table: ");
 		for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) {
 			printk("%2.2x:", p->mcast_table[i]);
@@ -1909,7 +1911,7 @@
 */
 static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_private *lp = netdev_priv(dev);
 	struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_ifru;
 	int i, status = 0;
 	u_long ioaddr = dev->base_addr;
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index f803711..c749e9f 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -85,6 +85,19 @@
 
 static const struct ethtool_ops ethtool_ops;
 
+static const struct net_device_ops netdev_ops = {
+	.ndo_open		= rio_open,
+	.ndo_start_xmit	= start_xmit,
+	.ndo_stop		= rio_close,
+	.ndo_get_stats		= get_stats,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address 	= eth_mac_addr,
+	.ndo_set_multicast_list = set_multicast,
+	.ndo_do_ioctl		= rio_ioctl,
+	.ndo_tx_timeout		= rio_tx_timeout,
+	.ndo_change_mtu		= change_mtu,
+};
+
 static int __devinit
 rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -97,7 +110,6 @@
 	static int version_printed;
 	void *ring_space;
 	dma_addr_t ring_dma;
-	DECLARE_MAC_BUF(mac);
 
 	if (!version_printed++)
 		printk ("%s", version);
@@ -198,15 +210,8 @@
 		else if (tx_coalesce > TX_RING_SIZE-1)
 			tx_coalesce = TX_RING_SIZE - 1;
 	}
-	dev->open = &rio_open;
-	dev->hard_start_xmit = &start_xmit;
-	dev->stop = &rio_close;
-	dev->get_stats = &get_stats;
-	dev->set_multicast_list = &set_multicast;
-	dev->do_ioctl = &rio_ioctl;
-	dev->tx_timeout = &rio_tx_timeout;
+	dev->netdev_ops = &netdev_ops;
 	dev->watchdog_timeo = TX_TIMEOUT;
-	dev->change_mtu = &change_mtu;
 	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 #if 0
 	dev->features = NETIF_F_IP_CSUM;
@@ -257,8 +262,8 @@
 
 	card_idx++;
 
-	printk (KERN_INFO "%s: %s, %s, IRQ %d\n",
-		dev->name, np->name, print_mac(mac, dev->dev_addr), irq);
+	printk (KERN_INFO "%s: %s, %pM, IRQ %d\n",
+		dev->name, np->name, dev->dev_addr, irq);
 	if (tx_coalesce > 1)
 		printk(KERN_INFO "tx_coalesce:\t%d packets\n",
 				tx_coalesce);
@@ -892,7 +897,6 @@
 			}
 #endif
 			netif_rx (skb);
-			dev->last_rx = jiffies;
 		}
 		entry = (entry + 1) % RX_RING_SIZE;
 	}
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 5a9083e..bcf9291 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -137,7 +137,7 @@
 
 static inline board_info_t *to_dm9000_board(struct net_device *dev)
 {
-	return dev->priv;
+	return netdev_priv(dev);
 }
 
 /* DM9000 network board routine ---------------------------- */
@@ -626,7 +626,7 @@
 static void
 dm9000_hash_table(struct net_device *dev)
 {
-	board_info_t *db = (board_info_t *) dev->priv;
+	board_info_t *db = netdev_priv(dev);
 	struct dev_mc_list *mcptr = dev->mc_list;
 	int mc_cnt = dev->mc_count;
 	int i, oft;
@@ -677,7 +677,7 @@
 static void
 dm9000_init_dm9000(struct net_device *dev)
 {
-	board_info_t *db = dev->priv;
+	board_info_t *db = netdev_priv(dev);
 	unsigned int imr;
 
 	dm9000_dbg(db, 1, "entering %s\n", __func__);
@@ -723,7 +723,7 @@
 /* Our watchdog timed out. Called by the networking layer */
 static void dm9000_timeout(struct net_device *dev)
 {
-	board_info_t *db = (board_info_t *) dev->priv;
+	board_info_t *db = netdev_priv(dev);
 	u8 reg_save;
 	unsigned long flags;
 
@@ -751,7 +751,7 @@
 dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	unsigned long flags;
-	board_info_t *db = dev->priv;
+	board_info_t *db = netdev_priv(dev);
 
 	dm9000_dbg(db, 3, "%s:\n", __func__);
 
@@ -831,7 +831,7 @@
 static void
 dm9000_rx(struct net_device *dev)
 {
-	board_info_t *db = (board_info_t *) dev->priv;
+	board_info_t *db = netdev_priv(dev);
 	struct dm9000_rxhdr rxhdr;
 	struct sk_buff *skb;
 	u8 rxbyte, *rdptr;
@@ -928,7 +928,7 @@
 static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
-	board_info_t *db = dev->priv;
+	board_info_t *db = netdev_priv(dev);
 	int int_status;
 	u8 reg_save;
 
@@ -996,7 +996,7 @@
 static int
 dm9000_open(struct net_device *dev)
 {
-	board_info_t *db = dev->priv;
+	board_info_t *db = netdev_priv(dev);
 	unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
 
 	if (netif_msg_ifup(db))
@@ -1046,7 +1046,7 @@
 static int
 dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
 {
-	board_info_t *db = (board_info_t *) dev->priv;
+	board_info_t *db = netdev_priv(dev);
 	unsigned long flags;
 	unsigned int reg_save;
 	int ret;
@@ -1093,7 +1093,7 @@
 dm9000_phy_write(struct net_device *dev,
 		 int phyaddr_unused, int reg, int value)
 {
-	board_info_t *db = (board_info_t *) dev->priv;
+	board_info_t *db = netdev_priv(dev);
 	unsigned long flags;
 	unsigned long reg_save;
 
@@ -1134,7 +1134,7 @@
 static void
 dm9000_shutdown(struct net_device *dev)
 {
-	board_info_t *db = dev->priv;
+	board_info_t *db = netdev_priv(dev);
 
 	/* RESET device */
 	dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);	/* PHY RESET */
@@ -1150,7 +1150,7 @@
 static int
 dm9000_stop(struct net_device *ndev)
 {
-	board_info_t *db = ndev->priv;
+	board_info_t *db = netdev_priv(ndev);
 
 	if (netif_msg_ifdown(db))
 		dev_dbg(db->dev, "shutting down %s\n", ndev->name);
@@ -1197,7 +1197,7 @@
 	dev_dbg(&pdev->dev, "dm9000_probe()\n");
 
 	/* setup board info structure */
-	db = ndev->priv;
+	db = netdev_priv(ndev);
 	memset(db, 0, sizeof(*db));
 
 	db->dev = &pdev->dev;
@@ -1385,13 +1385,11 @@
 	platform_set_drvdata(pdev, ndev);
 	ret = register_netdev(ndev);
 
-	if (ret == 0) {
-		DECLARE_MAC_BUF(mac);
-		printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %s (%s)\n",
+	if (ret == 0)
+		printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",
 		       ndev->name, dm9000_type_to_char(db->type),
 		       db->io_addr, db->io_data, ndev->irq,
-		       print_mac(mac, ndev->dev_addr), mac_src);
-	}
+		       ndev->dev_addr, mac_src);
 	return 0;
 
 out:
@@ -1410,7 +1408,7 @@
 	board_info_t *db;
 
 	if (ndev) {
-		db = (board_info_t *) ndev->priv;
+		db = netdev_priv(ndev);
 		db->in_suspend = 1;
 
 		if (netif_running(ndev)) {
@@ -1425,7 +1423,7 @@
 dm9000_drv_resume(struct platform_device *dev)
 {
 	struct net_device *ndev = platform_get_drvdata(dev);
-	board_info_t *db = (board_info_t *) ndev->priv;
+	board_info_t *db = netdev_priv(ndev);
 
 	if (ndev) {
 
@@ -1449,7 +1447,7 @@
 	platform_set_drvdata(pdev, NULL);
 
 	unregister_netdev(ndev);
-	dm9000_release_board(pdev, (board_info_t *) ndev->priv);
+	dm9000_release_board(pdev, (board_info_t *) netdev_priv(ndev));
 	free_netdev(ndev);		/* free device structure */
 
 	dev_dbg(&pdev->dev, "released and freed device\n");
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 84e14f3..8ebd7d7 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -57,18 +57,23 @@
 {
 }
 
+static const struct net_device_ops dummy_netdev_ops = {
+	.ndo_start_xmit		= dummy_xmit,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_multicast_list = set_multicast_list,
+	.ndo_set_mac_address	= dummy_set_address,
+};
+
 static void dummy_setup(struct net_device *dev)
 {
+	ether_setup(dev);
+
 	/* Initialize the device structure. */
-	dev->hard_start_xmit = dummy_xmit;
-	dev->set_multicast_list = set_multicast_list;
-	dev->set_mac_address = dummy_set_address;
+	dev->netdev_ops = &dummy_netdev_ops;
 	dev->destructor = free_netdev;
 
 	/* Fill in device structure with ethernet-generic values. */
-	ether_setup(dev);
 	dev->tx_queue_len = 0;
-	dev->change_mtu = NULL;
 	dev->flags |= IFF_NOARP;
 	dev->flags &= ~IFF_MULTICAST;
 	random_ether_addr(dev->dev_addr);
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index e8bfcce..9f38b16 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1580,11 +1580,13 @@
 	mii_ethtool_gset(&nic->mii, &cmd);
 
 	if(mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) {
-		DPRINTK(LINK, INFO, "link up, %sMbps, %s-duplex\n",
-			cmd.speed == SPEED_100 ? "100" : "10",
-			cmd.duplex == DUPLEX_FULL ? "full" : "half");
+		printk(KERN_INFO "e100: %s NIC Link is Up %s Mbps %s Duplex\n",
+		       nic->netdev->name,
+		       cmd.speed == SPEED_100 ? "100" : "10",
+		       cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
 	} else if(!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) {
-		DPRINTK(LINK, INFO, "link down\n");
+		printk(KERN_INFO "e100: %s NIC Link is Down\n",
+		       nic->netdev->name);
 	}
 
 	mii_check_link(&nic->mii);
@@ -1880,7 +1882,6 @@
 	} else {
 		dev->stats.rx_packets++;
 		dev->stats.rx_bytes += actual_size;
-		nic->netdev->last_rx = jiffies;
 		netif_receive_skb(skb);
 		if(work_done)
 			(*work_done)++;
@@ -2048,9 +2049,9 @@
 	if(stat_ack & stat_ack_rnr)
 		nic->ru_running = RU_SUSPENDED;
 
-	if(likely(netif_rx_schedule_prep(netdev, &nic->napi))) {
+	if(likely(netif_rx_schedule_prep(&nic->napi))) {
 		e100_disable_irq(nic);
-		__netif_rx_schedule(netdev, &nic->napi);
+		__netif_rx_schedule(&nic->napi);
 	}
 
 	return IRQ_HANDLED;
@@ -2059,7 +2060,6 @@
 static int e100_poll(struct napi_struct *napi, int budget)
 {
 	struct nic *nic = container_of(napi, struct nic, napi);
-	struct net_device *netdev = nic->netdev;
 	unsigned int work_done = 0;
 
 	e100_rx_clean(nic, &work_done, budget);
@@ -2067,7 +2067,7 @@
 
 	/* If budget not fully consumed, exit the polling mode */
 	if (work_done < budget) {
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 		e100_enable_irq(nic);
 	}
 
@@ -2322,7 +2322,8 @@
 {
 	struct nic *nic = netdev_priv(netdev);
 
-	if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
+	if ((wol->wolopts && wol->wolopts != WAKE_MAGIC) ||
+	    !device_can_wakeup(&nic->pdev->dev))
 		return -EOPNOTSUPP;
 
 	if(wol->wolopts)
@@ -2330,6 +2331,8 @@
 	else
 		nic->flags &= ~wol_magic;
 
+	device_set_wakeup_enable(&nic->pdev->dev, wol->wolopts);
+
 	e100_exec_cb(nic, NULL, e100_configure);
 
 	return 0;
@@ -2610,13 +2613,27 @@
 	return 0;
 }
 
+static const struct net_device_ops e100_netdev_ops = {
+	.ndo_open		= e100_open,
+	.ndo_stop		= e100_close,
+	.ndo_start_xmit		= e100_xmit_frame,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_multicast_list	= e100_set_multicast_list,
+	.ndo_set_mac_address	= e100_set_mac_address,
+	.ndo_change_mtu		= e100_change_mtu,
+	.ndo_do_ioctl		= e100_do_ioctl,
+	.ndo_tx_timeout		= e100_tx_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= e100_netpoll,
+#endif
+};
+
 static int __devinit e100_probe(struct pci_dev *pdev,
 	const struct pci_device_id *ent)
 {
 	struct net_device *netdev;
 	struct nic *nic;
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	if(!(netdev = alloc_etherdev(sizeof(struct nic)))) {
 		if(((1 << debug) - 1) & NETIF_MSG_PROBE)
@@ -2624,19 +2641,9 @@
 		return -ENOMEM;
 	}
 
-	netdev->open = e100_open;
-	netdev->stop = e100_close;
-	netdev->hard_start_xmit = e100_xmit_frame;
-	netdev->set_multicast_list = e100_set_multicast_list;
-	netdev->set_mac_address = e100_set_mac_address;
-	netdev->change_mtu = e100_change_mtu;
-	netdev->do_ioctl = e100_do_ioctl;
+	netdev->netdev_ops = &e100_netdev_ops;
 	SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops);
-	netdev->tx_timeout = e100_tx_timeout;
 	netdev->watchdog_timeo = E100_WATCHDOG_PERIOD;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	netdev->poll_controller = e100_netpoll;
-#endif
 	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
 
 	nic = netdev_priv(netdev);
@@ -2734,8 +2741,10 @@
 
 	/* Wol magic packet can be enabled from eeprom */
 	if((nic->mac >= mac_82558_D101_A4) &&
-	   (nic->eeprom[eeprom_id] & eeprom_id_wol))
+	   (nic->eeprom[eeprom_id] & eeprom_id_wol)) {
 		nic->flags |= wol_magic;
+		device_set_wakeup_enable(&pdev->dev, true);
+	}
 
 	/* ack any pending wake events, disable PME */
 	pci_pme_active(pdev, false);
@@ -2746,9 +2755,9 @@
 		goto err_out_free;
 	}
 
-	DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %s\n",
+	DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n",
 		(unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
-		pdev->irq, print_mac(mac, netdev->dev_addr));
+		pdev->irq, netdev->dev_addr);
 
 	return 0;
 
@@ -2794,11 +2803,10 @@
 	pci_save_state(pdev);
 
 	if ((nic->flags & wol_magic) | e100_asf(nic)) {
-		pci_enable_wake(pdev, PCI_D3hot, 1);
-		pci_enable_wake(pdev, PCI_D3cold, 1);
+		if (pci_enable_wake(pdev, PCI_D3cold, true))
+			pci_enable_wake(pdev, PCI_D3hot, true);
 	} else {
-		pci_enable_wake(pdev, PCI_D3hot, 0);
-		pci_enable_wake(pdev, PCI_D3cold, 0);
+		pci_enable_wake(pdev, PCI_D3hot, false);
 	}
 
 	pci_disable_device(pdev);
@@ -2843,7 +2851,7 @@
 	struct nic *nic = netdev_priv(netdev);
 
 	/* Similar to calling e100_down(), but avoids adapter I/O. */
-	netdev->stop(netdev);
+	e100_close(netdev);
 
 	/* Detach; put netif into a state similar to hotplug unplug. */
 	napi_enable(&nic->napi);
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 62f6297..f5581de 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -284,7 +284,6 @@
 			     int cleaned_count);
 	struct e1000_rx_ring *rx_ring;      /* One per active queue */
 	struct napi_struct napi;
-	struct net_device *polling_netdev;  /* One per active queue */
 
 	int num_tx_queues;
 	int num_rx_queues;
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 872799b..26474c9 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -888,6 +888,26 @@
 	}
 }
 
+static const struct net_device_ops e1000_netdev_ops = {
+	.ndo_open		= e1000_open,
+	.ndo_stop		= e1000_close,
+	.ndo_start_xmit		= e1000_xmit_frame,
+	.ndo_get_stats		= e1000_get_stats,
+	.ndo_set_rx_mode	= e1000_set_rx_mode,
+	.ndo_set_mac_address	= e1000_set_mac,
+	.ndo_tx_timeout 	= e1000_tx_timeout,
+	.ndo_change_mtu		= e1000_change_mtu,
+	.ndo_do_ioctl		= e1000_ioctl,
+	.ndo_validate_addr	= eth_validate_addr,
+
+	.ndo_vlan_rx_register	= e1000_vlan_rx_register,
+	.ndo_vlan_rx_add_vid	= e1000_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= e1000_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= e1000_netpoll,
+#endif
+};
+
 /**
  * e1000_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -912,7 +932,6 @@
 	u16 eeprom_data = 0;
 	u16 eeprom_apme_mask = E1000_EEPROM_APME;
 	int bars, need_ioport;
-	DECLARE_MAC_BUF(mac);
 
 	/* do not allocate ioport bars when not needed */
 	need_ioport = e1000_is_need_ioport(pdev);
@@ -967,8 +986,7 @@
 	hw->back = adapter;
 
 	err = -EIO;
-	hw->hw_addr = ioremap(pci_resource_start(pdev, BAR_0),
-			      pci_resource_len(pdev, BAR_0));
+	hw->hw_addr = pci_ioremap_bar(pdev, BAR_0);
 	if (!hw->hw_addr)
 		goto err_ioremap;
 
@@ -983,24 +1001,11 @@
 		}
 	}
 
-	netdev->open = &e1000_open;
-	netdev->stop = &e1000_close;
-	netdev->hard_start_xmit = &e1000_xmit_frame;
-	netdev->get_stats = &e1000_get_stats;
-	netdev->set_rx_mode = &e1000_set_rx_mode;
-	netdev->set_mac_address = &e1000_set_mac;
-	netdev->change_mtu = &e1000_change_mtu;
-	netdev->do_ioctl = &e1000_ioctl;
+	netdev->netdev_ops = &e1000_netdev_ops;
 	e1000_set_ethtool_ops(netdev);
-	netdev->tx_timeout = &e1000_tx_timeout;
 	netdev->watchdog_timeo = 5 * HZ;
 	netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
-	netdev->vlan_rx_register = e1000_vlan_rx_register;
-	netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
-	netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	netdev->poll_controller = e1000_netpoll;
-#endif
+
 	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
 
 	adapter->bd_number = cards_found;
@@ -1016,9 +1021,7 @@
 	 * because it depends on mac_type */
 	if ((hw->mac_type == e1000_ich8lan) &&
 	   (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
-		hw->flash_address =
-			ioremap(pci_resource_start(pdev, 1),
-				pci_resource_len(pdev, 1));
+		hw->flash_address = pci_ioremap_bar(pdev, 1);
 		if (!hw->flash_address)
 			goto err_flashmap;
 	}
@@ -1195,7 +1198,7 @@
 		 (hw->bus_width == e1000_bus_width_pciex_1) ? "Width x1" :
 		 "32-bit"));
 
-	printk("%s\n", print_mac(mac, netdev->dev_addr));
+	printk("%pM\n", netdev->dev_addr);
 
 	if (hw->bus_type == e1000_bus_type_pci_express) {
 		DPRINTK(PROBE, WARNING, "This device (id %04x:%04x) will no "
@@ -1239,12 +1242,8 @@
 	if (hw->flash_address)
 		iounmap(hw->flash_address);
 err_flashmap:
-	for (i = 0; i < adapter->num_rx_queues; i++)
-		dev_put(&adapter->polling_netdev[i]);
-
 	kfree(adapter->tx_ring);
 	kfree(adapter->rx_ring);
-	kfree(adapter->polling_netdev);
 err_sw_init:
 	iounmap(hw->hw_addr);
 err_ioremap:
@@ -1272,7 +1271,6 @@
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-	int i;
 
 	cancel_work_sync(&adapter->reset_task);
 
@@ -1282,9 +1280,6 @@
 	 * would have already happened in close and is redundant. */
 	e1000_release_hw_control(adapter);
 
-	for (i = 0; i < adapter->num_rx_queues; i++)
-		dev_put(&adapter->polling_netdev[i]);
-
 	unregister_netdev(netdev);
 
 	if (!e1000_check_phy_reset_block(hw))
@@ -1292,7 +1287,6 @@
 
 	kfree(adapter->tx_ring);
 	kfree(adapter->rx_ring);
-	kfree(adapter->polling_netdev);
 
 	iounmap(hw->hw_addr);
 	if (hw->flash_address)
@@ -1318,7 +1312,6 @@
 	struct e1000_hw *hw = &adapter->hw;
 	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
-	int i;
 
 	/* PCI config space info */
 
@@ -1375,11 +1368,6 @@
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < adapter->num_rx_queues; i++) {
-		adapter->polling_netdev[i].priv = adapter;
-		dev_hold(&adapter->polling_netdev[i]);
-		set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state);
-	}
 	spin_lock_init(&adapter->tx_queue_lock);
 
 	/* Explicitly disable IRQ since the NIC can be in any state. */
@@ -1397,8 +1385,7 @@
  * @adapter: board private structure to initialize
  *
  * We allocate one ring per queue at run-time since we don't know the
- * number of queues at compile-time.  The polling_netdev array is
- * intended for Multiqueue, but should work fine with a single queue.
+ * number of queues at compile-time.
  **/
 
 static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter)
@@ -1415,15 +1402,6 @@
 		return -ENOMEM;
 	}
 
-	adapter->polling_netdev = kcalloc(adapter->num_rx_queues,
-	                                  sizeof(struct net_device),
-	                                  GFP_KERNEL);
-	if (!adapter->polling_netdev) {
-		kfree(adapter->tx_ring);
-		kfree(adapter->rx_ring);
-		return -ENOMEM;
-	}
-
 	return E1000_SUCCESS;
 }
 
@@ -2521,10 +2499,11 @@
 			                           &adapter->link_duplex);
 
 			ctrl = er32(CTRL);
-			DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s, "
-			        "Flow Control: %s\n",
-			        adapter->link_speed,
-			        adapter->link_duplex == FULL_DUPLEX ?
+			printk(KERN_INFO "e1000: %s NIC Link is Up %d Mbps %s, "
+			       "Flow Control: %s\n",
+			       netdev->name,
+			       adapter->link_speed,
+			       adapter->link_duplex == FULL_DUPLEX ?
 			        "Full Duplex" : "Half Duplex",
 			        ((ctrl & E1000_CTRL_TFCE) && (ctrl &
 			        E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl &
@@ -2600,7 +2579,8 @@
 		if (netif_carrier_ok(netdev)) {
 			adapter->link_speed = 0;
 			adapter->link_duplex = 0;
-			DPRINTK(LINK, INFO, "NIC Link is Down\n");
+			printk(KERN_INFO "e1000: %s NIC Link is Down\n",
+			       netdev->name);
 			netif_carrier_off(netdev);
 			netif_stop_queue(netdev);
 			mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ));
@@ -3707,12 +3687,12 @@
 			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
-	if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) {
+	if (likely(netif_rx_schedule_prep(&adapter->napi))) {
 		adapter->total_tx_bytes = 0;
 		adapter->total_tx_packets = 0;
 		adapter->total_rx_bytes = 0;
 		adapter->total_rx_packets = 0;
-		__netif_rx_schedule(netdev, &adapter->napi);
+		__netif_rx_schedule(&adapter->napi);
 	} else
 		e1000_irq_enable(adapter);
 
@@ -3767,12 +3747,12 @@
 		ew32(IMC, ~0);
 		E1000_WRITE_FLUSH();
 	}
-	if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) {
+	if (likely(netif_rx_schedule_prep(&adapter->napi))) {
 		adapter->total_tx_bytes = 0;
 		adapter->total_tx_packets = 0;
 		adapter->total_rx_bytes = 0;
 		adapter->total_rx_packets = 0;
-		__netif_rx_schedule(netdev, &adapter->napi);
+		__netif_rx_schedule(&adapter->napi);
 	} else
 		/* this really should not happen! if it does it is basically a
 		 * bug, but not a hard error, so enable ints and continue */
@@ -3791,8 +3771,7 @@
 	struct net_device *poll_dev = adapter->netdev;
 	int tx_cleaned = 0, work_done = 0;
 
-	/* Must NOT use netdev_priv macro here. */
-	adapter = poll_dev->priv;
+	adapter = netdev_priv(poll_dev);
 
 	/* e1000_clean is called per-cpu.  This lock protects
 	 * tx_ring[0] from being cleaned by multiple cpus
@@ -3814,7 +3793,7 @@
 	if (work_done < budget) {
 		if (likely(adapter->itr_setting & 3))
 			e1000_set_itr(adapter);
-		netif_rx_complete(poll_dev, napi);
+		netif_rx_complete(napi);
 		e1000_irq_enable(adapter);
 	}
 
@@ -4104,8 +4083,6 @@
 			netif_receive_skb(skb);
 		}
 
-		netdev->last_rx = jiffies;
-
 next_desc:
 		rx_desc->status = 0;
 
@@ -4789,7 +4766,7 @@
 						pci_channel_state_t state)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 
 	netif_device_detach(netdev);
 
@@ -4811,7 +4788,7 @@
 static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	int err;
 
@@ -4845,7 +4822,7 @@
 static void e1000_io_resume(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct e1000_adapter *adapter = netdev->priv;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 
 	e1000_init_manageability(adapter);
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index b2c910c..cf43ee74 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -28,6 +28,7 @@
 
 /*
  * 82571EB Gigabit Ethernet Controller
+ * 82571EB Gigabit Ethernet Controller (Copper)
  * 82571EB Gigabit Ethernet Controller (Fiber)
  * 82571EB Dual Port Gigabit Mezzanine Adapter
  * 82571EB Quad Port Gigabit Mezzanine Adapter
@@ -331,8 +332,9 @@
 
 	case e1000_82573:
 		if (pdev->device == E1000_DEV_ID_82573L) {
-			e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
-				       &eeprom_data);
+			if (e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
+				       &eeprom_data) < 0)
+				break;
 			if (eeprom_data & NVM_WORD1A_ASPM_MASK)
 				adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
 		}
@@ -973,6 +975,12 @@
 		ew32(CTRL_EXT, reg);
 	}
 
+	if (hw->mac.type == e1000_82571) {
+		reg = er32(PBA_ECC);
+		reg |= E1000_PBA_ECC_CORR_EN;
+		ew32(PBA_ECC, reg);
+	}
+
 	/* PCI-Ex Control Register */
 	if (hw->mac.type == e1000_82574) {
 		reg = er32(GCR);
@@ -1111,8 +1119,8 @@
 	 * set it to full.
 	 */
 	if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
-	    hw->fc.type == e1000_fc_default)
-		hw->fc.type = e1000_fc_full;
+	    hw->fc.requested_mode == e1000_fc_default)
+		hw->fc.requested_mode = e1000_fc_full;
 
 	return e1000e_setup_link(hw);
 }
@@ -1387,6 +1395,7 @@
 	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
 	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
 	.write_phy_reg		= e1000e_write_phy_reg_igp,
+	.cfg_on_link_up      	= NULL,
 };
 
 static struct e1000_phy_operations e82_phy_ops_m88 = {
@@ -1403,6 +1412,7 @@
 	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
 	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
 	.write_phy_reg		= e1000e_write_phy_reg_m88,
+	.cfg_on_link_up      	= NULL,
 };
 
 static struct e1000_phy_operations e82_phy_ops_bm = {
@@ -1419,6 +1429,7 @@
 	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
 	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
 	.write_phy_reg		= e1000e_write_phy_reg_bm2,
+	.cfg_on_link_up      	= NULL,
 };
 
 static struct e1000_nvm_operations e82571_nvm_ops = {
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index 48f79ec..e6caf29 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -372,6 +372,13 @@
 #define E1000_ICR_TXQ1          0x00800000 /* Tx Queue 1 Interrupt */
 #define E1000_ICR_OTHER         0x01000000 /* Other Interrupts */
 
+/* PBA ECC Register */
+#define E1000_PBA_ECC_COUNTER_MASK  0xFFF00000 /* ECC counter mask */
+#define E1000_PBA_ECC_COUNTER_SHIFT 20         /* ECC counter shift value */
+#define E1000_PBA_ECC_CORR_EN       0x00000001 /* ECC correction enable */
+#define E1000_PBA_ECC_STAT_CLR      0x00000002 /* Clear ECC error counter */
+#define E1000_PBA_ECC_INT_EN        0x00000004 /* Enable ICR bit 5 for ECC */
+
 /*
  * This defines the bits that are set in the Interrupt Mask
  * Set/Read Register.  Each bit is documented below:
@@ -565,6 +572,7 @@
 #define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
 #define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
 #define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
 
 #define E1000_NVM_RW_REG_DATA   16   /* Offset to data in NVM read/write registers */
 #define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index c55fd6f..37bcb19 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -193,6 +193,7 @@
 	u16 mng_vlan_id;
 	u16 link_speed;
 	u16 link_duplex;
+	u16 eeprom_vers;
 
 	spinlock_t tx_queue_lock; /* prevent concurrent tail updates */
 
@@ -388,6 +389,7 @@
 extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
 extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
 extern void e1000e_update_stats(struct e1000_adapter *adapter);
+extern bool e1000_has_link(struct e1000_adapter *adapter);
 extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
 extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
 
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
index da9c09c..8964838 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/e1000e/es2lan.c
@@ -112,6 +112,11 @@
 static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
 static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
 static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex);
+static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+                                            u16 *data);
+static s32  e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+                                             u16 data);
 
 /**
  *  e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs.
@@ -275,8 +280,6 @@
 	u16 mask;
 
 	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
-	mask |= E1000_SWFW_CSR_SM;
-
 	return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
 }
 
@@ -292,7 +295,36 @@
 	u16 mask;
 
 	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
-	mask |= E1000_SWFW_CSR_SM;
+	e1000_release_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ *  e1000_acquire_mac_csr_80003es2lan - Acquire rights to access Kumeran register
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the semaphore to access the Kumeran interface.
+ *
+ **/
+static s32 e1000_acquire_mac_csr_80003es2lan(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	mask = E1000_SWFW_CSR_SM;
+
+	return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ *  e1000_release_mac_csr_80003es2lan - Release rights to access Kumeran Register
+ *  @hw: pointer to the HW structure
+ *
+ *  Release the semaphore used to access the Kumeran interface
+ **/
+static void e1000_release_mac_csr_80003es2lan(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	mask = E1000_SWFW_CSR_SM;
 
 	e1000_release_swfw_sync_80003es2lan(hw, mask);
 }
@@ -347,7 +379,7 @@
 	u32 swmask = mask;
 	u32 fwmask = mask << 16;
 	s32 i = 0;
-	s32 timeout = 200;
+	s32 timeout = 50;
 
 	while (i < timeout) {
 		if (e1000e_get_hw_semaphore(hw))
@@ -715,13 +747,7 @@
 		ret_val = e1000e_get_speed_and_duplex_copper(hw,
 								    speed,
 								    duplex);
-		if (ret_val)
-			return ret_val;
-		if (*speed == SPEED_1000)
-			ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw);
-		else
-			ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw,
-							      *duplex);
+		hw->phy.ops.cfg_on_link_up(hw);
 	} else {
 		ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw,
 								  speed,
@@ -763,8 +789,10 @@
 
 	ctrl = er32(CTRL);
 
+	ret_val = e1000_acquire_phy_80003es2lan(hw);
 	hw_dbg(hw, "Issuing a global reset to MAC\n");
 	ew32(CTRL, ctrl | E1000_CTRL_RST);
+	e1000_release_phy_80003es2lan(hw);
 
 	ret_val = e1000e_get_auto_rd_done(hw);
 	if (ret_val)
@@ -907,8 +935,7 @@
 	struct e1000_phy_info *phy = &hw->phy;
 	s32 ret_val;
 	u32 ctrl_ext;
-	u32 i = 0;
-	u16 data, data2;
+	u16 data;
 
 	ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &data);
 	if (ret_val)
@@ -972,19 +999,20 @@
 	}
 
 	/* Bypass Rx and Tx FIFO's */
-	ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
+	ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+					E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
 					E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
 					E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
 	if (ret_val)
 		return ret_val;
 
-	ret_val = e1000e_read_kmrn_reg(hw,
+	ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
 				       E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
 				       &data);
 	if (ret_val)
 		return ret_val;
 	data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE;
-	ret_val = e1000e_write_kmrn_reg(hw,
+	ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
 					E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
 					data);
 	if (ret_val)
@@ -1019,18 +1047,9 @@
 		if (ret_val)
 			return ret_val;
 
-		do {
-			ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
-					   &data);
-			if (ret_val)
-				return ret_val;
-
-			ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
-					   &data2);
-			if (ret_val)
-				return ret_val;
-			i++;
-		} while ((data != data2) && (i < GG82563_MAX_KMRN_RETRY));
+		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data);
+		if (ret_val)
+			return ret_val;
 
 		data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
 		ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data);
@@ -1077,23 +1096,27 @@
 	 * iteration and increase the max iterations when
 	 * polling the phy; this fixes erroneous timeouts at 10Mbps.
 	 */
-	ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
+	ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4),
+	                                           0xFFFF);
 	if (ret_val)
 		return ret_val;
-	ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
+	ret_val = e1000_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
+	                                          &reg_data);
 	if (ret_val)
 		return ret_val;
 	reg_data |= 0x3F;
-	ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
+	ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
+	                                           reg_data);
 	if (ret_val)
 		return ret_val;
-	ret_val = e1000e_read_kmrn_reg(hw,
+	ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
 				      E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
 				      &reg_data);
 	if (ret_val)
 		return ret_val;
 	reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
-	ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+	ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+					E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
 					reg_data);
 	if (ret_val)
 		return ret_val;
@@ -1108,6 +1131,35 @@
 }
 
 /**
+ *  e1000_cfg_on_link_up_80003es2lan - es2 link configuration after link-up
+ *  @hw: pointer to the HW structure
+ *  @duplex: current duplex setting
+ *
+ *  Configure the KMRN interface by applying last minute quirks for
+ *  10/100 operation.
+ **/
+static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+	u16 speed;
+	u16 duplex;
+
+	if (hw->phy.media_type == e1000_media_type_copper) {
+		ret_val = e1000e_get_speed_and_duplex_copper(hw, &speed,
+		                                             &duplex);
+		if (ret_val)
+			return ret_val;
+
+		if (speed == SPEED_1000)
+			ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw);
+		else
+			ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, duplex);
+	}
+
+	return ret_val;
+}
+
+/**
  *  e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation
  *  @hw: pointer to the HW structure
  *  @duplex: current duplex setting
@@ -1123,8 +1175,9 @@
 	u16 reg_data, reg_data2;
 
 	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
-	ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
-					reg_data);
+	ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+	                               E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+	                               reg_data);
 	if (ret_val)
 		return ret_val;
 
@@ -1170,8 +1223,9 @@
 	u32 i = 0;
 
 	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
-	ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
-					reg_data);
+	ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+	                               E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+	                               reg_data);
 	if (ret_val)
 		return ret_val;
 
@@ -1199,6 +1253,71 @@
 }
 
 /**
+ *  e1000_read_kmrn_reg_80003es2lan - Read kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquire semaphore, then read the PHY register at offset
+ *  using the kumeran interface.  The information retrieved is stored in data.
+ *  Release the semaphore before exiting.
+ **/
+static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+					   u16 *data)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = 0;
+
+	ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
+	if (ret_val)
+		return ret_val;
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+	ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+	udelay(2);
+
+	kmrnctrlsta = er32(KMRNCTRLSTA);
+	*data = (u16)kmrnctrlsta;
+
+	e1000_release_mac_csr_80003es2lan(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_write_kmrn_reg_80003es2lan - Write kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquire semaphore, then write the data to PHY register
+ *  at the offset using the kumeran interface.  Release semaphore
+ *  before exiting.
+ **/
+static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+					    u16 data)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = 0;
+
+	ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
+	if (ret_val)
+		return ret_val;
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | data;
+	ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+	udelay(2);
+
+	e1000_release_mac_csr_80003es2lan(hw);
+
+	return ret_val;
+}
+
+/**
  *  e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters
  *  @hw: pointer to the HW structure
  *
@@ -1276,6 +1395,7 @@
 	.set_d0_lplu_state  	= NULL,
 	.set_d3_lplu_state  	= e1000e_set_d3_lplu_state,
 	.write_phy_reg      	= e1000_write_phy_reg_gg82563_80003es2lan,
+	.cfg_on_link_up      	= e1000_cfg_on_link_up_80003es2lan,
 };
 
 static struct e1000_nvm_operations es2_nvm_ops = {
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 62421ce..e48956d 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -173,11 +173,8 @@
 static u32 e1000_get_link(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
-	struct e1000_hw *hw = &adapter->hw;
-	u32 status;
-	
-	status = er32(STATUS);
-	return (status & E1000_STATUS_LU) ? 1 : 0;
+
+	return e1000_has_link(adapter);
 }
 
 static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
@@ -249,7 +246,7 @@
 						     ADVERTISED_Autoneg;
 		ecmd->advertising = hw->phy.autoneg_advertised;
 		if (adapter->fc_autoneg)
-			hw->fc.original_type = e1000_fc_default;
+			hw->fc.requested_mode = e1000_fc_default;
 	} else {
 		if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
 			clear_bit(__E1000_RESETTING, &adapter->state);
@@ -279,11 +276,11 @@
 	pause->autoneg =
 		(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
 
-	if (hw->fc.type == e1000_fc_rx_pause) {
+	if (hw->fc.current_mode == e1000_fc_rx_pause) {
 		pause->rx_pause = 1;
-	} else if (hw->fc.type == e1000_fc_tx_pause) {
+	} else if (hw->fc.current_mode == e1000_fc_tx_pause) {
 		pause->tx_pause = 1;
-	} else if (hw->fc.type == e1000_fc_full) {
+	} else if (hw->fc.current_mode == e1000_fc_full) {
 		pause->rx_pause = 1;
 		pause->tx_pause = 1;
 	}
@@ -301,19 +298,8 @@
 	while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
 		msleep(1);
 
-	if (pause->rx_pause && pause->tx_pause)
-		hw->fc.type = e1000_fc_full;
-	else if (pause->rx_pause && !pause->tx_pause)
-		hw->fc.type = e1000_fc_rx_pause;
-	else if (!pause->rx_pause && pause->tx_pause)
-		hw->fc.type = e1000_fc_tx_pause;
-	else if (!pause->rx_pause && !pause->tx_pause)
-		hw->fc.type = e1000_fc_none;
-
-	hw->fc.original_type = hw->fc.type;
-
 	if (adapter->fc_autoneg == AUTONEG_ENABLE) {
-		hw->fc.type = e1000_fc_default;
+		hw->fc.requested_mode = e1000_fc_default;
 		if (netif_running(adapter->netdev)) {
 			e1000e_down(adapter);
 			e1000e_up(adapter);
@@ -321,6 +307,17 @@
 			e1000e_reset(adapter);
 		}
 	} else {
+		if (pause->rx_pause && pause->tx_pause)
+			hw->fc.requested_mode = e1000_fc_full;
+		else if (pause->rx_pause && !pause->tx_pause)
+			hw->fc.requested_mode = e1000_fc_rx_pause;
+		else if (!pause->rx_pause && pause->tx_pause)
+			hw->fc.requested_mode = e1000_fc_tx_pause;
+		else if (!pause->rx_pause && !pause->tx_pause)
+			hw->fc.requested_mode = e1000_fc_none;
+
+		hw->fc.current_mode = hw->fc.requested_mode;
+
 		retval = ((hw->phy.media_type == e1000_media_type_fiber) ?
 			  hw->mac.ops.setup_link(hw) : e1000e_force_mac_fc(hw));
 	}
@@ -495,18 +492,19 @@
 		for (i = 0; i < last_word - first_word + 1; i++) {
 			ret_val = e1000_read_nvm(hw, first_word + i, 1,
 						      &eeprom_buff[i]);
-			if (ret_val) {
-				/* a read error occurred, throw away the
-				 * result */
-				memset(eeprom_buff, 0xff, sizeof(eeprom_buff));
+			if (ret_val)
 				break;
-			}
 		}
 	}
 
-	/* Device's eeprom is always little-endian, word addressable */
-	for (i = 0; i < last_word - first_word + 1; i++)
-		le16_to_cpus(&eeprom_buff[i]);
+	if (ret_val) {
+		/* a read error occurred, throw away the result */
+		memset(eeprom_buff, 0xff, sizeof(eeprom_buff));
+	} else {
+		/* Device's eeprom is always little-endian, word addressable */
+		for (i = 0; i < last_word - first_word + 1; i++)
+			le16_to_cpus(&eeprom_buff[i]);
+	}
 
 	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
 	kfree(eeprom_buff);
@@ -558,6 +556,9 @@
 		ret_val = e1000_read_nvm(hw, last_word, 1,
 				  &eeprom_buff[last_word - first_word]);
 
+	if (ret_val)
+		goto out;
+
 	/* Device's eeprom is always little-endian, word addressable */
 	for (i = 0; i < last_word - first_word + 1; i++)
 		le16_to_cpus(&eeprom_buff[i]);
@@ -570,15 +571,18 @@
 	ret_val = e1000_write_nvm(hw, first_word,
 				  last_word - first_word + 1, eeprom_buff);
 
+	if (ret_val)
+		goto out;
+
 	/*
 	 * Update the checksum over the first part of the EEPROM if needed
-	 * and flush shadow RAM for 82573 controllers
+	 * and flush shadow RAM for applicable controllers
 	 */
-	if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) ||
-			       (hw->mac.type == e1000_82574) ||
-			       (hw->mac.type == e1000_82573)))
-		e1000e_update_nvm_checksum(hw);
+	if ((first_word <= NVM_CHECKSUM_REG) ||
+	    (hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82573))
+		ret_val = e1000e_update_nvm_checksum(hw);
 
+out:
 	kfree(eeprom_buff);
 	return ret_val;
 }
@@ -588,7 +592,6 @@
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	char firmware_version[32];
-	u16 eeprom_data;
 
 	strncpy(drvinfo->driver,  e1000e_driver_name, 32);
 	strncpy(drvinfo->version, e1000e_driver_version, 32);
@@ -597,11 +600,10 @@
 	 * EEPROM image version # is reported as firmware version # for
 	 * PCI-E controllers
 	 */
-	e1000_read_nvm(&adapter->hw, 5, 1, &eeprom_data);
 	sprintf(firmware_version, "%d.%d-%d",
-		(eeprom_data & 0xF000) >> 12,
-		(eeprom_data & 0x0FF0) >> 4,
-		eeprom_data & 0x000F);
+		(adapter->eeprom_vers & 0xF000) >> 12,
+		(adapter->eeprom_vers & 0x0FF0) >> 4,
+		(adapter->eeprom_vers & 0x000F));
 
 	strncpy(drvinfo->fw_version, firmware_version, 32);
 	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
@@ -865,7 +867,7 @@
 	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
 		if ((e1000_read_nvm(&adapter->hw, i, 1, &temp)) < 0) {
 			*data = 1;
-			break;
+			return *data;
 		}
 		checksum += temp;
 	}
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index f66ed37..f25e961 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -87,6 +87,7 @@
 	E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */
 	E1000_EEWR     = 0x0102C, /* EEPROM Write Register - RW */
 	E1000_FLOP     = 0x0103C, /* FLASH Opcode Register */
+	E1000_PBA_ECC  = 0x01100, /* PBA ECC Register */
 	E1000_ERT      = 0x02008, /* Early Rx Threshold - RW */
 	E1000_FCRTL    = 0x02160, /* Flow Control Receive Threshold Low - RW */
 	E1000_FCRTH    = 0x02168, /* Flow Control Receive Threshold High - RW */
@@ -436,7 +437,7 @@
 	e1000_rev_polarity_undefined = 0xFF
 };
 
-enum e1000_fc_type {
+enum e1000_fc_mode {
 	e1000_fc_none = 0,
 	e1000_fc_rx_pause,
 	e1000_fc_tx_pause,
@@ -738,6 +739,7 @@
 	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
 	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
 	s32  (*write_phy_reg)(struct e1000_hw *, u32, u16);
+	s32  (*cfg_on_link_up)(struct e1000_hw *);
 };
 
 /* Function pointers for the NVM. */
@@ -848,8 +850,8 @@
 	u16 pause_time;          /* Flow control pause timer */
 	bool send_xon;           /* Flow control send XON */
 	bool strict_ieee;        /* Strict IEEE mode */
-	enum e1000_fc_type type; /* Type of flow control */
-	enum e1000_fc_type original_type;
+	enum e1000_fc_mode current_mode; /* FC mode in effect */
+	enum e1000_fc_mode requested_mode; /* FC mode requested by caller */
 };
 
 struct e1000_dev_spec_82571 {
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index d115a6d..f2a5963 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -27,6 +27,7 @@
 *******************************************************************************/
 
 /*
+ * 82562G 10/100 Network Connection
  * 82562G-2 10/100 Network Connection
  * 82562GT 10/100 Network Connection
  * 82562GT-2 10/100 Network Connection
@@ -40,6 +41,7 @@
  * 82566MM Gigabit Network Connection
  * 82567LM Gigabit Network Connection
  * 82567LF Gigabit Network Connection
+ * 82567V Gigabit Network Connection
  * 82567LM-2 Gigabit Network Connection
  * 82567LF-2 Gigabit Network Connection
  * 82567V-2 Gigabit Network Connection
@@ -92,6 +94,8 @@
 
 #define E1000_ICH_NVM_SIG_WORD		0x13
 #define E1000_ICH_NVM_SIG_MASK		0xC000
+#define E1000_ICH_NVM_VALID_SIG_MASK    0xC0
+#define E1000_ICH_NVM_SIG_VALUE         0x80
 
 #define E1000_ICH8_LAN_INIT_TIMEOUT	1500
 
@@ -956,45 +960,62 @@
  *  @bank:  pointer to the variable that returns the active bank
  *
  *  Reads signature byte from the NVM using the flash access registers.
+ *  Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
  **/
 static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
 {
+	u32 eecd;
 	struct e1000_nvm_info *nvm = &hw->nvm;
-	/* flash bank size is in words */
 	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
 	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
-	u8 bank_high_byte = 0;
+	u8 sig_byte = 0;
+	s32 ret_val = 0;
 
-	if (hw->mac.type != e1000_ich10lan) {
-		if (er32(EECD) & E1000_EECD_SEC1VAL)
-			*bank = 1;
-		else
-			*bank = 0;
-	} else {
-		/*
-		 * Make sure the signature for bank 0 is valid,
-		 * if not check for bank1
-		 */
-		e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte);
-		if ((bank_high_byte & 0xC0) == 0x80) {
-			*bank = 0;
-		} else {
-			/*
-			 * find if segment 1 is valid by verifying
-			 * bit 15:14 = 10b in word 0x13
-			 */
-			e1000_read_flash_byte_ich8lan(hw,
-						      act_offset + bank1_offset,
-						      &bank_high_byte);
-
-			/* bank1 has a valid signature equivalent to SEC1V */
-			if ((bank_high_byte & 0xC0) == 0x80) {
+	switch (hw->mac.type) {
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+		eecd = er32(EECD);
+		if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
+		    E1000_EECD_SEC1VAL_VALID_MASK) {
+			if (eecd & E1000_EECD_SEC1VAL)
 				*bank = 1;
-			} else {
-				hw_dbg(hw, "ERROR: EEPROM not present\n");
-				return -E1000_ERR_NVM;
-			}
+			else
+				*bank = 0;
+
+			return 0;
 		}
+		hw_dbg(hw, "Unable to determine valid NVM bank via EEC - "
+		       "reading flash signature\n");
+		/* fall-thru */
+	default:
+		/* set bank to 0 in case flash read fails */
+		*bank = 0;
+
+		/* Check bank 0 */
+		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
+		                                        &sig_byte);
+		if (ret_val)
+			return ret_val;
+		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+		    E1000_ICH_NVM_SIG_VALUE) {
+			*bank = 0;
+			return 0;
+		}
+
+		/* Check bank 1 */
+		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
+		                                        bank1_offset,
+		                                        &sig_byte);
+		if (ret_val)
+			return ret_val;
+		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
+		    E1000_ICH_NVM_SIG_VALUE) {
+			*bank = 1;
+			return 0;
+		}
+
+		hw_dbg(hw, "ERROR: No valid NVM bank present\n");
+		return -E1000_ERR_NVM;
 	}
 
 	return 0;
@@ -1027,11 +1048,11 @@
 
 	ret_val = e1000_acquire_swflag_ich8lan(hw);
 	if (ret_val)
-		return ret_val;
+		goto out;
 
 	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
 	if (ret_val)
-		return ret_val;
+		goto release;
 
 	act_offset = (bank) ? nvm->flash_bank_size : 0;
 	act_offset += offset;
@@ -1050,8 +1071,13 @@
 		}
 	}
 
+release:
 	e1000_release_swflag_ich8lan(hw);
 
+out:
+	if (ret_val)
+		hw_dbg(hw, "NVM read error: %d\n", ret_val);
+
 	return ret_val;
 }
 
@@ -1340,14 +1366,14 @@
 
 	ret_val = e1000e_update_nvm_checksum_generic(hw);
 	if (ret_val)
-		return ret_val;
+		goto out;
 
 	if (nvm->type != e1000_nvm_flash_sw)
-		return ret_val;
+		goto out;
 
 	ret_val = e1000_acquire_swflag_ich8lan(hw);
 	if (ret_val)
-		return ret_val;
+		goto out;
 
 	/*
 	 * We're writing to the opposite bank so if we're on bank 1,
@@ -1355,17 +1381,27 @@
 	 * is going to be written
 	 */
 	ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
-	if (ret_val)
-		return ret_val;
+	if (ret_val) {
+		e1000_release_swflag_ich8lan(hw);
+		goto out;
+	}
 
 	if (bank == 0) {
 		new_bank_offset = nvm->flash_bank_size;
 		old_bank_offset = 0;
-		e1000_erase_flash_bank_ich8lan(hw, 1);
+		ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
+		if (ret_val) {
+			e1000_release_swflag_ich8lan(hw);
+			goto out;
+		}
 	} else {
 		old_bank_offset = nvm->flash_bank_size;
 		new_bank_offset = 0;
-		e1000_erase_flash_bank_ich8lan(hw, 0);
+		ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
+		if (ret_val) {
+			e1000_release_swflag_ich8lan(hw);
+			goto out;
+		}
 	}
 
 	for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
@@ -1377,9 +1413,11 @@
 		if (dev_spec->shadow_ram[i].modified) {
 			data = dev_spec->shadow_ram[i].value;
 		} else {
-			e1000_read_flash_word_ich8lan(hw,
-						      i + old_bank_offset,
-						      &data);
+			ret_val = e1000_read_flash_word_ich8lan(hw, i +
+			                                        old_bank_offset,
+			                                        &data);
+			if (ret_val)
+				break;
 		}
 
 		/*
@@ -1420,7 +1458,7 @@
 		/* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
 		hw_dbg(hw, "Flash commit failed.\n");
 		e1000_release_swflag_ich8lan(hw);
-		return ret_val;
+		goto out;
 	}
 
 	/*
@@ -1430,14 +1468,18 @@
 	 * and we need to change bit 14 to 0b
 	 */
 	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
-	e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+	ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+	if (ret_val) {
+		e1000_release_swflag_ich8lan(hw);
+		goto out;
+	}
 	data &= 0xBFFF;
 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
 						       act_offset * 2 + 1,
 						       (u8)(data >> 8));
 	if (ret_val) {
 		e1000_release_swflag_ich8lan(hw);
-		return ret_val;
+		goto out;
 	}
 
 	/*
@@ -1450,7 +1492,7 @@
 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
 	if (ret_val) {
 		e1000_release_swflag_ich8lan(hw);
-		return ret_val;
+		goto out;
 	}
 
 	/* Great!  Everything worked, we can now clear the cached entries. */
@@ -1468,6 +1510,10 @@
 	e1000e_reload_nvm(hw);
 	msleep(10);
 
+out:
+	if (ret_val)
+		hw_dbg(hw, "NVM update error: %d\n", ret_val);
+
 	return ret_val;
 }
 
@@ -1894,7 +1940,7 @@
 	}
 	ret_val = e1000_acquire_swflag_ich8lan(hw);
 	/* Whether or not the swflag was acquired, we need to reset the part */
-	hw_dbg(hw, "Issuing a global reset to ich8lan");
+	hw_dbg(hw, "Issuing a global reset to ich8lan\n");
 	ew32(CTRL, (ctrl | E1000_CTRL_RST));
 	msleep(20);
 
@@ -2074,12 +2120,17 @@
 	 * the default flow control setting, so we explicitly
 	 * set it to full.
 	 */
-	if (hw->fc.type == e1000_fc_default)
-		hw->fc.type = e1000_fc_full;
+	if (hw->fc.requested_mode == e1000_fc_default)
+		hw->fc.requested_mode = e1000_fc_full;
 
-	hw->fc.original_type = hw->fc.type;
+	/*
+	 * Save off the requested flow control mode for use later.  Depending
+	 * on the link partner's capabilities, we may or may not use this mode.
+	 */
+	hw->fc.current_mode = hw->fc.requested_mode;
 
-	hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type);
+	hw_dbg(hw, "After fix-ups FlowControl is now = %x\n",
+		hw->fc.current_mode);
 
 	/* Continue to configure the copper link. */
 	ret_val = e1000_setup_copper_link_ich8lan(hw);
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index 089578f..6674110 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -575,20 +575,42 @@
 		 */
 		/* SYNCH bit and IV bit are sticky. */
 		udelay(10);
-		if (E1000_RXCW_SYNCH & er32(RXCW)) {
+		rxcw = er32(RXCW);
+		if (rxcw & E1000_RXCW_SYNCH) {
 			if (!(rxcw & E1000_RXCW_IV)) {
-				mac->serdes_has_link = 1;
-				hw_dbg(hw, "SERDES: Link is up.\n");
+				mac->serdes_has_link = true;
+				hw_dbg(hw, "SERDES: Link up - forced.\n");
 			}
 		} else {
-			mac->serdes_has_link = 0;
-			hw_dbg(hw, "SERDES: Link is down.\n");
+			mac->serdes_has_link = false;
+			hw_dbg(hw, "SERDES: Link down - force failed.\n");
 		}
 	}
 
 	if (E1000_TXCW_ANE & er32(TXCW)) {
 		status = er32(STATUS);
-		mac->serdes_has_link = (status & E1000_STATUS_LU);
+		if (status & E1000_STATUS_LU) {
+			/* SYNCH bit and IV bit are sticky, so reread rxcw.  */
+			udelay(10);
+			rxcw = er32(RXCW);
+			if (rxcw & E1000_RXCW_SYNCH) {
+				if (!(rxcw & E1000_RXCW_IV)) {
+					mac->serdes_has_link = true;
+					hw_dbg(hw, "SERDES: Link up - autoneg "
+					   "completed sucessfully.\n");
+				} else {
+					mac->serdes_has_link = false;
+					hw_dbg(hw, "SERDES: Link down - invalid"
+					   "codewords detected in autoneg.\n");
+				}
+			} else {
+				mac->serdes_has_link = false;
+				hw_dbg(hw, "SERDES: Link down - no sync.\n");
+			}
+		} else {
+			mac->serdes_has_link = false;
+			hw_dbg(hw, "SERDES: Link down - autoneg failed\n");
+		}
 	}
 
 	return 0;
@@ -623,12 +645,12 @@
 	}
 
 	if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
-		hw->fc.type = e1000_fc_none;
+		hw->fc.requested_mode = e1000_fc_none;
 	else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
 		 NVM_WORD0F_ASM_DIR)
-		hw->fc.type = e1000_fc_tx_pause;
+		hw->fc.requested_mode = e1000_fc_tx_pause;
 	else
-		hw->fc.type = e1000_fc_full;
+		hw->fc.requested_mode = e1000_fc_full;
 
 	return 0;
 }
@@ -656,23 +678,23 @@
 		return 0;
 
 	/*
-	 * If flow control is set to default, set flow control based on
-	 * the EEPROM flow control settings.
+	 * If requested flow control is set to default, set flow control
+	 * based on the EEPROM flow control settings.
 	 */
-	if (hw->fc.type == e1000_fc_default) {
+	if (hw->fc.requested_mode == e1000_fc_default) {
 		ret_val = e1000_set_default_fc_generic(hw);
 		if (ret_val)
 			return ret_val;
 	}
 
 	/*
-	 * We want to save off the original Flow Control configuration just
-	 * in case we get disconnected and then reconnected into a different
-	 * hub or switch with different Flow Control capabilities.
+	 * Save off the requested flow control mode for use later.  Depending
+	 * on the link partner's capabilities, we may or may not use this mode.
 	 */
-	hw->fc.original_type = hw->fc.type;
+	hw->fc.current_mode = hw->fc.requested_mode;
 
-	hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type);
+	hw_dbg(hw, "After fix-ups FlowControl is now = %x\n",
+		hw->fc.current_mode);
 
 	/* Call the necessary media_type subroutine to configure the link. */
 	ret_val = mac->ops.setup_physical_interface(hw);
@@ -724,7 +746,7 @@
 	 *	  do not support receiving pause frames).
 	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
 	 */
-	switch (hw->fc.type) {
+	switch (hw->fc.current_mode) {
 	case e1000_fc_none:
 		/* Flow control completely disabled by a software over-ride. */
 		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
@@ -906,7 +928,7 @@
 	 * ability to transmit pause frames is not enabled, then these
 	 * registers will be set to 0.
 	 */
-	if (hw->fc.type & e1000_fc_tx_pause) {
+	if (hw->fc.current_mode & e1000_fc_tx_pause) {
 		/*
 		 * We need to set up the Receive Threshold high and low water
 		 * marks as well as (optionally) enabling the transmission of
@@ -945,7 +967,7 @@
 	 * receive flow control.
 	 *
 	 * The "Case" statement below enables/disable flow control
-	 * according to the "hw->fc.type" parameter.
+	 * according to the "hw->fc.current_mode" parameter.
 	 *
 	 * The possible values of the "fc" parameter are:
 	 *      0:  Flow control is completely disabled
@@ -956,9 +978,9 @@
 	 *      3:  Both Rx and Tx flow control (symmetric) is enabled.
 	 *  other:  No other values should be possible at this point.
 	 */
-	hw_dbg(hw, "hw->fc.type = %u\n", hw->fc.type);
+	hw_dbg(hw, "hw->fc.current_mode = %u\n", hw->fc.current_mode);
 
-	switch (hw->fc.type) {
+	switch (hw->fc.current_mode) {
 	case e1000_fc_none:
 		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
 		break;
@@ -1102,11 +1124,11 @@
 			 * ONLY. Hence, we must now check to see if we need to
 			 * turn OFF  the TRANSMISSION of PAUSE frames.
 			 */
-			if (hw->fc.original_type == e1000_fc_full) {
-				hw->fc.type = e1000_fc_full;
+			if (hw->fc.requested_mode == e1000_fc_full) {
+				hw->fc.current_mode = e1000_fc_full;
 				hw_dbg(hw, "Flow Control = FULL.\r\n");
 			} else {
-				hw->fc.type = e1000_fc_rx_pause;
+				hw->fc.current_mode = e1000_fc_rx_pause;
 				hw_dbg(hw, "Flow Control = "
 					 "RX PAUSE frames only.\r\n");
 			}
@@ -1124,7 +1146,7 @@
 			  (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
 			  (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
 			  (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-			hw->fc.type = e1000_fc_tx_pause;
+			hw->fc.current_mode = e1000_fc_tx_pause;
 			hw_dbg(hw, "Flow Control = Tx PAUSE frames only.\r\n");
 		}
 		/*
@@ -1140,14 +1162,14 @@
 			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
 			 !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
 			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-			hw->fc.type = e1000_fc_rx_pause;
+			hw->fc.current_mode = e1000_fc_rx_pause;
 			hw_dbg(hw, "Flow Control = Rx PAUSE frames only.\r\n");
 		} else {
 			/*
 			 * Per the IEEE spec, at this point flow control
 			 * should be disabled.
 			 */
-			hw->fc.type = e1000_fc_none;
+			hw->fc.current_mode = e1000_fc_none;
 			hw_dbg(hw, "Flow Control = NONE.\r\n");
 		}
 
@@ -1163,7 +1185,7 @@
 		}
 
 		if (duplex == HALF_DUPLEX)
-			hw->fc.type = e1000_fc_none;
+			hw->fc.current_mode = e1000_fc_none;
 
 		/*
 		 * Now we call a subroutine to actually force the MAC
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 122539a..d4639fa 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -102,9 +102,7 @@
 		vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
 					 le16_to_cpu(vlan));
 	else
-		netif_receive_skb(skb);
-
-	netdev->last_rx = jiffies;
+		napi_gro_receive(&adapter->napi, skb);
 }
 
 /**
@@ -1181,12 +1179,12 @@
 			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
-	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+	if (netif_rx_schedule_prep(&adapter->napi)) {
 		adapter->total_tx_bytes = 0;
 		adapter->total_tx_packets = 0;
 		adapter->total_rx_bytes = 0;
 		adapter->total_rx_packets = 0;
-		__netif_rx_schedule(netdev, &adapter->napi);
+		__netif_rx_schedule(&adapter->napi);
 	}
 
 	return IRQ_HANDLED;
@@ -1248,12 +1246,12 @@
 			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
-	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+	if (netif_rx_schedule_prep(&adapter->napi)) {
 		adapter->total_tx_bytes = 0;
 		adapter->total_tx_packets = 0;
 		adapter->total_rx_bytes = 0;
 		adapter->total_rx_packets = 0;
-		__netif_rx_schedule(netdev, &adapter->napi);
+		__netif_rx_schedule(&adapter->napi);
 	}
 
 	return IRQ_HANDLED;
@@ -1322,10 +1320,10 @@
 		adapter->rx_ring->set_itr = 0;
 	}
 
-	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+	if (netif_rx_schedule_prep(&adapter->napi)) {
 		adapter->total_rx_bytes = 0;
 		adapter->total_rx_packets = 0;
-		__netif_rx_schedule(netdev, &adapter->napi);
+		__netif_rx_schedule(&adapter->napi);
 	}
 	return IRQ_HANDLED;
 }
@@ -1480,7 +1478,7 @@
 	int err = 0, vector = 0;
 
 	if (strlen(netdev->name) < (IFNAMSIZ - 5))
-		sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name);
+		sprintf(adapter->rx_ring->name, "%s-rx-0", netdev->name);
 	else
 		memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ);
 	err = request_irq(adapter->msix_entries[vector].vector,
@@ -1493,7 +1491,7 @@
 	vector++;
 
 	if (strlen(netdev->name) < (IFNAMSIZ - 5))
-		sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name);
+		sprintf(adapter->tx_ring->name, "%s-tx-0", netdev->name);
 	else
 		memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ);
 	err = request_irq(adapter->msix_entries[vector].vector,
@@ -2003,8 +2001,7 @@
 	struct net_device *poll_dev = adapter->netdev;
 	int tx_cleaned = 0, work_done = 0;
 
-	/* Must NOT use netdev_priv macro here. */
-	adapter = poll_dev->priv;
+	adapter = netdev_priv(poll_dev);
 
 	if (adapter->msix_entries &&
 	    !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val))
@@ -2031,7 +2028,7 @@
 	if (work_done < budget) {
 		if (adapter->itr_setting & 3)
 			e1000_set_itr(adapter);
-		netif_rx_complete(poll_dev, napi);
+		netif_rx_complete(napi);
 		if (adapter->msix_entries)
 			ew32(IMS, adapter->rx_ring->ims_val);
 		else
@@ -2787,7 +2784,7 @@
 	else
 		fc->pause_time = E1000_FC_PAUSE_TIME;
 	fc->send_xon = 1;
-	fc->type = fc->original_type;
+	fc->current_mode = fc->requested_mode;
 
 	/* Allow time for pending master requests to run */
 	mac->ops.reset_hw(hw);
@@ -3410,7 +3407,10 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 ctrl = er32(CTRL);
 
-	e_info("Link is Up %d Mbps %s, Flow Control: %s\n",
+	/* Link status message must follow this format for user tools */
+	printk(KERN_INFO "e1000e: %s NIC Link is Up %d Mbps %s, "
+	       "Flow Control: %s\n",
+	       adapter->netdev->name,
 	       adapter->link_speed,
 	       (adapter->link_duplex == FULL_DUPLEX) ?
 	                        "Full Duplex" : "Half Duplex",
@@ -3420,7 +3420,7 @@
 	       ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" )));
 }
 
-static bool e1000_has_link(struct e1000_adapter *adapter)
+bool e1000_has_link(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
 	bool link_active = 0;
@@ -3495,6 +3495,7 @@
 					struct e1000_adapter, watchdog_task);
 	struct net_device *netdev = adapter->netdev;
 	struct e1000_mac_info *mac = &adapter->hw.mac;
+	struct e1000_phy_info *phy = &adapter->hw.phy;
 	struct e1000_ring *tx_ring = adapter->tx_ring;
 	struct e1000_hw *hw = &adapter->hw;
 	u32 link, tctl;
@@ -3601,6 +3602,13 @@
 			tctl |= E1000_TCTL_EN;
 			ew32(TCTL, tctl);
 
+                        /*
+			 * Perform any post-link-up configuration before
+			 * reporting link up.
+			 */
+			if (phy->ops.cfg_on_link_up)
+				phy->ops.cfg_on_link_up(hw);
+
 			netif_carrier_on(netdev);
 			netif_tx_wake_all_queues(netdev);
 
@@ -3612,7 +3620,9 @@
 		if (netif_carrier_ok(netdev)) {
 			adapter->link_speed = 0;
 			adapter->link_duplex = 0;
-			e_info("Link is Down\n");
+			/* Link status message must follow this format */
+			printk(KERN_INFO "e1000e: %s NIC Link is Down\n",
+			       adapter->netdev->name);
 			netif_carrier_off(netdev);
 			netif_tx_stop_all_queues(netdev);
 			if (!test_bit(__E1000_DOWN, &adapter->state))
@@ -4464,7 +4474,27 @@
 
 	pci_disable_device(pdev);
 
-	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+	/*
+	 * The pci-e switch on some quad port adapters will report a
+	 * correctable error when the MAC transitions from D0 to D3.  To
+	 * prevent this we need to mask off the correctable errors on the
+	 * downstream port of the pci-e switch.
+	 */
+	if (adapter->flags & FLAG_IS_QUAD_PORT) {
+		struct pci_dev *us_dev = pdev->bus->self;
+		int pos = pci_find_capability(us_dev, PCI_CAP_ID_EXP);
+		u16 devctl;
+
+		pci_read_config_word(us_dev, pos + PCI_EXP_DEVCTL, &devctl);
+		pci_write_config_word(us_dev, pos + PCI_EXP_DEVCTL,
+		                      (devctl & ~PCI_EXP_DEVCTL_CERE));
+
+		pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+		pci_write_config_word(us_dev, pos + PCI_EXP_DEVCTL, devctl);
+	} else {
+		pci_set_power_state(pdev, pci_choose_state(pdev, state));
+	}
 
 	return 0;
 }
@@ -4669,14 +4699,12 @@
 	u32 pba_num;
 
 	/* print bus type/speed/width info */
-	e_info("(PCI Express:2.5GB/s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n",
+	e_info("(PCI Express:2.5GB/s:%s) %pM\n",
 	       /* bus width */
 	       ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" :
 	        "Width x1"),
 	       /* MAC address */
-	       netdev->dev_addr[0], netdev->dev_addr[1],
-	       netdev->dev_addr[2], netdev->dev_addr[3],
-	       netdev->dev_addr[4], netdev->dev_addr[5]);
+	       netdev->dev_addr);
 	e_info("Intel(R) PRO/%s Network Connection\n",
 	       (hw->phy.type == e1000_phy_ife) ? "10/100" : "1000");
 	e1000e_read_pba_num(hw, &pba_num);
@@ -4694,20 +4722,40 @@
 		return;
 
 	ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &buf);
-	if (!(le16_to_cpu(buf) & (1 << 0))) {
+	if (!ret_val && (!(le16_to_cpu(buf) & (1 << 0)))) {
 		/* Deep Smart Power Down (DSPD) */
 		dev_warn(&adapter->pdev->dev,
 			 "Warning: detected DSPD enabled in EEPROM\n");
 	}
 
 	ret_val = e1000_read_nvm(hw, NVM_INIT_3GIO_3, 1, &buf);
-	if (le16_to_cpu(buf) & (3 << 2)) {
+	if (!ret_val && (le16_to_cpu(buf) & (3 << 2))) {
 		/* ASPM enable */
 		dev_warn(&adapter->pdev->dev,
 			 "Warning: detected ASPM enabled in EEPROM\n");
 	}
 }
 
+static const struct net_device_ops e1000e_netdev_ops = {
+	.ndo_open		= e1000_open,
+	.ndo_stop		= e1000_close,
+	.ndo_start_xmit		= e1000_xmit_frame,
+	.ndo_get_stats		= e1000_get_stats,
+	.ndo_set_multicast_list	= e1000_set_multi,
+	.ndo_set_mac_address	= e1000_set_mac,
+	.ndo_change_mtu		= e1000_change_mtu,
+	.ndo_do_ioctl		= e1000_ioctl,
+	.ndo_tx_timeout		= e1000_tx_timeout,
+	.ndo_validate_addr	= eth_validate_addr,
+
+	.ndo_vlan_rx_register	= e1000_vlan_rx_register,
+	.ndo_vlan_rx_add_vid	= e1000_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= e1000_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= e1000_netpoll,
+#endif
+};
+
 /**
  * e1000_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -4766,7 +4814,10 @@
 		goto err_pci_reg;
 
 	pci_set_master(pdev);
-	pci_save_state(pdev);
+	/* PCI config space info */
+	err = pci_save_state(pdev);
+	if (err)
+		goto err_alloc_etherdev;
 
 	err = -ENOMEM;
 	netdev = alloc_etherdev(sizeof(struct e1000_adapter));
@@ -4806,24 +4857,10 @@
 	}
 
 	/* construct the net_device struct */
-	netdev->open			= &e1000_open;
-	netdev->stop			= &e1000_close;
-	netdev->hard_start_xmit		= &e1000_xmit_frame;
-	netdev->get_stats		= &e1000_get_stats;
-	netdev->set_multicast_list	= &e1000_set_multi;
-	netdev->set_mac_address		= &e1000_set_mac;
-	netdev->change_mtu		= &e1000_change_mtu;
-	netdev->do_ioctl		= &e1000_ioctl;
+	netdev->netdev_ops		= &e1000e_netdev_ops;
 	e1000e_set_ethtool_ops(netdev);
-	netdev->tx_timeout		= &e1000_tx_timeout;
 	netdev->watchdog_timeo		= 5 * HZ;
 	netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
-	netdev->vlan_rx_register	= e1000_vlan_rx_register;
-	netdev->vlan_rx_add_vid		= e1000_vlan_rx_add_vid;
-	netdev->vlan_rx_kill_vid	= e1000_vlan_rx_kill_vid;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	netdev->poll_controller		= e1000_netpoll;
-#endif
 	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
 
 	netdev->mem_start = mmio_start;
@@ -4924,10 +4961,7 @@
 	memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
 
 	if (!is_valid_ether_addr(netdev->perm_addr)) {
-		e_err("Invalid MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-		      netdev->perm_addr[0], netdev->perm_addr[1],
-		      netdev->perm_addr[2], netdev->perm_addr[3],
-		      netdev->perm_addr[4], netdev->perm_addr[5]);
+		e_err("Invalid MAC Address: %pM\n", netdev->perm_addr);
 		err = -EIO;
 		goto err_eeprom;
 	}
@@ -4948,8 +4982,8 @@
 	/* Initialize link parameters. User can change them with ethtool */
 	adapter->hw.mac.autoneg = 1;
 	adapter->fc_autoneg = 1;
-	adapter->hw.fc.original_type = e1000_fc_default;
-	adapter->hw.fc.type = e1000_fc_default;
+	adapter->hw.fc.requested_mode = e1000_fc_default;
+	adapter->hw.fc.current_mode = e1000_fc_default;
 	adapter->hw.phy.autoneg_advertised = 0x2f;
 
 	/* ring size defaults */
@@ -4990,6 +5024,9 @@
 	adapter->wol = adapter->eeprom_wol;
 	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
 
+	/* save off EEPROM version number */
+	e1000_read_nvm(&adapter->hw, 5, 1, &adapter->eeprom_vers);
+
 	/* reset the hardware with the new settings */
 	e1000e_reset(adapter);
 
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index 6cd333a..dc4a9cb 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -744,7 +744,7 @@
 	 *  other:  No software override.  The flow control configuration
 	 *	  in the EEPROM is used.
 	 */
-	switch (hw->fc.type) {
+	switch (hw->fc.current_mode) {
 	case e1000_fc_none:
 		/*
 		 * Flow control (Rx & Tx) is completely disabled by a
@@ -1030,14 +1030,14 @@
 
 	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
 
-	/* Reset the phy to commit changes. */
-	phy_data |= MII_CR_RESET;
-
 	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
 	if (ret_val)
 		return ret_val;
 
-	udelay(1);
+	/* Reset the phy to commit changes. */
+	ret_val = e1000e_commit_phy(hw);
+	if (ret_val)
+		return ret_val;
 
 	if (phy->autoneg_wait_to_complete) {
 		hw_dbg(hw, "Waiting for forced speed/duplex link on M88 phy.\n");
@@ -1114,7 +1114,7 @@
 	u32 ctrl;
 
 	/* Turn off flow control when forcing speed/duplex */
-	hw->fc.type = e1000_fc_none;
+	hw->fc.current_mode = e1000_fc_none;
 
 	/* Force speed/duplex on the mac */
 	ctrl = er32(CTRL);
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index 6390f51..20eb05c 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -107,7 +107,7 @@
 							 const unsigned char *buf, int start_page);
 static void e21_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 							int ring_page);
-
+static int e21_open(struct net_device *dev);
 static int e21_close(struct net_device *dev);
 
 
@@ -160,6 +160,21 @@
 }
 #endif
 
+static const struct net_device_ops e21_netdev_ops = {
+	.ndo_open		= e21_open,
+	.ndo_stop		= e21_close,
+
+	.ndo_start_xmit		= ei_start_xmit,
+	.ndo_tx_timeout		= ei_tx_timeout,
+	.ndo_get_stats		= ei_get_stats,
+	.ndo_set_multicast_list = ei_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller 	= ei_poll,
+#endif
+};
+
 static int __init e21_probe1(struct net_device *dev, int ioaddr)
 {
 	int i, status, retval;
@@ -265,11 +280,8 @@
 	ei_status.block_input = &e21_block_input;
 	ei_status.block_output = &e21_block_output;
 	ei_status.get_8390_hdr = &e21_get_8390_hdr;
-	dev->open = &e21_open;
-	dev->stop = &e21_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = ei_poll;
-#endif
+
+	dev->netdev_ops = &e21_netdev_ops;
 	NS8390_init(dev, 0);
 
 	retval = register_netdev(dev);
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 1f11350..e187c88 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -605,7 +605,7 @@
 
 static void __init printEEPROMInfo(struct net_device *dev)
 {
-	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	struct eepro_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	unsigned short Word;
 	int i,j;
@@ -690,7 +690,6 @@
 	struct eepro_local *	lp = netdev_priv(dev);
 	int			i;
 	const char *		ifmap[] = {"AUI", "10Base2", "10BaseT"};
-	DECLARE_MAC_BUF(mac);
 
 	i = inb(dev->base_addr + ID_REG);
 	printk(KERN_DEBUG " id: %#x ",i);
@@ -715,7 +714,7 @@
 			break;
 	}
 
-	printk(" %s", print_mac(mac, dev->dev_addr));
+	printk(" %pM", dev->dev_addr);
 
 	if (net_debug > 3)
 		printk(KERN_DEBUG ", %dK RCV buffer",
@@ -1396,7 +1395,7 @@
 #define eeprom_delay() { udelay(40); }
 #define EE_READ_CMD (6 << 6)
 
-int
+static int
 read_eeprom(int ioaddr, int location, struct net_device *dev)
 {
 	int i;
@@ -1581,7 +1580,6 @@
 
 			skb->protocol = eth_type_trans(skb,dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 		}
 
@@ -1676,7 +1674,7 @@
 static int eepro_ethtool_get_settings(struct net_device *dev,
 					struct ethtool_cmd *cmd)
 {
-	struct eepro_local	*lp = (struct eepro_local *)dev->priv;
+	struct eepro_local	*lp = netdev_priv(dev);
 
 	cmd->supported = 	SUPPORTED_10baseT_Half |
 				SUPPORTED_10baseT_Full |
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
deleted file mode 100644
index e3e26c5..0000000
--- a/drivers/net/eepro100.c
+++ /dev/null
@@ -1,2401 +0,0 @@
-/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */
-/*
-	Written 1996-1999 by Donald Becker.
-
-	The driver also contains updates by different kernel developers
-	(see incomplete list below).
-	Current maintainer is Andrey V. Savochkin <saw@saw.sw.com.sg>.
-	Please use this email address and linux-kernel mailing list for bug reports.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	This driver is for the Intel EtherExpress Pro100 (Speedo3) design.
-	It should work with all i82557/558/559 boards.
-
-	Version history:
-	1998 Apr - 2000 Feb  Andrey V. Savochkin <saw@saw.sw.com.sg>
-		Serious fixes for multicast filter list setting, TX timeout routine;
-		RX ring refilling logic;  other stuff
-	2000 Feb  Jeff Garzik <jgarzik@pobox.com>
-		Convert to new PCI driver interface
-	2000 Mar 24  Dragan Stancevic <visitor@valinux.com>
-		Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
-	2000 Jul 17 Goutham Rao <goutham.rao@intel.com>
-		PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary
-	2000 Aug 31 David Mosberger <davidm@hpl.hp.com>
-		rx_align support: enables rx DMA without causing unaligned accesses.
-*/
-
-static const char * const version =
-"eepro100.c:v1.09j-t 9/29/99 Donald Becker\n"
-"eepro100.c: $Revision: 1.36 $ 2000/11/17 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
-
-/* A few user-configurable values that apply to all boards.
-   First set is undocumented and spelled per Intel recommendations. */
-
-static int congenb /* = 0 */; /* Enable congestion control in the DP83840. */
-static int txfifo = 8;		/* Tx FIFO threshold in 4 byte units, 0-15 */
-static int rxfifo = 8;		/* Rx FIFO threshold, default 32 bytes. */
-/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
-static int txdmacount = 128;
-static int rxdmacount /* = 0 */;
-
-#if defined(__ia64__) || defined(__alpha__) || defined(__sparc__) || defined(__mips__) || \
-	defined(__arm__)
-  /* align rx buffers to 2 bytes so that IP header is aligned */
-# define rx_align(skb)		skb_reserve((skb), 2)
-# define RxFD_ALIGNMENT		__attribute__ ((aligned (2), packed))
-#else
-# define rx_align(skb)
-# define RxFD_ALIGNMENT
-#endif
-
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
-   Lower values use more memory, but are faster. */
-static int rx_copybreak = 200;
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-
-/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
-static int multicast_filter_limit = 64;
-
-/* 'options' is used to pass a transceiver override or full-duplex flag
-   e.g. "options=16" for FD, "options=32" for 100mbps-only. */
-static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
-/* A few values that may be tweaked. */
-/* The ring sizes should be a power of two for efficiency. */
-#define TX_RING_SIZE	64
-#define RX_RING_SIZE	64
-/* How much slots multicast filter setup may take.
-   Do not descrease without changing set_rx_mode() implementaion. */
-#define TX_MULTICAST_SIZE   2
-#define TX_MULTICAST_RESERV (TX_MULTICAST_SIZE*2)
-/* Actual number of TX packets queued, must be
-   <= TX_RING_SIZE-TX_MULTICAST_RESERV. */
-#define TX_QUEUE_LIMIT  (TX_RING_SIZE-TX_MULTICAST_RESERV)
-/* Hysteresis marking queue as no longer full. */
-#define TX_QUEUE_UNFULL (TX_QUEUE_LIMIT-4)
-
-/* Operational parameters that usually are not changed. */
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT		(2*HZ)
-/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
-#define PKT_BUF_SZ		1536
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/mii.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/rtnetlink.h>
-#include <linux/skbuff.h>
-#include <linux/ethtool.h>
-
-static int use_io;
-static int debug = -1;
-#define DEBUG_DEFAULT		(NETIF_MSG_DRV		| \
-				 NETIF_MSG_HW		| \
-				 NETIF_MSG_RX_ERR	| \
-				 NETIF_MSG_TX_ERR)
-#define DEBUG			((debug >= 0) ? (1<<debug)-1 : DEBUG_DEFAULT)
-
-
-MODULE_AUTHOR("Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>");
-MODULE_DESCRIPTION("Intel i82557/i82558/i82559 PCI EtherExpressPro driver");
-MODULE_LICENSE("GPL");
-module_param(use_io, int, 0);
-module_param(debug, int, 0);
-module_param_array(options, int, NULL, 0);
-module_param_array(full_duplex, int, NULL, 0);
-module_param(congenb, int, 0);
-module_param(txfifo, int, 0);
-module_param(rxfifo, int, 0);
-module_param(txdmacount, int, 0);
-module_param(rxdmacount, int, 0);
-module_param(rx_copybreak, int, 0);
-module_param(max_interrupt_work, int, 0);
-module_param(multicast_filter_limit, int, 0);
-MODULE_PARM_DESC(debug, "debug level (0-6)");
-MODULE_PARM_DESC(options, "Bits 0-3: transceiver type, bit 4: full duplex, bit 5: 100Mbps");
-MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)");
-MODULE_PARM_DESC(congenb, "Enable congestion control (1)");
-MODULE_PARM_DESC(txfifo, "Tx FIFO threshold in 4 byte units, (0-15)");
-MODULE_PARM_DESC(rxfifo, "Rx FIFO threshold in 4 byte units, (0-15)");
-MODULE_PARM_DESC(txdmacount, "Tx DMA burst length; 128 - disable (0-128)");
-MODULE_PARM_DESC(rxdmacount, "Rx DMA burst length; 128 - disable (0-128)");
-MODULE_PARM_DESC(rx_copybreak, "copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
-MODULE_PARM_DESC(multicast_filter_limit, "maximum number of filtered multicast addresses");
-
-#define RUN_AT(x) (jiffies + (x))
-
-#define netdevice_start(dev)
-#define netdevice_stop(dev)
-#define netif_set_tx_timeout(dev, tf, tm) \
-								do { \
-									(dev)->tx_timeout = (tf); \
-									(dev)->watchdog_timeo = (tm); \
-								} while(0)
-
-
-
-/*
-				Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the Intel i82557 "Speedo3" chip, Intel's
-single-chip fast Ethernet controller for PCI, as used on the Intel
-EtherExpress Pro 100 adapter.
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board.  The system BIOS should be set to assign the
-PCI INTA signal to an otherwise unused system IRQ line.  While it's
-possible to share PCI interrupt lines, it negatively impacts performance and
-only recent kernels support it.
-
-III. Driver operation
-
-IIIA. General
-The Speedo3 is very similar to other Intel network chips, that is to say
-"apparently designed on a different planet".  This chips retains the complex
-Rx and Tx descriptors and multiple buffers pointers as previous chips, but
-also has simplified Tx and Rx buffer modes.  This driver uses the "flexible"
-Tx mode, but in a simplified lower-overhead manner: it associates only a
-single buffer descriptor with each frame descriptor.
-
-Despite the extra space overhead in each receive skbuff, the driver must use
-the simplified Rx buffer mode to assure that only a single data buffer is
-associated with each RxFD. The driver implements this by reserving space
-for the Rx descriptor at the head of each Rx skbuff.
-
-The Speedo-3 has receive and command unit base addresses that are added to
-almost all descriptor pointers.  The driver sets these to zero, so that all
-pointer fields are absolute addresses.
-
-The System Control Block (SCB) of some previous Intel chips exists on the
-chip in both PCI I/O and memory space.  This driver uses the I/O space
-registers, but might switch to memory mapped mode to better support non-x86
-processors.
-
-IIIB. Transmit structure
-
-The driver must use the complex Tx command+descriptor mode in order to
-have a indirect pointer to the skbuff data section.  Each Tx command block
-(TxCB) is associated with two immediately appended Tx Buffer Descriptor
-(TxBD).  A fixed ring of these TxCB+TxBD pairs are kept as part of the
-speedo_private data structure for each adapter instance.
-
-The newer i82558 explicitly supports this structure, and can read the two
-TxBDs in the same PCI burst as the TxCB.
-
-This ring structure is used for all normal transmit packets, but the
-transmit packet descriptors aren't long enough for most non-Tx commands such
-as CmdConfigure.  This is complicated by the possibility that the chip has
-already loaded the link address in the previous descriptor.  So for these
-commands we convert the next free descriptor on the ring to a NoOp, and point
-that descriptor's link to the complex command.
-
-An additional complexity of these non-transmit commands are that they may be
-added asynchronous to the normal transmit queue, so we disable interrupts
-whenever the Tx descriptor ring is manipulated.
-
-A notable aspect of these special configure commands is that they do
-work with the normal Tx ring entry scavenge method.  The Tx ring scavenge
-is done at interrupt time using the 'dirty_tx' index, and checking for the
-command-complete bit.  While the setup frames may have the NoOp command on the
-Tx ring marked as complete, but not have completed the setup command, this
-is not a problem.  The tx_ring entry can be still safely reused, as the
-tx_skbuff[] entry is always empty for config_cmd and mc_setup frames.
-
-Commands may have bits set e.g. CmdSuspend in the command word to either
-suspend or stop the transmit/command unit.  This driver always flags the last
-command with CmdSuspend, erases the CmdSuspend in the previous command, and
-then issues a CU_RESUME.
-Note: Watch out for the potential race condition here: imagine
-	erasing the previous suspend
-		the chip processes the previous command
-		the chip processes the final command, and suspends
-	doing the CU_RESUME
-		the chip processes the next-yet-valid post-final-command.
-So blindly sending a CU_RESUME is only safe if we do it immediately after
-after erasing the previous CmdSuspend, without the possibility of an
-intervening delay.  Thus the resume command is always within the
-interrupts-disabled region.  This is a timing dependence, but handling this
-condition in a timing-independent way would considerably complicate the code.
-
-Note: In previous generation Intel chips, restarting the command unit was a
-notoriously slow process.  This is presumably no longer true.
-
-IIIC. Receive structure
-
-Because of the bus-master support on the Speedo3 this driver uses the new
-SKBUFF_RX_COPYBREAK scheme, rather than a fixed intermediate receive buffer.
-This scheme allocates full-sized skbuffs as receive buffers.  The value
-SKBUFF_RX_COPYBREAK is used as the copying breakpoint: it is chosen to
-trade-off the memory wasted by passing the full-sized skbuff to the queue
-layer for all frames vs. the copying cost of copying a frame to a
-correctly-sized skbuff.
-
-For small frames the copying cost is negligible (esp. considering that we
-are pre-loading the cache with immediately useful header information), so we
-allocate a new, minimally-sized skbuff.  For large frames the copying cost
-is non-trivial, and the larger copy might flush the cache of useful data, so
-we pass up the skbuff the packet was received into.
-
-IV. Notes
-
-Thanks to Steve Williams of Intel for arranging the non-disclosure agreement
-that stated that I could disclose the information.  But I still resent
-having to sign an Intel NDA when I'm helping Intel sell their own product!
-
-*/
-
-static int speedo_found1(struct pci_dev *pdev, void __iomem *ioaddr, int fnd_cnt, int acpi_idle_state);
-
-/* Offsets to the various registers.
-   All accesses need not be longword aligned. */
-enum speedo_offsets {
-	SCBStatus = 0, SCBCmd = 2,	/* Rx/Command Unit command and status. */
-	SCBIntmask = 3,
-	SCBPointer = 4,				/* General purpose pointer. */
-	SCBPort = 8,				/* Misc. commands and operands.  */
-	SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
-	SCBCtrlMDI = 16,			/* MDI interface control. */
-	SCBEarlyRx = 20,			/* Early receive byte count. */
-};
-/* Commands that can be put in a command list entry. */
-enum commands {
-	CmdNOp = 0, CmdIASetup = 0x10000, CmdConfigure = 0x20000,
-	CmdMulticastList = 0x30000, CmdTx = 0x40000, CmdTDR = 0x50000,
-	CmdDump = 0x60000, CmdDiagnose = 0x70000,
-	CmdSuspend = 0x40000000,	/* Suspend after completion. */
-	CmdIntr = 0x20000000,		/* Interrupt after completion. */
-	CmdTxFlex = 0x00080000,		/* Use "Flexible mode" for CmdTx command. */
-};
-/* Clear CmdSuspend (1<<30) avoiding interference with the card access to the
-   status bits.  Previous driver versions used separate 16 bit fields for
-   commands and statuses.  --SAW
- */
-#if defined(__alpha__)
-# define clear_suspend(cmd)  clear_bit(30, &(cmd)->cmd_status);
-#else
-# define clear_suspend(cmd)  ((__le16 *)&(cmd)->cmd_status)[1] &= ~cpu_to_le16(1<<14)
-#endif
-
-enum SCBCmdBits {
-	SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000,
-	SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
-	SCBTriggerIntr=0x0200, SCBMaskAll=0x0100,
-	/* The rest are Rx and Tx commands. */
-	CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050,
-	CUCmdBase=0x0060,	/* CU Base address (set to zero) . */
-	CUDumpStats=0x0070, /* Dump then reset stats counters. */
-	RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006,
-	RxResumeNoResources=0x0007,
-};
-
-enum SCBPort_cmds {
-	PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3,
-};
-
-/* The Speedo3 Rx and Tx frame/buffer descriptors. */
-struct descriptor {			    /* A generic descriptor. */
-	volatile __le32 cmd_status;	/* All command and status fields. */
-	__le32 link;				    /* struct descriptor *  */
-	unsigned char params[0];
-};
-
-/* The Speedo3 Rx and Tx buffer descriptors. */
-struct RxFD {					/* Receive frame descriptor. */
-	volatile __le32 status;
-	__le32 link;					/* struct RxFD * */
-	__le32 rx_buf_addr;			/* void * */
-	__le32 count;
-} RxFD_ALIGNMENT;
-
-/* Selected elements of the Tx/RxFD.status word. */
-enum RxFD_bits {
-	RxComplete=0x8000, RxOK=0x2000,
-	RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
-	RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
-	TxUnderrun=0x1000,  StatusComplete=0x8000,
-};
-
-#define CONFIG_DATA_SIZE 22
-struct TxFD {					/* Transmit frame descriptor set. */
-	__le32 status;
-	__le32 link;					/* void * */
-	__le32 tx_desc_addr;			/* Always points to the tx_buf_addr element. */
-	__le32 count;					/* # of TBD (=1), Tx start thresh., etc. */
-	/* This constitutes two "TBD" entries -- we only use one. */
-#define TX_DESCR_BUF_OFFSET 16
-	__le32 tx_buf_addr0;			/* void *, frame to be transmitted.  */
-	__le32 tx_buf_size0;			/* Length of Tx frame. */
-	__le32 tx_buf_addr1;			/* void *, frame to be transmitted.  */
-	__le32 tx_buf_size1;			/* Length of Tx frame. */
-	/* the structure must have space for at least CONFIG_DATA_SIZE starting
-	 * from tx_desc_addr field */
-};
-
-/* Multicast filter setting block.  --SAW */
-struct speedo_mc_block {
-	struct speedo_mc_block *next;
-	unsigned int tx;
-	dma_addr_t frame_dma;
-	unsigned int len;
-	struct descriptor frame __attribute__ ((__aligned__(16)));
-};
-
-/* Elements of the dump_statistics block. This block must be lword aligned. */
-struct speedo_stats {
-	__le32 tx_good_frames;
-	__le32 tx_coll16_errs;
-	__le32 tx_late_colls;
-	__le32 tx_underruns;
-	__le32 tx_lost_carrier;
-	__le32 tx_deferred;
-	__le32 tx_one_colls;
-	__le32 tx_multi_colls;
-	__le32 tx_total_colls;
-	__le32 rx_good_frames;
-	__le32 rx_crc_errs;
-	__le32 rx_align_errs;
-	__le32 rx_resource_errs;
-	__le32 rx_overrun_errs;
-	__le32 rx_colls_errs;
-	__le32 rx_runt_errs;
-	__le32 done_marker;
-};
-
-enum Rx_ring_state_bits {
-	RrNoMem=1, RrPostponed=2, RrNoResources=4, RrOOMReported=8,
-};
-
-/* Do not change the position (alignment) of the first few elements!
-   The later elements are grouped for cache locality.
-
-   Unfortunately, all the positions have been shifted since there.
-   A new re-alignment is required.  2000/03/06  SAW */
-struct speedo_private {
-    void __iomem *regs;
-	struct TxFD	*tx_ring;		/* Commands (usually CmdTxPacket). */
-	struct RxFD *rx_ringp[RX_RING_SIZE];	/* Rx descriptor, used as ring. */
-	/* The addresses of a Tx/Rx-in-place packets/buffers. */
-	struct sk_buff *tx_skbuff[TX_RING_SIZE];
-	struct sk_buff *rx_skbuff[RX_RING_SIZE];
-	/* Mapped addresses of the rings. */
-	dma_addr_t tx_ring_dma;
-#define TX_RING_ELEM_DMA(sp, n) ((sp)->tx_ring_dma + (n)*sizeof(struct TxFD))
-	dma_addr_t rx_ring_dma[RX_RING_SIZE];
-	struct descriptor *last_cmd;		/* Last command sent. */
-	unsigned int cur_tx, dirty_tx;		/* The ring entries to be free()ed. */
-	spinlock_t lock;			/* Group with Tx control cache line. */
-	u32 tx_threshold;			/* The value for txdesc.count. */
-	struct RxFD *last_rxf;			/* Last filled RX buffer. */
-	dma_addr_t last_rxf_dma;
-	unsigned int cur_rx, dirty_rx;		/* The next free ring entry */
-	long last_rx_time;			/* Last Rx, in jiffies, to handle Rx hang. */
-	struct net_device_stats stats;
-	struct speedo_stats *lstats;
-	dma_addr_t lstats_dma;
-	int chip_id;
-	struct pci_dev *pdev;
-	struct timer_list timer;		/* Media selection timer. */
-	struct speedo_mc_block *mc_setup_head;	/* Multicast setup frame list head. */
-	struct speedo_mc_block *mc_setup_tail;	/* Multicast setup frame list tail. */
-	long in_interrupt;			/* Word-aligned dev->interrupt */
-	unsigned char acpi_pwr;
-	signed char rx_mode;			/* Current PROMISC/ALLMULTI setting. */
-	unsigned int tx_full:1;			/* The Tx queue is full. */
-	unsigned int flow_ctrl:1;		/* Use 802.3x flow control. */
-	unsigned int rx_bug:1;			/* Work around receiver hang errata. */
-	unsigned char default_port:8;		/* Last dev->if_port value. */
-	unsigned char rx_ring_state;		/* RX ring status flags. */
-	unsigned short phy[2];			/* PHY media interfaces available. */
-	unsigned short partner;			/* Link partner caps. */
-	struct mii_if_info mii_if;		/* MII API hooks, info */
-	u32 msg_enable;				/* debug message level */
-};
-
-/* The parameters for a CmdConfigure operation.
-   There are so many options that it would be difficult to document each bit.
-   We mostly use the default or recommended settings. */
-static const char i82557_config_cmd[CONFIG_DATA_SIZE] = {
-	22, 0x08, 0, 0,  0, 0, 0x32, 0x03,  1, /* 1=Use MII  0=Use AUI */
-	0, 0x2E, 0,  0x60, 0,
-	0xf2, 0x48,   0, 0x40, 0xf2, 0x80, 		/* 0x40=Force full-duplex */
-	0x3f, 0x05, };
-static const char i82558_config_cmd[CONFIG_DATA_SIZE] = {
-	22, 0x08, 0, 1,  0, 0, 0x22, 0x03,  1, /* 1=Use MII  0=Use AUI */
-	0, 0x2E, 0,  0x60, 0x08, 0x88,
-	0x68, 0, 0x40, 0xf2, 0x84,		/* Disable FC */
-	0x31, 0x05, };
-
-/* PHY media interface chips. */
-static const char * const phys[] = {
-	"None", "i82553-A/B", "i82553-C", "i82503",
-	"DP83840", "80c240", "80c24", "i82555",
-	"unknown-8", "unknown-9", "DP83840A", "unknown-11",
-	"unknown-12", "unknown-13", "unknown-14", "unknown-15", };
-enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240,
-					 S80C24, I82555, DP83840A=10, };
-static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
-#define EE_READ_CMD		(6)
-
-static int eepro100_init_one(struct pci_dev *pdev,
-		const struct pci_device_id *ent);
-
-static int do_eeprom_cmd(void __iomem *ioaddr, int cmd, int cmd_len);
-static int mdio_read(struct net_device *dev, int phy_id, int location);
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
-static int speedo_open(struct net_device *dev);
-static void speedo_resume(struct net_device *dev);
-static void speedo_timer(unsigned long data);
-static void speedo_init_rx_ring(struct net_device *dev);
-static void speedo_tx_timeout(struct net_device *dev);
-static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void speedo_refill_rx_buffers(struct net_device *dev, int force);
-static int speedo_rx(struct net_device *dev);
-static void speedo_tx_buffer_gc(struct net_device *dev);
-static irqreturn_t speedo_interrupt(int irq, void *dev_instance);
-static int speedo_close(struct net_device *dev);
-static struct net_device_stats *speedo_get_stats(struct net_device *dev);
-static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void set_rx_mode(struct net_device *dev);
-static void speedo_show_state(struct net_device *dev);
-static const struct ethtool_ops ethtool_ops;
-
-
-
-#ifdef honor_default_port
-/* Optional driver feature to allow forcing the transceiver setting.
-   Not recommended. */
-static int mii_ctrl[8] = { 0x3300, 0x3100, 0x0000, 0x0100,
-						   0x2000, 0x2100, 0x0400, 0x3100};
-#endif
-
-/* How to wait for the command unit to accept a command.
-   Typically this takes 0 ticks. */
-static inline unsigned char wait_for_cmd_done(struct net_device *dev,
-											  	struct speedo_private *sp)
-{
-	int wait = 1000;
-	void __iomem *cmd_ioaddr = sp->regs + SCBCmd;
-	unsigned char r;
-
-	do  {
-		udelay(1);
-		r = ioread8(cmd_ioaddr);
-	} while(r && --wait >= 0);
-
-	if (wait < 0)
-		printk(KERN_ALERT "%s: wait_for_cmd_done timeout!\n", dev->name);
-	return r;
-}
-
-static int __devinit eepro100_init_one (struct pci_dev *pdev,
-		const struct pci_device_id *ent)
-{
-	void __iomem *ioaddr;
-	int irq, pci_bar;
-	int acpi_idle_state = 0, pm;
-	static int cards_found /* = 0 */;
-	unsigned long pci_base;
-
-#ifndef MODULE
-	/* when built-in, we only print version if device is found */
-	static int did_version;
-	if (did_version++ == 0)
-		printk(version);
-#endif
-
-	/* save power state before pci_enable_device overwrites it */
-	pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
-	if (pm) {
-		u16 pwr_command;
-		pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
-		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
-	}
-
-	if (pci_enable_device(pdev))
-		goto err_out_free_mmio_region;
-
-	pci_set_master(pdev);
-
-	if (!request_region(pci_resource_start(pdev, 1),
-			pci_resource_len(pdev, 1), "eepro100")) {
-		dev_err(&pdev->dev, "eepro100: cannot reserve I/O ports\n");
-		goto err_out_none;
-	}
-	if (!request_mem_region(pci_resource_start(pdev, 0),
-			pci_resource_len(pdev, 0), "eepro100")) {
-		dev_err(&pdev->dev, "eepro100: cannot reserve MMIO region\n");
-		goto err_out_free_pio_region;
-	}
-
-	irq = pdev->irq;
-	pci_bar = use_io ? 1 : 0;
-	pci_base = pci_resource_start(pdev, pci_bar);
-	if (DEBUG & NETIF_MSG_PROBE)
-		printk("Found Intel i82557 PCI Speedo at %#lx, IRQ %d.\n",
-		       pci_base, irq);
-
-	ioaddr = pci_iomap(pdev, pci_bar, 0);
-	if (!ioaddr) {
-		dev_err(&pdev->dev, "eepro100: cannot remap IO\n");
-		goto err_out_free_mmio_region;
-	}
-
-	if (speedo_found1(pdev, ioaddr, cards_found, acpi_idle_state) == 0)
-		cards_found++;
-	else
-		goto err_out_iounmap;
-
-	return 0;
-
-err_out_iounmap: ;
-	pci_iounmap(pdev, ioaddr);
-err_out_free_mmio_region:
-	release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
-err_out_free_pio_region:
-	release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
-err_out_none:
-	return -ENODEV;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling 'interrupt' - used by things like netconsole to send skbs
- * without having to re-enable interrupts. It's not called while
- * the interrupt routine is executing.
- */
-
-static void poll_speedo (struct net_device *dev)
-{
-	/* disable_irq is not very nice, but with the funny lockless design
-	   we have no other choice. */
-	disable_irq(dev->irq);
-	speedo_interrupt (dev->irq, dev);
-	enable_irq(dev->irq);
-}
-#endif
-
-static int __devinit speedo_found1(struct pci_dev *pdev,
-		void __iomem *ioaddr, int card_idx, int acpi_idle_state)
-{
-	struct net_device *dev;
-	struct speedo_private *sp;
-	const char *product;
-	int i, option;
-	u16 eeprom[0x100];
-	int size;
-	void *tx_ring_space;
-	dma_addr_t tx_ring_dma;
-	DECLARE_MAC_BUF(mac);
-
-	size = TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats);
-	tx_ring_space = pci_alloc_consistent(pdev, size, &tx_ring_dma);
-	if (tx_ring_space == NULL)
-		return -1;
-
-	dev = alloc_etherdev(sizeof(struct speedo_private));
-	if (dev == NULL) {
-		printk(KERN_ERR "eepro100: Could not allocate ethernet device.\n");
-		pci_free_consistent(pdev, size, tx_ring_space, tx_ring_dma);
-		return -1;
-	}
-
-	SET_NETDEV_DEV(dev, &pdev->dev);
-
-	if (dev->mem_start > 0)
-		option = dev->mem_start;
-	else if (card_idx >= 0  &&  options[card_idx] >= 0)
-		option = options[card_idx];
-	else
-		option = 0;
-
-	rtnl_lock();
-	if (dev_alloc_name(dev, dev->name) < 0)
-		goto err_free_unlock;
-
-	/* Read the station address EEPROM before doing the reset.
-	   Nominally his should even be done before accepting the device, but
-	   then we wouldn't have a device name with which to report the error.
-	   The size test is for 6 bit vs. 8 bit address serial EEPROMs.
-	*/
-	{
-		void __iomem *iobase;
-		int read_cmd, ee_size;
-		u16 sum;
-		int j;
-
-		/* Use IO only to avoid postponed writes and satisfy EEPROM timing
-		   requirements. */
-		iobase = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
-		if (!iobase)
-			goto err_free_unlock;
-		if ((do_eeprom_cmd(iobase, EE_READ_CMD << 24, 27) & 0xffe0000)
-			== 0xffe0000) {
-			ee_size = 0x100;
-			read_cmd = EE_READ_CMD << 24;
-		} else {
-			ee_size = 0x40;
-			read_cmd = EE_READ_CMD << 22;
-		}
-
-		for (j = 0, i = 0, sum = 0; i < ee_size; i++) {
-			u16 value = do_eeprom_cmd(iobase, read_cmd | (i << 16), 27);
-			eeprom[i] = value;
-			sum += value;
-			if (i < 3) {
-				dev->dev_addr[j++] = value;
-				dev->dev_addr[j++] = value >> 8;
-			}
-		}
-		if (sum != 0xBABA)
-			printk(KERN_WARNING "%s: Invalid EEPROM checksum %#4.4x, "
-				   "check settings before activating this device!\n",
-				   dev->name, sum);
-		/* Don't  unregister_netdev(dev);  as the EEPro may actually be
-		   usable, especially if the MAC address is set later.
-		   On the other hand, it may be unusable if MDI data is corrupted. */
-
-		pci_iounmap(pdev, iobase);
-	}
-
-	/* Reset the chip: stop Tx and Rx processes and clear counters.
-	   This takes less than 10usec and will easily finish before the next
-	   action. */
-	iowrite32(PortReset, ioaddr + SCBPort);
-	ioread32(ioaddr + SCBPort);
-	udelay(10);
-
-	if (eeprom[3] & 0x0100)
-		product = "OEM i82557/i82558 10/100 Ethernet";
-	else
-		product = pci_name(pdev);
-
-	printk(KERN_INFO "%s: %s, %s, IRQ %d.\n", dev->name, product,
-		   print_mac(mac, dev->dev_addr), pdev->irq);
-
-	sp = netdev_priv(dev);
-
-	/* we must initialize this early, for mdio_{read,write} */
-	sp->regs = ioaddr;
-
-#if 1 || defined(kernel_bloat)
-	/* OK, this is pure kernel bloat.  I don't like it when other drivers
-	   waste non-pageable kernel space to emit similar messages, but I need
-	   them for bug reports. */
-	{
-		const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"};
-		/* The self-test results must be paragraph aligned. */
-		volatile s32 *self_test_results;
-		int boguscnt = 16000;	/* Timeout for set-test. */
-		if ((eeprom[3] & 0x03) != 0x03)
-			printk(KERN_INFO "  Receiver lock-up bug exists -- enabling"
-				   " work-around.\n");
-		printk(KERN_INFO "  Board assembly %4.4x%2.2x-%3.3d, Physical"
-			   " connectors present:",
-			   eeprom[8], eeprom[9]>>8, eeprom[9] & 0xff);
-		for (i = 0; i < 4; i++)
-			if (eeprom[5] & (1<<i))
-				printk(connectors[i]);
-		printk("\n"KERN_INFO"  Primary interface chip %s PHY #%d.\n",
-			   phys[(eeprom[6]>>8)&15], eeprom[6] & 0x1f);
-		if (eeprom[7] & 0x0700)
-			printk(KERN_INFO "    Secondary interface chip %s.\n",
-				   phys[(eeprom[7]>>8)&7]);
-		if (((eeprom[6]>>8) & 0x3f) == DP83840
-			||  ((eeprom[6]>>8) & 0x3f) == DP83840A) {
-			int mdi_reg23 = mdio_read(dev, eeprom[6] & 0x1f, 23) | 0x0422;
-			if (congenb)
-			  mdi_reg23 |= 0x0100;
-			printk(KERN_INFO"  DP83840 specific setup, setting register 23 to %4.4x.\n",
-				   mdi_reg23);
-			mdio_write(dev, eeprom[6] & 0x1f, 23, mdi_reg23);
-		}
-		if ((option >= 0) && (option & 0x70)) {
-			printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
-				   (option & 0x20 ? 100 : 10),
-				   (option & 0x10 ? "full" : "half"));
-			mdio_write(dev, eeprom[6] & 0x1f, MII_BMCR,
-					   ((option & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
-					   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
-		}
-
-		/* Perform a system self-test. */
-		self_test_results = (s32*) ((((long) tx_ring_space) + 15) & ~0xf);
-		self_test_results[0] = 0;
-		self_test_results[1] = -1;
-		iowrite32(tx_ring_dma | PortSelfTest, ioaddr + SCBPort);
-		do {
-			udelay(10);
-		} while (self_test_results[1] == -1  &&  --boguscnt >= 0);
-
-		if (boguscnt < 0) {		/* Test optimized out. */
-			printk(KERN_ERR "Self test failed, status %8.8x:\n"
-				   KERN_ERR " Failure to initialize the i82557.\n"
-				   KERN_ERR " Verify that the card is a bus-master"
-				   " capable slot.\n",
-				   self_test_results[1]);
-		} else
-			printk(KERN_INFO "  General self-test: %s.\n"
-				   KERN_INFO "  Serial sub-system self-test: %s.\n"
-				   KERN_INFO "  Internal registers self-test: %s.\n"
-				   KERN_INFO "  ROM checksum self-test: %s (%#8.8x).\n",
-				   self_test_results[1] & 0x1000 ? "failed" : "passed",
-				   self_test_results[1] & 0x0020 ? "failed" : "passed",
-				   self_test_results[1] & 0x0008 ? "failed" : "passed",
-				   self_test_results[1] & 0x0004 ? "failed" : "passed",
-				   self_test_results[0]);
-	}
-#endif  /* kernel_bloat */
-
-	iowrite32(PortReset, ioaddr + SCBPort);
-	ioread32(ioaddr + SCBPort);
-	udelay(10);
-
-	/* Return the chip to its original power state. */
-	pci_set_power_state(pdev, acpi_idle_state);
-
-	pci_set_drvdata (pdev, dev);
-	SET_NETDEV_DEV(dev, &pdev->dev);
-
-	dev->irq = pdev->irq;
-
-	sp->pdev = pdev;
-	sp->msg_enable = DEBUG;
-	sp->acpi_pwr = acpi_idle_state;
-	sp->tx_ring = tx_ring_space;
-	sp->tx_ring_dma = tx_ring_dma;
-	sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE);
-	sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE);
-	init_timer(&sp->timer); /* used in ioctl() */
-	spin_lock_init(&sp->lock);
-
-	sp->mii_if.full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
-	if (card_idx >= 0) {
-		if (full_duplex[card_idx] >= 0)
-			sp->mii_if.full_duplex = full_duplex[card_idx];
-	}
-	sp->default_port = option >= 0 ? (option & 0x0f) : 0;
-
-	sp->phy[0] = eeprom[6];
-	sp->phy[1] = eeprom[7];
-
-	sp->mii_if.phy_id = eeprom[6] & 0x1f;
-	sp->mii_if.phy_id_mask = 0x1f;
-	sp->mii_if.reg_num_mask = 0x1f;
-	sp->mii_if.dev = dev;
-	sp->mii_if.mdio_read = mdio_read;
-	sp->mii_if.mdio_write = mdio_write;
-
-	sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1;
-	if (((pdev->device > 0x1030 && (pdev->device < 0x103F)))
-	    || (pdev->device == 0x2449) || (pdev->device == 0x2459)
-            || (pdev->device == 0x245D)) {
-	    	sp->chip_id = 1;
-	}
-
-	if (sp->rx_bug)
-		printk(KERN_INFO "  Receiver lock-up workaround activated.\n");
-
-	/* The Speedo-specific entries in the device structure. */
-	dev->open = &speedo_open;
-	dev->hard_start_xmit = &speedo_start_xmit;
-	netif_set_tx_timeout(dev, &speedo_tx_timeout, TX_TIMEOUT);
-	dev->stop = &speedo_close;
-	dev->get_stats = &speedo_get_stats;
-	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &speedo_ioctl;
-	SET_ETHTOOL_OPS(dev, &ethtool_ops);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = &poll_speedo;
-#endif
-
-	if (register_netdevice(dev))
-		goto err_free_unlock;
-	rtnl_unlock();
-
-	return 0;
-
- err_free_unlock:
-	rtnl_unlock();
-	free_netdev(dev);
-	return -1;
-}
-
-static void do_slow_command(struct net_device *dev, struct speedo_private *sp, int cmd)
-{
-	void __iomem *cmd_ioaddr = sp->regs + SCBCmd;
-	int wait = 0;
-	do
-		if (ioread8(cmd_ioaddr) == 0) break;
-	while(++wait <= 200);
-	if (wait > 100)
-		printk(KERN_ERR "Command %4.4x never accepted (%d polls)!\n",
-		       ioread8(cmd_ioaddr), wait);
-
-	iowrite8(cmd, cmd_ioaddr);
-
-	for (wait = 0; wait <= 100; wait++)
-		if (ioread8(cmd_ioaddr) == 0) return;
-	for (; wait <= 20000; wait++)
-		if (ioread8(cmd_ioaddr) == 0) return;
-		else udelay(1);
-	printk(KERN_ERR "Command %4.4x was not accepted after %d polls!"
-	       "  Current status %8.8x.\n",
-	       cmd, wait, ioread32(sp->regs + SCBStatus));
-}
-
-/* Serial EEPROM section.
-   A "bit" grungy, but we work our way through bit-by-bit :->. */
-/*  EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK	0x01	/* EEPROM shift clock. */
-#define EE_CS			0x02	/* EEPROM chip select. */
-#define EE_DATA_WRITE	0x04	/* EEPROM chip data in. */
-#define EE_DATA_READ	0x08	/* EEPROM chip data out. */
-#define EE_ENB			(0x4800 | EE_CS)
-#define EE_WRITE_0		0x4802
-#define EE_WRITE_1		0x4806
-#define EE_OFFSET		SCBeeprom
-
-/* The fixes for the code were kindly provided by Dragan Stancevic
-   <visitor@valinux.com> to strictly follow Intel specifications of EEPROM
-   access timing.
-   The publicly available sheet 64486302 (sec. 3.1) specifies 1us access
-   interval for serial EEPROM.  However, it looks like that there is an
-   additional requirement dictating larger udelay's in the code below.
-   2000/05/24  SAW */
-static int __devinit do_eeprom_cmd(void __iomem *ioaddr, int cmd, int cmd_len)
-{
-	unsigned retval = 0;
-	void __iomem *ee_addr = ioaddr + SCBeeprom;
-
-	iowrite16(EE_ENB, ee_addr); udelay(2);
-	iowrite16(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2);
-
-	/* Shift the command bits out. */
-	do {
-		short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
-		iowrite16(dataval, ee_addr); udelay(2);
-		iowrite16(dataval | EE_SHIFT_CLK, ee_addr); udelay(2);
-		retval = (retval << 1) | ((ioread16(ee_addr) & EE_DATA_READ) ? 1 : 0);
-	} while (--cmd_len >= 0);
-	iowrite16(EE_ENB, ee_addr); udelay(2);
-
-	/* Terminate the EEPROM access. */
-	iowrite16(EE_ENB & ~EE_CS, ee_addr);
-	return retval;
-}
-
-static int mdio_read(struct net_device *dev, int phy_id, int location)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
-	iowrite32(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
-	do {
-		val = ioread32(ioaddr + SCBCtrlMDI);
-		if (--boguscnt < 0) {
-			printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val);
-			break;
-		}
-	} while (! (val & 0x10000000));
-	return val & 0xffff;
-}
-
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
-	iowrite32(0x04000000 | (location<<16) | (phy_id<<21) | value,
-		 ioaddr + SCBCtrlMDI);
-	do {
-		val = ioread32(ioaddr + SCBCtrlMDI);
-		if (--boguscnt < 0) {
-			printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val);
-			break;
-		}
-	} while (! (val & 0x10000000));
-}
-
-static int
-speedo_open(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-	int retval;
-
-	if (netif_msg_ifup(sp))
-		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
-
-	pci_set_power_state(sp->pdev, PCI_D0);
-
-	/* Set up the Tx queue early.. */
-	sp->cur_tx = 0;
-	sp->dirty_tx = 0;
-	sp->last_cmd = NULL;
-	sp->tx_full = 0;
-	sp->in_interrupt = 0;
-
-	/* .. we can safely take handler calls during init. */
-	retval = request_irq(dev->irq, &speedo_interrupt, IRQF_SHARED, dev->name, dev);
-	if (retval) {
-		return retval;
-	}
-
-	dev->if_port = sp->default_port;
-
-#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us
-	/* Retrigger negotiation to reset previous errors. */
-	if ((sp->phy[0] & 0x8000) == 0) {
-		int phy_addr = sp->phy[0] & 0x1f ;
-		/* Use 0x3300 for restarting NWay, other values to force xcvr:
-		   0x0000 10-HD
-		   0x0100 10-FD
-		   0x2000 100-HD
-		   0x2100 100-FD
-		*/
-#ifdef honor_default_port
-		mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]);
-#else
-		mdio_write(dev, phy_addr, MII_BMCR, 0x3300);
-#endif
-	}
-#endif
-
-	speedo_init_rx_ring(dev);
-
-	/* Fire up the hardware. */
-	iowrite16(SCBMaskAll, ioaddr + SCBCmd);
-	speedo_resume(dev);
-
-	netdevice_start(dev);
-	netif_start_queue(dev);
-
-	/* Setup the chip and configure the multicast list. */
-	sp->mc_setup_head = NULL;
-	sp->mc_setup_tail = NULL;
-	sp->flow_ctrl = sp->partner = 0;
-	sp->rx_mode = -1;			/* Invalid -> always reset the mode. */
-	set_rx_mode(dev);
-	if ((sp->phy[0] & 0x8000) == 0)
-		sp->mii_if.advertising = mdio_read(dev, sp->phy[0] & 0x1f, MII_ADVERTISE);
-
-	mii_check_link(&sp->mii_if);
-
-	if (netif_msg_ifup(sp)) {
-		printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n",
-			   dev->name, ioread16(ioaddr + SCBStatus));
-	}
-
-	/* Set the timer.  The timer serves a dual purpose:
-	   1) to monitor the media interface (e.g. link beat) and perhaps switch
-	   to an alternate media type
-	   2) to monitor Rx activity, and restart the Rx process if the receiver
-	   hangs. */
-	sp->timer.expires = RUN_AT((24*HZ)/10); 			/* 2.4 sec. */
-	sp->timer.data = (unsigned long)dev;
-	sp->timer.function = &speedo_timer;					/* timer handler */
-	add_timer(&sp->timer);
-
-	/* No need to wait for the command unit to accept here. */
-	if ((sp->phy[0] & 0x8000) == 0)
-		mdio_read(dev, sp->phy[0] & 0x1f, MII_BMCR);
-
-	return 0;
-}
-
-/* Start the chip hardware after a full reset. */
-static void speedo_resume(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-
-	/* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */
-	sp->tx_threshold = 0x01208000;
-
-	/* Set the segment registers to '0'. */
-	if (wait_for_cmd_done(dev, sp) != 0) {
-		iowrite32(PortPartialReset, ioaddr + SCBPort);
-		udelay(10);
-	}
-
-        iowrite32(0, ioaddr + SCBPointer);
-        ioread32(ioaddr + SCBPointer);			/* Flush to PCI. */
-        udelay(10);			/* Bogus, but it avoids the bug. */
-
-        /* Note: these next two operations can take a while. */
-        do_slow_command(dev, sp, RxAddrLoad);
-        do_slow_command(dev, sp, CUCmdBase);
-
-	/* Load the statistics block and rx ring addresses. */
-	iowrite32(sp->lstats_dma, ioaddr + SCBPointer);
-	ioread32(ioaddr + SCBPointer);			/* Flush to PCI */
-
-	iowrite8(CUStatsAddr, ioaddr + SCBCmd);
-	sp->lstats->done_marker = 0;
-	wait_for_cmd_done(dev, sp);
-
-	if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) {
-		if (netif_msg_rx_err(sp))
-			printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n",
-					dev->name);
-	} else {
-		iowrite32(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
-			 ioaddr + SCBPointer);
-		ioread32(ioaddr + SCBPointer);		/* Flush to PCI */
-	}
-
-	/* Note: RxStart should complete instantly. */
-	do_slow_command(dev, sp, RxStart);
-	do_slow_command(dev, sp, CUDumpStats);
-
-	/* Fill the first command with our physical address. */
-	{
-		struct descriptor *ias_cmd;
-
-		ias_cmd =
-			(struct descriptor *)&sp->tx_ring[sp->cur_tx++ % TX_RING_SIZE];
-		/* Avoid a bug(?!) here by marking the command already completed. */
-		ias_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000);
-		ias_cmd->link =
-			cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE));
-		memcpy(ias_cmd->params, dev->dev_addr, 6);
-		if (sp->last_cmd)
-			clear_suspend(sp->last_cmd);
-		sp->last_cmd = ias_cmd;
-	}
-
-	/* Start the chip's Tx process and unmask interrupts. */
-	iowrite32(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE),
-		 ioaddr + SCBPointer);
-	/* We are not ACK-ing FCP and ER in the interrupt handler yet so they should
-	   remain masked --Dragan */
-	iowrite16(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd);
-}
-
-/*
- * Sometimes the receiver stops making progress.  This routine knows how to
- * get it going again, without losing packets or being otherwise nasty like
- * a chip reset would be.  Previously the driver had a whole sequence
- * of if RxSuspended, if it's no buffers do one thing, if it's no resources,
- * do another, etc.  But those things don't really matter.  Separate logic
- * in the ISR provides for allocating buffers--the other half of operation
- * is just making sure the receiver is active.  speedo_rx_soft_reset does that.
- * This problem with the old, more involved algorithm is shown up under
- * ping floods on the order of 60K packets/second on a 100Mbps fdx network.
- */
-static void
-speedo_rx_soft_reset(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	struct RxFD *rfd;
-	void __iomem *ioaddr;
-
-	ioaddr = sp->regs;
-	if (wait_for_cmd_done(dev, sp) != 0) {
-		printk("%s: previous command stalled\n", dev->name);
-		return;
-	}
-	/*
-	* Put the hardware into a known state.
-	*/
-	iowrite8(RxAbort, ioaddr + SCBCmd);
-
-	rfd = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
-
-	rfd->rx_buf_addr = cpu_to_le32(0xffffffff);
-
-	if (wait_for_cmd_done(dev, sp) != 0) {
-		printk("%s: RxAbort command stalled\n", dev->name);
-		return;
-	}
-	iowrite32(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
-		ioaddr + SCBPointer);
-	iowrite8(RxStart, ioaddr + SCBCmd);
-}
-
-
-/* Media monitoring and control. */
-static void speedo_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-	int phy_num = sp->phy[0] & 0x1f;
-
-	/* We have MII and lost link beat. */
-	if ((sp->phy[0] & 0x8000) == 0) {
-		int partner = mdio_read(dev, phy_num, MII_LPA);
-		if (partner != sp->partner) {
-			int flow_ctrl = sp->mii_if.advertising & partner & 0x0400 ? 1 : 0;
-			if (netif_msg_link(sp)) {
-				printk(KERN_DEBUG "%s: Link status change.\n", dev->name);
-				printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n",
-					   dev->name, sp->partner, partner, sp->mii_if.advertising);
-			}
-			sp->partner = partner;
-			if (flow_ctrl != sp->flow_ctrl) {
-				sp->flow_ctrl = flow_ctrl;
-				sp->rx_mode = -1;	/* Trigger a reload. */
-			}
-		}
-	}
-	mii_check_link(&sp->mii_if);
-	if (netif_msg_timer(sp)) {
-		printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n",
-			   dev->name, ioread16(ioaddr + SCBStatus));
-	}
-	if (sp->rx_mode < 0  ||
-		(sp->rx_bug  && jiffies - sp->last_rx_time > 2*HZ)) {
-		/* We haven't received a packet in a Long Time.  We might have been
-		   bitten by the receiver hang bug.  This can be cleared by sending
-		   a set multicast list command. */
-		if (netif_msg_timer(sp))
-			printk(KERN_DEBUG "%s: Sending a multicast list set command"
-				   " from a timer routine,"
-				   " m=%d, j=%ld, l=%ld.\n",
-				   dev->name, sp->rx_mode, jiffies, sp->last_rx_time);
-		set_rx_mode(dev);
-	}
-	/* We must continue to monitor the media. */
-	sp->timer.expires = RUN_AT(2*HZ); 			/* 2.0 sec. */
-	add_timer(&sp->timer);
-}
-
-static void speedo_show_state(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	int i;
-
-	if (netif_msg_pktdata(sp)) {
-		printk(KERN_DEBUG "%s: Tx ring dump,  Tx queue %u / %u:\n",
-		    dev->name, sp->cur_tx, sp->dirty_tx);
-		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(KERN_DEBUG "%s:  %c%c%2d %8.8x.\n", dev->name,
-			    i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ',
-			    i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ',
-			    i, sp->tx_ring[i].status);
-
-		printk(KERN_DEBUG "%s: Printing Rx ring"
-		    " (next to receive into %u, dirty index %u).\n",
-		    dev->name, sp->cur_rx, sp->dirty_rx);
-		for (i = 0; i < RX_RING_SIZE; i++)
-			printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name,
-			    sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ',
-			    i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ',
-			    i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ',
-			    i, (sp->rx_ringp[i] != NULL) ?
-			    (unsigned)sp->rx_ringp[i]->status : 0);
-	}
-
-#if 0
-	{
-		void __iomem *ioaddr = sp->regs;
-		int phy_num = sp->phy[0] & 0x1f;
-		for (i = 0; i < 16; i++) {
-			/* FIXME: what does it mean?  --SAW */
-			if (i == 6) i = 21;
-			printk(KERN_DEBUG "%s:  PHY index %d register %d is %4.4x.\n",
-				   dev->name, phy_num, i, mdio_read(dev, phy_num, i));
-		}
-	}
-#endif
-
-}
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void
-speedo_init_rx_ring(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	struct RxFD *rxf, *last_rxf = NULL;
-	dma_addr_t last_rxf_dma = 0 /* to shut up the compiler */;
-	int i;
-
-	sp->cur_rx = 0;
-
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb;
-		skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-		if (skb)
-			rx_align(skb);        /* Align IP on 16 byte boundary */
-		sp->rx_skbuff[i] = skb;
-		if (skb == NULL)
-			break;			/* OK.  Just initially short of Rx bufs. */
-		skb->dev = dev;			/* Mark as being used by this device. */
-		rxf = (struct RxFD *)skb->data;
-		sp->rx_ringp[i] = rxf;
-		sp->rx_ring_dma[i] =
-			pci_map_single(sp->pdev, rxf,
-					PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_BIDIRECTIONAL);
-		skb_reserve(skb, sizeof(struct RxFD));
-		if (last_rxf) {
-			last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]);
-			pci_dma_sync_single_for_device(sp->pdev, last_rxf_dma,
-										   sizeof(struct RxFD), PCI_DMA_TODEVICE);
-		}
-		last_rxf = rxf;
-		last_rxf_dma = sp->rx_ring_dma[i];
-		rxf->status = cpu_to_le32(0x00000001);	/* '1' is flag value only. */
-		rxf->link = 0;						/* None yet. */
-		/* This field unused by i82557. */
-		rxf->rx_buf_addr = cpu_to_le32(0xffffffff);
-		rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
-		pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[i],
-									   sizeof(struct RxFD), PCI_DMA_TODEVICE);
-	}
-	sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-	/* Mark the last entry as end-of-list. */
-	last_rxf->status = cpu_to_le32(0xC0000002);	/* '2' is flag value only. */
-	pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1],
-								   sizeof(struct RxFD), PCI_DMA_TODEVICE);
-	sp->last_rxf = last_rxf;
-	sp->last_rxf_dma = last_rxf_dma;
-}
-
-static void speedo_purge_tx(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	int entry;
-
-	while ((int)(sp->cur_tx - sp->dirty_tx) > 0) {
-		entry = sp->dirty_tx % TX_RING_SIZE;
-		if (sp->tx_skbuff[entry]) {
-			sp->stats.tx_errors++;
-			pci_unmap_single(sp->pdev,
-					le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0),
-					sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb_irq(sp->tx_skbuff[entry]);
-			sp->tx_skbuff[entry] = NULL;
-		}
-		sp->dirty_tx++;
-	}
-	while (sp->mc_setup_head != NULL) {
-		struct speedo_mc_block *t;
-		if (netif_msg_tx_err(sp))
-			printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
-		pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma,
-				sp->mc_setup_head->len, PCI_DMA_TODEVICE);
-		t = sp->mc_setup_head->next;
-		kfree(sp->mc_setup_head);
-		sp->mc_setup_head = t;
-	}
-	sp->mc_setup_tail = NULL;
-	sp->tx_full = 0;
-	netif_wake_queue(dev);
-}
-
-static void reset_mii(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-
-	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
-	if ((sp->phy[0] & 0x8000) == 0) {
-		int phy_addr = sp->phy[0] & 0x1f;
-		int advertising = mdio_read(dev, phy_addr, MII_ADVERTISE);
-		int mii_bmcr = mdio_read(dev, phy_addr, MII_BMCR);
-		mdio_write(dev, phy_addr, MII_BMCR, 0x0400);
-		mdio_write(dev, phy_addr, MII_BMSR, 0x0000);
-		mdio_write(dev, phy_addr, MII_ADVERTISE, 0x0000);
-		mdio_write(dev, phy_addr, MII_BMCR, 0x8000);
-#ifdef honor_default_port
-		mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]);
-#else
-		mdio_read(dev, phy_addr, MII_BMCR);
-		mdio_write(dev, phy_addr, MII_BMCR, mii_bmcr);
-		mdio_write(dev, phy_addr, MII_ADVERTISE, advertising);
-#endif
-	}
-}
-
-static void speedo_tx_timeout(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-	int status = ioread16(ioaddr + SCBStatus);
-	unsigned long flags;
-
-	if (netif_msg_tx_err(sp)) {
-		printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
-		   " %4.4x at %d/%d command %8.8x.\n",
-		   dev->name, status, ioread16(ioaddr + SCBCmd),
-		   sp->dirty_tx, sp->cur_tx,
-		   sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
-
-	}
-	speedo_show_state(dev);
-#if 0
-	if ((status & 0x00C0) != 0x0080
-		&&  (status & 0x003C) == 0x0010) {
-		/* Only the command unit has stopped. */
-		printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
-			   dev->name);
-		iowrite32(TX_RING_ELEM_DMA(sp, dirty_tx % TX_RING_SIZE]),
-			 ioaddr + SCBPointer);
-		iowrite16(CUStart, ioaddr + SCBCmd);
-		reset_mii(dev);
-	} else {
-#else
-	{
-#endif
-		del_timer_sync(&sp->timer);
-		/* Reset the Tx and Rx units. */
-		iowrite32(PortReset, ioaddr + SCBPort);
-		/* We may get spurious interrupts here.  But I don't think that they
-		   may do much harm.  1999/12/09 SAW */
-		udelay(10);
-		/* Disable interrupts. */
-		iowrite16(SCBMaskAll, ioaddr + SCBCmd);
-		synchronize_irq(dev->irq);
-		speedo_tx_buffer_gc(dev);
-		/* Free as much as possible.
-		   It helps to recover from a hang because of out-of-memory.
-		   It also simplifies speedo_resume() in case TX ring is full or
-		   close-to-be full. */
-		speedo_purge_tx(dev);
-		speedo_refill_rx_buffers(dev, 1);
-		spin_lock_irqsave(&sp->lock, flags);
-		speedo_resume(dev);
-		sp->rx_mode = -1;
-		dev->trans_start = jiffies;
-		spin_unlock_irqrestore(&sp->lock, flags);
-		set_rx_mode(dev); /* it takes the spinlock itself --SAW */
-		/* Reset MII transceiver.  Do it before starting the timer to serialize
-		   mdio_xxx operations.  Yes, it's a paranoya :-)  2000/05/09 SAW */
-		reset_mii(dev);
-		sp->timer.expires = RUN_AT(2*HZ);
-		add_timer(&sp->timer);
-	}
-	return;
-}
-
-static int
-speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-	int entry;
-
-	/* Prevent interrupts from changing the Tx ring from underneath us. */
-	unsigned long flags;
-
-	spin_lock_irqsave(&sp->lock, flags);
-
-	/* Check if there are enough space. */
-	if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-		printk(KERN_ERR "%s: incorrect tbusy state, fixed.\n", dev->name);
-		netif_stop_queue(dev);
-		sp->tx_full = 1;
-		spin_unlock_irqrestore(&sp->lock, flags);
-		return 1;
-	}
-
-	/* Calculate the Tx descriptor entry. */
-	entry = sp->cur_tx++ % TX_RING_SIZE;
-
-	sp->tx_skbuff[entry] = skb;
-	sp->tx_ring[entry].status =
-		cpu_to_le32(CmdSuspend | CmdTx | CmdTxFlex);
-	if (!(entry & ((TX_RING_SIZE>>2)-1)))
-		sp->tx_ring[entry].status |= cpu_to_le32(CmdIntr);
-	sp->tx_ring[entry].link =
-		cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE));
-	sp->tx_ring[entry].tx_desc_addr =
-		cpu_to_le32(TX_RING_ELEM_DMA(sp, entry) + TX_DESCR_BUF_OFFSET);
-	/* The data region is always in one buffer descriptor. */
-	sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold);
-	sp->tx_ring[entry].tx_buf_addr0 =
-		cpu_to_le32(pci_map_single(sp->pdev, skb->data,
-					   skb->len, PCI_DMA_TODEVICE));
-	sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len);
-
-	/* workaround for hardware bug on 10 mbit half duplex */
-
-	if ((sp->partner == 0) && (sp->chip_id == 1)) {
-		wait_for_cmd_done(dev, sp);
-		iowrite8(0 , ioaddr + SCBCmd);
-		udelay(1);
-	}
-
-	/* Trigger the command unit resume. */
-	wait_for_cmd_done(dev, sp);
-	clear_suspend(sp->last_cmd);
-	/* We want the time window between clearing suspend flag on the previous
-	   command and resuming CU to be as small as possible.
-	   Interrupts in between are very undesired.  --SAW */
-	iowrite8(CUResume, ioaddr + SCBCmd);
-	sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
-
-	/* Leave room for set_rx_mode(). If there is no more space than reserved
-	   for multicast filter mark the ring as full. */
-	if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-		netif_stop_queue(dev);
-		sp->tx_full = 1;
-	}
-
-	spin_unlock_irqrestore(&sp->lock, flags);
-
-	dev->trans_start = jiffies;
-
-	return 0;
-}
-
-static void speedo_tx_buffer_gc(struct net_device *dev)
-{
-	unsigned int dirty_tx;
-	struct speedo_private *sp = netdev_priv(dev);
-
-	dirty_tx = sp->dirty_tx;
-	while ((int)(sp->cur_tx - dirty_tx) > 0) {
-		int entry = dirty_tx % TX_RING_SIZE;
-		int status = le32_to_cpu(sp->tx_ring[entry].status);
-
-		if (netif_msg_tx_done(sp))
-			printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
-				   entry, status);
-		if ((status & StatusComplete) == 0)
-			break;			/* It still hasn't been processed. */
-		if (status & TxUnderrun)
-			if (sp->tx_threshold < 0x01e08000) {
-				if (netif_msg_tx_err(sp))
-					printk(KERN_DEBUG "%s: TX underrun, threshold adjusted.\n",
-						   dev->name);
-				sp->tx_threshold += 0x00040000;
-			}
-		/* Free the original skb. */
-		if (sp->tx_skbuff[entry]) {
-			sp->stats.tx_packets++;	/* Count only user packets. */
-			sp->stats.tx_bytes += sp->tx_skbuff[entry]->len;
-			pci_unmap_single(sp->pdev,
-					le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0),
-					sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb_irq(sp->tx_skbuff[entry]);
-			sp->tx_skbuff[entry] = NULL;
-		}
-		dirty_tx++;
-	}
-
-	if (netif_msg_tx_err(sp) && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) {
-		printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"
-			   " full=%d.\n",
-			   dirty_tx, sp->cur_tx, sp->tx_full);
-		dirty_tx += TX_RING_SIZE;
-	}
-
-	while (sp->mc_setup_head != NULL
-		   && (int)(dirty_tx - sp->mc_setup_head->tx - 1) > 0) {
-		struct speedo_mc_block *t;
-		if (netif_msg_tx_err(sp))
-			printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
-		pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma,
-				sp->mc_setup_head->len, PCI_DMA_TODEVICE);
-		t = sp->mc_setup_head->next;
-		kfree(sp->mc_setup_head);
-		sp->mc_setup_head = t;
-	}
-	if (sp->mc_setup_head == NULL)
-		sp->mc_setup_tail = NULL;
-
-	sp->dirty_tx = dirty_tx;
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
-   after the Tx thread. */
-static irqreturn_t speedo_interrupt(int irq, void *dev_instance)
-{
-	struct net_device *dev = (struct net_device *)dev_instance;
-	struct speedo_private *sp;
-	void __iomem *ioaddr;
-	long boguscnt = max_interrupt_work;
-	unsigned short status;
-	unsigned int handled = 0;
-
-	sp = netdev_priv(dev);
-	ioaddr = sp->regs;
-
-#ifndef final_version
-	/* A lock to prevent simultaneous entry on SMP machines. */
-	if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
-		printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-			   dev->name);
-		sp->in_interrupt = 0;	/* Avoid halting machine. */
-		return IRQ_NONE;
-	}
-#endif
-
-	do {
-		status = ioread16(ioaddr + SCBStatus);
-		/* Acknowledge all of the current interrupt sources ASAP. */
-		/* Will change from 0xfc00 to 0xff00 when we start handling
-		   FCP and ER interrupts --Dragan */
-		iowrite16(status & 0xfc00, ioaddr + SCBStatus);
-
-		if (netif_msg_intr(sp))
-			printk(KERN_DEBUG "%s: interrupt  status=%#4.4x.\n",
-				   dev->name, status);
-
-		if ((status & 0xfc00) == 0)
-			break;
-		handled = 1;
-
-
-		if ((status & 0x5000) ||	/* Packet received, or Rx error. */
-			(sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed)
-									/* Need to gather the postponed packet. */
-			speedo_rx(dev);
-
-		/* Always check if all rx buffers are allocated.  --SAW */
-		speedo_refill_rx_buffers(dev, 0);
-
-		spin_lock(&sp->lock);
-		/*
-		 * The chip may have suspended reception for various reasons.
-		 * Check for that, and re-prime it should this be the case.
-		 */
-		switch ((status >> 2) & 0xf) {
-		case 0: /* Idle */
-			break;
-		case 1:	/* Suspended */
-		case 2:	/* No resources (RxFDs) */
-		case 9:	/* Suspended with no more RBDs */
-		case 10: /* No resources due to no RBDs */
-		case 12: /* Ready with no RBDs */
-			speedo_rx_soft_reset(dev);
-			break;
-		case 3:  case 5:  case 6:  case 7:  case 8:
-		case 11:  case 13:  case 14:  case 15:
-			/* these are all reserved values */
-			break;
-		}
-
-
-		/* User interrupt, Command/Tx unit interrupt or CU not active. */
-		if (status & 0xA400) {
-			speedo_tx_buffer_gc(dev);
-			if (sp->tx_full
-				&& (int)(sp->cur_tx - sp->dirty_tx) < TX_QUEUE_UNFULL) {
-				/* The ring is no longer full. */
-				sp->tx_full = 0;
-				netif_wake_queue(dev); /* Attention: under a spinlock.  --SAW */
-			}
-		}
-
-		spin_unlock(&sp->lock);
-
-		if (--boguscnt < 0) {
-			printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
-				   dev->name, status);
-			/* Clear all interrupt sources. */
-			/* Will change from 0xfc00 to 0xff00 when we start handling
-			   FCP and ER interrupts --Dragan */
-			iowrite16(0xfc00, ioaddr + SCBStatus);
-			break;
-		}
-	} while (1);
-
-	if (netif_msg_intr(sp))
-		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-			   dev->name, ioread16(ioaddr + SCBStatus));
-
-	clear_bit(0, (void*)&sp->in_interrupt);
-	return IRQ_RETVAL(handled);
-}
-
-static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	struct RxFD *rxf;
-	struct sk_buff *skb;
-	/* Get a fresh skbuff to replace the consumed one. */
-	skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-	if (skb)
-		rx_align(skb);		/* Align IP on 16 byte boundary */
-	sp->rx_skbuff[entry] = skb;
-	if (skb == NULL) {
-		sp->rx_ringp[entry] = NULL;
-		return NULL;
-	}
-	rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->data;
-	sp->rx_ring_dma[entry] =
-		pci_map_single(sp->pdev, rxf,
-					   PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
-	skb->dev = dev;
-	skb_reserve(skb, sizeof(struct RxFD));
-	rxf->rx_buf_addr = cpu_to_le32(0xffffffff);
-	pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry],
-								   sizeof(struct RxFD), PCI_DMA_TODEVICE);
-	return rxf;
-}
-
-static inline void speedo_rx_link(struct net_device *dev, int entry,
-								  struct RxFD *rxf, dma_addr_t rxf_dma)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	rxf->status = cpu_to_le32(0xC0000001); 	/* '1' for driver use only. */
-	rxf->link = 0;			/* None yet. */
-	rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
-	sp->last_rxf->link = cpu_to_le32(rxf_dma);
-	sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
-	pci_dma_sync_single_for_device(sp->pdev, sp->last_rxf_dma,
-								   sizeof(struct RxFD), PCI_DMA_TODEVICE);
-	sp->last_rxf = rxf;
-	sp->last_rxf_dma = rxf_dma;
-}
-
-static int speedo_refill_rx_buf(struct net_device *dev, int force)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	int entry;
-	struct RxFD *rxf;
-
-	entry = sp->dirty_rx % RX_RING_SIZE;
-	if (sp->rx_skbuff[entry] == NULL) {
-		rxf = speedo_rx_alloc(dev, entry);
-		if (rxf == NULL) {
-			unsigned int forw;
-			int forw_entry;
-			if (netif_msg_rx_err(sp) || !(sp->rx_ring_state & RrOOMReported)) {
-				printk(KERN_WARNING "%s: can't fill rx buffer (force %d)!\n",
-						dev->name, force);
-				sp->rx_ring_state |= RrOOMReported;
-			}
-			speedo_show_state(dev);
-			if (!force)
-				return -1;	/* Better luck next time!  */
-			/* Borrow an skb from one of next entries. */
-			for (forw = sp->dirty_rx + 1; forw != sp->cur_rx; forw++)
-				if (sp->rx_skbuff[forw % RX_RING_SIZE] != NULL)
-					break;
-			if (forw == sp->cur_rx)
-				return -1;
-			forw_entry = forw % RX_RING_SIZE;
-			sp->rx_skbuff[entry] = sp->rx_skbuff[forw_entry];
-			sp->rx_skbuff[forw_entry] = NULL;
-			rxf = sp->rx_ringp[forw_entry];
-			sp->rx_ringp[forw_entry] = NULL;
-			sp->rx_ringp[entry] = rxf;
-		}
-	} else {
-		rxf = sp->rx_ringp[entry];
-	}
-	speedo_rx_link(dev, entry, rxf, sp->rx_ring_dma[entry]);
-	sp->dirty_rx++;
-	sp->rx_ring_state &= ~(RrNoMem|RrOOMReported); /* Mark the progress. */
-	return 0;
-}
-
-static void speedo_refill_rx_buffers(struct net_device *dev, int force)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-
-	/* Refill the RX ring. */
-	while ((int)(sp->cur_rx - sp->dirty_rx) > 0 &&
-			speedo_refill_rx_buf(dev, force) != -1);
-}
-
-static int
-speedo_rx(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	int entry = sp->cur_rx % RX_RING_SIZE;
-	int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
-	int alloc_ok = 1;
-	int npkts = 0;
-
-	if (netif_msg_intr(sp))
-		printk(KERN_DEBUG " In speedo_rx().\n");
-	/* If we own the next entry, it's a new packet. Send it up. */
-	while (sp->rx_ringp[entry] != NULL) {
-		int status;
-		int pkt_len;
-
-		pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry],
-									sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
-		status = le32_to_cpu(sp->rx_ringp[entry]->status);
-		pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff;
-
-		if (!(status & RxComplete))
-			break;
-
-		if (--rx_work_limit < 0)
-			break;
-
-		/* Check for a rare out-of-memory case: the current buffer is
-		   the last buffer allocated in the RX ring.  --SAW */
-		if (sp->last_rxf == sp->rx_ringp[entry]) {
-			/* Postpone the packet.  It'll be reaped at an interrupt when this
-			   packet is no longer the last packet in the ring. */
-			if (netif_msg_rx_err(sp))
-				printk(KERN_DEBUG "%s: RX packet postponed!\n",
-					   dev->name);
-			sp->rx_ring_state |= RrPostponed;
-			break;
-		}
-
-		if (netif_msg_rx_status(sp))
-			printk(KERN_DEBUG "  speedo_rx() status %8.8x len %d.\n", status,
-				   pkt_len);
-		if ((status & (RxErrTooBig|RxOK|0x0f90)) != RxOK) {
-			if (status & RxErrTooBig)
-				printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
-					   "status %8.8x!\n", dev->name, status);
-			else if (! (status & RxOK)) {
-				/* There was a fatal error.  This *should* be impossible. */
-				sp->stats.rx_errors++;
-				printk(KERN_ERR "%s: Anomalous event in speedo_rx(), "
-					   "status %8.8x.\n",
-					   dev->name, status);
-			}
-		} else {
-			struct sk_buff *skb;
-
-			/* Check if the packet is long enough to just accept without
-			   copying to a properly sized skbuff. */
-			if (pkt_len < rx_copybreak
-				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-				/* 'skb_put()' points to the start of sk_buff data area. */
-				pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry],
-											sizeof(struct RxFD) + pkt_len,
-											PCI_DMA_FROMDEVICE);
-
-#if 1 || USE_IP_CSUM
-				/* Packet is in one chunk -- we can copy + cksum. */
-				skb_copy_to_linear_data(skb, sp->rx_skbuff[entry]->data, pkt_len);
-				skb_put(skb, pkt_len);
-#else
-				skb_copy_from_linear_data(sp->rx_skbuff[entry],
-							  skb_put(skb, pkt_len),
-							  pkt_len);
-#endif
-				pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry],
-											   sizeof(struct RxFD) + pkt_len,
-											   PCI_DMA_FROMDEVICE);
-				npkts++;
-			} else {
-				/* Pass up the already-filled skbuff. */
-				skb = sp->rx_skbuff[entry];
-				if (skb == NULL) {
-					printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n",
-						   dev->name);
-					break;
-				}
-				sp->rx_skbuff[entry] = NULL;
-				skb_put(skb, pkt_len);
-				npkts++;
-				sp->rx_ringp[entry] = NULL;
-				pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry],
-								 PKT_BUF_SZ + sizeof(struct RxFD),
-								 PCI_DMA_FROMDEVICE);
-			}
-			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
-			dev->last_rx = jiffies;
-			sp->stats.rx_packets++;
-			sp->stats.rx_bytes += pkt_len;
-		}
-		entry = (++sp->cur_rx) % RX_RING_SIZE;
-		sp->rx_ring_state &= ~RrPostponed;
-		/* Refill the recently taken buffers.
-		   Do it one-by-one to handle traffic bursts better. */
-		if (alloc_ok && speedo_refill_rx_buf(dev, 0) == -1)
-			alloc_ok = 0;
-	}
-
-	/* Try hard to refill the recently taken buffers. */
-	speedo_refill_rx_buffers(dev, 1);
-
-	if (npkts)
-		sp->last_rx_time = jiffies;
-
-	return 0;
-}
-
-static int
-speedo_close(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-	int i;
-
-	netdevice_stop(dev);
-	netif_stop_queue(dev);
-
-	if (netif_msg_ifdown(sp))
-		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
-			   dev->name, ioread16(ioaddr + SCBStatus));
-
-	/* Shut off the media monitoring timer. */
-	del_timer_sync(&sp->timer);
-
-	iowrite16(SCBMaskAll, ioaddr + SCBCmd);
-
-	/* Shutting down the chip nicely fails to disable flow control. So.. */
-	iowrite32(PortPartialReset, ioaddr + SCBPort);
-	ioread32(ioaddr + SCBPort); /* flush posted write */
-	/*
-	 * The chip requires a 10 microsecond quiet period.  Wait here!
-	 */
-	udelay(10);
-
-	free_irq(dev->irq, dev);
-	speedo_show_state(dev);
-
-    /* Free all the skbuffs in the Rx and Tx queues. */
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb = sp->rx_skbuff[i];
-		sp->rx_skbuff[i] = NULL;
-		/* Clear the Rx descriptors. */
-		if (skb) {
-			pci_unmap_single(sp->pdev,
-					 sp->rx_ring_dma[i],
-					 PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
-			dev_kfree_skb(skb);
-		}
-	}
-
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		struct sk_buff *skb = sp->tx_skbuff[i];
-		sp->tx_skbuff[i] = NULL;
-		/* Clear the Tx descriptors. */
-		if (skb) {
-			pci_unmap_single(sp->pdev,
-					 le32_to_cpu(sp->tx_ring[i].tx_buf_addr0),
-					 skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb(skb);
-		}
-	}
-
-	/* Free multicast setting blocks. */
-	for (i = 0; sp->mc_setup_head != NULL; i++) {
-		struct speedo_mc_block *t;
-		t = sp->mc_setup_head->next;
-		kfree(sp->mc_setup_head);
-		sp->mc_setup_head = t;
-	}
-	sp->mc_setup_tail = NULL;
-	if (netif_msg_ifdown(sp))
-		printk(KERN_DEBUG "%s: %d multicast blocks dropped.\n", dev->name, i);
-
-	pci_set_power_state(sp->pdev, PCI_D2);
-
-	return 0;
-}
-
-/* The Speedo-3 has an especially awkward and unusable method of getting
-   statistics out of the chip.  It takes an unpredictable length of time
-   for the dump-stats command to complete.  To avoid a busy-wait loop we
-   update the stats with the previous dump results, and then trigger a
-   new dump.
-
-   Oh, and incoming frames are dropped while executing dump-stats!
-   */
-static struct net_device_stats *
-speedo_get_stats(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-
-	/* Update only if the previous dump finished. */
-	if (sp->lstats->done_marker == cpu_to_le32(0xA007)) {
-		sp->stats.tx_aborted_errors += le32_to_cpu(sp->lstats->tx_coll16_errs);
-		sp->stats.tx_window_errors += le32_to_cpu(sp->lstats->tx_late_colls);
-		sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats->tx_underruns);
-		sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats->tx_lost_carrier);
-		/*sp->stats.tx_deferred += le32_to_cpu(sp->lstats->tx_deferred);*/
-		sp->stats.collisions += le32_to_cpu(sp->lstats->tx_total_colls);
-		sp->stats.rx_crc_errors += le32_to_cpu(sp->lstats->rx_crc_errs);
-		sp->stats.rx_frame_errors += le32_to_cpu(sp->lstats->rx_align_errs);
-		sp->stats.rx_over_errors += le32_to_cpu(sp->lstats->rx_resource_errs);
-		sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats->rx_overrun_errs);
-		sp->stats.rx_length_errors += le32_to_cpu(sp->lstats->rx_runt_errs);
-		sp->lstats->done_marker = 0x0000;
-		if (netif_running(dev)) {
-			unsigned long flags;
-			/* Take a spinlock to make wait_for_cmd_done and sending the
-			   command atomic.  --SAW */
-			spin_lock_irqsave(&sp->lock, flags);
-			wait_for_cmd_done(dev, sp);
-			iowrite8(CUDumpStats, ioaddr + SCBCmd);
-			spin_unlock_irqrestore(&sp->lock, flags);
-		}
-	}
-	return &sp->stats;
-}
-
-static void speedo_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	strncpy(info->driver, "eepro100", sizeof(info->driver)-1);
-	strncpy(info->version, version, sizeof(info->version)-1);
-	if (sp->pdev)
-		strcpy(info->bus_info, pci_name(sp->pdev));
-}
-
-static int speedo_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	spin_lock_irq(&sp->lock);
-	mii_ethtool_gset(&sp->mii_if, ecmd);
-	spin_unlock_irq(&sp->lock);
-	return 0;
-}
-
-static int speedo_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	int res;
-	spin_lock_irq(&sp->lock);
-	res = mii_ethtool_sset(&sp->mii_if, ecmd);
-	spin_unlock_irq(&sp->lock);
-	return res;
-}
-
-static int speedo_nway_reset(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	return mii_nway_restart(&sp->mii_if);
-}
-
-static u32 speedo_get_link(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	return mii_link_ok(&sp->mii_if);
-}
-
-static u32 speedo_get_msglevel(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	return sp->msg_enable;
-}
-
-static void speedo_set_msglevel(struct net_device *dev, u32 v)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	sp->msg_enable = v;
-}
-
-static const struct ethtool_ops ethtool_ops = {
-	.get_drvinfo = speedo_get_drvinfo,
-	.get_settings = speedo_get_settings,
-	.set_settings = speedo_set_settings,
-	.nway_reset = speedo_nway_reset,
-	.get_link = speedo_get_link,
-	.get_msglevel = speedo_get_msglevel,
-	.set_msglevel = speedo_set_msglevel,
-};
-
-static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	struct mii_ioctl_data *data = if_mii(rq);
-	int phy = sp->phy[0] & 0x1f;
-	int saved_acpi;
-	int t;
-
-    switch(cmd) {
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-		data->phy_id = phy;
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-		/* FIXME: these operations need to be serialized with MDIO
-		   access from the timeout handler.
-		   They are currently serialized only with MDIO access from the
-		   timer routine.  2000/05/09 SAW */
-		saved_acpi = pci_set_power_state(sp->pdev, PCI_D0);
-		t = del_timer_sync(&sp->timer);
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		if (t)
-			add_timer(&sp->timer); /* may be set to the past  --SAW */
-		pci_set_power_state(sp->pdev, saved_acpi);
-		return 0;
-
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		saved_acpi = pci_set_power_state(sp->pdev, PCI_D0);
-		t = del_timer_sync(&sp->timer);
-		mdio_write(dev, data->phy_id, data->reg_num, data->val_in);
-		if (t)
-			add_timer(&sp->timer); /* may be set to the past  --SAW */
-		pci_set_power_state(sp->pdev, saved_acpi);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
-	}
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   This is very ugly with Intel chips -- we usually have to execute an
-   entire configuration command, plus process a multicast command.
-   This is complicated.  We must put a large configuration command and
-   an arbitrarily-sized multicast command in the transmit list.
-   To minimize the disruption -- the previous command might have already
-   loaded the link -- we convert the current command block, normally a Tx
-   command, into a no-op and link it to the new command.
-*/
-static void set_rx_mode(struct net_device *dev)
-{
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-	struct descriptor *last_cmd;
-	char new_rx_mode;
-	unsigned long flags;
-	int entry, i;
-
-	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
-		new_rx_mode = 3;
-	} else if ((dev->flags & IFF_ALLMULTI)  ||
-			   dev->mc_count > multicast_filter_limit) {
-		new_rx_mode = 1;
-	} else
-		new_rx_mode = 0;
-
-	if (netif_msg_rx_status(sp))
-		printk(KERN_DEBUG "%s: set_rx_mode %d -> %d\n", dev->name,
-				sp->rx_mode, new_rx_mode);
-
-	if ((int)(sp->cur_tx - sp->dirty_tx) > TX_RING_SIZE - TX_MULTICAST_SIZE) {
-	    /* The Tx ring is full -- don't add anything!  Hope the mode will be
-		 * set again later. */
-		sp->rx_mode = -1;
-		return;
-	}
-
-	if (new_rx_mode != sp->rx_mode) {
-		u8 *config_cmd_data;
-
-		spin_lock_irqsave(&sp->lock, flags);
-		entry = sp->cur_tx++ % TX_RING_SIZE;
-		last_cmd = sp->last_cmd;
-		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
-
-		sp->tx_skbuff[entry] = NULL;			/* Redundant. */
-		sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdConfigure);
-		sp->tx_ring[entry].link =
-			cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
-		config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr;
-		/* Construct a full CmdConfig frame. */
-		memcpy(config_cmd_data, i82558_config_cmd, CONFIG_DATA_SIZE);
-		config_cmd_data[1] = (txfifo << 4) | rxfifo;
-		config_cmd_data[4] = rxdmacount;
-		config_cmd_data[5] = txdmacount + 0x80;
-		config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
-		/* 0x80 doesn't disable FC 0x84 does.
-		   Disable Flow control since we are not ACK-ing any FC interrupts
-		   for now. --Dragan */
-		config_cmd_data[19] = 0x84;
-		config_cmd_data[19] |= sp->mii_if.full_duplex ? 0x40 : 0;
-		config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
-		if (sp->phy[0] & 0x8000) {			/* Use the AUI port instead. */
-			config_cmd_data[15] |= 0x80;
-			config_cmd_data[8] = 0;
-		}
-		/* Trigger the command unit resume. */
-		wait_for_cmd_done(dev, sp);
-		clear_suspend(last_cmd);
-		iowrite8(CUResume, ioaddr + SCBCmd);
-		if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-			netif_stop_queue(dev);
-			sp->tx_full = 1;
-		}
-		spin_unlock_irqrestore(&sp->lock, flags);
-	}
-
-	if (new_rx_mode == 0  &&  dev->mc_count < 4) {
-		/* The simple case of 0-3 multicast list entries occurs often, and
-		   fits within one tx_ring[] entry. */
-		struct dev_mc_list *mclist;
-		__le16 *setup_params, *eaddrs;
-
-		spin_lock_irqsave(&sp->lock, flags);
-		entry = sp->cur_tx++ % TX_RING_SIZE;
-		last_cmd = sp->last_cmd;
-		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
-
-		sp->tx_skbuff[entry] = NULL;
-		sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdMulticastList);
-		sp->tx_ring[entry].link =
-			cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
-		sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
-		setup_params = (__le16 *)&sp->tx_ring[entry].tx_desc_addr;
-		*setup_params++ = cpu_to_le16(dev->mc_count*6);
-		/* Fill in the multicast addresses. */
-		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
-			 i++, mclist = mclist->next) {
-			eaddrs = (__le16 *)mclist->dmi_addr;
-			*setup_params++ = *eaddrs++;
-			*setup_params++ = *eaddrs++;
-			*setup_params++ = *eaddrs++;
-		}
-
-		wait_for_cmd_done(dev, sp);
-		clear_suspend(last_cmd);
-		/* Immediately trigger the command unit resume. */
-		iowrite8(CUResume, ioaddr + SCBCmd);
-
-		if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-			netif_stop_queue(dev);
-			sp->tx_full = 1;
-		}
-		spin_unlock_irqrestore(&sp->lock, flags);
-	} else if (new_rx_mode == 0) {
-		struct dev_mc_list *mclist;
-		__le16 *setup_params, *eaddrs;
-		struct speedo_mc_block *mc_blk;
-		struct descriptor *mc_setup_frm;
-		int i;
-
-		mc_blk = kmalloc(sizeof(*mc_blk) + 2 + multicast_filter_limit*6,
-						 GFP_ATOMIC);
-		if (mc_blk == NULL) {
-			printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
-				   dev->name);
-			sp->rx_mode = -1; /* We failed, try again. */
-			return;
-		}
-		mc_blk->next = NULL;
-		mc_blk->len = 2 + multicast_filter_limit*6;
-		mc_blk->frame_dma =
-			pci_map_single(sp->pdev, &mc_blk->frame, mc_blk->len,
-					PCI_DMA_TODEVICE);
-		mc_setup_frm = &mc_blk->frame;
-
-		/* Fill the setup frame. */
-		if (netif_msg_ifup(sp))
-			printk(KERN_DEBUG "%s: Constructing a setup frame at %p.\n",
-				   dev->name, mc_setup_frm);
-		mc_setup_frm->cmd_status =
-			cpu_to_le32(CmdSuspend | CmdIntr | CmdMulticastList);
-		/* Link set below. */
-		setup_params = (__le16 *)&mc_setup_frm->params;
-		*setup_params++ = cpu_to_le16(dev->mc_count*6);
-		/* Fill in the multicast addresses. */
-		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
-			 i++, mclist = mclist->next) {
-			eaddrs = (__le16 *)mclist->dmi_addr;
-			*setup_params++ = *eaddrs++;
-			*setup_params++ = *eaddrs++;
-			*setup_params++ = *eaddrs++;
-		}
-
-		/* Disable interrupts while playing with the Tx Cmd list. */
-		spin_lock_irqsave(&sp->lock, flags);
-
-		if (sp->mc_setup_tail)
-			sp->mc_setup_tail->next = mc_blk;
-		else
-			sp->mc_setup_head = mc_blk;
-		sp->mc_setup_tail = mc_blk;
-		mc_blk->tx = sp->cur_tx;
-
-		entry = sp->cur_tx++ % TX_RING_SIZE;
-		last_cmd = sp->last_cmd;
-		sp->last_cmd = mc_setup_frm;
-
-		/* Change the command to a NoOp, pointing to the CmdMulti command. */
-		sp->tx_skbuff[entry] = NULL;
-		sp->tx_ring[entry].status = cpu_to_le32(CmdNOp);
-		sp->tx_ring[entry].link = cpu_to_le32(mc_blk->frame_dma);
-
-		/* Set the link in the setup frame. */
-		mc_setup_frm->link =
-			cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
-
-		pci_dma_sync_single_for_device(sp->pdev, mc_blk->frame_dma,
-									   mc_blk->len, PCI_DMA_TODEVICE);
-
-		wait_for_cmd_done(dev, sp);
-		clear_suspend(last_cmd);
-		/* Immediately trigger the command unit resume. */
-		iowrite8(CUResume, ioaddr + SCBCmd);
-
-		if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
-			netif_stop_queue(dev);
-			sp->tx_full = 1;
-		}
-		spin_unlock_irqrestore(&sp->lock, flags);
-
-		if (netif_msg_rx_status(sp))
-			printk(" CmdMCSetup frame length %d in entry %d.\n",
-				   dev->mc_count, entry);
-	}
-
-	sp->rx_mode = new_rx_mode;
-}
-
-#ifdef CONFIG_PM
-static int eepro100_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-	struct net_device *dev = pci_get_drvdata (pdev);
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-
-	pci_save_state(pdev);
-
-	if (!netif_running(dev))
-		return 0;
-
-	del_timer_sync(&sp->timer);
-
-	netif_device_detach(dev);
-	iowrite32(PortPartialReset, ioaddr + SCBPort);
-
-	/* XXX call pci_set_power_state ()? */
-	pci_disable_device(pdev);
-	pci_set_power_state (pdev, PCI_D3hot);
-	return 0;
-}
-
-static int eepro100_resume(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata (pdev);
-	struct speedo_private *sp = netdev_priv(dev);
-	void __iomem *ioaddr = sp->regs;
-	int rc;
-
-	pci_set_power_state(pdev, PCI_D0);
-	pci_restore_state(pdev);
-
-	rc = pci_enable_device(pdev);
-	if (rc)
-		return rc;
-
-	pci_set_master(pdev);
-
-	if (!netif_running(dev))
-		return 0;
-
-	/* I'm absolutely uncertain if this part of code may work.
-	   The problems are:
-	    - correct hardware reinitialization;
-		- correct driver behavior between different steps of the
-		  reinitialization;
-		- serialization with other driver calls.
-	   2000/03/08  SAW */
-	iowrite16(SCBMaskAll, ioaddr + SCBCmd);
-	speedo_resume(dev);
-	netif_device_attach(dev);
-	sp->rx_mode = -1;
-	sp->flow_ctrl = sp->partner = 0;
-	set_rx_mode(dev);
-	sp->timer.expires = RUN_AT(2*HZ);
-	add_timer(&sp->timer);
-	return 0;
-}
-#endif /* CONFIG_PM */
-
-static void __devexit eepro100_remove_one (struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata (pdev);
-	struct speedo_private *sp = netdev_priv(dev);
-
-	unregister_netdev(dev);
-
-	release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
-	release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
-
-	pci_iounmap(pdev, sp->regs);
-	pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
-								+ sizeof(struct speedo_stats),
-						sp->tx_ring, sp->tx_ring_dma);
-	pci_disable_device(pdev);
-	free_netdev(dev);
-}
-
-static struct pci_device_id eepro100_pci_tbl[] = {
-	{ PCI_VENDOR_ID_INTEL, 0x1229, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1209, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1029, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1030, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1031, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1032, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1033, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1034, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1035, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1036, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1037, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1038, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1039, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x103A, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x103B, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x103C, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x103D, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x103E, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1050, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1059, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x1227, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x2449, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x2459, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x245D, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x5200, PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, 0x5201, PCI_ANY_ID, PCI_ANY_ID, },
-	{ 0,}
-};
-MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);
-
-static struct pci_driver eepro100_driver = {
-	.name		= "eepro100",
-	.id_table	= eepro100_pci_tbl,
-	.probe		= eepro100_init_one,
-	.remove		= __devexit_p(eepro100_remove_one),
-#ifdef CONFIG_PM
-	.suspend	= eepro100_suspend,
-	.resume		= eepro100_resume,
-#endif /* CONFIG_PM */
-};
-
-static int __init eepro100_init_module(void)
-{
-#ifdef MODULE
-	printk(version);
-#endif
-	return pci_register_driver(&eepro100_driver);
-}
-
-static void __exit eepro100_cleanup_module(void)
-{
-	pci_unregister_driver(&eepro100_driver);
-}
-
-module_init(eepro100_init_module);
-module_exit(eepro100_cleanup_module);
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index b751c1b..9ff3f2f 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -967,7 +967,6 @@
 			        insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1);
 				skb->protocol = eth_type_trans(skb,dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += pkt_len;
 			}
@@ -1047,7 +1046,7 @@
 /*
  * Sanity check the suspected EtherExpress card
  * Read hardware address, reset card, size memory and initialize buffer
- * memory pointers. These are held in dev->priv, in case someone has more
+ * memory pointers. These are held in netdev_priv(), in case someone has more
  * than one card in a machine.
  */
 
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 002d918..9930d5f 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -40,7 +40,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME	"ehea"
-#define DRV_VERSION	"EHEA_0095"
+#define DRV_VERSION	"EHEA_0096"
 
 /* eHEA capability flags */
 #define DLPAR_PORT_ADD_REM 1
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 422fcb9..a2f1905 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -728,7 +728,6 @@
 			}
 
 			ehea_proc_skb(pr, cqe, skb);
-			dev->last_rx = jiffies;
 		} else {
 			pr->p_stats.poll_receive_errors++;
 			port_reset = ehea_treat_poll_error(pr, rq, cqe,
@@ -831,7 +830,7 @@
 	while ((rx != budget) || force_irq) {
 		pr->poll_counter = 0;
 		force_irq = 0;
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		ehea_reset_cq_ep(pr->recv_cq);
 		ehea_reset_cq_ep(pr->send_cq);
 		ehea_reset_cq_n1(pr->recv_cq);
@@ -842,7 +841,7 @@
 		if (!cqe && !cqe_skb)
 			return rx;
 
-		if (!netif_rx_reschedule(dev, napi))
+		if (!netif_rx_reschedule(napi))
 			return rx;
 
 		cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES);
@@ -860,7 +859,7 @@
 	int i;
 
 	for (i = 0; i < port->num_def_qps; i++)
-		netif_rx_schedule(dev, &port->port_res[i].napi);
+		netif_rx_schedule(&port->port_res[i].napi);
 }
 #endif
 
@@ -868,7 +867,7 @@
 {
 	struct ehea_port_res *pr = param;
 
-	netif_rx_schedule(pr->port->netdev, &pr->napi);
+	netif_rx_schedule(&pr->napi);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index 9d00687..225c692 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -182,7 +182,7 @@
 				goto out_kill_hwq;
 			}
 		} else {
-			if ((hret != H_PAGE_REGISTERED) || (!vpage)) {
+			if (hret != H_PAGE_REGISTERED) {
 				ehea_error("CQ: registration of page failed "
 					   "hret=%lx\n", hret);
 				goto out_kill_hwq;
@@ -303,7 +303,7 @@
 				goto out_kill_hwq;
 
 		} else {
-			if ((hret != H_PAGE_REGISTERED) || (!vpage))
+			if (hret != H_PAGE_REGISTERED)
 				goto out_kill_hwq;
 
 		}
@@ -653,7 +653,7 @@
 		int top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT);
 		int dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT);
 		int idx = i & EHEA_INDEX_MASK;
-		
+
 		if (add) {
 			int ret = ehea_init_bmap(ehea_bmap, top, dir);
 			if (ret)
@@ -780,7 +780,7 @@
 
 	kfree(ehea_bmap);
 	ehea_bmap = NULL;
-out_destroy:	
+out_destroy:
 	mutex_unlock(&ehea_busmap_mutex);
 }
 
@@ -858,10 +858,10 @@
 	for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) {
 		if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
 			continue;
-		
+
 		hret = ehea_reg_mr_section(top, dir, idx, pt, adapter, mr);
 		if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
-			    	return hret;
+			return hret;
 	}
 	return hret;
 }
@@ -879,7 +879,7 @@
 
 		hret = ehea_reg_mr_sections(top, dir, pt, adapter, mr);
 		if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
-			    	return hret;
+			return hret;
 	}
 	return hret;
 }
@@ -893,7 +893,7 @@
 
 	unsigned long top;
 
-	pt = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	pt = (void *)get_zeroed_page(GFP_KERNEL);
 	if (!pt) {
 		ehea_error("no mem");
 		ret = -ENOMEM;
@@ -937,7 +937,7 @@
 	mr->adapter = adapter;
 	ret = 0;
 out:
-	kfree(pt);
+	free_page((unsigned long)pt);
 	return ret;
 }
 
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index 36cb6e9..b0ef46c 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -196,16 +196,32 @@
  */
 static void enc28j60_set_bank(struct enc28j60_net *priv, u8 addr)
 {
-	if ((addr & BANK_MASK) != priv->bank) {
-		u8 b = (addr & BANK_MASK) >> 5;
+	u8 b = (addr & BANK_MASK) >> 5;
 
-		if (b != (ECON1_BSEL1 | ECON1_BSEL0))
+	/* These registers (EIE, EIR, ESTAT, ECON2, ECON1)
+	 * are present in all banks, no need to switch bank
+	 */
+	if (addr >= EIE && addr <= ECON1)
+		return;
+
+	/* Clear or set each bank selection bit as needed */
+	if ((b & ECON1_BSEL0) != (priv->bank & ECON1_BSEL0)) {
+		if (b & ECON1_BSEL0)
+			spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1,
+					ECON1_BSEL0);
+		else
 			spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1,
-				     ECON1_BSEL1 | ECON1_BSEL0);
-		if (b != 0)
-			spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, b);
-		priv->bank = (addr & BANK_MASK);
+					ECON1_BSEL0);
 	}
+	if ((b & ECON1_BSEL1) != (priv->bank & ECON1_BSEL1)) {
+		if (b & ECON1_BSEL1)
+			spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1,
+					ECON1_BSEL1);
+		else
+			spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1,
+					ECON1_BSEL1);
+	}
+	priv->bank = b;
 }
 
 /*
@@ -477,12 +493,10 @@
 
 	mutex_lock(&priv->lock);
 	if (!priv->hw_enable) {
-		if (netif_msg_drv(priv)) {
-			DECLARE_MAC_BUF(mac);
+		if (netif_msg_drv(priv))
 			printk(KERN_INFO DRV_NAME
-				": %s: Setting MAC address to %s\n",
-				ndev->name, print_mac(mac, ndev->dev_addr));
-		}
+				": %s: Setting MAC address to %pM\n",
+				ndev->name, ndev->dev_addr);
 		/* NOTE: MAC address in ENC28J60 is byte-backward */
 		nolock_regb_write(priv, MAADR5, ndev->dev_addr[0]);
 		nolock_regb_write(priv, MAADR4, ndev->dev_addr[1]);
@@ -958,7 +972,6 @@
 			/* update statistics */
 			ndev->stats.rx_packets++;
 			ndev->stats.rx_bytes += len;
-			ndev->last_rx = jiffies;
 			netif_rx_ni(skb);
 		}
 	}
@@ -1340,11 +1353,9 @@
 		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
 
 	if (!is_valid_ether_addr(dev->dev_addr)) {
-		if (netif_msg_ifup(priv)) {
-			DECLARE_MAC_BUF(mac);
-			dev_err(&dev->dev, "invalid MAC address %s\n",
-				print_mac(mac, dev->dev_addr));
-		}
+		if (netif_msg_ifup(priv))
+			dev_err(&dev->dev, "invalid MAC address %pM\n",
+				dev->dev_addr);
 		return -EADDRNOTAVAIL;
 	}
 	/* Reset the hardware here (and take it out of low power mode) */
@@ -1465,7 +1476,7 @@
 	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
 	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 	strlcpy(info->bus_info,
-		dev->dev.parent->bus_id, sizeof(info->bus_info));
+		dev_name(dev->dev.parent), sizeof(info->bus_info));
 }
 
 static int
diff --git a/drivers/net/enic/cq_desc.h b/drivers/net/enic/cq_desc.h
index c036a8b..1eb289f 100644
--- a/drivers/net/enic/cq_desc.h
+++ b/drivers/net/enic/cq_desc.h
@@ -44,9 +44,10 @@
 	u8 type_color;
 };
 
-#define CQ_DESC_TYPE_BITS        7
+#define CQ_DESC_TYPE_BITS        4
 #define CQ_DESC_TYPE_MASK        ((1 << CQ_DESC_TYPE_BITS) - 1)
 #define CQ_DESC_COLOR_MASK       1
+#define CQ_DESC_COLOR_SHIFT      7
 #define CQ_DESC_Q_NUM_BITS       10
 #define CQ_DESC_Q_NUM_MASK       ((1 << CQ_DESC_Q_NUM_BITS) - 1)
 #define CQ_DESC_COMP_NDX_BITS    12
@@ -58,7 +59,7 @@
 	const struct cq_desc *desc = desc_arg;
 	const u8 type_color = desc->type_color;
 
-	*color = (type_color >> CQ_DESC_TYPE_BITS) & CQ_DESC_COLOR_MASK;
+	*color = (type_color >> CQ_DESC_COLOR_SHIFT) & CQ_DESC_COLOR_MASK;
 
 	/*
 	 * Make sure color bit is read from desc *before* other fields
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index 7f677e8..a832cc5 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -33,7 +33,7 @@
 
 #define DRV_NAME		"enic"
 #define DRV_DESCRIPTION		"Cisco 10G Ethernet Driver"
-#define DRV_VERSION		"0.0.1-18163.472-k1"
+#define DRV_VERSION		"1.0.0.648"
 #define DRV_COPYRIGHT		"Copyright 2008 Cisco Systems, Inc"
 #define PFX			DRV_NAME ": "
 
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 180e968..d039e16 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -273,6 +273,8 @@
 	.set_sg = ethtool_op_set_sg,
 	.get_tso = ethtool_op_get_tso,
 	.set_tso = enic_set_tso,
+	.get_flags = ethtool_op_get_flags,
+	.set_flags = ethtool_op_set_flags,
 };
 
 static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
@@ -409,8 +411,8 @@
 	}
 
 	if (ENIC_TEST_INTR(pba, ENIC_INTX_WQ_RQ)) {
-		if (netif_rx_schedule_prep(netdev, &enic->napi))
-			__netif_rx_schedule(netdev, &enic->napi);
+		if (netif_rx_schedule_prep(&enic->napi))
+			__netif_rx_schedule(&enic->napi);
 	} else {
 		vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]);
 	}
@@ -438,7 +440,7 @@
 	 * writes).
 	 */
 
-	netif_rx_schedule(enic->netdev, &enic->napi);
+	netif_rx_schedule(&enic->napi);
 
 	return IRQ_HANDLED;
 }
@@ -448,7 +450,7 @@
 	struct enic *enic = data;
 
 	/* schedule NAPI polling for RQ cleanup */
-	netif_rx_schedule(enic->netdev, &enic->napi);
+	netif_rx_schedule(&enic->napi);
 
 	return IRQ_HANDLED;
 }
@@ -895,6 +897,7 @@
 	int skipped, void *opaque)
 {
 	struct enic *enic = vnic_dev_priv(rq->vdev);
+	struct net_device *netdev = enic->netdev;
 	struct sk_buff *skb;
 
 	u8 type, color, eop, sop, ingress_port, vlan_stripped;
@@ -929,7 +932,7 @@
 			if (net_ratelimit())
 				printk(KERN_ERR PFX
 					"%s: packet error: bad FCS\n",
-					enic->netdev->name);
+					netdev->name);
 		}
 
 		dev_kfree_skb_any(skb);
@@ -943,19 +946,18 @@
 		 */
 
 		skb_put(skb, bytes_written);
-		skb->protocol = eth_type_trans(skb, enic->netdev);
+		skb->protocol = eth_type_trans(skb, netdev);
 
 		if (enic->csum_rx_enabled && !csum_not_calc) {
 			skb->csum = htons(checksum);
 			skb->ip_summed = CHECKSUM_COMPLETE;
 		}
 
-		skb->dev = enic->netdev;
-		enic->netdev->last_rx = jiffies;
+		skb->dev = netdev;
 
 		if (enic->vlan_group && vlan_stripped) {
 
-			if (ENIC_SETTING(enic, LRO) && ipv4)
+			if ((netdev->features & NETIF_F_LRO) && ipv4)
 				lro_vlan_hwaccel_receive_skb(&enic->lro_mgr,
 					skb, enic->vlan_group,
 					vlan, cq_desc);
@@ -965,7 +967,7 @@
 
 		} else {
 
-			if (ENIC_SETTING(enic, LRO) && ipv4)
+			if ((netdev->features & NETIF_F_LRO) && ipv4)
 				lro_receive_skb(&enic->lro_mgr, skb, cq_desc);
 			else
 				netif_receive_skb(skb);
@@ -1063,10 +1065,10 @@
 		/* If no work done, flush all LROs and exit polling
 		 */
 
-		if (ENIC_SETTING(enic, LRO))
+		if (netdev->features & NETIF_F_LRO)
 			lro_flush_all(&enic->lro_mgr);
 
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 		vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]);
 	}
 
@@ -1107,10 +1109,10 @@
 		/* If no work done, flush all LROs and exit polling
 		 */
 
-		if (ENIC_SETTING(enic, LRO))
+		if (netdev->features & NETIF_F_LRO)
 			lro_flush_all(&enic->lro_mgr);
 
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 		vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]);
 	}
 
@@ -1591,6 +1593,23 @@
 		iounmap(enic->bar0.vaddr);
 }
 
+static const struct net_device_ops enic_netdev_ops = {
+	.ndo_open		= enic_open,
+	.ndo_stop		= enic_stop,
+	.ndo_start_xmit		= enic_hard_start_xmit,
+	.ndo_get_stats		= enic_get_stats,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_multicast_list	= enic_set_multicast_list,
+	.ndo_change_mtu		= enic_change_mtu,
+	.ndo_vlan_rx_register	= enic_vlan_rx_register,
+	.ndo_vlan_rx_add_vid	= enic_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= enic_vlan_rx_kill_vid,
+	.ndo_tx_timeout		= enic_tx_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= enic_poll_controller,
+#endif
+};
+
 static int __devinit enic_probe(struct pci_dev *pdev,
 	const struct pci_device_id *ent)
 {
@@ -1746,13 +1765,13 @@
 	}
 
 	/* Get available resource counts
-	*/
+	 */
 
 	enic_get_res_counts(enic);
 
 	/* Set interrupt mode based on resource counts and system
 	 * capabilities
-	*/
+	 */
 
 	err = enic_set_intr_mode(enic);
 	if (err) {
@@ -1814,21 +1833,9 @@
 		goto err_out_free_vnic_resources;
 	}
 
-	netdev->open = enic_open;
-	netdev->stop = enic_stop;
-	netdev->hard_start_xmit = enic_hard_start_xmit;
-	netdev->get_stats = enic_get_stats;
-	netdev->set_multicast_list = enic_set_multicast_list;
-	netdev->change_mtu = enic_change_mtu;
-	netdev->vlan_rx_register = enic_vlan_rx_register;
-	netdev->vlan_rx_add_vid = enic_vlan_rx_add_vid;
-	netdev->vlan_rx_kill_vid = enic_vlan_rx_kill_vid;
-	netdev->tx_timeout = enic_tx_timeout;
+	netdev->netdev_ops = &enic_netdev_ops;
 	netdev->watchdog_timeo = 2 * HZ;
 	netdev->ethtool_ops = &enic_ethtool_ops;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	netdev->poll_controller = enic_poll_controller;
-#endif
 
 	switch (vnic_dev_get_intr_mode(enic->vdev)) {
 	default:
@@ -1845,22 +1852,23 @@
 	if (ENIC_SETTING(enic, TSO))
 		netdev->features |= NETIF_F_TSO |
 			NETIF_F_TSO6 | NETIF_F_TSO_ECN;
+	if (ENIC_SETTING(enic, LRO))
+		netdev->features |= NETIF_F_LRO;
 	if (using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
 
 	enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM);
 
-	if (ENIC_SETTING(enic, LRO)) {
-		enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR;
-		enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC;
-		enic->lro_mgr.lro_arr = enic->lro_desc;
-		enic->lro_mgr.get_skb_header = enic_get_skb_header;
-		enic->lro_mgr.features	= LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
-		enic->lro_mgr.dev = netdev;
-		enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE;
-		enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
-	}
+	enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR;
+	enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC;
+	enic->lro_mgr.lro_arr = enic->lro_desc;
+	enic->lro_mgr.get_skb_header = enic_get_skb_header;
+	enic->lro_mgr.features	= LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
+	enic->lro_mgr.dev = netdev;
+	enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE;
+	enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
+
 
 	err = register_netdev(netdev);
 	if (err) {
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index 95184b9..e5fc938 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -90,11 +90,8 @@
 
 	c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer);
 
-	printk(KERN_INFO PFX "vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x "
-		"wq/rq %d/%d\n",
-		enic->mac_addr[0], enic->mac_addr[1], enic->mac_addr[2],
-		enic->mac_addr[3], enic->mac_addr[4], enic->mac_addr[5],
-		c->wq_desc_count, c->rq_desc_count);
+	printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n",
+		enic->mac_addr, c->wq_desc_count, c->rq_desc_count);
 	printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d "
 		"intr timer %d\n",
 		c->mtu, ENIC_SETTING(enic, TXCSUM),
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h
index 68534a2..7bf272f 100644
--- a/drivers/net/enic/enic_res.h
+++ b/drivers/net/enic/enic_res.h
@@ -58,8 +58,6 @@
 		(u16)vlan_tag,
 		0 /* loopback */);
 
-	wmb();
-
 	vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop);
 }
 
@@ -127,8 +125,6 @@
 		(u64)dma_addr | VNIC_PADDR_TARGET,
 		type, (u16)len);
 
-	wmb();
-
 	vnic_rq_post(rq, os_buf, os_buf_index, dma_addr, len);
 }
 
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c
index 4d104f5..1170857 100644
--- a/drivers/net/enic/vnic_dev.c
+++ b/drivers/net/enic/vnic_dev.c
@@ -43,6 +43,7 @@
 	struct vnic_devcmd_notify *notify;
 	struct vnic_devcmd_notify notify_copy;
 	dma_addr_t notify_pa;
+	u32 notify_sz;
 	u32 *linkstatus;
 	dma_addr_t linkstatus_pa;
 	struct vnic_stats *stats;
@@ -235,14 +236,6 @@
 	struct vnic_devcmd __iomem *devcmd = vdev->devcmd;
 	int delay;
 	u32 status;
-	int dev_cmd_err[] = {
-		/* convert from fw's version of error.h to host's version */
-		0,	/* ERR_SUCCESS */
-		EINVAL,	/* ERR_EINVAL */
-		EFAULT,	/* ERR_EFAULT */
-		EPERM,	/* ERR_EPERM */
-		EBUSY,  /* ERR_EBUSY */
-	};
 	int err;
 
 	status = ioread32(&devcmd->status);
@@ -270,10 +263,12 @@
 		if (!(status & STAT_BUSY)) {
 
 			if (status & STAT_ERROR) {
-				err = dev_cmd_err[(int)readq(&devcmd->args[0])];
-				printk(KERN_ERR "Error %d devcmd %d\n",
-					err, _CMD_N(cmd));
-				return -err;
+				err = (int)readq(&devcmd->args[0]);
+				if (err != ERR_ECMDUNKNOWN ||
+				    cmd != CMD_CAPABILITY)
+					printk(KERN_ERR "Error %d devcmd %d\n",
+						err, _CMD_N(cmd));
+				return err;
 			}
 
 			if (_CMD_DIR(cmd) & _CMD_DIR_READ) {
@@ -290,6 +285,17 @@
 	return -ETIMEDOUT;
 }
 
+static int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd)
+{
+	u64 a0 = (u32)cmd, a1 = 0;
+	int wait = 1000;
+	int err;
+
+	err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait);
+
+	return !(err || a0);
+}
+
 int vnic_dev_fw_info(struct vnic_dev *vdev,
 	struct vnic_devcmd_fw_info **fw_info)
 {
@@ -489,10 +495,7 @@
 
 	err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
 	if (err)
-		printk(KERN_ERR
-			"Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n",
-			addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
-			err);
+		printk(KERN_ERR "Can't add addr [%pM], %d\n", addr, err);
 }
 
 void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
@@ -507,16 +510,14 @@
 
 	err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait);
 	if (err)
-		printk(KERN_ERR
-			"Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n",
-			addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
-			err);
+		printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err);
 }
 
 int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
 {
 	u64 a0, a1;
 	int wait = 1000;
+	int r;
 
 	if (!vdev->notify) {
 		vdev->notify = pci_alloc_consistent(vdev->pdev,
@@ -524,13 +525,16 @@
 			&vdev->notify_pa);
 		if (!vdev->notify)
 			return -ENOMEM;
+		memset(vdev->notify, 0, sizeof(struct vnic_devcmd_notify));
 	}
 
 	a0 = vdev->notify_pa;
 	a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL;
 	a1 += sizeof(struct vnic_devcmd_notify);
 
-	return vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
+	r = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
+	vdev->notify_sz = (r == 0) ? (u32)a1 : 0;
+	return r;
 }
 
 void vnic_dev_notify_unset(struct vnic_dev *vdev)
@@ -543,22 +547,22 @@
 	a1 += sizeof(struct vnic_devcmd_notify);
 
 	vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
+	vdev->notify_sz = 0;
 }
 
 static int vnic_dev_notify_ready(struct vnic_dev *vdev)
 {
 	u32 *words;
-	unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4;
+	unsigned int nwords = vdev->notify_sz / 4;
 	unsigned int i;
 	u32 csum;
 
-	if (!vdev->notify)
+	if (!vdev->notify || !vdev->notify_sz)
 		return 0;
 
 	do {
 		csum = 0;
-		memcpy(&vdev->notify_copy, vdev->notify,
-			sizeof(struct vnic_devcmd_notify));
+		memcpy(&vdev->notify_copy, vdev->notify, vdev->notify_sz);
 		words = (u32 *)&vdev->notify_copy;
 		for (i = 1; i < nwords; i++)
 			csum += words[i];
@@ -571,7 +575,20 @@
 {
 	u64 a0 = (u32)arg, a1 = 0;
 	int wait = 1000;
-	return vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait);
+        int r = 0;
+
+	if (vnic_dev_capable(vdev, CMD_INIT))
+		r = vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait);
+	else {
+		vnic_dev_cmd(vdev, CMD_INIT_v1, &a0, &a1, wait);
+		if (a0 & CMD_INITF_DEFAULT_MAC) {
+			// Emulate these for old CMD_INIT_v1 which
+			// didn't pass a0 so no CMD_INITF_*.
+			vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait);
+			vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
+		}
+        }
+        return r;
 }
 
 int vnic_dev_link_status(struct vnic_dev *vdev)
@@ -672,3 +689,4 @@
 	return NULL;
 }
 
+
diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h
index d8617a3..8062c75 100644
--- a/drivers/net/enic/vnic_devcmd.h
+++ b/drivers/net/enic/vnic_devcmd.h
@@ -168,7 +168,8 @@
 	CMD_CLOSE		= _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 25),
 
 	/* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */
-	CMD_INIT		= _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26),
+/***** Replaced by CMD_INIT *****/
+	CMD_INIT_v1		= _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26),
 
 	/* variant of CMD_INIT, with provisioning info
 	 *     (u64)a0=paddr of vnic_devcmd_provinfo
@@ -198,6 +199,14 @@
 
 	/* undo initialize of virtual link */
 	CMD_DEINIT		= _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 34),
+
+	/* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */
+	CMD_INIT		= _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 35),
+
+	/* check fw capability of a cmd:
+	 * in:  (u32)a0=cmd
+	 * out: (u32)a0=errno, 0:valid cmd, a1=supported VNIC_STF_* bits */
+	CMD_CAPABILITY		= _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 36),
 };
 
 /* flags for CMD_OPEN */
@@ -249,8 +258,16 @@
 	u32 uif;		/* uplink interface */
 	u32 status;		/* status bits (see VNIC_STF_*) */
 	u32 error;		/* error code (see ERR_*) for first ERR */
+	u32 link_down_cnt;	/* running count of link down transitions */
 };
 #define VNIC_STF_FATAL_ERR	0x0001	/* fatal fw error */
+#define VNIC_STF_STD_PAUSE	0x0002	/* standard link-level pause on */
+#define VNIC_STF_PFC_PAUSE	0x0004	/* priority flow control pause on */
+/* all supported status flags */
+#define VNIC_STF_ALL		(VNIC_STF_FATAL_ERR |\
+				 VNIC_STF_STD_PAUSE |\
+				 VNIC_STF_PFC_PAUSE |\
+				 0)
 
 struct vnic_devcmd_provinfo {
 	u8 oui[3];
diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h
index ccc4081..ce633a5 100644
--- a/drivers/net/enic/vnic_intr.h
+++ b/drivers/net/enic/vnic_intr.h
@@ -78,7 +78,7 @@
 
 static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba)
 {
-	/* get and ack interrupt in one read (clear-and-ack-on-read) */
+	/* read PBA without clearing */
 	return ioread32(legacy_pba);
 }
 
diff --git a/drivers/net/enic/vnic_resource.h b/drivers/net/enic/vnic_resource.h
index 144d281..b61c22a 100644
--- a/drivers/net/enic/vnic_resource.h
+++ b/drivers/net/enic/vnic_resource.h
@@ -38,7 +38,7 @@
 	RES_TYPE_INTR_CTRL,		/* Interrupt ctrl table */
 	RES_TYPE_INTR_TABLE,		/* MSI/MSI-X Interrupt table */
 	RES_TYPE_INTR_PBA,		/* MSI/MSI-X PBA table */
-	RES_TYPE_INTR_PBA_LEGACY,	/* Legacy intr status, r2c */
+	RES_TYPE_INTR_PBA_LEGACY,	/* Legacy intr status */
 	RES_TYPE_RSVD6,
 	RES_TYPE_RSVD7,
 	RES_TYPE_DEVCMD,		/* Device command region */
diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h
index 82bfca6..fd0ef66 100644
--- a/drivers/net/enic/vnic_rq.h
+++ b/drivers/net/enic/vnic_rq.h
@@ -132,8 +132,15 @@
 #define VNIC_RQ_RETURN_RATE		0xf	/* keep 2^n - 1 */
 #endif
 
-	if ((buf->index & VNIC_RQ_RETURN_RATE) == 0)
+	if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) {
+		/* Adding write memory barrier prevents compiler and/or CPU
+		 * reordering, thus avoiding descriptor posting before
+		 * descriptor is initialized. Otherwise, hardware can read
+		 * stale descriptor fields.
+		 */
+		wmb();
 		iowrite32(buf->index, &rq->ctrl->posted_index);
+	}
 }
 
 static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count)
diff --git a/drivers/net/enic/vnic_rss.h b/drivers/net/enic/vnic_rss.h
index e325d65..5fbb3c9 100644
--- a/drivers/net/enic/vnic_rss.h
+++ b/drivers/net/enic/vnic_rss.h
@@ -1,6 +1,19 @@
 /*
  * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
  * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may 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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
  */
 
 #ifndef _VNIC_RSS_H_
diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/enic/vnic_wq.h
index 7081828..c826137 100644
--- a/drivers/net/enic/vnic_wq.h
+++ b/drivers/net/enic/vnic_wq.h
@@ -108,8 +108,15 @@
 	buf->len = len;
 
 	buf = buf->next;
-	if (eop)
+	if (eop) {
+		/* Adding write memory barrier prevents compiler and/or CPU
+		 * reordering, thus avoiding descriptor posting before
+		 * descriptor is initialized. Otherwise, hardware can read
+		 * stale descriptor fields.
+		 */
+		wmb();
 		iowrite32(buf->index, &wq->ctrl->posted_index);
+	}
 	wq->to_use = buf;
 
 	wq->ring.desc_avail--;
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 76118ddd..f9b37c8 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -322,7 +322,6 @@
 	int i, ret, option = 0, duplex = 0;
 	void *ring_space;
 	dma_addr_t ring_dma;
-	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -364,7 +363,7 @@
 	ioaddr = pci_resource_start (pdev, 0);
 #else
 	ioaddr = pci_resource_start (pdev, 1);
-	ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
+	ioaddr = (long) pci_ioremap_bar(pdev, 1);
 	if (!ioaddr) {
 		dev_err(&pdev->dev, "ioremap failed\n");
 		goto err_out_free_netdev;
@@ -372,7 +371,7 @@
 #endif
 
 	pci_set_drvdata(pdev, dev);
-	ep = dev->priv;
+	ep = netdev_priv(dev);
 	ep->mii.dev = dev;
 	ep->mii.mdio_read = mdio_read;
 	ep->mii.mdio_write = mdio_write;
@@ -499,9 +498,9 @@
 	if (ret < 0)
 		goto err_out_unmap_rx;
 
-	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n",
+	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %pM\n",
 	       dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq,
-	       print_mac(mac, dev->dev_addr));
+	       dev->dev_addr);
 
 out:
 	return ret;
@@ -655,7 +654,7 @@
 
 static int epic_open(struct net_device *dev)
 {
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i;
 	int retval;
@@ -767,7 +766,7 @@
 static void epic_pause(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 
 	netif_stop_queue (dev);
 
@@ -790,7 +789,7 @@
 static void epic_restart(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	int i;
 
 	/* Soft reset the chip. */
@@ -842,7 +841,7 @@
 
 static void check_media(struct net_device *dev)
 {
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int mii_lpa = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], MII_LPA) : 0;
 	int negotiated = mii_lpa & ep->mii.advertising;
@@ -864,7 +863,7 @@
 static void epic_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int next_tick = 5*HZ;
 
@@ -885,7 +884,7 @@
 
 static void epic_tx_timeout(struct net_device *dev)
 {
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	if (debug > 0) {
@@ -914,7 +913,7 @@
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void epic_init_ring(struct net_device *dev)
 {
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	int i;
 
 	ep->tx_full = 0;
@@ -960,7 +959,7 @@
 
 static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	int entry, free_count;
 	u32 ctrl_word;
 	unsigned long flags;
@@ -1088,7 +1087,7 @@
 static irqreturn_t epic_interrupt(int irq, void *dev_instance)
 {
 	struct net_device *dev = dev_instance;
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	unsigned int handled = 0;
 	int status;
@@ -1110,9 +1109,9 @@
 
 	if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) {
 		spin_lock(&ep->napi_lock);
-		if (netif_rx_schedule_prep(dev, &ep->napi)) {
+		if (netif_rx_schedule_prep(&ep->napi)) {
 			epic_napi_irq_off(dev, ep);
-			__netif_rx_schedule(dev, &ep->napi);
+			__netif_rx_schedule(&ep->napi);
 		} else
 			ep->reschedule_in_poll++;
 		spin_unlock(&ep->napi_lock);
@@ -1156,7 +1155,7 @@
 
 static int epic_rx(struct net_device *dev, int budget)
 {
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	int entry = ep->cur_rx % RX_RING_SIZE;
 	int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx;
 	int work_done = 0;
@@ -1223,7 +1222,6 @@
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_receive_skb(skb);
-			dev->last_rx = jiffies;
 			ep->stats.rx_packets++;
 			ep->stats.rx_bytes += pkt_len;
 		}
@@ -1290,7 +1288,7 @@
 
 		more = ep->reschedule_in_poll;
 		if (!more) {
-			__netif_rx_complete(dev, napi);
+			__netif_rx_complete(napi);
 			outl(EpicNapiEvent, ioaddr + INTSTAT);
 			epic_napi_irq_on(dev, ep);
 		} else
@@ -1308,7 +1306,7 @@
 static int epic_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	struct sk_buff *skb;
 	int i;
 
@@ -1358,7 +1356,7 @@
 
 static struct net_device_stats *epic_get_stats(struct net_device *dev)
 {
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	if (netif_running(dev)) {
@@ -1379,7 +1377,7 @@
 static void set_rx_mode(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 	unsigned char mc_filter[8];		 /* Multicast hash filter */
 	int i;
 
@@ -1418,7 +1416,7 @@
 
 static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct epic_private *np = dev->priv;
+	struct epic_private *np = netdev_priv(dev);
 
 	strcpy (info->driver, DRV_NAME);
 	strcpy (info->version, DRV_VERSION);
@@ -1427,7 +1425,7 @@
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct epic_private *np = dev->priv;
+	struct epic_private *np = netdev_priv(dev);
 	int rc;
 
 	spin_lock_irq(&np->lock);
@@ -1439,7 +1437,7 @@
 
 static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct epic_private *np = dev->priv;
+	struct epic_private *np = netdev_priv(dev);
 	int rc;
 
 	spin_lock_irq(&np->lock);
@@ -1451,13 +1449,13 @@
 
 static int netdev_nway_reset(struct net_device *dev)
 {
-	struct epic_private *np = dev->priv;
+	struct epic_private *np = netdev_priv(dev);
 	return mii_nway_restart(&np->mii);
 }
 
 static u32 netdev_get_link(struct net_device *dev)
 {
-	struct epic_private *np = dev->priv;
+	struct epic_private *np = netdev_priv(dev);
 	return mii_link_ok(&np->mii);
 }
 
@@ -1506,7 +1504,7 @@
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct epic_private *np = dev->priv;
+	struct epic_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	struct mii_ioctl_data *data = if_mii(rq);
 	int rc;
@@ -1534,7 +1532,7 @@
 static void __devexit epic_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct epic_private *ep = dev->priv;
+	struct epic_private *ep = netdev_priv(dev);
 
 	pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
 	pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index 18f1364..4012569 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -162,6 +162,13 @@
 static char version[] __initdata =
 	"Equalizer2002: Simon Janes (simon@ncm.com) and David S. Miller (davem@redhat.com)\n";
 
+static const struct net_device_ops eql_netdev_ops = {
+	.ndo_open	= eql_open,
+	.ndo_stop	= eql_close,
+	.ndo_do_ioctl	= eql_ioctl,
+	.ndo_start_xmit	= eql_slave_xmit,
+};
+
 static void __init eql_setup(struct net_device *dev)
 {
 	equalizer_t *eql = netdev_priv(dev);
@@ -175,10 +182,7 @@
 	INIT_LIST_HEAD(&eql->queue.all_slaves);
 	eql->queue.master_dev	= dev;
 
-	dev->open		= eql_open;
-	dev->stop		= eql_close;
-	dev->do_ioctl		= eql_ioctl;
-	dev->hard_start_xmit	= eql_slave_xmit;
+	dev->netdev_ops		= &eql_netdev_ops;
 
 	/*
 	 *	Now we undo some of the things that eth_setup does
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index deefa51..5569f2f 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -64,9 +64,6 @@
 
 static int es_probe1(struct net_device *dev, int ioaddr);
 
-static int es_open(struct net_device *dev);
-static int es_close(struct net_device *dev);
-
 static void es_reset_8390(struct net_device *dev);
 
 static void es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
@@ -179,7 +176,6 @@
 {
 	int i, retval;
 	unsigned long eisa_id;
-	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210"))
 		return -ENODEV;
@@ -205,14 +201,14 @@
 	if (dev->dev_addr[0] != ES_ADDR0 ||
 	    dev->dev_addr[1] != ES_ADDR1 ||
 	    dev->dev_addr[2] != ES_ADDR2) {
-		printk("es3210.c: card not found %s (invalid_prefix).\n",
-		       print_mac(mac, dev->dev_addr));
+		printk("es3210.c: card not found %pM (invalid_prefix).\n",
+		       dev->dev_addr);
 		retval = -ENODEV;
 		goto out;
 	}
 
-	printk("es3210.c: ES3210 rev. %ld at %#x, node %s",
-	       eisa_id>>24, ioaddr, print_mac(mac, dev->dev_addr));
+	printk("es3210.c: ES3210 rev. %ld at %#x, node %pM",
+	       eisa_id>>24, ioaddr, dev->dev_addr);
 
 	/* Snarf the interrupt now. */
 	if (dev->irq == 0) {
@@ -290,11 +286,7 @@
 	ei_status.block_output = &es_block_output;
 	ei_status.get_8390_hdr = &es_get_8390_hdr;
 
-	dev->open = &es_open;
-	dev->stop = &es_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = ei_poll;
-#endif
+	dev->netdev_ops = &ei_netdev_ops;
 	NS8390_init(dev, 0);
 
 	retval = register_netdev(dev);
@@ -386,22 +378,6 @@
 	memcpy_toio(shmem, buf, count);
 }
 
-static int es_open(struct net_device *dev)
-{
-	ei_open(dev);
-	return 0;
-}
-
-static int es_close(struct net_device *dev)
-{
-
-	if (ei_debug > 1)
-		printk("%s: Shutting down ethercard.\n", dev->name);
-
-	ei_close(dev);
-	return 0;
-}
-
 #ifdef MODULE
 #define MAX_ES_CARDS	4	/* Max number of ES3210 cards per module */
 #define NAMELEN		8	/* # of chars for storing dev->name */
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index bee8b3f..5c048f2 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -1205,7 +1205,6 @@
 				printk(KERN_DEBUG ".\n");
 			}
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += pkt_len;
 
@@ -1466,7 +1465,7 @@
 	for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) {
 		struct net_device *dev = dev_eth16i[this_dev];
 
-		if(dev->priv) {
+		if (netdev_priv(dev)) {
 			unregister_netdev(dev);
 			free_irq(dev->irq, dev);
 			release_region(dev->base_addr, ETH16I_IO_EXTENT);
@@ -1475,15 +1474,3 @@
 	}
 }
 #endif /* MODULE */
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eth16i.c"
- *  alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict -prototypes -O6 -c eth16i.c"
- *  tab-width: 8
- *  c-basic-offset: 8
- *  c-indent-level: 8
- * End:
- */
-
-/* End of file eth16i.c */
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index 593a120..b852303 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -396,7 +396,6 @@
 	u_long mem_start, shmem_length;
 	u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0;
 	u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0;
-	DECLARE_MAC_BUF(mac);
 
 	/*
 	** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot.
@@ -461,7 +460,7 @@
 	if (lemac != LeMAC2)
 		DevicePresent(iobase);	/* need after EWRK3_INIT */
 	status = get_hw_addr(dev, eeprom_image, lemac);
-	printk("%s\n", print_mac(mac, dev->dev_addr));
+	printk("%pM\n", dev->dev_addr);
 
 	if (status) {
 		printk("      which has an EEPROM CRC error.\n");
@@ -646,10 +645,8 @@
 			ewrk3_init(dev);
 
 			if (ewrk3_debug > 1) {
-				DECLARE_MAC_BUF(mac);
 				printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq);
-				printk("  physical address: %s\n",
-				       print_mac(mac, dev->dev_addr));
+				printk("  physical address: %pM\n", dev->dev_addr);
 				if (lp->shmem_length == 0) {
 					printk("  no shared memory, I/O only mode\n");
 				} else {
@@ -1029,7 +1026,6 @@
 						/*
 						   ** Update stats
 						 */
-						dev->last_rx = jiffies;
 						dev->stats.rx_packets++;
 						dev->stats.rx_bytes += pkt_len;
 					} else {
@@ -1971,13 +1967,3 @@
 module_init(ewrk3_init_module);
 #endif				/* MODULE */
 MODULE_LICENSE("GPL");
-
-
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c ewrk3.c"
- *
- *  compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c ewrk3.c"
- * End:
- */
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index b455ae9..31ab1ff 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -486,7 +486,6 @@
 #else
 	int bar = 1;
 #endif
-	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -665,9 +664,9 @@
 	if (err)
 		goto err_out_free_tx;
 
-	printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+	printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n",
 	       dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr,
-	       print_mac(mac, dev->dev_addr), irq);
+	       dev->dev_addr, irq);
 
 	return 0;
 
@@ -1727,7 +1726,6 @@
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			np->stats.rx_packets++;
 			np->stats.rx_bytes += pkt_len;
 		}
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index ecd5c71..7e33c12 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -1155,7 +1155,7 @@
 
 static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev)
 {
-	struct fec_enet_private *fep = dev->priv;
+	struct fec_enet_private *fep = netdev_priv(dev);
 	volatile uint *s = &(fep->phy_status);
 
 	*s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
@@ -2562,7 +2562,6 @@
 {
 	struct net_device *dev;
 	int i, err;
-	DECLARE_MAC_BUF(mac);
 
 	printk("FEC ENET Version 0.2\n");
 
@@ -2581,8 +2580,7 @@
 			return -EIO;
 		}
 
-		printk("%s: ethernet %s\n",
-		       dev->name, print_mac(mac, dev->dev_addr));
+		printk("%s: ethernet %pM\n", dev->name, dev->dev_addr);
 	}
 	return 0;
 }
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index aec3b97..cd8e98b 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -216,7 +216,7 @@
 	struct phy_device *phydev;
 	char phy_id[BUS_ID_SIZE];
 
-	snprintf(phy_id, BUS_ID_SIZE, "%x:%02x",
+	snprintf(phy_id, sizeof(phy_id), "%x:%02x",
 			(unsigned int)dev->base_addr, priv->phy_addr);
 
 	priv->link = PHY_DOWN;
@@ -487,7 +487,6 @@
 			rskb->protocol = eth_type_trans(rskb, dev);
 
 			netif_rx(rskb);
-			dev->last_rx = jiffies;
 		} else {
 			/* Can't get a new one : reuse the same & drop pkt */
 			dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n");
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
index 45dd9bd..dd9bfa4 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -122,9 +122,6 @@
 	out_be32(&priv->regs->mii_speed,
 		((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
 
-	/* enable MII interrupt */
-	out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII);
-
 	err = mdiobus_register(bus);
 	if (err)
 		goto out_unmap;
@@ -156,7 +153,7 @@
 
 	iounmap(priv->regs);
 	for (i=0; i<PHY_MAX_ADDR; i++)
-		if (bus->irq[i])
+		if (bus->irq[i] != PHY_POLL)
 			irq_dispose_mapping(bus->irq[i]);
 	kfree(priv);
 	kfree(bus->irq);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index cc7328b..5b68dc2 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -712,12 +712,12 @@
 
 /*
  * SMP locking:
- * All hardware access under dev->priv->lock, except the performance
+ * All hardware access under netdev_priv(dev)->lock, except the performance
  * critical parts:
  * - rx is (pseudo-) lockless: it relies on the single-threading provided
  *	by the arch code for interrupts.
  * - tx setup is lockless: it relies on netif_tx_lock. Actual submission
- *	needs dev->priv->lock :-(
+ *	needs netdev_priv(dev)->lock :-(
  * - set_multicast_list: preparation lockless, relies on netif_tx_lock.
  */
 
@@ -818,7 +818,7 @@
  * Maximum number of loops until we assume that a bit in the irq mask
  * is stuck. Overridable with module param.
  */
-static int max_interrupt_work = 5;
+static int max_interrupt_work = 15;
 
 /*
  * Optimization can be either throuput mode or cpu mode
@@ -1446,9 +1446,9 @@
 	/* some phys clear out pause advertisment on reset, set it back */
 	mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg);
 
-	/* restart auto negotiation */
+	/* restart auto negotiation, power down phy */
 	mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
-	mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE);
+	mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE | BMCR_PDOWN);
 	if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) {
 		return PHY_ERROR;
 	}
@@ -1760,7 +1760,7 @@
 	struct fe_priv *np = netdev_priv(dev);
 
 	/* Just reschedule NAPI rx processing */
-	netif_rx_schedule(dev, &np->napi);
+	netif_rx_schedule(&np->napi);
 }
 #else
 static void nv_do_rx_refill(unsigned long data)
@@ -2735,7 +2735,6 @@
 #else
 		netif_rx(skb);
 #endif
-		dev->last_rx = jiffies;
 		dev->stats.rx_packets++;
 		dev->stats.rx_bytes += len;
 next_pkt:
@@ -2848,7 +2847,6 @@
 				}
 			}
 
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += len;
 		} else {
@@ -3405,7 +3403,7 @@
 
 #ifdef CONFIG_FORCEDETH_NAPI
 		if (events & NVREG_IRQ_RX_ALL) {
-			netif_rx_schedule(dev, &np->napi);
+			netif_rx_schedule(&np->napi);
 
 			/* Disable furthur receive irq's */
 			spin_lock(&np->lock);
@@ -3522,7 +3520,7 @@
 
 #ifdef CONFIG_FORCEDETH_NAPI
 		if (events & NVREG_IRQ_RX_ALL) {
-			netif_rx_schedule(dev, &np->napi);
+			netif_rx_schedule(&np->napi);
 
 			/* Disable furthur receive irq's */
 			spin_lock(&np->lock);
@@ -3680,7 +3678,7 @@
 		/* re-enable receive interrupts */
 		spin_lock_irqsave(&np->lock, flags);
 
-		__netif_rx_complete(dev, napi);
+		__netif_rx_complete(napi);
 
 		np->irqmask |= NVREG_IRQ_RX_ALL;
 		if (np->msi_flags & NV_MSI_X_ENABLED)
@@ -3706,7 +3704,7 @@
 	writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
 
 	if (events) {
-		netif_rx_schedule(dev, &np->napi);
+		netif_rx_schedule(&np->napi);
 		/* disable receive interrupts on the nic */
 		writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
 		pci_push(base);
@@ -5210,6 +5208,10 @@
 
 	dprintk(KERN_DEBUG "nv_open: begin\n");
 
+	/* power up phy */
+	mii_rw(dev, np->phyaddr, MII_BMCR,
+	       mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ) & ~BMCR_PDOWN);
+
 	/* erase previous misconfiguration */
 	if (np->driver_data & DEV_HAS_POWER_CNTRL)
 		nv_mac_reset(dev);
@@ -5403,6 +5405,10 @@
 	if (np->wolenabled) {
 		writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags);
 		nv_start_rx(dev);
+	} else {
+		/* power down phy */
+		mii_rw(dev, np->phyaddr, MII_BMCR,
+		       mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ)|BMCR_PDOWN);
 	}
 
 	/* FIXME: power down nic */
@@ -5410,6 +5416,38 @@
 	return 0;
 }
 
+static const struct net_device_ops nv_netdev_ops = {
+	.ndo_open		= nv_open,
+	.ndo_stop		= nv_close,
+	.ndo_get_stats		= nv_get_stats,
+	.ndo_start_xmit		= nv_start_xmit,
+	.ndo_tx_timeout		= nv_tx_timeout,
+	.ndo_change_mtu		= nv_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= nv_set_mac_address,
+	.ndo_set_multicast_list	= nv_set_multicast,
+	.ndo_vlan_rx_register	= nv_vlan_rx_register,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= nv_poll_controller,
+#endif
+};
+
+static const struct net_device_ops nv_netdev_ops_optimized = {
+	.ndo_open		= nv_open,
+	.ndo_stop		= nv_close,
+	.ndo_get_stats		= nv_get_stats,
+	.ndo_start_xmit		= nv_start_xmit_optimized,
+	.ndo_tx_timeout		= nv_tx_timeout,
+	.ndo_change_mtu		= nv_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= nv_set_mac_address,
+	.ndo_set_multicast_list	= nv_set_multicast,
+	.ndo_vlan_rx_register	= nv_vlan_rx_register,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= nv_poll_controller,
+#endif
+};
+
 static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 {
 	struct net_device *dev;
@@ -5420,7 +5458,6 @@
 	u32 powerstate, txreg;
 	u32 phystate_orig = 0, phystate;
 	int phyinitialized = 0;
-	DECLARE_MAC_BUF(mac);
 	static int printed_version;
 
 	if (!printed_version++)
@@ -5530,7 +5567,6 @@
 	if (id->driver_data & DEV_HAS_VLAN) {
 		np->vlanctl_bits = NVREG_VLANCONTROL_ENABLE;
 		dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX;
-		dev->vlan_rx_register = nv_vlan_rx_register;
 	}
 
 	np->msi_flags = 0;
@@ -5580,25 +5616,15 @@
 	if (!np->rx_skb || !np->tx_skb)
 		goto out_freering;
 
-	dev->open = nv_open;
-	dev->stop = nv_close;
-
 	if (!nv_optimized(np))
-		dev->hard_start_xmit = nv_start_xmit;
+		dev->netdev_ops = &nv_netdev_ops;
 	else
-		dev->hard_start_xmit = nv_start_xmit_optimized;
-	dev->get_stats = nv_get_stats;
-	dev->change_mtu = nv_change_mtu;
-	dev->set_mac_address = nv_set_mac_address;
-	dev->set_multicast_list = nv_set_multicast;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = nv_poll_controller;
-#endif
+		dev->netdev_ops = &nv_netdev_ops_optimized;
+
 #ifdef CONFIG_FORCEDETH_NAPI
 	netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP);
 #endif
 	SET_ETHTOOL_OPS(dev, &ops);
-	dev->tx_timeout = nv_tx_timeout;
 	dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
 
 	pci_set_drvdata(pci_dev, dev);
@@ -5653,8 +5679,8 @@
 		 * to 01:23:45:67:89:ab
 		 */
 		dev_printk(KERN_ERR, &pci_dev->dev,
-			"Invalid Mac address detected: %s\n",
-		        print_mac(mac, dev->dev_addr));
+			"Invalid Mac address detected: %pM\n",
+		        dev->dev_addr);
 		dev_printk(KERN_ERR, &pci_dev->dev,
 			"Please complain to your hardware vendor. Switching to a random MAC.\n");
 		dev->dev_addr[0] = 0x00;
@@ -5663,8 +5689,8 @@
 		get_random_bytes(&dev->dev_addr[3], 3);
 	}
 
-	dprintk(KERN_DEBUG "%s: MAC Address %s\n",
-		pci_name(pci_dev), print_mac(mac, dev->dev_addr));
+	dprintk(KERN_DEBUG "%s: MAC Address %pM\n",
+		pci_name(pci_dev), dev->dev_addr);
 
 	/* set mac address */
 	nv_copy_mac_to_hw(dev);
@@ -6141,7 +6167,7 @@
 	},
 	{	/* MCP79 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+		.driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
 	},
 	{	/* MCP79 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37),
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index a6f49d0..4e6a919 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -209,7 +209,7 @@
 
 	if (received < budget) {
 		/* done */
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		(*fep->ops->napi_enable_rx)(dev);
 	}
 	return received;
@@ -478,7 +478,7 @@
 				/* NOTE: it is possible for FCCs in NAPI mode    */
 				/* to submit a spurious interrupt while in poll  */
 				if (napi_ok)
-					__netif_rx_schedule(dev, &fep->napi);
+					__netif_rx_schedule(&fep->napi);
 			}
 		}
 
@@ -1117,10 +1117,7 @@
 	if (ret)
 		goto out_free_bd;
 
-	printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       ndev->name,
-	       ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
-	       ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+	printk(KERN_INFO "%s: fs_enet: %pM\n", ndev->name, ndev->dev_addr);
 
 	return 0;
 
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index c4af949..c672ecf 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -25,11 +25,8 @@
  *
  *  Theory of operation
  *
- *  The driver is initialized through platform_device.  Structures which
- *  define the configuration needed by the board are defined in a
- *  board structure in arch/ppc/platforms (though I do not
- *  discount the possibility that other architectures could one
- *  day be supported.
+ *  The driver is initialized through of_device. Configuration information
+ *  is therefore conveyed through an OF-style device tree.
  *
  *  The Gianfar Ethernet Controller uses a ring of buffer
  *  descriptors.  The beginning is indicated by a register
@@ -78,7 +75,7 @@
 #include <linux/if_vlan.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
-#include <linux/platform_device.h>
+#include <linux/of_platform.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
@@ -92,6 +89,8 @@
 #include <linux/crc32.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/of.h>
 
 #include "gianfar.h"
 #include "gianfar_mii.h"
@@ -119,8 +118,9 @@
 static void adjust_link(struct net_device *dev);
 static void init_registers(struct net_device *dev);
 static int init_phy(struct net_device *dev);
-static int gfar_probe(struct platform_device *pdev);
-static int gfar_remove(struct platform_device *pdev);
+static int gfar_probe(struct of_device *ofdev,
+		const struct of_device_id *match);
+static int gfar_remove(struct of_device *ofdev);
 static void free_skb_resources(struct gfar_private *priv);
 static void gfar_set_multi(struct net_device *dev);
 static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
@@ -131,7 +131,8 @@
 #endif
 int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 static int gfar_clean_tx_ring(struct net_device *dev);
-static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
+static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
+			      int amount_pull);
 static void gfar_vlan_rx_register(struct net_device *netdev,
 		                struct vlan_group *grp);
 void gfar_halt(struct net_device *dev);
@@ -149,29 +150,163 @@
 /* Returns 1 if incoming frames use an FCB */
 static inline int gfar_uses_fcb(struct gfar_private *priv)
 {
-	return (priv->vlan_enable || priv->rx_csum_enable);
+	return priv->vlgrp || priv->rx_csum_enable;
+}
+
+static int gfar_of_init(struct net_device *dev)
+{
+	struct device_node *phy, *mdio;
+	const unsigned int *id;
+	const char *model;
+	const char *ctype;
+	const void *mac_addr;
+	const phandle *ph;
+	u64 addr, size;
+	int err = 0;
+	struct gfar_private *priv = netdev_priv(dev);
+	struct device_node *np = priv->node;
+	char bus_name[MII_BUS_ID_SIZE];
+
+	if (!np || !of_device_is_available(np))
+		return -ENODEV;
+
+	/* get a pointer to the register memory */
+	addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
+	priv->regs = ioremap(addr, size);
+
+	if (priv->regs == NULL)
+		return -ENOMEM;
+
+	priv->interruptTransmit = irq_of_parse_and_map(np, 0);
+
+	model = of_get_property(np, "model", NULL);
+
+	/* If we aren't the FEC we have multiple interrupts */
+	if (model && strcasecmp(model, "FEC")) {
+		priv->interruptReceive = irq_of_parse_and_map(np, 1);
+
+		priv->interruptError = irq_of_parse_and_map(np, 2);
+
+		if (priv->interruptTransmit < 0 ||
+				priv->interruptReceive < 0 ||
+				priv->interruptError < 0) {
+			err = -EINVAL;
+			goto err_out;
+		}
+	}
+
+	mac_addr = of_get_mac_address(np);
+	if (mac_addr)
+		memcpy(dev->dev_addr, mac_addr, MAC_ADDR_LEN);
+
+	if (model && !strcasecmp(model, "TSEC"))
+		priv->device_flags =
+			FSL_GIANFAR_DEV_HAS_GIGABIT |
+			FSL_GIANFAR_DEV_HAS_COALESCE |
+			FSL_GIANFAR_DEV_HAS_RMON |
+			FSL_GIANFAR_DEV_HAS_MULTI_INTR;
+	if (model && !strcasecmp(model, "eTSEC"))
+		priv->device_flags =
+			FSL_GIANFAR_DEV_HAS_GIGABIT |
+			FSL_GIANFAR_DEV_HAS_COALESCE |
+			FSL_GIANFAR_DEV_HAS_RMON |
+			FSL_GIANFAR_DEV_HAS_MULTI_INTR |
+			FSL_GIANFAR_DEV_HAS_PADDING |
+			FSL_GIANFAR_DEV_HAS_CSUM |
+			FSL_GIANFAR_DEV_HAS_VLAN |
+			FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
+			FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
+
+	ctype = of_get_property(np, "phy-connection-type", NULL);
+
+	/* We only care about rgmii-id.  The rest are autodetected */
+	if (ctype && !strcmp(ctype, "rgmii-id"))
+		priv->interface = PHY_INTERFACE_MODE_RGMII_ID;
+	else
+		priv->interface = PHY_INTERFACE_MODE_MII;
+
+	if (of_get_property(np, "fsl,magic-packet", NULL))
+		priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
+
+	ph = of_get_property(np, "phy-handle", NULL);
+	if (ph == NULL) {
+		u32 *fixed_link;
+
+		fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL);
+		if (!fixed_link) {
+			err = -ENODEV;
+			goto err_out;
+		}
+
+		snprintf(priv->phy_bus_id, BUS_ID_SIZE, PHY_ID_FMT, "0",
+				fixed_link[0]);
+	} else {
+		phy = of_find_node_by_phandle(*ph);
+
+		if (phy == NULL) {
+			err = -ENODEV;
+			goto err_out;
+		}
+
+		mdio = of_get_parent(phy);
+
+		id = of_get_property(phy, "reg", NULL);
+
+		of_node_put(phy);
+		of_node_put(mdio);
+
+		gfar_mdio_bus_name(bus_name, mdio);
+		snprintf(priv->phy_bus_id, BUS_ID_SIZE, "%s:%02x",
+				bus_name, *id);
+	}
+
+	/* Find the TBI PHY.  If it's not there, we don't support SGMII */
+	ph = of_get_property(np, "tbi-handle", NULL);
+	if (ph) {
+		struct device_node *tbi = of_find_node_by_phandle(*ph);
+		struct of_device *ofdev;
+		struct mii_bus *bus;
+
+		if (!tbi)
+			return 0;
+
+		mdio = of_get_parent(tbi);
+		if (!mdio)
+			return 0;
+
+		ofdev = of_find_device_by_node(mdio);
+
+		of_node_put(mdio);
+
+		id = of_get_property(tbi, "reg", NULL);
+		if (!id)
+			return 0;
+
+		of_node_put(tbi);
+
+		bus = dev_get_drvdata(&ofdev->dev);
+
+		priv->tbiphy = bus->phy_map[*id];
+	}
+
+	return 0;
+
+err_out:
+	iounmap(priv->regs);
+	return err;
 }
 
 /* Set up the ethernet device structure, private data,
  * and anything else we need before we start */
-static int gfar_probe(struct platform_device *pdev)
+static int gfar_probe(struct of_device *ofdev,
+		const struct of_device_id *match)
 {
 	u32 tempval;
 	struct net_device *dev = NULL;
 	struct gfar_private *priv = NULL;
-	struct gianfar_platform_data *einfo;
-	struct resource *r;
-	int err = 0, irq;
 	DECLARE_MAC_BUF(mac);
-
-	einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
-
-	if (NULL == einfo) {
-		printk(KERN_ERR "gfar %d: Missing additional data!\n",
-		       pdev->id);
-
-		return -ENODEV;
-	}
+	int err = 0;
+	int len_devname;
 
 	/* Create an ethernet device instance */
 	dev = alloc_etherdev(sizeof (*priv));
@@ -181,64 +316,23 @@
 
 	priv = netdev_priv(dev);
 	priv->dev = dev;
+	priv->node = ofdev->node;
 
-	/* Set the info in the priv to the current info */
-	priv->einfo = einfo;
+	err = gfar_of_init(dev);
 
-	/* fill out IRQ fields */
-	if (einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-		irq = platform_get_irq_byname(pdev, "tx");
-		if (irq < 0)
-			goto regs_fail;
-		priv->interruptTransmit = irq;
-
-		irq = platform_get_irq_byname(pdev, "rx");
-		if (irq < 0)
-			goto regs_fail;
-		priv->interruptReceive = irq;
-
-		irq = platform_get_irq_byname(pdev, "error");
-		if (irq < 0)
-			goto regs_fail;
-		priv->interruptError = irq;
-	} else {
-		irq = platform_get_irq(pdev, 0);
-		if (irq < 0)
-			goto regs_fail;
-		priv->interruptTransmit = irq;
-	}
-
-	/* get a pointer to the register memory */
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	priv->regs = ioremap(r->start, sizeof (struct gfar));
-
-	if (NULL == priv->regs) {
-		err = -ENOMEM;
+	if (err)
 		goto regs_fail;
-	}
 
 	spin_lock_init(&priv->txlock);
 	spin_lock_init(&priv->rxlock);
 	spin_lock_init(&priv->bflock);
 	INIT_WORK(&priv->reset_task, gfar_reset_task);
 
-	platform_set_drvdata(pdev, dev);
+	dev_set_drvdata(&ofdev->dev, priv);
 
 	/* Stop the DMA engine now, in case it was running before */
 	/* (The firmware could have used it, and left it running). */
-	/* To do this, we write Graceful Receive Stop and Graceful */
-	/* Transmit Stop, and then wait until the corresponding bits */
-	/* in IEVENT indicate the stops have completed. */
-	tempval = gfar_read(&priv->regs->dmactrl);
-	tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
-	gfar_write(&priv->regs->dmactrl, tempval);
-
-	tempval = gfar_read(&priv->regs->dmactrl);
-	tempval |= (DMACTRL_GRS | DMACTRL_GTS);
-	gfar_write(&priv->regs->dmactrl, tempval);
-
-	while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)))
-		cpu_relax();
+	gfar_halt(dev);
 
 	/* Reset MAC layer */
 	gfar_write(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
@@ -252,13 +346,10 @@
 	/* Initialize ECNTRL */
 	gfar_write(&priv->regs->ecntrl, ECNTRL_INIT_SETTINGS);
 
-	/* Copy the station address into the dev structure, */
-	memcpy(dev->dev_addr, einfo->mac_addr, MAC_ADDR_LEN);
-
 	/* Set the dev->base_addr to the gfar reg region */
 	dev->base_addr = (unsigned long) (priv->regs);
 
-	SET_NETDEV_DEV(dev, &pdev->dev);
+	SET_NETDEV_DEV(dev, &ofdev->dev);
 
 	/* Fill in the dev structure */
 	dev->open = gfar_enet_open;
@@ -276,23 +367,21 @@
 
 	dev->ethtool_ops = &gfar_ethtool_ops;
 
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
 		priv->rx_csum_enable = 1;
-		dev->features |= NETIF_F_IP_CSUM;
+		dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA;
 	} else
 		priv->rx_csum_enable = 0;
 
 	priv->vlgrp = NULL;
 
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
 		dev->vlan_rx_register = gfar_vlan_rx_register;
 
 		dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-
-		priv->vlan_enable = 1;
 	}
 
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
 		priv->extended_hash = 1;
 		priv->hash_width = 9;
 
@@ -327,7 +416,7 @@
 		priv->hash_regs[7] = &priv->regs->gaddr7;
 	}
 
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)
 		priv->padding = DEFAULT_PADDING;
 	else
 		priv->padding = 0;
@@ -338,13 +427,12 @@
 	priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
 	priv->tx_ring_size = DEFAULT_TX_RING_SIZE;
 	priv->rx_ring_size = DEFAULT_RX_RING_SIZE;
+	priv->num_txbdfree = DEFAULT_TX_RING_SIZE;
 
 	priv->txcoalescing = DEFAULT_TX_COALESCE;
-	priv->txcount = DEFAULT_TXCOUNT;
-	priv->txtime = DEFAULT_TXTIME;
+	priv->txic = DEFAULT_TXIC;
 	priv->rxcoalescing = DEFAULT_RX_COALESCE;
-	priv->rxcount = DEFAULT_RXCOUNT;
-	priv->rxtime = DEFAULT_RXTIME;
+	priv->rxic = DEFAULT_RXIC;
 
 	/* Enable most messages by default */
 	priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
@@ -360,12 +448,28 @@
 		goto register_fail;
 	}
 
+	/* fill out IRQ number and name fields */
+	len_devname = strlen(dev->name);
+	strncpy(&priv->int_name_tx[0], dev->name, len_devname);
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
+		strncpy(&priv->int_name_tx[len_devname],
+			"_tx", sizeof("_tx") + 1);
+
+		strncpy(&priv->int_name_rx[0], dev->name, len_devname);
+		strncpy(&priv->int_name_rx[len_devname],
+			"_rx", sizeof("_rx") + 1);
+
+		strncpy(&priv->int_name_er[0], dev->name, len_devname);
+		strncpy(&priv->int_name_er[len_devname],
+			"_er", sizeof("_er") + 1);
+	} else
+		priv->int_name_tx[len_devname] = '\0';
+
 	/* Create all the sysfs files */
 	gfar_init_sysfs(dev);
 
 	/* Print out the device info */
-	printk(KERN_INFO DEVICE_NAME "%s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO DEVICE_NAME "%pM\n", dev->name, dev->dev_addr);
 
 	/* Even more device info helps when determining which kernel */
 	/* provided which set of benchmarks. */
@@ -382,29 +486,28 @@
 	return err;
 }
 
-static int gfar_remove(struct platform_device *pdev)
+static int gfar_remove(struct of_device *ofdev)
 {
-	struct net_device *dev = platform_get_drvdata(pdev);
-	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
 
-	platform_set_drvdata(pdev, NULL);
+	dev_set_drvdata(&ofdev->dev, NULL);
 
 	iounmap(priv->regs);
-	free_netdev(dev);
+	free_netdev(priv->dev);
 
 	return 0;
 }
 
 #ifdef CONFIG_PM
-static int gfar_suspend(struct platform_device *pdev, pm_message_t state)
+static int gfar_suspend(struct of_device *ofdev, pm_message_t state)
 {
-	struct net_device *dev = platform_get_drvdata(pdev);
-	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
+	struct net_device *dev = priv->dev;
 	unsigned long flags;
 	u32 tempval;
 
 	int magic_packet = priv->wol_en &&
-		(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+		(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
 	netif_device_detach(dev);
 
@@ -445,14 +548,14 @@
 	return 0;
 }
 
-static int gfar_resume(struct platform_device *pdev)
+static int gfar_resume(struct of_device *ofdev)
 {
-	struct net_device *dev = platform_get_drvdata(pdev);
-	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
+	struct net_device *dev = priv->dev;
 	unsigned long flags;
 	u32 tempval;
 	int magic_packet = priv->wol_en &&
-		(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+		(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
 	if (!netif_running(dev)) {
 		netif_device_attach(dev);
@@ -511,7 +614,7 @@
 		if (ecntrl & ECNTRL_REDUCED_MII_MODE)
 			return PHY_INTERFACE_MODE_RMII;
 		else {
-			phy_interface_t interface = priv->einfo->interface;
+			phy_interface_t interface = priv->interface;
 
 			/*
 			 * This isn't autodetected right now, so it must
@@ -524,7 +627,7 @@
 		}
 	}
 
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT)
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT)
 		return PHY_INTERFACE_MODE_GMII;
 
 	return PHY_INTERFACE_MODE_MII;
@@ -538,21 +641,18 @@
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	uint gigabit_support =
-		priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ?
+		priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ?
 		SUPPORTED_1000baseT_Full : 0;
 	struct phy_device *phydev;
-	char phy_id[BUS_ID_SIZE];
 	phy_interface_t interface;
 
 	priv->oldlink = 0;
 	priv->oldspeed = 0;
 	priv->oldduplex = -1;
 
-	snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id);
-
 	interface = gfar_get_interface(dev);
 
-	phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface);
+	phydev = phy_connect(dev, priv->phy_bus_id, &adjust_link, 0, interface);
 
 	if (interface == PHY_INTERFACE_MODE_SGMII)
 		gfar_configure_serdes(dev);
@@ -583,35 +683,31 @@
 static void gfar_configure_serdes(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar_mii __iomem *regs =
-			(void __iomem *)&priv->regs->gfar_mii_regs;
-	int tbipa = gfar_read(&priv->regs->tbipa);
-	struct mii_bus *bus = gfar_get_miibus(priv);
 
-	if (bus)
-		mutex_lock(&bus->mdio_lock);
+	if (!priv->tbiphy) {
+		printk(KERN_WARNING "SGMII mode requires that the device "
+				"tree specify a tbi-handle\n");
+		return;
+	}
 
-	/* If the link is already up, we must already be ok, and don't need to
+	/*
+	 * If the link is already up, we must already be ok, and don't need to
 	 * configure and reset the TBI<->SerDes link.  Maybe U-Boot configured
 	 * everything for us?  Resetting it takes the link down and requires
 	 * several seconds for it to come back.
 	 */
-	if (gfar_local_mdio_read(regs, tbipa, MII_BMSR) & BMSR_LSTATUS)
-		goto done;
+	if (phy_read(priv->tbiphy, MII_BMSR) & BMSR_LSTATUS)
+		return;
 
 	/* Single clk mode, mii mode off(for serdes communication) */
-	gfar_local_mdio_write(regs, tbipa, MII_TBICON, TBICON_CLK_SELECT);
+	phy_write(priv->tbiphy, MII_TBICON, TBICON_CLK_SELECT);
 
-	gfar_local_mdio_write(regs, tbipa, MII_ADVERTISE,
+	phy_write(priv->tbiphy, MII_ADVERTISE,
 			ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
 			ADVERTISE_1000XPSE_ASYM);
 
-	gfar_local_mdio_write(regs, tbipa, MII_BMCR, BMCR_ANENABLE |
+	phy_write(priv->tbiphy, MII_BMCR, BMCR_ANENABLE |
 			BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000);
-
-	done:
-	if (bus)
-		mutex_unlock(&bus->mdio_lock);
 }
 
 static void init_registers(struct net_device *dev)
@@ -644,7 +740,7 @@
 	gfar_write(&priv->regs->gaddr7, 0);
 
 	/* Zero out the rmon mib registers if it has them */
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
 		memset_io(&(priv->regs->rmon), 0, sizeof (struct rmon_mib));
 
 		/* Mask off the CAM interrupts */
@@ -719,7 +815,7 @@
 	spin_unlock_irqrestore(&priv->txlock, flags);
 
 	/* Free the IRQs */
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
 		free_irq(priv->interruptError, dev);
 		free_irq(priv->interruptTransmit, dev);
 		free_irq(priv->interruptReceive, dev);
@@ -742,22 +838,26 @@
 {
 	struct rxbd8 *rxbdp;
 	struct txbd8 *txbdp;
-	int i;
+	int i, j;
 
 	/* Go through all the buffer descriptors and free their data buffers */
 	txbdp = priv->tx_bd_base;
 
 	for (i = 0; i < priv->tx_ring_size; i++) {
+		if (!priv->tx_skbuff[i])
+			continue;
 
-		if (priv->tx_skbuff[i]) {
-			dma_unmap_single(&priv->dev->dev, txbdp->bufPtr,
-					txbdp->length,
-					DMA_TO_DEVICE);
-			dev_kfree_skb_any(priv->tx_skbuff[i]);
-			priv->tx_skbuff[i] = NULL;
+		dma_unmap_single(&priv->dev->dev, txbdp->bufPtr,
+				txbdp->length, DMA_TO_DEVICE);
+		txbdp->lstatus = 0;
+		for (j = 0; j < skb_shinfo(priv->tx_skbuff[i])->nr_frags; j++) {
+			txbdp++;
+			dma_unmap_page(&priv->dev->dev, txbdp->bufPtr,
+					txbdp->length, DMA_TO_DEVICE);
 		}
-
 		txbdp++;
+		dev_kfree_skb_any(priv->tx_skbuff[i]);
+		priv->tx_skbuff[i] = NULL;
 	}
 
 	kfree(priv->tx_skbuff);
@@ -777,8 +877,7 @@
 				priv->rx_skbuff[i] = NULL;
 			}
 
-			rxbdp->status = 0;
-			rxbdp->length = 0;
+			rxbdp->lstatus = 0;
 			rxbdp->bufPtr = 0;
 
 			rxbdp++;
@@ -815,6 +914,8 @@
 
 	/* Unmask the interrupts we look for */
 	gfar_write(&regs->imask, IMASK_DEFAULT);
+
+	dev->trans_start = jiffies;
 }
 
 /* Bring the controller up and running */
@@ -889,6 +990,7 @@
 		priv->rx_skbuff[i] = NULL;
 
 	/* Initialize some variables in our dev structure */
+	priv->num_txbdfree = priv->tx_ring_size;
 	priv->dirty_tx = priv->cur_tx = priv->tx_bd_base;
 	priv->cur_rx = priv->rx_bd_base;
 	priv->skb_curtx = priv->skb_dirtytx = 0;
@@ -897,8 +999,7 @@
 	/* Initialize Transmit Descriptor Ring */
 	txbdp = priv->tx_bd_base;
 	for (i = 0; i < priv->tx_ring_size; i++) {
-		txbdp->status = 0;
-		txbdp->length = 0;
+		txbdp->lstatus = 0;
 		txbdp->bufPtr = 0;
 		txbdp++;
 	}
@@ -933,11 +1034,11 @@
 
 	/* If the device has multiple interrupts, register for
 	 * them.  Otherwise, only register for the one */
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
 		/* Install our interrupt handlers for Error,
 		 * Transmit, and Receive */
 		if (request_irq(priv->interruptError, gfar_error,
-				0, "enet_error", dev) < 0) {
+				0, priv->int_name_er, dev) < 0) {
 			if (netif_msg_intr(priv))
 				printk(KERN_ERR "%s: Can't get IRQ %d\n",
 					dev->name, priv->interruptError);
@@ -947,7 +1048,7 @@
 		}
 
 		if (request_irq(priv->interruptTransmit, gfar_transmit,
-				0, "enet_tx", dev) < 0) {
+				0, priv->int_name_tx, dev) < 0) {
 			if (netif_msg_intr(priv))
 				printk(KERN_ERR "%s: Can't get IRQ %d\n",
 					dev->name, priv->interruptTransmit);
@@ -958,7 +1059,7 @@
 		}
 
 		if (request_irq(priv->interruptReceive, gfar_receive,
-				0, "enet_rx", dev) < 0) {
+				0, priv->int_name_rx, dev) < 0) {
 			if (netif_msg_intr(priv))
 				printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
 						dev->name, priv->interruptReceive);
@@ -968,10 +1069,10 @@
 		}
 	} else {
 		if (request_irq(priv->interruptTransmit, gfar_interrupt,
-				0, "gfar_interrupt", dev) < 0) {
+				0, priv->int_name_tx, dev) < 0) {
 			if (netif_msg_intr(priv))
 				printk(KERN_ERR "%s: Can't get IRQ %d\n",
-					dev->name, priv->interruptError);
+					dev->name, priv->interruptTransmit);
 
 			err = -1;
 			goto err_irq_fail;
@@ -981,17 +1082,13 @@
 	phy_start(priv->phydev);
 
 	/* Configure the coalescing support */
+	gfar_write(&regs->txic, 0);
 	if (priv->txcoalescing)
-		gfar_write(&regs->txic,
-			   mk_ic_value(priv->txcount, priv->txtime));
-	else
-		gfar_write(&regs->txic, 0);
+		gfar_write(&regs->txic, priv->txic);
 
+	gfar_write(&regs->rxic, 0);
 	if (priv->rxcoalescing)
-		gfar_write(&regs->rxic,
-			   mk_ic_value(priv->rxcount, priv->rxtime));
-	else
-		gfar_write(&regs->rxic, 0);
+		gfar_write(&regs->rxic, priv->rxic);
 
 	if (priv->rx_csum_enable)
 		rctrl |= RCTRL_CHECKSUMMING;
@@ -1003,9 +1100,6 @@
 		rctrl |= RCTRL_EMEN;
 	}
 
-	if (priv->vlan_enable)
-		rctrl |= RCTRL_VLAN;
-
 	if (priv->padding) {
 		rctrl &= ~RCTRL_PAL_MASK;
 		rctrl |= RCTRL_PADDING(priv->padding);
@@ -1094,11 +1188,11 @@
 	return err;
 }
 
-static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
+static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb)
 {
 	struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
 
-	memset(fcb, 0, GMAC_FCB_LEN);
+	cacheable_memzero(fcb, GMAC_FCB_LEN);
 
 	return fcb;
 }
@@ -1137,96 +1231,140 @@
 	fcb->vlctl = vlan_tx_tag_get(skb);
 }
 
+static inline struct txbd8 *skip_txbd(struct txbd8 *bdp, int stride,
+			       struct txbd8 *base, int ring_size)
+{
+	struct txbd8 *new_bd = bdp + stride;
+
+	return (new_bd >= (base + ring_size)) ? (new_bd - ring_size) : new_bd;
+}
+
+static inline struct txbd8 *next_txbd(struct txbd8 *bdp, struct txbd8 *base,
+		int ring_size)
+{
+	return skip_txbd(bdp, 1, base, ring_size);
+}
+
 /* This is called by the kernel when a frame is ready for transmission. */
 /* It is pointed to by the dev->hard_start_xmit function pointer */
 static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct txfcb *fcb = NULL;
-	struct txbd8 *txbdp;
-	u16 status;
+	struct txbd8 *txbdp, *txbdp_start, *base;
+	u32 lstatus;
+	int i;
+	u32 bufaddr;
 	unsigned long flags;
+	unsigned int nr_frags, length;
+
+	base = priv->tx_bd_base;
+
+	/* total number of fragments in the SKB */
+	nr_frags = skb_shinfo(skb)->nr_frags;
+
+	spin_lock_irqsave(&priv->txlock, flags);
+
+	/* check if there is space to queue this packet */
+	if (nr_frags > priv->num_txbdfree) {
+		/* no space, stop the queue */
+		netif_stop_queue(dev);
+		dev->stats.tx_fifo_errors++;
+		spin_unlock_irqrestore(&priv->txlock, flags);
+		return NETDEV_TX_BUSY;
+	}
 
 	/* Update transmit stats */
 	dev->stats.tx_bytes += skb->len;
 
-	/* Lock priv now */
-	spin_lock_irqsave(&priv->txlock, flags);
+	txbdp = txbdp_start = priv->cur_tx;
 
-	/* Point at the first free tx descriptor */
-	txbdp = priv->cur_tx;
+	if (nr_frags == 0) {
+		lstatus = txbdp->lstatus | BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
+	} else {
+		/* Place the fragment addresses and lengths into the TxBDs */
+		for (i = 0; i < nr_frags; i++) {
+			/* Point at the next BD, wrapping as needed */
+			txbdp = next_txbd(txbdp, base, priv->tx_ring_size);
 
-	/* Clear all but the WRAP status flags */
-	status = txbdp->status & TXBD_WRAP;
+			length = skb_shinfo(skb)->frags[i].size;
+
+			lstatus = txbdp->lstatus | length |
+				BD_LFLAG(TXBD_READY);
+
+			/* Handle the last BD specially */
+			if (i == nr_frags - 1)
+				lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
+
+			bufaddr = dma_map_page(&dev->dev,
+					skb_shinfo(skb)->frags[i].page,
+					skb_shinfo(skb)->frags[i].page_offset,
+					length,
+					DMA_TO_DEVICE);
+
+			/* set the TxBD length and buffer pointer */
+			txbdp->bufPtr = bufaddr;
+			txbdp->lstatus = lstatus;
+		}
+
+		lstatus = txbdp_start->lstatus;
+	}
 
 	/* Set up checksumming */
-	if (likely((dev->features & NETIF_F_IP_CSUM)
-			&& (CHECKSUM_PARTIAL == skb->ip_summed))) {
-		fcb = gfar_add_fcb(skb, txbdp);
-		status |= TXBD_TOE;
+	if (CHECKSUM_PARTIAL == skb->ip_summed) {
+		fcb = gfar_add_fcb(skb);
+		lstatus |= BD_LFLAG(TXBD_TOE);
 		gfar_tx_checksum(skb, fcb);
 	}
 
-	if (priv->vlan_enable &&
-			unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) {
+	if (priv->vlgrp && vlan_tx_tag_present(skb)) {
 		if (unlikely(NULL == fcb)) {
-			fcb = gfar_add_fcb(skb, txbdp);
-			status |= TXBD_TOE;
+			fcb = gfar_add_fcb(skb);
+			lstatus |= BD_LFLAG(TXBD_TOE);
 		}
 
 		gfar_tx_vlan(skb, fcb);
 	}
 
-	/* Set buffer length and pointer */
-	txbdp->length = skb->len;
-	txbdp->bufPtr = dma_map_single(&dev->dev, skb->data,
-			skb->len, DMA_TO_DEVICE);
-
-	/* Save the skb pointer so we can free it later */
+	/* setup the TxBD length and buffer pointer for the first BD */
 	priv->tx_skbuff[priv->skb_curtx] = skb;
+	txbdp_start->bufPtr = dma_map_single(&dev->dev, skb->data,
+			skb_headlen(skb), DMA_TO_DEVICE);
 
-	/* Update the current skb pointer (wrapping if this was the last) */
-	priv->skb_curtx =
-	    (priv->skb_curtx + 1) & TX_RING_MOD_MASK(priv->tx_ring_size);
+	lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
 
-	/* Flag the BD as interrupt-causing */
-	status |= TXBD_INTERRUPT;
-
-	/* Flag the BD as ready to go, last in frame, and  */
-	/* in need of CRC */
-	status |= (TXBD_READY | TXBD_LAST | TXBD_CRC);
-
-	dev->trans_start = jiffies;
-
-	/* The powerpc-specific eieio() is used, as wmb() has too strong
+	/*
+	 * The powerpc-specific eieio() is used, as wmb() has too strong
 	 * semantics (it requires synchronization between cacheable and
 	 * uncacheable mappings, which eieio doesn't provide and which we
 	 * don't need), thus requiring a more expensive sync instruction.  At
 	 * some point, the set of architecture-independent barrier functions
 	 * should be expanded to include weaker barriers.
 	 */
-
 	eieio();
-	txbdp->status = status;
 
-	/* If this was the last BD in the ring, the next one */
-	/* is at the beginning of the ring */
-	if (txbdp->status & TXBD_WRAP)
-		txbdp = priv->tx_bd_base;
-	else
-		txbdp++;
+	txbdp_start->lstatus = lstatus;
+
+	/* Update the current skb pointer to the next entry we will use
+	 * (wrapping if necessary) */
+	priv->skb_curtx = (priv->skb_curtx + 1) &
+		TX_RING_MOD_MASK(priv->tx_ring_size);
+
+	priv->cur_tx = next_txbd(txbdp, base, priv->tx_ring_size);
+
+	/* reduce TxBD free count */
+	priv->num_txbdfree -= (nr_frags + 1);
+
+	dev->trans_start = jiffies;
 
 	/* If the next BD still needs to be cleaned up, then the bds
 	   are full.  We need to tell the kernel to stop sending us stuff. */
-	if (txbdp == priv->dirty_tx) {
+	if (!priv->num_txbdfree) {
 		netif_stop_queue(dev);
 
 		dev->stats.tx_fifo_errors++;
 	}
 
-	/* Update the current txbd to the next one */
-	priv->cur_tx = txbdp;
-
 	/* Tell the DMA to go go go */
 	gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
 
@@ -1270,11 +1408,15 @@
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	unsigned long flags;
+	struct vlan_group *old_grp;
 	u32 tempval;
 
 	spin_lock_irqsave(&priv->rxlock, flags);
 
-	priv->vlgrp = grp;
+	old_grp = priv->vlgrp;
+
+	if (old_grp == grp)
+		return;
 
 	if (grp) {
 		/* Enable VLAN tag insertion */
@@ -1286,6 +1428,7 @@
 		/* Enable VLAN tag extraction */
 		tempval = gfar_read(&priv->regs->rctrl);
 		tempval |= RCTRL_VLEX;
+		tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT);
 		gfar_write(&priv->regs->rctrl, tempval);
 	} else {
 		/* Disable VLAN tag insertion */
@@ -1296,9 +1439,16 @@
 		/* Disable VLAN tag extraction */
 		tempval = gfar_read(&priv->regs->rctrl);
 		tempval &= ~RCTRL_VLEX;
+		/* If parse is no longer required, then disable parser */
+		if (tempval & RCTRL_REQ_PARSER)
+			tempval |= RCTRL_PRSDEP_INIT;
+		else
+			tempval &= ~RCTRL_PRSDEP_INIT;
 		gfar_write(&priv->regs->rctrl, tempval);
 	}
 
+	gfar_change_mtu(dev, dev->mtu);
+
 	spin_unlock_irqrestore(&priv->rxlock, flags);
 }
 
@@ -1309,14 +1459,9 @@
 	int oldsize = priv->rx_buffer_size;
 	int frame_size = new_mtu + ETH_HLEN;
 
-	if (priv->vlan_enable)
+	if (priv->vlgrp)
 		frame_size += VLAN_HLEN;
 
-	if (gfar_uses_fcb(priv))
-		frame_size += GMAC_FCB_LEN;
-
-	frame_size += priv->padding;
-
 	if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
 		if (netif_msg_drv(priv))
 			printk(KERN_ERR "%s: Invalid MTU setting\n",
@@ -1324,6 +1469,11 @@
 		return -EINVAL;
 	}
 
+	if (gfar_uses_fcb(priv))
+		frame_size += GMAC_FCB_LEN;
+
+	frame_size += priv->padding;
+
 	tempsize =
 	    (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) +
 	    INCREMENTAL_BUFFER_SIZE;
@@ -1388,83 +1538,85 @@
 /* Interrupt Handler for Transmit complete */
 static int gfar_clean_tx_ring(struct net_device *dev)
 {
-	struct txbd8 *bdp;
 	struct gfar_private *priv = netdev_priv(dev);
+	struct txbd8 *bdp;
+	struct txbd8 *lbdp = NULL;
+	struct txbd8 *base = priv->tx_bd_base;
+	struct sk_buff *skb;
+	int skb_dirtytx;
+	int tx_ring_size = priv->tx_ring_size;
+	int frags = 0;
+	int i;
 	int howmany = 0;
+	u32 lstatus;
 
 	bdp = priv->dirty_tx;
-	while ((bdp->status & TXBD_READY) == 0) {
-		/* If dirty_tx and cur_tx are the same, then either the */
-		/* ring is empty or full now (it could only be full in the beginning, */
-		/* obviously).  If it is empty, we are done. */
-		if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0))
+	skb_dirtytx = priv->skb_dirtytx;
+
+	while ((skb = priv->tx_skbuff[skb_dirtytx])) {
+		frags = skb_shinfo(skb)->nr_frags;
+		lbdp = skip_txbd(bdp, frags, base, tx_ring_size);
+
+		lstatus = lbdp->lstatus;
+
+		/* Only clean completed frames */
+		if ((lstatus & BD_LFLAG(TXBD_READY)) &&
+				(lstatus & BD_LENGTH_MASK))
 			break;
 
+		dma_unmap_single(&dev->dev,
+				bdp->bufPtr,
+				bdp->length,
+				DMA_TO_DEVICE);
+
+		bdp->lstatus &= BD_LFLAG(TXBD_WRAP);
+		bdp = next_txbd(bdp, base, tx_ring_size);
+
+		for (i = 0; i < frags; i++) {
+			dma_unmap_page(&dev->dev,
+					bdp->bufPtr,
+					bdp->length,
+					DMA_TO_DEVICE);
+			bdp->lstatus &= BD_LFLAG(TXBD_WRAP);
+			bdp = next_txbd(bdp, base, tx_ring_size);
+		}
+
+		dev_kfree_skb_any(skb);
+		priv->tx_skbuff[skb_dirtytx] = NULL;
+
+		skb_dirtytx = (skb_dirtytx + 1) &
+			TX_RING_MOD_MASK(tx_ring_size);
+
 		howmany++;
+		priv->num_txbdfree += frags + 1;
+	}
 
-		/* Deferred means some collisions occurred during transmit, */
-		/* but we eventually sent the packet. */
-		if (bdp->status & TXBD_DEF)
-			dev->stats.collisions++;
+	/* If we freed a buffer, we can restart transmission, if necessary */
+	if (netif_queue_stopped(dev) && priv->num_txbdfree)
+		netif_wake_queue(dev);
 
-		/* Unmap the DMA memory */
-		dma_unmap_single(&priv->dev->dev, bdp->bufPtr,
-				bdp->length, DMA_TO_DEVICE);
-
-		/* Free the sk buffer associated with this TxBD */
-		dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]);
-
-		priv->tx_skbuff[priv->skb_dirtytx] = NULL;
-		priv->skb_dirtytx =
-		    (priv->skb_dirtytx +
-		     1) & TX_RING_MOD_MASK(priv->tx_ring_size);
-
-		/* Clean BD length for empty detection */
-		bdp->length = 0;
-
-		/* update bdp to point at next bd in the ring (wrapping if necessary) */
-		if (bdp->status & TXBD_WRAP)
-			bdp = priv->tx_bd_base;
-		else
-			bdp++;
-
-		/* Move dirty_tx to be the next bd */
-		priv->dirty_tx = bdp;
-
-		/* We freed a buffer, so now we can restart transmission */
-		if (netif_queue_stopped(dev))
-			netif_wake_queue(dev);
-	} /* while ((bdp->status & TXBD_READY) == 0) */
+	/* Update dirty indicators */
+	priv->skb_dirtytx = skb_dirtytx;
+	priv->dirty_tx = bdp;
 
 	dev->stats.tx_packets += howmany;
 
 	return howmany;
 }
 
+static void gfar_schedule_cleanup(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	if (netif_rx_schedule_prep(&priv->napi)) {
+		gfar_write(&priv->regs->imask, IMASK_RTX_DISABLED);
+		__netif_rx_schedule(&priv->napi);
+	}
+}
+
 /* Interrupt Handler for Transmit complete */
 static irqreturn_t gfar_transmit(int irq, void *dev_id)
 {
-	struct net_device *dev = (struct net_device *) dev_id;
-	struct gfar_private *priv = netdev_priv(dev);
-
-	/* Clear IEVENT */
-	gfar_write(&priv->regs->ievent, IEVENT_TX_MASK);
-
-	/* Lock priv */
-	spin_lock(&priv->txlock);
-
-	gfar_clean_tx_ring(dev);
-
-	/* If we are coalescing the interrupts, reset the timer */
-	/* Otherwise, clear it */
-	if (likely(priv->txcoalescing)) {
-		gfar_write(&priv->regs->txic, 0);
-		gfar_write(&priv->regs->txic,
-			   mk_ic_value(priv->txcount, priv->txtime));
-	}
-
-	spin_unlock(&priv->txlock);
-
+	gfar_schedule_cleanup((struct net_device *)dev_id);
 	return IRQ_HANDLED;
 }
 
@@ -1472,20 +1624,19 @@
 		struct sk_buff *skb)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	u32 * status_len = (u32 *)bdp;
-	u16 flags;
+	u32 lstatus;
 
 	bdp->bufPtr = dma_map_single(&dev->dev, skb->data,
 			priv->rx_buffer_size, DMA_FROM_DEVICE);
 
-	flags = RXBD_EMPTY | RXBD_INTERRUPT;
+	lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT);
 
 	if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1)
-		flags |= RXBD_WRAP;
+		lstatus |= BD_LFLAG(RXBD_WRAP);
 
 	eieio();
 
-	*status_len = (u32)flags << 16;
+	bdp->lstatus = lstatus;
 }
 
 
@@ -1552,28 +1703,7 @@
 
 irqreturn_t gfar_receive(int irq, void *dev_id)
 {
-	struct net_device *dev = (struct net_device *) dev_id;
-	struct gfar_private *priv = netdev_priv(dev);
-	u32 tempval;
-
-	/* support NAPI */
-	/* Clear IEVENT, so interrupts aren't called again
-	 * because of the packets that have already arrived */
-	gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK);
-
-	if (netif_rx_schedule_prep(dev, &priv->napi)) {
-		tempval = gfar_read(&priv->regs->imask);
-		tempval &= IMASK_RTX_DISABLED;
-		gfar_write(&priv->regs->imask, tempval);
-
-		__netif_rx_schedule(dev, &priv->napi);
-	} else {
-		if (netif_msg_rx_err(priv))
-			printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
-				dev->name, gfar_read(&priv->regs->ievent),
-				gfar_read(&priv->regs->imask));
-	}
-
+	gfar_schedule_cleanup((struct net_device *)dev_id);
 	return IRQ_HANDLED;
 }
 
@@ -1589,59 +1719,38 @@
 }
 
 
-static inline struct rxfcb *gfar_get_fcb(struct sk_buff *skb)
-{
-	struct rxfcb *fcb = (struct rxfcb *)skb->data;
-
-	/* Remove the FCB from the skb */
-	skb_pull(skb, GMAC_FCB_LEN);
-
-	return fcb;
-}
-
 /* gfar_process_frame() -- handle one incoming packet if skb
  * isn't NULL.  */
 static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
-		int length)
+			      int amount_pull)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct rxfcb *fcb = NULL;
 
-	if (NULL == skb) {
-		if (netif_msg_rx_err(priv))
-			printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
-		dev->stats.rx_dropped++;
-		priv->extra_stats.rx_skbmissing++;
-	} else {
-		int ret;
+	int ret;
 
-		/* Prep the skb for the packet */
-		skb_put(skb, length);
+	/* fcb is at the beginning if exists */
+	fcb = (struct rxfcb *)skb->data;
 
-		/* Grab the FCB if there is one */
-		if (gfar_uses_fcb(priv))
-			fcb = gfar_get_fcb(skb);
+	/* Remove the FCB from the skb */
+	/* Remove the padded bytes, if there are any */
+	if (amount_pull)
+		skb_pull(skb, amount_pull);
 
-		/* Remove the padded bytes, if there are any */
-		if (priv->padding)
-			skb_pull(skb, priv->padding);
+	if (priv->rx_csum_enable)
+		gfar_rx_checksum(skb, fcb);
 
-		if (priv->rx_csum_enable)
-			gfar_rx_checksum(skb, fcb);
+	/* Tell the skb what kind of packet this is */
+	skb->protocol = eth_type_trans(skb, dev);
 
-		/* Tell the skb what kind of packet this is */
-		skb->protocol = eth_type_trans(skb, dev);
+	/* Send the packet up the stack */
+	if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN)))
+		ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp, fcb->vlctl);
+	else
+		ret = netif_receive_skb(skb);
 
-		/* Send the packet up the stack */
-		if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN))) {
-			ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp,
-						       fcb->vlctl);
-		} else
-			ret = netif_receive_skb(skb);
-
-		if (NET_RX_DROP == ret)
-			priv->extra_stats.kernel_dropped++;
-	}
+	if (NET_RX_DROP == ret)
+		priv->extra_stats.kernel_dropped++;
 
 	return 0;
 }
@@ -1652,14 +1761,19 @@
  */
 int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 {
-	struct rxbd8 *bdp;
+	struct rxbd8 *bdp, *base;
 	struct sk_buff *skb;
-	u16 pkt_len;
+	int pkt_len;
+	int amount_pull;
 	int howmany = 0;
 	struct gfar_private *priv = netdev_priv(dev);
 
 	/* Get the first full descriptor */
 	bdp = priv->cur_rx;
+	base = priv->rx_bd_base;
+
+	amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) +
+		priv->padding;
 
 	while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
 		struct sk_buff *newskb;
@@ -1680,34 +1794,38 @@
 
 			if (unlikely(!newskb))
 				newskb = skb;
-
-			if (skb)
+			else if (skb)
 				dev_kfree_skb_any(skb);
 		} else {
 			/* Increment the number of packets */
 			dev->stats.rx_packets++;
 			howmany++;
 
-			/* Remove the FCS from the packet length */
-			pkt_len = bdp->length - 4;
+			if (likely(skb)) {
+				pkt_len = bdp->length - ETH_FCS_LEN;
+				/* Remove the FCS from the packet length */
+				skb_put(skb, pkt_len);
+				dev->stats.rx_bytes += pkt_len;
 
-			gfar_process_frame(dev, skb, pkt_len);
+				gfar_process_frame(dev, skb, amount_pull);
 
-			dev->stats.rx_bytes += pkt_len;
+			} else {
+				if (netif_msg_rx_err(priv))
+					printk(KERN_WARNING
+					       "%s: Missing skb!\n", dev->name);
+				dev->stats.rx_dropped++;
+				priv->extra_stats.rx_skbmissing++;
+			}
+
 		}
 
-		dev->last_rx = jiffies;
-
 		priv->rx_skbuff[priv->skb_currx] = newskb;
 
 		/* Setup the new bdp */
 		gfar_new_rxbdp(dev, bdp, newskb);
 
 		/* Update to the next pointer */
-		if (bdp->status & RXBD_WRAP)
-			bdp = priv->rx_bd_base;
-		else
-			bdp++;
+		bdp = next_bd(bdp, base, priv->rx_ring_size);
 
 		/* update to point at the next skb */
 		priv->skb_currx =
@@ -1725,19 +1843,27 @@
 {
 	struct gfar_private *priv = container_of(napi, struct gfar_private, napi);
 	struct net_device *dev = priv->dev;
-	int howmany;
+	int tx_cleaned = 0;
+	int rx_cleaned = 0;
 	unsigned long flags;
 
+	/* Clear IEVENT, so interrupts aren't called again
+	 * because of the packets that have already arrived */
+	gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK);
+
 	/* If we fail to get the lock, don't bother with the TX BDs */
 	if (spin_trylock_irqsave(&priv->txlock, flags)) {
-		gfar_clean_tx_ring(dev);
+		tx_cleaned = gfar_clean_tx_ring(dev);
 		spin_unlock_irqrestore(&priv->txlock, flags);
 	}
 
-	howmany = gfar_clean_rx_ring(dev, budget);
+	rx_cleaned = gfar_clean_rx_ring(dev, budget);
 
-	if (howmany < budget) {
-		netif_rx_complete(dev, napi);
+	if (tx_cleaned)
+		return budget;
+
+	if (rx_cleaned < budget) {
+		netif_rx_complete(napi);
 
 		/* Clear the halt bit in RSTAT */
 		gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
@@ -1748,12 +1874,15 @@
 		/* Otherwise, clear it */
 		if (likely(priv->rxcoalescing)) {
 			gfar_write(&priv->regs->rxic, 0);
-			gfar_write(&priv->regs->rxic,
-				   mk_ic_value(priv->rxcount, priv->rxtime));
+			gfar_write(&priv->regs->rxic, priv->rxic);
+		}
+		if (likely(priv->txcoalescing)) {
+			gfar_write(&priv->regs->txic, 0);
+			gfar_write(&priv->regs->txic, priv->txic);
 		}
 	}
 
-	return howmany;
+	return rx_cleaned;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1767,7 +1896,7 @@
 	struct gfar_private *priv = netdev_priv(dev);
 
 	/* If the device has multiple interrupts, run tx/rx */
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
 		disable_irq(priv->interruptTransmit);
 		disable_irq(priv->interruptReceive);
 		disable_irq(priv->interruptError);
@@ -2061,7 +2190,7 @@
 	gfar_write(&priv->regs->ievent, events & IEVENT_ERR_MASK);
 
 	/* Magic Packet is not an error. */
-	if ((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
+	if ((priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
 	    (events & IEVENT_MAG))
 		events &= ~IEVENT_MAG;
 
@@ -2127,16 +2256,24 @@
 /* work with hotplug and coldplug */
 MODULE_ALIAS("platform:fsl-gianfar");
 
+static struct of_device_id gfar_match[] =
+{
+	{
+		.type = "network",
+		.compatible = "gianfar",
+	},
+	{},
+};
+
 /* Structure for a device driver */
-static struct platform_driver gfar_driver = {
+static struct of_platform_driver gfar_driver = {
+	.name = "fsl-gianfar",
+	.match_table = gfar_match,
+
 	.probe = gfar_probe,
 	.remove = gfar_remove,
 	.suspend = gfar_suspend,
 	.resume = gfar_resume,
-	.driver	= {
-		.name = "fsl-gianfar",
-		.owner = THIS_MODULE,
-	},
 };
 
 static int __init gfar_init(void)
@@ -2146,7 +2283,7 @@
 	if (err)
 		return err;
 
-	err = platform_driver_register(&gfar_driver);
+	err = of_register_platform_driver(&gfar_driver);
 
 	if (err)
 		gfar_mdio_exit();
@@ -2156,7 +2293,7 @@
 
 static void __exit gfar_exit(void)
 {
-	platform_driver_unregister(&gfar_driver);
+	of_unregister_platform_driver(&gfar_driver);
 	gfar_mdio_exit();
 }
 
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index f46e9b6..b1a8334 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -189,6 +189,18 @@
 #define mk_ic_value(count, time) (IC_ICEN | \
 				mk_ic_icft(count) | \
 				mk_ic_ictt(time))
+#define get_icft_value(ic)	(((unsigned long)ic & IC_ICFT_MASK) >> \
+				 IC_ICFT_SHIFT)
+#define get_ictt_value(ic)	((unsigned long)ic & IC_ICTT_MASK)
+
+#define DEFAULT_TXIC mk_ic_value(DEFAULT_TXCOUNT, DEFAULT_TXTIME)
+#define DEFAULT_RXIC mk_ic_value(DEFAULT_RXCOUNT, DEFAULT_RXTIME)
+
+#define skip_bd(bdp, stride, base, ring_size) ({ \
+	typeof(bdp) new_bd = (bdp) + (stride); \
+	(new_bd >= (base) + (ring_size)) ? (new_bd - (ring_size)) : new_bd; })
+
+#define next_bd(bdp, base, ring_size) skip_bd(bdp, 1, base, ring_size)
 
 #define RCTRL_PAL_MASK		0x001f0000
 #define RCTRL_VLEX		0x00002000
@@ -200,8 +212,10 @@
 #define RCTRL_PRSDEP_INIT	0x000000c0
 #define RCTRL_PROM		0x00000008
 #define RCTRL_EMEN		0x00000002
-#define RCTRL_CHECKSUMMING	(RCTRL_IPCSEN \
-		| RCTRL_TUCSEN | RCTRL_PRSDEP_INIT)
+#define RCTRL_REQ_PARSER	(RCTRL_VLEX | RCTRL_IPCSEN | \
+				 RCTRL_TUCSEN)
+#define RCTRL_CHECKSUMMING	(RCTRL_IPCSEN | RCTRL_TUCSEN | \
+				RCTRL_PRSDEP_INIT)
 #define RCTRL_EXTHASH		(RCTRL_GHTX)
 #define RCTRL_VLAN		(RCTRL_PRSDEP_INIT)
 #define RCTRL_PADDING(x)	((x << 16) & RCTRL_PAL_MASK)
@@ -237,7 +251,7 @@
 #define IEVENT_FIQ		0x00000004
 #define IEVENT_DPE		0x00000002
 #define IEVENT_PERR		0x00000001
-#define IEVENT_RX_MASK          (IEVENT_RXB0 | IEVENT_RXF0)
+#define IEVENT_RX_MASK          (IEVENT_RXB0 | IEVENT_RXF0 | IEVENT_BSY)
 #define IEVENT_TX_MASK          (IEVENT_TXB | IEVENT_TXF)
 #define IEVENT_RTX_MASK         (IEVENT_RX_MASK | IEVENT_TX_MASK)
 #define IEVENT_ERR_MASK         \
@@ -297,6 +311,8 @@
 #define ATTRELI_EI_MASK		0x00003fff
 #define ATTRELI_EI(x) (x)
 
+#define BD_LFLAG(flags) ((flags) << 16)
+#define BD_LENGTH_MASK		0x00ff
 
 /* TxBD status field bits */
 #define TXBD_READY		0x8000
@@ -358,10 +374,17 @@
 #define RXFCB_PERR_MASK		0x000c
 #define RXFCB_PERR_BADL3	0x0008
 
+#define GFAR_INT_NAME_MAX	IFNAMSIZ + 4
+
 struct txbd8
 {
-	u16	status;	/* Status Fields */
-	u16	length;	/* Buffer length */
+	union {
+		struct {
+			u16	status;	/* Status Fields */
+			u16	length;	/* Buffer length */
+		};
+		u32 lstatus;
+	};
 	u32	bufPtr;	/* Buffer Pointer */
 };
 
@@ -376,8 +399,13 @@
 
 struct rxbd8
 {
-	u16	status;	/* Status Fields */
-	u16	length;	/* Buffer Length */
+	union {
+		struct {
+			u16	status;	/* Status Fields */
+			u16	length;	/* Buffer Length */
+		};
+		u32 lstatus;
+	};
 	u32	bufPtr;	/* Buffer Pointer */
 };
 
@@ -657,6 +685,19 @@
 
 };
 
+/* Flags related to gianfar device features */
+#define FSL_GIANFAR_DEV_HAS_GIGABIT		0x00000001
+#define FSL_GIANFAR_DEV_HAS_COALESCE		0x00000002
+#define FSL_GIANFAR_DEV_HAS_RMON		0x00000004
+#define FSL_GIANFAR_DEV_HAS_MULTI_INTR		0x00000008
+#define FSL_GIANFAR_DEV_HAS_CSUM		0x00000010
+#define FSL_GIANFAR_DEV_HAS_VLAN		0x00000020
+#define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH	0x00000040
+#define FSL_GIANFAR_DEV_HAS_PADDING		0x00000080
+#define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET	0x00000100
+#define FSL_GIANFAR_DEV_HAS_BD_STASHING		0x00000200
+#define FSL_GIANFAR_DEV_HAS_BUF_STASHING	0x00000400
+
 /* Struct stolen almost completely (and shamelessly) from the FCC enet source
  * (Ok, that's not so true anymore, but there is a family resemblence)
  * The GFAR buffer descriptors track the ring buffers.  The rx_bd_base
@@ -681,8 +722,7 @@
 
 	/* Configuration info for the coalescing features */
 	unsigned char txcoalescing;
-	unsigned short txcount;
-	unsigned short txtime;
+	unsigned long txic;
 
 	/* Buffer descriptor pointers */
 	struct txbd8 *tx_bd_base;	/* First tx buffer descriptor */
@@ -690,10 +730,12 @@
 	struct txbd8 *dirty_tx;		/* First buffer in line
 					   to be transmitted */
 	unsigned int tx_ring_size;
+	unsigned int num_txbdfree;	/* number of TxBDs free */
 
 	/* RX Locked fields */
 	spinlock_t rxlock;
 
+	struct device_node *node;
 	struct net_device *dev;
 	struct napi_struct napi;
 
@@ -703,8 +745,7 @@
 
 	/* RX Coalescing values */
 	unsigned char rxcoalescing;
-	unsigned short rxcount;
-	unsigned short rxtime;
+	unsigned long rxic;
 
 	struct rxbd8 *rx_bd_base;	/* First Rx buffers */
 	struct rxbd8 *cur_rx;           /* Next free rx ring entry */
@@ -733,8 +774,10 @@
 	/* Bitfield update lock */
 	spinlock_t bflock;
 
-	unsigned char vlan_enable:1,
-		rx_csum_enable:1,
+	phy_interface_t interface;
+	char	phy_bus_id[BUS_ID_SIZE];
+	u32 device_flags;
+	unsigned char rx_csum_enable:1,
 		extended_hash:1,
 		bd_stash_en:1,
 		wol_en:1; /* Wake-on-LAN enabled */
@@ -744,11 +787,9 @@
 	unsigned int interruptReceive;
 	unsigned int interruptError;
 
-	/* info structure initialized by platform code */
-	struct gianfar_platform_data *einfo;
-
 	/* PHY stuff */
 	struct phy_device *phydev;
+	struct phy_device *tbiphy;
 	struct mii_bus *mii_bus;
 	int oldspeed;
 	int oldduplex;
@@ -757,6 +798,11 @@
 	uint32_t msg_enable;
 
 	struct work_struct reset_task;
+
+	char int_name_tx[GFAR_INT_NAME_MAX];
+	char int_name_rx[GFAR_INT_NAME_MAX];
+	char int_name_er[GFAR_INT_NAME_MAX];
+
 	/* Network Statistics */
 	struct gfar_extra_stats extra_stats;
 };
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index fb7d3cc..59b3b5d 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -121,7 +121,7 @@
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
 		memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
 	else
 		memcpy(buf, stat_gstrings,
@@ -138,7 +138,7 @@
 	struct gfar_private *priv = netdev_priv(dev);
 	u64 *extra = (u64 *) & priv->extra_stats;
 
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
 		u32 __iomem *rmon = (u32 __iomem *) & priv->regs->rmon;
 		struct gfar_stats *stats = (struct gfar_stats *) buf;
 
@@ -158,7 +158,7 @@
 
 	switch (sset) {
 	case ETH_SS_STATS:
-		if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+		if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
 			return GFAR_STATS_LEN;
 		else
 			return GFAR_EXTRA_STATS_LEN;
@@ -201,8 +201,8 @@
 	if (NULL == phydev)
 		return -ENODEV;
 
-	cmd->maxtxpkt = priv->txcount;
-	cmd->maxrxpkt = priv->rxcount;
+	cmd->maxtxpkt = get_icft_value(priv->txic);
+	cmd->maxrxpkt = get_icft_value(priv->rxic);
 
 	return phy_ethtool_gset(phydev, cmd);
 }
@@ -279,18 +279,26 @@
 static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	unsigned long rxtime;
+	unsigned long rxcount;
+	unsigned long txtime;
+	unsigned long txcount;
 
-	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
 		return -EOPNOTSUPP;
 
 	if (NULL == priv->phydev)
 		return -ENODEV;
 
-	cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
-	cvals->rx_max_coalesced_frames = priv->rxcount;
+	rxtime  = get_ictt_value(priv->rxic);
+	rxcount = get_icft_value(priv->rxic);
+	txtime  = get_ictt_value(priv->txic);
+	txcount = get_icft_value(priv->txic);;
+	cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, rxtime);
+	cvals->rx_max_coalesced_frames = rxcount;
 
-	cvals->tx_coalesce_usecs = gfar_ticks2usecs(priv, priv->txtime);
-	cvals->tx_max_coalesced_frames = priv->txcount;
+	cvals->tx_coalesce_usecs = gfar_ticks2usecs(priv, txtime);
+	cvals->tx_max_coalesced_frames = txcount;
 
 	cvals->use_adaptive_rx_coalesce = 0;
 	cvals->use_adaptive_tx_coalesce = 0;
@@ -332,7 +340,7 @@
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
-	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
 		return -EOPNOTSUPP;
 
 	/* Set up rx coalescing */
@@ -358,8 +366,9 @@
 		return -EINVAL;
 	}
 
-	priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs);
-	priv->rxcount = cvals->rx_max_coalesced_frames;
+	priv->rxic = mk_ic_value(
+		gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs),
+		cvals->rx_max_coalesced_frames);
 
 	/* Set up tx coalescing */
 	if ((cvals->tx_coalesce_usecs == 0) ||
@@ -381,20 +390,17 @@
 		return -EINVAL;
 	}
 
-	priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs);
-	priv->txcount = cvals->tx_max_coalesced_frames;
+	priv->txic = mk_ic_value(
+		gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs),
+		cvals->tx_max_coalesced_frames);
 
+	gfar_write(&priv->regs->rxic, 0);
 	if (priv->rxcoalescing)
-		gfar_write(&priv->regs->rxic,
-			   mk_ic_value(priv->rxcount, priv->rxtime));
-	else
-		gfar_write(&priv->regs->rxic, 0);
+		gfar_write(&priv->regs->rxic, priv->rxic);
 
+	gfar_write(&priv->regs->txic, 0);
 	if (priv->txcoalescing)
-		gfar_write(&priv->regs->txic,
-			   mk_ic_value(priv->txcount, priv->txtime));
-	else
-		gfar_write(&priv->regs->txic, 0);
+		gfar_write(&priv->regs->txic, priv->txic);
 
 	return 0;
 }
@@ -456,11 +462,12 @@
 		spin_lock(&priv->rxlock);
 
 		gfar_halt(dev);
-		gfar_clean_rx_ring(dev, priv->rx_ring_size);
 
 		spin_unlock(&priv->rxlock);
 		spin_unlock_irqrestore(&priv->txlock, flags);
 
+		gfar_clean_rx_ring(dev, priv->rx_ring_size);
+
 		/* Now we take down the rings to rebuild them */
 		stop_gfar(dev);
 	}
@@ -468,11 +475,13 @@
 	/* Change the size */
 	priv->rx_ring_size = rvals->rx_pending;
 	priv->tx_ring_size = rvals->tx_pending;
+	priv->num_txbdfree = priv->tx_ring_size;
 
 	/* Rebuild the rings with the new size */
-	if (dev->flags & IFF_UP)
+	if (dev->flags & IFF_UP) {
 		err = startup_gfar(dev);
-
+		netif_wake_queue(dev);
+	}
 	return err;
 }
 
@@ -482,7 +491,7 @@
 	unsigned long flags;
 	int err = 0;
 
-	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
 		return -EOPNOTSUPP;
 
 	if (dev->flags & IFF_UP) {
@@ -492,11 +501,12 @@
 		spin_lock(&priv->rxlock);
 
 		gfar_halt(dev);
-		gfar_clean_rx_ring(dev, priv->rx_ring_size);
 
 		spin_unlock(&priv->rxlock);
 		spin_unlock_irqrestore(&priv->txlock, flags);
 
+		gfar_clean_rx_ring(dev, priv->rx_ring_size);
+
 		/* Now we take down the rings to rebuild them */
 		stop_gfar(dev);
 	}
@@ -505,9 +515,10 @@
 	priv->rx_csum_enable = data;
 	spin_unlock_irqrestore(&priv->bflock, flags);
 
-	if (dev->flags & IFF_UP)
+	if (dev->flags & IFF_UP) {
 		err = startup_gfar(dev);
-
+		netif_wake_queue(dev);
+	}
 	return err;
 }
 
@@ -515,7 +526,7 @@
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
-	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
 		return 0;
 
 	return priv->rx_csum_enable;
@@ -523,22 +534,19 @@
 
 static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
 {
-	unsigned long flags;
 	struct gfar_private *priv = netdev_priv(dev);
 
-	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
 		return -EOPNOTSUPP;
 
-	spin_lock_irqsave(&priv->txlock, flags);
-	gfar_halt(dev);
+	netif_tx_lock_bh(dev);
 
 	if (data)
 		dev->features |= NETIF_F_IP_CSUM;
 	else
 		dev->features &= ~NETIF_F_IP_CSUM;
 
-	gfar_start(dev);
-	spin_unlock_irqrestore(&priv->txlock, flags);
+	netif_tx_unlock_bh(dev);
 
 	return 0;
 }
@@ -547,7 +555,7 @@
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
-	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
 		return 0;
 
 	return (dev->features & NETIF_F_IP_CSUM) != 0;
@@ -570,7 +578,7 @@
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) {
+	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) {
 		wol->supported = WAKE_MAGIC;
 		wol->wolopts = priv->wol_en ? WAKE_MAGIC : 0;
 	} else {
@@ -583,7 +591,7 @@
 	struct gfar_private *priv = netdev_priv(dev);
 	unsigned long flags;
 
-	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
+	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
 	    wol->wolopts != 0)
 		return -EINVAL;
 
@@ -616,6 +624,7 @@
 	.get_tx_csum = gfar_get_tx_csum,
 	.set_rx_csum = gfar_set_rx_csum,
 	.set_tx_csum = gfar_set_tx_csum,
+	.set_sg = ethtool_op_set_sg,
 	.get_msglevel = gfar_get_msglevel,
 	.set_msglevel = gfar_set_msglevel,
 #ifdef CONFIG_PM
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index 0e2595d..f3706e4 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -34,6 +34,8 @@
 #include <linux/crc32.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -150,19 +152,83 @@
 	return 0;
 }
 
-
-static int gfar_mdio_probe(struct device *dev)
+/* Allocate an array which provides irq #s for each PHY on the given bus */
+static int *create_irq_map(struct device_node *np)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct gianfar_mdio_data *pdata;
+	int *irqs;
+	int i;
+	struct device_node *child = NULL;
+
+	irqs = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
+
+	if (!irqs)
+		return NULL;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		irqs[i] = PHY_POLL;
+
+	while ((child = of_get_next_child(np, child)) != NULL) {
+		int irq = irq_of_parse_and_map(child, 0);
+		const u32 *id;
+
+		if (irq == NO_IRQ)
+			continue;
+
+		id = of_get_property(child, "reg", NULL);
+
+		if (!id)
+			continue;
+
+		if (*id < PHY_MAX_ADDR && *id >= 0)
+			irqs[*id] = irq;
+		else
+			printk(KERN_WARNING "%s: "
+					"%d is not a valid PHY address\n",
+					np->full_name, *id);
+	}
+
+	return irqs;
+}
+
+
+void gfar_mdio_bus_name(char *name, struct device_node *np)
+{
+	const u32 *reg;
+
+	reg = of_get_property(np, "reg", NULL);
+
+	snprintf(name, MII_BUS_ID_SIZE, "%s@%x", np->name, reg ? *reg : 0);
+}
+
+/* Scan the bus in reverse, looking for an empty spot */
+static int gfar_mdio_find_free(struct mii_bus *new_bus)
+{
+	int i;
+
+	for (i = PHY_MAX_ADDR; i > 0; i--) {
+		u32 phy_id;
+
+		if (get_phy_id(new_bus, i, &phy_id))
+			return -1;
+
+		if (phy_id == 0xffffffff)
+			break;
+	}
+
+	return i;
+}
+
+static int gfar_mdio_probe(struct of_device *ofdev,
+		const struct of_device_id *match)
+{
 	struct gfar_mii __iomem *regs;
 	struct gfar __iomem *enet_regs;
 	struct mii_bus *new_bus;
-	struct resource *r;
-	int i, err = 0;
-
-	if (NULL == dev)
-		return -EINVAL;
+	int err = 0;
+	u64 addr, size;
+	struct device_node *np = ofdev->node;
+	struct device_node *tbi;
+	int tbiaddr = -1;
 
 	new_bus = mdiobus_alloc();
 	if (NULL == new_bus)
@@ -172,31 +238,28 @@
 	new_bus->read = &gfar_mdio_read,
 	new_bus->write = &gfar_mdio_write,
 	new_bus->reset = &gfar_mdio_reset,
-	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
-
-	pdata = (struct gianfar_mdio_data *)pdev->dev.platform_data;
-
-	if (NULL == pdata) {
-		printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id);
-		return -ENODEV;
-	}
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	gfar_mdio_bus_name(new_bus->id, np);
 
 	/* Set the PHY base address */
-	regs = ioremap(r->start, sizeof (struct gfar_mii));
+	addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
+	regs = ioremap(addr, size);
 
 	if (NULL == regs) {
 		err = -ENOMEM;
-		goto reg_map_fail;
+		goto err_free_bus;
 	}
 
 	new_bus->priv = (void __force *)regs;
 
-	new_bus->irq = pdata->irq;
+	new_bus->irq = create_irq_map(np);
 
-	new_bus->parent = dev;
-	dev_set_drvdata(dev, new_bus);
+	if (new_bus->irq == NULL) {
+		err = -ENOMEM;
+		goto err_unmap_regs;
+	}
+
+	new_bus->parent = &ofdev->dev;
+	dev_set_drvdata(&ofdev->dev, new_bus);
 
 	/*
 	 * This is mildly evil, but so is our hardware for doing this.
@@ -206,96 +269,109 @@
 	enet_regs = (struct gfar __iomem *)
 		((char *)regs - offsetof(struct gfar, gfar_mii_regs));
 
-	/* Scan the bus, looking for an empty spot for TBIPA */
-	gfar_write(&enet_regs->tbipa, 0);
-	for (i = PHY_MAX_ADDR; i > 0; i--) {
-		u32 phy_id;
-
-		err = get_phy_id(new_bus, i, &phy_id);
-		if (err)
-			goto bus_register_fail;
-
-		if (phy_id == 0xffffffff)
+	for_each_child_of_node(np, tbi) {
+		if (!strncmp(tbi->type, "tbi-phy", 8))
 			break;
 	}
 
-	/* The bus is full.  We don't support using 31 PHYs, sorry */
-	if (i == 0) {
-		err = -EBUSY;
+	if (tbi) {
+		const u32 *prop = of_get_property(tbi, "reg", NULL);
 
-		goto bus_register_fail;
+		if (prop)
+			tbiaddr = *prop;
 	}
 
-	gfar_write(&enet_regs->tbipa, i);
+	if (tbiaddr == -1) {
+		gfar_write(&enet_regs->tbipa, 0);
+
+		tbiaddr = gfar_mdio_find_free(new_bus);
+	}
+
+	/*
+	 * We define TBIPA at 0 to be illegal, opting to fail for boards that
+	 * have PHYs at 1-31, rather than change tbipa and rescan.
+	 */
+	if (tbiaddr == 0) {
+		err = -EBUSY;
+
+		goto err_free_irqs;
+	}
+
+	gfar_write(&enet_regs->tbipa, tbiaddr);
+
+	/*
+	 * The TBIPHY-only buses will find PHYs at every address,
+	 * so we mask them all but the TBI
+	 */
+	if (!of_device_is_compatible(np, "fsl,gianfar-mdio"))
+		new_bus->phy_mask = ~(1 << tbiaddr);
 
 	err = mdiobus_register(new_bus);
 
-	if (0 != err) {
+	if (err != 0) {
 		printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
 				new_bus->name);
-		goto bus_register_fail;
+		goto err_free_irqs;
 	}
 
 	return 0;
 
-bus_register_fail:
+err_free_irqs:
+	kfree(new_bus->irq);
+err_unmap_regs:
 	iounmap(regs);
-reg_map_fail:
+err_free_bus:
 	mdiobus_free(new_bus);
 
 	return err;
 }
 
 
-static int gfar_mdio_remove(struct device *dev)
+static int gfar_mdio_remove(struct of_device *ofdev)
 {
-	struct mii_bus *bus = dev_get_drvdata(dev);
+	struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
 
 	mdiobus_unregister(bus);
 
-	dev_set_drvdata(dev, NULL);
+	dev_set_drvdata(&ofdev->dev, NULL);
 
 	iounmap((void __iomem *)bus->priv);
 	bus->priv = NULL;
+	kfree(bus->irq);
 	mdiobus_free(bus);
 
 	return 0;
 }
 
-static struct device_driver gianfar_mdio_driver = {
+static struct of_device_id gfar_mdio_match[] =
+{
+	{
+		.compatible = "fsl,gianfar-mdio",
+	},
+	{
+		.compatible = "fsl,gianfar-tbi",
+	},
+	{
+		.type = "mdio",
+		.compatible = "gianfar",
+	},
+	{},
+};
+
+static struct of_platform_driver gianfar_mdio_driver = {
 	.name = "fsl-gianfar_mdio",
-	.bus = &platform_bus_type,
+	.match_table = gfar_mdio_match,
+
 	.probe = gfar_mdio_probe,
 	.remove = gfar_mdio_remove,
 };
 
-static int match_mdio_bus(struct device *dev, void *data)
-{
-	const struct gfar_private *priv = data;
-	const struct platform_device *pdev = to_platform_device(dev);
-
-	return !strcmp(pdev->name, gianfar_mdio_driver.name) &&
-		pdev->id == priv->einfo->mdio_bus;
-}
-
-/* Given a gfar_priv structure, find the mii_bus controlled by this device (not
- * necessarily the same as the bus the gfar's PHY is on), if one exists.
- * Normally only the first gianfar controls a mii_bus.  */
-struct mii_bus *gfar_get_miibus(const struct gfar_private *priv)
-{
-	/*const*/ struct device *d;
-
-	d = bus_find_device(gianfar_mdio_driver.bus, NULL, (void *)priv,
-			    match_mdio_bus);
-	return d ? dev_get_drvdata(d) : NULL;
-}
-
 int __init gfar_mdio_init(void)
 {
-	return driver_register(&gianfar_mdio_driver);
+	return of_register_platform_driver(&gianfar_mdio_driver);
 }
 
 void gfar_mdio_exit(void)
 {
-	driver_unregister(&gianfar_mdio_driver);
+	of_unregister_platform_driver(&gianfar_mdio_driver);
 }
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
index 02dc970..65c242c 100644
--- a/drivers/net/gianfar_mii.h
+++ b/drivers/net/gianfar_mii.h
@@ -49,4 +49,6 @@
 struct mii_bus *gfar_get_miibus(const struct gfar_private *priv);
 int __init gfar_mdio_init(void);
 void gfar_mdio_exit(void);
+
+void gfar_mdio_bus_name(char *name, struct device_node *np);
 #endif /* GIANFAR_PHY_H */
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 3199526..3220022 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -568,6 +568,19 @@
 static const struct ethtool_ops ethtool_ops;
 static const struct ethtool_ops ethtool_ops_no_mii;
 
+static const struct net_device_ops hamachi_netdev_ops = {
+	.ndo_open		= hamachi_open,
+	.ndo_stop		= hamachi_close,
+	.ndo_start_xmit		= hamachi_start_xmit,
+	.ndo_get_stats		= hamachi_get_stats,
+	.ndo_set_multicast_list	= set_rx_mode,
+	.ndo_change_mtu		= eth_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_tx_timeout		= hamachi_tx_timeout,
+	.ndo_do_ioctl		= netdev_ioctl,
+};
+
+
 static int __devinit hamachi_init_one (struct pci_dev *pdev,
 				    const struct pci_device_id *ent)
 {
@@ -582,7 +595,6 @@
 	void *ring_space;
 	dma_addr_t ring_dma;
 	int ret = -ENOMEM;
-	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -723,17 +735,11 @@
 
 
 	/* The Hamachi-specific entries in the device structure. */
-	dev->open = &hamachi_open;
-	dev->hard_start_xmit = &hamachi_start_xmit;
-	dev->stop = &hamachi_close;
-	dev->get_stats = &hamachi_get_stats;
-	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &netdev_ioctl;
+	dev->netdev_ops = &hamachi_netdev_ops;
 	if (chip_tbl[hmp->chip_id].flags & CanHaveMII)
 		SET_ETHTOOL_OPS(dev, &ethtool_ops);
 	else
 		SET_ETHTOOL_OPS(dev, &ethtool_ops_no_mii);
-	dev->tx_timeout = &hamachi_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	if (mtu)
 		dev->mtu = mtu;
@@ -744,9 +750,9 @@
 		goto err_out_unmap_rx;
 	}
 
-	printk(KERN_INFO "%s: %s type %x at %p, %s, IRQ %d.\n",
+	printk(KERN_INFO "%s: %s type %x at %p, %pM, IRQ %d.\n",
 		   dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev),
-		   ioaddr, print_mac(mac, dev->dev_addr), irq);
+		   ioaddr, dev->dev_addr, irq);
 	i = readb(ioaddr + PCIClkMeas);
 	printk(KERN_INFO "%s:  %d-bit %d Mhz PCI bus (%d), Virtual Jumpers "
 		   "%2.2x, LPA %4.4x.\n",
@@ -1646,7 +1652,6 @@
 #endif  /* RX_CHECKSUM */
 
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			hmp->stats.rx_packets++;
 		}
 		entry = (++hmp->cur_rx) % RX_RING_SIZE;
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 0f501d2..50f1e17 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -373,7 +373,6 @@
 	memcpy(ptr, sp->cooked_buf + 1, count);
 	skb->protocol = ax25_type_trans(skb, sp->dev);
 	netif_rx(skb);
-	sp->dev->last_rx = jiffies;
 	sp->dev->stats.rx_packets++;
 
 	return;
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 00bc7fb..81a65e3 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -555,7 +555,6 @@
 	memcpy(cp, bc->hdlcrx.buf, pktlen - 1);
 	skb->protocol = ax25_type_trans(skb, dev);
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 	bc->stats.rx_packets++;
 }
 
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 58f4b1d..46f8f33 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -230,7 +230,6 @@
 
 	skb->protocol = ax25_type_trans(skb, dev);
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 unlock:
 
 	rcu_read_unlock();
@@ -441,16 +440,15 @@
 			 "dev   ether      destination        accept from\n");
 	else {
 		const struct bpqdev *bpqdev = v;
-		DECLARE_MAC_BUF(mac);
 
-		seq_printf(seq, "%-5s %-10s %s  ",
+		seq_printf(seq, "%-5s %-10s %pM  ",
 			bpqdev->axdev->name, bpqdev->ethdev->name,
-			print_mac(mac, bpqdev->dest_addr));
+			bpqdev->dest_addr);
 
 		if (is_multicast_ether_addr(bpqdev->acpt_addr))
 			seq_printf(seq, "*\n");
 		else
-			seq_printf(seq, "%s\n", print_mac(mac, bpqdev->acpt_addr));
+			seq_printf(seq, "%pM\n", bpqdev->acpt_addr);
 
 	}
 	return 0;
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index e8cfade..e671033 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -572,7 +572,7 @@
 		priv->param.persist = 256;
 		priv->param.dma = -1;
 		INIT_WORK(&priv->rx_work, rx_bh);
-		dev->priv = priv;
+		dev->ml_priv = priv;
 		sprintf(dev->name, "dmascc%i", 2 * n + i);
 		dev->base_addr = card_base;
 		dev->irq = irq;
@@ -720,7 +720,7 @@
 
 static int scc_open(struct net_device *dev)
 {
-	struct scc_priv *priv = dev->priv;
+	struct scc_priv *priv = dev->ml_priv;
 	struct scc_info *info = priv->info;
 	int card_base = priv->card_base;
 
@@ -862,7 +862,7 @@
 
 static int scc_close(struct net_device *dev)
 {
-	struct scc_priv *priv = dev->priv;
+	struct scc_priv *priv = dev->ml_priv;
 	struct scc_info *info = priv->info;
 	int card_base = priv->card_base;
 
@@ -891,7 +891,7 @@
 
 static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	struct scc_priv *priv = dev->priv;
+	struct scc_priv *priv = dev->ml_priv;
 
 	switch (cmd) {
 	case SIOCGSCCPARAM:
@@ -918,7 +918,7 @@
 
 static int scc_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct scc_priv *priv = dev->priv;
+	struct scc_priv *priv = dev->ml_priv;
 	unsigned long flags;
 	int i;
 
@@ -963,7 +963,7 @@
 
 static struct net_device_stats *scc_get_stats(struct net_device *dev)
 {
-	struct scc_priv *priv = dev->priv;
+	struct scc_priv *priv = dev->ml_priv;
 
 	return &priv->stats;
 }
@@ -1283,7 +1283,6 @@
 			memcpy(&data[1], priv->rx_buf[i], cb);
 			skb->protocol = ax25_type_trans(skb, priv->dev);
 			netif_rx(skb);
-			priv->dev->last_rx = jiffies;
 			priv->stats.rx_packets++;
 			priv->stats.rx_bytes += cb;
 		}
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index c258a05..8eba61a 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -162,7 +162,6 @@
 	memcpy(cp, s->hdlcrx.buffer, pkt_len - 1);
 	skb->protocol = ax25_type_trans(skb, dev);
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 	s->stats.rx_packets++;
 }
 
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index b8e25c4..bbdb311 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -303,7 +303,6 @@
 	memcpy(skb_put(skb,count), ax->rbuff, count);
 	skb->protocol = ax25_type_trans(skb, ax->dev);
 	netif_rx(skb);
-	ax->dev->last_rx = jiffies;
 	ax->stats.rx_packets++;
 	ax->stats.rx_bytes += count;
 	spin_unlock_bh(&ax->buflock);
@@ -847,12 +846,13 @@
 	unsigned int cmd, unsigned long arg)
 {
 	struct mkiss *ax = mkiss_get(tty);
-	struct net_device *dev = ax->dev;
+	struct net_device *dev;
 	unsigned int tmp, err;
 
 	/* First make sure we're connected. */
 	if (ax == NULL)
 		return -ENXIO;
+	dev = ax->dev;
 
 	switch (cmd) {
  	case SIOCGIFNAME:
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index c17e39b..c011af7 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1518,7 +1518,7 @@
 	if (!dev) 
 		return -ENOMEM;
 
-	dev->priv = scc;
+	dev->ml_priv = scc;
 	scc->dev = dev;
 	spin_lock_init(&scc->lock);
 	init_timer(&scc->tx_t);
@@ -1575,7 +1575,7 @@
 
 static int scc_net_open(struct net_device *dev)
 {
-	struct scc_channel *scc = (struct scc_channel *) dev->priv;
+	struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
 
  	if (!scc->init)
 		return -EINVAL;
@@ -1593,7 +1593,7 @@
 
 static int scc_net_close(struct net_device *dev)
 {
-	struct scc_channel *scc = (struct scc_channel *) dev->priv;
+	struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
 	unsigned long flags;
 
 	netif_stop_queue(dev);
@@ -1627,7 +1627,6 @@
 	skb->protocol = ax25_type_trans(skb, scc->dev);
 	
 	netif_rx(skb);
-	scc->dev->last_rx = jiffies;
 	return;
 }
 
@@ -1635,7 +1634,7 @@
 
 static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct scc_channel *scc = (struct scc_channel *) dev->priv;
+	struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
 	unsigned long flags;
 	char kisscmd;
 
@@ -1705,7 +1704,7 @@
 	struct scc_mem_config memcfg;
 	struct scc_hw_config hwcfg;
 	struct scc_calibrate cal;
-	struct scc_channel *scc = (struct scc_channel *) dev->priv;
+	struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
 	int chan;
 	unsigned char device_name[IFNAMSIZ];
 	void __user *arg = ifr->ifr_data;
@@ -1952,7 +1951,7 @@
 
 static struct net_device_stats *scc_net_get_stats(struct net_device *dev)
 {
-	struct scc_channel *scc = (struct scc_channel *) dev->priv;
+	struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
 	
 	scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over;
 	scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under;
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 1c94286..5407f74 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -515,7 +515,6 @@
 				memcpy(cp, yp->rx_buf, pkt_len - 1);
 				skb->protocol = ax25_type_trans(skb, dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				++yp->stats.rx_packets;
 			}
 		}
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index c01e290..b507dbc 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -158,6 +158,21 @@
 }
 #endif
 
+static const struct net_device_ops hpp_netdev_ops = {
+	.ndo_open		= hpp_open,
+	.ndo_stop		= hpp_close,
+	.ndo_start_xmit		= eip_start_xmit,
+	.ndo_tx_timeout		= eip_tx_timeout,
+	.ndo_get_stats		= eip_get_stats,
+	.ndo_set_multicast_list = eip_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= eip_poll,
+#endif
+};
+
+
 /* Do the interesting part of the probe at a single address. */
 static int __init hpp_probe1(struct net_device *dev, int ioaddr)
 {
@@ -166,7 +181,6 @@
 	const char name[] = "HP-PC-LAN+";
 	int mem_start;
 	static unsigned version_printed;
-	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -193,7 +207,7 @@
 	}
 	checksum += inb(ioaddr + 14);
 
-	printk("%s", print_mac(mac, dev->dev_addr));
+	printk("%pM", dev->dev_addr);
 
 	if (checksum != 0xff) {
 		printk(" bad checksum %2.2x.\n", checksum);
@@ -227,11 +241,7 @@
 	/* Set the base address to point to the NIC, not the "real" base! */
 	dev->base_addr = ioaddr + NIC_OFFSET;
 
-	dev->open = &hpp_open;
-	dev->stop = &hpp_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = eip_poll;
-#endif
+	dev->netdev_ops = &hpp_netdev_ops;
 
 	ei_status.name = name;
 	ei_status.word16 = 0;		/* Agggghhhhh! Debug time: 2 days! */
@@ -302,8 +312,7 @@
 	/* Select the operational page. */
 	outw(Perf_Page, ioaddr + HP_PAGING);
 
-	eip_open(dev);
-	return 0;
+	return eip_open(dev);
 }
 
 static int
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index 0a8c649..5c4d78c 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -59,8 +59,6 @@
 
 static int hp_probe1(struct net_device *dev, int ioaddr);
 
-static int hp_open(struct net_device *dev);
-static int hp_close(struct net_device *dev);
 static void hp_reset_8390(struct net_device *dev);
 static void hp_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 					int ring_page);
@@ -127,7 +125,6 @@
 	int i, retval, board_id, wordmode;
 	const char *name;
 	static unsigned version_printed;
-	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -161,7 +158,7 @@
 	for(i = 0; i < ETHER_ADDR_LEN; i++)
 		dev->dev_addr[i] = inb(ioaddr + i);
 
-	printk(" %s", print_mac(mac, dev->dev_addr));
+	printk(" %pM", dev->dev_addr);
 
 	/* Snarf the interrupt now.  Someday this could be moved to open(). */
 	if (dev->irq < 2) {
@@ -199,11 +196,7 @@
 
 	/* Set the base address to point to the NIC, not the "real" base! */
 	dev->base_addr = ioaddr + NIC_OFFSET;
-	dev->open = &hp_open;
-	dev->stop = &hp_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = eip_poll;
-#endif
+	dev->netdev_ops = &eip_netdev_ops;
 
 	ei_status.name = name;
 	ei_status.word16 = wordmode;
@@ -228,20 +221,6 @@
 	return retval;
 }
 
-static int
-hp_open(struct net_device *dev)
-{
-	eip_open(dev);
-	return 0;
-}
-
-static int
-hp_close(struct net_device *dev)
-{
-	eip_close(dev);
-	return 0;
-}
-
 static void
 hp_reset_8390(struct net_device *dev)
 {
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 571dd80..ebe7651 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1212,7 +1212,7 @@
 	*(pdlptr + 2) = (u_int) virt_to_whatever(dev, pdlptr);	/* Address Frag 1 */
 	*(pdlptr + 3) = 4;	/* Length  Frag 1 */
 
-	return ((((MAX_RX_FRAG * 2 + 2) + 3) / 4) * 4);
+	return roundup(MAX_RX_FRAG * 2 + 2, 4);
 }
 
 
@@ -1227,7 +1227,7 @@
 	ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr);	/* +1 */
 	ringptr->skb = (void *) NULL;
 
-	return ((((MAX_TX_FRAG * 2 + 2) + 3) / 4) * 4);
+	return roundup(MAX_TX_FRAG * 2 + 2, 4);
 }
 
 /*
@@ -1256,7 +1256,7 @@
 	/* Note: This depends on the alloc_skb functions allocating more
 	 * space than requested, i.e. aligning to 16bytes */
 
-	ringptr->skb = dev_alloc_skb(((MAX_ETHER_SIZE + 2 + 3) / 4) * 4);
+	ringptr->skb = dev_alloc_skb(roundup(MAX_ETHER_SIZE + 2, 4));
 
 	if (NULL != ringptr->skb) {
 		/*
@@ -1279,7 +1279,7 @@
 #ifdef HP100_DEBUG_BM
 		printk("hp100: %s: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n",
 				     dev->name, (u_int) ringptr->pdl,
-				     ((MAX_ETHER_SIZE + 2 + 3) / 4) * 4,
+				     roundup(MAX_ETHER_SIZE + 2, 4),
 				     (unsigned int) ringptr->skb->data);
 #endif
 
@@ -1834,7 +1834,6 @@
 					ptr[9], ptr[10], ptr[11]);
 #endif
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			lp->stats.rx_packets++;
 			lp->stats.rx_bytes += pkt_len;
 		}
@@ -1925,7 +1924,6 @@
 
 				netif_rx(ptr->skb);	/* Up and away... */
 
-				dev->last_rx = jiffies;
 				lp->stats.rx_packets++;
 				lp->stats.rx_bytes += pkt_len;
 			}
@@ -2093,9 +2091,8 @@
 				addrs = dmi->dmi_addr;
 				if ((*addrs & 0x01) == 0x01) {	/* multicast address? */
 #ifdef HP100_DEBUG
-					DECLARE_MAC_BUF(mac);
-					printk("hp100: %s: multicast = %s, ",
-						     dev->name, print_mac(mac, addrs));
+					printk("hp100: %s: multicast = %pM, ",
+						     dev->name, addrs);
 #endif
 					for (j = idx = 0; j < 6; j++) {
 						idx ^= *addrs++ & 0x3f;
@@ -3057,12 +3054,3 @@
 
 module_init(hp100_module_init)
 module_exit(hp100_module_exit)
-
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp100.c"
- *  c-indent-level: 2
- *  tab-width: 8
- * End:
- */
diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c
index b96cf2d..9cb38a8 100644
--- a/drivers/net/hydra.c
+++ b/drivers/net/hydra.c
@@ -94,6 +94,21 @@
     return 0;
 }
 
+static const struct net_device_ops hydra_netdev_ops = {
+	.ndo_open		= hydra_open,
+	.ndo_stop		= hydra_close,
+
+	.ndo_start_xmit		= ei_start_xmit,
+	.ndo_tx_timeout		= ei_tx_timeout,
+	.ndo_get_stats		= ei_get_stats,
+	.ndo_set_multicast_list = ei_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= ei_poll,
+#endif
+};
+
 static int __devinit hydra_init(struct zorro_dev *z)
 {
     struct net_device *dev;
@@ -103,14 +118,13 @@
     int start_page, stop_page;
     int j;
     int err;
-    DECLARE_MAC_BUF(mac);
 
     static u32 hydra_offsets[16] = {
 	0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
 	0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
     };
 
-    dev = ____alloc_ei_netdev(0);
+    dev = alloc_ei_netdev();
     if (!dev)
 	return -ENOMEM;
 
@@ -145,12 +159,8 @@
     ei_status.block_output = &hydra_block_output;
     ei_status.get_8390_hdr = &hydra_get_8390_hdr;
     ei_status.reg_offset = hydra_offsets;
-    dev->open = &hydra_open;
-    dev->stop = &hydra_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-    dev->poll_controller = __ei_poll;
-#endif
 
+    dev->netdev_ops = &hydra_netdev_ops;
     __NS8390_init(dev, 0);
 
     err = register_netdev(dev);
@@ -163,8 +173,8 @@
     zorro_set_drvdata(z, dev);
 
     printk(KERN_INFO "%s: Hydra at 0x%08lx, address "
-	   "%s (hydra.c " HYDRA_VERSION ")\n",
-	   dev->name, z->resource.start, print_mac(mac, dev->dev_addr));
+	   "%pM (hydra.c " HYDRA_VERSION ")\n",
+	   dev->name, z->resource.start, dev->dev_addr);
 
     return 0;
 }
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 901212a..87a7066 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -396,9 +396,7 @@
 
 	for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) {
 		int slot, reg, mask;
-		DBG2(dev, "mc %02x:%02x:%02x:%02x:%02x:%02x" NL,
-		     dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
-		     dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+		DBG2(dev, "mc %pM" NL, dmi->dmi_addr);
 
 		slot = EMAC_XAHT_CRC_TO_SLOT(dev, ether_crc(ETH_ALEN, dmi->dmi_addr));
 		reg = EMAC_XAHT_SLOT_TO_REG(dev, slot);
@@ -2865,11 +2863,8 @@
 	wake_up_all(&emac_probe_wait);
 
 
-	printk(KERN_INFO
-	       "%s: EMAC-%d %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       ndev->name, dev->cell_index, np->full_name,
-	       ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
-	       ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+	printk(KERN_INFO "%s: EMAC-%d %s, MAC %pM\n",
+	       ndev->name, dev->cell_index, np->full_name, ndev->dev_addr);
 
 	if (dev->phy_mode == PHY_MODE_SGMII)
 		printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name);
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index f027647..5b5bf9f 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -605,7 +605,6 @@
 				skb->ip_summed = CHECKSUM_NONE;
 
 				/* bookkeeping */
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += rda.length;
 
@@ -914,7 +913,6 @@
 	int base = 0, irq = 0, iobase = 0, memlen = 0;
 	ibmlana_priv *priv;
 	ibmlana_medium medium;
-	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof(ibmlana_priv));
 	if (!dev)
@@ -990,10 +988,10 @@
 	/* print config */
 
 	printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, "
-	       "MAC address %s.\n",
+	       "MAC address %pM.\n",
 	       dev->name, priv->realirq, dev->base_addr,
 	       dev->mem_start, dev->mem_end - 1,
-	       print_mac(mac, dev->dev_addr));
+	       dev->dev_addr);
 	printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]);
 
 	/* reset board */
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index c2d57f8..9bc0f17 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -527,7 +527,7 @@
 
 static int ibmveth_open(struct net_device *netdev)
 {
-	struct ibmveth_adapter *adapter = netdev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(netdev);
 	u64 mac_address = 0;
 	int rxq_entries = 1;
 	unsigned long lpar_rc;
@@ -666,7 +666,7 @@
 
 static int ibmveth_close(struct net_device *netdev)
 {
-	struct ibmveth_adapter *adapter = netdev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(netdev);
 	long lpar_rc;
 
 	ibmveth_debug_printk("close starting\n");
@@ -722,7 +722,7 @@
 
 static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data)
 {
-	struct ibmveth_adapter *adapter = dev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(dev);
 
 	if (data)
 		adapter->rx_csum = 1;
@@ -741,7 +741,7 @@
 
 static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data)
 {
-	struct ibmveth_adapter *adapter = dev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(dev);
 
 	if (data) {
 		dev->features |= NETIF_F_IP_CSUM;
@@ -753,7 +753,7 @@
 static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
 				    void (*done) (struct net_device *, u32))
 {
-	struct ibmveth_adapter *adapter = dev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(dev);
 	u64 set_attr, clr_attr, ret_attr;
 	long ret;
 	int rc1 = 0, rc2 = 0;
@@ -805,7 +805,7 @@
 
 static int ibmveth_set_rx_csum(struct net_device *dev, u32 data)
 {
-	struct ibmveth_adapter *adapter = dev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(dev);
 
 	if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum))
 		return 0;
@@ -815,7 +815,7 @@
 
 static int ibmveth_set_tx_csum(struct net_device *dev, u32 data)
 {
-	struct ibmveth_adapter *adapter = dev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(dev);
 	int rc = 0;
 
 	if (data && (dev->features & NETIF_F_IP_CSUM))
@@ -833,7 +833,7 @@
 
 static u32 ibmveth_get_rx_csum(struct net_device *dev)
 {
-	struct ibmveth_adapter *adapter = dev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(dev);
 	return adapter->rx_csum;
 }
 
@@ -862,7 +862,7 @@
 				      struct ethtool_stats *stats, u64 *data)
 {
 	int i;
-	struct ibmveth_adapter *adapter = dev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(dev);
 
 	for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++)
 		data[i] = IBMVETH_GET_STAT(adapter, ibmveth_stats[i].offset);
@@ -889,7 +889,7 @@
 
 static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-	struct ibmveth_adapter *adapter = netdev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(netdev);
 	union ibmveth_buf_desc desc;
 	unsigned long lpar_rc;
 	unsigned long correlator;
@@ -1014,7 +1014,6 @@
 			netdev->stats.rx_packets++;
 			netdev->stats.rx_bytes += length;
 			frames_processed++;
-			netdev->last_rx = jiffies;
 		}
 	} while (frames_processed < budget);
 
@@ -1029,10 +1028,10 @@
 
 		ibmveth_assert(lpar_rc == H_SUCCESS);
 
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 
 		if (ibmveth_rxq_pending_buffer(adapter) &&
-		    netif_rx_reschedule(netdev, napi)) {
+		    netif_rx_reschedule(napi)) {
 			lpar_rc = h_vio_signal(adapter->vdev->unit_address,
 					       VIO_IRQ_DISABLE);
 			goto restart_poll;
@@ -1045,21 +1044,21 @@
 static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance)
 {
 	struct net_device *netdev = dev_instance;
-	struct ibmveth_adapter *adapter = netdev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(netdev);
 	unsigned long lpar_rc;
 
-	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+	if (netif_rx_schedule_prep(&adapter->napi)) {
 		lpar_rc = h_vio_signal(adapter->vdev->unit_address,
 				       VIO_IRQ_DISABLE);
 		ibmveth_assert(lpar_rc == H_SUCCESS);
-		__netif_rx_schedule(netdev, &adapter->napi);
+		__netif_rx_schedule(&adapter->napi);
 	}
 	return IRQ_HANDLED;
 }
 
 static void ibmveth_set_multicast_list(struct net_device *netdev)
 {
-	struct ibmveth_adapter *adapter = netdev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(netdev);
 	unsigned long lpar_rc;
 
 	if((netdev->flags & IFF_PROMISC) || (netdev->mc_count > adapter->mcastFilterSize)) {
@@ -1107,7 +1106,7 @@
 
 static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct ibmveth_adapter *adapter = dev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(dev);
 	struct vio_dev *viodev = adapter->vdev;
 	int new_mtu_oh = new_mtu + IBMVETH_BUFF_OH;
 	int i;
@@ -1159,7 +1158,7 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void ibmveth_poll_controller(struct net_device *dev)
 {
-	ibmveth_replenish_task(dev->priv);
+	ibmveth_replenish_task(netdev_priv(dev));
 	ibmveth_interrupt(dev->irq, dev);
 }
 #endif
@@ -1241,7 +1240,7 @@
 	if(!netdev)
 		return -ENOMEM;
 
-	adapter = netdev->priv;
+	adapter = netdev_priv(netdev);
 	dev->dev.driver_data = netdev;
 
 	adapter->vdev = dev;
@@ -1337,7 +1336,7 @@
 static int __devexit ibmveth_remove(struct vio_dev *dev)
 {
 	struct net_device *netdev = dev->dev.driver_data;
-	struct ibmveth_adapter *adapter = netdev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(netdev);
 	int i;
 
 	for(i = 0; i<IbmVethNumBufferPools; i++)
@@ -1371,13 +1370,12 @@
 	struct ibmveth_adapter *adapter = seq->private;
 	char *current_mac = ((char*) &adapter->netdev->dev_addr);
 	char *firmware_mac = ((char*) &adapter->mac_addr) ;
-	DECLARE_MAC_BUF(mac);
 
 	seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version);
 
 	seq_printf(seq, "Unit Address:    0x%x\n", adapter->vdev->unit_address);
-	seq_printf(seq, "Current MAC:     %s\n", print_mac(mac, current_mac));
-	seq_printf(seq, "Firmware MAC:    %s\n", print_mac(mac, firmware_mac));
+	seq_printf(seq, "Current MAC:     %pM\n", current_mac);
+	seq_printf(seq, "Firmware MAC:    %pM\n", firmware_mac);
 
 	seq_printf(seq, "\nAdapter Statistics:\n");
 	seq_printf(seq, "  TX:  vio_map_single failres:      %ld\n", adapter->tx_map_failed);
@@ -1472,7 +1470,7 @@
 						      kobj);
 	struct net_device *netdev =
 	    container_of(kobj->parent, struct device, kobj)->driver_data;
-	struct ibmveth_adapter *adapter = netdev->priv;
+	struct ibmveth_adapter *adapter = netdev_priv(netdev);
 	long value = simple_strtol(buf, NULL, 10);
 	long rc;
 
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index e4fbefc..60a2630 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -137,18 +137,23 @@
 
 }
 
+static const struct net_device_ops ifb_netdev_ops = {
+	.ndo_open	= ifb_open,
+	.ndo_stop	= ifb_close,
+	.ndo_start_xmit	= ifb_xmit,
+	.ndo_validate_addr = eth_validate_addr,
+};
+
 static void ifb_setup(struct net_device *dev)
 {
 	/* Initialize the device structure. */
-	dev->hard_start_xmit = ifb_xmit;
-	dev->open = &ifb_open;
-	dev->stop = &ifb_close;
 	dev->destructor = free_netdev;
+	dev->netdev_ops = &ifb_netdev_ops;
 
 	/* Fill in device structure with ethernet-generic values. */
 	ether_setup(dev);
 	dev->tx_queue_len = TX_Q_LIMIT;
-	dev->change_mtu = NULL;
+
 	dev->flags |= IFF_NOARP;
 	dev->flags &= ~IFF_MULTICAST;
 	random_ether_addr(dev->dev_addr);
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index ce70068..40d0342 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -168,18 +168,12 @@
 #define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
 #define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
 #define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
 #define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
 #define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
 #define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
 #define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
-#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
-#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
-#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
 #define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
 #define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
-#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
 #define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
 
 /*
@@ -329,6 +323,7 @@
 #define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
 #define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
 #define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
 /* Extended desc bits for Linksec and timesync */
 
 /* Transmit Control */
diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c
index e18747c..97f0049 100644
--- a/drivers/net/igb/e1000_mac.c
+++ b/drivers/net/igb/e1000_mac.c
@@ -50,13 +50,6 @@
 	kfree(hw->dev_spec);
 }
 
-static void igb_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value)
-{
-	struct igb_adapter *adapter = hw->back;
-
-	pci_read_config_word(adapter->pdev, reg, value);
-}
-
 static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
 {
 	struct igb_adapter *adapter = hw->back;
@@ -83,8 +76,8 @@
 {
 	struct e1000_bus_info *bus = &hw->bus;
 	s32 ret_val;
-	u32 status;
-	u16 pcie_link_status, pci_header_type;
+	u32 reg;
+	u16 pcie_link_status;
 
 	bus->type = e1000_bus_type_pci_express;
 	bus->speed = e1000_bus_speed_2500;
@@ -99,14 +92,8 @@
 						     PCIE_LINK_WIDTH_MASK) >>
 						     PCIE_LINK_WIDTH_SHIFT);
 
-	igb_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type);
-	if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
-		status = rd32(E1000_STATUS);
-		bus->func = (status & E1000_STATUS_FUNC_MASK)
-			    >> E1000_STATUS_FUNC_SHIFT;
-	} else {
-		bus->func = 0;
-	}
+	reg = rd32(E1000_STATUS);
+	bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
 
 	return 0;
 }
@@ -229,8 +216,8 @@
 	if (!hw->mac.disable_av)
 		rar_high |= E1000_RAH_AV;
 
-	array_wr32(E1000_RA, (index << 1), rar_low);
-	array_wr32(E1000_RA, ((index << 1) + 1), rar_high);
+	wr32(E1000_RAL(index), rar_low);
+	wr32(E1000_RAH(index), rar_high);
 }
 
 /**
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
index 95523af..bdf5d83 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/igb/e1000_regs.h
@@ -221,6 +221,10 @@
 #define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
 #define E1000_RA       0x05400  /* Receive Address - RW Array */
 #define E1000_RA2      0x054E0  /* 2nd half of receive address array - RW Array */
+#define E1000_RAL(_i)  (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
+                                       (0x054E0 + ((_i - 16) * 8)))
+#define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
+                                       (0x054E4 + ((_i - 16) * 8)))
 #define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
 #define E1000_VMD_CTL  0x0581C  /* VMDq Control - RW */
 #define E1000_WUC      0x05800  /* Wakeup Control - RW */
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
index 4ff6f05..5a27825 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/igb/igb.h
@@ -43,8 +43,6 @@
 #endif
 
 /* Interrupt defines */
-#define IGB_MAX_TX_CLEAN 72
-
 #define IGB_MIN_DYN_ITR 3000
 #define IGB_MAX_DYN_ITR 96000
 
@@ -127,7 +125,8 @@
 		/* TX */
 		struct {
 			unsigned long time_stamp;
-			u32 length;
+			u16 length;
+			u16 next_to_watch;
 		};
 		/* RX */
 		struct {
@@ -160,7 +159,8 @@
 	u16 itr_register;
 	u16 cpu;
 
-	int queue_index;
+	u16 queue_index;
+	u16 reg_idx;
 	unsigned int total_bytes;
 	unsigned int total_packets;
 
@@ -294,6 +294,8 @@
 	unsigned int lro_flushed;
 	unsigned int lro_no_desc;
 #endif
+	unsigned int tx_ring_count;
+	unsigned int rx_ring_count;
 };
 
 #define IGB_FLAG_HAS_MSI           (1 << 0)
@@ -325,7 +327,41 @@
 extern int igb_set_spd_dplx(struct igb_adapter *, u16);
 extern int igb_setup_tx_resources(struct igb_adapter *, struct igb_ring *);
 extern int igb_setup_rx_resources(struct igb_adapter *, struct igb_ring *);
+extern void igb_free_tx_resources(struct igb_ring *);
+extern void igb_free_rx_resources(struct igb_ring *);
 extern void igb_update_stats(struct igb_adapter *);
 extern void igb_set_ethtool_ops(struct net_device *);
 
+static inline s32 igb_reset_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.reset_phy)
+		return hw->phy.ops.reset_phy(hw);
+
+	return 0;
+}
+
+static inline s32 igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	if (hw->phy.ops.read_phy_reg)
+		return hw->phy.ops.read_phy_reg(hw, offset, data);
+
+	return 0;
+}
+
+static inline s32 igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	if (hw->phy.ops.write_phy_reg)
+		return hw->phy.ops.write_phy_reg(hw, offset, data);
+
+	return 0;
+}
+
+static inline s32 igb_get_phy_info(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.get_phy_info)
+		return hw->phy.ops.get_phy_info(hw);
+
+	return 0;
+}
+
 #endif /* _IGB_H_ */
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index 89964fa..3c831f1 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -101,8 +101,8 @@
 };
 
 #define IGB_QUEUE_STATS_LEN \
-	((((struct igb_adapter *)netdev->priv)->num_rx_queues + \
-	 ((struct igb_adapter *)netdev->priv)->num_tx_queues) * \
+	((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues + \
+	 ((struct igb_adapter *)netdev_priv(netdev))->num_tx_queues) * \
 	(sizeof(struct igb_queue_stats) / sizeof(u64)))
 #define IGB_GLOBAL_STATS_LEN	\
 	sizeof(igb_gstrings_stats) / sizeof(struct igb_stats)
@@ -494,8 +494,6 @@
 
 	/* These should probably be added to e1000_regs.h instead */
 	#define E1000_PSRTYPE_REG(_i) (0x05480 + ((_i) * 4))
-	#define E1000_RAL(_i)         (0x05400 + ((_i) * 8))
-	#define E1000_RAH(_i)         (0x05404 + ((_i) * 8))
 	#define E1000_IP4AT_REG(_i)   (0x05840 + ((_i) * 8))
 	#define E1000_IP6AT_REG(_i)   (0x05880 + ((_i) * 4))
 	#define E1000_WUPM_REG(_i)    (0x05A00 + ((_i) * 4))
@@ -714,15 +712,13 @@
 			      struct ethtool_ringparam *ring)
 {
 	struct igb_adapter *adapter = netdev_priv(netdev);
-	struct igb_ring *tx_ring = adapter->tx_ring;
-	struct igb_ring *rx_ring = adapter->rx_ring;
 
 	ring->rx_max_pending = IGB_MAX_RXD;
 	ring->tx_max_pending = IGB_MAX_TXD;
 	ring->rx_mini_max_pending = 0;
 	ring->rx_jumbo_max_pending = 0;
-	ring->rx_pending = rx_ring->count;
-	ring->tx_pending = tx_ring->count;
+	ring->rx_pending = adapter->rx_ring_count;
+	ring->tx_pending = adapter->tx_ring_count;
 	ring->rx_mini_pending = 0;
 	ring->rx_jumbo_pending = 0;
 }
@@ -731,12 +727,9 @@
 			     struct ethtool_ringparam *ring)
 {
 	struct igb_adapter *adapter = netdev_priv(netdev);
-	struct igb_buffer *old_buf;
-	struct igb_buffer *old_rx_buf;
-	void *old_desc;
+	struct igb_ring *temp_ring;
 	int i, err;
-	u32 new_rx_count, new_tx_count, old_size;
-	dma_addr_t old_dma;
+	u32 new_rx_count, new_tx_count;
 
 	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
 		return -EINVAL;
@@ -749,12 +742,19 @@
 	new_tx_count = min(new_tx_count, (u32)IGB_MAX_TXD);
 	new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE);
 
-	if ((new_tx_count == adapter->tx_ring->count) &&
-	    (new_rx_count == adapter->rx_ring->count)) {
+	if ((new_tx_count == adapter->tx_ring_count) &&
+	    (new_rx_count == adapter->rx_ring_count)) {
 		/* nothing to do */
 		return 0;
 	}
 
+	if (adapter->num_tx_queues > adapter->num_rx_queues)
+		temp_ring = vmalloc(adapter->num_tx_queues * sizeof(struct igb_ring));
+	else
+		temp_ring = vmalloc(adapter->num_rx_queues * sizeof(struct igb_ring));
+	if (!temp_ring)
+		return -ENOMEM;
+
 	while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
 		msleep(1);
 
@@ -766,62 +766,55 @@
 	 * because the ISRs in MSI-X mode get passed pointers
 	 * to the tx and rx ring structs.
 	 */
-	if (new_tx_count != adapter->tx_ring->count) {
+	if (new_tx_count != adapter->tx_ring_count) {
+		memcpy(temp_ring, adapter->tx_ring,
+		       adapter->num_tx_queues * sizeof(struct igb_ring));
+
 		for (i = 0; i < adapter->num_tx_queues; i++) {
-			/* Save existing descriptor ring */
-			old_buf = adapter->tx_ring[i].buffer_info;
-			old_desc = adapter->tx_ring[i].desc;
-			old_size = adapter->tx_ring[i].size;
-			old_dma = adapter->tx_ring[i].dma;
-			/* Try to allocate a new one */
-			adapter->tx_ring[i].buffer_info = NULL;
-			adapter->tx_ring[i].desc = NULL;
-			adapter->tx_ring[i].count = new_tx_count;
-			err = igb_setup_tx_resources(adapter,
-						&adapter->tx_ring[i]);
+			temp_ring[i].count = new_tx_count;
+			err = igb_setup_tx_resources(adapter, &temp_ring[i]);
 			if (err) {
-				/* Restore the old one so at least
-				   the adapter still works, even if
-				   we failed the request */
-				adapter->tx_ring[i].buffer_info = old_buf;
-				adapter->tx_ring[i].desc = old_desc;
-				adapter->tx_ring[i].size = old_size;
-				adapter->tx_ring[i].dma = old_dma;
+				while (i) {
+					i--;
+					igb_free_tx_resources(&temp_ring[i]);
+				}
 				goto err_setup;
 			}
-			/* Free the old buffer manually */
-			vfree(old_buf);
-			pci_free_consistent(adapter->pdev, old_size,
-					    old_desc, old_dma);
 		}
+
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			igb_free_tx_resources(&adapter->tx_ring[i]);
+
+		memcpy(adapter->tx_ring, temp_ring,
+		       adapter->num_tx_queues * sizeof(struct igb_ring));
+
+		adapter->tx_ring_count = new_tx_count;
 	}
 
 	if (new_rx_count != adapter->rx_ring->count) {
+		memcpy(temp_ring, adapter->rx_ring,
+		       adapter->num_rx_queues * sizeof(struct igb_ring));
+
 		for (i = 0; i < adapter->num_rx_queues; i++) {
-
-			old_rx_buf = adapter->rx_ring[i].buffer_info;
-			old_desc = adapter->rx_ring[i].desc;
-			old_size = adapter->rx_ring[i].size;
-			old_dma = adapter->rx_ring[i].dma;
-
-			adapter->rx_ring[i].buffer_info = NULL;
-			adapter->rx_ring[i].desc = NULL;
-			adapter->rx_ring[i].dma = 0;
-			adapter->rx_ring[i].count = new_rx_count;
-			err = igb_setup_rx_resources(adapter,
-						     &adapter->rx_ring[i]);
+			temp_ring[i].count = new_rx_count;
+			err = igb_setup_rx_resources(adapter, &temp_ring[i]);
 			if (err) {
-				adapter->rx_ring[i].buffer_info = old_rx_buf;
-				adapter->rx_ring[i].desc = old_desc;
-				adapter->rx_ring[i].size = old_size;
-				adapter->rx_ring[i].dma = old_dma;
+				while (i) {
+					i--;
+					igb_free_rx_resources(&temp_ring[i]);
+				}
 				goto err_setup;
 			}
 
-			vfree(old_rx_buf);
-			pci_free_consistent(adapter->pdev, old_size, old_desc,
-					    old_dma);
 		}
+
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			igb_free_rx_resources(&adapter->rx_ring[i]);
+
+		memcpy(adapter->rx_ring, temp_ring,
+		       adapter->num_rx_queues * sizeof(struct igb_ring));
+
+		adapter->rx_ring_count = new_rx_count;
 	}
 
 	err = 0;
@@ -830,6 +823,7 @@
 		igb_up(adapter);
 
 	clear_bit(__IGB_RESETTING, &adapter->state);
+	vfree(temp_ring);
 	return err;
 }
 
@@ -1343,8 +1337,9 @@
 	wr32(E1000_RDLEN(0), rx_ring->size);
 	wr32(E1000_RDH(0), 0);
 	wr32(E1000_RDT(0), 0);
+	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
 	rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
-		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+		E1000_RCTL_RDMTS_HALF |
 		(adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
 	wr32(E1000_RCTL, rctl);
 	wr32(E1000_SRRCTL(0), 0);
@@ -1380,10 +1375,10 @@
 	struct e1000_hw *hw = &adapter->hw;
 
 	/* Write out to PHY registers 29 and 30 to disable the Receiver. */
-	hw->phy.ops.write_phy_reg(hw, 29, 0x001F);
-	hw->phy.ops.write_phy_reg(hw, 30, 0x8FFC);
-	hw->phy.ops.write_phy_reg(hw, 29, 0x001A);
-	hw->phy.ops.write_phy_reg(hw, 30, 0x8FF0);
+	igb_write_phy_reg(hw, 29, 0x001F);
+	igb_write_phy_reg(hw, 30, 0x8FFC);
+	igb_write_phy_reg(hw, 29, 0x001A);
+	igb_write_phy_reg(hw, 30, 0x8FF0);
 }
 
 static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
@@ -1396,17 +1391,17 @@
 
 	if (hw->phy.type == e1000_phy_m88) {
 		/* Auto-MDI/MDIX Off */
-		hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
+		igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
 		/* reset to update Auto-MDI/MDIX */
-		hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x9140);
+		igb_write_phy_reg(hw, PHY_CONTROL, 0x9140);
 		/* autoneg off */
-		hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x8140);
+		igb_write_phy_reg(hw, PHY_CONTROL, 0x8140);
 	}
 
 	ctrl_reg = rd32(E1000_CTRL);
 
 	/* force 1000, set loopback */
-	hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x4140);
+	igb_write_phy_reg(hw, PHY_CONTROL, 0x4140);
 
 	/* Now set up the MAC to the same speed/duplex as the PHY. */
 	ctrl_reg = rd32(E1000_CTRL);
@@ -1500,10 +1495,10 @@
 	wr32(E1000_RCTL, rctl);
 
 	hw->mac.autoneg = true;
-	hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_reg);
+	igb_read_phy_reg(hw, PHY_CONTROL, &phy_reg);
 	if (phy_reg & MII_CR_LOOPBACK) {
 		phy_reg &= ~MII_CR_LOOPBACK;
-		hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_reg);
+		igb_write_phy_reg(hw, PHY_CONTROL, phy_reg);
 		igb_phy_sw_reset(hw);
 	}
 }
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 20d27e6..022794e 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -42,6 +42,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/if_ether.h>
+#include <linux/aer.h>
 #ifdef CONFIG_IGB_DCA
 #include <linux/dca.h>
 #endif
@@ -76,8 +77,6 @@
 static int igb_setup_all_rx_resources(struct igb_adapter *);
 static void igb_free_all_tx_resources(struct igb_adapter *);
 static void igb_free_all_rx_resources(struct igb_adapter *);
-static void igb_free_tx_resources(struct igb_ring *);
-static void igb_free_rx_resources(struct igb_ring *);
 void igb_update_stats(struct igb_adapter *);
 static int igb_probe(struct pci_dev *, const struct pci_device_id *);
 static void __devexit igb_remove(struct pci_dev *pdev);
@@ -232,6 +231,40 @@
 
 module_exit(igb_exit_module);
 
+#define Q_IDX_82576(i) (((i & 0x1) << 3) + (i >> 1))
+/**
+ * igb_cache_ring_register - Descriptor ring to register mapping
+ * @adapter: board private structure to initialize
+ *
+ * Once we know the feature-set enabled for the device, we'll cache
+ * the register offset the descriptor ring is assigned to.
+ **/
+static void igb_cache_ring_register(struct igb_adapter *adapter)
+{
+	int i;
+
+	switch (adapter->hw.mac.type) {
+	case e1000_82576:
+		/* The queues are allocated for virtualization such that VF 0
+		 * is allocated queues 0 and 8, VF 1 queues 1 and 9, etc.
+		 * In order to avoid collision we start at the first free queue
+		 * and continue consuming queues in the same sequence
+		 */
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			adapter->rx_ring[i].reg_idx = Q_IDX_82576(i);
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			adapter->tx_ring[i].reg_idx = Q_IDX_82576(i);
+		break;
+	case e1000_82575:
+	default:
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			adapter->rx_ring[i].reg_idx = i;
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			adapter->tx_ring[i].reg_idx = i;
+		break;
+	}
+}
+
 /**
  * igb_alloc_queues - Allocate memory for all rings
  * @adapter: board private structure to initialize
@@ -259,11 +292,13 @@
 
 	for (i = 0; i < adapter->num_tx_queues; i++) {
 		struct igb_ring *ring = &(adapter->tx_ring[i]);
+		ring->count = adapter->tx_ring_count;
 		ring->adapter = adapter;
 		ring->queue_index = i;
 	}
 	for (i = 0; i < adapter->num_rx_queues; i++) {
 		struct igb_ring *ring = &(adapter->rx_ring[i]);
+		ring->count = adapter->rx_ring_count;
 		ring->adapter = adapter;
 		ring->queue_index = i;
 		ring->itr_register = E1000_ITR;
@@ -271,6 +306,8 @@
 		/* set a default napi handler for each rx_ring */
 		netif_napi_add(adapter->netdev, &ring->napi, igb_poll, 64);
 	}
+
+	igb_cache_ring_register(adapter);
 	return 0;
 }
 
@@ -311,36 +348,36 @@
 		array_wr32(E1000_MSIXBM(0), msix_vector, msixbm);
 		break;
 	case e1000_82576:
-		/* The 82576 uses a table-based method for assigning vectors.
+		/* 82576 uses a table-based method for assigning vectors.
 		   Each queue has a single entry in the table to which we write
 		   a vector number along with a "valid" bit.  Sadly, the layout
 		   of the table is somewhat counterintuitive. */
 		if (rx_queue > IGB_N0_QUEUE) {
-			index = (rx_queue & 0x7);
+			index = (rx_queue >> 1);
 			ivar = array_rd32(E1000_IVAR0, index);
-			if (rx_queue < 8) {
-				/* vector goes into low byte of register */
-				ivar = ivar & 0xFFFFFF00;
-				ivar |= msix_vector | E1000_IVAR_VALID;
-			} else {
+			if (rx_queue & 0x1) {
 				/* vector goes into third byte of register */
 				ivar = ivar & 0xFF00FFFF;
 				ivar |= (msix_vector | E1000_IVAR_VALID) << 16;
+			} else {
+				/* vector goes into low byte of register */
+				ivar = ivar & 0xFFFFFF00;
+				ivar |= msix_vector | E1000_IVAR_VALID;
 			}
 			adapter->rx_ring[rx_queue].eims_value= 1 << msix_vector;
 			array_wr32(E1000_IVAR0, index, ivar);
 		}
 		if (tx_queue > IGB_N0_QUEUE) {
-			index = (tx_queue & 0x7);
+			index = (tx_queue >> 1);
 			ivar = array_rd32(E1000_IVAR0, index);
-			if (tx_queue < 8) {
-				/* vector goes into second byte of register */
-				ivar = ivar & 0xFFFF00FF;
-				ivar |= (msix_vector | E1000_IVAR_VALID) << 8;
-			} else {
+			if (tx_queue & 0x1) {
 				/* vector goes into high byte of register */
 				ivar = ivar & 0x00FFFFFF;
 				ivar |= (msix_vector | E1000_IVAR_VALID) << 24;
+			} else {
+				/* vector goes into second byte of register */
+				ivar = ivar & 0xFFFF00FF;
+				ivar |= (msix_vector | E1000_IVAR_VALID) << 8;
 			}
 			adapter->tx_ring[tx_queue].eims_value= 1 << msix_vector;
 			array_wr32(E1000_IVAR0, index, ivar);
@@ -445,7 +482,7 @@
 
 	for (i = 0; i < adapter->num_tx_queues; i++) {
 		struct igb_ring *ring = &(adapter->tx_ring[i]);
-		sprintf(ring->name, "%s-tx%d", netdev->name, i);
+		sprintf(ring->name, "%s-tx-%d", netdev->name, i);
 		err = request_irq(adapter->msix_entries[vector].vector,
 				  &igb_msix_tx, 0, ring->name,
 				  &(adapter->tx_ring[i]));
@@ -458,7 +495,7 @@
 	for (i = 0; i < adapter->num_rx_queues; i++) {
 		struct igb_ring *ring = &(adapter->rx_ring[i]);
 		if (strlen(netdev->name) < (IFNAMSIZ - 5))
-			sprintf(ring->name, "%s-rx%d", netdev->name, i);
+			sprintf(ring->name, "%s-rx-%d", netdev->name, i);
 		else
 			memcpy(ring->name, netdev->name, IFNAMSIZ);
 		err = request_irq(adapter->msix_entries[vector].vector,
@@ -931,8 +968,7 @@
 	wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE);
 
 	igb_reset_adaptive(&adapter->hw);
-	if (adapter->hw.phy.ops.get_phy_info)
-		adapter->hw.phy.ops.get_phy_info(&adapter->hw);
+	igb_get_phy_info(&adapter->hw);
 }
 
 /**
@@ -950,6 +986,25 @@
 	}
 }
 
+static const struct net_device_ops igb_netdev_ops = {
+	.ndo_open 		= igb_open,
+	.ndo_stop		= igb_close,
+	.ndo_start_xmit		= igb_xmit_frame_adv,
+	.ndo_get_stats		= igb_get_stats,
+	.ndo_set_multicast_list	= igb_set_multi,
+	.ndo_set_mac_address	= igb_set_mac,
+	.ndo_change_mtu		= igb_change_mtu,
+	.ndo_do_ioctl		= igb_ioctl,
+	.ndo_tx_timeout		= igb_tx_timeout,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_vlan_rx_register	= igb_vlan_rx_register,
+	.ndo_vlan_rx_add_vid	= igb_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= igb_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= igb_netpoll,
+#endif
+};
+
 /**
  * igb_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -1031,6 +1086,13 @@
 	if (err)
 		goto err_pci_reg;
 
+	err = pci_enable_pcie_error_reporting(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed "
+		        "0x%x\n", err);
+		/* non-fatal, continue */
+	}
+
 	pci_set_master(pdev);
 	pci_save_state(pdev);
 
@@ -1059,23 +1121,9 @@
 	if (!adapter->hw.hw_addr)
 		goto err_ioremap;
 
-	netdev->open = &igb_open;
-	netdev->stop = &igb_close;
-	netdev->get_stats = &igb_get_stats;
-	netdev->set_multicast_list = &igb_set_multi;
-	netdev->set_mac_address = &igb_set_mac;
-	netdev->change_mtu = &igb_change_mtu;
-	netdev->do_ioctl = &igb_ioctl;
+	netdev->netdev_ops = &igb_netdev_ops;
 	igb_set_ethtool_ops(netdev);
-	netdev->tx_timeout = &igb_tx_timeout;
 	netdev->watchdog_timeo = 5 * HZ;
-	netdev->vlan_rx_register = igb_vlan_rx_register;
-	netdev->vlan_rx_add_vid = igb_vlan_rx_add_vid;
-	netdev->vlan_rx_kill_vid = igb_vlan_rx_kill_vid;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	netdev->poll_controller = igb_netpoll;
-#endif
-	netdev->hard_start_xmit = &igb_xmit_frame_adv;
 
 	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
 
@@ -1275,16 +1323,14 @@
 
 	dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n");
 	/* print bus type/speed/width info */
-	dev_info(&pdev->dev,
-		 "%s: (PCIe:%s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n",
+	dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n",
 		 netdev->name,
 		 ((hw->bus.speed == e1000_bus_speed_2500)
 		  ? "2.5Gb/s" : "unknown"),
 		 ((hw->bus.width == e1000_bus_width_pcie_x4)
 		  ? "Width x4" : (hw->bus.width == e1000_bus_width_pcie_x1)
 		  ? "Width x1" : "unknown"),
-		 netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
-		 netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+		 netdev->dev_addr);
 
 	igb_read_part_num(hw, &part_num);
 	dev_info(&pdev->dev, "%s: PBA No: %06x-%03x\n", netdev->name,
@@ -1302,7 +1348,7 @@
 	igb_release_hw_control(adapter);
 err_eeprom:
 	if (!igb_check_reset_block(hw))
-		hw->phy.ops.reset_phy(hw);
+		igb_reset_phy(hw);
 
 	if (hw->flash_address)
 		iounmap(hw->flash_address);
@@ -1338,6 +1384,7 @@
 #ifdef CONFIG_IGB_DCA
 	struct e1000_hw *hw = &adapter->hw;
 #endif
+	int err;
 
 	/* flush_scheduled work may reschedule our watchdog task, so
 	 * explicitly disable watchdog tasks from being rescheduled  */
@@ -1362,9 +1409,8 @@
 
 	unregister_netdev(netdev);
 
-	if (adapter->hw.phy.ops.reset_phy &&
-	    !igb_check_reset_block(&adapter->hw))
-		adapter->hw.phy.ops.reset_phy(&adapter->hw);
+	if (!igb_check_reset_block(&adapter->hw))
+		igb_reset_phy(&adapter->hw);
 
 	igb_remove_device(&adapter->hw);
 	igb_reset_interrupt_capability(adapter);
@@ -1378,6 +1424,11 @@
 
 	free_netdev(netdev);
 
+	err = pci_disable_pcie_error_reporting(pdev);
+	if (err)
+		dev_err(&pdev->dev,
+		        "pci_disable_pcie_error_reporting failed 0x%x\n", err);
+
 	pci_disable_device(pdev);
 }
 
@@ -1397,6 +1448,8 @@
 
 	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
 
+	adapter->tx_ring_count = IGB_DEFAULT_TXD;
+	adapter->rx_ring_count = IGB_DEFAULT_RXD;
 	adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
 	adapter->rx_ps_hdr_size = 0; /* disable packet split */
 	adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
@@ -1558,8 +1611,7 @@
 	memset(tx_ring->buffer_info, 0, size);
 
 	/* round up to nearest 4K */
-	tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc)
-			+ sizeof(u32);
+	tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
 	tx_ring->size = ALIGN(tx_ring->size, 4096);
 
 	tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
@@ -1618,43 +1670,37 @@
  **/
 static void igb_configure_tx(struct igb_adapter *adapter)
 {
-	u64 tdba, tdwba;
+	u64 tdba;
 	struct e1000_hw *hw = &adapter->hw;
 	u32 tctl;
 	u32 txdctl, txctrl;
-	int i;
+	int i, j;
 
 	for (i = 0; i < adapter->num_tx_queues; i++) {
 		struct igb_ring *ring = &(adapter->tx_ring[i]);
-
-		wr32(E1000_TDLEN(i),
+		j = ring->reg_idx;
+		wr32(E1000_TDLEN(j),
 				ring->count * sizeof(struct e1000_tx_desc));
 		tdba = ring->dma;
-		wr32(E1000_TDBAL(i),
+		wr32(E1000_TDBAL(j),
 				tdba & 0x00000000ffffffffULL);
-		wr32(E1000_TDBAH(i), tdba >> 32);
+		wr32(E1000_TDBAH(j), tdba >> 32);
 
-		tdwba = ring->dma + ring->count * sizeof(struct e1000_tx_desc);
-		tdwba |= 1; /* enable head wb */
-		wr32(E1000_TDWBAL(i),
-				tdwba & 0x00000000ffffffffULL);
-		wr32(E1000_TDWBAH(i), tdwba >> 32);
-
-		ring->head = E1000_TDH(i);
-		ring->tail = E1000_TDT(i);
+		ring->head = E1000_TDH(j);
+		ring->tail = E1000_TDT(j);
 		writel(0, hw->hw_addr + ring->tail);
 		writel(0, hw->hw_addr + ring->head);
-		txdctl = rd32(E1000_TXDCTL(i));
+		txdctl = rd32(E1000_TXDCTL(j));
 		txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
-		wr32(E1000_TXDCTL(i), txdctl);
+		wr32(E1000_TXDCTL(j), txdctl);
 
 		/* Turn off Relaxed Ordering on head write-backs.  The
 		 * writebacks MUST be delivered in order or it will
 		 * completely screw up our bookeeping.
 		 */
-		txctrl = rd32(E1000_DCA_TXCTRL(i));
+		txctrl = rd32(E1000_DCA_TXCTRL(j));
 		txctrl &= ~E1000_DCA_TXCTRL_TX_WB_RO_EN;
-		wr32(E1000_DCA_TXCTRL(i), txctrl);
+		wr32(E1000_DCA_TXCTRL(j), txctrl);
 	}
 
 
@@ -1771,14 +1817,14 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 rctl;
 	u32 srrctl = 0;
-	int i;
+	int i, j;
 
 	rctl = rd32(E1000_RCTL);
 
 	rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
+	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
 
-	rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
-		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+	rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_RDMTS_HALF |
 		(adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
 
 	/*
@@ -1788,38 +1834,26 @@
 	*/
 	rctl |= E1000_RCTL_SECRC;
 
-	rctl &= ~E1000_RCTL_SBP;
+	/*
+	 * disable store bad packets, long packet enable, and clear size bits.
+	 */
+	rctl &= ~(E1000_RCTL_SBP | E1000_RCTL_LPE | E1000_RCTL_SZ_256);
 
-	if (adapter->netdev->mtu <= ETH_DATA_LEN)
-		rctl &= ~E1000_RCTL_LPE;
-	else
+	if (adapter->netdev->mtu > ETH_DATA_LEN)
 		rctl |= E1000_RCTL_LPE;
-	if (adapter->rx_buffer_len <= IGB_RXBUFFER_2048) {
-		/* Setup buffer sizes */
-		rctl &= ~E1000_RCTL_SZ_4096;
-		rctl |= E1000_RCTL_BSEX;
-		switch (adapter->rx_buffer_len) {
-		case IGB_RXBUFFER_256:
-			rctl |= E1000_RCTL_SZ_256;
-			rctl &= ~E1000_RCTL_BSEX;
-			break;
-		case IGB_RXBUFFER_512:
-			rctl |= E1000_RCTL_SZ_512;
-			rctl &= ~E1000_RCTL_BSEX;
-			break;
-		case IGB_RXBUFFER_1024:
-			rctl |= E1000_RCTL_SZ_1024;
-			rctl &= ~E1000_RCTL_BSEX;
-			break;
-		case IGB_RXBUFFER_2048:
-		default:
-			rctl |= E1000_RCTL_SZ_2048;
-			rctl &= ~E1000_RCTL_BSEX;
-			break;
-		}
-	} else {
-		rctl &= ~E1000_RCTL_BSEX;
-		srrctl = adapter->rx_buffer_len >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+
+	/* Setup buffer sizes */
+	switch (adapter->rx_buffer_len) {
+	case IGB_RXBUFFER_256:
+		rctl |= E1000_RCTL_SZ_256;
+		break;
+	case IGB_RXBUFFER_512:
+		rctl |= E1000_RCTL_SZ_512;
+		break;
+	default:
+		srrctl = ALIGN(adapter->rx_buffer_len, 1024)
+		         >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+		break;
 	}
 
 	/* 82575 and greater support packet-split where the protocol
@@ -1841,8 +1875,10 @@
 		srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
 	}
 
-	for (i = 0; i < adapter->num_rx_queues; i++)
-		wr32(E1000_SRRCTL(i), srrctl);
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		j = adapter->rx_ring[i].reg_idx;
+		wr32(E1000_SRRCTL(j), srrctl);
+	}
 
 	wr32(E1000_RCTL, rctl);
 }
@@ -1859,7 +1895,7 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 rctl, rxcsum;
 	u32 rxdctl;
-	int i;
+	int i, j;
 
 	/* disable receives while setting up the descriptors */
 	rctl = rd32(E1000_RCTL);
@@ -1874,25 +1910,26 @@
 	 * the Base and Length of the Rx Descriptor Ring */
 	for (i = 0; i < adapter->num_rx_queues; i++) {
 		struct igb_ring *ring = &(adapter->rx_ring[i]);
+		j = ring->reg_idx;
 		rdba = ring->dma;
-		wr32(E1000_RDBAL(i),
+		wr32(E1000_RDBAL(j),
 				rdba & 0x00000000ffffffffULL);
-		wr32(E1000_RDBAH(i), rdba >> 32);
-		wr32(E1000_RDLEN(i),
+		wr32(E1000_RDBAH(j), rdba >> 32);
+		wr32(E1000_RDLEN(j),
 			       ring->count * sizeof(union e1000_adv_rx_desc));
 
-		ring->head = E1000_RDH(i);
-		ring->tail = E1000_RDT(i);
+		ring->head = E1000_RDH(j);
+		ring->tail = E1000_RDT(j);
 		writel(0, hw->hw_addr + ring->tail);
 		writel(0, hw->hw_addr + ring->head);
 
-		rxdctl = rd32(E1000_RXDCTL(i));
+		rxdctl = rd32(E1000_RXDCTL(j));
 		rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
 		rxdctl &= 0xFFF00000;
 		rxdctl |= IGB_RX_PTHRESH;
 		rxdctl |= IGB_RX_HTHRESH << 8;
 		rxdctl |= IGB_RX_WTHRESH << 16;
-		wr32(E1000_RXDCTL(i), rxdctl);
+		wr32(E1000_RXDCTL(j), rxdctl);
 #ifdef CONFIG_IGB_LRO
 		/* Intitial LRO Settings */
 		ring->lro_mgr.max_aggr = MAX_LRO_AGGR;
@@ -1922,7 +1959,7 @@
 			shift = 6;
 		for (j = 0; j < (32 * 4); j++) {
 			reta.bytes[j & 3] =
-				(j % adapter->num_rx_queues) << shift;
+				adapter->rx_ring[(j % adapter->num_rx_queues)].reg_idx << shift;
 			if ((j & 3) == 3)
 				writel(reta.dword,
 				       hw->hw_addr + E1000_RETA(0) + (j & ~3));
@@ -1984,7 +2021,7 @@
  *
  * Free all transmit software resources
  **/
-static void igb_free_tx_resources(struct igb_ring *tx_ring)
+void igb_free_tx_resources(struct igb_ring *tx_ring)
 {
 	struct pci_dev *pdev = tx_ring->adapter->pdev;
 
@@ -2082,7 +2119,7 @@
  *
  * Free all receive software resources
  **/
-static void igb_free_rx_resources(struct igb_ring *rx_ring)
+void igb_free_rx_resources(struct igb_ring *rx_ring)
 {
 	struct pci_dev *pdev = rx_ring->adapter->pdev;
 
@@ -2274,8 +2311,7 @@
 static void igb_update_phy_info(unsigned long data)
 {
 	struct igb_adapter *adapter = (struct igb_adapter *) data;
-	if (adapter->hw.phy.ops.get_phy_info)
-		adapter->hw.phy.ops.get_phy_info(&adapter->hw);
+	igb_get_phy_info(&adapter->hw);
 }
 
 /**
@@ -2330,9 +2366,10 @@
 						   &adapter->link_duplex);
 
 			ctrl = rd32(E1000_CTRL);
-			dev_info(&adapter->pdev->dev,
-				 "NIC Link is Up %d Mbps %s, "
+			/* Links status message must follow this format */
+			printk(KERN_INFO "igb: %s NIC Link is Up %d Mbps %s, "
 				 "Flow Control: %s\n",
+			         netdev->name,
 				 adapter->link_speed,
 				 adapter->link_duplex == FULL_DUPLEX ?
 				 "Full Duplex" : "Half Duplex",
@@ -2367,7 +2404,9 @@
 		if (netif_carrier_ok(netdev)) {
 			adapter->link_speed = 0;
 			adapter->link_duplex = 0;
-			dev_info(&adapter->pdev->dev, "NIC Link is Down\n");
+			/* Links status message must follow this format */
+			printk(KERN_INFO "igb: %s NIC Link is Down\n",
+			       netdev->name);
 			netif_carrier_off(netdev);
 			netif_tx_stop_all_queues(netdev);
 			if (!test_bit(__IGB_DOWN, &adapter->state))
@@ -2703,6 +2742,7 @@
 	context_desc->seqnum_seed = 0;
 
 	buffer_info->time_stamp = jiffies;
+	buffer_info->next_to_watch = i;
 	buffer_info->dma = 0;
 	i++;
 	if (i == tx_ring->count)
@@ -2766,6 +2806,7 @@
 				cpu_to_le32(tx_ring->queue_index << 4);
 
 		buffer_info->time_stamp = jiffies;
+		buffer_info->next_to_watch = i;
 		buffer_info->dma = 0;
 
 		i++;
@@ -2784,8 +2825,8 @@
 #define IGB_MAX_DATA_PER_TXD	(1<<IGB_MAX_TXD_PWR)
 
 static inline int igb_tx_map_adv(struct igb_adapter *adapter,
-				 struct igb_ring *tx_ring,
-				 struct sk_buff *skb)
+				 struct igb_ring *tx_ring, struct sk_buff *skb,
+				 unsigned int first)
 {
 	struct igb_buffer *buffer_info;
 	unsigned int len = skb_headlen(skb);
@@ -2799,6 +2840,7 @@
 	buffer_info->length = len;
 	/* set time_stamp *before* dma to help avoid a possible race */
 	buffer_info->time_stamp = jiffies;
+	buffer_info->next_to_watch = i;
 	buffer_info->dma = pci_map_single(adapter->pdev, skb->data, len,
 					  PCI_DMA_TODEVICE);
 	count++;
@@ -2816,6 +2858,7 @@
 		BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
 		buffer_info->length = len;
 		buffer_info->time_stamp = jiffies;
+		buffer_info->next_to_watch = i;
 		buffer_info->dma = pci_map_page(adapter->pdev,
 						frag->page,
 						frag->page_offset,
@@ -2828,8 +2871,9 @@
 			i = 0;
 	}
 
-	i = (i == 0) ? tx_ring->count - 1 : i - 1;
+	i = ((i == 0) ? tx_ring->count - 1 : i - 1);
 	tx_ring->buffer_info[i].skb = skb;
+	tx_ring->buffer_info[first].next_to_watch = i;
 
 	return count;
 }
@@ -2936,6 +2980,7 @@
 				   struct igb_ring *tx_ring)
 {
 	struct igb_adapter *adapter = netdev_priv(netdev);
+	unsigned int first;
 	unsigned int tx_flags = 0;
 	unsigned int len;
 	u8 hdr_len = 0;
@@ -2972,6 +3017,8 @@
 	if (skb->protocol == htons(ETH_P_IP))
 		tx_flags |= IGB_TX_FLAGS_IPV4;
 
+	first = tx_ring->next_to_use;
+
 	tso = skb_is_gso(skb) ? igb_tso_adv(adapter, tx_ring, skb, tx_flags,
 					      &hdr_len) : 0;
 
@@ -2987,7 +3034,7 @@
 				tx_flags |= IGB_TX_FLAGS_CSUM;
 
 	igb_tx_queue_adv(adapter, tx_ring, tx_flags,
-			 igb_tx_map_adv(adapter, tx_ring, skb),
+			 igb_tx_map_adv(adapter, tx_ring, skb, first),
 			 skb->len, hdr_len);
 
 	netdev->trans_start = jiffies;
@@ -3249,7 +3296,7 @@
 	/* Phy Stats */
 	if (hw->phy.media_type == e1000_media_type_copper) {
 		if ((adapter->link_speed == SPEED_1000) &&
-		   (!hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS,
+		   (!igb_read_phy_reg(hw, PHY_1000T_STATUS,
 					      &phy_tmp))) {
 			phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
 			adapter->phy_stats.idle_errors += phy_tmp;
@@ -3332,7 +3379,6 @@
 static irqreturn_t igb_msix_rx(int irq, void *data)
 {
 	struct igb_ring *rx_ring = data;
-	struct igb_adapter *adapter = rx_ring->adapter;
 
 	/* Write the ITR value calculated at the end of the
 	 * previous interrupt.
@@ -3340,11 +3386,11 @@
 
 	igb_write_itr(rx_ring);
 
-	if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi))
-		__netif_rx_schedule(adapter->netdev, &rx_ring->napi);
+	if (netif_rx_schedule_prep(&rx_ring->napi))
+		__netif_rx_schedule(&rx_ring->napi);
 
 #ifdef CONFIG_IGB_DCA
-	if (adapter->flags & IGB_FLAG_DCA_ENABLED)
+	if (rx_ring->adapter->flags & IGB_FLAG_DCA_ENABLED)
 		igb_update_rx_dca(rx_ring);
 #endif
 		return IRQ_HANDLED;
@@ -3357,7 +3403,7 @@
 	struct igb_adapter *adapter = rx_ring->adapter;
 	struct e1000_hw *hw = &adapter->hw;
 	int cpu = get_cpu();
-	int q = rx_ring - adapter->rx_ring;
+	int q = rx_ring->reg_idx;
 
 	if (rx_ring->cpu != cpu) {
 		dca_rxctrl = rd32(E1000_DCA_RXCTRL(q));
@@ -3384,7 +3430,7 @@
 	struct igb_adapter *adapter = tx_ring->adapter;
 	struct e1000_hw *hw = &adapter->hw;
 	int cpu = get_cpu();
-	int q = tx_ring - adapter->tx_ring;
+	int q = tx_ring->reg_idx;
 
 	if (tx_ring->cpu != cpu) {
 		dca_txctrl = rd32(E1000_DCA_TXCTRL(q));
@@ -3493,7 +3539,7 @@
 			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
-	netif_rx_schedule(netdev, &adapter->rx_ring[0].napi);
+	netif_rx_schedule(&adapter->rx_ring[0].napi);
 
 	return IRQ_HANDLED;
 }
@@ -3531,7 +3577,7 @@
 			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
-	netif_rx_schedule(netdev, &adapter->rx_ring[0].napi);
+	netif_rx_schedule(&adapter->rx_ring[0].napi);
 
 	return IRQ_HANDLED;
 }
@@ -3566,7 +3612,7 @@
 	    !netif_running(netdev)) {
 		if (adapter->itr_setting & 3)
 			igb_set_itr(adapter);
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 		if (!test_bit(__IGB_DOWN, &adapter->state))
 			igb_irq_enable(adapter);
 		return 0;
@@ -3592,7 +3638,7 @@
 
 	/* If not enough Rx work done, exit the polling mode */
 	if ((work_done == 0) || !netif_running(netdev)) {
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 
 		if (adapter->itr_setting & 3) {
 			if (adapter->num_rx_queues == 1)
@@ -3610,12 +3656,6 @@
 	return 1;
 }
 
-static inline u32 get_head(struct igb_ring *tx_ring)
-{
-	void *end = (struct e1000_tx_desc *)tx_ring->desc + tx_ring->count;
-	return le32_to_cpu(*(volatile __le32 *)end);
-}
-
 /**
  * igb_clean_tx_irq - Reclaim resources after transmit completes
  * @adapter: board private structure
@@ -3624,24 +3664,25 @@
 static bool igb_clean_tx_irq(struct igb_ring *tx_ring)
 {
 	struct igb_adapter *adapter = tx_ring->adapter;
-	struct e1000_hw *hw = &adapter->hw;
 	struct net_device *netdev = adapter->netdev;
-	struct e1000_tx_desc *tx_desc;
+	struct e1000_hw *hw = &adapter->hw;
 	struct igb_buffer *buffer_info;
 	struct sk_buff *skb;
-	unsigned int i;
-	u32 head, oldhead;
-	unsigned int count = 0;
+	union e1000_adv_tx_desc *tx_desc, *eop_desc;
 	unsigned int total_bytes = 0, total_packets = 0;
-	bool retval = true;
+	unsigned int i, eop, count = 0;
+	bool cleaned = false;
 
-	rmb();
-	head = get_head(tx_ring);
 	i = tx_ring->next_to_clean;
-	while (1) {
-		while (i != head) {
-			tx_desc = E1000_TX_DESC(*tx_ring, i);
+	eop = tx_ring->buffer_info[i].next_to_watch;
+	eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop);
+
+	while ((eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)) &&
+	       (count < tx_ring->count)) {
+		for (cleaned = false; !cleaned; count++) {
+			tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
 			buffer_info = &tx_ring->buffer_info[i];
+			cleaned = (i == eop);
 			skb = buffer_info->skb;
 
 			if (skb) {
@@ -3656,25 +3697,17 @@
 			}
 
 			igb_unmap_and_free_tx_resource(adapter, buffer_info);
+			tx_desc->wb.status = 0;
 
 			i++;
 			if (i == tx_ring->count)
 				i = 0;
-
-			count++;
-			if (count == IGB_MAX_TX_CLEAN) {
-				retval = false;
-				goto done_cleaning;
-			}
 		}
-		oldhead = head;
-		rmb();
-		head = get_head(tx_ring);
-		if (head == oldhead)
-			goto done_cleaning;
-	}  /* while (1) */
 
-done_cleaning:
+		eop = tx_ring->buffer_info[i].next_to_watch;
+		eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop);
+	}
+
 	tx_ring->next_to_clean = i;
 
 	if (unlikely(count &&
@@ -3701,7 +3734,6 @@
 		    && !(rd32(E1000_STATUS) &
 			 E1000_STATUS_TXOFF)) {
 
-			tx_desc = E1000_TX_DESC(*tx_ring, i);
 			/* detected Tx unit hang */
 			dev_err(&adapter->pdev->dev,
 				"Detected Tx Unit Hang\n"
@@ -3710,9 +3742,9 @@
 				"  TDT                  <%x>\n"
 				"  next_to_use          <%x>\n"
 				"  next_to_clean        <%x>\n"
-				"  head (WB)            <%x>\n"
 				"buffer_info[next_to_clean]\n"
 				"  time_stamp           <%lx>\n"
+				"  next_to_watch        <%x>\n"
 				"  jiffies              <%lx>\n"
 				"  desc.status          <%x>\n",
 				tx_ring->queue_index,
@@ -3720,10 +3752,10 @@
 				readl(adapter->hw.hw_addr + tx_ring->tail),
 				tx_ring->next_to_use,
 				tx_ring->next_to_clean,
-				head,
 				tx_ring->buffer_info[i].time_stamp,
+				eop,
 				jiffies,
-				tx_desc->upper.fields.status);
+				eop_desc->wb.status);
 			netif_stop_subqueue(netdev, tx_ring->queue_index);
 		}
 	}
@@ -3733,7 +3765,7 @@
 	tx_ring->tx_stats.packets += total_packets;
 	adapter->net_stats.tx_bytes += total_bytes;
 	adapter->net_stats.tx_packets += total_packets;
-	return retval;
+	return (count < tx_ring->count);
 }
 
 #ifdef CONFIG_IGB_LRO
@@ -3919,8 +3951,10 @@
 		next_buffer = &rx_ring->buffer_info[i];
 
 		if (!(staterr & E1000_RXD_STAT_EOP)) {
-			buffer_info->skb = xchg(&next_buffer->skb, skb);
-			buffer_info->dma = xchg(&next_buffer->dma, 0);
+			buffer_info->skb = next_buffer->skb;
+			buffer_info->dma = next_buffer->dma;
+			next_buffer->skb = skb;
+			next_buffer->dma = 0;
 			goto next_desc;
 		}
 
@@ -3938,8 +3972,6 @@
 
 		igb_receive_skb(rx_ring, staterr, rx_desc, skb);
 
-		netdev->last_rx = jiffies;
-
 next_desc:
 		rx_desc->wb.upper.status_error = 0;
 
@@ -4102,9 +4134,8 @@
 	case SIOCGMIIREG:
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		if (adapter->hw.phy.ops.read_phy_reg(&adapter->hw,
-						     data->reg_num
-						     & 0x1F, &data->val_out))
+		if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+		                     &data->val_out))
 			return -EIO;
 		break;
 	case SIOCSMIIREG:
@@ -4474,27 +4505,38 @@
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct igb_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
+	pci_ers_result_t result;
 	int err;
 
 	if (adapter->need_ioport)
 		err = pci_enable_device(pdev);
 	else
 		err = pci_enable_device_mem(pdev);
+
 	if (err) {
 		dev_err(&pdev->dev,
 			"Cannot re-enable PCI device after reset.\n");
-		return PCI_ERS_RESULT_DISCONNECT;
+		result = PCI_ERS_RESULT_DISCONNECT;
+	} else {
+		pci_set_master(pdev);
+		pci_restore_state(pdev);
+
+		pci_enable_wake(pdev, PCI_D3hot, 0);
+		pci_enable_wake(pdev, PCI_D3cold, 0);
+
+		igb_reset(adapter);
+		wr32(E1000_WUS, ~0);
+		result = PCI_ERS_RESULT_RECOVERED;
 	}
-	pci_set_master(pdev);
-	pci_restore_state(pdev);
 
-	pci_enable_wake(pdev, PCI_D3hot, 0);
-	pci_enable_wake(pdev, PCI_D3cold, 0);
+	err = pci_cleanup_aer_uncorrect_error_status(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "pci_cleanup_aer_uncorrect_error_status "
+		        "failed 0x%0x\n", err);
+		/* non-fatal, continue */
+	}
 
-	igb_reset(adapter);
-	wr32(E1000_WUS, ~0);
-
-	return PCI_ERS_RESULT_RECOVERED;
+	return result;
 }
 
 /**
@@ -4522,7 +4564,6 @@
 	/* let the f/w know that the h/w is now under the control of the
 	 * driver. */
 	igb_get_hw_control(adapter);
-
 }
 
 /* igb_main.c */
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 1f25263..170b12d 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -390,11 +390,8 @@
 	}
 
 	printk("Found %s NIC", type);
-	if (type != unknown) {
-		printk (" registration number %02x:%02x:%02x:%02x:%02x:%02x,"
-			" CRC %02x", serial[0], serial[1], serial[2],
-			serial[3], serial[4], serial[5], crc);
-	}
+	if (type != unknown)
+		printk (" registration number %pM, CRC %02x", serial, crc);
 	printk(".\n");
 
 	return 0;
@@ -443,12 +440,9 @@
  */
 static void ioc3_get_eaddr(struct ioc3_private *ip)
 {
-	DECLARE_MAC_BUF(mac);
-
 	ioc3_get_eaddr_nic(ip);
 
-	printk("Ethernet address is %s.\n",
-	       print_mac(mac, priv_netdev(ip)->dev_addr));
+	printk("Ethernet address is %pM.\n", priv_netdev(ip)->dev_addr);
 }
 
 static void __ioc3_set_mac_address(struct net_device *dev)
@@ -627,7 +621,6 @@
 			rxb = (struct ioc3_erxbuf *) new_skb->data;
 			skb_reserve(new_skb, RX_OFFSET);
 
-			priv_netdev(ip)->last_rx = jiffies;
 			ip->stats.rx_packets++;		/* Statistics */
 			ip->stats.rx_bytes += len;
 		} else {
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
index 0593698..7b6d435 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -1222,7 +1222,6 @@
 	skb->protocol = eth_type_trans(skb, dev);
 	skb->ip_summed = CHECKSUM_NONE;
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 	sp->rx_buff[entry] = NULL;
 }
 
@@ -1256,7 +1255,6 @@
 	jumbo->skb = skb;
 
 	sp->rx_buff[entry] = NULL;
-	dev->last_rx = jiffies;
 }
 
 static void ipg_nic_rx_with_end(struct net_device *dev,
@@ -1292,7 +1290,6 @@
 			}
 		}
 
-		dev->last_rx = jiffies;
 		jumbo->found_start = 0;
 		jumbo->current_size = 0;
 		jumbo->skb = NULL;
@@ -1325,7 +1322,6 @@
 					       skb->data, sp->rxfrag_size);
 				}
 			}
-			dev->last_rx = jiffies;
 			ipg_nic_rx_free_skb(dev);
 		}
 	} else {
@@ -1494,11 +1490,6 @@
 			 * when processing completes.
 			 */
 			netif_rx(skb);
-
-			/* Record frame receive time (jiffies = Linux
-			 * kernel current time stamp).
-			 */
-			dev->last_rx = jiffies;
 		}
 
 		/* Assure RX buffer is not reused by IPG. */
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 2ff1818..3c58e67 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -292,7 +292,7 @@
 		return -ENOMEM;
 	}
 
-	self = dev->priv;
+	self = netdev_priv(dev);
 	self->netdev = dev;
 	spin_lock_init(&self->lock);
    
@@ -665,7 +665,7 @@
 		
 	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__);
 		
-	self = dev->priv;
+	self = netdev_priv(dev);
 	
 	spin_lock(&self->lock);
 	
@@ -1333,7 +1333,7 @@
 	
 	IRDA_ASSERT(dev != NULL, return -1;);
 	
-	self = (struct ali_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 	
 	IRDA_ASSERT(self != NULL, return 0;);
 	
@@ -1396,7 +1396,7 @@
 		
 	IRDA_ASSERT(dev != NULL, return -1;);
 
-	self = (struct ali_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 	IRDA_ASSERT(self != NULL, return 0;);
 
 	/* Stop device */
@@ -1436,7 +1436,7 @@
 	
 	IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ );
 	
-	self = (struct ali_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 	iobase = self->io.fir_base;
 
 	netif_stop_queue(dev);
@@ -1931,7 +1931,6 @@
 			skb_reset_mac_header(skb);
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
-			self->netdev->last_rx = jiffies;
 		}
 	}
 	
@@ -1960,7 +1959,7 @@
 	
 	IRDA_ASSERT(dev != NULL, return 0;);
 	
-	self = (struct ali_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 	IRDA_ASSERT(self != NULL, return 0;);
 
 	iobase = self->io.sir_base;
@@ -2028,7 +2027,7 @@
 	
 	IRDA_ASSERT(dev != NULL, return -1;);
 
-	self = dev->priv;
+	self = netdev_priv(dev);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -2114,7 +2113,7 @@
 
 static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev)
 {
-	struct ali_ircc_cb *self = (struct ali_ircc_cb *) dev->priv;
+	struct ali_ircc_cb *self = netdev_priv(dev);
 	
 	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ );
 		
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index a1e4508..6c4b53f 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -620,7 +620,6 @@
 		/* next descriptor */
 		prxd = aup->rx_ring[aup->rx_head];
 		flags = prxd->flags;
-		dev->last_rx = jiffies;
 
 	}
 	return 0;
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 69d16b3..687c2d5 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -979,7 +979,7 @@
   unsigned long flags;
   struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb;
 
-  self = (struct toshoboe_cb *) dev->priv;
+  self = netdev_priv(dev);
 
   IRDA_ASSERT (self != NULL, return 0; );
 
@@ -1384,7 +1384,7 @@
   IRDA_DEBUG (4, "%s()\n", __func__);
 
   IRDA_ASSERT (dev != NULL, return -1; );
-  self = (struct toshoboe_cb *) dev->priv;
+  self = netdev_priv(dev);
 
   /* Stop device */
   netif_stop_queue(dev);
@@ -1422,7 +1422,7 @@
 
   IRDA_ASSERT (dev != NULL, return -1; );
 
-  self = dev->priv;
+  self = netdev_priv(dev);
 
   IRDA_ASSERT (self != NULL, return -1; );
 
@@ -1546,7 +1546,7 @@
       return -ENOMEM;
     }
 
-  self = dev->priv;
+  self = netdev_priv(dev);
   self->netdev = dev;
   self->pdev = pci_dev;
   self->base = pci_resource_start(pci_dev,0);
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index b5d6b9a..205e4e8 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -384,7 +384,7 @@
  */
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-	struct irda_usb_cb *self = netdev->priv;
+	struct irda_usb_cb *self = netdev_priv(netdev);
 	struct urb *urb = self->tx_urb;
 	unsigned long flags;
 	s32 speed;
@@ -628,7 +628,7 @@
 static void irda_usb_net_timeout(struct net_device *netdev)
 {
 	unsigned long flags;
-	struct irda_usb_cb *self = netdev->priv;
+	struct irda_usb_cb *self = netdev_priv(netdev);
 	struct urb *urb;
 	int	done = 0;	/* If we have made any progress */
 
@@ -929,7 +929,6 @@
 	/* Keep stats up to date */
 	self->stats.rx_bytes += len;
 	self->stats.rx_packets++;
-	self->netdev->last_rx = jiffies;
 
 done:
 	/* Note : at this point, the URB we've just received (urb)
@@ -1175,7 +1174,7 @@
 	IRDA_DEBUG(1, "%s()\n", __func__);
 
 	IRDA_ASSERT(netdev != NULL, return -1;);
-	self = (struct irda_usb_cb *) netdev->priv;
+	self = netdev_priv(netdev);
 	IRDA_ASSERT(self != NULL, return -1;);
 
 	spin_lock_irqsave(&self->lock, flags);
@@ -1257,7 +1256,7 @@
 	IRDA_DEBUG(1, "%s()\n", __func__);
 
 	IRDA_ASSERT(netdev != NULL, return -1;);
-	self = (struct irda_usb_cb *) netdev->priv;
+	self = netdev_priv(netdev);
 	IRDA_ASSERT(self != NULL, return -1;);
 
 	/* Clear this flag *before* unlinking the urbs and *before*
@@ -1306,7 +1305,7 @@
 	int ret = 0;
 
 	IRDA_ASSERT(dev != NULL, return -1;);
-	self = dev->priv;
+	self = netdev_priv(dev);
 	IRDA_ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
@@ -1348,7 +1347,7 @@
  */
 static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev)
 {
-	struct irda_usb_cb *self = dev->priv;
+	struct irda_usb_cb *self = netdev_priv(dev);
 	return &self->stats;
 }
 
@@ -1641,7 +1640,7 @@
 		goto err_out;
 
 	SET_NETDEV_DEV(net, &intf->dev);
-	self = net->priv;
+	self = netdev_priv(net);
 	self->netdev = net;
 	spin_lock_init(&self->lock);
 	init_timer(&self->rx_defer_timer);
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 6bcee01..d53aa95 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -191,7 +191,7 @@
 	tty = priv->tty;
 	if (!tty->ops->write)
 		return 0;
-	tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+	set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	writelen = tty_write_room(tty);
 	if (writelen > len)
 		writelen = len;
@@ -263,8 +263,7 @@
 	IRDA_ASSERT(priv != NULL, return;);
 	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
 
-	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-
+	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	if (priv->dev)
 		sirdev_write_complete(priv->dev);
 }
@@ -522,7 +521,7 @@
 
 	/* Stop tty */
 	irtty_stop_receiver(tty, TRUE);
-	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	if (tty->ops->stop)
 		tty->ops->stop(tty);
 
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
index e1429fc..c747c87 100644
--- a/drivers/net/irda/kingsun-sir.c
+++ b/drivers/net/irda/kingsun-sir.c
@@ -235,7 +235,6 @@
 						  &kingsun->stats,
 						  &kingsun->rx_buff, bytes[i]);
 			}
-			kingsun->netdev->last_rx = jiffies;
 			do_gettimeofday(&kingsun->rx_time);
 			kingsun->receiving =
 				(kingsun->rx_buff.state != OUTSIDE_FRAME)
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
index 2e67ae0..600d96f 100644
--- a/drivers/net/irda/ks959-sir.c
+++ b/drivers/net/irda/ks959-sir.c
@@ -474,7 +474,6 @@
 						  bytes[i]);
 			}
 		}
-		kingsun->netdev->last_rx = jiffies;
 		do_gettimeofday(&kingsun->rx_time);
 		kingsun->receiving =
 		    (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
index 3843b5f..0e7f893 100644
--- a/drivers/net/irda/ksdazzle-sir.c
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -371,7 +371,6 @@
 			async_unwrap_char(kingsun->netdev, &kingsun->stats,
 					  &kingsun->rx_unwrap_buff, bytes[i]);
 		}
-		kingsun->netdev->last_rx = jiffies;
 		kingsun->receiving =
 		    (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
 	}
diff --git a/drivers/net/irda/ma600-sir.c b/drivers/net/irda/ma600-sir.c
index 1ceed9c..e912164 100644
--- a/drivers/net/irda/ma600-sir.c
+++ b/drivers/net/irda/ma600-sir.c
@@ -236,7 +236,7 @@
  * avoid the state machine complexity before we get things working
  */
 
-int ma600_reset(struct sir_dev *dev)
+static int ma600_reset(struct sir_dev *dev)
 {
 	IRDA_DEBUG(2, "%s()\n", __func__);
 
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index ad92d3f..904c961 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -806,7 +806,6 @@
 			mcs_unwrap_fir(mcs, urb->transfer_buffer,
 				urb->actual_length);
 		}
-		mcs->netdev->last_rx = jiffies;
 		do_gettimeofday(&mcs->rx_time);
 	}
 
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 8583d95..2c6bf2d 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -373,7 +373,7 @@
 		return -ENOMEM;
 	}
 
-	self = dev->priv;
+	self = netdev_priv(dev);
 	self->netdev = dev;
 	spin_lock_init(&self->lock);
    
@@ -1354,7 +1354,7 @@
 	__s32 speed;
 	__u8 bank;
 	
-	self = (struct nsc_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 
 	IRDA_ASSERT(self != NULL, return 0;);
 
@@ -1427,7 +1427,7 @@
 	__u8 bank;
 	int mtt, diff;
 	
-	self = (struct nsc_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 	iobase = self->io.fir_base;
 
 	netif_stop_queue(dev);
@@ -1896,7 +1896,6 @@
 			skb_reset_mac_header(skb);
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
-			self->netdev->last_rx = jiffies;
 		}
 	}
 	/* Restore bank register */
@@ -2085,7 +2084,7 @@
 	__u8 bsr, eir;
 	int iobase;
 
-	self = dev->priv;
+	self = netdev_priv(dev);
 
 	spin_lock(&self->lock);	
 
@@ -2166,7 +2165,7 @@
 	IRDA_DEBUG(4, "%s()\n", __func__);
 	
 	IRDA_ASSERT(dev != NULL, return -1;);
-	self = (struct nsc_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 	
 	IRDA_ASSERT(self != NULL, return 0;);
 	
@@ -2229,7 +2228,7 @@
 	
 	IRDA_ASSERT(dev != NULL, return -1;);
 
-	self = (struct nsc_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 	IRDA_ASSERT(self != NULL, return 0;);
 
 	/* Stop device */
@@ -2275,7 +2274,7 @@
 
 	IRDA_ASSERT(dev != NULL, return -1;);
 
-	self = dev->priv;
+	self = netdev_priv(dev);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -2310,7 +2309,7 @@
 
 static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev)
 {
-	struct nsc_ircc_cb *self = (struct nsc_ircc_cb *) dev->priv;
+	struct nsc_ircc_cb *self = netdev_priv(dev);
 	
 	return &self->stats;
 }
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index c5b02b6..a0ee053 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -225,7 +225,6 @@
 			}
 			lsr = STLSR;
 		}
-		dev->last_rx = jiffies;
 		si->last_oscr = OSCR;
 		break;
 
@@ -237,7 +236,6 @@
 		    si->stats.rx_bytes++;
 	            async_unwrap_char(dev, &si->stats, &si->rx_buff, STRBR);
 	  	} while (STLSR & LSR_DR);
-	  	dev->last_rx = jiffies;
 		si->last_oscr = OSCR;
 	  	break;
 
@@ -397,8 +395,6 @@
 
 		si->stats.rx_packets++;
 		si->stats.rx_bytes += len;
-
-		dev->last_rx = jiffies;
 	}
 }
 
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index a951889..ccde582 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -298,7 +298,7 @@
 	if (!dev)
 		return 0;
 
-	si = dev->priv;
+	si = netdev_priv(dev);
 	if (si->open) {
 		/*
 		 * Stop the transmit queue
@@ -323,7 +323,7 @@
 	if (!dev)
 		return 0;
 
-	si = dev->priv;
+	si = netdev_priv(dev);
 	if (si->open) {
 		/*
 		 * If we missed a speed change, initialise at the new speed
@@ -359,7 +359,7 @@
  */
 static void sa1100_irda_hpsir_irq(struct net_device *dev)
 {
-	struct sa1100_irda *si = dev->priv;
+	struct sa1100_irda *si = netdev_priv(dev);
 	int status;
 
 	status = Ser2UTSR0;
@@ -410,7 +410,6 @@
 					  Ser2UTDR);
 		} while (Ser2UTSR1 & UTSR1_RNE);
 
-		dev->last_rx = jiffies;
 	}
 
 	if (status & UTSR0_TFS && si->tx_buff.len) {
@@ -515,7 +514,6 @@
 		sa1100_irda_rx_alloc(si);
 
 		netif_rx(skb);
-		dev->last_rx = jiffies;
 	} else {
 		/*
 		 * Remap the buffer.
@@ -534,7 +532,7 @@
  */
 static void sa1100_irda_fir_irq(struct net_device *dev)
 {
-	struct sa1100_irda *si = dev->priv;
+	struct sa1100_irda *si = netdev_priv(dev);
 
 	/*
 	 * Stop RX DMA
@@ -582,7 +580,7 @@
 static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
-	if (IS_FIR(((struct sa1100_irda *)dev->priv)))
+	if (IS_FIR(((struct sa1100_irda *)netdev_priv(dev))))
 		sa1100_irda_fir_irq(dev);
 	else
 		sa1100_irda_hpsir_irq(dev);
@@ -595,7 +593,7 @@
 static void sa1100_irda_txdma_irq(void *id)
 {
 	struct net_device *dev = id;
-	struct sa1100_irda *si = dev->priv;
+	struct sa1100_irda *si = netdev_priv(dev);
 	struct sk_buff *skb = si->txskb;
 
 	si->txskb = NULL;
@@ -649,7 +647,7 @@
 
 static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct sa1100_irda *si = dev->priv;
+	struct sa1100_irda *si = netdev_priv(dev);
 	int speed = irda_get_next_speed(skb);
 
 	/*
@@ -724,7 +722,7 @@
 sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
 {
 	struct if_irda_req *rq = (struct if_irda_req *)ifreq;
-	struct sa1100_irda *si = dev->priv;
+	struct sa1100_irda *si = netdev_priv(dev);
 	int ret = -EOPNOTSUPP;
 
 	switch (cmd) {
@@ -766,13 +764,13 @@
 
 static struct net_device_stats *sa1100_irda_stats(struct net_device *dev)
 {
-	struct sa1100_irda *si = dev->priv;
+	struct sa1100_irda *si = netdev_priv(dev);
 	return &si->stats;
 }
 
 static int sa1100_irda_start(struct net_device *dev)
 {
-	struct sa1100_irda *si = dev->priv;
+	struct sa1100_irda *si = netdev_priv(dev);
 	int err;
 
 	si->speed = 9600;
@@ -835,7 +833,7 @@
 
 static int sa1100_irda_stop(struct net_device *dev)
 {
-	struct sa1100_irda *si = dev->priv;
+	struct sa1100_irda *si = netdev_priv(dev);
 
 	disable_irq(dev->irq);
 	sa1100_irda_shutdown(si);
@@ -908,7 +906,7 @@
 	if (!dev)
 		goto err_mem_4;
 
-	si = dev->priv;
+	si = netdev_priv(dev);
 	si->dev = &pdev->dev;
 	si->pdata = pdev->dev.platform_data;
 
@@ -987,7 +985,7 @@
 	struct net_device *dev = platform_get_drvdata(pdev);
 
 	if (dev) {
-		struct sa1100_irda *si = dev->priv;
+		struct sa1100_irda *si = netdev_priv(dev);
 		unregister_netdev(dev);
 		kfree(si->tx_buff.head);
 		kfree(si->rx_buff.head);
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index 3f32909..ceef040 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -584,14 +584,14 @@
 
 static struct net_device_stats *sirdev_get_stats(struct net_device *ndev)
 {
-	struct sir_dev *dev = ndev->priv;
+	struct sir_dev *dev = netdev_priv(ndev);
 
 	return (dev) ? &dev->stats : NULL;
 }
 
 static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
-	struct sir_dev *dev = ndev->priv;
+	struct sir_dev *dev = netdev_priv(ndev);
 	unsigned long flags;
 	int actual = 0;
 	int err;
@@ -683,7 +683,7 @@
 static int sirdev_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
 {
 	struct if_irda_req *irq = (struct if_irda_req *) rq;
-	struct sir_dev *dev = ndev->priv;
+	struct sir_dev *dev = netdev_priv(ndev);
 	int ret = 0;
 
 	IRDA_ASSERT(dev != NULL, return -1;);
@@ -795,7 +795,7 @@
 
 static int sirdev_open(struct net_device *ndev)
 {
-	struct sir_dev *dev = ndev->priv;
+	struct sir_dev *dev = netdev_priv(ndev);
 	const struct sir_driver *drv = dev->drv;
 
 	if (!drv)
@@ -840,7 +840,7 @@
 
 static int sirdev_close(struct net_device *ndev)
 {
-	struct sir_dev *dev = ndev->priv;
+	struct sir_dev *dev = netdev_priv(ndev);
 	const struct sir_driver *drv;
 
 //	IRDA_DEBUG(0, "%s\n", __func__);
@@ -896,7 +896,7 @@
 		IRDA_ERROR("%s - Can't allocate memory for IrDA control block!\n", __func__);
 		goto out;
 	}
-	dev = ndev->priv;
+	dev = netdev_priv(ndev);
 
 	irda_init_max_qos_capabilies(&dev->qos);
 	dev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index b5360fe..5d09e15 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -872,7 +872,7 @@
  *    waits until the next transmit interrupt, and continues until the
  *    frame is transmitted.
  */
-int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
+static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
 {
 	struct smsc_ircc_cb *self;
 	unsigned long flags;
@@ -1128,7 +1128,7 @@
  *    Set speed of IrDA port to specified baudrate
  *
  */
-void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed)
+static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed)
 {
 	int iobase;
 	int fcr;    /* FIFO control reg */
@@ -1894,7 +1894,7 @@
  * This function *must* be called with spinlock held, because it may
  * be called from the irq handler (via smsc_ircc_change_speed()). - Jean II
  */
-void smsc_ircc_sir_start(struct smsc_ircc_cb *self)
+static void smsc_ircc_sir_start(struct smsc_ircc_cb *self)
 {
 	struct net_device *dev;
 	int fir_base, sir_base;
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 3575804..ca4cd92 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -824,7 +824,6 @@
 		unwrap_chars(stir, urb->transfer_buffer,
 			     urb->actual_length);
 		
-		stir->netdev->last_rx = jiffies;
 		do_gettimeofday(&stir->rx_time);
 	}
 
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 84e609e..74c78cf 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -334,7 +334,7 @@
 	if (dev == NULL) 
 		return -ENOMEM;
 
-	self = dev->priv;
+	self = netdev_priv(dev);
 	self->netdev = dev;
 	spin_lock_init(&self->lock);
 
@@ -824,7 +824,7 @@
 	u16 iobase;
 	__u32 speed;
 
-	self = (struct via_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 	IRDA_ASSERT(self != NULL, return 0;);
 	iobase = self->io.fir_base;
 
@@ -896,7 +896,7 @@
 	__u32 speed;
 	unsigned long flags;
 
-	self = (struct via_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 	iobase = self->io.fir_base;
 
 	if (self->st_fifo.len)
@@ -1349,7 +1349,7 @@
 static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id)
 {
 	struct net_device *dev = dev_id;
-	struct via_ircc_cb *self = dev->priv;
+	struct via_ircc_cb *self = netdev_priv(dev);
 	int iobase;
 	u8 iHostIntType, iRxIntType, iTxIntType;
 
@@ -1522,7 +1522,7 @@
 	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	IRDA_ASSERT(dev != NULL, return -1;);
-	self = (struct via_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 	self->stats.rx_packets = 0;
 	IRDA_ASSERT(self != NULL, return 0;);
 	iobase = self->io.fir_base;
@@ -1589,7 +1589,7 @@
 	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	IRDA_ASSERT(dev != NULL, return -1;);
-	self = (struct via_ircc_cb *) dev->priv;
+	self = netdev_priv(dev);
 	IRDA_ASSERT(self != NULL, return 0;);
 
 	/* Stop device */
@@ -1628,7 +1628,7 @@
 	int ret = 0;
 
 	IRDA_ASSERT(dev != NULL, return -1;);
-	self = dev->priv;
+	self = netdev_priv(dev);
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_DEBUG(1, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name,
 		   cmd);
@@ -1663,7 +1663,7 @@
 static struct net_device_stats *via_ircc_net_get_stats(struct net_device
 						       *dev)
 {
-	struct via_ircc_cb *self = (struct via_ircc_cb *) dev->priv;
+	struct via_ircc_cb *self = netdev_priv(dev);
 
 	return &self->stats;
 }
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 9c926d2..0d30f8d 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -178,7 +178,7 @@
 		
 static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev)
 {
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 	u8 byte;
 	u16 word;
 	unsigned delta1, delta2;
@@ -346,7 +346,7 @@
 static int vlsi_seq_show(struct seq_file *seq, void *v)
 {
 	struct net_device *ndev = seq->private;
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 	unsigned long flags;
 
 	seq_printf(seq, "\n%s %s\n\n", DRIVER_NAME, DRIVER_VERSION);
@@ -543,7 +543,7 @@
 	struct sk_buff	*skb;
 	int		ret = 0;
 	struct net_device *ndev = (struct net_device *)pci_get_drvdata(r->pdev);
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 
 	pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir);
 	/* dma buffer now owned by the CPU */
@@ -600,7 +600,6 @@
 		netif_rx(skb);
 	else
 		netif_rx_ni(skb);
-	ndev->last_rx = jiffies;
 
 done:
 	rd_set_status(rd, 0);
@@ -638,7 +637,7 @@
 
 static void vlsi_rx_interrupt(struct net_device *ndev)
 {
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 	struct vlsi_ring *r = idev->rx_ring;
 	struct ring_descr *rd;
 	int ret;
@@ -856,7 +855,7 @@
 
 static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 	struct vlsi_ring	*r = idev->tx_ring;
 	struct ring_descr *rd;
 	unsigned long flags;
@@ -1063,7 +1062,7 @@
 
 static void vlsi_tx_interrupt(struct net_device *ndev)
 {
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 	struct vlsi_ring	*r = idev->tx_ring;
 	struct ring_descr	*rd;
 	unsigned	iobase;
@@ -1262,7 +1261,7 @@
 static int vlsi_init_chip(struct pci_dev *pdev)
 {
 	struct net_device *ndev = pci_get_drvdata(pdev);
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 	unsigned	iobase;
 	u16 ptr;
 
@@ -1376,14 +1375,14 @@
 
 static struct net_device_stats * vlsi_get_stats(struct net_device *ndev)
 {
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 
 	return &idev->stats;
 }
 
 static void vlsi_tx_timeout(struct net_device *ndev)
 {
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 
 
 	vlsi_reg_debug(ndev->base_addr, __func__);
@@ -1408,7 +1407,7 @@
 
 static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
 {
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 	struct if_irda_req *irq = (struct if_irda_req *) rq;
 	unsigned long flags;
 	u16 fifocnt;
@@ -1458,7 +1457,7 @@
 static irqreturn_t vlsi_interrupt(int irq, void *dev_instance)
 {
 	struct net_device *ndev = dev_instance;
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 	unsigned	iobase;
 	u8		irintr;
 	int 		boguscount = 5;
@@ -1499,7 +1498,7 @@
 
 static int vlsi_open(struct net_device *ndev)
 {
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 	int	err = -EAGAIN;
 	char	hwname[32];
 
@@ -1558,7 +1557,7 @@
 
 static int vlsi_close(struct net_device *ndev)
 {
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 
 	netif_stop_queue(ndev);
 
@@ -1581,7 +1580,7 @@
 
 static int vlsi_irda_init(struct net_device *ndev)
 {
-	vlsi_irda_dev_t *idev = ndev->priv;
+	vlsi_irda_dev_t *idev = netdev_priv(ndev);
 	struct pci_dev *pdev = idev->pdev;
 
 	ndev->irq = pdev->irq;
@@ -1656,7 +1655,7 @@
 		goto out_disable;
 	}
 
-	idev = ndev->priv;
+	idev = netdev_priv(ndev);
 
 	spin_lock_init(&idev->lock);
 	mutex_init(&idev->mtx);
@@ -1713,7 +1712,7 @@
 
 	unregister_netdev(ndev);
 
-	idev = ndev->priv;
+	idev = netdev_priv(ndev);
 	mutex_lock(&idev->mtx);
 	if (idev->proc_entry) {
 		remove_proc_entry(ndev->name, vlsi_proc_root);
@@ -1748,7 +1747,7 @@
 			   __func__, pci_name(pdev));
 		return 0;
 	}
-	idev = ndev->priv;	
+	idev = netdev_priv(ndev);
 	mutex_lock(&idev->mtx);
 	if (pdev->current_state != 0) {			/* already suspended */
 		if (state.event > pdev->current_state) {	/* simply go deeper */
@@ -1787,7 +1786,7 @@
 			   __func__, pci_name(pdev));
 		return 0;
 	}
-	idev = ndev->priv;	
+	idev = netdev_priv(ndev);
 	mutex_lock(&idev->mtx);
 	if (pdev->current_state == 0) {
 		mutex_unlock(&idev->mtx);
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 002a6d7..30ec913 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -147,8 +147,8 @@
  *    Open driver instance
  *
  */
-int w83977af_open(int i, unsigned int iobase, unsigned int irq, 
-		  unsigned int dma)
+static int w83977af_open(int i, unsigned int iobase, unsigned int irq,
+			 unsigned int dma)
 {
 	struct net_device *dev;
         struct w83977af_ir *self;
@@ -178,7 +178,7 @@
 		goto err_out;
 	}
 
-	self = dev->priv;
+	self = netdev_priv(dev);
 	spin_lock_init(&self->lock);
    
 
@@ -310,7 +310,7 @@
 	return 0;
 }
 
-int w83977af_probe( int iobase, int irq, int dma)
+static int w83977af_probe(int iobase, int irq, int dma)
 {
   	int version;
 	int i;
@@ -409,7 +409,7 @@
 	return -1;
 }
 
-void w83977af_change_speed(struct w83977af_ir *self, __u32 speed)
+static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed)
 {
 	int ir_mode = HCR_SIR;
 	int iobase; 
@@ -489,7 +489,7 @@
  *    Sets up a DMA transfer to send the current frame.
  *
  */
-int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct w83977af_ir *self;
 	__s32 speed;
@@ -497,7 +497,7 @@
 	__u8 set;
 	int mtt;
 	
-	self = (struct w83977af_ir *) dev->priv;
+	self = netdev_priv(dev);
 
 	iobase = self->io.fir_base;
 
@@ -731,7 +731,7 @@
  *    if it starts to receive a frame.
  *
  */
-int w83977af_dma_receive(struct w83977af_ir *self) 
+static int w83977af_dma_receive(struct w83977af_ir *self)
 {
 	int iobase;
 	__u8 set;
@@ -803,7 +803,7 @@
  *    Finished with receiving a frame
  *
  */
-int w83977af_dma_receive_complete(struct w83977af_ir *self)
+static int w83977af_dma_receive_complete(struct w83977af_ir *self)
 {
 	struct sk_buff *skb;
 	struct st_fifo *st_fifo;
@@ -923,7 +923,6 @@
 			skb_reset_mac_header(skb);
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
-			self->netdev->last_rx = jiffies;
 		}
 	}
 	/* Restore set register */
@@ -1119,7 +1118,7 @@
 	__u8 set, icr, isr;
 	int iobase;
 
-	self = dev->priv;
+	self = netdev_priv(dev);
 
 	iobase = self->io.fir_base;
 
@@ -1192,7 +1191,7 @@
 	IRDA_DEBUG(0, "%s()\n", __func__ );
 	
 	IRDA_ASSERT(dev != NULL, return -1;);
-	self = (struct w83977af_ir *) dev->priv;
+	self = netdev_priv(dev);
 	
 	IRDA_ASSERT(self != NULL, return 0;);
 	
@@ -1256,7 +1255,7 @@
 
 	IRDA_ASSERT(dev != NULL, return -1;);
 	
-	self = (struct w83977af_ir *) dev->priv;
+	self = netdev_priv(dev);
 	
 	IRDA_ASSERT(self != NULL, return 0;);
 	
@@ -1303,7 +1302,7 @@
 
 	IRDA_ASSERT(dev != NULL, return -1;);
 
-	self = dev->priv;
+	self = netdev_priv(dev);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -1339,7 +1338,7 @@
 
 static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev)
 {
-	struct w83977af_ir *self = (struct w83977af_ir *) dev->priv;
+	struct w83977af_ir *self = netdev_priv(dev);
 	
 	return &self->stats;
 }
diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
index d6ff26a..3126678 100644
--- a/drivers/net/isa-skeleton.c
+++ b/drivers/net/isa-skeleton.c
@@ -192,7 +192,6 @@
 	static unsigned version_printed;
 	int i;
 	int err = -ENODEV;
-	DECLARE_MAC_BUF(mac);
 
 	/* Grab the region so that no one else tries to probe our ioports. */
 	if (!request_region(ioaddr, NETCARD_IO_EXTENT, cardname))
@@ -220,7 +219,7 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(ioaddr + i);
 
-	printk("%s", print_mac(mac, dev->dev_addr));
+	printk("%pM", dev->dev_addr);
 
 	err = -EAGAIN;
 #ifdef jumpered_interrupts
@@ -584,7 +583,6 @@
 			insw(ioaddr, skb->data, (pkt_len + 1) >> 1);
 
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			lp->stats.rx_packets++;
 			lp->stats.rx_bytes += pkt_len;
 		}
@@ -711,15 +709,3 @@
 }
 
 #endif /* MODULE */
-
-/*
- * Local variables:
- *  compile-command:
- *	gcc -D__KERNEL__ -Wall -Wstrict-prototypes -Wwrite-strings
- *	-Wredundant-decls -O2 -m486 -c skeleton.c
- *  version-control: t
- *  kept-new-versions: 5
- *  tab-width: 4
- *  c-indent-level: 4
- * End:
- */
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index c46864d..c7457f9 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -952,7 +952,7 @@
 
 static void veth_set_multicast_list(struct net_device *dev)
 {
-	struct veth_port *port = (struct veth_port *) dev->priv;
+	struct veth_port *port = netdev_priv(dev);
 	unsigned long flags;
 
 	write_lock_irqsave(&port->mcast_gate, flags);
@@ -1044,7 +1044,7 @@
 		return NULL;
 	}
 
-	port = (struct veth_port *) dev->priv;
+	port = netdev_priv(dev);
 
 	spin_lock_init(&port->queue_lock);
 	rwlock_init(&port->mcast_gate);
@@ -1102,7 +1102,7 @@
 				struct net_device *dev)
 {
 	struct veth_lpar_connection *cnx = veth_cnx[rlp];
-	struct veth_port *port = (struct veth_port *) dev->priv;
+	struct veth_port *port = netdev_priv(dev);
 	HvLpEvent_Rc rc;
 	struct veth_msg *msg = NULL;
 	unsigned long flags;
@@ -1191,7 +1191,7 @@
 static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	unsigned char *frame = skb->data;
-	struct veth_port *port = (struct veth_port *) dev->priv;
+	struct veth_port *port = netdev_priv(dev);
 	HvLpIndexMap lpmask;
 
 	if (! (frame[0] & 0x01)) {
@@ -1255,7 +1255,7 @@
 		if (! dev)
 			continue;
 
-		port = (struct veth_port *)dev->priv;
+		port = netdev_priv(dev);
 
 		if (! (port->lpar_map & (1<<cnx->remote_lp)))
 			continue;
@@ -1284,7 +1284,7 @@
 		if (! dev)
 			continue;
 
-		port = (struct veth_port *)dev->priv;
+		port = netdev_priv(dev);
 
 		/* If this cnx is not on the vlan for this port, continue */
 		if (! (port->lpar_map & (1 << cnx->remote_lp)))
@@ -1506,7 +1506,7 @@
 			continue;
 		}
 
-		port = (struct veth_port *)dev->priv;
+		port = netdev_priv(dev);
 		dest = *((u64 *) skb->data) & 0xFFFFFFFFFFFF0000;
 
 		if ((vlan > HVMAXARCHITECTEDVIRTUALLANS) || !port) {
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index be3c7dc..eee28d3 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -321,6 +321,24 @@
 	}
 }
 
+static const struct net_device_ops ixgb_netdev_ops = {
+	.ndo_open 		= ixgb_open,
+	.ndo_stop		= ixgb_close,
+	.ndo_start_xmit		= ixgb_xmit_frame,
+	.ndo_get_stats		= ixgb_get_stats,
+	.ndo_set_multicast_list	= ixgb_set_multi,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= ixgb_set_mac,
+	.ndo_change_mtu		= ixgb_change_mtu,
+	.ndo_tx_timeout		= ixgb_tx_timeout,
+	.ndo_vlan_rx_register	= ixgb_vlan_rx_register,
+	.ndo_vlan_rx_add_vid	= ixgb_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= ixgb_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= ixgb_netpoll,
+#endif
+};
+
 /**
  * ixgb_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -381,8 +399,7 @@
 	adapter->hw.back = adapter;
 	adapter->msg_enable = netif_msg_init(debug, DEFAULT_DEBUG_LEVEL_SHIFT);
 
-	adapter->hw.hw_addr = ioremap(pci_resource_start(pdev, BAR_0),
-	                              pci_resource_len(pdev, BAR_0));
+	adapter->hw.hw_addr = pci_ioremap_bar(pdev, BAR_0);
 	if (!adapter->hw.hw_addr) {
 		err = -EIO;
 		goto err_ioremap;
@@ -397,23 +414,10 @@
 		}
 	}
 
-	netdev->open = &ixgb_open;
-	netdev->stop = &ixgb_close;
-	netdev->hard_start_xmit = &ixgb_xmit_frame;
-	netdev->get_stats = &ixgb_get_stats;
-	netdev->set_multicast_list = &ixgb_set_multi;
-	netdev->set_mac_address = &ixgb_set_mac;
-	netdev->change_mtu = &ixgb_change_mtu;
+	netdev->netdev_ops = &ixgb_netdev_ops;
 	ixgb_set_ethtool_ops(netdev);
-	netdev->tx_timeout = &ixgb_tx_timeout;
 	netdev->watchdog_timeo = 5 * HZ;
 	netif_napi_add(netdev, &adapter->napi, ixgb_clean, 64);
-	netdev->vlan_rx_register = ixgb_vlan_rx_register;
-	netdev->vlan_rx_add_vid = ixgb_vlan_rx_add_vid;
-	netdev->vlan_rx_kill_vid = ixgb_vlan_rx_kill_vid;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	netdev->poll_controller = ixgb_netpoll;
-#endif
 
 	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
 
@@ -1106,8 +1110,15 @@
 
 	if (adapter->hw.link_up) {
 		if (!netif_carrier_ok(netdev)) {
-			DPRINTK(LINK, INFO,
-			        "NIC Link is Up 10000 Mbps Full Duplex\n");
+			printk(KERN_INFO "ixgb: %s NIC Link is Up 10 Gbps "
+			       "Full Duplex, Flow Control: %s\n",
+			       netdev->name,
+			       (adapter->hw.fc.type == ixgb_fc_full) ?
+			        "RX/TX" :
+			        ((adapter->hw.fc.type == ixgb_fc_rx_pause) ?
+			         "RX" :
+			         ((adapter->hw.fc.type == ixgb_fc_tx_pause) ?
+			          "TX" : "None")));
 			adapter->link_speed = 10000;
 			adapter->link_duplex = FULL_DUPLEX;
 			netif_carrier_on(netdev);
@@ -1117,7 +1128,8 @@
 		if (netif_carrier_ok(netdev)) {
 			adapter->link_speed = 0;
 			adapter->link_duplex = 0;
-			DPRINTK(LINK, INFO, "NIC Link is Down\n");
+			printk(KERN_INFO "ixgb: %s NIC Link is Down\n",
+			       netdev->name);
 			netif_carrier_off(netdev);
 			netif_stop_queue(netdev);
 
@@ -1709,14 +1721,14 @@
 		if (!test_bit(__IXGB_DOWN, &adapter->flags))
 			mod_timer(&adapter->watchdog_timer, jiffies);
 
-	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+	if (netif_rx_schedule_prep(&adapter->napi)) {
 
 		/* Disable interrupts and register for poll. The flush
 		  of the posted write is intentionally left out.
 		*/
 
 		IXGB_WRITE_REG(&adapter->hw, IMC, ~0);
-		__netif_rx_schedule(netdev, &adapter->napi);
+		__netif_rx_schedule(&adapter->napi);
 	}
 	return IRQ_HANDLED;
 }
@@ -1730,7 +1742,6 @@
 ixgb_clean(struct napi_struct *napi, int budget)
 {
 	struct ixgb_adapter *adapter = container_of(napi, struct ixgb_adapter, napi);
-	struct net_device *netdev = adapter->netdev;
 	int work_done = 0;
 
 	ixgb_clean_tx_irq(adapter);
@@ -1738,7 +1749,7 @@
 
 	/* If budget not fully consumed, exit the polling mode */
 	if (work_done < budget) {
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 		if (!test_bit(__IXGB_DOWN, &adapter->flags))
 			ixgb_irq_enable(adapter);
 	}
@@ -1981,7 +1992,6 @@
 		} else {
 			netif_receive_skb(skb);
 		}
-		netdev->last_rx = jiffies;
 
 rxdesc_done:
 		/* clean up descriptor, might be written over by hw */
diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile
index ccd83d9..6e7ef76 100644
--- a/drivers/net/ixgbe/Makefile
+++ b/drivers/net/ixgbe/Makefile
@@ -34,3 +34,5 @@
 
 ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
               ixgbe_82598.o ixgbe_phy.o
+
+ixgbe-$(CONFIG_IXGBE_DCB) +=  ixgbe_dcb.o ixgbe_dcb_82598.o ixgbe_dcb_nl.o
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index e116d34..e112008 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -32,10 +32,11 @@
 #include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/inet_lro.h>
+#include <linux/aer.h>
 
 #include "ixgbe_type.h"
 #include "ixgbe_common.h"
-
+#include "ixgbe_dcb.h"
 #ifdef CONFIG_IXGBE_DCA
 #include <linux/dca.h>
 #endif
@@ -84,6 +85,7 @@
 #define IXGBE_TX_FLAGS_TSO		(u32)(1 << 2)
 #define IXGBE_TX_FLAGS_IPV4		(u32)(1 << 3)
 #define IXGBE_TX_FLAGS_VLAN_MASK	0xffff0000
+#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK   0x0000e000
 #define IXGBE_TX_FLAGS_VLAN_SHIFT	16
 
 #define IXGBE_MAX_LRO_DESCRIPTORS       8
@@ -134,7 +136,7 @@
 
 	u16 reg_idx; /* holds the special value that gets the hardware register
 		      * offset associated with this ring, which is different
-		      * for DCE and RSS modes */
+		      * for DCB and RSS modes */
 
 #ifdef CONFIG_IXGBE_DCA
 	/* cpu for tx queue */
@@ -152,8 +154,10 @@
 	u16 rx_buf_len;
 };
 
+#define RING_F_DCB  0
 #define RING_F_VMDQ 1
 #define RING_F_RSS  2
+#define IXGBE_MAX_DCB_INDICES   8
 #define IXGBE_MAX_RSS_INDICES  16
 #define IXGBE_MAX_VMDQ_INDICES 16
 struct ixgbe_ring_feature {
@@ -164,6 +168,10 @@
 #define MAX_RX_QUEUES 64
 #define MAX_TX_QUEUES 32
 
+#define MAX_RX_PACKET_BUFFERS ((adapter->flags & IXGBE_FLAG_DCB_ENABLED) \
+                              ? 8 : 1)
+#define MAX_TX_PACKET_BUFFERS MAX_RX_PACKET_BUFFERS
+
 /* MAX_MSIX_Q_VECTORS of these are allocated,
  * but we only use one per queue-specific vector.
  */
@@ -215,6 +223,9 @@
 	struct work_struct reset_task;
 	struct ixgbe_q_vector q_vector[MAX_MSIX_Q_VECTORS];
 	char name[MAX_MSIX_COUNT][IFNAMSIZ + 5];
+	struct ixgbe_dcb_config dcb_cfg;
+	struct ixgbe_dcb_config temp_dcb_cfg;
+	u8 dcb_set_bitmap;
 
 	/* Interrupt Throttle Rate */
 	u32 itr_setting;
@@ -267,8 +278,10 @@
 #define IXGBE_FLAG_RSS_CAPABLE                  (u32)(1 << 17)
 #define IXGBE_FLAG_VMDQ_CAPABLE                 (u32)(1 << 18)
 #define IXGBE_FLAG_VMDQ_ENABLED                 (u32)(1 << 19)
+#define IXGBE_FLAG_FAN_FAIL_CAPABLE             (u32)(1 << 20)
 #define IXGBE_FLAG_NEED_LINK_UPDATE             (u32)(1 << 22)
 #define IXGBE_FLAG_IN_WATCHDOG_TASK             (u32)(1 << 23)
+#define IXGBE_FLAG_DCB_ENABLED                  (u32)(1 << 24)
 
 /* default to trying for four seconds */
 #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ)
@@ -299,12 +312,15 @@
 	unsigned long link_check_timeout;
 
 	struct work_struct watchdog_task;
+	struct work_struct sfp_task;
+	struct timer_list sfp_timer;
 };
 
 enum ixbge_state_t {
 	__IXGBE_TESTING,
 	__IXGBE_RESETTING,
-	__IXGBE_DOWN
+	__IXGBE_DOWN,
+	__IXGBE_SFP_MODULE_NOT_FOUND
 };
 
 enum ixgbe_boards {
@@ -312,6 +328,12 @@
 };
 
 extern struct ixgbe_info ixgbe_82598_info;
+#ifdef CONFIG_IXGBE_DCB
+extern struct dcbnl_rtnl_ops dcbnl_ops;
+extern int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg,
+                              struct ixgbe_dcb_config *dst_dcb_cfg,
+                              int tc_max);
+#endif
 
 extern char ixgbe_driver_name[];
 extern const char ixgbe_driver_version[];
@@ -326,5 +348,9 @@
 extern void ixgbe_free_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
 extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
 extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
+extern void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter);
+extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter);
+void ixgbe_napi_add_all(struct ixgbe_adapter *adapter);
+void ixgbe_napi_del_all(struct ixgbe_adapter *adapter);
 
 #endif /* _IXGBE_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index 7cddcfb..ad5699d 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -46,6 +46,8 @@
                                                ixgbe_link_speed speed,
                                                bool autoneg,
                                                bool autoneg_wait_to_complete);
+static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
+                                       u8 *eeprom_data);
 
 /**
  */
@@ -53,12 +55,40 @@
 {
 	struct ixgbe_mac_info *mac = &hw->mac;
 	struct ixgbe_phy_info *phy = &hw->phy;
+	s32 ret_val = 0;
+	u16 list_offset, data_offset;
 
 	/* Call PHY identify routine to get the phy type */
 	ixgbe_identify_phy_generic(hw);
 
 	/* PHY Init */
 	switch (phy->type) {
+	case ixgbe_phy_tn:
+		phy->ops.check_link = &ixgbe_check_phy_link_tnx;
+		phy->ops.get_firmware_version =
+		             &ixgbe_get_phy_firmware_version_tnx;
+		break;
+	case ixgbe_phy_nl:
+		phy->ops.reset = &ixgbe_reset_phy_nl;
+
+		/* Call SFP+ identify routine to get the SFP+ module type */
+		ret_val = phy->ops.identify_sfp(hw);
+		if (ret_val != 0)
+			goto out;
+		else if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) {
+			ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED;
+			goto out;
+		}
+
+		/* Check to see if SFP+ module is supported */
+		ret_val = ixgbe_get_sfp_init_sequence_offsets(hw,
+		                                              &list_offset,
+		                                              &data_offset);
+		if (ret_val != 0) {
+			ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED;
+			goto out;
+		}
+		break;
 	default:
 		break;
 	}
@@ -77,7 +107,8 @@
 	mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES;
 	mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES;
 
-	return 0;
+out:
+	return ret_val;
 }
 
 /**
@@ -146,9 +177,9 @@
  *
  *  Determines the link capabilities by reading the AUTOC register.
  **/
-s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw,
-                                             ixgbe_link_speed *speed,
-                                             bool *autoneg)
+static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw,
+						    ixgbe_link_speed *speed,
+						    bool *autoneg)
 {
 	s32 status = IXGBE_ERR_LINK_SETUP;
 	u16 speed_ability;
@@ -186,9 +217,15 @@
 	case IXGBE_DEV_ID_82598AF_SINGLE_PORT:
 	case IXGBE_DEV_ID_82598EB_CX4:
 	case IXGBE_DEV_ID_82598_CX4_DUAL_PORT:
+	case IXGBE_DEV_ID_82598_DA_DUAL_PORT:
+	case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM:
 	case IXGBE_DEV_ID_82598EB_XF_LR:
+	case IXGBE_DEV_ID_82598EB_SFP_LOM:
 		media_type = ixgbe_media_type_fiber;
 		break;
+	case IXGBE_DEV_ID_82598AT:
+		media_type = ixgbe_media_type_copper;
+		break;
 	default:
 		media_type = ixgbe_media_type_unknown;
 		break;
@@ -205,7 +242,7 @@
  *  Configures the flow control settings based on SW configuration.  This
  *  function is used for 802.3x flow control configuration only.
  **/
-s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
+static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
 {
 	u32 frctl_reg;
 	u32 rmcs_reg;
@@ -391,6 +428,46 @@
 {
 	u32 links_reg;
 	u32 i;
+	u16 link_reg, adapt_comp_reg;
+
+	/*
+	 * SERDES PHY requires us to read link status from register 0xC79F.
+	 * Bit 0 set indicates link is up/ready; clear indicates link down.
+	 * 0xC00C is read to check that the XAUI lanes are active.  Bit 0
+	 * clear indicates active; set indicates inactive.
+	 */
+	if (hw->phy.type == ixgbe_phy_nl) {
+		hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg);
+		hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg);
+		hw->phy.ops.read_reg(hw, 0xC00C, IXGBE_TWINAX_DEV,
+		                     &adapt_comp_reg);
+		if (link_up_wait_to_complete) {
+			for (i = 0; i < IXGBE_LINK_UP_TIME; i++) {
+				if ((link_reg & 1) &&
+				    ((adapt_comp_reg & 1) == 0)) {
+					*link_up = true;
+					break;
+				} else {
+					*link_up = false;
+				}
+				msleep(100);
+				hw->phy.ops.read_reg(hw, 0xC79F,
+				                     IXGBE_TWINAX_DEV,
+				                     &link_reg);
+				hw->phy.ops.read_reg(hw, 0xC00C,
+				                     IXGBE_TWINAX_DEV,
+				                     &adapt_comp_reg);
+			}
+		} else {
+			if ((link_reg & 1) && ((adapt_comp_reg & 1) == 0))
+				*link_up = true;
+			else
+				*link_up = false;
+		}
+
+		if (*link_up == false)
+			goto out;
+	}
 
 	links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
 	if (link_up_wait_to_complete) {
@@ -416,6 +493,7 @@
 	else
 		*speed = IXGBE_LINK_SPEED_1GB_FULL;
 
+out:
 	return 0;
 }
 
@@ -648,7 +726,7 @@
  *  @rar: receive address register index to associate with a VMDq index
  *  @vmdq: VMDq set index
  **/
-s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
+static s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
 {
 	u32 rar_high;
 
@@ -692,8 +770,8 @@
  *
  *  Turn on/off specified VLAN in the VLAN filter table.
  **/
-s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind,
-                         bool vlan_on)
+static s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind,
+				bool vlan_on)
 {
 	u32 regindex;
 	u32 bitindex;
@@ -816,7 +894,7 @@
  *
  *  Performs read operation to Atlas analog register specified.
  **/
-s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val)
+static s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val)
 {
 	u32  atlas_ctl;
 
@@ -838,7 +916,7 @@
  *
  *  Performs write operation to Atlas analog register specified.
  **/
-s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val)
+static s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val)
 {
 	u32  atlas_ctl;
 
@@ -851,12 +929,75 @@
 }
 
 /**
+ *  ixgbe_read_i2c_eeprom_82598 - Read 8 bit EEPROM word of an SFP+ module
+ *  over I2C interface through an intermediate phy.
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: EEPROM byte offset to read
+ *  @eeprom_data: value read
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface.
+ **/
+static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
+				       u8 *eeprom_data)
+{
+	s32 status = 0;
+	u16 sfp_addr = 0;
+	u16 sfp_data = 0;
+	u16 sfp_stat = 0;
+	u32 i;
+
+	if (hw->phy.type == ixgbe_phy_nl) {
+		/*
+		 * phy SDA/SCL registers are at addresses 0xC30A to
+		 * 0xC30D.  These registers are used to talk to the SFP+
+		 * module's EEPROM through the SDA/SCL (I2C) interface.
+		 */
+		sfp_addr = (IXGBE_I2C_EEPROM_DEV_ADDR << 8) + byte_offset;
+		sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK);
+		hw->phy.ops.write_reg(hw,
+		                      IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR,
+		                      IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+		                      sfp_addr);
+
+		/* Poll status */
+		for (i = 0; i < 100; i++) {
+			hw->phy.ops.read_reg(hw,
+			                     IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT,
+			                     IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+			                     &sfp_stat);
+			sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK;
+			if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS)
+				break;
+			msleep(10);
+		}
+
+		if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_PASS) {
+			hw_dbg(hw, "EEPROM read did not pass.\n");
+			status = IXGBE_ERR_SFP_NOT_PRESENT;
+			goto out;
+		}
+
+		/* Read data */
+		hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA,
+		                     IXGBE_MDIO_PMA_PMD_DEV_TYPE, &sfp_data);
+
+		*eeprom_data = (u8)(sfp_data >> 8);
+	} else {
+		status = IXGBE_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return status;
+}
+
+/**
  *  ixgbe_get_supported_physical_layer_82598 - Returns physical layer type
  *  @hw: pointer to hardware structure
  *
  *  Determines physical layer capabilities of the current configuration.
  **/
-s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw)
+static s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw)
 {
 	s32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
 
@@ -865,13 +1006,39 @@
 	case IXGBE_DEV_ID_82598_CX4_DUAL_PORT:
 		physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4;
 		break;
+	case IXGBE_DEV_ID_82598_DA_DUAL_PORT:
+		physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU;
+		break;
 	case IXGBE_DEV_ID_82598AF_DUAL_PORT:
 	case IXGBE_DEV_ID_82598AF_SINGLE_PORT:
+	case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM:
 		physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
 		break;
 	case IXGBE_DEV_ID_82598EB_XF_LR:
 		physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
 		break;
+	case IXGBE_DEV_ID_82598AT:
+		physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_T |
+		                  IXGBE_PHYSICAL_LAYER_1000BASE_T);
+		break;
+	case IXGBE_DEV_ID_82598EB_SFP_LOM:
+		hw->phy.ops.identify_sfp(hw);
+
+		switch (hw->phy.sfp_type) {
+		case ixgbe_sfp_type_da_cu:
+			physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU;
+			break;
+		case ixgbe_sfp_type_sr:
+			physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
+			break;
+		case ixgbe_sfp_type_lr:
+			physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
+			break;
+		default:
+			physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
+			break;
+		}
+		break;
 
 	default:
 		physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
@@ -923,12 +1090,13 @@
 
 static struct ixgbe_phy_operations phy_ops_82598 = {
 	.identify		= &ixgbe_identify_phy_generic,
-	/* .identify_sfp	= &ixgbe_identify_sfp_module_generic, */
+	.identify_sfp		= &ixgbe_identify_sfp_module_generic,
 	.reset			= &ixgbe_reset_phy_generic,
 	.read_reg		= &ixgbe_read_phy_reg_generic,
 	.write_reg		= &ixgbe_write_phy_reg_generic,
 	.setup_link		= &ixgbe_setup_phy_link_generic,
 	.setup_link_speed	= &ixgbe_setup_phy_link_speed_generic,
+	.read_i2c_eeprom	= &ixgbe_read_i2c_eeprom_82598,
 };
 
 struct ixgbe_info ixgbe_82598_info = {
diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c
new file mode 100644
index 0000000..e2e28ac
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_dcb.c
@@ -0,0 +1,332 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+#include "ixgbe.h"
+#include "ixgbe_type.h"
+#include "ixgbe_dcb.h"
+#include "ixgbe_dcb_82598.h"
+
+/**
+ * ixgbe_dcb_config - Struct containing DCB settings.
+ * @dcb_config: Pointer to DCB config structure
+ *
+ * This function checks DCB rules for DCB settings.
+ * The following rules are checked:
+ * 1. The sum of bandwidth percentages of all Bandwidth Groups must total 100%.
+ * 2. The sum of bandwidth percentages of all Traffic Classes within a Bandwidth
+ *    Group must total 100.
+ * 3. A Traffic Class should not be set to both Link Strict Priority
+ *    and Group Strict Priority.
+ * 4. Link strict Bandwidth Groups can only have link strict traffic classes
+ *    with zero bandwidth.
+ */
+s32 ixgbe_dcb_check_config(struct ixgbe_dcb_config *dcb_config)
+{
+	struct tc_bw_alloc *p;
+	s32 ret_val = 0;
+	u8 i, j, bw = 0, bw_id;
+	u8 bw_sum[2][MAX_BW_GROUP];
+	bool link_strict[2][MAX_BW_GROUP];
+
+	memset(bw_sum, 0, sizeof(bw_sum));
+	memset(link_strict, 0, sizeof(link_strict));
+
+	/* First Tx, then Rx */
+	for (i = 0; i < 2; i++) {
+		/* Check each traffic class for rule violation */
+		for (j = 0; j < MAX_TRAFFIC_CLASS; j++) {
+			p = &dcb_config->tc_config[j].path[i];
+
+			bw = p->bwg_percent;
+			bw_id = p->bwg_id;
+
+			if (bw_id >= MAX_BW_GROUP) {
+				ret_val = DCB_ERR_CONFIG;
+				goto err_config;
+			}
+			if (p->prio_type == prio_link) {
+				link_strict[i][bw_id] = true;
+				/* Link strict should have zero bandwidth */
+				if (bw) {
+					ret_val = DCB_ERR_LS_BW_NONZERO;
+					goto err_config;
+				}
+			} else if (!bw) {
+				/*
+				 * Traffic classes without link strict
+				 * should have non-zero bandwidth.
+				 */
+				ret_val = DCB_ERR_TC_BW_ZERO;
+				goto err_config;
+			}
+			bw_sum[i][bw_id] += bw;
+		}
+
+		bw = 0;
+
+		/* Check each bandwidth group for rule violation */
+		for (j = 0; j < MAX_BW_GROUP; j++) {
+			bw += dcb_config->bw_percentage[i][j];
+			/*
+			 * Sum of bandwidth percentages of all traffic classes
+			 * within a Bandwidth Group must total 100 except for
+			 * link strict group (zero bandwidth).
+			 */
+			if (link_strict[i][j]) {
+				if (bw_sum[i][j]) {
+					/*
+					 * Link strict group should have zero
+					 * bandwidth.
+					 */
+					ret_val = DCB_ERR_LS_BWG_NONZERO;
+					goto err_config;
+				}
+			} else if (bw_sum[i][j] != BW_PERCENT &&
+				   bw_sum[i][j] != 0) {
+				ret_val = DCB_ERR_TC_BW;
+				goto err_config;
+			}
+		}
+
+		if (bw != BW_PERCENT) {
+			ret_val = DCB_ERR_BW_GROUP;
+			goto err_config;
+		}
+	}
+
+err_config:
+	return ret_val;
+}
+
+/**
+ * ixgbe_dcb_calculate_tc_credits - Calculates traffic class credits
+ * @ixgbe_dcb_config: Struct containing DCB settings.
+ * @direction: Configuring either Tx or Rx.
+ *
+ * This function calculates the credits allocated to each traffic class.
+ * It should be called only after the rules are checked by
+ * ixgbe_dcb_check_config().
+ */
+s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config,
+                                   u8 direction)
+{
+	struct tc_bw_alloc *p;
+	s32 ret_val = 0;
+	/* Initialization values default for Tx settings */
+	u32 credit_refill       = 0;
+	u32 credit_max          = 0;
+	u16 link_percentage     = 0;
+	u8  bw_percent          = 0;
+	u8  i;
+
+	if (dcb_config == NULL) {
+		ret_val = DCB_ERR_CONFIG;
+		goto out;
+	}
+
+	/* Find out the link percentage for each TC first */
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		p = &dcb_config->tc_config[i].path[direction];
+		bw_percent = dcb_config->bw_percentage[direction][p->bwg_id];
+
+		link_percentage = p->bwg_percent;
+		/* Must be careful of integer division for very small nums */
+		link_percentage = (link_percentage * bw_percent) / 100;
+		if (p->bwg_percent > 0 && link_percentage == 0)
+			link_percentage = 1;
+
+		/* Save link_percentage for reference */
+		p->link_percent = (u8)link_percentage;
+
+		/* Calculate credit refill and save it */
+		credit_refill = link_percentage * MINIMUM_CREDIT_REFILL;
+		p->data_credits_refill = (u16)credit_refill;
+
+		/* Calculate maximum credit for the TC */
+		credit_max = (link_percentage * MAX_CREDIT) / 100;
+
+		/*
+		 * Adjustment based on rule checking, if the percentage
+		 * of a TC is too small, the maximum credit may not be
+		 * enough to send out a jumbo frame in data plane arbitration.
+		 */
+		if (credit_max && (credit_max < MINIMUM_CREDIT_FOR_JUMBO))
+			credit_max = MINIMUM_CREDIT_FOR_JUMBO;
+
+		if (direction == DCB_TX_CONFIG) {
+			/*
+			 * Adjustment based on rule checking, if the
+			 * percentage of a TC is too small, the maximum
+			 * credit may not be enough to send out a TSO
+			 * packet in descriptor plane arbitration.
+			 */
+			if (credit_max &&
+			    (credit_max < MINIMUM_CREDIT_FOR_TSO))
+				credit_max = MINIMUM_CREDIT_FOR_TSO;
+
+			dcb_config->tc_config[i].desc_credits_max =
+				(u16)credit_max;
+		}
+
+		p->data_credits_max = (u16)credit_max;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ * ixgbe_dcb_get_tc_stats - Returns status of each traffic class
+ * @hw: pointer to hardware structure
+ * @stats: pointer to statistics structure
+ * @tc_count:  Number of elements in bwg_array.
+ *
+ * This function returns the status data for each of the Traffic Classes in use.
+ */
+s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats,
+                           u8 tc_count)
+{
+	s32 ret = 0;
+	if (hw->mac.type == ixgbe_mac_82598EB)
+		ret = ixgbe_dcb_get_tc_stats_82598(hw, stats, tc_count);
+	return ret;
+}
+
+/**
+ * ixgbe_dcb_get_pfc_stats - Returns CBFC status of each traffic class
+ * hw - pointer to hardware structure
+ * stats - pointer to statistics structure
+ * tc_count -  Number of elements in bwg_array.
+ *
+ * This function returns the CBFC status data for each of the Traffic Classes.
+ */
+s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats,
+                            u8 tc_count)
+{
+	s32 ret = 0;
+	if (hw->mac.type == ixgbe_mac_82598EB)
+		ret = ixgbe_dcb_get_pfc_stats_82598(hw, stats, tc_count);
+	return ret;
+}
+
+/**
+ * ixgbe_dcb_config_rx_arbiter - Config Rx arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Rx Data Arbiter and credits for each traffic class.
+ */
+s32 ixgbe_dcb_config_rx_arbiter(struct ixgbe_hw *hw,
+                                struct ixgbe_dcb_config *dcb_config)
+{
+	s32 ret = 0;
+	if (hw->mac.type == ixgbe_mac_82598EB)
+		ret = ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config);
+	return ret;
+}
+
+/**
+ * ixgbe_dcb_config_tx_desc_arbiter - Config Tx Desc arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Tx Descriptor Arbiter and credits for each traffic class.
+ */
+s32 ixgbe_dcb_config_tx_desc_arbiter(struct ixgbe_hw *hw,
+                                     struct ixgbe_dcb_config *dcb_config)
+{
+	s32 ret = 0;
+	if (hw->mac.type == ixgbe_mac_82598EB)
+		ret = ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config);
+	return ret;
+}
+
+/**
+ * ixgbe_dcb_config_tx_data_arbiter - Config Tx data arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Tx Data Arbiter and credits for each traffic class.
+ */
+s32 ixgbe_dcb_config_tx_data_arbiter(struct ixgbe_hw *hw,
+                                     struct ixgbe_dcb_config *dcb_config)
+{
+	s32 ret = 0;
+	if (hw->mac.type == ixgbe_mac_82598EB)
+		ret = ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config);
+	return ret;
+}
+
+/**
+ * ixgbe_dcb_config_pfc - Config priority flow control
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Priority Flow Control for each traffic class.
+ */
+s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *hw,
+                         struct ixgbe_dcb_config *dcb_config)
+{
+	s32 ret = 0;
+	if (hw->mac.type == ixgbe_mac_82598EB)
+		ret = ixgbe_dcb_config_pfc_82598(hw, dcb_config);
+	return ret;
+}
+
+/**
+ * ixgbe_dcb_config_tc_stats - Config traffic class statistics
+ * @hw: pointer to hardware structure
+ *
+ * Configure queue statistics registers, all queues belonging to same traffic
+ * class uses a single set of queue statistics counters.
+ */
+s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *hw)
+{
+	s32 ret = 0;
+	if (hw->mac.type == ixgbe_mac_82598EB)
+		ret = ixgbe_dcb_config_tc_stats_82598(hw);
+	return ret;
+}
+
+/**
+ * ixgbe_dcb_hw_config - Config and enable DCB
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure dcb settings and enable dcb mode.
+ */
+s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw,
+                        struct ixgbe_dcb_config *dcb_config)
+{
+	s32 ret = 0;
+	if (hw->mac.type == ixgbe_mac_82598EB)
+		ret = ixgbe_dcb_hw_config_82598(hw, dcb_config);
+	return ret;
+}
+
diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h
new file mode 100644
index 0000000..75f6efe
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_dcb.h
@@ -0,0 +1,184 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _DCB_CONFIG_H_
+#define _DCB_CONFIG_H_
+
+#include "ixgbe_type.h"
+
+/* DCB data structures */
+
+#define IXGBE_MAX_PACKET_BUFFERS 8
+#define MAX_USER_PRIORITY        8
+#define MAX_TRAFFIC_CLASS        8
+#define MAX_BW_GROUP             8
+#define BW_PERCENT               100
+
+#define DCB_TX_CONFIG            0
+#define DCB_RX_CONFIG            1
+
+/* DCB error Codes */
+#define DCB_SUCCESS              0
+#define DCB_ERR_CONFIG           -1
+#define DCB_ERR_PARAM            -2
+
+/* Transmit and receive Errors */
+/* Error in bandwidth group allocation */
+#define DCB_ERR_BW_GROUP        -3
+/* Error in traffic class bandwidth allocation */
+#define DCB_ERR_TC_BW           -4
+/* Traffic class has both link strict and group strict enabled */
+#define DCB_ERR_LS_GS           -5
+/* Link strict traffic class has non zero bandwidth */
+#define DCB_ERR_LS_BW_NONZERO   -6
+/* Link strict bandwidth group has non zero bandwidth */
+#define DCB_ERR_LS_BWG_NONZERO  -7
+/*  Traffic class has zero bandwidth */
+#define DCB_ERR_TC_BW_ZERO      -8
+
+#define DCB_NOT_IMPLEMENTED      0x7FFFFFFF
+
+struct dcb_pfc_tc_debug {
+	u8  tc;
+	u8  pause_status;
+	u64 pause_quanta;
+};
+
+enum strict_prio_type {
+	prio_none = 0,
+	prio_group,
+	prio_link
+};
+
+/* Traffic class bandwidth allocation per direction */
+struct tc_bw_alloc {
+	u8 bwg_id;		  /* Bandwidth Group (BWG) ID */
+	u8 bwg_percent;		  /* % of BWG's bandwidth */
+	u8 link_percent;	  /* % of link bandwidth */
+	u8 up_to_tc_bitmap;	  /* User Priority to Traffic Class mapping */
+	u16 data_credits_refill;  /* Credit refill amount in 64B granularity */
+	u16 data_credits_max;	  /* Max credits for a configured packet buffer
+				   * in 64B granularity.*/
+	enum strict_prio_type prio_type; /* Link or Group Strict Priority */
+};
+
+enum dcb_pfc_type {
+	pfc_disabled = 0,
+	pfc_enabled_full,
+	pfc_enabled_tx,
+	pfc_enabled_rx
+};
+
+/* Traffic class configuration */
+struct tc_configuration {
+	struct tc_bw_alloc path[2]; /* One each for Tx/Rx */
+	enum dcb_pfc_type  dcb_pfc; /* Class based flow control setting */
+
+	u16 desc_credits_max; /* For Tx Descriptor arbitration */
+	u8 tc; /* Traffic class (TC) */
+};
+
+enum dcb_rx_pba_cfg {
+	pba_equal,     /* PBA[0-7] each use 64KB FIFO */
+	pba_80_48      /* PBA[0-3] each use 80KB, PBA[4-7] each use 48KB */
+};
+
+/*
+ * This structure contains many values encoded as fixed-point
+ * numbers, meaning that some of bits are dedicated to the
+ * magnitude and others to the fraction part. In the comments
+ * this is shown as f=n, where n is the number of fraction bits.
+ * These fraction bits are always the low-order bits. The size
+ * of the magnitude is not specified.
+ */
+struct bcn_config {
+	u32 rp_admin_mode[MAX_TRAFFIC_CLASS]; /* BCN enabled, per TC */
+	u32 bcna_option[2]; /* BCNA Port + MAC Addr */
+	u32 rp_w;        /* Derivative Weight, f=3 */
+	u32 rp_gi;       /* Increase Gain, f=12 */
+	u32 rp_gd;       /* Decrease Gain, f=12 */
+	u32 rp_ru;       /* Rate Unit */
+	u32 rp_alpha;    /* Max Decrease Factor, f=12 */
+	u32 rp_beta;     /* Max Increase Factor, f=12 */
+	u32 rp_ri;       /* Initial Rate */
+	u32 rp_td;       /* Drift Interval Timer */
+	u32 rp_rd;       /* Drift Increase */
+	u32 rp_tmax;     /* Severe Congestion Backoff Timer Range */
+	u32 rp_rmin;     /* Severe Congestion Restart Rate */
+	u32 rp_wrtt;     /* RTT Moving Average Weight */
+};
+
+struct ixgbe_dcb_config {
+	struct bcn_config bcn;
+
+	struct tc_configuration tc_config[MAX_TRAFFIC_CLASS];
+	u8     bw_percentage[2][MAX_BW_GROUP]; /* One each for Tx/Rx */
+
+	bool  round_robin_enable;
+
+	enum dcb_rx_pba_cfg rx_pba_cfg;
+
+	u32  dcb_cfg_version; /* Not used...OS-specific? */
+	u32  link_speed; /* For bandwidth allocation validation purpose */
+};
+
+/* DCB driver APIs */
+
+/* DCB rule checking function.*/
+s32 ixgbe_dcb_check_config(struct ixgbe_dcb_config *config);
+
+/* DCB credits calculation */
+s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *, u8);
+
+/* DCB PFC functions */
+s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *, struct ixgbe_dcb_config *g);
+s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *, struct ixgbe_hw_stats *, u8);
+
+/* DCB traffic class stats */
+s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *);
+s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *, struct ixgbe_hw_stats *, u8);
+
+/* DCB config arbiters */
+s32 ixgbe_dcb_config_tx_desc_arbiter(struct ixgbe_hw *,
+                                     struct ixgbe_dcb_config *);
+s32 ixgbe_dcb_config_tx_data_arbiter(struct ixgbe_hw *,
+                                     struct ixgbe_dcb_config *);
+s32 ixgbe_dcb_config_rx_arbiter(struct ixgbe_hw *, struct ixgbe_dcb_config *);
+
+/* DCB hw initialization */
+s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *);
+
+/* DCB definitions for credit calculation */
+#define MAX_CREDIT_REFILL       511  /* 0x1FF * 64B = 32704B */
+#define MINIMUM_CREDIT_REFILL   5    /* 5*64B = 320B */
+#define MINIMUM_CREDIT_FOR_JUMBO 145  /* 145= UpperBound((9*1024+54)/64B) for 9KB jumbo frame */
+#define DCB_MAX_TSO_SIZE        (32*1024) /* MAX TSO packet size supported in DCB mode */
+#define MINIMUM_CREDIT_FOR_TSO  (DCB_MAX_TSO_SIZE/64 + 1) /* 513 for 32KB TSO packet */
+#define MAX_CREDIT              4095 /* Maximum credit supported: 256KB * 1204 / 64B */
+
+#endif /* _DCB_CONFIG_H */
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c
new file mode 100644
index 0000000..2c046b0
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c
@@ -0,0 +1,398 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "ixgbe.h"
+#include "ixgbe_type.h"
+#include "ixgbe_dcb.h"
+#include "ixgbe_dcb_82598.h"
+
+/**
+ * ixgbe_dcb_get_tc_stats_82598 - Return status data for each traffic class
+ * @hw: pointer to hardware structure
+ * @stats: pointer to statistics structure
+ * @tc_count:  Number of elements in bwg_array.
+ *
+ * This function returns the status data for each of the Traffic Classes in use.
+ */
+s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *hw,
+                                 struct ixgbe_hw_stats *stats,
+                                 u8 tc_count)
+{
+	int tc;
+
+	if (tc_count > MAX_TRAFFIC_CLASS)
+		return DCB_ERR_PARAM;
+
+	/* Statistics pertaining to each traffic class */
+	for (tc = 0; tc < tc_count; tc++) {
+		/* Transmitted Packets */
+		stats->qptc[tc] += IXGBE_READ_REG(hw, IXGBE_QPTC(tc));
+		/* Transmitted Bytes */
+		stats->qbtc[tc] += IXGBE_READ_REG(hw, IXGBE_QBTC(tc));
+		/* Received Packets */
+		stats->qprc[tc] += IXGBE_READ_REG(hw, IXGBE_QPRC(tc));
+		/* Received Bytes */
+		stats->qbrc[tc] += IXGBE_READ_REG(hw, IXGBE_QBRC(tc));
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_dcb_get_pfc_stats_82598 - Returns CBFC status data
+ * @hw: pointer to hardware structure
+ * @stats: pointer to statistics structure
+ * @tc_count:  Number of elements in bwg_array.
+ *
+ * This function returns the CBFC status data for each of the Traffic Classes.
+ */
+s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *hw,
+                                  struct ixgbe_hw_stats *stats,
+                                  u8 tc_count)
+{
+	int tc;
+
+	if (tc_count > MAX_TRAFFIC_CLASS)
+		return DCB_ERR_PARAM;
+
+	for (tc = 0; tc < tc_count; tc++) {
+		/* Priority XOFF Transmitted */
+		stats->pxofftxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(tc));
+		/* Priority XOFF Received */
+		stats->pxoffrxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(tc));
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_dcb_config_packet_buffers_82598 - Configure packet buffers
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure packet buffers for DCB mode.
+ */
+static s32 ixgbe_dcb_config_packet_buffers_82598(struct ixgbe_hw *hw,
+						 struct ixgbe_dcb_config *dcb_config)
+{
+	s32 ret_val = 0;
+	u32 value = IXGBE_RXPBSIZE_64KB;
+	u8  i = 0;
+
+	/* Setup Rx packet buffer sizes */
+	switch (dcb_config->rx_pba_cfg) {
+	case pba_80_48:
+		/* Setup the first four at 80KB */
+		value = IXGBE_RXPBSIZE_80KB;
+		for (; i < 4; i++)
+			IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value);
+		/* Setup the last four at 48KB...don't re-init i */
+		value = IXGBE_RXPBSIZE_48KB;
+		/* Fall Through */
+	case pba_equal:
+	default:
+		for (; i < IXGBE_MAX_PACKET_BUFFERS; i++)
+			IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value);
+
+		/* Setup Tx packet buffer sizes */
+		for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) {
+			IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i),
+					IXGBE_TXPBSIZE_40KB);
+		}
+		break;
+	}
+
+	return ret_val;
+}
+
+/**
+ * ixgbe_dcb_config_rx_arbiter_82598 - Config Rx data arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Rx Data Arbiter and credits for each traffic class.
+ */
+s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw,
+                                      struct ixgbe_dcb_config *dcb_config)
+{
+	struct tc_bw_alloc    *p;
+	u32    reg           = 0;
+	u32    credit_refill = 0;
+	u32    credit_max    = 0;
+	u8     i             = 0;
+
+	reg = IXGBE_READ_REG(hw, IXGBE_RUPPBMR) | IXGBE_RUPPBMR_MQA;
+	IXGBE_WRITE_REG(hw, IXGBE_RUPPBMR, reg);
+
+	reg = IXGBE_READ_REG(hw, IXGBE_RMCS);
+	/* Enable Arbiter */
+	reg &= ~IXGBE_RMCS_ARBDIS;
+	/* Enable Receive Recycle within the BWG */
+	reg |= IXGBE_RMCS_RRM;
+	/* Enable Deficit Fixed Priority arbitration*/
+	reg |= IXGBE_RMCS_DFP;
+
+	IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg);
+
+	/* Configure traffic class credits and priority */
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		p = &dcb_config->tc_config[i].path[DCB_RX_CONFIG];
+		credit_refill = p->data_credits_refill;
+		credit_max    = p->data_credits_max;
+
+		reg = credit_refill | (credit_max << IXGBE_RT2CR_MCL_SHIFT);
+
+		if (p->prio_type == prio_link)
+			reg |= IXGBE_RT2CR_LSP;
+
+		IXGBE_WRITE_REG(hw, IXGBE_RT2CR(i), reg);
+	}
+
+	reg = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+	reg |= IXGBE_RDRXCTL_RDMTS_1_2;
+	reg |= IXGBE_RDRXCTL_MPBEN;
+	reg |= IXGBE_RDRXCTL_MCEN;
+	IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg);
+
+	reg = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+	/* Make sure there is enough descriptors before arbitration */
+	reg &= ~IXGBE_RXCTRL_DMBYPS;
+	IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg);
+
+	return 0;
+}
+
+/**
+ * ixgbe_dcb_config_tx_desc_arbiter_82598 - Config Tx Desc. arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Tx Descriptor Arbiter and credits for each traffic class.
+ */
+s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
+                                           struct ixgbe_dcb_config *dcb_config)
+{
+	struct tc_bw_alloc *p;
+	u32    reg, max_credits;
+	u8     i;
+
+	reg = IXGBE_READ_REG(hw, IXGBE_DPMCS);
+
+	/* Enable arbiter */
+	reg &= ~IXGBE_DPMCS_ARBDIS;
+	if (!(dcb_config->round_robin_enable)) {
+		/* Enable DFP and Recycle mode */
+		reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM);
+	}
+	reg |= IXGBE_DPMCS_TSOEF;
+	/* Configure Max TSO packet size 34KB including payload and headers */
+	reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT);
+
+	IXGBE_WRITE_REG(hw, IXGBE_DPMCS, reg);
+
+	/* Configure traffic class credits and priority */
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG];
+		max_credits = dcb_config->tc_config[i].desc_credits_max;
+		reg = max_credits << IXGBE_TDTQ2TCCR_MCL_SHIFT;
+		reg |= p->data_credits_refill;
+		reg |= (u32)(p->bwg_id) << IXGBE_TDTQ2TCCR_BWG_SHIFT;
+
+		if (p->prio_type == prio_group)
+			reg |= IXGBE_TDTQ2TCCR_GSP;
+
+		if (p->prio_type == prio_link)
+			reg |= IXGBE_TDTQ2TCCR_LSP;
+
+		IXGBE_WRITE_REG(hw, IXGBE_TDTQ2TCCR(i), reg);
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_dcb_config_tx_data_arbiter_82598 - Config Tx data arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Tx Data Arbiter and credits for each traffic class.
+ */
+s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw,
+                                           struct ixgbe_dcb_config *dcb_config)
+{
+	struct tc_bw_alloc *p;
+	u32 reg;
+	u8 i;
+
+	reg = IXGBE_READ_REG(hw, IXGBE_PDPMCS);
+	/* Enable Data Plane Arbiter */
+	reg &= ~IXGBE_PDPMCS_ARBDIS;
+	/* Enable DFP and Transmit Recycle Mode */
+	reg |= (IXGBE_PDPMCS_TPPAC | IXGBE_PDPMCS_TRM);
+
+	IXGBE_WRITE_REG(hw, IXGBE_PDPMCS, reg);
+
+	/* Configure traffic class credits and priority */
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG];
+		reg = p->data_credits_refill;
+		reg |= (u32)(p->data_credits_max) << IXGBE_TDPT2TCCR_MCL_SHIFT;
+		reg |= (u32)(p->bwg_id) << IXGBE_TDPT2TCCR_BWG_SHIFT;
+
+		if (p->prio_type == prio_group)
+			reg |= IXGBE_TDPT2TCCR_GSP;
+
+		if (p->prio_type == prio_link)
+			reg |= IXGBE_TDPT2TCCR_LSP;
+
+		IXGBE_WRITE_REG(hw, IXGBE_TDPT2TCCR(i), reg);
+	}
+
+	/* Enable Tx packet buffer division */
+	reg = IXGBE_READ_REG(hw, IXGBE_DTXCTL);
+	reg |= IXGBE_DTXCTL_ENDBUBD;
+	IXGBE_WRITE_REG(hw, IXGBE_DTXCTL, reg);
+
+	return 0;
+}
+
+/**
+ * ixgbe_dcb_config_pfc_82598 - Config priority flow control
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Priority Flow Control for each traffic class.
+ */
+s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw,
+                               struct ixgbe_dcb_config *dcb_config)
+{
+	u32 reg, rx_pba_size;
+	u8  i;
+
+	/* Enable Transmit Priority Flow Control */
+	reg = IXGBE_READ_REG(hw, IXGBE_RMCS);
+	reg &= ~IXGBE_RMCS_TFCE_802_3X;
+	/* correct the reporting of our flow control status */
+	hw->fc.type = ixgbe_fc_none;
+	reg |= IXGBE_RMCS_TFCE_PRIORITY;
+	IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg);
+
+	/* Enable Receive Priority Flow Control */
+	reg = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+	reg &= ~IXGBE_FCTRL_RFCE;
+	reg |= IXGBE_FCTRL_RPFCE;
+	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg);
+
+	/*
+	 * Configure flow control thresholds and enable priority flow control
+	 * for each traffic class.
+	 */
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		if (dcb_config->rx_pba_cfg == pba_equal) {
+			rx_pba_size = IXGBE_RXPBSIZE_64KB;
+		} else {
+			rx_pba_size = (i < 4) ? IXGBE_RXPBSIZE_80KB
+					      : IXGBE_RXPBSIZE_48KB;
+		}
+
+		reg = ((rx_pba_size >> 5) &  0xFFF0);
+		if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx ||
+		    dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full)
+			reg |= IXGBE_FCRTL_XONE;
+
+		IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), reg);
+
+		reg = ((rx_pba_size >> 2) & 0xFFF0);
+		if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx ||
+		    dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full)
+			reg |= IXGBE_FCRTH_FCEN;
+
+		IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), reg);
+	}
+
+	/* Configure pause time */
+	for (i = 0; i < (MAX_TRAFFIC_CLASS >> 1); i++)
+		IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), 0x68006800);
+
+	/* Configure flow control refresh threshold value */
+	IXGBE_WRITE_REG(hw, IXGBE_FCRTV, 0x3400);
+
+	return 0;
+}
+
+/**
+ * ixgbe_dcb_config_tc_stats_82598 - Configure traffic class statistics
+ * @hw: pointer to hardware structure
+ *
+ * Configure queue statistics registers, all queues belonging to same traffic
+ * class uses a single set of queue statistics counters.
+ */
+s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw)
+{
+	u32 reg = 0;
+	u8  i   = 0;
+	u8  j   = 0;
+
+	/* Receive Queues stats setting -  8 queues per statistics reg */
+	for (i = 0, j = 0; i < 15 && j < 8; i = i + 2, j++) {
+		reg = IXGBE_READ_REG(hw, IXGBE_RQSMR(i));
+		reg |= ((0x1010101) * j);
+		IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i), reg);
+		reg = IXGBE_READ_REG(hw, IXGBE_RQSMR(i + 1));
+		reg |= ((0x1010101) * j);
+		IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i + 1), reg);
+	}
+	/* Transmit Queues stats setting -  4 queues per statistics reg */
+	for (i = 0; i < 8; i++) {
+		reg = IXGBE_READ_REG(hw, IXGBE_TQSMR(i));
+		reg |= ((0x1010101) * i);
+		IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i), reg);
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_dcb_hw_config_82598 - Config and enable DCB
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure dcb settings and enable dcb mode.
+ */
+s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw,
+                              struct ixgbe_dcb_config *dcb_config)
+{
+	ixgbe_dcb_config_packet_buffers_82598(hw, dcb_config);
+	ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config);
+	ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config);
+	ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config);
+	ixgbe_dcb_config_pfc_82598(hw, dcb_config);
+	ixgbe_dcb_config_tc_stats_82598(hw);
+
+	return 0;
+}
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.h b/drivers/net/ixgbe/ixgbe_dcb_82598.h
new file mode 100644
index 0000000..1e6a313
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_dcb_82598.h
@@ -0,0 +1,94 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _DCB_82598_CONFIG_H_
+#define _DCB_82598_CONFIG_H_
+
+/* DCB register definitions */
+
+#define IXGBE_DPMCS_MTSOS_SHIFT 16
+#define IXGBE_DPMCS_TDPAC       0x00000001 /* 0 Round Robin, 1 DFP - Deficit Fixed Priority */
+#define IXGBE_DPMCS_TRM         0x00000010 /* Transmit Recycle Mode */
+#define IXGBE_DPMCS_ARBDIS      0x00000040 /* DCB arbiter disable */
+#define IXGBE_DPMCS_TSOEF       0x00080000 /* TSO Expand Factor: 0=x4, 1=x2 */
+
+#define IXGBE_RUPPBMR_MQA       0x80000000 /* Enable UP to queue mapping */
+
+#define IXGBE_RT2CR_MCL_SHIFT   12 /* Offset to Max Credit Limit setting */
+#define IXGBE_RT2CR_LSP         0x80000000 /* LSP enable bit */
+
+#define IXGBE_RDRXCTL_MPBEN     0x00000010 /* DMA config for multiple packet buffers enable */
+#define IXGBE_RDRXCTL_MCEN      0x00000040 /* DMA config for multiple cores (RSS) enable */
+
+#define IXGBE_TDTQ2TCCR_MCL_SHIFT   12
+#define IXGBE_TDTQ2TCCR_BWG_SHIFT   9
+#define IXGBE_TDTQ2TCCR_GSP     0x40000000
+#define IXGBE_TDTQ2TCCR_LSP     0x80000000
+
+#define IXGBE_TDPT2TCCR_MCL_SHIFT   12
+#define IXGBE_TDPT2TCCR_BWG_SHIFT   9
+#define IXGBE_TDPT2TCCR_GSP     0x40000000
+#define IXGBE_TDPT2TCCR_LSP     0x80000000
+
+#define IXGBE_PDPMCS_TPPAC      0x00000020 /* 0 Round Robin, 1 for DFP - Deficit Fixed Priority */
+#define IXGBE_PDPMCS_ARBDIS     0x00000040 /* Arbiter disable */
+#define IXGBE_PDPMCS_TRM        0x00000100 /* Transmit Recycle Mode enable */
+
+#define IXGBE_DTXCTL_ENDBUBD    0x00000004 /* Enable DBU buffer division */
+
+#define IXGBE_TXPBSIZE_40KB     0x0000A000 /* 40KB Packet Buffer */
+#define IXGBE_RXPBSIZE_48KB     0x0000C000 /* 48KB Packet Buffer */
+#define IXGBE_RXPBSIZE_64KB     0x00010000 /* 64KB Packet Buffer */
+#define IXGBE_RXPBSIZE_80KB     0x00014000 /* 80KB Packet Buffer */
+
+#define IXGBE_RDRXCTL_RDMTS_1_2 0x00000000
+
+/* DCB hardware-specific driver APIs */
+
+/* DCB PFC functions */
+s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *);
+s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *, struct ixgbe_hw_stats *,
+                                  u8);
+
+/* DCB traffic class stats */
+s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *);
+s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *, struct ixgbe_hw_stats *,
+                                 u8);
+
+/* DCB config arbiters */
+s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *,
+                                           struct ixgbe_dcb_config *);
+s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *,
+                                           struct ixgbe_dcb_config *);
+s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *,
+                                      struct ixgbe_dcb_config *);
+
+/* DCB hw initialization */
+s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *);
+
+#endif /* _DCB_82598_CONFIG_H */
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
new file mode 100644
index 0000000..4129976
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -0,0 +1,641 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "ixgbe.h"
+#include <linux/dcbnl.h>
+
+/* Callbacks for DCB netlink in the kernel */
+#define BIT_DCB_MODE	0x01
+#define BIT_PFC		0x02
+#define BIT_PG_RX	0x04
+#define BIT_PG_TX	0x08
+#define BIT_BCN         0x10
+
+int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg,
+                       struct ixgbe_dcb_config *dst_dcb_cfg, int tc_max)
+{
+	struct tc_configuration *src_tc_cfg = NULL;
+	struct tc_configuration *dst_tc_cfg = NULL;
+	int i;
+
+	if (!src_dcb_cfg || !dst_dcb_cfg)
+		return -EINVAL;
+
+	for (i = DCB_PG_ATTR_TC_0; i < tc_max + DCB_PG_ATTR_TC_0; i++) {
+		src_tc_cfg = &src_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0];
+		dst_tc_cfg = &dst_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0];
+
+		dst_tc_cfg->path[DCB_TX_CONFIG].prio_type =
+				src_tc_cfg->path[DCB_TX_CONFIG].prio_type;
+
+		dst_tc_cfg->path[DCB_TX_CONFIG].bwg_id =
+				src_tc_cfg->path[DCB_TX_CONFIG].bwg_id;
+
+		dst_tc_cfg->path[DCB_TX_CONFIG].bwg_percent =
+				src_tc_cfg->path[DCB_TX_CONFIG].bwg_percent;
+
+		dst_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap =
+				src_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap;
+
+		dst_tc_cfg->path[DCB_RX_CONFIG].prio_type =
+				src_tc_cfg->path[DCB_RX_CONFIG].prio_type;
+
+		dst_tc_cfg->path[DCB_RX_CONFIG].bwg_id =
+				src_tc_cfg->path[DCB_RX_CONFIG].bwg_id;
+
+		dst_tc_cfg->path[DCB_RX_CONFIG].bwg_percent =
+				src_tc_cfg->path[DCB_RX_CONFIG].bwg_percent;
+
+		dst_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap =
+				src_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap;
+	}
+
+	for (i = DCB_PG_ATTR_BW_ID_0; i < DCB_PG_ATTR_BW_ID_MAX; i++) {
+		dst_dcb_cfg->bw_percentage[DCB_TX_CONFIG]
+			[i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage
+				[DCB_TX_CONFIG][i-DCB_PG_ATTR_BW_ID_0];
+		dst_dcb_cfg->bw_percentage[DCB_RX_CONFIG]
+			[i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage
+				[DCB_RX_CONFIG][i-DCB_PG_ATTR_BW_ID_0];
+	}
+
+	for (i = DCB_PFC_UP_ATTR_0; i < DCB_PFC_UP_ATTR_MAX; i++) {
+		dst_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc =
+			src_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc;
+	}
+
+	for (i = DCB_BCN_ATTR_RP_0; i < DCB_BCN_ATTR_RP_ALL; i++) {
+		dst_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0] =
+			src_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0];
+	}
+	dst_dcb_cfg->bcn.bcna_option[0] = src_dcb_cfg->bcn.bcna_option[0];
+	dst_dcb_cfg->bcn.bcna_option[1] = src_dcb_cfg->bcn.bcna_option[1];
+	dst_dcb_cfg->bcn.rp_alpha = src_dcb_cfg->bcn.rp_alpha;
+	dst_dcb_cfg->bcn.rp_beta = src_dcb_cfg->bcn.rp_beta;
+	dst_dcb_cfg->bcn.rp_gd = src_dcb_cfg->bcn.rp_gd;
+	dst_dcb_cfg->bcn.rp_gi = src_dcb_cfg->bcn.rp_gi;
+	dst_dcb_cfg->bcn.rp_tmax = src_dcb_cfg->bcn.rp_tmax;
+	dst_dcb_cfg->bcn.rp_td = src_dcb_cfg->bcn.rp_td;
+	dst_dcb_cfg->bcn.rp_rmin = src_dcb_cfg->bcn.rp_rmin;
+	dst_dcb_cfg->bcn.rp_w = src_dcb_cfg->bcn.rp_w;
+	dst_dcb_cfg->bcn.rp_rd = src_dcb_cfg->bcn.rp_rd;
+	dst_dcb_cfg->bcn.rp_ru = src_dcb_cfg->bcn.rp_ru;
+	dst_dcb_cfg->bcn.rp_wrtt = src_dcb_cfg->bcn.rp_wrtt;
+	dst_dcb_cfg->bcn.rp_ri = src_dcb_cfg->bcn.rp_ri;
+
+	return 0;
+}
+
+static u8 ixgbe_dcbnl_get_state(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	DPRINTK(DRV, INFO, "Get DCB Admin Mode.\n");
+
+	return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED);
+}
+
+static u16 ixgbe_dcb_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+	/* All traffic should default to class 0 */
+	return 0;
+}
+
+static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
+{
+	u8 err = 0;
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	DPRINTK(DRV, INFO, "Set DCB Admin Mode.\n");
+
+	if (state > 0) {
+		/* Turn on DCB */
+		if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
+			goto out;
+
+		if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
+			DPRINTK(DRV, ERR, "Enable failed, needs MSI-X\n");
+			err = 1;
+			goto out;
+		}
+
+		if (netif_running(netdev))
+			netdev->netdev_ops->ndo_stop(netdev);
+		ixgbe_reset_interrupt_capability(adapter);
+		ixgbe_napi_del_all(adapter);
+		INIT_LIST_HEAD(&netdev->napi_list);
+		kfree(adapter->tx_ring);
+		kfree(adapter->rx_ring);
+		adapter->tx_ring = NULL;
+		adapter->rx_ring = NULL;
+		netdev->select_queue = &ixgbe_dcb_select_queue;
+
+		adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
+		adapter->flags |= IXGBE_FLAG_DCB_ENABLED;
+		ixgbe_init_interrupt_scheme(adapter);
+		if (netif_running(netdev))
+			netdev->netdev_ops->ndo_open(netdev);
+	} else {
+		/* Turn off DCB */
+		if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+			if (netif_running(netdev))
+				netdev->netdev_ops->ndo_stop(netdev);
+			ixgbe_reset_interrupt_capability(adapter);
+			ixgbe_napi_del_all(adapter);
+			INIT_LIST_HEAD(&netdev->napi_list);
+			kfree(adapter->tx_ring);
+			kfree(adapter->rx_ring);
+			adapter->tx_ring = NULL;
+			adapter->rx_ring = NULL;
+			netdev->select_queue = NULL;
+
+			adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
+			adapter->flags |= IXGBE_FLAG_RSS_ENABLED;
+			ixgbe_init_interrupt_scheme(adapter);
+			if (netif_running(netdev))
+				netdev->netdev_ops->ndo_open(netdev);
+		}
+	}
+out:
+	return err;
+}
+
+static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev,
+					 u8 *perm_addr)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	int i;
+
+	for (i = 0; i < netdev->addr_len; i++)
+		perm_addr[i] = adapter->hw.mac.perm_addr[i];
+}
+
+static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc,
+                                         u8 prio, u8 bwg_id, u8 bw_pct,
+                                         u8 up_map)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	if (prio != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type = prio;
+	if (bwg_id != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id = bwg_id;
+	if (bw_pct != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent =
+			bw_pct;
+	if (up_map != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap =
+			up_map;
+
+	if ((adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type !=
+	     adapter->dcb_cfg.tc_config[tc].path[0].prio_type) ||
+	    (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id !=
+	     adapter->dcb_cfg.tc_config[tc].path[0].bwg_id) ||
+	    (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent !=
+	     adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent) ||
+	    (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap !=
+	     adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap))
+		adapter->dcb_set_bitmap |= BIT_PG_TX;
+}
+
+static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id,
+                                          u8 bw_pct)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct;
+
+	if (adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] !=
+	    adapter->dcb_cfg.bw_percentage[0][bwg_id])
+		adapter->dcb_set_bitmap |= BIT_PG_RX;
+}
+
+static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc,
+                                         u8 prio, u8 bwg_id, u8 bw_pct,
+                                         u8 up_map)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	if (prio != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type = prio;
+	if (bwg_id != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id = bwg_id;
+	if (bw_pct != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent =
+			bw_pct;
+	if (up_map != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap =
+			up_map;
+
+	if ((adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type !=
+	     adapter->dcb_cfg.tc_config[tc].path[1].prio_type) ||
+	    (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id !=
+	     adapter->dcb_cfg.tc_config[tc].path[1].bwg_id) ||
+	    (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent !=
+	     adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent) ||
+	    (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap !=
+	     adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap))
+		adapter->dcb_set_bitmap |= BIT_PG_RX;
+}
+
+static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id,
+                                          u8 bw_pct)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct;
+
+	if (adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] !=
+	    adapter->dcb_cfg.bw_percentage[1][bwg_id])
+		adapter->dcb_set_bitmap |= BIT_PG_RX;
+}
+
+static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc,
+                                         u8 *prio, u8 *bwg_id, u8 *bw_pct,
+                                         u8 *up_map)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	*prio = adapter->dcb_cfg.tc_config[tc].path[0].prio_type;
+	*bwg_id = adapter->dcb_cfg.tc_config[tc].path[0].bwg_id;
+	*bw_pct = adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent;
+	*up_map = adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap;
+}
+
+static void ixgbe_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id,
+                                          u8 *bw_pct)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	*bw_pct = adapter->dcb_cfg.bw_percentage[0][bwg_id];
+}
+
+static void ixgbe_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int tc,
+                                         u8 *prio, u8 *bwg_id, u8 *bw_pct,
+                                         u8 *up_map)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	*prio = adapter->dcb_cfg.tc_config[tc].path[1].prio_type;
+	*bwg_id = adapter->dcb_cfg.tc_config[tc].path[1].bwg_id;
+	*bw_pct = adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent;
+	*up_map = adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap;
+}
+
+static void ixgbe_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id,
+                                          u8 *bw_pct)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	*bw_pct = adapter->dcb_cfg.bw_percentage[1][bwg_id];
+}
+
+static void ixgbe_dcbnl_set_pfc_cfg(struct net_device *netdev, int priority,
+                                    u8 setting)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc = setting;
+	if (adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc !=
+	    adapter->dcb_cfg.tc_config[priority].dcb_pfc)
+		adapter->dcb_set_bitmap |= BIT_PFC;
+}
+
+static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority,
+                                    u8 *setting)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	*setting = adapter->dcb_cfg.tc_config[priority].dcb_pfc;
+}
+
+static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	int ret;
+
+	adapter->dcb_set_bitmap &= ~BIT_BCN;	/* no set for BCN */
+	if (!adapter->dcb_set_bitmap)
+		return 1;
+
+	while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
+		msleep(1);
+
+	if (netif_running(netdev))
+		ixgbe_down(adapter);
+
+	ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg,
+				 adapter->ring_feature[RING_F_DCB].indices);
+	if (ret) {
+		clear_bit(__IXGBE_RESETTING, &adapter->state);
+		return ret;
+	}
+
+	if (netif_running(netdev))
+		ixgbe_up(adapter);
+
+	adapter->dcb_set_bitmap = 0x00;
+	clear_bit(__IXGBE_RESETTING, &adapter->state);
+	return ret;
+}
+
+static u8 ixgbe_dcbnl_getcap(struct net_device *netdev, int capid, u8 *cap)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	u8 rval = 0;
+
+	if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+		switch (capid) {
+		case DCB_CAP_ATTR_PG:
+			*cap = true;
+			break;
+		case DCB_CAP_ATTR_PFC:
+			*cap = true;
+			break;
+		case DCB_CAP_ATTR_UP2TC:
+			*cap = false;
+			break;
+		case DCB_CAP_ATTR_PG_TCS:
+			*cap = 0x80;
+			break;
+		case DCB_CAP_ATTR_PFC_TCS:
+			*cap = 0x80;
+			break;
+		case DCB_CAP_ATTR_GSP:
+			*cap = true;
+			break;
+		case DCB_CAP_ATTR_BCN:
+			*cap = false;
+			break;
+		default:
+			rval = -EINVAL;
+			break;
+		}
+	} else {
+		rval = -EINVAL;
+	}
+
+	return rval;
+}
+
+static u8 ixgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	u8 rval = 0;
+
+	if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+		switch (tcid) {
+		case DCB_NUMTCS_ATTR_PG:
+			*num = MAX_TRAFFIC_CLASS;
+			break;
+		case DCB_NUMTCS_ATTR_PFC:
+			*num = MAX_TRAFFIC_CLASS;
+			break;
+		default:
+			rval = -EINVAL;
+			break;
+		}
+	} else {
+		rval = -EINVAL;
+	}
+
+	return rval;
+}
+
+static u8 ixgbe_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num)
+{
+	return -EINVAL;
+}
+
+static u8 ixgbe_dcbnl_getpfcstate(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED);
+}
+
+static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state)
+{
+	return;
+}
+
+static void ixgbe_dcbnl_getbcnrp(struct net_device *netdev, int priority,
+				  u8 *setting)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	*setting = adapter->dcb_cfg.bcn.rp_admin_mode[priority];
+}
+
+
+static void ixgbe_dcbnl_getbcncfg(struct net_device *netdev, int enum_index,
+				  u32 *setting)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	switch (enum_index) {
+	case DCB_BCN_ATTR_BCNA_0:
+		*setting = adapter->dcb_cfg.bcn.bcna_option[0];
+		break;
+	case DCB_BCN_ATTR_BCNA_1:
+		*setting = adapter->dcb_cfg.bcn.bcna_option[1];
+		break;
+	case DCB_BCN_ATTR_ALPHA:
+		*setting = adapter->dcb_cfg.bcn.rp_alpha;
+		break;
+	case DCB_BCN_ATTR_BETA:
+		*setting = adapter->dcb_cfg.bcn.rp_beta;
+		break;
+	case DCB_BCN_ATTR_GD:
+		*setting = adapter->dcb_cfg.bcn.rp_gd;
+		break;
+	case DCB_BCN_ATTR_GI:
+		*setting = adapter->dcb_cfg.bcn.rp_gi;
+		break;
+	case DCB_BCN_ATTR_TMAX:
+		*setting = adapter->dcb_cfg.bcn.rp_tmax;
+		break;
+	case DCB_BCN_ATTR_TD:
+		*setting = adapter->dcb_cfg.bcn.rp_td;
+		break;
+	case DCB_BCN_ATTR_RMIN:
+		*setting = adapter->dcb_cfg.bcn.rp_rmin;
+		break;
+	case DCB_BCN_ATTR_W:
+		*setting = adapter->dcb_cfg.bcn.rp_w;
+		break;
+	case DCB_BCN_ATTR_RD:
+		*setting = adapter->dcb_cfg.bcn.rp_rd;
+		break;
+	case DCB_BCN_ATTR_RU:
+		*setting = adapter->dcb_cfg.bcn.rp_ru;
+		break;
+	case DCB_BCN_ATTR_WRTT:
+		*setting = adapter->dcb_cfg.bcn.rp_wrtt;
+		break;
+	case DCB_BCN_ATTR_RI:
+		*setting = adapter->dcb_cfg.bcn.rp_ri;
+		break;
+	default:
+		*setting = -1;
+	}
+}
+
+static void ixgbe_dcbnl_setbcnrp(struct net_device *netdev, int priority,
+				 u8 setting)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	adapter->temp_dcb_cfg.bcn.rp_admin_mode[priority] = setting;
+
+	if (adapter->temp_dcb_cfg.bcn.rp_admin_mode[priority] !=
+	    adapter->dcb_cfg.bcn.rp_admin_mode[priority])
+		adapter->dcb_set_bitmap |= BIT_BCN;
+}
+
+static void ixgbe_dcbnl_setbcncfg(struct net_device *netdev, int enum_index,
+				 u32 setting)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	switch (enum_index) {
+	case DCB_BCN_ATTR_BCNA_0:
+		adapter->temp_dcb_cfg.bcn.bcna_option[0] = setting;
+		if (adapter->temp_dcb_cfg.bcn.bcna_option[0] !=
+			adapter->dcb_cfg.bcn.bcna_option[0])
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_BCNA_1:
+		adapter->temp_dcb_cfg.bcn.bcna_option[1] = setting;
+		if (adapter->temp_dcb_cfg.bcn.bcna_option[1] !=
+			adapter->dcb_cfg.bcn.bcna_option[1])
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_ALPHA:
+		adapter->temp_dcb_cfg.bcn.rp_alpha = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_alpha !=
+		    adapter->dcb_cfg.bcn.rp_alpha)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_BETA:
+		adapter->temp_dcb_cfg.bcn.rp_beta = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_beta !=
+		    adapter->dcb_cfg.bcn.rp_beta)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_GD:
+		adapter->temp_dcb_cfg.bcn.rp_gd = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_gd !=
+		    adapter->dcb_cfg.bcn.rp_gd)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_GI:
+		adapter->temp_dcb_cfg.bcn.rp_gi = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_gi !=
+		    adapter->dcb_cfg.bcn.rp_gi)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_TMAX:
+		adapter->temp_dcb_cfg.bcn.rp_tmax = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_tmax !=
+		    adapter->dcb_cfg.bcn.rp_tmax)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_TD:
+		adapter->temp_dcb_cfg.bcn.rp_td = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_td !=
+		    adapter->dcb_cfg.bcn.rp_td)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_RMIN:
+		adapter->temp_dcb_cfg.bcn.rp_rmin = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_rmin !=
+		    adapter->dcb_cfg.bcn.rp_rmin)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_W:
+		adapter->temp_dcb_cfg.bcn.rp_w = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_w !=
+		    adapter->dcb_cfg.bcn.rp_w)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_RD:
+		adapter->temp_dcb_cfg.bcn.rp_rd = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_rd !=
+		    adapter->dcb_cfg.bcn.rp_rd)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_RU:
+		adapter->temp_dcb_cfg.bcn.rp_ru = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_ru !=
+		    adapter->dcb_cfg.bcn.rp_ru)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_WRTT:
+		adapter->temp_dcb_cfg.bcn.rp_wrtt = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_wrtt !=
+		    adapter->dcb_cfg.bcn.rp_wrtt)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	case DCB_BCN_ATTR_RI:
+		adapter->temp_dcb_cfg.bcn.rp_ri = setting;
+		if (adapter->temp_dcb_cfg.bcn.rp_ri !=
+		    adapter->dcb_cfg.bcn.rp_ri)
+			adapter->dcb_set_bitmap |= BIT_BCN;
+		break;
+	default:
+		break;
+	}
+}
+
+struct dcbnl_rtnl_ops dcbnl_ops = {
+	.getstate	= ixgbe_dcbnl_get_state,
+	.setstate	= ixgbe_dcbnl_set_state,
+	.getpermhwaddr	= ixgbe_dcbnl_get_perm_hw_addr,
+	.setpgtccfgtx	= ixgbe_dcbnl_set_pg_tc_cfg_tx,
+	.setpgbwgcfgtx	= ixgbe_dcbnl_set_pg_bwg_cfg_tx,
+	.setpgtccfgrx	= ixgbe_dcbnl_set_pg_tc_cfg_rx,
+	.setpgbwgcfgrx	= ixgbe_dcbnl_set_pg_bwg_cfg_rx,
+	.getpgtccfgtx	= ixgbe_dcbnl_get_pg_tc_cfg_tx,
+	.getpgbwgcfgtx	= ixgbe_dcbnl_get_pg_bwg_cfg_tx,
+	.getpgtccfgrx	= ixgbe_dcbnl_get_pg_tc_cfg_rx,
+	.getpgbwgcfgrx	= ixgbe_dcbnl_get_pg_bwg_cfg_rx,
+	.setpfccfg	= ixgbe_dcbnl_set_pfc_cfg,
+	.getpfccfg	= ixgbe_dcbnl_get_pfc_cfg,
+	.setall		= ixgbe_dcbnl_set_all,
+	.getcap		= ixgbe_dcbnl_getcap,
+	.getnumtcs	= ixgbe_dcbnl_getnumtcs,
+	.setnumtcs	= ixgbe_dcbnl_setnumtcs,
+	.getpfcstate	= ixgbe_dcbnl_getpfcstate,
+	.setpfcstate	= ixgbe_dcbnl_setpfcstate,
+	.getbcncfg      = ixgbe_dcbnl_getbcncfg,
+	.getbcnrp       = ixgbe_dcbnl_getbcnrp,
+	.setbcncfg      = ixgbe_dcbnl_setbcncfg,
+	.setbcnrp       = ixgbe_dcbnl_setbcnrp
+};
+
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 81a9c4b..67f87a7 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -94,12 +94,21 @@
 };
 
 #define IXGBE_QUEUE_STATS_LEN \
-                ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \
-                 ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \
-                 (sizeof(struct ixgbe_queue_stats) / sizeof(u64)))
-#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
+	((((struct ixgbe_adapter *)netdev_priv(netdev))->num_tx_queues + \
+	((struct ixgbe_adapter *)netdev_priv(netdev))->num_rx_queues) * \
+	(sizeof(struct ixgbe_queue_stats) / sizeof(u64)))
 #define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats)
-#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
+#define IXGBE_PB_STATS_LEN ( \
+                 (((struct ixgbe_adapter *)netdev_priv(netdev))->flags & \
+                 IXGBE_FLAG_DCB_ENABLED) ? \
+                 (sizeof(((struct ixgbe_adapter *)0)->stats.pxonrxc) + \
+                  sizeof(((struct ixgbe_adapter *)0)->stats.pxontxc) + \
+                  sizeof(((struct ixgbe_adapter *)0)->stats.pxoffrxc) + \
+                  sizeof(((struct ixgbe_adapter *)0)->stats.pxofftxc)) \
+                  / sizeof(u64) : 0)
+#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + \
+                         IXGBE_PB_STATS_LEN + \
+                         IXGBE_QUEUE_STATS_LEN)
 
 static int ixgbe_get_settings(struct net_device *netdev,
                               struct ethtool_cmd *ecmd)
@@ -149,6 +158,8 @@
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_hw *hw = &adapter->hw;
+	u32 advertised, old;
+	s32 err;
 
 	switch (hw->phy.media_type) {
 	case ixgbe_media_type_fiber:
@@ -157,6 +168,31 @@
 			return -EINVAL;
 		/* in this case we currently only support 10Gb/FULL */
 		break;
+	case ixgbe_media_type_copper:
+		/* 10000/copper and 1000/copper must autoneg
+		 * this function does not support any duplex forcing, but can
+		 * limit the advertising of the adapter to only 10000 or 1000 */
+		if (ecmd->autoneg == AUTONEG_DISABLE)
+			return -EINVAL;
+
+		old = hw->phy.autoneg_advertised;
+		advertised = 0;
+		if (ecmd->advertising & ADVERTISED_10000baseT_Full)
+			advertised |= IXGBE_LINK_SPEED_10GB_FULL;
+
+		if (ecmd->advertising & ADVERTISED_1000baseT_Full)
+			advertised |= IXGBE_LINK_SPEED_1GB_FULL;
+
+		if (old == advertised)
+			break;
+		/* this sets the link speed and restarts auto-neg */
+		err = hw->mac.ops.setup_link_speed(hw, advertised, true, true);
+		if (err) {
+			DPRINTK(PROBE, INFO,
+			        "setup link failed with code %d\n", err);
+			hw->mac.ops.setup_link_speed(hw, old, true, true);
+		}
+		break;
 	default:
 		break;
 	}
@@ -676,30 +712,15 @@
 		return 0;
 	}
 
-	if (adapter->num_tx_queues > adapter->num_rx_queues)
-		temp_ring = vmalloc(adapter->num_tx_queues *
-		                    sizeof(struct ixgbe_ring));
-	else
-		temp_ring = vmalloc(adapter->num_rx_queues *
-		                    sizeof(struct ixgbe_ring));
+	temp_ring = kcalloc(adapter->num_tx_queues,
+	                    sizeof(struct ixgbe_ring), GFP_KERNEL);
 	if (!temp_ring)
 		return -ENOMEM;
 
 	while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
 		msleep(1);
 
-	if (netif_running(netdev))
-		ixgbe_down(adapter);
-
-	/*
-	 * We can't just free everything and then setup again,
-	 * because the ISRs in MSI-X mode get passed pointers
-	 * to the tx and rx ring structs.
-	 */
 	if (new_tx_count != adapter->tx_ring->count) {
-		memcpy(temp_ring, adapter->tx_ring,
-		       adapter->num_tx_queues * sizeof(struct ixgbe_ring));
-
 		for (i = 0; i < adapter->num_tx_queues; i++) {
 			temp_ring[i].count = new_tx_count;
 			err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]);
@@ -711,21 +732,28 @@
 				}
 				goto err_setup;
 			}
+			temp_ring[i].v_idx = adapter->tx_ring[i].v_idx;
 		}
-
-		for (i = 0; i < adapter->num_tx_queues; i++)
-			ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
-
-		memcpy(adapter->tx_ring, temp_ring,
-		       adapter->num_tx_queues * sizeof(struct ixgbe_ring));
-
+		if (netif_running(netdev))
+			netdev->netdev_ops->ndo_stop(netdev);
+		ixgbe_reset_interrupt_capability(adapter);
+		ixgbe_napi_del_all(adapter);
+		INIT_LIST_HEAD(&netdev->napi_list);
+		kfree(adapter->tx_ring);
+		adapter->tx_ring = temp_ring;
+		temp_ring = NULL;
 		adapter->tx_ring_count = new_tx_count;
 	}
 
-	if (new_rx_count != adapter->rx_ring->count) {
-		memcpy(temp_ring, adapter->rx_ring,
-		       adapter->num_rx_queues * sizeof(struct ixgbe_ring));
+	temp_ring = kcalloc(adapter->num_rx_queues,
+	                    sizeof(struct ixgbe_ring), GFP_KERNEL);
+	if (!temp_ring) {
+		if (netif_running(netdev))
+			netdev->netdev_ops->ndo_open(netdev);
+		return -ENOMEM;
+	}
 
+	if (new_rx_count != adapter->rx_ring->count) {
 		for (i = 0; i < adapter->num_rx_queues; i++) {
 			temp_ring[i].count = new_rx_count;
 			err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]);
@@ -737,13 +765,16 @@
 				}
 				goto err_setup;
 			}
+			temp_ring[i].v_idx = adapter->rx_ring[i].v_idx;
 		}
-
-		for (i = 0; i < adapter->num_rx_queues; i++)
-			ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
-
-		memcpy(adapter->rx_ring, temp_ring,
-		       adapter->num_rx_queues * sizeof(struct ixgbe_ring));
+		if (netif_running(netdev))
+			netdev->netdev_ops->ndo_stop(netdev);
+		ixgbe_reset_interrupt_capability(adapter);
+		ixgbe_napi_del_all(adapter);
+		INIT_LIST_HEAD(&netdev->napi_list);
+		kfree(adapter->rx_ring);
+		adapter->rx_ring = temp_ring;
+		temp_ring = NULL;
 
 		adapter->rx_ring_count = new_rx_count;
 	}
@@ -751,8 +782,9 @@
 	/* success! */
 	err = 0;
 err_setup:
+	ixgbe_init_interrupt_scheme(adapter);
 	if (netif_running(netdev))
-		ixgbe_up(adapter);
+		netdev->netdev_ops->ndo_open(netdev);
 
 	clear_bit(__IXGBE_RESETTING, &adapter->state);
 	return err;
@@ -804,6 +836,16 @@
 			data[i + k] = queue_stat[k];
 		i += k;
 	}
+	if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+		for (j = 0; j < MAX_TX_PACKET_BUFFERS; j++) {
+			data[i++] = adapter->stats.pxontxc[j];
+			data[i++] = adapter->stats.pxofftxc[j];
+		}
+		for (j = 0; j < MAX_RX_PACKET_BUFFERS; j++) {
+			data[i++] = adapter->stats.pxonrxc[j];
+			data[i++] = adapter->stats.pxoffrxc[j];
+		}
+	}
 }
 
 static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
@@ -832,6 +874,20 @@
 			sprintf(p, "rx_queue_%u_bytes", i);
 			p += ETH_GSTRING_LEN;
 		}
+		if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+			for (i = 0; i < MAX_TX_PACKET_BUFFERS; i++) {
+				sprintf(p, "tx_pb_%u_pxon", i);
+				p += ETH_GSTRING_LEN;
+				sprintf(p, "tx_pb_%u_pxoff", i);
+				p += ETH_GSTRING_LEN;
+			}
+			for (i = 0; i < MAX_RX_PACKET_BUFFERS; i++) {
+				sprintf(p, "rx_pb_%u_pxon", i);
+				p += ETH_GSTRING_LEN;
+				sprintf(p, "rx_pb_%u_pxoff", i);
+				p += ETH_GSTRING_LEN;
+			}
+		}
 		/* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */
 		break;
 	}
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 5236f63..acef3c6 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -68,12 +68,20 @@
 	 board_82598 },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT),
 	 board_82598 },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT),
+	 board_82598 },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4),
 	 board_82598 },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT),
 	 board_82598 },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_DA_DUAL_PORT),
+	 board_82598 },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM),
+	 board_82598 },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR),
 	 board_82598 },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM),
+	 board_82598 },
 
 	/* required last entry */
 	{0, }
@@ -402,7 +410,7 @@
 
 	if (adapter->netdev->features & NETIF_F_LRO &&
 	    skb->ip_summed == CHECKSUM_UNNECESSARY) {
-		if (adapter->vlgrp && is_vlan)
+		if (adapter->vlgrp && is_vlan && (tag != 0))
 			lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb,
 			                             adapter->vlgrp, tag,
 			                             rx_desc);
@@ -411,12 +419,12 @@
 		ring->lro_used = true;
 	} else {
 		if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
-			if (adapter->vlgrp && is_vlan)
+			if (adapter->vlgrp && is_vlan && (tag != 0))
 				vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag);
 			else
 				netif_receive_skb(skb);
 		} else {
-			if (adapter->vlgrp && is_vlan)
+			if (adapter->vlgrp && is_vlan && (tag != 0))
 				vlan_hwaccel_rx(skb, adapter->vlgrp, tag);
 			else
 				netif_rx(skb);
@@ -471,7 +479,6 @@
 	union ixgbe_adv_rx_desc *rx_desc;
 	struct ixgbe_rx_buffer *bi;
 	unsigned int i;
-	unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN;
 
 	i = rx_ring->next_to_use;
 	bi = &rx_ring->rx_buffer_info[i];
@@ -500,8 +507,10 @@
 		}
 
 		if (!bi->skb) {
-			struct sk_buff *skb = netdev_alloc_skb(adapter->netdev,
-			                                       bufsz);
+			struct sk_buff *skb;
+			skb = netdev_alloc_skb(adapter->netdev,
+			                       (rx_ring->rx_buf_len +
+			                        NET_IP_ALIGN));
 
 			if (!skb) {
 				adapter->alloc_rx_buff_failed++;
@@ -516,7 +525,8 @@
 			skb_reserve(skb, NET_IP_ALIGN);
 
 			bi->skb = skb;
-			bi->dma = pci_map_single(pdev, skb->data, bufsz,
+			bi->dma = pci_map_single(pdev, skb->data,
+			                         rx_ring->rx_buf_len,
 			                         PCI_DMA_FROMDEVICE);
 		}
 		/* Refresh the desc even if buffer_addrs didn't change because
@@ -607,7 +617,7 @@
 
 		if (len && !skb_shinfo(skb)->nr_frags) {
 			pci_unmap_single(pdev, rx_buffer_info->dma,
-			                 rx_ring->rx_buf_len + NET_IP_ALIGN,
+			                 rx_ring->rx_buf_len,
 			                 PCI_DMA_FROMDEVICE);
 			skb_put(skb, len);
 		}
@@ -666,7 +676,6 @@
 
 		skb->protocol = eth_type_trans(skb, adapter->netdev);
 		ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc);
-		adapter->netdev->last_rx = jiffies;
 
 next_desc:
 		rx_desc->wb.upper.status_error = 0;
@@ -904,6 +913,17 @@
 	return;
 }
 
+static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+
+	if ((adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) &&
+	    (eicr & IXGBE_EICR_GPI_SDP1)) {
+		DPRINTK(PROBE, CRIT, "Fan has stopped, replace the adapter\n");
+		/* write to clear the interrupt */
+		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
+	}
+}
 
 static void ixgbe_check_lsc(struct ixgbe_adapter *adapter)
 {
@@ -928,6 +948,8 @@
 	if (eicr & IXGBE_EICR_LSC)
 		ixgbe_check_lsc(adapter);
 
+	ixgbe_check_fan_failure(adapter, eicr);
+
 	if (!test_bit(__IXGBE_DOWN, &adapter->state))
 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
 
@@ -990,7 +1012,7 @@
 	rx_ring = &(adapter->rx_ring[r_idx]);
 	/* disable interrupts on this vector only */
 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx);
-	netif_rx_schedule(adapter->netdev, &q_vector->napi);
+	netif_rx_schedule(&q_vector->napi);
 
 	return IRQ_HANDLED;
 }
@@ -1031,7 +1053,7 @@
 
 	/* If all Rx work done, exit the polling mode */
 	if (work_done < budget) {
-		netif_rx_complete(adapter->netdev, napi);
+		netif_rx_complete(napi);
 		if (adapter->itr_setting & 3)
 			ixgbe_set_itr_msix(q_vector);
 		if (!test_bit(__IXGBE_DOWN, &adapter->state))
@@ -1080,7 +1102,7 @@
 	rx_ring = &(adapter->rx_ring[r_idx]);
 	/* If all Rx work done, exit the polling mode */
 	if (work_done < budget) {
-		netif_rx_complete(adapter->netdev, napi);
+		netif_rx_complete(napi);
 		if (adapter->itr_setting & 3)
 			ixgbe_set_itr_msix(q_vector);
 		if (!test_bit(__IXGBE_DOWN, &adapter->state))
@@ -1187,6 +1209,7 @@
 	struct net_device *netdev = adapter->netdev;
 	irqreturn_t (*handler)(int, void *);
 	int i, vector, q_vectors, err;
+	int ri=0, ti=0;
 
 	/* Decrement for Other and TCP Timer vectors */
 	q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
@@ -1201,10 +1224,19 @@
                          &ixgbe_msix_clean_many)
 	for (vector = 0; vector < q_vectors; vector++) {
 		handler = SET_HANDLER(&adapter->q_vector[vector]);
-		sprintf(adapter->name[vector], "%s:v%d-%s",
-		        netdev->name, vector,
-		        (handler == &ixgbe_msix_clean_rx) ? "Rx" :
-		         ((handler == &ixgbe_msix_clean_tx) ? "Tx" : "TxRx"));
+
+		if(handler == &ixgbe_msix_clean_rx) {
+			sprintf(adapter->name[vector], "%s-%s-%d",
+				netdev->name, "rx", ri++);
+		}
+		else if(handler == &ixgbe_msix_clean_tx) {
+			sprintf(adapter->name[vector], "%s-%s-%d",
+				netdev->name, "tx", ti++);
+		}
+		else
+			sprintf(adapter->name[vector], "%s-%s-%d",
+				netdev->name, "TxRx", vector);
+
 		err = request_irq(adapter->msix_entries[vector].vector,
 		                  handler, 0, adapter->name[vector],
 		                  &(adapter->q_vector[vector]));
@@ -1312,6 +1344,8 @@
 {
 	u32 mask;
 	mask = IXGBE_EIMS_ENABLE_MASK;
+	if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
+		mask |= IXGBE_EIMS_GPI_SDP1;
 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
 	IXGBE_WRITE_FLUSH(&adapter->hw);
 }
@@ -1342,13 +1376,15 @@
 	if (eicr & IXGBE_EICR_LSC)
 		ixgbe_check_lsc(adapter);
 
-	if (netif_rx_schedule_prep(netdev, &adapter->q_vector[0].napi)) {
+	ixgbe_check_fan_failure(adapter, eicr);
+
+	if (netif_rx_schedule_prep(&adapter->q_vector[0].napi)) {
 		adapter->tx_ring[0].total_packets = 0;
 		adapter->tx_ring[0].total_bytes = 0;
 		adapter->rx_ring[0].total_packets = 0;
 		adapter->rx_ring[0].total_bytes = 0;
 		/* would disable interrupts here but EIAM disabled it */
-		__netif_rx_schedule(netdev, &adapter->q_vector[0].napi);
+		__netif_rx_schedule(&adapter->q_vector[0].napi);
 	}
 
 	return IRQ_HANDLED;
@@ -1651,10 +1687,12 @@
 	 * effects of setting this bit are only that SRRCTL must be
 	 * fully programmed [0..15]
 	 */
-	rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
-	rdrxctl |= IXGBE_RDRXCTL_MVMEN;
-	IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
-
+	if (adapter->flags &
+	    (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_VMDQ_ENABLED)) {
+		rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+		rdrxctl |= IXGBE_RDRXCTL_MVMEN;
+		IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
+	}
 
 	if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
 		/* Fill out redirection table */
@@ -1713,6 +1751,16 @@
 		ixgbe_irq_disable(adapter);
 	adapter->vlgrp = grp;
 
+	/*
+	 * For a DCB driver, always enable VLAN tag stripping so we can
+	 * still receive traffic from a DCB-enabled host even if we're
+	 * not in DCB mode.
+	 */
+	ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
+	ctrl |= IXGBE_VLNCTRL_VME;
+	ctrl &= ~IXGBE_VLNCTRL_CFIEN;
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
+
 	if (grp) {
 		/* enable VLAN tag insert/strip */
 		ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
@@ -1877,6 +1925,44 @@
 	}
 }
 
+#ifdef CONFIG_IXGBE_DCB
+/*
+ * ixgbe_configure_dcb - Configure DCB hardware
+ * @adapter: ixgbe adapter struct
+ *
+ * This is called by the driver on open to configure the DCB hardware.
+ * This is also called by the gennetlink interface when reconfiguring
+ * the DCB state.
+ */
+static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 txdctl, vlnctrl;
+	int i, j;
+
+	ixgbe_dcb_check_config(&adapter->dcb_cfg);
+	ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_TX_CONFIG);
+	ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_RX_CONFIG);
+
+	/* reconfigure the hardware */
+	ixgbe_dcb_hw_config(&adapter->hw, &adapter->dcb_cfg);
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		j = adapter->tx_ring[i].reg_idx;
+		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
+		/* PThresh workaround for Tx hang with DFP enabled. */
+		txdctl |= 32;
+		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
+	}
+	/* Enable VLAN tag insert/strip */
+	vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+	vlnctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
+	vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
+	IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+	hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true);
+}
+
+#endif
 static void ixgbe_configure(struct ixgbe_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
@@ -1885,6 +1971,16 @@
 	ixgbe_set_rx_mode(netdev);
 
 	ixgbe_restore_vlan(adapter);
+#ifdef CONFIG_IXGBE_DCB
+	if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+		netif_set_gso_max_size(netdev, 32768);
+		ixgbe_configure_dcb(adapter);
+	} else {
+		netif_set_gso_max_size(netdev, 65536);
+	}
+#else
+	netif_set_gso_max_size(netdev, 65536);
+#endif
 
 	ixgbe_configure_tx(adapter);
 	ixgbe_configure_rx(adapter);
@@ -1924,6 +2020,13 @@
 		IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
 	}
 
+	/* Enable fan failure interrupt if media type is copper */
+	if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) {
+		gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+		gpie |= IXGBE_SDP1_GPIEN;
+		IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+	}
+
 	mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
 	if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) {
 		mhadd &= ~IXGBE_MHADD_MFS_MASK;
@@ -1961,6 +2064,8 @@
 	else
 		ixgbe_configure_msi_and_legacy(adapter);
 
+	ixgbe_napi_add_all(adapter);
+
 	clear_bit(__IXGBE_DOWN, &adapter->state);
 	ixgbe_napi_enable_all(adapter);
 
@@ -2205,7 +2310,7 @@
 
 	/* If budget not fully consumed, exit the polling mode */
 	if (work_done < budget) {
-		netif_rx_complete(adapter->netdev, napi);
+		netif_rx_complete(napi);
 		if (adapter->itr_setting & 3)
 			ixgbe_set_itr(adapter);
 		if (!test_bit(__IXGBE_DOWN, &adapter->state))
@@ -2231,6 +2336,11 @@
 	struct ixgbe_adapter *adapter;
 	adapter = container_of(work, struct ixgbe_adapter, reset_task);
 
+	/* If we're already down or resetting, just bail */
+	if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+	    test_bit(__IXGBE_RESETTING, &adapter->state))
+		return;
+
 	adapter->tx_timeout_count++;
 
 	ixgbe_reinit_locked(adapter);
@@ -2240,15 +2350,31 @@
 {
 	int nrq = 1, ntq = 1;
 	int feature_mask = 0, rss_i, rss_m;
+	int dcb_i, dcb_m;
 
 	/* Number of supported queues */
 	switch (adapter->hw.mac.type) {
 	case ixgbe_mac_82598EB:
+		dcb_i = adapter->ring_feature[RING_F_DCB].indices;
+		dcb_m = 0;
 		rss_i = adapter->ring_feature[RING_F_RSS].indices;
 		rss_m = 0;
 		feature_mask |= IXGBE_FLAG_RSS_ENABLED;
+		feature_mask |= IXGBE_FLAG_DCB_ENABLED;
 
 		switch (adapter->flags & feature_mask) {
+		case (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_DCB_ENABLED):
+			dcb_m = 0x7 << 3;
+			rss_i = min(8, rss_i);
+			rss_m = 0x7;
+			nrq = dcb_i * rss_i;
+			ntq = min(MAX_TX_QUEUES, dcb_i * rss_i);
+			break;
+		case (IXGBE_FLAG_DCB_ENABLED):
+			dcb_m = 0x7 << 3;
+			nrq = dcb_i;
+			ntq = dcb_i;
+			break;
 		case (IXGBE_FLAG_RSS_ENABLED):
 			rss_m = 0xF;
 			nrq = rss_i;
@@ -2256,6 +2382,8 @@
 			break;
 		case 0:
 		default:
+			dcb_i = 0;
+			dcb_m = 0;
 			rss_i = 0;
 			rss_m = 0;
 			nrq = 1;
@@ -2263,6 +2391,12 @@
 			break;
 		}
 
+		/* Sanity check, we should never have zero queues */
+		nrq = (nrq ?:1);
+		ntq = (ntq ?:1);
+
+		adapter->ring_feature[RING_F_DCB].indices = dcb_i;
+		adapter->ring_feature[RING_F_DCB].mask = dcb_m;
 		adapter->ring_feature[RING_F_RSS].indices = rss_i;
 		adapter->ring_feature[RING_F_RSS].mask = rss_m;
 		break;
@@ -2314,6 +2448,7 @@
 		adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
 		kfree(adapter->msix_entries);
 		adapter->msix_entries = NULL;
+		adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
 		adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
 		ixgbe_set_num_queues(adapter);
 	} else {
@@ -2333,15 +2468,42 @@
 {
 	int feature_mask = 0, rss_i;
 	int i, txr_idx, rxr_idx;
+	int dcb_i;
 
 	/* Number of supported queues */
 	switch (adapter->hw.mac.type) {
 	case ixgbe_mac_82598EB:
+		dcb_i = adapter->ring_feature[RING_F_DCB].indices;
 		rss_i = adapter->ring_feature[RING_F_RSS].indices;
 		txr_idx = 0;
 		rxr_idx = 0;
+		feature_mask |= IXGBE_FLAG_DCB_ENABLED;
 		feature_mask |= IXGBE_FLAG_RSS_ENABLED;
 		switch (adapter->flags & feature_mask) {
+		case (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_DCB_ENABLED):
+			for (i = 0; i < dcb_i; i++) {
+				int j;
+				/* Rx first */
+				for (j = 0; j < adapter->num_rx_queues; j++) {
+					adapter->rx_ring[rxr_idx].reg_idx =
+						i << 3 | j;
+					rxr_idx++;
+				}
+				/* Tx now */
+				for (j = 0; j < adapter->num_tx_queues; j++) {
+					adapter->tx_ring[txr_idx].reg_idx =
+						i << 2 | (j >> 1);
+					if (j & 1)
+						txr_idx++;
+				}
+			}
+		case (IXGBE_FLAG_DCB_ENABLED):
+			/* the number of queues is assumed to be symmetric */
+			for (i = 0; i < dcb_i; i++) {
+				adapter->rx_ring[i].reg_idx = i << 3;
+				adapter->tx_ring[i].reg_idx = i << 2;
+			}
+			break;
 		case (IXGBE_FLAG_RSS_ENABLED):
 			for (i = 0; i < adapter->num_rx_queues; i++)
 				adapter->rx_ring[i].reg_idx = i;
@@ -2363,8 +2525,7 @@
  * @adapter: board private structure to initialize
  *
  * We allocate one ring per queue at run-time since we don't know the
- * number of queues at compile-time.  The polling_netdev array is
- * intended for Multiqueue, but should work fine with a single queue.
+ * number of queues at compile-time.
  **/
 static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
 {
@@ -2435,6 +2596,7 @@
 	adapter->msix_entries = kcalloc(v_budget,
 	                                sizeof(struct msix_entry), GFP_KERNEL);
 	if (!adapter->msix_entries) {
+		adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
 		adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
 		ixgbe_set_num_queues(adapter);
 		kfree(adapter->tx_ring);
@@ -2475,7 +2637,7 @@
 	return err;
 }
 
-static void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter)
+void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter)
 {
 	if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
 		adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
@@ -2499,7 +2661,7 @@
  * - Hardware queue count (num_*_queues)
  *   - defined by miscellaneous hardware support/features (RSS, etc.)
  **/
-static int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter)
+int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter)
 {
 	int err;
 
@@ -2535,6 +2697,57 @@
 }
 
 /**
+ * ixgbe_sfp_timer - worker thread to find a missing module
+ * @data: pointer to our adapter struct
+ **/
+static void ixgbe_sfp_timer(unsigned long data)
+{
+	struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
+
+	/* Do the sfp_timer outside of interrupt context due to the
+	 * delays that sfp+ detection requires
+	 */
+	schedule_work(&adapter->sfp_task);
+}
+
+/**
+ * ixgbe_sfp_task - worker thread to find a missing module
+ * @work: pointer to work_struct containing our data
+ **/
+static void ixgbe_sfp_task(struct work_struct *work)
+{
+	struct ixgbe_adapter *adapter = container_of(work,
+	                                             struct ixgbe_adapter,
+	                                             sfp_task);
+	struct ixgbe_hw *hw = &adapter->hw;
+
+	if ((hw->phy.type == ixgbe_phy_nl) &&
+	    (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
+		s32 ret = hw->phy.ops.identify_sfp(hw);
+		if (ret)
+			goto reschedule;
+		ret = hw->phy.ops.reset(hw);
+		if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+			DPRINTK(PROBE, ERR, "failed to initialize because an "
+			        "unsupported SFP+ module type was detected.\n"
+			        "Reload the driver after installing a "
+			        "supported module.\n");
+			unregister_netdev(adapter->netdev);
+		} else {
+			DPRINTK(PROBE, INFO, "detected SFP+: %d\n",
+			        hw->phy.sfp_type);
+		}
+		/* don't need this routine any more */
+		clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
+	}
+	return;
+reschedule:
+	if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state))
+		mod_timer(&adapter->sfp_timer,
+		          round_jiffies(jiffies + (2 * HZ)));
+}
+
+/**
  * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter)
  * @adapter: board private structure to initialize
  *
@@ -2547,6 +2760,10 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct pci_dev *pdev = adapter->pdev;
 	unsigned int rss;
+#ifdef CONFIG_IXGBE_DCB
+	int j;
+	struct tc_configuration *tc;
+#endif
 
 	/* PCI config space info */
 
@@ -2560,6 +2777,30 @@
 	rss = min(IXGBE_MAX_RSS_INDICES, (int)num_online_cpus());
 	adapter->ring_feature[RING_F_RSS].indices = rss;
 	adapter->flags |= IXGBE_FLAG_RSS_ENABLED;
+	adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES;
+
+#ifdef CONFIG_IXGBE_DCB
+	/* Configure DCB traffic classes */
+	for (j = 0; j < MAX_TRAFFIC_CLASS; j++) {
+		tc = &adapter->dcb_cfg.tc_config[j];
+		tc->path[DCB_TX_CONFIG].bwg_id = 0;
+		tc->path[DCB_TX_CONFIG].bwg_percent = 12 + (j & 1);
+		tc->path[DCB_RX_CONFIG].bwg_id = 0;
+		tc->path[DCB_RX_CONFIG].bwg_percent = 12 + (j & 1);
+		tc->dcb_pfc = pfc_disabled;
+	}
+	adapter->dcb_cfg.bw_percentage[DCB_TX_CONFIG][0] = 100;
+	adapter->dcb_cfg.bw_percentage[DCB_RX_CONFIG][0] = 100;
+	adapter->dcb_cfg.rx_pba_cfg = pba_equal;
+	adapter->dcb_cfg.round_robin_enable = false;
+	adapter->dcb_set_bitmap = 0x00;
+	ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg,
+	                   adapter->ring_feature[RING_F_DCB].indices);
+
+#endif
+	if (hw->mac.ops.get_media_type &&
+	    (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper))
+		adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
 
 	/* default flow control settings */
 	hw->fc.original_type = ixgbe_fc_none;
@@ -2934,11 +3175,16 @@
  * @adapter: private struct
  * helper function to napi_add each possible q_vector->napi
  */
-static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter)
+void ixgbe_napi_add_all(struct ixgbe_adapter *adapter)
 {
 	int q_idx, q_vectors;
+	struct net_device *netdev = adapter->netdev;
 	int (*poll)(struct napi_struct *, int);
 
+	/* check if we already have our netdev->napi_list populated */
+	if (&netdev->napi_list != netdev->napi_list.next)
+		return;
+
 	if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
 		poll = &ixgbe_clean_rxonly;
 		/* Only enable as many vectors as we have rx queues. */
@@ -2955,7 +3201,7 @@
 	}
 }
 
-static void ixgbe_napi_del_all(struct ixgbe_adapter *adapter)
+void ixgbe_napi_del_all(struct ixgbe_adapter *adapter)
 {
 	int q_idx;
 	int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
@@ -3032,6 +3278,7 @@
 	}
 	ixgbe_reset_interrupt_capability(adapter);
 	ixgbe_napi_del_all(adapter);
+	INIT_LIST_HEAD(&netdev->napi_list);
 	kfree(adapter->tx_ring);
 	kfree(adapter->rx_ring);
 
@@ -3076,6 +3323,18 @@
 		adapter->stats.mpc[i] += mpc;
 		total_mpc += adapter->stats.mpc[i];
 		adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+		adapter->stats.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
+		adapter->stats.qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i));
+		adapter->stats.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
+		adapter->stats.qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i));
+		adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw,
+		                                            IXGBE_PXONRXC(i));
+		adapter->stats.pxontxc[i] += IXGBE_READ_REG(hw,
+		                                            IXGBE_PXONTXC(i));
+		adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw,
+		                                            IXGBE_PXOFFRXC(i));
+		adapter->stats.pxofftxc[i] += IXGBE_READ_REG(hw,
+		                                            IXGBE_PXOFFTXC(i));
 	}
 	adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
 	/* work around hardware counting issue */
@@ -3204,15 +3463,16 @@
 			u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
 #define FLOW_RX (frctl & IXGBE_FCTRL_RFCE)
 #define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X)
-			DPRINTK(LINK, INFO, "NIC Link is Up %s, "
-			        "Flow Control: %s\n",
-			        (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
-			         "10 Gbps" :
-			         (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
-			          "1 Gbps" : "unknown speed")),
-			        ((FLOW_RX && FLOW_TX) ? "RX/TX" :
-			         (FLOW_RX ? "RX" :
-			         (FLOW_TX ? "TX" : "None"))));
+			printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, "
+			       "Flow Control: %s\n",
+			       netdev->name,
+			       (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
+			        "10 Gbps" :
+			        (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
+			         "1 Gbps" : "unknown speed")),
+			       ((FLOW_RX && FLOW_TX) ? "RX/TX" :
+			        (FLOW_RX ? "RX" :
+			        (FLOW_TX ? "TX" : "None"))));
 
 			netif_carrier_on(netdev);
 			netif_tx_wake_all_queues(netdev);
@@ -3224,7 +3484,8 @@
 		adapter->link_up = false;
 		adapter->link_speed = 0;
 		if (netif_carrier_ok(netdev)) {
-			DPRINTK(LINK, INFO, "NIC Link is Down\n");
+			printk(KERN_INFO "ixgbe: %s NIC Link is Down\n",
+			       netdev->name);
 			netif_carrier_off(netdev);
 			netif_tx_stop_all_queues(netdev);
 		}
@@ -3573,6 +3834,14 @@
 
 	if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
 		tx_flags |= vlan_tx_tag_get(skb);
+		if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+			tx_flags &= ~IXGBE_TX_FLAGS_VLAN_PRIO_MASK;
+			tx_flags |= (skb->queue_mapping << 13);
+		}
+		tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
+		tx_flags |= IXGBE_TX_FLAGS_VLAN;
+	} else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+		tx_flags |= (skb->queue_mapping << 13);
 		tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
 		tx_flags |= IXGBE_TX_FLAGS_VLAN;
 	}
@@ -3687,9 +3956,31 @@
 	/* must always autoneg for both 1G and 10G link */
 	hw->mac.autoneg = true;
 
+	if ((hw->mac.type == ixgbe_mac_82598EB) &&
+	    (hw->phy.media_type == ixgbe_media_type_copper))
+		autoneg = IXGBE_LINK_SPEED_82598_AUTONEG;
+
 	return hw->mac.ops.setup_link_speed(hw, autoneg, true, true);
 }
 
+static const struct net_device_ops ixgbe_netdev_ops = {
+	.ndo_open 		= ixgbe_open,
+	.ndo_stop		= ixgbe_close,
+	.ndo_start_xmit		= ixgbe_xmit_frame,
+	.ndo_get_stats		= ixgbe_get_stats,
+	.ndo_set_multicast_list	= ixgbe_set_rx_mode,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= ixgbe_set_mac,
+	.ndo_change_mtu		= ixgbe_change_mtu,
+	.ndo_tx_timeout		= ixgbe_tx_timeout,
+	.ndo_vlan_rx_register	= ixgbe_vlan_rx_register,
+	.ndo_vlan_rx_add_vid	= ixgbe_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= ixgbe_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= ixgbe_netpoll,
+#endif
+};
+
 /**
  * ixgbe_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -3739,6 +4030,13 @@
 		goto err_pci_reg;
 	}
 
+	err = pci_enable_pcie_error_reporting(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed "
+		                    "0x%x\n", err);
+		/* non-fatal, continue */
+	}
+
 	pci_set_master(pdev);
 	pci_save_state(pdev);
 
@@ -3771,23 +4069,9 @@
 			continue;
 	}
 
-	netdev->open = &ixgbe_open;
-	netdev->stop = &ixgbe_close;
-	netdev->hard_start_xmit = &ixgbe_xmit_frame;
-	netdev->get_stats = &ixgbe_get_stats;
-	netdev->set_rx_mode = &ixgbe_set_rx_mode;
-	netdev->set_multicast_list = &ixgbe_set_rx_mode;
-	netdev->set_mac_address = &ixgbe_set_mac;
-	netdev->change_mtu = &ixgbe_change_mtu;
+	netdev->netdev_ops = &ixgbe_netdev_ops;
 	ixgbe_set_ethtool_ops(netdev);
-	netdev->tx_timeout = &ixgbe_tx_timeout;
 	netdev->watchdog_timeo = 5 * HZ;
-	netdev->vlan_rx_register = ixgbe_vlan_rx_register;
-	netdev->vlan_rx_add_vid = ixgbe_vlan_rx_add_vid;
-	netdev->vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	netdev->poll_controller = ixgbe_netpoll;
-#endif
 	strcpy(netdev->name, pci_name(pdev));
 
 	adapter->bd_number = cards_found;
@@ -3805,11 +4089,31 @@
 
 	/* PHY */
 	memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops));
-	/* phy->sfp_type = ixgbe_sfp_type_unknown; */
+	hw->phy.sfp_type = ixgbe_sfp_type_unknown;
+
+	/* set up this timer and work struct before calling get_invariants
+	 * which might start the timer
+	 */
+	init_timer(&adapter->sfp_timer);
+	adapter->sfp_timer.function = &ixgbe_sfp_timer;
+	adapter->sfp_timer.data = (unsigned long) adapter;
+
+	INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task);
 
 	err = ii->get_invariants(hw);
-	if (err)
+	if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
+		/* start a kernel thread to watch for a module to arrive */
+		set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
+		mod_timer(&adapter->sfp_timer,
+		          round_jiffies(jiffies + (2 * HZ)));
+		err = 0;
+	} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+		DPRINTK(PROBE, ERR, "failed to load because an "
+		        "unsupported SFP+ module type was detected.\n");
 		goto err_hw_init;
+	} else if (err) {
+		goto err_hw_init;
+	}
 
 	/* setup the private structure */
 	err = ixgbe_sw_init(adapter);
@@ -3839,6 +4143,13 @@
 	netdev->vlan_features |= NETIF_F_IP_CSUM;
 	netdev->vlan_features |= NETIF_F_SG;
 
+	if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
+		adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
+
+#ifdef CONFIG_IXGBE_DCB
+	netdev->dcbnl_ops = &dcbnl_ops;
+#endif
+
 	if (pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
@@ -3873,8 +4184,7 @@
 	pci_read_config_word(pdev, IXGBE_PCI_LINK_STATUS, &link_status);
 	link_speed = link_status & IXGBE_PCI_LINK_SPEED;
 	link_width = link_status & IXGBE_PCI_LINK_WIDTH;
-	dev_info(&pdev->dev, "(PCI Express:%s:%s) "
-	         "%02x:%02x:%02x:%02x:%02x:%02x\n",
+	dev_info(&pdev->dev, "(PCI Express:%s:%s) %pM\n",
 	        ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" :
 	         (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" :
 	         "Unknown"),
@@ -3883,8 +4193,7 @@
 	         (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" :
 	         (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" :
 	         "Unknown"),
-	        netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
-	        netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+	        netdev->dev_addr);
 	ixgbe_read_pba_num_generic(hw, &part_num);
 	dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
 	         hw->mac.type, hw->phy.type,
@@ -3911,8 +4220,6 @@
 	netif_carrier_off(netdev);
 	netif_tx_stop_all_queues(netdev);
 
-	ixgbe_napi_add_all(adapter);
-
 	strcpy(netdev->name, "eth%d");
 	err = register_netdev(netdev);
 	if (err)
@@ -3938,6 +4245,9 @@
 err_sw_init:
 	ixgbe_reset_interrupt_capability(adapter);
 err_eeprom:
+	clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
+	del_timer_sync(&adapter->sfp_timer);
+	cancel_work_sync(&adapter->sfp_task);
 	iounmap(hw->hw_addr);
 err_ioremap:
 	free_netdev(netdev);
@@ -3962,10 +4272,18 @@
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	int err;
 
 	set_bit(__IXGBE_DOWN, &adapter->state);
+	/* clear the module not found bit to make sure the worker won't
+	 * reschedule
+	 */
+	clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
 	del_timer_sync(&adapter->watchdog_timer);
 
+	del_timer_sync(&adapter->sfp_timer);
+	cancel_work_sync(&adapter->watchdog_task);
+	cancel_work_sync(&adapter->sfp_task);
 	flush_scheduled_work();
 
 #ifdef CONFIG_IXGBE_DCA
@@ -3976,7 +4294,8 @@
 	}
 
 #endif
-	unregister_netdev(netdev);
+	if (netdev->reg_state == NETREG_REGISTERED)
+		unregister_netdev(netdev);
 
 	ixgbe_reset_interrupt_capability(adapter);
 
@@ -3986,12 +4305,16 @@
 	pci_release_regions(pdev);
 
 	DPRINTK(PROBE, INFO, "complete\n");
-	ixgbe_napi_del_all(adapter);
 	kfree(adapter->tx_ring);
 	kfree(adapter->rx_ring);
 
 	free_netdev(netdev);
 
+	err = pci_disable_pcie_error_reporting(pdev);
+	if (err)
+		dev_err(&pdev->dev,
+		        "pci_disable_pcie_error_reporting failed 0x%x\n", err);
+
 	pci_disable_device(pdev);
 }
 
@@ -4007,7 +4330,7 @@
                                                 pci_channel_state_t state)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct ixgbe_adapter *adapter = netdev->priv;
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
 	netif_device_detach(netdev);
 
@@ -4028,22 +4351,34 @@
 static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct ixgbe_adapter *adapter = netdev->priv;
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	pci_ers_result_t result;
+	int err;
 
 	if (pci_enable_device(pdev)) {
 		DPRINTK(PROBE, ERR,
 		        "Cannot re-enable PCI device after reset.\n");
-		return PCI_ERS_RESULT_DISCONNECT;
+		result = PCI_ERS_RESULT_DISCONNECT;
+	} else {
+		pci_set_master(pdev);
+		pci_restore_state(pdev);
+
+		pci_enable_wake(pdev, PCI_D3hot, 0);
+		pci_enable_wake(pdev, PCI_D3cold, 0);
+
+		ixgbe_reset(adapter);
+
+		result = PCI_ERS_RESULT_RECOVERED;
 	}
-	pci_set_master(pdev);
-	pci_restore_state(pdev);
 
-	pci_enable_wake(pdev, PCI_D3hot, 0);
-	pci_enable_wake(pdev, PCI_D3cold, 0);
+	err = pci_cleanup_aer_uncorrect_error_status(pdev);
+	if (err) {
+		dev_err(&pdev->dev,
+		  "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n", err);
+		/* non-fatal, continue */
+	}
 
-	ixgbe_reset(adapter);
-
-	return PCI_ERS_RESULT_RECOVERED;
+	return result;
 }
 
 /**
@@ -4056,7 +4391,7 @@
 static void ixgbe_io_resume(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct ixgbe_adapter *adapter = netdev->priv;
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
 	if (netif_running(netdev)) {
 		if (ixgbe_up(adapter)) {
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
index 764035a..5a8669a 100644
--- a/drivers/net/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -121,9 +121,15 @@
 	enum ixgbe_phy_type phy_type;
 
 	switch (phy_id) {
+	case TN1010_PHY_ID:
+		phy_type = ixgbe_phy_tn;
+		break;
 	case QT2022_PHY_ID:
 		phy_type = ixgbe_phy_qt;
 		break;
+	case ATH_PHY_ID:
+		phy_type = ixgbe_phy_nl;
+		break;
 	default:
 		phy_type = ixgbe_phy_unknown;
 		break;
@@ -426,3 +432,323 @@
 	return 0;
 }
 
+/**
+ *  ixgbe_reset_phy_nl - Performs a PHY reset
+ *  @hw: pointer to hardware structure
+ **/
+s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
+{
+	u16 phy_offset, control, eword, edata, block_crc;
+	bool end_data = false;
+	u16 list_offset, data_offset;
+	u16 phy_data = 0;
+	s32 ret_val = 0;
+	u32 i;
+
+	hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
+	                     IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
+
+	/* reset the PHY and poll for completion */
+	hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
+	                      IXGBE_MDIO_PHY_XS_DEV_TYPE,
+	                      (phy_data | IXGBE_MDIO_PHY_XS_RESET));
+
+	for (i = 0; i < 100; i++) {
+		hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
+		                     IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
+		if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0)
+			break;
+		msleep(10);
+	}
+
+	if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) {
+		hw_dbg(hw, "PHY reset did not complete.\n");
+		ret_val = IXGBE_ERR_PHY;
+		goto out;
+	}
+
+	/* Get init offsets */
+	ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset,
+	                                              &data_offset);
+	if (ret_val != 0)
+		goto out;
+
+	ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc);
+	data_offset++;
+	while (!end_data) {
+		/*
+		 * Read control word from PHY init contents offset
+		 */
+		ret_val = hw->eeprom.ops.read(hw, data_offset, &eword);
+		control = (eword & IXGBE_CONTROL_MASK_NL) >>
+		           IXGBE_CONTROL_SHIFT_NL;
+		edata = eword & IXGBE_DATA_MASK_NL;
+		switch (control) {
+		case IXGBE_DELAY_NL:
+			data_offset++;
+			hw_dbg(hw, "DELAY: %d MS\n", edata);
+			msleep(edata);
+			break;
+		case IXGBE_DATA_NL:
+			hw_dbg(hw, "DATA:  \n");
+			data_offset++;
+			hw->eeprom.ops.read(hw, data_offset++,
+			                    &phy_offset);
+			for (i = 0; i < edata; i++) {
+				hw->eeprom.ops.read(hw, data_offset, &eword);
+				hw->phy.ops.write_reg(hw, phy_offset,
+				                      IXGBE_TWINAX_DEV, eword);
+				hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword,
+				       phy_offset);
+				data_offset++;
+				phy_offset++;
+			}
+			break;
+		case IXGBE_CONTROL_NL:
+			data_offset++;
+			hw_dbg(hw, "CONTROL: \n");
+			if (edata == IXGBE_CONTROL_EOL_NL) {
+				hw_dbg(hw, "EOL\n");
+				end_data = true;
+			} else if (edata == IXGBE_CONTROL_SOL_NL) {
+				hw_dbg(hw, "SOL\n");
+			} else {
+				hw_dbg(hw, "Bad control value\n");
+				ret_val = IXGBE_ERR_PHY;
+				goto out;
+			}
+			break;
+		default:
+			hw_dbg(hw, "Bad control type\n");
+			ret_val = IXGBE_ERR_PHY;
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  ixgbe_identify_sfp_module_generic - Identifies SFP module and assigns
+ *                                      the PHY type.
+ *  @hw: pointer to hardware structure
+ *
+ *  Searches for and indentifies the SFP module.  Assings appropriate PHY type.
+ **/
+s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
+{
+	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
+	u32 vendor_oui = 0;
+	u8 identifier = 0;
+	u8 comp_codes_1g = 0;
+	u8 comp_codes_10g = 0;
+	u8 oui_bytes[4] = {0, 0, 0, 0};
+	u8 transmission_media = 0;
+
+	status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER,
+	                                     &identifier);
+
+	if (status == IXGBE_ERR_SFP_NOT_PRESENT) {
+		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
+		goto out;
+	}
+
+	if (identifier == IXGBE_SFF_IDENTIFIER_SFP) {
+		hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_1GBE_COMP_CODES,
+		                            &comp_codes_1g);
+		hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES,
+		                            &comp_codes_10g);
+		hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_TRANSMISSION_MEDIA,
+		                            &transmission_media);
+
+		/* ID Module
+		 * =========
+		 * 0	SFP_DA_CU
+		 * 1	SFP_SR
+		 * 2	SFP_LR
+		 */
+		if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE)
+			hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
+		else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
+			hw->phy.sfp_type = ixgbe_sfp_type_sr;
+		else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
+			hw->phy.sfp_type = ixgbe_sfp_type_lr;
+		else
+			hw->phy.sfp_type = ixgbe_sfp_type_unknown;
+
+		/* Determine PHY vendor */
+		if (hw->phy.type == ixgbe_phy_unknown) {
+			hw->phy.id = identifier;
+			hw->phy.ops.read_i2c_eeprom(hw,
+			                            IXGBE_SFF_VENDOR_OUI_BYTE0,
+			                            &oui_bytes[0]);
+			hw->phy.ops.read_i2c_eeprom(hw,
+			                            IXGBE_SFF_VENDOR_OUI_BYTE1,
+			                            &oui_bytes[1]);
+			hw->phy.ops.read_i2c_eeprom(hw,
+			                            IXGBE_SFF_VENDOR_OUI_BYTE2,
+			                            &oui_bytes[2]);
+
+			vendor_oui =
+			  ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
+			   (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
+			   (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
+
+			switch (vendor_oui) {
+			case IXGBE_SFF_VENDOR_OUI_TYCO:
+				if (transmission_media &
+				    IXGBE_SFF_TWIN_AX_CAPABLE)
+					hw->phy.type = ixgbe_phy_tw_tyco;
+				break;
+			case IXGBE_SFF_VENDOR_OUI_FTL:
+				hw->phy.type = ixgbe_phy_sfp_ftl;
+				break;
+			case IXGBE_SFF_VENDOR_OUI_AVAGO:
+				hw->phy.type = ixgbe_phy_sfp_avago;
+				break;
+			default:
+				if (transmission_media &
+				    IXGBE_SFF_TWIN_AX_CAPABLE)
+					hw->phy.type = ixgbe_phy_tw_unknown;
+				else
+					hw->phy.type = ixgbe_phy_sfp_unknown;
+				break;
+			}
+		}
+		status = 0;
+	}
+
+out:
+	return status;
+}
+
+/**
+ *  ixgbe_get_sfp_init_sequence_offsets - Checks the MAC's EEPROM to see
+ *  if it supports a given SFP+ module type, if so it returns the offsets to the
+ *  phy init sequence block.
+ *  @hw: pointer to hardware structure
+ *  @list_offset: offset to the SFP ID list
+ *  @data_offset: offset to the SFP data block
+ **/
+s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
+                                        u16 *list_offset,
+                                        u16 *data_offset)
+{
+	u16 sfp_id;
+
+	if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
+		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+
+	if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
+		return IXGBE_ERR_SFP_NOT_PRESENT;
+
+	if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) &&
+	    (hw->phy.sfp_type == ixgbe_sfp_type_da_cu))
+		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+
+	/* Read offset to PHY init contents */
+	hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset);
+
+	if ((!*list_offset) || (*list_offset == 0xFFFF))
+		return IXGBE_ERR_PHY;
+
+	/* Shift offset to first ID word */
+	(*list_offset)++;
+
+	/*
+	 * Find the matching SFP ID in the EEPROM
+	 * and program the init sequence
+	 */
+	hw->eeprom.ops.read(hw, *list_offset, &sfp_id);
+
+	while (sfp_id != IXGBE_PHY_INIT_END_NL) {
+		if (sfp_id == hw->phy.sfp_type) {
+			(*list_offset)++;
+			hw->eeprom.ops.read(hw, *list_offset, data_offset);
+			if ((!*data_offset) || (*data_offset == 0xFFFF)) {
+				hw_dbg(hw, "SFP+ module not supported\n");
+				return IXGBE_ERR_SFP_NOT_SUPPORTED;
+			} else {
+				break;
+			}
+		} else {
+			(*list_offset) += 2;
+			if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id))
+				return IXGBE_ERR_PHY;
+		}
+	}
+
+	if (sfp_id == IXGBE_PHY_INIT_END_NL) {
+		hw_dbg(hw, "No matching SFP+ module found\n");
+		return IXGBE_ERR_SFP_NOT_SUPPORTED;
+	}
+
+	return 0;
+}
+
+/**
+ *  ixgbe_check_phy_link_tnx - Determine link and speed status
+ *  @hw: pointer to hardware structure
+ *
+ *  Reads the VS1 register to determine if link is up and the current speed for
+ *  the PHY.
+ **/
+s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+                             bool *link_up)
+{
+	s32 status = 0;
+	u32 time_out;
+	u32 max_time_out = 10;
+	u16 phy_link = 0;
+	u16 phy_speed = 0;
+	u16 phy_data = 0;
+
+	/* Initialize speed and link to default case */
+	*link_up = false;
+	*speed = IXGBE_LINK_SPEED_10GB_FULL;
+
+	/*
+	 * Check current speed and link status of the PHY register.
+	 * This is a vendor specific register and may have to
+	 * be changed for other copper PHYs.
+	 */
+	for (time_out = 0; time_out < max_time_out; time_out++) {
+		udelay(10);
+		status = hw->phy.ops.read_reg(hw,
+		                        IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS,
+		                        IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+		                        &phy_data);
+		phy_link = phy_data &
+		           IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
+		phy_speed = phy_data &
+		            IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
+		if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
+			*link_up = true;
+			if (phy_speed ==
+			    IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
+				*speed = IXGBE_LINK_SPEED_1GB_FULL;
+			break;
+		}
+	}
+
+	return status;
+}
+
+/**
+ *  ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version
+ *  @hw: pointer to hardware structure
+ *  @firmware_version: pointer to the PHY Firmware Version
+ **/
+s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw,
+                                       u16 *firmware_version)
+{
+	s32 status = 0;
+
+	status = hw->phy.ops.read_reg(hw, TNX_FW_REV,
+	                              IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+	                              firmware_version);
+
+	return status;
+}
+
diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h
index 9bfe3f2..43a97bc 100644
--- a/drivers/net/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ixgbe/ixgbe_phy.h
@@ -63,6 +63,18 @@
 #define IXGBE_SFF_VENDOR_OUI_FTL      0x00906500
 #define IXGBE_SFF_VENDOR_OUI_AVAGO    0x00176A00
 
+/* I2C SDA and SCL timing parameters for standard mode */
+#define IXGBE_I2C_T_HD_STA  4
+#define IXGBE_I2C_T_LOW     5
+#define IXGBE_I2C_T_HIGH    4
+#define IXGBE_I2C_T_SU_STA  5
+#define IXGBE_I2C_T_HD_DATA 5
+#define IXGBE_I2C_T_SU_DATA 1
+#define IXGBE_I2C_T_RISE    1
+#define IXGBE_I2C_T_FALL    1
+#define IXGBE_I2C_T_SU_STO  4
+#define IXGBE_I2C_T_BUF     5
+
 
 s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw);
 s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw);
@@ -77,4 +89,17 @@
                                        bool autoneg,
                                        bool autoneg_wait_to_complete);
 
+/* PHY specific */
+s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw,
+                             ixgbe_link_speed *speed,
+                             bool *link_up);
+s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw,
+                                       u16 *firmware_version);
+
+s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw);
+s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw);
+s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
+                                        u16 *list_offset,
+                                        u16 *data_offset);
+
 #endif /* _IXGBE_PHY_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index c6f8fa1..83a11ff 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -36,8 +36,12 @@
 /* Device IDs */
 #define IXGBE_DEV_ID_82598AF_DUAL_PORT   0x10C6
 #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
+#define IXGBE_DEV_ID_82598EB_SFP_LOM     0x10DB
+#define IXGBE_DEV_ID_82598AT             0x10C8
 #define IXGBE_DEV_ID_82598EB_CX4         0x10DD
 #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC
+#define IXGBE_DEV_ID_82598_DA_DUAL_PORT  0x10F1
+#define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM      0x10E1
 #define IXGBE_DEV_ID_82598EB_XF_LR       0x10F4
 
 /* General Registers */
@@ -452,6 +456,7 @@
 #define IXGBE_MDIO_PHY_XS_DEV_TYPE                0x4
 #define IXGBE_MDIO_AUTO_NEG_DEV_TYPE              0x7
 #define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE     0x1E   /* Device 30 */
+#define IXGBE_TWINAX_DEV                          1
 
 #define IXGBE_MDIO_COMMAND_TIMEOUT     100 /* PHY Timeout for 1 GB mode */
 
@@ -487,12 +492,27 @@
 #define IXGBE_PHY_REVISION_MASK        0xFFFFFFF0
 #define IXGBE_MAX_PHY_ADDR             32
 
-/* PHY IDs*/
+/* PHY IDs */
+#define TN1010_PHY_ID    0x00A19410
+#define TNX_FW_REV       0xB
 #define QT2022_PHY_ID    0x0043A400
+#define ATH_PHY_ID       0x03429050
 
 /* PHY Types */
 #define IXGBE_M88E1145_E_PHY_ID  0x01410CD0
 
+/* Special PHY Init Routine */
+#define IXGBE_PHY_INIT_OFFSET_NL 0x002B
+#define IXGBE_PHY_INIT_END_NL    0xFFFF
+#define IXGBE_CONTROL_MASK_NL    0xF000
+#define IXGBE_DATA_MASK_NL       0x0FFF
+#define IXGBE_CONTROL_SHIFT_NL   12
+#define IXGBE_DELAY_NL           0
+#define IXGBE_DATA_NL            1
+#define IXGBE_CONTROL_NL         0x000F
+#define IXGBE_CONTROL_EOL_NL     0x0FFF
+#define IXGBE_CONTROL_SOL_NL     0x0000
+
 /* General purpose Interrupt Enable */
 #define IXGBE_SDP0_GPIEN         0x00000001 /* SDP0 */
 #define IXGBE_SDP1_GPIEN         0x00000002 /* SDP1 */
@@ -1202,8 +1222,10 @@
 
 enum ixgbe_phy_type {
 	ixgbe_phy_unknown = 0,
+	ixgbe_phy_tn,
 	ixgbe_phy_qt,
 	ixgbe_phy_xaui,
+	ixgbe_phy_nl,
 	ixgbe_phy_tw_tyco,
 	ixgbe_phy_tw_unknown,
 	ixgbe_phy_sfp_avago,
@@ -1225,6 +1247,7 @@
 	ixgbe_sfp_type_da_cu = 0,
 	ixgbe_sfp_type_sr = 1,
 	ixgbe_sfp_type_lr = 2,
+	ixgbe_sfp_type_not_present = 0xFFFE,
 	ixgbe_sfp_type_unknown = 0xFFFF
 };
 
@@ -1396,6 +1419,8 @@
 	s32 (*setup_link)(struct ixgbe_hw *);
 	s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool,
 	                        bool);
+	s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *);
+	s32 (*get_firmware_version)(struct ixgbe_hw *, u16 *);
 	s32 (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *);
 	s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8);
 	s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *);
@@ -1486,6 +1511,7 @@
 #define IXGBE_ERR_PHY_ADDR_INVALID              -17
 #define IXGBE_ERR_I2C                           -18
 #define IXGBE_ERR_SFP_NOT_SUPPORTED             -19
+#define IXGBE_ERR_SFP_NOT_PRESENT               -20
 #define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
 
 #endif /* _IXGBE_TYPE_H_ */
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index 7b70c66..0147457 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -114,8 +114,6 @@
 			skb_put(skb, desc->pkt_length);
 			skb->protocol = eth_type_trans(skb, nds[desc->channel]);
 
-			dev->last_rx = jiffies;
-
 			netif_receive_skb(skb);
 		}
 
@@ -143,7 +141,7 @@
 			break;
 	} while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff);
 
-	netif_rx_complete(dev, napi);
+	netif_rx_complete(napi);
 	ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff);
 
 	return rx;
@@ -206,7 +204,7 @@
 
 		ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff);
 		if (likely(napi_schedule_prep(&ip->napi))) {
-			__netif_rx_schedule(dev, &ip->napi);
+			__netif_rx_schedule(&ip->napi);
 		} else {
 			printk(KERN_CRIT "ixp2000: irq while polling!!\n");
 		}
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 0794482..334ff9e 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -208,7 +208,6 @@
 	struct sonic_local *lp;
 	struct resource *res;
 	int err = 0;
-	DECLARE_MAC_BUF(mac);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -233,8 +232,7 @@
 	if (err)
 		goto out1;
 
-	printk("%s: MAC %s IRQ %d\n",
-	       dev->name, print_mac(mac, dev->dev_addr), dev->irq);
+	printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq);
 
 	return 0;
 
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 665e70d..08b3405 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -435,15 +435,18 @@
 					GHC_DPX);
 		switch (phylink & PHY_LINK_SPEED_MASK) {
 		case PHY_LINK_SPEED_10M:
-			ghc |= GHC_SPEED_10M;
+			ghc |= GHC_SPEED_10M |
+				GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE;
 			strcat(linkmsg, "10 Mbps, ");
 			break;
 		case PHY_LINK_SPEED_100M:
-			ghc |= GHC_SPEED_100M;
+			ghc |= GHC_SPEED_100M |
+				GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE;
 			strcat(linkmsg, "100 Mbps, ");
 			break;
 		case PHY_LINK_SPEED_1000M:
-			ghc |= GHC_SPEED_1000M;
+			ghc |= GHC_SPEED_1000M |
+				GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY;
 			strcat(linkmsg, "1000 Mbps, ");
 			break;
 		default:
@@ -463,14 +466,6 @@
 				TXTRHD_TXREN |
 				((8 << TXTRHD_TXRL_SHIFT) & TXTRHD_TXRL));
 		}
-		strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ?
-					"Full-Duplex, " :
-					"Half-Duplex, ");
-
-		if (phylink & PHY_LINK_MDI_STAT)
-			strcat(linkmsg, "MDI-X");
-		else
-			strcat(linkmsg, "MDI");
 
 		gpreg1 = GPREG1_DEFAULT;
 		if (is_buggy250(jme->pdev->device, jme->chiprev)) {
@@ -492,11 +487,17 @@
 				break;
 			}
 		}
+
 		jwrite32(jme, JME_GPREG1, gpreg1);
-
-		jme->reg_ghc = ghc;
 		jwrite32(jme, JME_GHC, ghc);
+		jme->reg_ghc = ghc;
 
+		strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ?
+					"Full-Duplex, " :
+					"Half-Duplex, ");
+		strcat(linkmsg, (phylink & PHY_LINK_MDI_STAT) ?
+					"MDI-X" :
+					"MDI");
 		msg_link(jme, "Link is up at %s.\n", linkmsg);
 		netif_carrier_on(netdev);
 	} else {
@@ -931,7 +932,6 @@
 		    cpu_to_le16(RXWBFLAG_DEST_MUL))
 			++(NET_STAT(jme).multicast);
 
-		jme->dev->last_rx = jiffies;
 		NET_STAT(jme).rx_bytes += framesize;
 		++(NET_STAT(jme).rx_packets);
 	}
@@ -1250,7 +1250,6 @@
 jme_poll(JME_NAPI_HOLDER(holder), JME_NAPI_WEIGHT(budget))
 {
 	struct jme_adapter *jme = jme_napi_priv(holder);
-	struct net_device *netdev = jme->dev;
 	int rest;
 
 	rest = jme_process_receive(jme, JME_NAPI_WEIGHT_VAL(budget));
@@ -2591,14 +2590,6 @@
 static int
 jme_pci_dma64(struct pci_dev *pdev)
 {
-	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK))
-		if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
-			return 1;
-
-	if (!pci_set_dma_mask(pdev, DMA_40BIT_MASK))
-		if (!pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK))
-			return 1;
-
 	if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK))
 		if (!pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
 			return 0;
@@ -2626,6 +2617,18 @@
 	jme->chiprev = (chipmode & CM_CHIPREV_MASK) >> CM_CHIPREV_SHIFT;
 }
 
+static const struct net_device_ops jme_netdev_ops = {
+	.ndo_open		= jme_open,
+	.ndo_stop		= jme_close,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_start_xmit		= jme_start_xmit,
+	.ndo_set_mac_address	= jme_set_macaddr,
+	.ndo_set_multicast_list	= jme_set_multi,
+	.ndo_change_mtu		= jme_change_mtu,
+	.ndo_tx_timeout		= jme_tx_timeout,
+	.ndo_vlan_rx_register	= jme_vlan_rx_register,
+};
+
 static int __devinit
 jme_init_one(struct pci_dev *pdev,
 	     const struct pci_device_id *ent)
@@ -2675,17 +2678,9 @@
 		rc = -ENOMEM;
 		goto err_out_release_regions;
 	}
-	netdev->open			= jme_open;
-	netdev->stop			= jme_close;
-	netdev->hard_start_xmit		= jme_start_xmit;
-	netdev->set_mac_address		= jme_set_macaddr;
-	netdev->set_multicast_list	= jme_set_multi;
-	netdev->change_mtu		= jme_change_mtu;
+	netdev->netdev_ops = &jme_netdev_ops;
 	netdev->ethtool_ops		= &jme_ethtool_ops;
-	netdev->tx_timeout		= jme_tx_timeout;
 	netdev->watchdog_timeo		= TX_TIMEOUT;
-	netdev->vlan_rx_register	= jme_vlan_rx_register;
-	NETDEV_GET_STATS(netdev, &jme_get_stats);
 	netdev->features		=	NETIF_F_HW_CSUM |
 						NETIF_F_SG |
 						NETIF_F_TSO |
@@ -2861,18 +2856,10 @@
 		goto err_out_free_shadow;
 	}
 
-	msg_probe(jme,
-		"JMC250 gigabit%s ver:%x rev:%x "
-		"macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
+	msg_probe(jme, "JMC250 gigabit%s ver:%x rev:%x macaddr:%pM\n",
 		(jme->fpgaver != 0) ? " (FPGA)" : "",
 		(jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev,
-		jme->rev,
-		netdev->dev_addr[0],
-		netdev->dev_addr[1],
-		netdev->dev_addr[2],
-		netdev->dev_addr[3],
-		netdev->dev_addr[4],
-		netdev->dev_addr[5]);
+		jme->rev, netdev->dev_addr);
 
 	return 0;
 
diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index 3f5d915..5154411 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -398,15 +398,15 @@
 #define JME_NAPI_WEIGHT(w) int w
 #define JME_NAPI_WEIGHT_VAL(w) w
 #define JME_NAPI_WEIGHT_SET(w, r)
-#define JME_RX_COMPLETE(dev, napis) netif_rx_complete(dev, napis)
+#define JME_RX_COMPLETE(dev, napis) netif_rx_complete(napis)
 #define JME_NAPI_ENABLE(priv) napi_enable(&priv->napi);
 #define JME_NAPI_DISABLE(priv) \
 	if (!napi_disable_pending(&priv->napi)) \
 		napi_disable(&priv->napi);
 #define JME_RX_SCHEDULE_PREP(priv) \
-	netif_rx_schedule_prep(priv->dev, &priv->napi)
+	netif_rx_schedule_prep(&priv->napi)
 #define JME_RX_SCHEDULE(priv) \
-	__netif_rx_schedule(priv->dev, &priv->napi);
+	__netif_rx_schedule(&priv->napi);
 
 /*
  * Jmac Adapter Private data
@@ -815,16 +815,30 @@
  * Global Host Control
  */
 enum jme_ghc_bit_mask {
-	GHC_SWRST	= 0x40000000,
-	GHC_DPX		= 0x00000040,
-	GHC_SPEED	= 0x00000030,
-	GHC_LINK_POLL	= 0x00000001,
+	GHC_SWRST		= 0x40000000,
+	GHC_DPX			= 0x00000040,
+	GHC_SPEED		= 0x00000030,
+	GHC_LINK_POLL		= 0x00000001,
 };
 
 enum jme_ghc_speed_val {
-	GHC_SPEED_10M	= 0x00000010,
-	GHC_SPEED_100M	= 0x00000020,
-	GHC_SPEED_1000M	= 0x00000030,
+	GHC_SPEED_10M		= 0x00000010,
+	GHC_SPEED_100M		= 0x00000020,
+	GHC_SPEED_1000M		= 0x00000030,
+};
+
+enum jme_ghc_to_clk {
+	GHC_TO_CLK_OFF		= 0x00000000,
+	GHC_TO_CLK_GPHY		= 0x00400000,
+	GHC_TO_CLK_PCIE		= 0x00800000,
+	GHC_TO_CLK_INVALID	= 0x00C00000,
+};
+
+enum jme_ghc_txmac_clk {
+	GHC_TXMAC_CLK_OFF	= 0x00000000,
+	GHC_TXMAC_CLK_GPHY	= 0x00100000,
+	GHC_TXMAC_CLK_PCIE	= 0x00200000,
+	GHC_TXMAC_CLK_INVALID	= 0x00300000,
 };
 
 /*
diff --git a/drivers/net/korina.c b/drivers/net/korina.c
index e185763..4a5580c 100644
--- a/drivers/net/korina.c
+++ b/drivers/net/korina.c
@@ -327,7 +327,7 @@
 
 	dmas = readl(&lp->rx_dma_regs->dmas);
 	if (dmas & (DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR)) {
-		netif_rx_schedule_prep(dev, &lp->napi);
+		netif_rx_schedule_prep(&lp->napi);
 
 		dmasm = readl(&lp->rx_dma_regs->dmasm);
 		writel(dmasm | (DMA_STAT_DONE |
@@ -409,7 +409,6 @@
 
 				/* Pass the packet to upper layers */
 				netif_receive_skb(skb);
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += pkt_len;
 
@@ -467,7 +466,7 @@
 
 	work_done = korina_rx(dev, budget);
 	if (work_done < budget) {
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 
 		writel(readl(&lp->rx_dma_regs->dmasm) &
 			~(DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR),
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 977ed34..d7afb93 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -359,7 +359,7 @@
 
 static void cleanup_card(struct net_device *dev)
 {
-	struct lance_private *lp = dev->priv;
+	struct lance_private *lp = dev->ml_priv;
 	if (dev->dma != 4)
 		free_dma(dev->dma);
 	release_region(dev->base_addr, LANCE_TOTAL_SIZE);
@@ -418,7 +418,7 @@
 			if (card < NUM_CARDS) { /*Signature OK*/
 				result = lance_probe1(dev, ioaddr, 0, 0);
 				if (!result) {
-					struct lance_private *lp = dev->priv;
+					struct lance_private *lp = dev->ml_priv;
 					int ver = lp->chip_version;
 
 					r->name = chip_table[ver].name;
@@ -466,7 +466,6 @@
 	unsigned long flags;
 	int err = -ENOMEM;
 	void __iomem *bios;
-	DECLARE_MAC_BUF(mac);
 
 	/* First we look for special cases.
 	   Check for HP's on-board ethernet by looking for 'HP' in the BIOS.
@@ -520,7 +519,7 @@
 		}
 	}
 
-	/* We can't allocate dev->priv from alloc_etherdev() because it must
+	/* We can't allocate private data from alloc_etherdev() because it must
 	   a ISA DMA-able region. */
 	chipname = chip_table[lance_version].name;
 	printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr);
@@ -529,7 +528,7 @@
 	   The first six bytes are the station address. */
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(ioaddr + i);
-	printk("%s", print_mac(mac, dev->dev_addr));
+	printk("%pM", dev->dev_addr);
 
 	dev->base_addr = ioaddr;
 	/* Make certain the data structures used by the LANCE are aligned and DMAble. */
@@ -538,7 +537,7 @@
 	if(lp==NULL)
 		return -ENODEV;
 	if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
-	dev->priv = lp;
+	dev->ml_priv = lp;
 	lp->name = chipname;
 	lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE,
 						  GFP_DMA | GFP_KERNEL);
@@ -742,7 +741,7 @@
 static int
 lance_open(struct net_device *dev)
 {
-	struct lance_private *lp = dev->priv;
+	struct lance_private *lp = dev->ml_priv;
 	int ioaddr = dev->base_addr;
 	int i;
 
@@ -830,7 +829,7 @@
 static void
 lance_purge_ring(struct net_device *dev)
 {
-	struct lance_private *lp = dev->priv;
+	struct lance_private *lp = dev->ml_priv;
 	int i;
 
 	/* Free all the skbuffs in the Rx and Tx queues. */
@@ -854,7 +853,7 @@
 static void
 lance_init_ring(struct net_device *dev, gfp_t gfp)
 {
-	struct lance_private *lp = dev->priv;
+	struct lance_private *lp = dev->ml_priv;
 	int i;
 
 	lp->cur_rx = lp->cur_tx = 0;
@@ -896,7 +895,7 @@
 static void
 lance_restart(struct net_device *dev, unsigned int csr0_bits, int must_reinit)
 {
-	struct lance_private *lp = dev->priv;
+	struct lance_private *lp = dev->ml_priv;
 
 	if (must_reinit ||
 		(chip_table[lp->chip_version].flags & LANCE_MUST_REINIT_RING)) {
@@ -910,7 +909,7 @@
 
 static void lance_tx_timeout (struct net_device *dev)
 {
-	struct lance_private *lp = (struct lance_private *) dev->priv;
+	struct lance_private *lp = (struct lance_private *) dev->ml_priv;
 	int ioaddr = dev->base_addr;
 
 	outw (0, ioaddr + LANCE_ADDR);
@@ -944,7 +943,7 @@
 
 static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct lance_private *lp = dev->priv;
+	struct lance_private *lp = dev->ml_priv;
 	int ioaddr = dev->base_addr;
 	int entry;
 	unsigned long flags;
@@ -1021,7 +1020,7 @@
 	int must_restart;
 
 	ioaddr = dev->base_addr;
-	lp = dev->priv;
+	lp = dev->ml_priv;
 
 	spin_lock (&lp->devlock);
 
@@ -1134,7 +1133,7 @@
 static int
 lance_rx(struct net_device *dev)
 {
-	struct lance_private *lp = dev->priv;
+	struct lance_private *lp = dev->ml_priv;
 	int entry = lp->cur_rx & RX_RING_MOD_MASK;
 	int i;
 
@@ -1191,7 +1190,6 @@
 					pkt_len);
 				skb->protocol=eth_type_trans(skb,dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				lp->stats.rx_packets++;
 				lp->stats.rx_bytes+=pkt_len;
 			}
@@ -1213,7 +1211,7 @@
 lance_close(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
-	struct lance_private *lp = dev->priv;
+	struct lance_private *lp = dev->ml_priv;
 
 	netif_stop_queue (dev);
 
@@ -1246,7 +1244,7 @@
 
 static struct net_device_stats *lance_get_stats(struct net_device *dev)
 {
-	struct lance_private *lp = dev->priv;
+	struct lance_private *lp = dev->ml_priv;
 
 	if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) {
 		short ioaddr = dev->base_addr;
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
index b59f442..7415f51 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/lib82596.c
@@ -739,7 +739,6 @@
 				skb->len = pkt_len;
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += pkt_len;
 			}
@@ -1034,12 +1033,8 @@
 
 static void print_eth(unsigned char *add, char *str)
 {
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
-
-	printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n",
-	       add, print_mac(mac, add + 6), print_mac(mac2, add),
-	       add[12], add[13], str);
+	printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n",
+	       add, add + 6, add, add[12], add[13], str);
 }
 
 static int __devinit i82596_probe(struct net_device *dev)
@@ -1343,7 +1338,6 @@
 	struct i596_private *lp = netdev_priv(dev);
 	struct i596_dma *dma = lp->dma;
 	int config = 0, cnt;
-	DECLARE_MAC_BUF(mac);
 
 	DEB(DEB_MULTI,
 	    printk(KERN_DEBUG
@@ -1407,8 +1401,8 @@
 			if (i596_debug > 1)
 				DEB(DEB_MULTI,
 				    printk(KERN_DEBUG
-					   "%s: Adding address %s\n",
-					   dev->name, print_mac(mac, cp)));
+					   "%s: Adding address %pM\n",
+					   dev->name, cp));
 		}
 		DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
 		i596_add_cmd(dev, &cmd->cmd);
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index f80dcc1..789b6cb 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -108,14 +108,13 @@
 /* Index to functions. */
 static void ei_tx_intr(struct net_device *dev);
 static void ei_tx_err(struct net_device *dev);
-static void ei_tx_timeout(struct net_device *dev);
+void ei_tx_timeout(struct net_device *dev);
 static void ei_receive(struct net_device *dev);
 static void ei_rx_overrun(struct net_device *dev);
 
 /* Routines generic to NS8390-based boards. */
 static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
 								int start_page);
-static void set_multicast_list(struct net_device *dev);
 static void do_set_multicast_list(struct net_device *dev);
 static void __NS8390_init(struct net_device *dev, int startp);
 
@@ -206,10 +205,6 @@
 	unsigned long flags;
 	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
 
-	/* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout
-	    wrapper that does e.g. media check & then calls ei_tx_timeout. */
-	if (dev->tx_timeout == NULL)
-		 dev->tx_timeout = ei_tx_timeout;
 	if (dev->watchdog_timeo <= 0)
 		 dev->watchdog_timeo = TX_TIMEOUT;
 
@@ -258,7 +253,7 @@
  * completed (or failed) - i.e. never posted a Tx related interrupt.
  */
 
-static void ei_tx_timeout(struct net_device *dev)
+static void __ei_tx_timeout(struct net_device *dev)
 {
 	unsigned long e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
@@ -304,7 +299,7 @@
  * Sends a packet to an 8390 network device.
  */
 
-static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	unsigned long e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
@@ -764,7 +759,6 @@
 				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
 				skb->protocol=eth_type_trans(skb,dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += pkt_len;
 				if (pkt_stat & ENRSR_PHY)
@@ -883,7 +877,7 @@
  *	Collect the stats. This is called unlocked and from several contexts.
  */
 
-static struct net_device_stats *get_stats(struct net_device *dev)
+static struct net_device_stats *__ei_get_stats(struct net_device *dev)
 {
 	unsigned long ioaddr = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
@@ -992,7 +986,7 @@
  *	not called too often. Must protect against both bh and irq users
  */
 
-static void set_multicast_list(struct net_device *dev)
+static void __ei_set_multicast_list(struct net_device *dev)
 {
 	unsigned long flags;
 	struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
@@ -1016,10 +1010,6 @@
 	if (ei_debug > 1)
 		printk(version);
 
-	dev->hard_start_xmit = &ei_start_xmit;
-	dev->get_stats	= get_stats;
-	dev->set_multicast_list = &set_multicast_list;
-
 	ether_setup(dev);
 
 	spin_lock_init(&ei_local->page_lock);
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index b369890..41cbaae 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -53,9 +53,6 @@
 
 static int lne390_probe1(struct net_device *dev, int ioaddr);
 
-static int lne390_open(struct net_device *dev);
-static int lne390_close(struct net_device *dev);
-
 static void lne390_reset_8390(struct net_device *dev);
 
 static void lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
@@ -169,7 +166,6 @@
 {
 	int i, revision, ret;
 	unsigned long eisa_id;
-	DECLARE_MAC_BUF(mac);
 
 	if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV;
 
@@ -203,8 +199,8 @@
 
 	for(i = 0; i < ETHER_ADDR_LEN; i++)
 		dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i);
-	printk("lne390.c: LNE390%X in EISA slot %d, address %s.\n",
-	       0xa+revision, ioaddr/0x1000, print_mac(mac, dev->dev_addr));
+	printk("lne390.c: LNE390%X in EISA slot %d, address %pM.\n",
+	       0xa+revision, ioaddr/0x1000, dev->dev_addr);
 
 	printk("lne390.c: ");
 
@@ -279,11 +275,7 @@
 	ei_status.block_output = &lne390_block_output;
 	ei_status.get_8390_hdr = &lne390_get_8390_hdr;
 
-	dev->open = &lne390_open;
-	dev->stop = &lne390_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = ei_poll;
-#endif
+	dev->netdev_ops = &ei_netdev_ops;
 	NS8390_init(dev, 0);
 
 	ret = register_netdev(dev);
@@ -375,21 +367,6 @@
 	memcpy_toio(shmem, buf, count);
 }
 
-static int lne390_open(struct net_device *dev)
-{
-	ei_open(dev);
-	return 0;
-}
-
-static int lne390_close(struct net_device *dev)
-{
-
-	if (ei_debug > 1)
-		printk("%s: Shutting down ethercard.\n", dev->name);
-
-	ei_close(dev);
-	return 0;
-}
 
 #ifdef MODULE
 #define MAX_LNE_CARDS	4	/* Max number of LNE390 cards per module */
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index b1ac63a..b7d438a 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -76,8 +76,6 @@
 
 	skb->protocol = eth_type_trans(skb,dev);
 
-	dev->last_rx = jiffies;
-
 	/* it's OK to use per_cpu_ptr() because BHs are off */
 	pcpu_lstats = dev->ml_priv;
 	lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id());
@@ -89,7 +87,7 @@
 	return 0;
 }
 
-static struct net_device_stats *get_stats(struct net_device *dev)
+static struct net_device_stats *loopback_get_stats(struct net_device *dev)
 {
 	const struct pcpu_lstats *pcpu_lstats;
 	struct net_device_stats *stats = &dev->stats;
@@ -145,15 +143,19 @@
 	free_netdev(dev);
 }
 
+static const struct net_device_ops loopback_ops = {
+	.ndo_init      = loopback_dev_init,
+	.ndo_start_xmit= loopback_xmit,
+	.ndo_get_stats = loopback_get_stats,
+};
+
 /*
  * The loopback device is special. There is only one instance
  * per network namespace.
  */
 static void loopback_setup(struct net_device *dev)
 {
-	dev->get_stats		= &get_stats;
 	dev->mtu		= (16 * 1024) + 20 + 20 + 12;
-	dev->hard_start_xmit	= loopback_xmit;
 	dev->hard_header_len	= ETH_HLEN;	/* 14	*/
 	dev->addr_len		= ETH_ALEN;	/* 6	*/
 	dev->tx_queue_len	= 0;
@@ -167,8 +169,8 @@
 		| NETIF_F_NETNS_LOCAL;
 	dev->ethtool_ops	= &loopback_ethtool_ops;
 	dev->header_ops		= &eth_header_ops;
-	dev->init = loopback_dev_init;
-	dev->destructor = loopback_dev_free;
+	dev->netdev_ops		= &loopback_ops;
+	dev->destructor		= loopback_dev_free;
 }
 
 /* Setup and register the loopback device. */
@@ -206,17 +208,8 @@
 	unregister_netdev(dev);
 }
 
-static struct pernet_operations __net_initdata loopback_net_ops = {
+/* Registered in net/core/dev.c */
+struct pernet_operations __net_initdata loopback_net_ops = {
        .init = loopback_net_init,
        .exit = loopback_net_exit,
 };
-
-static int __init loopback_init(void)
-{
-	return register_pernet_device(&loopback_net_ops);
-}
-
-/* Loopback is special. It should be initialized before any other network
- * device and network subsystem.
- */
-fs_initcall(loopback_init);
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index 83fa9d8..4d1a059 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -390,7 +390,7 @@
 	struct i596_private *lp;
 	int boguscnt = ct;
 
-	lp = (struct i596_private *) dev->priv;
+	lp = netdev_priv(dev);
 	while (lp->scb.command) {
 		if (--boguscnt == 0) {
 			printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n",
@@ -411,7 +411,7 @@
 	int i;
 	// struct i596_rbd *rbd;
 
-	lp = (struct i596_private *) dev->priv;
+	lp = netdev_priv(dev);
 	lp->scb.pa_rfd = I596_NULL;
 
 	for (i = 0; i < num; i++) {
@@ -468,7 +468,7 @@
 	struct i596_private *lp;
 	struct i596_rfd *rfd;
 
-	lp = (struct i596_private *) dev->priv;
+	lp = netdev_priv(dev);
 	lp->rx_tail->pa_next = I596_NULL;
 
 	do {
@@ -517,7 +517,7 @@
 /* selftest or dump */
 static void
 i596_port_do(struct net_device *dev, int portcmd, char *cmdname) {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	u16 *outp;
 	int i, m;
 
@@ -541,7 +541,7 @@
 
 static int
 i596_scp_setup(struct net_device *dev) {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	int boguscnt;
 
 	/* Setup SCP, ISCP, SCB */
@@ -622,7 +622,7 @@
 	if (i596_scp_setup(dev))
 		return 1;
 
-	lp = (struct i596_private *) dev->priv;
+	lp = netdev_priv(dev);
 	lp->scb.command = 0;
 
 	memcpy ((void *)lp->i596_config, init_setup, 14);
@@ -676,7 +676,6 @@
 
 		skb->protocol = eth_type_trans(skb,dev);
 		netif_rx(skb);
-		dev->last_rx = jiffies;
 		dev->stats.rx_packets++;
 	} else {
 #if 0
@@ -705,7 +704,7 @@
 
 static int
 i596_rx(struct net_device *dev) {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	struct i596_rfd *rfd;
 	int frames = 0;
 
@@ -738,7 +737,7 @@
 	struct i596_private *lp;
 	struct i596_cmd *cmd;
 
-	lp = (struct i596_private *) dev->priv;
+	lp = netdev_priv(dev);
 	while (lp->cmd_head) {
 		cmd = (struct i596_cmd *)lp->cmd_head;
 
@@ -806,7 +805,7 @@
 }
 
 static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	unsigned long flags;
 
@@ -912,7 +911,7 @@
 
 static void
 i596_tx_timeout (struct net_device *dev) {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
 	/* Transmitter timeout, serious problems. */
@@ -970,7 +969,7 @@
 		return -EBUSY;
 	}
 
-	lp = (struct i596_private *) dev->priv;
+	lp = netdev_priv(dev);
 	spin_lock_init(&lp->cmd_lock);
 
 	/*
@@ -1147,7 +1146,7 @@
 i596_interrupt(int irq, void *dev_instance)
 {
 	struct net_device *dev = dev_instance;
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	unsigned short status, ack_cmd = 0;
 	int frames_in = 0;
 
@@ -1215,7 +1214,7 @@
 }
 
 static int i596_close(struct net_device *dev) {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 
@@ -1242,7 +1241,7 @@
 */
 
 static void set_multicast_list(struct net_device *dev) {
-	struct i596_private *lp = dev->priv;
+	struct i596_private *lp = netdev_priv(dev);
 	struct i596_cmd *cmd;
 
 	if (i596_debug > 1)
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index 98e3eb2..57716e2 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -304,7 +304,7 @@
 	if (!MACH_IS_MAC)
 		return ERR_PTR(-ENODEV);
 
-	dev = ____alloc_ei_netdev(0);
+	dev = alloc_ei_netdev();
 	if (!dev)
 		return ERR_PTR(-ENOMEM);
 
@@ -478,6 +478,20 @@
 
 #endif /* MODULE */
 
+static const struct net_device_ops mac8390_netdev_ops = {
+	.ndo_open 		= mac8390_open,
+	.ndo_stop		= mac8390_close,
+	.ndo_start_xmit		= ei_start_xmit,
+	.ndo_tx_timeout		= ei_tx_timeout,
+	.ndo_get_stats		= ei_get_stats,
+	.ndo_set_multicast_list = ei_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= ei_poll,
+#endif
+};
+
 static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
 			    enum mac8390_type type)
 {
@@ -503,11 +517,7 @@
 	int access_bitmode = 0;
 
 	/* Now fill in our stuff */
-	dev->open = &mac8390_open;
-	dev->stop = &mac8390_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = __ei_poll;
-#endif
+	dev->netdev_ops = &mac8390_netdev_ops;
 
 	/* GAR, ei_status is actually a macro even though it looks global */
 	ei_status.name = cardname[type];
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 4ce8afd..380a1a5 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -181,7 +181,6 @@
 	unsigned long ioaddr;
 	unsigned short sig;
 	int err = -ENODEV;
-	DECLARE_MAC_BUF(mac);
 
 	if (!MACH_IS_MAC)
 		return ERR_PTR(-ENODEV);
@@ -279,8 +278,7 @@
 
 	/* print the IRQ and ethernet address. */
 
-	printk(" IRQ %d ADDR %s\n",
-	       dev->irq, print_mac(mac, dev->dev_addr));
+	printk(" IRQ %d ADDR %pM\n", dev->irq, dev->dev_addr);
 
 	dev->open		= net_open;
 	dev->stop		= net_close;
@@ -518,7 +516,6 @@
 
         skb->protocol=eth_type_trans(skb,dev);
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 	lp->stats.rx_packets++;
 	lp->stats.rx_bytes += length;
 }
@@ -628,14 +625,3 @@
 	free_netdev(dev_cs89x0);
 }
 #endif /* MODULE */
-
-/*
- * Local variables:
- *  compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -c -o mac89x0.o mac89x0.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  c-indent-level: 8
- *  tab-width: 8
- * End:
- *
- */
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 01f7a31..a04da4e 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -435,7 +435,6 @@
 
 	bp->stats.rx_packets++;
 	bp->stats.rx_bytes += len;
-	bp->dev->last_rx = jiffies;
 	dev_dbg(&bp->pdev->dev, "received skb of length %u, csum: %08x\n",
 		skb->len, skb->csum);
 	netif_receive_skb(skb);
@@ -520,7 +519,7 @@
 		 * this function was called last time, and no packets
 		 * have been received since.
 		 */
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		goto out;
 	}
 
@@ -531,13 +530,13 @@
 		dev_warn(&bp->pdev->dev,
 			 "No RX buffers complete, status = %02lx\n",
 			 (unsigned long)status);
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		goto out;
 	}
 
 	work_done = macb_rx(bp, budget);
 	if (work_done < budget)
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 
 	/*
 	 * We've done what we can to clean the buffers. Make sure we
@@ -572,7 +571,7 @@
 		}
 
 		if (status & MACB_RX_INT_FLAGS) {
-			if (netif_rx_schedule_prep(dev, &bp->napi)) {
+			if (netif_rx_schedule_prep(&bp->napi)) {
 				/*
 				 * There's no point taking any more interrupts
 				 * until we have processed the buffers
@@ -580,7 +579,7 @@
 				macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
 				dev_dbg(&bp->pdev->dev,
 					"scheduling RX softirq\n");
-				__netif_rx_schedule(dev, &bp->napi);
+				__netif_rx_schedule(&bp->napi);
 			}
 		}
 
@@ -1104,7 +1103,6 @@
 	unsigned long pclk_hz;
 	u32 config;
 	int err = -ENXIO;
-	DECLARE_MAC_BUF(mac);
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!regs) {
@@ -1223,10 +1221,8 @@
 
 	platform_set_drvdata(pdev, dev);
 
-	printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d "
-	       "(%s)\n",
-	       dev->name, dev->base_addr, dev->irq,
-	       print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d (%pM)\n",
+	       dev->name, dev->base_addr, dev->irq, dev->dev_addr);
 
 	phydev = bp->phy_dev;
 	printk(KERN_INFO "%s: attached PHY driver [%s] "
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 451acdc..feebbd9 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -101,7 +101,6 @@
 	struct mace_data *mp;
 	const unsigned char *addr;
 	int j, rev, rc = -EBUSY;
-	DECLARE_MAC_BUF(mac);
 
 	if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
 		printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n",
@@ -144,7 +143,7 @@
 	}
 	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
 
-	mp = dev->priv;
+	mp = netdev_priv(dev);
 	mp->mdev = mdev;
 	macio_set_drvdata(mdev, dev);
 
@@ -165,7 +164,7 @@
 			in_8(&mp->mace->chipid_lo);
 
 
-	mp = (struct mace_data *) dev->priv;
+	mp = netdev_priv(dev);
 	mp->maccc = ENXMT | ENRCV;
 
 	mp->tx_dma = ioremap(macio_resource_start(mdev, 1), 0x1000);
@@ -241,8 +240,8 @@
 		goto err_free_rx_irq;
 	}
 
-	printk(KERN_INFO "%s: MACE at %s, chip revision %d.%d\n",
-	       dev->name, print_mac(mac, dev->dev_addr),
+	printk(KERN_INFO "%s: MACE at %pM, chip revision %d.%d\n",
+	       dev->name, dev->dev_addr,
 	       mp->chipid >> 8, mp->chipid & 0xff);
 
 	return 0;
@@ -276,7 +275,7 @@
 
 	macio_set_drvdata(mdev, NULL);
 
-	mp = dev->priv;
+	mp = netdev_priv(dev);
 
 	unregister_netdev(dev);
 
@@ -312,7 +311,7 @@
 
 static void mace_reset(struct net_device *dev)
 {
-    struct mace_data *mp = (struct mace_data *) dev->priv;
+    struct mace_data *mp = netdev_priv(dev);
     volatile struct mace __iomem *mb = mp->mace;
     int i;
 
@@ -367,7 +366,7 @@
 
 static void __mace_set_address(struct net_device *dev, void *addr)
 {
-    struct mace_data *mp = (struct mace_data *) dev->priv;
+    struct mace_data *mp = netdev_priv(dev);
     volatile struct mace __iomem *mb = mp->mace;
     unsigned char *p = addr;
     int i;
@@ -388,7 +387,7 @@
 
 static int mace_set_address(struct net_device *dev, void *addr)
 {
-    struct mace_data *mp = (struct mace_data *) dev->priv;
+    struct mace_data *mp = netdev_priv(dev);
     volatile struct mace __iomem *mb = mp->mace;
     unsigned long flags;
 
@@ -423,7 +422,7 @@
 
 static int mace_open(struct net_device *dev)
 {
-    struct mace_data *mp = (struct mace_data *) dev->priv;
+    struct mace_data *mp = netdev_priv(dev);
     volatile struct mace __iomem *mb = mp->mace;
     volatile struct dbdma_regs __iomem *rd = mp->rx_dma;
     volatile struct dbdma_regs __iomem *td = mp->tx_dma;
@@ -493,7 +492,7 @@
 
 static int mace_close(struct net_device *dev)
 {
-    struct mace_data *mp = (struct mace_data *) dev->priv;
+    struct mace_data *mp = netdev_priv(dev);
     volatile struct mace __iomem *mb = mp->mace;
     volatile struct dbdma_regs __iomem *rd = mp->rx_dma;
     volatile struct dbdma_regs __iomem *td = mp->tx_dma;
@@ -513,7 +512,7 @@
 
 static inline void mace_set_timeout(struct net_device *dev)
 {
-    struct mace_data *mp = (struct mace_data *) dev->priv;
+    struct mace_data *mp = netdev_priv(dev);
 
     if (mp->timeout_active)
 	del_timer(&mp->tx_timeout);
@@ -526,7 +525,7 @@
 
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
 {
-    struct mace_data *mp = (struct mace_data *) dev->priv;
+    struct mace_data *mp = netdev_priv(dev);
     volatile struct dbdma_regs __iomem *td = mp->tx_dma;
     volatile struct dbdma_cmd *cp, *np;
     unsigned long flags;
@@ -581,7 +580,7 @@
 
 static void mace_set_multicast(struct net_device *dev)
 {
-    struct mace_data *mp = (struct mace_data *) dev->priv;
+    struct mace_data *mp = netdev_priv(dev);
     volatile struct mace __iomem *mb = mp->mace;
     int i, j;
     u32 crc;
@@ -656,7 +655,7 @@
 static irqreturn_t mace_interrupt(int irq, void *dev_id)
 {
     struct net_device *dev = (struct net_device *) dev_id;
-    struct mace_data *mp = (struct mace_data *) dev->priv;
+    struct mace_data *mp = netdev_priv(dev);
     volatile struct mace __iomem *mb = mp->mace;
     volatile struct dbdma_regs __iomem *td = mp->tx_dma;
     volatile struct dbdma_cmd *cp;
@@ -802,7 +801,7 @@
 static void mace_tx_timeout(unsigned long data)
 {
     struct net_device *dev = (struct net_device *) data;
-    struct mace_data *mp = (struct mace_data *) dev->priv;
+    struct mace_data *mp = netdev_priv(dev);
     volatile struct mace __iomem *mb = mp->mace;
     volatile struct dbdma_regs __iomem *td = mp->tx_dma;
     volatile struct dbdma_regs __iomem *rd = mp->rx_dma;
@@ -873,7 +872,7 @@
 static irqreturn_t mace_rxdma_intr(int irq, void *dev_id)
 {
     struct net_device *dev = (struct net_device *) dev_id;
-    struct mace_data *mp = (struct mace_data *) dev->priv;
+    struct mace_data *mp = netdev_priv(dev);
     volatile struct dbdma_regs __iomem *rd = mp->rx_dma;
     volatile struct dbdma_cmd *cp, *np;
     int i, nb, stat, next;
@@ -929,7 +928,6 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		dev->stats.rx_bytes += skb->len;
 		netif_rx(skb);
-		dev->last_rx = jiffies;
 		mp->rx_bufs[i] = NULL;
 		++dev->stats.rx_packets;
 	    }
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 85587a66..274e99b 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -194,7 +194,6 @@
 	unsigned char checksum = 0;
 	static int found = 0;
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	if (found || macintosh_config->ether_type != MAC_ETHER_MACE)
 		return -ENODEV;
@@ -249,8 +248,8 @@
 	dev->set_multicast_list	= mace_set_multicast;
 	dev->set_mac_address	= mace_set_address;
 
-	printk(KERN_INFO "%s: 68K MACE, hardware address %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: 68K MACE, hardware address %pM\n",
+	       dev->name, dev->dev_addr);
 
 	err = register_netdev(dev);
 	if (!err)
@@ -674,7 +673,6 @@
 
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
-		dev->last_rx = jiffies;
 		dev->stats.rx_packets++;
 		dev->stats.rx_bytes += frame_length;
 	}
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index e64c208..205bb05 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -220,7 +220,6 @@
 	struct sonic_local *lp = netdev_priv(dev);
 	const int prom_addr = ONBOARD_SONIC_PROM_BASE;
 	int i;
-	DECLARE_MAC_BUF(mac);
 
 	/* On NuBus boards we can sometimes look in the ROM resources.
 	   No such luck for comm-slot/onboard. */
@@ -264,8 +263,8 @@
 		dev->dev_addr[1] = val >> 8;
 		dev->dev_addr[0] = val & 0xff;
 
-		printk(KERN_INFO "HW Address from CAM 15: %s\n",
-		       print_mac(mac, dev->dev_addr));
+		printk(KERN_INFO "HW Address from CAM 15: %pM\n",
+		       dev->dev_addr);
 	} else return 0;
 
 	if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
@@ -560,7 +559,6 @@
 	struct net_device *dev;
 	struct sonic_local *lp;
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof(struct sonic_local));
 	if (!dev)
@@ -584,8 +582,7 @@
 	if (err)
 		goto out;
 
-	printk("%s: MAC %s IRQ %d\n",
-	       dev->name, print_mac(mac, dev->dev_addr), dev->irq);
+	printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq);
 
 	return 0;
 
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 590039c..7e24b50 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -87,7 +87,6 @@
 			dev->stats.rx_bytes += skb->len + ETH_HLEN;
 			dev->stats.rx_packets++;
 			dev->stats.multicast++;
-			dev->last_rx = jiffies;
 
 			nskb->dev = dev;
 			if (!compare_ether_addr(eth->h_dest, dev->broadcast))
@@ -136,7 +135,6 @@
 
 	dev->stats.rx_bytes += skb->len + ETH_HLEN;
 	dev->stats.rx_packets++;
-	dev->last_rx = jiffies;
 
 	skb->dev = dev;
 	skb->pkt_type = PACKET_HOST;
@@ -145,7 +143,7 @@
 	return NULL;
 }
 
-static int macvlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int macvlan_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	const struct macvlan_dev *vlan = netdev_priv(dev);
 	unsigned int len = skb->len;
@@ -336,24 +334,53 @@
 	return lowerdev->ethtool_ops->get_rx_csum(lowerdev);
 }
 
+static int macvlan_ethtool_get_settings(struct net_device *dev,
+					struct ethtool_cmd *cmd)
+{
+	const struct macvlan_dev *vlan = netdev_priv(dev);
+	struct net_device *lowerdev = vlan->lowerdev;
+
+	if (!lowerdev->ethtool_ops->get_settings)
+		return -EOPNOTSUPP;
+
+	return lowerdev->ethtool_ops->get_settings(lowerdev, cmd);
+}
+
+static u32 macvlan_ethtool_get_flags(struct net_device *dev)
+{
+	const struct macvlan_dev *vlan = netdev_priv(dev);
+	struct net_device *lowerdev = vlan->lowerdev;
+
+	if (!lowerdev->ethtool_ops->get_flags)
+		return 0;
+	return lowerdev->ethtool_ops->get_flags(lowerdev);
+}
+
 static const struct ethtool_ops macvlan_ethtool_ops = {
 	.get_link		= ethtool_op_get_link,
+	.get_settings		= macvlan_ethtool_get_settings,
 	.get_rx_csum		= macvlan_ethtool_get_rx_csum,
 	.get_drvinfo		= macvlan_ethtool_get_drvinfo,
+	.get_flags		= macvlan_ethtool_get_flags,
+};
+
+static const struct net_device_ops macvlan_netdev_ops = {
+	.ndo_init		= macvlan_init,
+	.ndo_open		= macvlan_open,
+	.ndo_stop		= macvlan_stop,
+	.ndo_start_xmit		= macvlan_start_xmit,
+	.ndo_change_mtu		= macvlan_change_mtu,
+	.ndo_change_rx_flags	= macvlan_change_rx_flags,
+	.ndo_set_mac_address	= macvlan_set_mac_address,
+	.ndo_set_multicast_list	= macvlan_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
 };
 
 static void macvlan_setup(struct net_device *dev)
 {
 	ether_setup(dev);
 
-	dev->init		= macvlan_init;
-	dev->open		= macvlan_open;
-	dev->stop		= macvlan_stop;
-	dev->change_mtu		= macvlan_change_mtu;
-	dev->change_rx_flags	= macvlan_change_rx_flags;
-	dev->set_mac_address	= macvlan_set_mac_address;
-	dev->set_multicast_list	= macvlan_set_multicast_list;
-	dev->hard_start_xmit	= macvlan_hard_start_xmit;
+	dev->netdev_ops		= &macvlan_netdev_ops;
 	dev->destructor		= free_netdev;
 	dev->header_ops		= &macvlan_hard_header_ops,
 	dev->ethtool_ops	= &macvlan_ethtool_ops;
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index a1e22ed..c336a1f 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -94,10 +94,9 @@
 static inline void load_eaddr(struct net_device *dev)
 {
 	int i;
-	DECLARE_MAC_BUF(mac);
 	u64 macaddr;
 
-	DPRINTK("Loading MAC Address: %s\n", print_mac(mac, dev->dev_addr));
+	DPRINTK("Loading MAC Address: %pM\n", dev->dev_addr);
 	macaddr = 0;
 	for (i = 0; i < 6; i++)
 		macaddr |= (u64)dev->dev_addr[i] << ((5 - i) * 8);
@@ -421,7 +420,6 @@
 					skb_put(skb_c, len);
 					priv->rx_skbs[priv->rx_write] = skb;
 					skb_c->protocol = eth_type_trans(skb_c, dev);
-					dev->last_rx = jiffies;
 					dev->stats.rx_packets++;
 					dev->stats.rx_bytes += len;
 					netif_rx(skb_c);
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index b7ad282..ac57b6a 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -189,7 +189,7 @@
 
 int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
 		  struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
-		  int collapsed)
+		  unsigned vector, int collapsed)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	struct mlx4_cq_table *cq_table = &priv->cq_table;
@@ -198,6 +198,11 @@
 	u64 mtt_addr;
 	int err;
 
+	if (vector >= dev->caps.num_comp_vectors)
+		return -EINVAL;
+
+	cq->vector = vector;
+
 	cq->cqn = mlx4_bitmap_alloc(&cq_table->bitmap);
 	if (cq->cqn == -1)
 		return -ENOMEM;
@@ -227,7 +232,7 @@
 
 	cq_context->flags	    = cpu_to_be32(!!collapsed << 18);
 	cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index);
-	cq_context->comp_eqn        = priv->eq_table.eq[MLX4_EQ_COMP].eqn;
+	cq_context->comp_eqn	    = priv->eq_table.eq[vector].eqn;
 	cq_context->log_page_size   = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
 
 	mtt_addr = mlx4_mtt_addr(dev, mtt);
@@ -276,7 +281,7 @@
 	if (err)
 		mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn);
 
-	synchronize_irq(priv->eq_table.eq[MLX4_EQ_COMP].irq);
+	synchronize_irq(priv->eq_table.eq[cq->vector].irq);
 
 	spin_lock_irq(&cq_table->lock);
 	radix_tree_delete(&cq_table->tree, cq->cqn);
diff --git a/drivers/net/mlx4/en_cq.c b/drivers/net/mlx4/en_cq.c
index 1368a80..91f50de 100644
--- a/drivers/net/mlx4/en_cq.c
+++ b/drivers/net/mlx4/en_cq.c
@@ -51,10 +51,13 @@
 	int err;
 
 	cq->size = entries;
-	if (mode == RX)
+	if (mode == RX) {
 		cq->buf_size = cq->size * sizeof(struct mlx4_cqe);
-	else
+		cq->vector   = ring % mdev->dev->caps.num_comp_vectors;
+	} else {
 		cq->buf_size = sizeof(struct mlx4_cqe);
+		cq->vector   = 0;
+	}
 
 	cq->ring = ring;
 	cq->is_tx = mode;
@@ -68,6 +71,8 @@
 	err = mlx4_en_map_buffer(&cq->wqres.buf);
 	if (err)
 		mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size);
+	else
+		cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf;
 
 	return err;
 }
@@ -82,11 +87,10 @@
 	cq->mcq.arm_db     = cq->wqres.db.db + 1;
 	*cq->mcq.set_ci_db = 0;
 	*cq->mcq.arm_db    = 0;
-	cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf;
 	memset(cq->buf, 0, cq->buf_size);
 
 	err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar,
-			    cq->wqres.db.dma, &cq->mcq, cq->is_tx);
+			    cq->wqres.db.dma, &cq->mcq, cq->vector, cq->is_tx);
 	if (err)
 		return err;
 
@@ -136,7 +140,6 @@
 
 int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
 {
-	cq->armed = 1;
 	mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map,
 		    &priv->mdev->uar_lock);
 
diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c
index 4b9794e..c1c05852 100644
--- a/drivers/net/mlx4/en_main.c
+++ b/drivers/net/mlx4/en_main.c
@@ -170,9 +170,9 @@
 		mlx4_info(mdev, "Using %d tx rings for port:%d\n",
 			  mdev->profile.prof[i].tx_ring_num, i);
 		if (!mdev->profile.prof[i].rx_ring_num) {
-			mdev->profile.prof[i].rx_ring_num = 1;
+			mdev->profile.prof[i].rx_ring_num = dev->caps.num_comp_vectors;
 			mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n",
-				  1, i);
+				  mdev->profile.prof[i].rx_ring_num, i);
 		} else
 			mlx4_info(mdev, "Using %d rx rings for port:%d\n",
 				  mdev->profile.prof[i].rx_ring_num, i);
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 96e709d..ebada3c 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -369,7 +369,6 @@
 
 static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
 {
-	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_en_cq *cq;
 	int i;
 
@@ -379,15 +378,8 @@
 	 *   satisfy our coelsing target.
 	 * - moder_time is set to a fixed value.
 	 */
-	priv->rx_frames = (mdev->profile.rx_moder_cnt ==
-			   MLX4_EN_AUTO_CONF) ?
-				MLX4_EN_RX_COAL_TARGET /
-				priv->dev->mtu + 1 :
-				mdev->profile.rx_moder_cnt;
-	priv->rx_usecs = (mdev->profile.rx_moder_time ==
-			  MLX4_EN_AUTO_CONF) ?
-				MLX4_EN_RX_COAL_TIME :
-				mdev->profile.rx_moder_time;
+	priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->mtu + 1;
+	priv->rx_usecs = MLX4_EN_RX_COAL_TIME;
 	mlx4_dbg(INTR, priv, "Default coalesing params for mtu:%d - "
 			     "rx_frames:%d rx_usecs:%d\n",
 		 priv->dev->mtu, priv->rx_frames, priv->rx_usecs);
@@ -411,7 +403,7 @@
 	priv->pkt_rate_high = MLX4_EN_RX_RATE_HIGH;
 	priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH;
 	priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL;
-	priv->adaptive_rx_coal = mdev->profile.auto_moder;
+	priv->adaptive_rx_coal = 1;
 	priv->last_moder_time = MLX4_EN_AUTO_CONF;
 	priv->last_moder_jiffies = 0;
 	priv->last_moder_packets = 0;
@@ -953,6 +945,23 @@
 	return 0;
 }
 
+static const struct net_device_ops mlx4_netdev_ops = {
+	.ndo_open		= mlx4_en_open,
+	.ndo_stop		= mlx4_en_close,
+	.ndo_start_xmit		= mlx4_en_xmit,
+	.ndo_get_stats		= mlx4_en_get_stats,
+	.ndo_set_multicast_list	= mlx4_en_set_multicast,
+	.ndo_set_mac_address	= mlx4_en_set_mac,
+	.ndo_change_mtu		= mlx4_en_change_mtu,
+	.ndo_tx_timeout		= mlx4_en_tx_timeout,
+	.ndo_vlan_rx_register	= mlx4_en_vlan_rx_register,
+	.ndo_vlan_rx_add_vid	= mlx4_en_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= mlx4_en_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= mlx4_en_netpoll,
+#endif
+};
+
 int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 			struct mlx4_en_port_profile *prof)
 {
@@ -1029,22 +1038,9 @@
 	/*
 	 * Initialize netdev entry points
 	 */
-
-	dev->open = &mlx4_en_open;
-	dev->stop = &mlx4_en_close;
-	dev->hard_start_xmit = &mlx4_en_xmit;
-	dev->get_stats = &mlx4_en_get_stats;
-	dev->set_multicast_list = &mlx4_en_set_multicast;
-	dev->set_mac_address = &mlx4_en_set_mac;
-	dev->change_mtu = &mlx4_en_change_mtu;
-	dev->tx_timeout = &mlx4_en_tx_timeout;
+	dev->netdev_ops = &mlx4_netdev_ops;
 	dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT;
-	dev->vlan_rx_register = mlx4_en_vlan_rx_register;
-	dev->vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid;
-	dev->vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = mlx4_en_netpoll;
-#endif
+
 	SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops);
 
 	/* Set defualt MAC */
diff --git a/drivers/net/mlx4/en_params.c b/drivers/net/mlx4/en_params.c
index 95706ee..047b37f 100644
--- a/drivers/net/mlx4/en_params.c
+++ b/drivers/net/mlx4/en_params.c
@@ -60,24 +60,11 @@
 		 "Number of LRO sessions per ring or disabled (0)");
 
 /* Priority pausing */
-MLX4_EN_PARM_INT(pptx, MLX4_EN_DEF_TX_PAUSE,
-		 "Pause policy on TX: 0 never generate pause frames "
-		 "1 generate pause frames according to RX buffer threshold");
-MLX4_EN_PARM_INT(pprx, MLX4_EN_DEF_RX_PAUSE,
-		 "Pause policy on RX: 0 ignore received pause frames "
-		 "1 respect received pause frames");
 MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
 			   " Per priority bit mask");
 MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]."
 			   " Per priority bit mask");
 
-/* Interrupt moderation tunning */
-MLX4_EN_PARM_INT(rx_moder_cnt, MLX4_EN_AUTO_CONF,
-	       "Max coalesced descriptors for Rx interrupt moderation");
-MLX4_EN_PARM_INT(rx_moder_time, MLX4_EN_AUTO_CONF,
-	       "Timeout following last packet for Rx interrupt moderation");
-MLX4_EN_PARM_INT(auto_moder, 1, "Enable dynamic interrupt moderation");
-
 MLX4_EN_PARM_INT(rx_ring_num1, 0, "Number or Rx rings for port 1 (0 = #cores)");
 MLX4_EN_PARM_INT(rx_ring_num2, 0, "Number or Rx rings for port 2 (0 = #cores)");
 
@@ -92,16 +79,13 @@
 	struct mlx4_en_profile *params = &mdev->profile;
 	int i;
 
-	params->rx_moder_cnt = min_t(int, rx_moder_cnt, MLX4_EN_AUTO_CONF);
-	params->rx_moder_time = min_t(int, rx_moder_time, MLX4_EN_AUTO_CONF);
-	params->auto_moder = auto_moder;
 	params->rss_xor = (rss_xor != 0);
 	params->rss_mask = rss_mask & 0x1f;
 	params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS);
 	for (i = 1; i <= MLX4_MAX_PORTS; i++) {
-		params->prof[i].rx_pause = pprx;
+		params->prof[i].rx_pause = 1;
 		params->prof[i].rx_ppp = pfcrx;
-		params->prof[i].tx_pause = pptx;
+		params->prof[i].tx_pause = 1;
 		params->prof[i].tx_ppp = pfctx;
 	}
 	if (pfcrx || pfctx) {
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c
index 6232227..c61b0bd 100644
--- a/drivers/net/mlx4/en_rx.c
+++ b/drivers/net/mlx4/en_rx.c
@@ -443,7 +443,8 @@
 		/* Fill Rx buffers */
 		ring->full = 0;
 	}
-	if (mlx4_en_fill_rx_buffers(priv))
+	err = mlx4_en_fill_rx_buffers(priv);
+	if (err)
 		goto err_buffers;
 
 	for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
@@ -776,8 +777,6 @@
 		} else
 			netif_receive_skb(skb);
 
-		dev->last_rx = jiffies;
-
 next:
 		++cq->mcq.cons_index;
 		index = (cq->mcq.cons_index) & ring->size_mask;
@@ -815,7 +814,7 @@
 	struct mlx4_en_priv *priv = netdev_priv(cq->dev);
 
 	if (priv->port_up)
-		netif_rx_schedule(cq->dev, &cq->napi);
+		netif_rx_schedule(&cq->napi);
 	else
 		mlx4_en_arm_cq(priv, cq);
 }
@@ -835,7 +834,7 @@
 		INC_PERF_COUNTER(priv->pstats.napi_quota);
 	else {
 		/* Done for now */
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		mlx4_en_arm_cq(priv, cq);
 	}
 	return done;
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c
index 8592f8f..ff4d752 100644
--- a/drivers/net/mlx4/en_tx.c
+++ b/drivers/net/mlx4/en_tx.c
@@ -379,8 +379,8 @@
 
 	/* Wakeup Tx queue if this ring stopped it */
 	if (unlikely(ring->blocked)) {
-		if (((u32) (ring->prod - ring->cons) <=
-		     ring->size - HEADROOM - MAX_DESC_TXBBS) && !cq->armed) {
+		if ((u32) (ring->prod - ring->cons) <=
+		     ring->size - HEADROOM - MAX_DESC_TXBBS) {
 
 			/* TODO: support multiqueue netdevs. Currently, we block
 			 * when *any* ring is full. Note that:
@@ -404,14 +404,11 @@
 	struct mlx4_en_priv *priv = netdev_priv(cq->dev);
 	struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring];
 
-	spin_lock_irq(&ring->comp_lock);
-	cq->armed = 0;
+	if (!spin_trylock(&ring->comp_lock))
+		return;
 	mlx4_en_process_tx_cq(cq->dev, cq);
-	if (ring->blocked)
-		mlx4_en_arm_cq(priv, cq);
-	else
-		mod_timer(&cq->timer, jiffies + 1);
-	spin_unlock_irq(&ring->comp_lock);
+	mod_timer(&cq->timer, jiffies + 1);
+	spin_unlock(&ring->comp_lock);
 }
 
 
@@ -424,8 +421,10 @@
 
 	INC_PERF_COUNTER(priv->pstats.tx_poll);
 
-	netif_tx_lock(priv->dev);
-	spin_lock_irq(&ring->comp_lock);
+	if (!spin_trylock(&ring->comp_lock)) {
+		mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT);
+		return;
+	}
 	mlx4_en_process_tx_cq(cq->dev, cq);
 	inflight = (u32) (ring->prod - ring->cons - ring->last_nr_txbb);
 
@@ -435,8 +434,7 @@
 	if (inflight && priv->port_up)
 		mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT);
 
-	spin_unlock_irq(&ring->comp_lock);
-	netif_tx_unlock(priv->dev);
+	spin_unlock(&ring->comp_lock);
 }
 
 static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv,
@@ -479,7 +477,10 @@
 
 	/* Poll the CQ every mlx4_en_TX_MODER_POLL packets */
 	if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0)
-		mlx4_en_process_tx_cq(priv->dev, cq);
+		if (spin_trylock(&ring->comp_lock)) {
+			mlx4_en_process_tx_cq(priv->dev, cq);
+			spin_unlock(&ring->comp_lock);
+		}
 }
 
 static void *get_frag_ptr(struct sk_buff *skb)
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index de16933..2c19bff7c 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -243,10 +243,6 @@
 		 * least that often.
 		 */
 		if (unlikely(set_ci >= MLX4_NUM_SPARE_EQE)) {
-			/*
-			 * Conditional on hca_type is OK here because
-			 * this is a rare case, not the fast path.
-			 */
 			eq_set_ci(eq, 0);
 			set_ci = 0;
 		}
@@ -266,7 +262,7 @@
 
 	writel(priv->eq_table.clr_mask, priv->eq_table.clr_int);
 
-	for (i = 0; i < MLX4_NUM_EQ; ++i)
+	for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
 		work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]);
 
 	return IRQ_RETVAL(work);
@@ -304,6 +300,17 @@
 			    MLX4_CMD_TIME_CLASS_A);
 }
 
+static int mlx4_num_eq_uar(struct mlx4_dev *dev)
+{
+	/*
+	 * Each UAR holds 4 EQ doorbells.  To figure out how many UARs
+	 * we need to map, take the difference of highest index and
+	 * the lowest index we'll use and add 1.
+	 */
+	return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs) / 4 -
+		dev->caps.reserved_eqs / 4 + 1;
+}
+
 static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
@@ -483,9 +490,11 @@
 
 	if (eq_table->have_irq)
 		free_irq(dev->pdev->irq, dev);
-	for (i = 0; i < MLX4_NUM_EQ; ++i)
+	for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
 		if (eq_table->eq[i].have_irq)
 			free_irq(eq_table->eq[i].irq, eq_table->eq + i);
+
+	kfree(eq_table->irq_names);
 }
 
 static int mlx4_map_clr_int(struct mlx4_dev *dev)
@@ -551,57 +560,93 @@
 	__free_page(priv->eq_table.icm_page);
 }
 
+int mlx4_alloc_eq_table(struct mlx4_dev *dev)
+{
+	struct mlx4_priv *priv = mlx4_priv(dev);
+
+	priv->eq_table.eq = kcalloc(dev->caps.num_eqs - dev->caps.reserved_eqs,
+				    sizeof *priv->eq_table.eq, GFP_KERNEL);
+	if (!priv->eq_table.eq)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void mlx4_free_eq_table(struct mlx4_dev *dev)
+{
+	kfree(mlx4_priv(dev)->eq_table.eq);
+}
+
 int mlx4_init_eq_table(struct mlx4_dev *dev)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	int err;
 	int i;
 
+	priv->eq_table.uar_map = kcalloc(sizeof *priv->eq_table.uar_map,
+					 mlx4_num_eq_uar(dev), GFP_KERNEL);
+	if (!priv->eq_table.uar_map) {
+		err = -ENOMEM;
+		goto err_out_free;
+	}
+
 	err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs,
 			       dev->caps.num_eqs - 1, dev->caps.reserved_eqs, 0);
 	if (err)
-		return err;
+		goto err_out_free;
 
-	for (i = 0; i < ARRAY_SIZE(priv->eq_table.uar_map); ++i)
+	for (i = 0; i < mlx4_num_eq_uar(dev); ++i)
 		priv->eq_table.uar_map[i] = NULL;
 
 	err = mlx4_map_clr_int(dev);
 	if (err)
-		goto err_out_free;
+		goto err_out_bitmap;
 
 	priv->eq_table.clr_mask =
 		swab32(1 << (priv->eq_table.inta_pin & 31));
 	priv->eq_table.clr_int  = priv->clr_base +
 		(priv->eq_table.inta_pin < 32 ? 4 : 0);
 
-	err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE,
-			     (dev->flags & MLX4_FLAG_MSI_X) ? MLX4_EQ_COMP : 0,
-			     &priv->eq_table.eq[MLX4_EQ_COMP]);
-	if (err)
-		goto err_out_unmap;
+	priv->eq_table.irq_names = kmalloc(16 * dev->caps.num_comp_vectors, GFP_KERNEL);
+	if (!priv->eq_table.irq_names) {
+		err = -ENOMEM;
+		goto err_out_bitmap;
+	}
+
+	for (i = 0; i < dev->caps.num_comp_vectors; ++i) {
+		err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE,
+				     (dev->flags & MLX4_FLAG_MSI_X) ? i : 0,
+				     &priv->eq_table.eq[i]);
+		if (err)
+			goto err_out_unmap;
+	}
 
 	err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE,
-			     (dev->flags & MLX4_FLAG_MSI_X) ? MLX4_EQ_ASYNC : 0,
-			     &priv->eq_table.eq[MLX4_EQ_ASYNC]);
+			     (dev->flags & MLX4_FLAG_MSI_X) ? dev->caps.num_comp_vectors : 0,
+			     &priv->eq_table.eq[dev->caps.num_comp_vectors]);
 	if (err)
 		goto err_out_comp;
 
 	if (dev->flags & MLX4_FLAG_MSI_X) {
-		static const char *eq_name[] = {
-			[MLX4_EQ_COMP]  = DRV_NAME " (comp)",
-			[MLX4_EQ_ASYNC] = DRV_NAME " (async)"
-		};
+		static const char async_eq_name[] = "mlx4-async";
+		const char *eq_name;
 
-		for (i = 0; i < MLX4_NUM_EQ; ++i) {
+		for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) {
+			if (i < dev->caps.num_comp_vectors) {
+				snprintf(priv->eq_table.irq_names + i * 16, 16,
+					 "mlx4-comp-%d", i);
+				eq_name = priv->eq_table.irq_names + i * 16;
+			} else
+				eq_name = async_eq_name;
+
 			err = request_irq(priv->eq_table.eq[i].irq,
-					  mlx4_msi_x_interrupt,
-					  0, eq_name[i], priv->eq_table.eq + i);
+					  mlx4_msi_x_interrupt, 0, eq_name,
+					  priv->eq_table.eq + i);
 			if (err)
 				goto err_out_async;
 
 			priv->eq_table.eq[i].have_irq = 1;
 		}
-
 	} else {
 		err = request_irq(dev->pdev->irq, mlx4_interrupt,
 				  IRQF_SHARED, DRV_NAME, dev);
@@ -612,28 +657,36 @@
 	}
 
 	err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
-			  priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
+			  priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
 	if (err)
 		mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
-			   priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err);
+			   priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err);
 
-	for (i = 0; i < MLX4_NUM_EQ; ++i)
+	for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
 		eq_set_ci(&priv->eq_table.eq[i], 1);
 
 	return 0;
 
 err_out_async:
-	mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
+	mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]);
 
 err_out_comp:
-	mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_COMP]);
+	i = dev->caps.num_comp_vectors - 1;
 
 err_out_unmap:
+	while (i >= 0) {
+		mlx4_free_eq(dev, &priv->eq_table.eq[i]);
+		--i;
+	}
 	mlx4_unmap_clr_int(dev);
 	mlx4_free_irqs(dev);
 
-err_out_free:
+err_out_bitmap:
 	mlx4_bitmap_cleanup(&priv->eq_table.bitmap);
+
+err_out_free:
+	kfree(priv->eq_table.uar_map);
+
 	return err;
 }
 
@@ -643,18 +696,20 @@
 	int i;
 
 	mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
-		    priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
+		    priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
 
 	mlx4_free_irqs(dev);
 
-	for (i = 0; i < MLX4_NUM_EQ; ++i)
+	for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
 		mlx4_free_eq(dev, &priv->eq_table.eq[i]);
 
 	mlx4_unmap_clr_int(dev);
 
-	for (i = 0; i < ARRAY_SIZE(priv->eq_table.uar_map); ++i)
+	for (i = 0; i < mlx4_num_eq_uar(dev); ++i)
 		if (priv->eq_table.uar_map[i])
 			iounmap(priv->eq_table.uar_map[i]);
 
 	mlx4_bitmap_cleanup(&priv->eq_table.bitmap);
+
+	kfree(priv->eq_table.uar_map);
 }
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 90a0281..710c79e 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -421,9 +421,7 @@
 				  ((u64) (MLX4_CMPT_TYPE_EQ *
 					  cmpt_entry_sz) << MLX4_CMPT_SHIFT),
 				  cmpt_entry_sz,
-				  roundup_pow_of_two(MLX4_NUM_EQ +
-						     dev->caps.reserved_eqs),
-				  MLX4_NUM_EQ + dev->caps.reserved_eqs, 0, 0);
+				  dev->caps.num_eqs, dev->caps.num_eqs, 0, 0);
 	if (err)
 		goto err_cq;
 
@@ -810,12 +808,12 @@
 		if (dev->flags & MLX4_FLAG_MSI_X) {
 			mlx4_warn(dev, "NOP command failed to generate MSI-X "
 				  "interrupt IRQ %d).\n",
-				  priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
+				  priv->eq_table.eq[dev->caps.num_comp_vectors].irq);
 			mlx4_warn(dev, "Trying again without MSI-X.\n");
 		} else {
 			mlx4_err(dev, "NOP command failed to generate interrupt "
 				 "(IRQ %d), aborting.\n",
-				 priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
+				 priv->eq_table.eq[dev->caps.num_comp_vectors].irq);
 			mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n");
 		}
 
@@ -908,31 +906,50 @@
 static void mlx4_enable_msi_x(struct mlx4_dev *dev)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
-	struct msix_entry entries[MLX4_NUM_EQ];
+	struct msix_entry *entries;
+	int nreq;
 	int err;
 	int i;
 
 	if (msi_x) {
-		for (i = 0; i < MLX4_NUM_EQ; ++i)
+		nreq = min(dev->caps.num_eqs - dev->caps.reserved_eqs,
+			   num_possible_cpus() + 1);
+		entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL);
+		if (!entries)
+			goto no_msi;
+
+		for (i = 0; i < nreq; ++i)
 			entries[i].entry = i;
 
-		err = pci_enable_msix(dev->pdev, entries, ARRAY_SIZE(entries));
+	retry:
+		err = pci_enable_msix(dev->pdev, entries, nreq);
 		if (err) {
-			if (err > 0)
-				mlx4_info(dev, "Only %d MSI-X vectors available, "
-					  "not using MSI-X\n", err);
+			/* Try again if at least 2 vectors are available */
+			if (err > 1) {
+				mlx4_info(dev, "Requested %d vectors, "
+					  "but only %d MSI-X vectors available, "
+					  "trying again\n", nreq, err);
+				nreq = err;
+				goto retry;
+			}
+
 			goto no_msi;
 		}
 
-		for (i = 0; i < MLX4_NUM_EQ; ++i)
+		dev->caps.num_comp_vectors = nreq - 1;
+		for (i = 0; i < nreq; ++i)
 			priv->eq_table.eq[i].irq = entries[i].vector;
 
 		dev->flags |= MLX4_FLAG_MSI_X;
+
+		kfree(entries);
 		return;
 	}
 
 no_msi:
-	for (i = 0; i < MLX4_NUM_EQ; ++i)
+	dev->caps.num_comp_vectors = 1;
+
+	for (i = 0; i < 2; ++i)
 		priv->eq_table.eq[i].irq = dev->pdev->irq;
 }
 
@@ -1074,6 +1091,10 @@
 	if (err)
 		goto err_cmd;
 
+	err = mlx4_alloc_eq_table(dev);
+	if (err)
+		goto err_close;
+
 	mlx4_enable_msi_x(dev);
 
 	err = mlx4_setup_hca(dev);
@@ -1084,7 +1105,7 @@
 	}
 
 	if (err)
-		goto err_close;
+		goto err_free_eq;
 
 	for (port = 1; port <= dev->caps.num_ports; port++) {
 		err = mlx4_init_port_info(dev, port);
@@ -1114,6 +1135,9 @@
 	mlx4_cleanup_pd_table(dev);
 	mlx4_cleanup_uar_table(dev);
 
+err_free_eq:
+	mlx4_free_eq_table(dev);
+
 err_close:
 	if (dev->flags & MLX4_FLAG_MSI_X)
 		pci_disable_msix(pdev);
@@ -1177,6 +1201,7 @@
 		iounmap(priv->kar);
 		mlx4_uar_free(dev, &priv->driver_uar);
 		mlx4_cleanup_uar_table(dev);
+		mlx4_free_eq_table(dev);
 		mlx4_close_hca(dev);
 		mlx4_cmd_cleanup(dev);
 
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c
index 592c01a..6053c35 100644
--- a/drivers/net/mlx4/mcg.c
+++ b/drivers/net/mlx4/mcg.c
@@ -118,17 +118,7 @@
 		return err;
 
 	if (0)
-		mlx4_dbg(dev, "Hash for %04x:%04x:%04x:%04x:"
-			  "%04x:%04x:%04x:%04x is %04x\n",
-			  be16_to_cpu(((__be16 *) gid)[0]),
-			  be16_to_cpu(((__be16 *) gid)[1]),
-			  be16_to_cpu(((__be16 *) gid)[2]),
-			  be16_to_cpu(((__be16 *) gid)[3]),
-			  be16_to_cpu(((__be16 *) gid)[4]),
-			  be16_to_cpu(((__be16 *) gid)[5]),
-			  be16_to_cpu(((__be16 *) gid)[6]),
-			  be16_to_cpu(((__be16 *) gid)[7]),
-			  *hash);
+		mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash);
 
 	*index = *hash;
 	*prev  = -1;
@@ -215,7 +205,7 @@
 
 	if (block_mcast_loopback)
 		mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |
-						       (1 << MGM_BLCK_LB_BIT));
+						       (1U << MGM_BLCK_LB_BIT));
 	else
 		mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK);
 
@@ -277,16 +267,7 @@
 		goto out;
 
 	if (index == -1) {
-		mlx4_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
-			  "not found\n",
-			  be16_to_cpu(((__be16 *) gid)[0]),
-			  be16_to_cpu(((__be16 *) gid)[1]),
-			  be16_to_cpu(((__be16 *) gid)[2]),
-			  be16_to_cpu(((__be16 *) gid)[3]),
-			  be16_to_cpu(((__be16 *) gid)[4]),
-			  be16_to_cpu(((__be16 *) gid)[5]),
-			  be16_to_cpu(((__be16 *) gid)[6]),
-			  be16_to_cpu(((__be16 *) gid)[7]));
+		mlx4_err(dev, "MGID %pI6 not found\n", gid);
 		err = -EINVAL;
 		goto out;
 	}
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 34c909d..e0213bad 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -63,12 +63,6 @@
 };
 
 enum {
-	MLX4_EQ_ASYNC,
-	MLX4_EQ_COMP,
-	MLX4_NUM_EQ
-};
-
-enum {
 	MLX4_NUM_PDS		= 1 << 15
 };
 
@@ -205,10 +199,11 @@
 
 struct mlx4_eq_table {
 	struct mlx4_bitmap	bitmap;
+	char		       *irq_names;
 	void __iomem	       *clr_int;
-	void __iomem	       *uar_map[(MLX4_NUM_EQ + 6) / 4];
+	void __iomem	      **uar_map;
 	u32			clr_mask;
-	struct mlx4_eq		eq[MLX4_NUM_EQ];
+	struct mlx4_eq	       *eq;
 	u64			icm_virt;
 	struct page	       *icm_page;
 	dma_addr_t		icm_dma;
@@ -328,6 +323,9 @@
 
 int mlx4_reset(struct mlx4_dev *dev);
 
+int mlx4_alloc_eq_table(struct mlx4_dev *dev);
+void mlx4_free_eq_table(struct mlx4_dev *dev);
+
 int mlx4_init_pd_table(struct mlx4_dev *dev);
 int mlx4_init_uar_table(struct mlx4_dev *dev);
 int mlx4_init_mr_table(struct mlx4_dev *dev);
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h
index 98ddc08..e782097 100644
--- a/drivers/net/mlx4/mlx4_en.h
+++ b/drivers/net/mlx4/mlx4_en.h
@@ -58,17 +58,17 @@
 #define mlx4_dbg(mlevel, priv, format, arg...)	\
 	if (NETIF_MSG_##mlevel & priv->msg_enable) \
 	printk(KERN_DEBUG "%s %s: " format , DRV_NAME ,\
-		(&priv->mdev->pdev->dev)->bus_id , ## arg)
+		(dev_name(&priv->mdev->pdev->dev)) , ## arg)
 
 #define mlx4_err(mdev, format, arg...) \
 	printk(KERN_ERR "%s %s: " format , DRV_NAME ,\
-		(&mdev->pdev->dev)->bus_id , ## arg)
+		(dev_name(&mdev->pdev->dev)) , ## arg)
 #define mlx4_info(mdev, format, arg...) \
 	printk(KERN_INFO "%s %s: " format , DRV_NAME ,\
-		(&mdev->pdev->dev)->bus_id , ## arg)
+		(dev_name(&mdev->pdev->dev)) , ## arg)
 #define mlx4_warn(mdev, format, arg...) \
 	printk(KERN_WARNING "%s %s: " format , DRV_NAME ,\
-		(&mdev->pdev->dev)->bus_id , ## arg)
+		(dev_name(&mdev->pdev->dev)) , ## arg)
 
 /*
  * Device constants
@@ -311,7 +311,6 @@
 	enum cq_type is_tx;
 	u16 moder_time;
 	u16 moder_cnt;
-	int armed;
 	struct mlx4_cqe *buf;
 #define MLX4_EN_OPCODE_ERROR	0x1e
 };
@@ -334,9 +333,6 @@
 	u8 rss_mask;
 	u32 active_ports;
 	u32 small_pkt_int;
-	int rx_moder_cnt;
-	int rx_moder_time;
-	int auto_moder;
 	u8 no_reset;
 	struct mlx4_en_port_profile prof[MLX4_MAX_PORTS + 1];
 };
diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c
index 9ca42b2..919fb9e 100644
--- a/drivers/net/mlx4/profile.c
+++ b/drivers/net/mlx4/profile.c
@@ -107,7 +107,9 @@
 	profile[MLX4_RES_AUXC].num    = request->num_qp;
 	profile[MLX4_RES_SRQ].num     = request->num_srq;
 	profile[MLX4_RES_CQ].num      = request->num_cq;
-	profile[MLX4_RES_EQ].num      = MLX4_NUM_EQ + dev_cap->reserved_eqs;
+	profile[MLX4_RES_EQ].num      = min(dev_cap->max_eqs,
+					    dev_cap->reserved_eqs +
+					    num_possible_cpus() + 1);
 	profile[MLX4_RES_DMPT].num    = request->num_mpt;
 	profile[MLX4_RES_CMPT].num    = MLX4_NUM_CMPTS;
 	profile[MLX4_RES_MTT].num     = request->num_mtt;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index e513f76..7253a49 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -51,8 +51,8 @@
 #include <linux/workqueue.h>
 #include <linux/phy.h>
 #include <linux/mv643xx_eth.h>
-#include <asm/io.h>
-#include <asm/types.h>
+#include <linux/io.h>
+#include <linux/types.h>
 #include <asm/system.h>
 
 static char mv643xx_eth_driver_name[] = "mv643xx_eth";
@@ -78,16 +78,17 @@
 #define WINDOW_PROTECT(w)		(0x0294 + ((w) << 4))
 
 /*
- * Per-port registers.
+ * Main per-port registers.  These live at offset 0x0400 for
+ * port #0, 0x0800 for port #1, and 0x0c00 for port #2.
  */
-#define PORT_CONFIG(p)			(0x0400 + ((p) << 10))
+#define PORT_CONFIG			0x0000
 #define  UNICAST_PROMISCUOUS_MODE	0x00000001
-#define PORT_CONFIG_EXT(p)		(0x0404 + ((p) << 10))
-#define MAC_ADDR_LOW(p)			(0x0414 + ((p) << 10))
-#define MAC_ADDR_HIGH(p)		(0x0418 + ((p) << 10))
-#define SDMA_CONFIG(p)			(0x041c + ((p) << 10))
-#define PORT_SERIAL_CONTROL(p)		(0x043c + ((p) << 10))
-#define PORT_STATUS(p)			(0x0444 + ((p) << 10))
+#define PORT_CONFIG_EXT			0x0004
+#define MAC_ADDR_LOW			0x0014
+#define MAC_ADDR_HIGH			0x0018
+#define SDMA_CONFIG			0x001c
+#define PORT_SERIAL_CONTROL		0x003c
+#define PORT_STATUS			0x0044
 #define  TX_FIFO_EMPTY			0x00000400
 #define  TX_IN_PROGRESS			0x00000080
 #define  PORT_SPEED_MASK		0x00000030
@@ -97,31 +98,35 @@
 #define  FLOW_CONTROL_ENABLED		0x00000008
 #define  FULL_DUPLEX			0x00000004
 #define  LINK_UP			0x00000002
-#define TXQ_COMMAND(p)			(0x0448 + ((p) << 10))
-#define TXQ_FIX_PRIO_CONF(p)		(0x044c + ((p) << 10))
-#define TX_BW_RATE(p)			(0x0450 + ((p) << 10))
-#define TX_BW_MTU(p)			(0x0458 + ((p) << 10))
-#define TX_BW_BURST(p)			(0x045c + ((p) << 10))
-#define INT_CAUSE(p)			(0x0460 + ((p) << 10))
+#define TXQ_COMMAND			0x0048
+#define TXQ_FIX_PRIO_CONF		0x004c
+#define TX_BW_RATE			0x0050
+#define TX_BW_MTU			0x0058
+#define TX_BW_BURST			0x005c
+#define INT_CAUSE			0x0060
 #define  INT_TX_END			0x07f80000
 #define  INT_RX				0x000003fc
 #define  INT_EXT			0x00000002
-#define INT_CAUSE_EXT(p)		(0x0464 + ((p) << 10))
+#define INT_CAUSE_EXT			0x0064
 #define  INT_EXT_LINK_PHY		0x00110000
 #define  INT_EXT_TX			0x000000ff
-#define INT_MASK(p)			(0x0468 + ((p) << 10))
-#define INT_MASK_EXT(p)			(0x046c + ((p) << 10))
-#define TX_FIFO_URGENT_THRESHOLD(p)	(0x0474 + ((p) << 10))
-#define TXQ_FIX_PRIO_CONF_MOVED(p)	(0x04dc + ((p) << 10))
-#define TX_BW_RATE_MOVED(p)		(0x04e0 + ((p) << 10))
-#define TX_BW_MTU_MOVED(p)		(0x04e8 + ((p) << 10))
-#define TX_BW_BURST_MOVED(p)		(0x04ec + ((p) << 10))
-#define RXQ_CURRENT_DESC_PTR(p, q)	(0x060c + ((p) << 10) + ((q) << 4))
-#define RXQ_COMMAND(p)			(0x0680 + ((p) << 10))
-#define TXQ_CURRENT_DESC_PTR(p, q)	(0x06c0 + ((p) << 10) + ((q) << 2))
-#define TXQ_BW_TOKENS(p, q)		(0x0700 + ((p) << 10) + ((q) << 4))
-#define TXQ_BW_CONF(p, q)		(0x0704 + ((p) << 10) + ((q) << 4))
-#define TXQ_BW_WRR_CONF(p, q)		(0x0708 + ((p) << 10) + ((q) << 4))
+#define INT_MASK			0x0068
+#define INT_MASK_EXT			0x006c
+#define TX_FIFO_URGENT_THRESHOLD	0x0074
+#define TXQ_FIX_PRIO_CONF_MOVED		0x00dc
+#define TX_BW_RATE_MOVED		0x00e0
+#define TX_BW_MTU_MOVED			0x00e8
+#define TX_BW_BURST_MOVED		0x00ec
+#define RXQ_CURRENT_DESC_PTR(q)		(0x020c + ((q) << 4))
+#define RXQ_COMMAND			0x0280
+#define TXQ_CURRENT_DESC_PTR(q)		(0x02c0 + ((q) << 2))
+#define TXQ_BW_TOKENS(q)		(0x0300 + ((q) << 4))
+#define TXQ_BW_CONF(q)			(0x0304 + ((q) << 4))
+#define TXQ_BW_WRR_CONF(q)		(0x0308 + ((q) << 4))
+
+/*
+ * Misc per-port registers.
+ */
 #define MIB_COUNTERS(p)			(0x1000 + ((p) << 7))
 #define SPECIAL_MCAST_TABLE(p)		(0x1400 + ((p) << 10))
 #define OTHER_MCAST_TABLE(p)		(0x1500 + ((p) << 10))
@@ -138,14 +143,14 @@
 
 #if defined(__BIG_ENDIAN)
 #define PORT_SDMA_CONFIG_DEFAULT_VALUE		\
-		RX_BURST_SIZE_16_64BIT	|	\
-		TX_BURST_SIZE_16_64BIT
+		(RX_BURST_SIZE_16_64BIT	|	\
+		TX_BURST_SIZE_16_64BIT)
 #elif defined(__LITTLE_ENDIAN)
 #define PORT_SDMA_CONFIG_DEFAULT_VALUE		\
-		RX_BURST_SIZE_16_64BIT	|	\
+		(RX_BURST_SIZE_16_64BIT	|	\
 		BLM_RX_NO_SWAP		|	\
 		BLM_TX_NO_SWAP		|	\
-		TX_BURST_SIZE_16_64BIT
+		TX_BURST_SIZE_16_64BIT)
 #else
 #error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined
 #endif
@@ -351,6 +356,7 @@
 
 struct mv643xx_eth_private {
 	struct mv643xx_eth_shared_private *shared;
+	void __iomem *base;
 	int port_num;
 
 	struct net_device *dev;
@@ -401,11 +407,21 @@
 	return readl(mp->shared->base + offset);
 }
 
+static inline u32 rdlp(struct mv643xx_eth_private *mp, int offset)
+{
+	return readl(mp->base + offset);
+}
+
 static inline void wrl(struct mv643xx_eth_private *mp, int offset, u32 data)
 {
 	writel(data, mp->shared->base + offset);
 }
 
+static inline void wrlp(struct mv643xx_eth_private *mp, int offset, u32 data)
+{
+	writel(data, mp->base + offset);
+}
+
 
 /* rxq/txq helper functions *************************************************/
 static struct mv643xx_eth_private *rxq_to_mp(struct rx_queue *rxq)
@@ -421,7 +437,7 @@
 static void rxq_enable(struct rx_queue *rxq)
 {
 	struct mv643xx_eth_private *mp = rxq_to_mp(rxq);
-	wrl(mp, RXQ_COMMAND(mp->port_num), 1 << rxq->index);
+	wrlp(mp, RXQ_COMMAND, 1 << rxq->index);
 }
 
 static void rxq_disable(struct rx_queue *rxq)
@@ -429,26 +445,25 @@
 	struct mv643xx_eth_private *mp = rxq_to_mp(rxq);
 	u8 mask = 1 << rxq->index;
 
-	wrl(mp, RXQ_COMMAND(mp->port_num), mask << 8);
-	while (rdl(mp, RXQ_COMMAND(mp->port_num)) & mask)
+	wrlp(mp, RXQ_COMMAND, mask << 8);
+	while (rdlp(mp, RXQ_COMMAND) & mask)
 		udelay(10);
 }
 
 static void txq_reset_hw_ptr(struct tx_queue *txq)
 {
 	struct mv643xx_eth_private *mp = txq_to_mp(txq);
-	int off = TXQ_CURRENT_DESC_PTR(mp->port_num, txq->index);
 	u32 addr;
 
 	addr = (u32)txq->tx_desc_dma;
 	addr += txq->tx_curr_desc * sizeof(struct tx_desc);
-	wrl(mp, off, addr);
+	wrlp(mp, TXQ_CURRENT_DESC_PTR(txq->index), addr);
 }
 
 static void txq_enable(struct tx_queue *txq)
 {
 	struct mv643xx_eth_private *mp = txq_to_mp(txq);
-	wrl(mp, TXQ_COMMAND(mp->port_num), 1 << txq->index);
+	wrlp(mp, TXQ_COMMAND, 1 << txq->index);
 }
 
 static void txq_disable(struct tx_queue *txq)
@@ -456,8 +471,8 @@
 	struct mv643xx_eth_private *mp = txq_to_mp(txq);
 	u8 mask = 1 << txq->index;
 
-	wrl(mp, TXQ_COMMAND(mp->port_num), mask << 8);
-	while (rdl(mp, TXQ_COMMAND(mp->port_num)) & mask)
+	wrlp(mp, TXQ_COMMAND, mask << 8);
+	while (rdlp(mp, TXQ_COMMAND) & mask)
 		udelay(10);
 }
 
@@ -528,37 +543,38 @@
 		 * on, or the error summary bit is set, the packet needs
 		 * to be dropped.
 		 */
-		if (((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) !=
-					(RX_FIRST_DESC | RX_LAST_DESC))
-				|| (cmd_sts & ERROR_SUMMARY)) {
-			stats->rx_dropped++;
+		if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC | ERROR_SUMMARY))
+			!= (RX_FIRST_DESC | RX_LAST_DESC))
+			goto err;
 
-			if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) !=
-				(RX_FIRST_DESC | RX_LAST_DESC)) {
-				if (net_ratelimit())
-					dev_printk(KERN_ERR, &mp->dev->dev,
-						   "received packet spanning "
-						   "multiple descriptors\n");
-			}
+		/*
+		 * The -4 is for the CRC in the trailer of the
+		 * received packet
+		 */
+		skb_put(skb, byte_cnt - 2 - 4);
 
-			if (cmd_sts & ERROR_SUMMARY)
-				stats->rx_errors++;
+		if (cmd_sts & LAYER_4_CHECKSUM_OK)
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		skb->protocol = eth_type_trans(skb, mp->dev);
+		netif_receive_skb(skb);
 
-			dev_kfree_skb(skb);
-		} else {
-			/*
-			 * The -4 is for the CRC in the trailer of the
-			 * received packet
-			 */
-			skb_put(skb, byte_cnt - 2 - 4);
+		continue;
 
-			if (cmd_sts & LAYER_4_CHECKSUM_OK)
-				skb->ip_summed = CHECKSUM_UNNECESSARY;
-			skb->protocol = eth_type_trans(skb, mp->dev);
-			netif_receive_skb(skb);
+err:
+		stats->rx_dropped++;
+
+		if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) !=
+			(RX_FIRST_DESC | RX_LAST_DESC)) {
+			if (net_ratelimit())
+				dev_printk(KERN_ERR, &mp->dev->dev,
+					   "received packet spanning "
+					   "multiple descriptors\n");
 		}
 
-		mp->dev->last_rx = jiffies;
+		if (cmd_sts & ERROR_SUMMARY)
+			stats->rx_errors++;
+
+		dev_kfree_skb(skb);
 	}
 
 	if (rx < budget)
@@ -577,6 +593,7 @@
 		struct sk_buff *skb;
 		int unaligned;
 		int rx;
+		struct rx_desc *rx_desc;
 
 		skb = __skb_dequeue(&mp->rx_recycle);
 		if (skb == NULL)
@@ -599,13 +616,14 @@
 		if (rxq->rx_used_desc == rxq->rx_ring_size)
 			rxq->rx_used_desc = 0;
 
-		rxq->rx_desc_area[rx].buf_ptr = dma_map_single(NULL, skb->data,
-						mp->skb_size, DMA_FROM_DEVICE);
-		rxq->rx_desc_area[rx].buf_size = mp->skb_size;
+		rx_desc = rxq->rx_desc_area + rx;
+
+		rx_desc->buf_ptr = dma_map_single(NULL, skb->data,
+					mp->skb_size, DMA_FROM_DEVICE);
+		rx_desc->buf_size = mp->skb_size;
 		rxq->rx_skb[rx] = skb;
 		wmb();
-		rxq->rx_desc_area[rx].cmd_sts = BUFFER_OWNED_BY_DMA |
-						RX_ENABLE_INTERRUPT;
+		rx_desc->cmd_sts = BUFFER_OWNED_BY_DMA | RX_ENABLE_INTERRUPT;
 		wmb();
 
 		/*
@@ -638,21 +656,6 @@
 	return 0;
 }
 
-static int txq_alloc_desc_index(struct tx_queue *txq)
-{
-	int tx_desc_curr;
-
-	BUG_ON(txq->tx_desc_count >= txq->tx_ring_size);
-
-	tx_desc_curr = txq->tx_curr_desc++;
-	if (txq->tx_curr_desc == txq->tx_ring_size)
-		txq->tx_curr_desc = 0;
-
-	BUG_ON(txq->tx_curr_desc == txq->tx_used_desc);
-
-	return tx_desc_curr;
-}
-
 static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb)
 {
 	int nr_frags = skb_shinfo(skb)->nr_frags;
@@ -664,7 +667,9 @@
 		struct tx_desc *desc;
 
 		this_frag = &skb_shinfo(skb)->frags[frag];
-		tx_index = txq_alloc_desc_index(txq);
+		tx_index = txq->tx_curr_desc++;
+		if (txq->tx_curr_desc == txq->tx_ring_size)
+			txq->tx_curr_desc = 0;
 		desc = &txq->tx_desc_area[tx_index];
 
 		/*
@@ -746,7 +751,9 @@
 		cmd_sts |= 5 << TX_IHL_SHIFT;
 	}
 
-	tx_index = txq_alloc_desc_index(txq);
+	tx_index = txq->tx_curr_desc++;
+	if (txq->tx_curr_desc == txq->tx_ring_size)
+		txq->tx_curr_desc = 0;
 	desc = &txq->tx_desc_area[tx_index];
 
 	if (nr_frags) {
@@ -831,10 +838,10 @@
 
 	__netif_tx_lock(nq, smp_processor_id());
 
-	if (rdl(mp, TXQ_COMMAND(mp->port_num)) & (1 << txq->index))
+	if (rdlp(mp, TXQ_COMMAND) & (1 << txq->index))
 		goto out;
 
-	hw_desc_ptr = rdl(mp, TXQ_CURRENT_DESC_PTR(mp->port_num, txq->index));
+	hw_desc_ptr = rdlp(mp, TXQ_CURRENT_DESC_PTR(txq->index));
 	expected_ptr = (u32)txq->tx_desc_dma +
 				txq->tx_curr_desc * sizeof(struct tx_desc);
 
@@ -941,14 +948,14 @@
 
 	switch (mp->shared->tx_bw_control) {
 	case TX_BW_CONTROL_OLD_LAYOUT:
-		wrl(mp, TX_BW_RATE(mp->port_num), token_rate);
-		wrl(mp, TX_BW_MTU(mp->port_num), mtu);
-		wrl(mp, TX_BW_BURST(mp->port_num), bucket_size);
+		wrlp(mp, TX_BW_RATE, token_rate);
+		wrlp(mp, TX_BW_MTU, mtu);
+		wrlp(mp, TX_BW_BURST, bucket_size);
 		break;
 	case TX_BW_CONTROL_NEW_LAYOUT:
-		wrl(mp, TX_BW_RATE_MOVED(mp->port_num), token_rate);
-		wrl(mp, TX_BW_MTU_MOVED(mp->port_num), mtu);
-		wrl(mp, TX_BW_BURST_MOVED(mp->port_num), bucket_size);
+		wrlp(mp, TX_BW_RATE_MOVED, token_rate);
+		wrlp(mp, TX_BW_MTU_MOVED, mtu);
+		wrlp(mp, TX_BW_BURST_MOVED, bucket_size);
 		break;
 	}
 }
@@ -967,9 +974,8 @@
 	if (bucket_size > 65535)
 		bucket_size = 65535;
 
-	wrl(mp, TXQ_BW_TOKENS(mp->port_num, txq->index), token_rate << 14);
-	wrl(mp, TXQ_BW_CONF(mp->port_num, txq->index),
-			(bucket_size << 10) | token_rate);
+	wrlp(mp, TXQ_BW_TOKENS(txq->index), token_rate << 14);
+	wrlp(mp, TXQ_BW_CONF(txq->index), (bucket_size << 10) | token_rate);
 }
 
 static void txq_set_fixed_prio_mode(struct tx_queue *txq)
@@ -984,17 +990,17 @@
 	off = 0;
 	switch (mp->shared->tx_bw_control) {
 	case TX_BW_CONTROL_OLD_LAYOUT:
-		off = TXQ_FIX_PRIO_CONF(mp->port_num);
+		off = TXQ_FIX_PRIO_CONF;
 		break;
 	case TX_BW_CONTROL_NEW_LAYOUT:
-		off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num);
+		off = TXQ_FIX_PRIO_CONF_MOVED;
 		break;
 	}
 
 	if (off) {
-		val = rdl(mp, off);
+		val = rdlp(mp, off);
 		val |= 1 << txq->index;
-		wrl(mp, off, val);
+		wrlp(mp, off, val);
 	}
 }
 
@@ -1010,26 +1016,25 @@
 	off = 0;
 	switch (mp->shared->tx_bw_control) {
 	case TX_BW_CONTROL_OLD_LAYOUT:
-		off = TXQ_FIX_PRIO_CONF(mp->port_num);
+		off = TXQ_FIX_PRIO_CONF;
 		break;
 	case TX_BW_CONTROL_NEW_LAYOUT:
-		off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num);
+		off = TXQ_FIX_PRIO_CONF_MOVED;
 		break;
 	}
 
 	if (off) {
-		val = rdl(mp, off);
+		val = rdlp(mp, off);
 		val &= ~(1 << txq->index);
-		wrl(mp, off, val);
+		wrlp(mp, off, val);
 
 		/*
 		 * Configure WRR weight for this queue.
 		 */
-		off = TXQ_BW_WRR_CONF(mp->port_num, txq->index);
 
-		val = rdl(mp, off);
+		val = rdlp(mp, off);
 		val = (val & ~0xff) | (weight & 0xff);
-		wrl(mp, off, val);
+		wrlp(mp, TXQ_BW_WRR_CONF(txq->index), val);
 	}
 }
 
@@ -1084,20 +1089,20 @@
 	int ret;
 
 	if (smi_wait_ready(msp)) {
-		printk("mv643xx_eth: SMI bus busy timeout\n");
+		printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n");
 		return -ETIMEDOUT;
 	}
 
 	writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg);
 
 	if (smi_wait_ready(msp)) {
-		printk("mv643xx_eth: SMI bus busy timeout\n");
+		printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n");
 		return -ETIMEDOUT;
 	}
 
 	ret = readl(smi_reg);
 	if (!(ret & SMI_READ_VALID)) {
-		printk("mv643xx_eth: SMI bus read not valid\n");
+		printk(KERN_WARNING "mv643xx_eth: SMI bus read not valid\n");
 		return -ENODEV;
 	}
 
@@ -1110,7 +1115,7 @@
 	void __iomem *smi_reg = msp->base + SMI_REG;
 
 	if (smi_wait_ready(msp)) {
-		printk("mv643xx_eth: SMI bus busy timeout\n");
+		printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n");
 		return -ETIMEDOUT;
 	}
 
@@ -1118,7 +1123,7 @@
 		(addr << 16) | (val & 0xffff), smi_reg);
 
 	if (smi_wait_ready(msp)) {
-		printk("mv643xx_eth: SMI bus busy timeout\n");
+		printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n");
 		return -ETIMEDOUT;
 	}
 
@@ -1271,7 +1276,8 @@
 	MIBSTAT(late_collision),
 };
 
-static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int
+mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
 	int err;
@@ -1289,12 +1295,14 @@
 	return err;
 }
 
-static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd)
+static int
+mv643xx_eth_get_settings_phyless(struct net_device *dev,
+				 struct ethtool_cmd *cmd)
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
 	u32 port_status;
 
-	port_status = rdl(mp, PORT_STATUS(mp->port_num));
+	port_status = rdlp(mp, PORT_STATUS);
 
 	cmd->supported = SUPPORTED_MII;
 	cmd->advertising = ADVERTISED_MII;
@@ -1323,7 +1331,8 @@
 	return 0;
 }
 
-static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int
+mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
 
@@ -1335,7 +1344,9 @@
 	return phy_ethtool_sset(mp->phy, cmd);
 }
 
-static int mv643xx_eth_set_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd)
+static int
+mv643xx_eth_set_settings_phyless(struct net_device *dev,
+				 struct ethtool_cmd *cmd)
 {
 	return -EINVAL;
 }
@@ -1443,11 +1454,8 @@
 /* address handling *********************************************************/
 static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr)
 {
-	unsigned int mac_h;
-	unsigned int mac_l;
-
-	mac_h = rdl(mp, MAC_ADDR_HIGH(mp->port_num));
-	mac_l = rdl(mp, MAC_ADDR_LOW(mp->port_num));
+	unsigned int mac_h = rdlp(mp, MAC_ADDR_HIGH);
+	unsigned int mac_l = rdlp(mp, MAC_ADDR_LOW);
 
 	addr[0] = (mac_h >> 24) & 0xff;
 	addr[1] = (mac_h >> 16) & 0xff;
@@ -1457,57 +1465,71 @@
 	addr[5] = mac_l & 0xff;
 }
 
-static void init_mac_tables(struct mv643xx_eth_private *mp)
-{
-	int i;
-
-	for (i = 0; i < 0x100; i += 4) {
-		wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0);
-		wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0);
-	}
-
-	for (i = 0; i < 0x10; i += 4)
-		wrl(mp, UNICAST_TABLE(mp->port_num) + i, 0);
-}
-
-static void set_filter_table_entry(struct mv643xx_eth_private *mp,
-				   int table, unsigned char entry)
-{
-	unsigned int table_reg;
-
-	/* Set "accepts frame bit" at specified table entry */
-	table_reg = rdl(mp, table + (entry & 0xfc));
-	table_reg |= 0x01 << (8 * (entry & 3));
-	wrl(mp, table + (entry & 0xfc), table_reg);
-}
-
 static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr)
 {
-	unsigned int mac_h;
-	unsigned int mac_l;
-	int table;
-
-	mac_l = (addr[4] << 8) | addr[5];
-	mac_h = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
-
-	wrl(mp, MAC_ADDR_LOW(mp->port_num), mac_l);
-	wrl(mp, MAC_ADDR_HIGH(mp->port_num), mac_h);
-
-	table = UNICAST_TABLE(mp->port_num);
-	set_filter_table_entry(mp, table, addr[5] & 0x0f);
+	wrlp(mp, MAC_ADDR_HIGH,
+		(addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]);
+	wrlp(mp, MAC_ADDR_LOW, (addr[4] << 8) | addr[5]);
 }
 
-static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr)
+static u32 uc_addr_filter_mask(struct net_device *dev)
+{
+	struct dev_addr_list *uc_ptr;
+	u32 nibbles;
+
+	if (dev->flags & IFF_PROMISC)
+		return 0;
+
+	nibbles = 1 << (dev->dev_addr[5] & 0x0f);
+	for (uc_ptr = dev->uc_list; uc_ptr != NULL; uc_ptr = uc_ptr->next) {
+		if (memcmp(dev->dev_addr, uc_ptr->da_addr, 5))
+			return 0;
+		if ((dev->dev_addr[5] ^ uc_ptr->da_addr[5]) & 0xf0)
+			return 0;
+
+		nibbles |= 1 << (uc_ptr->da_addr[5] & 0x0f);
+	}
+
+	return nibbles;
+}
+
+static void mv643xx_eth_program_unicast_filter(struct net_device *dev)
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
+	u32 port_config;
+	u32 nibbles;
+	int i;
 
-	/* +2 is for the offset of the HW addr type */
-	memcpy(dev->dev_addr, addr + 2, 6);
-
-	init_mac_tables(mp);
 	uc_addr_set(mp, dev->dev_addr);
 
-	return 0;
+	port_config = rdlp(mp, PORT_CONFIG);
+	nibbles = uc_addr_filter_mask(dev);
+	if (!nibbles) {
+		port_config |= UNICAST_PROMISCUOUS_MODE;
+		wrlp(mp, PORT_CONFIG, port_config);
+		return;
+	}
+
+	for (i = 0; i < 16; i += 4) {
+		int off = UNICAST_TABLE(mp->port_num) + i;
+		u32 v;
+
+		v = 0;
+		if (nibbles & 1)
+			v |= 0x00000001;
+		if (nibbles & 2)
+			v |= 0x00000100;
+		if (nibbles & 4)
+			v |= 0x00010000;
+		if (nibbles & 8)
+			v |= 0x01000000;
+		nibbles >>= 4;
+
+		wrl(mp, off, v);
+	}
+
+	port_config &= ~UNICAST_PROMISCUOUS_MODE;
+	wrlp(mp, PORT_CONFIG, port_config);
 }
 
 static int addr_crc(unsigned char *addr)
@@ -1528,24 +1550,22 @@
 	return crc;
 }
 
-static void mv643xx_eth_set_rx_mode(struct net_device *dev)
+static void mv643xx_eth_program_multicast_filter(struct net_device *dev)
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
-	u32 port_config;
+	u32 *mc_spec;
+	u32 *mc_other;
 	struct dev_addr_list *addr;
 	int i;
 
-	port_config = rdl(mp, PORT_CONFIG(mp->port_num));
-	if (dev->flags & IFF_PROMISC)
-		port_config |= UNICAST_PROMISCUOUS_MODE;
-	else
-		port_config &= ~UNICAST_PROMISCUOUS_MODE;
-	wrl(mp, PORT_CONFIG(mp->port_num), port_config);
-
 	if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
-		int port_num = mp->port_num;
-		u32 accept = 0x01010101;
+		int port_num;
+		u32 accept;
+		int i;
 
+oom:
+		port_num = mp->port_num;
+		accept = 0x01010101;
 		for (i = 0; i < 0x100; i += 4) {
 			wrl(mp, SPECIAL_MCAST_TABLE(port_num) + i, accept);
 			wrl(mp, OTHER_MCAST_TABLE(port_num) + i, accept);
@@ -1553,28 +1573,55 @@
 		return;
 	}
 
-	for (i = 0; i < 0x100; i += 4) {
-		wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0);
-		wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0);
-	}
+	mc_spec = kmalloc(0x200, GFP_KERNEL);
+	if (mc_spec == NULL)
+		goto oom;
+	mc_other = mc_spec + (0x100 >> 2);
+
+	memset(mc_spec, 0, 0x100);
+	memset(mc_other, 0, 0x100);
 
 	for (addr = dev->mc_list; addr != NULL; addr = addr->next) {
 		u8 *a = addr->da_addr;
-		int table;
-
-		if (addr->da_addrlen != 6)
-			continue;
+		u32 *table;
+		int entry;
 
 		if (memcmp(a, "\x01\x00\x5e\x00\x00", 5) == 0) {
-			table = SPECIAL_MCAST_TABLE(mp->port_num);
-			set_filter_table_entry(mp, table, a[5]);
+			table = mc_spec;
+			entry = a[5];
 		} else {
-			int crc = addr_crc(a);
-
-			table = OTHER_MCAST_TABLE(mp->port_num);
-			set_filter_table_entry(mp, table, crc);
+			table = mc_other;
+			entry = addr_crc(a);
 		}
+
+		table[entry >> 2] |= 1 << (entry & 3);
 	}
+
+	for (i = 0; i < 0x100; i += 4) {
+		wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, mc_spec[i >> 2]);
+		wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, mc_other[i >> 2]);
+	}
+
+	kfree(mc_spec);
+}
+
+static void mv643xx_eth_set_rx_mode(struct net_device *dev)
+{
+	mv643xx_eth_program_unicast_filter(dev);
+	mv643xx_eth_program_multicast_filter(dev);
+}
+
+static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct sockaddr *sa = addr;
+
+	memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
+
+	netif_addr_lock_bh(dev);
+	mv643xx_eth_program_unicast_filter(dev);
+	netif_addr_unlock_bh(dev);
+
+	return 0;
 }
 
 
@@ -1758,26 +1805,25 @@
 	u32 int_cause;
 	u32 int_cause_ext;
 
-	int_cause = rdl(mp, INT_CAUSE(mp->port_num)) &
-			(INT_TX_END | INT_RX | INT_EXT);
+	int_cause = rdlp(mp, INT_CAUSE) & (INT_TX_END | INT_RX | INT_EXT);
 	if (int_cause == 0)
 		return 0;
 
 	int_cause_ext = 0;
 	if (int_cause & INT_EXT)
-		int_cause_ext = rdl(mp, INT_CAUSE_EXT(mp->port_num));
+		int_cause_ext = rdlp(mp, INT_CAUSE_EXT);
 
 	int_cause &= INT_TX_END | INT_RX;
 	if (int_cause) {
-		wrl(mp, INT_CAUSE(mp->port_num), ~int_cause);
+		wrlp(mp, INT_CAUSE, ~int_cause);
 		mp->work_tx_end |= ((int_cause & INT_TX_END) >> 19) &
-				~(rdl(mp, TXQ_COMMAND(mp->port_num)) & 0xff);
+				~(rdlp(mp, TXQ_COMMAND) & 0xff);
 		mp->work_rx |= (int_cause & INT_RX) >> 2;
 	}
 
 	int_cause_ext &= INT_EXT_LINK_PHY | INT_EXT_TX;
 	if (int_cause_ext) {
-		wrl(mp, INT_CAUSE_EXT(mp->port_num), ~int_cause_ext);
+		wrlp(mp, INT_CAUSE_EXT, ~int_cause_ext);
 		if (int_cause_ext & INT_EXT_LINK_PHY)
 			mp->work_link = 1;
 		mp->work_tx |= int_cause_ext & INT_EXT_TX;
@@ -1794,7 +1840,7 @@
 	if (unlikely(!mv643xx_eth_collect_events(mp)))
 		return IRQ_NONE;
 
-	wrl(mp, INT_MASK(mp->port_num), 0);
+	wrlp(mp, INT_MASK, 0);
 	napi_schedule(&mp->napi);
 
 	return IRQ_HANDLED;
@@ -1808,7 +1854,7 @@
 	int duplex;
 	int fc;
 
-	port_status = rdl(mp, PORT_STATUS(mp->port_num));
+	port_status = rdlp(mp, PORT_STATUS);
 	if (!(port_status & LINK_UP)) {
 		if (netif_carrier_ok(dev)) {
 			int i;
@@ -1908,7 +1954,7 @@
 		if (mp->work_rx_oom)
 			mod_timer(&mp->rx_oom, jiffies + (HZ / 10));
 		napi_complete(napi);
-		wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT);
+		wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT);
 	}
 
 	return work_done;
@@ -1957,17 +2003,17 @@
 	/*
 	 * Configure basic link parameters.
 	 */
-	pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num));
+	pscr = rdlp(mp, PORT_SERIAL_CONTROL);
 
 	pscr |= SERIAL_PORT_ENABLE;
-	wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
+	wrlp(mp, PORT_SERIAL_CONTROL, pscr);
 
 	pscr |= DO_NOT_FORCE_LINK_FAIL;
 	if (mp->phy == NULL)
 		pscr |= FORCE_LINK_PASS;
-	wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
+	wrlp(mp, PORT_SERIAL_CONTROL, pscr);
 
-	wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE);
+	wrlp(mp, SDMA_CONFIG, PORT_SDMA_CONFIG_DEFAULT_VALUE);
 
 	/*
 	 * Configure TX path and queues.
@@ -1984,31 +2030,30 @@
 	/*
 	 * Add configured unicast address to address filter table.
 	 */
-	uc_addr_set(mp, mp->dev->dev_addr);
+	mv643xx_eth_program_unicast_filter(mp->dev);
 
 	/*
 	 * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast
 	 * frames to RX queue #0, and include the pseudo-header when
 	 * calculating receive checksums.
 	 */
-	wrl(mp, PORT_CONFIG(mp->port_num), 0x02000000);
+	wrlp(mp, PORT_CONFIG, 0x02000000);
 
 	/*
 	 * Treat BPDUs as normal multicasts, and disable partition mode.
 	 */
-	wrl(mp, PORT_CONFIG_EXT(mp->port_num), 0x00000000);
+	wrlp(mp, PORT_CONFIG_EXT, 0x00000000);
 
 	/*
 	 * Enable the receive queues.
 	 */
 	for (i = 0; i < mp->rxq_count; i++) {
 		struct rx_queue *rxq = mp->rxq + i;
-		int off = RXQ_CURRENT_DESC_PTR(mp->port_num, i);
 		u32 addr;
 
 		addr = (u32)rxq->rx_desc_dma;
 		addr += rxq->rx_curr_desc * sizeof(struct rx_desc);
-		wrl(mp, off, addr);
+		wrlp(mp, RXQ_CURRENT_DESC_PTR(i), addr);
 
 		rxq_enable(rxq);
 	}
@@ -2019,7 +2064,7 @@
 	unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64;
 	u32 val;
 
-	val = rdl(mp, SDMA_CONFIG(mp->port_num));
+	val = rdlp(mp, SDMA_CONFIG);
 	if (mp->shared->extended_rx_coal_limit) {
 		if (coal > 0xffff)
 			coal = 0xffff;
@@ -2032,7 +2077,7 @@
 		val &= ~0x003fff00;
 		val |= (coal & 0x3fff) << 8;
 	}
-	wrl(mp, SDMA_CONFIG(mp->port_num), val);
+	wrlp(mp, SDMA_CONFIG, val);
 }
 
 static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay)
@@ -2041,7 +2086,7 @@
 
 	if (coal > 0x3fff)
 		coal = 0x3fff;
-	wrl(mp, TX_FIFO_URGENT_THRESHOLD(mp->port_num), (coal & 0x3fff) << 4);
+	wrlp(mp, TX_FIFO_URGENT_THRESHOLD, (coal & 0x3fff) << 4);
 }
 
 static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp)
@@ -2070,9 +2115,9 @@
 	int err;
 	int i;
 
-	wrl(mp, INT_CAUSE(mp->port_num), 0);
-	wrl(mp, INT_CAUSE_EXT(mp->port_num), 0);
-	rdl(mp, INT_CAUSE_EXT(mp->port_num));
+	wrlp(mp, INT_CAUSE, 0);
+	wrlp(mp, INT_CAUSE_EXT, 0);
+	rdlp(mp, INT_CAUSE_EXT);
 
 	err = request_irq(dev->irq, mv643xx_eth_irq,
 			  IRQF_SHARED, dev->name, dev);
@@ -2081,8 +2126,6 @@
 		return -EAGAIN;
 	}
 
-	init_mac_tables(mp);
-
 	mv643xx_eth_recalc_skb_size(mp);
 
 	napi_enable(&mp->napi);
@@ -2121,8 +2164,8 @@
 	set_rx_coal(mp, 0);
 	set_tx_coal(mp, 0);
 
-	wrl(mp, INT_MASK_EXT(mp->port_num), INT_EXT_LINK_PHY | INT_EXT_TX);
-	wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT);
+	wrlp(mp, INT_MASK_EXT, INT_EXT_LINK_PHY | INT_EXT_TX);
+	wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT);
 
 	return 0;
 
@@ -2147,7 +2190,7 @@
 		txq_disable(mp->txq + i);
 
 	while (1) {
-		u32 ps = rdl(mp, PORT_STATUS(mp->port_num));
+		u32 ps = rdlp(mp, PORT_STATUS);
 
 		if ((ps & (TX_IN_PROGRESS | TX_FIFO_EMPTY)) == TX_FIFO_EMPTY)
 			break;
@@ -2155,11 +2198,11 @@
 	}
 
 	/* Reset the Enable bit in the Configuration Register */
-	data = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num));
+	data = rdlp(mp, PORT_SERIAL_CONTROL);
 	data &= ~(SERIAL_PORT_ENABLE		|
 		  DO_NOT_FORCE_LINK_FAIL	|
 		  FORCE_LINK_PASS);
-	wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), data);
+	wrlp(mp, PORT_SERIAL_CONTROL, data);
 }
 
 static int mv643xx_eth_stop(struct net_device *dev)
@@ -2167,8 +2210,8 @@
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
 	int i;
 
-	wrl(mp, INT_MASK(mp->port_num), 0x00000000);
-	rdl(mp, INT_MASK(mp->port_num));
+	wrlp(mp, INT_MASK, 0x00000000);
+	rdlp(mp, INT_MASK);
 
 	del_timer_sync(&mp->mib_counters_timer);
 
@@ -2261,12 +2304,12 @@
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
 
-	wrl(mp, INT_MASK(mp->port_num), 0x00000000);
-	rdl(mp, INT_MASK(mp->port_num));
+	wrlp(mp, INT_MASK, 0x00000000);
+	rdlp(mp, INT_MASK);
 
 	mv643xx_eth_irq(dev->irq, dev);
 
-	wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT);
+	wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT);
 }
 #endif
 
@@ -2314,8 +2357,8 @@
 	 * [21:8], or a 16-bit coal limit in bits [25,21:7] of the
 	 * SDMA config register.
 	 */
-	writel(0x02000000, msp->base + SDMA_CONFIG(0));
-	if (readl(msp->base + SDMA_CONFIG(0)) & 0x02000000)
+	writel(0x02000000, msp->base + 0x0400 + SDMA_CONFIG);
+	if (readl(msp->base + 0x0400 + SDMA_CONFIG) & 0x02000000)
 		msp->extended_rx_coal_limit = 1;
 	else
 		msp->extended_rx_coal_limit = 0;
@@ -2325,12 +2368,12 @@
 	 * yes, whether its associated registers are in the old or
 	 * the new place.
 	 */
-	writel(1, msp->base + TX_BW_MTU_MOVED(0));
-	if (readl(msp->base + TX_BW_MTU_MOVED(0)) & 1) {
+	writel(1, msp->base + 0x0400 + TX_BW_MTU_MOVED);
+	if (readl(msp->base + 0x0400 + TX_BW_MTU_MOVED) & 1) {
 		msp->tx_bw_control = TX_BW_CONTROL_NEW_LAYOUT;
 	} else {
-		writel(7, msp->base + TX_BW_RATE(0));
-		if (readl(msp->base + TX_BW_RATE(0)) & 7)
+		writel(7, msp->base + 0x0400 + TX_BW_RATE);
+		if (readl(msp->base + 0x0400 + TX_BW_RATE) & 7)
 			msp->tx_bw_control = TX_BW_CONTROL_OLD_LAYOUT;
 		else
 			msp->tx_bw_control = TX_BW_CONTROL_ABSENT;
@@ -2339,7 +2382,7 @@
 
 static int mv643xx_eth_shared_probe(struct platform_device *pdev)
 {
-	static int mv643xx_eth_version_printed = 0;
+	static int mv643xx_eth_version_printed;
 	struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data;
 	struct mv643xx_eth_shared_private *msp;
 	struct resource *res;
@@ -2563,10 +2606,10 @@
 {
 	u32 pscr;
 
-	pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num));
+	pscr = rdlp(mp, PORT_SERIAL_CONTROL);
 	if (pscr & SERIAL_PORT_ENABLE) {
 		pscr &= ~SERIAL_PORT_ENABLE;
-		wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
+		wrlp(mp, PORT_SERIAL_CONTROL, pscr);
 	}
 
 	pscr = MAX_RX_PACKET_9700BYTE | SERIAL_PORT_CONTROL_RESERVED;
@@ -2584,7 +2627,7 @@
 			pscr |= SET_FULL_DUPLEX_MODE;
 	}
 
-	wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);
+	wrlp(mp, PORT_SERIAL_CONTROL, pscr);
 }
 
 static int mv643xx_eth_probe(struct platform_device *pdev)
@@ -2593,7 +2636,6 @@
 	struct mv643xx_eth_private *mp;
 	struct net_device *dev;
 	struct resource *res;
-	DECLARE_MAC_BUF(mac);
 	int err;
 
 	pd = pdev->dev.platform_data;
@@ -2617,6 +2659,7 @@
 	platform_set_drvdata(pdev, mp);
 
 	mp->shared = platform_get_drvdata(pd->shared);
+	mp->base = mp->shared->base + 0x0400 + (pd->port_number << 10);
 	mp->port_num = pd->port_number;
 
 	mp->dev = dev;
@@ -2664,7 +2707,7 @@
 	dev->hard_start_xmit = mv643xx_eth_xmit;
 	dev->open = mv643xx_eth_open;
 	dev->stop = mv643xx_eth_stop;
-	dev->set_multicast_list = mv643xx_eth_set_rx_mode;
+	dev->set_rx_mode = mv643xx_eth_set_rx_mode;
 	dev->set_mac_address = mv643xx_eth_set_mac_address;
 	dev->do_ioctl = mv643xx_eth_ioctl;
 	dev->change_mtu = mv643xx_eth_change_mtu;
@@ -2687,8 +2730,8 @@
 	if (err)
 		goto out;
 
-	dev_printk(KERN_NOTICE, &dev->dev, "port %d with MAC address %s\n",
-		   mp->port_num, print_mac(mac, dev->dev_addr));
+	dev_printk(KERN_NOTICE, &dev->dev, "port %d with MAC address %pM\n",
+		   mp->port_num, dev->dev_addr);
 
 	if (mp->tx_desc_sram_size > 0)
 		dev_printk(KERN_NOTICE, &dev->dev, "configured with sram\n");
@@ -2721,8 +2764,8 @@
 	struct mv643xx_eth_private *mp = platform_get_drvdata(pdev);
 
 	/* Mask all interrupts on ethernet port */
-	wrl(mp, INT_MASK(mp->port_num), 0);
-	rdl(mp, INT_MASK(mp->port_num));
+	wrlp(mp, INT_MASK, 0);
+	rdlp(mp, INT_MASK);
 
 	if (netif_running(mp->dev))
 		port_reset(mp);
diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c
index 06ca425..435e5a8 100644
--- a/drivers/net/mvme147.c
+++ b/drivers/net/mvme147.c
@@ -67,7 +67,6 @@
 	u_long *addr;
 	u_long address;
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	if (!MACH_IS_MVME147 || called)
 		return ERR_PTR(-ENODEV);
@@ -102,11 +101,11 @@
 	dev->dev_addr[3]=address&0xff;
 
 	printk("%s: MVME147 at 0x%08lx, irq %d, "
-	       "Hardware Address %s\n",
+	       "Hardware Address %pM\n",
 	       dev->name, dev->base_addr, MVME147_LANCE_IRQ,
-	       print_mac(mac, dev->dev_addr));
+	       dev->dev_addr);
 
-	lp = (struct m147lance_private *)dev->priv;
+	lp = netdev_priv(dev);
 	lp->ram = __get_dma_pages(GFP_ATOMIC, 3);	/* 16K */
 	if (!lp->ram)
 	{
@@ -190,7 +189,7 @@
 
 void __exit cleanup_module(void)
 {
-	struct m147lance_private *lp = dev_mvme147_lance->priv;
+	struct m147lance_private *lp = netdev_priv(dev_mvme147_lance);
 	unregister_netdev(dev_mvme147_lance);
 	free_pages(lp->ram, 3);
 	free_netdev(dev_mvme147_lance);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index b378670..5e70180 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -75,7 +75,7 @@
 #include "myri10ge_mcp.h"
 #include "myri10ge_mcp_gen_header.h"
 
-#define MYRI10GE_VERSION_STR "1.4.3-1.378"
+#define MYRI10GE_VERSION_STR "1.4.4-1.395"
 
 MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
 MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -1024,7 +1024,7 @@
 			ss->dca_tag = NULL;
 		}
 	}
-#endif				/* CONFIG_DCA */
+#endif				/* CONFIG_MYRI10GE_DCA */
 
 	/* reset mcp/driver shared state back to 0 */
 
@@ -1121,7 +1121,7 @@
 		myri10ge_teardown_dca(mgp);
 	return 0;
 }
-#endif				/* CONFIG_DCA */
+#endif				/* CONFIG_MYRI10GE_DCA */
 
 static inline void
 myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst,
@@ -1309,7 +1309,7 @@
 
 	skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16);
 	if (unlikely(skb == NULL)) {
-		mgp->stats.rx_dropped++;
+		ss->stats.rx_dropped++;
 		do {
 			i--;
 			put_page(rx_frags[i].page);
@@ -1334,7 +1334,6 @@
 			myri10ge_vlan_ip_csum(skb, csum);
 	}
 	netif_receive_skb(skb);
-	dev->last_rx = jiffies;
 	return 1;
 }
 
@@ -1504,7 +1503,6 @@
 {
 	struct myri10ge_slice_state *ss =
 	    container_of(napi, struct myri10ge_slice_state, napi);
-	struct net_device *netdev = ss->mgp->dev;
 	int work_done;
 
 #ifdef CONFIG_MYRI10GE_DCA
@@ -1516,7 +1514,7 @@
 	work_done = myri10ge_clean_rx_done(ss, budget);
 
 	if (work_done < budget) {
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 		put_be32(htonl(3), ss->irq_claim);
 	}
 	return work_done;
@@ -1534,7 +1532,7 @@
 	/* an interrupt on a non-zero receive-only slice is implicitly
 	 * valid  since MSI-X irqs are not shared */
 	if ((mgp->dev->real_num_tx_queues == 1) && (ss != mgp->ss)) {
-		netif_rx_schedule(ss->dev, &ss->napi);
+		netif_rx_schedule(&ss->napi);
 		return (IRQ_HANDLED);
 	}
 
@@ -1545,7 +1543,7 @@
 	/* low bit indicates receives are present, so schedule
 	 * napi poll handler */
 	if (stats->valid & 1)
-		netif_rx_schedule(ss->dev, &ss->napi);
+		netif_rx_schedule(&ss->napi);
 
 	if (!mgp->msi_enabled && !mgp->msix_enabled) {
 		put_be32(0, mgp->irq_deassert);
@@ -2230,6 +2228,8 @@
 	*ip_hdr = iph;
 	if (iph->protocol != IPPROTO_TCP)
 		return -1;
+	if (iph->frag_off & htons(IP_MF | IP_OFFSET))
+		return -1;
 	*hdr_flags |= LRO_TCP;
 	*tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
 
@@ -2927,6 +2927,7 @@
 {
 	struct sk_buff *segs, *curr;
 	struct myri10ge_priv *mgp = netdev_priv(dev);
+	struct myri10ge_slice_state *ss;
 	int status;
 
 	segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6);
@@ -2953,8 +2954,9 @@
 	return 0;
 
 drop:
+	ss = &mgp->ss[skb_get_queue_mapping(skb)];
 	dev_kfree_skb_any(skb);
-	mgp->stats.tx_dropped += 1;
+	ss->stats.tx_dropped += 1;
 	return 0;
 }
 
@@ -2985,7 +2987,6 @@
 	struct dev_mc_list *mc_list;
 	__be32 data[2] = { 0, 0 };
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	/* can be called from atomic contexts,
 	 * pass 1 to force atomicity in myri10ge_send_cmd() */
@@ -3032,8 +3033,7 @@
 			printk(KERN_ERR "myri10ge: %s: Failed "
 			       "MXGEFW_JOIN_MULTICAST_GROUP, error status:"
 			       "%d\t", dev->name, err);
-			printk(KERN_ERR "MAC %s\n",
-			       print_mac(mac, mc_list->dmi_addr));
+			printk(KERN_ERR "MAC %pM\n", mc_list->dmi_addr);
 			goto abort;
 		}
 	}
@@ -3732,6 +3732,17 @@
 	myri10ge_load_firmware(mgp, 0);
 }
 
+static const struct net_device_ops myri10ge_netdev_ops = {
+	.ndo_open		= myri10ge_open,
+	.ndo_stop		= myri10ge_close,
+	.ndo_start_xmit		= myri10ge_xmit,
+	.ndo_get_stats		= myri10ge_get_stats,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= myri10ge_change_mtu,
+	.ndo_set_multicast_list = myri10ge_set_multicast_list,
+	.ndo_set_mac_address	= myri10ge_set_mac_address,
+};
+
 static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct net_device *netdev;
@@ -3740,6 +3751,7 @@
 	int i;
 	int status = -ENXIO;
 	int dac_enabled;
+	unsigned hdr_offset, ss_offset;
 
 	netdev = alloc_etherdev_mq(sizeof(*mgp), MYRI10GE_MAX_SLICES);
 	if (netdev == NULL) {
@@ -3807,14 +3819,6 @@
 	if (mgp->mtrr >= 0)
 		mgp->wc_enabled = 1;
 #endif
-	/* Hack.  need to get rid of these magic numbers */
-	mgp->sram_size =
-	    2 * 1024 * 1024 - (2 * (48 * 1024) + (32 * 1024)) - 0x100;
-	if (mgp->sram_size > mgp->board_span) {
-		dev_err(&pdev->dev, "board span %ld bytes too small\n",
-			mgp->board_span);
-		goto abort_with_mtrr;
-	}
 	mgp->sram = ioremap_wc(mgp->iomem_base, mgp->board_span);
 	if (mgp->sram == NULL) {
 		dev_err(&pdev->dev, "ioremap failed for %ld bytes at 0x%lx\n",
@@ -3822,9 +3826,19 @@
 		status = -ENXIO;
 		goto abort_with_mtrr;
 	}
+	hdr_offset =
+	    ntohl(__raw_readl(mgp->sram + MCP_HEADER_PTR_OFFSET)) & 0xffffc;
+	ss_offset = hdr_offset + offsetof(struct mcp_gen_header, string_specs);
+	mgp->sram_size = ntohl(__raw_readl(mgp->sram + ss_offset));
+	if (mgp->sram_size > mgp->board_span ||
+	    mgp->sram_size <= MYRI10GE_FW_OFFSET) {
+		dev_err(&pdev->dev,
+			"invalid sram_size %dB or board span %ldB\n",
+			mgp->sram_size, mgp->board_span);
+		goto abort_with_ioremap;
+	}
 	memcpy_fromio(mgp->eeprom_strings,
-		      mgp->sram + mgp->sram_size - MYRI10GE_EEPROM_STRINGS_SIZE,
-		      MYRI10GE_EEPROM_STRINGS_SIZE);
+		      mgp->sram + mgp->sram_size, MYRI10GE_EEPROM_STRINGS_SIZE);
 	memset(mgp->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE - 2, 0, 2);
 	status = myri10ge_read_mac_addr(mgp);
 	if (status)
@@ -3860,15 +3874,10 @@
 		myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;
 	if ((myri10ge_initial_mtu + ETH_HLEN) < 68)
 		myri10ge_initial_mtu = 68;
+
+	netdev->netdev_ops = &myri10ge_netdev_ops;
 	netdev->mtu = myri10ge_initial_mtu;
-	netdev->open = myri10ge_open;
-	netdev->stop = myri10ge_close;
-	netdev->hard_start_xmit = myri10ge_xmit;
-	netdev->get_stats = myri10ge_get_stats;
 	netdev->base_addr = mgp->iomem_base;
-	netdev->change_mtu = myri10ge_change_mtu;
-	netdev->set_multicast_list = myri10ge_set_multicast_list;
-	netdev->set_mac_address = myri10ge_set_mac_address;
 	netdev->features = mgp->features;
 
 	if (dac_enabled)
@@ -4019,7 +4028,7 @@
 	.next = NULL,
 	.priority = 0,
 };
-#endif				/* CONFIG_DCA */
+#endif				/* CONFIG_MYRI10GE_DCA */
 
 static __init int myri10ge_init_module(void)
 {
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h
index 9937210..11be150 100644
--- a/drivers/net/myri10ge/myri10ge_mcp.h
+++ b/drivers/net/myri10ge/myri10ge_mcp.h
@@ -111,61 +111,61 @@
 	MXGEFW_CMD_NONE = 0,
 	/* Reset the mcp, it is left in a safe state, waiting
 	 * for the driver to set all its parameters */
-	MXGEFW_CMD_RESET,
+	MXGEFW_CMD_RESET = 1,
 
 	/* get the version number of the current firmware..
 	 * (may be available in the eeprom strings..? */
-	MXGEFW_GET_MCP_VERSION,
+	MXGEFW_GET_MCP_VERSION = 2,
 
 	/* Parameters which must be set by the driver before it can
 	 * issue MXGEFW_CMD_ETHERNET_UP. They persist until the next
 	 * MXGEFW_CMD_RESET is issued */
 
-	MXGEFW_CMD_SET_INTRQ_DMA,
+	MXGEFW_CMD_SET_INTRQ_DMA = 3,
 	/* data0 = LSW of the host address
 	 * data1 = MSW of the host address
 	 * data2 = slice number if multiple slices are used
 	 */
 
-	MXGEFW_CMD_SET_BIG_BUFFER_SIZE,	/* in bytes, power of 2 */
-	MXGEFW_CMD_SET_SMALL_BUFFER_SIZE,	/* in bytes */
+	MXGEFW_CMD_SET_BIG_BUFFER_SIZE = 4,	/* in bytes, power of 2 */
+	MXGEFW_CMD_SET_SMALL_BUFFER_SIZE = 5,	/* in bytes */
 
 	/* Parameters which refer to lanai SRAM addresses where the
 	 * driver must issue PIO writes for various things */
 
-	MXGEFW_CMD_GET_SEND_OFFSET,
-	MXGEFW_CMD_GET_SMALL_RX_OFFSET,
-	MXGEFW_CMD_GET_BIG_RX_OFFSET,
+	MXGEFW_CMD_GET_SEND_OFFSET = 6,
+	MXGEFW_CMD_GET_SMALL_RX_OFFSET = 7,
+	MXGEFW_CMD_GET_BIG_RX_OFFSET = 8,
 	/* data0 = slice number if multiple slices are used */
 
-	MXGEFW_CMD_GET_IRQ_ACK_OFFSET,
-	MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET,
+	MXGEFW_CMD_GET_IRQ_ACK_OFFSET = 9,
+	MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET = 10,
 
 	/* Parameters which refer to rings stored on the MCP,
 	 * and whose size is controlled by the mcp */
 
-	MXGEFW_CMD_GET_SEND_RING_SIZE,	/* in bytes */
-	MXGEFW_CMD_GET_RX_RING_SIZE,	/* in bytes */
+	MXGEFW_CMD_GET_SEND_RING_SIZE = 11,	/* in bytes */
+	MXGEFW_CMD_GET_RX_RING_SIZE = 12,	/* in bytes */
 
 	/* Parameters which refer to rings stored in the host,
 	 * and whose size is controlled by the host.  Note that
 	 * all must be physically contiguous and must contain
 	 * a power of 2 number of entries.  */
 
-	MXGEFW_CMD_SET_INTRQ_SIZE,	/* in bytes */
+	MXGEFW_CMD_SET_INTRQ_SIZE = 13,	/* in bytes */
 #define MXGEFW_CMD_SET_INTRQ_SIZE_FLAG_NO_STRICT_SIZE_CHECK  (1 << 31)
 
 	/* command to bring ethernet interface up.  Above parameters
 	 * (plus mtu & mac address) must have been exchanged prior
 	 * to issuing this command  */
-	MXGEFW_CMD_ETHERNET_UP,
+	MXGEFW_CMD_ETHERNET_UP = 14,
 
 	/* command to bring ethernet interface down.  No further sends
 	 * or receives may be processed until an MXGEFW_CMD_ETHERNET_UP
 	 * is issued, and all interrupt queues must be flushed prior
 	 * to ack'ing this command */
 
-	MXGEFW_CMD_ETHERNET_DOWN,
+	MXGEFW_CMD_ETHERNET_DOWN = 15,
 
 	/* commands the driver may issue live, without resetting
 	 * the nic.  Note that increasing the mtu "live" should
@@ -173,40 +173,40 @@
 	 * sufficiently large to handle the new mtu.  Decreasing
 	 * the mtu live is safe */
 
-	MXGEFW_CMD_SET_MTU,
-	MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET,	/* in microseconds */
-	MXGEFW_CMD_SET_STATS_INTERVAL,	/* in microseconds */
-	MXGEFW_CMD_SET_STATS_DMA_OBSOLETE,	/* replaced by SET_STATS_DMA_V2 */
+	MXGEFW_CMD_SET_MTU = 16,
+	MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET = 17,	/* in microseconds */
+	MXGEFW_CMD_SET_STATS_INTERVAL = 18,	/* in microseconds */
+	MXGEFW_CMD_SET_STATS_DMA_OBSOLETE = 19,	/* replaced by SET_STATS_DMA_V2 */
 
-	MXGEFW_ENABLE_PROMISC,
-	MXGEFW_DISABLE_PROMISC,
-	MXGEFW_SET_MAC_ADDRESS,
+	MXGEFW_ENABLE_PROMISC = 20,
+	MXGEFW_DISABLE_PROMISC = 21,
+	MXGEFW_SET_MAC_ADDRESS = 22,
 
-	MXGEFW_ENABLE_FLOW_CONTROL,
-	MXGEFW_DISABLE_FLOW_CONTROL,
+	MXGEFW_ENABLE_FLOW_CONTROL = 23,
+	MXGEFW_DISABLE_FLOW_CONTROL = 24,
 
 	/* do a DMA test
 	 * data0,data1 = DMA address
 	 * data2       = RDMA length (MSH), WDMA length (LSH)
 	 * command return data = repetitions (MSH), 0.5-ms ticks (LSH)
 	 */
-	MXGEFW_DMA_TEST,
+	MXGEFW_DMA_TEST = 25,
 
-	MXGEFW_ENABLE_ALLMULTI,
-	MXGEFW_DISABLE_ALLMULTI,
+	MXGEFW_ENABLE_ALLMULTI = 26,
+	MXGEFW_DISABLE_ALLMULTI = 27,
 
 	/* returns MXGEFW_CMD_ERROR_MULTICAST
 	 * if there is no room in the cache
 	 * data0,MSH(data1) = multicast group address */
-	MXGEFW_JOIN_MULTICAST_GROUP,
+	MXGEFW_JOIN_MULTICAST_GROUP = 28,
 	/* returns MXGEFW_CMD_ERROR_MULTICAST
 	 * if the address is not in the cache,
 	 * or is equal to FF-FF-FF-FF-FF-FF
 	 * data0,MSH(data1) = multicast group address */
-	MXGEFW_LEAVE_MULTICAST_GROUP,
-	MXGEFW_LEAVE_ALL_MULTICAST_GROUPS,
+	MXGEFW_LEAVE_MULTICAST_GROUP = 29,
+	MXGEFW_LEAVE_ALL_MULTICAST_GROUPS = 30,
 
-	MXGEFW_CMD_SET_STATS_DMA_V2,
+	MXGEFW_CMD_SET_STATS_DMA_V2 = 31,
 	/* data0, data1 = bus addr,
 	 * data2 = sizeof(struct mcp_irq_data) from driver point of view, allows
 	 * adding new stuff to mcp_irq_data without changing the ABI
@@ -216,14 +216,14 @@
 	 * (in the upper 16 bits).
 	 */
 
-	MXGEFW_CMD_UNALIGNED_TEST,
+	MXGEFW_CMD_UNALIGNED_TEST = 32,
 	/* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned
 	 * chipset */
 
-	MXGEFW_CMD_UNALIGNED_STATUS,
+	MXGEFW_CMD_UNALIGNED_STATUS = 33,
 	/* return data = boolean, true if the chipset is known to be unaligned */
 
-	MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS,
+	MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS = 34,
 	/* data0 = number of big buffers to use.  It must be 0 or a power of 2.
 	 * 0 indicates that the NIC consumes as many buffers as they are required
 	 * for packet. This is the default behavior.
@@ -233,8 +233,8 @@
 	 * the NIC to be able to receive maximum-sized packets.
 	 */
 
-	MXGEFW_CMD_GET_MAX_RSS_QUEUES,
-	MXGEFW_CMD_ENABLE_RSS_QUEUES,
+	MXGEFW_CMD_GET_MAX_RSS_QUEUES = 35,
+	MXGEFW_CMD_ENABLE_RSS_QUEUES = 36,
 	/* data0 = number of slices n (0, 1, ..., n-1) to enable
 	 * data1 = interrupt mode | use of multiple transmit queues.
 	 * 0=share one INTx/MSI.
@@ -249,18 +249,18 @@
 #define MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE   0x1
 #define MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES 0x2
 
-	MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET,
-	MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA,
+	MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET = 37,
+	MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA = 38,
 	/* data0, data1 = bus address lsw, msw */
-	MXGEFW_CMD_GET_RSS_TABLE_OFFSET,
+	MXGEFW_CMD_GET_RSS_TABLE_OFFSET = 39,
 	/* get the offset of the indirection table */
-	MXGEFW_CMD_SET_RSS_TABLE_SIZE,
+	MXGEFW_CMD_SET_RSS_TABLE_SIZE = 40,
 	/* set the size of the indirection table */
-	MXGEFW_CMD_GET_RSS_KEY_OFFSET,
+	MXGEFW_CMD_GET_RSS_KEY_OFFSET = 41,
 	/* get the offset of the secret key */
-	MXGEFW_CMD_RSS_KEY_UPDATED,
+	MXGEFW_CMD_RSS_KEY_UPDATED = 42,
 	/* tell nic that the secret key's been updated */
-	MXGEFW_CMD_SET_RSS_ENABLE,
+	MXGEFW_CMD_SET_RSS_ENABLE = 43,
 	/* data0 = enable/disable rss
 	 * 0: disable rss.  nic does not distribute receive packets.
 	 * 1: enable rss.  nic distributes receive packets among queues.
@@ -277,7 +277,7 @@
 #define MXGEFW_RSS_HASH_TYPE_SRC_DST_PORT 0x5
 #define MXGEFW_RSS_HASH_TYPE_MAX 0x5
 
-	MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
+	MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE = 44,
 	/* Return data = the max. size of the entire headers of a IPv6 TSO packet.
 	 * If the header size of a IPv6 TSO packet is larger than the specified
 	 * value, then the driver must not use TSO.
@@ -286,7 +286,7 @@
 	 * always has enough header buffer to store maximum-sized headers.
 	 */
 
-	MXGEFW_CMD_SET_TSO_MODE,
+	MXGEFW_CMD_SET_TSO_MODE = 45,
 	/* data0 = TSO mode.
 	 * 0: Linux/FreeBSD style (NIC default)
 	 * 1: NDIS/NetBSD style
@@ -294,33 +294,37 @@
 #define MXGEFW_TSO_MODE_LINUX  0
 #define MXGEFW_TSO_MODE_NDIS   1
 
-	MXGEFW_CMD_MDIO_READ,
+	MXGEFW_CMD_MDIO_READ = 46,
 	/* data0 = dev_addr (PMA/PMD or PCS ...), data1 = register/addr */
-	MXGEFW_CMD_MDIO_WRITE,
+	MXGEFW_CMD_MDIO_WRITE = 47,
 	/* data0 = dev_addr,  data1 = register/addr, data2 = value  */
 
-	MXGEFW_CMD_XFP_I2C_READ,
-	/* Starts to get a fresh copy of one byte or of the whole xfp i2c table, the
+	MXGEFW_CMD_I2C_READ = 48,
+	/* Starts to get a fresh copy of one byte or of the module i2c table, the
 	 * obtained data is cached inside the xaui-xfi chip :
-	 *   data0 : "all" flag : 0 => get one byte, 1=> get 256 bytes,
-	 *   data1 : if (data0 == 0): index of byte to refresh [ not used otherwise ]
+	 *   data0 :  0 => get one byte, 1=> get 256 bytes
+	 *   data1 :  If data0 == 0: location to refresh
+	 *               bit 7:0  register location
+	 *               bit 8:15 is the i2c slave addr (0 is interpreted as 0xA1)
+	 *               bit 23:16 is the i2c bus number (for multi-port NICs)
+	 *            If data0 == 1: unused
 	 * The operation might take ~1ms for a single byte or ~65ms when refreshing all 256 bytes
-	 * During the i2c operation,  MXGEFW_CMD_XFP_I2C_READ or MXGEFW_CMD_XFP_BYTE attempts
+	 * During the i2c operation,  MXGEFW_CMD_I2C_READ or MXGEFW_CMD_I2C_BYTE attempts
 	 *  will return MXGEFW_CMD_ERROR_BUSY
 	 */
-	MXGEFW_CMD_XFP_BYTE,
+	MXGEFW_CMD_I2C_BYTE = 49,
 	/* Return the last obtained copy of a given byte in the xfp i2c table
-	 * (copy cached during the last relevant MXGEFW_CMD_XFP_I2C_READ)
+	 * (copy cached during the last relevant MXGEFW_CMD_I2C_READ)
 	 *   data0 : index of the desired table entry
 	 *  Return data = the byte stored at the requested index in the table
 	 */
 
-	MXGEFW_CMD_GET_VPUMP_OFFSET,
+	MXGEFW_CMD_GET_VPUMP_OFFSET = 50,
 	/* Return data = NIC memory offset of mcp_vpump_public_global */
-	MXGEFW_CMD_RESET_VPUMP,
+	MXGEFW_CMD_RESET_VPUMP = 51,
 	/* Resets the VPUMP state */
 
-	MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE,
+	MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE = 52,
 	/* data0 = mcp_slot type to use.
 	 * 0 = the default 4B mcp_slot
 	 * 1 = 8B mcp_slot_8
@@ -328,7 +332,7 @@
 #define MXGEFW_RSS_MCP_SLOT_TYPE_MIN        0
 #define MXGEFW_RSS_MCP_SLOT_TYPE_WITH_HASH  1
 
-	MXGEFW_CMD_SET_THROTTLE_FACTOR,
+	MXGEFW_CMD_SET_THROTTLE_FACTOR = 53,
 	/* set the throttle factor for ethp_z8e
 	 * data0 = throttle_factor
 	 * throttle_factor = 256 * pcie-raw-speed / tx_speed
@@ -344,45 +348,50 @@
 	 * with tx_boundary == 4096, max-throttle-factor == 4095 => min-speed == 1Gb/s
 	 */
 
-	MXGEFW_CMD_VPUMP_UP,
+	MXGEFW_CMD_VPUMP_UP = 54,
 	/* Allocates VPump Connection, Send Request and Zero copy buffer address tables */
-	MXGEFW_CMD_GET_VPUMP_CLK,
+	MXGEFW_CMD_GET_VPUMP_CLK = 55,
 	/* Get the lanai clock */
 
-	MXGEFW_CMD_GET_DCA_OFFSET,
+	MXGEFW_CMD_GET_DCA_OFFSET = 56,
 	/* offset of dca control for WDMAs */
 
 	/* VMWare NetQueue commands */
-	MXGEFW_CMD_NETQ_GET_FILTERS_PER_QUEUE,
-	MXGEFW_CMD_NETQ_ADD_FILTER,
+	MXGEFW_CMD_NETQ_GET_FILTERS_PER_QUEUE = 57,
+	MXGEFW_CMD_NETQ_ADD_FILTER = 58,
 	/* data0 = filter_id << 16 | queue << 8 | type */
 	/* data1 = MS4 of MAC Addr */
 	/* data2 = LS2_MAC << 16 | VLAN_tag */
-	MXGEFW_CMD_NETQ_DEL_FILTER,
+	MXGEFW_CMD_NETQ_DEL_FILTER = 59,
 	/* data0 = filter_id */
-	MXGEFW_CMD_NETQ_QUERY1,
-	MXGEFW_CMD_NETQ_QUERY2,
-	MXGEFW_CMD_NETQ_QUERY3,
-	MXGEFW_CMD_NETQ_QUERY4,
+	MXGEFW_CMD_NETQ_QUERY1 = 60,
+	MXGEFW_CMD_NETQ_QUERY2 = 61,
+	MXGEFW_CMD_NETQ_QUERY3 = 62,
+	MXGEFW_CMD_NETQ_QUERY4 = 63,
 
+	MXGEFW_CMD_RELAX_RXBUFFER_ALIGNMENT = 64,
+	/* When set, small receive buffers can cross page boundaries.
+	 * Both small and big receive buffers may start at any address.
+	 * This option has performance implications, so use with caution.
+	 */
 };
 
 enum myri10ge_mcp_cmd_status {
 	MXGEFW_CMD_OK = 0,
-	MXGEFW_CMD_UNKNOWN,
-	MXGEFW_CMD_ERROR_RANGE,
-	MXGEFW_CMD_ERROR_BUSY,
-	MXGEFW_CMD_ERROR_EMPTY,
-	MXGEFW_CMD_ERROR_CLOSED,
-	MXGEFW_CMD_ERROR_HASH_ERROR,
-	MXGEFW_CMD_ERROR_BAD_PORT,
-	MXGEFW_CMD_ERROR_RESOURCES,
-	MXGEFW_CMD_ERROR_MULTICAST,
-	MXGEFW_CMD_ERROR_UNALIGNED,
-	MXGEFW_CMD_ERROR_NO_MDIO,
-	MXGEFW_CMD_ERROR_XFP_FAILURE,
-	MXGEFW_CMD_ERROR_XFP_ABSENT,
-	MXGEFW_CMD_ERROR_BAD_PCIE_LINK
+	MXGEFW_CMD_UNKNOWN = 1,
+	MXGEFW_CMD_ERROR_RANGE = 2,
+	MXGEFW_CMD_ERROR_BUSY = 3,
+	MXGEFW_CMD_ERROR_EMPTY = 4,
+	MXGEFW_CMD_ERROR_CLOSED = 5,
+	MXGEFW_CMD_ERROR_HASH_ERROR = 6,
+	MXGEFW_CMD_ERROR_BAD_PORT = 7,
+	MXGEFW_CMD_ERROR_RESOURCES = 8,
+	MXGEFW_CMD_ERROR_MULTICAST = 9,
+	MXGEFW_CMD_ERROR_UNALIGNED = 10,
+	MXGEFW_CMD_ERROR_NO_MDIO = 11,
+	MXGEFW_CMD_ERROR_I2C_FAILURE = 12,
+	MXGEFW_CMD_ERROR_I2C_ABSENT = 13,
+	MXGEFW_CMD_ERROR_BAD_PCIE_LINK = 14
 };
 
 #define MXGEFW_OLD_IRQ_DATA_LEN 40
diff --git a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
index a8662ea..caa6cbb 100644
--- a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
+++ b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
@@ -41,6 +41,8 @@
 	unsigned short handoff_id_major;	/* must be equal */
 	unsigned short handoff_id_caps;	/* bitfield: new mcp must have superset */
 	unsigned msix_table_addr;	/* start address of msix table in firmware */
+	unsigned bss_addr;	/* start of bss */
+	unsigned features;
 	/* 8 */
 };
 
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 3ad7589..899ed06 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -318,13 +318,10 @@
 #ifdef DEBUG_HEADER
 static void dump_ehdr(struct ethhdr *ehdr)
 {
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
-	printk("ehdr[h_dst(%s)"
-	       "h_source(%s)"
+	printk("ehdr[h_dst(%pM)"
+	       "h_source(%pM)"
 	       "h_proto(%04x)]\n",
-	       print_mac(mac, ehdr->h_dest), print_mac(mac2, ehdr->h_source),
-	       ehdr->h_proto);
+	       ehdr->h_dest, ehdr->h_source, ehdr->h_proto);
 }
 
 static void dump_ehdr_and_myripad(unsigned char *stuff)
@@ -528,7 +525,6 @@
 		DRX(("prot[%04x] netif_rx ", skb->protocol));
 		netif_rx(skb);
 
-		dev->last_rx = jiffies;
 		dev->stats.rx_packets++;
 		dev->stats.rx_bytes += len;
 	next:
@@ -540,7 +536,7 @@
 static irqreturn_t myri_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev		= (struct net_device *) dev_id;
-	struct myri_eth *mp		= (struct myri_eth *) dev->priv;
+	struct myri_eth *mp		= netdev_priv(dev);
 	void __iomem *lregs		= mp->lregs;
 	struct myri_channel __iomem *chan = &mp->shmem->channel;
 	unsigned long flags;
@@ -579,14 +575,14 @@
 
 static int myri_open(struct net_device *dev)
 {
-	struct myri_eth *mp = (struct myri_eth *) dev->priv;
+	struct myri_eth *mp = netdev_priv(dev);
 
 	return myri_init(mp, in_interrupt());
 }
 
 static int myri_close(struct net_device *dev)
 {
-	struct myri_eth *mp = (struct myri_eth *) dev->priv;
+	struct myri_eth *mp = netdev_priv(dev);
 
 	myri_clean_rings(mp);
 	return 0;
@@ -594,7 +590,7 @@
 
 static void myri_tx_timeout(struct net_device *dev)
 {
-	struct myri_eth *mp = (struct myri_eth *) dev->priv;
+	struct myri_eth *mp = netdev_priv(dev);
 
 	printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 
@@ -605,7 +601,7 @@
 
 static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct myri_eth *mp = (struct myri_eth *) dev->priv;
+	struct myri_eth *mp = netdev_priv(dev);
 	struct sendq __iomem *sq = mp->sq;
 	struct myri_txd __iomem *txd;
 	unsigned long flags;
@@ -905,7 +901,6 @@
 	struct device_node *dp = op->node;
 	static unsigned version_printed;
 	struct net_device *dev;
-	DECLARE_MAC_BUF(mac);
 	struct myri_eth *mp;
 	const void *prop;
 	static int num;
@@ -1088,15 +1083,15 @@
 
 	num++;
 
-	printk("%s: MyriCOM MyriNET Ethernet %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk("%s: MyriCOM MyriNET Ethernet %pM\n",
+	       dev->name, dev->dev_addr);
 
 	return 0;
 
 err_free_irq:
 	free_irq(dev->irq, dev);
 err:
-	/* This will also free the co-allocated 'dev->priv' */
+	/* This will also free the co-allocated private data*/
 	free_netdev(dev);
 	return -ENODEV;
 }
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index f7fa394..478edb9 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -792,7 +792,6 @@
 	const int pcibar = 1; /* PCI base address register */
 	int prev_eedata;
 	u32 tmp;
-	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -948,10 +947,10 @@
 
 	if (netif_msg_drv(np)) {
 		printk(KERN_INFO "natsemi %s: %s at %#08llx "
-		       "(%s), %s, IRQ %d",
+		       "(%s), %pM, IRQ %d",
 		       dev->name, natsemi_pci_info[chip_idx].name,
 		       (unsigned long long)iostart, pci_name(np->pci_dev),
-		       print_mac(mac, dev->dev_addr), irq);
+		       dev->dev_addr, irq);
 		if (dev->if_port == PORT_TP)
 			printk(", port TP.\n");
 		else if (np->ignore_phy)
@@ -2194,10 +2193,10 @@
 
 	prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]);
 
-	if (netif_rx_schedule_prep(dev, &np->napi)) {
+	if (netif_rx_schedule_prep(&np->napi)) {
 		/* Disable interrupts and register for poll */
 		natsemi_irq_disable(dev);
-		__netif_rx_schedule(dev, &np->napi);
+		__netif_rx_schedule(&np->napi);
 	} else
 		printk(KERN_WARNING
 	       	       "%s: Ignoring interrupt, status %#08x, mask %#08x.\n",
@@ -2249,7 +2248,7 @@
 		np->intr_status = readl(ioaddr + IntrStatus);
 	} while (np->intr_status);
 
-	netif_rx_complete(dev, napi);
+	netif_rx_complete(napi);
 
 	/* Reenable interrupts providing nothing is trying to shut
 	 * the chip down. */
@@ -2362,7 +2361,6 @@
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_receive_skb(skb);
-			dev->last_rx = jiffies;
 			np->stats.rx_packets++;
 			np->stats.rx_bytes += pkt_len;
 		}
diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c
index fbc7531..b572391 100644
--- a/drivers/net/ne-h8300.c
+++ b/drivers/net/ne-h8300.c
@@ -167,7 +167,7 @@
 #ifndef MODULE
 struct net_device * __init ne_probe(int unit)
 {
-	struct net_device *dev = ____alloc_ei_netdev(0);
+	struct net_device *dev = alloc_ei_netdev();
 	int err;
 
 	if (!dev)
@@ -193,6 +193,21 @@
 }
 #endif
 
+static const struct net_device_ops ne_netdev_ops = {
+	.ndo_open		= ne_open,
+	.ndo_stop		= ne_close,
+
+	.ndo_start_xmit		= ei_start_xmit,
+	.ndo_tx_timeout		= ei_tx_timeout,
+	.ndo_get_stats		= ei_get_stats,
+	.ndo_set_multicast_list = ei_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= ei_poll,
+#endif
+};
+
 static int __init ne_probe1(struct net_device *dev, int ioaddr)
 {
 	int i;
@@ -204,7 +219,6 @@
 	static unsigned version_printed;
 	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
 	unsigned char bus_width;
-	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -299,7 +313,7 @@
 
 	for(i = 0; i < ETHER_ADDR_LEN; i++)
 		dev->dev_addr[i] = SA_prom[i];
-	printk(" %s\n", print_mac(mac, dev->dev_addr));
+	printk(" %pM\n", dev->dev_addr);
 
 	printk("%s: %s found at %#x, using IRQ %d.\n",
 		dev->name, name, ioaddr, dev->irq);
@@ -320,11 +334,9 @@
 	ei_status.block_output = &ne_block_output;
 	ei_status.get_8390_hdr = &ne_get_8390_hdr;
 	ei_status.priv = 0;
-	dev->open = &ne_open;
-	dev->stop = &ne_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = __ei_poll;
-#endif
+
+	dev->netdev_ops = &ne_netdev_ops;
+
 	__NS8390_init(dev, 0);
 
 	ret = register_netdev(dev);
@@ -625,7 +637,7 @@
 	int err;
 
 	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
-		struct net_device *dev = ____alloc_ei_netdev(0);
+		struct net_device *dev = alloc_ei_netdev();
 		if (!dev)
 			break;
 		if (io[this_dev]) {
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index eb681c0..5c3e242 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -174,9 +174,6 @@
 static int ne_probe1(struct net_device *dev, unsigned long ioaddr);
 static int ne_probe_isapnp(struct net_device *dev);
 
-static int ne_open(struct net_device *dev);
-static int ne_close(struct net_device *dev);
-
 static void ne_reset_8390(struct net_device *dev);
 static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 			  int ring_page);
@@ -297,7 +294,6 @@
 	int neX000, ctron, copam, bad_card;
 	int reg0, ret;
 	static unsigned version_printed;
-	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -517,7 +513,7 @@
 	}
 #endif
 
-	printk("%s\n", print_mac(mac, dev->dev_addr));
+	printk("%pM\n", dev->dev_addr);
 
 	ei_status.name = name;
 	ei_status.tx_start_page = start_page;
@@ -537,11 +533,8 @@
 	ei_status.block_output = &ne_block_output;
 	ei_status.get_8390_hdr = &ne_get_8390_hdr;
 	ei_status.priv = 0;
-	dev->open = &ne_open;
-	dev->stop = &ne_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = eip_poll;
-#endif
+
+	dev->netdev_ops = &eip_netdev_ops;
 	NS8390p_init(dev, 0);
 
 	ret = register_netdev(dev);
@@ -558,20 +551,6 @@
 	return ret;
 }
 
-static int ne_open(struct net_device *dev)
-{
-	eip_open(dev);
-	return 0;
-}
-
-static int ne_close(struct net_device *dev)
-{
-	if (ei_debug > 1)
-		printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
-	eip_close(dev);
-	return 0;
-}
-
 /* Hard reset the card.  This used to pause for the same period that a
    8390 reset command required, but that shouldn't be necessary. */
 
@@ -950,7 +929,7 @@
 }
 
 #ifdef MODULE
-int __init init_module()
+int __init init_module(void)
 {
 	int retval;
 	ne_add_devices();
diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
index 332df75..a53bb20 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ne2.c
@@ -137,9 +137,6 @@
 
 static int ne2_probe1(struct net_device *dev, int slot);
 
-static int ne_open(struct net_device *dev);
-static int ne_close(struct net_device *dev);
-
 static void ne_reset_8390(struct net_device *dev);
 static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 		int ring_page);
@@ -302,7 +299,6 @@
 static int ne2_procinfo(char *buf, int slot, struct net_device *dev)
 {
 	int len=0;
-	DECLARE_MAC_BUF(mac);
 
 	len += sprintf(buf+len, "The NE/2 Ethernet Adapter\n" );
 	len += sprintf(buf+len, "Driver written by Wim Dumon ");
@@ -313,7 +309,7 @@
 	len += sprintf(buf+len, "Based on the original NE2000 drivers\n" );
 	len += sprintf(buf+len, "Base IO: %#x\n", (unsigned int)dev->base_addr);
 	len += sprintf(buf+len, "IRQ    : %d\n", dev->irq);
-	len += sprintf(buf+len, "HW addr : %s\n", print_mac(mac, dev->dev_addr));
+	len += sprintf(buf+len, "HW addr : %pM\n", dev->dev_addr);
 
 	return len;
 }
@@ -326,7 +322,6 @@
 	const char *name = "NE/2";
 	int start_page, stop_page;
 	static unsigned version_printed;
-	DECLARE_MAC_BUF(mac);
 
 	if (ei_debug && version_printed++ == 0)
 		printk(version);
@@ -469,7 +464,7 @@
 	for(i = 0; i < ETHER_ADDR_LEN; i++)
 		dev->dev_addr[i] = SA_prom[i];
 
-	printk(" %s\n", print_mac(mac, dev->dev_addr));
+	printk(" %pM\n", dev->dev_addr);
 
 	printk("%s: %s found at %#x, using IRQ %d.\n",
 			dev->name, name, base_addr, dev->irq);
@@ -494,11 +489,7 @@
 
 	ei_status.priv = slot;
 
-	dev->open = &ne_open;
-	dev->stop = &ne_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = eip_poll;
-#endif
+	dev->netdev_ops = &eip_netdev_ops;
 	NS8390p_init(dev, 0);
 
 	retval = register_netdev(dev);
@@ -513,20 +504,6 @@
 	return retval;
 }
 
-static int ne_open(struct net_device *dev)
-{
-	eip_open(dev);
-	return 0;
-}
-
-static int ne_close(struct net_device *dev)
-{
-	if (ei_debug > 1)
-		printk("%s: Shutting down ethercard.\n", dev->name);
-	eip_close(dev);
-	return 0;
-}
-
 /* Hard reset the card.  This used to pause for the same period that a
    8390 reset command required, but that shouldn't be necessary. */
 static void ne_reset_8390(struct net_device *dev)
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index de0de74..62f20ba 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -200,6 +200,19 @@
   in the 'dev' and 'ei_status' structures.
 */
 
+static const struct net_device_ops ne2k_netdev_ops = {
+	.ndo_open		= ne2k_pci_open,
+	.ndo_stop		= ne2k_pci_close,
+	.ndo_start_xmit		= ei_start_xmit,
+	.ndo_tx_timeout		= ei_tx_timeout,
+	.ndo_get_stats		= ei_get_stats,
+	.ndo_set_multicast_list = ei_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller = ei_poll,
+#endif
+};
 
 static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
 				     const struct pci_device_id *ent)
@@ -212,7 +225,6 @@
 	static unsigned int fnd_cnt;
 	long ioaddr;
 	int flags = pci_clone_list[chip_idx].flags;
-	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -266,6 +278,8 @@
 		dev_err(&pdev->dev, "cannot allocate ethernet device\n");
 		goto err_out_free_res;
 	}
+	dev->netdev_ops = &ne2k_netdev_ops;
+
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	/* Reset card. Who knows what dain-bramaged state it was left in. */
@@ -354,12 +368,8 @@
 	ei_status.block_output = &ne2k_pci_block_output;
 	ei_status.get_8390_hdr = &ne2k_pci_get_8390_hdr;
 	ei_status.priv = (unsigned long) pdev;
-	dev->open = &ne2k_pci_open;
-	dev->stop = &ne2k_pci_close;
+
 	dev->ethtool_ops = &ne2k_pci_ethtool_ops;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = ei_poll;
-#endif
 	NS8390_init(dev, 0);
 
 	i = register_netdev(dev);
@@ -368,9 +378,9 @@
 
 	for(i = 0; i < 6; i++)
 		dev->dev_addr[i] = SA_prom[i];
-	printk("%s: %s found at %#lx, IRQ %d, %s.\n",
+	printk("%s: %s found at %#lx, IRQ %d, %pM.\n",
 	       dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq,
-	       print_mac(mac, dev->dev_addr));
+	       dev->dev_addr);
 
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
@@ -626,7 +636,7 @@
 static void ne2k_pci_get_drvinfo(struct net_device *dev,
 				 struct ethtool_drvinfo *info)
 {
-	struct ei_device *ei = dev->priv;
+	struct ei_device *ei = netdev_priv(dev);
 	struct pci_dev *pci_dev = (struct pci_dev *) ei->priv;
 
 	strcpy(info->driver, DRV_NAME);
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
index 425043a..fac43fd 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -45,9 +45,6 @@
 
 #define DRV_NAME "ne3210"
 
-static int ne3210_open(struct net_device *dev);
-static int ne3210_close(struct net_device *dev);
-
 static void ne3210_reset_8390(struct net_device *dev);
 
 static void ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
@@ -99,7 +96,6 @@
 	int i, retval, port_index;
 	struct eisa_device *edev = to_eisa_device (device);
 	struct net_device *dev;
-	DECLARE_MAC_BUF(mac);
 
 	/* Allocate dev->priv and fill in 8390 specific dev fields. */
 	if (!(dev = alloc_ei_netdev ())) {
@@ -131,8 +127,8 @@
 	port_index = inb(ioaddr + NE3210_CFG2) >> 6;
 	for(i = 0; i < ETHER_ADDR_LEN; i++)
 		dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i);
-	printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %s.\n",
-		edev->slot, ifmap[port_index], print_mac(mac, dev->dev_addr));
+	printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %pM.\n",
+		edev->slot, ifmap[port_index], dev->dev_addr);
 
 	/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
 	dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
@@ -200,11 +196,8 @@
 	ei_status.block_output = &ne3210_block_output;
 	ei_status.get_8390_hdr = &ne3210_get_8390_hdr;
 
-	dev->open = &ne3210_open;
-	dev->stop = &ne3210_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = ei_poll;
-#endif
+	dev->netdev_ops = &ei_netdev_ops;
+
 	dev->if_port = ifmap_val[port_index];
 
 	if ((retval = register_netdev (dev)))
@@ -321,22 +314,6 @@
 	memcpy_toio(shmem, buf, count);
 }
 
-static int ne3210_open(struct net_device *dev)
-{
-	ei_open(dev);
-	return 0;
-}
-
-static int ne3210_close(struct net_device *dev)
-{
-
-	if (ei_debug > 1)
-		printk("%s: Shutting down ethercard.\n", dev->name);
-
-	ei_close(dev);
-	return 0;
-}
-
 static struct eisa_device_id ne3210_ids[] = {
 	{ "EGL0101" },
 	{ "NVL1801" },
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 9681618..d304d38 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -307,17 +307,14 @@
 static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
 {
 	struct net_device *dev = nt->np.dev;
+	static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-	DECLARE_MAC_BUF(mac);
-	return snprintf(buf, PAGE_SIZE, "%s\n", dev ?
-			print_mac(mac, dev->dev_addr) : "ff:ff:ff:ff:ff:ff");
+	return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast);
 }
 
 static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf)
 {
-	DECLARE_MAC_BUF(mac);
-	return snprintf(buf, PAGE_SIZE, "%s\n",
-			print_mac(mac, nt->np.remote_mac));
+	return snprintf(buf, PAGE_SIZE, "%pM\n", nt->np.remote_mac);
 }
 
 /*
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index b289a0a..1861d5b 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -165,7 +165,6 @@
 	pfifo_push(EMPTY_PTR_FIFO(priv->id),
 		FIFO_PTR_SEGMENT(seg) | FIFO_PTR_FRAMENO(frameno));
 
-	ndev->last_rx = jiffies;
 	skb->protocol = eth_type_trans(skb, ndev);
 	netif_rx(skb);
 	ndev->stats.rx_packets++;
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index b974ca0..e45ce29 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -275,11 +275,11 @@
 	} else
 		return -EOPNOTSUPP;
 
-	if (netif_running(dev)) {
-		dev->stop(dev);
-		dev->open(dev);
-	}
-	return 0;
+	if (!netif_running(dev))
+		return 0;
+
+	dev->netdev_ops->ndo_stop(dev);
+	return dev->netdev_ops->ndo_open(dev);
 }
 
 static int netxen_nic_get_regs_len(struct net_device *dev)
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 84978f8..aa6e603 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -537,7 +537,7 @@
 static int nx_p3_sre_macaddr_change(struct net_device *dev,
 		u8 *addr, unsigned op)
 {
-	struct netxen_adapter *adapter = (struct netxen_adapter *)dev->priv;
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	nx_nic_req_t req;
 	nx_mac_req_t mac_req;
 	int rv;
@@ -1459,7 +1459,7 @@
 			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2);
 		else
 			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
-		if (mem_ptr == 0UL) {
+		if (mem_ptr == NULL) {
 			*(uint8_t  *)data = 0;
 			return -1;
 		}
@@ -1533,7 +1533,7 @@
 			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2);
 		else
 			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
-		if (mem_ptr == 0UL)
+		if (mem_ptr == NULL)
 			return -1;
 		addr = mem_ptr;
 		addr += start & (PAGE_SIZE - 1);
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 5bba675..d924468 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -1285,9 +1285,7 @@
 		}
 		adapter->stats.rxdropped++;
 	} else {
-
 		netif_receive_skb(skb);
-		netdev->last_rx = jiffies;
 
 		adapter->stats.no_rcv++;
 		adapter->stats.rxbytes += length;
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 6ef3f0d..ba01524 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -439,7 +439,6 @@
 	int i;
 	unsigned char *p;
 	__le64 mac_addr;
-	DECLARE_MAC_BUF(mac);
 	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
 
@@ -462,15 +461,39 @@
 
 	/* set station address */
 
-	if (!is_valid_ether_addr(netdev->perm_addr)) {
-		dev_warn(&pdev->dev, "Bad MAC address %s.\n",
-				print_mac(mac, netdev->dev_addr));
-	} else
+	if (!is_valid_ether_addr(netdev->perm_addr))
+		dev_warn(&pdev->dev, "Bad MAC address %pM.\n", netdev->dev_addr);
+	else
 		adapter->macaddr_set(adapter, netdev->dev_addr);
 
 	return 0;
 }
 
+static void netxen_set_multicast_list(struct net_device *dev)
+{
+	struct netxen_adapter *adapter = netdev_priv(dev);
+
+	if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+		netxen_p3_nic_set_multi(dev);
+	else
+		netxen_p2_nic_set_multi(dev);
+}
+
+static const struct net_device_ops netxen_netdev_ops = {
+	.ndo_open	   = netxen_nic_open,
+	.ndo_stop	   = netxen_nic_close,
+	.ndo_start_xmit    = netxen_nic_xmit_frame,
+	.ndo_get_stats	   = netxen_nic_get_stats,
+	.ndo_validate_addr = eth_validate_addr,
+	.ndo_set_multicast_list = netxen_set_multicast_list,
+	.ndo_set_mac_address    = netxen_nic_set_mac,
+	.ndo_change_mtu	   = netxen_nic_change_mtu,
+	.ndo_tx_timeout	   = netxen_tx_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller = netxen_nic_poll_controller,
+#endif
+};
+
 /*
  * netxen_nic_probe()
  *
@@ -543,7 +566,7 @@
 
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
-	adapter = netdev->priv;
+	adapter = netdev_priv(netdev);
 	adapter->netdev  = netdev;
 	adapter->pdev    = pdev;
 	adapter->ahw.pci_func  = pci_func_id;
@@ -682,25 +705,13 @@
 	else
 		adapter->max_mc_count = 16;
 
-	netdev->open		   = netxen_nic_open;
-	netdev->stop		   = netxen_nic_close;
-	netdev->hard_start_xmit    = netxen_nic_xmit_frame;
-	netdev->get_stats	   = netxen_nic_get_stats;
-	if (NX_IS_REVISION_P3(revision_id))
-		netdev->set_multicast_list = netxen_p3_nic_set_multi;
-	else
-		netdev->set_multicast_list = netxen_p2_nic_set_multi;
-	netdev->set_mac_address    = netxen_nic_set_mac;
-	netdev->change_mtu	   = netxen_nic_change_mtu;
-	netdev->tx_timeout	   = netxen_tx_timeout;
+	netdev->netdev_ops	   = &netxen_netdev_ops;
 	netdev->watchdog_timeo     = 2*HZ;
 
 	netxen_nic_change_mtu(netdev, netdev->mtu);
 
 	SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	netdev->poll_controller = netxen_nic_poll_controller;
-#endif
+
 	/* ScatterGather support */
 	netdev->features = NETIF_F_SG;
 	netdev->features |= NETIF_F_IP_CSUM;
@@ -988,7 +999,7 @@
  */
 static int netxen_nic_open(struct net_device *netdev)
 {
-	struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv;
+	struct netxen_adapter *adapter = netdev_priv(netdev);
 	int err = 0;
 	int ctx, ring;
 	irq_handler_t handler;
@@ -1077,7 +1088,7 @@
 
 	netxen_nic_set_link_parameters(adapter);
 
-	netdev->set_multicast_list(netdev);
+	netxen_set_multicast_list(netdev);
 	if (adapter->set_mtu)
 		adapter->set_mtu(adapter, netdev->mtu);
 
@@ -1572,7 +1583,7 @@
 	}
 
 	if ((work_done < budget) && tx_complete) {
-		netif_rx_complete(adapter->netdev, &adapter->napi);
+		netif_rx_complete(&adapter->napi);
 		netxen_nic_enable_int(adapter);
 	}
 
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index 27f07f6..c3b9c83 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -608,7 +608,6 @@
 	int phy = adapter->physical_port;
 	unsigned char mac_addr[6];
 	int i;
-	DECLARE_MAC_BUF(mac);
 
 	if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
 		return 0;
@@ -636,10 +635,8 @@
 	if (i == 10) {
 		printk(KERN_ERR "%s: cannot set Mac addr for %s\n",
 		       netxen_nic_driver_name, adapter->netdev->name);
-		printk(KERN_ERR "MAC address set: %s.\n",
-		       print_mac(mac, addr));
-		printk(KERN_ERR "MAC address get: %s.\n",
-		       print_mac(mac, mac_addr));
+		printk(KERN_ERR "MAC address set: %pM.\n", addr);
+		printk(KERN_ERR "MAC address get: %pM.\n", mac_addr);
 	}
 	return 0;
 }
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 8e0ca9f..539e18a 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -203,7 +203,6 @@
 	unsigned int data = 0;
 	int boguscount = 40;
 	int err = -ENODEV;
-	DECLARE_MAC_BUF(mac);
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
@@ -271,7 +270,7 @@
 		outw(i, IE_GP);
 		dev->dev_addr[i] = inb(IE_SAPROM);
 	}
-	printk("%s ", print_mac(mac, dev->dev_addr));
+	printk("%pM ", dev->dev_addr);
 
 	PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
 
@@ -329,7 +328,7 @@
         	outb(0, IE_RBUF);	/* set buffer byte 0 to 0 again */
 	}
         printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
-	memset(dev->priv, 0, sizeof(struct ni5010_local));
+	memset(netdev_priv(dev), 0, sizeof(struct ni5010_local));
 
 	dev->open		= ni5010_open;
 	dev->stop		= ni5010_close;
@@ -570,7 +569,6 @@
 
 	skb->protocol = eth_type_trans(skb,dev);
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 	dev->stats.rx_packets++;
 	dev->stats.rx_bytes += i_pkt_size;
 
@@ -768,12 +766,3 @@
 module_exit(ni5010_cleanup_module);
 #endif /* MODULE */
 MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c ni5010.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  tab-width: 4
- * End:
- */
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index b9a882d..a8bcc00 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -9,8 +9,6 @@
  *    [feel free to mail ....]
  *
  * when using as module: (no autoprobing!)
- *   compile with:
- *       gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ -DMODULE -c ni52.c
  *   run with e.g:
  *       insmod ni52.o io=0x360 irq=9 memstart=0xd0000 memend=0xd4000
  *
@@ -214,7 +212,7 @@
 /* wait for command with timeout: */
 static void wait_for_scb_cmd(struct net_device *dev)
 {
-	struct priv *p = dev->priv;
+	struct priv *p = netdev_priv(dev);
 	int i;
 	for (i = 0; i < 16384; i++) {
 		if (readb(&p->scb->cmd_cuc) == 0)
@@ -233,7 +231,7 @@
 
 static void wait_for_scb_cmd_ruc(struct net_device *dev)
 {
-	struct priv *p = dev->priv;
+	struct priv *p = netdev_priv(dev);
 	int i;
 	for (i = 0; i < 16384; i++) {
 		if (readb(&p->scb->cmd_ruc) == 0)
@@ -298,7 +296,7 @@
 static int check_iscp(struct net_device *dev, void __iomem *addr)
 {
 	struct iscp_struct __iomem *iscp = addr;
-	struct priv *p = dev->priv;
+	struct priv *p = netdev_priv(dev);
 	memset_io(iscp, 0, sizeof(struct iscp_struct));
 
 	writel(make24(iscp), &p->scp->iscp);
@@ -318,7 +316,7 @@
  */
 static int check586(struct net_device *dev, unsigned size)
 {
-	struct priv *p = dev->priv;
+	struct priv *p = netdev_priv(dev);
 	int i;
 
 	p->mapped = ioremap(dev->mem_start, size);
@@ -354,7 +352,7 @@
  */
 static void alloc586(struct net_device *dev)
 {
-	struct priv *p =	(struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	ni_reset586();
 	mdelay(32);
@@ -400,7 +398,7 @@
 	if (!dev)
 		return ERR_PTR(-ENOMEM);
 
-	p = dev->priv;
+	p = netdev_priv(dev);
 
 	if (unit >= 0) {
 		sprintf(dev->name, "eth%d", unit);
@@ -446,7 +444,7 @@
 static int __init ni52_probe1(struct net_device *dev, int ioaddr)
 {
 	int i, size, retval;
-	struct priv *priv = dev->priv;
+	struct priv *priv = netdev_priv(dev);
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
@@ -588,7 +586,7 @@
 {
 	void __iomem *ptr;
 	int i, result = 0;
-	struct priv *p = (struct priv *)dev->priv;
+	struct priv *p = netdev_priv(dev);
 	struct configure_cmd_struct __iomem *cfg_cmd;
 	struct iasetup_cmd_struct __iomem *ias_cmd;
 	struct tdr_cmd_struct __iomem *tdr_cmd;
@@ -829,7 +827,7 @@
 	struct rfd_struct __iomem *rfd = ptr;
 	struct rbd_struct __iomem *rbd;
 	int i;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	memset_io(rfd, 0,
 		sizeof(struct rfd_struct) * (p->num_recv_buffs + rfdadd));
@@ -878,7 +876,7 @@
 	int cnt = 0;
 	struct priv *p;
 
-	p = (struct priv *) dev->priv;
+	p = netdev_priv(dev);
 
 	if (debuglevel > 1)
 		printk("I");
@@ -950,7 +948,7 @@
 	unsigned short totlen;
 	struct sk_buff *skb;
 	struct rbd_struct __iomem *rbd;
-	struct priv *p = (struct priv *)dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	if (debuglevel > 0)
 		printk("R");
@@ -970,7 +968,6 @@
 					memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen);
 					skb->protocol = eth_type_trans(skb, dev);
 					netif_rx(skb);
-					dev->last_rx = jiffies;
 					p->stats.rx_packets++;
 					p->stats.rx_bytes += totlen;
 				} else
@@ -1040,7 +1037,7 @@
 
 static void ni52_rnr_int(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	p->stats.rx_errors++;
 
@@ -1065,7 +1062,7 @@
 static void ni52_xmt_int(struct net_device *dev)
 {
 	int status;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	if (debuglevel > 0)
 		printk("X");
@@ -1113,7 +1110,7 @@
 
 static void startrecv586(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	wait_for_scb_cmd(dev);
 	wait_for_scb_cmd_ruc(dev);
@@ -1126,7 +1123,7 @@
 
 static void ni52_timeout(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 #ifndef NO_NOPCOMMANDS
 	if (readb(&p->scb->cus) & CU_ACTIVE) { /* COMMAND-UNIT active? */
 		netif_wake_queue(dev);
@@ -1177,7 +1174,7 @@
 #ifndef NO_NOPCOMMANDS
 	int next_nop;
 #endif
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	if (skb->len > XMIT_BUFF_SIZE) {
 		printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
@@ -1274,7 +1271,7 @@
 
 static struct net_device_stats *ni52_get_stats(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 	unsigned short crc, aln, rsc, ovrn;
 
 	/* Get error-statistics from the ni82586 */
@@ -1337,7 +1334,7 @@
 
 void __exit cleanup_module(void)
 {
-	struct priv *p = dev_ni52->priv;
+	struct priv *p = netdev_priv(dev_ni52);
 	unregister_netdev(dev_ni52);
 	iounmap(p->mapped);
 	release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE);
@@ -1346,7 +1343,3 @@
 #endif /* MODULE */
 
 MODULE_LICENSE("GPL");
-
-/*
- * END: linux/drivers/net/ni52.c
- */
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 3edc971..2540572 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -7,8 +7,6 @@
  * EtherBlaster. (probably it also works with every full NE2100
  * compatible card)
  *
- * To compile as module, type:
- *     gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ -DMODULE -c ni65.c
  * driver probes: io: 0x360,0x300,0x320,0x340 / dma: 3,5,6,7
  *
  * This is an extension to the Linux operating system, and is covered by the
@@ -295,7 +293,7 @@
  */
 static int ni65_open(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = dev->ml_priv;
 	int irqval = request_irq(dev->irq, &ni65_interrupt,0,
                         cards[p->cardno].cardname,dev);
 	if (irqval) {
@@ -321,7 +319,7 @@
  */
 static int ni65_close(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = dev->ml_priv;
 
 	netif_stop_queue(dev);
 
@@ -345,7 +343,7 @@
 
 static void cleanup_card(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = dev->ml_priv;
 	disable_dma(dev->dma);
 	free_dma(dev->dma);
 	release_region(dev->base_addr, cards[p->cardno].total_size);
@@ -444,7 +442,7 @@
 		release_region(ioaddr, cards[i].total_size);
 		return j;
 	}
-	p = (struct priv *) dev->priv;
+	p = dev->ml_priv;
 	p->cmdr_addr = ioaddr + cards[i].cmd_offset;
 	p->cardno = i;
 	spin_lock_init(&p->ring_lock);
@@ -647,8 +645,8 @@
 	if(!ptr)
 		return -ENOMEM;
 
-	p = dev->priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7);
-	memset((char *) dev->priv,0,sizeof(struct priv));
+	p = dev->ml_priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7);
+	memset((char *)p, 0, sizeof(struct priv));
 	p->self = ptr;
 
 	for(i=0;i<TMDNUM;i++)
@@ -790,7 +788,7 @@
 static int ni65_lance_reinit(struct net_device *dev)
 {
 	 int i;
-	 struct priv *p = (struct priv *) dev->priv;
+	 struct priv *p = dev->ml_priv;
 	 unsigned long flags;
 
 	 p->lock = 0;
@@ -876,7 +874,7 @@
 	struct priv *p;
 	int bcnt = 32;
 
-	p = (struct priv *) dev->priv;
+	p = dev->ml_priv;
 
 	spin_lock(&p->ring_lock);
 
@@ -899,7 +897,7 @@
 
 		if(csr0 & CSR0_ERR)
 		{
-			struct priv *p = (struct priv *) dev->priv;
+			struct priv *p = dev->ml_priv;
 			if(debuglevel > 1)
 				printk(KERN_ERR "%s: general error: %04x.\n",dev->name,csr0);
 			if(csr0 & CSR0_BABL)
@@ -924,7 +922,7 @@
  int j;
  for(j=0;j<RMDNUM;j++)
  {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = dev->ml_priv;
 	int i,k,num1,num2;
 	for(i=RMDNUM-1;i>0;i--) {
 		 num2 = (p->rmdnum + i) & (RMDNUM-1);
@@ -982,7 +980,7 @@
  */
 static void ni65_xmit_intr(struct net_device *dev,int csr0)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = dev->ml_priv;
 
 	while(p->xmit_queued)
 	{
@@ -1049,7 +1047,7 @@
 	struct rmd *rmdp;
 	int rmdstat,len;
 	int cnt=0;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = dev->ml_priv;
 
 	rmdp = p->rmdhead + p->rmdnum;
 	while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN))
@@ -1113,7 +1111,6 @@
 				p->stats.rx_bytes += len;
 				skb->protocol=eth_type_trans(skb,dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 			}
 			else
 			{
@@ -1140,7 +1137,7 @@
 static void ni65_timeout(struct net_device *dev)
 {
 	int i;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = dev->ml_priv;
 
 	printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
 	for(i=0;i<TMDNUM;i++)
@@ -1157,7 +1154,7 @@
 
 static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = dev->ml_priv;
 
 	netif_stop_queue(dev);
 
@@ -1222,7 +1219,7 @@
 
 #if 0
 	int i;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = dev->ml_priv;
 	for(i=0;i<RMDNUM;i++)
 	{
 		struct rmd *rmdp = p->rmdhead + ((p->rmdnum + i) & (RMDNUM-1));
@@ -1231,7 +1228,7 @@
 	printk("\n");
 #endif
 
-	return &((struct priv *) dev->priv)->stats;
+	return &((struct priv *)dev->ml_priv)->stats;
 }
 
 static void set_multicast_list(struct net_device *dev)
@@ -1266,7 +1263,3 @@
 #endif /* MODULE */
 
 MODULE_LICENSE("GPL");
-
-/*
- * END of ni65.c
- */
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 1b6f548..0c0b752 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -448,7 +448,7 @@
 	struct niu_link_config *lp = &np->link_config;
 	u16 pll_cfg, pll_sts;
 	int max_retry = 100;
-	u64 sig, mask, val;
+	u64 uninitialized_var(sig), mask, val;
 	u32 tx_cfg, rx_cfg;
 	unsigned long i;
 	int err;
@@ -547,7 +547,7 @@
 	struct niu_link_config *lp = &np->link_config;
 	u32 tx_cfg, rx_cfg, pll_cfg, pll_sts;
 	int max_retry = 100;
-	u64 sig, mask, val;
+	u64 uninitialized_var(sig), mask, val;
 	unsigned long i;
 	int err;
 
@@ -738,7 +738,7 @@
 
 static int esr_reset(struct niu *np)
 {
-	u32 reset;
+	u32 uninitialized_var(reset);
 	int err;
 
 	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
@@ -3392,8 +3392,6 @@
 	skb->protocol = eth_type_trans(skb, np->dev);
 	netif_receive_skb(skb);
 
-	np->dev->last_rx = jiffies;
-
 	return num_rcr;
 }
 
@@ -3529,6 +3527,57 @@
 	}
 }
 
+static inline void niu_sync_rx_discard_stats(struct niu *np,
+					     struct rx_ring_info *rp,
+					     const int limit)
+{
+	/* This elaborate scheme is needed for reading the RX discard
+	 * counters, as they are only 16-bit and can overflow quickly,
+	 * and because the overflow indication bit is not usable as
+	 * the counter value does not wrap, but remains at max value
+	 * 0xFFFF.
+	 *
+	 * In theory and in practice counters can be lost in between
+	 * reading nr64() and clearing the counter nw64().  For this
+	 * reason, the number of counter clearings nw64() is
+	 * limited/reduced though the limit parameter.
+	 */
+	int rx_channel = rp->rx_channel;
+	u32 misc, wred;
+
+	/* RXMISC (Receive Miscellaneous Discard Count), covers the
+	 * following discard events: IPP (Input Port Process),
+	 * FFLP/TCAM, Full RCR (Receive Completion Ring) RBR (Receive
+	 * Block Ring) prefetch buffer is empty.
+	 */
+	misc = nr64(RXMISC(rx_channel));
+	if (unlikely((misc & RXMISC_COUNT) > limit)) {
+		nw64(RXMISC(rx_channel), 0);
+		rp->rx_errors += misc & RXMISC_COUNT;
+
+		if (unlikely(misc & RXMISC_OFLOW))
+			dev_err(np->device, "rx-%d: Counter overflow "
+				"RXMISC discard\n", rx_channel);
+
+		niudbg(RX_ERR, "%s-rx-%d: MISC drop=%u over=%u\n",
+		       np->dev->name, rx_channel, misc, misc-limit);
+	}
+
+	/* WRED (Weighted Random Early Discard) by hardware */
+	wred = nr64(RED_DIS_CNT(rx_channel));
+	if (unlikely((wred & RED_DIS_CNT_COUNT) > limit)) {
+		nw64(RED_DIS_CNT(rx_channel), 0);
+		rp->rx_dropped += wred & RED_DIS_CNT_COUNT;
+
+		if (unlikely(wred & RED_DIS_CNT_OFLOW))
+			dev_err(np->device, "rx-%d: Counter overflow "
+				"WRED discard\n", rx_channel);
+
+		niudbg(RX_ERR, "%s-rx-%d: WRED drop=%u over=%u\n",
+		       np->dev->name, rx_channel, wred, wred-limit);
+	}
+}
+
 static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget)
 {
 	int qlen, rcr_done = 0, work_done = 0;
@@ -3569,6 +3618,10 @@
 
 	nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat);
 
+	/* Only sync discards stats when qlen indicate potential for drops */
+	if (qlen > 10)
+		niu_sync_rx_discard_stats(np, rp, 0x7FFF);
+
 	return work_done;
 }
 
@@ -3616,7 +3669,7 @@
 	work_done = niu_poll_core(np, lp, budget);
 
 	if (work_done < budget) {
-		netif_rx_complete(np->dev, napi);
+		netif_rx_complete(napi);
 		niu_ldg_rearm(np, lp, 1);
 	}
 	return work_done;
@@ -4035,12 +4088,12 @@
 static void niu_schedule_napi(struct niu *np, struct niu_ldg *lp,
 			      u64 v0, u64 v1, u64 v2)
 {
-	if (likely(netif_rx_schedule_prep(np->dev, &lp->napi))) {
+	if (likely(netif_rx_schedule_prep(&lp->napi))) {
 		lp->v0 = v0;
 		lp->v1 = v1;
 		lp->v2 = v2;
 		__niu_fastpath_interrupt(np, lp->ldg_num, v0);
-		__netif_rx_schedule(np->dev, &lp->napi);
+		__netif_rx_schedule(&lp->napi);
 	}
 }
 
@@ -5849,17 +5902,42 @@
 	niu_reset_rx_channels(np);
 }
 
+static void niu_set_irq_name(struct niu *np)
+{
+	int port = np->port;
+	int i, j = 1;
+
+	sprintf(np->irq_name[0], "%s:MAC", np->dev->name);
+
+	if (port == 0) {
+		sprintf(np->irq_name[1], "%s:MIF", np->dev->name);
+		sprintf(np->irq_name[2], "%s:SYSERR", np->dev->name);
+		j = 3;
+	}
+
+	for (i = 0; i < np->num_ldg - j; i++) {
+		if (i < np->num_rx_rings)
+			sprintf(np->irq_name[i+j], "%s-rx-%d",
+				np->dev->name, i);
+		else if (i < np->num_tx_rings + np->num_rx_rings)
+			sprintf(np->irq_name[i+j], "%s-tx-%d", np->dev->name,
+				i - np->num_rx_rings);
+	}
+}
+
 static int niu_request_irq(struct niu *np)
 {
 	int i, j, err;
 
+	niu_set_irq_name(np);
+
 	err = 0;
 	for (i = 0; i < np->num_ldg; i++) {
 		struct niu_ldg *lp = &np->ldg[i];
 
 		err = request_irq(lp->irq, niu_interrupt,
 				  IRQF_SHARED | IRQF_SAMPLE_RANDOM,
-				  np->dev->name, lp);
+				  np->irq_name[i], lp);
 		if (err)
 			goto out_free_irqs;
 
@@ -6050,15 +6128,17 @@
 	for (i = 0; i < np->num_rx_rings; i++) {
 		struct rx_ring_info *rp = &np->rx_rings[i];
 
+		niu_sync_rx_discard_stats(np, rp, 0);
+
 		pkts += rp->rx_packets;
 		bytes += rp->rx_bytes;
 		dropped += rp->rx_dropped;
 		errors += rp->rx_errors;
 	}
-	np->net_stats.rx_packets = pkts;
-	np->net_stats.rx_bytes = bytes;
-	np->net_stats.rx_dropped = dropped;
-	np->net_stats.rx_errors = errors;
+	np->dev->stats.rx_packets = pkts;
+	np->dev->stats.rx_bytes = bytes;
+	np->dev->stats.rx_dropped = dropped;
+	np->dev->stats.rx_errors = errors;
 }
 
 static void niu_get_tx_stats(struct niu *np)
@@ -6074,9 +6154,9 @@
 		bytes += rp->tx_bytes;
 		errors += rp->tx_errors;
 	}
-	np->net_stats.tx_packets = pkts;
-	np->net_stats.tx_bytes = bytes;
-	np->net_stats.tx_errors = errors;
+	np->dev->stats.tx_packets = pkts;
+	np->dev->stats.tx_bytes = bytes;
+	np->dev->stats.tx_errors = errors;
 }
 
 static struct net_device_stats *niu_get_stats(struct net_device *dev)
@@ -6086,7 +6166,7 @@
 	niu_get_rx_stats(np);
 	niu_get_tx_stats(np);
 
-	return &np->net_stats;
+	return &dev->stats;
 }
 
 static void niu_load_hash_xmac(struct niu *np, u16 *hash)
@@ -6991,6 +7071,8 @@
 	for (i = 0; i < np->num_rx_rings; i++) {
 		struct rx_ring_info *rp = &np->rx_rings[i];
 
+		niu_sync_rx_discard_stats(np, rp, 0);
+
 		data[0] = rp->rx_channel;
 		data[1] = rp->rx_packets;
 		data[2] = rp->rx_bytes;
@@ -8824,7 +8906,7 @@
 static void niu_pci_unmap_page(struct device *dev, u64 dma_address,
 			       size_t size, enum dma_data_direction direction)
 {
-	return dma_unmap_page(dev, dma_address, size, direction);
+	dma_unmap_page(dev, dma_address, size, direction);
 }
 
 static u64 niu_pci_map_single(struct device *dev, void *cpu_addr,
@@ -8891,28 +8973,31 @@
 	return dev;
 }
 
+static const struct net_device_ops niu_netdev_ops = {
+	.ndo_open		= niu_open,
+	.ndo_stop		= niu_close,
+	.ndo_start_xmit		= niu_start_xmit,
+	.ndo_get_stats		= niu_get_stats,
+	.ndo_set_multicast_list	= niu_set_rx_mode,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= niu_set_mac_addr,
+	.ndo_do_ioctl		= niu_ioctl,
+	.ndo_tx_timeout		= niu_tx_timeout,
+	.ndo_change_mtu		= niu_change_mtu,
+};
+
 static void __devinit niu_assign_netdev_ops(struct net_device *dev)
 {
-	dev->open = niu_open;
-	dev->stop = niu_close;
-	dev->get_stats = niu_get_stats;
-	dev->set_multicast_list = niu_set_rx_mode;
-	dev->set_mac_address = niu_set_mac_addr;
-	dev->do_ioctl = niu_ioctl;
-	dev->tx_timeout = niu_tx_timeout;
-	dev->hard_start_xmit = niu_start_xmit;
+	dev->netdev_ops = &niu_netdev_ops;
 	dev->ethtool_ops = &niu_ethtool_ops;
 	dev->watchdog_timeo = NIU_TX_TIMEOUT;
-	dev->change_mtu = niu_change_mtu;
 }
 
 static void __devinit niu_device_announce(struct niu *np)
 {
 	struct net_device *dev = np->dev;
-	DECLARE_MAC_BUF(mac);
 
-	pr_info("%s: NIU Ethernet %s\n",
-		dev->name, print_mac(mac, dev->dev_addr));
+	pr_info("%s: NIU Ethernet %pM\n", dev->name, dev->dev_addr);
 
 	if (np->parent->plat_type == PLAT_TYPE_ATCA_CP3220) {
 		pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n",
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
index 180ca8a..e1a7392 100644
--- a/drivers/net/niu.h
+++ b/drivers/net/niu.h
@@ -3243,12 +3243,12 @@
 #define NIU_FLAGS_XMAC			0x00010000 /* 0=BMAC 1=XMAC */
 
 	u32				msg_enable;
+	char                            irq_name[NIU_NUM_RXCHAN+NIU_NUM_TXCHAN+3][IFNAMSIZ + 6];
 
 	/* Protects hw programming, and ring state.  */
 	spinlock_t			lock;
 
 	const struct niu_ops		*ops;
-	struct net_device_stats		net_stats;
 	union niu_mac_stats		mac_stats;
 
 	struct rx_ring_info		*rx_rings;
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index ff44961..46b0772 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1948,14 +1948,25 @@
 }
 #endif
 
-static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id)
+static const struct net_device_ops netdev_ops = {
+	.ndo_open		= ns83820_open,
+	.ndo_stop		= ns83820_stop,
+	.ndo_start_xmit		= ns83820_hard_start_xmit,
+	.ndo_get_stats		= ns83820_get_stats,
+	.ndo_change_mtu		= ns83820_change_mtu,
+	.ndo_set_multicast_list = ns83820_set_multicast,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_tx_timeout		= ns83820_tx_timeout,
+};
+
+static int __devinit ns83820_init_one(struct pci_dev *pci_dev,
+				      const struct pci_device_id *id)
 {
 	struct net_device *ndev;
 	struct ns83820 *dev;
 	long addr;
 	int err;
 	int using_dac = 0;
-	DECLARE_MAC_BUF(mac);
 
 	/* See if we can set the dma mask early on; failure is fatal. */
 	if (sizeof(dma_addr_t) == 8 &&
@@ -2041,14 +2052,8 @@
 		ndev->name, le32_to_cpu(readl(dev->base + 0x22c)),
 		pci_dev->subsystem_vendor, pci_dev->subsystem_device);
 
-	ndev->open = ns83820_open;
-	ndev->stop = ns83820_stop;
-	ndev->hard_start_xmit = ns83820_hard_start_xmit;
-	ndev->get_stats = ns83820_get_stats;
-	ndev->change_mtu = ns83820_change_mtu;
-	ndev->set_multicast_list = ns83820_set_multicast;
+	ndev->netdev_ops = &netdev_ops;
 	SET_ETHTOOL_OPS(ndev, &ops);
-	ndev->tx_timeout = ns83820_tx_timeout;
 	ndev->watchdog_timeo = 5 * HZ;
 	pci_set_drvdata(pci_dev, ndev);
 
@@ -2220,12 +2225,11 @@
 		ndev->features |= NETIF_F_HIGHDMA;
 	}
 
-	printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %s io=0x%08lx irq=%d f=%s\n",
+	printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %pM io=0x%08lx irq=%d f=%s\n",
 		ndev->name,
 		(unsigned)readl(dev->base + SRR) >> 8,
 		(unsigned)readl(dev->base + SRR) & 0xff,
-		print_mac(mac, ndev->dev_addr),
-		addr, pci_dev->irq,
+		ndev->dev_addr, addr, pci_dev->irq,
 		(ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg"
 		);
 
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index edc0fd5..dcd1990 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -971,7 +971,7 @@
 	if (*chan->status & PAS_STATUS_ERROR)
 		reg |= PAS_IOB_DMA_RXCH_RESET_DINTC;
 
-	netif_rx_schedule(dev, &mac->napi);
+	netif_rx_schedule(&mac->napi);
 
 	write_iob_reg(PAS_IOB_DMA_RXCH_RESET(chan->chno), reg);
 
@@ -1011,7 +1011,7 @@
 
 	mod_timer(&txring->clean_timer, jiffies + (TX_CLEAN_INTERVAL)*2);
 
-	netif_rx_schedule(mac->netdev, &mac->napi);
+	netif_rx_schedule(&mac->napi);
 
 	if (reg)
 		write_iob_reg(PAS_IOB_DMA_TXCH_RESET(chan->chno), reg);
@@ -1105,7 +1105,8 @@
 		goto err;
 
 	phy_id = *prop;
-	snprintf(mac->phy_id, BUS_ID_SIZE, "%x:%02x", (int)r.start, phy_id);
+	snprintf(mac->phy_id, sizeof(mac->phy_id), "%x:%02x",
+		 (int)r.start, phy_id);
 
 	of_node_put(phy_dn);
 
@@ -1640,7 +1641,7 @@
 	pkts = pasemi_mac_clean_rx(rx_ring(mac), budget);
 	if (pkts < budget) {
 		/* all done, no more packets present */
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 
 		pasemi_mac_restart_rx_intr(mac);
 		pasemi_mac_restart_tx_intr(mac);
@@ -1742,7 +1743,6 @@
 	struct net_device *dev;
 	struct pasemi_mac *mac;
 	int err;
-	DECLARE_MAC_BUF(mac_buf);
 
 	err = pci_enable_device(pdev);
 	if (err)
@@ -1849,9 +1849,9 @@
 			err);
 		goto out;
 	} else if netif_msg_probe(mac)
-		printk(KERN_INFO "%s: PA Semi %s: intf %d, hw addr %s\n",
+		printk(KERN_INFO "%s: PA Semi %s: intf %d, hw addr %pM\n",
 		       dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
-		       mac->dma_if, print_mac(mac_buf, dev->dev_addr));
+		       mac->dma_if, dev->dev_addr);
 
 	return err;
 
diff --git a/drivers/net/pasemi_mac_ethtool.c b/drivers/net/pasemi_mac_ethtool.c
index 5e8df3a..064a4fe 100644
--- a/drivers/net/pasemi_mac_ethtool.c
+++ b/drivers/net/pasemi_mac_ethtool.c
@@ -109,7 +109,7 @@
 pasemi_mac_ethtool_get_ringparam(struct net_device *netdev,
 				 struct ethtool_ringparam *ering)
 {
-	struct pasemi_mac *mac = netdev->priv;
+	struct pasemi_mac *mac = netdev_priv(netdev);
 
 	ering->tx_max_pending = TX_RING_SIZE/2;
 	ering->tx_pending = RING_USED(mac->tx)/2;
@@ -130,7 +130,7 @@
 static void pasemi_mac_get_ethtool_stats(struct net_device *netdev,
 		struct ethtool_stats *stats, u64 *data)
 {
-	struct pasemi_mac *mac = netdev->priv;
+	struct pasemi_mac *mac = netdev_priv(netdev);
 	int i;
 
 	data[0] = pasemi_read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if))
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 0a575fe..c95fd72 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -737,7 +737,6 @@
 	int i, addr_len, option;
 	void *ioaddr = NULL;
 	static int board_idx = -1;
-	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -782,7 +781,7 @@
 	dev->irq = pdev->irq;
 	dev->base_addr = (unsigned long) ioaddr;
 
-	/* dev->priv/tp zeroed and aligned in alloc_etherdev */
+	/* netdev_priv()/tp zeroed and aligned in alloc_etherdev */
 	tp = netdev_priv(dev);
 
 	/* note: tp->chipset set in netdrv_init_board */
@@ -797,11 +796,11 @@
 
 	tp->phys[0] = 32;
 
-	printk (KERN_INFO "%s: %s at 0x%lx, %sIRQ %d\n",
+	printk (KERN_INFO "%s: %s at 0x%lx, %pM IRQ %d\n",
 		dev->name,
 		board_info[ent->driver_data].name,
 		dev->base_addr,
-		print_mac(mac, dev->dev_addr),
+		dev->dev_addr,
 		dev->irq);
 
 	printk (KERN_DEBUG "%s:  Identified 8139 chip type '%s'\n",
@@ -1566,7 +1565,6 @@
 
 			skb->protocol = eth_type_trans (skb, dev);
 			netif_rx (skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_bytes += pkt_size;
 			dev->stats.rx_packets++;
 		} else {
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 08c4dd8..e5cb6b1 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -345,7 +345,6 @@
 	__be16 *phys_addr;
 	char *cardname;
 	__u32 config;
-	DECLARE_MAC_BUF(mac);
 
 	phys_addr = (__be16 *)dev->dev_addr;
 
@@ -463,9 +462,9 @@
 	strcpy(lp->node.dev_name, dev->name);
 
 	printk(KERN_INFO "%s: %s at io %#3lx, irq %d, "
-	       "hw_addr %s.\n",
+	       "hw_addr %pM.\n",
 	       dev->name, cardname, dev->base_addr, dev->irq,
-	       print_mac(mac, dev->dev_addr));
+	       dev->dev_addr);
 	printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
 		   8 << config & Ram_size,
 		   ram_split[(config & Ram_split) >> Ram_split_shift],
@@ -1062,7 +1061,6 @@
 						((pkt_len+3)>>2));
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += pkt_len;
 			} else {
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index c235cdb..73ecc65 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -255,7 +255,6 @@
     int last_fn, last_ret, i, j, multi = 0, fifo;
     unsigned int ioaddr;
     char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
-    DECLARE_MAC_BUF(mac);
     
     DEBUG(0, "3c589_config(0x%p)\n", link);
 
@@ -333,9 +332,9 @@
     strcpy(lp->node.dev_name, dev->name);
 
     printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, "
-	   "hw_addr %s\n",
+	   "hw_addr %pM\n",
 	   dev->name, (multi ? "562" : "589"), dev->base_addr, dev->irq,
-	   print_mac(mac, dev->dev_addr));
+	   dev->dev_addr);
     printk(KERN_INFO "  %dK FIFO split %s Rx:Tx, %s xcvr\n",
 	   (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
 	   if_names[dev->if_port]);
@@ -884,7 +883,6 @@
 			(pkt_len+3)>>2);
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
-		dev->last_rx = jiffies;
 		dev->stats.rx_packets++;
 		dev->stats.rx_bytes += pkt_len;
 	    } else {
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 0418045..0afa720 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -321,7 +321,6 @@
     struct net_device *dev = link->priv;
     axnet_dev_t *info = PRIV(dev);
     int i, j, last_ret, last_fn;
-    DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "axnet_config(0x%p)\n", link);
 
@@ -397,10 +396,10 @@
     strcpy(info->node.dev_name, dev->name);
 
     printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, "
-	   "hw_addr %s\n",
+	   "hw_addr %pM\n",
 	   dev->name, ((info->flags & IS_AX88790) ? 7 : 1),
 	   dev->base_addr, dev->irq,
-	   print_mac(mac, dev->dev_addr));
+	   dev->dev_addr);
     if (info->phy_id != -1) {
 	DEBUG(0, "  MII transceiver at index %d, status %x.\n", info->phy_id, j);
     } else {
@@ -906,7 +905,7 @@
 /* Index to functions. */
 static void ei_tx_intr(struct net_device *dev);
 static void ei_tx_err(struct net_device *dev);
-static void ei_tx_timeout(struct net_device *dev);
+static void axnet_tx_timeout(struct net_device *dev);
 static void ei_receive(struct net_device *dev);
 static void ei_rx_overrun(struct net_device *dev);
 
@@ -957,9 +956,9 @@
 
 #ifdef HAVE_TX_TIMEOUT
 	/* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout
-	    wrapper that does e.g. media check & then calls ei_tx_timeout. */
+	    wrapper that does e.g. media check & then calls axnet_tx_timeout. */
 	if (dev->tx_timeout == NULL)
-		 dev->tx_timeout = ei_tx_timeout;
+		 dev->tx_timeout = axnet_tx_timeout;
 	if (dev->watchdog_timeo <= 0)
 		 dev->watchdog_timeo = TX_TIMEOUT;
 #endif
@@ -1003,14 +1002,14 @@
 }
 
 /**
- * ei_tx_timeout - handle transmit time out condition
+ * axnet_tx_timeout - handle transmit time out condition
  * @dev: network device which has apparently fallen asleep
  *
  * Called by kernel when device never acknowledges a transmit has
  * completed (or failed) - i.e. never posted a Tx related interrupt.
  */
 
-static void ei_tx_timeout(struct net_device *dev)
+static void axnet_tx_timeout(struct net_device *dev)
 {
 	long e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
@@ -1047,14 +1046,14 @@
 }
     
 /**
- * ei_start_xmit - begin packet transmission
+ * axnet_start_xmit - begin packet transmission
  * @skb: packet to be sent
  * @dev: network device to which packet is sent
  *
  * Sends a packet to an 8390 network device.
  */
  
-static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	long e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
@@ -1493,7 +1492,6 @@
 				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
 				skb->protocol=eth_type_trans(skb,dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += pkt_len;
 				if (pkt_stat & ENRSR_PHY)
@@ -1720,7 +1718,7 @@
 	ei_local = (struct ei_device *)netdev_priv(dev);
 	spin_lock_init(&ei_local->page_lock);
     
-	dev->hard_start_xmit = &ei_start_xmit;
+	dev->hard_start_xmit = &axnet_start_xmit;
 	dev->get_stats	= get_stats;
 	dev->set_multicast_list = &set_multicast_list;
 
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 831090c..7b5c77b7 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -155,7 +155,7 @@
     if (!dev)
 	goto fail_alloc_dev;
 
-    lp = dev->priv;
+    lp = netdev_priv(dev);
     lp->timeout = timeout;
     lp->backplane = backplane;
     lp->clockp = clockp;
@@ -303,7 +303,7 @@
 	goto failed;
     }
     
-    lp = dev->priv;
+    lp = netdev_priv(dev);
     lp->card_name = "PCMCIA COM20020";
     lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
 
@@ -364,7 +364,7 @@
 
 	if (link->open) {
 		int ioaddr = dev->base_addr;
-		struct arcnet_local *lp = dev->priv;
+		struct arcnet_local *lp = netdev_priv(dev);
 		ARCRESET;
 	}
 
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 69d916d..69dcfbb 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -125,6 +125,7 @@
     u_short tx_queue_len;
     cardtype_t cardtype;
     u_short sent;
+    u_char __iomem *base;
 } local_info_t;
 
 #define MC_FILTERBREAK 64
@@ -242,6 +243,7 @@
     lp = netdev_priv(dev);
     link->priv = dev;
     lp->p_dev = link;
+    lp->base = NULL;
 
     /* The io structure describes IO port mapping */
     link->io.NumPorts1 = 32;
@@ -348,7 +350,6 @@
     cardtype_t cardtype;
     char *card_name = "unknown";
     u_char *node_id;
-    DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "fmvj18x_config(0x%p)\n", link);
 
@@ -443,8 +444,10 @@
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
 
-    if (link->io.BasePort2 != 0)
-	fmvj18x_setup_mfc(link);
+    if (link->io.BasePort2 != 0) {
+	ret = fmvj18x_setup_mfc(link);
+	if (ret != 0) goto failed;
+    }
 
     ioaddr = dev->base_addr;
 
@@ -539,9 +542,9 @@
 
     /* print current configuration */
     printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, "
-	   "hw_addr %s\n",
+	   "hw_addr %pM\n",
 	   dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", 
-	   dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr));
+	   dev->base_addr, dev->irq, dev->dev_addr);
 
     return 0;
     
@@ -611,10 +614,10 @@
 {
     win_req_t req;
     memreq_t mem;
-    u_char __iomem *base;
-    int i, j;
+    int i;
     struct net_device *dev = link->priv;
     unsigned int ioaddr;
+    local_info_t *lp = netdev_priv(dev);
 
     /* Allocate a small memory window */
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
@@ -626,25 +629,32 @@
 	return -1;
     }
 
-    base = ioremap(req.Base, req.Size);
+    lp->base = ioremap(req.Base, req.Size);
+    if (lp->base == NULL) {
+	printk(KERN_NOTICE "fmvj18x_cs: ioremap failed\n");
+	return -1;
+    }
+
     mem.Page = 0;
     mem.CardOffset = 0;
-    pcmcia_map_mem_page(link->win, &mem);
-
+    i = pcmcia_map_mem_page(link->win, &mem);
+    if (i != 0) {
+	iounmap(lp->base);
+	lp->base = NULL;
+	cs_error(link, MapMemPage, i);
+	return -1;
+    }
+    
     ioaddr = dev->base_addr;
-    writeb(0x47, base+0x800);	/* Config Option Register of LAN */
-    writeb(0x0, base+0x802);	/* Config and Status Register */
+    writeb(0x47, lp->base+0x800);	/* Config Option Register of LAN */
+    writeb(0x0,  lp->base+0x802);	/* Config and Status Register */
 
-    writeb(ioaddr & 0xff, base+0x80a);		/* I/O Base(Low) of LAN */
-    writeb((ioaddr >> 8) & 0xff, base+0x80c);	/* I/O Base(High) of LAN */
+    writeb(ioaddr & 0xff, lp->base+0x80a);	  /* I/O Base(Low) of LAN */
+    writeb((ioaddr >> 8) & 0xff, lp->base+0x80c); /* I/O Base(High) of LAN */
    
-    writeb(0x45, base+0x820);	/* Config Option Register of Modem */
-    writeb(0x8, base+0x822);	/* Config and Status Register */
+    writeb(0x45, lp->base+0x820);	/* Config Option Register of Modem */
+    writeb(0x8,  lp->base+0x822);	/* Config and Status Register */
 
-    iounmap(base);
-    j = pcmcia_release_window(link->win);
-    if (j != 0)
-	cs_error(link, ReleaseWindow, j);
     return 0;
 
 }
@@ -652,8 +662,25 @@
 
 static void fmvj18x_release(struct pcmcia_device *link)
 {
-	DEBUG(0, "fmvj18x_release(0x%p)\n", link);
-	pcmcia_disable_device(link);
+
+    struct net_device *dev = link->priv;
+    local_info_t *lp = netdev_priv(dev);
+    u_char __iomem *tmp;
+    int j;
+
+    DEBUG(0, "fmvj18x_release(0x%p)\n", link);
+
+    if (lp->base != NULL) {
+	tmp = lp->base;
+	lp->base = NULL;    /* set NULL before iounmap */
+	iounmap(tmp);
+	j = pcmcia_release_window(link->win);
+	if (j != 0)
+	    cs_error(link, ReleaseWindow, j);
+    }
+
+    pcmcia_disable_device(link);
+
 }
 
 static int fmvj18x_suspend(struct pcmcia_device *link)
@@ -784,6 +811,13 @@
 
     outb(D_TX_INTR, ioaddr + TX_INTR);
     outb(D_RX_INTR, ioaddr + RX_INTR);
+
+    if (lp->base != NULL) {
+	/* Ack interrupt for multifunction card */
+	writeb(0x01, lp->base+0x802);
+	writeb(0x09, lp->base+0x822);
+    }
+
     return IRQ_HANDLED;
 
 } /* fjn_interrupt */
@@ -1036,7 +1070,6 @@
 #endif
 
 	    netif_rx(skb);
-	    dev->last_rx = jiffies;
 	    lp->stats.rx_packets++;
 	    lp->stats.rx_bytes += pkt_len;
 	}
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 448cd40..ec7c588 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -659,7 +659,6 @@
   u_char buf[64];
   int i, last_ret, last_fn;
   unsigned int ioaddr;
-  DECLARE_MAC_BUF(mac);
 
   DEBUG(0, "nmclan_config(0x%p)\n", link);
 
@@ -719,9 +718,9 @@
   strcpy(lp->node.dev_name, dev->name);
 
   printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port,"
-	 " hw_addr %s\n",
+	 " hw_addr %pM\n",
 	 dev->name, dev->base_addr, dev->irq, if_names[dev->if_port],
-	 print_mac(mac, dev->dev_addr));
+	 dev->dev_addr);
   return 0;
 
 cs_failed:
@@ -1193,7 +1192,6 @@
 	
 	netif_rx(skb); /* Send the packet to the upper (protocol) layers. */
 
-	dev->last_rx = jiffies;
 	lp->linux_stats.rx_packets++;
 	lp->linux_stats.rx_bytes += pkt_len;
 	outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index ce486f0..c38ed77 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -554,7 +554,6 @@
     int last_ret, last_fn, start_pg, stop_pg, cm_offset;
     int has_shmem = 0;
     hw_info_t *local_hw_info;
-    DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "pcnet_config(0x%p)\n", link);
 
@@ -675,7 +674,7 @@
 	printk (" mem %#5lx,", dev->mem_start);
     if (info->flags & HAS_MISC_REG)
 	printk(" %s xcvr,", if_names[dev->if_port]);
-    printk(" hw_addr %s\n", print_mac(mac, dev->dev_addr));
+    printk(" hw_addr %pM\n", dev->dev_addr);
     return 0;
 
 cs_failed:
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index c74d665..fccd53e 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -949,7 +949,6 @@
     int i, j, rev;
     unsigned int ioaddr;
     u_long mir;
-    DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "smc91c92_config(0x%p)\n", link);
 
@@ -1062,9 +1061,9 @@
     strcpy(smc->node.dev_name, dev->name);
 
     printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
-	   "hw_addr %s\n",
+	   "hw_addr %pM\n",
 	   dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq,
-	   print_mac(mac, dev->dev_addr));
+	   dev->dev_addr);
 
     if (rev > 0) {
 	if (mir & 0x3ff)
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index e1fd585..fef7e18 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -772,7 +772,6 @@
     int err, i;
     u_char buf[64];
     cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
-    DECLARE_MAC_BUF(mac);
 
     local->dingo_ccr = NULL;
 
@@ -1051,9 +1050,9 @@
     strcpy(local->node.dev_name, dev->name);
 
     /* give some infos about the hardware */
-    printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %s\n",
+    printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %pM\n",
 	   dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq,
-	   print_mac(mac, dev->dev_addr));
+	   dev->dev_addr);
 
     return 0;
 
@@ -1243,7 +1242,6 @@
 		}
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
-		dev->last_rx = jiffies;
 		lp->stats.rx_packets++;
 		lp->stats.rx_bytes += pktlen;
 		if (!(rsr & PhyPkt))
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index ca8c0e0..044b7b0 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1246,7 +1246,6 @@
 	dev->stats.rx_bytes += skb->len;
 	skb->protocol = eth_type_trans(skb, dev);
 	netif_receive_skb(skb);
-	dev->last_rx = jiffies;
 	dev->stats.rx_packets++;
 	return;
 }
@@ -1398,7 +1397,7 @@
 	if (work_done < budget) {
 		spin_lock_irqsave(&lp->lock, flags);
 
-		__netif_rx_complete(dev, napi);
+		__netif_rx_complete(napi);
 
 		/* clear interrupt masks */
 		val = lp->a.read_csr(ioaddr, CSR3);
@@ -1747,8 +1746,7 @@
 		memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
 
 	if (pcnet32_debug & NETIF_MSG_PROBE) {
-		DECLARE_MAC_BUF(mac);
-		printk(" %s", print_mac(mac, dev->dev_addr));
+		printk(" %pM", dev->dev_addr);
 
 		/* Version 0x2623 and 0x2624 */
 		if (((chip_version + 1) & 0xfffe) == 0x2624) {
@@ -2588,14 +2586,14 @@
 				       dev->name, csr0);
 			/* unlike for the lance, there is no restart needed */
 		}
-		if (netif_rx_schedule_prep(dev, &lp->napi)) {
+		if (netif_rx_schedule_prep(&lp->napi)) {
 			u16 val;
 			/* set interrupt masks */
 			val = lp->a.read_csr(ioaddr, CSR3);
 			val |= 0x5f00;
 			lp->a.write_csr(ioaddr, CSR3, val);
 			mmiowb();
-			__netif_rx_schedule(dev, &lp->napi);
+			__netif_rx_schedule(&lp->napi);
 			break;
 		}
 		csr0 = lp->a.read_csr(ioaddr, CSR0);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index d55932a..de9cf51 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -66,6 +66,22 @@
 	---help---
 	  Supports the Realtek 821x PHY.
 
+config NATIONAL_PHY
+	tristate "Drivers for National Semiconductor PHYs"
+	---help---
+	  Currently supports the DP83865 PHY.
+
+config STE10XP
+	depends on PHYLIB
+	tristate "Driver for STMicroelectronics STe10Xp PHYs"
+	---help---
+	  This is the driver for the STe100p and STe101p PHYs.
+
+config LSI_ET1011C_PHY
+	tristate "Driver for LSI ET1011C PHY"
+	---help---
+	  Supports the LSI ET1011C PHY.
+
 config FIXED_PHY
 	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
 	depends on PHYLIB=y
@@ -84,10 +100,13 @@
 
 	  If in doubt, say N.
 
-config MDIO_OF_GPIO
+config MDIO_GPIO
 	tristate "Support for GPIO lib-based bitbanged MDIO buses"
-	depends on MDIO_BITBANG && OF_GPIO
+	depends on MDIO_BITBANG && GENERIC_GPIO
 	---help---
 	  Supports GPIO lib-based MDIO busses.
 
+	  To compile this driver as a module, choose M here: the module
+	  will be called mdio-gpio.
+
 endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index eee329f..3a1bfef 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -13,6 +13,9 @@
 obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
 obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
 obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
 obj-$(CONFIG_FIXED_PHY)		+= fixed.o
 obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
-obj-$(CONFIG_MDIO_OF_GPIO)	+= mdio-ofgpio.o
+obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
+obj-$(CONFIG_NATIONAL_PHY)	+= national.o
+obj-$(CONFIG_STE10XP)		+= ste10Xp.o
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 4b4dc98..190efc3 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -17,6 +17,8 @@
 #include <linux/module.h>
 #include <linux/phy.h>
 
+#define PHY_ID_BCM50610		0x0143bd60
+
 #define MII_BCM54XX_ECR		0x10	/* BCM54xx extended control register */
 #define MII_BCM54XX_ECR_IM	0x1000	/* Interrupt mask */
 #define MII_BCM54XX_ECR_IF	0x0800	/* Interrupt force */
@@ -54,6 +56,21 @@
 #define MII_BCM54XX_SHD_DATA(x)	((x & 0x3ff) << 0)
 
 /*
+ * AUXILIARY CONTROL SHADOW ACCESS REGISTERS.  (PHY REG 0x18)
+ */
+#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL	0x0000
+#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB		0x0400
+#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA	0x0800
+
+#define MII_BCM54XX_AUXCTL_MISC_WREN	0x8000
+#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX	0x0200
+#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC	0x7000
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC	0x0007
+
+#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL	0x0000
+
+
+/*
  * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
  * BCM5482, and possibly some others.
  */
@@ -88,6 +105,24 @@
 #define BCM5482_SHD_MODE_1000BX	0x0001	/* Enable 1000BASE-X registers */
 
 /*
+ * EXPANSION SHADOW ACCESS REGISTERS.  (PHY REG 0x15, 0x16, and 0x17)
+ */
+#define MII_BCM54XX_EXP_AADJ1CH0		0x001f
+#define  MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN	0x0200
+#define  MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF	0x0100
+#define MII_BCM54XX_EXP_AADJ1CH3		0x601f
+#define  MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ	0x0002
+#define MII_BCM54XX_EXP_EXP08			0x0F08
+#define  MII_BCM54XX_EXP_EXP08_RJCT_2MHZ	0x0001
+#define  MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE	0x0200
+#define MII_BCM54XX_EXP_EXP75			0x0f75
+#define  MII_BCM54XX_EXP_EXP75_VDACCTRL		0x003c
+#define MII_BCM54XX_EXP_EXP96			0x0f96
+#define  MII_BCM54XX_EXP_EXP96_MYST		0x0010
+#define MII_BCM54XX_EXP_EXP97			0x0f97
+#define  MII_BCM54XX_EXP_EXP97_MYST		0x0c0c
+
+/*
  * BCM5482: Secondary SerDes registers
  */
 #define BCM5482_SSD_1000BX_CTL		0x00	/* 1000BASE-X Control */
@@ -128,40 +163,93 @@
 			 MII_BCM54XX_SHD_DATA(val));
 }
 
-/*
- * Indirect register access functions for the Expansion Registers
- * and Secondary SerDes registers (when sec_serdes=1).
- */
-static int bcm54xx_exp_read(struct phy_device *phydev,
-			    int sec_serdes, u8 regnum)
+/* Indirect register access functions for the Expansion Registers */
+static int bcm54xx_exp_read(struct phy_device *phydev, u8 regnum)
 {
 	int val;
 
-	phy_write(phydev, MII_BCM54XX_EXP_SEL,
-		  (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD :
-				MII_BCM54XX_EXP_SEL_ER) |
-		  regnum);
+	val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+	if (val < 0)
+		return val;
+
 	val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
-	phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+
+	/* Restore default value.  It's O.K. if this write fails. */
+	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
 
 	return val;
 }
 
-static int bcm54xx_exp_write(struct phy_device *phydev,
-			     int sec_serdes, u8 regnum, u16 val)
+static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
 {
 	int ret;
 
-	phy_write(phydev, MII_BCM54XX_EXP_SEL,
-		  (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD :
-				MII_BCM54XX_EXP_SEL_ER) |
-		  regnum);
+	ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+	if (ret < 0)
+		return ret;
+
 	ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
-	phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+
+	/* Restore default value.  It's O.K. if this write fails. */
+	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
 
 	return ret;
 }
 
+static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
+{
+	return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
+}
+
+static int bcm50610_a0_workaround(struct phy_device *phydev)
+{
+	int err;
+
+	err = bcm54xx_auxctl_write(phydev,
+				   MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
+				   MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
+				   MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
+	if (err < 0)
+		return err;
+
+	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
+				MII_BCM54XX_EXP_EXP08_RJCT_2MHZ	|
+				MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE);
+	if (err < 0)
+		goto error;
+
+	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
+				MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
+				MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
+	if (err < 0)
+		goto error;
+
+	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
+					MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
+	if (err < 0)
+		goto error;
+
+	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
+				MII_BCM54XX_EXP_EXP75_VDACCTRL);
+	if (err < 0)
+		goto error;
+
+	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
+				MII_BCM54XX_EXP_EXP96_MYST);
+	if (err < 0)
+		goto error;
+
+	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
+				MII_BCM54XX_EXP_EXP97_MYST);
+
+error:
+	bcm54xx_auxctl_write(phydev,
+			     MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
+			     MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
+
+	return err;
+}
+
 static int bcm54xx_config_init(struct phy_device *phydev)
 {
 	int reg, err;
@@ -183,6 +271,13 @@
 	err = phy_write(phydev, MII_BCM54XX_IMR, reg);
 	if (err < 0)
 		return err;
+
+	if (phydev->drv->phy_id == PHY_ID_BCM50610) {
+		err = bcm50610_a0_workaround(phydev);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
 
@@ -205,18 +300,27 @@
 		/*
 		 * Enable SGMII slave mode and auto-detection
 		 */
-		reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_SGMII_SLAVE);
-		bcm54xx_exp_write(phydev, 1, BCM5482_SSD_SGMII_SLAVE,
-				  reg |
-				  BCM5482_SSD_SGMII_SLAVE_EN |
-				  BCM5482_SSD_SGMII_SLAVE_AD);
+		reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
+		err = bcm54xx_exp_read(phydev, reg);
+		if (err < 0)
+			return err;
+		err = bcm54xx_exp_write(phydev, reg, err |
+					BCM5482_SSD_SGMII_SLAVE_EN |
+					BCM5482_SSD_SGMII_SLAVE_AD);
+		if (err < 0)
+			return err;
 
 		/*
 		 * Disable secondary SerDes powerdown
 		 */
-		reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_1000BX_CTL);
-		bcm54xx_exp_write(phydev, 1, BCM5482_SSD_1000BX_CTL,
-				  reg & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
+		reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
+		err = bcm54xx_exp_read(phydev, reg);
+		if (err < 0)
+			return err;
+		err = bcm54xx_exp_write(phydev, reg,
+					err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
+		if (err < 0)
+			return err;
 
 		/*
 		 * Select 1000BASE-X register set (primary SerDes)
@@ -335,7 +439,8 @@
 	.phy_id		= 0x00206070,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5411",
-	.features	= PHY_GBIT_FEATURES,
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
@@ -349,7 +454,8 @@
 	.phy_id		= 0x002060e0,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5421",
-	.features	= PHY_GBIT_FEATURES,
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
@@ -363,7 +469,8 @@
 	.phy_id		= 0x002060c0,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5461",
-	.features	= PHY_GBIT_FEATURES,
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
@@ -377,7 +484,8 @@
 	.phy_id		= 0x002060b0,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5464",
-	.features	= PHY_GBIT_FEATURES,
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
@@ -391,7 +499,8 @@
 	.phy_id		= 0x0143bca0,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5481",
-	.features	= PHY_GBIT_FEATURES,
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= bcm5481_config_aneg,
@@ -405,7 +514,8 @@
 	.phy_id		= 0x0143bcb0,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Broadcom BCM5482",
-	.features	= PHY_GBIT_FEATURES,
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 	.config_init	= bcm5482_config_init,
 	.config_aneg	= genphy_config_aneg,
@@ -415,6 +525,36 @@
 	.driver 	= { .owner = THIS_MODULE },
 };
 
+static struct phy_driver bcm50610_driver = {
+	.phy_id		= PHY_ID_BCM50610,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM50610",
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= bcm54xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm54xx_ack_interrupt,
+	.config_intr	= bcm54xx_config_intr,
+	.driver 	= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver bcm57780_driver = {
+	.phy_id		= 0x03625d90,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "Broadcom BCM57780",
+	.features	= PHY_GBIT_FEATURES |
+			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= bcm54xx_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= bcm54xx_ack_interrupt,
+	.config_intr	= bcm54xx_config_intr,
+	.driver 	= { .owner = THIS_MODULE },
+};
+
 static int __init broadcom_init(void)
 {
 	int ret;
@@ -437,8 +577,18 @@
 	ret = phy_driver_register(&bcm5482_driver);
 	if (ret)
 		goto out_5482;
+	ret = phy_driver_register(&bcm50610_driver);
+	if (ret)
+		goto out_50610;
+	ret = phy_driver_register(&bcm57780_driver);
+	if (ret)
+		goto out_57780;
 	return ret;
 
+out_57780:
+	phy_driver_unregister(&bcm50610_driver);
+out_50610:
+	phy_driver_unregister(&bcm5482_driver);
 out_5482:
 	phy_driver_unregister(&bcm5481_driver);
 out_5481:
@@ -455,6 +605,8 @@
 
 static void __exit broadcom_exit(void)
 {
+	phy_driver_unregister(&bcm57780_driver);
+	phy_driver_unregister(&bcm50610_driver);
 	phy_driver_unregister(&bcm5482_driver);
 	phy_driver_unregister(&bcm5481_driver);
 	phy_driver_unregister(&bcm5464_driver);
diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c
new file mode 100644
index 0000000..b031fa2
--- /dev/null
+++ b/drivers/net/phy/et1011c.c
@@ -0,0 +1,113 @@
+/*
+ * drivers/net/phy/et1011c.c
+ *
+ * Driver for LSI ET1011C PHYs
+ *
+ * Author: Chaithrika U S
+ *
+ * Copyright (c) 2008 Texas Instruments
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <asm/irq.h>
+
+#define ET1011C_STATUS_REG	(0x1A)
+#define ET1011C_CONFIG_REG	(0x16)
+#define ET1011C_SPEED_MASK		(0x0300)
+#define ET1011C_GIGABIT_SPEED		(0x0200)
+#define ET1011C_TX_FIFO_MASK		(0x3000)
+#define ET1011C_TX_FIFO_DEPTH_8		(0x0000)
+#define ET1011C_TX_FIFO_DEPTH_16	(0x1000)
+#define ET1011C_INTERFACE_MASK		(0x0007)
+#define ET1011C_GMII_INTERFACE		(0x0002)
+#define ET1011C_SYS_CLK_EN		(0x01 << 4)
+
+
+MODULE_DESCRIPTION("LSI ET1011C PHY driver");
+MODULE_AUTHOR("Chaithrika U S");
+MODULE_LICENSE("GPL");
+
+static int et1011c_config_aneg(struct phy_device *phydev)
+{
+	int ctl = 0;
+	ctl = phy_read(phydev, MII_BMCR);
+	if (ctl < 0)
+		return ctl;
+	ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 |
+		 BMCR_ANENABLE);
+	/* First clear the PHY */
+	phy_write(phydev, MII_BMCR, ctl | BMCR_RESET);
+
+	return genphy_config_aneg(phydev);
+}
+
+static int et1011c_read_status(struct phy_device *phydev)
+{
+	int ret;
+	u32 val;
+	static int speed;
+	ret = genphy_read_status(phydev);
+
+	if (speed != phydev->speed) {
+		speed = phydev->speed;
+		val = phy_read(phydev, ET1011C_STATUS_REG);
+		if ((val & ET1011C_SPEED_MASK) ==
+					ET1011C_GIGABIT_SPEED) {
+			val = phy_read(phydev, ET1011C_CONFIG_REG);
+			val &= ~ET1011C_TX_FIFO_MASK;
+			phy_write(phydev, ET1011C_CONFIG_REG, val\
+					| ET1011C_GMII_INTERFACE\
+					| ET1011C_SYS_CLK_EN\
+					| ET1011C_TX_FIFO_DEPTH_16);
+
+		}
+	}
+	return ret;
+}
+
+static struct phy_driver et1011c_driver = {
+	.phy_id		= 0x0282f014,
+	.name		= "ET1011C",
+	.phy_id_mask	= 0xfffffff0,
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_1000baseT_Full),
+	.flags		= PHY_POLL,
+	.config_aneg	= et1011c_config_aneg,
+	.read_status	= et1011c_read_status,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static int __init et1011c_init(void)
+{
+	return phy_driver_register(&et1011c_driver);
+}
+
+static void __exit et1011c_exit(void)
+{
+	phy_driver_unregister(&et1011c_driver);
+}
+
+module_init(et1011c_init);
+module_exit(et1011c_exit);
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
new file mode 100644
index 0000000..a439ebe
--- /dev/null
+++ b/drivers/net/phy/mdio-gpio.c
@@ -0,0 +1,296 @@
+/*
+ * GPIO based MDIO bitbang driver.
+ * Supports OpenFirmware.
+ *
+ * Copyright (c) 2008 CSE Semaphore Belgium.
+ *  by Laurent Pinchart <laurentp@cse-semaphore.com>
+ *
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * Based on earlier work by
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.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/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mdio-gpio.h>
+
+#ifdef CONFIG_OF_GPIO
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#endif
+
+struct mdio_gpio_info {
+	struct mdiobb_ctrl ctrl;
+	int mdc, mdio;
+};
+
+static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
+{
+	struct mdio_gpio_info *bitbang =
+		container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+	if (dir)
+		gpio_direction_output(bitbang->mdio, 1);
+	else
+		gpio_direction_input(bitbang->mdio);
+}
+
+static int mdio_get(struct mdiobb_ctrl *ctrl)
+{
+	struct mdio_gpio_info *bitbang =
+		container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+	return gpio_get_value(bitbang->mdio);
+}
+
+static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
+{
+	struct mdio_gpio_info *bitbang =
+		container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+	gpio_set_value(bitbang->mdio, what);
+}
+
+static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
+{
+	struct mdio_gpio_info *bitbang =
+		container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+	gpio_set_value(bitbang->mdc, what);
+}
+
+static struct mdiobb_ops mdio_gpio_ops = {
+	.owner = THIS_MODULE,
+	.set_mdc = mdc_set,
+	.set_mdio_dir = mdio_dir,
+	.set_mdio_data = mdio_set,
+	.get_mdio_data = mdio_get,
+};
+
+static int __devinit mdio_gpio_bus_init(struct device *dev,
+					struct mdio_gpio_platform_data *pdata,
+					int bus_id)
+{
+	struct mii_bus *new_bus;
+	struct mdio_gpio_info *bitbang;
+	int ret = -ENOMEM;
+	int i;
+
+	bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
+	if (!bitbang)
+		goto out;
+
+	bitbang->ctrl.ops = &mdio_gpio_ops;
+	bitbang->mdc = pdata->mdc;
+	bitbang->mdio = pdata->mdio;
+
+	new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+	if (!new_bus)
+		goto out_free_bitbang;
+
+	new_bus->name = "GPIO Bitbanged MDIO",
+
+	ret = -ENODEV;
+
+	new_bus->phy_mask = pdata->phy_mask;
+	new_bus->irq = pdata->irqs;
+	new_bus->parent = dev;
+
+	if (new_bus->phy_mask == ~0)
+		goto out_free_bus;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		if (!new_bus->irq[i])
+			new_bus->irq[i] = PHY_POLL;
+
+	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bus_id);
+
+	if (gpio_request(bitbang->mdc, "mdc"))
+		goto out_free_bus;
+
+	if (gpio_request(bitbang->mdio, "mdio"))
+		goto out_free_mdc;
+
+	dev_set_drvdata(dev, new_bus);
+
+	ret = mdiobus_register(new_bus);
+	if (ret)
+		goto out_free_all;
+
+	return 0;
+
+out_free_all:
+	dev_set_drvdata(dev, NULL);
+	gpio_free(bitbang->mdio);
+out_free_mdc:
+	gpio_free(bitbang->mdc);
+out_free_bus:
+	free_mdio_bitbang(new_bus);
+out_free_bitbang:
+	kfree(bitbang);
+out:
+	return ret;
+}
+
+static void __devexit mdio_gpio_bus_destroy(struct device *dev)
+{
+	struct mii_bus *bus = dev_get_drvdata(dev);
+	struct mdio_gpio_info *bitbang = bus->priv;
+
+	mdiobus_unregister(bus);
+	free_mdio_bitbang(bus);
+	dev_set_drvdata(dev, NULL);
+	gpio_free(bitbang->mdc);
+	gpio_free(bitbang->mdio);
+	kfree(bitbang);
+}
+
+static int __devinit mdio_gpio_probe(struct platform_device *pdev)
+{
+	struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!pdata)
+		return -ENODEV;
+
+	return mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
+}
+
+static int __devexit mdio_gpio_remove(struct platform_device *pdev)
+{
+	mdio_gpio_bus_destroy(&pdev->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF_GPIO
+static void __devinit add_phy(struct mdio_gpio_platform_data *pdata,
+			      struct device_node *np)
+{
+	const u32 *data;
+	int len, id, irq;
+
+	data = of_get_property(np, "reg", &len);
+	if (!data || len != 4)
+		return;
+
+	id = *data;
+	pdata->phy_mask &= ~(1 << id);
+
+	irq = of_irq_to_resource(np, 0, NULL);
+	if (irq)
+		pdata->irqs[id] = irq;
+}
+
+static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
+                                        const struct of_device_id *match)
+{
+	struct device_node *np = NULL;
+	struct mdio_gpio_platform_data *pdata;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdata->mdc = of_get_gpio(ofdev->node, 0);
+	pdata->mdio = of_get_gpio(ofdev->node, 1);
+
+	if (pdata->mdc < 0 || pdata->mdio < 0)
+		goto out_free;
+
+	while ((np = of_get_next_child(ofdev->node, np)))
+		if (!strcmp(np->type, "ethernet-phy"))
+			add_phy(pdata, np);
+
+	return mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
+
+out_free:
+	kfree(pdata);
+	return -ENODEV;
+}
+
+static int __devexit mdio_ofgpio_remove(struct of_device *ofdev)
+{
+	mdio_gpio_bus_destroy(&ofdev->dev);
+	kfree(ofdev->dev.platform_data);
+
+	return 0;
+}
+
+static struct of_device_id mdio_ofgpio_match[] = {
+	{
+		.compatible = "virtual,mdio-gpio",
+	},
+	{},
+};
+
+static struct of_platform_driver mdio_ofgpio_driver = {
+	.name = "mdio-gpio",
+	.match_table = mdio_ofgpio_match,
+	.probe = mdio_ofgpio_probe,
+	.remove = __devexit_p(mdio_ofgpio_remove),
+};
+
+static inline int __init mdio_ofgpio_init(void)
+{
+	return of_register_platform_driver(&mdio_ofgpio_driver);
+}
+
+static inline void __exit mdio_ofgpio_exit(void)
+{
+	of_unregister_platform_driver(&mdio_ofgpio_driver);
+}
+#else
+static inline int __init mdio_ofgpio_init(void) { return 0; }
+static inline void __exit mdio_ofgpio_exit(void) { }
+#endif /* CONFIG_OF_GPIO */
+
+static struct platform_driver mdio_gpio_driver = {
+	.probe = mdio_gpio_probe,
+	.remove = __devexit_p(mdio_gpio_remove),
+	.driver		= {
+		.name	= "mdio-gpio",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init mdio_gpio_init(void)
+{
+	int ret;
+
+	ret = mdio_ofgpio_init();
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&mdio_gpio_driver);
+	if (ret)
+		mdio_ofgpio_exit();
+
+	return ret;
+}
+module_init(mdio_gpio_init);
+
+static void __exit mdio_gpio_exit(void)
+{
+	platform_driver_unregister(&mdio_gpio_driver);
+	mdio_ofgpio_exit();
+}
+module_exit(mdio_gpio_exit);
+
+MODULE_ALIAS("platform:mdio-gpio");
+MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");
diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c
deleted file mode 100644
index 2ff9775..0000000
--- a/drivers/net/phy/mdio-ofgpio.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * OpenFirmware GPIO based MDIO bitbang driver.
- *
- * Copyright (c) 2008 CSE Semaphore Belgium.
- *  by Laurent Pinchart <laurentp@cse-semaphore.com>
- *
- * Based on earlier work by
- *
- * Copyright (c) 2003 Intracom S.A.
- *  by Pantelis Antoniou <panto@intracom.gr>
- *
- * 2005 (c) MontaVista Software, Inc.
- * Vitaly Bordug <vbordug@ru.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/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/mdio-bitbang.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
-
-struct mdio_gpio_info {
-	struct mdiobb_ctrl ctrl;
-	int mdc, mdio;
-};
-
-static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
-{
-	struct mdio_gpio_info *bitbang =
-		container_of(ctrl, struct mdio_gpio_info, ctrl);
-
-	if (dir)
-		gpio_direction_output(bitbang->mdio, 1);
-	else
-		gpio_direction_input(bitbang->mdio);
-}
-
-static int mdio_read(struct mdiobb_ctrl *ctrl)
-{
-	struct mdio_gpio_info *bitbang =
-		container_of(ctrl, struct mdio_gpio_info, ctrl);
-
-	return gpio_get_value(bitbang->mdio);
-}
-
-static void mdio(struct mdiobb_ctrl *ctrl, int what)
-{
-	struct mdio_gpio_info *bitbang =
-		container_of(ctrl, struct mdio_gpio_info, ctrl);
-
-	gpio_set_value(bitbang->mdio, what);
-}
-
-static void mdc(struct mdiobb_ctrl *ctrl, int what)
-{
-	struct mdio_gpio_info *bitbang =
-		container_of(ctrl, struct mdio_gpio_info, ctrl);
-
-	gpio_set_value(bitbang->mdc, what);
-}
-
-static struct mdiobb_ops mdio_gpio_ops = {
-	.owner = THIS_MODULE,
-	.set_mdc = mdc,
-	.set_mdio_dir = mdio_dir,
-	.set_mdio_data = mdio,
-	.get_mdio_data = mdio_read,
-};
-
-static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
-                                         struct device_node *np)
-{
-	struct mdio_gpio_info *bitbang = bus->priv;
-
-	bitbang->mdc = of_get_gpio(np, 0);
-	bitbang->mdio = of_get_gpio(np, 1);
-
-	if (bitbang->mdc < 0 || bitbang->mdio < 0)
-		return -ENODEV;
-
-	snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
-	return 0;
-}
-
-static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
-{
-	const u32 *data;
-	int len, id, irq;
-
-	data = of_get_property(np, "reg", &len);
-	if (!data || len != 4)
-		return;
-
-	id = *data;
-	bus->phy_mask &= ~(1 << id);
-
-	irq = of_irq_to_resource(np, 0, NULL);
-	if (irq != NO_IRQ)
-		bus->irq[id] = irq;
-}
-
-static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
-                                        const struct of_device_id *match)
-{
-	struct device_node *np = NULL;
-	struct mii_bus *new_bus;
-	struct mdio_gpio_info *bitbang;
-	int ret = -ENOMEM;
-	int i;
-
-	bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
-	if (!bitbang)
-		goto out;
-
-	bitbang->ctrl.ops = &mdio_gpio_ops;
-
-	new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
-	if (!new_bus)
-		goto out_free_bitbang;
-
-	new_bus->name = "GPIO Bitbanged MII",
-
-	ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
-	if (ret)
-		goto out_free_bus;
-
-	new_bus->phy_mask = ~0;
-	new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
-	if (!new_bus->irq)
-		goto out_free_bus;
-
-	for (i = 0; i < PHY_MAX_ADDR; i++)
-		new_bus->irq[i] = -1;
-
-	while ((np = of_get_next_child(ofdev->node, np)))
-		if (!strcmp(np->type, "ethernet-phy"))
-			add_phy(new_bus, np);
-
-	new_bus->parent = &ofdev->dev;
-	dev_set_drvdata(&ofdev->dev, new_bus);
-
-	ret = mdiobus_register(new_bus);
-	if (ret)
-		goto out_free_irqs;
-
-	return 0;
-
-out_free_irqs:
-	dev_set_drvdata(&ofdev->dev, NULL);
-	kfree(new_bus->irq);
-out_free_bus:
-	free_mdio_bitbang(new_bus);
-out_free_bitbang:
-	kfree(bitbang);
-out:
-	return ret;
-}
-
-static int mdio_ofgpio_remove(struct of_device *ofdev)
-{
-	struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
-	struct mdio_gpio_info *bitbang = bus->priv;
-
-	mdiobus_unregister(bus);
-	kfree(bus->irq);
-	free_mdio_bitbang(bus);
-	dev_set_drvdata(&ofdev->dev, NULL);
-	kfree(bitbang);
-
-	return 0;
-}
-
-static struct of_device_id mdio_ofgpio_match[] = {
-	{
-		.compatible = "virtual,mdio-gpio",
-	},
-	{},
-};
-
-static struct of_platform_driver mdio_ofgpio_driver = {
-	.name = "mdio-gpio",
-	.match_table = mdio_ofgpio_match,
-	.probe = mdio_ofgpio_probe,
-	.remove = mdio_ofgpio_remove,
-};
-
-static int mdio_ofgpio_init(void)
-{
-	return of_register_platform_driver(&mdio_ofgpio_driver);
-}
-
-static void mdio_ofgpio_exit(void)
-{
-	of_unregister_platform_driver(&mdio_ofgpio_driver);
-}
-
-module_init(mdio_ofgpio_init);
-module_exit(mdio_ofgpio_exit);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 289fc26..11adf6e 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -63,7 +63,9 @@
 static void mdiobus_release(struct device *d)
 {
 	struct mii_bus *bus = to_mii_bus(d);
-	BUG_ON(bus->state != MDIOBUS_RELEASED);
+	BUG_ON(bus->state != MDIOBUS_RELEASED &&
+	       /* for compatibility with error handling in drivers */
+	       bus->state != MDIOBUS_ALLOCATED);
 	kfree(bus);
 }
 
@@ -83,8 +85,7 @@
  */
 int mdiobus_register(struct mii_bus *bus)
 {
-	int i;
-	int err = 0;
+	int i, err;
 
 	if (NULL == bus || NULL == bus->name ||
 			NULL == bus->read ||
@@ -97,7 +98,7 @@
 	bus->dev.parent = bus->parent;
 	bus->dev.class = &mdio_bus_class;
 	bus->dev.groups = NULL;
-	memcpy(bus->dev.bus_id, bus->id, MII_BUS_ID_SIZE);
+	dev_set_name(&bus->dev, bus->id);
 
 	err = device_register(&bus->dev);
 	if (err) {
@@ -116,16 +117,23 @@
 			struct phy_device *phydev;
 
 			phydev = mdiobus_scan(bus, i);
-			if (IS_ERR(phydev))
+			if (IS_ERR(phydev)) {
 				err = PTR_ERR(phydev);
+				goto error;
+			}
 		}
 	}
 
-	if (!err)
-		bus->state = MDIOBUS_REGISTERED;
-
+	bus->state = MDIOBUS_REGISTERED;
 	pr_info("%s: probed\n", bus->name);
+	return 0;
 
+error:
+	while (--i >= 0) {
+		if (bus->phy_map[i])
+			device_unregister(&bus->phy_map[i]->dev);
+	}
+	device_del(&bus->dev);
 	return err;
 }
 EXPORT_SYMBOL(mdiobus_register);
@@ -192,7 +200,7 @@
 
 	phydev->dev.parent = bus->parent;
 	phydev->dev.bus = &mdio_bus_type;
-	snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, addr);
+	dev_set_name(&phydev->dev, PHY_ID_FMT, bus->id, addr);
 
 	phydev->bus = bus;
 
@@ -285,9 +293,12 @@
 {
 	int ret = 0;
 	struct device_driver *drv = dev->driver;
+	struct phy_driver *phydrv = to_phy_driver(drv);
+	struct phy_device *phydev = to_phy_device(dev);
 
-	if (drv && drv->suspend)
-		ret = drv->suspend(dev, state);
+	if ((!device_may_wakeup(phydev->dev.parent)) &&
+		(phydrv && phydrv->suspend))
+			ret = phydrv->suspend(phydev);
 
 	return ret;
 }
@@ -296,9 +307,12 @@
 {
 	int ret = 0;
 	struct device_driver *drv = dev->driver;
+	struct phy_driver *phydrv = to_phy_driver(drv);
+	struct phy_device *phydev = to_phy_device(dev);
 
-	if (drv && drv->resume)
-		ret = drv->resume(dev);
+	if ((!device_may_wakeup(phydev->dev.parent)) &&
+		(phydrv && phydrv->resume))
+		ret = phydrv->resume(phydev);
 
 	return ret;
 }
diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c
new file mode 100644
index 0000000..6c636eb
--- /dev/null
+++ b/drivers/net/phy/national.c
@@ -0,0 +1,155 @@
+/*
+ * drivers/net/phy/national.c
+ *
+ * Driver for National Semiconductor PHYs
+ *
+ * Author: Stuart Menefy <stuart.menefy@st.com>
+ * Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *
+ * Copyright (c) 2008 STMicroelectronics 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+
+/* DP83865 phy identifier values */
+#define DP83865_PHY_ID	0x20005c7a
+
+#define DP83865_INT_MASK_REG 0x15
+#define DP83865_INT_MASK_STATUS 0x14
+
+#define DP83865_INT_REMOTE_FAULT 0x0008
+#define DP83865_INT_ANE_COMPLETED 0x0010
+#define DP83865_INT_LINK_CHANGE	0xe000
+#define DP83865_INT_MASK_DEFAULT (DP83865_INT_REMOTE_FAULT | \
+				DP83865_INT_ANE_COMPLETED | \
+				DP83865_INT_LINK_CHANGE)
+
+/* Advanced proprietary configuration */
+#define NS_EXP_MEM_CTL	0x16
+#define NS_EXP_MEM_DATA	0x1d
+#define NS_EXP_MEM_ADD	0x1e
+
+#define LED_CTRL_REG 0x13
+#define AN_FALLBACK_AN 0x0001
+#define AN_FALLBACK_CRC 0x0002
+#define AN_FALLBACK_IE 0x0004
+#define ALL_FALLBACK_ON (AN_FALLBACK_AN |  AN_FALLBACK_CRC | AN_FALLBACK_IE)
+
+enum hdx_loopback {
+	hdx_loopback_on = 0,
+	hdx_loopback_off = 1,
+};
+
+static u8 ns_exp_read(struct phy_device *phydev, u16 reg)
+{
+	phy_write(phydev, NS_EXP_MEM_ADD, reg);
+	return phy_read(phydev, NS_EXP_MEM_DATA);
+}
+
+static void ns_exp_write(struct phy_device *phydev, u16 reg, u8 data)
+{
+	phy_write(phydev, NS_EXP_MEM_ADD, reg);
+	phy_write(phydev, NS_EXP_MEM_DATA, data);
+}
+
+static int ns_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, DP83865_INT_MASK_REG,
+				DP83865_INT_MASK_DEFAULT);
+	else
+		err = phy_write(phydev, DP83865_INT_MASK_REG, 0);
+
+	return err;
+}
+
+static int ns_ack_interrupt(struct phy_device *phydev)
+{
+	int ret = phy_read(phydev, DP83865_INT_MASK_STATUS);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void ns_giga_speed_fallback(struct phy_device *phydev, int mode)
+{
+	int bmcr = phy_read(phydev, MII_BMCR);
+
+	phy_write(phydev, MII_BMCR, (bmcr | BMCR_PDOWN));
+
+	/* Enable 8 bit expended memory read/write (no auto increment) */
+	phy_write(phydev, NS_EXP_MEM_CTL, 0);
+	phy_write(phydev, NS_EXP_MEM_ADD, 0x1C0);
+	phy_write(phydev, NS_EXP_MEM_DATA, 0x0008);
+	phy_write(phydev, MII_BMCR, (bmcr & ~BMCR_PDOWN));
+	phy_write(phydev, LED_CTRL_REG, mode);
+	return;
+}
+
+static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable)
+{
+	if (disable)
+		ns_exp_write(phydev, 0x1c0, ns_exp_read(phydev, 0x1c0) | 1);
+	else
+		ns_exp_write(phydev, 0x1c0,
+			     ns_exp_read(phydev, 0x1c0) & 0xfffe);
+
+	printk(KERN_DEBUG "DP83865 PHY: 10BASE-T HDX loopback %s\n",
+	       (ns_exp_read(phydev, 0x1c0) & 0x0001) ? "off" : "on");
+
+	return;
+}
+
+static int ns_config_init(struct phy_device *phydev)
+{
+	ns_giga_speed_fallback(phydev, ALL_FALLBACK_ON);
+	/* In the latest MAC or switches design, the 10 Mbps loopback
+	   is desired to be turned off. */
+	ns_10_base_t_hdx_loopack(phydev, hdx_loopback_off);
+	return ns_ack_interrupt(phydev);
+}
+
+static struct phy_driver dp83865_driver = {
+	.phy_id = DP83865_PHY_ID,
+	.phy_id_mask = 0xfffffff0,
+	.name = "NatSemi DP83865",
+	.features = PHY_GBIT_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+	.flags = PHY_HAS_INTERRUPT,
+	.config_init = ns_config_init,
+	.config_aneg = genphy_config_aneg,
+	.read_status = genphy_read_status,
+	.ack_interrupt = ns_ack_interrupt,
+	.config_intr = ns_config_intr,
+	.driver = {.owner = THIS_MODULE,}
+};
+
+static int __init ns_init(void)
+{
+	return phy_driver_register(&dp83865_driver);
+}
+
+static void __exit ns_exit(void)
+{
+	phy_driver_unregister(&dp83865_driver);
+}
+
+MODULE_DESCRIPTION("NatSemi PHY driver");
+MODULE_AUTHOR("Stuart Menefy");
+MODULE_LICENSE("GPL");
+
+module_init(ns_init);
+module_exit(ns_exit);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index df4e625..e4ede60 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -45,7 +45,7 @@
  */
 void phy_print_status(struct phy_device *phydev)
 {
-	pr_info("PHY: %s - Link is %s", phydev->dev.bus_id,
+	pr_info("PHY: %s - Link is %s", dev_name(&phydev->dev),
 			phydev->link ? "Up" : "Down");
 	if (phydev->link)
 		printk(" - %d/%s", phydev->speed,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 25acbbd..e354601 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -74,7 +74,7 @@
 	if (!fixup)
 		return -ENOMEM;
 
-	strncpy(fixup->bus_id, bus_id, BUS_ID_SIZE);
+	strlcpy(fixup->bus_id, bus_id, sizeof(fixup->bus_id));
 	fixup->phy_uid = phy_uid;
 	fixup->phy_uid_mask = phy_uid_mask;
 	fixup->run = run;
@@ -109,7 +109,7 @@
  */
 static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)
 {
-	if (strcmp(fixup->bus_id, phydev->dev.bus_id) != 0)
+	if (strcmp(fixup->bus_id, dev_name(&phydev->dev)) != 0)
 		if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0)
 			return 0;
 
@@ -232,7 +232,7 @@
 		return NULL;
 
 	/*
-	 * Broken hardware is sometimes missing the pull down resistor on the
+	 * Broken hardware is sometimes missing the pull-up resistor on the
 	 * MDIO line, which results in reads to non-existent devices returning
 	 * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent
 	 * device as well.
@@ -517,23 +517,6 @@
 	
 	err = phy_write(phydev, MII_BMCR, ctl);
 
-	if (err < 0)
-		return err;
-
-	/*
-	 * Run the fixups on this PHY, just in case the
-	 * board code needs to change something after a reset
-	 */
-	err = phy_scan_fixups(phydev);
-
-	if (err < 0)
-		return err;
-
-	/* We just reset the device, so we'd better configure any
-	 * settings the PHY requires to operate */
-	if (phydev->drv->config_init)
-		err = phydev->drv->config_init(phydev);
-
 	return err;
 }
 
@@ -779,7 +762,35 @@
 
 	return 0;
 }
+int genphy_suspend(struct phy_device *phydev)
+{
+	int value;
 
+	mutex_lock(&phydev->lock);
+
+	value = phy_read(phydev, MII_BMCR);
+	phy_write(phydev, MII_BMCR, (value | BMCR_PDOWN));
+
+	mutex_unlock(&phydev->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(genphy_suspend);
+
+int genphy_resume(struct phy_device *phydev)
+{
+	int value;
+
+	mutex_lock(&phydev->lock);
+
+	value = phy_read(phydev, MII_BMCR);
+	phy_write(phydev, MII_BMCR, (value & ~BMCR_PDOWN));
+
+	mutex_unlock(&phydev->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(genphy_resume);
 
 /**
  * phy_probe - probe and init a PHY device
@@ -855,7 +866,6 @@
 {
 	int retval;
 
-	memset(&new_driver->driver, 0, sizeof(new_driver->driver));
 	new_driver->driver.name = new_driver->name;
 	new_driver->driver.bus = &mdio_bus_type;
 	new_driver->driver.probe = phy_probe;
@@ -890,6 +900,8 @@
 	.features	= 0,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
 	.driver		= {.owner= THIS_MODULE, },
 };
 
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 73baa7a..c05d38d 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -126,6 +126,27 @@
 	.driver		= { .owner = THIS_MODULE, }
 };
 
+static struct phy_driver lan911x_int_driver = {
+	.phy_id		= 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "SMSC LAN911x Internal PHY",
+
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+	/* basic functions */
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.config_init	= smsc_phy_config_init,
+
+	/* IRQ related */
+	.ack_interrupt	= smsc_phy_ack_interrupt,
+	.config_intr	= smsc_phy_config_intr,
+
+	.driver		= { .owner = THIS_MODULE, }
+};
+
 static int __init smsc_init(void)
 {
 	int ret;
@@ -142,8 +163,14 @@
 	if (ret)
 		goto err3;
 
+	ret = phy_driver_register (&lan911x_int_driver);
+	if (ret)
+		goto err4;
+
 	return 0;
 
+err4:
+	phy_driver_unregister (&lan8700_driver);
 err3:
 	phy_driver_unregister (&lan8187_driver);
 err2:
@@ -154,6 +181,7 @@
 
 static void __exit smsc_exit(void)
 {
+	phy_driver_unregister (&lan911x_int_driver);
 	phy_driver_unregister (&lan8700_driver);
 	phy_driver_unregister (&lan8187_driver);
 	phy_driver_unregister (&lan83c185_driver);
diff --git a/drivers/net/phy/ste10Xp.c b/drivers/net/phy/ste10Xp.c
new file mode 100644
index 0000000..6bdb0d5
--- /dev/null
+++ b/drivers/net/phy/ste10Xp.c
@@ -0,0 +1,137 @@
+/*
+ * drivers/net/phy/ste10Xp.c
+ *
+ * Driver for STMicroelectronics STe10Xp PHYs
+ *
+ * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *
+ * Copyright (c) 2008 STMicroelectronics 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#define MII_XCIIS   	0x11	/* Configuration Info IRQ & Status Reg */
+#define MII_XIE     	0x12	/* Interrupt Enable Register */
+#define MII_XIE_DEFAULT_MASK 0x0070 /* ANE complete, Remote Fault, Link Down */
+
+#define STE101P_PHY_ID		0x00061c50
+#define STE100P_PHY_ID       	0x1c040011
+
+static int ste10Xp_config_init(struct phy_device *phydev)
+{
+	int value, err;
+
+	/* Software Reset PHY */
+	value = phy_read(phydev, MII_BMCR);
+	if (value < 0)
+		return value;
+
+	value |= BMCR_RESET;
+	err = phy_write(phydev, MII_BMCR, value);
+	if (err < 0)
+		return err;
+
+	do {
+		value = phy_read(phydev, MII_BMCR);
+	} while (value & BMCR_RESET);
+
+	return 0;
+}
+
+static int ste10Xp_config_intr(struct phy_device *phydev)
+{
+	int err, value;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		/* Enable all STe101P interrupts (PR12) */
+		err = phy_write(phydev, MII_XIE, MII_XIE_DEFAULT_MASK);
+		/* clear any pending interrupts */
+		if (err == 0) {
+			value = phy_read(phydev, MII_XCIIS);
+			if (value < 0)
+				err = value;
+		}
+	} else
+		err = phy_write(phydev, MII_XIE, 0);
+
+	return err;
+}
+
+static int ste10Xp_ack_interrupt(struct phy_device *phydev)
+{
+	int err = phy_read(phydev, MII_XCIIS);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static struct phy_driver ste101p_pdriver = {
+	.phy_id = STE101P_PHY_ID,
+	.phy_id_mask = 0xfffffff0,
+	.name = "STe101p",
+	.features = PHY_BASIC_FEATURES | SUPPORTED_Pause,
+	.flags = PHY_HAS_INTERRUPT,
+	.config_init = ste10Xp_config_init,
+	.config_aneg = genphy_config_aneg,
+	.read_status = genphy_read_status,
+	.ack_interrupt = ste10Xp_ack_interrupt,
+	.config_intr = ste10Xp_config_intr,
+	.suspend = genphy_suspend,
+	.resume = genphy_resume,
+	.driver = {.owner = THIS_MODULE,}
+};
+
+static struct phy_driver ste100p_pdriver = {
+	.phy_id = STE100P_PHY_ID,
+	.phy_id_mask = 0xffffffff,
+	.name = "STe100p",
+	.features = PHY_BASIC_FEATURES | SUPPORTED_Pause,
+	.flags = PHY_HAS_INTERRUPT,
+	.config_init = ste10Xp_config_init,
+	.config_aneg = genphy_config_aneg,
+	.read_status = genphy_read_status,
+	.ack_interrupt = ste10Xp_ack_interrupt,
+	.config_intr = ste10Xp_config_intr,
+	.suspend = genphy_suspend,
+	.resume = genphy_resume,
+	.driver = {.owner = THIS_MODULE,}
+};
+
+static int __init ste10Xp_init(void)
+{
+	int retval;
+
+	retval = phy_driver_register(&ste100p_pdriver);
+	if (retval < 0)
+		return retval;
+	return phy_driver_register(&ste101p_pdriver);
+}
+
+static void __exit ste10Xp_exit(void)
+{
+	phy_driver_unregister(&ste100p_pdriver);
+	phy_driver_unregister(&ste101p_pdriver);
+}
+
+module_init(ste10Xp_init);
+module_exit(ste10Xp_exit);
+
+MODULE_DESCRIPTION("STMicroelectronics STe10Xp PHY driver");
+MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 1e96542..0c46d60 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -229,7 +229,7 @@
 	if (dev->irq != -1)
 	{
 		struct parport *port =
-		   ((struct net_local *)dev->priv)->pardev->port;
+		   ((struct net_local *)netdev_priv(dev))->pardev->port;
 		port->ops->enable_irq (port);
 	}
 }
@@ -239,7 +239,7 @@
 	if (dev->irq != -1)
 	{
 		struct parport *port =
-		   ((struct net_local *)dev->priv)->pardev->port;
+		   ((struct net_local *)netdev_priv(dev))->pardev->port;
 		port->ops->disable_irq (port);
 	}
 }
@@ -247,7 +247,7 @@
 static inline void write_data (struct net_device *dev, unsigned char data)
 {
 	struct parport *port =
-	   ((struct net_local *)dev->priv)->pardev->port;
+	   ((struct net_local *)netdev_priv(dev))->pardev->port;
 
 	port->ops->write_data (port, data);
 }
@@ -255,7 +255,7 @@
 static inline unsigned char read_status (struct net_device *dev)
 {
 	struct parport *port =
-	   ((struct net_local *)dev->priv)->pardev->port;
+	   ((struct net_local *)netdev_priv(dev))->pardev->port;
 
 	return port->ops->read_status (port);
 }
@@ -638,14 +638,14 @@
 
 	case PLIP_PK_DATA:
 		lbuf = rcv->skb->data;
-		do
+		do {
 			if (plip_receive(nibble_timeout, dev,
 					 &rcv->nibble, &lbuf[rcv->byte]))
 				return TIMEOUT;
-		while (++rcv->byte < rcv->length.h);
-		do
+		} while (++rcv->byte < rcv->length.h);
+		do {
 			rcv->checksum += lbuf[--rcv->byte];
-		while (rcv->byte);
+		} while (rcv->byte);
 		rcv->state = PLIP_PK_CHECKSUM;
 
 	case PLIP_PK_CHECKSUM:
@@ -664,7 +664,6 @@
 		/* Inform the upper layer for the arrival of a packet. */
 		rcv->skb->protocol=plip_type_trans(rcv->skb, dev);
 		netif_rx_ni(rcv->skb);
-		dev->last_rx = jiffies;
 		dev->stats.rx_bytes += rcv->length.h;
 		dev->stats.rx_packets++;
 		rcv->skb = NULL;
@@ -817,14 +816,14 @@
 		snd->checksum = 0;
 
 	case PLIP_PK_DATA:
-		do
+		do {
 			if (plip_send(nibble_timeout, dev,
 				      &snd->nibble, lbuf[snd->byte]))
 				return TIMEOUT;
-		while (++snd->byte < snd->length.h);
-		do
+		} while (++snd->byte < snd->length.h);
+		do {
 			snd->checksum += lbuf[--snd->byte];
-		while (snd->byte);
+		} while (snd->byte);
 		snd->state = PLIP_PK_CHECKSUM;
 
 	case PLIP_PK_CHECKSUM:
@@ -1018,8 +1017,8 @@
 	return ret;
 }
 
-int plip_hard_header_cache(const struct neighbour *neigh,
-                           struct hh_cache *hh)
+static int plip_hard_header_cache(const struct neighbour *neigh,
+				  struct hh_cache *hh)
 {
 	int ret;
 
@@ -1397,9 +1396,3 @@
 module_init(plip_init);
 module_exit(plip_cleanup_module);
 MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -c plip.c"
- * End:
- */
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 451bdb5..6567fab 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -293,9 +293,6 @@
 	err = -EFAULT;
 	switch (cmd) {
 	case PPPIOCGCHAN:
-		err = -ENXIO;
-		if (!ap)
-			break;
 		err = -EFAULT;
 		if (put_user(ppp_channel_index(&ap->chan), p))
 			break;
@@ -303,9 +300,6 @@
 		break;
 
 	case PPPIOCGUNIT:
-		err = -ENXIO;
-		if (!ap)
-			break;
 		err = -EFAULT;
 		if (put_user(ppp_unit_number(&ap->chan), p))
 			break;
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 7e857e9..06b4482 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -27,6 +27,7 @@
 #include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/idr.h>
 #include <linux/netdevice.h>
 #include <linux/poll.h>
 #include <linux/ppp_defs.h>
@@ -116,6 +117,7 @@
 	unsigned long	last_xmit;	/* jiffies when last pkt sent 9c */
 	unsigned long	last_recv;	/* jiffies when last pkt rcvd a0 */
 	struct net_device *dev;		/* network interface device a4 */
+	int		closing;	/* is device closing down? a8 */
 #ifdef CONFIG_PPP_MULTILINK
 	int		nxchan;		/* next channel to send something on */
 	u32		nxseq;		/* next sequence number to send */
@@ -172,35 +174,13 @@
  */
 
 /*
- * A cardmap represents a mapping from unsigned integers to pointers,
- * and provides a fast "find lowest unused number" operation.
- * It uses a broad (32-way) tree with a bitmap at each level.
- * It is designed to be space-efficient for small numbers of entries
- * and time-efficient for large numbers of entries.
- */
-#define CARDMAP_ORDER	5
-#define CARDMAP_WIDTH	(1U << CARDMAP_ORDER)
-#define CARDMAP_MASK	(CARDMAP_WIDTH - 1)
-
-struct cardmap {
-	int shift;
-	unsigned long inuse;
-	struct cardmap *parent;
-	void *ptr[CARDMAP_WIDTH];
-};
-static void *cardmap_get(struct cardmap *map, unsigned int nr);
-static int cardmap_set(struct cardmap **map, unsigned int nr, void *ptr);
-static unsigned int cardmap_find_first_free(struct cardmap *map);
-static void cardmap_destroy(struct cardmap **map);
-
-/*
  * all_ppp_mutex protects the all_ppp_units mapping.
  * It also ensures that finding a ppp unit in the all_ppp_units map
  * and updating its file.refcnt field is atomic.
  */
 static DEFINE_MUTEX(all_ppp_mutex);
-static struct cardmap *all_ppp_units;
 static atomic_t ppp_unit_count = ATOMIC_INIT(0);
+static DEFINE_IDR(ppp_units_idr);
 
 /*
  * all_channels_lock protects all_channels and last_channel_index,
@@ -269,6 +249,9 @@
 static int ppp_connect_channel(struct channel *pch, int unit);
 static int ppp_disconnect_channel(struct channel *pch);
 static void ppp_destroy_channel(struct channel *pch);
+static int unit_get(struct idr *p, void *ptr);
+static void unit_put(struct idr *p, int n);
+static void *unit_find(struct idr *p, int n);
 
 static struct class *ppp_class;
 
@@ -886,7 +869,7 @@
 static int
 ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct ppp *ppp = (struct ppp *) dev->priv;
+	struct ppp *ppp = netdev_priv(dev);
 	int npi, proto;
 	unsigned char *pp;
 
@@ -931,7 +914,7 @@
 static int
 ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	struct ppp *ppp = dev->priv;
+	struct ppp *ppp = netdev_priv(dev);
 	int err = -EFAULT;
 	void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data;
 	struct ppp_stats stats;
@@ -971,8 +954,14 @@
 	return err;
 }
 
+static const struct net_device_ops ppp_netdev_ops = {
+	.ndo_start_xmit = ppp_start_xmit,
+	.ndo_do_ioctl   = ppp_net_ioctl,
+};
+
 static void ppp_setup(struct net_device *dev)
 {
+	dev->netdev_ops = &ppp_netdev_ops;
 	dev->hard_header_len = PPP_HDRLEN;
 	dev->mtu = PPP_MTU;
 	dev->addr_len = 0;
@@ -995,7 +984,7 @@
 	struct sk_buff *skb;
 
 	ppp_xmit_lock(ppp);
-	if (ppp->dev) {
+	if (!ppp->closing) {
 		ppp_push(ppp);
 		while (!ppp->xmit_pending
 		       && (skb = skb_dequeue(&ppp->file.xq)))
@@ -1463,8 +1452,7 @@
 ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
 {
 	ppp_recv_lock(ppp);
-	/* ppp->dev == 0 means interface is closing down */
-	if (ppp->dev)
+	if (!ppp->closing)
 		ppp_receive_frame(ppp, skb, pch);
 	else
 		kfree_skb(skb);
@@ -1684,7 +1672,6 @@
 			skb->protocol = htons(npindex_to_ethertype[npi]);
 			skb_reset_mac_header(skb);
 			netif_rx(skb);
-			ppp->dev->last_rx = jiffies;
 		}
 	}
 	return;
@@ -2414,13 +2401,12 @@
 	int ret = -ENOMEM;
 	int i;
 
-	ppp = kzalloc(sizeof(struct ppp), GFP_KERNEL);
-	if (!ppp)
-		goto out;
-	dev = alloc_netdev(0, "", ppp_setup);
+	dev = alloc_netdev(sizeof(struct ppp), "", ppp_setup);
 	if (!dev)
 		goto out1;
 
+	ppp = netdev_priv(dev);
+	ppp->dev = dev;
 	ppp->mru = PPP_MRU;
 	init_ppp_file(&ppp->file, INTERFACE);
 	ppp->file.hdrlen = PPP_HDRLEN - 2;	/* don't count proto bytes */
@@ -2433,18 +2419,25 @@
 	ppp->minseq = -1;
 	skb_queue_head_init(&ppp->mrq);
 #endif /* CONFIG_PPP_MULTILINK */
-	ppp->dev = dev;
-	dev->priv = ppp;
-
-	dev->hard_start_xmit = ppp_start_xmit;
-	dev->do_ioctl = ppp_net_ioctl;
 
 	ret = -EEXIST;
 	mutex_lock(&all_ppp_mutex);
-	if (unit < 0)
-		unit = cardmap_find_first_free(all_ppp_units);
-	else if (cardmap_get(all_ppp_units, unit) != NULL)
-		goto out2;	/* unit already exists */
+
+	if (unit < 0) {
+		unit = unit_get(&ppp_units_idr, ppp);
+		if (unit < 0) {
+			*retp = unit;
+			goto out2;
+		}
+	} else {
+		if (unit_find(&ppp_units_idr, unit))
+			goto out2; /* unit already exists */
+		else {
+			/* darn, someone is cheating us? */
+			*retp = -EINVAL;
+			goto out2;
+		}
+	}
 
 	/* Initialize the new ppp unit */
 	ppp->file.index = unit;
@@ -2452,29 +2445,22 @@
 
 	ret = register_netdev(dev);
 	if (ret != 0) {
+		unit_put(&ppp_units_idr, unit);
 		printk(KERN_ERR "PPP: couldn't register device %s (%d)\n",
 		       dev->name, ret);
 		goto out2;
 	}
 
 	atomic_inc(&ppp_unit_count);
-	ret = cardmap_set(&all_ppp_units, unit, ppp);
-	if (ret != 0)
-		goto out3;
-
 	mutex_unlock(&all_ppp_mutex);
+
 	*retp = 0;
 	return ppp;
 
-out3:
-	atomic_dec(&ppp_unit_count);
-	unregister_netdev(dev);
 out2:
 	mutex_unlock(&all_ppp_mutex);
 	free_netdev(dev);
 out1:
-	kfree(ppp);
-out:
 	*retp = ret;
 	return NULL;
 }
@@ -2498,19 +2484,17 @@
  */
 static void ppp_shutdown_interface(struct ppp *ppp)
 {
-	struct net_device *dev;
-
 	mutex_lock(&all_ppp_mutex);
-	ppp_lock(ppp);
-	dev = ppp->dev;
-	ppp->dev = NULL;
-	ppp_unlock(ppp);
 	/* This will call dev_close() for us. */
-	if (dev) {
-		unregister_netdev(dev);
-		free_netdev(dev);
-	}
-	cardmap_set(&all_ppp_units, ppp->file.index, NULL);
+	ppp_lock(ppp);
+	if (!ppp->closing) {
+		ppp->closing = 1;
+		ppp_unlock(ppp);
+		unregister_netdev(ppp->dev);
+	} else
+		ppp_unlock(ppp);
+
+	unit_put(&ppp_units_idr, ppp->file.index);
 	ppp->file.dead = 1;
 	ppp->owner = NULL;
 	wake_up_interruptible(&ppp->file.rwait);
@@ -2554,7 +2538,7 @@
 	if (ppp->xmit_pending)
 		kfree_skb(ppp->xmit_pending);
 
-	kfree(ppp);
+	free_netdev(ppp->dev);
 }
 
 /*
@@ -2564,7 +2548,7 @@
 static struct ppp *
 ppp_find_unit(int unit)
 {
-	return cardmap_get(all_ppp_units, unit);
+	return unit_find(&ppp_units_idr, unit);
 }
 
 /*
@@ -2616,7 +2600,7 @@
 	if (pch->file.hdrlen > ppp->file.hdrlen)
 		ppp->file.hdrlen = pch->file.hdrlen;
 	hdrlen = pch->file.hdrlen + 2;	/* for protocol bytes */
-	if (ppp->dev && hdrlen > ppp->dev->hard_header_len)
+	if (hdrlen > ppp->dev->hard_header_len)
 		ppp->dev->hard_header_len = hdrlen;
 	list_add_tail(&pch->clist, &ppp->channels);
 	++ppp->n_channels;
@@ -2682,123 +2666,45 @@
 	/* should never happen */
 	if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count))
 		printk(KERN_ERR "PPP: removing module but units remain!\n");
-	cardmap_destroy(&all_ppp_units);
 	unregister_chrdev(PPP_MAJOR, "ppp");
 	device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
 	class_destroy(ppp_class);
+	idr_destroy(&ppp_units_idr);
 }
 
 /*
- * Cardmap implementation.
+ * Units handling. Caller must protect concurrent access
+ * by holding all_ppp_mutex
  */
-static void *cardmap_get(struct cardmap *map, unsigned int nr)
-{
-	struct cardmap *p;
-	int i;
 
-	for (p = map; p != NULL; ) {
-		if ((i = nr >> p->shift) >= CARDMAP_WIDTH)
-			return NULL;
-		if (p->shift == 0)
-			return p->ptr[i];
-		nr &= ~(CARDMAP_MASK << p->shift);
-		p = p->ptr[i];
+/* get new free unit number and associate pointer with it */
+static int unit_get(struct idr *p, void *ptr)
+{
+	int unit, err;
+
+again:
+	if (idr_pre_get(p, GFP_KERNEL) == 0) {
+		printk(KERN_ERR "Out of memory expanding drawable idr\n");
+		return -ENOMEM;
 	}
-	return NULL;
+
+	err = idr_get_new_above(p, ptr, 0, &unit);
+	if (err == -EAGAIN)
+		goto again;
+
+	return unit;
 }
 
-static int cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
+/* put unit number back to a pool */
+static void unit_put(struct idr *p, int n)
 {
-	struct cardmap *p;
-	int i;
-
-	p = *pmap;
-	if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) {
-		do {
-			/* need a new top level */
-			struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL);
-			if (!np)
-				goto enomem;
-			np->ptr[0] = p;
-			if (p != NULL) {
-				np->shift = p->shift + CARDMAP_ORDER;
-				p->parent = np;
-			} else
-				np->shift = 0;
-			p = np;
-		} while ((nr >> p->shift) >= CARDMAP_WIDTH);
-		*pmap = p;
-	}
-	while (p->shift > 0) {
-		i = (nr >> p->shift) & CARDMAP_MASK;
-		if (p->ptr[i] == NULL) {
-			struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL);
-			if (!np)
-				goto enomem;
-			np->shift = p->shift - CARDMAP_ORDER;
-			np->parent = p;
-			p->ptr[i] = np;
-		}
-		if (ptr == NULL)
-			clear_bit(i, &p->inuse);
-		p = p->ptr[i];
-	}
-	i = nr & CARDMAP_MASK;
-	p->ptr[i] = ptr;
-	if (ptr != NULL)
-		set_bit(i, &p->inuse);
-	else
-		clear_bit(i, &p->inuse);
-	return 0;
- enomem:
-	return -ENOMEM;
+	idr_remove(p, n);
 }
 
-static unsigned int cardmap_find_first_free(struct cardmap *map)
+/* get pointer associated with the number */
+static void *unit_find(struct idr *p, int n)
 {
-	struct cardmap *p;
-	unsigned int nr = 0;
-	int i;
-
-	if ((p = map) == NULL)
-		return 0;
-	for (;;) {
-		i = find_first_zero_bit(&p->inuse, CARDMAP_WIDTH);
-		if (i >= CARDMAP_WIDTH) {
-			if (p->parent == NULL)
-				return CARDMAP_WIDTH << p->shift;
-			p = p->parent;
-			i = (nr >> p->shift) & CARDMAP_MASK;
-			set_bit(i, &p->inuse);
-			continue;
-		}
-		nr = (nr & (~CARDMAP_MASK << p->shift)) | (i << p->shift);
-		if (p->shift == 0 || p->ptr[i] == NULL)
-			return nr;
-		p = p->ptr[i];
-	}
-}
-
-static void cardmap_destroy(struct cardmap **pmap)
-{
-	struct cardmap *p, *np;
-	int i;
-
-	for (p = *pmap; p != NULL; p = np) {
-		if (p->shift != 0) {
-			for (i = 0; i < CARDMAP_WIDTH; ++i)
-				if (p->ptr[i] != NULL)
-					break;
-			if (i < CARDMAP_WIDTH) {
-				np = p->ptr[i];
-				p->ptr[i] = NULL;
-				continue;
-			}
-		}
-		np = p->parent;
-		kfree(p);
-	}
-	*pmap = NULL;
+	return idr_find(p, n);
 }
 
 /* Module/initialization stuff */
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 801d8f9..1e892b7 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -333,9 +333,6 @@
 	err = -EFAULT;
 	switch (cmd) {
 	case PPPIOCGCHAN:
-		err = -ENXIO;
-		if (!ap)
-			break;
 		err = -EFAULT;
 		if (put_user(ppp_channel_index(&ap->chan), p))
 			break;
@@ -343,9 +340,6 @@
 		break;
 
 	case PPPIOCGUNIT:
-		err = -ENXIO;
-		if (!ap)
-			break;
 		err = -EFAULT;
 		if (put_user(ppp_unit_number(&ap->chan), p))
 			break;
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index b646e92..c22b305 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -958,7 +958,6 @@
 {
 	struct pppox_sock *po;
 	char *dev_name;
-	DECLARE_MAC_BUF(mac);
 
 	if (v == SEQ_START_TOKEN) {
 		seq_puts(seq, "Id       Address              Device\n");
@@ -968,8 +967,8 @@
 	po = v;
 	dev_name = po->pppoe_pa.dev;
 
-	seq_printf(seq, "%08X %s %8s\n",
-		   po->pppoe_pa.sid, print_mac(mac, po->pppoe_pa.remote), dev_name);
+	seq_printf(seq, "%08X %pM %8s\n",
+		   po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name);
 out:
 	return 0;
 }
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index e98d977..f1a9467 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -489,6 +489,30 @@
 	spin_unlock_bh(&session->reorder_q.lock);
 }
 
+static inline int pppol2tp_verify_udp_checksum(struct sock *sk,
+					       struct sk_buff *skb)
+{
+	struct udphdr *uh = udp_hdr(skb);
+	u16 ulen = ntohs(uh->len);
+	struct inet_sock *inet;
+	__wsum psum;
+
+	if (sk->sk_no_check || skb_csum_unnecessary(skb) || !uh->check)
+		return 0;
+
+	inet = inet_sk(sk);
+	psum = csum_tcpudp_nofold(inet->saddr, inet->daddr, ulen,
+				  IPPROTO_UDP, 0);
+
+	if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
+	    !csum_fold(csum_add(psum, skb->csum)))
+		return 0;
+
+	skb->csum = psum;
+
+	return __skb_checksum_complete(skb);
+}
+
 /* Internal receive frame. Do the real work of receiving an L2TP data frame
  * here. The skb is not on a list when we get here.
  * Returns 0 if the packet was a data packet and was successfully passed on.
@@ -509,6 +533,9 @@
 	if (tunnel == NULL)
 		goto no_tunnel;
 
+	if (tunnel->sock && pppol2tp_verify_udp_checksum(tunnel->sock, skb))
+		goto discard_bad_csum;
+
 	/* UDP always verifies the packet length. */
 	__skb_pull(skb, sizeof(struct udphdr));
 
@@ -725,6 +752,14 @@
 
 	return 0;
 
+discard_bad_csum:
+	LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name);
+	UDP_INC_STATS_USER(&init_net, UDP_MIB_INERRORS, 0);
+	tunnel->stats.rx_errors++;
+	kfree_skb(skb);
+
+	return 0;
+
 error:
 	/* Put UDP header back */
 	__skb_push(skb, sizeof(struct udphdr));
@@ -851,7 +886,7 @@
 	static const unsigned char ppph[2] = { 0xff, 0x03 };
 	struct sock *sk = sock->sk;
 	struct inet_sock *inet;
-	__wsum csum = 0;
+	__wsum csum;
 	struct sk_buff *skb;
 	int error;
 	int hdr_len;
@@ -859,6 +894,8 @@
 	struct pppol2tp_tunnel *tunnel;
 	struct udphdr *uh;
 	unsigned int len;
+	struct sock *sk_tun;
+	u16 udp_len;
 
 	error = -ENOTCONN;
 	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
@@ -870,7 +907,8 @@
 	if (session == NULL)
 		goto error;
 
-	tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
+	sk_tun = session->tunnel_sock;
+	tunnel = pppol2tp_sock_to_tunnel(sk_tun);
 	if (tunnel == NULL)
 		goto error_put_sess;
 
@@ -893,11 +931,12 @@
 	skb_reset_transport_header(skb);
 
 	/* Build UDP header */
-	inet = inet_sk(session->tunnel_sock);
+	inet = inet_sk(sk_tun);
+	udp_len = hdr_len + sizeof(ppph) + total_len;
 	uh = (struct udphdr *) skb->data;
 	uh->source = inet->sport;
 	uh->dest = inet->dport;
-	uh->len = htons(hdr_len + sizeof(ppph) + total_len);
+	uh->len = htons(udp_len);
 	uh->check = 0;
 	skb_put(skb, sizeof(struct udphdr));
 
@@ -919,8 +958,22 @@
 	skb_put(skb, total_len);
 
 	/* Calculate UDP checksum if configured to do so */
-	if (session->tunnel_sock->sk_no_check != UDP_CSUM_NOXMIT)
-		csum = udp_csum_outgoing(sk, skb);
+	if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT)
+		skb->ip_summed = CHECKSUM_NONE;
+	else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) {
+		skb->ip_summed = CHECKSUM_COMPLETE;
+		csum = skb_checksum(skb, 0, udp_len, 0);
+		uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr,
+					      udp_len, IPPROTO_UDP, csum);
+		if (uh->check == 0)
+			uh->check = CSUM_MANGLED_0;
+	} else {
+		skb->ip_summed = CHECKSUM_PARTIAL;
+		skb->csum_start = skb_transport_header(skb) - skb->head;
+		skb->csum_offset = offsetof(struct udphdr, check);
+		uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr,
+					       udp_len, IPPROTO_UDP, 0);
+	}
 
 	/* Debug */
 	if (session->send_seq)
@@ -1008,13 +1061,14 @@
 	struct sock *sk = (struct sock *) chan->private;
 	struct sock *sk_tun;
 	int hdr_len;
+	u16 udp_len;
 	struct pppol2tp_session *session;
 	struct pppol2tp_tunnel *tunnel;
 	int rc;
 	int headroom;
 	int data_len = skb->len;
 	struct inet_sock *inet;
-	__wsum csum = 0;
+	__wsum csum;
 	struct udphdr *uh;
 	unsigned int len;
 	int old_headroom;
@@ -1060,6 +1114,8 @@
 	/* Setup L2TP header */
 	pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len));
 
+	udp_len = sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len;
+
 	/* Setup UDP header */
 	inet = inet_sk(sk_tun);
 	__skb_push(skb, sizeof(*uh));
@@ -1067,13 +1123,9 @@
 	uh = udp_hdr(skb);
 	uh->source = inet->sport;
 	uh->dest = inet->dport;
-	uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len);
+	uh->len = htons(udp_len);
 	uh->check = 0;
 
-	/* *BROKEN* Calculate UDP checksum if configured to do so */
-	if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT)
-		csum = udp_csum_outgoing(sk_tun, skb);
-
 	/* Debug */
 	if (session->send_seq)
 		PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
@@ -1108,6 +1160,24 @@
 	skb->dst = dst_clone(__sk_dst_get(sk_tun));
 	pppol2tp_skb_set_owner_w(skb, sk_tun);
 
+	/* Calculate UDP checksum if configured to do so */
+	if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT)
+		skb->ip_summed = CHECKSUM_NONE;
+	else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) {
+		skb->ip_summed = CHECKSUM_COMPLETE;
+		csum = skb_checksum(skb, 0, udp_len, 0);
+		uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr,
+					      udp_len, IPPROTO_UDP, csum);
+		if (uh->check == 0)
+			uh->check = CSUM_MANGLED_0;
+	} else {
+		skb->ip_summed = CHECKSUM_PARTIAL;
+		skb->csum_start = skb_transport_header(skb) - skb->head;
+		skb->csum_offset = offsetof(struct udphdr, check);
+		uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr,
+					       udp_len, IPPROTO_UDP, 0);
+	}
+
 	/* Queue the packet to IP for output */
 	len = skb->len;
 	rc = ip_queue_xmit(skb, 1);
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index 2eb54fd..4b564ed 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -1443,7 +1443,6 @@
 {
 	int status;
 	u64 v1, v2;
-	DECLARE_MAC_BUF(mac);
 
 	netdev->features = NETIF_F_IP_CSUM;
 
@@ -1474,9 +1473,8 @@
 			__func__, netdev->name, status);
 		return status;
 	}
-	dev_info(ctodev(card), "%s: MAC addr %s\n",
-		 netdev->name,
-		 print_mac(mac, netdev->dev_addr));
+	dev_info(ctodev(card), "%s: MAC addr %pM\n",
+		 netdev->name, netdev->dev_addr);
 
 	return 0;
 }
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c
index a834b52..ec23142 100644
--- a/drivers/net/ps3_gelic_wireless.c
+++ b/drivers/net/ps3_gelic_wireless.c
@@ -30,10 +30,11 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/if_arp.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 
 #include <linux/dma-mapping.h>
 #include <net/checksum.h>
@@ -449,9 +450,9 @@
 
 	/* element id */
 	if (rsn)
-		*buf++ = MFIE_TYPE_RSN;
+		*buf++ = WLAN_EID_RSN;
 	else
-		*buf++ = MFIE_TYPE_GENERIC;
+		*buf++ = WLAN_EID_GENERIC;
 
 	/* length filed; set later */
 	buf++;
@@ -539,7 +540,7 @@
 			break;
 
 		switch (item_id) {
-		case MFIE_TYPE_GENERIC:
+		case WLAN_EID_GENERIC:
 			if ((OUI_LEN + 1 <= item_len) &&
 			    !memcmp(pos, wpa_oui, OUI_LEN) &&
 			    pos[OUI_LEN] == 0x01) {
@@ -547,7 +548,7 @@
 				ie_info->wpa.len = item_len + 2;
 			}
 			break;
-		case MFIE_TYPE_RSN:
+		case WLAN_EID_RSN:
 			ie_info->rsn.data = pos - 2;
 			/* length includes the header */
 			ie_info->rsn.len = item_len + 2;
@@ -581,7 +582,7 @@
 	char *tmp;
 	u8 rate;
 	unsigned int i, j, len;
-	u8 buf[MAX_WPA_IE_LEN];
+	u8 buf[64]; /* arbitrary size large enough */
 
 	pr_debug("%s: <-\n", __func__);
 
@@ -763,7 +764,6 @@
 {
 	struct gelic_wl_scan_info *scan_info;
 	int i;
-	DECLARE_MAC_BUF(mac);
 
 	i = 0;
 	list_for_each_entry(scan_info, &wl->network_list, list) {
@@ -775,8 +775,7 @@
 			 scan_info->rate_len, scan_info->rate_ext_len,
 			 scan_info->essid_len);
 		/* -- */
-		pr_debug("bssid=%s\n",
-			 print_mac(mac, &scan_info->hwinfo->bssid[2]));
+		pr_debug("bssid=%pM\n", &scan_info->hwinfo->bssid[2]);
 		pr_debug("essid=%s\n", scan_info->hwinfo->essid);
 	}
 }
@@ -1167,11 +1166,7 @@
 		       ETH_ALEN);
 		set_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
 		set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
-		pr_debug("%s: bss=%02x:%02x:%02x:%02x:%02x:%02x\n",
-			 __func__,
-			 wl->bssid[0], wl->bssid[1],
-			 wl->bssid[2], wl->bssid[3],
-			 wl->bssid[4], wl->bssid[5]);
+		pr_debug("%s: bss=%pM\n", __func__, wl->bssid);
 	} else {
 		pr_debug("%s: clear bssid\n", __func__);
 		clear_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat);
@@ -1632,7 +1627,6 @@
 	unsigned long this_time = jiffies;
 	unsigned int data_len, i, found, r;
 	void *buf;
-	DECLARE_MAC_BUF(mac);
 
 	pr_debug("%s:start\n", __func__);
 	mutex_lock(&wl->scan_lock);
@@ -1684,9 +1678,9 @@
 	     scan_info_size < data_len;
 	     i++, scan_info_size += be16_to_cpu(scan_info->size),
 	     scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) {
-		pr_debug("%s:size=%d bssid=%s scan_info=%p\n", __func__,
+		pr_debug("%s:size=%d bssid=%pM scan_info=%p\n", __func__,
 			 be16_to_cpu(scan_info->size),
-			 print_mac(mac, &scan_info->bssid[2]), scan_info);
+			 &scan_info->bssid[2], scan_info);
 
 		/*
 		 * The wireless firmware may return invalid channel 0 and/or
@@ -1741,14 +1735,14 @@
 		target->essid_len = strnlen(scan_info->essid,
 					    sizeof(scan_info->essid));
 		target->rate_len = 0;
-		for (r = 0; r < MAX_RATES_LENGTH; r++)
+		for (r = 0; r < 12; r++)
 			if (scan_info->rate[r])
 				target->rate_len++;
 		if (8 < target->rate_len)
 			pr_info("%s: AP returns %d rates\n", __func__,
 				target->rate_len);
 		target->rate_ext_len = 0;
-		for (r = 0; r < MAX_RATES_EX_LENGTH; r++)
+		for (r = 0; r < 16; r++)
 			if (scan_info->ext_rate[r])
 				target->rate_ext_len++;
 		list_move_tail(&target->list, &wl->network_list);
@@ -1787,7 +1781,6 @@
 	struct gelic_wl_scan_info *best_bss;
 	int weight, best_weight;
 	u16 security;
-	DECLARE_MAC_BUF(mac);
 
 	pr_debug("%s: <-\n", __func__);
 
@@ -1857,8 +1850,8 @@
 #ifdef DEBUG
 	pr_debug("%s: -> bss=%p\n", __func__, best_bss);
 	if (best_bss) {
-		pr_debug("%s:addr=%s\n", __func__,
-			 print_mac(mac, &best_bss->hwinfo->bssid[2]));
+		pr_debug("%s:addr=%pM\n", __func__,
+			 &best_bss->hwinfo->bssid[2]);
 	}
 #endif
 	return best_bss;
diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h
index 5339e00..5b631c6 100644
--- a/drivers/net/ps3_gelic_wireless.h
+++ b/drivers/net/ps3_gelic_wireless.h
@@ -164,8 +164,8 @@
 	__be16 security;
 	u8  bssid[8]; /* last ETH_ALEN are valid. bssid[0],[1] are unused */
 	u8  essid[32]; /* IW_ESSID_MAX_SIZE */
-	u8  rate[16]; /* first MAX_RATES_LENGTH(12) are valid */
-	u8  ext_rate[16]; /* first MAX_RATES_EX_LENGTH(16) are valid */
+	u8  rate[16]; /* first 12 are valid */
+	u8  ext_rate[16]; /* first 16 are valid */
 	__be32 reserved1;
 	__be32 reserved2;
 	__be32 reserved3;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 508452c..189ec29 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -2127,7 +2127,6 @@
 	skb->protocol = eth_type_trans(skb, qdev->ndev);
 
 	netif_receive_skb(skb);
-	qdev->ndev->last_rx = jiffies;
 	lrg_buf_cb2->skb = NULL;
 
 	if (qdev->device_id == QL3022_DEVICE_ID)
@@ -2201,7 +2200,6 @@
 	netif_receive_skb(skb2);
 	ndev->stats.rx_packets++;
 	ndev->stats.rx_bytes += length;
-	ndev->last_rx = jiffies;
 	lrg_buf_cb2->skb = NULL;
 
 	if (qdev->device_id == QL3022_DEVICE_ID)
@@ -2286,7 +2284,6 @@
 static int ql_poll(struct napi_struct *napi, int budget)
 {
 	struct ql3_adapter *qdev = container_of(napi, struct ql3_adapter, napi);
-	struct net_device *ndev = qdev->ndev;
 	int rx_cleaned = 0, tx_cleaned = 0;
 	unsigned long hw_flags;
 	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
@@ -2295,7 +2292,7 @@
 
 	if (tx_cleaned + rx_cleaned != budget) {
 		spin_lock_irqsave(&qdev->hw_lock, hw_flags);
-		__netif_rx_complete(ndev, napi);
+		__netif_rx_complete(napi);
 		ql_update_small_bufq_prod_index(qdev);
 		ql_update_lrg_bufq_prod_index(qdev);
 		writel(qdev->rsp_consumer_index,
@@ -2354,8 +2351,8 @@
 		spin_unlock(&qdev->adapter_lock);
 	} else if (value & ISP_IMR_DISABLE_CMPL_INT) {
 		ql_disable_interrupts(qdev);
-		if (likely(netif_rx_schedule_prep(ndev, &qdev->napi))) {
-			__netif_rx_schedule(ndev, &qdev->napi);
+		if (likely(netif_rx_schedule_prep(&qdev->napi))) {
+			__netif_rx_schedule(&qdev->napi);
 		}
 	} else {
 		return IRQ_NONE;
@@ -3520,7 +3517,6 @@
 {
 	struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
 	struct pci_dev *pdev = qdev->pdev;
-	DECLARE_MAC_BUF(mac);
 
 	printk(KERN_INFO PFX
 	       "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n",
@@ -3546,8 +3542,8 @@
 
 	if (netif_msg_probe(qdev))
 		printk(KERN_INFO PFX
-		       "%s: MAC address %s\n",
-		       ndev->name, print_mac(mac, ndev->dev_addr));
+		       "%s: MAC address %pM\n",
+		       ndev->name, ndev->dev_addr);
 }
 
 static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
@@ -3903,13 +3899,24 @@
 	queue_delayed_work(qdev->workqueue, &qdev->link_state_work, 0);
 }
 
+static const struct net_device_ops ql3xxx_netdev_ops = {
+	.ndo_open		= ql3xxx_open,
+	.ndo_start_xmit		= ql3xxx_send,
+	.ndo_stop		= ql3xxx_close,
+	.ndo_set_multicast_list = NULL, /* not allowed on NIC side */
+	.ndo_change_mtu		= eth_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= ql3xxx_set_mac_address,
+	.ndo_tx_timeout		= ql3xxx_tx_timeout,
+};
+
 static int __devinit ql3xxx_probe(struct pci_dev *pdev,
 				  const struct pci_device_id *pci_entry)
 {
 	struct net_device *ndev = NULL;
 	struct ql3_adapter *qdev = NULL;
 	static int cards_found = 0;
-	int pci_using_dac, err;
+	int uninitialized_var(pci_using_dac), err;
 
 	err = pci_enable_device(pdev);
 	if (err) {
@@ -3969,9 +3976,7 @@
 	if (qdev->device_id == QL3032_DEVICE_ID)
 		ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
 
-	qdev->mem_map_registers =
-	    ioremap_nocache(pci_resource_start(pdev, 1),
-			    pci_resource_len(qdev->pdev, 1));
+	qdev->mem_map_registers = pci_ioremap_bar(pdev, 1);
 	if (!qdev->mem_map_registers) {
 		printk(KERN_ERR PFX "%s: cannot map device registers\n",
 		       pci_name(pdev));
@@ -3983,17 +3988,8 @@
 	spin_lock_init(&qdev->hw_lock);
 
 	/* Set driver entry points */
-	ndev->open = ql3xxx_open;
-	ndev->hard_start_xmit = ql3xxx_send;
-	ndev->stop = ql3xxx_close;
-	/* ndev->set_multicast_list
-	 * This device is one side of a two-function adapter
-	 * (NIC and iSCSI).  Promiscuous mode setting/clearing is
-	 * not allowed from the NIC side.
-	 */
+	ndev->netdev_ops = &ql3xxx_netdev_ops;
 	SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops);
-	ndev->set_mac_address = ql3xxx_set_mac_address;
-	ndev->tx_timeout = ql3xxx_tx_timeout;
 	ndev->watchdog_timeo = 5 * HZ;
 
 	netif_napi_add(ndev, &qdev->napi, ql_poll, 64);
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index b62fbd4..eefb81b 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -97,7 +97,7 @@
 	return status;
 }
 
-void ql_update_stats(struct ql_adapter *qdev)
+static void ql_update_stats(struct ql_adapter *qdev)
 {
 	u32 i;
 	u64 data;
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index b83a9c9..718a7bd 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -336,12 +336,11 @@
 			    (addr[5]);
 
 			QPRINTK(qdev, IFUP, INFO,
-				"Adding %s address %02x:%02x:%02x:%02x:%02x:%02x"
+				"Adding %s address %pM"
 				" at index %d in the CAM.\n",
 				((type ==
 				  MAC_ADDR_TYPE_MULTI_MAC) ? "MULTICAST" :
-				 "UNICAST"), addr[0], addr[1], addr[2], addr[3],
-				addr[4], addr[5], index);
+				 "UNICAST"), addr, index);
 
 			status =
 			    ql_wait_reg_rdy(qdev,
@@ -643,7 +642,7 @@
 
 }
 
-int ql_read_flash_word(struct ql_adapter *qdev, int offset, u32 *data)
+static int ql_read_flash_word(struct ql_adapter *qdev, int offset, u32 *data)
 {
 	int status = 0;
 	/* wait for reg to come ready */
@@ -833,7 +832,7 @@
 }
 
 /* Get the next large buffer. */
-struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring)
+static struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring)
 {
 	struct bq_desc *lbq_desc = &rx_ring->lbq[rx_ring->lbq_curr_idx];
 	rx_ring->lbq_curr_idx++;
@@ -844,7 +843,7 @@
 }
 
 /* Get the next small buffer. */
-struct bq_desc *ql_get_curr_sbuf(struct rx_ring *rx_ring)
+static struct bq_desc *ql_get_curr_sbuf(struct rx_ring *rx_ring)
 {
 	struct bq_desc *sbq_desc = &rx_ring->sbq[rx_ring->sbq_curr_idx];
 	rx_ring->sbq_curr_idx++;
@@ -1167,7 +1166,7 @@
 	return NETDEV_TX_BUSY;
 }
 
-void ql_realign_skb(struct sk_buff *skb, int len)
+static void ql_realign_skb(struct sk_buff *skb, int len)
 {
 	void *temp_addr = skb->data;
 
@@ -1452,7 +1451,6 @@
 			"Passing a normal packet upstream.\n");
 		netif_rx(skb);
 	}
-	ndev->last_rx = jiffies;
 }
 
 /* Process an outbound completion from an rx ring. */
@@ -1649,7 +1647,7 @@
 		rx_ring->cq_id);
 
 	if (work_done < budget) {
-		__netif_rx_complete(qdev->ndev, napi);
+		__netif_rx_complete(napi);
 		ql_enable_completion_interrupt(qdev, rx_ring->irq);
 	}
 	return work_done;
@@ -1734,8 +1732,7 @@
 static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id)
 {
 	struct rx_ring *rx_ring = dev_id;
-	struct ql_adapter *qdev = rx_ring->qdev;
-	netif_rx_schedule(qdev->ndev, &rx_ring->napi);
+	netif_rx_schedule(&rx_ring->napi);
 	return IRQ_HANDLED;
 }
 
@@ -1821,8 +1818,7 @@
 							      &rx_ring->rx_work,
 							      0);
 				else
-					netif_rx_schedule(qdev->ndev,
-							  &rx_ring->napi);
+					netif_rx_schedule(&rx_ring->napi);
 				work_done++;
 			}
 		}
@@ -2071,7 +2067,7 @@
 	return -ENOMEM;
 }
 
-void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring)
+static void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring)
 {
 	int i;
 	struct bq_desc *lbq_desc;
@@ -2134,7 +2130,7 @@
 	return -ENOMEM;
 }
 
-void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring)
+static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring)
 {
 	int i;
 	struct bq_desc *sbq_desc;
@@ -2469,7 +2465,7 @@
 	rx_ring->sbq_base_indirect_dma = shadow_reg_dma;
 
 	/* PCI doorbell mem area + 0x00 for consumer index register */
-	rx_ring->cnsmr_idx_db_reg = (u32 *) doorbell_area;
+	rx_ring->cnsmr_idx_db_reg = (u32 __iomem *) doorbell_area;
 	rx_ring->cnsmr_idx = 0;
 	rx_ring->curr_entry = rx_ring->cq_base;
 
@@ -2477,10 +2473,10 @@
 	rx_ring->valid_db_reg = doorbell_area + 0x04;
 
 	/* PCI doorbell mem area + 0x18 for large buffer consumer */
-	rx_ring->lbq_prod_idx_db_reg = (u32 *) (doorbell_area + 0x18);
+	rx_ring->lbq_prod_idx_db_reg = (u32 __iomem *) (doorbell_area + 0x18);
 
 	/* PCI doorbell mem area + 0x1c */
-	rx_ring->sbq_prod_idx_db_reg = (u32 *) (doorbell_area + 0x1c);
+	rx_ring->sbq_prod_idx_db_reg = (u32 __iomem *) (doorbell_area + 0x1c);
 
 	memset((void *)cqicb, 0, sizeof(struct cqicb));
 	cqicb->msix_vect = rx_ring->irq;
@@ -2611,7 +2607,7 @@
 	 * Assign doorbell registers for this tx_ring.
 	 */
 	/* TX PCI doorbell mem area for tx producer index */
-	tx_ring->prod_idx_db_reg = (u32 *) doorbell_area;
+	tx_ring->prod_idx_db_reg = (u32 __iomem *) doorbell_area;
 	tx_ring->prod_idx = 0;
 	/* TX PCI doorbell mem area + 0x04 */
 	tx_ring->valid_db_reg = doorbell_area + 0x04;
@@ -3127,11 +3123,7 @@
 		qdev->chip_rev_id >> 4 & 0x0000000f,
 		qdev->chip_rev_id >> 8 & 0x0000000f,
 		qdev->chip_rev_id >> 12 & 0x0000000f);
-	QPRINTK(qdev, PROBE, INFO,
-		"MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
-		ndev->dev_addr[0], ndev->dev_addr[1],
-		ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4],
-		ndev->dev_addr[5]);
+	QPRINTK(qdev, PROBE, INFO, "MAC address %pM\n", ndev->dev_addr);
 }
 
 static int ql_adapter_down(struct ql_adapter *qdev)
@@ -3156,7 +3148,7 @@
 	 * a workqueue only if it's a single interrupt
 	 * environment (MSI/Legacy).
 	 */
-	for (i = 1; i > qdev->rx_ring_count; i++) {
+	for (i = 1; i < qdev->rx_ring_count; i++) {
 		rx_ring = &qdev->rx_ring[i];
 		/* Only the RSS rings use NAPI on multi irq
 		 * environment.  Outbound completion processing
@@ -3526,6 +3518,7 @@
 {
 	struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
 	struct sockaddr *addr = p;
+	int ret = 0;
 
 	if (netif_running(ndev))
 		return -EBUSY;
@@ -3538,11 +3531,11 @@
 	if (ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr,
 			MAC_ADDR_TYPE_CAM_MAC, qdev->func)) {/* Unicast */
 		QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n");
-		return -1;
+		ret = -1;
 	}
 	spin_unlock(&qdev->hw_lock);
 
-	return 0;
+	return ret;
 }
 
 static void qlge_tx_timeout(struct net_device *ndev)
@@ -3592,7 +3585,7 @@
 		qdev->q_workqueue = NULL;
 	}
 	if (qdev->reg_base)
-		iounmap((void *)qdev->reg_base);
+		iounmap(qdev->reg_base);
 	if (qdev->doorbell_area)
 		iounmap(qdev->doorbell_area);
 	pci_release_regions(pdev);
@@ -3721,6 +3714,22 @@
 	return err;
 }
 
+
+static const struct net_device_ops qlge_netdev_ops = {
+	.ndo_open		= qlge_open,
+	.ndo_stop		= qlge_close,
+	.ndo_start_xmit		= qlge_send,
+	.ndo_change_mtu		= qlge_change_mtu,
+	.ndo_get_stats		= qlge_get_stats,
+	.ndo_set_multicast_list = qlge_set_multicast_list,
+	.ndo_set_mac_address	= qlge_set_mac_address,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_tx_timeout		= qlge_tx_timeout,
+	.ndo_vlan_rx_register	= ql_vlan_rx_register,
+	.ndo_vlan_rx_add_vid	= ql_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= ql_vlan_rx_kill_vid,
+};
+
 static int __devinit qlge_probe(struct pci_dev *pdev,
 				const struct pci_device_id *pci_entry)
 {
@@ -3758,19 +3767,11 @@
 	 */
 	ndev->tx_queue_len = qdev->tx_ring_size;
 	ndev->irq = pdev->irq;
-	ndev->open = qlge_open;
-	ndev->stop = qlge_close;
-	ndev->hard_start_xmit = qlge_send;
+
+	ndev->netdev_ops = &qlge_netdev_ops;
 	SET_ETHTOOL_OPS(ndev, &qlge_ethtool_ops);
-	ndev->change_mtu = qlge_change_mtu;
-	ndev->get_stats = qlge_get_stats;
-	ndev->set_multicast_list = qlge_set_multicast_list;
-	ndev->set_mac_address = qlge_set_mac_address;
-	ndev->tx_timeout = qlge_tx_timeout;
 	ndev->watchdog_timeo = 10 * HZ;
-	ndev->vlan_rx_register = ql_vlan_rx_register;
-	ndev->vlan_rx_add_vid = ql_vlan_rx_add_vid;
-	ndev->vlan_rx_kill_vid = ql_vlan_rx_kill_vid;
+
 	err = register_netdev(ndev);
 	if (err) {
 		dev_err(&pdev->dev, "net device registration failed.\n");
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 24fe344..fa31891 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -19,7 +19,7 @@
 	return status;
 }
 
-int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
+static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
 {
 	int i, status;
 
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 34fe7ef..53bbddf 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -49,8 +49,8 @@
 #include <asm/processor.h>
 
 #define DRV_NAME	"r6040"
-#define DRV_VERSION	"0.18"
-#define DRV_RELDATE	"13Jul2008"
+#define DRV_VERSION	"0.19"
+#define DRV_RELDATE	"18Dec2008"
 
 /* PHY CHIP Address */
 #define PHY1_ADDR	1	/* For MAC1 */
@@ -214,7 +214,7 @@
 	/* Wait for the read bit to be cleared */
 	while (limit--) {
 		cmd = ioread16(ioaddr + MMDIO);
-		if (cmd & MDIO_READ)
+		if (!(cmd & MDIO_READ))
 			break;
 	}
 
@@ -233,7 +233,7 @@
 	/* Wait for the write bit to be cleared */
 	while (limit--) {
 		cmd = ioread16(ioaddr + MMDIO);
-		if (cmd & MDIO_WRITE)
+		if (!(cmd & MDIO_WRITE))
 			break;
 	}
 }
@@ -598,7 +598,6 @@
 		
 		/* Send to upper layer */
 		netif_receive_skb(skb_ptr);
-		dev->last_rx = jiffies;
 		dev->stats.rx_packets++;
 		dev->stats.rx_bytes += descptr->len - 4;
 
@@ -668,7 +667,7 @@
 	work_done = r6040_rx(dev, budget);
 
 	if (work_done < budget) {
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		/* Enable RX interrupt */
 		iowrite16(ioread16(ioaddr + MIER) | RX_INTS, ioaddr + MIER);
 	}
@@ -681,8 +680,10 @@
 	struct net_device *dev = dev_id;
 	struct r6040_private *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->base;
-	u16 status;
+	u16 misr, status;
 
+	/* Save MIER */
+	misr = ioread16(ioaddr + MIER);
 	/* Mask off RDC MAC interrupt */
 	iowrite16(MSK_INT, ioaddr + MIER);
 	/* Read MISR status and clear */
@@ -702,14 +703,17 @@
 			dev->stats.rx_fifo_errors++;
 
 		/* Mask off RX interrupt */
-		iowrite16(ioread16(ioaddr + MIER) & ~RX_INTS, ioaddr + MIER);
-		netif_rx_schedule(dev, &lp->napi);
+		misr &= ~RX_INTS;
+		netif_rx_schedule(&lp->napi);
 	}
 
 	/* TX interrupt request */
 	if (status & TX_INTS)
 		r6040_tx(dev);
 
+	/* Restore RDC MAC interrupt */
+	iowrite16(misr, ioaddr + MIER);
+
 	return IRQ_HANDLED;
 }
 
@@ -1030,13 +1034,28 @@
 	return mii_link_ok(&rp->mii_if);
 }
 
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
 	.get_drvinfo		= netdev_get_drvinfo,
 	.get_settings		= netdev_get_settings,
 	.set_settings		= netdev_set_settings,
 	.get_link		= netdev_get_link,
 };
 
+static const struct net_device_ops r6040_netdev_ops = {
+	.ndo_open		= r6040_open,
+	.ndo_stop		= r6040_close,
+	.ndo_start_xmit		= r6040_start_xmit,
+	.ndo_get_stats		= r6040_get_stats,
+	.ndo_set_multicast_list = r6040_multicast_list,
+	.ndo_change_mtu		= eth_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= r6040_ioctl,
+	.ndo_tx_timeout		= r6040_tx_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= r6040_poll_controller,
+#endif
+};
+
 static int __devinit r6040_init_one(struct pci_dev *pdev,
 					 const struct pci_device_id *ent)
 {
@@ -1128,18 +1147,10 @@
 	lp->switch_sig = 0;
 
 	/* The RDC-specific entries in the device structure. */
-	dev->open = &r6040_open;
-	dev->hard_start_xmit = &r6040_start_xmit;
-	dev->stop = &r6040_close;
-	dev->get_stats = r6040_get_stats;
-	dev->set_multicast_list = &r6040_multicast_list;
-	dev->do_ioctl = &r6040_ioctl;
+	dev->netdev_ops = &r6040_netdev_ops;
 	dev->ethtool_ops = &netdev_ethtool_ops;
-	dev->tx_timeout = &r6040_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = r6040_poll_controller;
-#endif
+
 	netif_napi_add(dev, &lp->napi, r6040_poll, 64);
 	lp->mii_if.dev = dev;
 	lp->mii_if.mdio_read = r6040_mdio_read;
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 4b7cb38..2c73ca6 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -474,6 +474,7 @@
 	void (*hw_start)(struct net_device *);
 	unsigned int (*phy_reset_pending)(void __iomem *);
 	unsigned int (*link_ok)(void __iomem *);
+	int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd);
 	int pcie_cap;
 	struct delayed_work task;
 	unsigned features;
@@ -1829,9 +1830,11 @@
 	struct rtl8169_private *tp = netdev_priv(dev);
 	struct mii_ioctl_data *data = if_mii(ifr);
 
-	if (!netif_running(dev))
-		return -ENODEV;
+	return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV;
+}
 
+static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
+{
 	switch (cmd) {
 	case SIOCGMIIPHY:
 		data->phy_id = 32; /* Internal PHY */
@@ -1850,6 +1853,11 @@
 	return -EOPNOTSUPP;
 }
 
+static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
+{
+	return -EOPNOTSUPP;
+}
+
 static const struct rtl_cfg_info {
 	void (*hw_start)(struct net_device *);
 	unsigned int region;
@@ -1915,6 +1923,26 @@
 	}
 }
 
+static const struct net_device_ops rtl8169_netdev_ops = {
+	.ndo_open		= rtl8169_open,
+	.ndo_stop		= rtl8169_close,
+	.ndo_get_stats		= rtl8169_get_stats,
+	.ndo_start_xmit		= rtl8169_start_xmit,
+	.ndo_tx_timeout		= rtl8169_tx_timeout,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= rtl8169_change_mtu,
+	.ndo_set_mac_address	= rtl_set_mac_address,
+	.ndo_do_ioctl		= rtl8169_ioctl,
+	.ndo_set_multicast_list	= rtl_set_rx_mode,
+#ifdef CONFIG_R8169_VLAN
+	.ndo_vlan_rx_register	= rtl8169_vlan_rx_register,
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= rtl8169_netpoll,
+#endif
+
+};
+
 static int __devinit
 rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -1941,6 +1969,7 @@
 	}
 
 	SET_NETDEV_DEV(dev, &pdev->dev);
+	dev->netdev_ops = &rtl8169_netdev_ops;
 	tp = netdev_priv(dev);
 	tp->dev = dev;
 	tp->pci_dev = pdev;
@@ -2076,6 +2105,7 @@
 		tp->phy_reset_enable = rtl8169_tbi_reset_enable;
 		tp->phy_reset_pending = rtl8169_tbi_reset_pending;
 		tp->link_ok = rtl8169_tbi_link_ok;
+		tp->do_ioctl = rtl_tbi_ioctl;
 
 		tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
 	} else {
@@ -2084,8 +2114,7 @@
 		tp->phy_reset_enable = rtl8169_xmii_reset_enable;
 		tp->phy_reset_pending = rtl8169_xmii_reset_pending;
 		tp->link_ok = rtl8169_xmii_link_ok;
-
-		dev->do_ioctl = rtl8169_ioctl;
+		tp->do_ioctl = rtl_xmii_ioctl;
 	}
 
 	spin_lock_init(&tp->lock);
@@ -2097,28 +2126,15 @@
 		dev->dev_addr[i] = RTL_R8(MAC0 + i);
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
-	dev->open = rtl8169_open;
-	dev->hard_start_xmit = rtl8169_start_xmit;
-	dev->get_stats = rtl8169_get_stats;
 	SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
-	dev->stop = rtl8169_close;
-	dev->tx_timeout = rtl8169_tx_timeout;
-	dev->set_multicast_list = rtl_set_rx_mode;
 	dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
 	dev->irq = pdev->irq;
 	dev->base_addr = (unsigned long) ioaddr;
-	dev->change_mtu = rtl8169_change_mtu;
-	dev->set_mac_address = rtl_set_mac_address;
 
 	netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
 
 #ifdef CONFIG_R8169_VLAN
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-	dev->vlan_rx_register = rtl8169_vlan_rx_register;
-#endif
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = rtl8169_netpoll;
 #endif
 
 	tp->intr_mask = 0xffff;
@@ -3484,7 +3500,6 @@
 			if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0)
 				netif_receive_skb(skb);
 
-			dev->last_rx = jiffies;
 			dev->stats.rx_bytes += pkt_size;
 			dev->stats.rx_packets++;
 		}
@@ -3566,8 +3581,8 @@
 		RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
 		tp->intr_mask = ~tp->napi_event;
 
-		if (likely(netif_rx_schedule_prep(dev, &tp->napi)))
-			__netif_rx_schedule(dev, &tp->napi);
+		if (likely(netif_rx_schedule_prep(&tp->napi)))
+			__netif_rx_schedule(&tp->napi);
 		else if (netif_msg_intr(tp)) {
 			printk(KERN_INFO "%s: interrupt %04x in poll\n",
 			       dev->name, status);
@@ -3588,7 +3603,7 @@
 	rtl8169_tx_interrupt(dev, tp, ioaddr);
 
 	if (work_done < budget) {
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		tp->intr_mask = 0xffff;
 		/*
 		 * 20040426: the barrier is not strictly required but the
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index 2b8fd68..a6fd27a 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -94,7 +94,7 @@
 {
 	int i;
 	int error = 0;
-	struct rionet_private *rnet = ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 	void *data;
 
 	i = rnet->rx_slot;
@@ -132,7 +132,7 @@
 static void rionet_rx_fill(struct net_device *ndev, int end)
 {
 	int i;
-	struct rionet_private *rnet = ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 
 	i = rnet->rx_slot;
 	do {
@@ -151,7 +151,7 @@
 static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev,
 			       struct rio_dev *rdev)
 {
-	struct rionet_private *rnet = ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 
 	rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len);
 	rnet->tx_skb[rnet->tx_slot] = skb;
@@ -175,7 +175,7 @@
 static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	int i;
-	struct rionet_private *rnet = ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 	struct ethhdr *eth = (struct ethhdr *)skb->data;
 	u16 destid;
 	unsigned long flags;
@@ -215,7 +215,7 @@
 			       u16 info)
 {
 	struct net_device *ndev = dev_id;
-	struct rionet_private *rnet = ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 	struct rionet_peer *peer;
 
 	if (netif_msg_intr(rnet))
@@ -243,7 +243,7 @@
 {
 	int n;
 	struct net_device *ndev = dev_id;
-	struct rionet_private *rnet = (struct rionet_private *)ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 
 	if (netif_msg_intr(rnet))
 		printk(KERN_INFO "%s: inbound message event, mbox %d slot %d\n",
@@ -258,7 +258,7 @@
 static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot)
 {
 	struct net_device *ndev = dev_id;
-	struct rionet_private *rnet = ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 
 	spin_lock(&rnet->lock);
 
@@ -287,7 +287,7 @@
 	int i, rc = 0;
 	struct rionet_peer *peer, *tmp;
 	u32 pwdcsr;
-	struct rionet_private *rnet = ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 
 	if (netif_msg_ifup(rnet))
 		printk(KERN_INFO "%s: open\n", DRV_NAME);
@@ -351,7 +351,7 @@
 
 static int rionet_close(struct net_device *ndev)
 {
-	struct rionet_private *rnet = (struct rionet_private *)ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 	struct rionet_peer *peer, *tmp;
 	int i;
 
@@ -400,7 +400,7 @@
 static void rionet_get_drvinfo(struct net_device *ndev,
 			       struct ethtool_drvinfo *info)
 {
-	struct rionet_private *rnet = ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
@@ -410,14 +410,14 @@
 
 static u32 rionet_get_msglevel(struct net_device *ndev)
 {
-	struct rionet_private *rnet = ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 
 	return rnet->msg_enable;
 }
 
 static void rionet_set_msglevel(struct net_device *ndev, u32 value)
 {
-	struct rionet_private *rnet = ndev->priv;
+	struct rionet_private *rnet = netdev_priv(ndev);
 
 	rnet->msg_enable = value;
 }
@@ -435,7 +435,6 @@
 	struct net_device *ndev = NULL;
 	struct rionet_private *rnet;
 	u16 device_id;
-	DECLARE_MAC_BUF(mac);
 
 	/* Allocate our net_device structure */
 	ndev = alloc_etherdev(sizeof(struct rionet_private));
@@ -456,7 +455,7 @@
 				RIO_MAX_ROUTE_ENTRIES(mport->sys_size));
 
 	/* Set up private area */
-	rnet = (struct rionet_private *)ndev->priv;
+	rnet = netdev_priv(ndev);
 	rnet->mport = mport;
 
 	/* Set the default MAC address */
@@ -485,12 +484,12 @@
 	if (rc != 0)
 		goto out;
 
-	printk("%s: %s %s Version %s, MAC %s\n",
+	printk("%s: %s %s Version %s, MAC %pM\n",
 	       ndev->name,
 	       DRV_NAME,
 	       DRV_DESC,
 	       DRV_VERSION,
-	       print_mac(mac, ndev->dev_addr));
+	       ndev->dev_addr);
 
       out:
 	return rc;
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 3dd8f13..d890829 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -63,6 +63,16 @@
 
 static char version[] __devinitdata = "rrunner.c: v0.50 11/11/2002  Jes Sorensen (jes@wildopensource.com)\n";
 
+
+static const struct net_device_ops rr_netdev_ops = {
+	.ndo_open 		= rr_open,
+	.ndo_stop		= rr_close,
+	.ndo_do_ioctl		= rr_ioctl,
+	.ndo_start_xmit		= rr_start_xmit,
+	.ndo_change_mtu		= hippi_change_mtu,
+	.ndo_set_mac_address	= hippi_mac_addr,
+};
+
 /*
  * Implementation notes:
  *
@@ -115,10 +125,7 @@
 	spin_lock_init(&rrpriv->lock);
 
 	dev->irq = pdev->irq;
-	dev->open = &rr_open;
-	dev->hard_start_xmit = &rr_start_xmit;
-	dev->stop = &rr_close;
-	dev->do_ioctl = &rr_ioctl;
+	dev->netdev_ops = &rr_netdev_ops;
 
 	dev->base_addr = pci_resource_start(pdev, 0);
 
@@ -511,7 +518,6 @@
 	struct rr_private *rrpriv;
 	struct rr_regs __iomem *regs;
 	u32 sram_size, rev;
-	DECLARE_MAC_BUF(mac);
 
 	rrpriv = netdev_priv(dev);
 	regs = rrpriv->regs;
@@ -549,7 +555,7 @@
 	*(__be32 *)(dev->dev_addr+2) =
 	  htonl(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA[4])));
 
-	printk("  MAC: %s\n", print_mac(mac, dev->dev_addr));
+	printk("  MAC: %pM\n", dev->dev_addr);
 
 	sram_size = rr_read_eeprom_word(rrpriv, 8);
 	printk("  SRAM size 0x%06x\n", sram_size);
@@ -1006,7 +1012,6 @@
 
 			netif_rx(skb);		/* send it up */
 
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += pkt_len;
 		}
@@ -1708,9 +1713,3 @@
 
 module_init(rr_init_module);
 module_exit(rr_cleanup_module);
-
-/*
- * Local variables:
- * compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c"
- * End:
- */
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 6a1375f..f5c57c0 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -352,12 +352,13 @@
 	sp->def_mac_addr[offset].mac_addr[1] = (u8) (mac_addr >> 32);
 	sp->def_mac_addr[offset].mac_addr[0] = (u8) (mac_addr >> 40);
 }
+
 /* Add the vlan */
 static void s2io_vlan_rx_register(struct net_device *dev,
-					struct vlan_group *grp)
+				  struct vlan_group *grp)
 {
 	int i;
-	struct s2io_nic *nic = dev->priv;
+	struct s2io_nic *nic = netdev_priv(dev);
 	unsigned long flags[MAX_TX_FIFOS];
 	struct mac_info *mac_control = &nic->mac_control;
 	struct config_param *config = &nic->config;
@@ -372,10 +373,10 @@
 }
 
 /* Unregister the vlan */
-static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
+static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 {
 	int i;
-	struct s2io_nic *nic = dev->priv;
+	struct s2io_nic *nic = netdev_priv(dev);
 	unsigned long flags[MAX_TX_FIFOS];
 	struct mac_info *mac_control = &nic->mac_control;
 	struct config_param *config = &nic->config;
@@ -2837,7 +2838,7 @@
 	int pkts_processed = 0;
 	u8 __iomem *addr = NULL;
 	u8 val8 = 0;
-	struct s2io_nic *nic = dev->priv;
+	struct s2io_nic *nic = netdev_priv(dev);
 	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	int budget_org = budget;
 
@@ -2851,7 +2852,7 @@
 	s2io_chk_rx_buffers(nic, ring);
 
 	if (pkts_processed < budget_org) {
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		/*Re Enable MSI-Rx Vector*/
 		addr = (u8 __iomem *)&bar0->xmsi_mask_reg;
 		addr += 7 - ring->ring_no;
@@ -2865,7 +2866,6 @@
 {
 	struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi);
 	struct ring_info *ring;
-	struct net_device *dev = nic->dev;
 	struct config_param *config;
 	struct mac_info *mac_control;
 	int pkts_processed = 0;
@@ -2889,7 +2889,7 @@
 			break;
 	}
 	if (pkts_processed < budget_org) {
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		/* Re enable the Rx interrupts for the ring */
 		writeq(0, &bar0->rx_traffic_mask);
 		readl(&bar0->rx_traffic_mask);
@@ -2909,7 +2909,7 @@
  */
 static void s2io_netpoll(struct net_device *dev)
 {
-	struct s2io_nic *nic = dev->priv;
+	struct s2io_nic *nic = netdev_priv(dev);
 	struct mac_info *mac_control;
 	struct config_param *config;
 	struct XENA_dev_config __iomem *bar0 = nic->bar0;
@@ -3171,7 +3171,7 @@
 static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
 {
 	u64 val64 = 0x0;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
 	//address transaction
@@ -3220,7 +3220,7 @@
 {
 	u64 val64 = 0x0;
 	u64 rval64 = 0x0;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
 	/* address transaction */
@@ -3324,7 +3324,7 @@
 	u64 val64 = 0x0;
 	u64 addr  = 0x0;
 
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct stat_block *stat_info = sp->mac_control.stats_info;
 
 	/* Check the communication with the MDIO slave */
@@ -3990,7 +3990,7 @@
 
 static int s2io_open(struct net_device *dev)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	int err = 0;
 
 	/*
@@ -4048,7 +4048,7 @@
 
 static int s2io_close(struct net_device *dev)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct config_param *config = &sp->config;
 	u64 tmp64;
 	int offset;
@@ -4087,7 +4087,7 @@
 
 static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
 	register u64 val64;
 	struct TxD *txdp;
@@ -4329,7 +4329,6 @@
 	struct ring_info *ring = (struct ring_info *)dev_id;
 	struct s2io_nic *sp = ring->nic;
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
-	struct net_device *dev = sp->dev;
 
 	if (unlikely(!is_s2io_card_up(sp)))
 		return IRQ_HANDLED;
@@ -4343,7 +4342,7 @@
 		val8 = (ring->ring_no == 0) ? 0x7f : 0xff;
 		writeb(val8, addr);
 		val8 = readb(addr);
-		netif_rx_schedule(dev, &ring->napi);
+		netif_rx_schedule(&ring->napi);
 	} else {
 		rx_intr_handler(ring, 0);
 		s2io_chk_rx_buffers(sp, ring);
@@ -4485,7 +4484,7 @@
 static void s2io_handle_errors(void * dev_id)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 temp64 = 0,val64=0;
 	int i = 0;
@@ -4752,7 +4751,7 @@
 static irqreturn_t s2io_isr(int irq, void *dev_id)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	int i;
 	u64 reason = 0;
@@ -4790,7 +4789,7 @@
 
 		if (config->napi) {
 			if (reason & GEN_INTR_RXTRAFFIC) {
-				netif_rx_schedule(dev, &sp->napi);
+				netif_rx_schedule(&sp->napi);
 				writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
 				writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
 				readl(&bar0->rx_traffic_int);
@@ -4881,7 +4880,7 @@
 
 static struct net_device_stats *s2io_get_stats(struct net_device *dev)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct mac_info *mac_control;
 	struct config_param *config;
 	int i;
@@ -4948,7 +4947,7 @@
 {
 	int i, j, prev_cnt;
 	struct dev_mc_list *mclist;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
 	    0xfeffffffffffULL;
@@ -5112,7 +5111,7 @@
 /* read from CAM unicast & multicast addresses and store it in
  * def_mac_addr structure
  */
-void do_s2io_store_unicast_mc(struct s2io_nic *sp)
+static void do_s2io_store_unicast_mc(struct s2io_nic *sp)
 {
 	int offset;
 	u64 mac_addr = 0x0;
@@ -5277,7 +5276,7 @@
 
 static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	register u64 mac_addr = 0, perm_addr = 0;
 	int i;
 	u64 tmp64;
@@ -5336,7 +5335,7 @@
 static int s2io_ethtool_sset(struct net_device *dev,
 			     struct ethtool_cmd *info)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	if ((info->autoneg == AUTONEG_ENABLE) ||
 	    (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
 		return -EINVAL;
@@ -5362,7 +5361,7 @@
 
 static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
 	info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
 	info->port = PORT_FIBRE;
@@ -5397,7 +5396,7 @@
 static void s2io_ethtool_gdrvinfo(struct net_device *dev,
 				  struct ethtool_drvinfo *info)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 
 	strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
 	strncpy(info->version, s2io_driver_version, sizeof(info->version));
@@ -5427,7 +5426,7 @@
 	int i;
 	u64 reg;
 	u8 *reg_space = (u8 *) space;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 
 	regs->len = XENA_REG_SPACE;
 	regs->version = sp->pdev->subsystem_device;
@@ -5487,7 +5486,7 @@
 static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
 {
 	u64 val64 = 0, last_gpio_ctrl_val;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u16 subid;
 
@@ -5525,7 +5524,7 @@
 static void s2io_ethtool_gringparam(struct net_device *dev,
                                     struct ethtool_ringparam *ering)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	int i,tx_desc_count=0,rx_desc_count=0;
 
 	if (sp->rxd_mode == RXD_MODE_1)
@@ -5568,7 +5567,7 @@
 				       struct ethtool_pauseparam *ep)
 {
 	u64 val64;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
 	val64 = readq(&bar0->rmac_pause_cfg);
@@ -5595,7 +5594,7 @@
 			       struct ethtool_pauseparam *ep)
 {
 	u64 val64;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
 	val64 = readq(&bar0->rmac_pause_cfg);
@@ -5825,7 +5824,7 @@
 {
 	u32 i, valid;
 	u64 data;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 
 	eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
 
@@ -5863,7 +5862,7 @@
 {
 	int len = eeprom->len, cnt = 0;
 	u64 valid = 0, data;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 
 	if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
 		DBG_PRINT(ERR_DBG,
@@ -6243,7 +6242,7 @@
 			      struct ethtool_test *ethtest,
 			      uint64_t * data)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	int orig_state = netif_running(sp->dev);
 
 	if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
@@ -6299,7 +6298,7 @@
 				   u64 * tmp_stats)
 {
 	int i = 0, k;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	struct stat_block *stat_info = sp->mac_control.stats_info;
 
 	s2io_updt_stats(sp);
@@ -6578,14 +6577,14 @@
 
 static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 
 	return (sp->rx_csum);
 }
 
 static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 
 	if (data)
 		sp->rx_csum = 1;
@@ -6602,7 +6601,7 @@
 
 static int s2io_get_sset_count(struct net_device *dev, int sset)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 
 	switch (sset) {
 	case ETH_SS_TEST:
@@ -6625,7 +6624,7 @@
 				     u32 stringset, u8 * data)
 {
 	int stat_size = 0;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 
 	switch (stringset) {
 	case ETH_SS_TEST:
@@ -6727,7 +6726,7 @@
 
 static int s2io_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 	int ret = 0;
 
 	if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
@@ -7331,7 +7330,7 @@
 
 static void s2io_tx_watchdog(struct net_device *dev)
 {
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 
 	if (netif_carrier_ok(dev)) {
 		sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt++;
@@ -7366,7 +7365,7 @@
 	int ring_no = ring_data->ring_no;
 	u16 l3_csum, l4_csum;
 	unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
-	struct lro *lro;
+	struct lro *uninitialized_var(lro);
 	u8 err_mask;
 
 	skb->dev = dev;
@@ -7544,7 +7543,6 @@
 	sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
 send_up:
 	queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2));
-	dev->last_rx = jiffies;
 aggregate:
 	sp->mac_control.rings[ring_no].rx_bufs_left -= 1;
 	return SUCCESS;
@@ -7718,6 +7716,24 @@
 				S2IO_BIT_RESET);
 }
 
+static const struct net_device_ops s2io_netdev_ops = {
+	.ndo_open	        = s2io_open,
+	.ndo_stop	        = s2io_close,
+	.ndo_get_stats	        = s2io_get_stats,
+	.ndo_start_xmit    	= s2io_xmit,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_multicast_list = s2io_set_multicast,
+	.ndo_do_ioctl	   	= s2io_ioctl,
+	.ndo_set_mac_address    = s2io_set_mac_addr,
+	.ndo_change_mtu	   	= s2io_change_mtu,
+	.ndo_vlan_rx_register   = s2io_vlan_rx_register,
+	.ndo_vlan_rx_kill_vid   = s2io_vlan_rx_kill_vid,
+	.ndo_tx_timeout	   	= s2io_tx_watchdog,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller    = s2io_netpoll,
+#endif
+};
+
 /**
  *  s2io_init_nic - Initialization of the adapter .
  *  @pdev : structure containing the PCI related information of the device.
@@ -7748,7 +7764,6 @@
 	int mode;
 	u8 dev_intr_type = intr_type;
 	u8 dev_multiq = 0;
-	DECLARE_MAC_BUF(mac);
 
 	ret = s2io_verify_parm(pdev, &dev_intr_type, &dev_multiq);
 	if (ret)
@@ -7798,7 +7813,7 @@
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	/*  Private member variable initialized to s2io NIC structure */
-	sp = dev->priv;
+	sp = netdev_priv(dev);
 	memset(sp, 0, sizeof(struct s2io_nic));
 	sp->dev = dev;
 	sp->pdev = pdev;
@@ -7918,8 +7933,7 @@
 		goto mem_alloc_failed;
 	}
 
-	sp->bar0 = ioremap(pci_resource_start(pdev, 0),
-				     pci_resource_len(pdev, 0));
+	sp->bar0 = pci_ioremap_bar(pdev, 0);
 	if (!sp->bar0) {
 		DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
 			  dev->name);
@@ -7927,8 +7941,7 @@
 		goto bar0_remap_failed;
 	}
 
-	sp->bar1 = ioremap(pci_resource_start(pdev, 2),
-				     pci_resource_len(pdev, 2));
+	sp->bar1 = pci_ioremap_bar(pdev, 2);
 	if (!sp->bar1) {
 		DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
 			  dev->name);
@@ -7946,26 +7959,9 @@
 	}
 
 	/*  Driver entry points */
-	dev->open = &s2io_open;
-	dev->stop = &s2io_close;
-	dev->hard_start_xmit = &s2io_xmit;
-	dev->get_stats = &s2io_get_stats;
-	dev->set_multicast_list = &s2io_set_multicast;
-	dev->do_ioctl = &s2io_ioctl;
-	dev->set_mac_address = &s2io_set_mac_addr;
-	dev->change_mtu = &s2io_change_mtu;
+	dev->netdev_ops = &s2io_netdev_ops;
 	SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-	dev->vlan_rx_register = s2io_vlan_rx_register;
-	dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid;
-
-	/*
-	 * will use eth_mac_addr() for  dev->set_mac_address
-	 * mac address will be set every time dev->open() is called
-	 */
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = s2io_netpoll;
-#endif
 
 	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 	if (sp->high_dma_flag == TRUE)
@@ -7976,7 +7972,6 @@
 		dev->features |= NETIF_F_UFO;
 		dev->features |= NETIF_F_HW_CSUM;
 	}
-	dev->tx_timeout = &s2io_tx_watchdog;
 	dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
 	INIT_WORK(&sp->rst_timer_task, s2io_restart_nic);
 	INIT_WORK(&sp->set_link_task, s2io_set_link);
@@ -8125,8 +8120,7 @@
 		  sp->product_name, pdev->revision);
 	DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
 		  s2io_driver_version);
-	DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %s\n",
-		  dev->name, print_mac(mac, dev->dev_addr));
+	DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %pM\n", dev->name, dev->dev_addr);
 	DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
 	if (sp->device_type & XFRAME_II_DEVICE) {
 		mode = s2io_print_pci_mode(sp);
@@ -8255,7 +8249,7 @@
 
 	flush_scheduled_work();
 
-	sp = dev->priv;
+	sp = netdev_priv(dev);
 	unregister_netdev(dev);
 
 	free_shared_mem(sp);
@@ -8590,7 +8584,7 @@
 static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag)
 {
 	struct net_device *dev = skb->dev;
-	struct s2io_nic *sp = dev->priv;
+	struct s2io_nic *sp = netdev_priv(dev);
 
 	skb->protocol = eth_type_trans(skb, dev);
 	if (sp->vlgrp && vlan_tag
@@ -8639,7 +8633,7 @@
                                                pci_channel_state_t state)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct s2io_nic *sp = netdev->priv;
+	struct s2io_nic *sp = netdev_priv(netdev);
 
 	netif_device_detach(netdev);
 
@@ -8664,7 +8658,7 @@
 static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct s2io_nic *sp = netdev->priv;
+	struct s2io_nic *sp = netdev_priv(netdev);
 
 	if (pci_enable_device(pdev)) {
 		printk(KERN_ERR "s2io: "
@@ -8688,7 +8682,7 @@
 static void s2io_io_resume(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct s2io_nic *sp = netdev->priv;
+	struct s2io_nic *sp = netdev_priv(netdev);
 
 	if (netif_running(netdev)) {
 		if (s2io_card_up(sp)) {
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index 5986cec..be30253 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -869,7 +869,6 @@
 	/* datagram completed: send to upper level */
 	skb_trim(skb, dlen);
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 	stats->rx_bytes+=dlen;
 	stats->rx_packets++;
 	lp->rx_skb[ns] = NULL;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 2615d46..31e38fa 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -2039,9 +2039,9 @@
 		sbdma_tx_process(sc,&(sc->sbm_txdma), 0);
 
 	if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
-		if (netif_rx_schedule_prep(dev, &sc->napi)) {
+		if (netif_rx_schedule_prep(&sc->napi)) {
 			__raw_writeq(0, sc->sbm_imr);
-			__netif_rx_schedule(dev, &sc->napi);
+			__netif_rx_schedule(&sc->napi);
 			/* Depend on the exit from poll to reenable intr */
 		}
 		else {
@@ -2292,7 +2292,6 @@
 	uint64_t ea_reg;
 	int i;
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	sc->sbm_dev = dev;
 	sc->sbe_idx = idx;
@@ -2373,8 +2372,8 @@
 	 * process so we need to finish off the config message that
 	 * was being displayed)
 	 */
-	pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n",
-	       dev->name, base, print_mac(mac, eaddr));
+	pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %pM\n",
+	       dev->name, base, eaddr);
 
 	sc->mii_bus->name = sbmac_mdio_string;
 	snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx);
@@ -2668,7 +2667,7 @@
 	sbdma_tx_process(sc, &(sc->sbm_txdma), 1);
 
 	if (work_done < budget) {
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 
 #ifdef CONFIG_SBMAC_COALESCE
 		__raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index 61955f8..42fd312 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -816,7 +816,6 @@
 		}
 
 		skb->protocol = eth_type_trans(skb, dev);
-		dev->last_rx = jiffies;
 		netif_rx(skb);
 
 		dev->stats.rx_bytes += pkt_size;
@@ -1387,7 +1386,7 @@
 	spin_unlock_bh(&priv->lock);
 }
 
-static struct ethtool_ops sc92031_ethtool_ops = {
+static const struct ethtool_ops sc92031_ethtool_ops = {
 	.get_settings		= sc92031_ethtool_get_settings,
 	.set_settings		= sc92031_ethtool_set_settings,
 	.get_drvinfo		= sc92031_ethtool_get_drvinfo,
@@ -1400,6 +1399,21 @@
 	.get_ethtool_stats	= sc92031_ethtool_get_ethtool_stats,
 };
 
+
+static const struct net_device_ops sc92031_netdev_ops = {
+	.ndo_get_stats		= sc92031_get_stats,
+	.ndo_start_xmit		= sc92031_start_xmit,
+	.ndo_open		= sc92031_open,
+	.ndo_stop		= sc92031_stop,
+	.ndo_set_multicast_list	= sc92031_set_multicast_list,
+	.ndo_change_mtu		= eth_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_tx_timeout		= sc92031_tx_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= sc92031_poll_controller,
+#endif
+};
+
 static int __devinit sc92031_probe(struct pci_dev *pdev,
 		const struct pci_device_id *id)
 {
@@ -1453,17 +1467,9 @@
 	/* faked with skb_copy_and_csum_dev */
 	dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
 
-	dev->get_stats		= sc92031_get_stats;
-	dev->ethtool_ops	= &sc92031_ethtool_ops;
-	dev->hard_start_xmit	= sc92031_start_xmit;
+	dev->netdev_ops		= &sc92031_netdev_ops;
 	dev->watchdog_timeo	= TX_TIMEOUT;
-	dev->open		= sc92031_open;
-	dev->stop		= sc92031_stop;
-	dev->set_multicast_list	= sc92031_set_multicast_list;
-	dev->tx_timeout		= sc92031_tx_timeout;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller	= sc92031_poll_controller;
-#endif
+	dev->ethtool_ops	= &sc92031_ethtool_ops;
 
 	priv = netdev_priv(dev);
 	spin_lock_init(&priv->lock);
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index 48c64fb..12a8fff 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -158,7 +158,6 @@
 	int old_dmaar;
 	int old_rear;
 	int retval;
-	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
 		return -ENODEV;
@@ -303,7 +302,7 @@
 	/* Retrieve and print the ethernet address. */
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = SA_prom[i+6];
-	printk("%s", print_mac(mac, dev->dev_addr));
+	printk("%pM", dev->dev_addr);
 
 	if (dev->irq == 0xff)
 		;			/* Do nothing: a user-level program will set it. */
@@ -564,7 +563,6 @@
 
 			skb->protocol=eth_type_trans(skb,dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += pkt_len;
 		}
@@ -746,12 +744,3 @@
 }
 
 #endif /* MODULE */
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  tab-width: 4
- * End:
- */
diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig
index 3be13b5..c535408 100644
--- a/drivers/net/sfc/Kconfig
+++ b/drivers/net/sfc/Kconfig
@@ -12,3 +12,11 @@
 
 	  To compile this driver as a module, choose M here.  The module
 	  will be called sfc.
+config SFC_MTD
+	bool "Solarflare Solarstorm SFC4000 flash MTD support"
+	depends on SFC && MTD && !(SFC=y && MTD=m)
+	default y
+	help
+	  This exposes the on-board flash memory as an MTD device (e.g.
+          /dev/mtd1).  This makes it possible to upload new boot code
+          to the NIC.
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
index c8f5704..b89f9be 100644
--- a/drivers/net/sfc/Makefile
+++ b/drivers/net/sfc/Makefile
@@ -1,5 +1,6 @@
-sfc-y			+= efx.o falcon.o tx.o rx.o falcon_xmac.o \
-			   selftest.o ethtool.o xfp_phy.o \
+sfc-y			+= efx.o falcon.o tx.o rx.o falcon_gmac.o \
+			   falcon_xmac.o selftest.o ethtool.o xfp_phy.o \
 			   mdio_10g.o tenxpress.o boards.o sfe4001.o
+sfc-$(CONFIG_SFC_MTD)	+= mtd.o
 
 obj-$(CONFIG_SFC)	+= sfc.o
diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c
index 99e6023..6490349 100644
--- a/drivers/net/sfc/boards.c
+++ b/drivers/net/sfc/boards.c
@@ -1,6 +1,6 @@
 /****************************************************************************
  * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2007 Solarflare Communications Inc.
+ * Copyright 2007-2008 Solarflare Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
@@ -11,6 +11,7 @@
 #include "phy.h"
 #include "boards.h"
 #include "efx.h"
+#include "workarounds.h"
 
 /* Macros for unpacking the board revision */
 /* The revision info is in host byte order. */
@@ -52,9 +53,128 @@
 }
 
 /*****************************************************************************
+ * Support for LM87 sensor chip used on several boards
+ */
+#define LM87_REG_ALARMS1		0x41
+#define LM87_REG_ALARMS2		0x42
+#define LM87_IN_LIMITS(nr, _min, _max)			\
+	0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min
+#define LM87_AIN_LIMITS(nr, _min, _max)			\
+	0x3B + (nr), _max, 0x1A + (nr), _min
+#define LM87_TEMP_INT_LIMITS(_min, _max)		\
+	0x39, _max, 0x3A, _min
+#define LM87_TEMP_EXT1_LIMITS(_min, _max)		\
+	0x37, _max, 0x38, _min
+
+#define LM87_ALARM_TEMP_INT		0x10
+#define LM87_ALARM_TEMP_EXT1		0x20
+
+#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE)
+
+static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
+			 const u8 *reg_values)
+{
+	struct i2c_client *client = i2c_new_device(&efx->i2c_adap, info);
+	int rc;
+
+	if (!client)
+		return -EIO;
+
+	while (*reg_values) {
+		u8 reg = *reg_values++;
+		u8 value = *reg_values++;
+		rc = i2c_smbus_write_byte_data(client, reg, value);
+		if (rc)
+			goto err;
+	}
+
+	efx->board_info.hwmon_client = client;
+	return 0;
+
+err:
+	i2c_unregister_device(client);
+	return rc;
+}
+
+static void efx_fini_lm87(struct efx_nic *efx)
+{
+	i2c_unregister_device(efx->board_info.hwmon_client);
+}
+
+static int efx_check_lm87(struct efx_nic *efx, unsigned mask)
+{
+	struct i2c_client *client = efx->board_info.hwmon_client;
+	s32 alarms1, alarms2;
+
+	/* If link is up then do not monitor temperature */
+	if (EFX_WORKAROUND_7884(efx) && efx->link_up)
+		return 0;
+
+	alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
+	alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
+	if (alarms1 < 0)
+		return alarms1;
+	if (alarms2 < 0)
+		return alarms2;
+	alarms1 &= mask;
+	alarms2 &= mask >> 8;
+	if (alarms1 || alarms2) {
+		EFX_ERR(efx,
+			"LM87 detected a hardware failure (status %02x:%02x)"
+			"%s%s\n",
+			alarms1, alarms2,
+			(alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "",
+			(alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : "");
+		return -ERANGE;
+	}
+
+	return 0;
+}
+
+#else /* !CONFIG_SENSORS_LM87 */
+
+static inline int
+efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
+	      const u8 *reg_values)
+{
+	return 0;
+}
+static inline void efx_fini_lm87(struct efx_nic *efx)
+{
+}
+static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask)
+{
+	return 0;
+}
+
+#endif /* CONFIG_SENSORS_LM87 */
+
+/*****************************************************************************
  * Support for the SFE4002
  *
  */
+static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */
+
+static const u8 sfe4002_lm87_regs[] = {
+	LM87_IN_LIMITS(0, 0x83, 0x91),		/* 2.5V:  1.8V +/- 5% */
+	LM87_IN_LIMITS(1, 0x51, 0x5a),		/* Vccp1: 1.2V +/- 5% */
+	LM87_IN_LIMITS(2, 0xb6, 0xca),		/* 3.3V:  3.3V +/- 5% */
+	LM87_IN_LIMITS(3, 0xb0, 0xc9),		/* 5V:    4.6-5.2V */
+	LM87_IN_LIMITS(4, 0xb0, 0xe0),		/* 12V:   11-14V */
+	LM87_IN_LIMITS(5, 0x44, 0x4b),		/* Vccp2: 1.0V +/- 5% */
+	LM87_AIN_LIMITS(0, 0xa0, 0xb2),		/* AIN1:  1.66V +/- 5% */
+	LM87_AIN_LIMITS(1, 0x91, 0xa1),		/* AIN2:  1.5V +/- 5% */
+	LM87_TEMP_INT_LIMITS(10, 60),		/* board */
+	LM87_TEMP_EXT1_LIMITS(10, 70),		/* Falcon */
+	0
+};
+
+static struct i2c_board_info sfe4002_hwmon_info = {
+	I2C_BOARD_INFO("lm87", 0x2e),
+	.platform_data	= &sfe4002_lm87_channel,
+	.irq		= -1,
+};
+
 /****************************************************************************/
 /* LED allocations. Note that on rev A0 boards the schematic and the reality
  * differ: red and green are swapped. Below is the fixed (A1) layout (there
@@ -84,81 +204,67 @@
 			QUAKE_LED_OFF);
 }
 
+static int sfe4002_check_hw(struct efx_nic *efx)
+{
+	/* A0 board rev. 4002s report a temperature fault the whole time
+	 * (bad sensor) so we mask it out. */
+	unsigned alarm_mask =
+		(efx->board_info.major == 0 && efx->board_info.minor == 0) ?
+		~LM87_ALARM_TEMP_EXT1 : ~0;
+
+	return efx_check_lm87(efx, alarm_mask);
+}
+
 static int sfe4002_init(struct efx_nic *efx)
 {
+	int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs);
+	if (rc)
+		return rc;
+	efx->board_info.monitor = sfe4002_check_hw;
 	efx->board_info.init_leds = sfe4002_init_leds;
 	efx->board_info.set_fault_led = sfe4002_fault_led;
 	efx->board_info.blink = board_blink;
+	efx->board_info.fini = efx_fini_lm87;
 	return 0;
 }
 
 /* This will get expanded as board-specific details get moved out of the
  * PHY drivers. */
 struct efx_board_data {
+	enum efx_board_type type;
 	const char *ref_model;
 	const char *gen_type;
 	int (*init) (struct efx_nic *nic);
 };
 
-static int dummy_init(struct efx_nic *nic)
-{
-	return 0;
-}
 
 static struct efx_board_data board_data[] = {
-	[EFX_BOARD_INVALID] =
-	{NULL,	    NULL,                  dummy_init},
-	[EFX_BOARD_SFE4001] =
-	{"SFE4001", "10GBASE-T adapter",   sfe4001_init},
-	[EFX_BOARD_SFE4002] =
-	{"SFE4002", "XFP adapter",         sfe4002_init},
+	{ EFX_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init },
+	{ EFX_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init },
+	{ EFX_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter",
+	  sfn4111t_init },
 };
 
-int efx_set_board_info(struct efx_nic *efx, u16 revision_info)
+void efx_set_board_info(struct efx_nic *efx, u16 revision_info)
 {
-	int rc = 0;
-	struct efx_board_data *data;
+	struct efx_board_data *data = NULL;
+	int i;
 
-	if (BOARD_TYPE(revision_info) >= EFX_BOARD_MAX) {
-		EFX_ERR(efx, "squashing unknown board type %d\n",
-			BOARD_TYPE(revision_info));
-		revision_info = 0;
-	}
+	efx->board_info.type = BOARD_TYPE(revision_info);
+	efx->board_info.major = BOARD_MAJOR(revision_info);
+	efx->board_info.minor = BOARD_MINOR(revision_info);
 
-	if (BOARD_TYPE(revision_info) == 0) {
-		efx->board_info.major = 0;
-		efx->board_info.minor = 0;
-		/* For early boards that don't have revision info. there is
-		 * only 1 board for each PHY type, so we can work it out, with
-		 * the exception of the PHY-less boards. */
-		switch (efx->phy_type) {
-		case PHY_TYPE_10XPRESS:
-			efx->board_info.type = EFX_BOARD_SFE4001;
-			break;
-		case PHY_TYPE_XFP:
-			efx->board_info.type = EFX_BOARD_SFE4002;
-			break;
-		default:
-			efx->board_info.type = 0;
-			break;
-		}
-	} else {
-		efx->board_info.type = BOARD_TYPE(revision_info);
-		efx->board_info.major = BOARD_MAJOR(revision_info);
-		efx->board_info.minor = BOARD_MINOR(revision_info);
-	}
+	for (i = 0; i < ARRAY_SIZE(board_data); i++)
+		if (board_data[i].type == efx->board_info.type)
+			data = &board_data[i];
 
-	data = &board_data[efx->board_info.type];
-
-	/* Report the board model number or generic type for recognisable
-	 * boards. */
-	if (efx->board_info.type != 0)
+	if (data) {
 		EFX_INFO(efx, "board is %s rev %c%d\n",
 			 (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
 			 ? data->ref_model : data->gen_type,
 			 'A' + efx->board_info.major, efx->board_info.minor);
-
-	efx->board_info.init = data->init;
-
-	return rc;
+		efx->board_info.init = data->init;
+	} else {
+		EFX_ERR(efx, "unknown board type %d\n", efx->board_info.type);
+	}
 }
diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h
index c6e01b6..d93c6c6 100644
--- a/drivers/net/sfc/boards.h
+++ b/drivers/net/sfc/boards.h
@@ -1,6 +1,6 @@
 /****************************************************************************
  * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2007 Solarflare Communications Inc.
+ * Copyright 2007-2008 Solarflare Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
@@ -12,14 +12,16 @@
 
 /* Board IDs (must fit in 8 bits) */
 enum efx_board_type {
-	EFX_BOARD_INVALID = 0,
-	EFX_BOARD_SFE4001 = 1,   /* SFE4001 (10GBASE-T) */
+	EFX_BOARD_SFE4001 = 1,
 	EFX_BOARD_SFE4002 = 2,
-	/* Insert new types before here */
-	EFX_BOARD_MAX
+	EFX_BOARD_SFN4111T = 0x51,
 };
 
-extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
+extern void efx_set_board_info(struct efx_nic *efx, u16 revision_info);
+
+/* SFE4001 (10GBASE-T) */
 extern int sfe4001_init(struct efx_nic *efx);
+/* SFN4111T (100/1000/10GBASE-T) */
+extern int sfn4111t_init(struct efx_nic *efx);
 
 #endif
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 06ea71c..7673fd9 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -21,14 +21,12 @@
 #include <linux/ethtool.h>
 #include <linux/topology.h>
 #include "net_driver.h"
-#include "gmii.h"
 #include "ethtool.h"
 #include "tx.h"
 #include "rx.h"
 #include "efx.h"
 #include "mdio_10g.h"
 #include "falcon.h"
-#include "mac.h"
 
 #define EFX_MAX_MTU (9 * 1024)
 
@@ -39,6 +37,12 @@
  */
 static struct workqueue_struct *refill_workqueue;
 
+/* Reset workqueue. If any NIC has a hardware failure then a reset will be
+ * queued onto this work queue. This is not a per-nic work queue, because
+ * efx_reset_work() acquires the rtnl lock, so resets are naturally serialised.
+ */
+static struct workqueue_struct *reset_workqueue;
+
 /**************************************************************************
  *
  * Configurable values
@@ -58,13 +62,15 @@
 /*
  * Use separate channels for TX and RX events
  *
- * Set this to 1 to use separate channels for TX and RX. It allows us to
- * apply a higher level of interrupt moderation to TX events.
+ * Set this to 1 to use separate channels for TX and RX. It allows us
+ * to control interrupt affinity separately for TX and RX.
  *
- * This is forced to 0 for MSI interrupt mode as the interrupt vector
- * is not written
+ * This is only used in MSI-X interrupt mode
  */
-static unsigned int separate_tx_and_rx_channels = true;
+static unsigned int separate_tx_channels;
+module_param(separate_tx_channels, uint, 0644);
+MODULE_PARM_DESC(separate_tx_channels,
+		 "Use separate channels for TX and RX");
 
 /* This is the weight assigned to each of the (per-channel) virtual
  * NAPI devices.
@@ -77,11 +83,6 @@
  */
 unsigned int efx_monitor_interval = 1 * HZ;
 
-/* This controls whether or not the hardware monitor will trigger a
- * reset when it detects an error condition.
- */
-static unsigned int monitor_reset = true;
-
 /* This controls whether or not the driver will initialise devices
  * with invalid MAC addresses stored in the EEPROM or flash.  If true,
  * such devices will be initialised with a random locally-generated
@@ -128,6 +129,10 @@
 module_param(rss_cpus, uint, 0444);
 MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling");
 
+static int phy_flash_cfg;
+module_param(phy_flash_cfg, int, 0644);
+MODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially");
+
 /**************************************************************************
  *
  * Utility functions and prototypes
@@ -211,7 +216,6 @@
 {
 	struct efx_channel *channel =
 		container_of(napi, struct efx_channel, napi_str);
-	struct net_device *napi_dev = channel->napi_dev;
 	int rx_packets;
 
 	EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n",
@@ -225,7 +229,7 @@
 		 * since efx_channel_processed() will have no effect if
 		 * interrupts have already been disabled.
 		 */
-		netif_rx_complete(napi_dev, napi);
+		netif_rx_complete(napi);
 		efx_channel_processed(channel);
 	}
 
@@ -349,6 +353,27 @@
 }
 
 
+static void efx_set_channel_names(struct efx_nic *efx)
+{
+	struct efx_channel *channel;
+	const char *type = "";
+	int number;
+
+	efx_for_each_channel(channel, efx) {
+		number = channel->channel;
+		if (efx->n_channels > efx->n_rx_queues) {
+			if (channel->channel < efx->n_rx_queues) {
+				type = "-rx";
+			} else {
+				type = "-tx";
+				number -= efx->n_rx_queues;
+			}
+		}
+		snprintf(channel->name, sizeof(channel->name),
+			 "%s%s-%d", efx->name, type, number);
+	}
+}
+
 /* Channels are shutdown and reinitialised whilst the NIC is running
  * to propagate configuration changes (mtu, checksum offload), or
  * to clear hardware error conditions
@@ -523,26 +548,8 @@
 
 	/* Status message for kernel log */
 	if (efx->link_up) {
-		struct mii_if_info *gmii = &efx->mii;
-		unsigned adv, lpa;
-		/* NONE here means direct XAUI from the controller, with no
-		 * MDIO-attached device we can query. */
-		if (efx->phy_type != PHY_TYPE_NONE) {
-			adv = gmii_advertised(gmii);
-			lpa = gmii_lpa(gmii);
-		} else {
-			lpa = GM_LPA_10000 | LPA_DUPLEX;
-			adv = lpa;
-		}
-		EFX_INFO(efx, "link up at %dMbps %s-duplex "
-			 "(adv %04x lpa %04x) (MTU %d)%s\n",
-			 (efx->link_options & GM_LPA_10000 ? 10000 :
-			  (efx->link_options & GM_LPA_1000 ? 1000 :
-			   (efx->link_options & GM_LPA_100 ? 100 :
-			    10))),
-			 (efx->link_options & GM_LPA_DUPLEX ?
-			  "full" : "half"),
-			 adv, lpa,
+		EFX_INFO(efx, "link up at %uMbps %s-duplex (MTU %d)%s\n",
+			 efx->link_speed, efx->link_fd ? "full" : "half",
 			 efx->net_dev->mtu,
 			 (efx->promiscuous ? " [PROMISC]" : ""));
 	} else {
@@ -566,10 +573,28 @@
 		netif_addr_unlock_bh(efx->net_dev);
 	}
 
-	falcon_reconfigure_xmac(efx);
+	falcon_deconfigure_mac_wrapper(efx);
+
+	/* Reconfigure the PHY, disabling transmit in mac level loopback. */
+	if (LOOPBACK_INTERNAL(efx))
+		efx->phy_mode |= PHY_MODE_TX_DISABLED;
+	else
+		efx->phy_mode &= ~PHY_MODE_TX_DISABLED;
+	efx->phy_op->reconfigure(efx);
+
+	if (falcon_switch_mac(efx))
+		goto fail;
+
+	efx->mac_op->reconfigure(efx);
 
 	/* Inform kernel of loss/gain of carrier */
 	efx_link_status_changed(efx);
+	return;
+
+fail:
+	EFX_ERR(efx, "failed to reconfigure MAC\n");
+	efx->phy_op->fini(efx);
+	efx->port_initialized = false;
 }
 
 /* Reinitialise the MAC to pick up new PHY settings, even if the port is
@@ -586,10 +611,9 @@
 /* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all()
  * we don't efx_reconfigure_port() if the port is disabled. Care is taken
  * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */
-static void efx_reconfigure_work(struct work_struct *data)
+static void efx_phy_work(struct work_struct *data)
 {
-	struct efx_nic *efx = container_of(data, struct efx_nic,
-					   reconfigure_work);
+	struct efx_nic *efx = container_of(data, struct efx_nic, phy_work);
 
 	mutex_lock(&efx->mac_lock);
 	if (efx->port_enabled)
@@ -597,6 +621,16 @@
 	mutex_unlock(&efx->mac_lock);
 }
 
+static void efx_mac_work(struct work_struct *data)
+{
+	struct efx_nic *efx = container_of(data, struct efx_nic, mac_work);
+
+	mutex_lock(&efx->mac_lock);
+	if (efx->port_enabled)
+		efx->mac_op->irq(efx);
+	mutex_unlock(&efx->mac_lock);
+}
+
 static int efx_probe_port(struct efx_nic *efx)
 {
 	int rc;
@@ -608,21 +642,22 @@
 	if (rc)
 		goto err;
 
+	if (phy_flash_cfg)
+		efx->phy_mode = PHY_MODE_SPECIAL;
+
 	/* Sanity check MAC address */
 	if (is_valid_ether_addr(efx->mac_address)) {
 		memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN);
 	} else {
-		DECLARE_MAC_BUF(mac);
-
-		EFX_ERR(efx, "invalid MAC address %s\n",
-			print_mac(mac, efx->mac_address));
+		EFX_ERR(efx, "invalid MAC address %pM\n",
+			efx->mac_address);
 		if (!allow_bad_hwaddr) {
 			rc = -EINVAL;
 			goto err;
 		}
 		random_ether_addr(efx->net_dev->dev_addr);
-		EFX_INFO(efx, "using locally-generated MAC %s\n",
-			 print_mac(mac, efx->net_dev->dev_addr));
+		EFX_INFO(efx, "using locally-generated MAC %pM\n",
+			 efx->net_dev->dev_addr);
 	}
 
 	return 0;
@@ -638,23 +673,30 @@
 
 	EFX_LOG(efx, "init port\n");
 
-	/* Initialise the MAC and PHY */
-	rc = falcon_init_xmac(efx);
+	rc = efx->phy_op->init(efx);
 	if (rc)
 		return rc;
+	efx->phy_op->reconfigure(efx);
+
+	mutex_lock(&efx->mac_lock);
+	rc = falcon_switch_mac(efx);
+	mutex_unlock(&efx->mac_lock);
+	if (rc)
+		goto fail;
+	efx->mac_op->reconfigure(efx);
 
 	efx->port_initialized = true;
 	efx->stats_enabled = true;
-
-	/* Reconfigure port to program MAC registers */
-	falcon_reconfigure_xmac(efx);
-
 	return 0;
+
+fail:
+	efx->phy_op->fini(efx);
+	return rc;
 }
 
 /* Allow efx_reconfigure_port() to be scheduled, and close the window
  * between efx_stop_port and efx_flush_all whereby a previously scheduled
- * efx_reconfigure_port() may have been cancelled */
+ * efx_phy_work()/efx_mac_work() may have been cancelled */
 static void efx_start_port(struct efx_nic *efx)
 {
 	EFX_LOG(efx, "start port\n");
@@ -663,13 +705,14 @@
 	mutex_lock(&efx->mac_lock);
 	efx->port_enabled = true;
 	__efx_reconfigure_port(efx);
+	efx->mac_op->irq(efx);
 	mutex_unlock(&efx->mac_lock);
 }
 
-/* Prevent efx_reconfigure_work and efx_monitor() from executing, and
- * efx_set_multicast_list() from scheduling efx_reconfigure_work.
- * efx_reconfigure_work can still be scheduled via NAPI processing
- * until efx_flush_all() is called */
+/* Prevent efx_phy_work, efx_mac_work, and efx_monitor() from executing,
+ * and efx_set_multicast_list() from scheduling efx_phy_work. efx_phy_work
+ * and efx_mac_work may still be scheduled via NAPI processing until
+ * efx_flush_all() is called */
 static void efx_stop_port(struct efx_nic *efx)
 {
 	EFX_LOG(efx, "stop port\n");
@@ -692,7 +735,7 @@
 	if (!efx->port_initialized)
 		return;
 
-	falcon_fini_xmac(efx);
+	efx->phy_op->fini(efx);
 	efx->port_initialized = false;
 
 	efx->link_up = false;
@@ -840,26 +883,33 @@
 	if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
 		struct msix_entry xentries[EFX_MAX_CHANNELS];
 		int wanted_ints;
+		int rx_queues;
 
 		/* We want one RX queue and interrupt per CPU package
 		 * (or as specified by the rss_cpus module parameter).
 		 * We will need one channel per interrupt.
 		 */
-		wanted_ints = rss_cpus ? rss_cpus : efx_wanted_rx_queues();
-		efx->n_rx_queues = min(wanted_ints, max_channels);
+		rx_queues = rss_cpus ? rss_cpus : efx_wanted_rx_queues();
+		wanted_ints = rx_queues + (separate_tx_channels ? 1 : 0);
+		wanted_ints = min(wanted_ints, max_channels);
 
-		for (i = 0; i < efx->n_rx_queues; i++)
+		for (i = 0; i < wanted_ints; i++)
 			xentries[i].entry = i;
-		rc = pci_enable_msix(efx->pci_dev, xentries, efx->n_rx_queues);
+		rc = pci_enable_msix(efx->pci_dev, xentries, wanted_ints);
 		if (rc > 0) {
-			EFX_BUG_ON_PARANOID(rc >= efx->n_rx_queues);
-			efx->n_rx_queues = rc;
+			EFX_ERR(efx, "WARNING: Insufficient MSI-X vectors"
+				" available (%d < %d).\n", rc, wanted_ints);
+			EFX_ERR(efx, "WARNING: Performance may be reduced.\n");
+			EFX_BUG_ON_PARANOID(rc >= wanted_ints);
+			wanted_ints = rc;
 			rc = pci_enable_msix(efx->pci_dev, xentries,
-					     efx->n_rx_queues);
+					     wanted_ints);
 		}
 
 		if (rc == 0) {
-			for (i = 0; i < efx->n_rx_queues; i++)
+			efx->n_rx_queues = min(rx_queues, wanted_ints);
+			efx->n_channels = wanted_ints;
+			for (i = 0; i < wanted_ints; i++)
 				efx->channel[i].irq = xentries[i].vector;
 		} else {
 			/* Fall back to single channel MSI */
@@ -871,6 +921,7 @@
 	/* Try single interrupt MSI */
 	if (efx->interrupt_mode == EFX_INT_MODE_MSI) {
 		efx->n_rx_queues = 1;
+		efx->n_channels = 1;
 		rc = pci_enable_msi(efx->pci_dev);
 		if (rc == 0) {
 			efx->channel[0].irq = efx->pci_dev->irq;
@@ -883,6 +934,7 @@
 	/* Assume legacy interrupts */
 	if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) {
 		efx->n_rx_queues = 1;
+		efx->n_channels = 1 + (separate_tx_channels ? 1 : 0);
 		efx->legacy_irq = efx->pci_dev->irq;
 	}
 }
@@ -907,8 +959,8 @@
 	struct efx_rx_queue *rx_queue;
 
 	efx_for_each_tx_queue(tx_queue, efx) {
-		if (!EFX_INT_MODE_USE_MSI(efx) && separate_tx_and_rx_channels)
-			tx_queue->channel = &efx->channel[1];
+		if (separate_tx_channels)
+			tx_queue->channel = &efx->channel[efx->n_channels-1];
 		else
 			tx_queue->channel = &efx->channel[0];
 		tx_queue->channel->used_flags |= EFX_USED_BY_TX;
@@ -985,6 +1037,7 @@
 			goto fail3;
 		}
 	}
+	efx_set_channel_names(efx);
 
 	return 0;
 
@@ -1050,7 +1103,8 @@
 		cancel_delayed_work_sync(&rx_queue->work);
 
 	/* Stop scheduled port reconfigurations */
-	cancel_work_sync(&efx->reconfigure_work);
+	cancel_work_sync(&efx->mac_work);
+	cancel_work_sync(&efx->phy_work);
 
 }
 
@@ -1087,7 +1141,7 @@
 	 * window to loose phy events */
 	efx_stop_port(efx);
 
-	/* Flush reconfigure_work, refill_workqueue, monitor_work */
+	/* Flush efx_phy_work, efx_mac_work, refill_workqueue, monitor_work */
 	efx_flush_all(efx);
 
 	/* Isolate the MAC from the TX and RX engines, so that queue
@@ -1159,36 +1213,31 @@
 {
 	struct efx_nic *efx = container_of(data, struct efx_nic,
 					   monitor_work.work);
-	int rc = 0;
+	int rc;
 
 	EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
 		  raw_smp_processor_id());
 
-
 	/* If the mac_lock is already held then it is likely a port
 	 * reconfiguration is already in place, which will likely do
 	 * most of the work of check_hw() anyway. */
-	if (!mutex_trylock(&efx->mac_lock)) {
-		queue_delayed_work(efx->workqueue, &efx->monitor_work,
-				   efx_monitor_interval);
-		return;
-	}
-
-	if (efx->port_enabled)
-		rc = falcon_check_xmac(efx);
-	mutex_unlock(&efx->mac_lock);
-
+	if (!mutex_trylock(&efx->mac_lock))
+		goto out_requeue;
+	if (!efx->port_enabled)
+		goto out_unlock;
+	rc = efx->board_info.monitor(efx);
 	if (rc) {
-		if (monitor_reset) {
-			EFX_ERR(efx, "hardware monitor detected a fault: "
-				"triggering reset\n");
-			efx_schedule_reset(efx, RESET_TYPE_MONITOR);
-		} else {
-			EFX_ERR(efx, "hardware monitor detected a fault, "
-				"skipping reset\n");
-		}
+		EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
+			(rc == -ERANGE) ? "reported fault" : "failed");
+		efx->phy_mode |= PHY_MODE_LOW_POWER;
+		falcon_sim_phy_event(efx);
 	}
+	efx->phy_op->poll(efx);
+	efx->mac_op->poll(efx);
 
+out_unlock:
+	mutex_unlock(&efx->mac_lock);
+out_requeue:
 	queue_delayed_work(efx->workqueue, &efx->monitor_work,
 			   efx_monitor_interval);
 }
@@ -1282,6 +1331,8 @@
 	EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name,
 		raw_smp_processor_id());
 
+	if (efx->state == STATE_DISABLED)
+		return -EIO;
 	if (efx->phy_mode & PHY_MODE_SPECIAL)
 		return -EBUSY;
 
@@ -1300,10 +1351,12 @@
 	EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name,
 		raw_smp_processor_id());
 
-	/* Stop the device and flush all the channels */
-	efx_stop_all(efx);
-	efx_fini_channels(efx);
-	efx_init_channels(efx);
+	if (efx->state != STATE_DISABLED) {
+		/* Stop the device and flush all the channels */
+		efx_stop_all(efx);
+		efx_fini_channels(efx);
+		efx_init_channels(efx);
+	}
 
 	return 0;
 }
@@ -1322,7 +1375,7 @@
 	if (!spin_trylock(&efx->stats_lock))
 		return stats;
 	if (efx->stats_enabled) {
-		falcon_update_stats_xmac(efx);
+		efx->mac_op->update_stats(efx);
 		falcon_update_nic_stats(efx);
 	}
 	spin_unlock(&efx->stats_lock);
@@ -1360,12 +1413,11 @@
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
 
-	EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n",
-		atomic_read(&efx->netif_stop_count), efx->port_enabled,
-		monitor_reset ? "resetting channels" : "skipping reset");
+	EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d:"
+		" resetting channels\n",
+		atomic_read(&efx->netif_stop_count), efx->port_enabled);
 
-	if (monitor_reset)
-		efx_schedule_reset(efx, RESET_TYPE_MONITOR);
+	efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG);
 }
 
 
@@ -1401,9 +1453,8 @@
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
 	if (!is_valid_ether_addr(new_addr)) {
-		DECLARE_MAC_BUF(mac);
-		EFX_ERR(efx, "invalid ethernet MAC address requested: %s\n",
-			print_mac(mac, new_addr));
+		EFX_ERR(efx, "invalid ethernet MAC address requested: %pM\n",
+			new_addr);
 		return -EINVAL;
 	}
 
@@ -1447,22 +1498,43 @@
 		return;
 
 	if (changed)
-		queue_work(efx->workqueue, &efx->reconfigure_work);
+		queue_work(efx->workqueue, &efx->phy_work);
 
 	/* Create and activate new global multicast hash table */
 	falcon_set_multicast_hash(efx);
 }
 
+static const struct net_device_ops efx_netdev_ops = {
+	.ndo_open		= efx_net_open,
+	.ndo_stop		= efx_net_stop,
+	.ndo_get_stats		= efx_net_stats,
+	.ndo_tx_timeout		= efx_watchdog,
+	.ndo_start_xmit		= efx_hard_start_xmit,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= efx_ioctl,
+	.ndo_change_mtu		= efx_change_mtu,
+	.ndo_set_mac_address	= efx_set_mac_address,
+	.ndo_set_multicast_list = efx_set_multicast_list,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller = efx_netpoll,
+#endif
+};
+
+static void efx_update_name(struct efx_nic *efx)
+{
+	strcpy(efx->name, efx->net_dev->name);
+	efx_mtd_rename(efx);
+	efx_set_channel_names(efx);
+}
+
 static int efx_netdev_event(struct notifier_block *this,
 			    unsigned long event, void *ptr)
 {
 	struct net_device *net_dev = ptr;
 
-	if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) {
-		struct efx_nic *efx = netdev_priv(net_dev);
-
-		strcpy(efx->name, net_dev->name);
-	}
+	if (net_dev->netdev_ops == &efx_netdev_ops &&
+	    event == NETDEV_CHANGENAME)
+		efx_update_name(netdev_priv(net_dev));
 
 	return NOTIFY_DONE;
 }
@@ -1471,6 +1543,14 @@
 	.notifier_call = efx_netdev_event,
 };
 
+static ssize_t
+show_phy_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+	return sprintf(buf, "%d\n", efx->phy_type);
+}
+static DEVICE_ATTR(phy_type, 0644, show_phy_type, NULL);
+
 static int efx_register_netdev(struct efx_nic *efx)
 {
 	struct net_device *net_dev = efx->net_dev;
@@ -1478,18 +1558,7 @@
 
 	net_dev->watchdog_timeo = 5 * HZ;
 	net_dev->irq = efx->pci_dev->irq;
-	net_dev->open = efx_net_open;
-	net_dev->stop = efx_net_stop;
-	net_dev->get_stats = efx_net_stats;
-	net_dev->tx_timeout = &efx_watchdog;
-	net_dev->hard_start_xmit = efx_hard_start_xmit;
-	net_dev->do_ioctl = efx_ioctl;
-	net_dev->change_mtu = efx_change_mtu;
-	net_dev->set_mac_address = efx_set_mac_address;
-	net_dev->set_multicast_list = efx_set_multicast_list;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	net_dev->poll_controller = efx_netpoll;
-#endif
+	net_dev->netdev_ops = &efx_netdev_ops;
 	SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev);
 	SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
 
@@ -1497,7 +1566,7 @@
 	netif_carrier_off(efx->net_dev);
 
 	/* Clear MAC statistics */
-	falcon_update_stats_xmac(efx);
+	efx->mac_op->update_stats(efx);
 	memset(&efx->mac_stats, 0, sizeof(efx->mac_stats));
 
 	rc = register_netdev(net_dev);
@@ -1505,9 +1574,22 @@
 		EFX_ERR(efx, "could not register net dev\n");
 		return rc;
 	}
-	strcpy(efx->name, net_dev->name);
+
+	rtnl_lock();
+	efx_update_name(efx);
+	rtnl_unlock();
+
+	rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type);
+	if (rc) {
+		EFX_ERR(efx, "failed to init net dev attributes\n");
+		goto fail_registered;
+	}
 
 	return 0;
+
+fail_registered:
+	unregister_netdev(net_dev);
+	return rc;
 }
 
 static void efx_unregister_netdev(struct efx_nic *efx)
@@ -1527,6 +1609,7 @@
 
 	if (efx_dev_registered(efx)) {
 		strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
+		device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type);
 		unregister_netdev(efx->net_dev);
 	}
 }
@@ -1541,8 +1624,6 @@
  * before reset.  */
 void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 {
-	int rc;
-
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
 	/* The net_dev->get_stats handler is quite slow, and will fail
@@ -1553,10 +1634,9 @@
 
 	efx_stop_all(efx);
 	mutex_lock(&efx->mac_lock);
+	mutex_lock(&efx->spi_lock);
 
-	rc = falcon_xmac_get_settings(efx, ecmd);
-	if (rc)
-		EFX_ERR(efx, "could not back up PHY settings\n");
+	efx->phy_op->get_settings(efx, ecmd);
 
 	efx_fini_channels(efx);
 }
@@ -1581,10 +1661,11 @@
 	if (ok) {
 		efx_init_channels(efx);
 
-		if (falcon_xmac_set_settings(efx, ecmd))
+		if (efx->phy_op->set_settings(efx, ecmd))
 			EFX_ERR(efx, "could not restore PHY settings\n");
 	}
 
+	mutex_unlock(&efx->spi_lock);
 	mutex_unlock(&efx->mac_lock);
 
 	if (ok) {
@@ -1607,7 +1688,7 @@
 {
 	struct ethtool_cmd ecmd;
 	enum reset_type method = efx->reset_pending;
-	int rc;
+	int rc = 0;
 
 	/* Serialise with kernel interfaces */
 	rtnl_lock();
@@ -1616,7 +1697,7 @@
 	 * flag set so that efx_pci_probe_main will be retried */
 	if (efx->state != STATE_RUNNING) {
 		EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
-		goto unlock_rtnl;
+		goto out_unlock;
 	}
 
 	EFX_INFO(efx, "resetting (%d)\n", method);
@@ -1626,7 +1707,7 @@
 	rc = falcon_reset_hw(efx, method);
 	if (rc) {
 		EFX_ERR(efx, "failed to reset hardware\n");
-		goto fail;
+		goto out_disable;
 	}
 
 	/* Allow resets to be rescheduled. */
@@ -1640,28 +1721,23 @@
 
 	/* Leave device stopped if necessary */
 	if (method == RESET_TYPE_DISABLE) {
+		efx_reset_up(efx, &ecmd, false);
 		rc = -EIO;
-		goto fail;
+	} else {
+		rc = efx_reset_up(efx, &ecmd, true);
 	}
 
-	rc = efx_reset_up(efx, &ecmd, true);
-	if (rc)
-		goto disable;
+out_disable:
+	if (rc) {
+		EFX_ERR(efx, "has been disabled\n");
+		efx->state = STATE_DISABLED;
+		dev_close(efx->net_dev);
+	} else {
+		EFX_LOG(efx, "reset complete\n");
+	}
 
-	EFX_LOG(efx, "reset complete\n");
- unlock_rtnl:
+out_unlock:
 	rtnl_unlock();
-	return 0;
-
- fail:
-	efx_reset_up(efx, &ecmd, false);
- disable:
-	EFX_ERR(efx, "has been disabled\n");
-	efx->state = STATE_DISABLED;
-
-	rtnl_unlock();
-	efx_unregister_netdev(efx);
-	efx_fini_port(efx);
 	return rc;
 }
 
@@ -1709,7 +1785,7 @@
 
 	efx->reset_pending = method;
 
-	queue_work(efx->reset_workqueue, &efx->reset_work);
+	queue_work(reset_workqueue, &efx->reset_work);
 }
 
 /**************************************************************************
@@ -1743,10 +1819,16 @@
 void efx_port_dummy_op_void(struct efx_nic *efx) {}
 void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {}
 
+static struct efx_mac_operations efx_dummy_mac_operations = {
+	.reconfigure	= efx_port_dummy_op_void,
+	.poll		= efx_port_dummy_op_void,
+	.irq		= efx_port_dummy_op_void,
+};
+
 static struct efx_phy_operations efx_dummy_phy_operations = {
 	.init		 = efx_port_dummy_op_int,
 	.reconfigure	 = efx_port_dummy_op_void,
-	.check_hw        = efx_port_dummy_op_int,
+	.poll		 = efx_port_dummy_op_void,
 	.fini		 = efx_port_dummy_op_void,
 	.clear_interrupt = efx_port_dummy_op_void,
 };
@@ -1755,6 +1837,7 @@
 	.init		= efx_port_dummy_op_int,
 	.init_leds	= efx_port_dummy_op_int,
 	.set_fault_led	= efx_port_dummy_op_blink,
+	.monitor	= efx_port_dummy_op_int,
 	.blink		= efx_port_dummy_op_blink,
 	.fini		= efx_port_dummy_op_void,
 };
@@ -1774,12 +1857,13 @@
 	struct efx_channel *channel;
 	struct efx_tx_queue *tx_queue;
 	struct efx_rx_queue *rx_queue;
-	int i, rc;
+	int i;
 
 	/* Initialise common structures */
 	memset(efx, 0, sizeof(*efx));
 	spin_lock_init(&efx->biu_lock);
 	spin_lock_init(&efx->phy_lock);
+	mutex_init(&efx->spi_lock);
 	INIT_WORK(&efx->reset_work, efx_reset_work);
 	INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor);
 	efx->pci_dev = pci_dev;
@@ -1793,9 +1877,11 @@
 	spin_lock_init(&efx->netif_stop_lock);
 	spin_lock_init(&efx->stats_lock);
 	mutex_init(&efx->mac_lock);
+	efx->mac_op = &efx_dummy_mac_operations;
 	efx->phy_op = &efx_dummy_phy_operations;
 	efx->mii.dev = net_dev;
-	INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work);
+	INIT_WORK(&efx->phy_work, efx_phy_work);
+	INIT_WORK(&efx->mac_work, efx_mac_work);
 	atomic_set(&efx->netif_stop_count, 1);
 
 	for (i = 0; i < EFX_MAX_CHANNELS; i++) {
@@ -1841,34 +1927,18 @@
 	efx->interrupt_mode = max(efx->type->max_interrupt_mode,
 				  interrupt_mode);
 
-	efx->workqueue = create_singlethread_workqueue("sfc_work");
-	if (!efx->workqueue) {
-		rc = -ENOMEM;
-		goto fail1;
-	}
-
-	efx->reset_workqueue = create_singlethread_workqueue("sfc_reset");
-	if (!efx->reset_workqueue) {
-		rc = -ENOMEM;
-		goto fail2;
-	}
+	/* Would be good to use the net_dev name, but we're too early */
+	snprintf(efx->workqueue_name, sizeof(efx->workqueue_name), "sfc%s",
+		 pci_name(pci_dev));
+	efx->workqueue = create_singlethread_workqueue(efx->workqueue_name);
+	if (!efx->workqueue)
+		return -ENOMEM;
 
 	return 0;
-
- fail2:
-	destroy_workqueue(efx->workqueue);
-	efx->workqueue = NULL;
-
- fail1:
-	return rc;
 }
 
 static void efx_fini_struct(struct efx_nic *efx)
 {
-	if (efx->reset_workqueue) {
-		destroy_workqueue(efx->reset_workqueue);
-		efx->reset_workqueue = NULL;
-	}
 	if (efx->workqueue) {
 		destroy_workqueue(efx->workqueue);
 		efx->workqueue = NULL;
@@ -1927,11 +1997,13 @@
 
 	efx_unregister_netdev(efx);
 
+	efx_mtd_remove(efx);
+
 	/* Wait for any scheduled resets to complete. No more will be
 	 * scheduled from this point because efx_stop_all() has been
 	 * called, we are no longer registered with driverlink, and
 	 * the net_device's have been removed. */
-	flush_workqueue(efx->reset_workqueue);
+	cancel_work_sync(&efx->reset_work);
 
 	efx_pci_remove_main(efx);
 
@@ -1992,6 +2064,7 @@
 	efx_fini_port(efx);
  fail5:
  fail4:
+	efx->board_info.fini(efx);
  fail3:
 	efx_fini_napi(efx);
  fail2:
@@ -2045,14 +2118,23 @@
 	 * we're in STATE_INIT. */
 	for (i = 0; i < 5; i++) {
 		rc = efx_pci_probe_main(efx);
-		if (rc == 0)
-			break;
 
 		/* Serialise against efx_reset(). No more resets will be
 		 * scheduled since efx_stop_all() has been called, and we
 		 * have not and never have been registered with either
 		 * the rtnetlink or driverlink layers. */
-		flush_workqueue(efx->reset_workqueue);
+		cancel_work_sync(&efx->reset_work);
+
+		if (rc == 0) {
+			if (efx->reset_pending != RESET_TYPE_NONE) {
+				/* If there was a scheduled reset during
+				 * probe, the NIC is probably hosed anyway */
+				efx_pci_remove_main(efx);
+				rc = -EIO;
+			} else {
+				break;
+			}
+		}
 
 		/* Retry if a recoverably reset event has been scheduled */
 		if ((efx->reset_pending != RESET_TYPE_INVISIBLE) &&
@@ -2070,16 +2152,15 @@
 	/* Switch to the running state before we expose the device to
 	 * the OS.  This is to ensure that the initial gathering of
 	 * MAC stats succeeds. */
-	rtnl_lock();
 	efx->state = STATE_RUNNING;
-	rtnl_unlock();
+
+	efx_mtd_probe(efx); /* allowed to fail */
 
 	rc = efx_register_netdev(efx);
 	if (rc)
 		goto fail5;
 
 	EFX_LOG(efx, "initialisation successful\n");
-
 	return 0;
 
  fail5:
@@ -2127,6 +2208,11 @@
 		rc = -ENOMEM;
 		goto err_refill;
 	}
+	reset_workqueue = create_singlethread_workqueue("sfc_reset");
+	if (!reset_workqueue) {
+		rc = -ENOMEM;
+		goto err_reset;
+	}
 
 	rc = pci_register_driver(&efx_pci_driver);
 	if (rc < 0)
@@ -2135,6 +2221,8 @@
 	return 0;
 
  err_pci:
+	destroy_workqueue(reset_workqueue);
+ err_reset:
 	destroy_workqueue(refill_workqueue);
  err_refill:
 	unregister_netdevice_notifier(&efx_netdev_notifier);
@@ -2147,6 +2235,7 @@
 	printk(KERN_INFO "Solarflare NET driver unloading\n");
 
 	pci_unregister_driver(&efx_pci_driver);
+	destroy_workqueue(reset_workqueue);
 	destroy_workqueue(refill_workqueue);
 	unregister_netdevice_notifier(&efx_netdev_notifier);
 
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index d02937b..0dd7a53 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -58,6 +58,16 @@
 extern void efx_port_dummy_op_void(struct efx_nic *efx);
 extern void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink);
 
+/* MTD */
+#ifdef CONFIG_SFC_MTD
+extern int efx_mtd_probe(struct efx_nic *efx);
+extern void efx_mtd_rename(struct efx_nic *efx);
+extern void efx_mtd_remove(struct efx_nic *efx);
+#else
+static inline int efx_mtd_probe(struct efx_nic *efx) { return 0; }
+static inline void efx_mtd_rename(struct efx_nic *efx) {}
+static inline void efx_mtd_remove(struct efx_nic *efx) {}
+#endif
 
 extern unsigned int efx_monitor_interval;
 
@@ -67,7 +77,7 @@
 		  channel->channel, raw_smp_processor_id());
 	channel->work_pending = true;
 
-	netif_rx_schedule(channel->napi_dev, &channel->napi_str);
+	netif_rx_schedule(&channel->napi_str);
 }
 
 #endif /* EFX_EFX_H */
diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h
index cec15db..60cbc6e 100644
--- a/drivers/net/sfc/enum.h
+++ b/drivers/net/sfc/enum.h
@@ -1,6 +1,6 @@
 /****************************************************************************
  * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2007 Solarflare Communications Inc.
+ * Copyright 2007-2008 Solarflare Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
@@ -13,22 +13,24 @@
 /**
  * enum efx_loopback_mode - loopback modes
  * @LOOPBACK_NONE: no loopback
- * @LOOPBACK_XGMII: loopback within MAC at XGMII level
- * @LOOPBACK_XGXS: loopback within MAC at XGXS level
- * @LOOPBACK_XAUI: loopback within MAC at XAUI level
- * @LOOPBACK_PHYXS: loopback within PHY at PHYXS level
- * @LOOPBACK_PCS: loopback within PHY at PCS level
- * @LOOPBACK_PMAPMD: loopback within PHY at PMAPMD level
+ * @LOOPBACK_GMAC: loopback within GMAC at unspecified level
+ * @LOOPBACK_XGMII: loopback within XMAC at XGMII level
+ * @LOOPBACK_XGXS: loopback within XMAC at XGXS level
+ * @LOOPBACK_XAUI: loopback within XMAC at XAUI level
+ * @LOOPBACK_GPHY: loopback within 1G PHY at unspecified level
+ * @LOOPBACK_PHYXS: loopback within 10G PHY at PHYXS level
+ * @LOOPBACK_PCS: loopback within 10G PHY at PCS level
+ * @LOOPBACK_PMAPMD: loopback within 10G PHY at PMAPMD level
  * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!)
  */
 /* Please keep in order and up-to-date w.r.t the following two #defines */
 enum efx_loopback_mode {
 	LOOPBACK_NONE = 0,
-	LOOPBACK_MAC = 1,
+	LOOPBACK_GMAC = 1,
 	LOOPBACK_XGMII = 2,
 	LOOPBACK_XGXS = 3,
 	LOOPBACK_XAUI = 4,
-	LOOPBACK_PHY = 5,
+	LOOPBACK_GPHY = 5,
 	LOOPBACK_PHYXS = 6,
 	LOOPBACK_PCS = 7,
 	LOOPBACK_PMAPMD = 8,
@@ -45,15 +47,19 @@
 	LOOPBACK_MODE_NAME(efx->loopback_mode)
 
 /* These loopbacks occur within the controller */
-#define LOOPBACKS_10G_INTERNAL ((1 << LOOPBACK_XGMII)| \
-				(1 << LOOPBACK_XGXS) | \
-				(1 << LOOPBACK_XAUI))
+#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_GMAC) |     \
+			    (1 << LOOPBACK_XGMII)|     \
+			    (1 << LOOPBACK_XGXS) |     \
+			    (1 << LOOPBACK_XAUI))
 
 #define LOOPBACK_MASK(_efx)			\
 	(1 << (_efx)->loopback_mode)
 
 #define LOOPBACK_INTERNAL(_efx)				\
-	(!!(LOOPBACKS_10G_INTERNAL & LOOPBACK_MASK(_efx)))
+	(!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx)))
+
+#define LOOPBACK_CHANGED(_from, _to, _mask)				\
+	(!!((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & (_mask)))
 
 #define LOOPBACK_OUT_OF(_from, _to, _mask)				\
 	((LOOPBACK_MASK(_from) & (_mask)) && !(LOOPBACK_MASK(_to) & (_mask)))
@@ -72,7 +78,7 @@
  * @RESET_TYPE_ALL: reset everything but PCI core blocks
  * @RESET_TYPE_WORLD: reset everything, save & restore PCI config
  * @RESET_TYPE_DISABLE: disable NIC
- * @RESET_TYPE_MONITOR: reset due to hardware monitor
+ * @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog
  * @RESET_TYPE_INT_ERROR: reset due to internal error
  * @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors
  * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch
@@ -86,7 +92,7 @@
 	RESET_TYPE_WORLD = 2,
 	RESET_TYPE_DISABLE = 3,
 	RESET_TYPE_MAX_METHOD,
-	RESET_TYPE_MONITOR,
+	RESET_TYPE_TX_WATCHDOG,
 	RESET_TYPE_INT_ERROR,
 	RESET_TYPE_RX_RECOVERY,
 	RESET_TYPE_RX_DESC_FETCH,
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index cd0d087..53d259e 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -12,24 +12,24 @@
 #include <linux/ethtool.h>
 #include <linux/rtnetlink.h>
 #include "net_driver.h"
+#include "workarounds.h"
 #include "selftest.h"
 #include "efx.h"
 #include "ethtool.h"
 #include "falcon.h"
-#include "gmii.h"
 #include "spi.h"
-#include "mac.h"
+#include "mdio_10g.h"
 
 const char *efx_loopback_mode_names[] = {
 	[LOOPBACK_NONE]		= "NONE",
-	[LOOPBACK_MAC]		= "MAC",
+	[LOOPBACK_GMAC]		= "GMAC",
 	[LOOPBACK_XGMII]	= "XGMII",
 	[LOOPBACK_XGXS]		= "XGXS",
 	[LOOPBACK_XAUI] 	= "XAUI",
-	[LOOPBACK_PHY]		= "PHY",
-	[LOOPBACK_PHYXS]	= "PHY(XS)",
-	[LOOPBACK_PCS]	 	= "PHY(PCS)",
-	[LOOPBACK_PMAPMD]	= "PHY(PMAPMD)",
+	[LOOPBACK_GPHY]		= "GPHY",
+	[LOOPBACK_PHYXS]	= "PHYXS",
+	[LOOPBACK_PCS]	 	= "PCS",
+	[LOOPBACK_PMAPMD]	= "PMA/PMD",
 	[LOOPBACK_NETWORK]	= "NETWORK",
 };
 
@@ -172,10 +172,7 @@
 /* Number of ethtool statistics */
 #define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
 
-/* EEPROM range with gPXE configuration */
 #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB
-#define EFX_ETHTOOL_EEPROM_MIN 0x800U
-#define EFX_ETHTOOL_EEPROM_MAX 0x1800U
 
 /**************************************************************************
  *
@@ -185,12 +182,16 @@
  */
 
 /* Identify device by flashing LEDs */
-static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds)
+static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count)
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
 
 	efx->board_info.blink(efx, 1);
-	schedule_timeout_interruptible(seconds * HZ);
+	set_current_state(TASK_INTERRUPTIBLE);
+	if (count)
+		schedule_timeout(count * HZ);
+	else
+		schedule();
 	efx->board_info.blink(efx, 0);
 	return 0;
 }
@@ -200,13 +201,15 @@
 			     struct ethtool_cmd *ecmd)
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
-	int rc;
 
 	mutex_lock(&efx->mac_lock);
-	rc = falcon_xmac_get_settings(efx, ecmd);
+	efx->phy_op->get_settings(efx, ecmd);
 	mutex_unlock(&efx->mac_lock);
 
-	return rc;
+	/* Falcon GMAC does not support 1000Mbps HD */
+	ecmd->supported &= ~SUPPORTED_1000baseT_Half;
+
+	return 0;
 }
 
 /* This must be called with rtnl_lock held. */
@@ -216,8 +219,18 @@
 	struct efx_nic *efx = netdev_priv(net_dev);
 	int rc;
 
+	if (EFX_WORKAROUND_13963(efx) && !ecmd->autoneg)
+		return -EINVAL;
+
+	/* Falcon GMAC does not support 1000Mbps HD */
+	if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) {
+		EFX_LOG(efx, "rejecting unsupported 1000Mbps HD"
+			" setting\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&efx->mac_lock);
-	rc = falcon_xmac_set_settings(efx, ecmd);
+	rc = efx->phy_op->set_settings(efx, ecmd);
 	mutex_unlock(&efx->mac_lock);
 	if (!rc)
 		efx_reconfigure_port(efx);
@@ -241,10 +254,10 @@
  * @strings:		Ethtool strings, or %NULL
  * @data:		Ethtool test results, or %NULL
  * @test:		Pointer to test result (used only if data != %NULL)
- * @unit_format:	Unit name format (e.g. "channel\%d")
- * @unit_id:		Unit id (e.g. 0 for "channel0")
+ * @unit_format:	Unit name format (e.g. "chan\%d")
+ * @unit_id:		Unit id (e.g. 0 for "chan0")
  * @test_format:	Test name format (e.g. "loopback.\%s.tx.sent")
- * @test_id:		Test id (e.g. "PHY" for "loopback.PHY.tx_sent")
+ * @test_id:		Test id (e.g. "PHYXS" for "loopback.PHYXS.tx_sent")
  *
  * Fill in an individual self-test entry.
  */
@@ -261,18 +274,20 @@
 
 	/* Fill string, if applicable */
 	if (strings) {
-		snprintf(unit_str.name, sizeof(unit_str.name),
-			 unit_format, unit_id);
+		if (strchr(unit_format, '%'))
+			snprintf(unit_str.name, sizeof(unit_str.name),
+				 unit_format, unit_id);
+		else
+			strcpy(unit_str.name, unit_format);
 		snprintf(test_str.name, sizeof(test_str.name),
 			 test_format, test_id);
 		snprintf(strings[test_index].name,
 			 sizeof(strings[test_index].name),
-			 "%-9s%-17s", unit_str.name, test_str.name);
+			 "%-6s %-24s", unit_str.name, test_str.name);
 	}
 }
 
-#define EFX_PORT_NAME "port%d", 0
-#define EFX_CHANNEL_NAME(_channel) "channel%d", _channel->channel
+#define EFX_CHANNEL_NAME(_channel) "chan%d", _channel->channel
 #define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue
 #define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue
 #define EFX_LOOPBACK_NAME(_mode, _counter)			\
@@ -307,11 +322,11 @@
 	}
 	efx_fill_test(test_index++, strings, data,
 		      &lb_tests->rx_good,
-		      EFX_PORT_NAME,
+		      "rx", 0,
 		      EFX_LOOPBACK_NAME(mode, "rx_good"));
 	efx_fill_test(test_index++, strings, data,
 		      &lb_tests->rx_bad,
-		      EFX_PORT_NAME,
+		      "rx", 0,
 		      EFX_LOOPBACK_NAME(mode, "rx_bad"));
 
 	return test_index;
@@ -330,7 +345,7 @@
 				       u64 *data)
 {
 	struct efx_channel *channel;
-	unsigned int n = 0;
+	unsigned int n = 0, i;
 	enum efx_loopback_mode mode;
 
 	efx_fill_test(n++, strings, data, &tests->mii,
@@ -358,14 +373,12 @@
 
 	efx_fill_test(n++, strings, data, &tests->registers,
 		      "core", 0, "registers", NULL);
-	efx_fill_test(n++, strings, data, &tests->phy,
-		      EFX_PORT_NAME, "phy", NULL);
+
+	for (i = 0; i < efx->phy_op->num_tests; i++)
+		efx_fill_test(n++, strings, data, &tests->phy[i],
+			      "phy", 0, efx->phy_op->test_names[i], NULL);
 
 	/* Loopback tests */
-	efx_fill_test(n++, strings, data, &tests->loopback_speed,
-		      EFX_PORT_NAME, "loopback.speed", NULL);
-	efx_fill_test(n++, strings, data, &tests->loopback_full_duplex,
-		      EFX_PORT_NAME, "loopback.full_duplex", NULL);
 	for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) {
 		if (!(efx->loopback_modes & (1 << mode)))
 			continue;
@@ -429,7 +442,7 @@
 	EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
 
 	/* Update MAC and NIC statistics */
-	net_dev->get_stats(net_dev);
+	dev_get_stats(net_dev);
 
 	/* Fill detailed statistics buffer */
 	for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
@@ -476,7 +489,7 @@
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
 	struct efx_self_tests efx_tests;
-	int offline, already_up;
+	int already_up;
 	int rc;
 
 	ASSERT_RTNL();
@@ -496,24 +509,15 @@
 	}
 
 	memset(&efx_tests, 0, sizeof(efx_tests));
-	offline = (test->flags & ETH_TEST_FL_OFFLINE);
 
-	/* Perform online self tests first */
-	rc = efx_online_test(efx, &efx_tests);
-	if (rc)
-		goto out;
+	rc = efx_selftest(efx, &efx_tests, test->flags);
 
-	/* Perform offline tests only if online tests passed */
-	if (offline)
-		rc = efx_offline_test(efx, &efx_tests,
-				      efx->loopback_modes);
-
- out:
 	if (!already_up)
 		dev_close(efx->net_dev);
 
-	EFX_LOG(efx, "%s all %sline self-tests\n",
-		rc == 0 ? "passed" : "failed", offline ? "off" : "on");
+	EFX_LOG(efx, "%s %sline self-tests\n",
+		rc == 0 ? "passed" : "failed",
+		(test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
 
  fail2:
  fail1:
@@ -545,8 +549,8 @@
 
 	if (!spi)
 		return 0;
-	return min(spi->size, EFX_ETHTOOL_EEPROM_MAX) -
-		min(spi->size, EFX_ETHTOOL_EEPROM_MIN);
+	return min(spi->size, EFX_EEPROM_BOOTCONFIG_END) -
+		min(spi->size, EFX_EEPROM_BOOTCONFIG_START);
 }
 
 static int efx_ethtool_get_eeprom(struct net_device *net_dev,
@@ -557,8 +561,13 @@
 	size_t len;
 	int rc;
 
-	rc = falcon_spi_read(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN,
+	rc = mutex_lock_interruptible(&efx->spi_lock);
+	if (rc)
+		return rc;
+	rc = falcon_spi_read(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
 			     eeprom->len, &len, buf);
+	mutex_unlock(&efx->spi_lock);
+
 	eeprom->magic = EFX_ETHTOOL_EEPROM_MAGIC;
 	eeprom->len = len;
 	return rc;
@@ -575,8 +584,13 @@
 	if (eeprom->magic != EFX_ETHTOOL_EEPROM_MAGIC)
 		return -EINVAL;
 
-	rc = falcon_spi_write(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN,
+	rc = mutex_lock_interruptible(&efx->spi_lock);
+	if (rc)
+		return rc;
+	rc = falcon_spi_write(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
 			      eeprom->len, &len, buf);
+	mutex_unlock(&efx->spi_lock);
+
 	eeprom->len = len;
 	return rc;
 }
@@ -666,23 +680,52 @@
 				      struct ethtool_pauseparam *pause)
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
-	enum efx_fc_type flow_control = efx->flow_control;
-	int rc;
+	enum efx_fc_type wanted_fc;
+	bool reset;
 
-	flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO);
-	flow_control |= pause->rx_pause ? EFX_FC_RX : 0;
-	flow_control |= pause->tx_pause ? EFX_FC_TX : 0;
-	flow_control |= pause->autoneg ? EFX_FC_AUTO : 0;
+	wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) |
+		     (pause->tx_pause ? EFX_FC_TX : 0) |
+		     (pause->autoneg ? EFX_FC_AUTO : 0));
+
+	if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) {
+		EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n");
+		return -EINVAL;
+	}
+
+	if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) &&
+	    (wanted_fc & EFX_FC_AUTO)) {
+		EFX_LOG(efx, "PHY does not support flow control "
+			"autonegotiation\n");
+		return -EINVAL;
+	}
+
+	/* TX flow control may automatically turn itself off if the
+	 * link partner (intermittently) stops responding to pause
+	 * frames. There isn't any indication that this has happened,
+	 * so the best we do is leave it up to the user to spot this
+	 * and fix it be cycling transmit flow control on this end. */
+	reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX);
+	if (EFX_WORKAROUND_11482(efx) && reset) {
+		if (falcon_rev(efx) >= FALCON_REV_B0) {
+			/* Recover by resetting the EM block */
+			if (efx->link_up)
+				falcon_drain_tx_fifo(efx);
+		} else {
+			/* Schedule a reset to recover */
+			efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
+		}
+	}
 
 	/* Try to push the pause parameters */
 	mutex_lock(&efx->mac_lock);
-	rc = falcon_xmac_set_pause(efx, flow_control);
+
+	efx->wanted_fc = wanted_fc;
+	mdio_clause45_set_pause(efx);
+	__efx_reconfigure_port(efx);
+
 	mutex_unlock(&efx->mac_lock);
 
-	if (!rc)
-		efx_reconfigure_port(efx);
-
-	return rc;
+	return 0;
 }
 
 static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
@@ -690,9 +733,9 @@
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
 
-	pause->rx_pause = !!(efx->flow_control & EFX_FC_RX);
-	pause->tx_pause = !!(efx->flow_control & EFX_FC_TX);
-	pause->autoneg = !!(efx->flow_control & EFX_FC_AUTO);
+	pause->rx_pause = !!(efx->wanted_fc & EFX_FC_RX);
+	pause->tx_pause = !!(efx->wanted_fc & EFX_FC_TX);
+	pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO);
 }
 
 
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 31ed1f4..6884dc8 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -15,11 +15,11 @@
 #include <linux/seq_file.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/mii.h>
 #include "net_driver.h"
 #include "bitfield.h"
 #include "efx.h"
 #include "mac.h"
-#include "gmii.h"
 #include "spi.h"
 #include "falcon.h"
 #include "falcon_hwdefs.h"
@@ -70,6 +70,20 @@
 #define RX_DC_ENTRIES_ORDER 2
 #define RX_DC_BASE 0x100000
 
+static const unsigned int
+/* "Large" EEPROM device: Atmel AT25640 or similar
+ * 8 KB, 16-bit address, 32 B write block */
+large_eeprom_type = ((13 << SPI_DEV_TYPE_SIZE_LBN)
+		     | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN)
+		     | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)),
+/* Default flash device: Atmel AT25F1024
+ * 128 KB, 24-bit address, 32 KB erase block, 256 B write block */
+default_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN)
+		      | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN)
+		      | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN)
+		      | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN)
+		      | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN));
+
 /* RX FIFO XOFF watermark
  *
  * When the amount of the RX FIFO increases used increases past this
@@ -770,15 +784,18 @@
 			   rx_ev_buf_owner_id_err | rx_ev_eth_crc_err |
 			   rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err);
 
-	/* Count errors that are not in MAC stats. */
+	/* Count errors that are not in MAC stats.  Ignore expected
+	 * checksum errors during self-test. */
 	if (rx_ev_frm_trunc)
 		++rx_queue->channel->n_rx_frm_trunc;
 	else if (rx_ev_tobe_disc)
 		++rx_queue->channel->n_rx_tobe_disc;
-	else if (rx_ev_ip_hdr_chksum_err)
-		++rx_queue->channel->n_rx_ip_hdr_chksum_err;
-	else if (rx_ev_tcp_udp_chksum_err)
-		++rx_queue->channel->n_rx_tcp_udp_chksum_err;
+	else if (!efx->loopback_selftest) {
+		if (rx_ev_ip_hdr_chksum_err)
+			++rx_queue->channel->n_rx_ip_hdr_chksum_err;
+		else if (rx_ev_tcp_udp_chksum_err)
+			++rx_queue->channel->n_rx_tcp_udp_chksum_err;
+	}
 	if (rx_ev_ip_frag_err)
 		++rx_queue->channel->n_rx_ip_frag_err;
 
@@ -809,7 +826,7 @@
 #endif
 
 	if (unlikely(rx_ev_eth_crc_err && EFX_WORKAROUND_10750(efx) &&
-		     efx->phy_type == PHY_TYPE_10XPRESS))
+		     efx->phy_type == PHY_TYPE_SFX7101))
 		tenxpress_crc_err(efx);
 }
 
@@ -893,22 +910,20 @@
 				       efx_qword_t *event)
 {
 	struct efx_nic *efx = channel->efx;
-	bool is_phy_event = false, handled = false;
+	bool handled = false;
 
-	/* Check for interrupt on either port.  Some boards have a
-	 * single PHY wired to the interrupt line for port 1. */
 	if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) ||
 	    EFX_QWORD_FIELD(*event, G_PHY1_INTR) ||
-	    EFX_QWORD_FIELD(*event, XG_PHY_INTR))
-		is_phy_event = true;
+	    EFX_QWORD_FIELD(*event, XG_PHY_INTR) ||
+	    EFX_QWORD_FIELD(*event, XFP_PHY_INTR)) {
+		efx->phy_op->clear_interrupt(efx);
+		queue_work(efx->workqueue, &efx->phy_work);
+		handled = true;
+	}
 
 	if ((falcon_rev(efx) >= FALCON_REV_B0) &&
-	    EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0))
-		is_phy_event = true;
-
-	if (is_phy_event) {
-		efx->phy_op->clear_interrupt(efx);
-		queue_work(efx->workqueue, &efx->reconfigure_work);
+	    EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0)) {
+		queue_work(efx->workqueue, &efx->mac_work);
 		handled = true;
 	}
 
@@ -1151,6 +1166,19 @@
 	falcon_generate_event(channel, &test_event);
 }
 
+void falcon_sim_phy_event(struct efx_nic *efx)
+{
+	efx_qword_t phy_event;
+
+	EFX_POPULATE_QWORD_1(phy_event, EV_CODE, GLOBAL_EV_DECODE);
+	if (EFX_IS10G(efx))
+		EFX_SET_OWORD_FIELD(phy_event, XG_PHY_INTR, 1);
+	else
+		EFX_SET_OWORD_FIELD(phy_event, G_PHY0_INTR, 1);
+
+	falcon_generate_event(&efx->channel[0], &phy_event);
+}
+
 /**************************************************************************
  *
  * Flush handling
@@ -1560,7 +1588,7 @@
 	efx_for_each_channel(channel, efx) {
 		rc = request_irq(channel->irq, falcon_msi_interrupt,
 				 IRQF_PROBE_SHARED, /* Not shared */
-				 efx->name, channel);
+				 channel->name, channel);
 		if (rc) {
 			EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq);
 			goto fail2;
@@ -1605,32 +1633,45 @@
  **************************************************************************
  */
 
-#define FALCON_SPI_MAX_LEN ((unsigned) sizeof(efx_oword_t))
+#define FALCON_SPI_MAX_LEN sizeof(efx_oword_t)
+
+static int falcon_spi_poll(struct efx_nic *efx)
+{
+	efx_oword_t reg;
+	falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER);
+	return EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0;
+}
 
 /* Wait for SPI command completion */
 static int falcon_spi_wait(struct efx_nic *efx)
 {
-	unsigned long timeout = jiffies + DIV_ROUND_UP(HZ, 10);
-	efx_oword_t reg;
-	bool cmd_en, timer_active;
+	/* Most commands will finish quickly, so we start polling at
+	 * very short intervals.  Sometimes the command may have to
+	 * wait for VPD or expansion ROM access outside of our
+	 * control, so we allow up to 100 ms. */
+	unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 10);
+	int i;
+
+	for (i = 0; i < 10; i++) {
+		if (!falcon_spi_poll(efx))
+			return 0;
+		udelay(10);
+	}
 
 	for (;;) {
-		falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER);
-		cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN);
-		timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE);
-		if (!cmd_en && !timer_active)
+		if (!falcon_spi_poll(efx))
 			return 0;
 		if (time_after_eq(jiffies, timeout)) {
 			EFX_ERR(efx, "timed out waiting for SPI\n");
 			return -ETIMEDOUT;
 		}
-		cpu_relax();
+		schedule_timeout_uninterruptible(1);
 	}
 }
 
-static int falcon_spi_cmd(const struct efx_spi_device *spi,
-			  unsigned int command, int address,
-			  const void *in, void *out, unsigned int len)
+int falcon_spi_cmd(const struct efx_spi_device *spi,
+		   unsigned int command, int address,
+		   const void *in, void *out, size_t len)
 {
 	struct efx_nic *efx = spi->efx;
 	bool addressed = (address >= 0);
@@ -1641,9 +1682,10 @@
 	/* Input validation */
 	if (len > FALCON_SPI_MAX_LEN)
 		return -EINVAL;
+	BUG_ON(!mutex_is_locked(&efx->spi_lock));
 
-	/* Check SPI not currently being accessed */
-	rc = falcon_spi_wait(efx);
+	/* Check that previous command is not still running */
+	rc = falcon_spi_poll(efx);
 	if (rc)
 		return rc;
 
@@ -1685,8 +1727,8 @@
 	return 0;
 }
 
-static unsigned int
-falcon_spi_write_limit(const struct efx_spi_device *spi, unsigned int start)
+static size_t
+falcon_spi_write_limit(const struct efx_spi_device *spi, size_t start)
 {
 	return min(FALCON_SPI_MAX_LEN,
 		   (spi->block_size - (start & (spi->block_size - 1))));
@@ -1699,38 +1741,40 @@
 	return command | (((address >> 8) & spi->munge_address) << 3);
 }
 
-
-static int falcon_spi_fast_wait(const struct efx_spi_device *spi)
+/* Wait up to 10 ms for buffered write completion */
+int falcon_spi_wait_write(const struct efx_spi_device *spi)
 {
+	struct efx_nic *efx = spi->efx;
+	unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100);
 	u8 status;
-	int i, rc;
+	int rc;
 
-	/* Wait up to 1000us for flash/EEPROM to finish a fast operation. */
-	for (i = 0; i < 50; i++) {
-		udelay(20);
-
+	for (;;) {
 		rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL,
 				    &status, sizeof(status));
 		if (rc)
 			return rc;
 		if (!(status & SPI_STATUS_NRDY))
 			return 0;
+		if (time_after_eq(jiffies, timeout)) {
+			EFX_ERR(efx, "SPI write timeout on device %d"
+				" last status=0x%02x\n",
+				spi->device_id, status);
+			return -ETIMEDOUT;
+		}
+		schedule_timeout_uninterruptible(1);
 	}
-	EFX_ERR(spi->efx,
-		"timed out waiting for device %d last status=0x%02x\n",
-		spi->device_id, status);
-	return -ETIMEDOUT;
 }
 
 int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
 		    size_t len, size_t *retlen, u8 *buffer)
 {
-	unsigned int command, block_len, pos = 0;
+	size_t block_len, pos = 0;
+	unsigned int command;
 	int rc = 0;
 
 	while (pos < len) {
-		block_len = min((unsigned int)len - pos,
-				FALCON_SPI_MAX_LEN);
+		block_len = min(len - pos, FALCON_SPI_MAX_LEN);
 
 		command = efx_spi_munge_command(spi, SPI_READ, start + pos);
 		rc = falcon_spi_cmd(spi, command, start + pos, NULL,
@@ -1756,7 +1800,8 @@
 		     size_t len, size_t *retlen, const u8 *buffer)
 {
 	u8 verify_buffer[FALCON_SPI_MAX_LEN];
-	unsigned int command, block_len, pos = 0;
+	size_t block_len, pos = 0;
+	unsigned int command;
 	int rc = 0;
 
 	while (pos < len) {
@@ -1764,7 +1809,7 @@
 		if (rc)
 			break;
 
-		block_len = min((unsigned int)len - pos,
+		block_len = min(len - pos,
 				falcon_spi_write_limit(spi, start + pos));
 		command = efx_spi_munge_command(spi, SPI_WRITE, start + pos);
 		rc = falcon_spi_cmd(spi, command, start + pos,
@@ -1772,7 +1817,7 @@
 		if (rc)
 			break;
 
-		rc = falcon_spi_fast_wait(spi);
+		rc = falcon_spi_wait_write(spi);
 		if (rc)
 			break;
 
@@ -1805,40 +1850,61 @@
  *
  **************************************************************************
  */
-void falcon_drain_tx_fifo(struct efx_nic *efx)
+
+static int falcon_reset_macs(struct efx_nic *efx)
 {
-	efx_oword_t temp;
+	efx_oword_t reg;
 	int count;
 
-	if ((falcon_rev(efx) < FALCON_REV_B0) ||
-	    (efx->loopback_mode != LOOPBACK_NONE))
-		return;
+	if (falcon_rev(efx) < FALCON_REV_B0) {
+		/* It's not safe to use GLB_CTL_REG to reset the
+		 * macs, so instead use the internal MAC resets
+		 */
+		if (!EFX_IS10G(efx)) {
+			EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 1);
+			falcon_write(efx, &reg, GM_CFG1_REG);
+			udelay(1000);
 
-	falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
-	/* There is no point in draining more than once */
-	if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
-		return;
+			EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 0);
+			falcon_write(efx, &reg, GM_CFG1_REG);
+			udelay(1000);
+			return 0;
+		} else {
+			EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1);
+			falcon_write(efx, &reg, XM_GLB_CFG_REG);
+
+			for (count = 0; count < 10000; count++) {
+				falcon_read(efx, &reg, XM_GLB_CFG_REG);
+				if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0)
+					return 0;
+				udelay(10);
+			}
+
+			EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
+			return -ETIMEDOUT;
+		}
+	}
 
 	/* MAC stats will fail whilst the TX fifo is draining. Serialise
 	 * the drain sequence with the statistics fetch */
 	spin_lock(&efx->stats_lock);
 
-	EFX_SET_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0, 1);
-	falcon_write(efx, &temp, MAC0_CTRL_REG_KER);
+	falcon_read(efx, &reg, MAC0_CTRL_REG_KER);
+	EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1);
+	falcon_write(efx, &reg, MAC0_CTRL_REG_KER);
 
-	/* Reset the MAC and EM block. */
-	falcon_read(efx, &temp, GLB_CTL_REG_KER);
-	EFX_SET_OWORD_FIELD(temp, RST_XGTX, 1);
-	EFX_SET_OWORD_FIELD(temp, RST_XGRX, 1);
-	EFX_SET_OWORD_FIELD(temp, RST_EM, 1);
-	falcon_write(efx, &temp, GLB_CTL_REG_KER);
+	falcon_read(efx, &reg, GLB_CTL_REG_KER);
+	EFX_SET_OWORD_FIELD(reg, RST_XGTX, 1);
+	EFX_SET_OWORD_FIELD(reg, RST_XGRX, 1);
+	EFX_SET_OWORD_FIELD(reg, RST_EM, 1);
+	falcon_write(efx, &reg, GLB_CTL_REG_KER);
 
 	count = 0;
 	while (1) {
-		falcon_read(efx, &temp, GLB_CTL_REG_KER);
-		if (!EFX_OWORD_FIELD(temp, RST_XGTX) &&
-		    !EFX_OWORD_FIELD(temp, RST_XGRX) &&
-		    !EFX_OWORD_FIELD(temp, RST_EM)) {
+		falcon_read(efx, &reg, GLB_CTL_REG_KER);
+		if (!EFX_OWORD_FIELD(reg, RST_XGTX) &&
+		    !EFX_OWORD_FIELD(reg, RST_XGRX) &&
+		    !EFX_OWORD_FIELD(reg, RST_EM)) {
 			EFX_LOG(efx, "Completed MAC reset after %d loops\n",
 				count);
 			break;
@@ -1855,21 +1921,39 @@
 
 	/* If we've reset the EM block and the link is up, then
 	 * we'll have to kick the XAUI link so the PHY can recover */
-	if (efx->link_up && EFX_WORKAROUND_5147(efx))
+	if (efx->link_up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx))
 		falcon_reset_xaui(efx);
+
+	return 0;
+}
+
+void falcon_drain_tx_fifo(struct efx_nic *efx)
+{
+	efx_oword_t reg;
+
+	if ((falcon_rev(efx) < FALCON_REV_B0) ||
+	    (efx->loopback_mode != LOOPBACK_NONE))
+		return;
+
+	falcon_read(efx, &reg, MAC0_CTRL_REG_KER);
+	/* There is no point in draining more than once */
+	if (EFX_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0))
+		return;
+
+	falcon_reset_macs(efx);
 }
 
 void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
 {
-	efx_oword_t temp;
+	efx_oword_t reg;
 
 	if (falcon_rev(efx) < FALCON_REV_B0)
 		return;
 
 	/* Isolate the MAC -> RX */
-	falcon_read(efx, &temp, RX_CFG_REG_KER);
-	EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 0);
-	falcon_write(efx, &temp, RX_CFG_REG_KER);
+	falcon_read(efx, &reg, RX_CFG_REG_KER);
+	EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 0);
+	falcon_write(efx, &reg, RX_CFG_REG_KER);
 
 	if (!efx->link_up)
 		falcon_drain_tx_fifo(efx);
@@ -1881,14 +1965,12 @@
 	int link_speed;
 	bool tx_fc;
 
-	if (efx->link_options & GM_LPA_10000)
-		link_speed = 0x3;
-	else if (efx->link_options & GM_LPA_1000)
-		link_speed = 0x2;
-	else if (efx->link_options & GM_LPA_100)
-		link_speed = 0x1;
-	else
-		link_speed = 0x0;
+	switch (efx->link_speed) {
+	case 10000: link_speed = 3; break;
+	case 1000:  link_speed = 2; break;
+	case 100:   link_speed = 1; break;
+	default:    link_speed = 0; break;
+	}
 	/* MAC_LINK_STATUS controls MAC backpressure but doesn't work
 	 * as advertised.  Disable to ensure packets are not
 	 * indefinitely held and TX queue can be flushed at any point
@@ -1914,7 +1996,7 @@
 	/* Transmission of pause frames when RX crosses the threshold is
 	 * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
 	 * Action on receipt of pause frames is controller by XM_DIS_FCNTL */
-	tx_fc = !!(efx->flow_control & EFX_FC_TX);
+	tx_fc = !!(efx->link_fc & EFX_FC_TX);
 	falcon_read(efx, &reg, RX_CFG_REG_KER);
 	EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);
 
@@ -1998,7 +2080,8 @@
 	efx_dword_t md_stat;
 	int count;
 
-	for (count = 0; count < 1000; count++) {	/* wait upto 10ms */
+	/* wait upto 50ms - taken max from datasheet */
+	for (count = 0; count < 5000; count++) {
 		falcon_readl(efx, &md_stat, MD_STAT_REG_KER);
 		if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) {
 			if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 ||
@@ -2162,10 +2245,14 @@
 static int falcon_probe_phy(struct efx_nic *efx)
 {
 	switch (efx->phy_type) {
-	case PHY_TYPE_10XPRESS:
-		efx->phy_op = &falcon_tenxpress_phy_ops;
+	case PHY_TYPE_SFX7101:
+		efx->phy_op = &falcon_sfx7101_phy_ops;
 		break;
-	case PHY_TYPE_XFP:
+	case PHY_TYPE_SFT9001A:
+	case PHY_TYPE_SFT9001B:
+		efx->phy_op = &falcon_sft9001_phy_ops;
+		break;
+	case PHY_TYPE_QT2022C2:
 		efx->phy_op = &falcon_xfp_phy_ops;
 		break;
 	default:
@@ -2174,10 +2261,59 @@
 		return -1;
 	}
 
-	efx->loopback_modes = LOOPBACKS_10G_INTERNAL | efx->phy_op->loopbacks;
+	if (efx->phy_op->macs & EFX_XMAC)
+		efx->loopback_modes |= ((1 << LOOPBACK_XGMII) |
+					(1 << LOOPBACK_XGXS) |
+					(1 << LOOPBACK_XAUI));
+	if (efx->phy_op->macs & EFX_GMAC)
+		efx->loopback_modes |= (1 << LOOPBACK_GMAC);
+	efx->loopback_modes |= efx->phy_op->loopbacks;
+
 	return 0;
 }
 
+int falcon_switch_mac(struct efx_nic *efx)
+{
+	struct efx_mac_operations *old_mac_op = efx->mac_op;
+	efx_oword_t nic_stat;
+	unsigned strap_val;
+
+	/* Internal loopbacks override the phy speed setting */
+	if (efx->loopback_mode == LOOPBACK_GMAC) {
+		efx->link_speed = 1000;
+		efx->link_fd = true;
+	} else if (LOOPBACK_INTERNAL(efx)) {
+		efx->link_speed = 10000;
+		efx->link_fd = true;
+	}
+
+	efx->mac_op = (EFX_IS10G(efx) ?
+		       &falcon_xmac_operations : &falcon_gmac_operations);
+	if (old_mac_op == efx->mac_op)
+		return 0;
+
+	WARN_ON(!mutex_is_locked(&efx->mac_lock));
+
+	/* Not all macs support a mac-level link state */
+	efx->mac_up = true;
+
+	falcon_read(efx, &nic_stat, NIC_STAT_REG);
+	strap_val = EFX_IS10G(efx) ? 5 : 3;
+	if (falcon_rev(efx) >= FALCON_REV_B0) {
+		EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_EN, 1);
+		EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_OVR, strap_val);
+		falcon_write(efx, &nic_stat, NIC_STAT_REG);
+	} else {
+		/* Falcon A1 does not support 1G/10G speed switching
+		 * and must not be used with a PHY that does. */
+		BUG_ON(EFX_OWORD_FIELD(nic_stat, STRAP_PINS) != strap_val);
+	}
+
+
+	EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
+	return falcon_reset_macs(efx);
+}
+
 /* This call is responsible for hooking in the MAC and PHY operations */
 int falcon_probe_port(struct efx_nic *efx)
 {
@@ -2194,9 +2330,9 @@
 
 	/* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
 	if (falcon_rev(efx) >= FALCON_REV_B0)
-		efx->flow_control = EFX_FC_RX | EFX_FC_TX;
+		efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
 	else
-		efx->flow_control = EFX_FC_RX;
+		efx->wanted_fc = EFX_FC_RX;
 
 	/* Allocate buffer for stats */
 	rc = falcon_alloc_buffer(efx, &efx->stats_buffer,
@@ -2253,13 +2389,18 @@
 	__le16 *word, *limit;
 	u32 csum;
 
-	region = kmalloc(NVCONFIG_END, GFP_KERNEL);
+	spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom;
+	if (!spi)
+		return -EINVAL;
+
+	region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL);
 	if (!region)
 		return -ENOMEM;
 	nvconfig = region + NVCONFIG_OFFSET;
 
-	spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom;
-	rc = falcon_spi_read(spi, 0, NVCONFIG_END, NULL, region);
+	mutex_lock(&efx->spi_lock);
+	rc = falcon_spi_read(spi, 0, FALCON_NVCONFIG_END, NULL, region);
+	mutex_unlock(&efx->spi_lock);
 	if (rc) {
 		EFX_ERR(efx, "Failed to read %s\n",
 			efx->spi_flash ? "flash" : "EEPROM");
@@ -2283,7 +2424,7 @@
 		limit = (__le16 *) (nvconfig + 1);
 	} else {
 		word = region;
-		limit = region + NVCONFIG_END;
+		limit = region + FALCON_NVCONFIG_END;
 	}
 	for (csum = 0; word < limit; ++word)
 		csum += le16_to_cpu(*word);
@@ -2325,6 +2466,10 @@
 	  EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) },
 	{ DP_CTRL_REG,
 	  EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) },
+	{ GM_CFG2_REG,
+	  EFX_OWORD32(0x00007337, 0x00000000, 0x00000000, 0x00000000) },
+	{ GMF_CFG0_REG,
+	  EFX_OWORD32(0x00001F1F, 0x00000000, 0x00000000, 0x00000000) },
 	{ XM_GLB_CFG_REG,
 	  EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) },
 	{ XM_TX_CFG_REG,
@@ -2545,7 +2690,7 @@
 	struct efx_spi_device *spi_device;
 
 	if (device_type != 0) {
-		spi_device = kmalloc(sizeof(*spi_device), GFP_KERNEL);
+		spi_device = kzalloc(sizeof(*spi_device), GFP_KERNEL);
 		if (!spi_device)
 			return -ENOMEM;
 		spi_device->device_id = device_id;
@@ -2555,6 +2700,11 @@
 			SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN);
 		spi_device->munge_address = (spi_device->size == 1 << 9 &&
 					     spi_device->addr_len == 1);
+		spi_device->erase_command =
+			SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ERASE_CMD);
+		spi_device->erase_size =
+			1 << SPI_DEV_TYPE_FIELD(device_type,
+						SPI_DEV_TYPE_ERASE_SIZE);
 		spi_device->block_size =
 			1 << SPI_DEV_TYPE_FIELD(device_type,
 						SPI_DEV_TYPE_BLOCK_SIZE);
@@ -2645,6 +2795,7 @@
 static int falcon_probe_nic_variant(struct efx_nic *efx)
 {
 	efx_oword_t altera_build;
+	efx_oword_t nic_stat;
 
 	falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER);
 	if (EFX_OWORD_FIELD(altera_build, VER_ALL)) {
@@ -2652,27 +2803,20 @@
 		return -ENODEV;
 	}
 
+	falcon_read(efx, &nic_stat, NIC_STAT_REG);
+
 	switch (falcon_rev(efx)) {
 	case FALCON_REV_A0:
 	case 0xff:
 		EFX_ERR(efx, "Falcon rev A0 not supported\n");
 		return -ENODEV;
 
-	case FALCON_REV_A1:{
-		efx_oword_t nic_stat;
-
-		falcon_read(efx, &nic_stat, NIC_STAT_REG);
-
+	case FALCON_REV_A1:
 		if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) {
 			EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
 			return -ENODEV;
 		}
-		if (!EFX_OWORD_FIELD(nic_stat, STRAP_10G)) {
-			EFX_ERR(efx, "1G mode not supported\n");
-			return -ENODEV;
-		}
 		break;
-	}
 
 	case FALCON_REV_B0:
 		break;
@@ -2682,6 +2826,9 @@
 		return -ENODEV;
 	}
 
+	/* Initial assumed speed */
+	efx->link_speed = EFX_OWORD_FIELD(nic_stat, STRAP_10G) ? 10000 : 1000;
+
 	return 0;
 }
 
@@ -2689,80 +2836,37 @@
 static void falcon_probe_spi_devices(struct efx_nic *efx)
 {
 	efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
-	bool has_flash, has_eeprom, boot_is_external;
+	int boot_dev;
 
 	falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER);
 	falcon_read(efx, &nic_stat, NIC_STAT_REG);
 	falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
 
-	has_flash = EFX_OWORD_FIELD(nic_stat, SF_PRST);
-	has_eeprom = EFX_OWORD_FIELD(nic_stat, EE_PRST);
-	boot_is_external = EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE);
-
-	if (has_flash) {
-		/* Default flash SPI device: Atmel AT25F1024
-		 * 128 KB, 24-bit address, 32 KB erase block,
-		 * 256 B write block
-		 */
-		u32 flash_device_type =
-			(17 << SPI_DEV_TYPE_SIZE_LBN)
-			| (3 << SPI_DEV_TYPE_ADDR_LEN_LBN)
-			| (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN)
-			| (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN)
-			| (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
-
-		falcon_spi_device_init(efx, &efx->spi_flash,
-				       EE_SPI_FLASH, flash_device_type);
-
-		if (!boot_is_external) {
-			/* Disable VPD and set clock dividers to safe
-			 * values for initial programming.
-			 */
-			EFX_LOG(efx, "Booted from internal ASIC settings;"
-				" setting SPI config\n");
-			EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0,
-					     /* 125 MHz / 7 ~= 20 MHz */
-					     EE_SF_CLOCK_DIV, 7,
-					     /* 125 MHz / 63 ~= 2 MHz */
-					     EE_EE_CLOCK_DIV, 63);
-			falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
-		}
+	if (EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE)) {
+		boot_dev = (EFX_OWORD_FIELD(nic_stat, SF_PRST) ?
+			    EE_SPI_FLASH : EE_SPI_EEPROM);
+		EFX_LOG(efx, "Booted from %s\n",
+			boot_dev == EE_SPI_FLASH ? "flash" : "EEPROM");
+	} else {
+		/* Disable VPD and set clock dividers to safe
+		 * values for initial programming. */
+		boot_dev = -1;
+		EFX_LOG(efx, "Booted from internal ASIC settings;"
+			" setting SPI config\n");
+		EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0,
+				     /* 125 MHz / 7 ~= 20 MHz */
+				     EE_SF_CLOCK_DIV, 7,
+				     /* 125 MHz / 63 ~= 2 MHz */
+				     EE_EE_CLOCK_DIV, 63);
+		falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
 	}
 
-	if (has_eeprom) {
-		u32 eeprom_device_type;
-
-		/* If it has no flash, it must have a large EEPROM
-		 * for chip config; otherwise check whether 9-bit
-		 * addressing is used for VPD configuration
-		 */
-		if (has_flash &&
-		    (!boot_is_external ||
-		     EFX_OWORD_FIELD(ee_vpd_cfg, EE_VPD_EN_AD9_MODE))) {
-			/* Default SPI device: Atmel AT25040 or similar
-			 * 512 B, 9-bit address, 8 B write block
-			 */
-			eeprom_device_type =
-				(9 << SPI_DEV_TYPE_SIZE_LBN)
-				| (1 << SPI_DEV_TYPE_ADDR_LEN_LBN)
-				| (3 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
-		} else {
-			/* "Large" SPI device: Atmel AT25640 or similar
-			 * 8 KB, 16-bit address, 32 B write block
-			 */
-			eeprom_device_type =
-				(13 << SPI_DEV_TYPE_SIZE_LBN)
-				| (2 << SPI_DEV_TYPE_ADDR_LEN_LBN)
-				| (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
-		}
-
-		falcon_spi_device_init(efx, &efx->spi_eeprom,
-				       EE_SPI_EEPROM, eeprom_device_type);
-	}
-
-	EFX_LOG(efx, "flash is %s, EEPROM is %s\n",
-		(has_flash ? "present" : "absent"),
-		(has_eeprom ? "present" : "absent"));
+	if (boot_dev == EE_SPI_FLASH)
+		falcon_spi_device_init(efx, &efx->spi_flash, EE_SPI_FLASH,
+				       default_flash_type);
+	if (boot_dev == EE_SPI_EEPROM)
+		falcon_spi_device_init(efx, &efx->spi_eeprom, EE_SPI_EEPROM,
+				       large_eeprom_type);
 }
 
 int falcon_probe_nic(struct efx_nic *efx)
@@ -2825,10 +2929,10 @@
 		goto fail5;
 
 	/* Initialise I2C adapter */
- 	efx->i2c_adap.owner = THIS_MODULE;
+	efx->i2c_adap.owner = THIS_MODULE;
 	nic_data->i2c_data = falcon_i2c_bit_operations;
 	nic_data->i2c_data.data = efx;
- 	efx->i2c_adap.algo_data = &nic_data->i2c_data;
+	efx->i2c_adap.algo_data = &nic_data->i2c_data;
 	efx->i2c_adap.dev.parent = &efx->pci_dev->dev;
 	strlcpy(efx->i2c_adap.name, "SFC4000 GPIO", sizeof(efx->i2c_adap.name));
 	rc = i2c_bit_add_bus(&efx->i2c_adap);
@@ -2862,20 +2966,18 @@
 	unsigned thresh;
 	int rc;
 
-	/* Set up the address region register. This is only needed
-	 * for the B0 FPGA, but since we are just pushing in the
-	 * reset defaults this may as well be unconditional. */
-	EFX_POPULATE_OWORD_4(temp, ADR_REGION0, 0,
-				   ADR_REGION1, (1 << 16),
-				   ADR_REGION2, (2 << 16),
-				   ADR_REGION3, (3 << 16));
-	falcon_write(efx, &temp, ADR_REGION_REG_KER);
-
 	/* Use on-chip SRAM */
 	falcon_read(efx, &temp, NIC_STAT_REG);
 	EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1);
 	falcon_write(efx, &temp, NIC_STAT_REG);
 
+	/* Set the source of the GMAC clock */
+	if (falcon_rev(efx) == FALCON_REV_B0) {
+		falcon_read(efx, &temp, GPIO_CTL_REG_KER);
+		EFX_SET_OWORD_FIELD(temp, GPIO_USE_NIC_CLK, true);
+		falcon_write(efx, &temp, GPIO_CTL_REG_KER);
+	}
+
 	/* Set buffer table mode */
 	EFX_POPULATE_OWORD_1(temp, BUF_TBL_MODE, BUF_TBL_MODE_FULL);
 	falcon_write(efx, &temp, BUF_TBL_CFG_REG_KER);
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index be025ba..7869c3d 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -12,6 +12,7 @@
 #define EFX_FALCON_H
 
 #include "net_driver.h"
+#include "efx.h"
 
 /*
  * Falcon hardware control
@@ -65,6 +66,7 @@
 extern void falcon_remove_port(struct efx_nic *efx);
 
 /* MAC/PHY */
+extern int falcon_switch_mac(struct efx_nic *efx);
 extern bool falcon_xaui_link_ok(struct efx_nic *efx);
 extern int falcon_dma_stats(struct efx_nic *efx,
 			    unsigned int done_offset);
@@ -77,6 +79,7 @@
 extern void falcon_enable_interrupts(struct efx_nic *efx);
 extern void falcon_generate_test_event(struct efx_channel *channel,
 				       unsigned int magic);
+extern void falcon_sim_phy_event(struct efx_nic *efx);
 extern void falcon_generate_interrupt(struct efx_nic *efx);
 extern void falcon_set_int_moderation(struct efx_channel *channel);
 extern void falcon_disable_interrupts(struct efx_nic *efx);
diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c
new file mode 100644
index 0000000..8865eae
--- /dev/null
+++ b/drivers/net/sfc/falcon_gmac.c
@@ -0,0 +1,229 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/delay.h>
+#include "net_driver.h"
+#include "efx.h"
+#include "falcon.h"
+#include "mac.h"
+#include "falcon_hwdefs.h"
+#include "falcon_io.h"
+#include "gmii.h"
+
+/**************************************************************************
+ *
+ * MAC operations
+ *
+ *************************************************************************/
+
+static void falcon_reconfigure_gmac(struct efx_nic *efx)
+{
+	bool loopback, tx_fc, rx_fc, bytemode;
+	int if_mode;
+	unsigned int max_frame_len;
+	efx_oword_t reg;
+
+	/* Configuration register 1 */
+	tx_fc = (efx->link_fc & EFX_FC_TX) || !efx->link_fd;
+	rx_fc = !!(efx->link_fc & EFX_FC_RX);
+	loopback = (efx->loopback_mode == LOOPBACK_GMAC);
+	bytemode = (efx->link_speed == 1000);
+
+	EFX_POPULATE_OWORD_5(reg,
+			     GM_LOOP, loopback,
+			     GM_TX_EN, 1,
+			     GM_TX_FC_EN, tx_fc,
+			     GM_RX_EN, 1,
+			     GM_RX_FC_EN, rx_fc);
+	falcon_write(efx, &reg, GM_CFG1_REG);
+	udelay(10);
+
+	/* Configuration register 2 */
+	if_mode = (bytemode) ? 2 : 1;
+	EFX_POPULATE_OWORD_5(reg,
+			     GM_IF_MODE, if_mode,
+			     GM_PAD_CRC_EN, 1,
+			     GM_LEN_CHK, 1,
+			     GM_FD, efx->link_fd,
+			     GM_PAMBL_LEN, 0x7/*datasheet recommended */);
+
+	falcon_write(efx, &reg, GM_CFG2_REG);
+	udelay(10);
+
+	/* Max frame len register */
+	max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
+	EFX_POPULATE_OWORD_1(reg, GM_MAX_FLEN, max_frame_len);
+	falcon_write(efx, &reg, GM_MAX_FLEN_REG);
+	udelay(10);
+
+	/* FIFO configuration register 0 */
+	EFX_POPULATE_OWORD_5(reg,
+			     GMF_FTFENREQ, 1,
+			     GMF_STFENREQ, 1,
+			     GMF_FRFENREQ, 1,
+			     GMF_SRFENREQ, 1,
+			     GMF_WTMENREQ, 1);
+	falcon_write(efx, &reg, GMF_CFG0_REG);
+	udelay(10);
+
+	/* FIFO configuration register 1 */
+	EFX_POPULATE_OWORD_2(reg,
+			     GMF_CFGFRTH, 0x12,
+			     GMF_CFGXOFFRTX, 0xffff);
+	falcon_write(efx, &reg, GMF_CFG1_REG);
+	udelay(10);
+
+	/* FIFO configuration register 2 */
+	EFX_POPULATE_OWORD_2(reg,
+			     GMF_CFGHWM, 0x3f,
+			     GMF_CFGLWM, 0xa);
+	falcon_write(efx, &reg, GMF_CFG2_REG);
+	udelay(10);
+
+	/* FIFO configuration register 3 */
+	EFX_POPULATE_OWORD_2(reg,
+			     GMF_CFGHWMFT, 0x1c,
+			     GMF_CFGFTTH, 0x08);
+	falcon_write(efx, &reg, GMF_CFG3_REG);
+	udelay(10);
+
+	/* FIFO configuration register 4 */
+	EFX_POPULATE_OWORD_1(reg, GMF_HSTFLTRFRM_PAUSE, 1);
+	falcon_write(efx, &reg, GMF_CFG4_REG);
+	udelay(10);
+
+	/* FIFO configuration register 5 */
+	falcon_read(efx, &reg, GMF_CFG5_REG);
+	EFX_SET_OWORD_FIELD(reg, GMF_CFGBYTMODE, bytemode);
+	EFX_SET_OWORD_FIELD(reg, GMF_CFGHDPLX, !efx->link_fd);
+	EFX_SET_OWORD_FIELD(reg, GMF_HSTDRPLT64, !efx->link_fd);
+	EFX_SET_OWORD_FIELD(reg, GMF_HSTFLTRFRMDC_PAUSE, 0);
+	falcon_write(efx, &reg, GMF_CFG5_REG);
+	udelay(10);
+
+	/* MAC address */
+	EFX_POPULATE_OWORD_4(reg,
+			     GM_HWADDR_5, efx->net_dev->dev_addr[5],
+			     GM_HWADDR_4, efx->net_dev->dev_addr[4],
+			     GM_HWADDR_3, efx->net_dev->dev_addr[3],
+			     GM_HWADDR_2, efx->net_dev->dev_addr[2]);
+	falcon_write(efx, &reg, GM_ADR1_REG);
+	udelay(10);
+	EFX_POPULATE_OWORD_2(reg,
+			     GM_HWADDR_1, efx->net_dev->dev_addr[1],
+			     GM_HWADDR_0, efx->net_dev->dev_addr[0]);
+	falcon_write(efx, &reg, GM_ADR2_REG);
+	udelay(10);
+
+	falcon_reconfigure_mac_wrapper(efx);
+}
+
+static void falcon_update_stats_gmac(struct efx_nic *efx)
+{
+	struct efx_mac_stats *mac_stats = &efx->mac_stats;
+	unsigned long old_rx_pause, old_tx_pause;
+	unsigned long new_rx_pause, new_tx_pause;
+	int rc;
+
+	rc = falcon_dma_stats(efx, GDmaDone_offset);
+	if (rc)
+		return;
+
+	/* Pause frames are erroneously counted as errors (SFC bug 3269) */
+	old_rx_pause = mac_stats->rx_pause;
+	old_tx_pause = mac_stats->tx_pause;
+
+	/* Update MAC stats from DMAed values */
+	FALCON_STAT(efx, GRxGoodOct, rx_good_bytes);
+	FALCON_STAT(efx, GRxBadOct, rx_bad_bytes);
+	FALCON_STAT(efx, GRxMissPkt, rx_missed);
+	FALCON_STAT(efx, GRxFalseCRS, rx_false_carrier);
+	FALCON_STAT(efx, GRxPausePkt, rx_pause);
+	FALCON_STAT(efx, GRxBadPkt, rx_bad);
+	FALCON_STAT(efx, GRxUcastPkt, rx_unicast);
+	FALCON_STAT(efx, GRxMcastPkt, rx_multicast);
+	FALCON_STAT(efx, GRxBcastPkt, rx_broadcast);
+	FALCON_STAT(efx, GRxGoodLt64Pkt, rx_good_lt64);
+	FALCON_STAT(efx, GRxBadLt64Pkt, rx_bad_lt64);
+	FALCON_STAT(efx, GRx64Pkt, rx_64);
+	FALCON_STAT(efx, GRx65to127Pkt, rx_65_to_127);
+	FALCON_STAT(efx, GRx128to255Pkt, rx_128_to_255);
+	FALCON_STAT(efx, GRx256to511Pkt, rx_256_to_511);
+	FALCON_STAT(efx, GRx512to1023Pkt, rx_512_to_1023);
+	FALCON_STAT(efx, GRx1024to15xxPkt, rx_1024_to_15xx);
+	FALCON_STAT(efx, GRx15xxtoJumboPkt, rx_15xx_to_jumbo);
+	FALCON_STAT(efx, GRxGtJumboPkt, rx_gtjumbo);
+	FALCON_STAT(efx, GRxFcsErr64to15xxPkt, rx_bad_64_to_15xx);
+	FALCON_STAT(efx, GRxFcsErr15xxtoJumboPkt, rx_bad_15xx_to_jumbo);
+	FALCON_STAT(efx, GRxFcsErrGtJumboPkt, rx_bad_gtjumbo);
+	FALCON_STAT(efx, GTxGoodBadOct, tx_bytes);
+	FALCON_STAT(efx, GTxGoodOct, tx_good_bytes);
+	FALCON_STAT(efx, GTxSglColPkt, tx_single_collision);
+	FALCON_STAT(efx, GTxMultColPkt, tx_multiple_collision);
+	FALCON_STAT(efx, GTxExColPkt, tx_excessive_collision);
+	FALCON_STAT(efx, GTxDefPkt, tx_deferred);
+	FALCON_STAT(efx, GTxLateCol, tx_late_collision);
+	FALCON_STAT(efx, GTxExDefPkt, tx_excessive_deferred);
+	FALCON_STAT(efx, GTxPausePkt, tx_pause);
+	FALCON_STAT(efx, GTxBadPkt, tx_bad);
+	FALCON_STAT(efx, GTxUcastPkt, tx_unicast);
+	FALCON_STAT(efx, GTxMcastPkt, tx_multicast);
+	FALCON_STAT(efx, GTxBcastPkt, tx_broadcast);
+	FALCON_STAT(efx, GTxLt64Pkt, tx_lt64);
+	FALCON_STAT(efx, GTx64Pkt, tx_64);
+	FALCON_STAT(efx, GTx65to127Pkt, tx_65_to_127);
+	FALCON_STAT(efx, GTx128to255Pkt, tx_128_to_255);
+	FALCON_STAT(efx, GTx256to511Pkt, tx_256_to_511);
+	FALCON_STAT(efx, GTx512to1023Pkt, tx_512_to_1023);
+	FALCON_STAT(efx, GTx1024to15xxPkt, tx_1024_to_15xx);
+	FALCON_STAT(efx, GTx15xxtoJumboPkt, tx_15xx_to_jumbo);
+	FALCON_STAT(efx, GTxGtJumboPkt, tx_gtjumbo);
+	FALCON_STAT(efx, GTxNonTcpUdpPkt, tx_non_tcpudp);
+	FALCON_STAT(efx, GTxMacSrcErrPkt, tx_mac_src_error);
+	FALCON_STAT(efx, GTxIpSrcErrPkt, tx_ip_src_error);
+
+	/* Pause frames are erroneously counted as errors (SFC bug 3269) */
+	new_rx_pause = mac_stats->rx_pause;
+	new_tx_pause = mac_stats->tx_pause;
+	mac_stats->rx_bad -= (new_rx_pause - old_rx_pause);
+	mac_stats->tx_bad -= (new_tx_pause - old_tx_pause);
+
+	/* Derive stats that the MAC doesn't provide directly */
+	mac_stats->tx_bad_bytes =
+		mac_stats->tx_bytes - mac_stats->tx_good_bytes;
+	mac_stats->tx_packets =
+		mac_stats->tx_lt64 + mac_stats->tx_64 +
+		mac_stats->tx_65_to_127 + mac_stats->tx_128_to_255 +
+		mac_stats->tx_256_to_511 + mac_stats->tx_512_to_1023 +
+		mac_stats->tx_1024_to_15xx + mac_stats->tx_15xx_to_jumbo +
+		mac_stats->tx_gtjumbo;
+	mac_stats->tx_collision =
+		mac_stats->tx_single_collision +
+		mac_stats->tx_multiple_collision +
+		mac_stats->tx_excessive_collision +
+		mac_stats->tx_late_collision;
+	mac_stats->rx_bytes =
+		mac_stats->rx_good_bytes + mac_stats->rx_bad_bytes;
+	mac_stats->rx_packets =
+		mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64 +
+		mac_stats->rx_64 + mac_stats->rx_65_to_127 +
+		mac_stats->rx_128_to_255 + mac_stats->rx_256_to_511 +
+		mac_stats->rx_512_to_1023 + mac_stats->rx_1024_to_15xx +
+		mac_stats->rx_15xx_to_jumbo + mac_stats->rx_gtjumbo;
+	mac_stats->rx_good = mac_stats->rx_packets - mac_stats->rx_bad;
+	mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64;
+}
+
+struct efx_mac_operations falcon_gmac_operations = {
+	.reconfigure	= falcon_reconfigure_gmac,
+	.update_stats	= falcon_update_stats_gmac,
+	.irq		= efx_port_dummy_op_void,
+	.poll		= efx_port_dummy_op_void,
+};
diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h
index 5d584b0..bda8d5b 100644
--- a/drivers/net/sfc/falcon_hwdefs.h
+++ b/drivers/net/sfc/falcon_hwdefs.h
@@ -111,12 +111,18 @@
 
 /* NIC status register */
 #define NIC_STAT_REG 0x0200
+#define EE_STRAP_EN_LBN 31
+#define EE_STRAP_EN_WIDTH 1
+#define EE_STRAP_OVR_LBN 24
+#define EE_STRAP_OVR_WIDTH 4
 #define ONCHIP_SRAM_LBN 16
 #define ONCHIP_SRAM_WIDTH 1
 #define SF_PRST_LBN 9
 #define SF_PRST_WIDTH 1
 #define EE_PRST_LBN 8
 #define EE_PRST_WIDTH 1
+#define STRAP_PINS_LBN 0
+#define STRAP_PINS_WIDTH 3
 /* These bit definitions are extrapolated from the list of numerical
  * values for STRAP_PINS.
  */
@@ -130,6 +136,8 @@
 
 /* GPIO control register */
 #define GPIO_CTL_REG_KER 0x0210
+#define GPIO_USE_NIC_CLK_LBN (30)
+#define GPIO_USE_NIC_CLK_WIDTH (1)
 #define GPIO_OUTPUTS_LBN   (16)
 #define GPIO_OUTPUTS_WIDTH (4)
 #define GPIO_INPUTS_LBN (8)
@@ -492,6 +500,107 @@
 #define MAC_MCAST_HASH_REG0_KER 0xca0
 #define MAC_MCAST_HASH_REG1_KER 0xcb0
 
+/* GMAC configuration register 1 */
+#define GM_CFG1_REG 0xe00
+#define GM_SW_RST_LBN 31
+#define GM_SW_RST_WIDTH 1
+#define GM_LOOP_LBN 8
+#define GM_LOOP_WIDTH 1
+#define GM_RX_FC_EN_LBN 5
+#define GM_RX_FC_EN_WIDTH 1
+#define GM_TX_FC_EN_LBN 4
+#define GM_TX_FC_EN_WIDTH 1
+#define GM_RX_EN_LBN 2
+#define GM_RX_EN_WIDTH 1
+#define GM_TX_EN_LBN 0
+#define GM_TX_EN_WIDTH 1
+
+/* GMAC configuration register 2 */
+#define GM_CFG2_REG 0xe10
+#define GM_PAMBL_LEN_LBN 12
+#define GM_PAMBL_LEN_WIDTH 4
+#define GM_IF_MODE_LBN 8
+#define GM_IF_MODE_WIDTH 2
+#define GM_LEN_CHK_LBN 4
+#define GM_LEN_CHK_WIDTH 1
+#define GM_PAD_CRC_EN_LBN 2
+#define GM_PAD_CRC_EN_WIDTH 1
+#define GM_FD_LBN 0
+#define GM_FD_WIDTH 1
+
+/* GMAC maximum frame length register */
+#define GM_MAX_FLEN_REG 0xe40
+#define GM_MAX_FLEN_LBN 0
+#define GM_MAX_FLEN_WIDTH 16
+
+/* GMAC station address register 1 */
+#define GM_ADR1_REG 0xf00
+#define GM_HWADDR_5_LBN 24
+#define GM_HWADDR_5_WIDTH 8
+#define GM_HWADDR_4_LBN 16
+#define GM_HWADDR_4_WIDTH 8
+#define GM_HWADDR_3_LBN 8
+#define GM_HWADDR_3_WIDTH 8
+#define GM_HWADDR_2_LBN 0
+#define GM_HWADDR_2_WIDTH 8
+
+/* GMAC station address register 2 */
+#define GM_ADR2_REG 0xf10
+#define GM_HWADDR_1_LBN 24
+#define GM_HWADDR_1_WIDTH 8
+#define GM_HWADDR_0_LBN 16
+#define GM_HWADDR_0_WIDTH 8
+
+/* GMAC FIFO configuration register 0 */
+#define GMF_CFG0_REG 0xf20
+#define GMF_FTFENREQ_LBN 12
+#define GMF_FTFENREQ_WIDTH 1
+#define GMF_STFENREQ_LBN 11
+#define GMF_STFENREQ_WIDTH 1
+#define GMF_FRFENREQ_LBN 10
+#define GMF_FRFENREQ_WIDTH 1
+#define GMF_SRFENREQ_LBN 9
+#define GMF_SRFENREQ_WIDTH 1
+#define GMF_WTMENREQ_LBN 8
+#define GMF_WTMENREQ_WIDTH 1
+
+/* GMAC FIFO configuration register 1 */
+#define GMF_CFG1_REG 0xf30
+#define GMF_CFGFRTH_LBN 16
+#define GMF_CFGFRTH_WIDTH 5
+#define GMF_CFGXOFFRTX_LBN 0
+#define GMF_CFGXOFFRTX_WIDTH 16
+
+/* GMAC FIFO configuration register 2 */
+#define GMF_CFG2_REG 0xf40
+#define GMF_CFGHWM_LBN 16
+#define GMF_CFGHWM_WIDTH 6
+#define GMF_CFGLWM_LBN 0
+#define GMF_CFGLWM_WIDTH 6
+
+/* GMAC FIFO configuration register 3 */
+#define GMF_CFG3_REG 0xf50
+#define GMF_CFGHWMFT_LBN 16
+#define GMF_CFGHWMFT_WIDTH 6
+#define GMF_CFGFTTH_LBN 0
+#define GMF_CFGFTTH_WIDTH 6
+
+/* GMAC FIFO configuration register 4 */
+#define GMF_CFG4_REG 0xf60
+#define GMF_HSTFLTRFRM_PAUSE_LBN 12
+#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
+
+/* GMAC FIFO configuration register 5 */
+#define GMF_CFG5_REG 0xf70
+#define GMF_CFGHDPLX_LBN 22
+#define GMF_CFGHDPLX_WIDTH 1
+#define GMF_CFGBYTMODE_LBN 19
+#define GMF_CFGBYTMODE_WIDTH 1
+#define GMF_HSTDRPLT64_LBN 18
+#define GMF_HSTDRPLT64_WIDTH 1
+#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
+#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
+
 /* XGMAC address register low */
 #define XM_ADR_LO_REG 0x1200
 #define XM_ADR_3_LBN 24
@@ -944,6 +1053,8 @@
 #define XG_MNT_INTR_B0_WIDTH 1
 #define RX_RECOVERY_A1_LBN 11
 #define RX_RECOVERY_A1_WIDTH 1
+#define XFP_PHY_INTR_LBN 10
+#define XFP_PHY_INTR_WIDTH 1
 #define XG_PHY_INTR_LBN 9
 #define XG_PHY_INTR_WIDTH 1
 #define G_PHY1_INTR_LBN 8
@@ -962,54 +1073,103 @@
  **************************************************************************
  *
  */
+
 #define GRxGoodOct_offset 0x0
+#define GRxGoodOct_WIDTH 48
 #define GRxBadOct_offset 0x8
+#define GRxBadOct_WIDTH 48
 #define GRxMissPkt_offset 0x10
+#define GRxMissPkt_WIDTH 32
 #define GRxFalseCRS_offset 0x14
+#define GRxFalseCRS_WIDTH 32
 #define GRxPausePkt_offset 0x18
+#define GRxPausePkt_WIDTH 32
 #define GRxBadPkt_offset 0x1C
+#define GRxBadPkt_WIDTH 32
 #define GRxUcastPkt_offset 0x20
+#define GRxUcastPkt_WIDTH 32
 #define GRxMcastPkt_offset 0x24
+#define GRxMcastPkt_WIDTH 32
 #define GRxBcastPkt_offset 0x28
+#define GRxBcastPkt_WIDTH 32
 #define GRxGoodLt64Pkt_offset 0x2C
+#define GRxGoodLt64Pkt_WIDTH 32
 #define GRxBadLt64Pkt_offset 0x30
+#define GRxBadLt64Pkt_WIDTH 32
 #define GRx64Pkt_offset 0x34
+#define GRx64Pkt_WIDTH 32
 #define GRx65to127Pkt_offset 0x38
+#define GRx65to127Pkt_WIDTH 32
 #define GRx128to255Pkt_offset 0x3C
+#define GRx128to255Pkt_WIDTH 32
 #define GRx256to511Pkt_offset 0x40
+#define GRx256to511Pkt_WIDTH 32
 #define GRx512to1023Pkt_offset 0x44
+#define GRx512to1023Pkt_WIDTH 32
 #define GRx1024to15xxPkt_offset 0x48
+#define GRx1024to15xxPkt_WIDTH 32
 #define GRx15xxtoJumboPkt_offset 0x4C
+#define GRx15xxtoJumboPkt_WIDTH 32
 #define GRxGtJumboPkt_offset 0x50
+#define GRxGtJumboPkt_WIDTH 32
 #define GRxFcsErr64to15xxPkt_offset 0x54
+#define GRxFcsErr64to15xxPkt_WIDTH 32
 #define GRxFcsErr15xxtoJumboPkt_offset 0x58
+#define GRxFcsErr15xxtoJumboPkt_WIDTH 32
 #define GRxFcsErrGtJumboPkt_offset 0x5C
+#define GRxFcsErrGtJumboPkt_WIDTH 32
 #define GTxGoodBadOct_offset 0x80
+#define GTxGoodBadOct_WIDTH 48
 #define GTxGoodOct_offset 0x88
+#define GTxGoodOct_WIDTH 48
 #define GTxSglColPkt_offset 0x90
+#define GTxSglColPkt_WIDTH 32
 #define GTxMultColPkt_offset 0x94
+#define GTxMultColPkt_WIDTH 32
 #define GTxExColPkt_offset 0x98
+#define GTxExColPkt_WIDTH 32
 #define GTxDefPkt_offset 0x9C
+#define GTxDefPkt_WIDTH 32
 #define GTxLateCol_offset 0xA0
+#define GTxLateCol_WIDTH 32
 #define GTxExDefPkt_offset 0xA4
+#define GTxExDefPkt_WIDTH 32
 #define GTxPausePkt_offset 0xA8
+#define GTxPausePkt_WIDTH 32
 #define GTxBadPkt_offset 0xAC
+#define GTxBadPkt_WIDTH 32
 #define GTxUcastPkt_offset 0xB0
+#define GTxUcastPkt_WIDTH 32
 #define GTxMcastPkt_offset 0xB4
+#define GTxMcastPkt_WIDTH 32
 #define GTxBcastPkt_offset 0xB8
+#define GTxBcastPkt_WIDTH 32
 #define GTxLt64Pkt_offset 0xBC
+#define GTxLt64Pkt_WIDTH 32
 #define GTx64Pkt_offset 0xC0
+#define GTx64Pkt_WIDTH 32
 #define GTx65to127Pkt_offset 0xC4
+#define GTx65to127Pkt_WIDTH 32
 #define GTx128to255Pkt_offset 0xC8
+#define GTx128to255Pkt_WIDTH 32
 #define GTx256to511Pkt_offset 0xCC
+#define GTx256to511Pkt_WIDTH 32
 #define GTx512to1023Pkt_offset 0xD0
+#define GTx512to1023Pkt_WIDTH 32
 #define GTx1024to15xxPkt_offset 0xD4
+#define GTx1024to15xxPkt_WIDTH 32
 #define GTx15xxtoJumboPkt_offset 0xD8
+#define GTx15xxtoJumboPkt_WIDTH 32
 #define GTxGtJumboPkt_offset 0xDC
+#define GTxGtJumboPkt_WIDTH 32
 #define GTxNonTcpUdpPkt_offset 0xE0
+#define GTxNonTcpUdpPkt_WIDTH 16
 #define GTxMacSrcErrPkt_offset 0xE4
+#define GTxMacSrcErrPkt_WIDTH 16
 #define GTxIpSrcErrPkt_offset 0xE8
+#define GTxIpSrcErrPkt_WIDTH 16
 #define GDmaDone_offset 0xEC
+#define GDmaDone_WIDTH 32
 
 #define XgRxOctets_offset 0x0
 #define XgRxOctets_WIDTH 48
@@ -1150,7 +1310,6 @@
 	(((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field)))
 
 #define NVCONFIG_OFFSET 0x300
-#define NVCONFIG_END 0x400
 
 #define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
 struct falcon_nvconfig {
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index d401231..5a03713 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -15,7 +15,6 @@
 #include "falcon_hwdefs.h"
 #include "falcon_io.h"
 #include "mac.h"
-#include "gmii.h"
 #include "mdio_10g.h"
 #include "phy.h"
 #include "boards.h"
@@ -26,24 +25,6 @@
  * MAC operations
  *
  *************************************************************************/
-static int falcon_reset_xmac(struct efx_nic *efx)
-{
-	efx_oword_t reg;
-	int count;
-
-	EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1);
-	falcon_write(efx, &reg, XM_GLB_CFG_REG);
-
-	for (count = 0; count < 10000; count++) {	/* wait upto 100ms */
-		falcon_read(efx, &reg, XM_GLB_CFG_REG);
-		if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0)
-			return 0;
-		udelay(10);
-	}
-
-	EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
-	return -ETIMEDOUT;
-}
 
 /* Configure the XAUI driver that is an output from Falcon */
 static void falcon_setup_xaui(struct efx_nic *efx)
@@ -99,31 +80,20 @@
 	return -ETIMEDOUT;
 }
 
-static bool falcon_xgmii_status(struct efx_nic *efx)
-{
-	efx_oword_t reg;
-
-	if (falcon_rev(efx) < FALCON_REV_B0)
-		return true;
-
-	/* The ISR latches, so clear it and re-read */
-	falcon_read(efx, &reg, XM_MGT_INT_REG_B0);
-	falcon_read(efx, &reg, XM_MGT_INT_REG_B0);
-
-	if (EFX_OWORD_FIELD(reg, XM_LCLFLT) ||
-	    EFX_OWORD_FIELD(reg, XM_RMTFLT)) {
-		EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg));
-		return false;
-	}
-
-	return true;
-}
-
 static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
 {
 	efx_oword_t reg;
 
-	if ((falcon_rev(efx) < FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
+	if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
+		return;
+
+	/* We expect xgmii faults if the wireside link is up */
+	if (!EFX_WORKAROUND_5147(efx) || !efx->link_up)
+		return;
+
+	/* We can only use this interrupt to signal the negative edge of
+	 * xaui_align [we have to poll the positive edge]. */
+	if (!efx->mac_up)
 		return;
 
 	/* Flush the ISR */
@@ -136,35 +106,7 @@
 	falcon_write(efx, &reg, XM_MGT_INT_MSK_REG_B0);
 }
 
-int falcon_init_xmac(struct efx_nic *efx)
-{
-	int rc;
-
-	/* Initialize the PHY first so the clock is around */
-	rc = efx->phy_op->init(efx);
-	if (rc)
-		goto fail1;
-
-	rc = falcon_reset_xaui(efx);
-	if (rc)
-		goto fail2;
-
-	/* Wait again. Give the PHY and MAC time to come back */
-	schedule_timeout_uninterruptible(HZ / 10);
-
-	rc = falcon_reset_xmac(efx);
-	if (rc)
-		goto fail2;
-
-	falcon_mask_status_intr(efx, true);
-	return 0;
-
- fail2:
-	efx->phy_op->fini(efx);
- fail1:
-	return rc;
-}
-
+/* Get status of XAUI link */
 bool falcon_xaui_link_ok(struct efx_nic *efx)
 {
 	efx_oword_t reg;
@@ -188,18 +130,10 @@
 	EFX_SET_OWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET);
 	falcon_write(efx, &reg, XX_CORE_STAT_REG);
 
-	/* If the link is up, then check the phy side of the xaui link
-	 * (error conditions from the wire side propoagate back through
-	 * the phy to the xaui side). */
-	if (efx->link_up && link_ok) {
+	/* If the link is up, then check the phy side of the xaui link */
+	if (efx->link_up && link_ok)
 		if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS))
 			link_ok = mdio_clause45_phyxgxs_lane_sync(efx);
-	}
-
-	/* If the PHY and XAUI links are up, then check the mac's xgmii
-	 * fault state */
-	if (efx->link_up && link_ok)
-		link_ok = falcon_xgmii_status(efx);
 
 	return link_ok;
 }
@@ -208,7 +142,7 @@
 {
 	unsigned int max_frame_len;
 	efx_oword_t reg;
-	bool rx_fc = !!(efx->flow_control & EFX_FC_RX);
+	bool rx_fc = !!(efx->link_fc & EFX_FC_RX);
 
 	/* Configure MAC  - cut-thru mode is hard wired on */
 	EFX_POPULATE_DWORD_3(reg,
@@ -311,70 +245,39 @@
 
 /* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
  * to come back up. Bash it until it comes back up */
-static bool falcon_check_xaui_link_up(struct efx_nic *efx)
+static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
 {
-	int max_tries, tries;
-	tries = EFX_WORKAROUND_5147(efx) ? 5 : 1;
-	max_tries = tries;
+	efx->mac_up = falcon_xaui_link_ok(efx);
 
 	if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
-	    (efx->phy_type == PHY_TYPE_NONE) ||
 	    efx_phy_mode_disabled(efx->phy_mode))
-		return false;
+		/* XAUI link is expected to be down */
+		return;
 
-	while (tries) {
-		if (falcon_xaui_link_ok(efx))
-			return true;
-
-		EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n",
-			__func__, tries);
+	while (!efx->mac_up && tries) {
+		EFX_LOG(efx, "bashing xaui\n");
 		falcon_reset_xaui(efx);
 		udelay(200);
-		tries--;
-	}
 
-	EFX_LOG(efx, "Failed to bring XAUI link back up in %d tries!\n",
-		max_tries);
-	return false;
+		efx->mac_up = falcon_xaui_link_ok(efx);
+		--tries;
+	}
 }
 
-void falcon_reconfigure_xmac(struct efx_nic *efx)
+static void falcon_reconfigure_xmac(struct efx_nic *efx)
 {
-	bool xaui_link_ok;
-
 	falcon_mask_status_intr(efx, false);
 
-	falcon_deconfigure_mac_wrapper(efx);
-
-	/* Reconfigure the PHY, disabling transmit in mac level loopback. */
-	if (LOOPBACK_INTERNAL(efx))
-		efx->phy_mode |= PHY_MODE_TX_DISABLED;
-	else
-		efx->phy_mode &= ~PHY_MODE_TX_DISABLED;
-	efx->phy_op->reconfigure(efx);
-
 	falcon_reconfigure_xgxs_core(efx);
 	falcon_reconfigure_xmac_core(efx);
 
 	falcon_reconfigure_mac_wrapper(efx);
 
-	/* Ensure XAUI link is up */
-	xaui_link_ok = falcon_check_xaui_link_up(efx);
-
-	if (xaui_link_ok && efx->link_up)
-		falcon_mask_status_intr(efx, true);
+	falcon_check_xaui_link_up(efx, 5);
+	falcon_mask_status_intr(efx, true);
 }
 
-void falcon_fini_xmac(struct efx_nic *efx)
-{
-	/* Isolate the MAC - PHY */
-	falcon_deconfigure_mac_wrapper(efx);
-
-	/* Potentially power down the PHY */
-	efx->phy_op->fini(efx);
-}
-
-void falcon_update_stats_xmac(struct efx_nic *efx)
+static void falcon_update_stats_xmac(struct efx_nic *efx)
 {
 	struct efx_mac_stats *mac_stats = &efx->mac_stats;
 	int rc;
@@ -439,97 +342,35 @@
 		 mac_stats->rx_control * 64);
 }
 
-int falcon_check_xmac(struct efx_nic *efx)
+static void falcon_xmac_irq(struct efx_nic *efx)
 {
-	bool xaui_link_ok;
-	int rc;
+	/* The XGMII link has a transient fault, which indicates either:
+	 *   - there's a transient xgmii fault
+	 *   - falcon's end of the xaui link may need a kick
+	 *   - the wire-side link may have gone down, but the lasi/poll()
+	 *     hasn't noticed yet.
+	 *
+	 * We only want to even bother polling XAUI if we're confident it's
+	 * not (1) or (3). In both cases, the only reliable way to spot this
+	 * is to wait a bit. We do this here by forcing the mac link state
+	 * to down, and waiting for the mac poll to come round and check
+	 */
+	efx->mac_up = false;
+}
 
-	if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
-	    efx_phy_mode_disabled(efx->phy_mode))
-		return 0;
+static void falcon_poll_xmac(struct efx_nic *efx)
+{
+	if (!EFX_WORKAROUND_5147(efx) || !efx->link_up || efx->mac_up)
+		return;
 
 	falcon_mask_status_intr(efx, false);
-	xaui_link_ok = falcon_xaui_link_ok(efx);
-
-	if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok)
-		falcon_reset_xaui(efx);
-
-	/* Call the PHY check_hw routine */
-	rc = efx->phy_op->check_hw(efx);
-
-	/* Unmask interrupt if everything was (and still is) ok */
-	if (xaui_link_ok && efx->link_up)
-		falcon_mask_status_intr(efx, true);
-
-	return rc;
+	falcon_check_xaui_link_up(efx, 1);
+	falcon_mask_status_intr(efx, true);
 }
 
-/* Simulate a PHY event */
-void falcon_xmac_sim_phy_event(struct efx_nic *efx)
-{
-	efx_qword_t phy_event;
-
-	EFX_POPULATE_QWORD_2(phy_event,
-			     EV_CODE, GLOBAL_EV_DECODE,
-			     XG_PHY_INTR, 1);
-	falcon_generate_event(&efx->channel[0], &phy_event);
-}
-
-int falcon_xmac_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
-{
-	mdio_clause45_get_settings(efx, ecmd);
-	ecmd->transceiver = XCVR_INTERNAL;
-	ecmd->phy_address = efx->mii.phy_id;
-	ecmd->autoneg = AUTONEG_DISABLE;
-	ecmd->duplex = DUPLEX_FULL;
-	return 0;
-}
-
-int falcon_xmac_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
-{
-	if (ecmd->transceiver != XCVR_INTERNAL)
-		return -EINVAL;
-	if (ecmd->autoneg != AUTONEG_DISABLE)
-		return -EINVAL;
-	if (ecmd->duplex != DUPLEX_FULL)
-		return -EINVAL;
-
-	return mdio_clause45_set_settings(efx, ecmd);
-}
-
-
-int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control)
-{
-	bool reset;
-
-	if (flow_control & EFX_FC_AUTO) {
-		EFX_LOG(efx, "10G does not support flow control "
-			"autonegotiation\n");
-		return -EINVAL;
-	}
-
-	if ((flow_control & EFX_FC_TX) && !(flow_control & EFX_FC_RX))
-		return -EINVAL;
-
-	/* TX flow control may automatically turn itself off if the
-	 * link partner (intermittently) stops responding to pause
-	 * frames. There isn't any indication that this has happened,
-	 * so the best we do is leave it up to the user to spot this
-	 * and fix it be cycling transmit flow control on this end. */
-	reset = ((flow_control & EFX_FC_TX) &&
-		 !(efx->flow_control & EFX_FC_TX));
-	if (EFX_WORKAROUND_11482(efx) && reset) {
-		if (falcon_rev(efx) >= FALCON_REV_B0) {
-			/* Recover by resetting the EM block */
-			if (efx->link_up)
-				falcon_drain_tx_fifo(efx);
-		} else {
-			/* Schedule a reset to recover */
-			efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
-		}
-	}
-
-	efx->flow_control = flow_control;
-
-	return 0;
-}
+struct efx_mac_operations falcon_xmac_operations = {
+	.reconfigure	= falcon_reconfigure_xmac,
+	.update_stats	= falcon_update_stats_xmac,
+	.irq		= falcon_xmac_irq,
+	.poll		= falcon_poll_xmac,
+};
diff --git a/drivers/net/sfc/gmii.h b/drivers/net/sfc/gmii.h
index d25bbd1..dfccaa7 100644
--- a/drivers/net/sfc/gmii.h
+++ b/drivers/net/sfc/gmii.h
@@ -1,7 +1,7 @@
 /****************************************************************************
  * Driver for Solarflare Solarstorm network controllers and boards
  * Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006 Solarflare Communications Inc.
+ * Copyright 2006-2008 Solarflare Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
@@ -57,139 +57,4 @@
 #define ISR_POLARITY_CHG	0x0002	/* Bit 1 - polarity changed */
 #define ISR_JABBER		0x0001	/* Bit 0 - jabber */
 
-/* Logically extended advertisement register */
-#define GM_ADVERTISE_SLCT		ADVERTISE_SLCT
-#define GM_ADVERTISE_CSMA		ADVERTISE_CSMA
-#define GM_ADVERTISE_10HALF		ADVERTISE_10HALF
-#define GM_ADVERTISE_1000XFULL		ADVERTISE_1000XFULL
-#define GM_ADVERTISE_10FULL		ADVERTISE_10FULL
-#define GM_ADVERTISE_1000XHALF		ADVERTISE_1000XHALF
-#define GM_ADVERTISE_100HALF		ADVERTISE_100HALF
-#define GM_ADVERTISE_1000XPAUSE		ADVERTISE_1000XPAUSE
-#define GM_ADVERTISE_100FULL		ADVERTISE_100FULL
-#define GM_ADVERTISE_1000XPSE_ASYM	ADVERTISE_1000XPSE_ASYM
-#define GM_ADVERTISE_100BASE4		ADVERTISE_100BASE4
-#define GM_ADVERTISE_PAUSE_CAP		ADVERTISE_PAUSE_CAP
-#define GM_ADVERTISE_PAUSE_ASYM		ADVERTISE_PAUSE_ASYM
-#define GM_ADVERTISE_RESV		ADVERTISE_RESV
-#define GM_ADVERTISE_RFAULT		ADVERTISE_RFAULT
-#define GM_ADVERTISE_LPACK		ADVERTISE_LPACK
-#define GM_ADVERTISE_NPAGE		ADVERTISE_NPAGE
-#define GM_ADVERTISE_1000FULL		(ADVERTISE_1000FULL << 8)
-#define GM_ADVERTISE_1000HALF		(ADVERTISE_1000HALF << 8)
-#define GM_ADVERTISE_1000		(GM_ADVERTISE_1000FULL | \
-					 GM_ADVERTISE_1000HALF)
-#define GM_ADVERTISE_FULL		(GM_ADVERTISE_1000FULL | \
-					 ADVERTISE_FULL)
-#define GM_ADVERTISE_ALL		(GM_ADVERTISE_1000FULL | \
-					 GM_ADVERTISE_1000HALF | \
-					 ADVERTISE_ALL)
-
-/* Logically extended link partner ability register */
-#define GM_LPA_SLCT			LPA_SLCT
-#define GM_LPA_10HALF			LPA_10HALF
-#define GM_LPA_1000XFULL		LPA_1000XFULL
-#define GM_LPA_10FULL			LPA_10FULL
-#define GM_LPA_1000XHALF		LPA_1000XHALF
-#define GM_LPA_100HALF			LPA_100HALF
-#define GM_LPA_1000XPAUSE		LPA_1000XPAUSE
-#define GM_LPA_100FULL			LPA_100FULL
-#define GM_LPA_1000XPAUSE_ASYM		LPA_1000XPAUSE_ASYM
-#define GM_LPA_100BASE4			LPA_100BASE4
-#define GM_LPA_PAUSE_CAP		LPA_PAUSE_CAP
-#define GM_LPA_PAUSE_ASYM		LPA_PAUSE_ASYM
-#define GM_LPA_RESV			LPA_RESV
-#define GM_LPA_RFAULT			LPA_RFAULT
-#define GM_LPA_LPACK			LPA_LPACK
-#define GM_LPA_NPAGE			LPA_NPAGE
-#define GM_LPA_1000FULL			(LPA_1000FULL << 6)
-#define GM_LPA_1000HALF			(LPA_1000HALF << 6)
-#define GM_LPA_10000FULL		0x00040000
-#define GM_LPA_10000HALF		0x00080000
-#define GM_LPA_DUPLEX			(GM_LPA_1000FULL | GM_LPA_10000FULL \
-					 | LPA_DUPLEX)
-#define GM_LPA_10			(LPA_10FULL | LPA_10HALF)
-#define GM_LPA_100			LPA_100
-#define GM_LPA_1000			(GM_LPA_1000FULL | GM_LPA_1000HALF)
-#define GM_LPA_10000			(GM_LPA_10000FULL | GM_LPA_10000HALF)
-
-/* Retrieve GMII autonegotiation advertised abilities
- *
- * The MII advertisment register (MII_ADVERTISE) is logically extended
- * to include advertisement bits ADVERTISE_1000FULL and
- * ADVERTISE_1000HALF from MII_CTRL1000.  The result can be tested
- * against the GM_ADVERTISE_xxx constants.
- */
-static inline unsigned int gmii_advertised(struct mii_if_info *gmii)
-{
-	unsigned int advertise;
-	unsigned int ctrl1000;
-
-	advertise = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_ADVERTISE);
-	ctrl1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000);
-	return (((ctrl1000 << 8) & GM_ADVERTISE_1000) | advertise);
-}
-
-/* Retrieve GMII autonegotiation link partner abilities
- *
- * The MII link partner ability register (MII_LPA) is logically
- * extended by adding bits LPA_1000HALF and LPA_1000FULL from
- * MII_STAT1000.  The result can be tested against the GM_LPA_xxx
- * constants.
- */
-static inline unsigned int gmii_lpa(struct mii_if_info *gmii)
-{
-	unsigned int lpa;
-	unsigned int stat1000;
-
-	lpa = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_LPA);
-	stat1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_STAT1000);
-	return (((stat1000 << 6) & GM_LPA_1000) | lpa);
-}
-
-/* Calculate GMII autonegotiated link technology
- *
- * "negotiated" should be the result of gmii_advertised() logically
- * ANDed with the result of gmii_lpa().
- *
- * "tech" will be negotiated with the unused bits masked out.  For
- * example, if both ends of the link are capable of both
- * GM_LPA_1000FULL and GM_LPA_100FULL, GM_LPA_100FULL will be masked
- * out.
- */
-static inline unsigned int gmii_nway_result(unsigned int negotiated)
-{
-	unsigned int other_bits;
-
-	/* Mask out the speed and duplexity bits */
-	other_bits = negotiated & ~(GM_LPA_10 | GM_LPA_100 | GM_LPA_1000);
-
-	if (negotiated & GM_LPA_1000FULL)
-		return (other_bits | GM_LPA_1000FULL);
-	else if (negotiated & GM_LPA_1000HALF)
-		return (other_bits | GM_LPA_1000HALF);
-	else
-		return (other_bits | mii_nway_result(negotiated));
-}
-
-/* Calculate GMII non-autonegotiated link technology
- *
- * This provides an equivalent to gmii_nway_result for the case when
- * autonegotiation is disabled.
- */
-static inline unsigned int gmii_forced_result(unsigned int bmcr)
-{
-	unsigned int result;
-	int full_duplex;
-
-	full_duplex = bmcr & BMCR_FULLDPLX;
-	if (bmcr & BMCR_SPEED1000)
-		result = full_duplex ? GM_LPA_1000FULL : GM_LPA_1000HALF;
-	else if (bmcr & BMCR_SPEED100)
-		result = full_duplex ? GM_LPA_100FULL : GM_LPA_100HALF;
-	else
-		result = full_duplex ? GM_LPA_10FULL : GM_LPA_10HALF;
-	return result;
-}
-
 #endif /* EFX_GMII_H */
diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h
index a31571c..4e70742 100644
--- a/drivers/net/sfc/mac.h
+++ b/drivers/net/sfc/mac.h
@@ -1,7 +1,7 @@
 /****************************************************************************
  * Driver for Solarflare Solarstorm network controllers and boards
  * Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2007 Solarflare Communications Inc.
+ * Copyright 2006-2008 Solarflare Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
@@ -13,17 +13,7 @@
 
 #include "net_driver.h"
 
-extern int falcon_init_xmac(struct efx_nic *efx);
-extern void falcon_reconfigure_xmac(struct efx_nic *efx);
-extern void falcon_update_stats_xmac(struct efx_nic *efx);
-extern void falcon_fini_xmac(struct efx_nic *efx);
-extern int falcon_check_xmac(struct efx_nic *efx);
-extern void falcon_xmac_sim_phy_event(struct efx_nic *efx);
-extern int falcon_xmac_get_settings(struct efx_nic *efx,
-				    struct ethtool_cmd *ecmd);
-extern int falcon_xmac_set_settings(struct efx_nic *efx,
-				    struct ethtool_cmd *ecmd);
-extern int falcon_xmac_set_pause(struct efx_nic *efx,
-				 enum efx_fc_type pause_params);
+extern struct efx_mac_operations falcon_gmac_operations;
+extern struct efx_mac_operations falcon_xmac_operations;
 
 #endif
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 003e48d..f6a1642 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -47,13 +47,16 @@
 	if (LOOPBACK_INTERNAL(efx))
 		return 0;
 
-	/* Read MMD STATUS2 to check it is responding. */
-	status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2);
-	if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) &
-	     ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) !=
-	    MDIO_MMDREG_STAT2_PRESENT_VAL) {
-		EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd);
-		return -EIO;
+	if (mmd != MDIO_MMD_AN) {
+		/* Read MMD STATUS2 to check it is responding. */
+		status = mdio_clause45_read(efx, phy_id, mmd,
+					    MDIO_MMDREG_STAT2);
+		if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) &
+		     ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) !=
+		    MDIO_MMDREG_STAT2_PRESENT_VAL) {
+			EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd);
+			return -EIO;
+		}
 	}
 
 	/* Read MMD STATUS 1 to check for fault. */
@@ -121,16 +124,18 @@
 int mdio_clause45_check_mmds(struct efx_nic *efx,
 			     unsigned int mmd_mask, unsigned int fatal_mask)
 {
-	int devices, mmd = 0;
-	int probe_mmd;
+	u32 devices;
+	int mmd = 0, probe_mmd;
 
 	/* Historically we have probed the PHYXS to find out what devices are
 	 * present,but that doesn't work so well if the PHYXS isn't expected
 	 * to exist, if so just find the first item in the list supplied. */
-	probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS0_PHYXS) ? MDIO_MMD_PHYXS :
+	probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS_PHYXS) ? MDIO_MMD_PHYXS :
 	    __ffs(mmd_mask);
-	devices = mdio_clause45_read(efx, efx->mii.phy_id,
-				     probe_mmd, MDIO_MMDREG_DEVS0);
+	devices = (mdio_clause45_read(efx, efx->mii.phy_id,
+				      probe_mmd, MDIO_MMDREG_DEVS0) |
+		   mdio_clause45_read(efx, efx->mii.phy_id,
+				      probe_mmd, MDIO_MMDREG_DEVS1) << 16);
 
 	/* Check all the expected MMDs are present */
 	if (devices < 0) {
@@ -162,7 +167,7 @@
 bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
 {
 	int phy_id = efx->mii.phy_id;
-	int status;
+	u32 reg;
 	bool ok = true;
 	int mmd = 0;
 
@@ -174,26 +179,33 @@
 		return false;
 	else if (efx_phy_mode_disabled(efx->phy_mode))
 		return false;
-	else if (efx->loopback_mode == LOOPBACK_PHYXS)
-		mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS |
-			      MDIO_MMDREG_DEVS0_PCS |
-			      MDIO_MMDREG_DEVS0_PMAPMD);
-	else if (efx->loopback_mode == LOOPBACK_PCS)
-		mmd_mask &= ~(MDIO_MMDREG_DEVS0_PCS |
-			      MDIO_MMDREG_DEVS0_PMAPMD);
+	else if (efx->loopback_mode == LOOPBACK_PHYXS) {
+		mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS |
+			      MDIO_MMDREG_DEVS_PCS |
+			      MDIO_MMDREG_DEVS_PMAPMD |
+			      MDIO_MMDREG_DEVS_AN);
+		if (!mmd_mask) {
+			reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
+						 MDIO_PHYXS_STATUS2);
+			return !(reg & (1 << MDIO_PHYXS_STATUS2_RX_FAULT_LBN));
+		}
+	} else if (efx->loopback_mode == LOOPBACK_PCS)
+		mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS |
+			      MDIO_MMDREG_DEVS_PMAPMD |
+			      MDIO_MMDREG_DEVS_AN);
 	else if (efx->loopback_mode == LOOPBACK_PMAPMD)
-		mmd_mask &= ~MDIO_MMDREG_DEVS0_PMAPMD;
+		mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD |
+			      MDIO_MMDREG_DEVS_AN);
 
 	while (mmd_mask) {
 		if (mmd_mask & 1) {
 			/* Double reads because link state is latched, and a
 			 * read moves the current state into the register */
-			status = mdio_clause45_read(efx, phy_id,
-						    mmd, MDIO_MMDREG_STAT1);
-			status = mdio_clause45_read(efx, phy_id,
-						    mmd, MDIO_MMDREG_STAT1);
-
-			ok = ok && (status & (1 << MDIO_MMDREG_STAT1_LINK_LBN));
+			reg = mdio_clause45_read(efx, phy_id,
+						 mmd, MDIO_MMDREG_STAT1);
+			reg = mdio_clause45_read(efx, phy_id,
+						 mmd, MDIO_MMDREG_STAT1);
+			ok = ok && (reg & (1 << MDIO_MMDREG_STAT1_LINK_LBN));
 		}
 		mmd_mask = (mmd_mask >> 1);
 		mmd++;
@@ -203,61 +215,73 @@
 
 void mdio_clause45_transmit_disable(struct efx_nic *efx)
 {
-	int phy_id = efx->mii.phy_id;
-	int ctrl1, ctrl2;
-
-	ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
-					   MDIO_MMDREG_TXDIS);
-	if (efx->phy_mode & PHY_MODE_TX_DISABLED)
-		ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
-	else
-		ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
-	if (ctrl1 != ctrl2)
-		mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
-				    MDIO_MMDREG_TXDIS, ctrl2);
+	mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+			       MDIO_MMDREG_TXDIS, MDIO_MMDREG_TXDIS_GLOBAL_LBN,
+			       efx->phy_mode & PHY_MODE_TX_DISABLED);
 }
 
 void mdio_clause45_phy_reconfigure(struct efx_nic *efx)
 {
 	int phy_id = efx->mii.phy_id;
-	int ctrl1, ctrl2;
 
-	/* Handle (with debouncing) PMA/PMD loopback */
-	ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
-					   MDIO_MMDREG_CTRL1);
+	mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD,
+			       MDIO_MMDREG_CTRL1, MDIO_PMAPMD_CTRL1_LBACK_LBN,
+			       efx->loopback_mode == LOOPBACK_PMAPMD);
+	mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PCS,
+			       MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN,
+			       efx->loopback_mode == LOOPBACK_PCS);
+	mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS,
+			       MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN,
+			       efx->loopback_mode == LOOPBACK_NETWORK);
+}
 
-	if (efx->loopback_mode == LOOPBACK_PMAPMD)
-		ctrl2 |= (1 << MDIO_PMAPMD_CTRL1_LBACK_LBN);
-	else
-		ctrl2 &= ~(1 << MDIO_PMAPMD_CTRL1_LBACK_LBN);
+static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx,
+					 int lpower, int mmd)
+{
+	int phy = efx->mii.phy_id;
+	int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1);
 
-	if (ctrl1 != ctrl2)
-		mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
-				    MDIO_MMDREG_CTRL1, ctrl2);
+	EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n",
+		  mmd, lpower);
 
-	/* Handle (with debouncing) PCS loopback */
-	ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
-					   MDIO_MMDREG_CTRL1);
-	if (efx->loopback_mode == LOOPBACK_PCS)
-		ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
-	else
-		ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
+	if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) {
+		mdio_clause45_set_flag(efx, phy, mmd, MDIO_MMDREG_CTRL1,
+				       MDIO_MMDREG_CTRL1_LPOWER_LBN, lpower);
+	}
+}
 
-	if (ctrl1 != ctrl2)
-		mdio_clause45_write(efx, phy_id, MDIO_MMD_PCS,
-				    MDIO_MMDREG_CTRL1, ctrl2);
+void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
+				   int low_power, unsigned int mmd_mask)
+{
+	int mmd = 0;
+	mmd_mask &= ~MDIO_MMDREG_DEVS_AN;
+	while (mmd_mask) {
+		if (mmd_mask & 1)
+			mdio_clause45_set_mmd_lpower(efx, low_power, mmd);
+		mmd_mask = (mmd_mask >> 1);
+		mmd++;
+	}
+}
 
-	/* Handle (with debouncing) PHYXS network loopback */
-	ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
-					   MDIO_MMDREG_CTRL1);
-	if (efx->loopback_mode == LOOPBACK_NETWORK)
-		ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
-	else
-		ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
+static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp)
+{
+	int phy_id = efx->mii.phy_id;
+	u32 result = 0;
+	int reg;
 
-	if (ctrl1 != ctrl2)
-		mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS,
-				    MDIO_MMDREG_CTRL1, ctrl2);
+	reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, addr);
+	if (reg & ADVERTISE_10HALF)
+		result |= ADVERTISED_10baseT_Half;
+	if (reg & ADVERTISE_10FULL)
+		result |= ADVERTISED_10baseT_Full;
+	if (reg & ADVERTISE_100HALF)
+		result |= ADVERTISED_100baseT_Half;
+	if (reg & ADVERTISE_100FULL)
+		result |= ADVERTISED_100baseT_Full;
+	if (reg & LPA_RESV)
+		result |= xnp;
+
+	return result;
 }
 
 /**
@@ -266,72 +290,117 @@
  * @ecmd: 		Buffer for settings
  *
  * On return the 'port', 'speed', 'supported' and 'advertising' fields of
- * ecmd have been filled out based on the PMA type.
+ * ecmd have been filled out.
  */
 void mdio_clause45_get_settings(struct efx_nic *efx,
 				struct ethtool_cmd *ecmd)
 {
-	int pma_type;
+	mdio_clause45_get_settings_ext(efx, ecmd, 0, 0);
+}
 
-	/* If no PMA is present we are presumably talking something XAUI-ish
-	 * like CX4. Which we report as FIBRE (see below) */
-	if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) {
-		ecmd->speed = SPEED_10000;
+/**
+ * mdio_clause45_get_settings_ext - Read (some of) the PHY settings over MDIO.
+ * @efx:		Efx NIC
+ * @ecmd: 		Buffer for settings
+ * @xnp:		Advertised Extended Next Page state
+ * @xnp_lpa:		Link Partner's advertised XNP state
+ *
+ * On return the 'port', 'speed', 'supported' and 'advertising' fields of
+ * ecmd have been filled out.
+ */
+void mdio_clause45_get_settings_ext(struct efx_nic *efx,
+				    struct ethtool_cmd *ecmd,
+				    u32 xnp, u32 xnp_lpa)
+{
+	int phy_id = efx->mii.phy_id;
+	int reg;
+
+	ecmd->transceiver = XCVR_INTERNAL;
+	ecmd->phy_address = phy_id;
+
+	reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+				 MDIO_MMDREG_CTRL2);
+	switch (reg & MDIO_PMAPMD_CTRL2_TYPE_MASK) {
+	case MDIO_PMAPMD_CTRL2_10G_BT:
+	case MDIO_PMAPMD_CTRL2_1G_BT:
+	case MDIO_PMAPMD_CTRL2_100_BT:
+	case MDIO_PMAPMD_CTRL2_10_BT:
+		ecmd->port = PORT_TP;
+		ecmd->supported = SUPPORTED_TP;
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+					 MDIO_MMDREG_SPEED);
+		if (reg & (1 << MDIO_MMDREG_SPEED_10G_LBN))
+			ecmd->supported |= SUPPORTED_10000baseT_Full;
+		if (reg & (1 << MDIO_MMDREG_SPEED_1000M_LBN))
+			ecmd->supported |= (SUPPORTED_1000baseT_Full |
+					    SUPPORTED_1000baseT_Half);
+		if (reg & (1 << MDIO_MMDREG_SPEED_100M_LBN))
+			ecmd->supported |= (SUPPORTED_100baseT_Full |
+					    SUPPORTED_100baseT_Half);
+		if (reg & (1 << MDIO_MMDREG_SPEED_10M_LBN))
+			ecmd->supported |= (SUPPORTED_10baseT_Full |
+					    SUPPORTED_10baseT_Half);
+		ecmd->advertising = ADVERTISED_TP;
+		break;
+
+	/* We represent CX4 as fibre in the absence of anything better */
+	case MDIO_PMAPMD_CTRL2_10G_CX4:
+	/* All the other defined modes are flavours of optical */
+	default:
 		ecmd->port = PORT_FIBRE;
 		ecmd->supported = SUPPORTED_FIBRE;
 		ecmd->advertising = ADVERTISED_FIBRE;
-		return;
+		break;
 	}
 
-	pma_type = mdio_clause45_read(efx, efx->mii.phy_id,
-				      MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2);
-	pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK;
+	if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) {
+		ecmd->supported |= SUPPORTED_Autoneg;
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
+					 MDIO_MMDREG_CTRL1);
+		if (reg & BMCR_ANENABLE) {
+			ecmd->autoneg = AUTONEG_ENABLE;
+			ecmd->advertising |=
+				ADVERTISED_Autoneg |
+				mdio_clause45_get_an(efx,
+						     MDIO_AN_ADVERTISE, xnp);
+		} else
+			ecmd->autoneg = AUTONEG_DISABLE;
+	} else
+		ecmd->autoneg = AUTONEG_DISABLE;
 
-	switch (pma_type) {
-		/* We represent CX4 as fibre in the absence of anything
-		   better. */
-	case MDIO_PMAPMD_CTRL2_10G_CX4:
-		ecmd->speed = SPEED_10000;
-		ecmd->port = PORT_FIBRE;
-		ecmd->supported = SUPPORTED_FIBRE;
-		ecmd->advertising = ADVERTISED_FIBRE;
-		break;
-		/* 10G Base-T */
-	case MDIO_PMAPMD_CTRL2_10G_BT:
-		ecmd->speed = SPEED_10000;
-		ecmd->port = PORT_TP;
-		ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full;
-		ecmd->advertising = (ADVERTISED_FIBRE
-				     | ADVERTISED_10000baseT_Full);
-		break;
-	case MDIO_PMAPMD_CTRL2_1G_BT:
-		ecmd->speed = SPEED_1000;
-		ecmd->port = PORT_TP;
-		ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full;
-		ecmd->advertising = (ADVERTISED_FIBRE
-				     | ADVERTISED_1000baseT_Full);
-		break;
-	case MDIO_PMAPMD_CTRL2_100_BT:
-		ecmd->speed = SPEED_100;
-		ecmd->port = PORT_TP;
-		ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full;
-		ecmd->advertising = (ADVERTISED_FIBRE
-				     | ADVERTISED_100baseT_Full);
-		break;
-	case MDIO_PMAPMD_CTRL2_10_BT:
-		ecmd->speed = SPEED_10;
-		ecmd->port = PORT_TP;
-		ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full;
-		ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full;
-		break;
-	/* All the other defined modes are flavours of
-	 * 10G optical */
-	default:
-		ecmd->speed = SPEED_10000;
-		ecmd->port = PORT_FIBRE;
-		ecmd->supported = SUPPORTED_FIBRE;
-		ecmd->advertising = ADVERTISED_FIBRE;
-		break;
+	if (ecmd->autoneg) {
+		/* If AN is complete, report best common mode,
+		 * otherwise report best advertised mode. */
+		u32 common = ecmd->advertising;
+		if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
+				       MDIO_MMDREG_STAT1) &
+		    (1 << MDIO_AN_STATUS_AN_DONE_LBN)) {
+			common &= mdio_clause45_get_an(efx, MDIO_AN_LPA,
+						       xnp_lpa);
+		}
+		if (common & ADVERTISED_10000baseT_Full) {
+			ecmd->speed = SPEED_10000;
+			ecmd->duplex = DUPLEX_FULL;
+		} else if (common & (ADVERTISED_1000baseT_Full |
+				     ADVERTISED_1000baseT_Half)) {
+			ecmd->speed = SPEED_1000;
+			ecmd->duplex = !!(common & ADVERTISED_1000baseT_Full);
+		} else if (common & (ADVERTISED_100baseT_Full |
+				     ADVERTISED_100baseT_Half)) {
+			ecmd->speed = SPEED_100;
+			ecmd->duplex = !!(common & ADVERTISED_100baseT_Full);
+		} else {
+			ecmd->speed = SPEED_10;
+			ecmd->duplex = !!(common & ADVERTISED_10baseT_Full);
+		}
+	} else {
+		/* Report forced settings */
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+					 MDIO_MMDREG_CTRL1);
+		ecmd->speed = (((reg & BMCR_SPEED1000) ? 100 : 1) *
+			       ((reg & BMCR_SPEED100) ? 100 : 10));
+		ecmd->duplex = (reg & BMCR_FULLDPLX ||
+				ecmd->speed == SPEED_10000);
 	}
 }
 
@@ -339,22 +408,172 @@
  * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO.
  * @efx:		Efx NIC
  * @ecmd: 		New settings
- *
- * Currently this just enforces that we are _not_ changing the
- * 'port', 'speed', 'supported' or 'advertising' settings as these
- * cannot be changed on any currently supported PHY.
  */
 int mdio_clause45_set_settings(struct efx_nic *efx,
 			       struct ethtool_cmd *ecmd)
 {
-	struct ethtool_cmd tmpcmd;
-	mdio_clause45_get_settings(efx, &tmpcmd);
-	/* None of the current PHYs support more than one mode
-	 * of operation (and only 10GBT ever will), so keep things
-	 * simple for now */
-	if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) &&
-	    (ecmd->supported == tmpcmd.supported) &&
-	    (ecmd->advertising == tmpcmd.advertising))
+	int phy_id = efx->mii.phy_id;
+	struct ethtool_cmd prev;
+	u32 required;
+	int ctrl1_bits, reg;
+
+	efx->phy_op->get_settings(efx, &prev);
+
+	if (ecmd->advertising == prev.advertising &&
+	    ecmd->speed == prev.speed &&
+	    ecmd->duplex == prev.duplex &&
+	    ecmd->port == prev.port &&
+	    ecmd->autoneg == prev.autoneg)
 		return 0;
-	return -EOPNOTSUPP;
+
+	/* We can only change these settings for -T PHYs */
+	if (prev.port != PORT_TP || ecmd->port != PORT_TP)
+		return -EINVAL;
+
+	/* Check that PHY supports these settings and work out the
+	 * basic control bits */
+	if (ecmd->duplex) {
+		switch (ecmd->speed) {
+		case SPEED_10:
+			ctrl1_bits = BMCR_FULLDPLX;
+			required = SUPPORTED_10baseT_Full;
+			break;
+		case SPEED_100:
+			ctrl1_bits = BMCR_SPEED100 | BMCR_FULLDPLX;
+			required = SUPPORTED_100baseT_Full;
+			break;
+		case SPEED_1000:
+			ctrl1_bits = BMCR_SPEED1000 | BMCR_FULLDPLX;
+			required = SUPPORTED_1000baseT_Full;
+			break;
+		case SPEED_10000:
+			ctrl1_bits = (BMCR_SPEED1000 | BMCR_SPEED100 |
+				      BMCR_FULLDPLX);
+			required = SUPPORTED_10000baseT_Full;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		switch (ecmd->speed) {
+		case SPEED_10:
+			ctrl1_bits = 0;
+			required = SUPPORTED_10baseT_Half;
+			break;
+		case SPEED_100:
+			ctrl1_bits = BMCR_SPEED100;
+			required = SUPPORTED_100baseT_Half;
+			break;
+		case SPEED_1000:
+			ctrl1_bits = BMCR_SPEED1000;
+			required = SUPPORTED_1000baseT_Half;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+	if (ecmd->autoneg)
+		required |= SUPPORTED_Autoneg;
+	required |= ecmd->advertising;
+	if (required & ~prev.supported)
+		return -EINVAL;
+
+	/* Set the basic control bits */
+	reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+				 MDIO_MMDREG_CTRL1);
+	reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | 0x003c);
+	reg |= ctrl1_bits;
+	mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL1,
+			    reg);
+
+	/* Set the AN registers */
+	if (ecmd->autoneg != prev.autoneg ||
+	    ecmd->advertising != prev.advertising) {
+		bool xnp = false;
+
+		if (efx->phy_op->set_xnp_advertise)
+			xnp = efx->phy_op->set_xnp_advertise(efx,
+							     ecmd->advertising);
+
+		if (ecmd->autoneg) {
+			reg = 0;
+			if (ecmd->advertising & ADVERTISED_10baseT_Half)
+				reg |= ADVERTISE_10HALF;
+			if (ecmd->advertising & ADVERTISED_10baseT_Full)
+				reg |= ADVERTISE_10FULL;
+			if (ecmd->advertising & ADVERTISED_100baseT_Half)
+				reg |= ADVERTISE_100HALF;
+			if (ecmd->advertising & ADVERTISED_100baseT_Full)
+				reg |= ADVERTISE_100FULL;
+			if (xnp)
+				reg |= ADVERTISE_RESV;
+			mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
+					    MDIO_AN_ADVERTISE, reg);
+		}
+
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
+					 MDIO_MMDREG_CTRL1);
+		if (ecmd->autoneg)
+			reg |= BMCR_ANENABLE | BMCR_ANRESTART;
+		else
+			reg &= ~BMCR_ANENABLE;
+		if (xnp)
+			reg |= 1 << MDIO_AN_CTRL_XNP_LBN;
+		else
+			reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN);
+		mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
+				    MDIO_MMDREG_CTRL1, reg);
+	}
+
+	return 0;
+}
+
+void mdio_clause45_set_pause(struct efx_nic *efx)
+{
+	int phy_id = efx->mii.phy_id;
+	int reg;
+
+	if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) {
+		/* Set pause capability advertising */
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
+					 MDIO_AN_ADVERTISE);
+		reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+		reg |= efx_fc_advertise(efx->wanted_fc);
+		mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
+				    MDIO_AN_ADVERTISE, reg);
+
+		/* Restart auto-negotiation */
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
+					 MDIO_MMDREG_CTRL1);
+		if (reg & BMCR_ANENABLE) {
+			reg |= BMCR_ANRESTART;
+			mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
+					    MDIO_MMDREG_CTRL1, reg);
+		}
+	}
+}
+
+enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx)
+{
+	int phy_id = efx->mii.phy_id;
+	int lpa;
+
+	if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)))
+		return efx->wanted_fc;
+	lpa = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_AN_LPA);
+	return efx_fc_resolve(efx->wanted_fc, lpa);
+}
+
+void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev,
+			    u16 addr, int bit, bool sense)
+{
+	int old_val = mdio_clause45_read(efx, prt, dev, addr);
+	int new_val;
+
+	if (sense)
+		new_val = old_val | (1 << bit);
+	else
+		new_val = old_val & ~(1 << bit);
+	if (old_val != new_val)
+		mdio_clause45_write(efx, prt, dev, addr, new_val);
 }
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index 19c42ea..09bf801 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -33,6 +33,8 @@
 #define MDIO_MMD_TC	(6)
 /* Auto negotiation */
 #define MDIO_MMD_AN	(7)
+/* Clause 22 extension */
+#define MDIO_MMD_C22EXT	29
 
 /* Generic register locations */
 #define MDIO_MMDREG_CTRL1	(0)
@@ -54,6 +56,9 @@
 /* Loopback bit for WIS, PCS, PHYSX and DTEXS */
 #define MDIO_MMDREG_CTRL1_LBACK_LBN	(14)
 #define MDIO_MMDREG_CTRL1_LBACK_WIDTH	(1)
+/* Low power */
+#define MDIO_MMDREG_CTRL1_LPOWER_LBN	(11)
+#define MDIO_MMDREG_CTRL1_LPOWER_WIDTH	(1)
 
 /* Bits in MMDREG_STAT1 */
 #define MDIO_MMDREG_STAT1_FAULT_LBN	(7)
@@ -70,14 +75,26 @@
 #define MDIO_ID_MODEL(_id32)	((_id32 >> 4) & 0x3f)
 #define MDIO_ID_OUI(_id32)	(_id32 >> 10)
 
-/* Bits in MMDREG_DEVS0. Someone thoughtfully layed things out
+/* Bits in MMDREG_DEVS0/1. Someone thoughtfully layed things out
  * so the 'bit present' bit number of an MMD is the number of
  * that MMD */
 #define DEV_PRESENT_BIT(_b) (1 << _b)
 
-#define MDIO_MMDREG_DEVS0_PHYXS	 DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
-#define MDIO_MMDREG_DEVS0_PCS	 DEV_PRESENT_BIT(MDIO_MMD_PCS)
-#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
+#define MDIO_MMDREG_DEVS_PHYXS	DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
+#define MDIO_MMDREG_DEVS_PCS	DEV_PRESENT_BIT(MDIO_MMD_PCS)
+#define MDIO_MMDREG_DEVS_PMAPMD	DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
+#define MDIO_MMDREG_DEVS_AN	DEV_PRESENT_BIT(MDIO_MMD_AN)
+#define MDIO_MMDREG_DEVS_C22EXT	DEV_PRESENT_BIT(MDIO_MMD_C22EXT)
+
+/* Bits in MMDREG_SPEED */
+#define MDIO_MMDREG_SPEED_10G_LBN	0
+#define MDIO_MMDREG_SPEED_10G_WIDTH	1
+#define MDIO_MMDREG_SPEED_1000M_LBN	4
+#define MDIO_MMDREG_SPEED_1000M_WIDTH	1
+#define MDIO_MMDREG_SPEED_100M_LBN	5
+#define MDIO_MMDREG_SPEED_100M_WIDTH	1
+#define MDIO_MMDREG_SPEED_10M_LBN	6
+#define MDIO_MMDREG_SPEED_10M_WIDTH	1
 
 /* Bits in MMDREG_STAT2 */
 #define MDIO_MMDREG_STAT2_PRESENT_VAL	(2)
@@ -111,17 +128,34 @@
 #define MDIO_PMAPMD_CTRL2_10_BT		(0xf)
 #define MDIO_PMAPMD_CTRL2_TYPE_MASK	(0xf)
 
+/* PMA 10GBT registers */
+#define MDIO_PMAPMD_10GBT_TXPWR		(131)
+#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN (0)
+#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_WIDTH (1)
+
+/* PHY XGXS Status 2 */
+#define MDIO_PHYXS_STATUS2              (8)
+#define MDIO_PHYXS_STATUS2_RX_FAULT_LBN 10
+
 /* PHY XGXS lane state */
 #define MDIO_PHYXS_LANE_STATE		(0x18)
 #define MDIO_PHYXS_LANE_ALIGNED_LBN	(12)
 
 /* AN registers */
+#define MDIO_AN_CTRL_XNP_LBN		13
 #define MDIO_AN_STATUS			(1)
 #define MDIO_AN_STATUS_XNP_LBN		(7)
 #define MDIO_AN_STATUS_PAGE_LBN		(6)
 #define MDIO_AN_STATUS_AN_DONE_LBN	(5)
 #define MDIO_AN_STATUS_LP_AN_CAP_LBN	(0)
 
+#define MDIO_AN_ADVERTISE		16
+#define MDIO_AN_ADVERTISE_XNP_LBN	12
+#define MDIO_AN_LPA			19
+#define MDIO_AN_XNP			22
+#define MDIO_AN_LPA_XNP			25
+
+#define MDIO_AN_10GBT_ADVERTISE		32
 #define MDIO_AN_10GBT_STATUS		(33)
 #define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */
 #define MDIO_AN_10GBT_STATUS_MS_LBN     (14) /* MASTER/SLAVE config */
@@ -240,16 +274,37 @@
 /* Generic part of reconfigure: set/clear loopback bits */
 extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx);
 
+/* Set the power state of the specified MMDs */
+extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
+					  int low_power, unsigned int mmd_mask);
+
 /* Read (some of) the PHY settings over MDIO */
 extern void mdio_clause45_get_settings(struct efx_nic *efx,
 				       struct ethtool_cmd *ecmd);
 
+/* Read (some of) the PHY settings over MDIO */
+extern void
+mdio_clause45_get_settings_ext(struct efx_nic *efx, struct ethtool_cmd *ecmd,
+			       u32 xnp, u32 xnp_lpa);
+
 /* Set (some of) the PHY settings over MDIO */
 extern int mdio_clause45_set_settings(struct efx_nic *efx,
 				      struct ethtool_cmd *ecmd);
 
+/* Set pause parameters to be advertised through AN (if available) */
+extern void mdio_clause45_set_pause(struct efx_nic *efx);
+
+/* Get pause parameters from AN if available (otherwise return
+ * requested pause parameters)
+ */
+enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx);
+
 /* Wait for specified MMDs to exit reset within a timeout */
 extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
 					 unsigned int mmd_mask);
 
+/* Set or clear flag, debouncing */
+extern void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev,
+				   u16 addr, int bit, bool sense);
+
 #endif /* EFX_MDIO_10G_H */
diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c
new file mode 100644
index 0000000..665cafb
--- /dev/null
+++ b/drivers/net/sfc/mtd.c
@@ -0,0 +1,268 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/delay.h>
+
+#define EFX_DRIVER_NAME "sfc_mtd"
+#include "net_driver.h"
+#include "spi.h"
+
+#define EFX_SPI_VERIFY_BUF_LEN 16
+
+struct efx_mtd {
+	const struct efx_spi_device *spi;
+	struct mtd_info mtd;
+	char name[IFNAMSIZ + 20];
+};
+
+/* SPI utilities */
+
+static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible)
+{
+	const struct efx_spi_device *spi = efx_mtd->spi;
+	struct efx_nic *efx = spi->efx;
+	u8 status;
+	int rc, i;
+
+	/* Wait up to 4s for flash/EEPROM to finish a slow operation. */
+	for (i = 0; i < 40; i++) {
+		__set_current_state(uninterruptible ?
+				    TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ / 10);
+		rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL,
+				    &status, sizeof(status));
+		if (rc)
+			return rc;
+		if (!(status & SPI_STATUS_NRDY))
+			return 0;
+		if (signal_pending(current))
+			return -EINTR;
+	}
+	EFX_ERR(efx, "timed out waiting for %s\n", efx_mtd->name);
+	return -ETIMEDOUT;
+}
+
+static int efx_spi_unlock(const struct efx_spi_device *spi)
+{
+	const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
+				SPI_STATUS_BP0);
+	u8 status;
+	int rc;
+
+	rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status));
+	if (rc)
+		return rc;
+
+	if (!(status & unlock_mask))
+		return 0; /* already unlocked */
+
+	rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
+	if (rc)
+		return rc;
+	rc = falcon_spi_cmd(spi, SPI_SST_EWSR, -1, NULL, NULL, 0);
+	if (rc)
+		return rc;
+
+	status &= ~unlock_mask;
+	rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status));
+	if (rc)
+		return rc;
+	rc = falcon_spi_wait_write(spi);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len)
+{
+	const struct efx_spi_device *spi = efx_mtd->spi;
+	unsigned pos, block_len;
+	u8 empty[EFX_SPI_VERIFY_BUF_LEN];
+	u8 buffer[EFX_SPI_VERIFY_BUF_LEN];
+	int rc;
+
+	if (len != spi->erase_size)
+		return -EINVAL;
+
+	if (spi->erase_command == 0)
+		return -EOPNOTSUPP;
+
+	rc = efx_spi_unlock(spi);
+	if (rc)
+		return rc;
+	rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
+	if (rc)
+		return rc;
+	rc = falcon_spi_cmd(spi, spi->erase_command, start, NULL, NULL, 0);
+	if (rc)
+		return rc;
+	rc = efx_spi_slow_wait(efx_mtd, false);
+
+	/* Verify the entire region has been wiped */
+	memset(empty, 0xff, sizeof(empty));
+	for (pos = 0; pos < len; pos += block_len) {
+		block_len = min(len - pos, sizeof(buffer));
+		rc = falcon_spi_read(spi, start + pos, block_len, NULL, buffer);
+		if (rc)
+			return rc;
+		if (memcmp(empty, buffer, block_len))
+			return -EIO;
+
+		/* Avoid locking up the system */
+		cond_resched();
+		if (signal_pending(current))
+			return -EINTR;
+	}
+
+	return rc;
+}
+
+/* MTD interface */
+
+static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len,
+			size_t *retlen, u8 *buffer)
+{
+	struct efx_mtd *efx_mtd = mtd->priv;
+	const struct efx_spi_device *spi = efx_mtd->spi;
+	struct efx_nic *efx = spi->efx;
+	int rc;
+
+	rc = mutex_lock_interruptible(&efx->spi_lock);
+	if (rc)
+		return rc;
+	rc = falcon_spi_read(spi, FALCON_FLASH_BOOTCODE_START + start,
+			     len, retlen, buffer);
+	mutex_unlock(&efx->spi_lock);
+	return rc;
+}
+
+static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+	struct efx_mtd *efx_mtd = mtd->priv;
+	struct efx_nic *efx = efx_mtd->spi->efx;
+	int rc;
+
+	rc = mutex_lock_interruptible(&efx->spi_lock);
+	if (rc)
+		return rc;
+	rc = efx_spi_erase(efx_mtd, FALCON_FLASH_BOOTCODE_START + erase->addr,
+			   erase->len);
+	mutex_unlock(&efx->spi_lock);
+
+	if (rc == 0) {
+		erase->state = MTD_ERASE_DONE;
+	} else {
+		erase->state = MTD_ERASE_FAILED;
+		erase->fail_addr = 0xffffffff;
+	}
+	mtd_erase_callback(erase);
+	return rc;
+}
+
+static int efx_mtd_write(struct mtd_info *mtd, loff_t start,
+			 size_t len, size_t *retlen, const u8 *buffer)
+{
+	struct efx_mtd *efx_mtd = mtd->priv;
+	const struct efx_spi_device *spi = efx_mtd->spi;
+	struct efx_nic *efx = spi->efx;
+	int rc;
+
+	rc = mutex_lock_interruptible(&efx->spi_lock);
+	if (rc)
+		return rc;
+	rc = falcon_spi_write(spi, FALCON_FLASH_BOOTCODE_START + start,
+			      len, retlen, buffer);
+	mutex_unlock(&efx->spi_lock);
+	return rc;
+}
+
+static void efx_mtd_sync(struct mtd_info *mtd)
+{
+	struct efx_mtd *efx_mtd = mtd->priv;
+	struct efx_nic *efx = efx_mtd->spi->efx;
+	int rc;
+
+	mutex_lock(&efx->spi_lock);
+	rc = efx_spi_slow_wait(efx_mtd, true);
+	mutex_unlock(&efx->spi_lock);
+
+	if (rc)
+		EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc);
+	return;
+}
+
+void efx_mtd_remove(struct efx_nic *efx)
+{
+	if (efx->spi_flash && efx->spi_flash->mtd) {
+		struct efx_mtd *efx_mtd = efx->spi_flash->mtd;
+		int rc;
+
+		for (;;) {
+			rc = del_mtd_device(&efx_mtd->mtd);
+			if (rc != -EBUSY)
+				break;
+			ssleep(1);
+		}
+		WARN_ON(rc);
+		kfree(efx_mtd);
+	}
+}
+
+void efx_mtd_rename(struct efx_nic *efx)
+{
+	if (efx->spi_flash && efx->spi_flash->mtd) {
+		struct efx_mtd *efx_mtd = efx->spi_flash->mtd;
+		snprintf(efx_mtd->name, sizeof(efx_mtd->name),
+			 "%s sfc_flash_bootrom", efx->name);
+	}
+}
+
+int efx_mtd_probe(struct efx_nic *efx)
+{
+	struct efx_spi_device *spi = efx->spi_flash;
+	struct efx_mtd *efx_mtd;
+
+	if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START)
+		return -ENODEV;
+
+	efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
+	if (!efx_mtd)
+		return -ENOMEM;
+
+	efx_mtd->spi = spi;
+	spi->mtd = efx_mtd;
+
+	efx_mtd->mtd.type = MTD_NORFLASH;
+	efx_mtd->mtd.flags = MTD_CAP_NORFLASH;
+	efx_mtd->mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START;
+	efx_mtd->mtd.erasesize = spi->erase_size;
+	efx_mtd->mtd.writesize = 1;
+	efx_mtd_rename(efx);
+
+	efx_mtd->mtd.owner = THIS_MODULE;
+	efx_mtd->mtd.priv = efx_mtd;
+	efx_mtd->mtd.name = efx_mtd->name;
+	efx_mtd->mtd.erase = efx_mtd_erase;
+	efx_mtd->mtd.read = efx_mtd_read;
+	efx_mtd->mtd.write = efx_mtd_write;
+	efx_mtd->mtd.sync = efx_mtd_sync;
+
+	if (add_mtd_device(&efx_mtd->mtd)) {
+		kfree(efx_mtd);
+		spi->mtd = NULL;
+		/* add_mtd_device() returns 1 if the MTD table is full */
+		return -ENOMEM;
+	}
+
+	return 0;
+}
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index cdb11fa..5f255f7 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -42,7 +42,7 @@
 #ifndef EFX_DRIVER_NAME
 #define EFX_DRIVER_NAME	"sfc"
 #endif
-#define EFX_DRIVER_VERSION	"2.2"
+#define EFX_DRIVER_VERSION	"2.3"
 
 #ifdef EFX_ENABLE_DEBUG
 #define EFX_BUG_ON_PARANOID(x) BUG_ON(x)
@@ -327,6 +327,7 @@
  *
  * @efx: Associated Efx NIC
  * @channel: Channel instance number
+ * @name: Name for channel and IRQ
  * @used_flags: Channel is used by net driver
  * @enabled: Channel enabled indicator
  * @irq: IRQ number (MSI and MSI-X only)
@@ -357,6 +358,7 @@
 struct efx_channel {
 	struct efx_nic *efx;
 	int channel;
+	char name[IFNAMSIZ + 6];
 	int used_flags;
 	bool enabled;
 	int irq;
@@ -414,6 +416,7 @@
  * @init_leds: Sets up board LEDs
  * @set_fault_led: Turns the fault LED on or off
  * @blink: Starts/stops blinking
+ * @monitor: Board-specific health check function
  * @fini: Cleanup function
  * @blinker: used to blink LEDs in software
  * @hwmon_client: I2C client for hardware monitor
@@ -428,6 +431,7 @@
 	 * have a separate init callback that happens later than
 	 * board init. */
 	int (*init_leds)(struct efx_nic *efx);
+	int (*monitor) (struct efx_nic *nic);
 	void (*set_fault_led) (struct efx_nic *efx, bool state);
 	void (*blink) (struct efx_nic *efx, bool start);
 	void (*fini) (struct efx_nic *nic);
@@ -449,16 +453,20 @@
 
 enum phy_type {
 	PHY_TYPE_NONE = 0,
-	PHY_TYPE_CX4_RTMR = 1,
-	PHY_TYPE_1G_ALASKA = 2,
-	PHY_TYPE_10XPRESS = 3,
-	PHY_TYPE_XFP = 4,
+	PHY_TYPE_TXC43128 = 1,
+	PHY_TYPE_88E1111 = 2,
+	PHY_TYPE_SFX7101 = 3,
+	PHY_TYPE_QT2022C2 = 4,
 	PHY_TYPE_PM8358 = 6,
+	PHY_TYPE_SFT9001A = 8,
+	PHY_TYPE_SFT9001B = 10,
 	PHY_TYPE_MAX	/* Insert any new items before this */
 };
 
 #define PHY_ADDR_INVALID 0xff
 
+#define EFX_IS10G(efx) ((efx)->link_speed == 10000)
+
 enum nic_state {
 	STATE_INIT = 0,
 	STATE_RUNNING = 1,
@@ -499,6 +507,55 @@
 	EFX_FC_AUTO = 4,
 };
 
+/* Supported MAC bit-mask */
+enum efx_mac_type {
+	EFX_GMAC = 1,
+	EFX_XMAC = 2,
+};
+
+static inline unsigned int efx_fc_advertise(enum efx_fc_type wanted_fc)
+{
+	unsigned int adv = 0;
+	if (wanted_fc & EFX_FC_RX)
+		adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+	if (wanted_fc & EFX_FC_TX)
+		adv ^= ADVERTISE_PAUSE_ASYM;
+	return adv;
+}
+
+static inline enum efx_fc_type efx_fc_resolve(enum efx_fc_type wanted_fc,
+					      unsigned int lpa)
+{
+	unsigned int adv = efx_fc_advertise(wanted_fc);
+
+	if (!(wanted_fc & EFX_FC_AUTO))
+		return wanted_fc;
+
+	if (adv & lpa & ADVERTISE_PAUSE_CAP)
+		return EFX_FC_RX | EFX_FC_TX;
+	if (adv & lpa & ADVERTISE_PAUSE_ASYM) {
+		if (adv & ADVERTISE_PAUSE_CAP)
+			return EFX_FC_RX;
+		if (lpa & ADVERTISE_PAUSE_CAP)
+			return EFX_FC_TX;
+	}
+	return 0;
+}
+
+/**
+ * struct efx_mac_operations - Efx MAC operations table
+ * @reconfigure: Reconfigure MAC. Serialised by the mac_lock
+ * @update_stats: Update statistics
+ * @irq: Hardware MAC event callback. Serialised by the mac_lock
+ * @poll: Poll for hardware state. Serialised by the mac_lock
+ */
+struct efx_mac_operations {
+	void (*reconfigure) (struct efx_nic *efx);
+	void (*update_stats) (struct efx_nic *efx);
+	void (*irq) (struct efx_nic *efx);
+	void (*poll) (struct efx_nic *efx);
+};
+
 /**
  * struct efx_phy_operations - Efx PHY operations table
  * @init: Initialise PHY
@@ -506,17 +563,33 @@
  * @reconfigure: Reconfigure PHY (e.g. for new link parameters)
  * @clear_interrupt: Clear down interrupt
  * @blink: Blink LEDs
- * @check_hw: Check hardware
+ * @poll: Poll for hardware state. Serialised by the mac_lock.
+ * @get_settings: Get ethtool settings. Serialised by the mac_lock.
+ * @set_settings: Set ethtool settings. Serialised by the mac_lock.
+ * @set_xnp_advertise: Set abilities advertised in Extended Next Page
+ *	(only needed where AN bit is set in mmds)
+ * @num_tests: Number of PHY-specific tests/results
+ * @test_names: Names of the tests/results
+ * @run_tests: Run tests and record results as appropriate.
+ *	Flags are the ethtool tests flags.
  * @mmds: MMD presence mask
  * @loopbacks: Supported loopback modes mask
  */
 struct efx_phy_operations {
+	enum efx_mac_type macs;
 	int (*init) (struct efx_nic *efx);
 	void (*fini) (struct efx_nic *efx);
 	void (*reconfigure) (struct efx_nic *efx);
 	void (*clear_interrupt) (struct efx_nic *efx);
-	int (*check_hw) (struct efx_nic *efx);
-	int (*test) (struct efx_nic *efx);
+	void (*poll) (struct efx_nic *efx);
+	void (*get_settings) (struct efx_nic *efx,
+			      struct ethtool_cmd *ecmd);
+	int (*set_settings) (struct efx_nic *efx,
+			     struct ethtool_cmd *ecmd);
+	bool (*set_xnp_advertise) (struct efx_nic *efx, u32);
+	u32 num_tests;
+	const char *const *test_names;
+	int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
 	int mmds;
 	unsigned loopbacks;
 };
@@ -525,11 +598,15 @@
  * @enum efx_phy_mode - PHY operating mode flags
  * @PHY_MODE_NORMAL: on and should pass traffic
  * @PHY_MODE_TX_DISABLED: on with TX disabled
+ * @PHY_MODE_LOW_POWER: set to low power through MDIO
+ * @PHY_MODE_OFF: switched off through external control
  * @PHY_MODE_SPECIAL: on but will not pass traffic
  */
 enum efx_phy_mode {
 	PHY_MODE_NORMAL		= 0,
 	PHY_MODE_TX_DISABLED	= 1,
+	PHY_MODE_LOW_POWER	= 2,
+	PHY_MODE_OFF		= 4,
 	PHY_MODE_SPECIAL	= 8,
 };
 
@@ -629,7 +706,7 @@
  * @legacy_irq: IRQ number
  * @workqueue: Workqueue for port reconfigures and the HW monitor.
  *	Work items do not hold and must not acquire RTNL.
- * @reset_workqueue: Workqueue for resets.  Work item will acquire RTNL.
+ * @workqueue_name: Name of workqueue
  * @reset_work: Scheduled reset workitem
  * @monitor_work: Hardware monitor workitem
  * @membase_phys: Memory BAR value as physical address
@@ -644,6 +721,7 @@
  * @rx_queue: RX DMA queues
  * @channel: Channels
  * @n_rx_queues: Number of RX queues
+ * @n_channels: Number of channels in use
  * @rx_buffer_len: RX buffer length
  * @rx_buffer_order: Order (log2) of number of pages for each RX buffer
  * @irq_status: Interrupt status buffer
@@ -655,15 +733,16 @@
  *	This field will be %NULL if no flash device is present.
  * @spi_eeprom: SPI EEPROM device
  *	This field will be %NULL if no EEPROM device is present.
+ * @spi_lock: SPI bus lock
  * @n_rx_nodesc_drop_cnt: RX no descriptor drop count
  * @nic_data: Hardware dependant state
  * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode,
  *	@port_inhibited, efx_monitor() and efx_reconfigure_port()
  * @port_enabled: Port enabled indicator.
- *	Serialises efx_stop_all(), efx_start_all() and efx_monitor() and
- *	efx_reconfigure_work with kernel interfaces. Safe to read under any
- *	one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must
- *	be held to modify it.
+ *	Serialises efx_stop_all(), efx_start_all(), efx_monitor(),
+ *	efx_phy_work(), and efx_mac_work() with kernel interfaces. Safe to read
+ *	under any one of the rtnl_lock, mac_lock, or netif_tx_lock, but all
+ *	three must be held to modify it.
  * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock
  * @port_initialized: Port initialized?
  * @net_dev: Operating system network device. Consider holding the rtnl lock
@@ -677,6 +756,7 @@
  * @stats_lock: Statistics update lock. Serialises statistics fetches
  * @stats_enabled: Temporarily disable statistics fetches.
  *	Serialised by @stats_lock
+ * @mac_op: MAC interface
  * @mac_address: Permanent MAC address
  * @phy_type: PHY type
  * @phy_lock: PHY access lock
@@ -684,13 +764,17 @@
  * @phy_data: PHY private data (including PHY-specific stats)
  * @mii: PHY interface
  * @phy_mode: PHY operating mode. Serialised by @mac_lock.
+ * @mac_up: MAC link state
  * @link_up: Link status
- * @link_options: Link options (MII/GMII format)
+ * @link_fd: Link is full duplex
+ * @link_fc: Actualy flow control flags
+ * @link_speed: Link speed (Mbps)
  * @n_link_state_changes: Number of times the link has changed state
  * @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
  * @multicast_hash: Multicast hash table
- * @flow_control: Flow control flags - separate RX/TX so can't use link_options
- * @reconfigure_work: work item for dealing with PHY events
+ * @wanted_fc: Wanted flow control flags
+ * @phy_work: work item for dealing with PHY events
+ * @mac_work: work item for dealing with MAC events
  * @loopback_mode: Loopback status
  * @loopback_modes: Supported loopback mode bitmask
  * @loopback_selftest: Offline self-test private state
@@ -704,7 +788,7 @@
 	const struct efx_nic_type *type;
 	int legacy_irq;
 	struct workqueue_struct *workqueue;
-	struct workqueue_struct *reset_workqueue;
+	char workqueue_name[16];
 	struct work_struct reset_work;
 	struct delayed_work monitor_work;
 	resource_size_t membase_phys;
@@ -723,6 +807,7 @@
 	struct efx_channel channel[EFX_MAX_CHANNELS];
 
 	int n_rx_queues;
+	int n_channels;
 	unsigned int rx_buffer_len;
 	unsigned int rx_buffer_order;
 
@@ -731,12 +816,14 @@
 
 	struct efx_spi_device *spi_flash;
 	struct efx_spi_device *spi_eeprom;
+	struct mutex spi_lock;
 
 	unsigned n_rx_nodesc_drop_cnt;
 
 	struct falcon_nic_data *nic_data;
 
 	struct mutex mac_lock;
+	struct work_struct mac_work;
 	bool port_enabled;
 	bool port_inhibited;
 
@@ -752,23 +839,27 @@
 	spinlock_t stats_lock;
 	bool stats_enabled;
 
+	struct efx_mac_operations *mac_op;
 	unsigned char mac_address[ETH_ALEN];
 
 	enum phy_type phy_type;
 	spinlock_t phy_lock;
+	struct work_struct phy_work;
 	struct efx_phy_operations *phy_op;
 	void *phy_data;
 	struct mii_if_info mii;
 	enum efx_phy_mode phy_mode;
 
+	bool mac_up;
 	bool link_up;
-	unsigned int link_options;
+	bool link_fd;
+	enum efx_fc_type link_fc;
+	unsigned int link_speed;
 	unsigned int n_link_state_changes;
 
 	bool promiscuous;
 	union efx_multicast_hash multicast_hash;
-	enum efx_fc_type flow_control;
-	struct work_struct reconfigure_work;
+	enum efx_fc_type wanted_fc;
 
 	atomic_t rx_reset;
 	enum efx_loopback_mode loopback_mode;
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h
index f746536..58c493e 100644
--- a/drivers/net/sfc/phy.h
+++ b/drivers/net/sfc/phy.h
@@ -1,6 +1,6 @@
 /****************************************************************************
  * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2007 Solarflare Communications Inc.
+ * Copyright 2007-2008 Solarflare Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
@@ -11,9 +11,10 @@
 #define EFX_PHY_H
 
 /****************************************************************************
- * 10Xpress (SFX7101) PHY
+ * 10Xpress (SFX7101 and SFT9001) PHYs
  */
-extern struct efx_phy_operations falcon_tenxpress_phy_ops;
+extern struct efx_phy_operations falcon_sfx7101_phy_ops;
+extern struct efx_phy_operations falcon_sft9001_phy_ops;
 
 extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink);
 extern void tenxpress_crc_err(struct efx_nic *efx);
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index 0f805da..b8ba4bb 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -752,7 +752,7 @@
 	channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
 
 done:
-	efx->net_dev->last_rx = jiffies;
+	;
 }
 
 void efx_rx_strategy(struct efx_channel *channel)
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 362956e..dba0d64 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -26,7 +26,6 @@
 #include "selftest.h"
 #include "boards.h"
 #include "workarounds.h"
-#include "mac.h"
 #include "spi.h"
 #include "falcon_io.h"
 #include "mdio_10g.h"
@@ -105,9 +104,11 @@
 		goto out;
 	}
 
-	rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0);
-	if (rc)
-		goto out;
+	if (EFX_IS10G(efx)) {
+		rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0);
+		if (rc)
+			goto out;
+	}
 
 out:
 	mutex_unlock(&efx->mac_lock);
@@ -246,17 +247,20 @@
 	return 0;
 }
 
-static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests)
+static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests,
+			unsigned flags)
 {
 	int rc;
 
-	if (!efx->phy_op->test)
+	if (!efx->phy_op->run_tests)
 		return 0;
 
+	EFX_BUG_ON_PARANOID(efx->phy_op->num_tests == 0 ||
+			    efx->phy_op->num_tests > EFX_MAX_PHY_TESTS);
+
 	mutex_lock(&efx->mac_lock);
-	rc = efx->phy_op->test(efx);
+	rc = efx->phy_op->run_tests(efx, tests->phy, flags);
 	mutex_unlock(&efx->mac_lock);
-	tests->phy = rc ? -1 : 1;
 	return rc;
 }
 
@@ -563,8 +567,7 @@
 	return 0;
 }
 
-static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd,
-			      struct efx_self_tests *tests,
+static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
 			      unsigned int loopback_modes)
 {
 	enum efx_loopback_mode mode;
@@ -593,12 +596,14 @@
 		efx->loopback_mode = mode;
 		efx_reconfigure_port(efx);
 
-		/* Wait for the PHY to signal the link is up */
+		/* Wait for the PHY to signal the link is up. Interrupts
+		 * are enabled for PHY's using LASI, otherwise we poll()
+		 * quickly */
 		count = 0;
 		do {
 			struct efx_channel *channel = &efx->channel[0];
 
-			falcon_check_xmac(efx);
+			efx->phy_op->poll(efx);
 			schedule_timeout_uninterruptible(HZ / 10);
 			if (channel->work_pending)
 				efx_process_channel_now(channel);
@@ -606,13 +611,12 @@
 			flush_workqueue(efx->workqueue);
 			rmb();
 
-			/* efx->link_up can be 1 even if the XAUI link is down,
-			 * (bug5762). Usually, it's not worth bothering with the
-			 * difference, but for selftests, we need that extra
-			 * guarantee that the link is really, really, up.
-			 */
+			/* We need both the phy and xaui links to be ok.
+			 * rather than relying on the falcon_xmac irq/poll
+			 * regime, just poll xaui directly */
 			link_up = efx->link_up;
-			if (!falcon_xaui_link_ok(efx))
+			if (link_up && EFX_IS10G(efx) &&
+			    !falcon_xaui_link_ok(efx))
 				link_up = false;
 
 		} while ((++count < 20) && !link_up);
@@ -652,47 +656,48 @@
 
 /**************************************************************************
  *
- * Entry points
+ * Entry point
  *
  *************************************************************************/
 
-/* Online (i.e. non-disruptive) testing
- * This checks interrupt generation, event delivery and PHY presence. */
-int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests)
-{
-	struct efx_channel *channel;
-	int rc, rc2 = 0;
-
-	rc = efx_test_mii(efx, tests);
-	if (rc && !rc2)
-		rc2 = rc;
-
-	rc = efx_test_nvram(efx, tests);
-	if (rc && !rc2)
-		rc2 = rc;
-
-	rc = efx_test_interrupts(efx, tests);
-	if (rc && !rc2)
-		rc2 = rc;
-
-	efx_for_each_channel(channel, efx) {
-		rc = efx_test_eventq_irq(channel, tests);
-		if (rc && !rc2)
-			rc2 = rc;
-	}
-
-	return rc2;
-}
-
-/* Offline (i.e. disruptive) testing
- * This checks MAC and PHY loopback on the specified port. */
-int efx_offline_test(struct efx_nic *efx,
-		     struct efx_self_tests *tests, unsigned int loopback_modes)
+int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
+		 unsigned flags)
 {
 	enum efx_loopback_mode loopback_mode = efx->loopback_mode;
 	int phy_mode = efx->phy_mode;
-	struct ethtool_cmd ecmd, ecmd_test;
-	int rc, rc2 = 0;
+	struct ethtool_cmd ecmd;
+	struct efx_channel *channel;
+	int rc_test = 0, rc_reset = 0, rc;
+
+	/* Online (i.e. non-disruptive) testing
+	 * This checks interrupt generation, event delivery and PHY presence. */
+
+	rc = efx_test_mii(efx, tests);
+	if (rc && !rc_test)
+		rc_test = rc;
+
+	rc = efx_test_nvram(efx, tests);
+	if (rc && !rc_test)
+		rc_test = rc;
+
+	rc = efx_test_interrupts(efx, tests);
+	if (rc && !rc_test)
+		rc_test = rc;
+
+	efx_for_each_channel(channel, efx) {
+		rc = efx_test_eventq_irq(channel, tests);
+		if (rc && !rc_test)
+			rc_test = rc;
+	}
+
+	if (rc_test)
+		return rc_test;
+
+	if (!(flags & ETH_TEST_FL_OFFLINE))
+		return efx_test_phy(efx, tests, flags);
+
+	/* Offline (i.e. disruptive) testing
+	 * This checks MAC and PHY loopback on the specified port. */
 
 	/* force the carrier state off so the kernel doesn't transmit during
 	 * the loopback test, and the watchdog timeout doesn't fire. Also put
@@ -700,8 +705,15 @@
 	 */
 	mutex_lock(&efx->mac_lock);
 	efx->port_inhibited = true;
-	if (efx->loopback_modes)
-		efx->loopback_mode = __ffs(efx->loopback_modes);
+	if (efx->loopback_modes) {
+		/* We need the 312 clock from the PHY to test the XMAC
+		 * registers, so move into XGMII loopback if available */
+		if (efx->loopback_modes & (1 << LOOPBACK_XGMII))
+			efx->loopback_mode = LOOPBACK_XGMII;
+		else
+			efx->loopback_mode = __ffs(efx->loopback_modes);
+	}
+
 	__efx_reconfigure_port(efx);
 	mutex_unlock(&efx->mac_lock);
 
@@ -709,39 +721,34 @@
 	efx_reset_down(efx, &ecmd);
 
 	rc = efx_test_chip(efx, tests);
-	if (rc && !rc2)
-		rc2 = rc;
+	if (rc && !rc_test)
+		rc_test = rc;
 
 	/* reset the chip to recover from the register test */
-	rc = falcon_reset_hw(efx, RESET_TYPE_ALL);
+	rc_reset = falcon_reset_hw(efx, RESET_TYPE_ALL);
 
-	/* Modify the saved ecmd so that when efx_reset_up() restores the phy
-	 * state, AN is disabled, and the phy is powered, and out of loopback */
-	memcpy(&ecmd_test, &ecmd, sizeof(ecmd_test));
-	if (ecmd_test.autoneg == AUTONEG_ENABLE) {
-		ecmd_test.autoneg = AUTONEG_DISABLE;
-		ecmd_test.duplex = DUPLEX_FULL;
-		ecmd_test.speed = SPEED_10000;
-	}
+	/* Ensure that the phy is powered and out of loopback
+	 * for the bist and loopback tests */
+	efx->phy_mode &= ~PHY_MODE_LOW_POWER;
 	efx->loopback_mode = LOOPBACK_NONE;
 
-	rc = efx_reset_up(efx, &ecmd_test, rc == 0);
-	if (rc) {
+	rc = efx_reset_up(efx, &ecmd, rc_reset == 0);
+	if (rc && !rc_reset)
+		rc_reset = rc;
+
+	if (rc_reset) {
 		EFX_ERR(efx, "Unable to recover from chip test\n");
 		efx_schedule_reset(efx, RESET_TYPE_DISABLE);
-		return rc;
+		return rc_reset;
 	}
 
-	tests->loopback_speed = ecmd_test.speed;
-	tests->loopback_full_duplex = ecmd_test.duplex;
+	rc = efx_test_phy(efx, tests, flags);
+	if (rc && !rc_test)
+		rc_test = rc;
 
-	rc = efx_test_phy(efx, tests);
-	if (rc && !rc2)
-		rc2 = rc;
-
-	rc = efx_test_loopbacks(efx, ecmd_test, tests, loopback_modes);
-	if (rc && !rc2)
-		rc2 = rc;
+	rc = efx_test_loopbacks(efx, tests, efx->loopback_modes);
+	if (rc && !rc_test)
+		rc_test = rc;
 
 	/* restore the PHY to the previous state */
 	efx->loopback_mode = loopback_mode;
@@ -749,6 +756,6 @@
 	efx->port_inhibited = false;
 	efx_ethtool_set_settings(efx->net_dev, &ecmd);
 
-	return rc2;
+	return rc_test;
 }
 
diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h
index fc15df1..39451cf 100644
--- a/drivers/net/sfc/selftest.h
+++ b/drivers/net/sfc/selftest.h
@@ -24,6 +24,8 @@
 	int rx_bad;
 };
 
+#define EFX_MAX_PHY_TESTS 20
+
 /* Efx self test results
  * For fields which are not counters, 1 indicates success and -1
  * indicates failure.
@@ -38,18 +40,14 @@
 	int eventq_poll[EFX_MAX_CHANNELS];
 	/* offline tests */
 	int registers;
-	int phy;
-	int loopback_speed;
-	int loopback_full_duplex;
+	int phy[EFX_MAX_PHY_TESTS];
 	struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1];
 };
 
 extern void efx_loopback_rx_packet(struct efx_nic *efx,
 				   const char *buf_ptr, int pkt_len);
-extern int efx_online_test(struct efx_nic *efx,
-			   struct efx_self_tests *tests);
-extern int efx_offline_test(struct efx_nic *efx,
-			    struct efx_self_tests *tests,
-			    unsigned int loopback_modes);
+extern int efx_selftest(struct efx_nic *efx,
+			struct efx_self_tests *tests,
+			unsigned flags);
 
 #endif /* EFX_SELFTEST_H */
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c
index fe4e3fd..16b80ac 100644
--- a/drivers/net/sfc/sfe4001.c
+++ b/drivers/net/sfc/sfe4001.c
@@ -1,6 +1,6 @@
 /****************************************************************************
  * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2007 Solarflare Communications Inc.
+ * Copyright 2007-2008 Solarflare Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
@@ -8,10 +8,21 @@
  */
 
 /*****************************************************************************
- * Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that
- * controls the PHY power rails, and for the MAX6647 temp. sensor used to check
- * the PHY
+ * Support for the SFE4001 and SFN4111T NICs.
+ *
+ * The SFE4001 does not power-up fully at reset due to its high power
+ * consumption.  We control its power via a PCA9539 I/O expander.
+ * Both boards have a MAX6647 temperature monitor which we expose to
+ * the lm90 driver.
+ *
+ * This also provides minimal support for reflashing the PHY, which is
+ * initiated by resetting it with the FLASH_CFG_1 pin pulled down.
+ * On SFE4001 rev A2 and later this is connected to the 3V3X output of
+ * the IO-expander; on the SFN4111T it is connected to Falcon's GPIO3.
+ * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually
+ * exclusive with the network device being open.
  */
+
 #include <linux/delay.h>
 #include "net_driver.h"
 #include "efx.h"
@@ -21,6 +32,7 @@
 #include "falcon_hwdefs.h"
 #include "falcon_io.h"
 #include "mac.h"
+#include "workarounds.h"
 
 /**************************************************************************
  *
@@ -65,48 +77,9 @@
 #define	P1_SPARE_LBN 4
 #define	P1_SPARE_WIDTH 4
 
-
-/**************************************************************************
- *
- * Temperature Sensor
- *
- **************************************************************************/
-#define	MAX6647	0x4e
-
-#define	RLTS	0x00
-#define	RLTE	0x01
-#define	RSL	0x02
-#define	RCL	0x03
-#define	RCRA	0x04
-#define	RLHN	0x05
-#define	RLLI	0x06
-#define	RRHI	0x07
-#define	RRLS	0x08
-#define	WCRW	0x0a
-#define	WLHO	0x0b
-#define	WRHA	0x0c
-#define	WRLN	0x0e
-#define	OSHT	0x0f
-#define	REET	0x10
-#define	RIET	0x11
-#define	RWOE	0x19
-#define	RWOI	0x20
-#define	HYS	0x21
-#define	QUEUE	0x22
-#define	MFID	0xfe
-#define	REVID	0xff
-
-/* Status bits */
-#define MAX6647_BUSY	(1 << 7)	/* ADC is converting */
-#define MAX6647_LHIGH	(1 << 6)	/* Local high temp. alarm */
-#define MAX6647_LLOW	(1 << 5)	/* Local low temp. alarm */
-#define MAX6647_RHIGH	(1 << 4)	/* Remote high temp. alarm */
-#define MAX6647_RLOW	(1 << 3)	/* Remote low temp. alarm */
-#define MAX6647_FAULT	(1 << 2)	/* DXN/DXP short/open circuit */
-#define MAX6647_EOT	(1 << 1)	/* Remote junction overtemp. */
-#define MAX6647_IOT	(1 << 0)	/* Local junction overtemp. */
-
-static const u8 xgphy_max_temperature = 90;
+/* Temperature Sensor */
+#define MAX664X_REG_RSL		0x02
+#define MAX664X_REG_WLHO	0x0B
 
 static void sfe4001_poweroff(struct efx_nic *efx)
 {
@@ -119,7 +92,7 @@
 	i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff);
 
 	/* Clear any over-temperature alert */
-	i2c_smbus_read_byte_data(hwmon_client, RSL);
+	i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
 }
 
 static int sfe4001_poweron(struct efx_nic *efx)
@@ -131,7 +104,7 @@
 	u8 out;
 
 	/* Clear any previous over-temperature alert */
-	rc = i2c_smbus_read_byte_data(hwmon_client, RSL);
+	rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
 	if (rc < 0)
 		return rc;
 
@@ -209,10 +182,29 @@
 	return rc;
 }
 
-/* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin
- * using the 3V3X output of the IO-expander.  Allow the user to set
- * this when the device is stopped, and keep it stopped then.
- */
+static int sfn4111t_reset(struct efx_nic *efx)
+{
+	efx_oword_t reg;
+
+	/* GPIO pins are also used for I2C, so block that temporarily */
+	mutex_lock(&efx->i2c_adap.bus_lock);
+
+	falcon_read(efx, &reg, GPIO_CTL_REG_KER);
+	EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, true);
+	EFX_SET_OWORD_FIELD(reg, GPIO2_OUT, false);
+	falcon_write(efx, &reg, GPIO_CTL_REG_KER);
+	msleep(1000);
+	EFX_SET_OWORD_FIELD(reg, GPIO2_OUT, true);
+	EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, true);
+	EFX_SET_OWORD_FIELD(reg, GPIO3_OUT,
+			    !(efx->phy_mode & PHY_MODE_SPECIAL));
+	falcon_write(efx, &reg, GPIO_CTL_REG_KER);
+
+	mutex_unlock(&efx->i2c_adap.bus_lock);
+
+	ssleep(1);
+	return 0;
+}
 
 static ssize_t show_phy_flash_cfg(struct device *dev,
 				  struct device_attribute *attr, char *buf)
@@ -241,7 +233,10 @@
 		err = -EBUSY;
 	} else {
 		efx->phy_mode = new_mode;
-		err = sfe4001_poweron(efx);
+		if (efx->board_info.type == EFX_BOARD_SFE4001)
+			err = sfe4001_poweron(efx);
+		else
+			err = sfn4111t_reset(efx);
 		efx_reconfigure_port(efx);
 	}
 	rtnl_unlock();
@@ -261,35 +256,62 @@
 	i2c_unregister_device(efx->board_info.hwmon_client);
 }
 
+static int sfe4001_check_hw(struct efx_nic *efx)
+{
+	s32 status;
+
+	/* If XAUI link is up then do not monitor */
+	if (EFX_WORKAROUND_7884(efx) && efx->mac_up)
+		return 0;
+
+	/* Check the powered status of the PHY. Lack of power implies that
+	 * the MAX6647 has shut down power to it, probably due to a temp.
+	 * alarm. Reading the power status rather than the MAX6647 status
+	 * directly because the later is read-to-clear and would thus
+	 * start to power up the PHY again when polled, causing us to blip
+	 * the power undesirably.
+	 * We know we can read from the IO expander because we did
+	 * it during power-on. Assume failure now is bad news. */
+	status = i2c_smbus_read_byte_data(efx->board_info.ioexp_client, P1_IN);
+	if (status >= 0 &&
+	    (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0)
+		return 0;
+
+	/* Use board power control, not PHY power control */
+	sfe4001_poweroff(efx);
+	efx->phy_mode = PHY_MODE_OFF;
+
+	return (status < 0) ? -EIO : -ERANGE;
+}
+
+static struct i2c_board_info sfe4001_hwmon_info = {
+	I2C_BOARD_INFO("max6647", 0x4e),
+	.irq		= -1,
+};
+
 /* This board uses an I2C expander to provider power to the PHY, which needs to
  * be turned on before the PHY can be used.
  * Context: Process context, rtnl lock held
  */
 int sfe4001_init(struct efx_nic *efx)
 {
-	struct i2c_client *hwmon_client;
 	int rc;
 
-	hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647);
-	if (!hwmon_client)
+#if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE)
+	efx->board_info.hwmon_client =
+		i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info);
+#else
+	efx->board_info.hwmon_client =
+		i2c_new_dummy(&efx->i2c_adap, sfe4001_hwmon_info.addr);
+#endif
+	if (!efx->board_info.hwmon_client)
 		return -EIO;
-	efx->board_info.hwmon_client = hwmon_client;
 
-	/* Set DSP over-temperature alert threshold */
-	EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
-	rc = i2c_smbus_write_byte_data(hwmon_client, WLHO,
-				       xgphy_max_temperature);
+	/* Raise board/PHY high limit from 85 to 90 degrees Celsius */
+	rc = i2c_smbus_write_byte_data(efx->board_info.hwmon_client,
+				       MAX664X_REG_WLHO, 90);
 	if (rc)
-		goto fail_ioexp;
-
-	/* Read it back and verify */
-	rc = i2c_smbus_read_byte_data(hwmon_client, RLHN);
-	if (rc < 0)
-		goto fail_ioexp;
-	if (rc != xgphy_max_temperature) {
-		rc = -EFAULT;
-		goto fail_ioexp;
-	}
+		goto fail_hwmon;
 
 	efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
 	if (!efx->board_info.ioexp_client) {
@@ -301,6 +323,7 @@
 	 * blink code. */
 	efx->board_info.blink = tenxpress_phy_blink;
 
+	efx->board_info.monitor = sfe4001_check_hw;
 	efx->board_info.fini = sfe4001_fini;
 
 	rc = sfe4001_poweron(efx);
@@ -319,6 +342,64 @@
 fail_ioexp:
 	i2c_unregister_device(efx->board_info.ioexp_client);
 fail_hwmon:
-	i2c_unregister_device(hwmon_client);
+	i2c_unregister_device(efx->board_info.hwmon_client);
+	return rc;
+}
+
+static int sfn4111t_check_hw(struct efx_nic *efx)
+{
+	s32 status;
+
+	/* If XAUI link is up then do not monitor */
+	if (EFX_WORKAROUND_7884(efx) && efx->mac_up)
+		return 0;
+
+	/* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */
+	status = i2c_smbus_read_byte_data(efx->board_info.hwmon_client,
+					  MAX664X_REG_RSL);
+	if (status < 0)
+		return -EIO;
+	if (status & 0x57)
+		return -ERANGE;
+	return 0;
+}
+
+static void sfn4111t_fini(struct efx_nic *efx)
+{
+	EFX_INFO(efx, "%s\n", __func__);
+
+	device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
+	i2c_unregister_device(efx->board_info.hwmon_client);
+}
+
+static struct i2c_board_info sfn4111t_hwmon_info = {
+	I2C_BOARD_INFO("max6647", 0x4e),
+	.irq		= -1,
+};
+
+int sfn4111t_init(struct efx_nic *efx)
+{
+	int rc;
+
+	efx->board_info.hwmon_client =
+		i2c_new_device(&efx->i2c_adap, &sfn4111t_hwmon_info);
+	if (!efx->board_info.hwmon_client)
+		return -EIO;
+
+	efx->board_info.blink = tenxpress_phy_blink;
+	efx->board_info.monitor = sfn4111t_check_hw;
+	efx->board_info.fini = sfn4111t_fini;
+
+	rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
+	if (rc)
+		goto fail_hwmon;
+
+	if (efx->phy_mode & PHY_MODE_SPECIAL)
+		sfn4111t_reset(efx);
+
+	return 0;
+
+fail_hwmon:
+	i2c_unregister_device(efx->board_info.hwmon_client);
 	return rc;
 }
diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h
index feef619..1b1ceb4 100644
--- a/drivers/net/sfc/spi.h
+++ b/drivers/net/sfc/spi.h
@@ -25,6 +25,7 @@
 #define SPI_WRDI 0x04		/* Reset write enable latch */
 #define SPI_RDSR 0x05		/* Read status register */
 #define SPI_WREN 0x06		/* Set write enable latch */
+#define SPI_SST_EWSR 0x50	/* SST: Enable write to status register */
 
 #define SPI_STATUS_WPEN 0x80	/* Write-protect pin enabled */
 #define SPI_STATUS_BP2 0x10	/* Block protection bit 2 */
@@ -36,6 +37,7 @@
 /**
  * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device
  * @efx:		The Efx controller that owns this device
+ * @mtd:		MTD state
  * @device_id:		Controller's id for the device
  * @size:		Size (in bytes)
  * @addr_len:		Number of address bytes in read/write commands
@@ -44,23 +46,51 @@
  *	use bit 3 of the command byte as address bit A8, rather
  *	than having a two-byte address.  If this flag is set, then
  *	commands should be munged in this way.
+ * @erase_command:	Erase command (or 0 if sector erase not needed).
+ * @erase_size:		Erase sector size (in bytes)
+ *	Erase commands affect sectors with this size and alignment.
+ *	This must be a power of two.
  * @block_size:		Write block size (in bytes).
  *	Write commands are limited to blocks with this size and alignment.
- * @read:		Read function for the device
- * @write:		Write function for the device
  */
 struct efx_spi_device {
 	struct efx_nic *efx;
+#ifdef CONFIG_SFC_MTD
+	void *mtd;
+#endif
 	int device_id;
 	unsigned int size;
 	unsigned int addr_len;
 	unsigned int munge_address:1;
+	u8 erase_command;
+	unsigned int erase_size;
 	unsigned int block_size;
 };
 
+int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command,
+		   int address, const void* in, void *out, size_t len);
+int falcon_spi_wait_write(const struct efx_spi_device *spi);
 int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
 		    size_t len, size_t *retlen, u8 *buffer);
 int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
 		     size_t len, size_t *retlen, const u8 *buffer);
 
+/*
+ * SFC4000 flash is partitioned into:
+ *     0-0x400       chip and board config (see falcon_hwdefs.h)
+ *     0x400-0x8000  unused (or may contain VPD if EEPROM not present)
+ *     0x8000-end    boot code (mapped to PCI expansion ROM)
+ * SFC4000 small EEPROM (size < 0x400) is used for VPD only.
+ * SFC4000 large EEPROM (size >= 0x400) is partitioned into:
+ *     0-0x400       chip and board config
+ *     configurable  VPD
+ *     0x800-0x1800  boot config
+ * Aside from the chip and board config, all of these are optional and may
+ * be absent or truncated depending on the devices used.
+ */
+#define FALCON_NVCONFIG_END 0x400U
+#define FALCON_FLASH_BOOTCODE_START 0x8000U
+#define EFX_EEPROM_BOOTCONFIG_START 0x800U
+#define EFX_EEPROM_BOOTCONFIG_END 0x1800U
+
 #endif /* EFX_SPI_H */
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index d507c93..b976876 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -1,6 +1,6 @@
 /****************************************************************************
- * Driver for Solarflare 802.3an compliant PHY
- * Copyright 2007 Solarflare Communications Inc.
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007-2008 Solarflare Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published
@@ -10,45 +10,76 @@
 #include <linux/delay.h>
 #include <linux/seq_file.h>
 #include "efx.h"
-#include "gmii.h"
 #include "mdio_10g.h"
 #include "falcon.h"
 #include "phy.h"
 #include "falcon_hwdefs.h"
 #include "boards.h"
-#include "mac.h"
+#include "workarounds.h"
+#include "selftest.h"
 
-/* We expect these MMDs to be in the package */
-/* AN not here as mdio_check_mmds() requires STAT2 support */
-#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PMAPMD | \
-				 MDIO_MMDREG_DEVS0_PCS    | \
-				 MDIO_MMDREG_DEVS0_PHYXS)
+/* We expect these MMDs to be in the package.  SFT9001 also has a
+ * clause 22 extension MMD, but since it doesn't have all the generic
+ * MMD registers it is pointless to include it here.
+ */
+#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PMAPMD	| \
+				 MDIO_MMDREG_DEVS_PCS		| \
+				 MDIO_MMDREG_DEVS_PHYXS		| \
+				 MDIO_MMDREG_DEVS_AN)
 
-#define TENXPRESS_LOOPBACKS ((1 << LOOPBACK_PHYXS) |	\
-			     (1 << LOOPBACK_PCS) |	\
-			     (1 << LOOPBACK_PMAPMD) |	\
-			     (1 << LOOPBACK_NETWORK))
+#define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) |	\
+			   (1 << LOOPBACK_PCS) |	\
+			   (1 << LOOPBACK_PMAPMD) |	\
+			   (1 << LOOPBACK_NETWORK))
+
+#define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) |	\
+			   (1 << LOOPBACK_PHYXS) |	\
+			   (1 << LOOPBACK_PCS) |	\
+			   (1 << LOOPBACK_PMAPMD) |	\
+			   (1 << LOOPBACK_NETWORK))
 
 /* We complain if we fail to see the link partner as 10G capable this many
  * times in a row (must be > 1 as sampling the autoneg. registers is racy)
  */
 #define MAX_BAD_LP_TRIES	(5)
 
+/* LASI Control */
+#define PMA_PMD_LASI_CTRL	36866
+#define PMA_PMD_LASI_STATUS	36869
+#define PMA_PMD_LS_ALARM_LBN	0
+#define PMA_PMD_LS_ALARM_WIDTH	1
+#define PMA_PMD_TX_ALARM_LBN	1
+#define PMA_PMD_TX_ALARM_WIDTH	1
+#define PMA_PMD_RX_ALARM_LBN	2
+#define PMA_PMD_RX_ALARM_WIDTH	1
+#define PMA_PMD_AN_ALARM_LBN	3
+#define PMA_PMD_AN_ALARM_WIDTH	1
+
 /* Extended control register */
-#define	PMA_PMD_XCONTROL_REG 0xc000
-#define	PMA_PMD_LNPGA_POWERDOWN_LBN 8
-#define	PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
+#define PMA_PMD_XCONTROL_REG	49152
+#define PMA_PMD_EXT_GMII_EN_LBN	1
+#define PMA_PMD_EXT_GMII_EN_WIDTH 1
+#define PMA_PMD_EXT_CLK_OUT_LBN	2
+#define PMA_PMD_EXT_CLK_OUT_WIDTH 1
+#define PMA_PMD_LNPGA_POWERDOWN_LBN 8	/* SFX7101 only */
+#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
+#define PMA_PMD_EXT_CLK312_LBN	8	/* SFT9001 only */
+#define PMA_PMD_EXT_CLK312_WIDTH 1
+#define PMA_PMD_EXT_LPOWER_LBN  12
+#define PMA_PMD_EXT_LPOWER_WIDTH 1
+#define PMA_PMD_EXT_SSR_LBN	15
+#define PMA_PMD_EXT_SSR_WIDTH	1
 
 /* extended status register */
-#define PMA_PMD_XSTATUS_REG 0xc001
+#define PMA_PMD_XSTATUS_REG	49153
 #define PMA_PMD_XSTAT_FLP_LBN   (12)
 
 /* LED control register */
-#define PMA_PMD_LED_CTRL_REG	(0xc007)
+#define PMA_PMD_LED_CTRL_REG	49159
 #define PMA_PMA_LED_ACTIVITY_LBN	(3)
 
 /* LED function override register */
-#define PMA_PMD_LED_OVERR_REG	(0xc009)
+#define PMA_PMD_LED_OVERR_REG	49161
 /* Bit positions for different LEDs (there are more but not wired on SFE4001)*/
 #define PMA_PMD_LED_LINK_LBN	(0)
 #define PMA_PMD_LED_SPEED_LBN	(2)
@@ -59,41 +90,99 @@
 #define	PMA_PMD_LED_ON		(1)
 #define	PMA_PMD_LED_OFF		(2)
 #define PMA_PMD_LED_FLASH	(3)
+#define PMA_PMD_LED_MASK	3
 /* All LEDs under hardware control */
 #define PMA_PMD_LED_FULL_AUTO	(0)
 /* Green and Amber under hardware control, Red off */
 #define PMA_PMD_LED_DEFAULT	(PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
 
+#define PMA_PMD_SPEED_ENABLE_REG 49192
+#define PMA_PMD_100TX_ADV_LBN    1
+#define PMA_PMD_100TX_ADV_WIDTH  1
+#define PMA_PMD_1000T_ADV_LBN    2
+#define PMA_PMD_1000T_ADV_WIDTH  1
+#define PMA_PMD_10000T_ADV_LBN   3
+#define PMA_PMD_10000T_ADV_WIDTH 1
+#define PMA_PMD_SPEED_LBN        4
+#define PMA_PMD_SPEED_WIDTH      4
 
-/* Special Software reset register */
-#define PMA_PMD_EXT_CTRL_REG 49152
-#define PMA_PMD_EXT_SSR_LBN 15
+/* Cable diagnostics - SFT9001 only */
+#define PMA_PMD_CDIAG_CTRL_REG  49213
+#define CDIAG_CTRL_IMMED_LBN    15
+#define CDIAG_CTRL_BRK_LINK_LBN 12
+#define CDIAG_CTRL_IN_PROG_LBN  11
+#define CDIAG_CTRL_LEN_UNIT_LBN 10
+#define CDIAG_CTRL_LEN_METRES   1
+#define PMA_PMD_CDIAG_RES_REG   49174
+#define CDIAG_RES_A_LBN         12
+#define CDIAG_RES_B_LBN         8
+#define CDIAG_RES_C_LBN         4
+#define CDIAG_RES_D_LBN         0
+#define CDIAG_RES_WIDTH         4
+#define CDIAG_RES_OPEN          2
+#define CDIAG_RES_OK            1
+#define CDIAG_RES_INVALID       0
+/* Set of 4 registers for pairs A-D */
+#define PMA_PMD_CDIAG_LEN_REG   49175
 
-/* Misc register defines */
-#define PCS_CLOCK_CTRL_REG 0xd801
+/* Serdes control registers - SFT9001 only */
+#define PMA_PMD_CSERDES_CTRL_REG 64258
+/* Set the 156.25 MHz output to 312.5 MHz to drive Falcon's XMAC */
+#define PMA_PMD_CSERDES_DEFAULT	0x000f
+
+/* Misc register defines - SFX7101 only */
+#define PCS_CLOCK_CTRL_REG	55297
 #define PLL312_RST_N_LBN 2
 
-#define PCS_SOFT_RST2_REG 0xd806
+#define PCS_SOFT_RST2_REG	55302
 #define SERDES_RST_N_LBN 13
 #define XGXS_RST_N_LBN 12
 
-#define	PCS_TEST_SELECT_REG 0xd807	/* PRM 10.5.8 */
+#define	PCS_TEST_SELECT_REG	55303	/* PRM 10.5.8 */
 #define	CLK312_EN_LBN 3
 
 /* PHYXS registers */
+#define PHYXS_XCONTROL_REG	49152
+#define PHYXS_RESET_LBN		15
+#define PHYXS_RESET_WIDTH	1
+
 #define PHYXS_TEST1         (49162)
 #define LOOPBACK_NEAR_LBN   (8)
 #define LOOPBACK_NEAR_WIDTH (1)
 
+#define PCS_10GBASET_STAT1       32
+#define PCS_10GBASET_BLKLK_LBN   0
+#define PCS_10GBASET_BLKLK_WIDTH 1
+
 /* Boot status register */
-#define PCS_BOOT_STATUS_REG	(0xd000)
+#define PCS_BOOT_STATUS_REG	53248
 #define PCS_BOOT_FATAL_ERR_LBN	(0)
 #define PCS_BOOT_PROGRESS_LBN	(1)
 #define PCS_BOOT_PROGRESS_WIDTH	(2)
 #define PCS_BOOT_COMPLETE_LBN	(3)
+
 #define PCS_BOOT_MAX_DELAY	(100)
 #define PCS_BOOT_POLL_DELAY	(10)
 
+/* 100M/1G PHY registers */
+#define GPHY_XCONTROL_REG	49152
+#define GPHY_ISOLATE_LBN	10
+#define GPHY_ISOLATE_WIDTH	1
+#define GPHY_DUPLEX_LBN	  	8
+#define GPHY_DUPLEX_WIDTH	1
+#define GPHY_LOOPBACK_NEAR_LBN	14
+#define GPHY_LOOPBACK_NEAR_WIDTH 1
+
+#define C22EXT_STATUS_REG       49153
+#define C22EXT_STATUS_LINK_LBN  2
+#define C22EXT_STATUS_LINK_WIDTH 1
+
+#define C22EXT_MSTSLV_REG       49162
+#define C22EXT_MSTSLV_1000_HD_LBN 10
+#define C22EXT_MSTSLV_1000_HD_WIDTH 1
+#define C22EXT_MSTSLV_1000_FD_LBN 11
+#define C22EXT_MSTSLV_1000_FD_WIDTH 1
+
 /* Time to wait between powering down the LNPGA and turning off the power
  * rails */
 #define LNPGA_PDOWN_WAIT	(HZ / 5)
@@ -117,6 +206,38 @@
 		atomic_inc(&phy_data->bad_crc_count);
 }
 
+static ssize_t show_phy_short_reach(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+	int reg;
+
+	reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+				 MDIO_PMAPMD_10GBT_TXPWR);
+	return sprintf(buf, "%d\n",
+		       !!(reg & (1 << MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN)));
+}
+
+static ssize_t set_phy_short_reach(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+
+	rtnl_lock();
+	mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+			       MDIO_PMAPMD_10GBT_TXPWR,
+			       MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN,
+			       count != 0 && *buf != '0');
+	efx_reconfigure_port(efx);
+	rtnl_unlock();
+
+	return count;
+}
+
+static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach,
+		   set_phy_short_reach);
+
 /* Check that the C166 has booted successfully */
 static int tenxpress_phy_check(struct efx_nic *efx)
 {
@@ -148,27 +269,42 @@
 
 static int tenxpress_init(struct efx_nic *efx)
 {
-	int rc, reg;
+	int phy_id = efx->mii.phy_id;
+	int reg;
+	int rc;
 
-	/* Turn on the clock  */
-	reg = (1 << CLK312_EN_LBN);
-	mdio_clause45_write(efx, efx->mii.phy_id,
-			    MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg);
+	if (efx->phy_type == PHY_TYPE_SFX7101) {
+		/* Enable 312.5 MHz clock */
+		mdio_clause45_write(efx, phy_id,
+				    MDIO_MMD_PCS, PCS_TEST_SELECT_REG,
+				    1 << CLK312_EN_LBN);
+	} else {
+		/* Enable 312.5 MHz clock and GMII */
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+					 PMA_PMD_XCONTROL_REG);
+		reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) |
+			(1 << PMA_PMD_EXT_CLK_OUT_LBN) |
+			(1 << PMA_PMD_EXT_CLK312_LBN));
+		mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
+				    PMA_PMD_XCONTROL_REG, reg);
+		mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT,
+				       GPHY_XCONTROL_REG, GPHY_ISOLATE_LBN,
+				       false);
+	}
 
 	rc = tenxpress_phy_check(efx);
 	if (rc < 0)
 		return rc;
 
 	/* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
-	reg = mdio_clause45_read(efx, efx->mii.phy_id,
-				 MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG);
-	reg |= (1 << PMA_PMA_LED_ACTIVITY_LBN);
-	mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-			    PMA_PMD_LED_CTRL_REG, reg);
-
-	reg = PMA_PMD_LED_DEFAULT;
-	mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-			    PMA_PMD_LED_OVERR_REG, reg);
+	if (efx->phy_type == PHY_TYPE_SFX7101) {
+		mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD,
+				       PMA_PMD_LED_CTRL_REG,
+				       PMA_PMA_LED_ACTIVITY_LBN,
+				       true);
+		mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
+				    PMA_PMD_LED_OVERR_REG, PMA_PMD_LED_DEFAULT);
+	}
 
 	return rc;
 }
@@ -184,22 +320,43 @@
 	efx->phy_data = phy_data;
 	phy_data->phy_mode = efx->phy_mode;
 
-	rc = mdio_clause45_wait_reset_mmds(efx,
-					   TENXPRESS_REQUIRED_DEVS);
-	if (rc < 0)
-		goto fail;
+	if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {
+		if (efx->phy_type == PHY_TYPE_SFT9001A) {
+			int reg;
+			reg = mdio_clause45_read(efx, efx->mii.phy_id,
+						 MDIO_MMD_PMAPMD,
+						 PMA_PMD_XCONTROL_REG);
+			reg |= (1 << PMA_PMD_EXT_SSR_LBN);
+			mdio_clause45_write(efx, efx->mii.phy_id,
+					    MDIO_MMD_PMAPMD,
+					    PMA_PMD_XCONTROL_REG, reg);
+			mdelay(200);
+		}
 
-	rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
-	if (rc < 0)
-		goto fail;
+		rc = mdio_clause45_wait_reset_mmds(efx,
+						   TENXPRESS_REQUIRED_DEVS);
+		if (rc < 0)
+			goto fail;
+
+		rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
+		if (rc < 0)
+			goto fail;
+	}
 
 	rc = tenxpress_init(efx);
 	if (rc < 0)
 		goto fail;
 
+	if (efx->phy_type == PHY_TYPE_SFT9001B) {
+		rc = device_create_file(&efx->pci_dev->dev,
+					&dev_attr_phy_short_reach);
+		if (rc)
+			goto fail;
+	}
+
 	schedule_timeout_uninterruptible(HZ / 5); /* 200ms */
 
-	/* Let XGXS and SerDes out of reset and resets 10XPress */
+	/* Let XGXS and SerDes out of reset */
 	falcon_reset_xaui(efx);
 
 	return 0;
@@ -210,21 +367,24 @@
 	return rc;
 }
 
+/* Perform a "special software reset" on the PHY. The caller is
+ * responsible for saving and restoring the PHY hardware registers
+ * properly, and masking/unmasking LASI */
 static int tenxpress_special_reset(struct efx_nic *efx)
 {
 	int rc, reg;
 
 	/* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so
 	 * a special software reset can glitch the XGMAC sufficiently for stats
-	 * requests to fail. Since we don't ofen special_reset, just lock. */
+	 * requests to fail. Since we don't often special_reset, just lock. */
 	spin_lock(&efx->stats_lock);
 
 	/* Initiate reset */
 	reg = mdio_clause45_read(efx, efx->mii.phy_id,
-				 MDIO_MMD_PMAPMD, PMA_PMD_EXT_CTRL_REG);
+				 MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
 	reg |= (1 << PMA_PMD_EXT_SSR_LBN);
 	mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-			    PMA_PMD_EXT_CTRL_REG, reg);
+			    PMA_PMD_XCONTROL_REG, reg);
 
 	mdelay(200);
 
@@ -239,174 +399,257 @@
 	if (rc < 0)
 		goto unlock;
 
+	/* Wait for the XGXS state machine to churn */
+	mdelay(10);
 unlock:
 	spin_unlock(&efx->stats_lock);
 	return rc;
 }
 
-static void tenxpress_set_bad_lp(struct efx_nic *efx, bool bad_lp)
+static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok)
 {
 	struct tenxpress_phy_data *pd = efx->phy_data;
+	int phy_id = efx->mii.phy_id;
+	bool bad_lp;
 	int reg;
 
+	if (link_ok) {
+		bad_lp = false;
+	} else {
+		/* Check that AN has started but not completed. */
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
+					 MDIO_AN_STATUS);
+		if (!(reg & (1 << MDIO_AN_STATUS_LP_AN_CAP_LBN)))
+			return; /* LP status is unknown */
+		bad_lp = !(reg & (1 << MDIO_AN_STATUS_AN_DONE_LBN));
+		if (bad_lp)
+			pd->bad_lp_tries++;
+	}
+
 	/* Nothing to do if all is well and was previously so. */
-	if (!(bad_lp || pd->bad_lp_tries))
+	if (!pd->bad_lp_tries)
 		return;
 
-	reg = mdio_clause45_read(efx, efx->mii.phy_id,
-				 MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG);
-
-	if (bad_lp)
-		pd->bad_lp_tries++;
-	else
-		pd->bad_lp_tries = 0;
-
-	if (pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
-		pd->bad_lp_tries = 0;	/* Restart count */
-		reg &= ~(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
-		reg |= (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
-		EFX_ERR(efx, "This NIC appears to be plugged into"
-			" a port that is not 10GBASE-T capable.\n"
-			" This PHY is 10GBASE-T ONLY, so no link can"
-			" be established.\n");
-	} else {
-		reg |= (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN);
+	/* Use the RX (red) LED as an error indicator once we've seen AN
+	 * failure several times in a row, and also log a message. */
+	if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+					 PMA_PMD_LED_OVERR_REG);
+		reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN);
+		if (!bad_lp) {
+			reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN;
+		} else {
+			reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN;
+			EFX_ERR(efx, "appears to be plugged into a port"
+				" that is not 10GBASE-T capable. The PHY"
+				" supports 10GBASE-T ONLY, so no link can"
+				" be established\n");
+		}
+		mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
+				    PMA_PMD_LED_OVERR_REG, reg);
+		pd->bad_lp_tries = bad_lp;
 	}
-	mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-			    PMA_PMD_LED_OVERR_REG, reg);
 }
 
-/* Check link status and return a boolean OK value. If the link is NOT
- * OK we have a quick rummage round to see if we appear to be plugged
- * into a non-10GBT port and if so warn the user that they won't get
- * link any time soon as we are 10GBT only, unless caller specified
- * not to do this check (it isn't useful in loopback) */
-static bool tenxpress_link_ok(struct efx_nic *efx, bool check_lp)
+static bool sfx7101_link_ok(struct efx_nic *efx)
 {
-	bool ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS);
-
-	if (ok) {
-		tenxpress_set_bad_lp(efx, false);
-	} else if (check_lp) {
-		/* Are we plugged into the wrong sort of link? */
-		bool bad_lp = false;
-		int phy_id = efx->mii.phy_id;
-		int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
-						 MDIO_AN_STATUS);
-		int xphy_stat = mdio_clause45_read(efx, phy_id,
-						   MDIO_MMD_PMAPMD,
-						   PMA_PMD_XSTATUS_REG);
-		/* Are we plugged into anything that sends FLPs? If
-		 * not we can't distinguish between not being plugged
-		 * in and being plugged into a non-AN antique. The FLP
-		 * bit has the advantage of not clearing when autoneg
-		 * restarts. */
-		if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) {
-			tenxpress_set_bad_lp(efx, false);
-			return ok;
-		}
-
-		/* If it can do 10GBT it must be XNP capable */
-		bad_lp = !(an_stat & (1 << MDIO_AN_STATUS_XNP_LBN));
-		if (!bad_lp && (an_stat & (1 << MDIO_AN_STATUS_PAGE_LBN))) {
-			bad_lp = !(mdio_clause45_read(efx, phy_id,
-					MDIO_MMD_AN, MDIO_AN_10GBT_STATUS) &
-					(1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN));
-		}
-		tenxpress_set_bad_lp(efx, bad_lp);
-	}
-	return ok;
+	return mdio_clause45_links_ok(efx,
+				      MDIO_MMDREG_DEVS_PMAPMD |
+				      MDIO_MMDREG_DEVS_PCS |
+				      MDIO_MMDREG_DEVS_PHYXS);
 }
 
-static void tenxpress_phyxs_loopback(struct efx_nic *efx)
+static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 {
 	int phy_id = efx->mii.phy_id;
-	int ctrl1, ctrl2;
+	u32 reg;
 
-	ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
-					   PHYXS_TEST1);
-	if (efx->loopback_mode == LOOPBACK_PHYXS)
-		ctrl2 |= (1 << LOOPBACK_NEAR_LBN);
+	if (efx_phy_mode_disabled(efx->phy_mode))
+		return false;
+	else if (efx->loopback_mode == LOOPBACK_GPHY)
+		return true;
+	else if (efx->loopback_mode)
+		return mdio_clause45_links_ok(efx,
+					      MDIO_MMDREG_DEVS_PMAPMD |
+					      MDIO_MMDREG_DEVS_PHYXS);
+
+	/* We must use the same definition of link state as LASI,
+	 * otherwise we can miss a link state transition
+	 */
+	if (ecmd->speed == 10000) {
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
+					 PCS_10GBASET_STAT1);
+		return reg & (1 << PCS_10GBASET_BLKLK_LBN);
+	} else {
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT,
+					 C22EXT_STATUS_REG);
+		return reg & (1 << C22EXT_STATUS_LINK_LBN);
+	}
+}
+
+static void tenxpress_ext_loopback(struct efx_nic *efx)
+{
+	int phy_id = efx->mii.phy_id;
+
+	mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS,
+			       PHYXS_TEST1, LOOPBACK_NEAR_LBN,
+			       efx->loopback_mode == LOOPBACK_PHYXS);
+	if (efx->phy_type != PHY_TYPE_SFX7101)
+		mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT,
+				       GPHY_XCONTROL_REG,
+				       GPHY_LOOPBACK_NEAR_LBN,
+				       efx->loopback_mode == LOOPBACK_GPHY);
+}
+
+static void tenxpress_low_power(struct efx_nic *efx)
+{
+	int phy_id = efx->mii.phy_id;
+
+	if (efx->phy_type == PHY_TYPE_SFX7101)
+		mdio_clause45_set_mmds_lpower(
+			efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER),
+			TENXPRESS_REQUIRED_DEVS);
 	else
-		ctrl2 &= ~(1 << LOOPBACK_NEAR_LBN);
-	if (ctrl1 != ctrl2)
-		mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS,
-				    PHYXS_TEST1, ctrl2);
+		mdio_clause45_set_flag(
+			efx, phy_id, MDIO_MMD_PMAPMD,
+			PMA_PMD_XCONTROL_REG, PMA_PMD_EXT_LPOWER_LBN,
+			!!(efx->phy_mode & PHY_MODE_LOW_POWER));
 }
 
 static void tenxpress_phy_reconfigure(struct efx_nic *efx)
 {
 	struct tenxpress_phy_data *phy_data = efx->phy_data;
-	bool loop_change = LOOPBACK_OUT_OF(phy_data, efx,
-					   TENXPRESS_LOOPBACKS);
+	struct ethtool_cmd ecmd;
+	bool phy_mode_change, loop_reset, loop_toggle, loopback;
 
-	if (efx->phy_mode & PHY_MODE_SPECIAL) {
+	if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) {
 		phy_data->phy_mode = efx->phy_mode;
 		return;
 	}
 
-	/* When coming out of transmit disable, coming out of low power
-	 * mode, or moving out of any PHY internal loopback mode,
-	 * perform a special software reset */
-	if ((efx->phy_mode == PHY_MODE_NORMAL &&
-	     phy_data->phy_mode != PHY_MODE_NORMAL) ||
-	    loop_change) {
-		tenxpress_special_reset(efx);
-		falcon_reset_xaui(efx);
+	tenxpress_low_power(efx);
+
+	phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL &&
+			   phy_data->phy_mode != PHY_MODE_NORMAL);
+	loopback = LOOPBACK_MASK(efx) & efx->phy_op->loopbacks;
+	loop_toggle = LOOPBACK_CHANGED(phy_data, efx, efx->phy_op->loopbacks);
+	loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) ||
+		      LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY));
+
+	if (loop_reset || loop_toggle || loopback || phy_mode_change) {
+		int rc;
+
+		efx->phy_op->get_settings(efx, &ecmd);
+
+		if (loop_reset || phy_mode_change) {
+			tenxpress_special_reset(efx);
+
+			/* Reset XAUI if we were in 10G, and are staying
+			 * in 10G. If we're moving into and out of 10G
+			 * then xaui will be reset anyway */
+			if (EFX_IS10G(efx))
+				falcon_reset_xaui(efx);
+		}
+
+		if (efx->phy_type != PHY_TYPE_SFX7101) {
+			/* Only change autoneg once, on coming out or
+			 * going into loopback */
+			if (loop_toggle)
+				ecmd.autoneg = !loopback;
+			if (loopback) {
+				ecmd.duplex = DUPLEX_FULL;
+				if (efx->loopback_mode == LOOPBACK_GPHY)
+					ecmd.speed = SPEED_1000;
+				else
+					ecmd.speed = SPEED_10000;
+			}
+		}
+
+		rc = efx->phy_op->set_settings(efx, &ecmd);
+		WARN_ON(rc);
 	}
 
 	mdio_clause45_transmit_disable(efx);
 	mdio_clause45_phy_reconfigure(efx);
-	tenxpress_phyxs_loopback(efx);
+	tenxpress_ext_loopback(efx);
 
 	phy_data->loopback_mode = efx->loopback_mode;
 	phy_data->phy_mode = efx->phy_mode;
-	efx->link_up = tenxpress_link_ok(efx, false);
-	efx->link_options = GM_LPA_10000FULL;
-}
 
-static void tenxpress_phy_clear_interrupt(struct efx_nic *efx)
-{
-	/* Nothing done here - LASI interrupts aren't reliable so poll  */
+	if (efx->phy_type == PHY_TYPE_SFX7101) {
+		efx->link_speed = 10000;
+		efx->link_fd = true;
+		efx->link_up = sfx7101_link_ok(efx);
+	} else {
+		efx->phy_op->get_settings(efx, &ecmd);
+		efx->link_speed = ecmd.speed;
+		efx->link_fd = ecmd.duplex == DUPLEX_FULL;
+		efx->link_up = sft9001_link_ok(efx, &ecmd);
+	}
+	efx->link_fc = mdio_clause45_get_pause(efx);
 }
 
-
 /* Poll PHY for interrupt */
-static int tenxpress_phy_check_hw(struct efx_nic *efx)
+static void tenxpress_phy_poll(struct efx_nic *efx)
 {
 	struct tenxpress_phy_data *phy_data = efx->phy_data;
-	bool link_ok;
+	bool change = false, link_ok;
+	unsigned link_fc;
 
-	link_ok = tenxpress_link_ok(efx, true);
+	if (efx->phy_type == PHY_TYPE_SFX7101) {
+		link_ok = sfx7101_link_ok(efx);
+		if (link_ok != efx->link_up) {
+			change = true;
+		} else {
+			link_fc = mdio_clause45_get_pause(efx);
+			if (link_fc != efx->link_fc)
+				change = true;
+		}
+		sfx7101_check_bad_lp(efx, link_ok);
+	} else if (efx->loopback_mode) {
+		bool link_ok = sft9001_link_ok(efx, NULL);
+		if (link_ok != efx->link_up)
+			change = true;
+	} else {
+		u32 status = mdio_clause45_read(efx, efx->mii.phy_id,
+						MDIO_MMD_PMAPMD,
+						PMA_PMD_LASI_STATUS);
+		if (status & (1 << PMA_PMD_LS_ALARM_LBN))
+			change = true;
+	}
 
-	if (link_ok != efx->link_up)
-		falcon_xmac_sim_phy_event(efx);
+	if (change)
+		falcon_sim_phy_event(efx);
 
 	if (phy_data->phy_mode != PHY_MODE_NORMAL)
-		return 0;
+		return;
 
-	if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) {
+	if (EFX_WORKAROUND_10750(efx) &&
+	    atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) {
 		EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n");
 		falcon_reset_xaui(efx);
 		atomic_set(&phy_data->bad_crc_count, 0);
 	}
-
-	return 0;
 }
 
 static void tenxpress_phy_fini(struct efx_nic *efx)
 {
 	int reg;
 
-	/* Power down the LNPGA */
-	reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
-	mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-			    PMA_PMD_XCONTROL_REG, reg);
+	if (efx->phy_type == PHY_TYPE_SFT9001B) {
+		device_remove_file(&efx->pci_dev->dev,
+				   &dev_attr_phy_short_reach);
+	} else {
+		/* Power down the LNPGA */
+		reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
+		mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+				    PMA_PMD_XCONTROL_REG, reg);
 
-	/* Waiting here ensures that the board fini, which can turn off the
-	 * power to the PHY, won't get run until the LNPGA powerdown has been
-	 * given long enough to complete. */
-	schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
+		/* Waiting here ensures that the board fini, which can turn
+		 * off the power to the PHY, won't get run until the LNPGA
+		 * powerdown has been given long enough to complete. */
+		schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
+	}
 
 	kfree(efx->phy_data);
 	efx->phy_data = NULL;
@@ -430,19 +673,236 @@
 			    PMA_PMD_LED_OVERR_REG, reg);
 }
 
-static int tenxpress_phy_test(struct efx_nic *efx)
+static const char *const sfx7101_test_names[] = {
+	"bist"
+};
+
+static int
+sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags)
 {
+	int rc;
+
+	if (!(flags & ETH_TEST_FL_OFFLINE))
+		return 0;
+
 	/* BIST is automatically run after a special software reset */
-	return tenxpress_special_reset(efx);
+	rc = tenxpress_special_reset(efx);
+	results[0] = rc ? -1 : 1;
+	return rc;
 }
 
-struct efx_phy_operations falcon_tenxpress_phy_ops = {
+static const char *const sft9001_test_names[] = {
+	"bist",
+	"cable.pairA.status",
+	"cable.pairB.status",
+	"cable.pairC.status",
+	"cable.pairD.status",
+	"cable.pairA.length",
+	"cable.pairB.length",
+	"cable.pairC.length",
+	"cable.pairD.length",
+};
+
+static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
+{
+	struct ethtool_cmd ecmd;
+	int phy_id = efx->mii.phy_id;
+	int rc = 0, rc2, i, res_reg;
+
+	if (!(flags & ETH_TEST_FL_OFFLINE))
+		return 0;
+
+	efx->phy_op->get_settings(efx, &ecmd);
+
+	/* Initialise cable diagnostic results to unknown failure */
+	for (i = 1; i < 9; ++i)
+		results[i] = -1;
+
+	/* Run cable diagnostics; wait up to 5 seconds for them to complete.
+	 * A cable fault is not a self-test failure, but a timeout is. */
+	mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
+			    PMA_PMD_CDIAG_CTRL_REG,
+			    (1 << CDIAG_CTRL_IMMED_LBN) |
+			    (1 << CDIAG_CTRL_BRK_LINK_LBN) |
+			    (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN));
+	i = 0;
+	while (mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+				  PMA_PMD_CDIAG_CTRL_REG) &
+	       (1 << CDIAG_CTRL_IN_PROG_LBN)) {
+		if (++i == 50) {
+			rc = -ETIMEDOUT;
+			goto reset;
+		}
+		msleep(100);
+	}
+	res_reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+				     PMA_PMD_CDIAG_RES_REG);
+	for (i = 0; i < 4; i++) {
+		int pair_res =
+			(res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH))
+			& ((1 << CDIAG_RES_WIDTH) - 1);
+		int len_reg = mdio_clause45_read(efx, efx->mii.phy_id,
+						 MDIO_MMD_PMAPMD,
+						 PMA_PMD_CDIAG_LEN_REG + i);
+		if (pair_res == CDIAG_RES_OK)
+			results[1 + i] = 1;
+		else if (pair_res == CDIAG_RES_INVALID)
+			results[1 + i] = -1;
+		else
+			results[1 + i] = -pair_res;
+		if (pair_res != CDIAG_RES_INVALID &&
+		    pair_res != CDIAG_RES_OPEN &&
+		    len_reg != 0xffff)
+			results[5 + i] = len_reg;
+	}
+
+	/* We must reset to exit cable diagnostic mode.  The BIST will
+	 * also run when we do this. */
+reset:
+	rc2 = tenxpress_special_reset(efx);
+	results[0] = rc2 ? -1 : 1;
+	if (!rc)
+		rc = rc2;
+
+	rc2 = efx->phy_op->set_settings(efx, &ecmd);
+	if (!rc)
+		rc = rc2;
+
+	return rc;
+}
+
+static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx)
+{
+	int phy = efx->mii.phy_id;
+	u32 lpa = 0;
+	int reg;
+
+	if (efx->phy_type != PHY_TYPE_SFX7101) {
+		reg = mdio_clause45_read(efx, phy, MDIO_MMD_C22EXT,
+					 C22EXT_MSTSLV_REG);
+		if (reg & (1 << C22EXT_MSTSLV_1000_HD_LBN))
+			lpa |= ADVERTISED_1000baseT_Half;
+		if (reg & (1 << C22EXT_MSTSLV_1000_FD_LBN))
+			lpa |= ADVERTISED_1000baseT_Full;
+	}
+	reg = mdio_clause45_read(efx, phy, MDIO_MMD_AN, MDIO_AN_10GBT_STATUS);
+	if (reg & (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN))
+		lpa |= ADVERTISED_10000baseT_Full;
+	return lpa;
+}
+
+static void sfx7101_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+	mdio_clause45_get_settings_ext(efx, ecmd, ADVERTISED_10000baseT_Full,
+				       tenxpress_get_xnp_lpa(efx));
+	ecmd->supported |= SUPPORTED_10000baseT_Full;
+	ecmd->advertising |= ADVERTISED_10000baseT_Full;
+}
+
+static void sft9001_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+	int phy_id = efx->mii.phy_id;
+	u32 xnp_adv = 0;
+	int reg;
+
+	reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+				 PMA_PMD_SPEED_ENABLE_REG);
+	if (EFX_WORKAROUND_13204(efx) && (reg & (1 << PMA_PMD_100TX_ADV_LBN)))
+		xnp_adv |= ADVERTISED_100baseT_Full;
+	if (reg & (1 << PMA_PMD_1000T_ADV_LBN))
+		xnp_adv |= ADVERTISED_1000baseT_Full;
+	if (reg & (1 << PMA_PMD_10000T_ADV_LBN))
+		xnp_adv |= ADVERTISED_10000baseT_Full;
+
+	mdio_clause45_get_settings_ext(efx, ecmd, xnp_adv,
+				       tenxpress_get_xnp_lpa(efx));
+
+	ecmd->supported |= (SUPPORTED_100baseT_Half |
+			    SUPPORTED_100baseT_Full |
+			    SUPPORTED_1000baseT_Full);
+
+	/* Use the vendor defined C22ext register for duplex settings */
+	if (ecmd->speed != SPEED_10000 && !ecmd->autoneg) {
+		reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT,
+					 GPHY_XCONTROL_REG);
+		ecmd->duplex = (reg & (1 << GPHY_DUPLEX_LBN) ?
+				DUPLEX_FULL : DUPLEX_HALF);
+	}
+}
+
+static int sft9001_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+	int phy_id = efx->mii.phy_id;
+	int rc;
+
+	rc = mdio_clause45_set_settings(efx, ecmd);
+	if (rc)
+		return rc;
+
+	if (ecmd->speed != SPEED_10000 && !ecmd->autoneg)
+		mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT,
+				       GPHY_XCONTROL_REG, GPHY_DUPLEX_LBN,
+				       ecmd->duplex == DUPLEX_FULL);
+
+	return rc;
+}
+
+static bool sft9001_set_xnp_advertise(struct efx_nic *efx, u32 advertising)
+{
+	int phy = efx->mii.phy_id;
+	int reg = mdio_clause45_read(efx, phy, MDIO_MMD_PMAPMD,
+				     PMA_PMD_SPEED_ENABLE_REG);
+	bool enabled;
+
+	reg &= ~((1 << 2) | (1 << 3));
+	if (EFX_WORKAROUND_13204(efx) &&
+	    (advertising & ADVERTISED_100baseT_Full))
+		reg |= 1 << PMA_PMD_100TX_ADV_LBN;
+	if (advertising & ADVERTISED_1000baseT_Full)
+		reg |= 1 << PMA_PMD_1000T_ADV_LBN;
+	if (advertising & ADVERTISED_10000baseT_Full)
+		reg |= 1 << PMA_PMD_10000T_ADV_LBN;
+	mdio_clause45_write(efx, phy, MDIO_MMD_PMAPMD,
+			    PMA_PMD_SPEED_ENABLE_REG, reg);
+
+	enabled = (advertising &
+		   (ADVERTISED_1000baseT_Half |
+		    ADVERTISED_1000baseT_Full |
+		    ADVERTISED_10000baseT_Full));
+	if (EFX_WORKAROUND_13204(efx))
+		enabled |= (advertising & ADVERTISED_100baseT_Full);
+	return enabled;
+}
+
+struct efx_phy_operations falcon_sfx7101_phy_ops = {
+	.macs		  = EFX_XMAC,
 	.init             = tenxpress_phy_init,
 	.reconfigure      = tenxpress_phy_reconfigure,
-	.check_hw         = tenxpress_phy_check_hw,
+	.poll             = tenxpress_phy_poll,
 	.fini             = tenxpress_phy_fini,
-	.clear_interrupt  = tenxpress_phy_clear_interrupt,
-	.test             = tenxpress_phy_test,
+	.clear_interrupt  = efx_port_dummy_op_void,
+	.get_settings	  = sfx7101_get_settings,
+	.set_settings	  = mdio_clause45_set_settings,
+	.num_tests	  = ARRAY_SIZE(sfx7101_test_names),
+	.test_names	  = sfx7101_test_names,
+	.run_tests	  = sfx7101_run_tests,
 	.mmds             = TENXPRESS_REQUIRED_DEVS,
-	.loopbacks        = TENXPRESS_LOOPBACKS,
+	.loopbacks        = SFX7101_LOOPBACKS,
+};
+
+struct efx_phy_operations falcon_sft9001_phy_ops = {
+	.macs		  = EFX_GMAC | EFX_XMAC,
+	.init             = tenxpress_phy_init,
+	.reconfigure      = tenxpress_phy_reconfigure,
+	.poll             = tenxpress_phy_poll,
+	.fini             = tenxpress_phy_fini,
+	.clear_interrupt  = efx_port_dummy_op_void,
+	.get_settings	  = sft9001_get_settings,
+	.set_settings	  = sft9001_set_settings,
+	.set_xnp_advertise = sft9001_set_xnp_advertise,
+	.num_tests	  = ARRAY_SIZE(sft9001_test_names),
+	.test_names	  = sft9001_test_names,
+	.run_tests	  = sft9001_run_tests,
+	.mmds             = TENXPRESS_REQUIRED_DEVS,
+	.loopbacks        = SFT9001_LOOPBACKS,
 };
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index fa7b49d..82e03e1 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -17,15 +17,20 @@
 
 #define EFX_WORKAROUND_ALWAYS(efx) 1
 #define EFX_WORKAROUND_FALCON_A(efx) (falcon_rev(efx) <= FALCON_REV_A1)
+#define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx)
+#define EFX_WORKAROUND_SFX7101(efx) ((efx)->phy_type == PHY_TYPE_SFX7101)
+#define EFX_WORKAROUND_SFT9001A(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A)
 
 /* XAUI resets if link not detected */
 #define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
 /* RX PCIe double split performance issue */
 #define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS
+/* Bit-bashed I2C reads cause performance drop */
+#define EFX_WORKAROUND_7884 EFX_WORKAROUND_10G
 /* TX pkt parser problem with <= 16 byte TXes */
 #define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS
 /* Low rate CRC errors require XAUI reset */
-#define EFX_WORKAROUND_10750 EFX_WORKAROUND_ALWAYS
+#define EFX_WORKAROUND_10750 EFX_WORKAROUND_SFX7101
 /* TX_EV_PKT_ERR can be caused by a dangling TX descriptor
  * or a PCIe error (bug 11028) */
 #define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS
@@ -49,4 +54,9 @@
 /* Leak overlength packets rather than free */
 #define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
 
+/* Need to send XNP pages for 100BaseT */
+#define EFX_WORKAROUND_13204 EFX_WORKAROUND_SFT9001A
+/* Need to keep AN enabled */
+#define EFX_WORKAROUND_13963 EFX_WORKAROUND_SFT9001A
+
 #endif /* EFX_WORKAROUNDS_H */
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c
index 276151d..2d50b6e 100644
--- a/drivers/net/sfc/xfp_phy.c
+++ b/drivers/net/sfc/xfp_phy.c
@@ -7,22 +7,21 @@
  * by the Free Software Foundation, incorporated herein by reference.
  */
 /*
- * Driver for XFP optical PHYs (plus some support specific to the Quake 2032)
+ * Driver for XFP optical PHYs (plus some support specific to the Quake 2022/32)
  * See www.amcc.com for details (search for qt2032)
  */
 
 #include <linux/timer.h>
 #include <linux/delay.h>
 #include "efx.h"
-#include "gmii.h"
 #include "mdio_10g.h"
 #include "xenpack.h"
 #include "phy.h"
-#include "mac.h"
+#include "falcon.h"
 
-#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PCS |	\
-			   MDIO_MMDREG_DEVS0_PMAPMD |	\
-			   MDIO_MMDREG_DEVS0_PHYXS)
+#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PCS |	\
+			   MDIO_MMDREG_DEVS_PMAPMD |	\
+			   MDIO_MMDREG_DEVS_PHYXS)
 
 #define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) |		\
 		       (1 << LOOPBACK_PMAPMD) |		\
@@ -65,7 +64,7 @@
 	/* Check that all the MMDs we expect are present and responding. We
 	 * expect faults on some if the link is down, but not on the PHY XS */
 	rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS,
-				      MDIO_MMDREG_DEVS0_PHYXS);
+				      MDIO_MMDREG_DEVS_PHYXS);
 	if (rc < 0)
 		goto fail;
 
@@ -120,15 +119,12 @@
 	return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS);
 }
 
-static int xfp_phy_check_hw(struct efx_nic *efx)
+static void xfp_phy_poll(struct efx_nic *efx)
 {
-	int rc = 0;
 	int link_up = xfp_link_ok(efx);
 	/* Simulate a PHY event if link state has changed */
 	if (link_up != efx->link_up)
-		falcon_xmac_sim_phy_event(efx);
-
-	return rc;
+		falcon_sim_phy_event(efx);
 }
 
 static void xfp_phy_reconfigure(struct efx_nic *efx)
@@ -145,7 +141,9 @@
 
 	phy_data->phy_mode = efx->phy_mode;
 	efx->link_up = xfp_link_ok(efx);
-	efx->link_options = GM_LPA_10000FULL;
+	efx->link_speed = 10000;
+	efx->link_fd = true;
+	efx->link_fc = efx->wanted_fc;
 }
 
 
@@ -160,11 +158,14 @@
 }
 
 struct efx_phy_operations falcon_xfp_phy_ops = {
+	.macs		 = EFX_XMAC,
 	.init            = xfp_phy_init,
 	.reconfigure     = xfp_phy_reconfigure,
-	.check_hw        = xfp_phy_check_hw,
+	.poll            = xfp_phy_poll,
 	.fini            = xfp_phy_fini,
 	.clear_interrupt = xfp_phy_clear_interrupt,
+	.get_settings    = mdio_clause45_get_settings,
+	.set_settings	 = mdio_clause45_set_settings,
 	.mmds            = XFP_REQUIRED_DEVS,
 	.loopbacks       = XFP_LOOPBACKS,
 };
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 6261201..97d6856 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -377,7 +377,6 @@
 					skb_put(skb, len);
 					skb->protocol = eth_type_trans(skb, dev);
 					netif_rx(skb);
-					dev->last_rx = jiffies;
 					dev->stats.rx_packets++;
 					dev->stats.rx_bytes += len;
 				} else {
@@ -657,7 +656,7 @@
 
 static void sgiseeq_set_multicast(struct net_device *dev)
 {
-	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	struct sgiseeq_private *sp = netdev_priv(dev);
 	unsigned char oldmode = sp->mode;
 
 	if(dev->flags & IFF_PROMISC)
@@ -719,7 +718,6 @@
 	struct sgiseeq_private *sp;
 	struct net_device *dev;
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof (struct sgiseeq_private));
 	if (!dev) {
@@ -793,8 +791,7 @@
 		goto err_out_free_page;
 	}
 
-	printk(KERN_INFO "%s: %s %s\n",
-	       dev->name, sgiseeqstr, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: %s %pM\n", dev->name, sgiseeqstr, dev->dev_addr);
 
 	return 0;
 
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 59f242a..7f8e514 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -540,7 +540,6 @@
 			skb_put(skb, pkt_len);
 			skb->protocol = eth_type_trans(skb, ndev);
 			netif_rx(skb);
-			ndev->last_rx = jiffies;
 			mdp->stats.rx_packets++;
 			mdp->stats.rx_bytes += pkt_len;
 		}
@@ -800,7 +799,7 @@
 	char phy_id[BUS_ID_SIZE];
 	struct phy_device *phydev = NULL;
 
-	snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT,
+	snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
 		mdp->mii_bus->id , mdp->phy_id);
 
 	mdp->link = PHY_DOWN;
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index e6e3bf5..83cc3c5 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -627,7 +627,6 @@
 
 			sis190_rx_skb(skb);
 
-			dev->last_rx = jiffies;
 			stats->rx_packets++;
 			stats->rx_bytes += pkt_size;
 			if ((status & BCAST) == MCAST)
@@ -1791,7 +1790,6 @@
 	struct net_device *dev;
 	void __iomem *ioaddr;
 	int rc;
-	DECLARE_MAC_BUF(mac);
 
 	if (!printed_version) {
 		net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n");
@@ -1841,10 +1839,9 @@
 	if (rc < 0)
 		goto err_remove_mii;
 
-	net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), "
-		  "%s\n",
+	net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), %pM\n",
 		  pci_name(pdev), sis_chip_info[ent->driver_data].name,
-		  ioaddr, dev->irq, print_mac(mac, dev->dev_addr));
+		  ioaddr, dev->irq, dev->dev_addr);
 
 	net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name,
 		  (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII");
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 8e8337e..4acd41a 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -381,6 +381,21 @@
 	return 0;
 }
 
+static const struct net_device_ops sis900_netdev_ops = {
+	.ndo_open		 = sis900_open,
+	.ndo_stop		= sis900_close,
+	.ndo_start_xmit		= sis900_start_xmit,
+	.ndo_set_config		= sis900_set_config,
+	.ndo_set_multicast_list	= set_rx_mode,
+	.ndo_change_mtu		= eth_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= mii_ioctl,
+	.ndo_tx_timeout		= sis900_tx_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+        .ndo_poll_controller	= sis900_poll,
+#endif
+};
+
 /**
  *	sis900_probe - Probe for sis900 device
  *	@pci_dev: the sis900 pci device
@@ -404,7 +419,6 @@
 	int i, ret;
 	const char *card_name = card_names[pci_id->driver_data];
 	const char *dev_name = pci_name(pci_dev);
-	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -437,7 +451,7 @@
 	if (ret)
 		goto err_out;
 
-	sis_priv = net_dev->priv;
+	sis_priv = netdev_priv(net_dev);
 	net_dev->base_addr = ioaddr;
 	net_dev->irq = pci_dev->irq;
 	sis_priv->pci_dev = pci_dev;
@@ -462,20 +476,10 @@
 	sis_priv->rx_ring_dma = ring_dma;
 
 	/* The SiS900-specific entries in the device structure. */
-	net_dev->open = &sis900_open;
-	net_dev->hard_start_xmit = &sis900_start_xmit;
-	net_dev->stop = &sis900_close;
-	net_dev->set_config = &sis900_set_config;
-	net_dev->set_multicast_list = &set_rx_mode;
-	net_dev->do_ioctl = &mii_ioctl;
-	net_dev->tx_timeout = sis900_tx_timeout;
+	net_dev->netdev_ops = &sis900_netdev_ops;
 	net_dev->watchdog_timeo = TX_TIMEOUT;
 	net_dev->ethtool_ops = &sis900_ethtool_ops;
 
-#ifdef CONFIG_NET_POLL_CONTROLLER
-        net_dev->poll_controller = &sis900_poll;
-#endif
-
 	if (sis900_debug > 0)
 		sis_priv->msg_enable = sis900_debug;
 	else
@@ -534,9 +538,9 @@
 		goto err_unmap_rx;
 
 	/* print some information about our NIC */
-	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n",
+	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %pM\n",
 	       net_dev->name, card_name, ioaddr, net_dev->irq,
-	       print_mac(mac, net_dev->dev_addr));
+	       net_dev->dev_addr);
 
 	/* Detect Wake on Lan support */
 	ret = (inl(net_dev->base_addr + CFGPMC) & PMESP) >> 27;
@@ -570,7 +574,7 @@
 
 static int __devinit sis900_mii_probe(struct net_device * net_dev)
 {
-	struct sis900_private * sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	const char *dev_name = pci_name(sis_priv->pci_dev);
 	u16 poll_bit = MII_STAT_LINK, status = 0;
 	unsigned long timeout = jiffies + 5 * HZ;
@@ -698,7 +702,7 @@
 
 static u16 sis900_default_phy(struct net_device * net_dev)
 {
-	struct sis900_private * sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
  	struct mii_phy *phy = NULL, *phy_home = NULL,
 		*default_phy = NULL, *phy_lan = NULL;
 	u16 status;
@@ -999,7 +1003,7 @@
 static int
 sis900_open(struct net_device *net_dev)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	long ioaddr = net_dev->base_addr;
 	int ret;
 
@@ -1055,7 +1059,7 @@
 static void
 sis900_init_rxfilter (struct net_device * net_dev)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	long ioaddr = net_dev->base_addr;
 	u32 rfcrSave;
 	u32 i;
@@ -1093,7 +1097,7 @@
 static void
 sis900_init_tx_ring(struct net_device *net_dev)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	long ioaddr = net_dev->base_addr;
 	int i;
 
@@ -1127,7 +1131,7 @@
 static void
 sis900_init_rx_ring(struct net_device *net_dev)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	long ioaddr = net_dev->base_addr;
 	int i;
 
@@ -1198,7 +1202,7 @@
 
 static void sis630_set_eq(struct net_device *net_dev, u8 revision)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	u16 reg14h, eq_value=0, max_value=0, min_value=0;
 	int i, maxcount=10;
 
@@ -1271,13 +1275,13 @@
 static void sis900_timer(unsigned long data)
 {
 	struct net_device *net_dev = (struct net_device *)data;
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	struct mii_phy *mii_phy = sis_priv->mii;
 	static const int next_tick = 5*HZ;
 	u16 status;
 
 	if (!sis_priv->autong_complete){
-		int speed, duplex = 0;
+		int uninitialized_var(speed), duplex = 0;
 
 		sis900_read_mode(net_dev, &speed, &duplex);
 		if (duplex){
@@ -1341,7 +1345,7 @@
 
 static void sis900_check_mode(struct net_device *net_dev, struct mii_phy *mii_phy)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	long ioaddr = net_dev->base_addr;
 	int speed, duplex;
 
@@ -1420,7 +1424,7 @@
 
 static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	int i = 0;
 	u32 status;
 
@@ -1455,7 +1459,7 @@
 
 static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	struct mii_phy *phy = sis_priv->mii;
 	int phy_addr = sis_priv->cur_phy;
 	u32 status;
@@ -1510,7 +1514,7 @@
 
 static void sis900_tx_timeout(struct net_device *net_dev)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	long ioaddr = net_dev->base_addr;
 	unsigned long flags;
 	int i;
@@ -1569,7 +1573,7 @@
 static int
 sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	long ioaddr = net_dev->base_addr;
 	unsigned int  entry;
 	unsigned long flags;
@@ -1638,7 +1642,7 @@
 static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
 {
 	struct net_device *net_dev = dev_instance;
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	int boguscnt = max_interrupt_work;
 	long ioaddr = net_dev->base_addr;
 	u32 status;
@@ -1700,7 +1704,7 @@
 
 static int sis900_rx(struct net_device *net_dev)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	long ioaddr = net_dev->base_addr;
 	unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC;
 	u32 rx_status = sis_priv->rx_ring[entry].cmdsts;
@@ -1789,7 +1793,6 @@
 			/* some network statistics */
 			if ((rx_status & BCAST) == MCAST)
 				net_dev->stats.multicast++;
-			net_dev->last_rx = jiffies;
 			net_dev->stats.rx_bytes += rx_size;
 			net_dev->stats.rx_packets++;
 			sis_priv->dirty_rx++;
@@ -1850,7 +1853,7 @@
 
 static void sis900_finish_xmit (struct net_device *net_dev)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 
 	for (; sis_priv->dirty_tx != sis_priv->cur_tx; sis_priv->dirty_tx++) {
 		struct sk_buff *skb;
@@ -1919,7 +1922,7 @@
 static int sis900_close(struct net_device *net_dev)
 {
 	long ioaddr = net_dev->base_addr;
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	struct sk_buff *skb;
 	int i;
 
@@ -1974,7 +1977,7 @@
 static void sis900_get_drvinfo(struct net_device *net_dev,
 			       struct ethtool_drvinfo *info)
 {
- 	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 
 	strcpy (info->driver, SIS900_MODULE_NAME);
 	strcpy (info->version, SIS900_DRV_VERSION);
@@ -1983,26 +1986,26 @@
 
 static u32 sis900_get_msglevel(struct net_device *net_dev)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	return sis_priv->msg_enable;
 }
 
 static void sis900_set_msglevel(struct net_device *net_dev, u32 value)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	sis_priv->msg_enable = value;
 }
 
 static u32 sis900_get_link(struct net_device *net_dev)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	return mii_link_ok(&sis_priv->mii_info);
 }
 
 static int sis900_get_settings(struct net_device *net_dev,
 				struct ethtool_cmd *cmd)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	spin_lock_irq(&sis_priv->lock);
 	mii_ethtool_gset(&sis_priv->mii_info, cmd);
 	spin_unlock_irq(&sis_priv->lock);
@@ -2012,7 +2015,7 @@
 static int sis900_set_settings(struct net_device *net_dev,
 				struct ethtool_cmd *cmd)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	int rt;
 	spin_lock_irq(&sis_priv->lock);
 	rt = mii_ethtool_sset(&sis_priv->mii_info, cmd);
@@ -2022,7 +2025,7 @@
 
 static int sis900_nway_reset(struct net_device *net_dev)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	return mii_nway_restart(&sis_priv->mii_info);
 }
 
@@ -2039,7 +2042,7 @@
 
 static int sis900_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	long pmctrl_addr = net_dev->base_addr + pmctrl;
 	u32 cfgpmcsr = 0, pmctrl_bits = 0;
 
@@ -2110,7 +2113,7 @@
 
 static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd)
 {
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	struct mii_ioctl_data *data = if_mii(rq);
 
 	switch(cmd) {
@@ -2144,7 +2147,7 @@
 
 static int sis900_set_config(struct net_device *dev, struct ifmap *map)
 {
-	struct sis900_private *sis_priv = dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(dev);
 	struct mii_phy *mii_phy = sis_priv->mii;
 
 	u16 status;
@@ -2267,7 +2270,7 @@
 static void set_rx_mode(struct net_device *net_dev)
 {
 	long ioaddr = net_dev->base_addr;
-	struct sis900_private * sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	u16 mc_filter[16] = {0};	/* 256/128 bits multicast hash table */
 	int i, table_entries;
 	u32 rx_mode;
@@ -2342,7 +2345,7 @@
 
 static void sis900_reset(struct net_device *net_dev)
 {
-	struct sis900_private * sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	long ioaddr = net_dev->base_addr;
 	int i = 0;
 	u32 status = TxRCMP | RxRCMP;
@@ -2375,7 +2378,7 @@
 static void __devexit sis900_remove(struct pci_dev *pci_dev)
 {
 	struct net_device *net_dev = pci_get_drvdata(pci_dev);
-	struct sis900_private * sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	struct mii_phy *phy = NULL;
 
 	while (sis_priv->first_mii) {
@@ -2419,7 +2422,7 @@
 static int sis900_resume(struct pci_dev *pci_dev)
 {
 	struct net_device *net_dev = pci_get_drvdata(pci_dev);
-	struct sis900_private *sis_priv = net_dev->priv;
+	struct sis900_private *sis_priv = netdev_priv(net_dev);
 	long ioaddr = net_dev->base_addr;
 
 	if(!netif_running(net_dev))
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index a2b092b..607efea 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -168,6 +168,17 @@
 #define PRINTK(s, args...)
 #endif				// DRIVERDEBUG
 
+static const struct net_device_ops skfp_netdev_ops = {
+	.ndo_open		= skfp_open,
+	.ndo_stop		= skfp_close,
+	.ndo_start_xmit		= skfp_send_pkt,
+	.ndo_get_stats		= skfp_ctl_get_stats,
+	.ndo_change_mtu		= fddi_change_mtu,
+	.ndo_set_multicast_list = skfp_ctl_set_multicast_list,
+	.ndo_set_mac_address	= skfp_ctl_set_mac_address,
+	.ndo_do_ioctl		= skfp_ioctl,
+};
+
 /*
  * =================
  * = skfp_init_one =
@@ -253,13 +264,7 @@
 	}
 
 	dev->irq = pdev->irq;
-	dev->get_stats = &skfp_ctl_get_stats;
-	dev->open = &skfp_open;
-	dev->stop = &skfp_close;
-	dev->hard_start_xmit = &skfp_send_pkt;
-	dev->set_multicast_list = &skfp_ctl_set_multicast_list;
-	dev->set_mac_address = &skfp_ctl_set_mac_address;
-	dev->do_ioctl = &skfp_ioctl;
+	dev->netdev_ops = &skfp_netdev_ops;
 
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -612,7 +617,7 @@
  *   Interrupts are disabled, then reenabled at the adapter.
  */
 
-irqreturn_t skfp_interrupt(int irq, void *dev_id)
+static irqreturn_t skfp_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
 	struct s_smc *smc;	/* private board structure pointer */
@@ -679,7 +684,7 @@
  *   independent.
  *
  */
-struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev)
+static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev)
 {
 	struct s_smc *bp = netdev_priv(dev);
 
@@ -1224,7 +1229,7 @@
  * Verify if the source address is set. Insert it if necessary.
  *
  ************************/
-void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr)
+static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr)
 {
 	unsigned char SRBit;
 
@@ -1680,7 +1685,6 @@
 	skb->protocol = fddi_type_trans(skb, bp->dev);
 
 	netif_rx(skb);
-	bp->dev->last_rx = jiffies;
 
 	HWM_RX_CHECK(smc, RX_LOW_WATERMARK);
 	return;
@@ -1939,7 +1943,6 @@
 
 	// deliver frame to system
 	skb->protocol = fddi_type_trans(skb, smc->os.dev);
-	skb->dev->last_rx = jiffies;
 	netif_rx(skb);
 
 	return (0);
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 43f4c73..c9dbb06 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -104,6 +104,7 @@
 static void yukon_init(struct skge_hw *hw, int port);
 static void genesis_mac_init(struct skge_hw *hw, int port);
 static void genesis_link_up(struct skge_port *skge);
+static void skge_set_multicast(struct net_device *dev);
 
 /* Avoid conditionals by using array */
 static const int txqaddr[] = { Q_XA1, Q_XA2 };
@@ -149,24 +150,6 @@
 	return WAKE_MAGIC | WAKE_PHY;
 }
 
-static u32 pci_wake_enabled(struct pci_dev *dev)
-{
-	int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
-	u16 value;
-
-	/* If device doesn't support PM Capabilities, but request is to disable
-	 * wake events, it's a nop; otherwise fail */
-	if (!pm)
-		return 0;
-
-	pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
-
-	value &= PCI_PM_CAP_PME_MASK;
-	value >>= ffs(PCI_PM_CAP_PME_MASK) - 1;   /* First bit of mask */
-
-	return value != 0;
-}
-
 static void skge_wol_init(struct skge_port *skge)
 {
 	struct skge_hw *hw = skge->hw;
@@ -254,10 +237,14 @@
 	struct skge_port *skge = netdev_priv(dev);
 	struct skge_hw *hw = skge->hw;
 
-	if (wol->wolopts & ~wol_supported(hw))
+	if ((wol->wolopts & ~wol_supported(hw))
+	    || !device_can_wakeup(&hw->pdev->dev))
 		return -EOPNOTSUPP;
 
 	skge->wol = wol->wolopts;
+
+	device_set_wakeup_enable(&hw->pdev->dev, skge->wol);
+
 	return 0;
 }
 
@@ -2477,7 +2464,7 @@
 	}
 	spin_unlock_bh(&hw->phy_lock);
 
-	dev->set_multicast_list(dev);
+	skge_set_multicast(dev);
 }
 
 /* Basic MII support */
@@ -3045,6 +3032,18 @@
 			(status & GMR_FS_RX_OK) == 0;
 }
 
+static void skge_set_multicast(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		genesis_set_multicast(dev);
+	else
+		yukon_set_multicast(dev);
+
+}
+
 
 /* Get receive buffer from descriptor.
  * Handles copy of small buffers and reallocation failures
@@ -3200,7 +3199,6 @@
 
 		skb = skge_rx_get(dev, e, control, rd->status, rd->csum2);
 		if (likely(skb)) {
-			dev->last_rx = jiffies;
 			netif_receive_skb(skb);
 
 			++work_done;
@@ -3216,7 +3214,7 @@
 		unsigned long flags;
 
 		spin_lock_irqsave(&hw->hw_lock, flags);
-		__netif_rx_complete(dev, napi);
+		__netif_rx_complete(napi);
 		hw->intr_mask |= napimask[skge->port];
 		skge_write32(hw, B0_IMSK, hw->intr_mask);
 		skge_read32(hw, B0_IMSK);
@@ -3379,7 +3377,7 @@
 	if (status & (IS_XA1_F|IS_R1_F)) {
 		struct skge_port *skge = netdev_priv(hw->dev[0]);
 		hw->intr_mask &= ~(IS_XA1_F|IS_R1_F);
-		netif_rx_schedule(hw->dev[0], &skge->napi);
+		netif_rx_schedule(&skge->napi);
 	}
 
 	if (status & IS_PA_TO_TX1)
@@ -3399,7 +3397,7 @@
 
 		if (status & (IS_XA2_F|IS_R2_F)) {
 			hw->intr_mask &= ~(IS_XA2_F|IS_R2_F);
-			netif_rx_schedule(hw->dev[1], &skge->napi);
+			netif_rx_schedule(&skge->napi);
 		}
 
 		if (status & IS_PA_TO_RX2) {
@@ -3730,7 +3728,7 @@
 	struct skge_port *skge;
 	struct dentry *d;
 
-	if (dev->open != &skge_up || !skge_debug)
+	if (dev->netdev_ops->ndo_open != &skge_up || !skge_debug)
 		goto done;
 
 	skge = netdev_priv(dev);
@@ -3804,6 +3802,23 @@
 #define skge_debug_cleanup()
 #endif
 
+static const struct net_device_ops skge_netdev_ops = {
+	.ndo_open		= skge_up,
+	.ndo_stop		= skge_down,
+	.ndo_start_xmit		= skge_xmit_frame,
+	.ndo_do_ioctl		= skge_ioctl,
+	.ndo_get_stats		= skge_get_stats,
+	.ndo_tx_timeout		= skge_tx_timeout,
+	.ndo_change_mtu		= skge_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_multicast_list	= skge_set_multicast,
+	.ndo_set_mac_address	= skge_set_mac_address,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= skge_netpoll,
+#endif
+};
+
+
 /* Initialize network device */
 static struct net_device *skge_devinit(struct skge_hw *hw, int port,
 				       int highmem)
@@ -3817,24 +3832,9 @@
 	}
 
 	SET_NETDEV_DEV(dev, &hw->pdev->dev);
-	dev->open = skge_up;
-	dev->stop = skge_down;
-	dev->do_ioctl = skge_ioctl;
-	dev->hard_start_xmit = skge_xmit_frame;
-	dev->get_stats = skge_get_stats;
-	if (hw->chip_id == CHIP_ID_GENESIS)
-		dev->set_multicast_list = genesis_set_multicast;
-	else
-		dev->set_multicast_list = yukon_set_multicast;
-
-	dev->set_mac_address = skge_set_mac_address;
-	dev->change_mtu = skge_change_mtu;
-	SET_ETHTOOL_OPS(dev, &skge_ethtool_ops);
-	dev->tx_timeout = skge_tx_timeout;
+	dev->netdev_ops = &skge_netdev_ops;
+	dev->ethtool_ops = &skge_ethtool_ops;
 	dev->watchdog_timeo = TX_WATCHDOG;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = skge_netpoll;
-#endif
 	dev->irq = hw->pdev->irq;
 
 	if (highmem)
@@ -3856,7 +3856,7 @@
 	skge->speed = -1;
 	skge->advertising = skge_supported_modes(hw);
 
-	if (pci_wake_enabled(hw->pdev))
+	if (device_may_wakeup(&hw->pdev->dev))
 		skge->wol = wol_supported(hw) & WAKE_MAGIC;
 
 	hw->dev[port] = dev;
@@ -3885,11 +3885,10 @@
 static void __devinit skge_show_addr(struct net_device *dev)
 {
 	const struct skge_port *skge = netdev_priv(dev);
-	DECLARE_MAC_BUF(mac);
 
 	if (netif_msg_probe(skge))
-		printk(KERN_INFO PFX "%s: addr %s\n",
-		       dev->name, print_mac(mac, dev->dev_addr));
+		printk(KERN_INFO PFX "%s: addr %pM\n",
+		       dev->name, dev->dev_addr);
 }
 
 static int __devinit skge_probe(struct pci_dev *pdev,
@@ -4082,8 +4081,8 @@
 	}
 
 	skge_write32(hw, B0_IMSK, 0);
-	pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
-	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	pci_prepare_to_sleep(pdev);
 
 	return 0;
 }
@@ -4096,7 +4095,7 @@
 	if (!hw)
 		return 0;
 
-	err = pci_set_power_state(pdev, PCI_D0);
+	err = pci_back_from_sleep(pdev);
 	if (err)
 		goto out;
 
@@ -4104,8 +4103,6 @@
 	if (err)
 		goto out;
 
-	pci_enable_wake(pdev, PCI_D0, 0);
-
 	err = skge_reset(hw);
 	if (err)
 		goto out;
@@ -4146,8 +4143,8 @@
 		wol |= skge->wol;
 	}
 
-	pci_enable_wake(pdev, PCI_D3hot, wol);
-	pci_enable_wake(pdev, PCI_D3cold, wol);
+	if (pci_enable_wake(pdev, PCI_D3cold, wol))
+		pci_enable_wake(pdev, PCI_D3hot, wol);
 
 	pci_disable_device(pdev);
 	pci_set_power_state(pdev, PCI_D3hot);
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 3813d15..3668e81 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -3979,7 +3979,7 @@
 	struct net_device *dev = ptr;
 	struct sky2_port *sky2 = netdev_priv(dev);
 
-	if (dev->open != sky2_up || !sky2_debug)
+	if (dev->netdev_ops->ndo_open != sky2_up || !sky2_debug)
 		return NOTIFY_DONE;
 
 	switch(event) {
@@ -4041,6 +4041,41 @@
 #define sky2_debug_cleanup()
 #endif
 
+/* Two copies of network device operations to handle special case of
+   not allowing netpoll on second port */
+static const struct net_device_ops sky2_netdev_ops[2] = {
+  {
+	.ndo_open		= sky2_up,
+	.ndo_stop		= sky2_down,
+	.ndo_start_xmit		= sky2_xmit_frame,
+	.ndo_do_ioctl		= sky2_ioctl,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= sky2_set_mac_address,
+	.ndo_set_multicast_list	= sky2_set_multicast,
+	.ndo_change_mtu		= sky2_change_mtu,
+	.ndo_tx_timeout		= sky2_tx_timeout,
+#ifdef SKY2_VLAN_TAG_USED
+	.ndo_vlan_rx_register	= sky2_vlan_rx_register,
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= sky2_netpoll,
+#endif
+  },
+  {
+	.ndo_open		= sky2_up,
+	.ndo_stop		= sky2_down,
+	.ndo_start_xmit		= sky2_xmit_frame,
+	.ndo_do_ioctl		= sky2_ioctl,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= sky2_set_mac_address,
+	.ndo_set_multicast_list	= sky2_set_multicast,
+	.ndo_change_mtu		= sky2_change_mtu,
+	.ndo_tx_timeout		= sky2_tx_timeout,
+#ifdef SKY2_VLAN_TAG_USED
+	.ndo_vlan_rx_register	= sky2_vlan_rx_register,
+#endif
+  },
+};
 
 /* Initialize network device */
 static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
@@ -4057,20 +4092,9 @@
 
 	SET_NETDEV_DEV(dev, &hw->pdev->dev);
 	dev->irq = hw->pdev->irq;
-	dev->open = sky2_up;
-	dev->stop = sky2_down;
-	dev->do_ioctl = sky2_ioctl;
-	dev->hard_start_xmit = sky2_xmit_frame;
-	dev->set_multicast_list = sky2_set_multicast;
-	dev->set_mac_address = sky2_set_mac_address;
-	dev->change_mtu = sky2_change_mtu;
 	SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops);
-	dev->tx_timeout = sky2_tx_timeout;
 	dev->watchdog_timeo = TX_WATCHDOG;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	if (port == 0)
-		dev->poll_controller = sky2_netpoll;
-#endif
+	dev->netdev_ops = &sky2_netdev_ops[port];
 
 	sky2 = netdev_priv(dev);
 	sky2->netdev = dev;
@@ -4104,7 +4128,6 @@
 	if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
 	      sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0)) {
 		dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-		dev->vlan_rx_register = sky2_vlan_rx_register;
 	}
 #endif
 
@@ -4118,11 +4141,10 @@
 static void __devinit sky2_show_addr(struct net_device *dev)
 {
 	const struct sky2_port *sky2 = netdev_priv(dev);
-	DECLARE_MAC_BUF(mac);
 
 	if (netif_msg_probe(sky2))
-		printk(KERN_INFO PFX "%s: addr %s\n",
-		       dev->name, print_mac(mac, dev->dev_addr));
+		printk(KERN_INFO PFX "%s: addr %pM\n",
+		       dev->name, dev->dev_addr);
 }
 
 /* Handle software interrupt used during MSI test */
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 1d58991..8e1c0ba 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -365,7 +365,6 @@
 	skb_reset_mac_header(skb);
 	skb->protocol = htons(ETH_P_IP);
 	netif_rx(skb);
-	sl->dev->last_rx = jiffies;
 	sl->rx_packets++;
 }
 
@@ -402,7 +401,7 @@
 	 * if we did not request it before write operation.
 	 *       14 Oct 1994  Dmitry Gorodchanin.
 	 */
-	sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+	set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
 	actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
 #ifdef SL_CHECK_TRANSMIT
 	sl->dev->trans_start = jiffies;
@@ -432,7 +431,7 @@
 		/* Now serial buffer is almost free & we can start
 		 * transmission of another packet */
 		sl->tx_packets++;
-		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 		sl_unlock(sl);
 		return;
 	}
@@ -465,7 +464,7 @@
 			(tty_chars_in_buffer(sl->tty) || sl->xleft) ?
 				"bad line quality" : "driver error");
 		sl->xleft = 0;
-		sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+		clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
 		sl_unlock(sl);
 #endif
 	}
@@ -515,10 +514,9 @@
 	struct slip *sl = netdev_priv(dev);
 
 	spin_lock_bh(&sl->lock);
-	if (sl->tty) {
+	if (sl->tty)
 		/* TTY discipline is running. */
-		sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-	}
+		clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
 	netif_stop_queue(dev);
 	sl->rcount   = 0;
 	sl->xleft    = 0;
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index d6abb68..404b80e 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -182,6 +182,22 @@
 
 static int ultra_found = 0;
 
+
+static const struct net_device_ops ultramca_netdev_ops = {
+	.ndo_open		= ultramca_open,
+	.ndo_stop		= ultramca_close_card,
+
+	.ndo_start_xmit		= ei_start_xmit,
+	.ndo_tx_timeout		= ei_tx_timeout,
+	.ndo_get_stats		= ei_get_stats,
+	.ndo_set_multicast_list = ei_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller 	= ei_poll,
+#endif
+};
+
 static int __init ultramca_probe(struct device *gen_dev)
 {
 	unsigned short ioaddr;
@@ -196,7 +212,6 @@
 	int tirq = 0;
 	int base_addr = ultra_io[ultra_found];
 	int irq = ultra_irq[ultra_found];
-	DECLARE_MAC_BUF(mac);
 
 	if (base_addr || irq) {
 		printk(KERN_INFO "Probing for SMC MCA adapter");
@@ -334,8 +349,8 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(ioaddr + 8 + i);
 
-	printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x, %s",
-	       slot + 1, ioaddr, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x, %pM",
+	       slot + 1, ioaddr, dev->dev_addr);
 
 	/* Switch from the station address to the alternate register set
 	 * and read the useful registers there.
@@ -385,11 +400,7 @@
 
 	ei_status.priv = slot;
 
-	dev->open = &ultramca_open;
-	dev->stop = &ultramca_close_card;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = ei_poll;
-#endif
+	dev->netdev_ops = &ultramca_netdev_ops;
 
 	NS8390_init(dev, 0);
 
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index 00d6cf1..b386608 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -187,6 +187,21 @@
 }
 #endif
 
+static const struct net_device_ops ultra_netdev_ops = {
+	.ndo_open		= ultra_open,
+	.ndo_stop		= ultra_close_card,
+
+	.ndo_start_xmit		= ei_start_xmit,
+	.ndo_tx_timeout		= ei_tx_timeout,
+	.ndo_get_stats		= ei_get_stats,
+	.ndo_set_multicast_list = ei_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller 	= ei_poll,
+#endif
+};
+
 static int __init ultra_probe1(struct net_device *dev, int ioaddr)
 {
 	int i, retval;
@@ -198,7 +213,6 @@
 	unsigned char num_pages, irqreg, addr, piomode;
 	unsigned char idreg = inb(ioaddr + 7);
 	unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
-	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -228,8 +242,8 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(ioaddr + 8 + i);
 
-	printk("%s: %s at %#3x, %s", dev->name, model_name,
-	       ioaddr, print_mac(mac, dev->dev_addr));
+	printk("%s: %s at %#3x, %pM", dev->name, model_name,
+	       ioaddr, dev->dev_addr);
 
 	/* Switch from the station address to the alternate register set and
 	   read the useful registers there. */
@@ -301,11 +315,8 @@
 		ei_status.get_8390_hdr = &ultra_get_8390_hdr;
 	}
 	ei_status.reset_8390 = &ultra_reset_8390;
-	dev->open = &ultra_open;
-	dev->stop = &ultra_close_card;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = ei_poll;
-#endif
+
+	dev->netdev_ops = &ultra_netdev_ops;
 	NS8390_init(dev, 0);
 
 	retval = register_netdev(dev);
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index a5a91ac..cb6c097 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -163,7 +163,6 @@
 	unsigned char idreg;
 	unsigned char reg4;
 	const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
-	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -207,8 +206,8 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(ioaddr + 8 + i);
 
-	printk("%s: %s at 0x%X, %s",
-	       dev->name, model_name, ioaddr, print_mac(mac, dev->dev_addr));
+	printk("%s: %s at 0x%X, %pM",
+	       dev->name, model_name, ioaddr, dev->dev_addr);
 
 	/* Switch from the station address to the alternate register set and
 	   read the useful registers there. */
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 9a16a79..bf3aa2a 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -439,7 +439,6 @@
 
 		DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name);
 		PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64);
-		dev->last_rx = jiffies;
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
 		dev->stats.rx_packets++;
@@ -1231,7 +1230,6 @@
 	BUG_ON(skb == NULL);
 	lp->current_rx_skb = NULL;
 	PRINT_PKT(skb->data, skb->len);
-	dev->last_rx = jiffies;
 	skb->protocol = eth_type_trans(skb, dev);
 	dev->stats.rx_packets++;
 	dev->stats.rx_bytes += skb->len;
@@ -2050,9 +2048,6 @@
  */
 static int __devinit smc911x_drv_probe(struct platform_device *pdev)
 {
-#ifdef SMC_DYNAMIC_BUS_CONFIG
-	struct smc911x_platdata *pd = pdev->dev.platform_data;
-#endif
 	struct net_device *ndev;
 	struct resource *res;
 	struct smc911x_local *lp;
@@ -2087,11 +2082,14 @@
 	lp = netdev_priv(ndev);
 	lp->netdev = ndev;
 #ifdef SMC_DYNAMIC_BUS_CONFIG
-	if (!pd) {
-		ret = -EINVAL;
-		goto release_both;
+	{
+		struct smc911x_platdata *pd = pdev->dev.platform_data;
+		if (!pd) {
+			ret = -EINVAL;
+			goto release_both;
+		}
+		memcpy(&lp->cfg, pd, sizeof(lp->cfg));
 	}
-	memcpy(&lp->cfg, pd, sizeof(lp->cfg));
 #endif
 
 	addr = ioremap(res->start, SMC911X_IO_EXTENT);
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index de67744..18d653b 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -764,7 +764,7 @@
  . interrupt, so an auto-detect routine can detect it, and find the IRQ,
  ------------------------------------------------------------------------
 */
-int __init smc_findirq( int ioaddr )
+static int __init smc_findirq(int ioaddr)
 {
 #ifndef NO_AUTOPROBE
 	int	timeout = 20;
@@ -876,8 +876,6 @@
 	word memory_info_register;
 	word memory_cfg_register;
 
-	DECLARE_MAC_BUF(mac);
-
 	/* Grab the region so that no one else tries to probe our ioports. */
 	if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -1033,10 +1031,10 @@
 	/*
 	 . Print the Ethernet address
 	*/
-	printk("ADDR: %s\n", print_mac(mac, dev->dev_addr));
+	printk("ADDR: %pM\n", dev->dev_addr);
 
 	/* set the private data to zero by default */
-	memset(dev->priv, 0, sizeof(struct smc_local));
+	memset(netdev_priv(dev), 0, sizeof(struct smc_local));
 
 	/* Grab the IRQ */
       	retval = request_irq(dev->irq, &smc_interrupt, 0, DRV_NAME, dev);
@@ -1110,7 +1108,7 @@
 	int	i;	/* used to set hw ethernet address */
 
 	/* clear out all the junk that was put here before... */
-	memset(dev->priv, 0, sizeof(struct smc_local));
+	memset(netdev_priv(dev), 0, sizeof(struct smc_local));
 
 	/* reset the hardware */
 
@@ -1166,7 +1164,7 @@
 	smc_enable( dev->base_addr );
 	dev->trans_start = jiffies;
 	/* clear anything saved */
-	((struct smc_local *)dev->priv)->saved_skb = NULL;
+	((struct smc_local *)netdev_priv(dev))->saved_skb = NULL;
 	netif_wake_queue(dev);
 }
 
@@ -1272,7 +1270,6 @@
 
 		skb->protocol = eth_type_trans(skb, dev );
 		netif_rx(skb);
-		dev->last_rx = jiffies;
 		dev->stats.rx_packets++;
 		dev->stats.rx_bytes += packet_length;
 	} else {
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 35c56ab..b215a8d 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -90,33 +90,6 @@
 
 #include "smc91x.h"
 
-#ifdef CONFIG_ISA
-/*
- * the LAN91C111 can be at any of the following port addresses.  To change,
- * for a slightly different card, you can add it to the array.  Keep in
- * mind that the array must end in zero.
- */
-static unsigned int smc_portlist[] __initdata = {
-	0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
-	0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0
-};
-
-#ifndef SMC_IOADDR
-# define SMC_IOADDR		-1
-#endif
-static unsigned long io = SMC_IOADDR;
-module_param(io, ulong, 0400);
-MODULE_PARM_DESC(io, "I/O base address");
-
-#ifndef SMC_IRQ
-# define SMC_IRQ		-1
-#endif
-static int irq = SMC_IRQ;
-module_param(irq, int, 0400);
-MODULE_PARM_DESC(irq, "IRQ number");
-
-#endif  /* CONFIG_ISA */
-
 #ifndef SMC_NOWAIT
 # define SMC_NOWAIT		0
 #endif
@@ -518,7 +491,6 @@
 
 		PRINT_PKT(data, packet_len - 4);
 
-		dev->last_rx = jiffies;
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
 		dev->stats.rx_packets++;
@@ -1778,7 +1750,6 @@
 	int retval;
 	unsigned int val, revision_register;
 	const char *version_string;
-	DECLARE_MAC_BUF(mac);
 
 	DBG(2, "%s: %s\n", CARDNAME, __func__);
 
@@ -1972,8 +1943,8 @@
 			       "set using ifconfig\n", dev->name);
 		} else {
 			/* Print the Ethernet address */
-			printk("%s: Ethernet addr: %s\n",
-			       dev->name, print_mac(mac, dev->dev_addr));
+			printk("%s: Ethernet addr: %pM\n",
+			       dev->name, dev->dev_addr);
 		}
 
 		if (lp->phy_type == 0) {
@@ -2316,15 +2287,6 @@
 
 static int __init smc_init(void)
 {
-#ifdef MODULE
-#ifdef CONFIG_ISA
-	if (io == -1)
-		printk(KERN_WARNING
-			"%s: You shouldn't use auto-probing with insmod!\n",
-			CARDNAME);
-#endif
-#endif
-
 	return platform_driver_register(&smc_driver);
 }
 
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index a07cc93..3e7c6a3 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -87,49 +87,28 @@
 #define RPC_LSA_DEFAULT		RPC_LED_100_10
 #define RPC_LSB_DEFAULT		RPC_LED_TX_RX
 
-# if defined (CONFIG_BFIN561_EZKIT)
 #define SMC_CAN_USE_8BIT	0
 #define SMC_CAN_USE_16BIT	1
+# if defined(CONFIG_BF561)
 #define SMC_CAN_USE_32BIT	1
-#define SMC_IO_SHIFT		0
-#define SMC_NOWAIT      	1
-#define SMC_USE_BFIN_DMA	0
-
-
-#define SMC_inw(a, r)       	readw((a) + (r))
-#define SMC_outw(v, a, r)   	writew(v, (a) + (r))
-#define SMC_inl(a, r)       	readl((a) + (r))
-#define SMC_outl(v, a, r)   	writel(v, (a) + (r))
-#define SMC_outsl(a, r, p, l)	outsl((unsigned long *)((a) + (r)), p, l)
-#define SMC_insl(a, r, p, l) 	insl ((unsigned long *)((a) + (r)), p, l)
 # else
-#define SMC_CAN_USE_8BIT	0
-#define SMC_CAN_USE_16BIT	1
 #define SMC_CAN_USE_32BIT	0
+# endif
 #define SMC_IO_SHIFT		0
 #define SMC_NOWAIT      	1
 #define SMC_USE_BFIN_DMA	0
 
-
-#define SMC_inw(a, r)       	readw((a) + (r))
-#define SMC_outw(v, a, r)   	writew(v, (a) + (r))
-#define SMC_outsw(a, r, p, l)	outsw((unsigned long *)((a) + (r)), p, l)
-#define SMC_insw(a, r, p, l) 	insw ((unsigned long *)((a) + (r)), p, l)
+#define SMC_inw(a, r)		readw((a) + (r))
+#define SMC_outw(v, a, r)	writew(v, (a) + (r))
+#define SMC_insw(a, r, p, l)	readsw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
+# if SMC_CAN_USE_32BIT
+#define SMC_inl(a, r)		readl((a) + (r))
+#define SMC_outl(v, a, r)	writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l)	readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l)	writesl((a) + (r), p, l)
 # endif
-/* check if the mac in reg is valid */
-#define SMC_GET_MAC_ADDR(lp, addr)				\
-	do {							\
-		unsigned int __v;				\
-		__v = SMC_inw(ioaddr, ADDR0_REG(lp));		\
-		addr[0] = __v; addr[1] = __v >> 8;		\
-		__v = SMC_inw(ioaddr, ADDR1_REG(lp));		\
-		addr[2] = __v; addr[3] = __v >> 8;		\
-		__v = SMC_inw(ioaddr, ADDR2_REG(lp));		\
-		addr[4] = __v; addr[5] = __v >> 8;		\
-		if (*(u32 *)(&addr[0]) == 0xFFFFFFFF) {		\
-			random_ether_addr(addr);		\
-		}						\
-	} while (0)
+
 #elif defined(CONFIG_REDWOOD_5) || defined(CONFIG_REDWOOD_6)
 
 /* We can only do 16-bit reads and writes in the static memory space. */
@@ -286,19 +265,6 @@
 
 #define SMC_IRQ_FLAGS		(0)
 
-#elif	defined(CONFIG_ISA)
-
-#define SMC_CAN_USE_8BIT	1
-#define SMC_CAN_USE_16BIT	1
-#define SMC_CAN_USE_32BIT	0
-
-#define SMC_inb(a, r)		inb((a) + (r))
-#define SMC_inw(a, r)		inw((a) + (r))
-#define SMC_outb(v, a, r)	outb(v, (a) + (r))
-#define SMC_outw(v, a, r)	outw(v, (a) + (r))
-#define SMC_insw(a, r, p, l)	insw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)	outsw((a) + (r), p, l)
-
 #elif   defined(CONFIG_M32R)
 
 #define SMC_CAN_USE_8BIT	0
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
new file mode 100644
index 0000000..5e989d8
--- /dev/null
+++ b/drivers/net/smsc911x.c
@@ -0,0 +1,2071 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2004-2008 SMSC
+ * Copyright (C) 2005-2008 ARM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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.
+ *
+ ***************************************************************************
+ * Rewritten, heavily based on smsc911x simple driver by SMSC.
+ * Partly uses io macros from smc91x.c by Nicolas Pitre
+ *
+ * Supported devices:
+ *   LAN9115, LAN9116, LAN9117, LAN9118
+ *   LAN9215, LAN9216, LAN9217, LAN9218
+ *   LAN9210, LAN9211
+ *   LAN9220, LAN9221
+ *
+ */
+
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/smsc911x.h>
+#include "smsc911x.h"
+
+#define SMSC_CHIPNAME		"smsc911x"
+#define SMSC_MDIONAME		"smsc911x-mdio"
+#define SMSC_DRV_VERSION	"2008-10-21"
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(SMSC_DRV_VERSION);
+
+#if USE_DEBUG > 0
+static int debug = 16;
+#else
+static int debug = 3;
+#endif
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+struct smsc911x_data {
+	void __iomem *ioaddr;
+
+	unsigned int idrev;
+
+	/* used to decide which workarounds apply */
+	unsigned int generation;
+
+	/* device configuration (copied from platform_data during probe) */
+	struct smsc911x_platform_config config;
+
+	/* This needs to be acquired before calling any of below:
+	 * smsc911x_mac_read(), smsc911x_mac_write()
+	 */
+	spinlock_t mac_lock;
+
+	/* spinlock to ensure 16-bit accesses are serialised.
+	 * unused with a 32-bit bus */
+	spinlock_t dev_lock;
+
+	struct phy_device *phy_dev;
+	struct mii_bus *mii_bus;
+	int phy_irq[PHY_MAX_ADDR];
+	unsigned int using_extphy;
+	int last_duplex;
+	int last_carrier;
+
+	u32 msg_enable;
+	unsigned int gpio_setting;
+	unsigned int gpio_orig_setting;
+	struct net_device *dev;
+	struct napi_struct napi;
+
+	unsigned int software_irq_signal;
+
+#ifdef USE_PHY_WORK_AROUND
+#define MIN_PACKET_SIZE (64)
+	char loopback_tx_pkt[MIN_PACKET_SIZE];
+	char loopback_rx_pkt[MIN_PACKET_SIZE];
+	unsigned int resetcount;
+#endif
+
+	/* Members for Multicast filter workaround */
+	unsigned int multicast_update_pending;
+	unsigned int set_bits_mask;
+	unsigned int clear_bits_mask;
+	unsigned int hashhi;
+	unsigned int hashlo;
+};
+
+/* The 16-bit access functions are significantly slower, due to the locking
+ * necessary.  If your bus hardware can be configured to do this for you
+ * (in response to a single 32-bit operation from software), you should use
+ * the 32-bit access functions instead. */
+
+static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
+{
+	if (pdata->config.flags & SMSC911X_USE_32BIT)
+		return readl(pdata->ioaddr + reg);
+
+	if (pdata->config.flags & SMSC911X_USE_16BIT) {
+		u32 data;
+		unsigned long flags;
+
+		/* these two 16-bit reads must be performed consecutively, so
+		 * must not be interrupted by our own ISR (which would start
+		 * another read operation) */
+		spin_lock_irqsave(&pdata->dev_lock, flags);
+		data = ((readw(pdata->ioaddr + reg) & 0xFFFF) |
+			((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16));
+		spin_unlock_irqrestore(&pdata->dev_lock, flags);
+
+		return data;
+	}
+
+	BUG();
+}
+
+static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
+				      u32 val)
+{
+	if (pdata->config.flags & SMSC911X_USE_32BIT) {
+		writel(val, pdata->ioaddr + reg);
+		return;
+	}
+
+	if (pdata->config.flags & SMSC911X_USE_16BIT) {
+		unsigned long flags;
+
+		/* these two 16-bit writes must be performed consecutively, so
+		 * must not be interrupted by our own ISR (which would start
+		 * another read operation) */
+		spin_lock_irqsave(&pdata->dev_lock, flags);
+		writew(val & 0xFFFF, pdata->ioaddr + reg);
+		writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2);
+		spin_unlock_irqrestore(&pdata->dev_lock, flags);
+		return;
+	}
+
+	BUG();
+}
+
+/* Writes a packet to the TX_DATA_FIFO */
+static inline void
+smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf,
+		      unsigned int wordcount)
+{
+	if (pdata->config.flags & SMSC911X_USE_32BIT) {
+		writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount);
+		return;
+	}
+
+	if (pdata->config.flags & SMSC911X_USE_16BIT) {
+		while (wordcount--)
+			smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++);
+		return;
+	}
+
+	BUG();
+}
+
+/* Reads a packet out of the RX_DATA_FIFO */
+static inline void
+smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf,
+		     unsigned int wordcount)
+{
+	if (pdata->config.flags & SMSC911X_USE_32BIT) {
+		readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount);
+		return;
+	}
+
+	if (pdata->config.flags & SMSC911X_USE_16BIT) {
+		while (wordcount--)
+			*buf++ = smsc911x_reg_read(pdata, RX_DATA_FIFO);
+		return;
+	}
+
+	BUG();
+}
+
+/* waits for MAC not busy, with timeout.  Only called by smsc911x_mac_read
+ * and smsc911x_mac_write, so assumes mac_lock is held */
+static int smsc911x_mac_complete(struct smsc911x_data *pdata)
+{
+	int i;
+	u32 val;
+
+	SMSC_ASSERT_MAC_LOCK(pdata);
+
+	for (i = 0; i < 40; i++) {
+		val = smsc911x_reg_read(pdata, MAC_CSR_CMD);
+		if (!(val & MAC_CSR_CMD_CSR_BUSY_))
+			return 0;
+	}
+	SMSC_WARNING(HW, "Timed out waiting for MAC not BUSY. "
+		"MAC_CSR_CMD: 0x%08X", val);
+	return -EIO;
+}
+
+/* Fetches a MAC register value. Assumes mac_lock is acquired */
+static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset)
+{
+	unsigned int temp;
+
+	SMSC_ASSERT_MAC_LOCK(pdata);
+
+	temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
+	if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
+		SMSC_WARNING(HW, "MAC busy at entry");
+		return 0xFFFFFFFF;
+	}
+
+	/* Send the MAC cmd */
+	smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) |
+		MAC_CSR_CMD_CSR_BUSY_ | MAC_CSR_CMD_R_NOT_W_));
+
+	/* Workaround for hardware read-after-write restriction */
+	temp = smsc911x_reg_read(pdata, BYTE_TEST);
+
+	/* Wait for the read to complete */
+	if (likely(smsc911x_mac_complete(pdata) == 0))
+		return smsc911x_reg_read(pdata, MAC_CSR_DATA);
+
+	SMSC_WARNING(HW, "MAC busy after read");
+	return 0xFFFFFFFF;
+}
+
+/* Set a mac register, mac_lock must be acquired before calling */
+static void smsc911x_mac_write(struct smsc911x_data *pdata,
+			       unsigned int offset, u32 val)
+{
+	unsigned int temp;
+
+	SMSC_ASSERT_MAC_LOCK(pdata);
+
+	temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
+	if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
+		SMSC_WARNING(HW,
+			"smsc911x_mac_write failed, MAC busy at entry");
+		return;
+	}
+
+	/* Send data to write */
+	smsc911x_reg_write(pdata, MAC_CSR_DATA, val);
+
+	/* Write the actual data */
+	smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) |
+		MAC_CSR_CMD_CSR_BUSY_));
+
+	/* Workaround for hardware read-after-write restriction */
+	temp = smsc911x_reg_read(pdata, BYTE_TEST);
+
+	/* Wait for the write to complete */
+	if (likely(smsc911x_mac_complete(pdata) == 0))
+		return;
+
+	SMSC_WARNING(HW,
+		"smsc911x_mac_write failed, MAC busy after write");
+}
+
+/* Get a phy register */
+static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
+{
+	struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv;
+	unsigned long flags;
+	unsigned int addr;
+	int i, reg;
+
+	spin_lock_irqsave(&pdata->mac_lock, flags);
+
+	/* Confirm MII not busy */
+	if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
+		SMSC_WARNING(HW,
+			"MII is busy in smsc911x_mii_read???");
+		reg = -EIO;
+		goto out;
+	}
+
+	/* Set the address, index & direction (read from PHY) */
+	addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6);
+	smsc911x_mac_write(pdata, MII_ACC, addr);
+
+	/* Wait for read to complete w/ timeout */
+	for (i = 0; i < 100; i++)
+		if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
+			reg = smsc911x_mac_read(pdata, MII_DATA);
+			goto out;
+		}
+
+	SMSC_WARNING(HW, "Timed out waiting for MII write to finish");
+	reg = -EIO;
+
+out:
+	spin_unlock_irqrestore(&pdata->mac_lock, flags);
+	return reg;
+}
+
+/* Set a phy register */
+static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
+			   u16 val)
+{
+	struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv;
+	unsigned long flags;
+	unsigned int addr;
+	int i, reg;
+
+	spin_lock_irqsave(&pdata->mac_lock, flags);
+
+	/* Confirm MII not busy */
+	if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
+		SMSC_WARNING(HW,
+			"MII is busy in smsc911x_mii_write???");
+		reg = -EIO;
+		goto out;
+	}
+
+	/* Put the data to write in the MAC */
+	smsc911x_mac_write(pdata, MII_DATA, val);
+
+	/* Set the address, index & direction (write to PHY) */
+	addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) |
+		MII_ACC_MII_WRITE_;
+	smsc911x_mac_write(pdata, MII_ACC, addr);
+
+	/* Wait for write to complete w/ timeout */
+	for (i = 0; i < 100; i++)
+		if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
+			reg = 0;
+			goto out;
+		}
+
+	SMSC_WARNING(HW, "Timed out waiting for MII write to finish");
+	reg = -EIO;
+
+out:
+	spin_unlock_irqrestore(&pdata->mac_lock, flags);
+	return reg;
+}
+
+/* Autodetects and initialises external phy for SMSC9115 and SMSC9117 flavors.
+ * If something goes wrong, returns -ENODEV to revert back to internal phy.
+ * Performed at initialisation only, so interrupts are enabled */
+static int smsc911x_phy_initialise_external(struct smsc911x_data *pdata)
+{
+	unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG);
+
+	/* External phy is requested, supported, and detected */
+	if (hwcfg & HW_CFG_EXT_PHY_DET_) {
+
+		/* Switch to external phy. Assuming tx and rx are stopped
+		 * because smsc911x_phy_initialise is called before
+		 * smsc911x_rx_initialise and tx_initialise. */
+
+		/* Disable phy clocks to the MAC */
+		hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
+		hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
+		smsc911x_reg_write(pdata, HW_CFG, hwcfg);
+		udelay(10);	/* Enough time for clocks to stop */
+
+		/* Switch to external phy */
+		hwcfg |= HW_CFG_EXT_PHY_EN_;
+		smsc911x_reg_write(pdata, HW_CFG, hwcfg);
+
+		/* Enable phy clocks to the MAC */
+		hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
+		hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
+		smsc911x_reg_write(pdata, HW_CFG, hwcfg);
+		udelay(10);	/* Enough time for clocks to restart */
+
+		hwcfg |= HW_CFG_SMI_SEL_;
+		smsc911x_reg_write(pdata, HW_CFG, hwcfg);
+
+		SMSC_TRACE(HW, "Successfully switched to external PHY");
+		pdata->using_extphy = 1;
+	} else {
+		SMSC_WARNING(HW, "No external PHY detected, "
+			"Using internal PHY instead.");
+		/* Use internal phy */
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/* Fetches a tx status out of the status fifo */
+static unsigned int smsc911x_tx_get_txstatus(struct smsc911x_data *pdata)
+{
+	unsigned int result =
+	    smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TSUSED_;
+
+	if (result != 0)
+		result = smsc911x_reg_read(pdata, TX_STATUS_FIFO);
+
+	return result;
+}
+
+/* Fetches the next rx status */
+static unsigned int smsc911x_rx_get_rxstatus(struct smsc911x_data *pdata)
+{
+	unsigned int result =
+	    smsc911x_reg_read(pdata, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED_;
+
+	if (result != 0)
+		result = smsc911x_reg_read(pdata, RX_STATUS_FIFO);
+
+	return result;
+}
+
+#ifdef USE_PHY_WORK_AROUND
+static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
+{
+	unsigned int tries;
+	u32 wrsz;
+	u32 rdsz;
+	ulong bufp;
+
+	for (tries = 0; tries < 10; tries++) {
+		unsigned int txcmd_a;
+		unsigned int txcmd_b;
+		unsigned int status;
+		unsigned int pktlength;
+		unsigned int i;
+
+		/* Zero-out rx packet memory */
+		memset(pdata->loopback_rx_pkt, 0, MIN_PACKET_SIZE);
+
+		/* Write tx packet to 118 */
+		txcmd_a = (u32)((ulong)pdata->loopback_tx_pkt & 0x03) << 16;
+		txcmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
+		txcmd_a |= MIN_PACKET_SIZE;
+
+		txcmd_b = MIN_PACKET_SIZE << 16 | MIN_PACKET_SIZE;
+
+		smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_a);
+		smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_b);
+
+		bufp = (ulong)pdata->loopback_tx_pkt & (~0x3);
+		wrsz = MIN_PACKET_SIZE + 3;
+		wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3);
+		wrsz >>= 2;
+
+		smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
+
+		/* Wait till transmit is done */
+		i = 60;
+		do {
+			udelay(5);
+			status = smsc911x_tx_get_txstatus(pdata);
+		} while ((i--) && (!status));
+
+		if (!status) {
+			SMSC_WARNING(HW, "Failed to transmit "
+				"during loopback test");
+			continue;
+		}
+		if (status & TX_STS_ES_) {
+			SMSC_WARNING(HW, "Transmit encountered "
+				"errors during loopback test");
+			continue;
+		}
+
+		/* Wait till receive is done */
+		i = 60;
+		do {
+			udelay(5);
+			status = smsc911x_rx_get_rxstatus(pdata);
+		} while ((i--) && (!status));
+
+		if (!status) {
+			SMSC_WARNING(HW,
+				"Failed to receive during loopback test");
+			continue;
+		}
+		if (status & RX_STS_ES_) {
+			SMSC_WARNING(HW, "Receive encountered "
+				"errors during loopback test");
+			continue;
+		}
+
+		pktlength = ((status & 0x3FFF0000UL) >> 16);
+		bufp = (ulong)pdata->loopback_rx_pkt;
+		rdsz = pktlength + 3;
+		rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3);
+		rdsz >>= 2;
+
+		smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz);
+
+		if (pktlength != (MIN_PACKET_SIZE + 4)) {
+			SMSC_WARNING(HW, "Unexpected packet size "
+				"during loop back test, size=%d, will retry",
+				pktlength);
+		} else {
+			unsigned int j;
+			int mismatch = 0;
+			for (j = 0; j < MIN_PACKET_SIZE; j++) {
+				if (pdata->loopback_tx_pkt[j]
+				    != pdata->loopback_rx_pkt[j]) {
+					mismatch = 1;
+					break;
+				}
+			}
+			if (!mismatch) {
+				SMSC_TRACE(HW, "Successfully verified "
+					   "loopback packet");
+				return 0;
+			} else {
+				SMSC_WARNING(HW, "Data mismatch "
+					"during loop back test, will retry");
+			}
+		}
+	}
+
+	return -EIO;
+}
+
+static int smsc911x_phy_reset(struct smsc911x_data *pdata)
+{
+	struct phy_device *phy_dev = pdata->phy_dev;
+	unsigned int temp;
+	unsigned int i = 100000;
+
+	BUG_ON(!phy_dev);
+	BUG_ON(!phy_dev->bus);
+
+	SMSC_TRACE(HW, "Performing PHY BCR Reset");
+	smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET);
+	do {
+		msleep(1);
+		temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr,
+			MII_BMCR);
+	} while ((i--) && (temp & BMCR_RESET));
+
+	if (temp & BMCR_RESET) {
+		SMSC_WARNING(HW, "PHY reset failed to complete.");
+		return -EIO;
+	}
+	/* Extra delay required because the phy may not be completed with
+	* its reset when BMCR_RESET is cleared. Specs say 256 uS is
+	* enough delay but using 1ms here to be safe */
+	msleep(1);
+
+	return 0;
+}
+
+static int smsc911x_phy_loopbacktest(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	struct phy_device *phy_dev = pdata->phy_dev;
+	int result = -EIO;
+	unsigned int i, val;
+	unsigned long flags;
+
+	/* Initialise tx packet using broadcast destination address */
+	memset(pdata->loopback_tx_pkt, 0xff, ETH_ALEN);
+
+	/* Use incrementing source address */
+	for (i = 6; i < 12; i++)
+		pdata->loopback_tx_pkt[i] = (char)i;
+
+	/* Set length type field */
+	pdata->loopback_tx_pkt[12] = 0x00;
+	pdata->loopback_tx_pkt[13] = 0x00;
+
+	for (i = 14; i < MIN_PACKET_SIZE; i++)
+		pdata->loopback_tx_pkt[i] = (char)i;
+
+	val = smsc911x_reg_read(pdata, HW_CFG);
+	val &= HW_CFG_TX_FIF_SZ_;
+	val |= HW_CFG_SF_;
+	smsc911x_reg_write(pdata, HW_CFG, val);
+
+	smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_);
+	smsc911x_reg_write(pdata, RX_CFG,
+		(u32)((ulong)pdata->loopback_rx_pkt & 0x03) << 8);
+
+	for (i = 0; i < 10; i++) {
+		/* Set PHY to 10/FD, no ANEG, and loopback mode */
+		smsc911x_mii_write(phy_dev->bus, phy_dev->addr,	MII_BMCR,
+			BMCR_LOOPBACK | BMCR_FULLDPLX);
+
+		/* Enable MAC tx/rx, FD */
+		spin_lock_irqsave(&pdata->mac_lock, flags);
+		smsc911x_mac_write(pdata, MAC_CR, MAC_CR_FDPX_
+				   | MAC_CR_TXEN_ | MAC_CR_RXEN_);
+		spin_unlock_irqrestore(&pdata->mac_lock, flags);
+
+		if (smsc911x_phy_check_loopbackpkt(pdata) == 0) {
+			result = 0;
+			break;
+		}
+		pdata->resetcount++;
+
+		/* Disable MAC rx */
+		spin_lock_irqsave(&pdata->mac_lock, flags);
+		smsc911x_mac_write(pdata, MAC_CR, 0);
+		spin_unlock_irqrestore(&pdata->mac_lock, flags);
+
+		smsc911x_phy_reset(pdata);
+	}
+
+	/* Disable MAC */
+	spin_lock_irqsave(&pdata->mac_lock, flags);
+	smsc911x_mac_write(pdata, MAC_CR, 0);
+	spin_unlock_irqrestore(&pdata->mac_lock, flags);
+
+	/* Cancel PHY loopback mode */
+	smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, 0);
+
+	smsc911x_reg_write(pdata, TX_CFG, 0);
+	smsc911x_reg_write(pdata, RX_CFG, 0);
+
+	return result;
+}
+#endif				/* USE_PHY_WORK_AROUND */
+
+static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata)
+{
+	struct phy_device *phy_dev = pdata->phy_dev;
+	u32 afc = smsc911x_reg_read(pdata, AFC_CFG);
+	u32 flow;
+	unsigned long flags;
+
+	if (phy_dev->duplex == DUPLEX_FULL) {
+		u16 lcladv = phy_read(phy_dev, MII_ADVERTISE);
+		u16 rmtadv = phy_read(phy_dev, MII_LPA);
+		u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+
+		if (cap & FLOW_CTRL_RX)
+			flow = 0xFFFF0002;
+		else
+			flow = 0;
+
+		if (cap & FLOW_CTRL_TX)
+			afc |= 0xF;
+		else
+			afc &= ~0xF;
+
+		SMSC_TRACE(HW, "rx pause %s, tx pause %s",
+			(cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
+			(cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
+	} else {
+		SMSC_TRACE(HW, "half duplex");
+		flow = 0;
+		afc |= 0xF;
+	}
+
+	spin_lock_irqsave(&pdata->mac_lock, flags);
+	smsc911x_mac_write(pdata, FLOW, flow);
+	spin_unlock_irqrestore(&pdata->mac_lock, flags);
+
+	smsc911x_reg_write(pdata, AFC_CFG, afc);
+}
+
+/* Update link mode if anything has changed.  Called periodically when the
+ * PHY is in polling mode, even if nothing has changed. */
+static void smsc911x_phy_adjust_link(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	struct phy_device *phy_dev = pdata->phy_dev;
+	unsigned long flags;
+	int carrier;
+
+	if (phy_dev->duplex != pdata->last_duplex) {
+		unsigned int mac_cr;
+		SMSC_TRACE(HW, "duplex state has changed");
+
+		spin_lock_irqsave(&pdata->mac_lock, flags);
+		mac_cr = smsc911x_mac_read(pdata, MAC_CR);
+		if (phy_dev->duplex) {
+			SMSC_TRACE(HW,
+				"configuring for full duplex mode");
+			mac_cr |= MAC_CR_FDPX_;
+		} else {
+			SMSC_TRACE(HW,
+				"configuring for half duplex mode");
+			mac_cr &= ~MAC_CR_FDPX_;
+		}
+		smsc911x_mac_write(pdata, MAC_CR, mac_cr);
+		spin_unlock_irqrestore(&pdata->mac_lock, flags);
+
+		smsc911x_phy_update_flowcontrol(pdata);
+		pdata->last_duplex = phy_dev->duplex;
+	}
+
+	carrier = netif_carrier_ok(dev);
+	if (carrier != pdata->last_carrier) {
+		SMSC_TRACE(HW, "carrier state has changed");
+		if (carrier) {
+			SMSC_TRACE(HW, "configuring for carrier OK");
+			if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) &&
+			    (!pdata->using_extphy)) {
+				/* Restore orginal GPIO configuration */
+				pdata->gpio_setting = pdata->gpio_orig_setting;
+				smsc911x_reg_write(pdata, GPIO_CFG,
+					pdata->gpio_setting);
+			}
+		} else {
+			SMSC_TRACE(HW, "configuring for no carrier");
+			/* Check global setting that LED1
+			 * usage is 10/100 indicator */
+			pdata->gpio_setting = smsc911x_reg_read(pdata,
+				GPIO_CFG);
+			if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_)
+			    && (!pdata->using_extphy)) {
+				/* Force 10/100 LED off, after saving
+				 * orginal GPIO configuration */
+				pdata->gpio_orig_setting = pdata->gpio_setting;
+
+				pdata->gpio_setting &= ~GPIO_CFG_LED1_EN_;
+				pdata->gpio_setting |= (GPIO_CFG_GPIOBUF0_
+							| GPIO_CFG_GPIODIR0_
+							| GPIO_CFG_GPIOD0_);
+				smsc911x_reg_write(pdata, GPIO_CFG,
+					pdata->gpio_setting);
+			}
+		}
+		pdata->last_carrier = carrier;
+	}
+}
+
+static int smsc911x_mii_probe(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	struct phy_device *phydev = NULL;
+	int phy_addr;
+
+	/* find the first phy */
+	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+		if (pdata->mii_bus->phy_map[phy_addr]) {
+			phydev = pdata->mii_bus->phy_map[phy_addr];
+			SMSC_TRACE(PROBE, "PHY %d: addr %d, phy_id 0x%08X",
+				phy_addr, phydev->addr, phydev->phy_id);
+			break;
+		}
+	}
+
+	if (!phydev) {
+		pr_err("%s: no PHY found\n", dev->name);
+		return -ENODEV;
+	}
+
+	phydev = phy_connect(dev, phydev->dev.bus_id,
+		&smsc911x_phy_adjust_link, 0, pdata->config.phy_interface);
+
+	if (IS_ERR(phydev)) {
+		pr_err("%s: Could not attach to PHY\n", dev->name);
+		return PTR_ERR(phydev);
+	}
+
+	pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+		dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+
+	/* mask with MAC supported features */
+	phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
+			      SUPPORTED_Asym_Pause);
+	phydev->advertising = phydev->supported;
+
+	pdata->phy_dev = phydev;
+	pdata->last_duplex = -1;
+	pdata->last_carrier = -1;
+
+#ifdef USE_PHY_WORK_AROUND
+	if (smsc911x_phy_loopbacktest(dev) < 0) {
+		SMSC_WARNING(HW, "Failed Loop Back Test");
+		return -ENODEV;
+	}
+	SMSC_TRACE(HW, "Passed Loop Back Test");
+#endif				/* USE_PHY_WORK_AROUND */
+
+	SMSC_TRACE(HW, "phy initialised succesfully");
+	return 0;
+}
+
+static int __devinit smsc911x_mii_init(struct platform_device *pdev,
+				       struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	int err = -ENXIO, i;
+
+	pdata->mii_bus = mdiobus_alloc();
+	if (!pdata->mii_bus) {
+		err = -ENOMEM;
+		goto err_out_1;
+	}
+
+	pdata->mii_bus->name = SMSC_MDIONAME;
+	snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+	pdata->mii_bus->priv = pdata;
+	pdata->mii_bus->read = smsc911x_mii_read;
+	pdata->mii_bus->write = smsc911x_mii_write;
+	pdata->mii_bus->irq = pdata->phy_irq;
+	for (i = 0; i < PHY_MAX_ADDR; ++i)
+		pdata->mii_bus->irq[i] = PHY_POLL;
+
+	pdata->mii_bus->parent = &pdev->dev;
+
+	pdata->using_extphy = 0;
+
+	switch (pdata->idrev & 0xFFFF0000) {
+	case 0x01170000:
+	case 0x01150000:
+	case 0x117A0000:
+	case 0x115A0000:
+		/* External PHY supported, try to autodetect */
+		if (smsc911x_phy_initialise_external(pdata) < 0) {
+			SMSC_TRACE(HW, "No external PHY detected, "
+				"using internal PHY");
+		}
+		break;
+	default:
+		SMSC_TRACE(HW, "External PHY is not supported, "
+			"using internal PHY");
+		break;
+	}
+
+	if (!pdata->using_extphy) {
+		/* Mask all PHYs except ID 1 (internal) */
+		pdata->mii_bus->phy_mask = ~(1 << 1);
+	}
+
+	if (mdiobus_register(pdata->mii_bus)) {
+		SMSC_WARNING(PROBE, "Error registering mii bus");
+		goto err_out_free_bus_2;
+	}
+
+	if (smsc911x_mii_probe(dev) < 0) {
+		SMSC_WARNING(PROBE, "Error registering mii bus");
+		goto err_out_unregister_bus_3;
+	}
+
+	return 0;
+
+err_out_unregister_bus_3:
+	mdiobus_unregister(pdata->mii_bus);
+err_out_free_bus_2:
+	mdiobus_free(pdata->mii_bus);
+err_out_1:
+	return err;
+}
+
+/* Gets the number of tx statuses in the fifo */
+static unsigned int smsc911x_tx_get_txstatcount(struct smsc911x_data *pdata)
+{
+	return (smsc911x_reg_read(pdata, TX_FIFO_INF)
+		& TX_FIFO_INF_TSUSED_) >> 16;
+}
+
+/* Reads tx statuses and increments counters where necessary */
+static void smsc911x_tx_update_txcounters(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	unsigned int tx_stat;
+
+	while ((tx_stat = smsc911x_tx_get_txstatus(pdata)) != 0) {
+		if (unlikely(tx_stat & 0x80000000)) {
+			/* In this driver the packet tag is used as the packet
+			 * length. Since a packet length can never reach the
+			 * size of 0x8000, this bit is reserved. It is worth
+			 * noting that the "reserved bit" in the warning above
+			 * does not reference a hardware defined reserved bit
+			 * but rather a driver defined one.
+			 */
+			SMSC_WARNING(HW,
+				"Packet tag reserved bit is high");
+		} else {
+			if (unlikely(tx_stat & 0x00008000)) {
+				dev->stats.tx_errors++;
+			} else {
+				dev->stats.tx_packets++;
+				dev->stats.tx_bytes += (tx_stat >> 16);
+			}
+			if (unlikely(tx_stat & 0x00000100)) {
+				dev->stats.collisions += 16;
+				dev->stats.tx_aborted_errors += 1;
+			} else {
+				dev->stats.collisions +=
+				    ((tx_stat >> 3) & 0xF);
+			}
+			if (unlikely(tx_stat & 0x00000800))
+				dev->stats.tx_carrier_errors += 1;
+			if (unlikely(tx_stat & 0x00000200)) {
+				dev->stats.collisions++;
+				dev->stats.tx_aborted_errors++;
+			}
+		}
+	}
+}
+
+/* Increments the Rx error counters */
+static void
+smsc911x_rx_counterrors(struct net_device *dev, unsigned int rxstat)
+{
+	int crc_err = 0;
+
+	if (unlikely(rxstat & 0x00008000)) {
+		dev->stats.rx_errors++;
+		if (unlikely(rxstat & 0x00000002)) {
+			dev->stats.rx_crc_errors++;
+			crc_err = 1;
+		}
+	}
+	if (likely(!crc_err)) {
+		if (unlikely((rxstat & 0x00001020) == 0x00001020)) {
+			/* Frame type indicates length,
+			 * and length error is set */
+			dev->stats.rx_length_errors++;
+		}
+		if (rxstat & RX_STS_MCAST_)
+			dev->stats.multicast++;
+	}
+}
+
+/* Quickly dumps bad packets */
+static void
+smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes)
+{
+	unsigned int pktwords = (pktbytes + NET_IP_ALIGN + 3) >> 2;
+
+	if (likely(pktwords >= 4)) {
+		unsigned int timeout = 500;
+		unsigned int val;
+		smsc911x_reg_write(pdata, RX_DP_CTRL, RX_DP_CTRL_RX_FFWD_);
+		do {
+			udelay(1);
+			val = smsc911x_reg_read(pdata, RX_DP_CTRL);
+		} while (timeout-- && (val & RX_DP_CTRL_RX_FFWD_));
+
+		if (unlikely(timeout == 0))
+			SMSC_WARNING(HW, "Timed out waiting for "
+				"RX FFWD to finish, RX_DP_CTRL: 0x%08X", val);
+	} else {
+		unsigned int temp;
+		while (pktwords--)
+			temp = smsc911x_reg_read(pdata, RX_DATA_FIFO);
+	}
+}
+
+/* NAPI poll function */
+static int smsc911x_poll(struct napi_struct *napi, int budget)
+{
+	struct smsc911x_data *pdata =
+		container_of(napi, struct smsc911x_data, napi);
+	struct net_device *dev = pdata->dev;
+	int npackets = 0;
+
+	while (likely(netif_running(dev)) && (npackets < budget)) {
+		unsigned int pktlength;
+		unsigned int pktwords;
+		struct sk_buff *skb;
+		unsigned int rxstat = smsc911x_rx_get_rxstatus(pdata);
+
+		if (!rxstat) {
+			unsigned int temp;
+			/* We processed all packets available.  Tell NAPI it can
+			 * stop polling then re-enable rx interrupts */
+			smsc911x_reg_write(pdata, INT_STS, INT_STS_RSFL_);
+			netif_rx_complete(napi);
+			temp = smsc911x_reg_read(pdata, INT_EN);
+			temp |= INT_EN_RSFL_EN_;
+			smsc911x_reg_write(pdata, INT_EN, temp);
+			break;
+		}
+
+		/* Count packet for NAPI scheduling, even if it has an error.
+		 * Error packets still require cycles to discard */
+		npackets++;
+
+		pktlength = ((rxstat & 0x3FFF0000) >> 16);
+		pktwords = (pktlength + NET_IP_ALIGN + 3) >> 2;
+		smsc911x_rx_counterrors(dev, rxstat);
+
+		if (unlikely(rxstat & RX_STS_ES_)) {
+			SMSC_WARNING(RX_ERR,
+				"Discarding packet with error bit set");
+			/* Packet has an error, discard it and continue with
+			 * the next */
+			smsc911x_rx_fastforward(pdata, pktwords);
+			dev->stats.rx_dropped++;
+			continue;
+		}
+
+		skb = netdev_alloc_skb(dev, pktlength + NET_IP_ALIGN);
+		if (unlikely(!skb)) {
+			SMSC_WARNING(RX_ERR,
+				"Unable to allocate skb for rx packet");
+			/* Drop the packet and stop this polling iteration */
+			smsc911x_rx_fastforward(pdata, pktwords);
+			dev->stats.rx_dropped++;
+			break;
+		}
+
+		skb->data = skb->head;
+		skb_reset_tail_pointer(skb);
+
+		/* Align IP on 16B boundary */
+		skb_reserve(skb, NET_IP_ALIGN);
+		skb_put(skb, pktlength - 4);
+		smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head,
+				     pktwords);
+		skb->protocol = eth_type_trans(skb, dev);
+		skb->ip_summed = CHECKSUM_NONE;
+		netif_receive_skb(skb);
+
+		/* Update counters */
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += (pktlength - 4);
+		dev->last_rx = jiffies;
+	}
+
+	/* Return total received packets */
+	return npackets;
+}
+
+/* Returns hash bit number for given MAC address
+ * Example:
+ * 01 00 5E 00 00 01 -> returns bit number 31 */
+static unsigned int smsc911x_hash(char addr[ETH_ALEN])
+{
+	return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
+}
+
+static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata)
+{
+	/* Performs the multicast & mac_cr update.  This is called when
+	 * safe on the current hardware, and with the mac_lock held */
+	unsigned int mac_cr;
+
+	SMSC_ASSERT_MAC_LOCK(pdata);
+
+	mac_cr = smsc911x_mac_read(pdata, MAC_CR);
+	mac_cr |= pdata->set_bits_mask;
+	mac_cr &= ~(pdata->clear_bits_mask);
+	smsc911x_mac_write(pdata, MAC_CR, mac_cr);
+	smsc911x_mac_write(pdata, HASHH, pdata->hashhi);
+	smsc911x_mac_write(pdata, HASHL, pdata->hashlo);
+	SMSC_TRACE(HW, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X",
+		mac_cr, pdata->hashhi, pdata->hashlo);
+}
+
+static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata)
+{
+	unsigned int mac_cr;
+
+	/* This function is only called for older LAN911x devices
+	 * (revA or revB), where MAC_CR, HASHH and HASHL should not
+	 * be modified during Rx - newer devices immediately update the
+	 * registers.
+	 *
+	 * This is called from interrupt context */
+
+	spin_lock(&pdata->mac_lock);
+
+	/* Check Rx has stopped */
+	if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_)
+		SMSC_WARNING(DRV, "Rx not stopped");
+
+	/* Perform the update - safe to do now Rx has stopped */
+	smsc911x_rx_multicast_update(pdata);
+
+	/* Re-enable Rx */
+	mac_cr = smsc911x_mac_read(pdata, MAC_CR);
+	mac_cr |= MAC_CR_RXEN_;
+	smsc911x_mac_write(pdata, MAC_CR, mac_cr);
+
+	pdata->multicast_update_pending = 0;
+
+	spin_unlock(&pdata->mac_lock);
+}
+
+static int smsc911x_soft_reset(struct smsc911x_data *pdata)
+{
+	unsigned int timeout;
+	unsigned int temp;
+
+	/* Reset the LAN911x */
+	smsc911x_reg_write(pdata, HW_CFG, HW_CFG_SRST_);
+	timeout = 10;
+	do {
+		udelay(10);
+		temp = smsc911x_reg_read(pdata, HW_CFG);
+	} while ((--timeout) && (temp & HW_CFG_SRST_));
+
+	if (unlikely(temp & HW_CFG_SRST_)) {
+		SMSC_WARNING(DRV, "Failed to complete reset");
+		return -EIO;
+	}
+	return 0;
+}
+
+/* Sets the device MAC address to dev_addr, called with mac_lock held */
+static void
+smsc911x_set_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6])
+{
+	u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4];
+	u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
+	    (dev_addr[1] << 8) | dev_addr[0];
+
+	SMSC_ASSERT_MAC_LOCK(pdata);
+
+	smsc911x_mac_write(pdata, ADDRH, mac_high16);
+	smsc911x_mac_write(pdata, ADDRL, mac_low32);
+}
+
+static int smsc911x_open(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	unsigned int timeout;
+	unsigned int temp;
+	unsigned int intcfg;
+
+	/* if the phy is not yet registered, retry later*/
+	if (!pdata->phy_dev) {
+		SMSC_WARNING(HW, "phy_dev is NULL");
+		return -EAGAIN;
+	}
+
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		SMSC_WARNING(HW, "dev_addr is not a valid MAC address");
+		return -EADDRNOTAVAIL;
+	}
+
+	/* Reset the LAN911x */
+	if (smsc911x_soft_reset(pdata)) {
+		SMSC_WARNING(HW, "soft reset failed");
+		return -EIO;
+	}
+
+	smsc911x_reg_write(pdata, HW_CFG, 0x00050000);
+	smsc911x_reg_write(pdata, AFC_CFG, 0x006E3740);
+
+	/* Make sure EEPROM has finished loading before setting GPIO_CFG */
+	timeout = 50;
+	while ((timeout--) &&
+	       (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_)) {
+		udelay(10);
+	}
+
+	if (unlikely(timeout == 0))
+		SMSC_WARNING(IFUP,
+			"Timed out waiting for EEPROM busy bit to clear");
+
+	smsc911x_reg_write(pdata, GPIO_CFG, 0x70070000);
+
+	/* The soft reset above cleared the device's MAC address,
+	 * restore it from local copy (set in probe) */
+	spin_lock_irq(&pdata->mac_lock);
+	smsc911x_set_mac_address(pdata, dev->dev_addr);
+	spin_unlock_irq(&pdata->mac_lock);
+
+	/* Initialise irqs, but leave all sources disabled */
+	smsc911x_reg_write(pdata, INT_EN, 0);
+	smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
+
+	/* Set interrupt deassertion to 100uS */
+	intcfg = ((10 << 24) | INT_CFG_IRQ_EN_);
+
+	if (pdata->config.irq_polarity) {
+		SMSC_TRACE(IFUP, "irq polarity: active high");
+		intcfg |= INT_CFG_IRQ_POL_;
+	} else {
+		SMSC_TRACE(IFUP, "irq polarity: active low");
+	}
+
+	if (pdata->config.irq_type) {
+		SMSC_TRACE(IFUP, "irq type: push-pull");
+		intcfg |= INT_CFG_IRQ_TYPE_;
+	} else {
+		SMSC_TRACE(IFUP, "irq type: open drain");
+	}
+
+	smsc911x_reg_write(pdata, INT_CFG, intcfg);
+
+	SMSC_TRACE(IFUP, "Testing irq handler using IRQ %d", dev->irq);
+	pdata->software_irq_signal = 0;
+	smp_wmb();
+
+	temp = smsc911x_reg_read(pdata, INT_EN);
+	temp |= INT_EN_SW_INT_EN_;
+	smsc911x_reg_write(pdata, INT_EN, temp);
+
+	timeout = 1000;
+	while (timeout--) {
+		if (pdata->software_irq_signal)
+			break;
+		msleep(1);
+	}
+
+	if (!pdata->software_irq_signal) {
+		dev_warn(&dev->dev, "ISR failed signaling test (IRQ %d)\n",
+			 dev->irq);
+		return -ENODEV;
+	}
+	SMSC_TRACE(IFUP, "IRQ handler passed test using IRQ %d", dev->irq);
+
+	dev_info(&dev->dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n",
+		 (unsigned long)pdata->ioaddr, dev->irq);
+
+	/* Bring the PHY up */
+	phy_start(pdata->phy_dev);
+
+	temp = smsc911x_reg_read(pdata, HW_CFG);
+	/* Preserve TX FIFO size and external PHY configuration */
+	temp &= (HW_CFG_TX_FIF_SZ_|0x00000FFF);
+	temp |= HW_CFG_SF_;
+	smsc911x_reg_write(pdata, HW_CFG, temp);
+
+	temp = smsc911x_reg_read(pdata, FIFO_INT);
+	temp |= FIFO_INT_TX_AVAIL_LEVEL_;
+	temp &= ~(FIFO_INT_RX_STS_LEVEL_);
+	smsc911x_reg_write(pdata, FIFO_INT, temp);
+
+	/* set RX Data offset to 2 bytes for alignment */
+	smsc911x_reg_write(pdata, RX_CFG, (2 << 8));
+
+	/* enable NAPI polling before enabling RX interrupts */
+	napi_enable(&pdata->napi);
+
+	temp = smsc911x_reg_read(pdata, INT_EN);
+	temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_);
+	smsc911x_reg_write(pdata, INT_EN, temp);
+
+	spin_lock_irq(&pdata->mac_lock);
+	temp = smsc911x_mac_read(pdata, MAC_CR);
+	temp |= (MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_);
+	smsc911x_mac_write(pdata, MAC_CR, temp);
+	spin_unlock_irq(&pdata->mac_lock);
+
+	smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_);
+
+	netif_start_queue(dev);
+	return 0;
+}
+
+/* Entry point for stopping the interface */
+static int smsc911x_stop(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	unsigned int temp;
+
+	/* Disable all device interrupts */
+	temp = smsc911x_reg_read(pdata, INT_CFG);
+	temp &= ~INT_CFG_IRQ_EN_;
+	smsc911x_reg_write(pdata, INT_CFG, temp);
+
+	/* Stop Tx and Rx polling */
+	netif_stop_queue(dev);
+	napi_disable(&pdata->napi);
+
+	/* At this point all Rx and Tx activity is stopped */
+	dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
+	smsc911x_tx_update_txcounters(dev);
+
+	/* Bring the PHY down */
+	if (pdata->phy_dev)
+		phy_stop(pdata->phy_dev);
+
+	SMSC_TRACE(IFDOWN, "Interface stopped");
+	return 0;
+}
+
+/* Entry point for transmitting a packet */
+static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	unsigned int freespace;
+	unsigned int tx_cmd_a;
+	unsigned int tx_cmd_b;
+	unsigned int temp;
+	u32 wrsz;
+	ulong bufp;
+
+	freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_;
+
+	if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD))
+		SMSC_WARNING(TX_ERR,
+			"Tx data fifo low, space available: %d", freespace);
+
+	/* Word alignment adjustment */
+	tx_cmd_a = (u32)((ulong)skb->data & 0x03) << 16;
+	tx_cmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
+	tx_cmd_a |= (unsigned int)skb->len;
+
+	tx_cmd_b = ((unsigned int)skb->len) << 16;
+	tx_cmd_b |= (unsigned int)skb->len;
+
+	smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_a);
+	smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_b);
+
+	bufp = (ulong)skb->data & (~0x3);
+	wrsz = (u32)skb->len + 3;
+	wrsz += (u32)((ulong)skb->data & 0x3);
+	wrsz >>= 2;
+
+	smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
+	freespace -= (skb->len + 32);
+	dev_kfree_skb(skb);
+	dev->trans_start = jiffies;
+
+	if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30))
+		smsc911x_tx_update_txcounters(dev);
+
+	if (freespace < TX_FIFO_LOW_THRESHOLD) {
+		netif_stop_queue(dev);
+		temp = smsc911x_reg_read(pdata, FIFO_INT);
+		temp &= 0x00FFFFFF;
+		temp |= 0x32000000;
+		smsc911x_reg_write(pdata, FIFO_INT, temp);
+	}
+
+	return NETDEV_TX_OK;
+}
+
+/* Entry point for getting status counters */
+static struct net_device_stats *smsc911x_get_stats(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	smsc911x_tx_update_txcounters(dev);
+	dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
+	return &dev->stats;
+}
+
+/* Entry point for setting addressing modes */
+static void smsc911x_set_multicast_list(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	unsigned long flags;
+
+	if (dev->flags & IFF_PROMISC) {
+		/* Enabling promiscuous mode */
+		pdata->set_bits_mask = MAC_CR_PRMS_;
+		pdata->clear_bits_mask = (MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+		pdata->hashhi = 0;
+		pdata->hashlo = 0;
+	} else if (dev->flags & IFF_ALLMULTI) {
+		/* Enabling all multicast mode */
+		pdata->set_bits_mask = MAC_CR_MCPAS_;
+		pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_);
+		pdata->hashhi = 0;
+		pdata->hashlo = 0;
+	} else if (dev->mc_count > 0) {
+		/* Enabling specific multicast addresses */
+		unsigned int hash_high = 0;
+		unsigned int hash_low = 0;
+		unsigned int count = 0;
+		struct dev_mc_list *mc_list = dev->mc_list;
+
+		pdata->set_bits_mask = MAC_CR_HPFILT_;
+		pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_);
+
+		while (mc_list) {
+			count++;
+			if ((mc_list->dmi_addrlen) == ETH_ALEN) {
+				unsigned int bitnum =
+				    smsc911x_hash(mc_list->dmi_addr);
+				unsigned int mask = 0x01 << (bitnum & 0x1F);
+				if (bitnum & 0x20)
+					hash_high |= mask;
+				else
+					hash_low |= mask;
+			} else {
+				SMSC_WARNING(DRV, "dmi_addrlen != 6");
+			}
+			mc_list = mc_list->next;
+		}
+		if (count != (unsigned int)dev->mc_count)
+			SMSC_WARNING(DRV, "mc_count != dev->mc_count");
+
+		pdata->hashhi = hash_high;
+		pdata->hashlo = hash_low;
+	} else {
+		/* Enabling local MAC address only */
+		pdata->set_bits_mask = 0;
+		pdata->clear_bits_mask =
+		    (MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+		pdata->hashhi = 0;
+		pdata->hashlo = 0;
+	}
+
+	spin_lock_irqsave(&pdata->mac_lock, flags);
+
+	if (pdata->generation <= 1) {
+		/* Older hardware revision - cannot change these flags while
+		 * receiving data */
+		if (!pdata->multicast_update_pending) {
+			unsigned int temp;
+			SMSC_TRACE(HW, "scheduling mcast update");
+			pdata->multicast_update_pending = 1;
+
+			/* Request the hardware to stop, then perform the
+			 * update when we get an RX_STOP interrupt */
+			smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_);
+			temp = smsc911x_reg_read(pdata, INT_EN);
+			temp |= INT_EN_RXSTOP_INT_EN_;
+			smsc911x_reg_write(pdata, INT_EN, temp);
+
+			temp = smsc911x_mac_read(pdata, MAC_CR);
+			temp &= ~(MAC_CR_RXEN_);
+			smsc911x_mac_write(pdata, MAC_CR, temp);
+		} else {
+			/* There is another update pending, this should now
+			 * use the newer values */
+		}
+	} else {
+		/* Newer hardware revision - can write immediately */
+		smsc911x_rx_multicast_update(pdata);
+	}
+
+	spin_unlock_irqrestore(&pdata->mac_lock, flags);
+}
+
+static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	u32 intsts = smsc911x_reg_read(pdata, INT_STS);
+	u32 inten = smsc911x_reg_read(pdata, INT_EN);
+	int serviced = IRQ_NONE;
+	u32 temp;
+
+	if (unlikely(intsts & inten & INT_STS_SW_INT_)) {
+		temp = smsc911x_reg_read(pdata, INT_EN);
+		temp &= (~INT_EN_SW_INT_EN_);
+		smsc911x_reg_write(pdata, INT_EN, temp);
+		smsc911x_reg_write(pdata, INT_STS, INT_STS_SW_INT_);
+		pdata->software_irq_signal = 1;
+		smp_wmb();
+		serviced = IRQ_HANDLED;
+	}
+
+	if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) {
+		/* Called when there is a multicast update scheduled and
+		 * it is now safe to complete the update */
+		SMSC_TRACE(INTR, "RX Stop interrupt");
+		temp = smsc911x_reg_read(pdata, INT_EN);
+		temp &= (~INT_EN_RXSTOP_INT_EN_);
+		smsc911x_reg_write(pdata, INT_EN, temp);
+		smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_);
+		smsc911x_rx_multicast_update_workaround(pdata);
+		serviced = IRQ_HANDLED;
+	}
+
+	if (intsts & inten & INT_STS_TDFA_) {
+		temp = smsc911x_reg_read(pdata, FIFO_INT);
+		temp |= FIFO_INT_TX_AVAIL_LEVEL_;
+		smsc911x_reg_write(pdata, FIFO_INT, temp);
+		smsc911x_reg_write(pdata, INT_STS, INT_STS_TDFA_);
+		netif_wake_queue(dev);
+		serviced = IRQ_HANDLED;
+	}
+
+	if (unlikely(intsts & inten & INT_STS_RXE_)) {
+		SMSC_TRACE(INTR, "RX Error interrupt");
+		smsc911x_reg_write(pdata, INT_STS, INT_STS_RXE_);
+		serviced = IRQ_HANDLED;
+	}
+
+	if (likely(intsts & inten & INT_STS_RSFL_)) {
+		if (likely(netif_rx_schedule_prep(dev, &pdata->napi))) {
+			/* Disable Rx interrupts */
+			temp = smsc911x_reg_read(pdata, INT_EN);
+			temp &= (~INT_EN_RSFL_EN_);
+			smsc911x_reg_write(pdata, INT_EN, temp);
+			/* Schedule a NAPI poll */
+			__netif_rx_schedule(dev, &pdata->napi);
+		} else {
+			SMSC_WARNING(RX_ERR,
+				"netif_rx_schedule_prep failed");
+		}
+		serviced = IRQ_HANDLED;
+	}
+
+	return serviced;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void smsc911x_poll_controller(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	smsc911x_irqhandler(0, dev);
+	enable_irq(dev->irq);
+}
+#endif				/* CONFIG_NET_POLL_CONTROLLER */
+
+/* Standard ioctls for mii-tool */
+static int smsc911x_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+
+	if (!netif_running(dev) || !pdata->phy_dev)
+		return -EINVAL;
+
+	return phy_mii_ioctl(pdata->phy_dev, if_mii(ifr), cmd);
+}
+
+static int
+smsc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+
+	cmd->maxtxpkt = 1;
+	cmd->maxrxpkt = 1;
+	return phy_ethtool_gset(pdata->phy_dev, cmd);
+}
+
+static int
+smsc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+
+	return phy_ethtool_sset(pdata->phy_dev, cmd);
+}
+
+static void smsc911x_ethtool_getdrvinfo(struct net_device *dev,
+					struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, SMSC_CHIPNAME, sizeof(info->driver));
+	strlcpy(info->version, SMSC_DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, dev->dev.parent->bus_id,
+		sizeof(info->bus_info));
+}
+
+static int smsc911x_ethtool_nwayreset(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+
+	return phy_start_aneg(pdata->phy_dev);
+}
+
+static u32 smsc911x_ethtool_getmsglevel(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	return pdata->msg_enable;
+}
+
+static void smsc911x_ethtool_setmsglevel(struct net_device *dev, u32 level)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	pdata->msg_enable = level;
+}
+
+static int smsc911x_ethtool_getregslen(struct net_device *dev)
+{
+	return (((E2P_DATA - ID_REV) / 4 + 1) + (WUCSR - MAC_CR) + 1 + 32) *
+	    sizeof(u32);
+}
+
+static void
+smsc911x_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs,
+			 void *buf)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	struct phy_device *phy_dev = pdata->phy_dev;
+	unsigned long flags;
+	unsigned int i;
+	unsigned int j = 0;
+	u32 *data = buf;
+
+	regs->version = pdata->idrev;
+	for (i = ID_REV; i <= E2P_DATA; i += (sizeof(u32)))
+		data[j++] = smsc911x_reg_read(pdata, i);
+
+	for (i = MAC_CR; i <= WUCSR; i++) {
+		spin_lock_irqsave(&pdata->mac_lock, flags);
+		data[j++] = smsc911x_mac_read(pdata, i);
+		spin_unlock_irqrestore(&pdata->mac_lock, flags);
+	}
+
+	for (i = 0; i <= 31; i++)
+		data[j++] = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, i);
+}
+
+static void smsc911x_eeprom_enable_access(struct smsc911x_data *pdata)
+{
+	unsigned int temp = smsc911x_reg_read(pdata, GPIO_CFG);
+	temp &= ~GPIO_CFG_EEPR_EN_;
+	smsc911x_reg_write(pdata, GPIO_CFG, temp);
+	msleep(1);
+}
+
+static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op)
+{
+	int timeout = 100;
+	u32 e2cmd;
+
+	SMSC_TRACE(DRV, "op 0x%08x", op);
+	if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
+		SMSC_WARNING(DRV, "Busy at start");
+		return -EBUSY;
+	}
+
+	e2cmd = op | E2P_CMD_EPC_BUSY_;
+	smsc911x_reg_write(pdata, E2P_CMD, e2cmd);
+
+	do {
+		msleep(1);
+		e2cmd = smsc911x_reg_read(pdata, E2P_CMD);
+	} while ((e2cmd & E2P_CMD_EPC_BUSY_) && (timeout--));
+
+	if (!timeout) {
+		SMSC_TRACE(DRV, "TIMED OUT");
+		return -EAGAIN;
+	}
+
+	if (e2cmd & E2P_CMD_EPC_TIMEOUT_) {
+		SMSC_TRACE(DRV, "Error occured during eeprom operation");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata,
+					 u8 address, u8 *data)
+{
+	u32 op = E2P_CMD_EPC_CMD_READ_ | address;
+	int ret;
+
+	SMSC_TRACE(DRV, "address 0x%x", address);
+	ret = smsc911x_eeprom_send_cmd(pdata, op);
+
+	if (!ret)
+		data[address] = smsc911x_reg_read(pdata, E2P_DATA);
+
+	return ret;
+}
+
+static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata,
+					  u8 address, u8 data)
+{
+	u32 op = E2P_CMD_EPC_CMD_ERASE_ | address;
+	int ret;
+
+	SMSC_TRACE(DRV, "address 0x%x, data 0x%x", address, data);
+	ret = smsc911x_eeprom_send_cmd(pdata, op);
+
+	if (!ret) {
+		op = E2P_CMD_EPC_CMD_WRITE_ | address;
+		smsc911x_reg_write(pdata, E2P_DATA, (u32)data);
+		ret = smsc911x_eeprom_send_cmd(pdata, op);
+	}
+
+	return ret;
+}
+
+static int smsc911x_ethtool_get_eeprom_len(struct net_device *dev)
+{
+	return SMSC911X_EEPROM_SIZE;
+}
+
+static int smsc911x_ethtool_get_eeprom(struct net_device *dev,
+				       struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	u8 eeprom_data[SMSC911X_EEPROM_SIZE];
+	int len;
+	int i;
+
+	smsc911x_eeprom_enable_access(pdata);
+
+	len = min(eeprom->len, SMSC911X_EEPROM_SIZE);
+	for (i = 0; i < len; i++) {
+		int ret = smsc911x_eeprom_read_location(pdata, i, eeprom_data);
+		if (ret < 0) {
+			eeprom->len = 0;
+			return ret;
+		}
+	}
+
+	memcpy(data, &eeprom_data[eeprom->offset], len);
+	eeprom->len = len;
+	return 0;
+}
+
+static int smsc911x_ethtool_set_eeprom(struct net_device *dev,
+				       struct ethtool_eeprom *eeprom, u8 *data)
+{
+	int ret;
+	struct smsc911x_data *pdata = netdev_priv(dev);
+
+	smsc911x_eeprom_enable_access(pdata);
+	smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWEN_);
+	ret = smsc911x_eeprom_write_location(pdata, eeprom->offset, *data);
+	smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWDS_);
+
+	/* Single byte write, according to man page */
+	eeprom->len = 1;
+
+	return ret;
+}
+
+static const struct ethtool_ops smsc911x_ethtool_ops = {
+	.get_settings = smsc911x_ethtool_getsettings,
+	.set_settings = smsc911x_ethtool_setsettings,
+	.get_link = ethtool_op_get_link,
+	.get_drvinfo = smsc911x_ethtool_getdrvinfo,
+	.nway_reset = smsc911x_ethtool_nwayreset,
+	.get_msglevel = smsc911x_ethtool_getmsglevel,
+	.set_msglevel = smsc911x_ethtool_setmsglevel,
+	.get_regs_len = smsc911x_ethtool_getregslen,
+	.get_regs = smsc911x_ethtool_getregs,
+	.get_eeprom_len = smsc911x_ethtool_get_eeprom_len,
+	.get_eeprom = smsc911x_ethtool_get_eeprom,
+	.set_eeprom = smsc911x_ethtool_set_eeprom,
+};
+
+static const struct net_device_ops smsc911x_netdev_ops = {
+	.ndo_open		= smsc911x_open,
+	.ndo_stop		= smsc911x_stop,
+	.ndo_start_xmit		= smsc911x_hard_start_xmit,
+	.ndo_get_stats		= smsc911x_get_stats,
+	.ndo_set_multicast_list	= smsc911x_set_multicast_list,
+	.ndo_do_ioctl		= smsc911x_do_ioctl,
+	.ndo_validate_addr	= eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= smsc911x_poll_controller,
+#endif
+};
+
+/* Initializing private device structures, only called from probe */
+static int __devinit smsc911x_init(struct net_device *dev)
+{
+	struct smsc911x_data *pdata = netdev_priv(dev);
+	unsigned int byte_test;
+
+	SMSC_TRACE(PROBE, "Driver Parameters:");
+	SMSC_TRACE(PROBE, "LAN base: 0x%08lX",
+		(unsigned long)pdata->ioaddr);
+	SMSC_TRACE(PROBE, "IRQ: %d", dev->irq);
+	SMSC_TRACE(PROBE, "PHY will be autodetected.");
+
+	spin_lock_init(&pdata->dev_lock);
+
+	if (pdata->ioaddr == 0) {
+		SMSC_WARNING(PROBE, "pdata->ioaddr: 0x00000000");
+		return -ENODEV;
+	}
+
+	/* Check byte ordering */
+	byte_test = smsc911x_reg_read(pdata, BYTE_TEST);
+	SMSC_TRACE(PROBE, "BYTE_TEST: 0x%08X", byte_test);
+	if (byte_test == 0x43218765) {
+		SMSC_TRACE(PROBE, "BYTE_TEST looks swapped, "
+			"applying WORD_SWAP");
+		smsc911x_reg_write(pdata, WORD_SWAP, 0xffffffff);
+
+		/* 1 dummy read of BYTE_TEST is needed after a write to
+		 * WORD_SWAP before its contents are valid */
+		byte_test = smsc911x_reg_read(pdata, BYTE_TEST);
+
+		byte_test = smsc911x_reg_read(pdata, BYTE_TEST);
+	}
+
+	if (byte_test != 0x87654321) {
+		SMSC_WARNING(DRV, "BYTE_TEST: 0x%08X", byte_test);
+		if (((byte_test >> 16) & 0xFFFF) == (byte_test & 0xFFFF)) {
+			SMSC_WARNING(PROBE,
+				"top 16 bits equal to bottom 16 bits");
+			SMSC_TRACE(PROBE, "This may mean the chip is set "
+				"for 32 bit while the bus is reading 16 bit");
+		}
+		return -ENODEV;
+	}
+
+	/* Default generation to zero (all workarounds apply) */
+	pdata->generation = 0;
+
+	pdata->idrev = smsc911x_reg_read(pdata, ID_REV);
+	switch (pdata->idrev & 0xFFFF0000) {
+	case 0x01180000:
+	case 0x01170000:
+	case 0x01160000:
+	case 0x01150000:
+		/* LAN911[5678] family */
+		pdata->generation = pdata->idrev & 0x0000FFFF;
+		break;
+
+	case 0x118A0000:
+	case 0x117A0000:
+	case 0x116A0000:
+	case 0x115A0000:
+		/* LAN921[5678] family */
+		pdata->generation = 3;
+		break;
+
+	case 0x92100000:
+	case 0x92110000:
+	case 0x92200000:
+	case 0x92210000:
+		/* LAN9210/LAN9211/LAN9220/LAN9221 */
+		pdata->generation = 4;
+		break;
+
+	default:
+		SMSC_WARNING(PROBE, "LAN911x not identified, idrev: 0x%08X",
+			pdata->idrev);
+		return -ENODEV;
+	}
+
+	SMSC_TRACE(PROBE, "LAN911x identified, idrev: 0x%08X, generation: %d",
+		pdata->idrev, pdata->generation);
+
+	if (pdata->generation == 0)
+		SMSC_WARNING(PROBE,
+			"This driver is not intended for this chip revision");
+
+	/* Reset the LAN911x */
+	if (smsc911x_soft_reset(pdata))
+		return -ENODEV;
+
+	/* Disable all interrupt sources until we bring the device up */
+	smsc911x_reg_write(pdata, INT_EN, 0);
+
+	ether_setup(dev);
+	dev->flags |= IFF_MULTICAST;
+	netif_napi_add(dev, &pdata->napi, smsc911x_poll, SMSC_NAPI_WEIGHT);
+	dev->netdev_ops = &smsc911x_netdev_ops;
+	dev->ethtool_ops = &smsc911x_ethtool_ops;
+
+	return 0;
+}
+
+static int __devexit smsc911x_drv_remove(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct smsc911x_data *pdata;
+	struct resource *res;
+
+	dev = platform_get_drvdata(pdev);
+	BUG_ON(!dev);
+	pdata = netdev_priv(dev);
+	BUG_ON(!pdata);
+	BUG_ON(!pdata->ioaddr);
+	BUG_ON(!pdata->phy_dev);
+
+	SMSC_TRACE(IFDOWN, "Stopping driver.");
+
+	phy_disconnect(pdata->phy_dev);
+	pdata->phy_dev = NULL;
+	mdiobus_unregister(pdata->mii_bus);
+	mdiobus_free(pdata->mii_bus);
+
+	platform_set_drvdata(pdev, NULL);
+	unregister_netdev(dev);
+	free_irq(dev->irq, dev);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   "smsc911x-memory");
+	if (!res)
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	release_mem_region(res->start, res->end - res->start);
+
+	iounmap(pdata->ioaddr);
+
+	free_netdev(dev);
+
+	return 0;
+}
+
+static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct smsc911x_data *pdata;
+	struct smsc911x_platform_config *config = pdev->dev.platform_data;
+	struct resource *res;
+	unsigned int intcfg = 0;
+	int res_size;
+	int retval;
+	DECLARE_MAC_BUF(mac);
+
+	pr_info("%s: Driver version %s.\n", SMSC_CHIPNAME, SMSC_DRV_VERSION);
+
+	/* platform data specifies irq & dynamic bus configuration */
+	if (!pdev->dev.platform_data) {
+		pr_warning("%s: platform_data not provided\n", SMSC_CHIPNAME);
+		retval = -ENODEV;
+		goto out_0;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   "smsc911x-memory");
+	if (!res)
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		pr_warning("%s: Could not allocate resource.\n",
+			SMSC_CHIPNAME);
+		retval = -ENODEV;
+		goto out_0;
+	}
+	res_size = res->end - res->start;
+
+	if (!request_mem_region(res->start, res_size, SMSC_CHIPNAME)) {
+		retval = -EBUSY;
+		goto out_0;
+	}
+
+	dev = alloc_etherdev(sizeof(struct smsc911x_data));
+	if (!dev) {
+		pr_warning("%s: Could not allocate device.\n", SMSC_CHIPNAME);
+		retval = -ENOMEM;
+		goto out_release_io_1;
+	}
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	pdata = netdev_priv(dev);
+
+	dev->irq = platform_get_irq(pdev, 0);
+	pdata->ioaddr = ioremap_nocache(res->start, res_size);
+
+	/* copy config parameters across to pdata */
+	memcpy(&pdata->config, config, sizeof(pdata->config));
+
+	pdata->dev = dev;
+	pdata->msg_enable = ((1 << debug) - 1);
+
+	if (pdata->ioaddr == NULL) {
+		SMSC_WARNING(PROBE,
+			"Error smsc911x base address invalid");
+		retval = -ENOMEM;
+		goto out_free_netdev_2;
+	}
+
+	retval = smsc911x_init(dev);
+	if (retval < 0)
+		goto out_unmap_io_3;
+
+	/* configure irq polarity and type before connecting isr */
+	if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
+		intcfg |= INT_CFG_IRQ_POL_;
+
+	if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL)
+		intcfg |= INT_CFG_IRQ_TYPE_;
+
+	smsc911x_reg_write(pdata, INT_CFG, intcfg);
+
+	/* Ensure interrupts are globally disabled before connecting ISR */
+	smsc911x_reg_write(pdata, INT_EN, 0);
+	smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
+
+	retval = request_irq(dev->irq, smsc911x_irqhandler, IRQF_DISABLED,
+			     SMSC_CHIPNAME, dev);
+	if (retval) {
+		SMSC_WARNING(PROBE,
+			"Unable to claim requested irq: %d", dev->irq);
+		goto out_unmap_io_3;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	retval = register_netdev(dev);
+	if (retval) {
+		SMSC_WARNING(PROBE,
+			"Error %i registering device", retval);
+		goto out_unset_drvdata_4;
+	} else {
+		SMSC_TRACE(PROBE, "Network interface: \"%s\"", dev->name);
+	}
+
+	spin_lock_init(&pdata->mac_lock);
+
+	retval = smsc911x_mii_init(pdev, dev);
+	if (retval) {
+		SMSC_WARNING(PROBE,
+			"Error %i initialising mii", retval);
+		goto out_unregister_netdev_5;
+	}
+
+	spin_lock_irq(&pdata->mac_lock);
+
+	/* Check if mac address has been specified when bringing interface up */
+	if (is_valid_ether_addr(dev->dev_addr)) {
+		smsc911x_set_mac_address(pdata, dev->dev_addr);
+		SMSC_TRACE(PROBE, "MAC Address is specified by configuration");
+	} else {
+		/* Try reading mac address from device. if EEPROM is present
+		 * it will already have been set */
+		u32 mac_high16 = smsc911x_mac_read(pdata, ADDRH);
+		u32 mac_low32 = smsc911x_mac_read(pdata, ADDRL);
+		dev->dev_addr[0] = (u8)(mac_low32);
+		dev->dev_addr[1] = (u8)(mac_low32 >> 8);
+		dev->dev_addr[2] = (u8)(mac_low32 >> 16);
+		dev->dev_addr[3] = (u8)(mac_low32 >> 24);
+		dev->dev_addr[4] = (u8)(mac_high16);
+		dev->dev_addr[5] = (u8)(mac_high16 >> 8);
+
+		if (is_valid_ether_addr(dev->dev_addr)) {
+			/* eeprom values are valid  so use them */
+			SMSC_TRACE(PROBE,
+				"Mac Address is read from LAN911x EEPROM");
+		} else {
+			/* eeprom values are invalid, generate random MAC */
+			random_ether_addr(dev->dev_addr);
+			smsc911x_set_mac_address(pdata, dev->dev_addr);
+			SMSC_TRACE(PROBE,
+				"MAC Address is set to random_ether_addr");
+		}
+	}
+
+	spin_unlock_irq(&pdata->mac_lock);
+
+	dev_info(&dev->dev, "MAC Address: %s\n",
+		 print_mac(mac, dev->dev_addr));
+
+	return 0;
+
+out_unregister_netdev_5:
+	unregister_netdev(dev);
+out_unset_drvdata_4:
+	platform_set_drvdata(pdev, NULL);
+	free_irq(dev->irq, dev);
+out_unmap_io_3:
+	iounmap(pdata->ioaddr);
+out_free_netdev_2:
+	free_netdev(dev);
+out_release_io_1:
+	release_mem_region(res->start, res->end - res->start);
+out_0:
+	return retval;
+}
+
+static struct platform_driver smsc911x_driver = {
+	.probe = smsc911x_drv_probe,
+	.remove = smsc911x_drv_remove,
+	.driver = {
+		.name = SMSC_CHIPNAME,
+	},
+};
+
+/* Entry point for loading the module */
+static int __init smsc911x_init_module(void)
+{
+	return platform_driver_register(&smsc911x_driver);
+}
+
+/* entry point for unloading the module */
+static void __exit smsc911x_cleanup_module(void)
+{
+	platform_driver_unregister(&smsc911x_driver);
+}
+
+module_init(smsc911x_init_module);
+module_exit(smsc911x_cleanup_module);
diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h
new file mode 100644
index 0000000..2b76654
--- /dev/null
+++ b/drivers/net/smsc911x.h
@@ -0,0 +1,390 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2004-2008 SMSC
+ * Copyright (C) 2005-2008 ARM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 __SMSC911X_H__
+#define __SMSC911X_H__
+
+#define TX_FIFO_LOW_THRESHOLD	((u32)1600)
+#define SMSC911X_EEPROM_SIZE	((u32)7)
+#define USE_DEBUG		0
+
+/* This is the maximum number of packets to be received every
+ * NAPI poll */
+#define SMSC_NAPI_WEIGHT	16
+
+/* implements a PHY loopback test at initialisation time, to ensure a packet
+ * can be succesfully looped back */
+#define USE_PHY_WORK_AROUND
+
+#define DPRINTK(nlevel, klevel, fmt, args...) \
+	((void)((NETIF_MSG_##nlevel & pdata->msg_enable) && \
+	printk(KERN_##klevel "%s: %s: " fmt "\n", \
+	pdata->dev->name, __func__, ## args)))
+
+#if USE_DEBUG >= 1
+#define SMSC_WARNING(nlevel, fmt, args...) \
+	DPRINTK(nlevel, WARNING, fmt, ## args)
+#else
+#define SMSC_WARNING(nlevel, fmt, args...) \
+	({ do {} while (0); 0; })
+#endif
+
+#if USE_DEBUG >= 2
+#define SMSC_TRACE(nlevel, fmt, args...) \
+	DPRINTK(nlevel, INFO, fmt, ## args)
+#else
+#define SMSC_TRACE(nlevel, fmt, args...) \
+	({ do {} while (0); 0; })
+#endif
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+#define SMSC_ASSERT_MAC_LOCK(pdata) \
+		WARN_ON(!spin_is_locked(&pdata->mac_lock))
+#else
+#define SMSC_ASSERT_MAC_LOCK(pdata) do {} while (0)
+#endif				/* CONFIG_DEBUG_SPINLOCK */
+
+/* SMSC911x registers and bitfields */
+#define RX_DATA_FIFO			0x00
+
+#define TX_DATA_FIFO			0x20
+#define TX_CMD_A_ON_COMP_		0x80000000
+#define TX_CMD_A_BUF_END_ALGN_		0x03000000
+#define TX_CMD_A_4_BYTE_ALGN_		0x00000000
+#define TX_CMD_A_16_BYTE_ALGN_		0x01000000
+#define TX_CMD_A_32_BYTE_ALGN_		0x02000000
+#define TX_CMD_A_DATA_OFFSET_		0x001F0000
+#define TX_CMD_A_FIRST_SEG_		0x00002000
+#define TX_CMD_A_LAST_SEG_		0x00001000
+#define TX_CMD_A_BUF_SIZE_		0x000007FF
+#define TX_CMD_B_PKT_TAG_		0xFFFF0000
+#define TX_CMD_B_ADD_CRC_DISABLE_	0x00002000
+#define TX_CMD_B_DISABLE_PADDING_	0x00001000
+#define TX_CMD_B_PKT_BYTE_LENGTH_	0x000007FF
+
+#define RX_STATUS_FIFO			0x40
+#define RX_STS_ES_			0x00008000
+#define RX_STS_MCAST_			0x00000400
+
+#define RX_STATUS_FIFO_PEEK		0x44
+
+#define TX_STATUS_FIFO			0x48
+#define TX_STS_ES_			0x00008000
+
+#define TX_STATUS_FIFO_PEEK		0x4C
+
+#define ID_REV				0x50
+#define ID_REV_CHIP_ID_			0xFFFF0000
+#define ID_REV_REV_ID_			0x0000FFFF
+
+#define INT_CFG				0x54
+#define INT_CFG_INT_DEAS_		0xFF000000
+#define INT_CFG_INT_DEAS_CLR_		0x00004000
+#define INT_CFG_INT_DEAS_STS_		0x00002000
+#define INT_CFG_IRQ_INT_		0x00001000
+#define INT_CFG_IRQ_EN_			0x00000100
+#define INT_CFG_IRQ_POL_		0x00000010
+#define INT_CFG_IRQ_TYPE_		0x00000001
+
+#define INT_STS				0x58
+#define INT_STS_SW_INT_			0x80000000
+#define INT_STS_TXSTOP_INT_		0x02000000
+#define INT_STS_RXSTOP_INT_		0x01000000
+#define INT_STS_RXDFH_INT_		0x00800000
+#define INT_STS_RXDF_INT_		0x00400000
+#define INT_STS_TX_IOC_			0x00200000
+#define INT_STS_RXD_INT_		0x00100000
+#define INT_STS_GPT_INT_		0x00080000
+#define INT_STS_PHY_INT_		0x00040000
+#define INT_STS_PME_INT_		0x00020000
+#define INT_STS_TXSO_			0x00010000
+#define INT_STS_RWT_			0x00008000
+#define INT_STS_RXE_			0x00004000
+#define INT_STS_TXE_			0x00002000
+#define INT_STS_TDFU_			0x00000800
+#define INT_STS_TDFO_			0x00000400
+#define INT_STS_TDFA_			0x00000200
+#define INT_STS_TSFF_			0x00000100
+#define INT_STS_TSFL_			0x00000080
+#define INT_STS_RXDF_			0x00000040
+#define INT_STS_RDFL_			0x00000020
+#define INT_STS_RSFF_			0x00000010
+#define INT_STS_RSFL_			0x00000008
+#define INT_STS_GPIO2_INT_		0x00000004
+#define INT_STS_GPIO1_INT_		0x00000002
+#define INT_STS_GPIO0_INT_		0x00000001
+
+#define INT_EN				0x5C
+#define INT_EN_SW_INT_EN_		0x80000000
+#define INT_EN_TXSTOP_INT_EN_		0x02000000
+#define INT_EN_RXSTOP_INT_EN_		0x01000000
+#define INT_EN_RXDFH_INT_EN_		0x00800000
+#define INT_EN_TIOC_INT_EN_		0x00200000
+#define INT_EN_RXD_INT_EN_		0x00100000
+#define INT_EN_GPT_INT_EN_		0x00080000
+#define INT_EN_PHY_INT_EN_		0x00040000
+#define INT_EN_PME_INT_EN_		0x00020000
+#define INT_EN_TXSO_EN_			0x00010000
+#define INT_EN_RWT_EN_			0x00008000
+#define INT_EN_RXE_EN_			0x00004000
+#define INT_EN_TXE_EN_			0x00002000
+#define INT_EN_TDFU_EN_			0x00000800
+#define INT_EN_TDFO_EN_			0x00000400
+#define INT_EN_TDFA_EN_			0x00000200
+#define INT_EN_TSFF_EN_			0x00000100
+#define INT_EN_TSFL_EN_			0x00000080
+#define INT_EN_RXDF_EN_			0x00000040
+#define INT_EN_RDFL_EN_			0x00000020
+#define INT_EN_RSFF_EN_			0x00000010
+#define INT_EN_RSFL_EN_			0x00000008
+#define INT_EN_GPIO2_INT_		0x00000004
+#define INT_EN_GPIO1_INT_		0x00000002
+#define INT_EN_GPIO0_INT_		0x00000001
+
+#define BYTE_TEST			0x64
+
+#define FIFO_INT			0x68
+#define FIFO_INT_TX_AVAIL_LEVEL_	0xFF000000
+#define FIFO_INT_TX_STS_LEVEL_		0x00FF0000
+#define FIFO_INT_RX_AVAIL_LEVEL_	0x0000FF00
+#define FIFO_INT_RX_STS_LEVEL_		0x000000FF
+
+#define RX_CFG				0x6C
+#define RX_CFG_RX_END_ALGN_		0xC0000000
+#define RX_CFG_RX_END_ALGN4_		0x00000000
+#define RX_CFG_RX_END_ALGN16_		0x40000000
+#define RX_CFG_RX_END_ALGN32_		0x80000000
+#define RX_CFG_RX_DMA_CNT_		0x0FFF0000
+#define RX_CFG_RX_DUMP_			0x00008000
+#define RX_CFG_RXDOFF_			0x00001F00
+
+#define TX_CFG				0x70
+#define TX_CFG_TXS_DUMP_		0x00008000
+#define TX_CFG_TXD_DUMP_		0x00004000
+#define TX_CFG_TXSAO_			0x00000004
+#define TX_CFG_TX_ON_			0x00000002
+#define TX_CFG_STOP_TX_			0x00000001
+
+#define HW_CFG				0x74
+#define HW_CFG_TTM_			0x00200000
+#define HW_CFG_SF_			0x00100000
+#define HW_CFG_TX_FIF_SZ_		0x000F0000
+#define HW_CFG_TR_			0x00003000
+#define HW_CFG_SRST_			0x00000001
+
+/* only available on 115/117 */
+#define HW_CFG_PHY_CLK_SEL_		0x00000060
+#define HW_CFG_PHY_CLK_SEL_INT_PHY_	0x00000000
+#define HW_CFG_PHY_CLK_SEL_EXT_PHY_	0x00000020
+#define HW_CFG_PHY_CLK_SEL_CLK_DIS_	0x00000040
+#define HW_CFG_SMI_SEL_		 	0x00000010
+#define HW_CFG_EXT_PHY_DET_		0x00000008
+#define HW_CFG_EXT_PHY_EN_		0x00000004
+#define HW_CFG_SRST_TO_			0x00000002
+
+/* only available  on 116/118 */
+#define HW_CFG_32_16_BIT_MODE_		0x00000004
+
+#define RX_DP_CTRL			0x78
+#define RX_DP_CTRL_RX_FFWD_		0x80000000
+
+#define RX_FIFO_INF			0x7C
+#define RX_FIFO_INF_RXSUSED_		0x00FF0000
+#define RX_FIFO_INF_RXDUSED_		0x0000FFFF
+
+#define TX_FIFO_INF			0x80
+#define TX_FIFO_INF_TSUSED_		0x00FF0000
+#define TX_FIFO_INF_TDFREE_		0x0000FFFF
+
+#define PMT_CTRL			0x84
+#define PMT_CTRL_PM_MODE_		0x00003000
+#define PMT_CTRL_PM_MODE_D0_		0x00000000
+#define PMT_CTRL_PM_MODE_D1_		0x00001000
+#define PMT_CTRL_PM_MODE_D2_		0x00002000
+#define PMT_CTRL_PM_MODE_D3_		0x00003000
+#define PMT_CTRL_PHY_RST_		0x00000400
+#define PMT_CTRL_WOL_EN_		0x00000200
+#define PMT_CTRL_ED_EN_			0x00000100
+#define PMT_CTRL_PME_TYPE_		0x00000040
+#define PMT_CTRL_WUPS_			0x00000030
+#define PMT_CTRL_WUPS_NOWAKE_		0x00000000
+#define PMT_CTRL_WUPS_ED_		0x00000010
+#define PMT_CTRL_WUPS_WOL_		0x00000020
+#define PMT_CTRL_WUPS_MULTI_		0x00000030
+#define PMT_CTRL_PME_IND_		0x00000008
+#define PMT_CTRL_PME_POL_		0x00000004
+#define PMT_CTRL_PME_EN_		0x00000002
+#define PMT_CTRL_READY_			0x00000001
+
+#define GPIO_CFG			0x88
+#define GPIO_CFG_LED3_EN_		0x40000000
+#define GPIO_CFG_LED2_EN_		0x20000000
+#define GPIO_CFG_LED1_EN_		0x10000000
+#define GPIO_CFG_GPIO2_INT_POL_		0x04000000
+#define GPIO_CFG_GPIO1_INT_POL_		0x02000000
+#define GPIO_CFG_GPIO0_INT_POL_		0x01000000
+#define GPIO_CFG_EEPR_EN_		0x00700000
+#define GPIO_CFG_GPIOBUF2_		0x00040000
+#define GPIO_CFG_GPIOBUF1_		0x00020000
+#define GPIO_CFG_GPIOBUF0_		0x00010000
+#define GPIO_CFG_GPIODIR2_		0x00000400
+#define GPIO_CFG_GPIODIR1_		0x00000200
+#define GPIO_CFG_GPIODIR0_		0x00000100
+#define GPIO_CFG_GPIOD4_		0x00000020
+#define GPIO_CFG_GPIOD3_		0x00000010
+#define GPIO_CFG_GPIOD2_		0x00000004
+#define GPIO_CFG_GPIOD1_		0x00000002
+#define GPIO_CFG_GPIOD0_		0x00000001
+
+#define GPT_CFG				0x8C
+#define GPT_CFG_TIMER_EN_		0x20000000
+#define GPT_CFG_GPT_LOAD_		0x0000FFFF
+
+#define GPT_CNT				0x90
+#define GPT_CNT_GPT_CNT_		0x0000FFFF
+
+#define WORD_SWAP			0x98
+
+#define FREE_RUN			0x9C
+
+#define RX_DROP				0xA0
+
+#define MAC_CSR_CMD			0xA4
+#define MAC_CSR_CMD_CSR_BUSY_		0x80000000
+#define MAC_CSR_CMD_R_NOT_W_		0x40000000
+#define MAC_CSR_CMD_CSR_ADDR_		0x000000FF
+
+#define MAC_CSR_DATA			0xA8
+
+#define AFC_CFG				0xAC
+#define AFC_CFG_AFC_HI_			0x00FF0000
+#define AFC_CFG_AFC_LO_			0x0000FF00
+#define AFC_CFG_BACK_DUR_		0x000000F0
+#define AFC_CFG_FCMULT_			0x00000008
+#define AFC_CFG_FCBRD_			0x00000004
+#define AFC_CFG_FCADD_			0x00000002
+#define AFC_CFG_FCANY_			0x00000001
+
+#define E2P_CMD				0xB0
+#define E2P_CMD_EPC_BUSY_		0x80000000
+#define E2P_CMD_EPC_CMD_		0x70000000
+#define E2P_CMD_EPC_CMD_READ_		0x00000000
+#define E2P_CMD_EPC_CMD_EWDS_		0x10000000
+#define E2P_CMD_EPC_CMD_EWEN_		0x20000000
+#define E2P_CMD_EPC_CMD_WRITE_		0x30000000
+#define E2P_CMD_EPC_CMD_WRAL_		0x40000000
+#define E2P_CMD_EPC_CMD_ERASE_		0x50000000
+#define E2P_CMD_EPC_CMD_ERAL_		0x60000000
+#define E2P_CMD_EPC_CMD_RELOAD_		0x70000000
+#define E2P_CMD_EPC_TIMEOUT_		0x00000200
+#define E2P_CMD_MAC_ADDR_LOADED_	0x00000100
+#define E2P_CMD_EPC_ADDR_		0x000000FF
+
+#define E2P_DATA			0xB4
+#define E2P_DATA_EEPROM_DATA_		0x000000FF
+#define LAN_REGISTER_EXTENT		0x00000100
+
+/*
+ * MAC Control and Status Register (Indirect Address)
+ * Offset (through the MAC_CSR CMD and DATA port)
+ */
+#define MAC_CR				0x01
+#define MAC_CR_RXALL_			0x80000000
+#define MAC_CR_HBDIS_			0x10000000
+#define MAC_CR_RCVOWN_			0x00800000
+#define MAC_CR_LOOPBK_			0x00200000
+#define MAC_CR_FDPX_			0x00100000
+#define MAC_CR_MCPAS_			0x00080000
+#define MAC_CR_PRMS_			0x00040000
+#define MAC_CR_INVFILT_			0x00020000
+#define MAC_CR_PASSBAD_			0x00010000
+#define MAC_CR_HFILT_			0x00008000
+#define MAC_CR_HPFILT_			0x00002000
+#define MAC_CR_LCOLL_			0x00001000
+#define MAC_CR_BCAST_			0x00000800
+#define MAC_CR_DISRTY_			0x00000400
+#define MAC_CR_PADSTR_			0x00000100
+#define MAC_CR_BOLMT_MASK_		0x000000C0
+#define MAC_CR_DFCHK_			0x00000020
+#define MAC_CR_TXEN_			0x00000008
+#define MAC_CR_RXEN_			0x00000004
+
+#define ADDRH				0x02
+
+#define ADDRL				0x03
+
+#define HASHH				0x04
+
+#define HASHL				0x05
+
+#define MII_ACC				0x06
+#define MII_ACC_PHY_ADDR_		0x0000F800
+#define MII_ACC_MIIRINDA_		0x000007C0
+#define MII_ACC_MII_WRITE_		0x00000002
+#define MII_ACC_MII_BUSY_		0x00000001
+
+#define MII_DATA			0x07
+
+#define FLOW				0x08
+#define FLOW_FCPT_			0xFFFF0000
+#define FLOW_FCPASS_			0x00000004
+#define FLOW_FCEN_			0x00000002
+#define FLOW_FCBSY_			0x00000001
+
+#define VLAN1				0x09
+
+#define VLAN2				0x0A
+
+#define WUFF				0x0B
+
+#define WUCSR				0x0C
+#define WUCSR_GUE_			0x00000200
+#define WUCSR_WUFR_			0x00000040
+#define WUCSR_MPR_			0x00000020
+#define WUCSR_WAKE_EN_			0x00000004
+#define WUCSR_MPEN_			0x00000002
+
+/*
+ * Phy definitions (vendor-specific)
+ */
+#define LAN9118_PHY_ID			0x00C0001C
+
+#define MII_INTSTS			0x1D
+
+#define MII_INTMSK			0x1E
+#define PHY_INTMSK_AN_RCV_		(1 << 1)
+#define PHY_INTMSK_PDFAULT_		(1 << 2)
+#define PHY_INTMSK_AN_ACK_		(1 << 3)
+#define PHY_INTMSK_LNKDOWN_		(1 << 4)
+#define PHY_INTMSK_RFAULT_		(1 << 5)
+#define PHY_INTMSK_AN_COMP_		(1 << 6)
+#define PHY_INTMSK_ENERGYON_		(1 << 7)
+#define PHY_INTMSK_DEFAULT_		(PHY_INTMSK_ENERGYON_ | \
+					 PHY_INTMSK_AN_COMP_ | \
+					 PHY_INTMSK_RFAULT_ | \
+					 PHY_INTMSK_LNKDOWN_)
+
+#define ADVERTISE_PAUSE_ALL		(ADVERTISE_PAUSE_CAP | \
+					 ADVERTISE_PAUSE_ASYM)
+
+#define LPA_PAUSE_ALL			(LPA_PAUSE_CAP | \
+					 LPA_PAUSE_ASYM)
+
+#endif				/* __SMSC911X_H__ */
diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c
new file mode 100644
index 0000000..27e017d
--- /dev/null
+++ b/drivers/net/smsc9420.c
@@ -0,0 +1,1744 @@
+ /***************************************************************************
+ *
+ * Copyright (C) 2007,2008  SMSC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/netdevice.h>
+#include <linux/phy.h>
+#include <linux/pci.h>
+#include <linux/if_vlan.h>
+#include <linux/dma-mapping.h>
+#include <linux/crc32.h>
+#include <asm/unaligned.h>
+#include "smsc9420.h"
+
+#define DRV_NAME		"smsc9420"
+#define PFX			DRV_NAME ": "
+#define DRV_MDIONAME		"smsc9420-mdio"
+#define DRV_DESCRIPTION		"SMSC LAN9420 driver"
+#define DRV_VERSION		"1.01"
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+struct smsc9420_dma_desc {
+	u32 status;
+	u32 length;
+	u32 buffer1;
+	u32 buffer2;
+};
+
+struct smsc9420_ring_info {
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+};
+
+struct smsc9420_pdata {
+	void __iomem *base_addr;
+	struct pci_dev *pdev;
+	struct net_device *dev;
+
+	struct smsc9420_dma_desc *rx_ring;
+	struct smsc9420_dma_desc *tx_ring;
+	struct smsc9420_ring_info *tx_buffers;
+	struct smsc9420_ring_info *rx_buffers;
+	dma_addr_t rx_dma_addr;
+	dma_addr_t tx_dma_addr;
+	int tx_ring_head, tx_ring_tail;
+	int rx_ring_head, rx_ring_tail;
+
+	spinlock_t int_lock;
+	spinlock_t phy_lock;
+
+	struct napi_struct napi;
+
+	bool software_irq_signal;
+	bool rx_csum;
+	u32 msg_enable;
+
+	struct phy_device *phy_dev;
+	struct mii_bus *mii_bus;
+	int phy_irq[PHY_MAX_ADDR];
+	int last_duplex;
+	int last_carrier;
+};
+
+static const struct pci_device_id smsc9420_id_table[] = {
+	{ PCI_VENDOR_ID_9420, PCI_DEVICE_ID_9420, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, smsc9420_id_table);
+
+#define SMSC_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
+
+static uint smsc_debug;
+static uint debug = -1;
+module_param(debug, uint, 0);
+MODULE_PARM_DESC(debug, "debug level");
+
+#define smsc_dbg(TYPE, f, a...) \
+do {	if ((pd)->msg_enable & NETIF_MSG_##TYPE) \
+		printk(KERN_DEBUG PFX f "\n", ## a); \
+} while (0)
+
+#define smsc_info(TYPE, f, a...) \
+do {	if ((pd)->msg_enable & NETIF_MSG_##TYPE) \
+		printk(KERN_INFO PFX f "\n", ## a); \
+} while (0)
+
+#define smsc_warn(TYPE, f, a...) \
+do {	if ((pd)->msg_enable & NETIF_MSG_##TYPE) \
+		printk(KERN_WARNING PFX f "\n", ## a); \
+} while (0)
+
+static inline u32 smsc9420_reg_read(struct smsc9420_pdata *pd, u32 offset)
+{
+	return ioread32(pd->base_addr + offset);
+}
+
+static inline void
+smsc9420_reg_write(struct smsc9420_pdata *pd, u32 offset, u32 value)
+{
+	iowrite32(value, pd->base_addr + offset);
+}
+
+static inline void smsc9420_pci_flush_write(struct smsc9420_pdata *pd)
+{
+	/* to ensure PCI write completion, we must perform a PCI read */
+	smsc9420_reg_read(pd, ID_REV);
+}
+
+static int smsc9420_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
+{
+	struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv;
+	unsigned long flags;
+	u32 addr;
+	int i, reg = -EIO;
+
+	spin_lock_irqsave(&pd->phy_lock, flags);
+
+	/*  confirm MII not busy */
+	if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) {
+		smsc_warn(DRV, "MII is busy???");
+		goto out;
+	}
+
+	/* set the address, index & direction (read from PHY) */
+	addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) |
+		MII_ACCESS_MII_READ_;
+	smsc9420_reg_write(pd, MII_ACCESS, addr);
+
+	/* wait for read to complete with 50us timeout */
+	for (i = 0; i < 5; i++) {
+		if (!(smsc9420_reg_read(pd, MII_ACCESS) &
+			MII_ACCESS_MII_BUSY_)) {
+			reg = (u16)smsc9420_reg_read(pd, MII_DATA);
+			goto out;
+		}
+		udelay(10);
+	}
+
+	smsc_warn(DRV, "MII busy timeout!");
+
+out:
+	spin_unlock_irqrestore(&pd->phy_lock, flags);
+	return reg;
+}
+
+static int smsc9420_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
+			   u16 val)
+{
+	struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv;
+	unsigned long flags;
+	u32 addr;
+	int i, reg = -EIO;
+
+	spin_lock_irqsave(&pd->phy_lock, flags);
+
+	/* confirm MII not busy */
+	if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) {
+		smsc_warn(DRV, "MII is busy???");
+		goto out;
+	}
+
+	/* put the data to write in the MAC */
+	smsc9420_reg_write(pd, MII_DATA, (u32)val);
+
+	/* set the address, index & direction (write to PHY) */
+	addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) |
+		MII_ACCESS_MII_WRITE_;
+	smsc9420_reg_write(pd, MII_ACCESS, addr);
+
+	/* wait for write to complete with 50us timeout */
+	for (i = 0; i < 5; i++) {
+		if (!(smsc9420_reg_read(pd, MII_ACCESS) &
+			MII_ACCESS_MII_BUSY_)) {
+			reg = 0;
+			goto out;
+		}
+		udelay(10);
+	}
+
+	smsc_warn(DRV, "MII busy timeout!");
+
+out:
+	spin_unlock_irqrestore(&pd->phy_lock, flags);
+	return reg;
+}
+
+/* Returns hash bit number for given MAC address
+ * Example:
+ * 01 00 5E 00 00 01 -> returns bit number 31 */
+static u32 smsc9420_hash(u8 addr[ETH_ALEN])
+{
+	return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
+}
+
+static int smsc9420_eeprom_reload(struct smsc9420_pdata *pd)
+{
+	int timeout = 100000;
+
+	BUG_ON(!pd);
+
+	if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
+		smsc_dbg(DRV, "smsc9420_eeprom_reload: Eeprom busy");
+		return -EIO;
+	}
+
+	smsc9420_reg_write(pd, E2P_CMD,
+		(E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_RELOAD_));
+
+	do {
+		udelay(10);
+		if (!(smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_))
+			return 0;
+	} while (timeout--);
+
+	smsc_warn(DRV, "smsc9420_eeprom_reload: Eeprom timed out");
+	return -EIO;
+}
+
+/* Standard ioctls for mii-tool */
+static int smsc9420_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+
+	if (!netif_running(dev) || !pd->phy_dev)
+		return -EINVAL;
+
+	return phy_mii_ioctl(pd->phy_dev, if_mii(ifr), cmd);
+}
+
+static int smsc9420_ethtool_get_settings(struct net_device *dev,
+					 struct ethtool_cmd *cmd)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+
+	cmd->maxtxpkt = 1;
+	cmd->maxrxpkt = 1;
+	return phy_ethtool_gset(pd->phy_dev, cmd);
+}
+
+static int smsc9420_ethtool_set_settings(struct net_device *dev,
+					 struct ethtool_cmd *cmd)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+
+	return phy_ethtool_sset(pd->phy_dev, cmd);
+}
+
+static void smsc9420_ethtool_get_drvinfo(struct net_device *netdev,
+					 struct ethtool_drvinfo *drvinfo)
+{
+	struct smsc9420_pdata *pd = netdev_priv(netdev);
+
+	strcpy(drvinfo->driver, DRV_NAME);
+	strcpy(drvinfo->bus_info, pci_name(pd->pdev));
+	strcpy(drvinfo->version, DRV_VERSION);
+}
+
+static u32 smsc9420_ethtool_get_msglevel(struct net_device *netdev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(netdev);
+	return pd->msg_enable;
+}
+
+static void smsc9420_ethtool_set_msglevel(struct net_device *netdev, u32 data)
+{
+	struct smsc9420_pdata *pd = netdev_priv(netdev);
+	pd->msg_enable = data;
+}
+
+static int smsc9420_ethtool_nway_reset(struct net_device *netdev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(netdev);
+	return phy_start_aneg(pd->phy_dev);
+}
+
+static int smsc9420_ethtool_getregslen(struct net_device *dev)
+{
+	/* all smsc9420 registers plus all phy registers */
+	return 0x100 + (32 * sizeof(u32));
+}
+
+static void
+smsc9420_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs,
+			 void *buf)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	struct phy_device *phy_dev = pd->phy_dev;
+	unsigned int i, j = 0;
+	u32 *data = buf;
+
+	regs->version = smsc9420_reg_read(pd, ID_REV);
+	for (i = 0; i < 0x100; i += (sizeof(u32)))
+		data[j++] = smsc9420_reg_read(pd, i);
+
+	for (i = 0; i <= 31; i++)
+		data[j++] = smsc9420_mii_read(phy_dev->bus, phy_dev->addr, i);
+}
+
+static void smsc9420_eeprom_enable_access(struct smsc9420_pdata *pd)
+{
+	unsigned int temp = smsc9420_reg_read(pd, GPIO_CFG);
+	temp &= ~GPIO_CFG_EEPR_EN_;
+	smsc9420_reg_write(pd, GPIO_CFG, temp);
+	msleep(1);
+}
+
+static int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op)
+{
+	int timeout = 100;
+	u32 e2cmd;
+
+	smsc_dbg(HW, "op 0x%08x", op);
+	if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
+		smsc_warn(HW, "Busy at start");
+		return -EBUSY;
+	}
+
+	e2cmd = op | E2P_CMD_EPC_BUSY_;
+	smsc9420_reg_write(pd, E2P_CMD, e2cmd);
+
+	do {
+		msleep(1);
+		e2cmd = smsc9420_reg_read(pd, E2P_CMD);
+	} while ((e2cmd & E2P_CMD_EPC_BUSY_) && (timeout--));
+
+	if (!timeout) {
+		smsc_info(HW, "TIMED OUT");
+		return -EAGAIN;
+	}
+
+	if (e2cmd & E2P_CMD_EPC_TIMEOUT_) {
+		smsc_info(HW, "Error occured during eeprom operation");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int smsc9420_eeprom_read_location(struct smsc9420_pdata *pd,
+					 u8 address, u8 *data)
+{
+	u32 op = E2P_CMD_EPC_CMD_READ_ | address;
+	int ret;
+
+	smsc_dbg(HW, "address 0x%x", address);
+	ret = smsc9420_eeprom_send_cmd(pd, op);
+
+	if (!ret)
+		data[address] = smsc9420_reg_read(pd, E2P_DATA);
+
+	return ret;
+}
+
+static int smsc9420_eeprom_write_location(struct smsc9420_pdata *pd,
+					  u8 address, u8 data)
+{
+	u32 op = E2P_CMD_EPC_CMD_ERASE_ | address;
+	int ret;
+
+	smsc_dbg(HW, "address 0x%x, data 0x%x", address, data);
+	ret = smsc9420_eeprom_send_cmd(pd, op);
+
+	if (!ret) {
+		op = E2P_CMD_EPC_CMD_WRITE_ | address;
+		smsc9420_reg_write(pd, E2P_DATA, (u32)data);
+		ret = smsc9420_eeprom_send_cmd(pd, op);
+	}
+
+	return ret;
+}
+
+static int smsc9420_ethtool_get_eeprom_len(struct net_device *dev)
+{
+	return SMSC9420_EEPROM_SIZE;
+}
+
+static int smsc9420_ethtool_get_eeprom(struct net_device *dev,
+				       struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	u8 eeprom_data[SMSC9420_EEPROM_SIZE];
+	int len, i;
+
+	smsc9420_eeprom_enable_access(pd);
+
+	len = min(eeprom->len, SMSC9420_EEPROM_SIZE);
+	for (i = 0; i < len; i++) {
+		int ret = smsc9420_eeprom_read_location(pd, i, eeprom_data);
+		if (ret < 0) {
+			eeprom->len = 0;
+			return ret;
+		}
+	}
+
+	memcpy(data, &eeprom_data[eeprom->offset], len);
+	eeprom->len = len;
+	return 0;
+}
+
+static int smsc9420_ethtool_set_eeprom(struct net_device *dev,
+				       struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	int ret;
+
+	smsc9420_eeprom_enable_access(pd);
+	smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWEN_);
+	ret = smsc9420_eeprom_write_location(pd, eeprom->offset, *data);
+	smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWDS_);
+
+	/* Single byte write, according to man page */
+	eeprom->len = 1;
+
+	return ret;
+}
+
+static const struct ethtool_ops smsc9420_ethtool_ops = {
+	.get_settings = smsc9420_ethtool_get_settings,
+	.set_settings = smsc9420_ethtool_set_settings,
+	.get_drvinfo = smsc9420_ethtool_get_drvinfo,
+	.get_msglevel = smsc9420_ethtool_get_msglevel,
+	.set_msglevel = smsc9420_ethtool_set_msglevel,
+	.nway_reset = smsc9420_ethtool_nway_reset,
+	.get_link = ethtool_op_get_link,
+	.get_eeprom_len = smsc9420_ethtool_get_eeprom_len,
+	.get_eeprom = smsc9420_ethtool_get_eeprom,
+	.set_eeprom = smsc9420_ethtool_set_eeprom,
+	.get_regs_len = smsc9420_ethtool_getregslen,
+	.get_regs = smsc9420_ethtool_getregs,
+};
+
+/* Sets the device MAC address to dev_addr */
+static void smsc9420_set_mac_address(struct net_device *dev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	u8 *dev_addr = dev->dev_addr;
+	u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4];
+	u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
+	    (dev_addr[1] << 8) | dev_addr[0];
+
+	smsc9420_reg_write(pd, ADDRH, mac_high16);
+	smsc9420_reg_write(pd, ADDRL, mac_low32);
+}
+
+static void smsc9420_check_mac_address(struct net_device *dev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+
+	/* Check if mac address has been specified when bringing interface up */
+	if (is_valid_ether_addr(dev->dev_addr)) {
+		smsc9420_set_mac_address(dev);
+		smsc_dbg(PROBE, "MAC Address is specified by configuration");
+	} else {
+		/* Try reading mac address from device. if EEPROM is present
+		 * it will already have been set */
+		u32 mac_high16 = smsc9420_reg_read(pd, ADDRH);
+		u32 mac_low32 = smsc9420_reg_read(pd, ADDRL);
+		dev->dev_addr[0] = (u8)(mac_low32);
+		dev->dev_addr[1] = (u8)(mac_low32 >> 8);
+		dev->dev_addr[2] = (u8)(mac_low32 >> 16);
+		dev->dev_addr[3] = (u8)(mac_low32 >> 24);
+		dev->dev_addr[4] = (u8)(mac_high16);
+		dev->dev_addr[5] = (u8)(mac_high16 >> 8);
+
+		if (is_valid_ether_addr(dev->dev_addr)) {
+			/* eeprom values are valid  so use them */
+			smsc_dbg(PROBE, "Mac Address is read from EEPROM");
+		} else {
+			/* eeprom values are invalid, generate random MAC */
+			random_ether_addr(dev->dev_addr);
+			smsc9420_set_mac_address(dev);
+			smsc_dbg(PROBE,
+				"MAC Address is set to random_ether_addr");
+		}
+	}
+}
+
+static void smsc9420_stop_tx(struct smsc9420_pdata *pd)
+{
+	u32 dmac_control, mac_cr, dma_intr_ena;
+	int timeOut = 1000;
+
+	/* disable TX DMAC */
+	dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL);
+	dmac_control &= (~DMAC_CONTROL_ST_);
+	smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control);
+
+	/* Wait max 10ms for transmit process to stop */
+	while (timeOut--) {
+		if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_TS_)
+			break;
+		udelay(10);
+	}
+
+	if (!timeOut)
+		smsc_warn(IFDOWN, "TX DMAC failed to stop");
+
+	/* ACK Tx DMAC stop bit */
+	smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_TXPS_);
+
+	/* mask TX DMAC interrupts */
+	dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
+	dma_intr_ena &= ~(DMAC_INTR_ENA_TX_);
+	smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
+	smsc9420_pci_flush_write(pd);
+
+	/* stop MAC TX */
+	mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_TXEN_);
+	smsc9420_reg_write(pd, MAC_CR, mac_cr);
+	smsc9420_pci_flush_write(pd);
+}
+
+static void smsc9420_free_tx_ring(struct smsc9420_pdata *pd)
+{
+	int i;
+
+	BUG_ON(!pd->tx_ring);
+
+	if (!pd->tx_buffers)
+		return;
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		struct sk_buff *skb = pd->tx_buffers[i].skb;
+
+		if (skb) {
+			BUG_ON(!pd->tx_buffers[i].mapping);
+			pci_unmap_single(pd->pdev, pd->tx_buffers[i].mapping,
+					 skb->len, PCI_DMA_TODEVICE);
+			dev_kfree_skb_any(skb);
+		}
+
+		pd->tx_ring[i].status = 0;
+		pd->tx_ring[i].length = 0;
+		pd->tx_ring[i].buffer1 = 0;
+		pd->tx_ring[i].buffer2 = 0;
+	}
+	wmb();
+
+	kfree(pd->tx_buffers);
+	pd->tx_buffers = NULL;
+
+	pd->tx_ring_head = 0;
+	pd->tx_ring_tail = 0;
+}
+
+static void smsc9420_free_rx_ring(struct smsc9420_pdata *pd)
+{
+	int i;
+
+	BUG_ON(!pd->rx_ring);
+
+	if (!pd->rx_buffers)
+		return;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		if (pd->rx_buffers[i].skb)
+			dev_kfree_skb_any(pd->rx_buffers[i].skb);
+
+		if (pd->rx_buffers[i].mapping)
+			pci_unmap_single(pd->pdev, pd->rx_buffers[i].mapping,
+				PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+
+		pd->rx_ring[i].status = 0;
+		pd->rx_ring[i].length = 0;
+		pd->rx_ring[i].buffer1 = 0;
+		pd->rx_ring[i].buffer2 = 0;
+	}
+	wmb();
+
+	kfree(pd->rx_buffers);
+	pd->rx_buffers = NULL;
+
+	pd->rx_ring_head = 0;
+	pd->rx_ring_tail = 0;
+}
+
+static void smsc9420_stop_rx(struct smsc9420_pdata *pd)
+{
+	int timeOut = 1000;
+	u32 mac_cr, dmac_control, dma_intr_ena;
+
+	/* mask RX DMAC interrupts */
+	dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
+	dma_intr_ena &= (~DMAC_INTR_ENA_RX_);
+	smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
+	smsc9420_pci_flush_write(pd);
+
+	/* stop RX MAC prior to stoping DMA */
+	mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_RXEN_);
+	smsc9420_reg_write(pd, MAC_CR, mac_cr);
+	smsc9420_pci_flush_write(pd);
+
+	/* stop RX DMAC */
+	dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL);
+	dmac_control &= (~DMAC_CONTROL_SR_);
+	smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control);
+	smsc9420_pci_flush_write(pd);
+
+	/* wait up to 10ms for receive to stop */
+	while (timeOut--) {
+		if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_RS_)
+			break;
+		udelay(10);
+	}
+
+	if (!timeOut)
+		smsc_warn(IFDOWN, "RX DMAC did not stop! timeout.");
+
+	/* ACK the Rx DMAC stop bit */
+	smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_RXPS_);
+}
+
+static irqreturn_t smsc9420_isr(int irq, void *dev_id)
+{
+	struct smsc9420_pdata *pd = dev_id;
+	u32 int_cfg, int_sts, int_ctl;
+	irqreturn_t ret = IRQ_NONE;
+	ulong flags;
+
+	BUG_ON(!pd);
+	BUG_ON(!pd->base_addr);
+
+	int_cfg = smsc9420_reg_read(pd, INT_CFG);
+
+	/* check if it's our interrupt */
+	if ((int_cfg & (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) !=
+	    (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_))
+		return IRQ_NONE;
+
+	int_sts = smsc9420_reg_read(pd, INT_STAT);
+
+	if (likely(INT_STAT_DMAC_INT_ & int_sts)) {
+		u32 status = smsc9420_reg_read(pd, DMAC_STATUS);
+		u32 ints_to_clear = 0;
+
+		if (status & DMAC_STS_TX_) {
+			ints_to_clear |= (DMAC_STS_TX_ | DMAC_STS_NIS_);
+			netif_wake_queue(pd->dev);
+		}
+
+		if (status & DMAC_STS_RX_) {
+			/* mask RX DMAC interrupts */
+			u32 dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
+			dma_intr_ena &= (~DMAC_INTR_ENA_RX_);
+			smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
+			smsc9420_pci_flush_write(pd);
+
+			ints_to_clear |= (DMAC_STS_RX_ | DMAC_STS_NIS_);
+			netif_rx_schedule(&pd->napi);
+		}
+
+		if (ints_to_clear)
+			smsc9420_reg_write(pd, DMAC_STATUS, ints_to_clear);
+
+		ret = IRQ_HANDLED;
+	}
+
+	if (unlikely(INT_STAT_SW_INT_ & int_sts)) {
+		/* mask software interrupt */
+		spin_lock_irqsave(&pd->int_lock, flags);
+		int_ctl = smsc9420_reg_read(pd, INT_CTL);
+		int_ctl &= (~INT_CTL_SW_INT_EN_);
+		smsc9420_reg_write(pd, INT_CTL, int_ctl);
+		spin_unlock_irqrestore(&pd->int_lock, flags);
+
+		smsc9420_reg_write(pd, INT_STAT, INT_STAT_SW_INT_);
+		pd->software_irq_signal = true;
+		smp_wmb();
+
+		ret = IRQ_HANDLED;
+	}
+
+	/* to ensure PCI write completion, we must perform a PCI read */
+	smsc9420_pci_flush_write(pd);
+
+	return ret;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void smsc9420_poll_controller(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	smsc9420_isr(0, dev);
+	enable_irq(dev->irq);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+static void smsc9420_dmac_soft_reset(struct smsc9420_pdata *pd)
+{
+	smsc9420_reg_write(pd, BUS_MODE, BUS_MODE_SWR_);
+	smsc9420_reg_read(pd, BUS_MODE);
+	udelay(2);
+	if (smsc9420_reg_read(pd, BUS_MODE) & BUS_MODE_SWR_)
+		smsc_warn(DRV, "Software reset not cleared");
+}
+
+static int smsc9420_stop(struct net_device *dev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	u32 int_cfg;
+	ulong flags;
+
+	BUG_ON(!pd);
+	BUG_ON(!pd->phy_dev);
+
+	/* disable master interrupt */
+	spin_lock_irqsave(&pd->int_lock, flags);
+	int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
+	smsc9420_reg_write(pd, INT_CFG, int_cfg);
+	spin_unlock_irqrestore(&pd->int_lock, flags);
+
+	netif_tx_disable(dev);
+	napi_disable(&pd->napi);
+
+	smsc9420_stop_tx(pd);
+	smsc9420_free_tx_ring(pd);
+
+	smsc9420_stop_rx(pd);
+	smsc9420_free_rx_ring(pd);
+
+	free_irq(dev->irq, pd);
+
+	smsc9420_dmac_soft_reset(pd);
+
+	phy_stop(pd->phy_dev);
+
+	phy_disconnect(pd->phy_dev);
+	pd->phy_dev = NULL;
+	mdiobus_unregister(pd->mii_bus);
+	mdiobus_free(pd->mii_bus);
+
+	return 0;
+}
+
+static void smsc9420_rx_count_stats(struct net_device *dev, u32 desc_status)
+{
+	if (unlikely(desc_status & RDES0_ERROR_SUMMARY_)) {
+		dev->stats.rx_errors++;
+		if (desc_status & RDES0_DESCRIPTOR_ERROR_)
+			dev->stats.rx_over_errors++;
+		else if (desc_status & (RDES0_FRAME_TOO_LONG_ |
+			RDES0_RUNT_FRAME_ | RDES0_COLLISION_SEEN_))
+			dev->stats.rx_frame_errors++;
+		else if (desc_status & RDES0_CRC_ERROR_)
+			dev->stats.rx_crc_errors++;
+	}
+
+	if (unlikely(desc_status & RDES0_LENGTH_ERROR_))
+		dev->stats.rx_length_errors++;
+
+	if (unlikely(!((desc_status & RDES0_LAST_DESCRIPTOR_) &&
+		(desc_status & RDES0_FIRST_DESCRIPTOR_))))
+		dev->stats.rx_length_errors++;
+
+	if (desc_status & RDES0_MULTICAST_FRAME_)
+		dev->stats.multicast++;
+}
+
+static void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index,
+				const u32 status)
+{
+	struct net_device *dev = pd->dev;
+	struct sk_buff *skb;
+	u16 packet_length = (status & RDES0_FRAME_LENGTH_MASK_)
+		>> RDES0_FRAME_LENGTH_SHFT_;
+
+	/* remove crc from packet lendth */
+	packet_length -= 4;
+
+	if (pd->rx_csum)
+		packet_length -= 2;
+
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += packet_length;
+
+	pci_unmap_single(pd->pdev, pd->rx_buffers[index].mapping,
+		PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+	pd->rx_buffers[index].mapping = 0;
+
+	skb = pd->rx_buffers[index].skb;
+	pd->rx_buffers[index].skb = NULL;
+
+	if (pd->rx_csum) {
+		u16 hw_csum = get_unaligned_le16(skb_tail_pointer(skb) +
+			NET_IP_ALIGN + packet_length + 4);
+		put_unaligned_le16(cpu_to_le16(hw_csum), &skb->csum);
+		skb->ip_summed = CHECKSUM_COMPLETE;
+	}
+
+	skb_reserve(skb, NET_IP_ALIGN);
+	skb_put(skb, packet_length);
+
+	skb->protocol = eth_type_trans(skb, dev);
+
+	netif_receive_skb(skb);
+	dev->last_rx = jiffies;
+}
+
+static int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index)
+{
+	struct sk_buff *skb = netdev_alloc_skb(pd->dev, PKT_BUF_SZ);
+	dma_addr_t mapping;
+
+	BUG_ON(pd->rx_buffers[index].skb);
+	BUG_ON(pd->rx_buffers[index].mapping);
+
+	if (unlikely(!skb)) {
+		smsc_warn(RX_ERR, "Failed to allocate new skb!");
+		return -ENOMEM;
+	}
+
+	skb->dev = pd->dev;
+
+	mapping = pci_map_single(pd->pdev, skb_tail_pointer(skb),
+				 PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(pd->pdev, mapping)) {
+		dev_kfree_skb_any(skb);
+		smsc_warn(RX_ERR, "pci_map_single failed!");
+		return -ENOMEM;
+	}
+
+	pd->rx_buffers[index].skb = skb;
+	pd->rx_buffers[index].mapping = mapping;
+	pd->rx_ring[index].buffer1 = mapping + NET_IP_ALIGN;
+	pd->rx_ring[index].status = RDES0_OWN_;
+	wmb();
+
+	return 0;
+}
+
+static void smsc9420_alloc_new_rx_buffers(struct smsc9420_pdata *pd)
+{
+	while (pd->rx_ring_tail != pd->rx_ring_head) {
+		if (smsc9420_alloc_rx_buffer(pd, pd->rx_ring_tail))
+			break;
+
+		pd->rx_ring_tail = (pd->rx_ring_tail + 1) % RX_RING_SIZE;
+	}
+}
+
+static int smsc9420_rx_poll(struct napi_struct *napi, int budget)
+{
+	struct smsc9420_pdata *pd =
+		container_of(napi, struct smsc9420_pdata, napi);
+	struct net_device *dev = pd->dev;
+	u32 drop_frame_cnt, dma_intr_ena, status;
+	int work_done;
+
+	for (work_done = 0; work_done < budget; work_done++) {
+		rmb();
+		status = pd->rx_ring[pd->rx_ring_head].status;
+
+		/* stop if DMAC owns this dma descriptor */
+		if (status & RDES0_OWN_)
+			break;
+
+		smsc9420_rx_count_stats(dev, status);
+		smsc9420_rx_handoff(pd, pd->rx_ring_head, status);
+		pd->rx_ring_head = (pd->rx_ring_head + 1) % RX_RING_SIZE;
+		smsc9420_alloc_new_rx_buffers(pd);
+	}
+
+	drop_frame_cnt = smsc9420_reg_read(pd, MISS_FRAME_CNTR);
+	dev->stats.rx_dropped +=
+	    (drop_frame_cnt & 0xFFFF) + ((drop_frame_cnt >> 17) & 0x3FF);
+
+	/* Kick RXDMA */
+	smsc9420_reg_write(pd, RX_POLL_DEMAND, 1);
+	smsc9420_pci_flush_write(pd);
+
+	if (work_done < budget) {
+		netif_rx_complete(&pd->napi);
+
+		/* re-enable RX DMA interrupts */
+		dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
+		dma_intr_ena |= (DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_);
+		smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
+		smsc9420_pci_flush_write(pd);
+	}
+	return work_done;
+}
+
+static void
+smsc9420_tx_update_stats(struct net_device *dev, u32 status, u32 length)
+{
+	if (unlikely(status & TDES0_ERROR_SUMMARY_)) {
+		dev->stats.tx_errors++;
+		if (status & (TDES0_EXCESSIVE_DEFERRAL_ |
+			TDES0_EXCESSIVE_COLLISIONS_))
+			dev->stats.tx_aborted_errors++;
+
+		if (status & (TDES0_LOSS_OF_CARRIER_ | TDES0_NO_CARRIER_))
+			dev->stats.tx_carrier_errors++;
+	} else {
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += (length & 0x7FF);
+	}
+
+	if (unlikely(status & TDES0_EXCESSIVE_COLLISIONS_)) {
+		dev->stats.collisions += 16;
+	} else {
+		dev->stats.collisions +=
+			(status & TDES0_COLLISION_COUNT_MASK_) >>
+			TDES0_COLLISION_COUNT_SHFT_;
+	}
+
+	if (unlikely(status & TDES0_HEARTBEAT_FAIL_))
+		dev->stats.tx_heartbeat_errors++;
+}
+
+/* Check for completed dma transfers, update stats and free skbs */
+static void smsc9420_complete_tx(struct net_device *dev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+
+	while (pd->tx_ring_tail != pd->tx_ring_head) {
+		int index = pd->tx_ring_tail;
+		u32 status, length;
+
+		rmb();
+		status = pd->tx_ring[index].status;
+		length = pd->tx_ring[index].length;
+
+		/* Check if DMA still owns this descriptor */
+		if (unlikely(TDES0_OWN_ & status))
+			break;
+
+		smsc9420_tx_update_stats(dev, status, length);
+
+		BUG_ON(!pd->tx_buffers[index].skb);
+		BUG_ON(!pd->tx_buffers[index].mapping);
+
+		pci_unmap_single(pd->pdev, pd->tx_buffers[index].mapping,
+			pd->tx_buffers[index].skb->len, PCI_DMA_TODEVICE);
+		pd->tx_buffers[index].mapping = 0;
+
+		dev_kfree_skb_any(pd->tx_buffers[index].skb);
+		pd->tx_buffers[index].skb = NULL;
+
+		pd->tx_ring[index].buffer1 = 0;
+		wmb();
+
+		pd->tx_ring_tail = (pd->tx_ring_tail + 1) % TX_RING_SIZE;
+	}
+}
+
+static int smsc9420_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	dma_addr_t mapping;
+	int index = pd->tx_ring_head;
+	u32 tmp_desc1;
+	bool about_to_take_last_desc =
+		(((pd->tx_ring_head + 2) % TX_RING_SIZE) == pd->tx_ring_tail);
+
+	smsc9420_complete_tx(dev);
+
+	rmb();
+	BUG_ON(pd->tx_ring[index].status & TDES0_OWN_);
+	BUG_ON(pd->tx_buffers[index].skb);
+	BUG_ON(pd->tx_buffers[index].mapping);
+
+	mapping = pci_map_single(pd->pdev, skb->data,
+				 skb->len, PCI_DMA_TODEVICE);
+	if (pci_dma_mapping_error(pd->pdev, mapping)) {
+		smsc_warn(TX_ERR, "pci_map_single failed, dropping packet");
+		return NETDEV_TX_BUSY;
+	}
+
+	pd->tx_buffers[index].skb = skb;
+	pd->tx_buffers[index].mapping = mapping;
+
+	tmp_desc1 = (TDES1_LS_ | ((u32)skb->len & 0x7FF));
+	if (unlikely(about_to_take_last_desc)) {
+		tmp_desc1 |= TDES1_IC_;
+		netif_stop_queue(pd->dev);
+	}
+
+	/* check if we are at the last descriptor and need to set EOR */
+	if (unlikely(index == (TX_RING_SIZE - 1)))
+		tmp_desc1 |= TDES1_TER_;
+
+	pd->tx_ring[index].buffer1 = mapping;
+	pd->tx_ring[index].length = tmp_desc1;
+	wmb();
+
+	/* increment head */
+	pd->tx_ring_head = (pd->tx_ring_head + 1) % TX_RING_SIZE;
+
+	/* assign ownership to DMAC */
+	pd->tx_ring[index].status = TDES0_OWN_;
+	wmb();
+
+	/* kick the DMA */
+	smsc9420_reg_write(pd, TX_POLL_DEMAND, 1);
+	smsc9420_pci_flush_write(pd);
+
+	dev->trans_start = jiffies;
+
+	return NETDEV_TX_OK;
+}
+
+static struct net_device_stats *smsc9420_get_stats(struct net_device *dev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	u32 counter = smsc9420_reg_read(pd, MISS_FRAME_CNTR);
+	dev->stats.rx_dropped +=
+	    (counter & 0x0000FFFF) + ((counter >> 17) & 0x000003FF);
+	return &dev->stats;
+}
+
+static void smsc9420_set_multicast_list(struct net_device *dev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	u32 mac_cr = smsc9420_reg_read(pd, MAC_CR);
+
+	if (dev->flags & IFF_PROMISC) {
+		smsc_dbg(HW, "Promiscuous Mode Enabled");
+		mac_cr |= MAC_CR_PRMS_;
+		mac_cr &= (~MAC_CR_MCPAS_);
+		mac_cr &= (~MAC_CR_HPFILT_);
+	} else if (dev->flags & IFF_ALLMULTI) {
+		smsc_dbg(HW, "Receive all Multicast Enabled");
+		mac_cr &= (~MAC_CR_PRMS_);
+		mac_cr |= MAC_CR_MCPAS_;
+		mac_cr &= (~MAC_CR_HPFILT_);
+	} else if (dev->mc_count > 0) {
+		struct dev_mc_list *mc_list = dev->mc_list;
+		u32 hash_lo = 0, hash_hi = 0;
+
+		smsc_dbg(HW, "Multicast filter enabled");
+		while (mc_list) {
+			u32 bit_num = smsc9420_hash(mc_list->dmi_addr);
+			u32 mask = 1 << (bit_num & 0x1F);
+
+			if (bit_num & 0x20)
+				hash_hi |= mask;
+			else
+				hash_lo |= mask;
+
+			mc_list = mc_list->next;
+		}
+		smsc9420_reg_write(pd, HASHH, hash_hi);
+		smsc9420_reg_write(pd, HASHL, hash_lo);
+
+		mac_cr &= (~MAC_CR_PRMS_);
+		mac_cr &= (~MAC_CR_MCPAS_);
+		mac_cr |= MAC_CR_HPFILT_;
+	} else {
+		smsc_dbg(HW, "Receive own packets only.");
+		smsc9420_reg_write(pd, HASHH, 0);
+		smsc9420_reg_write(pd, HASHL, 0);
+
+		mac_cr &= (~MAC_CR_PRMS_);
+		mac_cr &= (~MAC_CR_MCPAS_);
+		mac_cr &= (~MAC_CR_HPFILT_);
+	}
+
+	smsc9420_reg_write(pd, MAC_CR, mac_cr);
+	smsc9420_pci_flush_write(pd);
+}
+
+static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd)
+{
+	struct phy_device *phy_dev = pd->phy_dev;
+	u32 flow;
+
+	if (phy_dev->duplex == DUPLEX_FULL) {
+		u16 lcladv = phy_read(phy_dev, MII_ADVERTISE);
+		u16 rmtadv = phy_read(phy_dev, MII_LPA);
+		u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+
+		if (cap & FLOW_CTRL_RX)
+			flow = 0xFFFF0002;
+		else
+			flow = 0;
+
+		smsc_info(LINK, "rx pause %s, tx pause %s",
+			(cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
+			(cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
+	} else {
+		smsc_info(LINK, "half duplex");
+		flow = 0;
+	}
+
+	smsc9420_reg_write(pd, FLOW, flow);
+}
+
+/* Update link mode if anything has changed.  Called periodically when the
+ * PHY is in polling mode, even if nothing has changed. */
+static void smsc9420_phy_adjust_link(struct net_device *dev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	struct phy_device *phy_dev = pd->phy_dev;
+	int carrier;
+
+	if (phy_dev->duplex != pd->last_duplex) {
+		u32 mac_cr = smsc9420_reg_read(pd, MAC_CR);
+		if (phy_dev->duplex) {
+			smsc_dbg(LINK, "full duplex mode");
+			mac_cr |= MAC_CR_FDPX_;
+		} else {
+			smsc_dbg(LINK, "half duplex mode");
+			mac_cr &= ~MAC_CR_FDPX_;
+		}
+		smsc9420_reg_write(pd, MAC_CR, mac_cr);
+
+		smsc9420_phy_update_flowcontrol(pd);
+		pd->last_duplex = phy_dev->duplex;
+	}
+
+	carrier = netif_carrier_ok(dev);
+	if (carrier != pd->last_carrier) {
+		if (carrier)
+			smsc_dbg(LINK, "carrier OK");
+		else
+			smsc_dbg(LINK, "no carrier");
+		pd->last_carrier = carrier;
+	}
+}
+
+static int smsc9420_mii_probe(struct net_device *dev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	struct phy_device *phydev = NULL;
+
+	BUG_ON(pd->phy_dev);
+
+	/* Device only supports internal PHY at address 1 */
+	if (!pd->mii_bus->phy_map[1]) {
+		pr_err("%s: no PHY found at address 1\n", dev->name);
+		return -ENODEV;
+	}
+
+	phydev = pd->mii_bus->phy_map[1];
+	smsc_info(PROBE, "PHY addr %d, phy_id 0x%08X", phydev->addr,
+		phydev->phy_id);
+
+	phydev = phy_connect(dev, phydev->dev.bus_id,
+		&smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+
+	if (IS_ERR(phydev)) {
+		pr_err("%s: Could not attach to PHY\n", dev->name);
+		return PTR_ERR(phydev);
+	}
+
+	pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+		dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+
+	/* mask with MAC supported features */
+	phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
+			      SUPPORTED_Asym_Pause);
+	phydev->advertising = phydev->supported;
+
+	pd->phy_dev = phydev;
+	pd->last_duplex = -1;
+	pd->last_carrier = -1;
+
+	return 0;
+}
+
+static int smsc9420_mii_init(struct net_device *dev)
+{
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	int err = -ENXIO, i;
+
+	pd->mii_bus = mdiobus_alloc();
+	if (!pd->mii_bus) {
+		err = -ENOMEM;
+		goto err_out_1;
+	}
+	pd->mii_bus->name = DRV_MDIONAME;
+	snprintf(pd->mii_bus->id, MII_BUS_ID_SIZE, "%x",
+		(pd->pdev->bus->number << 8) | pd->pdev->devfn);
+	pd->mii_bus->priv = pd;
+	pd->mii_bus->read = smsc9420_mii_read;
+	pd->mii_bus->write = smsc9420_mii_write;
+	pd->mii_bus->irq = pd->phy_irq;
+	for (i = 0; i < PHY_MAX_ADDR; ++i)
+		pd->mii_bus->irq[i] = PHY_POLL;
+
+	/* Mask all PHYs except ID 1 (internal) */
+	pd->mii_bus->phy_mask = ~(1 << 1);
+
+	if (mdiobus_register(pd->mii_bus)) {
+		smsc_warn(PROBE, "Error registering mii bus");
+		goto err_out_free_bus_2;
+	}
+
+	if (smsc9420_mii_probe(dev) < 0) {
+		smsc_warn(PROBE, "Error probing mii bus");
+		goto err_out_unregister_bus_3;
+	}
+
+	return 0;
+
+err_out_unregister_bus_3:
+	mdiobus_unregister(pd->mii_bus);
+err_out_free_bus_2:
+	mdiobus_free(pd->mii_bus);
+err_out_1:
+	return err;
+}
+
+static int smsc9420_alloc_tx_ring(struct smsc9420_pdata *pd)
+{
+	int i;
+
+	BUG_ON(!pd->tx_ring);
+
+	pd->tx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) *
+		TX_RING_SIZE), GFP_KERNEL);
+	if (!pd->tx_buffers) {
+		smsc_warn(IFUP, "Failed to allocated tx_buffers");
+		return -ENOMEM;
+	}
+
+	/* Initialize the TX Ring */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		pd->tx_buffers[i].skb = NULL;
+		pd->tx_buffers[i].mapping = 0;
+		pd->tx_ring[i].status = 0;
+		pd->tx_ring[i].length = 0;
+		pd->tx_ring[i].buffer1 = 0;
+		pd->tx_ring[i].buffer2 = 0;
+	}
+	pd->tx_ring[TX_RING_SIZE - 1].length = TDES1_TER_;
+	wmb();
+
+	pd->tx_ring_head = 0;
+	pd->tx_ring_tail = 0;
+
+	smsc9420_reg_write(pd, TX_BASE_ADDR, pd->tx_dma_addr);
+	smsc9420_pci_flush_write(pd);
+
+	return 0;
+}
+
+static int smsc9420_alloc_rx_ring(struct smsc9420_pdata *pd)
+{
+	int i;
+
+	BUG_ON(!pd->rx_ring);
+
+	pd->rx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) *
+		RX_RING_SIZE), GFP_KERNEL);
+	if (pd->rx_buffers == NULL) {
+		smsc_warn(IFUP, "Failed to allocated rx_buffers");
+		goto out;
+	}
+
+	/* initialize the rx ring */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		pd->rx_ring[i].status = 0;
+		pd->rx_ring[i].length = PKT_BUF_SZ;
+		pd->rx_ring[i].buffer2 = 0;
+		pd->rx_buffers[i].skb = NULL;
+		pd->rx_buffers[i].mapping = 0;
+	}
+	pd->rx_ring[RX_RING_SIZE - 1].length = (PKT_BUF_SZ | RDES1_RER_);
+
+	/* now allocate the entire ring of skbs */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		if (smsc9420_alloc_rx_buffer(pd, i)) {
+			smsc_warn(IFUP, "failed to allocate rx skb %d", i);
+			goto out_free_rx_skbs;
+		}
+	}
+
+	pd->rx_ring_head = 0;
+	pd->rx_ring_tail = 0;
+
+	smsc9420_reg_write(pd, VLAN1, ETH_P_8021Q);
+	smsc_dbg(IFUP, "VLAN1 = 0x%08x", smsc9420_reg_read(pd, VLAN1));
+
+	if (pd->rx_csum) {
+		/* Enable RX COE */
+		u32 coe = smsc9420_reg_read(pd, COE_CR) | RX_COE_EN;
+		smsc9420_reg_write(pd, COE_CR, coe);
+		smsc_dbg(IFUP, "COE_CR = 0x%08x", coe);
+	}
+
+	smsc9420_reg_write(pd, RX_BASE_ADDR, pd->rx_dma_addr);
+	smsc9420_pci_flush_write(pd);
+
+	return 0;
+
+out_free_rx_skbs:
+	smsc9420_free_rx_ring(pd);
+out:
+	return -ENOMEM;
+}
+
+static int smsc9420_open(struct net_device *dev)
+{
+	struct smsc9420_pdata *pd;
+	u32 bus_mode, mac_cr, dmac_control, int_cfg, dma_intr_ena, int_ctl;
+	unsigned long flags;
+	int result = 0, timeout;
+
+	BUG_ON(!dev);
+	pd = netdev_priv(dev);
+	BUG_ON(!pd);
+
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		smsc_warn(IFUP, "dev_addr is not a valid MAC address");
+		result = -EADDRNOTAVAIL;
+		goto out_0;
+	}
+
+	netif_carrier_off(dev);
+
+	/* disable, mask and acknowlege all interrupts */
+	spin_lock_irqsave(&pd->int_lock, flags);
+	int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
+	smsc9420_reg_write(pd, INT_CFG, int_cfg);
+	smsc9420_reg_write(pd, INT_CTL, 0);
+	spin_unlock_irqrestore(&pd->int_lock, flags);
+	smsc9420_reg_write(pd, DMAC_INTR_ENA, 0);
+	smsc9420_reg_write(pd, INT_STAT, 0xFFFFFFFF);
+	smsc9420_pci_flush_write(pd);
+
+	if (request_irq(dev->irq, smsc9420_isr, IRQF_SHARED | IRQF_DISABLED,
+			DRV_NAME, pd)) {
+		smsc_warn(IFUP, "Unable to use IRQ = %d", dev->irq);
+		result = -ENODEV;
+		goto out_0;
+	}
+
+	smsc9420_dmac_soft_reset(pd);
+
+	/* make sure MAC_CR is sane */
+	smsc9420_reg_write(pd, MAC_CR, 0);
+
+	smsc9420_set_mac_address(dev);
+
+	/* Configure GPIO pins to drive LEDs */
+	smsc9420_reg_write(pd, GPIO_CFG,
+		(GPIO_CFG_LED_3_ | GPIO_CFG_LED_2_ | GPIO_CFG_LED_1_));
+
+	bus_mode = BUS_MODE_DMA_BURST_LENGTH_16;
+
+#ifdef __BIG_ENDIAN
+	bus_mode |= BUS_MODE_DBO_;
+#endif
+
+	smsc9420_reg_write(pd, BUS_MODE, bus_mode);
+
+	smsc9420_pci_flush_write(pd);
+
+	/* set bus master bridge arbitration priority for Rx and TX DMA */
+	smsc9420_reg_write(pd, BUS_CFG, BUS_CFG_RXTXWEIGHT_4_1);
+
+	smsc9420_reg_write(pd, DMAC_CONTROL,
+		(DMAC_CONTROL_SF_ | DMAC_CONTROL_OSF_));
+
+	smsc9420_pci_flush_write(pd);
+
+	/* test the IRQ connection to the ISR */
+	smsc_dbg(IFUP, "Testing ISR using IRQ %d", dev->irq);
+
+	spin_lock_irqsave(&pd->int_lock, flags);
+	/* configure interrupt deassertion timer and enable interrupts */
+	int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_;
+	int_cfg &= ~(INT_CFG_INT_DEAS_MASK);
+	int_cfg |= (INT_DEAS_TIME & INT_CFG_INT_DEAS_MASK);
+	smsc9420_reg_write(pd, INT_CFG, int_cfg);
+
+	/* unmask software interrupt */
+	int_ctl = smsc9420_reg_read(pd, INT_CTL) | INT_CTL_SW_INT_EN_;
+	smsc9420_reg_write(pd, INT_CTL, int_ctl);
+	spin_unlock_irqrestore(&pd->int_lock, flags);
+	smsc9420_pci_flush_write(pd);
+
+	timeout = 1000;
+	pd->software_irq_signal = false;
+	smp_wmb();
+	while (timeout--) {
+		if (pd->software_irq_signal)
+			break;
+		msleep(1);
+	}
+
+	/* disable interrupts */
+	spin_lock_irqsave(&pd->int_lock, flags);
+	int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
+	smsc9420_reg_write(pd, INT_CFG, int_cfg);
+	spin_unlock_irqrestore(&pd->int_lock, flags);
+
+	if (!pd->software_irq_signal) {
+		smsc_warn(IFUP, "ISR failed signaling test");
+		result = -ENODEV;
+		goto out_free_irq_1;
+	}
+
+	smsc_dbg(IFUP, "ISR passed test using IRQ %d", dev->irq);
+
+	result = smsc9420_alloc_tx_ring(pd);
+	if (result) {
+		smsc_warn(IFUP, "Failed to Initialize tx dma ring");
+		result = -ENOMEM;
+		goto out_free_irq_1;
+	}
+
+	result = smsc9420_alloc_rx_ring(pd);
+	if (result) {
+		smsc_warn(IFUP, "Failed to Initialize rx dma ring");
+		result = -ENOMEM;
+		goto out_free_tx_ring_2;
+	}
+
+	result = smsc9420_mii_init(dev);
+	if (result) {
+		smsc_warn(IFUP, "Failed to initialize Phy");
+		result = -ENODEV;
+		goto out_free_rx_ring_3;
+	}
+
+	/* Bring the PHY up */
+	phy_start(pd->phy_dev);
+
+	napi_enable(&pd->napi);
+
+	/* start tx and rx */
+	mac_cr = smsc9420_reg_read(pd, MAC_CR) | MAC_CR_TXEN_ | MAC_CR_RXEN_;
+	smsc9420_reg_write(pd, MAC_CR, mac_cr);
+
+	dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL);
+	dmac_control |= DMAC_CONTROL_ST_ | DMAC_CONTROL_SR_;
+	smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control);
+	smsc9420_pci_flush_write(pd);
+
+	dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
+	dma_intr_ena |=
+		(DMAC_INTR_ENA_TX_ | DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_);
+	smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
+	smsc9420_pci_flush_write(pd);
+
+	netif_wake_queue(dev);
+
+	smsc9420_reg_write(pd, RX_POLL_DEMAND, 1);
+
+	/* enable interrupts */
+	spin_lock_irqsave(&pd->int_lock, flags);
+	int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_;
+	smsc9420_reg_write(pd, INT_CFG, int_cfg);
+	spin_unlock_irqrestore(&pd->int_lock, flags);
+
+	return 0;
+
+out_free_rx_ring_3:
+	smsc9420_free_rx_ring(pd);
+out_free_tx_ring_2:
+	smsc9420_free_tx_ring(pd);
+out_free_irq_1:
+	free_irq(dev->irq, pd);
+out_0:
+	return result;
+}
+
+#ifdef CONFIG_PM
+
+static int smsc9420_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	u32 int_cfg;
+	ulong flags;
+
+	/* disable interrupts */
+	spin_lock_irqsave(&pd->int_lock, flags);
+	int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
+	smsc9420_reg_write(pd, INT_CFG, int_cfg);
+	spin_unlock_irqrestore(&pd->int_lock, flags);
+
+	if (netif_running(dev)) {
+		netif_tx_disable(dev);
+		smsc9420_stop_tx(pd);
+		smsc9420_free_tx_ring(pd);
+
+		napi_disable(&pd->napi);
+		smsc9420_stop_rx(pd);
+		smsc9420_free_rx_ring(pd);
+
+		free_irq(dev->irq, pd);
+
+		netif_device_detach(dev);
+	}
+
+	pci_save_state(pdev);
+	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+static int smsc9420_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct smsc9420_pdata *pd = netdev_priv(dev);
+	int err;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	pci_set_master(pdev);
+
+	err = pci_enable_wake(pdev, 0, 0);
+	if (err)
+		smsc_warn(IFUP, "pci_enable_wake failed: %d", err);
+
+	if (netif_running(dev)) {
+		err = smsc9420_open(dev);
+		netif_device_attach(dev);
+	}
+	return err;
+}
+
+#endif /* CONFIG_PM */
+
+static const struct net_device_ops smsc9420_netdev_ops = {
+	.ndo_open		= smsc9420_open,
+	.ndo_stop		= smsc9420_stop,
+	.ndo_start_xmit		= smsc9420_hard_start_xmit,
+	.ndo_get_stats		= smsc9420_get_stats,
+	.ndo_set_multicast_list	= smsc9420_set_multicast_list,
+	.ndo_do_ioctl		= smsc9420_do_ioctl,
+	.ndo_validate_addr	= eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= smsc9420_poll_controller,
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+};
+
+static int __devinit
+smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct net_device *dev;
+	struct smsc9420_pdata *pd;
+	void __iomem *virt_addr;
+	int result = 0;
+	u32 id_rev;
+
+	printk(KERN_INFO DRV_DESCRIPTION " version " DRV_VERSION "\n");
+
+	/* First do the PCI initialisation */
+	result = pci_enable_device(pdev);
+	if (unlikely(result)) {
+		printk(KERN_ERR "Cannot enable smsc9420\n");
+		goto out_0;
+	}
+
+	pci_set_master(pdev);
+
+	dev = alloc_etherdev(sizeof(*pd));
+	if (!dev) {
+		printk(KERN_ERR "ether device alloc failed\n");
+		goto out_disable_pci_device_1;
+	}
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	if (!(pci_resource_flags(pdev, SMSC_BAR) & IORESOURCE_MEM)) {
+		printk(KERN_ERR "Cannot find PCI device base address\n");
+		goto out_free_netdev_2;
+	}
+
+	if ((pci_request_regions(pdev, DRV_NAME))) {
+		printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n");
+		goto out_free_netdev_2;
+	}
+
+	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+		printk(KERN_ERR "No usable DMA configuration, aborting.\n");
+		goto out_free_regions_3;
+	}
+
+	virt_addr = ioremap(pci_resource_start(pdev, SMSC_BAR),
+		pci_resource_len(pdev, SMSC_BAR));
+	if (!virt_addr) {
+		printk(KERN_ERR "Cannot map device registers, aborting.\n");
+		goto out_free_regions_3;
+	}
+
+	/* registers are double mapped with 0 offset for LE and 0x200 for BE */
+	virt_addr += LAN9420_CPSR_ENDIAN_OFFSET;
+
+	dev->base_addr = (ulong)virt_addr;
+
+	pd = netdev_priv(dev);
+
+	/* pci descriptors are created in the PCI consistent area */
+	pd->rx_ring = pci_alloc_consistent(pdev,
+		sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE +
+		sizeof(struct smsc9420_dma_desc) * TX_RING_SIZE,
+		&pd->rx_dma_addr);
+
+	if (!pd->rx_ring)
+		goto out_free_io_4;
+
+	/* descriptors are aligned due to the nature of pci_alloc_consistent */
+	pd->tx_ring = (struct smsc9420_dma_desc *)
+	    (pd->rx_ring + RX_RING_SIZE);
+	pd->tx_dma_addr = pd->rx_dma_addr +
+	    sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE;
+
+	pd->pdev = pdev;
+	pd->dev = dev;
+	pd->base_addr = virt_addr;
+	pd->msg_enable = smsc_debug;
+	pd->rx_csum = true;
+
+	smsc_dbg(PROBE, "lan_base=0x%08lx", (ulong)virt_addr);
+
+	id_rev = smsc9420_reg_read(pd, ID_REV);
+	switch (id_rev & 0xFFFF0000) {
+	case 0x94200000:
+		smsc_info(PROBE, "LAN9420 identified, ID_REV=0x%08X", id_rev);
+		break;
+	default:
+		smsc_warn(PROBE, "LAN9420 NOT identified");
+		smsc_warn(PROBE, "ID_REV=0x%08X", id_rev);
+		goto out_free_dmadesc_5;
+	}
+
+	smsc9420_dmac_soft_reset(pd);
+	smsc9420_eeprom_reload(pd);
+	smsc9420_check_mac_address(dev);
+
+	dev->netdev_ops = &smsc9420_netdev_ops;
+	dev->ethtool_ops = &smsc9420_ethtool_ops;
+	dev->irq = pdev->irq;
+
+	netif_napi_add(dev, &pd->napi, smsc9420_rx_poll, NAPI_WEIGHT);
+
+	result = register_netdev(dev);
+	if (result) {
+		smsc_warn(PROBE, "error %i registering device", result);
+		goto out_free_dmadesc_5;
+	}
+
+	pci_set_drvdata(pdev, dev);
+
+	spin_lock_init(&pd->int_lock);
+	spin_lock_init(&pd->phy_lock);
+
+	dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr);
+
+	return 0;
+
+out_free_dmadesc_5:
+	pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) *
+		(RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr);
+out_free_io_4:
+	iounmap(virt_addr - LAN9420_CPSR_ENDIAN_OFFSET);
+out_free_regions_3:
+	pci_release_regions(pdev);
+out_free_netdev_2:
+	free_netdev(dev);
+out_disable_pci_device_1:
+	pci_disable_device(pdev);
+out_0:
+	return -ENODEV;
+}
+
+static void __devexit smsc9420_remove(struct pci_dev *pdev)
+{
+	struct net_device *dev;
+	struct smsc9420_pdata *pd;
+
+	dev = pci_get_drvdata(pdev);
+	if (!dev)
+		return;
+
+	pci_set_drvdata(pdev, NULL);
+
+	pd = netdev_priv(dev);
+	unregister_netdev(dev);
+
+	/* tx_buffers and rx_buffers are freed in stop */
+	BUG_ON(pd->tx_buffers);
+	BUG_ON(pd->rx_buffers);
+
+	BUG_ON(!pd->tx_ring);
+	BUG_ON(!pd->rx_ring);
+
+	pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) *
+		(RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr);
+
+	iounmap(pd->base_addr - LAN9420_CPSR_ENDIAN_OFFSET);
+	pci_release_regions(pdev);
+	free_netdev(dev);
+	pci_disable_device(pdev);
+}
+
+static struct pci_driver smsc9420_driver = {
+	.name = DRV_NAME,
+	.id_table = smsc9420_id_table,
+	.probe = smsc9420_probe,
+	.remove = __devexit_p(smsc9420_remove),
+#ifdef CONFIG_PM
+	.suspend = smsc9420_suspend,
+	.resume = smsc9420_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init smsc9420_init_module(void)
+{
+	smsc_debug = netif_msg_init(debug, SMSC_MSG_DEFAULT);
+
+	return pci_register_driver(&smsc9420_driver);
+}
+
+static void __exit smsc9420_exit_module(void)
+{
+	pci_unregister_driver(&smsc9420_driver);
+}
+
+module_init(smsc9420_init_module);
+module_exit(smsc9420_exit_module);
diff --git a/drivers/net/smsc9420.h b/drivers/net/smsc9420.h
new file mode 100644
index 0000000..69c351f
--- /dev/null
+++ b/drivers/net/smsc9420.h
@@ -0,0 +1,275 @@
+ /***************************************************************************
+ *
+ * Copyright (C) 2007,2008  SMSC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 _SMSC9420_H
+#define _SMSC9420_H
+
+#define TX_RING_SIZE			(32)
+#define RX_RING_SIZE			(128)
+
+/* interrupt deassertion in multiples of 10us */
+#define INT_DEAS_TIME			(50)
+
+#define NAPI_WEIGHT			(64)
+#define SMSC_BAR			(3)
+
+#ifdef __BIG_ENDIAN
+/* Register set is duplicated for BE at an offset of 0x200 */
+#define LAN9420_CPSR_ENDIAN_OFFSET	(0x200)
+#else
+#define LAN9420_CPSR_ENDIAN_OFFSET	(0)
+#endif
+
+#define PCI_VENDOR_ID_9420		(0x1055)
+#define PCI_DEVICE_ID_9420		(0xE420)
+
+#define LAN_REGISTER_EXTENT		(0x400)
+
+#define SMSC9420_EEPROM_SIZE		((u32)11)
+
+#define PKT_BUF_SZ			(VLAN_ETH_FRAME_LEN + NET_IP_ALIGN + 4)
+
+/***********************************************/
+/* DMA Controller Control and Status Registers */
+/***********************************************/
+#define BUS_MODE			(0x00)
+#define BUS_MODE_SWR_			(BIT(0))
+#define BUS_MODE_DMA_BURST_LENGTH_1	(BIT(8))
+#define BUS_MODE_DMA_BURST_LENGTH_2	(BIT(9))
+#define BUS_MODE_DMA_BURST_LENGTH_4	(BIT(10))
+#define BUS_MODE_DMA_BURST_LENGTH_8	(BIT(11))
+#define BUS_MODE_DMA_BURST_LENGTH_16	(BIT(12))
+#define BUS_MODE_DMA_BURST_LENGTH_32	(BIT(13))
+#define BUS_MODE_DBO_			(BIT(20))
+
+#define TX_POLL_DEMAND			(0x04)
+
+#define RX_POLL_DEMAND			(0x08)
+
+#define RX_BASE_ADDR			(0x0C)
+
+#define TX_BASE_ADDR			(0x10)
+
+#define DMAC_STATUS			(0x14)
+#define DMAC_STS_TS_			(7 << 20)
+#define DMAC_STS_RS_ 			(7 << 17)
+#define DMAC_STS_NIS_			(BIT(16))
+#define DMAC_STS_AIS_			(BIT(15))
+#define DMAC_STS_RWT_			(BIT(9))
+#define DMAC_STS_RXPS_			(BIT(8))
+#define DMAC_STS_RXBU_			(BIT(7))
+#define DMAC_STS_RX_			(BIT(6))
+#define DMAC_STS_TXUNF_			(BIT(5))
+#define DMAC_STS_TXBU_			(BIT(2))
+#define DMAC_STS_TXPS_			(BIT(1))
+#define DMAC_STS_TX_			(BIT(0))
+
+#define DMAC_CONTROL			(0x18)
+#define DMAC_CONTROL_TTM_		(BIT(22))
+#define DMAC_CONTROL_SF_		(BIT(21))
+#define DMAC_CONTROL_ST_		(BIT(13))
+#define DMAC_CONTROL_OSF_		(BIT(2))
+#define DMAC_CONTROL_SR_		(BIT(1))
+
+#define DMAC_INTR_ENA			(0x1C)
+#define DMAC_INTR_ENA_NIS_		(BIT(16))
+#define DMAC_INTR_ENA_AIS_		(BIT(15))
+#define DMAC_INTR_ENA_RWT_		(BIT(9))
+#define DMAC_INTR_ENA_RXPS_		(BIT(8))
+#define DMAC_INTR_ENA_RXBU_		(BIT(7))
+#define DMAC_INTR_ENA_RX_		(BIT(6))
+#define DMAC_INTR_ENA_TXBU_		(BIT(2))
+#define DMAC_INTR_ENA_TXPS_		(BIT(1))
+#define DMAC_INTR_ENA_TX_		(BIT(0))
+
+#define MISS_FRAME_CNTR			(0x20)
+
+#define TX_BUFF_ADDR			(0x50)
+
+#define RX_BUFF_ADDR			(0x54)
+
+/* Transmit Descriptor Bit Defs */
+#define TDES0_OWN_			(0x80000000)
+#define TDES0_ERROR_SUMMARY_		(0x00008000)
+#define TDES0_LOSS_OF_CARRIER_		(0x00000800)
+#define TDES0_NO_CARRIER_		(0x00000400)
+#define TDES0_LATE_COLLISION_		(0x00000200)
+#define TDES0_EXCESSIVE_COLLISIONS_	(0x00000100)
+#define TDES0_HEARTBEAT_FAIL_		(0x00000080)
+#define TDES0_COLLISION_COUNT_MASK_	(0x00000078)
+#define TDES0_COLLISION_COUNT_SHFT_	(3)
+#define TDES0_EXCESSIVE_DEFERRAL_	(0x00000004)
+#define TDES0_DEFERRED_			(0x00000001)
+
+#define TDES1_IC_			0x80000000
+#define TDES1_LS_			0x40000000
+#define TDES1_FS_			0x20000000
+#define TDES1_TXCSEN_			0x08000000
+#define TDES1_TER_			(BIT(25))
+#define TDES1_TCH_			0x01000000
+
+/* Receive Descriptor 0 Bit Defs */
+#define RDES0_OWN_			(0x80000000)
+#define RDES0_FRAME_LENGTH_MASK_	(0x07FF0000)
+#define RDES0_FRAME_LENGTH_SHFT_	(16)
+#define RDES0_ERROR_SUMMARY_		(0x00008000)
+#define RDES0_DESCRIPTOR_ERROR_		(0x00004000)
+#define RDES0_LENGTH_ERROR_		(0x00001000)
+#define RDES0_RUNT_FRAME_		(0x00000800)
+#define RDES0_MULTICAST_FRAME_		(0x00000400)
+#define RDES0_FIRST_DESCRIPTOR_		(0x00000200)
+#define RDES0_LAST_DESCRIPTOR_		(0x00000100)
+#define RDES0_FRAME_TOO_LONG_		(0x00000080)
+#define RDES0_COLLISION_SEEN_		(0x00000040)
+#define RDES0_FRAME_TYPE_		(0x00000020)
+#define RDES0_WATCHDOG_TIMEOUT_		(0x00000010)
+#define RDES0_MII_ERROR_		(0x00000008)
+#define RDES0_DRIBBLING_BIT_		(0x00000004)
+#define RDES0_CRC_ERROR_		(0x00000002)
+
+/* Receive Descriptor 1 Bit Defs */
+#define RDES1_RER_			(0x02000000)
+
+/***********************************************/
+/*       MAC Control and Status Registers      */
+/***********************************************/
+#define MAC_CR				(0x80)
+#define MAC_CR_RXALL_			(0x80000000)
+#define MAC_CR_DIS_RXOWN_		(0x00800000)
+#define MAC_CR_LOOPBK_			(0x00200000)
+#define MAC_CR_FDPX_			(0x00100000)
+#define MAC_CR_MCPAS_			(0x00080000)
+#define MAC_CR_PRMS_			(0x00040000)
+#define MAC_CR_INVFILT_			(0x00020000)
+#define MAC_CR_PASSBAD_			(0x00010000)
+#define MAC_CR_HFILT_			(0x00008000)
+#define MAC_CR_HPFILT_			(0x00002000)
+#define MAC_CR_LCOLL_			(0x00001000)
+#define MAC_CR_DIS_BCAST_		(0x00000800)
+#define MAC_CR_DIS_RTRY_		(0x00000400)
+#define MAC_CR_PADSTR_			(0x00000100)
+#define MAC_CR_BOLMT_MSK		(0x000000C0)
+#define MAC_CR_MFCHK_			(0x00000020)
+#define MAC_CR_TXEN_			(0x00000008)
+#define MAC_CR_RXEN_			(0x00000004)
+
+#define ADDRH				(0x84)
+
+#define ADDRL				(0x88)
+
+#define HASHH				(0x8C)
+
+#define HASHL				(0x90)
+
+#define MII_ACCESS			(0x94)
+#define MII_ACCESS_MII_BUSY_		(0x00000001)
+#define MII_ACCESS_MII_WRITE_		(0x00000002)
+#define MII_ACCESS_MII_READ_		(0x00000000)
+#define MII_ACCESS_INDX_MSK_		(0x000007C0)
+#define MII_ACCESS_PHYADDR_MSK_		(0x0000F8C0)
+#define MII_ACCESS_INDX_SHFT_CNT	(6)
+#define MII_ACCESS_PHYADDR_SHFT_CNT	(11)
+
+#define MII_DATA			(0x98)
+
+#define FLOW				(0x9C)
+
+#define VLAN1				(0xA0)
+
+#define VLAN2				(0xA4)
+
+#define WUFF				(0xA8)
+
+#define WUCSR				(0xAC)
+
+#define COE_CR				(0xB0)
+#define TX_COE_EN			(0x00010000)
+#define RX_COE_MODE			(0x00000002)
+#define RX_COE_EN			(0x00000001)
+
+/***********************************************/
+/*     System Control and Status Registers     */
+/***********************************************/
+#define ID_REV				(0xC0)
+
+#define INT_CTL				(0xC4)
+#define INT_CTL_SW_INT_EN_		(0x00008000)
+#define INT_CTL_SBERR_INT_EN_		(1 << 12)
+#define INT_CTL_MBERR_INT_EN_		(1 << 13)
+#define INT_CTL_GPT_INT_EN_		(0x00000008)
+#define INT_CTL_PHY_INT_EN_		(0x00000004)
+#define INT_CTL_WAKE_INT_EN_		(0x00000002)
+
+#define INT_STAT			(0xC8)
+#define INT_STAT_SW_INT_		(1 << 15)
+#define INT_STAT_MBERR_INT_		(1 << 13)
+#define INT_STAT_SBERR_INT_		(1 << 12)
+#define INT_STAT_GPT_INT_		(1 << 3)
+#define INT_STAT_PHY_INT_		(0x00000004)
+#define INT_STAT_WAKE_INT_		(0x00000002)
+#define INT_STAT_DMAC_INT_		(0x00000001)
+
+#define INT_CFG				(0xCC)
+#define INT_CFG_IRQ_INT_		(0x00080000)
+#define INT_CFG_IRQ_EN_			(0x00040000)
+#define INT_CFG_INT_DEAS_CLR_		(0x00000200)
+#define INT_CFG_INT_DEAS_MASK		(0x000000FF)
+
+#define GPIO_CFG			(0xD0)
+#define GPIO_CFG_LED_3_			(0x40000000)
+#define GPIO_CFG_LED_2_			(0x20000000)
+#define GPIO_CFG_LED_1_			(0x10000000)
+#define GPIO_CFG_EEPR_EN_		(0x00700000)
+
+#define GPT_CFG				(0xD4)
+#define GPT_CFG_TIMER_EN_		(0x20000000)
+
+#define GPT_CNT				(0xD8)
+
+#define BUS_CFG				(0xDC)
+#define BUS_CFG_RXTXWEIGHT_1_1		(0 << 25)
+#define BUS_CFG_RXTXWEIGHT_2_1		(1 << 25)
+#define BUS_CFG_RXTXWEIGHT_3_1		(2 << 25)
+#define BUS_CFG_RXTXWEIGHT_4_1		(3 << 25)
+
+#define PMT_CTRL			(0xE0)
+
+#define FREE_RUN			(0xF4)
+
+#define E2P_CMD				(0xF8)
+#define E2P_CMD_EPC_BUSY_		(0x80000000)
+#define E2P_CMD_EPC_CMD_		(0x70000000)
+#define E2P_CMD_EPC_CMD_READ_		(0x00000000)
+#define E2P_CMD_EPC_CMD_EWDS_		(0x10000000)
+#define E2P_CMD_EPC_CMD_EWEN_		(0x20000000)
+#define E2P_CMD_EPC_CMD_WRITE_		(0x30000000)
+#define E2P_CMD_EPC_CMD_WRAL_		(0x40000000)
+#define E2P_CMD_EPC_CMD_ERASE_		(0x50000000)
+#define E2P_CMD_EPC_CMD_ERAL_		(0x60000000)
+#define E2P_CMD_EPC_CMD_RELOAD_		(0x70000000)
+#define E2P_CMD_EPC_TIMEOUT_		(0x00000200)
+#define E2P_CMD_MAC_ADDR_LOADED_	(0x00000100)
+#define E2P_CMD_EPC_ADDR_		(0x000000FF)
+
+#define E2P_DATA			(0xFC)
+#define E2P_DATA_EEPROM_DATA_		(0x000000FF)
+
+#endif /* _SMSC9420_H */
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index 8069f3e..211e805 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -450,7 +450,6 @@
 			skb_trim(used_skb, pkt_len);
 			used_skb->protocol = eth_type_trans(used_skb, dev);
 			netif_rx(used_skb);
-			dev->last_rx = jiffies;
 			lp->stats.rx_packets++;
 			lp->stats.rx_bytes += pkt_len;
 
diff --git a/drivers/net/sonic.h b/drivers/net/sonic.h
index 7db13e4..07091dd 100644
--- a/drivers/net/sonic.h
+++ b/drivers/net/sonic.h
@@ -371,7 +371,7 @@
 static inline void sonic_cda_put(struct net_device* dev, int entry,
 				 int offset, __u16 val)
 {
-	struct sonic_local* lp = (struct sonic_local *) dev->priv;
+	struct sonic_local *lp = netdev_priv(dev);
 	sonic_buf_put(lp->cda, lp->dma_bitmode,
 		      (entry * SIZEOF_SONIC_CD) + offset, val);
 }
@@ -379,27 +379,27 @@
 static inline __u16 sonic_cda_get(struct net_device* dev, int entry,
 				  int offset)
 {
-	struct sonic_local* lp = (struct sonic_local *) dev->priv;
+	struct sonic_local *lp = netdev_priv(dev);
 	return sonic_buf_get(lp->cda, lp->dma_bitmode,
 			     (entry * SIZEOF_SONIC_CD) + offset);
 }
 
 static inline void sonic_set_cam_enable(struct net_device* dev, __u16 val)
 {
-	struct sonic_local* lp = (struct sonic_local *) dev->priv;
+	struct sonic_local *lp = netdev_priv(dev);
 	sonic_buf_put(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE, val);
 }
 
 static inline __u16 sonic_get_cam_enable(struct net_device* dev)
 {
-	struct sonic_local* lp = (struct sonic_local *) dev->priv;
+	struct sonic_local *lp = netdev_priv(dev);
 	return sonic_buf_get(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE);
 }
 
 static inline void sonic_tda_put(struct net_device* dev, int entry,
 				 int offset, __u16 val)
 {
-	struct sonic_local* lp = (struct sonic_local *) dev->priv;
+	struct sonic_local *lp = netdev_priv(dev);
 	sonic_buf_put(lp->tda, lp->dma_bitmode,
 		      (entry * SIZEOF_SONIC_TD) + offset, val);
 }
@@ -407,7 +407,7 @@
 static inline __u16 sonic_tda_get(struct net_device* dev, int entry,
 				  int offset)
 {
-	struct sonic_local* lp = (struct sonic_local *) dev->priv;
+	struct sonic_local *lp = netdev_priv(dev);
 	return sonic_buf_get(lp->tda, lp->dma_bitmode,
 			     (entry * SIZEOF_SONIC_TD) + offset);
 }
@@ -415,7 +415,7 @@
 static inline void sonic_rda_put(struct net_device* dev, int entry,
 				 int offset, __u16 val)
 {
-	struct sonic_local* lp = (struct sonic_local *) dev->priv;
+	struct sonic_local *lp = netdev_priv(dev);
 	sonic_buf_put(lp->rda, lp->dma_bitmode,
 		      (entry * SIZEOF_SONIC_RD) + offset, val);
 }
@@ -423,7 +423,7 @@
 static inline __u16 sonic_rda_get(struct net_device* dev, int entry,
 				  int offset)
 {
-	struct sonic_local* lp = (struct sonic_local *) dev->priv;
+	struct sonic_local *lp = netdev_priv(dev);
 	return sonic_buf_get(lp->rda, lp->dma_bitmode,
 			     (entry * SIZEOF_SONIC_RD) + offset);
 }
@@ -431,7 +431,7 @@
 static inline void sonic_rra_put(struct net_device* dev, int entry,
 				 int offset, __u16 val)
 {
-	struct sonic_local* lp = (struct sonic_local *) dev->priv;
+	struct sonic_local *lp = netdev_priv(dev);
 	sonic_buf_put(lp->rra, lp->dma_bitmode,
 		      (entry * SIZEOF_SONIC_RR) + offset, val);
 }
@@ -439,7 +439,7 @@
 static inline __u16 sonic_rra_get(struct net_device* dev, int entry,
 				  int offset)
 {
-	struct sonic_local* lp = (struct sonic_local *) dev->priv;
+	struct sonic_local *lp = netdev_priv(dev);
 	return sonic_buf_get(lp->rra, lp->dma_bitmode,
 			     (entry * SIZEOF_SONIC_RR) + offset);
 }
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 07599b4..c5c123d 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -789,7 +789,7 @@
  * spider_net_release_tx_chain releases the tx descriptors that spider has
  * finished with (if non-brutal) or simply release tx descriptors (if brutal).
  * If some other context is calling this function, we return 1 so that we're
- * scheduled again (if we were scheduled) and will not loose initiative.
+ * scheduled again (if we were scheduled) and will not lose initiative.
  */
 static int
 spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
@@ -1302,7 +1302,7 @@
 	/* if all packets are in the stack, enable interrupts and return 0 */
 	/* if not, return 1 */
 	if (packets_done < budget) {
-		netif_rx_complete(netdev, napi);
+		netif_rx_complete(napi);
 		spider_net_rx_irq_on(card);
 		card->ignore_rx_ramfull = 0;
 	}
@@ -1529,8 +1529,7 @@
 			spider_net_refill_rx_chain(card);
 			spider_net_enable_rxdmac(card);
 			card->num_rx_ints ++;
-			netif_rx_schedule(card->netdev,
-					  &card->napi);
+			netif_rx_schedule(&card->napi);
 		}
 		show_error = 0;
 		break;
@@ -1550,8 +1549,7 @@
 		spider_net_refill_rx_chain(card);
 		spider_net_enable_rxdmac(card);
 		card->num_rx_ints ++;
-		netif_rx_schedule(card->netdev,
-				  &card->napi);
+		netif_rx_schedule(&card->napi);
 		show_error = 0;
 		break;
 
@@ -1565,8 +1563,7 @@
 		spider_net_refill_rx_chain(card);
 		spider_net_enable_rxdmac(card);
 		card->num_rx_ints ++;
-		netif_rx_schedule(card->netdev,
-				  &card->napi);
+		netif_rx_schedule(&card->napi);
 		show_error = 0;
 		break;
 
@@ -1660,11 +1657,11 @@
 
 	if (status_reg & SPIDER_NET_RXINT ) {
 		spider_net_rx_irq_off(card);
-		netif_rx_schedule(netdev, &card->napi);
+		netif_rx_schedule(&card->napi);
 		card->num_rx_ints ++;
 	}
 	if (status_reg & SPIDER_NET_TXINT)
-		netif_rx_schedule(netdev, &card->napi);
+		netif_rx_schedule(&card->napi);
 
 	if (status_reg & SPIDER_NET_LINKINT)
 		spider_net_link_reset(netdev);
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index 85691d2..5bae728 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -118,7 +118,7 @@
 static u32
 spider_net_ethtool_get_rx_csum(struct net_device *netdev)
 {
-	struct spider_net_card *card = netdev->priv;
+	struct spider_net_card *card = netdev_priv(netdev);
 
 	return card->options.rx_csum;
 }
@@ -126,7 +126,7 @@
 static int
 spider_net_ethtool_set_rx_csum(struct net_device *netdev, u32 n)
 {
-	struct spider_net_card *card = netdev->priv;
+	struct spider_net_card *card = netdev_priv(netdev);
 
 	card->options.rx_csum = n;
 	return 0;
@@ -137,7 +137,7 @@
 spider_net_ethtool_get_ringparam(struct net_device *netdev,
 				 struct ethtool_ringparam *ering)
 {
-	struct spider_net_card *card = netdev->priv;
+	struct spider_net_card *card = netdev_priv(netdev);
 
 	ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX;
 	ering->tx_pending = card->tx_chain.num_desc;
@@ -158,7 +158,7 @@
 static void spider_net_get_ethtool_stats(struct net_device *netdev,
 		struct ethtool_stats *stats, u64 *data)
 {
-	struct spider_net_card *card = netdev->priv;
+	struct spider_net_card *card = netdev_priv(netdev);
 
 	data[0] = netdev->stats.tx_packets;
 	data[1] = netdev->stats.tx_bytes;
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 5a40f2d..f54ac23 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -653,7 +653,6 @@
 	void __iomem *base;
 	int drv_flags, io_size;
 	int boguscnt;
-	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -823,9 +822,9 @@
 	if (register_netdev(dev))
 		goto err_out_cleardev;
 
-	printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+	printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n",
 	       dev->name, netdrv_tbl[chip_idx].name, base,
-	       print_mac(mac, dev->dev_addr), irq);
+	       dev->dev_addr, irq);
 
 	if (drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
@@ -881,9 +880,9 @@
 	void __iomem *mdio_addr = np->base + MIICtrl + (phy_id<<7) + (location<<2);
 	int result, boguscnt=1000;
 	/* ??? Should we add a busy-wait here? */
-	do
+	do {
 		result = readl(mdio_addr);
-	while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0);
+	} while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0);
 	if (boguscnt == 0)
 		return 0;
 	if ((result & 0xffff) == 0xffff)
@@ -1291,8 +1290,8 @@
 		if (intr_status & (IntrRxDone | IntrRxEmpty)) {
 			u32 enable;
 
-			if (likely(netif_rx_schedule_prep(dev, &np->napi))) {
-				__netif_rx_schedule(dev, &np->napi);
+			if (likely(netif_rx_schedule_prep(&np->napi))) {
+				__netif_rx_schedule(&np->napi);
 				enable = readl(ioaddr + IntrEnable);
 				enable &= ~(IntrRxDone | IntrRxEmpty);
 				writel(enable, ioaddr + IntrEnable);
@@ -1452,12 +1451,8 @@
 #ifndef final_version			/* Remove after testing. */
 		/* You will want this info for the initial debug. */
 		if (debug > 5) {
-			printk(KERN_DEBUG "  Rx data " MAC_FMT " " MAC_FMT
-			       " %2.2x%2.2x.\n",
-			       skb->data[0], skb->data[1], skb->data[2],
-			       skb->data[3], skb->data[4], skb->data[5],
-			       skb->data[6], skb->data[7], skb->data[8],
-			       skb->data[9], skb->data[10], skb->data[11],
+			printk(KERN_DEBUG "  Rx data %pM %pM %2.2x%2.2x.\n",
+			       skb->data, skb->data + 6,
 			       skb->data[12], skb->data[13]);
 		}
 #endif
@@ -1501,7 +1496,6 @@
 		} else
 #endif /* VLAN_SUPPORT */
 			netif_receive_skb(skb);
-		dev->last_rx = jiffies;
 		np->stats.rx_packets++;
 
 	next_rx:
@@ -1541,7 +1535,7 @@
 		intr_status = readl(ioaddr + IntrStatus);
 	} while (intr_status & (IntrRxDone | IntrRxEmpty));
 
-	netif_rx_complete(dev, napi);
+	netif_rx_complete(napi);
 	intr_status = readl(ioaddr + IntrEnable);
 	intr_status |= IntrRxDone | IntrRxEmpty;
 	writel(intr_status, ioaddr + IntrEnable);
diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c
index 2ed0bd5..87a6b8e 100644
--- a/drivers/net/stnic.c
+++ b/drivers/net/stnic.c
@@ -60,8 +60,6 @@
 
 static struct net_device *stnic_dev;
 
-static int stnic_open (struct net_device *dev);
-static int stnic_close (struct net_device *dev);
 static void stnic_reset (struct net_device *dev);
 static void stnic_get_hdr (struct net_device *dev, struct e8390_pkt_hdr *hdr,
 			   int ring_page);
@@ -122,11 +120,7 @@
   /* Set the base address to point to the NIC, not the "real" base! */
   dev->base_addr = 0x1000;
   dev->irq = IRQ_STNIC;
-  dev->open = &stnic_open;
-  dev->stop = &stnic_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-  dev->poll_controller = ei_poll;
-#endif
+  dev->netdev_ops = &ei_netdev_ops;
 
   /* Snarf the interrupt now.  There's no point in waiting since we cannot
      share and the board will usually be enabled. */
@@ -168,23 +162,6 @@
   return 0;
 }
 
-static int
-stnic_open (struct net_device *dev)
-{
-#if 0
-  printk (KERN_DEBUG "stnic open\n");
-#endif
-  ei_open (dev);
-  return 0;
-}
-
-static int
-stnic_close (struct net_device *dev)
-{
-  ei_close (dev);
-  return 0;
-}
-
 static void
 stnic_reset (struct net_device *dev)
 {
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index e531302..e0d8477 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -209,7 +209,7 @@
 static int check586(struct net_device *dev,char *where,unsigned size)
 {
 	struct priv pb;
-	struct priv *p = /* (struct priv *) dev->priv*/ &pb;
+	struct priv *p = &pb;
 	char *iscp_addr;
 	int i;
 
@@ -247,7 +247,7 @@
  */
 static void alloc586(struct net_device *dev)
 {
-	struct priv *p =	(struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	sun3_reset586();
 	DELAY(1);
@@ -363,17 +363,21 @@
 		goto out;
 	}
 
-	((struct priv *) (dev->priv))->memtop = (char *)dvma_btov(dev->mem_start);
-	((struct priv *) (dev->priv))->base = (unsigned long) dvma_btov(0);
+	((struct priv *)netdev_priv(dev))->memtop =
+					(char *)dvma_btov(dev->mem_start);
+	((struct priv *)netdev_priv(dev))->base = (unsigned long) dvma_btov(0);
 	alloc586(dev);
 
 	/* set number of receive-buffs according to memsize */
 	if(size == 0x2000)
-		((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8;
+		((struct priv *)netdev_priv(dev))->num_recv_buffs =
+							NUM_RECV_BUFFS_8;
 	else if(size == 0x4000)
-		((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16;
+		((struct priv *)netdev_priv(dev))->num_recv_buffs =
+							NUM_RECV_BUFFS_16;
 	else
-		((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_32;
+		((struct priv *)netdev_priv(dev))->num_recv_buffs =
+							NUM_RECV_BUFFS_32;
 
 	printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq);
 
@@ -397,7 +401,7 @@
 {
 	void *ptr;
 	int i,result=0;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 	volatile struct configure_cmd_struct	*cfg_cmd;
 	volatile struct iasetup_cmd_struct *ias_cmd;
 	volatile struct tdr_cmd_struct *tdr_cmd;
@@ -631,7 +635,7 @@
 	volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
 	volatile struct rbd_struct *rbd;
 	int i;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
 	p->rfd_first = rfd;
@@ -683,7 +687,7 @@
 		printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq);
 		return IRQ_NONE;
 	}
-	p = (struct priv *) dev->priv;
+	p = netdev_priv(dev);
 
 	if(debuglevel > 1)
 		printk("I");
@@ -753,7 +757,7 @@
 	unsigned short totlen;
 	struct sk_buff *skb;
 	struct rbd_struct *rbd;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	if(debuglevel > 0)
 		printk("R");
@@ -871,7 +875,7 @@
 
 static void sun3_82586_rnr_int(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	p->stats.rx_errors++;
 
@@ -895,7 +899,7 @@
 static void sun3_82586_xmt_int(struct net_device *dev)
 {
 	int status;
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	if(debuglevel > 0)
 		printk("X");
@@ -945,7 +949,7 @@
 
 static void startrecv586(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	WAIT_4_SCB_CMD();
 	WAIT_4_SCB_CMD_RUC();
@@ -957,7 +961,7 @@
 
 static void sun3_82586_timeout(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 #ifndef NO_NOPCOMMANDS
 	if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
 	{
@@ -999,7 +1003,7 @@
 #ifndef NO_NOPCOMMANDS
 	int next_nop;
 #endif
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 
 	if(skb->len > XMIT_BUFF_SIZE)
 	{
@@ -1108,7 +1112,7 @@
 
 static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 	unsigned short crc,aln,rsc,ovrn;
 
 	crc = swab16(p->scb->crc_errs); /* get error-statistic from the ni82586 */
@@ -1171,7 +1175,7 @@
  */
 void sun3_82586_dump(struct net_device *dev,void *ptr)
 {
-	struct priv *p = (struct priv *) dev->priv;
+	struct priv *p = netdev_priv(dev);
 	struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
 	int i;
 
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index 359452a..4bb8f72 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -303,7 +303,6 @@
 	static int 		did_version;
 	volatile unsigned short *ioaddr_probe;
 	unsigned short tmp1, tmp2;
-	DECLARE_MAC_BUF(mac);
 
 #ifdef CONFIG_SUN3
 	ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE);
@@ -379,7 +378,7 @@
 	MEM->init.hwaddr[4] = dev->dev_addr[5];
 	MEM->init.hwaddr[5] = dev->dev_addr[4];
 
-	printk("%s\n", print_mac(mac, dev->dev_addr));
+	printk("%pM\n", dev->dev_addr);
 
 	MEM->init.mode = 0x0000;
 	MEM->init.filter[0] = 0x00000000;
@@ -824,12 +823,10 @@
 #if 0
 				if (lance_debug >= 3) {
 					u_char *data = PKTBUF_ADDR(head);
-					DECLARE_MAC_BUF(mac);
-					DECLARE_MAC_BUF(mac2)
 					printk("%s: RX pkt %d type 0x%04x"
-					       " from %s to %s",
+					       " from %pM to %pM",
 					       dev->name, lp->new_tx, ((u_short *)data)[6],
-					       print_mac(mac, &data[6]), print_mac(mac2, data));
+					       &data[6], data);
 
 					printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
 					       "len %d at %08x\n",
@@ -852,7 +849,6 @@
 
 				skb->protocol = eth_type_trans( skb, dev );
 				netif_rx( skb );
-				dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += pkt_len;
 			}
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 018d0fc..7f69c7f 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -878,7 +878,6 @@
 		/* No checksums done by the BigMAC ;-( */
 		skb->protocol = eth_type_trans(skb, bp->dev);
 		netif_rx(skb);
-		bp->dev->last_rx = jiffies;
 		bp->enet_stats.rx_packets++;
 		bp->enet_stats.rx_bytes += len;
 	next:
@@ -917,7 +916,7 @@
 
 static int bigmac_open(struct net_device *dev)
 {
-	struct bigmac *bp = (struct bigmac *) dev->priv;
+	struct bigmac *bp = netdev_priv(dev);
 	int ret;
 
 	ret = request_irq(dev->irq, &bigmac_interrupt, IRQF_SHARED, dev->name, bp);
@@ -934,7 +933,7 @@
 
 static int bigmac_close(struct net_device *dev)
 {
-	struct bigmac *bp = (struct bigmac *) dev->priv;
+	struct bigmac *bp = netdev_priv(dev);
 
 	del_timer(&bp->bigmac_timer);
 	bp->timer_state = asleep;
@@ -948,7 +947,7 @@
 
 static void bigmac_tx_timeout(struct net_device *dev)
 {
-	struct bigmac *bp = (struct bigmac *) dev->priv;
+	struct bigmac *bp = netdev_priv(dev);
 
 	bigmac_init_hw(bp, 0);
 	netif_wake_queue(dev);
@@ -957,7 +956,7 @@
 /* Put a packet on the wire. */
 static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct bigmac *bp = (struct bigmac *) dev->priv;
+	struct bigmac *bp = netdev_priv(dev);
 	int len, entry;
 	u32 mapping;
 
@@ -990,7 +989,7 @@
 
 static struct net_device_stats *bigmac_get_stats(struct net_device *dev)
 {
-	struct bigmac *bp = (struct bigmac *) dev->priv;
+	struct bigmac *bp = netdev_priv(dev);
 
 	bigmac_get_counters(bp, bp->bregs);
 	return &bp->enet_stats;
@@ -998,7 +997,7 @@
 
 static void bigmac_set_multicast(struct net_device *dev)
 {
-	struct bigmac *bp = (struct bigmac *) dev->priv;
+	struct bigmac *bp = netdev_priv(dev);
 	void __iomem *bregs = bp->bregs;
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
@@ -1061,7 +1060,7 @@
 
 static u32 bigmac_get_link(struct net_device *dev)
 {
-	struct bigmac *bp = dev->priv;
+	struct bigmac *bp = netdev_priv(dev);
 
 	spin_lock_irq(&bp->lock);
 	bp->sw_bmsr = bigmac_tcvr_read(bp, bp->tregs, BIGMAC_BMSR);
@@ -1081,7 +1080,6 @@
 	static int version_printed;
 	struct net_device *dev;
 	u8 bsizes, bsizes_more;
-	DECLARE_MAC_BUF(mac);
 	struct bigmac *bp;
 	int i;
 
@@ -1212,8 +1210,8 @@
 
 	dev_set_drvdata(&bp->bigmac_op->dev, bp);
 
-	printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %pM\n",
+	       dev->name, dev->dev_addr);
 
 	return 0;
 
@@ -1235,7 +1233,7 @@
 				  bp->bmac_block,
 				  bp->bblock_dvma);
 
-	/* This also frees the co-located 'dev->priv' */
+	/* This also frees the co-located private data */
 	free_netdev(dev);
 	return -ENODEV;
 }
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index f860ea1..698893b 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -468,7 +468,6 @@
 	int bar = 1;
 #endif
 	int phy, phy_end, phy_idx = 0;
-	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -547,9 +546,9 @@
 	if (i)
 		goto err_out_unmap_rx;
 
-	printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+	printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n",
 	       dev->name, pci_id_tbl[chip_idx].name, ioaddr,
-	       print_mac(mac, dev->dev_addr), irq);
+	       dev->dev_addr, irq);
 
 	np->phys[0] = 1;		/* Default setting */
 	np->mii_preamble_required++;
@@ -1351,7 +1350,6 @@
 			skb->protocol = eth_type_trans(skb, dev);
 			/* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 		}
 		entry = (entry + 1) % RX_RING_SIZE;
 		received++;
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index fed7eba..8a74604 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -164,7 +164,7 @@
 
 static inline int _phy_read(struct net_device *dev, int mii_id, int reg)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	return __phy_read(gp, mii_id, reg);
 }
 
@@ -197,7 +197,7 @@
 
 static inline void _phy_write(struct net_device *dev, int mii_id, int reg, int val)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	__phy_write(gp, mii_id, reg, val & 0xffff);
 }
 
@@ -863,7 +863,6 @@
 
 		gp->net_stats.rx_packets++;
 		gp->net_stats.rx_bytes += len;
-		gp->dev->last_rx = jiffies;
 
 	next:
 		entry = NEXT_RX(entry);
@@ -922,7 +921,7 @@
 		gp->status = readl(gp->regs + GREG_STAT);
 	} while (gp->status & GREG_STAT_NAPI);
 
-	__netif_rx_complete(dev, napi);
+	__netif_rx_complete(napi);
 	gem_enable_ints(gp);
 
 	spin_unlock_irqrestore(&gp->lock, flags);
@@ -933,7 +932,7 @@
 static irqreturn_t gem_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	unsigned long flags;
 
 	/* Swallow interrupts when shutting the chip down, though
@@ -945,7 +944,7 @@
 
 	spin_lock_irqsave(&gp->lock, flags);
 
-	if (netif_rx_schedule_prep(dev, &gp->napi)) {
+	if (netif_rx_schedule_prep(&gp->napi)) {
 		u32 gem_status = readl(gp->regs + GREG_STAT);
 
 		if (gem_status == 0) {
@@ -955,7 +954,7 @@
 		}
 		gp->status = gem_status;
 		gem_disable_ints(gp);
-		__netif_rx_schedule(dev, &gp->napi);
+		__netif_rx_schedule(&gp->napi);
 	}
 
 	spin_unlock_irqrestore(&gp->lock, flags);
@@ -979,7 +978,7 @@
 
 static void gem_tx_timeout(struct net_device *dev)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 
 	printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 	if (!gp->running) {
@@ -1018,7 +1017,7 @@
 
 static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	int entry;
 	u64 ctrl;
 	unsigned long flags;
@@ -2208,7 +2207,7 @@
 
 static int gem_do_start(struct net_device *dev)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&gp->lock, flags);
@@ -2255,7 +2254,7 @@
 
 static void gem_do_stop(struct net_device *dev, int wol)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&gp->lock, flags);
@@ -2330,7 +2329,7 @@
 
 static int gem_open(struct net_device *dev)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	int rc = 0;
 
 	mutex_lock(&gp->pm_mutex);
@@ -2349,7 +2348,7 @@
 
 static int gem_close(struct net_device *dev)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 
 	mutex_lock(&gp->pm_mutex);
 
@@ -2368,7 +2367,7 @@
 static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	unsigned long flags;
 
 	mutex_lock(&gp->pm_mutex);
@@ -2432,7 +2431,7 @@
 static int gem_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	unsigned long flags;
 
 	printk(KERN_INFO "%s: resuming\n", dev->name);
@@ -2506,7 +2505,7 @@
 
 static struct net_device_stats *gem_get_stats(struct net_device *dev)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	struct net_device_stats *stats = &gp->net_stats;
 
 	spin_lock_irq(&gp->lock);
@@ -2542,7 +2541,7 @@
 static int gem_set_mac_address(struct net_device *dev, void *addr)
 {
 	struct sockaddr *macaddr = (struct sockaddr *) addr;
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	unsigned char *e = &dev->dev_addr[0];
 
 	if (!is_valid_ether_addr(macaddr->sa_data))
@@ -2570,7 +2569,7 @@
 
 static void gem_set_multicast(struct net_device *dev)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	u32 rxcfg, rxcfg_new;
 	int limit = 10000;
 
@@ -2619,7 +2618,7 @@
 
 static int gem_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 
 	if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU)
 		return -EINVAL;
@@ -2650,7 +2649,7 @@
 
 static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
@@ -2659,7 +2658,7 @@
 
 static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 
 	if (gp->phy_type == phy_mii_mdio0 ||
 	    gp->phy_type == phy_mii_mdio1) {
@@ -2720,7 +2719,7 @@
 
 static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 
 	/* Verify the settings we care about. */
 	if (cmd->autoneg != AUTONEG_ENABLE &&
@@ -2751,7 +2750,7 @@
 
 static int gem_nway_reset(struct net_device *dev)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 
 	if (!gp->want_autoneg)
 		return -EINVAL;
@@ -2768,13 +2767,13 @@
 
 static u32 gem_get_msglevel(struct net_device *dev)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	return gp->msg_enable;
 }
 
 static void gem_set_msglevel(struct net_device *dev, u32 value)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	gp->msg_enable = value;
 }
 
@@ -2786,7 +2785,7 @@
 
 static void gem_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 
 	/* Add more when I understand how to program the chip */
 	if (gp->has_wol) {
@@ -2800,7 +2799,7 @@
 
 static int gem_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 
 	if (!gp->has_wol)
 		return -EOPNOTSUPP;
@@ -2822,7 +2821,7 @@
 
 static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = netdev_priv(dev);
 	struct mii_ioctl_data *data = if_mii(ifr);
 	int rc = -EOPNOTSUPP;
 	unsigned long flags;
@@ -2954,7 +2953,7 @@
 	struct net_device *dev = pci_get_drvdata(pdev);
 
 	if (dev) {
-		struct gem *gp = dev->priv;
+		struct gem *gp = netdev_priv(dev);
 
 		unregister_netdev(dev);
 
@@ -2998,7 +2997,6 @@
 	struct net_device *dev;
 	struct gem *gp;
 	int err, pci_using_dac;
-	DECLARE_MAC_BUF(mac);
 
 	if (gem_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -3058,7 +3056,7 @@
 	}
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	gp = dev->priv;
+	gp = netdev_priv(dev);
 
 	err = pci_request_regions(pdev, DRV_NAME);
 	if (err) {
@@ -3182,9 +3180,8 @@
 		goto err_out_free_consistent;
 	}
 
-	printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet "
-	       "%s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet %pM\n",
+	       dev->name, dev->dev_addr);
 
 	if (gp->phy_type == phy_mii_mdio0 ||
      	    gp->phy_type == phy_mii_mdio1)
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index f1ebeb5..b22d335 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2072,7 +2072,6 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
 
-		dev->last_rx = jiffies;
 		hp->net_stats.rx_packets++;
 		hp->net_stats.rx_bytes += len;
 	next:
@@ -2131,7 +2130,7 @@
 
 	for (i = 0; i < 4; i++) {
 		struct net_device *dev = qp->happy_meals[i];
-		struct happy_meal *hp  = dev->priv;
+		struct happy_meal *hp  = netdev_priv(dev);
 		u32 happy_status       = hme_read32(hp, hp->gregs + GREG_STAT);
 
 		HMD(("quattro_interrupt: status=%08x ", happy_status));
@@ -2176,7 +2175,7 @@
 
 static int happy_meal_open(struct net_device *dev)
 {
-	struct happy_meal *hp = dev->priv;
+	struct happy_meal *hp = netdev_priv(dev);
 	int res;
 
 	HMD(("happy_meal_open: "));
@@ -2208,7 +2207,7 @@
 
 static int happy_meal_close(struct net_device *dev)
 {
-	struct happy_meal *hp = dev->priv;
+	struct happy_meal *hp = netdev_priv(dev);
 
 	spin_lock_irq(&hp->happy_lock);
 	happy_meal_stop(hp, hp->gregs);
@@ -2237,7 +2236,7 @@
 
 static void happy_meal_tx_timeout(struct net_device *dev)
 {
-	struct happy_meal *hp = dev->priv;
+	struct happy_meal *hp = netdev_priv(dev);
 
 	printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 	tx_dump_log();
@@ -2255,7 +2254,7 @@
 
 static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct happy_meal *hp = dev->priv;
+	struct happy_meal *hp = netdev_priv(dev);
  	int entry;
  	u32 tx_flags;
 
@@ -2344,7 +2343,7 @@
 
 static struct net_device_stats *happy_meal_get_stats(struct net_device *dev)
 {
-	struct happy_meal *hp = dev->priv;
+	struct happy_meal *hp = netdev_priv(dev);
 
 	spin_lock_irq(&hp->happy_lock);
 	happy_meal_get_counters(hp, hp->bigmacregs);
@@ -2355,7 +2354,7 @@
 
 static void happy_meal_set_multicast(struct net_device *dev)
 {
-	struct happy_meal *hp = dev->priv;
+	struct happy_meal *hp = netdev_priv(dev);
 	void __iomem *bregs = hp->bigmacregs;
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
@@ -2401,7 +2400,7 @@
 /* Ethtool support... */
 static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct happy_meal *hp = dev->priv;
+	struct happy_meal *hp = netdev_priv(dev);
 
 	cmd->supported =
 		(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
@@ -2446,7 +2445,7 @@
 
 static int hme_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct happy_meal *hp = dev->priv;
+	struct happy_meal *hp = netdev_priv(dev);
 
 	/* Verify the settings we care about. */
 	if (cmd->autoneg != AUTONEG_ENABLE &&
@@ -2470,7 +2469,7 @@
 
 static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct happy_meal *hp = dev->priv;
+	struct happy_meal *hp = netdev_priv(dev);
 
 	strcpy(info->driver, "sunhme");
 	strcpy(info->version, "2.02");
@@ -2492,7 +2491,7 @@
 
 static u32 hme_get_link(struct net_device *dev)
 {
-	struct happy_meal *hp = dev->priv;
+	struct happy_meal *hp = netdev_priv(dev);
 
 	spin_lock_irq(&hp->happy_lock);
 	hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR);
@@ -2617,7 +2616,6 @@
 	struct net_device *dev;
 	int i, qfe_slot = -1;
 	int err = -ENODEV;
-	DECLARE_MAC_BUF(mac);
 
 	if (is_qfe) {
 		qp = quattro_sbus_find(op);
@@ -2797,7 +2795,7 @@
 		printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
 		       dev->name);
 
-	printk("%s\n", print_mac(mac, dev->dev_addr));
+	printk("%pM\n", dev->dev_addr);
 
 	return 0;
 
@@ -2932,7 +2930,6 @@
 	int i, qfe_slot = -1;
 	char prom_name[64];
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	/* Now make sure pci_dev cookie is there. */
 #ifdef CONFIG_SPARC
@@ -2973,7 +2970,7 @@
 
 	dev->base_addr = (long) pdev;
 
-	hp = (struct happy_meal *)dev->priv;
+	hp = netdev_priv(dev);
 	memset(hp, 0, sizeof(*hp));
 
 	hp->happy_dev = pdev;
@@ -3141,7 +3138,7 @@
 		printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
 		       dev->name);
 
-	printk("%s\n", print_mac(mac, dev->dev_addr));
+	printk("%pM\n", dev->dev_addr);
 
 	return 0;
 
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 704301a..2813732 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -555,7 +555,6 @@
 					 len);
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 		}
 
@@ -726,7 +725,6 @@
 			lance_piocopy_to_skb(skb, &(ib->rx_buf[entry][0]), len);
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 		}
 
@@ -1321,7 +1319,6 @@
 	static unsigned version_printed;
 	struct lance_private *lp;
 	struct net_device *dev;
-	DECLARE_MAC_BUF(mac);
 	int    i;
 
 	dev = alloc_etherdev(sizeof(struct lance_private) + 8);
@@ -1491,8 +1488,8 @@
 
 	dev_set_drvdata(&op->dev, lp);
 
-	printk(KERN_INFO "%s: LANCE %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: LANCE %pM\n",
+	       dev->name, dev->dev_addr);
 
 	return 0;
 
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index f636447..6e8f377 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -446,7 +446,6 @@
 						 len);
 				skb->protocol = eth_type_trans(skb, qep->dev);
 				netif_rx(skb);
-				qep->dev->last_rx = jiffies;
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += len;
 			}
@@ -513,7 +512,7 @@
 
 static int qe_open(struct net_device *dev)
 {
-	struct sunqe *qep = (struct sunqe *) dev->priv;
+	struct sunqe *qep = netdev_priv(dev);
 
 	qep->mconfig = (MREGS_MCONFIG_TXENAB |
 			MREGS_MCONFIG_RXENAB |
@@ -523,7 +522,7 @@
 
 static int qe_close(struct net_device *dev)
 {
-	struct sunqe *qep = (struct sunqe *) dev->priv;
+	struct sunqe *qep = netdev_priv(dev);
 
 	qe_stop(qep);
 	return 0;
@@ -549,7 +548,7 @@
 
 static void qe_tx_timeout(struct net_device *dev)
 {
-	struct sunqe *qep = (struct sunqe *) dev->priv;
+	struct sunqe *qep = netdev_priv(dev);
 	int tx_full;
 
 	spin_lock_irq(&qep->lock);
@@ -575,7 +574,7 @@
 /* Get a packet queued to go onto the wire. */
 static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct sunqe *qep = (struct sunqe *) dev->priv;
+	struct sunqe *qep = netdev_priv(dev);
 	struct sunqe_buffers *qbufs = qep->buffers;
 	__u32 txbuf_dvma, qbufs_dvma = qep->buffers_dvma;
 	unsigned char *txbuf;
@@ -627,7 +626,7 @@
 
 static void qe_set_multicast(struct net_device *dev)
 {
-	struct sunqe *qep = (struct sunqe *) dev->priv;
+	struct sunqe *qep = netdev_priv(dev);
 	struct dev_mc_list *dmi = dev->mc_list;
 	u8 new_mconfig = qep->mconfig;
 	char *addrs;
@@ -693,7 +692,7 @@
 static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	const struct linux_prom_registers *regs;
-	struct sunqe *qep = dev->priv;
+	struct sunqe *qep = netdev_priv(dev);
 	struct of_device *op;
 
 	strcpy(info->driver, "sunqe");
@@ -708,7 +707,7 @@
 
 static u32 qe_get_link(struct net_device *dev)
 {
-	struct sunqe *qep = dev->priv;
+	struct sunqe *qep = netdev_priv(dev);
 	void __iomem *mregs = qep->mregs;
 	u8 phyconfig;
 
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index a720065..233f1cd 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -1149,7 +1149,6 @@
 	struct vnet *vp;
 	const u64 *rmac;
 	int len, i, err, switch_port;
-	DECLARE_MAC_BUF(mac);
 
 	print_version();
 
@@ -1214,8 +1213,8 @@
 
 	dev_set_drvdata(&vdev->dev, port);
 
-	printk(KERN_INFO "%s: PORT ( remote-mac %s%s )\n",
-	       vp->dev->name, print_mac(mac, port->raddr),
+	printk(KERN_INFO "%s: PORT ( remote-mac %pM%s )\n",
+	       vp->dev->name, port->raddr,
 	       switch_port ? " switch-port" : "");
 
 	vio_port_up(&port->vio);
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index df20caf..bcd0e60 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -37,6 +37,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
+#include <linux/if_vlan.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/spinlock.h>
@@ -236,7 +237,7 @@
 #define Rx_Halted	       0x00008000 /* Rx Halted			     */
 #define Rx_Good		       0x00004000 /* Rx Good			     */
 #define Rx_RxPar	       0x00002000 /* Rx Parity Error		     */
-			    /* 0x00001000    not use			     */
+#define Rx_TypePkt	       0x00001000 /* Rx Type Packet		     */
 #define Rx_LongErr	       0x00000800 /* Rx Long Error		     */
 #define Rx_Over		       0x00000400 /* Rx Overflow		     */
 #define Rx_CRCErr	       0x00000200 /* Rx CRC Error		     */
@@ -244,8 +245,9 @@
 #define Rx_10Stat	       0x00000080 /* Rx 10Mbps Status		     */
 #define Rx_IntRx	       0x00000040 /* Rx Interrupt		     */
 #define Rx_CtlRecd	       0x00000020 /* Rx Control Receive		     */
+#define Rx_InLenErr	       0x00000010 /* Rx In Range Frame Length Error  */
 
-#define Rx_Stat_Mask	       0x0000EFC0 /* Rx All Status Mask		     */
+#define Rx_Stat_Mask	       0x0000FFF0 /* Rx All Status Mask		     */
 
 /* Int_En bit asign -------------------------------------------------------- */
 #define Int_NRAbtEn	       0x00000800 /* 1:Non-recoverable Abort Enable  */
@@ -340,7 +342,7 @@
 	Tx_En)	/* maybe  0x7b01 */
 #endif
 #define RX_CTL_CMD	(Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
-	| Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn)	/* maybe 0x6f01 */
+	| Rx_EnCRCErr | Rx_EnAlign | Rx_StripCRC | Rx_RxEn) /* maybe 0x6f11 */
 #define INT_EN_CMD  (Int_NRAbtEn | \
 	Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \
 	Int_SSysErrEn  | Int_RMasAbtEn | Int_RTargAbtEn | \
@@ -372,9 +374,11 @@
 #if RX_CTL_CMD & Rx_LongEn
 #define RX_BUF_SIZE	PAGE_SIZE
 #elif RX_CTL_CMD & Rx_StripCRC
-#define RX_BUF_SIZE	ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */
+#define RX_BUF_SIZE	\
+	L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + NET_IP_ALIGN)
 #else
-#define RX_BUF_SIZE	ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */
+#define RX_BUF_SIZE	\
+	L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN + NET_IP_ALIGN)
 #endif
 #endif /* TC35815_USE_PACKEDBUFFER */
 #define RX_FD_RESERVE	(2 / 2)	/* max 2 BD per RxFD */
@@ -865,7 +869,6 @@
 	struct net_device *dev;
 	struct tc35815_local *lp;
 	int rc;
-	DECLARE_MAC_BUF(mac);
 
 	static int printed_version;
 	if (!printed_version++) {
@@ -942,11 +945,11 @@
 		goto err_out;
 
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-	printk(KERN_INFO "%s: %s at 0x%lx, %s, IRQ %d\n",
+	printk(KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n",
 		dev->name,
 		chip_info[ent->driver_data].name,
 		dev->base_addr,
-		print_mac(mac, dev->dev_addr),
+		dev->dev_addr,
 		dev->irq);
 
 	rc = tc_mii_init(dev);
@@ -1288,12 +1291,9 @@
 
 static void print_eth(const u8 *add)
 {
-	DECLARE_MAC_BUF(mac);
-
 	printk(KERN_DEBUG "print_eth(%p)\n", add);
-	printk(KERN_DEBUG " %s =>", print_mac(mac, add + 6));
-	printk(KERN_CONT " %s : %02x%02x\n",
-		print_mac(mac, add), add[12], add[13]);
+	printk(KERN_DEBUG " %pM => %pM : %02x%02x\n",
+		add + 6, add, add[12], add[13]);
 }
 
 static int tc35815_tx_full(struct net_device *dev)
@@ -1609,8 +1609,8 @@
 	if (!(dmactl & DMA_IntMask)) {
 		/* disable interrupts */
 		tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
-		if (netif_rx_schedule_prep(dev, &lp->napi))
-			__netif_rx_schedule(dev, &lp->napi);
+		if (netif_rx_schedule_prep(&lp->napi))
+			__netif_rx_schedule(&lp->napi);
 		else {
 			printk(KERN_ERR "%s: interrupt taken in poll\n",
 			       dev->name);
@@ -1669,7 +1669,7 @@
 		struct RxFD *next_rfd;
 #endif
 #if (RX_CTL_CMD & Rx_StripCRC) == 0
-		pkt_len -= 4;
+		pkt_len -= ETH_FCS_LEN;
 #endif
 
 		if (netif_msg_rx_status(lp))
@@ -1688,14 +1688,14 @@
 #endif
 #ifdef TC35815_USE_PACKEDBUFFER
 			BUG_ON(bd_count > 2);
-			skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
+			skb = dev_alloc_skb(pkt_len + NET_IP_ALIGN);
 			if (skb == NULL) {
 				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
 				       dev->name);
 				dev->stats.rx_dropped++;
 				break;
 			}
-			skb_reserve(skb, 2);   /* 16 bit alignment */
+			skb_reserve(skb, NET_IP_ALIGN);
 
 			data = skb_put(skb, pkt_len);
 
@@ -1747,8 +1747,9 @@
 			pci_unmap_single(lp->pci_dev,
 					 lp->rx_skbs[cur_bd].skb_dma,
 					 RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-			if (!HAVE_DMA_RXALIGN(lp))
-				memmove(skb->data, skb->data - 2, pkt_len);
+			if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN)
+				memmove(skb->data, skb->data - NET_IP_ALIGN,
+					pkt_len);
 			data = skb_put(skb, pkt_len);
 #endif /* TC35815_USE_PACKEDBUFFER */
 			if (netif_msg_pktdata(lp))
@@ -1760,7 +1761,6 @@
 #else
 			netif_rx(skb);
 #endif
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += pkt_len;
 		} else {
@@ -1919,7 +1919,7 @@
 	spin_unlock(&lp->lock);
 
 	if (received < budget) {
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		/* enable interrupts */
 		tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
 	}
@@ -2153,13 +2153,12 @@
 	int cam_index = index * 6;
 	u32 cam_data;
 	u32 saved_addr;
-	DECLARE_MAC_BUF(mac);
 
 	saved_addr = tc_readl(&tr->CAM_Adr);
 
 	if (netif_msg_hw(lp))
-		printk(KERN_DEBUG "%s: CAM %d: %s\n",
-			dev->name, index, print_mac(mac, addr));
+		printk(KERN_DEBUG "%s: CAM %d: %pM\n",
+			dev->name, index, addr);
 	if (index & 1) {
 		/* read modify write */
 		tc_writel(cam_index - 2, &tr->CAM_Adr);
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 91f9054..a10a83a 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -251,7 +251,7 @@
 static irqreturn_t bdx_isr_napi(int irq, void *dev)
 {
 	struct net_device *ndev = dev;
-	struct bdx_priv *priv = ndev->priv;
+	struct bdx_priv *priv = netdev_priv(ndev);
 	u32 isr;
 
 	ENTER;
@@ -265,8 +265,8 @@
 		bdx_isr_extra(priv, isr);
 
 	if (isr & (IR_RX_DESC_0 | IR_TX_FREE_0)) {
-		if (likely(netif_rx_schedule_prep(ndev, &priv->napi))) {
-			__netif_rx_schedule(ndev, &priv->napi);
+		if (likely(netif_rx_schedule_prep(&priv->napi))) {
+			__netif_rx_schedule(&priv->napi);
 			RET(IRQ_HANDLED);
 		} else {
 			/* NOTE: we get here if intr has slipped into window
@@ -289,7 +289,6 @@
 static int bdx_poll(struct napi_struct *napi, int budget)
 {
 	struct bdx_priv *priv = container_of(napi, struct bdx_priv, napi);
-	struct net_device *dev = priv->ndev;
 	int work_done;
 
 	ENTER;
@@ -303,7 +302,7 @@
 		 * device lock and allow waiting tasks (eg rmmod) to advance) */
 		priv->napi_stop = 0;
 
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		bdx_enable_interrupts(priv);
 	}
 	return work_done;
@@ -559,7 +558,7 @@
 	struct bdx_priv *priv = NULL;
 
 	ENTER;
-	priv = ndev->priv;
+	priv = netdev_priv(ndev);
 
 	napi_disable(&priv->napi);
 
@@ -588,7 +587,7 @@
 	int rc;
 
 	ENTER;
-	priv = ndev->priv;
+	priv = netdev_priv(ndev);
 	bdx_reset(priv);
 	if (netif_running(ndev))
 		netif_stop_queue(priv->ndev);
@@ -633,7 +632,7 @@
 
 static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
 {
-	struct bdx_priv *priv = ndev->priv;
+	struct bdx_priv *priv = netdev_priv(ndev);
 	u32 data[3];
 	int error;
 
@@ -698,7 +697,7 @@
  */
 static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable)
 {
-	struct bdx_priv *priv = ndev->priv;
+	struct bdx_priv *priv = netdev_priv(ndev);
 	u32 reg, bit, val;
 
 	ENTER;
@@ -748,7 +747,7 @@
 static void
 bdx_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp)
 {
-	struct bdx_priv *priv = ndev->priv;
+	struct bdx_priv *priv = netdev_priv(ndev);
 
 	ENTER;
 	DBG("device='%s', group='%p'\n", ndev->name, grp);
@@ -787,7 +786,7 @@
 
 static void bdx_setmulti(struct net_device *ndev)
 {
-	struct bdx_priv *priv = ndev->priv;
+	struct bdx_priv *priv = netdev_priv(ndev);
 
 	u32 rxf_val =
 	    GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB | GMAC_RX_FILTER_OSEN;
@@ -847,7 +846,7 @@
 
 static int bdx_set_mac(struct net_device *ndev, void *p)
 {
-	struct bdx_priv *priv = ndev->priv;
+	struct bdx_priv *priv = netdev_priv(ndev);
 	struct sockaddr *addr = p;
 
 	ENTER;
@@ -929,7 +928,7 @@
 
 static struct net_device_stats *bdx_get_stats(struct net_device *ndev)
 {
-	struct bdx_priv *priv = ndev->priv;
+	struct bdx_priv *priv = netdev_priv(ndev);
 	struct net_device_stats *net_stat = &priv->net_stats;
 	return net_stat;
 }
@@ -1237,7 +1236,6 @@
 	ENTER;
 	max_done = budget;
 
-	priv->ndev->last_rx = jiffies;
 	f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_WR_PTR;
 
 	size = f->m.wptr - f->m.rptr;
@@ -1624,7 +1622,7 @@
  */
 static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev)
 {
-	struct bdx_priv *priv = ndev->priv;
+	struct bdx_priv *priv = netdev_priv(ndev);
 	struct txd_fifo *f = &priv->txd_fifo0;
 	int txd_checksum = 7;	/* full checksum */
 	int txd_lgsnd = 0;
@@ -1886,6 +1884,21 @@
 	RET();
 }
 
+static const struct net_device_ops bdx_netdev_ops = {
+	.ndo_open	 	= bdx_open,
+	.ndo_stop		= bdx_close,
+	.ndo_start_xmit		= bdx_tx_transmit,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= bdx_ioctl,
+	.ndo_set_multicast_list = bdx_setmulti,
+	.ndo_get_stats		= bdx_get_stats,
+	.ndo_change_mtu		= bdx_change_mtu,
+	.ndo_set_mac_address	= bdx_set_mac,
+	.ndo_vlan_rx_register	= bdx_vlan_rx_register,
+	.ndo_vlan_rx_add_vid	= bdx_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= bdx_vlan_rx_kill_vid,
+};
+
 /**
  * bdx_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -1995,18 +2008,8 @@
 			goto err_out_iomap;
 		}
 
-		ndev->open = bdx_open;
-		ndev->stop = bdx_close;
-		ndev->hard_start_xmit = bdx_tx_transmit;
-		ndev->do_ioctl = bdx_ioctl;
-		ndev->set_multicast_list = bdx_setmulti;
-		ndev->get_stats = bdx_get_stats;
-		ndev->change_mtu = bdx_change_mtu;
-		ndev->set_mac_address = bdx_set_mac;
+		ndev->netdev_ops = &bdx_netdev_ops;
 		ndev->tx_queue_len = BDX_NDEV_TXQ_LEN;
-		ndev->vlan_rx_register = bdx_vlan_rx_register;
-		ndev->vlan_rx_add_vid = bdx_vlan_rx_add_vid;
-		ndev->vlan_rx_kill_vid = bdx_vlan_rx_kill_vid;
 
 		bdx_ethtool_ops(ndev);	/* ethtool interface */
 
@@ -2027,7 +2030,7 @@
 			ndev->features |= NETIF_F_HIGHDMA;
 
 	/************** priv ****************/
-		priv = nic->priv[port] = ndev->priv;
+		priv = nic->priv[port] = netdev_priv(ndev);
 
 		memset(priv, 0, sizeof(struct bdx_priv));
 		priv->pBdxRegs = nic->regs + port * 0x8000;
@@ -2150,7 +2153,7 @@
 {
 	u32 rdintcm;
 	u32 tdintcm;
-	struct bdx_priv *priv = netdev->priv;
+	struct bdx_priv *priv = netdev_priv(netdev);
 
 	rdintcm = priv->rdintcm;
 	tdintcm = priv->tdintcm;
@@ -2181,7 +2184,7 @@
 static void
 bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
 {
-	struct bdx_priv *priv = netdev->priv;
+	struct bdx_priv *priv = netdev_priv(netdev);
 
 	strlcat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver));
 	strlcat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version));
@@ -2223,7 +2226,7 @@
 {
 	u32 rdintcm;
 	u32 tdintcm;
-	struct bdx_priv *priv = netdev->priv;
+	struct bdx_priv *priv = netdev_priv(netdev);
 
 	rdintcm = priv->rdintcm;
 	tdintcm = priv->tdintcm;
@@ -2252,7 +2255,7 @@
 {
 	u32 rdintcm;
 	u32 tdintcm;
-	struct bdx_priv *priv = netdev->priv;
+	struct bdx_priv *priv = netdev_priv(netdev);
 	int rx_coal;
 	int tx_coal;
 	int rx_max_coal;
@@ -2310,7 +2313,7 @@
 static void
 bdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
 {
-	struct bdx_priv *priv = netdev->priv;
+	struct bdx_priv *priv = netdev_priv(netdev);
 
 	/*max_pending - the maximum-sized FIFO we allow */
 	ring->rx_max_pending = bdx_rx_fifo_size_to_packets(3);
@@ -2327,7 +2330,7 @@
 static int
 bdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
 {
-	struct bdx_priv *priv = netdev->priv;
+	struct bdx_priv *priv = netdev_priv(netdev);
 	int rx_size = 0;
 	int tx_size = 0;
 
@@ -2388,7 +2391,7 @@
  */
 static int bdx_get_stats_count(struct net_device *netdev)
 {
-	struct bdx_priv *priv = netdev->priv;
+	struct bdx_priv *priv = netdev_priv(netdev);
 	BDX_ASSERT(ARRAY_SIZE(bdx_stat_names)
 		   != sizeof(struct bdx_stats) / sizeof(u64));
 	return ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names)	: 0);
@@ -2403,7 +2406,7 @@
 static void bdx_get_ethtool_stats(struct net_device *netdev,
 				  struct ethtool_stats *stats, u64 *data)
 {
-	struct bdx_priv *priv = netdev->priv;
+	struct bdx_priv *priv = netdev_priv(netdev);
 
 	if (priv->stats_flag) {
 
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index eb9f8f3..04ae1e8 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -54,20 +54,21 @@
 #include <asm/prom.h>
 #endif
 
+#define BAR_0	0
+#define BAR_2	2
+
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define TG3_VLAN_TAG_USED 1
 #else
 #define TG3_VLAN_TAG_USED 0
 #endif
 
-#define TG3_TSO_SUPPORT	1
-
 #include "tg3.h"
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.94"
-#define DRV_MODULE_RELDATE	"August 14, 2008"
+#define DRV_MODULE_VERSION	"3.97"
+#define DRV_MODULE_RELDATE	"December 10, 2008"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -129,6 +130,8 @@
 /* minimum number of free TX descriptors required to wake up TX process */
 #define TG3_TX_WAKEUP_THRESH(tp)		((tp)->tx_pending / 4)
 
+#define TG3_RAW_IP_ALIGN 2
+
 /* number of ETHTOOL_GSTATS u64's */
 #define TG3_NUM_STATS		(sizeof(struct tg3_ethtool_stats)/sizeof(u64))
 
@@ -205,7 +208,13 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761S)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761SE)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57760)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57720)},
 	{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
 	{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -872,13 +881,48 @@
 	return 0;
 }
 
-static void tg3_mdio_config(struct tg3 *tp)
+static void tg3_mdio_config_5785(struct tg3 *tp)
 {
 	u32 val;
+	struct phy_device *phydev;
 
-	if (tp->mdio_bus->phy_map[PHY_ADDR]->interface !=
-	    PHY_INTERFACE_MODE_RGMII)
+	phydev = tp->mdio_bus->phy_map[PHY_ADDR];
+	switch (phydev->drv->phy_id & phydev->drv->phy_id_mask) {
+	case TG3_PHY_ID_BCM50610:
+		val = MAC_PHYCFG2_50610_LED_MODES;
+		break;
+	case TG3_PHY_ID_BCMAC131:
+		val = MAC_PHYCFG2_AC131_LED_MODES;
+		break;
+	case TG3_PHY_ID_RTL8211C:
+		val = MAC_PHYCFG2_RTL8211C_LED_MODES;
+		break;
+	case TG3_PHY_ID_RTL8201E:
+		val = MAC_PHYCFG2_RTL8201E_LED_MODES;
+		break;
+	default:
 		return;
+	}
+
+	if (phydev->interface != PHY_INTERFACE_MODE_RGMII) {
+		tw32(MAC_PHYCFG2, val);
+
+		val = tr32(MAC_PHYCFG1);
+		val &= ~MAC_PHYCFG1_RGMII_INT;
+		tw32(MAC_PHYCFG1, val);
+
+		return;
+	}
+
+	if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE))
+		val |= MAC_PHYCFG2_EMODE_MASK_MASK |
+		       MAC_PHYCFG2_FMODE_MASK_MASK |
+		       MAC_PHYCFG2_GMODE_MASK_MASK |
+		       MAC_PHYCFG2_ACT_MASK_MASK   |
+		       MAC_PHYCFG2_QUAL_MASK_MASK |
+		       MAC_PHYCFG2_INBAND_ENABLE;
+
+	tw32(MAC_PHYCFG2, val);
 
 	val = tr32(MAC_PHYCFG1) & ~(MAC_PHYCFG1_RGMII_EXT_RX_DEC |
 				    MAC_PHYCFG1_RGMII_SND_STAT_EN);
@@ -890,11 +934,6 @@
 	}
 	tw32(MAC_PHYCFG1, val | MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV);
 
-	val = tr32(MAC_PHYCFG2) & ~(MAC_PHYCFG2_INBAND_ENABLE);
-	if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE))
-		val |= MAC_PHYCFG2_INBAND_ENABLE;
-	tw32(MAC_PHYCFG2, val);
-
 	val = tr32(MAC_EXT_RGMII_MODE);
 	val &= ~(MAC_RGMII_MODE_RX_INT_B |
 		 MAC_RGMII_MODE_RX_QUALITY |
@@ -903,7 +942,7 @@
 		 MAC_RGMII_MODE_TX_ENABLE |
 		 MAC_RGMII_MODE_TX_LOWPWR |
 		 MAC_RGMII_MODE_TX_RESET);
-	if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) {
+	if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) {
 		if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
 			val |= MAC_RGMII_MODE_RX_INT_B |
 			       MAC_RGMII_MODE_RX_QUALITY |
@@ -929,8 +968,9 @@
 	tw32_f(MAC_MI_MODE, tp->mi_mode);
 	udelay(80);
 
-	if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED)
-		tg3_mdio_config(tp);
+	if ((tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+		tg3_mdio_config_5785(tp);
 }
 
 static void tg3_mdio_stop(struct tg3 *tp)
@@ -984,29 +1024,44 @@
 	if (i) {
 		printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n",
 			tp->dev->name, i);
+		mdiobus_free(tp->mdio_bus);
 		return i;
 	}
 
-	tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED;
-
 	phydev = tp->mdio_bus->phy_map[PHY_ADDR];
 
-	switch (phydev->phy_id) {
+	if (!phydev || !phydev->drv) {
+		printk(KERN_WARNING "%s: No PHY devices\n", tp->dev->name);
+		mdiobus_unregister(tp->mdio_bus);
+		mdiobus_free(tp->mdio_bus);
+		return -ENODEV;
+	}
+
+	switch (phydev->drv->phy_id & phydev->drv->phy_id_mask) {
+	case TG3_PHY_ID_BCM57780:
+		phydev->interface = PHY_INTERFACE_MODE_GMII;
+		break;
 	case TG3_PHY_ID_BCM50610:
-		phydev->interface = PHY_INTERFACE_MODE_RGMII;
 		if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)
 			phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE;
 		if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
 			phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE;
 		if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
 			phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE;
+		/* fallthru */
+	case TG3_PHY_ID_RTL8211C:
+		phydev->interface = PHY_INTERFACE_MODE_RGMII;
 		break;
+	case TG3_PHY_ID_RTL8201E:
 	case TG3_PHY_ID_BCMAC131:
 		phydev->interface = PHY_INTERFACE_MODE_MII;
 		break;
 	}
 
-	tg3_mdio_config(tp);
+	tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+		tg3_mdio_config_5785(tp);
 
 	return 0;
 }
@@ -1130,9 +1185,9 @@
 		printk(KERN_INFO PFX
 		       "%s: Flow control is %s for TX and %s for RX.\n",
 		       tp->dev->name,
-		       (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ?
+		       (tp->link_config.active_flowctrl & FLOW_CTRL_TX) ?
 		       "on" : "off",
-		       (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
+		       (tp->link_config.active_flowctrl & FLOW_CTRL_RX) ?
 		       "on" : "off");
 		tg3_ump_link_report(tp);
 	}
@@ -1142,11 +1197,11 @@
 {
 	u16 miireg;
 
-	if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+	if ((flow_ctrl & FLOW_CTRL_TX) && (flow_ctrl & FLOW_CTRL_RX))
 		miireg = ADVERTISE_PAUSE_CAP;
-	else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+	else if (flow_ctrl & FLOW_CTRL_TX)
 		miireg = ADVERTISE_PAUSE_ASYM;
-	else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+	else if (flow_ctrl & FLOW_CTRL_RX)
 		miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
 	else
 		miireg = 0;
@@ -1158,11 +1213,11 @@
 {
 	u16 miireg;
 
-	if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+	if ((flow_ctrl & FLOW_CTRL_TX) && (flow_ctrl & FLOW_CTRL_RX))
 		miireg = ADVERTISE_1000XPAUSE;
-	else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+	else if (flow_ctrl & FLOW_CTRL_TX)
 		miireg = ADVERTISE_1000XPSE_ASYM;
-	else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+	else if (flow_ctrl & FLOW_CTRL_RX)
 		miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
 	else
 		miireg = 0;
@@ -1170,28 +1225,6 @@
 	return miireg;
 }
 
-static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
-{
-	u8 cap = 0;
-
-	if (lcladv & ADVERTISE_PAUSE_CAP) {
-		if (lcladv & ADVERTISE_PAUSE_ASYM) {
-			if (rmtadv & LPA_PAUSE_CAP)
-				cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
-			else if (rmtadv & LPA_PAUSE_ASYM)
-				cap = TG3_FLOW_CTRL_RX;
-		} else {
-			if (rmtadv & LPA_PAUSE_CAP)
-				cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
-		}
-	} else if (lcladv & ADVERTISE_PAUSE_ASYM) {
-		if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
-			cap = TG3_FLOW_CTRL_TX;
-	}
-
-	return cap;
-}
-
 static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
 {
 	u8 cap = 0;
@@ -1199,16 +1232,16 @@
 	if (lcladv & ADVERTISE_1000XPAUSE) {
 		if (lcladv & ADVERTISE_1000XPSE_ASYM) {
 			if (rmtadv & LPA_1000XPAUSE)
-				cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+				cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
 			else if (rmtadv & LPA_1000XPAUSE_ASYM)
-				cap = TG3_FLOW_CTRL_RX;
+				cap = FLOW_CTRL_RX;
 		} else {
 			if (rmtadv & LPA_1000XPAUSE)
-				cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+				cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
 		}
 	} else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
 		if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
-			cap = TG3_FLOW_CTRL_TX;
+			cap = FLOW_CTRL_TX;
 	}
 
 	return cap;
@@ -1231,13 +1264,13 @@
 		if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
 			flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv);
 		else
-			flowctrl = tg3_resolve_flowctrl_1000T(lcladv, rmtadv);
+			flowctrl = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
 	} else
 		flowctrl = tp->link_config.flowctrl;
 
 	tp->link_config.active_flowctrl = flowctrl;
 
-	if (flowctrl & TG3_FLOW_CTRL_RX)
+	if (flowctrl & FLOW_CTRL_RX)
 		tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
 	else
 		tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
@@ -1245,7 +1278,7 @@
 	if (old_rx_mode != tp->rx_mode)
 		tw32_f(MAC_RX_MODE, tp->rx_mode);
 
-	if (flowctrl & TG3_FLOW_CTRL_TX)
+	if (flowctrl & FLOW_CTRL_TX)
 		tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
 	else
 		tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
@@ -1299,6 +1332,15 @@
 		udelay(40);
 	}
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+		if (phydev->speed == SPEED_10)
+			tw32(MAC_MI_STAT,
+			     MAC_MI_STAT_10MBPS_MODE |
+			     MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
+		else
+			tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
+	}
+
 	if (phydev->speed == SPEED_1000 && phydev->duplex == DUPLEX_HALF)
 		tw32(MAC_TX_LENGTHS,
 		     ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
@@ -1339,26 +1381,38 @@
 	phydev = tp->mdio_bus->phy_map[PHY_ADDR];
 
 	/* Attach the MAC to the PHY. */
-	phydev = phy_connect(tp->dev, phydev->dev.bus_id, tg3_adjust_link,
+	phydev = phy_connect(tp->dev, dev_name(&phydev->dev), tg3_adjust_link,
 			     phydev->dev_flags, phydev->interface);
 	if (IS_ERR(phydev)) {
 		printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name);
 		return PTR_ERR(phydev);
 	}
 
+	/* Mask with MAC supported features. */
+	switch (phydev->interface) {
+	case PHY_INTERFACE_MODE_GMII:
+	case PHY_INTERFACE_MODE_RGMII:
+		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
+			phydev->supported &= (PHY_GBIT_FEATURES |
+					      SUPPORTED_Pause |
+					      SUPPORTED_Asym_Pause);
+			break;
+		}
+		/* fallthru */
+	case PHY_INTERFACE_MODE_MII:
+		phydev->supported &= (PHY_BASIC_FEATURES |
+				      SUPPORTED_Pause |
+				      SUPPORTED_Asym_Pause);
+		break;
+	default:
+		phy_disconnect(tp->mdio_bus->phy_map[PHY_ADDR]);
+		return -EINVAL;
+	}
+
 	tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED;
 
-	/* Mask with MAC supported features. */
-	phydev->supported &= (PHY_GBIT_FEATURES |
-			      SUPPORTED_Pause |
-			      SUPPORTED_Asym_Pause);
-
 	phydev->advertising = phydev->supported;
 
-	printk(KERN_INFO
-	       "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
-	       tp->dev->name, phydev->drv->name, phydev->dev.bus_id);
-
 	return 0;
 }
 
@@ -1406,6 +1460,34 @@
 	tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
 }
 
+static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable)
+{
+	u32 reg;
+
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+		return;
+
+	reg = MII_TG3_MISC_SHDW_WREN |
+	      MII_TG3_MISC_SHDW_SCR5_SEL |
+	      MII_TG3_MISC_SHDW_SCR5_LPED |
+	      MII_TG3_MISC_SHDW_SCR5_DLPTLM |
+	      MII_TG3_MISC_SHDW_SCR5_SDTL |
+	      MII_TG3_MISC_SHDW_SCR5_C125OE;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 || !enable)
+		reg |= MII_TG3_MISC_SHDW_SCR5_DLLAPD;
+
+	tg3_writephy(tp, MII_TG3_MISC_SHDW, reg);
+
+
+	reg = MII_TG3_MISC_SHDW_WREN |
+	      MII_TG3_MISC_SHDW_APD_SEL |
+	      MII_TG3_MISC_SHDW_APD_WKTM_84MS;
+	if (enable)
+		reg |= MII_TG3_MISC_SHDW_APD_ENABLE;
+
+	tg3_writephy(tp, MII_TG3_MISC_SHDW, reg);
+}
+
 static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
 {
 	u32 phy;
@@ -1737,7 +1819,8 @@
 		tw32(TG3_CPMU_CTRL, cpmuctrl);
 	}
 
-	if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
+	    GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) {
 		u32 val;
 
 		val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
@@ -1747,16 +1830,15 @@
 			udelay(40);
 			tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val);
 		}
-
-		/* Disable GPHY autopowerdown. */
-		tg3_writephy(tp, MII_TG3_MISC_SHDW,
-			     MII_TG3_MISC_SHDW_WREN |
-			     MII_TG3_MISC_SHDW_APD_SEL |
-			     MII_TG3_MISC_SHDW_APD_WKTM_84MS);
 	}
 
 	tg3_phy_apply_otp(tp);
 
+	if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD)
+		tg3_phy_toggle_apd(tp, true);
+	else
+		tg3_phy_toggle_apd(tp, false);
+
 out:
 	if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) {
 		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
@@ -1961,7 +2043,7 @@
 static int tg3_nvram_lock(struct tg3 *);
 static void tg3_nvram_unlock(struct tg3 *);
 
-static void tg3_power_down_phy(struct tg3 *tp)
+static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
 {
 	u32 val;
 
@@ -1984,10 +2066,15 @@
 		tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
 		udelay(40);
 		return;
-	} else if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
+	} else if (do_low_power) {
 		tg3_writephy(tp, MII_TG3_EXT_CTRL,
 			     MII_TG3_EXT_CTRL_FORCE_LED_OFF);
-		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
+
+		tg3_writephy(tp, MII_TG3_AUX_CTRL,
+			     MII_TG3_AUXCTL_SHDWSEL_PWRCTL |
+			     MII_TG3_AUXCTL_PCTL_100TX_LPWR |
+			     MII_TG3_AUXCTL_PCTL_SPR_ISOLATE |
+			     MII_TG3_AUXCTL_PCTL_VREG_11V);
 	}
 
 	/* The PHY should not be powered down on some chips because
@@ -1999,7 +2086,8 @@
 	     (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
 		return;
 
-	if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
+	    GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) {
 		val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
 		val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
 		val |= CPMU_LSPD_1000MB_MACCLK_12_5;
@@ -2009,9 +2097,47 @@
 	tg3_writephy(tp, MII_BMCR, BMCR_PDOWN);
 }
 
+/* tp->lock is held. */
+static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1)
+{
+	u32 addr_high, addr_low;
+	int i;
+
+	addr_high = ((tp->dev->dev_addr[0] << 8) |
+		     tp->dev->dev_addr[1]);
+	addr_low = ((tp->dev->dev_addr[2] << 24) |
+		    (tp->dev->dev_addr[3] << 16) |
+		    (tp->dev->dev_addr[4] <<  8) |
+		    (tp->dev->dev_addr[5] <<  0));
+	for (i = 0; i < 4; i++) {
+		if (i == 1 && skip_mac_1)
+			continue;
+		tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high);
+		tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+		for (i = 0; i < 12; i++) {
+			tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
+			tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
+		}
+	}
+
+	addr_high = (tp->dev->dev_addr[0] +
+		     tp->dev->dev_addr[1] +
+		     tp->dev->dev_addr[2] +
+		     tp->dev->dev_addr[3] +
+		     tp->dev->dev_addr[4] +
+		     tp->dev->dev_addr[5]) &
+		TX_BACKOFF_SEED_MASK;
+	tw32(MAC_TX_BACKOFF_SEED, addr_high);
+}
+
 static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
 {
 	u32 misc_host_ctrl;
+	bool device_should_wake, do_low_power;
 
 	/* Make sure register accesses (indirect or otherwise)
 	 * will function correctly.
@@ -2041,15 +2167,34 @@
 			tp->dev->name, state);
 		return -EINVAL;
 	}
+
+	/* Restore the CLKREQ setting. */
+	if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) {
+		u16 lnkctl;
+
+		pci_read_config_word(tp->pdev,
+				     tp->pcie_cap + PCI_EXP_LNKCTL,
+				     &lnkctl);
+		lnkctl |= PCI_EXP_LNKCTL_CLKREQ_EN;
+		pci_write_config_word(tp->pdev,
+				      tp->pcie_cap + PCI_EXP_LNKCTL,
+				      lnkctl);
+	}
+
 	misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL);
 	tw32(TG3PCI_MISC_HOST_CTRL,
 	     misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT);
 
+	device_should_wake = pci_pme_capable(tp->pdev, state) &&
+			     device_may_wakeup(&tp->pdev->dev) &&
+			     (tp->tg3_flags & TG3_FLAG_WOL_ENABLE);
+
 	if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+		do_low_power = false;
 		if ((tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) &&
 		    !tp->link_config.phy_is_low_power) {
 			struct phy_device *phydev;
-			u32 advertising;
+			u32 phyid, advertising;
 
 			phydev = tp->mdio_bus->phy_map[PHY_ADDR];
 
@@ -2066,7 +2211,7 @@
 				      ADVERTISED_10baseT_Half;
 
 			if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
-			    (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) {
+			    device_should_wake) {
 				if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB)
 					advertising |=
 						ADVERTISED_100baseT_Half |
@@ -2079,8 +2224,19 @@
 			phydev->advertising = advertising;
 
 			phy_start_aneg(phydev);
+
+			phyid = phydev->drv->phy_id & phydev->drv->phy_id_mask;
+			if (phyid != TG3_PHY_ID_BCMAC131) {
+				phyid &= TG3_PHY_OUI_MASK;
+				if (phyid == TG3_PHY_OUI_1 &&
+				    phyid == TG3_PHY_OUI_2 &&
+				    phyid == TG3_PHY_OUI_3)
+					do_low_power = true;
+			}
 		}
 	} else {
+		do_low_power = true;
+
 		if (tp->link_config.phy_is_low_power == 0) {
 			tp->link_config.phy_is_low_power = 1;
 			tp->link_config.orig_speed = tp->link_config.speed;
@@ -2096,6 +2252,8 @@
 		}
 	}
 
+	__tg3_set_mac_addr(tp, 0);
+
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
 		u32 val;
 
@@ -2118,11 +2276,11 @@
 						     WOL_DRV_WOL |
 						     WOL_SET_MAGIC_PKT);
 
-	if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) {
+	if (device_should_wake) {
 		u32 mac_mode;
 
 		if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
-			if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
+			if (do_low_power) {
 				tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
 				udelay(40);
 			}
@@ -2150,9 +2308,12 @@
 		if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
 			tw32(MAC_LED_CTRL, tp->led_ctrl);
 
-		if (pci_pme_capable(tp->pdev, state) &&
-		     (tp->tg3_flags & TG3_FLAG_WOL_ENABLE))
-			mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE;
+		mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE;
+		if (((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
+		    !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) &&
+		    ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+		     (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)))
+			mac_mode |= MAC_MODE_KEEP_FRAME_IN_WOL;
 
 		if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
 			mac_mode |= tp->mac_mode &
@@ -2224,10 +2385,9 @@
 		}
 	}
 
-	if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
-	    !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
-	    !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
-		tg3_power_down_phy(tp);
+	if (!(device_should_wake) &&
+	    !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+		tg3_power_down_phy(tp, do_low_power);
 
 	tg3_frob_aux_power(tp);
 
@@ -2250,7 +2410,7 @@
 
 	tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
 
-	if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
+	if (device_should_wake)
 		pci_enable_wake(tp->pdev, state, true);
 
 	/* Finally, set the new power state. */
@@ -2789,6 +2949,24 @@
 			      NIC_SRAM_FIRMWARE_MBOX_MAGIC2);
 	}
 
+	/* Prevent send BD corruption. */
+	if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) {
+		u16 oldlnkctl, newlnkctl;
+
+		pci_read_config_word(tp->pdev,
+				     tp->pcie_cap + PCI_EXP_LNKCTL,
+				     &oldlnkctl);
+		if (tp->link_config.active_speed == SPEED_100 ||
+		    tp->link_config.active_speed == SPEED_10)
+			newlnkctl = oldlnkctl & ~PCI_EXP_LNKCTL_CLKREQ_EN;
+		else
+			newlnkctl = oldlnkctl | PCI_EXP_LNKCTL_CLKREQ_EN;
+		if (newlnkctl != oldlnkctl)
+			pci_write_config_word(tp->pdev,
+					      tp->pcie_cap + PCI_EXP_LNKCTL,
+					      newlnkctl);
+	}
+
 	if (current_link_up != netif_carrier_ok(tp->dev)) {
 		if (current_link_up)
 			netif_carrier_on(tp->dev);
@@ -3765,8 +3943,7 @@
 		err = tg3_setup_copper_phy(tp, force_reset);
 	}
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5784_A1) {
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) {
 		u32 val, scale;
 
 		val = tr32(TG3_CPMU_CLCK_STAT) & CPMU_CLCK_STAT_MAC_CLCK_MASK;
@@ -4100,12 +4277,15 @@
 			goto next_pkt;
 		}
 
-		len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
+		len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) -
+		      ETH_FCS_LEN;
 
 		if (len > RX_COPY_THRESHOLD
-			&& tp->rx_offset == 2
-			/* rx_offset != 2 iff this is a 5701 card running
-			 * in PCI-X mode [see tg3_get_invariants()] */
+			&& tp->rx_offset == NET_IP_ALIGN
+			/* rx_offset will likely not equal NET_IP_ALIGN
+			 * if this is a 5701 card running in PCI-X mode
+			 * [see tg3_get_invariants()]
+			 */
 		) {
 			int skb_size;
 
@@ -4125,11 +4305,12 @@
 			tg3_recycle_rx(tp, opaque_key,
 				       desc_idx, *post_ptr);
 
-			copy_skb = netdev_alloc_skb(tp->dev, len + 2);
+			copy_skb = netdev_alloc_skb(tp->dev,
+						    len + TG3_RAW_IP_ALIGN);
 			if (copy_skb == NULL)
 				goto drop_it_no_recycle;
 
-			skb_reserve(copy_skb, 2);
+			skb_reserve(copy_skb, TG3_RAW_IP_ALIGN);
 			skb_put(copy_skb, len);
 			pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
 			skb_copy_from_linear_data(skb, copy_skb->data, len);
@@ -4157,7 +4338,6 @@
 #endif
 			netif_receive_skb(skb);
 
-		tp->dev->last_rx = jiffies;
 		received++;
 		budget--;
 
@@ -4271,7 +4451,7 @@
 			sblk->status &= ~SD_STATUS_UPDATED;
 
 		if (likely(!tg3_has_work(tp))) {
-			netif_rx_complete(tp->dev, napi);
+			netif_rx_complete(napi);
 			tg3_restart_ints(tp);
 			break;
 		}
@@ -4281,7 +4461,7 @@
 
 tx_recovery:
 	/* work_done is guaranteed to be less than budget. */
-	netif_rx_complete(tp->dev, napi);
+	netif_rx_complete(napi);
 	schedule_work(&tp->reset_task);
 	return work_done;
 }
@@ -4330,7 +4510,7 @@
 	prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
 
 	if (likely(!tg3_irq_sync(tp)))
-		netif_rx_schedule(dev, &tp->napi);
+		netif_rx_schedule(&tp->napi);
 
 	return IRQ_HANDLED;
 }
@@ -4355,7 +4535,7 @@
 	 */
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
 	if (likely(!tg3_irq_sync(tp)))
-		netif_rx_schedule(dev, &tp->napi);
+		netif_rx_schedule(&tp->napi);
 
 	return IRQ_RETVAL(1);
 }
@@ -4397,7 +4577,7 @@
 	sblk->status &= ~SD_STATUS_UPDATED;
 	if (likely(tg3_has_work(tp))) {
 		prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
-		netif_rx_schedule(dev, &tp->napi);
+		netif_rx_schedule(&tp->napi);
 	} else {
 		/* No work, shared interrupt perhaps?  re-enable
 		 * interrupts, and flush that PCI write
@@ -4443,7 +4623,7 @@
 	tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
 	if (tg3_irq_sync(tp))
 		goto out;
-	if (netif_rx_schedule_prep(dev, &tp->napi)) {
+	if (netif_rx_schedule_prep(&tp->napi)) {
 		prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
 		/* Update last_tag to mark that this status has been
 		 * seen. Because interrupt may be shared, we may be
@@ -4451,7 +4631,7 @@
 		 * if tg3_poll() is not scheduled.
 		 */
 		tp->last_tag = sblk->status_tag;
-		__netif_rx_schedule(dev, &tp->napi);
+		__netif_rx_schedule(&tp->napi);
 	}
 out:
 	return IRQ_RETVAL(handled);
@@ -5557,6 +5737,13 @@
 			event = APE_EVENT_STATUS_STATE_START;
 			break;
 		case RESET_KIND_SHUTDOWN:
+			/* With the interface we are currently using,
+			 * APE does not track driver state.  Wiping
+			 * out the HOST SEGMENT SIGNATURE forces
+			 * the APE to assume OS absent status.
+			 */
+			tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0);
+
 			event = APE_EVENT_STATUS_STATE_UNLOAD;
 			break;
 		case RESET_KIND_SUSPEND:
@@ -5721,17 +5908,19 @@
 
 	pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
 
-	if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
-		pcie_set_readrq(tp->pdev, 4096);
-	else {
-		pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
-				      tp->pci_cacheline_sz);
-		pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER,
-				      tp->pci_lat_timer);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) {
+		if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
+			pcie_set_readrq(tp->pdev, 4096);
+		else {
+			pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
+					      tp->pci_cacheline_sz);
+			pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER,
+					      tp->pci_lat_timer);
+		}
 	}
 
 	/* Make sure PCI-X relaxed ordering bit is clear. */
-	if (tp->pcix_cap) {
+	if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) {
 		u16 pcix_cmd;
 
 		pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
@@ -5788,11 +5977,7 @@
 	tg3_save_pci_state(tp);
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+	    (tp->tg3_flags3 & TG3_FLG3_5755_PLUS))
 		tw32(GRC_FASTBOOT_PC, 0);
 
 	/*
@@ -5871,7 +6056,7 @@
 
 	udelay(120);
 
-	if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+	if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pcie_cap) {
 		if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) {
 			int i;
 			u32 cfg_val;
@@ -5884,8 +6069,23 @@
 			pci_write_config_dword(tp->pdev, 0xc4,
 					       cfg_val | (1 << 15));
 		}
-		/* Set PCIE max payload size and clear error status.  */
-		pci_write_config_dword(tp->pdev, 0xd8, 0xf5000);
+
+		/* Set PCIE max payload size to 128 bytes and
+		 * clear the "no snoop" and "relaxed ordering" bits.
+		 */
+		pci_write_config_word(tp->pdev,
+				      tp->pcie_cap + PCI_EXP_DEVCTL,
+				      0);
+
+		pcie_set_readrq(tp->pdev, 4096);
+
+		/* Clear error status */
+		pci_write_config_word(tp->pdev,
+				      tp->pcie_cap + PCI_EXP_DEVSTA,
+				      PCI_EXP_DEVSTA_CED |
+				      PCI_EXP_DEVSTA_NFED |
+				      PCI_EXP_DEVSTA_FED |
+				      PCI_EXP_DEVSTA_URD);
 	}
 
 	tg3_restore_pci_state(tp);
@@ -6883,43 +7083,6 @@
 }
 
 
-/* tp->lock is held. */
-static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1)
-{
-	u32 addr_high, addr_low;
-	int i;
-
-	addr_high = ((tp->dev->dev_addr[0] << 8) |
-		     tp->dev->dev_addr[1]);
-	addr_low = ((tp->dev->dev_addr[2] << 24) |
-		    (tp->dev->dev_addr[3] << 16) |
-		    (tp->dev->dev_addr[4] <<  8) |
-		    (tp->dev->dev_addr[5] <<  0));
-	for (i = 0; i < 4; i++) {
-		if (i == 1 && skip_mac_1)
-			continue;
-		tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high);
-		tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
-	}
-
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
-		for (i = 0; i < 12; i++) {
-			tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
-			tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
-		}
-	}
-
-	addr_high = (tp->dev->dev_addr[0] +
-		     tp->dev->dev_addr[1] +
-		     tp->dev->dev_addr[2] +
-		     tp->dev->dev_addr[3] +
-		     tp->dev->dev_addr[4] +
-		     tp->dev->dev_addr[5]) &
-		TX_BACKOFF_SEED_MASK;
-	tw32(MAC_TX_BACKOFF_SEED, addr_high);
-}
-
 static int tg3_set_mac_addr(struct net_device *dev, void *p)
 {
 	struct tg3 *tp = netdev_priv(dev);
@@ -7024,8 +7187,7 @@
 
 	tg3_write_sig_legacy(tp, RESET_KIND_INIT);
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5784_A1) {
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) {
 		val = tr32(TG3_CPMU_CTRL);
 		val &= ~(CPMU_CTRL_LINK_AWARE_MODE | CPMU_CTRL_LINK_IDLE_MODE);
 		tw32(TG3_CPMU_CTRL, val);
@@ -7091,8 +7253,7 @@
 		return err;
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) {
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
 		/* This value is determined during the probe time DMA
 		 * engine test, tg3_test_dma.
 		 */
@@ -7332,7 +7493,8 @@
 		      RDMAC_MODE_LNGREAD_ENAB);
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
 		rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB |
 			      RDMAC_MODE_MBUF_RBD_CRPT_ENAB |
 			      RDMAC_MODE_MBUF_SBD_CRPT_ENAB;
@@ -7354,7 +7516,11 @@
 		rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
 
 	if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
-		rdmac_mode |= (1 << 27);
+		rdmac_mode |= RDMAC_MODE_IPV4_LSO_EN;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+		rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN;
 
 	/* Receive/send statistics. */
 	if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
@@ -7501,11 +7667,7 @@
 	}
 
 	/* Enable host coalescing bug fix */
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) ||
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) ||
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) ||
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) ||
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785))
+	if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
 		val |= WDMAC_MODE_STATUS_TAG_FIX;
 
 	tw32_f(WDMAC_MODE, val);
@@ -7566,10 +7728,7 @@
 	udelay(100);
 
 	tp->rx_mode = RX_MODE_ENABLE;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+	if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
 		tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE;
 
 	tw32_f(MAC_RX_MODE, tp->rx_mode);
@@ -9066,7 +9225,8 @@
 	else
 		wol->supported = 0;
 	wol->wolopts = 0;
-	if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
+	if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
+	    device_can_wakeup(&tp->pdev->dev))
 		wol->wolopts = WAKE_MAGIC;
 	memset(&wol->sopass, 0, sizeof(wol->sopass));
 }
@@ -9116,14 +9276,15 @@
 			return -EINVAL;
 		return 0;
 	}
-	if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
+	if ((dev->features & NETIF_F_IPV6_CSUM) &&
+	    (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2)) {
 		if (value) {
 			dev->features |= NETIF_F_TSO6;
 			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
 			    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
 			     GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
-			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
 				dev->features |= NETIF_F_TSO_ECN;
 		} else
 			dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN);
@@ -9238,12 +9399,12 @@
 
 	epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
 
-	if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX)
+	if (tp->link_config.active_flowctrl & FLOW_CTRL_RX)
 		epause->rx_pause = 1;
 	else
 		epause->rx_pause = 0;
 
-	if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX)
+	if (tp->link_config.active_flowctrl & FLOW_CTRL_TX)
 		epause->tx_pause = 1;
 	else
 		epause->tx_pause = 0;
@@ -9294,14 +9455,14 @@
 			}
 		} else {
 			if (epause->rx_pause)
-				tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
+				tp->link_config.flowctrl |= FLOW_CTRL_RX;
 			else
-				tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
+				tp->link_config.flowctrl &= ~FLOW_CTRL_RX;
 
 			if (epause->tx_pause)
-				tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
+				tp->link_config.flowctrl |= FLOW_CTRL_TX;
 			else
-				tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
+				tp->link_config.flowctrl &= ~FLOW_CTRL_TX;
 
 			if (netif_running(dev))
 				tg3_setup_flow_control(tp, 0, 0);
@@ -9321,13 +9482,13 @@
 		else
 			tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
 		if (epause->rx_pause)
-			tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
+			tp->link_config.flowctrl |= FLOW_CTRL_RX;
 		else
-			tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
+			tp->link_config.flowctrl &= ~FLOW_CTRL_RX;
 		if (epause->tx_pause)
-			tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
+			tp->link_config.flowctrl |= FLOW_CTRL_TX;
 		else
-			tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
+			tp->link_config.flowctrl &= ~FLOW_CTRL_TX;
 
 		if (netif_running(dev)) {
 			tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
@@ -9378,11 +9539,7 @@
   		return 0;
   	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+	if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
 		ethtool_op_set_tx_ipv6_csum(dev, data);
 	else
 		ethtool_op_set_tx_csum(dev, data);
@@ -9899,18 +10056,13 @@
 	int err = 0;
 	int i;
 
-	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
-			mem_tbl = mem_tbl_5755;
-		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
-			mem_tbl = mem_tbl_5906;
-		else
-			mem_tbl = mem_tbl_5705;
-	} else
+	if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
+		mem_tbl = mem_tbl_5755;
+	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+		mem_tbl = mem_tbl_5906;
+	else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+		mem_tbl = mem_tbl_5705;
+	else
 		mem_tbl = mem_tbl_570x;
 
 	for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
@@ -10110,9 +10262,11 @@
 	if (err)
 		return TG3_LOOPBACK_FAILED;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+	/* Turn off gphy autopowerdown. */
+	if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD)
+		tg3_phy_toggle_apd(tp, false);
+
+	if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) {
 		int i;
 		u32 status;
 
@@ -10139,9 +10293,7 @@
 	if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
 		err |= TG3_MAC_LOOPBACK_FAILED;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+	if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) {
 		tw32(TG3_CPMU_CTRL, cpmuctrl);
 
 		/* Release the mutex */
@@ -10154,6 +10306,10 @@
 			err |= TG3_PHY_LOOPBACK_FAILED;
 	}
 
+	/* Re-enable gphy autopowerdown. */
+	if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD)
+		tg3_phy_toggle_apd(tp, true);
+
 	return err;
 }
 
@@ -10756,6 +10912,102 @@
 	tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
 }
 
+static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp)
+{
+	u32 nvcfg1;
+
+	nvcfg1 = tr32(NVRAM_CFG1);
+
+	switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
+	case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ:
+	case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ:
+		tp->nvram_jedecnum = JEDEC_ATMEL;
+		tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+		tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
+
+		nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
+		tw32(NVRAM_CFG1, nvcfg1);
+		return;
+	case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED:
+	case FLASH_57780VENDOR_ATMEL_AT45DB011D:
+	case FLASH_57780VENDOR_ATMEL_AT45DB011B:
+	case FLASH_57780VENDOR_ATMEL_AT45DB021D:
+	case FLASH_57780VENDOR_ATMEL_AT45DB021B:
+	case FLASH_57780VENDOR_ATMEL_AT45DB041D:
+	case FLASH_57780VENDOR_ATMEL_AT45DB041B:
+		tp->nvram_jedecnum = JEDEC_ATMEL;
+		tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+		tp->tg3_flags2 |= TG3_FLG2_FLASH;
+
+		switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
+		case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED:
+		case FLASH_57780VENDOR_ATMEL_AT45DB011D:
+		case FLASH_57780VENDOR_ATMEL_AT45DB011B:
+			tp->nvram_size = TG3_NVRAM_SIZE_128KB;
+			break;
+		case FLASH_57780VENDOR_ATMEL_AT45DB021D:
+		case FLASH_57780VENDOR_ATMEL_AT45DB021B:
+			tp->nvram_size = TG3_NVRAM_SIZE_256KB;
+			break;
+		case FLASH_57780VENDOR_ATMEL_AT45DB041D:
+		case FLASH_57780VENDOR_ATMEL_AT45DB041B:
+			tp->nvram_size = TG3_NVRAM_SIZE_512KB;
+			break;
+		}
+		break;
+	case FLASH_5752VENDOR_ST_M45PE10:
+	case FLASH_5752VENDOR_ST_M45PE20:
+	case FLASH_5752VENDOR_ST_M45PE40:
+		tp->nvram_jedecnum = JEDEC_ST;
+		tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+		tp->tg3_flags2 |= TG3_FLG2_FLASH;
+
+		switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
+		case FLASH_5752VENDOR_ST_M45PE10:
+			tp->nvram_size = TG3_NVRAM_SIZE_128KB;
+			break;
+		case FLASH_5752VENDOR_ST_M45PE20:
+			tp->nvram_size = TG3_NVRAM_SIZE_256KB;
+			break;
+		case FLASH_5752VENDOR_ST_M45PE40:
+			tp->nvram_size = TG3_NVRAM_SIZE_512KB;
+			break;
+		}
+		break;
+	default:
+		return;
+	}
+
+	switch (nvcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) {
+	case FLASH_5752PAGE_SIZE_256:
+		tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS;
+		tp->nvram_pagesize = 256;
+		break;
+	case FLASH_5752PAGE_SIZE_512:
+		tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS;
+		tp->nvram_pagesize = 512;
+		break;
+	case FLASH_5752PAGE_SIZE_1K:
+		tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS;
+		tp->nvram_pagesize = 1024;
+		break;
+	case FLASH_5752PAGE_SIZE_2K:
+		tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS;
+		tp->nvram_pagesize = 2048;
+		break;
+	case FLASH_5752PAGE_SIZE_4K:
+		tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS;
+		tp->nvram_pagesize = 4096;
+		break;
+	case FLASH_5752PAGE_SIZE_264:
+		tp->nvram_pagesize = 264;
+		break;
+	case FLASH_5752PAGE_SIZE_528:
+		tp->nvram_pagesize = 528;
+		break;
+	}
+}
+
 /* Chips other than 5700/5701 use the NVRAM for fetching info. */
 static void __devinit tg3_nvram_init(struct tg3 *tp)
 {
@@ -10796,6 +11048,8 @@
 			tg3_get_5761_nvram_info(tp);
 		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
 			tg3_get_5906_nvram_info(tp);
+		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+			tg3_get_57780_nvram_info(tp);
 		else
 			tg3_get_nvram_info(tp);
 
@@ -11116,12 +11370,8 @@
 		if (i == (len - 4))
 			nvram_cmd |= NVRAM_CMD_LAST;
 
-		if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) &&
-		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) &&
-		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) &&
-		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) &&
-		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) &&
-		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) &&
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
+		    !(tp->tg3_flags3 & TG3_FLG3_5755_PLUS) &&
 		    (tp->nvram_jedecnum == JEDEC_ST) &&
 		    (nvram_cmd & NVRAM_CMD_FIRST)) {
 
@@ -11296,10 +11546,9 @@
 		if (val & VCPU_CFGSHDW_ASPM_DBNC)
 			tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
 		if ((val & VCPU_CFGSHDW_WOL_ENABLE) &&
-		    (val & VCPU_CFGSHDW_WOL_MAGPKT) &&
-		    device_may_wakeup(&tp->pdev->dev))
+		    (val & VCPU_CFGSHDW_WOL_MAGPKT))
 			tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
-		return;
+		goto done;
 	}
 
 	tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
@@ -11421,15 +11670,17 @@
 			if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
 				tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
 		}
-		if (nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE)
+
+		if ((nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) &&
+			(tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
 			tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE;
+
 		if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
 		    !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
 			tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
 
 		if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) &&
-		    (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE) &&
-		    device_may_wakeup(&tp->pdev->dev))
+		    (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE))
 			tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
 
 		if (cfg2 & (1 << 17))
@@ -11440,6 +11691,11 @@
 		if (cfg2 & (1 << 18))
 			tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS;
 
+		if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+		      GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX)) &&
+		    (cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN))
+			tp->tg3_flags3 |= TG3_FLG3_PHY_ENABLE_APD;
+
 		if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
 			u32 cfg3;
 
@@ -11455,6 +11711,10 @@
 		if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN)
 			tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN;
 	}
+done:
+	device_init_wakeup(&tp->pdev->dev, tp->tg3_flags & TG3_FLAG_WOL_CAP);
+	device_set_wakeup_enable(&tp->pdev->dev,
+				 tp->tg3_flags & TG3_FLAG_WOL_ENABLE);
 }
 
 static int __devinit tg3_issue_otp_command(struct tg3 *tp, u32 cmd)
@@ -11751,6 +12011,51 @@
 	return 1;
 }
 
+static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val)
+{
+	u32 offset, major, minor, build;
+
+	tp->fw_ver[0] = 's';
+	tp->fw_ver[1] = 'b';
+	tp->fw_ver[2] = '\0';
+
+	if ((val & TG3_EEPROM_SB_FORMAT_MASK) != TG3_EEPROM_SB_FORMAT_1)
+		return;
+
+	switch (val & TG3_EEPROM_SB_REVISION_MASK) {
+	case TG3_EEPROM_SB_REVISION_0:
+		offset = TG3_EEPROM_SB_F1R0_EDH_OFF;
+		break;
+	case TG3_EEPROM_SB_REVISION_2:
+		offset = TG3_EEPROM_SB_F1R2_EDH_OFF;
+		break;
+	case TG3_EEPROM_SB_REVISION_3:
+		offset = TG3_EEPROM_SB_F1R3_EDH_OFF;
+		break;
+	default:
+		return;
+	}
+
+	if (tg3_nvram_read_swab(tp, offset, &val))
+		return;
+
+	build = (val & TG3_EEPROM_SB_EDH_BLD_MASK) >>
+		TG3_EEPROM_SB_EDH_BLD_SHFT;
+	major = (val & TG3_EEPROM_SB_EDH_MAJ_MASK) >>
+		TG3_EEPROM_SB_EDH_MAJ_SHFT;
+	minor =  val & TG3_EEPROM_SB_EDH_MIN_MASK;
+
+	if (minor > 99 || build > 26)
+		return;
+
+	snprintf(&tp->fw_ver[2], 30, " v%d.%02d", major, minor);
+
+	if (build > 0) {
+		tp->fw_ver[8] = 'a' + build - 1;
+		tp->fw_ver[9] = '\0';
+	}
+}
+
 static void __devinit tg3_read_fw_ver(struct tg3 *tp)
 {
 	u32 val, offset, start;
@@ -11760,8 +12065,12 @@
 	if (tg3_nvram_read_swab(tp, 0, &val))
 		return;
 
-	if (val != TG3_EEPROM_MAGIC)
+	if (val != TG3_EEPROM_MAGIC) {
+		if ((val & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW)
+			tg3_read_sb_ver(tp, val);
+
 		return;
+	}
 
 	if (tg3_nvram_read_swab(tp, 0xc, &offset) ||
 	    tg3_nvram_read_swab(tp, 0x4, &start))
@@ -11849,11 +12158,10 @@
 		{ },
 	};
 	u32 misc_ctrl_reg;
-	u32 cacheline_sz_reg;
 	u32 pci_state_reg, grc_misc_cfg;
 	u32 val;
 	u16 pci_cmd;
-	int err, pcie_cap;
+	int err;
 
 	/* Force memory write invalidate off.  If we leave it on,
 	 * then on 5700_BX chips we have to enable a workaround.
@@ -11882,7 +12190,7 @@
 
 		pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV,
 				      &prod_id_asic_rev);
-		tp->pci_chip_rev_id = prod_id_asic_rev & PROD_ID_ASIC_REV_MASK;
+		tp->pci_chip_rev_id = prod_id_asic_rev;
 	}
 
 	/* Wrong chip ID in 5752 A0. This code can be removed later
@@ -12019,26 +12327,23 @@
 	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
 			       tp->misc_host_ctrl);
 
-	pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
-			      &cacheline_sz_reg);
-
-	tp->pci_cacheline_sz = (cacheline_sz_reg >>  0) & 0xff;
-	tp->pci_lat_timer    = (cacheline_sz_reg >>  8) & 0xff;
-	tp->pci_hdr_type     = (cacheline_sz_reg >> 16) & 0xff;
-	tp->pci_bist         = (cacheline_sz_reg >> 24) & 0xff;
-
 	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
 	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714))
 		tp->pdev_peer = tg3_find_peer(tp);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+	/* Intentionally exclude ASIC_REV_5906 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+		tp->tg3_flags3 |= TG3_FLG3_5755_PLUS;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
+	    (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
 	    (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
 		tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
 
@@ -12046,6 +12351,18 @@
 	    (tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
 		tp->tg3_flags2 |= TG3_FLG2_5705_PLUS;
 
+	/* 5700 B0 chips do not support checksumming correctly due
+	 * to hardware bugs.
+	 */
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0)
+		tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS;
+	else {
+		tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
+		tp->dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+		if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
+			tp->dev->features |= NETIF_F_IPV6_CSUM;
+	}
+
 	if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
 		tp->tg3_flags |= TG3_FLAG_SUPPORT_MSI;
 		if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX ||
@@ -12055,11 +12372,7 @@
 		     tp->pdev_peer == tp->pdev))
 			tp->tg3_flags &= ~TG3_FLAG_SUPPORT_MSI;
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+		if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
 		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
 			tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
 			tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
@@ -12076,21 +12389,41 @@
 	     (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
 		tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
 
-	pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP);
-	if (pcie_cap != 0) {
+	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
+			      &pci_state_reg);
+
+	tp->pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP);
+	if (tp->pcie_cap != 0) {
+		u16 lnkctl;
+
 		tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
 
 		pcie_set_readrq(tp->pdev, 4096);
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
-			u16 lnkctl;
-
-			pci_read_config_word(tp->pdev,
-					     pcie_cap + PCI_EXP_LNKCTL,
-					     &lnkctl);
-			if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN)
+		pci_read_config_word(tp->pdev,
+				     tp->pcie_cap + PCI_EXP_LNKCTL,
+				     &lnkctl);
+		if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) {
+			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
 				tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2;
+			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+				tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG;
 		}
+	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+		tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
+	} else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+		   (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+		tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX);
+		if (!tp->pcix_cap) {
+			printk(KERN_ERR PFX "Cannot find PCI-X "
+					    "capability, aborting.\n");
+			return -EIO;
+		}
+
+		if (!(pci_state_reg & PCISTATE_CONV_PCI_MODE))
+			tp->tg3_flags |= TG3_FLAG_PCIX_MODE;
 	}
 
 	/* If we have an AMD 762 or VIA K8T800 chipset, write
@@ -12103,42 +12436,29 @@
 	    !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
 		tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER;
 
+	pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
+			     &tp->pci_cacheline_sz);
+	pci_read_config_byte(tp->pdev, PCI_LATENCY_TIMER,
+			     &tp->pci_lat_timer);
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
 	    tp->pci_lat_timer < 64) {
 		tp->pci_lat_timer = 64;
-
-		cacheline_sz_reg  = ((tp->pci_cacheline_sz & 0xff) <<  0);
-		cacheline_sz_reg |= ((tp->pci_lat_timer    & 0xff) <<  8);
-		cacheline_sz_reg |= ((tp->pci_hdr_type     & 0xff) << 16);
-		cacheline_sz_reg |= ((tp->pci_bist         & 0xff) << 24);
-
-		pci_write_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
-				       cacheline_sz_reg);
+		pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER,
+				      tp->pci_lat_timer);
 	}
 
-	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
-	    (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
-		tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX);
-		if (!tp->pcix_cap) {
-			printk(KERN_ERR PFX "Cannot find PCI-X "
-					    "capability, aborting.\n");
-			return -EIO;
-		}
-	}
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) {
+		/* 5700 BX chips need to have their TX producer index
+		 * mailboxes written twice to workaround a bug.
+		 */
+		tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG;
 
-	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
-			      &pci_state_reg);
-
-	if (tp->pcix_cap && (pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) {
-		tp->tg3_flags |= TG3_FLAG_PCIX_MODE;
-
-		/* If this is a 5700 BX chipset, and we are in PCI-X
-		 * mode, enable register write workaround.
+		/* If we are in PCI-X mode, enable register write workaround.
 		 *
 		 * The workaround is to use indirect register accesses
 		 * for all chip writes not to mailbox registers.
 		 */
-		if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) {
+		if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) {
 			u32 pm_reg;
 
 			tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
@@ -12163,12 +12483,6 @@
 		}
 	}
 
-	/* 5700 BX chips need to have their TX producer index mailboxes
-	 * written twice to workaround a bug.
-	 */
-	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX)
-		tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG;
-
 	if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0)
 		tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED;
 	if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
@@ -12263,16 +12577,10 @@
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
 		tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
 
-		if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
-		    tp->pci_chip_rev_id == CHIPREV_ID_5784_A1 ||
-		    tp->pci_chip_rev_id == CHIPREV_ID_5761_A0 ||
-		    tp->pci_chip_rev_id == CHIPREV_ID_5761_A1)
-			tp->tg3_flags3 |= TG3_FLG3_5761_5784_AX_FIXES;
-	}
-
 	/* Set up tp->grc_local_ctrl before calling tg3_set_power_state().
 	 * GPIO1 driven high will bring 5700's external PHY out of reset.
 	 * It is also used as eeprom write protect on LOMs.
@@ -12288,7 +12596,8 @@
 	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
 		tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
 		tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
 
 	if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) {
@@ -12308,12 +12617,6 @@
 		return err;
 	}
 
-	/* 5700 B0 chips do not support checksumming correctly due
-	 * to hardware bugs.
-	 */
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0)
-		tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS;
-
 	/* Derive initial jumbo mode from MTU assigned in
 	 * ether_setup() via the alloc_etherdev() call
 	 */
@@ -12346,7 +12649,10 @@
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
 		tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG;
 
-	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+	if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780) {
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
 		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
 		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
@@ -12356,8 +12662,7 @@
 				tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
 			if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M)
 				tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM;
-		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 &&
-			   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785)
+		} else
 			tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
 	}
 
@@ -12378,7 +12683,8 @@
 	    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
 		tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
 		tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB;
 
 	err = tg3_mdio_init(tp);
@@ -12463,6 +12769,7 @@
 	     (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F ||
 	      tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F ||
 	      tp->pdev->device == PCI_DEVICE_ID_TIGON3_5787F)) ||
+	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
 		tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
 
@@ -12512,20 +12819,7 @@
 	else
 		tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
 
-	/* All chips before 5787 can get confused if TX buffers
-	 * straddle the 4GB address boundary in some cases.
-	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
-		tp->dev->hard_start_xmit = tg3_start_xmit;
-	else
-		tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug;
-
-	tp->rx_offset = 2;
+	tp->rx_offset = NET_IP_ALIGN;
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
 	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0)
 		tp->rx_offset = 0;
@@ -13241,18 +13535,53 @@
 	}
 }
 
+static const struct net_device_ops tg3_netdev_ops = {
+	.ndo_open		= tg3_open,
+	.ndo_stop		= tg3_close,
+	.ndo_start_xmit		= tg3_start_xmit,
+	.ndo_get_stats		= tg3_get_stats,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_multicast_list	= tg3_set_rx_mode,
+	.ndo_set_mac_address	= tg3_set_mac_addr,
+	.ndo_do_ioctl		= tg3_ioctl,
+	.ndo_tx_timeout		= tg3_tx_timeout,
+	.ndo_change_mtu		= tg3_change_mtu,
+#if TG3_VLAN_TAG_USED
+	.ndo_vlan_rx_register	= tg3_vlan_rx_register,
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= tg3_poll_controller,
+#endif
+};
+
+static const struct net_device_ops tg3_netdev_ops_dma_bug = {
+	.ndo_open		= tg3_open,
+	.ndo_stop		= tg3_close,
+	.ndo_start_xmit		= tg3_start_xmit_dma_bug,
+	.ndo_get_stats		= tg3_get_stats,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_multicast_list	= tg3_set_rx_mode,
+	.ndo_set_mac_address	= tg3_set_mac_addr,
+	.ndo_do_ioctl		= tg3_ioctl,
+	.ndo_tx_timeout		= tg3_tx_timeout,
+	.ndo_change_mtu		= tg3_change_mtu,
+#if TG3_VLAN_TAG_USED
+	.ndo_vlan_rx_register	= tg3_vlan_rx_register,
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= tg3_poll_controller,
+#endif
+};
+
 static int __devinit tg3_init_one(struct pci_dev *pdev,
 				  const struct pci_device_id *ent)
 {
 	static int tg3_version_printed = 0;
-	resource_size_t tg3reg_base;
-	unsigned long tg3reg_len;
 	struct net_device *dev;
 	struct tg3 *tp;
 	int err, pm_cap;
 	char str[40];
 	u64 dma_mask, persist_dma_mask;
-	DECLARE_MAC_BUF(mac);
 
 	if (tg3_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -13264,13 +13593,6 @@
 		return err;
 	}
 
-	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-		printk(KERN_ERR PFX "Cannot find proper PCI device "
-		       "base address, aborting.\n");
-		err = -ENODEV;
-		goto err_out_disable_pdev;
-	}
-
 	err = pci_request_regions(pdev, DRV_MODULE_NAME);
 	if (err) {
 		printk(KERN_ERR PFX "Cannot obtain PCI resources, "
@@ -13289,9 +13611,6 @@
 		goto err_out_free_res;
 	}
 
-	tg3reg_base = pci_resource_start(pdev, 0);
-	tg3reg_len = pci_resource_len(pdev, 0);
-
 	dev = alloc_etherdev(sizeof(*tp));
 	if (!dev) {
 		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
@@ -13303,7 +13622,6 @@
 
 #if TG3_VLAN_TAG_USED
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-	dev->vlan_rx_register = tg3_vlan_rx_register;
 #endif
 
 	tp = netdev_priv(dev);
@@ -13343,7 +13661,7 @@
 	spin_lock_init(&tp->indirect_lock);
 	INIT_WORK(&tp->reset_task, tg3_reset_task);
 
-	tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len);
+	tp->regs = pci_ioremap_bar(pdev, BAR_0);
 	if (!tp->regs) {
 		printk(KERN_ERR PFX "Cannot map device registers, "
 		       "aborting.\n");
@@ -13357,21 +13675,10 @@
 	tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
 	tp->tx_pending = TG3_DEF_TX_RING_PENDING;
 
-	dev->open = tg3_open;
-	dev->stop = tg3_close;
-	dev->get_stats = tg3_get_stats;
-	dev->set_multicast_list = tg3_set_rx_mode;
-	dev->set_mac_address = tg3_set_mac_addr;
-	dev->do_ioctl = tg3_ioctl;
-	dev->tx_timeout = tg3_tx_timeout;
 	netif_napi_add(dev, &tp->napi, tg3_poll, 64);
 	dev->ethtool_ops = &tg3_ethtool_ops;
 	dev->watchdog_timeo = TG3_TX_TIMEOUT;
-	dev->change_mtu = tg3_change_mtu;
 	dev->irq = pdev->irq;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = tg3_poll_controller;
-#endif
 
 	err = tg3_get_invariants(tp);
 	if (err) {
@@ -13380,6 +13687,13 @@
 		goto err_out_iounmap;
 	}
 
+	if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+		dev->netdev_ops = &tg3_netdev_ops;
+	else
+		dev->netdev_ops = &tg3_netdev_ops_dma_bug;
+
+
 	/* The EPB bridge inside 5714, 5715, and 5780 and any
 	 * device behind the EPB cannot support DMA addresses > 40-bit.
 	 * On 64-bit systems with IOMMU, use 40-bit dma_mask.
@@ -13439,14 +13753,16 @@
 	 * is off by default, but can be enabled using ethtool.
 	 */
 	if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
-		dev->features |= NETIF_F_TSO;
-		if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
-		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906))
+		if (dev->features & NETIF_F_IP_CSUM)
+			dev->features |= NETIF_F_TSO;
+		if ((dev->features & NETIF_F_IPV6_CSUM) &&
+		    (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2))
 			dev->features |= NETIF_F_TSO6;
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
 		    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
 		     GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
-			GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+			GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
 			dev->features |= NETIF_F_TSO_ECN;
 	}
 
@@ -13466,17 +13782,7 @@
 	}
 
 	if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
-		if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
-			printk(KERN_ERR PFX "Cannot find proper PCI device "
-			       "base address for APE, aborting.\n");
-			err = -ENODEV;
-			goto err_out_iounmap;
-		}
-
-		tg3reg_base = pci_resource_start(pdev, 2);
-		tg3reg_len = pci_resource_len(pdev, 2);
-
-		tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len);
+		tp->aperegs = pci_ioremap_bar(pdev, BAR_2);
 		if (!tp->aperegs) {
 			printk(KERN_ERR PFX "Cannot map APE registers, "
 			       "aborting.\n");
@@ -13504,25 +13810,9 @@
 		goto err_out_apeunmap;
 	}
 
-	/* Tigon3 can do ipv4 only... and some chips have buggy
-	 * checksumming.
-	 */
-	if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) {
-		dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
-			dev->features |= NETIF_F_IPV6_CSUM;
-
-		tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
-	} else
-		tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
-
 	/* flow control autonegotiation is default behavior */
 	tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
-	tp->link_config.flowctrl = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+	tp->link_config.flowctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
 
 	tg3_init_coal(tp);
 
@@ -13535,26 +13825,34 @@
 		goto err_out_apeunmap;
 	}
 
-	printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] "
-	       "(%s) %s Ethernet %s\n",
+	printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x] (%s) MAC address %pM\n",
 	       dev->name,
 	       tp->board_part_number,
 	       tp->pci_chip_rev_id,
-	       tg3_phy_string(tp),
 	       tg3_bus_string(tp, str),
-	       ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" :
-		((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" :
-		 "10/100/1000Base-T")),
-	       print_mac(mac, dev->dev_addr));
+	       dev->dev_addr);
 
-	printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] "
-	       "MIirq[%d] ASF[%d] WireSpeed[%d] TSOcap[%d]\n",
+	if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)
+		printk(KERN_INFO
+		       "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
+		       tp->dev->name,
+		       tp->mdio_bus->phy_map[PHY_ADDR]->drv->name,
+		       dev_name(&tp->mdio_bus->phy_map[PHY_ADDR]->dev));
+	else
+		printk(KERN_INFO
+		       "%s: attached PHY is %s (%s Ethernet) (WireSpeed[%d])\n",
+		       tp->dev->name, tg3_phy_string(tp),
+		       ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" :
+			((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" :
+			 "10/100/1000Base-T")),
+		       (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0);
+
+	printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n",
 	       dev->name,
 	       (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0,
 	       (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0,
 	       (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0,
 	       (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0,
-	       (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0,
 	       (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0);
 	printk(KERN_INFO "%s: dma_rwctrl[%08x] dma_mask[%d-bit]\n",
 	       dev->name, tp->dma_rwctrl,
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index be252ab..8936edf 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -38,26 +38,13 @@
 #define  TG3PCI_DEVICE_TIGON3_2		 0x1645 /* BCM5701 */
 #define  TG3PCI_DEVICE_TIGON3_3		 0x1646 /* BCM5702 */
 #define  TG3PCI_DEVICE_TIGON3_4		 0x1647 /* BCM5703 */
-#define TG3PCI_COMMAND			0x00000004
-#define TG3PCI_STATUS			0x00000006
-#define TG3PCI_CCREVID			0x00000008
-#define TG3PCI_CACHELINESZ		0x0000000c
-#define TG3PCI_LATTIMER			0x0000000d
-#define TG3PCI_HEADERTYPE		0x0000000e
-#define TG3PCI_BIST			0x0000000f
-#define TG3PCI_BASE0_LOW		0x00000010
-#define TG3PCI_BASE0_HIGH		0x00000014
-/* 0x18 --> 0x2c unused */
-#define TG3PCI_SUBSYSVENID		0x0000002c
-#define TG3PCI_SUBSYSID			0x0000002e
-#define TG3PCI_ROMADDR			0x00000030
-#define TG3PCI_CAPLIST			0x00000034
-/* 0x35 --> 0x3c unused */
-#define TG3PCI_IRQ_LINE			0x0000003c
-#define TG3PCI_IRQ_PIN			0x0000003d
-#define TG3PCI_MIN_GNT			0x0000003e
-#define TG3PCI_MAX_LAT			0x0000003f
-/* 0x40 --> 0x64 unused */
+#define  TG3PCI_DEVICE_TIGON3_5761S	 0x1688
+#define  TG3PCI_DEVICE_TIGON3_5761SE	 0x1689
+#define  TG3PCI_DEVICE_TIGON3_57780	 0x1692
+#define  TG3PCI_DEVICE_TIGON3_57760	 0x1690
+#define  TG3PCI_DEVICE_TIGON3_57790	 0x1694
+#define  TG3PCI_DEVICE_TIGON3_57720	 0x168c
+/* 0x04 --> 0x64 unused */
 #define TG3PCI_MSI_DATA			0x00000064
 /* 0x66 --> 0x68 unused */
 #define TG3PCI_MISC_HOST_CTRL		0x00000068
@@ -108,10 +95,6 @@
 #define  CHIPREV_ID_5752_A1		 0x6001
 #define  CHIPREV_ID_5714_A2		 0x9002
 #define  CHIPREV_ID_5906_A1		 0xc001
-#define  CHIPREV_ID_5784_A0		 0x5784000
-#define  CHIPREV_ID_5784_A1		 0x5784001
-#define  CHIPREV_ID_5761_A0		 0x5761000
-#define  CHIPREV_ID_5761_A1		 0x5761001
 #define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
 #define   ASIC_REV_5700			 0x07
 #define   ASIC_REV_5701			 0x00
@@ -129,6 +112,7 @@
 #define   ASIC_REV_5784			 0x5784
 #define   ASIC_REV_5761			 0x5761
 #define   ASIC_REV_5785			 0x5785
+#define   ASIC_REV_57780		 0x57780
 #define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
 #define   CHIPREV_5700_AX		 0x70
 #define   CHIPREV_5700_BX		 0x71
@@ -325,6 +309,7 @@
 #define  MAC_MODE_TDE_ENABLE		 0x00200000
 #define  MAC_MODE_RDE_ENABLE		 0x00400000
 #define  MAC_MODE_FHDE_ENABLE		 0x00800000
+#define  MAC_MODE_KEEP_FRAME_IN_WOL	 0x01000000
 #define  MAC_MODE_APE_RX_EN		 0x08000000
 #define  MAC_MODE_APE_TX_EN		 0x10000000
 #define MAC_STATUS			0x00000404
@@ -414,6 +399,7 @@
 #define  MI_COM_DATA_MASK		 0x0000ffff
 #define MAC_MI_STAT			0x00000450
 #define  MAC_MI_STAT_LNKSTAT_ATTN_ENAB	 0x00000001
+#define  MAC_MI_STAT_10MBPS_MODE	 0x00000002
 #define MAC_MI_MODE			0x00000454
 #define  MAC_MI_MODE_CLK_10MHZ		 0x00000001
 #define  MAC_MI_MODE_SHORT_PREAMBLE	 0x00000002
@@ -539,6 +525,100 @@
 #define  MAC_PHYCFG1_TXC_DRV		 0x20000000
 #define MAC_PHYCFG2			0x000005a4
 #define  MAC_PHYCFG2_INBAND_ENABLE	 0x00000001
+#define  MAC_PHYCFG2_EMODE_MASK_MASK	 0x000001c0
+#define  MAC_PHYCFG2_EMODE_MASK_AC131	 0x000000c0
+#define  MAC_PHYCFG2_EMODE_MASK_50610	 0x00000100
+#define  MAC_PHYCFG2_EMODE_MASK_RT8211	 0x00000000
+#define  MAC_PHYCFG2_EMODE_MASK_RT8201	 0x000001c0
+#define  MAC_PHYCFG2_EMODE_COMP_MASK	 0x00000e00
+#define  MAC_PHYCFG2_EMODE_COMP_AC131	 0x00000600
+#define  MAC_PHYCFG2_EMODE_COMP_50610	 0x00000400
+#define  MAC_PHYCFG2_EMODE_COMP_RT8211	 0x00000800
+#define  MAC_PHYCFG2_EMODE_COMP_RT8201	 0x00000000
+#define  MAC_PHYCFG2_FMODE_MASK_MASK	 0x00007000
+#define  MAC_PHYCFG2_FMODE_MASK_AC131	 0x00006000
+#define  MAC_PHYCFG2_FMODE_MASK_50610	 0x00004000
+#define  MAC_PHYCFG2_FMODE_MASK_RT8211	 0x00000000
+#define  MAC_PHYCFG2_FMODE_MASK_RT8201	 0x00007000
+#define  MAC_PHYCFG2_FMODE_COMP_MASK	 0x00038000
+#define  MAC_PHYCFG2_FMODE_COMP_AC131	 0x00030000
+#define  MAC_PHYCFG2_FMODE_COMP_50610	 0x00008000
+#define  MAC_PHYCFG2_FMODE_COMP_RT8211	 0x00038000
+#define  MAC_PHYCFG2_FMODE_COMP_RT8201	 0x00000000
+#define  MAC_PHYCFG2_GMODE_MASK_MASK	 0x001c0000
+#define  MAC_PHYCFG2_GMODE_MASK_AC131	 0x001c0000
+#define  MAC_PHYCFG2_GMODE_MASK_50610	 0x00100000
+#define  MAC_PHYCFG2_GMODE_MASK_RT8211	 0x00000000
+#define  MAC_PHYCFG2_GMODE_MASK_RT8201	 0x001c0000
+#define  MAC_PHYCFG2_GMODE_COMP_MASK	 0x00e00000
+#define  MAC_PHYCFG2_GMODE_COMP_AC131	 0x00e00000
+#define  MAC_PHYCFG2_GMODE_COMP_50610	 0x00000000
+#define  MAC_PHYCFG2_GMODE_COMP_RT8211	 0x00200000
+#define  MAC_PHYCFG2_GMODE_COMP_RT8201	 0x00000000
+#define  MAC_PHYCFG2_ACT_MASK_MASK	 0x03000000
+#define  MAC_PHYCFG2_ACT_MASK_AC131	 0x03000000
+#define  MAC_PHYCFG2_ACT_MASK_50610	 0x01000000
+#define  MAC_PHYCFG2_ACT_MASK_RT8211	 0x03000000
+#define  MAC_PHYCFG2_ACT_MASK_RT8201	 0x01000000
+#define  MAC_PHYCFG2_ACT_COMP_MASK	 0x0c000000
+#define  MAC_PHYCFG2_ACT_COMP_AC131	 0x00000000
+#define  MAC_PHYCFG2_ACT_COMP_50610	 0x00000000
+#define  MAC_PHYCFG2_ACT_COMP_RT8211	 0x00000000
+#define  MAC_PHYCFG2_ACT_COMP_RT8201	 0x08000000
+#define  MAC_PHYCFG2_QUAL_MASK_MASK	 0x30000000
+#define  MAC_PHYCFG2_QUAL_MASK_AC131	 0x30000000
+#define  MAC_PHYCFG2_QUAL_MASK_50610	 0x30000000
+#define  MAC_PHYCFG2_QUAL_MASK_RT8211	 0x30000000
+#define  MAC_PHYCFG2_QUAL_MASK_RT8201	 0x30000000
+#define  MAC_PHYCFG2_QUAL_COMP_MASK	 0xc0000000
+#define  MAC_PHYCFG2_QUAL_COMP_AC131	 0x00000000
+#define  MAC_PHYCFG2_QUAL_COMP_50610	 0x00000000
+#define  MAC_PHYCFG2_QUAL_COMP_RT8211	 0x00000000
+#define  MAC_PHYCFG2_QUAL_COMP_RT8201	 0x00000000
+#define MAC_PHYCFG2_50610_LED_MODES \
+	(MAC_PHYCFG2_EMODE_MASK_50610 | \
+	 MAC_PHYCFG2_EMODE_COMP_50610 | \
+	 MAC_PHYCFG2_FMODE_MASK_50610 | \
+	 MAC_PHYCFG2_FMODE_COMP_50610 | \
+	 MAC_PHYCFG2_GMODE_MASK_50610 | \
+	 MAC_PHYCFG2_GMODE_COMP_50610 | \
+	 MAC_PHYCFG2_ACT_MASK_50610 | \
+	 MAC_PHYCFG2_ACT_COMP_50610 | \
+	 MAC_PHYCFG2_QUAL_MASK_50610 | \
+	 MAC_PHYCFG2_QUAL_COMP_50610)
+#define MAC_PHYCFG2_AC131_LED_MODES \
+	(MAC_PHYCFG2_EMODE_MASK_AC131 | \
+	 MAC_PHYCFG2_EMODE_COMP_AC131 | \
+	 MAC_PHYCFG2_FMODE_MASK_AC131 | \
+	 MAC_PHYCFG2_FMODE_COMP_AC131 | \
+	 MAC_PHYCFG2_GMODE_MASK_AC131 | \
+	 MAC_PHYCFG2_GMODE_COMP_AC131 | \
+	 MAC_PHYCFG2_ACT_MASK_AC131 | \
+	 MAC_PHYCFG2_ACT_COMP_AC131 | \
+	 MAC_PHYCFG2_QUAL_MASK_AC131 | \
+	 MAC_PHYCFG2_QUAL_COMP_AC131)
+#define MAC_PHYCFG2_RTL8211C_LED_MODES \
+	(MAC_PHYCFG2_EMODE_MASK_RT8211 | \
+	 MAC_PHYCFG2_EMODE_COMP_RT8211 | \
+	 MAC_PHYCFG2_FMODE_MASK_RT8211 | \
+	 MAC_PHYCFG2_FMODE_COMP_RT8211 | \
+	 MAC_PHYCFG2_GMODE_MASK_RT8211 | \
+	 MAC_PHYCFG2_GMODE_COMP_RT8211 | \
+	 MAC_PHYCFG2_ACT_MASK_RT8211 | \
+	 MAC_PHYCFG2_ACT_COMP_RT8211 | \
+	 MAC_PHYCFG2_QUAL_MASK_RT8211 | \
+	 MAC_PHYCFG2_QUAL_COMP_RT8211)
+#define MAC_PHYCFG2_RTL8201E_LED_MODES \
+	(MAC_PHYCFG2_EMODE_MASK_RT8201 | \
+	 MAC_PHYCFG2_EMODE_COMP_RT8201 | \
+	 MAC_PHYCFG2_FMODE_MASK_RT8201 | \
+	 MAC_PHYCFG2_FMODE_COMP_RT8201 | \
+	 MAC_PHYCFG2_GMODE_MASK_RT8201 | \
+	 MAC_PHYCFG2_GMODE_COMP_RT8201 | \
+	 MAC_PHYCFG2_ACT_MASK_RT8201 | \
+	 MAC_PHYCFG2_ACT_COMP_RT8201 | \
+	 MAC_PHYCFG2_QUAL_MASK_RT8201 | \
+	 MAC_PHYCFG2_QUAL_COMP_RT8201)
 #define MAC_EXT_RGMII_MODE		0x000005a8
 #define  MAC_RGMII_MODE_TX_ENABLE	 0x00000001
 #define  MAC_RGMII_MODE_TX_LOWPWR	 0x00000002
@@ -1104,6 +1184,8 @@
 #define  RDMAC_MODE_MBUF_SBD_CRPT_ENAB	 0x00002000
 #define  RDMAC_MODE_FIFO_SIZE_128	 0x00020000
 #define  RDMAC_MODE_FIFO_LONG_BURST	 0x00030000
+#define  RDMAC_MODE_IPV4_LSO_EN		 0x08000000
+#define  RDMAC_MODE_IPV6_LSO_EN		 0x10000000
 #define RDMAC_STATUS			0x00004804
 #define  RDMAC_STATUS_TGTABORT		 0x00000004
 #define  RDMAC_STATUS_MSTABORT		 0x00000008
@@ -1550,6 +1632,12 @@
 #define  FLASH_5761VENDOR_ST_A_M45PE40	 0x02000000
 #define  FLASH_5761VENDOR_ST_A_M45PE80	 0x02000002
 #define  FLASH_5761VENDOR_ST_A_M45PE16	 0x02000003
+#define  FLASH_57780VENDOR_ATMEL_AT45DB011D 0x00400000
+#define  FLASH_57780VENDOR_ATMEL_AT45DB011B 0x03400000
+#define  FLASH_57780VENDOR_ATMEL_AT45DB021D 0x00400002
+#define  FLASH_57780VENDOR_ATMEL_AT45DB021B 0x03400002
+#define  FLASH_57780VENDOR_ATMEL_AT45DB041D 0x00400001
+#define  FLASH_57780VENDOR_ATMEL_AT45DB041B 0x03400001
 #define  NVRAM_CFG1_5752PAGE_SIZE_MASK	 0x70000000
 #define  FLASH_5752PAGE_SIZE_256	 0x00000000
 #define  FLASH_5752PAGE_SIZE_512	 0x10000000
@@ -1557,6 +1645,7 @@
 #define  FLASH_5752PAGE_SIZE_2K		 0x30000000
 #define  FLASH_5752PAGE_SIZE_4K		 0x40000000
 #define  FLASH_5752PAGE_SIZE_264	 0x50000000
+#define  FLASH_5752PAGE_SIZE_528	 0x60000000
 #define NVRAM_CFG2			0x00007018
 #define NVRAM_CFG3			0x0000701c
 #define NVRAM_SWARB			0x00007020
@@ -1649,6 +1738,17 @@
 #define TG3_NVM_DIRTYPE_SHIFT		24
 #define TG3_NVM_DIRTYPE_ASFINI		1
 
+#define TG3_EEPROM_SB_F1R0_EDH_OFF	0x10
+#define TG3_EEPROM_SB_F1R2_EDH_OFF	0x14
+#define TG3_EEPROM_SB_F1R2_MBA_OFF	0x10
+#define TG3_EEPROM_SB_F1R3_EDH_OFF	0x18
+#define TG3_EEPROM_SB_EDH_MAJ_MASK	0x00000700
+#define TG3_EEPROM_SB_EDH_MAJ_SHFT	8
+#define TG3_EEPROM_SB_EDH_MIN_MASK	0x000000ff
+#define TG3_EEPROM_SB_EDH_BLD_MASK	0x0000f800
+#define TG3_EEPROM_SB_EDH_BLD_SHFT	11
+
+
 /* 32K Window into NIC internal memory */
 #define NIC_SRAM_WIN_BASE		0x00008000
 
@@ -1724,6 +1824,7 @@
 
 #define NIC_SRAM_DATA_CFG_2		0x00000d38
 
+#define  NIC_SRAM_DATA_CFG_2_APD_EN	 0x00000400
 #define  SHASTA_EXT_LED_MODE_MASK	 0x00018000
 #define  SHASTA_EXT_LED_LEGACY		 0x00000000
 #define  SHASTA_EXT_LED_SHARED		 0x00008000
@@ -1792,6 +1893,11 @@
 
 #define MII_TG3_AUX_CTRL		0x18 /* auxilliary control register */
 
+#define MII_TG3_AUXCTL_PCTL_100TX_LPWR	0x0010
+#define MII_TG3_AUXCTL_PCTL_SPR_ISOLATE	0x0020
+#define MII_TG3_AUXCTL_PCTL_VREG_11V	0x0180
+#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL	0x0002
+
 #define MII_TG3_AUXCTL_MISC_WREN	0x8000
 #define MII_TG3_AUXCTL_MISC_FORCE_AMDIX	0x0200
 #define MII_TG3_AUXCTL_MISC_RDSEL_MISC	0x7000
@@ -1817,12 +1923,6 @@
 #define MII_TG3_ISTAT			0x1a /* IRQ status register */
 #define MII_TG3_IMASK			0x1b /* IRQ mask register */
 
-#define MII_TG3_MISC_SHDW		0x1c
-#define MII_TG3_MISC_SHDW_WREN		0x8000
-#define MII_TG3_MISC_SHDW_APD_SEL	0x2800
-
-#define MII_TG3_MISC_SHDW_APD_WKTM_84MS	0x0001
-
 /* ISTAT/IMASK event bits */
 #define MII_TG3_INT_LINKCHG		0x0002
 #define MII_TG3_INT_SPEEDCHG		0x0004
@@ -1831,7 +1931,9 @@
 
 #define MII_TG3_MISC_SHDW		0x1c
 #define MII_TG3_MISC_SHDW_WREN		0x8000
-#define MII_TG3_MISC_SHDW_SCR5_SEL	0x1400
+
+#define MII_TG3_MISC_SHDW_APD_WKTM_84MS	0x0001
+#define MII_TG3_MISC_SHDW_APD_ENABLE	0x0020
 #define MII_TG3_MISC_SHDW_APD_SEL	0x2800
 
 #define MII_TG3_MISC_SHDW_SCR5_C125OE	0x0001
@@ -1839,9 +1941,8 @@
 #define MII_TG3_MISC_SHDW_SCR5_SDTL	0x0004
 #define MII_TG3_MISC_SHDW_SCR5_DLPTLM	0x0008
 #define MII_TG3_MISC_SHDW_SCR5_LPED	0x0010
+#define MII_TG3_MISC_SHDW_SCR5_SEL	0x1400
 
-#define MII_TG3_MISC_SHDW_APD_WKTM_84MS	0x0001
-#define MII_TG3_MISC_SHDW_APD_ENABLE	0x0020
 
 #define MII_TG3_EPHY_TEST		0x1f /* 5906 PHY register */
 #define MII_TG3_EPHY_SHADOW_EN		0x80
@@ -2211,8 +2312,6 @@
 	u8				duplex;
 	u8				autoneg;
 	u8				flowctrl;
-#define TG3_FLOW_CTRL_TX		0x01
-#define TG3_FLOW_CTRL_RX		0x02
 
 	/* Describes what we actually have. */
 	u8				active_flowctrl;
@@ -2507,7 +2606,6 @@
 	u32				tg3_flags3;
 #define TG3_FLG3_NO_NVRAM_ADDR_TRANS	0x00000001
 #define TG3_FLG3_ENABLE_APE		0x00000002
-#define TG3_FLG3_5761_5784_AX_FIXES	0x00000004
 #define TG3_FLG3_5701_DMA_BUG		0x00000008
 #define TG3_FLG3_USE_PHYLIB		0x00000010
 #define TG3_FLG3_MDIOBUS_INITED		0x00000020
@@ -2516,6 +2614,9 @@
 #define TG3_FLG3_RGMII_STD_IBND_DISABLE	0x00000100
 #define TG3_FLG3_RGMII_EXT_IBND_RX_EN	0x00000200
 #define TG3_FLG3_RGMII_EXT_IBND_TX_EN	0x00000400
+#define TG3_FLG3_CLKREQ_BUG		0x00000800
+#define TG3_FLG3_PHY_ENABLE_APD		0x00001000
+#define TG3_FLG3_5755_PLUS		0x00002000
 
 	struct timer_list		timer;
 	u16				timer_counter;
@@ -2547,14 +2648,16 @@
 
 	/* PCI block */
 	u32				pci_chip_rev_id;
+	u16				pci_cmd;
 	u8				pci_cacheline_sz;
 	u8				pci_lat_timer;
-	u8				pci_hdr_type;
-	u8				pci_bist;
 
 	int				pm_cap;
 	int				msi_cap;
+	union {
 	int				pcix_cap;
+	int				pcie_cap;
+	};
 
 	struct mii_bus			*mdio_bus;
 	int				mdio_irq[PHY_MAX_ADDR];
@@ -2588,11 +2691,16 @@
 #define PHY_REV_BCM5411_X0		0x1 /* Found on Netgear GA302T */
 #define TG3_PHY_ID_BCM50610		0x143bd60
 #define TG3_PHY_ID_BCMAC131		0x143bc70
-
+#define TG3_PHY_ID_RTL8211C		0x001cc910
+#define TG3_PHY_ID_RTL8201E		0x00008200
+#define TG3_PHY_ID_BCM57780		0x03625d90
+#define TG3_PHY_OUI_MASK		0xfffffc00
+#define TG3_PHY_OUI_1			0x00206000
+#define TG3_PHY_OUI_2			0x0143bc00
+#define TG3_PHY_OUI_3			0x03625c00
 
 	u32				led_ctrl;
 	u32				phy_otp;
-	u16				pci_cmd;
 
 	char				board_part_number[24];
 #define TG3_VER_SIZE 32
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index e604982..85ef8b7 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -163,6 +163,11 @@
  *	v1.15 Apr 4, 2002    - Correct operation when aui=1 to be
  *	                       10T half duplex no loopback
  *	                       Thanks to Gunnar Eikman
+ *
+ *	Sakari Ailus <sakari.ailus@iki.fi>:
+ *
+ *	v1.15a Dec 15 2008   - Remove bbuf support, it doesn't work anyway.
+ *
  *******************************************************************************/
 
 #include <linux/module.h>
@@ -213,12 +218,8 @@
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "ThunderLAN debug mask");
 
-static	int		bbuf;
-module_param(bbuf, int, 0);
-MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)");
-
 static	const char TLanSignature[] = "TLAN";
-static  const char tlan_banner[] = "ThunderLAN driver v1.15\n";
+static  const char tlan_banner[] = "ThunderLAN driver v1.15a\n";
 static  int tlan_have_pci;
 static  int tlan_have_eisa;
 
@@ -859,13 +860,8 @@
 
 	priv = netdev_priv(dev);
 
-	if ( bbuf ) {
-		dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
-	           * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE );
-	} else {
-		dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
-	           * ( sizeof(TLanList) );
-	}
+	dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
+		* ( sizeof(TLanList) );
 	priv->dmaStorage = pci_alloc_consistent(priv->pciDev,
 						dma_size, &priv->dmaStorageDMA);
 	priv->dmaSize = dma_size;
@@ -881,16 +877,6 @@
 	priv->txList = priv->rxList + TLAN_NUM_RX_LISTS;
 	priv->txListDMA = priv->rxListDMA + sizeof(TLanList) * TLAN_NUM_RX_LISTS;
 
-	if ( bbuf ) {
-		priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS );
-		priv->rxBufferDMA =priv->txListDMA
-			+ sizeof(TLanList) * TLAN_NUM_TX_LISTS;
-		priv->txBuffer = priv->rxBuffer
-			+ ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
-		priv->txBufferDMA = priv->rxBufferDMA
-			+ ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
-	}
-
 	err = 0;
 	for ( i = 0;  i < 6 ; i++ )
 		err |= TLan_EeReadByte( dev,
@@ -1094,9 +1080,8 @@
 static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
 {
 	TLanPrivateInfo *priv = netdev_priv(dev);
-	TLanList	*tail_list;
 	dma_addr_t	tail_list_phys;
-	u8		*tail_buffer;
+	TLanList	*tail_list;
 	unsigned long	flags;
 	unsigned int    txlen;
 
@@ -1125,15 +1110,10 @@
 
 	tail_list->forward = 0;
 
-	if ( bbuf ) {
-		tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
-		skb_copy_from_linear_data(skb, tail_buffer, txlen);
-	} else {
-		tail_list->buffer[0].address = pci_map_single(priv->pciDev,
-							      skb->data, txlen,
-							      PCI_DMA_TODEVICE);
-		TLan_StoreSKB(tail_list, skb);
-	}
+	tail_list->buffer[0].address = pci_map_single(priv->pciDev,
+						      skb->data, txlen,
+						      PCI_DMA_TODEVICE);
+	TLan_StoreSKB(tail_list, skb);
 
 	tail_list->frameSize = (u16) txlen;
 	tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) txlen;
@@ -1163,9 +1143,6 @@
 
 	CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
 
-	if ( bbuf )
-		dev_kfree_skb_any(skb);
-
 	dev->trans_start = jiffies;
 	return 0;
 
@@ -1429,17 +1406,16 @@
 	head_list = priv->txList + priv->txHead;
 
 	while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {
+		struct sk_buff *skb = TLan_GetSKB(head_list);
+
 		ack++;
-		if ( ! bbuf ) {
-			struct sk_buff *skb = TLan_GetSKB(head_list);
-			pci_unmap_single(priv->pciDev, head_list->buffer[0].address,
-					 max(skb->len,
-					     (unsigned int)TLAN_MIN_FRAME_SIZE),
-					 PCI_DMA_TODEVICE);
-			dev_kfree_skb_any(skb);
-			head_list->buffer[8].address = 0;
-			head_list->buffer[9].address = 0;
-		}
+		pci_unmap_single(priv->pciDev, head_list->buffer[0].address,
+				 max(skb->len,
+				     (unsigned int)TLAN_MIN_FRAME_SIZE),
+				 PCI_DMA_TODEVICE);
+		dev_kfree_skb_any(skb);
+		head_list->buffer[8].address = 0;
+		head_list->buffer[9].address = 0;
 
 		if ( tmpCStat & TLAN_CSTAT_EOC )
 			eoc = 1;
@@ -1549,7 +1525,6 @@
 	TLanPrivateInfo	*priv = netdev_priv(dev);
 	u32		ack = 0;
 	int		eoc = 0;
-	u8		*head_buffer;
 	TLanList	*head_list;
 	struct sk_buff	*skb;
 	TLanList	*tail_list;
@@ -1564,53 +1539,33 @@
 	while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {
 		dma_addr_t frameDma = head_list->buffer[0].address;
 		u32 frameSize = head_list->frameSize;
+		struct sk_buff *new_skb;
+
 		ack++;
 		if (tmpCStat & TLAN_CSTAT_EOC)
 			eoc = 1;
 
-		if (bbuf) {
-			skb = netdev_alloc_skb(dev, frameSize + 7);
-			if ( !skb )
-				goto drop_and_reuse;
+		new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 );
+		if ( !new_skb )
+			goto drop_and_reuse;
 
-			head_buffer = priv->rxBuffer
-				+ (priv->rxHead * TLAN_MAX_FRAME_SIZE);
-			skb_reserve(skb, 2);
-			pci_dma_sync_single_for_cpu(priv->pciDev,
-						    frameDma, frameSize,
-						    PCI_DMA_FROMDEVICE);
-			skb_copy_from_linear_data(skb, head_buffer, frameSize);
-			skb_put(skb, frameSize);
-			dev->stats.rx_bytes += frameSize;
+		skb = TLan_GetSKB(head_list);
+		pci_unmap_single(priv->pciDev, frameDma,
+				 TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
+		skb_put( skb, frameSize );
 
-			skb->protocol = eth_type_trans( skb, dev );
-			netif_rx( skb );
-		} else {
-			struct sk_buff *new_skb;
+		dev->stats.rx_bytes += frameSize;
 
-			new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 );
-			if ( !new_skb )
-				goto drop_and_reuse;
+		skb->protocol = eth_type_trans( skb, dev );
+		netif_rx( skb );
 
-			skb = TLan_GetSKB(head_list);
-			pci_unmap_single(priv->pciDev, frameDma,
-					 TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
-			skb_put( skb, frameSize );
+		skb_reserve( new_skb, NET_IP_ALIGN );
+		head_list->buffer[0].address = pci_map_single(priv->pciDev,
+							      new_skb->data,
+							      TLAN_MAX_FRAME_SIZE,
+							      PCI_DMA_FROMDEVICE);
 
-			dev->stats.rx_bytes += frameSize;
-
-			skb->protocol = eth_type_trans( skb, dev );
-			netif_rx( skb );
-
-			skb_reserve( new_skb, NET_IP_ALIGN );
-			head_list->buffer[0].address = pci_map_single(priv->pciDev,
-								      new_skb->data,
-								      TLAN_MAX_FRAME_SIZE,
-								      PCI_DMA_FROMDEVICE);
-
-			TLan_StoreSKB(head_list, new_skb);
-
-		}
+		TLan_StoreSKB(head_list, new_skb);
 drop_and_reuse:
 		head_list->forward = 0;
 		head_list->cStat = 0;
@@ -1653,8 +1608,6 @@
 		}
 	}
 
-	dev->last_rx = jiffies;
-
 	return ack;
 
 } /* TLan_HandleRxEOF */
@@ -1995,12 +1948,7 @@
 	for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
 		list = priv->txList + i;
 		list->cStat = TLAN_CSTAT_UNUSED;
-		if ( bbuf ) {
-			list->buffer[0].address = priv->txBufferDMA
-				+ ( i * TLAN_MAX_FRAME_SIZE );
-		} else {
-			list->buffer[0].address = 0;
-		}
+		list->buffer[0].address = 0;
 		list->buffer[2].count = 0;
 		list->buffer[2].address = 0;
 		list->buffer[8].address = 0;
@@ -2015,23 +1963,18 @@
 		list->cStat = TLAN_CSTAT_READY;
 		list->frameSize = TLAN_MAX_FRAME_SIZE;
 		list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
-		if ( bbuf ) {
-			list->buffer[0].address = priv->rxBufferDMA
-				+ ( i * TLAN_MAX_FRAME_SIZE );
-		} else {
-			skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 );
-			if ( !skb ) {
-				pr_err("TLAN: out of memory for received data.\n" );
-				break;
-			}
-
-			skb_reserve( skb, NET_IP_ALIGN );
-			list->buffer[0].address = pci_map_single(priv->pciDev,
-								 skb->data,
-								 TLAN_MAX_FRAME_SIZE,
-								 PCI_DMA_FROMDEVICE);
-			TLan_StoreSKB(list, skb);
+		skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 );
+		if ( !skb ) {
+			pr_err("TLAN: out of memory for received data.\n" );
+			break;
 		}
+
+		skb_reserve( skb, NET_IP_ALIGN );
+		list->buffer[0].address = pci_map_single(priv->pciDev,
+							 skb->data,
+							 TLAN_MAX_FRAME_SIZE,
+							 PCI_DMA_FROMDEVICE);
+		TLan_StoreSKB(list, skb);
 		list->buffer[1].count = 0;
 		list->buffer[1].address = 0;
 		list->forward = list_phys + sizeof(TLanList);
@@ -2054,35 +1997,33 @@
 	TLanList	*list;
 	struct sk_buff	*skb;
 
-	if ( ! bbuf ) {
-		for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
-			list = priv->txList + i;
-			skb = TLan_GetSKB(list);
-			if ( skb ) {
-				pci_unmap_single(
-					priv->pciDev,
-					list->buffer[0].address,
-					max(skb->len,
-					    (unsigned int)TLAN_MIN_FRAME_SIZE),
-					PCI_DMA_TODEVICE);
-				dev_kfree_skb_any( skb );
-				list->buffer[8].address = 0;
-				list->buffer[9].address = 0;
-			}
+	for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
+		list = priv->txList + i;
+		skb = TLan_GetSKB(list);
+		if ( skb ) {
+			pci_unmap_single(
+				priv->pciDev,
+				list->buffer[0].address,
+				max(skb->len,
+				    (unsigned int)TLAN_MIN_FRAME_SIZE),
+				PCI_DMA_TODEVICE);
+			dev_kfree_skb_any( skb );
+			list->buffer[8].address = 0;
+			list->buffer[9].address = 0;
 		}
+	}
 
-		for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) {
-			list = priv->rxList + i;
-			skb = TLan_GetSKB(list);
-			if ( skb ) {
-				pci_unmap_single(priv->pciDev,
-						 list->buffer[0].address,
-						 TLAN_MAX_FRAME_SIZE,
-						 PCI_DMA_FROMDEVICE);
-				dev_kfree_skb_any( skb );
-				list->buffer[8].address = 0;
-				list->buffer[9].address = 0;
-			}
+	for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) {
+		list = priv->rxList + i;
+		skb = TLan_GetSKB(list);
+		if ( skb ) {
+			pci_unmap_single(priv->pciDev,
+					 list->buffer[0].address,
+					 TLAN_MAX_FRAME_SIZE,
+					 PCI_DMA_FROMDEVICE);
+			dev_kfree_skb_any( skb );
+			list->buffer[8].address = 0;
+			list->buffer[9].address = 0;
 		}
 	}
 } /* TLan_FreeLists */
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index bf62132..43853e3 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -296,8 +296,9 @@
 	} ; 
 
 	/* 
-	 * Allowing init_trdev to allocate the dev->priv structure will align xl_private
-   	 * on a 32 bytes boundary which we need for the rx/tx descriptors
+	 * Allowing init_trdev to allocate the private data will align
+	 * xl_private on a 32 bytes boundary which we need for the rx/tx
+	 * descriptors
 	 */
 
 	dev = alloc_trdev(sizeof(struct xl_private)) ; 
@@ -638,13 +639,13 @@
 	/* These MUST be on 8 byte boundaries */
 	xl_priv->xl_tx_ring = kzalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL);
 	if (xl_priv->xl_tx_ring == NULL) {
-		printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n",
+		printk(KERN_WARNING "%s: Not enough memory to allocate tx buffers.\n",
 				     dev->name);
 		free_irq(dev->irq,dev);
 		return -ENOMEM;
 	}
 	xl_priv->xl_rx_ring = kzalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL);
-	if (xl_priv->xl_tx_ring == NULL) {
+	if (xl_priv->xl_rx_ring == NULL) {
 		printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n",
 				     dev->name);
 		free_irq(dev->irq,dev);
@@ -669,6 +670,8 @@
 	if (i==0) { 
 		printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled \n",dev->name) ; 
 		free_irq(dev->irq,dev) ; 
+		kfree(xl_priv->xl_tx_ring);
+		kfree(xl_priv->xl_rx_ring);
 		return -EIO ; 
 	} 
 
@@ -974,7 +977,6 @@
 
 			netif_rx(skb2) ; 		
 		 } /* if multiple buffers */
-		dev->last_rx = jiffies ; 	
 	} /* while packet to do */
 
 	/* Clear the updComplete interrupt */
@@ -1571,7 +1573,6 @@
 		 * anyway.
 		 */
 
-		dev->last_rx = jiffies ; 
 		/* Acknowledge interrupt, this tells nic we are done with the arb */
 		writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; 
 
diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig
index e6b2e06..c4137b0 100644
--- a/drivers/net/tokenring/Kconfig
+++ b/drivers/net/tokenring/Kconfig
@@ -4,7 +4,7 @@
 
 # So far, we only have PCI, ISA, and MCA token ring devices
 menuconfig TR
-	bool "Token Ring driver support"
+	tristate "Token Ring driver support"
 	depends on NETDEVICES && !UML
 	depends on (PCI || ISA || MCA || CCW)
 	select LLC
diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
index 7a7de04..b566d6d 100644
--- a/drivers/net/tokenring/abyss.c
+++ b/drivers/net/tokenring/abyss.c
@@ -99,7 +99,6 @@
 	struct net_local *tp;
 	int ret, pci_irq_line;
 	unsigned long pci_ioaddr;
-	DECLARE_MAC_BUF(mac);
 	
 	if (versionprinted++ == 0)
 		printk("%s", version);
@@ -147,8 +146,7 @@
 
 	abyss_read_eeprom(dev);
 
-	printk("%s:    Ring Station Address: %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk("%s:    Ring Station Address: %pM\n", dev->name, dev->dev_addr);
 
 	tp = netdev_priv(dev);
 	tp->setnselout = abyss_setnselout_pins;
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index e494c63..fa7bce6 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -389,7 +389,6 @@
         unsigned long timeout;
 	static int version_printed;
 #endif
-	DECLARE_MAC_BUF(mac);
 
 	/*    Query the adapter PIO base port which will return
 	 *    indication of where MMIO was placed. We also have a
@@ -703,8 +702,7 @@
 		channel_def[cardpresent - 1], adapter_def(ti->adapter_type));
 	DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n",
 			irq, PIOaddr, ti->mapped_ram_size / 2);
-	DPRINTK("Hardware address : %s\n",
-		print_mac(mac, dev->dev_addr));
+	DPRINTK("Hardware address : %pM\n", dev->dev_addr);
 	if (ti->page_mask)
 		DPRINTK("Shared RAM paging enabled. "
 			"Page size: %uK Shared Ram size %dK\n",
@@ -1741,8 +1739,6 @@
 		void __iomem *trhhdr = rbuf + offsetof(struct rec_buf, data);
 		u8 saddr[6];
 		u8 daddr[6];
-		DECLARE_MAC_BUF(mac);
-		DECLARE_MAC_BUF(mac2);
 		int i;
 		for (i = 0 ; i < 6 ; i++)
 			saddr[i] = readb(trhhdr + SADDR_OFST + i);
@@ -1750,9 +1746,9 @@
 			daddr[i] = readb(trhhdr + DADDR_OFST + i);
 		DPRINTK("Probably non-IP frame received.\n");
 		DPRINTK("ssap: %02X dsap: %02X "
-			"saddr: %s daddr: %$s\n",
+			"saddr: %pM daddr: %pM\n",
 			readb(llc + SSAP_OFST), readb(llc + DSAP_OFST),
-			print_mac(mac, saddr), print_mac(mac2, daddr));
+			saddr, daddr);
 	}
 #endif
 
@@ -1826,7 +1822,6 @@
 		skb->ip_summed = CHECKSUM_COMPLETE;
 	}
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 }				/*tr_rx */
 
 /*****************************************************************************/
@@ -1842,8 +1837,8 @@
 
 /*****************************************************************************/
 
-void tok_rerun(unsigned long dev_addr){
-
+static void tok_rerun(unsigned long dev_addr)
+{
 	struct net_device *dev = (struct net_device *)dev_addr;
 	struct tok_info *ti = netdev_priv(dev);
 
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 59d1673..239c752 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -446,9 +446,6 @@
 	unsigned int uaa_addr;
 	struct sk_buff *skb = NULL;
 	__u16 misr;
-#if STREAMER_DEBUG
-	DECLARE_MAC_BUF(mac);
-#endif
 
 	streamer_priv = netdev_priv(dev);
 	streamer_mmio = streamer_priv->streamer_mmio;
@@ -577,8 +574,7 @@
 			dev->dev_addr[i+1]= addr & 0xff;
 		}
 #if STREAMER_DEBUG
-		printk("Adapter address: %s\n",
-		       print_mac(mac, dev->dev_addr));
+		printk("Adapter address: %pM\n", dev->dev_addr);
 #endif
 	}
 	return 0;
@@ -1013,7 +1009,6 @@
 					/* send up to the protocol */
 					netif_rx(skb);
 				}
-				dev->last_rx = jiffies;
 				streamer_priv->streamer_stats.rx_packets++;
 				streamer_priv->streamer_stats.rx_bytes += length;
 			}	/* if skb == null */
@@ -1538,7 +1533,6 @@
 
 #if STREAMER_NETWORK_MONITOR
 	struct trh_hdr *mac_hdr;
-	DECLARE_MAC_BUF(mac);
 #endif
 
 	writew(streamer_priv->arb, streamer_mmio + LAPA);
@@ -1611,11 +1605,11 @@
 		       dev->name);
 		mac_hdr = tr_hdr(mac_frame);
 		printk(KERN_WARNING
-		       "%s: MAC Frame Dest. Addr: %s\n",
-		       dev->name, print_mac(mac, mac_hdr->daddr));
+		       "%s: MAC Frame Dest. Addr: %pM\n",
+		       dev->name, mac_hdr->daddr);
 		printk(KERN_WARNING
-		       "%s: MAC Frame Srce. Addr: %s\n",
-		       dev->name, DEV->ADDR6(mac_hdr->saddr));
+		       "%s: MAC Frame Srce. Addr: %pM\n",
+		       dev->name, mac_hdr->saddr);
 #endif
 		netif_rx(mac_frame);
 
@@ -1850,8 +1844,6 @@
 	struct streamer_parameters_table spt;
 	int size = 0;
 	int i;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
 
 	writew(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA);
 	for (i = 0; i < 14; i += 2) {
@@ -1873,9 +1865,8 @@
 	size = sprintf(buffer, "\n%6s: Adapter Address   : Node Address      : Functional Addr\n", dev->name);
 
 	size += sprintf(buffer + size,
-			"%6s: %s : %s : %02x:%02x:%02x:%02x\n",
-			dev->name, print_mac(mac, dev->dev_addr),
-			print_mac(mac2, sat.node_addr),
+			"%6s: %pM : %pM : %02x:%02x:%02x:%02x\n",
+			dev->name, dev->dev_addr, sat.node_addr,
 			sat.func_addr[0], sat.func_addr[1],
 			sat.func_addr[2], sat.func_addr[3]);
 
@@ -1884,19 +1875,18 @@
 	size += sprintf(buffer + size, "%6s: Physical Addr : Up Node Address   : Poll Address      : AccPri : Auth Src : Att Code :\n", dev->name);
 
 	size += sprintf(buffer + size,
-		    "%6s: %02x:%02x:%02x:%02x   : %s : %s : %04x   : %04x     :  %04x    :\n",
+		    "%6s: %02x:%02x:%02x:%02x   : %pM : %pM : %04x   : %04x     :  %04x    :\n",
 		    dev->name, spt.phys_addr[0], spt.phys_addr[1],
 		    spt.phys_addr[2], spt.phys_addr[3],
-		    print_mac(mac, spt.up_node_addr),
-		    print_mac(mac2, spt.poll_addr),
+		    spt.up_node_addr, spt.poll_addr,
 		    ntohs(spt.acc_priority), ntohs(spt.auth_source_class),
 		    ntohs(spt.att_code));
 
 	size += sprintf(buffer + size, "%6s: Source Address    : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name);
 
 	size += sprintf(buffer + size,
-		    "%6s: %s : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
-		    dev->name, print_mac(mac, spt.source_addr),
+		    "%6s: %pM : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
+		    dev->name, spt.source_addr,
 		    ntohs(spt.beacon_type), ntohs(spt.major_vector),
 		    ntohs(spt.lan_status), ntohs(spt.local_ring),
 		    ntohs(spt.mon_error), ntohs(spt.frame_correl));
@@ -1905,10 +1895,10 @@
 		    dev->name);
 
 	size += sprintf(buffer + size,
-		    "%6s:                :  %02x  :  %02x  : %s : %02x:%02x:%02x:%02x    : \n",
+		    "%6s:                :  %02x  :  %02x  : %pM : %02x:%02x:%02x:%02x    : \n",
 		    dev->name, ntohs(spt.beacon_transmit),
 		    ntohs(spt.beacon_receive),
-		    print_mac(mac, spt.beacon_naun),
+		    spt.beacon_naun,
 		    spt.beacon_phys[0], spt.beacon_phys[1],
 		    spt.beacon_phys[2], spt.beacon_phys[3]);
 	return size;
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index c9c5a2b..917b4d2 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -152,7 +152,6 @@
 	struct card_info *card;
 	struct mca_device *mdev = to_mca_device(device);
 	int ret = 0;
-	DECLARE_MAC_BUF(mac);
 
 	if (versionprinted++ == 0)
 		printk("%s", version);
@@ -323,8 +322,8 @@
 	mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME);
 	mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev);
 
-	printk("%s:     Ring Station Address: %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk("%s:     Ring Station Address: %pM\n",
+	       dev->name, dev->dev_addr);
 
 	if (tmsdev_init(dev, device)) {
 		printk("%s: unable to get memory for dev->priv.\n", 
@@ -467,7 +466,7 @@
  * zero to leave the TMS NSELOUT bits unaffected.
  *
  */
-unsigned short madgemc_setnselout_pins(struct net_device *dev)
+static unsigned short madgemc_setnselout_pins(struct net_device *dev)
 {
 	unsigned char reg1;
 	struct net_local *tp = netdev_priv(dev);
@@ -690,7 +689,6 @@
 	struct net_local *tp = netdev_priv(dev);
 	struct card_info *curcard = tp->tmspriv;
 	int len = 0;
-	DECLARE_MAC_BUF(mac);
 	
 	len += sprintf(buf+len, "-------\n");
 	if (curcard) {
@@ -714,8 +712,8 @@
 		}
 		len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair");
 		
-		len += sprintf(buf+len, "Ring Station Address: %s\n",
-			       print_mac(mac, dev->dev_addr));
+		len += sprintf(buf+len, "Ring Station Address: %pM\n",
+			       dev->dev_addr);
 	} else 
 		len += sprintf(buf+len, "Card not configured\n");
 
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 0ab51a0..ecb5c7c 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -421,10 +421,7 @@
 	memcpy_fromio(&dev->dev_addr[0], adapter_addr,6);
 
 #if OLYMPIC_DEBUG
- {
-	DECLARE_MAC_BUF(mac);
-	printk("adapter address: %s\n", print_mac(mac, dev->dev_addr));
- }
+	printk("adapter address: %pM\n", dev->dev_addr);
 #endif
 
 	olympic_priv->olympic_addr_table_addr = swab16(readw(init_srb + 12)); 
@@ -441,7 +438,6 @@
 	unsigned long flags, t;
 	int i, open_finished = 1 ;
 	u8 resp, err;
-	DECLARE_MAC_BUF(mac);
 
 	DECLARE_WAITQUEUE(wait,current) ; 
 
@@ -569,8 +565,8 @@
 			goto out;
 
 		case 0x32:
-			printk(KERN_WARNING "%s: Invalid LAA: %s\n",
-			       dev->name, print_mac(mac, olympic_priv->olympic_laa));
+			printk(KERN_WARNING "%s: Invalid LAA: %pM\n",
+			       dev->name, olympic_priv->olympic_laa);
 			goto out;
 
 		default:
@@ -704,13 +700,12 @@
 		u8 __iomem *opt;
 		int i;
 		u8 addr[6];
-		DECLARE_MAC_BUF(mac);
 		oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr);
 		opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr);
 
 		for (i = 0; i < 6; i++)
 			addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+i);
-		printk("%s: Node Address: %s\n",dev->name, print_mac(mac, addr));
+		printk("%s: Node Address: %pM\n", dev->name, addr);
 		printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, 
 			readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
 			readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
@@ -719,7 +714,7 @@
 
 		for (i = 0; i < 6; i++)
 			addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+i);
-		printk("%s: NAUN Address: %s\n",dev->name, print_mac(mac, addr));
+		printk("%s: NAUN Address: %pM\n", dev->name, addr);
 	}
 	
 	netif_start_queue(dev);
@@ -867,7 +862,6 @@
 						skb->protocol = tr_type_trans(skb,dev);
 						netif_rx(skb) ; 
 					} 
-					dev->last_rx = jiffies ; 
 					olympic_priv->olympic_stats.rx_packets++ ; 
 					olympic_priv->olympic_stats.rx_bytes += length ; 
 				} /* if skb == null */
@@ -1440,19 +1434,12 @@
 			struct trh_hdr *mac_hdr;
 			printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name);
 			mac_hdr = tr_hdr(mac_frame);
-			printk(KERN_WARNING "%s: MAC Frame Dest. Addr: "
-			       MAC_FMT " \n", dev->name,
-			       mac_hdr->daddr[0], mac_hdr->daddr[1],
-			       mac_hdr->daddr[2], mac_hdr->daddr[3],
-			       mac_hdr->daddr[4], mac_hdr->daddr[5]);
-			printk(KERN_WARNING "%s: MAC Frame Srce. Addr: "
-			       MAC_FMT " \n", dev->name,
-			       mac_hdr->saddr[0], mac_hdr->saddr[1],
-			       mac_hdr->saddr[2], mac_hdr->saddr[3],
-			       mac_hdr->saddr[4], mac_hdr->saddr[5]);
+			printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %pM\n",
+			       dev->name, mac_hdr->daddr);
+			printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %pM\n",
+			       dev->name, mac_hdr->saddr);
 		}
 		netif_rx(mac_frame);
-		dev->last_rx = jiffies;
 
 drop_frame:
 		/* Now tell the card we have dealt with the received frame */
@@ -1647,8 +1634,6 @@
 	u8 addr[6];
 	u8 addr2[6];
 	int i;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
 
 	size = sprintf(buffer, 
 		"IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name);
@@ -1658,10 +1643,9 @@
 	for (i = 0 ; i < 6 ; i++)
 		addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr) + i);
 
-	size += sprintf(buffer+size, "%6s: %s : %s : %02x:%02x:%02x:%02x\n",
+	size += sprintf(buffer+size, "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n",
 	   dev->name,
-	   print_mac(mac, dev->dev_addr),
-	   print_mac(mac2, addr),
+	   dev->dev_addr, addr,
 	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
 	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
 	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
@@ -1677,14 +1661,13 @@
 	for (i = 0 ; i < 6 ; i++)
 		addr2[i] =  readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i);
 
-	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x   : %s : %s : %04x   : %04x     :  %04x    :\n",
+	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x   : %pM : %pM : %04x   : %04x     :  %04x    :\n",
 	  dev->name,
 	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)),
 	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1),
 	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2),
 	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3),
-	  print_mac(mac, addr),
-	  print_mac(mac2, addr2),
+	  addr, addr2,
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code))));
@@ -1694,9 +1677,8 @@
 	
 	for (i = 0 ; i < 6 ; i++)
 		addr[i] = readb(opt+offsetof(struct olympic_parameters_table, source_addr) + i);
-	size += sprintf(buffer+size, "%6s: %s : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
-	  dev->name,
-	  print_mac(mac, addr),
+	size += sprintf(buffer+size, "%6s: %pM : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
+	  dev->name, addr,
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, lan_status))),
@@ -1709,11 +1691,11 @@
 
 	for (i = 0 ; i < 6 ; i++)
 		addr[i] = readb(opt+offsetof(struct olympic_parameters_table, beacon_naun) + i);
-	size += sprintf(buffer+size, "%6s:                :  %02x  :  %02x  : %s : %02x:%02x:%02x:%02x    : \n",
+	size += sprintf(buffer+size, "%6s:                :  %02x  :  %02x  : %pM : %02x:%02x:%02x:%02x    : \n",
 	  dev->name,
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))),
-	  print_mac(mac, addr),
+	  addr,
 	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)),
 	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1),
 	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2),
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
index 00ea945..b8c955f 100644
--- a/drivers/net/tokenring/proteon.c
+++ b/drivers/net/tokenring/proteon.c
@@ -122,7 +122,6 @@
         static int versionprinted;
 	const unsigned *port;
 	int j,err = 0;
-	DECLARE_MAC_BUF(mac);
 
 	if (!dev)
 		return -ENOMEM;
@@ -153,8 +152,8 @@
 		
 	proteon_read_eeprom(dev);
 
-	printk(KERN_DEBUG "proteon.c:    Ring Station Address: %s\n",
-	       print_mac(mac, dev->dev_addr));
+	printk(KERN_DEBUG "proteon.c:    Ring Station Address: %pM\n",
+	       dev->dev_addr);
 		
 	tp = netdev_priv(dev);
 	tp->setnselout = proteon_setnselout_pins;
@@ -284,7 +283,7 @@
 		dev->dev_addr[i] = proteon_sifreadw(dev, SIFINC) >> 8;
 }
 
-unsigned short proteon_setnselout_pins(struct net_device *dev)
+static unsigned short proteon_setnselout_pins(struct net_device *dev)
 {
 	return 0;
 }
diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c
index 41b6999..c0f58f0 100644
--- a/drivers/net/tokenring/skisa.c
+++ b/drivers/net/tokenring/skisa.c
@@ -139,7 +139,6 @@
         static int versionprinted;
 	const unsigned *port;
 	int j, err = 0;
-	DECLARE_MAC_BUF(mac);
 
 	if (!dev)
 		return -ENOMEM;
@@ -170,8 +169,8 @@
 		
 	sk_isa_read_eeprom(dev);
 
-	printk(KERN_DEBUG "skisa.c:    Ring Station Address: %s\n",
-	       print_mac(mac, dev->dev_addr));
+	printk(KERN_DEBUG "skisa.c:    Ring Station Address: %pM\n",
+	       dev->dev_addr);
 		
 	tp = netdev_priv(dev);
 	tp->setnselout = sk_isa_setnselout_pins;
@@ -301,7 +300,7 @@
 		dev->dev_addr[i] = sk_isa_sifreadw(dev, SIFINC) >> 8;
 }
 
-unsigned short sk_isa_setnselout_pins(struct net_device *dev)
+static unsigned short sk_isa_setnselout_pins(struct net_device *dev)
 {
 	return 0;
 }
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index ed50d28..a011666 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -3910,7 +3910,6 @@
                 /* Kick the packet on up. */
                 skb->protocol = tr_type_trans(skb, dev);
                 netif_rx(skb);
-		dev->last_rx = jiffies;
                 err = 0;
         }
 
@@ -4496,7 +4495,6 @@
                                 	/* Kick the packet on up. */
                                 	skb->protocol = tr_type_trans(skb, dev);
                                 	netif_rx(skb);
-					dev->last_rx = jiffies;
 				} else {
 				}
                         }
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index d07c452..5be34c2 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -180,10 +180,14 @@
 static void 	tms380tr_write_rpl_status(RPL *rpl, unsigned int Status);
 static void 	tms380tr_write_tpl_status(TPL *tpl, unsigned int Status);
 
-#define SIFREADB(reg) (((struct net_local *)dev->priv)->sifreadb(dev, reg))
-#define SIFWRITEB(val, reg) (((struct net_local *)dev->priv)->sifwriteb(dev, val, reg))
-#define SIFREADW(reg) (((struct net_local *)dev->priv)->sifreadw(dev, reg))
-#define SIFWRITEW(val, reg) (((struct net_local *)dev->priv)->sifwritew(dev, val, reg))
+#define SIFREADB(reg) \
+	(((struct net_local *)netdev_priv(dev))->sifreadb(dev, reg))
+#define SIFWRITEB(val, reg) \
+	(((struct net_local *)netdev_priv(dev))->sifwriteb(dev, val, reg))
+#define SIFREADW(reg) \
+	(((struct net_local *)netdev_priv(dev))->sifreadw(dev, reg))
+#define SIFWRITEW(val, reg) \
+	(((struct net_local *)netdev_priv(dev))->sifwritew(dev, val, reg))
 
 
 
@@ -2186,7 +2190,6 @@
 				skb_trim(skb,Length);
 				skb->protocol = tr_type_trans(skb,dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 			}
 		}
 		else	/* Invalid frame */
@@ -2331,7 +2334,7 @@
 {
 	struct net_local *tms_local;
 
-	memset(dev->priv, 0, sizeof(struct net_local));
+	memset(netdev_priv(dev), 0, sizeof(struct net_local));
 	tms_local = netdev_priv(dev);
 	init_waitqueue_head(&tms_local->wait_for_tok_int);
 	if (pdev->dma_mask)
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index 5f0ee88..5f60177 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -100,7 +100,6 @@
 	unsigned int pci_irq_line;
 	unsigned long pci_ioaddr;
 	struct card_info *cardinfo = &card_info_table[ent->driver_data];
-	DECLARE_MAC_BUF(mac);
 
 	if (versionprinted++ == 0)
 		printk("%s", version);
@@ -137,8 +136,8 @@
 		
 	tms_pci_read_eeprom(dev);
 
-	printk("%s:    Ring Station Address: %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk("%s:    Ring Station Address: %pM\n",
+	       dev->name, dev->dev_addr);
 		
 	ret = tmsdev_init(dev, &pdev->dev);
 	if (ret) {
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index eb1da6f..75461db 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -788,7 +788,6 @@
 		skb_put(skb, data->rxring[rx].len);
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_receive_skb(skb);
-		dev->last_rx = jiffies;
 	}
 
 	return done;
@@ -889,7 +888,7 @@
 
 	if (num_received < budget) {
 		data->rxpending = 0;
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 
 		TSI_WRITE(TSI108_EC_INTMASK,
 				     TSI_READ(TSI108_EC_INTMASK)
@@ -920,7 +919,7 @@
 	 * from tsi108_check_rxring().
 	 */
 
-	if (netif_rx_schedule_prep(dev, &data->napi)) {
+	if (netif_rx_schedule_prep(&data->napi)) {
 		/* Mask, rather than ack, the receive interrupts.  The ack
 		 * will happen in tsi108_poll().
 		 */
@@ -931,7 +930,7 @@
 				     | TSI108_INT_RXTHRESH |
 				     TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR |
 				     TSI108_INT_RXWAIT);
-		__netif_rx_schedule(dev, &data->napi);
+		__netif_rx_schedule(&data->napi);
 	} else {
 		if (!netif_running(dev)) {
 			/* This can happen if an interrupt occurs while the
@@ -1569,7 +1568,6 @@
 	struct tsi108_prv_data *data = NULL;
 	hw_info *einfo;
 	int err = 0;
-	DECLARE_MAC_BUF(mac);
 
 	einfo = pdev->dev.platform_data;
 
@@ -1659,8 +1657,8 @@
 	}
 
 	platform_set_drvdata(pdev, dev);
-	printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %pM\n",
+	       dev->name, dev->dev_addr);
 #ifdef DEBUG
 	data->msg_enable = DEBUG;
 	dump_eth_one(dev);
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 124d5d6..5166be9 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -459,7 +459,6 @@
 
 		de->net_stats.rx_packets++;
 		de->net_stats.rx_bytes += skb->len;
-		de->dev->last_rx = jiffies;
 		rc = netif_rx (skb);
 		if (rc == NET_RX_DROP)
 			drop = 1;
@@ -484,7 +483,7 @@
 static irqreturn_t de_interrupt (int irq, void *dev_instance)
 {
 	struct net_device *dev = dev_instance;
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 	u32 status;
 
 	status = dr32(MacStatus);
@@ -590,7 +589,7 @@
 
 static int de_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 	unsigned int entry, tx_free;
 	u32 mapping, len, flags = FirstFrag | LastFrag;
 	struct de_desc *txd;
@@ -653,7 +652,7 @@
 
 static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 	u16 hash_table[32];
 	struct dev_mc_list *mclist;
 	int i;
@@ -684,7 +683,7 @@
 
 static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 	struct dev_mc_list *mclist;
 	int i;
 	u16 *eaddrs;
@@ -712,7 +711,7 @@
 
 static void __de_set_rx_mode (struct net_device *dev)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 	u32 macmode;
 	unsigned int entry;
 	u32 mapping;
@@ -797,7 +796,7 @@
 static void de_set_rx_mode (struct net_device *dev)
 {
 	unsigned long flags;
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 
 	spin_lock_irqsave (&de->lock, flags);
 	__de_set_rx_mode(dev);
@@ -821,7 +820,7 @@
 
 static struct net_device_stats *de_get_stats(struct net_device *dev)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 
 	/* The chip only need report frame silently dropped. */
 	spin_lock_irq(&de->lock);
@@ -1355,7 +1354,7 @@
 
 static int de_open (struct net_device *dev)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 	int rc;
 
 	if (netif_msg_ifup(de))
@@ -1400,7 +1399,7 @@
 
 static int de_close (struct net_device *dev)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 	unsigned long flags;
 
 	if (netif_msg_ifdown(de))
@@ -1423,7 +1422,7 @@
 
 static void de_tx_timeout (struct net_device *dev)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 
 	printk(KERN_DEBUG "%s: NIC status %08x mode %08x sia %08x desc %u/%u/%u\n",
 	       dev->name, dr32(MacStatus), dr32(MacMode), dr32(SIAStatus),
@@ -1574,7 +1573,7 @@
 
 static void de_get_drvinfo (struct net_device *dev,struct ethtool_drvinfo *info)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 
 	strcpy (info->driver, DRV_NAME);
 	strcpy (info->version, DRV_VERSION);
@@ -1589,7 +1588,7 @@
 
 static int de_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 	int rc;
 
 	spin_lock_irq(&de->lock);
@@ -1601,7 +1600,7 @@
 
 static int de_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 	int rc;
 
 	spin_lock_irq(&de->lock);
@@ -1613,14 +1612,14 @@
 
 static u32 de_get_msglevel(struct net_device *dev)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 
 	return de->msg_enable;
 }
 
 static void de_set_msglevel(struct net_device *dev, u32 msglvl)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 
 	de->msg_enable = msglvl;
 }
@@ -1628,7 +1627,7 @@
 static int de_get_eeprom(struct net_device *dev,
 			 struct ethtool_eeprom *eeprom, u8 *data)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 
 	if (!de->ee_data)
 		return -EOPNOTSUPP;
@@ -1642,7 +1641,7 @@
 
 static int de_nway_reset(struct net_device *dev)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 	u32 status;
 
 	if (de->media_type != DE_MEDIA_TP_AUTO)
@@ -1661,7 +1660,7 @@
 static void de_get_regs(struct net_device *dev, struct ethtool_regs *regs,
 			void *data)
 {
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 
 	regs->version = (DE_REGS_VER << 2) | de->de21040;
 
@@ -1692,9 +1691,9 @@
 
 	for (i = 0; i < 6; i++) {
 		int value, boguscnt = 100000;
-		do
+		do {
 			value = dr32(ROMCmd);
-		while (value < 0 && --boguscnt > 0);
+		} while (value < 0 && --boguscnt > 0);
 		de->dev->dev_addr[i] = value;
 		udelay(1);
 		if (boguscnt <= 0)
@@ -1932,7 +1931,6 @@
 	void __iomem *regs;
 	unsigned long pciaddr;
 	static int board_idx = -1;
-	DECLARE_MAC_BUF(mac);
 
 	board_idx++;
 
@@ -1956,7 +1954,7 @@
 	dev->tx_timeout = de_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
-	de = dev->priv;
+	de = netdev_priv(dev);
 	de->de21040 = ent->driver_data == 0 ? 1 : 0;
 	de->pdev = pdev;
 	de->dev = dev;
@@ -2046,11 +2044,11 @@
 		goto err_out_iomap;
 
 	/* print info about board and interface just registered */
-	printk (KERN_INFO "%s: %s at 0x%lx, %s, IRQ %d\n",
+	printk (KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n",
 		dev->name,
 		de->de21040 ? "21040" : "21041",
 		dev->base_addr,
-		print_mac(mac, dev->dev_addr),
+		dev->dev_addr,
 		dev->irq);
 
 	pci_set_drvdata(pdev, dev);
@@ -2078,7 +2076,7 @@
 static void __devexit de_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 
 	BUG_ON(!dev);
 	unregister_netdev(dev);
@@ -2095,7 +2093,7 @@
 static int de_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 
 	rtnl_lock();
 	if (netif_running (dev)) {
@@ -2130,7 +2128,7 @@
 static int de_resume (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
-	struct de_private *de = dev->priv;
+	struct de_private *de = netdev_priv(dev);
 	int retval = 0;
 
 	rtnl_lock();
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 6444cbe..67bfd6f 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -1085,7 +1085,6 @@
     struct de4x5_private *lp = netdev_priv(dev);
     struct pci_dev *pdev = NULL;
     int i, status=0;
-    DECLARE_MAC_BUF(mac);
 
     gendev->driver_data = dev;
 
@@ -1119,10 +1118,10 @@
     }
 
     dev->base_addr = iobase;
-    printk ("%s: %s at 0x%04lx", gendev->bus_id, name, iobase);
+    printk ("%s: %s at 0x%04lx", dev_name(gendev), name, iobase);
 
     status = get_hw_addr(dev);
-    printk(", h/w address %s\n", print_mac(mac, dev->dev_addr));
+    printk(", h/w address %pM\n", dev->dev_addr);
 
     if (status != 0) {
 	printk("      which has an Ethernet PROM CRC error.\n");
@@ -1154,7 +1153,7 @@
             }
         }
 	lp->fdx = lp->params.fdx;
-	sprintf(lp->adapter_name,"%s (%s)", name, gendev->bus_id);
+	sprintf(lp->adapter_name,"%s (%s)", name, dev_name(gendev));
 
 	lp->dma_size = (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc);
 #if defined(__alpha__) || defined(__powerpc__) || defined(CONFIG_SPARC) || defined(DE4X5_DO_MEMCPY)
@@ -1647,7 +1646,6 @@
 		    netif_rx(skb);
 
 		    /* Update stats */
-		    dev->last_rx = jiffies;
 		    lp->stats.rx_packets++;
  		    lp->stats.rx_bytes += pkt_len;
 		}
@@ -5401,7 +5399,6 @@
 de4x5_dbg_srom(struct de4x5_srom *p)
 {
     int i;
-    DECLARE_MAC_BUF(mac);
 
     if (de4x5_debug & DEBUG_SROM) {
 	printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id));
@@ -5410,7 +5407,7 @@
 	printk("SROM version:         %02x\n", (u_char)(p->version));
 	printk("# controllers:        %02x\n", (u_char)(p->num_controllers));
 
-	printk("Hardware Address:     %s\n", print_mac(mac, p->ieee_addr));
+	printk("Hardware Address:     %pM\n", p->ieee_addr);
 	printk("CRC checksum:         %04x\n", (u_short)(p->chksum));
 	for (i=0; i<64; i++) {
 	    printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i));
@@ -5424,12 +5421,10 @@
 de4x5_dbg_rx(struct sk_buff *skb, int len)
 {
     int i, j;
-    DECLARE_MAC_BUF(mac);
-    DECLARE_MAC_BUF(mac2);
 
     if (de4x5_debug & DEBUG_RX) {
-	printk("R: %s <- %s len/SAP:%02x%02x [%d]\n",
-	       print_mac(mac, skb->data), print_mac(mac2, &skb->data[6]),
+	printk("R: %pM <- %pM len/SAP:%02x%02x [%d]\n",
+	       skb->data, &skb->data[6],
 	       (u_char)skb->data[12],
 	       (u_char)skb->data[13],
 	       len);
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index c91852f..28a5c51 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -362,7 +362,6 @@
 	struct net_device *dev;
 	u32 pci_pmr;
 	int i, err;
-	DECLARE_MAC_BUF(mac);
 
 	DMFE_DBUG(0, "dmfe_init_one()", 0);
 
@@ -475,12 +474,11 @@
 	if (err)
 		goto err_out_free_buf;
 
-	printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, "
-	       "%s, irq %d.\n",
+	printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, %pM, irq %d.\n",
 	       dev->name,
 	       ent->driver_data >> 16,
 	       pci_name(pdev),
-	       print_mac(mac, dev->dev_addr),
+	       dev->dev_addr,
 	       dev->irq);
 
 	pci_set_master(pdev);
@@ -1010,7 +1008,6 @@
 
 					skb->protocol = eth_type_trans(skb, dev);
 					netif_rx(skb);
-					dev->last_rx = jiffies;
 					db->stats.rx_packets++;
 					db->stats.rx_bytes += rxlen;
 				}
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
index 0dcced1..391acd3 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/tulip/eeprom.c
@@ -337,7 +337,7 @@
 {
 	int i;
 	unsigned retval = 0;
-	struct tulip_private *tp = dev->priv;
+	struct tulip_private *tp = netdev_priv(dev);
 	void __iomem *ee_addr = tp->base_addr + CSR9;
 	int read_cmd = location | (EE_READ_CMD << addr_len);
 
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index c6bad98..6c3428a 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -103,7 +103,7 @@
 {
         struct net_device *dev = (struct net_device *)data;
 	struct tulip_private *tp = netdev_priv(dev);
-	netif_rx_schedule(dev, &tp->napi);
+	netif_rx_schedule(&tp->napi);
 }
 
 int tulip_poll(struct napi_struct *napi, int budget)
@@ -231,7 +231,6 @@
 
                                netif_receive_skb(skb);
 
-                               dev->last_rx = jiffies;
                                tp->stats.rx_packets++;
                                tp->stats.rx_bytes += pkt_len;
                        }
@@ -301,7 +300,7 @@
 
          /* Remove us from polling list and enable RX intr. */
 
-         netif_rx_complete(dev, napi);
+         netif_rx_complete(napi);
          iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7);
 
          /* The last op happens after poll completion. Which means the following:
@@ -337,7 +336,7 @@
           * before we did netif_rx_complete(). See? We would lose it. */
 
          /* remove ourselves from the polling list */
-         netif_rx_complete(dev, napi);
+         netif_rx_complete(napi);
 
          return work_done;
 }
@@ -444,7 +443,6 @@
 
 			netif_rx(skb);
 
-			dev->last_rx = jiffies;
 			tp->stats.rx_packets++;
 			tp->stats.rx_bytes += pkt_len;
 		}
@@ -521,7 +519,7 @@
 			rxd++;
 			/* Mask RX intrs and add the device to poll list. */
 			iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7);
-			netif_rx_schedule(dev, &tp->napi);
+			netif_rx_schedule(&tp->napi);
 
 			if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass)))
                                break;
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index cafa89e..ff84bab 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1050,13 +1050,11 @@
 					filterbit = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
 				filterbit &= 0x3f;
 				mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
-				if (tulip_debug > 2) {
-					DECLARE_MAC_BUF(mac);
-					printk(KERN_INFO "%s: Added filter for %s"
+				if (tulip_debug > 2)
+					printk(KERN_INFO "%s: Added filter for %pM"
 					       "  %8.8x bit %d.\n",
-					       dev->name, print_mac(mac, mclist->dmi_addr),
+					       dev->name, mclist->dmi_addr,
 					       ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
-				}
 			}
 			if (mc_filter[0] == tp->mc_filter[0]  &&
 				mc_filter[1] == tp->mc_filter[1])
@@ -1250,7 +1248,6 @@
 	const char *chip_name = tulip_tbl[chip_idx].chip_name;
 	unsigned int eeprom_missing = 0;
 	unsigned int force_csr0 = 0;
-	DECLARE_MAC_BUF(mac);
 
 #ifndef MODULE
 	static int did_version;		/* Already printed version info. */
@@ -1432,9 +1429,9 @@
 		for (i = 0; i < 3; i++) {
 			int value, boguscnt = 100000;
 			iowrite32(0x600 | i, ioaddr + 0x98);
-			do
+			do {
 				value = ioread32(ioaddr + CSR9);
-			while (value < 0  && --boguscnt > 0);
+			} while (value < 0  && --boguscnt > 0);
 			put_unaligned_le16(value, ((__le16 *)dev->dev_addr) + i);
 			sum += value & 0xffff;
 		}
@@ -1635,7 +1632,7 @@
 
 	if (eeprom_missing)
 		printk(" EEPROM not present,");
-	printk(" %s", print_mac(mac, dev->dev_addr));
+	printk(" %pM", dev->dev_addr);
 	printk(", IRQ %d.\n", irq);
 
         if (tp->chip_id == PNIC2)
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index e9e62862..00cbc52 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -261,7 +261,6 @@
 	struct uli526x_board_info *db;	/* board information structure */
 	struct net_device *dev;
 	int i, err;
-	DECLARE_MAC_BUF(mac);
 
 	ULI526X_DBUG(0, "uli526x_init_one()", 0);
 
@@ -379,9 +378,9 @@
 	if (err)
 		goto err_out_res;
 
-	printk(KERN_INFO "%s: ULi M%04lx at pci%s, %s, irq %d.\n",
+	printk(KERN_INFO "%s: ULi M%04lx at pci%s, %pM, irq %d.\n",
 	       dev->name,ent->driver_data >> 16,pci_name(pdev),
-	       print_mac(mac, dev->dev_addr), dev->irq);
+	       dev->dev_addr, dev->irq);
 
 	pci_set_master(pdev);
 
@@ -855,7 +854,6 @@
 
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
 				db->stats.rx_packets++;
 				db->stats.rx_bytes += rxlen;
 
@@ -892,7 +890,7 @@
 
 static void uli526x_set_filter_mode(struct net_device * dev)
 {
-	struct uli526x_board_info *db = dev->priv;
+	struct uli526x_board_info *db = netdev_priv(dev);
 	unsigned long flags;
 
 	ULI526X_DBUG(0, "uli526x_set_filter_mode()", 0);
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 5006819..022d99a 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -355,7 +355,6 @@
 	int irq;
 	int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
 	void __iomem *ioaddr;
-	DECLARE_MAC_BUF(mac);
 
 	i = pci_enable_device(pdev);
 	if (i) return i;
@@ -435,9 +434,9 @@
 	if (i)
 		goto err_out_cleardev;
 
-	printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+	printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n",
 	       dev->name, pci_id_tbl[chip_idx].name, ioaddr,
-	       print_mac(mac, dev->dev_addr), irq);
+	       dev->dev_addr, irq);
 
 	if (np->drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
@@ -1245,20 +1244,15 @@
 			}
 #ifndef final_version				/* Remove after testing. */
 			/* You will want this info for the initial debug. */
-			if (debug > 5) {
-				DECLARE_MAC_BUF(mac);
-				DECLARE_MAC_BUF(mac2);
-
-				printk(KERN_DEBUG "  Rx data %s %s"
+			if (debug > 5)
+				printk(KERN_DEBUG "  Rx data %pM %pM"
 				       " %2.2x%2.2x %d.%d.%d.%d.\n",
-				       print_mac(mac, &skb->data[0]), print_mac(mac2, &skb->data[6]),
+				       &skb->data[0], &skb->data[6],
 				       skb->data[12], skb->data[13],
 				       skb->data[14], skb->data[15], skb->data[16], skb->data[17]);
-			}
 #endif
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			np->stats.rx_packets++;
 			np->stats.rx_bytes += pkt_len;
 		}
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 6b93d016..13c8703 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -1072,7 +1072,6 @@
 	unsigned char j, tuple, link, data_id, data_count;
 	unsigned long flags;
 	int i;
-	DECLARE_MAC_BUF(mac);
 
 	enter("read_mac_address");
 
@@ -1102,7 +1101,7 @@
 		}
 	}
 	spin_unlock_irqrestore(&card->lock, flags);
-	pr_debug(" %s\n", print_mac(mac, card->dev->dev_addr));
+	pr_debug(" %pM\n", card->dev->dev_addr);
 	leave("read_mac_address");
 }
 
@@ -1202,7 +1201,6 @@
 			skb_put(skb, pkt_len);
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			card->stats.rx_packets++;
 			card->stats.rx_bytes += pkt_len;
 
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 33b6d1b..666c1d9 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -305,6 +305,23 @@
 	return 0;
 }
 
+static const struct net_device_ops tun_netdev_ops = {
+	.ndo_open		= tun_net_open,
+	.ndo_stop		= tun_net_close,
+	.ndo_start_xmit		= tun_net_xmit,
+	.ndo_change_mtu		= tun_net_change_mtu,
+};
+
+static const struct net_device_ops tap_netdev_ops = {
+	.ndo_open		= tun_net_open,
+	.ndo_stop		= tun_net_close,
+	.ndo_start_xmit		= tun_net_xmit,
+	.ndo_change_mtu		= tun_net_change_mtu,
+	.ndo_set_multicast_list	= tun_net_mclist,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+};
+
 /* Initialize net device. */
 static void tun_net_init(struct net_device *dev)
 {
@@ -312,11 +329,12 @@
 
 	switch (tun->flags & TUN_TYPE_MASK) {
 	case TUN_TUN_DEV:
+		dev->netdev_ops = &tun_netdev_ops;
+
 		/* Point-to-Point TUN Device */
 		dev->hard_header_len = 0;
 		dev->addr_len = 0;
 		dev->mtu = 1500;
-		dev->change_mtu = tun_net_change_mtu;
 
 		/* Zero header length */
 		dev->type = ARPHRD_NONE;
@@ -325,10 +343,9 @@
 		break;
 
 	case TUN_TAP_DEV:
+		dev->netdev_ops = &tun_netdev_ops;
 		/* Ethernet TAP Device */
 		ether_setup(dev);
-		dev->change_mtu         = tun_net_change_mtu;
-		dev->set_multicast_list = tun_net_mclist;
 
 		random_ether_addr(dev->dev_addr);
 
@@ -529,7 +546,6 @@
 	}
 
 	netif_rx_ni(skb);
-	tun->dev->last_rx = jiffies;
 
 	tun->dev->stats.rx_packets++;
 	tun->dev->stats.rx_bytes += len;
@@ -676,9 +692,6 @@
 	tun->owner = -1;
 	tun->group = -1;
 
-	dev->open = tun_net_open;
-	dev->hard_start_xmit = tun_net_xmit;
-	dev->stop = tun_net_close;
 	dev->ethtool_ops = &tun_ethtool_ops;
 	dev->destructor = free_netdev;
 	dev->features |= NETIF_F_NETNS_LOCAL;
@@ -702,6 +715,7 @@
 	struct tun_net *tn;
 	struct tun_struct *tun;
 	struct net_device *dev;
+	const struct cred *cred = current_cred();
 	int err;
 
 	tn = net_generic(net, tun_net_id);
@@ -712,11 +726,12 @@
 
 		/* Check permissions */
 		if (((tun->owner != -1 &&
-		      current->euid != tun->owner) ||
+		      cred->euid != tun->owner) ||
 		     (tun->group != -1 &&
-		      current->egid != tun->group)) &&
-		     !capable(CAP_NET_ADMIN))
+		      cred->egid != tun->group)) &&
+		    !capable(CAP_NET_ADMIN)) {
 			return -EPERM;
+		}
 	}
 	else if (__dev_get_by_name(net, ifr->ifr_name))
 		return -EINVAL;
@@ -750,6 +765,7 @@
 			return -ENOMEM;
 
 		dev_net_set(dev, net);
+
 		tun = netdev_priv(dev);
 		tun->dev = dev;
 		tun->flags = flags;
@@ -883,7 +899,6 @@
 	void __user* argp = (void __user*)arg;
 	struct ifreq ifr;
 	int ret;
-	DECLARE_MAC_BUF(mac);
 
 	if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89)
 		if (copy_from_user(&ifr, argp, sizeof ifr))
@@ -1011,8 +1026,8 @@
 
 	case SIOCSIFHWADDR:
 		/* Set hw address */
-		DBG(KERN_DEBUG "%s: set hw address: %s\n",
-			tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
+		DBG(KERN_DEBUG "%s: set hw address: %pM\n",
+			tun->dev->name, ifr.ifr_hwaddr.sa_data);
 
 		rtnl_lock();
 		ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr);
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 734ce09..0009f4e 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -1729,7 +1729,6 @@
 			netif_receive_skb(new_skb);
 		spin_unlock(&tp->state_lock);
 
-		tp->dev->last_rx = jiffies;
 		received++;
 		budget--;
 	}
@@ -1756,7 +1755,6 @@
 typhoon_poll(struct napi_struct *napi, int budget)
 {
 	struct typhoon *tp = container_of(napi, struct typhoon, napi);
-	struct net_device *dev = tp->dev;
 	struct typhoon_indexes *indexes = tp->indexes;
 	int work_done;
 
@@ -1785,7 +1783,7 @@
 	}
 
 	if (work_done < budget) {
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		iowrite32(TYPHOON_INTR_NONE,
 				tp->ioaddr + TYPHOON_REG_INTR_MASK);
 		typhoon_post_pci_writes(tp->ioaddr);
@@ -1798,7 +1796,7 @@
 typhoon_interrupt(int irq, void *dev_instance)
 {
 	struct net_device *dev = dev_instance;
-	struct typhoon *tp = dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 	void __iomem *ioaddr = tp->ioaddr;
 	u32 intr_status;
 
@@ -1808,10 +1806,10 @@
 
 	iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS);
 
-	if (netif_rx_schedule_prep(dev, &tp->napi)) {
+	if (netif_rx_schedule_prep(&tp->napi)) {
 		iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
 		typhoon_post_pci_writes(ioaddr);
-		__netif_rx_schedule(dev, &tp->napi);
+		__netif_rx_schedule(&tp->napi);
 	} else {
 		printk(KERN_ERR "%s: Error, poll already scheduled\n",
                        dev->name);
@@ -2311,7 +2309,6 @@
 	struct cmd_desc xp_cmd;
 	struct resp_desc xp_resp[3];
 	int err = 0;
-	DECLARE_MAC_BUF(mac);
 
 	if(!did_version++)
 		printk(KERN_INFO "%s", version);
@@ -2526,11 +2523,11 @@
 
 	pci_set_drvdata(pdev, dev);
 
-	printk(KERN_INFO "%s: %s at %s 0x%llx, %s\n",
+	printk(KERN_INFO "%s: %s at %s 0x%llx, %pM\n",
 	       dev->name, typhoon_card_info[card_id].name,
 	       use_mmio ? "MMIO" : "IO",
 	       (unsigned long long)pci_resource_start(pdev, use_mmio),
-	       print_mac(mac, dev->dev_addr));
+	       dev->dev_addr);
 
 	/* xp_resp still contains the response to the READ_VERSIONS command.
 	 * For debugging, let the user know what version he has.
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index c87747b..7d5a130 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -188,17 +188,6 @@
 }
 #endif /* DEBUG */
 
-#ifdef CONFIG_UGETH_FILTERING
-static void enqueue(struct list_head *node, struct list_head *lh)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ugeth_lock, flags);
-	list_add_tail(node, lh);
-	spin_unlock_irqrestore(&ugeth_lock, flags);
-}
-#endif /* CONFIG_UGETH_FILTERING */
-
 static struct list_head *dequeue(struct list_head *lh)
 {
 	unsigned long flags;
@@ -391,23 +380,6 @@
 }
 #endif
 
-#ifdef CONFIG_UGETH_FILTERING
-static struct enet_addr_container *get_enet_addr_container(void)
-{
-	struct enet_addr_container *enet_addr_cont;
-
-	/* allocate memory */
-	enet_addr_cont = kmalloc(sizeof(struct enet_addr_container), GFP_KERNEL);
-	if (!enet_addr_cont) {
-		ugeth_err("%s: No memory for enet_addr_container object.",
-			  __func__);
-		return NULL;
-	}
-
-	return enet_addr_cont;
-}
-#endif /* CONFIG_UGETH_FILTERING */
-
 static void put_enet_addr_container(struct enet_addr_container *enet_addr_cont)
 {
 	kfree(enet_addr_cont);
@@ -420,28 +392,6 @@
 	out_be16(&reg[2], ((u16)mac[1] << 8) | mac[0]);
 }
 
-#ifdef CONFIG_UGETH_FILTERING
-static int hw_add_addr_in_paddr(struct ucc_geth_private *ugeth,
-                                u8 *p_enet_addr, u8 paddr_num)
-{
-	struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
-
-	if (!(paddr_num < NUM_OF_PADDRS)) {
-		ugeth_warn("%s: Illegal paddr_num.", __func__);
-		return -EINVAL;
-	}
-
-	p_82xx_addr_filt =
-	    (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
-	    addressfiltering;
-
-	/* Ethernet frames are defined in Little Endian mode,    */
-	/* therefore to insert the address we reverse the bytes. */
-	set_mac_addr(&p_82xx_addr_filt->paddr[paddr_num].h, p_enet_addr);
-	return 0;
-}
-#endif /* CONFIG_UGETH_FILTERING */
-
 static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num)
 {
 	struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
@@ -1615,8 +1565,8 @@
 	priv->oldspeed = 0;
 	priv->oldduplex = -1;
 
-	snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus,
-			priv->ug_info->phy_address);
+	snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, priv->ug_info->mdio_bus,
+		 priv->ug_info->phy_address);
 
 	phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface);
 
@@ -1647,6 +1597,7 @@
 	struct ucc_fast_private *uccf;
 	u32 cecr_subblock;
 	u32 temp;
+	int i = 10;
 
 	uccf = ugeth->uccf;
 
@@ -1664,8 +1615,9 @@
 
 	/* Wait for command to complete */
 	do {
+		msleep(10);
 		temp = in_be32(uccf->p_ucce);
-	} while (!(temp & UCCE_GRA));
+	} while (!(temp & UCCE_GRA) && --i);
 
 	uccf->stopped_tx = 1;
 
@@ -1677,6 +1629,7 @@
 	struct ucc_fast_private *uccf;
 	u32 cecr_subblock;
 	u8 temp;
+	int i = 10;
 
 	uccf = ugeth->uccf;
 
@@ -1694,9 +1647,9 @@
 						ucc_num);
 		qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock,
 			     QE_CR_PROTOCOL_ETHERNET, 0);
-
+		msleep(10);
 		temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack);
-	} while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX));
+	} while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX) && --i);
 
 	uccf->stopped_rx = 1;
 
@@ -1799,196 +1752,6 @@
 #endif
 }
 
-#ifdef CONFIG_UGETH_FILTERING
-static int ugeth_ext_filtering_serialize_tad(struct ucc_geth_tad_params *
-					     p_UccGethTadParams,
-					     struct qe_fltr_tad *qe_fltr_tad)
-{
-	u16 temp;
-
-	/* Zero serialized TAD */
-	memset(qe_fltr_tad, 0, QE_FLTR_TAD_SIZE);
-
-	qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_V;	/* Must have this */
-	if (p_UccGethTadParams->rx_non_dynamic_extended_features_mode ||
-	    (p_UccGethTadParams->vtag_op != UCC_GETH_VLAN_OPERATION_TAGGED_NOP)
-	    || (p_UccGethTadParams->vnontag_op !=
-		UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP)
-	    )
-		qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_EF;
-	if (p_UccGethTadParams->reject_frame)
-		qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_REJ;
-	temp =
-	    (u16) (((u16) p_UccGethTadParams->
-		    vtag_op) << UCC_GETH_TAD_VTAG_OP_SHIFT);
-	qe_fltr_tad->serialized[0] |= (u8) (temp >> 8);	/* upper bits */
-
-	qe_fltr_tad->serialized[1] |= (u8) (temp & 0x00ff);	/* lower bits */
-	if (p_UccGethTadParams->vnontag_op ==
-	    UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT)
-		qe_fltr_tad->serialized[1] |= UCC_GETH_TAD_V_NON_VTAG_OP;
-	qe_fltr_tad->serialized[1] |=
-	    p_UccGethTadParams->rqos << UCC_GETH_TAD_RQOS_SHIFT;
-
-	qe_fltr_tad->serialized[2] |=
-	    p_UccGethTadParams->vpri << UCC_GETH_TAD_V_PRIORITY_SHIFT;
-	/* upper bits */
-	qe_fltr_tad->serialized[2] |= (u8) (p_UccGethTadParams->vid >> 8);
-	/* lower bits */
-	qe_fltr_tad->serialized[3] |= (u8) (p_UccGethTadParams->vid & 0x00ff);
-
-	return 0;
-}
-
-static struct enet_addr_container_t
-    *ugeth_82xx_filtering_get_match_addr_in_hash(struct ucc_geth_private *ugeth,
-						 struct enet_addr *p_enet_addr)
-{
-	struct enet_addr_container *enet_addr_cont;
-	struct list_head *p_lh;
-	u16 i, num;
-	int32_t j;
-	u8 *p_counter;
-
-	if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
-		p_lh = &ugeth->group_hash_q;
-		p_counter = &(ugeth->numGroupAddrInHash);
-	} else {
-		p_lh = &ugeth->ind_hash_q;
-		p_counter = &(ugeth->numIndAddrInHash);
-	}
-
-	if (!p_lh)
-		return NULL;
-
-	num = *p_counter;
-
-	for (i = 0; i < num; i++) {
-		enet_addr_cont =
-		    (struct enet_addr_container *)
-		    ENET_ADDR_CONT_ENTRY(dequeue(p_lh));
-		for (j = ENET_NUM_OCTETS_PER_ADDRESS - 1; j >= 0; j--) {
-			if ((*p_enet_addr)[j] != (enet_addr_cont->address)[j])
-				break;
-			if (j == 0)
-				return enet_addr_cont;	/* Found */
-		}
-		enqueue(p_lh, &enet_addr_cont->node);	/* Put it back */
-	}
-	return NULL;
-}
-
-static int ugeth_82xx_filtering_add_addr_in_hash(struct ucc_geth_private *ugeth,
-						 struct enet_addr *p_enet_addr)
-{
-	enum ucc_geth_enet_address_recognition_location location;
-	struct enet_addr_container *enet_addr_cont;
-	struct list_head *p_lh;
-	u8 i;
-	u32 limit;
-	u8 *p_counter;
-
-	if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
-		p_lh = &ugeth->group_hash_q;
-		limit = ugeth->ug_info->maxGroupAddrInHash;
-		location =
-		    UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH;
-		p_counter = &(ugeth->numGroupAddrInHash);
-	} else {
-		p_lh = &ugeth->ind_hash_q;
-		limit = ugeth->ug_info->maxIndAddrInHash;
-		location =
-		    UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH;
-		p_counter = &(ugeth->numIndAddrInHash);
-	}
-
-	if ((enet_addr_cont =
-	     ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr))) {
-		list_add(p_lh, &enet_addr_cont->node);	/* Put it back */
-		return 0;
-	}
-	if ((!p_lh) || (!(*p_counter < limit)))
-		return -EBUSY;
-	if (!(enet_addr_cont = get_enet_addr_container()))
-		return -ENOMEM;
-	for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++)
-		(enet_addr_cont->address)[i] = (*p_enet_addr)[i];
-	enet_addr_cont->location = location;
-	enqueue(p_lh, &enet_addr_cont->node);	/* Put it back */
-	++(*p_counter);
-
-	hw_add_addr_in_hash(ugeth, enet_addr_cont->address);
-	return 0;
-}
-
-static int ugeth_82xx_filtering_clear_addr_in_hash(struct ucc_geth_private *ugeth,
-						   struct enet_addr *p_enet_addr)
-{
-	struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
-	struct enet_addr_container *enet_addr_cont;
-	struct ucc_fast_private *uccf;
-	enum comm_dir comm_dir;
-	u16 i, num;
-	struct list_head *p_lh;
-	u32 *addr_h, *addr_l;
-	u8 *p_counter;
-
-	uccf = ugeth->uccf;
-
-	p_82xx_addr_filt =
-	    (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
-	    addressfiltering;
-
-	if (!
-	    (enet_addr_cont =
-	     ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr)))
-		return -ENOENT;
-
-	/* It's been found and removed from the CQ. */
-	/* Now destroy its container */
-	put_enet_addr_container(enet_addr_cont);
-
-	if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
-		addr_h = &(p_82xx_addr_filt->gaddr_h);
-		addr_l = &(p_82xx_addr_filt->gaddr_l);
-		p_lh = &ugeth->group_hash_q;
-		p_counter = &(ugeth->numGroupAddrInHash);
-	} else {
-		addr_h = &(p_82xx_addr_filt->iaddr_h);
-		addr_l = &(p_82xx_addr_filt->iaddr_l);
-		p_lh = &ugeth->ind_hash_q;
-		p_counter = &(ugeth->numIndAddrInHash);
-	}
-
-	comm_dir = 0;
-	if (uccf->enabled_tx)
-		comm_dir |= COMM_DIR_TX;
-	if (uccf->enabled_rx)
-		comm_dir |= COMM_DIR_RX;
-	if (comm_dir)
-		ugeth_disable(ugeth, comm_dir);
-
-	/* Clear the hash table. */
-	out_be32(addr_h, 0x00000000);
-	out_be32(addr_l, 0x00000000);
-
-	/* Add all remaining CQ elements back into hash */
-	num = --(*p_counter);
-	for (i = 0; i < num; i++) {
-		enet_addr_cont =
-		    (struct enet_addr_container *)
-		    ENET_ADDR_CONT_ENTRY(dequeue(p_lh));
-		hw_add_addr_in_hash(ugeth, enet_addr_cont->address);
-		enqueue(p_lh, &enet_addr_cont->node);	/* Put it back */
-	}
-
-	if (comm_dir)
-		ugeth_enable(ugeth, comm_dir);
-
-	return 0;
-}
-#endif /* CONFIG_UGETH_FILTERING */
-
 static int ugeth_82xx_filtering_clear_all_addr_in_hash(struct ucc_geth_private *
 						       ugeth,
 						       enum enet_addr_type
@@ -2051,28 +1814,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_UGETH_FILTERING
-static int ugeth_82xx_filtering_add_addr_in_paddr(struct ucc_geth_private *ugeth,
-						  struct enet_addr *p_enet_addr,
-						  u8 paddr_num)
-{
-	int i;
-
-	if ((*p_enet_addr)[0] & ENET_GROUP_ADDR)
-		ugeth_warn
-		    ("%s: multicast address added to paddr will have no "
-		     "effect - is this what you wanted?",
-		     __func__);
-
-	ugeth->indAddrRegUsed[paddr_num] = 1;	/* mark this paddr as used */
-	/* store address in our database */
-	for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++)
-		ugeth->paddr[paddr_num][i] = (*p_enet_addr)[i];
-	/* put in hardware */
-	return hw_add_addr_in_paddr(ugeth, p_enet_addr, paddr_num);
-}
-#endif /* CONFIG_UGETH_FILTERING */
-
 static int ugeth_82xx_filtering_clear_addr_in_paddr(struct ucc_geth_private *ugeth,
 						    u8 paddr_num)
 {
@@ -2215,7 +1956,10 @@
 	while (!list_empty(&ugeth->ind_hash_q))
 		put_enet_addr_container(ENET_ADDR_CONT_ENTRY
 					(dequeue(&ugeth->ind_hash_q)));
-
+	if (ugeth->ug_regs) {
+		iounmap(ugeth->ug_regs);
+		ugeth->ug_regs = NULL;
+	}
 }
 
 static void ucc_geth_set_multi(struct net_device *dev)
@@ -2297,8 +2041,6 @@
 	tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
 	out_be32(&ug_regs->maccfg1, tempval);
 
-	free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
-
 	ucc_geth_memclean(ugeth);
 }
 
@@ -2419,11 +2161,15 @@
 	if (ucc_fast_init(uf_info, &ugeth->uccf)) {
 		if (netif_msg_probe(ugeth))
 			ugeth_err("%s: Failed to init uccf.", __func__);
-		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
 
-	ugeth->ug_regs = (struct ucc_geth __iomem *) ioremap(uf_info->regs, sizeof(struct ucc_geth));
+	ugeth->ug_regs = ioremap(uf_info->regs, sizeof(*ugeth->ug_regs));
+	if (!ugeth->ug_regs) {
+		if (netif_msg_probe(ugeth))
+			ugeth_err("%s: Failed to ioremap regs.", __func__);
+		return -ENOMEM;
+	}
 
 	return 0;
 }
@@ -2475,7 +2221,6 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Bad number of Rx threads value.",
 				       	__func__);
-		ucc_geth_memclean(ugeth);
 		return -EINVAL;
 		break;
 	}
@@ -2500,7 +2245,6 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Bad number of Tx threads value.",
 				       	__func__);
-		ucc_geth_memclean(ugeth);
 		return -EINVAL;
 		break;
 	}
@@ -2554,7 +2298,6 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: IPGIFG initialization parameter too large.",
 				  __func__);
-		ucc_geth_memclean(ugeth);
 		return ret_val;
 	}
 
@@ -2572,7 +2315,6 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Half Duplex initialization parameter too large.",
 			  __func__);
-		ucc_geth_memclean(ugeth);
 		return ret_val;
 	}
 
@@ -2627,7 +2369,6 @@
 				ugeth_err
 				    ("%s: Can not allocate memory for Tx bd rings.",
 				     __func__);
-			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
 		/* Zero unused end of bd ring, according to spec */
@@ -2663,7 +2404,6 @@
 				ugeth_err
 				    ("%s: Can not allocate memory for Rx bd rings.",
 				     __func__);
-			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
 	}
@@ -2679,7 +2419,6 @@
 			if (netif_msg_ifup(ugeth))
 				ugeth_err("%s: Could not allocate tx_skbuff",
 					  __func__);
-			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
 
@@ -2711,7 +2450,6 @@
 			if (netif_msg_ifup(ugeth))
 				ugeth_err("%s: Could not allocate rx_skbuff",
 					  __func__);
-			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
 
@@ -2745,7 +2483,6 @@
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.",
 			     __func__);
-		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
 	ugeth->p_tx_glbl_pram =
@@ -2768,7 +2505,6 @@
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_thread_data_tx.",
 			     __func__);
-		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
 
@@ -2798,7 +2534,6 @@
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.",
 			     __func__);
-		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
 
@@ -2842,7 +2577,6 @@
 				ugeth_err
 				 ("%s: Can not allocate DPRAM memory for p_scheduler.",
 				     __func__);
-			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
 
@@ -2893,7 +2627,6 @@
 				    ("%s: Can not allocate DPRAM memory for"
 					" p_tx_fw_statistics_pram.",
 				       	__func__);
-			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
 		ugeth->p_tx_fw_statistics_pram =
@@ -2933,7 +2666,6 @@
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.",
 			     __func__);
-		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
 	ugeth->p_rx_glbl_pram =
@@ -2955,7 +2687,6 @@
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_thread_data_rx.",
 			     __func__);
-		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
 
@@ -2979,7 +2710,6 @@
 				ugeth_err
 					("%s: Can not allocate DPRAM memory for"
 					" p_rx_fw_statistics_pram.", __func__);
-			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
 		ugeth->p_rx_fw_statistics_pram =
@@ -3002,7 +2732,6 @@
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for"
 				" p_rx_irq_coalescing_tbl.", __func__);
-		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
 
@@ -3071,7 +2800,6 @@
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.",
 			     __func__);
-		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
 
@@ -3148,7 +2876,6 @@
 			if (netif_msg_ifup(ugeth))
 				ugeth_err("%s: Null Extended Filtering Chain Pointer.",
 					  __func__);
-			ucc_geth_memclean(ugeth);
 			return -EINVAL;
 		}
 
@@ -3162,7 +2889,6 @@
 				ugeth_err
 					("%s: Can not allocate DPRAM memory for"
 					" p_exf_glbl_param.", __func__);
-			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
 
@@ -3210,7 +2936,6 @@
 			ugeth_err
 			    ("%s: Can not allocate memory for"
 				" p_UccInitEnetParamShadows.", __func__);
-		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
 	/* Zero out *p_init_enet_param_shadow */
@@ -3245,7 +2970,6 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Invalid largest External Lookup Key Size.",
 				  __func__);
-		ucc_geth_memclean(ugeth);
 		return -EINVAL;
 	}
 	ugeth->p_init_enet_param_shadow->largestexternallookupkeysize =
@@ -3272,7 +2996,6 @@
 		if (netif_msg_ifup(ugeth))
 				ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
 					__func__);
-		ucc_geth_memclean(ugeth);
 		return ret_val;
 	}
 
@@ -3288,7 +3011,6 @@
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
 				  __func__);
-		ucc_geth_memclean(ugeth);
 		return ret_val;
 	}
 
@@ -3298,7 +3020,6 @@
 			if (netif_msg_ifup(ugeth))
 				ugeth_err("%s: Can not fill Rx bds with buffers.",
 					  __func__);
-			ucc_geth_memclean(ugeth);
 			return ret_val;
 		}
 	}
@@ -3310,7 +3031,6 @@
 			ugeth_err
 			    ("%s: Can not allocate DPRAM memory for p_init_enet_pram.",
 			     __func__);
-		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
 	p_init_enet_pram =
@@ -3352,28 +3072,6 @@
 	return 0;
 }
 
-/* ucc_geth_timeout gets called when a packet has not been
- * transmitted after a set amount of time.
- * For now, assume that clearing out all the structures, and
- * starting over will fix the problem. */
-static void ucc_geth_timeout(struct net_device *dev)
-{
-	struct ucc_geth_private *ugeth = netdev_priv(dev);
-
-	ugeth_vdbg("%s: IN", __func__);
-
-	dev->stats.tx_errors++;
-
-	ugeth_dump_regs(ugeth);
-
-	if (dev->flags & IFF_UP) {
-		ucc_geth_stop(ugeth);
-		ucc_geth_startup(ugeth);
-	}
-
-	netif_tx_schedule_all(dev);
-}
-
 /* This is called by the kernel when a frame is ready for transmission. */
 /* It is pointed to by the dev->hard_start_xmit function pointer */
 static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -3502,8 +3200,6 @@
 			netif_receive_skb(skb);
 		}
 
-		ugeth->dev->last_rx = jiffies;
-
 		skb = get_new_skb(ugeth, bd);
 		if (!skb) {
 			if (netif_msg_rx_err(ugeth))
@@ -3592,7 +3288,7 @@
 		struct ucc_fast_private *uccf;
 		u32 uccm;
 
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 		uccf = ugeth->uccf;
 		uccm = in_be32(uccf->p_uccm);
 		uccm |= UCCE_RX_EVENTS;
@@ -3626,10 +3322,10 @@
 
 	/* check for receive events that require processing */
 	if (ucce & UCCE_RX_EVENTS) {
-		if (netif_rx_schedule_prep(dev, &ugeth->napi)) {
+		if (netif_rx_schedule_prep(&ugeth->napi)) {
 			uccm &= ~UCCE_RX_EVENTS;
 			out_be32(uccf->p_uccm, uccm);
-			__netif_rx_schedule(dev, &ugeth->napi);
+			__netif_rx_schedule(&ugeth->napi);
 		}
 	}
 
@@ -3697,7 +3393,7 @@
 	if (err) {
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
-		return err;
+		goto out_err_stop;
 	}
 
 	napi_enable(&ugeth->napi);
@@ -3738,22 +3434,19 @@
 
 	phy_start(ugeth->phydev);
 
-	err =
-	    request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0,
-			"UCC Geth", dev);
-	if (err) {
-		if (netif_msg_ifup(ugeth))
-			ugeth_err("%s: Cannot get IRQ for net device, aborting.",
-				  dev->name);
-		ucc_geth_stop(ugeth);
-		goto out_err;
-	}
-
 	err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
 	if (err) {
 		if (netif_msg_ifup(ugeth))
 			ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
-		ucc_geth_stop(ugeth);
+		goto out_err;
+	}
+
+	err = request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler,
+			  0, "UCC Geth", dev);
+	if (err) {
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Cannot get IRQ for net device, aborting.",
+				  dev->name);
 		goto out_err;
 	}
 
@@ -3763,7 +3456,8 @@
 
 out_err:
 	napi_disable(&ugeth->napi);
-
+out_err_stop:
+	ucc_geth_stop(ugeth);
 	return err;
 }
 
@@ -3778,6 +3472,8 @@
 
 	ucc_geth_stop(ugeth);
 
+	free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
+
 	phy_disconnect(ugeth->phydev);
 	ugeth->phydev = NULL;
 
@@ -3786,6 +3482,45 @@
 	return 0;
 }
 
+/* Reopen device. This will reset the MAC and PHY. */
+static void ucc_geth_timeout_work(struct work_struct *work)
+{
+	struct ucc_geth_private *ugeth;
+	struct net_device *dev;
+
+	ugeth = container_of(work, struct ucc_geth_private, timeout_work);
+	dev = ugeth->dev;
+
+	ugeth_vdbg("%s: IN", __func__);
+
+	dev->stats.tx_errors++;
+
+	ugeth_dump_regs(ugeth);
+
+	if (dev->flags & IFF_UP) {
+		/*
+		 * Must reset MAC *and* PHY. This is done by reopening
+		 * the device.
+		 */
+		ucc_geth_close(dev);
+		ucc_geth_open(dev);
+	}
+
+	netif_tx_schedule_all(dev);
+}
+
+/*
+ * ucc_geth_timeout gets called when a packet has not been
+ * transmitted after a set amount of time.
+ */
+static void ucc_geth_timeout(struct net_device *dev)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+	netif_carrier_off(dev);
+	schedule_work(&ugeth->timeout_work);
+}
+
 static phy_interface_t to_phy_interface(const char *phy_connection_type)
 {
 	if (strcasecmp(phy_connection_type, "mii") == 0)
@@ -4026,6 +3761,7 @@
 	dev->hard_start_xmit = ucc_geth_start_xmit;
 	dev->tx_timeout = ucc_geth_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+	INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work);
 	netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = ucc_netpoll;
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index abc0e22..d74d2f7 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -1186,6 +1186,7 @@
 	struct ucc_fast_private *uccf;
 	struct net_device *dev;
 	struct napi_struct napi;
+	struct work_struct timeout_work;
 	struct ucc_geth __iomem *ug_regs;
 	struct ucc_geth_init_pram *p_init_enet_param_shadow;
 	struct ucc_geth_exf_global_pram __iomem *p_exf_glbl_param;
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index de57490..e009481 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -246,10 +246,11 @@
 static void asix_async_cmd_callback(struct urb *urb)
 {
 	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
+	int status = urb->status;
 
-	if (urb->status < 0)
+	if (status < 0)
 		printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d",
-			urb->status);
+			status);
 
 	kfree(req);
 	usb_free_urb(urb);
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 466a89e..cb7acbb 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -229,14 +229,15 @@
 	u8 *pkt_start = urb->transfer_buffer;
 	struct sk_buff *skb;
 	int pkt_len, pkt_offset = 0;
+	int status = urb->status;
 
 	if (!catc->is_f5u011) {
 		clear_bit(RX_RUNNING, &catc->flags);
 		pkt_offset = 2;
 	}
 
-	if (urb->status) {
-		dbg("rx_done, status %d, length %d", urb->status, urb->actual_length);
+	if (status) {
+		dbg("rx_done, status %d, length %d", status, urb->actual_length);
 		return;
 	}
 
@@ -271,16 +272,14 @@
 
 	} while (pkt_start - (u8 *) urb->transfer_buffer < urb->actual_length);
 
-	catc->netdev->last_rx = jiffies;
-
 	if (catc->is_f5u011) {
 		if (atomic_read(&catc->recq_sz)) {
-			int status;
+			int state;
 			atomic_dec(&catc->recq_sz);
 			dbg("getting extra packet");
 			urb->dev = catc->usbdev;
-			if ((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
-				dbg("submit(rx_urb) status %d", status);
+			if ((state = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+				dbg("submit(rx_urb) status %d", state);
 			}
 		} else {
 			clear_bit(RX_RUNNING, &catc->flags);
@@ -292,8 +291,9 @@
 {
 	struct catc *catc = urb->context;
 	u8 *data = urb->transfer_buffer;
-	int status;
+	int status = urb->status;
 	unsigned int hasdata = 0, linksts = LinkNoChange;
+	int res;
 
 	if (!catc->is_f5u011) {
 		hasdata = data[1] & 0x80;
@@ -309,7 +309,7 @@
 			linksts = LinkBad;
 	}
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:			/* success */
 		break;
 	case -ECONNRESET:	/* unlink */
@@ -318,7 +318,7 @@
 		return;
 	/* -EPIPE:  should clear the halt */
 	default:		/* error */
-		dbg("irq_done, status %d, data %02x %02x.", urb->status, data[0], data[1]);
+		dbg("irq_done, status %d, data %02x %02x.", status, data[0], data[1]);
 		goto resubmit;
 	}
 
@@ -338,17 +338,17 @@
 				atomic_inc(&catc->recq_sz);
 		} else {
 			catc->rx_urb->dev = catc->usbdev;
-			if ((status = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) {
-				err("submit(rx_urb) status %d", status);
+			if ((res = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) {
+				err("submit(rx_urb) status %d", res);
 			}
 		} 
 	}
 resubmit:
-	status = usb_submit_urb (urb, GFP_ATOMIC);
-	if (status)
+	res = usb_submit_urb (urb, GFP_ATOMIC);
+	if (res)
 		err ("can't resubmit intr, %s-%s, status %d",
 				catc->usbdev->bus->bus_name,
-				catc->usbdev->devpath, status);
+				catc->usbdev->devpath, res);
 }
 
 /*
@@ -380,9 +380,9 @@
 {
 	struct catc *catc = urb->context;
 	unsigned long flags;
-	int r;
+	int r, status = urb->status;
 
-	if (urb->status == -ECONNRESET) {
+	if (status == -ECONNRESET) {
 		dbg("Tx Reset.");
 		urb->status = 0;
 		catc->netdev->trans_start = jiffies;
@@ -392,8 +392,8 @@
 		return;
 	}
 
-	if (urb->status) {
-		dbg("tx_done, status %d, length %d", urb->status, urb->actual_length);
+	if (status) {
+		dbg("tx_done, status %d, length %d", status, urb->actual_length);
 		return;
 	}
 
@@ -504,9 +504,10 @@
 	struct catc *catc = urb->context;
 	struct ctrl_queue *q;
 	unsigned long flags;
+	int status = urb->status;
 
-	if (urb->status)
-		dbg("ctrl_done, status %d, len %d.", urb->status, urb->actual_length);
+	if (status)
+		dbg("ctrl_done, status %d, len %d.", status, urb->actual_length);
 
 	spin_lock_irqsave(&catc->ctrl_lock, flags);
 
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index db3377d..edd244f 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -123,10 +123,11 @@
 static void dm_write_async_callback(struct urb *urb)
 {
 	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
+	int status = urb->status;
 
-	if (urb->status < 0)
+	if (status < 0)
 		printk(KERN_DEBUG "dm_write_async_callback() failed with %d\n",
-		       urb->status);
+		       status);
 
 	kfree(req);
 	usb_free_urb(urb);
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 8e90891..198ce3c 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -417,6 +417,11 @@
 	{USB_DEVICE(0x0af0, 0x7401)},		/* GI 0401 */
 	{USB_DEVICE(0x0af0, 0x7501)},		/* GTM 382 */
 	{USB_DEVICE(0x0af0, 0x7601)},		/* GE40x */
+	{USB_DEVICE(0x0af0, 0x7701)},
+	{USB_DEVICE(0x0af0, 0x7801)},
+	{USB_DEVICE(0x0af0, 0x7901)},
+	{USB_DEVICE(0x0af0, 0x7361)},
+	{icon321_port_device(0x0af0, 0xd051)},
 	{}
 };
 MODULE_DEVICE_TABLE(usb, hso_ids);
@@ -658,10 +663,9 @@
 	odev->rx_buf_missing = sizeof(struct iphdr);
 	spin_unlock_irqrestore(&odev->net_lock, flags);
 
-	hso_start_net_device(odev->parent);
-
 	/* We are up and running. */
 	set_bit(HSO_NET_RUNNING, &odev->flags);
+	hso_start_net_device(odev->parent);
 
 	/* Tell the kernel we are ready to start receiving from it */
 	netif_start_queue(net);
@@ -2750,18 +2754,21 @@
 		if (network_table[i] &&
 		    (network_table[i]->interface == iface)) {
 			hso_net = dev2net(network_table[i]);
-			/* First transmit any lingering data, then restart the
-			 * device. */
-			if (hso_net->skb_tx_buf) {
-				dev_dbg(&iface->dev,
-					"Transmitting lingering data\n");
-				hso_net_start_xmit(hso_net->skb_tx_buf,
-						   hso_net->net);
-				hso_net->skb_tx_buf = NULL;
+			if (hso_net->flags & IFF_UP) {
+				/* First transmit any lingering data,
+				   then restart the device. */
+				if (hso_net->skb_tx_buf) {
+					dev_dbg(&iface->dev,
+						"Transmitting"
+						" lingering data\n");
+					hso_net_start_xmit(hso_net->skb_tx_buf,
+							   hso_net->net);
+					hso_net->skb_tx_buf = NULL;
+				}
+				result = hso_start_net_device(network_table[i]);
+				if (result)
+					goto out;
 			}
-			result = hso_start_net_device(network_table[i]);
-			if (result)
-				goto out;
 		}
 	}
 
@@ -2894,6 +2901,7 @@
 	.id_table = hso_ids,
 	.suspend = hso_suspend,
 	.resume = hso_resume,
+	.reset_resume = hso_resume,
 	.supports_autosuspend = 1,
 };
 
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index fdbf3be..2ee034f 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -516,8 +516,9 @@
 {
 	struct kaweth_device *kaweth = u->context;
 	int act_state;
+	int status = u->status;
 
-	switch (u->status) {
+	switch (status) {
 	case 0:			/* success */
 		break;
 	case -ECONNRESET:	/* unlink */
@@ -598,6 +599,7 @@
 {
 	struct kaweth_device *kaweth = urb->context;
 	struct net_device *net = kaweth->net;
+	int status = urb->status;
 
 	int count = urb->actual_length;
 	int count2 = urb->transfer_buffer_length;
@@ -606,7 +608,7 @@
 
 	struct sk_buff *skb;
 
-	if(unlikely(urb->status == -ECONNRESET || urb->status == -ESHUTDOWN))
+	if(unlikely(status == -ECONNRESET || status == -ESHUTDOWN))
 	/* we are killed - set a flag and wake the disconnect handler */
 	{
 		kaweth->end = 1;
@@ -621,10 +623,10 @@
 	}
 	spin_unlock(&kaweth->device_lock);
 
-	if(urb->status && urb->status != -EREMOTEIO && count != 1) {
+	if(status && status != -EREMOTEIO && count != 1) {
 		err("%s RX status: %d count: %d packet_len: %d",
                            net->name,
-			   urb->status,
+			   status,
 			   count,
 			   (int)pkt_len);
 		kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
@@ -775,10 +777,11 @@
 {
 	struct kaweth_device *kaweth = urb->context;
 	struct sk_buff *skb = kaweth->tx_skb;
+	int status = urb->status;
 
-	if (unlikely(urb->status != 0))
-		if (urb->status != -ENOENT)
-			dbg("%s: TX status %d.", kaweth->net->name, urb->status);
+	if (unlikely(status != 0))
+		if (status != -ENOENT)
+			dbg("%s: TX status %d.", kaweth->net->name, status);
 
 	netif_wake_queue(kaweth->net);
 	dev_kfree_skb_irq(skb);
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index b514350..5385d66 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -115,10 +115,11 @@
 static void mcs7830_async_cmd_callback(struct urb *urb)
 {
 	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
+	int status = urb->status;
 
-	if (urb->status < 0)
+	if (status < 0)
 		printk(KERN_DEBUG "%s() failed with %d\n",
-		       __func__, urb->status);
+		       __func__, status);
 
 	kfree(req);
 	usb_free_urb(urb);
@@ -344,14 +345,14 @@
 static int mcs7830_mdio_read(struct net_device *netdev, int phy_id,
 			     int location)
 {
-	struct usbnet *dev = netdev->priv;
+	struct usbnet *dev = netdev_priv(netdev);
 	return mcs7830_read_phy(dev, location);
 }
 
 static void mcs7830_mdio_write(struct net_device *netdev, int phy_id,
 				int location, int val)
 {
-	struct usbnet *dev = netdev->priv;
+	struct usbnet *dev = netdev_priv(netdev);
 	mcs7830_write_phy(dev, location, val);
 }
 
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 7914867..166880c 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -99,11 +99,12 @@
 static void ctrl_callback(struct urb *urb)
 {
 	pegasus_t *pegasus = urb->context;
+	int status = urb->status;
 
 	if (!pegasus)
 		return;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		if (pegasus->flags & ETH_REGS_CHANGE) {
 			pegasus->flags &= ~ETH_REGS_CHANGE;
@@ -119,7 +120,7 @@
 	default:
 		if (netif_msg_drv(pegasus) && printk_ratelimit())
 			dev_dbg(&pegasus->intf->dev, "%s, status %d\n",
-				__func__, urb->status);
+				__func__, status);
 	}
 	pegasus->flags &= ~ETH_REGS_CHANGED;
 	wake_up(&pegasus->ctrl_wait);
@@ -611,6 +612,7 @@
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net;
 	int rx_status, count = urb->actual_length;
+	int status = urb->status;
 	u8 *buf = urb->transfer_buffer;
 	__u16 pkt_len;
 
@@ -621,7 +623,7 @@
 	if (!netif_device_present(net) || !netif_running(net))
 		return;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		break;
 	case -ETIME:
@@ -639,11 +641,11 @@
 	case -ECONNRESET:
 	case -ESHUTDOWN:
 		if (netif_msg_ifdown(pegasus))
-			pr_debug("%s: rx unlink, %d\n", net->name, urb->status);
+			pr_debug("%s: rx unlink, %d\n", net->name, status);
 		return;
 	default:
 		if (netif_msg_rx_err(pegasus))
-			pr_debug("%s: RX status %d\n", net->name, urb->status);
+			pr_debug("%s: RX status %d\n", net->name, status);
 		goto goon;
 	}
 
@@ -769,6 +771,7 @@
 {
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net;
+	int status = urb->status;
 
 	if (!pegasus)
 		return;
@@ -778,7 +781,7 @@
 	if (!netif_device_present(net) || !netif_running(net))
 		return;
 
-	switch (urb->status) {
+	switch (status) {
 	case -EPIPE:
 		/* FIXME schedule_work() to clear the tx halt */
 		netif_stop_queue(net);
@@ -790,11 +793,11 @@
 	case -ECONNRESET:
 	case -ESHUTDOWN:
 		if (netif_msg_ifdown(pegasus))
-			pr_debug("%s: tx unlink, %d\n", net->name, urb->status);
+			pr_debug("%s: tx unlink, %d\n", net->name, status);
 		return;
 	default:
 		if (netif_msg_tx_err(pegasus))
-			pr_info("%s: TX status %d\n", net->name, urb->status);
+			pr_info("%s: TX status %d\n", net->name, status);
 		/* FALL THROUGH */
 	case 0:
 		break;
@@ -808,13 +811,13 @@
 {
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net;
-	int status;
+	int res, status = urb->status;
 
 	if (!pegasus)
 		return;
 	net = pegasus->net;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		break;
 	case -ECONNRESET:	/* unlink */
@@ -827,7 +830,7 @@
 		 */
 		if (netif_msg_timer(pegasus))
 			pr_debug("%s: intr status %d\n", net->name,
-					urb->status);
+					status);
 	}
 
 	if (urb->actual_length >= 6) {
@@ -854,12 +857,12 @@
 		pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4];
 	}
 
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status == -ENODEV)
+	res = usb_submit_urb(urb, GFP_ATOMIC);
+	if (res == -ENODEV)
 		netif_device_detach(pegasus->net);
-	if (status && netif_msg_timer(pegasus))
+	if (res && netif_msg_timer(pegasus))
 		printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n",
-				net->name, status);
+				net->name, res);
 }
 
 static void pegasus_tx_timeout(struct net_device *net)
@@ -1213,7 +1216,7 @@
 		pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
 		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
 		if (netif_msg_link(pegasus))
-			pr_info("%s: set allmulti\n", net->name);
+			pr_debug("%s: set allmulti\n", net->name);
 	} else {
 		pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;
 		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
@@ -1273,6 +1276,7 @@
 }
 
 
+static int pegasus_count;
 static struct workqueue_struct *pegasus_workqueue = NULL;
 #define CARRIER_CHECK_DELAY (2 * HZ)
 
@@ -1301,6 +1305,18 @@
 	return 0;
 }
 
+/* we rely on probe() and remove() being serialized so we
+ * don't need extra locking on pegasus_count.
+ */
+static void pegasus_dec_workqueue(void)
+{
+	pegasus_count--;
+	if (pegasus_count == 0) {
+		destroy_workqueue(pegasus_workqueue);
+		pegasus_workqueue = NULL;
+	}
+}
+
 static int pegasus_probe(struct usb_interface *intf,
 			 const struct usb_device_id *id)
 {
@@ -1309,15 +1325,19 @@
 	pegasus_t *pegasus;
 	int dev_index = id - pegasus_ids;
 	int res = -ENOMEM;
-	DECLARE_MAC_BUF(mac);
+
+	if (pegasus_blacklisted(dev))
+		return -ENODEV;
+
+	if (pegasus_count == 0) {
+		pegasus_workqueue = create_singlethread_workqueue("pegasus");
+		if (!pegasus_workqueue)
+			return -ENOMEM;
+	}
+	pegasus_count++;
 
 	usb_get_dev(dev);
 
-	if (pegasus_blacklisted(dev)) {
-		res = -ENODEV;
-		goto out;
-	}
-
 	net = alloc_etherdev(sizeof(struct pegasus));
 	if (!net) {
 		dev_err(&intf->dev, "can't allocate %s\n", "device");
@@ -1386,10 +1406,10 @@
 	queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
 				CARRIER_CHECK_DELAY);
 
-	dev_info(&intf->dev, "%s, %s, %s\n",
+	dev_info(&intf->dev, "%s, %s, %pM\n",
 		 net->name,
 		 usb_dev_id[dev_index].name,
-		 print_mac(mac, net->dev_addr));
+		 net->dev_addr);
 	return 0;
 
 out3:
@@ -1401,6 +1421,7 @@
 	free_netdev(net);
 out:
 	usb_put_dev(dev);
+	pegasus_dec_workqueue();
 	return res;
 }
 
@@ -1426,6 +1447,7 @@
 		pegasus->rx_skb = NULL;
 	}
 	free_netdev(pegasus->net);
+	pegasus_dec_workqueue();
 }
 
 static int pegasus_suspend (struct usb_interface *intf, pm_message_t message)
@@ -1469,7 +1491,7 @@
 	.resume = pegasus_resume,
 };
 
-static void parse_id(char *id)
+static void __init parse_id(char *id)
 {
 	unsigned int vendor_id=0, device_id=0, flags=0, i=0;
 	char *token, *name=NULL;
@@ -1505,15 +1527,11 @@
 	pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION);
 	if (devid)
 		parse_id(devid);
-	pegasus_workqueue = create_singlethread_workqueue("pegasus");
-	if (!pegasus_workqueue)
-		return -ENOMEM;
 	return usb_register(&pegasus_driver);
 }
 
 static void __exit pegasus_exit(void)
 {
-	destroy_workqueue(pegasus_workqueue);
 	usb_deregister(&pegasus_driver);
 }
 
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 6133401..d8664bf 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -212,8 +212,9 @@
 static void ctrl_callback(struct urb *urb)
 {
 	rtl8150_t *dev;
+	int status = urb->status;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		break;
 	case -EINPROGRESS:
@@ -221,7 +222,7 @@
 	case -ENOENT:
 		break;
 	default:
-		dev_warn(&urb->dev->dev, "ctrl urb status %d\n", urb->status);
+		dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status);
 	}
 	dev = urb->context;
 	clear_bit(RX_REG_SET, &dev->flags);
@@ -424,7 +425,8 @@
 	struct sk_buff *skb;
 	struct net_device *netdev;
 	u16 rx_stat;
-	int status;
+	int status = urb->status;
+	int result;
 
 	dev = urb->context;
 	if (!dev)
@@ -435,7 +437,7 @@
 	if (!netif_device_present(netdev))
 		return;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		break;
 	case -ENOENT:
@@ -444,7 +446,7 @@
 		dev_warn(&urb->dev->dev, "may be reset is needed?..\n");
 		goto goon;
 	default:
-		dev_warn(&urb->dev->dev, "Rx status %d\n", urb->status);
+		dev_warn(&urb->dev->dev, "Rx status %d\n", status);
 		goto goon;
 	}
 
@@ -474,10 +476,10 @@
 goon:
 	usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
 		      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
-	status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
-	if (status == -ENODEV)
+	result = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
+	if (result == -ENODEV)
 		netif_device_detach(dev->netdev);
-	else if (status) {
+	else if (result) {
 		set_bit(RX_URB_FAIL, &dev->flags);
 		goto resched;
 	} else {
@@ -530,6 +532,7 @@
 static void write_bulk_callback(struct urb *urb)
 {
 	rtl8150_t *dev;
+	int status = urb->status;
 
 	dev = urb->context;
 	if (!dev)
@@ -537,9 +540,9 @@
 	dev_kfree_skb_irq(dev->tx_skb);
 	if (!netif_device_present(dev->netdev))
 		return;
-	if (urb->status)
+	if (status)
 		dev_info(&urb->dev->dev, "%s: Tx status %d\n",
-			 dev->netdev->name, urb->status);
+			 dev->netdev->name, status);
 	dev->netdev->trans_start = jiffies;
 	netif_wake_queue(dev->netdev);
 }
@@ -548,12 +551,13 @@
 {
 	rtl8150_t *dev;
 	__u8 *d;
-	int status;
+	int status = urb->status;
+	int res;
 
 	dev = urb->context;
 	if (!dev)
 		return;
-	switch (urb->status) {
+	switch (status) {
 	case 0:			/* success */
 		break;
 	case -ECONNRESET:	/* unlink */
@@ -563,7 +567,7 @@
 	/* -EPIPE:  should clear the halt */
 	default:
 		dev_info(&urb->dev->dev, "%s: intr status %d\n",
-			 dev->netdev->name, urb->status);
+			 dev->netdev->name, status);
 		goto resubmit;
 	}
 
@@ -591,13 +595,13 @@
 	}
 
 resubmit:
-	status = usb_submit_urb (urb, GFP_ATOMIC);
-	if (status == -ENODEV)
+	res = usb_submit_urb (urb, GFP_ATOMIC);
+	if (res == -ENODEV)
 		netif_device_detach(dev->netdev);
-	else if (status)
+	else if (res)
 		err ("can't resubmit intr, %s-%s/input0, status %d",
 				dev->udev->bus->bus_name,
-				dev->udev->devpath, status);
+				dev->udev->devpath, res);
 }
 
 static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message)
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 51e2f5d..5574abe 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -31,7 +31,7 @@
 #include "smsc95xx.h"
 
 #define SMSC_CHIPNAME			"smsc95xx"
-#define SMSC_DRIVER_VERSION		"1.0.3"
+#define SMSC_DRIVER_VERSION		"1.0.4"
 #define HS_USB_PKT_SIZE			(512)
 #define FS_USB_PKT_SIZE			(64)
 #define DEFAULT_HS_BURST_CAP_SIZE	(16 * 1024 + 5 * HS_USB_PKT_SIZE)
@@ -40,15 +40,16 @@
 #define MAX_SINGLE_PACKET_SIZE		(2048)
 #define LAN95XX_EEPROM_MAGIC		(0x9500)
 #define EEPROM_MAC_OFFSET		(0x01)
+#define DEFAULT_TX_CSUM_ENABLE		(true)
 #define DEFAULT_RX_CSUM_ENABLE		(true)
 #define SMSC95XX_INTERNAL_PHY_ID	(1)
 #define SMSC95XX_TX_OVERHEAD		(8)
-#define FLOW_CTRL_TX			(1)
-#define FLOW_CTRL_RX			(2)
+#define SMSC95XX_TX_OVERHEAD_CSUM	(12)
 
 struct smsc95xx_priv {
 	u32 mac_cr;
 	spinlock_t mac_cr_lock;
+	bool use_tx_csum;
 	bool use_rx_csum;
 };
 
@@ -310,9 +311,10 @@
 {
 	struct usb_context *usb_context = urb->context;
 	struct usbnet *dev = usb_context->dev;
+	int status = urb->status;
 
-	if (urb->status < 0)
-		devwarn(dev, "async callback failed with %d", urb->status);
+	if (status < 0)
+		devwarn(dev, "async callback failed with %d", status);
 
 	complete(&usb_context->notify);
 
@@ -434,28 +436,6 @@
 	smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr);
 }
 
-static u8 smsc95xx_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv)
-{
-	u8 cap = 0;
-
-	if (lcladv & ADVERTISE_PAUSE_CAP) {
-		if (lcladv & ADVERTISE_PAUSE_ASYM) {
-			if (rmtadv & LPA_PAUSE_CAP)
-				cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
-			else if (rmtadv & LPA_PAUSE_ASYM)
-				cap = FLOW_CTRL_RX;
-		} else {
-			if (rmtadv & LPA_PAUSE_CAP)
-				cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
-		}
-	} else if (lcladv & ADVERTISE_PAUSE_ASYM) {
-		if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
-			cap = FLOW_CTRL_TX;
-	}
-
-	return cap;
-}
-
 static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
 					    u16 lcladv, u16 rmtadv)
 {
@@ -468,7 +448,7 @@
 	}
 
 	if (duplex == DUPLEX_FULL) {
-		u8 cap = smsc95xx_resolve_flowctrl_fulldplx(lcladv, rmtadv);
+		u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
 
 		if (cap & FLOW_CTRL_RX)
 			flow = 0xFFFF0002;
@@ -556,9 +536,10 @@
 		devwarn(dev, "unexpected interrupt, intdata=0x%08X", intdata);
 }
 
-/* Enable or disable Rx checksum offload engine */
-static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable)
+/* Enable or disable Tx & Rx checksum offload engines */
+static int smsc95xx_set_csums(struct usbnet *dev)
 {
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
 	u32 read_buf;
 	int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
 	if (ret < 0) {
@@ -566,7 +547,12 @@
 		return ret;
 	}
 
-	if (enable)
+	if (pdata->use_tx_csum)
+		read_buf |= Tx_COE_EN_;
+	else
+		read_buf &= ~Tx_COE_EN_;
+
+	if (pdata->use_rx_csum)
 		read_buf |= Rx_COE_EN_;
 	else
 		read_buf &= ~Rx_COE_EN_;
@@ -626,7 +612,26 @@
 
 	pdata->use_rx_csum = !!val;
 
-	return smsc95xx_set_rx_csum(dev, pdata->use_rx_csum);
+	return smsc95xx_set_csums(dev);
+}
+
+static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+
+	return pdata->use_tx_csum;
+}
+
+static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+
+	pdata->use_tx_csum = !!val;
+
+	ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
+	return smsc95xx_set_csums(dev);
 }
 
 static struct ethtool_ops smsc95xx_ethtool_ops = {
@@ -640,6 +645,8 @@
 	.get_eeprom_len	= smsc95xx_ethtool_get_eeprom_len,
 	.get_eeprom	= smsc95xx_ethtool_get_eeprom,
 	.set_eeprom	= smsc95xx_ethtool_set_eeprom,
+	.get_tx_csum	= smsc95xx_ethtool_get_tx_csum,
+	.set_tx_csum	= smsc95xx_ethtool_set_tx_csum,
 	.get_rx_csum	= smsc95xx_ethtool_get_rx_csum,
 	.set_rx_csum	= smsc95xx_ethtool_set_rx_csum,
 };
@@ -757,9 +764,9 @@
 static int smsc95xx_reset(struct usbnet *dev)
 {
 	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	struct net_device *netdev = dev->net;
 	u32 read_buf, write_buf, burst_cap;
 	int ret = 0, timeout;
-	DECLARE_MAC_BUF(mac);
 
 	if (netif_msg_ifup(dev))
 		devdbg(dev, "entering smsc95xx_reset");
@@ -818,8 +825,7 @@
 		return ret;
 
 	if (netif_msg_ifup(dev))
-		devdbg(dev, "MAC Address: %s",
-			print_mac(mac, dev->net->dev_addr));
+		devdbg(dev, "MAC Address: %pM", dev->net->dev_addr);
 
 	ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
 	if (ret < 0) {
@@ -970,10 +976,11 @@
 		return ret;
 	}
 
-	/* Enable or disable Rx checksum offload engine */
-	ret = smsc95xx_set_rx_csum(dev, pdata->use_rx_csum);
+	/* Enable or disable checksum offload engines */
+	ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
+	ret = smsc95xx_set_csums(dev);
 	if (ret < 0) {
-		devwarn(dev, "Failed to set Rx csum offload: %d", ret);
+		devwarn(dev, "Failed to set csum offload: %d", ret);
 		return ret;
 	}
 
@@ -1029,6 +1036,7 @@
 
 	spin_lock_init(&pdata->mac_cr_lock);
 
+	pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE;
 	pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
 
 	/* Init all registers */
@@ -1148,22 +1156,44 @@
 	return 1;
 }
 
+static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb)
+{
+	int len = skb->data - skb->head;
+	u16 high_16 = (u16)(skb->csum_offset + skb->csum_start - len);
+	u16 low_16 = (u16)(skb->csum_start - len);
+	return (high_16 << 16) | low_16;
+}
+
 static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
 					 struct sk_buff *skb, gfp_t flags)
 {
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL);
+	int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD;
 	u32 tx_cmd_a, tx_cmd_b;
 
-	if (skb_headroom(skb) < SMSC95XX_TX_OVERHEAD) {
+	/* We do not advertise SG, so skbs should be already linearized */
+	BUG_ON(skb_shinfo(skb)->nr_frags);
+
+	if (skb_headroom(skb) < overhead) {
 		struct sk_buff *skb2 = skb_copy_expand(skb,
-			SMSC95XX_TX_OVERHEAD, 0, flags);
+			overhead, 0, flags);
 		dev_kfree_skb_any(skb);
 		skb = skb2;
 		if (!skb)
 			return NULL;
 	}
 
+	if (csum) {
+		u32 csum_preamble = smsc95xx_calc_csum_preamble(skb);
+		skb_push(skb, 4);
+		memcpy(skb->data, &csum_preamble, 4);
+	}
+
 	skb_push(skb, 4);
 	tx_cmd_b = (u32)(skb->len - 4);
+	if (csum)
+		tx_cmd_b |= TX_CMD_B_CSUM_ENABLE;
 	cpu_to_le32s(&tx_cmd_b);
 	memcpy(skb->data, &tx_cmd_b, 4);
 
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 02d25c7..aa31490 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1125,7 +1125,6 @@
 	struct usb_device		*xdev;
 	int				status;
 	const char			*name;
-	DECLARE_MAC_BUF(mac);
 
 	name = udev->dev.driver->name;
 	info = (struct driver_info *) prod->driver_info;
@@ -1236,11 +1235,11 @@
 	if (status)
 		goto out3;
 	if (netif_msg_probe (dev))
-		devinfo (dev, "register '%s' at usb-%s-%s, %s, %s",
+		devinfo (dev, "register '%s' at usb-%s-%s, %s, %pM",
 			udev->dev.driver->name,
 			xdev->bus->bus_name, xdev->devpath,
 			dev->driver_info->description,
-			print_mac(mac, net->dev_addr));
+			net->dev_addr);
 
 	// ok, it's ready to go.
 	usb_set_intfdata (udev, dev);
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 31cd817..852d0e7 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -8,7 +8,6 @@
  *
  */
 
-#include <linux/list.h>
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
@@ -30,14 +29,10 @@
 
 struct veth_priv {
 	struct net_device *peer;
-	struct net_device *dev;
-	struct list_head list;
 	struct veth_net_stats *stats;
 	unsigned ip_summed;
 };
 
-static LIST_HEAD(veth_list);
-
 /*
  * ethtool interface
  */
@@ -267,16 +262,20 @@
 	free_netdev(dev);
 }
 
+static const struct net_device_ops veth_netdev_ops = {
+	.ndo_init	= veth_dev_init,
+	.ndo_open	= veth_open,
+	.ndo_start_xmit = veth_xmit,
+	.ndo_get_stats	= veth_get_stats,
+};
+
 static void veth_setup(struct net_device *dev)
 {
 	ether_setup(dev);
 
-	dev->hard_start_xmit = veth_xmit;
-	dev->get_stats = veth_get_stats;
-	dev->open = veth_open;
+	dev->netdev_ops = &veth_netdev_ops;
 	dev->ethtool_ops = &veth_ethtool_ops;
 	dev->features |= NETIF_F_LLTX;
-	dev->init = veth_dev_init;
 	dev->destructor = veth_dev_free;
 }
 
@@ -302,7 +301,7 @@
 {
 	struct net_device *dev = ptr;
 
-	if (dev->open != veth_open)
+	if (dev->netdev_ops->ndo_open != veth_open)
 		goto out;
 
 	switch (event) {
@@ -420,14 +419,10 @@
 	 */
 
 	priv = netdev_priv(dev);
-	priv->dev = dev;
 	priv->peer = peer;
-	list_add(&priv->list, &veth_list);
 
 	priv = netdev_priv(peer);
-	priv->dev = peer;
 	priv->peer = dev;
-	INIT_LIST_HEAD(&priv->list);
 	return 0;
 
 err_register_dev:
@@ -449,13 +444,6 @@
 	priv = netdev_priv(dev);
 	peer = priv->peer;
 
-	if (!list_empty(&priv->list))
-		list_del(&priv->list);
-
-	priv = netdev_priv(peer);
-	if (!list_empty(&priv->list))
-		list_del(&priv->list);
-
 	unregister_netdevice(dev);
 	unregister_netdevice(peer);
 }
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 5b78700..ac07cc6 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -191,12 +191,13 @@
 
 The driver runs as two independent, single-threaded flows of control. One
 is the send-packet routine, which enforces single-threaded use by the
-dev->priv->lock spinlock. The other thread is the interrupt handler, which
-is single threaded by the hardware and interrupt handling software.
+netdev_priv(dev)->lock spinlock. The other thread is the interrupt handler,
+which is single threaded by the hardware and interrupt handling software.
 
 The send packet thread has partial control over the Tx ring. It locks the
-dev->priv->lock whenever it's queuing a Tx packet. If the next slot in the ring
-is not available it stops the transmit queue by calling netif_stop_queue.
+netdev_priv(dev)->lock whenever it's queuing a Tx packet. If the next slot in
+the ring is not available it stops the transmit queue by
+calling netif_stop_queue.
 
 The interrupt handler has exclusive control over the Rx ring and records stats
 from the Tx ring. After reaping the stats, it marks the Tx queue entry as
@@ -588,7 +589,7 @@
 	work_done = rhine_rx(dev, budget);
 
 	if (work_done < budget) {
-		netif_rx_complete(dev, napi);
+		netif_rx_complete(napi);
 
 		iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
 			  IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
@@ -614,6 +615,20 @@
 	rhine_reload_eeprom(pioaddr, dev);
 }
 
+static const struct net_device_ops rhine_netdev_ops = {
+	.ndo_open		 = rhine_open,
+	.ndo_stop		 = rhine_close,
+	.ndo_start_xmit		 = rhine_start_tx,
+	.ndo_get_stats		 = rhine_get_stats,
+	.ndo_set_multicast_list	 = rhine_set_rx_mode,
+	.ndo_validate_addr	 = eth_validate_addr,
+	.ndo_do_ioctl		 = netdev_ioctl,
+	.ndo_tx_timeout 	 = rhine_tx_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	 = rhine_poll,
+#endif
+};
+
 static int __devinit rhine_init_one(struct pci_dev *pdev,
 				    const struct pci_device_id *ent)
 {
@@ -631,7 +646,6 @@
 #else
 	int bar = 0;
 #endif
-	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -765,18 +779,10 @@
 	rp->mii_if.reg_num_mask = 0x1f;
 
 	/* The chip-specific entries in the device structure. */
-	dev->open = rhine_open;
-	dev->hard_start_xmit = rhine_start_tx;
-	dev->stop = rhine_close;
-	dev->get_stats = rhine_get_stats;
-	dev->set_multicast_list = rhine_set_rx_mode;
-	dev->do_ioctl = netdev_ioctl;
-	dev->ethtool_ops = &netdev_ethtool_ops;
-	dev->tx_timeout = rhine_tx_timeout;
+	dev->netdev_ops = &rhine_netdev_ops;
+	dev->ethtool_ops = &netdev_ethtool_ops,
 	dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = rhine_poll;
-#endif
+
 	netif_napi_add(dev, &rp->napi, rhine_napipoll, 64);
 
 	if (rp->quirks & rqRhineI)
@@ -787,14 +793,14 @@
 	if (rc)
 		goto err_out_unmap;
 
-	printk(KERN_INFO "%s: VIA %s at 0x%lx, %s, IRQ %d.\n",
+	printk(KERN_INFO "%s: VIA %s at 0x%lx, %pM, IRQ %d.\n",
 	       dev->name, name,
 #ifdef USE_MMIO
 	       memaddr,
 #else
 	       (long)ioaddr,
 #endif
-	       print_mac(mac, dev->dev_addr), pdev->irq);
+	       dev->dev_addr, pdev->irq);
 
 	pci_set_drvdata(pdev, dev);
 
@@ -1312,7 +1318,7 @@
 				  IntrPCIErr | IntrStatsMax | IntrLinkChange,
 				  ioaddr + IntrEnable);
 
-			netif_rx_schedule(dev, &rp->napi);
+			netif_rx_schedule(&rp->napi);
 		}
 
 		if (intr_status & (IntrTxErrSummary | IntrTxDone)) {
@@ -1505,7 +1511,6 @@
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_receive_skb(skb);
-			dev->last_rx = jiffies;
 			rp->stats.rx_bytes += pkt_len;
 			rp->stats.rx_packets++;
 		}
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 11cb3e5..58e25d0 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -849,6 +849,20 @@
 	return 0;
 }
 
+static const struct net_device_ops velocity_netdev_ops = {
+	.ndo_open		= velocity_open,
+	.ndo_stop		= velocity_close,
+	.ndo_start_xmit		= velocity_xmit,
+	.ndo_get_stats		= velocity_get_stats,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_multicast_list	= velocity_set_multi,
+	.ndo_change_mtu		= velocity_change_mtu,
+	.ndo_do_ioctl		= velocity_ioctl,
+	.ndo_vlan_rx_add_vid	= velocity_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= velocity_vlan_rx_kill_vid,
+	.ndo_vlan_rx_register	= velocity_vlan_rx_register,
+};
+
 /**
  *	velocity_found1		-	set up discovered velocity card
  *	@pdev: PCI device
@@ -958,18 +972,8 @@
 	vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
 
 	dev->irq = pdev->irq;
-	dev->open = velocity_open;
-	dev->hard_start_xmit = velocity_xmit;
-	dev->stop = velocity_close;
-	dev->get_stats = velocity_get_stats;
-	dev->set_multicast_list = velocity_set_multi;
-	dev->do_ioctl = velocity_ioctl;
+	dev->netdev_ops = &velocity_netdev_ops;
 	dev->ethtool_ops = &velocity_ethtool_ops;
-	dev->change_mtu = velocity_change_mtu;
-
-	dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid;
-	dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid;
-	dev->vlan_rx_register = velocity_vlan_rx_register;
 
 #ifdef  VELOCITY_ZERO_COPY_SUPPORT
 	dev->features |= NETIF_F_SG;
@@ -1412,8 +1416,6 @@
 
 		rd->size |= RX_INTEN;
 
-		vptr->dev->last_rx = jiffies;
-
 		rd_curr++;
 		if (rd_curr >= vptr->options.numrx)
 			rd_curr = 0;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 0196a0d..b7004ff 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -34,6 +34,7 @@
 
 /* FIXME: MTU in config. */
 #define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN)
+#define GOOD_COPY_LEN	128
 
 struct virtnet_info
 {
@@ -58,6 +59,9 @@
 	/* I like... big packets and I cannot lie! */
 	bool big_packets;
 
+	/* Host will merge rx buffers for big packets (shake it! shake it!) */
+	bool mergeable_rx_bufs;
+
 	/* Receive & send queues. */
 	struct sk_buff_head recv;
 	struct sk_buff_head send;
@@ -66,22 +70,27 @@
 	struct page *pages;
 };
 
-static inline struct virtio_net_hdr *skb_vnet_hdr(struct sk_buff *skb)
+static inline void *skb_vnet_hdr(struct sk_buff *skb)
 {
 	return (struct virtio_net_hdr *)skb->cb;
 }
 
-static inline void vnet_hdr_to_sg(struct scatterlist *sg, struct sk_buff *skb)
-{
-	sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr));
-}
-
 static void give_a_page(struct virtnet_info *vi, struct page *page)
 {
 	page->private = (unsigned long)vi->pages;
 	vi->pages = page;
 }
 
+static void trim_pages(struct virtnet_info *vi, struct sk_buff *skb)
+{
+	unsigned int i;
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+		give_a_page(vi, skb_shinfo(skb)->frags[i].page);
+	skb_shinfo(skb)->nr_frags = 0;
+	skb->data_len = 0;
+}
+
 static struct page *get_a_page(struct virtnet_info *vi, gfp_t gfp_mask)
 {
 	struct page *p = vi->pages;
@@ -111,31 +120,97 @@
 static void receive_skb(struct net_device *dev, struct sk_buff *skb,
 			unsigned len)
 {
+	struct virtnet_info *vi = netdev_priv(dev);
 	struct virtio_net_hdr *hdr = skb_vnet_hdr(skb);
 	int err;
+	int i;
 
 	if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
 		pr_debug("%s: short packet %i\n", dev->name, len);
 		dev->stats.rx_length_errors++;
 		goto drop;
 	}
-	len -= sizeof(struct virtio_net_hdr);
 
-	if (len <= MAX_PACKET_LEN) {
-		unsigned int i;
+	if (vi->mergeable_rx_bufs) {
+		struct virtio_net_hdr_mrg_rxbuf *mhdr = skb_vnet_hdr(skb);
+		unsigned int copy;
+		char *p = page_address(skb_shinfo(skb)->frags[0].page);
 
-		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-			give_a_page(dev->priv, skb_shinfo(skb)->frags[i].page);
-		skb->data_len = 0;
-		skb_shinfo(skb)->nr_frags = 0;
+		if (len > PAGE_SIZE)
+			len = PAGE_SIZE;
+		len -= sizeof(struct virtio_net_hdr_mrg_rxbuf);
+
+		memcpy(hdr, p, sizeof(*mhdr));
+		p += sizeof(*mhdr);
+
+		copy = len;
+		if (copy > skb_tailroom(skb))
+			copy = skb_tailroom(skb);
+
+		memcpy(skb_put(skb, copy), p, copy);
+
+		len -= copy;
+
+		if (!len) {
+			give_a_page(vi, skb_shinfo(skb)->frags[0].page);
+			skb_shinfo(skb)->nr_frags--;
+		} else {
+			skb_shinfo(skb)->frags[0].page_offset +=
+				sizeof(*mhdr) + copy;
+			skb_shinfo(skb)->frags[0].size = len;
+			skb->data_len += len;
+			skb->len += len;
+		}
+
+		while (--mhdr->num_buffers) {
+			struct sk_buff *nskb;
+
+			i = skb_shinfo(skb)->nr_frags;
+			if (i >= MAX_SKB_FRAGS) {
+				pr_debug("%s: packet too long %d\n", dev->name,
+					 len);
+				dev->stats.rx_length_errors++;
+				goto drop;
+			}
+
+			nskb = vi->rvq->vq_ops->get_buf(vi->rvq, &len);
+			if (!nskb) {
+				pr_debug("%s: rx error: %d buffers missing\n",
+					 dev->name, mhdr->num_buffers);
+				dev->stats.rx_length_errors++;
+				goto drop;
+			}
+
+			__skb_unlink(nskb, &vi->recv);
+			vi->num--;
+
+			skb_shinfo(skb)->frags[i] = skb_shinfo(nskb)->frags[0];
+			skb_shinfo(nskb)->nr_frags = 0;
+			kfree_skb(nskb);
+
+			if (len > PAGE_SIZE)
+				len = PAGE_SIZE;
+
+			skb_shinfo(skb)->frags[i].size = len;
+			skb_shinfo(skb)->nr_frags++;
+			skb->data_len += len;
+			skb->len += len;
+		}
+	} else {
+		len -= sizeof(struct virtio_net_hdr);
+
+		if (len <= MAX_PACKET_LEN)
+			trim_pages(vi, skb);
+
+		err = pskb_trim(skb, len);
+		if (err) {
+			pr_debug("%s: pskb_trim failed %i %d\n", dev->name,
+				 len, err);
+			dev->stats.rx_dropped++;
+			goto drop;
+		}
 	}
 
-	err = pskb_trim(skb, len);
-	if (err) {
-		pr_debug("%s: pskb_trim failed %i %d\n", dev->name, len, err);
-		dev->stats.rx_dropped++;
-		goto drop;
-	}
 	skb->truesize += skb->data_len;
 	dev->stats.rx_bytes += skb->len;
 	dev->stats.rx_packets++;
@@ -194,7 +269,7 @@
 	dev_kfree_skb(skb);
 }
 
-static void try_fill_recv(struct virtnet_info *vi)
+static void try_fill_recv_maxbufs(struct virtnet_info *vi)
 {
 	struct sk_buff *skb;
 	struct scatterlist sg[2+MAX_SKB_FRAGS];
@@ -202,12 +277,16 @@
 
 	sg_init_table(sg, 2+MAX_SKB_FRAGS);
 	for (;;) {
+		struct virtio_net_hdr *hdr;
+
 		skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN);
 		if (unlikely(!skb))
 			break;
 
 		skb_put(skb, MAX_PACKET_LEN);
-		vnet_hdr_to_sg(sg, skb);
+
+		hdr = skb_vnet_hdr(skb);
+		sg_init_one(sg, hdr, sizeof(*hdr));
 
 		if (vi->big_packets) {
 			for (i = 0; i < MAX_SKB_FRAGS; i++) {
@@ -232,6 +311,55 @@
 		err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb);
 		if (err) {
 			skb_unlink(skb, &vi->recv);
+			trim_pages(vi, skb);
+			kfree_skb(skb);
+			break;
+		}
+		vi->num++;
+	}
+	if (unlikely(vi->num > vi->max))
+		vi->max = vi->num;
+	vi->rvq->vq_ops->kick(vi->rvq);
+}
+
+static void try_fill_recv(struct virtnet_info *vi)
+{
+	struct sk_buff *skb;
+	struct scatterlist sg[1];
+	int err;
+
+	if (!vi->mergeable_rx_bufs) {
+		try_fill_recv_maxbufs(vi);
+		return;
+	}
+
+	for (;;) {
+		skb_frag_t *f;
+
+		skb = netdev_alloc_skb(vi->dev, GOOD_COPY_LEN + NET_IP_ALIGN);
+		if (unlikely(!skb))
+			break;
+
+		skb_reserve(skb, NET_IP_ALIGN);
+
+		f = &skb_shinfo(skb)->frags[0];
+		f->page = get_a_page(vi, GFP_ATOMIC);
+		if (!f->page) {
+			kfree_skb(skb);
+			break;
+		}
+
+		f->page_offset = 0;
+		f->size = PAGE_SIZE;
+
+		skb_shinfo(skb)->nr_frags++;
+
+		sg_init_one(sg, page_address(f->page), PAGE_SIZE);
+		skb_queue_head(&vi->recv, skb);
+
+		err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 1, skb);
+		if (err) {
+			skb_unlink(skb, &vi->recv);
 			kfree_skb(skb);
 			break;
 		}
@@ -246,9 +374,9 @@
 {
 	struct virtnet_info *vi = rvq->vdev->priv;
 	/* Schedule NAPI, Suppress further interrupts if successful. */
-	if (netif_rx_schedule_prep(vi->dev, &vi->napi)) {
+	if (netif_rx_schedule_prep(&vi->napi)) {
 		rvq->vq_ops->disable_cb(rvq);
-		__netif_rx_schedule(vi->dev, &vi->napi);
+		__netif_rx_schedule(&vi->napi);
 	}
 }
 
@@ -274,11 +402,11 @@
 
 	/* Out of packets? */
 	if (received < budget) {
-		netif_rx_complete(vi->dev, napi);
+		netif_rx_complete(napi);
 		if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq))
 		    && napi_schedule_prep(napi)) {
 			vi->rvq->vq_ops->disable_cb(vi->rvq);
-			__netif_rx_schedule(vi->dev, napi);
+			__netif_rx_schedule(napi);
 			goto again;
 		}
 	}
@@ -320,17 +448,14 @@
 {
 	int num, err;
 	struct scatterlist sg[2+MAX_SKB_FRAGS];
-	struct virtio_net_hdr *hdr;
+	struct virtio_net_hdr_mrg_rxbuf *mhdr = skb_vnet_hdr(skb);
+	struct virtio_net_hdr *hdr = skb_vnet_hdr(skb);
 	const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
 
 	sg_init_table(sg, 2+MAX_SKB_FRAGS);
 
-	pr_debug("%s: xmit %p " MAC_FMT "\n", vi->dev->name, skb,
-		 dest[0], dest[1], dest[2],
-		 dest[3], dest[4], dest[5]);
+	pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
 
-	/* Encode metadata header at front. */
-	hdr = skb_vnet_hdr(skb);
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
 		hdr->csum_start = skb->csum_start - skb_headroom(skb);
@@ -358,7 +483,14 @@
 		hdr->gso_size = hdr->hdr_len = 0;
 	}
 
-	vnet_hdr_to_sg(sg, skb);
+	mhdr->num_buffers = 0;
+
+	/* Encode metadata header at front. */
+	if (vi->mergeable_rx_bufs)
+		sg_init_one(sg, mhdr, sizeof(*mhdr));
+	else
+		sg_init_one(sg, hdr, sizeof(*hdr));
+
 	num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
 
 	err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
@@ -448,9 +580,9 @@
 	 * won't get another interrupt, so process any outstanding packets
 	 * now.  virtnet_poll wants re-enable the queue, so we disable here.
 	 * We synchronize against interrupts via NAPI_STATE_SCHED */
-	if (netif_rx_schedule_prep(dev, &vi->napi)) {
+	if (netif_rx_schedule_prep(&vi->napi)) {
 		vi->rvq->vq_ops->disable_cb(vi->rvq);
-		__netif_rx_schedule(dev, &vi->napi);
+		__netif_rx_schedule(&vi->napi);
 	}
 	return 0;
 }
@@ -478,8 +610,20 @@
 static struct ethtool_ops virtnet_ethtool_ops = {
 	.set_tx_csum = virtnet_set_tx_csum,
 	.set_sg = ethtool_op_set_sg,
+	.set_tso = ethtool_op_set_tso,
 };
 
+#define MIN_MTU 68
+#define MAX_MTU 65535
+
+static int virtnet_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if (new_mtu < MIN_MTU || new_mtu > MAX_MTU)
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
 static int virtnet_probe(struct virtio_device *vdev)
 {
 	int err;
@@ -495,6 +639,7 @@
 	dev->open = virtnet_open;
 	dev->stop = virtnet_close;
 	dev->hard_start_xmit = start_xmit;
+	dev->change_mtu = virtnet_change_mtu;
 	dev->features = NETIF_F_HIGHDMA;
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = virtnet_netpoll;
@@ -547,6 +692,9 @@
 	    || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
 		vi->big_packets = true;
 
+	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)) {
@@ -639,6 +787,7 @@
 	VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
 	VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
 	VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */
+	VIRTIO_NET_F_MRG_RXBUF,
 	VIRTIO_F_NOTIFY_ON_EMPTY,
 };
 
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 21efd99..d08ce6a 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -207,6 +207,8 @@
 	tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
 	depends on HDLC && PCI && BROKEN
 	---help---
+	  This driver is broken because of struct tty_driver change.
+
 	  Driver for the Cyclades-PC300 synchronous communication boards.
 
 	  These boards provide synchronous serial interfaces to your
@@ -333,6 +335,13 @@
 
 	  Say Y if your card supports this feature.
 
+config IXP4XX_HSS
+	tristate "Intel IXP4xx HSS (synchronous serial port) support"
+	depends on HDLC && ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
+	help
+	  Say Y here if you want to use built-in HSS ports
+	  on IXP4xx processor.
+
 config DLCI
 	tristate "Frame Relay DLCI support"
 	---help---
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 1025496..19d14bc 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -14,7 +14,7 @@
 obj-$(CONFIG_HDLC_RAW_ETH)	+= hdlc_raw_eth.o
 obj-$(CONFIG_HDLC_CISCO)	+= hdlc_cisco.o
 obj-$(CONFIG_HDLC_FR)		+= hdlc_fr.o
-obj-$(CONFIG_HDLC_PPP)		+= hdlc_ppp.o	syncppp.o
+obj-$(CONFIG_HDLC_PPP)		+= hdlc_ppp.o
 obj-$(CONFIG_HDLC_X25)		+= hdlc_x25.o
 
 pc300-y				:= pc300_drv.o
@@ -41,6 +41,7 @@
 obj-$(CONFIG_WANXL)		+= wanxl.o
 obj-$(CONFIG_PCI200SYN)		+= pci200syn.o
 obj-$(CONFIG_PC300TOO)		+= pc300too.o
+obj-$(CONFIG_IXP4XX_HSS)	+= ixp4xx_hss.o
 
 clean-files := wanxlfw.inc
 $(obj)/wanxl.o:	$(obj)/wanxlfw.inc
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index c8e5631..b468979 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -88,7 +88,7 @@
 /* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */
 #define sca_outw(value, reg, card) do { \
 	writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \
-	writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg+1));\
+	writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\
 } while(0)
 
 #define port_to_card(port)	   (port)
@@ -113,7 +113,7 @@
 }
 
 
-#include "hd6457x.c"
+#include "hd64570.c"
 
 
 static inline void set_carrier(port_t *port)
@@ -381,7 +381,7 @@
 		return result;
 	}
 
-	sca_init_sync_port(card); /* Set up C101 memory */
+	sca_init_port(card); /* Set up C101 memory */
 	set_carrier(card);
 
 	printk(KERN_INFO "%s: Moxa C101 on IRQ%u,"
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 7f97f8d..d80b72e 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -754,7 +754,6 @@
 	chan->netdev->stats.rx_bytes += chan->cosa->rxsize;
 	netif_rx(chan->rx_skb);
 	chan->rx_skb = NULL;
-	chan->netdev->last_rx = jiffies;
 	return 0;
 }
 
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index 5a7303d..5fa5292 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -199,6 +199,8 @@
 static struct net_device *
 	cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte);
 
+static void cycx_x25_chan_setup(struct net_device *dev);
+
 #ifdef CYCLOMX_X25_DEBUG
 static void hex_dump(char *msg, unsigned char *p, int len);
 static void cycx_x25_dump_config(struct cycx_x25_config *conf);
@@ -353,6 +355,12 @@
 	return 0;
 }
 
+/* callback to initialize device */
+static void cycx_x25_chan_setup(struct net_device *dev)
+{
+	dev->init = cycx_netdevice_init;
+}
+
 /* Create new logical channel.
  * This routine is called by the router when ROUTER_IFNEW IOCTL is being
  * handled.
@@ -376,11 +384,12 @@
 		return -EINVAL;
 	}
 
-	/* allocate and initialize private data */
-	chan = kzalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL);
-	if (!chan)
+	dev = alloc_netdev(sizeof(struct cycx_x25_channel), conf->name,
+			     cycx_x25_chan_setup);
+	if (!dev)
 		return -ENOMEM;
 
+	chan = netdev_priv(dev);
 	strcpy(chan->name, conf->name);
 	chan->card = card;
 	chan->link = conf->port;
@@ -396,14 +405,14 @@
 			if (len > WAN_ADDRESS_SZ) {
 				printk(KERN_ERR "%s: %s local addr too long!\n",
 						wandev->name, chan->name);
-				kfree(chan);
-				return -EINVAL;
+				err = -EINVAL;
+				goto error;
 			} else {
 				chan->local_addr = kmalloc(len + 1, GFP_KERNEL);
 
 				if (!chan->local_addr) {
-					kfree(chan);
-					return -ENOMEM;
+					err = -ENOMEM;
+					goto error;
 				}
 			}
 
@@ -429,41 +438,31 @@
 				"%s: PVC %u is out of range on interface %s!\n",
 				wandev->name, lcn, chan->name);
 			err = -EINVAL;
+			goto error;
 		}
 	} else {
 		printk(KERN_ERR "%s: invalid media address on interface %s!\n",
 				wandev->name, chan->name);
 		err = -EINVAL;
+		goto error;
 	}
 
-	if (err) {
-		kfree(chan->local_addr);
-		kfree(chan);
-		return err;
-	}
-
-	/* prepare network device data space for registration */
-	strcpy(dev->name, chan->name);
-	dev->init = cycx_netdevice_init;
-	dev->priv = chan;
-
 	return 0;
+
+error:
+	free_netdev(dev);
+	return err;
 }
 
 /* Delete logical channel. */
 static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev)
 {
-	if (dev->priv) {
-		struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_x25_channel *chan = netdev_priv(dev);
 
-		if (chan->svc) {
-			kfree(chan->local_addr);
-			if (chan->state == WAN_CONNECTED)
-				del_timer(&chan->timer);
-		}
-
-		kfree(chan);
-		dev->priv = NULL;
+	if (chan->svc) {
+		kfree(chan->local_addr);
+		if (chan->state == WAN_CONNECTED)
+			del_timer(&chan->timer);
 	}
 
 	return 0;
@@ -484,7 +483,7 @@
  * registration. */
 static int cycx_netdevice_init(struct net_device *dev)
 {
-	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_x25_channel *chan = netdev_priv(dev);
 	struct cycx_device *card = chan->card;
 	struct wan_device *wandev = &card->wandev;
 
@@ -542,7 +541,7 @@
  * o if there's no more open channels then disconnect physical link. */
 static int cycx_netdevice_stop(struct net_device *dev)
 {
-	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_x25_channel *chan = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 
@@ -596,7 +595,7 @@
 static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
 					  struct net_device *dev)
 {
-	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_x25_channel *chan = netdev_priv(dev);
 	struct cycx_device *card = chan->card;
 
 	if (!chan->svc)
@@ -670,7 +669,7 @@
  * Return a pointer to struct net_device_stats */
 static struct net_device_stats *cycx_netdevice_get_stats(struct net_device *dev)
 {
-	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_x25_channel *chan = netdev_priv(dev);
 
 	return chan ? &chan->ifstats : NULL;
 }
@@ -783,7 +782,7 @@
 		return;
 	}
 
-	chan = dev->priv;
+	chan = netdev_priv(dev);
 	reset_timer(dev);
 
 	if (chan->drop_sequence) {
@@ -843,7 +842,6 @@
 
 	skb_reset_mac_header(skb);
 	netif_rx(skb);
-	dev->last_rx = jiffies;		/* timestamp */
 }
 
 /* Connect interrupt handler. */
@@ -884,7 +882,7 @@
 		return;
 	}
 
-	chan = dev->priv;
+	chan = netdev_priv(dev);
 	chan->lcn = lcn;
 	cycx_x25_connect_response(card, chan);
 	cycx_x25_set_chan_state(dev, WAN_CONNECTED);
@@ -914,7 +912,7 @@
 	}
 
 	clear_bit(--key, (void*)&card->u.x.connection_keys);
-	chan = dev->priv;
+	chan = netdev_priv(dev);
 	chan->lcn = lcn;
 	cycx_x25_set_chan_state(dev, WAN_CONNECTED);
 }
@@ -954,7 +952,7 @@
 
 	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
 	if (dev) {
-		struct cycx_x25_channel *chan = dev->priv;
+		struct cycx_x25_channel *chan = netdev_priv(dev);
 
 		cycx_x25_disconnect_response(card, chan->link, lcn);
 		cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
@@ -1302,7 +1300,7 @@
 	struct cycx_x25_channel *chan;
 
 	while (dev) {
-		chan = (struct cycx_x25_channel*)dev->priv;
+		chan = netdev_priv(dev);
 
 		if (chan->lcn == lcn)
 			break;
@@ -1319,7 +1317,7 @@
 	struct cycx_x25_channel *chan;
 
 	while (dev) {
-		chan = (struct cycx_x25_channel*)dev->priv;
+		chan = netdev_priv(dev);
 
 		if (!strcmp(chan->addr, dte))
 			break;
@@ -1337,7 +1335,7 @@
  *		<0	failure */
 static int cycx_x25_chan_connect(struct net_device *dev)
 {
-	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_x25_channel *chan = netdev_priv(dev);
 	struct cycx_device *card = chan->card;
 
 	if (chan->svc) {
@@ -1362,7 +1360,7 @@
  * o if SVC then clear X.25 call */
 static void cycx_x25_chan_disconnect(struct net_device *dev)
 {
-	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_x25_channel *chan = netdev_priv(dev);
 
 	if (chan->svc) {
 		x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0);
@@ -1375,7 +1373,7 @@
 static void cycx_x25_chan_timer(unsigned long d)
 {
 	struct net_device *dev = (struct net_device *)d;
-	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_x25_channel *chan = netdev_priv(dev);
 
 	if (chan->state == WAN_CONNECTED)
 		cycx_x25_chan_disconnect(dev);
@@ -1387,7 +1385,7 @@
 /* Set logical channel state. */
 static void cycx_x25_set_chan_state(struct net_device *dev, u8 state)
 {
-	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_x25_channel *chan = netdev_priv(dev);
 	struct cycx_device *card = chan->card;
 	unsigned long flags;
 	char *string_state = NULL;
@@ -1453,7 +1451,7 @@
  *    to the router.  */
 static int cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb)
 {
-	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_x25_channel *chan = netdev_priv(dev);
 	struct cycx_device *card = chan->card;
 	int bitm = 0;		/* final packet */
 	unsigned len = skb->len;
@@ -1494,7 +1492,6 @@
 
 	skb->protocol = x25_type_trans(skb, dev);
 	netif_rx(skb);
-	dev->last_rx = jiffies;		/* timestamp */
 }
 
 /* Convert line speed in bps to a number used by cyclom 2x code. */
@@ -1547,7 +1544,7 @@
 
 static void reset_timer(struct net_device *dev)
 {
-	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_x25_channel *chan = netdev_priv(dev);
 
 	if (chan->svc)
 		mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ);
@@ -1600,7 +1597,7 @@
 	printk(KERN_INFO "---------------------------------------\n");
 
 	while(dev) {
-		struct cycx_x25_channel *chan = dev->priv;
+		struct cycx_x25_channel *chan = netdev_priv(dev);
 
 		printk(KERN_INFO "%-5.5s %-15.15s   %d     ETH_P_%s\n",
 				 chan->name, chan->addr, netif_queue_stopped(dev),
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index b142427..a297e3e 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -74,7 +74,7 @@
 	unsigned int		hlen;
 	char			*dest;
 
-	dlp = dev->priv;
+	dlp = netdev_priv(dev);
 
 	hdr.control = FRAD_I_UI;
 	switch(type)
@@ -110,7 +110,7 @@
 	struct frhdr		*hdr;
 	int					process, header;
 
-	dlp = dev->priv;
+	dlp = netdev_priv(dev);
 	if (!pskb_may_pull(skb, sizeof(*hdr))) {
 		printk(KERN_NOTICE "%s: invalid data no header\n",
 		       dev->name);
@@ -181,7 +181,6 @@
 		dlp->stats.rx_bytes += skb->len;
 		netif_rx(skb);
 		dlp->stats.rx_packets++;
-		dev->last_rx = jiffies;
 	}
 	else
 		dev_kfree_skb(skb);
@@ -197,7 +196,7 @@
 	if (!skb || !dev)
 		return(0);
 
-	dlp = dev->priv;
+	dlp = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 	
@@ -235,9 +234,9 @@
 	struct frad_local	*flp;
 	int			err;
 
-	dlp = dev->priv;
+	dlp = netdev_priv(dev);
 
-	flp = dlp->slave->priv;
+	flp = netdev_priv(dlp->slave);
 
 	if (!get)
 	{
@@ -269,7 +268,7 @@
 	if (!capable(CAP_NET_ADMIN))
 		return(-EPERM);
 
-	dlp = dev->priv;
+	dlp = netdev_priv(dev);
 
 	switch(cmd)
 	{
@@ -298,7 +297,7 @@
 {
 	struct dlci_local *dlp;
 
-	dlp = dev->priv;
+	dlp = netdev_priv(dev);
 
 	return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
 }
@@ -309,7 +308,7 @@
 	struct frad_local	*flp;
 	int			err;
 
-	dlp = dev->priv;
+	dlp = netdev_priv(dev);
 
 	if (!*(short *)(dev->dev_addr))
 		return(-EINVAL);
@@ -317,7 +316,7 @@
 	if (!netif_running(dlp->slave))
 		return(-ENOTCONN);
 
-	flp = dlp->slave->priv;
+	flp = netdev_priv(dlp->slave);
 	err = (*flp->activate)(dlp->slave, dev);
 	if (err)
 		return(err);
@@ -335,9 +334,9 @@
 
 	netif_stop_queue(dev);
 
-	dlp = dev->priv;
+	dlp = netdev_priv(dev);
 
-	flp = dlp->slave->priv;
+	flp = netdev_priv(dlp->slave);
 	err = (*flp->deactivate)(dlp->slave, dev);
 
 	return 0;
@@ -347,7 +346,7 @@
 {
 	struct dlci_local *dlp;
 
-	dlp = dev->priv;
+	dlp = netdev_priv(dev);
 
 	return(&dlp->stats);
 }
@@ -365,7 +364,7 @@
 	if (!slave)
 		return -ENODEV;
 
-	if (slave->type != ARPHRD_FRAD || slave->priv == NULL)
+	if (slave->type != ARPHRD_FRAD || netdev_priv(slave) == NULL)
 		goto err1;
 
 	/* create device name */
@@ -391,11 +390,11 @@
 
 	*(short *)(master->dev_addr) = dlci->dlci;
 
-	dlp = (struct dlci_local *) master->priv;
+	dlp = netdev_priv(master);
 	dlp->slave = slave;
 	dlp->master = master;
 
-	flp = slave->priv;
+	flp = netdev_priv(slave);
 	err = (*flp->assoc)(slave, master);
 	if (err < 0)
 		goto err2;
@@ -435,9 +434,9 @@
 		return(-EBUSY);
 	}
 
-	dlp = master->priv;
+	dlp = netdev_priv(master);
 	slave = dlp->slave;
-	flp = slave->priv;
+	flp = netdev_priv(slave);
 
 	rtnl_lock();
 	err = (*flp->deassoc)(slave, master);
@@ -491,7 +490,7 @@
 
 static void dlci_setup(struct net_device *dev)
 {
-	struct dlci_local *dlp = dev->priv;
+	struct dlci_local *dlp = netdev_priv(dev);
 
 	dev->flags		= 0;
 	dev->open		= dlci_open;
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 5f1ccb2..888025d 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -659,7 +659,6 @@
 		skb_put(skb, pkt_len);
 		if (netif_running(dev))
 			skb->protocol = hdlc_type_trans(skb, dev);
-		skb->dev->last_rx = jiffies;
 		netif_rx(skb);
 	} else {
 		if (skb->data[pkt_len] & FrameRdo)
@@ -730,8 +729,7 @@
 	        goto err_free_mmio_region_1;
 	}
 
-	ioaddr = ioremap(pci_resource_start(pdev, 0),
-					pci_resource_len(pdev, 0));
+	ioaddr = pci_ioremap_bar(pdev, 0);
 	if (!ioaddr) {
 		printk(KERN_ERR "%s: cannot remap MMIO region %llx @ %llx\n",
 			DRV_NAME, (unsigned long long)pci_resource_len(pdev, 0),
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 9557ad0..48a2c9d 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -896,7 +896,6 @@
 	fst_process_rx_status(rx_status, port_to_dev(port)->name);
 	if (rx_status == NET_RX_DROP)
 		dev->stats.rx_dropped++;
-	dev->last_rx = jiffies;
 }
 
 /*
@@ -1322,7 +1321,6 @@
 		fst_process_rx_status(rx_status, port_to_dev(port)->name);
 		if (rx_status == NET_RX_DROP)
 			dev->stats.rx_dropped++;
-		dev->last_rx = jiffies;
 	} else {
 		card->dma_skb_rx = skb;
 		card->dma_port_rx = port;
diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd64570.c
similarity index 77%
rename from drivers/net/wan/hd6457x.c
rename to drivers/net/wan/hd64570.c
index 591fb45..223238d 100644
--- a/drivers/net/wan/hd6457x.c
+++ b/drivers/net/wan/hd64570.c
@@ -1,5 +1,5 @@
 /*
- * Hitachi SCA HD64570 and HD64572 common driver for Linux
+ * Hitachi SCA HD64570 driver for Linux
  *
  * Copyright (C) 1998-2003 Krzysztof Halasa <khc@pm.waw.pl>
  *
@@ -7,9 +7,7 @@
  * under the terms of version 2 of the GNU General Public License
  * as published by the Free Software Foundation.
  *
- * Sources of information:
- *    Hitachi HD64570 SCA User's Manual
- *    Hitachi HD64572 SCA-II User's Manual
+ * Source of information: Hitachi HD64570 SCA User's Manual
  *
  * We use the following SCA memory map:
  *
@@ -26,33 +24,26 @@
  * tx_ring_buffers * HDLC_MAX_MRU     = logical channel #0 TX buffers (if used)
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
 #include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/hdlc.h>
+#include <linux/in.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
-
-#include <linux/hdlc.h>
-
-#if (!defined (__HD64570_H) && !defined (__HD64572_H)) || \
-    (defined (__HD64570_H) && defined (__HD64572_H))
-#error Either hd64570.h or hd64572.h must be included
-#endif
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include "hd64570.h"
 
 #define get_msci(port)	  (phy_node(port) ?   MSCI1_OFFSET :   MSCI0_OFFSET)
 #define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
@@ -62,16 +53,6 @@
 #define SCA_INTR_DMAC_RX(node) (node ? 0x20 : 0x02)
 #define SCA_INTR_DMAC_TX(node) (node ? 0x40 : 0x04)
 
-#ifdef __HD64570_H /* HD64570 */
-#define sca_outa(value, reg, card)	sca_outw(value, reg, card)
-#define sca_ina(reg, card)		sca_inw(reg, card)
-#define writea(value, ptr)		writew(value, ptr)
-
-#else /* HD64572 */
-#define sca_outa(value, reg, card)	sca_outl(value, reg, card)
-#define sca_ina(reg, card)		sca_inl(reg, card)
-#define writea(value, ptr)		writel(value, ptr)
-#endif
 
 static inline struct net_device *port_to_dev(port_t *port)
 {
@@ -81,8 +62,6 @@
 static inline int sca_intr_status(card_t *card)
 {
 	u8 result = 0;
-
-#ifdef __HD64570_H /* HD64570 */
 	u8 isr0 = sca_in(ISR0, card);
 	u8 isr1 = sca_in(ISR1, card);
 
@@ -93,18 +72,6 @@
 	if (isr0 & 0x0F) result |= SCA_INTR_MSCI(0);
 	if (isr0 & 0xF0) result |= SCA_INTR_MSCI(1);
 
-#else /* HD64572 */
-	u32 isr0 = sca_inl(ISR0, card);
-
-	if (isr0 & 0x0000000F) result |= SCA_INTR_DMAC_RX(0);
-	if (isr0 & 0x000000F0) result |= SCA_INTR_DMAC_TX(0);
-	if (isr0 & 0x00000F00) result |= SCA_INTR_DMAC_RX(1);
-	if (isr0 & 0x0000F000) result |= SCA_INTR_DMAC_TX(1);
-	if (isr0 & 0x003E0000) result |= SCA_INTR_MSCI(0);
-	if (isr0 & 0x3E000000) result |= SCA_INTR_MSCI(1);
-
-#endif /* HD64570 vs HD64572 */
-
 	if (!(result & SCA_INTR_DMAC_TX(0)))
 		if (sca_in(DSR_TX(0), card) & DSR_EOM)
 			result |= SCA_INTR_DMAC_TX(0);
@@ -127,7 +94,6 @@
 }
 
 
-
 static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit)
 {
 	u16 rx_buffs = port_to_card(port)->rx_ring_buffers;
@@ -139,28 +105,26 @@
 }
 
 
-
 static inline u16 desc_offset(port_t *port, u16 desc, int transmit)
 {
-	/* Descriptor offset always fits in 16 bytes */
+	/* Descriptor offset always fits in 16 bits */
 	return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc);
 }
 
 
-
-static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc, int transmit)
+static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc,
+					     int transmit)
 {
 #ifdef PAGE0_ALWAYS_MAPPED
 	return (pkt_desc __iomem *)(win0base(port_to_card(port))
-			   + desc_offset(port, desc, transmit));
+				    + desc_offset(port, desc, transmit));
 #else
 	return (pkt_desc __iomem *)(winbase(port_to_card(port))
-			   + desc_offset(port, desc, transmit));
+				    + desc_offset(port, desc, transmit));
 #endif
 }
 
 
-
 static inline u32 buffer_offset(port_t *port, u16 desc, int transmit)
 {
 	return port_to_card(port)->buff_offset +
@@ -186,7 +150,7 @@
 }
 
 
-static void sca_init_sync_port(port_t *port)
+static void sca_init_port(port_t *port)
 {
 	card_t *card = port_to_card(port);
 	int transmit, i;
@@ -195,7 +159,7 @@
 	port->txin = 0;
 	port->txlast = 0;
 
-#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
+#ifndef PAGE0_ALWAYS_MAPPED
 	openwin(card, 0);
 #endif
 
@@ -209,7 +173,7 @@
 			u16 chain_off = desc_offset(port, i + 1, transmit);
 			u32 buff_off = buffer_offset(port, i, transmit);
 
-			writea(chain_off, &desc->cp);
+			writew(chain_off, &desc->cp);
 			writel(buff_off, &desc->bp);
 			writew(0, &desc->len);
 			writeb(0, &desc->stat);
@@ -222,16 +186,14 @@
 		sca_out(DCR_ABORT, transmit ? DCR_TX(phy_node(port)) :
 			DCR_RX(phy_node(port)), card);
 
-#ifdef __HD64570_H
-		sca_out(0, dmac + CPB, card); /* pointer base */
-#endif
 		/* current desc addr */
-		sca_outa(desc_offset(port, 0, transmit), dmac + CDAL, card);
+		sca_out(0, dmac + CPB, card); /* pointer base */
+		sca_outw(desc_offset(port, 0, transmit), dmac + CDAL, card);
 		if (!transmit)
-			sca_outa(desc_offset(port, buffs - 1, transmit),
+			sca_outw(desc_offset(port, buffs - 1, transmit),
 				 dmac + EDAL, card);
 		else
-			sca_outa(desc_offset(port, 0, transmit), dmac + EDAL,
+			sca_outw(desc_offset(port, 0, transmit), dmac + EDAL,
 				 card);
 
 		/* clear frame end interrupt counter */
@@ -258,7 +220,6 @@
 }
 
 
-
 #ifdef NEED_SCA_MSCI_INTR
 /* MSCI interrupt service */
 static inline void sca_msci_intr(port_t *port)
@@ -282,17 +243,15 @@
 #endif
 
 
-
-static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u16 rxin)
+static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc,
+			  u16 rxin)
 {
 	struct net_device *dev = port_to_dev(port);
 	struct sk_buff *skb;
 	u16 len;
 	u32 buff;
-#ifndef ALL_PAGES_ALWAYS_MAPPED
 	u32 maxlen;
 	u8 page;
-#endif
 
 	len = readw(&desc->len);
 	skb = dev_alloc_skb(len);
@@ -302,7 +261,6 @@
 	}
 
 	buff = buffer_offset(port, rxin, 0);
-#ifndef ALL_PAGES_ALWAYS_MAPPED
 	page = buff / winsize(card);
 	buff = buff % winsize(card);
 	maxlen = winsize(card) - buff;
@@ -314,12 +272,10 @@
 		openwin(card, page + 1);
 		memcpy_fromio(skb->data + maxlen, winbase(card), len - maxlen);
 	} else
-#endif
-	memcpy_fromio(skb->data, winbase(card) + buff, len);
+		memcpy_fromio(skb->data, winbase(card) + buff, len);
 
-#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
-	/* select pkt_desc table page back */
-	openwin(card, 0);
+#ifndef PAGE0_ALWAYS_MAPPED
+	openwin(card, 0);	/* select pkt_desc table page back */
 #endif
 	skb_put(skb, len);
 #ifdef DEBUG_PKT
@@ -328,13 +284,11 @@
 #endif
 	dev->stats.rx_packets++;
 	dev->stats.rx_bytes += skb->len;
-	dev->last_rx = jiffies;
 	skb->protocol = hdlc_type_trans(skb, dev);
 	netif_rx(skb);
 }
 
 
-
 /* Receive DMA interrupt service */
 static inline void sca_rx_intr(port_t *port)
 {
@@ -354,7 +308,7 @@
 	while (1) {
 		u32 desc_off = desc_offset(port, port->rxin, 0);
 		pkt_desc __iomem *desc;
-		u32 cda = sca_ina(dmac + CDAL, card);
+		u32 cda = sca_inw(dmac + CDAL, card);
 
 		if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
 			break;	/* No frame received */
@@ -378,7 +332,7 @@
 			sca_rx(card, port, desc, port->rxin);
 
 		/* Set new error descriptor address */
-		sca_outa(desc_off, dmac + EDAL, card);
+		sca_outw(desc_off, dmac + EDAL, card);
 		port->rxin = next_desc(port, port->rxin, 0);
 	}
 
@@ -387,7 +341,6 @@
 }
 
 
-
 /* Transmit DMA interrupt service */
 static inline void sca_tx_intr(port_t *port)
 {
@@ -408,7 +361,7 @@
 		pkt_desc __iomem *desc;
 
 		u32 desc_off = desc_offset(port, port->txlast, 1);
-		u32 cda = sca_ina(dmac + CDAL, card);
+		u32 cda = sca_inw(dmac + CDAL, card);
 		if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
 			break;	/* Transmitter is/will_be sending this frame */
 
@@ -424,17 +377,13 @@
 }
 
 
-
 static irqreturn_t sca_intr(int irq, void* dev_id)
 {
 	card_t *card = dev_id;
 	int i;
 	u8 stat;
 	int handled = 0;
-
-#ifndef ALL_PAGES_ALWAYS_MAPPED
 	u8 page = sca_get_page(card);
-#endif
 
 	while((stat = sca_intr_status(card)) != 0) {
 		handled = 1;
@@ -453,14 +402,11 @@
 		}
 	}
 
-#ifndef ALL_PAGES_ALWAYS_MAPPED
 	openwin(card, page);		/* Restore original page */
-#endif
 	return IRQ_RETVAL(handled);
 }
 
 
-
 static void sca_set_port(port_t *port)
 {
 	card_t* card = port_to_card(port);
@@ -498,12 +444,7 @@
 	port->tmc = tmc;
 
 	/* baud divisor - time constant*/
-#ifdef __HD64570_H
 	sca_out(port->tmc, msci + TMC, card);
-#else
-	sca_out(port->tmc, msci + TMCR, card);
-	sca_out(port->tmc, msci + TMCT, card);
-#endif
 
 	/* Set BRG bits */
 	sca_out(port->rxs, msci + RXS, card);
@@ -519,7 +460,6 @@
 }
 
 
-
 static void sca_open(struct net_device *dev)
 {
 	port_t *port = dev_to_port(dev);
@@ -541,11 +481,7 @@
 	switch(port->parity) {
 	case PARITY_CRC16_PR0:	     md0 = MD0_HDLC | MD0_CRC_16_0;  break;
 	case PARITY_CRC16_PR1:	     md0 = MD0_HDLC | MD0_CRC_16;    break;
-#ifdef __HD64570_H
 	case PARITY_CRC16_PR0_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU_0; break;
-#else
-	case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break;
-#endif
 	case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU;   break;
 	default:		     md0 = MD0_HDLC | MD0_CRC_NONE;
 	}
@@ -555,35 +491,20 @@
 	sca_out(0x00, msci + MD1, card); /* no address field check */
 	sca_out(md2, msci + MD2, card);
 	sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */
-#ifdef __HD64570_H
 	sca_out(CTL_IDLE, msci + CTL, card);
-#else
-	/* Skip the rest of underrun frame */
-	sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card);
-#endif
 
-#ifdef __HD64570_H
 	/* Allow at least 8 bytes before requesting RX DMA operation */
 	/* TX with higher priority and possibly with shorter transfers */
 	sca_out(0x07, msci + RRC, card); /* +1=RXRDY/DMA activation condition*/
 	sca_out(0x10, msci + TRC0, card); /* = TXRDY/DMA activation condition*/
 	sca_out(0x14, msci + TRC1, card); /* +1=TXRDY/DMA deactiv condition */
-#else
-	sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */
-	sca_out(0x3C, msci + TFS, card); /* +1 = TX start */
-	sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */
-	sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */
-	sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/
-#endif
 
 /* We're using the following interrupts:
    - TXINT (DMAC completed all transmisions, underrun or DCD change)
    - all DMA interrupts
 */
-
 	sca_set_carrier(port);
 
-#ifdef __HD64570_H
 	/* MSCI TX INT and RX INT A IRQ enable */
 	sca_out(IE0_TXINT | IE0_RXINTA, msci + IE0, card);
 	sca_out(IE1_UDRN | IE1_CDCD, msci + IE1, card);
@@ -592,21 +513,8 @@
 	/* enable DMA IRQ */
 	sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F),
 		IER1, card);
-#else
-	/* MSCI TXINT and RXINTA interrupt enable */
-	sca_outl(IE0_TXINT | IE0_RXINTA | IE0_UDRN | IE0_CDCD, msci + IE0,
-		 card);
-	/* DMA & MSCI IRQ enable */
-	sca_outl(sca_inl(IER0, card) |
-		 (phy_node(port) ? 0x0A006600 : 0x000A0066), IER0, card);
-#endif
 
-#ifdef __HD64570_H
 	sca_out(port->tmc, msci + TMC, card); /* Restore registers */
-#else
-	sca_out(port->tmc, msci + TMCR, card);
-	sca_out(port->tmc, msci + TMCT, card);
-#endif
 	sca_out(port->rxs, msci + RXS, card);
 	sca_out(port->txs, msci + TXS, card);
 	sca_out(CMD_TX_ENABLE, msci + CMD, card);
@@ -616,7 +524,6 @@
 }
 
 
-
 static void sca_close(struct net_device *dev)
 {
 	port_t *port = dev_to_port(dev);
@@ -624,23 +531,17 @@
 
 	/* reset channel */
 	sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
-#ifdef __HD64570_H
 	/* disable MSCI interrupts */
 	sca_out(sca_in(IER0, card) & (phy_node(port) ? 0x0F : 0xF0),
 		IER0, card);
 	/* disable DMA interrupts */
 	sca_out(sca_in(IER1, card) & (phy_node(port) ? 0x0F : 0xF0),
 		IER1, card);
-#else
-	/* disable DMA & MSCI IRQ */
-	sca_outl(sca_inl(IER0, card) &
-		 (phy_node(port) ? 0x00FF00FF : 0xFF00FF00), IER0, card);
-#endif
+
 	netif_stop_queue(dev);
 }
 
 
-
 static int sca_attach(struct net_device *dev, unsigned short encoding,
 		      unsigned short parity)
 {
@@ -654,11 +555,7 @@
 	if (parity != PARITY_NONE &&
 	    parity != PARITY_CRC16_PR0 &&
 	    parity != PARITY_CRC16_PR1 &&
-#ifdef __HD64570_H
 	    parity != PARITY_CRC16_PR0_CCITT &&
-#else
-	    parity != PARITY_CRC32_PR1_CCITT &&
-#endif
 	    parity != PARITY_CRC16_PR1_CCITT)
 		return -EINVAL;
 
@@ -668,34 +565,30 @@
 }
 
 
-
 #ifdef DEBUG_RINGS
 static void sca_dump_rings(struct net_device *dev)
 {
 	port_t *port = dev_to_port(dev);
 	card_t *card = port_to_card(port);
 	u16 cnt;
-#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
-	u8 page;
-#endif
+#ifndef PAGE0_ALWAYS_MAPPED
+	u8 page = sca_get_page(card);
 
-#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
-	page = sca_get_page(card);
 	openwin(card, 0);
 #endif
 
 	printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive",
-	       sca_ina(get_dmac_rx(port) + CDAL, card),
-	       sca_ina(get_dmac_rx(port) + EDAL, card),
+	       sca_inw(get_dmac_rx(port) + CDAL, card),
+	       sca_inw(get_dmac_rx(port) + EDAL, card),
 	       sca_in(DSR_RX(phy_node(port)), card), port->rxin,
-	       sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in");
+	       sca_in(DSR_RX(phy_node(port)), card) & DSR_DE ? "" : "in");
 	for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++)
 		printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat)));
 
 	printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
 	       "last=%u %sactive",
-	       sca_ina(get_dmac_tx(port) + CDAL, card),
-	       sca_ina(get_dmac_tx(port) + EDAL, card),
+	       sca_inw(get_dmac_tx(port) + CDAL, card),
+	       sca_inw(get_dmac_tx(port) + EDAL, card),
 	       sca_in(DSR_TX(phy_node(port)), card), port->txin, port->txlast,
 	       sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in");
 
@@ -703,12 +596,8 @@
 		printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat)));
 	printk("\n");
 
-	printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, "
-	       "ST: %02x %02x %02x %02x"
-#ifdef __HD64572_H
-	       " %02x"
-#endif
-	       ", FST: %02x CST: %02x %02x\n",
+	printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, ST: %02x %02x %02x %02x,"
+	       " FST: %02x CST: %02x %02x\n",
 	       sca_in(get_msci(port) + MD0, card),
 	       sca_in(get_msci(port) + MD1, card),
 	       sca_in(get_msci(port) + MD2, card),
@@ -716,52 +605,33 @@
 	       sca_in(get_msci(port) + ST1, card),
 	       sca_in(get_msci(port) + ST2, card),
 	       sca_in(get_msci(port) + ST3, card),
-#ifdef __HD64572_H
-	       sca_in(get_msci(port) + ST4, card),
-#endif
 	       sca_in(get_msci(port) + FST, card),
 	       sca_in(get_msci(port) + CST0, card),
 	       sca_in(get_msci(port) + CST1, card));
 
-#ifdef __HD64572_H
-	printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card),
-	       sca_inl(ISR0, card), sca_inl(ISR1, card));
-#else
 	printk(KERN_DEBUG "ISR: %02x %02x %02x\n", sca_in(ISR0, card),
 	       sca_in(ISR1, card), sca_in(ISR2, card));
-#endif
 
-#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
+#ifndef PAGE0_ALWAYS_MAPPED
 	openwin(card, page); /* Restore original page */
 #endif
 }
 #endif /* DEBUG_RINGS */
 
 
-
 static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	port_t *port = dev_to_port(dev);
 	card_t *card = port_to_card(port);
 	pkt_desc __iomem *desc;
 	u32 buff, len;
-#ifndef ALL_PAGES_ALWAYS_MAPPED
 	u8 page;
 	u32 maxlen;
-#endif
 
 	spin_lock_irq(&port->lock);
 
 	desc = desc_address(port, port->txin + 1, 1);
-	if (readb(&desc->stat)) { /* allow 1 packet gap */
-		/* should never happen - previous xmit should stop queue */
-#ifdef DEBUG_PKT
-		printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name);
-#endif
-		netif_stop_queue(dev);
-		spin_unlock_irq(&port->lock);
-		return 1;	/* request packet to be queued */
-	}
+	BUG_ON(readb(&desc->stat)); /* previous xmit should stop queue */
 
 #ifdef DEBUG_PKT
 	printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len);
@@ -771,7 +641,6 @@
 	desc = desc_address(port, port->txin, 1);
 	buff = buffer_offset(port, port->txin, 1);
 	len = skb->len;
-#ifndef ALL_PAGES_ALWAYS_MAPPED
 	page = buff / winsize(card);
 	buff = buff % winsize(card);
 	maxlen = winsize(card) - buff;
@@ -781,12 +650,10 @@
 		memcpy_toio(winbase(card) + buff, skb->data, maxlen);
 		openwin(card, page + 1);
 		memcpy_toio(winbase(card), skb->data + maxlen, len - maxlen);
-	}
-	else
-#endif
+	} else
 		memcpy_toio(winbase(card) + buff, skb->data, len);
 
-#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
+#ifndef PAGE0_ALWAYS_MAPPED
 	openwin(card, 0);	/* select pkt_desc table page back */
 #endif
 	writew(len, &desc->len);
@@ -794,7 +661,7 @@
 	dev->trans_start = jiffies;
 
 	port->txin = next_desc(port, port->txin, 1);
-	sca_outa(desc_offset(port, port->txin, 1),
+	sca_outw(desc_offset(port, port->txin, 1),
 		 get_dmac_tx(port) + EDAL, card);
 
 	sca_out(DSR_DE, DSR_TX(phy_node(port)), card); /* Enable TX DMA */
@@ -810,40 +677,29 @@
 }
 
 
-
 #ifdef NEED_DETECT_RAM
-static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsize)
+static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase,
+				    u32 ramsize)
 {
 	/* Round RAM size to 32 bits, fill from end to start */
 	u32 i = ramsize &= ~3;
-
-#ifndef ALL_PAGES_ALWAYS_MAPPED
 	u32 size = winsize(card);
 
 	openwin(card, (i - 4) / size); /* select last window */
-#endif
+
 	do {
 		i -= 4;
-#ifndef ALL_PAGES_ALWAYS_MAPPED
 		if ((i + 4) % size == 0)
 			openwin(card, i / size);
 		writel(i ^ 0x12345678, rambase + i % size);
-#else
-		writel(i ^ 0x12345678, rambase + i);
-#endif
-	}while (i > 0);
+	} while (i > 0);
 
 	for (i = 0; i < ramsize ; i += 4) {
-#ifndef ALL_PAGES_ALWAYS_MAPPED
 		if (i % size == 0)
 			openwin(card, i / size);
 
 		if (readl(rambase + i % size) != (i ^ 0x12345678))
 			break;
-#else
-		if (readl(rambase + i) != (i ^ 0x12345678))
-			break;
-#endif
 	}
 
 	return i;
@@ -851,7 +707,6 @@
 #endif /* NEED_DETECT_RAM */
 
 
-
 static void __devinit sca_init(card_t *card, int wait_states)
 {
 	sca_out(wait_states, WCRL, card); /* Wait Control */
diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c
new file mode 100644
index 0000000..08b3536
--- /dev/null
+++ b/drivers/net/wan/hd64572.c
@@ -0,0 +1,640 @@
+/*
+ * Hitachi (now Renesas) SCA-II HD64572 driver for Linux
+ *
+ * Copyright (C) 1998-2008 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ *
+ * Source of information: HD64572 SCA-II User's Manual
+ *
+ * We use the following SCA memory map:
+ *
+ * Packet buffer descriptor rings - starting from card->rambase:
+ * rx_ring_buffers * sizeof(pkt_desc) = logical channel #0 RX ring
+ * tx_ring_buffers * sizeof(pkt_desc) = logical channel #0 TX ring
+ * rx_ring_buffers * sizeof(pkt_desc) = logical channel #1 RX ring (if used)
+ * tx_ring_buffers * sizeof(pkt_desc) = logical channel #1 TX ring (if used)
+ *
+ * Packet data buffers - starting from card->rambase + buff_offset:
+ * rx_ring_buffers * HDLC_MAX_MRU     = logical channel #0 RX buffers
+ * tx_ring_buffers * HDLC_MAX_MRU     = logical channel #0 TX buffers
+ * rx_ring_buffers * HDLC_MAX_MRU     = logical channel #0 RX buffers (if used)
+ * tx_ring_buffers * HDLC_MAX_MRU     = logical channel #0 TX buffers (if used)
+ */
+
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/hdlc.h>
+#include <linux/in.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include "hd64572.h"
+
+#define NAPI_WEIGHT		16
+
+#define get_msci(port)	  (port->chan ?   MSCI1_OFFSET :   MSCI0_OFFSET)
+#define get_dmac_rx(port) (port->chan ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
+#define get_dmac_tx(port) (port->chan ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)
+
+#define sca_in(reg, card)	     readb(card->scabase + (reg))
+#define sca_out(value, reg, card)    writeb(value, card->scabase + (reg))
+#define sca_inw(reg, card)	     readw(card->scabase + (reg))
+#define sca_outw(value, reg, card)   writew(value, card->scabase + (reg))
+#define sca_inl(reg, card)	     readl(card->scabase + (reg))
+#define sca_outl(value, reg, card)   writel(value, card->scabase + (reg))
+
+static int sca_poll(struct napi_struct *napi, int budget);
+
+static inline port_t* dev_to_port(struct net_device *dev)
+{
+	return dev_to_hdlc(dev)->priv;
+}
+
+static inline void enable_intr(port_t *port)
+{
+	/* enable DMIB and MSCI RXINTA interrupts */
+	sca_outl(sca_inl(IER0, port->card) |
+		 (port->chan ? 0x08002200 : 0x00080022), IER0, port->card);
+}
+
+static inline void disable_intr(port_t *port)
+{
+	sca_outl(sca_inl(IER0, port->card) &
+		 (port->chan ? 0x00FF00FF : 0xFF00FF00), IER0, port->card);
+}
+
+static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit)
+{
+	u16 rx_buffs = port->card->rx_ring_buffers;
+	u16 tx_buffs = port->card->tx_ring_buffers;
+
+	desc %= (transmit ? tx_buffs : rx_buffs); // called with "X + 1" etc.
+	return port->chan * (rx_buffs + tx_buffs) + transmit * rx_buffs + desc;
+}
+
+
+static inline u16 desc_offset(port_t *port, u16 desc, int transmit)
+{
+	/* Descriptor offset always fits in 16 bits */
+	return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc);
+}
+
+
+static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc,
+					     int transmit)
+{
+	return (pkt_desc __iomem *)(port->card->rambase +
+				    desc_offset(port, desc, transmit));
+}
+
+
+static inline u32 buffer_offset(port_t *port, u16 desc, int transmit)
+{
+	return port->card->buff_offset +
+		desc_abs_number(port, desc, transmit) * (u32)HDLC_MAX_MRU;
+}
+
+
+static inline void sca_set_carrier(port_t *port)
+{
+	if (!(sca_in(get_msci(port) + ST3, port->card) & ST3_DCD)) {
+#ifdef DEBUG_LINK
+		printk(KERN_DEBUG "%s: sca_set_carrier on\n",
+		       port->netdev.name);
+#endif
+		netif_carrier_on(port->netdev);
+	} else {
+#ifdef DEBUG_LINK
+		printk(KERN_DEBUG "%s: sca_set_carrier off\n",
+		       port->netdev.name);
+#endif
+		netif_carrier_off(port->netdev);
+	}
+}
+
+
+static void sca_init_port(port_t *port)
+{
+	card_t *card = port->card;
+	u16 dmac_rx = get_dmac_rx(port), dmac_tx = get_dmac_tx(port);
+	int transmit, i;
+
+	port->rxin = 0;
+	port->txin = 0;
+	port->txlast = 0;
+
+	for (transmit = 0; transmit < 2; transmit++) {
+		u16 buffs = transmit ? card->tx_ring_buffers
+			: card->rx_ring_buffers;
+
+		for (i = 0; i < buffs; i++) {
+			pkt_desc __iomem *desc = desc_address(port, i, transmit);
+			u16 chain_off = desc_offset(port, i + 1, transmit);
+			u32 buff_off = buffer_offset(port, i, transmit);
+
+			writel(chain_off, &desc->cp);
+			writel(buff_off, &desc->bp);
+			writew(0, &desc->len);
+			writeb(0, &desc->stat);
+		}
+	}
+
+	/* DMA disable - to halt state */
+	sca_out(0, DSR_RX(port->chan), card);
+	sca_out(0, DSR_TX(port->chan), card);
+
+	/* software ABORT - to initial state */
+	sca_out(DCR_ABORT, DCR_RX(port->chan), card);
+	sca_out(DCR_ABORT, DCR_TX(port->chan), card);
+
+	/* current desc addr */
+	sca_outl(desc_offset(port, 0, 0), dmac_rx + CDAL, card);
+	sca_outl(desc_offset(port, card->tx_ring_buffers - 1, 0),
+		 dmac_rx + EDAL, card);
+	sca_outl(desc_offset(port, 0, 1), dmac_tx + CDAL, card);
+	sca_outl(desc_offset(port, 0, 1), dmac_tx + EDAL, card);
+
+	/* clear frame end interrupt counter */
+	sca_out(DCR_CLEAR_EOF, DCR_RX(port->chan), card);
+	sca_out(DCR_CLEAR_EOF, DCR_TX(port->chan), card);
+
+	/* Receive */
+	sca_outw(HDLC_MAX_MRU, dmac_rx + BFLL, card); /* set buffer length */
+	sca_out(0x14, DMR_RX(port->chan), card); /* Chain mode, Multi-frame */
+	sca_out(DIR_EOME, DIR_RX(port->chan), card); /* enable interrupts */
+	sca_out(DSR_DE, DSR_RX(port->chan), card); /* DMA enable */
+
+	/* Transmit */
+	sca_out(0x14, DMR_TX(port->chan), card); /* Chain mode, Multi-frame */
+	sca_out(DIR_EOME, DIR_TX(port->chan), card); /* enable interrupts */
+
+	sca_set_carrier(port);
+	netif_napi_add(port->netdev, &port->napi, sca_poll, NAPI_WEIGHT);
+}
+
+
+/* MSCI interrupt service */
+static inline void sca_msci_intr(port_t *port)
+{
+	u16 msci = get_msci(port);
+	card_t* card = port->card;
+
+	if (sca_in(msci + ST1, card) & ST1_CDCD) {
+		/* Reset MSCI CDCD status bit */
+		sca_out(ST1_CDCD, msci + ST1, card);
+		sca_set_carrier(port);
+	}
+}
+
+
+static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc,
+			  u16 rxin)
+{
+	struct net_device *dev = port->netdev;
+	struct sk_buff *skb;
+	u16 len;
+	u32 buff;
+
+	len = readw(&desc->len);
+	skb = dev_alloc_skb(len);
+	if (!skb) {
+		dev->stats.rx_dropped++;
+		return;
+	}
+
+	buff = buffer_offset(port, rxin, 0);
+	memcpy_fromio(skb->data, card->rambase + buff, len);
+
+	skb_put(skb, len);
+#ifdef DEBUG_PKT
+	printk(KERN_DEBUG "%s RX(%i):", dev->name, skb->len);
+	debug_frame(skb);
+#endif
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += skb->len;
+	skb->protocol = hdlc_type_trans(skb, dev);
+	netif_receive_skb(skb);
+}
+
+
+/* Receive DMA service */
+static inline int sca_rx_done(port_t *port, int budget)
+{
+	struct net_device *dev = port->netdev;
+	u16 dmac = get_dmac_rx(port);
+	card_t *card = port->card;
+	u8 stat = sca_in(DSR_RX(port->chan), card); /* read DMA Status */
+	int received = 0;
+
+	/* Reset DSR status bits */
+	sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE,
+		DSR_RX(port->chan), card);
+
+	if (stat & DSR_BOF)
+		/* Dropped one or more frames */
+		dev->stats.rx_over_errors++;
+
+	while (received < budget) {
+		u32 desc_off = desc_offset(port, port->rxin, 0);
+		pkt_desc __iomem *desc;
+		u32 cda = sca_inl(dmac + CDAL, card);
+
+		if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
+			break;	/* No frame received */
+
+		desc = desc_address(port, port->rxin, 0);
+		stat = readb(&desc->stat);
+		if (!(stat & ST_RX_EOM))
+			port->rxpart = 1; /* partial frame received */
+		else if ((stat & ST_ERROR_MASK) || port->rxpart) {
+			dev->stats.rx_errors++;
+			if (stat & ST_RX_OVERRUN)
+				dev->stats.rx_fifo_errors++;
+			else if ((stat & (ST_RX_SHORT | ST_RX_ABORT |
+					  ST_RX_RESBIT)) || port->rxpart)
+				dev->stats.rx_frame_errors++;
+			else if (stat & ST_RX_CRC)
+				dev->stats.rx_crc_errors++;
+			if (stat & ST_RX_EOM)
+				port->rxpart = 0; /* received last fragment */
+		} else {
+			sca_rx(card, port, desc, port->rxin);
+			received++;
+		}
+
+		/* Set new error descriptor address */
+		sca_outl(desc_off, dmac + EDAL, card);
+		port->rxin = (port->rxin + 1) % card->rx_ring_buffers;
+	}
+
+	/* make sure RX DMA is enabled */
+	sca_out(DSR_DE, DSR_RX(port->chan), card);
+	return received;
+}
+
+
+/* Transmit DMA service */
+static inline void sca_tx_done(port_t *port)
+{
+	struct net_device *dev = port->netdev;
+	card_t* card = port->card;
+	u8 stat;
+
+	spin_lock(&port->lock);
+
+	stat = sca_in(DSR_TX(port->chan), card); /* read DMA Status */
+
+	/* Reset DSR status bits */
+	sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE,
+		DSR_TX(port->chan), card);
+
+	while (1) {
+		pkt_desc __iomem *desc = desc_address(port, port->txlast, 1);
+		u8 stat = readb(&desc->stat);
+
+		if (!(stat & ST_TX_OWNRSHP))
+			break; /* not yet transmitted */
+		if (stat & ST_TX_UNDRRUN) {
+			dev->stats.tx_errors++;
+			dev->stats.tx_fifo_errors++;
+		} else {
+			dev->stats.tx_packets++;
+			dev->stats.tx_bytes += readw(&desc->len);
+		}
+		writeb(0, &desc->stat);	/* Free descriptor */
+		port->txlast = (port->txlast + 1) % card->tx_ring_buffers;
+	}
+
+	netif_wake_queue(dev);
+	spin_unlock(&port->lock);
+}
+
+
+static int sca_poll(struct napi_struct *napi, int budget)
+{
+	port_t *port = container_of(napi, port_t, napi);
+	u32 isr0 = sca_inl(ISR0, port->card);
+	int received = 0;
+
+	if (isr0 & (port->chan ? 0x08000000 : 0x00080000))
+		sca_msci_intr(port);
+
+	if (isr0 & (port->chan ? 0x00002000 : 0x00000020))
+		sca_tx_done(port);
+
+	if (isr0 & (port->chan ? 0x00000200 : 0x00000002))
+		received = sca_rx_done(port, budget);
+
+	if (received < budget) {
+		netif_rx_complete(napi);
+		enable_intr(port);
+	}
+
+	return received;
+}
+
+static irqreturn_t sca_intr(int irq, void *dev_id)
+{
+	card_t *card = dev_id;
+	u32 isr0 = sca_inl(ISR0, card);
+	int i, handled = 0;
+
+	for (i = 0; i < 2; i++) {
+		port_t *port = get_port(card, i);
+		if (port && (isr0 & (i ? 0x08002200 : 0x00080022))) {
+			handled = 1;
+			disable_intr(port);
+			netif_rx_schedule(&port->napi);
+		}
+	}
+
+	return IRQ_RETVAL(handled);
+}
+
+
+static void sca_set_port(port_t *port)
+{
+	card_t* card = port->card;
+	u16 msci = get_msci(port);
+	u8 md2 = sca_in(msci + MD2, card);
+	unsigned int tmc, br = 10, brv = 1024;
+
+
+	if (port->settings.clock_rate > 0) {
+		/* Try lower br for better accuracy*/
+		do {
+			br--;
+			brv >>= 1; /* brv = 2^9 = 512 max in specs */
+
+			/* Baud Rate = CLOCK_BASE / TMC / 2^BR */
+			tmc = CLOCK_BASE / brv / port->settings.clock_rate;
+		}while (br > 1 && tmc <= 128);
+
+		if (tmc < 1) {
+			tmc = 1;
+			br = 0;	/* For baud=CLOCK_BASE we use tmc=1 br=0 */
+			brv = 1;
+		} else if (tmc > 255)
+			tmc = 256; /* tmc=0 means 256 - low baud rates */
+
+		port->settings.clock_rate = CLOCK_BASE / brv / tmc;
+	} else {
+		br = 9; /* Minimum clock rate */
+		tmc = 256;	/* 8bit = 0 */
+		port->settings.clock_rate = CLOCK_BASE / (256 * 512);
+	}
+
+	port->rxs = (port->rxs & ~CLK_BRG_MASK) | br;
+	port->txs = (port->txs & ~CLK_BRG_MASK) | br;
+	port->tmc = tmc;
+
+	/* baud divisor - time constant*/
+	sca_out(port->tmc, msci + TMCR, card);
+	sca_out(port->tmc, msci + TMCT, card);
+
+	/* Set BRG bits */
+	sca_out(port->rxs, msci + RXS, card);
+	sca_out(port->txs, msci + TXS, card);
+
+	if (port->settings.loopback)
+		md2 |= MD2_LOOPBACK;
+	else
+		md2 &= ~MD2_LOOPBACK;
+
+	sca_out(md2, msci + MD2, card);
+
+}
+
+
+static void sca_open(struct net_device *dev)
+{
+	port_t *port = dev_to_port(dev);
+	card_t* card = port->card;
+	u16 msci = get_msci(port);
+	u8 md0, md2;
+
+	switch(port->encoding) {
+	case ENCODING_NRZ:	md2 = MD2_NRZ;		break;
+	case ENCODING_NRZI:	md2 = MD2_NRZI;		break;
+	case ENCODING_FM_MARK:	md2 = MD2_FM_MARK;	break;
+	case ENCODING_FM_SPACE:	md2 = MD2_FM_SPACE;	break;
+	default:		md2 = MD2_MANCHESTER;
+	}
+
+	if (port->settings.loopback)
+		md2 |= MD2_LOOPBACK;
+
+	switch(port->parity) {
+	case PARITY_CRC16_PR0:	     md0 = MD0_HDLC | MD0_CRC_16_0;  break;
+	case PARITY_CRC16_PR1:	     md0 = MD0_HDLC | MD0_CRC_16;    break;
+	case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break;
+	case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU;   break;
+	default:		     md0 = MD0_HDLC | MD0_CRC_NONE;
+	}
+
+	sca_out(CMD_RESET, msci + CMD, card);
+	sca_out(md0, msci + MD0, card);
+	sca_out(0x00, msci + MD1, card); /* no address field check */
+	sca_out(md2, msci + MD2, card);
+	sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */
+	/* Skip the rest of underrun frame */
+	sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card);
+	sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */
+	sca_out(0x3C, msci + TFS, card); /* +1 = TX start */
+	sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */
+	sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */
+	sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/
+
+/* We're using the following interrupts:
+   - RXINTA (DCD changes only)
+   - DMIB (EOM - single frame transfer complete)
+*/
+	sca_outl(IE0_RXINTA | IE0_CDCD, msci + IE0, card);
+
+	sca_out(port->tmc, msci + TMCR, card);
+	sca_out(port->tmc, msci + TMCT, card);
+	sca_out(port->rxs, msci + RXS, card);
+	sca_out(port->txs, msci + TXS, card);
+	sca_out(CMD_TX_ENABLE, msci + CMD, card);
+	sca_out(CMD_RX_ENABLE, msci + CMD, card);
+
+	sca_set_carrier(port);
+	enable_intr(port);
+	napi_enable(&port->napi);
+	netif_start_queue(dev);
+}
+
+
+static void sca_close(struct net_device *dev)
+{
+	port_t *port = dev_to_port(dev);
+
+	/* reset channel */
+	sca_out(CMD_RESET, get_msci(port) + CMD, port->card);
+	disable_intr(port);
+	napi_disable(&port->napi);
+	netif_stop_queue(dev);
+}
+
+
+static int sca_attach(struct net_device *dev, unsigned short encoding,
+		      unsigned short parity)
+{
+	if (encoding != ENCODING_NRZ &&
+	    encoding != ENCODING_NRZI &&
+	    encoding != ENCODING_FM_MARK &&
+	    encoding != ENCODING_FM_SPACE &&
+	    encoding != ENCODING_MANCHESTER)
+		return -EINVAL;
+
+	if (parity != PARITY_NONE &&
+	    parity != PARITY_CRC16_PR0 &&
+	    parity != PARITY_CRC16_PR1 &&
+	    parity != PARITY_CRC32_PR1_CCITT &&
+	    parity != PARITY_CRC16_PR1_CCITT)
+		return -EINVAL;
+
+	dev_to_port(dev)->encoding = encoding;
+	dev_to_port(dev)->parity = parity;
+	return 0;
+}
+
+
+#ifdef DEBUG_RINGS
+static void sca_dump_rings(struct net_device *dev)
+{
+	port_t *port = dev_to_port(dev);
+	card_t *card = port->card;
+	u16 cnt;
+
+	printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive",
+	       sca_inl(get_dmac_rx(port) + CDAL, card),
+	       sca_inl(get_dmac_rx(port) + EDAL, card),
+	       sca_in(DSR_RX(port->chan), card), port->rxin,
+	       sca_in(DSR_RX(port->chan), card) & DSR_DE ? "" : "in");
+	for (cnt = 0; cnt < port->card->rx_ring_buffers; cnt++)
+		printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat)));
+
+	printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
+	       "last=%u %sactive",
+	       sca_inl(get_dmac_tx(port) + CDAL, card),
+	       sca_inl(get_dmac_tx(port) + EDAL, card),
+	       sca_in(DSR_TX(port->chan), card), port->txin, port->txlast,
+	       sca_in(DSR_TX(port->chan), card) & DSR_DE ? "" : "in");
+
+	for (cnt = 0; cnt < port->card->tx_ring_buffers; cnt++)
+		printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat)));
+	printk("\n");
+
+	printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x,"
+	       " ST: %02x %02x %02x %02x %02x, FST: %02x CST: %02x %02x\n",
+	       sca_in(get_msci(port) + MD0, card),
+	       sca_in(get_msci(port) + MD1, card),
+	       sca_in(get_msci(port) + MD2, card),
+	       sca_in(get_msci(port) + ST0, card),
+	       sca_in(get_msci(port) + ST1, card),
+	       sca_in(get_msci(port) + ST2, card),
+	       sca_in(get_msci(port) + ST3, card),
+	       sca_in(get_msci(port) + ST4, card),
+	       sca_in(get_msci(port) + FST, card),
+	       sca_in(get_msci(port) + CST0, card),
+	       sca_in(get_msci(port) + CST1, card));
+
+	printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card),
+	       sca_inl(ISR0, card), sca_inl(ISR1, card));
+}
+#endif /* DEBUG_RINGS */
+
+
+static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	port_t *port = dev_to_port(dev);
+	card_t *card = port->card;
+	pkt_desc __iomem *desc;
+	u32 buff, len;
+
+	spin_lock_irq(&port->lock);
+
+	desc = desc_address(port, port->txin + 1, 1);
+	BUG_ON(readb(&desc->stat)); /* previous xmit should stop queue */
+
+#ifdef DEBUG_PKT
+	printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len);
+	debug_frame(skb);
+#endif
+
+	desc = desc_address(port, port->txin, 1);
+	buff = buffer_offset(port, port->txin, 1);
+	len = skb->len;
+	memcpy_toio(card->rambase + buff, skb->data, len);
+
+	writew(len, &desc->len);
+	writeb(ST_TX_EOM, &desc->stat);
+	dev->trans_start = jiffies;
+
+	port->txin = (port->txin + 1) % card->tx_ring_buffers;
+	sca_outl(desc_offset(port, port->txin, 1),
+		 get_dmac_tx(port) + EDAL, card);
+
+	sca_out(DSR_DE, DSR_TX(port->chan), card); /* Enable TX DMA */
+
+	desc = desc_address(port, port->txin + 1, 1);
+	if (readb(&desc->stat)) /* allow 1 packet gap */
+		netif_stop_queue(dev);
+
+	spin_unlock_irq(&port->lock);
+
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+
+static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase,
+				    u32 ramsize)
+{
+	/* Round RAM size to 32 bits, fill from end to start */
+	u32 i = ramsize &= ~3;
+
+	do {
+		i -= 4;
+		writel(i ^ 0x12345678, rambase + i);
+	} while (i > 0);
+
+	for (i = 0; i < ramsize ; i += 4) {
+		if (readl(rambase + i) != (i ^ 0x12345678))
+			break;
+	}
+
+	return i;
+}
+
+
+static void __devinit sca_init(card_t *card, int wait_states)
+{
+	sca_out(wait_states, WCRL, card); /* Wait Control */
+	sca_out(wait_states, WCRM, card);
+	sca_out(wait_states, WCRH, card);
+
+	sca_out(0, DMER, card);	/* DMA Master disable */
+	sca_out(0x03, PCR, card); /* DMA priority */
+	sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */
+	sca_out(0, DSR_TX(0), card);
+	sca_out(0, DSR_RX(1), card);
+	sca_out(0, DSR_TX(1), card);
+	sca_out(DMER_DME, DMER, card); /* DMA Master enable */
+}
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index d3d5055..f1ddd7c 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -342,7 +342,7 @@
 
 static int pvc_open(struct net_device *dev)
 {
-	pvc_device *pvc = dev->priv;
+	pvc_device *pvc = dev->ml_priv;
 
 	if ((pvc->frad->flags & IFF_UP) == 0)
 		return -EIO;  /* Frad must be UP in order to activate PVC */
@@ -362,7 +362,7 @@
 
 static int pvc_close(struct net_device *dev)
 {
-	pvc_device *pvc = dev->priv;
+	pvc_device *pvc = dev->ml_priv;
 
 	if (--pvc->open_count == 0) {
 		hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
@@ -381,7 +381,7 @@
 
 static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	pvc_device *pvc = dev->priv;
+	pvc_device *pvc = dev->ml_priv;
 	fr_proto_pvc_info info;
 
 	if (ifr->ifr_settings.type == IF_GET_PROTO) {
@@ -409,7 +409,7 @@
 
 static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	pvc_device *pvc = dev->priv;
+	pvc_device *pvc = dev->ml_priv;
 
 	if (pvc->state.active) {
 		if (dev->type == ARPHRD_ETHER) {
@@ -1111,7 +1111,7 @@
 	dev->change_mtu = pvc_change_mtu;
 	dev->mtu = HDLC_MAX_MTU;
 	dev->tx_queue_len = 0;
-	dev->priv = pvc;
+	dev->ml_priv = pvc;
 
 	result = dev_alloc_name(dev, dev->name);
 	if (result < 0) {
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index 4efe9e6..57fe714 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -2,7 +2,7 @@
  * Generic HDLC support routines for Linux
  * Point-to-point protocol support
  *
- * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2008 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -18,87 +18,633 @@
 #include <linux/module.h>
 #include <linux/pkt_sched.h>
 #include <linux/poll.h>
-#include <linux/rtnetlink.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
-#include <net/syncppp.h>
+#include <linux/spinlock.h>
 
-struct ppp_state {
-	struct ppp_device pppdev;
-	struct ppp_device *syncppp_ptr;
-	int (*old_change_mtu)(struct net_device *dev, int new_mtu);
+#define DEBUG_CP		0 /* also bytes# to dump */
+#define DEBUG_STATE		0
+#define DEBUG_HARD_HEADER	0
+
+#define HDLC_ADDR_ALLSTATIONS	0xFF
+#define HDLC_CTRL_UI		0x03
+
+#define PID_LCP			0xC021
+#define PID_IP			0x0021
+#define PID_IPCP		0x8021
+#define PID_IPV6		0x0057
+#define PID_IPV6CP		0x8057
+
+enum {IDX_LCP = 0, IDX_IPCP, IDX_IPV6CP, IDX_COUNT};
+enum {CP_CONF_REQ = 1, CP_CONF_ACK, CP_CONF_NAK, CP_CONF_REJ, CP_TERM_REQ,
+      CP_TERM_ACK, CP_CODE_REJ, LCP_PROTO_REJ, LCP_ECHO_REQ, LCP_ECHO_REPLY,
+      LCP_DISC_REQ, CP_CODES};
+#if DEBUG_CP
+static const char *const code_names[CP_CODES] = {
+	"0", "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq",
+	"TermAck", "CodeRej", "ProtoRej", "EchoReq", "EchoReply", "Discard"
 };
+static char debug_buffer[64 + 3 * DEBUG_CP];
+#endif
+
+enum {LCP_OPTION_MRU = 1, LCP_OPTION_ACCM, LCP_OPTION_MAGIC = 5};
+
+struct hdlc_header {
+	u8 address;
+	u8 control;
+	__be16 protocol;
+};
+
+struct cp_header {
+	u8 code;
+	u8 id;
+	__be16 len;
+};
+
+
+struct proto {
+	struct net_device *dev;
+	struct timer_list timer;
+	unsigned long timeout;
+	u16 pid;		/* protocol ID */
+	u8 state;
+	u8 cr_id;		/* ID of last Configuration-Request */
+	u8 restart_counter;
+};
+
+struct ppp {
+	struct proto protos[IDX_COUNT];
+	spinlock_t lock;
+	unsigned long last_pong;
+	unsigned int req_timeout, cr_retries, term_retries;
+	unsigned int keepalive_interval, keepalive_timeout;
+	u8 seq;			/* local sequence number for requests */
+	u8 echo_id;		/* ID of last Echo-Request (LCP) */
+};
+
+enum {CLOSED = 0, STOPPED, STOPPING, REQ_SENT, ACK_RECV, ACK_SENT, OPENED,
+      STATES, STATE_MASK = 0xF};
+enum {START = 0, STOP, TO_GOOD, TO_BAD, RCR_GOOD, RCR_BAD, RCA, RCN, RTR, RTA,
+      RUC, RXJ_GOOD, RXJ_BAD, EVENTS};
+enum {INV = 0x10, IRC = 0x20, ZRC = 0x40, SCR = 0x80, SCA = 0x100,
+      SCN = 0x200, STR = 0x400, STA = 0x800, SCJ = 0x1000};
+
+#if DEBUG_STATE
+static const char *const state_names[STATES] = {
+	"Closed", "Stopped", "Stopping", "ReqSent", "AckRecv", "AckSent",
+	"Opened"
+};
+static const char *const event_names[EVENTS] = {
+	"Start", "Stop", "TO+", "TO-", "RCR+", "RCR-", "RCA", "RCN",
+	"RTR", "RTA", "RUC", "RXJ+", "RXJ-"
+};
+#endif
+
+static struct sk_buff_head tx_queue; /* used when holding the spin lock */
 
 static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
 
-
-static inline struct ppp_state* state(hdlc_device *hdlc)
+static inline struct ppp* get_ppp(struct net_device *dev)
 {
-	return(struct ppp_state *)(hdlc->state);
+	return (struct ppp *)dev_to_hdlc(dev)->state;
 }
 
-
-static int ppp_open(struct net_device *dev)
+static inline struct proto* get_proto(struct net_device *dev, u16 pid)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	int (*old_ioctl)(struct net_device *, struct ifreq *, int);
-	int result;
+	struct ppp *ppp = get_ppp(dev);
 
-	dev->ml_priv = &state(hdlc)->syncppp_ptr;
-	state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev;
-	state(hdlc)->pppdev.dev = dev;
-
-	old_ioctl = dev->do_ioctl;
-	state(hdlc)->old_change_mtu = dev->change_mtu;
-	sppp_attach(&state(hdlc)->pppdev);
-	/* sppp_attach nukes them. We don't need syncppp's ioctl */
-	dev->do_ioctl = old_ioctl;
-	state(hdlc)->pppdev.sppp.pp_flags &= ~PP_CISCO;
-	dev->type = ARPHRD_PPP;
-	result = sppp_open(dev);
-	if (result) {
-		sppp_detach(dev);
-		return result;
+	switch (pid) {
+	case PID_LCP:
+		return &ppp->protos[IDX_LCP];
+	case PID_IPCP:
+		return &ppp->protos[IDX_IPCP];
+	case PID_IPV6CP:
+		return &ppp->protos[IDX_IPV6CP];
+	default:
+		return NULL;
 	}
-
-	return 0;
 }
 
-
-
-static void ppp_close(struct net_device *dev)
+static inline const char* proto_name(u16 pid)
 {
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-
-	sppp_close(dev);
-	sppp_detach(dev);
-
-	dev->change_mtu = state(hdlc)->old_change_mtu;
-	dev->mtu = HDLC_MAX_MTU;
-	dev->hard_header_len = 16;
+	switch (pid) {
+	case PID_LCP:
+		return "LCP";
+	case PID_IPCP:
+		return "IPCP";
+	case PID_IPV6CP:
+		return "IPV6CP";
+	default:
+		return NULL;
+	}
 }
 
-
-
 static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
-	return __constant_htons(ETH_P_WAN_PPP);
+	struct hdlc_header *data = (struct hdlc_header*)skb->data;
+
+	if (skb->len < sizeof(struct hdlc_header))
+		return htons(ETH_P_HDLC);
+	if (data->address != HDLC_ADDR_ALLSTATIONS ||
+	    data->control != HDLC_CTRL_UI)
+		return htons(ETH_P_HDLC);
+
+	switch (data->protocol) {
+	case __constant_htons(PID_IP):
+		skb_pull(skb, sizeof(struct hdlc_header));
+		return htons(ETH_P_IP);
+
+	case __constant_htons(PID_IPV6):
+		skb_pull(skb, sizeof(struct hdlc_header));
+		return htons(ETH_P_IPV6);
+
+	default:
+		return htons(ETH_P_HDLC);
+	}
 }
 
 
+static int ppp_hard_header(struct sk_buff *skb, struct net_device *dev,
+			   u16 type, const void *daddr, const void *saddr,
+			   unsigned int len)
+{
+	struct hdlc_header *data;
+#if DEBUG_HARD_HEADER
+	printk(KERN_DEBUG "%s: ppp_hard_header() called\n", dev->name);
+#endif
+
+	skb_push(skb, sizeof(struct hdlc_header));
+	data = (struct hdlc_header*)skb->data;
+
+	data->address = HDLC_ADDR_ALLSTATIONS;
+	data->control = HDLC_CTRL_UI;
+	switch (type) {
+	case ETH_P_IP:
+		data->protocol = htons(PID_IP);
+		break;
+	case ETH_P_IPV6:
+		data->protocol = htons(PID_IPV6);
+		break;
+	case PID_LCP:
+	case PID_IPCP:
+	case PID_IPV6CP:
+		data->protocol = htons(type);
+		break;
+	default:		/* unknown protocol */
+		data->protocol = 0;
+	}
+	return sizeof(struct hdlc_header);
+}
+
+
+static void ppp_tx_flush(void)
+{
+	struct sk_buff *skb;
+	while ((skb = skb_dequeue(&tx_queue)) != NULL)
+		dev_queue_xmit(skb);
+}
+
+static void ppp_tx_cp(struct net_device *dev, u16 pid, u8 code,
+		      u8 id, unsigned int len, const void *data)
+{
+	struct sk_buff *skb;
+	struct cp_header *cp;
+	unsigned int magic_len = 0;
+	static u32 magic;
+
+#if DEBUG_CP
+	int i;
+	char *ptr;
+#endif
+
+	if (pid == PID_LCP && (code == LCP_ECHO_REQ || code == LCP_ECHO_REPLY))
+		magic_len = sizeof(magic);
+
+	skb = dev_alloc_skb(sizeof(struct hdlc_header) +
+			    sizeof(struct cp_header) + magic_len + len);
+	if (!skb) {
+		printk(KERN_WARNING "%s: out of memory in ppp_tx_cp()\n",
+		       dev->name);
+		return;
+	}
+	skb_reserve(skb, sizeof(struct hdlc_header));
+
+	cp = (struct cp_header *)skb_put(skb, sizeof(struct cp_header));
+	cp->code = code;
+	cp->id = id;
+	cp->len = htons(sizeof(struct cp_header) + magic_len + len);
+
+	if (magic_len)
+		memcpy(skb_put(skb, magic_len), &magic, magic_len);
+	if (len)
+		memcpy(skb_put(skb, len), data, len);
+
+#if DEBUG_CP
+	BUG_ON(code >= CP_CODES);
+	ptr = debug_buffer;
+	*ptr = '\x0';
+	for (i = 0; i < min_t(unsigned int, magic_len + len, DEBUG_CP); i++) {
+		sprintf(ptr, " %02X", skb->data[sizeof(struct cp_header) + i]);
+		ptr += strlen(ptr);
+	}
+	printk(KERN_DEBUG "%s: TX %s [%s id 0x%X]%s\n", dev->name,
+	       proto_name(pid), code_names[code], id, debug_buffer);
+#endif
+
+	ppp_hard_header(skb, dev, pid, NULL, NULL, 0);
+
+	skb->priority = TC_PRIO_CONTROL;
+	skb->dev = dev;
+	skb_reset_network_header(skb);
+	skb_queue_tail(&tx_queue, skb);
+}
+
+
+/* State transition table (compare STD-51)
+   Events                                   Actions
+   TO+  = Timeout with counter > 0          irc = Initialize-Restart-Count
+   TO-  = Timeout with counter expired      zrc = Zero-Restart-Count
+
+   RCR+ = Receive-Configure-Request (Good)  scr = Send-Configure-Request
+   RCR- = Receive-Configure-Request (Bad)
+   RCA  = Receive-Configure-Ack             sca = Send-Configure-Ack
+   RCN  = Receive-Configure-Nak/Rej         scn = Send-Configure-Nak/Rej
+
+   RTR  = Receive-Terminate-Request         str = Send-Terminate-Request
+   RTA  = Receive-Terminate-Ack             sta = Send-Terminate-Ack
+
+   RUC  = Receive-Unknown-Code              scj = Send-Code-Reject
+   RXJ+ = Receive-Code-Reject (permitted)
+       or Receive-Protocol-Reject
+   RXJ- = Receive-Code-Reject (catastrophic)
+       or Receive-Protocol-Reject
+*/
+static int cp_table[EVENTS][STATES] = {
+	/* CLOSED     STOPPED STOPPING REQ_SENT ACK_RECV ACK_SENT OPENED
+	     0           1         2       3       4      5          6    */
+	{IRC|SCR|3,     INV     , INV ,   INV   , INV ,  INV    ,   INV   }, /* START */
+	{   INV   ,      0      ,  0  ,    0    ,  0  ,   0     ,    0    }, /* STOP */
+	{   INV   ,     INV     ,STR|2,  SCR|3  ,SCR|3,  SCR|5  ,   INV   }, /* TO+ */
+	{   INV   ,     INV     ,  1  ,    1    ,  1  ,    1    ,   INV   }, /* TO- */
+	{  STA|0  ,IRC|SCR|SCA|5,  2  ,  SCA|5  ,SCA|6,  SCA|5  ,SCR|SCA|5}, /* RCR+ */
+	{  STA|0  ,IRC|SCR|SCN|3,  2  ,  SCN|3  ,SCN|4,  SCN|3  ,SCR|SCN|3}, /* RCR- */
+	{  STA|0  ,    STA|1    ,  2  ,  IRC|4  ,SCR|3,    6    , SCR|3   }, /* RCA */
+	{  STA|0  ,    STA|1    ,  2  ,IRC|SCR|3,SCR|3,IRC|SCR|5, SCR|3   }, /* RCN */
+	{  STA|0  ,    STA|1    ,STA|2,  STA|3  ,STA|3,  STA|3  ,ZRC|STA|2}, /* RTR */
+	{    0    ,      1      ,  1  ,    3    ,  3  ,    5    ,  SCR|3  }, /* RTA */
+	{  SCJ|0  ,    SCJ|1    ,SCJ|2,  SCJ|3  ,SCJ|4,  SCJ|5  ,  SCJ|6  }, /* RUC */
+	{    0    ,      1      ,  2  ,    3    ,  3  ,    5    ,    6    }, /* RXJ+ */
+	{    0    ,      1      ,  1  ,    1    ,  1  ,    1    ,IRC|STR|2}, /* RXJ- */
+};
+
+
+/* SCA: RCR+ must supply id, len and data
+   SCN: RCR- must supply code, id, len and data
+   STA: RTR must supply id
+   SCJ: RUC must supply CP packet len and data */
+static void ppp_cp_event(struct net_device *dev, u16 pid, u16 event, u8 code,
+			 u8 id, unsigned int len, const void *data)
+{
+	int old_state, action;
+	struct ppp *ppp = get_ppp(dev);
+	struct proto *proto = get_proto(dev, pid);
+
+	old_state = proto->state;
+	BUG_ON(old_state >= STATES);
+	BUG_ON(event >= EVENTS);
+
+#if DEBUG_STATE
+	printk(KERN_DEBUG "%s: %s ppp_cp_event(%s) %s ...\n", dev->name,
+	       proto_name(pid), event_names[event], state_names[proto->state]);
+#endif
+
+	action = cp_table[event][old_state];
+
+	proto->state = action & STATE_MASK;
+	if (action & (SCR | STR)) /* set Configure-Req/Terminate-Req timer */
+		mod_timer(&proto->timer, proto->timeout =
+			  jiffies + ppp->req_timeout * HZ);
+	if (action & ZRC)
+		proto->restart_counter = 0;
+	if (action & IRC)
+		proto->restart_counter = (proto->state == STOPPING) ?
+			ppp->term_retries : ppp->cr_retries;
+
+	if (action & SCR)	/* send Configure-Request */
+		ppp_tx_cp(dev, pid, CP_CONF_REQ, proto->cr_id = ++ppp->seq,
+			  0, NULL);
+	if (action & SCA)	/* send Configure-Ack */
+		ppp_tx_cp(dev, pid, CP_CONF_ACK, id, len, data);
+	if (action & SCN)	/* send Configure-Nak/Reject */
+		ppp_tx_cp(dev, pid, code, id, len, data);
+	if (action & STR)	/* send Terminate-Request */
+		ppp_tx_cp(dev, pid, CP_TERM_REQ, ++ppp->seq, 0, NULL);
+	if (action & STA)	/* send Terminate-Ack */
+		ppp_tx_cp(dev, pid, CP_TERM_ACK, id, 0, NULL);
+	if (action & SCJ)	/* send Code-Reject */
+		ppp_tx_cp(dev, pid, CP_CODE_REJ, ++ppp->seq, len, data);
+
+	if (old_state != OPENED && proto->state == OPENED) {
+		printk(KERN_INFO "%s: %s up\n", dev->name, proto_name(pid));
+		if (pid == PID_LCP) {
+			netif_dormant_off(dev);
+			ppp_cp_event(dev, PID_IPCP, START, 0, 0, 0, NULL);
+			ppp_cp_event(dev, PID_IPV6CP, START, 0, 0, 0, NULL);
+			ppp->last_pong = jiffies;
+			mod_timer(&proto->timer, proto->timeout =
+				  jiffies + ppp->keepalive_interval * HZ);
+		}
+	}
+	if (old_state == OPENED && proto->state != OPENED) {
+		printk(KERN_INFO "%s: %s down\n", dev->name, proto_name(pid));
+		if (pid == PID_LCP) {
+			netif_dormant_on(dev);
+			ppp_cp_event(dev, PID_IPCP, STOP, 0, 0, 0, NULL);
+			ppp_cp_event(dev, PID_IPV6CP, STOP, 0, 0, 0, NULL);
+		}
+	}
+	if (old_state != CLOSED && proto->state == CLOSED)
+		del_timer(&proto->timer);
+
+#if DEBUG_STATE
+	printk(KERN_DEBUG "%s: %s ppp_cp_event(%s) ... %s\n", dev->name,
+	       proto_name(pid), event_names[event], state_names[proto->state]);
+#endif
+}
+
+
+static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id,
+			    unsigned int req_len, const u8 *data)
+{
+	static u8 const valid_accm[6] = { LCP_OPTION_ACCM, 6, 0, 0, 0, 0 };
+	const u8 *opt;
+	u8 *out;
+	unsigned int len = req_len, nak_len = 0, rej_len = 0;
+
+	if (!(out = kmalloc(len, GFP_ATOMIC))) {
+		dev->stats.rx_dropped++;
+		return;	/* out of memory, ignore CR packet */
+	}
+
+	for (opt = data; len; len -= opt[1], opt += opt[1]) {
+		if (len < 2 || len < opt[1]) {
+			dev->stats.rx_errors++;
+			return; /* bad packet, drop silently */
+		}
+
+		if (pid == PID_LCP)
+			switch (opt[0]) {
+			case LCP_OPTION_MRU:
+				continue; /* MRU always OK and > 1500 bytes? */
+
+			case LCP_OPTION_ACCM: /* async control character map */
+				if (!memcmp(opt, valid_accm,
+					    sizeof(valid_accm)))
+					continue;
+				if (!rej_len) { /* NAK it */
+					memcpy(out + nak_len, valid_accm,
+					       sizeof(valid_accm));
+					nak_len += sizeof(valid_accm);
+					continue;
+				}
+				break;
+			case LCP_OPTION_MAGIC:
+				if (opt[1] != 6 || (!opt[2] && !opt[3] &&
+						    !opt[4] && !opt[5]))
+					break; /* reject invalid magic number */
+				continue;
+			}
+		/* reject this option */
+		memcpy(out + rej_len, opt, opt[1]);
+		rej_len += opt[1];
+	}
+
+	if (rej_len)
+		ppp_cp_event(dev, pid, RCR_BAD, CP_CONF_REJ, id, rej_len, out);
+	else if (nak_len)
+		ppp_cp_event(dev, pid, RCR_BAD, CP_CONF_NAK, id, nak_len, out);
+	else
+		ppp_cp_event(dev, pid, RCR_GOOD, CP_CONF_ACK, id, req_len, data);
+
+	kfree(out);
+}
+
+static int ppp_rx(struct sk_buff *skb)
+{
+	struct hdlc_header *hdr = (struct hdlc_header*)skb->data;
+	struct net_device *dev = skb->dev;
+	struct ppp *ppp = get_ppp(dev);
+	struct proto *proto;
+	struct cp_header *cp;
+	unsigned long flags;
+	unsigned int len;
+	u16 pid;
+#if DEBUG_CP
+	int i;
+	char *ptr;
+#endif
+
+	spin_lock_irqsave(&ppp->lock, flags);
+	/* Check HDLC header */
+	if (skb->len < sizeof(struct hdlc_header))
+		goto rx_error;
+	cp = (struct cp_header*)skb_pull(skb, sizeof(struct hdlc_header));
+	if (hdr->address != HDLC_ADDR_ALLSTATIONS ||
+	    hdr->control != HDLC_CTRL_UI)
+		goto rx_error;
+
+	pid = ntohs(hdr->protocol);
+	proto = get_proto(dev, pid);
+	if (!proto) {
+		if (ppp->protos[IDX_LCP].state == OPENED)
+			ppp_tx_cp(dev, PID_LCP, LCP_PROTO_REJ,
+				  ++ppp->seq, skb->len + 2, &hdr->protocol);
+		goto rx_error;
+	}
+
+	len = ntohs(cp->len);
+	if (len < sizeof(struct cp_header) /* no complete CP header? */ ||
+	    skb->len < len /* truncated packet? */)
+		goto rx_error;
+	skb_pull(skb, sizeof(struct cp_header));
+	len -= sizeof(struct cp_header);
+
+	/* HDLC and CP headers stripped from skb */
+#if DEBUG_CP
+	if (cp->code < CP_CODES)
+		sprintf(debug_buffer, "[%s id 0x%X]", code_names[cp->code],
+			cp->id);
+	else
+		sprintf(debug_buffer, "[code %u id 0x%X]", cp->code, cp->id);
+	ptr = debug_buffer + strlen(debug_buffer);
+	for (i = 0; i < min_t(unsigned int, len, DEBUG_CP); i++) {
+		sprintf(ptr, " %02X", skb->data[i]);
+		ptr += strlen(ptr);
+	}
+	printk(KERN_DEBUG "%s: RX %s %s\n", dev->name, proto_name(pid),
+	       debug_buffer);
+#endif
+
+	/* LCP only */
+	if (pid == PID_LCP)
+		switch (cp->code) {
+		case LCP_PROTO_REJ:
+			pid = ntohs(*(__be16*)skb->data);
+			if (pid == PID_LCP || pid == PID_IPCP ||
+			    pid == PID_IPV6CP)
+				ppp_cp_event(dev, pid, RXJ_BAD, 0, 0,
+					     0, NULL);
+			goto out;
+
+		case LCP_ECHO_REQ: /* send Echo-Reply */
+			if (len >= 4 && proto->state == OPENED)
+				ppp_tx_cp(dev, PID_LCP, LCP_ECHO_REPLY,
+					  cp->id, len - 4, skb->data + 4);
+			goto out;
+
+		case LCP_ECHO_REPLY:
+			if (cp->id == ppp->echo_id)
+				ppp->last_pong = jiffies;
+			goto out;
+
+		case LCP_DISC_REQ: /* discard */
+			goto out;
+		}
+
+	/* LCP, IPCP and IPV6CP */
+	switch (cp->code) {
+	case CP_CONF_REQ:
+		ppp_cp_parse_cr(dev, pid, cp->id, len, skb->data);
+		goto out;
+
+	case CP_CONF_ACK:
+		if (cp->id == proto->cr_id)
+			ppp_cp_event(dev, pid, RCA, 0, 0, 0, NULL);
+		goto out;
+
+	case CP_CONF_REJ:
+	case CP_CONF_NAK:
+		if (cp->id == proto->cr_id)
+			ppp_cp_event(dev, pid, RCN, 0, 0, 0, NULL);
+		goto out;
+
+	case CP_TERM_REQ:
+		ppp_cp_event(dev, pid, RTR, 0, cp->id, 0, NULL);
+		goto out;
+
+	case CP_TERM_ACK:
+		ppp_cp_event(dev, pid, RTA, 0, 0, 0, NULL);
+		goto out;
+
+	case CP_CODE_REJ:
+		ppp_cp_event(dev, pid, RXJ_BAD, 0, 0, 0, NULL);
+		goto out;
+
+	default:
+		len += sizeof(struct cp_header);
+		if (len > dev->mtu)
+			len = dev->mtu;
+		ppp_cp_event(dev, pid, RUC, 0, 0, len, cp);
+		goto out;
+	}
+	goto out;
+
+rx_error:
+	dev->stats.rx_errors++;
+out:
+	spin_unlock_irqrestore(&ppp->lock, flags);
+	dev_kfree_skb_any(skb);
+	ppp_tx_flush();
+	return NET_RX_DROP;
+}
+
+
+static void ppp_timer(unsigned long arg)
+{
+	struct proto *proto = (struct proto *)arg;
+	struct ppp *ppp = get_ppp(proto->dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ppp->lock, flags);
+	switch (proto->state) {
+	case STOPPING:
+	case REQ_SENT:
+	case ACK_RECV:
+	case ACK_SENT:
+		if (proto->restart_counter) {
+			ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0,
+				     0, NULL);
+			proto->restart_counter--;
+		} else
+			ppp_cp_event(proto->dev, proto->pid, TO_BAD, 0, 0,
+				     0, NULL);
+		break;
+
+	case OPENED:
+		if (proto->pid != PID_LCP)
+			break;
+		if (time_after(jiffies, ppp->last_pong +
+			       ppp->keepalive_timeout * HZ)) {
+			printk(KERN_INFO "%s: Link down\n", proto->dev->name);
+			ppp_cp_event(proto->dev, PID_LCP, STOP, 0, 0, 0, NULL);
+			ppp_cp_event(proto->dev, PID_LCP, START, 0, 0, 0, NULL);
+		} else {	/* send keep-alive packet */
+			ppp->echo_id = ++ppp->seq;
+			ppp_tx_cp(proto->dev, PID_LCP, LCP_ECHO_REQ,
+				  ppp->echo_id, 0, NULL);
+			proto->timer.expires = jiffies +
+				ppp->keepalive_interval * HZ;
+			add_timer(&proto->timer);
+		}
+		break;
+	}
+	spin_unlock_irqrestore(&ppp->lock, flags);
+	ppp_tx_flush();
+}
+
+
+static void ppp_start(struct net_device *dev)
+{
+	struct ppp *ppp = get_ppp(dev);
+	int i;
+
+	for (i = 0; i < IDX_COUNT; i++) {
+		struct proto *proto = &ppp->protos[i];
+		proto->dev = dev;
+		init_timer(&proto->timer);
+		proto->timer.function = ppp_timer;
+		proto->timer.data = (unsigned long)proto;
+		proto->state = CLOSED;
+	}
+	ppp->protos[IDX_LCP].pid = PID_LCP;
+	ppp->protos[IDX_IPCP].pid = PID_IPCP;
+	ppp->protos[IDX_IPV6CP].pid = PID_IPV6CP;
+
+	ppp_cp_event(dev, PID_LCP, START, 0, 0, 0, NULL);
+}
+
+static void ppp_stop(struct net_device *dev)
+{
+	ppp_cp_event(dev, PID_LCP, STOP, 0, 0, 0, NULL);
+}
 
 static struct hdlc_proto proto = {
-	.open		= ppp_open,
-	.close		= ppp_close,
+	.start		= ppp_start,
+	.stop		= ppp_stop,
 	.type_trans	= ppp_type_trans,
 	.ioctl		= ppp_ioctl,
+	.netif_rx	= ppp_rx,
 	.module		= THIS_MODULE,
 };
 
+static const struct header_ops ppp_header_ops = {
+	.create = ppp_hard_header,
+};
 
 static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
 {
 	hdlc_device *hdlc = dev_to_hdlc(dev);
+	struct ppp *ppp;
 	int result;
 
 	switch (ifr->ifr_settings.type) {
@@ -109,25 +655,35 @@
 		return 0; /* return protocol only, no settable parameters */
 
 	case IF_PROTO_PPP:
-		if(!capable(CAP_NET_ADMIN))
+		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
-		if(dev->flags & IFF_UP)
+		if (dev->flags & IFF_UP)
 			return -EBUSY;
 
 		/* no settable parameters */
 
-		result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		result = hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
 		if (result)
 			return result;
 
-		result = attach_hdlc_protocol(dev, &proto,
-					      sizeof(struct ppp_state));
+		result = attach_hdlc_protocol(dev, &proto, sizeof(struct ppp));
 		if (result)
 			return result;
+
+		ppp = get_ppp(dev);
+		spin_lock_init(&ppp->lock);
+		ppp->req_timeout = 2;
+		ppp->cr_retries = 10;
+		ppp->term_retries = 2;
+		ppp->keepalive_interval = 10;
+		ppp->keepalive_timeout = 60;
+
 		dev->hard_start_xmit = hdlc->xmit;
+		dev->hard_header_len = sizeof(struct hdlc_header);
+		dev->header_ops = &ppp_header_ops;
 		dev->type = ARPHRD_PPP;
-		netif_dormant_off(dev);
+		netif_dormant_on(dev);
 		return 0;
 	}
 
@@ -137,12 +693,11 @@
 
 static int __init mod_init(void)
 {
+	skb_queue_head_init(&tx_queue);
 	register_hdlc_protocol(&proto);
 	return 0;
 }
 
-
-
 static void __exit mod_exit(void)
 {
 	unregister_hdlc_protocol(&proto);
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index e299313..af54f0c 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -66,7 +66,6 @@
 	 *	it right now.
 	 */
 	netif_rx(skb);
-	c->netdevice->last_rx = jiffies;
 }
 
 /*
diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c
new file mode 100644
index 0000000..0c68025
--- /dev/null
+++ b/drivers/net/wan/ixp4xx_hss.c
@@ -0,0 +1,1325 @@
+/*
+ * Intel IXP4xx HSS (synchronous serial port) driver for Linux
+ *
+ * Copyright (C) 2007-2008 Krzysztof Hałasa <khc@pm.waw.pl>
+ *
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/cdev.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/fs.h>
+#include <linux/hdlc.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <mach/npe.h>
+#include <mach/qmgr.h>
+
+#define DEBUG_DESC		0
+#define DEBUG_RX		0
+#define DEBUG_TX		0
+#define DEBUG_PKT_BYTES		0
+#define DEBUG_CLOSE		0
+
+#define DRV_NAME		"ixp4xx_hss"
+
+#define PKT_EXTRA_FLAGS		0 /* orig 1 */
+#define PKT_NUM_PIPES		1 /* 1, 2 or 4 */
+#define PKT_PIPE_FIFO_SIZEW	4 /* total 4 dwords per HSS */
+
+#define RX_DESCS		16 /* also length of all RX queues */
+#define TX_DESCS		16 /* also length of all TX queues */
+
+#define POOL_ALLOC_SIZE		(sizeof(struct desc) * (RX_DESCS + TX_DESCS))
+#define RX_SIZE			(HDLC_MAX_MRU + 4) /* NPE needs more space */
+#define MAX_CLOSE_WAIT		1000 /* microseconds */
+#define HSS_COUNT		2
+#define FRAME_SIZE		256 /* doesn't matter at this point */
+#define FRAME_OFFSET		0
+#define MAX_CHANNELS		(FRAME_SIZE / 8)
+
+#define NAPI_WEIGHT		16
+
+/* Queue IDs */
+#define HSS0_CHL_RXTRIG_QUEUE	12	/* orig size = 32 dwords */
+#define HSS0_PKT_RX_QUEUE	13	/* orig size = 32 dwords */
+#define HSS0_PKT_TX0_QUEUE	14	/* orig size = 16 dwords */
+#define HSS0_PKT_TX1_QUEUE	15
+#define HSS0_PKT_TX2_QUEUE	16
+#define HSS0_PKT_TX3_QUEUE	17
+#define HSS0_PKT_RXFREE0_QUEUE	18	/* orig size = 16 dwords */
+#define HSS0_PKT_RXFREE1_QUEUE	19
+#define HSS0_PKT_RXFREE2_QUEUE	20
+#define HSS0_PKT_RXFREE3_QUEUE	21
+#define HSS0_PKT_TXDONE_QUEUE	22	/* orig size = 64 dwords */
+
+#define HSS1_CHL_RXTRIG_QUEUE	10
+#define HSS1_PKT_RX_QUEUE	0
+#define HSS1_PKT_TX0_QUEUE	5
+#define HSS1_PKT_TX1_QUEUE	6
+#define HSS1_PKT_TX2_QUEUE	7
+#define HSS1_PKT_TX3_QUEUE	8
+#define HSS1_PKT_RXFREE0_QUEUE	1
+#define HSS1_PKT_RXFREE1_QUEUE	2
+#define HSS1_PKT_RXFREE2_QUEUE	3
+#define HSS1_PKT_RXFREE3_QUEUE	4
+#define HSS1_PKT_TXDONE_QUEUE	9
+
+#define NPE_PKT_MODE_HDLC		0
+#define NPE_PKT_MODE_RAW		1
+#define NPE_PKT_MODE_56KMODE		2
+#define NPE_PKT_MODE_56KENDIAN_MSB	4
+
+/* PKT_PIPE_HDLC_CFG_WRITE flags */
+#define PKT_HDLC_IDLE_ONES		0x1 /* default = flags */
+#define PKT_HDLC_CRC_32			0x2 /* default = CRC-16 */
+#define PKT_HDLC_MSB_ENDIAN		0x4 /* default = LE */
+
+
+/* hss_config, PCRs */
+/* Frame sync sampling, default = active low */
+#define PCR_FRM_SYNC_ACTIVE_HIGH	0x40000000
+#define PCR_FRM_SYNC_FALLINGEDGE	0x80000000
+#define PCR_FRM_SYNC_RISINGEDGE		0xC0000000
+
+/* Frame sync pin: input (default) or output generated off a given clk edge */
+#define PCR_FRM_SYNC_OUTPUT_FALLING	0x20000000
+#define PCR_FRM_SYNC_OUTPUT_RISING	0x30000000
+
+/* Frame and data clock sampling on edge, default = falling */
+#define PCR_FCLK_EDGE_RISING		0x08000000
+#define PCR_DCLK_EDGE_RISING		0x04000000
+
+/* Clock direction, default = input */
+#define PCR_SYNC_CLK_DIR_OUTPUT		0x02000000
+
+/* Generate/Receive frame pulses, default = enabled */
+#define PCR_FRM_PULSE_DISABLED		0x01000000
+
+ /* Data rate is full (default) or half the configured clk speed */
+#define PCR_HALF_CLK_RATE		0x00200000
+
+/* Invert data between NPE and HSS FIFOs? (default = no) */
+#define PCR_DATA_POLARITY_INVERT	0x00100000
+
+/* TX/RX endianness, default = LSB */
+#define PCR_MSB_ENDIAN			0x00080000
+
+/* Normal (default) / open drain mode (TX only) */
+#define PCR_TX_PINS_OPEN_DRAIN		0x00040000
+
+/* No framing bit transmitted and expected on RX? (default = framing bit) */
+#define PCR_SOF_NO_FBIT			0x00020000
+
+/* Drive data pins? */
+#define PCR_TX_DATA_ENABLE		0x00010000
+
+/* Voice 56k type: drive the data pins low (default), high, high Z */
+#define PCR_TX_V56K_HIGH		0x00002000
+#define PCR_TX_V56K_HIGH_IMP		0x00004000
+
+/* Unassigned type: drive the data pins low (default), high, high Z */
+#define PCR_TX_UNASS_HIGH		0x00000800
+#define PCR_TX_UNASS_HIGH_IMP		0x00001000
+
+/* T1 @ 1.544MHz only: Fbit dictated in FIFO (default) or high Z */
+#define PCR_TX_FB_HIGH_IMP		0x00000400
+
+/* 56k data endiannes - which bit unused: high (default) or low */
+#define PCR_TX_56KE_BIT_0_UNUSED	0x00000200
+
+/* 56k data transmission type: 32/8 bit data (default) or 56K data */
+#define PCR_TX_56KS_56K_DATA		0x00000100
+
+/* hss_config, cCR */
+/* Number of packetized clients, default = 1 */
+#define CCR_NPE_HFIFO_2_HDLC		0x04000000
+#define CCR_NPE_HFIFO_3_OR_4HDLC	0x08000000
+
+/* default = no loopback */
+#define CCR_LOOPBACK			0x02000000
+
+/* HSS number, default = 0 (first) */
+#define CCR_SECOND_HSS			0x01000000
+
+
+/* hss_config, clkCR: main:10, num:10, denom:12 */
+#define CLK42X_SPEED_EXP	((0x3FF << 22) | (  2 << 12) |   15) /*65 KHz*/
+
+#define CLK42X_SPEED_512KHZ	((  130 << 22) | (  2 << 12) |   15)
+#define CLK42X_SPEED_1536KHZ	((   43 << 22) | ( 18 << 12) |   47)
+#define CLK42X_SPEED_1544KHZ	((   43 << 22) | ( 33 << 12) |  192)
+#define CLK42X_SPEED_2048KHZ	((   32 << 22) | ( 34 << 12) |   63)
+#define CLK42X_SPEED_4096KHZ	((   16 << 22) | ( 34 << 12) |  127)
+#define CLK42X_SPEED_8192KHZ	((    8 << 22) | ( 34 << 12) |  255)
+
+#define CLK46X_SPEED_512KHZ	((  130 << 22) | ( 24 << 12) |  127)
+#define CLK46X_SPEED_1536KHZ	((   43 << 22) | (152 << 12) |  383)
+#define CLK46X_SPEED_1544KHZ	((   43 << 22) | ( 66 << 12) |  385)
+#define CLK46X_SPEED_2048KHZ	((   32 << 22) | (280 << 12) |  511)
+#define CLK46X_SPEED_4096KHZ	((   16 << 22) | (280 << 12) | 1023)
+#define CLK46X_SPEED_8192KHZ	((    8 << 22) | (280 << 12) | 2047)
+
+
+/* hss_config, LUT entries */
+#define TDMMAP_UNASSIGNED	0
+#define TDMMAP_HDLC		1	/* HDLC - packetized */
+#define TDMMAP_VOICE56K		2	/* Voice56K - 7-bit channelized */
+#define TDMMAP_VOICE64K		3	/* Voice64K - 8-bit channelized */
+
+/* offsets into HSS config */
+#define HSS_CONFIG_TX_PCR	0x00 /* port configuration registers */
+#define HSS_CONFIG_RX_PCR	0x04
+#define HSS_CONFIG_CORE_CR	0x08 /* loopback control, HSS# */
+#define HSS_CONFIG_CLOCK_CR	0x0C /* clock generator control */
+#define HSS_CONFIG_TX_FCR	0x10 /* frame configuration registers */
+#define HSS_CONFIG_RX_FCR	0x14
+#define HSS_CONFIG_TX_LUT	0x18 /* channel look-up tables */
+#define HSS_CONFIG_RX_LUT	0x38
+
+
+/* NPE command codes */
+/* writes the ConfigWord value to the location specified by offset */
+#define PORT_CONFIG_WRITE		0x40
+
+/* triggers the NPE to load the contents of the configuration table */
+#define PORT_CONFIG_LOAD		0x41
+
+/* triggers the NPE to return an HssErrorReadResponse message */
+#define PORT_ERROR_READ			0x42
+
+/* triggers the NPE to reset internal status and enable the HssPacketized
+   operation for the flow specified by pPipe */
+#define PKT_PIPE_FLOW_ENABLE		0x50
+#define PKT_PIPE_FLOW_DISABLE		0x51
+#define PKT_NUM_PIPES_WRITE		0x52
+#define PKT_PIPE_FIFO_SIZEW_WRITE	0x53
+#define PKT_PIPE_HDLC_CFG_WRITE		0x54
+#define PKT_PIPE_IDLE_PATTERN_WRITE	0x55
+#define PKT_PIPE_RX_SIZE_WRITE		0x56
+#define PKT_PIPE_MODE_WRITE		0x57
+
+/* HDLC packet status values - desc->status */
+#define ERR_SHUTDOWN		1 /* stop or shutdown occurrance */
+#define ERR_HDLC_ALIGN		2 /* HDLC alignment error */
+#define ERR_HDLC_FCS		3 /* HDLC Frame Check Sum error */
+#define ERR_RXFREE_Q_EMPTY	4 /* RX-free queue became empty while receiving
+				     this packet (if buf_len < pkt_len) */
+#define ERR_HDLC_TOO_LONG	5 /* HDLC frame size too long */
+#define ERR_HDLC_ABORT		6 /* abort sequence received */
+#define ERR_DISCONNECTING	7 /* disconnect is in progress */
+
+
+#ifdef __ARMEB__
+typedef struct sk_buff buffer_t;
+#define free_buffer dev_kfree_skb
+#define free_buffer_irq dev_kfree_skb_irq
+#else
+typedef void buffer_t;
+#define free_buffer kfree
+#define free_buffer_irq kfree
+#endif
+
+struct port {
+	struct device *dev;
+	struct npe *npe;
+	struct net_device *netdev;
+	struct napi_struct napi;
+	struct hss_plat_info *plat;
+	buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS];
+	struct desc *desc_tab;	/* coherent */
+	u32 desc_tab_phys;
+	unsigned int id;
+	unsigned int clock_type, clock_rate, loopback;
+	unsigned int initialized, carrier;
+	u8 hdlc_cfg;
+};
+
+/* NPE message structure */
+struct msg {
+#ifdef __ARMEB__
+	u8 cmd, unused, hss_port, index;
+	union {
+		struct { u8 data8a, data8b, data8c, data8d; };
+		struct { u16 data16a, data16b; };
+		struct { u32 data32; };
+	};
+#else
+	u8 index, hss_port, unused, cmd;
+	union {
+		struct { u8 data8d, data8c, data8b, data8a; };
+		struct { u16 data16b, data16a; };
+		struct { u32 data32; };
+	};
+#endif
+};
+
+/* HDLC packet descriptor */
+struct desc {
+	u32 next;		/* pointer to next buffer, unused */
+
+#ifdef __ARMEB__
+	u16 buf_len;		/* buffer length */
+	u16 pkt_len;		/* packet length */
+	u32 data;		/* pointer to data buffer in RAM */
+	u8 status;
+	u8 error_count;
+	u16 __reserved;
+#else
+	u16 pkt_len;		/* packet length */
+	u16 buf_len;		/* buffer length */
+	u32 data;		/* pointer to data buffer in RAM */
+	u16 __reserved;
+	u8 error_count;
+	u8 status;
+#endif
+	u32 __reserved1[4];
+};
+
+
+#define rx_desc_phys(port, n)	((port)->desc_tab_phys +		\
+				 (n) * sizeof(struct desc))
+#define rx_desc_ptr(port, n)	(&(port)->desc_tab[n])
+
+#define tx_desc_phys(port, n)	((port)->desc_tab_phys +		\
+				 ((n) + RX_DESCS) * sizeof(struct desc))
+#define tx_desc_ptr(port, n)	(&(port)->desc_tab[(n) + RX_DESCS])
+
+/*****************************************************************************
+ * global variables
+ ****************************************************************************/
+
+static int ports_open;
+static struct dma_pool *dma_pool;
+static spinlock_t npe_lock;
+
+static const struct {
+	int tx, txdone, rx, rxfree;
+}queue_ids[2] = {{HSS0_PKT_TX0_QUEUE, HSS0_PKT_TXDONE_QUEUE, HSS0_PKT_RX_QUEUE,
+		  HSS0_PKT_RXFREE0_QUEUE},
+		 {HSS1_PKT_TX0_QUEUE, HSS1_PKT_TXDONE_QUEUE, HSS1_PKT_RX_QUEUE,
+		  HSS1_PKT_RXFREE0_QUEUE},
+};
+
+/*****************************************************************************
+ * utility functions
+ ****************************************************************************/
+
+static inline struct port* dev_to_port(struct net_device *dev)
+{
+	return dev_to_hdlc(dev)->priv;
+}
+
+#ifndef __ARMEB__
+static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
+{
+	int i;
+	for (i = 0; i < cnt; i++)
+		dest[i] = swab32(src[i]);
+}
+#endif
+
+/*****************************************************************************
+ * HSS access
+ ****************************************************************************/
+
+static void hss_npe_send(struct port *port, struct msg *msg, const char* what)
+{
+	u32 *val = (u32*)msg;
+	if (npe_send_message(port->npe, msg, what)) {
+		printk(KERN_CRIT "HSS-%i: unable to send command [%08X:%08X]"
+		       " to %s\n", port->id, val[0], val[1],
+		       npe_name(port->npe));
+		BUG();
+	}
+}
+
+static void hss_config_set_lut(struct port *port)
+{
+	struct msg msg;
+	int ch;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PORT_CONFIG_WRITE;
+	msg.hss_port = port->id;
+
+	for (ch = 0; ch < MAX_CHANNELS; ch++) {
+		msg.data32 >>= 2;
+		msg.data32 |= TDMMAP_HDLC << 30;
+
+		if (ch % 16 == 15) {
+			msg.index = HSS_CONFIG_TX_LUT + ((ch / 4) & ~3);
+			hss_npe_send(port, &msg, "HSS_SET_TX_LUT");
+
+			msg.index += HSS_CONFIG_RX_LUT - HSS_CONFIG_TX_LUT;
+			hss_npe_send(port, &msg, "HSS_SET_RX_LUT");
+		}
+	}
+}
+
+static void hss_config(struct port *port)
+{
+	struct msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PORT_CONFIG_WRITE;
+	msg.hss_port = port->id;
+	msg.index = HSS_CONFIG_TX_PCR;
+	msg.data32 = PCR_FRM_SYNC_OUTPUT_RISING | PCR_MSB_ENDIAN |
+		PCR_TX_DATA_ENABLE | PCR_SOF_NO_FBIT;
+	if (port->clock_type == CLOCK_INT)
+		msg.data32 |= PCR_SYNC_CLK_DIR_OUTPUT;
+	hss_npe_send(port, &msg, "HSS_SET_TX_PCR");
+
+	msg.index = HSS_CONFIG_RX_PCR;
+	msg.data32 ^= PCR_TX_DATA_ENABLE | PCR_DCLK_EDGE_RISING;
+	hss_npe_send(port, &msg, "HSS_SET_RX_PCR");
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PORT_CONFIG_WRITE;
+	msg.hss_port = port->id;
+	msg.index = HSS_CONFIG_CORE_CR;
+	msg.data32 = (port->loopback ? CCR_LOOPBACK : 0) |
+		(port->id ? CCR_SECOND_HSS : 0);
+	hss_npe_send(port, &msg, "HSS_SET_CORE_CR");
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PORT_CONFIG_WRITE;
+	msg.hss_port = port->id;
+	msg.index = HSS_CONFIG_CLOCK_CR;
+	msg.data32 = CLK42X_SPEED_2048KHZ /* FIXME */;
+	hss_npe_send(port, &msg, "HSS_SET_CLOCK_CR");
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PORT_CONFIG_WRITE;
+	msg.hss_port = port->id;
+	msg.index = HSS_CONFIG_TX_FCR;
+	msg.data16a = FRAME_OFFSET;
+	msg.data16b = FRAME_SIZE - 1;
+	hss_npe_send(port, &msg, "HSS_SET_TX_FCR");
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PORT_CONFIG_WRITE;
+	msg.hss_port = port->id;
+	msg.index = HSS_CONFIG_RX_FCR;
+	msg.data16a = FRAME_OFFSET;
+	msg.data16b = FRAME_SIZE - 1;
+	hss_npe_send(port, &msg, "HSS_SET_RX_FCR");
+
+	hss_config_set_lut(port);
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PORT_CONFIG_LOAD;
+	msg.hss_port = port->id;
+	hss_npe_send(port, &msg, "HSS_LOAD_CONFIG");
+
+	if (npe_recv_message(port->npe, &msg, "HSS_LOAD_CONFIG") ||
+	    /* HSS_LOAD_CONFIG for port #1 returns port_id = #4 */
+	    msg.cmd != PORT_CONFIG_LOAD || msg.data32) {
+		printk(KERN_CRIT "HSS-%i: HSS_LOAD_CONFIG failed\n",
+		       port->id);
+		BUG();
+	}
+
+	/* HDLC may stop working without this - check FIXME */
+	npe_recv_message(port->npe, &msg, "FLUSH_IT");
+}
+
+static void hss_set_hdlc_cfg(struct port *port)
+{
+	struct msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PKT_PIPE_HDLC_CFG_WRITE;
+	msg.hss_port = port->id;
+	msg.data8a = port->hdlc_cfg; /* rx_cfg */
+	msg.data8b = port->hdlc_cfg | (PKT_EXTRA_FLAGS << 3); /* tx_cfg */
+	hss_npe_send(port, &msg, "HSS_SET_HDLC_CFG");
+}
+
+static u32 hss_get_status(struct port *port)
+{
+	struct msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PORT_ERROR_READ;
+	msg.hss_port = port->id;
+	hss_npe_send(port, &msg, "PORT_ERROR_READ");
+	if (npe_recv_message(port->npe, &msg, "PORT_ERROR_READ")) {
+		printk(KERN_CRIT "HSS-%i: unable to read HSS status\n",
+		       port->id);
+		BUG();
+	}
+
+	return msg.data32;
+}
+
+static void hss_start_hdlc(struct port *port)
+{
+	struct msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PKT_PIPE_FLOW_ENABLE;
+	msg.hss_port = port->id;
+	msg.data32 = 0;
+	hss_npe_send(port, &msg, "HSS_ENABLE_PKT_PIPE");
+}
+
+static void hss_stop_hdlc(struct port *port)
+{
+	struct msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PKT_PIPE_FLOW_DISABLE;
+	msg.hss_port = port->id;
+	hss_npe_send(port, &msg, "HSS_DISABLE_PKT_PIPE");
+	hss_get_status(port); /* make sure it's halted */
+}
+
+static int hss_load_firmware(struct port *port)
+{
+	struct msg msg;
+	int err;
+
+	if (port->initialized)
+		return 0;
+
+	if (!npe_running(port->npe) &&
+	    (err = npe_load_firmware(port->npe, npe_name(port->npe),
+				     port->dev)))
+		return err;
+
+	/* HDLC mode configuration */
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = PKT_NUM_PIPES_WRITE;
+	msg.hss_port = port->id;
+	msg.data8a = PKT_NUM_PIPES;
+	hss_npe_send(port, &msg, "HSS_SET_PKT_PIPES");
+
+	msg.cmd = PKT_PIPE_FIFO_SIZEW_WRITE;
+	msg.data8a = PKT_PIPE_FIFO_SIZEW;
+	hss_npe_send(port, &msg, "HSS_SET_PKT_FIFO");
+
+	msg.cmd = PKT_PIPE_MODE_WRITE;
+	msg.data8a = NPE_PKT_MODE_HDLC;
+	/* msg.data8b = inv_mask */
+	/* msg.data8c = or_mask */
+	hss_npe_send(port, &msg, "HSS_SET_PKT_MODE");
+
+	msg.cmd = PKT_PIPE_RX_SIZE_WRITE;
+	msg.data16a = HDLC_MAX_MRU; /* including CRC */
+	hss_npe_send(port, &msg, "HSS_SET_PKT_RX_SIZE");
+
+	msg.cmd = PKT_PIPE_IDLE_PATTERN_WRITE;
+	msg.data32 = 0x7F7F7F7F; /* ??? FIXME */
+	hss_npe_send(port, &msg, "HSS_SET_PKT_IDLE");
+
+	port->initialized = 1;
+	return 0;
+}
+
+/*****************************************************************************
+ * packetized (HDLC) operation
+ ****************************************************************************/
+
+static inline void debug_pkt(struct net_device *dev, const char *func,
+			     u8 *data, int len)
+{
+#if DEBUG_PKT_BYTES
+	int i;
+
+	printk(KERN_DEBUG "%s: %s(%i)", dev->name, func, len);
+	for (i = 0; i < len; i++) {
+		if (i >= DEBUG_PKT_BYTES)
+			break;
+		printk("%s%02X", !(i % 4) ? " " : "", data[i]);
+	}
+	printk("\n");
+#endif
+}
+
+
+static inline void debug_desc(u32 phys, struct desc *desc)
+{
+#if DEBUG_DESC
+	printk(KERN_DEBUG "%X: %X %3X %3X %08X %X %X\n",
+	       phys, desc->next, desc->buf_len, desc->pkt_len,
+	       desc->data, desc->status, desc->error_count);
+#endif
+}
+
+static inline int queue_get_desc(unsigned int queue, struct port *port,
+				 int is_tx)
+{
+	u32 phys, tab_phys, n_desc;
+	struct desc *tab;
+
+	if (!(phys = qmgr_get_entry(queue)))
+		return -1;
+
+	BUG_ON(phys & 0x1F);
+	tab_phys = is_tx ? tx_desc_phys(port, 0) : rx_desc_phys(port, 0);
+	tab = is_tx ? tx_desc_ptr(port, 0) : rx_desc_ptr(port, 0);
+	n_desc = (phys - tab_phys) / sizeof(struct desc);
+	BUG_ON(n_desc >= (is_tx ? TX_DESCS : RX_DESCS));
+	debug_desc(phys, &tab[n_desc]);
+	BUG_ON(tab[n_desc].next);
+	return n_desc;
+}
+
+static inline void queue_put_desc(unsigned int queue, u32 phys,
+				  struct desc *desc)
+{
+	debug_desc(phys, desc);
+	BUG_ON(phys & 0x1F);
+	qmgr_put_entry(queue, phys);
+	BUG_ON(qmgr_stat_overflow(queue));
+}
+
+
+static inline void dma_unmap_tx(struct port *port, struct desc *desc)
+{
+#ifdef __ARMEB__
+	dma_unmap_single(&port->netdev->dev, desc->data,
+			 desc->buf_len, DMA_TO_DEVICE);
+#else
+	dma_unmap_single(&port->netdev->dev, desc->data & ~3,
+			 ALIGN((desc->data & 3) + desc->buf_len, 4),
+			 DMA_TO_DEVICE);
+#endif
+}
+
+
+static void hss_hdlc_set_carrier(void *pdev, int carrier)
+{
+	struct net_device *netdev = pdev;
+	struct port *port = dev_to_port(netdev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&npe_lock, flags);
+	port->carrier = carrier;
+	if (!port->loopback) {
+		if (carrier)
+			netif_carrier_on(netdev);
+		else
+			netif_carrier_off(netdev);
+	}
+	spin_unlock_irqrestore(&npe_lock, flags);
+}
+
+static void hss_hdlc_rx_irq(void *pdev)
+{
+	struct net_device *dev = pdev;
+	struct port *port = dev_to_port(dev);
+
+#if DEBUG_RX
+	printk(KERN_DEBUG "%s: hss_hdlc_rx_irq\n", dev->name);
+#endif
+	qmgr_disable_irq(queue_ids[port->id].rx);
+	netif_rx_schedule(dev, &port->napi);
+}
+
+static int hss_hdlc_poll(struct napi_struct *napi, int budget)
+{
+	struct port *port = container_of(napi, struct port, napi);
+	struct net_device *dev = port->netdev;
+	unsigned int rxq = queue_ids[port->id].rx;
+	unsigned int rxfreeq = queue_ids[port->id].rxfree;
+	int received = 0;
+
+#if DEBUG_RX
+	printk(KERN_DEBUG "%s: hss_hdlc_poll\n", dev->name);
+#endif
+
+	while (received < budget) {
+		struct sk_buff *skb;
+		struct desc *desc;
+		int n;
+#ifdef __ARMEB__
+		struct sk_buff *temp;
+		u32 phys;
+#endif
+
+		if ((n = queue_get_desc(rxq, port, 0)) < 0) {
+#if DEBUG_RX
+			printk(KERN_DEBUG "%s: hss_hdlc_poll"
+			       " netif_rx_complete\n", dev->name);
+#endif
+			netif_rx_complete(dev, napi);
+			qmgr_enable_irq(rxq);
+			if (!qmgr_stat_empty(rxq) &&
+			    netif_rx_reschedule(dev, napi)) {
+#if DEBUG_RX
+				printk(KERN_DEBUG "%s: hss_hdlc_poll"
+				       " netif_rx_reschedule succeeded\n",
+				       dev->name);
+#endif
+				qmgr_disable_irq(rxq);
+				continue;
+			}
+#if DEBUG_RX
+			printk(KERN_DEBUG "%s: hss_hdlc_poll all done\n",
+			       dev->name);
+#endif
+			return received; /* all work done */
+		}
+
+		desc = rx_desc_ptr(port, n);
+#if 0 /* FIXME - error_count counts modulo 256, perhaps we should use it */
+		if (desc->error_count)
+			printk(KERN_DEBUG "%s: hss_hdlc_poll status 0x%02X"
+			       " errors %u\n", dev->name, desc->status,
+			       desc->error_count);
+#endif
+		skb = NULL;
+		switch (desc->status) {
+		case 0:
+#ifdef __ARMEB__
+			if ((skb = netdev_alloc_skb(dev, RX_SIZE)) != NULL) {
+				phys = dma_map_single(&dev->dev, skb->data,
+						      RX_SIZE,
+						      DMA_FROM_DEVICE);
+				if (dma_mapping_error(&dev->dev, phys)) {
+					dev_kfree_skb(skb);
+					skb = NULL;
+				}
+			}
+#else
+			skb = netdev_alloc_skb(dev, desc->pkt_len);
+#endif
+			if (!skb)
+				dev->stats.rx_dropped++;
+			break;
+		case ERR_HDLC_ALIGN:
+		case ERR_HDLC_ABORT:
+			dev->stats.rx_frame_errors++;
+			dev->stats.rx_errors++;
+			break;
+		case ERR_HDLC_FCS:
+			dev->stats.rx_crc_errors++;
+			dev->stats.rx_errors++;
+			break;
+		case ERR_HDLC_TOO_LONG:
+			dev->stats.rx_length_errors++;
+			dev->stats.rx_errors++;
+			break;
+		default:	/* FIXME - remove printk */
+			printk(KERN_ERR "%s: hss_hdlc_poll: status 0x%02X"
+			       " errors %u\n", dev->name, desc->status,
+			       desc->error_count);
+			dev->stats.rx_errors++;
+		}
+
+		if (!skb) {
+			/* put the desc back on RX-ready queue */
+			desc->buf_len = RX_SIZE;
+			desc->pkt_len = desc->status = 0;
+			queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc);
+			continue;
+		}
+
+		/* process received frame */
+#ifdef __ARMEB__
+		temp = skb;
+		skb = port->rx_buff_tab[n];
+		dma_unmap_single(&dev->dev, desc->data,
+				 RX_SIZE, DMA_FROM_DEVICE);
+#else
+		dma_sync_single(&dev->dev, desc->data,
+				RX_SIZE, DMA_FROM_DEVICE);
+		memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n],
+			      ALIGN(desc->pkt_len, 4) / 4);
+#endif
+		skb_put(skb, desc->pkt_len);
+
+		debug_pkt(dev, "hss_hdlc_poll", skb->data, skb->len);
+
+		skb->protocol = hdlc_type_trans(skb, dev);
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += skb->len;
+		netif_receive_skb(skb);
+
+		/* put the new buffer on RX-free queue */
+#ifdef __ARMEB__
+		port->rx_buff_tab[n] = temp;
+		desc->data = phys;
+#endif
+		desc->buf_len = RX_SIZE;
+		desc->pkt_len = 0;
+		queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc);
+		received++;
+	}
+#if DEBUG_RX
+	printk(KERN_DEBUG "hss_hdlc_poll: end, not all work done\n");
+#endif
+	return received;	/* not all work done */
+}
+
+
+static void hss_hdlc_txdone_irq(void *pdev)
+{
+	struct net_device *dev = pdev;
+	struct port *port = dev_to_port(dev);
+	int n_desc;
+
+#if DEBUG_TX
+	printk(KERN_DEBUG DRV_NAME ": hss_hdlc_txdone_irq\n");
+#endif
+	while ((n_desc = queue_get_desc(queue_ids[port->id].txdone,
+					port, 1)) >= 0) {
+		struct desc *desc;
+		int start;
+
+		desc = tx_desc_ptr(port, n_desc);
+
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += desc->pkt_len;
+
+		dma_unmap_tx(port, desc);
+#if DEBUG_TX
+		printk(KERN_DEBUG "%s: hss_hdlc_txdone_irq free %p\n",
+		       dev->name, port->tx_buff_tab[n_desc]);
+#endif
+		free_buffer_irq(port->tx_buff_tab[n_desc]);
+		port->tx_buff_tab[n_desc] = NULL;
+
+		start = qmgr_stat_empty(port->plat->txreadyq);
+		queue_put_desc(port->plat->txreadyq,
+			       tx_desc_phys(port, n_desc), desc);
+		if (start) {
+#if DEBUG_TX
+			printk(KERN_DEBUG "%s: hss_hdlc_txdone_irq xmit"
+			       " ready\n", dev->name);
+#endif
+			netif_wake_queue(dev);
+		}
+	}
+}
+
+static int hss_hdlc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct port *port = dev_to_port(dev);
+	unsigned int txreadyq = port->plat->txreadyq;
+	int len, offset, bytes, n;
+	void *mem;
+	u32 phys;
+	struct desc *desc;
+
+#if DEBUG_TX
+	printk(KERN_DEBUG "%s: hss_hdlc_xmit\n", dev->name);
+#endif
+
+	if (unlikely(skb->len > HDLC_MAX_MRU)) {
+		dev_kfree_skb(skb);
+		dev->stats.tx_errors++;
+		return NETDEV_TX_OK;
+	}
+
+	debug_pkt(dev, "hss_hdlc_xmit", skb->data, skb->len);
+
+	len = skb->len;
+#ifdef __ARMEB__
+	offset = 0; /* no need to keep alignment */
+	bytes = len;
+	mem = skb->data;
+#else
+	offset = (int)skb->data & 3; /* keep 32-bit alignment */
+	bytes = ALIGN(offset + len, 4);
+	if (!(mem = kmalloc(bytes, GFP_ATOMIC))) {
+		dev_kfree_skb(skb);
+		dev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
+	memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
+	dev_kfree_skb(skb);
+#endif
+
+	phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE);
+	if (dma_mapping_error(&dev->dev, phys)) {
+#ifdef __ARMEB__
+		dev_kfree_skb(skb);
+#else
+		kfree(mem);
+#endif
+		dev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
+
+	n = queue_get_desc(txreadyq, port, 1);
+	BUG_ON(n < 0);
+	desc = tx_desc_ptr(port, n);
+
+#ifdef __ARMEB__
+	port->tx_buff_tab[n] = skb;
+#else
+	port->tx_buff_tab[n] = mem;
+#endif
+	desc->data = phys + offset;
+	desc->buf_len = desc->pkt_len = len;
+
+	wmb();
+	queue_put_desc(queue_ids[port->id].tx, tx_desc_phys(port, n), desc);
+	dev->trans_start = jiffies;
+
+	if (qmgr_stat_empty(txreadyq)) {
+#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 DEBUG_TX
+			printk(KERN_DEBUG "%s: hss_hdlc_xmit ready again\n",
+			       dev->name);
+#endif
+			netif_wake_queue(dev);
+		}
+	}
+
+#if DEBUG_TX
+	printk(KERN_DEBUG "%s: hss_hdlc_xmit end\n", dev->name);
+#endif
+	return NETDEV_TX_OK;
+}
+
+
+static int request_hdlc_queues(struct port *port)
+{
+	int err;
+
+	err = qmgr_request_queue(queue_ids[port->id].rxfree, RX_DESCS, 0, 0,
+				 "%s:RX-free", port->netdev->name);
+	if (err)
+		return err;
+
+	err = qmgr_request_queue(queue_ids[port->id].rx, RX_DESCS, 0, 0,
+				 "%s:RX", port->netdev->name);
+	if (err)
+		goto rel_rxfree;
+
+	err = qmgr_request_queue(queue_ids[port->id].tx, TX_DESCS, 0, 0,
+				 "%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);
+	if (err)
+		goto rel_tx;
+
+	err = qmgr_request_queue(queue_ids[port->id].txdone, TX_DESCS, 0, 0,
+				 "%s:TX-done", port->netdev->name);
+	if (err)
+		goto rel_txready;
+	return 0;
+
+rel_txready:
+	qmgr_release_queue(port->plat->txreadyq);
+rel_tx:
+	qmgr_release_queue(queue_ids[port->id].tx);
+rel_rx:
+	qmgr_release_queue(queue_ids[port->id].rx);
+rel_rxfree:
+	qmgr_release_queue(queue_ids[port->id].rxfree);
+	printk(KERN_DEBUG "%s: unable to request hardware queues\n",
+	       port->netdev->name);
+	return err;
+}
+
+static void release_hdlc_queues(struct port *port)
+{
+	qmgr_release_queue(queue_ids[port->id].rxfree);
+	qmgr_release_queue(queue_ids[port->id].rx);
+	qmgr_release_queue(queue_ids[port->id].txdone);
+	qmgr_release_queue(queue_ids[port->id].tx);
+	qmgr_release_queue(port->plat->txreadyq);
+}
+
+static int init_hdlc_queues(struct port *port)
+{
+	int i;
+
+	if (!ports_open)
+		if (!(dma_pool = dma_pool_create(DRV_NAME, NULL,
+						 POOL_ALLOC_SIZE, 32, 0)))
+			return -ENOMEM;
+
+	if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL,
+					      &port->desc_tab_phys)))
+		return -ENOMEM;
+	memset(port->desc_tab, 0, POOL_ALLOC_SIZE);
+	memset(port->rx_buff_tab, 0, sizeof(port->rx_buff_tab)); /* tables */
+	memset(port->tx_buff_tab, 0, sizeof(port->tx_buff_tab));
+
+	/* Setup RX buffers */
+	for (i = 0; i < RX_DESCS; i++) {
+		struct desc *desc = rx_desc_ptr(port, i);
+		buffer_t *buff;
+		void *data;
+#ifdef __ARMEB__
+		if (!(buff = netdev_alloc_skb(port->netdev, RX_SIZE)))
+			return -ENOMEM;
+		data = buff->data;
+#else
+		if (!(buff = kmalloc(RX_SIZE, GFP_KERNEL)))
+			return -ENOMEM;
+		data = buff;
+#endif
+		desc->buf_len = RX_SIZE;
+		desc->data = dma_map_single(&port->netdev->dev, data,
+					    RX_SIZE, DMA_FROM_DEVICE);
+		if (dma_mapping_error(&port->netdev->dev, desc->data)) {
+			free_buffer(buff);
+			return -EIO;
+		}
+		port->rx_buff_tab[i] = buff;
+	}
+
+	return 0;
+}
+
+static void destroy_hdlc_queues(struct port *port)
+{
+	int i;
+
+	if (port->desc_tab) {
+		for (i = 0; i < RX_DESCS; i++) {
+			struct desc *desc = rx_desc_ptr(port, i);
+			buffer_t *buff = port->rx_buff_tab[i];
+			if (buff) {
+				dma_unmap_single(&port->netdev->dev,
+						 desc->data, RX_SIZE,
+						 DMA_FROM_DEVICE);
+				free_buffer(buff);
+			}
+		}
+		for (i = 0; i < TX_DESCS; i++) {
+			struct desc *desc = tx_desc_ptr(port, i);
+			buffer_t *buff = port->tx_buff_tab[i];
+			if (buff) {
+				dma_unmap_tx(port, desc);
+				free_buffer(buff);
+			}
+		}
+		dma_pool_free(dma_pool, port->desc_tab, port->desc_tab_phys);
+		port->desc_tab = NULL;
+	}
+
+	if (!ports_open && dma_pool) {
+		dma_pool_destroy(dma_pool);
+		dma_pool = NULL;
+	}
+}
+
+static int hss_hdlc_open(struct net_device *dev)
+{
+	struct port *port = dev_to_port(dev);
+	unsigned long flags;
+	int i, err = 0;
+
+	if ((err = hdlc_open(dev)))
+		return err;
+
+	if ((err = hss_load_firmware(port)))
+		goto err_hdlc_close;
+
+	if ((err = request_hdlc_queues(port)))
+		goto err_hdlc_close;
+
+	if ((err = init_hdlc_queues(port)))
+		goto err_destroy_queues;
+
+	spin_lock_irqsave(&npe_lock, flags);
+	if (port->plat->open)
+		if ((err = port->plat->open(port->id, dev,
+					    hss_hdlc_set_carrier)))
+			goto err_unlock;
+	spin_unlock_irqrestore(&npe_lock, flags);
+
+	/* Populate queues with buffers, no failure after this point */
+	for (i = 0; i < TX_DESCS; i++)
+		queue_put_desc(port->plat->txreadyq,
+			       tx_desc_phys(port, i), tx_desc_ptr(port, i));
+
+	for (i = 0; i < RX_DESCS; i++)
+		queue_put_desc(queue_ids[port->id].rxfree,
+			       rx_desc_phys(port, i), rx_desc_ptr(port, i));
+
+	napi_enable(&port->napi);
+	netif_start_queue(dev);
+
+	qmgr_set_irq(queue_ids[port->id].rx, QUEUE_IRQ_SRC_NOT_EMPTY,
+		     hss_hdlc_rx_irq, dev);
+
+	qmgr_set_irq(queue_ids[port->id].txdone, QUEUE_IRQ_SRC_NOT_EMPTY,
+		     hss_hdlc_txdone_irq, dev);
+	qmgr_enable_irq(queue_ids[port->id].txdone);
+
+	ports_open++;
+
+	hss_set_hdlc_cfg(port);
+	hss_config(port);
+
+	hss_start_hdlc(port);
+
+	/* we may already have RX data, enables IRQ */
+	netif_rx_schedule(dev, &port->napi);
+	return 0;
+
+err_unlock:
+	spin_unlock_irqrestore(&npe_lock, flags);
+err_destroy_queues:
+	destroy_hdlc_queues(port);
+	release_hdlc_queues(port);
+err_hdlc_close:
+	hdlc_close(dev);
+	return err;
+}
+
+static int hss_hdlc_close(struct net_device *dev)
+{
+	struct port *port = dev_to_port(dev);
+	unsigned long flags;
+	int i, buffs = RX_DESCS; /* allocated RX buffers */
+
+	spin_lock_irqsave(&npe_lock, flags);
+	ports_open--;
+	qmgr_disable_irq(queue_ids[port->id].rx);
+	netif_stop_queue(dev);
+	napi_disable(&port->napi);
+
+	hss_stop_hdlc(port);
+
+	while (queue_get_desc(queue_ids[port->id].rxfree, port, 0) >= 0)
+		buffs--;
+	while (queue_get_desc(queue_ids[port->id].rx, port, 0) >= 0)
+		buffs--;
+
+	if (buffs)
+		printk(KERN_CRIT "%s: unable to drain RX queue, %i buffer(s)"
+		       " left in NPE\n", dev->name, buffs);
+
+	buffs = TX_DESCS;
+	while (queue_get_desc(queue_ids[port->id].tx, port, 1) >= 0)
+		buffs--; /* cancel TX */
+
+	i = 0;
+	do {
+		while (queue_get_desc(port->plat->txreadyq, port, 1) >= 0)
+			buffs--;
+		if (!buffs)
+			break;
+	} while (++i < MAX_CLOSE_WAIT);
+
+	if (buffs)
+		printk(KERN_CRIT "%s: unable to drain TX queue, %i buffer(s) "
+		       "left in NPE\n", dev->name, buffs);
+#if DEBUG_CLOSE
+	if (!buffs)
+		printk(KERN_DEBUG "Draining TX queues took %i cycles\n", i);
+#endif
+	qmgr_disable_irq(queue_ids[port->id].txdone);
+
+	if (port->plat->close)
+		port->plat->close(port->id, dev);
+	spin_unlock_irqrestore(&npe_lock, flags);
+
+	destroy_hdlc_queues(port);
+	release_hdlc_queues(port);
+	hdlc_close(dev);
+	return 0;
+}
+
+
+static int hss_hdlc_attach(struct net_device *dev, unsigned short encoding,
+			   unsigned short parity)
+{
+	struct port *port = dev_to_port(dev);
+
+	if (encoding != ENCODING_NRZ)
+		return -EINVAL;
+
+	switch(parity) {
+	case PARITY_CRC16_PR1_CCITT:
+		port->hdlc_cfg = 0;
+		return 0;
+
+	case PARITY_CRC32_PR1_CCITT:
+		port->hdlc_cfg = PKT_HDLC_CRC_32;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+
+static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	const size_t size = sizeof(sync_serial_settings);
+	sync_serial_settings new_line;
+	sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
+	struct port *port = dev_to_port(dev);
+	unsigned long flags;
+	int clk;
+
+	if (cmd != SIOCWANDEV)
+		return hdlc_ioctl(dev, ifr, cmd);
+
+	switch(ifr->ifr_settings.type) {
+	case IF_GET_IFACE:
+		ifr->ifr_settings.type = IF_IFACE_V35;
+		if (ifr->ifr_settings.size < size) {
+			ifr->ifr_settings.size = size; /* data size wanted */
+			return -ENOBUFS;
+		}
+		memset(&new_line, 0, sizeof(new_line));
+		new_line.clock_type = port->clock_type;
+		new_line.clock_rate = 2048000; /* FIXME */
+		new_line.loopback = port->loopback;
+		if (copy_to_user(line, &new_line, size))
+			return -EFAULT;
+		return 0;
+
+	case IF_IFACE_SYNC_SERIAL:
+	case IF_IFACE_V35:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (copy_from_user(&new_line, line, size))
+			return -EFAULT;
+
+		clk = new_line.clock_type;
+		if (port->plat->set_clock)
+			clk = port->plat->set_clock(port->id, clk);
+
+		if (clk != CLOCK_EXT && clk != CLOCK_INT)
+			return -EINVAL;	/* No such clock setting */
+
+		if (new_line.loopback != 0 && new_line.loopback != 1)
+			return -EINVAL;
+
+		port->clock_type = clk; /* Update settings */
+		/* FIXME port->clock_rate = new_line.clock_rate */;
+		port->loopback = new_line.loopback;
+
+		spin_lock_irqsave(&npe_lock, flags);
+
+		if (dev->flags & IFF_UP)
+			hss_config(port);
+
+		if (port->loopback || port->carrier)
+			netif_carrier_on(port->netdev);
+		else
+			netif_carrier_off(port->netdev);
+		spin_unlock_irqrestore(&npe_lock, flags);
+
+		return 0;
+
+	default:
+		return hdlc_ioctl(dev, ifr, cmd);
+	}
+}
+
+/*****************************************************************************
+ * initialization
+ ****************************************************************************/
+
+static int __devinit hss_init_one(struct platform_device *pdev)
+{
+	struct port *port;
+	struct net_device *dev;
+	hdlc_device *hdlc;
+	int err;
+
+	if ((port = kzalloc(sizeof(*port), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	if ((port->npe = npe_request(0)) == NULL) {
+		err = -ENOSYS;
+		goto err_free;
+	}
+
+	if ((port->netdev = dev = alloc_hdlcdev(port)) == NULL) {
+		err = -ENOMEM;
+		goto err_plat;
+	}
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	hdlc = dev_to_hdlc(dev);
+	hdlc->attach = hss_hdlc_attach;
+	hdlc->xmit = hss_hdlc_xmit;
+	dev->open = hss_hdlc_open;
+	dev->stop = hss_hdlc_close;
+	dev->do_ioctl = hss_hdlc_ioctl;
+	dev->tx_queue_len = 100;
+	port->clock_type = CLOCK_EXT;
+	port->clock_rate = 2048000;
+	port->id = pdev->id;
+	port->dev = &pdev->dev;
+	port->plat = pdev->dev.platform_data;
+	netif_napi_add(dev, &port->napi, hss_hdlc_poll, NAPI_WEIGHT);
+
+	if ((err = register_hdlc_device(dev)))
+		goto err_free_netdev;
+
+	platform_set_drvdata(pdev, port);
+
+	printk(KERN_INFO "%s: HSS-%i\n", dev->name, port->id);
+	return 0;
+
+err_free_netdev:
+	free_netdev(dev);
+err_plat:
+	npe_release(port->npe);
+err_free:
+	kfree(port);
+	return err;
+}
+
+static int __devexit hss_remove_one(struct platform_device *pdev)
+{
+	struct port *port = platform_get_drvdata(pdev);
+
+	unregister_hdlc_device(port->netdev);
+	free_netdev(port->netdev);
+	npe_release(port->npe);
+	platform_set_drvdata(pdev, NULL);
+	kfree(port);
+	return 0;
+}
+
+static struct platform_driver ixp4xx_hss_driver = {
+	.driver.name	= DRV_NAME,
+	.probe		= hss_init_one,
+	.remove		= hss_remove_one,
+};
+
+static int __init hss_init_module(void)
+{
+	if ((ixp4xx_read_feature_bits() &
+	     (IXP4XX_FEATURE_HDLC | IXP4XX_FEATURE_HSS)) !=
+	    (IXP4XX_FEATURE_HDLC | IXP4XX_FEATURE_HSS))
+		return -ENOSYS;
+
+	spin_lock_init(&npe_lock);
+
+	return platform_driver_register(&ixp4xx_hss_driver);
+}
+
+static void __exit hss_cleanup_module(void)
+{
+	platform_driver_unregister(&ixp4xx_hss_driver);
+}
+
+MODULE_AUTHOR("Krzysztof Halasa");
+MODULE_DESCRIPTION("Intel IXP4xx HSS driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ixp4xx_hss");
+module_init(hss_init_module);
+module_exit(hss_cleanup_module);
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 24fd613..5b61b3e 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -143,7 +143,6 @@
 	*ptr = 0x00;
 
 	skb->protocol = x25_type_trans(skb, dev);
-	skb->dev->last_rx = jiffies;
 	return netif_rx(skb);
 }
 
@@ -235,7 +234,6 @@
 	*ptr = 0x01;
 
 	skb->protocol = x25_type_trans(skb, dev);
-	skb->dev->last_rx = jiffies;
 	netif_rx(skb);
 }
 
@@ -253,7 +251,6 @@
 	*ptr = 0x02;
 
 	skb->protocol = x25_type_trans(skb, dev);
-	skb->dev->last_rx = jiffies;
 	netif_rx(skb);
 }
 
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index d7bb63e..feac3b9 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -1594,7 +1594,6 @@
             goto skip_packet;
         }
         
-        dev->last_rx = jiffies;
 	sc->lmc_device->stats.rx_packets++;
 	sc->lmc_device->stats.rx_bytes += len;
 
diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c
index be9877f..94b4c20 100644
--- a/drivers/net/wan/lmc/lmc_proto.c
+++ b/drivers/net/wan/lmc/lmc_proto.c
@@ -142,7 +142,6 @@
     case LMC_PPP:
     case LMC_NET:
     default:
-        skb->dev->last_rx = jiffies;
         netif_rx(skb);
         break;
     case LMC_RAW:
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index 0a566b0..697715a 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -53,7 +53,7 @@
 #define NEED_SCA_MSCI_INTR
 #define MAX_TX_BUFFERS 10
 
-static char *hw = NULL;	/* pointer to hw=xxx command line string */
+static char *hw;	/* pointer to hw=xxx command line string */
 
 /* RISCom/N2 Board Registers */
 
@@ -145,7 +145,6 @@
 					 &(card)->ports[port] : NULL)
 
 
-
 static __inline__ u8 sca_get_page(card_t *card)
 {
 	return inb(card->io + N2_PSR) & PSR_PAGEBITS;
@@ -159,9 +158,7 @@
 }
 
 
-
-#include "hd6457x.c"
-
+#include "hd64570.c"
 
 
 static void n2_set_iface(port_t *port)
@@ -478,7 +475,7 @@
 			n2_destroy_card(card);
 			return -ENOBUFS;
 		}
-		sca_init_sync_port(port); /* Set up SCA memory */
+		sca_init_port(port); /* Set up SCA memory */
 
 		printk(KERN_INFO "%s: RISCom/N2 node %d\n",
 		       dev->name, port->phy_node);
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index d0a8d1e..c23fde0 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -1769,7 +1769,7 @@
 
 static void cpc_tx_timeout(struct net_device *dev)
 {
-	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
 	pc300ch_t *chan = (pc300ch_t *) d->chan;
 	pc300_t *card = (pc300_t *) chan->card;
 	int ch = chan->channel;
@@ -1796,7 +1796,7 @@
 
 static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
 	pc300ch_t *chan = (pc300ch_t *) d->chan;
 	pc300_t *card = (pc300_t *) chan->card;
 	int ch = chan->channel;
@@ -1874,7 +1874,7 @@
 
 static void cpc_net_rx(struct net_device *dev)
 {
-	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
 	pc300ch_t *chan = (pc300ch_t *) d->chan;
 	pc300_t *card = (pc300_t *) chan->card;
 	int ch = chan->channel;
@@ -2522,7 +2522,7 @@
 
 static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
 	pc300ch_t *chan = (pc300ch_t *) d->chan;
 	pc300_t *card = (pc300_t *) chan->card;
 	pc300conf_t conf_aux;
@@ -2718,9 +2718,8 @@
 					}
 					pc300patrntst.num_errors =
 						falc_pattern_test_error(card, ch);
-					if (!arg
-					    || copy_to_user(arg, &pc300patrntst,
-							    sizeof (pc300patterntst_t)))
+					if (copy_to_user(arg, &pc300patrntst,
+							 sizeof(pc300patterntst_t)))
 							return -EINVAL;
 				} else {
 					falc_pattern_test(card, ch, pc300patrntst.patrntst_on);
@@ -3058,7 +3057,7 @@
 static int cpc_attach(struct net_device *dev, unsigned short encoding,
 		      unsigned short parity)
 {
-	pc300dev_t *d = (pc300dev_t *)dev->priv;
+	pc300dev_t *d = (pc300dev_t *)dev_to_hdlc(dev)->priv;
 	pc300ch_t *chan = (pc300ch_t *)d->chan;
 	pc300_t *card = (pc300_t *)chan->card;
 	pc300chconf_t *conf = (pc300chconf_t *)&chan->conf;
@@ -3138,7 +3137,7 @@
 
 int cpc_open(struct net_device *dev)
 {
-	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
 	struct ifreq ifr;
 	int result;
 
@@ -3166,7 +3165,7 @@
 
 static int cpc_close(struct net_device *dev)
 {
-	pc300dev_t *d = (pc300dev_t *) dev->priv;
+	pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
 	pc300ch_t *chan = (pc300ch_t *) d->chan;
 	pc300_t *card = (pc300_t *) chan->card;
 	unsigned long flags;
@@ -3347,7 +3346,7 @@
 		d->line_on = 0;
 		d->line_off = 0;
 
-		dev = alloc_hdlcdev(NULL);
+		dev = alloc_hdlcdev(d);
 		if (dev == NULL)
 			continue;
 
@@ -3372,7 +3371,6 @@
 		dev->do_ioctl = cpc_ioctl;
 
 		if (register_hdlc_device(dev) == 0) {
-			dev->priv = d;	/* We need 'priv', hdlc doesn't */
 			printk("%s: Cyclades-PC300/", dev->name);
 			switch (card->hw.type) {
 				case PC300_TE:
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
index bf1b015..f247e5d 100644
--- a/drivers/net/wan/pc300too.c
+++ b/drivers/net/wan/pc300too.c
@@ -1,7 +1,7 @@
 /*
  * Cyclades PC300 synchronous serial card driver for Linux
  *
- * Copyright (C) 2000-2007 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 2000-2008 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -11,7 +11,7 @@
  *
  * Sources of information:
  *    Hitachi HD64572 SCA-II User's Manual
- *    Cyclades PC300 Linux driver
+ *    Original Cyclades PC300 Linux driver
  *
  * This driver currently supports only PC300/RSV (V.24/V.35) and
  * PC300/X21 cards.
@@ -37,17 +37,11 @@
 
 #include "hd64572.h"
 
-static const char* version = "Cyclades PC300 driver version: 1.17";
-static const char* devname = "PC300";
-
 #undef DEBUG_PKT
 #define DEBUG_RINGS
 
 #define PC300_PLX_SIZE		0x80    /* PLX control window size (128 B) */
 #define PC300_SCA_SIZE		0x400   /* SCA window size (1 KB) */
-#define ALL_PAGES_ALWAYS_MAPPED
-#define NEED_DETECT_RAM
-#define NEED_SCA_MSCI_INTR
 #define MAX_TX_BUFFERS		10
 
 static int pci_clock_freq = 33000000;
@@ -81,7 +75,8 @@
 
 
 typedef struct port_s {
-	struct net_device *dev;
+	struct napi_struct napi;
+	struct net_device *netdev;
 	struct card_s *card;
 	spinlock_t lock;	/* TX lock */
 	sync_serial_settings settings;
@@ -93,7 +88,7 @@
 	u16 txin;		/* tx ring buffer 'in' and 'last' pointers */
 	u16 txlast;
 	u8 rxs, txs, tmc;	/* SCA registers */
-	u8 phy_node;		/* physical port # - 0 or 1 */
+	u8 chan;		/* physical port # - 0 or 1 */
 }port_t;
 
 
@@ -114,21 +109,10 @@
 }card_t;
 
 
-#define sca_in(reg, card)	     readb(card->scabase + (reg))
-#define sca_out(value, reg, card)    writeb(value, card->scabase + (reg))
-#define sca_inw(reg, card)	     readw(card->scabase + (reg))
-#define sca_outw(value, reg, card)   writew(value, card->scabase + (reg))
-#define sca_inl(reg, card)	     readl(card->scabase + (reg))
-#define sca_outl(value, reg, card)   writel(value, card->scabase + (reg))
-
-#define port_to_card(port)	     (port->card)
-#define log_node(port)		     (port->phy_node)
-#define phy_node(port)		     (port->phy_node)
-#define winbase(card)		     (card->rambase)
 #define get_port(card, port)	     ((port) < (card)->n_ports ? \
 					 (&(card)->ports[port]) : (NULL))
 
-#include "hd6457x.c"
+#include "hd64572.c"
 
 
 static void pc300_set_iface(port_t *port)
@@ -139,8 +123,8 @@
 	u8 rxs = port->rxs & CLK_BRG_MASK;
 	u8 txs = port->txs & CLK_BRG_MASK;
 
-	sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
-		port_to_card(port));
+	sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
+		port->card);
 	switch(port->settings.clock_type) {
 	case CLOCK_INT:
 		rxs |= CLK_BRG; /* BRG output */
@@ -172,10 +156,10 @@
 	if (port->card->type == PC300_RSV) {
 		if (port->iface == IF_IFACE_V35)
 			writel(card->init_ctrl_value |
-			       PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+			       PC300_CHMEDIA_MASK(port->chan), init_ctrl);
 		else
 			writel(card->init_ctrl_value &
-			       ~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+			       ~PC300_CHMEDIA_MASK(port->chan), init_ctrl);
 	}
 }
 
@@ -280,10 +264,8 @@
 	card_t *card = pci_get_drvdata(pdev);
 
 	for (i = 0; i < 2; i++)
-		if (card->ports[i].card) {
-			struct net_device *dev = port_to_dev(&card->ports[i]);
-			unregister_hdlc_device(dev);
-		}
+		if (card->ports[i].card)
+			unregister_hdlc_device(card->ports[i].netdev);
 
 	if (card->irq)
 		free_irq(card->irq, card);
@@ -298,10 +280,10 @@
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
-	if (card->ports[0].dev)
-		free_netdev(card->ports[0].dev);
-	if (card->ports[1].dev)
-		free_netdev(card->ports[1].dev);
+	if (card->ports[0].netdev)
+		free_netdev(card->ports[0].netdev);
+	if (card->ports[1].netdev)
+		free_netdev(card->ports[1].netdev);
 	kfree(card);
 }
 
@@ -318,12 +300,6 @@
 	u32 scaphys;		/* SCA memory base */
 	u32 plxphys;		/* PLX registers memory base */
 
-#ifndef MODULE
-	static int printed_version;
-	if (!printed_version++)
-		printk(KERN_INFO "%s\n", version);
-#endif
-
 	i = pci_enable_device(pdev);
 	if (i)
 		return i;
@@ -343,6 +319,35 @@
 	}
 	pci_set_drvdata(pdev, card);
 
+	if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE ||
+	    pci_resource_len(pdev, 2) != PC300_SCA_SIZE ||
+	    pci_resource_len(pdev, 3) < 16384) {
+		printk(KERN_ERR "pc300: invalid card EEPROM parameters\n");
+		pc300_pci_remove_one(pdev);
+		return -EFAULT;
+	}
+
+	plxphys = pci_resource_start(pdev, 0) & PCI_BASE_ADDRESS_MEM_MASK;
+	card->plxbase = ioremap(plxphys, PC300_PLX_SIZE);
+
+	scaphys = pci_resource_start(pdev, 2) & PCI_BASE_ADDRESS_MEM_MASK;
+	card->scabase = ioremap(scaphys, PC300_SCA_SIZE);
+
+	ramphys = pci_resource_start(pdev, 3) & PCI_BASE_ADDRESS_MEM_MASK;
+	card->rambase = pci_ioremap_bar(pdev, 3);
+
+	if (card->plxbase == NULL ||
+	    card->scabase == NULL ||
+	    card->rambase == NULL) {
+		printk(KERN_ERR "pc300: ioremap() failed\n");
+		pc300_pci_remove_one(pdev);
+	}
+
+	/* PLX PCI 9050 workaround for local configuration register read bug */
+	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys);
+	card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl);
+	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys);
+
 	if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 ||
 	    pdev->device == PCI_DEVICE_ID_PC300_TE_2)
 		card->type = PC300_TE; /* not fully supported */
@@ -358,41 +363,12 @@
 		card->n_ports = 2;
 
 	for (i = 0; i < card->n_ports; i++)
-		if (!(card->ports[i].dev = alloc_hdlcdev(&card->ports[i]))) {
+		if (!(card->ports[i].netdev = alloc_hdlcdev(&card->ports[i]))) {
 			printk(KERN_ERR "pc300: unable to allocate memory\n");
 			pc300_pci_remove_one(pdev);
 			return -ENOMEM;
 		}
 
-	if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE ||
-	    pci_resource_len(pdev, 2) != PC300_SCA_SIZE ||
-	    pci_resource_len(pdev, 3) < 16384) {
-		printk(KERN_ERR "pc300: invalid card EEPROM parameters\n");
-		pc300_pci_remove_one(pdev);
-		return -EFAULT;
-	}
-
-	plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK;
-	card->plxbase = ioremap(plxphys, PC300_PLX_SIZE);
-
-	scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK;
-	card->scabase = ioremap(scaphys, PC300_SCA_SIZE);
-
-	ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK;
-	card->rambase = ioremap(ramphys, pci_resource_len(pdev,3));
-
-	if (card->plxbase == NULL ||
-	    card->scabase == NULL ||
-	    card->rambase == NULL) {
-		printk(KERN_ERR "pc300: ioremap() failed\n");
-		pc300_pci_remove_one(pdev);
-	}
-
-	/* PLX PCI 9050 workaround for local configuration register read bug */
-	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys);
-	card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl);
-	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys);
-
 	/* Reset PLX */
 	p = &card->plxbase->init_ctrl;
 	writel(card->init_ctrl_value | 0x40000000, p);
@@ -446,7 +422,7 @@
 	writew(0x0041, &card->plxbase->intr_ctrl_stat);
 
 	/* Allocate IRQ */
-	if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) {
+	if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, "pc300", card)) {
 		printk(KERN_WARNING "pc300: could not allocate IRQ%d.\n",
 		       pdev->irq);
 		pc300_pci_remove_one(pdev);
@@ -463,9 +439,9 @@
 
 	for (i = 0; i < card->n_ports; i++) {
 		port_t *port = &card->ports[i];
-		struct net_device *dev = port_to_dev(port);
+		struct net_device *dev = port->netdev;
 		hdlc_device *hdlc = dev_to_hdlc(dev);
-		port->phy_node = i;
+		port->chan = i;
 
 		spin_lock_init(&port->lock);
 		dev->irq = card->irq;
@@ -484,6 +460,7 @@
 		else
 			port->iface = IF_IFACE_V35;
 
+		sca_init_port(port);
 		if (register_hdlc_device(dev)) {
 			printk(KERN_ERR "pc300: unable to register hdlc "
 			       "device\n");
@@ -491,10 +468,9 @@
 			pc300_pci_remove_one(pdev);
 			return -ENOBUFS;
 		}
-		sca_init_sync_port(port);	/* Set up SCA memory */
 
-		printk(KERN_INFO "%s: PC300 node %d\n",
-		       dev->name, port->phy_node);
+		printk(KERN_INFO "%s: PC300 channel %d\n",
+		       dev->name, port->chan);
 	}
 	return 0;
 }
@@ -524,9 +500,6 @@
 
 static int __init pc300_init_module(void)
 {
-#ifdef MODULE
-	printk(KERN_INFO "%s\n", version);
-#endif
 	if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
 		printk(KERN_ERR "pc300: Invalid PCI clock frequency\n");
 		return -EINVAL;
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index b595b64..1104d3a 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -1,7 +1,7 @@
 /*
  * Goramo PCI200SYN synchronous serial card driver for Linux
  *
- * Copyright (C) 2002-2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 2002-2008 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -33,17 +33,11 @@
 
 #include "hd64572.h"
 
-static const char* version = "Goramo PCI200SYN driver version: 1.16";
-static const char* devname = "PCI200SYN";
-
 #undef DEBUG_PKT
 #define DEBUG_RINGS
 
 #define PCI200SYN_PLX_SIZE	0x80	/* PLX control window size (128b) */
 #define PCI200SYN_SCA_SIZE	0x400	/* SCA window size (1Kb) */
-#define ALL_PAGES_ALWAYS_MAPPED
-#define NEED_DETECT_RAM
-#define NEED_SCA_MSCI_INTR
 #define MAX_TX_BUFFERS		10
 
 static int pci_clock_freq = 33000000;
@@ -68,7 +62,8 @@
 
 
 typedef struct port_s {
-	struct net_device *dev;
+	struct napi_struct napi;
+	struct net_device *netdev;
 	struct card_s *card;
 	spinlock_t lock;	/* TX lock */
 	sync_serial_settings settings;
@@ -79,7 +74,7 @@
 	u16 txin;		/* tx ring buffer 'in' and 'last' pointers */
 	u16 txlast;
 	u8 rxs, txs, tmc;	/* SCA registers */
-	u8 phy_node;		/* physical port # - 0 or 1 */
+	u8 chan;		/* physical port # - 0 or 1 */
 }port_t;
 
 
@@ -97,17 +92,6 @@
 }card_t;
 
 
-#define sca_in(reg, card)	     readb(card->scabase + (reg))
-#define sca_out(value, reg, card)    writeb(value, card->scabase + (reg))
-#define sca_inw(reg, card)	     readw(card->scabase + (reg))
-#define sca_outw(value, reg, card)   writew(value, card->scabase + (reg))
-#define sca_inl(reg, card)	     readl(card->scabase + (reg))
-#define sca_outl(value, reg, card)   writel(value, card->scabase + (reg))
-
-#define port_to_card(port)	     (port->card)
-#define log_node(port)		     (port->phy_node)
-#define phy_node(port)		     (port->phy_node)
-#define winbase(card)		     (card->rambase)
 #define get_port(card, port)	     (&card->ports[port])
 #define sca_flush(card)		     (sca_in(IER0, card));
 
@@ -127,7 +111,7 @@
 #undef memcpy_toio
 #define memcpy_toio new_memcpy_toio
 
-#include "hd6457x.c"
+#include "hd64572.c"
 
 
 static void pci200_set_iface(port_t *port)
@@ -137,8 +121,8 @@
 	u8 rxs = port->rxs & CLK_BRG_MASK;
 	u8 txs = port->txs & CLK_BRG_MASK;
 
-	sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
-		port_to_card(port));
+	sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
+		port->card);
 	switch(port->settings.clock_type) {
 	case CLOCK_INT:
 		rxs |= CLK_BRG; /* BRG output */
@@ -180,7 +164,7 @@
 
 	sca_open(dev);
 	pci200_set_iface(port);
-	sca_flush(port_to_card(port));
+	sca_flush(port->card);
 	return 0;
 }
 
@@ -189,7 +173,7 @@
 static int pci200_close(struct net_device *dev)
 {
 	sca_close(dev);
-	sca_flush(port_to_card(dev_to_port(dev)));
+	sca_flush(dev_to_port(dev)->card);
 	hdlc_close(dev);
 	return 0;
 }
@@ -242,7 +226,7 @@
 
 		memcpy(&port->settings, &new_line, size); /* Update settings */
 		pci200_set_iface(port);
-		sca_flush(port_to_card(port));
+		sca_flush(port->card);
 		return 0;
 
 	default:
@@ -258,10 +242,8 @@
 	card_t *card = pci_get_drvdata(pdev);
 
 	for (i = 0; i < 2; i++)
-		if (card->ports[i].card) {
-			struct net_device *dev = port_to_dev(&card->ports[i]);
-			unregister_hdlc_device(dev);
-		}
+		if (card->ports[i].card)
+			unregister_hdlc_device(card->ports[i].netdev);
 
 	if (card->irq)
 		free_irq(card->irq, card);
@@ -276,10 +258,10 @@
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
-	if (card->ports[0].dev)
-		free_netdev(card->ports[0].dev);
-	if (card->ports[1].dev)
-		free_netdev(card->ports[1].dev);
+	if (card->ports[0].netdev)
+		free_netdev(card->ports[0].netdev);
+	if (card->ports[1].netdev)
+		free_netdev(card->ports[1].netdev);
 	kfree(card);
 }
 
@@ -296,12 +278,6 @@
 	u32 scaphys;		/* SCA memory base */
 	u32 plxphys;		/* PLX registers memory base */
 
-#ifndef MODULE
-	static int printed_version;
-	if (!printed_version++)
-		printk(KERN_INFO "%s\n", version);
-#endif
-
 	i = pci_enable_device(pdev);
 	if (i)
 		return i;
@@ -320,9 +296,9 @@
 		return -ENOBUFS;
 	}
 	pci_set_drvdata(pdev, card);
-	card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
-	card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
-	if (!card->ports[0].dev || !card->ports[1].dev) {
+	card->ports[0].netdev = alloc_hdlcdev(&card->ports[0]);
+	card->ports[1].netdev = alloc_hdlcdev(&card->ports[1]);
+	if (!card->ports[0].netdev || !card->ports[1].netdev) {
 		printk(KERN_ERR "pci200syn: unable to allocate memory\n");
 		pci200_pci_remove_one(pdev);
 		return -ENOMEM;
@@ -343,7 +319,7 @@
 	card->scabase = ioremap(scaphys, PCI200SYN_SCA_SIZE);
 
 	ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK;
-	card->rambase = ioremap(ramphys, pci_resource_len(pdev,3));
+	card->rambase = pci_ioremap_bar(pdev, 3);
 
 	if (card->plxbase == NULL ||
 	    card->scabase == NULL ||
@@ -398,7 +374,7 @@
 	writew(readw(p) | 0x0040, p);
 
 	/* Allocate IRQ */
-	if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) {
+	if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, "pci200syn", card)) {
 		printk(KERN_WARNING "pci200syn: could not allocate IRQ%d.\n",
 		       pdev->irq);
 		pci200_pci_remove_one(pdev);
@@ -410,9 +386,9 @@
 
 	for (i = 0; i < 2; i++) {
 		port_t *port = &card->ports[i];
-		struct net_device *dev = port_to_dev(port);
+		struct net_device *dev = port->netdev;
 		hdlc_device *hdlc = dev_to_hdlc(dev);
-		port->phy_node = i;
+		port->chan = i;
 
 		spin_lock_init(&port->lock);
 		dev->irq = card->irq;
@@ -426,6 +402,7 @@
 		hdlc->xmit = sca_xmit;
 		port->settings.clock_type = CLOCK_EXT;
 		port->card = card;
+		sca_init_port(port);
 		if (register_hdlc_device(dev)) {
 			printk(KERN_ERR "pci200syn: unable to register hdlc "
 			       "device\n");
@@ -433,10 +410,9 @@
 			pci200_pci_remove_one(pdev);
 			return -ENOBUFS;
 		}
-		sca_init_sync_port(port);	/* Set up SCA memory */
 
-		printk(KERN_INFO "%s: PCI200SYN node %d\n",
-		       dev->name, port->phy_node);
+		printk(KERN_INFO "%s: PCI200SYN channel %d\n",
+		       dev->name, port->chan);
 	}
 
 	sca_flush(card);
@@ -464,9 +440,6 @@
 
 static int __init pci200_init_module(void)
 {
-#ifdef MODULE
-	printk(KERN_INFO "%s\n", version);
-#endif
 	if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
 		printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n");
 		return -EINVAL;
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index ee51b6a..0aa28e1 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -186,6 +186,7 @@
 	0x2b0, 0x2b4, 0x2c0, 0x2c4, 0x2d0, 0x2d4, 0x2e0, 0x2e4, 0x2f0, 0x2f4,
 	0 };
 
+#define NET_LOCAL_LOCK(dev) (((struct net_local *)netdev_priv(dev))->lock)
 
 /*
  * Look for SBNI card which addr stored in dev->base_addr, if nonzero.
@@ -287,7 +288,7 @@
 }
 
 
-int __init
+static int __init
 sbni_pci_probe( struct net_device  *dev )
 {
 	struct pci_dev  *pdev = NULL;
@@ -378,22 +379,23 @@
 	dev->irq = irq;
 	dev->base_addr = ioaddr;
 
-	/* Allocate dev->priv and fill in sbni-specific dev fields. */
-	nl = dev->priv;
+	/* Fill in sbni-specific dev fields. */
+	nl = netdev_priv(dev);
 	if( !nl ) {
 		printk( KERN_ERR "%s: unable to get memory!\n", dev->name );
 		release_region( ioaddr, SBNI_IO_EXTENT );
 		return NULL;
 	}
 
-	dev->priv = nl;
 	memset( nl, 0, sizeof(struct net_local) );
 	spin_lock_init( &nl->lock );
 
 	/* store MAC address (generate if that isn't known) */
 	*(__be16 *)dev->dev_addr = htons( 0x00ff );
 	*(__be32 *)(dev->dev_addr + 2) = htonl( 0x01000000 |
-		( (mac[num]  ?  mac[num]  :  (u32)((long)dev->priv)) & 0x00ffffff) );
+		((mac[num] ?
+		mac[num] :
+		(u32)((long)netdev_priv(dev))) & 0x00ffffff));
 
 	/* store link settings (speed, receive level ) */
 	nl->maxframe  = DEFAULT_FRAME_LEN;
@@ -447,7 +449,7 @@
 
 	/* Looking for idle device in the list */
 	for( p = dev;  p; ) {
-		struct net_local  *nl = (struct net_local *) p->priv;
+		struct net_local  *nl = netdev_priv(p);
 		spin_lock( &nl->lock );
 		if( nl->tx_buf_p  ||  (nl->state & FL_LINE_DOWN) ) {
 			p = nl->link;
@@ -469,7 +471,7 @@
 static int
 sbni_start_xmit( struct sk_buff  *skb,  struct net_device  *dev )
 {
-	struct net_local  *nl  = (struct net_local *) dev->priv;
+	struct net_local  *nl  = netdev_priv(dev);
 
 	netif_stop_queue( dev );
 	spin_lock( &nl->lock );
@@ -503,12 +505,12 @@
 sbni_interrupt( int  irq,  void  *dev_id )
 {
 	struct net_device	  *dev = dev_id;
-	struct net_local  *nl  = dev->priv;
+	struct net_local  *nl  = netdev_priv(dev);
 	int	repeat;
 
 	spin_lock( &nl->lock );
 	if( nl->second )
-		spin_lock( &((struct net_local *) nl->second->priv)->lock );
+		spin_lock(&NET_LOCAL_LOCK(nl->second));
 
 	do {
 		repeat = 0;
@@ -522,7 +524,7 @@
 	} while( repeat );
 
 	if( nl->second )
-		spin_unlock( &((struct net_local *)nl->second->priv)->lock );
+		spin_unlock(&NET_LOCAL_LOCK(nl->second));
 	spin_unlock( &nl->lock );
 	return IRQ_HANDLED;
 }
@@ -531,7 +533,7 @@
 static void
 handle_channel( struct net_device  *dev )
 {
-	struct net_local	*nl    = (struct net_local *) dev->priv;
+	struct net_local	*nl    = netdev_priv(dev);
 	unsigned long		ioaddr = dev->base_addr;
 
 	int  req_ans;
@@ -540,7 +542,7 @@
 #ifdef CONFIG_SBNI_MULTILINE
 	/* Lock the master device because we going to change its local data */
 	if( nl->state & FL_SLAVE )
-		spin_lock( &((struct net_local *) nl->master->priv)->lock );
+		spin_lock(&NET_LOCAL_LOCK(nl->master));
 #endif
 
 	outb( (inb( ioaddr + CSR0 ) & ~EN_INT) | TR_REQ, ioaddr + CSR0 );
@@ -576,7 +578,7 @@
 
 #ifdef CONFIG_SBNI_MULTILINE
 	if( nl->state & FL_SLAVE )
-		spin_unlock( &((struct net_local *) nl->master->priv)->lock );
+		spin_unlock(&NET_LOCAL_LOCK(nl->master));
 #endif
 }
 
@@ -589,7 +591,7 @@
 static int
 recv_frame( struct net_device  *dev )
 {
-	struct net_local  *nl   = (struct net_local *) dev->priv;
+	struct net_local  *nl   = netdev_priv(dev);
 	unsigned long  ioaddr	= dev->base_addr;
 
 	u32  crc = CRC32_INITIAL;
@@ -623,7 +625,7 @@
 static void
 send_frame( struct net_device  *dev )
 {
-	struct net_local  *nl    = (struct net_local *) dev->priv;
+	struct net_local  *nl    = netdev_priv(dev);
 
 	u32  crc = CRC32_INITIAL;
 
@@ -680,7 +682,7 @@
 static void
 download_data( struct net_device  *dev,  u32  *crc_p )
 {
-	struct net_local  *nl    = (struct net_local *) dev->priv;
+	struct net_local  *nl    = netdev_priv(dev);
 	struct sk_buff    *skb	 = nl->tx_buf_p;
 
 	unsigned  len = min_t(unsigned int, skb->len - nl->outpos, nl->framelen);
@@ -699,7 +701,7 @@
 upload_data( struct net_device  *dev,  unsigned  framelen,  unsigned  frameno,
 	     unsigned  is_first,  u32  crc )
 {
-	struct net_local  *nl = (struct net_local *) dev->priv;
+	struct net_local  *nl = netdev_priv(dev);
 
 	int  frame_ok;
 
@@ -721,9 +723,9 @@
 			nl->wait_frameno = 0,
 			nl->inppos = 0,
 #ifdef CONFIG_SBNI_MULTILINE
-			((struct net_local *) nl->master->priv)
+			((struct net_local *)netdev_priv(nl->master))
 				->stats.rx_errors++,
-			((struct net_local *) nl->master->priv)
+			((struct net_local *)netdev_priv(nl->master))
 				->stats.rx_missed_errors++;
 #else
 			nl->stats.rx_errors++,
@@ -740,8 +742,10 @@
 		 */
 		nl->wait_frameno = 0,
 #ifdef CONFIG_SBNI_MULTILINE
-		((struct net_local *) nl->master->priv)->stats.rx_errors++,
-		((struct net_local *) nl->master->priv)->stats.rx_crc_errors++;
+		((struct net_local *)netdev_priv(nl->master))
+			->stats.rx_errors++,
+		((struct net_local *)netdev_priv(nl->master))
+			->stats.rx_crc_errors++;
 #else
 		nl->stats.rx_errors++,
 		nl->stats.rx_crc_errors++;
@@ -755,8 +759,8 @@
 send_complete( struct net_local  *nl )
 {
 #ifdef CONFIG_SBNI_MULTILINE
-	((struct net_local *) nl->master->priv)->stats.tx_packets++;
-	((struct net_local *) nl->master->priv)->stats.tx_bytes
+	((struct net_local *)netdev_priv(nl->master))->stats.tx_packets++;
+	((struct net_local *)netdev_priv(nl->master))->stats.tx_bytes
 		+= nl->tx_buf_p->len;
 #else
 	nl->stats.tx_packets++;
@@ -775,7 +779,7 @@
 static void
 interpret_ack( struct net_device  *dev,  unsigned  ack )
 {
-	struct net_local  *nl = (struct net_local *) dev->priv;
+	struct net_local  *nl = netdev_priv(dev);
 
 	if( ack == FRAME_SENT_OK ) {
 		nl->state &= ~FL_NEED_RESEND;
@@ -809,7 +813,7 @@
 static int
 append_frame_to_pkt( struct net_device  *dev,  unsigned  framelen,  u32  crc )
 {
-	struct net_local  *nl = (struct net_local *) dev->priv;
+	struct net_local  *nl = netdev_priv(dev);
 
 	u8  *p;
 
@@ -840,7 +844,7 @@
 static void
 prepare_to_send( struct sk_buff  *skb,  struct net_device  *dev )
 {
-	struct net_local  *nl = (struct net_local *) dev->priv;
+	struct net_local  *nl = netdev_priv(dev);
 
 	unsigned int  len;
 
@@ -871,15 +875,15 @@
 static void
 drop_xmit_queue( struct net_device  *dev )
 {
-	struct net_local  *nl = (struct net_local *) dev->priv;
+	struct net_local  *nl = netdev_priv(dev);
 
 	if( nl->tx_buf_p )
 		dev_kfree_skb_any( nl->tx_buf_p ),
 		nl->tx_buf_p = NULL,
 #ifdef CONFIG_SBNI_MULTILINE
-		((struct net_local *) nl->master->priv)
+		((struct net_local *)netdev_priv(nl->master))
 			->stats.tx_errors++,
-		((struct net_local *) nl->master->priv)
+		((struct net_local *)netdev_priv(nl->master))
 			->stats.tx_carrier_errors++;
 #else
 		nl->stats.tx_errors++,
@@ -903,7 +907,7 @@
 static void
 send_frame_header( struct net_device  *dev,  u32  *crc_p )
 {
-	struct net_local  *nl  = (struct net_local *) dev->priv;
+	struct net_local  *nl  = netdev_priv(dev);
 
 	u32  crc = *crc_p;
 	u32  len_field = nl->framelen + 6;	/* CRC + frameno + reserved */
@@ -1005,7 +1009,7 @@
 static void
 indicate_pkt( struct net_device  *dev )
 {
-	struct net_local  *nl  = (struct net_local *) dev->priv;
+	struct net_local  *nl  = netdev_priv(dev);
 	struct sk_buff    *skb = nl->rx_buf_p;
 
 	skb_put( skb, nl->inppos );
@@ -1013,13 +1017,12 @@
 #ifdef CONFIG_SBNI_MULTILINE
 	skb->protocol = eth_type_trans( skb, nl->master );
 	netif_rx( skb );
-	dev->last_rx = jiffies;
-	++((struct net_local *) nl->master->priv)->stats.rx_packets;
-	((struct net_local *) nl->master->priv)->stats.rx_bytes += nl->inppos;
+	++((struct net_local *)netdev_priv(nl->master))->stats.rx_packets;
+	((struct net_local *)netdev_priv(nl->master))->stats.rx_bytes +=
+		nl->inppos;
 #else
 	skb->protocol = eth_type_trans( skb, dev );
 	netif_rx( skb );
-	dev->last_rx = jiffies;
 	++nl->stats.rx_packets;
 	nl->stats.rx_bytes += nl->inppos;
 #endif
@@ -1038,7 +1041,7 @@
 sbni_watchdog( unsigned long  arg )
 {
 	struct net_device  *dev = (struct net_device *) arg;
-	struct net_local   *nl  = (struct net_local *) dev->priv;
+	struct net_local   *nl  = netdev_priv(dev);
 	struct timer_list  *w   = &nl->watchdog; 
 	unsigned long	   flags;
 	unsigned char	   csr0;
@@ -1091,7 +1094,7 @@
 static void
 card_start( struct net_device  *dev )
 {
-	struct net_local  *nl = (struct net_local *) dev->priv;
+	struct net_local  *nl = netdev_priv(dev);
 
 	nl->timer_ticks = CHANGE_LEVEL_START_TICKS;
 	nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
@@ -1113,7 +1116,7 @@
 static void
 change_level( struct net_device  *dev )
 {
-	struct net_local  *nl = (struct net_local *) dev->priv;
+	struct net_local  *nl = netdev_priv(dev);
 
 	if( nl->delta_rxl == 0 )	/* do not auto-negotiate RxL */
 		return;
@@ -1137,7 +1140,7 @@
 static void
 timeout_change_level( struct net_device  *dev )
 {
-	struct net_local  *nl = (struct net_local *) dev->priv;
+	struct net_local  *nl = netdev_priv(dev);
 
 	nl->cur_rxl_index = timeout_rxl_tab[ nl->timeout_rxl ];
 	if( ++nl->timeout_rxl >= 4 )
@@ -1160,7 +1163,7 @@
 static int
 sbni_open( struct net_device  *dev )
 {
-	struct net_local	*nl = (struct net_local *) dev->priv;
+	struct net_local	*nl = netdev_priv(dev);
 	struct timer_list	*w  = &nl->watchdog;
 
 	/*
@@ -1176,7 +1179,7 @@
 				 ||  (*p)->base_addr == dev->base_addr - 4)
 			    &&  (*p)->flags & IFF_UP ) {
 
-				((struct net_local *) ((*p)->priv))
+				((struct net_local *) (netdev_priv(*p)))
 					->second = dev;
 				printk( KERN_NOTICE "%s: using shared irq "
 					"with %s\n", dev->name, (*p)->name );
@@ -1216,7 +1219,7 @@
 static int
 sbni_close( struct net_device  *dev )
 {
-	struct net_local  *nl = (struct net_local *) dev->priv;
+	struct net_local  *nl = netdev_priv(dev);
 
 	if( nl->second  &&  nl->second->flags & IFF_UP ) {
 		printk( KERN_NOTICE "Secondary channel (%s) is active!\n",
@@ -1300,7 +1303,7 @@
 static int
 sbni_ioctl( struct net_device  *dev,  struct ifreq  *ifr,  int  cmd )
 {
-	struct net_local  *nl = (struct net_local *) dev->priv; 
+	struct net_local  *nl = netdev_priv(dev);
 	struct sbni_flags  flags;
 	int  error = 0;
 
@@ -1390,8 +1393,8 @@
 static int
 enslave( struct net_device  *dev,  struct net_device  *slave_dev )
 {
-	struct net_local  *nl  = (struct net_local *) dev->priv;
-	struct net_local  *snl = (struct net_local *) slave_dev->priv;
+	struct net_local  *nl  = netdev_priv(dev);
+	struct net_local  *snl = netdev_priv(slave_dev);
 
 	if( nl->state & FL_SLAVE )	/* This isn't master or free device */
 		return  -EBUSY;
@@ -1425,9 +1428,9 @@
 static int
 emancipate( struct net_device  *dev )
 {
-	struct net_local   *snl = (struct net_local *) dev->priv;
+	struct net_local   *snl = netdev_priv(dev);
 	struct net_device  *p   = snl->master;
-	struct net_local   *nl  = (struct net_local *) p->priv;
+	struct net_local   *nl  = netdev_priv(p);
 
 	if( !(snl->state & FL_SLAVE) )
 		return  -EINVAL;
@@ -1438,7 +1441,7 @@
 
 	/* exclude from list */
 	for(;;) {	/* must be in list */
-		struct net_local  *t = (struct net_local *) p->priv;
+		struct net_local  *t = netdev_priv(p);
 		if( t->link == dev ) {
 			t->link = snl->link;
 			break;
@@ -1465,7 +1468,7 @@
 static struct net_device_stats *
 sbni_get_stats( struct net_device  *dev )
 {
-	return  &((struct net_local *) dev->priv)->stats;
+	return  &((struct net_local *)netdev_priv(dev))->stats;
 }
 
 
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 73e2f27..6a07ba9 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -185,7 +185,7 @@
 {
 	struct frad_local *flp;
 
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 	switch(flp->type)
 	{
 		case SDLA_S502A:
@@ -212,7 +212,7 @@
 {
 	struct frad_local *flp;
 
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 	switch(flp->type)
 	{
 		case SDLA_S502A:
@@ -432,7 +432,7 @@
 	int                      ret, waiting, len;
 	long                     window;
 
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 	window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;
 	cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));
 	ret = 0;
@@ -509,7 +509,7 @@
 	struct frad_local *flp;
 	int i;
 
-	flp = slave->priv;
+	flp = netdev_priv(slave);
 
 	for(i=0;i<CONFIG_DLCI_MAX;i++)
 		if (flp->master[i] == master)
@@ -531,7 +531,7 @@
 	struct frad_local *flp;
 	int               i;
 
-	flp = slave->priv;
+	flp = netdev_priv(slave);
 
 	for(i=0;i<CONFIG_DLCI_MAX;i++)
 		if (flp->master[i] == master)
@@ -556,7 +556,7 @@
 	if (master->type != ARPHRD_DLCI)
 		return(-EINVAL);
 
-	flp = slave->priv;
+	flp = netdev_priv(slave);
 
 	for(i=0;i<CONFIG_DLCI_MAX;i++)
 	{
@@ -589,7 +589,7 @@
 	struct frad_local *flp;
 	int               i;
 
-	flp = slave->priv;
+	flp = netdev_priv(slave);
 
 	for(i=0;i<CONFIG_DLCI_MAX;i++)
 		if (flp->master[i] == master)
@@ -619,7 +619,7 @@
 	int               i;
 	short             len, ret;
 
-	flp = slave->priv;
+	flp = netdev_priv(slave);
 
 	for(i=0;i<CONFIG_DLCI_MAX;i++)
 		if (flp->master[i] == master)
@@ -628,7 +628,7 @@
 	if (i == CONFIG_DLCI_MAX)
 		return(-ENODEV);
 
-	dlp = master->priv;
+	dlp = netdev_priv(master);
 
 	ret = SDLA_RET_OK;
 	len = sizeof(struct dlci_conf);
@@ -659,7 +659,7 @@
 	unsigned long     flags;
 	struct buf_entry  *pbuf;
 
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 	ret = 0;
 	accept = 1;
 
@@ -755,7 +755,7 @@
 	int               i=0, received, success, addr, buf_base, buf_top;
 	short             dlci, len, len2, split;
 
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 	success = 1;
 	received = addr = buf_top = buf_base = 0;
 	len = dlci = 0;
@@ -860,7 +860,7 @@
 	if (success)
 	{
 		flp->stats.rx_packets++;
-		dlp = master->priv;
+		dlp = netdev_priv(master);
 		(*dlp->receive)(skb, master);
 	}
 
@@ -925,7 +925,7 @@
 	struct frad_local *flp;
 
 	dev = (struct net_device *) device;
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 
 	if (sdla_byte(dev, SDLA_502_RCV_BUF))
 		sdla_receive(dev);
@@ -941,7 +941,7 @@
 	int               len, i;
 	short             dlcis[CONFIG_DLCI_MAX];
 
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 
 	len = 0;
 	for(i=0;i<CONFIG_DLCI_MAX;i++)
@@ -1002,7 +1002,7 @@
 	int               len, i;
 	char              byte;
 
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 
 	if (!flp->initialized)
 		return(-EPERM);
@@ -1079,7 +1079,7 @@
 	for(i=0;i<CONFIG_DLCI_MAX;i++)
 		if (flp->dlci[i])
 		{
-			dlp = flp->master[i]->priv;
+			dlp = netdev_priv(flp->master[i]);
 			if (dlp->configured)
 				sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL);
 		}
@@ -1099,7 +1099,7 @@
 	if (dev->type == 0xFFFF)
 		return(-EUNATCH);
 
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 
 	if (!get)
 	{
@@ -1230,7 +1230,7 @@
 	struct conf_data  data;
 	int               i, len;
 
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 
 	len = 0;
 	for(i=0;i<CONFIG_DLCI_MAX;i++)
@@ -1255,7 +1255,7 @@
 	if(!capable(CAP_NET_ADMIN))
 		return -EPERM;
 		
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 
 	if (!flp->initialized)
 		return(-EINVAL);
@@ -1321,7 +1321,7 @@
 {
 	struct frad_local *flp;
 
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 
 	if (netif_running(dev))
 		return(-EBUSY);
@@ -1338,7 +1338,7 @@
 	unsigned base;
 	int err = -EINVAL;
 
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 
 	if (flp->initialized)
 		return(-EINVAL);
@@ -1593,14 +1593,14 @@
 static struct net_device_stats *sdla_stats(struct net_device *dev)
 {
 	struct frad_local *flp;
-	flp = dev->priv;
+	flp = netdev_priv(dev);
 
 	return(&flp->stats);
 }
 
 static void setup_sdla(struct net_device *dev)
 {
-	struct frad_local *flp = dev->priv;
+	struct frad_local *flp = netdev_priv(dev);
 
 	netdev_boot_setup_check(dev);
 
@@ -1651,7 +1651,7 @@
 
 static void __exit exit_sdla(void)
 {
-	struct frad_local *flp = sdla->priv;
+	struct frad_local *flp = netdev_priv(sdla);
 
 	unregister_netdev(sdla);
 	if (flp->initialized) {
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index c023584..0941a26 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -68,7 +68,6 @@
 	skb_reset_mac_header(skb);
 	skb->dev = c->netdevice;
 	netif_rx(skb);
-	c->netdevice->last_rx = jiffies;
 }
 
 /*
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
deleted file mode 100644
index 6e92f7b..0000000
--- a/drivers/net/wan/syncppp.c
+++ /dev/null
@@ -1,1480 +0,0 @@
-/*
- *	NET3:	A (fairly minimal) implementation of synchronous PPP for Linux
- *		as well as a CISCO HDLC implementation. See the copyright 
- *		message below for the original source.
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License
- *	as published by the Free Software Foundation; either version
- *	2 of the license, or (at your option) any later version.
- *
- *	Note however. This code is also used in a different form by FreeBSD.
- *	Therefore when making any non OS specific change please consider
- *	contributing it back to the original author under the terms
- *	below in addition.
- *		-- Alan
- *
- *	Port for Linux-2.1 by Jan "Yenya" Kasprzak <kas@fi.muni.cz>
- */
-
-/*
- * Synchronous PPP/Cisco link level subroutines.
- * Keepalive protocol implemented in both Cisco and PPP modes.
- *
- * Copyright (C) 1994 Cronyx Ltd.
- * Author: Serge Vakulenko, <vak@zebub.msk.su>
- *
- * This software is distributed with NO WARRANTIES, not even the implied
- * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Authors grant any other persons or organisations permission to use
- * or modify this software as long as this message is kept with the software,
- * all derivative works or modified versions.
- *
- * Version 1.9, Wed Oct  4 18:58:15 MSK 1995
- *
- * $Id: syncppp.c,v 1.18 2000/04/11 05:25:31 asj Exp $
- */
-#undef DEBUG
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <linux/route.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/random.h>
-#include <linux/pkt_sched.h>
-#include <linux/spinlock.h>
-#include <linux/rcupdate.h>
-
-#include <net/net_namespace.h>
-#include <net/syncppp.h>
-
-#include <asm/byteorder.h>
-#include <asm/uaccess.h>
-
-#define MAXALIVECNT     6               /* max. alive packets */
-
-#define PPP_ALLSTATIONS 0xff            /* All-Stations broadcast address */
-#define PPP_UI          0x03            /* Unnumbered Information */
-#define PPP_IP          0x0021          /* Internet Protocol */
-#define PPP_ISO         0x0023          /* ISO OSI Protocol */
-#define PPP_XNS         0x0025          /* Xerox NS Protocol */
-#define PPP_IPX         0x002b          /* Novell IPX Protocol */
-#define PPP_LCP         0xc021          /* Link Control Protocol */
-#define PPP_IPCP        0x8021          /* Internet Protocol Control Protocol */
-
-#define LCP_CONF_REQ    1               /* PPP LCP configure request */
-#define LCP_CONF_ACK    2               /* PPP LCP configure acknowledge */
-#define LCP_CONF_NAK    3               /* PPP LCP configure negative ack */
-#define LCP_CONF_REJ    4               /* PPP LCP configure reject */
-#define LCP_TERM_REQ    5               /* PPP LCP terminate request */
-#define LCP_TERM_ACK    6               /* PPP LCP terminate acknowledge */
-#define LCP_CODE_REJ    7               /* PPP LCP code reject */
-#define LCP_PROTO_REJ   8               /* PPP LCP protocol reject */
-#define LCP_ECHO_REQ    9               /* PPP LCP echo request */
-#define LCP_ECHO_REPLY  10              /* PPP LCP echo reply */
-#define LCP_DISC_REQ    11              /* PPP LCP discard request */
-
-#define LCP_OPT_MRU             1       /* maximum receive unit */
-#define LCP_OPT_ASYNC_MAP       2       /* async control character map */
-#define LCP_OPT_AUTH_PROTO      3       /* authentication protocol */
-#define LCP_OPT_QUAL_PROTO      4       /* quality protocol */
-#define LCP_OPT_MAGIC           5       /* magic number */
-#define LCP_OPT_RESERVED        6       /* reserved */
-#define LCP_OPT_PROTO_COMP      7       /* protocol field compression */
-#define LCP_OPT_ADDR_COMP       8       /* address/control field compression */
-
-#define IPCP_CONF_REQ   LCP_CONF_REQ    /* PPP IPCP configure request */
-#define IPCP_CONF_ACK   LCP_CONF_ACK    /* PPP IPCP configure acknowledge */
-#define IPCP_CONF_NAK   LCP_CONF_NAK    /* PPP IPCP configure negative ack */
-#define IPCP_CONF_REJ   LCP_CONF_REJ    /* PPP IPCP configure reject */
-#define IPCP_TERM_REQ   LCP_TERM_REQ    /* PPP IPCP terminate request */
-#define IPCP_TERM_ACK   LCP_TERM_ACK    /* PPP IPCP terminate acknowledge */
-#define IPCP_CODE_REJ   LCP_CODE_REJ    /* PPP IPCP code reject */
-
-#define CISCO_MULTICAST         0x8f    /* Cisco multicast address */
-#define CISCO_UNICAST           0x0f    /* Cisco unicast address */
-#define CISCO_KEEPALIVE         0x8035  /* Cisco keepalive protocol */
-#define CISCO_ADDR_REQ          0       /* Cisco address request */
-#define CISCO_ADDR_REPLY        1       /* Cisco address reply */
-#define CISCO_KEEPALIVE_REQ     2       /* Cisco keepalive request */
-
-struct ppp_header {
-	u8 address;
-	u8 control;
-	__be16 protocol;
-};
-#define PPP_HEADER_LEN          sizeof (struct ppp_header)
-
-struct lcp_header {
-	u8 type;
-	u8 ident;
-	__be16 len;
-};
-#define LCP_HEADER_LEN          sizeof (struct lcp_header)
-
-struct cisco_packet {
-	__be32 type;
-	__be32 par1;
-	__be32 par2;
-	__be16 rel;
-	__be16 time0;
-	__be16 time1;
-};
-#define CISCO_PACKET_LEN 18
-#define CISCO_BIG_PACKET_LEN 20
-
-static struct sppp *spppq;
-static struct timer_list sppp_keepalive_timer;
-static DEFINE_SPINLOCK(spppq_lock);
-
-/* global xmit queue for sending packets while spinlock is held */
-static struct sk_buff_head tx_queue;
-
-static void sppp_keepalive (unsigned long dummy);
-static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,
-	u8 ident, u16 len, void *data);
-static void sppp_cisco_send (struct sppp *sp, int type, u32 par1, u32 par2);
-static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m);
-static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m);
-static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m);
-static void sppp_lcp_open (struct sppp *sp);
-static void sppp_ipcp_open (struct sppp *sp);
-static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
-	int len, u32 *magic);
-static void sppp_cp_timeout (unsigned long arg);
-static char *sppp_lcp_type_name (u8 type);
-static char *sppp_ipcp_type_name (u8 type);
-static void sppp_print_bytes (u8 *p, u16 len);
-
-static int debug;
-
-/* Flush global outgoing packet queue to dev_queue_xmit().
- *
- * dev_queue_xmit() must be called with interrupts enabled
- * which means it can't be called with spinlocks held.
- * If a packet needs to be sent while a spinlock is held,
- * then put the packet into tx_queue, and call sppp_flush_xmit()
- * after spinlock is released.
- */
-static void sppp_flush_xmit(void)
-{
-	struct sk_buff *skb;
-	while ((skb = skb_dequeue(&tx_queue)) != NULL)
-		dev_queue_xmit(skb);
-}
-
-/*
- *	Interface down stub
- */	
-
-static void if_down(struct net_device *dev)
-{
-	struct sppp *sp = (struct sppp *)sppp_of(dev);
-
-	sp->pp_link_state=SPPP_LINK_DOWN;
-}
-
-/*
- * Timeout routine activations.
- */
-
-static void sppp_set_timeout(struct sppp *p,int s) 
-{
-	if (! (p->pp_flags & PP_TIMO)) 
-	{
-		init_timer(&p->pp_timer);
-		p->pp_timer.function=sppp_cp_timeout;
-		p->pp_timer.expires=jiffies+s*HZ;
-		p->pp_timer.data=(unsigned long)p;
-		p->pp_flags |= PP_TIMO;
-		add_timer(&p->pp_timer);
-	}
-}
-
-static void sppp_clear_timeout(struct sppp *p)
-{
-	if (p->pp_flags & PP_TIMO) 
-	{
-		del_timer(&p->pp_timer);
-		p->pp_flags &= ~PP_TIMO; 
-	}
-}
-
-/**
- *	sppp_input -	receive and process a WAN PPP frame
- *	@skb:	The buffer to process
- *	@dev:	The device it arrived on
- *
- *	This can be called directly by cards that do not have
- *	timing constraints but is normally called from the network layer
- *	after interrupt servicing to process frames queued via netif_rx().
- *
- *	We process the options in the card. If the frame is destined for
- *	the protocol stacks then it requeues the frame for the upper level
- *	protocol. If it is a control from it is processed and discarded
- *	here.
- */
- 
-static void sppp_input (struct net_device *dev, struct sk_buff *skb)
-{
-	struct ppp_header *h;
-	struct sppp *sp = (struct sppp *)sppp_of(dev);
-	unsigned long flags;
-
-	skb->dev=dev;
-	skb_reset_mac_header(skb);
-
-	if (!pskb_may_pull(skb, PPP_HEADER_LEN)) {
-		/* Too small packet, drop it. */
-		if (sp->pp_flags & PP_DEBUG)
-			printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n",
-				dev->name, skb->len);
-		kfree_skb(skb);
-		return;
-	}
-
-	/* Get PPP header. */
-	h = (struct ppp_header *)skb->data;
-	skb_pull(skb,sizeof(struct ppp_header));
-
-	spin_lock_irqsave(&sp->lock, flags);
-	
-	switch (h->address) {
-	default:        /* Invalid PPP packet. */
-		goto invalid;
-	case PPP_ALLSTATIONS:
-		if (h->control != PPP_UI)
-			goto invalid;
-		if (sp->pp_flags & PP_CISCO) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n",
-					dev->name,
-					h->address, h->control, ntohs (h->protocol));
-			goto drop;
-		}
-		switch (ntohs (h->protocol)) {
-		default:
-			if (sp->lcp.state == LCP_STATE_OPENED)
-				sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ,
-					++sp->pp_seq, skb->len + 2,
-					&h->protocol);
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n",
-					dev->name,
-					h->address, h->control, ntohs (h->protocol));
-			goto drop;
-		case PPP_LCP:
-			sppp_lcp_input (sp, skb);
-			goto drop;
-		case PPP_IPCP:
-			if (sp->lcp.state == LCP_STATE_OPENED)
-				sppp_ipcp_input (sp, skb);
-			else
-				printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n");
-			goto drop;
-		case PPP_IP:
-			if (sp->ipcp.state == IPCP_STATE_OPENED) {
-				if(sp->pp_flags&PP_DEBUG)
-					printk(KERN_DEBUG "Yow an IP frame.\n");
-				skb->protocol=htons(ETH_P_IP);
-				netif_rx(skb);
-				dev->last_rx = jiffies;
-				goto done;
-			}
-			break;
-#ifdef IPX
-		case PPP_IPX:
-			/* IPX IPXCP not implemented yet */
-			if (sp->lcp.state == LCP_STATE_OPENED) {
-				skb->protocol=htons(ETH_P_IPX);
-				netif_rx(skb);
-				dev->last_rx = jiffies;
-				goto done;
-			}
-			break;
-#endif
-		}
-		break;
-	case CISCO_MULTICAST:
-	case CISCO_UNICAST:
-		/* Don't check the control field here (RFC 1547). */
-		if (! (sp->pp_flags & PP_CISCO)) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n",
-					dev->name,
-					h->address, h->control, ntohs (h->protocol));
-			goto drop;
-		}
-		switch (ntohs (h->protocol)) {
-		default:
-			goto invalid;
-		case CISCO_KEEPALIVE:
-			sppp_cisco_input (sp, skb);
-			goto drop;
-#ifdef CONFIG_INET
-		case ETH_P_IP:
-			skb->protocol=htons(ETH_P_IP);
-			netif_rx(skb);
-			dev->last_rx = jiffies;
-			goto done;
-#endif
-#ifdef CONFIG_IPX
-		case ETH_P_IPX:
-			skb->protocol=htons(ETH_P_IPX);
-			netif_rx(skb);
-			dev->last_rx = jiffies;
-			goto done;
-#endif
-		}
-		break;
-	}
-	goto drop;
-
-invalid:
-	if (sp->pp_flags & PP_DEBUG)
-		printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n",
-			dev->name, h->address, h->control, ntohs (h->protocol));
-drop:
-	kfree_skb(skb);
-done:
-	spin_unlock_irqrestore(&sp->lock, flags);
-	sppp_flush_xmit();
-	return;
-}
-
-/*
- *	Handle transmit packets.
- */
- 
-static int sppp_hard_header(struct sk_buff *skb,
-			    struct net_device *dev, __u16 type,
-			    const void *daddr, const void *saddr,
-			    unsigned int len)
-{
-	struct sppp *sp = (struct sppp *)sppp_of(dev);
-	struct ppp_header *h;
-	skb_push(skb,sizeof(struct ppp_header));
-	h=(struct ppp_header *)skb->data;
-	if(sp->pp_flags&PP_CISCO)
-	{
-		h->address = CISCO_UNICAST;
-		h->control = 0;
-	}
-	else
-	{
-		h->address = PPP_ALLSTATIONS;
-		h->control = PPP_UI;
-	}
-	if(sp->pp_flags & PP_CISCO)
-	{
-		h->protocol = htons(type);
-	}
-	else switch(type)
-	{
-		case ETH_P_IP:
-			h->protocol = htons(PPP_IP);
-			break;
-		case ETH_P_IPX:
-			h->protocol = htons(PPP_IPX);
-			break;
-	}
-	return sizeof(struct ppp_header);
-}
-
-static const struct header_ops sppp_header_ops = {
-	.create = sppp_hard_header,
-};
-
-/*
- * Send keepalive packets, every 10 seconds.
- */
-
-static void sppp_keepalive (unsigned long dummy)
-{
-	struct sppp *sp;
-	unsigned long flags;
-
-	spin_lock_irqsave(&spppq_lock, flags);
-
-	for (sp=spppq; sp; sp=sp->pp_next) 
-	{
-		struct net_device *dev = sp->pp_if;
-
-		/* Keepalive mode disabled or channel down? */
-		if (! (sp->pp_flags & PP_KEEPALIVE) ||
-		    ! (dev->flags & IFF_UP))
-			continue;
-
-		spin_lock(&sp->lock);
-
-		/* No keepalive in PPP mode if LCP not opened yet. */
-		if (! (sp->pp_flags & PP_CISCO) &&
-		    sp->lcp.state != LCP_STATE_OPENED) {
-			spin_unlock(&sp->lock);
-			continue;
-		}
-
-		if (sp->pp_alivecnt == MAXALIVECNT) {
-			/* No keepalive packets got.  Stop the interface. */
-			printk (KERN_WARNING "%s: protocol down\n", dev->name);
-			if_down (dev);
-			if (! (sp->pp_flags & PP_CISCO)) {
-				/* Shut down the PPP link. */
-				sp->lcp.magic = jiffies;
-				sp->lcp.state = LCP_STATE_CLOSED;
-				sp->ipcp.state = IPCP_STATE_CLOSED;
-				sppp_clear_timeout (sp);
-				/* Initiate negotiation. */
-				sppp_lcp_open (sp);
-			}
-		}
-		if (sp->pp_alivecnt <= MAXALIVECNT)
-			++sp->pp_alivecnt;
-		if (sp->pp_flags & PP_CISCO)
-			sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
-				sp->pp_rseq);
-		else if (sp->lcp.state == LCP_STATE_OPENED) {
-			__be32 nmagic = htonl (sp->lcp.magic);
-			sp->lcp.echoid = ++sp->pp_seq;
-			sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ,
-				sp->lcp.echoid, 4, &nmagic);
-		}
-
-		spin_unlock(&sp->lock);
-	}
-	spin_unlock_irqrestore(&spppq_lock, flags);
-	sppp_flush_xmit();
-	sppp_keepalive_timer.expires=jiffies+10*HZ;
-	add_timer(&sppp_keepalive_timer);
-}
-
-/*
- * Handle incoming PPP Link Control Protocol packets.
- */
- 
-static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb)
-{
-	struct lcp_header *h;
-	struct net_device *dev = sp->pp_if;
-	int len = skb->len;
-	u8 *p, opt[6];
-	u32 rmagic = 0;
-
-	if (!pskb_may_pull(skb, sizeof(struct lcp_header))) {
-		if (sp->pp_flags & PP_DEBUG)
-			printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n",
-				dev->name, len);
-		return;
-	}
-	h = (struct lcp_header *)skb->data;
-	skb_pull(skb,sizeof(struct lcp_header *));
-	
-	if (sp->pp_flags & PP_DEBUG) 
-	{
-		char state = '?';
-		switch (sp->lcp.state) {
-		case LCP_STATE_CLOSED:   state = 'C'; break;
-		case LCP_STATE_ACK_RCVD: state = 'R'; break;
-		case LCP_STATE_ACK_SENT: state = 'S'; break;
-		case LCP_STATE_OPENED:   state = 'O'; break;
-		}
-		printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh",
-			dev->name, state, len,
-			sppp_lcp_type_name (h->type), h->ident, ntohs (h->len));
-		if (len > 4)
-			sppp_print_bytes ((u8*) (h+1), len-4);
-		printk (">\n");
-	}
-	if (len > ntohs (h->len))
-		len = ntohs (h->len);
-	switch (h->type) {
-	default:
-		/* Unknown packet type -- send Code-Reject packet. */
-		sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq,
-			skb->len, h);
-		break;
-	case LCP_CONF_REQ:
-		if (len < 4) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n",
-					dev->name, len);
-			break;
-		}
-		if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic))
-			goto badreq;
-		if (rmagic == sp->lcp.magic) {
-			/* Local and remote magics equal -- loopback? */
-			if (sp->pp_loopcnt >= MAXALIVECNT*5) {
-				printk (KERN_WARNING "%s: loopback\n",
-					dev->name);
-				sp->pp_loopcnt = 0;
-				if (dev->flags & IFF_UP) {
-					if_down (dev);
-				}
-			} else if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_DEBUG "%s: conf req: magic glitch\n",
-					dev->name);
-			++sp->pp_loopcnt;
-
-			/* MUST send Conf-Nack packet. */
-			rmagic = ~sp->lcp.magic;
-			opt[0] = LCP_OPT_MAGIC;
-			opt[1] = sizeof (opt);
-			opt[2] = rmagic >> 24;
-			opt[3] = rmagic >> 16;
-			opt[4] = rmagic >> 8;
-			opt[5] = rmagic;
-			sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK,
-				h->ident, sizeof (opt), &opt);
-badreq:
-			switch (sp->lcp.state) {
-			case LCP_STATE_OPENED:
-				/* Initiate renegotiation. */
-				sppp_lcp_open (sp);
-				/* fall through... */
-			case LCP_STATE_ACK_SENT:
-				/* Go to closed state. */
-				sp->lcp.state = LCP_STATE_CLOSED;
-				sp->ipcp.state = IPCP_STATE_CLOSED;
-			}
-			break;
-		}
-		/* Send Configure-Ack packet. */
-		sp->pp_loopcnt = 0;
-		if (sp->lcp.state != LCP_STATE_OPENED) {
-			sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
-					h->ident, len-4, h+1);
-		}
-		/* Change the state. */
-		switch (sp->lcp.state) {
-		case LCP_STATE_CLOSED:
-			sp->lcp.state = LCP_STATE_ACK_SENT;
-			break;
-		case LCP_STATE_ACK_RCVD:
-			sp->lcp.state = LCP_STATE_OPENED;
-			sppp_ipcp_open (sp);
-			break;
-		case LCP_STATE_OPENED:
-			/* Remote magic changed -- close session. */
-			sp->lcp.state = LCP_STATE_CLOSED;
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-			/* Initiate renegotiation. */
-			sppp_lcp_open (sp);
-			/* Send ACK after our REQ in attempt to break loop */
-			sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
-					h->ident, len-4, h+1);
-			sp->lcp.state = LCP_STATE_ACK_SENT;
-			break;
-		}
-		break;
-	case LCP_CONF_ACK:
-		if (h->ident != sp->lcp.confid)
-			break;
-		sppp_clear_timeout (sp);
-		if ((sp->pp_link_state != SPPP_LINK_UP) &&
-		    (dev->flags & IFF_UP)) {
-			/* Coming out of loopback mode. */
-			sp->pp_link_state=SPPP_LINK_UP;
-			printk (KERN_INFO "%s: protocol up\n", dev->name);
-		}
-		switch (sp->lcp.state) {
-		case LCP_STATE_CLOSED:
-			sp->lcp.state = LCP_STATE_ACK_RCVD;
-			sppp_set_timeout (sp, 5);
-			break;
-		case LCP_STATE_ACK_SENT:
-			sp->lcp.state = LCP_STATE_OPENED;
-			sppp_ipcp_open (sp);
-			break;
-		}
-		break;
-	case LCP_CONF_NAK:
-		if (h->ident != sp->lcp.confid)
-			break;
-		p = (u8*) (h+1);
-		if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) {
-			rmagic = (u32)p[2] << 24 |
-				(u32)p[3] << 16 | p[4] << 8 | p[5];
-			if (rmagic == ~sp->lcp.magic) {
-				int newmagic;
-				if (sp->pp_flags & PP_DEBUG)
-					printk (KERN_DEBUG "%s: conf nak: magic glitch\n",
-						dev->name);
-				get_random_bytes(&newmagic, sizeof(newmagic));
-				sp->lcp.magic += newmagic;
-			} else
-				sp->lcp.magic = rmagic;
-			}
-		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
-			/* Go to closed state. */
-			sp->lcp.state = LCP_STATE_CLOSED;
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-		}
-		/* The link will be renegotiated after timeout,
-		 * to avoid endless req-nack loop. */
-		sppp_clear_timeout (sp);
-		sppp_set_timeout (sp, 2);
-		break;
-	case LCP_CONF_REJ:
-		if (h->ident != sp->lcp.confid)
-			break;
-		sppp_clear_timeout (sp);
-		/* Initiate renegotiation. */
-		sppp_lcp_open (sp);
-		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
-			/* Go to closed state. */
-			sp->lcp.state = LCP_STATE_CLOSED;
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-		}
-		break;
-	case LCP_TERM_REQ:
-		sppp_clear_timeout (sp);
-		/* Send Terminate-Ack packet. */
-		sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, NULL);
-		/* Go to closed state. */
-		sp->lcp.state = LCP_STATE_CLOSED;
-		sp->ipcp.state = IPCP_STATE_CLOSED;
-		/* Initiate renegotiation. */
-		sppp_lcp_open (sp);
-		break;
-	case LCP_TERM_ACK:
-	case LCP_CODE_REJ:
-	case LCP_PROTO_REJ:
-		/* Ignore for now. */
-		break;
-	case LCP_DISC_REQ:
-		/* Discard the packet. */
-		break;
-	case LCP_ECHO_REQ:
-		if (sp->lcp.state != LCP_STATE_OPENED)
-			break;
-		if (len < 8) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n",
-					dev->name, len);
-			break;
-		}
-		if (ntohl (*(__be32*)(h+1)) == sp->lcp.magic) {
-			/* Line loopback mode detected. */
-			printk (KERN_WARNING "%s: loopback\n", dev->name);
-			if_down (dev);
-
-			/* Shut down the PPP link. */
-			sp->lcp.state = LCP_STATE_CLOSED;
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-			sppp_clear_timeout (sp);
-			/* Initiate negotiation. */
-			sppp_lcp_open (sp);
-			break;
-		}
-		*(__be32 *)(h+1) = htonl (sp->lcp.magic);
-		sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1);
-		break;
-	case LCP_ECHO_REPLY:
-		if (h->ident != sp->lcp.echoid)
-			break;
-		if (len < 8) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n",
-					dev->name, len);
-			break;
-		}
-		if (ntohl(*(__be32 *)(h+1)) != sp->lcp.magic)
-		sp->pp_alivecnt = 0;
-		break;
-	}
-}
-
-/*
- * Handle incoming Cisco keepalive protocol packets.
- */
-
-static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
-{
-	struct cisco_packet *h;
-	struct net_device *dev = sp->pp_if;
-
-	if (!pskb_may_pull(skb, sizeof(struct cisco_packet))
-	    || (skb->len != CISCO_PACKET_LEN
-		&& skb->len != CISCO_BIG_PACKET_LEN)) {
-		if (sp->pp_flags & PP_DEBUG)
-			printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n",
-				dev->name,  skb->len);
-		return;
-	}
-	h = (struct cisco_packet *)skb->data;
-	skb_pull(skb, sizeof(struct cisco_packet*));
-	if (sp->pp_flags & PP_DEBUG)
-		printk (KERN_WARNING "%s: cisco input: %d bytes <%xh %xh %xh %xh %xh-%xh>\n",
-			dev->name,  skb->len,
-			ntohl (h->type), h->par1, h->par2, h->rel,
-			h->time0, h->time1);
-	switch (ntohl (h->type)) {
-	default:
-		if (sp->pp_flags & PP_DEBUG)
-			printk (KERN_WARNING "%s: unknown cisco packet type: 0x%x\n",
-				dev->name,  ntohl (h->type));
-		break;
-	case CISCO_ADDR_REPLY:
-		/* Reply on address request, ignore */
-		break;
-	case CISCO_KEEPALIVE_REQ:
-		sp->pp_alivecnt = 0;
-		sp->pp_rseq = ntohl (h->par1);
-		if (sp->pp_seq == sp->pp_rseq) {
-			/* Local and remote sequence numbers are equal.
-			 * Probably, the line is in loopback mode. */
-			int newseq;
-			if (sp->pp_loopcnt >= MAXALIVECNT) {
-				printk (KERN_WARNING "%s: loopback\n",
-					dev->name);
-				sp->pp_loopcnt = 0;
-				if (dev->flags & IFF_UP) {
-					if_down (dev);
-				}
-			}
-			++sp->pp_loopcnt;
-
-			/* Generate new local sequence number */
-			get_random_bytes(&newseq, sizeof(newseq));
-			sp->pp_seq ^= newseq;
-			break;
-		}
-		sp->pp_loopcnt = 0;
-		if (sp->pp_link_state==SPPP_LINK_DOWN &&
-		    (dev->flags & IFF_UP)) {
-			sp->pp_link_state=SPPP_LINK_UP;
-			printk (KERN_INFO "%s: protocol up\n", dev->name);
-		}
-		break;
-	case CISCO_ADDR_REQ:
-		/* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */
-		{
-		__be32 addr = 0, mask = htonl(~0U); /* FIXME: is the mask correct? */
-#ifdef CONFIG_INET
-		struct in_device *in_dev;
-		struct in_ifaddr *ifa;
-
-		rcu_read_lock();
-		if ((in_dev = __in_dev_get_rcu(dev)) != NULL)
-		{
-			for (ifa=in_dev->ifa_list; ifa != NULL;
-				ifa=ifa->ifa_next) {
-				if (strcmp(dev->name, ifa->ifa_label) == 0) 
-				{
-					addr = ifa->ifa_local;
-					mask = ifa->ifa_mask;
-					break;
-				}
-			}
-		}
-		rcu_read_unlock();
-#endif		
-		sppp_cisco_send (sp, CISCO_ADDR_REPLY, ntohl(addr), ntohl(mask));
-		break;
-		}
-	}
-}
-
-
-/*
- * Send PPP LCP packet.
- */
-
-static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,
-	u8 ident, u16 len, void *data)
-{
-	struct ppp_header *h;
-	struct lcp_header *lh;
-	struct sk_buff *skb;
-	struct net_device *dev = sp->pp_if;
-
-	skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len,
-		GFP_ATOMIC);
-	if (skb==NULL)
-		return;
-
-	skb_reserve(skb,dev->hard_header_len);
-	
-	h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header));
-	h->address = PPP_ALLSTATIONS;        /* broadcast address */
-	h->control = PPP_UI;                 /* Unnumbered Info */
-	h->protocol = htons (proto);         /* Link Control Protocol */
-
-	lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header));
-	lh->type = type;
-	lh->ident = ident;
-	lh->len = htons (LCP_HEADER_LEN + len);
-
-	if (len)
-		memcpy(skb_put(skb,len),data, len);
-
-	if (sp->pp_flags & PP_DEBUG) {
-		printk (KERN_WARNING "%s: %s output <%s id=%xh len=%xh",
-			dev->name, 
-			proto==PPP_LCP ? "lcp" : "ipcp",
-			proto==PPP_LCP ? sppp_lcp_type_name (lh->type) :
-			sppp_ipcp_type_name (lh->type), lh->ident,
-			ntohs (lh->len));
-		if (len)
-			sppp_print_bytes ((u8*) (lh+1), len);
-		printk (">\n");
-	}
-	/* Control is high priority so it doesn't get queued behind data */
-	skb->priority=TC_PRIO_CONTROL;
-	skb->dev = dev;
-	skb_queue_tail(&tx_queue, skb);
-}
-
-/*
- * Send Cisco keepalive packet.
- */
-
-static void sppp_cisco_send (struct sppp *sp, int type, u32 par1, u32 par2)
-{
-	struct ppp_header *h;
-	struct cisco_packet *ch;
-	struct sk_buff *skb;
-	struct net_device *dev = sp->pp_if;
-	u32 t = jiffies * 1000/HZ;
-
-	skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN,
-		GFP_ATOMIC);
-
-	if(skb==NULL)
-		return;
-		
-	skb_reserve(skb, dev->hard_header_len);
-	h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header));
-	h->address = CISCO_MULTICAST;
-	h->control = 0;
-	h->protocol = htons (CISCO_KEEPALIVE);
-
-	ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN);
-	ch->type = htonl (type);
-	ch->par1 = htonl (par1);
-	ch->par2 = htonl (par2);
-	ch->rel = htons(0xffff);
-	ch->time0 = htons ((u16) (t >> 16));
-	ch->time1 = htons ((u16) t);
-
-	if (sp->pp_flags & PP_DEBUG)
-		printk (KERN_WARNING "%s: cisco output: <%xh %xh %xh %xh %xh-%xh>\n",
-			dev->name,  ntohl (ch->type), ch->par1,
-			ch->par2, ch->rel, ch->time0, ch->time1);
-	skb->priority=TC_PRIO_CONTROL;
-	skb->dev = dev;
-	skb_queue_tail(&tx_queue, skb);
-}
-
-/**
- *	sppp_close - close down a synchronous PPP or Cisco HDLC link
- *	@dev: The network device to drop the link of
- *
- *	This drops the logical interface to the channel. It is not
- *	done politely as we assume we will also be dropping DTR. Any
- *	timeouts are killed.
- */
-
-int sppp_close (struct net_device *dev)
-{
-	struct sppp *sp = (struct sppp *)sppp_of(dev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&sp->lock, flags);
-	sp->pp_link_state = SPPP_LINK_DOWN;
-	sp->lcp.state = LCP_STATE_CLOSED;
-	sp->ipcp.state = IPCP_STATE_CLOSED;
-	sppp_clear_timeout (sp);
-	spin_unlock_irqrestore(&sp->lock, flags);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(sppp_close);
-
-/**
- *	sppp_open - open a synchronous PPP or Cisco HDLC link
- *	@dev:	Network device to activate
- *	
- *	Close down any existing synchronous session and commence
- *	from scratch. In the PPP case this means negotiating LCP/IPCP
- *	and friends, while for Cisco HDLC we simply need to start sending
- *	keepalives
- */
-
-int sppp_open (struct net_device *dev)
-{
-	struct sppp *sp = (struct sppp *)sppp_of(dev);
-	unsigned long flags;
-
-	sppp_close(dev);
-
-	spin_lock_irqsave(&sp->lock, flags);
-	if (!(sp->pp_flags & PP_CISCO)) {
-		sppp_lcp_open (sp);
-	}
-	sp->pp_link_state = SPPP_LINK_DOWN;
-	spin_unlock_irqrestore(&sp->lock, flags);
-	sppp_flush_xmit();
-
-	return 0;
-}
-
-EXPORT_SYMBOL(sppp_open);
-
-/**
- *	sppp_reopen - notify of physical link loss
- *	@dev: Device that lost the link
- *
- *	This function informs the synchronous protocol code that
- *	the underlying link died (for example a carrier drop on X.21)
- *
- *	We increment the magic numbers to ensure that if the other end
- *	failed to notice we will correctly start a new session. It happens
- *	do to the nature of telco circuits is that you can lose carrier on
- *	one endonly.
- *
- *	Having done this we go back to negotiating. This function may
- *	be called from an interrupt context.
- */
- 
-int sppp_reopen (struct net_device *dev)
-{
-	struct sppp *sp = (struct sppp *)sppp_of(dev);
-	unsigned long flags;
-
-	sppp_close(dev);
-
-	spin_lock_irqsave(&sp->lock, flags);
-	if (!(sp->pp_flags & PP_CISCO))
-	{
-		sp->lcp.magic = jiffies;
-		++sp->pp_seq;
-		sp->lcp.state = LCP_STATE_CLOSED;
-		sp->ipcp.state = IPCP_STATE_CLOSED;
-		/* Give it a moment for the line to settle then go */
-		sppp_set_timeout (sp, 1);
-	} 
-	sp->pp_link_state=SPPP_LINK_DOWN;
-	spin_unlock_irqrestore(&sp->lock, flags);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(sppp_reopen);
-
-/**
- *	sppp_change_mtu - Change the link MTU
- *	@dev:	Device to change MTU on
- *	@new_mtu: New MTU
- *
- *	Change the MTU on the link. This can only be called with
- *	the link down. It returns an error if the link is up or
- *	the mtu is out of range.
- */
- 
-static int sppp_change_mtu(struct net_device *dev, int new_mtu)
-{
-	if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP))
-		return -EINVAL;
-	dev->mtu=new_mtu;
-	return 0;
-}
-
-/**
- *	sppp_do_ioctl - Ioctl handler for ppp/hdlc
- *	@dev: Device subject to ioctl
- *	@ifr: Interface request block from the user
- *	@cmd: Command that is being issued
- *	
- *	This function handles the ioctls that may be issued by the user
- *	to control the settings of a PPP/HDLC link. It does both busy
- *	and security checks. This function is intended to be wrapped by
- *	callers who wish to add additional ioctl calls of their own.
- */
- 
-int sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	struct sppp *sp = (struct sppp *)sppp_of(dev);
-
-	if(dev->flags&IFF_UP)
-		return -EBUSY;
-		
-	if(!capable(CAP_NET_ADMIN))
-		return -EPERM;
-	
-	switch(cmd)
-	{
-		case SPPPIOCCISCO:
-			sp->pp_flags|=PP_CISCO;
-			dev->type = ARPHRD_HDLC;
-			break;
-		case SPPPIOCPPP:
-			sp->pp_flags&=~PP_CISCO;
-			dev->type = ARPHRD_PPP;
-			break;
-		case SPPPIOCDEBUG:
-			sp->pp_flags&=~PP_DEBUG;
-			if(ifr->ifr_flags)
-				sp->pp_flags|=PP_DEBUG;
-			break;
-		case SPPPIOCGFLAGS:
-			if(copy_to_user(ifr->ifr_data, &sp->pp_flags, sizeof(sp->pp_flags)))
-				return -EFAULT;
-			break;
-		case SPPPIOCSFLAGS:
-			if(copy_from_user(&sp->pp_flags, ifr->ifr_data, sizeof(sp->pp_flags)))
-				return -EFAULT;
-			break;
-		default:
-			return -EINVAL;
-	}
-	return 0;
-}
-
-EXPORT_SYMBOL(sppp_do_ioctl);
-
-/**
- *	sppp_attach - attach synchronous PPP/HDLC to a device
- *	@pd:	PPP device to initialise
- *
- *	This initialises the PPP/HDLC support on an interface. At the
- *	time of calling the dev element must point to the network device
- *	that this interface is attached to. The interface should not yet
- *	be registered. 
- */
- 
-void sppp_attach(struct ppp_device *pd)
-{
-	struct net_device *dev = pd->dev;
-	struct sppp *sp = &pd->sppp;
-	unsigned long flags;
-
-	/* Make sure embedding is safe for sppp_of */
-	BUG_ON(sppp_of(dev) != sp);
-
-	spin_lock_irqsave(&spppq_lock, flags);
-	/* Initialize keepalive handler. */
-	if (! spppq)
-	{
-		init_timer(&sppp_keepalive_timer);
-		sppp_keepalive_timer.expires=jiffies+10*HZ;
-		sppp_keepalive_timer.function=sppp_keepalive;
-		add_timer(&sppp_keepalive_timer);
-	}
-	/* Insert new entry into the keepalive list. */
-	sp->pp_next = spppq;
-	spppq = sp;
-	spin_unlock_irqrestore(&spppq_lock, flags);
-
-	sp->pp_loopcnt = 0;
-	sp->pp_alivecnt = 0;
-	sp->pp_seq = 0;
-	sp->pp_rseq = 0;
-	sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/
-	sp->lcp.magic = 0;
-	sp->lcp.state = LCP_STATE_CLOSED;
-	sp->ipcp.state = IPCP_STATE_CLOSED;
-	sp->pp_if = dev;
-	spin_lock_init(&sp->lock);
-	
-	/* 
-	 *	Device specific setup. All but interrupt handler and
-	 *	hard_start_xmit.
-	 */
-	 
-	dev->header_ops = &sppp_header_ops;
-
-	dev->tx_queue_len = 10;
-	dev->type = ARPHRD_HDLC;
-	dev->addr_len = 0;
-	dev->hard_header_len = sizeof(struct ppp_header);
-	dev->mtu = PPP_MTU;
-	/*
-	 *	These 4 are callers but MUST also call sppp_ functions
-	 */
-	dev->do_ioctl = sppp_do_ioctl;
-#if 0
-	dev->get_stats = NULL;		/* Let the driver override these */
-	dev->open = sppp_open;
-	dev->stop = sppp_close;
-#endif	
-	dev->change_mtu = sppp_change_mtu;
-	dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
-}
-
-EXPORT_SYMBOL(sppp_attach);
-
-/**
- *	sppp_detach - release PPP resources from a device
- *	@dev:	Network device to release
- *
- *	Stop and free up any PPP/HDLC resources used by this
- *	interface. This must be called before the device is
- *	freed.
- */
- 
-void sppp_detach (struct net_device *dev)
-{
-	struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&spppq_lock, flags);
-	/* Remove the entry from the keepalive list. */
-	for (q = &spppq; (p = *q); q = &p->pp_next)
-		if (p == sp) {
-			*q = p->pp_next;
-			break;
-		}
-
-	/* Stop keepalive handler. */
-	if (! spppq)
-		del_timer(&sppp_keepalive_timer);
-	sppp_clear_timeout (sp);
-	spin_unlock_irqrestore(&spppq_lock, flags);
-}
-
-EXPORT_SYMBOL(sppp_detach);
-
-/*
- * Analyze the LCP Configure-Request options list
- * for the presence of unknown options.
- * If the request contains unknown options, build and
- * send Configure-reject packet, containing only unknown options.
- */
-static int
-sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
-	int len, u32 *magic)
-{
-	u8 *buf, *r, *p;
-	int rlen;
-
-	len -= 4;
-	buf = r = kmalloc (len, GFP_ATOMIC);
-	if (! buf)
-		return (0);
-
-	p = (void*) (h+1);
-	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
-		switch (*p) {
-		case LCP_OPT_MAGIC:
-			/* Magic number -- extract. */
-			if (len >= 6 && p[1] == 6) {
-				*magic = (u32)p[2] << 24 |
-					(u32)p[3] << 16 | p[4] << 8 | p[5];
-				continue;
-			}
-			break;
-		case LCP_OPT_ASYNC_MAP:
-			/* Async control character map -- check to be zero. */
-			if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] &&
-			    ! p[4] && ! p[5])
-				continue;
-			break;
-		case LCP_OPT_MRU:
-			/* Maximum receive unit -- always OK. */
-			continue;
-		default:
-			/* Others not supported. */
-			break;
-		}
-		/* Add the option to rejected list. */
-		memcpy(r, p, p[1]);
-		r += p[1];
-		rlen += p[1];
-	}
-	if (rlen)
-		sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf);
-	kfree(buf);
-	return (rlen == 0);
-}
-
-static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb)
-{
-	struct lcp_header *h;
-	struct net_device *dev = sp->pp_if;
-	int len = skb->len;
-
-	if (!pskb_may_pull(skb, sizeof(struct lcp_header))) {
-		if (sp->pp_flags & PP_DEBUG)
-			printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n",
-				dev->name,  len);
-		return;
-	}
-	h = (struct lcp_header *)skb->data;
-	skb_pull(skb,sizeof(struct lcp_header));
-	if (sp->pp_flags & PP_DEBUG) {
-		printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh",
-			dev->name,  len,
-			sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len));
-		if (len > 4)
-			sppp_print_bytes ((u8*) (h+1), len-4);
-		printk (">\n");
-	}
-	if (len > ntohs (h->len))
-		len = ntohs (h->len);
-	switch (h->type) {
-	default:
-		/* Unknown packet type -- send Code-Reject packet. */
-		sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h);
-		break;
-	case IPCP_CONF_REQ:
-		if (len < 4) {
-			if (sp->pp_flags & PP_DEBUG)
-				printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n",
-					dev->name, len);
-			return;
-		}
-		if (len > 4) {
-			sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident,
-				len-4, h+1);
-
-			switch (sp->ipcp.state) {
-			case IPCP_STATE_OPENED:
-				/* Initiate renegotiation. */
-				sppp_ipcp_open (sp);
-				/* fall through... */
-			case IPCP_STATE_ACK_SENT:
-				/* Go to closed state. */
-				sp->ipcp.state = IPCP_STATE_CLOSED;
-			}
-		} else {
-			/* Send Configure-Ack packet. */
-			sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident,
-				0, NULL);
-			/* Change the state. */
-			if (sp->ipcp.state == IPCP_STATE_ACK_RCVD)
-				sp->ipcp.state = IPCP_STATE_OPENED;
-			else
-				sp->ipcp.state = IPCP_STATE_ACK_SENT;
-		}
-		break;
-	case IPCP_CONF_ACK:
-		if (h->ident != sp->ipcp.confid)
-			break;
-		sppp_clear_timeout (sp);
-		switch (sp->ipcp.state) {
-		case IPCP_STATE_CLOSED:
-			sp->ipcp.state = IPCP_STATE_ACK_RCVD;
-			sppp_set_timeout (sp, 5);
-			break;
-		case IPCP_STATE_ACK_SENT:
-			sp->ipcp.state = IPCP_STATE_OPENED;
-			break;
-		}
-		break;
-	case IPCP_CONF_NAK:
-	case IPCP_CONF_REJ:
-		if (h->ident != sp->ipcp.confid)
-			break;
-		sppp_clear_timeout (sp);
-			/* Initiate renegotiation. */
-		sppp_ipcp_open (sp);
-		if (sp->ipcp.state != IPCP_STATE_ACK_SENT)
-			/* Go to closed state. */
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-		break;
-	case IPCP_TERM_REQ:
-		/* Send Terminate-Ack packet. */
-		sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, NULL);
-		/* Go to closed state. */
-		sp->ipcp.state = IPCP_STATE_CLOSED;
-		/* Initiate renegotiation. */
-		sppp_ipcp_open (sp);
-		break;
-	case IPCP_TERM_ACK:
-		/* Ignore for now. */
-	case IPCP_CODE_REJ:
-		/* Ignore for now. */
-		break;
-	}
-}
-
-static void sppp_lcp_open (struct sppp *sp)
-{
-	char opt[6];
-
-	if (! sp->lcp.magic)
-		sp->lcp.magic = jiffies;
-	opt[0] = LCP_OPT_MAGIC;
-	opt[1] = sizeof (opt);
-	opt[2] = sp->lcp.magic >> 24;
-	opt[3] = sp->lcp.magic >> 16;
-	opt[4] = sp->lcp.magic >> 8;
-	opt[5] = sp->lcp.magic;
-	sp->lcp.confid = ++sp->pp_seq;
-	sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid,
-		sizeof (opt), &opt);
-	sppp_set_timeout (sp, 2);
-}
-
-static void sppp_ipcp_open (struct sppp *sp)
-{
-	sp->ipcp.confid = ++sp->pp_seq;
-	sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, NULL);
-	sppp_set_timeout (sp, 2);
-}
-
-/*
- * Process PPP control protocol timeouts.
- */
- 
-static void sppp_cp_timeout (unsigned long arg)
-{
-	struct sppp *sp = (struct sppp*) arg;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sp->lock, flags);
-
-	sp->pp_flags &= ~PP_TIMO;
-	if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) {
-		spin_unlock_irqrestore(&sp->lock, flags);
-		return;
-	}
-	switch (sp->lcp.state) {
-	case LCP_STATE_CLOSED:
-		/* No ACK for Configure-Request, retry. */
-		sppp_lcp_open (sp);
-		break;
-	case LCP_STATE_ACK_RCVD:
-		/* ACK got, but no Configure-Request for peer, retry. */
-		sppp_lcp_open (sp);
-		sp->lcp.state = LCP_STATE_CLOSED;
-		break;
-	case LCP_STATE_ACK_SENT:
-		/* ACK sent but no ACK for Configure-Request, retry. */
-		sppp_lcp_open (sp);
-		break;
-	case LCP_STATE_OPENED:
-		/* LCP is already OK, try IPCP. */
-		switch (sp->ipcp.state) {
-		case IPCP_STATE_CLOSED:
-			/* No ACK for Configure-Request, retry. */
-			sppp_ipcp_open (sp);
-			break;
-		case IPCP_STATE_ACK_RCVD:
-			/* ACK got, but no Configure-Request for peer, retry. */
-			sppp_ipcp_open (sp);
-			sp->ipcp.state = IPCP_STATE_CLOSED;
-			break;
-		case IPCP_STATE_ACK_SENT:
-			/* ACK sent but no ACK for Configure-Request, retry. */
-			sppp_ipcp_open (sp);
-			break;
-		case IPCP_STATE_OPENED:
-			/* IPCP is OK. */
-			break;
-		}
-		break;
-	}
-	spin_unlock_irqrestore(&sp->lock, flags);
-	sppp_flush_xmit();
-}
-
-static char *sppp_lcp_type_name (u8 type)
-{
-	static char buf [8];
-	switch (type) {
-	case LCP_CONF_REQ:   return ("conf-req");
-	case LCP_CONF_ACK:   return ("conf-ack");
-	case LCP_CONF_NAK:   return ("conf-nack");
-	case LCP_CONF_REJ:   return ("conf-rej");
-	case LCP_TERM_REQ:   return ("term-req");
-	case LCP_TERM_ACK:   return ("term-ack");
-	case LCP_CODE_REJ:   return ("code-rej");
-	case LCP_PROTO_REJ:  return ("proto-rej");
-	case LCP_ECHO_REQ:   return ("echo-req");
-	case LCP_ECHO_REPLY: return ("echo-reply");
-	case LCP_DISC_REQ:   return ("discard-req");
-	}
-	sprintf (buf, "%xh", type);
-	return (buf);
-}
-
-static char *sppp_ipcp_type_name (u8 type)
-{
-	static char buf [8];
-	switch (type) {
-	case IPCP_CONF_REQ:   return ("conf-req");
-	case IPCP_CONF_ACK:   return ("conf-ack");
-	case IPCP_CONF_NAK:   return ("conf-nack");
-	case IPCP_CONF_REJ:   return ("conf-rej");
-	case IPCP_TERM_REQ:   return ("term-req");
-	case IPCP_TERM_ACK:   return ("term-ack");
-	case IPCP_CODE_REJ:   return ("code-rej");
-	}
-	sprintf (buf, "%xh", type);
-	return (buf);
-}
-
-static void sppp_print_bytes (u_char *p, u16 len)
-{
-	printk (" %x", *p++);
-	while (--len > 0)
-		printk ("-%x", *p++);
-}
-
-/**
- *	sppp_rcv -	receive and process a WAN PPP frame
- *	@skb:	The buffer to process
- *	@dev:	The device it arrived on
- *	@p: Unused
- *	@orig_dev: Unused
- *
- *	Protocol glue. This drives the deferred processing mode the poorer
- *	cards use. This can be called directly by cards that do not have
- *	timing constraints but is normally called from the network layer
- *	after interrupt servicing to process frames queued via netif_rx.
- */
-
-static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev)
-{
-	if (dev_net(dev) != &init_net) {
-		kfree_skb(skb);
-		return 0;
-	}
-
-	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
-		return NET_RX_DROP;
-	sppp_input(dev,skb);
-	return 0;
-}
-
-static struct packet_type sppp_packet_type = {
-	.type	= __constant_htons(ETH_P_WAN_PPP),
-	.func	= sppp_rcv,
-};
-
-static char banner[] __initdata = 
-	KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"
-	KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & "
-		  "Jan \"Yenya\" Kasprzak.\n";
-
-static int __init sync_ppp_init(void)
-{
-	if(debug)
-		debug=PP_DEBUG;
-	printk(banner);
-	skb_queue_head_init(&tx_queue);
-	dev_add_pack(&sppp_packet_type);
-	return 0;
-}
-
-
-static void __exit sync_ppp_cleanup(void)
-{
-	dev_remove_pack(&sppp_packet_type);
-}
-
-module_init(sync_ppp_init);
-module_exit(sync_ppp_cleanup);
-module_param(debug, int, 0);
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index a8a5ca0..4bffb67 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -220,7 +220,6 @@
 #endif
 				dev->stats.rx_packets++;
 				dev->stats.rx_bytes += skb->len;
-				dev->last_rx = jiffies;
 				skb->protocol = hdlc_type_trans(skb, dev);
 				netif_rx(skb);
 				skb = NULL;
@@ -411,12 +410,12 @@
 	writel(1 << (DOORBELL_TO_CARD_OPEN_0 + port->node), dbr);
 
 	timeout = jiffies + HZ;
-	do
+	do {
 		if (get_status(port)->open) {
 			netif_start_queue(dev);
 			return 0;
 		}
-	while (time_after(timeout, jiffies));
+	} while (time_after(timeout, jiffies));
 
 	printk(KERN_ERR "%s: unable to open port\n", dev->name);
 	/* ask the card to close the port, should it be still alive */
@@ -438,10 +437,10 @@
 	       port->card->plx + PLX_DOORBELL_TO_CARD);
 
 	timeout = jiffies + HZ;
-	do
+	do {
 		if (!get_status(port)->open)
 			break;
-	while (time_after(timeout, jiffies));
+	} while (time_after(timeout, jiffies));
 
 	if (get_status(port)->open)
 		printk(KERN_ERR "%s: unable to close port\n", dev->name);
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 2a6c7a6..e6e2ce3 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -64,7 +64,7 @@
 		if (dev == NULL)
 			break;
 
-		sl = dev->priv;
+		sl = netdev_priv(dev);
 		/* Not in use ? */
 		if (!test_and_set_bit(SLF_INUSE, &sl->flags))
 			return sl;
@@ -86,7 +86,7 @@
 			return NULL;
 
 		/* Initialize channel control data */
-		sl = dev->priv;
+		sl = netdev_priv(dev);
 		dev->base_addr    = i;
 
 		/* register device so that it can be ifconfig'ed       */
@@ -120,7 +120,7 @@
 
 static int x25_asy_change_mtu(struct net_device *dev, int newmtu)
 {
-	struct x25_asy *sl = dev->priv;
+	struct x25_asy *sl = netdev_priv(dev);
 	unsigned char *xbuff, *rbuff;
 	int len = 2 * newmtu;
 
@@ -211,7 +211,6 @@
 		printk(KERN_DEBUG "x25_asy: data received err - %d\n", err);
 	} else {
 		netif_rx(skb);
-		sl->dev->last_rx = jiffies;
 		sl->stats.rx_packets++;
 	}
 }
@@ -243,7 +242,7 @@
 	 * if we did not request it before write operation.
 	 *       14 Oct 1994  Dmitry Gorodchanin.
 	 */
-	sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+	set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
 	actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
 	sl->xleft = count - actual;
 	sl->xhead = sl->xbuff + actual;
@@ -258,7 +257,7 @@
 static void x25_asy_write_wakeup(struct tty_struct *tty)
 {
 	int actual;
-	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
+	struct x25_asy *sl = tty->disc_data;
 
 	/* First make sure we're connected. */
 	if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
@@ -268,7 +267,7 @@
 		/* Now serial buffer is almost free & we can start
 		 * transmission of another packet */
 		sl->stats.tx_packets++;
-		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 		x25_asy_unlock(sl);
 		return;
 	}
@@ -280,7 +279,7 @@
 
 static void x25_asy_timeout(struct net_device *dev)
 {
-	struct x25_asy *sl = dev->priv;
+	struct x25_asy *sl = netdev_priv(dev);
 
 	spin_lock(&sl->lock);
 	if (netif_queue_stopped(dev)) {
@@ -291,7 +290,7 @@
 		       (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
 		       "bad line quality" : "driver error");
 		sl->xleft = 0;
-		sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+		clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
 		x25_asy_unlock(sl);
 	}
 	spin_unlock(&sl->lock);
@@ -301,7 +300,7 @@
 
 static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct x25_asy *sl = dev->priv;
+	struct x25_asy *sl = netdev_priv(dev);
 	int err;
 
 	if (!netif_running(sl->dev)) {
@@ -361,7 +360,6 @@
 
 static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb)
 {
-	skb->dev->last_rx = jiffies;
 	return netif_rx(skb);
 }
 
@@ -373,7 +371,7 @@
 
 static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb)
 {
-	struct x25_asy *sl = dev->priv;
+	struct x25_asy *sl = netdev_priv(dev);
 
 	spin_lock(&sl->lock);
 	if (netif_queue_stopped(sl->dev) || sl->tty == NULL) {
@@ -398,7 +396,7 @@
 
 static void x25_asy_connected(struct net_device *dev, int reason)
 {
-	struct x25_asy *sl = dev->priv;
+	struct x25_asy *sl = netdev_priv(dev);
 	struct sk_buff *skb;
 	unsigned char *ptr;
 
@@ -413,12 +411,11 @@
 
 	skb->protocol = x25_type_trans(skb, sl->dev);
 	netif_rx(skb);
-	sl->dev->last_rx = jiffies;
 }
 
 static void x25_asy_disconnected(struct net_device *dev, int reason)
 {
-	struct x25_asy *sl = dev->priv;
+	struct x25_asy *sl = netdev_priv(dev);
 	struct sk_buff *skb;
 	unsigned char *ptr;
 
@@ -433,7 +430,6 @@
 
 	skb->protocol = x25_type_trans(skb, sl->dev);
 	netif_rx(skb);
-	sl->dev->last_rx = jiffies;
 }
 
 static struct lapb_register_struct x25_asy_callbacks = {
@@ -450,7 +446,7 @@
 /* Open the low-level part of the X.25 channel. Easy! */
 static int x25_asy_open(struct net_device *dev)
 {
-	struct x25_asy *sl = dev->priv;
+	struct x25_asy *sl = netdev_priv(dev);
 	unsigned long len;
 	int err;
 
@@ -499,12 +495,12 @@
 /* Close the low-level part of the X.25 channel. Easy! */
 static int x25_asy_close(struct net_device *dev)
 {
-	struct x25_asy *sl = dev->priv;
+	struct x25_asy *sl = netdev_priv(dev);
 	int err;
 
 	spin_lock(&sl->lock);
 	if (sl->tty)
-		sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+		clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
 
 	netif_stop_queue(dev);
 	sl->rcount = 0;
@@ -527,7 +523,7 @@
 static void x25_asy_receive_buf(struct tty_struct *tty,
 				const unsigned char *cp, char *fp, int count)
 {
-	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
+	struct x25_asy *sl = tty->disc_data;
 
 	if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
 		return;
@@ -555,7 +551,7 @@
 
 static int x25_asy_open_tty(struct tty_struct *tty)
 {
-	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
+	struct x25_asy *sl = tty->disc_data;
 	int err;
 
 	if (tty->ops->write == NULL)
@@ -596,7 +592,7 @@
  */
 static void x25_asy_close_tty(struct tty_struct *tty)
 {
-	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
+	struct x25_asy *sl = tty->disc_data;
 
 	/* First make sure we're connected. */
 	if (!sl || sl->magic != X25_ASY_MAGIC)
@@ -615,7 +611,7 @@
 
 static struct net_device_stats *x25_asy_get_stats(struct net_device *dev)
 {
-	struct x25_asy *sl = dev->priv;
+	struct x25_asy *sl = netdev_priv(dev);
 	return &sl->stats;
 }
 
@@ -624,7 +620,7 @@
   *			STANDARD X.25 ENCAPSULATION		  	 *
   ************************************************************************/
 
-int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
+static int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
 {
 	unsigned char *ptr = d;
 	unsigned char c;
@@ -696,7 +692,7 @@
 static int x25_asy_ioctl(struct tty_struct *tty, struct file *file,
 			 unsigned int cmd,  unsigned long arg)
 {
-	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
+	struct x25_asy *sl = tty->disc_data;
 
 	/* First make sure we're connected. */
 	if (!sl || sl->magic != X25_ASY_MAGIC)
@@ -717,7 +713,7 @@
 
 static int x25_asy_open_dev(struct net_device *dev)
 {
-	struct x25_asy *sl = dev->priv;
+	struct x25_asy *sl = netdev_priv(dev);
 	if (sl->tty == NULL)
 		return -ENODEV;
 	return 0;
@@ -726,7 +722,7 @@
 /* Initialise the X.25 driver.  Called by the device init code */
 static void x25_asy_setup(struct net_device *dev)
 {
-	struct x25_asy *sl = dev->priv;
+	struct x25_asy *sl = netdev_priv(dev);
 
 	sl->magic  = X25_ASY_MAGIC;
 	sl->dev	   = dev;
@@ -793,7 +789,7 @@
 	for (i = 0; i < x25_asy_maxdev; i++) {
 		dev = x25_asy_devs[i];
 		if (dev) {
-			struct x25_asy *sl = dev->priv;
+			struct x25_asy *sl = netdev_priv(dev);
 
 			spin_lock_bh(&sl->lock);
 			if (sl->tty)
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 5bf7e01..3d00971 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -601,24 +601,18 @@
 	write_zsctrl(chan, RES_H_IUS);
 }
 
-struct z8530_irqhandler z8530_dma_sync=
-{
+static struct z8530_irqhandler z8530_dma_sync = {
 	z8530_dma_rx,
 	z8530_dma_tx,
 	z8530_dma_status
 };
 
-EXPORT_SYMBOL(z8530_dma_sync);
-
-struct z8530_irqhandler z8530_txdma_sync=
-{
+static struct z8530_irqhandler z8530_txdma_sync = {
 	z8530_rx,
 	z8530_dma_tx,
 	z8530_dma_status
 };
 
-EXPORT_SYMBOL(z8530_txdma_sync);
-
 /**
  *	z8530_rx_clear - Handle RX events from a stopped chip
  *	@c: Z8530 channel to shut up
@@ -710,7 +704,7 @@
 irqreturn_t z8530_interrupt(int irq, void *dev_id)
 {
 	struct z8530_dev *dev=dev_id;
-	u8 intr;
+	u8 uninitialized_var(intr);
 	static volatile int locker=0;
 	int work=0;
 	struct z8530_irqhandler *irqs;
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index fa14255..3c1edda 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -147,6 +147,20 @@
 }
 #endif
 
+static const struct net_device_ops wd_netdev_ops = {
+	.ndo_open		= wd_open,
+	.ndo_stop		= wd_close,
+	.ndo_start_xmit		= ei_start_xmit,
+	.ndo_tx_timeout		= ei_tx_timeout,
+	.ndo_get_stats		= ei_get_stats,
+	.ndo_set_multicast_list = ei_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller 	= ei_poll,
+#endif
+};
+
 static int __init wd_probe1(struct net_device *dev, int ioaddr)
 {
 	int i;
@@ -156,7 +170,6 @@
 	int word16 = 0;				/* 0 = 8 bit, 1 = 16 bit */
 	const char *model_name;
 	static unsigned version_printed;
-	DECLARE_MAC_BUF(mac);
 
 	for (i = 0; i < 8; i++)
 		checksum += inb(ioaddr + 8 + i);
@@ -178,8 +191,8 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(ioaddr + 8 + i);
 
-	printk("%s: WD80x3 at %#3x, %s",
-	       dev->name, ioaddr, print_mac(mac, dev->dev_addr));
+	printk("%s: WD80x3 at %#3x, %pM",
+	       dev->name, ioaddr, dev->dev_addr);
 
 	/* The following PureData probe code was contributed by
 	   Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
@@ -332,11 +345,8 @@
 	ei_status.block_input = &wd_block_input;
 	ei_status.block_output = &wd_block_output;
 	ei_status.get_8390_hdr = &wd_get_8390_hdr;
-	dev->open = &wd_open;
-	dev->stop = &wd_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	dev->poll_controller = ei_poll;
-#endif
+
+	dev->netdev_ops = &wd_netdev_ops;
 	NS8390_init(dev, 0);
 
 #if 1
@@ -366,8 +376,7 @@
 	  outb(ei_status.reg5, ioaddr+WD_CMDREG5);
   outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
 
-  ei_open(dev);
-  return 0;
+  return ei_open(dev);
 }
 
 static void
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 45bdf0b..ea543fc 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -123,154 +123,11 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called ray_cs.  If unsure, say N.
 
-config IPW2100
-	tristate "Intel PRO/Wireless 2100 Network Connection"
-	depends on PCI && WLAN_80211
-	select WIRELESS_EXT
-	select FW_LOADER
-	select IEEE80211
-	---help---
-          A driver for the Intel PRO/Wireless 2100 Network 
-	  Connection 802.11b wireless network adapter.
-
-          See <file:Documentation/networking/README.ipw2100> for information on
-          the capabilities currently enabled in this driver and for tips
-          for debugging issues and problems.
-
-	  In order to use this driver, you will need a firmware image for it.
-          You can obtain the firmware from
-	  <http://ipw2100.sf.net/>.  Once you have the firmware image, you 
-	  will need to place it in /lib/firmware.
-
-          You will also very likely need the Wireless Tools in order to
-          configure your card:
-
-          <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
-          It is recommended that you compile this driver as a module (M)
-          rather than built-in (Y). This driver requires firmware at device
-          initialization time, and when built-in this typically happens
-          before the filesystem is accessible (hence firmware will be
-          unavailable and initialization will fail). If you do choose to build
-          this driver into your kernel image, you can avoid this problem by
-          including the firmware and a firmware loader in an initramfs.
- 
-config IPW2100_MONITOR
-        bool "Enable promiscuous mode"
-        depends on IPW2100
-        ---help---
-	  Enables promiscuous/monitor mode support for the ipw2100 driver.
-	  With this feature compiled into the driver, you can switch to 
-	  promiscuous mode via the Wireless Tool's Monitor mode.  While in this
-	  mode, no packets can be sent.
-
-config IPW2100_DEBUG
-	bool "Enable full debugging output in IPW2100 module."
-	depends on IPW2100
-	---help---
-	  This option will enable debug tracing output for the IPW2100.  
-
-	  This will result in the kernel module being ~60k larger.  You can 
-	  control which debug output is sent to the kernel log by setting the 
-	  value in 
-
-	  /sys/bus/pci/drivers/ipw2100/debug_level
-
-	  This entry will only exist if this option is enabled.
-
-	  If you are not trying to debug or develop the IPW2100 driver, you 
-	  most likely want to say N here.
-
-config IPW2200
-	tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
-	depends on PCI && WLAN_80211
-	select WIRELESS_EXT
-	select FW_LOADER
-	select IEEE80211
-	---help---
-          A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
-	  Connection adapters. 
-
-          See <file:Documentation/networking/README.ipw2200> for 
-	  information on the capabilities currently enabled in this 
-	  driver and for tips for debugging issues and problems.
-
-	  In order to use this driver, you will need a firmware image for it.
-          You can obtain the firmware from
-	  <http://ipw2200.sf.net/>.  See the above referenced README.ipw2200 
-	  for information on where to install the firmware images.
-
-          You will also very likely need the Wireless Tools in order to
-          configure your card:
-
-          <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
-          It is recommended that you compile this driver as a module (M)
-          rather than built-in (Y). This driver requires firmware at device
-          initialization time, and when built-in this typically happens
-          before the filesystem is accessible (hence firmware will be
-          unavailable and initialization will fail). If you do choose to build
-          this driver into your kernel image, you can avoid this problem by
-          including the firmware and a firmware loader in an initramfs.
-
-config IPW2200_MONITOR
-        bool "Enable promiscuous mode"
-        depends on IPW2200
-        ---help---
-	  Enables promiscuous/monitor mode support for the ipw2200 driver.
-	  With this feature compiled into the driver, you can switch to 
-	  promiscuous mode via the Wireless Tool's Monitor mode.  While in this
-	  mode, no packets can be sent.
-
-config IPW2200_RADIOTAP
-	bool "Enable radiotap format 802.11 raw packet support"
-	depends on IPW2200_MONITOR
-
-config IPW2200_PROMISCUOUS
-	bool "Enable creation of a RF radiotap promiscuous interface"
-	depends on IPW2200_MONITOR
-	select IPW2200_RADIOTAP
-	---help---
-          Enables the creation of a second interface prefixed 'rtap'. 
-          This second interface will provide every received in radiotap
-	  format.
-
-          This is useful for performing wireless network analysis while
-          maintaining an active association.
-
-          Example usage:
-
-            % modprobe ipw2200 rtap_iface=1
-            % ifconfig rtap0 up
-            % tethereal -i rtap0
-
-          If you do not specify 'rtap_iface=1' as a module parameter then 
-          the rtap interface will not be created and you will need to turn 
-          it on via sysfs:
-	
-            % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface
-
-config IPW2200_QOS
-        bool "Enable QoS support"
-        depends on IPW2200 && EXPERIMENTAL
-
-config IPW2200_DEBUG
-	bool "Enable full debugging output in IPW2200 module."
-	depends on IPW2200
-	---help---
-	  This option will enable low level debug tracing output for IPW2200.
-
-	  Note, normal debug code is already compiled in. This low level
-	  debug option enables debug on hot paths (e.g Tx, Rx, ISR) and
-	  will result in the kernel module being ~70 larger.  Most users
-	  will typically not need this high verbosity debug information.
-
-	  If you are not sure, say N here.
-
 config LIBERTAS
 	tristate "Marvell 8xxx Libertas WLAN driver support"
 	depends on WLAN_80211
 	select WIRELESS_EXT
+	select LIB80211
 	select FW_LOADER
 	---help---
 	  A library for Marvell Libertas 8xxx devices.
@@ -357,6 +214,21 @@
 	  configure your card and that /etc/pcmcia/wireless.opts works :
 	  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
 
+config HERMES_CACHE_FW_ON_INIT
+	bool "Cache Hermes firmware on driver initialisation"
+	depends on HERMES
+	default y
+	---help---
+	  Say Y to cache any firmware required by the Hermes drivers
+	  on startup.  The firmware will remain cached until the
+	  driver is unloaded.  The cache uses 64K of RAM.
+
+	  Otherwise load the firmware from userspace as required.  In
+	  this case the driver should be unloaded and restarted
+	  whenever the firmware is changed.
+
+	  If you are not sure, say Y.
+
 config APPLE_AIRPORT
 	tristate "Apple Airport support (built-in)"
 	depends on PPC_PMAC && HERMES
@@ -651,7 +523,7 @@
 
 config RTL8187
 	tristate "Realtek 8187 and 8187B USB support"
-	depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
+	depends on MAC80211 && USB && WLAN_80211
 	select EEPROM_93CX6
 	---help---
 	  This is a driver for RTL8187 and RTL8187B based cards.
@@ -711,6 +583,7 @@
 source "drivers/net/wireless/p54/Kconfig"
 source "drivers/net/wireless/ath5k/Kconfig"
 source "drivers/net/wireless/ath9k/Kconfig"
+source "drivers/net/wireless/ipw2x00/Kconfig"
 source "drivers/net/wireless/iwlwifi/Kconfig"
 source "drivers/net/wireless/hostap/Kconfig"
 source "drivers/net/wireless/b43/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 59d2d80..ac590e1c 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -2,9 +2,8 @@
 # Makefile for the Linux Wireless network device drivers.
 #
 
-obj-$(CONFIG_IPW2100) += ipw2100.o
-
-obj-$(CONFIG_IPW2200) += ipw2200.o
+obj-$(CONFIG_IPW2100) += ipw2x00/
+obj-$(CONFIG_IPW2200) += ipw2x00/
 
 obj-$(CONFIG_STRIP) += strip.o
 obj-$(CONFIG_ARLAN) += arlan.o 
@@ -16,14 +15,7 @@
 obj-$(CONFIG_PCMCIA_NETWAVE)	+= netwave_cs.o
 obj-$(CONFIG_PCMCIA_WAVELAN)	+= wavelan_cs.o
 
-obj-$(CONFIG_HERMES)		+= orinoco.o hermes.o hermes_dld.o
-obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o
-obj-$(CONFIG_APPLE_AIRPORT)	+= airport.o
-obj-$(CONFIG_PLX_HERMES)	+= orinoco_plx.o
-obj-$(CONFIG_PCI_HERMES)	+= orinoco_pci.o
-obj-$(CONFIG_TMD_HERMES)	+= orinoco_tmd.o
-obj-$(CONFIG_NORTEL_HERMES)	+= orinoco_nortel.o
-obj-$(CONFIG_PCMCIA_SPECTRUM)	+= spectrum_cs.o
+obj-$(CONFIG_HERMES)		+= orinoco/
 
 obj-$(CONFIG_AIRO)		+= airo.o
 obj-$(CONFIG_AIRO_CS)		+= airo_cs.o airo.o
@@ -38,6 +30,8 @@
 obj-$(CONFIG_B43)		+= b43/
 obj-$(CONFIG_B43LEGACY)		+= b43legacy/
 obj-$(CONFIG_ZD1211RW)		+= zd1211rw/
+obj-$(CONFIG_RTL8180)		+= rtl818x/
+obj-$(CONFIG_RTL8187)		+= rtl818x/
 
 # 16-bit wireless PCMCIA client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
@@ -50,12 +44,6 @@
 
 obj-$(CONFIG_LIBERTAS_THINFIRM)	+= libertas_tf/
 
-rtl8180-objs		:= rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
-rtl8187-objs		:= rtl8187_dev.o rtl8187_rtl8225.o
-
-obj-$(CONFIG_RTL8180)	+= rtl8180.o
-obj-$(CONFIG_RTL8187)	+= rtl8187.o
-
 obj-$(CONFIG_ADM8211)	+= adm8211.o
 
 obj-$(CONFIG_IWLWIFI)	+= iwlwifi/
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index b2c050b..fc0897f 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -341,15 +341,14 @@
 		pci_unmap_single(priv->pdev, info->mapping,
 				 info->skb->len, PCI_DMA_TODEVICE);
 
-		memset(&txi->status, 0, sizeof(txi->status));
+		ieee80211_tx_info_clear_status(txi);
+
 		skb_pull(skb, sizeof(struct adm8211_tx_hdr));
 		memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
-		if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
-			if (status & TDES0_STATUS_ES)
-				txi->status.excessive_retries = 1;
-			else
-				txi->flags |= IEEE80211_TX_STAT_ACK;
-		}
+		if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) &&
+		    !(status & TDES0_STATUS_ES))
+			txi->flags |= IEEE80211_TX_STAT_ACK;
+
 		ieee80211_tx_status_irqsafe(dev, skb);
 
 		info->skb = NULL;
@@ -1298,25 +1297,10 @@
 	ADM8211_CSR_WRITE(ABDA1, reg);
 }
 
-static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len)
+static int adm8211_config(struct ieee80211_hw *dev, u32 changed)
 {
 	struct adm8211_priv *priv = dev->priv;
-	u8 buf[36];
-
-	if (ssid_len > 32)
-		return -EINVAL;
-
-	memset(buf, 0, sizeof(buf));
-	buf[0] = ssid_len;
-	memcpy(buf + 1, ssid, ssid_len);
-	adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33);
-	/* TODO: configure beacon for adhoc? */
-	return 0;
-}
-
-static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
-{
-	struct adm8211_priv *priv = dev->priv;
+	struct ieee80211_conf *conf = &dev->conf;
 	int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
 
 	if (channel != priv->channel) {
@@ -1338,13 +1322,6 @@
 		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 	}
 
-	if (conf->ssid_len != priv->ssid_len ||
-	    memcmp(conf->ssid, priv->ssid, conf->ssid_len)) {
-		adm8211_set_ssid(dev, conf->ssid, conf->ssid_len);
-		priv->ssid_len = conf->ssid_len;
-		memcpy(priv->ssid, conf->ssid, conf->ssid_len);
-	}
-
 	return 0;
 }
 
@@ -1690,8 +1667,10 @@
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info);
+	u8 rc_flags;
 
-	short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE);
+	rc_flags = info->control.rates[0].flags;
+	short_preamble = !!(rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
 	plcp_signal = txrate->bitrate;
 
 	hdr = (struct ieee80211_hdr *)skb->data;
@@ -1723,10 +1702,10 @@
 	if (short_preamble)
 		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
 
-	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+	if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
 		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
 
-	txhdr->retry_limit = info->control.retry_limit;
+	txhdr->retry_limit = info->control.rates[0].count;
 
 	adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
 
@@ -1791,7 +1770,6 @@
 	int err;
 	u32 reg;
 	u8 perm_addr[ETH_ALEN];
-	DECLARE_MAC_BUF(mac);
 
 	err = pci_enable_device(pdev);
 	if (err) {
@@ -1925,8 +1903,8 @@
 		goto err_free_desc;
 	}
 
-	printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n",
-	       wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
+	printk(KERN_INFO "%s: hwaddr %pM, Rev 0x%02x\n",
+	       wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
 	       pdev->revision);
 
 	return 0;
diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h
index 9b190ee..4f6ab13 100644
--- a/drivers/net/wireless/adm8211.h
+++ b/drivers/net/wireless/adm8211.h
@@ -553,8 +553,6 @@
 
 	int channel;
 	u8 bssid[ETH_ALEN];
-	u8 ssid[32];
-	size_t ssid_len;
 
 	u8 soft_rx_crc;
 	u8 retry_limit;
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 370133e..fc4322c 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -47,10 +47,11 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <asm/uaccess.h>
-#include <net/ieee80211.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
+#include <linux/ieee80211.h>
+
 #include "airo.h"
 
 #define DRV_NAME "airo"
@@ -1270,6 +1271,7 @@
 #define airo_print_err(name, fmt, args...) \
 	airo_print(KERN_ERR, name, fmt, ##args)
 
+#define AIRO_FLASH(dev) (((struct airo_info *)dev->ml_priv)->flash)
 
 /***********************************************************************
  *                              MIC ROUTINES                           *
@@ -1865,7 +1867,7 @@
 }
 
 static int airo_open(struct net_device *dev) {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	int rc = 0;
 
 	if (test_bit(FLAG_FLASHING, &ai->flags))
@@ -1912,7 +1914,7 @@
 static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
 	int npacks, pending;
 	unsigned long flags;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 
 	if (!skb) {
 		airo_print_err(dev->name, "%s: skb == NULL!",__func__);
@@ -1956,7 +1958,7 @@
 	unsigned char *buffer;
 	s16 len;
 	__le16 *payloadLen;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	u8 *sendbuf;
 
 	/* get a packet to send */
@@ -2085,7 +2087,7 @@
 static void airo_end_xmit(struct net_device *dev) {
 	u16 status;
 	int i;
-	struct airo_info *priv = dev->priv;
+	struct airo_info *priv = dev->ml_priv;
 	struct sk_buff *skb = priv->xmit.skb;
 	int fid = priv->xmit.fid;
 	u32 *fids = priv->fids;
@@ -2111,7 +2113,7 @@
 static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
 	s16 len;
 	int i, j;
-	struct airo_info *priv = dev->priv;
+	struct airo_info *priv = dev->ml_priv;
 	u32 *fids = priv->fids;
 
 	if ( skb == NULL ) {
@@ -2150,7 +2152,7 @@
 static void airo_end_xmit11(struct net_device *dev) {
 	u16 status;
 	int i;
-	struct airo_info *priv = dev->priv;
+	struct airo_info *priv = dev->ml_priv;
 	struct sk_buff *skb = priv->xmit11.skb;
 	int fid = priv->xmit11.fid;
 	u32 *fids = priv->fids;
@@ -2176,7 +2178,7 @@
 static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
 	s16 len;
 	int i, j;
-	struct airo_info *priv = dev->priv;
+	struct airo_info *priv = dev->ml_priv;
 	u32 *fids = priv->fids;
 
 	if (test_bit(FLAG_MPI, &priv->flags)) {
@@ -2220,7 +2222,7 @@
 
 static void airo_read_stats(struct net_device *dev)
 {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	StatsRid stats_rid;
 	__le32 *vals = stats_rid.vals;
 
@@ -2254,7 +2256,7 @@
 
 static struct net_device_stats *airo_get_stats(struct net_device *dev)
 {
-	struct airo_info *local =  dev->priv;
+	struct airo_info *local =  dev->ml_priv;
 
 	if (!test_bit(JOB_STATS, &local->jobs)) {
 		/* Get stats out of the card if available */
@@ -2281,7 +2283,7 @@
 }
 
 static void airo_set_multicast_list(struct net_device *dev) {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 
 	if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
 		change_bit(FLAG_PROMISC, &ai->flags);
@@ -2299,7 +2301,7 @@
 
 static int airo_set_mac_address(struct net_device *dev, void *p)
 {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	struct sockaddr *addr = p;
 
 	readConfigRid(ai, 1);
@@ -2339,7 +2341,7 @@
 }
 
 static int airo_close(struct net_device *dev) {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 
 	netif_stop_queue(dev);
 
@@ -2365,7 +2367,7 @@
 
 void stop_airo_card( struct net_device *dev, int freeres )
 {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 
 	set_bit(FLAG_RADIO_DOWN, &ai->flags);
 	disable_MAC(ai, 1);
@@ -2665,7 +2667,7 @@
 	struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup);
 	if (!dev)
 		return NULL;
-	dev->priv = ethdev->priv;
+	dev->ml_priv = ethdev->ml_priv;
 	dev->irq = ethdev->irq;
 	dev->base_addr = ethdev->base_addr;
 	dev->wireless_data = ethdev->wireless_data;
@@ -2680,7 +2682,7 @@
 }
 
 static int reset_card( struct net_device *dev , int lock) {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 
 	if (lock && down_interruptible(&ai->sem))
 		return -1;
@@ -2757,7 +2759,6 @@
 	struct net_device *dev;
 	struct airo_info *ai;
 	int i, rc;
-	DECLARE_MAC_BUF(mac);
 
 	/* Create the network device object. */
 	dev = alloc_netdev(sizeof(*ai), "", ether_setup);
@@ -2766,7 +2767,7 @@
 		return NULL;
 	}
 
-	ai = dev->priv;
+	ai = dev->ml_priv = netdev_priv(dev);
 	ai->wifidev = NULL;
 	ai->flags = 1 << FLAG_RADIO_DOWN;
 	ai->jobs = 0;
@@ -2860,15 +2861,14 @@
 		goto err_out_reg;
 
 	set_bit(FLAG_REGISTERED,&ai->flags);
-	airo_print_info(dev->name, "MAC enabled %s",
-			print_mac(mac, dev->dev_addr));
+	airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr);
 
 	/* Allocate the transmit buffers */
 	if (probe && !test_bit(FLAG_MPI,&ai->flags))
 		for( i = 0; i < MAX_FIDS; i++ )
 			ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
 
-	if (setup_proc_entry(dev, dev->priv) < 0)
+	if (setup_proc_entry(dev, dev->ml_priv) < 0)
 		goto err_out_wifi;
 
 	return dev;
@@ -2917,8 +2917,7 @@
 int reset_airo_card( struct net_device *dev )
 {
 	int i;
-	struct airo_info *ai = dev->priv;
-	DECLARE_MAC_BUF(mac);
+	struct airo_info *ai = dev->ml_priv;
 
 	if (reset_card (dev, 1))
 		return -1;
@@ -2927,8 +2926,7 @@
 		airo_print_err(dev->name, "MAC could not be enabled");
 		return -1;
 	}
-	airo_print_info(dev->name, "MAC enabled %s",
-			print_mac(mac, dev->dev_addr));
+	airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr);
 	/* Allocate the transmit buffers if needed */
 	if (!test_bit(FLAG_MPI,&ai->flags))
 		for( i = 0; i < MAX_FIDS; i++ )
@@ -2942,7 +2940,7 @@
 EXPORT_SYMBOL(reset_airo_card);
 
 static void airo_send_event(struct net_device *dev) {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	union iwreq_data wrqu;
 	StatusRid status_rid;
 
@@ -3019,7 +3017,7 @@
 
 static int airo_thread(void *data) {
 	struct net_device *dev = data;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	int locked;
 
 	set_freezable();
@@ -3134,7 +3132,7 @@
 	struct net_device *dev = dev_id;
 	u16 status;
 	u16 fid;
-	struct airo_info *apriv = dev->priv;
+	struct airo_info *apriv = dev->ml_priv;
 	u16 savedInterrupts = 0;
 	int handled = 0;
 
@@ -3369,7 +3367,6 @@
 				skb->protocol = htons(ETH_P_802_2);
 			} else
 				skb->protocol = eth_type_trans(skb,dev);
-			skb->dev->last_rx = jiffies;
 			skb->ip_summed = CHECKSUM_NONE;
 
 			netif_rx( skb );
@@ -3599,7 +3596,6 @@
 
 		skb->ip_summed = CHECKSUM_NONE;
 		skb->protocol = eth_type_trans(skb, ai->dev);
-		skb->dev->last_rx = jiffies;
 		netif_rx(skb);
 	}
 badrx:
@@ -3611,7 +3607,7 @@
 	}
 }
 
-void mpi_receive_802_11 (struct airo_info *ai)
+static void mpi_receive_802_11(struct airo_info *ai)
 {
 	RxFid rxd;
 	struct sk_buff *skb = NULL;
@@ -3693,7 +3689,6 @@
 	skb->pkt_type = PACKET_OTHERHOST;
 	skb->dev = ai->wifidev;
 	skb->protocol = htons(ETH_P_802_2);
-	skb->dev->last_rx = jiffies;
 	skb->ip_summed = CHECKSUM_NONE;
 	netif_rx( skb );
 badrx:
@@ -4604,7 +4599,7 @@
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *apriv = dev->priv;
+	struct airo_info *apriv = dev->ml_priv;
 	CapabilityRid cap_rid;
 	StatusRid status_rid;
 	u16 mode;
@@ -4687,7 +4682,7 @@
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *apriv = dev->priv;
+	struct airo_info *apriv = dev->ml_priv;
 	StatsRid stats;
 	int i, j;
 	__le32 *vals = stats.vals;
@@ -4750,7 +4745,7 @@
 	struct proc_data *data = file->private_data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	char *line;
 
 	if ( !data->writelen ) return;
@@ -4962,7 +4957,7 @@
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	int i;
 	__le16 mode;
 
@@ -5053,7 +5048,7 @@
 	struct proc_data *data = (struct proc_data *)file->private_data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	SsidRid SSID_rid;
 	int i;
 	char *p = data->wbuffer;
@@ -5096,7 +5091,7 @@
 	struct proc_data *data = (struct proc_data *)file->private_data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	APListRid APList_rid;
 	int i;
 
@@ -5191,7 +5186,7 @@
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	int i;
 	char key[16];
 	u16 index = 0;
@@ -5233,7 +5228,7 @@
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	char *ptr;
 	WepKeyRid wkr;
 	__le16 lastindex;
@@ -5282,7 +5277,7 @@
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	int i;
 	char *ptr;
 	SsidRid SSID_rid;
@@ -5326,11 +5321,10 @@
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	int i;
 	char *ptr;
 	APListRid APList_rid;
-	DECLARE_MAC_BUF(mac);
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
@@ -5354,8 +5348,7 @@
 // We end when we find a zero MAC
 		if ( !*(int*)APList_rid.ap[i] &&
 		     !*(int*)&APList_rid.ap[i][2]) break;
-		ptr += sprintf(ptr, "%s\n",
-			       print_mac(mac, APList_rid.ap[i]));
+		ptr += sprintf(ptr, "%pM\n", APList_rid.ap[i]);
 	}
 	if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
 
@@ -5368,13 +5361,12 @@
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	char *ptr;
 	BSSListRid BSSList_rid;
 	int rc;
 	/* If doLoseSync is not 1, we won't do a Lose Sync */
 	int doLoseSync = -1;
-	DECLARE_MAC_BUF(mac);
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
@@ -5411,8 +5403,8 @@
            we have to add a spin lock... */
 	rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
 	while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) {
-		ptr += sprintf(ptr, "%s %*s rssi = %d",
-			       print_mac(mac, BSSList_rid.bssid),
+		ptr += sprintf(ptr, "%pM %*s rssi = %d",
+			       BSSList_rid.bssid,
 				(int)BSSList_rid.ssidLen,
 				BSSList_rid.ssid,
 				le16_to_cpu(BSSList_rid.dBm));
@@ -5447,7 +5439,7 @@
    associated we will check every minute to see if anything has
    changed. */
 static void timer_func( struct net_device *dev ) {
-	struct airo_info *apriv = dev->priv;
+	struct airo_info *apriv = dev->ml_priv;
 
 /* We don't have a link so try changing the authtype */
 	readConfigRid(apriv, 0);
@@ -5518,7 +5510,7 @@
 static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	Cmd cmd;
 	Resp rsp;
 
@@ -5550,7 +5542,7 @@
 static int airo_pci_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	pci_power_t prev_state = pdev->current_state;
 
 	pci_set_power_state(pdev, PCI_D0);
@@ -5729,7 +5721,7 @@
 			 struct iw_freq *fwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	int rc = -EINPROGRESS;		/* Call commit handler */
 
 	/* If setting by frequency, convert to a channel */
@@ -5774,7 +5766,7 @@
 			 struct iw_freq *fwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	StatusRid status_rid;		/* Card status info */
 	int ch;
 
@@ -5805,7 +5797,7 @@
 			  struct iw_point *dwrq,
 			  char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	SsidRid SSID_rid;		/* SSIDs */
 
 	/* Reload the list of current SSID */
@@ -5851,7 +5843,7 @@
 			  struct iw_point *dwrq,
 			  char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	StatusRid status_rid;		/* Card status info */
 
 	readStatusRid(local, &status_rid, 1);
@@ -5879,7 +5871,7 @@
 			struct sockaddr *awrq,
 			char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	Cmd cmd;
 	Resp rsp;
 	APListRid APList_rid;
@@ -5916,7 +5908,7 @@
 			struct sockaddr *awrq,
 			char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	StatusRid status_rid;		/* Card status info */
 
 	readStatusRid(local, &status_rid, 1);
@@ -5937,7 +5929,7 @@
 			 struct iw_point *dwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 
 	/* Check the size of the string */
 	if(dwrq->length > 16) {
@@ -5960,7 +5952,7 @@
 			 struct iw_point *dwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 
 	readConfigRid(local, 1);
 	strncpy(extra, local->config.nodeName, 16);
@@ -5979,7 +5971,7 @@
 			 struct iw_param *vwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	CapabilityRid cap_rid;		/* Card capability info */
 	u8	brate = 0;
 	int	i;
@@ -6049,7 +6041,7 @@
 			 struct iw_param *vwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	StatusRid status_rid;		/* Card status info */
 
 	readStatusRid(local, &status_rid, 1);
@@ -6071,7 +6063,7 @@
 			struct iw_param *vwrq,
 			char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	int rthr = vwrq->value;
 
 	if(vwrq->disabled)
@@ -6095,7 +6087,7 @@
 			struct iw_param *vwrq,
 			char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 
 	readConfigRid(local, 1);
 	vwrq->value = le16_to_cpu(local->config.rtsThres);
@@ -6114,7 +6106,7 @@
 			 struct iw_param *vwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	int fthr = vwrq->value;
 
 	if(vwrq->disabled)
@@ -6139,7 +6131,7 @@
 			 struct iw_param *vwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 
 	readConfigRid(local, 1);
 	vwrq->value = le16_to_cpu(local->config.fragThresh);
@@ -6158,7 +6150,7 @@
 			 __u32 *uwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	int reset = 0;
 
 	readConfigRid(local, 1);
@@ -6221,7 +6213,7 @@
 			 __u32 *uwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 
 	readConfigRid(local, 1);
 	/* If not managed, assume it's ad-hoc */
@@ -6258,7 +6250,7 @@
 			   struct iw_point *dwrq,
 			   char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	CapabilityRid cap_rid;		/* Card capability info */
 	int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 );
 	__le16 currentAuthType = local->config.authType;
@@ -6345,7 +6337,7 @@
 			   struct iw_point *dwrq,
 			   char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 	CapabilityRid cap_rid;		/* Card capability info */
 
@@ -6393,7 +6385,7 @@
 			    union iwreq_data *wrqu,
 			    char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	struct iw_point *encoding = &wrqu->encoding;
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 	CapabilityRid cap_rid;		/* Card capability info */
@@ -6479,7 +6471,7 @@
 			    union iwreq_data *wrqu,
 			    char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	struct iw_point *encoding = &wrqu->encoding;
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 	CapabilityRid cap_rid;		/* Card capability info */
@@ -6542,7 +6534,7 @@
 			       struct iw_request_info *info,
 			       union iwreq_data *wrqu, char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	struct iw_param *param = &wrqu->param;
 	__le16 currentAuthType = local->config.authType;
 
@@ -6610,7 +6602,7 @@
 			       struct iw_request_info *info,
 			       union iwreq_data *wrqu, char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	struct iw_param *param = &wrqu->param;
 	__le16 currentAuthType = local->config.authType;
 
@@ -6659,7 +6651,7 @@
 			  struct iw_param *vwrq,
 			  char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	CapabilityRid cap_rid;		/* Card capability info */
 	int i;
 	int rc = -EINVAL;
@@ -6696,7 +6688,7 @@
 			  struct iw_param *vwrq,
 			  char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 
 	readConfigRid(local, 1);
 	vwrq->value = le16_to_cpu(local->config.txPower);
@@ -6716,7 +6708,7 @@
 			  struct iw_param *vwrq,
 			  char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	int rc = -EINVAL;
 
 	if(vwrq->disabled) {
@@ -6754,7 +6746,7 @@
 			  struct iw_param *vwrq,
 			  char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 
 	vwrq->disabled = 0;      /* Can't be disabled */
 
@@ -6785,7 +6777,7 @@
 			  struct iw_point *dwrq,
 			  char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	struct iw_range *range = (struct iw_range *) extra;
 	CapabilityRid cap_rid;		/* Card capability info */
 	int		i;
@@ -6910,7 +6902,7 @@
 			  struct iw_param *vwrq,
 			  char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 
 	readConfigRid(local, 1);
 	if (vwrq->disabled) {
@@ -6967,7 +6959,7 @@
 			  struct iw_param *vwrq,
 			  char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	__le16 mode;
 
 	readConfigRid(local, 1);
@@ -6998,7 +6990,7 @@
 			 struct iw_param *vwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 
 	readConfigRid(local, 1);
 	local->config.rssiThreshold =
@@ -7017,7 +7009,7 @@
 			 struct iw_param *vwrq,
 			 char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 
 	readConfigRid(local, 1);
 	vwrq->value = le16_to_cpu(local->config.rssiThreshold);
@@ -7037,7 +7029,7 @@
 			   struct iw_point *dwrq,
 			   char *extra)
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 	struct sockaddr *address = (struct sockaddr *) extra;
 	struct iw_quality qual[IW_MAX_AP];
 	BSSListRid BSSList;
@@ -7110,7 +7102,7 @@
 			 struct iw_point *dwrq,
 			 char *extra)
 {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	Cmd cmd;
 	Resp rsp;
 	int wake = 0;
@@ -7156,7 +7148,7 @@
 					char *end_buf,
 					BSSListRid *bss)
 {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	struct iw_event		iwe;		/* Temporary buffer */
 	__le16			capabilities;
 	char *			current_val;	/* For rates */
@@ -7274,56 +7266,53 @@
 	if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
 		unsigned int num_null_ies = 0;
 		u16 length = sizeof (bss->extra.iep);
-		struct ieee80211_info_element *info_element =
-			(struct ieee80211_info_element *) &bss->extra.iep;
+		u8 *ie = (void *)&bss->extra.iep;
 
-		while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) {
-			if (sizeof(*info_element) + info_element->len > length) {
+		while ((length >= 2) && (num_null_ies < 2)) {
+			if (2 + ie[1] > length) {
 				/* Invalid element, don't continue parsing IE */
 				break;
 			}
 
-			switch (info_element->id) {
-			case MFIE_TYPE_SSID:
+			switch (ie[0]) {
+			case WLAN_EID_SSID:
 				/* Two zero-length SSID elements
 				 * mean we're done parsing elements */
-				if (!info_element->len)
+				if (!ie[1])
 					num_null_ies++;
 				break;
 
-			case MFIE_TYPE_GENERIC:
-				if (info_element->len >= 4 &&
-				    info_element->data[0] == 0x00 &&
-				    info_element->data[1] == 0x50 &&
-				    info_element->data[2] == 0xf2 &&
-				    info_element->data[3] == 0x01) {
+			case WLAN_EID_GENERIC:
+				if (ie[1] >= 4 &&
+				    ie[2] == 0x00 &&
+				    ie[3] == 0x50 &&
+				    ie[4] == 0xf2 &&
+				    ie[5] == 0x01) {
 					iwe.cmd = IWEVGENIE;
-					iwe.u.data.length = min(info_element->len + 2,
-								  MAX_WPA_IE_LEN);
+					/* 64 is an arbitrary cut-off */
+					iwe.u.data.length = min(ie[1] + 2,
+								64);
 					current_ev = iwe_stream_add_point(
 							info, current_ev,
-							end_buf, &iwe,
-							(char *) info_element);
+							end_buf, &iwe, ie);
 				}
 				break;
 
-			case MFIE_TYPE_RSN:
+			case WLAN_EID_RSN:
 				iwe.cmd = IWEVGENIE;
-				iwe.u.data.length = min(info_element->len + 2,
-							  MAX_WPA_IE_LEN);
+				/* 64 is an arbitrary cut-off */
+				iwe.u.data.length = min(ie[1] + 2, 64);
 				current_ev = iwe_stream_add_point(
 					info, current_ev, end_buf,
-					&iwe, (char *) info_element);
+					&iwe, ie);
 				break;
 
 			default:
 				break;
 			}
 
-			length -= sizeof(*info_element) + info_element->len;
-			info_element =
-			    (struct ieee80211_info_element *)&info_element->
-			    data[info_element->len];
+			length -= 2 + ie[1];
+			ie += 2 + ie[1];
 		}
 	}
 	return current_ev;
@@ -7338,7 +7327,7 @@
 			 struct iw_point *dwrq,
 			 char *extra)
 {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	BSSListElement *net;
 	int err = 0;
 	char *current_ev = extra;
@@ -7382,7 +7371,7 @@
 			      void *zwrq,			/* NULL */
 			      char *extra)			/* NULL */
 {
-	struct airo_info *local = dev->priv;
+	struct airo_info *local = dev->ml_priv;
 
 	if (!test_bit (FLAG_COMMIT, &local->flags))
 		return 0;
@@ -7527,7 +7516,7 @@
 static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	int rc = 0;
-	struct airo_info *ai = (struct airo_info *)dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 
 	if (ai->power.event)
 		return 0;
@@ -7655,7 +7644,7 @@
 
 static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
 {
-	struct airo_info *local =  dev->priv;
+	struct airo_info *local =  dev->ml_priv;
 
 	if (!test_bit(JOB_WSTATS, &local->jobs)) {
 		/* Get stats out of the card if available */
@@ -7680,7 +7669,7 @@
 	unsigned short ridcode;
 	unsigned char *iobuf;
 	int len;
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 
 	if (test_bit(FLAG_FLASHING, &ai->flags))
 		return -EIO;
@@ -7746,7 +7735,7 @@
  */
 
 static int writerids(struct net_device *dev, aironet_ioctl *comp) {
-	struct airo_info *ai = dev->priv;
+	struct airo_info *ai = dev->ml_priv;
 	int  ridcode;
         int  enabled;
 	static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
@@ -7869,41 +7858,41 @@
 	switch(comp->command)
 	{
 	case AIROFLSHRST:
-		return cmdreset((struct airo_info *)dev->priv);
+		return cmdreset((struct airo_info *)dev->ml_priv);
 
 	case AIROFLSHSTFL:
-		if (!((struct airo_info *)dev->priv)->flash &&
-			(((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL)
+		if (!AIRO_FLASH(dev) &&
+		    (AIRO_FLASH(dev) = kmalloc(FLASHSIZE, GFP_KERNEL)) == NULL)
 			return -ENOMEM;
-		return setflashmode((struct airo_info *)dev->priv);
+		return setflashmode((struct airo_info *)dev->ml_priv);
 
 	case AIROFLSHGCHR: /* Get char from aux */
 		if(comp->len != sizeof(int))
 			return -EINVAL;
 		if (copy_from_user(&z,comp->data,comp->len))
 			return -EFAULT;
-		return flashgchar((struct airo_info *)dev->priv,z,8000);
+		return flashgchar((struct airo_info *)dev->ml_priv, z, 8000);
 
 	case AIROFLSHPCHR: /* Send char to card. */
 		if(comp->len != sizeof(int))
 			return -EINVAL;
 		if (copy_from_user(&z,comp->data,comp->len))
 			return -EFAULT;
-		return flashpchar((struct airo_info *)dev->priv,z,8000);
+		return flashpchar((struct airo_info *)dev->ml_priv, z, 8000);
 
 	case AIROFLPUTBUF: /* Send 32k to card */
-		if (!((struct airo_info *)dev->priv)->flash)
+		if (!AIRO_FLASH(dev))
 			return -ENOMEM;
 		if(comp->len > FLASHSIZE)
 			return -EINVAL;
-		if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len))
+		if (copy_from_user(AIRO_FLASH(dev), comp->data, comp->len))
 			return -EFAULT;
 
-		flashputbuf((struct airo_info *)dev->priv);
+		flashputbuf((struct airo_info *)dev->ml_priv);
 		return 0;
 
 	case AIRORESTART:
-		if(flashrestart((struct airo_info *)dev->priv,dev))
+		if (flashrestart((struct airo_info *)dev->ml_priv, dev))
 			return -EIO;
 		return 0;
 	}
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index dec5e87..bfca15d 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -1467,19 +1467,17 @@
 						else if (hw_dst_addr[1] == 0x40)
 							printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name);
 					while (dmi)
-					{							if (dmi->dmi_addrlen == 6)
-						{
-							DECLARE_MAC_BUF(mac);
+					{
+						if (dmi->dmi_addrlen == 6) {
 							if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
-								printk(KERN_ERR "%s mcl %s\n",
-								       dev->name, print_mac(mac, dmi->dmi_addr));
+								printk(KERN_ERR "%s mcl %pM\n",
+								       dev->name, dmi->dmi_addr);
 							for (i = 0; i < 6; i++)
 								if (dmi->dmi_addr[i] != hw_dst_addr[i])
 									break;
 							if (i == 6)
 								break;
-						}
-						else
+						} else
 							printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name);
 						dmi = dmi->next;
 					}
@@ -1512,18 +1510,14 @@
 			{
 				char immedDestAddress[6];
 				char immedSrcAddress[6];
-				DECLARE_MAC_BUF(mac);
-				DECLARE_MAC_BUF(mac2);
-				DECLARE_MAC_BUF(mac3);
-				DECLARE_MAC_BUF(mac4);
 				memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6);
 				memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6);
 
-				printk(KERN_WARNING "%s t %s f %s imd %s ims %s\n",
-				       dev->name, print_mac(mac, skbtmp),
-				       print_mac(mac2, &skbtmp[6]),
-				       print_mac(mac3, immedDestAddress),
-				       print_mac(mac4, immedSrcAddress));
+				printk(KERN_WARNING "%s t %pM f %pM imd %pM ims %pM\n",
+				       dev->name, skbtmp,
+				       &skbtmp[6],
+				       immedDestAddress,
+				       immedSrcAddress);
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
@@ -1535,7 +1529,6 @@
 					printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol);
 				}
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += pkt_len;
 		}
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
index 53ea439..183ffc8 100644
--- a/drivers/net/wireless/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath5k/ath5k.h
@@ -507,11 +507,15 @@
 #define AR5K_TXQ_FLAG_TXEOLINT_ENABLE		0x0004	/* Enable TXEOL interrupt -not used- */
 #define AR5K_TXQ_FLAG_TXDESCINT_ENABLE		0x0008	/* Enable TXDESC interrupt -not used- */
 #define AR5K_TXQ_FLAG_TXURNINT_ENABLE		0x0010	/* Enable TXURN interrupt */
-#define AR5K_TXQ_FLAG_BACKOFF_DISABLE		0x0020	/* Disable random post-backoff */
-#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE	0x0040	/* Enable ready time expiry policy (?)*/
-#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE	0x0080	/* Enable backoff while bursting */
-#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS		0x0100	/* Disable backoff while bursting */
-#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE	0x0200	/* Enable hw compression -not implemented-*/
+#define AR5K_TXQ_FLAG_CBRORNINT_ENABLE		0x0020	/* Enable CBRORN interrupt */
+#define AR5K_TXQ_FLAG_CBRURNINT_ENABLE		0x0040	/* Enable CBRURN interrupt */
+#define AR5K_TXQ_FLAG_QTRIGINT_ENABLE		0x0080	/* Enable QTRIG interrupt */
+#define AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE		0x0100	/* Enable TXNOFRM interrupt */
+#define AR5K_TXQ_FLAG_BACKOFF_DISABLE		0x0200	/* Disable random post-backoff */
+#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE	0x0300	/* Enable ready time expiry policy (?)*/
+#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE	0x0800	/* Enable backoff while bursting */
+#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS		0x1000	/* Disable backoff while bursting */
+#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE	0x2000	/* Enable hw compression -not implemented-*/
 
 /*
  * A struct to hold tx queue's parameters
@@ -817,13 +821,6 @@
 		return (false);			\
 } while (0)
 
-enum ath5k_ant_setting {
-	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
-	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
-	AR5K_ANT_FIXED_B	= 2,	/* fixed to 11b frequencies */
-	AR5K_ANT_MAX		= 3,
-};
-
 /*
  * Hardware interrupt abstraction
  */
@@ -853,7 +850,7 @@
  * 	checked. We should do this with ath5k_hw_update_mib_counters() but
  * 	it seems we should also then do some noise immunity work.
  * @AR5K_INT_RXPHY: RX PHY Error
- * @AR5K_INT_RXKCM: ??
+ * @AR5K_INT_RXKCM: RX Key cache miss
  * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
  * 	beacon that must be handled in software. The alternative is if you
  * 	have VEOL support, in that case you let the hardware deal with things.
@@ -869,7 +866,7 @@
  * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA
  * 	errors. These types of errors we can enable seem to be of type
  * 	AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR.
- * @AR5K_INT_GLOBAL: Seems to be used to clear and set the IER
+ * @AR5K_INT_GLOBAL: Used to clear and set the IER
  * @AR5K_INT_NOCARD: signals the card has been removed
  * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same
  * 	bit value
@@ -881,36 +878,61 @@
  * MACs.
  */
 enum ath5k_int {
-	AR5K_INT_RX	= 0x00000001, /* Not common */
+	AR5K_INT_RXOK	= 0x00000001,
 	AR5K_INT_RXDESC	= 0x00000002,
+	AR5K_INT_RXERR	= 0x00000004,
 	AR5K_INT_RXNOFRM = 0x00000008,
 	AR5K_INT_RXEOL	= 0x00000010,
 	AR5K_INT_RXORN	= 0x00000020,
-	AR5K_INT_TX	= 0x00000040, /* Not common */
+	AR5K_INT_TXOK	= 0x00000040,
 	AR5K_INT_TXDESC	= 0x00000080,
+	AR5K_INT_TXERR	= 0x00000100,
+	AR5K_INT_TXNOFRM = 0x00000200,
+	AR5K_INT_TXEOL	= 0x00000400,
 	AR5K_INT_TXURN	= 0x00000800,
 	AR5K_INT_MIB	= 0x00001000,
+	AR5K_INT_SWI	= 0x00002000,
 	AR5K_INT_RXPHY	= 0x00004000,
 	AR5K_INT_RXKCM	= 0x00008000,
 	AR5K_INT_SWBA	= 0x00010000,
+	AR5K_INT_BRSSI	= 0x00020000,
 	AR5K_INT_BMISS	= 0x00040000,
-	AR5K_INT_BNR	= 0x00100000, /* Not common */
-	AR5K_INT_GPIO	= 0x01000000,
-	AR5K_INT_FATAL	= 0x40000000, /* Not common */
-	AR5K_INT_GLOBAL	= 0x80000000,
+	AR5K_INT_FATAL	= 0x00080000, /* Non common */
+	AR5K_INT_BNR	= 0x00100000, /* Non common */
+	AR5K_INT_TIM	= 0x00200000, /* Non common */
+	AR5K_INT_DTIM	= 0x00400000, /* Non common */
+	AR5K_INT_DTIM_SYNC =	0x00800000, /* Non common */
+	AR5K_INT_GPIO	=	0x01000000,
+	AR5K_INT_BCN_TIMEOUT =	0x02000000, /* Non common */
+	AR5K_INT_CAB_TIMEOUT =	0x04000000, /* Non common */
+	AR5K_INT_RX_DOPPLER =	0x08000000, /* Non common */
+	AR5K_INT_QCBRORN =	0x10000000, /* Non common */
+	AR5K_INT_QCBRURN =	0x20000000, /* Non common */
+	AR5K_INT_QTRIG	=	0x40000000, /* Non common */
+	AR5K_INT_GLOBAL =	0x80000000,
 
-	AR5K_INT_COMMON  = AR5K_INT_RXNOFRM
-			| AR5K_INT_RXDESC
-			| AR5K_INT_RXEOL
-			| AR5K_INT_RXORN
-			| AR5K_INT_TXURN
-			| AR5K_INT_TXDESC
-			| AR5K_INT_MIB
-			| AR5K_INT_RXPHY
-			| AR5K_INT_RXKCM
-			| AR5K_INT_SWBA
-			| AR5K_INT_BMISS
-			| AR5K_INT_GPIO,
+	AR5K_INT_COMMON  = AR5K_INT_RXOK
+		| AR5K_INT_RXDESC
+		| AR5K_INT_RXERR
+		| AR5K_INT_RXNOFRM
+		| AR5K_INT_RXEOL
+		| AR5K_INT_RXORN
+		| AR5K_INT_TXOK
+		| AR5K_INT_TXDESC
+		| AR5K_INT_TXERR
+		| AR5K_INT_TXNOFRM
+		| AR5K_INT_TXEOL
+		| AR5K_INT_TXURN
+		| AR5K_INT_MIB
+		| AR5K_INT_SWI
+		| AR5K_INT_RXPHY
+		| AR5K_INT_RXKCM
+		| AR5K_INT_SWBA
+		| AR5K_INT_BRSSI
+		| AR5K_INT_BMISS
+		| AR5K_INT_GPIO
+		| AR5K_INT_GLOBAL,
+
 	AR5K_INT_NOCARD	= 0xffffffff
 };
 
@@ -1030,6 +1052,7 @@
 	bool			ah_calibration;
 	bool			ah_running;
 	bool			ah_single_chip;
+	bool			ah_combined_mic;
 	enum ath5k_rfgain	ah_rf_gain;
 
 	u32			ah_mac_srev;
@@ -1064,10 +1087,11 @@
 
 	u8			ah_sta_id[ETH_ALEN];
 
-	/* Current BSSID we are trying to assoc to / creating.
+	/* Current BSSID we are trying to assoc to / create.
 	 * This is passed by mac80211 on config_interface() and cached here for
 	 * use in resets */
 	u8			ah_bssid[ETH_ALEN];
+	u8			ah_bssid_mask[ETH_ALEN];
 
 	u32			ah_gpio[AR5K_MAX_GPIO];
 	int			ah_gpio_npins;
@@ -1081,6 +1105,11 @@
 	u32			ah_txq_imr_txurn;
 	u32			ah_txq_imr_txdesc;
 	u32			ah_txq_imr_txeol;
+	u32			ah_txq_imr_cbrorn;
+	u32			ah_txq_imr_cbrurn;
+	u32			ah_txq_imr_qtrig;
+	u32			ah_txq_imr_nofrm;
+	u32			ah_txq_isr;
 	u32			*ah_rf_banks;
 	size_t			ah_rf_banks_size;
 	struct ath5k_gain	ah_gain;
@@ -1321,4 +1350,9 @@
 	return retval;
 }
 
+static inline int ath5k_pad_size(int hdrlen)
+{
+	return (hdrlen < 24) ? 0 : hdrlen & 3;
+}
+
 #endif
diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c
index 51d5698..dea378f 100644
--- a/drivers/net/wireless/ath5k/attach.c
+++ b/drivers/net/wireless/ath5k/attach.c
@@ -106,7 +106,7 @@
 {
 	struct ath5k_hw *ah;
 	struct pci_dev *pdev = sc->pdev;
-	u8 mac[ETH_ALEN];
+	u8 mac[ETH_ALEN] = {};
 	int ret;
 	u32 srev;
 
@@ -317,15 +317,15 @@
 		goto err_free;
 	}
 
-	/* Set MAC address */
-	ret = ath5k_eeprom_read_mac(ah, mac);
-	if (ret) {
-		ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
-			sc->pdev->device);
-		goto err_free;
+	if (srev >= AR5K_SREV_AR2414) {
+		ah->ah_combined_mic = true;
+		AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,
+			AR5K_MISC_MODE_COMBINED_MIC);
 	}
 
+	/* MAC address is cleared until add_interface */
 	ath5k_hw_set_lladdr(ah, mac);
+
 	/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
 	memset(ah->ah_bssid, 0xff, ETH_ALEN);
 	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 2d14255..4af2607 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -60,6 +60,9 @@
 #include "debug.h"
 
 static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 
 
 /******************\
@@ -197,7 +200,7 @@
 #endif /* CONFIG_PM */
 
 static struct pci_driver ath5k_pci_driver = {
-	.name		= "ath5k_pci",
+	.name		= KBUILD_MODNAME,
 	.id_table	= ath5k_pci_id_table,
 	.probe		= ath5k_pci_probe,
 	.remove		= __devexit_p(ath5k_pci_remove),
@@ -219,8 +222,7 @@
 		struct ieee80211_if_init_conf *conf);
 static void ath5k_remove_interface(struct ieee80211_hw *hw,
 		struct ieee80211_if_init_conf *conf);
-static int ath5k_config(struct ieee80211_hw *hw,
-		struct ieee80211_conf *conf);
+static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
 static int ath5k_config_interface(struct ieee80211_hw *hw,
 		struct ieee80211_vif *vif,
 		struct ieee80211_if_conf *conf);
@@ -238,7 +240,7 @@
 		struct ieee80211_tx_queue_stats *stats);
 static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
 static void ath5k_reset_tsf(struct ieee80211_hw *hw);
-static int ath5k_beacon_update(struct ieee80211_hw *hw,
+static int ath5k_beacon_update(struct ath5k_softc *sc,
 		struct sk_buff *skb);
 static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
 		struct ieee80211_vif *vif,
@@ -548,8 +550,8 @@
 
 	/* set up multi-rate retry capabilities */
 	if (sc->ah->ah_version == AR5K_AR5212) {
-		hw->max_altrates = 3;
-		hw->max_altrate_tries = 11;
+		hw->max_rates = 4;
+		hw->max_rate_tries = 11;
 	}
 
 	/* Finish private driver data initialization */
@@ -711,7 +713,7 @@
 {
 	struct ath5k_softc *sc = hw->priv;
 	struct ath5k_hw *ah = sc->ah;
-	u8 mac[ETH_ALEN];
+	u8 mac[ETH_ALEN] = {};
 	int ret;
 
 	ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
@@ -781,7 +783,13 @@
 	tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
 	setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
 
-	ath5k_hw_get_lladdr(ah, mac);
+	ret = ath5k_eeprom_read_mac(ah, mac);
+	if (ret) {
+		ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
+			sc->pdev->device);
+		goto err_queues;
+	}
+
 	SET_IEEE80211_PERM_ADDR(hw, mac);
 	/* All MAC address bits matter for ACKs */
 	memset(sc->bssidmask, 0xff, ETH_ALEN);
@@ -1188,7 +1196,7 @@
 		ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
 		(sc->power_level * 2),
 		ieee80211_get_tx_rate(sc->hw, info)->hw_value,
-		info->control.retry_limit, keyidx, 0, flags, 0, 0);
+		info->control.rates[0].count, keyidx, 0, flags, 0, 0);
 	if (ret)
 		goto err_unmap;
 
@@ -1200,7 +1208,7 @@
 			break;
 
 		mrr_rate[i] = rate->hw_value;
-		mrr_tries[i] = info->control.retries[i].limit;
+		mrr_tries[i] = info->control.rates[i + 1].count;
 	}
 
 	ah->ah_setup_mrr_tx_desc(ah, ds,
@@ -1660,7 +1668,7 @@
 	struct ath5k_desc *ds;
 	int ret;
 	int hdrlen;
-	int pad;
+	int padsize;
 
 	spin_lock(&sc->rxbuflock);
 	if (list_empty(&sc->rxbuf)) {
@@ -1745,16 +1753,19 @@
 
 		skb_put(skb, rs.rs_datalen);
 
-		/*
-		 * the hardware adds a padding to 4 byte boundaries between
-		 * the header and the payload data if the header length is
-		 * not multiples of 4 - remove it
-		 */
+		/* The MAC header is padded to have 32-bit boundary if the
+		 * packet payload is non-zero. The general calculation for
+		 * padsize would take into account odd header lengths:
+		 * padsize = (4 - hdrlen % 4) % 4; However, since only
+		 * even-length headers are used, padding can only be 0 or 2
+		 * bytes and we can optimize this a bit. In addition, we must
+		 * not try to remove padding from short control frames that do
+		 * not have payload. */
 		hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-		if (hdrlen & 3) {
-			pad = hdrlen % 4;
-			memmove(skb->data + pad, skb->data, hdrlen);
-			skb_pull(skb, pad);
+		padsize = ath5k_pad_size(hdrlen);
+		if (padsize) {
+			memmove(skb->data + padsize, skb->data, hdrlen);
+			skb_pull(skb, padsize);
 		}
 
 		/*
@@ -1785,7 +1796,17 @@
 
 		rxs.noise = sc->ah->ah_noise_floor;
 		rxs.signal = rxs.noise + rs.rs_rssi;
-		rxs.qual = rs.rs_rssi * 100 / 64;
+
+		/* An rssi of 35 indicates you should be able use
+		 * 54 Mbps reliably. A more elaborate scheme can be used
+		 * here but it requires a map of SNR/throughput for each
+		 * possible mode used */
+		rxs.qual = rs.rs_rssi * 100 / 35;
+
+		/* rssi can be more than 35 though, anything above that
+		 * should be considered at 100% */
+		if (rxs.qual > 100)
+			rxs.qual = 100;
 
 		rxs.antenna = rs.rs_antenna;
 		rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
@@ -1846,30 +1867,26 @@
 		pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
 				PCI_DMA_TODEVICE);
 
-		memset(&info->status, 0, sizeof(info->status));
-		info->tx_rate_idx = ath5k_hw_to_driver_rix(sc,
-				ts.ts_rate[ts.ts_final_idx]);
-		info->status.retry_count = ts.ts_longretry;
-
+		ieee80211_tx_info_clear_status(info);
 		for (i = 0; i < 4; i++) {
-			struct ieee80211_tx_altrate *r =
-				&info->status.retries[i];
+			struct ieee80211_tx_rate *r =
+				&info->status.rates[i];
 
 			if (ts.ts_rate[i]) {
-				r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
-				r->limit = ts.ts_retry[i];
+				r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
+				r->count = ts.ts_retry[i];
 			} else {
-				r->rate_idx = -1;
-				r->limit = 0;
+				r->idx = -1;
+				r->count = 0;
 			}
 		}
 
-		info->status.excessive_retries = 0;
+		/* count the successful attempt as well */
+		info->status.rates[ts.ts_final_idx].count++;
+
 		if (unlikely(ts.ts_status)) {
 			sc->ll_stats.dot11ACKFailureCount++;
-			if (ts.ts_status & AR5K_TXERR_XRETRY)
-				info->status.excessive_retries = 1;
-			else if (ts.ts_status & AR5K_TXERR_FILT)
+			if (ts.ts_status & AR5K_TXERR_FILT)
 				info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
 		} else {
 			info->flags |= IEEE80211_TX_STAT_ACK;
@@ -2143,8 +2160,6 @@
  *
  * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA
  * interrupts to detect TSF updates only.
- *
- * AP mode is missing.
  */
 static void
 ath5k_beacon_config(struct ath5k_softc *sc)
@@ -2157,7 +2172,9 @@
 
 	if (sc->opmode == NL80211_IFTYPE_STATION) {
 		sc->imask |= AR5K_INT_BMISS;
-	} else if (sc->opmode == NL80211_IFTYPE_ADHOC) {
+	} else if (sc->opmode == NL80211_IFTYPE_ADHOC ||
+			sc->opmode == NL80211_IFTYPE_MESH_POINT ||
+			sc->opmode == NL80211_IFTYPE_AP) {
 		/*
 		 * In IBSS mode we use a self-linked tx descriptor and let the
 		 * hardware send the beacons automatically. We have to load it
@@ -2169,13 +2186,15 @@
 
 		sc->imask |= AR5K_INT_SWBA;
 
-		if (ath5k_hw_hasveol(ah)) {
-			spin_lock(&sc->block);
-			ath5k_beacon_send(sc);
-			spin_unlock(&sc->block);
-		}
+		if (sc->opmode == NL80211_IFTYPE_ADHOC) {
+			if (ath5k_hw_hasveol(ah)) {
+				spin_lock(&sc->block);
+				ath5k_beacon_send(sc);
+				spin_unlock(&sc->block);
+			}
+		} else
+			ath5k_beacon_update_timers(sc, -1);
 	}
-	/* TODO else AP */
 
 	ath5k_hw_set_imr(ah, sc->imask);
 }
@@ -2215,9 +2234,9 @@
 	 */
 	sc->curchan = sc->hw->conf.channel;
 	sc->curband = &sc->sbands[sc->curchan->band];
-	sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL |
-		AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL |
-		AR5K_INT_MIB;
+	sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
+		AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
+		AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;
 	ret = ath5k_reset(sc, false, false);
 	if (ret)
 		goto done;
@@ -2409,9 +2428,10 @@
 				/* bump tx trigger level */
 				ath5k_hw_update_tx_triglevel(ah, true);
 			}
-			if (status & AR5K_INT_RX)
+			if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
 				tasklet_schedule(&sc->rxtq);
-			if (status & AR5K_INT_TX)
+			if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
+					| AR5K_INT_TXERR | AR5K_INT_TXEOL))
 				tasklet_schedule(&sc->txtq);
 			if (status & AR5K_INT_BMISS) {
 			}
@@ -2527,8 +2547,7 @@
 	led->led_dev.brightness_set = ath5k_led_brightness_set;
 
 	err = led_classdev_register(&sc->pdev->dev, &led->led_dev);
-	if (err)
-	{
+	if (err) {
 		ATH5K_WARN(sc, "could not register LED %s\n", name);
 		led->sc = NULL;
 	}
@@ -2607,7 +2626,7 @@
 	struct ath5k_buf *bf;
 	unsigned long flags;
 	int hdrlen;
-	int pad;
+	int padsize;
 
 	ath5k_debug_dump_skb(sc, skb, "TX  ", 1);
 
@@ -2619,15 +2638,16 @@
 	 * if this is not the case we add the padding after the header
 	 */
 	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-	if (hdrlen & 3) {
-		pad = hdrlen % 4;
-		if (skb_headroom(skb) < pad) {
+	padsize = ath5k_pad_size(hdrlen);
+	if (padsize) {
+
+		if (skb_headroom(skb) < padsize) {
 			ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
-				" headroom to pad %d\n", hdrlen, pad);
+				  " headroom to pad %d\n", hdrlen, padsize);
 			return -1;
 		}
-		skb_push(skb, pad);
-		memmove(skb->data, skb->data+pad, hdrlen);
+		skb_push(skb, padsize);
+		memmove(skb->data, skb->data+padsize, hdrlen);
 	}
 
 	spin_lock_irqsave(&sc->txbuflock, flags);
@@ -2746,8 +2766,10 @@
 	sc->vif = conf->vif;
 
 	switch (conf->type) {
+	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_MONITOR:
 		sc->opmode = conf->type;
 		break;
@@ -2759,6 +2781,7 @@
 	/* Set to a reasonable value. Note that this will
 	 * be set to mac80211's value at ath5k_config(). */
 	sc->bintval = 1000;
+	ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
 
 	ret = 0;
 end:
@@ -2771,11 +2794,13 @@
 			struct ieee80211_if_init_conf *conf)
 {
 	struct ath5k_softc *sc = hw->priv;
+	u8 mac[ETH_ALEN] = {};
 
 	mutex_lock(&sc->lock);
 	if (sc->vif != conf->vif)
 		goto end;
 
+	ath5k_hw_set_lladdr(sc->ah, mac);
 	sc->vif = NULL;
 end:
 	mutex_unlock(&sc->lock);
@@ -2785,10 +2810,10 @@
  * TODO: Phy disable/diversity etc
  */
 static int
-ath5k_config(struct ieee80211_hw *hw,
-			struct ieee80211_conf *conf)
+ath5k_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct ath5k_softc *sc = hw->priv;
+	struct ieee80211_conf *conf = &hw->conf;
 
 	sc->bintval = conf->beacon_int;
 	sc->power_level = conf->power_level;
@@ -2809,7 +2834,7 @@
 		ret = -EIO;
 		goto unlock;
 	}
-	if (conf->bssid) {
+	if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) {
 		/* Cache for later use during resets */
 		memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN);
 		/* XXX: assoc id is set to 0 for now, mac80211 doesn't have
@@ -2817,18 +2842,17 @@
 		ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
 		mmiowb();
 	}
-
 	if (conf->changed & IEEE80211_IFCC_BEACON &&
-	    vif->type == NL80211_IFTYPE_ADHOC) {
+			(vif->type == NL80211_IFTYPE_ADHOC ||
+			 vif->type == NL80211_IFTYPE_MESH_POINT ||
+			 vif->type == NL80211_IFTYPE_AP)) {
 		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
 		if (!beacon) {
 			ret = -ENOMEM;
 			goto unlock;
 		}
-		/* call old handler for now */
-		ath5k_beacon_update(hw, beacon);
+		ath5k_beacon_update(sc, beacon);
 	}
-
 	mutex_unlock(&sc->lock);
 
 	return ath5k_reset_wake(sc);
@@ -2888,9 +2912,9 @@
 		if (*new_flags & FIF_PROMISC_IN_BSS) {
 			rfilt |= AR5K_RX_FILTER_PROM;
 			__set_bit(ATH_STAT_PROMISC, sc->status);
-		}
-		else
+		} else {
 			__clear_bit(ATH_STAT_PROMISC, sc->status);
+		}
 	}
 
 	/* Note, AR5K_RX_FILTER_MCAST is already enabled */
@@ -2948,12 +2972,15 @@
 		test_bit(ATH_STAT_PROMISC, sc->status))
 		rfilt |= AR5K_RX_FILTER_PROM;
 	if ((sc->opmode == NL80211_IFTYPE_STATION && sc->assoc) ||
-		sc->opmode == NL80211_IFTYPE_ADHOC) {
+		sc->opmode == NL80211_IFTYPE_ADHOC ||
+		sc->opmode == NL80211_IFTYPE_AP)
 		rfilt |= AR5K_RX_FILTER_BEACON;
-	}
+	if (sc->opmode == NL80211_IFTYPE_MESH_POINT)
+		rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
+			AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
 
 	/* Set filters */
-	ath5k_hw_set_rx_filter(ah,rfilt);
+	ath5k_hw_set_rx_filter(ah, rfilt);
 
 	/* Set multicast bits */
 	ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
@@ -2970,12 +2997,13 @@
 	struct ath5k_softc *sc = hw->priv;
 	int ret = 0;
 
-	switch(key->alg) {
+	if (modparam_nohwcrypt)
+		return -EOPNOTSUPP;
+
+	switch (key->alg) {
 	case ALG_WEP:
-	/* XXX: fix hardware encryption, its not working. For now
-	 * allow software encryption */
-		/* break; */
 	case ALG_TKIP:
+		break;
 	case ALG_CCMP:
 		return -EOPNOTSUPP;
 	default:
@@ -2994,6 +3022,8 @@
 		}
 		__set_bit(key->keyidx, sc->keymap);
 		key->hw_key_idx = key->keyidx;
+		key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV |
+			       IEEE80211_KEY_FLAG_GENERATE_MMIC);
 		break;
 	case DISABLE_KEY:
 		ath5k_hw_reset_key(sc->ah, key->keyidx);
@@ -3060,19 +3090,13 @@
 }
 
 static int
-ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
+ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb)
 {
-	struct ath5k_softc *sc = hw->priv;
 	unsigned long flags;
 	int ret;
 
 	ath5k_debug_dump_skb(sc, skb, "BC  ", 1);
 
-	if (sc->opmode != NL80211_IFTYPE_ADHOC) {
-		ret = -EIO;
-		goto end;
-	}
-
 	spin_lock_irqsave(&sc->block, flags);
 	ath5k_txbuf_free(sc, sc->bbuf);
 	sc->bbuf->skb = skb;
@@ -3085,7 +3109,6 @@
 		mmiowb();
 	}
 
-end:
 	return ret;
 }
 static void
diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c
index 5e362a7..b40a928 100644
--- a/drivers/net/wireless/ath5k/desc.c
+++ b/drivers/net/wireless/ath5k/desc.c
@@ -71,7 +71,7 @@
 	/* Verify and set frame length */
 
 	/* remove padding we might have added before */
-	frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+	frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN;
 
 	if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
 		return -EINVAL;
@@ -202,7 +202,7 @@
 	/* Verify and set frame length */
 
 	/* remove padding we might have added before */
-	frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+	frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN;
 
 	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
 		return -EINVAL;
diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c
index 7adceb2..7e2b1a6 100644
--- a/drivers/net/wireless/ath5k/dma.c
+++ b/drivers/net/wireless/ath5k/dma.c
@@ -472,9 +472,6 @@
  *
  * NOTE: We use read-and-clear register, so after this function is called ISR
  * is zeroed.
- *
- * XXX: Why filter interrupts in sw with interrupt_mask ? No benefit at all
- * plus it can be misleading (one might thing that we save interrupts this way)
  */
 int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
 {
@@ -494,11 +491,16 @@
 		}
 	} else {
 		/*
-		 * Read interrupt status from the Read-And-Clear
-		 * shadow register.
+		 * Read interrupt status from Interrupt
+		 * Status Register shadow copy (Read And Clear)
+		 *
 		 * Note: PISR/SISR Not available on 5210
 		 */
 		data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
+		if (unlikely(data == AR5K_INT_NOCARD)) {
+			*interrupt_mask = data;
+			return -ENODEV;
+		}
 	}
 
 	/*
@@ -506,17 +508,9 @@
 	 */
 	*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
 
-	if (unlikely(data == AR5K_INT_NOCARD))
-		return -ENODEV;
-
-	if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR))
-		*interrupt_mask |= AR5K_INT_RX;
-
-	if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR
-		| AR5K_ISR_TXDESC | AR5K_ISR_TXEOL))
-		*interrupt_mask |= AR5K_INT_TX;
-
 	if (ah->ah_version != AR5K_AR5210) {
+		u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2);
+
 		/*HIU = Host Interface Unit (PCI etc)*/
 		if (unlikely(data & (AR5K_ISR_HIUERR)))
 			*interrupt_mask |= AR5K_INT_FATAL;
@@ -524,24 +518,93 @@
 		/*Beacon Not Ready*/
 		if (unlikely(data & (AR5K_ISR_BNR)))
 			*interrupt_mask |= AR5K_INT_BNR;
-	}
 
-	/*
-	 * XXX: BMISS interrupts may occur after association.
-	 * I found this on 5210 code but it needs testing. If this is
-	 * true we should disable them before assoc and re-enable them
-	 * after a successfull assoc + some jiffies.
-	 */
-#if 0
-	interrupt_mask &= ~AR5K_INT_BMISS;
-#endif
+		if (unlikely(sisr2 & (AR5K_SISR2_SSERR |
+					AR5K_SISR2_DPERR |
+					AR5K_SISR2_MCABT)))
+			*interrupt_mask |= AR5K_INT_FATAL;
+
+		if (data & AR5K_ISR_TIM)
+			*interrupt_mask |= AR5K_INT_TIM;
+
+		if (data & AR5K_ISR_BCNMISC) {
+			if (sisr2 & AR5K_SISR2_TIM)
+				*interrupt_mask |= AR5K_INT_TIM;
+			if (sisr2 & AR5K_SISR2_DTIM)
+				*interrupt_mask |= AR5K_INT_DTIM;
+			if (sisr2 & AR5K_SISR2_DTIM_SYNC)
+				*interrupt_mask |= AR5K_INT_DTIM_SYNC;
+			if (sisr2 & AR5K_SISR2_BCN_TIMEOUT)
+				*interrupt_mask |= AR5K_INT_BCN_TIMEOUT;
+			if (sisr2 & AR5K_SISR2_CAB_TIMEOUT)
+				*interrupt_mask |= AR5K_INT_CAB_TIMEOUT;
+		}
+
+		if (data & AR5K_ISR_RXDOPPLER)
+			*interrupt_mask |= AR5K_INT_RX_DOPPLER;
+		if (data & AR5K_ISR_QCBRORN) {
+			*interrupt_mask |= AR5K_INT_QCBRORN;
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
+					AR5K_SISR3_QCBRORN);
+		}
+		if (data & AR5K_ISR_QCBRURN) {
+			*interrupt_mask |= AR5K_INT_QCBRURN;
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
+					AR5K_SISR3_QCBRURN);
+		}
+		if (data & AR5K_ISR_QTRIG) {
+			*interrupt_mask |= AR5K_INT_QTRIG;
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR4),
+					AR5K_SISR4_QTRIG);
+		}
+
+		if (data & AR5K_ISR_TXOK)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
+					AR5K_SISR0_QCU_TXOK);
+
+		if (data & AR5K_ISR_TXDESC)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
+					AR5K_SISR0_QCU_TXDESC);
+
+		if (data & AR5K_ISR_TXERR)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
+					AR5K_SISR1_QCU_TXERR);
+
+		if (data & AR5K_ISR_TXEOL)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
+					AR5K_SISR1_QCU_TXEOL);
+
+		if (data & AR5K_ISR_TXURN)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR2),
+					AR5K_SISR2_QCU_TXURN);
+	} else {
+		if (unlikely(data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT
+				| AR5K_ISR_HIUERR | AR5K_ISR_DPERR)))
+			*interrupt_mask |= AR5K_INT_FATAL;
+
+		/*
+		 * XXX: BMISS interrupts may occur after association.
+		 * I found this on 5210 code but it needs testing. If this is
+		 * true we should disable them before assoc and re-enable them
+		 * after a successfull assoc + some jiffies.
+			interrupt_mask &= ~AR5K_INT_BMISS;
+		 */
+	}
 
 	/*
 	 * In case we didn't handle anything,
 	 * print the register value.
 	 */
 	if (unlikely(*interrupt_mask == 0 && net_ratelimit()))
-		ATH5K_PRINTF("0x%08x\n", data);
+		ATH5K_PRINTF("ISR: 0x%08x IMR: 0x%08x\n", data, ah->ah_imr);
 
 	return 0;
 }
@@ -560,14 +623,17 @@
 {
 	enum ath5k_int old_mask, int_mask;
 
+	old_mask = ah->ah_imr;
+
 	/*
 	 * Disable card interrupts to prevent any race conditions
-	 * (they will be re-enabled afterwards).
+	 * (they will be re-enabled afterwards if AR5K_INT GLOBAL
+	 * is set again on the new mask).
 	 */
-	ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
-	ath5k_hw_reg_read(ah, AR5K_IER);
-
-	old_mask = ah->ah_imr;
+	if (old_mask & AR5K_INT_GLOBAL) {
+		ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
+		ath5k_hw_reg_read(ah, AR5K_IER);
+	}
 
 	/*
 	 * Add additional, chipset-dependent interrupt mask flags
@@ -575,30 +641,64 @@
 	 */
 	int_mask = new_mask & AR5K_INT_COMMON;
 
-	if (new_mask & AR5K_INT_RX)
-		int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN |
-			AR5K_IMR_RXDESC;
-
-	if (new_mask & AR5K_INT_TX)
-		int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC |
-			AR5K_IMR_TXURN;
-
 	if (ah->ah_version != AR5K_AR5210) {
+		/* Preserve per queue TXURN interrupt mask */
+		u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2)
+				& AR5K_SIMR2_QCU_TXURN;
+
 		if (new_mask & AR5K_INT_FATAL) {
 			int_mask |= AR5K_IMR_HIUERR;
-			AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT |
-					AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR);
+			simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR
+				| AR5K_SIMR2_DPERR);
 		}
+
+		/*Beacon Not Ready*/
+		if (new_mask & AR5K_INT_BNR)
+			int_mask |= AR5K_INT_BNR;
+
+		if (new_mask & AR5K_INT_TIM)
+			int_mask |= AR5K_IMR_TIM;
+
+		if (new_mask & AR5K_INT_TIM)
+			simr2 |= AR5K_SISR2_TIM;
+		if (new_mask & AR5K_INT_DTIM)
+			simr2 |= AR5K_SISR2_DTIM;
+		if (new_mask & AR5K_INT_DTIM_SYNC)
+			simr2 |= AR5K_SISR2_DTIM_SYNC;
+		if (new_mask & AR5K_INT_BCN_TIMEOUT)
+			simr2 |= AR5K_SISR2_BCN_TIMEOUT;
+		if (new_mask & AR5K_INT_CAB_TIMEOUT)
+			simr2 |= AR5K_SISR2_CAB_TIMEOUT;
+
+		if (new_mask & AR5K_INT_RX_DOPPLER)
+			int_mask |= AR5K_IMR_RXDOPPLER;
+
+		/* Note: Per queue interrupt masks
+		 * are set via reset_tx_queue (qcu.c) */
+		ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
+		ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2);
+
+	} else {
+		if (new_mask & AR5K_INT_FATAL)
+			int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT
+				| AR5K_IMR_HIUERR | AR5K_IMR_DPERR);
+
+		ath5k_hw_reg_write(ah, int_mask, AR5K_IMR);
 	}
 
-	ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
+	/* If RXNOFRM interrupt is masked disable it
+	 * by setting AR5K_RXNOFRM to zero */
+	if (!(new_mask & AR5K_INT_RXNOFRM))
+		ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM);
 
 	/* Store new interrupt mask */
 	ah->ah_imr = new_mask;
 
-	/* ..re-enable interrupts */
-	ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
-	ath5k_hw_reg_read(ah, AR5K_IER);
+	/* ..re-enable interrupts if AR5K_INT_GLOBAL is set */
+	if (new_mask & AR5K_INT_GLOBAL) {
+		ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
+		ath5k_hw_reg_read(ah, AR5K_IER);
+	}
 
 	return old_mask;
 }
diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c
index a883839..1cb7edf 100644
--- a/drivers/net/wireless/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath5k/eeprom.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
  * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -63,8 +64,8 @@
 /*
  * Translate binary channel representation in EEPROM to frequency
  */
-static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
-				unsigned int mode)
+static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
+                                 unsigned int mode)
 {
 	u16 val;
 
@@ -72,13 +73,13 @@
 		return bin;
 
 	if (mode == AR5K_EEPROM_MODE_11A) {
-		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
 			val = (5 * bin) + 4800;
 		else
 			val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
 				(bin * 10) + 5100;
 	} else {
-		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
 			val = bin + 2300;
 		else
 			val = bin + 2400;
@@ -88,6 +89,71 @@
 }
 
 /*
+ * Initialize eeprom & capabilities structs
+ */
+static int
+ath5k_eeprom_init_header(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	int ret;
+	u16 val;
+
+	/* Initial TX thermal adjustment values */
+	ee->ee_tx_clip = 4;
+	ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
+	ee->ee_gain_select = 1;
+
+	/*
+	 * Read values from EEPROM and store them in the capability structure
+	 */
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+
+	/* Return if we have an old EEPROM */
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
+		return 0;
+
+#ifdef notyet
+	/*
+	 * Validate the checksum of the EEPROM date. There are some
+	 * devices with invalid EEPROMs.
+	 */
+	for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
+		AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
+		cksum ^= val;
+	}
+	if (cksum != AR5K_EEPROM_INFO_CKSUM) {
+		ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
+		return -EIO;
+	}
+#endif
+
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
+	    ee_ant_gain);
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+	}
+
+	return 0;
+}
+
+
+/*
  * Read antenna infos from eeprom
  */
 static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
@@ -100,7 +166,7 @@
 
 	AR5K_EEPROM_READ(o++, val);
 	ee->ee_switch_settling[mode]	= (val >> 8) & 0x7f;
-	ee->ee_ant_tx_rx[mode]		= (val >> 2) & 0x3f;
+	ee->ee_atn_tx_rx[mode]		= (val >> 2) & 0x3f;
 	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
 
 	AR5K_EEPROM_READ(o++, val);
@@ -157,6 +223,30 @@
 	u16 val;
 	int ret;
 
+	ee->ee_n_piers[mode] = 0;
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		ee->ee_ob[mode][3]		= (val >> 5) & 0x7;
+		ee->ee_db[mode][3]		= (val >> 2) & 0x7;
+		ee->ee_ob[mode][2]		= (val << 1) & 0x7;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_ob[mode][2]		|= (val >> 15) & 0x1;
+		ee->ee_db[mode][2]		= (val >> 12) & 0x7;
+		ee->ee_ob[mode][1]		= (val >> 9) & 0x7;
+		ee->ee_db[mode][1]		= (val >> 6) & 0x7;
+		ee->ee_ob[mode][0]		= (val >> 3) & 0x7;
+		ee->ee_db[mode][0]		= val & 0x7;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+	case AR5K_EEPROM_MODE_11B:
+		ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
+		ee->ee_db[mode][1]		= val & 0x7;
+		break;
+	}
+
 	AR5K_EEPROM_READ(o++, val);
 	ee->ee_tx_end2xlna_enable[mode]	= (val >> 8) & 0xff;
 	ee->ee_thr_62[mode]		= val & 0xff;
@@ -209,8 +299,11 @@
 		AR5K_EEPROM_READ(o++, val);
 		ee->ee_i_gain[mode] |= (val << 3) & 0x38;
 
-		if (mode == AR5K_EEPROM_MODE_11G)
+		if (mode == AR5K_EEPROM_MODE_11G) {
 			ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
+			if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6)
+				ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+		}
 	}
 
 	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
@@ -219,10 +312,77 @@
 		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
 	}
 
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
-	    mode == AR5K_EEPROM_MODE_11G)
-		ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0)
+		goto done;
 
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)
+			break;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_margin_tx_rx[mode] = val & 0x3f;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		AR5K_EEPROM_READ(o++, val);
+
+		ee->ee_pwr_cal_b[0].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		ee->ee_pwr_cal_b[1].freq =
+			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+		if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_pwr_cal_b[2].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		AR5K_EEPROM_READ(o++, val);
+
+		ee->ee_pwr_cal_g[0].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		ee->ee_pwr_cal_g[1].freq =
+			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+		if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_turbo_max_power[mode] = val & 0x7f;
+		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_pwr_cal_g[2].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+			AR5K_EEPROM_READ(o++, val);
+			ee->ee_cck_ofdm_gain_delta = val & 0xff;
+		}
+		break;
+	}
+
+done:
 	/* return new offset */
 	*offset = o;
 
@@ -230,204 +390,944 @@
 }
 
 /*
- * Initialize eeprom & capabilities structs
+ * Read turbo mode information on newer EEPROM versions
  */
-int ath5k_eeprom_init(struct ath5k_hw *ah)
+static int
+ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
+			      u32 *offset, unsigned int mode)
 {
 	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	unsigned int mode, i;
+	u32 o = *offset;
+	u16 val;
 	int ret;
+
+	if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
+		return 0;
+
+	switch (mode){
+	case AR5K_EEPROM_MODE_11A:
+		ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;
+
+		ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3;
+		ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f;
+
+		ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7;
+		ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff;
+
+		if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2)
+			ee->ee_pd_gain_overlap = (val >> 9) & 0xf;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f;
+
+		ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1;
+		ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f;
+
+		ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5;
+		ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff;
+		break;
+	}
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+
+static int
+ath5k_eeprom_init_modes(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 mode_offset[3];
+	unsigned int mode;
+	u32 offset;
+	int ret;
+
+	/*
+	 * Get values for all modes
+	 */
+	mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+	mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+	mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+
+	ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] =
+		AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+
+	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
+		offset = mode_offset[mode];
+
+		ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+		if (ret)
+			return ret;
+
+		ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+		if (ret)
+			return ret;
+
+		ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode);
+		if (ret)
+			return ret;
+	}
+
+	/* override for older eeprom versions for better performance */
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) {
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15;
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28;
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28;
+	}
+
+	return 0;
+}
+
+static inline void
+ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
+{
+	const static u16 intercepts3[] =
+		{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
+	const static u16 intercepts3_2[] =
+		{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
+	const u16 *ip;
+	int i;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2)
+		ip = intercepts3_2;
+	else
+		ip = intercepts3;
+
+	for (i = 0; i < ARRAY_SIZE(intercepts3); i++)
+		*vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100;
+}
+
+static inline int
+ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
+                            struct ath5k_chan_pcal_info *pc, u8 *count)
+{
+	int o = *offset;
+	int i = 0;
+	u8 f1, f2;
+	int ret;
+	u16 val;
+
+	while(i < max) {
+		AR5K_EEPROM_READ(o++, val);
+
+		f1 = (val >> 8) & 0xff;
+		f2 = val & 0xff;
+
+		if (f1)
+			pc[i++].freq = f1;
+
+		if (f2)
+			pc[i++].freq = f2;
+
+		if (!f1 || !f2)
+			break;
+	}
+	*offset = o;
+	*count = i;
+
+	return 0;
+}
+
+static int
+ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a;
+	int i, ret;
+	u16 val;
+	u8 mask;
+
+	if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+		ath5k_eeprom_read_freq_list(ah, &offset,
+			AR5K_EEPROM_N_5GHZ_CHAN, pcal,
+			&ee->ee_n_piers[AR5K_EEPROM_MODE_11A]);
+	} else {
+		mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version);
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[0].freq  = (val >> 9) & mask;
+		pcal[1].freq  = (val >> 2) & mask;
+		pcal[2].freq  = (val << 5) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[2].freq |= (val >> 11) & 0x1f;
+		pcal[3].freq  = (val >> 4) & mask;
+		pcal[4].freq  = (val << 3) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[4].freq |= (val >> 13) & 0x7;
+		pcal[5].freq  = (val >> 6) & mask;
+		pcal[6].freq  = (val << 1) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[6].freq |= (val >> 15) & 0x1;
+		pcal[7].freq  = (val >> 8) & mask;
+		pcal[8].freq  = (val >> 1) & mask;
+		pcal[9].freq  = (val << 6) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[9].freq |= (val >> 10) & 0x3f;
+		ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10;
+	}
+
+	for(i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i += 1) {
+		pcal[i].freq = ath5k_eeprom_bin2freq(ee,
+				pcal[i].freq, AR5K_EEPROM_MODE_11A);
+	}
+
+	return 0;
+}
+
+static inline int
+ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal;
+	int i;
+
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11B:
+		pcal = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		pcal = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ath5k_eeprom_read_freq_list(ah, &offset,
+		AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal,
+		&ee->ee_n_piers[mode]);
+	for(i = 0; i < AR5K_EEPROM_N_2GHZ_CHAN_2413; i += 1) {
+		pcal[i].freq = ath5k_eeprom_bin2freq(ee,
+				pcal[i].freq, mode);
+	}
+
+	return 0;
+}
+
+
+static int
+ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal;
+	int offset, ret;
+	int i, j;
+	u16 val;
+
+	offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+			return 0;
+
+		ret = ath5k_eeprom_init_11a_pcal_freq(ah,
+			offset + AR5K_EEPROM_GROUP1_OFFSET);
+		if (ret < 0)
+			return ret;
+
+		offset += AR5K_EEPROM_GROUP2_OFFSET;
+		pcal = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		if (!AR5K_EEPROM_HDR_11B(ee->ee_header) &&
+		    !AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		pcal = ee->ee_pwr_cal_b;
+		offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+		/* fixed piers */
+		pcal[0].freq = 2412;
+		pcal[1].freq = 2447;
+		pcal[2].freq = 2484;
+		ee->ee_n_piers[mode] = 3;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		pcal = ee->ee_pwr_cal_g;
+		offset += AR5K_EEPROM_GROUP4_OFFSET;
+
+		/* fixed piers */
+		pcal[0].freq = 2312;
+		pcal[1].freq = 2412;
+		pcal[2].freq = 2484;
+		ee->ee_n_piers[mode] = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		struct ath5k_chan_pcal_info_rf5111 *cdata =
+			&pcal[i].rf5111_info;
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M);
+		cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M);
+		cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[0] |= ((val >> 14) & 0x3);
+		cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[3] |= ((val >> 12) & 0xf);
+		cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[5] = (val  & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[8] |= ((val >> 14) & 0x3);
+		cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+
+		ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min,
+			cdata->pcdac_max, cdata->pcdac);
+
+		for (j = 0; j < AR5K_EEPROM_N_PCDAC; j++) {
+			cdata->pwr[j] = (u16)
+				(AR5K_EEPROM_POWER_STEP * cdata->pwr[j]);
+		}
+	}
+
+	return 0;
+}
+
+static int
+ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info;
+	struct ath5k_chan_pcal_info *gen_chan_info;
+	u32 offset;
+	unsigned int i, c;
+	u16 val;
+	int ret;
+
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		/*
+		 * Read 5GHz EEPROM channels
+		 */
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+
+		offset += AR5K_EEPROM_GROUP2_OFFSET;
+		gen_chan_info = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+		/* NB: frequency piers parsed during mode init */
+		gen_chan_info = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP4_OFFSET;
+		else if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP2_OFFSET;
+
+		/* NB: frequency piers parsed during mode init */
+		gen_chan_info = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		chan_pcal_info = &gen_chan_info[i].rf5112_info;
+
+		/* Power values in dBm * 4
+		 * for the lower xpd gain curve
+		 * (0 dBm -> higher output power) */
+		for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr_x0[c] = (val & 0xff);
+			chan_pcal_info->pwr_x0[++c] = ((val >> 8) & 0xff);
+		}
+
+		/* PCDAC steps
+		 * corresponding to the above power
+		 * measurements */
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pcdac_x0[1] = (val & 0x1f);
+		chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f);
+		chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f);
+
+		/* Power values in dBm * 4
+		 * for the higher xpd gain curve
+		 * (18 dBm -> lower output power) */
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pwr_x3[0] = (val & 0xff);
+		chan_pcal_info->pwr_x3[1] = ((val >> 8) & 0xff);
+
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pwr_x3[2] = (val & 0xff);
+
+		/* PCDAC steps
+		 * corresponding to the above power
+		 * measurements (static) */
+		chan_pcal_info->pcdac_x3[0] = 20;
+		chan_pcal_info->pcdac_x3[1] = 35;
+		chan_pcal_info->pcdac_x3[2] = 63;
+
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) {
+			chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0xff);
+
+			/* Last xpd0 power level is also channel maximum */
+			gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3];
+		} else {
+			chan_pcal_info->pcdac_x0[0] = 1;
+			gen_chan_info[i].max_pwr = ((val >> 8) & 0xff);
+		}
+
+		/* Recreate pcdac_x0 table for this channel using pcdac steps */
+		chan_pcal_info->pcdac_x0[1] += chan_pcal_info->pcdac_x0[0];
+		chan_pcal_info->pcdac_x0[2] += chan_pcal_info->pcdac_x0[1];
+		chan_pcal_info->pcdac_x0[3] += chan_pcal_info->pcdac_x0[2];
+	}
+
+	return 0;
+}
+
+static inline unsigned int
+ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode)
+{
+	static const unsigned int pdgains_size[] = { 4, 6, 9, 12 };
+	unsigned int sz;
+
+	sz = pdgains_size[ee->ee_pd_gains[mode] - 1];
+	sz *= ee->ee_n_piers[mode];
+
+	return sz;
+}
+
+static unsigned int
+ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
+{
+	u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4);
+
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11G:
+		if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+			offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + 2;
+		/* fall through */
+	case AR5K_EEPROM_MODE_11B:
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + 5;
+		/* fall through */
+	case AR5K_EEPROM_MODE_11A:
+		break;
+	default:
+		break;
+	}
+
+	return offset;
+}
+
+static int
+ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info;
+	struct ath5k_chan_pcal_info *gen_chan_info;
+	unsigned int i, c;
+	u32 offset;
+	int ret;
+	u16 val;
+	u8 pd_gains = 0;
+
+	if (ee->ee_x_gain[mode] & 0x1) pd_gains++;
+	if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++;
+	if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++;
+	if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++;
+	ee->ee_pd_gains[mode] = pd_gains;
+
+	offset = ath5k_cal_data_offset_2413(ee, mode);
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+			return 0;
+
+		ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+		offset += AR5K_EEPROM_N_5GHZ_CHAN / 2;
+		gen_chan_info = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
+			return 0;
+
+		ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+		offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+		gen_chan_info = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+		offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+		gen_chan_info = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (pd_gains == 0)
+		return 0;
+
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		chan_pcal_info = &gen_chan_info[i].rf2413_info;
+
+		/*
+		 * Read pwr_i, pddac_i and the first
+		 * 2 pd points (pwr, pddac)
+		 */
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pwr_i[0] = val & 0x1f;
+		chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f;
+		chan_pcal_info->pwr[0][0] =
+					(val >> 12) & 0xf;
+
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pddac[0][0] = val & 0x3f;
+		chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf;
+		chan_pcal_info->pddac[0][1] =
+					(val >> 10) & 0x3f;
+
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pwr[0][2] = val & 0xf;
+		chan_pcal_info->pddac[0][2] =
+					(val >> 4) & 0x3f;
+
+		chan_pcal_info->pwr[0][3] = 0;
+		chan_pcal_info->pddac[0][3] = 0;
+
+		if (pd_gains > 1) {
+			/*
+			 * Pd gain 0 is not the last pd gain
+			 * so it only has 2 pd points.
+			 * Continue wih pd gain 1.
+			 */
+			chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f;
+
+			chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1;
+
+			chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf;
+			chan_pcal_info->pddac[1][0] =
+						(val >> 10) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr[1][1] = val & 0xf;
+			chan_pcal_info->pddac[1][1] =
+						(val >> 4) & 0x3f;
+			chan_pcal_info->pwr[1][2] =
+						(val >> 10) & 0xf;
+
+			chan_pcal_info->pddac[1][2] =
+						(val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pddac[1][2] |=
+						(val & 0xF) << 2;
+
+			chan_pcal_info->pwr[1][3] = 0;
+			chan_pcal_info->pddac[1][3] = 0;
+		} else if (pd_gains == 1) {
+			/*
+			 * Pd gain 0 is the last one so
+			 * read the extra point.
+			 */
+			chan_pcal_info->pwr[0][3] =
+						(val >> 10) & 0xf;
+
+			chan_pcal_info->pddac[0][3] =
+						(val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pddac[0][3] |=
+						(val & 0xF) << 2;
+		}
+
+		/*
+		 * Proceed with the other pd_gains
+		 * as above.
+		 */
+		if (pd_gains > 2) {
+			chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f;
+			chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f;
+
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr[2][0] =
+						(val >> 0) & 0xf;
+			chan_pcal_info->pddac[2][0] =
+						(val >> 4) & 0x3f;
+			chan_pcal_info->pwr[2][1] =
+						(val >> 10) & 0xf;
+
+			chan_pcal_info->pddac[2][1] =
+						(val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pddac[2][1] |=
+						(val & 0xF) << 2;
+
+			chan_pcal_info->pwr[2][2] =
+						(val >> 4) & 0xf;
+			chan_pcal_info->pddac[2][2] =
+						(val >> 8) & 0x3f;
+
+			chan_pcal_info->pwr[2][3] = 0;
+			chan_pcal_info->pddac[2][3] = 0;
+		} else if (pd_gains == 2) {
+			chan_pcal_info->pwr[1][3] =
+						(val >> 4) & 0xf;
+			chan_pcal_info->pddac[1][3] =
+						(val >> 8) & 0x3f;
+		}
+
+		if (pd_gains > 3) {
+			chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2;
+
+			chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f;
+			chan_pcal_info->pwr[3][0] =
+						(val >> 10) & 0xf;
+			chan_pcal_info->pddac[3][0] =
+						(val >> 14) & 0x3;
+
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pddac[3][0] |=
+						(val & 0xF) << 2;
+			chan_pcal_info->pwr[3][1] =
+						(val >> 4) & 0xf;
+			chan_pcal_info->pddac[3][1] =
+						(val >> 8) & 0x3f;
+
+			chan_pcal_info->pwr[3][2] =
+						(val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr[3][2] |=
+						((val >> 0) & 0x3) << 2;
+
+			chan_pcal_info->pddac[3][2] =
+						(val >> 2) & 0x3f;
+			chan_pcal_info->pwr[3][3] =
+						(val >> 8) & 0xf;
+
+			chan_pcal_info->pddac[3][3] =
+						(val >> 12) & 0xF;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pddac[3][3] |=
+						((val >> 0) & 0x3) << 4;
+		} else if (pd_gains == 3) {
+			chan_pcal_info->pwr[2][3] =
+						(val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr[2][3] |=
+						((val >> 0) & 0x3) << 2;
+
+			chan_pcal_info->pddac[2][3] =
+						(val >> 2) & 0x3f;
+		}
+
+		for (c = 0; c < pd_gains; c++) {
+			/* Recreate pwr table for this channel using pwr steps */
+			chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2;
+			chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0];
+			chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1];
+			chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2];
+			if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2])
+				chan_pcal_info->pwr[c][3] = 0;
+
+			/* Recreate pddac table for this channel using pddac steps */
+			chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c];
+			chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0];
+			chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1];
+			chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2];
+			if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2])
+				chan_pcal_info->pddac[c][3] = 0;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Read per rate target power (this is the maximum tx power
+ * supported by the card). This info is used when setting
+ * tx power, no matter the channel.
+ *
+ * This also works for v5 EEPROMs.
+ */
+static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_rate_pcal_info *rate_pcal_info;
+	u16 *rate_target_pwr_num;
+	u32 offset;
+	u16 val;
+	int ret, i;
+
+	offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1);
+	rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode];
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_a;
+		ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_b;
+		ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_g;
+		ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Different freq mask for older eeproms (<= v3.2) */
+	if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) {
+		for (i = 0; i < (*rate_target_pwr_num); i++) {
+			AR5K_EEPROM_READ(offset++, val);
+			rate_pcal_info[i].freq =
+			    ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);
+
+			rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);
+			rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+
+			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+			    val == 0) {
+				(*rate_target_pwr_num) = i;
+				break;
+			}
+
+			rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);
+			rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);
+			rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);
+		}
+	} else {
+		for (i = 0; i < (*rate_target_pwr_num); i++) {
+			AR5K_EEPROM_READ(offset++, val);
+			rate_pcal_info[i].freq =
+			    ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+
+			rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);
+			rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+
+			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+			    val == 0) {
+				(*rate_target_pwr_num) = i;
+				break;
+			}
+
+			rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;
+			rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);
+			rate_pcal_info[i].target_power_54 = (val & 0x3f);
+		}
+	}
+
+	return 0;
+}
+
+static int
+ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	int (*read_pcal)(struct ath5k_hw *hw, int mode);
+	int mode;
+	int err;
+
+	if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) &&
+			(AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1))
+		read_pcal = ath5k_eeprom_read_pcal_info_5112;
+	else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) &&
+			(AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2))
+		read_pcal = ath5k_eeprom_read_pcal_info_2413;
+	else
+		read_pcal = ath5k_eeprom_read_pcal_info_5111;
+
+	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
+		err = read_pcal(ah, mode);
+		if (err)
+			return err;
+
+		err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+/* Read conformance test limits */
+static int
+ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_edge_power *rep;
+	unsigned int fmask, pmask;
+	unsigned int ctl_mode;
+	int ret, i, j;
 	u32 offset;
 	u16 val;
 
-	/* Initial TX thermal adjustment values */
-	ee->ee_tx_clip = 4;
-	ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
-	ee->ee_gain_select = 1;
-
-	/*
-	 * Read values from EEPROM and store them in the capability structure
-	 */
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
-
-	/* Return if we have an old EEPROM */
-	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
-		return 0;
-
-#ifdef notyet
-	/*
-	 * Validate the checksum of the EEPROM date. There are some
-	 * devices with invalid EEPROMs.
-	 */
-	for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
-		AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
-		cksum ^= val;
-	}
-	if (cksum != AR5K_EEPROM_INFO_CKSUM) {
-		ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
-		return -EIO;
-	}
-#endif
-
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
-	    ee_ant_gain);
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
-		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
-		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
-	}
-
-	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
-		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
-		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
-		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
-
-		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
-		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
-		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
-	}
-
-	/*
-	 * Get conformance test limit values
-	 */
-	offset = AR5K_EEPROM_CTL(ah->ah_ee_version);
-	ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version);
-
-	for (i = 0; i < ee->ee_ctls; i++) {
+	pmask = AR5K_EEPROM_POWER_M;
+	fmask = AR5K_EEPROM_FREQ_M(ee->ee_version);
+	offset = AR5K_EEPROM_CTL(ee->ee_version);
+	ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version);
+	for (i = 0; i < ee->ee_ctls; i += 2) {
 		AR5K_EEPROM_READ(offset++, val);
 		ee->ee_ctl[i] = (val >> 8) & 0xff;
 		ee->ee_ctl[i + 1] = val & 0xff;
 	}
 
-	/*
-	 * Get values for 802.11a (5GHz)
-	 */
-	mode = AR5K_EEPROM_MODE_11A;
+	offset = AR5K_EEPROM_GROUP8_OFFSET;
+	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)
+		offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) -
+			AR5K_EEPROM_GROUP5_OFFSET;
+	else
+		offset += AR5K_EEPROM_GROUPS_START(ee->ee_version);
 
-	ee->ee_turbo_max_power[mode] =
-			AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
-
-	offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
-
-	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
-	ee->ee_ob[mode][3]		= (val >> 5) & 0x7;
-	ee->ee_db[mode][3]		= (val >> 2) & 0x7;
-	ee->ee_ob[mode][2]		= (val << 1) & 0x7;
-
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_ob[mode][2]		|= (val >> 15) & 0x1;
-	ee->ee_db[mode][2]		= (val >> 12) & 0x7;
-	ee->ee_ob[mode][1]		= (val >> 9) & 0x7;
-	ee->ee_db[mode][1]		= (val >> 6) & 0x7;
-	ee->ee_ob[mode][0]		= (val >> 3) & 0x7;
-	ee->ee_db[mode][0]		= val & 0x7;
-
-	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_margin_tx_rx[mode] = val & 0x3f;
-	}
-
-	/*
-	 * Get values for 802.11b (2.4GHz)
-	 */
-	mode = AR5K_EEPROM_MODE_11B;
-	offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
-
-	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
-	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
-	ee->ee_db[mode][1]		= val & 0x7;
-
-	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][0] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
-		ee->ee_cal_pier[mode][1] =
-			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
-
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][2] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
-	}
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
-		ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
-
-	/*
-	 * Get values for 802.11g (2.4GHz)
-	 */
-	mode = AR5K_EEPROM_MODE_11G;
-	offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
-
-	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	AR5K_EEPROM_READ(offset++, val);
-	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
-	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
-	ee->ee_db[mode][1]		= val & 0x7;
-
-	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
-	if (ret)
-		return ret;
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][0] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
-		ee->ee_cal_pier[mode][1] =
-			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
-
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_turbo_max_power[mode] = val & 0x7f;
-		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
-
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_cal_pier[mode][2] =
-			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
-
-		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
-			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
-
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
-		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
-
-		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
-			AR5K_EEPROM_READ(offset++, val);
-			ee->ee_cck_ofdm_gain_delta = val & 0xff;
+	rep = ee->ee_ctl_pwr;
+	for(i = 0; i < ee->ee_ctls; i++) {
+		switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
+		case AR5K_CTL_11A:
+		case AR5K_CTL_TURBO:
+			ctl_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		default:
+			ctl_mode = AR5K_EEPROM_MODE_11G;
+			break;
 		}
-	}
+		if (ee->ee_ctl[i] == 0) {
+			if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3)
+				offset += 8;
+			else
+				offset += 7;
+			rep += AR5K_EEPROM_N_EDGES;
+			continue;
+		}
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+			for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+				AR5K_EEPROM_READ(offset++, val);
+				rep[j].freq = (val >> 8) & fmask;
+				rep[j + 1].freq = val & fmask;
+			}
+			for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+				AR5K_EEPROM_READ(offset++, val);
+				rep[j].edge = (val >> 8) & pmask;
+				rep[j].flag = (val >> 14) & 1;
+				rep[j + 1].edge = val & pmask;
+				rep[j + 1].flag = (val >> 6) & 1;
+			}
+		} else {
+			AR5K_EEPROM_READ(offset++, val);
+			rep[0].freq = (val >> 9) & fmask;
+			rep[1].freq = (val >> 2) & fmask;
+			rep[2].freq = (val << 5) & fmask;
 
-	/*
-	 * Read 5GHz EEPROM channels
-	 */
+			AR5K_EEPROM_READ(offset++, val);
+			rep[2].freq |= (val >> 11) & 0x1f;
+			rep[3].freq = (val >> 4) & fmask;
+			rep[4].freq = (val << 3) & fmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[4].freq |= (val >> 13) & 0x7;
+			rep[5].freq = (val >> 6) & fmask;
+			rep[6].freq = (val << 1) & fmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[6].freq |= (val >> 15) & 0x1;
+			rep[7].freq = (val >> 8) & fmask;
+
+			rep[0].edge = (val >> 2) & pmask;
+			rep[1].edge = (val << 4) & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[1].edge |= (val >> 12) & 0xf;
+			rep[2].edge = (val >> 6) & pmask;
+			rep[3].edge = val & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[4].edge = (val >> 10) & pmask;
+			rep[5].edge = (val >> 4) & pmask;
+			rep[6].edge = (val << 2) & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[6].edge |= (val >> 14) & 0x3;
+			rep[7].edge = (val >> 8) & pmask;
+		}
+		for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) {
+			rep[j].freq = ath5k_eeprom_bin2freq(ee,
+				rep[j].freq, ctl_mode);
+		}
+		rep += AR5K_EEPROM_N_EDGES;
+	}
 
 	return 0;
 }
 
+
+/*
+ * Initialize eeprom power tables
+ */
+int
+ath5k_eeprom_init(struct ath5k_hw *ah)
+{
+	int err;
+
+	err = ath5k_eeprom_init_header(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_init_modes(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_read_pcal_info(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_read_ctl_info(ah);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
 /*
  * Read the MAC address from eeprom
  */
diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h
index a468ecf..09eb7d0 100644
--- a/drivers/net/wireless/ath5k/eeprom.h
+++ b/drivers/net/wireless/ath5k/eeprom.h
@@ -25,6 +25,128 @@
 #define AR5K_EEPROM_MAGIC_5211		0x0000145b /* 5211 */
 #define AR5K_EEPROM_MAGIC_5210		0x0000145a /* 5210 */
 
+#define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
+#define AR5K_EEPROM_CHECKSUM		0x00c0	/* EEPROM checksum */
+#define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
+#define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
+#define AR5K_EEPROM_INFO_CKSUM		0xffff
+#define AR5K_EEPROM_INFO(_n)		(AR5K_EEPROM_INFO_BASE + (_n))
+
+#define AR5K_EEPROM_VERSION		AR5K_EEPROM_INFO(1)	/* EEPROM Version */
+#define AR5K_EEPROM_VERSION_3_0		0x3000	/* No idea what's going on before this version */
+#define AR5K_EEPROM_VERSION_3_1		0x3001	/* ob/db values for 2Ghz (ar5211_rfregs) */
+#define AR5K_EEPROM_VERSION_3_2		0x3002	/* different frequency representation (eeprom_bin2freq) */
+#define AR5K_EEPROM_VERSION_3_3		0x3003	/* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain, ee_cck_ofdm_power_delta (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_1		0x4001	/* has ee_margin_tx_rx (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_2		0x4002	/* has ee_cck_ofdm_gain_delta (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_3		0x4003	/* power calibration changes */
+#define AR5K_EEPROM_VERSION_4_4		0x4004
+#define AR5K_EEPROM_VERSION_4_5		0x4005
+#define AR5K_EEPROM_VERSION_4_6		0x4006	/* has ee_scaled_cck_delta */
+#define AR5K_EEPROM_VERSION_4_7		0x3007	/* 4007 ? */
+#define AR5K_EEPROM_VERSION_4_9		0x4009	/* EAR futureproofing */
+#define AR5K_EEPROM_VERSION_5_0		0x5000	/* Has 2413 PDADC calibration etc */
+#define AR5K_EEPROM_VERSION_5_1		0x5001	/* Has capability values */
+#define AR5K_EEPROM_VERSION_5_3		0x5003	/* Has spur mitigation tables */
+
+#define AR5K_EEPROM_MODE_11A		0
+#define AR5K_EEPROM_MODE_11B		1
+#define AR5K_EEPROM_MODE_11G		2
+
+#define AR5K_EEPROM_HDR			AR5K_EEPROM_INFO(2)	/* Header that contains the device caps */
+#define AR5K_EEPROM_HDR_11A(_v)		(((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
+#define AR5K_EEPROM_HDR_11B(_v)		(((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
+#define AR5K_EEPROM_HDR_11G(_v)		(((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
+#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2Ghz (?) */
+#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
+#define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
+#define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
+#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz */
+
+#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
+#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
+#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
+#define AR5K_EEPROM_RFKILL_POLARITY_S	1
+
+/* Newer EEPROMs are using a different offset */
+#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
+	(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
+
+#define AR5K_EEPROM_ANT_GAIN(_v)	AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
+#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((s8)(((_v) >> 8) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((s8)((_v) & 0xff))
+
+/* Misc values available since EEPROM 4.0 */
+#define AR5K_EEPROM_MISC0		AR5K_EEPROM_INFO(4)
+#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
+#define AR5K_EEPROM_HDR_XR2_DIS(_v)	(((_v) >> 12) & 0x1)
+#define AR5K_EEPROM_HDR_XR5_DIS(_v)	(((_v) >> 13) & 0x1)
+#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
+
+#define AR5K_EEPROM_MISC1			AR5K_EEPROM_INFO(5)
+#define AR5K_EEPROM_TARGET_PWRSTART(_v)		((_v) & 0xfff)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)		(((_v) >> 14) & 0x1)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v)	(((_v) >> 15) & 0x1)
+
+#define AR5K_EEPROM_MISC2			AR5K_EEPROM_INFO(6)
+#define AR5K_EEPROM_EEP_FILE_VERSION(_v)	(((_v) >> 8) & 0xff)
+#define AR5K_EEPROM_EAR_FILE_VERSION(_v)	((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC3		AR5K_EEPROM_INFO(7)
+#define AR5K_EEPROM_ART_BUILD_NUM(_v)	(((_v) >> 10) & 0x3f)
+#define AR5K_EEPROM_EAR_FILE_ID(_v)	((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC4		AR5K_EEPROM_INFO(8)
+#define AR5K_EEPROM_CAL_DATA_START(_v)	(((_v) >> 4) & 0xfff)
+#define AR5K_EEPROM_MASK_R0(_v)		(((_v) >> 2) & 0x3)
+#define AR5K_EEPROM_MASK_R1(_v)		((_v) & 0x3)
+
+#define AR5K_EEPROM_MISC5		AR5K_EEPROM_INFO(9)
+#define AR5K_EEPROM_COMP_DIS(_v)	((_v) & 0x1)
+#define AR5K_EEPROM_AES_DIS(_v)		(((_v) >> 1) & 0x1)
+#define AR5K_EEPROM_FF_DIS(_v)		(((_v) >> 2) & 0x1)
+#define AR5K_EEPROM_BURST_DIS(_v)	(((_v) >> 3) & 0x1)
+#define AR5K_EEPROM_MAX_QCU(_v)		(((_v) >> 4) & 0xf)
+#define AR5K_EEPROM_HEAVY_CLIP_EN(_v)	(((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_KEY_CACHE_SIZE(_v)	(((_v) >> 12) & 0xf)
+
+#define AR5K_EEPROM_MISC6		AR5K_EEPROM_INFO(10)
+#define AR5K_EEPROM_TX_CHAIN_DIS	((_v) & 0x8)
+#define AR5K_EEPROM_RX_CHAIN_DIS	(((_v) >> 3) & 0x8)
+#define AR5K_EEPROM_FCC_MID_EN		(((_v) >> 6) & 0x1)
+#define AR5K_EEPROM_JAP_U1EVEN_EN	(((_v) >> 7) & 0x1)
+#define AR5K_EEPROM_JAP_U2_EN		(((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_JAP_U1ODD_EN	(((_v) >> 9) & 0x1)
+#define AR5K_EEPROM_JAP_11A_NEW_EN	(((_v) >> 10) & 0x1)
+
+/* calibration settings */
+#define AR5K_EEPROM_MODES_11A(_v)	AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
+#define AR5K_EEPROM_MODES_11B(_v)	AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
+#define AR5K_EEPROM_MODES_11G(_v)	AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
+#define AR5K_EEPROM_CTL(_v)		AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)	/* Conformance test limits */
+#define AR5K_EEPROM_GROUPS_START(_v)	AR5K_EEPROM_OFF(_v, 0x0100, 0x0150)	/* Start of Groups */
+#define AR5K_EEPROM_GROUP1_OFFSET	0x0
+#define AR5K_EEPROM_GROUP2_OFFSET	0x5
+#define AR5K_EEPROM_GROUP3_OFFSET	0x37
+#define AR5K_EEPROM_GROUP4_OFFSET	0x46
+#define AR5K_EEPROM_GROUP5_OFFSET	0x55
+#define AR5K_EEPROM_GROUP6_OFFSET	0x65
+#define AR5K_EEPROM_GROUP7_OFFSET	0x69
+#define AR5K_EEPROM_GROUP8_OFFSET	0x6f
+
+#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP5_OFFSET, 0x0000)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP6_OFFSET, 0x0010)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP7_OFFSET, 0x0014)
+
+/* [3.1 - 3.3] */
+#define AR5K_EEPROM_OBDB0_2GHZ		0x00ec
+#define AR5K_EEPROM_OBDB1_2GHZ		0x00ed
+
 #define AR5K_EEPROM_PROTECT		0x003f	/* EEPROM protect status */
 #define AR5K_EEPROM_PROTECT_RD_0_31	0x0001	/* Read protection bit for offsets 0x0 - 0x1f */
 #define AR5K_EEPROM_PROTECT_WR_0_31	0x0002	/* Write protection bit for offsets 0x0 - 0x1f */
@@ -42,72 +164,6 @@
 #define AR5K_EEPROM_PROTECT_WR_224_239	0x2000
 #define AR5K_EEPROM_PROTECT_RD_240_255	0x4000	/* 0xf0 - 0xff */
 #define AR5K_EEPROM_PROTECT_WR_240_255	0x8000
-#define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
-#define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
-#define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
-#define AR5K_EEPROM_INFO_CKSUM		0xffff
-#define AR5K_EEPROM_INFO(_n)		(AR5K_EEPROM_INFO_BASE + (_n))
-
-#define AR5K_EEPROM_VERSION		AR5K_EEPROM_INFO(1)	/* EEPROM Version */
-#define AR5K_EEPROM_VERSION_3_0		0x3000	/* No idea what's going on before this version */
-#define AR5K_EEPROM_VERSION_3_1		0x3001	/* ob/db values for 2Ghz (ar5211_rfregs) */
-#define AR5K_EEPROM_VERSION_3_2		0x3002	/* different frequency representation (eeprom_bin2freq) */
-#define AR5K_EEPROM_VERSION_3_3		0x3003	/* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_1		0x4001	/* has ee_margin_tx_rx (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_2		0x4002	/* has ee_cck_ofdm_gain_delta (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_3		0x4003
-#define AR5K_EEPROM_VERSION_4_4		0x4004
-#define AR5K_EEPROM_VERSION_4_5		0x4005
-#define AR5K_EEPROM_VERSION_4_6		0x4006	/* has ee_scaled_cck_delta */
-#define AR5K_EEPROM_VERSION_4_7		0x4007
-
-#define AR5K_EEPROM_MODE_11A		0
-#define AR5K_EEPROM_MODE_11B		1
-#define AR5K_EEPROM_MODE_11G		2
-
-#define AR5K_EEPROM_HDR			AR5K_EEPROM_INFO(2)	/* Header that contains the device caps */
-#define AR5K_EEPROM_HDR_11A(_v)		(((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
-#define AR5K_EEPROM_HDR_11B(_v)		(((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
-#define AR5K_EEPROM_HDR_11G(_v)		(((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
-#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2Ghz (?) */
-#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
-#define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
-#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz (?) */
-#define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
-
-#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
-#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
-#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
-#define AR5K_EEPROM_RFKILL_POLARITY_S	1
-
-/* Newer EEPROMs are using a different offset */
-#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
-	(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
-
-#define AR5K_EEPROM_ANT_GAIN(_v)	AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
-#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((int8_t)(((_v) >> 8) & 0xff))
-#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((int8_t)((_v) & 0xff))
-
-/* calibration settings */
-#define AR5K_EEPROM_MODES_11A(_v)	AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
-#define AR5K_EEPROM_MODES_11B(_v)	AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
-#define AR5K_EEPROM_MODES_11G(_v)	AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
-#define AR5K_EEPROM_CTL(_v)		AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)	/* Conformance test limits */
-
-/* [3.1 - 3.3] */
-#define AR5K_EEPROM_OBDB0_2GHZ		0x00ec
-#define AR5K_EEPROM_OBDB1_2GHZ		0x00ed
-
-/* Misc values available since EEPROM 4.0 */
-#define AR5K_EEPROM_MISC0		0x00c4
-#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
-#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
-#define AR5K_EEPROM_MISC1		0x00c5
-#define AR5K_EEPROM_TARGET_PWRSTART(_v)	((_v) & 0xfff)
-#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)	(((_v) >> 14) & 0x1)
-
 
 /* Some EEPROM defines */
 #define AR5K_EEPROM_EEP_SCALE		100
@@ -115,8 +171,11 @@
 #define AR5K_EEPROM_N_MODES		3
 #define AR5K_EEPROM_N_5GHZ_CHAN		10
 #define AR5K_EEPROM_N_2GHZ_CHAN		3
+#define AR5K_EEPROM_N_2GHZ_CHAN_2413	4
 #define AR5K_EEPROM_MAX_CHAN		10
+#define AR5K_EEPROM_N_PWR_POINTS_5111	11
 #define AR5K_EEPROM_N_PCDAC		11
+#define AR5K_EEPROM_N_PHASE_CAL		5
 #define AR5K_EEPROM_N_TEST_FREQ		8
 #define AR5K_EEPROM_N_EDGES		8
 #define AR5K_EEPROM_N_INTERCEPTS	11
@@ -136,6 +195,8 @@
 #define AR5K_EEPROM_N_XPD_PER_CHANNEL	4
 #define AR5K_EEPROM_N_XPD0_POINTS	4
 #define AR5K_EEPROM_N_XPD3_POINTS	3
+#define AR5K_EEPROM_N_PD_GAINS		4
+#define AR5K_EEPROM_N_PD_POINTS		5
 #define AR5K_EEPROM_N_INTERCEPT_10_2GHZ	35
 #define AR5K_EEPROM_N_INTERCEPT_10_5GHZ	55
 #define AR5K_EEPROM_POWER_M		0x3f
@@ -158,8 +219,99 @@
 #define AR5K_EEPROM_READ_HDR(_o, _v)					\
 	AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v);	\
 
-/* Struct to hold EEPROM calibration data */
+enum ath5k_ant_setting {
+	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
+	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
+	AR5K_ANT_FIXED_B	= 2,	/* fixed to 11b frequencies */
+	AR5K_ANT_MAX		= 3,
+};
+
+enum ath5k_ctl_mode {
+	AR5K_CTL_11A = 0,
+	AR5K_CTL_11B = 1,
+	AR5K_CTL_11G = 2,
+	AR5K_CTL_TURBO = 3,
+	AR5K_CTL_108G = 4,
+	AR5K_CTL_2GHT20 = 5,
+	AR5K_CTL_5GHT20 = 6,
+	AR5K_CTL_2GHT40 = 7,
+	AR5K_CTL_5GHT40 = 8,
+	AR5K_CTL_MODE_M = 15,
+};
+
+/* Per channel calibration data, used for power table setup */
+struct ath5k_chan_pcal_info_rf5111 {
+	/* Power levels in half dbm units
+	 * for one power curve. */
+	u8		pwr[AR5K_EEPROM_N_PWR_POINTS_5111];
+	/* PCDAC table steps
+	 * for the above values */
+	u8		pcdac[AR5K_EEPROM_N_PWR_POINTS_5111];
+	/* Starting PCDAC step */
+	u8		pcdac_min;
+	/* Final PCDAC step */
+	u8		pcdac_max;
+};
+
+struct ath5k_chan_pcal_info_rf5112 {
+	/* Power levels in quarter dBm units
+	 * for lower (0) and higher (3)
+	 * level curves */
+	s8		pwr_x0[AR5K_EEPROM_N_XPD0_POINTS];
+	s8		pwr_x3[AR5K_EEPROM_N_XPD3_POINTS];
+	/* PCDAC table steps
+	 * for the above values */
+	u8	pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS];
+	u8	pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS];
+};
+
+struct ath5k_chan_pcal_info_rf2413 {
+	/* Starting pwr/pddac values */
+	s8		pwr_i[AR5K_EEPROM_N_PD_GAINS];
+	u8	pddac_i[AR5K_EEPROM_N_PD_GAINS];
+	/* (pwr,pddac) points */
+	s8		pwr[AR5K_EEPROM_N_PD_GAINS]
+				[AR5K_EEPROM_N_PD_POINTS];
+	u8	pddac[AR5K_EEPROM_N_PD_GAINS]
+				[AR5K_EEPROM_N_PD_POINTS];
+};
+
+struct ath5k_chan_pcal_info {
+	/* Frequency */
+	u16	freq;
+	/* Max available power */
+	s8		max_pwr;
+	union {
+		struct ath5k_chan_pcal_info_rf5111 rf5111_info;
+		struct ath5k_chan_pcal_info_rf5112 rf5112_info;
+		struct ath5k_chan_pcal_info_rf2413 rf2413_info;
+	};
+};
+
+/* Per rate calibration data for each mode, used for power table setup */
+struct ath5k_rate_pcal_info {
+	u16	freq; /* Frequency */
+	/* Power level for 6-24Mbit/s rates */
+	u16	target_power_6to24;
+	/* Power level for 36Mbit rate */
+	u16	target_power_36;
+	/* Power level for 48Mbit rate */
+	u16	target_power_48;
+	/* Power level for 54Mbit rate */
+	u16	target_power_54;
+};
+
+/* Power edges for conformance test limits */
+struct ath5k_edge_power {
+	u16 freq;
+	u16 edge; /* in half dBm */
+	bool flag;
+};
+
+/* EEPROM calibration data */
 struct ath5k_eeprom_info {
+
+	/* Header information */
 	u16	ee_magic;
 	u16	ee_protect;
 	u16	ee_regdomain;
@@ -168,6 +320,11 @@
 	u16	ee_ant_gain;
 	u16	ee_misc0;
 	u16	ee_misc1;
+	u16	ee_misc2;
+	u16	ee_misc3;
+	u16	ee_misc4;
+	u16	ee_misc5;
+	u16	ee_misc6;
 	u16	ee_cck_ofdm_gain_delta;
 	u16	ee_cck_ofdm_power_delta;
 	u16	ee_scaled_cck_delta;
@@ -185,7 +342,7 @@
 	u16	ee_turbo_max_power[AR5K_EEPROM_N_MODES];
 	u16	ee_xr_power[AR5K_EEPROM_N_MODES];
 	u16	ee_switch_settling[AR5K_EEPROM_N_MODES];
-	u16	ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
+	u16	ee_atn_tx_rx[AR5K_EEPROM_N_MODES];
 	u16	ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
 	u16	ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
 	u16	ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
@@ -198,18 +355,40 @@
 	u16	ee_x_gain[AR5K_EEPROM_N_MODES];
 	u16	ee_i_gain[AR5K_EEPROM_N_MODES];
 	u16	ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
+	u16	ee_switch_settling_turbo[AR5K_EEPROM_N_MODES];
+	u16	ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES];
+	u16	ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES];
 
-	/* Unused */
+	/* Power calibration data */
 	u16	ee_false_detect[AR5K_EEPROM_N_MODES];
-	u16	ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN];
-	u16	ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/
+
+	/* Number of pd gain curves per mode (RF2413) */
+	u8 ee_pd_gains[AR5K_EEPROM_N_MODES];
+
+	u8 ee_n_piers[AR5K_EEPROM_N_MODES];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN];
+
+	/* Per rate target power levels */
+	u16	ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN];
 
 	/* Conformance test limits (Unused) */
 	u16	ee_ctls;
 	u16	ee_ctl[AR5K_EEPROM_MAX_CTLS];
+	struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS];
 
 	/* Noise Floor Calibration settings */
 	s16	ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
 	s8	ee_adc_desired_size[AR5K_EEPROM_N_MODES];
 	s8	ee_pga_desired_size[AR5K_EEPROM_N_MODES];
+	s8	ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES];
+	s8	ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES];
+	s8	ee_pd_gain_overlap;
+
+	u32	ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
 };
+
diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c
index ceaa6c4..450bd6e 100644
--- a/drivers/net/wireless/ath5k/initvals.c
+++ b/drivers/net/wireless/ath5k/initvals.c
@@ -1681,7 +1681,7 @@
 	 */
 
 	/* For AR5212 and combatible */
-	if (ah->ah_version == AR5K_AR5212){
+	if (ah->ah_version == AR5K_AR5212) {
 
 		/* First set of mode-specific settings */
 		ath5k_hw_ini_mode_registers(ah,
@@ -1695,7 +1695,7 @@
 					ar5212_ini, change_channel);
 
 		/* Second set of mode-specific settings */
-		if (ah->ah_radio == AR5K_RF5111){
+		if (ah->ah_radio == AR5K_RF5111) {
 
 			ath5k_hw_ini_mode_registers(ah,
 					ARRAY_SIZE(ar5212_rf5111_ini_mode_end),
@@ -1706,7 +1706,7 @@
 					ARRAY_SIZE(rf5111_ini_bbgain),
 					rf5111_ini_bbgain, change_channel);
 
-		} else if (ah->ah_radio == AR5K_RF5112){
+		} else if (ah->ah_radio == AR5K_RF5112) {
 
 			ath5k_hw_ini_mode_registers(ah,
 					ARRAY_SIZE(ar5212_rf5112_ini_mode_end),
@@ -1716,7 +1716,7 @@
 					ARRAY_SIZE(rf5112_ini_bbgain),
 					rf5112_ini_bbgain, change_channel);
 
-		} else if (ah->ah_radio == AR5K_RF5413){
+		} else if (ah->ah_radio == AR5K_RF5413) {
 
 			ath5k_hw_ini_mode_registers(ah,
 					ARRAY_SIZE(rf5413_ini_mode_end),
diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c
index a47df9a..0cac05c 100644
--- a/drivers/net/wireless/ath5k/pcu.c
+++ b/drivers/net/wireless/ath5k/pcu.c
@@ -46,34 +46,45 @@
 {
 	u32 pcu_reg, beacon_reg, low_id, high_id;
 
-	pcu_reg = 0;
+
+	/* Preserve rest settings */
+	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
+	pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
+			| AR5K_STA_ID1_KEYSRCH_MODE
+			| (ah->ah_version == AR5K_AR5210 ?
+			(AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
+
 	beacon_reg = 0;
 
 	ATH5K_TRACE(ah->ah_sc);
 
 	switch (ah->ah_op_mode) {
 	case NL80211_IFTYPE_ADHOC:
-		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
-				AR5K_STA_ID1_NO_PSPOLL : 0);
+		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
 		beacon_reg |= AR5K_BCR_ADHOC;
+		if (ah->ah_version == AR5K_AR5210)
+			pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
+		else
+			AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
 		break;
 
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_MESH_POINT:
-		pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
-				AR5K_STA_ID1_NO_PSPOLL : 0);
+		pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
 		beacon_reg |= AR5K_BCR_AP;
+		if (ah->ah_version == AR5K_AR5210)
+			pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
+		else
+			AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
 		break;
 
 	case NL80211_IFTYPE_STATION:
-		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
+		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+			| (ah->ah_version == AR5K_AR5210 ?
 				AR5K_STA_ID1_PWR_SV : 0);
 	case NL80211_IFTYPE_MONITOR:
-		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
-			(ah->ah_version == AR5K_AR5210 ?
+		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+			| (ah->ah_version == AR5K_AR5210 ?
 				AR5K_STA_ID1_NO_PSPOLL : 0);
 		break;
 
@@ -130,6 +141,8 @@
 		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
 		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
 	}
+
+	/* TODO: Handle ANI stats */
 }
 
 /**
@@ -258,16 +271,19 @@
 int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
 {
 	u32 low_id, high_id;
+	u32 pcu_reg;
 
 	ATH5K_TRACE(ah->ah_sc);
 	/* Set new station ID */
 	memcpy(ah->ah_sta_id, mac, ETH_ALEN);
 
+	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
+
 	low_id = AR5K_LOW_ID(mac);
 	high_id = AR5K_HIGH_ID(mac);
 
 	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
-	ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1);
+	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
 
 	return 0;
 }
@@ -290,8 +306,10 @@
 	 * Set simple BSSID mask on 5212
 	 */
 	if (ah->ah_version == AR5K_AR5212) {
-		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0);
-		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1);
+		ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
+							AR5K_BSS_IDM0);
+		ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
+							AR5K_BSS_IDM1);
 	}
 
 	/*
@@ -415,6 +433,9 @@
 	u32 low_id, high_id;
 	ATH5K_TRACE(ah->ah_sc);
 
+	/* Cache bssid mask so that we can restore it
+	 * on reset */
+	memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
 	if (ah->ah_version == AR5K_AR5212) {
 		low_id = AR5K_LOW_ID(mask);
 		high_id = AR5K_HIGH_ID(mask);
@@ -576,7 +597,7 @@
 		filter |= AR5K_RX_FILTER_PROM;
 	}
 
-	/*Zero length DMA*/
+	/*Zero length DMA (phy error reporting) */
 	if (data)
 		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
 	else
@@ -661,7 +682,12 @@
 	 * Set the additional timers by mode
 	 */
 	switch (ah->ah_op_mode) {
+	case NL80211_IFTYPE_MONITOR:
 	case NL80211_IFTYPE_STATION:
+		/* In STA mode timer1 is used as next wakeup
+		 * timer and timer2 as next CFP duration start
+		 * timer. Both in 1/8TUs. */
+		/* TODO: PCF handling */
 		if (ah->ah_version == AR5K_AR5210) {
 			timer1 = 0xffffffff;
 			timer2 = 0xffffffff;
@@ -669,27 +695,60 @@
 			timer1 = 0x0000ffff;
 			timer2 = 0x0007ffff;
 		}
+		/* Mark associated AP as PCF incapable for now */
+		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF);
 		break;
-
+	case NL80211_IFTYPE_ADHOC:
+		AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM);
 	default:
+		/* On non-STA modes timer1 is used as next DMA
+		 * beacon alert (DBA) timer and timer2 as next
+		 * software beacon alert. Both in 1/8TUs. */
 		timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
 		timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
+		break;
 	}
 
+	/* Timer3 marks the end of our ATIM window
+	 * a zero length window is not allowed because
+	 * we 'll get no beacons */
 	timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
 
 	/*
 	 * Set the beacon register and enable all timers.
-	 * (next beacon, DMA beacon, software beacon, ATIM window time)
 	 */
-	ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
+	/* When in AP mode zero timer0 to start TSF */
+	if (ah->ah_op_mode == NL80211_IFTYPE_AP)
+		ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
+	else
+		ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
 	ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
 	ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
 	ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
 
+	/* Force a TSF reset if requested and enable beacons */
+	if (interval & AR5K_BEACON_RESET_TSF)
+		ath5k_hw_reset_tsf(ah);
+
 	ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
-			AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE),
-		AR5K_BEACON);
+					AR5K_BEACON_ENABLE),
+						AR5K_BEACON);
+
+	/* Flush any pending BMISS interrupts on ISR by
+	 * performing a clear-on-write operation on PISR
+	 * register for the BMISS bit (writing a bit on
+	 * ISR togles a reset for that bit and leaves
+	 * the rest bits intact) */
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR);
+	else
+		ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR);
+
+	/* TODO: Set enchanced sleep registers on AR5212
+	 * based on vif->bss_conf params, until then
+	 * disable power save reporting.*/
+	AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV);
+
 }
 
 #if 0
@@ -899,14 +958,26 @@
  */
 int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
 {
-	unsigned int i;
+	unsigned int i, type;
+	u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
 
 	ATH5K_TRACE(ah->ah_sc);
 	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
 
+	type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
+
 	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
 		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
 
+	/* Reset associated MIC entry if TKIP
+	 * is enabled located at offset (entry + 64) */
+	if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+		AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE);
+		for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
+			ath5k_hw_reg_write(ah, 0,
+				AR5K_KEYTABLE_OFF(micentry, i));
+	}
+
 	/*
 	 * Set NULL encryption on AR5212+
 	 *
@@ -916,10 +987,16 @@
 	 * Note2: Windows driver (ndiswrapper) sets this to
 	 *        0x00000714 instead of 0x00000007
 	 */
-	if (ah->ah_version > AR5K_AR5211)
+	if (ah->ah_version > AR5K_AR5211) {
 		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
 				AR5K_KEYTABLE_TYPE(entry));
 
+		if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+			ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+				AR5K_KEYTABLE_TYPE(micentry));
+		}
+	}
+
 	return 0;
 }
 
@@ -936,6 +1013,23 @@
 		AR5K_KEYTABLE_VALID;
 }
 
+static
+int ath5k_keycache_type(const struct ieee80211_key_conf *key)
+{
+	switch (key->alg) {
+	case ALG_TKIP:
+		return AR5K_KEYTABLE_TYPE_TKIP;
+	case ALG_CCMP:
+		return AR5K_KEYTABLE_TYPE_CCM;
+	case ALG_WEP:
+		if (key->keylen == LEN_WEP40)
+			return AR5K_KEYTABLE_TYPE_40;
+		else if (key->keylen == LEN_WEP104)
+			return AR5K_KEYTABLE_TYPE_104;
+	}
+	return -EINVAL;
+}
+
 /*
  * Set a key entry on the table
  */
@@ -943,40 +1037,53 @@
 		const struct ieee80211_key_conf *key, const u8 *mac)
 {
 	unsigned int i;
+	int keylen;
 	__le32 key_v[5] = {};
+	__le32 key0 = 0, key1 = 0;
+	__le32 *rxmic, *txmic;
 	u32 keytype;
+	u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
+	bool is_tkip;
+	const u8 *key_ptr;
 
 	ATH5K_TRACE(ah->ah_sc);
 
-	/* key->keylen comes in from mac80211 in bytes */
+	is_tkip = (key->alg == ALG_TKIP);
 
-	if (key->keylen > AR5K_KEYTABLE_SIZE / 8)
+	/*
+	 * key->keylen comes in from mac80211 in bytes.
+	 * TKIP is 128 bit + 128 bit mic
+	 */
+	keylen = (is_tkip) ? (128 / 8) : key->keylen;
+
+	if (entry > AR5K_KEYTABLE_SIZE ||
+		(is_tkip && micentry > AR5K_KEYTABLE_SIZE))
 		return -EOPNOTSUPP;
 
-	switch (key->keylen) {
-	/* WEP 40-bit   = 40-bit  entered key + 24 bit IV = 64-bit */
-	case 40 / 8:
-		memcpy(&key_v[0], key->key, 5);
-		keytype = AR5K_KEYTABLE_TYPE_40;
-		break;
+	if (unlikely(keylen > 16))
+		return -EOPNOTSUPP;
 
-	/* WEP 104-bit  = 104-bit entered key + 24-bit IV = 128-bit */
-	case 104 / 8:
-		memcpy(&key_v[0], &key->key[0], 6);
-		memcpy(&key_v[2], &key->key[6], 6);
-		memcpy(&key_v[4], &key->key[12], 1);
-		keytype = AR5K_KEYTABLE_TYPE_104;
-		break;
-	/* WEP 128-bit  = 128-bit entered key + 24 bit IV = 152-bit */
-	case 128 / 8:
-		memcpy(&key_v[0], &key->key[0], 6);
-		memcpy(&key_v[2], &key->key[6], 6);
-		memcpy(&key_v[4], &key->key[12], 4);
-		keytype = AR5K_KEYTABLE_TYPE_128;
-		break;
+	keytype = ath5k_keycache_type(key);
+	if (keytype < 0)
+		return keytype;
 
-	default:
-		return -EINVAL; /* shouldn't happen */
+	/*
+	 * each key block is 6 bytes wide, written as pairs of
+	 * alternating 32 and 16 bit le values.
+	 */
+	key_ptr = key->key;
+	for (i = 0; keylen >= 6; keylen -= 6) {
+		memcpy(&key_v[i], key_ptr, 6);
+		i += 2;
+		key_ptr += 6;
+	}
+	if (keylen)
+		memcpy(&key_v[i], key_ptr, keylen);
+
+	/* intentionally corrupt key until mic is installed */
+	if (is_tkip) {
+		key0 = key_v[0] = ~key_v[0];
+		key1 = key_v[1] = ~key_v[1];
 	}
 
 	for (i = 0; i < ARRAY_SIZE(key_v); i++)
@@ -985,6 +1092,40 @@
 
 	ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
 
+	if (is_tkip) {
+		/* Install rx/tx MIC */
+		rxmic = (__le32 *) &key->key[16];
+		txmic = (__le32 *) &key->key[24];
+
+		if (ah->ah_combined_mic) {
+			key_v[0] = rxmic[0];
+			key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16);
+			key_v[2] = rxmic[1];
+			key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff);
+			key_v[4] = txmic[1];
+		} else {
+			key_v[0] = rxmic[0];
+			key_v[1] = 0;
+			key_v[2] = rxmic[1];
+			key_v[3] = 0;
+			key_v[4] = 0;
+		}
+		for (i = 0; i < ARRAY_SIZE(key_v); i++)
+			ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
+				AR5K_KEYTABLE_OFF(micentry, i));
+
+		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+			AR5K_KEYTABLE_TYPE(micentry));
+		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry));
+		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry));
+
+		/* restore first 2 words of key */
+		ath5k_hw_reg_write(ah, le32_to_cpu(~key0),
+			AR5K_KEYTABLE_OFF(entry, 0));
+		ath5k_hw_reg_write(ah, le32_to_cpu(~key1),
+			AR5K_KEYTABLE_OFF(entry, 1));
+	}
+
 	return ath5k_hw_set_key_lladdr(ah, entry, mac);
 }
 
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c
index e43f656..7ba18e0 100644
--- a/drivers/net/wireless/ath5k/phy.c
+++ b/drivers/net/wireless/ath5k/phy.c
@@ -1412,7 +1412,8 @@
 		rf_ini = rfregs_2112a;
 		rf_size = ARRAY_SIZE(rfregs_5112a);
 		if (mode < 2) {
-			ATH5K_ERR(ah->ah_sc,"invalid channel mode: %i\n",mode);
+			ATH5K_ERR(ah->ah_sc, "invalid channel mode: %i\n",
+				  mode);
 			return -EINVAL;
 		}
 		mode = mode - 2; /*no a/turboa modes for 2112*/
@@ -1708,7 +1709,7 @@
 		if (ah->ah_radio >= AR5K_RF5112) {
 			ath5k_hw_rfregs_gainf_corr(ah);
 			ah->ah_gain.g_current =
-				ah->ah_gain.g_current>=ah->ah_gain.g_f_corr ?
+				ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
 				(ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
 				0;
 		}
@@ -2195,9 +2196,7 @@
 		return ret;
 	}
 
-	ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
-	if (ret)
-		return ret;
+	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
 
 	/*
 	 * Re-enable RX/TX and beacons
diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c
index 01bf091..1b7bc50 100644
--- a/drivers/net/wireless/ath5k/qcu.c
+++ b/drivers/net/wireless/ath5k/qcu.c
@@ -432,13 +432,30 @@
 		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
 			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
 
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
 
 		/* Update secondary interrupt mask registers */
+
+		/* Filter out inactive queues */
 		ah->ah_txq_imr_txok &= ah->ah_txq_status;
 		ah->ah_txq_imr_txerr &= ah->ah_txq_status;
 		ah->ah_txq_imr_txurn &= ah->ah_txq_status;
 		ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
 		ah->ah_txq_imr_txeol &= ah->ah_txq_status;
+		ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
+		ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
+		ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
+		ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
 
 		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
 			AR5K_SIMR0_QCU_TXOK) |
@@ -448,8 +465,24 @@
 			AR5K_SIMR1_QCU_TXERR) |
 			AR5K_REG_SM(ah->ah_txq_imr_txeol,
 			AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
-		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn,
-			AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2);
+		/* Update simr2 but don't overwrite rest simr2 settings */
+		AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
+			AR5K_REG_SM(ah->ah_txq_imr_txurn,
+			AR5K_SIMR2_QCU_TXURN));
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
+			AR5K_SIMR3_QCBRORN) |
+			AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
+			AR5K_SIMR3_QCBRURN), AR5K_SIMR3);
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
+			AR5K_SIMR4_QTRIG), AR5K_SIMR4);
+		/* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
+			AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
+		/* No queue has TXNOFRM enabled, disable the interrupt
+		 * by setting AR5K_TXNOFRM to zero */
+		if (ah->ah_txq_imr_nofrm == 0)
+			ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
 	}
 
 	return 0;
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h
index e557fe1..91aaeaf 100644
--- a/drivers/net/wireless/ath5k/reg.h
+++ b/drivers/net/wireless/ath5k/reg.h
@@ -234,6 +234,7 @@
 #define AR5K_TXNOFRM		0x004c
 #define	AR5K_TXNOFRM_M		0x000003ff
 #define	AR5K_TXNOFRM_QCU	0x000ffc00
+#define	AR5K_TXNOFRM_QCU_S	10
 
 /*
  * Receive frame gap timeout register
@@ -350,7 +351,7 @@
 
 #define AR5K_SISR3		0x0090			/* Register Address [5211+] */
 #define AR5K_SISR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
-#define AR5K_SISR3_QCBORN_S	0
+#define AR5K_SISR3_QCBRORN_S	0
 #define AR5K_SISR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
 #define AR5K_SISR3_QCBRURN_S	16
 
@@ -1113,14 +1114,16 @@
 #define AR5K_PCU_MAX	0x8fff
 
 /*
- * First station id register (MAC address in lower 32 bits)
+ * First station id register (Lower 32 bits of MAC address)
  */
-#define AR5K_STA_ID0	0x8000
+#define AR5K_STA_ID0		0x8000
+#define	AR5K_STA_ID0_ARRD_L32	0xffffffff
 
 /*
- * Second station id register (MAC address in upper 16 bits)
+ * Second station id register (Upper 16 bits of MAC address + PCU settings)
  */
 #define AR5K_STA_ID1			0x8004			/* Register Address */
+#define	AR5K_STA_ID1_ADDR_U16		0x0000ffff	/* Upper 16 bits of MAC addres */
 #define AR5K_STA_ID1_AP			0x00010000	/* Set AP mode */
 #define AR5K_STA_ID1_ADHOC		0x00020000	/* Set Ad-Hoc mode */
 #define AR5K_STA_ID1_PWR_SV		0x00040000	/* Power save reporting */
@@ -1726,6 +1729,7 @@
 #define	AR5K_MISC_MODE			0x8120			/* Register Address */
 #define	AR5K_MISC_MODE_FBSSID_MATCH	0x00000001	/* Force BSSID match */
 #define	AR5K_MISC_MODE_ACKSIFS_MEM	0x00000002	/* ACK SIFS memory (?) */
+#define	AR5K_MISC_MODE_COMBINED_MIC	0x00000004	/* use rx/tx MIC key */
 /* more bits */
 
 /*
@@ -1810,6 +1814,10 @@
 #define AR5K_KEYTABLE_MAC1(_n)		AR5K_KEYTABLE_OFF(_n, 7)
 #define AR5K_KEYTABLE_VALID		0x00008000
 
+/* If key type is TKIP and MIC is enabled
+ * MIC key goes in offset entry + 64 */
+#define	AR5K_KEYTABLE_MIC_OFFSET	64
+
 /* WEP 40-bit	= 40-bit  entered key + 24 bit IV = 64-bit
  * WEP 104-bit	= 104-bit entered key + 24-bit IV = 128-bit
  * WEP 128-bit	= 128-bit entered key + 24 bit IV = 152-bit
diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c
index 1b6d45b..dc2d7d8 100644
--- a/drivers/net/wireless/ath5k/reset.c
+++ b/drivers/net/wireless/ath5k/reset.c
@@ -674,7 +674,7 @@
 			(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
 			0xffffc07f);
 		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN,
-			(ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
+			(ee->ee_atn_tx_rx[ee_mode] << 12) & 0x3f000,
 			0xfffc0fff);
 		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
 			(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
@@ -842,9 +842,7 @@
 	 *
 	 * XXX: Find an interval that's OK for all cards...
 	 */
-	ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
-	if (ret)
-		return ret;
+	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
 
 	/*
 	 * Reset queues and start beacon timers at the end of the reset routine
@@ -864,8 +862,7 @@
 
 	/* Pre-enable interrupts on 5211/5212*/
 	if (ah->ah_version != AR5K_AR5210)
-		ath5k_hw_set_imr(ah, AR5K_INT_RX | AR5K_INT_TX |
-				AR5K_INT_FATAL);
+		ath5k_hw_set_imr(ah, ah->ah_imr);
 
 	/*
 	 * Set RF kill flags if supported by the device (read from the EEPROM)
diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig
index 80a6924..c43bd32 100644
--- a/drivers/net/wireless/ath9k/Kconfig
+++ b/drivers/net/wireless/ath9k/Kconfig
@@ -9,3 +9,14 @@
 	  Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets.
 
 	  If you choose to build a module, it'll be called ath9k.
+
+config ATH9K_DEBUG
+	bool "Atheros ath9k debugging"
+	depends on ATH9K
+	---help---
+	  Say Y, if you need ath9k to display debug messages.
+	  Pass the debug mask as a module parameter:
+
+	  modprobe ath9k debug=0x00002000
+
+	  Look in ath9k/core.h for possible debug masks
diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile
index a641151..1209d14 100644
--- a/drivers/net/wireless/ath9k/Makefile
+++ b/drivers/net/wireless/ath9k/Makefile
@@ -1,11 +1,16 @@
 ath9k-y +=	hw.o \
+		eeprom.o \
+		mac.o \
+		calib.o \
+		ani.o \
 		phy.o \
 		regd.o \
 		beacon.o \
 		main.o \
 		recv.o \
 		xmit.o \
-		rc.o \
-		core.o
+		rc.o
+
+ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o
 
 obj-$(CONFIG_ATH9K) += ath9k.o
diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c
new file mode 100644
index 0000000..251e2d9
--- /dev/null
+++ b/drivers/net/wireless/ath9k/ani.c
@@ -0,0 +1,852 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah,
+					struct ath9k_channel *chan)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
+		if (ahp->ah_ani[i].c.channel == chan->channel)
+			return i;
+		if (ahp->ah_ani[i].c.channel == 0) {
+			ahp->ah_ani[i].c.channel = chan->channel;
+			ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
+			return i;
+		}
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+		"No more channel states left. Using channel 0\n");
+
+	return 0;
+}
+
+static bool ath9k_hw_ani_control(struct ath_hal *ah,
+				 enum ath9k_ani_cmd cmd, int param)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState = ahp->ah_curani;
+
+	switch (cmd & ahp->ah_ani_function) {
+	case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+				"level out of range (%u > %u)\n",
+				level,
+				(unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired));
+			return false;
+		}
+
+		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+			      AR_PHY_DESIRED_SZ_TOT_DES,
+			      ahp->ah_totalSizeDesired[level]);
+		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+			      AR_PHY_AGC_CTL1_COARSE_LOW,
+			      ahp->ah_coarseLow[level]);
+		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+			      AR_PHY_AGC_CTL1_COARSE_HIGH,
+			      ahp->ah_coarseHigh[level]);
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+			      AR_PHY_FIND_SIG_FIRPWR,
+			      ahp->ah_firpwr[level]);
+
+		if (level > aniState->noiseImmunityLevel)
+			ahp->ah_stats.ast_ani_niup++;
+		else if (level < aniState->noiseImmunityLevel)
+			ahp->ah_stats.ast_ani_nidown++;
+		aniState->noiseImmunityLevel = level;
+		break;
+	}
+	case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+		const int m1ThreshLow[] = { 127, 50 };
+		const int m2ThreshLow[] = { 127, 40 };
+		const int m1Thresh[] = { 127, 0x4d };
+		const int m2Thresh[] = { 127, 0x40 };
+		const int m2CountThr[] = { 31, 16 };
+		const int m2CountThrLow[] = { 63, 48 };
+		u32 on = param ? 1 : 0;
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+			      m1ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+			      m2ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M1_THRESH,
+			      m1Thresh[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2_THRESH,
+			      m2Thresh[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2COUNT_THR,
+			      m2CountThr[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+			      m2CountThrLow[on]);
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
+			      m1ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
+			      m2ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH,
+			      m1Thresh[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH,
+			      m2Thresh[on]);
+
+		if (on)
+			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+		else
+			REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
+				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+
+		if (!on != aniState->ofdmWeakSigDetectOff) {
+			if (on)
+				ahp->ah_stats.ast_ani_ofdmon++;
+			else
+				ahp->ah_stats.ast_ani_ofdmoff++;
+			aniState->ofdmWeakSigDetectOff = !on;
+		}
+		break;
+	}
+	case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
+		const int weakSigThrCck[] = { 8, 6 };
+		u32 high = param ? 1 : 0;
+
+		REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
+			      AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
+			      weakSigThrCck[high]);
+		if (high != aniState->cckWeakSigThreshold) {
+			if (high)
+				ahp->ah_stats.ast_ani_cckhigh++;
+			else
+				ahp->ah_stats.ast_ani_ccklow++;
+			aniState->cckWeakSigThreshold = high;
+		}
+		break;
+	}
+	case ATH9K_ANI_FIRSTEP_LEVEL:{
+		const int firstep[] = { 0, 4, 8 };
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(firstep)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+				"level out of range (%u > %u)\n",
+				level,
+				(unsigned) ARRAY_SIZE(firstep));
+			return false;
+		}
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+			      AR_PHY_FIND_SIG_FIRSTEP,
+			      firstep[level]);
+		if (level > aniState->firstepLevel)
+			ahp->ah_stats.ast_ani_stepup++;
+		else if (level < aniState->firstepLevel)
+			ahp->ah_stats.ast_ani_stepdown++;
+		aniState->firstepLevel = level;
+		break;
+	}
+	case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+		const int cycpwrThr1[] =
+			{ 2, 4, 6, 8, 10, 12, 14, 16 };
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(cycpwrThr1)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+				"level out of range (%u > %u)\n",
+				level,
+				(unsigned)
+				ARRAY_SIZE(cycpwrThr1));
+			return false;
+		}
+		REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+			      AR_PHY_TIMING5_CYCPWR_THR1,
+			      cycpwrThr1[level]);
+		if (level > aniState->spurImmunityLevel)
+			ahp->ah_stats.ast_ani_spurup++;
+		else if (level < aniState->spurImmunityLevel)
+			ahp->ah_stats.ast_ani_spurdown++;
+		aniState->spurImmunityLevel = level;
+		break;
+	}
+	case ATH9K_ANI_PRESENT:
+		break;
+	default:
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+			"invalid cmd %u\n", cmd);
+		return false;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n");
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+		"noiseImmunityLevel=%d, spurImmunityLevel=%d, "
+		"ofdmWeakSigDetectOff=%d\n",
+		aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
+		!aniState->ofdmWeakSigDetectOff);
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+		"cckWeakSigThreshold=%d, "
+		"firstepLevel=%d, listenTime=%d\n",
+		aniState->cckWeakSigThreshold, aniState->firstepLevel,
+		aniState->listenTime);
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+		"cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
+		aniState->cycleCount, aniState->ofdmPhyErrCount,
+		aniState->cckPhyErrCount);
+
+	return true;
+}
+
+static void ath9k_hw_update_mibstats(struct ath_hal *ah,
+				     struct ath9k_mib_stats *stats)
+{
+	stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
+	stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
+	stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
+	stats->rts_good += REG_READ(ah, AR_RTS_OK);
+	stats->beacons += REG_READ(ah, AR_BEACON_CNT);
+}
+
+static void ath9k_ani_restart(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = ahp->ah_curani;
+
+	aniState->listenTime = 0;
+	if (ahp->ah_hasHwPhyCounters) {
+		if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
+			aniState->ofdmPhyErrBase = 0;
+			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+				"OFDM Trigger is too high for hw counters\n");
+		} else {
+			aniState->ofdmPhyErrBase =
+				AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
+		}
+		if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
+			aniState->cckPhyErrBase = 0;
+			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+				"CCK Trigger is too high for hw counters\n");
+		} else {
+			aniState->cckPhyErrBase =
+				AR_PHY_COUNTMAX - aniState->cckTrigHigh;
+		}
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+			"Writing ofdmbase=%u   cckbase=%u\n",
+			aniState->ofdmPhyErrBase,
+			aniState->cckPhyErrBase);
+		REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
+		REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
+		REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+		REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+	}
+	aniState->ofdmPhyErrCount = 0;
+	aniState->cckPhyErrCount = 0;
+}
+
+static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_channel *chan = ah->ah_curchan;
+	struct ar5416AniState *aniState;
+	enum wireless_mode mode;
+	int32_t rssi;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = ahp->ah_curani;
+
+	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+					 aniState->noiseImmunityLevel + 1)) {
+			return;
+		}
+	}
+
+	if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+					 aniState->spurImmunityLevel + 1)) {
+			return;
+		}
+	}
+
+	if (ah->ah_opmode == NL80211_IFTYPE_AP) {
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+		}
+		return;
+	}
+	rssi = BEACON_RSSI(ahp);
+	if (rssi > aniState->rssiThrHigh) {
+		if (!aniState->ofdmWeakSigDetectOff) {
+			if (ath9k_hw_ani_control(ah,
+					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+					 false)) {
+				ath9k_hw_ani_control(ah,
+					ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
+				return;
+			}
+		}
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+			return;
+		}
+	} else if (rssi > aniState->rssiThrLow) {
+		if (aniState->ofdmWeakSigDetectOff)
+			ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				     true);
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+		return;
+	} else {
+		mode = ath9k_hw_chan2wmode(ah, chan);
+		if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
+			if (!aniState->ofdmWeakSigDetectOff)
+				ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				     false);
+			if (aniState->firstepLevel > 0)
+				ath9k_hw_ani_control(ah,
+					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
+			return;
+		}
+	}
+}
+
+static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_channel *chan = ah->ah_curchan;
+	struct ar5416AniState *aniState;
+	enum wireless_mode mode;
+	int32_t rssi;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = ahp->ah_curani;
+	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+					 aniState->noiseImmunityLevel + 1)) {
+			return;
+		}
+	}
+	if (ah->ah_opmode == NL80211_IFTYPE_AP) {
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+		}
+		return;
+	}
+	rssi = BEACON_RSSI(ahp);
+	if (rssi > aniState->rssiThrLow) {
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+	} else {
+		mode = ath9k_hw_chan2wmode(ah, chan);
+		if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
+			if (aniState->firstepLevel > 0)
+				ath9k_hw_ani_control(ah,
+					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
+		}
+	}
+}
+
+static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState;
+	int32_t rssi;
+
+	aniState = ahp->ah_curani;
+
+	if (ah->ah_opmode == NL80211_IFTYPE_AP) {
+		if (aniState->firstepLevel > 0) {
+			if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+						 aniState->firstepLevel - 1))
+				return;
+		}
+	} else {
+		rssi = BEACON_RSSI(ahp);
+		if (rssi > aniState->rssiThrHigh) {
+			/* XXX: Handle me */
+		} else if (rssi > aniState->rssiThrLow) {
+			if (aniState->ofdmWeakSigDetectOff) {
+				if (ath9k_hw_ani_control(ah,
+					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+					 true) == true)
+					return;
+			}
+			if (aniState->firstepLevel > 0) {
+				if (ath9k_hw_ani_control(ah,
+					 ATH9K_ANI_FIRSTEP_LEVEL,
+					 aniState->firstepLevel - 1) == true)
+					return;
+			}
+		} else {
+			if (aniState->firstepLevel > 0) {
+				if (ath9k_hw_ani_control(ah,
+					 ATH9K_ANI_FIRSTEP_LEVEL,
+					 aniState->firstepLevel - 1) == true)
+					return;
+			}
+		}
+	}
+
+	if (aniState->spurImmunityLevel > 0) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+					 aniState->spurImmunityLevel - 1))
+			return;
+	}
+
+	if (aniState->noiseImmunityLevel > 0) {
+		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+				     aniState->noiseImmunityLevel - 1);
+		return;
+	}
+}
+
+static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState;
+	u32 txFrameCount, rxFrameCount, cycleCount;
+	int32_t listenTime;
+
+	txFrameCount = REG_READ(ah, AR_TFCNT);
+	rxFrameCount = REG_READ(ah, AR_RFCNT);
+	cycleCount = REG_READ(ah, AR_CCCNT);
+
+	aniState = ahp->ah_curani;
+	if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
+
+		listenTime = 0;
+		ahp->ah_stats.ast_ani_lzero++;
+	} else {
+		int32_t ccdelta = cycleCount - aniState->cycleCount;
+		int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
+		int32_t tfdelta = txFrameCount - aniState->txFrameCount;
+		listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
+	}
+	aniState->cycleCount = cycleCount;
+	aniState->txFrameCount = txFrameCount;
+	aniState->rxFrameCount = rxFrameCount;
+
+	return listenTime;
+}
+
+void ath9k_ani_reset(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState;
+	struct ath9k_channel *chan = ah->ah_curchan;
+	int index;
+
+	if (!DO_ANI(ah))
+		return;
+
+	index = ath9k_hw_get_ani_channel_idx(ah, chan);
+	aniState = &ahp->ah_ani[index];
+	ahp->ah_curani = aniState;
+
+	if (DO_ANI(ah) && ah->ah_opmode != NL80211_IFTYPE_STATION
+	    && ah->ah_opmode != NL80211_IFTYPE_ADHOC) {
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+			"Reset ANI state opmode %u\n", ah->ah_opmode);
+		ahp->ah_stats.ast_ani_reset++;
+
+		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
+		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
+		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
+		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				     !ATH9K_ANI_USE_OFDM_WEAK_SIG);
+		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
+				     ATH9K_ANI_CCK_WEAK_SIG_THR);
+
+		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
+				     ATH9K_RX_FILTER_PHYERR);
+
+		if (ah->ah_opmode == NL80211_IFTYPE_AP) {
+			ahp->ah_curani->ofdmTrigHigh =
+				ah->ah_config.ofdm_trig_high;
+			ahp->ah_curani->ofdmTrigLow =
+				ah->ah_config.ofdm_trig_low;
+			ahp->ah_curani->cckTrigHigh =
+				ah->ah_config.cck_trig_high;
+			ahp->ah_curani->cckTrigLow =
+				ah->ah_config.cck_trig_low;
+		}
+		ath9k_ani_restart(ah);
+		return;
+	}
+
+	if (aniState->noiseImmunityLevel != 0)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+				     aniState->noiseImmunityLevel);
+	if (aniState->spurImmunityLevel != 0)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+				     aniState->spurImmunityLevel);
+	if (aniState->ofdmWeakSigDetectOff)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				     !aniState->ofdmWeakSigDetectOff);
+	if (aniState->cckWeakSigThreshold)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
+				     aniState->cckWeakSigThreshold);
+	if (aniState->firstepLevel != 0)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+				     aniState->firstepLevel);
+	if (ahp->ah_hasHwPhyCounters) {
+		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
+				     ~ATH9K_RX_FILTER_PHYERR);
+		ath9k_ani_restart(ah);
+		REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+		REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+	} else {
+		ath9k_ani_restart(ah);
+		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
+				     ATH9K_RX_FILTER_PHYERR);
+	}
+}
+
+void ath9k_hw_ani_monitor(struct ath_hal *ah,
+			  const struct ath9k_node_stats *stats,
+			  struct ath9k_channel *chan)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416AniState *aniState;
+	int32_t listenTime;
+
+	aniState = ahp->ah_curani;
+	ahp->ah_stats.ast_nodestats = *stats;
+
+	listenTime = ath9k_hw_ani_get_listen_time(ah);
+	if (listenTime < 0) {
+		ahp->ah_stats.ast_ani_lneg++;
+		ath9k_ani_restart(ah);
+		return;
+	}
+
+	aniState->listenTime += listenTime;
+
+	if (ahp->ah_hasHwPhyCounters) {
+		u32 phyCnt1, phyCnt2;
+		u32 ofdmPhyErrCnt, cckPhyErrCnt;
+
+		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+		phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+		phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+
+		if (phyCnt1 < aniState->ofdmPhyErrBase ||
+		    phyCnt2 < aniState->cckPhyErrBase) {
+			if (phyCnt1 < aniState->ofdmPhyErrBase) {
+				DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+					"phyCnt1 0x%x, resetting "
+					"counter value to 0x%x\n",
+					phyCnt1,
+					aniState->ofdmPhyErrBase);
+				REG_WRITE(ah, AR_PHY_ERR_1,
+					  aniState->ofdmPhyErrBase);
+				REG_WRITE(ah, AR_PHY_ERR_MASK_1,
+					  AR_PHY_ERR_OFDM_TIMING);
+			}
+			if (phyCnt2 < aniState->cckPhyErrBase) {
+				DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+					"phyCnt2 0x%x, resetting "
+					"counter value to 0x%x\n",
+					phyCnt2,
+					aniState->cckPhyErrBase);
+				REG_WRITE(ah, AR_PHY_ERR_2,
+					  aniState->cckPhyErrBase);
+				REG_WRITE(ah, AR_PHY_ERR_MASK_2,
+					  AR_PHY_ERR_CCK_TIMING);
+			}
+			return;
+		}
+
+		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+		ahp->ah_stats.ast_ani_ofdmerrs +=
+			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+		ahp->ah_stats.ast_ani_cckerrs +=
+			cckPhyErrCnt - aniState->cckPhyErrCount;
+		aniState->cckPhyErrCount = cckPhyErrCnt;
+	}
+
+	if (!DO_ANI(ah))
+		return;
+
+	if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
+		if (aniState->ofdmPhyErrCount <= aniState->listenTime *
+		    aniState->ofdmTrigLow / 1000 &&
+		    aniState->cckPhyErrCount <= aniState->listenTime *
+		    aniState->cckTrigLow / 1000)
+			ath9k_hw_ani_lower_immunity(ah);
+		ath9k_ani_restart(ah);
+	} else if (aniState->listenTime > ahp->ah_aniPeriod) {
+		if (aniState->ofdmPhyErrCount > aniState->listenTime *
+		    aniState->ofdmTrigHigh / 1000) {
+			ath9k_hw_ani_ofdm_err_trigger(ah);
+			ath9k_ani_restart(ah);
+		} else if (aniState->cckPhyErrCount >
+			   aniState->listenTime * aniState->cckTrigHigh /
+			   1000) {
+			ath9k_hw_ani_cck_err_trigger(ah);
+			ath9k_ani_restart(ah);
+		}
+	}
+}
+
+bool ath9k_hw_phycounters(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	return ahp->ah_hasHwPhyCounters ? true : false;
+}
+
+void ath9k_enable_mib_counters(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
+
+	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+	REG_WRITE(ah, AR_FILT_OFDM, 0);
+	REG_WRITE(ah, AR_FILT_CCK, 0);
+	REG_WRITE(ah, AR_MIBC,
+		  ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
+		  & 0x0f);
+	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+}
+
+void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
+
+	REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
+
+	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+	REG_WRITE(ah, AR_FILT_OFDM, 0);
+	REG_WRITE(ah, AR_FILT_CCK, 0);
+}
+
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
+				  u32 *rxc_pcnt,
+				  u32 *rxf_pcnt,
+				  u32 *txf_pcnt)
+{
+	static u32 cycles, rx_clear, rx_frame, tx_frame;
+	u32 good = 1;
+
+	u32 rc = REG_READ(ah, AR_RCCNT);
+	u32 rf = REG_READ(ah, AR_RFCNT);
+	u32 tf = REG_READ(ah, AR_TFCNT);
+	u32 cc = REG_READ(ah, AR_CCCNT);
+
+	if (cycles == 0 || cycles > cc) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+			"cycle counter wrap. ExtBusy = 0\n");
+		good = 0;
+	} else {
+		u32 cc_d = cc - cycles;
+		u32 rc_d = rc - rx_clear;
+		u32 rf_d = rf - rx_frame;
+		u32 tf_d = tf - tx_frame;
+
+		if (cc_d != 0) {
+			*rxc_pcnt = rc_d * 100 / cc_d;
+			*rxf_pcnt = rf_d * 100 / cc_d;
+			*txf_pcnt = tf_d * 100 / cc_d;
+		} else {
+			good = 0;
+		}
+	}
+
+	cycles = cc;
+	rx_frame = rf;
+	rx_clear = rc;
+	tx_frame = tf;
+
+	return good;
+}
+
+/*
+ * Process a MIB interrupt.  We may potentially be invoked because
+ * any of the MIB counters overflow/trigger so don't assume we're
+ * here because a PHY error counter triggered.
+ */
+void ath9k_hw_procmibevent(struct ath_hal *ah,
+			   const struct ath9k_node_stats *stats)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 phyCnt1, phyCnt2;
+
+	/* Reset these counters regardless */
+	REG_WRITE(ah, AR_FILT_OFDM, 0);
+	REG_WRITE(ah, AR_FILT_CCK, 0);
+	if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
+		REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
+
+	/* Clear the mib counters and save them in the stats */
+	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+	ahp->ah_stats.ast_nodestats = *stats;
+
+	if (!DO_ANI(ah))
+		return;
+
+	/* NB: these are not reset-on-read */
+	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
+	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
+		struct ar5416AniState *aniState = ahp->ah_curani;
+		u32 ofdmPhyErrCnt, cckPhyErrCnt;
+
+		/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
+		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+		ahp->ah_stats.ast_ani_ofdmerrs +=
+			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+		ahp->ah_stats.ast_ani_cckerrs +=
+			cckPhyErrCnt - aniState->cckPhyErrCount;
+		aniState->cckPhyErrCount = cckPhyErrCnt;
+
+		/*
+		 * NB: figure out which counter triggered.  If both
+		 * trigger we'll only deal with one as the processing
+		 * clobbers the error counter so the trigger threshold
+		 * check will never be true.
+		 */
+		if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
+			ath9k_hw_ani_ofdm_err_trigger(ah);
+		if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
+			ath9k_hw_ani_cck_err_trigger(ah);
+		/* NB: always restart to insure the h/w counters are reset */
+		ath9k_ani_restart(ah);
+	}
+}
+
+void ath9k_hw_ani_setup(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
+	const int coarseHigh[] = { -14, -14, -14, -14, -12 };
+	const int coarseLow[] = { -64, -64, -64, -64, -70 };
+	const int firpwr[] = { -78, -78, -78, -78, -80 };
+
+	for (i = 0; i < 5; i++) {
+		ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
+		ahp->ah_coarseHigh[i] = coarseHigh[i];
+		ahp->ah_coarseLow[i] = coarseLow[i];
+		ahp->ah_firpwr[i] = firpwr[i];
+	}
+}
+
+void ath9k_hw_ani_attach(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
+
+	ahp->ah_hasHwPhyCounters = 1;
+
+	memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
+	for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
+		ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
+		ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
+		ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
+		ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
+		ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
+		ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
+		ahp->ah_ani[i].ofdmWeakSigDetectOff =
+			!ATH9K_ANI_USE_OFDM_WEAK_SIG;
+		ahp->ah_ani[i].cckWeakSigThreshold =
+			ATH9K_ANI_CCK_WEAK_SIG_THR;
+		ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+		ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+		if (ahp->ah_hasHwPhyCounters) {
+			ahp->ah_ani[i].ofdmPhyErrBase =
+				AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
+			ahp->ah_ani[i].cckPhyErrBase =
+				AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
+		}
+	}
+	if (ahp->ah_hasHwPhyCounters) {
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+			"Setting OfdmErrBase = 0x%08x\n",
+			ahp->ah_ani[0].ofdmPhyErrBase);
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
+			ahp->ah_ani[0].cckPhyErrBase);
+
+		REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
+		REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
+		ath9k_enable_mib_counters(ah);
+	}
+	ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
+	if (ah->ah_config.enable_ani)
+		ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
+}
+
+void ath9k_hw_ani_detach(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
+
+	if (ahp->ah_hasHwPhyCounters) {
+		ath9k_hw_disable_mib_counters(ah);
+		REG_WRITE(ah, AR_PHY_ERR_1, 0);
+		REG_WRITE(ah, AR_PHY_ERR_2, 0);
+	}
+}
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index accace5..d278135 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -26,6 +26,7 @@
 #define AR9160_DEVID_PCI	0x0027
 #define AR9280_DEVID_PCI	0x0029
 #define AR9280_DEVID_PCIE	0x002a
+#define AR9285_DEVID_PCIE	0x002b
 
 #define AR5416_AR9100_DEVID	0x000b
 
@@ -138,6 +139,19 @@
 #define ATH9K_TXDESC_NOACK		0x0002
 #define ATH9K_TXDESC_RTSENA		0x0004
 #define ATH9K_TXDESC_CTSENA		0x0008
+/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for
+ * the descriptor its marked on.  We take a tx interrupt to reap
+ * descriptors when the h/w hits an EOL condition or
+ * when the descriptor is specifically marked to generate
+ * an interrupt with this flag. Descriptors should be
+ * marked periodically to insure timely replenishing of the
+ * supply needed for sending frames. Defering interrupts
+ * reduces system load and potentially allows more concurrent
+ * work to be done but if done to aggressively can cause
+ * senders to backup. When the hardware queue is left too
+ * large rate control information may also be too out of
+ * date. An Alternative for this is TX interrupt mitigation
+ * but this needs more testing. */
 #define ATH9K_TXDESC_INTREQ		0x0010
 #define ATH9K_TXDESC_VEOL		0x0020
 #define ATH9K_TXDESC_EXT_ONLY		0x0040
@@ -388,22 +402,6 @@
 	ATH9K_INT_NOCARD = 0xffffffff
 };
 
-struct ath9k_rate_table {
-	int rateCount;
-	u8 rateCodeToIndex[256];
-	struct {
-		u8 valid;
-		u8 phy;
-		u32 rateKbps;
-		u8 rateCode;
-		u8 shortPreamble;
-		u8 dot11Rate;
-		u8 controlRate;
-		u16 lpAckDuration;
-		u16 spAckDuration;
-	} info[32];
-};
-
 #define ATH9K_RATESERIES_RTS_CTS  0x0001
 #define ATH9K_RATESERIES_2040     0x0002
 #define ATH9K_RATESERIES_HALFGI   0x0004
@@ -479,12 +477,10 @@
        (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \
        (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \
        (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS))
-#define IS_CHAN_B(_c) (((_c)->channelFlags & CHANNEL_B) == CHANNEL_B)
 #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
        (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
        (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
        (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS))
-#define IS_CHAN_CCK(_c) (((_c)->channelFlags & CHANNEL_CCK) != 0)
 #define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
 #define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
 #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
@@ -493,6 +489,7 @@
 #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
 
 /* These macros check chanmode and not channelFlags */
+#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B)
 #define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) ||	\
 			  ((_c)->chanmode == CHANNEL_G_HT20))
 #define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) ||	\
@@ -651,13 +648,6 @@
 	ATH9K_ANT_FIXED_B
 };
 
-enum ath9k_opmode {
-	ATH9K_M_STA = 1,
-	ATH9K_M_IBSS = 0,
-	ATH9K_M_HOSTAP = 6,
-	ATH9K_M_MONITOR = 8
-};
-
 #define ATH9K_SLOT_TIME_6 6
 #define ATH9K_SLOT_TIME_9 9
 #define ATH9K_SLOT_TIME_20 20
@@ -689,13 +679,19 @@
 	ATH9K_ANI_ALL = 0xff
 };
 
-enum phytype {
-	PHY_DS,
-	PHY_FH,
-	PHY_OFDM,
-	PHY_HT,
+enum {
+	WLAN_RC_PHY_OFDM,
+	WLAN_RC_PHY_CCK,
+	WLAN_RC_PHY_HT_20_SS,
+	WLAN_RC_PHY_HT_20_DS,
+	WLAN_RC_PHY_HT_40_SS,
+	WLAN_RC_PHY_HT_40_DS,
+	WLAN_RC_PHY_HT_20_SS_HGI,
+	WLAN_RC_PHY_HT_20_DS_HGI,
+	WLAN_RC_PHY_HT_40_SS_HGI,
+	WLAN_RC_PHY_HT_40_DS_HGI,
+	WLAN_RC_PHY_MAX
 };
-#define PHY_CCK PHY_DS
 
 enum ath9k_tp_scale {
 	ATH9K_TP_SCALE_MAX = 0,
@@ -778,7 +774,8 @@
 
 	void __iomem *ah_sh;
 	struct ath_softc *ah_sc;
-	enum ath9k_opmode ah_opmode;
+
+	enum nl80211_iftype ah_opmode;
 	struct ath9k_ops_config ah_config;
 	struct ath9k_hw_capabilities ah_caps;
 
@@ -815,195 +812,246 @@
 	u16 ext_center;
 };
 
-int ath_hal_getcapability(struct ath_hal *ah,
-			  enum ath9k_capability_type type,
-			  u32 capability,
-			  u32 *result);
-const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
-						     u32 mode);
-void ath9k_hw_detach(struct ath_hal *ah);
-struct ath_hal *ath9k_hw_attach(u16 devid,
-				struct ath_softc *sc,
-				void __iomem *mem,
-				int *error);
-bool ath9k_regd_init_channels(struct ath_hal *ah,
-			      u32 maxchans, u32 *nchans,
-			      u8 *regclassids,
-			      u32 maxregids, u32 *nregids,
-			      u16 cc,
-			      bool enableOutdoor,
-			      bool enableExtendedChannels);
+struct ath_rate_table;
+
+/* Helpers */
+
+enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
+			       const struct ath9k_channel *chan);
+bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val);
+u32 ath9k_hw_reverse_bits(u32 val, u32 n);
+bool ath9k_get_channel_edges(struct ath_hal *ah,
+			     u16 flags, u16 *low,
+			     u16 *high);
+u16 ath9k_hw_computetxtime(struct ath_hal *ah,
+			   struct ath_rate_table *rates,
+			   u32 frameLen, u16 rateix,
+			   bool shortPreamble);
 u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
-enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah,
-				     enum ath9k_int ints);
-bool ath9k_hw_reset(struct ath_hal *ah,
-		    struct ath9k_channel *chan,
+void ath9k_hw_get_channel_centers(struct ath_hal *ah,
+				  struct ath9k_channel *chan,
+				  struct chan_centers *centers);
+
+/* Attach, Detach */
+
+const char *ath9k_hw_probe(u16 vendorid, u16 devid);
+void ath9k_hw_detach(struct ath_hal *ah);
+struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
+				void __iomem *mem, int *error);
+void ath9k_hw_rfdetach(struct ath_hal *ah);
+
+
+/* HW Reset */
+
+bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
 		    enum ath9k_ht_macmode macmode,
 		    u8 txchainmask, u8 rxchainmask,
 		    enum ath9k_ht_extprotspacing extprotspacing,
-		    bool bChannelChange,
-		    int *status);
-bool ath9k_hw_phy_disable(struct ath_hal *ah);
-void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
-			     bool *isCalDone);
-void ath9k_hw_ani_monitor(struct ath_hal *ah,
-			  const struct ath9k_node_stats *stats,
-			  struct ath9k_channel *chan);
-bool ath9k_hw_calibrate(struct ath_hal *ah,
-			struct ath9k_channel *chan,
-			u8 rxchainmask,
-			bool longcal,
-			bool *isCalDone);
-s16 ath9k_hw_getchan_noise(struct ath_hal *ah,
-			       struct ath9k_channel *chan);
-void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
-			    u16 assocId);
-void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits);
-void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
-			    u16 assocId);
-bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q);
-void ath9k_hw_reset_tsf(struct ath_hal *ah);
-bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry);
-bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry,
-			const u8 *mac);
-bool ath9k_hw_set_keycache_entry(struct ath_hal *ah,
-				 u16 entry,
-				 const struct ath9k_keyval *k,
-				 const u8 *mac,
-				 int xorKey);
-bool ath9k_hw_set_tsfadjust(struct ath_hal *ah,
-			    u32 setting);
-void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
-bool ath9k_hw_intrpend(struct ath_hal *ah);
-bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked);
-bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah,
-				bool bIncTrigLevel);
-void ath9k_hw_procmibevent(struct ath_hal *ah,
-			   const struct ath9k_node_stats *stats);
-bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set);
-void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode);
-bool ath9k_hw_phycounters(struct ath_hal *ah);
+		    bool bChannelChange, int *status);
+
+/* Key Cache Management */
+
 bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry);
-bool ath9k_hw_getcapability(struct ath_hal *ah,
-			    enum ath9k_capability_type type,
-			    u32 capability,
-			    u32 *result);
-bool ath9k_hw_setcapability(struct ath_hal *ah,
-			    enum ath9k_capability_type type,
-			    u32 capability,
-			    u32 setting,
-			    int *status);
-u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
-void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac);
-void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask);
-bool ath9k_hw_setbssidmask(struct ath_hal *ah,
-			   const u8 *mask);
+bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac);
+bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
+				 const struct ath9k_keyval *k,
+				 const u8 *mac, int xorKey);
+bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry);
+
+/* Power Management */
+
 bool ath9k_hw_setpower(struct ath_hal *ah,
 		       enum ath9k_power_mode mode);
-enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah);
-u64 ath9k_hw_gettsf64(struct ath_hal *ah);
+void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
+
+/* Beacon timers */
+
+void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period);
+void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
+				    const struct ath9k_beacon_state *bs);
+/* HW Capabilities */
+
+bool ath9k_hw_fill_cap_info(struct ath_hal *ah);
+bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+			    u32 capability, u32 *result);
+bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+			    u32 capability, u32 setting, int *status);
+
+/* GPIO / RFKILL / Antennae */
+
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
+void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
+			 u32 ah_signal_type);
+void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val);
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+void ath9k_enable_rfkill(struct ath_hal *ah);
+#endif
+int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg);
 u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
-bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us);
+void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna);
 bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
 			       enum ath9k_ant_setting settings,
 			       struct ath9k_channel *chan,
 			       u8 *tx_chainmask,
 			       u8 *rx_chainmask,
 			       u8 *antenna_cfgd);
-void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna);
-int ath9k_hw_select_antconfig(struct ath_hal *ah,
-			      u32 cfg);
-bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q,
-		       u32 txdp);
+
+/* General Operation */
+
+u32 ath9k_hw_getrxfilter(struct ath_hal *ah);
+void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits);
+bool ath9k_hw_phy_disable(struct ath_hal *ah);
+bool ath9k_hw_disable(struct ath_hal *ah);
+bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit);
+void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac);
+bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac);
+void ath9k_hw_setopmode(struct ath_hal *ah);
+void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1);
+void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask);
+bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask);
+void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId);
+u64 ath9k_hw_gettsf64(struct ath_hal *ah);
+void ath9k_hw_reset_tsf(struct ath_hal *ah);
+bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting);
+bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us);
+void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode);
+
+/* Regulatory */
+
+bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah);
+struct ath9k_channel* ath9k_regd_check_channel(struct ath_hal *ah,
+			 const struct ath9k_channel *c);
+u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan);
+u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
+				   struct ath9k_channel *chan);
+bool ath9k_regd_init_channels(struct ath_hal *ah,
+			      u32 maxchans, u32 *nchans, u8 *regclassids,
+			      u32 maxregids, u32 *nregids, u16 cc,
+			      bool enableOutdoor, bool enableExtendedChannels);
+
+/* ANI */
+
+void ath9k_ani_reset(struct ath_hal *ah);
+void ath9k_hw_ani_monitor(struct ath_hal *ah,
+			  const struct ath9k_node_stats *stats,
+			  struct ath9k_channel *chan);
+bool ath9k_hw_phycounters(struct ath_hal *ah);
+void ath9k_enable_mib_counters(struct ath_hal *ah);
+void ath9k_hw_disable_mib_counters(struct ath_hal *ah);
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
+				  u32 *rxc_pcnt,
+				  u32 *rxf_pcnt,
+				  u32 *txf_pcnt);
+void ath9k_hw_procmibevent(struct ath_hal *ah,
+			   const struct ath9k_node_stats *stats);
+void ath9k_hw_ani_setup(struct ath_hal *ah);
+void ath9k_hw_ani_attach(struct ath_hal *ah);
+void ath9k_hw_ani_detach(struct ath_hal *ah);
+
+/* Calibration */
+
+void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
+			     bool *isCalDone);
+void ath9k_hw_start_nfcal(struct ath_hal *ah);
+void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan);
+int16_t ath9k_hw_getnf(struct ath_hal *ah,
+		       struct ath9k_channel *chan);
+void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah);
+s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan);
+bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
+			u8 rxchainmask, bool longcal,
+			bool *isCalDone);
+bool ath9k_hw_init_cal(struct ath_hal *ah,
+		       struct ath9k_channel *chan);
+
+
+/* EEPROM */
+
+int ath9k_hw_set_txpower(struct ath_hal *ah,
+			 struct ath9k_channel *chan,
+			 u16 cfgCtl,
+			 u8 twiceAntennaReduction,
+			 u8 twiceMaxRegulatoryPower,
+			 u8 powerLimit);
+void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan);
+bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
+				       struct ath9k_channel *chan,
+				       int16_t *ratesArray,
+				       u16 cfgCtl,
+				       u8 AntennaReduction,
+				       u8 twiceMaxRegulatoryPower,
+				       u8 powerLimit);
+bool ath9k_hw_set_power_cal_table(struct ath_hal *ah,
+				  struct ath9k_channel *chan,
+				  int16_t *pTxPowerIndexOffset);
+bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
+				      struct ath9k_channel *chan);
+int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah,
+				    struct ath9k_channel *chan,
+				    u8 index, u16 *config);
+u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah,
+			       enum ieee80211_band freq_band);
+u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz);
+int ath9k_hw_eeprom_attach(struct ath_hal *ah);
+
+/* Interrupt Handling */
+
+bool ath9k_hw_intrpend(struct ath_hal *ah);
+bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked);
+enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah);
+enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints);
+
+/* MAC (PCU/QCU) */
+
+u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q);
+bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp);
 bool ath9k_hw_txstart(struct ath_hal *ah, u32 q);
-u16 ath9k_hw_computetxtime(struct ath_hal *ah,
-				 const struct ath9k_rate_table *rates,
-				 u32 frameLen, u16 rateix,
-				 bool shortPreamble);
+u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q);
+bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel);
+bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q);
+bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
+			 u32 segLen, bool firstSeg,
+			 bool lastSeg, const struct ath_desc *ds0);
+void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds);
+int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
+			    u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
+			    u32 keyIx, enum ath9k_key_type keyType, u32 flags);
 void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
 				  struct ath_desc *lastds,
 				  u32 durUpdateEn, u32 rtsctsRate,
 				  u32 rtsctsDuration,
 				  struct ath9k_11n_rate_series series[],
 				  u32 nseries, u32 flags);
-void ath9k_hw_set11n_burstduration(struct ath_hal *ah,
-				   struct ath_desc *ds,
+void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
+				u32 aggrLen);
+void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
+				 u32 numDelims);
+void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
 				   u32 burstDuration);
-void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds);
-u32 ath9k_hw_reverse_bits(u32 val, u32 n);
-bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q);
-u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan);
-u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
-				     struct ath9k_channel *chan);
-u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
-bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
-			    struct ath9k_tx_queue_info *qinfo);
+void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
+				     u32 vmf);
+void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs);
 bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
 			    const struct ath9k_tx_queue_info *qinfo);
-struct ath9k_channel *ath9k_regd_check_channel(struct ath_hal *ah,
-					      const struct ath9k_channel *c);
-void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
-			    u32 pktLen, enum ath9k_pkt_type type,
-			    u32 txPower, u32 keyIx,
-			    enum ath9k_key_type keyType, u32 flags);
-bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
-			 u32 segLen, bool firstSeg,
-			 bool lastSeg,
-			 const struct ath_desc *ds0);
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
-					u32 *rxc_pcnt,
-					u32 *rxf_pcnt,
-					u32 *txf_pcnt);
-void ath9k_hw_dmaRegDump(struct ath_hal *ah);
-void ath9k_hw_beaconinit(struct ath_hal *ah,
-			 u32 next_beacon, u32 beacon_period);
-void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
-				    const struct ath9k_beacon_state *bs);
+bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
+			    struct ath9k_tx_queue_info *qinfo);
+int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
+			  const struct ath9k_tx_queue_info *qinfo);
+bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q);
+bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q);
+int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
+			u32 pa, struct ath_desc *nds, u64 tsf);
 bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
 			  u32 size, u32 flags);
+bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set);
 void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp);
 void ath9k_hw_rxena(struct ath_hal *ah);
-void ath9k_hw_setopmode(struct ath_hal *ah);
-bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac);
-void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0,
-			     u32 filter1);
-u32 ath9k_hw_getrxfilter(struct ath_hal *ah);
 void ath9k_hw_startpcureceive(struct ath_hal *ah);
 void ath9k_hw_stoppcurecv(struct ath_hal *ah);
 bool ath9k_hw_stopdmarecv(struct ath_hal *ah);
-int ath9k_hw_rxprocdesc(struct ath_hal *ah,
-			struct ath_desc *ds, u32 pa,
-			struct ath_desc *nds, u64 tsf);
-u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q);
-int ath9k_hw_txprocdesc(struct ath_hal *ah,
-			struct ath_desc *ds);
-void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
-				 u32 numDelims);
-void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
-				u32 aggrLen);
-void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds);
-bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q);
-void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs);
-void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds);
-void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah,
-				     struct ath_desc *ds, u32 vmf);
-bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit);
-bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah);
-int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
-			  const struct ath9k_tx_queue_info *qinfo);
-u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q);
-const char *ath9k_hw_probe(u16 vendorid, u16 devid);
-bool ath9k_hw_disable(struct ath_hal *ah);
-void ath9k_hw_rfdetach(struct ath_hal *ah);
-void ath9k_hw_get_channel_centers(struct ath_hal *ah,
-				  struct ath9k_channel *chan,
-				  struct chan_centers *centers);
-bool ath9k_get_channel_edges(struct ath_hal *ah,
-			     u16 flags, u16 *low,
-			     u16 *high);
-void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
-			u32 ah_signal_type);
-void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value);
-u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
-void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
+
 #endif
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c
index 4dd1c1b..3ab0b43 100644
--- a/drivers/net/wireless/ath9k/beacon.c
+++ b/drivers/net/wireless/ath9k/beacon.c
@@ -14,13 +14,9 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
- /* Implementation of beacon processing. */
-
 #include "core.h"
 
 /*
- *  Configure parameters for the beacon queue
- *
  *  This function will modify certain transmit queue properties depending on
  *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
  *  settings and channel width min/max
@@ -30,33 +26,38 @@
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath9k_tx_queue_info qi;
 
-	ath9k_hw_get_txq_props(ah, sc->sc_bhalq, &qi);
-	if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
+	ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
+	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
 		/* Always burst out beacon and CAB traffic. */
 		qi.tqi_aifs = 1;
 		qi.tqi_cwmin = 0;
 		qi.tqi_cwmax = 0;
 	} else {
 		/* Adhoc mode; important thing is to use 2x cwmin. */
-		qi.tqi_aifs = sc->sc_beacon_qi.tqi_aifs;
-		qi.tqi_cwmin = 2*sc->sc_beacon_qi.tqi_cwmin;
-		qi.tqi_cwmax = sc->sc_beacon_qi.tqi_cwmax;
+		qi.tqi_aifs = sc->beacon.beacon_qi.tqi_aifs;
+		qi.tqi_cwmin = 2*sc->beacon.beacon_qi.tqi_cwmin;
+		qi.tqi_cwmax = sc->beacon.beacon_qi.tqi_cwmax;
 	}
 
-	if (!ath9k_hw_set_txq_props(ah, sc->sc_bhalq, &qi)) {
+	if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to update h/w beacon queue parameters\n",
-			__func__);
+			"unable to update h/w beacon queue parameters\n");
 		return 0;
 	} else {
-		ath9k_hw_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */
+		ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); /* push to h/w */
 		return 1;
 	}
 }
 
+static void ath_bstuck_process(struct ath_softc *sc)
+{
+	DPRINTF(sc, ATH_DBG_BEACON,
+		"stuck beacon; resetting (bmiss count %u)\n",
+		sc->beacon.bmisscnt);
+	ath_reset(sc, false);
+}
+
 /*
- *  Setup the beacon frame for transmit.
- *
  *  Associates the beacon frame buffer with a transmit descriptor.  Will set
  *  up all required antenna switch parameters, rate codes, and channel flags.
  *  Beacons are always sent out at the lowest rate, and are not retried.
@@ -68,21 +69,20 @@
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_desc *ds;
 	struct ath9k_11n_rate_series series[4];
-	const struct ath9k_rate_table *rt;
+	struct ath_rate_table *rt;
 	int flags, antenna;
 	u8 rix, rate;
 	int ctsrate = 0;
 	int ctsduration = 0;
 
-	DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n",
-		__func__, skb, skb->len);
+	DPRINTF(sc, ATH_DBG_BEACON, "m %p len %u\n", skb, skb->len);
 
 	/* setup descriptors */
 	ds = bf->bf_desc;
 
 	flags = ATH9K_TXDESC_NOACK;
 
-	if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS &&
+	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC &&
 	    (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
 		ds->ds_link = bf->bf_daddr; /* self-linked */
 		flags |= ATH9K_TXDESC_VEOL;
@@ -96,7 +96,7 @@
 		 * SWBA's
 		 * XXX assumes two antenna
 		 */
-		antenna = ((sc->ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1);
+		antenna = ((sc->beacon.ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1);
 	}
 
 	ds->ds_data = bf->bf_buf_addr;
@@ -106,15 +106,15 @@
 	 * XXX everything at min xmit rate
 	 */
 	rix = 0;
-	rt = sc->sc_currates;
-	rate = rt->info[rix].rateCode;
+	rt = sc->cur_rate_table;
+	rate = rt->info[rix].ratecode;
 	if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
-		rate |= rt->info[rix].shortPreamble;
+		rate |= rt->info[rix].short_preamble;
 
 	ath9k_hw_set11n_txdesc(ah, ds,
 			       skb->len + FCS_LEN,     /* frame length */
 			       ATH9K_PKT_TYPE_BEACON,  /* Atheros packet type */
-			       avp->av_btxctl.txpower, /* txpower XXX */
+			       MAX_RATE_POWER,         /* FIXME */
 			       ATH9K_TXKEYIX_INVALID,  /* no encryption */
 			       ATH9K_KEY_TYPE_CLEAR,   /* no encryption */
 			       flags                   /* no ack,
@@ -138,31 +138,26 @@
 		ctsrate, ctsduration, series, 4, 0);
 }
 
-/*
- *  Generate beacon frame and queue cab data for a vap.
- *
- *  Updates the contents of the beacon frame.  It is assumed that the buffer for
- *  the beacon frame has been allocated in the ATH object, and simply needs to
- *  be filled for this cycle.  Also, any CAB (crap after beacon?) traffic will
- *  be added to the beacon frame at this point.
-*/
+/* Generate beacon frame and queue cab data for a vap */
 static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
 {
 	struct ath_buf *bf;
 	struct ath_vap *avp;
 	struct sk_buff *skb;
 	struct ath_txq *cabq;
+	struct ieee80211_vif *vif;
 	struct ieee80211_tx_info *info;
 	int cabq_depth;
 
-	avp = sc->sc_vaps[if_id];
-	ASSERT(avp);
+	vif = sc->sc_vaps[if_id];
+	ASSERT(vif);
 
-	cabq = sc->sc_cabq;
+	avp = (void *)vif->drv_priv;
+	cabq = sc->beacon.cabq;
 
 	if (avp->av_bcbuf == NULL) {
-		DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n",
-			__func__, avp, avp->av_bcbuf);
+		DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n",
+			avp, avp->av_bcbuf);
 		return NULL;
 	}
 
@@ -172,9 +167,10 @@
 		pci_unmap_single(sc->pdev, bf->bf_dmacontext,
 				 skb->len,
 				 PCI_DMA_TODEVICE);
+		dev_kfree_skb_any(skb);
 	}
 
-	skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
+	skb = ieee80211_beacon_get(sc->hw, vif);
 	bf->bf_mpdu = skb;
 	if (skb == NULL)
 		return NULL;
@@ -186,17 +182,24 @@
 		 * TX frames)
 		 */
 		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-		sc->seq_no += 0x10;
+		sc->tx.seq_no += 0x10;
 		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-		hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+		hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
 	}
 
 	bf->bf_buf_addr = bf->bf_dmacontext =
 		pci_map_single(sc->pdev, skb->data,
 			       skb->len,
 			       PCI_DMA_TODEVICE);
+	if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) {
+		dev_kfree_skb_any(skb);
+		bf->bf_mpdu = NULL;
+		DPRINTF(sc, ATH_DBG_CONFIG,
+			"pci_dma_mapping_error() on beaconing\n");
+		return NULL;
+	}
 
-	skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
+	skb = ieee80211_get_buffered_bc(sc->hw, vif);
 
 	/*
 	 * if the CABQ traffic from previous DTIM is pending and the current
@@ -219,7 +222,7 @@
 		if (sc->sc_nvaps > 1) {
 			ath_tx_draintxq(sc, cabq, false);
 			DPRINTF(sc, ATH_DBG_BEACON,
-				"%s: flush previous cabq traffic\n", __func__);
+				"flush previous cabq traffic\n");
 		}
 	}
 
@@ -232,7 +235,7 @@
 	 */
 	while (skb) {
 		ath_tx_cabq(sc, skb);
-		skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
+		skb = ieee80211_get_buffered_bc(sc->hw, vif);
 	}
 
 	return bf;
@@ -244,17 +247,20 @@
 */
 static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
 {
+	struct ieee80211_vif *vif;
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_buf *bf;
 	struct ath_vap *avp;
 	struct sk_buff *skb;
 
-	avp = sc->sc_vaps[if_id];
-	ASSERT(avp);
+	vif = sc->sc_vaps[if_id];
+	ASSERT(vif);
+
+	avp = (void *)vif->drv_priv;
 
 	if (avp->av_bcbuf == NULL) {
-		DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n",
-			__func__, avp, avp != NULL ? avp->av_bcbuf : NULL);
+		DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n",
+			avp, avp != NULL ? avp->av_bcbuf : NULL);
 		return;
 	}
 	bf = avp->av_bcbuf;
@@ -264,20 +270,12 @@
 	ath_beacon_setup(sc, avp, bf);
 
 	/* NB: caller is known to have already stopped tx dma */
-	ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr);
-	ath9k_hw_txstart(ah, sc->sc_bhalq);
-	DPRINTF(sc, ATH_DBG_BEACON, "%s: TXDP%u = %llx (%p)\n", __func__,
-		sc->sc_bhalq, ito64(bf->bf_daddr), bf->bf_desc);
+	ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
+	ath9k_hw_txstart(ah, sc->beacon.beaconq);
+	DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n",
+		sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc);
 }
 
-/*
- *  Setup a h/w transmit queue for beacons.
- *
- *  This function allocates an information structure (struct ath9k_txq_info)
- *  on the stack, sets some specific parameters (zero out channel width
- *  min/max, and enable aifs). The info structure does not need to be
- *  persistant.
-*/
 int ath_beaconq_setup(struct ath_hal *ah)
 {
 	struct ath9k_tx_queue_info qi;
@@ -290,35 +288,29 @@
 	return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
 }
 
-
-/*
- *  Allocate and setup an initial beacon frame.
- *
- *  Allocate a beacon state variable for a specific VAP instance created on
- *  the ATH interface.  This routine also calculates the beacon "slot" for
- *  staggared beacons in the mBSSID case.
-*/
 int ath_beacon_alloc(struct ath_softc *sc, int if_id)
 {
+	struct ieee80211_vif *vif;
 	struct ath_vap *avp;
 	struct ieee80211_hdr *hdr;
 	struct ath_buf *bf;
 	struct sk_buff *skb;
 	__le64 tstamp;
 
-	avp = sc->sc_vaps[if_id];
-	ASSERT(avp);
+	vif = sc->sc_vaps[if_id];
+	ASSERT(vif);
+
+	avp = (void *)vif->drv_priv;
 
 	/* Allocate a beacon descriptor if we haven't done so. */
 	if (!avp->av_bcbuf) {
 		/* Allocate beacon state for hostap/ibss.  We know
 		 * a buffer is available. */
-
-		avp->av_bcbuf = list_first_entry(&sc->sc_bbuf,
+		avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf,
 						 struct ath_buf, list);
 		list_del(&avp->av_bcbuf->list);
 
-		if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
+		if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP ||
 		    !(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
 			int slot;
 			/*
@@ -327,13 +319,13 @@
 			 */
 			avp->av_bslot = 0;
 			for (slot = 0; slot < ATH_BCBUF; slot++)
-				if (sc->sc_bslot[slot] == ATH_IF_ID_ANY) {
+				if (sc->beacon.bslot[slot] == ATH_IF_ID_ANY) {
 					/*
 					 * XXX hack, space out slots to better
 					 * deal with misses
 					 */
 					if (slot+1 < ATH_BCBUF &&
-					    sc->sc_bslot[slot+1] ==
+					    sc->beacon.bslot[slot+1] ==
 						ATH_IF_ID_ANY) {
 						avp->av_bslot = slot+1;
 						break;
@@ -341,8 +333,8 @@
 					avp->av_bslot = slot;
 					/* NB: keep looking for a double slot */
 				}
-			BUG_ON(sc->sc_bslot[avp->av_bslot] != ATH_IF_ID_ANY);
-			sc->sc_bslot[avp->av_bslot] = if_id;
+			BUG_ON(sc->beacon.bslot[avp->av_bslot] != ATH_IF_ID_ANY);
+			sc->beacon.bslot[avp->av_bslot] = if_id;
 			sc->sc_nbcnvaps++;
 		}
 	}
@@ -363,15 +355,14 @@
 	 * FIXME: Fill avp->av_btxctl.txpower and
 	 * avp->av_btxctl.shortPreamble
 	 */
-	skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
+	skb = ieee80211_beacon_get(sc->hw, vif);
 	if (skb == NULL) {
-		DPRINTF(sc, ATH_DBG_BEACON, "%s: cannot get skb\n",
-			__func__);
+		DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n");
 		return -ENOMEM;
 	}
 
 	tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
-	sc->bc_tstamp = le64_to_cpu(tstamp);
+	sc->beacon.bc_tstamp = le64_to_cpu(tstamp);
 
 	/*
 	 * Calculate a TSF adjustment factor required for
@@ -402,36 +393,36 @@
 		val = cpu_to_le64(tsfadjust << 10);     /* TU->TSF */
 
 		DPRINTF(sc, ATH_DBG_BEACON,
-			"%s: %s beacons, bslot %d intval %u tsfadjust %llu\n",
-			__func__, "stagger",
+			"stagger beacons, bslot %d intval %u tsfadjust %llu\n",
 			avp->av_bslot, intval, (unsigned long long)tsfadjust);
 
 		hdr = (struct ieee80211_hdr *)skb->data;
 		memcpy(&hdr[1], &val, sizeof(val));
 	}
 
+	bf->bf_mpdu = skb;
 	bf->bf_buf_addr = bf->bf_dmacontext =
 		pci_map_single(sc->pdev, skb->data,
 			       skb->len,
 			       PCI_DMA_TODEVICE);
-	bf->bf_mpdu = skb;
+	if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) {
+		dev_kfree_skb_any(skb);
+		bf->bf_mpdu = NULL;
+		DPRINTF(sc, ATH_DBG_CONFIG,
+			"pci_dma_mapping_error() on beacon alloc\n");
+		return -ENOMEM;
+	}
 
 	return 0;
 }
 
-/*
- *  Reclaim beacon resources and return buffer to the pool.
- *
- *  Checks the VAP to put the beacon frame buffer back to the ATH object
- *  queue, and de-allocates any skbs that were sent as CAB traffic.
-*/
 void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
 {
 	if (avp->av_bcbuf != NULL) {
 		struct ath_buf *bf;
 
 		if (avp->av_bslot != -1) {
-			sc->sc_bslot[avp->av_bslot] = ATH_IF_ID_ANY;
+			sc->beacon.bslot[avp->av_bslot] = ATH_IF_ID_ANY;
 			sc->sc_nbcnvaps--;
 		}
 
@@ -444,19 +435,12 @@
 			dev_kfree_skb_any(skb);
 			bf->bf_mpdu = NULL;
 		}
-		list_add_tail(&bf->list, &sc->sc_bbuf);
+		list_add_tail(&bf->list, &sc->beacon.bbuf);
 
 		avp->av_bcbuf = NULL;
 	}
 }
 
-/*
- * Tasklet for Sending Beacons
- *
- * Transmit one or more beacon frames at SWBA.  Dynamic updates to the frame
- * contents are done as needed and the slot time is also adjusted based on
- * current state.
-*/
 void ath9k_beacon_tasklet(unsigned long data)
 {
 	struct ath_softc *sc = (struct ath_softc *)data;
@@ -473,9 +457,7 @@
 
 	if (sc->sc_flags & SC_OP_NO_RESET) {
 		show_cycles = ath9k_hw_GetMibCycleCountsPct(ah,
-							    &rx_clear,
-							    &rx_frame,
-							    &tx_frame);
+					    &rx_clear, &rx_frame, &tx_frame);
 	}
 
 	/*
@@ -487,67 +469,65 @@
 	 *
 	 * FIXME: Clean up this mess !!
 	 */
-	if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) {
-		sc->sc_bmisscount++;
+	if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
+		sc->beacon.bmisscnt++;
 		/* XXX: doth needs the chanchange IE countdown decremented.
 		 *      We should consider adding a mac80211 call to indicate
 		 *      a beacon miss so appropriate action could be taken
 		 *      (in that layer).
 		 */
-		if (sc->sc_bmisscount < BSTUCK_THRESH) {
+		if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
 			if (sc->sc_flags & SC_OP_NO_RESET) {
 				DPRINTF(sc, ATH_DBG_BEACON,
-					"%s: missed %u consecutive beacons\n",
-					__func__, sc->sc_bmisscount);
+					"missed %u consecutive beacons\n",
+					sc->beacon.bmisscnt);
 				if (show_cycles) {
 					/*
 					 * Display cycle counter stats from HW
 					 * to aide in debug of stickiness.
 					 */
 					DPRINTF(sc, ATH_DBG_BEACON,
-						"%s: busy times: rx_clear=%d, "
+						"busy times: rx_clear=%d, "
 						"rx_frame=%d, tx_frame=%d\n",
-						__func__, rx_clear, rx_frame,
+						rx_clear, rx_frame,
 						tx_frame);
 				} else {
 					DPRINTF(sc, ATH_DBG_BEACON,
-						"%s: unable to obtain "
-						"busy times\n", __func__);
+						"unable to obtain "
+						"busy times\n");
 				}
 			} else {
 				DPRINTF(sc, ATH_DBG_BEACON,
-					"%s: missed %u consecutive beacons\n",
-					__func__, sc->sc_bmisscount);
+					"missed %u consecutive beacons\n",
+					sc->beacon.bmisscnt);
 			}
-		} else if (sc->sc_bmisscount >= BSTUCK_THRESH) {
+		} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
 			if (sc->sc_flags & SC_OP_NO_RESET) {
-				if (sc->sc_bmisscount == BSTUCK_THRESH) {
+				if (sc->beacon.bmisscnt == BSTUCK_THRESH) {
 					DPRINTF(sc, ATH_DBG_BEACON,
-						"%s: beacon is officially "
-						"stuck\n", __func__);
-					ath9k_hw_dmaRegDump(ah);
+						"beacon is officially "
+						"stuck\n");
 				}
 			} else {
 				DPRINTF(sc, ATH_DBG_BEACON,
-					"%s: beacon is officially stuck\n",
-					__func__);
+					"beacon is officially stuck\n");
 				ath_bstuck_process(sc);
 			}
 		}
 		return;
 	}
 
-	if (sc->sc_bmisscount != 0) {
+	if (sc->beacon.bmisscnt != 0) {
 		if (sc->sc_flags & SC_OP_NO_RESET) {
 			DPRINTF(sc, ATH_DBG_BEACON,
-				"%s: resume beacon xmit after %u misses\n",
-				__func__, sc->sc_bmisscount);
+				"resume beacon xmit after %u misses\n",
+				sc->beacon.bmisscnt);
 		} else {
 			DPRINTF(sc, ATH_DBG_BEACON,
-				"%s: resume beacon xmit after %u misses\n",
-				__func__, sc->sc_bmisscount);
+				"resume beacon xmit after %u misses\n",
+				sc->beacon.bmisscnt);
 		}
-		sc->sc_bmisscount = 0;
+		sc->beacon.bmisscnt = 0;
 	}
 
 	/*
@@ -562,11 +542,11 @@
 	tsf = ath9k_hw_gettsf64(ah);
 	tsftu = TSF_TO_TU(tsf>>32, tsf);
 	slot = ((tsftu % intval) * ATH_BCBUF) / intval;
-	if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF];
+	if_id = sc->beacon.bslot[(slot + 1) % ATH_BCBUF];
 
 	DPRINTF(sc, ATH_DBG_BEACON,
-		"%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
-		__func__, slot, (unsigned long long)tsf, tsftu,
+		"slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
+		slot, (unsigned long long)tsf, tsftu,
 		intval, if_id);
 
 	bfaddr = 0;
@@ -594,48 +574,34 @@
 	 *     set to ATH_BCBUF so this check is a noop.
 	 */
 	/* XXX locking */
-	if (sc->sc_updateslot == UPDATE) {
-		sc->sc_updateslot = COMMIT; /* commit next beacon */
-		sc->sc_slotupdate = slot;
-	} else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot)
-		ath_setslottime(sc);        /* commit change to hardware */
-
+	if (sc->beacon.updateslot == UPDATE) {
+		sc->beacon.updateslot = COMMIT; /* commit next beacon */
+		sc->beacon.slotupdate = slot;
+	} else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) {
+		ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime);
+		sc->beacon.updateslot = OK;
+	}
 	if (bfaddr != 0) {
 		/*
 		 * Stop any current dma and put the new frame(s) on the queue.
 		 * This should never fail since we check above that no frames
 		 * are still pending on the queue.
 		 */
-		if (!ath9k_hw_stoptxdma(ah, sc->sc_bhalq)) {
+		if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
 			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: beacon queue %u did not stop?\n",
-				__func__, sc->sc_bhalq);
+				"beacon queue %u did not stop?\n", sc->beacon.beaconq);
 			/* NB: the HAL still stops DMA, so proceed */
 		}
 
 		/* NB: cabq traffic should already be queued and primed */
-		ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bfaddr);
-		ath9k_hw_txstart(ah, sc->sc_bhalq);
+		ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
+		ath9k_hw_txstart(ah, sc->beacon.beaconq);
 
-		sc->ast_be_xmit += bc;     /* XXX per-vap? */
+		sc->beacon.ast_be_xmit += bc;     /* XXX per-vap? */
 	}
 }
 
 /*
- *  Tasklet for Beacon Stuck processing
- *
- *  Processing for Beacon Stuck.
- *  Basically resets the chip.
-*/
-void ath_bstuck_process(struct ath_softc *sc)
-{
-	DPRINTF(sc, ATH_DBG_BEACON,
-		"%s: stuck beacon; resetting (bmiss count %u)\n",
-		__func__, sc->sc_bmisscount);
-	ath_reset(sc, false);
-}
-
-/*
  * Configure the beacon and sleep timers.
  *
  * When operating as an AP this resets the TSF and sets
@@ -652,15 +618,21 @@
  */
 void ath_beacon_config(struct ath_softc *sc, int if_id)
 {
+	struct ieee80211_vif *vif;
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_beacon_config conf;
-	enum ath9k_opmode av_opmode;
+	struct ath_vap *avp;
+	enum nl80211_iftype opmode;
 	u32 nexttbtt, intval;
 
-	if (if_id != ATH_IF_ID_ANY)
-		av_opmode = sc->sc_vaps[if_id]->av_opmode;
-	else
-		av_opmode = sc->sc_ah->ah_opmode;
+	if (if_id != ATH_IF_ID_ANY) {
+		vif = sc->sc_vaps[if_id];
+		ASSERT(vif);
+		avp = (void *)vif->drv_priv;
+		opmode = avp->av_opmode;
+	} else {
+		opmode = sc->sc_ah->ah_opmode;
+	}
 
 	memset(&conf, 0, sizeof(struct ath_beacon_config));
 
@@ -672,10 +644,10 @@
 	conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
 
 	/* extract tstamp from last beacon and convert to TU */
-	nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp);
+	nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
 
 	/* XXX conditionalize multi-bss support? */
-	if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
+	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
 		/*
 		 * For multi-bss ap support beacons are either staggered
 		 * evenly over N slots or burst together.  For the former
@@ -694,11 +666,11 @@
 	else if (intval)	/* NB: can be 0 for monitor mode */
 		nexttbtt = roundup(nexttbtt, intval);
 
-	DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
-		__func__, nexttbtt, intval, conf.beacon_interval);
+	DPRINTF(sc, ATH_DBG_BEACON, "nexttbtt %u intval %u (%u)\n",
+		nexttbtt, intval, conf.beacon_interval);
 
-	/* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */
-	if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
+	/* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */
+	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) {
 		struct ath9k_beacon_state bs;
 		u64 tsf;
 		u32 tsftu;
@@ -782,7 +754,7 @@
 			bs.bs_sleepduration = bs.bs_dtimperiod;
 
 		DPRINTF(sc, ATH_DBG_BEACON,
-			"%s: tsf %llu "
+			"tsf %llu "
 			"tsf:tu %u "
 			"intval %u "
 			"nexttbtt %u "
@@ -794,7 +766,6 @@
 			"maxdur %u "
 			"next %u "
 			"timoffset %u\n",
-			__func__,
 			(unsigned long long)tsf, tsftu,
 			bs.bs_intval,
 			bs.bs_nexttbtt,
@@ -818,7 +789,7 @@
 		ath9k_hw_set_interrupts(ah, 0);
 		if (nexttbtt == intval)
 			intval |= ATH9K_BEACON_RESET_TSF;
-		if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
+		if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) {
 			/*
 			 * Pull nexttbtt forward to reflect the current
 			 * TSF
@@ -834,8 +805,8 @@
 			}
 #undef FUDGE
 			DPRINTF(sc, ATH_DBG_BEACON,
-				"%s: IBSS nexttbtt %u intval %u (%u)\n",
-				__func__, nexttbtt,
+				"IBSS nexttbtt %u intval %u (%u)\n",
+				nexttbtt,
 				intval & ~ATH9K_BEACON_RESET_TSF,
 				conf.beacon_interval);
 
@@ -850,7 +821,7 @@
 			if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
 				sc->sc_imask |= ATH9K_INT_SWBA;
 			ath_beaconq_config(sc);
-		} else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
+		} else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
 			/*
 			 * In AP mode we enable the beacon timers and
 			 * SWBA interrupts to prepare beacon frames.
@@ -860,20 +831,18 @@
 			ath_beaconq_config(sc);
 		}
 		ath9k_hw_beaconinit(ah, nexttbtt, intval);
-		sc->sc_bmisscount = 0;
+		sc->beacon.bmisscnt = 0;
 		ath9k_hw_set_interrupts(ah, sc->sc_imask);
 		/*
 		 * When using a self-linked beacon descriptor in
 		 * ibss mode load it once here.
 		 */
-		if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS &&
+		if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC &&
 		    (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
 			ath_beacon_start_adhoc(sc, 0);
 	}
 }
 
-/* Function to collect beacon rssi data and resync beacon if necessary */
-
 void ath_beacon_sync(struct ath_softc *sc, int if_id)
 {
 	/*
diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c
new file mode 100644
index 0000000..3c7454f
--- /dev/null
+++ b/drivers/net/wireless/ath9k/calib.c
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 };
+
+/* We can tune this as we go by monitoring really low values */
+#define ATH9K_NF_TOO_LOW	-60
+
+/* AR5416 may return very high value (like -31 dBm), in those cases the nf
+ * is incorrect and we should use the static NF value. Later we can try to
+ * find out why they are reporting these values */
+
+static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
+{
+	if (nf > ATH9K_NF_TOO_LOW) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"noise floor value detected (%d) is "
+			"lower than what we think is a "
+			"reasonable value (%d)\n",
+			nf, ATH9K_NF_TOO_LOW);
+		return false;
+	}
+	return true;
+}
+
+static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
+{
+	int16_t nfval;
+	int16_t sort[ATH9K_NF_CAL_HIST_MAX];
+	int i, j;
+
+	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
+		sort[i] = nfCalBuffer[i];
+
+	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
+		for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
+			if (sort[j] > sort[j - 1]) {
+				nfval = sort[j];
+				sort[j] = sort[j - 1];
+				sort[j - 1] = nfval;
+			}
+		}
+	}
+	nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
+
+	return nfval;
+}
+
+static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
+					      int16_t *nfarray)
+{
+	int i;
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
+
+		if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
+			h[i].currIndex = 0;
+
+		if (h[i].invalidNFcount > 0) {
+			if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
+			    nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
+				h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
+			} else {
+				h[i].invalidNFcount--;
+				h[i].privNF = nfarray[i];
+			}
+		} else {
+			h[i].privNF =
+				ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
+		}
+	}
+	return;
+}
+
+static void ath9k_hw_do_getnf(struct ath_hal *ah,
+			      int16_t nfarray[NUM_NF_READINGS])
+{
+	int16_t nf;
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
+	else
+		nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
+
+	if (nf & 0x100)
+		nf = 0 - ((nf ^ 0x1ff) + 1);
+	DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+		"NF calibrated [ctl] [chain 0] is %d\n", nf);
+	nfarray[0] = nf;
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
+			AR9280_PHY_CH1_MINCCA_PWR);
+	else
+		nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
+			AR_PHY_CH1_MINCCA_PWR);
+
+	if (nf & 0x100)
+		nf = 0 - ((nf ^ 0x1ff) + 1);
+	DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+		"NF calibrated [ctl] [chain 1] is %d\n", nf);
+	nfarray[1] = nf;
+
+	if (!AR_SREV_9280(ah)) {
+		nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
+			AR_PHY_CH2_MINCCA_PWR);
+		if (nf & 0x100)
+			nf = 0 - ((nf ^ 0x1ff) + 1);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"NF calibrated [ctl] [chain 2] is %d\n", nf);
+		nfarray[2] = nf;
+	}
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
+			AR9280_PHY_EXT_MINCCA_PWR);
+	else
+		nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
+			AR_PHY_EXT_MINCCA_PWR);
+
+	if (nf & 0x100)
+		nf = 0 - ((nf ^ 0x1ff) + 1);
+	DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+		"NF calibrated [ext] [chain 0] is %d\n", nf);
+	nfarray[3] = nf;
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
+			AR9280_PHY_CH1_EXT_MINCCA_PWR);
+	else
+		nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
+			AR_PHY_CH1_EXT_MINCCA_PWR);
+
+	if (nf & 0x100)
+		nf = 0 - ((nf ^ 0x1ff) + 1);
+	DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+		"NF calibrated [ext] [chain 1] is %d\n", nf);
+	nfarray[4] = nf;
+
+	if (!AR_SREV_9280(ah)) {
+		nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
+			AR_PHY_CH2_EXT_MINCCA_PWR);
+		if (nf & 0x100)
+			nf = 0 - ((nf ^ 0x1ff) + 1);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"NF calibrated [ext] [chain 2] is %d\n", nf);
+		nfarray[5] = nf;
+	}
+}
+
+static bool getNoiseFloorThresh(struct ath_hal *ah,
+				const struct ath9k_channel *chan,
+				int16_t *nft)
+{
+	switch (chan->chanmode) {
+	case CHANNEL_A:
+	case CHANNEL_A_HT20:
+	case CHANNEL_A_HT40PLUS:
+	case CHANNEL_A_HT40MINUS:
+		*nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5);
+		break;
+	case CHANNEL_B:
+	case CHANNEL_G:
+	case CHANNEL_G_HT20:
+	case CHANNEL_G_HT40PLUS:
+	case CHANNEL_G_HT40MINUS:
+		*nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
+		break;
+	default:
+		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+			"invalid channel flags 0x%x\n", chan->channelFlags);
+		return false;
+	}
+
+	return true;
+}
+
+static void ath9k_hw_setup_calibration(struct ath_hal *ah,
+				       struct hal_cal_list *currCal)
+{
+	REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
+		      AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
+		      currCal->calData->calCountMax);
+
+	switch (currCal->calData->calType) {
+	case IQ_MISMATCH_CAL:
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"starting IQ Mismatch Calibration\n");
+		break;
+	case ADC_GAIN_CAL:
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"starting ADC Gain Calibration\n");
+		break;
+	case ADC_DC_CAL:
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"starting ADC DC Calibration\n");
+		break;
+	case ADC_DC_INIT_CAL:
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"starting Init ADC DC Calibration\n");
+		break;
+	}
+
+	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+		    AR_PHY_TIMING_CTRL4_DO_CAL);
+}
+
+static void ath9k_hw_reset_calibration(struct ath_hal *ah,
+				       struct hal_cal_list *currCal)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	ath9k_hw_setup_calibration(ah, currCal);
+
+	currCal->calState = CAL_RUNNING;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ahp->ah_Meas0.sign[i] = 0;
+		ahp->ah_Meas1.sign[i] = 0;
+		ahp->ah_Meas2.sign[i] = 0;
+		ahp->ah_Meas3.sign[i] = 0;
+	}
+
+	ahp->ah_CalSamples = 0;
+}
+
+static void ath9k_hw_per_calibration(struct ath_hal *ah,
+				     struct ath9k_channel *ichan,
+				     u8 rxchainmask,
+				     struct hal_cal_list *currCal,
+				     bool *isCalDone)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	*isCalDone = false;
+
+	if (currCal->calState == CAL_RUNNING) {
+		if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
+		      AR_PHY_TIMING_CTRL4_DO_CAL)) {
+
+			currCal->calData->calCollect(ah);
+			ahp->ah_CalSamples++;
+
+			if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) {
+				int i, numChains = 0;
+				for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+					if (rxchainmask & (1 << i))
+						numChains++;
+				}
+
+				currCal->calData->calPostProc(ah, numChains);
+				ichan->CalValid |= currCal->calData->calType;
+				currCal->calState = CAL_DONE;
+				*isCalDone = true;
+			} else {
+				ath9k_hw_setup_calibration(ah, currCal);
+			}
+		}
+	} else if (!(ichan->CalValid & currCal->calData->calType)) {
+		ath9k_hw_reset_calibration(ah, currCal);
+	}
+}
+
+static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
+				     struct ath9k_channel *chan,
+				     enum hal_cal_types calType)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	bool retval = false;
+
+	switch (calType & ahp->ah_suppCals) {
+	case IQ_MISMATCH_CAL:
+		if (!IS_CHAN_B(chan))
+			retval = true;
+		break;
+	case ADC_GAIN_CAL:
+	case ADC_DC_CAL:
+		if (!IS_CHAN_B(chan)
+		    && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
+			retval = true;
+		break;
+	}
+
+	return retval;
+}
+
+static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ahp->ah_totalPowerMeasI[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+		ahp->ah_totalPowerMeasQ[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+		ahp->ah_totalIqCorrMeas[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+			ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
+			ahp->ah_totalPowerMeasQ[i],
+			ahp->ah_totalIqCorrMeas[i]);
+	}
+}
+
+static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ahp->ah_totalAdcIOddPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+		ahp->ah_totalAdcIEvenPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+		ahp->ah_totalAdcQOddPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+		ahp->ah_totalAdcQEvenPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+			"oddq=0x%08x; evenq=0x%08x;\n",
+			ahp->ah_CalSamples, i,
+			ahp->ah_totalAdcIOddPhase[i],
+			ahp->ah_totalAdcIEvenPhase[i],
+			ahp->ah_totalAdcQOddPhase[i],
+			ahp->ah_totalAdcQEvenPhase[i]);
+	}
+}
+
+static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int i;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+		ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+		ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+		ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+			"oddq=0x%08x; evenq=0x%08x;\n",
+			ahp->ah_CalSamples, i,
+			ahp->ah_totalAdcDcOffsetIOddPhase[i],
+			ahp->ah_totalAdcDcOffsetIEvenPhase[i],
+			ahp->ah_totalAdcDcOffsetQOddPhase[i],
+			ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
+	}
+}
+
+static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 powerMeasQ, powerMeasI, iqCorrMeas;
+	u32 qCoffDenom, iCoffDenom;
+	int32_t qCoff, iCoff;
+	int iqCorrNeg, i;
+
+	for (i = 0; i < numChains; i++) {
+		powerMeasI = ahp->ah_totalPowerMeasI[i];
+		powerMeasQ = ahp->ah_totalPowerMeasQ[i];
+		iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Starting IQ Cal and Correction for Chain %d\n",
+			i);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Orignal: Chn %diq_corr_meas = 0x%08x\n",
+			i, ahp->ah_totalIqCorrMeas[i]);
+
+		iqCorrNeg = 0;
+
+		if (iqCorrMeas > 0x80000000) {
+			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
+			iqCorrNeg = 1;
+		}
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
+			iqCorrNeg);
+
+		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
+		qCoffDenom = powerMeasQ / 64;
+
+		if (powerMeasQ != 0) {
+			iCoff = iqCorrMeas / iCoffDenom;
+			qCoff = powerMeasI / qCoffDenom - 64;
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"Chn %d iCoff = 0x%08x\n", i, iCoff);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"Chn %d qCoff = 0x%08x\n", i, qCoff);
+
+			iCoff = iCoff & 0x3f;
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"New: Chn %d iCoff = 0x%08x\n", i, iCoff);
+			if (iqCorrNeg == 0x0)
+				iCoff = 0x40 - iCoff;
+
+			if (qCoff > 15)
+				qCoff = 15;
+			else if (qCoff <= -16)
+				qCoff = 16;
+
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
+				i, iCoff, qCoff);
+
+			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+				      AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
+				      iCoff);
+			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+				      AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
+				      qCoff);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"IQ Cal and Correction done for Chain %d\n",
+				i);
+		}
+	}
+
+	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+		    AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
+}
+
+static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
+	u32 qGainMismatch, iGainMismatch, val, i;
+
+	for (i = 0; i < numChains; i++) {
+		iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
+		iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
+		qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
+		qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Starting ADC Gain Cal for Chain %d\n", i);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_odd_i = 0x%08x\n", i,
+			iOddMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_even_i = 0x%08x\n", i,
+			iEvenMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_odd_q = 0x%08x\n", i,
+			qOddMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_even_q = 0x%08x\n", i,
+			qEvenMeasOffset);
+
+		if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
+			iGainMismatch =
+				((iEvenMeasOffset * 32) /
+				 iOddMeasOffset) & 0x3f;
+			qGainMismatch =
+				((qOddMeasOffset * 32) /
+				 qEvenMeasOffset) & 0x3f;
+
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"Chn %d gain_mismatch_i = 0x%08x\n", i,
+				iGainMismatch);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"Chn %d gain_mismatch_q = 0x%08x\n", i,
+				qGainMismatch);
+
+			val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+			val &= 0xfffff000;
+			val |= (qGainMismatch) | (iGainMismatch << 6);
+			REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"ADC Gain Cal done for Chain %d\n", i);
+		}
+	}
+
+	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+		  AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
+}
+
+static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 iOddMeasOffset, iEvenMeasOffset, val, i;
+	int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
+	const struct hal_percal_data *calData =
+		ahp->ah_cal_list_curr->calData;
+	u32 numSamples =
+		(1 << (calData->calCountMax + 5)) * calData->calNumSamples;
+
+	for (i = 0; i < numChains; i++) {
+		iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
+		iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
+		qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
+		qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Starting ADC DC Offset Cal for Chain %d\n", i);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_odd_i = %d\n", i,
+			iOddMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_even_i = %d\n", i,
+			iEvenMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_odd_q = %d\n", i,
+			qOddMeasOffset);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d pwr_meas_even_q = %d\n", i,
+			qEvenMeasOffset);
+
+		iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
+			       numSamples) & 0x1ff;
+		qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
+			       numSamples) & 0x1ff;
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
+			iDcMismatch);
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
+			qDcMismatch);
+
+		val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+		val &= 0xc0000fff;
+		val |= (qDcMismatch << 12) | (iDcMismatch << 21);
+		REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"ADC DC Offset Cal done for Chain %d\n", i);
+	}
+
+	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+		  AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
+}
+
+void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
+			     bool *isCalDone)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_channel *ichan =
+		ath9k_regd_check_channel(ah, chan);
+	struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+
+	*isCalDone = true;
+
+	if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
+		return;
+
+	if (currCal == NULL)
+		return;
+
+	if (ichan == NULL) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"invalid channel %u/0x%x; no mapping\n",
+			chan->channel, chan->channelFlags);
+		return;
+	}
+
+
+	if (currCal->calState != CAL_DONE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"Calibration state incorrect, %d\n",
+			currCal->calState);
+		return;
+	}
+
+
+	if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType))
+		return;
+
+	DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+		"Resetting Cal %d state for channel %u/0x%x\n",
+		currCal->calData->calType, chan->channel,
+		chan->channelFlags);
+
+	ichan->CalValid &= ~currCal->calData->calType;
+	currCal->calState = CAL_WAITING;
+
+	*isCalDone = false;
+}
+
+void ath9k_hw_start_nfcal(struct ath_hal *ah)
+{
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_ENABLE_NF);
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+}
+
+void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+	struct ath9k_nfcal_hist *h;
+	int i, j;
+	int32_t val;
+	const u32 ar5416_cca_regs[6] = {
+		AR_PHY_CCA,
+		AR_PHY_CH1_CCA,
+		AR_PHY_CH2_CCA,
+		AR_PHY_EXT_CCA,
+		AR_PHY_CH1_EXT_CCA,
+		AR_PHY_CH2_EXT_CCA
+	};
+	u8 chainmask;
+
+	if (AR_SREV_9280(ah))
+		chainmask = 0x1B;
+	else
+		chainmask = 0x3F;
+
+#ifdef ATH_NF_PER_CHAN
+	h = chan->nfCalHist;
+#else
+	h = ah->nfCalHist;
+#endif
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (chainmask & (1 << i)) {
+			val = REG_READ(ah, ar5416_cca_regs[i]);
+			val &= 0xFFFFFE00;
+			val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+			REG_WRITE(ah, ar5416_cca_regs[i], val);
+		}
+	}
+
+	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_ENABLE_NF);
+	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+
+	for (j = 0; j < 1000; j++) {
+		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
+		     AR_PHY_AGC_CONTROL_NF) == 0)
+			break;
+		udelay(10);
+	}
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (chainmask & (1 << i)) {
+			val = REG_READ(ah, ar5416_cca_regs[i]);
+			val &= 0xFFFFFE00;
+			val |= (((u32) (-50) << 1) & 0x1ff);
+			REG_WRITE(ah, ar5416_cca_regs[i], val);
+		}
+	}
+}
+
+int16_t ath9k_hw_getnf(struct ath_hal *ah,
+		       struct ath9k_channel *chan)
+{
+	int16_t nf, nfThresh;
+	int16_t nfarray[NUM_NF_READINGS] = { 0 };
+	struct ath9k_nfcal_hist *h;
+	u8 chainmask;
+
+	if (AR_SREV_9280(ah))
+		chainmask = 0x1B;
+	else
+		chainmask = 0x3F;
+
+	chan->channelFlags &= (~CHANNEL_CW_INT);
+	if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"NF did not complete in calibration window\n");
+		nf = 0;
+		chan->rawNoiseFloor = nf;
+		return chan->rawNoiseFloor;
+	} else {
+		ath9k_hw_do_getnf(ah, nfarray);
+		nf = nfarray[0];
+		if (getNoiseFloorThresh(ah, chan, &nfThresh)
+		    && nf > nfThresh) {
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"noise floor failed detected; "
+				"detected %d, threshold %d\n",
+				nf, nfThresh);
+			chan->channelFlags |= CHANNEL_CW_INT;
+		}
+	}
+
+#ifdef ATH_NF_PER_CHAN
+	h = chan->nfCalHist;
+#else
+	h = ah->nfCalHist;
+#endif
+
+	ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
+	chan->rawNoiseFloor = h[0].privNF;
+
+	return chan->rawNoiseFloor;
+}
+
+void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
+{
+	int i, j;
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		ah->nfCalHist[i].currIndex = 0;
+		ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
+		ah->nfCalHist[i].invalidNFcount =
+			AR_PHY_CCA_FILTERWINDOW_LENGTH;
+		for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
+			ah->nfCalHist[i].nfCalBuffer[j] =
+				AR_PHY_CCA_MAX_GOOD_VALUE;
+		}
+	}
+	return;
+}
+
+s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+	struct ath9k_channel *ichan;
+	s16 nf;
+
+	ichan = ath9k_regd_check_channel(ah, chan);
+	if (ichan == NULL) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"invalid channel %u/0x%x; no mapping\n",
+			chan->channel, chan->channelFlags);
+		return ATH_DEFAULT_NOISE_FLOOR;
+	}
+	if (ichan->rawNoiseFloor == 0) {
+		enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
+		nf = NOISE_FLOOR[mode];
+	} else
+		nf = ichan->rawNoiseFloor;
+
+	if (!ath9k_hw_nf_in_range(ah, nf))
+		nf = ATH_DEFAULT_NOISE_FLOOR;
+
+	return nf;
+}
+
+bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
+			u8 rxchainmask, bool longcal,
+			bool *isCalDone)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+	struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
+
+	*isCalDone = true;
+
+	if (ichan == NULL) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+			"invalid channel %u/0x%x; no mapping\n",
+			chan->channel, chan->channelFlags);
+		return false;
+	}
+
+	if (currCal &&
+	    (currCal->calState == CAL_RUNNING ||
+	     currCal->calState == CAL_WAITING)) {
+		ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal,
+					 isCalDone);
+		if (*isCalDone) {
+			ahp->ah_cal_list_curr = currCal = currCal->calNext;
+
+			if (currCal->calState == CAL_WAITING) {
+				*isCalDone = false;
+				ath9k_hw_reset_calibration(ah, currCal);
+			}
+		}
+	}
+
+	if (longcal) {
+		ath9k_hw_getnf(ah, ichan);
+		ath9k_hw_loadnf(ah, ah->ah_curchan);
+		ath9k_hw_start_nfcal(ah);
+
+		if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) {
+			chan->channelFlags |= CHANNEL_CW_INT;
+			ichan->channelFlags &= ~CHANNEL_CW_INT;
+		}
+	}
+
+	return true;
+}
+
+static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah)
+{
+
+	u32 regVal;
+	int i, offset, offs_6_1, offs_0;
+	u32 ccomp_org, reg_field;
+	u32 regList[][2] = {
+		{ 0x786c, 0 },
+		{ 0x7854, 0 },
+		{ 0x7820, 0 },
+		{ 0x7824, 0 },
+		{ 0x7868, 0 },
+		{ 0x783c, 0 },
+		{ 0x7838, 0 },
+	};
+
+	if (AR_SREV_9285_11(ah)) {
+		REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
+		udelay(10);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(regList); i++)
+		regList[i][1] = REG_READ(ah, regList[i][0]);
+
+	regVal = REG_READ(ah, 0x7834);
+	regVal &= (~(0x1));
+	REG_WRITE(ah, 0x7834, regVal);
+	regVal = REG_READ(ah, 0x9808);
+	regVal |= (0x1 << 27);
+	REG_WRITE(ah, 0x9808, regVal);
+
+	REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
+	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
+	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
+	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
+	ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7);
+
+	REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
+	udelay(30);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
+
+	for (i = 6; i > 0; i--) {
+		regVal = REG_READ(ah, 0x7834);
+		regVal |= (1 << (19 + i));
+		REG_WRITE(ah, 0x7834, regVal);
+		udelay(1);
+		regVal = REG_READ(ah, 0x7834);
+		regVal &= (~(0x1 << (19 + i)));
+		reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
+		regVal |= (reg_field << (19 + i));
+		REG_WRITE(ah, 0x7834, regVal);
+	}
+
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
+	udelay(1);
+	reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
+	offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
+	offs_0   = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
+
+	offset = (offs_6_1<<1) | offs_0;
+	offset = offset - 0;
+	offs_6_1 = offset>>1;
+	offs_0 = offset & 1;
+
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
+
+	regVal = REG_READ(ah, 0x7834);
+	regVal |= 0x1;
+	REG_WRITE(ah, 0x7834, regVal);
+	regVal = REG_READ(ah, 0x9808);
+	regVal &= (~(0x1 << 27));
+	REG_WRITE(ah, 0x9808, regVal);
+
+	for (i = 0; i < ARRAY_SIZE(regList); i++)
+		REG_WRITE(ah, regList[i][0], regList[i][1]);
+
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
+
+	if (AR_SREV_9285_11(ah))
+		REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
+
+}
+
+bool ath9k_hw_init_cal(struct ath_hal *ah,
+		       struct ath9k_channel *chan)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
+
+	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
+		  AR_PHY_AGC_CONTROL_CAL);
+
+	if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+			"offset calibration failed to complete in 1ms; "
+			"noisy environment?\n");
+		return false;
+	}
+
+	if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah))
+		ath9k_hw_9285_pa_cal(ah);
+
+	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
+		  AR_PHY_AGC_CONTROL_NF);
+
+	ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
+
+	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
+		if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
+			INIT_CAL(&ahp->ah_adcGainCalData);
+			INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"enabling ADC Gain Calibration.\n");
+		}
+		if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
+			INIT_CAL(&ahp->ah_adcDcCalData);
+			INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"enabling ADC DC Calibration.\n");
+		}
+		if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
+			INIT_CAL(&ahp->ah_iqCalData);
+			INSERT_CAL(ahp, &ahp->ah_iqCalData);
+			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+				"enabling IQ Calibration.\n");
+		}
+
+		ahp->ah_cal_list_curr = ahp->ah_cal_list;
+
+		if (ahp->ah_cal_list_curr)
+			ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr);
+	}
+
+	ichan->CalValid = 0;
+
+	return true;
+}
+
+const struct hal_percal_data iq_cal_multi_sample = {
+	IQ_MISMATCH_CAL,
+	MAX_CAL_SAMPLES,
+	PER_MIN_LOG_COUNT,
+	ath9k_hw_iqcal_collect,
+	ath9k_hw_iqcalibrate
+};
+const struct hal_percal_data iq_cal_single_sample = {
+	IQ_MISMATCH_CAL,
+	MIN_CAL_SAMPLES,
+	PER_MAX_LOG_COUNT,
+	ath9k_hw_iqcal_collect,
+	ath9k_hw_iqcalibrate
+};
+const struct hal_percal_data adc_gain_cal_multi_sample = {
+	ADC_GAIN_CAL,
+	MAX_CAL_SAMPLES,
+	PER_MIN_LOG_COUNT,
+	ath9k_hw_adc_gaincal_collect,
+	ath9k_hw_adc_gaincal_calibrate
+};
+const struct hal_percal_data adc_gain_cal_single_sample = {
+	ADC_GAIN_CAL,
+	MIN_CAL_SAMPLES,
+	PER_MAX_LOG_COUNT,
+	ath9k_hw_adc_gaincal_collect,
+	ath9k_hw_adc_gaincal_calibrate
+};
+const struct hal_percal_data adc_dc_cal_multi_sample = {
+	ADC_DC_CAL,
+	MAX_CAL_SAMPLES,
+	PER_MIN_LOG_COUNT,
+	ath9k_hw_adc_dccal_collect,
+	ath9k_hw_adc_dccal_calibrate
+};
+const struct hal_percal_data adc_dc_cal_single_sample = {
+	ADC_DC_CAL,
+	MIN_CAL_SAMPLES,
+	PER_MAX_LOG_COUNT,
+	ath9k_hw_adc_dccal_collect,
+	ath9k_hw_adc_dccal_calibrate
+};
+const struct hal_percal_data adc_init_dc_cal = {
+	ADC_DC_INIT_CAL,
+	MIN_CAL_SAMPLES,
+	INIT_LOG_COUNT,
+	ath9k_hw_adc_dccal_collect,
+	ath9k_hw_adc_dccal_calibrate
+};
diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c
deleted file mode 100644
index c5033f6..0000000
--- a/drivers/net/wireless/ath9k/core.c
+++ /dev/null
@@ -1,1886 +0,0 @@
-/*
- * Copyright (c) 2008, Atheros Communications Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
- /* Implementation of the main "ATH" layer. */
-
-#include "core.h"
-#include "regd.h"
-
-static int ath_outdoor;		/* enable outdoor use */
-
-static u32 ath_chainmask_sel_up_rssi_thres =
-	ATH_CHAINMASK_SEL_UP_RSSI_THRES;
-static u32 ath_chainmask_sel_down_rssi_thres =
-	ATH_CHAINMASK_SEL_DOWN_RSSI_THRES;
-static u32 ath_chainmask_sel_period =
-	ATH_CHAINMASK_SEL_TIMEOUT;
-
-/* return bus cachesize in 4B word units */
-
-static void bus_read_cachesize(struct ath_softc *sc, int *csz)
-{
-	u8 u8tmp;
-
-	pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp);
-	*csz = (int)u8tmp;
-
-	/*
-	 * This check was put in to avoid "unplesant" consequences if
-	 * the bootrom has not fully initialized all PCI devices.
-	 * Sometimes the cache line size register is not set
-	 */
-
-	if (*csz == 0)
-		*csz = DEFAULT_CACHELINE >> 2;   /* Use the default size */
-}
-
-/*
- *  Set current operating mode
- *
- *  This function initializes and fills the rate table in the ATH object based
- *  on the operating mode.
-*/
-static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
-{
-	const struct ath9k_rate_table *rt;
-	int i;
-
-	memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap));
-	rt = ath9k_hw_getratetable(sc->sc_ah, mode);
-	BUG_ON(!rt);
-
-	for (i = 0; i < rt->rateCount; i++)
-		sc->sc_rixmap[rt->info[i].rateCode] = (u8) i;
-
-	memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap));
-	for (i = 0; i < 256; i++) {
-		u8 ix = rt->rateCodeToIndex[i];
-
-		if (ix == 0xff)
-			continue;
-
-		sc->sc_hwmap[i].ieeerate =
-		    rt->info[ix].dot11Rate & IEEE80211_RATE_VAL;
-		sc->sc_hwmap[i].rateKbps = rt->info[ix].rateKbps;
-
-		if (rt->info[ix].shortPreamble ||
-		    rt->info[ix].phy == PHY_OFDM) {
-			/* XXX: Handle this */
-		}
-
-		/* NB: this uses the last entry if the rate isn't found */
-		/* XXX beware of overlow */
-	}
-	sc->sc_currates = rt;
-	sc->sc_curmode = mode;
-	/*
-	 * All protection frames are transmited at 2Mb/s for
-	 * 11g, otherwise at 1Mb/s.
-	 * XXX select protection rate index from rate table.
-	 */
-	sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0);
-}
-
-/*
- * Set up rate table (legacy rates)
- */
-static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	const struct ath9k_rate_table *rt = NULL;
-	struct ieee80211_supported_band *sband;
-	struct ieee80211_rate *rate;
-	int i, maxrates;
-
-	switch (band) {
-	case IEEE80211_BAND_2GHZ:
-		rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11G);
-		break;
-	case IEEE80211_BAND_5GHZ:
-		rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11A);
-		break;
-	default:
-		break;
-	}
-
-	if (rt == NULL)
-		return;
-
-	sband = &sc->sbands[band];
-	rate = sc->rates[band];
-
-	if (rt->rateCount > ATH_RATE_MAX)
-		maxrates = ATH_RATE_MAX;
-	else
-		maxrates = rt->rateCount;
-
-	for (i = 0; i < maxrates; i++) {
-		rate[i].bitrate = rt->info[i].rateKbps / 100;
-		rate[i].hw_value = rt->info[i].rateCode;
-		sband->n_bitrates++;
-		DPRINTF(sc, ATH_DBG_CONFIG,
-			"%s: Rate: %2dMbps, ratecode: %2d\n",
-			__func__,
-			rate[i].bitrate / 10,
-			rate[i].hw_value);
-	}
-}
-
-/*
- *  Set up channel list
- */
-static int ath_setup_channels(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	int nchan, i, a = 0, b = 0;
-	u8 regclassids[ATH_REGCLASSIDS_MAX];
-	u32 nregclass = 0;
-	struct ieee80211_supported_band *band_2ghz;
-	struct ieee80211_supported_band *band_5ghz;
-	struct ieee80211_channel *chan_2ghz;
-	struct ieee80211_channel *chan_5ghz;
-	struct ath9k_channel *c;
-
-	/* Fill in ah->ah_channels */
-	if (!ath9k_regd_init_channels(ah,
-				      ATH_CHAN_MAX,
-				      (u32 *)&nchan,
-				      regclassids,
-				      ATH_REGCLASSIDS_MAX,
-				      &nregclass,
-				      CTRY_DEFAULT,
-				      false,
-				      1)) {
-		u32 rd = ah->ah_currentRD;
-
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to collect channel list; "
-			"regdomain likely %u country code %u\n",
-			__func__, rd, CTRY_DEFAULT);
-		return -EINVAL;
-	}
-
-	band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ];
-	band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ];
-	chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ];
-	chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ];
-
-	for (i = 0; i < nchan; i++) {
-		c = &ah->ah_channels[i];
-		if (IS_CHAN_2GHZ(c)) {
-			chan_2ghz[a].band = IEEE80211_BAND_2GHZ;
-			chan_2ghz[a].center_freq = c->channel;
-			chan_2ghz[a].max_power = c->maxTxPower;
-
-			if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
-				chan_2ghz[a].flags |=
-					IEEE80211_CHAN_NO_IBSS;
-			if (c->channelFlags & CHANNEL_PASSIVE)
-				chan_2ghz[a].flags |=
-					IEEE80211_CHAN_PASSIVE_SCAN;
-
-			band_2ghz->n_channels = ++a;
-
-			DPRINTF(sc, ATH_DBG_CONFIG,
-				"%s: 2MHz channel: %d, "
-				"channelFlags: 0x%x\n",
-				__func__,
-				c->channel,
-				c->channelFlags);
-		} else if (IS_CHAN_5GHZ(c)) {
-			chan_5ghz[b].band = IEEE80211_BAND_5GHZ;
-			chan_5ghz[b].center_freq = c->channel;
-			chan_5ghz[b].max_power = c->maxTxPower;
-
-			if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
-				chan_5ghz[b].flags |=
-					IEEE80211_CHAN_NO_IBSS;
-			if (c->channelFlags & CHANNEL_PASSIVE)
-				chan_5ghz[b].flags |=
-					IEEE80211_CHAN_PASSIVE_SCAN;
-
-			band_5ghz->n_channels = ++b;
-
-			DPRINTF(sc, ATH_DBG_CONFIG,
-				"%s: 5MHz channel: %d, "
-				"channelFlags: 0x%x\n",
-				__func__,
-				c->channel,
-				c->channelFlags);
-		}
-	}
-
-	return 0;
-}
-
-/*
- *  Determine mode from channel flags
- *
- *  This routine will provide the enumerated WIRELESSS_MODE value based
- *  on the settings of the channel flags.  If no valid set of flags
- *  exist, the lowest mode (11b) is selected.
-*/
-
-static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
-{
-	if (chan->chanmode == CHANNEL_A)
-		return ATH9K_MODE_11A;
-	else if (chan->chanmode == CHANNEL_G)
-		return ATH9K_MODE_11G;
-	else if (chan->chanmode == CHANNEL_B)
-		return ATH9K_MODE_11B;
-	else if (chan->chanmode == CHANNEL_A_HT20)
-		return ATH9K_MODE_11NA_HT20;
-	else if (chan->chanmode == CHANNEL_G_HT20)
-		return ATH9K_MODE_11NG_HT20;
-	else if (chan->chanmode == CHANNEL_A_HT40PLUS)
-		return ATH9K_MODE_11NA_HT40PLUS;
-	else if (chan->chanmode == CHANNEL_A_HT40MINUS)
-		return ATH9K_MODE_11NA_HT40MINUS;
-	else if (chan->chanmode == CHANNEL_G_HT40PLUS)
-		return ATH9K_MODE_11NG_HT40PLUS;
-	else if (chan->chanmode == CHANNEL_G_HT40MINUS)
-		return ATH9K_MODE_11NG_HT40MINUS;
-
-	WARN_ON(1); /* should not get here */
-
-	return ATH9K_MODE_11B;
-}
-
-/*
- * Stop the device, grabbing the top-level lock to protect
- * against concurrent entry through ath_init (which can happen
- * if another thread does a system call and the thread doing the
- * stop is preempted).
- */
-
-static int ath_stop(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n",
-		__func__, sc->sc_flags & SC_OP_INVALID);
-
-	/*
-	 * Shutdown the hardware and driver:
-	 *    stop output from above
-	 *    turn off timers
-	 *    disable interrupts
-	 *    clear transmit machinery
-	 *    clear receive machinery
-	 *    turn off the radio
-	 *    reclaim beacon resources
-	 *
-	 * Note that some of this work is not possible if the
-	 * hardware is gone (invalid).
-	 */
-
-	ath_draintxq(sc, false);
-	if (!(sc->sc_flags & SC_OP_INVALID)) {
-		ath_stoprecv(sc);
-		ath9k_hw_phy_disable(ah);
-	} else
-		sc->sc_rxlink = NULL;
-
-	return 0;
-}
-
-/*
- * Set the current channel
- *
- * Set/change channels.  If the channel is really being changed, it's done
- * by reseting the chip.  To accomplish this we must first cleanup any pending
- * DMA, then restart stuff after a la ath_init.
-*/
-int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	bool fastcc = true, stopped;
-
-	if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */
-		return -EIO;
-
-	DPRINTF(sc, ATH_DBG_CONFIG,
-		"%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n",
-		__func__,
-		ath9k_hw_mhz2ieee(ah, sc->sc_ah->ah_curchan->channel,
-				  sc->sc_ah->ah_curchan->channelFlags),
-		sc->sc_ah->ah_curchan->channel,
-		ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags),
-		hchan->channel, hchan->channelFlags);
-
-	if (hchan->channel != sc->sc_ah->ah_curchan->channel ||
-	    hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags ||
-	    (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) ||
-	    (sc->sc_flags & SC_OP_FULL_RESET)) {
-		int status;
-		/*
-		 * This is only performed if the channel settings have
-		 * actually changed.
-		 *
-		 * To switch channels clear any pending DMA operations;
-		 * wait long enough for the RX fifo to drain, reset the
-		 * hardware at the new frequency, and then re-enable
-		 * the relevant bits of the h/w.
-		 */
-		ath9k_hw_set_interrupts(ah, 0);	/* disable interrupts */
-		ath_draintxq(sc, false);	/* clear pending tx frames */
-		stopped = ath_stoprecv(sc);	/* turn off frame recv */
-
-		/* XXX: do not flush receive queue here. We don't want
-		 * to flush data frames already in queue because of
-		 * changing channel. */
-
-		if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
-			fastcc = false;
-
-		spin_lock_bh(&sc->sc_resetlock);
-		if (!ath9k_hw_reset(ah, hchan,
-				    sc->sc_ht_info.tx_chan_width,
-				    sc->sc_tx_chainmask,
-				    sc->sc_rx_chainmask,
-				    sc->sc_ht_extprotspacing,
-				    fastcc, &status)) {
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: unable to reset channel %u (%uMhz) "
-				"flags 0x%x hal status %u\n", __func__,
-				ath9k_hw_mhz2ieee(ah, hchan->channel,
-						  hchan->channelFlags),
-				hchan->channel, hchan->channelFlags, status);
-			spin_unlock_bh(&sc->sc_resetlock);
-			return -EIO;
-		}
-		spin_unlock_bh(&sc->sc_resetlock);
-
-		sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
-		sc->sc_flags &= ~SC_OP_FULL_RESET;
-
-		/* Re-enable rx framework */
-		if (ath_startrecv(sc) != 0) {
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: unable to restart recv logic\n", __func__);
-			return -EIO;
-		}
-		/*
-		 * Change channels and update the h/w rate map
-		 * if we're switching; e.g. 11a to 11b/g.
-		 */
-		ath_setcurmode(sc, ath_chan2mode(hchan));
-
-		ath_update_txpow(sc);	/* update tx power state */
-		/*
-		 * Re-enable interrupts.
-		 */
-		ath9k_hw_set_interrupts(ah, sc->sc_imask);
-	}
-	return 0;
-}
-
-/**********************/
-/* Chainmask Handling */
-/**********************/
-
-static void ath_chainmask_sel_timertimeout(unsigned long data)
-{
-	struct ath_chainmask_sel *cm = (struct ath_chainmask_sel *)data;
-	cm->switch_allowed = 1;
-}
-
-/* Start chainmask select timer */
-static void ath_chainmask_sel_timerstart(struct ath_chainmask_sel *cm)
-{
-	cm->switch_allowed = 0;
-	mod_timer(&cm->timer, ath_chainmask_sel_period);
-}
-
-/* Stop chainmask select timer */
-static void ath_chainmask_sel_timerstop(struct ath_chainmask_sel *cm)
-{
-	cm->switch_allowed = 0;
-	del_timer_sync(&cm->timer);
-}
-
-static void ath_chainmask_sel_init(struct ath_softc *sc, struct ath_node *an)
-{
-	struct ath_chainmask_sel *cm = &an->an_chainmask_sel;
-
-	memset(cm, 0, sizeof(struct ath_chainmask_sel));
-
-	cm->cur_tx_mask = sc->sc_tx_chainmask;
-	cm->cur_rx_mask = sc->sc_rx_chainmask;
-	cm->tx_avgrssi = ATH_RSSI_DUMMY_MARKER;
-	setup_timer(&cm->timer,
-		ath_chainmask_sel_timertimeout, (unsigned long) cm);
-}
-
-int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an)
-{
-	struct ath_chainmask_sel *cm = &an->an_chainmask_sel;
-
-	/*
-	 * Disable auto-swtiching in one of the following if conditions.
-	 * sc_chainmask_auto_sel is used for internal global auto-switching
-	 * enabled/disabled setting
-	 */
-	if (sc->sc_ah->ah_caps.tx_chainmask != ATH_CHAINMASK_SEL_3X3) {
-		cm->cur_tx_mask = sc->sc_tx_chainmask;
-		return cm->cur_tx_mask;
-	}
-
-	if (cm->tx_avgrssi == ATH_RSSI_DUMMY_MARKER)
-		return cm->cur_tx_mask;
-
-	if (cm->switch_allowed) {
-		/* Switch down from tx 3 to tx 2. */
-		if (cm->cur_tx_mask == ATH_CHAINMASK_SEL_3X3 &&
-		    ATH_RSSI_OUT(cm->tx_avgrssi) >=
-		    ath_chainmask_sel_down_rssi_thres) {
-			cm->cur_tx_mask = sc->sc_tx_chainmask;
-
-			/* Don't let another switch happen until
-			 * this timer expires */
-			ath_chainmask_sel_timerstart(cm);
-		}
-		/* Switch up from tx 2 to 3. */
-		else if (cm->cur_tx_mask == sc->sc_tx_chainmask &&
-			 ATH_RSSI_OUT(cm->tx_avgrssi) <=
-			 ath_chainmask_sel_up_rssi_thres) {
-			cm->cur_tx_mask = ATH_CHAINMASK_SEL_3X3;
-
-			/* Don't let another switch happen
-			 * until this timer expires */
-			ath_chainmask_sel_timerstart(cm);
-		}
-	}
-
-	return cm->cur_tx_mask;
-}
-
-/*
- * Update tx/rx chainmask. For legacy association,
- * hard code chainmask to 1x1, for 11n association, use
- * the chainmask configuration.
- */
-
-void ath_update_chainmask(struct ath_softc *sc, int is_ht)
-{
-	sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
-	if (is_ht) {
-		sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask;
-		sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask;
-	} else {
-		sc->sc_tx_chainmask = 1;
-		sc->sc_rx_chainmask = 1;
-	}
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: tx chmask: %d, rx chmask: %d\n",
-		__func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask);
-}
-
-/*******/
-/* ANI */
-/*******/
-
-/*
- *  This routine performs the periodic noise floor calibration function
- *  that is used to adjust and optimize the chip performance.  This
- *  takes environmental changes (location, temperature) into account.
- *  When the task is complete, it reschedules itself depending on the
- *  appropriate interval that was calculated.
- */
-
-static void ath_ani_calibrate(unsigned long data)
-{
-	struct ath_softc *sc;
-	struct ath_hal *ah;
-	bool longcal = false;
-	bool shortcal = false;
-	bool aniflag = false;
-	unsigned int timestamp = jiffies_to_msecs(jiffies);
-	u32 cal_interval;
-
-	sc = (struct ath_softc *)data;
-	ah = sc->sc_ah;
-
-	/*
-	* don't calibrate when we're scanning.
-	* we are most likely not on our home channel.
-	*/
-	if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)
-		return;
-
-	/* Long calibration runs independently of short calibration. */
-	if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) {
-		longcal = true;
-		DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n",
-			__func__, jiffies);
-		sc->sc_ani.sc_longcal_timer = timestamp;
-	}
-
-	/* Short calibration applies only while sc_caldone is false */
-	if (!sc->sc_ani.sc_caldone) {
-		if ((timestamp - sc->sc_ani.sc_shortcal_timer) >=
-		    ATH_SHORT_CALINTERVAL) {
-			shortcal = true;
-			DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n",
-			       __func__, jiffies);
-			sc->sc_ani.sc_shortcal_timer = timestamp;
-			sc->sc_ani.sc_resetcal_timer = timestamp;
-		}
-	} else {
-		if ((timestamp - sc->sc_ani.sc_resetcal_timer) >=
-		    ATH_RESTART_CALINTERVAL) {
-			ath9k_hw_reset_calvalid(ah, ah->ah_curchan,
-						&sc->sc_ani.sc_caldone);
-			if (sc->sc_ani.sc_caldone)
-				sc->sc_ani.sc_resetcal_timer = timestamp;
-		}
-	}
-
-	/* Verify whether we must check ANI */
-	if ((timestamp - sc->sc_ani.sc_checkani_timer) >=
-	   ATH_ANI_POLLINTERVAL) {
-		aniflag = true;
-		sc->sc_ani.sc_checkani_timer = timestamp;
-	}
-
-	/* Skip all processing if there's nothing to do. */
-	if (longcal || shortcal || aniflag) {
-		/* Call ANI routine if necessary */
-		if (aniflag)
-			ath9k_hw_ani_monitor(ah, &sc->sc_halstats,
-					     ah->ah_curchan);
-
-		/* Perform calibration if necessary */
-		if (longcal || shortcal) {
-			bool iscaldone = false;
-
-			if (ath9k_hw_calibrate(ah, ah->ah_curchan,
-					       sc->sc_rx_chainmask, longcal,
-					       &iscaldone)) {
-				if (longcal)
-					sc->sc_ani.sc_noise_floor =
-						ath9k_hw_getchan_noise(ah,
-							       ah->ah_curchan);
-
-				DPRINTF(sc, ATH_DBG_ANI,
-					"%s: calibrate chan %u/%x nf: %d\n",
-					 __func__,
-					ah->ah_curchan->channel,
-					ah->ah_curchan->channelFlags,
-					sc->sc_ani.sc_noise_floor);
-			} else {
-				DPRINTF(sc, ATH_DBG_ANY,
-					"%s: calibrate chan %u/%x failed\n",
-					 __func__,
-					ah->ah_curchan->channel,
-					ah->ah_curchan->channelFlags);
-			}
-			sc->sc_ani.sc_caldone = iscaldone;
-		}
-	}
-
-	/*
-	* Set timer interval based on previous results.
-	* The interval must be the shortest necessary to satisfy ANI,
-	* short calibration and long calibration.
-	*/
-
-	cal_interval = ATH_ANI_POLLINTERVAL;
-	if (!sc->sc_ani.sc_caldone)
-		cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL);
-
-	mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval));
-}
-
-/******************/
-/* VAP management */
-/******************/
-
-int ath_vap_attach(struct ath_softc *sc,
-		   int if_id,
-		   struct ieee80211_vif *if_data,
-		   enum ath9k_opmode opmode)
-{
-	struct ath_vap *avp;
-
-	if (if_id >= ATH_BCBUF || sc->sc_vaps[if_id] != NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Invalid interface id = %u\n", __func__, if_id);
-		return -EINVAL;
-	}
-
-	switch (opmode) {
-	case ATH9K_M_STA:
-	case ATH9K_M_IBSS:
-	case ATH9K_M_MONITOR:
-		break;
-	case ATH9K_M_HOSTAP:
-		/* XXX not right, beacon buffer is allocated on RUN trans */
-		if (list_empty(&sc->sc_bbuf))
-			return -ENOMEM;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* create ath_vap */
-	avp = kmalloc(sizeof(struct ath_vap), GFP_KERNEL);
-	if (avp == NULL)
-		return -ENOMEM;
-
-	memset(avp, 0, sizeof(struct ath_vap));
-	avp->av_if_data = if_data;
-	/* Set the VAP opmode */
-	avp->av_opmode = opmode;
-	avp->av_bslot = -1;
-
-	if (opmode == ATH9K_M_HOSTAP)
-		ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
-
-	sc->sc_vaps[if_id] = avp;
-	sc->sc_nvaps++;
-	/* Set the device opmode */
-	sc->sc_ah->ah_opmode = opmode;
-
-	/* default VAP configuration */
-	avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE;
-	avp->av_config.av_fixed_retryset = 0x03030303;
-
-	return 0;
-}
-
-int ath_vap_detach(struct ath_softc *sc, int if_id)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	struct ath_vap *avp;
-
-	avp = sc->sc_vaps[if_id];
-	if (avp == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n",
-			__func__, if_id);
-		return -EINVAL;
-	}
-
-	/*
-	 * Quiesce the hardware while we remove the vap.  In
-	 * particular we need to reclaim all references to the
-	 * vap state by any frames pending on the tx queues.
-	 *
-	 * XXX can we do this w/o affecting other vap's?
-	 */
-	ath9k_hw_set_interrupts(ah, 0);	/* disable interrupts */
-	ath_draintxq(sc, false);	/* stop xmit side */
-	ath_stoprecv(sc);	/* stop recv side */
-	ath_flushrecv(sc);	/* flush recv queue */
-
-	kfree(avp);
-	sc->sc_vaps[if_id] = NULL;
-	sc->sc_nvaps--;
-
-	return 0;
-}
-
-int ath_vap_config(struct ath_softc *sc,
-	int if_id, struct ath_vap_config *if_config)
-{
-	struct ath_vap *avp;
-
-	if (if_id >= ATH_BCBUF) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Invalid interface id = %u\n", __func__, if_id);
-		return -EINVAL;
-	}
-
-	avp = sc->sc_vaps[if_id];
-	ASSERT(avp != NULL);
-
-	if (avp)
-		memcpy(&avp->av_config, if_config, sizeof(avp->av_config));
-
-	return 0;
-}
-
-/********/
-/* Core */
-/********/
-
-int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	int status;
-	int error = 0;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n",
-		__func__, sc->sc_ah->ah_opmode);
-
-	/*
-	 * Stop anything previously setup.  This is safe
-	 * whether this is the first time through or not.
-	 */
-	ath_stop(sc);
-
-	/* Initialize chanmask selection */
-	sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
-	sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
-
-	/* Reset SERDES registers */
-	ath9k_hw_configpcipowersave(ah, 0);
-
-	/*
-	 * The basic interface to setting the hardware in a good
-	 * state is ``reset''.  On return the hardware is known to
-	 * be powered up and with interrupts disabled.  This must
-	 * be followed by initialization of the appropriate bits
-	 * and then setup of the interrupt mask.
-	 */
-
-	spin_lock_bh(&sc->sc_resetlock);
-	if (!ath9k_hw_reset(ah, initial_chan,
-			    sc->sc_ht_info.tx_chan_width,
-			    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
-			    sc->sc_ht_extprotspacing, false, &status)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to reset hardware; hal status %u "
-			"(freq %u flags 0x%x)\n", __func__, status,
-			initial_chan->channel, initial_chan->channelFlags);
-		error = -EIO;
-		spin_unlock_bh(&sc->sc_resetlock);
-		goto done;
-	}
-	spin_unlock_bh(&sc->sc_resetlock);
-	/*
-	 * This is needed only to setup initial state
-	 * but it's best done after a reset.
-	 */
-	ath_update_txpow(sc);
-
-	/*
-	 * Setup the hardware after reset:
-	 * The receive engine is set going.
-	 * Frame transmit is handled entirely
-	 * in the frame output path; there's nothing to do
-	 * here except setup the interrupt mask.
-	 */
-	if (ath_startrecv(sc) != 0) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to start recv logic\n", __func__);
-		error = -EIO;
-		goto done;
-	}
-	/* Setup our intr mask. */
-	sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
-		| ATH9K_INT_RXEOL | ATH9K_INT_RXORN
-		| ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
-
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT)
-		sc->sc_imask |= ATH9K_INT_GTT;
-
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
-		sc->sc_imask |= ATH9K_INT_CST;
-
-	/*
-	 * Enable MIB interrupts when there are hardware phy counters.
-	 * Note we only do this (at the moment) for station mode.
-	 */
-	if (ath9k_hw_phycounters(ah) &&
-	    ((sc->sc_ah->ah_opmode == ATH9K_M_STA) ||
-	     (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)))
-		sc->sc_imask |= ATH9K_INT_MIB;
-	/*
-	 * Some hardware processes the TIM IE and fires an
-	 * interrupt when the TIM bit is set.  For hardware
-	 * that does, if not overridden by configuration,
-	 * enable the TIM interrupt when operating as station.
-	 */
-	if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
-	    (sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
-	    !sc->sc_config.swBeaconProcess)
-		sc->sc_imask |= ATH9K_INT_TIM;
-	/*
-	 *  Don't enable interrupts here as we've not yet built our
-	 *  vap and node data structures, which will be needed as soon
-	 *  as we start receiving.
-	 */
-	ath_setcurmode(sc, ath_chan2mode(initial_chan));
-
-	/* XXX: we must make sure h/w is ready and clear invalid flag
-	 * before turning on interrupt. */
-	sc->sc_flags &= ~SC_OP_INVALID;
-done:
-	return error;
-}
-
-int ath_reset(struct ath_softc *sc, bool retry_tx)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	int status;
-	int error = 0;
-
-	ath9k_hw_set_interrupts(ah, 0);	/* disable interrupts */
-	ath_draintxq(sc, retry_tx);	/* stop xmit */
-	ath_stoprecv(sc);		/* stop recv */
-	ath_flushrecv(sc);		/* flush recv queue */
-
-	/* Reset chip */
-	spin_lock_bh(&sc->sc_resetlock);
-	if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan,
-			    sc->sc_ht_info.tx_chan_width,
-			    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
-			    sc->sc_ht_extprotspacing, false, &status)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to reset hardware; hal status %u\n",
-			__func__, status);
-		error = -EIO;
-	}
-	spin_unlock_bh(&sc->sc_resetlock);
-
-	if (ath_startrecv(sc) != 0)	/* restart recv */
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to start recv logic\n", __func__);
-
-	/*
-	 * We may be doing a reset in response to a request
-	 * that changes the channel so update any state that
-	 * might change as a result.
-	 */
-	ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan));
-
-	ath_update_txpow(sc);
-
-	if (sc->sc_flags & SC_OP_BEACONS)
-		ath_beacon_config(sc, ATH_IF_ID_ANY);	/* restart beacons */
-
-	ath9k_hw_set_interrupts(ah, sc->sc_imask);
-
-	/* Restart the txq */
-	if (retry_tx) {
-		int i;
-		for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-			if (ATH_TXQ_SETUP(sc, i)) {
-				spin_lock_bh(&sc->sc_txq[i].axq_lock);
-				ath_txq_schedule(sc, &sc->sc_txq[i]);
-				spin_unlock_bh(&sc->sc_txq[i].axq_lock);
-			}
-		}
-	}
-
-	return error;
-}
-
-int ath_suspend(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-
-	/* No I/O if device has been surprise removed */
-	if (sc->sc_flags & SC_OP_INVALID)
-		return -EIO;
-
-	/* Shut off the interrupt before setting sc->sc_invalid to '1' */
-	ath9k_hw_set_interrupts(ah, 0);
-
-	/* XXX: we must make sure h/w will not generate any interrupt
-	 * before setting the invalid flag. */
-	sc->sc_flags |= SC_OP_INVALID;
-
-	/* disable HAL and put h/w to sleep */
-	ath9k_hw_disable(sc->sc_ah);
-
-	ath9k_hw_configpcipowersave(sc->sc_ah, 1);
-
-	return 0;
-}
-
-/* Interrupt handler.  Most of the actual processing is deferred.
- * It's the caller's responsibility to ensure the chip is awake. */
-
-irqreturn_t ath_isr(int irq, void *dev)
-{
-	struct ath_softc *sc = dev;
-	struct ath_hal *ah = sc->sc_ah;
-	enum ath9k_int status;
-	bool sched = false;
-
-	do {
-		if (sc->sc_flags & SC_OP_INVALID) {
-			/*
-			 * The hardware is not ready/present, don't
-			 * touch anything. Note this can happen early
-			 * on if the IRQ is shared.
-			 */
-			return IRQ_NONE;
-		}
-		if (!ath9k_hw_intrpend(ah)) {	/* shared irq, not for us */
-			return IRQ_NONE;
-		}
-
-		/*
-		 * Figure out the reason(s) for the interrupt.  Note
-		 * that the hal returns a pseudo-ISR that may include
-		 * bits we haven't explicitly enabled so we mask the
-		 * value to insure we only process bits we requested.
-		 */
-		ath9k_hw_getisr(ah, &status);	/* NB: clears ISR too */
-
-		status &= sc->sc_imask;	/* discard unasked-for bits */
-
-		/*
-		 * If there are no status bits set, then this interrupt was not
-		 * for me (should have been caught above).
-		 */
-
-		if (!status)
-			return IRQ_NONE;
-
-		sc->sc_intrstatus = status;
-
-		if (status & ATH9K_INT_FATAL) {
-			/* need a chip reset */
-			sched = true;
-		} else if (status & ATH9K_INT_RXORN) {
-			/* need a chip reset */
-			sched = true;
-		} else {
-			if (status & ATH9K_INT_SWBA) {
-				/* schedule a tasklet for beacon handling */
-				tasklet_schedule(&sc->bcon_tasklet);
-			}
-			if (status & ATH9K_INT_RXEOL) {
-				/*
-				 * NB: the hardware should re-read the link when
-				 *     RXE bit is written, but it doesn't work
-				 *     at least on older hardware revs.
-				 */
-				sched = true;
-			}
-
-			if (status & ATH9K_INT_TXURN)
-				/* bump tx trigger level */
-				ath9k_hw_updatetxtriglevel(ah, true);
-			/* XXX: optimize this */
-			if (status & ATH9K_INT_RX)
-				sched = true;
-			if (status & ATH9K_INT_TX)
-				sched = true;
-			if (status & ATH9K_INT_BMISS)
-				sched = true;
-			/* carrier sense timeout */
-			if (status & ATH9K_INT_CST)
-				sched = true;
-			if (status & ATH9K_INT_MIB) {
-				/*
-				 * Disable interrupts until we service the MIB
-				 * interrupt; otherwise it will continue to
-				 * fire.
-				 */
-				ath9k_hw_set_interrupts(ah, 0);
-				/*
-				 * Let the hal handle the event. We assume
-				 * it will clear whatever condition caused
-				 * the interrupt.
-				 */
-				ath9k_hw_procmibevent(ah, &sc->sc_halstats);
-				ath9k_hw_set_interrupts(ah, sc->sc_imask);
-			}
-			if (status & ATH9K_INT_TIM_TIMER) {
-				if (!(ah->ah_caps.hw_caps &
-				      ATH9K_HW_CAP_AUTOSLEEP)) {
-					/* Clear RxAbort bit so that we can
-					 * receive frames */
-					ath9k_hw_setrxabort(ah, 0);
-					sched = true;
-				}
-			}
-		}
-	} while (0);
-
-	if (sched) {
-		/* turn off every interrupt except SWBA */
-		ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA));
-		tasklet_schedule(&sc->intr_tq);
-	}
-
-	return IRQ_HANDLED;
-}
-
-/* Deferred interrupt processing  */
-
-static void ath9k_tasklet(unsigned long data)
-{
-	struct ath_softc *sc = (struct ath_softc *)data;
-	u32 status = sc->sc_intrstatus;
-
-	if (status & ATH9K_INT_FATAL) {
-		/* need a chip reset */
-		ath_reset(sc, false);
-		return;
-	} else {
-
-		if (status &
-		    (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
-			/* XXX: fill me in */
-			/*
-			if (status & ATH9K_INT_RXORN) {
-			}
-			if (status & ATH9K_INT_RXEOL) {
-			}
-			*/
-			spin_lock_bh(&sc->sc_rxflushlock);
-			ath_rx_tasklet(sc, 0);
-			spin_unlock_bh(&sc->sc_rxflushlock);
-		}
-		/* XXX: optimize this */
-		if (status & ATH9K_INT_TX)
-			ath_tx_tasklet(sc);
-		/* XXX: fill me in */
-		/*
-		if (status & ATH9K_INT_BMISS) {
-		}
-		if (status & (ATH9K_INT_TIM | ATH9K_INT_DTIMSYNC)) {
-			if (status & ATH9K_INT_TIM) {
-			}
-			if (status & ATH9K_INT_DTIMSYNC) {
-			}
-		}
-		*/
-	}
-
-	/* re-enable hardware interrupt */
-	ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
-}
-
-int ath_init(u16 devid, struct ath_softc *sc)
-{
-	struct ath_hal *ah = NULL;
-	int status;
-	int error = 0, i;
-	int csz = 0;
-
-	/* XXX: hardware will not be ready until ath_open() being called */
-	sc->sc_flags |= SC_OP_INVALID;
-
-	sc->sc_debug = DBG_DEFAULT;
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid);
-
-	/* Initialize tasklet */
-	tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
-	tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
-		     (unsigned long)sc);
-
-	/*
-	 * Cache line size is used to size and align various
-	 * structures used to communicate with the hardware.
-	 */
-	bus_read_cachesize(sc, &csz);
-	/* XXX assert csz is non-zero */
-	sc->sc_cachelsz = csz << 2;	/* convert to bytes */
-
-	spin_lock_init(&sc->sc_resetlock);
-
-	ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
-	if (ah == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to attach hardware; HAL status %u\n",
-			__func__, status);
-		error = -ENXIO;
-		goto bad;
-	}
-	sc->sc_ah = ah;
-
-	/* Initializes the noise floor to a reasonable default value.
-	 * Later on this will be updated during ANI processing. */
-	sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
-
-	/* Get the hardware key cache size. */
-	sc->sc_keymax = ah->ah_caps.keycache_size;
-	if (sc->sc_keymax > ATH_KEYMAX) {
-		DPRINTF(sc, ATH_DBG_KEYCACHE,
-			"%s: Warning, using only %u entries in %u key cache\n",
-			__func__, ATH_KEYMAX, sc->sc_keymax);
-		sc->sc_keymax = ATH_KEYMAX;
-	}
-
-	/*
-	 * Reset the key cache since some parts do not
-	 * reset the contents on initial power up.
-	 */
-	for (i = 0; i < sc->sc_keymax; i++)
-		ath9k_hw_keyreset(ah, (u16) i);
-	/*
-	 * Mark key cache slots associated with global keys
-	 * as in use.  If we knew TKIP was not to be used we
-	 * could leave the +32, +64, and +32+64 slots free.
-	 * XXX only for splitmic.
-	 */
-	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
-		set_bit(i, sc->sc_keymap);
-		set_bit(i + 32, sc->sc_keymap);
-		set_bit(i + 64, sc->sc_keymap);
-		set_bit(i + 32 + 64, sc->sc_keymap);
-	}
-	/*
-	 * Collect the channel list using the default country
-	 * code and including outdoor channels.  The 802.11 layer
-	 * is resposible for filtering this list based on settings
-	 * like the phy mode.
-	 */
-	error = ath_setup_channels(sc);
-	if (error)
-		goto bad;
-
-	/* default to STA mode */
-	sc->sc_ah->ah_opmode = ATH9K_M_MONITOR;
-
-	/* Setup rate tables */
-
-	ath_setup_rates(sc, IEEE80211_BAND_2GHZ);
-	ath_setup_rates(sc, IEEE80211_BAND_5GHZ);
-
-	/* NB: setup here so ath_rate_update is happy */
-	ath_setcurmode(sc, ATH9K_MODE_11A);
-
-	/*
-	 * Allocate hardware transmit queues: one queue for
-	 * beacon frames and one data queue for each QoS
-	 * priority.  Note that the hal handles reseting
-	 * these queues at the needed time.
-	 */
-	sc->sc_bhalq = ath_beaconq_setup(ah);
-	if (sc->sc_bhalq == -1) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup a beacon xmit queue\n", __func__);
-		error = -EIO;
-		goto bad2;
-	}
-	sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
-	if (sc->sc_cabq == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup CAB xmit queue\n", __func__);
-		error = -EIO;
-		goto bad2;
-	}
-
-	sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME;
-	ath_cabq_update(sc);
-
-	for (i = 0; i < ARRAY_SIZE(sc->sc_haltype2q); i++)
-		sc->sc_haltype2q[i] = -1;
-
-	/* Setup data queues */
-	/* NB: ensure BK queue is the lowest priority h/w queue */
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup xmit queue for BK traffic\n",
-			__func__);
-		error = -EIO;
-		goto bad2;
-	}
-
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup xmit queue for BE traffic\n",
-			__func__);
-		error = -EIO;
-		goto bad2;
-	}
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup xmit queue for VI traffic\n",
-			__func__);
-		error = -EIO;
-		goto bad2;
-	}
-	if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to setup xmit queue for VO traffic\n",
-			__func__);
-		error = -EIO;
-		goto bad2;
-	}
-
-	setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc);
-
-	sc->sc_rc = ath_rate_attach(ah);
-	if (sc->sc_rc == NULL) {
-		error = -EIO;
-		goto bad2;
-	}
-
-	if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
-				   ATH9K_CIPHER_TKIP, NULL)) {
-		/*
-		 * Whether we should enable h/w TKIP MIC.
-		 * XXX: if we don't support WME TKIP MIC, then we wouldn't
-		 * report WMM capable, so it's always safe to turn on
-		 * TKIP MIC in this case.
-		 */
-		ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC,
-				       0, 1, NULL);
-	}
-
-	/*
-	 * Check whether the separate key cache entries
-	 * are required to handle both tx+rx MIC keys.
-	 * With split mic keys the number of stations is limited
-	 * to 27 otherwise 59.
-	 */
-	if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
-				   ATH9K_CIPHER_TKIP, NULL)
-	    && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
-				      ATH9K_CIPHER_MIC, NULL)
-	    && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
-				      0, NULL))
-		sc->sc_splitmic = 1;
-
-	/* turn on mcast key search if possible */
-	if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
-		(void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1,
-					     1, NULL);
-
-	sc->sc_config.txpowlimit = ATH_TXPOWER_MAX;
-	sc->sc_config.txpowlimit_override = 0;
-
-	/* 11n Capabilities */
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
-		sc->sc_flags |= SC_OP_TXAGGR;
-		sc->sc_flags |= SC_OP_RXAGGR;
-	}
-
-	sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
-	sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
-
-	ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
-	sc->sc_defant = ath9k_hw_getdefantenna(ah);
-
-	ath9k_hw_getmac(ah, sc->sc_myaddr);
-	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) {
-		ath9k_hw_getbssidmask(ah, sc->sc_bssidmask);
-		ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask);
-		ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
-	}
-	sc->sc_slottime = ATH9K_SLOT_TIME_9;	/* default to short slot time */
-
-	/* initialize beacon slots */
-	for (i = 0; i < ARRAY_SIZE(sc->sc_bslot); i++)
-		sc->sc_bslot[i] = ATH_IF_ID_ANY;
-
-	/* save MISC configurations */
-	sc->sc_config.swBeaconProcess = 1;
-
-#ifdef CONFIG_SLOW_ANT_DIV
-	/* range is 40 - 255, we use something in the middle */
-	ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127);
-#endif
-
-	return 0;
-bad2:
-	/* cleanup tx queues */
-	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-		if (ATH_TXQ_SETUP(sc, i))
-			ath_tx_cleanupq(sc, &sc->sc_txq[i]);
-bad:
-	if (ah)
-		ath9k_hw_detach(ah);
-	return error;
-}
-
-void ath_deinit(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	int i;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__);
-
-	tasklet_kill(&sc->intr_tq);
-	tasklet_kill(&sc->bcon_tasklet);
-	ath_stop(sc);
-	if (!(sc->sc_flags & SC_OP_INVALID))
-		ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
-	ath_rate_detach(sc->sc_rc);
-	/* cleanup tx queues */
-	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-		if (ATH_TXQ_SETUP(sc, i))
-			ath_tx_cleanupq(sc, &sc->sc_txq[i]);
-	ath9k_hw_detach(ah);
-}
-
-/*******************/
-/* Node Management */
-/*******************/
-
-struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id)
-{
-	struct ath_vap *avp;
-	struct ath_node *an;
-	DECLARE_MAC_BUF(mac);
-
-	avp = sc->sc_vaps[if_id];
-	ASSERT(avp != NULL);
-
-	/* mac80211 sta_notify callback is from an IRQ context, so no sleep */
-	an = kmalloc(sizeof(struct ath_node), GFP_ATOMIC);
-	if (an == NULL)
-		return NULL;
-	memset(an, 0, sizeof(*an));
-
-	an->an_sc = sc;
-	memcpy(an->an_addr, addr, ETH_ALEN);
-	atomic_set(&an->an_refcnt, 1);
-
-	/* set up per-node tx/rx state */
-	ath_tx_node_init(sc, an);
-	ath_rx_node_init(sc, an);
-
-	ath_chainmask_sel_init(sc, an);
-	ath_chainmask_sel_timerstart(&an->an_chainmask_sel);
-	list_add(&an->list, &sc->node_list);
-
-	return an;
-}
-
-void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag)
-{
-	unsigned long flags;
-
-	DECLARE_MAC_BUF(mac);
-
-	ath_chainmask_sel_timerstop(&an->an_chainmask_sel);
-	an->an_flags |= ATH_NODE_CLEAN;
-	ath_tx_node_cleanup(sc, an, bh_flag);
-	ath_rx_node_cleanup(sc, an);
-
-	ath_tx_node_free(sc, an);
-	ath_rx_node_free(sc, an);
-
-	spin_lock_irqsave(&sc->node_lock, flags);
-
-	list_del(&an->list);
-
-	spin_unlock_irqrestore(&sc->node_lock, flags);
-
-	kfree(an);
-}
-
-/* Finds a node and increases the refcnt if found */
-
-struct ath_node *ath_node_get(struct ath_softc *sc, u8 *addr)
-{
-	struct ath_node *an = NULL, *an_found = NULL;
-
-	if (list_empty(&sc->node_list)) /* FIXME */
-		goto out;
-	list_for_each_entry(an, &sc->node_list, list) {
-		if (!compare_ether_addr(an->an_addr, addr)) {
-			atomic_inc(&an->an_refcnt);
-			an_found = an;
-			break;
-		}
-	}
-out:
-	return an_found;
-}
-
-/* Decrements the refcnt and if it drops to zero, detach the node */
-
-void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag)
-{
-	if (atomic_dec_and_test(&an->an_refcnt))
-		ath_node_detach(sc, an, bh_flag);
-}
-
-/* Finds a node, doesn't increment refcnt. Caller must hold sc->node_lock */
-struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr)
-{
-	struct ath_node *an = NULL, *an_found = NULL;
-
-	if (list_empty(&sc->node_list))
-		return NULL;
-
-	list_for_each_entry(an, &sc->node_list, list)
-		if (!compare_ether_addr(an->an_addr, addr)) {
-			an_found = an;
-			break;
-		}
-
-	return an_found;
-}
-
-/*
- * Set up New Node
- *
- * Setup driver-specific state for a newly associated node.  This routine
- * really only applies if compression or XR are enabled, there is no code
- * covering any other cases.
-*/
-
-void ath_newassoc(struct ath_softc *sc,
-	struct ath_node *an, int isnew, int isuapsd)
-{
-	int tidno;
-
-	/* if station reassociates, tear down the aggregation state. */
-	if (!isnew) {
-		for (tidno = 0; tidno < WME_NUM_TID; tidno++) {
-			if (sc->sc_flags & SC_OP_TXAGGR)
-				ath_tx_aggr_teardown(sc, an, tidno);
-			if (sc->sc_flags & SC_OP_RXAGGR)
-				ath_rx_aggr_teardown(sc, an, tidno);
-		}
-	}
-	an->an_flags = 0;
-}
-
-/**************/
-/* Encryption */
-/**************/
-
-void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot)
-{
-	ath9k_hw_keyreset(sc->sc_ah, keyix);
-	if (freeslot)
-		clear_bit(keyix, sc->sc_keymap);
-}
-
-int ath_keyset(struct ath_softc *sc,
-	       u16 keyix,
-	       struct ath9k_keyval *hk,
-	       const u8 mac[ETH_ALEN])
-{
-	bool status;
-
-	status = ath9k_hw_set_keycache_entry(sc->sc_ah,
-		keyix, hk, mac, false);
-
-	return status != false;
-}
-
-/***********************/
-/* TX Power/Regulatory */
-/***********************/
-
-/*
- *  Set Transmit power in HAL
- *
- *  This routine makes the actual HAL calls to set the new transmit power
- *  limit.
-*/
-
-void ath_update_txpow(struct ath_softc *sc)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	u32 txpow;
-
-	if (sc->sc_curtxpow != sc->sc_config.txpowlimit) {
-		ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit);
-		/* read back in case value is clamped */
-		ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
-		sc->sc_curtxpow = txpow;
-	}
-}
-
-/* Return the current country and domain information */
-void ath_get_currentCountry(struct ath_softc *sc,
-	struct ath9k_country_entry *ctry)
-{
-	ath9k_regd_get_current_country(sc->sc_ah, ctry);
-
-	/* If HAL not specific yet, since it is band dependent,
-	 * use the one we passed in. */
-	if (ctry->countryCode == CTRY_DEFAULT) {
-		ctry->iso[0] = 0;
-		ctry->iso[1] = 0;
-	} else if (ctry->iso[0] && ctry->iso[1]) {
-		if (!ctry->iso[2]) {
-			if (ath_outdoor)
-				ctry->iso[2] = 'O';
-			else
-				ctry->iso[2] = 'I';
-		}
-	}
-}
-
-/**************************/
-/* Slow Antenna Diversity */
-/**************************/
-
-void ath_slow_ant_div_init(struct ath_antdiv *antdiv,
-			   struct ath_softc *sc,
-			   int32_t rssitrig)
-{
-	int trig;
-
-	/* antdivf_rssitrig can range from 40 - 0xff */
-	trig = (rssitrig > 0xff) ? 0xff : rssitrig;
-	trig = (rssitrig < 40) ? 40 : rssitrig;
-
-	antdiv->antdiv_sc = sc;
-	antdiv->antdivf_rssitrig = trig;
-}
-
-void ath_slow_ant_div_start(struct ath_antdiv *antdiv,
-			    u8 num_antcfg,
-			    const u8 *bssid)
-{
-	antdiv->antdiv_num_antcfg =
-		num_antcfg < ATH_ANT_DIV_MAX_CFG ?
-		num_antcfg : ATH_ANT_DIV_MAX_CFG;
-	antdiv->antdiv_state = ATH_ANT_DIV_IDLE;
-	antdiv->antdiv_curcfg = 0;
-	antdiv->antdiv_bestcfg = 0;
-	antdiv->antdiv_laststatetsf = 0;
-
-	memcpy(antdiv->antdiv_bssid, bssid, sizeof(antdiv->antdiv_bssid));
-
-	antdiv->antdiv_start = 1;
-}
-
-void ath_slow_ant_div_stop(struct ath_antdiv *antdiv)
-{
-	antdiv->antdiv_start = 0;
-}
-
-static int32_t ath_find_max_val(int32_t *val,
-	u8 num_val, u8 *max_index)
-{
-	u32 MaxVal = *val++;
-	u32 cur_index = 0;
-
-	*max_index = 0;
-	while (++cur_index < num_val) {
-		if (*val > MaxVal) {
-			MaxVal = *val;
-			*max_index = cur_index;
-		}
-
-		val++;
-	}
-
-	return MaxVal;
-}
-
-void ath_slow_ant_div(struct ath_antdiv *antdiv,
-		      struct ieee80211_hdr *hdr,
-		      struct ath_rx_status *rx_stats)
-{
-	struct ath_softc *sc = antdiv->antdiv_sc;
-	struct ath_hal *ah = sc->sc_ah;
-	u64 curtsf = 0;
-	u8 bestcfg, curcfg = antdiv->antdiv_curcfg;
-	__le16 fc = hdr->frame_control;
-
-	if (antdiv->antdiv_start && ieee80211_is_beacon(fc)
-	    && !compare_ether_addr(hdr->addr3, antdiv->antdiv_bssid)) {
-		antdiv->antdiv_lastbrssi[curcfg] = rx_stats->rs_rssi;
-		antdiv->antdiv_lastbtsf[curcfg] = ath9k_hw_gettsf64(sc->sc_ah);
-		curtsf = antdiv->antdiv_lastbtsf[curcfg];
-	} else {
-		return;
-	}
-
-	switch (antdiv->antdiv_state) {
-	case ATH_ANT_DIV_IDLE:
-		if ((antdiv->antdiv_lastbrssi[curcfg] <
-		     antdiv->antdivf_rssitrig)
-		    && ((curtsf - antdiv->antdiv_laststatetsf) >
-			ATH_ANT_DIV_MIN_IDLE_US)) {
-
-			curcfg++;
-			if (curcfg == antdiv->antdiv_num_antcfg)
-				curcfg = 0;
-
-			if (!ath9k_hw_select_antconfig(ah, curcfg)) {
-				antdiv->antdiv_bestcfg = antdiv->antdiv_curcfg;
-				antdiv->antdiv_curcfg = curcfg;
-				antdiv->antdiv_laststatetsf = curtsf;
-				antdiv->antdiv_state = ATH_ANT_DIV_SCAN;
-			}
-		}
-		break;
-
-	case ATH_ANT_DIV_SCAN:
-		if ((curtsf - antdiv->antdiv_laststatetsf) <
-		    ATH_ANT_DIV_MIN_SCAN_US)
-			break;
-
-		curcfg++;
-		if (curcfg == antdiv->antdiv_num_antcfg)
-			curcfg = 0;
-
-		if (curcfg == antdiv->antdiv_bestcfg) {
-			ath_find_max_val(antdiv->antdiv_lastbrssi,
-				   antdiv->antdiv_num_antcfg, &bestcfg);
-			if (!ath9k_hw_select_antconfig(ah, bestcfg)) {
-				antdiv->antdiv_bestcfg = bestcfg;
-				antdiv->antdiv_curcfg = bestcfg;
-				antdiv->antdiv_laststatetsf = curtsf;
-				antdiv->antdiv_state = ATH_ANT_DIV_IDLE;
-			}
-		} else {
-			if (!ath9k_hw_select_antconfig(ah, curcfg)) {
-				antdiv->antdiv_curcfg = curcfg;
-				antdiv->antdiv_laststatetsf = curtsf;
-				antdiv->antdiv_state = ATH_ANT_DIV_SCAN;
-			}
-		}
-
-		break;
-	}
-}
-
-/***********************/
-/* Descriptor Handling */
-/***********************/
-
-/*
- *  Set up DMA descriptors
- *
- *  This function will allocate both the DMA descriptor structure, and the
- *  buffers it contains.  These are used to contain the descriptors used
- *  by the system.
-*/
-
-int ath_descdma_setup(struct ath_softc *sc,
-		      struct ath_descdma *dd,
-		      struct list_head *head,
-		      const char *name,
-		      int nbuf,
-		      int ndesc)
-{
-#define	DS2PHYS(_dd, _ds)						\
-	((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
-#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
-#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
-
-	struct ath_desc *ds;
-	struct ath_buf *bf;
-	int i, bsize, error;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA: %u buffers %u desc/buf\n",
-		__func__, name, nbuf, ndesc);
-
-	/* ath_desc must be a multiple of DWORDs */
-	if ((sizeof(struct ath_desc) % 4) != 0) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: ath_desc not DWORD aligned\n",
-			__func__);
-		ASSERT((sizeof(struct ath_desc) % 4) == 0);
-		error = -ENOMEM;
-		goto fail;
-	}
-
-	dd->dd_name = name;
-	dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
-
-	/*
-	 * Need additional DMA memory because we can't use
-	 * descriptors that cross the 4K page boundary. Assume
-	 * one skipped descriptor per 4K page.
-	 */
-	if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
-		u32 ndesc_skipped =
-			ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
-		u32 dma_len;
-
-		while (ndesc_skipped) {
-			dma_len = ndesc_skipped * sizeof(struct ath_desc);
-			dd->dd_desc_len += dma_len;
-
-			ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
-		};
-	}
-
-	/* allocate descriptors */
-	dd->dd_desc = pci_alloc_consistent(sc->pdev,
-			      dd->dd_desc_len,
-			      &dd->dd_desc_paddr);
-	if (dd->dd_desc == NULL) {
-		error = -ENOMEM;
-		goto fail;
-	}
-	ds = dd->dd_desc;
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA map: %p (%u) -> %llx (%u)\n",
-		__func__, dd->dd_name, ds, (u32) dd->dd_desc_len,
-		ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
-
-	/* allocate buffers */
-	bsize = sizeof(struct ath_buf) * nbuf;
-	bf = kmalloc(bsize, GFP_KERNEL);
-	if (bf == NULL) {
-		error = -ENOMEM;
-		goto fail2;
-	}
-	memset(bf, 0, bsize);
-	dd->dd_bufptr = bf;
-
-	INIT_LIST_HEAD(head);
-	for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
-		bf->bf_desc = ds;
-		bf->bf_daddr = DS2PHYS(dd, ds);
-
-		if (!(sc->sc_ah->ah_caps.hw_caps &
-		      ATH9K_HW_CAP_4KB_SPLITTRANS)) {
-			/*
-			 * Skip descriptor addresses which can cause 4KB
-			 * boundary crossing (addr + length) with a 32 dword
-			 * descriptor fetch.
-			 */
-			while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
-				ASSERT((caddr_t) bf->bf_desc <
-				       ((caddr_t) dd->dd_desc +
-					dd->dd_desc_len));
-
-				ds += ndesc;
-				bf->bf_desc = ds;
-				bf->bf_daddr = DS2PHYS(dd, ds);
-			}
-		}
-		list_add_tail(&bf->list, head);
-	}
-	return 0;
-fail2:
-	pci_free_consistent(sc->pdev,
-		dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
-fail:
-	memset(dd, 0, sizeof(*dd));
-	return error;
-#undef ATH_DESC_4KB_BOUND_CHECK
-#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
-#undef DS2PHYS
-}
-
-/*
- *  Cleanup DMA descriptors
- *
- *  This function will free the DMA block that was allocated for the descriptor
- *  pool.  Since this was allocated as one "chunk", it is freed in the same
- *  manner.
-*/
-
-void ath_descdma_cleanup(struct ath_softc *sc,
-			 struct ath_descdma *dd,
-			 struct list_head *head)
-{
-	/* Free memory associated with descriptors */
-	pci_free_consistent(sc->pdev,
-		dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
-
-	INIT_LIST_HEAD(head);
-	kfree(dd->dd_bufptr);
-	memset(dd, 0, sizeof(*dd));
-}
-
-/*************/
-/* Utilities */
-/*************/
-
-int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
-{
-	int qnum;
-
-	switch (queue) {
-	case 0:
-		qnum = sc->sc_haltype2q[ATH9K_WME_AC_VO];
-		break;
-	case 1:
-		qnum = sc->sc_haltype2q[ATH9K_WME_AC_VI];
-		break;
-	case 2:
-		qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
-		break;
-	case 3:
-		qnum = sc->sc_haltype2q[ATH9K_WME_AC_BK];
-		break;
-	default:
-		qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
-		break;
-	}
-
-	return qnum;
-}
-
-int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
-{
-	int qnum;
-
-	switch (queue) {
-	case ATH9K_WME_AC_VO:
-		qnum = 0;
-		break;
-	case ATH9K_WME_AC_VI:
-		qnum = 1;
-		break;
-	case ATH9K_WME_AC_BE:
-		qnum = 2;
-		break;
-	case ATH9K_WME_AC_BK:
-		qnum = 3;
-		break;
-	default:
-		qnum = -1;
-		break;
-	}
-
-	return qnum;
-}
-
-
-/*
- *  Expand time stamp to TSF
- *
- *  Extend 15-bit time stamp from rx descriptor to
- *  a full 64-bit TSF using the current h/w TSF.
-*/
-
-u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
-{
-	u64 tsf;
-
-	tsf = ath9k_hw_gettsf64(sc->sc_ah);
-	if ((tsf & 0x7fff) < rstamp)
-		tsf -= 0x8000;
-	return (tsf & ~0x7fff) | rstamp;
-}
-
-/*
- *  Set Default Antenna
- *
- *  Call into the HAL to set the default antenna to use.  Not really valid for
- *  MIMO technology.
-*/
-
-void ath_setdefantenna(void *context, u32 antenna)
-{
-	struct ath_softc *sc = (struct ath_softc *)context;
-	struct ath_hal *ah = sc->sc_ah;
-
-	/* XXX block beacon interrupts */
-	ath9k_hw_setantenna(ah, antenna);
-	sc->sc_defant = antenna;
-	sc->sc_rxotherant = 0;
-}
-
-/*
- * Set Slot Time
- *
- * This will wake up the chip if required, and set the slot time for the
- * frame (maximum transmit time).  Slot time is assumed to be already set
- * in the ATH object member sc_slottime
-*/
-
-void ath_setslottime(struct ath_softc *sc)
-{
-	ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime);
-	sc->sc_updateslot = OK;
-}
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index cb3e61e..4ca2aed 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -17,27 +17,8 @@
 #ifndef CORE_H
 #define CORE_H
 
-#include <linux/version.h>
-#include <linux/autoconf.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/wait.h>
 #include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <asm/byteorder.h>
-#include <linux/scatterlist.h>
-#include <asm/page.h>
 #include <net/mac80211.h>
 #include <linux/leds.h>
 #include <linux/rfkill.h>
@@ -47,10 +28,6 @@
 
 struct ath_node;
 
-/******************/
-/* Utility macros */
-/******************/
-
 /* Macro to expand scalars to 64-bit objects */
 
 #define	ito64(x) (sizeof(x) == 8) ?			\
@@ -84,94 +61,125 @@
 #define TSF_TO_TU(_h,_l) \
 	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
 
-#define ATH9K_BH_STATUS_INTACT		0
-#define ATH9K_BH_STATUS_CHANGE		1
-
-#define	ATH_TXQ_SETUP(sc, i)        ((sc)->sc_txqsetup & (1<<i))
-
-static inline unsigned long get_timestamp(void)
-{
-	return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ);
-}
+#define	ATH_TXQ_SETUP(sc, i)        ((sc)->tx.txqsetup & (1<<i))
 
 static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
-/*************/
-/* Debugging */
-/*************/
-
 enum ATH_DEBUG {
 	ATH_DBG_RESET		= 0x00000001,
-	ATH_DBG_PHY_IO		= 0x00000002,
-	ATH_DBG_REG_IO		= 0x00000004,
-	ATH_DBG_QUEUE		= 0x00000008,
-	ATH_DBG_EEPROM		= 0x00000010,
-	ATH_DBG_NF_CAL		= 0x00000020,
-	ATH_DBG_CALIBRATE	= 0x00000040,
-	ATH_DBG_CHANNEL		= 0x00000080,
-	ATH_DBG_INTERRUPT	= 0x00000100,
-	ATH_DBG_REGULATORY	= 0x00000200,
-	ATH_DBG_ANI		= 0x00000400,
-	ATH_DBG_POWER_MGMT	= 0x00000800,
-	ATH_DBG_XMIT		= 0x00001000,
-	ATH_DBG_BEACON		= 0x00002000,
-	ATH_DBG_RATE		= 0x00004000,
-	ATH_DBG_CONFIG		= 0x00008000,
-	ATH_DBG_KEYCACHE	= 0x00010000,
-	ATH_DBG_AGGR		= 0x00020000,
-	ATH_DBG_FATAL		= 0x00040000,
+	ATH_DBG_REG_IO		= 0x00000002,
+	ATH_DBG_QUEUE		= 0x00000004,
+	ATH_DBG_EEPROM		= 0x00000008,
+	ATH_DBG_CALIBRATE	= 0x00000010,
+	ATH_DBG_CHANNEL		= 0x00000020,
+	ATH_DBG_INTERRUPT	= 0x00000040,
+	ATH_DBG_REGULATORY	= 0x00000080,
+	ATH_DBG_ANI		= 0x00000100,
+	ATH_DBG_POWER_MGMT	= 0x00000200,
+	ATH_DBG_XMIT		= 0x00000400,
+	ATH_DBG_BEACON		= 0x00001000,
+	ATH_DBG_CONFIG		= 0x00002000,
+	ATH_DBG_KEYCACHE	= 0x00004000,
+	ATH_DBG_FATAL		= 0x00008000,
 	ATH_DBG_ANY		= 0xffffffff
 };
 
 #define DBG_DEFAULT (ATH_DBG_FATAL)
 
-#define	DPRINTF(sc, _m, _fmt, ...) do {			\
-		if (sc->sc_debug & (_m))                \
-			printk(_fmt , ##__VA_ARGS__);	\
-	} while (0)
+#ifdef CONFIG_ATH9K_DEBUG
 
-/***************************/
-/* Load-time Configuration */
-/***************************/
+/**
+ * struct ath_interrupt_stats - Contains statistics about interrupts
+ * @total: Total no. of interrupts generated so far
+ * @rxok: RX with no errors
+ * @rxeol: RX with no more RXDESC available
+ * @rxorn: RX FIFO overrun
+ * @txok: TX completed at the requested rate
+ * @txurn: TX FIFO underrun
+ * @mib: MIB regs reaching its threshold
+ * @rxphyerr: RX with phy errors
+ * @rx_keycache_miss: RX with key cache misses
+ * @swba: Software Beacon Alert
+ * @bmiss: Beacon Miss
+ * @bnr: Beacon Not Ready
+ * @cst: Carrier Sense TImeout
+ * @gtt: Global TX Timeout
+ * @tim: RX beacon TIM occurrence
+ * @cabend: RX End of CAB traffic
+ * @dtimsync: DTIM sync lossage
+ * @dtim: RX Beacon with DTIM
+ */
+struct ath_interrupt_stats {
+	u32 total;
+	u32 rxok;
+	u32 rxeol;
+	u32 rxorn;
+	u32 txok;
+	u32 txeol;
+	u32 txurn;
+	u32 mib;
+	u32 rxphyerr;
+	u32 rx_keycache_miss;
+	u32 swba;
+	u32 bmiss;
+	u32 bnr;
+	u32 cst;
+	u32 gtt;
+	u32 tim;
+	u32 cabend;
+	u32 dtimsync;
+	u32 dtim;
+};
 
-/* Per-instance load-time (note: NOT run-time) configurations
- * for Atheros Device */
+struct ath_stats {
+	struct ath_interrupt_stats istats;
+};
+
+struct ath9k_debug {
+	int debug_mask;
+	struct dentry *debugfs_root;
+	struct dentry *debugfs_phy;
+	struct dentry *debugfs_dma;
+	struct dentry *debugfs_interrupt;
+	struct ath_stats stats;
+};
+
+void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...);
+int ath9k_init_debug(struct ath_softc *sc);
+void ath9k_exit_debug(struct ath_softc *sc);
+void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
+
+#else
+
+static inline void DPRINTF(struct ath_softc *sc, int dbg_mask,
+			   const char *fmt, ...)
+{
+}
+
+static inline int ath9k_init_debug(struct ath_softc *sc)
+{
+	return 0;
+}
+
+static inline void ath9k_exit_debug(struct ath_softc *sc)
+{
+}
+
+static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
+					    enum ath9k_int status)
+{
+}
+
+#endif /* CONFIG_ATH9K_DEBUG */
+
 struct ath_config {
 	u32 ath_aggr_prot;
 	u16 txpowlimit;
 	u16 txpowlimit_override;
-	u8 cabqReadytime; /* Cabq Readytime % */
-	u8 swBeaconProcess; /* Process received beacons in SW (vs HW) */
+	u8 cabqReadytime;
+	u8 swBeaconProcess;
 };
 
-/***********************/
-/* Chainmask Selection */
-/***********************/
-
-#define ATH_CHAINMASK_SEL_TIMEOUT	   6000
-/* Default - Number of last RSSI values that is used for
- * chainmask selection */
-#define ATH_CHAINMASK_SEL_RSSI_CNT	   10
-/* Means use 3x3 chainmask instead of configured chainmask */
-#define ATH_CHAINMASK_SEL_3X3		   7
-/* Default - Rssi threshold below which we have to switch to 3x3 */
-#define ATH_CHAINMASK_SEL_UP_RSSI_THRES	   20
-/* Default - Rssi threshold above which we have to switch to
- * user configured values */
-#define ATH_CHAINMASK_SEL_DOWN_RSSI_THRES  35
-/* Struct to store the chainmask select related info */
-struct ath_chainmask_sel {
-	struct timer_list timer;
-	int cur_tx_mask; 	/* user configured or 3x3 */
-	int cur_rx_mask; 	/* user configured or 3x3 */
-	int tx_avgrssi;
-	u8 switch_allowed:1, 	/* timer will set this */
-	   cm_sel_enabled : 1;
-};
-
-int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an);
-void ath_update_chainmask(struct ath_softc *sc, int is_ht);
-
 /*************************/
 /* Descriptor Management */
 /*************************/
@@ -200,15 +208,14 @@
 };
 
 struct ath_buf_state {
-	int bfs_nframes;			/* # frames in aggregate */
-	u16 bfs_al;				/* length of aggregate */
-	u16 bfs_frmlen;				/* length of frame */
-	int bfs_seqno;				/* sequence number */
-	int bfs_tidno;				/* tid of this frame */
-	int bfs_retries;			/* current retries */
-	struct ath_rc_series bfs_rcs[4];	/* rate series */
-	u32 bf_type;				/* BUF_* (enum buffer_type) */
-	/* key type use to encrypt this frame */
+	int bfs_nframes;		/* # frames in aggregate */
+	u16 bfs_al;			/* length of aggregate */
+	u16 bfs_frmlen;			/* length of frame */
+	int bfs_seqno;			/* sequence number */
+	int bfs_tidno;			/* tid of this frame */
+	int bfs_retries;		/* current retries */
+	u32 bf_type;			/* BUF_* (enum buffer_type) */
+	u32 bfs_keyix;
 	enum ath9k_key_type bfs_keytype;
 };
 
@@ -219,6 +226,7 @@
 #define bf_seqno        	bf_state.bfs_seqno
 #define bf_tidno        	bf_state.bfs_tidno
 #define bf_rcs          	bf_state.bfs_rcs
+#define bf_keyix                bf_state.bfs_keyix
 #define bf_keytype      	bf_state.bfs_keytype
 #define bf_isdata(bf)		(bf->bf_state.bf_type & BUF_DATA)
 #define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR)
@@ -242,9 +250,7 @@
 					   an aggregate) */
 	struct ath_buf *bf_lastfrm;	/* last buf of this frame */
 	struct ath_buf *bf_next;	/* next subframe in the aggregate */
-	struct ath_buf *bf_rifslast;	/* last buf for RIFS burst */
 	void *bf_mpdu;			/* enclosing frame structure */
-	void *bf_node;			/* pointer to the node */
 	struct ath_desc *bf_desc;	/* virtual addr of desc */
 	dma_addr_t bf_daddr;		/* physical addr of desc */
 	dma_addr_t bf_buf_addr;		/* physical addr of data buffer */
@@ -254,13 +260,6 @@
 	dma_addr_t bf_dmacontext;
 };
 
-/*
- * reset the rx buffer.
- * any new fields added to the athbuf and require
- * reset need to be added to this macro.
- * currently bf_status is the only one requires that
- * requires reset.
- */
 #define ATH_RXBUF_RESET(_bf)    ((_bf)->bf_status = 0)
 
 /* hw processing complete, desc processed by hal */
@@ -281,304 +280,41 @@
 	dma_addr_t dd_dmacontext;
 };
 
-/* Abstraction of a received RX MPDU/MMPDU, or a RX fragment */
-
-struct ath_rx_context {
-	struct ath_buf *ctx_rxbuf;	/* associated ath_buf for rx */
-};
-#define ATH_RX_CONTEXT(skb) ((struct ath_rx_context *)skb->cb)
-
-int ath_descdma_setup(struct ath_softc *sc,
-		      struct ath_descdma *dd,
-		      struct list_head *head,
-		      const char *name,
-		      int nbuf,
-		      int ndesc);
-int ath_desc_alloc(struct ath_softc *sc);
-void ath_desc_free(struct ath_softc *sc);
-void ath_descdma_cleanup(struct ath_softc *sc,
-			 struct ath_descdma *dd,
+int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+		      struct list_head *head, const char *name,
+		      int nbuf, int ndesc);
+void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
 			 struct list_head *head);
 
-/******/
-/* RX */
-/******/
+/***********/
+/* RX / TX */
+/***********/
 
-#define ATH_MAX_ANTENNA          3
-#define ATH_RXBUF                512
-#define ATH_RX_TIMEOUT           40      /* 40 milliseconds */
-#define WME_NUM_TID              16
-#define IEEE80211_BAR_CTL_TID_M  0xF000  /* tid mask */
-#define IEEE80211_BAR_CTL_TID_S  12      /* tid shift */
-
-enum ATH_RX_TYPE {
-	ATH_RX_NON_CONSUMED = 0,
-	ATH_RX_CONSUMED
-};
-
-/* per frame rx status block */
-struct ath_recv_status {
-	u64 tsf;		/* mac tsf */
-	int8_t rssi;		/* RSSI (noise floor ajusted) */
-	int8_t rssictl[ATH_MAX_ANTENNA];	/* RSSI (noise floor ajusted) */
-	int8_t rssiextn[ATH_MAX_ANTENNA];	/* RSSI (noise floor ajusted) */
-	int8_t abs_rssi;	/* absolute RSSI */
-	u8 rateieee;		/* data rate received (IEEE rate code) */
-	u8 ratecode;		/* phy rate code */
-	int rateKbps;		/* data rate received (Kbps) */
-	int antenna;		/* rx antenna */
-	int flags;		/* status of associated skb */
-#define ATH_RX_FCS_ERROR        0x01
-#define ATH_RX_MIC_ERROR        0x02
-#define ATH_RX_DECRYPT_ERROR    0x04
-#define ATH_RX_RSSI_VALID       0x08
-/* if any of ctl,extn chainrssis are valid */
-#define ATH_RX_CHAIN_RSSI_VALID 0x10
-/* if extn chain rssis are valid */
-#define ATH_RX_RSSI_EXTN_VALID  0x20
-/* set if 40Mhz, clear if 20Mhz */
-#define ATH_RX_40MHZ            0x40
-/* set if short GI, clear if full GI */
-#define ATH_RX_SHORT_GI         0x80
-};
-
-struct ath_rxbuf {
-	struct sk_buff *rx_wbuf;
-	unsigned long rx_time;			/* system time when received */
-	struct ath_recv_status rx_status;	/* cached rx status */
-};
-
-/* Per-TID aggregate receiver state for a node */
-struct ath_arx_tid {
-	struct ath_node *an;
-	struct ath_rxbuf *rxbuf;	/* re-ordering buffer */
-	struct timer_list timer;
-	spinlock_t tidlock;
-	int baw_head;			/* seq_next at head */
-	int baw_tail;			/* tail of block-ack window */
-	int seq_reset;			/* need to reset start sequence */
-	int addba_exchangecomplete;
-	u16 seq_next;			/* next expected sequence */
-	u16 baw_size;			/* block-ack window size */
-};
-
-/* Per-node receiver aggregate state */
-struct ath_arx {
-	struct ath_arx_tid tid[WME_NUM_TID];
-};
-
-int ath_startrecv(struct ath_softc *sc);
-bool ath_stoprecv(struct ath_softc *sc);
-void ath_flushrecv(struct ath_softc *sc);
-u32 ath_calcrxfilter(struct ath_softc *sc);
-void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an);
-void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an);
-void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
-void ath_handle_rx_intr(struct ath_softc *sc);
-int ath_rx_init(struct ath_softc *sc, int nbufs);
-void ath_rx_cleanup(struct ath_softc *sc);
-int ath_rx_tasklet(struct ath_softc *sc, int flush);
-int ath_rx_input(struct ath_softc *sc,
-		 struct ath_node *node,
-		 int is_ampdu,
-		 struct sk_buff *skb,
-		 struct ath_recv_status *rx_status,
-		 enum ATH_RX_TYPE *status);
-int _ath_rx_indicate(struct ath_softc *sc,
-		     struct sk_buff *skb,
-		     struct ath_recv_status *status,
-		     u16 keyix);
-int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb,
-		    struct ath_recv_status *status);
-
-/******/
-/* TX */
-/******/
-
+#define ATH_MAX_ANTENNA         3
+#define ATH_RXBUF               512
+#define WME_NUM_TID             16
 #define ATH_TXBUF               512
-/* max number of transmit attempts (tries) */
 #define ATH_TXMAXTRY            13
-/* max number of 11n transmit attempts (tries) */
 #define ATH_11N_TXMAXTRY        10
-/* max number of tries for management and control frames */
 #define ATH_MGT_TXMAXTRY        4
 #define WME_BA_BMP_SIZE         64
 #define WME_MAX_BA              WME_BA_BMP_SIZE
 #define ATH_TID_MAX_BUFS        (2 * WME_MAX_BA)
+
 #define TID_TO_WME_AC(_tid)				\
 	((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE :	\
 	 (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK :	\
 	 (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI :	\
 	 WME_AC_VO)
 
-
-/* Wireless Multimedia Extension Defines */
-#define WME_AC_BE               0 /* best effort */
-#define WME_AC_BK               1 /* background */
-#define WME_AC_VI               2 /* video */
-#define WME_AC_VO               3 /* voice */
-#define WME_NUM_AC              4
-
-enum ATH_SM_PWRSAV{
-	ATH_SM_ENABLE,
-	ATH_SM_PWRSAV_STATIC,
-	ATH_SM_PWRSAV_DYNAMIC,
-};
-
-/*
- * Data transmit queue state.  One of these exists for each
- * hardware transmit queue.  Packets sent to us from above
- * are assigned to queues based on their priority.  Not all
- * devices support a complete set of hardware transmit queues.
- * For those devices the array sc_ac2q will map multiple
- * priorities to fewer hardware queues (typically all to one
- * hardware queue).
- */
-struct ath_txq {
-	u32 axq_qnum;			/* hardware q number */
-	u32 *axq_link;			/* link ptr in last TX desc */
-	struct list_head axq_q;		/* transmit queue */
-	spinlock_t axq_lock;
-	unsigned long axq_lockflags;	/* intr state when must cli */
-	u32 axq_depth;			/* queue depth */
-	u8 axq_aggr_depth;		/* aggregates queued */
-	u32 axq_totalqueued;		/* total ever queued */
-
-	/* count to determine if descriptor should generate int on this txq. */
-	u32 axq_intrcnt;
-
-	bool stopped;			/* Is mac80211 queue stopped ? */
-	struct ath_buf *axq_linkbuf;	/* virtual addr of last buffer*/
-
-	/* first desc of the last descriptor that contains CTS */
-	struct ath_desc *axq_lastdsWithCTS;
-
-	/* final desc of the gating desc that determines whether
-	   lastdsWithCTS has been DMA'ed or not */
-	struct ath_desc *axq_gatingds;
-
-	struct list_head axq_acq;
-};
-
-/* per TID aggregate tx state for a destination */
-struct ath_atx_tid {
-	struct list_head list;		/* round-robin tid entry */
-	struct list_head buf_q;		/* pending buffers */
-	struct ath_node *an;
-	struct ath_atx_ac *ac;
-	struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; /* active tx frames */
-	u16 seq_start;
-	u16 seq_next;
-	u16 baw_size;
-	int tidno;
-	int baw_head;			/* first un-acked tx buffer */
-	int baw_tail;			/* next unused tx buffer slot */
-	int sched;
-	int paused;
-	int cleanup_inprogress;
-	u32 addba_exchangecomplete:1;
-	int32_t addba_exchangeinprogress;
-	int addba_exchangeattempts;
-};
-
-/* per access-category aggregate tx state for a destination */
-struct ath_atx_ac {
-	int sched;			/* dest-ac is scheduled */
-	int qnum;			/* H/W queue number associated
-					   with this AC */
-	struct list_head list;		/* round-robin txq entry */
-	struct list_head tid_q;		/* queue of TIDs with buffers */
-};
-
-/* per dest tx state */
-struct ath_atx {
-	struct ath_atx_tid tid[WME_NUM_TID];
-	struct ath_atx_ac ac[WME_NUM_AC];
-};
-
-/* per-frame tx control block */
-struct ath_tx_control {
-	struct ath_node *an;
-	int if_id;
-	int qnum;
-	u32 ht:1;
-	u32 ps:1;
-	u32 use_minrate:1;
-	enum ath9k_pkt_type atype;
-	enum ath9k_key_type keytype;
-	u32 flags;
-	u16 seqno;
-	u16 tidno;
-	u16 txpower;
-	u16 frmlen;
-	u32 keyix;
-	int min_rate;
-	int mcast_rate;
-	struct ath_softc *dev;
-	dma_addr_t dmacontext;
-};
-
-/* per frame tx status block */
-struct ath_xmit_status {
-	int retries;	/* number of retries to successufully
-			   transmit this frame */
-	int flags;	/* status of transmit */
-#define ATH_TX_ERROR        0x01
-#define ATH_TX_XRETRY       0x02
-#define ATH_TX_BAR          0x04
-};
-
-struct ath_tx_stat {
-	int rssi;		/* RSSI (noise floor ajusted) */
-	int rssictl[ATH_MAX_ANTENNA];	/* RSSI (noise floor ajusted) */
-	int rssiextn[ATH_MAX_ANTENNA];	/* RSSI (noise floor ajusted) */
-	int rateieee;		/* data rate xmitted (IEEE rate code) */
-	int rateKbps;		/* data rate xmitted (Kbps) */
-	int ratecode;		/* phy rate code */
-	int flags;		/* validity flags */
-/* if any of ctl,extn chain rssis are valid */
-#define ATH_TX_CHAIN_RSSI_VALID 0x01
-/* if extn chain rssis are valid */
-#define ATH_TX_RSSI_EXTN_VALID  0x02
-	u32 airtime;	/* time on air per final tx rate */
-};
-
-struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
-void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
-int ath_tx_setup(struct ath_softc *sc, int haltype);
-void ath_draintxq(struct ath_softc *sc, bool retry_tx);
-void ath_tx_draintxq(struct ath_softc *sc,
-		     struct ath_txq *txq, bool retry_tx);
-void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
-void ath_tx_node_cleanup(struct ath_softc *sc,
-			 struct ath_node *an, bool bh_flag);
-void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an);
-void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
-int ath_tx_init(struct ath_softc *sc, int nbufs);
-int ath_tx_cleanup(struct ath_softc *sc);
-int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
-int ath_txq_update(struct ath_softc *sc, int qnum,
-		   struct ath9k_tx_queue_info *q);
-int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb);
-void ath_tx_tasklet(struct ath_softc *sc);
-u32 ath_txq_depth(struct ath_softc *sc, int qnum);
-u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum);
-void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth);
-void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
-		     struct ath_xmit_status *tx_status, struct ath_node *an);
-void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
-
-/**********************/
-/* Node / Aggregation */
-/**********************/
-
-/* indicates the node is clened up */
-#define ATH_NODE_CLEAN          0x1
-/* indicates the node is 80211 power save */
-#define ATH_NODE_PWRSAVE        0x2
+#define WME_AC_BE   0
+#define WME_AC_BK   1
+#define WME_AC_VI   2
+#define WME_AC_VO   3
+#define WME_NUM_AC  4
 
 #define ADDBA_EXCHANGE_ATTEMPTS    10
-#define ATH_AGGR_DELIM_SZ          4   /* delimiter size   */
+#define ATH_AGGR_DELIM_SZ          4
 #define ATH_AGGR_MINPLEN           256 /* in bytes, minimum packet length */
 /* number of delimiters for encryption padding */
 #define ATH_AGGR_ENCRYPTDELIM      10
@@ -588,6 +324,7 @@
 #define IEEE80211_SEQ_SEQ_SHIFT    4
 #define IEEE80211_SEQ_MAX          4096
 #define IEEE80211_MIN_AMPDU_BUF    0x8
+#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
 
 /* return whether a bit at index _n in bitmap _bm is set
  * _sz is the size of the bitmap  */
@@ -605,10 +342,10 @@
 #define BAW_WITHIN(_start, _bawsz, _seqno) \
 	((((_seqno) - (_start)) & 4095) < (_bawsz))
 
-#define ATH_DS_BA_SEQ(_ds)               ((_ds)->ds_us.tx.ts_seqnum)
-#define ATH_DS_BA_BITMAP(_ds)            (&(_ds)->ds_us.tx.ba_low)
-#define ATH_DS_TX_BA(_ds)	((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
-#define ATH_AN_2_TID(_an, _tidno)        (&(_an)->an_aggr.tx.tid[(_tidno)])
+#define ATH_DS_BA_SEQ(_ds)         ((_ds)->ds_us.tx.ts_seqnum)
+#define ATH_DS_BA_BITMAP(_ds)      (&(_ds)->ds_us.tx.ba_low)
+#define ATH_DS_TX_BA(_ds)          ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
+#define ATH_AN_2_TID(_an, _tidno)  (&(_an)->tid[(_tidno)])
 
 enum ATH_AGGR_STATUS {
 	ATH_AGGR_DONE,
@@ -618,12 +355,86 @@
 	ATH_AGGR_8K_LIMITED,
 };
 
-enum ATH_AGGR_CHECK {
-	AGGR_NOT_REQUIRED,
-	AGGR_REQUIRED,
-	AGGR_CLEANUP_PROGRESS,
-	AGGR_EXCHANGE_PROGRESS,
-	AGGR_EXCHANGE_DONE
+struct ath_txq {
+	u32 axq_qnum;			/* hardware q number */
+	u32 *axq_link;			/* link ptr in last TX desc */
+	struct list_head axq_q;		/* transmit queue */
+	spinlock_t axq_lock;
+	unsigned long axq_lockflags;	/* intr state when must cli */
+	u32 axq_depth;			/* queue depth */
+	u8 axq_aggr_depth;		/* aggregates queued */
+	u32 axq_totalqueued;		/* total ever queued */
+	bool stopped;			/* Is mac80211 queue stopped ? */
+	struct ath_buf *axq_linkbuf;	/* virtual addr of last buffer*/
+
+	/* first desc of the last descriptor that contains CTS */
+	struct ath_desc *axq_lastdsWithCTS;
+
+	/* final desc of the gating desc that determines whether
+	   lastdsWithCTS has been DMA'ed or not */
+	struct ath_desc *axq_gatingds;
+
+	struct list_head axq_acq;
+};
+
+#define AGGR_CLEANUP         BIT(1)
+#define AGGR_ADDBA_COMPLETE  BIT(2)
+#define AGGR_ADDBA_PROGRESS  BIT(3)
+
+/* per TID aggregate tx state for a destination */
+struct ath_atx_tid {
+	struct list_head list;		/* round-robin tid entry */
+	struct list_head buf_q;		/* pending buffers */
+	struct ath_node *an;
+	struct ath_atx_ac *ac;
+	struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; /* active tx frames */
+	u16 seq_start;
+	u16 seq_next;
+	u16 baw_size;
+	int tidno;
+	int baw_head;			/* first un-acked tx buffer */
+	int baw_tail;			/* next unused tx buffer slot */
+	int sched;
+	int paused;
+	u8 state;
+	int addba_exchangeattempts;
+};
+
+/* per access-category aggregate tx state for a destination */
+struct ath_atx_ac {
+	int sched;			/* dest-ac is scheduled */
+	int qnum;			/* H/W queue number associated
+					   with this AC */
+	struct list_head list;		/* round-robin txq entry */
+	struct list_head tid_q;		/* queue of TIDs with buffers */
+};
+
+/* per-frame tx control block */
+struct ath_tx_control {
+	struct ath_txq *txq;
+	int if_id;
+};
+
+/* per frame tx status block */
+struct ath_xmit_status {
+	int retries;	/* number of retries to successufully
+			   transmit this frame */
+	int flags;	/* status of transmit */
+#define ATH_TX_ERROR        0x01
+#define ATH_TX_XRETRY       0x02
+#define ATH_TX_BAR          0x04
+};
+
+/* All RSSI values are noise floor adjusted */
+struct ath_tx_stat {
+	int rssi;
+	int rssictl[ATH_MAX_ANTENNA];
+	int rssiextn[ATH_MAX_ANTENNA];
+	int rateieee;
+	int rateKbps;
+	int ratecode;
+	int flags;
+	u32 airtime;	/* time on air per final tx rate */
 };
 
 struct aggr_rifs_param {
@@ -634,94 +445,73 @@
 	struct ath_rc_series *param_rcs;
 };
 
-/* Per-node aggregation state */
-struct ath_node_aggr {
-	struct ath_atx tx;	/* node transmit state */
-	struct ath_arx rx;	/* node receive state */
-};
-
-/* driver-specific node state */
 struct ath_node {
-	struct list_head list;
 	struct ath_softc *an_sc;
-	atomic_t an_refcnt;
-	struct ath_chainmask_sel an_chainmask_sel;
-	struct ath_node_aggr an_aggr;
-	u8 an_smmode; /* SM Power save mode */
-	u8 an_flags;
-	u8 an_addr[ETH_ALEN];
+	struct ath_atx_tid tid[WME_NUM_TID];
+	struct ath_atx_ac ac[WME_NUM_AC];
+	u16 maxampdu;
+	u8 mpdudensity;
 };
 
-void ath_tx_resume_tid(struct ath_softc *sc,
-	struct ath_atx_tid *tid);
-enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc,
-	struct ath_node *an, u8 tidno);
-void ath_tx_aggr_teardown(struct ath_softc *sc,
-	struct ath_node *an, u8 tidno);
-void ath_rx_aggr_teardown(struct ath_softc *sc,
-	struct ath_node *an, u8 tidno);
-int ath_rx_aggr_start(struct ath_softc *sc,
-		      const u8 *addr,
-		      u16 tid,
-		      u16 *ssn);
-int ath_rx_aggr_stop(struct ath_softc *sc,
-		     const u8 *addr,
-		     u16 tid);
-int ath_tx_aggr_start(struct ath_softc *sc,
-		      const u8 *addr,
-		      u16 tid,
-		      u16 *ssn);
-int ath_tx_aggr_stop(struct ath_softc *sc,
-		     const u8 *addr,
-		     u16 tid);
-void ath_newassoc(struct ath_softc *sc,
-	struct ath_node *node, int isnew, int isuapsd);
-struct ath_node *ath_node_attach(struct ath_softc *sc,
-	u8 addr[ETH_ALEN], int if_id);
-void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag);
-struct ath_node *ath_node_get(struct ath_softc *sc, u8 addr[ETH_ALEN]);
-void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag);
-struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr);
-
-/*******************/
-/* Beacon Handling */
-/*******************/
-
-/*
- * Regardless of the number of beacons we stagger, (i.e. regardless of the
- * number of BSSIDs) if a given beacon does not go out even after waiting this
- * number of beacon intervals, the game's up.
- */
-#define BSTUCK_THRESH           	(9 * ATH_BCBUF)
-#define	ATH_BCBUF               	4   /* number of beacon buffers */
-#define ATH_DEFAULT_BINTVAL     	100 /* default beacon interval in TU */
-#define ATH_DEFAULT_BMISS_LIMIT 	10
-#define IEEE80211_MS_TO_TU(x)           (((x) * 1000) / 1024)
-
-/* beacon configuration */
-struct ath_beacon_config {
-	u16 beacon_interval;
-	u16 listen_interval;
-	u16 dtim_period;
-	u16 bmiss_timeout;
-	u8 dtim_count;
-	u8 tim_offset;
-	union {
-		u64 last_tsf;
-		u8 last_tstamp[8];
-	} u; /* last received beacon/probe response timestamp of this BSS. */
+struct ath_tx {
+	u16 seq_no;
+	u32 txqsetup;
+	int hwq_map[ATH9K_WME_AC_VO+1];
+	spinlock_t txbuflock;
+	struct list_head txbuf;
+	struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
+	struct ath_descdma txdma;
 };
 
-void ath9k_beacon_tasklet(unsigned long data);
-void ath_beacon_config(struct ath_softc *sc, int if_id);
-int ath_beaconq_setup(struct ath_hal *ah);
-int ath_beacon_alloc(struct ath_softc *sc, int if_id);
-void ath_bstuck_process(struct ath_softc *sc);
-void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp);
-void ath_beacon_sync(struct ath_softc *sc, int if_id);
-void ath_get_beaconconfig(struct ath_softc *sc,
-			  int if_id,
-			  struct ath_beacon_config *conf);
+struct ath_rx {
+	u8 defant;
+	u8 rxotherant;
+	u32 *rxlink;
+	int bufsize;
+	unsigned int rxfilter;
+	spinlock_t rxflushlock;
+	spinlock_t rxbuflock;
+	struct list_head rxbuf;
+	struct ath_descdma rxdma;
+};
+
+int ath_startrecv(struct ath_softc *sc);
+bool ath_stoprecv(struct ath_softc *sc);
+void ath_flushrecv(struct ath_softc *sc);
+u32 ath_calcrxfilter(struct ath_softc *sc);
+int ath_rx_init(struct ath_softc *sc, int nbufs);
+void ath_rx_cleanup(struct ath_softc *sc);
+int ath_rx_tasklet(struct ath_softc *sc, int flush);
+struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
+void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
+int ath_tx_setup(struct ath_softc *sc, int haltype);
+void ath_draintxq(struct ath_softc *sc, bool retry_tx);
+void ath_tx_draintxq(struct ath_softc *sc,
+		     struct ath_txq *txq, bool retry_tx);
+void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
+void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
+void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an);
+void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
+int ath_tx_init(struct ath_softc *sc, int nbufs);
+int ath_tx_cleanup(struct ath_softc *sc);
+int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
+struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
+int ath_txq_update(struct ath_softc *sc, int qnum,
+		   struct ath9k_tx_queue_info *q);
+int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
+		 struct ath_tx_control *txctl);
+void ath_tx_tasklet(struct ath_softc *sc);
+u32 ath_txq_depth(struct ath_softc *sc, int qnum);
+u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum);
+void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
+void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid);
+bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
+void ath_tx_aggr_teardown(struct ath_softc *sc,	struct ath_node *an, u8 tidno);
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+		      u16 tid, u16 *ssn);
+int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+
 /********/
 /* VAPs */
 /********/
@@ -737,68 +527,67 @@
 #define ATH_SET_VAP_BSSID_MASK(bssid_mask) \
 	((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))
 
-/* VAP configuration (from protocol layer) */
-struct ath_vap_config {
-	u32 av_fixed_rateset;
-	u32 av_fixed_retryset;
-};
-
-/* driver-specific vap state */
 struct ath_vap {
-	struct ieee80211_vif *av_if_data;
-	enum ath9k_opmode av_opmode;	/* VAP operational mode */
-	struct ath_buf *av_bcbuf;	/* beacon buffer */
-	struct ath_tx_control av_btxctl;  /* txctl information for beacon */
-	int av_bslot;			/* beacon slot index */
-	struct ath_vap_config av_config;/* vap configuration parameters*/
-	struct ath_rate_node *rc_node;
+	int av_bslot;
+	enum nl80211_iftype av_opmode;
+	struct ath_buf *av_bcbuf;
+	struct ath_tx_control av_btxctl;
 };
 
-int ath_vap_attach(struct ath_softc *sc,
-		   int if_id,
-		   struct ieee80211_vif *if_data,
-		   enum ath9k_opmode opmode);
-int ath_vap_detach(struct ath_softc *sc, int if_id);
-int ath_vap_config(struct ath_softc *sc,
-		   int if_id, struct ath_vap_config *if_config);
+/*******************/
+/* Beacon Handling */
+/*******************/
 
-/*********************/
-/* Antenna diversity */
-/*********************/
+/*
+ * Regardless of the number of beacons we stagger, (i.e. regardless of the
+ * number of BSSIDs) if a given beacon does not go out even after waiting this
+ * number of beacon intervals, the game's up.
+ */
+#define BSTUCK_THRESH           	(9 * ATH_BCBUF)
+#define	ATH_BCBUF               	1
+#define ATH_DEFAULT_BINTVAL     	100 /* TU */
+#define ATH_DEFAULT_BMISS_LIMIT 	10
+#define IEEE80211_MS_TO_TU(x)           (((x) * 1000) / 1024)
 
-#define ATH_ANT_DIV_MAX_CFG      2
-#define ATH_ANT_DIV_MIN_IDLE_US  1000000  /* us */
-#define ATH_ANT_DIV_MIN_SCAN_US  50000	  /* us */
-
-enum ATH_ANT_DIV_STATE{
-	ATH_ANT_DIV_IDLE,
-	ATH_ANT_DIV_SCAN,	/* evaluating antenna */
+struct ath_beacon_config {
+	u16 beacon_interval;
+	u16 listen_interval;
+	u16 dtim_period;
+	u16 bmiss_timeout;
+	u8 dtim_count;
+	u8 tim_offset;
+	union {
+		u64 last_tsf;
+		u8 last_tstamp[8];
+	} u; /* last received beacon/probe response timestamp of this BSS. */
 };
 
-struct ath_antdiv {
-	struct ath_softc *antdiv_sc;
-	u8 antdiv_start;
-	enum ATH_ANT_DIV_STATE antdiv_state;
-	u8 antdiv_num_antcfg;
-	u8 antdiv_curcfg;
-	u8 antdiv_bestcfg;
-	int32_t antdivf_rssitrig;
-	int32_t antdiv_lastbrssi[ATH_ANT_DIV_MAX_CFG];
-	u64 antdiv_lastbtsf[ATH_ANT_DIV_MAX_CFG];
-	u64 antdiv_laststatetsf;
-	u8 antdiv_bssid[ETH_ALEN];
+struct ath_beacon {
+	enum {
+		OK,		/* no change needed */
+		UPDATE,		/* update pending */
+		COMMIT		/* beacon sent, commit change */
+	} updateslot;		/* slot time update fsm */
+
+	u32 beaconq;
+	u32 bmisscnt;
+	u32 ast_be_xmit;
+	u64 bc_tstamp;
+	int bslot[ATH_BCBUF];
+	int slottime;
+	int slotupdate;
+	struct ath9k_tx_queue_info beacon_qi;
+	struct ath_descdma bdma;
+	struct ath_txq *cabq;
+	struct list_head bbuf;
 };
 
-void ath_slow_ant_div_init(struct ath_antdiv *antdiv,
-	struct ath_softc *sc, int32_t rssitrig);
-void ath_slow_ant_div_start(struct ath_antdiv *antdiv,
-			    u8 num_antcfg,
-			    const u8 *bssid);
-void ath_slow_ant_div_stop(struct ath_antdiv *antdiv);
-void ath_slow_ant_div(struct ath_antdiv *antdiv,
-		      struct ieee80211_hdr *wh,
-		      struct ath_rx_status *rx_stats);
-void ath_setdefantenna(void *sc, u32 antenna);
+void ath9k_beacon_tasklet(unsigned long data);
+void ath_beacon_config(struct ath_softc *sc, int if_id);
+int ath_beaconq_setup(struct ath_hal *ah);
+int ath_beacon_alloc(struct ath_softc *sc, int if_id);
+void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp);
+void ath_beacon_sync(struct ath_softc *sc, int if_id);
 
 /*******/
 /* ANI */
@@ -863,7 +652,7 @@
 #define DEFAULT_CACHELINE       32
 #define	ATH_DEFAULT_NOISE_FLOOR -95
 #define ATH_REGCLASSIDS_MAX     10
-#define ATH_CABQ_READY_TIME     80  /* % of beacon interval */
+#define ATH_CABQ_READY_TIME     80      /* % of beacon interval */
 #define ATH_MAX_SW_RETRIES      10
 #define ATH_CHAN_MAX            255
 #define IEEE80211_WEP_NKID      4       /* number of key ids */
@@ -876,34 +665,12 @@
  * Different parts have different size key caches.  We handle
  * up to ATH_KEYMAX entries (could dynamically allocate state).
  */
-#define	ATH_KEYMAX	        128        /* max key cache size we handle */
+#define	ATH_KEYMAX	        128     /* max key cache size we handle */
 
 #define ATH_IF_ID_ANY   	0xff
 #define ATH_TXPOWER_MAX         100     /* .5 dBm units */
-
-#define RSSI_LPF_THRESHOLD         -20
-#define ATH_RSSI_EP_MULTIPLIER     (1<<7)  /* pow2 to optimize out * and / */
-#define ATH_RATE_DUMMY_MARKER      0
-#define ATH_RSSI_LPF_LEN           10
-#define ATH_RSSI_DUMMY_MARKER      0x127
-
-#define ATH_EP_MUL(x, mul)         ((x) * (mul))
-#define ATH_EP_RND(x, mul)						\
-	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
-#define ATH_RSSI_OUT(x)							\
-	(((x) != ATH_RSSI_DUMMY_MARKER) ?				\
-	 (ATH_EP_RND((x), ATH_RSSI_EP_MULTIPLIER)) : ATH_RSSI_DUMMY_MARKER)
-#define ATH_RSSI_IN(x)					\
-	(ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
-#define ATH_LPF_RSSI(x, y, len)						\
-	((x != ATH_RSSI_DUMMY_MARKER) ? \
-		(((x) * ((len) - 1) + (y)) / (len)) : (y))
-#define ATH_RSSI_LPF(x, y) do {						\
-		if ((y) >= RSSI_LPF_THRESHOLD)				\
-			x = ATH_LPF_RSSI((x), \
-				ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
-	} while (0)
-
+#define ATH_RSSI_DUMMY_MARKER   0x127
+#define ATH_RATE_DUMMY_MARKER   0
 
 enum PROT_MODE {
 	PROT_M_NONE = 0,
@@ -911,19 +678,6 @@
 	PROT_M_CTSONLY
 };
 
-enum RATE_TYPE {
-	NORMAL_RATE = 0,
-	HALF_RATE,
-	QUARTER_RATE
-};
-
-struct ath_ht_info {
-	enum ath9k_ht_macmode tx_chan_width;
-	u16 maxampdu;
-	u8 mpdudensity;
-	u8 ext_chan_offset;
-};
-
 #define SC_OP_INVALID		BIT(0)
 #define SC_OP_BEACONS		BIT(1)
 #define SC_OP_RXAGGR		BIT(2)
@@ -944,141 +698,57 @@
 	struct pci_dev *pdev;
 	struct tasklet_struct intr_tq;
 	struct tasklet_struct bcon_tasklet;
-	struct ath_config sc_config;
 	struct ath_hal *sc_ah;
-	struct ath_rate_softc *sc_rc;
 	void __iomem *mem;
+	spinlock_t sc_resetlock;
+	struct mutex mutex;
 
 	u8 sc_curbssid[ETH_ALEN];
 	u8 sc_myaddr[ETH_ALEN];
 	u8 sc_bssidmask[ETH_ALEN];
-
-	int sc_debug;
 	u32 sc_intrstatus;
 	u32 sc_flags; /* SC_OP_* */
-	unsigned int rx_filter;
 	u16 sc_curtxpow;
 	u16 sc_curaid;
 	u16 sc_cachelsz;
-	int sc_slotupdate;		/* slot to next advance fsm */
-	int sc_slottime;
-	int sc_bslot[ATH_BCBUF];
+	u8 sc_nbcnvaps;
+	u16 sc_nvaps;
 	u8 sc_tx_chainmask;
 	u8 sc_rx_chainmask;
+	u32 sc_keymax;
+	DECLARE_BITMAP(sc_keymap, ATH_KEYMAX);
+	u8 sc_splitmic;
+	u8 sc_protrix;
 	enum ath9k_int sc_imask;
-	enum wireless_mode sc_curmode;	/* current phy mode */
 	enum PROT_MODE sc_protmode;
-
-	u8 sc_nbcnvaps;			/* # of vaps sending beacons */
-	u16 sc_nvaps;			/* # of active virtual ap's */
-	struct ath_vap *sc_vaps[ATH_BCBUF];
-
-	u8 sc_mcastantenna;
-	u8 sc_defant;			/* current default antenna */
-	u8 sc_rxotherant;		/* rx's on non-default antenna */
-
-	struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */
-	struct list_head node_list;
-	struct ath_ht_info sc_ht_info;
 	enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
+	enum ath9k_ht_macmode tx_chan_width;
 
-#ifdef CONFIG_SLOW_ANT_DIV
-	struct ath_antdiv sc_antdiv;
-#endif
-	enum {
-		OK,		/* no change needed */
-		UPDATE,		/* update pending */
-		COMMIT		/* beacon sent, commit change */
-	} sc_updateslot;	/* slot time update fsm */
-
-	/* Crypto */
-	u32 sc_keymax;		/* size of key cache */
-	DECLARE_BITMAP(sc_keymap, ATH_KEYMAX);	/* key use bit map */
-	u8 sc_splitmic;		/* split TKIP MIC keys */
-
-	/* RX */
-	struct list_head sc_rxbuf;
-	struct ath_descdma sc_rxdma;
-	int sc_rxbufsize;	/* rx size based on mtu */
-	u32 *sc_rxlink;		/* link ptr in last RX desc */
-
-	/* TX */
-	struct list_head sc_txbuf;
-	struct ath_txq sc_txq[ATH9K_NUM_TX_QUEUES];
-	struct ath_descdma sc_txdma;
-	u32 sc_txqsetup;
-	u32 sc_txintrperiod;	/* tx interrupt batching */
-	int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME	AC -> h/w qnum */
-	u16 seq_no; /* TX sequence number */
-
-	/* Beacon */
-	struct ath9k_tx_queue_info sc_beacon_qi;
-	struct ath_descdma sc_bdma;
-	struct ath_txq *sc_cabq;
-	struct list_head sc_bbuf;
-	u32 sc_bhalq;
-	u32 sc_bmisscount;
-	u32 ast_be_xmit;	/* beacons transmitted */
-	u64 bc_tstamp;
-
-	/* Rate */
+	struct ath_config sc_config;
+	struct ath_rx rx;
+	struct ath_tx tx;
+	struct ath_beacon beacon;
+	struct ieee80211_vif *sc_vaps[ATH_BCBUF];
 	struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
-	const struct ath9k_rate_table *sc_currates;
-	u8 sc_rixmap[256];	/* IEEE to h/w rate table ix */
-	u8 sc_protrix;		/* protection rate index */
-	struct {
-		u32 rateKbps;	/* transfer rate in kbs */
-		u8 ieeerate;	/* IEEE rate */
-	} sc_hwmap[256];	/* h/w rate ix mappings */
-
-	/* Channel, Band */
+	struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
+	struct ath_rate_table *cur_rate_table;
 	struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX];
 	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
-
-	/* Locks */
-	spinlock_t sc_rxflushlock;
-	spinlock_t sc_rxbuflock;
-	spinlock_t sc_txbuflock;
-	spinlock_t sc_resetlock;
-	spinlock_t node_lock;
-
-	/* LEDs */
 	struct ath_led radio_led;
 	struct ath_led assoc_led;
 	struct ath_led tx_led;
 	struct ath_led rx_led;
-
-	/* Rfkill */
 	struct ath_rfkill rf_kill;
-
-	/* ANI */
 	struct ath_ani sc_ani;
+	struct ath9k_node_stats sc_halstats;
+#ifdef CONFIG_ATH9K_DEBUG
+	struct ath9k_debug sc_debug;
+#endif
 };
 
-int ath_init(u16 devid, struct ath_softc *sc);
-void ath_deinit(struct ath_softc *sc);
-int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan);
-int ath_suspend(struct ath_softc *sc);
-irqreturn_t ath_isr(int irq, void *dev);
 int ath_reset(struct ath_softc *sc, bool retry_tx);
-int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan);
-
-/*********************/
-/* Utility Functions */
-/*********************/
-
-void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot);
-int ath_keyset(struct ath_softc *sc,
-	       u16 keyix,
-	       struct ath9k_keyval *hk,
-	       const u8 mac[ETH_ALEN]);
 int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
 int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
-void ath_setslottime(struct ath_softc *sc);
-void ath_update_txpow(struct ath_softc *sc);
 int ath_cabq_update(struct ath_softc *);
-void ath_get_currentCountry(struct ath_softc *sc,
-	struct ath9k_country_entry *ctry);
-u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp);
 
 #endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c
new file mode 100644
index 0000000..a80ed57
--- /dev/null
+++ b/drivers/net/wireless/ath9k/debug.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "reg.h"
+#include "hw.h"
+
+static unsigned int ath9k_debug = DBG_DEFAULT;
+module_param_named(debug, ath9k_debug, uint, 0);
+
+void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...)
+{
+	if (!sc)
+		return;
+
+	if (sc->sc_debug.debug_mask & dbg_mask) {
+		va_list args;
+
+		va_start(args, fmt);
+		printk(KERN_DEBUG "ath9k: ");
+		vprintk(fmt, args);
+		va_end(args);
+	}
+}
+
+static int ath9k_debugfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t read_file_dma(struct file *file, char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_hal *ah = sc->sc_ah;
+	char buf[1024];
+	unsigned int len = 0;
+	u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
+	int i, qcuOffset = 0, dcuOffset = 0;
+	u32 *qcuBase = &val[0], *dcuBase = &val[4];
+
+	REG_WRITE(ah, AR_MACMISC,
+		  ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
+		   (AR_MACMISC_MISC_OBS_BUS_1 <<
+		    AR_MACMISC_MISC_OBS_BUS_MSB_S)));
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"Raw DMA Debug values:\n");
+
+	for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
+		if (i % 4 == 0)
+			len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+		val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
+		len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ",
+				i, val[i]);
+	}
+
+	len += snprintf(buf + len, sizeof(buf) - len, "\n\n");
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
+
+	for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) {
+		if (i == 8) {
+			qcuOffset = 0;
+			qcuBase++;
+		}
+
+		if (i == 6) {
+			dcuOffset = 0;
+			dcuBase++;
+		}
+
+		len += snprintf(buf + len, sizeof(buf) - len,
+			"%2d          %2x      %1x     %2x           %2x\n",
+			i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
+			(*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
+			val[2] & (0x7 << (i * 3)) >> (i * 3),
+			(*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
+	}
+
+	len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"qcu_stitch state:   %2x    qcu_fetch state:        %2x\n",
+		(val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"qcu_complete state: %2x    dcu_complete state:     %2x\n",
+		(val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"dcu_arb state:      %2x    dcu_fp state:           %2x\n",
+		(val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"chan_idle_dur:     %3d    chan_idle_dur_valid:     %1d\n",
+		(val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"txfifo_valid_0:      %1d    txfifo_valid_1:          %1d\n",
+		(val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
+		(val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
+
+	len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n",
+			REG_READ(ah, AR_OBS_BUS_1));
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"AR_CR: 0x%x \n", REG_READ(ah, AR_CR));
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_dma = {
+	.read = read_file_dma,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE
+};
+
+
+void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
+{
+	if (status)
+		sc->sc_debug.stats.istats.total++;
+	if (status & ATH9K_INT_RX)
+		sc->sc_debug.stats.istats.rxok++;
+	if (status & ATH9K_INT_RXEOL)
+		sc->sc_debug.stats.istats.rxeol++;
+	if (status & ATH9K_INT_RXORN)
+		sc->sc_debug.stats.istats.rxorn++;
+	if (status & ATH9K_INT_TX)
+		sc->sc_debug.stats.istats.txok++;
+	if (status & ATH9K_INT_TXURN)
+		sc->sc_debug.stats.istats.txurn++;
+	if (status & ATH9K_INT_MIB)
+		sc->sc_debug.stats.istats.mib++;
+	if (status & ATH9K_INT_RXPHY)
+		sc->sc_debug.stats.istats.rxphyerr++;
+	if (status & ATH9K_INT_RXKCM)
+		sc->sc_debug.stats.istats.rx_keycache_miss++;
+	if (status & ATH9K_INT_SWBA)
+		sc->sc_debug.stats.istats.swba++;
+	if (status & ATH9K_INT_BMISS)
+		sc->sc_debug.stats.istats.bmiss++;
+	if (status & ATH9K_INT_BNR)
+		sc->sc_debug.stats.istats.bnr++;
+	if (status & ATH9K_INT_CST)
+		sc->sc_debug.stats.istats.cst++;
+	if (status & ATH9K_INT_GTT)
+		sc->sc_debug.stats.istats.gtt++;
+	if (status & ATH9K_INT_TIM)
+		sc->sc_debug.stats.istats.tim++;
+	if (status & ATH9K_INT_CABEND)
+		sc->sc_debug.stats.istats.cabend++;
+	if (status & ATH9K_INT_DTIMSYNC)
+		sc->sc_debug.stats.istats.dtimsync++;
+	if (status & ATH9K_INT_DTIM)
+		sc->sc_debug.stats.istats.dtim++;
+}
+
+static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[512];
+	unsigned int len = 0;
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "RX", sc->sc_debug.stats.istats.rxok);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "RXEOL", sc->sc_debug.stats.istats.rxeol);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "RXORN", sc->sc_debug.stats.istats.rxorn);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "TX", sc->sc_debug.stats.istats.txok);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "TXURN", sc->sc_debug.stats.istats.txurn);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "MIB", sc->sc_debug.stats.istats.mib);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "RXPHY", sc->sc_debug.stats.istats.rxphyerr);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "RXKCM", sc->sc_debug.stats.istats.rx_keycache_miss);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "SWBA", sc->sc_debug.stats.istats.swba);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "BMISS", sc->sc_debug.stats.istats.bmiss);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "BNR", sc->sc_debug.stats.istats.bnr);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "CST", sc->sc_debug.stats.istats.cst);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "GTT", sc->sc_debug.stats.istats.gtt);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "TIM", sc->sc_debug.stats.istats.tim);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "CABEND", sc->sc_debug.stats.istats.cabend);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "DTIMSYNC", sc->sc_debug.stats.istats.dtimsync);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "DTIM", sc->sc_debug.stats.istats.dtim);
+	len += snprintf(buf + len, sizeof(buf) - len,
+		"%8s: %10u\n", "TOTAL", sc->sc_debug.stats.istats.total);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_interrupt = {
+	.read = read_file_interrupt,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE
+};
+
+int ath9k_init_debug(struct ath_softc *sc)
+{
+	sc->sc_debug.debug_mask = ath9k_debug;
+
+	sc->sc_debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	if (!sc->sc_debug.debugfs_root)
+		goto err;
+
+	sc->sc_debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
+						      sc->sc_debug.debugfs_root);
+	if (!sc->sc_debug.debugfs_phy)
+		goto err;
+
+	sc->sc_debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
+				       sc->sc_debug.debugfs_phy, sc, &fops_dma);
+	if (!sc->sc_debug.debugfs_dma)
+		goto err;
+
+	sc->sc_debug.debugfs_interrupt = debugfs_create_file("interrupt",
+						     S_IRUGO,
+						     sc->sc_debug.debugfs_phy,
+						     sc, &fops_interrupt);
+	if (!sc->sc_debug.debugfs_interrupt)
+		goto err;
+
+	return 0;
+err:
+	ath9k_exit_debug(sc);
+	return -ENOMEM;
+}
+
+void ath9k_exit_debug(struct ath_softc *sc)
+{
+	debugfs_remove(sc->sc_debug.debugfs_interrupt);
+	debugfs_remove(sc->sc_debug.debugfs_dma);
+	debugfs_remove(sc->sc_debug.debugfs_phy);
+	debugfs_remove(sc->sc_debug.debugfs_root);
+}
diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c
new file mode 100644
index 0000000..acd6c53
--- /dev/null
+++ b/drivers/net/wireless/ath9k/eeprom.c
@@ -0,0 +1,2824 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah,
+				      u32 reg, u32 mask,
+				      u32 shift, u32 val)
+{
+	u32 regVal;
+
+	regVal = REG_READ(ah, reg) & ~mask;
+	regVal |= (val << shift) & mask;
+
+	REG_WRITE(ah, reg, regVal);
+
+	if (ah->ah_config.analog_shiftreg)
+		udelay(100);
+
+	return;
+}
+
+static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
+{
+
+	if (fbin == AR5416_BCHAN_UNUSED)
+		return fbin;
+
+	return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
+}
+
+static inline int16_t ath9k_hw_interpolate(u16 target,
+					   u16 srcLeft, u16 srcRight,
+					   int16_t targetLeft,
+					   int16_t targetRight)
+{
+	int16_t rv;
+
+	if (srcRight == srcLeft) {
+		rv = targetLeft;
+	} else {
+		rv = (int16_t) (((target - srcLeft) * targetRight +
+				 (srcRight - target) * targetLeft) /
+				(srcRight - srcLeft));
+	}
+	return rv;
+}
+
+static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList,
+						  u16 listSize, u16 *indexL,
+						  u16 *indexR)
+{
+	u16 i;
+
+	if (target <= pList[0]) {
+		*indexL = *indexR = 0;
+		return true;
+	}
+	if (target >= pList[listSize - 1]) {
+		*indexL = *indexR = (u16) (listSize - 1);
+		return true;
+	}
+
+	for (i = 0; i < listSize - 1; i++) {
+		if (pList[i] == target) {
+			*indexL = *indexR = i;
+			return true;
+		}
+		if (target < pList[i + 1]) {
+			*indexL = i;
+			*indexR = (u16) (i + 1);
+			return false;
+		}
+	}
+	return false;
+}
+
+static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+	(void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
+
+	if (!ath9k_hw_wait(ah,
+			   AR_EEPROM_STATUS_DATA,
+			   AR_EEPROM_STATUS_DATA_BUSY |
+			   AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
+		return false;
+	}
+
+	*data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
+		   AR_EEPROM_STATUS_DATA_VAL);
+
+	return true;
+}
+
+static int ath9k_hw_flash_map(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX);
+
+	if (!ahp->ah_cal_mem) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"cannot remap eeprom region \n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	*data = ioread16(ahp->ah_cal_mem + off);
+
+	return true;
+}
+
+static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+	if (ath9k_hw_use_flash(ah))
+		return ath9k_hw_flash_read(ah, off, data);
+	else
+		return ath9k_hw_eeprom_read(ah, off, data);
+}
+
+static bool ath9k_hw_fill_4k_eeprom(struct ath_hal *ah)
+{
+#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+	u16 *eep_data;
+	int addr, eep_start_loc = 0;
+
+	eep_start_loc = 64;
+
+	if (!ath9k_hw_use_flash(ah)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"Reading from EEPROM, not flash\n");
+	}
+
+	eep_data = (u16 *)eep;
+
+	for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
+		if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			       "Unable to read eeprom region \n");
+			return false;
+		}
+		eep_data++;
+	}
+	return true;
+#undef SIZE_EEPROM_4K
+}
+
+static bool ath9k_hw_fill_def_eeprom(struct ath_hal *ah)
+{
+#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16))
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+	u16 *eep_data;
+	int addr, ar5416_eep_start_loc = 0x100;
+
+	eep_data = (u16 *)eep;
+
+	for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) {
+		if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
+					 eep_data)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+				"Unable to read eeprom region\n");
+			return false;
+		}
+		eep_data++;
+	}
+	return true;
+#undef SIZE_EEPROM_DEF
+}
+
+static bool (*ath9k_fill_eeprom[]) (struct ath_hal *) = {
+	ath9k_hw_fill_def_eeprom,
+	ath9k_hw_fill_4k_eeprom
+};
+
+static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	return ath9k_fill_eeprom[ahp->ah_eep_map](ah);
+}
+
+static int ath9k_hw_check_def_eeprom(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_def *eep =
+		(struct ar5416_eeprom_def *) &ahp->ah_eeprom.def;
+	u16 *eepdata, temp, magic, magic2;
+	u32 sum = 0, el;
+	bool need_swap = false;
+	int i, addr, size;
+
+	if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
+				 &magic)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"Reading Magic # failed\n");
+		return false;
+	}
+
+	if (!ath9k_hw_use_flash(ah)) {
+
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+				"Read Magic = 0x%04X\n", magic);
+
+		if (magic != AR5416_EEPROM_MAGIC) {
+			magic2 = swab16(magic);
+
+			if (magic2 == AR5416_EEPROM_MAGIC) {
+				size = sizeof(struct ar5416_eeprom_def);
+				need_swap = true;
+				eepdata = (u16 *) (&ahp->ah_eeprom);
+
+				for (addr = 0; addr < size / sizeof(u16); addr++) {
+					temp = swab16(*eepdata);
+					*eepdata = temp;
+					eepdata++;
+
+					DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+						"0x%04X  ", *eepdata);
+
+					if (((addr + 1) % 6) == 0)
+						DPRINTF(ah->ah_sc,
+							ATH_DBG_EEPROM, "\n");
+				}
+			} else {
+				DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+					"Invalid EEPROM Magic. "
+					"endianness mismatch.\n");
+				return -EINVAL;
+			}
+		}
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
+		need_swap ? "True" : "False");
+
+	if (need_swap)
+		el = swab16(ahp->ah_eeprom.def.baseEepHeader.length);
+	else
+		el = ahp->ah_eeprom.def.baseEepHeader.length;
+
+	if (el > sizeof(struct ar5416_eeprom_def))
+		el = sizeof(struct ar5416_eeprom_def) / sizeof(u16);
+	else
+		el = el / sizeof(u16);
+
+	eepdata = (u16 *)(&ahp->ah_eeprom);
+
+	for (i = 0; i < el; i++)
+		sum ^= *eepdata++;
+
+	if (need_swap) {
+		u32 integer, j;
+		u16 word;
+
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"EEPROM Endianness is not native.. Changing \n");
+
+		word = swab16(eep->baseEepHeader.length);
+		eep->baseEepHeader.length = word;
+
+		word = swab16(eep->baseEepHeader.checksum);
+		eep->baseEepHeader.checksum = word;
+
+		word = swab16(eep->baseEepHeader.version);
+		eep->baseEepHeader.version = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[0]);
+		eep->baseEepHeader.regDmn[0] = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[1]);
+		eep->baseEepHeader.regDmn[1] = word;
+
+		word = swab16(eep->baseEepHeader.rfSilent);
+		eep->baseEepHeader.rfSilent = word;
+
+		word = swab16(eep->baseEepHeader.blueToothOptions);
+		eep->baseEepHeader.blueToothOptions = word;
+
+		word = swab16(eep->baseEepHeader.deviceCap);
+		eep->baseEepHeader.deviceCap = word;
+
+		for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
+			struct modal_eep_header *pModal =
+				&eep->modalHeader[j];
+			integer = swab32(pModal->antCtrlCommon);
+			pModal->antCtrlCommon = integer;
+
+			for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+				integer = swab32(pModal->antCtrlChain[i]);
+				pModal->antCtrlChain[i] = integer;
+			}
+
+			for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+				word = swab16(pModal->spurChans[i].spurChan);
+				pModal->spurChans[i].spurChan = word;
+			}
+		}
+	}
+
+	if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER ||
+	    ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+			sum, ar5416_get_eep_ver(ahp));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah)
+{
+#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_4k *eep =
+		(struct ar5416_eeprom_4k *) &ahp->ah_eeprom.map4k;
+	u16 *eepdata, temp, magic, magic2;
+	u32 sum = 0, el;
+	bool need_swap = false;
+	int i, addr;
+
+
+	if (!ath9k_hw_use_flash(ah)) {
+
+		if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
+					 &magic)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+				"Reading Magic # failed\n");
+			return false;
+		}
+
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+				"Read Magic = 0x%04X\n", magic);
+
+		if (magic != AR5416_EEPROM_MAGIC) {
+			magic2 = swab16(magic);
+
+			if (magic2 == AR5416_EEPROM_MAGIC) {
+				need_swap = true;
+				eepdata = (u16 *) (&ahp->ah_eeprom);
+
+				for (addr = 0; addr < EEPROM_4K_SIZE; addr++) {
+					temp = swab16(*eepdata);
+					*eepdata = temp;
+					eepdata++;
+
+					DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+						"0x%04X  ", *eepdata);
+
+					if (((addr + 1) % 6) == 0)
+						DPRINTF(ah->ah_sc,
+							ATH_DBG_EEPROM, "\n");
+				}
+			} else {
+				DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+					"Invalid EEPROM Magic. "
+					"endianness mismatch.\n");
+				return -EINVAL;
+			}
+		}
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
+		need_swap ? "True" : "False");
+
+	if (need_swap)
+		el = swab16(ahp->ah_eeprom.map4k.baseEepHeader.length);
+	else
+		el = ahp->ah_eeprom.map4k.baseEepHeader.length;
+
+	if (el > sizeof(struct ar5416_eeprom_def))
+		el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16);
+	else
+		el = el / sizeof(u16);
+
+	eepdata = (u16 *)(&ahp->ah_eeprom);
+
+	for (i = 0; i < el; i++)
+		sum ^= *eepdata++;
+
+	if (need_swap) {
+		u32 integer;
+		u16 word;
+
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"EEPROM Endianness is not native.. Changing \n");
+
+		word = swab16(eep->baseEepHeader.length);
+		eep->baseEepHeader.length = word;
+
+		word = swab16(eep->baseEepHeader.checksum);
+		eep->baseEepHeader.checksum = word;
+
+		word = swab16(eep->baseEepHeader.version);
+		eep->baseEepHeader.version = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[0]);
+		eep->baseEepHeader.regDmn[0] = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[1]);
+		eep->baseEepHeader.regDmn[1] = word;
+
+		word = swab16(eep->baseEepHeader.rfSilent);
+		eep->baseEepHeader.rfSilent = word;
+
+		word = swab16(eep->baseEepHeader.blueToothOptions);
+		eep->baseEepHeader.blueToothOptions = word;
+
+		word = swab16(eep->baseEepHeader.deviceCap);
+		eep->baseEepHeader.deviceCap = word;
+
+		integer = swab32(eep->modalHeader.antCtrlCommon);
+		eep->modalHeader.antCtrlCommon = integer;
+
+		for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+			integer = swab32(eep->modalHeader.antCtrlChain[i]);
+			eep->modalHeader.antCtrlChain[i] = integer;
+		}
+
+		for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+			word = swab16(eep->modalHeader.spurChans[i].spurChan);
+			eep->modalHeader.spurChans[i].spurChan = word;
+		}
+	}
+
+	if (sum != 0xffff || ar5416_get_eep4k_ver(ahp) != AR5416_EEP_VER ||
+	    ar5416_get_eep4k_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+			sum, ar5416_get_eep4k_ver(ahp));
+		return -EINVAL;
+	}
+
+	return 0;
+#undef EEPROM_4K_SIZE
+}
+
+static int (*ath9k_check_eeprom[]) (struct ath_hal *) = {
+	ath9k_hw_check_def_eeprom,
+	ath9k_hw_check_4k_eeprom
+};
+
+static inline int ath9k_hw_check_eeprom(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	return ath9k_check_eeprom[ahp->ah_eep_map](ah);
+}
+
+static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
+					   u8 *pVpdList, u16 numIntercepts,
+					   u8 *pRetVpdList)
+{
+	u16 i, k;
+	u8 currPwr = pwrMin;
+	u16 idxL = 0, idxR = 0;
+
+	for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
+		ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
+					       numIntercepts, &(idxL),
+					       &(idxR));
+		if (idxR < 1)
+			idxR = 1;
+		if (idxL == numIntercepts - 1)
+			idxL = (u16) (numIntercepts - 2);
+		if (pPwrList[idxL] == pPwrList[idxR])
+			k = pVpdList[idxL];
+		else
+			k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
+				   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
+				  (pPwrList[idxR] - pPwrList[idxL]));
+		pRetVpdList[i] = (u8) k;
+		currPwr += 2;
+	}
+
+	return true;
+}
+
+static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hal *ah,
+				struct ath9k_channel *chan,
+				struct cal_data_per_freq_4k *pRawDataSet,
+				u8 *bChans, u16 availPiers,
+				u16 tPdGainOverlap, int16_t *pMinCalPower,
+				u16 *pPdGainBoundaries, u8 *pPDADCValues,
+				u16 numXpdGains)
+{
+#define TMP_VAL_VPD_TABLE \
+	((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep));
+	int i, j, k;
+	int16_t ss;
+	u16 idxL = 0, idxR = 0, numPiers;
+	static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+	static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+	static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+	u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS];
+	u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS];
+	int16_t vpdStep;
+	int16_t tmpVal;
+	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+	bool match;
+	int16_t minDelta = 0;
+	struct chan_centers centers;
+#define PD_GAIN_BOUNDARY_DEFAULT 58;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	for (numPiers = 0; numPiers < availPiers; numPiers++) {
+		if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+			break;
+	}
+
+	match = ath9k_hw_get_lower_upper_index(
+					(u8)FREQ2FBIN(centers.synth_center,
+					IS_CHAN_2GHZ(chan)), bChans, numPiers,
+					&idxL, &idxR);
+
+	if (match) {
+		for (i = 0; i < numXpdGains; i++) {
+			minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+			maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+					pRawDataSet[idxL].pwrPdg[i],
+					pRawDataSet[idxL].vpdPdg[i],
+					AR5416_EEP4K_PD_GAIN_ICEPTS,
+					vpdTableI[i]);
+		}
+	} else {
+		for (i = 0; i < numXpdGains; i++) {
+			pVpdL = pRawDataSet[idxL].vpdPdg[i];
+			pPwrL = pRawDataSet[idxL].pwrPdg[i];
+			pVpdR = pRawDataSet[idxR].vpdPdg[i];
+			pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+			maxPwrT4[i] =
+				min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1],
+				    pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]);
+
+
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						pPwrL, pVpdL,
+						AR5416_EEP4K_PD_GAIN_ICEPTS,
+						vpdTableL[i]);
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						pPwrR, pVpdR,
+						AR5416_EEP4K_PD_GAIN_ICEPTS,
+						vpdTableR[i]);
+
+			for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+				vpdTableI[i][j] =
+					(u8)(ath9k_hw_interpolate((u16)
+					     FREQ2FBIN(centers.
+						       synth_center,
+						       IS_CHAN_2GHZ
+						       (chan)),
+					     bChans[idxL], bChans[idxR],
+					     vpdTableL[i][j], vpdTableR[i][j]));
+			}
+		}
+	}
+
+	*pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+
+	k = 0;
+
+	for (i = 0; i < numXpdGains; i++) {
+		if (i == (numXpdGains - 1))
+			pPdGainBoundaries[i] =
+				(u16)(maxPwrT4[i] / 2);
+		else
+			pPdGainBoundaries[i] =
+				(u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
+
+		pPdGainBoundaries[i] =
+			min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
+
+		if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
+			minDelta = pPdGainBoundaries[0] - 23;
+			pPdGainBoundaries[0] = 23;
+		} else {
+			minDelta = 0;
+		}
+
+		if (i == 0) {
+			if (AR_SREV_9280_10_OR_LATER(ah))
+				ss = (int16_t)(0 - (minPwrT4[i] / 2));
+			else
+				ss = 0;
+		} else {
+			ss = (int16_t)((pPdGainBoundaries[i - 1] -
+					(minPwrT4[i] / 2)) -
+				       tPdGainOverlap + 1 + minDelta);
+		}
+		vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+		while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+			tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+			pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+			ss++;
+		}
+
+		sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+		tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
+				(minPwrT4[i] / 2));
+		maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+			tgtIndex : sizeCurrVpdTable;
+
+		while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1)))
+			pPDADCValues[k++] = vpdTableI[i][ss++];
+
+		vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+				    vpdTableI[i][sizeCurrVpdTable - 2]);
+		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+		if (tgtIndex > maxIndex) {
+			while ((ss <= tgtIndex) &&
+			       (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+				tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
+				pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+							 255 : tmpVal);
+				ss++;
+			}
+		}
+	}
+
+	while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) {
+		pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT;
+		i++;
+	}
+
+	while (k < AR5416_NUM_PDADC_VALUES) {
+		pPDADCValues[k] = pPDADCValues[k - 1];
+		k++;
+	}
+
+	return;
+#undef TMP_VAL_VPD_TABLE
+}
+
+static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hal *ah,
+				struct ath9k_channel *chan,
+				struct cal_data_per_freq *pRawDataSet,
+				u8 *bChans, u16 availPiers,
+				u16 tPdGainOverlap, int16_t *pMinCalPower,
+				u16 *pPdGainBoundaries, u8 *pPDADCValues,
+				u16 numXpdGains)
+{
+	int i, j, k;
+	int16_t ss;
+	u16 idxL = 0, idxR = 0, numPiers;
+	static u8 vpdTableL[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+	static u8 vpdTableR[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+	static u8 vpdTableI[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+	u8 minPwrT4[AR5416_NUM_PD_GAINS];
+	u8 maxPwrT4[AR5416_NUM_PD_GAINS];
+	int16_t vpdStep;
+	int16_t tmpVal;
+	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+	bool match;
+	int16_t minDelta = 0;
+	struct chan_centers centers;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	for (numPiers = 0; numPiers < availPiers; numPiers++) {
+		if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+			break;
+	}
+
+	match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
+							     IS_CHAN_2GHZ(chan)),
+					       bChans, numPiers, &idxL, &idxR);
+
+	if (match) {
+		for (i = 0; i < numXpdGains; i++) {
+			minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+			maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+					pRawDataSet[idxL].pwrPdg[i],
+					pRawDataSet[idxL].vpdPdg[i],
+					AR5416_PD_GAIN_ICEPTS,
+					vpdTableI[i]);
+		}
+	} else {
+		for (i = 0; i < numXpdGains; i++) {
+			pVpdL = pRawDataSet[idxL].vpdPdg[i];
+			pPwrL = pRawDataSet[idxL].pwrPdg[i];
+			pVpdR = pRawDataSet[idxR].vpdPdg[i];
+			pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+			maxPwrT4[i] =
+				min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
+				    pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
+
+
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						pPwrL, pVpdL,
+						AR5416_PD_GAIN_ICEPTS,
+						vpdTableL[i]);
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						pPwrR, pVpdR,
+						AR5416_PD_GAIN_ICEPTS,
+						vpdTableR[i]);
+
+			for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+				vpdTableI[i][j] =
+					(u8)(ath9k_hw_interpolate((u16)
+					     FREQ2FBIN(centers.
+						       synth_center,
+						       IS_CHAN_2GHZ
+						       (chan)),
+					     bChans[idxL], bChans[idxR],
+					     vpdTableL[i][j], vpdTableR[i][j]));
+			}
+		}
+	}
+
+	*pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+
+	k = 0;
+
+	for (i = 0; i < numXpdGains; i++) {
+		if (i == (numXpdGains - 1))
+			pPdGainBoundaries[i] =
+				(u16)(maxPwrT4[i] / 2);
+		else
+			pPdGainBoundaries[i] =
+				(u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
+
+		pPdGainBoundaries[i] =
+			min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
+
+		if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
+			minDelta = pPdGainBoundaries[0] - 23;
+			pPdGainBoundaries[0] = 23;
+		} else {
+			minDelta = 0;
+		}
+
+		if (i == 0) {
+			if (AR_SREV_9280_10_OR_LATER(ah))
+				ss = (int16_t)(0 - (minPwrT4[i] / 2));
+			else
+				ss = 0;
+		} else {
+			ss = (int16_t)((pPdGainBoundaries[i - 1] -
+					(minPwrT4[i] / 2)) -
+				       tPdGainOverlap + 1 + minDelta);
+		}
+		vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+		while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+			tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+			pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+			ss++;
+		}
+
+		sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+		tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
+				(minPwrT4[i] / 2));
+		maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+			tgtIndex : sizeCurrVpdTable;
+
+		while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+			pPDADCValues[k++] = vpdTableI[i][ss++];
+		}
+
+		vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+				    vpdTableI[i][sizeCurrVpdTable - 2]);
+		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+		if (tgtIndex > maxIndex) {
+			while ((ss <= tgtIndex) &&
+			       (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+				tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
+						    (ss - maxIndex + 1) * vpdStep));
+				pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+							 255 : tmpVal);
+				ss++;
+			}
+		}
+	}
+
+	while (i < AR5416_PD_GAINS_IN_MASK) {
+		pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
+		i++;
+	}
+
+	while (k < AR5416_NUM_PDADC_VALUES) {
+		pPDADCValues[k] = pPDADCValues[k - 1];
+		k++;
+	}
+
+	return;
+}
+
+static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
+				      struct ath9k_channel *chan,
+				      struct cal_target_power_leg *powInfo,
+				      u16 numChannels,
+				      struct cal_target_power_leg *pNewPower,
+				      u16 numRates, bool isExtTarget)
+{
+	struct chan_centers centers;
+	u16 clo, chi;
+	int i;
+	int matchIndex = -1, lowIndex = -1;
+	u16 freq;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
+
+	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
+				       IS_CHAN_2GHZ(chan))) {
+		matchIndex = 0;
+	} else {
+		for (i = 0; (i < numChannels) &&
+			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						       IS_CHAN_2GHZ(chan))) {
+				matchIndex = i;
+				break;
+			} else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						      IS_CHAN_2GHZ(chan))) &&
+				   (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+						      IS_CHAN_2GHZ(chan)))) {
+				lowIndex = i - 1;
+				break;
+			}
+		}
+		if ((matchIndex == -1) && (lowIndex == -1))
+			matchIndex = i - 1;
+	}
+
+	if (matchIndex != -1) {
+		*pNewPower = powInfo[matchIndex];
+	} else {
+		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+					 IS_CHAN_2GHZ(chan));
+		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+					 IS_CHAN_2GHZ(chan));
+
+		for (i = 0; i < numRates; i++) {
+			pNewPower->tPow2x[i] =
+				(u8)ath9k_hw_interpolate(freq, clo, chi,
+						powInfo[lowIndex].tPow2x[i],
+						powInfo[lowIndex + 1].tPow2x[i]);
+		}
+	}
+}
+
+static void ath9k_hw_get_target_powers(struct ath_hal *ah,
+				       struct ath9k_channel *chan,
+				       struct cal_target_power_ht *powInfo,
+				       u16 numChannels,
+				       struct cal_target_power_ht *pNewPower,
+				       u16 numRates, bool isHt40Target)
+{
+	struct chan_centers centers;
+	u16 clo, chi;
+	int i;
+	int matchIndex = -1, lowIndex = -1;
+	u16 freq;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = isHt40Target ? centers.synth_center : centers.ctl_center;
+
+	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
+		matchIndex = 0;
+	} else {
+		for (i = 0; (i < numChannels) &&
+			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						       IS_CHAN_2GHZ(chan))) {
+				matchIndex = i;
+				break;
+			} else
+				if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						       IS_CHAN_2GHZ(chan))) &&
+				    (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+						       IS_CHAN_2GHZ(chan)))) {
+					lowIndex = i - 1;
+					break;
+				}
+		}
+		if ((matchIndex == -1) && (lowIndex == -1))
+			matchIndex = i - 1;
+	}
+
+	if (matchIndex != -1) {
+		*pNewPower = powInfo[matchIndex];
+	} else {
+		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+					 IS_CHAN_2GHZ(chan));
+		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+					 IS_CHAN_2GHZ(chan));
+
+		for (i = 0; i < numRates; i++) {
+			pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
+						clo, chi,
+						powInfo[lowIndex].tPow2x[i],
+						powInfo[lowIndex + 1].tPow2x[i]);
+		}
+	}
+}
+
+static u16 ath9k_hw_get_max_edge_power(u16 freq,
+				       struct cal_ctl_edges *pRdEdgesPower,
+				       bool is2GHz, int num_band_edges)
+{
+	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+	int i;
+
+	for (i = 0; (i < num_band_edges) &&
+		     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+		if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
+			twiceMaxEdgePower = pRdEdgesPower[i].tPower;
+			break;
+		} else if ((i > 0) &&
+			   (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
+						      is2GHz))) {
+			if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
+					       is2GHz) < freq &&
+			    pRdEdgesPower[i - 1].flag) {
+				twiceMaxEdgePower =
+					pRdEdgesPower[i - 1].tPower;
+			}
+			break;
+		}
+	}
+
+	return twiceMaxEdgePower;
+}
+
+static bool ath9k_hw_set_def_power_cal_table(struct ath_hal *ah,
+				  struct ath9k_channel *chan,
+				  int16_t *pTxPowerIndexOffset)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def;
+	struct cal_data_per_freq *pRawDataset;
+	u8 *pCalBChans = NULL;
+	u16 pdGainOverlap_t2;
+	static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+	u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+	u16 numPiers, i, j;
+	int16_t tMinCalPower;
+	u16 numXpdGain, xpdMask;
+	u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
+	u32 reg32, regOffset, regChainOffset;
+	int16_t modalIdx;
+
+	modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
+	xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		pdGainOverlap_t2 =
+			pEepData->modalHeader[modalIdx].pdGainOverlap;
+	} else {
+		pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+					    AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+	}
+
+	if (IS_CHAN_2GHZ(chan)) {
+		pCalBChans = pEepData->calFreqPier2G;
+		numPiers = AR5416_NUM_2G_CAL_PIERS;
+	} else {
+		pCalBChans = pEepData->calFreqPier5G;
+		numPiers = AR5416_NUM_5G_CAL_PIERS;
+	}
+
+	numXpdGain = 0;
+
+	for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+		if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+			if (numXpdGain >= AR5416_NUM_PD_GAINS)
+				break;
+			xpdGainValues[numXpdGain] =
+				(u16)(AR5416_PD_GAINS_IN_MASK - i);
+			numXpdGain++;
+		}
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+		      (numXpdGain - 1) & 0x3);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+		      xpdGainValues[0]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+		      xpdGainValues[1]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+		      xpdGainValues[2]);
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		if (AR_SREV_5416_V20_OR_LATER(ah) &&
+		    (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) &&
+		    (i != 0)) {
+			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+		} else
+			regChainOffset = i * 0x1000;
+
+		if (pEepData->baseEepHeader.txMask & (1 << i)) {
+			if (IS_CHAN_2GHZ(chan))
+				pRawDataset = pEepData->calPierData2G[i];
+			else
+				pRawDataset = pEepData->calPierData5G[i];
+
+			ath9k_hw_get_def_gain_boundaries_pdadcs(ah, chan,
+					    pRawDataset, pCalBChans,
+					    numPiers, pdGainOverlap_t2,
+					    &tMinCalPower, gainBoundaries,
+					    pdadcValues, numXpdGain);
+
+			if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+				REG_WRITE(ah,
+					  AR_PHY_TPCRG5 + regChainOffset,
+					  SM(pdGainOverlap_t2,
+					     AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+					  | SM(gainBoundaries[0],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+					  | SM(gainBoundaries[1],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+					  | SM(gainBoundaries[2],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+					  | SM(gainBoundaries[3],
+				       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+			}
+
+			regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
+			for (j = 0; j < 32; j++) {
+				reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
+					((pdadcValues[4 * j + 1] & 0xFF) << 8) |
+					((pdadcValues[4 * j + 2] & 0xFF) << 16)|
+					((pdadcValues[4 * j + 3] & 0xFF) << 24);
+				REG_WRITE(ah, regOffset, reg32);
+
+				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+					"PDADC (%d,%4x): %4.4x %8.8x\n",
+					i, regChainOffset, regOffset,
+					reg32);
+				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+					"PDADC: Chain %d | PDADC %3d "
+					"Value %3d | PDADC %3d Value %3d | "
+					"PDADC %3d Value %3d | PDADC %3d "
+					"Value %3d |\n",
+					i, 4 * j, pdadcValues[4 * j],
+					4 * j + 1, pdadcValues[4 * j + 1],
+					4 * j + 2, pdadcValues[4 * j + 2],
+					4 * j + 3,
+					pdadcValues[4 * j + 3]);
+
+				regOffset += 4;
+			}
+		}
+	}
+
+	*pTxPowerIndexOffset = 0;
+
+	return true;
+}
+
+static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah,
+				  struct ath9k_channel *chan,
+				  int16_t *pTxPowerIndexOffset)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k;
+	struct cal_data_per_freq_4k *pRawDataset;
+	u8 *pCalBChans = NULL;
+	u16 pdGainOverlap_t2;
+	static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+	u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+	u16 numPiers, i, j;
+	int16_t tMinCalPower;
+	u16 numXpdGain, xpdMask;
+	u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
+	u32 reg32, regOffset, regChainOffset;
+
+	xpdMask = pEepData->modalHeader.xpdGain;
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		pdGainOverlap_t2 =
+			pEepData->modalHeader.pdGainOverlap;
+	} else {
+		pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+					    AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+	}
+
+	pCalBChans = pEepData->calFreqPier2G;
+	numPiers = AR5416_NUM_2G_CAL_PIERS;
+
+	numXpdGain = 0;
+
+	for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+		if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+			if (numXpdGain >= AR5416_NUM_PD_GAINS)
+				break;
+			xpdGainValues[numXpdGain] =
+				(u16)(AR5416_PD_GAINS_IN_MASK - i);
+			numXpdGain++;
+		}
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+		      (numXpdGain - 1) & 0x3);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+		      xpdGainValues[0]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+		      xpdGainValues[1]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+		      xpdGainValues[2]);
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		if (AR_SREV_5416_V20_OR_LATER(ah) &&
+		    (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) &&
+		    (i != 0)) {
+			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+		} else
+			regChainOffset = i * 0x1000;
+
+		if (pEepData->baseEepHeader.txMask & (1 << i)) {
+			pRawDataset = pEepData->calPierData2G[i];
+
+			ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan,
+					    pRawDataset, pCalBChans,
+					    numPiers, pdGainOverlap_t2,
+					    &tMinCalPower, gainBoundaries,
+					    pdadcValues, numXpdGain);
+
+			if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+				REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
+					  SM(pdGainOverlap_t2,
+					     AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+					  | SM(gainBoundaries[0],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+					  | SM(gainBoundaries[1],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+					  | SM(gainBoundaries[2],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+					  | SM(gainBoundaries[3],
+				       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+			}
+
+			regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
+			for (j = 0; j < 32; j++) {
+				reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
+					((pdadcValues[4 * j + 1] & 0xFF) << 8) |
+					((pdadcValues[4 * j + 2] & 0xFF) << 16)|
+					((pdadcValues[4 * j + 3] & 0xFF) << 24);
+				REG_WRITE(ah, regOffset, reg32);
+
+				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+					"PDADC (%d,%4x): %4.4x %8.8x\n",
+					i, regChainOffset, regOffset,
+					reg32);
+				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+					"PDADC: Chain %d | "
+					"PDADC %3d Value %3d | "
+					"PDADC %3d Value %3d | "
+					"PDADC %3d Value %3d | "
+					"PDADC %3d Value %3d |\n",
+					i, 4 * j, pdadcValues[4 * j],
+					4 * j + 1, pdadcValues[4 * j + 1],
+					4 * j + 2, pdadcValues[4 * j + 2],
+					4 * j + 3,
+					pdadcValues[4 * j + 3]);
+
+				regOffset += 4;
+			}
+		}
+	}
+
+	*pTxPowerIndexOffset = 0;
+
+	return true;
+}
+
+static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hal *ah,
+						  struct ath9k_channel *chan,
+						  int16_t *ratesArray,
+						  u16 cfgCtl,
+						  u16 AntennaReduction,
+						  u16 twiceMaxRegulatoryPower,
+						  u16 powerLimit)
+{
+#define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
+#define REDUCE_SCALED_POWER_BY_THREE_CHAIN   10 /* 10*log10(3)*2 */
+
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def;
+	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+	static const u16 tpScaleReductionTable[5] =
+		{ 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+
+	int i;
+	int16_t twiceLargestAntenna;
+	struct cal_ctl_data *rep;
+	struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+		0, { 0, 0, 0, 0}
+	};
+	struct cal_target_power_leg targetPowerOfdmExt = {
+		0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+		0, { 0, 0, 0, 0 }
+	};
+	struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+		0, {0, 0, 0, 0}
+	};
+	u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+	u16 ctlModesFor11a[] =
+		{ CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
+	u16 ctlModesFor11g[] =
+		{ CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
+		  CTL_2GHT40
+		};
+	u16 numCtlModes, *pCtlMode, ctlMode, freq;
+	struct chan_centers centers;
+	int tx_chainmask;
+	u16 twiceMinEdgePower;
+
+	tx_chainmask = ahp->ah_txchainmask;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	twiceLargestAntenna = max(
+		pEepData->modalHeader
+			[IS_CHAN_2GHZ(chan)].antennaGainCh[0],
+		pEepData->modalHeader
+			[IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
+
+	twiceLargestAntenna = max((u8)twiceLargestAntenna,
+				  pEepData->modalHeader
+				  [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
+
+	twiceLargestAntenna = (int16_t)min(AntennaReduction -
+					   twiceLargestAntenna, 0);
+
+	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+	if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
+		maxRegAllowedPower -=
+			(tpScaleReductionTable[(ah->ah_tpScale)] * 2);
+	}
+
+	scaledPower = min(powerLimit, maxRegAllowedPower);
+
+	switch (ar5416_get_ntxchains(tx_chainmask)) {
+	case 1:
+		break;
+	case 2:
+		scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+		break;
+	case 3:
+		scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+		break;
+	}
+
+	scaledPower = max((u16)0, scaledPower);
+
+	if (IS_CHAN_2GHZ(chan)) {
+		numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
+			SUB_NUM_CTL_MODES_AT_2G_40;
+		pCtlMode = ctlModesFor11g;
+
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPowerCck,
+			AR5416_NUM_2G_CCK_TARGET_POWERS,
+			&targetPowerCck, 4, false);
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPower2G,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerOfdm, 4, false);
+		ath9k_hw_get_target_powers(ah, chan,
+			pEepData->calTargetPower2GHT20,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerHt20, 8, false);
+
+		if (IS_CHAN_HT40(chan)) {
+			numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+			ath9k_hw_get_target_powers(ah, chan,
+				pEepData->calTargetPower2GHT40,
+				AR5416_NUM_2G_40_TARGET_POWERS,
+				&targetPowerHt40, 8, true);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPowerCck,
+				AR5416_NUM_2G_CCK_TARGET_POWERS,
+				&targetPowerCckExt, 4, true);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPower2G,
+				AR5416_NUM_2G_20_TARGET_POWERS,
+				&targetPowerOfdmExt, 4, true);
+		}
+	} else {
+		numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
+			SUB_NUM_CTL_MODES_AT_5G_40;
+		pCtlMode = ctlModesFor11a;
+
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPower5G,
+			AR5416_NUM_5G_20_TARGET_POWERS,
+			&targetPowerOfdm, 4, false);
+		ath9k_hw_get_target_powers(ah, chan,
+			pEepData->calTargetPower5GHT20,
+			AR5416_NUM_5G_20_TARGET_POWERS,
+			&targetPowerHt20, 8, false);
+
+		if (IS_CHAN_HT40(chan)) {
+			numCtlModes = ARRAY_SIZE(ctlModesFor11a);
+			ath9k_hw_get_target_powers(ah, chan,
+				pEepData->calTargetPower5GHT40,
+				AR5416_NUM_5G_40_TARGET_POWERS,
+				&targetPowerHt40, 8, true);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPower5G,
+				AR5416_NUM_5G_20_TARGET_POWERS,
+				&targetPowerOfdmExt, 4, true);
+		}
+	}
+
+	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+		bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+			(pCtlMode[ctlMode] == CTL_2GHT40);
+		if (isHt40CtlMode)
+			freq = centers.synth_center;
+		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+			freq = centers.ext_center;
+		else
+			freq = centers.ctl_center;
+
+		if (ar5416_get_eep_ver(ahp) == 14 && ar5416_get_eep_rev(ahp) <= 2)
+			twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+
+		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+			"LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
+			"EXT_ADDITIVE %d\n",
+			ctlMode, numCtlModes, isHt40CtlMode,
+			(pCtlMode[ctlMode] & EXT_ADDITIVE));
+
+		for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
+			DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+				"  LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
+				"pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
+				"chan %d\n",
+				i, cfgCtl, pCtlMode[ctlMode],
+				pEepData->ctlIndex[i], chan->channel);
+
+			if ((((cfgCtl & ~CTL_MODE_M) |
+			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+			     pEepData->ctlIndex[i]) ||
+			    (((cfgCtl & ~CTL_MODE_M) |
+			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+			     ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
+				rep = &(pEepData->ctlData[i]);
+
+				twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
+				rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1],
+				IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
+
+				DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+					"    MATCH-EE_IDX %d: ch %d is2 %d "
+					"2xMinEdge %d chainmask %d chains %d\n",
+					i, freq, IS_CHAN_2GHZ(chan),
+					twiceMinEdgePower, tx_chainmask,
+					ar5416_get_ntxchains
+					(tx_chainmask));
+				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+					twiceMaxEdgePower = min(twiceMaxEdgePower,
+								twiceMinEdgePower);
+				} else {
+					twiceMaxEdgePower = twiceMinEdgePower;
+					break;
+				}
+			}
+		}
+
+		minCtlPower = min(twiceMaxEdgePower, scaledPower);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+			"    SEL-Min ctlMode %d pCtlMode %d "
+			"2xMaxEdge %d sP %d minCtlPwr %d\n",
+			ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+			scaledPower, minCtlPower);
+
+		switch (pCtlMode[ctlMode]) {
+		case CTL_11B:
+			for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+				targetPowerCck.tPow2x[i] =
+					min((u16)targetPowerCck.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11A:
+		case CTL_11G:
+			for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+				targetPowerOfdm.tPow2x[i] =
+					min((u16)targetPowerOfdm.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_5GHT20:
+		case CTL_2GHT20:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+				targetPowerHt20.tPow2x[i] =
+					min((u16)targetPowerHt20.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11B_EXT:
+			targetPowerCckExt.tPow2x[0] = min((u16)
+					targetPowerCckExt.tPow2x[0],
+					minCtlPower);
+			break;
+		case CTL_11A_EXT:
+		case CTL_11G_EXT:
+			targetPowerOfdmExt.tPow2x[0] = min((u16)
+					targetPowerOfdmExt.tPow2x[0],
+					minCtlPower);
+			break;
+		case CTL_5GHT40:
+		case CTL_2GHT40:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+				targetPowerHt40.tPow2x[i] =
+					min((u16)targetPowerHt40.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
+		ratesArray[rate18mb] = ratesArray[rate24mb] =
+		targetPowerOfdm.tPow2x[0];
+	ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+	ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+	ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+	ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+	for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+		ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+	if (IS_CHAN_2GHZ(chan)) {
+		ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+		ratesArray[rate2s] = ratesArray[rate2l] =
+			targetPowerCck.tPow2x[1];
+		ratesArray[rate5_5s] = ratesArray[rate5_5l] =
+			targetPowerCck.tPow2x[2];
+		;
+		ratesArray[rate11s] = ratesArray[rate11l] =
+			targetPowerCck.tPow2x[3];
+		;
+	}
+	if (IS_CHAN_HT40(chan)) {
+		for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+			ratesArray[rateHt40_0 + i] =
+				targetPowerHt40.tPow2x[i];
+		}
+		ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+		if (IS_CHAN_2GHZ(chan)) {
+			ratesArray[rateExtCck] =
+				targetPowerCckExt.tPow2x[0];
+		}
+	}
+	return true;
+}
+
+static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah,
+						 struct ath9k_channel *chan,
+						 int16_t *ratesArray,
+						 u16 cfgCtl,
+						 u16 AntennaReduction,
+						 u16 twiceMaxRegulatoryPower,
+						 u16 powerLimit)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k;
+	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+	static const u16 tpScaleReductionTable[5] =
+		{ 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+
+	int i;
+	int16_t twiceLargestAntenna;
+	struct cal_ctl_data_4k *rep;
+	struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+		0, { 0, 0, 0, 0}
+	};
+	struct cal_target_power_leg targetPowerOfdmExt = {
+		0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+		0, { 0, 0, 0, 0 }
+	};
+	struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+		0, {0, 0, 0, 0}
+	};
+	u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+	u16 ctlModesFor11g[] =
+		{ CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
+		  CTL_2GHT40
+		};
+	u16 numCtlModes, *pCtlMode, ctlMode, freq;
+	struct chan_centers centers;
+	int tx_chainmask;
+	u16 twiceMinEdgePower;
+
+	tx_chainmask = ahp->ah_txchainmask;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0];
+
+	twiceLargestAntenna = (int16_t)min(AntennaReduction -
+					   twiceLargestAntenna, 0);
+
+	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+	if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
+		maxRegAllowedPower -=
+			(tpScaleReductionTable[(ah->ah_tpScale)] * 2);
+	}
+
+	scaledPower = min(powerLimit, maxRegAllowedPower);
+	scaledPower = max((u16)0, scaledPower);
+
+	numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
+	pCtlMode = ctlModesFor11g;
+
+	ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPowerCck,
+			AR5416_NUM_2G_CCK_TARGET_POWERS,
+			&targetPowerCck, 4, false);
+	ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPower2G,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerOfdm, 4, false);
+	ath9k_hw_get_target_powers(ah, chan,
+			pEepData->calTargetPower2GHT20,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerHt20, 8, false);
+
+	if (IS_CHAN_HT40(chan)) {
+		numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+		ath9k_hw_get_target_powers(ah, chan,
+				pEepData->calTargetPower2GHT40,
+				AR5416_NUM_2G_40_TARGET_POWERS,
+				&targetPowerHt40, 8, true);
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPowerCck,
+				AR5416_NUM_2G_CCK_TARGET_POWERS,
+				&targetPowerCckExt, 4, true);
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPower2G,
+				AR5416_NUM_2G_20_TARGET_POWERS,
+				&targetPowerOfdmExt, 4, true);
+	}
+
+	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+		bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+			(pCtlMode[ctlMode] == CTL_2GHT40);
+		if (isHt40CtlMode)
+			freq = centers.synth_center;
+		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+			freq = centers.ext_center;
+		else
+			freq = centers.ctl_center;
+
+		if (ar5416_get_eep_ver(ahp) == 14 &&
+				ar5416_get_eep_rev(ahp) <= 2)
+			twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+
+		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+			"LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
+			"EXT_ADDITIVE %d\n",
+			ctlMode, numCtlModes, isHt40CtlMode,
+			(pCtlMode[ctlMode] & EXT_ADDITIVE));
+
+		for (i = 0; (i < AR5416_NUM_CTLS) &&
+				pEepData->ctlIndex[i]; i++) {
+			DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+				"  LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
+				"pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
+				"chan %d\n",
+				i, cfgCtl, pCtlMode[ctlMode],
+				pEepData->ctlIndex[i], chan->channel);
+
+			if ((((cfgCtl & ~CTL_MODE_M) |
+			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+			     pEepData->ctlIndex[i]) ||
+			    (((cfgCtl & ~CTL_MODE_M) |
+			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+			     ((pEepData->ctlIndex[i] & CTL_MODE_M) |
+			      SD_NO_CTL))) {
+				rep = &(pEepData->ctlData[i]);
+
+				twiceMinEdgePower =
+					ath9k_hw_get_max_edge_power(freq,
+				rep->ctlEdges[ar5416_get_ntxchains
+						(tx_chainmask) - 1],
+				IS_CHAN_2GHZ(chan),
+				AR5416_EEP4K_NUM_BAND_EDGES);
+
+				DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+					"    MATCH-EE_IDX %d: ch %d is2 %d "
+					"2xMinEdge %d chainmask %d chains %d\n",
+					i, freq, IS_CHAN_2GHZ(chan),
+					twiceMinEdgePower, tx_chainmask,
+					ar5416_get_ntxchains
+					(tx_chainmask));
+				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+					twiceMaxEdgePower =
+						min(twiceMaxEdgePower,
+						    twiceMinEdgePower);
+				} else {
+					twiceMaxEdgePower = twiceMinEdgePower;
+					break;
+				}
+			}
+		}
+
+		minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+
+		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+			"    SEL-Min ctlMode %d pCtlMode %d "
+			"2xMaxEdge %d sP %d minCtlPwr %d\n",
+			ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+			scaledPower, minCtlPower);
+
+		switch (pCtlMode[ctlMode]) {
+		case CTL_11B:
+			for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x);
+					i++) {
+				targetPowerCck.tPow2x[i] =
+					min((u16)targetPowerCck.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11G:
+			for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x);
+					i++) {
+				targetPowerOfdm.tPow2x[i] =
+					min((u16)targetPowerOfdm.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_2GHT20:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x);
+					i++) {
+				targetPowerHt20.tPow2x[i] =
+					min((u16)targetPowerHt20.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11B_EXT:
+			targetPowerCckExt.tPow2x[0] = min((u16)
+					targetPowerCckExt.tPow2x[0],
+					minCtlPower);
+			break;
+		case CTL_11G_EXT:
+			targetPowerOfdmExt.tPow2x[0] = min((u16)
+					targetPowerOfdmExt.tPow2x[0],
+					minCtlPower);
+			break;
+		case CTL_2GHT40:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x);
+					i++) {
+				targetPowerHt40.tPow2x[i] =
+					min((u16)targetPowerHt40.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
+		ratesArray[rate18mb] = ratesArray[rate24mb] =
+		targetPowerOfdm.tPow2x[0];
+	ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+	ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+	ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+	ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+	for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+		ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+	ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+	ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1];
+	ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
+	ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3];
+
+	if (IS_CHAN_HT40(chan)) {
+		for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+			ratesArray[rateHt40_0 + i] =
+				targetPowerHt40.tPow2x[i];
+		}
+		ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+		ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
+	}
+	return true;
+}
+
+static int ath9k_hw_def_set_txpower(struct ath_hal *ah,
+			 struct ath9k_channel *chan,
+			 u16 cfgCtl,
+			 u8 twiceAntennaReduction,
+			 u8 twiceMaxRegulatoryPower,
+			 u8 powerLimit)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def;
+	struct modal_eep_header *pModal =
+		&(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
+	int16_t ratesArray[Ar5416RateSize];
+	int16_t txPowerIndexOffset = 0;
+	u8 ht40PowerIncForPdadc = 2;
+	int i;
+
+	memset(ratesArray, 0, sizeof(ratesArray));
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+	}
+
+	if (!ath9k_hw_set_def_power_per_rate_table(ah, chan,
+					       &ratesArray[0], cfgCtl,
+					       twiceAntennaReduction,
+					       twiceMaxRegulatoryPower,
+					       powerLimit)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"ath9k_hw_set_txpower: unable to set "
+			"tx power per rate table\n");
+		return -EIO;
+	}
+
+	if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			 "ath9k_hw_set_txpower: unable to set power table\n");
+		return -EIO;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+		ratesArray[i] =	(int16_t)(txPowerIndexOffset + ratesArray[i]);
+		if (ratesArray[i] > AR5416_MAX_RATE_POWER)
+			ratesArray[i] = AR5416_MAX_RATE_POWER;
+	}
+
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		for (i = 0; i < Ar5416RateSize; i++)
+			ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+		  ATH9K_POW_SM(ratesArray[rate54mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+	if (IS_CHAN_2GHZ(chan)) {
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+			  ATH9K_POW_SM(ratesArray[rate2s], 24)
+			  | ATH9K_POW_SM(ratesArray[rate2l], 16)
+			  | ATH9K_POW_SM(ratesArray[rateXr], 8)
+			  | ATH9K_POW_SM(ratesArray[rate1l], 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+			  ATH9K_POW_SM(ratesArray[rate11s], 24)
+			  | ATH9K_POW_SM(ratesArray[rate11l], 16)
+			  | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+			  | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+		  ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+		  ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+	if (IS_CHAN_HT40(chan)) {
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+			  ATH9K_POW_SM(ratesArray[rateHt40_3] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+					 ht40PowerIncForPdadc, 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+			  ATH9K_POW_SM(ratesArray[rateHt40_7] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+					 ht40PowerIncForPdadc, 0));
+
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+			  ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+			  | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
+		  ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
+		  | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+
+	i = rate6mb;
+
+	if (IS_CHAN_HT40(chan))
+		i = rateHt40_0;
+	else if (IS_CHAN_HT20(chan))
+		i = rateHt20_0;
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		ah->ah_maxPowerLevel =
+			ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+	else
+		ah->ah_maxPowerLevel = ratesArray[i];
+
+	return 0;
+}
+
+static int ath9k_hw_4k_set_txpower(struct ath_hal *ah,
+			 struct ath9k_channel *chan,
+			 u16 cfgCtl,
+			 u8 twiceAntennaReduction,
+			 u8 twiceMaxRegulatoryPower,
+			 u8 powerLimit)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k;
+	struct modal_eep_4k_header *pModal = &pEepData->modalHeader;
+	int16_t ratesArray[Ar5416RateSize];
+	int16_t txPowerIndexOffset = 0;
+	u8 ht40PowerIncForPdadc = 2;
+	int i;
+
+	memset(ratesArray, 0, sizeof(ratesArray));
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+	}
+
+	if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan,
+					       &ratesArray[0], cfgCtl,
+					       twiceAntennaReduction,
+					       twiceMaxRegulatoryPower,
+					       powerLimit)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"ath9k_hw_set_txpower: unable to set "
+			"tx power per rate table\n");
+		return -EIO;
+	}
+
+	if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			 "ath9k_hw_set_txpower: unable to set power table\n");
+		return -EIO;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+		ratesArray[i] =	(int16_t)(txPowerIndexOffset + ratesArray[i]);
+		if (ratesArray[i] > AR5416_MAX_RATE_POWER)
+			ratesArray[i] = AR5416_MAX_RATE_POWER;
+	}
+
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		for (i = 0; i < Ar5416RateSize; i++)
+			ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+		  ATH9K_POW_SM(ratesArray[rate54mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+	if (IS_CHAN_2GHZ(chan)) {
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+			  ATH9K_POW_SM(ratesArray[rate2s], 24)
+			  | ATH9K_POW_SM(ratesArray[rate2l], 16)
+			  | ATH9K_POW_SM(ratesArray[rateXr], 8)
+			  | ATH9K_POW_SM(ratesArray[rate1l], 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+			  ATH9K_POW_SM(ratesArray[rate11s], 24)
+			  | ATH9K_POW_SM(ratesArray[rate11l], 16)
+			  | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+			  | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+		  ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+		  ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+	if (IS_CHAN_HT40(chan)) {
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+			  ATH9K_POW_SM(ratesArray[rateHt40_3] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+					 ht40PowerIncForPdadc, 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+			  ATH9K_POW_SM(ratesArray[rateHt40_7] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+					 ht40PowerIncForPdadc, 0));
+
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+			  ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+			  | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+	}
+
+	i = rate6mb;
+
+	if (IS_CHAN_HT40(chan))
+		i = rateHt40_0;
+	else if (IS_CHAN_HT20(chan))
+		i = rateHt20_0;
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		ah->ah_maxPowerLevel =
+			ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+	else
+		ah->ah_maxPowerLevel = ratesArray[i];
+
+	return 0;
+}
+
+static int (*ath9k_set_txpower[]) (struct ath_hal *,
+				   struct ath9k_channel *,
+				   u16, u8, u8, u8) = {
+	ath9k_hw_def_set_txpower,
+	ath9k_hw_4k_set_txpower
+};
+
+int ath9k_hw_set_txpower(struct ath_hal *ah,
+			 struct ath9k_channel *chan,
+			 u16 cfgCtl,
+			 u8 twiceAntennaReduction,
+			 u8 twiceMaxRegulatoryPower,
+			 u8 powerLimit)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	return ath9k_set_txpower[ahp->ah_eep_map](ah, chan, cfgCtl,
+			twiceAntennaReduction, twiceMaxRegulatoryPower,
+			powerLimit);
+}
+
+static void ath9k_hw_set_def_addac(struct ath_hal *ah,
+				   struct ath9k_channel *chan)
+{
+#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt])
+	struct modal_eep_header *pModal;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+	u8 biaslevel;
+
+	if (ah->ah_macVersion != AR_SREV_VERSION_9160)
+		return;
+
+	if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
+		return;
+
+	pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+	if (pModal->xpaBiasLvl != 0xff) {
+		biaslevel = pModal->xpaBiasLvl;
+	} else {
+		u16 resetFreqBin, freqBin, freqCount = 0;
+		struct chan_centers centers;
+
+		ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+		resetFreqBin = FREQ2FBIN(centers.synth_center,
+					 IS_CHAN_2GHZ(chan));
+		freqBin = XPA_LVL_FREQ(0) & 0xff;
+		biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14);
+
+		freqCount++;
+
+		while (freqCount < 3) {
+			if (XPA_LVL_FREQ(freqCount) == 0x0)
+				break;
+
+			freqBin = XPA_LVL_FREQ(freqCount) & 0xff;
+			if (resetFreqBin >= freqBin)
+				biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14);
+			else
+				break;
+			freqCount++;
+		}
+	}
+
+	if (IS_CHAN_2GHZ(chan)) {
+		INI_RA(&ahp->ah_iniAddac, 7, 1) = (INI_RA(&ahp->ah_iniAddac,
+					7, 1) & (~0x18)) | biaslevel << 3;
+	} else {
+		INI_RA(&ahp->ah_iniAddac, 6, 1) = (INI_RA(&ahp->ah_iniAddac,
+					6, 1) & (~0xc0)) | biaslevel << 6;
+	}
+#undef XPA_LVL_FREQ
+}
+
+static void ath9k_hw_set_4k_addac(struct ath_hal *ah,
+				  struct ath9k_channel *chan)
+{
+	struct modal_eep_4k_header *pModal;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+	u8 biaslevel;
+
+	if (ah->ah_macVersion != AR_SREV_VERSION_9160)
+		return;
+
+	if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
+		return;
+
+	pModal = &eep->modalHeader;
+
+	if (pModal->xpaBiasLvl != 0xff) {
+		biaslevel = pModal->xpaBiasLvl;
+		INI_RA(&ahp->ah_iniAddac, 7, 1) =
+		  (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3;
+	}
+}
+
+static void (*ath9k_set_addac[]) (struct ath_hal *, struct ath9k_channel *) = {
+	ath9k_hw_set_def_addac,
+	ath9k_hw_set_4k_addac
+};
+
+void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	ath9k_set_addac[ahp->ah_eep_map](ah, chan);
+}
+
+
+
+/* XXX: Clean me up, make me more legible */
+static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah,
+				      struct ath9k_channel *chan)
+{
+	struct modal_eep_header *pModal;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+	int i, regChainOffset;
+	u8 txRxAttenLocal;
+	u16 ant_config;
+
+	pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+	txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
+
+	ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config);
+	REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		if (AR_SREV_9280(ah)) {
+			if (i >= 2)
+				break;
+		}
+
+		if (AR_SREV_5416_V20_OR_LATER(ah) &&
+		    (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
+		    && (i != 0))
+			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+		else
+			regChainOffset = i * 0x1000;
+
+		REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+			  pModal->antCtrlChain[i]);
+
+		REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+			  (REG_READ(ah,
+				    AR_PHY_TIMING_CTRL4(0) +
+				    regChainOffset) &
+			   ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+			     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+			  SM(pModal->iqCalICh[i],
+			     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+			  SM(pModal->iqCalQCh[i],
+			     AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+		if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+			if ((eep->baseEepHeader.version &
+			     AR5416_EEP_VER_MINOR_MASK) >=
+			    AR5416_EEP_MINOR_VER_3) {
+				txRxAttenLocal = pModal->txRxAttenCh[i];
+				if (AR_SREV_9280_10_OR_LATER(ah)) {
+					REG_RMW_FIELD(ah,
+						AR_PHY_GAIN_2GHZ +
+						regChainOffset,
+						AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+						pModal->
+						bswMargin[i]);
+					REG_RMW_FIELD(ah,
+						AR_PHY_GAIN_2GHZ +
+						regChainOffset,
+						AR_PHY_GAIN_2GHZ_XATTEN1_DB,
+						pModal->
+						bswAtten[i]);
+					REG_RMW_FIELD(ah,
+						AR_PHY_GAIN_2GHZ +
+						regChainOffset,
+						AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+						pModal->
+						xatten2Margin[i]);
+					REG_RMW_FIELD(ah,
+						AR_PHY_GAIN_2GHZ +
+						regChainOffset,
+						AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+						pModal->
+						xatten2Db[i]);
+				} else {
+					REG_WRITE(ah,
+						  AR_PHY_GAIN_2GHZ +
+						  regChainOffset,
+						  (REG_READ(ah,
+							    AR_PHY_GAIN_2GHZ +
+							    regChainOffset) &
+						   ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
+						  | SM(pModal->
+						  bswMargin[i],
+						  AR_PHY_GAIN_2GHZ_BSW_MARGIN));
+					REG_WRITE(ah,
+						  AR_PHY_GAIN_2GHZ +
+						  regChainOffset,
+						  (REG_READ(ah,
+							    AR_PHY_GAIN_2GHZ +
+							    regChainOffset) &
+						   ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
+						  | SM(pModal->bswAtten[i],
+						  AR_PHY_GAIN_2GHZ_BSW_ATTEN));
+				}
+			}
+			if (AR_SREV_9280_10_OR_LATER(ah)) {
+				REG_RMW_FIELD(ah,
+					      AR_PHY_RXGAIN +
+					      regChainOffset,
+					      AR9280_PHY_RXGAIN_TXRX_ATTEN,
+					      txRxAttenLocal);
+				REG_RMW_FIELD(ah,
+					      AR_PHY_RXGAIN +
+					      regChainOffset,
+					      AR9280_PHY_RXGAIN_TXRX_MARGIN,
+					      pModal->rxTxMarginCh[i]);
+			} else {
+				REG_WRITE(ah,
+					  AR_PHY_RXGAIN + regChainOffset,
+					  (REG_READ(ah,
+						    AR_PHY_RXGAIN +
+						    regChainOffset) &
+					   ~AR_PHY_RXGAIN_TXRX_ATTEN) |
+					  SM(txRxAttenLocal,
+					     AR_PHY_RXGAIN_TXRX_ATTEN));
+				REG_WRITE(ah,
+					  AR_PHY_GAIN_2GHZ +
+					  regChainOffset,
+					  (REG_READ(ah,
+						    AR_PHY_GAIN_2GHZ +
+						    regChainOffset) &
+					   ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
+					  SM(pModal->rxTxMarginCh[i],
+					     AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
+			}
+		}
+	}
+
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		if (IS_CHAN_2GHZ(chan)) {
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+						  AR_AN_RF2G1_CH0_OB,
+						  AR_AN_RF2G1_CH0_OB_S,
+						  pModal->ob);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+						  AR_AN_RF2G1_CH0_DB,
+						  AR_AN_RF2G1_CH0_DB_S,
+						  pModal->db);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+						  AR_AN_RF2G1_CH1_OB,
+						  AR_AN_RF2G1_CH1_OB_S,
+						  pModal->ob_ch1);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+						  AR_AN_RF2G1_CH1_DB,
+						  AR_AN_RF2G1_CH1_DB_S,
+						  pModal->db_ch1);
+		} else {
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+						  AR_AN_RF5G1_CH0_OB5,
+						  AR_AN_RF5G1_CH0_OB5_S,
+						  pModal->ob);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+						  AR_AN_RF5G1_CH0_DB5,
+						  AR_AN_RF5G1_CH0_DB5_S,
+						  pModal->db);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+						  AR_AN_RF5G1_CH1_OB5,
+						  AR_AN_RF5G1_CH1_OB5_S,
+						  pModal->ob_ch1);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+						  AR_AN_RF5G1_CH1_DB5,
+						  AR_AN_RF5G1_CH1_DB5_S,
+						  pModal->db_ch1);
+		}
+		ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+					  AR_AN_TOP2_XPABIAS_LVL,
+					  AR_AN_TOP2_XPABIAS_LVL_S,
+					  pModal->xpaBiasLvl);
+		ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+					  AR_AN_TOP2_LOCALBIAS,
+					  AR_AN_TOP2_LOCALBIAS_S,
+					  pModal->local_bias);
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ForceXPAon: %d\n",
+			pModal->force_xpaon);
+		REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
+			      pModal->force_xpaon);
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+		      pModal->switchSettling);
+	REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+		      pModal->adcDesiredSize);
+
+	if (!AR_SREV_9280_10_OR_LATER(ah))
+		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+			      AR_PHY_DESIRED_SZ_PGA,
+			      pModal->pgaDesiredSize);
+
+	REG_WRITE(ah, AR_PHY_RF_CTL4,
+		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
+		  | SM(pModal->txEndToXpaOff,
+		       AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
+		  | SM(pModal->txFrameToXpaOn,
+		       AR_PHY_RF_CTL4_FRAME_XPAA_ON)
+		  | SM(pModal->txFrameToXpaOn,
+		       AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+	REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+		      pModal->txEndToRxOn);
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+			      pModal->thresh62);
+		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
+			      AR_PHY_EXT_CCA0_THRESH62,
+			      pModal->thresh62);
+	} else {
+		REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
+			      pModal->thresh62);
+		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+			      AR_PHY_EXT_CCA_THRESH62,
+			      pModal->thresh62);
+	}
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+			      AR_PHY_TX_END_DATA_START,
+			      pModal->txFrameToDataStart);
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+			      pModal->txFrameToPaOn);
+	}
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_3) {
+		if (IS_CHAN_HT40(chan))
+			REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+				      AR_PHY_SETTLING_SWITCH,
+				      pModal->swSettleHt40);
+	}
+
+	return true;
+}
+
+static bool ath9k_hw_eeprom_set_4k_board_values(struct ath_hal *ah,
+				      struct ath9k_channel *chan)
+{
+	struct modal_eep_4k_header *pModal;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+	int regChainOffset;
+	u8 txRxAttenLocal;
+	u16 ant_config = 0;
+	u8 ob[5], db1[5], db2[5];
+	u8 ant_div_control1, ant_div_control2;
+	u32 regVal;
+
+
+	pModal = &eep->modalHeader;
+
+	txRxAttenLocal = 23;
+
+	ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config);
+	REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
+
+	regChainOffset = 0;
+	REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+		  pModal->antCtrlChain[0]);
+
+	REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+		 (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) &
+		 ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+		 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+		 SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+		 SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+			AR5416_EEP_MINOR_VER_3) {
+		txRxAttenLocal = pModal->txRxAttenCh[0];
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+			pModal->xatten2Margin[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+			AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+	REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+			AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+
+	if (AR_SREV_9285_11(ah))
+		REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
+
+	/* Initialize Ant Diversity settings from EEPROM */
+	if (pModal->version == 3) {
+		ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf);
+		ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf);
+		regVal = REG_READ(ah, 0x99ac);
+		regVal &= (~(0x7f000000));
+		regVal |= ((ant_div_control1 & 0x1) << 24);
+		regVal |= (((ant_div_control1 >> 1) & 0x1) << 29);
+		regVal |= (((ant_div_control1 >> 2) & 0x1) << 30);
+		regVal |= ((ant_div_control2 & 0x3) << 25);
+		regVal |= (((ant_div_control2 >> 2) & 0x3) << 27);
+		REG_WRITE(ah, 0x99ac, regVal);
+		regVal = REG_READ(ah, 0x99ac);
+		regVal = REG_READ(ah, 0xa208);
+		regVal &= (~(0x1 << 13));
+		regVal |= (((ant_div_control1 >> 3) & 0x1) << 13);
+		REG_WRITE(ah, 0xa208, regVal);
+		regVal = REG_READ(ah, 0xa208);
+	}
+
+	if (pModal->version >= 2) {
+		ob[0] = (pModal->ob_01 & 0xf);
+		ob[1] = (pModal->ob_01 >> 4) & 0xf;
+		ob[2] = (pModal->ob_234 & 0xf);
+		ob[3] = ((pModal->ob_234 >> 4) & 0xf);
+		ob[4] = ((pModal->ob_234 >> 8) & 0xf);
+
+		db1[0] = (pModal->db1_01 & 0xf);
+		db1[1] = ((pModal->db1_01 >> 4) & 0xf);
+		db1[2] = (pModal->db1_234 & 0xf);
+		db1[3] = ((pModal->db1_234 >> 4) & 0xf);
+		db1[4] = ((pModal->db1_234 >> 8) & 0xf);
+
+		db2[0] = (pModal->db2_01 & 0xf);
+		db2[1] = ((pModal->db2_01 >> 4) & 0xf);
+		db2[2] = (pModal->db2_234 & 0xf);
+		db2[3] = ((pModal->db2_234 >> 4) & 0xf);
+		db2[4] = ((pModal->db2_234 >> 8) & 0xf);
+
+	} else if (pModal->version == 1) {
+
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"EEPROM Model version is set to 1 \n");
+		ob[0] = (pModal->ob_01 & 0xf);
+		ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf;
+		db1[0] = (pModal->db1_01 & 0xf);
+		db1[1] = db1[2] = db1[3] =
+			db1[4] = ((pModal->db1_01 >> 4) & 0xf);
+		db2[0] = (pModal->db2_01 & 0xf);
+		db2[1] = db2[2] = db2[3] =
+			db2[4] = ((pModal->db2_01 >> 4) & 0xf);
+	} else {
+		int i;
+		for (i = 0; i < 5; i++) {
+			ob[i] = pModal->ob_01;
+			db1[i] = pModal->db1_01;
+			db2[i] = pModal->db1_01;
+		}
+	}
+
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]);
+
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+			AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]);
+
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]);
+	ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+			AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]);
+
+
+	if (AR_SREV_9285_11(ah))
+		REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
+
+	REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+		      pModal->switchSettling);
+	REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+		      pModal->adcDesiredSize);
+
+	REG_WRITE(ah, AR_PHY_RF_CTL4,
+		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) |
+		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) |
+		  SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)  |
+		  SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+	REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+		      pModal->txEndToRxOn);
+	REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+		      pModal->thresh62);
+	REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62,
+		      pModal->thresh62);
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+						AR5416_EEP_MINOR_VER_2) {
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START,
+			      pModal->txFrameToDataStart);
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+			      pModal->txFrameToPaOn);
+	}
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+						AR5416_EEP_MINOR_VER_3) {
+		if (IS_CHAN_HT40(chan))
+			REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+				      AR_PHY_SETTLING_SWITCH,
+				      pModal->swSettleHt40);
+	}
+
+	return true;
+}
+
+static bool (*ath9k_eeprom_set_board_values[])(struct ath_hal *,
+					       struct ath9k_channel *) = {
+	ath9k_hw_eeprom_set_def_board_values,
+	ath9k_hw_eeprom_set_4k_board_values
+};
+
+bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
+				      struct ath9k_channel *chan)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	return ath9k_eeprom_set_board_values[ahp->ah_eep_map](ah, chan);
+}
+
+static int ath9k_hw_get_def_eeprom_antenna_cfg(struct ath_hal *ah,
+				    struct ath9k_channel *chan,
+				    u8 index, u16 *config)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+	struct modal_eep_header *pModal =
+		&(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+	struct base_eep_header *pBase = &eep->baseEepHeader;
+
+	switch (index) {
+	case 0:
+		*config = pModal->antCtrlCommon & 0xFFFF;
+		return 0;
+	case 1:
+		if (pBase->version >= 0x0E0D) {
+			if (pModal->useAnt1) {
+				*config =
+				((pModal->antCtrlCommon & 0xFFFF0000) >> 16);
+				return 0;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int ath9k_hw_get_4k_eeprom_antenna_cfg(struct ath_hal *ah,
+				    struct ath9k_channel *chan,
+				    u8 index, u16 *config)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+	struct modal_eep_4k_header *pModal = &eep->modalHeader;
+
+	switch (index) {
+	case 0:
+		*config = pModal->antCtrlCommon & 0xFFFF;
+		return 0;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int (*ath9k_get_eeprom_antenna_cfg[])(struct ath_hal *,
+					     struct ath9k_channel *,
+					     u8, u16 *) = {
+	ath9k_hw_get_def_eeprom_antenna_cfg,
+	ath9k_hw_get_4k_eeprom_antenna_cfg
+};
+
+int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah,
+				    struct ath9k_channel *chan,
+				    u8 index, u16 *config)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	return ath9k_get_eeprom_antenna_cfg[ahp->ah_eep_map](ah, chan,
+							     index, config);
+}
+
+static u8 ath9k_hw_get_4k_num_ant_config(struct ath_hal *ah,
+					 enum ieee80211_band freq_band)
+{
+	return 1;
+}
+
+static u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah,
+					  enum ieee80211_band freq_band)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+	struct modal_eep_header *pModal =
+		&(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]);
+	struct base_eep_header *pBase = &eep->baseEepHeader;
+	u8 num_ant_config;
+
+	num_ant_config = 1;
+
+	if (pBase->version >= 0x0E0D)
+		if (pModal->useAnt1)
+			num_ant_config += 1;
+
+	return num_ant_config;
+}
+
+static u8 (*ath9k_get_num_ant_config[])(struct ath_hal *,
+					enum ieee80211_band) = {
+	ath9k_hw_get_def_num_ant_config,
+	ath9k_hw_get_4k_num_ant_config
+};
+
+u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah,
+			       enum ieee80211_band freq_band)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	return ath9k_get_num_ant_config[ahp->ah_eep_map](ah, freq_band);
+}
+
+u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz)
+{
+#define EEP_MAP4K_SPURCHAN \
+	(ahp->ah_eeprom.map4k.modalHeader.spurChans[i].spurChan)
+#define EEP_DEF_SPURCHAN \
+	(ahp->ah_eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan)
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u16 spur_val = AR_NO_SPUR;
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+		"Getting spur idx %d is2Ghz. %d val %x\n",
+		i, is2GHz, ah->ah_config.spurchans[i][is2GHz]);
+
+	switch (ah->ah_config.spurmode) {
+	case SPUR_DISABLE:
+		break;
+	case SPUR_ENABLE_IOCTL:
+		spur_val = ah->ah_config.spurchans[i][is2GHz];
+		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+			"Getting spur val from new loc. %d\n", spur_val);
+		break;
+	case SPUR_ENABLE_EEPROM:
+		if (ahp->ah_eep_map == EEP_MAP_4KBITS)
+			spur_val = EEP_MAP4K_SPURCHAN;
+		else
+			spur_val = EEP_DEF_SPURCHAN;
+		break;
+
+	}
+
+	return spur_val;
+#undef EEP_DEF_SPURCHAN
+#undef EEP_MAP4K_SPURCHAN
+}
+
+static u32 ath9k_hw_get_eeprom_4k(struct ath_hal *ah,
+				  enum eeprom_param param)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+	struct modal_eep_4k_header *pModal = &eep->modalHeader;
+	struct base_eep_header_4k *pBase = &eep->baseEepHeader;
+
+	switch (param) {
+	case EEP_NFTHRESH_2:
+		return pModal[1].noiseFloorThreshCh[0];
+	case AR_EEPROM_MAC(0):
+		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+	case AR_EEPROM_MAC(1):
+		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+	case AR_EEPROM_MAC(2):
+		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+	case EEP_REG_0:
+		return pBase->regDmn[0];
+	case EEP_REG_1:
+		return pBase->regDmn[1];
+	case EEP_OP_CAP:
+		return pBase->deviceCap;
+	case EEP_OP_MODE:
+		return pBase->opCapFlags;
+	case EEP_RF_SILENT:
+		return pBase->rfSilent;
+	case EEP_OB_2:
+		return pModal->ob_01;
+	case EEP_DB_2:
+		return pModal->db1_01;
+	case EEP_MINOR_REV:
+		return pBase->version & AR5416_EEP_VER_MINOR_MASK;
+	case EEP_TX_MASK:
+		return pBase->txMask;
+	case EEP_RX_MASK:
+		return pBase->rxMask;
+	default:
+		return 0;
+	}
+}
+
+static u32 ath9k_hw_get_eeprom_def(struct ath_hal *ah,
+				   enum eeprom_param param)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+	struct modal_eep_header *pModal = eep->modalHeader;
+	struct base_eep_header *pBase = &eep->baseEepHeader;
+
+	switch (param) {
+	case EEP_NFTHRESH_5:
+		return pModal[0].noiseFloorThreshCh[0];
+	case EEP_NFTHRESH_2:
+		return pModal[1].noiseFloorThreshCh[0];
+	case AR_EEPROM_MAC(0):
+		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+	case AR_EEPROM_MAC(1):
+		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+	case AR_EEPROM_MAC(2):
+		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+	case EEP_REG_0:
+		return pBase->regDmn[0];
+	case EEP_REG_1:
+		return pBase->regDmn[1];
+	case EEP_OP_CAP:
+		return pBase->deviceCap;
+	case EEP_OP_MODE:
+		return pBase->opCapFlags;
+	case EEP_RF_SILENT:
+		return pBase->rfSilent;
+	case EEP_OB_5:
+		return pModal[0].ob;
+	case EEP_DB_5:
+		return pModal[0].db;
+	case EEP_OB_2:
+		return pModal[1].ob;
+	case EEP_DB_2:
+		return pModal[1].db;
+	case EEP_MINOR_REV:
+		return pBase->version & AR5416_EEP_VER_MINOR_MASK;
+	case EEP_TX_MASK:
+		return pBase->txMask;
+	case EEP_RX_MASK:
+		return pBase->rxMask;
+	case EEP_RXGAIN_TYPE:
+		return pBase->rxGainType;
+	case EEP_TXGAIN_TYPE:
+		return pBase->txGainType;
+
+	default:
+		return 0;
+	}
+}
+
+static u32 (*ath9k_get_eeprom[])(struct ath_hal *, enum eeprom_param) = {
+	ath9k_hw_get_eeprom_def,
+	ath9k_hw_get_eeprom_4k
+};
+
+u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
+			enum eeprom_param param)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	return ath9k_get_eeprom[ahp->ah_eep_map](ah, param);
+}
+
+int ath9k_hw_eeprom_attach(struct ath_hal *ah)
+{
+	int status;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	if (ath9k_hw_use_flash(ah))
+		ath9k_hw_flash_map(ah);
+
+	if (AR_SREV_9285(ah))
+		ahp->ah_eep_map = EEP_MAP_4KBITS;
+	else
+		ahp->ah_eep_map = EEP_MAP_DEFAULT;
+
+	if (!ath9k_hw_fill_eeprom(ah))
+		return -EIO;
+
+	status = ath9k_hw_check_eeprom(ah);
+
+	return status;
+}
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index 98bc25c..34474ed 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -23,195 +23,78 @@
 #include "phy.h"
 #include "initvals.h"
 
-static void ath9k_hw_iqcal_collect(struct ath_hal *ah);
-static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains);
-static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah);
-static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah,
-					   u8 numChains);
-static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah);
-static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah,
-					 u8 numChains);
-
 static const u8 CLOCK_RATE[] = { 40, 80, 22, 44, 88, 40 };
-static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 };
 
-static const struct hal_percal_data iq_cal_multi_sample = {
-	IQ_MISMATCH_CAL,
-	MAX_CAL_SAMPLES,
-	PER_MIN_LOG_COUNT,
-	ath9k_hw_iqcal_collect,
-	ath9k_hw_iqcalibrate
-};
-static const struct hal_percal_data iq_cal_single_sample = {
-	IQ_MISMATCH_CAL,
-	MIN_CAL_SAMPLES,
-	PER_MAX_LOG_COUNT,
-	ath9k_hw_iqcal_collect,
-	ath9k_hw_iqcalibrate
-};
-static const struct hal_percal_data adc_gain_cal_multi_sample = {
-	ADC_GAIN_CAL,
-	MAX_CAL_SAMPLES,
-	PER_MIN_LOG_COUNT,
-	ath9k_hw_adc_gaincal_collect,
-	ath9k_hw_adc_gaincal_calibrate
-};
-static const struct hal_percal_data adc_gain_cal_single_sample = {
-	ADC_GAIN_CAL,
-	MIN_CAL_SAMPLES,
-	PER_MAX_LOG_COUNT,
-	ath9k_hw_adc_gaincal_collect,
-	ath9k_hw_adc_gaincal_calibrate
-};
-static const struct hal_percal_data adc_dc_cal_multi_sample = {
-	ADC_DC_CAL,
-	MAX_CAL_SAMPLES,
-	PER_MIN_LOG_COUNT,
-	ath9k_hw_adc_dccal_collect,
-	ath9k_hw_adc_dccal_calibrate
-};
-static const struct hal_percal_data adc_dc_cal_single_sample = {
-	ADC_DC_CAL,
-	MIN_CAL_SAMPLES,
-	PER_MAX_LOG_COUNT,
-	ath9k_hw_adc_dccal_collect,
-	ath9k_hw_adc_dccal_calibrate
-};
-static const struct hal_percal_data adc_init_dc_cal = {
-	ADC_DC_INIT_CAL,
-	MIN_CAL_SAMPLES,
-	INIT_LOG_COUNT,
-	ath9k_hw_adc_dccal_collect,
-	ath9k_hw_adc_dccal_calibrate
-};
+extern struct hal_percal_data iq_cal_multi_sample;
+extern struct hal_percal_data iq_cal_single_sample;
+extern struct hal_percal_data adc_gain_cal_multi_sample;
+extern struct hal_percal_data adc_gain_cal_single_sample;
+extern struct hal_percal_data adc_dc_cal_multi_sample;
+extern struct hal_percal_data adc_dc_cal_single_sample;
+extern struct hal_percal_data adc_init_dc_cal;
 
-static struct ath9k_rate_table ar5416_11a_table = {
-	8,
-	{0},
-	{
-		{true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
-		{true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
-		{true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
-		{true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
-		{true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
-		{true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
-		{true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
-		{true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}
-	},
-};
+static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type);
+static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
+			      enum ath9k_ht_macmode macmode);
+static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
+			      struct ar5416_eeprom_def *pEepData,
+			      u32 reg, u32 value);
+static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
+static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
 
-static struct ath9k_rate_table ar5416_11b_table = {
-	4,
-	{0},
-	{
-		{true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
-		{true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
-		{true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1},
-		{true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1}
-	},
-};
+/********************/
+/* Helper Functions */
+/********************/
 
-static struct ath9k_rate_table ar5416_11g_table = {
-	12,
-	{0},
-	{
-		{true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
-		{true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
-		{true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
-		{true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
-
-		{false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
-		{false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
-		{true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
-		{true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
-		{true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
-		{true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
-		{true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
-		{true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}
-	},
-};
-
-static struct ath9k_rate_table ar5416_11ng_table = {
-	28,
-	{0},
-	{
-		{true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
-		{true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
-		{true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
-		{true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
-
-		{false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
-		{false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
-		{true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
-		{true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
-		{true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
-		{true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
-		{true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
-		{true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8},
-		{true, PHY_HT, 6500, 0x80, 0x00, 0, 4},
-		{true, PHY_HT, 13000, 0x81, 0x00, 1, 6},
-		{true, PHY_HT, 19500, 0x82, 0x00, 2, 6},
-		{true, PHY_HT, 26000, 0x83, 0x00, 3, 8},
-		{true, PHY_HT, 39000, 0x84, 0x00, 4, 8},
-		{true, PHY_HT, 52000, 0x85, 0x00, 5, 8},
-		{true, PHY_HT, 58500, 0x86, 0x00, 6, 8},
-		{true, PHY_HT, 65000, 0x87, 0x00, 7, 8},
-		{true, PHY_HT, 13000, 0x88, 0x00, 8, 4},
-		{true, PHY_HT, 26000, 0x89, 0x00, 9, 6},
-		{true, PHY_HT, 39000, 0x8a, 0x00, 10, 6},
-		{true, PHY_HT, 52000, 0x8b, 0x00, 11, 8},
-		{true, PHY_HT, 78000, 0x8c, 0x00, 12, 8},
-		{true, PHY_HT, 104000, 0x8d, 0x00, 13, 8},
-		{true, PHY_HT, 117000, 0x8e, 0x00, 14, 8},
-		{true, PHY_HT, 130000, 0x8f, 0x00, 15, 8},
-	},
-};
-
-static struct ath9k_rate_table ar5416_11na_table = {
-	24,
-	{0},
-	{
-		{true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
-		{true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
-		{true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
-		{true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
-		{true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
-		{true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
-		{true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
-		{true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4},
-		{true, PHY_HT, 6500, 0x80, 0x00, 0, 0},
-		{true, PHY_HT, 13000, 0x81, 0x00, 1, 2},
-		{true, PHY_HT, 19500, 0x82, 0x00, 2, 2},
-		{true, PHY_HT, 26000, 0x83, 0x00, 3, 4},
-		{true, PHY_HT, 39000, 0x84, 0x00, 4, 4},
-		{true, PHY_HT, 52000, 0x85, 0x00, 5, 4},
-		{true, PHY_HT, 58500, 0x86, 0x00, 6, 4},
-		{true, PHY_HT, 65000, 0x87, 0x00, 7, 4},
-		{true, PHY_HT, 13000, 0x88, 0x00, 8, 0},
-		{true, PHY_HT, 26000, 0x89, 0x00, 9, 2},
-		{true, PHY_HT, 39000, 0x8a, 0x00, 10, 2},
-		{true, PHY_HT, 52000, 0x8b, 0x00, 11, 4},
-		{true, PHY_HT, 78000, 0x8c, 0x00, 12, 4},
-		{true, PHY_HT, 104000, 0x8d, 0x00, 13, 4},
-		{true, PHY_HT, 117000, 0x8e, 0x00, 14, 4},
-		{true, PHY_HT, 130000, 0x8f, 0x00, 15, 4},
-	},
-};
-
-static enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
-				       const struct ath9k_channel *chan)
+static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks)
 {
-	if (IS_CHAN_CCK(chan))
-		return ATH9K_MODE_11A;
+	if (ah->ah_curchan != NULL)
+		return clks / CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)];
+	else
+		return clks / CLOCK_RATE[ATH9K_MODE_11B];
+}
+
+static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks)
+{
+	struct ath9k_channel *chan = ah->ah_curchan;
+
+	if (chan && IS_CHAN_HT40(chan))
+		return ath9k_hw_mac_usec(ah, clks) / 2;
+	else
+		return ath9k_hw_mac_usec(ah, clks);
+}
+
+static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs)
+{
+	if (ah->ah_curchan != NULL)
+		return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah,
+			ah->ah_curchan)];
+	else
+		return usecs * CLOCK_RATE[ATH9K_MODE_11B];
+}
+
+static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
+{
+	struct ath9k_channel *chan = ah->ah_curchan;
+
+	if (chan && IS_CHAN_HT40(chan))
+		return ath9k_hw_mac_clks(ah, usecs) * 2;
+	else
+		return ath9k_hw_mac_clks(ah, usecs);
+}
+
+enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
+			       const struct ath9k_channel *chan)
+{
+	if (IS_CHAN_B(chan))
+		return ATH9K_MODE_11B;
 	if (IS_CHAN_G(chan))
 		return ATH9K_MODE_11G;
+
 	return ATH9K_MODE_11A;
 }
 
-static bool ath9k_hw_wait(struct ath_hal *ah,
-			  u32 reg,
-			  u32 mask,
-			  u32 val)
+bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val)
 {
 	int i;
 
@@ -221,81 +104,14 @@
 
 		udelay(AH_TIME_QUANTUM);
 	}
-	DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
-		 "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
-		 __func__, reg, REG_READ(ah, reg), mask, val);
+
+	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+		"timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
+		reg, REG_READ(ah, reg), mask, val);
+
 	return false;
 }
 
-static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off,
-				 u16 *data)
-{
-	(void) REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
-
-	if (!ath9k_hw_wait(ah,
-			   AR_EEPROM_STATUS_DATA,
-			   AR_EEPROM_STATUS_DATA_BUSY |
-			   AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
-		return false;
-	}
-
-	*data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
-		   AR_EEPROM_STATUS_DATA_VAL);
-
-	return true;
-}
-
-static int ath9k_hw_flash_map(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX);
-
-	if (!ahp->ah_cal_mem) {
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			 "%s: cannot remap eeprom region \n", __func__);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off,
-				u16 *data)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	*data = ioread16(ahp->ah_cal_mem + off);
-	return true;
-}
-
-static void ath9k_hw_read_revisions(struct ath_hal *ah)
-{
-	u32 val;
-
-	val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
-
-	if (val == 0xFF) {
-		val = REG_READ(ah, AR_SREV);
-
-		ah->ah_macVersion =
-			(val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
-
-		ah->ah_macRev = MS(val, AR_SREV_REVISION2);
-		ah->ah_isPciExpress =
-			(val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
-
-	} else {
-		if (!AR_SREV_9100(ah))
-			ah->ah_macVersion = MS(val, AR_SREV_VERSION);
-
-		ah->ah_macRev = val & AR_SREV_REVISION;
-
-		if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE)
-			ah->ah_isPciExpress = true;
-	}
-}
-
 u32 ath9k_hw_reverse_bits(u32 val, u32 n)
 {
 	u32 retval;
@@ -308,6 +124,281 @@
 	return retval;
 }
 
+bool ath9k_get_channel_edges(struct ath_hal *ah,
+			     u16 flags, u16 *low,
+			     u16 *high)
+{
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+	if (flags & CHANNEL_5GHZ) {
+		*low = pCap->low_5ghz_chan;
+		*high = pCap->high_5ghz_chan;
+		return true;
+	}
+	if ((flags & CHANNEL_2GHZ)) {
+		*low = pCap->low_2ghz_chan;
+		*high = pCap->high_2ghz_chan;
+		return true;
+	}
+	return false;
+}
+
+u16 ath9k_hw_computetxtime(struct ath_hal *ah,
+			   struct ath_rate_table *rates,
+			   u32 frameLen, u16 rateix,
+			   bool shortPreamble)
+{
+	u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
+	u32 kbps;
+
+	kbps = rates->info[rateix].ratekbps;
+
+	if (kbps == 0)
+		return 0;
+
+	switch (rates->info[rateix].phy) {
+	case WLAN_RC_PHY_CCK:
+		phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
+		if (shortPreamble && rates->info[rateix].short_preamble)
+			phyTime >>= 1;
+		numBits = frameLen << 3;
+		txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps);
+		break;
+	case WLAN_RC_PHY_OFDM:
+		if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
+			bitsPerSymbol =	(kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
+			numBits = OFDM_PLCP_BITS + (frameLen << 3);
+			numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+			txTime = OFDM_SIFS_TIME_QUARTER
+				+ OFDM_PREAMBLE_TIME_QUARTER
+				+ (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
+		} else if (ah->ah_curchan &&
+			   IS_CHAN_HALF_RATE(ah->ah_curchan)) {
+			bitsPerSymbol =	(kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
+			numBits = OFDM_PLCP_BITS + (frameLen << 3);
+			numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+			txTime = OFDM_SIFS_TIME_HALF +
+				OFDM_PREAMBLE_TIME_HALF
+				+ (numSymbols * OFDM_SYMBOL_TIME_HALF);
+		} else {
+			bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000;
+			numBits = OFDM_PLCP_BITS + (frameLen << 3);
+			numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+			txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME
+				+ (numSymbols * OFDM_SYMBOL_TIME);
+		}
+		break;
+	default:
+		DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+			"Unknown phy %u (rate ix %u)\n",
+			rates->info[rateix].phy, rateix);
+		txTime = 0;
+		break;
+	}
+
+	return txTime;
+}
+
+u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags)
+{
+	if (flags & CHANNEL_2GHZ) {
+		if (freq == 2484)
+			return 14;
+		if (freq < 2484)
+			return (freq - 2407) / 5;
+		else
+			return 15 + ((freq - 2512) / 20);
+	} else if (flags & CHANNEL_5GHZ) {
+		if (ath9k_regd_is_public_safety_sku(ah) &&
+		    IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
+			return ((freq * 10) +
+				(((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
+		} else if ((flags & CHANNEL_A) && (freq <= 5000)) {
+			return (freq - 4000) / 5;
+		} else {
+			return (freq - 5000) / 5;
+		}
+	} else {
+		if (freq == 2484)
+			return 14;
+		if (freq < 2484)
+			return (freq - 2407) / 5;
+		if (freq < 5000) {
+			if (ath9k_regd_is_public_safety_sku(ah)
+			    && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
+				return ((freq * 10) +
+					(((freq % 5) ==
+					  2) ? 5 : 0) - 49400) / 5;
+			} else if (freq > 4900) {
+				return (freq - 4000) / 5;
+			} else {
+				return 15 + ((freq - 2512) / 20);
+			}
+		}
+		return (freq - 5000) / 5;
+	}
+}
+
+void ath9k_hw_get_channel_centers(struct ath_hal *ah,
+				  struct ath9k_channel *chan,
+				  struct chan_centers *centers)
+{
+	int8_t extoff;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	if (!IS_CHAN_HT40(chan)) {
+		centers->ctl_center = centers->ext_center =
+			centers->synth_center = chan->channel;
+		return;
+	}
+
+	if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+	    (chan->chanmode == CHANNEL_G_HT40PLUS)) {
+		centers->synth_center =
+			chan->channel + HT40_CHANNEL_CENTER_SHIFT;
+		extoff = 1;
+	} else {
+		centers->synth_center =
+			chan->channel - HT40_CHANNEL_CENTER_SHIFT;
+		extoff = -1;
+	}
+
+	centers->ctl_center =
+		centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT);
+	centers->ext_center =
+		centers->synth_center + (extoff *
+			 ((ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ?
+			  HT40_CHANNEL_CENTER_SHIFT : 15));
+
+}
+
+/******************/
+/* Chip Revisions */
+/******************/
+
+static void ath9k_hw_read_revisions(struct ath_hal *ah)
+{
+	u32 val;
+
+	val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
+
+	if (val == 0xFF) {
+		val = REG_READ(ah, AR_SREV);
+		ah->ah_macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
+		ah->ah_macRev = MS(val, AR_SREV_REVISION2);
+		ah->ah_isPciExpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
+	} else {
+		if (!AR_SREV_9100(ah))
+			ah->ah_macVersion = MS(val, AR_SREV_VERSION);
+
+		ah->ah_macRev = val & AR_SREV_REVISION;
+
+		if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE)
+			ah->ah_isPciExpress = true;
+	}
+}
+
+static int ath9k_hw_get_radiorev(struct ath_hal *ah)
+{
+	u32 val;
+	int i;
+
+	REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
+
+	for (i = 0; i < 8; i++)
+		REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
+	val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
+	val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
+
+	return ath9k_hw_reverse_bits(val, 8);
+}
+
+/************************************/
+/* HW Attach, Detach, Init Routines */
+/************************************/
+
+static void ath9k_hw_disablepcie(struct ath_hal *ah)
+{
+	if (!AR_SREV_9100(ah))
+		return;
+
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
+
+	REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+}
+
+static bool ath9k_hw_chip_test(struct ath_hal *ah)
+{
+	u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) };
+	u32 regHold[2];
+	u32 patternData[4] = { 0x55555555,
+			       0xaaaaaaaa,
+			       0x66666666,
+			       0x99999999 };
+	int i, j;
+
+	for (i = 0; i < 2; i++) {
+		u32 addr = regAddr[i];
+		u32 wrData, rdData;
+
+		regHold[i] = REG_READ(ah, addr);
+		for (j = 0; j < 0x100; j++) {
+			wrData = (j << 16) | j;
+			REG_WRITE(ah, addr, wrData);
+			rdData = REG_READ(ah, addr);
+			if (rdData != wrData) {
+				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+					"address test failed "
+					"addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+					addr, wrData, rdData);
+				return false;
+			}
+		}
+		for (j = 0; j < 4; j++) {
+			wrData = patternData[j];
+			REG_WRITE(ah, addr, wrData);
+			rdData = REG_READ(ah, addr);
+			if (wrData != rdData) {
+				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+					"address test failed "
+					"addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+					addr, wrData, rdData);
+				return false;
+			}
+		}
+		REG_WRITE(ah, regAddr[i], regHold[i]);
+	}
+	udelay(100);
+	return true;
+}
+
+static const char *ath9k_hw_devname(u16 devid)
+{
+	switch (devid) {
+	case AR5416_DEVID_PCI:
+		return "Atheros 5416";
+	case AR5416_DEVID_PCIE:
+		return "Atheros 5418";
+	case AR9160_DEVID_PCI:
+		return "Atheros 9160";
+	case AR9280_DEVID_PCI:
+	case AR9280_DEVID_PCIE:
+		return "Atheros 9280";
+	case AR9285_DEVID_PCIE:
+		return "Atheros 9285";
+	}
+
+	return NULL;
+}
+
 static void ath9k_hw_set_defaults(struct ath_hal *ah)
 {
 	int i;
@@ -345,813 +436,9 @@
 		ah->ah_config.spurchans[i][1] = AR_NO_SPUR;
 	}
 
-	ah->ah_config.intr_mitigation = 0;
+	ah->ah_config.intr_mitigation = 1;
 }
 
-static void ath9k_hw_override_ini(struct ath_hal *ah,
-					 struct ath9k_channel *chan)
-{
-	if (!AR_SREV_5416_V20_OR_LATER(ah)
-	    || AR_SREV_9280_10_OR_LATER(ah))
-		return;
-
-	REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
-}
-
-static void ath9k_hw_init_bb(struct ath_hal *ah,
-			     struct ath9k_channel *chan)
-{
-	u32 synthDelay;
-
-	synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
-	if (IS_CHAN_CCK(chan))
-		synthDelay = (4 * synthDelay) / 22;
-	else
-		synthDelay /= 10;
-
-	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
-
-	udelay(synthDelay + BASE_ACTIVATE_DELAY);
-}
-
-static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
-					  enum ath9k_opmode opmode)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	ahp->ah_maskReg = AR_IMR_TXERR |
-		AR_IMR_TXURN |
-		AR_IMR_RXERR |
-		AR_IMR_RXORN |
-		AR_IMR_BCNMISC;
-
-	if (ahp->ah_intrMitigation)
-		ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
-	else
-		ahp->ah_maskReg |= AR_IMR_RXOK;
-
-	ahp->ah_maskReg |= AR_IMR_TXOK;
-
-	if (opmode == ATH9K_M_HOSTAP)
-		ahp->ah_maskReg |= AR_IMR_MIB;
-
-	REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
-	REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
-
-	if (!AR_SREV_9100(ah)) {
-		REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
-		REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
-		REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
-	}
-}
-
-static void ath9k_hw_init_qos(struct ath_hal *ah)
-{
-	REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
-	REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
-
-	REG_WRITE(ah, AR_QOS_NO_ACK,
-		  SM(2, AR_QOS_NO_ACK_TWO_BIT) |
-		  SM(5, AR_QOS_NO_ACK_BIT_OFF) |
-		  SM(0, AR_QOS_NO_ACK_BYTE_OFF));
-
-	REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);
-	REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);
-	REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
-	REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
-	REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
-}
-
-static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah,
-				      u32 reg,
-				      u32 mask,
-				      u32 shift,
-				      u32 val)
-{
-	u32 regVal;
-
-	regVal = REG_READ(ah, reg) & ~mask;
-	regVal |= (val << shift) & mask;
-
-	REG_WRITE(ah, reg, regVal);
-
-	if (ah->ah_config.analog_shiftreg)
-		udelay(100);
-
-	return;
-}
-
-static u8 ath9k_hw_get_num_ant_config(struct ath_hal_5416 *ahp,
-				      enum ieee80211_band freq_band)
-{
-	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-	struct modal_eep_header *pModal =
-		&(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]);
-	struct base_eep_header *pBase = &eep->baseEepHeader;
-	u8 num_ant_config;
-
-	num_ant_config = 1;
-
-	if (pBase->version >= 0x0E0D)
-		if (pModal->useAnt1)
-			num_ant_config += 1;
-
-	return num_ant_config;
-}
-
-static int
-ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal_5416 *ahp,
-				struct ath9k_channel *chan,
-				u8 index,
-				u16 *config)
-{
-	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-	struct modal_eep_header *pModal =
-		&(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
-	struct base_eep_header *pBase = &eep->baseEepHeader;
-
-	switch (index) {
-	case 0:
-		*config = pModal->antCtrlCommon & 0xFFFF;
-		return 0;
-	case 1:
-		if (pBase->version >= 0x0E0D) {
-			if (pModal->useAnt1) {
-				*config =
-				((pModal->antCtrlCommon & 0xFFFF0000) >> 16);
-				return 0;
-			}
-		}
-		break;
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
-static inline bool ath9k_hw_nvram_read(struct ath_hal *ah,
-				       u32 off,
-				       u16 *data)
-{
-	if (ath9k_hw_use_flash(ah))
-		return ath9k_hw_flash_read(ah, off, data);
-	else
-		return ath9k_hw_eeprom_read(ah, off, data);
-}
-
-static bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-	u16 *eep_data;
-	int addr, ar5416_eep_start_loc = 0;
-
-	if (!ath9k_hw_use_flash(ah)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			 "%s: Reading from EEPROM, not flash\n", __func__);
-		ar5416_eep_start_loc = 256;
-	}
-	if (AR_SREV_9100(ah))
-		ar5416_eep_start_loc = 256;
-
-	eep_data = (u16 *) eep;
-	for (addr = 0;
-	     addr < sizeof(struct ar5416_eeprom) / sizeof(u16);
-	     addr++) {
-		if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
-					 eep_data)) {
-			DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-				 "%s: Unable to read eeprom region \n",
-				 __func__);
-			return false;
-		}
-		eep_data++;
-	}
-	return true;
-}
-
-/* XXX: Clean me up, make me more legible */
-static bool
-ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
-				 struct ath9k_channel *chan)
-{
-	struct modal_eep_header *pModal;
-	int i, regChainOffset;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-	u8 txRxAttenLocal;
-	u16 ant_config;
-
-	pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
-
-	txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
-
-	ath9k_hw_get_eeprom_antenna_cfg(ahp, chan, 1, &ant_config);
-	REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
-
-	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		if (AR_SREV_9280(ah)) {
-			if (i >= 2)
-				break;
-		}
-
-		if (AR_SREV_5416_V20_OR_LATER(ah) &&
-		    (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
-		    && (i != 0))
-			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
-		else
-			regChainOffset = i * 0x1000;
-
-		REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
-			  pModal->antCtrlChain[i]);
-
-		REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
-			  (REG_READ(ah,
-				    AR_PHY_TIMING_CTRL4(0) +
-				    regChainOffset) &
-			   ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
-			     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
-			  SM(pModal->iqCalICh[i],
-			     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
-			  SM(pModal->iqCalQCh[i],
-			     AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
-
-		if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
-			if ((eep->baseEepHeader.version &
-			     AR5416_EEP_VER_MINOR_MASK) >=
-			    AR5416_EEP_MINOR_VER_3) {
-				txRxAttenLocal = pModal->txRxAttenCh[i];
-				if (AR_SREV_9280_10_OR_LATER(ah)) {
-					REG_RMW_FIELD(ah,
-						AR_PHY_GAIN_2GHZ +
-						regChainOffset,
-						AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
-						pModal->
-						bswMargin[i]);
-					REG_RMW_FIELD(ah,
-						AR_PHY_GAIN_2GHZ +
-						regChainOffset,
-						AR_PHY_GAIN_2GHZ_XATTEN1_DB,
-						pModal->
-						bswAtten[i]);
-					REG_RMW_FIELD(ah,
-						AR_PHY_GAIN_2GHZ +
-						regChainOffset,
-						AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
-						pModal->
-						xatten2Margin[i]);
-					REG_RMW_FIELD(ah,
-						AR_PHY_GAIN_2GHZ +
-						regChainOffset,
-						AR_PHY_GAIN_2GHZ_XATTEN2_DB,
-						pModal->
-						xatten2Db[i]);
-				} else {
-					REG_WRITE(ah,
-						  AR_PHY_GAIN_2GHZ +
-						  regChainOffset,
-						  (REG_READ(ah,
-							    AR_PHY_GAIN_2GHZ +
-							    regChainOffset) &
-						   ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
-						  | SM(pModal->
-						  bswMargin[i],
-						  AR_PHY_GAIN_2GHZ_BSW_MARGIN));
-					REG_WRITE(ah,
-						  AR_PHY_GAIN_2GHZ +
-						  regChainOffset,
-						  (REG_READ(ah,
-							    AR_PHY_GAIN_2GHZ +
-							    regChainOffset) &
-						   ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
-						  | SM(pModal->bswAtten[i],
-						  AR_PHY_GAIN_2GHZ_BSW_ATTEN));
-				}
-			}
-			if (AR_SREV_9280_10_OR_LATER(ah)) {
-				REG_RMW_FIELD(ah,
-					      AR_PHY_RXGAIN +
-					      regChainOffset,
-					      AR9280_PHY_RXGAIN_TXRX_ATTEN,
-					      txRxAttenLocal);
-				REG_RMW_FIELD(ah,
-					      AR_PHY_RXGAIN +
-					      regChainOffset,
-					      AR9280_PHY_RXGAIN_TXRX_MARGIN,
-					      pModal->rxTxMarginCh[i]);
-			} else {
-				REG_WRITE(ah,
-					  AR_PHY_RXGAIN + regChainOffset,
-					  (REG_READ(ah,
-						    AR_PHY_RXGAIN +
-						    regChainOffset) &
-					   ~AR_PHY_RXGAIN_TXRX_ATTEN) |
-					  SM(txRxAttenLocal,
-					     AR_PHY_RXGAIN_TXRX_ATTEN));
-				REG_WRITE(ah,
-					  AR_PHY_GAIN_2GHZ +
-					  regChainOffset,
-					  (REG_READ(ah,
-						    AR_PHY_GAIN_2GHZ +
-						    regChainOffset) &
-					   ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
-					  SM(pModal->rxTxMarginCh[i],
-					     AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
-			}
-		}
-	}
-
-	if (AR_SREV_9280_10_OR_LATER(ah)) {
-		if (IS_CHAN_2GHZ(chan)) {
-			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
-						  AR_AN_RF2G1_CH0_OB,
-						  AR_AN_RF2G1_CH0_OB_S,
-						  pModal->ob);
-			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
-						  AR_AN_RF2G1_CH0_DB,
-						  AR_AN_RF2G1_CH0_DB_S,
-						  pModal->db);
-			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
-						  AR_AN_RF2G1_CH1_OB,
-						  AR_AN_RF2G1_CH1_OB_S,
-						  pModal->ob_ch1);
-			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
-						  AR_AN_RF2G1_CH1_DB,
-						  AR_AN_RF2G1_CH1_DB_S,
-						  pModal->db_ch1);
-		} else {
-			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
-						  AR_AN_RF5G1_CH0_OB5,
-						  AR_AN_RF5G1_CH0_OB5_S,
-						  pModal->ob);
-			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
-						  AR_AN_RF5G1_CH0_DB5,
-						  AR_AN_RF5G1_CH0_DB5_S,
-						  pModal->db);
-			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
-						  AR_AN_RF5G1_CH1_OB5,
-						  AR_AN_RF5G1_CH1_OB5_S,
-						  pModal->ob_ch1);
-			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
-						  AR_AN_RF5G1_CH1_DB5,
-						  AR_AN_RF5G1_CH1_DB5_S,
-						  pModal->db_ch1);
-		}
-		ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
-					  AR_AN_TOP2_XPABIAS_LVL,
-					  AR_AN_TOP2_XPABIAS_LVL_S,
-					  pModal->xpaBiasLvl);
-		ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
-					  AR_AN_TOP2_LOCALBIAS,
-					  AR_AN_TOP2_LOCALBIAS_S,
-					  pModal->local_bias);
-		DPRINTF(ah->ah_sc, ATH_DBG_ANY, "ForceXPAon: %d\n",
-			pModal->force_xpaon);
-		REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
-			      pModal->force_xpaon);
-	}
-
-	REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
-		      pModal->switchSettling);
-	REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
-		      pModal->adcDesiredSize);
-
-	if (!AR_SREV_9280_10_OR_LATER(ah))
-		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
-			      AR_PHY_DESIRED_SZ_PGA,
-			      pModal->pgaDesiredSize);
-
-	REG_WRITE(ah, AR_PHY_RF_CTL4,
-		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
-		  | SM(pModal->txEndToXpaOff,
-		       AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
-		  | SM(pModal->txFrameToXpaOn,
-		       AR_PHY_RF_CTL4_FRAME_XPAA_ON)
-		  | SM(pModal->txFrameToXpaOn,
-		       AR_PHY_RF_CTL4_FRAME_XPAB_ON));
-
-	REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
-		      pModal->txEndToRxOn);
-	if (AR_SREV_9280_10_OR_LATER(ah)) {
-		REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
-			      pModal->thresh62);
-		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
-			      AR_PHY_EXT_CCA0_THRESH62,
-			      pModal->thresh62);
-	} else {
-		REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
-			      pModal->thresh62);
-		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
-			      AR_PHY_EXT_CCA_THRESH62,
-			      pModal->thresh62);
-	}
-
-	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
-	    AR5416_EEP_MINOR_VER_2) {
-		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
-			      AR_PHY_TX_END_DATA_START,
-			      pModal->txFrameToDataStart);
-		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
-			      pModal->txFrameToPaOn);
-	}
-
-	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
-	    AR5416_EEP_MINOR_VER_3) {
-		if (IS_CHAN_HT40(chan))
-			REG_RMW_FIELD(ah, AR_PHY_SETTLING,
-				      AR_PHY_SETTLING_SWITCH,
-				      pModal->swSettleHt40);
-	}
-
-	return true;
-}
-
-static int ath9k_hw_check_eeprom(struct ath_hal *ah)
-{
-	u32 sum = 0, el;
-	u16 *eepdata;
-	int i;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	bool need_swap = false;
-	struct ar5416_eeprom *eep =
-		(struct ar5416_eeprom *) &ahp->ah_eeprom;
-
-	if (!ath9k_hw_use_flash(ah)) {
-		u16 magic, magic2;
-		int addr;
-
-		if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
-					&magic)) {
-			DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-				 "%s: Reading Magic # failed\n", __func__);
-			return false;
-		}
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n",
-			 __func__, magic);
-
-		if (magic != AR5416_EEPROM_MAGIC) {
-			magic2 = swab16(magic);
-
-			if (magic2 == AR5416_EEPROM_MAGIC) {
-				need_swap = true;
-				eepdata = (u16 *) (&ahp->ah_eeprom);
-
-				for (addr = 0;
-				     addr <
-					     sizeof(struct ar5416_eeprom) /
-					     sizeof(u16); addr++) {
-					u16 temp;
-
-					temp = swab16(*eepdata);
-					*eepdata = temp;
-					eepdata++;
-
-					DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-						 "0x%04X  ", *eepdata);
-					if (((addr + 1) % 6) == 0)
-						DPRINTF(ah->ah_sc,
-							 ATH_DBG_EEPROM,
-							 "\n");
-				}
-			} else {
-				DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-					 "Invalid EEPROM Magic. "
-					"endianness missmatch.\n");
-				return -EINVAL;
-			}
-		}
-	}
-	DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
-		 need_swap ? "True" : "False");
-
-	if (need_swap)
-		el = swab16(ahp->ah_eeprom.baseEepHeader.length);
-	else
-		el = ahp->ah_eeprom.baseEepHeader.length;
-
-	if (el > sizeof(struct ar5416_eeprom))
-		el = sizeof(struct ar5416_eeprom) / sizeof(u16);
-	else
-		el = el / sizeof(u16);
-
-	eepdata = (u16 *) (&ahp->ah_eeprom);
-
-	for (i = 0; i < el; i++)
-		sum ^= *eepdata++;
-
-	if (need_swap) {
-		u32 integer, j;
-		u16 word;
-
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			 "EEPROM Endianness is not native.. Changing \n");
-
-		word = swab16(eep->baseEepHeader.length);
-		eep->baseEepHeader.length = word;
-
-		word = swab16(eep->baseEepHeader.checksum);
-		eep->baseEepHeader.checksum = word;
-
-		word = swab16(eep->baseEepHeader.version);
-		eep->baseEepHeader.version = word;
-
-		word = swab16(eep->baseEepHeader.regDmn[0]);
-		eep->baseEepHeader.regDmn[0] = word;
-
-		word = swab16(eep->baseEepHeader.regDmn[1]);
-		eep->baseEepHeader.regDmn[1] = word;
-
-		word = swab16(eep->baseEepHeader.rfSilent);
-		eep->baseEepHeader.rfSilent = word;
-
-		word = swab16(eep->baseEepHeader.blueToothOptions);
-		eep->baseEepHeader.blueToothOptions = word;
-
-		word = swab16(eep->baseEepHeader.deviceCap);
-		eep->baseEepHeader.deviceCap = word;
-
-		for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
-			struct modal_eep_header *pModal =
-				&eep->modalHeader[j];
-			integer = swab32(pModal->antCtrlCommon);
-			pModal->antCtrlCommon = integer;
-
-			for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-				integer = swab32(pModal->antCtrlChain[i]);
-				pModal->antCtrlChain[i] = integer;
-			}
-
-			for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
-				word = swab16(pModal->spurChans[i].spurChan);
-				pModal->spurChans[i].spurChan = word;
-			}
-		}
-	}
-
-	if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER ||
-	    ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			 "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
-			 sum, ar5416_get_eep_ver(ahp));
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static bool ath9k_hw_chip_test(struct ath_hal *ah)
-{
-	u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) };
-	u32 regHold[2];
-	u32 patternData[4] = { 0x55555555,
-				     0xaaaaaaaa,
-				     0x66666666,
-				     0x99999999 };
-	int i, j;
-
-	for (i = 0; i < 2; i++) {
-		u32 addr = regAddr[i];
-		u32 wrData, rdData;
-
-		regHold[i] = REG_READ(ah, addr);
-		for (j = 0; j < 0x100; j++) {
-			wrData = (j << 16) | j;
-			REG_WRITE(ah, addr, wrData);
-			rdData = REG_READ(ah, addr);
-			if (rdData != wrData) {
-				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-				 "%s: address test failed "
-				"addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
-				 __func__, addr, wrData, rdData);
-				return false;
-			}
-		}
-		for (j = 0; j < 4; j++) {
-			wrData = patternData[j];
-			REG_WRITE(ah, addr, wrData);
-			rdData = REG_READ(ah, addr);
-			if (wrData != rdData) {
-				DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-				 "%s: address test failed "
-				"addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
-				 __func__, addr, wrData, rdData);
-				return false;
-			}
-		}
-		REG_WRITE(ah, regAddr[i], regHold[i]);
-	}
-	udelay(100);
-	return true;
-}
-
-u32 ath9k_hw_getrxfilter(struct ath_hal *ah)
-{
-	u32 bits = REG_READ(ah, AR_RX_FILTER);
-	u32 phybits = REG_READ(ah, AR_PHY_ERR);
-
-	if (phybits & AR_PHY_ERR_RADAR)
-		bits |= ATH9K_RX_FILTER_PHYRADAR;
-	if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING))
-		bits |= ATH9K_RX_FILTER_PHYERR;
-	return bits;
-}
-
-void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits)
-{
-	u32 phybits;
-
-	REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR);
-	phybits = 0;
-	if (bits & ATH9K_RX_FILTER_PHYRADAR)
-		phybits |= AR_PHY_ERR_RADAR;
-	if (bits & ATH9K_RX_FILTER_PHYERR)
-		phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
-	REG_WRITE(ah, AR_PHY_ERR, phybits);
-
-	if (phybits)
-		REG_WRITE(ah, AR_RXCFG,
-			  REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
-	else
-		REG_WRITE(ah, AR_RXCFG,
-			  REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
-}
-
-bool ath9k_hw_setcapability(struct ath_hal *ah,
-			    enum ath9k_capability_type type,
-			    u32 capability,
-			    u32 setting,
-			    int *status)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	u32 v;
-
-	switch (type) {
-	case ATH9K_CAP_TKIP_MIC:
-		if (setting)
-			ahp->ah_staId1Defaults |=
-				AR_STA_ID1_CRPT_MIC_ENABLE;
-		else
-			ahp->ah_staId1Defaults &=
-				~AR_STA_ID1_CRPT_MIC_ENABLE;
-		return true;
-	case ATH9K_CAP_DIVERSITY:
-		v = REG_READ(ah, AR_PHY_CCK_DETECT);
-		if (setting)
-			v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
-		else
-			v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
-		REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
-		return true;
-	case ATH9K_CAP_MCAST_KEYSRCH:
-		if (setting)
-			ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;
-		else
-			ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;
-		return true;
-	case ATH9K_CAP_TSF_ADJUST:
-		if (setting)
-			ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
-		else
-			ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
-		return true;
-	default:
-		return false;
-	}
-}
-
-void ath9k_hw_dmaRegDump(struct ath_hal *ah)
-{
-	u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
-	int qcuOffset = 0, dcuOffset = 0;
-	u32 *qcuBase = &val[0], *dcuBase = &val[4];
-	int i;
-
-	REG_WRITE(ah, AR_MACMISC,
-		  ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
-		   (AR_MACMISC_MISC_OBS_BUS_1 <<
-		    AR_MACMISC_MISC_OBS_BUS_MSB_S)));
-
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n");
-	for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
-		if (i % 4 == 0)
-			DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
-
-		val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
-		DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]);
-	}
-
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n");
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-		 "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
-
-	for (i = 0; i < ATH9K_NUM_QUEUES;
-	     i++, qcuOffset += 4, dcuOffset += 5) {
-		if (i == 8) {
-			qcuOffset = 0;
-			qcuBase++;
-		}
-
-		if (i == 6) {
-			dcuOffset = 0;
-			dcuBase++;
-		}
-
-		DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-			 "%2d          %2x      %1x     %2x           %2x\n",
-			 i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
-			 (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset +
-							     3),
-			 val[2] & (0x7 << (i * 3)) >> (i * 3),
-			 (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
-	}
-
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-		 "qcu_stitch state:   %2x    qcu_fetch state:        %2x\n",
-		 (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-		 "qcu_complete state: %2x    dcu_complete state:     %2x\n",
-		 (val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-		 "dcu_arb state:      %2x    dcu_fp state:           %2x\n",
-		 (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-		 "chan_idle_dur:     %3d    chan_idle_dur_valid:     %1d\n",
-		 (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-		 "txfifo_valid_0:      %1d    txfifo_valid_1:          %1d\n",
-		 (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-		 "txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
-		 (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
-
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n",
-		REG_READ(ah, AR_OBS_BUS_1));
-	DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-		"AR_CR 0x%x \n", REG_READ(ah, AR_CR));
-}
-
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
-					u32 *rxc_pcnt,
-					u32 *rxf_pcnt,
-					u32 *txf_pcnt)
-{
-	static u32 cycles, rx_clear, rx_frame, tx_frame;
-	u32 good = 1;
-
-	u32 rc = REG_READ(ah, AR_RCCNT);
-	u32 rf = REG_READ(ah, AR_RFCNT);
-	u32 tf = REG_READ(ah, AR_TFCNT);
-	u32 cc = REG_READ(ah, AR_CCCNT);
-
-	if (cycles == 0 || cycles > cc) {
-		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-			 "%s: cycle counter wrap. ExtBusy = 0\n",
-			 __func__);
-		good = 0;
-	} else {
-		u32 cc_d = cc - cycles;
-		u32 rc_d = rc - rx_clear;
-		u32 rf_d = rf - rx_frame;
-		u32 tf_d = tf - tx_frame;
-
-		if (cc_d != 0) {
-			*rxc_pcnt = rc_d * 100 / cc_d;
-			*rxf_pcnt = rf_d * 100 / cc_d;
-			*txf_pcnt = tf_d * 100 / cc_d;
-		} else {
-			good = 0;
-		}
-	}
-
-	cycles = cc;
-	rx_frame = rf;
-	rx_clear = rc;
-	tx_frame = tf;
-
-	return good;
-}
-
-void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode)
-{
-	u32 macmode;
-
-	if (mode == ATH9K_HT_MACMODE_2040 &&
-	    !ah->ah_config.cwm_ignore_extcca)
-		macmode = AR_2040_JOINED_RX_CLEAR;
-	else
-		macmode = 0;
-
-	REG_WRITE(ah, AR_2040_MODE, macmode);
-}
-
-static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah)
-{
-	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
-}
-
-
 static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
 					      struct ath_softc *sc,
 					      void __iomem *mem,
@@ -1165,20 +452,16 @@
 	ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL);
 	if (ahp == NULL) {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			 "%s: cannot allocate memory for state block\n",
-			 __func__);
+			"Cannot allocate memory for state block\n");
 		*status = -ENOMEM;
 		return NULL;
 	}
 
 	ah = &ahp->ah;
-
 	ah->ah_sc = sc;
 	ah->ah_sh = mem;
-
 	ah->ah_magic = AR5416_MAGIC;
 	ah->ah_countryCode = CTRY_DEFAULT;
-
 	ah->ah_devid = devid;
 	ah->ah_subvendorid = 0;
 
@@ -1190,12 +473,10 @@
 
 	ah->ah_powerLimit = MAX_RATE_POWER;
 	ah->ah_tpScale = ATH9K_TP_SCALE_MAX;
-
 	ahp->ah_atimWindow = 0;
 	ahp->ah_diversityControl = ah->ah_config.diversity_control;
 	ahp->ah_antennaSwitchSwap =
 		ah->ah_config.antenna_switch_swap;
-
 	ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
 	ahp->ah_beaconInterval = 100;
 	ahp->ah_enable32kHzClock = DONT_USE_32KHZ;
@@ -1210,163 +491,6 @@
 	return ahp;
 }
 
-static int ath9k_hw_eeprom_attach(struct ath_hal *ah)
-{
-	int status;
-
-	if (ath9k_hw_use_flash(ah))
-		ath9k_hw_flash_map(ah);
-
-	if (!ath9k_hw_fill_eeprom(ah))
-		return -EIO;
-
-	status = ath9k_hw_check_eeprom(ah);
-
-	return status;
-}
-
-u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
-			      enum eeprom_param param)
-{
-	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-	struct modal_eep_header *pModal = eep->modalHeader;
-	struct base_eep_header *pBase = &eep->baseEepHeader;
-
-	switch (param) {
-	case EEP_NFTHRESH_5:
-		return -pModal[0].noiseFloorThreshCh[0];
-	case EEP_NFTHRESH_2:
-		return -pModal[1].noiseFloorThreshCh[0];
-	case AR_EEPROM_MAC(0):
-		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
-	case AR_EEPROM_MAC(1):
-		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
-	case AR_EEPROM_MAC(2):
-		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
-	case EEP_REG_0:
-		return pBase->regDmn[0];
-	case EEP_REG_1:
-		return pBase->regDmn[1];
-	case EEP_OP_CAP:
-		return pBase->deviceCap;
-	case EEP_OP_MODE:
-		return pBase->opCapFlags;
-	case EEP_RF_SILENT:
-		return pBase->rfSilent;
-	case EEP_OB_5:
-		return pModal[0].ob;
-	case EEP_DB_5:
-		return pModal[0].db;
-	case EEP_OB_2:
-		return pModal[1].ob;
-	case EEP_DB_2:
-		return pModal[1].db;
-	case EEP_MINOR_REV:
-		return pBase->version & AR5416_EEP_VER_MINOR_MASK;
-	case EEP_TX_MASK:
-		return pBase->txMask;
-	case EEP_RX_MASK:
-		return pBase->rxMask;
-	default:
-		return 0;
-	}
-}
-
-static int ath9k_hw_get_radiorev(struct ath_hal *ah)
-{
-	u32 val;
-	int i;
-
-	REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
-	for (i = 0; i < 8; i++)
-		REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
-	val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
-	val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
-	return ath9k_hw_reverse_bits(val, 8);
-}
-
-static int ath9k_hw_init_macaddr(struct ath_hal *ah)
-{
-	u32 sum;
-	int i;
-	u16 eeval;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	DECLARE_MAC_BUF(mac);
-
-	sum = 0;
-	for (i = 0; i < 3; i++) {
-		eeval = ath9k_hw_get_eeprom(ahp, AR_EEPROM_MAC(i));
-		sum += eeval;
-		ahp->ah_macaddr[2 * i] = eeval >> 8;
-		ahp->ah_macaddr[2 * i + 1] = eeval & 0xff;
-	}
-	if (sum == 0 || sum == 0xffff * 3) {
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			 "%s: mac address read failed: %s\n", __func__,
-			 print_mac(mac, ahp->ah_macaddr));
-		return -EADDRNOTAVAIL;
-	}
-
-	return 0;
-}
-
-static inline int16_t ath9k_hw_interpolate(u16 target,
-					   u16 srcLeft,
-					   u16 srcRight,
-					   int16_t targetLeft,
-					   int16_t targetRight)
-{
-	int16_t rv;
-
-	if (srcRight == srcLeft) {
-		rv = targetLeft;
-	} else {
-		rv = (int16_t) (((target - srcLeft) * targetRight +
-				 (srcRight - target) * targetLeft) /
-				(srcRight - srcLeft));
-	}
-	return rv;
-}
-
-static inline u16 ath9k_hw_fbin2freq(u8 fbin,
-					   bool is2GHz)
-{
-
-	if (fbin == AR5416_BCHAN_UNUSED)
-		return fbin;
-
-	return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
-}
-
-static u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah,
-					       u16 i,
-					       bool is2GHz)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom *eep =
-		(struct ar5416_eeprom *) &ahp->ah_eeprom;
-	u16 spur_val = AR_NO_SPUR;
-
-	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-		 "Getting spur idx %d is2Ghz. %d val %x\n",
-		 i, is2GHz, ah->ah_config.spurchans[i][is2GHz]);
-
-	switch (ah->ah_config.spurmode) {
-	case SPUR_DISABLE:
-		break;
-	case SPUR_ENABLE_IOCTL:
-		spur_val = ah->ah_config.spurchans[i][is2GHz];
-		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-			 "Getting spur val from new loc. %d\n", spur_val);
-		break;
-	case SPUR_ENABLE_EEPROM:
-		spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan;
-		break;
-
-	}
-	return spur_val;
-}
-
 static int ath9k_hw_rfattach(struct ath_hal *ah)
 {
 	bool rfStatus = false;
@@ -1375,8 +499,7 @@
 	rfStatus = ath9k_hw_init_rf(ah, &ecode);
 	if (!rfStatus) {
 		DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-			 "%s: RF setup failed, status %u\n", __func__,
-			 ecode);
+			"RF setup failed, status %u\n", ecode);
 		return ecode;
 	}
 
@@ -1401,9 +524,9 @@
 		break;
 	default:
 		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-			 "%s: 5G Radio Chip Rev 0x%02X is not "
+			"5G Radio Chip Rev 0x%02X is not "
 			"supported by this driver\n",
-			 __func__, ah->ah_analog5GhzRev);
+			ah->ah_analog5GhzRev);
 		return -EOPNOTSUPP;
 	}
 
@@ -1412,1473 +535,76 @@
 	return 0;
 }
 
-static void ath9k_hw_init_pll(struct ath_hal *ah,
-			      struct ath9k_channel *chan)
+static int ath9k_hw_init_macaddr(struct ath_hal *ah)
 {
-	u32 pll;
-
-	if (AR_SREV_9100(ah)) {
-		if (chan && IS_CHAN_5GHZ(chan))
-			pll = 0x1450;
-		else
-			pll = 0x1458;
-	} else {
-		if (AR_SREV_9280_10_OR_LATER(ah)) {
-			pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
-
-			if (chan && IS_CHAN_HALF_RATE(chan))
-				pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
-			else if (chan && IS_CHAN_QUARTER_RATE(chan))
-				pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
-
-			if (chan && IS_CHAN_5GHZ(chan)) {
-				pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
-
-
-				if (AR_SREV_9280_20(ah)) {
-					if (((chan->channel % 20) == 0)
-					    || ((chan->channel % 10) == 0))
-						pll = 0x2850;
-					else
-						pll = 0x142c;
-				}
-			} else {
-				pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
-			}
-
-		} else if (AR_SREV_9160_10_OR_LATER(ah)) {
-
-			pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
-
-			if (chan && IS_CHAN_HALF_RATE(chan))
-				pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
-			else if (chan && IS_CHAN_QUARTER_RATE(chan))
-				pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
-
-			if (chan && IS_CHAN_5GHZ(chan))
-				pll |= SM(0x50, AR_RTC_9160_PLL_DIV);
-			else
-				pll |= SM(0x58, AR_RTC_9160_PLL_DIV);
-		} else {
-			pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
-
-			if (chan && IS_CHAN_HALF_RATE(chan))
-				pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
-			else if (chan && IS_CHAN_QUARTER_RATE(chan))
-				pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
-
-			if (chan && IS_CHAN_5GHZ(chan))
-				pll |= SM(0xa, AR_RTC_PLL_DIV);
-			else
-				pll |= SM(0xb, AR_RTC_PLL_DIV);
-		}
-	}
-	REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll);
-
-	udelay(RTC_PLL_SETTLE_DELAY);
-
-	REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
-}
-
-static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
-			      enum ath9k_ht_macmode macmode)
-{
-	u32 phymode;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
-		| AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH;
-
-	if (IS_CHAN_HT40(chan)) {
-		phymode |= AR_PHY_FC_DYN2040_EN;
-
-		if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
-		    (chan->chanmode == CHANNEL_G_HT40PLUS))
-			phymode |= AR_PHY_FC_DYN2040_PRI_CH;
-
-		if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
-			phymode |= AR_PHY_FC_DYN2040_EXT_CH;
-	}
-	REG_WRITE(ah, AR_PHY_TURBO, phymode);
-
-	ath9k_hw_set11nmac2040(ah, macmode);
-
-	REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
-	REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
-}
-
-static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode)
-{
-	u32 val;
-
-	val = REG_READ(ah, AR_STA_ID1);
-	val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);
-	switch (opmode) {
-	case ATH9K_M_HOSTAP:
-		REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP
-			  | AR_STA_ID1_KSRCH_MODE);
-		REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
-		break;
-	case ATH9K_M_IBSS:
-		REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC
-			  | AR_STA_ID1_KSRCH_MODE);
-		REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
-		break;
-	case ATH9K_M_STA:
-	case ATH9K_M_MONITOR:
-		REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
-		break;
-	}
-}
-
-static void
-ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan)
-{
-	u32 rfMode = 0;
-
-	if (chan == NULL)
-		return;
-
-	rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
-		? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
-
-	if (!AR_SREV_9280_10_OR_LATER(ah))
-		rfMode |= (IS_CHAN_5GHZ(chan)) ? AR_PHY_MODE_RF5GHZ :
-			AR_PHY_MODE_RF2GHZ;
-
-	if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan))
-		rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
-
-	REG_WRITE(ah, AR_PHY_MODE, rfMode);
-}
-
-static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
-{
-	u32 rst_flags;
-	u32 tmpReg;
-
-	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
-		  AR_RTC_FORCE_WAKE_ON_INT);
-
-	if (AR_SREV_9100(ah)) {
-		rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD |
-			AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;
-	} else {
-		tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE);
-		if (tmpReg &
-		    (AR_INTR_SYNC_LOCAL_TIMEOUT |
-		     AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
-			REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
-			REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
-		} else {
-			REG_WRITE(ah, AR_RC, AR_RC_AHB);
-		}
-
-		rst_flags = AR_RTC_RC_MAC_WARM;
-		if (type == ATH9K_RESET_COLD)
-			rst_flags |= AR_RTC_RC_MAC_COLD;
-	}
-
-	REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags);
-	udelay(50);
-
-	REG_WRITE(ah, (u16) (AR_RTC_RC), 0);
-	if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-			"%s: RTC stuck in MAC reset\n",
-			__func__);
-		return false;
-	}
-
-	if (!AR_SREV_9100(ah))
-		REG_WRITE(ah, AR_RC, 0);
-
-	ath9k_hw_init_pll(ah, NULL);
-
-	if (AR_SREV_9100(ah))
-		udelay(50);
-
-	return true;
-}
-
-static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
-{
-	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
-		  AR_RTC_FORCE_WAKE_ON_INT);
-
-	REG_WRITE(ah, (u16) (AR_RTC_RESET), 0);
-	REG_WRITE(ah, (u16) (AR_RTC_RESET), 1);
-
-	if (!ath9k_hw_wait(ah,
-			   AR_RTC_STATUS,
-			   AR_RTC_STATUS_M,
-			   AR_RTC_STATUS_ON)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: RTC not waking up\n",
-			 __func__);
-		return false;
-	}
-
-	ath9k_hw_read_revisions(ah);
-
-	return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM);
-}
-
-static bool ath9k_hw_set_reset_reg(struct ath_hal *ah,
-				   u32 type)
-{
-	REG_WRITE(ah, AR_RTC_FORCE_WAKE,
-		  AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
-
-	switch (type) {
-	case ATH9K_RESET_POWER_ON:
-		return ath9k_hw_set_reset_power_on(ah);
-		break;
-	case ATH9K_RESET_WARM:
-	case ATH9K_RESET_COLD:
-		return ath9k_hw_set_reset(ah, type);
-		break;
-	default:
-		return false;
-	}
-}
-
-static
-struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
-					  struct ath9k_channel *chan)
-{
-	if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) {
-		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-			 "%s: invalid channel %u/0x%x; not marked as "
-			 "2GHz or 5GHz\n", __func__, chan->channel,
-			 chan->channelFlags);
-		return NULL;
-	}
-
-	if (!IS_CHAN_OFDM(chan) &&
-	      !IS_CHAN_CCK(chan) &&
-	      !IS_CHAN_HT20(chan) &&
-	      !IS_CHAN_HT40(chan)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-			"%s: invalid channel %u/0x%x; not marked as "
-			"OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n",
-			__func__, chan->channel, chan->channelFlags);
-		return NULL;
-	}
-
-	return ath9k_regd_check_channel(ah, chan);
-}
-
-static inline bool
-ath9k_hw_get_lower_upper_index(u8 target,
-			       u8 *pList,
-			       u16 listSize,
-			       u16 *indexL,
-			       u16 *indexR)
-{
-	u16 i;
-
-	if (target <= pList[0]) {
-		*indexL = *indexR = 0;
-		return true;
-	}
-	if (target >= pList[listSize - 1]) {
-		*indexL = *indexR = (u16) (listSize - 1);
-		return true;
-	}
-
-	for (i = 0; i < listSize - 1; i++) {
-		if (pList[i] == target) {
-			*indexL = *indexR = i;
-			return true;
-		}
-		if (target < pList[i + 1]) {
-			*indexL = i;
-			*indexR = (u16) (i + 1);
-			return false;
-		}
-	}
-	return false;
-}
-
-static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
-{
-	int16_t nfval;
-	int16_t sort[ATH9K_NF_CAL_HIST_MAX];
-	int i, j;
-
-	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
-		sort[i] = nfCalBuffer[i];
-
-	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
-		for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
-			if (sort[j] > sort[j - 1]) {
-				nfval = sort[j];
-				sort[j] = sort[j - 1];
-				sort[j - 1] = nfval;
-			}
-		}
-	}
-	nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
-
-	return nfval;
-}
-
-static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
-					      int16_t *nfarray)
-{
+	u32 sum;
 	int i;
-
-	for (i = 0; i < NUM_NF_READINGS; i++) {
-		h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
-
-		if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
-			h[i].currIndex = 0;
-
-		if (h[i].invalidNFcount > 0) {
-			if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE
-			    || nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
-				h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
-			} else {
-				h[i].invalidNFcount--;
-				h[i].privNF = nfarray[i];
-			}
-		} else {
-			h[i].privNF =
-				ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
-		}
-	}
-	return;
-}
-
-static void ar5416GetNoiseFloor(struct ath_hal *ah,
-				int16_t nfarray[NUM_NF_READINGS])
-{
-	int16_t nf;
-
-	if (AR_SREV_9280_10_OR_LATER(ah))
-		nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
-	else
-		nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
-
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-		 "NF calibrated [ctl] [chain 0] is %d\n", nf);
-	nfarray[0] = nf;
-
-	if (AR_SREV_9280_10_OR_LATER(ah))
-		nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
-			AR9280_PHY_CH1_MINCCA_PWR);
-	else
-		nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
-			AR_PHY_CH1_MINCCA_PWR);
-
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-		 "NF calibrated [ctl] [chain 1] is %d\n", nf);
-	nfarray[1] = nf;
-
-	if (!AR_SREV_9280(ah)) {
-		nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
-			AR_PHY_CH2_MINCCA_PWR);
-		if (nf & 0x100)
-			nf = 0 - ((nf ^ 0x1ff) + 1);
-		DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-			 "NF calibrated [ctl] [chain 2] is %d\n", nf);
-		nfarray[2] = nf;
-	}
-
-	if (AR_SREV_9280_10_OR_LATER(ah))
-		nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
-			AR9280_PHY_EXT_MINCCA_PWR);
-	else
-		nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
-			AR_PHY_EXT_MINCCA_PWR);
-
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-		 "NF calibrated [ext] [chain 0] is %d\n", nf);
-	nfarray[3] = nf;
-
-	if (AR_SREV_9280_10_OR_LATER(ah))
-		nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
-			AR9280_PHY_CH1_EXT_MINCCA_PWR);
-	else
-		nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
-			AR_PHY_CH1_EXT_MINCCA_PWR);
-
-	if (nf & 0x100)
-		nf = 0 - ((nf ^ 0x1ff) + 1);
-	DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-		 "NF calibrated [ext] [chain 1] is %d\n", nf);
-	nfarray[4] = nf;
-
-	if (!AR_SREV_9280(ah)) {
-		nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
-			AR_PHY_CH2_EXT_MINCCA_PWR);
-		if (nf & 0x100)
-			nf = 0 - ((nf ^ 0x1ff) + 1);
-		DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-			 "NF calibrated [ext] [chain 2] is %d\n", nf);
-		nfarray[5] = nf;
-	}
-}
-
-static bool
-getNoiseFloorThresh(struct ath_hal *ah,
-		    const struct ath9k_channel *chan,
-		    int16_t *nft)
-{
+	u16 eeval;
 	struct ath_hal_5416 *ahp = AH5416(ah);
 
-	switch (chan->chanmode) {
-	case CHANNEL_A:
-	case CHANNEL_A_HT20:
-	case CHANNEL_A_HT40PLUS:
-	case CHANNEL_A_HT40MINUS:
-		*nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_5);
-		break;
-	case CHANNEL_B:
-	case CHANNEL_G:
-	case CHANNEL_G_HT20:
-	case CHANNEL_G_HT40PLUS:
-	case CHANNEL_G_HT40MINUS:
-		*nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_2);
-		break;
-	default:
-		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-			 "%s: invalid channel flags 0x%x\n", __func__,
-			 chan->channelFlags);
-		return false;
+	sum = 0;
+	for (i = 0; i < 3; i++) {
+		eeval = ath9k_hw_get_eeprom(ah, AR_EEPROM_MAC(i));
+		sum += eeval;
+		ahp->ah_macaddr[2 * i] = eeval >> 8;
+		ahp->ah_macaddr[2 * i + 1] = eeval & 0xff;
 	}
-	return true;
-}
-
-static void ath9k_hw_start_nfcal(struct ath_hal *ah)
-{
-	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
-		    AR_PHY_AGC_CONTROL_ENABLE_NF);
-	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
-		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
-	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-}
-
-static void
-ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
-{
-	struct ath9k_nfcal_hist *h;
-	int i, j;
-	int32_t val;
-	const u32 ar5416_cca_regs[6] = {
-		AR_PHY_CCA,
-		AR_PHY_CH1_CCA,
-		AR_PHY_CH2_CCA,
-		AR_PHY_EXT_CCA,
-		AR_PHY_CH1_EXT_CCA,
-		AR_PHY_CH2_EXT_CCA
-	};
-	u8 chainmask;
-
-	if (AR_SREV_9280(ah))
-		chainmask = 0x1B;
-	else
-		chainmask = 0x3F;
-
-#ifdef ATH_NF_PER_CHAN
-	h = chan->nfCalHist;
-#else
-	h = ah->nfCalHist;
-#endif
-
-	for (i = 0; i < NUM_NF_READINGS; i++) {
-		if (chainmask & (1 << i)) {
-			val = REG_READ(ah, ar5416_cca_regs[i]);
-			val &= 0xFFFFFE00;
-			val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
-			REG_WRITE(ah, ar5416_cca_regs[i], val);
-		}
+	if (sum == 0 || sum == 0xffff * 3) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"mac address read failed: %pM\n",
+			ahp->ah_macaddr);
+		return -EADDRNOTAVAIL;
 	}
 
-	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
-		    AR_PHY_AGC_CONTROL_ENABLE_NF);
-	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
-		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
-	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-
-	for (j = 0; j < 1000; j++) {
-		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
-		     AR_PHY_AGC_CONTROL_NF) == 0)
-			break;
-		udelay(10);
-	}
-
-	for (i = 0; i < NUM_NF_READINGS; i++) {
-		if (chainmask & (1 << i)) {
-			val = REG_READ(ah, ar5416_cca_regs[i]);
-			val &= 0xFFFFFE00;
-			val |= (((u32) (-50) << 1) & 0x1ff);
-			REG_WRITE(ah, ar5416_cca_regs[i], val);
-		}
-	}
-}
-
-static int16_t ath9k_hw_getnf(struct ath_hal *ah,
-			      struct ath9k_channel *chan)
-{
-	int16_t nf, nfThresh;
-	int16_t nfarray[NUM_NF_READINGS] = { 0 };
-	struct ath9k_nfcal_hist *h;
-	u8 chainmask;
-
-	if (AR_SREV_9280(ah))
-		chainmask = 0x1B;
-	else
-		chainmask = 0x3F;
-
-	chan->channelFlags &= (~CHANNEL_CW_INT);
-	if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "%s: NF did not complete in calibration window\n",
-			 __func__);
-		nf = 0;
-		chan->rawNoiseFloor = nf;
-		return chan->rawNoiseFloor;
-	} else {
-		ar5416GetNoiseFloor(ah, nfarray);
-		nf = nfarray[0];
-		if (getNoiseFloorThresh(ah, chan, &nfThresh)
-		    && nf > nfThresh) {
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "%s: noise floor failed detected; "
-				 "detected %d, threshold %d\n", __func__,
-				 nf, nfThresh);
-			chan->channelFlags |= CHANNEL_CW_INT;
-		}
-	}
-
-#ifdef ATH_NF_PER_CHAN
-	h = chan->nfCalHist;
-#else
-	h = ah->nfCalHist;
-#endif
-
-	ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
-	chan->rawNoiseFloor = h[0].privNF;
-
-	return chan->rawNoiseFloor;
-}
-
-static void ath9k_hw_update_mibstats(struct ath_hal *ah,
-			      struct ath9k_mib_stats *stats)
-{
-	stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
-	stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
-	stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
-	stats->rts_good += REG_READ(ah, AR_RTS_OK);
-	stats->beacons += REG_READ(ah, AR_BEACON_CNT);
-}
-
-static void ath9k_enable_mib_counters(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable mib counters\n");
-
-	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-
-	REG_WRITE(ah, AR_FILT_OFDM, 0);
-	REG_WRITE(ah, AR_FILT_CCK, 0);
-	REG_WRITE(ah, AR_MIBC,
-		  ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
-		  & 0x0f);
-	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
-	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-}
-
-static void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling MIB counters\n");
-
-	REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
-
-	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-
-	REG_WRITE(ah, AR_FILT_OFDM, 0);
-	REG_WRITE(ah, AR_FILT_CCK, 0);
-}
-
-static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah,
-					struct ath9k_channel *chan)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
-		if (ahp->ah_ani[i].c.channel == chan->channel)
-			return i;
-		if (ahp->ah_ani[i].c.channel == 0) {
-			ahp->ah_ani[i].c.channel = chan->channel;
-			ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
-			return i;
-		}
-	}
-
-	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-		 "No more channel states left. Using channel 0\n");
 	return 0;
 }
 
-static void ath9k_hw_ani_attach(struct ath_hal *ah)
+static void ath9k_hw_init_rxgain_ini(struct ath_hal *ah)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	int i;
-
-	ahp->ah_hasHwPhyCounters = 1;
-
-	memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
-	for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
-		ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
-		ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
-		ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
-		ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
-		ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
-		ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
-		ahp->ah_ani[i].ofdmWeakSigDetectOff =
-			!ATH9K_ANI_USE_OFDM_WEAK_SIG;
-		ahp->ah_ani[i].cckWeakSigThreshold =
-			ATH9K_ANI_CCK_WEAK_SIG_THR;
-		ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
-		ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
-		if (ahp->ah_hasHwPhyCounters) {
-			ahp->ah_ani[i].ofdmPhyErrBase =
-				AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
-			ahp->ah_ani[i].cckPhyErrBase =
-				AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
-		}
-	}
-	if (ahp->ah_hasHwPhyCounters) {
-		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-			"Setting OfdmErrBase = 0x%08x\n",
-			ahp->ah_ani[0].ofdmPhyErrBase);
-		DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
-			ahp->ah_ani[0].cckPhyErrBase);
-
-		REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
-		REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
-		ath9k_enable_mib_counters(ah);
-	}
-	ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
-	if (ah->ah_config.enable_ani)
-		ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
-}
-
-static void ath9k_hw_ani_setup(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	int i;
-
-	const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
-	const int coarseHigh[] = { -14, -14, -14, -14, -12 };
-	const int coarseLow[] = { -64, -64, -64, -64, -70 };
-	const int firpwr[] = { -78, -78, -78, -78, -80 };
-
-	for (i = 0; i < 5; i++) {
-		ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
-		ahp->ah_coarseHigh[i] = coarseHigh[i];
-		ahp->ah_coarseLow[i] = coarseLow[i];
-		ahp->ah_firpwr[i] = firpwr[i];
-	}
-}
-
-static void ath9k_hw_ani_detach(struct ath_hal *ah)
-{
+	u32 rxgain_type;
 	struct ath_hal_5416 *ahp = AH5416(ah);
 
-	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detaching Ani\n");
-	if (ahp->ah_hasHwPhyCounters) {
-		ath9k_hw_disable_mib_counters(ah);
-		REG_WRITE(ah, AR_PHY_ERR_1, 0);
-		REG_WRITE(ah, AR_PHY_ERR_2, 0);
-	}
-}
+	if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) {
+		rxgain_type = ath9k_hw_get_eeprom(ah, EEP_RXGAIN_TYPE);
 
-
-static bool ath9k_hw_ani_control(struct ath_hal *ah,
-				 enum ath9k_ani_cmd cmd, int param)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416AniState *aniState = ahp->ah_curani;
-
-	switch (cmd & ahp->ah_ani_function) {
-	case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
-		u32 level = param;
-
-		if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
-			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-				 "%s: level out of range (%u > %u)\n",
-				 __func__, level,
-				 (unsigned) ARRAY_SIZE(ahp->
-						       ah_totalSizeDesired));
-			return false;
-		}
-
-		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
-			      AR_PHY_DESIRED_SZ_TOT_DES,
-			      ahp->ah_totalSizeDesired[level]);
-		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
-			      AR_PHY_AGC_CTL1_COARSE_LOW,
-			      ahp->ah_coarseLow[level]);
-		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
-			      AR_PHY_AGC_CTL1_COARSE_HIGH,
-			      ahp->ah_coarseHigh[level]);
-		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
-			      AR_PHY_FIND_SIG_FIRPWR,
-			      ahp->ah_firpwr[level]);
-
-		if (level > aniState->noiseImmunityLevel)
-			ahp->ah_stats.ast_ani_niup++;
-		else if (level < aniState->noiseImmunityLevel)
-			ahp->ah_stats.ast_ani_nidown++;
-		aniState->noiseImmunityLevel = level;
-		break;
-	}
-	case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
-		const int m1ThreshLow[] = { 127, 50 };
-		const int m2ThreshLow[] = { 127, 40 };
-		const int m1Thresh[] = { 127, 0x4d };
-		const int m2Thresh[] = { 127, 0x40 };
-		const int m2CountThr[] = { 31, 16 };
-		const int m2CountThrLow[] = { 63, 48 };
-		u32 on = param ? 1 : 0;
-
-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-			      AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
-			      m1ThreshLow[on]);
-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-			      AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
-			      m2ThreshLow[on]);
-		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-			      AR_PHY_SFCORR_M1_THRESH,
-			      m1Thresh[on]);
-		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-			      AR_PHY_SFCORR_M2_THRESH,
-			      m2Thresh[on]);
-		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-			      AR_PHY_SFCORR_M2COUNT_THR,
-			      m2CountThr[on]);
-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-			      AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
-			      m2CountThrLow[on]);
-
-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
-			      m1ThreshLow[on]);
-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
-			      m2ThreshLow[on]);
-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-			      AR_PHY_SFCORR_EXT_M1_THRESH,
-			      m1Thresh[on]);
-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-			      AR_PHY_SFCORR_EXT_M2_THRESH,
-			      m2Thresh[on]);
-
-		if (on)
-			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
-				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+		if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
+			INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+			ar9280Modes_backoff_13db_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6);
+		else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
+			INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+			ar9280Modes_backoff_23db_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6);
 		else
-			REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
-				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
-
-		if (!on != aniState->ofdmWeakSigDetectOff) {
-			if (on)
-				ahp->ah_stats.ast_ani_ofdmon++;
-			else
-				ahp->ah_stats.ast_ani_ofdmoff++;
-			aniState->ofdmWeakSigDetectOff = !on;
-		}
-		break;
-	}
-	case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
-		const int weakSigThrCck[] = { 8, 6 };
-		u32 high = param ? 1 : 0;
-
-		REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
-			      AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
-			      weakSigThrCck[high]);
-		if (high != aniState->cckWeakSigThreshold) {
-			if (high)
-				ahp->ah_stats.ast_ani_cckhigh++;
-			else
-				ahp->ah_stats.ast_ani_ccklow++;
-			aniState->cckWeakSigThreshold = high;
-		}
-		break;
-	}
-	case ATH9K_ANI_FIRSTEP_LEVEL:{
-		const int firstep[] = { 0, 4, 8 };
-		u32 level = param;
-
-		if (level >= ARRAY_SIZE(firstep)) {
-			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-				 "%s: level out of range (%u > %u)\n",
-				 __func__, level,
-				(unsigned) ARRAY_SIZE(firstep));
-			return false;
-		}
-		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
-			      AR_PHY_FIND_SIG_FIRSTEP,
-			      firstep[level]);
-		if (level > aniState->firstepLevel)
-			ahp->ah_stats.ast_ani_stepup++;
-		else if (level < aniState->firstepLevel)
-			ahp->ah_stats.ast_ani_stepdown++;
-		aniState->firstepLevel = level;
-		break;
-	}
-	case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
-		const int cycpwrThr1[] =
-			{ 2, 4, 6, 8, 10, 12, 14, 16 };
-		u32 level = param;
-
-		if (level >= ARRAY_SIZE(cycpwrThr1)) {
-			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-				 "%s: level out of range (%u > %u)\n",
-				 __func__, level,
-				 (unsigned)
-				ARRAY_SIZE(cycpwrThr1));
-			return false;
-		}
-		REG_RMW_FIELD(ah, AR_PHY_TIMING5,
-			      AR_PHY_TIMING5_CYCPWR_THR1,
-			      cycpwrThr1[level]);
-		if (level > aniState->spurImmunityLevel)
-			ahp->ah_stats.ast_ani_spurup++;
-		else if (level < aniState->spurImmunityLevel)
-			ahp->ah_stats.ast_ani_spurdown++;
-		aniState->spurImmunityLevel = level;
-		break;
-	}
-	case ATH9K_ANI_PRESENT:
-		break;
-	default:
-		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-			"%s: invalid cmd %u\n", __func__, cmd);
-		return false;
-	}
-
-	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__);
-	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-		"noiseImmunityLevel=%d, spurImmunityLevel=%d, "
-		"ofdmWeakSigDetectOff=%d\n",
-		 aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
-		 !aniState->ofdmWeakSigDetectOff);
-	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-		"cckWeakSigThreshold=%d, "
-		"firstepLevel=%d, listenTime=%d\n",
-		 aniState->cckWeakSigThreshold, aniState->firstepLevel,
-		 aniState->listenTime);
-	DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-		 "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
-		 aniState->cycleCount, aniState->ofdmPhyErrCount,
-		 aniState->cckPhyErrCount);
-	return true;
+			INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+			ar9280Modes_original_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+	} else
+		INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+			ar9280Modes_original_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
 }
 
-static void ath9k_ani_restart(struct ath_hal *ah)
+static void ath9k_hw_init_txgain_ini(struct ath_hal *ah)
 {
+	u32 txgain_type;
 	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416AniState *aniState;
 
-	if (!DO_ANI(ah))
-		return;
+	if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) {
+		txgain_type = ath9k_hw_get_eeprom(ah, EEP_TXGAIN_TYPE);
 
-	aniState = ahp->ah_curani;
-
-	aniState->listenTime = 0;
-	if (ahp->ah_hasHwPhyCounters) {
-		if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
-			aniState->ofdmPhyErrBase = 0;
-			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-				 "OFDM Trigger is too high for hw counters\n");
-		} else {
-			aniState->ofdmPhyErrBase =
-				AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
-		}
-		if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
-			aniState->cckPhyErrBase = 0;
-			DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-				 "CCK Trigger is too high for hw counters\n");
-		} else {
-			aniState->cckPhyErrBase =
-				AR_PHY_COUNTMAX - aniState->cckTrigHigh;
-		}
-		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-			 "%s: Writing ofdmbase=%u   cckbase=%u\n",
-			 __func__, aniState->ofdmPhyErrBase,
-			 aniState->cckPhyErrBase);
-		REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
-		REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
-		REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
-		REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-
-		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-	}
-	aniState->ofdmPhyErrCount = 0;
-	aniState->cckPhyErrCount = 0;
-}
-
-static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_channel *chan = ah->ah_curchan;
-	struct ar5416AniState *aniState;
-	enum wireless_mode mode;
-	int32_t rssi;
-
-	if (!DO_ANI(ah))
-		return;
-
-	aniState = ahp->ah_curani;
-
-	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
-		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-					 aniState->noiseImmunityLevel + 1)) {
-			return;
-		}
-	}
-
-	if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
-		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-					 aniState->spurImmunityLevel + 1)) {
-			return;
-		}
-	}
-
-	if (ah->ah_opmode == ATH9K_M_HOSTAP) {
-		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-					     aniState->firstepLevel + 1);
-		}
-		return;
-	}
-	rssi = BEACON_RSSI(ahp);
-	if (rssi > aniState->rssiThrHigh) {
-		if (!aniState->ofdmWeakSigDetectOff) {
-			if (ath9k_hw_ani_control(ah,
-					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-					 false)) {
-				ath9k_hw_ani_control(ah,
-					ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-					0);
-				return;
-			}
-		}
-		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-					     aniState->firstepLevel + 1);
-			return;
-		}
-	} else if (rssi > aniState->rssiThrLow) {
-		if (aniState->ofdmWeakSigDetectOff)
-			ath9k_hw_ani_control(ah,
-				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-				     true);
-		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
-			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-					     aniState->firstepLevel + 1);
-		return;
-	} else {
-		mode = ath9k_hw_chan2wmode(ah, chan);
-		if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
-			if (!aniState->ofdmWeakSigDetectOff)
-				ath9k_hw_ani_control(ah,
-				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-				     false);
-			if (aniState->firstepLevel > 0)
-				ath9k_hw_ani_control(ah,
-						     ATH9K_ANI_FIRSTEP_LEVEL,
-						     0);
-			return;
-		}
-	}
-}
-
-static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_channel *chan = ah->ah_curchan;
-	struct ar5416AniState *aniState;
-	enum wireless_mode mode;
-	int32_t rssi;
-
-	if (!DO_ANI(ah))
-		return;
-
-	aniState = ahp->ah_curani;
-	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
-		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-					 aniState->noiseImmunityLevel + 1)) {
-			return;
-		}
-	}
-	if (ah->ah_opmode == ATH9K_M_HOSTAP) {
-		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-					     aniState->firstepLevel + 1);
-		}
-		return;
-	}
-	rssi = BEACON_RSSI(ahp);
-	if (rssi > aniState->rssiThrLow) {
-		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
-			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-					     aniState->firstepLevel + 1);
-	} else {
-		mode = ath9k_hw_chan2wmode(ah, chan);
-		if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
-			if (aniState->firstepLevel > 0)
-				ath9k_hw_ani_control(ah,
-						     ATH9K_ANI_FIRSTEP_LEVEL,
-						     0);
-		}
-	}
-}
-
-static void ath9k_ani_reset(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416AniState *aniState;
-	struct ath9k_channel *chan = ah->ah_curchan;
-	int index;
-
-	if (!DO_ANI(ah))
-		return;
-
-	index = ath9k_hw_get_ani_channel_idx(ah, chan);
-	aniState = &ahp->ah_ani[index];
-	ahp->ah_curani = aniState;
-
-	if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA
-	    && ah->ah_opmode != ATH9K_M_IBSS) {
-		DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-			 "%s: Reset ANI state opmode %u\n", __func__,
-			 ah->ah_opmode);
-		ahp->ah_stats.ast_ani_reset++;
-		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
-		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
-		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
-		ath9k_hw_ani_control(ah,
-				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-				     !ATH9K_ANI_USE_OFDM_WEAK_SIG);
-		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
-				     ATH9K_ANI_CCK_WEAK_SIG_THR);
-		ath9k_hw_setrxfilter(ah,
-				     ath9k_hw_getrxfilter(ah) |
-				     ATH9K_RX_FILTER_PHYERR);
-		if (ah->ah_opmode == ATH9K_M_HOSTAP) {
-			ahp->ah_curani->ofdmTrigHigh =
-				ah->ah_config.ofdm_trig_high;
-			ahp->ah_curani->ofdmTrigLow =
-				ah->ah_config.ofdm_trig_low;
-			ahp->ah_curani->cckTrigHigh =
-				ah->ah_config.cck_trig_high;
-			ahp->ah_curani->cckTrigLow =
-				ah->ah_config.cck_trig_low;
-		}
-		ath9k_ani_restart(ah);
-		return;
-	}
-
-	if (aniState->noiseImmunityLevel != 0)
-		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-				     aniState->noiseImmunityLevel);
-	if (aniState->spurImmunityLevel != 0)
-		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-				     aniState->spurImmunityLevel);
-	if (aniState->ofdmWeakSigDetectOff)
-		ath9k_hw_ani_control(ah,
-				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-				     !aniState->ofdmWeakSigDetectOff);
-	if (aniState->cckWeakSigThreshold)
-		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
-				     aniState->cckWeakSigThreshold);
-	if (aniState->firstepLevel != 0)
-		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-				     aniState->firstepLevel);
-	if (ahp->ah_hasHwPhyCounters) {
-		ath9k_hw_setrxfilter(ah,
-				     ath9k_hw_getrxfilter(ah) &
-				     ~ATH9K_RX_FILTER_PHYERR);
-		ath9k_ani_restart(ah);
-		REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
-		REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-
-	} else {
-		ath9k_ani_restart(ah);
-		ath9k_hw_setrxfilter(ah,
-				     ath9k_hw_getrxfilter(ah) |
-				     ATH9K_RX_FILTER_PHYERR);
-	}
-}
-
-/*
- * Process a MIB interrupt.  We may potentially be invoked because
- * any of the MIB counters overflow/trigger so don't assume we're
- * here because a PHY error counter triggered.
- */
-void ath9k_hw_procmibevent(struct ath_hal *ah,
-			   const struct ath9k_node_stats *stats)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	u32 phyCnt1, phyCnt2;
-
-	DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n");
-	/* Reset these counters regardless */
-	REG_WRITE(ah, AR_FILT_OFDM, 0);
-	REG_WRITE(ah, AR_FILT_CCK, 0);
-	if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
-		REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
-
-	/* Clear the mib counters and save them in the stats */
-	ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-	ahp->ah_stats.ast_nodestats = *stats;
-
-	if (!DO_ANI(ah))
-		return;
-
-	/* NB: these are not reset-on-read */
-	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
-	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
-	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
-		struct ar5416AniState *aniState = ahp->ah_curani;
-		u32 ofdmPhyErrCnt, cckPhyErrCnt;
-
-		/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
-		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
-		ahp->ah_stats.ast_ani_ofdmerrs +=
-			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
-		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
-
-		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
-		ahp->ah_stats.ast_ani_cckerrs +=
-			cckPhyErrCnt - aniState->cckPhyErrCount;
-		aniState->cckPhyErrCount = cckPhyErrCnt;
-
-		/*
-		 * NB: figure out which counter triggered.  If both
-		 * trigger we'll only deal with one as the processing
-		 * clobbers the error counter so the trigger threshold
-		 * check will never be true.
-		 */
-		if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
-			ath9k_hw_ani_ofdm_err_trigger(ah);
-		if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
-			ath9k_hw_ani_cck_err_trigger(ah);
-		/* NB: always restart to insure the h/w counters are reset */
-		ath9k_ani_restart(ah);
-	}
-}
-
-static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416AniState *aniState;
-	int32_t rssi;
-
-	aniState = ahp->ah_curani;
-
-	if (ah->ah_opmode == ATH9K_M_HOSTAP) {
-		if (aniState->firstepLevel > 0) {
-			if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-						 aniState->firstepLevel - 1)) {
-				return;
-			}
-		}
-	} else {
-		rssi = BEACON_RSSI(ahp);
-		if (rssi > aniState->rssiThrHigh) {
-			/* XXX: Handle me */
-		} else if (rssi > aniState->rssiThrLow) {
-			if (aniState->ofdmWeakSigDetectOff) {
-				if (ath9k_hw_ani_control(ah,
-					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-					 true) ==
-				    true) {
-					return;
-				}
-			}
-			if (aniState->firstepLevel > 0) {
-				if (ath9k_hw_ani_control
-				    (ah, ATH9K_ANI_FIRSTEP_LEVEL,
-				     aniState->firstepLevel - 1) ==
-				    true) {
-					return;
-				}
-			}
-		} else {
-			if (aniState->firstepLevel > 0) {
-				if (ath9k_hw_ani_control
-				    (ah, ATH9K_ANI_FIRSTEP_LEVEL,
-				     aniState->firstepLevel - 1) ==
-				    true) {
-					return;
-				}
-			}
-		}
-	}
-
-	if (aniState->spurImmunityLevel > 0) {
-		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-					 aniState->spurImmunityLevel - 1)) {
-			return;
-		}
-	}
-
-	if (aniState->noiseImmunityLevel > 0) {
-		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-				     aniState->noiseImmunityLevel - 1);
-		return;
-	}
-}
-
-static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416AniState *aniState;
-	u32 txFrameCount, rxFrameCount, cycleCount;
-	int32_t listenTime;
-
-	txFrameCount = REG_READ(ah, AR_TFCNT);
-	rxFrameCount = REG_READ(ah, AR_RFCNT);
-	cycleCount = REG_READ(ah, AR_CCCNT);
-
-	aniState = ahp->ah_curani;
-	if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
-
-		listenTime = 0;
-		ahp->ah_stats.ast_ani_lzero++;
-	} else {
-		int32_t ccdelta = cycleCount - aniState->cycleCount;
-		int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
-		int32_t tfdelta = txFrameCount - aniState->txFrameCount;
-		listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
-	}
-	aniState->cycleCount = cycleCount;
-	aniState->txFrameCount = txFrameCount;
-	aniState->rxFrameCount = rxFrameCount;
-
-	return listenTime;
-}
-
-void ath9k_hw_ani_monitor(struct ath_hal *ah,
-			  const struct ath9k_node_stats *stats,
-			  struct ath9k_channel *chan)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416AniState *aniState;
-	int32_t listenTime;
-
-	aniState = ahp->ah_curani;
-	ahp->ah_stats.ast_nodestats = *stats;
-
-	listenTime = ath9k_hw_ani_get_listen_time(ah);
-	if (listenTime < 0) {
-		ahp->ah_stats.ast_ani_lneg++;
-		ath9k_ani_restart(ah);
-		return;
-	}
-
-	aniState->listenTime += listenTime;
-
-	if (ahp->ah_hasHwPhyCounters) {
-		u32 phyCnt1, phyCnt2;
-		u32 ofdmPhyErrCnt, cckPhyErrCnt;
-
-		ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-
-		phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
-		phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-
-		if (phyCnt1 < aniState->ofdmPhyErrBase ||
-		    phyCnt2 < aniState->cckPhyErrBase) {
-			if (phyCnt1 < aniState->ofdmPhyErrBase) {
-				DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-					 "%s: phyCnt1 0x%x, resetting "
-					 "counter value to 0x%x\n",
-					 __func__, phyCnt1,
-					 aniState->ofdmPhyErrBase);
-				REG_WRITE(ah, AR_PHY_ERR_1,
-					  aniState->ofdmPhyErrBase);
-				REG_WRITE(ah, AR_PHY_ERR_MASK_1,
-					  AR_PHY_ERR_OFDM_TIMING);
-			}
-			if (phyCnt2 < aniState->cckPhyErrBase) {
-				DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-					 "%s: phyCnt2 0x%x, resetting "
-					 "counter value to 0x%x\n",
-					 __func__, phyCnt2,
-					 aniState->cckPhyErrBase);
-				REG_WRITE(ah, AR_PHY_ERR_2,
-					  aniState->cckPhyErrBase);
-				REG_WRITE(ah, AR_PHY_ERR_MASK_2,
-					  AR_PHY_ERR_CCK_TIMING);
-			}
-			return;
-		}
-
-		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
-		ahp->ah_stats.ast_ani_ofdmerrs +=
-			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
-		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
-
-		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
-		ahp->ah_stats.ast_ani_cckerrs +=
-			cckPhyErrCnt - aniState->cckPhyErrCount;
-		aniState->cckPhyErrCount = cckPhyErrCnt;
-	}
-
-	if (!DO_ANI(ah))
-		return;
-
-	if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
-		if (aniState->ofdmPhyErrCount <= aniState->listenTime *
-		    aniState->ofdmTrigLow / 1000 &&
-		    aniState->cckPhyErrCount <= aniState->listenTime *
-		    aniState->cckTrigLow / 1000)
-			ath9k_hw_ani_lower_immunity(ah);
-		ath9k_ani_restart(ah);
-	} else if (aniState->listenTime > ahp->ah_aniPeriod) {
-		if (aniState->ofdmPhyErrCount > aniState->listenTime *
-		    aniState->ofdmTrigHigh / 1000) {
-			ath9k_hw_ani_ofdm_err_trigger(ah);
-			ath9k_ani_restart(ah);
-		} else if (aniState->cckPhyErrCount >
-			   aniState->listenTime * aniState->cckTrigHigh /
-			   1000) {
-			ath9k_hw_ani_cck_err_trigger(ah);
-			ath9k_ani_restart(ah);
-		}
-	}
-}
-
-#ifndef ATH_NF_PER_CHAN
-static void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
-{
-	int i, j;
-
-	for (i = 0; i < NUM_NF_READINGS; i++) {
-		ah->nfCalHist[i].currIndex = 0;
-		ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
-		ah->nfCalHist[i].invalidNFcount =
-			AR_PHY_CCA_FILTERWINDOW_LENGTH;
-		for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
-			ah->nfCalHist[i].nfCalBuffer[j] =
-				AR_PHY_CCA_MAX_GOOD_VALUE;
-		}
-	}
-	return;
-}
-#endif
-
-static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah,
-					 u32 gpio, u32 type)
-{
-	int addr;
-	u32 gpio_shift, tmp;
-
-	if (gpio > 11)
-		addr = AR_GPIO_OUTPUT_MUX3;
-	else if (gpio > 5)
-		addr = AR_GPIO_OUTPUT_MUX2;
-	else
-		addr = AR_GPIO_OUTPUT_MUX1;
-
-	gpio_shift = (gpio % 6) * 5;
-
-	if (AR_SREV_9280_20_OR_LATER(ah)
-	    || (addr != AR_GPIO_OUTPUT_MUX1)) {
-		REG_RMW(ah, addr, (type << gpio_shift),
-			(0x1f << gpio_shift));
-	} else {
-		tmp = REG_READ(ah, addr);
-		tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0);
-		tmp &= ~(0x1f << gpio_shift);
-		tmp |= (type << gpio_shift);
-		REG_WRITE(ah, addr, tmp);
-	}
-}
-
-void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
-			 u32 ah_signal_type)
-{
-	u32 gpio_shift;
-
-	ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
-
-	gpio_shift = 2 * gpio;
-
-	REG_RMW(ah,
-		AR_GPIO_OE_OUT,
-		(AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
-		(AR_GPIO_OE_OUT_DRV << gpio_shift));
-}
-
-void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
-{
-	REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
-		AR_GPIO_BIT(gpio));
-}
-
-/*
- * Configure GPIO Input lines
- */
-void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
-{
-	u32 gpio_shift;
-
-	ASSERT(gpio < ah->ah_caps.num_gpio_pins);
-
-	gpio_shift = gpio << 1;
-
-	REG_RMW(ah,
-		AR_GPIO_OE_OUT,
-		(AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
-		(AR_GPIO_OE_OUT_DRV << gpio_shift));
-}
-
-#ifdef CONFIG_RFKILL
-static void ath9k_enable_rfkill(struct ath_hal *ah)
-{
-	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
-		    AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
-
-	REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
-		    AR_GPIO_INPUT_MUX2_RFSILENT);
-
-	ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
-	REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
-}
-#endif
-
-u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
-{
-	if (gpio >= ah->ah_caps.num_gpio_pins)
-		return 0xffffffff;
-
-	if (AR_SREV_9280_10_OR_LATER(ah)) {
-		return (MS
-			(REG_READ(ah, AR_GPIO_IN_OUT),
-			 AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0;
-	} else {
-		return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) &
-			AR_GPIO_BIT(gpio)) != 0;
-	}
+		if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
+			INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+			ar9280Modes_high_power_tx_gain_9280_2,
+			ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6);
+		else
+			INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+			ar9280Modes_original_tx_gain_9280_2,
+			ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+	} else
+		INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+		ar9280Modes_original_tx_gain_9280_2,
+		ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
 }
 
 static int ath9k_hw_post_attach(struct ath_hal *ah)
@@ -2887,7 +613,7 @@
 
 	if (!ath9k_hw_chip_test(ah)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-			 "%s: hardware self-test failed\n", __func__);
+			"hardware self-test failed\n");
 		return -ENODEV;
 	}
 
@@ -2906,365 +632,17 @@
 		ath9k_hw_ani_setup(ah);
 		ath9k_hw_ani_attach(ah);
 	}
+
 	return 0;
 }
 
-static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
-				    struct ar5416_eeprom *pEepData,
-				    u32 reg, u32 value)
-{
-	struct base_eep_header *pBase = &(pEepData->baseEepHeader);
-
-	switch (ah->ah_devid) {
-	case AR9280_DEVID_PCI:
-		if (reg == 0x7894) {
-			DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-				 "ini VAL: %x  EEPROM: %x\n", value,
-				 (pBase->version & 0xff));
-
-			if ((pBase->version & 0xff) > 0x0a) {
-				DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-					 "PWDCLKIND: %d\n",
-					 pBase->pwdclkind);
-				value &= ~AR_AN_TOP2_PWDCLKIND;
-				value |= AR_AN_TOP2_PWDCLKIND & (pBase->
-					 pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
-			} else {
-				DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-					 "PWDCLKIND Earlier Rev\n");
-			}
-
-			DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-				 "final ini VAL: %x\n", value);
-		}
-		break;
-	}
-	return value;
-}
-
-static bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-	u16 capField = 0, eeval;
-
-	eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_0);
-
-	ah->ah_currentRD = eeval;
-
-	eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_1);
-	ah->ah_currentRDExt = eeval;
-
-	capField = ath9k_hw_get_eeprom(ahp, EEP_OP_CAP);
-
-	if (ah->ah_opmode != ATH9K_M_HOSTAP &&
-	    ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) {
-		if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65)
-			ah->ah_currentRD += 5;
-		else if (ah->ah_currentRD == 0x41)
-			ah->ah_currentRD = 0x43;
-		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			 "%s: regdomain mapped to 0x%x\n", __func__,
-			 ah->ah_currentRD);
-	}
-
-	eeval = ath9k_hw_get_eeprom(ahp, EEP_OP_MODE);
-	bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX);
-
-	if (eeval & AR5416_OPFLAGS_11A) {
-		set_bit(ATH9K_MODE_11A, pCap->wireless_modes);
-		if (ah->ah_config.ht_enable) {
-			if (!(eeval & AR5416_OPFLAGS_N_5G_HT20))
-				set_bit(ATH9K_MODE_11NA_HT20,
-					pCap->wireless_modes);
-			if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) {
-				set_bit(ATH9K_MODE_11NA_HT40PLUS,
-					pCap->wireless_modes);
-				set_bit(ATH9K_MODE_11NA_HT40MINUS,
-					pCap->wireless_modes);
-			}
-		}
-	}
-
-	if (eeval & AR5416_OPFLAGS_11G) {
-		set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
-		set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
-		if (ah->ah_config.ht_enable) {
-			if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
-				set_bit(ATH9K_MODE_11NG_HT20,
-					pCap->wireless_modes);
-			if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) {
-				set_bit(ATH9K_MODE_11NG_HT40PLUS,
-					pCap->wireless_modes);
-				set_bit(ATH9K_MODE_11NG_HT40MINUS,
-					pCap->wireless_modes);
-			}
-		}
-	}
-
-	pCap->tx_chainmask = ath9k_hw_get_eeprom(ahp, EEP_TX_MASK);
-	if ((ah->ah_isPciExpress)
-	    || (eeval & AR5416_OPFLAGS_11A)) {
-		pCap->rx_chainmask =
-			ath9k_hw_get_eeprom(ahp, EEP_RX_MASK);
-	} else {
-		pCap->rx_chainmask =
-			(ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7;
-	}
-
-	if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0)))
-		ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA;
-
-	pCap->low_2ghz_chan = 2312;
-	pCap->high_2ghz_chan = 2732;
-
-	pCap->low_5ghz_chan = 4920;
-	pCap->high_5ghz_chan = 6100;
-
-	pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP;
-	pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP;
-	pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM;
-
-	pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP;
-	pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
-	pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
-
-	pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD;
-
-	if (ah->ah_config.ht_enable)
-		pCap->hw_caps |= ATH9K_HW_CAP_HT;
-	else
-		pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
-
-	pCap->hw_caps |= ATH9K_HW_CAP_GTT;
-	pCap->hw_caps |= ATH9K_HW_CAP_VEOL;
-	pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK;
-	pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH;
-
-	if (capField & AR_EEPROM_EEPCAP_MAXQCU)
-		pCap->total_queues =
-			MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
-	else
-		pCap->total_queues = ATH9K_NUM_TX_QUEUES;
-
-	if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES)
-		pCap->keycache_size =
-			1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES);
-	else
-		pCap->keycache_size = AR_KEYTABLE_SIZE;
-
-	pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
-	pCap->num_mr_retries = 4;
-	pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
-
-	if (AR_SREV_9280_10_OR_LATER(ah))
-		pCap->num_gpio_pins = AR928X_NUM_GPIO;
-	else
-		pCap->num_gpio_pins = AR_NUM_GPIO;
-
-	if (AR_SREV_9280_10_OR_LATER(ah)) {
-		pCap->hw_caps |= ATH9K_HW_CAP_WOW;
-		pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
-	} else {
-		pCap->hw_caps &= ~ATH9K_HW_CAP_WOW;
-		pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
-	}
-
-	if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) {
-		pCap->hw_caps |= ATH9K_HW_CAP_CST;
-		pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX;
-	} else {
-		pCap->rts_aggr_limit = (8 * 1024);
-	}
-
-	pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
-
-#ifdef CONFIG_RFKILL
-	ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT);
-	if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
-		ah->ah_rfkill_gpio =
-			MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
-		ah->ah_rfkill_polarity =
-			MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
-
-		pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
-	}
-#endif
-
-	if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
-	    (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
-	    (ah->ah_macVersion == AR_SREV_VERSION_9160) ||
-	    (ah->ah_macVersion == AR_SREV_VERSION_9100) ||
-	    (ah->ah_macVersion == AR_SREV_VERSION_9280))
-		pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
-	else
-		pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
-
-	if (AR_SREV_9280(ah))
-		pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
-	else
-		pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
-
-	if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) {
-		pCap->reg_cap =
-			AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
-			AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
-			AR_EEPROM_EEREGCAP_EN_KK_U2 |
-			AR_EEPROM_EEREGCAP_EN_KK_MIDBAND;
-	} else {
-		pCap->reg_cap =
-			AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
-			AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
-	}
-
-	pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
-
-	pCap->num_antcfg_5ghz =
-		ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_5GHZ);
-	pCap->num_antcfg_2ghz =
-		ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_2GHZ);
-
-	return true;
-}
-
-static void ar5416DisablePciePhy(struct ath_hal *ah)
-{
-	if (!AR_SREV_9100(ah))
-		return;
-
-	REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
-	REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
-	REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
-	REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824);
-	REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579);
-	REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000);
-	REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
-	REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
-	REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
-
-	REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-}
-
-static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip)
-{
-	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
-	if (setChip) {
-		REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
-			    AR_RTC_FORCE_WAKE_EN);
-		if (!AR_SREV_9100(ah))
-			REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
-
-		REG_CLR_BIT(ah, (u16) (AR_RTC_RESET),
-			    AR_RTC_RESET_EN);
-	}
-}
-
-static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip)
-{
-	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
-	if (setChip) {
-		struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-
-		if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
-			REG_WRITE(ah, AR_RTC_FORCE_WAKE,
-				  AR_RTC_FORCE_WAKE_ON_INT);
-		} else {
-			REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
-				    AR_RTC_FORCE_WAKE_EN);
-		}
-	}
-}
-
-static bool ath9k_hw_set_power_awake(struct ath_hal *ah,
-				     int setChip)
-{
-	u32 val;
-	int i;
-
-	if (setChip) {
-		if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) ==
-		    AR_RTC_STATUS_SHUTDOWN) {
-			if (ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)
-			    != true) {
-				return false;
-			}
-		}
-		if (AR_SREV_9100(ah))
-			REG_SET_BIT(ah, AR_RTC_RESET,
-				       AR_RTC_RESET_EN);
-
-		REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
-			    AR_RTC_FORCE_WAKE_EN);
-		udelay(50);
-
-		for (i = POWER_UP_TIME / 50; i > 0; i--) {
-			val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
-			if (val == AR_RTC_STATUS_ON)
-				break;
-			udelay(50);
-			REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
-				       AR_RTC_FORCE_WAKE_EN);
-		}
-		if (i == 0) {
-			DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-				 "%s: Failed to wakeup in %uus\n",
-				 __func__, POWER_UP_TIME / 20);
-			return false;
-		}
-	}
-
-	REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
-	return true;
-}
-
-bool ath9k_hw_setpower(struct ath_hal *ah,
-		       enum ath9k_power_mode mode)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	static const char *modes[] = {
-		"AWAKE",
-		"FULL-SLEEP",
-		"NETWORK SLEEP",
-		"UNDEFINED"
-	};
-	int status = true, setChip = true;
-
-	DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__,
-		 modes[ahp->ah_powerMode], modes[mode],
-		 setChip ? "set chip " : "");
-
-	switch (mode) {
-	case ATH9K_PM_AWAKE:
-		status = ath9k_hw_set_power_awake(ah, setChip);
-		break;
-	case ATH9K_PM_FULL_SLEEP:
-		ath9k_set_power_sleep(ah, setChip);
-		ahp->ah_chipFullSleep = true;
-		break;
-	case ATH9K_PM_NETWORK_SLEEP:
-		ath9k_set_power_network_sleep(ah, setChip);
-		break;
-	default:
-		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-			 "%s: unknown power mode %u\n", __func__, mode);
-		return false;
-	}
-	ahp->ah_powerMode = mode;
-	return status;
-}
-
-static struct ath_hal *ath9k_hw_do_attach(u16 devid,
-					  struct ath_softc *sc,
-					  void __iomem *mem,
-					  int *status)
+static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
+					  void __iomem *mem, int *status)
 {
 	struct ath_hal_5416 *ahp;
 	struct ath_hal *ah;
 	int ecode;
-#ifndef CONFIG_SLOW_ANT_DIV
-	u32 i;
-	u32 j;
-#endif
+	u32 i, j;
 
 	ahp = ath9k_hw_newstate(devid, sc, mem, status);
 	if (ahp == NULL)
@@ -3278,15 +656,13 @@
 		ahp->ah_intrMitigation = true;
 
 	if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't reset chip\n",
-			 __func__);
+		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't reset chip\n");
 		ecode = -EIO;
 		goto bad;
 	}
 
 	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't wakeup chip\n",
-			 __func__);
+		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't wakeup chip\n");
 		ecode = -EIO;
 		goto bad;
 	}
@@ -3300,18 +676,18 @@
 				SER_REG_MODE_OFF;
 		}
 	}
+
 	DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-		"%s: serialize_regmode is %d\n",
-		__func__, ah->ah_config.serialize_regmode);
+		"serialize_regmode is %d\n",
+		ah->ah_config.serialize_regmode);
 
 	if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) &&
 	    (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) &&
 	    (ah->ah_macVersion != AR_SREV_VERSION_9160) &&
-	    (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) {
+	    (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) {
 		DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-			 "%s: Mac Chip Rev 0x%02x.%x is not supported by "
-			 "this driver\n", __func__,
-			 ah->ah_macVersion, ah->ah_macRev);
+			"Mac Chip Rev 0x%02x.%x is not supported by "
+			"this driver\n", ah->ah_macVersion, ah->ah_macRev);
 		ecode = -EOPNOTSUPP;
 		goto bad;
 	}
@@ -3341,8 +717,7 @@
 			ahp->ah_adcDcCalInitData.calData =
 				&adc_init_dc_cal;
 		}
-		ahp->ah_suppCals =
-			ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
+		ahp->ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
 	}
 
 	if (AR_SREV_9160(ah)) {
@@ -3352,16 +727,46 @@
 	} else {
 		ahp->ah_ani_function = ATH9K_ANI_ALL;
 		if (AR_SREV_9280_10_OR_LATER(ah)) {
-			ahp->ah_ani_function &=
-				~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+			ahp->ah_ani_function &=	~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
 		}
 	}
 
 	DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-		 "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__,
-		 ah->ah_macVersion, ah->ah_macRev);
+		"This Mac Chip Rev 0x%02x.%x is \n",
+		ah->ah_macVersion, ah->ah_macRev);
 
-	if (AR_SREV_9280_20_OR_LATER(ah)) {
+	if (AR_SREV_9285_12_OR_LATER(ah)) {
+		INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285_1_2,
+			       ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
+		INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285_1_2,
+			       ARRAY_SIZE(ar9285Common_9285_1_2), 2);
+
+		if (ah->ah_config.pcie_clock_req) {
+			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+			ar9285PciePhy_clkreq_off_L1_9285_1_2,
+			ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2);
+		} else {
+			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+			ar9285PciePhy_clkreq_always_on_L1_9285_1_2,
+			ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
+				  2);
+		}
+	} else if (AR_SREV_9285_10_OR_LATER(ah)) {
+		INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285,
+			       ARRAY_SIZE(ar9285Modes_9285), 6);
+		INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285,
+			       ARRAY_SIZE(ar9285Common_9285), 2);
+
+		if (ah->ah_config.pcie_clock_req) {
+			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+			ar9285PciePhy_clkreq_off_L1_9285,
+			ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2);
+		} else {
+			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+			ar9285PciePhy_clkreq_always_on_L1_9285,
+			ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2);
+		}
+	} else if (AR_SREV_9280_20_OR_LATER(ah)) {
 		INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2,
 			       ARRAY_SIZE(ar9280Modes_9280_2), 6);
 		INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2,
@@ -3369,21 +774,16 @@
 
 		if (ah->ah_config.pcie_clock_req) {
 			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
-				       ar9280PciePhy_clkreq_off_L1_9280,
-				       ARRAY_SIZE
-				       (ar9280PciePhy_clkreq_off_L1_9280),
-				       2);
+			       ar9280PciePhy_clkreq_off_L1_9280,
+			       ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2);
 		} else {
 			INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
-				       ar9280PciePhy_clkreq_always_on_L1_9280,
-				       ARRAY_SIZE
-				       (ar9280PciePhy_clkreq_always_on_L1_9280),
-				       2);
+			       ar9280PciePhy_clkreq_always_on_L1_9280,
+			       ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
 		}
 		INIT_INI_ARRAY(&ahp->ah_iniModesAdditional,
 			       ar9280Modes_fast_clock_9280_2,
-			       ARRAY_SIZE(ar9280Modes_fast_clock_9280_2),
-			       3);
+			       ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
 	} else if (AR_SREV_9280_10_OR_LATER(ah)) {
 		INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280,
 			       ARRAY_SIZE(ar9280Modes_9280), 6);
@@ -3469,13 +869,20 @@
 	if (ah->ah_isPciExpress)
 		ath9k_hw_configpcipowersave(ah, 0);
 	else
-		ar5416DisablePciePhy(ah);
+		ath9k_hw_disablepcie(ah);
 
 	ecode = ath9k_hw_post_attach(ah);
 	if (ecode != 0)
 		goto bad;
 
-#ifndef CONFIG_SLOW_ANT_DIV
+	/* rxgain table */
+	if (AR_SREV_9280_20(ah))
+		ath9k_hw_init_rxgain_ini(ah);
+
+	/* txgain table */
+	if (AR_SREV_9280_20(ah))
+		ath9k_hw_init_txgain_ini(ah);
+
 	if (ah->ah_devid == AR9280_DEVID_PCI) {
 		for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
 			u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
@@ -3484,16 +891,16 @@
 				u32 val = INI_RA(&ahp->ah_iniModes, i, j);
 
 				INI_RA(&ahp->ah_iniModes, i, j) =
-					ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom,
+					ath9k_hw_ini_fixup(ah,
+							   &ahp->ah_eeprom.def,
 							   reg, val);
 			}
 		}
 	}
-#endif
 
 	if (!ath9k_hw_fill_cap_info(ah)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-			 "%s:failed ath9k_hw_fill_cap_info\n", __func__);
+			"failed ath9k_hw_fill_cap_info\n");
 		ecode = -EINVAL;
 		goto bad;
 	}
@@ -3501,8 +908,7 @@
 	ecode = ath9k_hw_init_macaddr(ah);
 	if (ecode != 0) {
 		DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-			 "%s: failed initializing mac address\n",
-			 __func__);
+			"failed initializing mac address\n");
 		goto bad;
 	}
 
@@ -3511,1108 +917,571 @@
 	else
 		ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S);
 
-#ifndef ATH_NF_PER_CHAN
-
 	ath9k_init_nfcal_hist_buffer(ah);
-#endif
 
 	return ah;
-
 bad:
 	if (ahp)
 		ath9k_hw_detach((struct ath_hal *) ahp);
 	if (status)
 		*status = ecode;
+
 	return NULL;
 }
 
+static void ath9k_hw_init_bb(struct ath_hal *ah,
+			     struct ath9k_channel *chan)
+{
+	u32 synthDelay;
+
+	synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+	if (IS_CHAN_B(chan))
+		synthDelay = (4 * synthDelay) / 22;
+	else
+		synthDelay /= 10;
+
+	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+	udelay(synthDelay + BASE_ACTIVATE_DELAY);
+}
+
+static void ath9k_hw_init_qos(struct ath_hal *ah)
+{
+	REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
+	REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
+
+	REG_WRITE(ah, AR_QOS_NO_ACK,
+		  SM(2, AR_QOS_NO_ACK_TWO_BIT) |
+		  SM(5, AR_QOS_NO_ACK_BIT_OFF) |
+		  SM(0, AR_QOS_NO_ACK_BYTE_OFF));
+
+	REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);
+	REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);
+	REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
+	REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
+	REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
+}
+
+static void ath9k_hw_init_pll(struct ath_hal *ah,
+			      struct ath9k_channel *chan)
+{
+	u32 pll;
+
+	if (AR_SREV_9100(ah)) {
+		if (chan && IS_CHAN_5GHZ(chan))
+			pll = 0x1450;
+		else
+			pll = 0x1458;
+	} else {
+		if (AR_SREV_9280_10_OR_LATER(ah)) {
+			pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
+
+			if (chan && IS_CHAN_HALF_RATE(chan))
+				pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+			else if (chan && IS_CHAN_QUARTER_RATE(chan))
+				pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
+
+			if (chan && IS_CHAN_5GHZ(chan)) {
+				pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
+
+
+				if (AR_SREV_9280_20(ah)) {
+					if (((chan->channel % 20) == 0)
+					    || ((chan->channel % 10) == 0))
+						pll = 0x2850;
+					else
+						pll = 0x142c;
+				}
+			} else {
+				pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
+			}
+
+		} else if (AR_SREV_9160_10_OR_LATER(ah)) {
+
+			pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
+
+			if (chan && IS_CHAN_HALF_RATE(chan))
+				pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+			else if (chan && IS_CHAN_QUARTER_RATE(chan))
+				pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
+
+			if (chan && IS_CHAN_5GHZ(chan))
+				pll |= SM(0x50, AR_RTC_9160_PLL_DIV);
+			else
+				pll |= SM(0x58, AR_RTC_9160_PLL_DIV);
+		} else {
+			pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
+
+			if (chan && IS_CHAN_HALF_RATE(chan))
+				pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
+			else if (chan && IS_CHAN_QUARTER_RATE(chan))
+				pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
+
+			if (chan && IS_CHAN_5GHZ(chan))
+				pll |= SM(0xa, AR_RTC_PLL_DIV);
+			else
+				pll |= SM(0xb, AR_RTC_PLL_DIV);
+		}
+	}
+	REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll);
+
+	udelay(RTC_PLL_SETTLE_DELAY);
+
+	REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
+}
+
+static void ath9k_hw_init_chain_masks(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int rx_chainmask, tx_chainmask;
+
+	rx_chainmask = ahp->ah_rxchainmask;
+	tx_chainmask = ahp->ah_txchainmask;
+
+	switch (rx_chainmask) {
+	case 0x5:
+		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+			    AR_PHY_SWAP_ALT_CHAIN);
+	case 0x3:
+		if (((ah)->ah_macVersion <= AR_SREV_VERSION_9160)) {
+			REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
+			REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
+			break;
+		}
+	case 0x1:
+	case 0x2:
+	case 0x7:
+		REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
+		REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
+		break;
+	default:
+		break;
+	}
+
+	REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
+	if (tx_chainmask == 0x5) {
+		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+			    AR_PHY_SWAP_ALT_CHAIN);
+	}
+	if (AR_SREV_9100(ah))
+		REG_WRITE(ah, AR_PHY_ANALOG_SWAP,
+			  REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
+}
+
+static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
+					  enum nl80211_iftype opmode)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	ahp->ah_maskReg = AR_IMR_TXERR |
+		AR_IMR_TXURN |
+		AR_IMR_RXERR |
+		AR_IMR_RXORN |
+		AR_IMR_BCNMISC;
+
+	if (ahp->ah_intrMitigation)
+		ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
+	else
+		ahp->ah_maskReg |= AR_IMR_RXOK;
+
+	ahp->ah_maskReg |= AR_IMR_TXOK;
+
+	if (opmode == NL80211_IFTYPE_AP)
+		ahp->ah_maskReg |= AR_IMR_MIB;
+
+	REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
+	REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
+
+	if (!AR_SREV_9100(ah)) {
+		REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
+		REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
+		REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
+	}
+}
+
+static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
+		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us);
+		ahp->ah_acktimeout = (u32) -1;
+		return false;
+	} else {
+		REG_RMW_FIELD(ah, AR_TIME_OUT,
+			      AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us));
+		ahp->ah_acktimeout = us;
+		return true;
+	}
+}
+
+static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
+		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us);
+		ahp->ah_ctstimeout = (u32) -1;
+		return false;
+	} else {
+		REG_RMW_FIELD(ah, AR_TIME_OUT,
+			      AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us));
+		ahp->ah_ctstimeout = us;
+		return true;
+	}
+}
+
+static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, u32 tu)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	if (tu > 0xFFFF) {
+		DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
+			"bad global tx timeout %u\n", tu);
+		ahp->ah_globaltxtimeout = (u32) -1;
+		return false;
+	} else {
+		REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu);
+		ahp->ah_globaltxtimeout = tu;
+		return true;
+	}
+}
+
+static void ath9k_hw_init_user_settings(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ahp->ah_miscMode 0x%x\n",
+		ahp->ah_miscMode);
+
+	if (ahp->ah_miscMode != 0)
+		REG_WRITE(ah, AR_PCU_MISC,
+			  REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode);
+	if (ahp->ah_slottime != (u32) -1)
+		ath9k_hw_setslottime(ah, ahp->ah_slottime);
+	if (ahp->ah_acktimeout != (u32) -1)
+		ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout);
+	if (ahp->ah_ctstimeout != (u32) -1)
+		ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout);
+	if (ahp->ah_globaltxtimeout != (u32) -1)
+		ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout);
+}
+
+const char *ath9k_hw_probe(u16 vendorid, u16 devid)
+{
+	return vendorid == ATHEROS_VENDOR_ID ?
+		ath9k_hw_devname(devid) : NULL;
+}
+
 void ath9k_hw_detach(struct ath_hal *ah)
 {
 	if (!AR_SREV_9100(ah))
 		ath9k_hw_ani_detach(ah);
-	ath9k_hw_rfdetach(ah);
 
+	ath9k_hw_rfdetach(ah);
 	ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
 	kfree(ah);
 }
 
-bool ath9k_get_channel_edges(struct ath_hal *ah,
-			     u16 flags, u16 *low,
-			     u16 *high)
+struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
+				void __iomem *mem, int *error)
 {
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath_hal *ah = NULL;
 
-	if (flags & CHANNEL_5GHZ) {
-		*low = pCap->low_5ghz_chan;
-		*high = pCap->high_5ghz_chan;
-		return true;
-	}
-	if ((flags & CHANNEL_2GHZ)) {
-		*low = pCap->low_2ghz_chan;
-		*high = pCap->high_2ghz_chan;
-
-		return true;
-	}
-	return false;
-}
-
-static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin,
-					   u8 pwrMax,
-					   u8 *pPwrList,
-					   u8 *pVpdList,
-					   u16
-					   numIntercepts,
-					   u8 *pRetVpdList)
-{
-	u16 i, k;
-	u8 currPwr = pwrMin;
-	u16 idxL = 0, idxR = 0;
-
-	for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
-		ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
-					       numIntercepts, &(idxL),
-					       &(idxR));
-		if (idxR < 1)
-			idxR = 1;
-		if (idxL == numIntercepts - 1)
-			idxL = (u16) (numIntercepts - 2);
-		if (pPwrList[idxL] == pPwrList[idxR])
-			k = pVpdList[idxL];
-		else
-			k = (u16) (((currPwr -
-					   pPwrList[idxL]) *
-					  pVpdList[idxR] +
-					  (pPwrList[idxR] -
-					   currPwr) * pVpdList[idxL]) /
-					 (pPwrList[idxR] -
-					  pPwrList[idxL]));
-		pRetVpdList[i] = (u8) k;
-		currPwr += 2;
-	}
-
-	return true;
-}
-
-static void
-ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah,
-				    struct ath9k_channel *chan,
-				    struct cal_data_per_freq *pRawDataSet,
-				    u8 *bChans,
-				    u16 availPiers,
-				    u16 tPdGainOverlap,
-				    int16_t *pMinCalPower,
-				    u16 *pPdGainBoundaries,
-				    u8 *pPDADCValues,
-				    u16 numXpdGains)
-{
-	int i, j, k;
-	int16_t ss;
-	u16 idxL = 0, idxR = 0, numPiers;
-	static u8 vpdTableL[AR5416_NUM_PD_GAINS]
-		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-	static u8 vpdTableR[AR5416_NUM_PD_GAINS]
-		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-	static u8 vpdTableI[AR5416_NUM_PD_GAINS]
-		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-
-	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
-	u8 minPwrT4[AR5416_NUM_PD_GAINS];
-	u8 maxPwrT4[AR5416_NUM_PD_GAINS];
-	int16_t vpdStep;
-	int16_t tmpVal;
-	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
-	bool match;
-	int16_t minDelta = 0;
-	struct chan_centers centers;
-
-	ath9k_hw_get_channel_centers(ah, chan, &centers);
-
-	for (numPiers = 0; numPiers < availPiers; numPiers++) {
-		if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
-			break;
-	}
-
-	match = ath9k_hw_get_lower_upper_index((u8)
-					       FREQ2FBIN(centers.
-							 synth_center,
-							 IS_CHAN_2GHZ
-							 (chan)), bChans,
-					       numPiers, &idxL, &idxR);
-
-	if (match) {
-		for (i = 0; i < numXpdGains; i++) {
-			minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
-			maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
-			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
-						pRawDataSet[idxL].
-						pwrPdg[i],
-						pRawDataSet[idxL].
-						vpdPdg[i],
-						AR5416_PD_GAIN_ICEPTS,
-						vpdTableI[i]);
-		}
-	} else {
-		for (i = 0; i < numXpdGains; i++) {
-			pVpdL = pRawDataSet[idxL].vpdPdg[i];
-			pPwrL = pRawDataSet[idxL].pwrPdg[i];
-			pVpdR = pRawDataSet[idxR].vpdPdg[i];
-			pPwrR = pRawDataSet[idxR].pwrPdg[i];
-
-			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
-
-			maxPwrT4[i] =
-				min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
-				    pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
-
-
-			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
-						pPwrL, pVpdL,
-						AR5416_PD_GAIN_ICEPTS,
-						vpdTableL[i]);
-			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
-						pPwrR, pVpdR,
-						AR5416_PD_GAIN_ICEPTS,
-						vpdTableR[i]);
-
-			for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
-				vpdTableI[i][j] =
-					(u8) (ath9k_hw_interpolate
-						    ((u16)
-						     FREQ2FBIN(centers.
-							       synth_center,
-							       IS_CHAN_2GHZ
-							       (chan)),
-						     bChans[idxL],
-						     bChans[idxR], vpdTableL[i]
-						     [j], vpdTableR[i]
-						     [j]));
-			}
-		}
-	}
-
-	*pMinCalPower = (int16_t) (minPwrT4[0] / 2);
-
-	k = 0;
-	for (i = 0; i < numXpdGains; i++) {
-		if (i == (numXpdGains - 1))
-			pPdGainBoundaries[i] =
-				(u16) (maxPwrT4[i] / 2);
-		else
-			pPdGainBoundaries[i] =
-				(u16) ((maxPwrT4[i] +
-					      minPwrT4[i + 1]) / 4);
-
-		pPdGainBoundaries[i] =
-			min((u16) AR5416_MAX_RATE_POWER,
-			    pPdGainBoundaries[i]);
-
-		if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
-			minDelta = pPdGainBoundaries[0] - 23;
-			pPdGainBoundaries[0] = 23;
-		} else {
-			minDelta = 0;
-		}
-
-		if (i == 0) {
-			if (AR_SREV_9280_10_OR_LATER(ah))
-				ss = (int16_t) (0 - (minPwrT4[i] / 2));
-			else
-				ss = 0;
-		} else {
-			ss = (int16_t) ((pPdGainBoundaries[i - 1] -
-					 (minPwrT4[i] / 2)) -
-					tPdGainOverlap + 1 + minDelta);
-		}
-		vpdStep = (int16_t) (vpdTableI[i][1] - vpdTableI[i][0]);
-		vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep);
-
-		while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
-			tmpVal = (int16_t) (vpdTableI[i][0] + ss * vpdStep);
-			pPDADCValues[k++] =
-				(u8) ((tmpVal < 0) ? 0 : tmpVal);
-			ss++;
-		}
-
-		sizeCurrVpdTable =
-			(u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
-		tgtIndex = (u8) (pPdGainBoundaries[i] + tPdGainOverlap -
-				       (minPwrT4[i] / 2));
-		maxIndex = (tgtIndex <
-			    sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
-
-		while ((ss < maxIndex)
-		       && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
-			pPDADCValues[k++] = vpdTableI[i][ss++];
-		}
-
-		vpdStep = (int16_t) (vpdTableI[i][sizeCurrVpdTable - 1] -
-				     vpdTableI[i][sizeCurrVpdTable - 2]);
-		vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep);
-
-		if (tgtIndex > maxIndex) {
-			while ((ss <= tgtIndex)
-			       && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
-				tmpVal = (int16_t) ((vpdTableI[i]
-						     [sizeCurrVpdTable -
-						      1] + (ss - maxIndex +
-							    1) * vpdStep));
-				pPDADCValues[k++] = (u8) ((tmpVal >
-						 255) ? 255 : tmpVal);
-				ss++;
-			}
-		}
-	}
-
-	while (i < AR5416_PD_GAINS_IN_MASK) {
-		pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
-		i++;
-	}
-
-	while (k < AR5416_NUM_PDADC_VALUES) {
-		pPDADCValues[k] = pPDADCValues[k - 1];
-		k++;
-	}
-	return;
-}
-
-static bool
-ath9k_hw_set_power_cal_table(struct ath_hal *ah,
-			     struct ar5416_eeprom *pEepData,
-			     struct ath9k_channel *chan,
-			     int16_t *pTxPowerIndexOffset)
-{
-	struct cal_data_per_freq *pRawDataset;
-	u8 *pCalBChans = NULL;
-	u16 pdGainOverlap_t2;
-	static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
-	u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
-	u16 numPiers, i, j;
-	int16_t tMinCalPower;
-	u16 numXpdGain, xpdMask;
-	u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
-	u32 reg32, regOffset, regChainOffset;
-	int16_t modalIdx;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
-	xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
-
-	if ((pEepData->baseEepHeader.
-	     version & AR5416_EEP_VER_MINOR_MASK) >=
-	    AR5416_EEP_MINOR_VER_2) {
-		pdGainOverlap_t2 =
-			pEepData->modalHeader[modalIdx].pdGainOverlap;
-	} else {
-		pdGainOverlap_t2 =
-			(u16) (MS
-				     (REG_READ(ah, AR_PHY_TPCRG5),
-				      AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
-	}
-
-	if (IS_CHAN_2GHZ(chan)) {
-		pCalBChans = pEepData->calFreqPier2G;
-		numPiers = AR5416_NUM_2G_CAL_PIERS;
-	} else {
-		pCalBChans = pEepData->calFreqPier5G;
-		numPiers = AR5416_NUM_5G_CAL_PIERS;
-	}
-
-	numXpdGain = 0;
-
-	for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
-		if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
-			if (numXpdGain >= AR5416_NUM_PD_GAINS)
-				break;
-			xpdGainValues[numXpdGain] =
-				(u16) (AR5416_PD_GAINS_IN_MASK - i);
-			numXpdGain++;
-		}
-	}
-
-	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
-		      (numXpdGain - 1) & 0x3);
-	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
-		      xpdGainValues[0]);
-	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
-		      xpdGainValues[1]);
-	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
-		      xpdGainValues[2]);
-
-	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		if (AR_SREV_5416_V20_OR_LATER(ah) &&
-		    (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
-		    && (i != 0)) {
-			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
-		} else
-			regChainOffset = i * 0x1000;
-		if (pEepData->baseEepHeader.txMask & (1 << i)) {
-			if (IS_CHAN_2GHZ(chan))
-				pRawDataset = pEepData->calPierData2G[i];
-			else
-				pRawDataset = pEepData->calPierData5G[i];
-
-			ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
-							    pRawDataset,
-							    pCalBChans,
-							    numPiers,
-							    pdGainOverlap_t2,
-							    &tMinCalPower,
-							    gainBoundaries,
-							    pdadcValues,
-							    numXpdGain);
-
-			if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
-
-				REG_WRITE(ah,
-					  AR_PHY_TPCRG5 + regChainOffset,
-					  SM(pdGainOverlap_t2,
-					     AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
-					  | SM(gainBoundaries[0],
-					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
-					  | SM(gainBoundaries[1],
-					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
-					  | SM(gainBoundaries[2],
-					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
-					  | SM(gainBoundaries[3],
-				       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
-			}
-
-			regOffset =
-				AR_PHY_BASE + (672 << 2) + regChainOffset;
-			for (j = 0; j < 32; j++) {
-				reg32 =
-					((pdadcValues[4 * j + 0] & 0xFF) << 0)
-					| ((pdadcValues[4 * j + 1] & 0xFF) <<
-					   8) | ((pdadcValues[4 * j + 2] &
-						  0xFF) << 16) |
-					((pdadcValues[4 * j + 3] & 0xFF) <<
-					 24);
-				REG_WRITE(ah, regOffset, reg32);
-
-				DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
-					 "PDADC (%d,%4x): %4.4x %8.8x\n",
-					 i, regChainOffset, regOffset,
-					 reg32);
-				DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
-				"PDADC: Chain %d | PDADC %3d Value %3d | "
-				"PDADC %3d Value %3d | PDADC %3d Value %3d | "
-				"PDADC %3d Value %3d |\n",
-					 i, 4 * j, pdadcValues[4 * j],
-					 4 * j + 1, pdadcValues[4 * j + 1],
-					 4 * j + 2, pdadcValues[4 * j + 2],
-					 4 * j + 3,
-					 pdadcValues[4 * j + 3]);
-
-				regOffset += 4;
-			}
-		}
-	}
-	*pTxPowerIndexOffset = 0;
-
-	return true;
-}
-
-void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	u8 i;
-
-	if (ah->ah_isPciExpress != true)
-		return;
-
-	if (ah->ah_config.pcie_powersave_enable == 2)
-		return;
-
-	if (restore)
-		return;
-
-	if (AR_SREV_9280_20_OR_LATER(ah)) {
-		for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) {
-			REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0),
-				  INI_RA(&ahp->ah_iniPcieSerdes, i, 1));
-		}
-		udelay(1000);
-	} else if (AR_SREV_9280(ah)
-		   && (ah->ah_macRev == AR_SREV_REVISION_9280_10)) {
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
-
-		REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
-
-		if (ah->ah_config.pcie_clock_req)
-			REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
-		else
-			REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
-
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
-
-		REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-
-		udelay(1000);
-	} else {
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
-		REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
-		REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-	}
-
-	REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
-
-	if (ah->ah_config.pcie_waen) {
-		REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen);
-	} else {
-		if (AR_SREV_9280(ah))
-			REG_WRITE(ah, AR_WA, 0x0040073f);
-		else
-			REG_WRITE(ah, AR_WA, 0x0000073f);
-	}
-}
-
-static void
-ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
-				  struct ath9k_channel *chan,
-				  struct cal_target_power_leg *powInfo,
-				  u16 numChannels,
-				  struct cal_target_power_leg *pNewPower,
-				  u16 numRates,
-				  bool isExtTarget)
-{
-	u16 clo, chi;
-	int i;
-	int matchIndex = -1, lowIndex = -1;
-	u16 freq;
-	struct chan_centers centers;
-
-	ath9k_hw_get_channel_centers(ah, chan, &centers);
-	freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
-
-	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
-		IS_CHAN_2GHZ(chan))) {
-		matchIndex = 0;
-	} else {
-		for (i = 0; (i < numChannels)
-		     && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
-			if (freq ==
-			    ath9k_hw_fbin2freq(powInfo[i].bChannel,
-					       IS_CHAN_2GHZ(chan))) {
-				matchIndex = i;
-				break;
-			} else if ((freq <
-				    ath9k_hw_fbin2freq(powInfo[i].bChannel,
-						       IS_CHAN_2GHZ(chan)))
-				   && (freq >
-				       ath9k_hw_fbin2freq(powInfo[i - 1].
-							  bChannel,
-							  IS_CHAN_2GHZ
-							  (chan)))) {
-				lowIndex = i - 1;
-				break;
-			}
-		}
-		if ((matchIndex == -1) && (lowIndex == -1))
-			matchIndex = i - 1;
-	}
-
-	if (matchIndex != -1) {
-		*pNewPower = powInfo[matchIndex];
-	} else {
-		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
-					 IS_CHAN_2GHZ(chan));
-		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
-					 IS_CHAN_2GHZ(chan));
-
-		for (i = 0; i < numRates; i++) {
-			pNewPower->tPow2x[i] =
-				(u8) ath9k_hw_interpolate(freq, clo, chi,
-								powInfo
-								[lowIndex].
-								tPow2x[i],
-								powInfo
-								[lowIndex +
-								 1].tPow2x[i]);
-		}
-	}
-}
-
-static void
-ath9k_hw_get_target_powers(struct ath_hal *ah,
-			   struct ath9k_channel *chan,
-			   struct cal_target_power_ht *powInfo,
-			   u16 numChannels,
-			   struct cal_target_power_ht *pNewPower,
-			   u16 numRates,
-			   bool isHt40Target)
-{
-	u16 clo, chi;
-	int i;
-	int matchIndex = -1, lowIndex = -1;
-	u16 freq;
-	struct chan_centers centers;
-
-	ath9k_hw_get_channel_centers(ah, chan, &centers);
-	freq = isHt40Target ? centers.synth_center : centers.ctl_center;
-
-	if (freq <=
-		ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
-		matchIndex = 0;
-	} else {
-		for (i = 0; (i < numChannels)
-		     && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
-			if (freq ==
-			    ath9k_hw_fbin2freq(powInfo[i].bChannel,
-					       IS_CHAN_2GHZ(chan))) {
-				matchIndex = i;
-				break;
-			} else
-				if ((freq <
-				     ath9k_hw_fbin2freq(powInfo[i].bChannel,
-							IS_CHAN_2GHZ(chan)))
-				    && (freq >
-					ath9k_hw_fbin2freq(powInfo[i - 1].
-							   bChannel,
-							   IS_CHAN_2GHZ
-							   (chan)))) {
-					lowIndex = i - 1;
-					break;
-				}
-		}
-		if ((matchIndex == -1) && (lowIndex == -1))
-			matchIndex = i - 1;
-	}
-
-	if (matchIndex != -1) {
-		*pNewPower = powInfo[matchIndex];
-	} else {
-		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
-					 IS_CHAN_2GHZ(chan));
-		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
-					 IS_CHAN_2GHZ(chan));
-
-		for (i = 0; i < numRates; i++) {
-			pNewPower->tPow2x[i] =
-				(u8) ath9k_hw_interpolate(freq, clo, chi,
-								powInfo
-								[lowIndex].
-								tPow2x[i],
-								powInfo
-								[lowIndex +
-								 1].tPow2x[i]);
-		}
-	}
-}
-
-static u16
-ath9k_hw_get_max_edge_power(u16 freq,
-			    struct cal_ctl_edges *pRdEdgesPower,
-			    bool is2GHz)
-{
-	u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-	int i;
-
-	for (i = 0; (i < AR5416_NUM_BAND_EDGES)
-	     && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
-		if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
-					       is2GHz)) {
-			twiceMaxEdgePower = pRdEdgesPower[i].tPower;
-			break;
-		} else if ((i > 0)
-			   && (freq <
-			       ath9k_hw_fbin2freq(pRdEdgesPower[i].
-						  bChannel, is2GHz))) {
-			if (ath9k_hw_fbin2freq
-			    (pRdEdgesPower[i - 1].bChannel, is2GHz) < freq
-			    && pRdEdgesPower[i - 1].flag) {
-				twiceMaxEdgePower =
-					pRdEdgesPower[i - 1].tPower;
-			}
-			break;
-		}
-	}
-	return twiceMaxEdgePower;
-}
-
-static bool
-ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
-				  struct ar5416_eeprom *pEepData,
-				  struct ath9k_channel *chan,
-				  int16_t *ratesArray,
-				  u16 cfgCtl,
-				  u8 AntennaReduction,
-				  u8 twiceMaxRegulatoryPower,
-				  u8 powerLimit)
-{
-	u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-	static const u16 tpScaleReductionTable[5] =
-		{ 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
-
-	int i;
-	int8_t twiceLargestAntenna;
-	struct cal_ctl_data *rep;
-	struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
-		0, { 0, 0, 0, 0}
-	};
-	struct cal_target_power_leg targetPowerOfdmExt = {
-		0, { 0, 0, 0, 0} }, targetPowerCckExt = {
-		0, { 0, 0, 0, 0 }
-	};
-	struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
-		0, {0, 0, 0, 0}
-	};
-	u8 scaledPower = 0, minCtlPower, maxRegAllowedPower;
-	u16 ctlModesFor11a[] =
-		{ CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
-	u16 ctlModesFor11g[] =
-		{ CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
-		  CTL_2GHT40
-		};
-	u16 numCtlModes, *pCtlMode, ctlMode, freq;
-	struct chan_centers centers;
-	int tx_chainmask;
-	u8 twiceMinEdgePower;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	tx_chainmask = ahp->ah_txchainmask;
-
-	ath9k_hw_get_channel_centers(ah, chan, &centers);
-
-	twiceLargestAntenna = max(
-		pEepData->modalHeader
-			[IS_CHAN_2GHZ(chan)].antennaGainCh[0],
-		pEepData->modalHeader
-			[IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
-
-	twiceLargestAntenna = max((u8) twiceLargestAntenna,
-		pEepData->modalHeader
-			[IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
-
-	twiceLargestAntenna =
-		(int8_t) min(AntennaReduction - twiceLargestAntenna, 0);
-
-	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
-
-	if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
-		maxRegAllowedPower -=
-			(tpScaleReductionTable[(ah->ah_tpScale)] * 2);
-	}
-
-	scaledPower = min(powerLimit, maxRegAllowedPower);
-
-	switch (ar5416_get_ntxchains(tx_chainmask)) {
-	case 1:
+	switch (devid) {
+	case AR5416_DEVID_PCI:
+	case AR5416_DEVID_PCIE:
+	case AR9160_DEVID_PCI:
+	case AR9280_DEVID_PCI:
+	case AR9280_DEVID_PCIE:
+	case AR9285_DEVID_PCIE:
+		ah = ath9k_hw_do_attach(devid, sc, mem, error);
 		break;
-	case 2:
-		scaledPower -=
-			pEepData->modalHeader[IS_CHAN_2GHZ(chan)].
-			pwrDecreaseFor2Chain;
-		break;
-	case 3:
-		scaledPower -=
-			pEepData->modalHeader[IS_CHAN_2GHZ(chan)].
-			pwrDecreaseFor3Chain;
+	default:
+		*error = -ENXIO;
 		break;
 	}
 
-	scaledPower = max(0, (int32_t) scaledPower);
-
-	if (IS_CHAN_2GHZ(chan)) {
-		numCtlModes =
-			ARRAY_SIZE(ctlModesFor11g) -
-			SUB_NUM_CTL_MODES_AT_2G_40;
-		pCtlMode = ctlModesFor11g;
-
-		ath9k_hw_get_legacy_target_powers(ah, chan,
-			pEepData->
-			calTargetPowerCck,
-			AR5416_NUM_2G_CCK_TARGET_POWERS,
-			&targetPowerCck, 4,
-			false);
-		ath9k_hw_get_legacy_target_powers(ah, chan,
-			pEepData->
-			calTargetPower2G,
-			AR5416_NUM_2G_20_TARGET_POWERS,
-			&targetPowerOfdm, 4,
-			false);
-		ath9k_hw_get_target_powers(ah, chan,
-			pEepData->calTargetPower2GHT20,
-			AR5416_NUM_2G_20_TARGET_POWERS,
-			&targetPowerHt20, 8, false);
-
-		if (IS_CHAN_HT40(chan)) {
-			numCtlModes = ARRAY_SIZE(ctlModesFor11g);
-			ath9k_hw_get_target_powers(ah, chan,
-				pEepData->
-				calTargetPower2GHT40,
-				AR5416_NUM_2G_40_TARGET_POWERS,
-				&targetPowerHt40, 8,
-				true);
-			ath9k_hw_get_legacy_target_powers(ah, chan,
-				pEepData->
-				calTargetPowerCck,
-				AR5416_NUM_2G_CCK_TARGET_POWERS,
-				&targetPowerCckExt,
-				4, true);
-			ath9k_hw_get_legacy_target_powers(ah, chan,
-				pEepData->
-				calTargetPower2G,
-				AR5416_NUM_2G_20_TARGET_POWERS,
-				&targetPowerOfdmExt,
-				4, true);
-		}
-	} else {
-
-		numCtlModes =
-			ARRAY_SIZE(ctlModesFor11a) -
-			SUB_NUM_CTL_MODES_AT_5G_40;
-		pCtlMode = ctlModesFor11a;
-
-		ath9k_hw_get_legacy_target_powers(ah, chan,
-			pEepData->
-			calTargetPower5G,
-			AR5416_NUM_5G_20_TARGET_POWERS,
-			&targetPowerOfdm, 4,
-			false);
-		ath9k_hw_get_target_powers(ah, chan,
-			pEepData->calTargetPower5GHT20,
-			AR5416_NUM_5G_20_TARGET_POWERS,
-			&targetPowerHt20, 8, false);
-
-		if (IS_CHAN_HT40(chan)) {
-			numCtlModes = ARRAY_SIZE(ctlModesFor11a);
-			ath9k_hw_get_target_powers(ah, chan,
-				pEepData->
-				calTargetPower5GHT40,
-				AR5416_NUM_5G_40_TARGET_POWERS,
-				&targetPowerHt40, 8,
-				true);
-			ath9k_hw_get_legacy_target_powers(ah, chan,
-				pEepData->
-				calTargetPower5G,
-				AR5416_NUM_5G_20_TARGET_POWERS,
-				&targetPowerOfdmExt,
-				4, true);
-		}
-	}
-
-	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
-		bool isHt40CtlMode =
-			(pCtlMode[ctlMode] == CTL_5GHT40)
-			|| (pCtlMode[ctlMode] == CTL_2GHT40);
-		if (isHt40CtlMode)
-			freq = centers.synth_center;
-		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
-			freq = centers.ext_center;
-		else
-			freq = centers.ctl_center;
-
-		if (ar5416_get_eep_ver(ahp) == 14
-		    && ar5416_get_eep_rev(ahp) <= 2)
-			twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-
-		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-			"LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
-			"EXT_ADDITIVE %d\n",
-			 ctlMode, numCtlModes, isHt40CtlMode,
-			 (pCtlMode[ctlMode] & EXT_ADDITIVE));
-
-		for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i];
-		     i++) {
-			DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-				"  LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
-				"pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
-				"chan %d\n",
-				i, cfgCtl, pCtlMode[ctlMode],
-				pEepData->ctlIndex[i], chan->channel);
-
-			if ((((cfgCtl & ~CTL_MODE_M) |
-			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
-			     pEepData->ctlIndex[i])
-			    ||
-			    (((cfgCtl & ~CTL_MODE_M) |
-			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
-			     ((pEepData->
-			       ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
-				rep = &(pEepData->ctlData[i]);
-
-				twiceMinEdgePower =
-					ath9k_hw_get_max_edge_power(freq,
-						rep->
-						ctlEdges
-						[ar5416_get_ntxchains
-						(tx_chainmask)
-						- 1],
-						IS_CHAN_2GHZ
-						(chan));
-
-				DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-					"    MATCH-EE_IDX %d: ch %d is2 %d "
-					"2xMinEdge %d chainmask %d chains %d\n",
-					 i, freq, IS_CHAN_2GHZ(chan),
-					 twiceMinEdgePower, tx_chainmask,
-					 ar5416_get_ntxchains
-					 (tx_chainmask));
-				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
-					twiceMaxEdgePower =
-						min(twiceMaxEdgePower,
-						    twiceMinEdgePower);
-				} else {
-					twiceMaxEdgePower =
-						twiceMinEdgePower;
-					break;
-				}
-			}
-		}
-
-		minCtlPower = min(twiceMaxEdgePower, scaledPower);
-
-		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-				"    SEL-Min ctlMode %d pCtlMode %d "
-				"2xMaxEdge %d sP %d minCtlPwr %d\n",
-			 ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
-			 scaledPower, minCtlPower);
-
-		switch (pCtlMode[ctlMode]) {
-		case CTL_11B:
-			for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x);
-			     i++) {
-				targetPowerCck.tPow2x[i] =
-					min(targetPowerCck.tPow2x[i],
-					    minCtlPower);
-			}
-			break;
-		case CTL_11A:
-		case CTL_11G:
-			for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x);
-			     i++) {
-				targetPowerOfdm.tPow2x[i] =
-					min(targetPowerOfdm.tPow2x[i],
-					    minCtlPower);
-			}
-			break;
-		case CTL_5GHT20:
-		case CTL_2GHT20:
-			for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x);
-			     i++) {
-				targetPowerHt20.tPow2x[i] =
-					min(targetPowerHt20.tPow2x[i],
-					    minCtlPower);
-			}
-			break;
-		case CTL_11B_EXT:
-			targetPowerCckExt.tPow2x[0] =
-				min(targetPowerCckExt.tPow2x[0], minCtlPower);
-			break;
-		case CTL_11A_EXT:
-		case CTL_11G_EXT:
-			targetPowerOfdmExt.tPow2x[0] =
-				min(targetPowerOfdmExt.tPow2x[0], minCtlPower);
-			break;
-		case CTL_5GHT40:
-		case CTL_2GHT40:
-			for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x);
-			     i++) {
-				targetPowerHt40.tPow2x[i] =
-					min(targetPowerHt40.tPow2x[i],
-					    minCtlPower);
-			}
-			break;
-		default:
-			break;
-		}
-	}
-
-	ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
-		ratesArray[rate18mb] = ratesArray[rate24mb] =
-		targetPowerOfdm.tPow2x[0];
-	ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
-	ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
-	ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
-	ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
-
-	for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
-		ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
-
-	if (IS_CHAN_2GHZ(chan)) {
-		ratesArray[rate1l] = targetPowerCck.tPow2x[0];
-		ratesArray[rate2s] = ratesArray[rate2l] =
-			targetPowerCck.tPow2x[1];
-		ratesArray[rate5_5s] = ratesArray[rate5_5l] =
-			targetPowerCck.tPow2x[2];
-		;
-		ratesArray[rate11s] = ratesArray[rate11l] =
-			targetPowerCck.tPow2x[3];
-		;
-	}
-	if (IS_CHAN_HT40(chan)) {
-		for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
-			ratesArray[rateHt40_0 + i] =
-				targetPowerHt40.tPow2x[i];
-		}
-		ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
-		ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
-		ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
-		if (IS_CHAN_2GHZ(chan)) {
-			ratesArray[rateExtCck] =
-				targetPowerCckExt.tPow2x[0];
-		}
-	}
-	return true;
+	return ah;
 }
 
-static int
-ath9k_hw_set_txpower(struct ath_hal *ah,
-		     struct ar5416_eeprom *pEepData,
-		     struct ath9k_channel *chan,
-		     u16 cfgCtl,
-		     u8 twiceAntennaReduction,
-		     u8 twiceMaxRegulatoryPower,
-		     u8 powerLimit)
+/*******/
+/* INI */
+/*******/
+
+static void ath9k_hw_override_ini(struct ath_hal *ah,
+				  struct ath9k_channel *chan)
 {
-	struct modal_eep_header *pModal =
-		&(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
-	int16_t ratesArray[Ar5416RateSize];
-	int16_t txPowerIndexOffset = 0;
-	u8 ht40PowerIncForPdadc = 2;
-	int i;
+	/*
+	 * Set the RX_ABORT and RX_DIS and clear if off only after
+	 * RXE is set for MAC. This prevents frames with corrupted
+	 * descriptor status.
+	 */
+	REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
 
-	memset(ratesArray, 0, sizeof(ratesArray));
 
-	if ((pEepData->baseEepHeader.
-	     version & AR5416_EEP_VER_MINOR_MASK) >=
-	    AR5416_EEP_MINOR_VER_2) {
-		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+	if (!AR_SREV_5416_V20_OR_LATER(ah) ||
+	    AR_SREV_9280_10_OR_LATER(ah))
+		return;
+
+	REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
+}
+
+static u32 ath9k_hw_def_ini_fixup(struct ath_hal *ah,
+			      struct ar5416_eeprom_def *pEepData,
+			      u32 reg, u32 value)
+{
+	struct base_eep_header *pBase = &(pEepData->baseEepHeader);
+
+	switch (ah->ah_devid) {
+	case AR9280_DEVID_PCI:
+		if (reg == 0x7894) {
+			DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+				"ini VAL: %x  EEPROM: %x\n", value,
+				(pBase->version & 0xff));
+
+			if ((pBase->version & 0xff) > 0x0a) {
+				DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+					"PWDCLKIND: %d\n",
+					pBase->pwdclkind);
+				value &= ~AR_AN_TOP2_PWDCLKIND;
+				value |= AR_AN_TOP2_PWDCLKIND &
+					(pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
+			} else {
+				DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+					"PWDCLKIND Earlier Rev\n");
+			}
+
+			DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+				"final ini VAL: %x\n", value);
+		}
+		break;
 	}
 
-	if (!ath9k_hw_set_power_per_rate_table(ah, pEepData, chan,
-					       &ratesArray[0], cfgCtl,
-					       twiceAntennaReduction,
-					       twiceMaxRegulatoryPower,
-					       powerLimit)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			"ath9k_hw_set_txpower: unable to set "
-			"tx power per rate table\n");
-		return -EIO;
-	}
+	return value;
+}
 
-	if (!ath9k_hw_set_power_cal_table
-	    (ah, pEepData, chan, &txPowerIndexOffset)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			 "ath9k_hw_set_txpower: unable to set power table\n");
-		return -EIO;
-	}
+static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
+			      struct ar5416_eeprom_def *pEepData,
+			      u32 reg, u32 value)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
 
-	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
-		ratesArray[i] =
-			(int16_t) (txPowerIndexOffset + ratesArray[i]);
-		if (ratesArray[i] > AR5416_MAX_RATE_POWER)
-			ratesArray[i] = AR5416_MAX_RATE_POWER;
-	}
-
-	if (AR_SREV_9280_10_OR_LATER(ah)) {
-		for (i = 0; i < Ar5416RateSize; i++)
-			ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
-	}
-
-	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
-		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
-		  | ATH9K_POW_SM(ratesArray[rate12mb], 16)
-		  | ATH9K_POW_SM(ratesArray[rate9mb], 8)
-		  | ATH9K_POW_SM(ratesArray[rate6mb], 0)
-		);
-	REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
-		  ATH9K_POW_SM(ratesArray[rate54mb], 24)
-		  | ATH9K_POW_SM(ratesArray[rate48mb], 16)
-		  | ATH9K_POW_SM(ratesArray[rate36mb], 8)
-		  | ATH9K_POW_SM(ratesArray[rate24mb], 0)
-		);
-
-	if (IS_CHAN_2GHZ(chan)) {
-		REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
-			  ATH9K_POW_SM(ratesArray[rate2s], 24)
-			  | ATH9K_POW_SM(ratesArray[rate2l], 16)
-			  | ATH9K_POW_SM(ratesArray[rateXr], 8)
-			  | ATH9K_POW_SM(ratesArray[rate1l], 0)
-			);
-		REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
-			  ATH9K_POW_SM(ratesArray[rate11s], 24)
-			  | ATH9K_POW_SM(ratesArray[rate11l], 16)
-			  | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
-			  | ATH9K_POW_SM(ratesArray[rate5_5l], 0)
-			);
-	}
-
-	REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
-		  ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)
-		);
-	REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
-		  ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
-		  | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)
-		);
-
-	if (IS_CHAN_HT40(chan)) {
-		REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
-			  ATH9K_POW_SM(ratesArray[rateHt40_3] +
-				       ht40PowerIncForPdadc, 24)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_2] +
-					 ht40PowerIncForPdadc, 16)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_1] +
-					 ht40PowerIncForPdadc, 8)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_0] +
-					 ht40PowerIncForPdadc, 0)
-			);
-		REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
-			  ATH9K_POW_SM(ratesArray[rateHt40_7] +
-				       ht40PowerIncForPdadc, 24)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_6] +
-					 ht40PowerIncForPdadc, 16)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_5] +
-					 ht40PowerIncForPdadc, 8)
-			  | ATH9K_POW_SM(ratesArray[rateHt40_4] +
-					 ht40PowerIncForPdadc, 0)
-			);
-
-		REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
-			  ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
-			  | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
-			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
-			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0)
-			);
-	}
-
-	REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
-		  ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
-		  | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)
-		);
-
-	i = rate6mb;
-	if (IS_CHAN_HT40(chan))
-		i = rateHt40_0;
-	else if (IS_CHAN_HT20(chan))
-		i = rateHt20_0;
-
-	if (AR_SREV_9280_10_OR_LATER(ah))
-		ah->ah_maxPowerLevel =
-			ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+	if (ahp->ah_eep_map == EEP_MAP_4KBITS)
+		return value;
 	else
-		ah->ah_maxPowerLevel = ratesArray[i];
+		return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value);
+}
+
+static int ath9k_hw_process_ini(struct ath_hal *ah,
+				struct ath9k_channel *chan,
+				enum ath9k_ht_macmode macmode)
+{
+	int i, regWrites = 0;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 modesIndex, freqIndex;
+	int status;
+
+	switch (chan->chanmode) {
+	case CHANNEL_A:
+	case CHANNEL_A_HT20:
+		modesIndex = 1;
+		freqIndex = 1;
+		break;
+	case CHANNEL_A_HT40PLUS:
+	case CHANNEL_A_HT40MINUS:
+		modesIndex = 2;
+		freqIndex = 1;
+		break;
+	case CHANNEL_G:
+	case CHANNEL_G_HT20:
+	case CHANNEL_B:
+		modesIndex = 4;
+		freqIndex = 2;
+		break;
+	case CHANNEL_G_HT40PLUS:
+	case CHANNEL_G_HT40MINUS:
+		modesIndex = 3;
+		freqIndex = 2;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	REG_WRITE(ah, AR_PHY(0), 0x00000007);
+
+	REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
+
+	ath9k_hw_set_addac(ah, chan);
+
+	if (AR_SREV_5416_V22_OR_LATER(ah)) {
+		REG_WRITE_ARRAY(&ahp->ah_iniAddac, 1, regWrites);
+	} else {
+		struct ar5416IniArray temp;
+		u32 addacSize =
+			sizeof(u32) * ahp->ah_iniAddac.ia_rows *
+			ahp->ah_iniAddac.ia_columns;
+
+		memcpy(ahp->ah_addac5416_21,
+		       ahp->ah_iniAddac.ia_array, addacSize);
+
+		(ahp->ah_addac5416_21)[31 * ahp->ah_iniAddac.ia_columns + 1] = 0;
+
+		temp.ia_array = ahp->ah_addac5416_21;
+		temp.ia_columns = ahp->ah_iniAddac.ia_columns;
+		temp.ia_rows = ahp->ah_iniAddac.ia_rows;
+		REG_WRITE_ARRAY(&temp, 1, regWrites);
+	}
+
+	REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
+
+	for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
+		u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
+		u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex);
+
+		REG_WRITE(ah, reg, val);
+
+		if (reg >= 0x7800 && reg < 0x78a0
+		    && ah->ah_config.analog_shiftreg) {
+			udelay(100);
+		}
+
+		DO_DELAY(regWrites);
+	}
+
+	if (AR_SREV_9280(ah))
+		REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites);
+
+	if (AR_SREV_9280(ah))
+		REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites);
+
+	for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) {
+		u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0);
+		u32 val = INI_RA(&ahp->ah_iniCommon, i, 1);
+
+		REG_WRITE(ah, reg, val);
+
+		if (reg >= 0x7800 && reg < 0x78a0
+		    && ah->ah_config.analog_shiftreg) {
+			udelay(100);
+		}
+
+		DO_DELAY(regWrites);
+	}
+
+	ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites);
+
+	if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) {
+		REG_WRITE_ARRAY(&ahp->ah_iniModesAdditional, modesIndex,
+				regWrites);
+	}
+
+	ath9k_hw_override_ini(ah, chan);
+	ath9k_hw_set_regs(ah, chan, macmode);
+	ath9k_hw_init_chain_masks(ah);
+
+	status = ath9k_hw_set_txpower(ah, chan,
+				      ath9k_regd_get_ctl(ah, chan),
+				      ath9k_regd_get_antenna_allowed(ah,
+								     chan),
+				      chan->maxRegTxPower * 2,
+				      min((u32) MAX_RATE_POWER,
+					  (u32) ah->ah_powerLimit));
+	if (status != 0) {
+		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+			"error init'ing transmit power\n");
+		return -EIO;
+	}
+
+	if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+			"ar5416SetRfRegs failed\n");
+		return -EIO;
+	}
 
 	return 0;
 }
 
+/****************************************/
+/* Reset and Channel Switching Routines */
+/****************************************/
+
+static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+	u32 rfMode = 0;
+
+	if (chan == NULL)
+		return;
+
+	rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
+		? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
+
+	if (!AR_SREV_9280_10_OR_LATER(ah))
+		rfMode |= (IS_CHAN_5GHZ(chan)) ?
+			AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ;
+
+	if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan))
+		rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
+
+	REG_WRITE(ah, AR_PHY_MODE, rfMode);
+}
+
+static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah)
+{
+	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+}
+
+static inline void ath9k_hw_set_dma(struct ath_hal *ah)
+{
+	u32 regval;
+
+	regval = REG_READ(ah, AR_AHB_MODE);
+	REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
+
+	regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
+	REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
+
+	REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel);
+
+	regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
+	REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
+
+	REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
+
+	if (AR_SREV_9285(ah)) {
+		REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
+			  AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
+	} else {
+		REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
+			  AR_PCU_TXBUF_CTRL_USABLE_SIZE);
+	}
+}
+
+static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode)
+{
+	u32 val;
+
+	val = REG_READ(ah, AR_STA_ID1);
+	val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);
+	switch (opmode) {
+	case NL80211_IFTYPE_AP:
+		REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP
+			  | AR_STA_ID1_KSRCH_MODE);
+		REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC
+			  | AR_STA_ID1_KSRCH_MODE);
+		REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
+		break;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_MONITOR:
+		REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
+		break;
+	}
+}
+
 static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah,
 						 u32 coef_scaled,
 						 u32 *coef_mantissa,
@@ -4632,9 +1501,8 @@
 	*coef_exponent = coef_exp - 16;
 }
 
-static void
-ath9k_hw_set_delta_slope(struct ath_hal *ah,
-			 struct ath9k_channel *chan)
+static void ath9k_hw_set_delta_slope(struct ath_hal *ah,
+				     struct ath9k_channel *chan)
 {
 	u32 coef_scaled, ds_coef_exp, ds_coef_man;
 	u32 clockMhzScaled = 0x64000000;
@@ -4667,8 +1535,243 @@
 		      AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);
 }
 
-static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah,
-					struct ath9k_channel *chan)
+static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
+{
+	u32 rst_flags;
+	u32 tmpReg;
+
+	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
+		  AR_RTC_FORCE_WAKE_ON_INT);
+
+	if (AR_SREV_9100(ah)) {
+		rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD |
+			AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;
+	} else {
+		tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE);
+		if (tmpReg &
+		    (AR_INTR_SYNC_LOCAL_TIMEOUT |
+		     AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
+			REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
+			REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+		} else {
+			REG_WRITE(ah, AR_RC, AR_RC_AHB);
+		}
+
+		rst_flags = AR_RTC_RC_MAC_WARM;
+		if (type == ATH9K_RESET_COLD)
+			rst_flags |= AR_RTC_RC_MAC_COLD;
+	}
+
+	REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags);
+	udelay(50);
+
+	REG_WRITE(ah, (u16) (AR_RTC_RC), 0);
+	if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+			"RTC stuck in MAC reset\n");
+		return false;
+	}
+
+	if (!AR_SREV_9100(ah))
+		REG_WRITE(ah, AR_RC, 0);
+
+	ath9k_hw_init_pll(ah, NULL);
+
+	if (AR_SREV_9100(ah))
+		udelay(50);
+
+	return true;
+}
+
+static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
+{
+	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
+		  AR_RTC_FORCE_WAKE_ON_INT);
+
+	REG_WRITE(ah, (u16) (AR_RTC_RESET), 0);
+	REG_WRITE(ah, (u16) (AR_RTC_RESET), 1);
+
+	if (!ath9k_hw_wait(ah,
+			   AR_RTC_STATUS,
+			   AR_RTC_STATUS_M,
+			   AR_RTC_STATUS_ON)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n");
+		return false;
+	}
+
+	ath9k_hw_read_revisions(ah);
+
+	return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM);
+}
+
+static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type)
+{
+	REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+		  AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
+
+	switch (type) {
+	case ATH9K_RESET_POWER_ON:
+		return ath9k_hw_set_reset_power_on(ah);
+		break;
+	case ATH9K_RESET_WARM:
+	case ATH9K_RESET_COLD:
+		return ath9k_hw_set_reset(ah, type);
+		break;
+	default:
+		return false;
+	}
+}
+
+static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
+			      enum ath9k_ht_macmode macmode)
+{
+	u32 phymode;
+	u32 enableDacFifo = 0;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	if (AR_SREV_9285_10_OR_LATER(ah))
+		enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) &
+					 AR_PHY_FC_ENABLE_DAC_FIFO);
+
+	phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
+		| AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo;
+
+	if (IS_CHAN_HT40(chan)) {
+		phymode |= AR_PHY_FC_DYN2040_EN;
+
+		if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+		    (chan->chanmode == CHANNEL_G_HT40PLUS))
+			phymode |= AR_PHY_FC_DYN2040_PRI_CH;
+
+		if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
+			phymode |= AR_PHY_FC_DYN2040_EXT_CH;
+	}
+	REG_WRITE(ah, AR_PHY_TURBO, phymode);
+
+	ath9k_hw_set11nmac2040(ah, macmode);
+
+	REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
+	REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
+}
+
+static bool ath9k_hw_chip_reset(struct ath_hal *ah,
+				struct ath9k_channel *chan)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
+		return false;
+
+	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+		return false;
+
+	ahp->ah_chipFullSleep = false;
+
+	ath9k_hw_init_pll(ah, chan);
+
+	ath9k_hw_set_rfmode(ah, chan);
+
+	return true;
+}
+
+static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
+						 struct ath9k_channel *chan)
+{
+	if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+			"invalid channel %u/0x%x; not marked as "
+			"2GHz or 5GHz\n", chan->channel, chan->channelFlags);
+		return NULL;
+	}
+
+	if (!IS_CHAN_OFDM(chan) &&
+	    !IS_CHAN_B(chan) &&
+	    !IS_CHAN_HT20(chan) &&
+	    !IS_CHAN_HT40(chan)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+			"invalid channel %u/0x%x; not marked as "
+			"OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n",
+			chan->channel, chan->channelFlags);
+		return NULL;
+	}
+
+	return ath9k_regd_check_channel(ah, chan);
+}
+
+static bool ath9k_hw_channel_change(struct ath_hal *ah,
+				    struct ath9k_channel *chan,
+				    enum ath9k_ht_macmode macmode)
+{
+	u32 synthDelay, qnum;
+
+	for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
+		if (ath9k_hw_numtxpending(ah, qnum)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+				"Transmit frames pending on queue %d\n", qnum);
+			return false;
+		}
+	}
+
+	REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
+	if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
+			   AR_PHY_RFBUS_GRANT_EN)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+			"Could not kill baseband RX\n");
+		return false;
+	}
+
+	ath9k_hw_set_regs(ah, chan, macmode);
+
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
+			DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+				"failed to set channel\n");
+			return false;
+		}
+	} else {
+		if (!(ath9k_hw_set_channel(ah, chan))) {
+			DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+				"failed to set channel\n");
+			return false;
+		}
+	}
+
+	if (ath9k_hw_set_txpower(ah, chan,
+				 ath9k_regd_get_ctl(ah, chan),
+				 ath9k_regd_get_antenna_allowed(ah, chan),
+				 chan->maxRegTxPower * 2,
+				 min((u32) MAX_RATE_POWER,
+				     (u32) ah->ah_powerLimit)) != 0) {
+		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+			"error init'ing transmit power\n");
+		return false;
+	}
+
+	synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+	if (IS_CHAN_B(chan))
+		synthDelay = (4 * synthDelay) / 22;
+	else
+		synthDelay /= 10;
+
+	udelay(synthDelay + BASE_ACTIVATE_DELAY);
+
+	REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
+
+	if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
+		ath9k_hw_set_delta_slope(ah, chan);
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		ath9k_hw_9280_spur_mitigate(ah, chan);
+	else
+		ath9k_hw_spur_mitigate(ah, chan);
+
+	if (!chan->oneTimeCalsDone)
+		chan->oneTimeCalsDone = true;
+
+	return true;
+}
+
+static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan)
 {
 	int bb_spur = AR_NO_SPUR;
 	int freq;
@@ -4918,8 +2021,7 @@
 	REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
 }
 
-static void ath9k_hw_spur_mitigate(struct ath_hal *ah,
-				   struct ath9k_channel *chan)
+static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan)
 {
 	int bb_spur = AR_NO_SPUR;
 	int bin, cur_bin;
@@ -5120,752 +2222,11 @@
 	REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
 }
 
-static void ath9k_hw_init_chain_masks(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	int rx_chainmask, tx_chainmask;
-
-	rx_chainmask = ahp->ah_rxchainmask;
-	tx_chainmask = ahp->ah_txchainmask;
-
-	switch (rx_chainmask) {
-	case 0x5:
-		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
-			    AR_PHY_SWAP_ALT_CHAIN);
-	case 0x3:
-		if (((ah)->ah_macVersion <= AR_SREV_VERSION_9160)) {
-			REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
-			REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
-			break;
-		}
-	case 0x1:
-	case 0x2:
-		if (!AR_SREV_9280(ah))
-			break;
-	case 0x7:
-		REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
-		REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
-		break;
-	default:
-		break;
-	}
-
-	REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
-	if (tx_chainmask == 0x5) {
-		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
-			    AR_PHY_SWAP_ALT_CHAIN);
-	}
-	if (AR_SREV_9100(ah))
-		REG_WRITE(ah, AR_PHY_ANALOG_SWAP,
-			  REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
-}
-
-static void ath9k_hw_set_addac(struct ath_hal *ah,
-			       struct ath9k_channel *chan)
-{
-	struct modal_eep_header *pModal;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-	u8 biaslevel;
-
-	if (ah->ah_macVersion != AR_SREV_VERSION_9160)
-		return;
-
-	if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
-		return;
-
-	pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
-
-	if (pModal->xpaBiasLvl != 0xff) {
-		biaslevel = pModal->xpaBiasLvl;
-	} else {
-
-		u16 resetFreqBin, freqBin, freqCount = 0;
-		struct chan_centers centers;
-
-		ath9k_hw_get_channel_centers(ah, chan, &centers);
-
-		resetFreqBin =
-			FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan));
-		freqBin = pModal->xpaBiasLvlFreq[0] & 0xff;
-		biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14);
-
-		freqCount++;
-
-		while (freqCount < 3) {
-			if (pModal->xpaBiasLvlFreq[freqCount] == 0x0)
-				break;
-
-			freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff;
-			if (resetFreqBin >= freqBin) {
-				biaslevel =
-					(u8) (pModal->
-						    xpaBiasLvlFreq[freqCount]
-						    >> 14);
-			} else {
-				break;
-			}
-			freqCount++;
-		}
-	}
-
-	if (IS_CHAN_2GHZ(chan)) {
-		INI_RA(&ahp->ah_iniAddac, 7, 1) =
-			(INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel
-			<< 3;
-	} else {
-		INI_RA(&ahp->ah_iniAddac, 6, 1) =
-			(INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel
-			<< 6;
-	}
-}
-
-static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks)
-{
-	if (ah->ah_curchan != NULL)
-		return clks /
-		CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)];
-	else
-		return clks / CLOCK_RATE[ATH9K_MODE_11B];
-}
-
-static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks)
-{
-	struct ath9k_channel *chan = ah->ah_curchan;
-
-	if (chan && IS_CHAN_HT40(chan))
-		return ath9k_hw_mac_usec(ah, clks) / 2;
-	else
-		return ath9k_hw_mac_usec(ah, clks);
-}
-
-static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs)
-{
-	if (ah->ah_curchan != NULL)
-		return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah,
-			ah->ah_curchan)];
-	else
-		return usecs * CLOCK_RATE[ATH9K_MODE_11B];
-}
-
-static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
-{
-	struct ath9k_channel *chan = ah->ah_curchan;
-
-	if (chan && IS_CHAN_HT40(chan))
-		return ath9k_hw_mac_clks(ah, usecs) * 2;
-	else
-		return ath9k_hw_mac_clks(ah, usecs);
-}
-
-static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad ack timeout %u\n",
-			 __func__, us);
-		ahp->ah_acktimeout = (u32) -1;
-		return false;
-	} else {
-		REG_RMW_FIELD(ah, AR_TIME_OUT,
-			      AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us));
-		ahp->ah_acktimeout = us;
-		return true;
-	}
-}
-
-static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad cts timeout %u\n",
-			 __func__, us);
-		ahp->ah_ctstimeout = (u32) -1;
-		return false;
-	} else {
-		REG_RMW_FIELD(ah, AR_TIME_OUT,
-			      AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us));
-		ahp->ah_ctstimeout = us;
-		return true;
-	}
-}
-static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah,
-					  u32 tu)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	if (tu > 0xFFFF) {
-		DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
-			"%s: bad global tx timeout %u\n", __func__, tu);
-		ahp->ah_globaltxtimeout = (u32) -1;
-		return false;
-	} else {
-		REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu);
-		ahp->ah_globaltxtimeout = tu;
-		return true;
-	}
-}
-
-bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad slot time %u\n",
-			 __func__, us);
-		ahp->ah_slottime = (u32) -1;
-		return false;
-	} else {
-		REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
-		ahp->ah_slottime = us;
-		return true;
-	}
-}
-
-static void ath9k_hw_init_user_settings(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	DPRINTF(ah->ah_sc, ATH_DBG_RESET, "--AP %s ahp->ah_miscMode 0x%x\n",
-		 __func__, ahp->ah_miscMode);
-	if (ahp->ah_miscMode != 0)
-		REG_WRITE(ah, AR_PCU_MISC,
-			  REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode);
-	if (ahp->ah_slottime != (u32) -1)
-		ath9k_hw_setslottime(ah, ahp->ah_slottime);
-	if (ahp->ah_acktimeout != (u32) -1)
-		ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout);
-	if (ahp->ah_ctstimeout != (u32) -1)
-		ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout);
-	if (ahp->ah_globaltxtimeout != (u32) -1)
-		ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout);
-}
-
-static int
-ath9k_hw_process_ini(struct ath_hal *ah,
-		     struct ath9k_channel *chan,
-		     enum ath9k_ht_macmode macmode)
-{
-	int i, regWrites = 0;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	u32 modesIndex, freqIndex;
-	int status;
-
-	switch (chan->chanmode) {
-	case CHANNEL_A:
-	case CHANNEL_A_HT20:
-		modesIndex = 1;
-		freqIndex = 1;
-		break;
-	case CHANNEL_A_HT40PLUS:
-	case CHANNEL_A_HT40MINUS:
-		modesIndex = 2;
-		freqIndex = 1;
-		break;
-	case CHANNEL_G:
-	case CHANNEL_G_HT20:
-	case CHANNEL_B:
-		modesIndex = 4;
-		freqIndex = 2;
-		break;
-	case CHANNEL_G_HT40PLUS:
-	case CHANNEL_G_HT40MINUS:
-		modesIndex = 3;
-		freqIndex = 2;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	REG_WRITE(ah, AR_PHY(0), 0x00000007);
-
-	REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
-
-	ath9k_hw_set_addac(ah, chan);
-
-	if (AR_SREV_5416_V22_OR_LATER(ah)) {
-		REG_WRITE_ARRAY(&ahp->ah_iniAddac, 1, regWrites);
-	} else {
-		struct ar5416IniArray temp;
-		u32 addacSize =
-			sizeof(u32) * ahp->ah_iniAddac.ia_rows *
-			ahp->ah_iniAddac.ia_columns;
-
-		memcpy(ahp->ah_addac5416_21,
-		       ahp->ah_iniAddac.ia_array, addacSize);
-
-		(ahp->ah_addac5416_21)[31 *
-				       ahp->ah_iniAddac.ia_columns + 1] = 0;
-
-		temp.ia_array = ahp->ah_addac5416_21;
-		temp.ia_columns = ahp->ah_iniAddac.ia_columns;
-		temp.ia_rows = ahp->ah_iniAddac.ia_rows;
-		REG_WRITE_ARRAY(&temp, 1, regWrites);
-	}
-	REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
-
-	for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
-		u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
-		u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex);
-
-#ifdef CONFIG_SLOW_ANT_DIV
-		if (ah->ah_devid == AR9280_DEVID_PCI)
-			val = ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, reg,
-						 val);
-#endif
-
-		REG_WRITE(ah, reg, val);
-
-		if (reg >= 0x7800 && reg < 0x78a0
-		    && ah->ah_config.analog_shiftreg) {
-			udelay(100);
-		}
-
-		DO_DELAY(regWrites);
-	}
-
-	for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) {
-		u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0);
-		u32 val = INI_RA(&ahp->ah_iniCommon, i, 1);
-
-		REG_WRITE(ah, reg, val);
-
-		if (reg >= 0x7800 && reg < 0x78a0
-		    && ah->ah_config.analog_shiftreg) {
-			udelay(100);
-		}
-
-		DO_DELAY(regWrites);
-	}
-
-	ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites);
-
-	if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) {
-		REG_WRITE_ARRAY(&ahp->ah_iniModesAdditional, modesIndex,
-				regWrites);
-	}
-
-	ath9k_hw_override_ini(ah, chan);
-	ath9k_hw_set_regs(ah, chan, macmode);
-	ath9k_hw_init_chain_masks(ah);
-
-	status = ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
-				      ath9k_regd_get_ctl(ah, chan),
-				      ath9k_regd_get_antenna_allowed(ah,
-								     chan),
-				      chan->maxRegTxPower * 2,
-				      min((u32) MAX_RATE_POWER,
-					  (u32) ah->ah_powerLimit));
-	if (status != 0) {
-		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-			 "%s: error init'ing transmit power\n", __func__);
-		return -EIO;
-	}
-
-	if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-			 "%s: ar5416SetRfRegs failed\n", __func__);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static void ath9k_hw_setup_calibration(struct ath_hal *ah,
-					      struct hal_cal_list *currCal)
-{
-	REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
-		      AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
-		      currCal->calData->calCountMax);
-
-	switch (currCal->calData->calType) {
-	case IQ_MISMATCH_CAL:
-		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "%s: starting IQ Mismatch Calibration\n",
-			 __func__);
-		break;
-	case ADC_GAIN_CAL:
-		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "%s: starting ADC Gain Calibration\n", __func__);
-		break;
-	case ADC_DC_CAL:
-		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "%s: starting ADC DC Calibration\n", __func__);
-		break;
-	case ADC_DC_INIT_CAL:
-		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "%s: starting Init ADC DC Calibration\n",
-			 __func__);
-		break;
-	}
-
-	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
-		    AR_PHY_TIMING_CTRL4_DO_CAL);
-}
-
-static void ath9k_hw_reset_calibration(struct ath_hal *ah,
-				       struct hal_cal_list *currCal)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	int i;
-
-	ath9k_hw_setup_calibration(ah, currCal);
-
-	currCal->calState = CAL_RUNNING;
-
-	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		ahp->ah_Meas0.sign[i] = 0;
-		ahp->ah_Meas1.sign[i] = 0;
-		ahp->ah_Meas2.sign[i] = 0;
-		ahp->ah_Meas3.sign[i] = 0;
-	}
-
-	ahp->ah_CalSamples = 0;
-}
-
-static void
-ath9k_hw_per_calibration(struct ath_hal *ah,
-			 struct ath9k_channel *ichan,
-			 u8 rxchainmask,
-			 struct hal_cal_list *currCal,
-			 bool *isCalDone)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	*isCalDone = false;
-
-	if (currCal->calState == CAL_RUNNING) {
-		if (!(REG_READ(ah,
-			       AR_PHY_TIMING_CTRL4(0)) &
-		      AR_PHY_TIMING_CTRL4_DO_CAL)) {
-
-			currCal->calData->calCollect(ah);
-
-			ahp->ah_CalSamples++;
-
-			if (ahp->ah_CalSamples >=
-			    currCal->calData->calNumSamples) {
-				int i, numChains = 0;
-				for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-					if (rxchainmask & (1 << i))
-						numChains++;
-				}
-
-				currCal->calData->calPostProc(ah,
-							      numChains);
-
-				ichan->CalValid |=
-					currCal->calData->calType;
-				currCal->calState = CAL_DONE;
-				*isCalDone = true;
-			} else {
-				ath9k_hw_setup_calibration(ah, currCal);
-			}
-		}
-	} else if (!(ichan->CalValid & currCal->calData->calType)) {
-		ath9k_hw_reset_calibration(ah, currCal);
-	}
-}
-
-static inline bool ath9k_hw_run_init_cals(struct ath_hal *ah,
-					  int init_cal_count)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_channel ichan;
-	bool isCalDone;
-	struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
-	const struct hal_percal_data *calData = currCal->calData;
-	int i;
-
-	if (currCal == NULL)
-		return false;
-
-	ichan.CalValid = 0;
-
-	for (i = 0; i < init_cal_count; i++) {
-		ath9k_hw_reset_calibration(ah, currCal);
-
-		if (!ath9k_hw_wait(ah, AR_PHY_TIMING_CTRL4(0),
-				   AR_PHY_TIMING_CTRL4_DO_CAL, 0)) {
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "%s: Cal %d failed to complete in 100ms.\n",
-				 __func__, calData->calType);
-
-			ahp->ah_cal_list = ahp->ah_cal_list_last =
-				ahp->ah_cal_list_curr = NULL;
-			return false;
-		}
-
-		ath9k_hw_per_calibration(ah, &ichan, ahp->ah_rxchainmask,
-					 currCal, &isCalDone);
-		if (!isCalDone) {
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "%s: Not able to run Init Cal %d.\n",
-				 __func__, calData->calType);
-		}
-		if (currCal->calNext) {
-			currCal = currCal->calNext;
-			calData = currCal->calData;
-		}
-	}
-
-	ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
-	return true;
-}
-
-static bool
-ath9k_hw_channel_change(struct ath_hal *ah,
-			struct ath9k_channel *chan,
-			enum ath9k_ht_macmode macmode)
-{
-	u32 synthDelay, qnum;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
-		if (ath9k_hw_numtxpending(ah, qnum)) {
-			DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-				 "%s: Transmit frames pending on queue %d\n",
-				 __func__, qnum);
-			return false;
-		}
-	}
-
-	REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
-	if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
-			   AR_PHY_RFBUS_GRANT_EN)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
-			 "%s: Could not kill baseband RX\n", __func__);
-		return false;
-	}
-
-	ath9k_hw_set_regs(ah, chan, macmode);
-
-	if (AR_SREV_9280_10_OR_LATER(ah)) {
-		if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
-			DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-				 "%s: failed to set channel\n", __func__);
-			return false;
-		}
-	} else {
-		if (!(ath9k_hw_set_channel(ah, chan))) {
-			DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-				 "%s: failed to set channel\n", __func__);
-			return false;
-		}
-	}
-
-	if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
-				 ath9k_regd_get_ctl(ah, chan),
-				 ath9k_regd_get_antenna_allowed(ah, chan),
-				 chan->maxRegTxPower * 2,
-				 min((u32) MAX_RATE_POWER,
-				     (u32) ah->ah_powerLimit)) != 0) {
-		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			 "%s: error init'ing transmit power\n", __func__);
-		return false;
-	}
-
-	synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
-	if (IS_CHAN_CCK(chan))
-		synthDelay = (4 * synthDelay) / 22;
-	else
-		synthDelay /= 10;
-
-	udelay(synthDelay + BASE_ACTIVATE_DELAY);
-
-	REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
-
-	if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
-		ath9k_hw_set_delta_slope(ah, chan);
-
-	if (AR_SREV_9280_10_OR_LATER(ah))
-		ath9k_hw_9280_spur_mitigate(ah, chan);
-	else
-		ath9k_hw_spur_mitigate(ah, chan);
-
-	if (!chan->oneTimeCalsDone)
-		chan->oneTimeCalsDone = true;
-
-	return true;
-}
-
-static bool ath9k_hw_chip_reset(struct ath_hal *ah,
-				struct ath9k_channel *chan)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
-		return false;
-
-	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
-		return false;
-
-	ahp->ah_chipFullSleep = false;
-
-	ath9k_hw_init_pll(ah, chan);
-
-	ath9k_hw_set_rfmode(ah, chan);
-
-	return true;
-}
-
-static inline void ath9k_hw_set_dma(struct ath_hal *ah)
-{
-	u32 regval;
-
-	regval = REG_READ(ah, AR_AHB_MODE);
-	REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
-
-	regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
-	REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
-
-	REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel);
-
-	regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
-	REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
-
-	REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
-
-	if (AR_SREV_9285(ah)) {
-		REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
-			  AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
-	} else {
-		REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
-			  AR_PCU_TXBUF_CTRL_USABLE_SIZE);
-	}
-}
-
-bool ath9k_hw_stopdmarecv(struct ath_hal *ah)
-{
-	REG_WRITE(ah, AR_CR, AR_CR_RXD);
-	if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-			"%s: dma failed to stop in 10ms\n"
-			"AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
-			__func__,
-			REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
-		return false;
-	} else {
-		return true;
-	}
-}
-
-void ath9k_hw_startpcureceive(struct ath_hal *ah)
-{
-	REG_CLR_BIT(ah, AR_DIAG_SW,
-		    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
-
-	ath9k_enable_mib_counters(ah);
-
-	ath9k_ani_reset(ah);
-}
-
-void ath9k_hw_stoppcurecv(struct ath_hal *ah)
-{
-	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
-
-	ath9k_hw_disable_mib_counters(ah);
-}
-
-static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
-				     struct ath9k_channel *chan,
-				     enum hal_cal_types calType)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	bool retval = false;
-
-	switch (calType & ahp->ah_suppCals) {
-	case IQ_MISMATCH_CAL:
-		if (!IS_CHAN_B(chan))
-			retval = true;
-		break;
-	case ADC_GAIN_CAL:
-	case ADC_DC_CAL:
-		if (!IS_CHAN_B(chan)
-		    && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
-			retval = true;
-		break;
-	}
-
-	return retval;
-}
-
-static bool ath9k_hw_init_cal(struct ath_hal *ah,
-			      struct ath9k_channel *chan)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_channel *ichan =
-		ath9k_regd_check_channel(ah, chan);
-
-	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
-		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
-		  AR_PHY_AGC_CONTROL_CAL);
-
-	if (!ath9k_hw_wait
-	    (ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "%s: offset calibration failed to complete in 1ms; "
-			 "noisy environment?\n", __func__);
-		return false;
-	}
-
-	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
-		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
-		  AR_PHY_AGC_CONTROL_NF);
-
-	ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr =
-		NULL;
-
-	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
-		if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
-			INIT_CAL(&ahp->ah_adcGainCalData);
-			INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "%s: enabling ADC Gain Calibration.\n",
-				 __func__);
-		}
-		if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
-			INIT_CAL(&ahp->ah_adcDcCalData);
-			INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "%s: enabling ADC DC Calibration.\n",
-				 __func__);
-		}
-		if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
-			INIT_CAL(&ahp->ah_iqCalData);
-			INSERT_CAL(ahp, &ahp->ah_iqCalData);
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "%s: enabling IQ Calibration.\n",
-				 __func__);
-		}
-
-		ahp->ah_cal_list_curr = ahp->ah_cal_list;
-
-		if (ahp->ah_cal_list_curr)
-			ath9k_hw_reset_calibration(ah,
-						   ahp->ah_cal_list_curr);
-	}
-
-	ichan->CalValid = 0;
-
-	return true;
-}
-
-
-bool ath9k_hw_reset(struct ath_hal *ah,
-		    struct ath9k_channel *chan,
+bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
 		    enum ath9k_ht_macmode macmode,
 		    u8 txchainmask, u8 rxchainmask,
 		    enum ath9k_ht_extprotspacing extprotspacing,
-		    bool bChannelChange,
-		    int *status)
+		    bool bChannelChange, int *status)
 {
 	u32 saveLedState;
 	struct ath_hal_5416 *ahp = AH5416(ah);
@@ -5886,8 +2247,8 @@
 
 	if (ath9k_hw_check_chan(ah, chan) == NULL) {
 		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-			 "%s: invalid channel %u/0x%x; no mapping\n",
-			 __func__, chan->channel, chan->channelFlags);
+			"invalid channel %u/0x%x; no mapping\n",
+			chan->channel, chan->channelFlags);
 		ecode = -EINVAL;
 		goto bad;
 	}
@@ -5907,8 +2268,7 @@
 	    ((chan->channelFlags & CHANNEL_ALL) ==
 	     (ah->ah_curchan->channelFlags & CHANNEL_ALL)) &&
 	    (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) &&
-				   !IS_CHAN_A_5MHZ_SPACED(ah->
-							  ah_curchan)))) {
+				   !IS_CHAN_A_5MHZ_SPACED(ah->ah_curchan)))) {
 
 		if (ath9k_hw_channel_change(ah, chan, macmode)) {
 			ath9k_hw_loadnf(ah, ah->ah_curchan);
@@ -5930,8 +2290,7 @@
 	ath9k_hw_mark_phy_inactive(ah);
 
 	if (!ath9k_hw_chip_reset(ah, chan)) {
-		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: chip reset failed\n",
-			 __func__);
+		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n");
 		ecode = -EINVAL;
 		goto bad;
 	}
@@ -5965,7 +2324,7 @@
 
 	if (!ath9k_hw_eeprom_set_board_values(ah, chan)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-			 "%s: error setting board options\n", __func__);
+			"error setting board options\n");
 		ecode = -EIO;
 		goto bad;
 	}
@@ -6016,7 +2375,7 @@
 	ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode);
 	ath9k_hw_init_qos(ah);
 
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		ath9k_enable_rfkill(ah);
 #endif
@@ -6055,15 +2414,13 @@
 		mask = REG_READ(ah, AR_CFG);
 		if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
 			DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-				 "%s CFG Byte Swap Set 0x%x\n", __func__,
-				 mask);
+				"CFG Byte Swap Set 0x%x\n", mask);
 		} else {
 			mask =
 				INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
 			REG_WRITE(ah, AR_CFG, mask);
 			DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-				 "%s Setting CFG 0x%x\n", __func__,
-				 REG_READ(ah, AR_CFG));
+				"Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
 		}
 	} else {
 #ifdef __BIG_ENDIAN
@@ -6078,584 +2435,975 @@
 	return false;
 }
 
-bool ath9k_hw_phy_disable(struct ath_hal *ah)
+/************************/
+/* Key Cache Management */
+/************************/
+
+bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry)
 {
-	return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM);
-}
+	u32 keyType;
 
-bool ath9k_hw_disable(struct ath_hal *ah)
-{
-	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
-		return false;
-
-	return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
-}
-
-bool
-ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
-		   u8 rxchainmask, bool longcal,
-		   bool *isCalDone)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
-	struct ath9k_channel *ichan =
-		ath9k_regd_check_channel(ah, chan);
-
-	*isCalDone = true;
-
-	if (ichan == NULL) {
-		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-			 "%s: invalid channel %u/0x%x; no mapping\n",
-			 __func__, chan->channel, chan->channelFlags);
+	if (entry >= ah->ah_caps.keycache_size) {
+		DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+			"entry %u out of range\n", entry);
 		return false;
 	}
 
-	if (currCal &&
-	    (currCal->calState == CAL_RUNNING ||
-	     currCal->calState == CAL_WAITING)) {
-		ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal,
-					 isCalDone);
-		if (*isCalDone) {
-			ahp->ah_cal_list_curr = currCal = currCal->calNext;
+	keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
 
-			if (currCal->calState == CAL_WAITING) {
-				*isCalDone = false;
-				ath9k_hw_reset_calibration(ah, currCal);
+	REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
+	REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
+
+	if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
+		u16 micentry = entry + 64;
+
+		REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
+		REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+		REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
+		REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+
+	}
+
+	if (ah->ah_curchan == NULL)
+		return true;
+
+	return true;
+}
+
+bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac)
+{
+	u32 macHi, macLo;
+
+	if (entry >= ah->ah_caps.keycache_size) {
+		DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+			"entry %u out of range\n", entry);
+		return false;
+	}
+
+	if (mac != NULL) {
+		macHi = (mac[5] << 8) | mac[4];
+		macLo = (mac[3] << 24) |
+			(mac[2] << 16) |
+			(mac[1] << 8) |
+			mac[0];
+		macLo >>= 1;
+		macLo |= (macHi & 1) << 31;
+		macHi >>= 1;
+	} else {
+		macLo = macHi = 0;
+	}
+	REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
+	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID);
+
+	return true;
+}
+
+bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
+				 const struct ath9k_keyval *k,
+				 const u8 *mac, int xorKey)
+{
+	const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	u32 key0, key1, key2, key3, key4;
+	u32 keyType;
+	u32 xorMask = xorKey ?
+		(ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8
+		 | ATH9K_KEY_XOR) : 0;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	if (entry >= pCap->keycache_size) {
+		DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+			"entry %u out of range\n", entry);
+		return false;
+	}
+
+	switch (k->kv_type) {
+	case ATH9K_CIPHER_AES_OCB:
+		keyType = AR_KEYTABLE_TYPE_AES;
+		break;
+	case ATH9K_CIPHER_AES_CCM:
+		if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
+			DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+				"AES-CCM not supported by mac rev 0x%x\n",
+				ah->ah_macRev);
+			return false;
+		}
+		keyType = AR_KEYTABLE_TYPE_CCM;
+		break;
+	case ATH9K_CIPHER_TKIP:
+		keyType = AR_KEYTABLE_TYPE_TKIP;
+		if (ATH9K_IS_MIC_ENABLED(ah)
+		    && entry + 64 >= pCap->keycache_size) {
+			DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+				"entry %u inappropriate for TKIP\n", entry);
+			return false;
+		}
+		break;
+	case ATH9K_CIPHER_WEP:
+		if (k->kv_len < LEN_WEP40) {
+			DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+				"WEP key length %u too small\n", k->kv_len);
+			return false;
+		}
+		if (k->kv_len <= LEN_WEP40)
+			keyType = AR_KEYTABLE_TYPE_40;
+		else if (k->kv_len <= LEN_WEP104)
+			keyType = AR_KEYTABLE_TYPE_104;
+		else
+			keyType = AR_KEYTABLE_TYPE_128;
+		break;
+	case ATH9K_CIPHER_CLR:
+		keyType = AR_KEYTABLE_TYPE_CLR;
+		break;
+	default:
+		DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+			"cipher %u not supported\n", k->kv_type);
+		return false;
+	}
+
+	key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask;
+	key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff;
+	key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask;
+	key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff;
+	key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask;
+	if (k->kv_len <= LEN_WEP104)
+		key4 &= 0xff;
+
+	if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
+		u16 micentry = entry + 64;
+
+		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
+		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
+		REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
+		REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+		REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
+		REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+		(void) ath9k_hw_keysetmac(ah, entry, mac);
+
+		if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) {
+			u32 mic0, mic1, mic2, mic3, mic4;
+
+			mic0 = get_unaligned_le32(k->kv_mic + 0);
+			mic2 = get_unaligned_le32(k->kv_mic + 4);
+			mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
+			mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
+			mic4 = get_unaligned_le32(k->kv_txmic + 4);
+			REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
+			REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
+			REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
+			REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
+			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
+			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
+				  AR_KEYTABLE_TYPE_CLR);
+
+		} else {
+			u32 mic0, mic2;
+
+			mic0 = get_unaligned_le32(k->kv_mic + 0);
+			mic2 = get_unaligned_le32(k->kv_mic + 4);
+			REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
+			REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+			REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
+			REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
+			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
+				  AR_KEYTABLE_TYPE_CLR);
+		}
+		REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
+		REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
+		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
+		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+	} else {
+		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
+		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+		REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
+		REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+		REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
+		REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+
+		(void) ath9k_hw_keysetmac(ah, entry, mac);
+	}
+
+	if (ah->ah_curchan == NULL)
+		return true;
+
+	return true;
+}
+
+bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry)
+{
+	if (entry < ah->ah_caps.keycache_size) {
+		u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
+		if (val & AR_KEYTABLE_VALID)
+			return true;
+	}
+	return false;
+}
+
+/******************************/
+/* Power Management (Chipset) */
+/******************************/
+
+static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip)
+{
+	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+	if (setChip) {
+		REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
+			    AR_RTC_FORCE_WAKE_EN);
+		if (!AR_SREV_9100(ah))
+			REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+
+		REG_CLR_BIT(ah, (u16) (AR_RTC_RESET),
+			    AR_RTC_RESET_EN);
+	}
+}
+
+static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip)
+{
+	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+	if (setChip) {
+		struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+		if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+			REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+				  AR_RTC_FORCE_WAKE_ON_INT);
+		} else {
+			REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
+				    AR_RTC_FORCE_WAKE_EN);
+		}
+	}
+}
+
+static bool ath9k_hw_set_power_awake(struct ath_hal *ah,
+				     int setChip)
+{
+	u32 val;
+	int i;
+
+	if (setChip) {
+		if ((REG_READ(ah, AR_RTC_STATUS) &
+		     AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
+			if (ath9k_hw_set_reset_reg(ah,
+					   ATH9K_RESET_POWER_ON) != true) {
+				return false;
+			}
+		}
+		if (AR_SREV_9100(ah))
+			REG_SET_BIT(ah, AR_RTC_RESET,
+				    AR_RTC_RESET_EN);
+
+		REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+			    AR_RTC_FORCE_WAKE_EN);
+		udelay(50);
+
+		for (i = POWER_UP_TIME / 50; i > 0; i--) {
+			val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
+			if (val == AR_RTC_STATUS_ON)
+				break;
+			udelay(50);
+			REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+				    AR_RTC_FORCE_WAKE_EN);
+		}
+		if (i == 0) {
+			DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+				"Failed to wakeup in %uus\n", POWER_UP_TIME / 20);
+			return false;
+		}
+	}
+
+	REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+
+	return true;
+}
+
+bool ath9k_hw_setpower(struct ath_hal *ah,
+		       enum ath9k_power_mode mode)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	static const char *modes[] = {
+		"AWAKE",
+		"FULL-SLEEP",
+		"NETWORK SLEEP",
+		"UNDEFINED"
+	};
+	int status = true, setChip = true;
+
+	DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n",
+		modes[ahp->ah_powerMode], modes[mode],
+		setChip ? "set chip " : "");
+
+	switch (mode) {
+	case ATH9K_PM_AWAKE:
+		status = ath9k_hw_set_power_awake(ah, setChip);
+		break;
+	case ATH9K_PM_FULL_SLEEP:
+		ath9k_set_power_sleep(ah, setChip);
+		ahp->ah_chipFullSleep = true;
+		break;
+	case ATH9K_PM_NETWORK_SLEEP:
+		ath9k_set_power_network_sleep(ah, setChip);
+		break;
+	default:
+		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+			"Unknown power mode %u\n", mode);
+		return false;
+	}
+	ahp->ah_powerMode = mode;
+
+	return status;
+}
+
+void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u8 i;
+
+	if (ah->ah_isPciExpress != true)
+		return;
+
+	if (ah->ah_config.pcie_powersave_enable == 2)
+		return;
+
+	if (restore)
+		return;
+
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) {
+			REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0),
+				  INI_RA(&ahp->ah_iniPcieSerdes, i, 1));
+		}
+		udelay(1000);
+	} else if (AR_SREV_9280(ah) &&
+		   (ah->ah_macRev == AR_SREV_REVISION_9280_10)) {
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+
+		REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
+
+		if (ah->ah_config.pcie_clock_req)
+			REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
+		else
+			REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
+
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
+
+		REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+		udelay(1000);
+	} else {
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+		REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
+		REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+	}
+
+	REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+
+	if (ah->ah_config.pcie_waen) {
+		REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen);
+	} else {
+		if (AR_SREV_9285(ah))
+			REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
+		else if (AR_SREV_9280(ah))
+			REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT);
+		else
+			REG_WRITE(ah, AR_WA, AR_WA_DEFAULT);
+	}
+
+}
+
+/**********************/
+/* Interrupt Handling */
+/**********************/
+
+bool ath9k_hw_intrpend(struct ath_hal *ah)
+{
+	u32 host_isr;
+
+	if (AR_SREV_9100(ah))
+		return true;
+
+	host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
+	if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS))
+		return true;
+
+	host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE);
+	if ((host_isr & AR_INTR_SYNC_DEFAULT)
+	    && (host_isr != AR_INTR_SPURIOUS))
+		return true;
+
+	return false;
+}
+
+bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
+{
+	u32 isr = 0;
+	u32 mask2 = 0;
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	u32 sync_cause = 0;
+	bool fatal_int = false;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	if (!AR_SREV_9100(ah)) {
+		if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
+			if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
+			    == AR_RTC_STATUS_ON) {
+				isr = REG_READ(ah, AR_ISR);
+			}
+		}
+
+		sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) &
+			AR_INTR_SYNC_DEFAULT;
+
+		*masked = 0;
+
+		if (!isr && !sync_cause)
+			return false;
+	} else {
+		*masked = 0;
+		isr = REG_READ(ah, AR_ISR);
+	}
+
+	if (isr) {
+		if (isr & AR_ISR_BCNMISC) {
+			u32 isr2;
+			isr2 = REG_READ(ah, AR_ISR_S2);
+			if (isr2 & AR_ISR_S2_TIM)
+				mask2 |= ATH9K_INT_TIM;
+			if (isr2 & AR_ISR_S2_DTIM)
+				mask2 |= ATH9K_INT_DTIM;
+			if (isr2 & AR_ISR_S2_DTIMSYNC)
+				mask2 |= ATH9K_INT_DTIMSYNC;
+			if (isr2 & (AR_ISR_S2_CABEND))
+				mask2 |= ATH9K_INT_CABEND;
+			if (isr2 & AR_ISR_S2_GTT)
+				mask2 |= ATH9K_INT_GTT;
+			if (isr2 & AR_ISR_S2_CST)
+				mask2 |= ATH9K_INT_CST;
+		}
+
+		isr = REG_READ(ah, AR_ISR_RAC);
+		if (isr == 0xffffffff) {
+			*masked = 0;
+			return false;
+		}
+
+		*masked = isr & ATH9K_INT_COMMON;
+
+		if (ahp->ah_intrMitigation) {
+			if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
+				*masked |= ATH9K_INT_RX;
+		}
+
+		if (isr & (AR_ISR_RXOK | AR_ISR_RXERR))
+			*masked |= ATH9K_INT_RX;
+		if (isr &
+		    (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
+		     AR_ISR_TXEOL)) {
+			u32 s0_s, s1_s;
+
+			*masked |= ATH9K_INT_TX;
+
+			s0_s = REG_READ(ah, AR_ISR_S0_S);
+			ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
+			ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
+
+			s1_s = REG_READ(ah, AR_ISR_S1_S);
+			ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
+			ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
+		}
+
+		if (isr & AR_ISR_RXORN) {
+			DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
+				"receive FIFO overrun interrupt\n");
+		}
+
+		if (!AR_SREV_9100(ah)) {
+			if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+				u32 isr5 = REG_READ(ah, AR_ISR_S5_S);
+				if (isr5 & AR_ISR_S5_TIM_TIMER)
+					*masked |= ATH9K_INT_TIM_TIMER;
+			}
+		}
+
+		*masked |= mask2;
+	}
+
+	if (AR_SREV_9100(ah))
+		return true;
+
+	if (sync_cause) {
+		fatal_int =
+			(sync_cause &
+			 (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))
+			? true : false;
+
+		if (fatal_int) {
+			if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
+				DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+					"received PCI FATAL interrupt\n");
+			}
+			if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
+				DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+					"received PCI PERR interrupt\n");
+			}
+		}
+		if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
+			DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
+				"AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
+			REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
+			REG_WRITE(ah, AR_RC, 0);
+			*masked |= ATH9K_INT_FATAL;
+		}
+		if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) {
+			DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
+				"AR_INTR_SYNC_LOCAL_TIMEOUT\n");
+		}
+
+		REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
+		(void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
+	}
+
+	return true;
+}
+
+enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah)
+{
+	return AH5416(ah)->ah_maskReg;
+}
+
+enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 omask = ahp->ah_maskReg;
+	u32 mask, mask2;
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+	DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
+
+	if (omask & ATH9K_INT_GLOBAL) {
+		DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "disable IER\n");
+		REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
+		(void) REG_READ(ah, AR_IER);
+		if (!AR_SREV_9100(ah)) {
+			REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
+			(void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
+
+			REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
+			(void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
+		}
+	}
+
+	mask = ints & ATH9K_INT_COMMON;
+	mask2 = 0;
+
+	if (ints & ATH9K_INT_TX) {
+		if (ahp->ah_txOkInterruptMask)
+			mask |= AR_IMR_TXOK;
+		if (ahp->ah_txDescInterruptMask)
+			mask |= AR_IMR_TXDESC;
+		if (ahp->ah_txErrInterruptMask)
+			mask |= AR_IMR_TXERR;
+		if (ahp->ah_txEolInterruptMask)
+			mask |= AR_IMR_TXEOL;
+	}
+	if (ints & ATH9K_INT_RX) {
+		mask |= AR_IMR_RXERR;
+		if (ahp->ah_intrMitigation)
+			mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
+		else
+			mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
+		if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+			mask |= AR_IMR_GENTMR;
+	}
+
+	if (ints & (ATH9K_INT_BMISC)) {
+		mask |= AR_IMR_BCNMISC;
+		if (ints & ATH9K_INT_TIM)
+			mask2 |= AR_IMR_S2_TIM;
+		if (ints & ATH9K_INT_DTIM)
+			mask2 |= AR_IMR_S2_DTIM;
+		if (ints & ATH9K_INT_DTIMSYNC)
+			mask2 |= AR_IMR_S2_DTIMSYNC;
+		if (ints & ATH9K_INT_CABEND)
+			mask2 |= (AR_IMR_S2_CABEND);
+	}
+
+	if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) {
+		mask |= AR_IMR_BCNMISC;
+		if (ints & ATH9K_INT_GTT)
+			mask2 |= AR_IMR_S2_GTT;
+		if (ints & ATH9K_INT_CST)
+			mask2 |= AR_IMR_S2_CST;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
+	REG_WRITE(ah, AR_IMR, mask);
+	mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM |
+					   AR_IMR_S2_DTIM |
+					   AR_IMR_S2_DTIMSYNC |
+					   AR_IMR_S2_CABEND |
+					   AR_IMR_S2_CABTO |
+					   AR_IMR_S2_TSFOOR |
+					   AR_IMR_S2_GTT | AR_IMR_S2_CST);
+	REG_WRITE(ah, AR_IMR_S2, mask | mask2);
+	ahp->ah_maskReg = ints;
+
+	if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+		if (ints & ATH9K_INT_TIM_TIMER)
+			REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
+		else
+			REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
+	}
+
+	if (ints & ATH9K_INT_GLOBAL) {
+		DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "enable IER\n");
+		REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
+		if (!AR_SREV_9100(ah)) {
+			REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
+				  AR_INTR_MAC_IRQ);
+			REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
+
+
+			REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
+				  AR_INTR_SYNC_DEFAULT);
+			REG_WRITE(ah, AR_INTR_SYNC_MASK,
+				  AR_INTR_SYNC_DEFAULT);
+		}
+		DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
+			 REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
+	}
+
+	return omask;
+}
+
+/*******************/
+/* Beacon Handling */
+/*******************/
+
+void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	int flags = 0;
+
+	ahp->ah_beaconInterval = beacon_period;
+
+	switch (ah->ah_opmode) {
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_MONITOR:
+		REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
+		REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff);
+		REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff);
+		flags |= AR_TBTT_TIMER_EN;
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		REG_SET_BIT(ah, AR_TXCFG,
+			    AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
+		REG_WRITE(ah, AR_NEXT_NDP_TIMER,
+			  TU_TO_USEC(next_beacon +
+				     (ahp->ah_atimWindow ? ahp->
+				      ah_atimWindow : 1)));
+		flags |= AR_NDP_TIMER_EN;
+	case NL80211_IFTYPE_AP:
+		REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
+		REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
+			  TU_TO_USEC(next_beacon -
+				     ah->ah_config.
+				     dma_beacon_response_time));
+		REG_WRITE(ah, AR_NEXT_SWBA,
+			  TU_TO_USEC(next_beacon -
+				     ah->ah_config.
+				     sw_beacon_response_time));
+		flags |=
+			AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
+		break;
+	default:
+		DPRINTF(ah->ah_sc, ATH_DBG_BEACON,
+			"%s: unsupported opmode: %d\n",
+			__func__, ah->ah_opmode);
+		return;
+		break;
+	}
+
+	REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period));
+	REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period));
+	REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period));
+	REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
+
+	beacon_period &= ~ATH9K_BEACON_ENA;
+	if (beacon_period & ATH9K_BEACON_RESET_TSF) {
+		beacon_period &= ~ATH9K_BEACON_RESET_TSF;
+		ath9k_hw_reset_tsf(ah);
+	}
+
+	REG_SET_BIT(ah, AR_TIMER_MODE, flags);
+}
+
+void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
+				    const struct ath9k_beacon_state *bs)
+{
+	u32 nextTbtt, beaconintval, dtimperiod, beacontimeout;
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+	REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
+
+	REG_WRITE(ah, AR_BEACON_PERIOD,
+		  TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
+	REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
+		  TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
+
+	REG_RMW_FIELD(ah, AR_RSSI_THR,
+		      AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
+
+	beaconintval = bs->bs_intval & ATH9K_BEACON_PERIOD;
+
+	if (bs->bs_sleepduration > beaconintval)
+		beaconintval = bs->bs_sleepduration;
+
+	dtimperiod = bs->bs_dtimperiod;
+	if (bs->bs_sleepduration > dtimperiod)
+		dtimperiod = bs->bs_sleepduration;
+
+	if (beaconintval == dtimperiod)
+		nextTbtt = bs->bs_nextdtim;
+	else
+		nextTbtt = bs->bs_nexttbtt;
+
+	DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim);
+	DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt);
+	DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
+	DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
+
+	REG_WRITE(ah, AR_NEXT_DTIM,
+		  TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
+	REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));
+
+	REG_WRITE(ah, AR_SLEEP1,
+		  SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT)
+		  | AR_SLEEP1_ASSUME_DTIM);
+
+	if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)
+		beacontimeout = (BEACON_TIMEOUT_VAL << 3);
+	else
+		beacontimeout = MIN_BEACON_TIMEOUT_VAL;
+
+	REG_WRITE(ah, AR_SLEEP2,
+		  SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT));
+
+	REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
+	REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
+
+	REG_SET_BIT(ah, AR_TIMER_MODE,
+		    AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
+		    AR_DTIM_TIMER_EN);
+
+}
+
+/*******************/
+/* HW Capabilities */
+/*******************/
+
+bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	u16 capField = 0, eeval;
+
+	eeval = ath9k_hw_get_eeprom(ah, EEP_REG_0);
+
+	ah->ah_currentRD = eeval;
+
+	eeval = ath9k_hw_get_eeprom(ah, EEP_REG_1);
+	ah->ah_currentRDExt = eeval;
+
+	capField = ath9k_hw_get_eeprom(ah, EEP_OP_CAP);
+
+	if (ah->ah_opmode != NL80211_IFTYPE_AP &&
+	    ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) {
+		if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65)
+			ah->ah_currentRD += 5;
+		else if (ah->ah_currentRD == 0x41)
+			ah->ah_currentRD = 0x43;
+		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+			"regdomain mapped to 0x%x\n", ah->ah_currentRD);
+	}
+
+	eeval = ath9k_hw_get_eeprom(ah, EEP_OP_MODE);
+	bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX);
+
+	if (eeval & AR5416_OPFLAGS_11A) {
+		set_bit(ATH9K_MODE_11A, pCap->wireless_modes);
+		if (ah->ah_config.ht_enable) {
+			if (!(eeval & AR5416_OPFLAGS_N_5G_HT20))
+				set_bit(ATH9K_MODE_11NA_HT20,
+					pCap->wireless_modes);
+			if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) {
+				set_bit(ATH9K_MODE_11NA_HT40PLUS,
+					pCap->wireless_modes);
+				set_bit(ATH9K_MODE_11NA_HT40MINUS,
+					pCap->wireless_modes);
 			}
 		}
 	}
 
-	if (longcal) {
-		ath9k_hw_getnf(ah, ichan);
-		ath9k_hw_loadnf(ah, ah->ah_curchan);
-		ath9k_hw_start_nfcal(ah);
-
-		if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) {
-
-			chan->channelFlags |= CHANNEL_CW_INT;
-			ichan->channelFlags &= ~CHANNEL_CW_INT;
-		}
-	}
-
-	return true;
-}
-
-static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	int i;
-
-	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		ahp->ah_totalPowerMeasI[i] +=
-			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-		ahp->ah_totalPowerMeasQ[i] +=
-			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-		ahp->ah_totalIqCorrMeas[i] +=
-			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
-			 ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
-			 ahp->ah_totalPowerMeasQ[i],
-			 ahp->ah_totalIqCorrMeas[i]);
-	}
-}
-
-static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	int i;
-
-	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		ahp->ah_totalAdcIOddPhase[i] +=
-			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-		ahp->ah_totalAdcIEvenPhase[i] +=
-			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-		ahp->ah_totalAdcQOddPhase[i] +=
-			REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-		ahp->ah_totalAdcQEvenPhase[i] +=
-			REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
-
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
-			"oddq=0x%08x; evenq=0x%08x;\n",
-			 ahp->ah_CalSamples, i,
-			 ahp->ah_totalAdcIOddPhase[i],
-			 ahp->ah_totalAdcIEvenPhase[i],
-			 ahp->ah_totalAdcQOddPhase[i],
-			 ahp->ah_totalAdcQEvenPhase[i]);
-	}
-}
-
-static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	int i;
-
-	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-		ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
-			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-		ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
-			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-		ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
-			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-		ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
-			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
-
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
-			"oddq=0x%08x; evenq=0x%08x;\n",
-			 ahp->ah_CalSamples, i,
-			 ahp->ah_totalAdcDcOffsetIOddPhase[i],
-			 ahp->ah_totalAdcDcOffsetIEvenPhase[i],
-			 ahp->ah_totalAdcDcOffsetQOddPhase[i],
-			 ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
-	}
-}
-
-static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	u32 powerMeasQ, powerMeasI, iqCorrMeas;
-	u32 qCoffDenom, iCoffDenom;
-	int32_t qCoff, iCoff;
-	int iqCorrNeg, i;
-
-	for (i = 0; i < numChains; i++) {
-		powerMeasI = ahp->ah_totalPowerMeasI[i];
-		powerMeasQ = ahp->ah_totalPowerMeasQ[i];
-		iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
-
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Starting IQ Cal and Correction for Chain %d\n",
-			 i);
-
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Orignal: Chn %diq_corr_meas = 0x%08x\n",
-			 i, ahp->ah_totalIqCorrMeas[i]);
-
-		iqCorrNeg = 0;
-
-
-		if (iqCorrMeas > 0x80000000) {
-			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
-			iqCorrNeg = 1;
-		}
-
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
-			 iqCorrNeg);
-
-		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
-		qCoffDenom = powerMeasQ / 64;
-
-		if (powerMeasQ != 0) {
-
-			iCoff = iqCorrMeas / iCoffDenom;
-			qCoff = powerMeasI / qCoffDenom - 64;
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "Chn %d iCoff = 0x%08x\n", i, iCoff);
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "Chn %d qCoff = 0x%08x\n", i, qCoff);
-
-
-			iCoff = iCoff & 0x3f;
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
-			if (iqCorrNeg == 0x0)
-				iCoff = 0x40 - iCoff;
-
-			if (qCoff > 15)
-				qCoff = 15;
-			else if (qCoff <= -16)
-				qCoff = 16;
-
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
-				i, iCoff, qCoff);
-
-			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
-				      AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
-				      iCoff);
-			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
-				      AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
-				      qCoff);
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				"IQ Cal and Correction done for Chain %d\n",
-				i);
-		}
-	}
-
-	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
-		    AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
-}
-
-static void
-ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset,
-		qEvenMeasOffset;
-	u32 qGainMismatch, iGainMismatch, val, i;
-
-	for (i = 0; i < numChains; i++) {
-		iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
-		iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
-		qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
-		qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
-
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Starting ADC Gain Cal for Chain %d\n", i);
-
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
-			 iOddMeasOffset);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d pwr_meas_even_i = 0x%08x\n", i,
-			 iEvenMeasOffset);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
-			 qOddMeasOffset);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d pwr_meas_even_q = 0x%08x\n", i,
-			 qEvenMeasOffset);
-
-		if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
-			iGainMismatch =
-				((iEvenMeasOffset * 32) /
-				 iOddMeasOffset) & 0x3f;
-			qGainMismatch =
-				((qOddMeasOffset * 32) /
-				 qEvenMeasOffset) & 0x3f;
-
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "Chn %d gain_mismatch_i = 0x%08x\n", i,
-				 iGainMismatch);
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "Chn %d gain_mismatch_q = 0x%08x\n", i,
-				 qGainMismatch);
-
-			val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
-			val &= 0xfffff000;
-			val |= (qGainMismatch) | (iGainMismatch << 6);
-			REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
-
-			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-				 "ADC Gain Cal done for Chain %d\n", i);
-		}
-	}
-
-	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
-		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
-		  AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
-}
-
-static void
-ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	u32 iOddMeasOffset, iEvenMeasOffset, val, i;
-	int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
-	const struct hal_percal_data *calData =
-		ahp->ah_cal_list_curr->calData;
-	u32 numSamples =
-		(1 << (calData->calCountMax + 5)) * calData->calNumSamples;
-
-	for (i = 0; i < numChains; i++) {
-		iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
-		iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
-		qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
-		qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
-
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Starting ADC DC Offset Cal for Chain %d\n", i);
-
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d pwr_meas_odd_i = %d\n", i,
-			 iOddMeasOffset);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d pwr_meas_even_i = %d\n", i,
-			 iEvenMeasOffset);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d pwr_meas_odd_q = %d\n", i,
-			 qOddMeasOffset);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d pwr_meas_even_q = %d\n", i,
-			 qEvenMeasOffset);
-
-		iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
-			       numSamples) & 0x1ff;
-		qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
-			       numSamples) & 0x1ff;
-
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
-			 iDcMismatch);
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
-			 qDcMismatch);
-
-		val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
-		val &= 0xc0000fff;
-		val |= (qDcMismatch << 12) | (iDcMismatch << 21);
-		REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
-
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "ADC DC Offset Cal done for Chain %d\n", i);
-	}
-
-	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
-		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
-		  AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
-}
-
-bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_channel *chan = ah->ah_curchan;
-
-	ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER);
-
-	if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
-				 ath9k_regd_get_ctl(ah, chan),
-				 ath9k_regd_get_antenna_allowed(ah,
-								chan),
-				 chan->maxRegTxPower * 2,
-				 min((u32) MAX_RATE_POWER,
-				     (u32) ah->ah_powerLimit)) != 0)
-		return false;
-
-	return true;
-}
-
-void
-ath9k_hw_get_channel_centers(struct ath_hal *ah,
-			     struct ath9k_channel *chan,
-			     struct chan_centers *centers)
-{
-	int8_t extoff;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	if (!IS_CHAN_HT40(chan)) {
-		centers->ctl_center = centers->ext_center =
-			centers->synth_center = chan->channel;
-		return;
-	}
-
-	if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
-	    (chan->chanmode == CHANNEL_G_HT40PLUS)) {
-		centers->synth_center =
-			chan->channel + HT40_CHANNEL_CENTER_SHIFT;
-		extoff = 1;
-	} else {
-		centers->synth_center =
-			chan->channel - HT40_CHANNEL_CENTER_SHIFT;
-		extoff = -1;
-	}
-
-	centers->ctl_center = centers->synth_center - (extoff *
-		HT40_CHANNEL_CENTER_SHIFT);
-	centers->ext_center = centers->synth_center + (extoff *
-		((ahp->
-		ah_extprotspacing
-		==
-		ATH9K_HT_EXTPROTSPACING_20)
-		?
-		HT40_CHANNEL_CENTER_SHIFT
-		: 15));
-
-}
-
-void
-ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
-			bool *isCalDone)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_channel *ichan =
-		ath9k_regd_check_channel(ah, chan);
-	struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
-
-	*isCalDone = true;
-
-	if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
-		return;
-
-	if (currCal == NULL)
-		return;
-
-	if (ichan == NULL) {
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "%s: invalid channel %u/0x%x; no mapping\n",
-			 __func__, chan->channel, chan->channelFlags);
-		return;
-	}
-
-
-	if (currCal->calState != CAL_DONE) {
-		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-			 "%s: Calibration state incorrect, %d\n",
-			 __func__, currCal->calState);
-		return;
-	}
-
-
-	if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType))
-		return;
-
-	DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-		 "%s: Resetting Cal %d state for channel %u/0x%x\n",
-		 __func__, currCal->calData->calType, chan->channel,
-		 chan->channelFlags);
-
-	ichan->CalValid &= ~currCal->calData->calType;
-	currCal->calState = CAL_WAITING;
-
-	*isCalDone = false;
-}
-
-void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	memcpy(mac, ahp->ah_macaddr, ETH_ALEN);
-}
-
-bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	memcpy(ahp->ah_macaddr, mac, ETH_ALEN);
-	return true;
-}
-
-void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	memcpy(mask, ahp->ah_bssidmask, ETH_ALEN);
-}
-
-bool
-ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	memcpy(ahp->ah_bssidmask, mask, ETH_ALEN);
-
-	REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
-	REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
-
-	return true;
-}
-
-void
-ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
-		       u16 assocId)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	memcpy(ahp->ah_bssid, bssid, ETH_ALEN);
-	ahp->ah_assocId = assocId;
-
-	REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
-	REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
-		  ((assocId & 0x3fff) << AR_BSS_ID1_AID_S));
-}
-
-u64 ath9k_hw_gettsf64(struct ath_hal *ah)
-{
-	u64 tsf;
-
-	tsf = REG_READ(ah, AR_TSF_U32);
-	tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32);
-	return tsf;
-}
-
-void ath9k_hw_reset_tsf(struct ath_hal *ah)
-{
-	int count;
-
-	count = 0;
-	while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
-		count++;
-		if (count > 10) {
-			DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-			 "%s: AR_SLP32_TSF_WRITE_STATUS limit exceeded\n",
-				 __func__);
-			break;
-		}
-		udelay(10);
-	}
-	REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
-}
-
-u32 ath9k_hw_getdefantenna(struct ath_hal *ah)
-{
-	return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
-}
-
-void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna)
-{
-	REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
-}
-
-bool
-ath9k_hw_setantennaswitch(struct ath_hal *ah,
-			  enum ath9k_ant_setting settings,
-			  struct ath9k_channel *chan,
-			  u8 *tx_chainmask,
-			  u8 *rx_chainmask,
-			  u8 *antenna_cfgd)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	static u8 tx_chainmask_cfg, rx_chainmask_cfg;
-
-	if (AR_SREV_9280(ah)) {
-		if (!tx_chainmask_cfg) {
-
-			tx_chainmask_cfg = *tx_chainmask;
-			rx_chainmask_cfg = *rx_chainmask;
-		}
-
-		switch (settings) {
-		case ATH9K_ANT_FIXED_A:
-			*tx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
-			*rx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
-			*antenna_cfgd = true;
-			break;
-		case ATH9K_ANT_FIXED_B:
-			if (ah->ah_caps.tx_chainmask >
-			    ATH9K_ANTENNA1_CHAINMASK) {
-				*tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
+	if (eeval & AR5416_OPFLAGS_11G) {
+		set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
+		set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
+		if (ah->ah_config.ht_enable) {
+			if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
+				set_bit(ATH9K_MODE_11NG_HT20,
+					pCap->wireless_modes);
+			if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) {
+				set_bit(ATH9K_MODE_11NG_HT40PLUS,
+					pCap->wireless_modes);
+				set_bit(ATH9K_MODE_11NG_HT40MINUS,
+					pCap->wireless_modes);
 			}
-			*rx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
-			*antenna_cfgd = true;
-			break;
-		case ATH9K_ANT_VARIABLE:
-			*tx_chainmask = tx_chainmask_cfg;
-			*rx_chainmask = rx_chainmask_cfg;
-			*antenna_cfgd = true;
-			break;
-		default:
-			break;
 		}
-	} else {
-		ahp->ah_diversityControl = settings;
 	}
 
+	pCap->tx_chainmask = ath9k_hw_get_eeprom(ah, EEP_TX_MASK);
+	if ((ah->ah_isPciExpress)
+	    || (eeval & AR5416_OPFLAGS_11A)) {
+		pCap->rx_chainmask =
+			ath9k_hw_get_eeprom(ah, EEP_RX_MASK);
+	} else {
+		pCap->rx_chainmask =
+			(ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7;
+	}
+
+	if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0)))
+		ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA;
+
+	pCap->low_2ghz_chan = 2312;
+	pCap->high_2ghz_chan = 2732;
+
+	pCap->low_5ghz_chan = 4920;
+	pCap->high_5ghz_chan = 6100;
+
+	pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP;
+	pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP;
+	pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM;
+
+	pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP;
+	pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
+	pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
+
+	pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD;
+
+	if (ah->ah_config.ht_enable)
+		pCap->hw_caps |= ATH9K_HW_CAP_HT;
+	else
+		pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
+
+	pCap->hw_caps |= ATH9K_HW_CAP_GTT;
+	pCap->hw_caps |= ATH9K_HW_CAP_VEOL;
+	pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK;
+	pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH;
+
+	if (capField & AR_EEPROM_EEPCAP_MAXQCU)
+		pCap->total_queues =
+			MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
+	else
+		pCap->total_queues = ATH9K_NUM_TX_QUEUES;
+
+	if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES)
+		pCap->keycache_size =
+			1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES);
+	else
+		pCap->keycache_size = AR_KEYTABLE_SIZE;
+
+	pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
+	pCap->num_mr_retries = 4;
+	pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
+
+	if (AR_SREV_9280_10_OR_LATER(ah))
+		pCap->num_gpio_pins = AR928X_NUM_GPIO;
+	else
+		pCap->num_gpio_pins = AR_NUM_GPIO;
+
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		pCap->hw_caps |= ATH9K_HW_CAP_WOW;
+		pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
+	} else {
+		pCap->hw_caps &= ~ATH9K_HW_CAP_WOW;
+		pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
+	}
+
+	if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) {
+		pCap->hw_caps |= ATH9K_HW_CAP_CST;
+		pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX;
+	} else {
+		pCap->rts_aggr_limit = (8 * 1024);
+	}
+
+	pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
+
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+	ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT);
+	if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
+		ah->ah_rfkill_gpio =
+			MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
+		ah->ah_rfkill_polarity =
+			MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
+
+		pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
+	}
+#endif
+
+	if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
+	    (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
+	    (ah->ah_macVersion == AR_SREV_VERSION_9160) ||
+	    (ah->ah_macVersion == AR_SREV_VERSION_9100) ||
+	    (ah->ah_macVersion == AR_SREV_VERSION_9280))
+		pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
+	else
+		pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
+
+	if (AR_SREV_9280(ah) || AR_SREV_9285(ah))
+		pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
+	else
+		pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
+
+	if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) {
+		pCap->reg_cap =
+			AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
+			AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
+			AR_EEPROM_EEREGCAP_EN_KK_U2 |
+			AR_EEPROM_EEREGCAP_EN_KK_MIDBAND;
+	} else {
+		pCap->reg_cap =
+			AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
+			AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
+	}
+
+	pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
+
+	pCap->num_antcfg_5ghz =
+		ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ);
+	pCap->num_antcfg_2ghz =
+		ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
+
 	return true;
 }
 
-void ath9k_hw_setopmode(struct ath_hal *ah)
-{
-	ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
-}
-
-bool
-ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
-		       u32 capability, u32 *result)
+bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+			    u32 capability, u32 *result)
 {
 	struct ath_hal_5416 *ahp = AH5416(ah);
 	const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
@@ -6741,21 +3489,154 @@
 	}
 }
 
-int
-ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg)
+bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+			    u32 capability, u32 setting, int *status)
 {
 	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 v;
+
+	switch (type) {
+	case ATH9K_CAP_TKIP_MIC:
+		if (setting)
+			ahp->ah_staId1Defaults |=
+				AR_STA_ID1_CRPT_MIC_ENABLE;
+		else
+			ahp->ah_staId1Defaults &=
+				~AR_STA_ID1_CRPT_MIC_ENABLE;
+		return true;
+	case ATH9K_CAP_DIVERSITY:
+		v = REG_READ(ah, AR_PHY_CCK_DETECT);
+		if (setting)
+			v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+		else
+			v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+		REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
+		return true;
+	case ATH9K_CAP_MCAST_KEYSRCH:
+		if (setting)
+			ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;
+		else
+			ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;
+		return true;
+	case ATH9K_CAP_TSF_ADJUST:
+		if (setting)
+			ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
+		else
+			ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
+		return true;
+	default:
+		return false;
+	}
+}
+
+/****************************/
+/* GPIO / RFKILL / Antennae */
+/****************************/
+
+static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah,
+					 u32 gpio, u32 type)
+{
+	int addr;
+	u32 gpio_shift, tmp;
+
+	if (gpio > 11)
+		addr = AR_GPIO_OUTPUT_MUX3;
+	else if (gpio > 5)
+		addr = AR_GPIO_OUTPUT_MUX2;
+	else
+		addr = AR_GPIO_OUTPUT_MUX1;
+
+	gpio_shift = (gpio % 6) * 5;
+
+	if (AR_SREV_9280_20_OR_LATER(ah)
+	    || (addr != AR_GPIO_OUTPUT_MUX1)) {
+		REG_RMW(ah, addr, (type << gpio_shift),
+			(0x1f << gpio_shift));
+	} else {
+		tmp = REG_READ(ah, addr);
+		tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0);
+		tmp &= ~(0x1f << gpio_shift);
+		tmp |= (type << gpio_shift);
+		REG_WRITE(ah, addr, tmp);
+	}
+}
+
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
+{
+	u32 gpio_shift;
+
+	ASSERT(gpio < ah->ah_caps.num_gpio_pins);
+
+	gpio_shift = gpio << 1;
+
+	REG_RMW(ah,
+		AR_GPIO_OE_OUT,
+		(AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
+		(AR_GPIO_OE_OUT_DRV << gpio_shift));
+}
+
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
+{
+	if (gpio >= ah->ah_caps.num_gpio_pins)
+		return 0xffffffff;
+
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		return (MS
+			(REG_READ(ah, AR_GPIO_IN_OUT),
+			 AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0;
+	} else {
+		return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) &
+			AR_GPIO_BIT(gpio)) != 0;
+	}
+}
+
+void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
+			 u32 ah_signal_type)
+{
+	u32 gpio_shift;
+
+	ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
+
+	gpio_shift = 2 * gpio;
+
+	REG_RMW(ah,
+		AR_GPIO_OE_OUT,
+		(AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
+		(AR_GPIO_OE_OUT_DRV << gpio_shift));
+}
+
+void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
+{
+	REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
+		AR_GPIO_BIT(gpio));
+}
+
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+void ath9k_enable_rfkill(struct ath_hal *ah)
+{
+	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+		    AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
+
+	REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+		    AR_GPIO_INPUT_MUX2_RFSILENT);
+
+	ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
+	REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
+}
+#endif
+
+int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg)
+{
 	struct ath9k_channel *chan = ah->ah_curchan;
 	const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 	u16 ant_config;
 	u32 halNumAntConfig;
 
-	halNumAntConfig =
-		IS_CHAN_2GHZ(chan) ? pCap->num_antcfg_2ghz : pCap->
-		num_antcfg_5ghz;
+	halNumAntConfig = IS_CHAN_2GHZ(chan) ?
+		pCap->num_antcfg_2ghz : pCap->num_antcfg_5ghz;
 
 	if (cfg < halNumAntConfig) {
-		if (!ath9k_hw_get_eeprom_antenna_cfg(ahp, chan,
+		if (!ath9k_hw_get_eeprom_antenna_cfg(ah, chan,
 						     cfg, &ant_config)) {
 			REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
 			return 0;
@@ -6765,1699 +3646,212 @@
 	return -EINVAL;
 }
 
-bool ath9k_hw_intrpend(struct ath_hal *ah)
+u32 ath9k_hw_getdefantenna(struct ath_hal *ah)
 {
-	u32 host_isr;
-
-	if (AR_SREV_9100(ah))
-		return true;
-
-	host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
-	if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS))
-		return true;
-
-	host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE);
-	if ((host_isr & AR_INTR_SYNC_DEFAULT)
-	    && (host_isr != AR_INTR_SPURIOUS))
-		return true;
-
-	return false;
+	return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
 }
 
-bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
+void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna)
 {
-	u32 isr = 0;
-	u32 mask2 = 0;
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-	u32 sync_cause = 0;
-	bool fatal_int = false;
+	REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
+}
 
-	if (!AR_SREV_9100(ah)) {
-		if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
-			if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
-			    == AR_RTC_STATUS_ON) {
-				isr = REG_READ(ah, AR_ISR);
+bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
+			       enum ath9k_ant_setting settings,
+			       struct ath9k_channel *chan,
+			       u8 *tx_chainmask,
+			       u8 *rx_chainmask,
+			       u8 *antenna_cfgd)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	static u8 tx_chainmask_cfg, rx_chainmask_cfg;
+
+	if (AR_SREV_9280(ah)) {
+		if (!tx_chainmask_cfg) {
+
+			tx_chainmask_cfg = *tx_chainmask;
+			rx_chainmask_cfg = *rx_chainmask;
+		}
+
+		switch (settings) {
+		case ATH9K_ANT_FIXED_A:
+			*tx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
+			*rx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
+			*antenna_cfgd = true;
+			break;
+		case ATH9K_ANT_FIXED_B:
+			if (ah->ah_caps.tx_chainmask >
+			    ATH9K_ANTENNA1_CHAINMASK) {
+				*tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
 			}
+			*rx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
+			*antenna_cfgd = true;
+			break;
+		case ATH9K_ANT_VARIABLE:
+			*tx_chainmask = tx_chainmask_cfg;
+			*rx_chainmask = rx_chainmask_cfg;
+			*antenna_cfgd = true;
+			break;
+		default:
+			break;
 		}
-
-		sync_cause =
-			REG_READ(ah,
-				 AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT;
-
-		*masked = 0;
-
-		if (!isr && !sync_cause)
-			return false;
 	} else {
-		*masked = 0;
-		isr = REG_READ(ah, AR_ISR);
+		ahp->ah_diversityControl = settings;
 	}
 
-	if (isr) {
-		struct ath_hal_5416 *ahp = AH5416(ah);
-
-		if (isr & AR_ISR_BCNMISC) {
-			u32 isr2;
-			isr2 = REG_READ(ah, AR_ISR_S2);
-			if (isr2 & AR_ISR_S2_TIM)
-				mask2 |= ATH9K_INT_TIM;
-			if (isr2 & AR_ISR_S2_DTIM)
-				mask2 |= ATH9K_INT_DTIM;
-			if (isr2 & AR_ISR_S2_DTIMSYNC)
-				mask2 |= ATH9K_INT_DTIMSYNC;
-			if (isr2 & (AR_ISR_S2_CABEND))
-				mask2 |= ATH9K_INT_CABEND;
-			if (isr2 & AR_ISR_S2_GTT)
-				mask2 |= ATH9K_INT_GTT;
-			if (isr2 & AR_ISR_S2_CST)
-				mask2 |= ATH9K_INT_CST;
-		}
-
-		isr = REG_READ(ah, AR_ISR_RAC);
-		if (isr == 0xffffffff) {
-			*masked = 0;
-			return false;
-		}
-
-		*masked = isr & ATH9K_INT_COMMON;
-
-		if (ahp->ah_intrMitigation) {
-
-			if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
-				*masked |= ATH9K_INT_RX;
-		}
-
-		if (isr & (AR_ISR_RXOK | AR_ISR_RXERR))
-			*masked |= ATH9K_INT_RX;
-		if (isr &
-		    (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
-		     AR_ISR_TXEOL)) {
-			u32 s0_s, s1_s;
-
-			*masked |= ATH9K_INT_TX;
-
-			s0_s = REG_READ(ah, AR_ISR_S0_S);
-			ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
-			ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
-
-			s1_s = REG_READ(ah, AR_ISR_S1_S);
-			ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
-			ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
-		}
-
-		if (isr & AR_ISR_RXORN) {
-			DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
-				 "%s: receive FIFO overrun interrupt\n",
-				 __func__);
-		}
-
-		if (!AR_SREV_9100(ah)) {
-			if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
-				u32 isr5 = REG_READ(ah, AR_ISR_S5_S);
-				if (isr5 & AR_ISR_S5_TIM_TIMER)
-					*masked |= ATH9K_INT_TIM_TIMER;
-			}
-		}
-
-		*masked |= mask2;
-	}
-	if (AR_SREV_9100(ah))
-		return true;
-	if (sync_cause) {
-		fatal_int =
-			(sync_cause &
-			 (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))
-			? true : false;
-
-		if (fatal_int) {
-			if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
-				DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-					 "%s: received PCI FATAL interrupt\n",
-					 __func__);
-			}
-			if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
-				DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-					 "%s: received PCI PERR interrupt\n",
-					 __func__);
-			}
-		}
-		if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
-			DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
-				 "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n",
-				 __func__);
-			REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
-			REG_WRITE(ah, AR_RC, 0);
-			*masked |= ATH9K_INT_FATAL;
-		}
-		if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) {
-			DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
-				 "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n",
-				 __func__);
-		}
-
-		REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
-		(void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
-	}
 	return true;
 }
 
-enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah)
+/*********************/
+/* General Operation */
+/*********************/
+
+u32 ath9k_hw_getrxfilter(struct ath_hal *ah)
 {
-	return AH5416(ah)->ah_maskReg;
+	u32 bits = REG_READ(ah, AR_RX_FILTER);
+	u32 phybits = REG_READ(ah, AR_PHY_ERR);
+
+	if (phybits & AR_PHY_ERR_RADAR)
+		bits |= ATH9K_RX_FILTER_PHYRADAR;
+	if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING))
+		bits |= ATH9K_RX_FILTER_PHYERR;
+
+	return bits;
 }
 
-enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints)
+void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits)
 {
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	u32 omask = ahp->ah_maskReg;
-	u32 mask, mask2;
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	u32 phybits;
 
-	DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: 0x%x => 0x%x\n", __func__,
-		 omask, ints);
+	REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR);
+	phybits = 0;
+	if (bits & ATH9K_RX_FILTER_PHYRADAR)
+		phybits |= AR_PHY_ERR_RADAR;
+	if (bits & ATH9K_RX_FILTER_PHYERR)
+		phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
+	REG_WRITE(ah, AR_PHY_ERR, phybits);
 
-	if (omask & ATH9K_INT_GLOBAL) {
-		DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: disable IER\n",
-			 __func__);
-		REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
-		(void) REG_READ(ah, AR_IER);
-		if (!AR_SREV_9100(ah)) {
-			REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
-			(void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
-
-			REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
-			(void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
-		}
-	}
-
-	mask = ints & ATH9K_INT_COMMON;
-	mask2 = 0;
-
-	if (ints & ATH9K_INT_TX) {
-		if (ahp->ah_txOkInterruptMask)
-			mask |= AR_IMR_TXOK;
-		if (ahp->ah_txDescInterruptMask)
-			mask |= AR_IMR_TXDESC;
-		if (ahp->ah_txErrInterruptMask)
-			mask |= AR_IMR_TXERR;
-		if (ahp->ah_txEolInterruptMask)
-			mask |= AR_IMR_TXEOL;
-	}
-	if (ints & ATH9K_INT_RX) {
-		mask |= AR_IMR_RXERR;
-		if (ahp->ah_intrMitigation)
-			mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
-		else
-			mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
-		if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
-			mask |= AR_IMR_GENTMR;
-	}
-
-	if (ints & (ATH9K_INT_BMISC)) {
-		mask |= AR_IMR_BCNMISC;
-		if (ints & ATH9K_INT_TIM)
-			mask2 |= AR_IMR_S2_TIM;
-		if (ints & ATH9K_INT_DTIM)
-			mask2 |= AR_IMR_S2_DTIM;
-		if (ints & ATH9K_INT_DTIMSYNC)
-			mask2 |= AR_IMR_S2_DTIMSYNC;
-		if (ints & ATH9K_INT_CABEND)
-			mask2 |= (AR_IMR_S2_CABEND);
-	}
-
-	if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) {
-		mask |= AR_IMR_BCNMISC;
-		if (ints & ATH9K_INT_GTT)
-			mask2 |= AR_IMR_S2_GTT;
-		if (ints & ATH9K_INT_CST)
-			mask2 |= AR_IMR_S2_CST;
-	}
-
-	DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: new IMR 0x%x\n", __func__,
-		 mask);
-	REG_WRITE(ah, AR_IMR, mask);
-	mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM |
-					   AR_IMR_S2_DTIM |
-					   AR_IMR_S2_DTIMSYNC |
-					   AR_IMR_S2_CABEND |
-					   AR_IMR_S2_CABTO |
-					   AR_IMR_S2_TSFOOR |
-					   AR_IMR_S2_GTT | AR_IMR_S2_CST);
-	REG_WRITE(ah, AR_IMR_S2, mask | mask2);
-	ahp->ah_maskReg = ints;
-
-	if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
-		if (ints & ATH9K_INT_TIM_TIMER)
-			REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
-		else
-			REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
-	}
-
-	if (ints & ATH9K_INT_GLOBAL) {
-		DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: enable IER\n",
-			 __func__);
-		REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
-		if (!AR_SREV_9100(ah)) {
-			REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
-				  AR_INTR_MAC_IRQ);
-			REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
-
-
-			REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
-				  AR_INTR_SYNC_DEFAULT);
-			REG_WRITE(ah, AR_INTR_SYNC_MASK,
-				  AR_INTR_SYNC_DEFAULT);
-		}
-		DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
-			 REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
-	}
-
-	return omask;
-}
-
-void
-ath9k_hw_beaconinit(struct ath_hal *ah,
-		    u32 next_beacon, u32 beacon_period)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	int flags = 0;
-
-	ahp->ah_beaconInterval = beacon_period;
-
-	switch (ah->ah_opmode) {
-	case ATH9K_M_STA:
-	case ATH9K_M_MONITOR:
-		REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
-		REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff);
-		REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff);
-		flags |= AR_TBTT_TIMER_EN;
-		break;
-	case ATH9K_M_IBSS:
-		REG_SET_BIT(ah, AR_TXCFG,
-			    AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
-		REG_WRITE(ah, AR_NEXT_NDP_TIMER,
-			  TU_TO_USEC(next_beacon +
-				     (ahp->ah_atimWindow ? ahp->
-				      ah_atimWindow : 1)));
-		flags |= AR_NDP_TIMER_EN;
-	case ATH9K_M_HOSTAP:
-		REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
-		REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
-			  TU_TO_USEC(next_beacon -
-				     ah->ah_config.
-				     dma_beacon_response_time));
-		REG_WRITE(ah, AR_NEXT_SWBA,
-			  TU_TO_USEC(next_beacon -
-				     ah->ah_config.
-				     sw_beacon_response_time));
-		flags |=
-			AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
-		break;
-	}
-
-	REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period));
-	REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period));
-	REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period));
-	REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
-
-	beacon_period &= ~ATH9K_BEACON_ENA;
-	if (beacon_period & ATH9K_BEACON_RESET_TSF) {
-		beacon_period &= ~ATH9K_BEACON_RESET_TSF;
-		ath9k_hw_reset_tsf(ah);
-	}
-
-	REG_SET_BIT(ah, AR_TIMER_MODE, flags);
-}
-
-void
-ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
-			       const struct ath9k_beacon_state *bs)
-{
-	u32 nextTbtt, beaconintval, dtimperiod, beacontimeout;
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-
-	REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
-
-	REG_WRITE(ah, AR_BEACON_PERIOD,
-		  TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
-	REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
-		  TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
-
-	REG_RMW_FIELD(ah, AR_RSSI_THR,
-		      AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
-
-	beaconintval = bs->bs_intval & ATH9K_BEACON_PERIOD;
-
-	if (bs->bs_sleepduration > beaconintval)
-		beaconintval = bs->bs_sleepduration;
-
-	dtimperiod = bs->bs_dtimperiod;
-	if (bs->bs_sleepduration > dtimperiod)
-		dtimperiod = bs->bs_sleepduration;
-
-	if (beaconintval == dtimperiod)
-		nextTbtt = bs->bs_nextdtim;
+	if (phybits)
+		REG_WRITE(ah, AR_RXCFG,
+			  REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
 	else
-		nextTbtt = bs->bs_nexttbtt;
-
-	DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next DTIM %d\n", __func__,
-		 bs->bs_nextdtim);
-	DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next beacon %d\n", __func__,
-		 nextTbtt);
-	DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: beacon period %d\n", __func__,
-		 beaconintval);
-	DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: DTIM period %d\n", __func__,
-		 dtimperiod);
-
-	REG_WRITE(ah, AR_NEXT_DTIM,
-		  TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
-	REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));
-
-	REG_WRITE(ah, AR_SLEEP1,
-		  SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT)
-		  | AR_SLEEP1_ASSUME_DTIM);
-
-	if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)
-		beacontimeout = (BEACON_TIMEOUT_VAL << 3);
-	else
-		beacontimeout = MIN_BEACON_TIMEOUT_VAL;
-
-	REG_WRITE(ah, AR_SLEEP2,
-		  SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT));
-
-	REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
-	REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
-
-	REG_SET_BIT(ah, AR_TIMER_MODE,
-		    AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
-		    AR_DTIM_TIMER_EN);
-
+		REG_WRITE(ah, AR_RXCFG,
+			  REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
 }
 
-bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry)
+bool ath9k_hw_phy_disable(struct ath_hal *ah)
 {
-	if (entry < ah->ah_caps.keycache_size) {
-		u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
-		if (val & AR_KEYTABLE_VALID)
-			return true;
-	}
-	return false;
+	return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM);
 }
 
-bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry)
+bool ath9k_hw_disable(struct ath_hal *ah)
 {
-	u32 keyType;
-
-	if (entry >= ah->ah_caps.keycache_size) {
-		DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-			 "%s: entry %u out of range\n", __func__, entry);
+	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
 		return false;
-	}
-	keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
 
-	REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
-	REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
-	REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
-	REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
-	REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
-	REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
-	REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
-	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
-
-	if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
-		u16 micentry = entry + 64;
-
-		REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
-		REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
-		REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
-		REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
-
-	}
-
-	if (ah->ah_curchan == NULL)
-		return true;
-
-	return true;
+	return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
 }
 
-bool
-ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry,
-		   const u8 *mac)
+bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit)
 {
-	u32 macHi, macLo;
-
-	if (entry >= ah->ah_caps.keycache_size) {
-		DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-			 "%s: entry %u out of range\n", __func__, entry);
-		return false;
-	}
-
-	if (mac != NULL) {
-		macHi = (mac[5] << 8) | mac[4];
-		macLo = (mac[3] << 24) | (mac[2] << 16)
-			| (mac[1] << 8) | mac[0];
-		macLo >>= 1;
-		macLo |= (macHi & 1) << 31;
-		macHi >>= 1;
-	} else {
-		macLo = macHi = 0;
-	}
-	REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
-	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID);
-
-	return true;
-}
-
-bool
-ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
-			    const struct ath9k_keyval *k,
-			    const u8 *mac, int xorKey)
-{
-	const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-	u32 key0, key1, key2, key3, key4;
-	u32 keyType;
-	u32 xorMask = xorKey ?
-		(ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8
-		 | ATH9K_KEY_XOR) : 0;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	if (entry >= pCap->keycache_size) {
-		DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-			 "%s: entry %u out of range\n", __func__, entry);
-		return false;
-	}
-	switch (k->kv_type) {
-	case ATH9K_CIPHER_AES_OCB:
-		keyType = AR_KEYTABLE_TYPE_AES;
-		break;
-	case ATH9K_CIPHER_AES_CCM:
-		if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
-			DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-				 "%s: AES-CCM not supported by "
-				 "mac rev 0x%x\n", __func__,
-				 ah->ah_macRev);
-			return false;
-		}
-		keyType = AR_KEYTABLE_TYPE_CCM;
-		break;
-	case ATH9K_CIPHER_TKIP:
-		keyType = AR_KEYTABLE_TYPE_TKIP;
-		if (ATH9K_IS_MIC_ENABLED(ah)
-		    && entry + 64 >= pCap->keycache_size) {
-			DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-				 "%s: entry %u inappropriate for TKIP\n",
-				 __func__, entry);
-			return false;
-		}
-		break;
-	case ATH9K_CIPHER_WEP:
-		if (k->kv_len < LEN_WEP40) {
-			DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-				 "%s: WEP key length %u too small\n",
-				 __func__, k->kv_len);
-			return false;
-		}
-		if (k->kv_len <= LEN_WEP40)
-			keyType = AR_KEYTABLE_TYPE_40;
-		else if (k->kv_len <= LEN_WEP104)
-			keyType = AR_KEYTABLE_TYPE_104;
-		else
-			keyType = AR_KEYTABLE_TYPE_128;
-		break;
-	case ATH9K_CIPHER_CLR:
-		keyType = AR_KEYTABLE_TYPE_CLR;
-		break;
-	default:
-		DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-			 "%s: cipher %u not supported\n", __func__,
-			 k->kv_type);
-		return false;
-	}
-
-	key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask;
-	key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff;
-	key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask;
-	key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff;
-	key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask;
-	if (k->kv_len <= LEN_WEP104)
-		key4 &= 0xff;
-
-	if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
-		u16 micentry = entry + 64;
-
-		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
-		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
-		REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
-		REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
-		REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
-		REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
-		(void) ath9k_hw_keysetmac(ah, entry, mac);
-
-		if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) {
-			u32 mic0, mic1, mic2, mic3, mic4;
-
-			mic0 = get_unaligned_le32(k->kv_mic + 0);
-			mic2 = get_unaligned_le32(k->kv_mic + 4);
-			mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
-			mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
-			mic4 = get_unaligned_le32(k->kv_txmic + 4);
-			REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
-			REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
-			REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
-			REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
-			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
-			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
-				  AR_KEYTABLE_TYPE_CLR);
-
-		} else {
-			u32 mic0, mic2;
-
-			mic0 = get_unaligned_le32(k->kv_mic + 0);
-			mic2 = get_unaligned_le32(k->kv_mic + 4);
-			REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
-			REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
-			REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
-			REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
-			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
-			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
-				  AR_KEYTABLE_TYPE_CLR);
-		}
-		REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
-		REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
-		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
-		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
-	} else {
-		REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
-		REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
-		REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
-		REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
-		REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
-		REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
-
-		(void) ath9k_hw_keysetmac(ah, entry, mac);
-	}
-
-	if (ah->ah_curchan == NULL)
-		return true;
-
-	return true;
-}
-
-bool
-ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	u32 txcfg, curLevel, newLevel;
-	enum ath9k_int omask;
-
-	if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD)
-		return false;
-
-	omask = ath9k_hw_set_interrupts(ah,
-					ahp->ah_maskReg & ~ATH9K_INT_GLOBAL);
-
-	txcfg = REG_READ(ah, AR_TXCFG);
-	curLevel = MS(txcfg, AR_FTRIG);
-	newLevel = curLevel;
-	if (bIncTrigLevel) {
-		if (curLevel < MAX_TX_FIFO_THRESHOLD)
-			newLevel++;
-	} else if (curLevel > MIN_TX_FIFO_THRESHOLD)
-		newLevel--;
-	if (newLevel != curLevel)
-		REG_WRITE(ah, AR_TXCFG,
-			  (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
-
-	ath9k_hw_set_interrupts(ah, omask);
-
-	ah->ah_txTrigLevel = newLevel;
-
-	return newLevel != curLevel;
-}
-
-bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
-			    const struct ath9k_tx_queue_info *qinfo)
-{
-	u32 cw;
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-	struct ath9k_tx_queue_info *qi;
-
-	if (q >= pCap->total_queues) {
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
-			 __func__, q);
-		return false;
-	}
-
-	qi = &ahp->ah_txq[q];
-	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
-			 __func__);
-		return false;
-	}
-
-	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi);
-
-	qi->tqi_ver = qinfo->tqi_ver;
-	qi->tqi_subtype = qinfo->tqi_subtype;
-	qi->tqi_qflags = qinfo->tqi_qflags;
-	qi->tqi_priority = qinfo->tqi_priority;
-	if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
-		qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
-	else
-		qi->tqi_aifs = INIT_AIFS;
-	if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
-		cw = min(qinfo->tqi_cwmin, 1024U);
-		qi->tqi_cwmin = 1;
-		while (qi->tqi_cwmin < cw)
-			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
-	} else
-		qi->tqi_cwmin = qinfo->tqi_cwmin;
-	if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
-		cw = min(qinfo->tqi_cwmax, 1024U);
-		qi->tqi_cwmax = 1;
-		while (qi->tqi_cwmax < cw)
-			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
-	} else
-		qi->tqi_cwmax = INIT_CWMAX;
-
-	if (qinfo->tqi_shretry != 0)
-		qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
-	else
-		qi->tqi_shretry = INIT_SH_RETRY;
-	if (qinfo->tqi_lgretry != 0)
-		qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
-	else
-		qi->tqi_lgretry = INIT_LG_RETRY;
-	qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
-	qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
-	qi->tqi_burstTime = qinfo->tqi_burstTime;
-	qi->tqi_readyTime = qinfo->tqi_readyTime;
-
-	switch (qinfo->tqi_subtype) {
-	case ATH9K_WME_UPSD:
-		if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
-			qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
-		break;
-	default:
-		break;
-	}
-	return true;
-}
-
-bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
-			    struct ath9k_tx_queue_info *qinfo)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-	struct ath9k_tx_queue_info *qi;
-
-	if (q >= pCap->total_queues) {
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
-			 __func__, q);
-		return false;
-	}
-
-	qi = &ahp->ah_txq[q];
-	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
-			 __func__);
-		return false;
-	}
-
-	qinfo->tqi_qflags = qi->tqi_qflags;
-	qinfo->tqi_ver = qi->tqi_ver;
-	qinfo->tqi_subtype = qi->tqi_subtype;
-	qinfo->tqi_qflags = qi->tqi_qflags;
-	qinfo->tqi_priority = qi->tqi_priority;
-	qinfo->tqi_aifs = qi->tqi_aifs;
-	qinfo->tqi_cwmin = qi->tqi_cwmin;
-	qinfo->tqi_cwmax = qi->tqi_cwmax;
-	qinfo->tqi_shretry = qi->tqi_shretry;
-	qinfo->tqi_lgretry = qi->tqi_lgretry;
-	qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
-	qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
-	qinfo->tqi_burstTime = qi->tqi_burstTime;
-	qinfo->tqi_readyTime = qi->tqi_readyTime;
-
-	return true;
-}
-
-int
-ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
-		      const struct ath9k_tx_queue_info *qinfo)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_tx_queue_info *qi;
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-	int q;
-
-	switch (type) {
-	case ATH9K_TX_QUEUE_BEACON:
-		q = pCap->total_queues - 1;
-		break;
-	case ATH9K_TX_QUEUE_CAB:
-		q = pCap->total_queues - 2;
-		break;
-	case ATH9K_TX_QUEUE_PSPOLL:
-		q = 1;
-		break;
-	case ATH9K_TX_QUEUE_UAPSD:
-		q = pCap->total_queues - 3;
-		break;
-	case ATH9K_TX_QUEUE_DATA:
-		for (q = 0; q < pCap->total_queues; q++)
-			if (ahp->ah_txq[q].tqi_type ==
-			    ATH9K_TX_QUEUE_INACTIVE)
-				break;
-		if (q == pCap->total_queues) {
-			DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-				 "%s: no available tx queue\n", __func__);
-			return -1;
-		}
-		break;
-	default:
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: bad tx queue type %u\n",
-			 __func__, type);
-		return -1;
-	}
-
-	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
-
-	qi = &ahp->ah_txq[q];
-	if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-			 "%s: tx queue %u already active\n", __func__, q);
-		return -1;
-	}
-	memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
-	qi->tqi_type = type;
-	if (qinfo == NULL) {
-		qi->tqi_qflags =
-			TXQ_FLAG_TXOKINT_ENABLE
-			| TXQ_FLAG_TXERRINT_ENABLE
-			| TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
-		qi->tqi_aifs = INIT_AIFS;
-		qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
-		qi->tqi_cwmax = INIT_CWMAX;
-		qi->tqi_shretry = INIT_SH_RETRY;
-		qi->tqi_lgretry = INIT_LG_RETRY;
-		qi->tqi_physCompBuf = 0;
-	} else {
-		qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
-		(void) ath9k_hw_set_txq_props(ah, q, qinfo);
-	}
-
-	return q;
-}
-
-static void
-ath9k_hw_set_txq_interrupts(struct ath_hal *ah,
-			    struct ath9k_tx_queue_info *qi)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
-		 "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
-		 __func__, ahp->ah_txOkInterruptMask,
-		 ahp->ah_txErrInterruptMask, ahp->ah_txDescInterruptMask,
-		 ahp->ah_txEolInterruptMask, ahp->ah_txUrnInterruptMask);
-
-	REG_WRITE(ah, AR_IMR_S0,
-		  SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
-		  | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC));
-	REG_WRITE(ah, AR_IMR_S1,
-		  SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
-		  | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL));
-	REG_RMW_FIELD(ah, AR_IMR_S2,
-		      AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
-}
-
-bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-	struct ath9k_tx_queue_info *qi;
-
-	if (q >= pCap->total_queues) {
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
-			 __func__, q);
-		return false;
-	}
-	qi = &ahp->ah_txq[q];
-	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
-			 __func__, q);
-		return false;
-	}
-
-	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: release queue %u\n",
-		__func__, q);
-
-	qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
-	ahp->ah_txOkInterruptMask &= ~(1 << q);
-	ahp->ah_txErrInterruptMask &= ~(1 << q);
-	ahp->ah_txDescInterruptMask &= ~(1 << q);
-	ahp->ah_txEolInterruptMask &= ~(1 << q);
-	ahp->ah_txUrnInterruptMask &= ~(1 << q);
-	ath9k_hw_set_txq_interrupts(ah, qi);
-
-	return true;
-}
-
-bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 	struct ath9k_channel *chan = ah->ah_curchan;
-	struct ath9k_tx_queue_info *qi;
-	u32 cwMin, chanCwMin, value;
 
-	if (q >= pCap->total_queues) {
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
-			 __func__, q);
+	ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER);
+
+	if (ath9k_hw_set_txpower(ah, chan,
+				 ath9k_regd_get_ctl(ah, chan),
+				 ath9k_regd_get_antenna_allowed(ah, chan),
+				 chan->maxRegTxPower * 2,
+				 min((u32) MAX_RATE_POWER,
+				     (u32) ah->ah_powerLimit)) != 0)
 		return false;
-	}
-	qi = &ahp->ah_txq[q];
-	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
-			 __func__, q);
-		return true;
-	}
-
-	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: reset queue %u\n", __func__, q);
-
-	if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
-		if (chan && IS_CHAN_B(chan))
-			chanCwMin = INIT_CWMIN_11B;
-		else
-			chanCwMin = INIT_CWMIN;
-
-		for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
-	} else
-		cwMin = qi->tqi_cwmin;
-
-	REG_WRITE(ah, AR_DLCL_IFS(q), SM(cwMin, AR_D_LCL_IFS_CWMIN)
-		  | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX)
-		  | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
-
-	REG_WRITE(ah, AR_DRETRY_LIMIT(q),
-		  SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH)
-		  | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG)
-		  | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
-
-	REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
-	REG_WRITE(ah, AR_DMISC(q),
-		  AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
-
-	if (qi->tqi_cbrPeriod) {
-		REG_WRITE(ah, AR_QCBRCFG(q),
-			  SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL)
-			  | SM(qi->tqi_cbrOverflowLimit,
-			       AR_Q_CBRCFG_OVF_THRESH));
-		REG_WRITE(ah, AR_QMISC(q),
-			  REG_READ(ah,
-				   AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | (qi->
-					tqi_cbrOverflowLimit
-					?
-					AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN
-					:
-					0));
-	}
-	if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
-		REG_WRITE(ah, AR_QRDYTIMECFG(q),
-			  SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
-			  AR_Q_RDYTIMECFG_EN);
-	}
-
-	REG_WRITE(ah, AR_DCHNTIME(q),
-		  SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
-		  (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
-
-	if (qi->tqi_burstTime
-	    && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
-		REG_WRITE(ah, AR_QMISC(q),
-			  REG_READ(ah,
-				   AR_QMISC(q)) |
-			  AR_Q_MISC_RDYTIME_EXP_POLICY);
-
-	}
-
-	if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
-		REG_WRITE(ah, AR_DMISC(q),
-			  REG_READ(ah, AR_DMISC(q)) |
-			  AR_D_MISC_POST_FR_BKOFF_DIS);
-	}
-	if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
-		REG_WRITE(ah, AR_DMISC(q),
-			  REG_READ(ah, AR_DMISC(q)) |
-			  AR_D_MISC_FRAG_BKOFF_EN);
-	}
-	switch (qi->tqi_type) {
-	case ATH9K_TX_QUEUE_BEACON:
-		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
-			  | AR_Q_MISC_FSP_DBA_GATED
-			  | AR_Q_MISC_BEACON_USE
-			  | AR_Q_MISC_CBR_INCR_DIS1);
-
-		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
-			  | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
-			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
-			  | AR_D_MISC_BEACON_USE
-			  | AR_D_MISC_POST_FR_BKOFF_DIS);
-		break;
-	case ATH9K_TX_QUEUE_CAB:
-		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
-			  | AR_Q_MISC_FSP_DBA_GATED
-			  | AR_Q_MISC_CBR_INCR_DIS1
-			  | AR_Q_MISC_CBR_INCR_DIS0);
-		value = (qi->tqi_readyTime
-			 - (ah->ah_config.sw_beacon_response_time -
-			    ah->ah_config.dma_beacon_response_time)
-			 -
-			 ah->ah_config.additional_swba_backoff) *
-			1024;
-		REG_WRITE(ah, AR_QRDYTIMECFG(q),
-			  value | AR_Q_RDYTIMECFG_EN);
-		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
-			  | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
-			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
-		break;
-	case ATH9K_TX_QUEUE_PSPOLL:
-		REG_WRITE(ah, AR_QMISC(q),
-			  REG_READ(ah,
-				   AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
-		break;
-	case ATH9K_TX_QUEUE_UAPSD:
-		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
-			  | AR_D_MISC_POST_FR_BKOFF_DIS);
-		break;
-	default:
-		break;
-	}
-
-	if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
-		REG_WRITE(ah, AR_DMISC(q),
-			  REG_READ(ah, AR_DMISC(q)) |
-			  SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
-			     AR_D_MISC_ARB_LOCKOUT_CNTRL) |
-			  AR_D_MISC_POST_FR_BKOFF_DIS);
-	}
-
-	if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
-		ahp->ah_txOkInterruptMask |= 1 << q;
-	else
-		ahp->ah_txOkInterruptMask &= ~(1 << q);
-	if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
-		ahp->ah_txErrInterruptMask |= 1 << q;
-	else
-		ahp->ah_txErrInterruptMask &= ~(1 << q);
-	if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
-		ahp->ah_txDescInterruptMask |= 1 << q;
-	else
-		ahp->ah_txDescInterruptMask &= ~(1 << q);
-	if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
-		ahp->ah_txEolInterruptMask |= 1 << q;
-	else
-		ahp->ah_txEolInterruptMask &= ~(1 << q);
-	if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
-		ahp->ah_txUrnInterruptMask |= 1 << q;
-	else
-		ahp->ah_txUrnInterruptMask &= ~(1 << q);
-	ath9k_hw_set_txq_interrupts(ah, qi);
 
 	return true;
 }
 
-void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs)
+void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac)
 {
 	struct ath_hal_5416 *ahp = AH5416(ah);
-	*txqs &= ahp->ah_intrTxqs;
-	ahp->ah_intrTxqs &= ~(*txqs);
+
+	memcpy(mac, ahp->ah_macaddr, ETH_ALEN);
 }
 
-bool
-ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
-		    u32 segLen, bool firstSeg,
-		    bool lastSeg, const struct ath_desc *ds0)
+bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac)
 {
-	struct ar5416_desc *ads = AR5416DESC(ds);
-
-	if (firstSeg) {
-		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
-	} else if (lastSeg) {
-		ads->ds_ctl0 = 0;
-		ads->ds_ctl1 = segLen;
-		ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
-		ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
-	} else {
-		ads->ds_ctl0 = 0;
-		ads->ds_ctl1 = segLen | AR_TxMore;
-		ads->ds_ctl2 = 0;
-		ads->ds_ctl3 = 0;
-	}
-	ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
-	ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
-	ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
-	ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
-	ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
-	return true;
-}
-
-void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
-{
-	struct ar5416_desc *ads = AR5416DESC(ds);
-
-	ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
-	ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
-	ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
-	ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
-	ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
-}
-
-int
-ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
-{
-	struct ar5416_desc *ads = AR5416DESC(ds);
-
-	if ((ads->ds_txstatus9 & AR_TxDone) == 0)
-		return -EINPROGRESS;
-
-	ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
-	ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
-	ds->ds_txstat.ts_status = 0;
-	ds->ds_txstat.ts_flags = 0;
-
-	if (ads->ds_txstatus1 & AR_ExcessiveRetries)
-		ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
-	if (ads->ds_txstatus1 & AR_Filtered)
-		ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
-	if (ads->ds_txstatus1 & AR_FIFOUnderrun)
-		ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
-	if (ads->ds_txstatus9 & AR_TxOpExceeded)
-		ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
-	if (ads->ds_txstatus1 & AR_TxTimerExpired)
-		ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
-
-	if (ads->ds_txstatus1 & AR_DescCfgErr)
-		ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
-	if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
-		ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
-		ath9k_hw_updatetxtriglevel(ah, true);
-	}
-	if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
-		ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
-		ath9k_hw_updatetxtriglevel(ah, true);
-	}
-	if (ads->ds_txstatus0 & AR_TxBaStatus) {
-		ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
-		ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
-		ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
-	}
-
-	ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
-	switch (ds->ds_txstat.ts_rateindex) {
-	case 0:
-		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
-		break;
-	case 1:
-		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
-		break;
-	case 2:
-		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
-		break;
-	case 3:
-		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
-		break;
-	}
-
-	ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
-	ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
-	ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
-	ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
-	ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
-	ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
-	ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
-	ds->ds_txstat.evm0 = ads->AR_TxEVM0;
-	ds->ds_txstat.evm1 = ads->AR_TxEVM1;
-	ds->ds_txstat.evm2 = ads->AR_TxEVM2;
-	ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
-	ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
-	ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
-	ds->ds_txstat.ts_antenna = 1;
-
-	return 0;
-}
-
-void
-ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
-		       u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
-		       u32 keyIx, enum ath9k_key_type keyType, u32 flags)
-{
-	struct ar5416_desc *ads = AR5416DESC(ds);
 	struct ath_hal_5416 *ahp = AH5416(ah);
 
-	txPower += ahp->ah_txPowerIndexOffset;
-	if (txPower > 63)
-		txPower = 63;
-
-	ads->ds_ctl0 = (pktLen & AR_FrameLen)
-		| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
-		| SM(txPower, AR_XmitPower)
-		| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
-		| (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
-		| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
-		| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
-
-	ads->ds_ctl1 =
-		(keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
-		| SM(type, AR_FrameType)
-		| (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
-		| (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
-		| (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
-
-	ads->ds_ctl6 = SM(keyType, AR_EncrType);
-
-	if (AR_SREV_9285(ah)) {
-
-		ads->ds_ctl8 = 0;
-		ads->ds_ctl9 = 0;
-		ads->ds_ctl10 = 0;
-		ads->ds_ctl11 = 0;
-	}
-}
-
-void
-ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
-			     struct ath_desc *lastds,
-			     u32 durUpdateEn, u32 rtsctsRate,
-			     u32 rtsctsDuration,
-			     struct ath9k_11n_rate_series series[],
-			     u32 nseries, u32 flags)
-{
-	struct ar5416_desc *ads = AR5416DESC(ds);
-	struct ar5416_desc *last_ads = AR5416DESC(lastds);
-	u32 ds_ctl0;
-
-	(void) nseries;
-	(void) rtsctsDuration;
-
-	if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
-		ds_ctl0 = ads->ds_ctl0;
-
-		if (flags & ATH9K_TXDESC_RTSENA) {
-			ds_ctl0 &= ~AR_CTSEnable;
-			ds_ctl0 |= AR_RTSEnable;
-		} else {
-			ds_ctl0 &= ~AR_RTSEnable;
-			ds_ctl0 |= AR_CTSEnable;
-		}
-
-		ads->ds_ctl0 = ds_ctl0;
-	} else {
-		ads->ds_ctl0 =
-			(ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
-	}
-
-	ads->ds_ctl2 = set11nTries(series, 0)
-		| set11nTries(series, 1)
-		| set11nTries(series, 2)
-		| set11nTries(series, 3)
-		| (durUpdateEn ? AR_DurUpdateEna : 0)
-		| SM(0, AR_BurstDur);
-
-	ads->ds_ctl3 = set11nRate(series, 0)
-		| set11nRate(series, 1)
-		| set11nRate(series, 2)
-		| set11nRate(series, 3);
-
-	ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
-		| set11nPktDurRTSCTS(series, 1);
-
-	ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
-		| set11nPktDurRTSCTS(series, 3);
-
-	ads->ds_ctl7 = set11nRateFlags(series, 0)
-		| set11nRateFlags(series, 1)
-		| set11nRateFlags(series, 2)
-		| set11nRateFlags(series, 3)
-		| SM(rtsctsRate, AR_RTSCTSRate);
-	last_ads->ds_ctl2 = ads->ds_ctl2;
-	last_ads->ds_ctl3 = ads->ds_ctl3;
-}
-
-void
-ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
-			   u32 aggrLen)
-{
-	struct ar5416_desc *ads = AR5416DESC(ds);
-
-	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
-
-	ads->ds_ctl6 &= ~AR_AggrLen;
-	ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
-}
-
-void
-ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
-			    u32 numDelims)
-{
-	struct ar5416_desc *ads = AR5416DESC(ds);
-	unsigned int ctl6;
-
-	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
-
-	ctl6 = ads->ds_ctl6;
-	ctl6 &= ~AR_PadDelim;
-	ctl6 |= SM(numDelims, AR_PadDelim);
-	ads->ds_ctl6 = ctl6;
-}
-
-void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
-{
-	struct ar5416_desc *ads = AR5416DESC(ds);
-
-	ads->ds_ctl1 |= AR_IsAggr;
-	ads->ds_ctl1 &= ~AR_MoreAggr;
-	ads->ds_ctl6 &= ~AR_PadDelim;
-}
-
-void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds)
-{
-	struct ar5416_desc *ads = AR5416DESC(ds);
-
-	ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
-}
-
-void
-ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
-			      u32 burstDuration)
-{
-	struct ar5416_desc *ads = AR5416DESC(ds);
-
-	ads->ds_ctl2 &= ~AR_BurstDur;
-	ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
-}
-
-void
-ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
-				u32 vmf)
-{
-	struct ar5416_desc *ads = AR5416DESC(ds);
-
-	if (vmf)
-		ads->ds_ctl0 |= AR_VirtMoreFrag;
-	else
-		ads->ds_ctl0 &= ~AR_VirtMoreFrag;
-}
-
-void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp)
-{
-	REG_WRITE(ah, AR_RXDP, rxdp);
-}
-
-void ath9k_hw_rxena(struct ath_hal *ah)
-{
-	REG_WRITE(ah, AR_CR, AR_CR_RXE);
-}
-
-bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
-{
-	if (set) {
-
-		REG_SET_BIT(ah, AR_DIAG_SW,
-			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
-
-		if (!ath9k_hw_wait
-		    (ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) {
-			u32 reg;
-
-			REG_CLR_BIT(ah, AR_DIAG_SW,
-				    (AR_DIAG_RX_DIS |
-				     AR_DIAG_RX_ABORT));
-
-			reg = REG_READ(ah, AR_OBS_BUS_1);
-			DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
-				"%s: rx failed to go idle in 10 ms RXSM=0x%x\n",
-				__func__, reg);
-
-			return false;
-		}
-	} else {
-		REG_CLR_BIT(ah, AR_DIAG_SW,
-			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
-	}
+	memcpy(ahp->ah_macaddr, mac, ETH_ALEN);
 
 	return true;
 }
 
-void
-ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0,
-			u32 filter1)
+void ath9k_hw_setopmode(struct ath_hal *ah)
+{
+	ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
+}
+
+void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1)
 {
 	REG_WRITE(ah, AR_MCAST_FIL0, filter0);
 	REG_WRITE(ah, AR_MCAST_FIL1, filter1);
 }
 
-bool
-ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
-		     u32 size, u32 flags)
+void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask)
 {
-	struct ar5416_desc *ads = AR5416DESC(ds);
-	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath_hal_5416 *ahp = AH5416(ah);
 
-	ads->ds_ctl1 = size & AR_BufLen;
-	if (flags & ATH9K_RXDESC_INTREQ)
-		ads->ds_ctl1 |= AR_RxIntrReq;
+	memcpy(mask, ahp->ah_bssidmask, ETH_ALEN);
+}
 
-	ads->ds_rxstatus8 &= ~AR_RxDone;
-	if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
-		memset(&(ads->u), 0, sizeof(ads->u));
+bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	memcpy(ahp->ah_bssidmask, mask, ETH_ALEN);
+
+	REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
+	REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
+
 	return true;
 }
 
-int
-ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
-		    u32 pa, struct ath_desc *nds, u64 tsf)
+void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId)
 {
-	struct ar5416_desc ads;
-	struct ar5416_desc *adsp = AR5416DESC(ds);
+	struct ath_hal_5416 *ahp = AH5416(ah);
 
-	if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
-		return -EINPROGRESS;
+	memcpy(ahp->ah_bssid, bssid, ETH_ALEN);
+	ahp->ah_assocId = assocId;
 
-	ads.u.rx = adsp->u.rx;
-
-	ds->ds_rxstat.rs_status = 0;
-	ds->ds_rxstat.rs_flags = 0;
-
-	ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
-	ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
-
-	ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
-	ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
-	ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
-	ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
-	ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
-	ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
-	ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
-	if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
-		ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
-	else
-		ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
-
-	ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
-	ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
-
-	ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
-	ds->ds_rxstat.rs_moreaggr =
-		(ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
-	ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
-	ds->ds_rxstat.rs_flags =
-		(ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
-	ds->ds_rxstat.rs_flags |=
-		(ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
-
-	if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
-		ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
-	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
-		ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
-	if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
-		ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
-
-	if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
-
-		if (ads.ds_rxstatus8 & AR_CRCErr)
-			ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
-		else if (ads.ds_rxstatus8 & AR_PHYErr) {
-			u32 phyerr;
-
-			ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
-			phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
-			ds->ds_rxstat.rs_phyerr = phyerr;
-		} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
-			ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
-		else if (ads.ds_rxstatus8 & AR_MichaelErr)
-			ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
-	}
-
-	return 0;
+	REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
+	REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
+		  ((assocId & 0x3fff) << AR_BSS_ID1_AID_S));
 }
 
-static void ath9k_hw_setup_rate_table(struct ath_hal *ah,
-				      struct ath9k_rate_table *rt)
+u64 ath9k_hw_gettsf64(struct ath_hal *ah)
 {
-	int i;
+	u64 tsf;
 
-	if (rt->rateCodeToIndex[0] != 0)
-		return;
-	for (i = 0; i < 256; i++)
-		rt->rateCodeToIndex[i] = (u8) -1;
-	for (i = 0; i < rt->rateCount; i++) {
-		u8 code = rt->info[i].rateCode;
-		u8 cix = rt->info[i].controlRate;
+	tsf = REG_READ(ah, AR_TSF_U32);
+	tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32);
 
-		rt->rateCodeToIndex[code] = i;
-		rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
-
-		rt->info[i].lpAckDuration =
-			ath9k_hw_computetxtime(ah, rt,
-					       WLAN_CTRL_FRAME_SIZE,
-					       cix,
-					       false);
-		rt->info[i].spAckDuration =
-			ath9k_hw_computetxtime(ah, rt,
-					       WLAN_CTRL_FRAME_SIZE,
-					       cix,
-					       true);
-	}
+	return tsf;
 }
 
-const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
-						   u32 mode)
+void ath9k_hw_reset_tsf(struct ath_hal *ah)
 {
-	struct ath9k_rate_table *rt;
-	switch (mode) {
-	case ATH9K_MODE_11A:
-		rt = &ar5416_11a_table;
-		break;
-	case ATH9K_MODE_11B:
-		rt = &ar5416_11b_table;
-		break;
-	case ATH9K_MODE_11G:
-		rt = &ar5416_11g_table;
-		break;
-	case ATH9K_MODE_11NG_HT20:
-	case ATH9K_MODE_11NG_HT40PLUS:
-	case ATH9K_MODE_11NG_HT40MINUS:
-		rt = &ar5416_11ng_table;
-		break;
-	case ATH9K_MODE_11NA_HT20:
-	case ATH9K_MODE_11NA_HT40PLUS:
-	case ATH9K_MODE_11NA_HT40MINUS:
-		rt = &ar5416_11na_table;
-		break;
-	default:
-		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n",
-			 __func__, mode);
-		return NULL;
-	}
-	ath9k_hw_setup_rate_table(ah, rt);
-	return rt;
-}
+	int count;
 
-static const char *ath9k_hw_devname(u16 devid)
-{
-	switch (devid) {
-	case AR5416_DEVID_PCI:
-	case AR5416_DEVID_PCIE:
-		return "Atheros 5416";
-	case AR9160_DEVID_PCI:
-		return "Atheros 9160";
-	case AR9280_DEVID_PCI:
-	case AR9280_DEVID_PCIE:
-		return "Atheros 9280";
-	}
-	return NULL;
-}
-
-const char *ath9k_hw_probe(u16 vendorid, u16 devid)
-{
-	return vendorid == ATHEROS_VENDOR_ID ?
-		ath9k_hw_devname(devid) : NULL;
-}
-
-struct ath_hal *ath9k_hw_attach(u16 devid,
-				struct ath_softc *sc,
-				void __iomem *mem,
-				int *error)
-{
-	struct ath_hal *ah = NULL;
-
-	switch (devid) {
-	case AR5416_DEVID_PCI:
-	case AR5416_DEVID_PCIE:
-	case AR9160_DEVID_PCI:
-	case AR9280_DEVID_PCI:
-	case AR9280_DEVID_PCIE:
-		ah = ath9k_hw_do_attach(devid, sc, mem, error);
-		break;
-	default:
-		DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-			 "devid=0x%x not supported.\n", devid);
-		ah = NULL;
-		*error = -ENXIO;
-		break;
-	}
-
-	return ah;
-}
-
-u16
-ath9k_hw_computetxtime(struct ath_hal *ah,
-		       const struct ath9k_rate_table *rates,
-		       u32 frameLen, u16 rateix,
-		       bool shortPreamble)
-{
-	u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
-	u32 kbps;
-
-	kbps = rates->info[rateix].rateKbps;
-
-	if (kbps == 0)
-		return 0;
-	switch (rates->info[rateix].phy) {
-
-	case PHY_CCK:
-		phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
-		if (shortPreamble && rates->info[rateix].shortPreamble)
-			phyTime >>= 1;
-		numBits = frameLen << 3;
-		txTime = CCK_SIFS_TIME + phyTime
-			+ ((numBits * 1000) / kbps);
-		break;
-	case PHY_OFDM:
-		if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
-			bitsPerSymbol =
-				(kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
-
-			numBits = OFDM_PLCP_BITS + (frameLen << 3);
-			numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
-			txTime = OFDM_SIFS_TIME_QUARTER
-				+ OFDM_PREAMBLE_TIME_QUARTER
-				+ (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
-		} else if (ah->ah_curchan &&
-			   IS_CHAN_HALF_RATE(ah->ah_curchan)) {
-			bitsPerSymbol =
-				(kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
-
-			numBits = OFDM_PLCP_BITS + (frameLen << 3);
-			numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
-			txTime = OFDM_SIFS_TIME_HALF +
-				OFDM_PREAMBLE_TIME_HALF
-				+ (numSymbols * OFDM_SYMBOL_TIME_HALF);
-		} else {
-			bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000;
-
-			numBits = OFDM_PLCP_BITS + (frameLen << 3);
-			numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
-			txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME
-				+ (numSymbols * OFDM_SYMBOL_TIME);
+	count = 0;
+	while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
+		count++;
+		if (count > 10) {
+			DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+				"AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
+			break;
 		}
-		break;
-
-	default:
-		DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
-			 "%s: unknown phy %u (rate ix %u)\n", __func__,
-			 rates->info[rateix].phy, rateix);
-		txTime = 0;
-		break;
+		udelay(10);
 	}
-	return txTime;
-}
-
-u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags)
-{
-	if (flags & CHANNEL_2GHZ) {
-		if (freq == 2484)
-			return 14;
-		if (freq < 2484)
-			return (freq - 2407) / 5;
-		else
-			return 15 + ((freq - 2512) / 20);
-	} else if (flags & CHANNEL_5GHZ) {
-		if (ath9k_regd_is_public_safety_sku(ah) &&
-		    IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
-			return ((freq * 10) +
-				(((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
-		} else if ((flags & CHANNEL_A) && (freq <= 5000)) {
-			return (freq - 4000) / 5;
-		} else {
-			return (freq - 5000) / 5;
-		}
-	} else {
-		if (freq == 2484)
-			return 14;
-		if (freq < 2484)
-			return (freq - 2407) / 5;
-		if (freq < 5000) {
-			if (ath9k_regd_is_public_safety_sku(ah)
-			    && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
-				return ((freq * 10) +
-					(((freq % 5) ==
-					  2) ? 5 : 0) - 49400) / 5;
-			} else if (freq > 4900) {
-				return (freq - 4000) / 5;
-			} else {
-				return 15 + ((freq - 2512) / 20);
-			}
-		}
-		return (freq - 5000) / 5;
-	}
-}
-
-/* We can tune this as we go by monitoring really low values */
-#define ATH9K_NF_TOO_LOW	-60
-
-/* AR5416 may return very high value (like -31 dBm), in those cases the nf
- * is incorrect and we should use the static NF value. Later we can try to
- * find out why they are reporting these values */
-static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
-{
-	if (nf > ATH9K_NF_TOO_LOW) {
-		DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-			 "%s: noise floor value detected (%d) is "
-			"lower than what we think is a "
-			"reasonable value (%d)\n",
-			 __func__, nf, ATH9K_NF_TOO_LOW);
-		return false;
-	}
-	return true;
-}
-
-s16
-ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
-{
-	struct ath9k_channel *ichan;
-	s16 nf;
-
-	ichan = ath9k_regd_check_channel(ah, chan);
-	if (ichan == NULL) {
-		DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-			 "%s: invalid channel %u/0x%x; no mapping\n",
-			 __func__, chan->channel, chan->channelFlags);
-		return ATH_DEFAULT_NOISE_FLOOR;
-	}
-	if (ichan->rawNoiseFloor == 0) {
-		enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
-		nf = NOISE_FLOOR[mode];
-	} else
-		nf = ichan->rawNoiseFloor;
-
-	if (!ath9k_hw_nf_in_range(ah, nf))
-		nf = ATH_DEFAULT_NOISE_FLOOR;
-
-	return nf;
+	REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
 }
 
 bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)
@@ -8468,110 +3862,34 @@
 		ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
 	else
 		ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
+
 	return true;
 }
 
-bool ath9k_hw_phycounters(struct ath_hal *ah)
+bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us)
 {
 	struct ath_hal_5416 *ahp = AH5416(ah);
 
-	return ahp->ah_hasHwPhyCounters ? true : false;
-}
-
-u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q)
-{
-	return REG_READ(ah, AR_QTXDP(q));
-}
-
-bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q,
-		       u32 txdp)
-{
-	REG_WRITE(ah, AR_QTXDP(q), txdp);
-
-	return true;
-}
-
-bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
-{
-	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
-
-	REG_WRITE(ah, AR_Q_TXE, 1 << q);
-
-	return true;
-}
-
-u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
-{
-	u32 npend;
-
-	npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
-	if (npend == 0) {
-
-		if (REG_READ(ah, AR_Q_TXE) & (1 << q))
-			npend = 1;
+	if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us);
+		ahp->ah_slottime = (u32) -1;
+		return false;
+	} else {
+		REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
+		ahp->ah_slottime = us;
+		return true;
 	}
-	return npend;
 }
 
-bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
+void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode)
 {
-	u32 wait;
+	u32 macmode;
 
-	REG_WRITE(ah, AR_Q_TXD, 1 << q);
+	if (mode == ATH9K_HT_MACMODE_2040 &&
+	    !ah->ah_config.cwm_ignore_extcca)
+		macmode = AR_2040_JOINED_RX_CLEAR;
+	else
+		macmode = 0;
 
-	for (wait = 1000; wait != 0; wait--) {
-		if (ath9k_hw_numtxpending(ah, q) == 0)
-			break;
-		udelay(100);
-	}
-
-	if (ath9k_hw_numtxpending(ah, q)) {
-		u32 tsfLow, j;
-
-		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-			 "%s: Num of pending TX Frames %d on Q %d\n",
-			 __func__, ath9k_hw_numtxpending(ah, q), q);
-
-		for (j = 0; j < 2; j++) {
-			tsfLow = REG_READ(ah, AR_TSF_L32);
-			REG_WRITE(ah, AR_QUIET2,
-				  SM(10, AR_QUIET2_QUIET_DUR));
-			REG_WRITE(ah, AR_QUIET_PERIOD, 100);
-			REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
-			REG_SET_BIT(ah, AR_TIMER_MODE,
-				       AR_QUIET_TIMER_EN);
-
-			if ((REG_READ(ah, AR_TSF_L32) >> 10) ==
-			    (tsfLow >> 10)) {
-				break;
-			}
-			DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-				"%s: TSF have moved while trying to set "
-				"quiet time TSF: 0x%08x\n",
-				__func__, tsfLow);
-		}
-
-		REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
-
-		udelay(200);
-		REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
-
-		wait = 1000;
-
-		while (ath9k_hw_numtxpending(ah, q)) {
-			if ((--wait) == 0) {
-				DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
-					"%s: Failed to stop Tx DMA in 100 "
-					"msec after killing last frame\n",
-					__func__);
-				break;
-			}
-			udelay(100);
-		}
-
-		REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
-	}
-
-	REG_WRITE(ah, AR_Q_TXD, 0);
-	return wait != 0;
+	REG_WRITE(ah, AR_2040_MODE, macmode);
 }
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h
index 2113818..91d8f59 100644
--- a/drivers/net/wireless/ath9k/hw.h
+++ b/drivers/net/wireless/ath9k/hw.h
@@ -415,6 +415,9 @@
 #define AR5416_EEP_MINOR_VER_3       0x3
 #define AR5416_EEP_MINOR_VER_7       0x7
 #define AR5416_EEP_MINOR_VER_9       0x9
+#define AR5416_EEP_MINOR_VER_16      0x10
+#define AR5416_EEP_MINOR_VER_17      0x11
+#define AR5416_EEP_MINOR_VER_19      0x13
 
 #define AR5416_NUM_5G_CAL_PIERS         8
 #define AR5416_NUM_2G_CAL_PIERS         4
@@ -436,6 +439,27 @@
 #define AR5416_MAX_CHAINS               3
 #define AR5416_PWR_TABLE_OFFSET         -5
 
+/* Rx gain type values */
+#define AR5416_EEP_RXGAIN_23DB_BACKOFF     0
+#define AR5416_EEP_RXGAIN_13DB_BACKOFF     1
+#define AR5416_EEP_RXGAIN_ORIG             2
+
+/* Tx gain type values */
+#define AR5416_EEP_TXGAIN_ORIGINAL         0
+#define AR5416_EEP_TXGAIN_HIGH_POWER       1
+
+#define AR5416_EEP4K_START_LOC         64
+#define AR5416_EEP4K_NUM_2G_CAL_PIERS      3
+#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3
+#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS  3
+#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS  3
+#define AR5416_EEP4K_NUM_CTLS              12
+#define AR5416_EEP4K_NUM_BAND_EDGES        4
+#define AR5416_EEP4K_NUM_PD_GAINS          2
+#define AR5416_EEP4K_PD_GAINS_IN_MASK      4
+#define AR5416_EEP4K_PD_GAIN_ICEPTS        5
+#define AR5416_EEP4K_MAX_CHAINS            1
+
 enum eeprom_param {
 	EEP_NFTHRESH_5,
 	EEP_NFTHRESH_2,
@@ -454,6 +478,8 @@
 	EEP_MINOR_REV,
 	EEP_TX_MASK,
 	EEP_RX_MASK,
+	EEP_RXGAIN_TYPE,
+	EEP_TXGAIN_TYPE,
 };
 
 enum ar5416_rates {
@@ -469,6 +495,11 @@
 	Ar5416RateSize
 };
 
+enum ath9k_hal_freq_band {
+	ATH9K_HAL_FREQ_BAND_5GHZ = 0,
+	ATH9K_HAL_FREQ_BAND_2GHZ = 1
+};
+
 struct base_eep_header {
 	u16 length;
 	u16 checksum;
@@ -485,9 +516,32 @@
 	u32 binBuildNumber;
 	u8 deviceType;
 	u8 pwdclkind;
-	u8 futureBase[32];
+	u8 futureBase_1[2];
+	u8 rxGainType;
+	u8 futureBase_2[3];
+	u8 txGainType;
+	u8 futureBase_3[25];
 } __packed;
 
+struct base_eep_header_4k {
+	u16 length;
+	u16 checksum;
+	u16 version;
+	u8 opCapFlags;
+	u8 eepMisc;
+	u16 regDmn[2];
+	u8 macAddr[6];
+	u8 rxMask;
+	u8 txMask;
+	u16 rfSilent;
+	u16 blueToothOptions;
+	u16 deviceCap;
+	u32 binBuildNumber;
+	u8 deviceType;
+	u8 futureBase[1];
+} __packed;
+
+
 struct spur_chan {
 	u16 spurChan;
 	u8 spurRangeLow;
@@ -540,11 +594,58 @@
 	struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
 } __packed;
 
+struct modal_eep_4k_header {
+    u32  antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
+    u32  antCtrlCommon;
+    u8   antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
+    u8   switchSettling;
+    u8   txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
+    u8   rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS];
+    u8   adcDesiredSize;
+    u8   pgaDesiredSize;
+    u8   xlnaGainCh[AR5416_EEP4K_MAX_CHAINS];
+    u8   txEndToXpaOff;
+    u8   txEndToRxOn;
+    u8   txFrameToXpaOn;
+    u8   thresh62;
+    u8   noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS];
+    u8   xpdGain;
+    u8   xpd;
+    u8   iqCalICh[AR5416_EEP4K_MAX_CHAINS];
+    u8   iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
+    u8   pdGainOverlap;
+    u8   ob_01;
+    u8   db1_01;
+    u8   xpaBiasLvl;
+    u8   txFrameToDataStart;
+    u8   txFrameToPaOn;
+    u8   ht40PowerIncForPdadc;
+    u8   bswAtten[AR5416_EEP4K_MAX_CHAINS];
+    u8   bswMargin[AR5416_EEP4K_MAX_CHAINS];
+    u8   swSettleHt40;
+    u8   xatten2Db[AR5416_EEP4K_MAX_CHAINS];
+    u8   xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
+    u8   db2_01;
+    u8   version;
+    u16  ob_234;
+    u16  db1_234;
+    u16  db2_234;
+    u8   futureModal[4];
+
+    struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
+} __packed;
+
+
 struct cal_data_per_freq {
 	u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
 	u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
 } __packed;
 
+struct cal_data_per_freq_4k {
+	u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
+	u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
+} __packed;
+
 struct cal_target_power_leg {
 	u8 bChannel;
 	u8 tPow2x[4];
@@ -555,6 +656,7 @@
 	u8 tPow2x[8];
 } __packed;
 
+
 #ifdef __BIG_ENDIAN_BITFIELD
 struct cal_ctl_edges {
 	u8 bChannel;
@@ -569,10 +671,15 @@
 
 struct cal_ctl_data {
 	struct cal_ctl_edges
-	 ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
+	ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
 } __packed;
 
-struct ar5416_eeprom {
+struct cal_ctl_data_4k {
+	struct cal_ctl_edges
+	ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES];
+} __packed;
+
+struct ar5416_eeprom_def {
 	struct base_eep_header baseEepHeader;
 	u8 custData[64];
 	struct modal_eep_header modalHeader[2];
@@ -601,6 +708,26 @@
 	u8 padding;
 } __packed;
 
+struct ar5416_eeprom_4k {
+	struct base_eep_header_4k baseEepHeader;
+	u8 custData[20];
+	struct modal_eep_4k_header modalHeader;
+	u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS];
+	struct cal_data_per_freq_4k
+	calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS];
+	struct cal_target_power_leg
+	calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS];
+	struct cal_target_power_leg
+	calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS];
+	u8 ctlIndex[AR5416_EEP4K_NUM_CTLS];
+	struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS];
+	u8 padding;
+} __packed;
+
 struct ar5416IniArray {
 	u32 *ia_array;
 	u32 ia_rows;
@@ -668,9 +795,22 @@
 	struct hal_cal_list *calNext;
 };
 
+/*
+ * Enum to indentify the eeprom mappings
+ */
+enum hal_eep_map {
+	EEP_MAP_DEFAULT = 0x0,
+	EEP_MAP_4KBITS,
+	EEP_MAP_MAX
+};
+
+
 struct ath_hal_5416 {
 	struct ath_hal ah;
-	struct ar5416_eeprom ah_eeprom;
+	union {
+		struct ar5416_eeprom_def def;
+		struct ar5416_eeprom_4k map4k;
+	} ah_eeprom;
 	struct ar5416Stats ah_stats;
 	struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES];
 	void __iomem *ah_cal_mem;
@@ -792,6 +932,10 @@
 	struct ar5416IniArray ah_iniAddac;
 	struct ar5416IniArray ah_iniPcieSerdes;
 	struct ar5416IniArray ah_iniModesAdditional;
+	struct ar5416IniArray ah_iniModesRxGain;
+	struct ar5416IniArray ah_iniModesTxGain;
+	/* To indicate EEPROM mapping used */
+	enum hal_eep_map ah_eep_map;
 };
 #define AH5416(_ah) ((struct ath_hal_5416 *)(_ah))
 
@@ -833,13 +977,20 @@
 	(AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200
 #define AR5416_EEPROM_MAX           0xae0
 #define ar5416_get_eep_ver(_ahp) \
-	(((_ahp)->ah_eeprom.baseEepHeader.version >> 12) & 0xF)
+	(((_ahp)->ah_eeprom.def.baseEepHeader.version >> 12) & 0xF)
 #define ar5416_get_eep_rev(_ahp) \
-	(((_ahp)->ah_eeprom.baseEepHeader.version) & 0xFFF)
+	(((_ahp)->ah_eeprom.def.baseEepHeader.version) & 0xFFF)
 #define ar5416_get_ntxchains(_txchainmask) \
 	(((_txchainmask >> 2) & 1) + \
 		((_txchainmask >> 1) & 1) + (_txchainmask & 1))
 
+/* EEPROM 4K bit map definations */
+#define ar5416_get_eep4k_ver(_ahp)   \
+    (((_ahp)->ah_eeprom.map4k.baseEepHeader.version >> 12) & 0xF)
+#define ar5416_get_eep4k_rev(_ahp)   \
+    (((_ahp)->ah_eeprom.map4k.baseEepHeader.version) & 0xFFF)
+
+
 #ifdef __BIG_ENDIAN
 #define AR5416_EEPROM_MAGIC 0x5aa5
 #else
@@ -923,7 +1074,7 @@
 #define OFDM_PLCP_BITS_QUARTER      22
 #define OFDM_SYMBOL_TIME_QUARTER    16
 
-u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
+u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
 			enum eeprom_param param);
 
 #endif
diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h
index 3dd3815..f3cfa16 100644
--- a/drivers/net/wireless/ath9k/initvals.h
+++ b/drivers/net/wireless/ath9k/initvals.h
@@ -14,6 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+/* AR5416 to Fowl ar5146.ini */
 static const u32 ar5416Modes_9100[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -31,17 +32,17 @@
     { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
     { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
     { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x00009850, 0x6de8b4e0, 0x6de8b4e0, 0x6de8b0de, 0x6de8b0de, 0x6de8b0de },
+    { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de },
     { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+    { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
     { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
     { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
     { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
     { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
-    { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
     { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 },
     { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b },
-    { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+    { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
     { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
     { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
     { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
@@ -207,7 +208,7 @@
     { 0x00008134, 0x00000000 },
     { 0x00008138, 0x00000000 },
     { 0x0000813c, 0x00000000 },
-    { 0x00008144, 0x00000000 },
+    { 0x00008144, 0xffffffff },
     { 0x00008168, 0x00000000 },
     { 0x0000816c, 0x00000000 },
     { 0x00008170, 0x32143320 },
@@ -266,7 +267,7 @@
     { 0x0000832c, 0x00000007 },
     { 0x00008330, 0x00000302 },
     { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00000000 },
+    { 0x00008338, 0x00070000 },
     { 0x0000833c, 0x00000000 },
     { 0x00008340, 0x000107ff },
     { 0x00009808, 0x00000000 },
@@ -661,6 +662,7 @@
     {0x000098c4,  0x00000000 },
 };
 
+/* ar5416 - howl ar5416_howl.ini */
 static const u32 ar5416Modes[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -952,7 +954,7 @@
     { 0x0000994c, 0x00020028 },
     { 0x0000c95c, 0x004b6a8e },
     { 0x0000c968, 0x000003ce },
-    { 0x00009970, 0x190fb514 },
+    { 0x00009970, 0x190fb515 },
     { 0x00009974, 0x00000000 },
     { 0x00009978, 0x00000001 },
     { 0x0000997c, 0x00000000 },
@@ -1311,7 +1313,7 @@
     {0x000098cc, 0x00000000 },
 };
 
-
+/* AR5416 9160 Sowl ar5416_sowl.ini */
 static const u32 ar5416Modes_9160[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -1329,21 +1331,22 @@
     { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
     { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
     { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 },
+    { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 },
     { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+    { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
     { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
     { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
     { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
     { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
-    { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
     { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
     { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
-    { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+    { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
     { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
     { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
     { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
     { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
+    { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
     { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 },
     { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
     { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
@@ -1505,7 +1508,7 @@
     { 0x00008134, 0x00000000 },
     { 0x00008138, 0x00000000 },
     { 0x0000813c, 0x00000000 },
-    { 0x00008144, 0x00000000 },
+    { 0x00008144, 0xffffffff },
     { 0x00008168, 0x00000000 },
     { 0x0000816c, 0x00000000 },
     { 0x00008170, 0x32143320 },
@@ -1564,7 +1567,7 @@
     { 0x0000832c, 0x00000007 },
     { 0x00008330, 0x00000302 },
     { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00000000 },
+    { 0x00008338, 0x00ff0000 },
     { 0x0000833c, 0x00000000 },
     { 0x00008340, 0x000107ff },
     { 0x00009808, 0x00000000 },
@@ -1597,7 +1600,6 @@
     { 0x00009958, 0x2108ecff },
     { 0x00009940, 0x00750604 },
     { 0x0000c95c, 0x004b6a8e },
-    { 0x0000c968, 0x000003ce },
     { 0x00009970, 0x190fb515 },
     { 0x00009974, 0x00000000 },
     { 0x00009978, 0x00000001 },
@@ -1699,7 +1701,7 @@
     { 0x0000a244, 0x00007bb6 },
     { 0x0000a248, 0x0fff3ffc },
     { 0x0000a24c, 0x00000001 },
-    { 0x0000a250, 0x0000a000 },
+    { 0x0000a250, 0x0000e000 },
     { 0x0000a254, 0x00000000 },
     { 0x0000a258, 0x0cc75380 },
     { 0x0000a25c, 0x0f0f0f01 },
@@ -1719,7 +1721,7 @@
     { 0x0000a34c, 0x3fffffff },
     { 0x0000a350, 0x3fffffff },
     { 0x0000a354, 0x0003ffff },
-    { 0x0000a358, 0x79a8aa33 },
+    { 0x0000a358, 0x79bfaa03 },
     { 0x0000d35c, 0x07ffffef },
     { 0x0000d360, 0x0fffffe7 },
     { 0x0000d364, 0x17ffffe5 },
@@ -1842,7 +1844,6 @@
 };
 
 static const u32 ar5416Bank6_9160[][3] = {
-
     { 0x0000989c, 0x00000000, 0x00000000 },
     { 0x0000989c, 0x00000000, 0x00000000 },
     { 0x0000989c, 0x00000000, 0x00000000 },
@@ -1920,7 +1921,6 @@
     { 0x000098cc, 0x0000000e },
 };
 
-
 static u32 ar5416Addac_9160[][2] = {
     {0x0000989c,  0x00000000 },
     {0x0000989c,  0x00000000 },
@@ -1956,7 +1956,6 @@
     {0x000098cc,  0x00000000 },
 };
 
-
 static u32 ar5416Addac_91601_1[][2] = {
     {0x0000989c,  0x00000000 },
     {0x0000989c,  0x00000000 },
@@ -1992,8 +1991,7 @@
     {0x000098cc,  0x00000000 },
 };
 
-
-
+/* XXX 9280 1 */
 static const u32 ar9280Modes_9280[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -2543,9 +2541,7 @@
     { 0x00007898, 0x2a850160 },
 };
 
-
-
-
+/* XXX 9280 2 */
 static const u32 ar9280Modes_9280_2[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -2560,26 +2556,24 @@
     { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
     { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
     { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
-    { 0x00009840, 0x206a012e, 0x206a012e, 0x206a022e, 0x206a022e, 0x206a022e },
+    { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e },
     { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
-    { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
-    { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
-    { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
-    { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+    { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
+    { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+    { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e },
     { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
-    { 0x0000c864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+    { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
     { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
     { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
-    { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
     { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
-    { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
-    { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 },
+    { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+    { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 },
     { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
     { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
     { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
-    { 0x0000c9b8, 0x0000000f, 0x0000000f, 0x0000001c, 0x0000001c, 0x0000001c },
-    { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+    { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c },
+    { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 },
     { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
     { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
     { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
@@ -2587,164 +2581,13 @@
     { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
     { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
     { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
-    { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
-    { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
-    { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
-    { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
-    { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
-    { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
-    { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
-    { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
-    { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
-    { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
-    { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
-    { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
-    { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
-    { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
-    { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
-    { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
-    { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
-    { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
-    { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
-    { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
-    { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
-    { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
-    { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
-    { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
-    { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
-    { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
-    { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
-    { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
-    { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
-    { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
-    { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
-    { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
-    { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
-    { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
-    { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
-    { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
-    { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
-    { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
-    { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
-    { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
-    { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
-    { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
-    { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
-    { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
-    { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
-    { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
-    { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
-    { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
-    { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
-    { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
-    { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
-    { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
-    { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
-    { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
-    { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
-    { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
-    { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
-    { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c },
-    { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 },
-    { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 },
-    { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 },
-    { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 },
-    { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 },
-    { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 },
-    { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 },
-    { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 },
-    { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 },
-    { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 },
-    { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 },
-    { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 },
-    { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c },
-    { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 },
-    { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 },
-    { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 },
-    { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 },
-    { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 },
-    { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 },
-    { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 },
-    { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 },
-    { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad },
-    { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 },
-    { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 },
-    { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 },
-    { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 },
-    { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 },
-    { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 },
-    { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 },
-    { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 },
-    { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 },
-    { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca },
-    { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce },
-    { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 },
-    { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 },
-    { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 },
-    { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 },
-    { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb },
-    { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf },
-    { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 },
-    { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
-    { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
     { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 },
-    { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 },
     { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
     { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
-    { 0x0000a21c, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a },
+    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
     { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a250, 0x001ff000, 0x001ff000, 0x001da000, 0x001da000, 0x001da000 },
+    { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 },
     { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
-    { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
-    { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b },
-    { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 },
-    { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 },
-    { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a },
-    { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 },
-    { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
-    { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b },
-    { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 },
-    { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 },
-    { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a },
-    { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 },
-    { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b },
-    { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 },
-    { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 },
-    { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a },
-    { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 },
-    { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a },
-    { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 },
-    { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 },
     { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
     { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
     { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 },
@@ -2884,7 +2727,7 @@
     { 0x00008134, 0x00000000 },
     { 0x00008138, 0x00000000 },
     { 0x0000813c, 0x00000000 },
-    { 0x00008144, 0x00000000 },
+    { 0x00008144, 0xffffffff },
     { 0x00008168, 0x00000000 },
     { 0x0000816c, 0x00000000 },
     { 0x00008170, 0x32143320 },
@@ -2923,6 +2766,7 @@
     { 0x00008258, 0x00000000 },
     { 0x0000825c, 0x400000ff },
     { 0x00008260, 0x00080922 },
+    { 0x00008264, 0xa8a00010 },
     { 0x00008270, 0x00000000 },
     { 0x00008274, 0x40000000 },
     { 0x00008278, 0x003e4180 },
@@ -2939,7 +2783,7 @@
     { 0x0000832c, 0x00000007 },
     { 0x00008330, 0x00000302 },
     { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00000000 },
+    { 0x00008338, 0x00ff0000 },
     { 0x0000833c, 0x00000000 },
     { 0x00008340, 0x000107ff },
     { 0x00008344, 0x00581043 },
@@ -2973,7 +2817,7 @@
     { 0x00009958, 0x2108ecff },
     { 0x00009940, 0x14750604 },
     { 0x0000c95c, 0x004b6a8e },
-    { 0x0000c968, 0x000003ce },
+    { 0x00009968, 0x000003ce },
     { 0x00009970, 0x190fb515 },
     { 0x00009974, 0x00000000 },
     { 0x00009978, 0x00000001 },
@@ -2999,13 +2843,14 @@
     { 0x000099ec, 0x0cc80caa },
     { 0x000099f0, 0x00000000 },
     { 0x000099fc, 0x00001042 },
+    { 0x0000a208, 0x803e4788 },
     { 0x0000a210, 0x4080a333 },
     { 0x0000a214, 0x40206c10 },
     { 0x0000a218, 0x009c4060 },
     { 0x0000a220, 0x01834061 },
     { 0x0000a224, 0x00000400 },
     { 0x0000a228, 0x000003b5 },
-    { 0x0000a22c, 0x233f71c0 },
+    { 0x0000a22c, 0x233f7180 },
     { 0x0000a234, 0x20202020 },
     { 0x0000a238, 0x20202020 },
     { 0x0000a23c, 0x13c88000 },
@@ -3022,7 +2867,6 @@
     { 0x0000b26c, 0x0ebae9c6 },
     { 0x0000d270, 0x00820820 },
     { 0x0000a278, 0x1ce739ce },
-    { 0x0000a27c, 0x050701ce },
     { 0x0000d35c, 0x07ffffef },
     { 0x0000d360, 0x0fffffe7 },
     { 0x0000d364, 0x17ffffe5 },
@@ -3064,7 +2908,6 @@
     { 0x00007808, 0x04924914 },
     { 0x0000780c, 0x21084210 },
     { 0x00007810, 0x6d801300 },
-    { 0x00007814, 0x0019beff },
     { 0x00007818, 0x07e41000 },
     { 0x0000781c, 0x00392000 },
     { 0x00007820, 0x92592480 },
@@ -3073,7 +2916,6 @@
     { 0x0000782c, 0x04924914 },
     { 0x00007830, 0x21084210 },
     { 0x00007834, 0x6d801300 },
-    { 0x00007838, 0x0019beff },
     { 0x0000783c, 0x07e40000 },
     { 0x00007840, 0x00392000 },
     { 0x00007844, 0x92592480 },
@@ -3110,12 +2952,465 @@
     { 0x00009828, 0x0b020001, 0x0b020001 },
     { 0x00009834, 0x00000f0f, 0x00000f0f },
     { 0x00009844, 0x03721821, 0x03721821 },
-    { 0x00009914, 0x00000898, 0x00000898 },
+    { 0x00009914, 0x00000898, 0x00001130 },
     { 0x00009918, 0x0000000b, 0x00000016 },
     { 0x00009944, 0xdfbc1210, 0xdfbc1210 },
 };
 
+static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = {
+    { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+    { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+    { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+    { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+    { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+    { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+    { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+    { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+    { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+    { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+    { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+    { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+    { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+    { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+    { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+    { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+    { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+    { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+    { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+    { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+    { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+    { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+    { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+    { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+    { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+    { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+    { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+    { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+    { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+    { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+    { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+    { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+    { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+    { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+    { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+    { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+    { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+    { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+    { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+    { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+    { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+    { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+    { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+    { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+    { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+    { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+    { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+    { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+    { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10 },
+    { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b14, 0x00008b14, 0x00008b14 },
+    { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b01, 0x00008b01, 0x00008b01 },
+    { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b05, 0x00008b05, 0x00008b05 },
+    { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b09, 0x00008b09, 0x00008b09 },
+    { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b0d, 0x00008b0d, 0x00008b0d },
+    { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b11, 0x00008b11, 0x00008b11 },
+    { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008b15, 0x00008b15, 0x00008b15 },
+    { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008b02, 0x00008b02, 0x00008b02 },
+    { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008b06, 0x00008b06, 0x00008b06 },
+    { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00008b0a, 0x00008b0a, 0x00008b0a },
+    { 0x00009aec, 0x0000b784, 0x0000b784, 0x00008b0e, 0x00008b0e, 0x00008b0e },
+    { 0x00009af0, 0x0000b788, 0x0000b788, 0x00008b12, 0x00008b12, 0x00008b12 },
+    { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008b16, 0x00008b16, 0x00008b16 },
+    { 0x00009af8, 0x0000b790, 0x0000b790, 0x00008b03, 0x00008b03, 0x00008b03 },
+    { 0x00009afc, 0x0000b794, 0x0000b794, 0x00008b07, 0x00008b07, 0x00008b07 },
+    { 0x00009b00, 0x0000b798, 0x0000b798, 0x00008b0b, 0x00008b0b, 0x00008b0b },
+    { 0x00009b04, 0x0000d784, 0x0000d784, 0x00008b0f, 0x00008b0f, 0x00008b0f },
+    { 0x00009b08, 0x0000d788, 0x0000d788, 0x00008b13, 0x00008b13, 0x00008b13 },
+    { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008b17, 0x00008b17, 0x00008b17 },
+    { 0x00009b10, 0x0000d790, 0x0000d790, 0x00008b23, 0x00008b23, 0x00008b23 },
+    { 0x00009b14, 0x0000f780, 0x0000f780, 0x00008b27, 0x00008b27, 0x00008b27 },
+    { 0x00009b18, 0x0000f784, 0x0000f784, 0x00008b2b, 0x00008b2b, 0x00008b2b },
+    { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00008b2f, 0x00008b2f, 0x00008b2f },
+    { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008b33, 0x00008b33, 0x00008b33 },
+    { 0x00009b24, 0x0000f790, 0x0000f790, 0x00008b37, 0x00008b37, 0x00008b37 },
+    { 0x00009b28, 0x0000f794, 0x0000f794, 0x00008b43, 0x00008b43, 0x00008b43 },
+    { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008b47, 0x00008b47, 0x00008b47 },
+    { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008b4b, 0x00008b4b, 0x00008b4b },
+    { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008b4f, 0x00008b4f, 0x00008b4f },
+    { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008b53, 0x00008b53, 0x00008b53 },
+    { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008b57, 0x00008b57, 0x00008b57 },
+    { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+    { 0x00009848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 },
+    { 0x0000a848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 },
+};
 
+static const u32 ar9280Modes_original_rxgain_9280_2[][6] = {
+    { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+    { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+    { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+    { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+    { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+    { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+    { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+    { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+    { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+    { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+    { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+    { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+    { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+    { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+    { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+    { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+    { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+    { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+    { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+    { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+    { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+    { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+    { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+    { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+    { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+    { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+    { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+    { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+    { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+    { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+    { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+    { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+    { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+    { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+    { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+    { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+    { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+    { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+    { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+    { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+    { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+    { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+    { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+    { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+    { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+    { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+    { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+    { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+    { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
+    { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
+    { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
+    { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
+    { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
+    { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
+    { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
+    { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
+    { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
+    { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
+    { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c },
+    { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 },
+    { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 },
+    { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 },
+    { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 },
+    { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 },
+    { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 },
+    { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 },
+    { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 },
+    { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 },
+    { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 },
+    { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 },
+    { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 },
+    { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c },
+    { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 },
+    { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 },
+    { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 },
+    { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 },
+    { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 },
+    { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 },
+    { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 },
+    { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 },
+    { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad },
+    { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 },
+    { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 },
+    { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 },
+    { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 },
+    { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 },
+    { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 },
+    { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 },
+    { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 },
+    { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 },
+    { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca },
+    { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce },
+    { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 },
+    { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 },
+    { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 },
+    { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 },
+    { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb },
+    { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf },
+    { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 },
+    { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+    { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
+    { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
+};
+
+static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = {
+    { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+    { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+    { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+    { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+    { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+    { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+    { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+    { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+    { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+    { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+    { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+    { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+    { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+    { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+    { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+    { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+    { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+    { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+    { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+    { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+    { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+    { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+    { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+    { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+    { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+    { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+    { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+    { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+    { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+    { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+    { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+    { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+    { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+    { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+    { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+    { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+    { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+    { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+    { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+    { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+    { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+    { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+    { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+    { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+    { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+    { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+    { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+    { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+    { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
+    { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
+    { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
+    { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
+    { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
+    { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
+    { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
+    { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
+    { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
+    { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
+    { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310 },
+    { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314 },
+    { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320 },
+    { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324 },
+    { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328 },
+    { 0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c },
+    { 0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330 },
+    { 0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334 },
+    { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321 },
+    { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325 },
+    { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329 },
+    { 0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d },
+    { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331 },
+    { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335 },
+    { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322 },
+    { 0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326 },
+    { 0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a },
+    { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e },
+    { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332 },
+    { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336 },
+    { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323 },
+    { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327 },
+    { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b },
+    { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f },
+    { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333 },
+    { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337 },
+    { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343 },
+    { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347 },
+    { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b },
+    { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f },
+    { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353 },
+    { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357 },
+    { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+    { 0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a },
+    { 0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a },
+};
+
+static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = {
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 },
+    { 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 },
+    { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010 },
+    { 0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012 },
+    { 0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014 },
+    { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a },
+    { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211 },
+    { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
+    { 0x0000a324, 0x00020092, 0x00020092, 0x00022411, 0x00022411, 0x00022411 },
+    { 0x0000a328, 0x0002410a, 0x0002410a, 0x00025413, 0x00025413, 0x00025413 },
+    { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00029811, 0x00029811, 0x00029811 },
+    { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002c813, 0x0002c813, 0x0002c813 },
+    { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030a14, 0x00030a14, 0x00030a14 },
+    { 0x0000a338, 0x000321ec, 0x000321ec, 0x00035a50, 0x00035a50, 0x00035a50 },
+    { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00039c4c, 0x00039c4c, 0x00039c4c },
+    { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003de8a, 0x0003de8a, 0x0003de8a },
+    { 0x0000a344, 0x000321ec, 0x000321ec, 0x00042e92, 0x00042e92, 0x00042e92 },
+    { 0x0000a348, 0x000321ec, 0x000321ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 },
+    { 0x0000a34c, 0x000321ec, 0x000321ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 },
+    { 0x0000a350, 0x000321ec, 0x000321ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 },
+    { 0x0000a354, 0x000321ec, 0x000321ec, 0x00053fd5, 0x00053fd5, 0x00053fd5 },
+    { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
+    { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
+    { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce },
+};
+
+static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
+    { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
+    { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b },
+    { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 },
+    { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 },
+    { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a },
+    { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 },
+    { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
+    { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b },
+    { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 },
+    { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 },
+    { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a },
+    { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 },
+    { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b },
+    { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 },
+    { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 },
+    { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a },
+    { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 },
+    { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a },
+    { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 },
+    { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 },
+    { 0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff },
+    { 0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff },
+    { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
+};
 
 static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
     {0x00004040,  0x9248fd00 },
@@ -3123,23 +3418,1384 @@
     {0x00004040,  0xa8000019 },
     {0x00004040,  0x13160820 },
     {0x00004040,  0xe5980560 },
-    {0x00004040,  0x401dcffc },
-    {0x00004040,  0x1aaabe40 },
+    {0x00004040,  0xc01dcffc },
+    {0x00004040,  0x1aaabe41 },
     {0x00004040,  0xbe105554 },
     {0x00004040,  0x00043007 },
     {0x00004044,  0x00000000 },
 };
 
-
-
 static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
     {0x00004040,  0xa8000019 },
     {0x00004040,  0x13160820 },
     {0x00004040,  0xe5980560 },
-    {0x00004040,  0x401dcffd },
-    {0x00004040,  0x1aaabe40 },
+    {0x00004040,  0xc01dcffd },
+    {0x00004040,  0x1aaabe41 },
+    {0x00004040,  0xbe105554 },
+    {0x00004040,  0x00043007 },
+    {0x00004044,  0x00000000 },
+};
+
+/* AR9285 */
+static const u_int32_t ar9285Modes_9285[][6] = {
+    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+    { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
+    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+    { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
+    { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
+    { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
+    { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
+    { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+    { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
+    { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+    { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
+    { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
+    { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 },
+    { 0x00009848, 0x00001066, 0x00001066, 0x0000004e, 0x0000004e, 0x00001059 },
+    { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
+    { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e },
+    { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 },
+    { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+    { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+    { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
+    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
+    { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+    { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
+    { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1020, 0xdfbc1020, 0xdfbc1010 },
+    { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x000099b8, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c },
+    { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+    { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+    { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+    { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
+    { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+    { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+    { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 },
+    { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 },
+    { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 },
+    { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 },
+    { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 },
+    { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 },
+    { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 },
+    { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+    { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 },
+    { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 },
+    { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 },
+    { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 },
+    { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 },
+    { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 },
+    { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 },
+    { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 },
+    { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 },
+    { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 },
+    { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 },
+    { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 },
+    { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 },
+    { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 },
+    { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 },
+    { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 },
+    { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 },
+    { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 },
+    { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 },
+    { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 },
+    { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
+    { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
+    { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
+    { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
+    { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
+    { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
+    { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 },
+    { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 },
+    { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 },
+    { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 },
+    { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 },
+    { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 },
+    { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 },
+    { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 },
+    { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 },
+    { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 },
+    { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+    { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 },
+    { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 },
+    { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 },
+    { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 },
+    { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 },
+    { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 },
+    { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 },
+    { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 },
+    { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 },
+    { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 },
+    { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 },
+    { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 },
+    { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 },
+    { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 },
+    { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 },
+    { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 },
+    { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 },
+    { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 },
+    { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 },
+    { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 },
+    { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 },
+    { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 },
+    { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 },
+    { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 },
+    { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 },
+    { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 },
+    { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 },
+    { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 },
+    { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 },
+    { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 },
+    { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 },
+    { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 },
+    { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 },
+    { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 },
+    { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 },
+    { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 },
+    { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 },
+    { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 },
+    { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 },
+    { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 },
+    { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 },
+    { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 },
+    { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 },
+    { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 },
+    { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 },
+    { 0x0000aa04, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 },
+    { 0x0000aa08, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 },
+    { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 },
+    { 0x0000aa10, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 },
+    { 0x0000aa14, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 },
+    { 0x0000aa18, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 },
+    { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 },
+    { 0x0000aa20, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 },
+    { 0x0000aa24, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+    { 0x0000aa28, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+    { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 },
+    { 0x0000aa30, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 },
+    { 0x0000aa34, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 },
+    { 0x0000aa38, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 },
+    { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 },
+    { 0x0000aa40, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 },
+    { 0x0000aa44, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 },
+    { 0x0000aa48, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 },
+    { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 },
+    { 0x0000aa50, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 },
+    { 0x0000aa54, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 },
+    { 0x0000aa58, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 },
+    { 0x0000aa5c, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 },
+    { 0x0000aa60, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 },
+    { 0x0000aa64, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 },
+    { 0x0000aa68, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 },
+    { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 },
+    { 0x0000aa70, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 },
+    { 0x0000aa74, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 },
+    { 0x0000aa78, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 },
+    { 0x0000aa7c, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 },
+    { 0x0000aa80, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 },
+    { 0x0000aa84, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 },
+    { 0x0000aa88, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 },
+    { 0x0000aa8c, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 },
+    { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 },
+    { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 },
+    { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 },
+    { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 },
+    { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 },
+    { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 },
+    { 0x0000aaa8, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 },
+    { 0x0000aaac, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 },
+    { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 },
+    { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+    { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+    { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 },
+    { 0x0000aac0, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 },
+    { 0x0000aac4, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 },
+    { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 },
+    { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 },
+    { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 },
+    { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 },
+    { 0x0000aad8, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 },
+    { 0x0000aadc, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 },
+    { 0x0000aae0, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 },
+    { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 },
+    { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 },
+    { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 },
+    { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 },
+    { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 },
+    { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 },
+    { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 },
+    { 0x0000ab00, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 },
+    { 0x0000ab04, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 },
+    { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 },
+    { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 },
+    { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 },
+    { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 },
+    { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 },
+    { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 },
+    { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 },
+    { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 },
+    { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 },
+    { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 },
+    { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 },
+    { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 },
+    { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 },
+    { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 },
+    { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 },
+    { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 },
+    { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 },
+    { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 },
+    { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 },
+    { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 },
+    { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 },
+    { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 },
+    { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 },
+    { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
+    { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 },
+    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+    { 0x0000a250, 0x001ff000, 0x001ff000, 0x001ca000, 0x001ca000, 0x001da000 },
+    { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 },
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
+    { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 },
+    { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 },
+    { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 },
+    { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 },
+    { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 },
+    { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 },
+    { 0x0000a320, 0x00000000, 0x00000000, 0x0002c89a, 0x0002c89a, 0x00000000 },
+    { 0x0000a324, 0x00000000, 0x00000000, 0x0002e89b, 0x0002e89b, 0x00000000 },
+    { 0x0000a328, 0x00000000, 0x00000000, 0x0003089c, 0x0003089c, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x0003289d, 0x0003289d, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x0003489e, 0x0003489e, 0x00000000 },
+    { 0x0000a334, 0x00000000, 0x00000000, 0x000388de, 0x000388de, 0x00000000 },
+    { 0x0000a338, 0x00000000, 0x00000000, 0x0003b91e, 0x0003b91e, 0x00000000 },
+    { 0x0000a33c, 0x00000000, 0x00000000, 0x0003d95e, 0x0003d95e, 0x00000000 },
+    { 0x0000a340, 0x00000000, 0x00000000, 0x000419df, 0x000419df, 0x00000000 },
+    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+};
+
+static const u_int32_t ar9285Common_9285[][2] = {
+    { 0x0000000c, 0x00000000 },
+    { 0x00000030, 0x00020045 },
+    { 0x00000034, 0x00000005 },
+    { 0x00000040, 0x00000000 },
+    { 0x00000044, 0x00000008 },
+    { 0x00000048, 0x00000008 },
+    { 0x0000004c, 0x00000010 },
+    { 0x00000050, 0x00000000 },
+    { 0x00000054, 0x0000001f },
+    { 0x00000800, 0x00000000 },
+    { 0x00000804, 0x00000000 },
+    { 0x00000808, 0x00000000 },
+    { 0x0000080c, 0x00000000 },
+    { 0x00000810, 0x00000000 },
+    { 0x00000814, 0x00000000 },
+    { 0x00000818, 0x00000000 },
+    { 0x0000081c, 0x00000000 },
+    { 0x00000820, 0x00000000 },
+    { 0x00000824, 0x00000000 },
+    { 0x00001040, 0x002ffc0f },
+    { 0x00001044, 0x002ffc0f },
+    { 0x00001048, 0x002ffc0f },
+    { 0x0000104c, 0x002ffc0f },
+    { 0x00001050, 0x002ffc0f },
+    { 0x00001054, 0x002ffc0f },
+    { 0x00001058, 0x002ffc0f },
+    { 0x0000105c, 0x002ffc0f },
+    { 0x00001060, 0x002ffc0f },
+    { 0x00001064, 0x002ffc0f },
+    { 0x00001230, 0x00000000 },
+    { 0x00001270, 0x00000000 },
+    { 0x00001038, 0x00000000 },
+    { 0x00001078, 0x00000000 },
+    { 0x000010b8, 0x00000000 },
+    { 0x000010f8, 0x00000000 },
+    { 0x00001138, 0x00000000 },
+    { 0x00001178, 0x00000000 },
+    { 0x000011b8, 0x00000000 },
+    { 0x000011f8, 0x00000000 },
+    { 0x00001238, 0x00000000 },
+    { 0x00001278, 0x00000000 },
+    { 0x000012b8, 0x00000000 },
+    { 0x000012f8, 0x00000000 },
+    { 0x00001338, 0x00000000 },
+    { 0x00001378, 0x00000000 },
+    { 0x000013b8, 0x00000000 },
+    { 0x000013f8, 0x00000000 },
+    { 0x00001438, 0x00000000 },
+    { 0x00001478, 0x00000000 },
+    { 0x000014b8, 0x00000000 },
+    { 0x000014f8, 0x00000000 },
+    { 0x00001538, 0x00000000 },
+    { 0x00001578, 0x00000000 },
+    { 0x000015b8, 0x00000000 },
+    { 0x000015f8, 0x00000000 },
+    { 0x00001638, 0x00000000 },
+    { 0x00001678, 0x00000000 },
+    { 0x000016b8, 0x00000000 },
+    { 0x000016f8, 0x00000000 },
+    { 0x00001738, 0x00000000 },
+    { 0x00001778, 0x00000000 },
+    { 0x000017b8, 0x00000000 },
+    { 0x000017f8, 0x00000000 },
+    { 0x0000103c, 0x00000000 },
+    { 0x0000107c, 0x00000000 },
+    { 0x000010bc, 0x00000000 },
+    { 0x000010fc, 0x00000000 },
+    { 0x0000113c, 0x00000000 },
+    { 0x0000117c, 0x00000000 },
+    { 0x000011bc, 0x00000000 },
+    { 0x000011fc, 0x00000000 },
+    { 0x0000123c, 0x00000000 },
+    { 0x0000127c, 0x00000000 },
+    { 0x000012bc, 0x00000000 },
+    { 0x000012fc, 0x00000000 },
+    { 0x0000133c, 0x00000000 },
+    { 0x0000137c, 0x00000000 },
+    { 0x000013bc, 0x00000000 },
+    { 0x000013fc, 0x00000000 },
+    { 0x0000143c, 0x00000000 },
+    { 0x0000147c, 0x00000000 },
+    { 0x00004030, 0x00000002 },
+    { 0x0000403c, 0x00000002 },
+    { 0x00004024, 0x0000001f },
+    { 0x00004060, 0x00000000 },
+    { 0x00004064, 0x00000000 },
+    { 0x00007010, 0x00000031 },
+    { 0x00007034, 0x00000002 },
+    { 0x00007038, 0x000004c2 },
+    { 0x00008004, 0x00000000 },
+    { 0x00008008, 0x00000000 },
+    { 0x0000800c, 0x00000000 },
+    { 0x00008018, 0x00000700 },
+    { 0x00008020, 0x00000000 },
+    { 0x00008038, 0x00000000 },
+    { 0x0000803c, 0x00000000 },
+    { 0x00008048, 0x00000000 },
+    { 0x00008054, 0x00000000 },
+    { 0x00008058, 0x00000000 },
+    { 0x0000805c, 0x000fc78f },
+    { 0x00008060, 0x0000000f },
+    { 0x00008064, 0x00000000 },
+    { 0x00008070, 0x00000000 },
+    { 0x000080c0, 0x2a80001a },
+    { 0x000080c4, 0x05dc01e0 },
+    { 0x000080c8, 0x1f402710 },
+    { 0x000080cc, 0x01f40000 },
+    { 0x000080d0, 0x00001e00 },
+    { 0x000080d4, 0x00000000 },
+    { 0x000080d8, 0x00400000 },
+    { 0x000080e0, 0xffffffff },
+    { 0x000080e4, 0x0000ffff },
+    { 0x000080e8, 0x003f3f3f },
+    { 0x000080ec, 0x00000000 },
+    { 0x000080f0, 0x00000000 },
+    { 0x000080f4, 0x00000000 },
+    { 0x000080f8, 0x00000000 },
+    { 0x000080fc, 0x00020000 },
+    { 0x00008100, 0x00020000 },
+    { 0x00008104, 0x00000001 },
+    { 0x00008108, 0x00000052 },
+    { 0x0000810c, 0x00000000 },
+    { 0x00008110, 0x00000168 },
+    { 0x00008118, 0x000100aa },
+    { 0x0000811c, 0x00003210 },
+    { 0x00008120, 0x08f04800 },
+    { 0x00008124, 0x00000000 },
+    { 0x00008128, 0x00000000 },
+    { 0x0000812c, 0x00000000 },
+    { 0x00008130, 0x00000000 },
+    { 0x00008134, 0x00000000 },
+    { 0x00008138, 0x00000000 },
+    { 0x0000813c, 0x00000000 },
+    { 0x00008144, 0x00000000 },
+    { 0x00008168, 0x00000000 },
+    { 0x0000816c, 0x00000000 },
+    { 0x00008170, 0x32143320 },
+    { 0x00008174, 0xfaa4fa50 },
+    { 0x00008178, 0x00000100 },
+    { 0x0000817c, 0x00000000 },
+    { 0x000081c0, 0x00000000 },
+    { 0x000081d0, 0x00003210 },
+    { 0x000081ec, 0x00000000 },
+    { 0x000081f0, 0x00000000 },
+    { 0x000081f4, 0x00000000 },
+    { 0x000081f8, 0x00000000 },
+    { 0x000081fc, 0x00000000 },
+    { 0x00008200, 0x00000000 },
+    { 0x00008204, 0x00000000 },
+    { 0x00008208, 0x00000000 },
+    { 0x0000820c, 0x00000000 },
+    { 0x00008210, 0x00000000 },
+    { 0x00008214, 0x00000000 },
+    { 0x00008218, 0x00000000 },
+    { 0x0000821c, 0x00000000 },
+    { 0x00008220, 0x00000000 },
+    { 0x00008224, 0x00000000 },
+    { 0x00008228, 0x00000000 },
+    { 0x0000822c, 0x00000000 },
+    { 0x00008230, 0x00000000 },
+    { 0x00008234, 0x00000000 },
+    { 0x00008238, 0x00000000 },
+    { 0x0000823c, 0x00000000 },
+    { 0x00008240, 0x00100000 },
+    { 0x00008244, 0x0010f400 },
+    { 0x00008248, 0x00000100 },
+    { 0x0000824c, 0x0001e800 },
+    { 0x00008250, 0x00000000 },
+    { 0x00008254, 0x00000000 },
+    { 0x00008258, 0x00000000 },
+    { 0x0000825c, 0x400000ff },
+    { 0x00008260, 0x00080922 },
+    { 0x00008264, 0xa8a00010 },
+    { 0x00008270, 0x00000000 },
+    { 0x00008274, 0x40000000 },
+    { 0x00008278, 0x003e4180 },
+    { 0x0000827c, 0x00000000 },
+    { 0x00008284, 0x0000002c },
+    { 0x00008288, 0x0000002c },
+    { 0x0000828c, 0x00000000 },
+    { 0x00008294, 0x00000000 },
+    { 0x00008298, 0x00000000 },
+    { 0x0000829c, 0x00000000 },
+    { 0x00008300, 0x00000040 },
+    { 0x00008314, 0x00000000 },
+    { 0x00008328, 0x00000000 },
+    { 0x0000832c, 0x00000001 },
+    { 0x00008330, 0x00000302 },
+    { 0x00008334, 0x00000e00 },
+    { 0x00008338, 0x00000000 },
+    { 0x0000833c, 0x00000000 },
+    { 0x00008340, 0x00010380 },
+    { 0x00008344, 0x00581043 },
+    { 0x00009808, 0x00000000 },
+    { 0x0000980c, 0xafe68e30 },
+    { 0x00009810, 0xfd14e000 },
+    { 0x00009814, 0x9c0a9f6b },
+    { 0x0000981c, 0x00000000 },
+    { 0x0000982c, 0x0000a000 },
+    { 0x00009830, 0x00000000 },
+    { 0x0000983c, 0x00200400 },
+    { 0x0000984c, 0x0040233c },
+    { 0x00009854, 0x00000044 },
+    { 0x00009900, 0x00000000 },
+    { 0x00009904, 0x00000000 },
+    { 0x00009908, 0x00000000 },
+    { 0x0000990c, 0x00000000 },
+    { 0x00009910, 0x01002310 },
+    { 0x0000991c, 0x10000fff },
+    { 0x00009920, 0x04900000 },
+    { 0x00009928, 0x00000001 },
+    { 0x0000992c, 0x00000004 },
+    { 0x00009934, 0x1e1f2022 },
+    { 0x00009938, 0x0a0b0c0d },
+    { 0x0000993c, 0x00000000 },
+    { 0x00009940, 0x14750604 },
+    { 0x00009948, 0x9280c00a },
+    { 0x0000994c, 0x00020028 },
+    { 0x00009954, 0x5f3ca3de },
+    { 0x00009958, 0x2108ecff },
+    { 0x00009968, 0x000003ce },
+    { 0x00009970, 0x1927b515 },
+    { 0x00009974, 0x00000000 },
+    { 0x00009978, 0x00000001 },
+    { 0x0000997c, 0x00000000 },
+    { 0x00009980, 0x00000000 },
+    { 0x00009984, 0x00000000 },
+    { 0x00009988, 0x00000000 },
+    { 0x0000998c, 0x00000000 },
+    { 0x00009990, 0x00000000 },
+    { 0x00009994, 0x00000000 },
+    { 0x00009998, 0x00000000 },
+    { 0x0000999c, 0x00000000 },
+    { 0x000099a0, 0x00000000 },
+    { 0x000099a4, 0x00000001 },
+    { 0x000099a8, 0x201fff00 },
+    { 0x000099ac, 0x2def0a00 },
+    { 0x000099b0, 0x03051000 },
+    { 0x000099b4, 0x00000820 },
+    { 0x000099dc, 0x00000000 },
+    { 0x000099e0, 0x00000000 },
+    { 0x000099e4, 0xaaaaaaaa },
+    { 0x000099e8, 0x3c466478 },
+    { 0x000099ec, 0x0cc80caa },
+    { 0x000099f0, 0x00000000 },
+    { 0x0000a208, 0x803e6788 },
+    { 0x0000a210, 0x4080a333 },
+    { 0x0000a214, 0x00206c10 },
+    { 0x0000a218, 0x009c4060 },
+    { 0x0000a220, 0x01834061 },
+    { 0x0000a224, 0x00000400 },
+    { 0x0000a228, 0x000003b5 },
+    { 0x0000a22c, 0x00000000 },
+    { 0x0000a234, 0x20202020 },
+    { 0x0000a238, 0x20202020 },
+    { 0x0000a244, 0x00000000 },
+    { 0x0000a248, 0xfffffffc },
+    { 0x0000a24c, 0x00000000 },
+    { 0x0000a254, 0x00000000 },
+    { 0x0000a258, 0x0ccb5380 },
+    { 0x0000a25c, 0x15151501 },
+    { 0x0000a260, 0xdfa90f01 },
+    { 0x0000a268, 0x00000000 },
+    { 0x0000a26c, 0x0ebae9e6 },
+    { 0x0000d270, 0x0d820820 },
+    { 0x0000a278, 0x39ce739c },
+    { 0x0000a27c, 0x050e039c },
+    { 0x0000d35c, 0x07ffffef },
+    { 0x0000d360, 0x0fffffe7 },
+    { 0x0000d364, 0x17ffffe5 },
+    { 0x0000d368, 0x1fffffe4 },
+    { 0x0000d36c, 0x37ffffe3 },
+    { 0x0000d370, 0x3fffffe3 },
+    { 0x0000d374, 0x57ffffe3 },
+    { 0x0000d378, 0x5fffffe2 },
+    { 0x0000d37c, 0x7fffffe2 },
+    { 0x0000d380, 0x7f3c7bba },
+    { 0x0000d384, 0xf3307ff0 },
+    { 0x0000a388, 0x0c000000 },
+    { 0x0000a38c, 0x20202020 },
+    { 0x0000a390, 0x20202020 },
+    { 0x0000a394, 0x39ce739c },
+    { 0x0000a398, 0x0000039c },
+    { 0x0000a39c, 0x00000001 },
+    { 0x0000a3a0, 0x00000000 },
+    { 0x0000a3a4, 0x00000000 },
+    { 0x0000a3a8, 0x00000000 },
+    { 0x0000a3ac, 0x00000000 },
+    { 0x0000a3b0, 0x00000000 },
+    { 0x0000a3b4, 0x00000000 },
+    { 0x0000a3b8, 0x00000000 },
+    { 0x0000a3bc, 0x00000000 },
+    { 0x0000a3c0, 0x00000000 },
+    { 0x0000a3c4, 0x00000000 },
+    { 0x0000a3cc, 0x20202020 },
+    { 0x0000a3d0, 0x20202020 },
+    { 0x0000a3d4, 0x20202020 },
+    { 0x0000a3dc, 0x39ce739c },
+    { 0x0000a3e0, 0x0000039c },
+    { 0x0000a3e4, 0x00000000 },
+    { 0x0000a3e8, 0x18c43433 },
+    { 0x0000a3ec, 0x00f70081 },
+    { 0x00007800, 0x00140000 },
+    { 0x00007804, 0x0e4548d8 },
+    { 0x00007808, 0x54214514 },
+    { 0x0000780c, 0x02025820 },
+    { 0x00007810, 0x71c0d388 },
+    { 0x00007814, 0x924934a8 },
+    { 0x0000781c, 0x00000000 },
+    { 0x00007820, 0x00000c04 },
+    { 0x00007824, 0x00d86fff },
+    { 0x00007828, 0x26d2491b },
+    { 0x0000782c, 0x6e36d97b },
+    { 0x00007830, 0xedb6d96c },
+    { 0x00007834, 0x71400086 },
+    { 0x00007838, 0xfac68800 },
+    { 0x0000783c, 0x0001fffe },
+    { 0x00007840, 0xffeb1a20 },
+    { 0x00007844, 0x000c0db6 },
+    { 0x00007848, 0x6db61b6f },
+    { 0x0000784c, 0x6d9b66db },
+    { 0x00007850, 0x6d8c6dba },
+    { 0x00007854, 0x00040000 },
+    { 0x00007858, 0xdb003012 },
+    { 0x0000785c, 0x04924914 },
+    { 0x00007860, 0x21084210 },
+    { 0x00007864, 0xf7d7ffde },
+    { 0x00007868, 0xc2034080 },
+    { 0x0000786c, 0x48609eb4 },
+    { 0x00007870, 0x10142c00 },
+};
+
+static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285[][2] = {
+    {0x00004040,  0x9248fd00 },
+    {0x00004040,  0x24924924 },
+    {0x00004040,  0xa8000019 },
+    {0x00004040,  0x13160820 },
+    {0x00004040,  0xe5980560 },
+    {0x00004040,  0xc01dcffd },
+    {0x00004040,  0x1aaabe41 },
+    {0x00004040,  0xbe105554 },
+    {0x00004040,  0x00043007 },
+    {0x00004044,  0x00000000 },
+};
+
+static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
+    {0x00004040,  0x9248fd00 },
+    {0x00004040,  0x24924924 },
+    {0x00004040,  0xa8000019 },
+    {0x00004040,  0x13160820 },
+    {0x00004040,  0xe5980560 },
+    {0x00004040,  0xc01dcffc },
+    {0x00004040,  0x1aaabe41 },
+    {0x00004040,  0xbe105554 },
+    {0x00004040,  0x00043007 },
+    {0x00004044,  0x00000000 },
+};
+
+static const u_int32_t ar9285Modes_9285_1_2[][6] = {
+    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+    { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
+    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+    { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
+    { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
+    { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
+    { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
+    { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+    { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
+    { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+    { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
+    { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
+    { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 },
+    { 0x00009848, 0x00001066, 0x00001066, 0x00000057, 0x00000057, 0x00001059 },
+    { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
+    { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e },
+    { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 },
+    { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+    { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+    { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
+    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
+    { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+    { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
+    { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 },
+    { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c },
+    { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+    { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+    { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+    { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
+    { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+    { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+    { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 },
+    { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 },
+    { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 },
+    { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 },
+    { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 },
+    { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 },
+    { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 },
+    { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+    { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 },
+    { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 },
+    { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 },
+    { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 },
+    { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 },
+    { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 },
+    { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 },
+    { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 },
+    { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 },
+    { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 },
+    { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 },
+    { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 },
+    { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 },
+    { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 },
+    { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 },
+    { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 },
+    { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 },
+    { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 },
+    { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 },
+    { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 },
+    { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
+    { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
+    { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
+    { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
+    { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
+    { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
+    { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 },
+    { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 },
+    { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 },
+    { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 },
+    { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 },
+    { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 },
+    { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 },
+    { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 },
+    { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 },
+    { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 },
+    { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+    { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 },
+    { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 },
+    { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 },
+    { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 },
+    { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 },
+    { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 },
+    { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 },
+    { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 },
+    { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 },
+    { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 },
+    { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 },
+    { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 },
+    { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 },
+    { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 },
+    { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 },
+    { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 },
+    { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 },
+    { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 },
+    { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 },
+    { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 },
+    { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 },
+    { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 },
+    { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 },
+    { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 },
+    { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 },
+    { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 },
+    { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 },
+    { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 },
+    { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 },
+    { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 },
+    { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 },
+    { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 },
+    { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 },
+    { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 },
+    { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 },
+    { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 },
+    { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 },
+    { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 },
+    { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 },
+    { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 },
+    { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 },
+    { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 },
+    { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 },
+    { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 },
+    { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+    { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 },
+    { 0x0000aa04, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 },
+    { 0x0000aa08, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 },
+    { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 },
+    { 0x0000aa10, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 },
+    { 0x0000aa14, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 },
+    { 0x0000aa18, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 },
+    { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 },
+    { 0x0000aa20, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 },
+    { 0x0000aa24, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 },
+    { 0x0000aa28, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 },
+    { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+    { 0x0000aa30, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+    { 0x0000aa34, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 },
+    { 0x0000aa38, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 },
+    { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 },
+    { 0x0000aa40, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 },
+    { 0x0000aa44, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 },
+    { 0x0000aa48, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 },
+    { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 },
+    { 0x0000aa50, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 },
+    { 0x0000aa54, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 },
+    { 0x0000aa58, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 },
+    { 0x0000aa5c, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 },
+    { 0x0000aa60, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 },
+    { 0x0000aa64, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 },
+    { 0x0000aa68, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 },
+    { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 },
+    { 0x0000aa70, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 },
+    { 0x0000aa74, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 },
+    { 0x0000aa78, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 },
+    { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 },
+    { 0x0000aa80, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 },
+    { 0x0000aa84, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 },
+    { 0x0000aa88, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 },
+    { 0x0000aa8c, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 },
+    { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 },
+    { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 },
+    { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 },
+    { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 },
+    { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 },
+    { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 },
+    { 0x0000aaa8, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 },
+    { 0x0000aaac, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 },
+    { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 },
+    { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 },
+    { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 },
+    { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+    { 0x0000aac0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+    { 0x0000aac4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 },
+    { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 },
+    { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 },
+    { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 },
+    { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 },
+    { 0x0000aad8, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 },
+    { 0x0000aadc, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 },
+    { 0x0000aae0, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 },
+    { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 },
+    { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 },
+    { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 },
+    { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 },
+    { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 },
+    { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 },
+    { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 },
+    { 0x0000ab00, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 },
+    { 0x0000ab04, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 },
+    { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 },
+    { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 },
+    { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 },
+    { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 },
+    { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 },
+    { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 },
+    { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 },
+    { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 },
+    { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 },
+    { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 },
+    { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 },
+    { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 },
+    { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 },
+    { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 },
+    { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 },
+    { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 },
+    { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 },
+    { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 },
+    { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 },
+    { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 },
+    { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 },
+    { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 },
+    { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 },
+    { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 },
+    { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 },
+    { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+    { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
+    { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 },
+    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+    { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
+    { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 },
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
+    { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 },
+    { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 },
+    { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 },
+    { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 },
+    { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 },
+    { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 },
+    { 0x0000a320, 0x00000000, 0x00000000, 0x0002b89a, 0x0002b89a, 0x00000000 },
+    { 0x0000a324, 0x00000000, 0x00000000, 0x0002d89b, 0x0002d89b, 0x00000000 },
+    { 0x0000a328, 0x00000000, 0x00000000, 0x0002f89c, 0x0002f89c, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x0003189d, 0x0003189d, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x0003389e, 0x0003389e, 0x00000000 },
+    { 0x0000a334, 0x00000000, 0x00000000, 0x000368de, 0x000368de, 0x00000000 },
+    { 0x0000a338, 0x00000000, 0x00000000, 0x0003891e, 0x0003891e, 0x00000000 },
+    { 0x0000a33c, 0x00000000, 0x00000000, 0x0003a95e, 0x0003a95e, 0x00000000 },
+    { 0x0000a340, 0x00000000, 0x00000000, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+};
+
+static const u_int32_t ar9285Common_9285_1_2[][2] = {
+    { 0x0000000c, 0x00000000 },
+    { 0x00000030, 0x00020045 },
+    { 0x00000034, 0x00000005 },
+    { 0x00000040, 0x00000000 },
+    { 0x00000044, 0x00000008 },
+    { 0x00000048, 0x00000008 },
+    { 0x0000004c, 0x00000010 },
+    { 0x00000050, 0x00000000 },
+    { 0x00000054, 0x0000001f },
+    { 0x00000800, 0x00000000 },
+    { 0x00000804, 0x00000000 },
+    { 0x00000808, 0x00000000 },
+    { 0x0000080c, 0x00000000 },
+    { 0x00000810, 0x00000000 },
+    { 0x00000814, 0x00000000 },
+    { 0x00000818, 0x00000000 },
+    { 0x0000081c, 0x00000000 },
+    { 0x00000820, 0x00000000 },
+    { 0x00000824, 0x00000000 },
+    { 0x00001040, 0x002ffc0f },
+    { 0x00001044, 0x002ffc0f },
+    { 0x00001048, 0x002ffc0f },
+    { 0x0000104c, 0x002ffc0f },
+    { 0x00001050, 0x002ffc0f },
+    { 0x00001054, 0x002ffc0f },
+    { 0x00001058, 0x002ffc0f },
+    { 0x0000105c, 0x002ffc0f },
+    { 0x00001060, 0x002ffc0f },
+    { 0x00001064, 0x002ffc0f },
+    { 0x00001230, 0x00000000 },
+    { 0x00001270, 0x00000000 },
+    { 0x00001038, 0x00000000 },
+    { 0x00001078, 0x00000000 },
+    { 0x000010b8, 0x00000000 },
+    { 0x000010f8, 0x00000000 },
+    { 0x00001138, 0x00000000 },
+    { 0x00001178, 0x00000000 },
+    { 0x000011b8, 0x00000000 },
+    { 0x000011f8, 0x00000000 },
+    { 0x00001238, 0x00000000 },
+    { 0x00001278, 0x00000000 },
+    { 0x000012b8, 0x00000000 },
+    { 0x000012f8, 0x00000000 },
+    { 0x00001338, 0x00000000 },
+    { 0x00001378, 0x00000000 },
+    { 0x000013b8, 0x00000000 },
+    { 0x000013f8, 0x00000000 },
+    { 0x00001438, 0x00000000 },
+    { 0x00001478, 0x00000000 },
+    { 0x000014b8, 0x00000000 },
+    { 0x000014f8, 0x00000000 },
+    { 0x00001538, 0x00000000 },
+    { 0x00001578, 0x00000000 },
+    { 0x000015b8, 0x00000000 },
+    { 0x000015f8, 0x00000000 },
+    { 0x00001638, 0x00000000 },
+    { 0x00001678, 0x00000000 },
+    { 0x000016b8, 0x00000000 },
+    { 0x000016f8, 0x00000000 },
+    { 0x00001738, 0x00000000 },
+    { 0x00001778, 0x00000000 },
+    { 0x000017b8, 0x00000000 },
+    { 0x000017f8, 0x00000000 },
+    { 0x0000103c, 0x00000000 },
+    { 0x0000107c, 0x00000000 },
+    { 0x000010bc, 0x00000000 },
+    { 0x000010fc, 0x00000000 },
+    { 0x0000113c, 0x00000000 },
+    { 0x0000117c, 0x00000000 },
+    { 0x000011bc, 0x00000000 },
+    { 0x000011fc, 0x00000000 },
+    { 0x0000123c, 0x00000000 },
+    { 0x0000127c, 0x00000000 },
+    { 0x000012bc, 0x00000000 },
+    { 0x000012fc, 0x00000000 },
+    { 0x0000133c, 0x00000000 },
+    { 0x0000137c, 0x00000000 },
+    { 0x000013bc, 0x00000000 },
+    { 0x000013fc, 0x00000000 },
+    { 0x0000143c, 0x00000000 },
+    { 0x0000147c, 0x00000000 },
+    { 0x00004030, 0x00000002 },
+    { 0x0000403c, 0x00000002 },
+    { 0x00004024, 0x0000001f },
+    { 0x00004060, 0x00000000 },
+    { 0x00004064, 0x00000000 },
+    { 0x00007010, 0x00000031 },
+    { 0x00007034, 0x00000002 },
+    { 0x00007038, 0x000004c2 },
+    { 0x00008004, 0x00000000 },
+    { 0x00008008, 0x00000000 },
+    { 0x0000800c, 0x00000000 },
+    { 0x00008018, 0x00000700 },
+    { 0x00008020, 0x00000000 },
+    { 0x00008038, 0x00000000 },
+    { 0x0000803c, 0x00000000 },
+    { 0x00008048, 0x00000000 },
+    { 0x00008054, 0x00000000 },
+    { 0x00008058, 0x00000000 },
+    { 0x0000805c, 0x000fc78f },
+    { 0x00008060, 0x0000000f },
+    { 0x00008064, 0x00000000 },
+    { 0x00008070, 0x00000000 },
+    { 0x000080c0, 0x2a80001a },
+    { 0x000080c4, 0x05dc01e0 },
+    { 0x000080c8, 0x1f402710 },
+    { 0x000080cc, 0x01f40000 },
+    { 0x000080d0, 0x00001e00 },
+    { 0x000080d4, 0x00000000 },
+    { 0x000080d8, 0x00400000 },
+    { 0x000080e0, 0xffffffff },
+    { 0x000080e4, 0x0000ffff },
+    { 0x000080e8, 0x003f3f3f },
+    { 0x000080ec, 0x00000000 },
+    { 0x000080f0, 0x00000000 },
+    { 0x000080f4, 0x00000000 },
+    { 0x000080f8, 0x00000000 },
+    { 0x000080fc, 0x00020000 },
+    { 0x00008100, 0x00020000 },
+    { 0x00008104, 0x00000001 },
+    { 0x00008108, 0x00000052 },
+    { 0x0000810c, 0x00000000 },
+    { 0x00008110, 0x00000168 },
+    { 0x00008118, 0x000100aa },
+    { 0x0000811c, 0x00003210 },
+    { 0x00008120, 0x08f04800 },
+    { 0x00008124, 0x00000000 },
+    { 0x00008128, 0x00000000 },
+    { 0x0000812c, 0x00000000 },
+    { 0x00008130, 0x00000000 },
+    { 0x00008134, 0x00000000 },
+    { 0x00008138, 0x00000000 },
+    { 0x0000813c, 0x00000000 },
+    { 0x00008144, 0xffffffff },
+    { 0x00008168, 0x00000000 },
+    { 0x0000816c, 0x00000000 },
+    { 0x00008170, 0x32143320 },
+    { 0x00008174, 0xfaa4fa50 },
+    { 0x00008178, 0x00000100 },
+    { 0x0000817c, 0x00000000 },
+    { 0x000081c0, 0x00000000 },
+    { 0x000081d0, 0x00003210 },
+    { 0x000081ec, 0x00000000 },
+    { 0x000081f0, 0x00000000 },
+    { 0x000081f4, 0x00000000 },
+    { 0x000081f8, 0x00000000 },
+    { 0x000081fc, 0x00000000 },
+    { 0x00008200, 0x00000000 },
+    { 0x00008204, 0x00000000 },
+    { 0x00008208, 0x00000000 },
+    { 0x0000820c, 0x00000000 },
+    { 0x00008210, 0x00000000 },
+    { 0x00008214, 0x00000000 },
+    { 0x00008218, 0x00000000 },
+    { 0x0000821c, 0x00000000 },
+    { 0x00008220, 0x00000000 },
+    { 0x00008224, 0x00000000 },
+    { 0x00008228, 0x00000000 },
+    { 0x0000822c, 0x00000000 },
+    { 0x00008230, 0x00000000 },
+    { 0x00008234, 0x00000000 },
+    { 0x00008238, 0x00000000 },
+    { 0x0000823c, 0x00000000 },
+    { 0x00008240, 0x00100000 },
+    { 0x00008244, 0x0010f400 },
+    { 0x00008248, 0x00000100 },
+    { 0x0000824c, 0x0001e800 },
+    { 0x00008250, 0x00000000 },
+    { 0x00008254, 0x00000000 },
+    { 0x00008258, 0x00000000 },
+    { 0x0000825c, 0x400000ff },
+    { 0x00008260, 0x00080922 },
+    { 0x00008264, 0xa8a00010 },
+    { 0x00008270, 0x00000000 },
+    { 0x00008274, 0x40000000 },
+    { 0x00008278, 0x003e4180 },
+    { 0x0000827c, 0x00000000 },
+    { 0x00008284, 0x0000002c },
+    { 0x00008288, 0x0000002c },
+    { 0x0000828c, 0x00000000 },
+    { 0x00008294, 0x00000000 },
+    { 0x00008298, 0x00000000 },
+    { 0x0000829c, 0x00000000 },
+    { 0x00008300, 0x00000040 },
+    { 0x00008314, 0x00000000 },
+    { 0x00008328, 0x00000000 },
+    { 0x0000832c, 0x00000001 },
+    { 0x00008330, 0x00000302 },
+    { 0x00008334, 0x00000e00 },
+    { 0x00008338, 0x00ff0000 },
+    { 0x0000833c, 0x00000000 },
+    { 0x00008340, 0x00010380 },
+    { 0x00008344, 0x00581043 },
+    { 0x00009808, 0x00000000 },
+    { 0x0000980c, 0xafe68e30 },
+    { 0x00009810, 0xfd14e000 },
+    { 0x00009814, 0x9c0a9f6b },
+    { 0x0000981c, 0x00000000 },
+    { 0x0000982c, 0x0000a000 },
+    { 0x00009830, 0x00000000 },
+    { 0x0000983c, 0x00200400 },
+    { 0x0000984c, 0x0040233c },
+    { 0x00009854, 0x00000044 },
+    { 0x00009900, 0x00000000 },
+    { 0x00009904, 0x00000000 },
+    { 0x00009908, 0x00000000 },
+    { 0x0000990c, 0x00000000 },
+    { 0x00009910, 0x01002310 },
+    { 0x0000991c, 0x10000fff },
+    { 0x00009920, 0x04900000 },
+    { 0x00009928, 0x00000001 },
+    { 0x0000992c, 0x00000004 },
+    { 0x00009934, 0x1e1f2022 },
+    { 0x00009938, 0x0a0b0c0d },
+    { 0x0000993c, 0x00000000 },
+    { 0x00009940, 0x14750604 },
+    { 0x00009948, 0x9280c00a },
+    { 0x0000994c, 0x00020028 },
+    { 0x00009954, 0x5f3ca3de },
+    { 0x00009958, 0x2108ecff },
+    { 0x00009968, 0x000003ce },
+    { 0x00009970, 0x192bb515 },
+    { 0x00009974, 0x00000000 },
+    { 0x00009978, 0x00000001 },
+    { 0x0000997c, 0x00000000 },
+    { 0x00009980, 0x00000000 },
+    { 0x00009984, 0x00000000 },
+    { 0x00009988, 0x00000000 },
+    { 0x0000998c, 0x00000000 },
+    { 0x00009990, 0x00000000 },
+    { 0x00009994, 0x00000000 },
+    { 0x00009998, 0x00000000 },
+    { 0x0000999c, 0x00000000 },
+    { 0x000099a0, 0x00000000 },
+    { 0x000099a4, 0x00000001 },
+    { 0x000099a8, 0x201fff00 },
+    { 0x000099ac, 0x2def1000 },
+    { 0x000099b0, 0x03051000 },
+    { 0x000099b4, 0x00000820 },
+    { 0x000099dc, 0x00000000 },
+    { 0x000099e0, 0x00000000 },
+    { 0x000099e4, 0xaaaaaaaa },
+    { 0x000099e8, 0x3c466478 },
+    { 0x000099ec, 0x0cc80caa },
+    { 0x000099f0, 0x00000000 },
+    { 0x0000a208, 0x803e6788 },
+    { 0x0000a210, 0x4080a333 },
+    { 0x0000a214, 0x00206c10 },
+    { 0x0000a218, 0x009c4060 },
+    { 0x0000a220, 0x01834061 },
+    { 0x0000a224, 0x00000400 },
+    { 0x0000a228, 0x000003b5 },
+    { 0x0000a22c, 0x00000000 },
+    { 0x0000a234, 0x20202020 },
+    { 0x0000a238, 0x20202020 },
+    { 0x0000a244, 0x00000000 },
+    { 0x0000a248, 0xfffffffc },
+    { 0x0000a24c, 0x00000000 },
+    { 0x0000a254, 0x00000000 },
+    { 0x0000a258, 0x0ccb5380 },
+    { 0x0000a25c, 0x15151501 },
+    { 0x0000a260, 0xdfa90f01 },
+    { 0x0000a268, 0x00000000 },
+    { 0x0000a26c, 0x0ebae9e6 },
+    { 0x0000d270, 0x0d820820 },
+    { 0x0000a278, 0x318c6318 },
+    { 0x0000a27c, 0x050c0318 },
+    { 0x0000d35c, 0x07ffffef },
+    { 0x0000d360, 0x0fffffe7 },
+    { 0x0000d364, 0x17ffffe5 },
+    { 0x0000d368, 0x1fffffe4 },
+    { 0x0000d36c, 0x37ffffe3 },
+    { 0x0000d370, 0x3fffffe3 },
+    { 0x0000d374, 0x57ffffe3 },
+    { 0x0000d378, 0x5fffffe2 },
+    { 0x0000d37c, 0x7fffffe2 },
+    { 0x0000d380, 0x7f3c7bba },
+    { 0x0000d384, 0xf3307ff0 },
+    { 0x0000a388, 0x0c000000 },
+    { 0x0000a38c, 0x20202020 },
+    { 0x0000a390, 0x20202020 },
+    { 0x0000a394, 0x318c6318 },
+    { 0x0000a398, 0x00000318 },
+    { 0x0000a39c, 0x00000001 },
+    { 0x0000a3a0, 0x00000000 },
+    { 0x0000a3a4, 0x00000000 },
+    { 0x0000a3a8, 0x00000000 },
+    { 0x0000a3ac, 0x00000000 },
+    { 0x0000a3b0, 0x00000000 },
+    { 0x0000a3b4, 0x00000000 },
+    { 0x0000a3b8, 0x00000000 },
+    { 0x0000a3bc, 0x00000000 },
+    { 0x0000a3c0, 0x00000000 },
+    { 0x0000a3c4, 0x00000000 },
+    { 0x0000a3cc, 0x20202020 },
+    { 0x0000a3d0, 0x20202020 },
+    { 0x0000a3d4, 0x20202020 },
+    { 0x0000a3dc, 0x318c6318 },
+    { 0x0000a3e0, 0x00000318 },
+    { 0x0000a3e4, 0x00000000 },
+    { 0x0000a3e8, 0x18c43433 },
+    { 0x0000a3ec, 0x00f70081 },
+    { 0x00007800, 0x00140000 },
+    { 0x00007804, 0x0e4548d8 },
+    { 0x00007808, 0x54214514 },
+    { 0x0000780c, 0x02025820 },
+    { 0x00007810, 0x71c0d388 },
+    { 0x00007814, 0x924934a8 },
+    { 0x0000781c, 0x00000000 },
+    { 0x00007820, 0x00000c04 },
+    { 0x00007824, 0x00d86fff },
+    { 0x00007828, 0x26d2491b },
+    { 0x0000782c, 0x6e36d97b },
+    { 0x00007830, 0xedb6d96e },
+    { 0x00007834, 0x71400087 },
+    { 0x00007838, 0xfac68801 },
+    { 0x0000783c, 0x0001fffe },
+    { 0x00007840, 0xffeb1a20 },
+    { 0x00007844, 0x000c0db6 },
+    { 0x00007848, 0x6db61b6f },
+    { 0x0000784c, 0x6d9b66db },
+    { 0x00007850, 0x6d8c6dba },
+    { 0x00007854, 0x00040000 },
+    { 0x00007858, 0xdb003012 },
+    { 0x0000785c, 0x04924914 },
+    { 0x00007860, 0x21084210 },
+    { 0x00007864, 0xf7d7ffde },
+    { 0x00007868, 0xc2034080 },
+    { 0x0000786c, 0x48609eb4 },
+    { 0x00007870, 0x10142c00 },
+};
+
+static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
+    {0x00004040,  0x9248fd00 },
+    {0x00004040,  0x24924924 },
+    {0x00004040,  0xa8000019 },
+    {0x00004040,  0x13160820 },
+    {0x00004040,  0xe5980560 },
+    {0x00004040,  0xc01dcffd },
+    {0x00004040,  0x1aaabe41 },
+    {0x00004040,  0xbe105554 },
+    {0x00004040,  0x00043007 },
+    {0x00004044,  0x00000000 },
+};
+
+static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
+    {0x00004040,  0x9248fd00 },
+    {0x00004040,  0x24924924 },
+    {0x00004040,  0xa8000019 },
+    {0x00004040,  0x13160820 },
+    {0x00004040,  0xe5980560 },
+    {0x00004040,  0xc01dcffc },
+    {0x00004040,  0x1aaabe41 },
     {0x00004040,  0xbe105554 },
     {0x00004040,  0x00043007 },
     {0x00004044,  0x00000000 },
diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c
new file mode 100644
index 0000000..af32d09
--- /dev/null
+++ b/drivers/net/wireless/ath9k/mac.c
@@ -0,0 +1,946 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah,
+					struct ath9k_tx_queue_info *qi)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
+		"tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
+		ahp->ah_txOkInterruptMask, ahp->ah_txErrInterruptMask,
+		ahp->ah_txDescInterruptMask, ahp->ah_txEolInterruptMask,
+		ahp->ah_txUrnInterruptMask);
+
+	REG_WRITE(ah, AR_IMR_S0,
+		  SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
+		  | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC));
+	REG_WRITE(ah, AR_IMR_S1,
+		  SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
+		  | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL));
+	REG_RMW_FIELD(ah, AR_IMR_S2,
+		      AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
+}
+
+u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q)
+{
+	return REG_READ(ah, AR_QTXDP(q));
+}
+
+bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp)
+{
+	REG_WRITE(ah, AR_QTXDP(q), txdp);
+
+	return true;
+}
+
+bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
+{
+	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
+
+	REG_WRITE(ah, AR_Q_TXE, 1 << q);
+
+	return true;
+}
+
+u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
+{
+	u32 npend;
+
+	npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
+	if (npend == 0) {
+
+		if (REG_READ(ah, AR_Q_TXE) & (1 << q))
+			npend = 1;
+	}
+
+	return npend;
+}
+
+bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	u32 txcfg, curLevel, newLevel;
+	enum ath9k_int omask;
+
+	if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD)
+		return false;
+
+	omask = ath9k_hw_set_interrupts(ah, ahp->ah_maskReg & ~ATH9K_INT_GLOBAL);
+
+	txcfg = REG_READ(ah, AR_TXCFG);
+	curLevel = MS(txcfg, AR_FTRIG);
+	newLevel = curLevel;
+	if (bIncTrigLevel) {
+		if (curLevel < MAX_TX_FIFO_THRESHOLD)
+			newLevel++;
+	} else if (curLevel > MIN_TX_FIFO_THRESHOLD)
+		newLevel--;
+	if (newLevel != curLevel)
+		REG_WRITE(ah, AR_TXCFG,
+			  (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
+
+	ath9k_hw_set_interrupts(ah, omask);
+
+	ah->ah_txTrigLevel = newLevel;
+
+	return newLevel != curLevel;
+}
+
+bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
+{
+	u32 tsfLow, j, wait;
+
+	REG_WRITE(ah, AR_Q_TXD, 1 << q);
+
+	for (wait = 1000; wait != 0; wait--) {
+		if (ath9k_hw_numtxpending(ah, q) == 0)
+			break;
+		udelay(100);
+	}
+
+	if (ath9k_hw_numtxpending(ah, q)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+			"%s: Num of pending TX Frames %d on Q %d\n",
+			__func__, ath9k_hw_numtxpending(ah, q), q);
+
+		for (j = 0; j < 2; j++) {
+			tsfLow = REG_READ(ah, AR_TSF_L32);
+			REG_WRITE(ah, AR_QUIET2,
+				  SM(10, AR_QUIET2_QUIET_DUR));
+			REG_WRITE(ah, AR_QUIET_PERIOD, 100);
+			REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
+			REG_SET_BIT(ah, AR_TIMER_MODE,
+				       AR_QUIET_TIMER_EN);
+
+			if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
+				break;
+
+			DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+				"TSF have moved while trying to set "
+				"quiet time TSF: 0x%08x\n", tsfLow);
+		}
+
+		REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+
+		udelay(200);
+		REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
+
+		wait = 1000;
+
+		while (ath9k_hw_numtxpending(ah, q)) {
+			if ((--wait) == 0) {
+				DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
+					"Failed to stop Tx DMA in 100 "
+					"msec after killing last frame\n");
+				break;
+			}
+			udelay(100);
+		}
+
+		REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+	}
+
+	REG_WRITE(ah, AR_Q_TXD, 0);
+
+	return wait != 0;
+}
+
+bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
+			 u32 segLen, bool firstSeg,
+			 bool lastSeg, const struct ath_desc *ds0)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	if (firstSeg) {
+		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
+	} else if (lastSeg) {
+		ads->ds_ctl0 = 0;
+		ads->ds_ctl1 = segLen;
+		ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
+		ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
+	} else {
+		ads->ds_ctl0 = 0;
+		ads->ds_ctl1 = segLen | AR_TxMore;
+		ads->ds_ctl2 = 0;
+		ads->ds_ctl3 = 0;
+	}
+	ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+	ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+	ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+	ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+	ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+
+	return true;
+}
+
+void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+	ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+	ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+	ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+	ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+}
+
+int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	if ((ads->ds_txstatus9 & AR_TxDone) == 0)
+		return -EINPROGRESS;
+
+	ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
+	ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
+	ds->ds_txstat.ts_status = 0;
+	ds->ds_txstat.ts_flags = 0;
+
+	if (ads->ds_txstatus1 & AR_ExcessiveRetries)
+		ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
+	if (ads->ds_txstatus1 & AR_Filtered)
+		ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
+	if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
+		ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
+		ath9k_hw_updatetxtriglevel(ah, true);
+	}
+	if (ads->ds_txstatus9 & AR_TxOpExceeded)
+		ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
+	if (ads->ds_txstatus1 & AR_TxTimerExpired)
+		ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
+
+	if (ads->ds_txstatus1 & AR_DescCfgErr)
+		ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
+	if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
+		ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
+		ath9k_hw_updatetxtriglevel(ah, true);
+	}
+	if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
+		ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
+		ath9k_hw_updatetxtriglevel(ah, true);
+	}
+	if (ads->ds_txstatus0 & AR_TxBaStatus) {
+		ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
+		ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
+		ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
+	}
+
+	ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
+	switch (ds->ds_txstat.ts_rateindex) {
+	case 0:
+		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
+		break;
+	case 1:
+		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
+		break;
+	case 2:
+		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
+		break;
+	case 3:
+		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
+		break;
+	}
+
+	ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
+	ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
+	ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
+	ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
+	ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
+	ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
+	ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
+	ds->ds_txstat.evm0 = ads->AR_TxEVM0;
+	ds->ds_txstat.evm1 = ads->AR_TxEVM1;
+	ds->ds_txstat.evm2 = ads->AR_TxEVM2;
+	ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
+	ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
+	ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
+	ds->ds_txstat.ts_antenna = 1;
+
+	return 0;
+}
+
+void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
+			    u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
+			    u32 keyIx, enum ath9k_key_type keyType, u32 flags)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	txPower += ahp->ah_txPowerIndexOffset;
+	if (txPower > 63)
+		txPower = 63;
+
+	ads->ds_ctl0 = (pktLen & AR_FrameLen)
+		| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+		| SM(txPower, AR_XmitPower)
+		| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+		| (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
+		| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
+		| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
+
+	ads->ds_ctl1 =
+		(keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
+		| SM(type, AR_FrameType)
+		| (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
+		| (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
+		| (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+
+	ads->ds_ctl6 = SM(keyType, AR_EncrType);
+
+	if (AR_SREV_9285(ah)) {
+		ads->ds_ctl8 = 0;
+		ads->ds_ctl9 = 0;
+		ads->ds_ctl10 = 0;
+		ads->ds_ctl11 = 0;
+	}
+}
+
+void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
+				  struct ath_desc *lastds,
+				  u32 durUpdateEn, u32 rtsctsRate,
+				  u32 rtsctsDuration,
+				  struct ath9k_11n_rate_series series[],
+				  u32 nseries, u32 flags)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	struct ar5416_desc *last_ads = AR5416DESC(lastds);
+	u32 ds_ctl0;
+
+	(void) nseries;
+	(void) rtsctsDuration;
+
+	if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
+		ds_ctl0 = ads->ds_ctl0;
+
+		if (flags & ATH9K_TXDESC_RTSENA) {
+			ds_ctl0 &= ~AR_CTSEnable;
+			ds_ctl0 |= AR_RTSEnable;
+		} else {
+			ds_ctl0 &= ~AR_RTSEnable;
+			ds_ctl0 |= AR_CTSEnable;
+		}
+
+		ads->ds_ctl0 = ds_ctl0;
+	} else {
+		ads->ds_ctl0 =
+			(ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
+	}
+
+	ads->ds_ctl2 = set11nTries(series, 0)
+		| set11nTries(series, 1)
+		| set11nTries(series, 2)
+		| set11nTries(series, 3)
+		| (durUpdateEn ? AR_DurUpdateEna : 0)
+		| SM(0, AR_BurstDur);
+
+	ads->ds_ctl3 = set11nRate(series, 0)
+		| set11nRate(series, 1)
+		| set11nRate(series, 2)
+		| set11nRate(series, 3);
+
+	ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
+		| set11nPktDurRTSCTS(series, 1);
+
+	ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
+		| set11nPktDurRTSCTS(series, 3);
+
+	ads->ds_ctl7 = set11nRateFlags(series, 0)
+		| set11nRateFlags(series, 1)
+		| set11nRateFlags(series, 2)
+		| set11nRateFlags(series, 3)
+		| SM(rtsctsRate, AR_RTSCTSRate);
+	last_ads->ds_ctl2 = ads->ds_ctl2;
+	last_ads->ds_ctl3 = ads->ds_ctl3;
+}
+
+void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
+				u32 aggrLen)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+	ads->ds_ctl6 &= ~AR_AggrLen;
+	ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
+}
+
+void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
+				 u32 numDelims)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	unsigned int ctl6;
+
+	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+
+	ctl6 = ads->ds_ctl6;
+	ctl6 &= ~AR_PadDelim;
+	ctl6 |= SM(numDelims, AR_PadDelim);
+	ads->ds_ctl6 = ctl6;
+}
+
+void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_ctl1 |= AR_IsAggr;
+	ads->ds_ctl1 &= ~AR_MoreAggr;
+	ads->ds_ctl6 &= ~AR_PadDelim;
+}
+
+void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
+}
+
+void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
+				   u32 burstDuration)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_ctl2 &= ~AR_BurstDur;
+	ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
+}
+
+void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
+				     u32 vmf)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	if (vmf)
+		ads->ds_ctl0 |= AR_VirtMoreFrag;
+	else
+		ads->ds_ctl0 &= ~AR_VirtMoreFrag;
+}
+
+void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+
+	*txqs &= ahp->ah_intrTxqs;
+	ahp->ah_intrTxqs &= ~(*txqs);
+}
+
+bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
+			    const struct ath9k_tx_queue_info *qinfo)
+{
+	u32 cw;
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_tx_queue_info *qi;
+
+	if (q >= pCap->total_queues) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+		return false;
+	}
+
+	qi = &ahp->ah_txq[q];
+	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
+		return false;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", qi);
+
+	qi->tqi_ver = qinfo->tqi_ver;
+	qi->tqi_subtype = qinfo->tqi_subtype;
+	qi->tqi_qflags = qinfo->tqi_qflags;
+	qi->tqi_priority = qinfo->tqi_priority;
+	if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
+		qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
+	else
+		qi->tqi_aifs = INIT_AIFS;
+	if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
+		cw = min(qinfo->tqi_cwmin, 1024U);
+		qi->tqi_cwmin = 1;
+		while (qi->tqi_cwmin < cw)
+			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
+	} else
+		qi->tqi_cwmin = qinfo->tqi_cwmin;
+	if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
+		cw = min(qinfo->tqi_cwmax, 1024U);
+		qi->tqi_cwmax = 1;
+		while (qi->tqi_cwmax < cw)
+			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
+	} else
+		qi->tqi_cwmax = INIT_CWMAX;
+
+	if (qinfo->tqi_shretry != 0)
+		qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
+	else
+		qi->tqi_shretry = INIT_SH_RETRY;
+	if (qinfo->tqi_lgretry != 0)
+		qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
+	else
+		qi->tqi_lgretry = INIT_LG_RETRY;
+	qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
+	qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
+	qi->tqi_burstTime = qinfo->tqi_burstTime;
+	qi->tqi_readyTime = qinfo->tqi_readyTime;
+
+	switch (qinfo->tqi_subtype) {
+	case ATH9K_WME_UPSD:
+		if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
+			qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
+		break;
+	default:
+		break;
+	}
+
+	return true;
+}
+
+bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
+			    struct ath9k_tx_queue_info *qinfo)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_tx_queue_info *qi;
+
+	if (q >= pCap->total_queues) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+		return false;
+	}
+
+	qi = &ahp->ah_txq[q];
+	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
+		return false;
+	}
+
+	qinfo->tqi_qflags = qi->tqi_qflags;
+	qinfo->tqi_ver = qi->tqi_ver;
+	qinfo->tqi_subtype = qi->tqi_subtype;
+	qinfo->tqi_qflags = qi->tqi_qflags;
+	qinfo->tqi_priority = qi->tqi_priority;
+	qinfo->tqi_aifs = qi->tqi_aifs;
+	qinfo->tqi_cwmin = qi->tqi_cwmin;
+	qinfo->tqi_cwmax = qi->tqi_cwmax;
+	qinfo->tqi_shretry = qi->tqi_shretry;
+	qinfo->tqi_lgretry = qi->tqi_lgretry;
+	qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
+	qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
+	qinfo->tqi_burstTime = qi->tqi_burstTime;
+	qinfo->tqi_readyTime = qi->tqi_readyTime;
+
+	return true;
+}
+
+int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
+			  const struct ath9k_tx_queue_info *qinfo)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_tx_queue_info *qi;
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	int q;
+
+	switch (type) {
+	case ATH9K_TX_QUEUE_BEACON:
+		q = pCap->total_queues - 1;
+		break;
+	case ATH9K_TX_QUEUE_CAB:
+		q = pCap->total_queues - 2;
+		break;
+	case ATH9K_TX_QUEUE_PSPOLL:
+		q = 1;
+		break;
+	case ATH9K_TX_QUEUE_UAPSD:
+		q = pCap->total_queues - 3;
+		break;
+	case ATH9K_TX_QUEUE_DATA:
+		for (q = 0; q < pCap->total_queues; q++)
+			if (ahp->ah_txq[q].tqi_type ==
+			    ATH9K_TX_QUEUE_INACTIVE)
+				break;
+		if (q == pCap->total_queues) {
+			DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+				"no available tx queue\n");
+			return -1;
+		}
+		break;
+	default:
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type);
+		return -1;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
+
+	qi = &ahp->ah_txq[q];
+	if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+			"tx queue %u already active\n", q);
+		return -1;
+	}
+	memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
+	qi->tqi_type = type;
+	if (qinfo == NULL) {
+		qi->tqi_qflags =
+			TXQ_FLAG_TXOKINT_ENABLE
+			| TXQ_FLAG_TXERRINT_ENABLE
+			| TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
+		qi->tqi_aifs = INIT_AIFS;
+		qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
+		qi->tqi_cwmax = INIT_CWMAX;
+		qi->tqi_shretry = INIT_SH_RETRY;
+		qi->tqi_lgretry = INIT_LG_RETRY;
+		qi->tqi_physCompBuf = 0;
+	} else {
+		qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
+		(void) ath9k_hw_set_txq_props(ah, q, qinfo);
+	}
+
+	return q;
+}
+
+bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_tx_queue_info *qi;
+
+	if (q >= pCap->total_queues) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+		return false;
+	}
+	qi = &ahp->ah_txq[q];
+	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
+		return false;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q);
+
+	qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
+	ahp->ah_txOkInterruptMask &= ~(1 << q);
+	ahp->ah_txErrInterruptMask &= ~(1 << q);
+	ahp->ah_txDescInterruptMask &= ~(1 << q);
+	ahp->ah_txEolInterruptMask &= ~(1 << q);
+	ahp->ah_txUrnInterruptMask &= ~(1 << q);
+	ath9k_hw_set_txq_interrupts(ah, qi);
+
+	return true;
+}
+
+bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
+{
+	struct ath_hal_5416 *ahp = AH5416(ah);
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+	struct ath9k_channel *chan = ah->ah_curchan;
+	struct ath9k_tx_queue_info *qi;
+	u32 cwMin, chanCwMin, value;
+
+	if (q >= pCap->total_queues) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+		return false;
+	}
+
+	qi = &ahp->ah_txq[q];
+	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
+		return true;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "reset queue %u\n", q);
+
+	if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
+		if (chan && IS_CHAN_B(chan))
+			chanCwMin = INIT_CWMIN_11B;
+		else
+			chanCwMin = INIT_CWMIN;
+
+		for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
+	} else
+		cwMin = qi->tqi_cwmin;
+
+	REG_WRITE(ah, AR_DLCL_IFS(q),
+		  SM(cwMin, AR_D_LCL_IFS_CWMIN) |
+		  SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
+		  SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
+
+	REG_WRITE(ah, AR_DRETRY_LIMIT(q),
+		  SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
+		  SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
+		  SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
+
+	REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
+	REG_WRITE(ah, AR_DMISC(q),
+		  AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
+
+	if (qi->tqi_cbrPeriod) {
+		REG_WRITE(ah, AR_QCBRCFG(q),
+			  SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
+			  SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
+		REG_WRITE(ah, AR_QMISC(q),
+			  REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
+			  (qi->tqi_cbrOverflowLimit ?
+			   AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
+	}
+	if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
+		REG_WRITE(ah, AR_QRDYTIMECFG(q),
+			  SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
+			  AR_Q_RDYTIMECFG_EN);
+	}
+
+	REG_WRITE(ah, AR_DCHNTIME(q),
+		  SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
+		  (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
+
+	if (qi->tqi_burstTime
+	    && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
+		REG_WRITE(ah, AR_QMISC(q),
+			  REG_READ(ah, AR_QMISC(q)) |
+			  AR_Q_MISC_RDYTIME_EXP_POLICY);
+
+	}
+
+	if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
+		REG_WRITE(ah, AR_DMISC(q),
+			  REG_READ(ah, AR_DMISC(q)) |
+			  AR_D_MISC_POST_FR_BKOFF_DIS);
+	}
+	if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
+		REG_WRITE(ah, AR_DMISC(q),
+			  REG_READ(ah, AR_DMISC(q)) |
+			  AR_D_MISC_FRAG_BKOFF_EN);
+	}
+	switch (qi->tqi_type) {
+	case ATH9K_TX_QUEUE_BEACON:
+		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
+			  | AR_Q_MISC_FSP_DBA_GATED
+			  | AR_Q_MISC_BEACON_USE
+			  | AR_Q_MISC_CBR_INCR_DIS1);
+
+		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
+			  | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
+			  | AR_D_MISC_BEACON_USE
+			  | AR_D_MISC_POST_FR_BKOFF_DIS);
+		break;
+	case ATH9K_TX_QUEUE_CAB:
+		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
+			  | AR_Q_MISC_FSP_DBA_GATED
+			  | AR_Q_MISC_CBR_INCR_DIS1
+			  | AR_Q_MISC_CBR_INCR_DIS0);
+		value = (qi->tqi_readyTime -
+			 (ah->ah_config.sw_beacon_response_time -
+			  ah->ah_config.dma_beacon_response_time) -
+			 ah->ah_config.additional_swba_backoff) * 1024;
+		REG_WRITE(ah, AR_QRDYTIMECFG(q),
+			  value | AR_Q_RDYTIMECFG_EN);
+		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
+			  | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
+		break;
+	case ATH9K_TX_QUEUE_PSPOLL:
+		REG_WRITE(ah, AR_QMISC(q),
+			  REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
+		break;
+	case ATH9K_TX_QUEUE_UAPSD:
+		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
+			  AR_D_MISC_POST_FR_BKOFF_DIS);
+		break;
+	default:
+		break;
+	}
+
+	if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
+		REG_WRITE(ah, AR_DMISC(q),
+			  REG_READ(ah, AR_DMISC(q)) |
+			  SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
+			     AR_D_MISC_ARB_LOCKOUT_CNTRL) |
+			  AR_D_MISC_POST_FR_BKOFF_DIS);
+	}
+
+	if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
+		ahp->ah_txOkInterruptMask |= 1 << q;
+	else
+		ahp->ah_txOkInterruptMask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
+		ahp->ah_txErrInterruptMask |= 1 << q;
+	else
+		ahp->ah_txErrInterruptMask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
+		ahp->ah_txDescInterruptMask |= 1 << q;
+	else
+		ahp->ah_txDescInterruptMask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
+		ahp->ah_txEolInterruptMask |= 1 << q;
+	else
+		ahp->ah_txEolInterruptMask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
+		ahp->ah_txUrnInterruptMask |= 1 << q;
+	else
+		ahp->ah_txUrnInterruptMask &= ~(1 << q);
+	ath9k_hw_set_txq_interrupts(ah, qi);
+
+	return true;
+}
+
+int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
+			u32 pa, struct ath_desc *nds, u64 tsf)
+{
+	struct ar5416_desc ads;
+	struct ar5416_desc *adsp = AR5416DESC(ds);
+	u32 phyerr;
+
+	if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
+		return -EINPROGRESS;
+
+	ads.u.rx = adsp->u.rx;
+
+	ds->ds_rxstat.rs_status = 0;
+	ds->ds_rxstat.rs_flags = 0;
+
+	ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
+	ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
+
+	ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+	ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
+	ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
+	ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
+	ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
+	ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
+	ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
+	if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
+		ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
+	else
+		ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
+
+	ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
+	ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
+
+	ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
+	ds->ds_rxstat.rs_moreaggr =
+		(ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
+	ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
+	ds->ds_rxstat.rs_flags =
+		(ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
+	ds->ds_rxstat.rs_flags |=
+		(ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
+
+	if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
+		ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
+	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
+		ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
+	if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
+		ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
+
+	if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
+		if (ads.ds_rxstatus8 & AR_CRCErr)
+			ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
+		else if (ads.ds_rxstatus8 & AR_PHYErr) {
+			ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
+			phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
+			ds->ds_rxstat.rs_phyerr = phyerr;
+		} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
+			ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
+		else if (ads.ds_rxstatus8 & AR_MichaelErr)
+			ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
+	}
+
+	return 0;
+}
+
+bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
+			  u32 size, u32 flags)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+	ads->ds_ctl1 = size & AR_BufLen;
+	if (flags & ATH9K_RXDESC_INTREQ)
+		ads->ds_ctl1 |= AR_RxIntrReq;
+
+	ads->ds_rxstatus8 &= ~AR_RxDone;
+	if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+		memset(&(ads->u), 0, sizeof(ads->u));
+
+	return true;
+}
+
+bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
+{
+	u32 reg;
+
+	if (set) {
+		REG_SET_BIT(ah, AR_DIAG_SW,
+			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+		if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) {
+			REG_CLR_BIT(ah, AR_DIAG_SW,
+				    (AR_DIAG_RX_DIS |
+				     AR_DIAG_RX_ABORT));
+
+			reg = REG_READ(ah, AR_OBS_BUS_1);
+			DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+				"rx failed to go idle in 10 ms RXSM=0x%x\n", reg);
+
+			return false;
+		}
+	} else {
+		REG_CLR_BIT(ah, AR_DIAG_SW,
+			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+	}
+
+	return true;
+}
+
+void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp)
+{
+	REG_WRITE(ah, AR_RXDP, rxdp);
+}
+
+void ath9k_hw_rxena(struct ath_hal *ah)
+{
+	REG_WRITE(ah, AR_CR, AR_CR_RXE);
+}
+
+void ath9k_hw_startpcureceive(struct ath_hal *ah)
+{
+	ath9k_enable_mib_counters(ah);
+
+	ath9k_ani_reset(ah);
+
+	REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+}
+
+void ath9k_hw_stoppcurecv(struct ath_hal *ah)
+{
+	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
+
+	ath9k_hw_disable_mib_counters(ah);
+}
+
+bool ath9k_hw_stopdmarecv(struct ath_hal *ah)
+{
+	REG_WRITE(ah, AR_CR, AR_CR_RXD);
+
+	if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+			"dma failed to stop in 10ms\n"
+			"AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
+			REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
+		return false;
+	} else {
+		return true;
+	}
+}
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index f05f584..191eec5 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -14,15 +14,13 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* mac80211 and PCI callbacks */
-
 #include <linux/nl80211.h>
 #include "core.h"
+#include "reg.h"
+#include "hw.h"
 
 #define ATH_PCI_VERSION "0.1"
 
-#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR	13
-
 static char *dev_info = "ath9k";
 
 MODULE_AUTHOR("Atheros Communications");
@@ -36,258 +34,79 @@
 	{ PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI   */
 	{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI   */
 	{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
+	{ PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
 	{ 0 }
 };
 
-static int ath_get_channel(struct ath_softc *sc,
-			   struct ieee80211_channel *chan)
+static void ath_detach(struct ath_softc *sc);
+
+/* return bus cachesize in 4B word units */
+
+static void bus_read_cachesize(struct ath_softc *sc, int *csz)
 {
-	int i;
+	u8 u8tmp;
 
-	for (i = 0; i < sc->sc_ah->ah_nchan; i++) {
-		if (sc->sc_ah->ah_channels[i].channel == chan->center_freq)
-			return i;
-	}
-
-	return -1;
-}
-
-static u32 ath_get_extchanmode(struct ath_softc *sc,
-				     struct ieee80211_channel *chan)
-{
-	u32 chanmode = 0;
-	u8 ext_chan_offset = sc->sc_ht_info.ext_chan_offset;
-	enum ath9k_ht_macmode tx_chan_width = sc->sc_ht_info.tx_chan_width;
-
-	switch (chan->band) {
-	case IEEE80211_BAND_2GHZ:
-		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_20))
-			chanmode = CHANNEL_G_HT20;
-		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
-			chanmode = CHANNEL_G_HT40PLUS;
-		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
-			chanmode = CHANNEL_G_HT40MINUS;
-		break;
-	case IEEE80211_BAND_5GHZ:
-		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_20))
-			chanmode = CHANNEL_A_HT20;
-		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
-			chanmode = CHANNEL_A_HT40PLUS;
-		if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) &&
-		    (tx_chan_width == ATH9K_HT_MACMODE_2040))
-			chanmode = CHANNEL_A_HT40MINUS;
-		break;
-	default:
-		break;
-	}
-
-	return chanmode;
-}
-
-
-static int ath_setkey_tkip(struct ath_softc *sc,
-			   struct ieee80211_key_conf *key,
-			   struct ath9k_keyval *hk,
-			   const u8 *addr)
-{
-	u8 *key_rxmic = NULL;
-	u8 *key_txmic = NULL;
-
-	key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
-	key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
-
-	if (addr == NULL) {
-		/* Group key installation */
-		memcpy(hk->kv_mic,  key_rxmic, sizeof(hk->kv_mic));
-		return ath_keyset(sc, key->keyidx, hk, addr);
-	}
-	if (!sc->sc_splitmic) {
-		/*
-		 * data key goes at first index,
-		 * the hal handles the MIC keys at index+64.
-		 */
-		memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
-		memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
-		return ath_keyset(sc, key->keyidx, hk, addr);
-	}
-	/*
-	 * TX key goes at first index, RX key at +32.
-	 * The hal handles the MIC keys at index+64.
-	 */
-	memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
-	if (!ath_keyset(sc, key->keyidx, hk, NULL)) {
-		/* Txmic entry failed. No need to proceed further */
-		DPRINTF(sc, ATH_DBG_KEYCACHE,
-			"%s Setting TX MIC Key Failed\n", __func__);
-		return 0;
-	}
-
-	memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
-	/* XXX delete tx key on failure? */
-	return ath_keyset(sc, key->keyidx+32, hk, addr);
-}
-
-static int ath_key_config(struct ath_softc *sc,
-			  const u8 *addr,
-			  struct ieee80211_key_conf *key)
-{
-	struct ieee80211_vif *vif;
-	struct ath9k_keyval hk;
-	const u8 *mac = NULL;
-	int ret = 0;
-	enum nl80211_iftype opmode;
-
-	memset(&hk, 0, sizeof(hk));
-
-	switch (key->alg) {
-	case ALG_WEP:
-		hk.kv_type = ATH9K_CIPHER_WEP;
-		break;
-	case ALG_TKIP:
-		hk.kv_type = ATH9K_CIPHER_TKIP;
-		break;
-	case ALG_CCMP:
-		hk.kv_type = ATH9K_CIPHER_AES_CCM;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	hk.kv_len  = key->keylen;
-	memcpy(hk.kv_val, key->key, key->keylen);
-
-	if (!sc->sc_vaps[0])
-		return -EIO;
-
-	vif = sc->sc_vaps[0]->av_if_data;
-	opmode = vif->type;
+	pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp);
+	*csz = (int)u8tmp;
 
 	/*
-	 *  Strategy:
-	 *   For _M_STA mc tx, we will not setup a key at all since we never
-	 *   tx mc.
-	 *   _M_STA mc rx, we will use the keyID.
-	 *   for _M_IBSS mc tx, we will use the keyID, and no macaddr.
-	 *   for _M_IBSS mc rx, we will alloc a slot and plumb the mac of the
-	 *   peer node. BUT we will plumb a cleartext key so that we can do
-	 *   perSta default key table lookup in software.
+	 * This check was put in to avoid "unplesant" consequences if
+	 * the bootrom has not fully initialized all PCI devices.
+	 * Sometimes the cache line size register is not set
 	 */
-	if (is_broadcast_ether_addr(addr)) {
-		switch (opmode) {
-		case NL80211_IFTYPE_STATION:
-			/* default key:  could be group WPA key
-			 * or could be static WEP key */
-			mac = NULL;
-			break;
-		case NL80211_IFTYPE_ADHOC:
-			break;
-		case NL80211_IFTYPE_AP:
-			break;
-		default:
-			ASSERT(0);
-			break;
-		}
-	} else {
-		mac = addr;
-	}
 
-	if (key->alg == ALG_TKIP)
-		ret = ath_setkey_tkip(sc, key, &hk, mac);
-	else
-		ret = ath_keyset(sc, key->keyidx, &hk, mac);
-
-	if (!ret)
-		return -EIO;
-
-	return 0;
+	if (*csz == 0)
+		*csz = DEFAULT_CACHELINE >> 2;   /* Use the default size */
 }
 
-static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
+static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
 {
-	int freeslot;
-
-	freeslot = (key->keyidx >= 4) ? 1 : 0;
-	ath_key_reset(sc, key->keyidx, freeslot);
-}
-
-static void setup_ht_cap(struct ieee80211_ht_info *ht_info)
-{
-#define	ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3	/* 2 ^ 16 */
-#define	ATH9K_HT_CAP_MPDUDENSITY_8 0x6		/* 8 usec */
-
-	ht_info->ht_supported = 1;
-	ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH
-			|(u16)IEEE80211_HT_CAP_SM_PS
-			|(u16)IEEE80211_HT_CAP_SGI_40
-			|(u16)IEEE80211_HT_CAP_DSSSCCK40;
-
-	ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536;
-	ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8;
-	/* setup supported mcs set */
-	memset(ht_info->supp_mcs_set, 0, 16);
-	ht_info->supp_mcs_set[0] = 0xff;
-	ht_info->supp_mcs_set[1] = 0xff;
-	ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED;
-}
-
-static int ath_rate2idx(struct ath_softc *sc, int rate)
-{
-	int i = 0, cur_band, n_rates;
-	struct ieee80211_hw *hw = sc->hw;
-
-	cur_band = hw->conf.channel->band;
-	n_rates = sc->sbands[cur_band].n_bitrates;
-
-	for (i = 0; i < n_rates; i++) {
-		if (sc->sbands[cur_band].bitrates[i].bitrate == rate)
-			break;
-	}
-
+	sc->cur_rate_table = sc->hw_rate_table[mode];
 	/*
-	 * NB:mac80211 validates rx rate index against the supported legacy rate
-	 * index only (should be done against ht rates also), return the highest
-	 * legacy rate index for rx rate which does not match any one of the
-	 * supported basic and extended rates to make mac80211 happy.
-	 * The following hack will be cleaned up once the issue with
-	 * the rx rate index validation in mac80211 is fixed.
+	 * All protection frames are transmited at 2Mb/s for
+	 * 11g, otherwise at 1Mb/s.
+	 * XXX select protection rate index from rate table.
 	 */
-	if (i == n_rates)
-		return n_rates - 1;
-	return i;
+	sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0);
 }
 
-static void ath9k_rx_prepare(struct ath_softc *sc,
-			     struct sk_buff *skb,
-			     struct ath_recv_status *status,
-			     struct ieee80211_rx_status *rx_status)
+static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
 {
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_channel *curchan = hw->conf.channel;
+	if (chan->chanmode == CHANNEL_A)
+		return ATH9K_MODE_11A;
+	else if (chan->chanmode == CHANNEL_G)
+		return ATH9K_MODE_11G;
+	else if (chan->chanmode == CHANNEL_B)
+		return ATH9K_MODE_11B;
+	else if (chan->chanmode == CHANNEL_A_HT20)
+		return ATH9K_MODE_11NA_HT20;
+	else if (chan->chanmode == CHANNEL_G_HT20)
+		return ATH9K_MODE_11NG_HT20;
+	else if (chan->chanmode == CHANNEL_A_HT40PLUS)
+		return ATH9K_MODE_11NA_HT40PLUS;
+	else if (chan->chanmode == CHANNEL_A_HT40MINUS)
+		return ATH9K_MODE_11NA_HT40MINUS;
+	else if (chan->chanmode == CHANNEL_G_HT40PLUS)
+		return ATH9K_MODE_11NG_HT40PLUS;
+	else if (chan->chanmode == CHANNEL_G_HT40MINUS)
+		return ATH9K_MODE_11NG_HT40MINUS;
 
-	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+	WARN_ON(1); /* should not get here */
 
-	rx_status->mactime = status->tsf;
-	rx_status->band = curchan->band;
-	rx_status->freq =  curchan->center_freq;
-	rx_status->noise = sc->sc_ani.sc_noise_floor;
-	rx_status->signal = rx_status->noise + status->rssi;
-	rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100));
-	rx_status->antenna = status->antenna;
+	return ATH9K_MODE_11B;
+}
 
-	/* XXX Fix me, 64 cannot be the max rssi value, rigure it out */
-	rx_status->qual = status->rssi * 100 / 64;
+static void ath_update_txpow(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+	u32 txpow;
 
-	if (status->flags & ATH_RX_MIC_ERROR)
-		rx_status->flag |= RX_FLAG_MMIC_ERROR;
-	if (status->flags & ATH_RX_FCS_ERROR)
-		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
-
-	rx_status->flag |= RX_FLAG_TSFT;
+	if (sc->sc_curtxpow != sc->sc_config.txpowlimit) {
+		ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit);
+		/* read back in case value is clamped */
+		ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
+		sc->sc_curtxpow = txpow;
+	}
 }
 
 static u8 parse_mpdudensity(u8 mpdudensity)
@@ -325,59 +144,780 @@
 	}
 }
 
-static void ath9k_ht_conf(struct ath_softc *sc,
-			  struct ieee80211_bss_conf *bss_conf)
+static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
 {
-#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14)
-	struct ath_ht_info *ht_info = &sc->sc_ht_info;
+	struct ath_rate_table *rate_table = NULL;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_rate *rate;
+	int i, maxrates;
 
-	if (bss_conf->assoc_ht) {
-		ht_info->ext_chan_offset =
-			bss_conf->ht_bss_conf->bss_cap &
-				IEEE80211_HT_IE_CHA_SEC_OFFSET;
-
-		if (!(bss_conf->ht_conf->cap &
-			IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
-			    (bss_conf->ht_bss_conf->bss_cap &
-				IEEE80211_HT_IE_CHA_WIDTH))
-			ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040;
-		else
-			ht_info->tx_chan_width = ATH9K_HT_MACMODE_20;
-
-		ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width);
-		ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
-					bss_conf->ht_conf->ampdu_factor);
-		ht_info->mpdudensity =
-			parse_mpdudensity(bss_conf->ht_conf->ampdu_density);
-
+	switch (band) {
+	case IEEE80211_BAND_2GHZ:
+		rate_table = sc->hw_rate_table[ATH9K_MODE_11G];
+		break;
+	case IEEE80211_BAND_5GHZ:
+		rate_table = sc->hw_rate_table[ATH9K_MODE_11A];
+		break;
+	default:
+		break;
 	}
 
-#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT
+	if (rate_table == NULL)
+		return;
+
+	sband = &sc->sbands[band];
+	rate = sc->rates[band];
+
+	if (rate_table->rate_cnt > ATH_RATE_MAX)
+		maxrates = ATH_RATE_MAX;
+	else
+		maxrates = rate_table->rate_cnt;
+
+	for (i = 0; i < maxrates; i++) {
+		rate[i].bitrate = rate_table->info[i].ratekbps / 100;
+		rate[i].hw_value = rate_table->info[i].ratecode;
+		sband->n_bitrates++;
+		DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n",
+			rate[i].bitrate / 10, rate[i].hw_value);
+	}
+}
+
+static int ath_setup_channels(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+	int nchan, i, a = 0, b = 0;
+	u8 regclassids[ATH_REGCLASSIDS_MAX];
+	u32 nregclass = 0;
+	struct ieee80211_supported_band *band_2ghz;
+	struct ieee80211_supported_band *band_5ghz;
+	struct ieee80211_channel *chan_2ghz;
+	struct ieee80211_channel *chan_5ghz;
+	struct ath9k_channel *c;
+
+	/* Fill in ah->ah_channels */
+	if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan,
+				      regclassids, ATH_REGCLASSIDS_MAX,
+				      &nregclass, CTRY_DEFAULT, false, 1)) {
+		u32 rd = ah->ah_currentRD;
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Unable to collect channel list; "
+			"regdomain likely %u country code %u\n",
+			rd, CTRY_DEFAULT);
+		return -EINVAL;
+	}
+
+	band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ];
+	band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ];
+	chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ];
+	chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ];
+
+	for (i = 0; i < nchan; i++) {
+		c = &ah->ah_channels[i];
+		if (IS_CHAN_2GHZ(c)) {
+			chan_2ghz[a].band = IEEE80211_BAND_2GHZ;
+			chan_2ghz[a].center_freq = c->channel;
+			chan_2ghz[a].max_power = c->maxTxPower;
+
+			if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
+				chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS;
+			if (c->channelFlags & CHANNEL_PASSIVE)
+				chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+			band_2ghz->n_channels = ++a;
+
+			DPRINTF(sc, ATH_DBG_CONFIG, "2MHz channel: %d, "
+				"channelFlags: 0x%x\n",
+				c->channel, c->channelFlags);
+		} else if (IS_CHAN_5GHZ(c)) {
+			chan_5ghz[b].band = IEEE80211_BAND_5GHZ;
+			chan_5ghz[b].center_freq = c->channel;
+			chan_5ghz[b].max_power = c->maxTxPower;
+
+			if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
+				chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS;
+			if (c->channelFlags & CHANNEL_PASSIVE)
+				chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+			band_5ghz->n_channels = ++b;
+
+			DPRINTF(sc, ATH_DBG_CONFIG, "5MHz channel: %d, "
+				"channelFlags: 0x%x\n",
+				c->channel, c->channelFlags);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Set/change channels.  If the channel is really being changed, it's done
+ * by reseting the chip.  To accomplish this we must first cleanup any pending
+ * DMA, then restart stuff.
+*/
+static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
+{
+	struct ath_hal *ah = sc->sc_ah;
+	bool fastcc = true, stopped;
+
+	if (sc->sc_flags & SC_OP_INVALID)
+		return -EIO;
+
+	if (hchan->channel != sc->sc_ah->ah_curchan->channel ||
+	    hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags ||
+	    (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) ||
+	    (sc->sc_flags & SC_OP_FULL_RESET)) {
+		int status;
+		/*
+		 * This is only performed if the channel settings have
+		 * actually changed.
+		 *
+		 * To switch channels clear any pending DMA operations;
+		 * wait long enough for the RX fifo to drain, reset the
+		 * hardware at the new frequency, and then re-enable
+		 * the relevant bits of the h/w.
+		 */
+		ath9k_hw_set_interrupts(ah, 0);
+		ath_draintxq(sc, false);
+		stopped = ath_stoprecv(sc);
+
+		/* XXX: do not flush receive queue here. We don't want
+		 * to flush data frames already in queue because of
+		 * changing channel. */
+
+		if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
+			fastcc = false;
+
+		DPRINTF(sc, ATH_DBG_CONFIG,
+			"(%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n",
+			sc->sc_ah->ah_curchan->channel,
+			hchan->channel, hchan->channelFlags, sc->tx_chan_width);
+
+		spin_lock_bh(&sc->sc_resetlock);
+		if (!ath9k_hw_reset(ah, hchan, sc->tx_chan_width,
+				    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+				    sc->sc_ht_extprotspacing, fastcc, &status)) {
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"Unable to reset channel %u (%uMhz) "
+				"flags 0x%x hal status %u\n",
+				ath9k_hw_mhz2ieee(ah, hchan->channel,
+						  hchan->channelFlags),
+				hchan->channel, hchan->channelFlags, status);
+			spin_unlock_bh(&sc->sc_resetlock);
+			return -EIO;
+		}
+		spin_unlock_bh(&sc->sc_resetlock);
+
+		sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
+		sc->sc_flags &= ~SC_OP_FULL_RESET;
+
+		if (ath_startrecv(sc) != 0) {
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"Unable to restart recv logic\n");
+			return -EIO;
+		}
+
+		ath_setcurmode(sc, ath_chan2mode(hchan));
+		ath_update_txpow(sc);
+		ath9k_hw_set_interrupts(ah, sc->sc_imask);
+	}
+	return 0;
+}
+
+/*
+ *  This routine performs the periodic noise floor calibration function
+ *  that is used to adjust and optimize the chip performance.  This
+ *  takes environmental changes (location, temperature) into account.
+ *  When the task is complete, it reschedules itself depending on the
+ *  appropriate interval that was calculated.
+ */
+static void ath_ani_calibrate(unsigned long data)
+{
+	struct ath_softc *sc;
+	struct ath_hal *ah;
+	bool longcal = false;
+	bool shortcal = false;
+	bool aniflag = false;
+	unsigned int timestamp = jiffies_to_msecs(jiffies);
+	u32 cal_interval;
+
+	sc = (struct ath_softc *)data;
+	ah = sc->sc_ah;
+
+	/*
+	* don't calibrate when we're scanning.
+	* we are most likely not on our home channel.
+	*/
+	if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC)
+		return;
+
+	/* Long calibration runs independently of short calibration. */
+	if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) {
+		longcal = true;
+		DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
+		sc->sc_ani.sc_longcal_timer = timestamp;
+	}
+
+	/* Short calibration applies only while sc_caldone is false */
+	if (!sc->sc_ani.sc_caldone) {
+		if ((timestamp - sc->sc_ani.sc_shortcal_timer) >=
+		    ATH_SHORT_CALINTERVAL) {
+			shortcal = true;
+			DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies);
+			sc->sc_ani.sc_shortcal_timer = timestamp;
+			sc->sc_ani.sc_resetcal_timer = timestamp;
+		}
+	} else {
+		if ((timestamp - sc->sc_ani.sc_resetcal_timer) >=
+		    ATH_RESTART_CALINTERVAL) {
+			ath9k_hw_reset_calvalid(ah, ah->ah_curchan,
+						&sc->sc_ani.sc_caldone);
+			if (sc->sc_ani.sc_caldone)
+				sc->sc_ani.sc_resetcal_timer = timestamp;
+		}
+	}
+
+	/* Verify whether we must check ANI */
+	if ((timestamp - sc->sc_ani.sc_checkani_timer) >=
+	   ATH_ANI_POLLINTERVAL) {
+		aniflag = true;
+		sc->sc_ani.sc_checkani_timer = timestamp;
+	}
+
+	/* Skip all processing if there's nothing to do. */
+	if (longcal || shortcal || aniflag) {
+		/* Call ANI routine if necessary */
+		if (aniflag)
+			ath9k_hw_ani_monitor(ah, &sc->sc_halstats,
+					     ah->ah_curchan);
+
+		/* Perform calibration if necessary */
+		if (longcal || shortcal) {
+			bool iscaldone = false;
+
+			if (ath9k_hw_calibrate(ah, ah->ah_curchan,
+					       sc->sc_rx_chainmask, longcal,
+					       &iscaldone)) {
+				if (longcal)
+					sc->sc_ani.sc_noise_floor =
+						ath9k_hw_getchan_noise(ah,
+							       ah->ah_curchan);
+
+				DPRINTF(sc, ATH_DBG_ANI,
+					"calibrate chan %u/%x nf: %d\n",
+					ah->ah_curchan->channel,
+					ah->ah_curchan->channelFlags,
+					sc->sc_ani.sc_noise_floor);
+			} else {
+				DPRINTF(sc, ATH_DBG_ANY,
+					"calibrate chan %u/%x failed\n",
+					ah->ah_curchan->channel,
+					ah->ah_curchan->channelFlags);
+			}
+			sc->sc_ani.sc_caldone = iscaldone;
+		}
+	}
+
+	/*
+	* Set timer interval based on previous results.
+	* The interval must be the shortest necessary to satisfy ANI,
+	* short calibration and long calibration.
+	*/
+	cal_interval = ATH_LONG_CALINTERVAL;
+	if (sc->sc_ah->ah_config.enable_ani)
+		cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
+	if (!sc->sc_ani.sc_caldone)
+		cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL);
+
+	mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval));
+}
+
+/*
+ * Update tx/rx chainmask. For legacy association,
+ * hard code chainmask to 1x1, for 11n association, use
+ * the chainmask configuration.
+ */
+static void ath_update_chainmask(struct ath_softc *sc, int is_ht)
+{
+	sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
+	if (is_ht) {
+		sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask;
+		sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask;
+	} else {
+		sc->sc_tx_chainmask = 1;
+		sc->sc_rx_chainmask = 1;
+	}
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n",
+		sc->sc_tx_chainmask, sc->sc_rx_chainmask);
+}
+
+static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
+{
+	struct ath_node *an;
+
+	an = (struct ath_node *)sta->drv_priv;
+
+	if (sc->sc_flags & SC_OP_TXAGGR)
+		ath_tx_node_init(sc, an);
+
+	an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
+			     sta->ht_cap.ampdu_factor);
+	an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+}
+
+static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
+{
+	struct ath_node *an = (struct ath_node *)sta->drv_priv;
+
+	if (sc->sc_flags & SC_OP_TXAGGR)
+		ath_tx_node_cleanup(sc, an);
+}
+
+static void ath9k_tasklet(unsigned long data)
+{
+	struct ath_softc *sc = (struct ath_softc *)data;
+	u32 status = sc->sc_intrstatus;
+
+	if (status & ATH9K_INT_FATAL) {
+		/* need a chip reset */
+		ath_reset(sc, false);
+		return;
+	} else {
+
+		if (status &
+		    (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
+			spin_lock_bh(&sc->rx.rxflushlock);
+			ath_rx_tasklet(sc, 0);
+			spin_unlock_bh(&sc->rx.rxflushlock);
+		}
+		/* XXX: optimize this */
+		if (status & ATH9K_INT_TX)
+			ath_tx_tasklet(sc);
+	}
+
+	/* re-enable hardware interrupt */
+	ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
+}
+
+static irqreturn_t ath_isr(int irq, void *dev)
+{
+	struct ath_softc *sc = dev;
+	struct ath_hal *ah = sc->sc_ah;
+	enum ath9k_int status;
+	bool sched = false;
+
+	do {
+		if (sc->sc_flags & SC_OP_INVALID) {
+			/*
+			 * The hardware is not ready/present, don't
+			 * touch anything. Note this can happen early
+			 * on if the IRQ is shared.
+			 */
+			return IRQ_NONE;
+		}
+		if (!ath9k_hw_intrpend(ah)) {	/* shared irq, not for us */
+			return IRQ_NONE;
+		}
+
+		/*
+		 * Figure out the reason(s) for the interrupt.  Note
+		 * that the hal returns a pseudo-ISR that may include
+		 * bits we haven't explicitly enabled so we mask the
+		 * value to insure we only process bits we requested.
+		 */
+		ath9k_hw_getisr(ah, &status);	/* NB: clears ISR too */
+
+		status &= sc->sc_imask;	/* discard unasked-for bits */
+
+		/*
+		 * If there are no status bits set, then this interrupt was not
+		 * for me (should have been caught above).
+		 */
+		if (!status)
+			return IRQ_NONE;
+
+		sc->sc_intrstatus = status;
+
+		if (status & ATH9K_INT_FATAL) {
+			/* need a chip reset */
+			sched = true;
+		} else if (status & ATH9K_INT_RXORN) {
+			/* need a chip reset */
+			sched = true;
+		} else {
+			if (status & ATH9K_INT_SWBA) {
+				/* schedule a tasklet for beacon handling */
+				tasklet_schedule(&sc->bcon_tasklet);
+			}
+			if (status & ATH9K_INT_RXEOL) {
+				/*
+				 * NB: the hardware should re-read the link when
+				 *     RXE bit is written, but it doesn't work
+				 *     at least on older hardware revs.
+				 */
+				sched = true;
+			}
+
+			if (status & ATH9K_INT_TXURN)
+				/* bump tx trigger level */
+				ath9k_hw_updatetxtriglevel(ah, true);
+			/* XXX: optimize this */
+			if (status & ATH9K_INT_RX)
+				sched = true;
+			if (status & ATH9K_INT_TX)
+				sched = true;
+			if (status & ATH9K_INT_BMISS)
+				sched = true;
+			/* carrier sense timeout */
+			if (status & ATH9K_INT_CST)
+				sched = true;
+			if (status & ATH9K_INT_MIB) {
+				/*
+				 * Disable interrupts until we service the MIB
+				 * interrupt; otherwise it will continue to
+				 * fire.
+				 */
+				ath9k_hw_set_interrupts(ah, 0);
+				/*
+				 * Let the hal handle the event. We assume
+				 * it will clear whatever condition caused
+				 * the interrupt.
+				 */
+				ath9k_hw_procmibevent(ah, &sc->sc_halstats);
+				ath9k_hw_set_interrupts(ah, sc->sc_imask);
+			}
+			if (status & ATH9K_INT_TIM_TIMER) {
+				if (!(ah->ah_caps.hw_caps &
+				      ATH9K_HW_CAP_AUTOSLEEP)) {
+					/* Clear RxAbort bit so that we can
+					 * receive frames */
+					ath9k_hw_setrxabort(ah, 0);
+					sched = true;
+				}
+			}
+		}
+	} while (0);
+
+	ath_debug_stat_interrupt(sc, status);
+
+	if (sched) {
+		/* turn off every interrupt except SWBA */
+		ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA));
+		tasklet_schedule(&sc->intr_tq);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int ath_get_channel(struct ath_softc *sc,
+			   struct ieee80211_channel *chan)
+{
+	int i;
+
+	for (i = 0; i < sc->sc_ah->ah_nchan; i++) {
+		if (sc->sc_ah->ah_channels[i].channel == chan->center_freq)
+			return i;
+	}
+
+	return -1;
+}
+
+static u32 ath_get_extchanmode(struct ath_softc *sc,
+			       struct ieee80211_channel *chan,
+			       enum nl80211_channel_type channel_type)
+{
+	u32 chanmode = 0;
+
+	switch (chan->band) {
+	case IEEE80211_BAND_2GHZ:
+		switch(channel_type) {
+		case NL80211_CHAN_NO_HT:
+		case NL80211_CHAN_HT20:
+			chanmode = CHANNEL_G_HT20;
+			break;
+		case NL80211_CHAN_HT40PLUS:
+			chanmode = CHANNEL_G_HT40PLUS;
+			break;
+		case NL80211_CHAN_HT40MINUS:
+			chanmode = CHANNEL_G_HT40MINUS;
+			break;
+		}
+		break;
+	case IEEE80211_BAND_5GHZ:
+		switch(channel_type) {
+		case NL80211_CHAN_NO_HT:
+		case NL80211_CHAN_HT20:
+			chanmode = CHANNEL_A_HT20;
+			break;
+		case NL80211_CHAN_HT40PLUS:
+			chanmode = CHANNEL_A_HT40PLUS;
+			break;
+		case NL80211_CHAN_HT40MINUS:
+			chanmode = CHANNEL_A_HT40MINUS;
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return chanmode;
+}
+
+static int ath_keyset(struct ath_softc *sc, u16 keyix,
+	       struct ath9k_keyval *hk, const u8 mac[ETH_ALEN])
+{
+	bool status;
+
+	status = ath9k_hw_set_keycache_entry(sc->sc_ah,
+		keyix, hk, mac, false);
+
+	return status != false;
+}
+
+static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
+			   struct ath9k_keyval *hk,
+			   const u8 *addr)
+{
+	const u8 *key_rxmic;
+	const u8 *key_txmic;
+
+	key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
+	key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
+
+	if (addr == NULL) {
+		/* Group key installation */
+		memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+		return ath_keyset(sc, keyix, hk, addr);
+	}
+	if (!sc->sc_splitmic) {
+		/*
+		 * data key goes at first index,
+		 * the hal handles the MIC keys at index+64.
+		 */
+		memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+		memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
+		return ath_keyset(sc, keyix, hk, addr);
+	}
+	/*
+	 * TX key goes at first index, RX key at +32.
+	 * The hal handles the MIC keys at index+64.
+	 */
+	memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
+	if (!ath_keyset(sc, keyix, hk, NULL)) {
+		/* Txmic entry failed. No need to proceed further */
+		DPRINTF(sc, ATH_DBG_KEYCACHE,
+			"Setting TX MIC Key Failed\n");
+		return 0;
+	}
+
+	memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+	/* XXX delete tx key on failure? */
+	return ath_keyset(sc, keyix + 32, hk, addr);
+}
+
+static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc)
+{
+	int i;
+
+	for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
+		if (test_bit(i, sc->sc_keymap) ||
+		    test_bit(i + 64, sc->sc_keymap))
+			continue; /* At least one part of TKIP key allocated */
+		if (sc->sc_splitmic &&
+		    (test_bit(i + 32, sc->sc_keymap) ||
+		     test_bit(i + 64 + 32, sc->sc_keymap)))
+			continue; /* At least one part of TKIP key allocated */
+
+		/* Found a free slot for a TKIP key */
+		return i;
+	}
+	return -1;
+}
+
+static int ath_reserve_key_cache_slot(struct ath_softc *sc)
+{
+	int i;
+
+	/* First, try to find slots that would not be available for TKIP. */
+	if (sc->sc_splitmic) {
+		for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 4; i++) {
+			if (!test_bit(i, sc->sc_keymap) &&
+			    (test_bit(i + 32, sc->sc_keymap) ||
+			     test_bit(i + 64, sc->sc_keymap) ||
+			     test_bit(i + 64 + 32, sc->sc_keymap)))
+				return i;
+			if (!test_bit(i + 32, sc->sc_keymap) &&
+			    (test_bit(i, sc->sc_keymap) ||
+			     test_bit(i + 64, sc->sc_keymap) ||
+			     test_bit(i + 64 + 32, sc->sc_keymap)))
+				return i + 32;
+			if (!test_bit(i + 64, sc->sc_keymap) &&
+			    (test_bit(i , sc->sc_keymap) ||
+			     test_bit(i + 32, sc->sc_keymap) ||
+			     test_bit(i + 64 + 32, sc->sc_keymap)))
+				return i + 64;
+			if (!test_bit(i + 64 + 32, sc->sc_keymap) &&
+			    (test_bit(i, sc->sc_keymap) ||
+			     test_bit(i + 32, sc->sc_keymap) ||
+			     test_bit(i + 64, sc->sc_keymap)))
+				return i + 64 + 32;
+		}
+	} else {
+		for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
+			if (!test_bit(i, sc->sc_keymap) &&
+			    test_bit(i + 64, sc->sc_keymap))
+				return i;
+			if (test_bit(i, sc->sc_keymap) &&
+			    !test_bit(i + 64, sc->sc_keymap))
+				return i + 64;
+		}
+	}
+
+	/* No partially used TKIP slots, pick any available slot */
+	for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) {
+		/* Do not allow slots that could be needed for TKIP group keys
+		 * to be used. This limitation could be removed if we know that
+		 * TKIP will not be used. */
+		if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
+			continue;
+		if (sc->sc_splitmic) {
+			if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
+				continue;
+			if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
+				continue;
+		}
+
+		if (!test_bit(i, sc->sc_keymap))
+			return i; /* Found a free slot for a key */
+	}
+
+	/* No free slot found */
+	return -1;
+}
+
+static int ath_key_config(struct ath_softc *sc,
+			  const u8 *addr,
+			  struct ieee80211_key_conf *key)
+{
+	struct ath9k_keyval hk;
+	const u8 *mac = NULL;
+	int ret = 0;
+	int idx;
+
+	memset(&hk, 0, sizeof(hk));
+
+	switch (key->alg) {
+	case ALG_WEP:
+		hk.kv_type = ATH9K_CIPHER_WEP;
+		break;
+	case ALG_TKIP:
+		hk.kv_type = ATH9K_CIPHER_TKIP;
+		break;
+	case ALG_CCMP:
+		hk.kv_type = ATH9K_CIPHER_AES_CCM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	hk.kv_len = key->keylen;
+	memcpy(hk.kv_val, key->key, key->keylen);
+
+	if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+		/* For now, use the default keys for broadcast keys. This may
+		 * need to change with virtual interfaces. */
+		idx = key->keyidx;
+	} else if (key->keyidx) {
+		struct ieee80211_vif *vif;
+
+		mac = addr;
+		vif = sc->sc_vaps[0];
+		if (vif->type != NL80211_IFTYPE_AP) {
+			/* Only keyidx 0 should be used with unicast key, but
+			 * allow this for client mode for now. */
+			idx = key->keyidx;
+		} else
+			return -EIO;
+	} else {
+		mac = addr;
+		if (key->alg == ALG_TKIP)
+			idx = ath_reserve_key_cache_slot_tkip(sc);
+		else
+			idx = ath_reserve_key_cache_slot(sc);
+		if (idx < 0)
+			return -EIO; /* no free key cache entries */
+	}
+
+	if (key->alg == ALG_TKIP)
+		ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac);
+	else
+		ret = ath_keyset(sc, idx, &hk, mac);
+
+	if (!ret)
+		return -EIO;
+
+	set_bit(idx, sc->sc_keymap);
+	if (key->alg == ALG_TKIP) {
+		set_bit(idx + 64, sc->sc_keymap);
+		if (sc->sc_splitmic) {
+			set_bit(idx + 32, sc->sc_keymap);
+			set_bit(idx + 64 + 32, sc->sc_keymap);
+		}
+	}
+
+	return idx;
+}
+
+static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
+{
+	ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx);
+	if (key->hw_key_idx < IEEE80211_WEP_NKID)
+		return;
+
+	clear_bit(key->hw_key_idx, sc->sc_keymap);
+	if (key->alg != ALG_TKIP)
+		return;
+
+	clear_bit(key->hw_key_idx + 64, sc->sc_keymap);
+	if (sc->sc_splitmic) {
+		clear_bit(key->hw_key_idx + 32, sc->sc_keymap);
+		clear_bit(key->hw_key_idx + 64 + 32, sc->sc_keymap);
+	}
+}
+
+static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info)
+{
+#define	ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3	/* 2 ^ 16 */
+#define	ATH9K_HT_CAP_MPDUDENSITY_8 0x6		/* 8 usec */
+
+	ht_info->ht_supported = true;
+	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+		       IEEE80211_HT_CAP_SM_PS |
+		       IEEE80211_HT_CAP_SGI_40 |
+		       IEEE80211_HT_CAP_DSSSCCK40;
+
+	ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536;
+	ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8;
+	/* set up supported mcs set */
+	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+	ht_info->mcs.rx_mask[0] = 0xff;
+	ht_info->mcs.rx_mask[1] = 0xff;
+	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
 }
 
 static void ath9k_bss_assoc_info(struct ath_softc *sc,
+				 struct ieee80211_vif *vif,
 				 struct ieee80211_bss_conf *bss_conf)
 {
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_channel *curchan = hw->conf.channel;
-	struct ath_vap *avp;
-	int pos;
-	DECLARE_MAC_BUF(mac);
+	struct ath_vap *avp = (void *)vif->drv_priv;
 
 	if (bss_conf->assoc) {
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n",
-			__func__,
-			bss_conf->aid);
-
-		avp = sc->sc_vaps[0];
-		if (avp == NULL) {
-			DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-				__func__);
-			return;
-		}
+		DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
+			bss_conf->aid, sc->sc_curbssid);
 
 		/* New association, store aid */
-		if (avp->av_opmode == ATH9K_M_STA) {
+		if (avp->av_opmode == NL80211_IFTYPE_STATION) {
 			sc->sc_curaid = bss_conf->aid;
 			ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
 					       sc->sc_curaid);
@@ -393,175 +933,16 @@
 		sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
 		sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
 
-		/* Update chainmask */
-		ath_update_chainmask(sc, bss_conf->assoc_ht);
-
-		DPRINTF(sc, ATH_DBG_CONFIG,
-			"%s: bssid %s aid 0x%x\n",
-			__func__,
-			print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
-
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
-			__func__,
-			curchan->center_freq);
-
-		pos = ath_get_channel(sc, curchan);
-		if (pos == -1) {
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Invalid channel\n", __func__);
-			return;
-		}
-
-		if (hw->conf.ht_conf.ht_supported)
-			sc->sc_ah->ah_channels[pos].chanmode =
-				ath_get_extchanmode(sc, curchan);
-		else
-			sc->sc_ah->ah_channels[pos].chanmode =
-				(curchan->band == IEEE80211_BAND_2GHZ) ?
-				CHANNEL_G : CHANNEL_A;
-
-		/* set h/w channel */
-		if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to set channel\n",
-				__func__);
-
-		ath_rate_newstate(sc, avp);
-		/* Update ratectrl about the new state */
-		ath_rc_node_update(hw, avp->rc_node);
-
 		/* Start ANI */
 		mod_timer(&sc->sc_ani.timer,
 			jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
 
 	} else {
-		DPRINTF(sc, ATH_DBG_CONFIG,
-		"%s: Bss Info DISSOC\n", __func__);
+		DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n");
 		sc->sc_curaid = 0;
 	}
 }
 
-void ath_get_beaconconfig(struct ath_softc *sc,
-			  int if_id,
-			  struct ath_beacon_config *conf)
-{
-	struct ieee80211_hw *hw = sc->hw;
-
-	/* fill in beacon config data */
-
-	conf->beacon_interval = hw->conf.beacon_int;
-	conf->listen_interval = 100;
-	conf->dtim_count = 1;
-	conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
-}
-
-void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
-		     struct ath_xmit_status *tx_status, struct ath_node *an)
-{
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-
-	DPRINTF(sc, ATH_DBG_XMIT,
-		"%s: TX complete: skb: %p\n", __func__, skb);
-
-	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
-		tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
-		/* free driver's private data area of tx_info */
-		if (tx_info->driver_data[0] != NULL)
-			kfree(tx_info->driver_data[0]);
-			tx_info->driver_data[0] = NULL;
-	}
-
-	if (tx_status->flags & ATH_TX_BAR) {
-		tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
-		tx_status->flags &= ~ATH_TX_BAR;
-	}
-
-	if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
-		if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-			/* Frame was not ACKed, but an ACK was expected */
-			tx_info->status.excessive_retries = 1;
-		}
-	} else {
-		/* Frame was ACKed */
-		tx_info->flags |= IEEE80211_TX_STAT_ACK;
-	}
-
-	tx_info->status.retry_count = tx_status->retries;
-
-	ieee80211_tx_status(hw, skb);
-	if (an)
-		ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE);
-}
-
-int _ath_rx_indicate(struct ath_softc *sc,
-		     struct sk_buff *skb,
-		     struct ath_recv_status *status,
-		     u16 keyix)
-{
-	struct ieee80211_hw *hw = sc->hw;
-	struct ath_node *an = NULL;
-	struct ieee80211_rx_status rx_status;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-	int padsize;
-	enum ATH_RX_TYPE st;
-
-	/* see if any padding is done by the hw and remove it */
-	if (hdrlen & 3) {
-		padsize = hdrlen % 4;
-		memmove(skb->data + padsize, skb->data, hdrlen);
-		skb_pull(skb, padsize);
-	}
-
-	/* Prepare rx status */
-	ath9k_rx_prepare(sc, skb, status, &rx_status);
-
-	if (!(keyix == ATH9K_RXKEYIX_INVALID) &&
-	    !(status->flags & ATH_RX_DECRYPT_ERROR)) {
-		rx_status.flag |= RX_FLAG_DECRYPTED;
-	} else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
-		   && !(status->flags & ATH_RX_DECRYPT_ERROR)
-		   && skb->len >= hdrlen + 4) {
-		keyix = skb->data[hdrlen + 3] >> 6;
-
-		if (test_bit(keyix, sc->sc_keymap))
-			rx_status.flag |= RX_FLAG_DECRYPTED;
-	}
-
-	spin_lock_bh(&sc->node_lock);
-	an = ath_node_find(sc, hdr->addr2);
-	spin_unlock_bh(&sc->node_lock);
-
-	if (an) {
-		ath_rx_input(sc, an,
-			     hw->conf.ht_conf.ht_supported,
-			     skb, status, &st);
-	}
-	if (!an || (st != ATH_RX_CONSUMED))
-		__ieee80211_rx(hw, skb, &rx_status);
-
-	return 0;
-}
-
-int ath_rx_subframe(struct ath_node *an,
-		    struct sk_buff *skb,
-		    struct ath_recv_status *status)
-{
-	struct ath_softc *sc = an->an_sc;
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_rx_status rx_status;
-
-	/* Prepare rx status */
-	ath9k_rx_prepare(sc, skb, status, &rx_status);
-	if (!(status->flags & ATH_RX_DECRYPT_ERROR))
-		rx_status.flag |= RX_FLAG_DECRYPTED;
-
-	__ieee80211_rx(hw, skb, &rx_status);
-
-	return 0;
-}
-
 /********************************/
 /*	 LED functions		*/
 /********************************/
@@ -677,7 +1058,8 @@
 	ath_deinit_leds(sc);
 }
 
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+
 /*******************/
 /*	Rfkill	   */
 /*******************/
@@ -689,14 +1071,14 @@
 
 	spin_lock_bh(&sc->sc_resetlock);
 	if (!ath9k_hw_reset(ah, ah->ah_curchan,
-			    sc->sc_ht_info.tx_chan_width,
+			    sc->tx_chan_width,
 			    sc->sc_tx_chainmask,
 			    sc->sc_rx_chainmask,
 			    sc->sc_ht_extprotspacing,
 			    false, &status)) {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to reset channel %u (%uMhz) "
-			"flags 0x%x hal status %u\n", __func__,
+			"Unable to reset channel %u (%uMhz) "
+			"flags 0x%x hal status %u\n",
 			ath9k_hw_mhz2ieee(ah,
 					  ah->ah_curchan->channel,
 					  ah->ah_curchan->channelFlags),
@@ -708,7 +1090,7 @@
 	ath_update_txpow(sc);
 	if (ath_startrecv(sc) != 0) {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to restart recv logic\n", __func__);
+			"Unable to restart recv logic\n");
 		return;
 	}
 
@@ -747,14 +1129,14 @@
 
 	spin_lock_bh(&sc->sc_resetlock);
 	if (!ath9k_hw_reset(ah, ah->ah_curchan,
-			    sc->sc_ht_info.tx_chan_width,
+			    sc->tx_chan_width,
 			    sc->sc_tx_chainmask,
 			    sc->sc_rx_chainmask,
 			    sc->sc_ht_extprotspacing,
 			    false, &status)) {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to reset channel %u (%uMhz) "
-			"flags 0x%x hal status %u\n", __func__,
+			"Unable to reset channel %u (%uMhz) "
+			"flags 0x%x hal status %u\n",
 			ath9k_hw_mhz2ieee(ah,
 				ah->ah_curchan->channel,
 				ah->ah_curchan->channelFlags),
@@ -834,7 +1216,7 @@
 			sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED;
 			if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) {
 				DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the"
-					"radio as it is disabled by h/w \n");
+					"radio as it is disabled by h/w\n");
 				return -EPERM;
 			}
 			ath_radio_enable(sc);
@@ -878,61 +1260,258 @@
 		sc->rf_kill.rfkill = NULL;
 	}
 }
-#endif /* CONFIG_RFKILL */
 
-static int ath_detach(struct ath_softc *sc)
+static int ath_start_rfkill_poll(struct ath_softc *sc)
 {
-	struct ieee80211_hw *hw = sc->hw;
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		queue_delayed_work(sc->hw->workqueue,
+				   &sc->rf_kill.rfkill_poll, 0);
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
+	if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
+		if (rfkill_register(sc->rf_kill.rfkill)) {
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"Unable to register rfkill\n");
+			rfkill_free(sc->rf_kill.rfkill);
 
-	/* Deinit LED control */
-	ath_deinit_leds(sc);
-
-#ifdef CONFIG_RFKILL
-	/* deinit rfkill */
-	ath_deinit_rfkill(sc);
-#endif
-
-	/* Unregister hw */
-
-	ieee80211_unregister_hw(hw);
-
-	/* unregister Rate control */
-	ath_rate_control_unregister();
-
-	/* tx/rx cleanup */
-
-	ath_rx_cleanup(sc);
-	ath_tx_cleanup(sc);
-
-	/* Deinit */
-
-	ath_deinit(sc);
+			/* Deinitialize the device */
+			ath_detach(sc);
+			if (sc->pdev->irq)
+				free_irq(sc->pdev->irq, sc);
+			pci_iounmap(sc->pdev, sc->mem);
+			pci_release_region(sc->pdev, 0);
+			pci_disable_device(sc->pdev);
+			ieee80211_free_hw(sc->hw);
+			return -EIO;
+		} else {
+			sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
+		}
+	}
 
 	return 0;
 }
+#endif /* CONFIG_RFKILL */
 
-static int ath_attach(u16 devid,
-		      struct ath_softc *sc)
+static void ath_detach(struct ath_softc *sc)
 {
 	struct ieee80211_hw *hw = sc->hw;
-	int error = 0;
+	int i = 0;
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__);
+	DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n");
 
-	error = ath_init(devid, sc);
-	if (error != 0)
-		return error;
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+	ath_deinit_rfkill(sc);
+#endif
+	ath_deinit_leds(sc);
 
-	/* Init nodes */
+	ieee80211_unregister_hw(hw);
+	ath_rx_cleanup(sc);
+	ath_tx_cleanup(sc);
 
-	INIT_LIST_HEAD(&sc->node_list);
-	spin_lock_init(&sc->node_lock);
+	tasklet_kill(&sc->intr_tq);
+	tasklet_kill(&sc->bcon_tasklet);
 
-	/* get mac address from hardware and set in mac80211 */
+	if (!(sc->sc_flags & SC_OP_INVALID))
+		ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
 
-	SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
+	/* cleanup tx queues */
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+		if (ATH_TXQ_SETUP(sc, i))
+			ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+
+	ath9k_hw_detach(sc->sc_ah);
+	ath9k_exit_debug(sc);
+}
+
+static int ath_init(u16 devid, struct ath_softc *sc)
+{
+	struct ath_hal *ah = NULL;
+	int status;
+	int error = 0, i;
+	int csz = 0;
+
+	/* XXX: hardware will not be ready until ath_open() being called */
+	sc->sc_flags |= SC_OP_INVALID;
+
+	if (ath9k_init_debug(sc) < 0)
+		printk(KERN_ERR "Unable to create debugfs files\n");
+
+	spin_lock_init(&sc->sc_resetlock);
+	mutex_init(&sc->mutex);
+	tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
+	tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
+		     (unsigned long)sc);
+
+	/*
+	 * Cache line size is used to size and align various
+	 * structures used to communicate with the hardware.
+	 */
+	bus_read_cachesize(sc, &csz);
+	/* XXX assert csz is non-zero */
+	sc->sc_cachelsz = csz << 2;	/* convert to bytes */
+
+	ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
+	if (ah == NULL) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Unable to attach hardware; HAL status %u\n", status);
+		error = -ENXIO;
+		goto bad;
+	}
+	sc->sc_ah = ah;
+
+	/* Get the hardware key cache size. */
+	sc->sc_keymax = ah->ah_caps.keycache_size;
+	if (sc->sc_keymax > ATH_KEYMAX) {
+		DPRINTF(sc, ATH_DBG_KEYCACHE,
+			"Warning, using only %u entries in %u key cache\n",
+			ATH_KEYMAX, sc->sc_keymax);
+		sc->sc_keymax = ATH_KEYMAX;
+	}
+
+	/*
+	 * Reset the key cache since some parts do not
+	 * reset the contents on initial power up.
+	 */
+	for (i = 0; i < sc->sc_keymax; i++)
+		ath9k_hw_keyreset(ah, (u16) i);
+
+	/* Collect the channel list using the default country code */
+
+	error = ath_setup_channels(sc);
+	if (error)
+		goto bad;
+
+	/* default to MONITOR mode */
+	sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR;
+
+
+	/* Setup rate tables */
+
+	ath_rate_attach(sc);
+	ath_setup_rates(sc, IEEE80211_BAND_2GHZ);
+	ath_setup_rates(sc, IEEE80211_BAND_5GHZ);
+
+	/*
+	 * Allocate hardware transmit queues: one queue for
+	 * beacon frames and one data queue for each QoS
+	 * priority.  Note that the hal handles reseting
+	 * these queues at the needed time.
+	 */
+	sc->beacon.beaconq = ath_beaconq_setup(ah);
+	if (sc->beacon.beaconq == -1) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Unable to setup a beacon xmit queue\n");
+		error = -EIO;
+		goto bad2;
+	}
+	sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
+	if (sc->beacon.cabq == NULL) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Unable to setup CAB xmit queue\n");
+		error = -EIO;
+		goto bad2;
+	}
+
+	sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME;
+	ath_cabq_update(sc);
+
+	for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++)
+		sc->tx.hwq_map[i] = -1;
+
+	/* Setup data queues */
+	/* NB: ensure BK queue is the lowest priority h/w queue */
+	if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Unable to setup xmit queue for BK traffic\n");
+		error = -EIO;
+		goto bad2;
+	}
+
+	if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Unable to setup xmit queue for BE traffic\n");
+		error = -EIO;
+		goto bad2;
+	}
+	if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Unable to setup xmit queue for VI traffic\n");
+		error = -EIO;
+		goto bad2;
+	}
+	if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Unable to setup xmit queue for VO traffic\n");
+		error = -EIO;
+		goto bad2;
+	}
+
+	/* Initializes the noise floor to a reasonable default value.
+	 * Later on this will be updated during ANI processing. */
+
+	sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
+	setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc);
+
+	if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+				   ATH9K_CIPHER_TKIP, NULL)) {
+		/*
+		 * Whether we should enable h/w TKIP MIC.
+		 * XXX: if we don't support WME TKIP MIC, then we wouldn't
+		 * report WMM capable, so it's always safe to turn on
+		 * TKIP MIC in this case.
+		 */
+		ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC,
+				       0, 1, NULL);
+	}
+
+	/*
+	 * Check whether the separate key cache entries
+	 * are required to handle both tx+rx MIC keys.
+	 * With split mic keys the number of stations is limited
+	 * to 27 otherwise 59.
+	 */
+	if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+				   ATH9K_CIPHER_TKIP, NULL)
+	    && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+				      ATH9K_CIPHER_MIC, NULL)
+	    && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
+				      0, NULL))
+		sc->sc_splitmic = 1;
+
+	/* turn on mcast key search if possible */
+	if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
+		(void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1,
+					     1, NULL);
+
+	sc->sc_config.txpowlimit = ATH_TXPOWER_MAX;
+	sc->sc_config.txpowlimit_override = 0;
+
+	/* 11n Capabilities */
+	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
+		sc->sc_flags |= SC_OP_TXAGGR;
+		sc->sc_flags |= SC_OP_RXAGGR;
+	}
+
+	sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
+	sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
+
+	ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
+	sc->rx.defant = ath9k_hw_getdefantenna(ah);
+
+	ath9k_hw_getmac(ah, sc->sc_myaddr);
+	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) {
+		ath9k_hw_getbssidmask(ah, sc->sc_bssidmask);
+		ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask);
+		ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
+	}
+
+	sc->beacon.slottime = ATH9K_SLOT_TIME_9;	/* default to short slot time */
+
+	/* initialize beacon slots */
+	for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
+		sc->beacon.bslot[i] = ATH_IF_ID_ANY;
+
+	/* save MISC configurations */
+	sc->sc_config.swBeaconProcess = 1;
 
 	/* setup channels and rates */
 
@@ -942,55 +1521,81 @@
 		sc->rates[IEEE80211_BAND_2GHZ];
 	sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
 
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
-		/* Setup HT capabilities for 2.4Ghz*/
-		setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info);
-
-	hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-		&sc->sbands[IEEE80211_BAND_2GHZ];
-
 	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
 		sc->sbands[IEEE80211_BAND_5GHZ].channels =
 			sc->channels[IEEE80211_BAND_5GHZ];
 		sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
 			sc->rates[IEEE80211_BAND_5GHZ];
-		sc->sbands[IEEE80211_BAND_5GHZ].band =
-			IEEE80211_BAND_5GHZ;
-
-		if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
-			/* Setup HT capabilities for 5Ghz*/
-			setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info);
-
-		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-			&sc->sbands[IEEE80211_BAND_5GHZ];
+		sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
 	}
 
-	/* FIXME: Have to figure out proper hw init values later */
+	return 0;
+bad2:
+	/* cleanup tx queues */
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+		if (ATH_TXQ_SETUP(sc, i))
+			ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+bad:
+	if (ah)
+		ath9k_hw_detach(ah);
+
+	return error;
+}
+
+static int ath_attach(u16 devid, struct ath_softc *sc)
+{
+	struct ieee80211_hw *hw = sc->hw;
+	int error = 0;
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
+
+	error = ath_init(devid, sc);
+	if (error != 0)
+		return error;
+
+	/* get mac address from hardware and set in mac80211 */
+
+	SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
+
+	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+		IEEE80211_HW_SIGNAL_DBM |
+		IEEE80211_HW_AMPDU_AGGREGATION;
+
+	hw->wiphy->interface_modes =
+		BIT(NL80211_IFTYPE_AP) |
+		BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_ADHOC);
 
 	hw->queues = 4;
-	hw->ampdu_queues = 1;
+	hw->max_rates = 4;
+	hw->max_rate_tries = ATH_11N_TXMAXTRY;
+	hw->sta_data_size = sizeof(struct ath_node);
+	hw->vif_data_size = sizeof(struct ath_vap);
 
-	/* Register rate control */
 	hw->rate_control_algorithm = "ath9k_rate_control";
-	error = ath_rate_control_register();
-	if (error != 0) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unable to register rate control "
-			"algorithm:%d\n", __func__, error);
-		ath_rate_control_unregister();
-		goto bad;
+
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
+		setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+		if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
+			setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
 	}
 
-	error = ieee80211_register_hw(hw);
-	if (error != 0) {
-		ath_rate_control_unregister();
-		goto bad;
-	}
+	hw->wiphy->bands[IEEE80211_BAND_2GHZ] =	&sc->sbands[IEEE80211_BAND_2GHZ];
+	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
+		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+			&sc->sbands[IEEE80211_BAND_5GHZ];
 
-	/* Initialize LED control */
-	ath_init_leds(sc);
+	/* initialize tx/rx engine */
+	error = ath_tx_init(sc, ATH_TXBUF);
+	if (error != 0)
+		goto detach;
 
-#ifdef CONFIG_RFKILL
+	error = ath_rx_init(sc, ATH_RXBUF);
+	if (error != 0)
+		goto detach;
+
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 	/* Initialze h/w Rfkill */
 	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
@@ -1000,88 +1605,371 @@
 		goto detach;
 #endif
 
-	/* initialize tx/rx engine */
+	error = ieee80211_register_hw(hw);
 
-	error = ath_tx_init(sc, ATH_TXBUF);
-	if (error != 0)
-		goto detach;
-
-	error = ath_rx_init(sc, ATH_RXBUF);
-	if (error != 0)
-		goto detach;
+	/* Initialize LED control */
+	ath_init_leds(sc);
 
 	return 0;
 detach:
 	ath_detach(sc);
-bad:
 	return error;
 }
 
+int ath_reset(struct ath_softc *sc, bool retry_tx)
+{
+	struct ath_hal *ah = sc->sc_ah;
+	int status;
+	int error = 0;
+
+	ath9k_hw_set_interrupts(ah, 0);
+	ath_draintxq(sc, retry_tx);
+	ath_stoprecv(sc);
+	ath_flushrecv(sc);
+
+	spin_lock_bh(&sc->sc_resetlock);
+	if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan,
+			    sc->tx_chan_width,
+			    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+			    sc->sc_ht_extprotspacing, false, &status)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Unable to reset hardware; hal status %u\n", status);
+		error = -EIO;
+	}
+	spin_unlock_bh(&sc->sc_resetlock);
+
+	if (ath_startrecv(sc) != 0)
+		DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n");
+
+	/*
+	 * We may be doing a reset in response to a request
+	 * that changes the channel so update any state that
+	 * might change as a result.
+	 */
+	ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan));
+
+	ath_update_txpow(sc);
+
+	if (sc->sc_flags & SC_OP_BEACONS)
+		ath_beacon_config(sc, ATH_IF_ID_ANY);	/* restart beacons */
+
+	ath9k_hw_set_interrupts(ah, sc->sc_imask);
+
+	if (retry_tx) {
+		int i;
+		for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+			if (ATH_TXQ_SETUP(sc, i)) {
+				spin_lock_bh(&sc->tx.txq[i].axq_lock);
+				ath_txq_schedule(sc, &sc->tx.txq[i]);
+				spin_unlock_bh(&sc->tx.txq[i].axq_lock);
+			}
+		}
+	}
+
+	return error;
+}
+
+/*
+ *  This function will allocate both the DMA descriptor structure, and the
+ *  buffers it contains.  These are used to contain the descriptors used
+ *  by the system.
+*/
+int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+		      struct list_head *head, const char *name,
+		      int nbuf, int ndesc)
+{
+#define	DS2PHYS(_dd, _ds)						\
+	((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
+#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
+#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
+
+	struct ath_desc *ds;
+	struct ath_buf *bf;
+	int i, bsize, error;
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
+		name, nbuf, ndesc);
+
+	/* ath_desc must be a multiple of DWORDs */
+	if ((sizeof(struct ath_desc) % 4) != 0) {
+		DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n");
+		ASSERT((sizeof(struct ath_desc) % 4) == 0);
+		error = -ENOMEM;
+		goto fail;
+	}
+
+	dd->dd_name = name;
+	dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
+
+	/*
+	 * Need additional DMA memory because we can't use
+	 * descriptors that cross the 4K page boundary. Assume
+	 * one skipped descriptor per 4K page.
+	 */
+	if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+		u32 ndesc_skipped =
+			ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
+		u32 dma_len;
+
+		while (ndesc_skipped) {
+			dma_len = ndesc_skipped * sizeof(struct ath_desc);
+			dd->dd_desc_len += dma_len;
+
+			ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
+		};
+	}
+
+	/* allocate descriptors */
+	dd->dd_desc = pci_alloc_consistent(sc->pdev,
+			      dd->dd_desc_len,
+			      &dd->dd_desc_paddr);
+	if (dd->dd_desc == NULL) {
+		error = -ENOMEM;
+		goto fail;
+	}
+	ds = dd->dd_desc;
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
+		dd->dd_name, ds, (u32) dd->dd_desc_len,
+		ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
+
+	/* allocate buffers */
+	bsize = sizeof(struct ath_buf) * nbuf;
+	bf = kmalloc(bsize, GFP_KERNEL);
+	if (bf == NULL) {
+		error = -ENOMEM;
+		goto fail2;
+	}
+	memset(bf, 0, bsize);
+	dd->dd_bufptr = bf;
+
+	INIT_LIST_HEAD(head);
+	for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
+		bf->bf_desc = ds;
+		bf->bf_daddr = DS2PHYS(dd, ds);
+
+		if (!(sc->sc_ah->ah_caps.hw_caps &
+		      ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+			/*
+			 * Skip descriptor addresses which can cause 4KB
+			 * boundary crossing (addr + length) with a 32 dword
+			 * descriptor fetch.
+			 */
+			while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
+				ASSERT((caddr_t) bf->bf_desc <
+				       ((caddr_t) dd->dd_desc +
+					dd->dd_desc_len));
+
+				ds += ndesc;
+				bf->bf_desc = ds;
+				bf->bf_daddr = DS2PHYS(dd, ds);
+			}
+		}
+		list_add_tail(&bf->list, head);
+	}
+	return 0;
+fail2:
+	pci_free_consistent(sc->pdev,
+		dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
+fail:
+	memset(dd, 0, sizeof(*dd));
+	return error;
+#undef ATH_DESC_4KB_BOUND_CHECK
+#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
+#undef DS2PHYS
+}
+
+void ath_descdma_cleanup(struct ath_softc *sc,
+			 struct ath_descdma *dd,
+			 struct list_head *head)
+{
+	pci_free_consistent(sc->pdev,
+		dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
+
+	INIT_LIST_HEAD(head);
+	kfree(dd->dd_bufptr);
+	memset(dd, 0, sizeof(*dd));
+}
+
+int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
+{
+	int qnum;
+
+	switch (queue) {
+	case 0:
+		qnum = sc->tx.hwq_map[ATH9K_WME_AC_VO];
+		break;
+	case 1:
+		qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI];
+		break;
+	case 2:
+		qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE];
+		break;
+	case 3:
+		qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK];
+		break;
+	default:
+		qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE];
+		break;
+	}
+
+	return qnum;
+}
+
+int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
+{
+	int qnum;
+
+	switch (queue) {
+	case ATH9K_WME_AC_VO:
+		qnum = 0;
+		break;
+	case ATH9K_WME_AC_VI:
+		qnum = 1;
+		break;
+	case ATH9K_WME_AC_BE:
+		qnum = 2;
+		break;
+	case ATH9K_WME_AC_BK:
+		qnum = 3;
+		break;
+	default:
+		qnum = -1;
+		break;
+	}
+
+	return qnum;
+}
+
+/**********************/
+/* mac80211 callbacks */
+/**********************/
+
 static int ath9k_start(struct ieee80211_hw *hw)
 {
 	struct ath_softc *sc = hw->priv;
 	struct ieee80211_channel *curchan = hw->conf.channel;
-	int error = 0, pos;
+	struct ath9k_channel *init_channel;
+	int error = 0, pos, status;
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with "
-		"initial channel: %d MHz\n", __func__, curchan->center_freq);
+	DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with "
+		"initial channel: %d MHz\n", curchan->center_freq);
 
 	/* setup initial channel */
 
 	pos = ath_get_channel(sc, curchan);
 	if (pos == -1) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
-		return -EINVAL;
+		DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq);
+		error = -EINVAL;
+		goto error;
 	}
 
+	sc->tx_chan_width = ATH9K_HT_MACMODE_20;
 	sc->sc_ah->ah_channels[pos].chanmode =
 		(curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
+	init_channel = &sc->sc_ah->ah_channels[pos];
 
-	/* open ath_dev */
-	error = ath_open(sc, &sc->sc_ah->ah_channels[pos]);
-	if (error) {
+	/* Reset SERDES registers */
+	ath9k_hw_configpcipowersave(sc->sc_ah, 0);
+
+	/*
+	 * The basic interface to setting the hardware in a good
+	 * state is ``reset''.  On return the hardware is known to
+	 * be powered up and with interrupts disabled.  This must
+	 * be followed by initialization of the appropriate bits
+	 * and then setup of the interrupt mask.
+	 */
+	spin_lock_bh(&sc->sc_resetlock);
+	if (!ath9k_hw_reset(sc->sc_ah, init_channel,
+			    sc->tx_chan_width,
+			    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+			    sc->sc_ht_extprotspacing, false, &status)) {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unable to complete ath_open\n", __func__);
-		return error;
+			"Unable to reset hardware; hal status %u "
+			"(freq %u flags 0x%x)\n", status,
+			init_channel->channel, init_channel->channelFlags);
+		error = -EIO;
+		spin_unlock_bh(&sc->sc_resetlock);
+		goto error;
+	}
+	spin_unlock_bh(&sc->sc_resetlock);
+
+	/*
+	 * This is needed only to setup initial state
+	 * but it's best done after a reset.
+	 */
+	ath_update_txpow(sc);
+
+	/*
+	 * Setup the hardware after reset:
+	 * The receive engine is set going.
+	 * Frame transmit is handled entirely
+	 * in the frame output path; there's nothing to do
+	 * here except setup the interrupt mask.
+	 */
+	if (ath_startrecv(sc) != 0) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Unable to start recv logic\n");
+		error = -EIO;
+		goto error;
 	}
 
-#ifdef CONFIG_RFKILL
-	/* Start rfkill polling */
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-		queue_delayed_work(sc->hw->workqueue,
-				   &sc->rf_kill.rfkill_poll, 0);
+	/* Setup our intr mask. */
+	sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
+		| ATH9K_INT_RXEOL | ATH9K_INT_RXORN
+		| ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
 
-	if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
-		if (rfkill_register(sc->rf_kill.rfkill)) {
-			DPRINTF(sc, ATH_DBG_FATAL,
-					"Unable to register rfkill\n");
-			rfkill_free(sc->rf_kill.rfkill);
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT)
+		sc->sc_imask |= ATH9K_INT_GTT;
 
-			/* Deinitialize the device */
-			if (sc->pdev->irq)
-				free_irq(sc->pdev->irq, sc);
-			ath_detach(sc);
-			pci_iounmap(sc->pdev, sc->mem);
-			pci_release_region(sc->pdev, 0);
-			pci_disable_device(sc->pdev);
-			ieee80211_free_hw(hw);
-			return -EIO;
-		} else {
-			sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
-		}
-	}
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
+		sc->sc_imask |= ATH9K_INT_CST;
+
+	/*
+	 * Enable MIB interrupts when there are hardware phy counters.
+	 * Note we only do this (at the moment) for station mode.
+	 */
+	if (ath9k_hw_phycounters(sc->sc_ah) &&
+	    ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) ||
+	     (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)))
+		sc->sc_imask |= ATH9K_INT_MIB;
+	/*
+	 * Some hardware processes the TIM IE and fires an
+	 * interrupt when the TIM bit is set.  For hardware
+	 * that does, if not overridden by configuration,
+	 * enable the TIM interrupt when operating as station.
+	 */
+	if ((sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
+	    (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) &&
+	    !sc->sc_config.swBeaconProcess)
+		sc->sc_imask |= ATH9K_INT_TIM;
+
+	ath_setcurmode(sc, ath_chan2mode(init_channel));
+
+	sc->sc_flags &= ~SC_OP_INVALID;
+
+	/* Disable BMISS interrupt when we're not associated */
+	sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+	ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
+
+	ieee80211_wake_queues(sc->hw);
+
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+	error = ath_start_rfkill_poll(sc);
 #endif
 
-	ieee80211_wake_queues(hw);
-	return 0;
+error:
+	return error;
 }
 
 static int ath9k_tx(struct ieee80211_hw *hw,
 		    struct sk_buff *skb)
 {
-	struct ath_softc *sc = hw->priv;
-	int hdrlen, padsize;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ath_softc *sc = hw->priv;
+	struct ath_tx_control txctl;
+	int hdrlen, padsize;
+
+	memset(&txctl, 0, sizeof(struct ath_tx_control));
 
 	/*
 	 * As a temporary workaround, assign seq# here; this will likely need
@@ -1091,9 +1979,9 @@
 	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
 		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 		if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
-			sc->seq_no += 0x10;
+			sc->tx.seq_no += 0x10;
 		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-		hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+		hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
 	}
 
 	/* Add the padding after the header if this is not already done */
@@ -1106,45 +1994,68 @@
 		memmove(skb->data, skb->data + padsize, hdrlen);
 	}
 
-	DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n",
-		__func__,
-		skb);
+	/* Check if a tx queue is available */
 
-	if (ath_tx_start(sc, skb) != 0) {
-		DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__);
-		dev_kfree_skb_any(skb);
-		/* FIXME: Check for proper return value from ATH_DEV */
-		return 0;
+	txctl.txq = ath_test_get_txq(sc, skb);
+	if (!txctl.txq)
+		goto exit;
+
+	DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
+
+	if (ath_tx_start(sc, skb, &txctl) != 0) {
+		DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n");
+		goto exit;
 	}
 
 	return 0;
+exit:
+	dev_kfree_skb_any(skb);
+	return 0;
 }
 
 static void ath9k_stop(struct ieee80211_hw *hw)
 {
 	struct ath_softc *sc = hw->priv;
-	int error;
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
+	if (sc->sc_flags & SC_OP_INVALID) {
+		DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
+		return;
+	}
 
-	error = ath_suspend(sc);
-	if (error)
-		DPRINTF(sc, ATH_DBG_CONFIG,
-			"%s: Device is no longer present\n", __func__);
+	DPRINTF(sc, ATH_DBG_CONFIG, "Cleaning up\n");
 
-	ieee80211_stop_queues(hw);
+	ieee80211_stop_queues(sc->hw);
 
-#ifdef CONFIG_RFKILL
+	/* make sure h/w will not generate any interrupt
+	 * before setting the invalid flag. */
+	ath9k_hw_set_interrupts(sc->sc_ah, 0);
+
+	if (!(sc->sc_flags & SC_OP_INVALID)) {
+		ath_draintxq(sc, false);
+		ath_stoprecv(sc);
+		ath9k_hw_phy_disable(sc->sc_ah);
+	} else
+		sc->rx.rxlink = NULL;
+
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
 #endif
+	/* disable HAL and put h/w to sleep */
+	ath9k_hw_disable(sc->sc_ah);
+	ath9k_hw_configpcipowersave(sc->sc_ah, 1);
+
+	sc->sc_flags |= SC_OP_INVALID;
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n");
 }
 
 static int ath9k_add_interface(struct ieee80211_hw *hw,
 			       struct ieee80211_if_init_conf *conf)
 {
 	struct ath_softc *sc = hw->priv;
-	int error, ic_opmode = 0;
+	struct ath_vap *avp = (void *)conf->vif->drv_priv;
+	enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
 
 	/* Support only vap for now */
 
@@ -1153,32 +2064,34 @@
 
 	switch (conf->type) {
 	case NL80211_IFTYPE_STATION:
-		ic_opmode = ATH9K_M_STA;
+		ic_opmode = NL80211_IFTYPE_STATION;
 		break;
 	case NL80211_IFTYPE_ADHOC:
-		ic_opmode = ATH9K_M_IBSS;
+		ic_opmode = NL80211_IFTYPE_ADHOC;
 		break;
 	case NL80211_IFTYPE_AP:
-		ic_opmode = ATH9K_M_HOSTAP;
+		ic_opmode = NL80211_IFTYPE_AP;
 		break;
 	default:
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Interface type %d not yet supported\n",
-			__func__, conf->type);
+			"Interface type %d not yet supported\n", conf->type);
 		return -EOPNOTSUPP;
 	}
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n",
-		__func__,
-		ic_opmode);
+	DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VAP of type: %d\n", ic_opmode);
 
-	error = ath_vap_attach(sc, 0, conf->vif, ic_opmode);
-	if (error) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unable to attach vap, error: %d\n",
-			__func__, error);
-		return error;
-	}
+	/* Set the VAP opmode */
+	avp->av_opmode = ic_opmode;
+	avp->av_bslot = -1;
+
+	if (ic_opmode == NL80211_IFTYPE_AP)
+		ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
+
+	sc->sc_vaps[0] = conf->vif;
+	sc->sc_nvaps++;
+
+	/* Set the device opmode */
+	sc->sc_ah->ah_opmode = ic_opmode;
 
 	if (conf->type == NL80211_IFTYPE_AP) {
 		/* TODO: is this a suitable place to start ANI for AP mode? */
@@ -1194,78 +2107,76 @@
 				   struct ieee80211_if_init_conf *conf)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ath_vap *avp;
-	int error;
+	struct ath_vap *avp = (void *)conf->vif->drv_priv;
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__);
+	DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n");
 
-	avp = sc->sc_vaps[0];
-	if (avp == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-			__func__);
-		return;
-	}
-
-#ifdef CONFIG_SLOW_ANT_DIV
-	ath_slow_ant_div_stop(&sc->sc_antdiv);
-#endif
 	/* Stop ANI */
 	del_timer_sync(&sc->sc_ani.timer);
 
-	/* Update ratectrl */
-	ath_rate_newstate(sc, avp);
-
 	/* Reclaim beacon resources */
-	if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
-	    sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
-		ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
+	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP ||
+	    sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) {
+		ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 		ath_beacon_return(sc, avp);
 	}
 
-	/* Set interrupt mask */
-	sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-	ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL);
 	sc->sc_flags &= ~SC_OP_BEACONS;
 
-	error = ath_vap_detach(sc, 0);
-	if (error)
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unable to detach vap, error: %d\n",
-			__func__, error);
+	sc->sc_vaps[0] = NULL;
+	sc->sc_nvaps--;
 }
 
-static int ath9k_config(struct ieee80211_hw *hw,
-			struct ieee80211_conf *conf)
+static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ieee80211_channel *curchan = hw->conf.channel;
-	int pos;
+	struct ieee80211_conf *conf = &hw->conf;
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
-		__func__,
-		curchan->center_freq);
+	mutex_lock(&sc->mutex);
+	if (changed & (IEEE80211_CONF_CHANGE_CHANNEL |
+		       IEEE80211_CONF_CHANGE_HT)) {
+		struct ieee80211_channel *curchan = hw->conf.channel;
+		int pos;
 
-	pos = ath_get_channel(sc, curchan);
-	if (pos == -1) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
-		return -EINVAL;
+		DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
+			curchan->center_freq);
+
+		pos = ath_get_channel(sc, curchan);
+		if (pos == -1) {
+			DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n",
+				curchan->center_freq);
+			mutex_unlock(&sc->mutex);
+			return -EINVAL;
+		}
+
+		sc->tx_chan_width = ATH9K_HT_MACMODE_20;
+		sc->sc_ah->ah_channels[pos].chanmode =
+			(curchan->band == IEEE80211_BAND_2GHZ) ?
+			CHANNEL_G : CHANNEL_A;
+
+		if (conf->ht.enabled) {
+			if (conf->ht.channel_type == NL80211_CHAN_HT40PLUS ||
+			    conf->ht.channel_type == NL80211_CHAN_HT40MINUS)
+				sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
+
+			sc->sc_ah->ah_channels[pos].chanmode =
+				ath_get_extchanmode(sc, curchan,
+						    conf->ht.channel_type);
+		}
+
+		if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
+			DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
+			mutex_unlock(&sc->mutex);
+			return -EINVAL;
+		}
+
+		ath_update_chainmask(sc, conf->ht.enabled);
 	}
 
-	sc->sc_ah->ah_channels[pos].chanmode =
-		(curchan->band == IEEE80211_BAND_2GHZ) ?
-		CHANNEL_G : CHANNEL_A;
+	if (changed & IEEE80211_CONF_CHANGE_POWER)
+		sc->sc_config.txpowlimit = 2 * conf->power_level;
 
-	if (sc->sc_curaid && hw->conf.ht_conf.ht_supported)
-		sc->sc_ah->ah_channels[pos].chanmode =
-			ath_get_extchanmode(sc, curchan);
-
-	sc->sc_config.txpowlimit = 2 * conf->power_level;
-
-	/* set h/w channel */
-	if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n",
-			__func__);
-
+	mutex_unlock(&sc->mutex);
 	return 0;
 }
 
@@ -1275,23 +2186,15 @@
 {
 	struct ath_softc *sc = hw->priv;
 	struct ath_hal *ah = sc->sc_ah;
-	struct ath_vap *avp;
+	struct ath_vap *avp = (void *)vif->drv_priv;
 	u32 rfilt = 0;
 	int error, i;
-	DECLARE_MAC_BUF(mac);
-
-	avp = sc->sc_vaps[0];
-	if (avp == NULL) {
-		DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-			__func__);
-		return -EINVAL;
-	}
 
 	/* TODO: Need to decide which hw opmode to use for multi-interface
 	 * cases */
 	if (vif->type == NL80211_IFTYPE_AP &&
-	    ah->ah_opmode != ATH9K_M_HOSTAP) {
-		ah->ah_opmode = ATH9K_M_HOSTAP;
+	    ah->ah_opmode != NL80211_IFTYPE_AP) {
+		ah->ah_opmode = NL80211_IFTYPE_STATION;
 		ath9k_hw_setopmode(ah);
 		ath9k_hw_write_associd(ah, sc->sc_myaddr, 0);
 		/* Request full reset to get hw opmode changed properly */
@@ -1303,9 +2206,6 @@
 		switch (vif->type) {
 		case NL80211_IFTYPE_STATION:
 		case NL80211_IFTYPE_ADHOC:
-			/* Update ratectrl about the new state */
-			ath_rate_newstate(sc, avp);
-
 			/* Set BSSID */
 			memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN);
 			sc->sc_curaid = 0;
@@ -1315,27 +2215,9 @@
 			/* Set aggregation protection mode parameters */
 			sc->sc_config.ath_aggr_prot = 0;
 
-			/*
-			 * Reset our TSF so that its value is lower than the
-			 * beacon that we are trying to catch.
-			 * Only then hw will update its TSF register with the
-			 * new beacon. Reset the TSF before setting the BSSID
-			 * to avoid allowing in any frames that would update
-			 * our TSF only to have us clear it
-			 * immediately thereafter.
-			 */
-			ath9k_hw_reset_tsf(sc->sc_ah);
-
-			/* Disable BMISS interrupt when we're not associated */
-			ath9k_hw_set_interrupts(sc->sc_ah,
-					sc->sc_imask &
-					~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
-			sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-
 			DPRINTF(sc, ATH_DBG_CONFIG,
-				"%s: RX filter 0x%x bssid %s aid 0x%x\n",
-				__func__, rfilt,
-				print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
+				"RX filter 0x%x bssid %pM aid 0x%x\n",
+				rfilt, sc->sc_curbssid, sc->sc_curaid);
 
 			/* need to reconfigure the beacon */
 			sc->sc_flags &= ~SC_OP_BEACONS ;
@@ -1357,7 +2239,7 @@
 		 * causes reconfiguration; we may be called
 		 * with beacon transmission active.
 		 */
-		ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
+		ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 
 		error = ath_beacon_alloc(sc, 0);
 		if (error != 0)
@@ -1403,7 +2285,7 @@
 	changed_flags &= SUPPORTED_FILTERS;
 	*total_flags &= SUPPORTED_FILTERS;
 
-	sc->rx_filter = *total_flags;
+	sc->rx.rxfilter = *total_flags;
 	rfilt = ath_calcrxfilter(sc);
 	ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
 
@@ -1412,8 +2294,7 @@
 			ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0);
 	}
 
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n",
-		__func__, sc->rx_filter);
+	DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter);
 }
 
 static void ath9k_sta_notify(struct ieee80211_hw *hw,
@@ -1422,37 +2303,13 @@
 			     struct ieee80211_sta *sta)
 {
 	struct ath_softc *sc = hw->priv;
-	struct ath_node *an;
-	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
-
-	spin_lock_irqsave(&sc->node_lock, flags);
-	an = ath_node_find(sc, sta->addr);
-	spin_unlock_irqrestore(&sc->node_lock, flags);
 
 	switch (cmd) {
 	case STA_NOTIFY_ADD:
-		spin_lock_irqsave(&sc->node_lock, flags);
-		if (!an) {
-			ath_node_attach(sc, sta->addr, 0);
-			DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n",
-				__func__, print_mac(mac, sta->addr));
-		} else {
-			ath_node_get(sc, sta->addr);
-		}
-		spin_unlock_irqrestore(&sc->node_lock, flags);
+		ath_node_attach(sc, sta);
 		break;
 	case STA_NOTIFY_REMOVE:
-		if (!an)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Removal of a non-existent node\n",
-				__func__);
-		else {
-			ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT);
-			DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n",
-				__func__,
-				print_mac(mac, sta->addr));
-		}
+		ath_node_detach(sc, sta);
 		break;
 	default:
 		break;
@@ -1477,20 +2334,14 @@
 	qnum = ath_get_hal_qnum(queue, sc);
 
 	DPRINTF(sc, ATH_DBG_CONFIG,
-		"%s: Configure tx [queue/halq] [%d/%d],  "
+		"Configure tx [queue/halq] [%d/%d],  "
 		"aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
-		__func__,
-		queue,
-		qnum,
-		params->aifs,
-		params->cw_min,
-		params->cw_max,
-		params->txop);
+		queue, qnum, params->aifs, params->cw_min,
+		params->cw_max, params->txop);
 
 	ret = ath_txq_update(sc, qnum, &qi);
 	if (ret)
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: TXQ Update failed\n", __func__);
+		DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n");
 
 	return ret;
 }
@@ -1504,23 +2355,22 @@
 	struct ath_softc *sc = hw->priv;
 	int ret = 0;
 
-	DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__);
+	DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n");
 
 	switch (cmd) {
 	case SET_KEY:
 		ret = ath_key_config(sc, addr, key);
-		if (!ret) {
-			set_bit(key->keyidx, sc->sc_keymap);
-			key->hw_key_idx = key->keyidx;
+		if (ret >= 0) {
+			key->hw_key_idx = ret;
 			/* push IV and Michael MIC generation to stack */
 			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 			if (key->alg == ALG_TKIP)
 				key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+			ret = 0;
 		}
 		break;
 	case DISABLE_KEY:
 		ath_key_delete(sc, key);
-		clear_bit(key->keyidx, sc->sc_keymap);
 		break;
 	default:
 		ret = -EINVAL;
@@ -1537,8 +2387,7 @@
 	struct ath_softc *sc = hw->priv;
 
 	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n",
-			__func__,
+		DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
 			bss_conf->use_short_preamble);
 		if (bss_conf->use_short_preamble)
 			sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
@@ -1547,8 +2396,7 @@
 	}
 
 	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n",
-			__func__,
+		DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
 			bss_conf->use_cts_prot);
 		if (bss_conf->use_cts_prot &&
 		    hw->conf.channel->band != IEEE80211_BAND_5GHZ)
@@ -1557,18 +2405,10 @@
 			sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
 	}
 
-	if (changed & BSS_CHANGED_HT) {
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n",
-			__func__,
-			bss_conf->assoc_ht);
-		ath9k_ht_conf(sc, bss_conf);
-	}
-
 	if (changed & BSS_CHANGED_ASSOC) {
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n",
-			__func__,
+		DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
 			bss_conf->assoc);
-		ath9k_bss_assoc_info(sc, bss_conf);
+		ath9k_bss_assoc_info(sc, vif, bss_conf);
 	}
 }
 
@@ -1601,50 +2441,37 @@
 
 	switch (action) {
 	case IEEE80211_AMPDU_RX_START:
-		ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn);
-		if (ret < 0)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to start RX aggregation\n",
-				__func__);
+		if (!(sc->sc_flags & SC_OP_RXAGGR))
+			ret = -ENOTSUPP;
 		break;
 	case IEEE80211_AMPDU_RX_STOP:
-		ret = ath_rx_aggr_stop(sc, sta->addr, tid);
-		if (ret < 0)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to stop RX aggregation\n",
-				__func__);
 		break;
 	case IEEE80211_AMPDU_TX_START:
-		ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn);
+		ret = ath_tx_aggr_start(sc, sta, tid, ssn);
 		if (ret < 0)
 			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to start TX aggregation\n",
-				__func__);
+				"Unable to start TX aggregation\n");
 		else
 			ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
 		break;
 	case IEEE80211_AMPDU_TX_STOP:
-		ret = ath_tx_aggr_stop(sc, sta->addr, tid);
+		ret = ath_tx_aggr_stop(sc, sta, tid);
 		if (ret < 0)
 			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to stop TX aggregation\n",
-				__func__);
+				"Unable to stop TX aggregation\n");
 
 		ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
 		break;
+	case IEEE80211_AMPDU_TX_RESUME:
+		ath_tx_aggr_resume(sc, sta, tid);
+		break;
 	default:
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unknown AMPDU action\n", __func__);
+		DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n");
 	}
 
 	return ret;
 }
 
-static int ath9k_no_fragmentation(struct ieee80211_hw *hw, u32 value)
-{
-	return -EOPNOTSUPP;
-}
-
 static struct ieee80211_ops ath9k_ops = {
 	.tx 		    = ath9k_tx,
 	.start 		    = ath9k_start,
@@ -1654,42 +2481,97 @@
 	.config 	    = ath9k_config,
 	.config_interface   = ath9k_config_interface,
 	.configure_filter   = ath9k_configure_filter,
-	.get_stats          = NULL,
 	.sta_notify         = ath9k_sta_notify,
 	.conf_tx 	    = ath9k_conf_tx,
-	.get_tx_stats 	    = NULL,
 	.bss_info_changed   = ath9k_bss_info_changed,
-	.set_tim            = NULL,
 	.set_key            = ath9k_set_key,
-	.hw_scan            = NULL,
-	.get_tkip_seq       = NULL,
-	.set_rts_threshold  = NULL,
-	.set_frag_threshold = NULL,
-	.set_retry_limit    = NULL,
 	.get_tsf 	    = ath9k_get_tsf,
 	.reset_tsf 	    = ath9k_reset_tsf,
-	.tx_last_beacon     = NULL,
 	.ampdu_action       = ath9k_ampdu_action,
-	.set_frag_threshold = ath9k_no_fragmentation,
 };
 
+static struct {
+	u32 version;
+	const char * name;
+} ath_mac_bb_names[] = {
+	{ AR_SREV_VERSION_5416_PCI,	"5416" },
+	{ AR_SREV_VERSION_5416_PCIE,	"5418" },
+	{ AR_SREV_VERSION_9100,		"9100" },
+	{ AR_SREV_VERSION_9160,		"9160" },
+	{ AR_SREV_VERSION_9280,		"9280" },
+	{ AR_SREV_VERSION_9285,		"9285" }
+};
+
+static struct {
+	u16 version;
+	const char * name;
+} ath_rf_names[] = {
+	{ 0,				"5133" },
+	{ AR_RAD5133_SREV_MAJOR,	"5133" },
+	{ AR_RAD5122_SREV_MAJOR,	"5122" },
+	{ AR_RAD2133_SREV_MAJOR,	"2133" },
+	{ AR_RAD2122_SREV_MAJOR,	"2122" }
+};
+
+/*
+ * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown.
+ */
+static const char *
+ath_mac_bb_name(u32 mac_bb_version)
+{
+	int i;
+
+	for (i=0; i<ARRAY_SIZE(ath_mac_bb_names); i++) {
+		if (ath_mac_bb_names[i].version == mac_bb_version) {
+			return ath_mac_bb_names[i].name;
+		}
+	}
+
+	return "????";
+}
+
+/*
+ * Return the RF name. "????" is returned if the RF is unknown.
+ */
+static const char *
+ath_rf_name(u16 rf_version)
+{
+	int i;
+
+	for (i=0; i<ARRAY_SIZE(ath_rf_names); i++) {
+		if (ath_rf_names[i].version == rf_version) {
+			return ath_rf_names[i].name;
+		}
+	}
+
+	return "????";
+}
+
 static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	void __iomem *mem;
 	struct ath_softc *sc;
 	struct ieee80211_hw *hw;
-	const char *athname;
 	u8 csz;
 	u32 val;
 	int ret = 0;
+	struct ath_hal *ah;
 
 	if (pci_enable_device(pdev))
 		return -EIO;
 
-	/* XXX 32-bit addressing only */
-	if (pci_set_dma_mask(pdev, 0xffffffff)) {
-		printk(KERN_ERR "ath_pci: 32-bit DMA not available\n");
-		ret = -ENODEV;
+	ret =  pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+
+	if (ret) {
+		printk(KERN_ERR "ath9k: 32-bit DMA not available\n");
+		goto bad;
+	}
+
+	ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+
+	if (ret) {
+		printk(KERN_ERR "ath9k: 32-bit DMA consistent "
+			"DMA enable failed\n");
 		goto bad;
 	}
 
@@ -1746,16 +2628,6 @@
 		goto bad2;
 	}
 
-	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-		IEEE80211_HW_SIGNAL_DBM |
-		IEEE80211_HW_NOISE_DBM;
-
-	hw->wiphy->interface_modes =
-		BIT(NL80211_IFTYPE_AP) |
-		BIT(NL80211_IFTYPE_STATION) |
-		BIT(NL80211_IFTYPE_ADHOC);
-
 	SET_IEEE80211_DEV(hw, &pdev->dev);
 	pci_set_drvdata(pdev, hw);
 
@@ -1778,11 +2650,15 @@
 		goto bad4;
 	}
 
-	athname = ath9k_hw_probe(id->vendor, id->device);
-
-	printk(KERN_INFO "%s: %s: mem=0x%lx, irq=%d\n",
+	ah = sc->sc_ah;
+	printk(KERN_INFO
+	       "%s: Atheros AR%s MAC/BB Rev:%x "
+	       "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n",
 	       wiphy_name(hw->wiphy),
-	       athname ? athname : "Atheros ???",
+	       ath_mac_bb_name(ah->ah_macVersion),
+	       ah->ah_macRev,
+	       ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
+	       ah->ah_phyRev,
 	       (unsigned long)mem, pdev->irq);
 
 	return 0;
@@ -1803,17 +2679,10 @@
 {
 	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
 	struct ath_softc *sc = hw->priv;
-	enum ath9k_int status;
 
-	if (pdev->irq) {
-		ath9k_hw_set_interrupts(sc->sc_ah, 0);
-		/* clear the ISR */
-		ath9k_hw_getisr(sc->sc_ah, &status);
-		sc->sc_flags |= SC_OP_INVALID;
-		free_irq(pdev->irq, sc);
-	}
 	ath_detach(sc);
-
+	if (pdev->irq)
+		free_irq(pdev->irq, sc);
 	pci_iounmap(pdev, sc->mem);
 	pci_release_region(pdev, 0);
 	pci_disable_device(pdev);
@@ -1829,7 +2698,7 @@
 
 	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
 
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
 #endif
@@ -1866,7 +2735,7 @@
 			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
 
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
 	/*
 	 * check the h/w rfkill state on resume
 	 * and start the rfkill poll timer
@@ -1896,11 +2765,24 @@
 
 static int __init init_ath_pci(void)
 {
+	int error;
+
 	printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION);
 
+	/* Register rate control algorithm */
+	error = ath_rate_control_register();
+	if (error != 0) {
+		printk(KERN_ERR
+			"Unable to register rate control algorithm: %d\n",
+			error);
+		ath_rate_control_unregister();
+		return error;
+	}
+
 	if (pci_register_driver(&ath_pci_driver) < 0) {
 		printk(KERN_ERR
 			"ath_pci: No devices found, driver not installed.\n");
+		ath_rate_control_unregister();
 		pci_unregister_driver(&ath_pci_driver);
 		return -ENODEV;
 	}
@@ -1911,7 +2793,8 @@
 
 static void __exit exit_ath_pci(void)
 {
+	ath_rate_control_unregister();
 	pci_unregister_driver(&ath_pci_driver);
-	printk(KERN_INFO "%s: driver unloaded\n", dev_info);
+	printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
 }
 module_exit(exit_ath_pci);
diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c
index eb9121f..766982a 100644
--- a/drivers/net/wireless/ath9k/phy.c
+++ b/drivers/net/wireless/ath9k/phy.c
@@ -52,8 +52,7 @@
 			bModeSynth = 1;
 		} else {
 			DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-				 "%s: invalid channel %u MHz\n", __func__,
-				 freq);
+				"Invalid channel %u MHz\n", freq);
 			return false;
 		}
 
@@ -86,7 +85,7 @@
 		aModeRefSel = ath9k_hw_reverse_bits(1, 2);
 	} else {
 		DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-			 "%s: invalid channel %u MHz\n", __func__, freq);
+			"Invalid channel %u MHz\n", freq);
 		return false;
 	}
 
@@ -215,7 +214,7 @@
 	if (AR_SREV_9280_10_OR_LATER(ah))
 		return true;
 
-	eepMinorRev = ath9k_hw_get_eeprom(ahp, EEP_MINOR_REV);
+	eepMinorRev = ath9k_hw_get_eeprom(ah, EEP_MINOR_REV);
 
 	RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1);
 
@@ -235,15 +234,15 @@
 
 	if (eepMinorRev >= 2) {
 		if (IS_CHAN_2GHZ(chan)) {
-			ob2GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_2);
-			db2GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_2);
+			ob2GHz = ath9k_hw_get_eeprom(ah, EEP_OB_2);
+			db2GHz = ath9k_hw_get_eeprom(ah, EEP_DB_2);
 			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
 						   ob2GHz, 3, 197, 0);
 			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
 						   db2GHz, 3, 194, 0);
 		} else {
-			ob5GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_5);
-			db5GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_5);
+			ob5GHz = ath9k_hw_get_eeprom(ah, EEP_OB_5);
+			db5GHz = ath9k_hw_get_eeprom(ah, EEP_DB_5);
 			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
 						   ob5GHz, 3, 203, 0);
 			ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
@@ -348,8 +347,7 @@
 		    || ahp->ah_analogBank6TPCData == NULL
 		    || ahp->ah_analogBank7Data == NULL) {
 			DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
-				 "%s: cannot allocate RF banks\n",
-				 __func__);
+				"Cannot allocate RF banks\n");
 			*status = -ENOMEM;
 			return false;
 		}
@@ -360,8 +358,7 @@
 			     ahp->ah_iniAddac.ia_columns), GFP_KERNEL);
 		if (ahp->ah_addac5416_21 == NULL) {
 			DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
-				 "%s: cannot allocate ah_addac5416_21\n",
-				 __func__);
+				"Cannot allocate ah_addac5416_21\n");
 			*status = -ENOMEM;
 			return false;
 		}
@@ -371,8 +368,7 @@
 			     ahp->ah_iniBank6.ia_rows), GFP_KERNEL);
 		if (ahp->ah_bank6Temp == NULL) {
 			DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
-				 "%s: cannot allocate ah_bank6Temp\n",
-				 __func__);
+				"Cannot allocate ah_bank6Temp\n");
 			*status = -ENOMEM;
 			return false;
 		}
diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h
index 1470234..3a406a5 100644
--- a/drivers/net/wireless/ath9k/phy.h
+++ b/drivers/net/wireless/ath9k/phy.h
@@ -50,6 +50,9 @@
 #define AR_PHY_FC_SHORT_GI_40       0x00000080
 #define AR_PHY_FC_WALSH             0x00000100
 #define AR_PHY_FC_SINGLE_HT_LTF1    0x00000200
+#define AR_PHY_FC_ENABLE_DAC_FIFO   0x00000800
+
+#define AR_PHY_TEST2 		    0x9808
 
 #define AR_PHY_TIMING2           0x9810
 #define AR_PHY_TIMING3           0x9814
@@ -100,6 +103,8 @@
 #define AR_PHY_RF_CTL4_FRAME_XPAA_ON      0x000000FF
 #define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S    0
 
+#define AR_PHY_TSTDAC_CONST               0x983c
+
 #define AR_PHY_SETTLING          0x9844
 #define AR_PHY_SETTLING_SWITCH   0x00003F80
 #define AR_PHY_SETTLING_SWITCH_S 7
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
index cca2fc5..04ab457 100644
--- a/drivers/net/wireless/ath9k/rc.c
+++ b/drivers/net/wireless/ath9k/rc.c
@@ -15,143 +15,136 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/*
- * Atheros rate control algorithm
- */
-
 #include "core.h"
-/* FIXME: remove this include! */
-#include "../net/mac80211/rate.h"
-
-static u32 tx_triglevel_max;
 
 static struct ath_rate_table ar5416_11na_ratetable = {
 	42,
+	{0},
 	{
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
 			5400, 0x0b, 0x00, 12,
 			0, 2, 1, 0, 0, 0, 0, 0 },
-		{ TRUE,	TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+		{ VALID,	VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
 			7800,  0x0f, 0x00, 18,
 			0, 3, 1, 1, 1, 1, 1, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
 			10000, 0x0a, 0x00, 24,
 			2, 4, 2, 2, 2, 2, 2, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
 			13900, 0x0e, 0x00, 36,
 			2, 6,  2, 3, 3, 3, 3, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
 			17300, 0x09, 0x00, 48,
 			4, 10, 3, 4, 4, 4, 4, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
 			23000, 0x0d, 0x00, 72,
 			4, 14, 3, 5, 5, 5, 5, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
 			27400, 0x08, 0x00, 96,
 			4, 20, 3, 6, 6, 6, 6, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
 			29300, 0x0c, 0x00, 108,
 			4, 23, 3, 7, 7, 7, 7, 0 },
-		{ TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */
+		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
 			6400, 0x80, 0x00, 0,
 			0, 2, 3, 8, 24, 8, 24, 3216 },
-		{ TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */
+		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
 			12700, 0x81, 0x00, 1,
 			2, 4, 3, 9, 25, 9, 25, 6434 },
-		{ TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */
+		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
 			18800, 0x82, 0x00, 2,
 			2, 6, 3, 10, 26, 10, 26, 9650 },
-		{ TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */
+		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
 			25000, 0x83, 0x00, 3,
 			4, 10, 3, 11, 27, 11, 27, 12868 },
-		{ TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */
+		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
 			36700, 0x84, 0x00, 4,
 			4, 14, 3, 12, 28, 12, 28, 19304 },
-		{ FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */
+		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
 			48100, 0x85, 0x00, 5,
 			4, 20, 3, 13, 29, 13, 29, 25740 },
-		{ FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */
+		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
 			53500, 0x86, 0x00, 6,
 			4, 23, 3, 14, 30, 14, 30,  28956 },
-		{ FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */
+		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
 			59000, 0x87, 0x00, 7,
 			4, 25, 3, 15, 31, 15, 32, 32180 },
-		{ FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
 			12700, 0x88, 0x00,
 			8, 0, 2, 3, 16, 33, 16, 33, 6430 },
-		{ FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
 			24800, 0x89, 0x00, 9,
 			2, 4, 3, 17, 34, 17, 34, 12860 },
-		{ FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
 			36600, 0x8a, 0x00, 10,
 			2, 6, 3, 18, 35, 18, 35, 19300 },
-		{ TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */
+		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
 			48100, 0x8b, 0x00, 11,
 			4, 10, 3, 19, 36, 19, 36, 25736 },
-		{ TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */
+		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
 			69500, 0x8c, 0x00, 12,
 			4, 14, 3, 20, 37, 20, 37, 38600 },
-		{ TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */
+		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
 			89500, 0x8d, 0x00, 13,
 			4, 20, 3, 21, 38, 21, 38, 51472 },
-		{ TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */
+		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
 			98900, 0x8e, 0x00, 14,
 			4, 23, 3, 22, 39, 22, 39, 57890 },
-		{ TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */
+		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
 			108300, 0x8f, 0x00, 15,
 			4, 25, 3, 23, 40, 23, 41, 64320 },
-		{ TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */
+		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
 			13200, 0x80, 0x00, 0,
 			0, 2, 3, 8, 24, 24, 24, 6684 },
-		{ TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */
+		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
 			25900, 0x81, 0x00, 1,
 			2, 4, 3, 9, 25, 25, 25, 13368 },
-		{ TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */
+		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
 			38600, 0x82, 0x00, 2,
 			2, 6, 3, 10, 26, 26, 26, 20052 },
-		{ TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */
+		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
 			49800, 0x83, 0x00, 3,
 			4, 10, 3, 11, 27, 27, 27, 26738 },
-		{ TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */
+		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
 			72200, 0x84, 0x00, 4,
 			4, 14, 3, 12, 28, 28, 28, 40104 },
-		{ FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */
+		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
 			92900, 0x85, 0x00, 5,
 			4, 20, 3, 13, 29, 29, 29, 53476 },
-		{ FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */
+		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
 			102700, 0x86, 0x00, 6,
 			4, 23, 3, 14, 30, 30, 30, 60156 },
-		{ FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */
+		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
 			112000, 0x87, 0x00, 7,
 			4, 25, 3, 15, 31, 32, 32, 66840 },
-		{ FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
+		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
 			122000, 0x87, 0x00, 7,
 			4, 25, 3, 15, 31, 32, 32, 74200 },
-		{ FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
 			25800, 0x88, 0x00, 8,
 			0, 2, 3, 16, 33, 33, 33, 13360 },
-		{ FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
 			49800, 0x89, 0x00, 9,
 			2, 4, 3, 17, 34, 34, 34, 26720 },
-		{ FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
 			71900, 0x8a, 0x00, 10,
 			2, 6, 3, 18, 35, 35, 35, 40080 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
 			92500, 0x8b, 0x00, 11,
 			4, 10, 3, 19, 36, 36, 36, 53440 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
 			130300, 0x8c, 0x00, 12,
 			4, 14, 3, 20, 37, 37, 37, 80160 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
 			162800, 0x8d, 0x00, 13,
 			4, 20, 3, 21, 38, 38, 38, 106880 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
 			178200, 0x8e, 0x00, 14,
 			4, 23, 3, 22, 39, 39, 39, 120240 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
 			192100, 0x8f, 0x00, 15,
 			4, 25, 3, 23, 40, 41, 41, 133600 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
 			207000, 0x8f, 0x00, 15,
 			4, 25, 3, 23, 40, 41, 41, 148400 },
 	},
@@ -160,153 +153,149 @@
 	WLAN_RC_HT_FLAG,  /* Phy rates allowed initially */
 };
 
-/* TRUE_ALL - valid for 20/40/Legacy,
- * TRUE - Legacy only,
- * TRUE_20 - HT 20 only,
- * TRUE_40 - HT 40 only */
-
 /* 4ms frame limit not used for NG mode.  The values filled
  * for HT are the 64K max aggregate limit */
 
 static struct ath_rate_table ar5416_11ng_ratetable = {
 	46,
+	{0},
 	{
-		{ TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 1000, /* 1 Mb */
+		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
 			900, 0x1b, 0x00, 2,
 			0, 0, 1, 0, 0, 0, 0, 0 },
-		{ TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 2000, /* 2 Mb */
+		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
 			1900, 0x1a, 0x04, 4,
 			1, 1, 1, 1, 1, 1, 1, 0 },
-		{ TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
 			4900, 0x19, 0x04, 11,
 			2, 2, 2, 2, 2, 2, 2, 0 },
-		{ TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 11000, /* 11 Mb */
+		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
 			8100, 0x18, 0x04, 22,
 			3, 3, 2, 3, 3, 3, 3, 0 },
-		{ FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
 			5400, 0x0b, 0x00, 12,
 			4, 2, 1, 4, 4, 4, 4, 0 },
-		{ FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
 			7800, 0x0f, 0x00, 18,
 			4, 3, 1, 5, 5, 5, 5, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
 			10100, 0x0a, 0x00, 24,
 			6, 4, 1, 6, 6, 6, 6, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
 			14100,  0x0e, 0x00, 36,
 			6, 6, 2, 7, 7, 7, 7, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
 			17700, 0x09, 0x00, 48,
 			8, 10, 3, 8, 8, 8, 8, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
 			23700, 0x0d, 0x00, 72,
 			8, 14, 3, 9, 9, 9, 9, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
 			27400, 0x08, 0x00, 96,
 			8, 20, 3, 10, 10, 10, 10, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
 			30900, 0x0c, 0x00, 108,
 			8, 23, 3, 11, 11, 11, 11, 0 },
-		{ FALSE, FALSE, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
 			6400, 0x80, 0x00, 0,
 			4, 2, 3, 12, 28, 12, 28, 3216 },
-		{ TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */
+		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
 			12700, 0x81, 0x00, 1,
 			6, 4, 3, 13, 29, 13, 29, 6434 },
-		{ TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */
+		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
 			18800, 0x82, 0x00, 2,
 			6, 6, 3, 14, 30, 14, 30, 9650 },
-		{ TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */
+		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
 			25000, 0x83, 0x00, 3,
 			8, 10, 3, 15, 31, 15, 31, 12868 },
-		{ TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */
+		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
 			36700, 0x84, 0x00, 4,
 			8, 14, 3, 16, 32, 16, 32, 19304 },
-		{ FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */
+		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
 			48100, 0x85, 0x00, 5,
 			8, 20, 3, 17, 33, 17, 33, 25740 },
-		{ FALSE,  TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */
+		{ INVALID,  VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
 			53500, 0x86, 0x00, 6,
 			8, 23, 3, 18, 34, 18, 34, 28956 },
-		{ FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */
+		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
 			59000, 0x87, 0x00, 7,
 			8, 25, 3, 19, 35, 19, 36, 32180 },
-		{ FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
 			12700, 0x88, 0x00, 8,
 			4, 2, 3, 20, 37, 20, 37, 6430 },
-		{ FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
 			24800, 0x89, 0x00, 9,
 			6, 4, 3, 21, 38, 21, 38, 12860 },
-		{ FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
 			36600, 0x8a, 0x00, 10,
 			6, 6, 3, 22, 39, 22, 39, 19300 },
-		{ TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */
+		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
 			48100, 0x8b, 0x00, 11,
 			8, 10, 3, 23, 40, 23, 40, 25736 },
-		{ TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */
+		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
 			69500, 0x8c, 0x00, 12,
 			8, 14, 3, 24, 41, 24, 41, 38600 },
-		{ TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */
+		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
 			89500, 0x8d, 0x00, 13,
 			8, 20, 3, 25, 42, 25, 42, 51472 },
-		{ TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */
+		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
 			98900, 0x8e, 0x00, 14,
 			8, 23, 3, 26, 43, 26, 44, 57890 },
-		{ TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */
+		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
 			108300, 0x8f, 0x00, 15,
 			8, 25, 3, 27, 44, 27, 45, 64320 },
-		{ TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */
+		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
 			13200, 0x80, 0x00, 0,
 			8, 2, 3, 12, 28, 28, 28, 6684 },
-		{ TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */
+		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
 			25900, 0x81, 0x00, 1,
 			8, 4, 3, 13, 29, 29, 29, 13368 },
-		{ TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */
+		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
 			38600, 0x82, 0x00, 2,
 			8, 6, 3, 14, 30, 30, 30, 20052 },
-		{ TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */
+		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
 			49800, 0x83, 0x00, 3,
 			8, 10, 3, 15, 31, 31, 31, 26738 },
-		{ TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */
+		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
 			72200, 0x84, 0x00, 4,
 			8, 14, 3, 16, 32, 32, 32, 40104 },
-		{ FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */
+		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
 			92900, 0x85, 0x00, 5,
 			8, 20, 3, 17, 33, 33, 33, 53476 },
-		{ FALSE,  TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */
+		{ INVALID,  VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
 			102700, 0x86, 0x00, 6,
 			8, 23, 3, 18, 34, 34, 34, 60156 },
-		{ FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */
+		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
 			112000, 0x87, 0x00, 7,
 			8, 23, 3, 19, 35, 36, 36, 66840 },
-		{ FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
+		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
 			122000, 0x87, 0x00, 7,
 			8, 25, 3, 19, 35, 36, 36, 74200 },
-		{ FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
 			25800, 0x88, 0x00, 8,
 			8, 2, 3, 20, 37, 37, 37, 13360 },
-		{ FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
 			49800, 0x89, 0x00, 9,
 			8, 4, 3, 21, 38, 38, 38, 26720 },
-		{ FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
 			71900, 0x8a, 0x00, 10,
 			8, 6, 3, 22, 39, 39, 39, 40080 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
 			92500, 0x8b, 0x00, 11,
 			8, 10, 3, 23, 40, 40, 40, 53440 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
 			130300, 0x8c, 0x00, 12,
 			8, 14, 3, 24, 41, 41, 41, 80160 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
 			162800, 0x8d, 0x00, 13,
 			8, 20, 3, 25, 42, 42, 42, 106880 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
 			178200, 0x8e, 0x00, 14,
 			8, 23, 3, 26, 43, 43, 43, 120240 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
 			192100, 0x8f, 0x00, 15,
 			8, 23, 3, 27, 44, 45, 45, 133600 },
-		{ TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
+		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
 			207000, 0x8f, 0x00, 15,
 			8, 25, 3, 27, 44, 45, 45, 148400 },
 		},
@@ -317,29 +306,30 @@
 
 static struct ath_rate_table ar5416_11a_ratetable = {
 	8,
+	{0},
 	{
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
 			5400, 0x0b, 0x00, (0x80|12),
 			0, 2, 1, 0, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
 			7800, 0x0f, 0x00, 18,
 			0, 3, 1, 1, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
 			10000, 0x0a, 0x00, (0x80|24),
 			2, 4, 2, 2, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
 			13900, 0x0e, 0x00, 36,
 			2, 6, 2, 3, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
 			17300, 0x09, 0x00, (0x80|48),
 			4, 10, 3, 4, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
 			23000, 0x0d, 0x00, 72,
 			4, 14, 3, 5, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
 			27400, 0x08, 0x00, 96,
 			4, 19, 3, 6, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
 			29300, 0x0c, 0x00, 108,
 			4, 23, 3, 7, 0 },
 	},
@@ -348,109 +338,44 @@
 	0,   /* Phy rates allowed initially */
 };
 
-static struct ath_rate_table ar5416_11a_ratetable_Half = {
-	8,
-	{
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 6 Mb */
-			2700, 0x0b, 0x00, (0x80|6),
-			0, 2,  1, 0, 0},
-		{ TRUE, TRUE,  WLAN_PHY_OFDM, 4500, /* 9 Mb */
-			3900, 0x0f, 0x00, 9,
-			0, 3, 1, 1, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 12 Mb */
-			5000, 0x0a, 0x00, (0x80|12),
-			2, 4, 2, 2, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 18 Mb */
-			6950, 0x0e, 0x00, 18,
-			2, 6, 2, 3, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 24 Mb */
-			8650, 0x09, 0x00, (0x80|24),
-			4, 10, 3, 4, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 36 Mb */
-			11500, 0x0d, 0x00, 36,
-			4, 14, 3, 5, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 48 Mb */
-			13700, 0x08, 0x00, 48,
-			4, 19, 3, 6, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 27000, /* 54 Mb */
-			14650, 0x0c, 0x00, 54,
-			4, 23, 3, 7, 0 },
-	},
-	50,  /* probe interval */
-	50,  /* rssi reduce interval */
-	0,   /* Phy rates allowed initially */
-};
-
-static struct ath_rate_table ar5416_11a_ratetable_Quarter = {
-	8,
-	{
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 1500, /* 6 Mb */
-			1350, 0x0b, 0x00, (0x80|3),
-			0, 2, 1, 0, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 2250, /* 9 Mb */
-			1950, 0x0f, 0x00, 4,
-			0, 3, 1, 1, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 12 Mb */
-			2500, 0x0a, 0x00, (0x80|6),
-			2, 4, 2, 2, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 18 Mb */
-			3475, 0x0e, 0x00, 9,
-			2, 6, 2, 3, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 25 Mb */
-			4325, 0x09, 0x00, (0x80|12),
-			4, 10, 3, 4, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 36 Mb */
-			5750, 0x0d, 0x00, 18,
-			4, 14, 3, 5, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 48 Mb */
-			6850, 0x08, 0x00, 24,
-			4, 19, 3, 6, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 13500, /* 54 Mb */
-			7325, 0x0c, 0x00, 27,
-			4, 23, 3, 7, 0 },
-	},
-	50,  /* probe interval */
-	50,  /* rssi reduce interval */
-	0,   /* Phy rates allowed initially */
-};
-
 static struct ath_rate_table ar5416_11g_ratetable = {
 	12,
+	{0},
 	{
-		{ TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
 			900, 0x1b, 0x00, 2,
 			0, 0, 1, 0, 0 },
-		{ TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
 			1900, 0x1a, 0x04, 4,
 			1, 1, 1, 1, 0 },
-		{ TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
 			4900, 0x19, 0x04, 11,
 			2, 2, 2, 2, 0 },
-		{ TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
 			8100, 0x18, 0x04, 22,
 			3, 3, 2, 3, 0 },
-		{ FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
 			5400, 0x0b, 0x00, 12,
 			4, 2, 1, 4, 0 },
-		{ FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
 			7800, 0x0f, 0x00, 18,
 			4, 3, 1, 5, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
 			10000, 0x0a, 0x00, 24,
 			6, 4, 1, 6, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
 			13900, 0x0e, 0x00, 36,
 			6, 6, 2, 7, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
 			17300, 0x09, 0x00, 48,
 			8, 10, 3, 8, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
 			23000, 0x0d, 0x00, 72,
 			8, 14, 3, 9, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
 			27400, 0x08, 0x00, 96,
 			8, 19, 3, 10, 0 },
-		{ TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
 			29300, 0x0c, 0x00, 108,
 			8, 23, 3, 11, 0 },
 	},
@@ -461,17 +386,18 @@
 
 static struct ath_rate_table ar5416_11b_ratetable = {
 	4,
+	{0},
 	{
-		{ TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
 			900, 0x1b,  0x00, (0x80|2),
 			0, 0, 1, 0, 0 },
-		{ TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
 			1800, 0x1a, 0x04, (0x80|4),
 			1, 1, 1, 1, 0 },
-		{ TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
 			4300, 0x19, 0x04, (0x80|11),
 			1, 2, 2, 2, 0 },
-		{ TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */
+		{ VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
 			7100, 0x18, 0x04, (0x80|22),
 			1, 4, 100, 3, 0 },
 	},
@@ -480,48 +406,6 @@
 	0,   /* Phy rates allowed initially */
 };
 
-static void ar5416_attach_ratetables(struct ath_rate_softc *sc)
-{
-	/*
-	 * Attach rate tables.
-	 */
-	sc->hw_rate_table[ATH9K_MODE_11B] = &ar5416_11b_ratetable;
-	sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable;
-	sc->hw_rate_table[ATH9K_MODE_11G] = &ar5416_11g_ratetable;
-
-	sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable;
-	sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable;
-	sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] =
-		&ar5416_11na_ratetable;
-	sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] =
-		&ar5416_11na_ratetable;
-	sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] =
-		&ar5416_11ng_ratetable;
-	sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] =
-		&ar5416_11ng_ratetable;
-}
-
-static void ar5416_setquarter_ratetable(struct ath_rate_softc *sc)
-{
-	sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Quarter;
-	return;
-}
-
-static void ar5416_sethalf_ratetable(struct ath_rate_softc *sc)
-{
-	sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Half;
-	return;
-}
-
-static void ar5416_setfull_ratetable(struct ath_rate_softc *sc)
-{
-	sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable;
-	return;
-}
-
-/*
- * Return the median of three numbers
- */
 static inline int8_t median(int8_t a, int8_t b, int8_t c)
 {
 	if (a >= b) {
@@ -541,68 +425,65 @@
 	}
 }
 
-static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table,
-				   struct ath_tx_ratectrl *rate_ctrl)
+static void ath_rc_sort_validrates(struct ath_rate_table *rate_table,
+				   struct ath_rate_priv *ath_rc_priv)
 {
 	u8 i, j, idx, idx_next;
 
-	for (i = rate_ctrl->max_valid_rate - 1; i > 0; i--) {
+	for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) {
 		for (j = 0; j <= i-1; j++) {
-			idx = rate_ctrl->valid_rate_index[j];
-			idx_next = rate_ctrl->valid_rate_index[j+1];
+			idx = ath_rc_priv->valid_rate_index[j];
+			idx_next = ath_rc_priv->valid_rate_index[j+1];
 
 			if (rate_table->info[idx].ratekbps >
 				rate_table->info[idx_next].ratekbps) {
-				rate_ctrl->valid_rate_index[j] = idx_next;
-				rate_ctrl->valid_rate_index[j+1] = idx;
+				ath_rc_priv->valid_rate_index[j] = idx_next;
+				ath_rc_priv->valid_rate_index[j+1] = idx;
 			}
 		}
 	}
 }
 
-/* Access functions for valid_txrate_mask */
-
-static void ath_rc_init_valid_txmask(struct ath_tx_ratectrl *rate_ctrl)
+static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv)
 {
 	u8 i;
 
-	for (i = 0; i < rate_ctrl->rate_table_size; i++)
-		rate_ctrl->valid_rate_index[i] = FALSE;
+	for (i = 0; i < ath_rc_priv->rate_table_size; i++)
+		ath_rc_priv->valid_rate_index[i] = 0;
 }
 
-static inline void ath_rc_set_valid_txmask(struct ath_tx_ratectrl *rate_ctrl,
+static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
 					   u8 index, int valid_tx_rate)
 {
-	ASSERT(index <= rate_ctrl->rate_table_size);
-	rate_ctrl->valid_rate_index[index] = valid_tx_rate ? TRUE : FALSE;
+	ASSERT(index <= ath_rc_priv->rate_table_size);
+	ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
 }
 
-static inline int ath_rc_isvalid_txmask(struct ath_tx_ratectrl *rate_ctrl,
+static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv,
 					u8 index)
 {
-	ASSERT(index <= rate_ctrl->rate_table_size);
-	return rate_ctrl->valid_rate_index[index];
+	ASSERT(index <= ath_rc_priv->rate_table_size);
+	return ath_rc_priv->valid_rate_index[index];
 }
 
-/* Iterators for valid_txrate_mask */
-static inline int
-ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
-			    struct ath_tx_ratectrl *rate_ctrl,
-			    u8 cur_valid_txrate,
-			    u8 *next_idx)
+static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table,
+					      struct ath_rate_priv *ath_rc_priv,
+					      u8 cur_valid_txrate,
+					      u8 *next_idx)
 {
 	u8 i;
 
-	for (i = 0; i < rate_ctrl->max_valid_rate - 1; i++) {
-		if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) {
-			*next_idx = rate_ctrl->valid_rate_index[i+1];
-			return TRUE;
+	for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) {
+		if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) {
+			*next_idx = ath_rc_priv->valid_rate_index[i+1];
+			return 1;
 		}
 	}
 
 	/* No more valid rates */
 	*next_idx = 0;
-	return FALSE;
+
+	return 0;
 }
 
 /* Return true only for single stream */
@@ -610,83 +491,72 @@
 static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
 {
 	if (WLAN_RC_PHY_HT(phy) & !(capflag & WLAN_RC_HT_FLAG))
-		return FALSE;
+		return 0;
 	if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG))
-		return FALSE;
+		return 0;
 	if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG))
-		return FALSE;
+		return 0;
 	if (!ignore_cw && WLAN_RC_PHY_HT(phy))
 		if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG))
-			return FALSE;
+			return 0;
 		if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG))
-			return FALSE;
-	return TRUE;
+			return 0;
+	return 1;
 }
 
 static inline int
-ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table,
-				 struct ath_tx_ratectrl *rate_ctrl,
+ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table,
+				 struct ath_rate_priv *ath_rc_priv,
 				 u8 cur_valid_txrate, u8 *next_idx)
 {
 	int8_t i;
 
-	for (i = 1; i < rate_ctrl->max_valid_rate ; i++) {
-		if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) {
-			*next_idx = rate_ctrl->valid_rate_index[i-1];
-			return TRUE;
+	for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) {
+		if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) {
+			*next_idx = ath_rc_priv->valid_rate_index[i-1];
+			return 1;
 		}
 	}
-	return FALSE;
+
+	return 0;
 }
 
-/*
- * Initialize the Valid Rate Index from valid entries in Rate Table
- */
-static u8
-ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv,
-			   const struct ath_rate_table *rate_table,
-			   u32 capflag)
+static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
+				 struct ath_rate_table *rate_table,
+				 u32 capflag)
 {
-	struct ath_tx_ratectrl *rate_ctrl;
 	u8 i, hi = 0;
 	u32 valid;
 
-	rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
 	for (i = 0; i < rate_table->rate_cnt; i++) {
 		valid = (ath_rc_priv->single_stream ?
 			 rate_table->info[i].valid_single_stream :
 			 rate_table->info[i].valid);
-		if (valid == TRUE) {
+		if (valid == 1) {
 			u32 phy = rate_table->info[i].phy;
 			u8 valid_rate_count = 0;
 
-			if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+			if (!ath_rc_valid_phyrate(phy, capflag, 0))
 				continue;
 
-			valid_rate_count = rate_ctrl->valid_phy_ratecnt[phy];
+			valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy];
 
-			rate_ctrl->valid_phy_rateidx[phy][valid_rate_count] = i;
-			rate_ctrl->valid_phy_ratecnt[phy] += 1;
-			ath_rc_set_valid_txmask(rate_ctrl, i, TRUE);
+			ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i;
+			ath_rc_priv->valid_phy_ratecnt[phy] += 1;
+			ath_rc_set_valid_txmask(ath_rc_priv, i, 1);
 			hi = A_MAX(hi, i);
 		}
 	}
+
 	return hi;
 }
 
-/*
- * Initialize the Valid Rate Index from Rate Set
- */
-static u8
-ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv,
-			  const struct ath_rate_table *rate_table,
-			  struct ath_rateset *rateset,
-			  u32 capflag)
+static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
+				struct ath_rate_table *rate_table,
+				struct ath_rateset *rateset,
+				u32 capflag)
 {
-	/* XXX: Clean me up and make identation friendly */
 	u8 i, j, hi = 0;
-	struct ath_tx_ratectrl *rate_ctrl =
-		(struct ath_tx_ratectrl *)(ath_rc_priv);
 
 	/* Use intersection of working rates and valid rates */
 	for (i = 0; i < rateset->rs_nrates; i++) {
@@ -695,196 +565,89 @@
 			u32 valid = (ath_rc_priv->single_stream ?
 				rate_table->info[j].valid_single_stream :
 				rate_table->info[j].valid);
+			u8 rate = rateset->rs_rates[i];
+			u8 dot11rate = rate_table->info[j].dot11rate;
 
 			/* We allow a rate only if its valid and the
 			 * capflag matches one of the validity
-			 * (TRUE/TRUE_20/TRUE_40) flags */
+			 * (VALID/VALID_20/VALID_40) flags */
 
-			/* XXX: catch the negative of this branch
-			 * first and then continue */
-			if (((rateset->rs_rates[i] & 0x7F) ==
-				(rate_table->info[j].dot11rate & 0x7F)) &&
-				((valid & WLAN_RC_CAP_MODE(capflag)) ==
-				WLAN_RC_CAP_MODE(capflag)) &&
-				!WLAN_RC_PHY_HT(phy)) {
-
+			if (((rate & 0x7F) == (dot11rate & 0x7F)) &&
+			    ((valid & WLAN_RC_CAP_MODE(capflag)) ==
+			     WLAN_RC_CAP_MODE(capflag)) &&
+			    !WLAN_RC_PHY_HT(phy)) {
 				u8 valid_rate_count = 0;
 
-				if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+				if (!ath_rc_valid_phyrate(phy, capflag, 0))
 					continue;
 
 				valid_rate_count =
-					rate_ctrl->valid_phy_ratecnt[phy];
+					ath_rc_priv->valid_phy_ratecnt[phy];
 
-				rate_ctrl->valid_phy_rateidx[phy]
+				ath_rc_priv->valid_phy_rateidx[phy]
 					[valid_rate_count] = j;
-				rate_ctrl->valid_phy_ratecnt[phy] += 1;
-				ath_rc_set_valid_txmask(rate_ctrl, j, TRUE);
+				ath_rc_priv->valid_phy_ratecnt[phy] += 1;
+				ath_rc_set_valid_txmask(ath_rc_priv, j, 1);
 				hi = A_MAX(hi, j);
 			}
 		}
 	}
+
 	return hi;
 }
 
-static u8
-ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv,
-			    const struct ath_rate_table *rate_table,
-			    u8 *mcs_set, u32 capflag)
+static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
+				  struct ath_rate_table *rate_table,
+				  u8 *mcs_set, u32 capflag)
 {
+	struct ath_rateset *rateset = (struct ath_rateset *)mcs_set;
+
 	u8 i, j, hi = 0;
-	struct ath_tx_ratectrl *rate_ctrl =
-		(struct ath_tx_ratectrl *)(ath_rc_priv);
 
 	/* Use intersection of working rates and valid rates */
-	for (i = 0; i <  ((struct ath_rateset *)mcs_set)->rs_nrates; i++) {
+	for (i = 0; i < rateset->rs_nrates; i++) {
 		for (j = 0; j < rate_table->rate_cnt; j++) {
 			u32 phy = rate_table->info[j].phy;
 			u32 valid = (ath_rc_priv->single_stream ?
 				     rate_table->info[j].valid_single_stream :
 				     rate_table->info[j].valid);
+			u8 rate = rateset->rs_rates[i];
+			u8 dot11rate = rate_table->info[j].dot11rate;
 
-			if (((((struct ath_rateset *)
-			       mcs_set)->rs_rates[i] & 0x7F) !=
-			     (rate_table->info[j].dot11rate & 0x7F)) ||
+			if (((rate & 0x7F) != (dot11rate & 0x7F)) ||
 			    !WLAN_RC_PHY_HT(phy) ||
 			    !WLAN_RC_PHY_HT_VALID(valid, capflag))
 				continue;
 
-			if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+			if (!ath_rc_valid_phyrate(phy, capflag, 0))
 				continue;
 
-			rate_ctrl->valid_phy_rateidx[phy]
-				[rate_ctrl->valid_phy_ratecnt[phy]] = j;
-			rate_ctrl->valid_phy_ratecnt[phy] += 1;
-			ath_rc_set_valid_txmask(rate_ctrl, j, TRUE);
+			ath_rc_priv->valid_phy_rateidx[phy]
+				[ath_rc_priv->valid_phy_ratecnt[phy]] = j;
+			ath_rc_priv->valid_phy_ratecnt[phy] += 1;
+			ath_rc_set_valid_txmask(ath_rc_priv, j, 1);
 			hi = A_MAX(hi, j);
 		}
 	}
+
 	return hi;
 }
 
-/*
- * Attach to a device instance.  Setup the public definition
- * of how much per-node space we need and setup the private
- * phy tables that have rate control parameters.
- */
-struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah)
-{
-	struct ath_rate_softc *asc;
-
-	/* we are only in user context so we can sleep for memory */
-	asc = kzalloc(sizeof(struct ath_rate_softc), GFP_KERNEL);
-	if (asc == NULL)
-		return NULL;
-
-	ar5416_attach_ratetables(asc);
-
-	/* Save Maximum TX Trigger Level (used for 11n) */
-	tx_triglevel_max = ah->ah_caps.tx_triglevel_max;
-	/*  return alias for ath_rate_softc * */
-	return asc;
-}
-
-static struct ath_rate_node *ath_rate_node_alloc(struct ath_vap *avp,
-						 struct ath_rate_softc *rsc,
-						 gfp_t gfp)
-{
-	struct ath_rate_node *anode;
-
-	anode = kzalloc(sizeof(struct ath_rate_node), gfp);
-	if (anode == NULL)
-		return NULL;
-
-	anode->avp = avp;
-	anode->asc = rsc;
-	avp->rc_node = anode;
-
-	return anode;
-}
-
-static void ath_rate_node_free(struct ath_rate_node *anode)
-{
-	if (anode != NULL)
-		kfree(anode);
-}
-
-void ath_rate_detach(struct ath_rate_softc *asc)
-{
-	if (asc != NULL)
-		kfree(asc);
-}
-
-u8 ath_rate_findrateix(struct ath_softc *sc,
-			     u8 dot11rate)
-{
-	const struct ath_rate_table *ratetable;
-	struct ath_rate_softc *rsc = sc->sc_rc;
-	int i;
-
-	ratetable = rsc->hw_rate_table[sc->sc_curmode];
-
-	if (WARN_ON(!ratetable))
-		return 0;
-
-	for (i = 0; i < ratetable->rate_cnt; i++) {
-		if ((ratetable->info[i].dot11rate & 0x7f) == (dot11rate & 0x7f))
-			return i;
-	}
-
-	return 0;
-}
-
-/*
- * Update rate-control state on a device state change.  When
- * operating as a station this includes associate/reassociate
- * with an AP.  Otherwise this gets called, for example, when
- * the we transition to run state when operating as an AP.
- */
-void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp)
-{
-	struct ath_rate_softc *asc = sc->sc_rc;
-
-	/* For half and quarter rate channles use different
-	 * rate tables
-	 */
-	if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_HALF)
-		ar5416_sethalf_ratetable(asc);
-	else if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_QUARTER)
-		ar5416_setquarter_ratetable(asc);
-	else /* full rate */
-		ar5416_setfull_ratetable(asc);
-
-	if (avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) {
-		asc->fixedrix =
-			sc->sc_rixmap[avp->av_config.av_fixed_rateset & 0xff];
-		/* NB: check the fixed rate exists */
-		if (asc->fixedrix == 0xff)
-			asc->fixedrix = IEEE80211_FIXED_RATE_NONE;
-	} else {
-		asc->fixedrix = IEEE80211_FIXED_RATE_NONE;
-	}
-}
-
 static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
-			     struct ath_rate_node *ath_rc_priv,
-			     const struct ath_rate_table *rate_table,
+			     struct ath_rate_priv *ath_rc_priv,
+			     struct ath_rate_table *rate_table,
 			     int probe_allowed, int *is_probing,
 			     int is_retry)
 {
 	u32 dt, best_thruput, this_thruput, now_msec;
 	u8 rate, next_rate, best_rate, maxindex, minindex;
 	int8_t  rssi_last, rssi_reduce = 0, index = 0;
-	struct ath_tx_ratectrl  *rate_ctrl = NULL;
 
-	rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv ?
-					       (ath_rc_priv) : NULL);
+	*is_probing = 0;
 
-	*is_probing = FALSE;
-
-	rssi_last = median(rate_ctrl->rssi_last,
-			   rate_ctrl->rssi_last_prev,
-			   rate_ctrl->rssi_last_prev2);
+	rssi_last = median(ath_rc_priv->rssi_last,
+			   ath_rc_priv->rssi_last_prev,
+			   ath_rc_priv->rssi_last_prev2);
 
 	/*
 	 * Age (reduce) last ack rssi based on how old it is.
@@ -896,7 +659,7 @@
 	 */
 
 	now_msec = jiffies_to_msecs(jiffies);
-	dt = now_msec - rate_ctrl->rssi_time;
+	dt = now_msec - ath_rc_priv->rssi_time;
 
 	if (dt >= 185)
 		rssi_reduce = 10;
@@ -915,7 +678,7 @@
 	 */
 
 	best_thruput = 0;
-	maxindex = rate_ctrl->max_valid_rate-1;
+	maxindex = ath_rc_priv->max_valid_rate-1;
 
 	minindex = 0;
 	best_rate = minindex;
@@ -927,8 +690,8 @@
 	for (index = maxindex; index >= minindex ; index--) {
 		u8 per_thres;
 
-		rate = rate_ctrl->valid_rate_index[index];
-		if (rate > rate_ctrl->rate_max_phy)
+		rate = ath_rc_priv->valid_rate_index[index];
+		if (rate > ath_rc_priv->rate_max_phy)
 			continue;
 
 		/*
@@ -942,7 +705,7 @@
 		 * 10-15 and we would be worse off then staying
 		 * at the current rate.
 		 */
-		per_thres = rate_ctrl->state[rate].per;
+		per_thres = ath_rc_priv->state[rate].per;
 		if (per_thres < 12)
 			per_thres = 12;
 
@@ -961,41 +724,35 @@
 	 * of max retries, use the min rate for the next retry
 	 */
 	if (is_retry)
-		rate = rate_ctrl->valid_rate_index[minindex];
+		rate = ath_rc_priv->valid_rate_index[minindex];
 
-	rate_ctrl->rssi_last_lookup = rssi_last;
+	ath_rc_priv->rssi_last_lookup = rssi_last;
 
 	/*
 	 * Must check the actual rate (ratekbps) to account for
 	 * non-monoticity of 11g's rate table
 	 */
 
-	if (rate >= rate_ctrl->rate_max_phy && probe_allowed) {
-		rate = rate_ctrl->rate_max_phy;
+	if (rate >= ath_rc_priv->rate_max_phy && probe_allowed) {
+		rate = ath_rc_priv->rate_max_phy;
 
 		/* Probe the next allowed phy state */
 		/* FIXME:XXXX Check to make sure ratMax is checked properly */
 		if (ath_rc_get_nextvalid_txrate(rate_table,
-						rate_ctrl, rate, &next_rate) &&
-		    (now_msec - rate_ctrl->probe_time >
+						ath_rc_priv, rate, &next_rate) &&
+		    (now_msec - ath_rc_priv->probe_time >
 		     rate_table->probe_interval) &&
-		    (rate_ctrl->hw_maxretry_pktcnt >= 1)) {
+		    (ath_rc_priv->hw_maxretry_pktcnt >= 1)) {
 			rate = next_rate;
-			rate_ctrl->probe_rate = rate;
-			rate_ctrl->probe_time = now_msec;
-			rate_ctrl->hw_maxretry_pktcnt = 0;
-			*is_probing = TRUE;
+			ath_rc_priv->probe_rate = rate;
+			ath_rc_priv->probe_time = now_msec;
+			ath_rc_priv->hw_maxretry_pktcnt = 0;
+			*is_probing = 1;
 		}
 	}
 
-	/*
-	 * Make sure rate is not higher than the allowed maximum.
-	 * We should also enforce the min, but I suspect the min is
-	 * normally 1 rather than 0 because of the rate 9 vs 6 issue
-	 * in the old code.
-	 */
-	if (rate > (rate_ctrl->rate_table_size - 1))
-		rate = rate_ctrl->rate_table_size - 1;
+	if (rate > (ath_rc_priv->rate_table_size - 1))
+		rate = ath_rc_priv->rate_table_size - 1;
 
 	ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) ||
 	       (rate_table->info[rate].valid_single_stream &&
@@ -1004,40 +761,36 @@
 	return rate;
 }
 
-static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table ,
-				   struct ath_rc_series *series,
-				   u8 tries,
-				   u8 rix,
-				   int rtsctsenable)
+static void ath_rc_rate_set_series(struct ath_rate_table *rate_table ,
+				   struct ieee80211_tx_rate *rate,
+				   u8 tries, u8 rix, int rtsctsenable)
 {
-	series->tries = tries;
-	series->flags = (rtsctsenable ? ATH_RC_RTSCTS_FLAG : 0) |
-		(WLAN_RC_PHY_DS(rate_table->info[rix].phy) ?
-		 ATH_RC_DS_FLAG : 0) |
-		(WLAN_RC_PHY_40(rate_table->info[rix].phy) ?
-		 ATH_RC_CW40_FLAG : 0) |
-		(WLAN_RC_PHY_SGI(rate_table->info[rix].phy) ?
-		 ATH_RC_SGI_FLAG : 0);
+	rate->count = tries;
+	rate->idx = rix;
 
-	series->rix = rate_table->info[rix].base_index;
-	series->max_4ms_framelen = rate_table->info[rix].max_4ms_framelen;
+	if (rtsctsenable)
+		rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
+	if (WLAN_RC_PHY_40(rate_table->info[rix].phy))
+		rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+	if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy))
+		rate->flags |= IEEE80211_TX_RC_SHORT_GI;
+	if (WLAN_RC_PHY_HT(rate_table->info[rix].phy))
+		rate->flags |= IEEE80211_TX_RC_MCS;
 }
 
 static u8 ath_rc_rate_getidx(struct ath_softc *sc,
-			     struct ath_rate_node *ath_rc_priv,
-			     const struct ath_rate_table *rate_table,
+			     struct ath_rate_priv *ath_rc_priv,
+			     struct ath_rate_table *rate_table,
 			     u8 rix, u16 stepdown,
 			     u16 min_rate)
 {
 	u32 j;
 	u8 nextindex;
-	struct ath_tx_ratectrl *rate_ctrl =
-		(struct ath_tx_ratectrl *)(ath_rc_priv);
 
 	if (min_rate) {
 		for (j = RATE_TABLE_SIZE; j > 0; j--) {
 			if (ath_rc_get_nextlowervalid_txrate(rate_table,
-						rate_ctrl, rix, &nextindex))
+						ath_rc_priv, rix, &nextindex))
 				rix = nextindex;
 			else
 				break;
@@ -1045,7 +798,7 @@
 	} else {
 		for (j = stepdown; j > 0; j--) {
 			if (ath_rc_get_nextlowervalid_txrate(rate_table,
-						rate_ctrl, rix, &nextindex))
+						ath_rc_priv, rix, &nextindex))
 				rix = nextindex;
 			else
 				break;
@@ -1055,41 +808,39 @@
 }
 
 static void ath_rc_ratefind(struct ath_softc *sc,
-			    struct ath_rate_node *ath_rc_priv,
-			    int num_tries, int num_rates, unsigned int rcflag,
-			    struct ath_rc_series series[], int *is_probe,
+			    struct ath_rate_priv *ath_rc_priv,
+			    int num_tries, int num_rates,
+			    struct ieee80211_tx_info *tx_info, int *is_probe,
 			    int is_retry)
 {
 	u8 try_per_rate = 0, i = 0, rix, nrix;
-	struct ath_rate_softc  *asc = (struct ath_rate_softc *)sc->sc_rc;
 	struct ath_rate_table *rate_table;
+	struct ieee80211_tx_rate *rates = tx_info->control.rates;
 
-	rate_table =
-		(struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
-	rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table,
-				 (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0,
+	rate_table = sc->cur_rate_table;
+	rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, 1,
 				 is_probe, is_retry);
 	nrix = rix;
 
-	if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*is_probe)) {
+	if (*is_probe) {
 		/* set one try for probe rates. For the
 		 * probes don't enable rts */
 		ath_rc_rate_set_series(rate_table,
-			&series[i++], 1, nrix, FALSE);
+			&rates[i++], 1, nrix, 0);
 
 		try_per_rate = (num_tries/num_rates);
 		/* Get the next tried/allowed rate. No RTS for the next series
 		 * after the probe rate
 		 */
 		nrix = ath_rc_rate_getidx(sc,
-			ath_rc_priv, rate_table, nrix, 1, FALSE);
+			ath_rc_priv, rate_table, nrix, 1, 0);
 		ath_rc_rate_set_series(rate_table,
-			&series[i++], try_per_rate, nrix, 0);
+			&rates[i++], try_per_rate, nrix, 0);
 	} else {
 		try_per_rate = (num_tries/num_rates);
 		/* Set the choosen rate. No RTS for first series entry. */
 		ath_rc_rate_set_series(rate_table,
-			&series[i++], try_per_rate, nrix, FALSE);
+			&rates[i++], try_per_rate, nrix, 0);
 	}
 
 	/* Fill in the other rates for multirate retry */
@@ -1099,14 +850,13 @@
 
 		try_num = ((i + 1) == num_rates) ?
 			num_tries - (try_per_rate * i) : try_per_rate ;
-		min_rate = (((i + 1) == num_rates) &&
-			    (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0;
+		min_rate = (((i + 1) == num_rates) && 0);
 
 		nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
 					  rate_table, nrix, 1, min_rate);
 		/* All other rates in the series have RTS enabled */
 		ath_rc_rate_set_series(rate_table,
-				       &series[i], try_num, nrix, TRUE);
+				       &rates[i], try_num, nrix, 1);
 	}
 
 	/*
@@ -1124,115 +874,29 @@
 	 * So, set fourth rate in series to be same as third one for
 	 * above conditions.
 	 */
-	if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) ||
-	    (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) ||
-	    (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) {
-		u8  dot11rate = rate_table->info[rix].dot11rate;
+	if ((sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ) &&
+	    (sc->hw->conf.ht.enabled)) {
+		u8 dot11rate = rate_table->info[rix].dot11rate;
 		u8 phy = rate_table->info[rix].phy;
 		if (i == 4 &&
 		    ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) ||
 		     (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) {
-			series[3].rix = series[2].rix;
-			series[3].flags = series[2].flags;
-			series[3].max_4ms_framelen = series[2].max_4ms_framelen;
+			rates[3].idx = rates[2].idx;
+			rates[3].flags = rates[2].flags;
 		}
 	}
 }
 
-/*
- * Return the Tx rate series.
- */
-static void ath_rate_findrate(struct ath_softc *sc,
-			      struct ath_rate_node *ath_rc_priv,
-			      int num_tries,
-			      int num_rates,
-			      unsigned int rcflag,
-			      struct ath_rc_series series[],
-			      int *is_probe,
-			      int is_retry)
+static bool ath_rc_update_per(struct ath_softc *sc,
+			      struct ath_rate_table *rate_table,
+			      struct ath_rate_priv *ath_rc_priv,
+			      struct ath_tx_info_priv *tx_info_priv,
+			      int tx_rate, int xretries, int retries,
+			      u32 now_msec)
 {
-	struct ath_vap *avp = ath_rc_priv->avp;
-
-	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
-
-	if (!num_rates || !num_tries)
-		return;
-
-	if (avp->av_config.av_fixed_rateset == IEEE80211_FIXED_RATE_NONE) {
-		ath_rc_ratefind(sc, ath_rc_priv, num_tries, num_rates,
-				rcflag, series, is_probe, is_retry);
-	} else {
-		/* Fixed rate */
-		int idx;
-		u8 flags;
-		u32 rix;
-		struct ath_rate_softc *asc = ath_rc_priv->asc;
-		struct ath_rate_table *rate_table;
-
-		rate_table = (struct ath_rate_table *)
-			asc->hw_rate_table[sc->sc_curmode];
-
-		for (idx = 0; idx < 4; idx++) {
-			unsigned int    mcs;
-			u8 series_rix = 0;
-
-			series[idx].tries = IEEE80211_RATE_IDX_ENTRY(
-				avp->av_config.av_fixed_retryset, idx);
-
-			mcs = IEEE80211_RATE_IDX_ENTRY(
-				avp->av_config.av_fixed_rateset, idx);
-
-			if (idx == 3 && (mcs & 0xf0) == 0x70)
-				mcs = (mcs & ~0xf0)|0x80;
-
-			if (!(mcs & 0x80))
-				flags = 0;
-			else
-				flags = ((ath_rc_priv->ht_cap &
-						WLAN_RC_DS_FLAG) ?
-						ATH_RC_DS_FLAG : 0) |
-					((ath_rc_priv->ht_cap &
-						WLAN_RC_40_FLAG) ?
-						ATH_RC_CW40_FLAG : 0) |
-					((ath_rc_priv->ht_cap &
-						WLAN_RC_SGI_FLAG) ?
-					((ath_rc_priv->ht_cap &
-						WLAN_RC_40_FLAG) ?
-						ATH_RC_SGI_FLAG : 0) : 0);
-
-			series[idx].rix = sc->sc_rixmap[mcs];
-			series_rix  = series[idx].rix;
-
-			/* XXX: Give me some cleanup love */
-			if ((flags & ATH_RC_CW40_FLAG) &&
-				(flags & ATH_RC_SGI_FLAG))
-				rix = rate_table->info[series_rix].ht_index;
-			else if (flags & ATH_RC_SGI_FLAG)
-				rix = rate_table->info[series_rix].sgi_index;
-			else if (flags & ATH_RC_CW40_FLAG)
-				rix = rate_table->info[series_rix].cw40index;
-			else
-				rix = rate_table->info[series_rix].base_index;
-			series[idx].max_4ms_framelen =
-				rate_table->info[rix].max_4ms_framelen;
-			series[idx].flags = flags;
-		}
-	}
-}
-
-static void ath_rc_update_ht(struct ath_softc *sc,
-			     struct ath_rate_node *ath_rc_priv,
-			     struct ath_tx_info_priv *info_priv,
-			     int tx_rate, int xretries, int retries)
-{
-	struct ath_tx_ratectrl *rate_ctrl;
-	u32 now_msec = jiffies_to_msecs(jiffies);
-	int state_change = FALSE, rate, count;
+	bool state_change = false;
+	int count;
 	u8 last_per;
-	struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
-	struct ath_rate_table *rate_table =
-		(struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
-
 	static u32 nretry_to_per_lookup[10] = {
 		100 * 0 / 1,
 		100 * 1 / 4,
@@ -1246,56 +910,35 @@
 		100 * 9 / 10
 	};
 
-	if (!ath_rc_priv)
-		return;
-
-	rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
-
-	ASSERT(tx_rate >= 0);
-	if (tx_rate < 0)
-		return;
-
-	/* To compensate for some imbalance between ctrl and ext. channel */
-
-	if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
-		info_priv->tx.ts_rssi =
-			info_priv->tx.ts_rssi < 3 ? 0 :
-			info_priv->tx.ts_rssi - 3;
-
-	last_per = rate_ctrl->state[tx_rate].per;
+	last_per = ath_rc_priv->state[tx_rate].per;
 
 	if (xretries) {
-		/* Update the PER. */
 		if (xretries == 1) {
-			rate_ctrl->state[tx_rate].per += 30;
-			if (rate_ctrl->state[tx_rate].per > 100)
-				rate_ctrl->state[tx_rate].per = 100;
+			ath_rc_priv->state[tx_rate].per += 30;
+			if (ath_rc_priv->state[tx_rate].per > 100)
+				ath_rc_priv->state[tx_rate].per = 100;
 		} else {
 			/* xretries == 2 */
-			count = sizeof(nretry_to_per_lookup) /
-				sizeof(nretry_to_per_lookup[0]);
+			count = ARRAY_SIZE(nretry_to_per_lookup);
 			if (retries >= count)
 				retries = count - 1;
+
 			/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
-			rate_ctrl->state[tx_rate].per =
-				(u8)(rate_ctrl->state[tx_rate].per -
-				     (rate_ctrl->state[tx_rate].per >> 3) +
-				     ((100) >> 3));
+			ath_rc_priv->state[tx_rate].per =
+				(u8)(last_per - (last_per >> 3) + (100 >> 3));
 		}
 
 		/* xretries == 1 or 2 */
 
-		if (rate_ctrl->probe_rate == tx_rate)
-			rate_ctrl->probe_rate = 0;
+		if (ath_rc_priv->probe_rate == tx_rate)
+			ath_rc_priv->probe_rate = 0;
 
-	} else {	/* xretries == 0 */
-		/* Update the PER. */
-		/* Make sure it doesn't index out of array's bounds. */
-		count = sizeof(nretry_to_per_lookup) /
-			sizeof(nretry_to_per_lookup[0]);
+	} else { /* xretries == 0 */
+		count = ARRAY_SIZE(nretry_to_per_lookup);
 		if (retries >= count)
 			retries = count - 1;
-		if (info_priv->n_bad_frames) {
+
+		if (tx_info_priv->n_bad_frames) {
 			/* new_PER = 7/8*old_PER + 1/8*(currentPER)
 			 * Assuming that n_frames is not 0.  The current PER
 			 * from the retries is 100 * retries / (retries+1),
@@ -1308,37 +951,35 @@
 			 * the above PER.  The expression below is a
 			 * simplified version of the sum of these two terms.
 			 */
-			if (info_priv->n_frames > 0)
-				rate_ctrl->state[tx_rate].per
-				      = (u8)
-					(rate_ctrl->state[tx_rate].per -
-					(rate_ctrl->state[tx_rate].per >> 3) +
-					((100*(retries*info_priv->n_frames +
-					info_priv->n_bad_frames) /
-					(info_priv->n_frames *
-						(retries+1))) >> 3));
-		} else {
-			/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
+			if (tx_info_priv->n_frames > 0) {
+				int n_frames, n_bad_frames;
+				u8 cur_per, new_per;
 
-			rate_ctrl->state[tx_rate].per = (u8)
-				(rate_ctrl->state[tx_rate].per -
-				(rate_ctrl->state[tx_rate].per >> 3) +
-				(nretry_to_per_lookup[retries] >> 3));
+				n_bad_frames = retries * tx_info_priv->n_frames +
+					tx_info_priv->n_bad_frames;
+				n_frames = tx_info_priv->n_frames * (retries + 1);
+				cur_per = (100 * n_bad_frames / n_frames) >> 3;
+				new_per = (u8)(last_per - (last_per >> 3) + cur_per);
+				ath_rc_priv->state[tx_rate].per = new_per;
+			}
+		} else {
+			ath_rc_priv->state[tx_rate].per =
+				(u8)(last_per - (last_per >> 3) +
+				     (nretry_to_per_lookup[retries] >> 3));
 		}
 
-		rate_ctrl->rssi_last_prev2 = rate_ctrl->rssi_last_prev;
-		rate_ctrl->rssi_last_prev  = rate_ctrl->rssi_last;
-		rate_ctrl->rssi_last = info_priv->tx.ts_rssi;
-		rate_ctrl->rssi_time = now_msec;
+		ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev;
+		ath_rc_priv->rssi_last_prev  = ath_rc_priv->rssi_last;
+		ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi;
+		ath_rc_priv->rssi_time = now_msec;
 
 		/*
 		 * If we got at most one retry then increase the max rate if
 		 * this was a probe.  Otherwise, ignore the probe.
 		 */
-
-		if (rate_ctrl->probe_rate && rate_ctrl->probe_rate == tx_rate) {
-			if (retries > 0 || 2 * info_priv->n_bad_frames >
-				info_priv->n_frames) {
+		if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) {
+			if (retries > 0 || 2 * tx_info_priv->n_bad_frames >
+				tx_info_priv->n_frames) {
 				/*
 				 * Since we probed with just a single attempt,
 				 * any retries means the probe failed.  Also,
@@ -1346,17 +987,18 @@
 				 * the subframes were bad then also consider
 				 * the probe a failure.
 				 */
-				rate_ctrl->probe_rate = 0;
+				ath_rc_priv->probe_rate = 0;
 			} else {
 				u8 probe_rate = 0;
 
-				rate_ctrl->rate_max_phy = rate_ctrl->probe_rate;
-				probe_rate = rate_ctrl->probe_rate;
+				ath_rc_priv->rate_max_phy =
+					ath_rc_priv->probe_rate;
+				probe_rate = ath_rc_priv->probe_rate;
 
-				if (rate_ctrl->state[probe_rate].per > 30)
-					rate_ctrl->state[probe_rate].per = 20;
+				if (ath_rc_priv->state[probe_rate].per > 30)
+					ath_rc_priv->state[probe_rate].per = 20;
 
-				rate_ctrl->probe_rate = 0;
+				ath_rc_priv->probe_rate = 0;
 
 				/*
 				 * Since this probe succeeded, we allow the next
@@ -1364,8 +1006,8 @@
 				 * to move up faster if the probes are
 				 * succesful.
 				 */
-				rate_ctrl->probe_time = now_msec -
-					rate_table->probe_interval / 2;
+				ath_rc_priv->probe_time =
+					now_msec - rate_table->probe_interval / 2;
 			}
 		}
 
@@ -1375,74 +1017,114 @@
 			 * this was because of collisions or poor signal.
 			 *
 			 * Later: if rssi_ack is close to
-			 * rate_ctrl->state[txRate].rssi_thres and we see lots
+			 * ath_rc_priv->state[txRate].rssi_thres and we see lots
 			 * of retries, then we could increase
-			 * rate_ctrl->state[txRate].rssi_thres.
+			 * ath_rc_priv->state[txRate].rssi_thres.
 			 */
-			rate_ctrl->hw_maxretry_pktcnt = 0;
+			ath_rc_priv->hw_maxretry_pktcnt = 0;
 		} else {
+			int32_t rssi_ackAvg;
+			int8_t rssi_thres;
+			int8_t rssi_ack_vmin;
+
 			/*
 			 * It worked with no retries. First ignore bogus (small)
 			 * rssi_ack values.
 			 */
-			if (tx_rate == rate_ctrl->rate_max_phy &&
-			    rate_ctrl->hw_maxretry_pktcnt < 255) {
-				rate_ctrl->hw_maxretry_pktcnt++;
+			if (tx_rate == ath_rc_priv->rate_max_phy &&
+			    ath_rc_priv->hw_maxretry_pktcnt < 255) {
+				ath_rc_priv->hw_maxretry_pktcnt++;
 			}
 
-			if (info_priv->tx.ts_rssi >=
-				rate_table->info[tx_rate].rssi_ack_validmin) {
-				/* Average the rssi */
-				if (tx_rate != rate_ctrl->rssi_sum_rate) {
-					rate_ctrl->rssi_sum_rate = tx_rate;
-					rate_ctrl->rssi_sum =
-						rate_ctrl->rssi_sum_cnt = 0;
-				}
+			if (tx_info_priv->tx.ts_rssi <
+			    rate_table->info[tx_rate].rssi_ack_validmin)
+				goto exit;
 
-				rate_ctrl->rssi_sum += info_priv->tx.ts_rssi;
-				rate_ctrl->rssi_sum_cnt++;
-
-				if (rate_ctrl->rssi_sum_cnt > 4) {
-					int32_t rssi_ackAvg =
-						(rate_ctrl->rssi_sum + 2) / 4;
-					int8_t rssi_thres =
-						rate_ctrl->state[tx_rate].
-						rssi_thres;
-					int8_t rssi_ack_vmin =
-						rate_table->info[tx_rate].
-						rssi_ack_validmin;
-
-					rate_ctrl->rssi_sum =
-						rate_ctrl->rssi_sum_cnt = 0;
-
-					/* Now reduce the current
-					 * rssi threshold. */
-					if ((rssi_ackAvg < rssi_thres + 2) &&
-					    (rssi_thres > rssi_ack_vmin)) {
-						rate_ctrl->state[tx_rate].
-							rssi_thres--;
-					}
-
-					state_change = TRUE;
-				}
+			/* Average the rssi */
+			if (tx_rate != ath_rc_priv->rssi_sum_rate) {
+				ath_rc_priv->rssi_sum_rate = tx_rate;
+				ath_rc_priv->rssi_sum =
+					ath_rc_priv->rssi_sum_cnt = 0;
 			}
+
+			ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi;
+			ath_rc_priv->rssi_sum_cnt++;
+
+			if (ath_rc_priv->rssi_sum_cnt < 4)
+				goto exit;
+
+			rssi_ackAvg =
+				(ath_rc_priv->rssi_sum + 2) / 4;
+			rssi_thres =
+				ath_rc_priv->state[tx_rate].rssi_thres;
+			rssi_ack_vmin =
+				rate_table->info[tx_rate].rssi_ack_validmin;
+
+			ath_rc_priv->rssi_sum =
+				ath_rc_priv->rssi_sum_cnt = 0;
+
+			/* Now reduce the current rssi threshold */
+			if ((rssi_ackAvg < rssi_thres + 2) &&
+			    (rssi_thres > rssi_ack_vmin)) {
+				ath_rc_priv->state[tx_rate].rssi_thres--;
+			}
+
+			state_change = true;
 		}
 	}
+exit:
+	return state_change;
+}
 
-	/* For all cases */
+/* Update PER, RSSI and whatever else that the code thinks it is doing.
+   If you can make sense of all this, you really need to go out more. */
+
+static void ath_rc_update_ht(struct ath_softc *sc,
+			     struct ath_rate_priv *ath_rc_priv,
+			     struct ath_tx_info_priv *tx_info_priv,
+			     int tx_rate, int xretries, int retries)
+{
+#define CHK_RSSI(rate)					\
+	((ath_rc_priv->state[(rate)].rssi_thres +	\
+	  rate_table->info[(rate)].rssi_ack_deltamin) > \
+	 ath_rc_priv->state[(rate)+1].rssi_thres)
+
+	u32 now_msec = jiffies_to_msecs(jiffies);
+	int rate;
+	u8 last_per;
+	bool state_change = false;
+	struct ath_rate_table *rate_table = sc->cur_rate_table;
+	int size = ath_rc_priv->rate_table_size;
+
+	if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt))
+		return;
+
+	/* To compensate for some imbalance between ctrl and ext. channel */
+
+	if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
+		tx_info_priv->tx.ts_rssi =
+			tx_info_priv->tx.ts_rssi < 3 ? 0 :
+			tx_info_priv->tx.ts_rssi - 3;
+
+	last_per = ath_rc_priv->state[tx_rate].per;
+
+	/* Update PER first */
+	state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
+					 tx_info_priv, tx_rate, xretries,
+					 retries, now_msec);
 
 	/*
 	 * If this rate looks bad (high PER) then stop using it for
 	 * a while (except if we are probing).
 	 */
-	if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 &&
+	if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 &&
 	    rate_table->info[tx_rate].ratekbps <=
-	    rate_table->info[rate_ctrl->rate_max_phy].ratekbps) {
-		ath_rc_get_nextlowervalid_txrate(rate_table, rate_ctrl,
-				 (u8) tx_rate, &rate_ctrl->rate_max_phy);
+	    rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) {
+		ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv,
+				 (u8)tx_rate, &ath_rc_priv->rate_max_phy);
 
 		/* Don't probe for a little while. */
-		rate_ctrl->probe_time = now_msec;
+		ath_rc_priv->probe_time = now_msec;
 	}
 
 	if (state_change) {
@@ -1453,20 +1135,15 @@
 		 *         made to keep the rssi thresholds monotonically
 		 *         increasing between the CCK and OFDM rates.)
 		 */
-		for (rate = tx_rate; rate <
-				rate_ctrl->rate_table_size - 1; rate++) {
+		for (rate = tx_rate; rate < size - 1; rate++) {
 			if (rate_table->info[rate+1].phy !=
-				rate_table->info[tx_rate].phy)
+			    rate_table->info[tx_rate].phy)
 				break;
 
-			if (rate_ctrl->state[rate].rssi_thres +
-			    rate_table->info[rate].rssi_ack_deltamin >
-			    rate_ctrl->state[rate+1].rssi_thres) {
-				rate_ctrl->state[rate+1].rssi_thres =
-					rate_ctrl->state[rate].
-					rssi_thres +
-					rate_table->info[rate].
-					rssi_ack_deltamin;
+			if (CHK_RSSI(rate)) {
+				ath_rc_priv->state[rate+1].rssi_thres =
+					ath_rc_priv->state[rate].rssi_thres +
+					rate_table->info[rate].rssi_ack_deltamin;
 			}
 		}
 
@@ -1476,27 +1153,20 @@
 			    rate_table->info[tx_rate].phy)
 				break;
 
-			if (rate_ctrl->state[rate].rssi_thres +
-			    rate_table->info[rate].rssi_ack_deltamin >
-			    rate_ctrl->state[rate+1].rssi_thres) {
-				if (rate_ctrl->state[rate+1].rssi_thres <
-				    rate_table->info[rate].
-				    rssi_ack_deltamin)
-					rate_ctrl->state[rate].rssi_thres = 0;
+			if (CHK_RSSI(rate)) {
+				if (ath_rc_priv->state[rate+1].rssi_thres <
+				    rate_table->info[rate].rssi_ack_deltamin)
+					ath_rc_priv->state[rate].rssi_thres = 0;
 				else {
-					rate_ctrl->state[rate].rssi_thres =
-						rate_ctrl->state[rate+1].
-						rssi_thres -
-						rate_table->info[rate].
-						rssi_ack_deltamin;
+					ath_rc_priv->state[rate].rssi_thres =
+					ath_rc_priv->state[rate+1].rssi_thres -
+					rate_table->info[rate].rssi_ack_deltamin;
 				}
 
-				if (rate_ctrl->state[rate].rssi_thres <
-				    rate_table->info[rate].
-				    rssi_ack_validmin) {
-					rate_ctrl->state[rate].rssi_thres =
-						rate_table->info[rate].
-						rssi_ack_validmin;
+				if (ath_rc_priv->state[rate].rssi_thres <
+				    rate_table->info[rate].rssi_ack_validmin) {
+					ath_rc_priv->state[rate].rssi_thres =
+					rate_table->info[rate].rssi_ack_validmin;
 				}
 			}
 		}
@@ -1504,74 +1174,86 @@
 
 	/* Make sure the rates below this have lower PER */
 	/* Monotonicity is kept only for rates below the current rate. */
-	if (rate_ctrl->state[tx_rate].per < last_per) {
+	if (ath_rc_priv->state[tx_rate].per < last_per) {
 		for (rate = tx_rate - 1; rate >= 0; rate--) {
 			if (rate_table->info[rate].phy !=
 			    rate_table->info[tx_rate].phy)
 				break;
 
-			if (rate_ctrl->state[rate].per >
-			    rate_ctrl->state[rate+1].per) {
-				rate_ctrl->state[rate].per =
-					rate_ctrl->state[rate+1].per;
+			if (ath_rc_priv->state[rate].per >
+			    ath_rc_priv->state[rate+1].per) {
+				ath_rc_priv->state[rate].per =
+					ath_rc_priv->state[rate+1].per;
 			}
 		}
 	}
 
 	/* Maintain monotonicity for rates above the current rate */
-	for (rate = tx_rate; rate < rate_ctrl->rate_table_size - 1; rate++) {
-		if (rate_ctrl->state[rate+1].per < rate_ctrl->state[rate].per)
-			rate_ctrl->state[rate+1].per =
-				rate_ctrl->state[rate].per;
+	for (rate = tx_rate; rate < size - 1; rate++) {
+		if (ath_rc_priv->state[rate+1].per <
+		    ath_rc_priv->state[rate].per)
+			ath_rc_priv->state[rate+1].per =
+				ath_rc_priv->state[rate].per;
 	}
 
 	/* Every so often, we reduce the thresholds and
 	 * PER (different for CCK and OFDM). */
-	if (now_msec - rate_ctrl->rssi_down_time >=
+	if (now_msec - ath_rc_priv->rssi_down_time >=
 	    rate_table->rssi_reduce_interval) {
 
-		for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
-			if (rate_ctrl->state[rate].rssi_thres >
+		for (rate = 0; rate < size; rate++) {
+			if (ath_rc_priv->state[rate].rssi_thres >
 			    rate_table->info[rate].rssi_ack_validmin)
-				rate_ctrl->state[rate].rssi_thres -= 1;
+				ath_rc_priv->state[rate].rssi_thres -= 1;
 		}
-		rate_ctrl->rssi_down_time = now_msec;
+		ath_rc_priv->rssi_down_time = now_msec;
 	}
 
 	/* Every so often, we reduce the thresholds
 	 * and PER (different for CCK and OFDM). */
-	if (now_msec - rate_ctrl->per_down_time >=
+	if (now_msec - ath_rc_priv->per_down_time >=
 	    rate_table->rssi_reduce_interval) {
-		for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
-			rate_ctrl->state[rate].per =
-				7 * rate_ctrl->state[rate].per / 8;
+		for (rate = 0; rate < size; rate++) {
+			ath_rc_priv->state[rate].per =
+				7 * ath_rc_priv->state[rate].per / 8;
 		}
 
-		rate_ctrl->per_down_time = now_msec;
+		ath_rc_priv->per_down_time = now_msec;
 	}
+
+#undef CHK_RSSI
 }
 
-/*
- * This routine is called in rate control callback tx_status() to give
- * the status of previous frames.
- */
-static void ath_rc_update(struct ath_softc *sc,
-			  struct ath_rate_node *ath_rc_priv,
-			  struct ath_tx_info_priv *info_priv, int final_ts_idx,
-			  int xretries, int long_retry)
+static int ath_rc_get_rateindex(struct ath_rate_table *rate_table,
+				struct ieee80211_tx_rate *rate)
 {
-	struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
-	struct ath_rate_table *rate_table;
-	struct ath_tx_ratectrl *rate_ctrl;
-	struct ath_rc_series rcs[4];
-	u8 flags;
-	u32 series = 0, rix;
+	int rix;
 
-	memcpy(rcs, info_priv->rcs, 4 * sizeof(rcs[0]));
-	rate_table = (struct ath_rate_table *)
-		asc->hw_rate_table[sc->sc_curmode];
-	rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
-	ASSERT(rcs[0].tries != 0);
+	if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
+	    (rate->flags & IEEE80211_TX_RC_SHORT_GI))
+		rix = rate_table->info[rate->idx].ht_index;
+	else if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+		rix = rate_table->info[rate->idx].sgi_index;
+	else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+		rix = rate_table->info[rate->idx].cw40index;
+	else
+		rix = rate_table->info[rate->idx].base_index;
+
+	return rix;
+}
+
+static void ath_rc_tx_status(struct ath_softc *sc,
+			     struct ath_rate_priv *ath_rc_priv,
+			     struct ieee80211_tx_info *tx_info,
+			     int final_ts_idx, int xretries, int long_retry)
+{
+	struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+	struct ath_rate_table *rate_table;
+	struct ieee80211_tx_rate *rates = tx_info->status.rates;
+	u8 flags;
+	u32 i = 0, rix;
+
+	rate_table = sc->cur_rate_table;
 
 	/*
 	 * If the first rate is not the final index, there
@@ -1579,32 +1261,22 @@
 	 */
 	if (final_ts_idx != 0) {
 		/* Process intermediate rates that failed.*/
-		for (series = 0; series < final_ts_idx ; series++) {
-			if (rcs[series].tries != 0) {
-				flags = rcs[series].flags;
+		for (i = 0; i < final_ts_idx ; i++) {
+			if (rates[i].count != 0 && (rates[i].idx >= 0)) {
+				flags = rates[i].flags;
+
 				/* If HT40 and we have switched mode from
 				 * 40 to 20 => don't update */
-				if ((flags & ATH_RC_CW40_FLAG) &&
-					(rate_ctrl->rc_phy_mode !=
-					(flags & ATH_RC_CW40_FLAG)))
+
+				if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
+				    (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG))
 					return;
-				if ((flags & ATH_RC_CW40_FLAG) &&
-					(flags & ATH_RC_SGI_FLAG))
-					rix = rate_table->info[
-						rcs[series].rix].ht_index;
-				else if (flags & ATH_RC_SGI_FLAG)
-					rix = rate_table->info[
-						rcs[series].rix].sgi_index;
-				else if (flags & ATH_RC_CW40_FLAG)
-					rix = rate_table->info[
-						rcs[series].rix].cw40index;
-				else
-					rix = rate_table->info[
-						rcs[series].rix].base_index;
+
+				rix = ath_rc_get_rateindex(rate_table, &rates[i]);
 				ath_rc_update_ht(sc, ath_rc_priv,
-						info_priv, rix,
+						tx_info_priv, rix,
 						xretries ? 1 : 2,
-						rcs[series].tries);
+						rates[i].count);
 			}
 		}
 	} else {
@@ -1614,240 +1286,152 @@
 		 * Treating it as an excessive retry penalizes the rate
 		 * inordinately.
 		 */
-		if (rcs[0].tries == 1 && xretries == 1)
+		if (rates[0].count == 1 && xretries == 1)
 			xretries = 2;
 	}
 
-	flags = rcs[series].flags;
+	flags = rates[i].flags;
+
 	/* If HT40 and we have switched mode from 40 to 20 => don't update */
-	if ((flags & ATH_RC_CW40_FLAG) &&
-		(rate_ctrl->rc_phy_mode != (flags & ATH_RC_CW40_FLAG)))
+	if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
+	    (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) {
 		return;
+	}
 
-	if ((flags & ATH_RC_CW40_FLAG) && (flags & ATH_RC_SGI_FLAG))
-		rix = rate_table->info[rcs[series].rix].ht_index;
-	else if (flags & ATH_RC_SGI_FLAG)
-		rix = rate_table->info[rcs[series].rix].sgi_index;
-	else if (flags & ATH_RC_CW40_FLAG)
-		rix = rate_table->info[rcs[series].rix].cw40index;
-	else
-		rix = rate_table->info[rcs[series].rix].base_index;
-
-	ath_rc_update_ht(sc, ath_rc_priv, info_priv, rix,
-		xretries, long_retry);
+	rix = ath_rc_get_rateindex(rate_table, &rates[i]);
+	ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix,
+			 xretries, long_retry);
 }
 
-/*
- * Process a tx descriptor for a completed transmit (success or failure).
- */
-static void ath_rate_tx_complete(struct ath_softc *sc,
-				 struct ath_node *an,
-				 struct ath_rate_node *rc_priv,
-				 struct ath_tx_info_priv *info_priv)
+static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
+						    enum ieee80211_band band,
+						    bool is_ht, bool is_cw_40)
 {
-	int final_ts_idx = info_priv->tx.ts_rateindex;
-	int tx_status = 0, is_underrun = 0;
-	struct ath_vap *avp;
+	int mode = 0;
 
-	avp = rc_priv->avp;
-	if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) ||
-	    (info_priv->tx.ts_status & ATH9K_TXERR_FILT))
-		return;
-
-	if (info_priv->tx.ts_rssi > 0) {
-		ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi,
-			     info_priv->tx.ts_rssi);
+	switch(band) {
+	case IEEE80211_BAND_2GHZ:
+		mode = ATH9K_MODE_11G;
+		if (is_ht)
+			mode = ATH9K_MODE_11NG_HT20;
+		if (is_cw_40)
+			mode = ATH9K_MODE_11NG_HT40PLUS;
+		break;
+	case IEEE80211_BAND_5GHZ:
+		mode = ATH9K_MODE_11A;
+		if (is_ht)
+			mode = ATH9K_MODE_11NA_HT20;
+		if (is_cw_40)
+			mode = ATH9K_MODE_11NA_HT40PLUS;
+		break;
+	default:
+		DPRINTF(sc, ATH_DBG_CONFIG, "Invalid band\n");
+		return NULL;
 	}
 
-	/*
-	 * If underrun error is seen assume it as an excessive retry only
-	 * if prefetch trigger level have reached the max (0x3f for 5416)
-	 * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
-	 * times. This affects how ratectrl updates PER for the failed rate.
-	 */
-	if (info_priv->tx.ts_flags &
-		(ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
-		((sc->sc_ah->ah_txTrigLevel) >= tx_triglevel_max)) {
-		tx_status = 1;
-		is_underrun = 1;
-	}
+	BUG_ON(mode >= ATH9K_MODE_MAX);
 
-	if ((info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
-			(info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
-		tx_status = 1;
-
-	ath_rc_update(sc, rc_priv, info_priv, final_ts_idx, tx_status,
-		      (is_underrun) ? ATH_11N_TXMAXTRY :
-		      info_priv->tx.ts_longretry);
+	DPRINTF(sc, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode);
+	return sc->hw_rate_table[mode];
 }
 
-/*
- *  Update the SIB's rate control information
- *
- *  This should be called when the supported rates change
- *  (e.g. SME operation, wireless mode change)
- *
- *  It will determine which rates are valid for use.
- */
-static void ath_rc_sib_update(struct ath_softc *sc,
-			      struct ath_rate_node *ath_rc_priv,
-			      u32 capflag, int keep_state,
-			      struct ath_rateset *negotiated_rates,
-			      struct ath_rateset *negotiated_htrates)
+static void ath_rc_init(struct ath_softc *sc,
+			struct ath_rate_priv *ath_rc_priv,
+			struct ieee80211_supported_band *sband,
+			struct ieee80211_sta *sta)
 {
 	struct ath_rate_table *rate_table = NULL;
-	struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
-	struct ath_rateset *rateset = negotiated_rates;
-	u8 *ht_mcs = (u8 *)negotiated_htrates;
-	struct ath_tx_ratectrl *rate_ctrl =
-		(struct ath_tx_ratectrl *)ath_rc_priv;
+	struct ath_rateset *rateset = &ath_rc_priv->neg_rates;
+	u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
 	u8 i, j, k, hi = 0, hthi = 0;
 
-	rate_table = (struct ath_rate_table *)
-		asc->hw_rate_table[sc->sc_curmode];
+	/* FIXME: Adhoc */
+	if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) ||
+	    (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)) {
+		bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+		rate_table = ath_choose_rate_table(sc, sband->band,
+						   sta->ht_cap.ht_supported,
+						   is_cw_40);
+	} else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
+		/* cur_rate_table would be set on init through config() */
+		rate_table = sc->cur_rate_table;
+	}
+
+	if (!rate_table) {
+		DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n");
+		return;
+	}
+
+	if (sta->ht_cap.ht_supported) {
+		ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG);
+		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+			ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG;
+	}
 
 	/* Initial rate table size. Will change depending
 	 * on the working rate set */
-	rate_ctrl->rate_table_size = MAX_TX_RATE_TBL;
+	ath_rc_priv->rate_table_size = RATE_TABLE_SIZE;
 
 	/* Initialize thresholds according to the global rate table */
-	for (i = 0 ; (i < rate_ctrl->rate_table_size) && (!keep_state); i++) {
-		rate_ctrl->state[i].rssi_thres =
+	for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) {
+		ath_rc_priv->state[i].rssi_thres =
 			rate_table->info[i].rssi_ack_validmin;
-		rate_ctrl->state[i].per = 0;
+		ath_rc_priv->state[i].per = 0;
 	}
 
 	/* Determine the valid rates */
-	ath_rc_init_valid_txmask(rate_ctrl);
+	ath_rc_init_valid_txmask(ath_rc_priv);
 
 	for (i = 0; i < WLAN_RC_PHY_MAX; i++) {
 		for (j = 0; j < MAX_TX_RATE_PHY; j++)
-			rate_ctrl->valid_phy_rateidx[i][j] = 0;
-		rate_ctrl->valid_phy_ratecnt[i] = 0;
+			ath_rc_priv->valid_phy_rateidx[i][j] = 0;
+		ath_rc_priv->valid_phy_ratecnt[i] = 0;
 	}
-	rate_ctrl->rc_phy_mode = (capflag & WLAN_RC_40_FLAG);
+	ath_rc_priv->rc_phy_mode = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG);
 
 	/* Set stream capability */
-	ath_rc_priv->single_stream = (capflag & WLAN_RC_DS_FLAG) ? 0 : 1;
+	ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1;
 
 	if (!rateset->rs_nrates) {
 		/* No working rate, just initialize valid rates */
-		hi = ath_rc_sib_init_validrates(ath_rc_priv, rate_table,
-						capflag);
+		hi = ath_rc_init_validrates(ath_rc_priv, rate_table,
+						ath_rc_priv->ht_cap);
 	} else {
 		/* Use intersection of working rates and valid rates */
-		hi = ath_rc_sib_setvalid_rates(ath_rc_priv, rate_table,
-					       rateset, capflag);
-		if (capflag & WLAN_RC_HT_FLAG) {
-			hthi = ath_rc_sib_setvalid_htrates(ath_rc_priv,
+		hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table,
+					       rateset, ath_rc_priv->ht_cap);
+		if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) {
+			hthi = ath_rc_setvalid_htrates(ath_rc_priv,
 							   rate_table,
 							   ht_mcs,
-							   capflag);
+							   ath_rc_priv->ht_cap);
 		}
 		hi = A_MAX(hi, hthi);
 	}
 
-	rate_ctrl->rate_table_size = hi + 1;
-	rate_ctrl->rate_max_phy = 0;
-	ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL);
+	ath_rc_priv->rate_table_size = hi + 1;
+	ath_rc_priv->rate_max_phy = 0;
+	ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE);
 
 	for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) {
-		for (j = 0; j < rate_ctrl->valid_phy_ratecnt[i]; j++) {
-			rate_ctrl->valid_rate_index[k++] =
-				rate_ctrl->valid_phy_rateidx[i][j];
+		for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) {
+			ath_rc_priv->valid_rate_index[k++] =
+				ath_rc_priv->valid_phy_rateidx[i][j];
 		}
 
-		if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, TRUE)
-		    || !rate_ctrl->valid_phy_ratecnt[i])
+		if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1)
+		    || !ath_rc_priv->valid_phy_ratecnt[i])
 			continue;
 
-		rate_ctrl->rate_max_phy = rate_ctrl->valid_phy_rateidx[i][j-1];
+		ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1];
 	}
-	ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL);
-	ASSERT(k <= MAX_TX_RATE_TBL);
+	ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE);
+	ASSERT(k <= RATE_TABLE_SIZE);
 
-	rate_ctrl->max_valid_rate = k;
-	/*
-	 * Some third party vendors don't send the supported rate series in
-	 * order. So sorting to make sure its in order, otherwise our RateFind
-	 * Algo will select wrong rates
-	 */
-	ath_rc_sort_validrates(rate_table, rate_ctrl);
-	rate_ctrl->rate_max_phy = rate_ctrl->valid_rate_index[k-4];
-}
-
-/*
- * Update rate-control state on station associate/reassociate.
- */
-static int ath_rate_newassoc(struct ath_softc *sc,
-			     struct ath_rate_node *ath_rc_priv,
-			     unsigned int capflag,
-			     struct ath_rateset *negotiated_rates,
-			     struct ath_rateset *negotiated_htrates)
-{
-
-
-	ath_rc_priv->ht_cap =
-		((capflag & ATH_RC_DS_FLAG) ? WLAN_RC_DS_FLAG : 0) |
-		((capflag & ATH_RC_SGI_FLAG) ? WLAN_RC_SGI_FLAG : 0) |
-		((capflag & ATH_RC_HT_FLAG)  ? WLAN_RC_HT_FLAG : 0) |
-		((capflag & ATH_RC_CW40_FLAG) ? WLAN_RC_40_FLAG : 0);
-
-	ath_rc_sib_update(sc, ath_rc_priv, ath_rc_priv->ht_cap, 0,
-			  negotiated_rates, negotiated_htrates);
-
-	return 0;
-}
-
-/*
- *  This routine is called to initialize the rate control parameters
- *  in the SIB. It is called initially during system initialization
- *  or when a station is associated with the AP.
- */
-static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv)
-{
-	struct ath_tx_ratectrl *rate_ctrl;
-
-	rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
-	rate_ctrl->rssi_down_time = jiffies_to_msecs(jiffies);
-}
-
-
-static void ath_setup_rates(struct ath_softc *sc,
-			    struct ieee80211_supported_band *sband,
-			    struct ieee80211_sta *sta,
-			    struct ath_rate_node *rc_priv)
-
-{
-	int i, j = 0;
-
-	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
-
-	for (i = 0; i < sband->n_bitrates; i++) {
-		if (sta->supp_rates[sband->band] & BIT(i)) {
-			rc_priv->neg_rates.rs_rates[j]
-				= (sband->bitrates[i].bitrate * 2) / 10;
-			j++;
-		}
-	}
-	rc_priv->neg_rates.rs_nrates = j;
-}
-
-void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv)
-{
-	struct ath_softc *sc = hw->priv;
-	u32 capflag = 0;
-
-	if (hw->conf.ht_conf.ht_supported) {
-		capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG;
-		if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040)
-			capflag |= ATH_RC_CW40_FLAG;
-	}
-
-	ath_rate_newassoc(sc, rc_priv, capflag,
-			  &rc_priv->neg_rates,
-			  &rc_priv->neg_ht_rates);
-
+	ath_rc_priv->max_valid_rate = k;
+	ath_rc_sort_validrates(rate_table, ath_rc_priv);
+	ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4];
+	sc->cur_rate_table = rate_table;
 }
 
 /* Rate Control callbacks */
@@ -1856,163 +1440,88 @@
 			  struct sk_buff *skb)
 {
 	struct ath_softc *sc = priv;
-	struct ath_tx_info_priv *tx_info_priv;
-	struct ath_node *an;
+	struct ath_rate_priv *ath_rc_priv = priv_sta;
+	struct ath_tx_info_priv *tx_info_priv = NULL;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr;
+	int final_ts_idx, tx_status = 0, is_underrun = 0;
 	__le16 fc;
 
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = hdr->frame_control;
-	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+	tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+	final_ts_idx = tx_info_priv->tx.ts_rateindex;
 
-	spin_lock_bh(&sc->node_lock);
-	an = ath_node_find(sc, hdr->addr1);
-	spin_unlock_bh(&sc->node_lock);
+	if (!priv_sta || !ieee80211_is_data(fc) ||
+	    !tx_info_priv->update_rc)
+		goto exit;
 
-	if (!an || !priv_sta || !ieee80211_is_data(fc)) {
-		if (tx_info->driver_data[0] != NULL) {
-			kfree(tx_info->driver_data[0]);
-			tx_info->driver_data[0] = NULL;
-		}
-		return;
-	}
-	if (tx_info->driver_data[0] != NULL) {
-		ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv);
-		kfree(tx_info->driver_data[0]);
-		tx_info->driver_data[0] = NULL;
-	}
-}
-
-static void ath_tx_aggr_resp(struct ath_softc *sc,
-			     struct ieee80211_supported_band *sband,
-			     struct ieee80211_sta *sta,
-			     struct ath_node *an,
-			     u8 tidno)
-{
-	struct ath_atx_tid *txtid;
-	u16 buffersize = 0;
-	int state;
-	struct sta_info *si;
-
-	if (!(sc->sc_flags & SC_OP_TXAGGR))
-		return;
-
-	txtid = ATH_AN_2_TID(an, tidno);
-	if (!txtid->paused)
-		return;
+	if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT)
+		goto exit;
 
 	/*
-	 * XXX: This is entirely busted, we aren't supposed to
-	 *	access the sta from here because it's internal
-	 *	to mac80211, and looking at the state without
-	 *	locking is wrong too.
+	 * If underrun error is seen assume it as an excessive retry only
+	 * if prefetch trigger level have reached the max (0x3f for 5416)
+	 * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
+	 * times. This affects how ratectrl updates PER for the failed rate.
 	 */
-	si = container_of(sta, struct sta_info, sta);
-	buffersize = IEEE80211_MIN_AMPDU_BUF <<
-		sband->ht_info.ampdu_factor; /* FIXME */
-	state = si->ampdu_mlme.tid_state_tx[tidno];
-
-	if (state & HT_ADDBA_RECEIVED_MSK) {
-		txtid->addba_exchangecomplete = 1;
-		txtid->addba_exchangeinprogress = 0;
-		txtid->baw_size = buffersize;
-
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: Resuming tid, buffersize: %d\n",
-			__func__,
-			buffersize);
-
-		ath_tx_resume_tid(sc, txtid);
+	if (tx_info_priv->tx.ts_flags &
+	    (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
+	    ((sc->sc_ah->ah_txTrigLevel) >= ath_rc_priv->tx_triglevel_max)) {
+		tx_status = 1;
+		is_underrun = 1;
 	}
+
+	if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
+	    (tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
+		tx_status = 1;
+
+	ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
+			 (is_underrun) ? ATH_11N_TXMAXTRY :
+			 tx_info_priv->tx.ts_longretry);
+
+exit:
+	kfree(tx_info_priv);
 }
 
-static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
-			 struct ieee80211_sta *sta, void *priv_sta,
-			 struct sk_buff *skb, struct rate_selection *sel)
+static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+			 struct ieee80211_tx_rate_control *txrc)
 {
+	struct ieee80211_supported_band *sband = txrc->sband;
+	struct sk_buff *skb = txrc->skb;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ath_softc *sc = priv;
 	struct ieee80211_hw *hw = sc->hw;
-	struct ath_tx_info_priv *tx_info_priv;
-	struct ath_rate_node *ath_rc_priv = priv_sta;
-	struct ath_node *an;
+	struct ath_rate_priv *ath_rc_priv = priv_sta;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	int is_probe = FALSE, chk, ret;
-	s8 lowest_idx;
+	int is_probe = 0;
 	__le16 fc = hdr->frame_control;
-	u8 *qc, tid;
-	DECLARE_MAC_BUF(mac);
 
-	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
-
-	/* allocate driver private area of tx_info */
-	tx_info->driver_data[0] = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
-	ASSERT(tx_info->driver_data[0] != NULL);
-	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
-
-	lowest_idx = rate_lowest_index(sband, sta);
-	tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
 	/* lowest rate for management and multicast/broadcast frames */
-	if (!ieee80211_is_data(fc) ||
-	    is_multicast_ether_addr(hdr->addr1) || !sta) {
-		sel->rate_idx = lowest_idx;
+	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
+	    !sta) {
+		tx_info->control.rates[0].idx = rate_lowest_index(sband, sta);
+		tx_info->control.rates[0].count =
+			is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY;
 		return;
 	}
 
 	/* Find tx rate for unicast frames */
-	ath_rate_findrate(sc, ath_rc_priv,
-			  ATH_11N_TXMAXTRY, 4,
-			  ATH_RC_PROBE_ALLOWED,
-			  tx_info_priv->rcs,
-			  &is_probe,
-			  false);
-	if (is_probe)
-		sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate;
-
-	/* Ratecontrol sometimes returns invalid rate index */
-	if (tx_info_priv->rcs[0].rix != 0xff)
-		ath_rc_priv->prev_data_rix = tx_info_priv->rcs[0].rix;
-	else
-		tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix;
-
-	sel->rate_idx = tx_info_priv->rcs[0].rix;
+	ath_rc_ratefind(sc, ath_rc_priv, ATH_11N_TXMAXTRY, 4,
+			tx_info, &is_probe, false);
 
 	/* Check if aggregation has to be enabled for this tid */
-
-	if (hw->conf.ht_conf.ht_supported) {
+	if (hw->conf.ht.enabled) {
 		if (ieee80211_is_data_qos(fc)) {
+			u8 *qc, tid;
+			struct ath_node *an;
+
 			qc = ieee80211_get_qos_ctl(hdr);
 			tid = qc[0] & 0xf;
+			an = (struct ath_node *)sta->drv_priv;
 
-			spin_lock_bh(&sc->node_lock);
-			an = ath_node_find(sc, hdr->addr1);
-			spin_unlock_bh(&sc->node_lock);
-
-			if (!an) {
-				DPRINTF(sc, ATH_DBG_AGGR,
-					"%s: Node not found to "
-					"init/chk TX aggr\n", __func__);
-				return;
-			}
-
-			chk = ath_tx_aggr_check(sc, an, tid);
-			if (chk == AGGR_REQUIRED) {
-				ret = ieee80211_start_tx_ba_session(hw,
-					hdr->addr1, tid);
-				if (ret)
-					DPRINTF(sc, ATH_DBG_AGGR,
-						"%s: Unable to start tx "
-						"aggr for: %s\n",
-						__func__,
-						print_mac(mac, hdr->addr1));
-				else
-					DPRINTF(sc, ATH_DBG_AGGR,
-						"%s: Started tx aggr for: %s\n",
-						__func__,
-						print_mac(mac, hdr->addr1));
-			} else if (chk == AGGR_EXCHANGE_PROGRESS)
-				ath_tx_aggr_resp(sc, sband, sta, an, tid);
+			if(ath_tx_aggr_check(sc, an, tid))
+				ieee80211_start_tx_ba_session(hw, hdr->addr1, tid);
 		}
 	}
 }
@@ -2021,34 +1530,33 @@
                           struct ieee80211_sta *sta, void *priv_sta)
 {
 	struct ath_softc *sc = priv;
-	struct ath_rate_node *ath_rc_priv = priv_sta;
+	struct ath_rate_priv *ath_rc_priv = priv_sta;
 	int i, j = 0;
 
-	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
+	for (i = 0; i < sband->n_bitrates; i++) {
+		if (sta->supp_rates[sband->band] & BIT(i)) {
+			ath_rc_priv->neg_rates.rs_rates[j]
+				= (sband->bitrates[i].bitrate * 2) / 10;
+			j++;
+		}
+	}
+	ath_rc_priv->neg_rates.rs_nrates = j;
 
-	ath_setup_rates(sc, sband, sta, ath_rc_priv);
-	if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
-		for (i = 0; i < MCS_SET_SIZE; i++) {
-			if (sc->hw->conf.ht_conf.supp_mcs_set[i/8] & (1<<(i%8)))
+	if (sta->ht_cap.ht_supported) {
+		for (i = 0, j = 0; i < 77; i++) {
+			if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
 				ath_rc_priv->neg_ht_rates.rs_rates[j++] = i;
 			if (j == ATH_RATE_MAX)
 				break;
 		}
 		ath_rc_priv->neg_ht_rates.rs_nrates = j;
 	}
-	ath_rc_node_update(sc->hw, priv_sta);
-}
 
-static void ath_rate_clear(void *priv)
-{
-	return;
+	ath_rc_init(sc, priv_sta, sband, sta);
 }
 
 static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
 {
-	struct ath_softc *sc = hw->priv;
-
-	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
 	return hw->priv;
 }
 
@@ -2060,19 +1568,17 @@
 static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
 {
 	struct ath_softc *sc = priv;
-	struct ath_vap *avp = sc->sc_vaps[0];
-	struct ath_rate_node *rate_priv;
+	struct ath_rate_priv *rate_priv;
 
-	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
-
-	rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp);
+	rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp);
 	if (!rate_priv) {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unable to allocate private rc structure\n",
-			__func__);
+			"Unable to allocate private rc structure\n");
 		return NULL;
 	}
-	ath_rc_sib_init(rate_priv);
+
+	rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
+	rate_priv->tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max;
 
 	return rate_priv;
 }
@@ -2080,11 +1586,8 @@
 static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta,
 			      void *priv_sta)
 {
-	struct ath_rate_node *rate_priv = priv_sta;
-	struct ath_softc *sc = priv;
-
-	DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
-	ath_rate_node_free(rate_priv);
+	struct ath_rate_priv *rate_priv = priv_sta;
+	kfree(rate_priv);
 }
 
 static struct rate_control_ops ath_rate_ops = {
@@ -2093,13 +1596,69 @@
 	.tx_status = ath_tx_status,
 	.get_rate = ath_get_rate,
 	.rate_init = ath_rate_init,
-	.clear = ath_rate_clear,
 	.alloc = ath_rate_alloc,
 	.free = ath_rate_free,
 	.alloc_sta = ath_rate_alloc_sta,
 	.free_sta = ath_rate_free_sta,
 };
 
+static void ath_setup_rate_table(struct ath_softc *sc,
+				 struct ath_rate_table *rate_table)
+{
+	int i;
+
+	for (i = 0; i < 256; i++)
+		rate_table->rateCodeToIndex[i] = (u8)-1;
+
+	for (i = 0; i < rate_table->rate_cnt; i++) {
+		u8 code = rate_table->info[i].ratecode;
+		u8 cix = rate_table->info[i].ctrl_rate;
+		u8 sh = rate_table->info[i].short_preamble;
+
+		rate_table->rateCodeToIndex[code] = i;
+		rate_table->rateCodeToIndex[code | sh] = i;
+
+		rate_table->info[i].lpAckDuration =
+			ath9k_hw_computetxtime(sc->sc_ah, rate_table,
+					       WLAN_CTRL_FRAME_SIZE,
+					       cix,
+					       false);
+		rate_table->info[i].spAckDuration =
+			ath9k_hw_computetxtime(sc->sc_ah, rate_table,
+					       WLAN_CTRL_FRAME_SIZE,
+					       cix,
+					       true);
+	}
+}
+
+void ath_rate_attach(struct ath_softc *sc)
+{
+	sc->hw_rate_table[ATH9K_MODE_11B] =
+		&ar5416_11b_ratetable;
+	sc->hw_rate_table[ATH9K_MODE_11A] =
+		&ar5416_11a_ratetable;
+	sc->hw_rate_table[ATH9K_MODE_11G] =
+		&ar5416_11g_ratetable;
+	sc->hw_rate_table[ATH9K_MODE_11NA_HT20] =
+		&ar5416_11na_ratetable;
+	sc->hw_rate_table[ATH9K_MODE_11NG_HT20] =
+		&ar5416_11ng_ratetable;
+	sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] =
+		&ar5416_11na_ratetable;
+	sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] =
+		&ar5416_11na_ratetable;
+	sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] =
+		&ar5416_11ng_ratetable;
+	sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] =
+		&ar5416_11ng_ratetable;
+
+	ath_setup_rate_table(sc, &ar5416_11b_ratetable);
+	ath_setup_rate_table(sc, &ar5416_11a_ratetable);
+	ath_setup_rate_table(sc, &ar5416_11g_ratetable);
+	ath_setup_rate_table(sc, &ar5416_11na_ratetable);
+	ath_setup_rate_table(sc, &ar5416_11ng_ratetable);
+}
+
 int ath_rate_control_register(void)
 {
 	return ieee80211_rate_control_register(&ath_rate_ops);
@@ -2109,4 +1668,3 @@
 {
 	ieee80211_rate_control_unregister(&ath_rate_ops);
 }
-
diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h
index b95b415..97c60d1 100644
--- a/drivers/net/wireless/ath9k/rc.h
+++ b/drivers/net/wireless/ath9k/rc.h
@@ -20,84 +20,24 @@
 #define RC_H
 
 #include "ath9k.h"
-/*
- * Interface definitions for transmit rate control modules for the
- * Atheros driver.
- *
- * A rate control module is responsible for choosing the transmit rate
- * for each data frame.  Management+control frames are always sent at
- * a fixed rate.
- *
- * Only one module may be present at a time; the driver references
- * rate control interfaces by symbol name.  If multiple modules are
- * to be supported we'll need to switch to a registration-based scheme
- * as is currently done, for example, for authentication modules.
- *
- * An instance of the rate control module is attached to each device
- * at attach time and detached when the device is destroyed.  The module
- * may associate data with each device and each node (station).  Both
- * sets of storage are opaque except for the size of the per-node storage
- * which must be provided when the module is attached.
- *
- * The rate control module is notified for each state transition and
- * station association/reassociation.  Otherwise it is queried for a
- * rate for each outgoing frame and provided status from each transmitted
- * frame.  Any ancillary processing is the responsibility of the module
- * (e.g. if periodic processing is required then the module should setup
- * it's own timer).
- *
- * In addition to the transmit rate for each frame the module must also
- * indicate the number of attempts to make at the specified rate.  If this
- * number is != ATH_TXMAXTRY then an additional callback is made to setup
- * additional transmit state.  The rate control code is assumed to write
- * this additional data directly to the transmit descriptor.
- */
 
 struct ath_softc;
 
-#define TRUE 1
-#define FALSE 0
+#define ATH_RATE_MAX     30
+#define RATE_TABLE_SIZE  64
+#define MAX_TX_RATE_PHY  48
 
-#define ATH_RATE_MAX	30
-#define MCS_SET_SIZE	128
+/* VALID_ALL - valid for 20/40/Legacy,
+ * VALID - Legacy only,
+ * VALID_20 - HT 20 only,
+ * VALID_40 - HT 40 only */
 
-enum ieee80211_fixed_rate_mode {
-	IEEE80211_FIXED_RATE_NONE  = 0,
-	IEEE80211_FIXED_RATE_MCS   = 1  /* HT rates */
-};
-
-/*
- * Use the hal os glue code to get ms time
- */
-#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8)))
-
-#define WLAN_PHY_HT_20_SS       WLAN_RC_PHY_HT_20_SS
-#define WLAN_PHY_HT_20_DS       WLAN_RC_PHY_HT_20_DS
-#define WLAN_PHY_HT_20_DS_HGI   WLAN_RC_PHY_HT_20_DS_HGI
-#define WLAN_PHY_HT_40_SS       WLAN_RC_PHY_HT_40_SS
-#define WLAN_PHY_HT_40_SS_HGI   WLAN_RC_PHY_HT_40_SS_HGI
-#define WLAN_PHY_HT_40_DS       WLAN_RC_PHY_HT_40_DS
-#define WLAN_PHY_HT_40_DS_HGI   WLAN_RC_PHY_HT_40_DS_HGI
-
-#define WLAN_PHY_OFDM	PHY_OFDM
-#define WLAN_PHY_CCK	PHY_CCK
-
-#define TRUE_20		0x2
-#define TRUE_40		0x4
-#define TRUE_2040	(TRUE_20|TRUE_40)
-#define TRUE_ALL	(TRUE_2040|TRUE)
-
-enum {
-	WLAN_RC_PHY_HT_20_SS = 4,
-	WLAN_RC_PHY_HT_20_DS,
-	WLAN_RC_PHY_HT_40_SS,
-	WLAN_RC_PHY_HT_40_DS,
-	WLAN_RC_PHY_HT_20_SS_HGI,
-	WLAN_RC_PHY_HT_20_DS_HGI,
-	WLAN_RC_PHY_HT_40_SS_HGI,
-	WLAN_RC_PHY_HT_40_DS_HGI,
-	WLAN_RC_PHY_MAX
-};
+#define INVALID    0x0
+#define VALID      0x1
+#define VALID_20   0x2
+#define VALID_40   0x4
+#define VALID_2040 (VALID_20|VALID_40)
+#define VALID_ALL  (VALID_2040|VALID)
 
 #define WLAN_RC_PHY_DS(_phy)   ((_phy == WLAN_RC_PHY_HT_20_DS)		\
 				|| (_phy == WLAN_RC_PHY_HT_40_DS)	\
@@ -114,26 +54,22 @@
 
 #define WLAN_RC_PHY_HT(_phy)    (_phy >= WLAN_RC_PHY_HT_20_SS)
 
-/* Returns the capflag mode */
 #define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ?	\
-		(capflag & WLAN_RC_40_FLAG) ? TRUE_40 : TRUE_20 : TRUE))
+		(capflag & WLAN_RC_40_FLAG) ? VALID_40 : VALID_20 : VALID))
 
 /* Return TRUE if flag supports HT20 && client supports HT20 or
  * return TRUE if flag supports HT40 && client supports HT40.
  * This is used becos some rates overlap between HT20/HT40.
  */
-
-#define WLAN_RC_PHY_HT_VALID(flag, capflag) (((flag & TRUE_20) && !(capflag \
-				& WLAN_RC_40_FLAG)) || ((flag & TRUE_40) && \
-				  (capflag & WLAN_RC_40_FLAG)))
+#define WLAN_RC_PHY_HT_VALID(flag, capflag)			\
+	(((flag & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \
+	 ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG)))
 
 #define WLAN_RC_DS_FLAG         (0x01)
 #define WLAN_RC_40_FLAG         (0x02)
 #define WLAN_RC_SGI_FLAG        (0x04)
 #define WLAN_RC_HT_FLAG         (0x08)
 
-#define RATE_TABLE_SIZE		64
-
 /**
  * struct ath_rate_table - Rate Control table
  * @valid: valid for use in rate control
@@ -150,10 +86,11 @@
  * @max_4ms_framelen: maximum frame length(bytes) for tx duration
  * @probe_interval: interval for rate control to probe for other rates
  * @rssi_reduce_interval: interval for rate control to reduce rssi
- * @initial_ratemax: initial ratemax value used in ath_rc_sib_update()
+ * @initial_ratemax: initial ratemax value
  */
 struct ath_rate_table {
 	int rate_cnt;
+	u8 rateCodeToIndex[256];
 	struct {
 		int valid;
 		int valid_single_stream;
@@ -171,42 +108,26 @@
 		u8 sgi_index;
 		u8 ht_index;
 		u32 max_4ms_framelen;
+		u16 lpAckDuration;
+		u16 spAckDuration;
 	} info[RATE_TABLE_SIZE];
 	u32 probe_interval;
 	u32 rssi_reduce_interval;
 	u8 initial_ratemax;
 };
 
-#define ATH_RC_PROBE_ALLOWED            0x00000001
-#define ATH_RC_MINRATE_LASTRATE         0x00000002
-
-struct ath_rc_series {
-	u8 rix;
-	u8 tries;
-	u8 flags;
-	u32 max_4ms_framelen;
-};
-
-/* rcs_flags definition */
-#define ATH_RC_DS_FLAG               0x01
-#define ATH_RC_CW40_FLAG             0x02    /* CW 40 */
-#define ATH_RC_SGI_FLAG              0x04    /* Short Guard Interval */
-#define ATH_RC_HT_FLAG               0x08    /* HT */
-#define ATH_RC_RTSCTS_FLAG           0x10    /* RTS-CTS */
-
-/*
- * State structures for new rate adaptation code
- */
-#define	MAX_TX_RATE_TBL	        64
-#define MAX_TX_RATE_PHY         48
-
 struct ath_tx_ratectrl_state {
 	int8_t rssi_thres;	/* required rssi for this rate (dB) */
 	u8 per;			/* recent estimate of packet error rate (%) */
 };
 
+struct ath_rateset {
+	u8 rs_nrates;
+	u8 rs_rates[ATH_RATE_MAX];
+};
+
 /**
- * struct ath_tx_ratectrl - TX Rate control Information
+ * struct ath_rate_priv - Rate Control priv data
  * @state: RC state
  * @rssi_last: last ACK rssi
  * @rssi_last_lookup: last ACK rssi used for lookup
@@ -225,9 +146,13 @@
  * @valid_phy_ratecnt: valid rate count
  * @rate_max_phy: phy index for the max rate
  * @probe_interval: interval for ratectrl to probe for other rates
+ * @prev_data_rix: rate idx of last data frame
+ * @ht_cap: HT capabilities
+ * @single_stream: When TRUE, only single TX stream possible
+ * @neg_rates: Negotatied rates
+ * @neg_ht_rates: Negotiated HT rates
  */
-struct ath_tx_ratectrl {
-	struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL];
+struct ath_rate_priv {
 	int8_t rssi_last;
 	int8_t rssi_last_lookup;
 	int8_t rssi_last_prev;
@@ -237,89 +162,40 @@
 	int32_t rssi_sum;
 	u8 rate_table_size;
 	u8 probe_rate;
+	u8 hw_maxretry_pktcnt;
+	u8 max_valid_rate;
+	u8 valid_rate_index[RATE_TABLE_SIZE];
+	u8 ht_cap;
+	u8 single_stream;
+	u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
+	u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
+	u8 rc_phy_mode;
+	u8 rate_max_phy;
 	u32 rssi_time;
 	u32 rssi_down_time;
 	u32 probe_time;
-	u8 hw_maxretry_pktcnt;
-	u8 max_valid_rate;
-	u8 valid_rate_index[MAX_TX_RATE_TBL];
 	u32 per_down_time;
-
-	/* 11n state */
-	u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
-	u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL];
-	u8 rc_phy_mode;
-	u8 rate_max_phy;
 	u32 probe_interval;
-};
-
-struct ath_rateset {
-	u8 rs_nrates;
-	u8 rs_rates[ATH_RATE_MAX];
-};
-
-/* per-device state */
-struct ath_rate_softc {
-	/* phy tables that contain rate control data */
-	const void *hw_rate_table[ATH9K_MODE_MAX];
-
-	/* -1 or index of fixed rate */
-	int fixedrix;
-};
-
-/* per-node state */
-struct ath_rate_node {
-	struct ath_tx_ratectrl tx_ratectrl;
-
-	/* rate idx of last data frame */
 	u32 prev_data_rix;
-
-	/* ht capabilities */
-	u8 ht_cap;
-
-	/* When TRUE, only single stream Tx possible */
-	u8 single_stream;
-
-	/* Negotiated rates */
+	u32 tx_triglevel_max;
+	struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE];
 	struct ath_rateset neg_rates;
-
-	/* Negotiated HT rates */
 	struct ath_rateset neg_ht_rates;
-
 	struct ath_rate_softc *asc;
-	struct ath_vap *avp;
 };
 
-/* Driver data of ieee80211_tx_info */
 struct ath_tx_info_priv {
-	struct ath_rc_series rcs[4];
 	struct ath_tx_status tx;
 	int n_frames;
 	int n_bad_frames;
-	u8 min_rate;
+	bool update_rc;
 };
 
-/*
- * Attach/detach a rate control module.
- */
-struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah);
-void ath_rate_detach(struct ath_rate_softc *asc);
+#define ATH_TX_INFO_PRIV(tx_info) \
+	((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0]))
 
-/*
- * Update/reset rate control state for 802.11 state transitions.
- * Important mostly as the analog to ath_rate_newassoc when operating
- * in station mode.
- */
-void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv);
-void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp);
-
-/*
- * Return rate index for given Dot11 Rate.
- */
-u8 ath_rate_findrateix(struct ath_softc *sc,
-		       u8 dot11_rate);
-
-/* Routines to register/unregister rate control algorithm */
+void ath_rate_attach(struct ath_softc *sc);
+u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
 int ath_rate_control_register(void);
 void ath_rate_control_unregister(void);
 
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
index 504a044..462e08c 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -14,10 +14,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/*
- * Implementation of receive path.
- */
-
 #include "core.h"
 
 /*
@@ -27,10 +23,7 @@
  * MAC acknowledges BA status as long as it copies frames to host
  * buffer (or rx fifo). This can incorrectly acknowledge packets
  * to a sender if last desc is self-linked.
- *
- * NOTE: Caller should hold the rxbuf lock.
  */
-
 static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
 {
 	struct ath_hal *ah = sc->sc_ah;
@@ -40,356 +33,53 @@
 	ATH_RXBUF_RESET(bf);
 
 	ds = bf->bf_desc;
-	ds->ds_link = 0;    /* link to null */
+	ds->ds_link = 0; /* link to null */
 	ds->ds_data = bf->bf_buf_addr;
 
-	/* XXX For RADAR?
-	 * virtual addr of the beginning of the buffer. */
+	/* virtual addr of the beginning of the buffer. */
 	skb = bf->bf_mpdu;
 	ASSERT(skb != NULL);
 	ds->ds_vdata = skb->data;
 
-	/* setup rx descriptors. The sc_rxbufsize here tells the harware
+	/* setup rx descriptors. The rx.bufsize here tells the harware
 	 * how much data it can DMA to us and that we are prepared
 	 * to process */
-	ath9k_hw_setuprxdesc(ah,
-			     ds,
-			     sc->sc_rxbufsize,
+	ath9k_hw_setuprxdesc(ah, ds,
+			     sc->rx.bufsize,
 			     0);
 
-	if (sc->sc_rxlink == NULL)
+	if (sc->rx.rxlink == NULL)
 		ath9k_hw_putrxbuf(ah, bf->bf_daddr);
 	else
-		*sc->sc_rxlink = bf->bf_daddr;
+		*sc->rx.rxlink = bf->bf_daddr;
 
-	sc->sc_rxlink = &ds->ds_link;
+	sc->rx.rxlink = &ds->ds_link;
 	ath9k_hw_rxena(ah);
 }
 
-/* Process received BAR frame */
-
-static int ath_bar_rx(struct ath_softc *sc,
-		      struct ath_node *an,
-		      struct sk_buff *skb)
+static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
 {
-	struct ieee80211_bar *bar;
-	struct ath_arx_tid *rxtid;
-	struct sk_buff *tskb;
-	struct ath_recv_status *rx_status;
-	int tidno, index, cindex;
-	u16 seqno;
-
-	/* look at BAR contents	 */
-
-	bar = (struct ieee80211_bar *)skb->data;
-	tidno = (le16_to_cpu(bar->control) & IEEE80211_BAR_CTL_TID_M)
-		>> IEEE80211_BAR_CTL_TID_S;
-	seqno = le16_to_cpu(bar->start_seq_num) >> IEEE80211_SEQ_SEQ_SHIFT;
-
-	/* process BAR - indicate all pending RX frames till the BAR seqno */
-
-	rxtid = &an->an_aggr.rx.tid[tidno];
-
-	spin_lock_bh(&rxtid->tidlock);
-
-	/* get relative index */
-
-	index = ATH_BA_INDEX(rxtid->seq_next, seqno);
-
-	/* drop BAR if old sequence (index is too large) */
-
-	if ((index > rxtid->baw_size) &&
-	    (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))))
-		/* discard frame, ieee layer may not treat frame as a dup */
-		goto unlock_and_free;
-
-	/* complete receive processing for all pending frames upto BAR seqno */
-
-	cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
-	while ((rxtid->baw_head != rxtid->baw_tail) &&
-	       (rxtid->baw_head != cindex)) {
-		tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf;
-		rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status;
-		rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL;
-
-		if (tskb != NULL)
-			ath_rx_subframe(an, tskb, rx_status);
-
-		INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-		INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-	}
-
-	/* ... and indicate rest of the frames in-order */
-
-	while (rxtid->baw_head != rxtid->baw_tail &&
-	       rxtid->rxbuf[rxtid->baw_head].rx_wbuf != NULL) {
-		tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf;
-		rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status;
-		rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL;
-
-		ath_rx_subframe(an, tskb, rx_status);
-
-		INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-		INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-	}
-
-unlock_and_free:
-	spin_unlock_bh(&rxtid->tidlock);
-	/* free bar itself */
-	dev_kfree_skb(skb);
-	return IEEE80211_FTYPE_CTL;
+	/* XXX block beacon interrupts */
+	ath9k_hw_setantenna(sc->sc_ah, antenna);
+	sc->rx.defant = antenna;
+	sc->rx.rxotherant = 0;
 }
 
-/* Function to handle a subframe of aggregation when HT is enabled */
-
-static int ath_ampdu_input(struct ath_softc *sc,
-			   struct ath_node *an,
-			   struct sk_buff *skb,
-			   struct ath_recv_status *rx_status)
+/*
+ *  Extend 15-bit time stamp from rx descriptor to
+ *  a full 64-bit TSF using the current h/w TSF.
+*/
+static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
 {
-	struct ieee80211_hdr *hdr;
-	struct ath_arx_tid *rxtid;
-	struct ath_rxbuf *rxbuf;
-	u8 type, subtype;
-	u16 rxseq;
-	int tid = 0, index, cindex, rxdiff;
-	__le16 fc;
-	u8 *qc;
+	u64 tsf;
 
-	hdr = (struct ieee80211_hdr *)skb->data;
-	fc = hdr->frame_control;
-
-	/* collect stats of frames with non-zero version */
-
-	if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_VERS) != 0) {
-		dev_kfree_skb(skb);
-		return -1;
-	}
-
-	type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
-	subtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE;
-
-	if (ieee80211_is_back_req(fc))
-		return ath_bar_rx(sc, an, skb);
-
-	/* special aggregate processing only for qos unicast data frames */
-
-	if (!ieee80211_is_data(fc) ||
-	    !ieee80211_is_data_qos(fc) ||
-	    is_multicast_ether_addr(hdr->addr1))
-		return ath_rx_subframe(an, skb, rx_status);
-
-	/* lookup rx tid state */
-
-	if (ieee80211_is_data_qos(fc)) {
-		qc = ieee80211_get_qos_ctl(hdr);
-		tid = qc[0] & 0xf;
-	}
-
-	if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
-		/* Drop the frame not belonging to me. */
-		if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) {
-			dev_kfree_skb(skb);
-			return -1;
-		}
-	}
-
-	rxtid = &an->an_aggr.rx.tid[tid];
-
-	spin_lock(&rxtid->tidlock);
-
-	rxdiff = (rxtid->baw_tail - rxtid->baw_head) &
-		(ATH_TID_MAX_BUFS - 1);
-
-	/*
-	 * If the ADDBA exchange has not been completed by the source,
-	 * process via legacy path (i.e. no reordering buffer is needed)
-	 */
-	if (!rxtid->addba_exchangecomplete) {
-		spin_unlock(&rxtid->tidlock);
-		return ath_rx_subframe(an, skb, rx_status);
-	}
-
-	/* extract sequence number from recvd frame */
-
-	rxseq = le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
-
-	if (rxtid->seq_reset) {
-		rxtid->seq_reset = 0;
-		rxtid->seq_next = rxseq;
-	}
-
-	index = ATH_BA_INDEX(rxtid->seq_next, rxseq);
-
-	/* drop frame if old sequence (index is too large) */
-
-	if (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))) {
-		/* discard frame, ieee layer may not treat frame as a dup */
-		spin_unlock(&rxtid->tidlock);
-		dev_kfree_skb(skb);
-		return IEEE80211_FTYPE_DATA;
-	}
-
-	/* sequence number is beyond block-ack window */
-
-	if (index >= rxtid->baw_size) {
-
-		/* complete receive processing for all pending frames */
-
-		while (index >= rxtid->baw_size) {
-
-			rxbuf = rxtid->rxbuf + rxtid->baw_head;
-
-			if (rxbuf->rx_wbuf != NULL) {
-				ath_rx_subframe(an, rxbuf->rx_wbuf,
-						&rxbuf->rx_status);
-				rxbuf->rx_wbuf = NULL;
-			}
-
-			INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-			INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-
-			index--;
-		}
-	}
-
-	/* add buffer to the recv ba window */
-
-	cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
-	rxbuf = rxtid->rxbuf + cindex;
-
-	if (rxbuf->rx_wbuf != NULL) {
-		spin_unlock(&rxtid->tidlock);
-		/* duplicate frame */
-		dev_kfree_skb(skb);
-		return IEEE80211_FTYPE_DATA;
-	}
-
-	rxbuf->rx_wbuf = skb;
-	rxbuf->rx_time = get_timestamp();
-	rxbuf->rx_status = *rx_status;
-
-	/* advance tail if sequence received is newer
-	 * than any received so far */
-
-	if (index >= rxdiff) {
-		rxtid->baw_tail = cindex;
-		INCR(rxtid->baw_tail, ATH_TID_MAX_BUFS);
-	}
-
-	/* indicate all in-order received frames */
-
-	while (rxtid->baw_head != rxtid->baw_tail) {
-		rxbuf = rxtid->rxbuf + rxtid->baw_head;
-		if (!rxbuf->rx_wbuf)
-			break;
-
-		ath_rx_subframe(an, rxbuf->rx_wbuf, &rxbuf->rx_status);
-		rxbuf->rx_wbuf = NULL;
-
-		INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-		INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-	}
-
-	/*
-	 * start a timer to flush all received frames if there are pending
-	 * receive frames
-	 */
-	if (rxtid->baw_head != rxtid->baw_tail)
-		mod_timer(&rxtid->timer, ATH_RX_TIMEOUT);
-	else
-		del_timer_sync(&rxtid->timer);
-
-	spin_unlock(&rxtid->tidlock);
-	return IEEE80211_FTYPE_DATA;
+	tsf = ath9k_hw_gettsf64(sc->sc_ah);
+	if ((tsf & 0x7fff) < rstamp)
+		tsf -= 0x8000;
+	return (tsf & ~0x7fff) | rstamp;
 }
 
-/* Timer to flush all received sub-frames */
-
-static void ath_rx_timer(unsigned long data)
-{
-	struct ath_arx_tid *rxtid = (struct ath_arx_tid *)data;
-	struct ath_node *an = rxtid->an;
-	struct ath_rxbuf *rxbuf;
-	int nosched;
-
-	spin_lock_bh(&rxtid->tidlock);
-	while (rxtid->baw_head != rxtid->baw_tail) {
-		rxbuf = rxtid->rxbuf + rxtid->baw_head;
-		if (!rxbuf->rx_wbuf) {
-			INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-			INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-			continue;
-		}
-
-		/*
-		 * Stop if the next one is a very recent frame.
-		 *
-		 * Call get_timestamp in every iteration to protect against the
-		 * case in which a new frame is received while we are executing
-		 * this function. Using a timestamp obtained before entering
-		 * the loop could lead to a very large time interval
-		 * (a negative value typecast to unsigned), breaking the
-		 * function's logic.
-		 */
-		if ((get_timestamp() - rxbuf->rx_time) <
-			(ATH_RX_TIMEOUT * HZ / 1000))
-			break;
-
-		ath_rx_subframe(an, rxbuf->rx_wbuf,
-				&rxbuf->rx_status);
-		rxbuf->rx_wbuf = NULL;
-
-		INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-		INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-	}
-
-	/*
-	 * start a timer to flush all received frames if there are pending
-	 * receive frames
-	 */
-	if (rxtid->baw_head != rxtid->baw_tail)
-		nosched = 0;
-	else
-		nosched = 1; /* no need to re-arm the timer again */
-
-	spin_unlock_bh(&rxtid->tidlock);
-}
-
-/* Free all pending sub-frames in the re-ordering buffer */
-
-static void ath_rx_flush_tid(struct ath_softc *sc,
-	struct ath_arx_tid *rxtid, int drop)
-{
-	struct ath_rxbuf *rxbuf;
-	unsigned long flag;
-
-	spin_lock_irqsave(&rxtid->tidlock, flag);
-	while (rxtid->baw_head != rxtid->baw_tail) {
-		rxbuf = rxtid->rxbuf + rxtid->baw_head;
-		if (!rxbuf->rx_wbuf) {
-			INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-			INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-			continue;
-		}
-
-		if (drop)
-			dev_kfree_skb(rxbuf->rx_wbuf);
-		else
-			ath_rx_subframe(rxtid->an,
-					rxbuf->rx_wbuf,
-					&rxbuf->rx_status);
-
-		rxbuf->rx_wbuf = NULL;
-
-		INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-		INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-	}
-	spin_unlock_irqrestore(&rxtid->tidlock, flag);
-}
-
-static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
-	u32 len)
+static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len)
 {
 	struct sk_buff *skb;
 	u32 off;
@@ -414,67 +104,131 @@
 			skb_reserve(skb, sc->sc_cachelsz - off);
 	} else {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: skbuff alloc of size %u failed\n",
-			__func__, len);
+			"skbuff alloc of size %u failed\n", len);
 		return NULL;
 	}
 
 	return skb;
 }
 
-static void ath_rx_requeue(struct ath_softc *sc, struct sk_buff *skb)
-{
-	struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf;
-
-	ASSERT(bf != NULL);
-
-	spin_lock_bh(&sc->sc_rxbuflock);
-	if (bf->bf_status & ATH_BUFSTATUS_STALE) {
-		/*
-		 * This buffer is still held for hw acess.
-		 * Mark it as free to be re-queued it later.
-		 */
-		bf->bf_status |= ATH_BUFSTATUS_FREE;
-	} else {
-		/* XXX: we probably never enter here, remove after
-		 * verification */
-		list_add_tail(&bf->list, &sc->sc_rxbuf);
-		ath_rx_buf_link(sc, bf);
-	}
-	spin_unlock_bh(&sc->sc_rxbuflock);
-}
-
 /*
- * The skb indicated to upper stack won't be returned to us.
- * So we have to allocate a new one and queue it by ourselves.
+ * For Decrypt or Demic errors, we only mark packet status here and always push
+ * up the frame up to let mac80211 handle the actual error case, be it no
+ * decryption key or real decryption error. This let us keep statistics there.
  */
-static int ath_rx_indicate(struct ath_softc *sc,
-			   struct sk_buff *skb,
-			   struct ath_recv_status *status,
-			   u16 keyix)
+static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
+			  struct ieee80211_rx_status *rx_status, bool *decrypt_error,
+			  struct ath_softc *sc)
 {
-	struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf;
-	struct sk_buff *nskb;
-	int type;
+	struct ieee80211_hdr *hdr;
+	u8 ratecode;
+	__le16 fc;
 
-	/* indicate frame to the stack, which will free the old skb. */
-	type = _ath_rx_indicate(sc, skb, status, keyix);
+	hdr = (struct ieee80211_hdr *)skb->data;
+	fc = hdr->frame_control;
+	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
 
-	/* allocate a new skb and queue it to for H/W processing */
-	nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
-	if (nskb != NULL) {
-		bf->bf_mpdu = nskb;
-		bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data,
-					 sc->sc_rxbufsize,
-					 PCI_DMA_FROMDEVICE);
-		bf->bf_dmacontext = bf->bf_buf_addr;
-		ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf;
+	if (ds->ds_rxstat.rs_more) {
+		/*
+		 * Frame spans multiple descriptors; this cannot happen yet
+		 * as we don't support jumbograms. If not in monitor mode,
+		 * discard the frame. Enable this if you want to see
+		 * error frames in Monitor mode.
+		 */
+		if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_MONITOR)
+			goto rx_next;
+	} else if (ds->ds_rxstat.rs_status != 0) {
+		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
+			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY)
+			goto rx_next;
 
-		/* queue the new wbuf to H/W */
-		ath_rx_requeue(sc, nskb);
+		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
+			*decrypt_error = true;
+		} else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
+			if (ieee80211_is_ctl(fc))
+				/*
+				 * Sometimes, we get invalid
+				 * MIC failures on valid control frames.
+				 * Remove these mic errors.
+				 */
+				ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC;
+			else
+				rx_status->flag |= RX_FLAG_MMIC_ERROR;
+		}
+		/*
+		 * Reject error frames with the exception of
+		 * decryption and MIC failures. For monitor mode,
+		 * we also ignore the CRC error.
+		 */
+		if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR) {
+			if (ds->ds_rxstat.rs_status &
+			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+			      ATH9K_RXERR_CRC))
+				goto rx_next;
+		} else {
+			if (ds->ds_rxstat.rs_status &
+			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
+				goto rx_next;
+			}
+		}
 	}
 
-	return type;
+	ratecode = ds->ds_rxstat.rs_rate;
+
+	if (ratecode & 0x80) {
+		/* HT rate */
+		rx_status->flag |= RX_FLAG_HT;
+		if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040)
+			rx_status->flag |= RX_FLAG_40MHZ;
+		if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
+			rx_status->flag |= RX_FLAG_SHORT_GI;
+		rx_status->rate_idx = ratecode & 0x7f;
+	} else {
+		int i = 0, cur_band, n_rates;
+		struct ieee80211_hw *hw = sc->hw;
+
+		cur_band = hw->conf.channel->band;
+		n_rates = sc->sbands[cur_band].n_bitrates;
+
+		for (i = 0; i < n_rates; i++) {
+			if (sc->sbands[cur_band].bitrates[i].hw_value ==
+			    ratecode) {
+				rx_status->rate_idx = i;
+				break;
+			}
+
+			if (sc->sbands[cur_band].bitrates[i].hw_value_short ==
+			    ratecode) {
+				rx_status->rate_idx = i;
+				rx_status->flag |= RX_FLAG_SHORTPRE;
+				break;
+			}
+		}
+	}
+
+	rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
+	rx_status->band = sc->hw->conf.channel->band;
+	rx_status->freq =  sc->hw->conf.channel->center_freq;
+	rx_status->noise = sc->sc_ani.sc_noise_floor;
+	rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
+	rx_status->antenna = ds->ds_rxstat.rs_antenna;
+
+	/* at 45 you will be able to use MCS 15 reliably. A more elaborate
+	 * scheme can be used here but it requires tables of SNR/throughput for
+	 * each possible mode used. */
+	rx_status->qual =  ds->ds_rxstat.rs_rssi * 100 / 45;
+
+	/* rssi can be more than 45 though, anything above that
+	 * should be considered at 100% */
+	if (rx_status->qual > 100)
+		rx_status->qual = 100;
+
+	rx_status->flag |= RX_FLAG_TSFT;
+
+	return 1;
+rx_next:
+	return 0;
 }
 
 static void ath_opmode_init(struct ath_softc *sc)
@@ -498,11 +252,7 @@
 
 	/* calculate and install multicast filter */
 	mfilt[0] = mfilt[1] = ~0;
-
 	ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
-	DPRINTF(sc, ATH_DBG_CONFIG ,
-		"%s: RX filter 0x%x, MC filter %08x:%08x\n",
-		__func__, rfilt, mfilt[0], mfilt[1]);
 }
 
 int ath_rx_init(struct ath_softc *sc, int nbufs)
@@ -512,38 +262,29 @@
 	int error = 0;
 
 	do {
-		spin_lock_init(&sc->sc_rxflushlock);
+		spin_lock_init(&sc->rx.rxflushlock);
 		sc->sc_flags &= ~SC_OP_RXFLUSH;
-		spin_lock_init(&sc->sc_rxbuflock);
+		spin_lock_init(&sc->rx.rxbuflock);
 
-		/*
-		 * Cisco's VPN software requires that drivers be able to
-		 * receive encapsulated frames that are larger than the MTU.
-		 * Since we can't be sure how large a frame we'll get, setup
-		 * to handle the larges on possible.
-		 */
-		sc->sc_rxbufsize = roundup(IEEE80211_MAX_MPDU_LEN,
+		sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
 					   min(sc->sc_cachelsz,
 					       (u16)64));
 
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: cachelsz %u rxbufsize %u\n",
-			__func__, sc->sc_cachelsz, sc->sc_rxbufsize);
+		DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
+			sc->sc_cachelsz, sc->rx.bufsize);
 
 		/* Initialize rx descriptors */
 
-		error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
+		error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
 					  "rx", nbufs, 1);
 		if (error != 0) {
 			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: failed to allocate rx descriptors: %d\n",
-				__func__, error);
+				"failed to allocate rx descriptors: %d\n", error);
 			break;
 		}
 
-		/* Pre-allocate a wbuf for each rx buffer */
-
-		list_for_each_entry(bf, &sc->sc_rxbuf, list) {
-			skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
+		list_for_each_entry(bf, &sc->rx.rxbuf, list) {
+			skb = ath_rxbuf_alloc(sc, sc->rx.bufsize);
 			if (skb == NULL) {
 				error = -ENOMEM;
 				break;
@@ -551,12 +292,20 @@
 
 			bf->bf_mpdu = skb;
 			bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data,
-					 sc->sc_rxbufsize,
-					 PCI_DMA_FROMDEVICE);
+							 sc->rx.bufsize,
+							 PCI_DMA_FROMDEVICE);
+			if (unlikely(pci_dma_mapping_error(sc->pdev,
+				  bf->bf_buf_addr))) {
+				dev_kfree_skb_any(skb);
+				bf->bf_mpdu = NULL;
+				DPRINTF(sc, ATH_DBG_CONFIG,
+					"pci_dma_mapping_error() on RX init\n");
+				error = -ENOMEM;
+				break;
+			}
 			bf->bf_dmacontext = bf->bf_buf_addr;
-			ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf;
 		}
-		sc->sc_rxlink = NULL;
+		sc->rx.rxlink = NULL;
 
 	} while (0);
 
@@ -566,23 +315,19 @@
 	return error;
 }
 
-/* Reclaim all rx queue resources */
-
 void ath_rx_cleanup(struct ath_softc *sc)
 {
 	struct sk_buff *skb;
 	struct ath_buf *bf;
 
-	list_for_each_entry(bf, &sc->sc_rxbuf, list) {
+	list_for_each_entry(bf, &sc->rx.rxbuf, list) {
 		skb = bf->bf_mpdu;
 		if (skb)
 			dev_kfree_skb(skb);
 	}
 
-	/* cleanup rx descriptors */
-
-	if (sc->sc_rxdma.dd_desc_len != 0)
-		ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+	if (sc->rx.rxdma.dd_desc_len != 0)
+		ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf);
 }
 
 /*
@@ -615,201 +360,115 @@
 		| ATH9K_RX_FILTER_MCAST;
 
 	/* If not a STA, enable processing of Probe Requests */
-	if (sc->sc_ah->ah_opmode != ATH9K_M_STA)
+	if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_STATION)
 		rfilt |= ATH9K_RX_FILTER_PROBEREQ;
 
 	/* Can't set HOSTAP into promiscous mode */
-	if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) &&
-	     (sc->rx_filter & FIF_PROMISC_IN_BSS)) ||
-	    (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) {
+	if (((sc->sc_ah->ah_opmode != NL80211_IFTYPE_AP) &&
+	     (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) ||
+	    (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR)) {
 		rfilt |= ATH9K_RX_FILTER_PROM;
 		/* ??? To prevent from sending ACK */
 		rfilt &= ~ATH9K_RX_FILTER_UCAST;
 	}
 
-	if (((sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
-	     (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) ||
-	    (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))
+	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION ||
+	    sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)
 		rfilt |= ATH9K_RX_FILTER_BEACON;
 
 	/* If in HOSTAP mode, want to enable reception of PSPOLL frames
 	   & beacon frames */
-	if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP)
+	if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP)
 		rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
+
 	return rfilt;
 
 #undef RX_FILTER_PRESERVE
 }
 
-/* Enable the receive h/w following a reset. */
-
 int ath_startrecv(struct ath_softc *sc)
 {
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_buf *bf, *tbf;
 
-	spin_lock_bh(&sc->sc_rxbuflock);
-	if (list_empty(&sc->sc_rxbuf))
+	spin_lock_bh(&sc->rx.rxbuflock);
+	if (list_empty(&sc->rx.rxbuf))
 		goto start_recv;
 
-	sc->sc_rxlink = NULL;
-	list_for_each_entry_safe(bf, tbf, &sc->sc_rxbuf, list) {
-		if (bf->bf_status & ATH_BUFSTATUS_STALE) {
-			/* restarting h/w, no need for holding descriptors */
-			bf->bf_status &= ~ATH_BUFSTATUS_STALE;
-			/*
-			 * Upper layer may not be done with the frame yet so
-			 * we can't just re-queue it to hardware. Remove it
-			 * from h/w queue. It'll be re-queued when upper layer
-			 * returns the frame and ath_rx_requeue_mpdu is called.
-			 */
-			if (!(bf->bf_status & ATH_BUFSTATUS_FREE)) {
-				list_del(&bf->list);
-				continue;
-			}
-		}
-		/* chain descriptors */
+	sc->rx.rxlink = NULL;
+	list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) {
 		ath_rx_buf_link(sc, bf);
 	}
 
 	/* We could have deleted elements so the list may be empty now */
-	if (list_empty(&sc->sc_rxbuf))
+	if (list_empty(&sc->rx.rxbuf))
 		goto start_recv;
 
-	bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list);
+	bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
 	ath9k_hw_putrxbuf(ah, bf->bf_daddr);
-	ath9k_hw_rxena(ah);      /* enable recv descriptors */
+	ath9k_hw_rxena(ah);
 
 start_recv:
-	spin_unlock_bh(&sc->sc_rxbuflock);
-	ath_opmode_init(sc);        /* set filters, etc. */
-	ath9k_hw_startpcureceive(ah);	/* re-enable PCU/DMA engine */
+	spin_unlock_bh(&sc->rx.rxbuflock);
+	ath_opmode_init(sc);
+	ath9k_hw_startpcureceive(ah);
+
 	return 0;
 }
 
-/* Disable the receive h/w in preparation for a reset. */
-
 bool ath_stoprecv(struct ath_softc *sc)
 {
 	struct ath_hal *ah = sc->sc_ah;
-	u64 tsf;
 	bool stopped;
 
-	ath9k_hw_stoppcurecv(ah);	/* disable PCU */
-	ath9k_hw_setrxfilter(ah, 0);	/* clear recv filter */
-	stopped = ath9k_hw_stopdmarecv(ah);	/* disable DMA engine */
-	mdelay(3);			/* 3ms is long enough for 1 frame */
-	tsf = ath9k_hw_gettsf64(ah);
-	sc->sc_rxlink = NULL;		/* just in case */
+	ath9k_hw_stoppcurecv(ah);
+	ath9k_hw_setrxfilter(ah, 0);
+	stopped = ath9k_hw_stopdmarecv(ah);
+	mdelay(3); /* 3ms is long enough for 1 frame */
+	sc->rx.rxlink = NULL;
+
 	return stopped;
 }
 
-/* Flush receive queue */
-
 void ath_flushrecv(struct ath_softc *sc)
 {
-	/*
-	 * ath_rx_tasklet may be used to handle rx interrupt and flush receive
-	 * queue at the same time. Use a lock to serialize the access of rx
-	 * queue.
-	 * ath_rx_tasklet cannot hold the spinlock while indicating packets.
-	 * Instead, do not claim the spinlock but check for a flush in
-	 * progress (see references to sc_rxflush)
-	 */
-	spin_lock_bh(&sc->sc_rxflushlock);
+	spin_lock_bh(&sc->rx.rxflushlock);
 	sc->sc_flags |= SC_OP_RXFLUSH;
-
 	ath_rx_tasklet(sc, 1);
-
 	sc->sc_flags &= ~SC_OP_RXFLUSH;
-	spin_unlock_bh(&sc->sc_rxflushlock);
+	spin_unlock_bh(&sc->rx.rxflushlock);
 }
 
-/* Process an individual frame */
-
-int ath_rx_input(struct ath_softc *sc,
-		 struct ath_node *an,
-		 int is_ampdu,
-		 struct sk_buff *skb,
-		 struct ath_recv_status *rx_status,
-		 enum ATH_RX_TYPE *status)
-{
-	if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) {
-		*status = ATH_RX_CONSUMED;
-		return ath_ampdu_input(sc, an, skb, rx_status);
-	} else {
-		*status = ATH_RX_NON_CONSUMED;
-		return -1;
-	}
-}
-
-/* Process receive queue, as well as LED, etc. */
-
 int ath_rx_tasklet(struct ath_softc *sc, int flush)
 {
 #define PA2DESC(_sc, _pa)                                               \
-	((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc +		\
-			     ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
+	((struct ath_desc *)((caddr_t)(_sc)->rx.rxdma.dd_desc +		\
+			     ((_pa) - (_sc)->rx.rxdma.dd_desc_paddr)))
 
-	struct ath_buf *bf, *bf_held = NULL;
+	struct ath_buf *bf;
 	struct ath_desc *ds;
-	struct ieee80211_hdr *hdr;
-	struct sk_buff *skb = NULL;
-	struct ath_recv_status rx_status;
+	struct sk_buff *skb = NULL, *requeue_skb;
+	struct ieee80211_rx_status rx_status;
 	struct ath_hal *ah = sc->sc_ah;
-	int type, rx_processed = 0;
-	u32 phyerr;
-	u8 chainreset = 0;
-	int retval;
-	__le16 fc;
+	struct ieee80211_hdr *hdr;
+	int hdrlen, padsize, retval;
+	bool decrypt_error = false;
+	u8 keyix;
+
+	spin_lock_bh(&sc->rx.rxbuflock);
 
 	do {
 		/* If handling rx interrupt and flush is in progress => exit */
 		if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
 			break;
 
-		spin_lock_bh(&sc->sc_rxbuflock);
-		if (list_empty(&sc->sc_rxbuf)) {
-			sc->sc_rxlink = NULL;
-			spin_unlock_bh(&sc->sc_rxbuflock);
+		if (list_empty(&sc->rx.rxbuf)) {
+			sc->rx.rxlink = NULL;
 			break;
 		}
 
-		bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list);
-
-		/*
-		 * There is a race condition that BH gets scheduled after sw
-		 * writes RxE and before hw re-load the last descriptor to get
-		 * the newly chained one. Software must keep the last DONE
-		 * descriptor as a holding descriptor - software does so by
-		 * marking it with the STALE flag.
-		 */
-		if (bf->bf_status & ATH_BUFSTATUS_STALE) {
-			bf_held = bf;
-			if (list_is_last(&bf_held->list, &sc->sc_rxbuf)) {
-				/*
-				 * The holding descriptor is the last
-				 * descriptor in queue. It's safe to
-				 * remove the last holding descriptor
-				 * in BH context.
-				 */
-				list_del(&bf_held->list);
-				bf_held->bf_status &= ~ATH_BUFSTATUS_STALE;
-				sc->sc_rxlink = NULL;
-
-				if (bf_held->bf_status & ATH_BUFSTATUS_FREE) {
-					list_add_tail(&bf_held->list,
-						&sc->sc_rxbuf);
-					ath_rx_buf_link(sc, bf_held);
-				}
-				spin_unlock_bh(&sc->sc_rxbuflock);
-				break;
-			}
-			bf = list_entry(bf->list.next, struct ath_buf, list);
-		}
-
+		bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
 		ds = bf->bf_desc;
-		++rx_processed;
 
 		/*
 		 * Must provide the virtual address of the current
@@ -822,8 +481,7 @@
 		 * on.  All this is necessary because of our use of
 		 * a self-linked list to avoid rx overruns.
 		 */
-		retval = ath9k_hw_rxprocdesc(ah,
-					     ds,
+		retval = ath9k_hw_rxprocdesc(ah, ds,
 					     bf->bf_daddr,
 					     PA2DESC(sc, ds->ds_link),
 					     0);
@@ -831,8 +489,8 @@
 			struct ath_buf *tbf;
 			struct ath_desc *tds;
 
-			if (list_is_last(&bf->list, &sc->sc_rxbuf)) {
-				spin_unlock_bh(&sc->sc_rxbuflock);
+			if (list_is_last(&bf->list, &sc->rx.rxbuf)) {
+				sc->rx.rxlink = NULL;
 				break;
 			}
 
@@ -850,451 +508,127 @@
 			 */
 
 			tds = tbf->bf_desc;
-			retval = ath9k_hw_rxprocdesc(ah,
-				tds, tbf->bf_daddr,
-				PA2DESC(sc, tds->ds_link), 0);
+			retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr,
+					     PA2DESC(sc, tds->ds_link), 0);
 			if (retval == -EINPROGRESS) {
-				spin_unlock_bh(&sc->sc_rxbuflock);
 				break;
 			}
 		}
 
-		/* XXX: we do not support frames spanning
-		 * multiple descriptors */
-		bf->bf_status |= ATH_BUFSTATUS_DONE;
-
 		skb = bf->bf_mpdu;
-		if (skb == NULL) {		/* XXX ??? can this happen */
-			spin_unlock_bh(&sc->sc_rxbuflock);
+		if (!skb)
 			continue;
-		}
+
 		/*
-		 * Now we know it's a completed frame, we can indicate the
-		 * frame. Remove the previous holding descriptor and leave
-		 * this one in the queue as the new holding descriptor.
+		 * Synchronize the DMA transfer with CPU before
+		 * 1. accessing the frame
+		 * 2. requeueing the same buffer to h/w
 		 */
-		if (bf_held) {
-			list_del(&bf_held->list);
-			bf_held->bf_status &= ~ATH_BUFSTATUS_STALE;
-			if (bf_held->bf_status & ATH_BUFSTATUS_FREE) {
-				list_add_tail(&bf_held->list, &sc->sc_rxbuf);
-				/* try to requeue this descriptor */
-				ath_rx_buf_link(sc, bf_held);
-			}
-		}
+		pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr,
+				sc->rx.bufsize,
+				PCI_DMA_FROMDEVICE);
 
-		bf->bf_status |= ATH_BUFSTATUS_STALE;
-		bf_held = bf;
 		/*
-		 * Release the lock here in case ieee80211_input() return
-		 * the frame immediately by calling ath_rx_mpdu_requeue().
+		 * If we're asked to flush receive queue, directly
+		 * chain it back at the queue without processing it.
 		 */
-		spin_unlock_bh(&sc->sc_rxbuflock);
+		if (flush)
+			goto requeue;
 
-		if (flush) {
-			/*
-			 * If we're asked to flush receive queue, directly
-			 * chain it back at the queue without processing it.
-			 */
-			goto rx_next;
-		}
+		if (!ds->ds_rxstat.rs_datalen)
+			goto requeue;
 
-		hdr = (struct ieee80211_hdr *)skb->data;
-		fc = hdr->frame_control;
-		memset(&rx_status, 0, sizeof(struct ath_recv_status));
+		/* The status portion of the descriptor could get corrupted. */
+		if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen)
+			goto requeue;
 
-		if (ds->ds_rxstat.rs_more) {
-			/*
-			 * Frame spans multiple descriptors; this
-			 * cannot happen yet as we don't support
-			 * jumbograms.  If not in monitor mode,
-			 * discard the frame.
-			 */
-#ifndef ERROR_FRAMES
-			/*
-			 * Enable this if you want to see
-			 * error frames in Monitor mode.
-			 */
-			if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR)
-				goto rx_next;
-#endif
-			/* fall thru for monitor mode handling... */
-		} else if (ds->ds_rxstat.rs_status != 0) {
-			if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
-				rx_status.flags |= ATH_RX_FCS_ERROR;
-			if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
-				phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
-				goto rx_next;
-			}
+		if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc))
+			goto requeue;
 
-			if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
-				/*
-				 * Decrypt error. We only mark packet status
-				 * here and always push up the frame up to let
-				 * mac80211 handle the actual error case, be
-				 * it no decryption key or real decryption
-				 * error. This let us keep statistics there.
-				 */
-				rx_status.flags |= ATH_RX_DECRYPT_ERROR;
-			} else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
-				/*
-				 * Demic error. We only mark frame status here
-				 * and always push up the frame up to let
-				 * mac80211 handle the actual error case. This
-				 * let us keep statistics there. Hardware may
-				 * post a false-positive MIC error.
-				 */
-				if (ieee80211_is_ctl(fc))
-					/*
-					 * Sometimes, we get invalid
-					 * MIC failures on valid control frames.
-					 * Remove these mic errors.
-					 */
-					ds->ds_rxstat.rs_status &=
-						~ATH9K_RXERR_MIC;
-				else
-					rx_status.flags |= ATH_RX_MIC_ERROR;
-			}
-			/*
-			 * Reject error frames with the exception of
-			 * decryption and MIC failures. For monitor mode,
-			 * we also ignore the CRC error.
-			 */
-			if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) {
-				if (ds->ds_rxstat.rs_status &
-				    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
-					ATH9K_RXERR_CRC))
-					goto rx_next;
-			} else {
-				if (ds->ds_rxstat.rs_status &
-				    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
-					goto rx_next;
-				}
-			}
-		}
-		/*
-		 * The status portion of the descriptor could get corrupted.
-		 */
-		if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen)
-			goto rx_next;
-		/*
-		 * Sync and unmap the frame.  At this point we're
-		 * committed to passing the sk_buff somewhere so
-		 * clear buf_skb; this means a new sk_buff must be
-		 * allocated when the rx descriptor is setup again
-		 * to receive another frame.
-		 */
-		skb_put(skb, ds->ds_rxstat.rs_datalen);
-		skb->protocol = cpu_to_be16(ETH_P_CONTROL);
-		rx_status.tsf = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
-		rx_status.rateieee =
-			sc->sc_hwmap[ds->ds_rxstat.rs_rate].ieeerate;
-		rx_status.rateKbps =
-			sc->sc_hwmap[ds->ds_rxstat.rs_rate].rateKbps;
-		rx_status.ratecode = ds->ds_rxstat.rs_rate;
+		/* Ensure we always have an skb to requeue once we are done
+		 * processing the current buffer's skb */
+		requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize);
 
-		/* HT rate */
-		if (rx_status.ratecode & 0x80) {
-			/* TODO - add table to avoid division */
-			if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) {
-				rx_status.flags |= ATH_RX_40MHZ;
-				rx_status.rateKbps =
-					(rx_status.rateKbps * 27) / 13;
-			}
-			if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
-				rx_status.rateKbps =
-					(rx_status.rateKbps * 10) / 9;
-			else
-				rx_status.flags |= ATH_RX_SHORT_GI;
-		}
+		/* If there is no memory we ignore the current RX'd frame,
+		 * tell hardware it can give us a new frame using the old
+		 * skb and put it at the tail of the sc->rx.rxbuf list for
+		 * processing. */
+		if (!requeue_skb)
+			goto requeue;
 
-		/* sc_noise_floor is only available when the station
-		   attaches to an AP, so we use a default value
-		   if we are not yet attached. */
-		rx_status.abs_rssi =
-			ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor;
-
-		pci_dma_sync_single_for_cpu(sc->pdev,
-					    bf->bf_buf_addr,
-					    sc->sc_rxbufsize,
-					    PCI_DMA_FROMDEVICE);
-		pci_unmap_single(sc->pdev,
-				 bf->bf_buf_addr,
-				 sc->sc_rxbufsize,
+		/* Unmap the frame */
+		pci_unmap_single(sc->pdev, bf->bf_buf_addr,
+				 sc->rx.bufsize,
 				 PCI_DMA_FROMDEVICE);
 
-		/* XXX: Ah! make me more readable, use a helper */
-		if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
-			if (ds->ds_rxstat.rs_moreaggr == 0) {
-				rx_status.rssictl[0] =
-					ds->ds_rxstat.rs_rssi_ctl0;
-				rx_status.rssictl[1] =
-					ds->ds_rxstat.rs_rssi_ctl1;
-				rx_status.rssictl[2] =
-					ds->ds_rxstat.rs_rssi_ctl2;
-				rx_status.rssi = ds->ds_rxstat.rs_rssi;
-				if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) {
-					rx_status.rssiextn[0] =
-						ds->ds_rxstat.rs_rssi_ext0;
-					rx_status.rssiextn[1] =
-						ds->ds_rxstat.rs_rssi_ext1;
-					rx_status.rssiextn[2] =
-						ds->ds_rxstat.rs_rssi_ext2;
-					rx_status.flags |=
-						ATH_RX_RSSI_EXTN_VALID;
-				}
-				rx_status.flags |= ATH_RX_RSSI_VALID |
-					ATH_RX_CHAIN_RSSI_VALID;
-			}
-		} else {
-			/*
-			 * Need to insert the "combined" rssi into the
-			 * status structure for upper layer processing
-			 */
-			rx_status.rssi = ds->ds_rxstat.rs_rssi;
-			rx_status.flags |= ATH_RX_RSSI_VALID;
+		skb_put(skb, ds->ds_rxstat.rs_datalen);
+		skb->protocol = cpu_to_be16(ETH_P_CONTROL);
+
+		/* see if any padding is done by the hw and remove it */
+		hdr = (struct ieee80211_hdr *)skb->data;
+		hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+
+		/* The MAC header is padded to have 32-bit boundary if the
+		 * packet payload is non-zero. The general calculation for
+		 * padsize would take into account odd header lengths:
+		 * padsize = (4 - hdrlen % 4) % 4; However, since only
+		 * even-length headers are used, padding can only be 0 or 2
+		 * bytes and we can optimize this a bit. In addition, we must
+		 * not try to remove padding from short control frames that do
+		 * not have payload. */
+		padsize = hdrlen & 3;
+		if (padsize && hdrlen >= 24) {
+			memmove(skb->data + padsize, skb->data, hdrlen);
+			skb_pull(skb, padsize);
 		}
 
-		/* Pass frames up to the stack. */
+		keyix = ds->ds_rxstat.rs_keyix;
 
-		type = ath_rx_indicate(sc, skb,
-			&rx_status, ds->ds_rxstat.rs_keyix);
+		if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
+			rx_status.flag |= RX_FLAG_DECRYPTED;
+		} else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
+			   && !decrypt_error && skb->len >= hdrlen + 4) {
+			keyix = skb->data[hdrlen + 3] >> 6;
+
+			if (test_bit(keyix, sc->sc_keymap))
+				rx_status.flag |= RX_FLAG_DECRYPTED;
+		}
+
+		/* Send the frame to mac80211 */
+		__ieee80211_rx(sc->hw, skb, &rx_status);
+
+		/* We will now give hardware our shiny new allocated skb */
+		bf->bf_mpdu = requeue_skb;
+		bf->bf_buf_addr = pci_map_single(sc->pdev, requeue_skb->data,
+					 sc->rx.bufsize,
+					 PCI_DMA_FROMDEVICE);
+		if (unlikely(pci_dma_mapping_error(sc->pdev,
+			  bf->bf_buf_addr))) {
+			dev_kfree_skb_any(requeue_skb);
+			bf->bf_mpdu = NULL;
+			DPRINTF(sc, ATH_DBG_CONFIG,
+				"pci_dma_mapping_error() on RX\n");
+			break;
+		}
+		bf->bf_dmacontext = bf->bf_buf_addr;
 
 		/*
 		 * change the default rx antenna if rx diversity chooses the
 		 * other antenna 3 times in a row.
 		 */
-		if (sc->sc_defant != ds->ds_rxstat.rs_antenna) {
-			if (++sc->sc_rxotherant >= 3)
-				ath_setdefantenna(sc,
-						ds->ds_rxstat.rs_antenna);
+		if (sc->rx.defant != ds->ds_rxstat.rs_antenna) {
+			if (++sc->rx.rxotherant >= 3)
+				ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna);
 		} else {
-			sc->sc_rxotherant = 0;
+			sc->rx.rxotherant = 0;
 		}
+requeue:
+		list_move_tail(&bf->list, &sc->rx.rxbuf);
+		ath_rx_buf_link(sc, bf);
+	} while (1);
 
-#ifdef CONFIG_SLOW_ANT_DIV
-		if ((rx_status.flags & ATH_RX_RSSI_VALID) &&
-		    ieee80211_is_beacon(fc)) {
-			ath_slow_ant_div(&sc->sc_antdiv, hdr, &ds->ds_rxstat);
-		}
-#endif
-		/*
-		 * For frames successfully indicated, the buffer will be
-		 * returned to us by upper layers by calling
-		 * ath_rx_mpdu_requeue, either synchronusly or asynchronously.
-		 * So we don't want to do it here in this loop.
-		 */
-		continue;
-
-rx_next:
-		bf->bf_status |= ATH_BUFSTATUS_FREE;
-	} while (TRUE);
-
-	if (chainreset) {
-		DPRINTF(sc, ATH_DBG_CONFIG,
-			"%s: Reset rx chain mask. "
-			"Do internal reset\n", __func__);
-		ASSERT(flush == 0);
-		ath_reset(sc, false);
-	}
+	spin_unlock_bh(&sc->rx.rxbuflock);
 
 	return 0;
 #undef PA2DESC
 }
-
-/* Process ADDBA request in per-TID data structure */
-
-int ath_rx_aggr_start(struct ath_softc *sc,
-		      const u8 *addr,
-		      u16 tid,
-		      u16 *ssn)
-{
-	struct ath_arx_tid *rxtid;
-	struct ath_node *an;
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_supported_band *sband;
-	u16 buffersize = 0;
-
-	spin_lock_bh(&sc->node_lock);
-	an = ath_node_find(sc, (u8 *) addr);
-	spin_unlock_bh(&sc->node_lock);
-
-	if (!an) {
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: Node not found to initialize RX aggregation\n",
-			__func__);
-		return -1;
-	}
-
-	sband = hw->wiphy->bands[hw->conf.channel->band];
-	buffersize = IEEE80211_MIN_AMPDU_BUF <<
-		sband->ht_info.ampdu_factor; /* FIXME */
-
-	rxtid = &an->an_aggr.rx.tid[tid];
-
-	spin_lock_bh(&rxtid->tidlock);
-	if (sc->sc_flags & SC_OP_RXAGGR) {
-		/* Allow aggregation reception
-		 * Adjust rx BA window size. Peer might indicate a
-		 * zero buffer size for a _dont_care_ condition.
-		 */
-		if (buffersize)
-			rxtid->baw_size = min(buffersize, rxtid->baw_size);
-
-		/* set rx sequence number */
-		rxtid->seq_next = *ssn;
-
-		/* Allocate the receive buffers for this TID */
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: Allcating rxbuffer for TID %d\n", __func__, tid);
-
-		if (rxtid->rxbuf == NULL) {
-			/*
-			* If the rxbuff is not NULL at this point, we *probably*
-			* already allocated the buffer on a previous ADDBA,
-			* and this is a subsequent ADDBA that got through.
-			* Don't allocate, but use the value in the pointer,
-			* we zero it out when we de-allocate.
-			*/
-			rxtid->rxbuf = kmalloc(ATH_TID_MAX_BUFS *
-				sizeof(struct ath_rxbuf), GFP_ATOMIC);
-		}
-		if (rxtid->rxbuf == NULL) {
-			DPRINTF(sc, ATH_DBG_AGGR,
-				"%s: Unable to allocate RX buffer, "
-				"refusing ADDBA\n", __func__);
-		} else {
-			/* Ensure the memory is zeroed out (all internal
-			 * pointers are null) */
-			memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS *
-				sizeof(struct ath_rxbuf));
-			DPRINTF(sc, ATH_DBG_AGGR,
-				"%s: Allocated @%p\n", __func__, rxtid->rxbuf);
-
-			/* Allow aggregation reception */
-			rxtid->addba_exchangecomplete = 1;
-		}
-	}
-	spin_unlock_bh(&rxtid->tidlock);
-
-	return 0;
-}
-
-/* Process DELBA */
-
-int ath_rx_aggr_stop(struct ath_softc *sc,
-		     const u8 *addr,
-		     u16 tid)
-{
-	struct ath_node *an;
-
-	spin_lock_bh(&sc->node_lock);
-	an = ath_node_find(sc, (u8 *) addr);
-	spin_unlock_bh(&sc->node_lock);
-
-	if (!an) {
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: RX aggr stop for non-existent node\n", __func__);
-		return -1;
-	}
-
-	ath_rx_aggr_teardown(sc, an, tid);
-	return 0;
-}
-
-/* Rx aggregation tear down */
-
-void ath_rx_aggr_teardown(struct ath_softc *sc,
-	struct ath_node *an, u8 tid)
-{
-	struct ath_arx_tid *rxtid = &an->an_aggr.rx.tid[tid];
-
-	if (!rxtid->addba_exchangecomplete)
-		return;
-
-	del_timer_sync(&rxtid->timer);
-	ath_rx_flush_tid(sc, rxtid, 0);
-	rxtid->addba_exchangecomplete = 0;
-
-	/* De-allocate the receive buffer array allocated when addba started */
-
-	if (rxtid->rxbuf) {
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: Deallocating TID %d rxbuff @%p\n",
-			__func__, tid, rxtid->rxbuf);
-		kfree(rxtid->rxbuf);
-
-		/* Set pointer to null to avoid reuse*/
-		rxtid->rxbuf = NULL;
-	}
-}
-
-/* Initialize per-node receive state */
-
-void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an)
-{
-	if (sc->sc_flags & SC_OP_RXAGGR) {
-		struct ath_arx_tid *rxtid;
-		int tidno;
-
-		/* Init per tid rx state */
-		for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno];
-				tidno < WME_NUM_TID;
-				tidno++, rxtid++) {
-			rxtid->an        = an;
-			rxtid->seq_reset = 1;
-			rxtid->seq_next  = 0;
-			rxtid->baw_size  = WME_MAX_BA;
-			rxtid->baw_head  = rxtid->baw_tail = 0;
-
-			/*
-			 * Ensure the buffer pointer is null at this point
-			 * (needs to be allocated when addba is received)
-			*/
-
-			rxtid->rxbuf     = NULL;
-			setup_timer(&rxtid->timer, ath_rx_timer,
-				(unsigned long)rxtid);
-			spin_lock_init(&rxtid->tidlock);
-
-			/* ADDBA state */
-			rxtid->addba_exchangecomplete = 0;
-		}
-	}
-}
-
-void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
-{
-	if (sc->sc_flags & SC_OP_RXAGGR) {
-		struct ath_arx_tid *rxtid;
-		int tidno, i;
-
-		/* Init per tid rx state */
-		for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno];
-				tidno < WME_NUM_TID;
-				tidno++, rxtid++) {
-
-			if (!rxtid->addba_exchangecomplete)
-				continue;
-
-			/* must cancel timer first */
-			del_timer_sync(&rxtid->timer);
-
-			/* drop any pending sub-frames */
-			ath_rx_flush_tid(sc, rxtid, 1);
-
-			for (i = 0; i < ATH_TID_MAX_BUFS; i++)
-				ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL);
-
-			rxtid->addba_exchangecomplete = 0;
-		}
-	}
-
-}
-
-/* Cleanup per-node receive state */
-
-void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an)
-{
-	ath_rx_node_cleanup(sc, an);
-}
diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h
index 60617ae..9fedb49 100644
--- a/drivers/net/wireless/ath9k/reg.h
+++ b/drivers/net/wireless/ath9k/reg.h
@@ -671,7 +671,11 @@
 #define AR_RC_APB            0x00000002
 #define AR_RC_HOSTIF         0x00000100
 
-#define AR_WA                0x4004
+#define AR_WA                		0x4004
+#define AR9285_WA_DEFAULT 		0x004a05cb
+#define AR9280_WA_DEFAULT           	0x0040073f
+#define AR_WA_DEFAULT               	0x0000073f
+
 
 #define AR_PM_STATE                 0x4008
 #define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000
@@ -738,6 +742,8 @@
 #define AR_SREV_REVISION_9280_21            2
 #define AR_SREV_VERSION_9285                  0xC0
 #define AR_SREV_REVISION_9285_10              0
+#define AR_SREV_REVISION_9285_11              1
+#define AR_SREV_REVISION_9285_12              2
 
 #define AR_SREV_9100_OR_LATER(_ah) \
 	(((_ah)->ah_macVersion >= AR_SREV_VERSION_5416_PCIE))
@@ -768,6 +774,16 @@
 #define AR_SREV_9285(_ah) (((_ah)->ah_macVersion == AR_SREV_VERSION_9285))
 #define AR_SREV_9285_10_OR_LATER(_ah) \
 	(((_ah)->ah_macVersion >= AR_SREV_VERSION_9285))
+#define AR_SREV_9285_11(_ah) \
+	(AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_11))
+#define AR_SREV_9285_11_OR_LATER(_ah) \
+	(((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \
+	 (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_11)))
+#define AR_SREV_9285_12(_ah) \
+	(AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_12))
+#define AR_SREV_9285_12_OR_LATER(_ah) \
+	(((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \
+	 (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_12)))
 
 #define AR_RADIO_SREV_MAJOR                   0xf0
 #define AR_RAD5133_SREV_MAJOR                 0xc0
@@ -1017,6 +1033,97 @@
 #define AR_AN_SYNTH9_REFDIVA    0xf8000000
 #define AR_AN_SYNTH9_REFDIVA_S  27
 
+#define AR9285_AN_RF2G1              0x7820
+#define AR9285_AN_RF2G1_ENPACAL      0x00000800
+#define AR9285_AN_RF2G1_ENPACAL_S    11
+#define AR9285_AN_RF2G1_PDPADRV1     0x02000000
+#define AR9285_AN_RF2G1_PDPADRV1_S   25
+#define AR9285_AN_RF2G1_PDPADRV2     0x01000000
+#define AR9285_AN_RF2G1_PDPADRV2_S   24
+#define AR9285_AN_RF2G1_PDPAOUT      0x00800000
+#define AR9285_AN_RF2G1_PDPAOUT_S    23
+
+
+#define AR9285_AN_RF2G2              0x7824
+#define AR9285_AN_RF2G2_OFFCAL       0x00001000
+#define AR9285_AN_RF2G2_OFFCAL_S     12
+
+#define AR9285_AN_RF2G3             0x7828
+#define AR9285_AN_RF2G3_PDVCCOMP    0x02000000
+#define AR9285_AN_RF2G3_PDVCCOMP_S  25
+#define AR9285_AN_RF2G3_OB_0    0x00E00000
+#define AR9285_AN_RF2G3_OB_0_S    21
+#define AR9285_AN_RF2G3_OB_1    0x001C0000
+#define AR9285_AN_RF2G3_OB_1_S    18
+#define AR9285_AN_RF2G3_OB_2    0x00038000
+#define AR9285_AN_RF2G3_OB_2_S    15
+#define AR9285_AN_RF2G3_OB_3    0x00007000
+#define AR9285_AN_RF2G3_OB_3_S    12
+#define AR9285_AN_RF2G3_OB_4    0x00000E00
+#define AR9285_AN_RF2G3_OB_4_S    9
+
+#define AR9285_AN_RF2G3_DB1_0    0x000001C0
+#define AR9285_AN_RF2G3_DB1_0_S    6
+#define AR9285_AN_RF2G3_DB1_1    0x00000038
+#define AR9285_AN_RF2G3_DB1_1_S    3
+#define AR9285_AN_RF2G3_DB1_2    0x00000007
+#define AR9285_AN_RF2G3_DB1_2_S    0
+#define AR9285_AN_RF2G4         0x782C
+#define AR9285_AN_RF2G4_DB1_3    0xE0000000
+#define AR9285_AN_RF2G4_DB1_3_S    29
+#define AR9285_AN_RF2G4_DB1_4    0x1C000000
+#define AR9285_AN_RF2G4_DB1_4_S    26
+
+#define AR9285_AN_RF2G4_DB2_0    0x03800000
+#define AR9285_AN_RF2G4_DB2_0_S    23
+#define AR9285_AN_RF2G4_DB2_1    0x00700000
+#define AR9285_AN_RF2G4_DB2_1_S    20
+#define AR9285_AN_RF2G4_DB2_2    0x000E0000
+#define AR9285_AN_RF2G4_DB2_2_S    17
+#define AR9285_AN_RF2G4_DB2_3    0x0001C000
+#define AR9285_AN_RF2G4_DB2_3_S    14
+#define AR9285_AN_RF2G4_DB2_4    0x00003800
+#define AR9285_AN_RF2G4_DB2_4_S    11
+
+#define AR9285_AN_RF2G6                 0x7834
+#define AR9285_AN_RF2G6_CCOMP           0x00007800
+#define AR9285_AN_RF2G6_CCOMP_S         11
+#define AR9285_AN_RF2G6_OFFS            0x03f00000
+#define AR9285_AN_RF2G6_OFFS_S          20
+
+#define AR9285_AN_RF2G7                 0x7838
+#define AR9285_AN_RF2G7_PWDDB           0x00000002
+#define AR9285_AN_RF2G7_PWDDB_S         1
+#define AR9285_AN_RF2G7_PADRVGN2TAB0    0xE0000000
+#define AR9285_AN_RF2G7_PADRVGN2TAB0_S  29
+
+#define AR9285_AN_RF2G8                  0x783C
+#define AR9285_AN_RF2G8_PADRVGN2TAB0     0x0001C000
+#define AR9285_AN_RF2G8_PADRVGN2TAB0_S   14
+
+
+#define AR9285_AN_RF2G9          0x7840
+#define AR9285_AN_RXTXBB1              0x7854
+#define AR9285_AN_RXTXBB1_PDRXTXBB1    0x00000020
+#define AR9285_AN_RXTXBB1_PDRXTXBB1_S  5
+#define AR9285_AN_RXTXBB1_PDV2I        0x00000080
+#define AR9285_AN_RXTXBB1_PDV2I_S      7
+#define AR9285_AN_RXTXBB1_PDDACIF      0x00000100
+#define AR9285_AN_RXTXBB1_PDDACIF_S    8
+#define AR9285_AN_RXTXBB1_SPARE9       0x00000001
+#define AR9285_AN_RXTXBB1_SPARE9_S     0
+
+#define AR9285_AN_TOP2           0x7868
+
+#define AR9285_AN_TOP3                  0x786c
+#define AR9285_AN_TOP3_XPABIAS_LVL      0x0000000C
+#define AR9285_AN_TOP3_XPABIAS_LVL_S    2
+#define AR9285_AN_TOP3_PWDDAC           0x00800000
+#define AR9285_AN_TOP3_PWDDAC_S    23
+
+#define AR9285_AN_TOP4           0x7870
+#define AR9285_AN_TOP4_DEFAULT   0x10142c00
+
 #define AR_STA_ID0                 0x8000
 #define AR_STA_ID1                 0x8004
 #define AR_STA_ID1_SADH_MASK       0x0000FFFF
diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c
index 62e2888..64043e9 100644
--- a/drivers/net/wireless/ath9k/regd.c
+++ b/drivers/net/wireless/ath9k/regd.c
@@ -42,7 +42,7 @@
 			u8 *u = t - size;
 			if (cmp(u, t) <= 0)
 				break;
-			swap(u, t, size);
+			swap_array(u, t, size);
 		}
 }
 
@@ -78,8 +78,7 @@
 				return true;
 	}
 	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-		 "%s: invalid regulatory domain/country code 0x%x\n",
-		 __func__, rd);
+		 "invalid regulatory domain/country code 0x%x\n", rd);
 	return false;
 }
 
@@ -107,13 +106,12 @@
 		return true;
 
 	rd = ath9k_regd_get_eepromRD(ah);
-	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: EEPROM regdomain 0x%x\n",
-		 __func__, rd);
+	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "EEPROM regdomain 0x%x\n", rd);
 
 	if (rd & COUNTRY_ERD_FLAG) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"%s: EEPROM setting is country code %u\n",
-			__func__, rd & ~COUNTRY_ERD_FLAG);
+			"EEPROM setting is country code %u\n",
+			rd & ~COUNTRY_ERD_FLAG);
 		return cc == (rd & ~COUNTRY_ERD_FLAG);
 	}
 
@@ -290,8 +288,7 @@
 		}
 		if (!found) {
 			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-				"%s: Failed to find reg domain pair %u\n",
-				__func__, regDmn);
+				"Failed to find reg domain pair %u\n", regDmn);
 			return false;
 		}
 		if (!(channelFlag & CHANNEL_2GHZ)) {
@@ -307,8 +304,7 @@
 	found = ath9k_regd_is_valid_reg_domain(regDmn, rd);
 	if (!found) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"%s: Failed to find unitary reg domain %u\n",
-			__func__, regDmn);
+			"Failed to find unitary reg domain %u\n", regDmn);
 		return false;
 	} else {
 		rd->pscan &= regPair->pscanMask;
@@ -430,30 +426,27 @@
 
 	if (!(c_lo <= c && c <= c_hi)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"%s: c %u out of range [%u..%u]\n",
-			__func__, c, c_lo, c_hi);
+			"c %u out of range [%u..%u]\n",
+			c, c_lo, c_hi);
 		return false;
 	}
 	if ((fband->channelBW == CHANNEL_HALF_BW) &&
 	    !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_HALFRATE)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"%s: Skipping %u half rate channel\n",
-			__func__, c);
+			"Skipping %u half rate channel\n", c);
 		return false;
 	}
 
 	if ((fband->channelBW == CHANNEL_QUARTER_BW) &&
 	    !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_QUARTERRATE)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"%s: Skipping %u quarter rate channel\n",
-			__func__, c);
+			"Skipping %u quarter rate channel\n", c);
 		return false;
 	}
 
 	if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"%s: c %u > maxChan %u\n",
-			__func__, c, maxChan);
+			"c %u > maxChan %u\n", c, maxChan);
 		return false;
 	}
 
@@ -463,7 +456,7 @@
 		return false;
 	}
 
-	if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == ATH9K_M_HOSTAP)) {
+	if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == NL80211_IFTYPE_AP)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
 			"Skipping HOSTAP channel\n");
 		return false;
@@ -606,8 +599,7 @@
 	}
 
 	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-		"%s: Skipping %d freq band\n",
-		__func__, j_bandcheck[i].freqbandbit);
+		"Skipping %d freq band\n", j_bandcheck[i].freqbandbit);
 
 	return skipband;
 }
@@ -632,20 +624,19 @@
 	unsigned long *modes_avail;
 	DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX);
 
-	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: cc %u %s %s\n",
-		 __func__, cc,
+	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "cc %u %s %s\n", cc,
 		 enableOutdoor ? "Enable outdoor" : "",
 		 enableExtendedChannels ? "Enable ecm" : "");
 
 	if (!ath9k_regd_is_ccode_valid(ah, cc)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"%s: invalid country code %d\n", __func__, cc);
+			"Invalid country code %d\n", cc);
 		return false;
 	}
 
 	if (!ath9k_regd_is_eeprom_valid(ah)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"%s: invalid EEPROM contents\n", __func__);
+			"Invalid EEPROM contents\n");
 		return false;
 	}
 
@@ -693,9 +684,9 @@
 					    ~CHANNEL_2GHZ,
 					    &rd5GHz)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"%s: couldn't find unitary "
+			"Couldn't find unitary "
 			"5GHz reg domain for country %u\n",
-			__func__, ah->ah_countryCode);
+			ah->ah_countryCode);
 		return false;
 	}
 	if (!ath9k_regd_get_wmode_regdomain(ah,
@@ -703,9 +694,9 @@
 					    CHANNEL_2GHZ,
 					    &rd2GHz)) {
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"%s: couldn't find unitary 2GHz "
+			"Couldn't find unitary 2GHz "
 			"reg domain for country %u\n",
-			__func__, ah->ah_countryCode);
+			ah->ah_countryCode);
 		return false;
 	}
 
@@ -717,9 +708,9 @@
 							    ~CHANNEL_2GHZ,
 							    &rd5GHz)) {
 				DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-					"%s: couldn't find unitary 5GHz "
+					"Couldn't find unitary 5GHz "
 					"reg domain for country %u\n",
-					__func__, ah->ah_countryCode);
+					ah->ah_countryCode);
 				return false;
 			}
 		}
@@ -749,15 +740,14 @@
 
 		if (!test_bit(cm->mode, modes_avail)) {
 			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-				"%s: !avail mode %d flags 0x%x\n",
-				__func__, cm->mode, cm->flags);
+				"!avail mode %d flags 0x%x\n",
+				cm->mode, cm->flags);
 			continue;
 		}
 		if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) {
 			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-				"%s: channels 0x%x not supported "
-				"by hardware\n",
-				__func__, cm->flags);
+				"channels 0x%x not supported "
+				"by hardware\n", cm->flags);
 			continue;
 		}
 
@@ -788,8 +778,7 @@
 			break;
 		default:
 			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-				"%s: Unknown HAL mode 0x%x\n", __func__,
-				cm->mode);
+				"Unknown HAL mode 0x%x\n", cm->mode);
 			continue;
 		}
 
@@ -841,9 +830,8 @@
 					if (next >= maxchans) {
 						DPRINTF(ah->ah_sc,
 							ATH_DBG_REGULATORY,
-							"%s: too many channels "
-							"for channel table\n",
-							__func__);
+							"too many channels "
+							"for channel table\n");
 						goto done;
 					}
 					if (ath9k_regd_add_channel(ah,
@@ -869,9 +857,8 @@
 
 		if (next > ARRAY_SIZE(ah->ah_channels)) {
 			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-				"%s: too many channels %u; truncating to %u\n",
-				__func__, next,
-				(int) ARRAY_SIZE(ah->ah_channels));
+				"too many channels %u; truncating to %u\n",
+				next, (int) ARRAY_SIZE(ah->ah_channels));
 			next = ARRAY_SIZE(ah->ah_channels);
 		}
 #ifdef ATH_NF_PER_CHAN
@@ -919,7 +906,7 @@
 	int n, lim;
 
 	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-		"%s: channel %u/0x%x (0x%x) requested\n", __func__,
+		"channel %u/0x%x (0x%x) requested\n",
 		c->channel, c->channelFlags, flags);
 
 	cc = ah->ah_curchan;
@@ -950,15 +937,15 @@
 			d = flags - (cc->channelFlags & CHAN_FLAGS);
 		}
 		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-			"%s: channel %u/0x%x d %d\n", __func__,
+			"channel %u/0x%x d %d\n",
 			cc->channel, cc->channelFlags, d);
 		if (d > 0) {
 			base = cc + 1;
 			lim--;
 		}
 	}
-	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: no match for %u/0x%x\n",
-		__func__, c->channel, c->channelFlags);
+	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "no match for %u/0x%x\n",
+		c->channel, c->channelFlags);
 	return NULL;
 }
 
diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h
index 0ecd344..512d990 100644
--- a/drivers/net/wireless/ath9k/regd.h
+++ b/drivers/net/wireless/ath9k/regd.h
@@ -125,7 +125,7 @@
 
 #define CHAN_FLAGS      (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER)
 
-#define swap(_a, _b, _size) {                   \
+#define swap_array(_a, _b, _size) {                   \
 	u8 *s = _b;                       \
 	int i = _size;                          \
 	do {                                    \
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
index 3a47579..3bfc3b9 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -14,10 +14,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/*
- * Implementation of transmit path.
- */
-
 #include "core.h"
 
 #define BITS_PER_BYTE           8
@@ -65,11 +61,12 @@
  * NB: must be called with txq lock held
  */
 
-static void ath_tx_txqaddbuf(struct ath_softc *sc,
-		struct ath_txq *txq, struct list_head *head)
+static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
+			     struct list_head *head)
 {
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_buf *bf;
+
 	/*
 	 * Insert the frame on the outbound list and
 	 * pass it on to the hardware.
@@ -86,18 +83,16 @@
 	txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
 
 	DPRINTF(sc, ATH_DBG_QUEUE,
-		"%s: txq depth = %d\n", __func__, txq->axq_depth);
+		"qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
 
 	if (txq->axq_link == NULL) {
 		ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
 		DPRINTF(sc, ATH_DBG_XMIT,
-			"%s: TXDP[%u] = %llx (%p)\n",
-			__func__, txq->axq_qnum,
-			ito64(bf->bf_daddr), bf->bf_desc);
+			"TXDP[%u] = %llx (%p)\n",
+			txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
 	} else {
 		*txq->axq_link = bf->bf_daddr;
-		DPRINTF(sc, ATH_DBG_XMIT, "%s: link[%u] (%p)=%llx (%p)\n",
-			__func__,
+		DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n",
 			txq->axq_qnum, txq->axq_link,
 			ito64(bf->bf_daddr), bf->bf_desc);
 	}
@@ -105,46 +100,94 @@
 	ath9k_hw_txstart(ah, txq->axq_qnum);
 }
 
-/* Get transmit rate index using rate in Kbps */
-
-static int ath_tx_findindex(const struct ath9k_rate_table *rt, int rate)
+static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
+			    struct ath_xmit_status *tx_status)
 {
-	int i;
-	int ndx = 0;
+	struct ieee80211_hw *hw = sc->hw;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+	int hdrlen, padsize;
 
-	for (i = 0; i < rt->rateCount; i++) {
-		if (rt->info[i].rateKbps == rate) {
-			ndx = i;
-			break;
-		}
+	DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
+
+	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
+	    tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
+		kfree(tx_info_priv);
+		tx_info->rate_driver_data[0] = NULL;
 	}
 
-	return ndx;
+	if (tx_status->flags & ATH_TX_BAR) {
+		tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+		tx_status->flags &= ~ATH_TX_BAR;
+	}
+
+	if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
+		/* Frame was ACKed */
+		tx_info->flags |= IEEE80211_TX_STAT_ACK;
+	}
+
+	tx_info->status.rates[0].count = tx_status->retries;
+	if (tx_info->status.rates[0].flags & IEEE80211_TX_RC_MCS) {
+		/* Change idx from internal table index to MCS index */
+		int idx = tx_info->status.rates[0].idx;
+		struct ath_rate_table *rate_table = sc->cur_rate_table;
+		if (idx >= 0 && idx < rate_table->rate_cnt)
+			tx_info->status.rates[0].idx =
+				rate_table->info[idx].ratecode & 0x7f;
+	}
+
+	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+	padsize = hdrlen & 3;
+	if (padsize && hdrlen >= 24) {
+		/*
+		 * Remove MAC header padding before giving the frame back to
+		 * mac80211.
+		 */
+		memmove(skb->data + padsize, skb->data, hdrlen);
+		skb_pull(skb, padsize);
+	}
+
+	ieee80211_tx_status(hw, skb);
 }
 
 /* Check if it's okay to send out aggregates */
 
-static int ath_aggr_query(struct ath_softc *sc,
-	struct ath_node *an, u8 tidno)
+static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno)
 {
 	struct ath_atx_tid *tid;
 	tid = ATH_AN_2_TID(an, tidno);
 
-	if (tid->addba_exchangecomplete || tid->addba_exchangeinprogress)
+	if (tid->state & AGGR_ADDBA_COMPLETE ||
+	    tid->state & AGGR_ADDBA_PROGRESS)
 		return 1;
 	else
 		return 0;
 }
 
-static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr)
+static void ath_get_beaconconfig(struct ath_softc *sc, int if_id,
+				 struct ath_beacon_config *conf)
 {
+	struct ieee80211_hw *hw = sc->hw;
+
+	/* fill in beacon config data */
+
+	conf->beacon_interval = hw->conf.beacon_int;
+	conf->listen_interval = 100;
+	conf->dtim_count = 1;
+	conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
+}
+
+/* Calculate Atheros packet type from IEEE80211 packet header */
+
+static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr;
 	enum ath9k_pkt_type htype;
 	__le16 fc;
 
+	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = hdr->frame_control;
 
-	/* Calculate Atheros packet type from IEEE80211 packet header */
-
 	if (ieee80211_is_beacon(fc))
 		htype = ATH9K_PKT_TYPE_BEACON;
 	else if (ieee80211_is_probe_resp(fc))
@@ -159,232 +202,123 @@
 	return htype;
 }
 
-static void fill_min_rates(struct sk_buff *skb, struct ath_tx_control *txctl)
+static bool is_pae(struct sk_buff *skb)
 {
 	struct ieee80211_hdr *hdr;
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct ath_tx_info_priv *tx_info_priv;
 	__le16 fc;
 
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = hdr->frame_control;
-	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
 
-	if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
-		txctl->use_minrate = 1;
-		txctl->min_rate = tx_info_priv->min_rate;
-	} else if (ieee80211_is_data(fc)) {
+	if (ieee80211_is_data(fc)) {
 		if (ieee80211_is_nullfunc(fc) ||
-			/* Port Access Entity (IEEE 802.1X) */
-			(skb->protocol == cpu_to_be16(0x888E))) {
-			txctl->use_minrate = 1;
-			txctl->min_rate = tx_info_priv->min_rate;
+		    /* Port Access Entity (IEEE 802.1X) */
+		    (skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+			return true;
 		}
-		if (is_multicast_ether_addr(hdr->addr1))
-			txctl->mcast_rate = tx_info_priv->min_rate;
 	}
 
+	return false;
 }
 
-/* This function will setup additional txctl information, mostly rate stuff */
-/* FIXME: seqno, ps */
-static int ath_tx_prepare(struct ath_softc *sc,
-			  struct sk_buff *skb,
-			  struct ath_tx_control *txctl)
+static int get_hw_crypto_keytype(struct sk_buff *skb)
 {
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_hdr *hdr;
-	struct ath_rc_series *rcs;
-	struct ath_txq *txq = NULL;
-	const struct ath9k_rate_table *rt;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct ath_tx_info_priv *tx_info_priv;
-	int hdrlen;
-	u8 rix, antenna;
+
+	if (tx_info->control.hw_key) {
+		if (tx_info->control.hw_key->alg == ALG_WEP)
+			return ATH9K_KEY_TYPE_WEP;
+		else if (tx_info->control.hw_key->alg == ALG_TKIP)
+			return ATH9K_KEY_TYPE_TKIP;
+		else if (tx_info->control.hw_key->alg == ALG_CCMP)
+			return ATH9K_KEY_TYPE_AES;
+	}
+
+	return ATH9K_KEY_TYPE_CLEAR;
+}
+
+/* Called only when tx aggregation is enabled and HT is supported */
+
+static void assign_aggr_tid_seqno(struct sk_buff *skb,
+				  struct ath_buf *bf)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr;
+	struct ath_node *an;
+	struct ath_atx_tid *tid;
 	__le16 fc;
 	u8 *qc;
 
-	txctl->dev = sc;
+	if (!tx_info->control.sta)
+		return;
+
+	an = (struct ath_node *)tx_info->control.sta->drv_priv;
 	hdr = (struct ieee80211_hdr *)skb->data;
-	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
 	fc = hdr->frame_control;
 
-	rt = sc->sc_currates;
-	BUG_ON(!rt);
-
-	/* Fill misc fields */
-
-	spin_lock_bh(&sc->node_lock);
-	txctl->an = ath_node_get(sc, hdr->addr1);
-	/* create a temp node, if the node is not there already */
-	if (!txctl->an)
-		txctl->an = ath_node_attach(sc, hdr->addr1, 0);
-	spin_unlock_bh(&sc->node_lock);
+	/* Get tidno */
 
 	if (ieee80211_is_data_qos(fc)) {
 		qc = ieee80211_get_qos_ctl(hdr);
-		txctl->tidno = qc[0] & 0xf;
+		bf->bf_tidno = qc[0] & 0xf;
 	}
 
-	txctl->if_id = 0;
-	txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3);
-	txctl->txpower = MAX_RATE_POWER; /* FIXME */
+	/* Get seqno */
 
-	/* Fill Key related fields */
-
-	txctl->keytype = ATH9K_KEY_TYPE_CLEAR;
-	txctl->keyix = ATH9K_TXKEYIX_INVALID;
-
-	if (tx_info->control.hw_key) {
-		txctl->keyix = tx_info->control.hw_key->hw_key_idx;
-		txctl->frmlen += tx_info->control.hw_key->icv_len;
-
-		if (tx_info->control.hw_key->alg == ALG_WEP)
-			txctl->keytype = ATH9K_KEY_TYPE_WEP;
-		else if (tx_info->control.hw_key->alg == ALG_TKIP)
-			txctl->keytype = ATH9K_KEY_TYPE_TKIP;
-		else if (tx_info->control.hw_key->alg == ALG_CCMP)
-			txctl->keytype = ATH9K_KEY_TYPE_AES;
-	}
-
-	/* Fill packet type */
-
-	txctl->atype = get_hal_packet_type(hdr);
-
-	/* Fill qnum */
-
-	if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) {
-		txctl->qnum = 0;
-		txq = sc->sc_cabq;
-	} else {
-		txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
-		txq = &sc->sc_txq[txctl->qnum];
-	}
-	spin_lock_bh(&txq->axq_lock);
-
-	/* Try to avoid running out of descriptors */
-	if (txq->axq_depth >= (ATH_TXBUF - 20) &&
-	    !(txctl->flags & ATH9K_TXDESC_CAB)) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: TX queue: %d is full, depth: %d\n",
-			__func__,
-			txctl->qnum,
-			txq->axq_depth);
-		ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
-		txq->stopped = 1;
-		spin_unlock_bh(&txq->axq_lock);
-		return -1;
-	}
-
-	spin_unlock_bh(&txq->axq_lock);
-
-	/* Fill rate */
-
-	fill_min_rates(skb, txctl);
-
-	/* Fill flags */
-
-	txctl->flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
-
-	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
-		txctl->flags |= ATH9K_TXDESC_NOACK;
-	if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
-		txctl->flags |= ATH9K_TXDESC_RTSENA;
-
-	/*
-	 * Setup for rate calculations.
-	 */
-	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
-	rcs = tx_info_priv->rcs;
-
-	if (ieee80211_is_data(fc) && !txctl->use_minrate) {
-
-		/* Enable HT only for DATA frames and not for EAPOL */
-		txctl->ht = (hw->conf.ht_conf.ht_supported &&
-			    (tx_info->flags & IEEE80211_TX_CTL_AMPDU));
-
-		if (is_multicast_ether_addr(hdr->addr1)) {
-			rcs[0].rix = (u8)
-				ath_tx_findindex(rt, txctl->mcast_rate);
-
-			/*
-			 * mcast packets are not re-tried.
-			 */
-			rcs[0].tries = 1;
-		}
+	if (ieee80211_is_data(fc) && !is_pae(skb)) {
 		/* For HT capable stations, we save tidno for later use.
 		 * We also override seqno set by upper layer with the one
 		 * in tx aggregation state.
 		 *
-		 * First, the fragmentation stat is determined.
 		 * If fragmentation is on, the sequence number is
 		 * not overridden, since it has been
 		 * incremented by the fragmentation routine.
+		 *
+		 * FIXME: check if the fragmentation threshold exceeds
+		 * IEEE80211 max.
 		 */
-		if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) &&
-		    txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
-			struct ath_atx_tid *tid;
-
-			tid = ATH_AN_2_TID(txctl->an, txctl->tidno);
-
-			hdr->seq_ctrl = cpu_to_le16(tid->seq_next <<
-				IEEE80211_SEQ_SEQ_SHIFT);
-			txctl->seqno = tid->seq_next;
-			INCR(tid->seq_next, IEEE80211_SEQ_MAX);
-		}
-	} else {
-		/* for management and control frames,
-		 * or for NULL and EAPOL frames */
-		if (txctl->min_rate)
-			rcs[0].rix = ath_rate_findrateix(sc, txctl->min_rate);
-		else
-			rcs[0].rix = 0;
-		rcs[0].tries = ATH_MGT_TXMAXTRY;
+		tid = ATH_AN_2_TID(an, bf->bf_tidno);
+		hdr->seq_ctrl = cpu_to_le16(tid->seq_next <<
+					    IEEE80211_SEQ_SEQ_SHIFT);
+		bf->bf_seqno = tid->seq_next;
+		INCR(tid->seq_next, IEEE80211_SEQ_MAX);
 	}
-	rix = rcs[0].rix;
+}
 
-	if (ieee80211_has_morefrags(fc) ||
-	    (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
-		/*
-		**  Force hardware to use computed duration for next
-		**  fragment by disabling multi-rate retry, which
-		**  updates duration based on the multi-rate
-		**  duration table.
-		*/
-		rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
-		rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
-		/* reset tries but keep rate index */
-		rcs[0].tries = ATH_TXMAXTRY;
+static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb,
+			  struct ath_txq *txq)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	int flags = 0;
+
+	flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
+	flags |= ATH9K_TXDESC_INTREQ;
+
+	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
+		flags |= ATH9K_TXDESC_NOACK;
+	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+		flags |= ATH9K_TXDESC_RTSENA;
+
+	return flags;
+}
+
+static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
+{
+	struct ath_buf *bf = NULL;
+
+	spin_lock_bh(&sc->tx.txbuflock);
+
+	if (unlikely(list_empty(&sc->tx.txbuf))) {
+		spin_unlock_bh(&sc->tx.txbuflock);
+		return NULL;
 	}
 
-	/*
-	 * Determine if a tx interrupt should be generated for
-	 * this descriptor.  We take a tx interrupt to reap
-	 * descriptors when the h/w hits an EOL condition or
-	 * when the descriptor is specifically marked to generate
-	 * an interrupt.  We periodically mark descriptors in this
-	 * way to insure timely replenishing of the supply needed
-	 * for sending frames.  Defering interrupts reduces system
-	 * load and potentially allows more concurrent work to be
-	 * done but if done to aggressively can cause senders to
-	 * backup.
-	 *
-	 * NB: use >= to deal with sc_txintrperiod changing
-	 *     dynamically through sysctl.
-	 */
-	spin_lock_bh(&txq->axq_lock);
-	if ((++txq->axq_intrcnt >= sc->sc_txintrperiod)) {
-		txctl->flags |= ATH9K_TXDESC_INTREQ;
-		txq->axq_intrcnt = 0;
-	}
-	spin_unlock_bh(&txq->axq_lock);
+	bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
+	list_del(&bf->list);
 
-	if (is_multicast_ether_addr(hdr->addr1)) {
-		antenna = sc->sc_mcastantenna + 1;
-		sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1;
-	}
+	spin_unlock_bh(&sc->tx.txbuflock);
 
-	return 0;
+	return bf;
 }
 
 /* To complete a chain of buffers associated a frame */
@@ -396,6 +330,7 @@
 {
 	struct sk_buff *skb = bf->bf_mpdu;
 	struct ath_xmit_status tx_status;
+	unsigned long flags;
 
 	/*
 	 * Set retry information.
@@ -414,20 +349,21 @@
 		if (bf_isxretried(bf))
 			tx_status.flags |= ATH_TX_XRETRY;
 	}
+
 	/* Unmap this frame */
 	pci_unmap_single(sc->pdev,
 			 bf->bf_dmacontext,
 			 skb->len,
 			 PCI_DMA_TODEVICE);
 	/* complete this frame */
-	ath_tx_complete(sc, skb, &tx_status, bf->bf_node);
+	ath_tx_complete(sc, skb, &tx_status);
 
 	/*
 	 * Return the list of ath_buf of this mpdu to free queue
 	 */
-	spin_lock_bh(&sc->sc_txbuflock);
-	list_splice_tail_init(bf_q, &sc->sc_txbuf);
-	spin_unlock_bh(&sc->sc_txbuflock);
+	spin_lock_irqsave(&sc->tx.txbuflock, flags);
+	list_splice_tail_init(bf_q, &sc->tx.txbuf);
+	spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
 }
 
 /*
@@ -468,7 +404,7 @@
 
 static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 {
-	struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum];
+	struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
 
 	spin_lock_bh(&txq->axq_lock);
 
@@ -481,7 +417,7 @@
 
 void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 {
-	struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum];
+	struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
 
 	ASSERT(tid->paused > 0);
 	spin_lock_bh(&txq->axq_lock);
@@ -505,11 +441,9 @@
 
 /* Compute the number of bad frames */
 
-static int ath_tx_num_badfrms(struct ath_softc *sc,
-	struct ath_buf *bf, int txok)
+static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
+			      int txok)
 {
-	struct ath_node *an = bf->bf_node;
-	int isnodegone = (an->an_flags & ATH_NODE_CLEAN);
 	struct ath_buf *bf_last = bf->bf_lastbf;
 	struct ath_desc *ds = bf_last->bf_desc;
 	u16 seq_st = 0;
@@ -518,7 +452,7 @@
 	int nbad = 0;
 	int isaggr = 0;
 
-	if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED)
+	if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED)
 		return 0;
 
 	isaggr = bf_isaggr(bf);
@@ -553,8 +487,8 @@
 
 /* Update block ack window */
 
-static void ath_tx_update_baw(struct ath_softc *sc,
-	struct ath_atx_tid *tid, int seqno)
+static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
+			      int seqno)
 {
 	int index, cindex;
 
@@ -577,34 +511,23 @@
  * width  - 0 for 20 MHz, 1 for 40 MHz
  * half_gi - to use 4us v/s 3.6 us for symbol time
  */
-
-static u32 ath_pkt_duration(struct ath_softc *sc,
-				  u8 rix,
-				  struct ath_buf *bf,
-				  int width,
-				  int half_gi,
-				  bool shortPreamble)
+static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
+			    int width, int half_gi, bool shortPreamble)
 {
-	const struct ath9k_rate_table *rt = sc->sc_currates;
+	struct ath_rate_table *rate_table = sc->cur_rate_table;
 	u32 nbits, nsymbits, duration, nsymbols;
 	u8 rc;
 	int streams, pktlen;
 
 	pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
-	rc = rt->info[rix].rateCode;
+	rc = rate_table->info[rix].ratecode;
 
-	/*
-	 * for legacy rates, use old function to compute packet duration
-	 */
+	/* for legacy rates, use old function to compute packet duration */
 	if (!IS_HT_RATE(rc))
-		return ath9k_hw_computetxtime(sc->sc_ah,
-					     rt,
-					     pktlen,
-					     rix,
-					     shortPreamble);
-	/*
-	 * find number of symbols: PLCP + data
-	 */
+		return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen,
+					      rix, shortPreamble);
+
+	/* find number of symbols: PLCP + data */
 	nbits = (pktlen << 3) + OFDM_PLCP_BITS;
 	nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
 	nsymbols = (nbits + nsymbits - 1) / nsymbits;
@@ -614,11 +537,10 @@
 	else
 		duration = SYMBOL_TIME_HALFGI(nsymbols);
 
-	/*
-	 * addup duration for legacy/ht training and signal fields
-	 */
+	/* addup duration for legacy/ht training and signal fields */
 	streams = HT_RC_2_STREAMS(rc);
 	duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
+
 	return duration;
 }
 
@@ -627,207 +549,127 @@
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
 {
 	struct ath_hal *ah = sc->sc_ah;
-	const struct ath9k_rate_table *rt;
+	struct ath_rate_table *rt;
 	struct ath_desc *ds = bf->bf_desc;
 	struct ath_desc *lastds = bf->bf_lastbf->bf_desc;
 	struct ath9k_11n_rate_series series[4];
-	int i, flags, rtsctsena = 0, dynamic_mimops = 0;
+	struct sk_buff *skb;
+	struct ieee80211_tx_info *tx_info;
+	struct ieee80211_tx_rate *rates;
+	struct ieee80211_hdr *hdr;
+	int i, flags, rtsctsena = 0;
 	u32 ctsduration = 0;
 	u8 rix = 0, cix, ctsrate = 0;
-	u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit;
-	struct ath_node *an = (struct ath_node *) bf->bf_node;
+	__le16 fc;
 
-	/*
-	 * get the cix for the lowest valid rix.
-	 */
-	rt = sc->sc_currates;
-	for (i = 4; i--;) {
-		if (bf->bf_rcs[i].tries) {
-			rix = bf->bf_rcs[i].rix;
+	memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
+
+	skb = (struct sk_buff *)bf->bf_mpdu;
+	hdr = (struct ieee80211_hdr *)skb->data;
+	fc = hdr->frame_control;
+	tx_info = IEEE80211_SKB_CB(skb);
+	rates = tx_info->control.rates;
+
+	if (ieee80211_has_morefrags(fc) ||
+	    (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
+		rates[1].count = rates[2].count = rates[3].count = 0;
+		rates[1].idx = rates[2].idx = rates[3].idx = 0;
+		rates[0].count = ATH_TXMAXTRY;
+	}
+
+	/* get the cix for the lowest valid rix */
+	rt = sc->cur_rate_table;
+	for (i = 3; i >= 0; i--) {
+		if (rates[i].count && (rates[i].idx >= 0)) {
+			rix = rates[i].idx;
 			break;
 		}
 	}
+
 	flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA));
-	cix = rt->info[rix].controlRate;
+	cix = rt->info[rix].ctrl_rate;
 
 	/*
-	 * If 802.11g protection is enabled, determine whether
-	 * to use RTS/CTS or just CTS.  Note that this is only
-	 * done for OFDM/HT unicast frames.
+	 * If 802.11g protection is enabled, determine whether to use RTS/CTS or
+	 * just CTS.  Note that this is only done for OFDM/HT unicast frames.
 	 */
-	if (sc->sc_protmode != PROT_M_NONE &&
-	    (rt->info[rix].phy == PHY_OFDM ||
-	     rt->info[rix].phy == PHY_HT) &&
-	    (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
+	if (sc->sc_protmode != PROT_M_NONE && !(bf->bf_flags & ATH9K_TXDESC_NOACK)
+	    && (rt->info[rix].phy == WLAN_RC_PHY_OFDM ||
+		WLAN_RC_PHY_HT(rt->info[rix].phy))) {
 		if (sc->sc_protmode == PROT_M_RTSCTS)
 			flags = ATH9K_TXDESC_RTSENA;
 		else if (sc->sc_protmode == PROT_M_CTSONLY)
 			flags = ATH9K_TXDESC_CTSENA;
 
-		cix = rt->info[sc->sc_protrix].controlRate;
+		cix = rt->info[sc->sc_protrix].ctrl_rate;
 		rtsctsena = 1;
 	}
 
-	/* For 11n, the default behavior is to enable RTS for
-	 * hw retried frames. We enable the global flag here and
-	 * let rate series flags determine which rates will actually
-	 * use RTS.
+	/* For 11n, the default behavior is to enable RTS for hw retried frames.
+	 * We enable the global flag here and let rate series flags determine
+	 * which rates will actually use RTS.
 	 */
 	if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) {
-		BUG_ON(!an);
-		/*
-		 * 802.11g protection not needed, use our default behavior
-		 */
+		/* 802.11g protection not needed, use our default behavior */
 		if (!rtsctsena)
 			flags = ATH9K_TXDESC_RTSENA;
-		/*
-		 * For dynamic MIMO PS, RTS needs to precede the first aggregate
-		 * and the second aggregate should have any protection at all.
-		 */
-		if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) {
-			if (!bf_isaggrburst(bf)) {
-				flags = ATH9K_TXDESC_RTSENA;
-				dynamic_mimops = 1;
-			} else {
-				flags = 0;
-			}
-		}
 	}
 
-	/*
-	 * Set protection if aggregate protection on
-	 */
+	/* Set protection if aggregate protection on */
 	if (sc->sc_config.ath_aggr_prot &&
 	    (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
 		flags = ATH9K_TXDESC_RTSENA;
-		cix = rt->info[sc->sc_protrix].controlRate;
+		cix = rt->info[sc->sc_protrix].ctrl_rate;
 		rtsctsena = 1;
 	}
 
-	/*
-	 *  For AR5416 - RTS cannot be followed by a frame larger than 8K.
-	 */
-	if (bf_isaggr(bf) && (bf->bf_al > aggr_limit_with_rts)) {
-		/*
-		 * Ensure that in the case of SM Dynamic power save
-		 * while we are bursting the second aggregate the
-		 * RTS is cleared.
-		 */
+	/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
+	if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit))
 		flags &= ~(ATH9K_TXDESC_RTSENA);
-	}
 
 	/*
-	 * CTS transmit rate is derived from the transmit rate
-	 * by looking in the h/w rate table.  We must also factor
-	 * in whether or not a short preamble is to be used.
+	 * CTS transmit rate is derived from the transmit rate by looking in the
+	 * h/w rate table.  We must also factor in whether or not a short
+	 * preamble is to be used. NB: cix is set above where RTS/CTS is enabled
 	 */
-	/* NB: cix is set above where RTS/CTS is enabled */
-	BUG_ON(cix == 0xff);
-	ctsrate = rt->info[cix].rateCode |
-		(bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0);
-
-	/*
-	 * Setup HAL rate series
-	 */
-	memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
+	ctsrate = rt->info[cix].ratecode |
+		(bf_isshpreamble(bf) ? rt->info[cix].short_preamble : 0);
 
 	for (i = 0; i < 4; i++) {
-		if (!bf->bf_rcs[i].tries)
+		if (!rates[i].count || (rates[i].idx < 0))
 			continue;
 
-		rix = bf->bf_rcs[i].rix;
+		rix = rates[i].idx;
 
-		series[i].Rate = rt->info[rix].rateCode |
-			(bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0);
+		series[i].Rate = rt->info[rix].ratecode |
+			(bf_isshpreamble(bf) ? rt->info[rix].short_preamble : 0);
 
-		series[i].Tries = bf->bf_rcs[i].tries;
+		series[i].Tries = rates[i].count;
 
 		series[i].RateFlags = (
-			(bf->bf_rcs[i].flags & ATH_RC_RTSCTS_FLAG) ?
+			(rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) ?
 				ATH9K_RATESERIES_RTS_CTS : 0) |
-			((bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) ?
+			((rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ?
 				ATH9K_RATESERIES_2040 : 0) |
-			((bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG) ?
+			((rates[i].flags & IEEE80211_TX_RC_SHORT_GI) ?
 				ATH9K_RATESERIES_HALFGI : 0);
 
-		series[i].PktDuration = ath_pkt_duration(
-			sc, rix, bf,
-			(bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0,
-			(bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG),
-			bf_isshpreamble(bf));
+		series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
+			 (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0,
+			 (rates[i].flags & IEEE80211_TX_RC_SHORT_GI),
+			 bf_isshpreamble(bf));
 
-		if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) &&
-		    (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) {
-			/*
-			 * When sending to an HT node that has enabled static
-			 * SM/MIMO power save, send at single stream rates but
-			 * use maximum allowed transmit chains per user,
-			 * hardware, regulatory, or country limits for
-			 * better range.
-			 */
-			series[i].ChSel = sc->sc_tx_chainmask;
-		} else {
-			if (bf_isht(bf))
-				series[i].ChSel =
-					ath_chainmask_sel_logic(sc, an);
-			else
-				series[i].ChSel = sc->sc_tx_chainmask;
-		}
+		series[i].ChSel = sc->sc_tx_chainmask;
 
 		if (rtsctsena)
 			series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
-
-		/*
-		 * Set RTS for all rates if node is in dynamic powersave
-		 * mode and we are using dual stream rates.
-		 */
-		if (dynamic_mimops && (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG))
-			series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
 	}
 
-	/*
-	 * For non-HT devices, calculate RTS/CTS duration in software
-	 * and disable multi-rate retry.
-	 */
-	if (flags && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)) {
-		/*
-		 * Compute the transmit duration based on the frame
-		 * size and the size of an ACK frame.  We call into the
-		 * HAL to do the computation since it depends on the
-		 * characteristics of the actual PHY being used.
-		 *
-		 * NB: CTS is assumed the same size as an ACK so we can
-		 *     use the precalculated ACK durations.
-		 */
-		if (flags & ATH9K_TXDESC_RTSENA) {    /* SIFS + CTS */
-			ctsduration += bf_isshpreamble(bf) ?
-				rt->info[cix].spAckDuration :
-				rt->info[cix].lpAckDuration;
-		}
-
-		ctsduration += series[0].PktDuration;
-
-		if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */
-			ctsduration += bf_isshpreamble(bf) ?
-				rt->info[rix].spAckDuration :
-				rt->info[rix].lpAckDuration;
-		}
-
-		/*
-		 * Disable multi-rate retry when using RTS/CTS by clearing
-		 * series 1, 2 and 3.
-		 */
-		memset(&series[1], 0, sizeof(struct ath9k_11n_rate_series) * 3);
-	}
-
-	/*
-	 * set dur_update_en for l-sig computation except for PS-Poll frames
-	 */
-	ath9k_hw_set11n_ratescenario(ah, ds, lastds,
-				     !bf_ispspoll(bf),
-				     ctsrate,
-				     ctsduration,
+	/* set dur_update_en for l-sig computation except for PS-Poll frames */
+	ath9k_hw_set11n_ratescenario(ah, ds, lastds, !bf_ispspoll(bf),
+				     ctsrate, ctsduration,
 				     series, 4, flags);
+
 	if (sc->sc_config.ath_aggr_prot && flags)
 		ath9k_hw_set11n_burstduration(ah, ds, 8192);
 }
@@ -836,27 +678,18 @@
  * Function to send a normal HT (non-AMPDU) frame
  * NB: must be called with txq lock held
  */
-
 static int ath_tx_send_normal(struct ath_softc *sc,
 			      struct ath_txq *txq,
 			      struct ath_atx_tid *tid,
 			      struct list_head *bf_head)
 {
 	struct ath_buf *bf;
-	struct sk_buff *skb;
-	struct ieee80211_tx_info *tx_info;
-	struct ath_tx_info_priv *tx_info_priv;
 
 	BUG_ON(list_empty(bf_head));
 
 	bf = list_first_entry(bf_head, struct ath_buf, list);
 	bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */
 
-	skb = (struct sk_buff *)bf->bf_mpdu;
-	tx_info = IEEE80211_SKB_CB(skb);
-	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
-	memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
-
 	/* update starting sequence number for subsequent ADDBA request */
 	INCR(tid->seq_start, IEEE80211_SEQ_MAX);
 
@@ -873,7 +706,7 @@
 
 static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 {
-	struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum];
+	struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
 	struct ath_buf *bf;
 	struct list_head bf_head;
 	INIT_LIST_HEAD(&bf_head);
@@ -906,8 +739,10 @@
 				      struct list_head *bf_q,
 				      int txok)
 {
-	struct ath_node *an = bf->bf_node;
-	struct ath_atx_tid *tid = ATH_AN_2_TID(an, bf->bf_tidno);
+	struct ath_node *an = NULL;
+	struct sk_buff *skb;
+	struct ieee80211_tx_info *tx_info;
+	struct ath_atx_tid *tid = NULL;
 	struct ath_buf *bf_last = bf->bf_lastbf;
 	struct ath_desc *ds = bf_last->bf_desc;
 	struct ath_buf *bf_next, *bf_lastq = NULL;
@@ -915,7 +750,14 @@
 	u16 seq_st = 0;
 	u32 ba[WME_BA_BMP_SIZE >> 5];
 	int isaggr, txfail, txpending, sendbar = 0, needreset = 0;
-	int isnodegone = (an->an_flags & ATH_NODE_CLEAN);
+
+	skb = (struct sk_buff *)bf->bf_mpdu;
+	tx_info = IEEE80211_SKB_CB(skb);
+
+	if (tx_info->control.sta) {
+		an = (struct ath_node *)tx_info->control.sta->drv_priv;
+		tid = ATH_AN_2_TID(an, bf->bf_tidno);
+	}
 
 	isaggr = bf_isaggr(bf);
 	if (isaggr) {
@@ -939,7 +781,8 @@
 				 * when perform internal reset in this routine.
 				 * Only enable reset in STA mode for now.
 				 */
-				if (sc->sc_ah->ah_opmode == ATH9K_M_STA)
+				if (sc->sc_ah->ah_opmode ==
+					    NL80211_IFTYPE_STATION)
 					needreset = 1;
 			}
 		} else {
@@ -961,7 +804,7 @@
 			/* transmit completion */
 		} else {
 
-			if (!tid->cleanup_inprogress && !isnodegone &&
+			if (!(tid->state & AGGR_CLEANUP) &&
 			    ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
 				if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
 					ath_tx_set_retry(sc, bf);
@@ -1038,18 +881,17 @@
 				struct ath_buf *tbf;
 
 				/* allocate new descriptor */
-				spin_lock_bh(&sc->sc_txbuflock);
-				ASSERT(!list_empty((&sc->sc_txbuf)));
-				tbf = list_first_entry(&sc->sc_txbuf,
+				spin_lock_bh(&sc->tx.txbuflock);
+				ASSERT(!list_empty((&sc->tx.txbuf)));
+				tbf = list_first_entry(&sc->tx.txbuf,
 						struct ath_buf, list);
 				list_del(&tbf->list);
-				spin_unlock_bh(&sc->sc_txbuflock);
+				spin_unlock_bh(&sc->tx.txbuflock);
 
 				ATH_TXBUF_RESET(tbf);
 
 				/* copy descriptor content */
 				tbf->bf_mpdu = bf_last->bf_mpdu;
-				tbf->bf_node = bf_last->bf_node;
 				tbf->bf_buf_addr = bf_last->bf_buf_addr;
 				*(tbf->bf_desc) = *(bf_last->bf_desc);
 
@@ -1090,25 +932,16 @@
 		bf = bf_next;
 	}
 
-	/*
-	 * node is already gone. no more assocication
-	 * with the node. the node might have been freed
-	 * any  node acces can result in panic.note tid
-	 * is part of the node.
-	 */
-	if (isnodegone)
-		return;
-
-	if (tid->cleanup_inprogress) {
+	if (tid->state & AGGR_CLEANUP) {
 		/* check to see if we're done with cleaning the h/w queue */
 		spin_lock_bh(&txq->axq_lock);
 
 		if (tid->baw_head == tid->baw_tail) {
-			tid->addba_exchangecomplete = 0;
+			tid->state &= ~AGGR_ADDBA_COMPLETE;
 			tid->addba_exchangeattempts = 0;
 			spin_unlock_bh(&txq->axq_lock);
 
-			tid->cleanup_inprogress = false;
+			tid->state &= ~AGGR_CLEANUP;
 
 			/* send buffered frames as singles */
 			ath_tx_flush_tid(sc, tid);
@@ -1136,29 +969,45 @@
 	return;
 }
 
+static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad)
+{
+	struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+
+	tx_info_priv->update_rc = false;
+	if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
+		tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+
+	if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
+	    (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
+		if (bf_isdata(bf)) {
+			memcpy(&tx_info_priv->tx, &ds->ds_txstat,
+			       sizeof(tx_info_priv->tx));
+			tx_info_priv->n_frames = bf->bf_nframes;
+			tx_info_priv->n_bad_frames = nbad;
+			tx_info_priv->update_rc = true;
+		}
+	}
+}
+
 /* Process completed xmit descriptors from the specified queue */
 
-static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
+static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 {
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_buf *bf, *lastbf, *bf_held = NULL;
 	struct list_head bf_head;
-	struct ath_desc *ds, *tmp_ds;
-	struct sk_buff *skb;
-	struct ieee80211_tx_info *tx_info;
-	struct ath_tx_info_priv *tx_info_priv;
-	int nacked, txok, nbad = 0, isrifs = 0;
+	struct ath_desc *ds;
+	int txok, nbad = 0;
 	int status;
 
-	DPRINTF(sc, ATH_DBG_QUEUE,
-		"%s: tx queue %d (%x), link %p\n", __func__,
+	DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
 		txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
 		txq->axq_link);
 
-	nacked = 0;
 	for (;;) {
 		spin_lock_bh(&txq->axq_lock);
-		txq->axq_intrcnt = 0; /* reset periodic desc intr count */
 		if (list_empty(&txq->axq_q)) {
 			txq->axq_link = NULL;
 			txq->axq_linkbuf = NULL;
@@ -1229,9 +1078,9 @@
 
 		if (bf_held) {
 			list_del(&bf_held->list);
-			spin_lock_bh(&sc->sc_txbuflock);
-			list_add_tail(&bf_held->list, &sc->sc_txbuf);
-			spin_unlock_bh(&sc->sc_txbuflock);
+			spin_lock_bh(&sc->tx.txbuflock);
+			list_add_tail(&bf_held->list, &sc->tx.txbuf);
+			spin_unlock_bh(&sc->tx.txbuflock);
 		}
 
 		if (!bf_isampdu(bf)) {
@@ -1246,29 +1095,8 @@
 		} else {
 			nbad = ath_tx_num_badfrms(sc, bf, txok);
 		}
-		skb = bf->bf_mpdu;
-		tx_info = IEEE80211_SKB_CB(skb);
-		tx_info_priv = (struct ath_tx_info_priv *)
-			tx_info->driver_data[0];
-		if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
-			tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
-		if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
-				(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
-			if (ds->ds_txstat.ts_status == 0)
-				nacked++;
 
-			if (bf_isdata(bf)) {
-				if (isrifs)
-					tmp_ds = bf->bf_rifslast->bf_desc;
-				else
-					tmp_ds = ds;
-				memcpy(&tx_info_priv->tx,
-					&tmp_ds->ds_txstat,
-					sizeof(tx_info_priv->tx));
-				tx_info_priv->n_frames = bf->bf_nframes;
-				tx_info_priv->n_bad_frames = nbad;
-			}
-		}
+		ath_tx_rc_status(bf, ds, nbad);
 
 		/*
 		 * Complete this transmit unit
@@ -1299,7 +1127,6 @@
 			ath_txq_schedule(sc, txq);
 		spin_unlock_bh(&txq->axq_lock);
 	}
-	return nacked;
 }
 
 static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq)
@@ -1307,9 +1134,9 @@
 	struct ath_hal *ah = sc->sc_ah;
 
 	(void) ath9k_hw_stoptxdma(ah, txq->axq_qnum);
-	DPRINTF(sc, ATH_DBG_XMIT, "%s: tx queue [%u] %x, link %p\n",
-		__func__, txq->axq_qnum,
-		ath9k_hw_gettxbuf(ah, txq->axq_qnum), txq->axq_link);
+	DPRINTF(sc, ATH_DBG_XMIT, "tx queue [%u] %x, link %p\n",
+		txq->axq_qnum, ath9k_hw_gettxbuf(ah, txq->axq_qnum),
+		txq->axq_link);
 }
 
 /* Drain only the data queues */
@@ -1317,40 +1144,33 @@
 static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx)
 {
 	struct ath_hal *ah = sc->sc_ah;
-	int i;
-	int npend = 0;
+	int i, status, npend = 0;
 
-	/* XXX return value */
 	if (!(sc->sc_flags & SC_OP_INVALID)) {
 		for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
 			if (ATH_TXQ_SETUP(sc, i)) {
-				ath_tx_stopdma(sc, &sc->sc_txq[i]);
-
+				ath_tx_stopdma(sc, &sc->tx.txq[i]);
 				/* The TxDMA may not really be stopped.
 				 * Double check the hal tx pending count */
 				npend += ath9k_hw_numtxpending(ah,
-					sc->sc_txq[i].axq_qnum);
+						       sc->tx.txq[i].axq_qnum);
 			}
 		}
 	}
 
 	if (npend) {
-		int status;
-
 		/* TxDMA not stopped, reset the hal */
-		DPRINTF(sc, ATH_DBG_XMIT,
-			"%s: Unable to stop TxDMA. Reset HAL!\n", __func__);
+		DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n");
 
 		spin_lock_bh(&sc->sc_resetlock);
 		if (!ath9k_hw_reset(ah,
 				    sc->sc_ah->ah_curchan,
-				    sc->sc_ht_info.tx_chan_width,
+				    sc->tx_chan_width,
 				    sc->sc_tx_chainmask, sc->sc_rx_chainmask,
 				    sc->sc_ht_extprotspacing, true, &status)) {
 
 			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: unable to reset hardware; hal status %u\n",
-				__func__,
+				"Unable to reset hardware; hal status %u\n",
 				status);
 		}
 		spin_unlock_bh(&sc->sc_resetlock);
@@ -1358,7 +1178,7 @@
 
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
 		if (ATH_TXQ_SETUP(sc, i))
-			ath_tx_draintxq(sc, &sc->sc_txq[i], retry_tx);
+			ath_tx_draintxq(sc, &sc->tx.txq[i], retry_tx);
 	}
 }
 
@@ -1390,24 +1210,17 @@
  * Function to send an A-MPDU
  * NB: must be called with txq lock held
  */
-
 static int ath_tx_send_ampdu(struct ath_softc *sc,
-			     struct ath_txq *txq,
 			     struct ath_atx_tid *tid,
 			     struct list_head *bf_head,
 			     struct ath_tx_control *txctl)
 {
 	struct ath_buf *bf;
-	struct sk_buff *skb;
-	struct ieee80211_tx_info *tx_info;
-	struct ath_tx_info_priv *tx_info_priv;
 
 	BUG_ON(list_empty(bf_head));
 
 	bf = list_first_entry(bf_head, struct ath_buf, list);
 	bf->bf_state.bf_type |= BUF_AMPDU;
-	bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */
-	bf->bf_tidno = txctl->tidno;
 
 	/*
 	 * Do not queue to h/w when any of the following conditions is true:
@@ -1418,21 +1231,16 @@
 	 */
 	if (!list_empty(&tid->buf_q) || tid->paused ||
 	    !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
-	    txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
+	    txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
 		/*
 		 * Add this frame to software queue for scheduling later
 		 * for aggregation.
 		 */
 		list_splice_tail_init(bf_head, &tid->buf_q);
-		ath_tx_queue_tid(txq, tid);
+		ath_tx_queue_tid(txctl->txq, tid);
 		return 0;
 	}
 
-	skb = (struct sk_buff *)bf->bf_mpdu;
-	tx_info = IEEE80211_SKB_CB(skb);
-	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
-	memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
-
 	/* Add sub-frame to BAW */
 	ath_tx_addto_baw(sc, tid, bf);
 
@@ -1440,7 +1248,8 @@
 	bf->bf_nframes = 1;
 	bf->bf_lastbf = bf->bf_lastfrm; /* one single frame */
 	ath_buf_set_rate(sc, bf);
-	ath_tx_txqaddbuf(sc, txq, bf_head);
+	ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
+
 	return 0;
 }
 
@@ -1448,25 +1257,24 @@
  * looks up the rate
  * returns aggr limit based on lowest of the rates
  */
-
 static u32 ath_lookup_rate(struct ath_softc *sc,
-				 struct ath_buf *bf)
+			   struct ath_buf *bf,
+			   struct ath_atx_tid *tid)
 {
-	const struct ath9k_rate_table *rt = sc->sc_currates;
+	struct ath_rate_table *rate_table = sc->cur_rate_table;
 	struct sk_buff *skb;
 	struct ieee80211_tx_info *tx_info;
+	struct ieee80211_tx_rate *rates;
 	struct ath_tx_info_priv *tx_info_priv;
 	u32 max_4ms_framelen, frame_length;
 	u16 aggr_limit, legacy = 0, maxampdu;
 	int i;
 
-
 	skb = (struct sk_buff *)bf->bf_mpdu;
 	tx_info = IEEE80211_SKB_CB(skb);
-	tx_info_priv = (struct ath_tx_info_priv *)
-		tx_info->driver_data[0];
-	memcpy(bf->bf_rcs,
-		tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
+	rates = tx_info->control.rates;
+	tx_info_priv =
+		(struct ath_tx_info_priv *)tx_info->rate_driver_data[0];
 
 	/*
 	 * Find the lowest frame length among the rate series that will have a
@@ -1476,14 +1284,14 @@
 	max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
 
 	for (i = 0; i < 4; i++) {
-		if (bf->bf_rcs[i].tries) {
-			frame_length = bf->bf_rcs[i].max_4ms_framelen;
-
-			if (rt->info[bf->bf_rcs[i].rix].phy != PHY_HT) {
+		if (rates[i].count) {
+			if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) {
 				legacy = 1;
 				break;
 			}
 
+			frame_length =
+				rate_table->info[rates[i].idx].max_4ms_framelen;
 			max_4ms_framelen = min(max_4ms_framelen, frame_length);
 		}
 	}
@@ -1504,7 +1312,7 @@
 	 * The IE, however can hold upto 65536, which shows up here
 	 * as zero. Ignore 65536 since we  are constrained by hw.
 	 */
-	maxampdu = sc->sc_ht_info.maxampdu;
+	maxampdu = tid->an->maxampdu;
 	if (maxampdu)
 		aggr_limit = min(aggr_limit, maxampdu);
 
@@ -1516,12 +1324,14 @@
  * meet the minimum required mpdudensity.
  * caller should make sure that the rate is  HT rate .
  */
-
 static int ath_compute_num_delims(struct ath_softc *sc,
+				  struct ath_atx_tid *tid,
 				  struct ath_buf *bf,
 				  u16 frmlen)
 {
-	const struct ath9k_rate_table *rt = sc->sc_currates;
+	struct ath_rate_table *rt = sc->cur_rate_table;
+	struct sk_buff *skb = bf->bf_mpdu;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	u32 nsymbits, nsymbols, mpdudensity;
 	u16 minlen;
 	u8 rc, flags, rix;
@@ -1545,7 +1355,7 @@
 	 * required minimum length for subframe. Take into account
 	 * whether high rate is 20 or 40Mhz and half or full GI.
 	 */
-	mpdudensity = sc->sc_ht_info.mpdudensity;
+	mpdudensity = tid->an->mpdudensity;
 
 	/*
 	 * If there is no mpdu density restriction, no further calculation
@@ -1554,11 +1364,11 @@
 	if (mpdudensity == 0)
 		return ndelim;
 
-	rix = bf->bf_rcs[0].rix;
-	flags = bf->bf_rcs[0].flags;
-	rc = rt->info[rix].rateCode;
-	width = (flags & ATH_RC_CW40_FLAG) ? 1 : 0;
-	half_gi = (flags & ATH_RC_SGI_FLAG) ? 1 : 0;
+	rix = tx_info->control.rates[0].idx;
+	flags = tx_info->control.rates[0].flags;
+	rc = rt->info[rix].ratecode;
+	width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
+	half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
 
 	if (half_gi)
 		nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity);
@@ -1585,7 +1395,6 @@
  * For aggregation from software buffer queue.
  * NB: must be called with txq lock held
  */
-
 static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 					struct ath_atx_tid *tid,
 					struct list_head *bf_q,
@@ -1600,7 +1409,7 @@
 	u16 aggr_limit = 0, al = 0, bpad = 0,
 		al_delta, h_baw = tid->baw_size / 2;
 	enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
-	int prev_al = 0, is_ds_rate = 0;
+	int prev_al = 0;
 	INIT_LIST_HEAD(&bf_head);
 
 	BUG_ON(list_empty(&tid->buf_q));
@@ -1619,13 +1428,8 @@
 		}
 
 		if (!rl) {
-			aggr_limit = ath_lookup_rate(sc, bf);
+			aggr_limit = ath_lookup_rate(sc, bf, tid);
 			rl = 1;
-			/*
-			 * Is rate dual stream
-			 */
-			is_ds_rate =
-				(bf->bf_rcs[0].flags & ATH_RC_DS_FLAG) ? 1 : 0;
 		}
 
 		/*
@@ -1657,7 +1461,7 @@
 		 * Get the delimiters needed to meet the MPDU
 		 * density for this node.
 		 */
-		ndelim = ath_compute_num_delims(sc, bf_first, bf->bf_frmlen);
+		ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
 
 		bpad = PADBYTES(al_delta) + (ndelim << 2);
 
@@ -1713,7 +1517,6 @@
  * process pending frames possibly doing a-mpdu aggregation
  * NB: must be called with txq lock held
  */
-
 static void ath_tx_sched_aggr(struct ath_softc *sc,
 	struct ath_txq *txq, struct ath_atx_tid *tid)
 {
@@ -1799,8 +1602,8 @@
 
 static void ath_tid_drain(struct ath_softc *sc,
 			  struct ath_txq *txq,
-			  struct ath_atx_tid *tid,
-			  bool bh_flag)
+			  struct ath_atx_tid *tid)
+
 {
 	struct ath_buf *bf;
 	struct list_head bf_head;
@@ -1821,18 +1624,12 @@
 		 * do not indicate packets while holding txq spinlock.
 		 * unlock is intentional here
 		 */
-		if (likely(bh_flag))
-			spin_unlock_bh(&txq->axq_lock);
-		else
-			spin_unlock(&txq->axq_lock);
+		spin_unlock(&txq->axq_lock);
 
 		/* complete this sub-frame */
 		ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
 
-		if (likely(bh_flag))
-			spin_lock_bh(&txq->axq_lock);
-		else
-			spin_lock(&txq->axq_lock);
+		spin_lock(&txq->axq_lock);
 	}
 
 	/*
@@ -1849,10 +1646,8 @@
  * Drain all pending buffers
  * NB: must be called with txq lock held
  */
-
 static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
-					  struct ath_txq *txq,
-					  bool bh_flag)
+					  struct ath_txq *txq)
 {
 	struct ath_atx_ac *ac, *ac_tmp;
 	struct ath_atx_tid *tid, *tid_tmp;
@@ -1863,51 +1658,33 @@
 		list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
 			list_del(&tid->list);
 			tid->sched = false;
-			ath_tid_drain(sc, txq, tid, bh_flag);
+			ath_tid_drain(sc, txq, tid);
 		}
 	}
 }
 
-static int ath_tx_start_dma(struct ath_softc *sc,
-			    struct sk_buff *skb,
-			    struct scatterlist *sg,
-			    u32 n_sg,
-			    struct ath_tx_control *txctl)
+static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
+				struct sk_buff *skb,
+				struct ath_tx_control *txctl)
 {
-	struct ath_node *an = txctl->an;
-	struct ath_buf *bf = NULL;
-	struct list_head bf_head;
-	struct ath_desc *ds;
-	struct ath_hal *ah = sc->sc_ah;
-	struct ath_txq *txq;
-	struct ath_tx_info_priv *tx_info_priv;
-	struct ath_rc_series *rcs;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct ieee80211_tx_info *tx_info =  IEEE80211_SKB_CB(skb);
-	__le16 fc = hdr->frame_control;
+	struct ath_tx_info_priv *tx_info_priv;
+	int hdrlen;
+	__le16 fc;
 
-	if (unlikely(txctl->flags & ATH9K_TXDESC_CAB))
-		txq = sc->sc_cabq;
-	else
-		txq = &sc->sc_txq[txctl->qnum];
-
-	/* For each sglist entry, allocate an ath_buf for DMA */
-	INIT_LIST_HEAD(&bf_head);
-	spin_lock_bh(&sc->sc_txbuflock);
-	if (unlikely(list_empty(&sc->sc_txbuf))) {
-		spin_unlock_bh(&sc->sc_txbuflock);
+	tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
+	if (unlikely(!tx_info_priv))
 		return -ENOMEM;
-	}
+	tx_info->rate_driver_data[0] = tx_info_priv;
+	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+	fc = hdr->frame_control;
 
-	bf = list_first_entry(&sc->sc_txbuf, struct ath_buf, list);
-	list_del(&bf->list);
-	spin_unlock_bh(&sc->sc_txbuflock);
-
-	list_add_tail(&bf->list, &bf_head);
-
-	/* set up this buffer */
 	ATH_TXBUF_RESET(bf);
-	bf->bf_frmlen = txctl->frmlen;
+
+	/* Frame type */
+
+	bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
 
 	ieee80211_is_data(fc) ?
 		(bf->bf_state.bf_type |= BUF_DATA) :
@@ -1921,120 +1698,158 @@
 	(sc->sc_flags & SC_OP_PREAMBLE_SHORT) ?
 		(bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) :
 		(bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE);
+	(sc->hw->conf.ht.enabled && !is_pae(skb) &&
+	 (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) ?
+		(bf->bf_state.bf_type |= BUF_HT) :
+		(bf->bf_state.bf_type &= ~BUF_HT);
 
-	bf->bf_flags = txctl->flags;
-	bf->bf_keytype = txctl->keytype;
-	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
-	rcs = tx_info_priv->rcs;
-	bf->bf_rcs[0] = rcs[0];
-	bf->bf_rcs[1] = rcs[1];
-	bf->bf_rcs[2] = rcs[2];
-	bf->bf_rcs[3] = rcs[3];
-	bf->bf_node = an;
+	bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
+
+	/* Crypto */
+
+	bf->bf_keytype = get_hw_crypto_keytype(skb);
+
+	if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
+		bf->bf_frmlen += tx_info->control.hw_key->icv_len;
+		bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
+	} else {
+		bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
+	}
+
+	/* Assign seqno, tidno */
+
+	if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR))
+		assign_aggr_tid_seqno(skb, bf);
+
+	/* DMA setup */
+
 	bf->bf_mpdu = skb;
-	bf->bf_buf_addr = sg_dma_address(sg);
+
+	bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data,
+					   skb->len, PCI_DMA_TODEVICE);
+	if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_dmacontext))) {
+		bf->bf_mpdu = NULL;
+		DPRINTF(sc, ATH_DBG_CONFIG,
+			"pci_dma_mapping_error() on TX\n");
+		return -ENOMEM;
+	}
+
+	bf->bf_buf_addr = bf->bf_dmacontext;
+	return 0;
+}
+
+/* FIXME: tx power */
+static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
+			     struct ath_tx_control *txctl)
+{
+	struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+	struct ieee80211_tx_info *tx_info =  IEEE80211_SKB_CB(skb);
+	struct ath_node *an = NULL;
+	struct list_head bf_head;
+	struct ath_desc *ds;
+	struct ath_atx_tid *tid;
+	struct ath_hal *ah = sc->sc_ah;
+	int frm_type;
+
+	frm_type = get_hw_packet_type(skb);
+
+	INIT_LIST_HEAD(&bf_head);
+	list_add_tail(&bf->list, &bf_head);
 
 	/* setup descriptor */
+
 	ds = bf->bf_desc;
 	ds->ds_link = 0;
 	ds->ds_data = bf->bf_buf_addr;
 
-	/*
-	 * Save the DMA context in the first ath_buf
-	 */
-	bf->bf_dmacontext = txctl->dmacontext;
+	/* Formulate first tx descriptor with tx controls */
 
-	/*
-	 * Formulate first tx descriptor with tx controls.
-	 */
-	ath9k_hw_set11n_txdesc(ah,
-			       ds,
-			       bf->bf_frmlen, /* frame length */
-			       txctl->atype, /* Atheros packet type */
-			       min(txctl->txpower, (u16)60), /* txpower */
-			       txctl->keyix,            /* key cache index */
-			       txctl->keytype,          /* key type */
-			       txctl->flags);           /* flags */
-	ath9k_hw_filltxdesc(ah,
-			    ds,
-			    sg_dma_len(sg),     /* segment length */
-			    true,            /* first segment */
-			    (n_sg == 1) ? true : false, /* last segment */
-			    ds);                /* first descriptor */
+	ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
+			       bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
+
+	ath9k_hw_filltxdesc(ah, ds,
+			    skb->len,	/* segment length */
+			    true,	/* first segment */
+			    true,	/* last segment */
+			    ds);	/* first descriptor */
 
 	bf->bf_lastfrm = bf;
-	(txctl->ht) ?
-		(bf->bf_state.bf_type |= BUF_HT) :
-		(bf->bf_state.bf_type &= ~BUF_HT);
 
-	spin_lock_bh(&txq->axq_lock);
+	spin_lock_bh(&txctl->txq->axq_lock);
 
-	if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
-		struct ath_atx_tid *tid = ATH_AN_2_TID(an, txctl->tidno);
-		if (ath_aggr_query(sc, an, txctl->tidno)) {
+	if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
+	    tx_info->control.sta) {
+		an = (struct ath_node *)tx_info->control.sta->drv_priv;
+		tid = ATH_AN_2_TID(an, bf->bf_tidno);
+
+		if (ath_aggr_query(sc, an, bf->bf_tidno)) {
 			/*
 			 * Try aggregation if it's a unicast data frame
 			 * and the destination is HT capable.
 			 */
-			ath_tx_send_ampdu(sc, txq, tid, &bf_head, txctl);
+			ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
 		} else {
 			/*
-			 * Send this frame as regular when ADDBA exchange
-			 * is neither complete nor pending.
+			 * Send this frame as regular when ADDBA
+			 * exchange is neither complete nor pending.
 			 */
-			ath_tx_send_normal(sc, txq, tid, &bf_head);
+			ath_tx_send_normal(sc, txctl->txq,
+					   tid, &bf_head);
 		}
 	} else {
 		bf->bf_lastbf = bf;
 		bf->bf_nframes = 1;
+
 		ath_buf_set_rate(sc, bf);
-
-		if (ieee80211_is_back_req(fc)) {
-			/* This is required for resuming tid
-			 * during BAR completion */
-			bf->bf_tidno = txctl->tidno;
-		}
-
-		ath_tx_txqaddbuf(sc, txq, &bf_head);
+		ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
 	}
-	spin_unlock_bh(&txq->axq_lock);
-	return 0;
+
+	spin_unlock_bh(&txctl->txq->axq_lock);
 }
 
-static void xmit_map_sg(struct ath_softc *sc,
-			struct sk_buff *skb,
-			struct ath_tx_control *txctl)
+/* Upon failure caller should free skb */
+int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
+		 struct ath_tx_control *txctl)
 {
-	struct ath_xmit_status tx_status;
-	struct ath_atx_tid *tid;
-	struct scatterlist sg;
+	struct ath_buf *bf;
+	int r;
 
-	txctl->dmacontext = pci_map_single(sc->pdev, skb->data,
-					   skb->len, PCI_DMA_TODEVICE);
+	/* Check if a tx buffer is available */
 
-	/* setup S/G list */
-	memset(&sg, 0, sizeof(struct scatterlist));
-	sg_dma_address(&sg) = txctl->dmacontext;
-	sg_dma_len(&sg) = skb->len;
-
-	if (ath_tx_start_dma(sc, skb, &sg, 1, txctl) != 0) {
-		/*
-		 *  We have to do drop frame here.
-		 */
-		pci_unmap_single(sc->pdev, txctl->dmacontext,
-				 skb->len, PCI_DMA_TODEVICE);
-
-		tx_status.retries = 0;
-		tx_status.flags = ATH_TX_ERROR;
-
-		if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
-			/* Reclaim the seqno. */
-			tid = ATH_AN_2_TID((struct ath_node *)
-				txctl->an, txctl->tidno);
-			DECR(tid->seq_next, IEEE80211_SEQ_MAX);
-		}
-		ath_tx_complete(sc, skb, &tx_status, txctl->an);
+	bf = ath_tx_get_buffer(sc);
+	if (!bf) {
+		DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n");
+		return -1;
 	}
+
+	r = ath_tx_setup_buffer(sc, bf, skb, txctl);
+	if (unlikely(r)) {
+		struct ath_txq *txq = txctl->txq;
+
+		DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n");
+
+		/* upon ath_tx_processq() this TX queue will be resumed, we
+		 * guarantee this will happen by knowing beforehand that
+		 * we will at least have to run TX completionon one buffer
+		 * on the queue */
+		spin_lock_bh(&txq->axq_lock);
+		if (ath_txq_depth(sc, txq->axq_qnum) > 1) {
+			ieee80211_stop_queue(sc->hw,
+				skb_get_queue_mapping(skb));
+			txq->stopped = 1;
+		}
+		spin_unlock_bh(&txq->axq_lock);
+
+		spin_lock_bh(&sc->tx.txbuflock);
+		list_add_tail(&bf->list, &sc->tx.txbuf);
+		spin_unlock_bh(&sc->tx.txbuflock);
+
+		return r;
+	}
+
+	ath_tx_start_dma(sc, bf, txctl);
+
+	return 0;
 }
 
 /* Initialize TX queue and h/w */
@@ -2044,26 +1859,25 @@
 	int error = 0;
 
 	do {
-		spin_lock_init(&sc->sc_txbuflock);
+		spin_lock_init(&sc->tx.txbuflock);
 
 		/* Setup tx descriptors */
-		error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf,
+		error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
 			"tx", nbufs, 1);
 		if (error != 0) {
 			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: failed to allocate tx descriptors: %d\n",
-				__func__, error);
+				"Failed to allocate tx descriptors: %d\n",
+				error);
 			break;
 		}
 
 		/* XXX allocate beacon state together with vap */
-		error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
+		error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
 					  "beacon", ATH_BCBUF, 1);
 		if (error != 0) {
 			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: failed to allocate "
-				"beacon descripotrs: %d\n",
-				__func__, error);
+				"Failed to allocate beacon descriptors: %d\n",
+				error);
 			break;
 		}
 
@@ -2080,12 +1894,12 @@
 int ath_tx_cleanup(struct ath_softc *sc)
 {
 	/* cleanup beacon descriptors */
-	if (sc->sc_bdma.dd_desc_len != 0)
-		ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf);
+	if (sc->beacon.bdma.dd_desc_len != 0)
+		ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
 
 	/* cleanup tx descriptors */
-	if (sc->sc_txdma.dd_desc_len != 0)
-		ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
+	if (sc->tx.txdma.dd_desc_len != 0)
+		ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
 
 	return 0;
 }
@@ -2133,15 +1947,15 @@
 		 */
 		return NULL;
 	}
-	if (qnum >= ARRAY_SIZE(sc->sc_txq)) {
+	if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: hal qnum %u out of range, max %u!\n",
-			__func__, qnum, (unsigned int)ARRAY_SIZE(sc->sc_txq));
+			"qnum %u out of range, max %u!\n",
+			qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
 		ath9k_hw_releasetxqueue(ah, qnum);
 		return NULL;
 	}
 	if (!ATH_TXQ_SETUP(sc, qnum)) {
-		struct ath_txq *txq = &sc->sc_txq[qnum];
+		struct ath_txq *txq = &sc->tx.txq[qnum];
 
 		txq->axq_qnum = qnum;
 		txq->axq_link = NULL;
@@ -2151,11 +1965,10 @@
 		txq->axq_depth = 0;
 		txq->axq_aggr_depth = 0;
 		txq->axq_totalqueued = 0;
-		txq->axq_intrcnt = 0;
 		txq->axq_linkbuf = NULL;
-		sc->sc_txqsetup |= 1<<qnum;
+		sc->tx.txqsetup |= 1<<qnum;
 	}
-	return &sc->sc_txq[qnum];
+	return &sc->tx.txq[qnum];
 }
 
 /* Reclaim resources for a setup queue */
@@ -2163,7 +1976,7 @@
 void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
 {
 	ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
-	sc->sc_txqsetup &= ~(1<<txq->axq_qnum);
+	sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
 }
 
 /*
@@ -2180,15 +1993,15 @@
 {
 	struct ath_txq *txq;
 
-	if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) {
+	if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: HAL AC %u out of range, max %zu!\n",
-			__func__, haltype, ARRAY_SIZE(sc->sc_haltype2q));
+			"HAL AC %u out of range, max %zu!\n",
+			 haltype, ARRAY_SIZE(sc->tx.hwq_map));
 		return 0;
 	}
 	txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
 	if (txq != NULL) {
-		sc->sc_haltype2q[haltype] = txq->axq_qnum;
+		sc->tx.hwq_map[haltype] = txq->axq_qnum;
 		return 1;
 	} else
 		return 0;
@@ -2200,20 +2013,19 @@
 
 	switch (qtype) {
 	case ATH9K_TX_QUEUE_DATA:
-		if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) {
+		if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
 			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: HAL AC %u out of range, max %zu!\n",
-				__func__,
-				haltype, ARRAY_SIZE(sc->sc_haltype2q));
+				"HAL AC %u out of range, max %zu!\n",
+				haltype, ARRAY_SIZE(sc->tx.hwq_map));
 			return -1;
 		}
-		qnum = sc->sc_haltype2q[haltype];
+		qnum = sc->tx.hwq_map[haltype];
 		break;
 	case ATH9K_TX_QUEUE_BEACON:
-		qnum = sc->sc_bhalq;
+		qnum = sc->beacon.beaconq;
 		break;
 	case ATH9K_TX_QUEUE_CAB:
-		qnum = sc->sc_cabq->axq_qnum;
+		qnum = sc->beacon.cabq->axq_qnum;
 		break;
 	default:
 		qnum = -1;
@@ -2221,6 +2033,34 @@
 	return qnum;
 }
 
+/* Get a transmit queue, if available */
+
+struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
+{
+	struct ath_txq *txq = NULL;
+	int qnum;
+
+	qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
+	txq = &sc->tx.txq[qnum];
+
+	spin_lock_bh(&txq->axq_lock);
+
+	/* Try to avoid running out of descriptors */
+	if (txq->axq_depth >= (ATH_TXBUF - 20)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"TX queue: %d is full, depth: %d\n",
+			qnum, txq->axq_depth);
+		ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb));
+		txq->stopped = 1;
+		spin_unlock_bh(&txq->axq_lock);
+		return NULL;
+	}
+
+	spin_unlock_bh(&txq->axq_lock);
+
+	return txq;
+}
+
 /* Update parameters for a transmit queue */
 
 int ath_txq_update(struct ath_softc *sc, int qnum,
@@ -2230,17 +2070,17 @@
 	int error = 0;
 	struct ath9k_tx_queue_info qi;
 
-	if (qnum == sc->sc_bhalq) {
+	if (qnum == sc->beacon.beaconq) {
 		/*
 		 * XXX: for beacon queue, we just save the parameter.
 		 * It will be picked up by ath_beaconq_config when
 		 * it's necessary.
 		 */
-		sc->sc_beacon_qi = *qinfo;
+		sc->beacon.beacon_qi = *qinfo;
 		return 0;
 	}
 
-	ASSERT(sc->sc_txq[qnum].axq_qnum == qnum);
+	ASSERT(sc->tx.txq[qnum].axq_qnum == qnum);
 
 	ath9k_hw_get_txq_props(ah, qnum, &qi);
 	qi.tqi_aifs = qinfo->tqi_aifs;
@@ -2251,8 +2091,7 @@
 
 	if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
 		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: unable to update hardware queue %u!\n",
-			__func__, qnum);
+			"Unable to update hardware queue %u!\n", qnum);
 		error = -EIO;
 	} else {
 		ath9k_hw_resettxqueue(ah, qnum); /* push to h/w */
@@ -2264,7 +2103,7 @@
 int ath_cabq_update(struct ath_softc *sc)
 {
 	struct ath9k_tx_queue_info qi;
-	int qnum = sc->sc_cabq->axq_qnum;
+	int qnum = sc->beacon.cabq->axq_qnum;
 	struct ath_beacon_config conf;
 
 	ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
@@ -2284,27 +2123,6 @@
 	return 0;
 }
 
-int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb)
-{
-	struct ath_tx_control txctl;
-	int error = 0;
-
-	memset(&txctl, 0, sizeof(struct ath_tx_control));
-	error = ath_tx_prepare(sc, skb, &txctl);
-	if (error == 0)
-		/*
-		 * Start DMA mapping.
-		 * ath_tx_start_dma() will be called either synchronously
-		 * or asynchrounsly once DMA is complete.
-		 */
-		xmit_map_sg(sc, skb, &txctl);
-	else
-		ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE);
-
-	/* failed packets will be dropped by the caller */
-	return error;
-}
-
 /* Deferred processing of transmit interrupt */
 
 void ath_tx_tasklet(struct ath_softc *sc)
@@ -2319,7 +2137,7 @@
 	 */
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
 		if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
-			ath_tx_processq(sc, &sc->sc_txq[i]);
+			ath_tx_processq(sc, &sc->tx.txq[i]);
 	}
 }
 
@@ -2351,9 +2169,9 @@
 			list_del(&bf->list);
 			spin_unlock_bh(&txq->axq_lock);
 
-			spin_lock_bh(&sc->sc_txbuflock);
-			list_add_tail(&bf->list, &sc->sc_txbuf);
-			spin_unlock_bh(&sc->sc_txbuflock);
+			spin_lock_bh(&sc->tx.txbuflock);
+			list_add_tail(&bf->list, &sc->tx.txbuf);
+			spin_unlock_bh(&sc->tx.txbuflock);
 			continue;
 		}
 
@@ -2378,8 +2196,7 @@
 	if (sc->sc_flags & SC_OP_TXAGGR) {
 		if (!retry_tx) {
 			spin_lock_bh(&txq->axq_lock);
-			ath_txq_drain_pending_buffers(sc, txq,
-				ATH9K_BH_STATUS_CHANGE);
+			ath_txq_drain_pending_buffers(sc, txq);
 			spin_unlock_bh(&txq->axq_lock);
 		}
 	}
@@ -2392,9 +2209,9 @@
 	/* stop beacon queue. The beacon will be freed when
 	 * we go to INIT state */
 	if (!(sc->sc_flags & SC_OP_INVALID)) {
-		(void) ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
-		DPRINTF(sc, ATH_DBG_XMIT, "%s: beacon queue %x\n", __func__,
-			ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq));
+		(void) ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
+		DPRINTF(sc, ATH_DBG_XMIT, "beacon queue %x\n",
+			ath9k_hw_gettxbuf(sc->sc_ah, sc->beacon.beaconq));
 	}
 
 	ath_drain_txdataq(sc, retry_tx);
@@ -2402,72 +2219,47 @@
 
 u32 ath_txq_depth(struct ath_softc *sc, int qnum)
 {
-	return sc->sc_txq[qnum].axq_depth;
+	return sc->tx.txq[qnum].axq_depth;
 }
 
 u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum)
 {
-	return sc->sc_txq[qnum].axq_aggr_depth;
+	return sc->tx.txq[qnum].axq_aggr_depth;
 }
 
-/* Check if an ADDBA is required. A valid node must be passed. */
-enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc,
-				      struct ath_node *an,
-				      u8 tidno)
+bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
 {
 	struct ath_atx_tid *txtid;
-	DECLARE_MAC_BUF(mac);
 
 	if (!(sc->sc_flags & SC_OP_TXAGGR))
-		return AGGR_NOT_REQUIRED;
+		return false;
 
-	/* ADDBA exchange must be completed before sending aggregates */
 	txtid = ATH_AN_2_TID(an, tidno);
 
-	if (txtid->addba_exchangecomplete)
-		return AGGR_EXCHANGE_DONE;
-
-	if (txtid->cleanup_inprogress)
-		return AGGR_CLEANUP_PROGRESS;
-
-	if (txtid->addba_exchangeinprogress)
-		return AGGR_EXCHANGE_PROGRESS;
-
-	if (!txtid->addba_exchangecomplete) {
-		if (!txtid->addba_exchangeinprogress &&
+	if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
+		if (!(txtid->state & AGGR_ADDBA_PROGRESS) &&
 		    (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) {
 			txtid->addba_exchangeattempts++;
-			return AGGR_REQUIRED;
+			return true;
 		}
 	}
 
-	return AGGR_NOT_REQUIRED;
+	return false;
 }
 
 /* Start TX aggregation */
 
-int ath_tx_aggr_start(struct ath_softc *sc,
-		      const u8 *addr,
-		      u16 tid,
-		      u16 *ssn)
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+		      u16 tid, u16 *ssn)
 {
 	struct ath_atx_tid *txtid;
 	struct ath_node *an;
 
-	spin_lock_bh(&sc->node_lock);
-	an = ath_node_find(sc, (u8 *) addr);
-	spin_unlock_bh(&sc->node_lock);
-
-	if (!an) {
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: Node not found to initialize "
-			"TX aggregation\n", __func__);
-		return -1;
-	}
+	an = (struct ath_node *)sta->drv_priv;
 
 	if (sc->sc_flags & SC_OP_TXAGGR) {
 		txtid = ATH_AN_2_TID(an, tid);
-		txtid->addba_exchangeinprogress = 1;
+		txtid->state |= AGGR_ADDBA_PROGRESS;
 		ath_tx_pause_tid(sc, txtid);
 	}
 
@@ -2476,26 +2268,33 @@
 
 /* Stop tx aggregation */
 
-int ath_tx_aggr_stop(struct ath_softc *sc,
-		     const u8 *addr,
-		     u16 tid)
+int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
 {
-	struct ath_node *an;
-
-	spin_lock_bh(&sc->node_lock);
-	an = ath_node_find(sc, (u8 *) addr);
-	spin_unlock_bh(&sc->node_lock);
-
-	if (!an) {
-		DPRINTF(sc, ATH_DBG_AGGR,
-			"%s: TX aggr stop for non-existent node\n", __func__);
-		return -1;
-	}
+	struct ath_node *an = (struct ath_node *)sta->drv_priv;
 
 	ath_tx_aggr_teardown(sc, an, tid);
 	return 0;
 }
 
+/* Resume tx aggregation */
+
+void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
+{
+	struct ath_atx_tid *txtid;
+	struct ath_node *an;
+
+	an = (struct ath_node *)sta->drv_priv;
+
+	if (sc->sc_flags & SC_OP_TXAGGR) {
+		txtid = ATH_AN_2_TID(an, tid);
+		txtid->baw_size =
+			IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
+		txtid->state |= AGGR_ADDBA_COMPLETE;
+		txtid->state &= ~AGGR_ADDBA_PROGRESS;
+		ath_tx_resume_tid(sc, txtid);
+	}
+}
+
 /*
  * Performs transmit side cleanup when TID changes from aggregated to
  * unaggregated.
@@ -2503,21 +2302,18 @@
  * - Discard all retry frames from the s/w queue.
  */
 
-void ath_tx_aggr_teardown(struct ath_softc *sc,
-	struct ath_node *an, u8 tid)
+void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid)
 {
 	struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
-	struct ath_txq *txq = &sc->sc_txq[txtid->ac->qnum];
+	struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
 	struct ath_buf *bf;
 	struct list_head bf_head;
 	INIT_LIST_HEAD(&bf_head);
 
-	DPRINTF(sc, ATH_DBG_AGGR, "%s: teardown TX aggregation\n", __func__);
-
-	if (txtid->cleanup_inprogress) /* cleanup is in progress */
+	if (txtid->state & AGGR_CLEANUP) /* cleanup is in progress */
 		return;
 
-	if (!txtid->addba_exchangecomplete) {
+	if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
 		txtid->addba_exchangeattempts = 0;
 		return;
 	}
@@ -2547,9 +2343,9 @@
 
 	if (txtid->baw_head != txtid->baw_tail) {
 		spin_unlock_bh(&txq->axq_lock);
-		txtid->cleanup_inprogress = true;
+		txtid->state |= AGGR_CLEANUP;
 	} else {
-		txtid->addba_exchangecomplete = 0;
+		txtid->state &= ~AGGR_ADDBA_COMPLETE;
 		txtid->addba_exchangeattempts = 0;
 		spin_unlock_bh(&txq->axq_lock);
 		ath_tx_flush_tid(sc, txtid);
@@ -2591,10 +2387,8 @@
 		if (tid->paused)    /* check next tid to keep h/w busy */
 			continue;
 
-		if (!(tid->an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) ||
-		    ((txq->axq_depth % 2) == 0)) {
+		if ((txq->axq_depth % 2) == 0)
 			ath_tx_sched_aggr(sc, txq, tid);
-		}
 
 		/*
 		 * add tid to round-robin queue if more frames
@@ -2625,72 +2419,67 @@
 
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
 {
-	if (sc->sc_flags & SC_OP_TXAGGR) {
-		struct ath_atx_tid *tid;
-		struct ath_atx_ac *ac;
-		int tidno, acno;
+	struct ath_atx_tid *tid;
+	struct ath_atx_ac *ac;
+	int tidno, acno;
 
-		sc->sc_ht_info.maxampdu = ATH_AMPDU_LIMIT_DEFAULT;
+	/*
+	 * Init per tid tx state
+	 */
+	for (tidno = 0, tid = &an->tid[tidno];
+	     tidno < WME_NUM_TID;
+	     tidno++, tid++) {
+		tid->an        = an;
+		tid->tidno     = tidno;
+		tid->seq_start = tid->seq_next = 0;
+		tid->baw_size  = WME_MAX_BA;
+		tid->baw_head  = tid->baw_tail = 0;
+		tid->sched     = false;
+		tid->paused = false;
+		tid->state &= ~AGGR_CLEANUP;
+		INIT_LIST_HEAD(&tid->buf_q);
 
-		/*
-		 * Init per tid tx state
-		 */
-		for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno];
-				tidno < WME_NUM_TID;
-				tidno++, tid++) {
-			tid->an        = an;
-			tid->tidno     = tidno;
-			tid->seq_start = tid->seq_next = 0;
-			tid->baw_size  = WME_MAX_BA;
-			tid->baw_head  = tid->baw_tail = 0;
-			tid->sched     = false;
-			tid->paused = false;
-			tid->cleanup_inprogress = false;
-			INIT_LIST_HEAD(&tid->buf_q);
+		acno = TID_TO_WME_AC(tidno);
+		tid->ac = &an->ac[acno];
 
-			acno = TID_TO_WME_AC(tidno);
-			tid->ac = &an->an_aggr.tx.ac[acno];
+		/* ADDBA state */
+		tid->state &= ~AGGR_ADDBA_COMPLETE;
+		tid->state &= ~AGGR_ADDBA_PROGRESS;
+		tid->addba_exchangeattempts = 0;
+	}
 
-			/* ADDBA state */
-			tid->addba_exchangecomplete     = 0;
-			tid->addba_exchangeinprogress   = 0;
-			tid->addba_exchangeattempts     = 0;
-		}
+	/*
+	 * Init per ac tx state
+	 */
+	for (acno = 0, ac = &an->ac[acno];
+	     acno < WME_NUM_AC; acno++, ac++) {
+		ac->sched    = false;
+		INIT_LIST_HEAD(&ac->tid_q);
 
-		/*
-		 * Init per ac tx state
-		 */
-		for (acno = 0, ac = &an->an_aggr.tx.ac[acno];
-				acno < WME_NUM_AC; acno++, ac++) {
-			ac->sched    = false;
-			INIT_LIST_HEAD(&ac->tid_q);
-
-			switch (acno) {
-			case WME_AC_BE:
-				ac->qnum = ath_tx_get_qnum(sc,
-					ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
-				break;
-			case WME_AC_BK:
-				ac->qnum = ath_tx_get_qnum(sc,
-					ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
-				break;
-			case WME_AC_VI:
-				ac->qnum = ath_tx_get_qnum(sc,
-					ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
-				break;
-			case WME_AC_VO:
-				ac->qnum = ath_tx_get_qnum(sc,
-					ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
-				break;
-			}
+		switch (acno) {
+		case WME_AC_BE:
+			ac->qnum = ath_tx_get_qnum(sc,
+				   ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+			break;
+		case WME_AC_BK:
+			ac->qnum = ath_tx_get_qnum(sc,
+				   ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
+			break;
+		case WME_AC_VI:
+			ac->qnum = ath_tx_get_qnum(sc,
+				   ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
+			break;
+		case WME_AC_VO:
+			ac->qnum = ath_tx_get_qnum(sc,
+				   ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
+			break;
 		}
 	}
 }
 
 /* Cleanupthe pending buffers for the node. */
 
-void ath_tx_node_cleanup(struct ath_softc *sc,
-	struct ath_node *an, bool bh_flag)
+void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
 {
 	int i;
 	struct ath_atx_ac *ac, *ac_tmp;
@@ -2698,12 +2487,9 @@
 	struct ath_txq *txq;
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
 		if (ATH_TXQ_SETUP(sc, i)) {
-			txq = &sc->sc_txq[i];
+			txq = &sc->tx.txq[i];
 
-			if (likely(bh_flag))
-				spin_lock_bh(&txq->axq_lock);
-			else
-				spin_lock(&txq->axq_lock);
+			spin_lock(&txq->axq_lock);
 
 			list_for_each_entry_safe(ac,
 					ac_tmp, &txq->axq_acq, list) {
@@ -2718,36 +2504,14 @@
 						tid_tmp, &ac->tid_q, list) {
 					list_del(&tid->list);
 					tid->sched = false;
-					ath_tid_drain(sc, txq, tid, bh_flag);
-					tid->addba_exchangecomplete = 0;
+					ath_tid_drain(sc, txq, tid);
+					tid->state &= ~AGGR_ADDBA_COMPLETE;
 					tid->addba_exchangeattempts = 0;
-					tid->cleanup_inprogress = false;
+					tid->state &= ~AGGR_CLEANUP;
 				}
 			}
 
-			if (likely(bh_flag))
-				spin_unlock_bh(&txq->axq_lock);
-			else
-				spin_unlock(&txq->axq_lock);
-		}
-	}
-}
-
-/* Cleanup per node transmit state */
-
-void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an)
-{
-	if (sc->sc_flags & SC_OP_TXAGGR) {
-		struct ath_atx_tid *tid;
-		int tidno, i;
-
-		/* Init per tid rx state */
-		for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno];
-			tidno < WME_NUM_TID;
-		     tidno++, tid++) {
-
-			for (i = 0; i < ATH_TID_MAX_BUFS; i++)
-				ASSERT(tid->tx_buf[i] == NULL);
+			spin_unlock(&txq->axq_lock);
 		}
 	}
 }
@@ -2758,6 +2522,8 @@
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ath_tx_control txctl;
 
+	memset(&txctl, 0, sizeof(struct ath_tx_control));
+
 	/*
 	 * As a temporary workaround, assign seq# here; this will likely need
 	 * to be cleaned up to work better with Beacon transmission and virtual
@@ -2766,9 +2532,9 @@
 	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
 		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 		if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
-			sc->seq_no += 0x10;
+			sc->tx.seq_no += 0x10;
 		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-		hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+		hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
 	}
 
 	/* Add the padding after the header if this is not already done */
@@ -2776,8 +2542,7 @@
 	if (hdrlen & 3) {
 		padsize = hdrlen % 4;
 		if (skb_headroom(skb) < padsize) {
-			DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ padding "
-				"failed\n", __func__);
+			DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n");
 			dev_kfree_skb_any(skb);
 			return;
 		}
@@ -2785,23 +2550,16 @@
 		memmove(skb->data, skb->data + padsize, hdrlen);
 	}
 
-	DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n",
-		__func__,
-		skb);
+	txctl.txq = sc->beacon.cabq;
 
-	memset(&txctl, 0, sizeof(struct ath_tx_control));
-	txctl.flags = ATH9K_TXDESC_CAB;
-	if (ath_tx_prepare(sc, skb, &txctl) == 0) {
-		/*
-		 * Start DMA mapping.
-		 * ath_tx_start_dma() will be called either synchronously
-		 * or asynchrounsly once DMA is complete.
-		 */
-		xmit_map_sg(sc, skb, &txctl);
-	} else {
-		ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE);
-		DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__);
-		dev_kfree_skb_any(skb);
+	DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb);
+
+	if (ath_tx_start(sc, skb, &txctl) != 0) {
+		DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n");
+		goto exit;
 	}
-}
 
+	return;
+exit:
+	dev_kfree_skb_any(skb);
+}
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index ecb02bd..350157f 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -67,7 +67,7 @@
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <linux/jiffies.h>
-#include <net/ieee80211.h>
+#include <linux/ieee80211.h>
 #include "atmel.h"
 
 #define DRIVER_MAJOR 0
@@ -569,7 +569,7 @@
 static void atmel_command_irq(struct atmel_private *priv);
 static int atmel_validate_channel(struct atmel_private *priv, int channel);
 static void atmel_management_frame(struct atmel_private *priv,
-				   struct ieee80211_hdr_4addr *header,
+				   struct ieee80211_hdr *header,
 				   u16 frame_len, u8 rssi);
 static void atmel_management_timer(u_long a);
 static void atmel_send_command(struct atmel_private *priv, int command,
@@ -577,7 +577,7 @@
 static int atmel_send_command_wait(struct atmel_private *priv, int command,
 				   void *cmd, int cmd_size);
 static void atmel_transmit_management_frame(struct atmel_private *priv,
-					    struct ieee80211_hdr_4addr *header,
+					    struct ieee80211_hdr *header,
 					    u8 *body, int body_len);
 
 static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
@@ -785,7 +785,7 @@
 {
 	static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 	struct atmel_private *priv = netdev_priv(dev);
-	struct ieee80211_hdr_4addr header;
+	struct ieee80211_hdr header;
 	unsigned long flags;
 	u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
 
@@ -823,7 +823,7 @@
 
 	frame_ctl = IEEE80211_FTYPE_DATA;
 	header.duration_id = 0;
-	header.seq_ctl = 0;
+	header.seq_ctrl = 0;
 	if (priv->wep_is_on)
 		frame_ctl |= IEEE80211_FCTL_PROTECTED;
 	if (priv->operating_mode == IW_MODE_ADHOC) {
@@ -840,7 +840,7 @@
 	if (priv->use_wpa)
 		memcpy(&header.addr4, SNAP_RFC1024, 6);
 
-	header.frame_ctl = cpu_to_le16(frame_ctl);
+	header.frame_control = cpu_to_le16(frame_ctl);
 	/* Copy the wireless header into the card */
 	atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE);
 	/* Copy the packet sans its 802.3 header addresses which have been replaced */
@@ -860,7 +860,7 @@
 }
 
 static void atmel_transmit_management_frame(struct atmel_private *priv,
-					    struct ieee80211_hdr_4addr *header,
+					    struct ieee80211_hdr *header,
 					    u8 *body, int body_len)
 {
 	u16 buff;
@@ -876,7 +876,7 @@
 }
 
 static void fast_rx_path(struct atmel_private *priv,
-			 struct ieee80211_hdr_4addr *header,
+			 struct ieee80211_hdr *header,
 			 u16 msdu_size, u16 rx_packet_loc, u32 crc)
 {
 	/* fast path: unfragmented packet copy directly into skbuf */
@@ -914,12 +914,11 @@
 	}
 
 	memcpy(skbp, header->addr1, 6); /* destination address */
-	if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+	if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
 		memcpy(&skbp[6], header->addr3, 6);
 	else
 		memcpy(&skbp[6], header->addr2, 6); /* source address */
 
-	priv->dev->last_rx = jiffies;
 	skb->protocol = eth_type_trans(skb, priv->dev);
 	skb->ip_summed = CHECKSUM_NONE;
 	netif_rx(skb);
@@ -950,7 +949,7 @@
 }
 
 static void frag_rx_path(struct atmel_private *priv,
-			 struct ieee80211_hdr_4addr *header,
+			 struct ieee80211_hdr *header,
 			 u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no,
 			 u8 frag_no, int more_frags)
 {
@@ -958,7 +957,7 @@
 	u8 source[6];
 	struct sk_buff *skb;
 
-	if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+	if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
 		memcpy(source, header->addr3, 6);
 	else
 		memcpy(source, header->addr2, 6);
@@ -1026,7 +1025,6 @@
 				memcpy(skb_put(skb, priv->frag_len + 12),
 				       priv->rx_buf,
 				       priv->frag_len + 12);
-				priv->dev->last_rx = jiffies;
 				skb->protocol = eth_type_trans(skb, priv->dev);
 				skb->ip_summed = CHECKSUM_NONE;
 				netif_rx(skb);
@@ -1041,7 +1039,7 @@
 static void rx_done_irq(struct atmel_private *priv)
 {
 	int i;
-	struct ieee80211_hdr_4addr header;
+	struct ieee80211_hdr header;
 
 	for (i = 0;
 	     atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID &&
@@ -1068,10 +1066,10 @@
 			goto next;
 		}
 
-		/* Get header as far as end of seq_ctl */
+		/* Get header as far as end of seq_ctrl */
 		atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24);
-		frame_ctl = le16_to_cpu(header.frame_ctl);
-		seq_control = le16_to_cpu(header.seq_ctl);
+		frame_ctl = le16_to_cpu(header.frame_control);
+		seq_control = le16_to_cpu(header.seq_ctrl);
 
 		/* probe for CRC use here if needed  once five packets have
 		   arrived with the same crc status, we assume we know what's
@@ -1479,7 +1477,6 @@
 	struct net_device *dev;
 	struct atmel_private *priv;
 	int rc;
-	DECLARE_MAC_BUF(mac);
 
 	/* Create the network device object. */
         dev = alloc_etherdev(sizeof(*priv));
@@ -1591,8 +1588,8 @@
 	if (!ent)
 		printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
 
-	printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %s\n",
-	       dev->name, DRIVER_MAJOR, DRIVER_MINOR, print_mac(mac, dev->dev_addr));
+	printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n",
+	       dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr);
 
 	return dev;
 
@@ -1822,7 +1819,7 @@
 	/* Determine and validate the key index */
 	idx = encoding->flags & IW_ENCODE_INDEX;
 	if (idx) {
-		if (idx < 1 || idx > WEP_KEYS)
+		if (idx < 1 || idx > 4)
 			return -EINVAL;
 		idx--;
 	} else
@@ -1885,7 +1882,7 @@
 
 	idx = encoding->flags & IW_ENCODE_INDEX;
 	if (idx) {
-		if (idx < 1 || idx > WEP_KEYS)
+		if (idx < 1 || idx > 4)
 			return -EINVAL;
 		idx--;
 	} else
@@ -2800,7 +2797,7 @@
 				u8 channel)
 {
 	int rejoin = 0;
-	int new = capability & MFIE_TYPE_POWER_CONSTRAINT ?
+	int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ?
 		SHORT_PREAMBLE : LONG_PREAMBLE;
 
 	if (priv->preamble != new) {
@@ -2829,19 +2826,19 @@
 static void send_authentication_request(struct atmel_private *priv, u16 system,
 					u8 *challenge, int challenge_len)
 {
-	struct ieee80211_hdr_4addr header;
+	struct ieee80211_hdr header;
 	struct auth_body auth;
 
-	header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
+	header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
 	header.duration_id = cpu_to_le16(0x8000);
-	header.seq_ctl = 0;
+	header.seq_ctrl = 0;
 	memcpy(header.addr1, priv->CurrentBSSID, 6);
 	memcpy(header.addr2, priv->dev->dev_addr, 6);
 	memcpy(header.addr3, priv->CurrentBSSID, 6);
 
 	if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1)
 		/* no WEP for authentication frames with TrSeqNo 1 */
-                header.frame_ctl |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+                header.frame_control |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 
 	auth.alg = cpu_to_le16(system);
 
@@ -2864,7 +2861,7 @@
 {
 	u8 *ssid_el_p;
 	int bodysize;
-	struct ieee80211_hdr_4addr header;
+	struct ieee80211_hdr header;
 	struct ass_req_format {
 		__le16 capability;
 		__le16 listen_interval;
@@ -2877,10 +2874,10 @@
 		u8 rates[4];
 	} body;
 
-	header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+	header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 		(is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ));
 	header.duration_id = cpu_to_le16(0x8000);
-	header.seq_ctl = 0;
+	header.seq_ctrl = 0;
 
 	memcpy(header.addr1, priv->CurrentBSSID, 6);
 	memcpy(header.addr2, priv->dev->dev_addr, 6);
@@ -2890,7 +2887,7 @@
 	if (priv->wep_is_on)
 		body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
 	if (priv->preamble == SHORT_PREAMBLE)
-		body.capability |= cpu_to_le16(MFIE_TYPE_POWER_CONSTRAINT);
+		body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
 
 	body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period);
 
@@ -2904,10 +2901,10 @@
 		bodysize = 12 + priv->SSID_size;
 	}
 
-	ssid_el_p[0] = MFIE_TYPE_SSID;
+	ssid_el_p[0] = WLAN_EID_SSID;
 	ssid_el_p[1] = priv->SSID_size;
 	memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size);
-	ssid_el_p[2 + priv->SSID_size] = MFIE_TYPE_RATES;
+	ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES;
 	ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */
 	memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4);
 
@@ -2915,9 +2912,9 @@
 }
 
 static int is_frame_from_current_bss(struct atmel_private *priv,
-				     struct ieee80211_hdr_4addr *header)
+				     struct ieee80211_hdr *header)
 {
-	if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+	if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
 		return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0;
 	else
 		return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0;
@@ -2965,7 +2962,7 @@
 }
 
 static void store_bss_info(struct atmel_private *priv,
-			   struct ieee80211_hdr_4addr *header, u16 capability,
+			   struct ieee80211_hdr *header, u16 capability,
 			   u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len,
 			   u8 *ssid, int is_beacon)
 {
@@ -3004,7 +3001,7 @@
 	else if (capability & WLAN_CAPABILITY_ESS)
 		priv->BSSinfo[index].BSStype =IW_MODE_INFRA;
 
-	priv->BSSinfo[index].preamble = capability & MFIE_TYPE_POWER_CONSTRAINT ?
+	priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ?
 		SHORT_PREAMBLE : LONG_PREAMBLE;
 }
 
@@ -3040,7 +3037,7 @@
 			}
 		} else if (system == WLAN_AUTH_SHARED_KEY) {
 			if (trans_seq_no == 0x0002 &&
-			    auth->el_id == MFIE_TYPE_CHALLENGE) {
+			    auth->el_id == WLAN_EID_CHALLENGE) {
 				send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len);
 				return;
 			} else if (trans_seq_no == 0x0004) {
@@ -3183,7 +3180,7 @@
 	}
 }
 
-void atmel_join_bss(struct atmel_private *priv, int bss_index)
+static void atmel_join_bss(struct atmel_private *priv, int bss_index)
 {
 	struct bss_info *bss =  &priv->BSSinfo[bss_index];
 
@@ -3291,12 +3288,12 @@
 
 /* deals with incoming managment frames. */
 static void atmel_management_frame(struct atmel_private *priv,
-				   struct ieee80211_hdr_4addr *header,
+				   struct ieee80211_hdr *header,
 				   u16 frame_len, u8 rssi)
 {
 	u16 subtype;
 
-	subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE;
+	subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE;
 	switch (subtype) {
 	case IEEE80211_STYPE_BEACON:
 	case IEEE80211_STYPE_PROBE_RESP:
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 427b820..a53c378 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -718,7 +718,6 @@
 
 	bool bad_frames_preempt;	/* Use "Bad Frames Preemption" (default off) */
 	bool dfq_valid;		/* Directed frame queue valid (IBSS PS mode, ATIM) */
-	bool short_slot;	/* TRUE, if short slot timing is enabled. */
 	bool radio_hw_enable;	/* saved state of radio hardware enabled state */
 	bool suspend_in_progress;	/* TRUE, if we are in a suspend/resume cycle */
 
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c
index 06a01da..e04fc91 100644
--- a/drivers/net/wireless/b43/debugfs.c
+++ b/drivers/net/wireless/b43/debugfs.c
@@ -731,6 +731,7 @@
 	add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
 	add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
 	add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
+	add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0);
 
 #undef add_dyn_dbg
 }
diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h
index 22ffd02..7886cbe 100644
--- a/drivers/net/wireless/b43/debugfs.h
+++ b/drivers/net/wireless/b43/debugfs.h
@@ -12,6 +12,7 @@
 	B43_DBG_PWORK_STOP,
 	B43_DBG_LO,
 	B43_DBG_FIRMWARE,
+	B43_DBG_KEYS,
 	__B43_NR_DYNDBG,
 };
 
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 098f886..6d65a02 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1387,13 +1387,11 @@
 
 			info = IEEE80211_SKB_CB(meta->skb);
 
-			memset(&info->status, 0, sizeof(info->status));
-
 			/*
 			 * Call back to inform the ieee80211 subsystem about
 			 * the status of the transmission.
 			 */
-			frame_succeed = b43_fill_txstatus_report(info, status);
+			frame_succeed = b43_fill_txstatus_report(dev, info, status);
 #ifdef CONFIG_B43_DEBUG
 			if (frame_succeed)
 				ring->nr_succeed_tx_packets++;
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 14c44df..7b31a32 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -703,13 +703,11 @@
 static void b43_short_slot_timing_enable(struct b43_wldev *dev)
 {
 	b43_set_slot_time(dev, 9);
-	dev->short_slot = 1;
 }
 
 static void b43_short_slot_timing_disable(struct b43_wldev *dev)
 {
 	b43_set_slot_time(dev, 20);
-	dev->short_slot = 0;
 }
 
 /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
@@ -994,6 +992,52 @@
 		b43_key_clear(dev, i);
 }
 
+static void b43_dump_keymemory(struct b43_wldev *dev)
+{
+	unsigned int i, index, offset;
+	DECLARE_MAC_BUF(macbuf);
+	u8 mac[ETH_ALEN];
+	u16 algo;
+	u32 rcmta0;
+	u16 rcmta1;
+	u64 hf;
+	struct b43_key *key;
+
+	if (!b43_debug(dev, B43_DBG_KEYS))
+		return;
+
+	hf = b43_hf_read(dev);
+	b43dbg(dev->wl, "Hardware key memory dump:  USEDEFKEYS=%u\n",
+	       !!(hf & B43_HF_USEDEFKEYS));
+	for (index = 0; index < dev->max_nr_keys; index++) {
+		key = &(dev->key[index]);
+		printk(KERN_DEBUG "Key slot %02u: %s",
+		       index, (key->keyconf == NULL) ? " " : "*");
+		offset = dev->ktp + (index * B43_SEC_KEYSIZE);
+		for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
+			u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
+			printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
+		}
+
+		algo = b43_shm_read16(dev, B43_SHM_SHARED,
+				      B43_SHM_SH_KEYIDXBLOCK + (index * 2));
+		printk("   Algo: %04X/%02X", algo, key->algorithm);
+
+		if (index >= 4) {
+			rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
+						((index - 4) * 2) + 0);
+			rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
+						((index - 4) * 2) + 1);
+			*((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
+			*((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
+			printk("   MAC: %s",
+			       print_mac(macbuf, mac));
+		} else
+			printk("   DEFAULT KEY");
+		printk("\n");
+	}
+}
+
 void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
 {
 	u32 macctl;
@@ -1339,25 +1383,6 @@
 	return antenna_nr;
 }
 
-static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
-{
-	antenna = b43_ieee80211_antenna_sanitize(dev, antenna);
-	switch (antenna) {
-	case 0:		/* default/diversity */
-		return B43_ANTENNA_DEFAULT;
-	case 1:		/* Antenna 0 */
-		return B43_ANTENNA0;
-	case 2:		/* Antenna 1 */
-		return B43_ANTENNA1;
-	case 3:		/* Antenna 2 */
-		return B43_ANTENNA2;
-	case 4:		/* Antenna 3 */
-		return B43_ANTENNA3;
-	default:
-		return B43_ANTENNA_DEFAULT;
-	}
-}
-
 /* Convert a b43 antenna number value to the PHY TX control value. */
 static u16 b43_antenna_to_phyctl(int antenna)
 {
@@ -1399,7 +1424,7 @@
 				  len, ram_offset, shm_size_offset, rate);
 
 	/* Write the PHY TX control parameters. */
-	antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx);
+	antenna = B43_ANTENNA_DEFAULT;
 	antenna = b43_antenna_to_phyctl(antenna);
 	ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
 	/* We can't send beacons with short preamble. Would get PHY errors. */
@@ -1693,25 +1718,6 @@
 	queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
 }
 
-static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
-{
-	u32 tmp;
-	u16 i, len;
-
-	len = min((u16) ssid_len, (u16) 0x100);
-	for (i = 0; i < len; i += sizeof(u32)) {
-		tmp = (u32) (ssid[i + 0]);
-		if (i + 1 < len)
-			tmp |= (u32) (ssid[i + 1]) << 8;
-		if (i + 2 < len)
-			tmp |= (u32) (ssid[i + 2]) << 16;
-		if (i + 3 < len)
-			tmp |= (u32) (ssid[i + 3]) << 24;
-		b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp);
-	}
-	b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len);
-}
-
 static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
 {
 	b43_time_lock(dev);
@@ -3339,15 +3345,31 @@
 	return err;
 }
 
-static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+/* Write the short and long frame retry limit values. */
+static void b43_set_retry_limits(struct b43_wldev *dev,
+				 unsigned int short_retry,
+				 unsigned int long_retry)
+{
+	/* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
+	 * the chip-internal counter. */
+	short_retry = min(short_retry, (unsigned int)0xF);
+	long_retry = min(long_retry, (unsigned int)0xF);
+
+	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
+			short_retry);
+	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
+			long_retry);
+}
+
+static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev;
 	struct b43_phy *phy;
+	struct ieee80211_conf *conf = &hw->conf;
 	unsigned long flags;
 	int antenna;
 	int err = 0;
-	u32 savedirqs;
 
 	mutex_lock(&wl->mutex);
 
@@ -3358,33 +3380,20 @@
 	dev = wl->current_dev;
 	phy = &dev->phy;
 
-	/* Disable IRQs while reconfiguring the device.
-	 * This makes it possible to drop the spinlock throughout
-	 * the reconfiguration process. */
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	if (b43_status(dev) < B43_STAT_STARTED) {
-		spin_unlock_irqrestore(&wl->irq_lock, flags);
-		goto out_unlock_mutex;
-	}
-	savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-	b43_synchronize_irq(dev);
+	b43_mac_suspend(dev);
+
+	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+		b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
+					  conf->long_frame_max_tx_count);
+	changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
+	if (!changed)
+		goto out_mac_enable;
 
 	/* Switch to the requested channel.
 	 * The firmware takes care of races with the TX handler. */
 	if (conf->channel->hw_value != phy->channel)
 		b43_switch_channel(dev, conf->channel->hw_value);
 
-	/* Enable/Disable ShortSlot timing. */
-	if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
-	    dev->short_slot) {
-		B43_WARN_ON(phy->type != B43_PHYTYPE_G);
-		if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
-			b43_short_slot_timing_enable(dev);
-		else
-			b43_short_slot_timing_disable(dev);
-	}
-
 	dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
 
 	/* Adjust the desired TX power level. */
@@ -3399,9 +3408,9 @@
 	}
 
 	/* Antennas for RX and management frame TX. */
-	antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
+	antenna = B43_ANTENNA_DEFAULT;
 	b43_mgmtframe_txantenna(dev, antenna);
-	antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
+	antenna = B43_ANTENNA_DEFAULT;
 	if (phy->ops->set_rx_antenna)
 		phy->ops->set_rx_antenna(dev, antenna);
 
@@ -3425,16 +3434,91 @@
 		}
 	}
 
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	b43_interrupt_enable(dev, savedirqs);
-	mmiowb();
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-      out_unlock_mutex:
+out_mac_enable:
+	b43_mac_enable(dev);
+out_unlock_mutex:
 	mutex_unlock(&wl->mutex);
 
 	return err;
 }
 
+static void b43_update_basic_rates(struct b43_wldev *dev, u64 brates)
+{
+	struct ieee80211_supported_band *sband =
+		dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)];
+	struct ieee80211_rate *rate;
+	int i;
+	u16 basic, direct, offset, basic_offset, rateptr;
+
+	for (i = 0; i < sband->n_bitrates; i++) {
+		rate = &sband->bitrates[i];
+
+		if (b43_is_cck_rate(rate->hw_value)) {
+			direct = B43_SHM_SH_CCKDIRECT;
+			basic = B43_SHM_SH_CCKBASIC;
+			offset = b43_plcp_get_ratecode_cck(rate->hw_value);
+			offset &= 0xF;
+		} else {
+			direct = B43_SHM_SH_OFDMDIRECT;
+			basic = B43_SHM_SH_OFDMBASIC;
+			offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
+			offset &= 0xF;
+		}
+
+		rate = ieee80211_get_response_rate(sband, brates, rate->bitrate);
+
+		if (b43_is_cck_rate(rate->hw_value)) {
+			basic_offset = b43_plcp_get_ratecode_cck(rate->hw_value);
+			basic_offset &= 0xF;
+		} else {
+			basic_offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
+			basic_offset &= 0xF;
+		}
+
+		/*
+		 * Get the pointer that we need to point to
+		 * from the direct map
+		 */
+		rateptr = b43_shm_read16(dev, B43_SHM_SHARED,
+					 direct + 2 * basic_offset);
+		/* and write it to the basic map */
+		b43_shm_write16(dev, B43_SHM_SHARED, basic + 2 * offset,
+				rateptr);
+	}
+}
+
+static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_bss_conf *conf,
+				    u32 changed)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev;
+
+	mutex_lock(&wl->mutex);
+
+	dev = wl->current_dev;
+	if (!dev || b43_status(dev) < B43_STAT_STARTED)
+		goto out_unlock_mutex;
+	b43_mac_suspend(dev);
+
+	if (changed & BSS_CHANGED_BASIC_RATES)
+		b43_update_basic_rates(dev, conf->basic_rates);
+
+	if (changed & BSS_CHANGED_ERP_SLOT) {
+		if (conf->use_short_slot)
+			b43_short_slot_timing_enable(dev);
+		else
+			b43_short_slot_timing_disable(dev);
+	}
+
+	b43_mac_enable(dev);
+out_unlock_mutex:
+	mutex_unlock(&wl->mutex);
+
+	return;
+}
+
 static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 			   const u8 *local_addr, const u8 *addr,
 			   struct ieee80211_key_conf *key)
@@ -3445,7 +3529,6 @@
 	u8 algorithm;
 	u8 index;
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	if (modparam_nohwcrypt)
 		return -ENOSPC; /* User disabled HW-crypto */
@@ -3528,15 +3611,18 @@
 	default:
 		B43_WARN_ON(1);
 	}
+
 out_unlock:
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-	mutex_unlock(&wl->mutex);
 	if (!err) {
 		b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
-		       "mac: %s\n",
+		       "mac: %pM\n",
 		       cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
-		       print_mac(mac, addr));
+		       addr);
+		b43_dump_keymemory(dev);
 	}
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	mutex_unlock(&wl->mutex);
+
 	return err;
 }
 
@@ -3598,8 +3684,6 @@
 		if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
 		    b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) {
 			B43_WARN_ON(vif->type != wl->if_type);
-			if (conf->changed & IEEE80211_IFCC_SSID)
-				b43_set_ssid(dev, conf->ssid, conf->ssid_len);
 			if (conf->changed & IEEE80211_IFCC_BEACON)
 				b43_update_templates(wl);
 		} else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
@@ -3878,22 +3962,6 @@
 #endif /* CONFIG_SSB_DRIVER_PCICORE */
 }
 
-/* Write the short and long frame retry limit values. */
-static void b43_set_retry_limits(struct b43_wldev *dev,
-				 unsigned int short_retry,
-				 unsigned int long_retry)
-{
-	/* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
-	 * the chip-internal counter. */
-	short_retry = min(short_retry, (unsigned int)0xF);
-	long_retry = min(long_retry, (unsigned int)0xF);
-
-	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
-			short_retry);
-	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
-			long_retry);
-}
-
 static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
 {
 	u16 pu_delay;
@@ -4214,26 +4282,6 @@
 	cancel_work_sync(&(wl->txpower_adjust_work));
 }
 
-static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
-				  u32 short_retry_limit, u32 long_retry_limit)
-{
-	struct b43_wl *wl = hw_to_b43_wl(hw);
-	struct b43_wldev *dev;
-	int err = 0;
-
-	mutex_lock(&wl->mutex);
-	dev = wl->current_dev;
-	if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) {
-		err = -ENODEV;
-		goto out_unlock;
-	}
-	b43_set_retry_limits(dev, short_retry_limit, long_retry_limit);
-out_unlock:
-	mutex_unlock(&wl->mutex);
-
-	return err;
-}
-
 static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
 				 struct ieee80211_sta *sta, bool set)
 {
@@ -4263,6 +4311,7 @@
 	.add_interface		= b43_op_add_interface,
 	.remove_interface	= b43_op_remove_interface,
 	.config			= b43_op_config,
+	.bss_info_changed	= b43_op_bss_info_changed,
 	.config_interface	= b43_op_config_interface,
 	.configure_filter	= b43_op_configure_filter,
 	.set_key		= b43_op_set_key,
@@ -4270,7 +4319,6 @@
 	.get_tx_stats		= b43_op_get_tx_stats,
 	.start			= b43_op_start,
 	.stop			= b43_op_stop,
-	.set_retry_limit	= b43_op_set_retry_limit,
 	.set_tim		= b43_op_beacon_set_tim,
 	.sta_notify		= b43_op_sta_notify,
 };
@@ -4588,7 +4636,7 @@
 		BIT(NL80211_IFTYPE_ADHOC);
 
 	hw->queues = b43_modparam_qos ? 4 : 1;
-	hw->max_altrates = 1;
+	hw->max_rates = 2;
 	SET_IEEE80211_DEV(hw, dev->dev);
 	if (is_valid_ether_addr(sprom->et1mac))
 		SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c
index 0f1a84c..7fe9d17 100644
--- a/drivers/net/wireless/b43/phy_a.c
+++ b/drivers/net/wireless/b43/phy_a.c
@@ -77,7 +77,7 @@
 }
 #endif
 
-void b43_radio_set_tx_iq(struct b43_wldev *dev)
+static void b43_radio_set_tx_iq(struct b43_wldev *dev)
 {
 	static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
 	static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
@@ -147,7 +147,7 @@
 //FIXME	b43_phy_xmitpower(dev);
 }
 
-void b43_radio_init2060(struct b43_wldev *dev)
+static void b43_radio_init2060(struct b43_wldev *dev)
 {
 	b43_radio_write16(dev, 0x0004, 0x00C0);
 	b43_radio_write16(dev, 0x0005, 0x0008);
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index af37abc..026b61c 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -178,13 +178,27 @@
 		b43_power_saving_ctl_bits(dev, 0);
 }
 
+static inline void assert_mac_suspended(struct b43_wldev *dev)
+{
+	if (!B43_DEBUG)
+		return;
+	if ((b43_status(dev) >= B43_STAT_INITIALIZED) &&
+	    (dev->mac_suspended <= 0)) {
+		b43dbg(dev->wl, "PHY/RADIO register access with "
+		       "enabled MAC.\n");
+		dump_stack();
+	}
+}
+
 u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
 {
+	assert_mac_suspended(dev);
 	return dev->phy.ops->radio_read(dev, reg);
 }
 
 void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
+	assert_mac_suspended(dev);
 	dev->phy.ops->radio_write(dev, reg, value);
 }
 
@@ -208,11 +222,13 @@
 
 u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
 {
+	assert_mac_suspended(dev);
 	return dev->phy.ops->phy_read(dev, reg);
 }
 
 void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
+	assert_mac_suspended(dev);
 	dev->phy.ops->phy_write(dev, reg, value);
 }
 
@@ -280,8 +296,10 @@
 		state = RFKILL_STATE_SOFT_BLOCKED;
 	}
 
+	b43_mac_suspend(dev);
 	phy->ops->software_rfkill(dev, state);
 	phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
+	b43_mac_enable(dev);
 }
 
 /**
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c
index 232181f..caac4a45 100644
--- a/drivers/net/wireless/b43/phy_g.c
+++ b/drivers/net/wireless/b43/phy_g.c
@@ -54,7 +54,7 @@
 	-20, -20, -20, -20,
 };
 
-const u8 b43_radio_channel_codes_bg[] = {
+static const u8 b43_radio_channel_codes_bg[] = {
 	12, 17, 22, 27,
 	32, 37, 42, 47,
 	52, 57, 62, 67,
@@ -215,9 +215,9 @@
 }
 
 /* Adjust the transmission power output (G-PHY) */
-void b43_set_txpower_g(struct b43_wldev *dev,
-		       const struct b43_bbatt *bbatt,
-		       const struct b43_rfatt *rfatt, u8 tx_control)
+static void b43_set_txpower_g(struct b43_wldev *dev,
+			      const struct b43_bbatt *bbatt,
+			      const struct b43_rfatt *rfatt, u8 tx_control)
 {
 	struct b43_phy *phy = &dev->phy;
 	struct b43_phy_g *gphy = phy->g;
@@ -383,14 +383,14 @@
 }
 
 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
+static void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
 {
 	b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
 	b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val);
 }
 
 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
+static s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
 {
 	u16 val;
 
@@ -401,7 +401,7 @@
 }
 
 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
+static void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
 {
 	u16 i;
 	s16 tmp;
@@ -415,7 +415,7 @@
 }
 
 /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-void b43_nrssi_mem_update(struct b43_wldev *dev)
+static void b43_nrssi_mem_update(struct b43_wldev *dev)
 {
 	struct b43_phy_g *gphy = dev->phy.g;
 	s16 i, delta;
@@ -589,7 +589,7 @@
 	b43_phy_write(dev, 0x0811, backup[1]);
 }
 
-void b43_calc_nrssi_slope(struct b43_wldev *dev)
+static void b43_calc_nrssi_slope(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
 	struct b43_phy_g *gphy = phy->g;
@@ -1354,7 +1354,7 @@
 	u16 phy_syncctl;
 };
 
-u16 b43_radio_init2050(struct b43_wldev *dev)
+static u16 b43_radio_init2050(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
 	struct init2050_saved_values sav;
@@ -3047,6 +3047,8 @@
 	int rfatt, bbatt;
 	u8 tx_control;
 
+	b43_mac_suspend(dev);
+
 	spin_lock_irq(&dev->wl->irq_lock);
 
 	/* Calculate the new attenuation values. */
@@ -3103,6 +3105,8 @@
 			  gphy->tx_control);
 	b43_radio_unlock(dev);
 	b43_phy_unlock(dev);
+
+	b43_mac_enable(dev);
 }
 
 static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
@@ -3215,9 +3219,9 @@
 	struct b43_phy *phy = &dev->phy;
 	struct b43_phy_g *gphy = phy->g;
 
+	b43_mac_suspend(dev);
 	//TODO: update_aci_moving_average
 	if (gphy->aci_enable && gphy->aci_wlan_automatic) {
-		b43_mac_suspend(dev);
 		if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) {
 			if (0 /*TODO: bunch of conditions */ ) {
 				phy->ops->interf_mitigation(dev,
@@ -3227,12 +3231,12 @@
 			   if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev))
 				phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
 		}
-		b43_mac_enable(dev);
 	} else if (gphy->interfmode == B43_INTERFMODE_NONWLAN &&
 		   phy->rev == 1) {
 		//TODO: implement rev1 workaround
 	}
 	b43_lo_g_maintanance_work(dev);
+	b43_mac_enable(dev);
 }
 
 static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index 40159126..1036bef 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -587,9 +587,8 @@
 	spin_lock(&q->lock); /* IRQs are already disabled. */
 
 	info = IEEE80211_SKB_CB(pack->skb);
-	memset(&info->status, 0, sizeof(info->status));
 
-	b43_fill_txstatus_report(info, status);
+	b43_fill_txstatus_report(dev, info, status);
 
 	total_len = pack->skb->len + b43_txhdr_size(dev);
 	total_len = roundup(total_len, 4);
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 2fabcf8..eae9b80 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -46,7 +46,6 @@
 	case 0x6E:
 		return 3;
 	}
-	B43_WARN_ON(1);
 	return -1;
 }
 
@@ -73,7 +72,6 @@
 	case 0xC:
 		return base + 7;
 	}
-	B43_WARN_ON(1);
 	return -1;
 }
 
@@ -185,7 +183,7 @@
 		       u8 *_txhdr,
 		       const unsigned char *fragment_data,
 		       unsigned int fragment_len,
-		       const struct ieee80211_tx_info *info,
+		       struct ieee80211_tx_info *info,
 		       u16 cookie)
 {
 	struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
@@ -202,6 +200,7 @@
 	u16 phy_ctl = 0;
 	u8 extra_ft = 0;
 	struct ieee80211_rate *txrate;
+	struct ieee80211_tx_rate *rates;
 
 	memset(txhdr, 0, sizeof(*txhdr));
 
@@ -291,7 +290,7 @@
 		phy_ctl |= B43_TXH_PHY_ENC_OFDM;
 	else
 		phy_ctl |= B43_TXH_PHY_ENC_CCK;
-	if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
 		phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
 
 	switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) {
@@ -314,6 +313,7 @@
 		B43_WARN_ON(1);
 	}
 
+	rates = info->control.rates;
 	/* MAC control */
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 		mac_ctl |= B43_TXH_MAC_ACK;
@@ -324,12 +324,22 @@
 		mac_ctl |= B43_TXH_MAC_STMSDU;
 	if (phy->type == B43_PHYTYPE_A)
 		mac_ctl |= B43_TXH_MAC_5GHZ;
-	if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
+
+	/* Overwrite rates[0].count to make the retry calculation
+	 * in the tx status easier. need the actual retry limit to
+	 * detect whether the fallback rate was used.
+	 */
+	if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+	    (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
+		rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
 		mac_ctl |= B43_TXH_MAC_LONGFRAME;
+	} else {
+		rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
+	}
 
 	/* Generate the RTS or CTS-to-self frame */
-	if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
-	    (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
+	if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+	    (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
 		unsigned int len;
 		struct ieee80211_hdr *hdr;
 		int rts_rate, rts_rate_fb;
@@ -344,7 +354,7 @@
 		rts_rate_fb = b43_calc_fallback_rate(rts_rate);
 		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
 
-		if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+		if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
 			struct ieee80211_cts *cts;
 
 			if (b43_is_old_txhdr_format(dev)) {
@@ -596,6 +606,8 @@
 						phytype == B43_PHYTYPE_A);
 	else
 		status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp);
+	if (unlikely(status.rate_idx == -1))
+		goto drop;
 	status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
 
 	/*
@@ -687,10 +699,18 @@
 /* Fill out the mac80211 TXstatus report based on the b43-specific
  * txstatus report data. This returns a boolean whether the frame was
  * successfully transmitted. */
-bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
+bool b43_fill_txstatus_report(struct b43_wldev *dev,
+			      struct ieee80211_tx_info *report,
 			      const struct b43_txstatus *status)
 {
 	bool frame_success = 1;
+	int retry_limit;
+
+	/* preserve the confiured retry limit before clearing the status
+	 * The xmit function has overwritten the rc's value with the actual
+	 * retry limit done by the hardware */
+	retry_limit = report->status.rates[0].count;
+	ieee80211_tx_info_clear_status(report);
 
 	if (status->acked) {
 		/* The frame was ACKed. */
@@ -700,14 +720,32 @@
 		if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) {
 			/* ...but we expected an ACK. */
 			frame_success = 0;
-			report->status.excessive_retries = 1;
 		}
 	}
 	if (status->frame_count == 0) {
 		/* The frame was not transmitted at all. */
-		report->status.retry_count = 0;
-	} else
-		report->status.retry_count = status->frame_count - 1;
+		report->status.rates[0].count = 0;
+	} else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
+		/*
+		 * If the short retries (RTS, not data frame) have exceeded
+		 * the limit, the hw will not have tried the selected rate,
+		 * but will have used the fallback rate instead.
+		 * Don't let the rate control count attempts for the selected
+		 * rate in this case, otherwise the statistics will be off.
+		 */
+		report->status.rates[0].count = 0;
+		report->status.rates[1].count = status->frame_count;
+	} else {
+		if (status->frame_count > retry_limit) {
+			report->status.rates[0].count = retry_limit;
+			report->status.rates[1].count = status->frame_count -
+					retry_limit;
+
+		} else {
+			report->status.rates[0].count = status->frame_count;
+			report->status.rates[1].idx = -1;
+		}
+	}
 
 	return frame_success;
 }
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index 0215faf..4fb2a19 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -178,7 +178,7 @@
 		       u8 * txhdr,
 		       const unsigned char *fragment_data,
 		       unsigned int fragment_len,
-		       const struct ieee80211_tx_info *txctl, u16 cookie);
+		       struct ieee80211_tx_info *txctl, u16 cookie);
 
 /* Transmit Status */
 struct b43_txstatus {
@@ -294,7 +294,8 @@
 
 void b43_handle_txstatus(struct b43_wldev *dev,
 			 const struct b43_txstatus *status);
-bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
+bool b43_fill_txstatus_report(struct b43_wldev *dev,
+			      struct ieee80211_tx_info *report,
 			      const struct b43_txstatus *status);
 
 void b43_tx_suspend(struct b43_wldev *dev);
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index c40078e..97b0e06 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -145,6 +145,10 @@
 #define B43legacy_SHM_SH_PRMAXTIME	0x0074 /* Probe Response max time */
 #define B43legacy_SHM_SH_PRPHYCTL	0x0188 /* Probe Resp PHY TX control */
 /* SHM_SHARED rate tables */
+#define B43legacy_SHM_SH_OFDMDIRECT	0x0480 /* Pointer to OFDM direct map */
+#define B43legacy_SHM_SH_OFDMBASIC	0x04A0 /* Pointer to OFDM basic rate map */
+#define B43legacy_SHM_SH_CCKDIRECT	0x04C0 /* Pointer to CCK direct map */
+#define B43legacy_SHM_SH_CCKBASIC	0x04E0 /* Pointer to CCK basic rate map */
 /* SHM_SHARED microcode soft registers */
 #define B43legacy_SHM_SH_UCODEREV	0x0000 /* Microcode revision */
 #define B43legacy_SHM_SH_UCODEPATCH	0x0002 /* Microcode patchlevel */
@@ -663,7 +667,6 @@
 	bool bad_frames_preempt;/* Use "Bad Frames Preemption". */
 	bool dfq_valid;		/* Directed frame queue valid (IBSS PS mode, ATIM). */
 	bool short_preamble;	/* TRUE if using short preamble. */
-	bool short_slot;	/* TRUE if using short slot timing. */
 	bool radio_hw_enable;	/* State of radio hardware enable bit. */
 
 	/* PHY/Radio device. */
diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c
index 03ce082..1f85ac5 100644
--- a/drivers/net/wireless/b43legacy/debugfs.c
+++ b/drivers/net/wireless/b43legacy/debugfs.c
@@ -211,7 +211,7 @@
 	struct b43legacy_dfs_file *dfile;
 	ssize_t uninitialized_var(ret);
 	char *buf;
-	const size_t bufsize = 1024 * 128;
+	const size_t bufsize = 1024 * 16; /* 16 KiB buffer */
 	const size_t buforder = get_order(bufsize);
 	int err = 0;
 
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index fb6819e..3649fc3 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -919,7 +919,7 @@
 			if (!ring->txhdr_cache)
 				goto err_kfree_meta;
 
-				dma_test = ssb_dma_map_single(dev->dev,
+			dma_test = ssb_dma_map_single(dev->dev,
 					ring->txhdr_cache,
 					sizeof(struct b43legacy_txhdr_fw3),
 					DMA_TO_DEVICE);
@@ -1411,6 +1411,7 @@
 	struct b43legacy_dmaring *ring;
 	struct b43legacy_dmadesc_generic *desc;
 	struct b43legacy_dmadesc_meta *meta;
+	int retry_limit;
 	int slot;
 
 	ring = parse_cookie(dev, status->cookie, &slot);
@@ -1437,25 +1438,42 @@
 			struct ieee80211_tx_info *info;
 			BUG_ON(!meta->skb);
 			info = IEEE80211_SKB_CB(meta->skb);
+
+			/* preserve the confiured retry limit before clearing the status
+			 * The xmit function has overwritten the rc's value with the actual
+			 * retry limit done by the hardware */
+			retry_limit = info->status.rates[0].count;
+			ieee80211_tx_info_clear_status(info);
+
+			if (status->acked)
+				info->flags |= IEEE80211_TX_STAT_ACK;
+
+			if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
+				/*
+				 * If the short retries (RTS, not data frame) have exceeded
+				 * the limit, the hw will not have tried the selected rate,
+				 * but will have used the fallback rate instead.
+				 * Don't let the rate control count attempts for the selected
+				 * rate in this case, otherwise the statistics will be off.
+				 */
+				info->status.rates[0].count = 0;
+				info->status.rates[1].count = status->frame_count;
+			} else {
+				if (status->frame_count > retry_limit) {
+					info->status.rates[0].count = retry_limit;
+					info->status.rates[1].count = status->frame_count -
+							retry_limit;
+
+				} else {
+					info->status.rates[0].count = status->frame_count;
+					info->status.rates[1].idx = -1;
+				}
+			}
+
 			/* Call back to inform the ieee80211 subsystem about the
 			 * status of the transmission.
 			 * Some fields of txstat are already filled in dma_tx().
 			 */
-
-			memset(&info->status, 0, sizeof(info->status));
-
-			if (status->acked) {
-				info->flags |= IEEE80211_TX_STAT_ACK;
-			} else {
-				if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
-					 info->status.excessive_retries = 1;
-			}
-			if (status->frame_count == 0) {
-				/* The frame was not transmitted at all. */
-				info->status.retry_count = 0;
-			} else
-				info->status.retry_count = status->frame_count
-							   - 1;
 			ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
 			/* skb is freed by ieee80211_tx_status_irqsafe() */
 			meta->skb = NULL;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index c66d575..c1324e3 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -576,13 +576,11 @@
 static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev)
 {
 	b43legacy_set_slot_time(dev, 9);
-	dev->short_slot = 1;
 }
 
 static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev)
 {
 	b43legacy_set_slot_time(dev, 20);
-	dev->short_slot = 0;
 }
 
 /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
@@ -1160,29 +1158,6 @@
 	wl->beacon1_uploaded = 0;
 }
 
-static void b43legacy_set_ssid(struct b43legacy_wldev *dev,
-			       const u8 *ssid, u8 ssid_len)
-{
-	u32 tmp;
-	u16 i;
-	u16 len;
-
-	len = min((u16)ssid_len, (u16)0x100);
-	for (i = 0; i < len; i += sizeof(u32)) {
-		tmp = (u32)(ssid[i + 0]);
-		if (i + 1 < len)
-			tmp |= (u32)(ssid[i + 1]) << 8;
-		if (i + 2 < len)
-			tmp |= (u32)(ssid[i + 2]) << 16;
-		if (i + 3 < len)
-			tmp |= (u32)(ssid[i + 3]) << 24;
-		b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
-				      0x380 + i, tmp);
-	}
-	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
-			      0x48, len);
-}
-
 static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
 				     u16 beacon_int)
 {
@@ -2556,26 +2531,27 @@
 	return err;
 }
 
-static int b43legacy_antenna_from_ieee80211(u8 antenna)
+/* Write the short and long frame retry limit values. */
+static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev,
+				       unsigned int short_retry,
+				       unsigned int long_retry)
 {
-	switch (antenna) {
-	case 0: /* default/diversity */
-		return B43legacy_ANTENNA_DEFAULT;
-	case 1: /* Antenna 0 */
-		return B43legacy_ANTENNA0;
-	case 2: /* Antenna 1 */
-		return B43legacy_ANTENNA1;
-	default:
-		return B43legacy_ANTENNA_DEFAULT;
-	}
+	/* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
+	 * the chip-internal counter. */
+	short_retry = min(short_retry, (unsigned int)0xF);
+	long_retry = min(long_retry, (unsigned int)0xF);
+
+	b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry);
+	b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry);
 }
 
 static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
-				   struct ieee80211_conf *conf)
+				   u32 changed)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev;
 	struct b43legacy_phy *phy;
+	struct ieee80211_conf *conf = &hw->conf;
 	unsigned long flags;
 	unsigned int new_phymode = 0xFFFF;
 	int antenna_tx;
@@ -2583,13 +2559,21 @@
 	int err = 0;
 	u32 savedirqs;
 
-	antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx);
-	antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx);
+	antenna_tx = B43legacy_ANTENNA_DEFAULT;
+	antenna_rx = B43legacy_ANTENNA_DEFAULT;
 
 	mutex_lock(&wl->mutex);
 	dev = wl->current_dev;
 	phy = &dev->phy;
 
+	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+		b43legacy_set_retry_limits(dev,
+					   conf->short_frame_max_tx_count,
+					   conf->long_frame_max_tx_count);
+	changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
+	if (!changed)
+		goto out_unlock_mutex;
+
 	/* Switch the PHY mode (if necessary). */
 	switch (conf->channel->band) {
 	case IEEE80211_BAND_2GHZ:
@@ -2622,16 +2606,6 @@
 	if (conf->channel->hw_value != phy->channel)
 		b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0);
 
-	/* Enable/Disable ShortSlot timing. */
-	if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME))
-	     != dev->short_slot) {
-		B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G);
-		if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
-			b43legacy_short_slot_timing_enable(dev);
-		else
-			b43legacy_short_slot_timing_disable(dev);
-	}
-
 	dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
 
 	/* Adjust the desired TX power level. */
@@ -2676,6 +2650,104 @@
 	return err;
 }
 
+static void b43legacy_update_basic_rates(struct b43legacy_wldev *dev, u64 brates)
+{
+	struct ieee80211_supported_band *sband =
+		dev->wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+	struct ieee80211_rate *rate;
+	int i;
+	u16 basic, direct, offset, basic_offset, rateptr;
+
+	for (i = 0; i < sband->n_bitrates; i++) {
+		rate = &sband->bitrates[i];
+
+		if (b43legacy_is_cck_rate(rate->hw_value)) {
+			direct = B43legacy_SHM_SH_CCKDIRECT;
+			basic = B43legacy_SHM_SH_CCKBASIC;
+			offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value);
+			offset &= 0xF;
+		} else {
+			direct = B43legacy_SHM_SH_OFDMDIRECT;
+			basic = B43legacy_SHM_SH_OFDMBASIC;
+			offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value);
+			offset &= 0xF;
+		}
+
+		rate = ieee80211_get_response_rate(sband, brates, rate->bitrate);
+
+		if (b43legacy_is_cck_rate(rate->hw_value)) {
+			basic_offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value);
+			basic_offset &= 0xF;
+		} else {
+			basic_offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value);
+			basic_offset &= 0xF;
+		}
+
+		/*
+		 * Get the pointer that we need to point to
+		 * from the direct map
+		 */
+		rateptr = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+					       direct + 2 * basic_offset);
+		/* and write it to the basic map */
+		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+				      basic + 2 * offset, rateptr);
+	}
+}
+
+static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_bss_conf *conf,
+				    u32 changed)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev;
+	struct b43legacy_phy *phy;
+	unsigned long flags;
+	u32 savedirqs;
+
+	mutex_lock(&wl->mutex);
+
+	dev = wl->current_dev;
+	phy = &dev->phy;
+
+	/* Disable IRQs while reconfiguring the device.
+	 * This makes it possible to drop the spinlock throughout
+	 * the reconfiguration process. */
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
+		spin_unlock_irqrestore(&wl->irq_lock, flags);
+		goto out_unlock_mutex;
+	}
+	savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	b43legacy_synchronize_irq(dev);
+
+	b43legacy_mac_suspend(dev);
+
+	if (changed & BSS_CHANGED_BASIC_RATES)
+		b43legacy_update_basic_rates(dev, conf->basic_rates);
+
+	if (changed & BSS_CHANGED_ERP_SLOT) {
+		if (conf->use_short_slot)
+			b43legacy_short_slot_timing_enable(dev);
+		else
+			b43legacy_short_slot_timing_disable(dev);
+	}
+
+	b43legacy_mac_enable(dev);
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43legacy_interrupt_enable(dev, savedirqs);
+	/* XXX: why? */
+	mmiowb();
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+ out_unlock_mutex:
+	mutex_unlock(&wl->mutex);
+
+	return;
+}
+
 static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
 					  unsigned int changed,
 					  unsigned int *fflags,
@@ -2735,7 +2807,6 @@
 	if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
 		if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) {
 			B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP);
-			b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
 			if (conf->changed & IEEE80211_IFCC_BEACON)
 				b43legacy_update_templates(wl);
 		} else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
@@ -3002,20 +3073,6 @@
 #endif /* CONFIG_SSB_DRIVER_PCICORE */
 }
 
-/* Write the short and long frame retry limit values. */
-static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev,
-				       unsigned int short_retry,
-				       unsigned int long_retry)
-{
-	/* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
-	 * the chip-internal counter. */
-	short_retry = min(short_retry, (unsigned int)0xF);
-	long_retry = min(long_retry, (unsigned int)0xF);
-
-	b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry);
-	b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry);
-}
-
 static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev,
 					  bool idle) {
 	u16 pu_delay = 1050;
@@ -3380,28 +3437,6 @@
 	mutex_unlock(&wl->mutex);
 }
 
-static int b43legacy_op_set_retry_limit(struct ieee80211_hw *hw,
-					u32 short_retry_limit,
-					u32 long_retry_limit)
-{
-	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
-	struct b43legacy_wldev *dev;
-	int err = 0;
-
-	mutex_lock(&wl->mutex);
-	dev = wl->current_dev;
-	if (unlikely(!dev ||
-		     (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED))) {
-		err = -ENODEV;
-		goto out_unlock;
-	}
-	b43legacy_set_retry_limits(dev, short_retry_limit, long_retry_limit);
-out_unlock:
-	mutex_unlock(&wl->mutex);
-
-	return err;
-}
-
 static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
 				       struct ieee80211_sta *sta, bool set)
 {
@@ -3421,13 +3456,13 @@
 	.add_interface		= b43legacy_op_add_interface,
 	.remove_interface	= b43legacy_op_remove_interface,
 	.config			= b43legacy_op_dev_config,
+	.bss_info_changed	= b43legacy_op_bss_info_changed,
 	.config_interface	= b43legacy_op_config_interface,
 	.configure_filter	= b43legacy_op_configure_filter,
 	.get_stats		= b43legacy_op_get_stats,
 	.get_tx_stats		= b43legacy_op_get_tx_stats,
 	.start			= b43legacy_op_start,
 	.stop			= b43legacy_op_stop,
-	.set_retry_limit	= b43legacy_op_set_retry_limit,
 	.set_tim		= b43legacy_op_beacon_set_tim,
 };
 
@@ -3710,7 +3745,7 @@
 		BIT(NL80211_IFTYPE_WDS) |
 		BIT(NL80211_IFTYPE_ADHOC);
 	hw->queues = 1; /* FIXME: hardware has more queues */
-	hw->max_altrates = 1;
+	hw->max_rates = 2;
 	SET_IEEE80211_DEV(hw, dev->dev);
 	if (is_valid_ether_addr(sprom->et1mac))
 		SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
index 4c9442b..11319ec 100644
--- a/drivers/net/wireless/b43legacy/phy.c
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -1296,12 +1296,10 @@
 	/* Sanity check. */
 	if (pair->low < -8 || pair->low > 8 ||
 	    pair->high < -8 || pair->high > 8) {
-		struct b43legacy_phy *phy = &dev->phy;
 		b43legacydbg(dev->wl,
 		       "WARNING: Writing invalid LOpair "
-		       "(low: %d, high: %d, index: %lu)\n",
-		       pair->low, pair->high,
-		       (unsigned long)(pair - phy->_lo_pairs));
+		       "(low: %d, high: %d)\n",
+		       pair->low, pair->high);
 		dump_stack();
 	}
 #endif
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
index a86c764..746d536 100644
--- a/drivers/net/wireless/b43legacy/pio.c
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -491,6 +491,7 @@
 	struct b43legacy_pioqueue *queue;
 	struct b43legacy_pio_txpacket *packet;
 	struct ieee80211_tx_info *info;
+	int retry_limit;
 
 	queue = parse_cookie(dev, status->cookie, &packet);
 	B43legacy_WARN_ON(!queue);
@@ -503,11 +504,37 @@
 				sizeof(struct b43legacy_txhdr_fw3));
 
 	info = IEEE80211_SKB_CB(packet->skb);
-	memset(&info->status, 0, sizeof(info->status));
+
+	/* preserve the confiured retry limit before clearing the status
+	 * The xmit function has overwritten the rc's value with the actual
+	 * retry limit done by the hardware */
+	retry_limit = info->status.rates[0].count;
+	ieee80211_tx_info_clear_status(info);
 
 	if (status->acked)
 		info->flags |= IEEE80211_TX_STAT_ACK;
-	info->status.retry_count = status->frame_count - 1;
+
+	if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
+		/*
+		 * If the short retries (RTS, not data frame) have exceeded
+		 * the limit, the hw will not have tried the selected rate,
+		 * but will have used the fallback rate instead.
+		 * Don't let the rate control count attempts for the selected
+		 * rate in this case, otherwise the statistics will be off.
+		 */
+		info->status.rates[0].count = 0;
+		info->status.rates[1].count = status->frame_count;
+	} else {
+		if (status->frame_count > retry_limit) {
+			info->status.rates[0].count = retry_limit;
+			info->status.rates[1].count = status->frame_count -
+					retry_limit;
+
+		} else {
+			info->status.rates[0].count = status->frame_count;
+			info->status.rates[1].idx = -1;
+		}
+	}
 	ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
 	packet->skb = NULL;
 
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index 65e8337..12fca99 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -188,7 +188,7 @@
 			       struct b43legacy_txhdr_fw3 *txhdr,
 			       const unsigned char *fragment_data,
 			       unsigned int fragment_len,
-			       const struct ieee80211_tx_info *info,
+			       struct ieee80211_tx_info *info,
 			       u16 cookie)
 {
 	const struct ieee80211_hdr *wlhdr;
@@ -201,6 +201,7 @@
 	u32 mac_ctl = 0;
 	u16 phy_ctl = 0;
 	struct ieee80211_rate *tx_rate;
+	struct ieee80211_tx_rate *rates;
 
 	wlhdr = (const struct ieee80211_hdr *)fragment_data;
 
@@ -274,7 +275,7 @@
 	/* PHY TX Control word */
 	if (rate_ofdm)
 		phy_ctl |= B43legacy_TX4_PHY_OFDM;
-	if (dev->short_preamble)
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
 		phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
 	switch (info->antenna_sel_tx) {
 	case 0:
@@ -291,6 +292,7 @@
 	}
 
 	/* MAC control */
+	rates = info->control.rates;
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 		mac_ctl |= B43legacy_TX4_MAC_ACK;
 	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
@@ -299,12 +301,22 @@
 		mac_ctl |= B43legacy_TX4_MAC_STMSDU;
 	if (rate_fb_ofdm)
 		mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
-	if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
+
+	/* Overwrite rates[0].count to make the retry calculation
+	 * in the tx status easier. need the actual retry limit to
+	 * detect whether the fallback rate was used.
+	 */
+	if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+	    (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
+		rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
 		mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
+	} else {
+		rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
+	}
 
 	/* Generate the RTS or CTS-to-self frame */
-	if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
-	    (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
+	if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+	    (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
 		unsigned int len;
 		struct ieee80211_hdr *hdr;
 		int rts_rate;
@@ -319,7 +331,7 @@
 		if (rts_rate_fb_ofdm)
 			mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
 
-		if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+		if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
 			ieee80211_ctstoself_get(dev->wl->hw,
 						info->control.vif,
 						fragment_data,
@@ -362,7 +374,7 @@
 			      u8 *txhdr,
 			      const unsigned char *fragment_data,
 			      unsigned int fragment_len,
-			      const struct ieee80211_tx_info *info,
+			      struct ieee80211_tx_info *info,
 			      u16 cookie)
 {
 	return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
index e56777e0f..62e09d0 100644
--- a/drivers/net/wireless/b43legacy/xmit.h
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -80,7 +80,7 @@
 			      u8 *txhdr,
 			      const unsigned char *fragment_data,
 			      unsigned int fragment_len,
-			      const struct ieee80211_tx_info *info,
+			      struct ieee80211_tx_info *info,
 			      u16 cookie);
 
 
diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig
index 1fef331..932d207 100644
--- a/drivers/net/wireless/hostap/Kconfig
+++ b/drivers/net/wireless/hostap/Kconfig
@@ -2,8 +2,17 @@
 	tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)"
 	depends on WLAN_80211
 	select WIRELESS_EXT
-	select IEEE80211
-	select IEEE80211_CRYPT_WEP
+	select CRYPTO
+	select CRYPTO_ARC4
+	select CRYPTO_ECB
+	select CRYPTO_AES
+	select CRYPTO_MICHAEL_MIC
+	select CRYPTO_ECB
+	select CRC32
+	select LIB80211
+	select LIB80211_CRYPT_WEP
+	select LIB80211_CRYPT_TKIP
+	select LIB80211_CRYPT_CCMP
 	---help---
 	Shared driver code for IEEE 802.11b wireless cards based on
 	Intersil Prism2/2.5/3 chipset. This driver supports so called
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h
index 3a386a6..2453dea 100644
--- a/drivers/net/wireless/hostap/hostap.h
+++ b/drivers/net/wireless/hostap/hostap.h
@@ -63,7 +63,7 @@
 int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac);
 void ap_control_kickall(struct ap_data *ap);
 void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
-			 struct ieee80211_crypt_data ***crypt);
+			 struct lib80211_crypt_data ***crypt);
 int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
 			   struct iw_quality qual[], int buf_size,
 			   int aplist);
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h
index 3694b1e..3a9474d 100644
--- a/drivers/net/wireless/hostap/hostap_80211.h
+++ b/drivers/net/wireless/hostap/hostap_80211.h
@@ -2,7 +2,7 @@
 #define HOSTAP_80211_H
 
 #include <linux/types.h>
-#include <net/ieee80211_crypt.h>
+#include <net/ieee80211.h>
 
 struct hostap_ieee80211_mgmt {
 	__le16 frame_control;
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index f106bc1..19b1bf0 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -1,5 +1,5 @@
 #include <linux/etherdevice.h>
-#include <net/ieee80211_crypt.h>
+#include <net/lib80211.h>
 
 #include "hostap_80211.h"
 #include "hostap.h"
@@ -19,7 +19,6 @@
 {
 	struct ieee80211_hdr_4addr *hdr;
 	u16 fc;
-	DECLARE_MAC_BUF(mac);
 
 	hdr = (struct ieee80211_hdr_4addr *) skb->data;
 
@@ -45,11 +44,11 @@
 	printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
 	       le16_to_cpu(hdr->seq_ctl));
 
-	printk(KERN_DEBUG "   A1=%s", print_mac(mac, hdr->addr1));
-	printk(" A2=%s", print_mac(mac, hdr->addr2));
-	printk(" A3=%s", print_mac(mac, hdr->addr3));
+	printk(KERN_DEBUG "   A1=%pM", hdr->addr1);
+	printk(" A2=%pM", hdr->addr2);
+	printk(" A3=%pM", hdr->addr3);
 	if (skb->len >= 30)
-		printk(" A4=%s", print_mac(mac, hdr->addr4));
+		printk(" A4=%pM", hdr->addr4);
 	printk("\n");
 }
 
@@ -68,7 +67,6 @@
 
 	iface = netdev_priv(dev);
 	local = iface->local;
-	dev->last_rx = jiffies;
 
 	if (dev->type == ARPHRD_IEEE80211_PRISM) {
 		if (local->monitor_type == PRISM2_MONITOR_PRISM) {
@@ -557,7 +555,6 @@
 hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
 		    u16 fc, struct net_device **wds)
 {
-	DECLARE_MAC_BUF(mac);
 	/* FIX: is this really supposed to accept WDS frames only in Master
 	 * mode? What about Repeater or Managed with WDS frames? */
 	if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) !=
@@ -573,10 +570,10 @@
 	     hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
 		/* RA (or BSSID) is not ours - drop */
 		PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with "
-		       "not own or broadcast %s=%s\n",
+		       "not own or broadcast %s=%pM\n",
 		       local->dev->name,
 		       fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
-		       print_mac(mac, hdr->addr1));
+		       hdr->addr1);
 		return -1;
 	}
 
@@ -589,8 +586,8 @@
 		/* require that WDS link has been registered with TA or the
 		 * frame is from current AP when using 'AP client mode' */
 		PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame "
-		       "from unknown TA=%s\n",
-		       local->dev->name, print_mac(mac, hdr->addr2));
+		       "from unknown TA=%pM\n",
+		       local->dev->name, hdr->addr2);
 		if (local->ap && local->ap->autom_ap_wds)
 			hostap_wds_link_oper(local, hdr->addr2, WDS_ADD);
 		return -1;
@@ -652,7 +649,7 @@
 /* Called only as a tasklet (software IRQ) */
 static int
 hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
-			struct ieee80211_crypt_data *crypt)
+			struct lib80211_crypt_data *crypt)
 {
 	struct ieee80211_hdr_4addr *hdr;
 	int res, hdrlen;
@@ -667,10 +664,8 @@
 	    strcmp(crypt->ops->name, "TKIP") == 0) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
-			       "received packet from " MAC_FMT "\n",
-			       local->dev->name,
-			       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-			       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+			       "received packet from %pM\n",
+			       local->dev->name, hdr->addr2);
 		}
 		return -1;
 	}
@@ -679,12 +674,8 @@
 	res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
 	atomic_dec(&crypt->refcnt);
 	if (res < 0) {
-		printk(KERN_DEBUG "%s: decryption failed (SA=" MAC_FMT
-		       ") res=%d\n",
-		       local->dev->name,
-		       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-		       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
-		       res);
+		printk(KERN_DEBUG "%s: decryption failed (SA=%pM) res=%d\n",
+		       local->dev->name, hdr->addr2, res);
 		local->comm_tallies.rx_discards_wep_undecryptable++;
 		return -1;
 	}
@@ -696,11 +687,10 @@
 /* Called only as a tasklet (software IRQ) */
 static int
 hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
-			     int keyidx, struct ieee80211_crypt_data *crypt)
+			     int keyidx, struct lib80211_crypt_data *crypt)
 {
 	struct ieee80211_hdr_4addr *hdr;
 	int res, hdrlen;
-	DECLARE_MAC_BUF(mac);
 
 	if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
 		return 0;
@@ -713,8 +703,8 @@
 	atomic_dec(&crypt->refcnt);
 	if (res < 0) {
 		printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
-		       " (SA=%s keyidx=%d)\n",
-		       local->dev->name, print_mac(mac, hdr->addr2), keyidx);
+		       " (SA=%pM keyidx=%d)\n",
+		       local->dev->name, hdr->addr2, keyidx);
 		return -1;
 	}
 
@@ -743,7 +733,7 @@
 	int from_assoc_ap = 0;
 	u8 dst[ETH_ALEN];
 	u8 src[ETH_ALEN];
-	struct ieee80211_crypt_data *crypt = NULL;
+	struct lib80211_crypt_data *crypt = NULL;
 	void *sta = NULL;
 	int keyidx = 0;
 
@@ -795,7 +785,7 @@
 		int idx = 0;
 		if (skb->len >= hdrlen + 3)
 			idx = skb->data[hdrlen + 3] >> 6;
-		crypt = local->crypt[idx];
+		crypt = local->crypt_info.crypt[idx];
 		sta = NULL;
 
 		/* Use station specific key to override default keys if the
@@ -822,10 +812,8 @@
 			 * frames silently instead of filling system log with
 			 * these reports. */
 			printk(KERN_DEBUG "%s: WEP decryption failed (not set)"
-			       " (SA=" MAC_FMT ")\n",
-			       local->dev->name,
-			       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-			       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+			       " (SA=%pM)\n",
+			       local->dev->name, hdr->addr2);
 #endif
 			local->comm_tallies.rx_discards_wep_undecryptable++;
 			goto rx_dropped;
@@ -839,9 +827,7 @@
 		    (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
 		{
 			printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
-			       "from " MAC_FMT "\n", dev->name,
-			       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-			       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+			       "from %pM\n", dev->name, hdr->addr2);
 			/* TODO: could inform hostapd about this so that it
 			 * could send auth failure report */
 			goto rx_dropped;
@@ -896,8 +882,6 @@
 		from_assoc_ap = 1;
 	}
 
-	dev->last_rx = jiffies;
-
 	if ((local->iw_mode == IW_MODE_MASTER ||
 	     local->iw_mode == IW_MODE_REPEAT) &&
 	    !from_assoc_ap) {
@@ -1009,10 +993,8 @@
 			       "unencrypted EAPOL frame\n", local->dev->name);
 		} else {
 			printk(KERN_DEBUG "%s: encryption configured, but RX "
-			       "frame not encrypted (SA=" MAC_FMT ")\n",
-			       local->dev->name,
-			       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-			       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+			       "frame not encrypted (SA=%pM)\n",
+			       local->dev->name, hdr->addr2);
 			goto rx_dropped;
 		}
 	}
@@ -1021,10 +1003,8 @@
 	    !hostap_is_eapol_frame(local, skb)) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: dropped unencrypted RX data "
-			       "frame from " MAC_FMT " (drop_unencrypted=1)\n",
-			       dev->name,
-			       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-			       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+			       "frame from %pM (drop_unencrypted=1)\n",
+			       dev->name, hdr->addr2);
 		}
 		goto rx_dropped;
 	}
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 921c984..078a010 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -17,7 +17,6 @@
 {
 	struct ieee80211_hdr_4addr *hdr;
 	u16 fc;
-	DECLARE_MAC_BUF(mac);
 
 	hdr = (struct ieee80211_hdr_4addr *) skb->data;
 
@@ -41,11 +40,11 @@
 	printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
 	       le16_to_cpu(hdr->seq_ctl));
 
-	printk(KERN_DEBUG "   A1=%s", print_mac(mac, hdr->addr1));
-	printk(" A2=%s", print_mac(mac, hdr->addr2));
-	printk(" A3=%s", print_mac(mac, hdr->addr3));
+	printk(KERN_DEBUG "   A1=%pM", hdr->addr1);
+	printk(" A2=%pM", hdr->addr2);
+	printk(" A3=%pM", hdr->addr3);
 	if (skb->len >= 30)
-		printk(" A4=%s", print_mac(mac, hdr->addr4));
+		printk(" A4=%pM", hdr->addr4);
 	printk("\n");
 }
 
@@ -307,7 +306,7 @@
 
 /* Called only from software IRQ */
 static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
-					  struct ieee80211_crypt_data *crypt)
+					  struct lib80211_crypt_data *crypt)
 {
 	struct hostap_interface *iface;
 	local_info_t *local;
@@ -328,10 +327,8 @@
 		hdr = (struct ieee80211_hdr_4addr *) skb->data;
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
-			       "TX packet to " MAC_FMT "\n",
-			       local->dev->name,
-			       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
-			       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+			       "TX packet to %pM\n",
+			       local->dev->name, hdr->addr1);
 		}
 		kfree_skb(skb);
 		return NULL;
@@ -408,7 +405,7 @@
 	if (local->host_encrypt) {
 		/* Set crypt to default algorithm and key; will be replaced in
 		 * AP code if STA has own alg/key */
-		tx.crypt = local->crypt[local->tx_keyidx];
+		tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx];
 		tx.host_encrypt = 1;
 	} else {
 		tx.crypt = NULL;
@@ -490,7 +487,9 @@
 
 	if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu))
 		tx.crypt = NULL;
-	else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) {
+	else if ((tx.crypt ||
+		 local->crypt_info.crypt[local->crypt_info.tx_keyidx]) &&
+		 !no_encrypt) {
 		/* Add ISWEP flag both for firmware and host based encryption
 		 */
 		fc |= IEEE80211_FCTL_PROTECTED;
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index af3d4ef..0903db7 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -94,7 +94,6 @@
 static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
 {
 	struct sta_info *s;
-	DECLARE_MAC_BUF(mac);
 
 	s = ap->sta_hash[STA_HASH(sta->addr)];
 	if (s == NULL) return;
@@ -109,20 +108,18 @@
 	if (s->hnext != NULL)
 		s->hnext = s->hnext->hnext;
 	else
-		printk("AP: could not remove STA %s"
-		       " from hash table\n",
-		       print_mac(mac, sta->addr));
+		printk("AP: could not remove STA %pM from hash table\n",
+		       sta->addr);
 }
 
 static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
 {
-	DECLARE_MAC_BUF(mac);
 	if (sta->ap && sta->local)
 		hostap_event_expired_sta(sta->local->dev, sta);
 
 	if (ap->proc != NULL) {
 		char name[20];
-		sprintf(name, "%s", print_mac(mac, sta->addr));
+		sprintf(name, "%pM", sta->addr);
 		remove_proc_entry(name, ap->proc);
 	}
 
@@ -185,7 +182,6 @@
 	struct ap_data *ap;
 	unsigned long next_time = 0;
 	int was_assoc;
-	DECLARE_MAC_BUF(mac);
 
 	if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) {
 		PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n");
@@ -242,8 +238,8 @@
 	if (sta->ap) {
 		if (ap->autom_ap_wds) {
 			PDEBUG(DEBUG_AP, "%s: removing automatic WDS "
-			       "connection to AP %s\n",
-			       local->dev->name, print_mac(mac, sta->addr));
+			       "connection to AP %pM\n",
+			       local->dev->name, sta->addr);
 			hostap_wds_link_oper(local, sta->addr, WDS_DEL);
 		}
 	} else if (sta->timeout_next == STA_NULLFUNC) {
@@ -259,11 +255,11 @@
 	} else {
 		int deauth = sta->timeout_next == STA_DEAUTH;
 		__le16 resp;
-		PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s"
+		PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM"
 		       "(last=%lu, jiffies=%lu)\n",
 		       local->dev->name,
 		       deauth ? "deauthentication" : "disassociation",
-		       print_mac(mac, sta->addr), sta->last_rx, jiffies);
+		       sta->addr, sta->last_rx, jiffies);
 
 		resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID :
 				   WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
@@ -275,10 +271,10 @@
 
 	if (sta->timeout_next == STA_DEAUTH) {
 		if (sta->flags & WLAN_STA_PERM) {
-			PDEBUG(DEBUG_AP, "%s: STA %s"
+			PDEBUG(DEBUG_AP, "%s: STA %pM"
 			       " would have been removed, "
 			       "but it has 'perm' flag\n",
-			       local->dev->name, print_mac(mac, sta->addr));
+			       local->dev->name, sta->addr);
 		} else
 			ap_free_sta(ap, sta);
 		return;
@@ -332,7 +328,6 @@
 	struct ap_data *ap = (struct ap_data *) data;
 	char *policy_txt;
 	struct mac_entry *entry;
-	DECLARE_MAC_BUF(mac);
 
 	if (off != 0) {
 		*eof = 1;
@@ -363,7 +358,7 @@
 			break;
 		}
 
-		p += sprintf(p, "%s\n", print_mac(mac, entry->addr));
+		p += sprintf(p, "%pM\n", entry->addr);
 	}
 	spin_unlock_bh(&ap->mac_restrictions.lock);
 
@@ -520,7 +515,6 @@
 	struct ap_data *ap = (struct ap_data *) data;
 	struct sta_info *sta;
 	int i;
-	DECLARE_MAC_BUF(mac);
 
 	if (off > PROC_LIMIT) {
 		*eof = 1;
@@ -533,8 +527,8 @@
 		if (!sta->ap)
 			continue;
 
-		p += sprintf(p, "%s %d %d %d %d '",
-			     print_mac(mac, sta->addr),
+		p += sprintf(p, "%pM %d %d %d %d '",
+			     sta->addr,
 			     sta->u.ap.channel, sta->last_rx_signal,
 			     sta->last_rx_silence, sta->last_rx_rate);
 		for (i = 0; i < sta->u.ap.ssid_len; i++)
@@ -683,11 +677,9 @@
 	if (sta)
 		atomic_dec(&sta->users);
 	if (txt) {
-		PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth_cb - alg=%d "
+		PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d "
 		       "trans#=%d status=%d - %s\n",
-		       dev->name,
-		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
-		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
+		       dev->name, hdr->addr1,
 		       auth_alg, auth_transaction, status, txt);
 	}
 	dev_kfree_skb(skb);
@@ -754,11 +746,8 @@
 	if (sta)
 		atomic_dec(&sta->users);
 	if (txt) {
-		PDEBUG(DEBUG_AP, "%s: " MAC_FMT " assoc_cb - %s\n",
-		       dev->name,
-		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
-		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
-		       txt);
+		PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n",
+		       dev->name, hdr->addr1, txt);
 	}
 	dev_kfree_skb(skb);
 }
@@ -781,11 +770,9 @@
 			sta->flags &= ~WLAN_STA_PENDING_POLL;
 		spin_unlock(&ap->sta_table_lock);
 	} else {
-		PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT
-		       " did not ACK activity poll frame\n",
-		       ap->local->dev->name,
-		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
-		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+		PDEBUG(DEBUG_AP,
+		       "%s: STA %pM did not ACK activity poll frame\n",
+		       ap->local->dev->name, hdr->addr1);
 	}
 
  fail:
@@ -1002,7 +989,6 @@
 	char *p = page;
 	struct sta_info *sta = (struct sta_info *) data;
 	int i;
-	DECLARE_MAC_BUF(mac);
 
 	/* FIX: possible race condition.. the STA data could have just expired,
 	 * but proc entry was still here so that the read could have started;
@@ -1013,11 +999,11 @@
 		return 0;
 	}
 
-	p += sprintf(p, "%s=%s\nusers=%d\naid=%d\n"
+	p += sprintf(p, "%s=%pM\nusers=%d\naid=%d\n"
 		     "flags=0x%04x%s%s%s%s%s%s%s\n"
 		     "capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
 		     sta->ap ? "AP" : "STA",
-		     print_mac(mac, sta->addr), atomic_read(&sta->users), sta->aid,
+		     sta->addr, atomic_read(&sta->users), sta->aid,
 		     sta->flags,
 		     sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
 		     sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
@@ -1078,7 +1064,6 @@
 	struct sta_info *sta;
 	char name[20];
 	struct add_sta_proc_data *entry, *prev;
-	DECLARE_MAC_BUF(mac);
 
 	entry = ap->add_sta_proc_entries;
 	ap->add_sta_proc_entries = NULL;
@@ -1091,7 +1076,7 @@
 		spin_unlock_bh(&ap->sta_table_lock);
 
 		if (sta) {
-			sprintf(name, "%s", print_mac(mac, sta->addr));
+			sprintf(name, "%pM", sta->addr);
 			sta->proc = create_proc_read_entry(
 				name, 0, ap->proc,
 				prism2_sta_proc_read, sta);
@@ -1221,7 +1206,7 @@
 
 static void ap_crypt_init(struct ap_data *ap)
 {
-	ap->crypt = ieee80211_get_crypto_ops("WEP");
+	ap->crypt = lib80211_get_crypto_ops("WEP");
 
 	if (ap->crypt) {
 		if (ap->crypt->init) {
@@ -1239,7 +1224,7 @@
 
 	if (ap->crypt == NULL) {
 		printk(KERN_WARNING "AP could not initialize WEP: load module "
-		       "ieee80211_crypt_wep.ko\n");
+		       "lib80211_crypt_wep.ko\n");
 	}
 }
 
@@ -1308,7 +1293,7 @@
 	__le16 *pos;
 	u16 resp = WLAN_STATUS_SUCCESS, fc;
 	struct sta_info *sta = NULL;
-	struct ieee80211_crypt_data *crypt;
+	struct lib80211_crypt_data *crypt;
 	char *txt = "";
 
 	len = skb->len - IEEE80211_MGMT_HDR_LEN;
@@ -1318,9 +1303,7 @@
 
 	if (len < 6) {
 		PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload "
-		       "(len=%d) from " MAC_FMT "\n", dev->name, len,
-		       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-		       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+		       "(len=%d) from %pM\n", dev->name, len, hdr->addr2);
 		return;
 	}
 
@@ -1336,7 +1319,7 @@
 		int idx = 0;
 		if (skb->len >= hdrlen + 3)
 			idx = skb->data[hdrlen + 3] >> 6;
-		crypt = local->crypt[idx];
+		crypt = local->crypt_info.crypt[idx];
 	}
 
 	pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
@@ -1385,10 +1368,8 @@
 		if (time_after(jiffies, sta->u.ap.last_beacon +
 			       (10 * sta->listen_interval * HZ) / 1024)) {
 			PDEBUG(DEBUG_AP, "%s: no beacons received for a while,"
-			       " assuming AP " MAC_FMT " is now STA\n",
-			       dev->name,
-			       sta->addr[0], sta->addr[1], sta->addr[2],
-			       sta->addr[3], sta->addr[4], sta->addr[5]);
+			       " assuming AP %pM is now STA\n",
+			       dev->name, sta->addr);
 			sta->ap = 0;
 			sta->flags = 0;
 			sta->u.sta.challenge = NULL;
@@ -1503,11 +1484,9 @@
 	}
 
 	if (resp) {
-		PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth (alg=%d "
+		PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d "
 		       "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n",
-		       dev->name,
-		       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-		       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
+		       dev->name, hdr->addr2,
 		       auth_alg, auth_transaction, status_code, len,
 		       fc, resp, txt);
 	}
@@ -1533,10 +1512,8 @@
 
 	if (len < (reassoc ? 10 : 4)) {
 		PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload "
-		       "(len=%d, reassoc=%d) from " MAC_FMT "\n",
-		       dev->name, len, reassoc,
-		       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-		       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+		       "(len=%d, reassoc=%d) from %pM\n",
+		       dev->name, len, reassoc, hdr->addr2);
 		return;
 	}
 
@@ -1613,12 +1590,9 @@
 		}
 
 		if (left > 0) {
-			PDEBUG(DEBUG_AP, "%s: assoc from " MAC_FMT
+			PDEBUG(DEBUG_AP, "%s: assoc from %pM"
 			       " with extra data (%d bytes) [",
-			       dev->name,
-			       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-			       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
-			       left);
+			       dev->name, hdr->addr2, left);
 			while (left > 0) {
 				PDEBUG2(DEBUG_AP, "<%02x>", *u);
 				u++; left--;
@@ -1717,14 +1691,12 @@
 	}
 
 #if 0
-	PDEBUG(DEBUG_AP, "%s: " MAC_FMT" %sassoc (len=%d "
-	       "prev_ap=" MAC_FMT") => %d(%d) (%s)\n",
+	PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d "
+	       "prev_ap=%pM) => %d(%d) (%s)\n",
 	       dev->name,
-	       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-	       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
+	       hdr->addr2,
 	       reassoc ? "re" : "", len,
-	       prev_ap[0], prev_ap[1], prev_ap[2],
-	       prev_ap[3], prev_ap[4], prev_ap[5],
+	       prev_ap,
 	       resp, send_deauth, txt);
 #endif
 }
@@ -1741,7 +1713,6 @@
 	u16 reason_code;
 	__le16 *pos;
 	struct sta_info *sta = NULL;
-	DECLARE_MAC_BUF(mac);
 
 	len = skb->len - IEEE80211_MGMT_HDR_LEN;
 
@@ -1753,10 +1724,8 @@
 	pos = (__le16 *) body;
 	reason_code = le16_to_cpu(*pos);
 
-	PDEBUG(DEBUG_AP, "%s: deauthentication: " MAC_FMT " len=%d, "
-	       "reason_code=%d\n", dev->name,
-	       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-	       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
+	PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, "
+	       "reason_code=%d\n", dev->name, hdr->addr2,
 	       len, reason_code);
 
 	spin_lock_bh(&local->ap->sta_table_lock);
@@ -1768,11 +1737,9 @@
 	}
 	spin_unlock_bh(&local->ap->sta_table_lock);
 	if (sta == NULL) {
-		printk("%s: deauthentication from " MAC_FMT ", "
+		printk("%s: deauthentication from %pM, "
 	       "reason_code=%d, but STA not authenticated\n", dev->name,
-		       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-		       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
-		       reason_code);
+		       hdr->addr2, reason_code);
 	}
 }
 
@@ -1799,10 +1766,8 @@
 	pos = (__le16 *) body;
 	reason_code = le16_to_cpu(*pos);
 
-	PDEBUG(DEBUG_AP, "%s: disassociation: " MAC_FMT " len=%d, "
-	       "reason_code=%d\n", dev->name,
-	       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-	       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
+	PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, "
+	       "reason_code=%d\n", dev->name, hdr->addr2,
 	       len, reason_code);
 
 	spin_lock_bh(&local->ap->sta_table_lock);
@@ -1814,12 +1779,9 @@
 	}
 	spin_unlock_bh(&local->ap->sta_table_lock);
 	if (sta == NULL) {
-		printk("%s: disassociation from " MAC_FMT ", "
+		printk("%s: disassociation from %pM, "
 		       "reason_code=%d, but STA not authenticated\n",
-		       dev->name,
-		       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-		       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
-		       reason_code);
+		       dev->name, hdr->addr2, reason_code);
 	}
 }
 
@@ -1909,19 +1871,14 @@
 	u16 aid;
 	struct sk_buff *skb;
 
-	PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MAC_FMT
-	       ", TA=" MAC_FMT " PWRMGT=%d\n",
-	       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
-	       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
-	       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
-	       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
+	PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n",
+	       hdr->addr1, hdr->addr2,
 	       !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM));
 
 	if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
-		PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MAC_FMT
-		       " not own MAC\n",
-		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
-		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+		PDEBUG(DEBUG_AP,
+		       "handle_pspoll - addr1(BSSID)=%pM not own MAC\n",
+		       hdr->addr1);
 		return;
 	}
 
@@ -2007,11 +1964,10 @@
 
 	while (entry) {
 		PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection "
-		       "to AP " MAC_FMT "\n",
+		       "to AP %pM\n",
 		       local->dev->name,
 		       entry->type == WDS_ADD ? "adding" : "removing",
-		       entry->addr[0], entry->addr[1], entry->addr[2],
-		       entry->addr[3], entry->addr[4], entry->addr[5]);
+		       entry->addr);
 		if (entry->type == WDS_ADD)
 			prism2_wds_add(local, entry->addr, 0);
 		else if (entry->type == WDS_DEL)
@@ -2215,10 +2171,8 @@
 		}
 
 		if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
-			PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)="
-			       MAC_FMT " not own MAC\n",
-			       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
-			       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+			PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM"
+			       " not own MAC\n", hdr->addr1);
 			goto done;
 		}
 
@@ -2254,18 +2208,14 @@
 	}
 
 	if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
-		PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MAC_FMT
-		       " not own MAC\n",
-		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
-		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+		PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM"
+		       " not own MAC\n", hdr->addr1);
 		goto done;
 	}
 
 	if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) {
-		PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MAC_FMT
-		       " not own MAC\n",
-		       hdr->addr3[0], hdr->addr3[1], hdr->addr3[2],
-		       hdr->addr3[3], hdr->addr3[4], hdr->addr3[5]);
+		PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM"
+		       " not own MAC\n", hdr->addr3);
 		goto done;
 	}
 
@@ -2366,10 +2316,9 @@
 	memcpy(hdr->addr2, sta->addr, ETH_ALEN);
 	hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14));
 
-	PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for STA "
-	       MAC_FMT "\n", local->dev->name,
-	       sta->addr[0], sta->addr[1], sta->addr[2],
-	       sta->addr[3], sta->addr[4], sta->addr[5]);
+	PDEBUG(DEBUG_PS2,
+	       "%s: Scheduling buffered packet delivery for STA %pM\n",
+	       local->dev->name, sta->addr);
 
 	skb->dev = local->dev;
 
@@ -2723,12 +2672,8 @@
 			case 3: sta->tx_rate = 110; break;
 			default: sta->tx_rate = 0; break;
 			}
-			PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT
-			       " TX rate raised to %d\n",
-			       dev->name,
-			       sta->addr[0], sta->addr[1], sta->addr[2],
-			       sta->addr[3], sta->addr[4], sta->addr[5],
-			       sta->tx_rate);
+			PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n",
+			       dev->name, sta->addr, sta->tx_rate);
 		}
 		sta->tx_since_last_failure = 0;
 	}
@@ -2781,9 +2726,7 @@
 		 * print out any errors here. */
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "AP: drop packet to non-associated "
-			       "STA " MAC_FMT "\n",
-			       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
-			       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+			       "STA %pM\n", hdr->addr1);
 		}
 #endif
 		local->ap->tx_drop_nonassoc++;
@@ -2821,11 +2764,9 @@
 	}
 
 	if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) {
-		PDEBUG(DEBUG_PS, "%s: No more space in STA (" MAC_FMT
-		       ")'s PS mode buffer\n",
-		       local->dev->name,
-		       sta->addr[0], sta->addr[1], sta->addr[2],
-		       sta->addr[3], sta->addr[4], sta->addr[5]);
+		PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s"
+		       "PS mode buffer\n",
+		       local->dev->name, sta->addr);
 		/* Make sure that TIM is set for the station (it might not be
 		 * after AP wlan hw reset). */
 		/* FIX: should fix hw reset to restore bits based on STA
@@ -2897,12 +2838,9 @@
 	sta = ap_get_sta(local->ap, hdr->addr1);
 	if (!sta) {
 		spin_unlock(&local->ap->sta_table_lock);
-		PDEBUG(DEBUG_AP, "%s: Could not find STA " MAC_FMT
+		PDEBUG(DEBUG_AP, "%s: Could not find STA %pM"
 		       " for this TX error (@%lu)\n",
-		       local->dev->name,
-		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
-		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
-		       jiffies);
+		       local->dev->name, hdr->addr1, jiffies);
 		return;
 	}
 
@@ -2929,12 +2867,9 @@
 			case 3: sta->tx_rate = 110; break;
 			default: sta->tx_rate = 0; break;
 			}
-			PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT
-			       " TX rate lowered to %d\n",
-			       local->dev->name,
-			       sta->addr[0], sta->addr[1], sta->addr[2],
-			       sta->addr[3], sta->addr[4], sta->addr[5],
-			       sta->tx_rate);
+			PDEBUG(DEBUG_AP,
+			       "%s: STA %pM TX rate lowered to %d\n",
+			       local->dev->name, sta->addr, sta->tx_rate);
 		}
 		sta->tx_consecutive_exc = 0;
 	}
@@ -2945,17 +2880,16 @@
 static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
 				  int pwrmgt, int type, int stype)
 {
-	DECLARE_MAC_BUF(mac);
 	if (pwrmgt && !(sta->flags & WLAN_STA_PS)) {
 		sta->flags |= WLAN_STA_PS;
-		PDEBUG(DEBUG_PS2, "STA %s changed to use PS "
+		PDEBUG(DEBUG_PS2, "STA %pM changed to use PS "
 		       "mode (type=0x%02X, stype=0x%02X)\n",
-		       print_mac(mac, sta->addr), type >> 2, stype >> 4);
+		       sta->addr, type >> 2, stype >> 4);
 	} else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) {
 		sta->flags &= ~WLAN_STA_PS;
-		PDEBUG(DEBUG_PS2, "STA %s changed to not use "
+		PDEBUG(DEBUG_PS2, "STA %pM changed to not use "
 		       "PS mode (type=0x%02X, stype=0x%02X)\n",
-		       print_mac(mac, sta->addr), type >> 2, stype >> 4);
+		       sta->addr, type >> 2, stype >> 4);
 		if (type != IEEE80211_FTYPE_CTL ||
 		    stype != IEEE80211_STYPE_PSPOLL)
 			schedule_packet_send(local, sta);
@@ -3029,13 +2963,9 @@
 #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
 			} else {
 				printk(KERN_DEBUG "%s: dropped received packet"
-				       " from non-associated STA "
-				       MAC_FMT
+				       " from non-associated STA %pM"
 				       " (type=0x%02x, subtype=0x%02x)\n",
-				       dev->name,
-				       hdr->addr2[0], hdr->addr2[1],
-				       hdr->addr2[2], hdr->addr2[3],
-				       hdr->addr2[4], hdr->addr2[5],
+				       dev->name, hdr->addr2,
 				       type >> 2, stype >> 4);
 				hostap_rx(dev, skb, rx_stats);
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
@@ -3068,13 +2998,9 @@
 			 * after being unavailable for some time. Speed up
 			 * re-association by informing the station about it not
 			 * being associated. */
-			printk(KERN_DEBUG "%s: rejected received nullfunc "
-			       "frame without ToDS from not associated STA "
-			       MAC_FMT "\n",
-			       dev->name,
-			       hdr->addr2[0], hdr->addr2[1],
-			       hdr->addr2[2], hdr->addr2[3],
-			       hdr->addr2[4], hdr->addr2[5]);
+			printk(KERN_DEBUG "%s: rejected received nullfunc frame"
+			       " without ToDS from not associated STA %pM\n",
+			       dev->name, hdr->addr2);
 			hostap_rx(dev, skb, rx_stats);
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
 		}
@@ -3090,13 +3016,10 @@
 		 * broadcast frame from an IBSS network. Drop it silently.
 		 * If BSSID is own, report the dropping of this frame. */
 		if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
-			printk(KERN_DEBUG "%s: dropped received packet from "
-			       MAC_FMT " with no ToDS flag "
+			printk(KERN_DEBUG "%s: dropped received packet from %pM"
+			       " with no ToDS flag "
 			       "(type=0x%02x, subtype=0x%02x)\n", dev->name,
-			       hdr->addr2[0], hdr->addr2[1],
-			       hdr->addr2[2], hdr->addr2[3],
-			       hdr->addr2[4], hdr->addr2[5],
-			       type >> 2, stype >> 4);
+			       hdr->addr2, type >> 2, stype >> 4);
 			hostap_dump_rx_80211(dev->name, skb, rx_stats);
 		}
 		ret = AP_RX_DROP;
@@ -3142,7 +3065,7 @@
 /* Called only as a tasklet (software IRQ) */
 int hostap_handle_sta_crypto(local_info_t *local,
 			     struct ieee80211_hdr_4addr *hdr,
-			     struct ieee80211_crypt_data **crypt,
+			     struct lib80211_crypt_data **crypt,
 			     void **sta_ptr)
 {
 	struct sta_info *sta;
@@ -3290,7 +3213,7 @@
 
 
 void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
-			 struct ieee80211_crypt_data ***crypt)
+			 struct lib80211_crypt_data ***crypt)
 {
 	struct sta_info *sta;
 
diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h
index 2fa2452..d36e4b1 100644
--- a/drivers/net/wireless/hostap/hostap_ap.h
+++ b/drivers/net/wireless/hostap/hostap_ap.h
@@ -74,7 +74,7 @@
 	u32 tx_since_last_failure;
 	u32 tx_consecutive_exc;
 
-	struct ieee80211_crypt_data *crypt;
+	struct lib80211_crypt_data *crypt;
 
 	int ap; /* whether this station is an AP */
 
@@ -209,7 +209,7 @@
 
 	/* WEP operations for generating challenges to be used with shared key
 	 * authentication */
-	struct ieee80211_crypto_ops *crypt;
+	struct lib80211_crypto_ops *crypt;
 	void *crypt_priv;
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
 };
@@ -229,7 +229,7 @@
 struct hostap_tx_data {
 	struct sk_buff *skb;
 	int host_encrypt;
-	struct ieee80211_crypt_data *crypt;
+	struct lib80211_crypt_data *crypt;
 	void *sta_ptr;
 };
 ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx);
@@ -244,7 +244,7 @@
 			       struct hostap_80211_rx_status *rx_stats,
 			       int wds);
 int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
-			     struct ieee80211_crypt_data **crypt,
+			     struct lib80211_crypt_data **crypt,
 			     void **sta_ptr);
 int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr);
 int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr);
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index b470c74..90b64b0 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -6,19 +6,6 @@
 
 /* IEEE 802.11 defines */
 
-/* Information Element IDs */
-#define WLAN_EID_SSID 0
-#define WLAN_EID_SUPP_RATES 1
-#define WLAN_EID_FH_PARAMS 2
-#define WLAN_EID_DS_PARAMS 3
-#define WLAN_EID_CF_PARAMS 4
-#define WLAN_EID_TIM 5
-#define WLAN_EID_IBSS_PARAMS 6
-#define WLAN_EID_CHALLENGE 16
-#define WLAN_EID_RSN 48
-#define WLAN_EID_GENERIC 221
-
-
 /* HFA384X Configuration RIDs */
 #define HFA384X_RID_CNFPORTTYPE 0xFC00
 #define HFA384X_RID_CNFOWNMACADDR 0xFC01
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 3153fe9..0f27059 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -47,7 +47,7 @@
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
 #include <net/ieee80211.h>
-#include <net/ieee80211_crypt.h>
+#include <net/lib80211.h>
 #include <asm/irq.h>
 
 #include "hostap_80211.h"
@@ -2335,10 +2335,6 @@
 	int show_dump, res;
 	char *payload = NULL;
 	struct hfa384x_tx_frame txdesc;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
-	DECLARE_MAC_BUF(mac3);
-	DECLARE_MAC_BUF(mac4);
 
 	show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR;
 	local->stats.tx_errors++;
@@ -2404,9 +2400,9 @@
 	       WLAN_FC_GET_STYPE(fc) >> 4,
 	       fc & IEEE80211_FCTL_TODS ? " ToDS" : "",
 	       fc & IEEE80211_FCTL_FROMDS ? " FromDS" : "");
-	PDEBUG(DEBUG_EXTRA, "   A1=%s A2=%s A3=%s A4=%s\n",
-	       print_mac(mac, txdesc.addr1), print_mac(mac2, txdesc.addr2),
-	       print_mac(mac3, txdesc.addr3), print_mac(mac4, txdesc.addr4));
+	PDEBUG(DEBUG_EXTRA, "   A1=%pM A2=%pM A3=%pM A4=%pM\n",
+	       txdesc.addr1, txdesc.addr2,
+	       txdesc.addr3, txdesc.addr4);
 }
 
 
@@ -2792,45 +2788,6 @@
 }
 
 
-static void prism2_crypt_deinit_entries(local_info_t *local, int force)
-{
-	struct list_head *ptr, *n;
-	struct ieee80211_crypt_data *entry;
-
-	for (ptr = local->crypt_deinit_list.next, n = ptr->next;
-	     ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) {
-		entry = list_entry(ptr, struct ieee80211_crypt_data, list);
-
-		if (atomic_read(&entry->refcnt) != 0 && !force)
-			continue;
-
-		list_del(ptr);
-
-		if (entry->ops)
-			entry->ops->deinit(entry->priv);
-		kfree(entry);
-	}
-}
-
-
-static void prism2_crypt_deinit_handler(unsigned long data)
-{
-	local_info_t *local = (local_info_t *) data;
-	unsigned long flags;
-
-	spin_lock_irqsave(&local->lock, flags);
-	prism2_crypt_deinit_entries(local, 0);
-	if (!list_empty(&local->crypt_deinit_list)) {
-		printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
-		       "deletion list\n", local->dev->name);
-		local->crypt_deinit_timer.expires = jiffies + HZ;
-		add_timer(&local->crypt_deinit_timer);
-	}
-	spin_unlock_irqrestore(&local->lock, flags);
-
-}
-
-
 static void hostap_passive_scan(unsigned long data)
 {
 	local_info_t *local = (local_info_t *) data;
@@ -3254,10 +3211,8 @@
 
 	INIT_LIST_HEAD(&local->cmd_queue);
 	init_waitqueue_head(&local->hostscan_wq);
-	INIT_LIST_HEAD(&local->crypt_deinit_list);
-	init_timer(&local->crypt_deinit_timer);
-	local->crypt_deinit_timer.data = (unsigned long) local;
-	local->crypt_deinit_timer.function = prism2_crypt_deinit_handler;
+
+	lib80211_crypt_info_init(&local->crypt_info, dev->name, &local->lock);
 
 	init_timer(&local->passive_scan_timer);
 	local->passive_scan_timer.data = (unsigned long) local;
@@ -3358,9 +3313,7 @@
 
 	flush_scheduled_work();
 
-	if (timer_pending(&local->crypt_deinit_timer))
-		del_timer(&local->crypt_deinit_timer);
-	prism2_crypt_deinit_entries(local, 1);
+	lib80211_crypt_info_free(&local->crypt_info);
 
 	if (timer_pending(&local->passive_scan_timer))
 		del_timer(&local->passive_scan_timer);
@@ -3377,16 +3330,6 @@
 	if (local->dev_enabled)
 		prism2_callback(local, PRISM2_CALLBACK_DISABLE);
 
-	for (i = 0; i < WEP_KEYS; i++) {
-		struct ieee80211_crypt_data *crypt = local->crypt[i];
-		if (crypt) {
-			if (crypt->ops)
-				crypt->ops->deinit(crypt->priv);
-			kfree(crypt);
-			local->crypt[i] = NULL;
-		}
-	}
-
 	if (local->ap != NULL)
 		hostap_free_data(local->ap);
 
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c
index 7cd3fb7..99b4cf4 100644
--- a/drivers/net/wireless/hostap/hostap_info.c
+++ b/drivers/net/wireless/hostap/hostap_info.c
@@ -166,7 +166,6 @@
 	struct hfa384x_hostscan_result *selected, *entry;
 	int i;
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
 
 	if (local->last_join_time &&
 	    time_before(jiffies, local->last_join_time + 10 * HZ)) {
@@ -199,9 +198,8 @@
 	    local->preferred_ap[2] || local->preferred_ap[3] ||
 	    local->preferred_ap[4] || local->preferred_ap[5]) {
 		/* Try to find preferred AP */
-		PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID "
-		       "%s\n",
-		       dev->name, print_mac(mac, local->preferred_ap));
+		PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n",
+		       dev->name, local->preferred_ap);
 		for (i = 0; i < local->last_scan_results_count; i++) {
 			entry = &local->last_scan_results[i];
 			if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
@@ -218,9 +216,9 @@
 	req.channel = selected->chid;
 	spin_unlock_irqrestore(&local->lock, flags);
 
-	PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%s"
+	PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM"
 	       " channel=%d\n",
-	       dev->name, print_mac(mac, req.bssid), le16_to_cpu(req.channel));
+	       dev->name, req.bssid, le16_to_cpu(req.channel));
 	if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
 				 sizeof(req))) {
 		printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
@@ -413,7 +411,6 @@
 	int val = local->prev_link_status;
 	int connected;
 	union iwreq_data wrqu;
-	DECLARE_MAC_BUF(mac);
 
 	connected =
 		val == HFA384X_LINKSTATUS_CONNECTED ||
@@ -425,10 +422,9 @@
 		printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
 		       "LinkStatus event\n", local->dev->name);
 	} else {
-		PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID="
-		       "%s\n",
+		PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n",
 		       local->dev->name,
-		       print_mac(mac, (unsigned char *) local->bssid));
+		       (unsigned char *) local->bssid);
 		if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
 			hostap_add_sta(local->ap, local->bssid);
 	}
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index 3f8b1d7..c40fdf4 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -2,7 +2,7 @@
 
 #include <linux/types.h>
 #include <linux/ethtool.h>
-#include <net/ieee80211_crypt.h>
+#include <net/lib80211.h>
 
 #include "hostap_wlan.h"
 #include "hostap.h"
@@ -116,32 +116,6 @@
 }
 
 
-static void prism2_crypt_delayed_deinit(local_info_t *local,
-					struct ieee80211_crypt_data **crypt)
-{
-	struct ieee80211_crypt_data *tmp;
-	unsigned long flags;
-
-	tmp = *crypt;
-	*crypt = NULL;
-
-	if (tmp == NULL)
-		return;
-
-	/* must not run ops->deinit() while there may be pending encrypt or
-	 * decrypt operations. Use a list of delayed deinits to avoid needing
-	 * locking. */
-
-	spin_lock_irqsave(&local->lock, flags);
-	list_add(&tmp->list, &local->crypt_deinit_list);
-	if (!timer_pending(&local->crypt_deinit_timer)) {
-		local->crypt_deinit_timer.expires = jiffies + HZ;
-		add_timer(&local->crypt_deinit_timer);
-	}
-	spin_unlock_irqrestore(&local->lock, flags);
-}
-
-
 static int prism2_ioctl_siwencode(struct net_device *dev,
 				  struct iw_request_info *info,
 				  struct iw_point *erq, char *keybuf)
@@ -149,47 +123,47 @@
 	struct hostap_interface *iface;
 	local_info_t *local;
 	int i;
-	struct ieee80211_crypt_data **crypt;
+	struct lib80211_crypt_data **crypt;
 
 	iface = netdev_priv(dev);
 	local = iface->local;
 
 	i = erq->flags & IW_ENCODE_INDEX;
 	if (i < 1 || i > 4)
-		i = local->tx_keyidx;
+		i = local->crypt_info.tx_keyidx;
 	else
 		i--;
 	if (i < 0 || i >= WEP_KEYS)
 		return -EINVAL;
 
-	crypt = &local->crypt[i];
+	crypt = &local->crypt_info.crypt[i];
 
 	if (erq->flags & IW_ENCODE_DISABLED) {
 		if (*crypt)
-			prism2_crypt_delayed_deinit(local, crypt);
+			lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
 		goto done;
 	}
 
 	if (*crypt != NULL && (*crypt)->ops != NULL &&
 	    strcmp((*crypt)->ops->name, "WEP") != 0) {
 		/* changing to use WEP; deinit previously used algorithm */
-		prism2_crypt_delayed_deinit(local, crypt);
+		lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
 	}
 
 	if (*crypt == NULL) {
-		struct ieee80211_crypt_data *new_crypt;
+		struct lib80211_crypt_data *new_crypt;
 
 		/* take WEP into use */
-		new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
+		new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
 				GFP_KERNEL);
 		if (new_crypt == NULL)
 			return -ENOMEM;
-		new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+		new_crypt->ops = lib80211_get_crypto_ops("WEP");
 		if (!new_crypt->ops) {
-			request_module("ieee80211_crypt_wep");
-			new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+			request_module("lib80211_crypt_wep");
+			new_crypt->ops = lib80211_get_crypto_ops("WEP");
 		}
-		if (new_crypt->ops)
+		if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
 			new_crypt->priv = new_crypt->ops->init(i);
 		if (!new_crypt->ops || !new_crypt->priv) {
 			kfree(new_crypt);
@@ -210,16 +184,16 @@
 			memset(keybuf + erq->length, 0, len - erq->length);
 		(*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv);
 		for (j = 0; j < WEP_KEYS; j++) {
-			if (j != i && local->crypt[j]) {
+			if (j != i && local->crypt_info.crypt[j]) {
 				first = 0;
 				break;
 			}
 		}
 		if (first)
-			local->tx_keyidx = i;
+			local->crypt_info.tx_keyidx = i;
 	} else {
 		/* No key data - just set the default TX key index */
-		local->tx_keyidx = i;
+		local->crypt_info.tx_keyidx = i;
 	}
 
  done:
@@ -252,20 +226,20 @@
 	local_info_t *local;
 	int i, len;
 	u16 val;
-	struct ieee80211_crypt_data *crypt;
+	struct lib80211_crypt_data *crypt;
 
 	iface = netdev_priv(dev);
 	local = iface->local;
 
 	i = erq->flags & IW_ENCODE_INDEX;
 	if (i < 1 || i > 4)
-		i = local->tx_keyidx;
+		i = local->crypt_info.tx_keyidx;
 	else
 		i--;
 	if (i < 0 || i >= WEP_KEYS)
 		return -EINVAL;
 
-	crypt = local->crypt[i];
+	crypt = local->crypt_info.crypt[i];
 	erq->flags = i + 1;
 
 	if (crypt == NULL || crypt->ops == NULL) {
@@ -664,7 +638,6 @@
 	unsigned long flags;
 	int i;
 	struct hfa384x_hostscan_result *entry;
-	DECLARE_MAC_BUF(mac);
 
 	iface = netdev_priv(dev);
 	local = iface->local;
@@ -686,14 +659,13 @@
 
 	if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
 				 sizeof(req))) {
-		printk(KERN_DEBUG "%s: JoinRequest %s"
-		       " failed\n",
-		       dev->name, print_mac(mac, local->preferred_ap));
+		printk(KERN_DEBUG "%s: JoinRequest %pM failed\n",
+		       dev->name, local->preferred_ap);
 		return -1;
 	}
 
-	printk(KERN_DEBUG "%s: Trying to join BSSID %s\n",
-	       dev->name, print_mac(mac, local->preferred_ap));
+	printk(KERN_DEBUG "%s: Trying to join BSSID %pM\n",
+	       dev->name, local->preferred_ap);
 
 	return 0;
 }
@@ -3229,8 +3201,8 @@
 	local_info_t *local = iface->local;
 	struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
 	int i, ret = 0;
-	struct ieee80211_crypto_ops *ops;
-	struct ieee80211_crypt_data **crypt;
+	struct lib80211_crypto_ops *ops;
+	struct lib80211_crypt_data **crypt;
 	void *sta_ptr;
 	u8 *addr;
 	const char *alg, *module;
@@ -3239,7 +3211,7 @@
 	if (i > WEP_KEYS)
 		return -EINVAL;
 	if (i < 1 || i > WEP_KEYS)
-		i = local->tx_keyidx;
+		i = local->crypt_info.tx_keyidx;
 	else
 		i--;
 	if (i < 0 || i >= WEP_KEYS)
@@ -3249,7 +3221,7 @@
 	if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
 	    addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
 		sta_ptr = NULL;
-		crypt = &local->crypt[i];
+		crypt = &local->crypt_info.crypt[i];
 	} else {
 		if (i != 0)
 			return -EINVAL;
@@ -3262,7 +3234,7 @@
 				 * is emulated by using default key idx 0.
 				 */
 				i = 0;
-				crypt = &local->crypt[i];
+				crypt = &local->crypt_info.crypt[i];
 			} else
 				return -EINVAL;
 		}
@@ -3271,22 +3243,22 @@
 	if ((erq->flags & IW_ENCODE_DISABLED) ||
 	    ext->alg == IW_ENCODE_ALG_NONE) {
 		if (*crypt)
-			prism2_crypt_delayed_deinit(local, crypt);
+			lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
 		goto done;
 	}
 
 	switch (ext->alg) {
 	case IW_ENCODE_ALG_WEP:
 		alg = "WEP";
-		module = "ieee80211_crypt_wep";
+		module = "lib80211_crypt_wep";
 		break;
 	case IW_ENCODE_ALG_TKIP:
 		alg = "TKIP";
-		module = "ieee80211_crypt_tkip";
+		module = "lib80211_crypt_tkip";
 		break;
 	case IW_ENCODE_ALG_CCMP:
 		alg = "CCMP";
-		module = "ieee80211_crypt_ccmp";
+		module = "lib80211_crypt_ccmp";
 		break;
 	default:
 		printk(KERN_DEBUG "%s: unsupported algorithm %d\n",
@@ -3295,10 +3267,10 @@
 		goto done;
 	}
 
-	ops = ieee80211_get_crypto_ops(alg);
+	ops = lib80211_get_crypto_ops(alg);
 	if (ops == NULL) {
 		request_module(module);
-		ops = ieee80211_get_crypto_ops(alg);
+		ops = lib80211_get_crypto_ops(alg);
 	}
 	if (ops == NULL) {
 		printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
@@ -3317,18 +3289,19 @@
 	}
 
 	if (*crypt == NULL || (*crypt)->ops != ops) {
-		struct ieee80211_crypt_data *new_crypt;
+		struct lib80211_crypt_data *new_crypt;
 
-		prism2_crypt_delayed_deinit(local, crypt);
+		lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
 
-		new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
+		new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
 				GFP_KERNEL);
 		if (new_crypt == NULL) {
 			ret = -ENOMEM;
 			goto done;
 		}
 		new_crypt->ops = ops;
-		new_crypt->priv = new_crypt->ops->init(i);
+		if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
+			new_crypt->priv = new_crypt->ops->init(i);
 		if (new_crypt->priv == NULL) {
 			kfree(new_crypt);
 			ret = -EINVAL;
@@ -3356,20 +3329,20 @@
 
 	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
 		if (!sta_ptr)
-			local->tx_keyidx = i;
+			local->crypt_info.tx_keyidx = i;
 	}
 
 
 	if (sta_ptr == NULL && ext->key_len > 0) {
 		int first = 1, j;
 		for (j = 0; j < WEP_KEYS; j++) {
-			if (j != i && local->crypt[j]) {
+			if (j != i && local->crypt_info.crypt[j]) {
 				first = 0;
 				break;
 			}
 		}
 		if (first)
-			local->tx_keyidx = i;
+			local->crypt_info.tx_keyidx = i;
 	}
 
  done:
@@ -3401,7 +3374,7 @@
 {
 	struct hostap_interface *iface = netdev_priv(dev);
 	local_info_t *local = iface->local;
-	struct ieee80211_crypt_data **crypt;
+	struct lib80211_crypt_data **crypt;
 	void *sta_ptr;
 	int max_key_len, i;
 	struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
@@ -3413,7 +3386,7 @@
 
 	i = erq->flags & IW_ENCODE_INDEX;
 	if (i < 1 || i > WEP_KEYS)
-		i = local->tx_keyidx;
+		i = local->crypt_info.tx_keyidx;
 	else
 		i--;
 
@@ -3421,7 +3394,7 @@
 	if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
 	    addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
 		sta_ptr = NULL;
-		crypt = &local->crypt[i];
+		crypt = &local->crypt_info.crypt[i];
 	} else {
 		i = 0;
 		sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt);
@@ -3470,8 +3443,8 @@
 				       int param_len)
 {
 	int ret = 0;
-	struct ieee80211_crypto_ops *ops;
-	struct ieee80211_crypt_data **crypt;
+	struct lib80211_crypto_ops *ops;
+	struct lib80211_crypt_data **crypt;
 	void *sta_ptr;
 
 	param->u.crypt.err = 0;
@@ -3488,7 +3461,7 @@
 		if (param->u.crypt.idx >= WEP_KEYS)
 			return -EINVAL;
 		sta_ptr = NULL;
-		crypt = &local->crypt[param->u.crypt.idx];
+		crypt = &local->crypt_info.crypt[param->u.crypt.idx];
 	} else {
 		if (param->u.crypt.idx)
 			return -EINVAL;
@@ -3505,20 +3478,20 @@
 
 	if (strcmp(param->u.crypt.alg, "none") == 0) {
 		if (crypt)
-			prism2_crypt_delayed_deinit(local, crypt);
+			lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
 		goto done;
 	}
 
-	ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+	ops = lib80211_get_crypto_ops(param->u.crypt.alg);
 	if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
-		request_module("ieee80211_crypt_wep");
-		ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+		request_module("lib80211_crypt_wep");
+		ops = lib80211_get_crypto_ops(param->u.crypt.alg);
 	} else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) {
-		request_module("ieee80211_crypt_tkip");
-		ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+		request_module("lib80211_crypt_tkip");
+		ops = lib80211_get_crypto_ops(param->u.crypt.alg);
 	} else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) {
-		request_module("ieee80211_crypt_ccmp");
-		ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+		request_module("lib80211_crypt_ccmp");
+		ops = lib80211_get_crypto_ops(param->u.crypt.alg);
 	}
 	if (ops == NULL) {
 		printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
@@ -3533,11 +3506,11 @@
 	local->host_decrypt = local->host_encrypt = 1;
 
 	if (*crypt == NULL || (*crypt)->ops != ops) {
-		struct ieee80211_crypt_data *new_crypt;
+		struct lib80211_crypt_data *new_crypt;
 
-		prism2_crypt_delayed_deinit(local, crypt);
+		lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
 
-		new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
+		new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
 				GFP_KERNEL);
 		if (new_crypt == NULL) {
 			ret = -ENOMEM;
@@ -3570,7 +3543,7 @@
 
 	if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) {
 		if (!sta_ptr)
-			local->tx_keyidx = param->u.crypt.idx;
+			local->crypt_info.tx_keyidx = param->u.crypt.idx;
 		else if (param->u.crypt.idx) {
 			printk(KERN_DEBUG "%s: TX key idx setting failed\n",
 			       local->dev->name);
@@ -3606,7 +3579,7 @@
 				       struct prism2_hostapd_param *param,
 				       int param_len)
 {
-	struct ieee80211_crypt_data **crypt;
+	struct lib80211_crypt_data **crypt;
 	void *sta_ptr;
 	int max_key_len;
 
@@ -3622,8 +3595,8 @@
 	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
 		sta_ptr = NULL;
 		if (param->u.crypt.idx >= WEP_KEYS)
-			param->u.crypt.idx = local->tx_keyidx;
-		crypt = &local->crypt[param->u.crypt.idx];
+			param->u.crypt.idx = local->crypt_info.tx_keyidx;
+		crypt = &local->crypt_info.crypt[param->u.crypt.idx];
 	} else {
 		param->u.crypt.idx = 0;
 		sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0,
@@ -3701,10 +3674,8 @@
 					  struct prism2_hostapd_param *param,
 					  int param_len)
 {
-	DECLARE_MAC_BUF(mac);
-	printk(KERN_DEBUG "%ssta: associated as client with AP "
-	       "%s\n",
-	       local->dev->name, print_mac(mac, param->sta_addr));
+	printk(KERN_DEBUG "%ssta: associated as client with AP %pM\n",
+	       local->dev->name, param->sta_addr);
 	memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN);
 	return 0;
 }
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 756ab56..02a312c 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -27,7 +27,7 @@
 #include <net/net_namespace.h>
 #include <net/iw_handler.h>
 #include <net/ieee80211.h>
-#include <net/ieee80211_crypt.h>
+#include <net/lib80211.h>
 #include <asm/uaccess.h>
 
 #include "hostap_wlan.h"
@@ -343,10 +343,11 @@
 	char keybuf[WEP_KEY_LEN + 1];
 	enum { NONE, WEP, OTHER } encrypt_type;
 
-	idx = local->tx_keyidx;
-	if (local->crypt[idx] == NULL || local->crypt[idx]->ops == NULL)
+	idx = local->crypt_info.tx_keyidx;
+	if (local->crypt_info.crypt[idx] == NULL ||
+	    local->crypt_info.crypt[idx]->ops == NULL)
 		encrypt_type = NONE;
-	else if (strcmp(local->crypt[idx]->ops->name, "WEP") == 0)
+	else if (strcmp(local->crypt_info.crypt[idx]->ops->name, "WEP") == 0)
 		encrypt_type = WEP;
 	else
 		encrypt_type = OTHER;
@@ -394,17 +395,17 @@
 	/* 104-bit support seems to require that all the keys are set to the
 	 * same keylen */
 	keylen = 6; /* first 5 octets */
-	len = local->crypt[idx]->ops->get_key(keybuf, sizeof(keybuf),
-					      NULL, local->crypt[idx]->priv);
+	len = local->crypt_info.crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), NULL,
+							   local->crypt_info.crypt[idx]->priv);
 	if (idx >= 0 && idx < WEP_KEYS && len > 5)
 		keylen = WEP_KEY_LEN + 1; /* first 13 octets */
 
 	for (i = 0; i < WEP_KEYS; i++) {
 		memset(keybuf, 0, sizeof(keybuf));
-		if (local->crypt[i]) {
-			(void) local->crypt[i]->ops->get_key(
+		if (local->crypt_info.crypt[i]) {
+			(void) local->crypt_info.crypt[i]->ops->get_key(
 				keybuf, sizeof(keybuf),
-				NULL, local->crypt[i]->priv);
+				NULL, local->crypt_info.crypt[i]->priv);
 		}
 		if (local->func->set_rid(local->dev,
 					 HFA384X_RID_CNFDEFAULTKEY0 + i,
@@ -530,10 +531,6 @@
 void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
 {
 	u16 status, fc;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
-	DECLARE_MAC_BUF(mac3);
-	DECLARE_MAC_BUF(mac4);
 
 	status = __le16_to_cpu(rx->status);
 
@@ -552,12 +549,11 @@
 	       fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
 	       fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
 
-	printk(KERN_DEBUG "   A1=%s A2=%s A3=%s A4=%s\n",
-	       print_mac(mac, rx->addr1), print_mac(mac2, rx->addr2),
-	       print_mac(mac3, rx->addr3), print_mac(mac4, rx->addr4));
+	printk(KERN_DEBUG "   A1=%pM A2=%pM A3=%pM A4=%pM\n",
+	       rx->addr1, rx->addr2, rx->addr3, rx->addr4);
 
-	printk(KERN_DEBUG "   dst=%s src=%s len=%d\n",
-	       print_mac(mac, rx->dst_addr), print_mac(mac2, rx->src_addr),
+	printk(KERN_DEBUG "   dst=%pM src=%pM len=%d\n",
+	       rx->dst_addr, rx->src_addr,
 	       __be16_to_cpu(rx->len));
 }
 
@@ -565,10 +561,6 @@
 void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
 {
 	u16 fc;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
-	DECLARE_MAC_BUF(mac3);
-	DECLARE_MAC_BUF(mac4);
 
 	printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d "
 	       "tx_control=0x%04x; jiffies=%ld\n",
@@ -584,12 +576,11 @@
 	       fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
 	       fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
 
-	printk(KERN_DEBUG "   A1=%s A2=%s A3=%s A4=%s\n",
-	       print_mac(mac, tx->addr1), print_mac(mac2, tx->addr2),
-	       print_mac(mac3, tx->addr3), print_mac(mac4, tx->addr4));
+	printk(KERN_DEBUG "   A1=%pM A2=%pM A3=%pM A4=%pM\n",
+	       tx->addr1, tx->addr2, tx->addr3, tx->addr4);
 
-	printk(KERN_DEBUG "   dst=%s src=%s len=%d\n",
-	       print_mac(mac, tx->dst_addr), print_mac(mac2, tx->src_addr),
+	printk(KERN_DEBUG "   dst=%pM src=%pM len=%d\n",
+	       tx->dst_addr, tx->src_addr,
 	       __be16_to_cpu(tx->len));
 }
 
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index 3a874fc..8fdd41f 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -312,7 +312,7 @@
 		goto err_out_disable;
 	}
 
-	mem = ioremap(phymem, pci_resource_len(pdev, 0));
+	mem = pci_ioremap_bar(pdev, 0);
 	if (mem == NULL) {
 		printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ;
 		goto fail;
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
index b035360..005ff25 100644
--- a/drivers/net/wireless/hostap/hostap_proc.c
+++ b/drivers/net/wireless/hostap/hostap_proc.c
@@ -2,7 +2,7 @@
 
 #include <linux/types.h>
 #include <linux/proc_fs.h>
-#include <net/ieee80211_crypt.h>
+#include <net/lib80211.h>
 
 #include "hostap_wlan.h"
 #include "hostap.h"
@@ -36,9 +36,10 @@
 	p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled);
 	p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
 	for (i = 0; i < WEP_KEYS; i++) {
-		if (local->crypt[i] && local->crypt[i]->ops) {
-			p += sprintf(p, "crypt[%d]=%s\n",
-				     i, local->crypt[i]->ops->name);
+		if (local->crypt_info.crypt[i] &&
+		    local->crypt_info.crypt[i]->ops) {
+			p += sprintf(p, "crypt[%d]=%s\n", i,
+				     local->crypt_info.crypt[i]->ops->name);
 		}
 	}
 	p += sprintf(p, "pri_only=%d\n", local->pri_only);
@@ -106,7 +107,6 @@
 	local_info_t *local = (local_info_t *) data;
 	struct list_head *ptr;
 	struct hostap_interface *iface;
-	DECLARE_MAC_BUF(mac);
 
 	if (off > PROC_LIMIT) {
 		*eof = 1;
@@ -118,9 +118,9 @@
 		iface = list_entry(ptr, struct hostap_interface, list);
 		if (iface->type != HOSTAP_INTERFACE_WDS)
 			continue;
-		p += sprintf(p, "%s\t%s\n",
+		p += sprintf(p, "%s\t%pM\n",
 			     iface->dev->name,
-			     print_mac(mac, iface->u.wds.remote_addr));
+			     iface->u.wds.remote_addr);
 		if ((p - page) > PROC_LIMIT) {
 			printk(KERN_DEBUG "%s: wds proc did not fit\n",
 			       local->dev->name);
@@ -148,7 +148,6 @@
 	struct list_head *ptr;
 	struct hostap_bss_info *bss;
 	int i;
-	DECLARE_MAC_BUF(mac);
 
 	if (off > PROC_LIMIT) {
 		*eof = 1;
@@ -160,8 +159,8 @@
 	spin_lock_bh(&local->lock);
 	list_for_each(ptr, &local->bss_list) {
 		bss = list_entry(ptr, struct hostap_bss_info, list);
-		p += sprintf(p, "%s\t%lu\t%u\t0x%x\t",
-			     print_mac(mac, bss->bssid), bss->last_update,
+		p += sprintf(p, "%pM\t%lu\t%u\t0x%x\t",
+			     bss->bssid, bss->last_update,
 			     bss->count, bss->capab_info);
 		for (i = 0; i < bss->ssid_len; i++) {
 			p += sprintf(p, "%c",
@@ -208,12 +207,13 @@
 		return 0;
 	}
 
-	p += sprintf(p, "tx_keyidx=%d\n", local->tx_keyidx);
+	p += sprintf(p, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx);
 	for (i = 0; i < WEP_KEYS; i++) {
-		if (local->crypt[i] && local->crypt[i]->ops &&
-		    local->crypt[i]->ops->print_stats) {
-			p = local->crypt[i]->ops->print_stats(
-				p, local->crypt[i]->priv);
+		if (local->crypt_info.crypt[i] &&
+		    local->crypt_info.crypt[i]->ops &&
+		    local->crypt_info.crypt[i]->ops->print_stats) {
+			p = local->crypt_info.crypt[i]->ops->print_stats(
+				p, local->crypt_info.crypt[i]->priv);
 		}
 	}
 
@@ -314,7 +314,6 @@
 	int entry, i, len, total = 0;
 	struct hfa384x_hostscan_result *scanres;
 	u8 *pos;
-	DECLARE_MAC_BUF(mac);
 
 	p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates "
 		     "SSID\n");
@@ -332,14 +331,14 @@
 		if ((p - page) > (PAGE_SIZE - 200))
 			break;
 
-		p += sprintf(p, "%d %d %d %d 0x%02x %d %s %d ",
+		p += sprintf(p, "%d %d %d %d 0x%02x %d %pM %d ",
 			     le16_to_cpu(scanres->chid),
 			     (s16) le16_to_cpu(scanres->anl),
 			     (s16) le16_to_cpu(scanres->sl),
 			     le16_to_cpu(scanres->beacon_interval),
 			     le16_to_cpu(scanres->capability),
 			     le16_to_cpu(scanres->rate),
-			     print_mac(mac, scanres->bssid),
+			     scanres->bssid,
 			     le16_to_cpu(scanres->atim));
 
 		pos = scanres->sup_rates;
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index a68f97c..4d8d51a 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -6,6 +6,7 @@
 #include <linux/mutex.h>
 #include <net/iw_handler.h>
 #include <net/ieee80211_radiotap.h>
+#include <net/lib80211.h>
 
 #include "hostap_config.h"
 #include "hostap_common.h"
@@ -763,10 +764,7 @@
 
 #define WEP_KEYS 4
 #define WEP_KEY_LEN 13
-	struct ieee80211_crypt_data *crypt[WEP_KEYS];
-	int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
-	struct timer_list crypt_deinit_timer;
-	struct list_head crypt_deinit_list;
+	struct lib80211_crypt_info crypt_info;
 
 	int open_wep; /* allow unencrypted frames */
 	int host_encrypt;
@@ -822,7 +820,7 @@
 	int last_scan_results_count;
 	enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type;
 	struct work_struct info_queue;
-	long pending_info; /* bit field of pending info_queue items */
+	unsigned long pending_info; /* bit field of pending info_queue items */
 #define PRISM2_INFO_PENDING_LINKSTATUS 0
 #define PRISM2_INFO_PENDING_SCANRESULTS 1
 	int prev_link_status; /* previous received LinkStatus info */
diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig
new file mode 100644
index 0000000..3d5cc44
--- /dev/null
+++ b/drivers/net/wireless/ipw2x00/Kconfig
@@ -0,0 +1,191 @@
+#
+# Intel Centrino wireless drivers
+#
+
+config IPW2100
+	tristate "Intel PRO/Wireless 2100 Network Connection"
+	depends on PCI && WLAN_80211
+	select WIRELESS_EXT
+	select FW_LOADER
+	select LIB80211
+	select LIBIPW
+	---help---
+          A driver for the Intel PRO/Wireless 2100 Network 
+	  Connection 802.11b wireless network adapter.
+
+          See <file:Documentation/networking/README.ipw2100> for information on
+          the capabilities currently enabled in this driver and for tips
+          for debugging issues and problems.
+
+	  In order to use this driver, you will need a firmware image for it.
+          You can obtain the firmware from
+	  <http://ipw2100.sf.net/>.  Once you have the firmware image, you 
+	  will need to place it in /lib/firmware.
+
+          You will also very likely need the Wireless Tools in order to
+          configure your card:
+
+          <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+
+          It is recommended that you compile this driver as a module (M)
+          rather than built-in (Y). This driver requires firmware at device
+          initialization time, and when built-in this typically happens
+          before the filesystem is accessible (hence firmware will be
+          unavailable and initialization will fail). If you do choose to build
+          this driver into your kernel image, you can avoid this problem by
+          including the firmware and a firmware loader in an initramfs.
+ 
+config IPW2100_MONITOR
+        bool "Enable promiscuous mode"
+        depends on IPW2100
+        ---help---
+	  Enables promiscuous/monitor mode support for the ipw2100 driver.
+	  With this feature compiled into the driver, you can switch to 
+	  promiscuous mode via the Wireless Tool's Monitor mode.  While in this
+	  mode, no packets can be sent.
+
+config IPW2100_DEBUG
+	bool "Enable full debugging output in IPW2100 module."
+	depends on IPW2100
+	---help---
+	  This option will enable debug tracing output for the IPW2100.  
+
+	  This will result in the kernel module being ~60k larger.  You can 
+	  control which debug output is sent to the kernel log by setting the 
+	  value in 
+
+	  /sys/bus/pci/drivers/ipw2100/debug_level
+
+	  This entry will only exist if this option is enabled.
+
+	  If you are not trying to debug or develop the IPW2100 driver, you 
+	  most likely want to say N here.
+
+config IPW2200
+	tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
+	depends on PCI && WLAN_80211
+	select WIRELESS_EXT
+	select FW_LOADER
+	select LIB80211
+	select LIBIPW
+	---help---
+          A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
+	  Connection adapters. 
+
+          See <file:Documentation/networking/README.ipw2200> for 
+	  information on the capabilities currently enabled in this 
+	  driver and for tips for debugging issues and problems.
+
+	  In order to use this driver, you will need a firmware image for it.
+          You can obtain the firmware from
+	  <http://ipw2200.sf.net/>.  See the above referenced README.ipw2200 
+	  for information on where to install the firmware images.
+
+          You will also very likely need the Wireless Tools in order to
+          configure your card:
+
+          <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+
+          It is recommended that you compile this driver as a module (M)
+          rather than built-in (Y). This driver requires firmware at device
+          initialization time, and when built-in this typically happens
+          before the filesystem is accessible (hence firmware will be
+          unavailable and initialization will fail). If you do choose to build
+          this driver into your kernel image, you can avoid this problem by
+          including the firmware and a firmware loader in an initramfs.
+
+config IPW2200_MONITOR
+        bool "Enable promiscuous mode"
+        depends on IPW2200
+        ---help---
+	  Enables promiscuous/monitor mode support for the ipw2200 driver.
+	  With this feature compiled into the driver, you can switch to 
+	  promiscuous mode via the Wireless Tool's Monitor mode.  While in this
+	  mode, no packets can be sent.
+
+config IPW2200_RADIOTAP
+	bool "Enable radiotap format 802.11 raw packet support"
+	depends on IPW2200_MONITOR
+
+config IPW2200_PROMISCUOUS
+	bool "Enable creation of a RF radiotap promiscuous interface"
+	depends on IPW2200_MONITOR
+	select IPW2200_RADIOTAP
+	---help---
+          Enables the creation of a second interface prefixed 'rtap'. 
+          This second interface will provide every received in radiotap
+	  format.
+
+          This is useful for performing wireless network analysis while
+          maintaining an active association.
+
+          Example usage:
+
+            % modprobe ipw2200 rtap_iface=1
+            % ifconfig rtap0 up
+            % tethereal -i rtap0
+
+          If you do not specify 'rtap_iface=1' as a module parameter then 
+          the rtap interface will not be created and you will need to turn 
+          it on via sysfs:
+	
+            % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface
+
+config IPW2200_QOS
+        bool "Enable QoS support"
+        depends on IPW2200 && EXPERIMENTAL
+
+config IPW2200_DEBUG
+	bool "Enable full debugging output in IPW2200 module."
+	depends on IPW2200
+	---help---
+	  This option will enable low level debug tracing output for IPW2200.
+
+	  Note, normal debug code is already compiled in. This low level
+	  debug option enables debug on hot paths (e.g Tx, Rx, ISR) and
+	  will result in the kernel module being ~70 larger.  Most users
+	  will typically not need this high verbosity debug information.
+
+	  If you are not sure, say N here.
+
+config LIBIPW
+	tristate
+	select WIRELESS_EXT
+	select CRYPTO
+	select CRYPTO_ARC4
+	select CRYPTO_ECB
+	select CRYPTO_AES
+	select CRYPTO_MICHAEL_MIC
+	select CRYPTO_ECB
+	select CRC32
+	select LIB80211
+	select LIB80211_CRYPT_WEP
+	select LIB80211_CRYPT_TKIP
+	select LIB80211_CRYPT_CCMP
+	---help---
+	This option enables the hardware independent IEEE 802.11
+	networking stack.  This component is deprecated in favor of the
+	mac80211 component.
+
+config LIBIPW_DEBUG
+	bool "Full debugging output for the LIBIPW component"
+	depends on LIBIPW
+	---help---
+	  This option will enable debug tracing output for the
+	  libipw component.
+
+	  This will result in the kernel module being ~70k larger.  You
+	  can control which debug output is sent to the kernel log by
+	  setting the value in
+
+	  /proc/net/ieee80211/debug_level
+
+	  For example:
+
+	  % echo 0x00000FFO > /proc/net/ieee80211/debug_level
+
+	  For a list of values you can assign to debug_level, you
+	  can look at the bit mask values in <net/ieee80211.h>
+
+	  If you are not trying to debug or develop the libipw
+	  component, you most likely want to say N here.
diff --git a/drivers/net/wireless/ipw2x00/Makefile b/drivers/net/wireless/ipw2x00/Makefile
new file mode 100644
index 0000000..aecd2cf
--- /dev/null
+++ b/drivers/net/wireless/ipw2x00/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the Intel Centrino wireless drivers
+#
+
+obj-$(CONFIG_IPW2100) += ipw2100.o
+obj-$(CONFIG_IPW2200) += ipw2200.o
+
+obj-$(CONFIG_LIBIPW) += libipw.o
+libipw-objs := \
+	libipw_module.o \
+	libipw_tx.o \
+	libipw_rx.o \
+	libipw_wx.o \
+	libipw_geo.o
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
similarity index 99%
rename from drivers/net/wireless/ipw2100.c
rename to drivers/net/wireless/ipw2x00/ipw2100.c
index bca7481..1667065 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -163,6 +163,8 @@
 #include <linux/ctype.h>
 #include <linux/pm_qos_params.h>
 
+#include <net/lib80211.h>
+
 #include "ipw2100.h"
 
 #define IPW2100_VERSION "git-1.2.2"
@@ -185,7 +187,7 @@
 static int debug = 0;
 static int mode = 0;
 static int channel = 0;
-static int associate = 1;
+static int associate = 0;
 static int disable = 0;
 #ifdef CONFIG_PM
 static struct ipw2100_fw ipw2100_firmware;
@@ -201,7 +203,7 @@
 MODULE_PARM_DESC(debug, "debug level");
 MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
 MODULE_PARM_DESC(channel, "channel");
-MODULE_PARM_DESC(associate, "auto associate when scanning (default on)");
+MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
 MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
 
 static u32 ipw2100_debug_level = IPW_DL_NONE;
@@ -1914,7 +1916,7 @@
 	u32 chan;
 	char *txratename;
 	u8 bssid[ETH_ALEN];
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 
 	/*
 	 * TBD: BSSID is usually 00:00:00:00:00:00 here and not
@@ -1975,10 +1977,9 @@
 		break;
 	}
 
-	IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID="
-		       "%s)\n",
-		       priv->net_dev->name, escape_essid(essid, essid_len),
-		       txratename, chan, print_mac(mac, bssid));
+	IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n",
+		       priv->net_dev->name, print_ssid(ssid, essid, essid_len),
+		       txratename, chan, bssid);
 
 	/* now we copy read ssid into dev */
 	if (!(priv->config & CFG_STATIC_ESSID)) {
@@ -2004,8 +2005,9 @@
 		.host_command_length = ssid_len
 	};
 	int err;
+	DECLARE_SSID_BUF(ssid);
 
-	IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len));
+	IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len));
 
 	if (ssid_len)
 		memcpy(cmd.host_command_parameters, essid, ssid_len);
@@ -2046,12 +2048,12 @@
 
 static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
 {
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 
 	IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
-		  "disassociated: '%s' %s \n",
-		  escape_essid(priv->essid, priv->essid_len),
-		  print_mac(mac, priv->bssid));
+		  "disassociated: '%s' %pM \n",
+		  print_ssid(ssid, priv->essid, priv->essid_len),
+		  priv->bssid);
 
 	priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
 
@@ -4008,7 +4010,7 @@
 	else
 		len += sprintf(buf + len, "not connected\n");
 
-	DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], "p");
+	DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p");
 	DUMP_VAR(status, "08lx");
 	DUMP_VAR(config, "08lx");
 	DUMP_VAR(capability, "08lx");
@@ -4058,7 +4060,6 @@
 	char *out = buf;
 	int length;
 	int ret;
-	DECLARE_MAC_BUF(mac);
 
 	if (priv->status & STATUS_RF_KILL_MASK)
 		return 0;
@@ -4086,7 +4087,7 @@
 			       __LINE__);
 
 	out += sprintf(out, "ESSID: %s\n", essid);
-	out += sprintf(out, "BSSID:   %s\n", print_mac(mac, bssid));
+	out += sprintf(out, "BSSID:   %pM\n", bssid);
 	out += sprintf(out, "Channel: %d\n", chan);
 
 	return out - buf;
@@ -4662,7 +4663,6 @@
 {
 	u32 length = ETH_ALEN;
 	u8 addr[ETH_ALEN];
-	DECLARE_MAC_BUF(mac);
 
 	int err;
 
@@ -4673,8 +4673,7 @@
 	}
 
 	memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
-	IPW_DEBUG_INFO("card MAC is %s\n",
-		       print_mac(mac, priv->net_dev->dev_addr));
+	IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr);
 
 	return 0;
 }
@@ -5053,10 +5052,8 @@
 	int err;
 
 #ifdef CONFIG_IPW2100_DEBUG
-	DECLARE_MAC_BUF(mac);
 	if (bssid != NULL)
-		IPW_DEBUG_HC("MANDATORY_BSSID: %s\n",
-			     print_mac(mac, bssid));
+		IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid);
 	else
 		IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
 #endif
@@ -5271,21 +5268,21 @@
 	return 0;
 }
 
-void ipw2100_queues_initialize(struct ipw2100_priv *priv)
+static void ipw2100_queues_initialize(struct ipw2100_priv *priv)
 {
 	ipw2100_tx_initialize(priv);
 	ipw2100_rx_initialize(priv);
 	ipw2100_msg_initialize(priv);
 }
 
-void ipw2100_queues_free(struct ipw2100_priv *priv)
+static void ipw2100_queues_free(struct ipw2100_priv *priv)
 {
 	ipw2100_tx_free(priv);
 	ipw2100_rx_free(priv);
 	ipw2100_msg_free(priv);
 }
 
-int ipw2100_queues_allocate(struct ipw2100_priv *priv)
+static int ipw2100_queues_allocate(struct ipw2100_priv *priv)
 {
 	if (ipw2100_tx_allocate(priv) ||
 	    ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
@@ -5517,7 +5514,7 @@
 			}
 		}
 
-		ipw2100_set_key_index(priv, priv->ieee->tx_keyidx, 1);
+		ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1);
 	}
 
 	/* Always enable privacy so the Host can filter WEP packets if
@@ -6905,7 +6902,6 @@
 	static const unsigned char off[] = {
 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 	};
-	DECLARE_MAC_BUF(mac);
 
 	// sanity checks
 	if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
@@ -6931,8 +6927,7 @@
 
 	err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
 
-	IPW_DEBUG_WX("SET BSSID -> %s\n",
-		     print_mac(mac, wrqu->ap_addr.sa_data));
+	IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data);
 
       done:
 	mutex_unlock(&priv->action_mutex);
@@ -6948,7 +6943,6 @@
 	 */
 
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
-	DECLARE_MAC_BUF(mac);
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured BSSID then return that; otherwise return ANY */
@@ -6958,8 +6952,7 @@
 	} else
 		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
 
-	IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
-		     print_mac(mac, wrqu->ap_addr.sa_data));
+	IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data);
 	return 0;
 }
 
@@ -6971,6 +6964,7 @@
 	char *essid = "";	/* ANY */
 	int length = 0;
 	int err = 0;
+	DECLARE_SSID_BUF(ssid);
 
 	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
@@ -7000,8 +6994,8 @@
 		goto done;
 	}
 
-	IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length),
-		     length);
+	IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
+		     print_ssid(ssid, essid, length), length);
 
 	priv->essid_len = length;
 	memcpy(priv->essid, essid, priv->essid_len);
@@ -7022,12 +7016,13 @@
 	 */
 
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	DECLARE_SSID_BUF(ssid);
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured ESSID then return that; otherwise return ANY */
 	if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
 		IPW_DEBUG_WX("Getting essid: '%s'\n",
-			     escape_essid(priv->essid, priv->essid_len));
+			     print_ssid(ssid, priv->essid, priv->essid_len));
 		memcpy(extra, priv->essid, priv->essid_len);
 		wrqu->essid.length = priv->essid_len;
 		wrqu->essid.flags = 1;	/* active */
@@ -7625,7 +7620,7 @@
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	struct ieee80211_device *ieee = priv->ieee;
 	struct iw_param *param = &wrqu->param;
-	struct ieee80211_crypt_data *crypt;
+	struct lib80211_crypt_data *crypt;
 	unsigned long flags;
 	int ret = 0;
 
@@ -7640,7 +7635,7 @@
 		break;
 
 	case IW_AUTH_TKIP_COUNTERMEASURES:
-		crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+		crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
 		if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
 			break;
 
@@ -7717,7 +7712,7 @@
 {
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	struct ieee80211_device *ieee = priv->ieee;
-	struct ieee80211_crypt_data *crypt;
+	struct lib80211_crypt_data *crypt;
 	struct iw_param *param = &wrqu->param;
 	int ret = 0;
 
@@ -7733,7 +7728,7 @@
 		break;
 
 	case IW_AUTH_TKIP_COUNTERMEASURES:
-		crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+		crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
 		if (!crypt || !crypt->ops->get_flags) {
 			IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
 					  "crypt not set!\n");
diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h
similarity index 100%
rename from drivers/net/wireless/ipw2100.h
rename to drivers/net/wireless/ipw2x00/ipw2100.h
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
similarity index 96%
rename from drivers/net/wireless/ipw2200.c
rename to drivers/net/wireless/ipw2x00/ipw2200.c
index 7a9f901..625f2cf 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -87,7 +87,7 @@
 static int mode = 0;
 
 static u32 ipw_debug_level;
-static int associate = 1;
+static int associate;
 static int auto_create = 1;
 static int led = 0;
 static int disable = 0;
@@ -2265,8 +2265,8 @@
 		return -1;
 	}
 
-	IPW_DEBUG_INFO("%s: Setting MAC to %s\n",
-		       priv->net_dev->name, print_mac(mac, mac));
+	IPW_DEBUG_INFO("%s: Setting MAC to %pM\n",
+		       priv->net_dev->name, mac);
 
 	return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac);
 }
@@ -3812,7 +3812,6 @@
 {
 	struct ipw_station_entry entry;
 	int i;
-	DECLARE_MAC_BUF(mac);
 
 	for (i = 0; i < priv->num_stations; i++) {
 		if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) {
@@ -3829,7 +3828,7 @@
 	if (i == MAX_STATIONS)
 		return IPW_INVALID_STATION;
 
-	IPW_DEBUG_SCAN("Adding AdHoc station: %s\n", print_mac(mac, bssid));
+	IPW_DEBUG_SCAN("Adding AdHoc station: %pM\n", bssid);
 
 	entry.reserved = 0;
 	entry.support_mode = 0;
@@ -3856,7 +3855,6 @@
 static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
 {
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	if (priv->status & STATUS_ASSOCIATING) {
 		IPW_DEBUG_ASSOC("Disassociating while associating.\n");
@@ -3869,9 +3867,9 @@
 		return;
 	}
 
-	IPW_DEBUG_ASSOC("Disassocation attempt from %s "
+	IPW_DEBUG_ASSOC("Disassocation attempt from %pM "
 			"on channel %d.\n",
-			print_mac(mac, priv->assoc_request.bssid),
+			priv->assoc_request.bssid,
 			priv->assoc_request.channel);
 
 	priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
@@ -4347,7 +4345,8 @@
 		return;
 	}
 
-	if (priv->status & STATUS_SCANNING) {
+	if (priv->status & STATUS_SCANNING &&
+	    missed_count > IPW_MB_SCAN_CANCEL_THRESHOLD) {
 		/* Stop scan to keep fw from getting
 		 * stuck (only if we aren't roaming --
 		 * otherwise we'll never scan more than 2 or 3
@@ -4398,7 +4397,7 @@
 static void ipw_rx_notification(struct ipw_priv *priv,
 				       struct ipw_rx_notification *notif)
 {
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 	u16 size = le16_to_cpu(notif->size);
 	notif->size = le16_to_cpu(notif->size);
 
@@ -4412,11 +4411,10 @@
 			case CMAS_ASSOCIATED:{
 					IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 						  IPW_DL_ASSOC,
-						  "associated: '%s' %s"
-						  " \n",
-						  escape_essid(priv->essid,
-							       priv->essid_len),
-						  print_mac(mac, priv->bssid));
+						  "associated: '%s' %pM \n",
+						  print_ssid(ssid, priv->essid,
+							     priv->essid_len),
+						  priv->bssid);
 
 					switch (priv->ieee->iw_mode) {
 					case IW_MODE_INFRA:
@@ -4450,7 +4448,7 @@
 
 #ifdef CONFIG_IPW2200_QOS
 #define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
-			 le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_ctl))
+			 le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_control))
 					if ((priv->status & STATUS_AUTH) &&
 					    (IPW_GET_PACKET_STYPE(&notif->u.raw)
 					     == IEEE80211_STYPE_ASSOC_RESP)) {
@@ -4493,13 +4491,14 @@
 							  IPW_DL_STATE |
 							  IPW_DL_ASSOC,
 							  "deauthenticated: '%s' "
-							  "%s"
+							  "%pM"
 							  ": (0x%04X) - %s \n",
-							  escape_essid(priv->
-								       essid,
-								       priv->
-								       essid_len),
-							  print_mac(mac, priv->bssid),
+							  print_ssid(ssid,
+								     priv->
+								     essid,
+								     priv->
+								     essid_len),
+							  priv->bssid,
 							  le16_to_cpu(auth->status),
 							  ipw_get_status_code
 							  (le16_to_cpu
@@ -4516,11 +4515,10 @@
 
 					IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 						  IPW_DL_ASSOC,
-						  "authenticated: '%s' %s"
-						  "\n",
-						  escape_essid(priv->essid,
-							       priv->essid_len),
-						  print_mac(mac, priv->bssid));
+						  "authenticated: '%s' %pM\n",
+						  print_ssid(ssid, priv->essid,
+							     priv->essid_len),
+						  priv->bssid);
 					break;
 				}
 
@@ -4545,11 +4543,10 @@
 
 					IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 						  IPW_DL_ASSOC,
-						  "disassociated: '%s' %s"
-						  " \n",
-						  escape_essid(priv->essid,
-							       priv->essid_len),
-						  print_mac(mac, priv->bssid));
+						  "disassociated: '%s' %pM \n",
+						  print_ssid(ssid, priv->essid,
+							     priv->essid_len),
+						  priv->bssid);
 
 					priv->status &=
 					    ~(STATUS_DISASSOCIATING |
@@ -4584,10 +4581,10 @@
 			switch (auth->state) {
 			case CMAS_AUTHENTICATED:
 				IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
-					  "authenticated: '%s' %s \n",
-					  escape_essid(priv->essid,
-						       priv->essid_len),
-					  print_mac(mac, priv->bssid));
+					  "authenticated: '%s' %pM \n",
+					  print_ssid(ssid, priv->essid,
+						     priv->essid_len),
+					  priv->bssid);
 				priv->status |= STATUS_AUTH;
 				break;
 
@@ -4603,10 +4600,10 @@
 				}
 				IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 					  IPW_DL_ASSOC,
-					  "deauthenticated: '%s' %s\n",
-					  escape_essid(priv->essid,
-						       priv->essid_len),
-					  print_mac(mac, priv->bssid));
+					  "deauthenticated: '%s' %pM\n",
+					  print_ssid(ssid, priv->essid,
+						     priv->essid_len),
+					  priv->bssid);
 
 				priv->status &= ~(STATUS_ASSOCIATING |
 						  STATUS_AUTH |
@@ -5430,27 +5427,17 @@
 				  int roaming)
 {
 	struct ipw_supported_rates rates;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
+	DECLARE_SSID_BUF(ssid);
 
 	/* Verify that this network's capability is compatible with the
 	 * current mode (AdHoc or Infrastructure) */
 	if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
 	     !(network->capability & WLAN_CAPABILITY_IBSS))) {
-		IPW_DEBUG_MERGE("Network '%s (%s)' excluded due to "
+		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to "
 				"capability mismatch.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid));
-		return 0;
-	}
-
-	/* If we do not have an ESSID for this AP, we can not associate with
-	 * it */
-	if (network->flags & NETWORK_EMPTY_ESSID) {
-		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
-				"because of hidden ESSID.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid));
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid);
 		return 0;
 	}
 
@@ -5460,11 +5447,11 @@
 		if ((network->ssid_len != match->network->ssid_len) ||
 		    memcmp(network->ssid, match->network->ssid,
 			   network->ssid_len)) {
-			IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+			IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
 					"because of non-network ESSID.\n",
-					escape_essid(network->ssid,
-						     network->ssid_len),
-					print_mac(mac, network->bssid));
+					print_ssid(ssid, network->ssid,
+						   network->ssid_len),
+					network->bssid);
 			return 0;
 		}
 	} else {
@@ -5477,13 +5464,14 @@
 			char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
 
 			strncpy(escaped,
-				escape_essid(network->ssid, network->ssid_len),
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
 				sizeof(escaped));
-			IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+			IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
 					"because of ESSID mismatch: '%s'.\n",
-					escaped, print_mac(mac, network->bssid),
-					escape_essid(priv->essid,
-						     priv->essid_len));
+					escaped, network->bssid,
+					print_ssid(ssid, priv->essid,
+						   priv->essid_len));
 			return 0;
 		}
 	}
@@ -5494,24 +5482,25 @@
 	if (network->time_stamp[0] < match->network->time_stamp[0]) {
 		IPW_DEBUG_MERGE("Network '%s excluded because newer than "
 				"current network.\n",
-				escape_essid(match->network->ssid,
-					     match->network->ssid_len));
+				print_ssid(ssid, match->network->ssid,
+					   match->network->ssid_len));
 		return 0;
 	} else if (network->time_stamp[1] < match->network->time_stamp[1]) {
 		IPW_DEBUG_MERGE("Network '%s excluded because newer than "
 				"current network.\n",
-				escape_essid(match->network->ssid,
-					     match->network->ssid_len));
+				print_ssid(ssid, match->network->ssid,
+					   match->network->ssid_len));
 		return 0;
 	}
 
 	/* Now go through and see if the requested network is valid... */
 	if (priv->ieee->scan_age != 0 &&
 	    time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
-		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
 				"because of age: %ums.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid),
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid,
 				jiffies_to_msecs(jiffies -
 						 network->last_scanned));
 		return 0;
@@ -5519,10 +5508,11 @@
 
 	if ((priv->config & CFG_STATIC_CHANNEL) &&
 	    (network->channel != priv->channel)) {
-		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
 				"because of channel mismatch: %d != %d.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid),
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid,
 				network->channel, priv->channel);
 		return 0;
 	}
@@ -5530,10 +5520,11 @@
 	/* Verify privacy compatability */
 	if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
 	    ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
-		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
 				"because of privacy mismatch: %s != %s.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid),
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid,
 				priv->
 				capability & CAP_PRIVACY_ON ? "on" : "off",
 				network->
@@ -5543,41 +5534,44 @@
 	}
 
 	if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
-		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
-				"because of the same BSSID match: %s"
-				".\n", escape_essid(network->ssid,
-						    network->ssid_len),
-				print_mac(mac, network->bssid),
-				print_mac(mac2, priv->bssid));
+		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
+				"because of the same BSSID match: %pM"
+				".\n", print_ssid(ssid, network->ssid,
+						  network->ssid_len),
+				network->bssid,
+				priv->bssid);
 		return 0;
 	}
 
 	/* Filter out any incompatible freq / mode combinations */
 	if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
-		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
 				"because of invalid frequency/mode "
 				"combination.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid));
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid);
 		return 0;
 	}
 
 	/* Ensure that the rates supported by the driver are compatible with
 	 * this AP, including verification of basic rates (mandatory) */
 	if (!ipw_compatible_rates(priv, network, &rates)) {
-		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
 				"because configured rate mask excludes "
 				"AP mandatory rate.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid));
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid);
 		return 0;
 	}
 
 	if (rates.num_rates == 0) {
-		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
 				"because of no compatible rates.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid));
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid);
 		return 0;
 	}
 
@@ -5588,15 +5582,16 @@
 	/* Set up 'new' AP to this network */
 	ipw_copy_rates(&match->rates, &rates);
 	match->network = network;
-	IPW_DEBUG_MERGE("Network '%s (%s)' is a viable match.\n",
-			escape_essid(network->ssid, network->ssid_len),
-			print_mac(mac, network->bssid));
+	IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n",
+			print_ssid(ssid, network->ssid, network->ssid_len),
+			network->bssid);
 
 	return 1;
 }
 
 static void ipw_merge_adhoc_network(struct work_struct *work)
 {
+	DECLARE_SSID_BUF(ssid);
 	struct ipw_priv *priv =
 		container_of(work, struct ipw_priv, merge_networks);
 	struct ieee80211_network *network = NULL;
@@ -5627,8 +5622,8 @@
 		mutex_lock(&priv->mutex);
 		if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) {
 			IPW_DEBUG_MERGE("remove network %s\n",
-					escape_essid(priv->essid,
-						     priv->essid_len));
+					print_ssid(ssid, priv->essid,
+						   priv->essid_len));
 			ipw_remove_current_network(priv);
 		}
 
@@ -5644,7 +5639,7 @@
 			    struct ieee80211_network *network, int roaming)
 {
 	struct ipw_supported_rates rates;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 
 	/* Verify that this network's capability is compatible with the
 	 * current mode (AdHoc or Infrastructure) */
@@ -5652,20 +5647,11 @@
 	     !(network->capability & WLAN_CAPABILITY_ESS)) ||
 	    (priv->ieee->iw_mode == IW_MODE_ADHOC &&
 	     !(network->capability & WLAN_CAPABILITY_IBSS))) {
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded due to "
+		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to "
 				"capability mismatch.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid));
-		return 0;
-	}
-
-	/* If we do not have an ESSID for this AP, we can not associate with
-	 * it */
-	if (network->flags & NETWORK_EMPTY_ESSID) {
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
-				"because of hidden ESSID.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid));
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid);
 		return 0;
 	}
 
@@ -5675,11 +5661,11 @@
 		if ((network->ssid_len != match->network->ssid_len) ||
 		    memcmp(network->ssid, match->network->ssid,
 			   network->ssid_len)) {
-			IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+			IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
 					"because of non-network ESSID.\n",
-					escape_essid(network->ssid,
-						     network->ssid_len),
-					print_mac(mac, network->bssid));
+					print_ssid(ssid, network->ssid,
+						   network->ssid_len),
+					network->bssid);
 			return 0;
 		}
 	} else {
@@ -5691,13 +5677,14 @@
 			    min(network->ssid_len, priv->essid_len)))) {
 			char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
 			strncpy(escaped,
-				escape_essid(network->ssid, network->ssid_len),
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
 				sizeof(escaped));
-			IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+			IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
 					"because of ESSID mismatch: '%s'.\n",
-					escaped, print_mac(mac, network->bssid),
-					escape_essid(priv->essid,
-						     priv->essid_len));
+					escaped, network->bssid,
+					print_ssid(ssid, priv->essid,
+						   priv->essid_len));
 			return 0;
 		}
 	}
@@ -5707,14 +5694,14 @@
 	if (match->network && match->network->stats.rssi > network->stats.rssi) {
 		char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
 		strncpy(escaped,
-			escape_essid(network->ssid, network->ssid_len),
+			print_ssid(ssid, network->ssid, network->ssid_len),
 			sizeof(escaped));
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded because "
-				"'%s (%s)' has a stronger signal.\n",
-				escaped, print_mac(mac, network->bssid),
-				escape_essid(match->network->ssid,
-					     match->network->ssid_len),
-				print_mac(mac, match->network->bssid));
+		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because "
+				"'%s (%pM)' has a stronger signal.\n",
+				escaped, network->bssid,
+				print_ssid(ssid, match->network->ssid,
+					   match->network->ssid_len),
+				match->network->bssid);
 		return 0;
 	}
 
@@ -5722,11 +5709,12 @@
 	 * last 3 seconds, do not try and associate again... */
 	if (network->last_associate &&
 	    time_after(network->last_associate + (HZ * 3UL), jiffies)) {
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
 				"because of storming (%ums since last "
 				"assoc attempt).\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid),
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid,
 				jiffies_to_msecs(jiffies -
 						 network->last_associate));
 		return 0;
@@ -5735,10 +5723,11 @@
 	/* Now go through and see if the requested network is valid... */
 	if (priv->ieee->scan_age != 0 &&
 	    time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
 				"because of age: %ums.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid),
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid,
 				jiffies_to_msecs(jiffies -
 						 network->last_scanned));
 		return 0;
@@ -5746,10 +5735,11 @@
 
 	if ((priv->config & CFG_STATIC_CHANNEL) &&
 	    (network->channel != priv->channel)) {
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
 				"because of channel mismatch: %d != %d.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid),
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid,
 				network->channel, priv->channel);
 		return 0;
 	}
@@ -5757,10 +5747,11 @@
 	/* Verify privacy compatability */
 	if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
 	    ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
 				"because of privacy mismatch: %s != %s.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid),
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid,
 				priv->capability & CAP_PRIVACY_ON ? "on" :
 				"off",
 				network->capability &
@@ -5770,48 +5761,53 @@
 
 	if ((priv->config & CFG_STATIC_BSSID) &&
 	    memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
-				"because of BSSID mismatch: %s.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid), print_mac(mac, priv->bssid));
+		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
+				"because of BSSID mismatch: %pM.\n",
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid, priv->bssid);
 		return 0;
 	}
 
 	/* Filter out any incompatible freq / mode combinations */
 	if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
 				"because of invalid frequency/mode "
 				"combination.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid));
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid);
 		return 0;
 	}
 
 	/* Filter out invalid channel in current GEO */
 	if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) {
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
 				"because of invalid channel in current GEO\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid));
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid);
 		return 0;
 	}
 
 	/* Ensure that the rates supported by the driver are compatible with
 	 * this AP, including verification of basic rates (mandatory) */
 	if (!ipw_compatible_rates(priv, network, &rates)) {
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
 				"because configured rate mask excludes "
 				"AP mandatory rate.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid));
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid);
 		return 0;
 	}
 
 	if (rates.num_rates == 0) {
-		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
 				"because of no compatible rates.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				print_mac(mac, network->bssid));
+				print_ssid(ssid, network->ssid,
+					   network->ssid_len),
+				network->bssid);
 		return 0;
 	}
 
@@ -5823,9 +5819,9 @@
 	ipw_copy_rates(&match->rates, &rates);
 	match->network = network;
 
-	IPW_DEBUG_ASSOC("Network '%s (%s)' is a viable match.\n",
-			escape_essid(network->ssid, network->ssid_len),
-			print_mac(mac, network->bssid));
+	IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n",
+			print_ssid(ssid, network->ssid, network->ssid_len),
+			network->bssid);
 
 	return 1;
 }
@@ -6067,7 +6063,7 @@
 
 static void ipw_debug_config(struct ipw_priv *priv)
 {
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 	IPW_DEBUG_INFO("Scan completed, no valid APs matched "
 		       "[CFG 0x%08X]\n", priv->config);
 	if (priv->config & CFG_STATIC_CHANNEL)
@@ -6076,12 +6072,11 @@
 		IPW_DEBUG_INFO("Channel unlocked.\n");
 	if (priv->config & CFG_STATIC_ESSID)
 		IPW_DEBUG_INFO("ESSID locked to '%s'\n",
-			       escape_essid(priv->essid, priv->essid_len));
+			       print_ssid(ssid, priv->essid, priv->essid_len));
 	else
 		IPW_DEBUG_INFO("ESSID unlocked.\n");
 	if (priv->config & CFG_STATIC_BSSID)
-		IPW_DEBUG_INFO("BSSID locked to %s\n",
-			       print_mac(mac, priv->bssid));
+		IPW_DEBUG_INFO("BSSID locked to %pM\n", priv->bssid);
 	else
 		IPW_DEBUG_INFO("BSSID unlocked.\n");
 	if (priv->capability & CAP_PRIVACY_ON)
@@ -6277,6 +6272,20 @@
 	}
 }
 
+static int ipw_passive_dwell_time(struct ipw_priv *priv)
+{
+	/* staying on passive channels longer than the DTIM interval during a
+	 * scan, while associated, causes the firmware to cancel the scan
+	 * without notification. Hence, don't stay on passive channels longer
+	 * than the beacon interval.
+	 */
+	if (priv->status & STATUS_ASSOCIATED
+	    && priv->assoc_network->beacon_interval > 10)
+		return priv->assoc_network->beacon_interval - 10;
+	else
+		return 120;
+}
+
 static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
 {
 	struct ipw_scan_request_ext scan;
@@ -6320,16 +6329,16 @@
 	scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
 
 	if (type == IW_SCAN_TYPE_PASSIVE) {
-	  	IPW_DEBUG_WX("use passive scanning\n");
-	  	scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN;
+		IPW_DEBUG_WX("use passive scanning\n");
+		scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN;
 		scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
-			cpu_to_le16(120);
+			cpu_to_le16(ipw_passive_dwell_time(priv));
 		ipw_add_scan_channels(priv, &scan, scan_type);
 		goto send_request;
 	}
 
 	/* Use active scan by default. */
-  	if (priv->config & CFG_SPEED_SCAN)
+	if (priv->config & CFG_SPEED_SCAN)
 		scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
 			cpu_to_le16(30);
 	else
@@ -6339,7 +6348,8 @@
 	scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
 		cpu_to_le16(20);
 
-  	scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
+	scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
+		cpu_to_le16(ipw_passive_dwell_time(priv));
 	scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
 
 #ifdef CONFIG_IPW2200_MONITOR
@@ -6607,7 +6617,7 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	struct ieee80211_device *ieee = priv->ieee;
 	struct iw_param *param = &wrqu->param;
-	struct ieee80211_crypt_data *crypt;
+	struct lib80211_crypt_data *crypt;
 	unsigned long flags;
 	int ret = 0;
 
@@ -6629,7 +6639,7 @@
 		break;
 
 	case IW_AUTH_TKIP_COUNTERMEASURES:
-		crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+		crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
 		if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
 			break;
 
@@ -6706,7 +6716,7 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	struct ieee80211_device *ieee = priv->ieee;
-	struct ieee80211_crypt_data *crypt;
+	struct lib80211_crypt_data *crypt;
 	struct iw_param *param = &wrqu->param;
 	int ret = 0;
 
@@ -6722,7 +6732,7 @@
 		break;
 
 	case IW_AUTH_TKIP_COUNTERMEASURES:
-		crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+		crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
 		if (!crypt || !crypt->ops->get_flags)
 			break;
 
@@ -6893,8 +6903,7 @@
 	if ((priv->status & STATUS_ASSOCIATED) &&
 	    (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) {
 		if (memcmp(network->bssid, priv->bssid, ETH_ALEN))
-			if ((network->capability & WLAN_CAPABILITY_IBSS) &&
-			    !(network->flags & NETWORK_EMPTY_ESSID))
+			if (network->capability & WLAN_CAPABILITY_IBSS)
 				if ((network->ssid_len ==
 				     priv->assoc_network->ssid_len) &&
 				    !memcmp(network->ssid,
@@ -7296,7 +7305,7 @@
 				 struct ipw_supported_rates *rates, int roaming)
 {
 	int err;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 
 	if (priv->config & CFG_FIXED_RATE)
 		ipw_set_fixed_rate(priv, network->mode);
@@ -7365,7 +7374,7 @@
 	IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, "
 			"802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
 			roaming ? "Rea" : "A",
-			escape_essid(priv->essid, priv->essid_len),
+			print_ssid(ssid, priv->essid, priv->essid_len),
 			network->channel,
 			ipw_modes[priv->assoc_request.ieee_mode],
 			rates->num_rates,
@@ -7464,9 +7473,9 @@
 		return err;
 	}
 
-	IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %s \n",
-		  escape_essid(priv->essid, priv->essid_len),
-		  print_mac(mac, priv->bssid));
+	IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n",
+		  print_ssid(ssid, priv->essid, priv->essid_len),
+		  priv->bssid);
 
 	return 0;
 }
@@ -7556,6 +7565,7 @@
 	struct ipw_supported_rates *rates;
 	struct list_head *element;
 	unsigned long flags;
+	DECLARE_SSID_BUF(ssid);
 
 	if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
 		IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n");
@@ -7582,8 +7592,7 @@
 	}
 
 	if (!(priv->config & CFG_ASSOCIATE) &&
-	    !(priv->config & (CFG_STATIC_ESSID |
-			      CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) {
+	    !(priv->config & (CFG_STATIC_ESSID | CFG_STATIC_BSSID))) {
 		IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n");
 		return 0;
 	}
@@ -7605,7 +7614,6 @@
 		if (list_empty(&priv->ieee->network_free_list)) {
 			struct ieee80211_network *oldest = NULL;
 			struct ieee80211_network *target;
-			DECLARE_MAC_BUF(mac);
 
 			list_for_each_entry(target, &priv->ieee->network_list, list) {
 				if ((oldest == NULL) ||
@@ -7616,11 +7624,11 @@
 			/* If there are no more slots, expire the oldest */
 			list_del(&oldest->list);
 			target = oldest;
-			IPW_DEBUG_ASSOC("Expired '%s' (%s) from "
+			IPW_DEBUG_ASSOC("Expired '%s' (%pM) from "
 					"network list.\n",
-					escape_essid(target->ssid,
-						     target->ssid_len),
-					print_mac(mac, target->bssid));
+					print_ssid(ssid, target->ssid,
+						   target->ssid_len),
+					target->bssid);
 			list_add_tail(&target->list,
 				      &priv->ieee->network_free_list);
 		}
@@ -7673,12 +7681,12 @@
 	u16 fc;
 
 	hdr = (struct ieee80211_hdr *)skb->data;
-	fc = le16_to_cpu(hdr->frame_ctl);
+	fc = le16_to_cpu(hdr->frame_control);
 	if (!(fc & IEEE80211_FCTL_PROTECTED))
 		return;
 
 	fc &= ~IEEE80211_FCTL_PROTECTED;
-	hdr->frame_ctl = cpu_to_le16(fc);
+	hdr->frame_control = cpu_to_le16(fc);
 	switch (priv->ieee->sec.level) {
 	case SEC_LEVEL_3:
 		/* Remove CCMP HDR */
@@ -7806,15 +7814,6 @@
 	memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr),
 		rxb->skb->data + IPW_RX_FRAME_SIZE, len);
 
-	/* Zero the radiotap static buffer  ...  We only need to zero the bytes NOT
-	 * part of our real header, saves a little time.
-	 *
-	 * No longer necessary since we fill in all our data.  Purge before merging
-	 * patch officially.
-	 * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0,
-	 *        IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr));
-	 */
-
 	ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data;
 
 	ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
@@ -7990,17 +7989,17 @@
 	}
 
 	hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE;
-	if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) {
+	if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) {
 		if (filter & IPW_PROM_NO_MGMT)
 			return;
 		if (filter & IPW_PROM_MGMT_HEADER_ONLY)
 			hdr_only = 1;
-	} else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) {
+	} else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) {
 		if (filter & IPW_PROM_NO_CTL)
 			return;
 		if (filter & IPW_PROM_CTL_HEADER_ONLY)
 			hdr_only = 1;
-	} else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) {
+	} else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) {
 		if (filter & IPW_PROM_NO_DATA)
 			return;
 		if (filter & IPW_PROM_DATA_HEADER_ONLY)
@@ -8018,19 +8017,10 @@
 	ipw_rt = (void *)skb->data;
 
 	if (hdr_only)
-		len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+		len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
 
 	memcpy(ipw_rt->payload, hdr, len);
 
-	/* Zero the radiotap static buffer  ...  We only need to zero the bytes
-	 * NOT part of our real header, saves a little time.
-	 *
-	 * No longer necessary since we fill in all our data.  Purge before
-	 * merging patch officially.
-	 * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0,
-	 *        IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr));
-	 */
-
 	ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
 	ipw_rt->rt_hdr.it_pad = 0;	/* always good to zero */
 	ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt));	/* total header+data */
@@ -8238,7 +8228,7 @@
 	/* Comment this line now since we observed the card receives
 	 * duplicate packets but the FCTL_RETRY bit is not set in the
 	 * IBSS mode with fragmentation enabled.
-	 BUG_ON(!(le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_RETRY)); */
+	 BUG_ON(!(le16_to_cpu(header->frame_control) & IEEE80211_FCTL_RETRY)); */
 	return 1;
 }
 
@@ -8302,9 +8292,6 @@
 	u32 r, w, i;
 	u8 network_packet;
 	u8 fill_rx = 0;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
-	DECLARE_MAC_BUF(mac3);
 
 	r = ipw_read32(priv, IPW_RX_READ_INDEX);
 	w = ipw_read32(priv, IPW_RX_WRITE_INDEX);
@@ -8434,18 +8421,12 @@
 									 header)))
 					{
 						IPW_DEBUG_DROP("Dropping: "
-							       "%s, "
-							       "%s, "
-							       "%s\n",
-							       print_mac(mac,
-									 header->
-								       addr1),
-							       print_mac(mac2,
-									 header->
-								       addr2),
-							       print_mac(mac3,
-									 header->
-								       addr3));
+							       "%pM, "
+							       "%pM, "
+							       "%pM\n",
+							       header->addr1,
+							       header->addr2,
+							       header->addr3);
 						break;
 					}
 
@@ -8984,7 +8965,6 @@
 			  union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	DECLARE_MAC_BUF(mac);
 
 	static const unsigned char any[] = {
 		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
@@ -9015,8 +8995,8 @@
 		return 0;
 	}
 
-	IPW_DEBUG_WX("Setting mandatory BSSID to %s\n",
-		     print_mac(mac, wrqu->ap_addr.sa_data));
+	IPW_DEBUG_WX("Setting mandatory BSSID to %pM\n",
+		     wrqu->ap_addr.sa_data);
 
 	memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
 
@@ -9034,7 +9014,6 @@
 			  union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	DECLARE_MAC_BUF(mac);
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured BSSID then return that; otherwise return ANY */
@@ -9046,8 +9025,8 @@
 	} else
 		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
 
-	IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
-		     print_mac(mac, wrqu->ap_addr.sa_data));
+	IPW_DEBUG_WX("Getting WAP BSSID: %pM\n",
+		     wrqu->ap_addr.sa_data);
 	mutex_unlock(&priv->mutex);
 	return 0;
 }
@@ -9058,6 +9037,7 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
         int length;
+	DECLARE_SSID_BUF(ssid);
 
         mutex_lock(&priv->mutex);
 
@@ -9082,8 +9062,8 @@
 		return 0;
 	}
 
-	IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(extra, length),
-		     length);
+	IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
+		     print_ssid(ssid, extra, length), length);
 
 	priv->essid_len = length;
 	memcpy(priv->essid, extra, priv->essid_len);
@@ -9102,6 +9082,7 @@
 			    union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
+	DECLARE_SSID_BUF(ssid);
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured ESSID then return that; otherwise return ANY */
@@ -9109,7 +9090,7 @@
 	if (priv->config & CFG_STATIC_ESSID ||
 	    priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
 		IPW_DEBUG_WX("Getting essid: '%s'\n",
-			     escape_essid(priv->essid, priv->essid_len));
+			     print_ssid(ssid, priv->essid, priv->essid_len));
 		memcpy(extra, priv->essid, priv->essid_len);
 		wrqu->essid.length = priv->essid_len;
 		wrqu->essid.flags = 1;	/* active */
@@ -10203,10 +10184,8 @@
 			id = ipw_add_station(priv, hdr->addr1);
 			if (id == IPW_INVALID_STATION) {
 				IPW_WARNING("Attempt to send data to "
-					    "invalid cell: " MAC_FMT "\n",
-					    hdr->addr1[0], hdr->addr1[1],
-					    hdr->addr1[2], hdr->addr1[3],
-					    hdr->addr1[4], hdr->addr1[5]);
+					    "invalid cell: %pM\n",
+					    hdr->addr1);
 				goto drop;
 			}
 		}
@@ -10274,8 +10253,8 @@
 		case SEC_LEVEL_1:
 			tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
 			    cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-			tfd->u.data.key_index = priv->ieee->tx_keyidx;
-			if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <=
+			tfd->u.data.key_index = priv->ieee->crypt_info.tx_keyidx;
+			if (priv->ieee->sec.key_sizes[priv->ieee->crypt_info.tx_keyidx] <=
 			    40)
 				tfd->u.data.key_index |= DCT_WEP_KEY_64Bit;
 			else
@@ -10403,17 +10382,17 @@
 
 	/* Filtering of fragment chains is done agains the first fragment */
 	hdr = (void *)txb->fragments[0]->data;
-	if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) {
+	if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) {
 		if (filter & IPW_PROM_NO_MGMT)
 			return;
 		if (filter & IPW_PROM_MGMT_HEADER_ONLY)
 			hdr_only = 1;
-	} else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) {
+	} else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) {
 		if (filter & IPW_PROM_NO_CTL)
 			return;
 		if (filter & IPW_PROM_CTL_HEADER_ONLY)
 			hdr_only = 1;
-	} else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) {
+	} else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) {
 		if (filter & IPW_PROM_NO_DATA)
 			return;
 		if (filter & IPW_PROM_DATA_HEADER_ONLY)
@@ -10428,13 +10407,13 @@
 
 		if (hdr_only) {
 			hdr = (void *)src->data;
-			len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+			len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
 		} else
 			len = src->len;
 
-		dst = alloc_skb(
-			len + IEEE80211_RADIOTAP_HDRLEN, GFP_ATOMIC);
-		if (!dst) continue;
+		dst = alloc_skb(len + sizeof(*rt_hdr), GFP_ATOMIC);
+		if (!dst)
+			continue;
 
 		rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr));
 
@@ -10509,15 +10488,14 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	struct sockaddr *addr = p;
-	DECLARE_MAC_BUF(mac);
 
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 	mutex_lock(&priv->mutex);
 	priv->config |= CFG_CUSTOM_MAC;
 	memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
-	printk(KERN_INFO "%s: Setting MAC to %s\n",
-	       priv->net_dev->name, print_mac(mac, priv->mac_addr));
+	printk(KERN_INFO "%s: Setting MAC to %pM\n",
+	       priv->net_dev->name, priv->mac_addr);
 	queue_work(priv->workqueue, &priv->adapter_restart);
 	mutex_unlock(&priv->mutex);
 	return 0;
@@ -11652,7 +11630,7 @@
 	length = pci_resource_len(pdev, 0);
 	priv->hw_len = length;
 
-	base = ioremap_nocache(pci_resource_start(pdev, 0), length);
+	base = pci_ioremap_bar(pdev, 0);
 	if (!base) {
 		err = -ENODEV;
 		goto out_pci_release_regions;
@@ -11944,7 +11922,7 @@
 MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
 
 module_param(associate, int, 0444);
-MODULE_PARM_DESC(associate, "auto associate when scanning (default on)");
+MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
 
 module_param(auto_create, int, 0444);
 MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h
similarity index 99%
rename from drivers/net/wireless/ipw2200.h
rename to drivers/net/wireless/ipw2x00/ipw2200.h
index 0bad1ec..277b274 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2x00/ipw2200.h
@@ -48,6 +48,7 @@
 #include <linux/jiffies.h>
 #include <asm/io.h>
 
+#include <net/lib80211.h>
 #include <net/ieee80211.h>
 #include <net/ieee80211_radiotap.h>
 
@@ -244,6 +245,7 @@
 #define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED       31
 
 #define HOST_NOTIFICATION_STATUS_BEACON_MISSING         1
+#define IPW_MB_SCAN_CANCEL_THRESHOLD                    3
 #define IPW_MB_ROAMING_THRESHOLD_MIN                    1
 #define IPW_MB_ROAMING_THRESHOLD_DEFAULT                8
 #define IPW_MB_ROAMING_THRESHOLD_MAX                    30
diff --git a/net/ieee80211/ieee80211_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c
similarity index 100%
rename from net/ieee80211/ieee80211_geo.c
rename to drivers/net/wireless/ipw2x00/libipw_geo.c
diff --git a/net/ieee80211/ieee80211_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c
similarity index 87%
rename from net/ieee80211/ieee80211_module.c
rename to drivers/net/wireless/ipw2x00/libipw_module.c
index 949772a..a2f5616 100644
--- a/net/ieee80211/ieee80211_module.c
+++ b/drivers/net/wireless/ipw2x00/libipw_module.c
@@ -180,13 +180,10 @@
 	ieee->host_open_frag = 1;
 	ieee->ieee802_1x = 1;	/* Default to supporting 802.1x */
 
-	INIT_LIST_HEAD(&ieee->crypt_deinit_list);
-	setup_timer(&ieee->crypt_deinit_timer, ieee80211_crypt_deinit_handler,
-			(unsigned long)ieee);
-	ieee->crypt_quiesced = 0;
-
 	spin_lock_init(&ieee->lock);
 
+	lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
+
 	ieee->wpa_enabled = 0;
 	ieee->drop_unencrypted = 0;
 	ieee->privacy_invoked = 0;
@@ -203,23 +200,7 @@
 {
 	struct ieee80211_device *ieee = netdev_priv(dev);
 
-	int i;
-
-	ieee80211_crypt_quiescing(ieee);
-	del_timer_sync(&ieee->crypt_deinit_timer);
-	ieee80211_crypt_deinit_entries(ieee, 1);
-
-	for (i = 0; i < WEP_KEYS; i++) {
-		struct ieee80211_crypt_data *crypt = ieee->crypt[i];
-		if (crypt) {
-			if (crypt->ops) {
-				crypt->ops->deinit(crypt->priv);
-				module_put(crypt->ops->owner);
-			}
-			kfree(crypt);
-			ieee->crypt[i] = NULL;
-		}
-	}
+	lib80211_crypt_info_free(&ieee->crypt_info);
 
 	ieee80211_networks_free(ieee);
 	free_netdev(dev);
@@ -308,31 +289,5 @@
 module_exit(ieee80211_exit);
 module_init(ieee80211_init);
 
-const char *escape_essid(const char *essid, u8 essid_len)
-{
-	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-	const char *s = essid;
-	char *d = escaped;
-
-	if (ieee80211_is_empty_essid(essid, essid_len)) {
-		memcpy(escaped, "<hidden>", sizeof("<hidden>"));
-		return escaped;
-	}
-
-	essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
-	while (essid_len--) {
-		if (*s == '\0') {
-			*d++ = '\\';
-			*d++ = '0';
-			s++;
-		} else {
-			*d++ = *s++;
-		}
-	}
-	*d = '\0';
-	return escaped;
-}
-
 EXPORT_SYMBOL(alloc_ieee80211);
 EXPORT_SYMBOL(free_ieee80211);
-EXPORT_SYMBOL(escape_essid);
diff --git a/net/ieee80211/ieee80211_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c
similarity index 93%
rename from net/ieee80211/ieee80211_rx.c
rename to drivers/net/wireless/ipw2x00/libipw_rx.c
index 69dbc34..9c67dfa 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_rx.c
@@ -32,6 +32,7 @@
 #include <asm/uaccess.h>
 #include <linux/ctype.h>
 
+#include <net/lib80211.h>
 #include <net/ieee80211.h>
 
 static void ieee80211_monitor_rx(struct ieee80211_device *ieee,
@@ -39,7 +40,7 @@
 					struct ieee80211_rx_stats *rx_stats)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	u16 fc = le16_to_cpu(hdr->frame_ctl);
+	u16 fc = le16_to_cpu(hdr->frame_control);
 
 	skb->dev = ieee->dev;
 	skb_reset_mac_header(skb);
@@ -267,7 +268,7 @@
 /* Called only as a tasklet (software IRQ), by ieee80211_rx */
 static int
 ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
-			   struct ieee80211_crypt_data *crypt)
+			   struct lib80211_crypt_data *crypt)
 {
 	struct ieee80211_hdr_3addr *hdr;
 	int res, hdrlen;
@@ -282,12 +283,8 @@
 	res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
 	atomic_dec(&crypt->refcnt);
 	if (res < 0) {
-		IEEE80211_DEBUG_DROP("decryption failed (SA=" MAC_FMT
-				     ") res=%d\n",
-				     hdr->addr2[0], hdr->addr2[1],
-				     hdr->addr2[2], hdr->addr2[3],
-				     hdr->addr2[4], hdr->addr2[5],
-				     res);
+		IEEE80211_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n",
+				     hdr->addr2, res);
 		if (res == -2)
 			IEEE80211_DEBUG_DROP("Decryption failed ICV "
 					     "mismatch (key %d)\n",
@@ -303,7 +300,7 @@
 static int
 ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,
 				struct sk_buff *skb, int keyidx,
-				struct ieee80211_crypt_data *crypt)
+				struct lib80211_crypt_data *crypt)
 {
 	struct ieee80211_hdr_3addr *hdr;
 	int res, hdrlen;
@@ -319,11 +316,7 @@
 	atomic_dec(&crypt->refcnt);
 	if (res < 0) {
 		printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
-		       " (SA=" MAC_FMT " keyidx=%d)\n",
-		       ieee->dev->name,
-		       hdr->addr2[0], hdr->addr2[1],
-		       hdr->addr2[2], hdr->addr2[3],
-		       hdr->addr2[4], hdr->addr2[5],
+		       " (SA=%pM keyidx=%d)\n", ieee->dev->name, hdr->addr2,
 		       keyidx);
 		return -1;
 	}
@@ -355,10 +348,9 @@
 #endif
 	u8 dst[ETH_ALEN];
 	u8 src[ETH_ALEN];
-	struct ieee80211_crypt_data *crypt = NULL;
+	struct lib80211_crypt_data *crypt = NULL;
 	int keyidx = 0;
 	int can_be_decrypted = 0;
-	DECLARE_MAC_BUF(mac);
 
 	hdr = (struct ieee80211_hdr_4addr *)skb->data;
 	stats = &ieee->stats;
@@ -439,7 +431,7 @@
 		 * is only allowed 2-bits of storage, no value of keyidx can
 		 * be provided via above code that would result in keyidx
 		 * being out of range */
-		crypt = ieee->crypt[keyidx];
+		crypt = ieee->crypt_info.crypt[keyidx];
 
 #ifdef NOT_YET
 		sta = NULL;
@@ -468,10 +460,7 @@
 			 * frames silently instead of filling system log with
 			 * these reports. */
 			IEEE80211_DEBUG_DROP("Decryption failed (not set)"
-					     " (SA=" MAC_FMT ")\n",
-					     hdr->addr2[0], hdr->addr2[1],
-					     hdr->addr2[2], hdr->addr2[3],
-					     hdr->addr2[4], hdr->addr2[5]);
+					     " (SA=%pM)\n", hdr->addr2);
 			ieee->ieee_stats.rx_discards_undecryptable++;
 			goto rx_dropped;
 		}
@@ -482,10 +471,7 @@
 		    fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt &&
 		    (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) {
 			printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
-			       "from " MAC_FMT "\n", dev->name,
-			       hdr->addr2[0], hdr->addr2[1],
-			       hdr->addr2[2], hdr->addr2[3],
-			       hdr->addr2[4], hdr->addr2[5]);
+			       "from %pM\n", dev->name, hdr->addr2);
 			/* TODO: could inform hostapd about this so that it
 			 * could send auth failure report */
 			goto rx_dropped;
@@ -547,8 +533,6 @@
 	}
 #endif
 
-	dev->last_rx = jiffies;
-
 #ifdef NOT_YET
 	if ((ieee->iw_mode == IW_MODE_MASTER ||
 	     ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) {
@@ -663,11 +647,8 @@
 			 * configured */
 		} else {
 			IEEE80211_DEBUG_DROP("encryption configured, but RX "
-					     "frame not encrypted (SA="
-					     MAC_FMT ")\n",
-					     hdr->addr2[0], hdr->addr2[1],
-					     hdr->addr2[2], hdr->addr2[3],
-					     hdr->addr2[4], hdr->addr2[5]);
+					     "frame not encrypted (SA=%pM)\n",
+					     hdr->addr2);
 			goto rx_dropped;
 		}
 	}
@@ -675,11 +656,8 @@
 	if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
 	    !ieee80211_is_eapol_frame(ieee, skb)) {
 		IEEE80211_DEBUG_DROP("dropped unencrypted RX data "
-				     "frame from " MAC_FMT
-				     " (drop_unencrypted=1)\n",
-				     hdr->addr2[0], hdr->addr2[1],
-				     hdr->addr2[2], hdr->addr2[3],
-				     hdr->addr2[4], hdr->addr2[5]);
+				     "frame from %pM (drop_unencrypted=1)\n",
+				     hdr->addr2);
 		goto rx_dropped;
 	}
 
@@ -1144,6 +1122,7 @@
 				      *info_element, u16 length,
 				      struct ieee80211_network *network)
 {
+	DECLARE_SSID_BUF(ssid);
 	u8 i;
 #ifdef CONFIG_IEEE80211_DEBUG
 	char rates_str[64];
@@ -1166,12 +1145,6 @@
 
 		switch (info_element->id) {
 		case MFIE_TYPE_SSID:
-			if (ieee80211_is_empty_essid(info_element->data,
-						     info_element->len)) {
-				network->flags |= NETWORK_EMPTY_ESSID;
-				break;
-			}
-
 			network->ssid_len = min(info_element->len,
 						(u8) IW_ESSID_MAX_SIZE);
 			memcpy(network->ssid, info_element->data,
@@ -1181,7 +1154,9 @@
 				       IW_ESSID_MAX_SIZE - network->ssid_len);
 
 			IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n",
-					     network->ssid, network->ssid_len);
+					     print_ssid(ssid, network->ssid,
+							network->ssid_len),
+					     network->ssid_len);
 			break;
 
 		case MFIE_TYPE_RATES:
@@ -1411,9 +1386,6 @@
 			network->mode |= IEEE_B;
 	}
 
-	if (ieee80211_is_empty_essid(network->ssid, network->ssid_len))
-		network->flags |= NETWORK_EMPTY_ESSID;
-
 	memcpy(&network->stats, stats, sizeof(network->stats));
 
 	if (ieee->handle_assoc_response != NULL)
@@ -1429,7 +1401,7 @@
 					 struct ieee80211_network *network,
 					 struct ieee80211_rx_stats *stats)
 {
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 
 	network->qos_data.active = 0;
 	network->qos_data.supported = 0;
@@ -1477,17 +1449,14 @@
 	}
 
 	if (network->mode == 0) {
-		IEEE80211_DEBUG_SCAN("Filtered out '%s (%s)' "
+		IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' "
 				     "network.\n",
-				     escape_essid(network->ssid,
-						  network->ssid_len),
-				     print_mac(mac, network->bssid));
+				     print_ssid(ssid, network->ssid,
+						 network->ssid_len),
+				     network->bssid);
 		return 1;
 	}
 
-	if (ieee80211_is_empty_essid(network->ssid, network->ssid_len))
-		network->flags |= NETWORK_EMPTY_ESSID;
-
 	memcpy(&network->stats, stats, sizeof(network->stats));
 
 	return 0;
@@ -1510,7 +1479,6 @@
 {
 	int qos_active;
 	u8 old_param;
-	DECLARE_MAC_BUF(mac);
 
 	ieee80211_network_reset(dst);
 	dst->ibss_dfs = src->ibss_dfs;
@@ -1524,8 +1492,8 @@
 		memcpy(&dst->stats, &src->stats,
 		       sizeof(struct ieee80211_rx_stats));
 	else
-		IEEE80211_DEBUG_SCAN("Network %s info received "
-			"off channel (%d vs. %d)\n", print_mac(mac, src->bssid),
+		IEEE80211_DEBUG_SCAN("Network %pM info received "
+			"off channel (%d vs. %d)\n", src->bssid,
 			dst->channel, src->stats.received_channel);
 
 	dst->capability = src->capability;
@@ -1597,12 +1565,12 @@
 	struct ieee80211_info_element *info_element = beacon->info_element;
 #endif
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 
-	IEEE80211_DEBUG_SCAN("'%s' (%s"
+	IEEE80211_DEBUG_SCAN("'%s' (%pM"
 		     "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
-		     escape_essid(info_element->data, info_element->len),
-		     print_mac(mac, beacon->header.addr3),
+		     print_ssid(ssid, info_element->data, info_element->len),
+		     beacon->header.addr3,
 		     (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0',
 		     (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0',
 		     (beacon->capability & cpu_to_le16(1 << 0xd)) ? '1' : '0',
@@ -1621,10 +1589,10 @@
 		     (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
 
 	if (ieee80211_network_init(ieee, beacon, &network, stats)) {
-		IEEE80211_DEBUG_SCAN("Dropped '%s' (%s) via %s.\n",
-				     escape_essid(info_element->data,
-						  info_element->len),
-				     print_mac(mac, beacon->header.addr3),
+		IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
+				     print_ssid(ssid, info_element->data,
+						 info_element->len),
+				     beacon->header.addr3,
 				     is_beacon(beacon->header.frame_ctl) ?
 				     "BEACON" : "PROBE RESPONSE");
 		return;
@@ -1658,11 +1626,11 @@
 			/* If there are no more slots, expire the oldest */
 			list_del(&oldest->list);
 			target = oldest;
-			IEEE80211_DEBUG_SCAN("Expired '%s' (%s) from "
+			IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from "
 					     "network list.\n",
-					     escape_essid(target->ssid,
-							  target->ssid_len),
-					     print_mac(mac, target->bssid));
+					     print_ssid(ssid, target->ssid,
+							 target->ssid_len),
+					     target->bssid);
 			ieee80211_network_reset(target);
 		} else {
 			/* Otherwise just pull from the free list */
@@ -1672,10 +1640,10 @@
 		}
 
 #ifdef CONFIG_IEEE80211_DEBUG
-		IEEE80211_DEBUG_SCAN("Adding '%s' (%s) via %s.\n",
-				     escape_essid(network.ssid,
-						  network.ssid_len),
-				     print_mac(mac, network.bssid),
+		IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
+				     print_ssid(ssid, network.ssid,
+						 network.ssid_len),
+				     network.bssid,
 				     is_beacon(beacon->header.frame_ctl) ?
 				     "BEACON" : "PROBE RESPONSE");
 #endif
@@ -1683,10 +1651,10 @@
 		network.ibss_dfs = NULL;
 		list_add_tail(&target->list, &ieee->network_list);
 	} else {
-		IEEE80211_DEBUG_SCAN("Updating '%s' (%s) via %s.\n",
-				     escape_essid(target->ssid,
-						  target->ssid_len),
-				     print_mac(mac, target->bssid),
+		IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
+				     print_ssid(ssid, target->ssid,
+						 target->ssid_len),
+				     target->bssid,
 				     is_beacon(beacon->header.frame_ctl) ?
 				     "BEACON" : "PROBE RESPONSE");
 		update_network(target, &network);
diff --git a/net/ieee80211/ieee80211_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c
similarity index 98%
rename from net/ieee80211/ieee80211_tx.c
rename to drivers/net/wireless/ipw2x00/libipw_tx.c
index d996547..f78f57e 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_tx.c
@@ -152,7 +152,8 @@
 static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
 					     struct sk_buff *frag, int hdr_len)
 {
-	struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
+	struct lib80211_crypt_data *crypt =
+		ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
 	int res;
 
 	if (crypt == NULL)
@@ -270,7 +271,7 @@
 		.qos_ctl = 0
 	};
 	u8 dest[ETH_ALEN], src[ETH_ALEN];
-	struct ieee80211_crypt_data *crypt;
+	struct lib80211_crypt_data *crypt;
 	int priority = skb->priority;
 	int snapped = 0;
 
@@ -294,7 +295,7 @@
 
 	ether_type = ((struct ethhdr *)skb->data)->h_proto;
 
-	crypt = ieee->crypt[ieee->tx_keyidx];
+	crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
 
 	encrypt = !(ether_type == htons(ETH_P_PAE) && ieee->ieee802_1x) &&
 	    ieee->sec.encrypt;
diff --git a/net/ieee80211/ieee80211_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c
similarity index 90%
rename from net/ieee80211/ieee80211_wx.c
rename to drivers/net/wireless/ipw2x00/libipw_wx.c
index 973832d..31ea3ab 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_wx.c
@@ -34,6 +34,7 @@
 #include <linux/module.h>
 #include <linux/jiffies.h>
 
+#include <net/lib80211.h>
 #include <net/ieee80211.h>
 #include <linux/wireless.h>
 
@@ -65,15 +66,9 @@
 	/* Add the ESSID */
 	iwe.cmd = SIOCGIWESSID;
 	iwe.u.data.flags = 1;
-	if (network->flags & NETWORK_EMPTY_ESSID) {
-		iwe.u.data.length = sizeof("<hidden>");
-		start = iwe_stream_add_point(info, start, stop,
-					     &iwe, "<hidden>");
-	} else {
-		iwe.u.data.length = min(network->ssid_len, (u8) 32);
-		start = iwe_stream_add_point(info, start, stop,
-					     &iwe, network->ssid);
-	}
+	iwe.u.data.length = min(network->ssid_len, (u8) 32);
+	start = iwe_stream_add_point(info, start, stop,
+				     &iwe, network->ssid);
 
 	/* Add the protocol name */
 	iwe.cmd = SIOCGIWNAME;
@@ -264,7 +259,7 @@
 	char *ev = extra;
 	char *stop = ev + wrqu->data.length;
 	int i = 0;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 
 	IEEE80211_DEBUG_WX("Getting scan\n");
 
@@ -283,10 +278,10 @@
 						      info);
 		else
 			IEEE80211_DEBUG_SCAN("Not showing network '%s ("
-					     "%s)' due to age (%dms).\n",
-					     escape_essid(network->ssid,
-							  network->ssid_len),
-					     print_mac(mac, network->bssid),
+					     "%pM)' due to age (%dms).\n",
+					     print_ssid(ssid, network->ssid,
+							 network->ssid_len),
+					     network->bssid,
 					     jiffies_to_msecs(jiffies -
 							      network->
 							      last_scanned));
@@ -312,8 +307,9 @@
 		.flags = 0
 	};
 	int i, key, key_provided, len;
-	struct ieee80211_crypt_data **crypt;
+	struct lib80211_crypt_data **crypt;
 	int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
+	DECLARE_SSID_BUF(ssid);
 
 	IEEE80211_DEBUG_WX("SET_ENCODE\n");
 
@@ -325,30 +321,30 @@
 		key_provided = 1;
 	} else {
 		key_provided = 0;
-		key = ieee->tx_keyidx;
+		key = ieee->crypt_info.tx_keyidx;
 	}
 
 	IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
 			   "provided" : "default");
 
-	crypt = &ieee->crypt[key];
+	crypt = &ieee->crypt_info.crypt[key];
 
 	if (erq->flags & IW_ENCODE_DISABLED) {
 		if (key_provided && *crypt) {
 			IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
 					   key);
-			ieee80211_crypt_delayed_deinit(ieee, crypt);
+			lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
 		} else
 			IEEE80211_DEBUG_WX("Disabling encryption.\n");
 
 		/* Check all the keys to see if any are still configured,
 		 * and if no key index was provided, de-init them all */
 		for (i = 0; i < WEP_KEYS; i++) {
-			if (ieee->crypt[i] != NULL) {
+			if (ieee->crypt_info.crypt[i] != NULL) {
 				if (key_provided)
 					break;
-				ieee80211_crypt_delayed_deinit(ieee,
-							       &ieee->crypt[i]);
+				lib80211_crypt_delayed_deinit(&ieee->crypt_info,
+							       &ieee->crypt_info.crypt[i]);
 			}
 		}
 
@@ -370,21 +366,21 @@
 	    strcmp((*crypt)->ops->name, "WEP") != 0) {
 		/* changing to use WEP; deinit previously used algorithm
 		 * on this key */
-		ieee80211_crypt_delayed_deinit(ieee, crypt);
+		lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
 	}
 
 	if (*crypt == NULL && host_crypto) {
-		struct ieee80211_crypt_data *new_crypt;
+		struct lib80211_crypt_data *new_crypt;
 
 		/* take WEP into use */
-		new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
+		new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
 				    GFP_KERNEL);
 		if (new_crypt == NULL)
 			return -ENOMEM;
-		new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+		new_crypt->ops = lib80211_get_crypto_ops("WEP");
 		if (!new_crypt->ops) {
-			request_module("ieee80211_crypt_wep");
-			new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+			request_module("lib80211_crypt_wep");
+			new_crypt->ops = lib80211_get_crypto_ops("WEP");
 		}
 
 		if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
@@ -395,7 +391,7 @@
 			new_crypt = NULL;
 
 			printk(KERN_WARNING "%s: could not initialize WEP: "
-			       "load module ieee80211_crypt_wep\n", dev->name);
+			       "load module lib80211_crypt_wep\n", dev->name);
 			return -EOPNOTSUPP;
 		}
 		*crypt = new_crypt;
@@ -403,13 +399,17 @@
 
 	/* If a new key was provided, set it up */
 	if (erq->length > 0) {
+#ifdef CONFIG_IEEE80211_DEBUG
+		DECLARE_SSID_BUF(ssid);
+#endif
+
 		len = erq->length <= 5 ? 5 : 13;
 		memcpy(sec.keys[key], keybuf, erq->length);
 		if (len > erq->length)
 			memset(sec.keys[key] + erq->length, 0,
 			       len - erq->length);
 		IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
-				   key, escape_essid(sec.keys[key], len),
+				   key, print_ssid(ssid, sec.keys[key], len),
 				   erq->length, len);
 		sec.key_sizes[key] = len;
 		if (*crypt)
@@ -440,7 +440,7 @@
 		if (key_provided) {
 			IEEE80211_DEBUG_WX("Setting key %d to default Tx "
 					   "key.\n", key);
-			ieee->tx_keyidx = key;
+			ieee->crypt_info.tx_keyidx = key;
 			sec.active_key = key;
 			sec.flags |= SEC_ACTIVE_KEY;
 		}
@@ -485,7 +485,7 @@
 {
 	struct iw_point *erq = &(wrqu->encoding);
 	int len, key;
-	struct ieee80211_crypt_data *crypt;
+	struct lib80211_crypt_data *crypt;
 	struct ieee80211_security *sec = &ieee->sec;
 
 	IEEE80211_DEBUG_WX("GET_ENCODE\n");
@@ -496,9 +496,9 @@
 			return -EINVAL;
 		key--;
 	} else
-		key = ieee->tx_keyidx;
+		key = ieee->crypt_info.tx_keyidx;
 
-	crypt = ieee->crypt[key];
+	crypt = ieee->crypt_info.crypt[key];
 	erq->flags = key + 1;
 
 	if (!sec->enabled) {
@@ -531,8 +531,8 @@
 	int i, idx, ret = 0;
 	int group_key = 0;
 	const char *alg, *module;
-	struct ieee80211_crypto_ops *ops;
-	struct ieee80211_crypt_data **crypt;
+	struct lib80211_crypto_ops *ops;
+	struct lib80211_crypt_data **crypt;
 
 	struct ieee80211_security sec = {
 		.flags = 0,
@@ -544,17 +544,17 @@
 			return -EINVAL;
 		idx--;
 	} else
-		idx = ieee->tx_keyidx;
+		idx = ieee->crypt_info.tx_keyidx;
 
 	if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
-		crypt = &ieee->crypt[idx];
+		crypt = &ieee->crypt_info.crypt[idx];
 		group_key = 1;
 	} else {
 		/* some Cisco APs use idx>0 for unicast in dynamic WEP */
 		if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
 			return -EINVAL;
 		if (ieee->iw_mode == IW_MODE_INFRA)
-			crypt = &ieee->crypt[idx];
+			crypt = &ieee->crypt_info.crypt[idx];
 		else
 			return -EINVAL;
 	}
@@ -563,10 +563,10 @@
 	if ((encoding->flags & IW_ENCODE_DISABLED) ||
 	    ext->alg == IW_ENCODE_ALG_NONE) {
 		if (*crypt)
-			ieee80211_crypt_delayed_deinit(ieee, crypt);
+			lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
 
 		for (i = 0; i < WEP_KEYS; i++)
-			if (ieee->crypt[i] != NULL)
+			if (ieee->crypt_info.crypt[i] != NULL)
 				break;
 
 		if (i == WEP_KEYS) {
@@ -589,15 +589,15 @@
 	switch (ext->alg) {
 	case IW_ENCODE_ALG_WEP:
 		alg = "WEP";
-		module = "ieee80211_crypt_wep";
+		module = "lib80211_crypt_wep";
 		break;
 	case IW_ENCODE_ALG_TKIP:
 		alg = "TKIP";
-		module = "ieee80211_crypt_tkip";
+		module = "lib80211_crypt_tkip";
 		break;
 	case IW_ENCODE_ALG_CCMP:
 		alg = "CCMP";
-		module = "ieee80211_crypt_ccmp";
+		module = "lib80211_crypt_ccmp";
 		break;
 	default:
 		IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
@@ -606,10 +606,10 @@
 		goto done;
 	}
 
-	ops = ieee80211_get_crypto_ops(alg);
+	ops = lib80211_get_crypto_ops(alg);
 	if (ops == NULL) {
 		request_module(module);
-		ops = ieee80211_get_crypto_ops(alg);
+		ops = lib80211_get_crypto_ops(alg);
 	}
 	if (ops == NULL) {
 		IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
@@ -619,9 +619,9 @@
 	}
 
 	if (*crypt == NULL || (*crypt)->ops != ops) {
-		struct ieee80211_crypt_data *new_crypt;
+		struct lib80211_crypt_data *new_crypt;
 
-		ieee80211_crypt_delayed_deinit(ieee, crypt);
+		lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
 
 		new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
 		if (new_crypt == NULL) {
@@ -649,7 +649,7 @@
 
       skip_host_crypt:
 	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
-		ieee->tx_keyidx = idx;
+		ieee->crypt_info.tx_keyidx = idx;
 		sec.active_key = idx;
 		sec.flags |= SEC_ACTIVE_KEY;
 	}
@@ -715,7 +715,7 @@
 			return -EINVAL;
 		idx--;
 	} else
-		idx = ieee->tx_keyidx;
+		idx = ieee->crypt_info.tx_keyidx;
 
 	if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
 	    ext->alg != IW_ENCODE_ALG_WEP)
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index b0ac0ce..47bee0e 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -4,6 +4,7 @@
 config IWLCORE
 	tristate "Intel Wireless Wifi Core"
 	depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+	select LIB80211
 	select IWLWIFI
 	select MAC80211_LEDS if IWLWIFI_LEDS
 	select LEDS_CLASS if IWLWIFI_LEDS
@@ -105,6 +106,7 @@
 	tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
 	depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
 	select FW_LOADER
+	select LIB80211
 	select IWLWIFI
 	select MAC80211_LEDS if IWL3945_LEDS
 	select LEDS_CLASS if IWL3945_LEDS
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 47aa28f..0be9e6b 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -5,9 +5,10 @@
 iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
 iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
 iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o
+iwlcore-$(CONFIG_IWLAGN_SPECTRUM_MEASUREMENT) += iwl-spectrum.o
 
 obj-$(CONFIG_IWLAGN)	+= iwlagn.o
-iwlagn-objs		:= iwl-agn.o iwl-agn-rs.o
+iwlagn-objs		:= iwl-agn.o iwl-agn-rs.o iwl-agn-hcmd-check.o
 
 iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
 iwlagn-$(CONFIG_IWL5000) += iwl-5000.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h
index 817ece7..c6f4eb5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -69,6 +69,12 @@
 #ifndef __iwl_3945_commands_h__
 #define __iwl_3945_commands_h__
 
+/* uCode version contains 4 values: Major/Minor/API/Serial */
+#define IWL_UCODE_MAJOR(ver)	(((ver) & 0xFF000000) >> 24)
+#define IWL_UCODE_MINOR(ver)	(((ver) & 0x00FF0000) >> 16)
+#define IWL_UCODE_API(ver)	(((ver) & 0x0000FF00) >> 8)
+#define IWL_UCODE_SERIAL(ver)	((ver) & 0x000000FF)
+
 enum {
 	REPLY_ALIVE = 0x1,
 	REPLY_ERROR = 0x2,
@@ -121,7 +127,7 @@
 	REPLY_TX_PWR_TABLE_CMD = 0x97,
 	MEASURE_ABORT_NOTIFICATION = 0x99,	/* not used */
 
-	/* Bluetooth device coexistance config command */
+	/* Bluetooth device coexistence config command */
 	REPLY_BT_CONFIG = 0x9b,
 
 	/* Statistics */
@@ -158,7 +164,7 @@
 	u8 cmd;		/* Command ID:  REPLY_RXON, etc. */
 	u8 flags;	/* IWL_CMD_* */
 	/*
-	 * The driver sets up the sequence number to values of its chosing.
+	 * The driver sets up the sequence number to values of its choosing.
 	 * uCode does not use this value, but passes it back to the driver
 	 * when sending the response to each driver-originated command, so
 	 * the driver can match the response to the command.  Since the values
@@ -220,7 +226,7 @@
  *
  *****************************************************************************/
 
-#define UCODE_VALID_OK	__constant_cpu_to_le32(0x1)
+#define UCODE_VALID_OK	cpu_to_le32(0x1)
 #define INITIALIZE_SUBTYPE    (9)
 
 /*
@@ -322,42 +328,42 @@
 
 /* rx_config flags */
 /* band & modulation selection */
-#define RXON_FLG_BAND_24G_MSK           __constant_cpu_to_le32(1 << 0)
-#define RXON_FLG_CCK_MSK                __constant_cpu_to_le32(1 << 1)
+#define RXON_FLG_BAND_24G_MSK           cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK                cpu_to_le32(1 << 1)
 /* auto detection enable */
-#define RXON_FLG_AUTO_DETECT_MSK        __constant_cpu_to_le32(1 << 2)
+#define RXON_FLG_AUTO_DETECT_MSK        cpu_to_le32(1 << 2)
 /* TGg protection when tx */
-#define RXON_FLG_TGG_PROTECT_MSK        __constant_cpu_to_le32(1 << 3)
+#define RXON_FLG_TGG_PROTECT_MSK        cpu_to_le32(1 << 3)
 /* cck short slot & preamble */
-#define RXON_FLG_SHORT_SLOT_MSK          __constant_cpu_to_le32(1 << 4)
-#define RXON_FLG_SHORT_PREAMBLE_MSK     __constant_cpu_to_le32(1 << 5)
+#define RXON_FLG_SHORT_SLOT_MSK          cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK     cpu_to_le32(1 << 5)
 /* antenna selection */
-#define RXON_FLG_DIS_DIV_MSK            __constant_cpu_to_le32(1 << 7)
-#define RXON_FLG_ANT_SEL_MSK            __constant_cpu_to_le32(0x0f00)
-#define RXON_FLG_ANT_A_MSK              __constant_cpu_to_le32(1 << 8)
-#define RXON_FLG_ANT_B_MSK              __constant_cpu_to_le32(1 << 9)
+#define RXON_FLG_DIS_DIV_MSK            cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK            cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK              cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK              cpu_to_le32(1 << 9)
 /* radar detection enable */
-#define RXON_FLG_RADAR_DETECT_MSK       __constant_cpu_to_le32(1 << 12)
-#define RXON_FLG_TGJ_NARROW_BAND_MSK    __constant_cpu_to_le32(1 << 13)
+#define RXON_FLG_RADAR_DETECT_MSK       cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK    cpu_to_le32(1 << 13)
 /* rx response to host with 8-byte TSF
 * (according to ON_AIR deassertion) */
-#define RXON_FLG_TSF2HOST_MSK           __constant_cpu_to_le32(1 << 15)
+#define RXON_FLG_TSF2HOST_MSK           cpu_to_le32(1 << 15)
 
 /* rx_config filter flags */
 /* accept all data frames */
-#define RXON_FILTER_PROMISC_MSK         __constant_cpu_to_le32(1 << 0)
+#define RXON_FILTER_PROMISC_MSK         cpu_to_le32(1 << 0)
 /* pass control & management to host */
-#define RXON_FILTER_CTL2HOST_MSK        __constant_cpu_to_le32(1 << 1)
+#define RXON_FILTER_CTL2HOST_MSK        cpu_to_le32(1 << 1)
 /* accept multi-cast */
-#define RXON_FILTER_ACCEPT_GRP_MSK      __constant_cpu_to_le32(1 << 2)
+#define RXON_FILTER_ACCEPT_GRP_MSK      cpu_to_le32(1 << 2)
 /* don't decrypt uni-cast frames */
-#define RXON_FILTER_DIS_DECRYPT_MSK     __constant_cpu_to_le32(1 << 3)
+#define RXON_FILTER_DIS_DECRYPT_MSK     cpu_to_le32(1 << 3)
 /* don't decrypt multi-cast frames */
-#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4)
 /* STA is associated */
-#define RXON_FILTER_ASSOC_MSK           __constant_cpu_to_le32(1 << 5)
+#define RXON_FILTER_ASSOC_MSK           cpu_to_le32(1 << 5)
 /* transfer to host non bssid beacons in associated state */
-#define RXON_FILTER_BCON_AWARE_MSK      __constant_cpu_to_le32(1 << 6)
+#define RXON_FILTER_BCON_AWARE_MSK      cpu_to_le32(1 << 6)
 
 /**
  * REPLY_RXON = 0x10 (command, has simple generic response)
@@ -471,9 +477,9 @@
 } __attribute__ ((packed));
 
 /* QoS flags defines */
-#define QOS_PARAM_FLG_UPDATE_EDCA_MSK	__constant_cpu_to_le32(0x01)
-#define QOS_PARAM_FLG_TGN_MSK		__constant_cpu_to_le32(0x02)
-#define QOS_PARAM_FLG_TXOP_TYPE_MSK	__constant_cpu_to_le32(0x10)
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK	cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK		cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK	cpu_to_le32(0x10)
 
 /* Number of Access Categories (AC) (EDCA), queues 0..3 */
 #define AC_NUM                4
@@ -508,27 +514,27 @@
 #define	IWL_STATION_COUNT	32 	/* MAX(3945,4965)*/
 #define	IWL_INVALID_STATION 	255
 
-#define STA_FLG_TX_RATE_MSK		__constant_cpu_to_le32(1 << 2);
-#define STA_FLG_PWR_SAVE_MSK		__constant_cpu_to_le32(1 << 8);
+#define STA_FLG_TX_RATE_MSK		cpu_to_le32(1 << 2);
+#define STA_FLG_PWR_SAVE_MSK		cpu_to_le32(1 << 8);
 
 /* Use in mode field.  1: modify existing entry, 0: add new station entry */
 #define STA_CONTROL_MODIFY_MSK		0x01
 
 /* key flags __le16*/
-#define STA_KEY_FLG_ENCRYPT_MSK	__constant_cpu_to_le16(0x0007)
-#define STA_KEY_FLG_NO_ENC	__constant_cpu_to_le16(0x0000)
-#define STA_KEY_FLG_WEP		__constant_cpu_to_le16(0x0001)
-#define STA_KEY_FLG_CCMP	__constant_cpu_to_le16(0x0002)
-#define STA_KEY_FLG_TKIP	__constant_cpu_to_le16(0x0003)
+#define STA_KEY_FLG_ENCRYPT_MSK	cpu_to_le16(0x0007)
+#define STA_KEY_FLG_NO_ENC	cpu_to_le16(0x0000)
+#define STA_KEY_FLG_WEP		cpu_to_le16(0x0001)
+#define STA_KEY_FLG_CCMP	cpu_to_le16(0x0002)
+#define STA_KEY_FLG_TKIP	cpu_to_le16(0x0003)
 
 #define STA_KEY_FLG_KEYID_POS	8
-#define STA_KEY_FLG_INVALID 	__constant_cpu_to_le16(0x0800)
+#define STA_KEY_FLG_INVALID 	cpu_to_le16(0x0800)
 /* wep key is either from global key (0) or from station info array (1) */
-#define STA_KEY_FLG_WEP_KEY_MAP_MSK  __constant_cpu_to_le16(0x0008)
+#define STA_KEY_FLG_WEP_KEY_MAP_MSK  cpu_to_le16(0x0008)
 
 /* wep key in STA: 5-bytes (0) or 13-bytes (1) */
-#define STA_KEY_FLG_KEY_SIZE_MSK     __constant_cpu_to_le16(0x1000)
-#define STA_KEY_MULTICAST_MSK        __constant_cpu_to_le16(0x4000)
+#define STA_KEY_FLG_KEY_SIZE_MSK     cpu_to_le16(0x1000)
+#define STA_KEY_MULTICAST_MSK        cpu_to_le16(0x4000)
 
 /* Flags indicate whether to modify vs. don't change various station params */
 #define	STA_MODIFY_KEY_MASK		0x01
@@ -666,14 +672,14 @@
 	u8 payload[0];
 } __attribute__ ((packed));
 
-#define RX_RES_STATUS_NO_CRC32_ERROR	__constant_cpu_to_le32(1 << 0)
-#define RX_RES_STATUS_NO_RXE_OVERFLOW	__constant_cpu_to_le32(1 << 1)
+#define RX_RES_STATUS_NO_CRC32_ERROR	cpu_to_le32(1 << 0)
+#define RX_RES_STATUS_NO_RXE_OVERFLOW	cpu_to_le32(1 << 1)
 
-#define RX_RES_PHY_FLAGS_BAND_24_MSK	__constant_cpu_to_le16(1 << 0)
-#define RX_RES_PHY_FLAGS_MOD_CCK_MSK		__constant_cpu_to_le16(1 << 1)
-#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	__constant_cpu_to_le16(1 << 2)
-#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK	__constant_cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK		__constant_cpu_to_le16(0xf0)
+#define RX_RES_PHY_FLAGS_BAND_24_MSK	cpu_to_le16(1 << 0)
+#define RX_RES_PHY_FLAGS_MOD_CCK_MSK		cpu_to_le16(1 << 1)
+#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	cpu_to_le16(1 << 2)
+#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK	cpu_to_le16(1 << 3)
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK		cpu_to_le16(0xf0)
 
 #define RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
 #define RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
@@ -733,57 +739,57 @@
 
 /* 1: Use Request-To-Send protocol before this frame.
  * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
-#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1)
 
 /* 1: Transmit Clear-To-Send to self before this frame.
  * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
  * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
-#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2)
 
 /* 1: Expect ACK from receiving station
  * 0: Don't expect ACK (MAC header's duration field s/b 0)
  * Set this for unicast frames, but not broadcast/multicast. */
-#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
+#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3)
 
 /* 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
  *    Tx command's initial_rate_index indicates first rate to try;
  *    uCode walks through table for additional Tx attempts.
  * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
  *    This rate will be used for all Tx attempts; it will not be scaled. */
-#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
+#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4)
 
 /* 1: Expect immediate block-ack.
  * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
-#define TX_CMD_FLG_IMM_BA_RSP_MASK  __constant_cpu_to_le32(1 << 6)
+#define TX_CMD_FLG_IMM_BA_RSP_MASK  cpu_to_le32(1 << 6)
 
 /* 1: Frame requires full Tx-Op protection.
  * Set this if either RTS or CTS Tx Flag gets set. */
-#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7)
 
 /* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
  * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
-#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
-#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
-#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK cpu_to_le32(1 << 9)
 
 /* 1: Ignore Bluetooth priority for this frame.
  * 0: Delay Tx until Bluetooth device is done (normal usage). */
-#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+#define TX_CMD_FLG_BT_DIS_MSK cpu_to_le32(1 << 12)
 
 /* 1: uCode overrides sequence control field in MAC header.
  * 0: Driver provides sequence control field in MAC header.
  * Set this for management frames, non-QOS data frames, non-unicast frames,
  * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
-#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
+#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13)
 
 /* 1: This frame is non-last MPDU; more fragments are coming.
  * 0: Last fragment, or not using fragmentation. */
-#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
+#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14)
 
 /* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
  * 0: No TSF required in outgoing frame.
  * Set this for transmitting beacons and probe responses. */
-#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
+#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16)
 
 /* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
  *    alignment of frame's payload data field.
@@ -791,10 +797,10 @@
  * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
  * field (but not both).  Driver must align frame data (i.e. data following
  * MAC header) to DWORD boundary. */
-#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
+#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20)
 
 /* HCCA-AP - disable duration overwriting. */
-#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25)
 
 /*
  * TX command security control
@@ -991,7 +997,7 @@
  *
  * 3945 and 4965 support hardware handshake with Bluetooth device on
  * same platform.  Bluetooth device alerts wireless device when it will Tx;
- * wireless device can delay or kill its own Tx to accomodate.
+ * wireless device can delay or kill its own Tx to accommodate.
  */
 struct iwl3945_bt_cmd {
 	u8 flags;
@@ -1158,9 +1164,9 @@
  */
 #define IWL_POWER_VEC_SIZE 5
 
-#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le32(1 << 0)
-#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le32(1 << 2)
-#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le32(1 << 3)
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	cpu_to_le32(1 << 0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK		cpu_to_le32(1 << 2)
+#define IWL_POWER_PCI_PM_MSK			cpu_to_le32(1 << 3)
 struct iwl3945_powertable_cmd {
 	__le32 flags;
 	__le32 rx_data_timeout;
@@ -1278,8 +1284,8 @@
 } __attribute__ ((packed));
 
 #define PROBE_OPTION_MAX        0x4
-#define TX_CMD_LIFE_TIME_INFINITE	__constant_cpu_to_le32(0xFFFFFFFF)
-#define IWL_GOOD_CRC_TH		__constant_cpu_to_le16(1)
+#define TX_CMD_LIFE_TIME_INFINITE	cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH		cpu_to_le16(1)
 #define IWL_MAX_SCAN_SIZE 1024
 
 /*
@@ -1379,7 +1385,7 @@
 } __attribute__ ((packed));
 
 /* Can abort will notify by complete notification with abort status. */
-#define CAN_ABORT_STATUS	__constant_cpu_to_le32(0x1)
+#define CAN_ABORT_STATUS	cpu_to_le32(0x1)
 /* complete notification statuses */
 #define ABORT_STATUS            0x2
 
@@ -1572,8 +1578,8 @@
  * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
  * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
  */
-#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1)	/* see above */
-#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1)	/* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */
 struct iwl3945_statistics_cmd {
 	__le32 configuration_flags;	/* IWL_STATS_CONF_* */
 } __attribute__ ((packed));
@@ -1593,8 +1599,8 @@
  * appropriately so that each notification contains statistics for only the
  * one channel that has just been scanned.
  */
-#define STATISTICS_REPLY_FLG_BAND_24G_MSK         __constant_cpu_to_le32(0x2)
-#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         __constant_cpu_to_le32(0x8)
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK         cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         cpu_to_le32(0x8)
 struct iwl3945_notif_statistics {
 	__le32 flag;
 	struct statistics_rx rx;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-core.h b/drivers/net/wireless/iwlwifi/iwl-3945-core.h
index bc12f97..6f46355 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-core.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -71,9 +71,33 @@
 #define IWL_SKU_G       0x1
 #define IWL_SKU_A       0x2
 
+/**
+ * struct iwl_3945_cfg
+ * @fw_name_pre: Firmware filename prefix. The api version and extension
+ * 	(.ucode) will be added to filename before loading from disk. The
+ * 	filename is constructed as fw_name_pre<api>.ucode.
+ * @ucode_api_max: Highest version of uCode API supported by driver.
+ * @ucode_api_min: Lowest version of uCode API supported by driver.
+ *
+ * We enable the driver to be backward compatible wrt API version. The
+ * driver specifies which APIs it supports (with @ucode_api_max being the
+ * highest and @ucode_api_min the lowest). Firmware will only be loaded if
+ * it has a supported API version. The firmware's API version will be
+ * stored in @iwl_priv, enabling the driver to make runtime changes based
+ * on firmware version used.
+ *
+ * For example,
+ * if (IWL_UCODE_API(priv->ucode_ver) >= 2) {
+ * 	Driver interacts with Firmware API version >= 2.
+ * } else {
+ * 	Driver interacts with Firmware API version 1.
+ * }
+ */
 struct iwl_3945_cfg {
 	const char *name;
-	const char *fw_name;
+	const char *fw_name_pre;
+	const unsigned int ucode_api_max;
+	const unsigned int ucode_api_min;
 	unsigned int sku;
 };
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
index 33016fb..85eb778 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
@@ -21,7 +21,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 644bd9e..94ea0e6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -103,7 +103,6 @@
  * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
  */
 #define IWL_EEPROM_ACCESS_TIMEOUT	5000 /* uSec */
-#define IWL_EEPROM_ACCESS_DELAY		10   /* uSec */
 
 /*
  * Regulatory channel usage flags in EEPROM struct iwl_eeprom_channel.flags.
@@ -321,6 +320,7 @@
 /* RSSR */
 #define FH_RSSR_CTRL            (FH_RSSR_TABLE+0x000)
 #define FH_RSSR_STATUS          (FH_RSSR_TABLE+0x004)
+#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE	(0x01000000)
 /* TCSR */
 #define FH_TCSR(_channel)           (FH_TCSR_TABLE+(_channel)*0x20)
 #define FH_TCSR_CONFIG(_channel)    (FH_TCSR(_channel)+0x00)
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
index b3fe48d..2440fd6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
@@ -21,7 +21,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -53,7 +53,7 @@
  * _iwl3945_read32.)
  *
  * These declarations are *extremely* useful in quickly isolating code deltas
- * which result in misconfiguring of the hardware I/O.  In combination with
+ * which result in misconfiguration of the hardware I/O.  In combination with
  * git-bisect and the IO debug level you can quickly determine the specific
  * commit which breaks the IO sequence to the hardware.
  *
@@ -93,7 +93,7 @@
 	do {
 		if ((_iwl3945_read32(priv, addr) & mask) == (bits & mask))
 			return i;
-		mdelay(10);
+		udelay(10);
 		i += 10;
 	} while (i < timeout);
 
@@ -107,7 +107,7 @@
 	int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout);
 	IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
 		      addr, bits, mask,
-		      unlikely(ret  == -ETIMEDOUT)?"timeout":"", f, l);
+		      unlikely(ret  == -ETIMEDOUT) ? "timeout" : "", f, l);
 	return ret;
 }
 #define iwl3945_poll_bit(priv, addr, bits, mask, timeout) \
@@ -271,16 +271,7 @@
 static inline int _iwl3945_poll_direct_bit(struct iwl3945_priv *priv,
 					   u32 addr, u32 mask, int timeout)
 {
-	int i = 0;
-
-	do {
-		if ((_iwl3945_read_direct32(priv, addr) & mask) == mask)
-			return i;
-		mdelay(10);
-		i += 10;
-	} while (i < timeout);
-
-	return -ETIMEDOUT;
+	return _iwl3945_poll_bit(priv, addr, mask, mask, timeout);
 }
 
 #ifdef CONFIG_IWL3945_DEBUG
@@ -307,6 +298,7 @@
 static inline u32 _iwl3945_read_prph(struct iwl3945_priv *priv, u32 reg)
 {
 	_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+	rmb();
 	return _iwl3945_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
 }
 #ifdef CONFIG_IWL3945_DEBUG
@@ -328,6 +320,7 @@
 {
 	_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WADDR,
 			      ((addr & 0x0000FFFF) | (3 << 24)));
+	wmb();
 	_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
 }
 #ifdef CONFIG_IWL3945_DEBUG
@@ -389,12 +382,14 @@
 static inline u32 iwl3945_read_targ_mem(struct iwl3945_priv *priv, u32 addr)
 {
 	iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
+	rmb();
 	return iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT);
 }
 
 static inline void iwl3945_write_targ_mem(struct iwl3945_priv *priv, u32 addr, u32 val)
 {
 	iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	wmb();
 	iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
 }
 
@@ -402,6 +397,7 @@
 					  u32 len, u32 *values)
 {
 	iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	wmb();
 	for (; 0 < len; len -= sizeof(u32), values++)
 		iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index 705c65b..4c63890 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
index 2fbd126..749ac03 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 6fc5e73..9b60a0c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -63,6 +63,9 @@
 	u8 ibss_sta_added;
 	struct timer_list rate_scale_flush;
 	struct iwl3945_rate_scale_data win[IWL_RATE_COUNT];
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct dentry *rs_sta_dbgfs_stats_table_file;
+#endif
 
 	/* used to be in sta_info */
 	int last_txrate_idx;
@@ -114,9 +117,11 @@
 };
 
 #define IWL_RATE_MAX_WINDOW          62
-#define IWL_RATE_FLUSH        (3*HZ/10)
+#define IWL_RATE_FLUSH       	 (3*HZ)
 #define IWL_RATE_WIN_FLUSH       (HZ/2)
 #define IWL_RATE_HIGH_TH          11520
+#define IWL_SUCCESS_UP_TH	   8960
+#define IWL_SUCCESS_DOWN_TH	  10880
 #define IWL_RATE_MIN_FAILURE_TH       8
 #define IWL_RATE_MIN_SUCCESS_TH       8
 #define IWL_RATE_DECREASE_TH       1920
@@ -203,6 +208,7 @@
 
 #define IWL_RATE_FLUSH_MAX              5000	/* msec */
 #define IWL_RATE_FLUSH_MIN              50	/* msec */
+#define IWL_AVERAGE_PACKETS             1500
 
 static void iwl3945_bg_rate_scale_flush(unsigned long data)
 {
@@ -217,8 +223,6 @@
 
 	spin_lock_irqsave(&rs_sta->lock, flags);
 
-	rs_sta->flush_pending = 0;
-
 	/* Number of packets Rx'd since last time this timer ran */
 	packet_count = (rs_sta->tx_packets - rs_sta->last_tx_packets) + 1;
 
@@ -227,7 +231,6 @@
 	if (unflushed) {
 		duration =
 		    jiffies_to_msecs(jiffies - rs_sta->last_partial_flush);
-/*              duration = jiffies_to_msecs(rs_sta->flush_time); */
 
 		IWL_DEBUG_RATE("Tx'd %d packets in %dms\n",
 			       packet_count, duration);
@@ -239,9 +242,11 @@
 			pps = 0;
 
 		if (pps) {
-			duration = IWL_RATE_FLUSH_MAX / pps;
+			duration = (IWL_AVERAGE_PACKETS * 1000) / pps;
 			if (duration < IWL_RATE_FLUSH_MIN)
 				duration = IWL_RATE_FLUSH_MIN;
+			else if (duration > IWL_RATE_FLUSH_MAX)
+				duration = IWL_RATE_FLUSH_MAX;
 		} else
 			duration = IWL_RATE_FLUSH_MAX;
 
@@ -254,8 +259,10 @@
 			  rs_sta->flush_time);
 
 		rs_sta->last_partial_flush = jiffies;
+	} else {
+		rs_sta->flush_time = IWL_RATE_FLUSH;
+		rs_sta->flush_pending = 0;
 	}
-
 	/* If there weren't any unflushed entries, we don't schedule the timer
 	 * to run again */
 
@@ -275,17 +282,18 @@
  */
 static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta,
 				struct iwl3945_rate_scale_data *window,
-				int success, int retries)
+				int success, int retries, int index)
 {
 	unsigned long flags;
+	s32 fail_count;
 
 	if (!retries) {
 		IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n");
 		return;
 	}
 
+	spin_lock_irqsave(&rs_sta->lock, flags);
 	while (retries--) {
-		spin_lock_irqsave(&rs_sta->lock, flags);
 
 		/* If we have filled up the window then subtract one from the
 		 * success counter if the high-bit is counting toward
@@ -313,14 +321,25 @@
 		/* Tag this window as having been updated */
 		window->stamp = jiffies;
 
-		spin_unlock_irqrestore(&rs_sta->lock, flags);
 	}
+
+	fail_count = window->counter - window->success_counter;
+	if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
+	    (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
+		window->average_tpt = ((window->success_ratio *
+				rs_sta->expected_tpt[index] + 64) / 128);
+	else
+		window->average_tpt = IWL_INV_TPT;
+
+	spin_unlock_irqrestore(&rs_sta->lock, flags);
+
 }
 
-static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband,
+static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
 			 struct ieee80211_sta *sta, void *priv_sta)
 {
 	struct iwl3945_rs_sta *rs_sta = priv_sta;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r;
 	int i;
 
 	IWL_DEBUG_RATE("enter\n");
@@ -330,16 +349,21 @@
 	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
 	 * after assoc.. */
 
-	for (i = IWL_RATE_COUNT - 1; i >= 0; i--) {
+	for (i = sband->n_bitrates - 1; i >= 0; i--) {
 		if (sta->supp_rates[sband->band] & (1 << i)) {
 			rs_sta->last_txrate_idx = i;
 			break;
 		}
 	}
 
+	priv->sta_supp_rates = sta->supp_rates[sband->band];
 	/* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */
-	if (sband->band == IEEE80211_BAND_5GHZ)
+	if (sband->band == IEEE80211_BAND_5GHZ) {
 		rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+		priv->sta_supp_rates = priv->sta_supp_rates <<
+						IWL_FIRST_OFDM_RATE;
+	}
+
 
 	IWL_DEBUG_RATE("leave\n");
 }
@@ -355,12 +379,6 @@
 	return;
 }
 
-static void rs_clear(void *priv)
-{
-	return;
-}
-
-
 static void *rs_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
 {
 	struct iwl3945_rs_sta *rs_sta;
@@ -422,34 +440,6 @@
 }
 
 
-/*
- * get ieee prev rate from rate scale table.
- * for A and B mode we need to overright prev
- * value
- */
-static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate)
-{
-	int next_rate = iwl3945_get_prev_ieee_rate(rate);
-
-	switch (priv->band) {
-	case IEEE80211_BAND_5GHZ:
-		if (rate == IWL_RATE_12M_INDEX)
-			next_rate = IWL_RATE_9M_INDEX;
-		else if (rate == IWL_RATE_6M_INDEX)
-			next_rate = IWL_RATE_6M_INDEX;
-		break;
-/* XXX cannot be invoked in current mac80211 so not a regression
-	case MODE_IEEE80211B:
-		if (rate == IWL_RATE_11M_INDEX_TABLE)
-			next_rate = IWL_RATE_5M_INDEX_TABLE;
-		break;
- */
-	default:
-		break;
-	}
-
-	return next_rate;
-}
 /**
  * rs_tx_status - Update rate control values based on Tx results
  *
@@ -460,7 +450,7 @@
 			 struct ieee80211_sta *sta, void *priv_sta,
 			 struct sk_buff *skb)
 {
-	u8 retries, current_count;
+	s8 retries = 0, current_count;
 	int scale_rate_index, first_index, last_index;
 	unsigned long flags;
 	struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
@@ -469,8 +459,9 @@
 
 	IWL_DEBUG_RATE("enter\n");
 
-	retries = info->status.retry_count;
-	first_index = sband->bitrates[info->tx_rate_idx].hw_value;
+	retries = info->status.rates[0].count;
+
+	first_index = sband->bitrates[info->status.rates[0].idx].hw_value;
 	if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
 		IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index);
 		return;
@@ -496,13 +487,13 @@
 	 * at which the frame was finally transmitted (or failed if no
 	 * ACK)
 	 */
-	while (retries > 0) {
-		if (retries < priv->retry_rate) {
-			current_count = retries;
+	while (retries > 1) {
+		if ((retries - 1) < priv->retry_rate) {
+			current_count = (retries - 1);
 			last_index = scale_rate_index;
 		} else {
 			current_count = priv->retry_rate;
-			last_index = rs_adjust_next_rate(priv,
+			last_index = iwl3945_rs_next_rate(priv,
 							 scale_rate_index);
 		}
 
@@ -510,15 +501,13 @@
 		 * as was used for it (per current_count) */
 		iwl3945_collect_tx_data(rs_sta,
 				    &rs_sta->win[scale_rate_index],
-				    0, current_count);
+				    0, current_count, scale_rate_index);
 		IWL_DEBUG_RATE("Update rate %d for %d retries.\n",
 			       scale_rate_index, current_count);
 
 		retries -= current_count;
 
-		if (retries)
-			scale_rate_index =
-			    rs_adjust_next_rate(priv, scale_rate_index);
+		scale_rate_index = last_index;
 	}
 
 
@@ -529,7 +518,7 @@
 		       "success" : "failure");
 	iwl3945_collect_tx_data(rs_sta,
 			    &rs_sta->win[last_index],
-			    info->flags & IEEE80211_TX_STAT_ACK, 1);
+			    info->flags & IEEE80211_TX_STAT_ACK, 1, last_index);
 
 	/* We updated the rate scale window -- if its been more than
 	 * flush_time since the last run, schedule the flush
@@ -537,9 +526,10 @@
 	spin_lock_irqsave(&rs_sta->lock, flags);
 
 	if (!rs_sta->flush_pending &&
-	    time_after(jiffies, rs_sta->last_partial_flush +
+	    time_after(jiffies, rs_sta->last_flush +
 		       rs_sta->flush_time)) {
 
+		rs_sta->last_partial_flush = jiffies;
 		rs_sta->flush_pending = 1;
 		mod_timer(&rs_sta->rate_scale_flush,
 			  jiffies + rs_sta->flush_time);
@@ -630,10 +620,11 @@
  * rate table and must reference the driver allocated rate table
  *
  */
-static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
-			struct ieee80211_sta *sta, void *priv_sta,
-			struct sk_buff *skb, struct rate_selection *sel)
+static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
+			void *priv_sta,	struct ieee80211_tx_rate_control *txrc)
 {
+	struct ieee80211_supported_band *sband = txrc->sband;
+	struct sk_buff *skb = txrc->skb;
 	u8 low = IWL_RATE_INVALID;
 	u8 high = IWL_RATE_INVALID;
 	u16 high_low;
@@ -649,7 +640,7 @@
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	u16 fc, rate_mask;
 	struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r;
-	DECLARE_MAC_BUF(mac);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
 	IWL_DEBUG_RATE("enter\n");
 
@@ -660,7 +651,7 @@
 	    is_multicast_ether_addr(hdr->addr1) ||
 	    !sta || !priv_sta) {
 		IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
-		sel->rate_idx = rate_lowest_index(sband, sta);
+		info->control.rates[0].idx = rate_lowest_index(sband, sta);
 		return;
 	}
 
@@ -675,8 +666,8 @@
 		u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
 
 		if (sta_id == IWL_INVALID_STATION) {
-			IWL_DEBUG_RATE("LQ: ADD station %s\n",
-				       print_mac(mac, hdr->addr1));
+			IWL_DEBUG_RATE("LQ: ADD station %pm\n",
+				       hdr->addr1);
 			sta_id = iwl3945_add_station(priv,
 				    hdr->addr1, 0, CMD_ASYNC);
 		}
@@ -686,8 +677,13 @@
 
 	spin_lock_irqsave(&rs_sta->lock, flags);
 
+	/* for recent assoc, choose best rate regarding
+	 * to rssi value
+	 */
 	if (rs_sta->start_rate != IWL_RATE_INVALID) {
-		index = rs_sta->start_rate;
+		if (rs_sta->start_rate < index &&
+		   (rate_mask & (1 << rs_sta->start_rate)))
+			index = rs_sta->start_rate;
 		rs_sta->start_rate = IWL_RATE_INVALID;
 	}
 
@@ -697,7 +693,6 @@
 
 	if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) &&
 	     (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) {
-		window->average_tpt = IWL_INV_TPT;
 		spin_unlock_irqrestore(&rs_sta->lock, flags);
 
 		IWL_DEBUG_RATE("Invalid average_tpt on rate %d: "
@@ -711,8 +706,6 @@
 
 	}
 
-	window->average_tpt = ((window->success_ratio *
-				rs_sta->expected_tpt[index] + 64) / 128);
 	current_tpt = window->average_tpt;
 
 	high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask,
@@ -760,13 +753,15 @@
 		}
 	}
 
-	if ((window->success_ratio > IWL_RATE_HIGH_TH) ||
-	    (current_tpt > window->average_tpt)) {
-		IWL_DEBUG_RATE("No action -- success_ratio [%d] > HIGH_TH or "
-			       "current_tpt [%d] > average_tpt [%d]\n",
-			       window->success_ratio,
-			       current_tpt, window->average_tpt);
-		scale_action = 0;
+	if (scale_action == -1) {
+		if (window->success_ratio > IWL_SUCCESS_DOWN_TH)
+			scale_action = 0;
+	} else if (scale_action == 1) {
+		if (window->success_ratio < IWL_SUCCESS_UP_TH) {
+			IWL_DEBUG_RATE("No action -- success_ratio [%d] < "
+			       "SUCCESS UP\n", window->success_ratio);
+			scale_action = 0;
+		}
 	}
 
 	switch (scale_action) {
@@ -793,24 +788,83 @@
 
 	rs_sta->last_txrate_idx = index;
 	if (sband->band == IEEE80211_BAND_5GHZ)
-		sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE;
+		info->control.rates[0].idx = rs_sta->last_txrate_idx -
+				IWL_FIRST_OFDM_RATE;
 	else
-		sel->rate_idx = rs_sta->last_txrate_idx;
+		info->control.rates[0].idx = rs_sta->last_txrate_idx;
 
 	IWL_DEBUG_RATE("leave: %d\n", index);
 }
 
+#ifdef CONFIG_MAC80211_DEBUGFS
+static int iwl3945_open_file_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t iwl3945_sta_dbgfs_stats_table_read(struct file *file,
+						  char __user *user_buf,
+						  size_t count, loff_t *ppos)
+{
+	char buff[1024];
+	int desc = 0;
+	int j;
+	struct iwl3945_rs_sta *lq_sta = file->private_data;
+
+	desc += sprintf(buff + desc, "tx packets=%d last rate index=%d\n"
+			"rate=0x%X flush time %d\n",
+			lq_sta->tx_packets,
+			lq_sta->last_txrate_idx,
+			lq_sta->start_rate, jiffies_to_msecs(lq_sta->flush_time));
+	for (j = 0; j < IWL_RATE_COUNT; j++) {
+		desc += sprintf(buff+desc,
+				"counter=%d success=%d %%=%d\n",
+				lq_sta->win[j].counter,
+				lq_sta->win[j].success_counter,
+				lq_sta->win[j].success_ratio);
+	}
+	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
+	.read = iwl3945_sta_dbgfs_stats_table_read,
+	.open = iwl3945_open_file_generic,
+};
+
+static void iwl3945_add_debugfs(void *priv, void *priv_sta,
+				struct dentry *dir)
+{
+	struct iwl3945_rs_sta *lq_sta = priv_sta;
+
+	lq_sta->rs_sta_dbgfs_stats_table_file =
+		debugfs_create_file("rate_stats_table", 0600, dir,
+		lq_sta, &rs_sta_dbgfs_stats_table_ops);
+
+}
+
+static void iwl3945_remove_debugfs(void *priv, void *priv_sta)
+{
+	struct iwl3945_rs_sta *lq_sta = priv_sta;
+	debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
+}
+#endif
+
 static struct rate_control_ops rs_ops = {
 	.module = NULL,
 	.name = RS_NAME,
 	.tx_status = rs_tx_status,
 	.get_rate = rs_get_rate,
 	.rate_init = rs_rate_init,
-	.clear = rs_clear,
 	.alloc = rs_alloc,
 	.free = rs_free,
 	.alloc_sta = rs_alloc_sta,
 	.free_sta = rs_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+	.add_sta_debugfs = iwl3945_add_debugfs,
+	.remove_sta_debugfs = iwl3945_remove_debugfs,
+#endif
+
 };
 
 void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
@@ -827,13 +881,12 @@
 	rcu_read_lock();
 
 	sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr);
-	psta = (void *) sta->drv_priv;
-	if (!sta || !psta) {
-		IWL_DEBUG_RATE("leave - no private rate data!\n");
+	if (!sta) {
 		rcu_read_unlock();
 		return;
 	}
 
+	psta = (void *) sta->drv_priv;
 	rs_sta = psta->rs_sta;
 
 	spin_lock_irqsave(&rs_sta->lock, flags);
@@ -857,7 +910,6 @@
 		break;
 	}
 
-	rcu_read_unlock();
 	spin_unlock_irqrestore(&rs_sta->lock, flags);
 
 	rssi = priv->last_rx_rssi;
@@ -871,6 +923,7 @@
 	IWL_DEBUG_RATE("leave: rssi %d assign rate index: "
 		       "%d (plcp 0x%x)\n", rssi, rs_sta->start_rate,
 		       iwl3945_rates[rs_sta->start_rate].plcp);
+	rcu_read_unlock();
 }
 
 int iwl3945_rate_control_register(void)
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
index 98b17ae..b5a6613 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 7ca5627..8fdb342 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -200,7 +200,7 @@
  * priv->eeprom  is used to determine if antenna AUX/MAIN are reversed
  * priv->antenna specifies the antenna diversity mode:
  *
- * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself
+ * IWL_ANTENNA_DIVERSITY - NIC selects best antenna by itself
  * IWL_ANTENNA_MAIN      - Force MAIN antenna
  * IWL_ANTENNA_AUX       - Force AUX antenna
  */
@@ -261,6 +261,37 @@
 }
 #endif
 
+/*
+ * get ieee prev rate from rate scale table.
+ * for A and B mode we need to overright prev
+ * value
+ */
+int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate)
+{
+	int next_rate = iwl3945_get_prev_ieee_rate(rate);
+
+	switch (priv->band) {
+	case IEEE80211_BAND_5GHZ:
+		if (rate == IWL_RATE_12M_INDEX)
+			next_rate = IWL_RATE_9M_INDEX;
+		else if (rate == IWL_RATE_6M_INDEX)
+			next_rate = IWL_RATE_6M_INDEX;
+		break;
+	case IEEE80211_BAND_2GHZ:
+		if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) &&
+		    iwl3945_is_associated(priv)) {
+			if (rate == IWL_RATE_11M_INDEX)
+				next_rate = IWL_RATE_5M_INDEX;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return next_rate;
+}
+
 
 /**
  * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
@@ -308,6 +339,7 @@
 	struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
 	u32  status = le32_to_cpu(tx_resp->status);
 	int rate_idx;
+	int fail;
 
 	if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) {
 		IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
@@ -318,9 +350,18 @@
 	}
 
 	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
-	memset(&info->status, 0, sizeof(info->status));
+	ieee80211_tx_info_clear_status(info);
 
-	info->status.retry_count = tx_resp->failure_frame;
+	/* Fill the MRR chain with some info about on-chip retransmissions */
+	rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
+	if (info->band == IEEE80211_BAND_5GHZ)
+		rate_idx -= IWL_FIRST_OFDM_RATE;
+
+	fail = tx_resp->failure_frame;
+
+	info->status.rates[0].idx = rate_idx;
+	info->status.rates[0].count = fail + 1; /* add final attempt */
+
 	/* tx_status->rts_retry_count = tx_resp->failure_rts; */
 	info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
 				IEEE80211_TX_STAT_ACK : 0;
@@ -329,10 +370,6 @@
 			txq_id, iwl3945_get_tx_fail_reason(status), status,
 			tx_resp->rate, tx_resp->failure_frame);
 
-	rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
-	if (info->band == IEEE80211_BAND_5GHZ)
-		rate_idx -= IWL_FIRST_OFDM_RATE;
-	info->tx_rate_idx = rate_idx;
 	IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
 	iwl3945_tx_queue_reclaim(priv, txq_id, index);
 
@@ -756,13 +793,19 @@
 
 u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr)
 {
-	int i;
+	int i, start = IWL_AP_ID;
 	int ret = IWL_INVALID_STATION;
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
+
+	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
+	    (priv->iw_mode == NL80211_IFTYPE_AP))
+		start = IWL_STA_ID;
+
+	if (is_broadcast_ether_addr(addr))
+		return priv->hw_setting.bcast_sta_id;
 
 	spin_lock_irqsave(&priv->sta_lock, flags);
-	for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+	for (i = start; i < priv->hw_setting.max_stations; i++)
 		if ((priv->stations[i].used) &&
 		    (!compare_ether_addr
 		     (priv->stations[i].sta.sta.addr, addr))) {
@@ -770,8 +813,8 @@
 			goto out;
 		}
 
-	IWL_DEBUG_INFO("can not find STA %s (total %d)\n",
-		       print_mac(mac, addr), priv->num_stations);
+	IWL_DEBUG_INFO("can not find STA %pM (total %d)\n",
+		       addr, priv->num_stations);
  out:
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 	return ret;
@@ -1060,9 +1103,8 @@
 		    CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
 
 	iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-	rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
-			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+	rc = iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL,
+			CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 	if (rc < 0) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		IWL_DEBUG_INFO("Failed to init the card\n");
@@ -1243,8 +1285,7 @@
 		IWL_DEBUG_INFO("Card in power save, master is already "
 			       "stopped\n");
 	else {
-		rc = iwl3945_poll_bit(priv, CSR_RESET,
-				  CSR_RESET_REG_FLAG_MASTER_DISABLED,
+		rc = iwl3945_poll_direct_bit(priv, CSR_RESET,
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
 		if (rc < 0) {
 			spin_unlock_irqrestore(&priv->lock, flags);
@@ -1269,9 +1310,8 @@
 
 	iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
-	rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
-			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+	iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL,
+			 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 
 	rc = iwl3945_grab_nic_access(priv);
 	if (!rc) {
@@ -1830,7 +1870,7 @@
 		ref_temp = (s16)priv->eeprom.groups[ch_info->group_index].
 		    temperature;
 
-		/* get power index adjustment based on curr and factory
+		/* get power index adjustment based on current and factory
 		 * temps */
 		delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature,
 							      ref_temp);
@@ -2268,7 +2308,8 @@
 	}
 
 	iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0), 0);
-	rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000);
+	rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS,
+			FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
 	if (rc < 0)
 		IWL_ERROR("Can't stop Rx DMA.\n");
 
@@ -2337,7 +2378,8 @@
 			iwl3945_hw_set_rate_n_flags(iwl3945_rates[i].plcp, 0);
 		table[index].try_cnt = priv->retry_rate;
 		prev_index = iwl3945_get_prev_ieee_rate(i);
-		table[index].next_rate_index = iwl3945_rates[prev_index].table_rs_index;
+		table[index].next_rate_index =
+				iwl3945_rates[prev_index].table_rs_index;
 	}
 
 	switch (priv->band) {
@@ -2345,11 +2387,14 @@
 		IWL_DEBUG_RATE("Select A mode rate scale\n");
 		/* If one of the following CCK rates is used,
 		 * have it fall back to the 6M OFDM rate */
-		for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++)
-			table[i].next_rate_index = iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
+		for (i = IWL_RATE_1M_INDEX_TABLE;
+			i <= IWL_RATE_11M_INDEX_TABLE; i++)
+			table[i].next_rate_index =
+			  iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
 
 		/* Don't fall back to CCK rates */
-		table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = IWL_RATE_9M_INDEX_TABLE;
+		table[IWL_RATE_12M_INDEX_TABLE].next_rate_index =
+						IWL_RATE_9M_INDEX_TABLE;
 
 		/* Don't drop out of OFDM rates */
 		table[IWL_RATE_6M_INDEX_TABLE].next_rate_index =
@@ -2360,11 +2405,20 @@
 		IWL_DEBUG_RATE("Select B/G mode rate scale\n");
 		/* If an OFDM rate is used, have it fall back to the
 		 * 1M CCK rates */
-		for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++)
-			table[i].next_rate_index = iwl3945_rates[IWL_FIRST_CCK_RATE].table_rs_index;
 
-		/* CCK shouldn't fall back to OFDM... */
-		table[IWL_RATE_11M_INDEX_TABLE].next_rate_index = IWL_RATE_5M_INDEX_TABLE;
+		if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) &&
+		    iwl3945_is_associated(priv)) {
+
+			index = IWL_FIRST_CCK_RATE;
+			for (i = IWL_RATE_6M_INDEX_TABLE;
+			     i <= IWL_RATE_54M_INDEX_TABLE; i++)
+				table[i].next_rate_index =
+					iwl3945_rates[index].table_rs_index;
+
+			index = IWL_RATE_11M_INDEX_TABLE;
+			/* CCK shouldn't fall back to OFDM... */
+			table[index].next_rate_index = IWL_RATE_5M_INDEX_TABLE;
+		}
 		break;
 
 	default:
@@ -2428,7 +2482,6 @@
 
 	frame_size = iwl3945_fill_beacon_frame(priv,
 				tx_beacon_cmd->frame,
-				iwl3945_broadcast_addr,
 				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
 
 	BUG_ON(frame_size > MAX_MPDU_SIZE);
@@ -2467,13 +2520,17 @@
 
 static struct iwl_3945_cfg iwl3945_bg_cfg = {
 	.name = "3945BG",
-	.fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode",
+	.fw_name_pre = IWL3945_FW_PRE,
+	.ucode_api_max = IWL3945_UCODE_API_MAX,
+	.ucode_api_min = IWL3945_UCODE_API_MIN,
 	.sku = IWL_SKU_G,
 };
 
 static struct iwl_3945_cfg iwl3945_abg_cfg = {
 	.name = "3945ABG",
-	.fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode",
+	.fw_name_pre = IWL3945_FW_PRE,
+	.ucode_api_max = IWL3945_UCODE_API_MAX,
+	.ucode_api_min = IWL3945_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G,
 };
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index bdd3247..2c0ddc5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -50,11 +50,15 @@
 #include "iwl-3945-debug.h"
 #include "iwl-3945-led.h"
 
-/* Change firmware file name, using "-" and incrementing number,
- *   *only* when uCode interface or architecture changes so that it
- *   is not compatible with earlier drivers.
- * This number will also appear in << 8 position of 1st dword of uCode file */
-#define IWL3945_UCODE_API "-1"
+/* Highest firmware API version supported */
+#define IWL3945_UCODE_API_MAX 2
+
+/* Lowest firmware API version supported */
+#define IWL3945_UCODE_API_MIN 1
+
+#define IWL3945_FW_PRE	"iwlwifi-3945-"
+#define _IWL3945_MODULE_FIRMWARE(api) IWL3945_FW_PRE #api ".ucode"
+#define IWL3945_MODULE_FIRMWARE(api) _IWL3945_MODULE_FIRMWARE(api)
 
 /* Default noise level to report when noise measurement is not available.
  *   This may be because we're:
@@ -401,12 +405,6 @@
 
 #define SCAN_INTERVAL 100
 
-#define MAX_A_CHANNELS  252
-#define MIN_A_CHANNELS  7
-
-#define MAX_B_CHANNELS  14
-#define MIN_B_CHANNELS  1
-
 #define STATUS_HCMD_ACTIVE	0	/* host command in progress */
 #define STATUS_HCMD_SYNC_ACTIVE	1	/* sync host command in progress */
 #define STATUS_INT_ENABLED	2
@@ -472,7 +470,6 @@
 
 /* QoS structures */
 struct iwl3945_qos_info {
-	int qos_enable;
 	int qos_active;
 	union iwl3945_qos_capabity qos_cap;
 	struct iwl3945_qosparam_cmd def_qos_parm;
@@ -505,7 +502,7 @@
 
 /* uCode file layout */
 struct iwl3945_ucode {
-	__le32 ver;		/* major/minor/subminor */
+	__le32 ver;		/* major/minor/API/serial */
 	__le32 inst_size;	/* bytes of runtime instructions */
 	__le32 data_size;	/* bytes of runtime data */
 	__le32 init_size;	/* bytes of initialization instructions */
@@ -587,8 +584,7 @@
 extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv,
 		struct iwl3945_host_cmd *cmd);
 extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
-					struct ieee80211_hdr *hdr,
-					const u8 *dest, int left);
+					struct ieee80211_hdr *hdr,int left);
 extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv,
 					 struct iwl3945_rx_queue *q);
 extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv);
@@ -762,6 +758,8 @@
 	void __iomem *hw_base;
 
 	/* uCode images, save to reload in case of failure */
+	u32 ucode_ver;			/* ucode version, copy of
+					   iwl3945_ucode.ver */
 	struct fw_desc ucode_code;	/* runtime inst */
 	struct fw_desc ucode_data;	/* runtime data original */
 	struct fw_desc ucode_data_backup;	/* runtime data save/restore */
@@ -804,6 +802,8 @@
 	u16 active_rate;
 	u16 active_rate_basic;
 
+	u32 sta_supp_rates;
+
 	u8 call_post_assoc_from_beacon;
 	/* Rate scaling data */
 	s8 data_retry_limit;
@@ -828,8 +828,6 @@
 	unsigned long last_statistics_time;
 
 	/* context information */
-	u8 essid[IW_ESSID_MAX_SIZE];
-	u8 essid_len;
 	u16 rates_mask;
 
 	u32 power_mode;
@@ -888,7 +886,6 @@
 	struct work_struct report_work;
 	struct work_struct request_scan;
 	struct work_struct beacon_update;
-	struct work_struct set_monitor;
 
 	struct tasklet_struct irq_tasklet;
 
@@ -903,9 +900,6 @@
 	s8 user_txpower_limit;
 	s8 max_channel_txpower_limit;
 
-#ifdef CONFIG_PM
-	u32 pm_state[16];
-#endif
 
 #ifdef CONFIG_IWL3945_DEBUG
 	/* debugging info */
@@ -954,6 +948,8 @@
 extern const struct iwl3945_channel_info *iwl3945_get_channel_info(
 	const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel);
 
+extern int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate);
+
 /* Requires full declaration of iwl3945_priv before including */
 #include "iwl-3945-io.h"
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index f4793a6..6649f7b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -71,7 +71,7 @@
 
 #include "iwl-fh.h"
 
-/* EERPROM */
+/* EEPROM */
 #define IWL4965_EEPROM_IMG_SIZE			1024
 
 /*
@@ -84,12 +84,6 @@
 #define IWL_CMD_FIFO_NUM        4
 #define IWL49_FIRST_AMPDU_QUEUE	7
 
-/* Tx rates */
-#define IWL_CCK_RATES 4
-#define IWL_OFDM_RATES 8
-#define IWL_HT_RATES 16
-#define IWL_MAX_RATES  (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES)
-
 /* Time constants */
 #define SHORT_SLOT_TIME 9
 #define LONG_SLOT_TIME 20
@@ -111,7 +105,6 @@
 #define PCI_CFG_CMD_REG_INT_DIS_MSK	0x04
 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
 
-#define TFD_QUEUE_SIZE_MAX      (256)
 
 #define IWL_NUM_SCAN_RATES         (2)
 
@@ -287,13 +280,13 @@
  *     that target txpower.
  *
  *
- * 3)  Determine (EEPROM) calibration subband for the target channel, by
- *     comparing against first and last channels in each subband
+ * 3)  Determine (EEPROM) calibration sub band for the target channel, by
+ *     comparing against first and last channels in each sub band
  *     (see struct iwl4965_eeprom_calib_subband_info).
  *
  *
  * 4)  Linearly interpolate (EEPROM) factory calibration measurement sets,
- *     referencing the 2 factory-measured (sample) channels within the subband.
+ *     referencing the 2 factory-measured (sample) channels within the sub band.
  *
  *     Interpolation is based on difference between target channel's frequency
  *     and the sample channels' frequencies.  Since channel numbers are based
@@ -301,7 +294,7 @@
  *     to interpolating based on channel number differences.
  *
  *     Note that the sample channels may or may not be the channels at the
- *     edges of the subband.  The target channel may be "outside" of the
+ *     edges of the sub band.  The target channel may be "outside" of the
  *     span of the sampled channels.
  *
  *     Driver may choose the pair (for 2 Tx chains) of measurements (see
@@ -345,7 +338,7 @@
  *     "4965 temperature calculation".
  *
  *     If current temperature is higher than factory temperature, driver must
- *     increase gain (lower gain table index), and vice versa.
+ *     increase gain (lower gain table index), and vice verse.
  *
  *     Temperature affects gain differently for different channels:
  *
@@ -815,125 +808,14 @@
  * up to 7 DMA channels (FIFOs).  Each Tx queue is supported by a circular array
  * in DRAM containing 256 Transmit Frame Descriptors (TFDs).
  */
-#define IWL49_MAX_WIN_SIZE	64
-#define IWL49_QUEUE_SIZE	256
 #define IWL49_NUM_FIFOS 	7
 #define IWL49_CMD_FIFO_NUM	4
 #define IWL49_NUM_QUEUES	16
 #define IWL49_NUM_AMPDU_QUEUES	8
 
-/**
- * struct iwl_tfd_frame_data
- *
- * Describes up to 2 buffers containing (contiguous) portions of a Tx frame.
- * Each buffer must be on dword boundary.
- * Up to 10 iwl_tfd_frame_data structures, describing up to 20 buffers,
- * may be filled within a TFD (iwl_tfd_frame).
- *
- * Bit fields in tb1_addr:
- * 31- 0: Tx buffer 1 address bits [31:0]
- *
- * Bit fields in val1:
- * 31-16: Tx buffer 2 address bits [15:0]
- * 15- 4: Tx buffer 1 length (bytes)
- *  3- 0: Tx buffer 1 address bits [32:32]
- *
- * Bit fields in val2:
- * 31-20: Tx buffer 2 length (bytes)
- * 19- 0: Tx buffer 2 address bits [35:16]
- */
-struct iwl_tfd_frame_data {
-	__le32 tb1_addr;
-
-	__le32 val1;
-	/* __le32 ptb1_32_35:4; */
-#define IWL_tb1_addr_hi_POS 0
-#define IWL_tb1_addr_hi_LEN 4
-#define IWL_tb1_addr_hi_SYM val1
-	/* __le32 tb_len1:12; */
-#define IWL_tb1_len_POS 4
-#define IWL_tb1_len_LEN 12
-#define IWL_tb1_len_SYM val1
-	/* __le32 ptb2_0_15:16; */
-#define IWL_tb2_addr_lo16_POS 16
-#define IWL_tb2_addr_lo16_LEN 16
-#define IWL_tb2_addr_lo16_SYM val1
-
-	__le32 val2;
-	/* __le32 ptb2_16_35:20; */
-#define IWL_tb2_addr_hi20_POS 0
-#define IWL_tb2_addr_hi20_LEN 20
-#define IWL_tb2_addr_hi20_SYM val2
-	/* __le32 tb_len2:12; */
-#define IWL_tb2_len_POS 20
-#define IWL_tb2_len_LEN 12
-#define IWL_tb2_len_SYM val2
-} __attribute__ ((packed));
-
 
 /**
- * struct iwl_tfd_frame
- *
- * Transmit Frame Descriptor (TFD)
- *
- * 4965 supports up to 16 Tx queues resident in host DRAM.
- * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM.
- * Both driver and device share these circular buffers, each of which must be
- * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes for 4965.
- *
- * Driver must indicate the physical address of the base of each
- * circular buffer via the 4965's FH_MEM_CBBC_QUEUE registers.
- *
- * Each TFD contains pointer/size information for up to 20 data buffers
- * in host DRAM.  These buffers collectively contain the (one) frame described
- * by the TFD.  Each buffer must be a single contiguous block of memory within
- * itself, but buffers may be scattered in host DRAM.  Each buffer has max size
- * of (4K - 4).  The 4965 concatenates all of a TFD's buffers into a single
- * Tx frame, up to 8 KBytes in size.
- *
- * Bit fields in the control dword (val0):
- * 31-30: # dwords (0-3) of padding required at end of frame for 16-byte bound
- *    29: reserved
- * 28-24: # Transmit Buffer Descriptors in TFD
- * 23- 0: reserved
- *
- * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
- */
-struct iwl_tfd_frame {
-	__le32 val0;
-	/* __le32 rsvd1:24; */
-	/* __le32 num_tbs:5; */
-#define IWL_num_tbs_POS 24
-#define IWL_num_tbs_LEN 5
-#define IWL_num_tbs_SYM val0
-	/* __le32 rsvd2:1; */
-	/* __le32 padding:2; */
-	struct iwl_tfd_frame_data pa[10];
-	__le32 reserved;
-} __attribute__ ((packed));
-
-
-/**
- * struct iwl4965_queue_byte_cnt_entry
- *
- * Byte Count Table Entry
- *
- * Bit fields:
- * 15-12: reserved
- * 11- 0: total to-be-transmitted byte count of frame (does not include command)
- */
-struct iwl4965_queue_byte_cnt_entry {
-	__le16 val;
-	/* __le16 byte_cnt:12; */
-#define IWL_byte_cnt_POS 0
-#define IWL_byte_cnt_LEN 12
-#define IWL_byte_cnt_SYM val
-	/* __le16 rsvd:4; */
-} __attribute__ ((packed));
-
-
-/**
- * struct iwl4965_sched_queue_byte_cnt_tbl
+ * struct iwl4965_schedq_bc_tbl
  *
  * Byte Count table
  *
@@ -947,71 +829,12 @@
  * count table for the chosen Tx queue.  If the TFD index is 0-63, the driver
  * must duplicate the byte count entry in corresponding index 256-319.
  *
- * "dont_care" padding puts each byte count table on a 1024-byte boundary;
+ * padding puts each byte count table on a 1024-byte boundary;
  * 4965 assumes tables are separated by 1024 bytes.
  */
-struct iwl4965_sched_queue_byte_cnt_tbl {
-	struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL49_QUEUE_SIZE +
-						       IWL49_MAX_WIN_SIZE];
-	u8 dont_care[1024 -
-		     (IWL49_QUEUE_SIZE + IWL49_MAX_WIN_SIZE) *
-		     sizeof(__le16)];
+struct iwl4965_scd_bc_tbl {
+	__le16 tfd_offset[TFD_QUEUE_BC_SIZE];
+	u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)];
 } __attribute__ ((packed));
 
-
-/**
- * struct iwl4965_shared - handshake area for Tx and Rx
- *
- * For convenience in allocating memory, this structure combines 2 areas of
- * DRAM which must be shared between driver and 4965.  These do not need to
- * be combined, if better allocation would result from keeping them separate:
- *
- * 1)  The Tx byte count tables occupy 1024 bytes each (16 KBytes total for
- *     16 queues).  Driver uses SCD_DRAM_BASE_ADDR to tell 4965 where to find
- *     the first of these tables.  4965 assumes tables are 1024 bytes apart.
- *
- * 2)  The Rx status (val0 and val1) occupies only 8 bytes.  Driver uses
- *     FH_RSCSR_CHNL0_STTS_WPTR_REG to tell 4965 where to find this area.
- *     Driver reads val0 to determine the latest Receive Buffer Descriptor (RBD)
- *     that has been filled by the 4965.
- *
- * Bit fields val0:
- * 31-12:  Not used
- * 11- 0:  Index of last filled Rx buffer descriptor (4965 writes, driver reads)
- *
- * Bit fields val1:
- * 31- 0:  Not used
- */
-struct iwl4965_shared {
-	struct iwl4965_sched_queue_byte_cnt_tbl
-	 queues_byte_cnt_tbls[IWL49_NUM_QUEUES];
-	__le32 rb_closed;
-
-	/* __le32 rb_closed_stts_rb_num:12; */
-#define IWL_rb_closed_stts_rb_num_POS 0
-#define IWL_rb_closed_stts_rb_num_LEN 12
-#define IWL_rb_closed_stts_rb_num_SYM rb_closed
-	/* __le32 rsrv1:4; */
-	/* __le32 rb_closed_stts_rx_frame_num:12; */
-#define IWL_rb_closed_stts_rx_frame_num_POS 16
-#define IWL_rb_closed_stts_rx_frame_num_LEN 12
-#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed
-	/* __le32 rsrv2:4; */
-
-	__le32 frm_finished;
-	/* __le32 frame_finished_stts_rb_num:12; */
-#define IWL_frame_finished_stts_rb_num_POS 0
-#define IWL_frame_finished_stts_rb_num_LEN 12
-#define IWL_frame_finished_stts_rb_num_SYM frm_finished
-	/* __le32 rsrv3:4; */
-	/* __le32 frame_finished_stts_rx_frame_num:12; */
-#define IWL_frame_finished_stts_rx_frame_num_POS 16
-#define IWL_frame_finished_stts_rx_frame_num_LEN 12
-#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished
-	/* __le32 rsrv4:4; */
-
-	__le32 padding1;  /* so that allocation will be aligned to 16B */
-	__le32 padding2;
-} __attribute__ ((packed));
-
-#endif /* __iwl4965_4965_hw_h__ */
+#endif /* !__iwl_4965_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 9838de5..5a72bc0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -48,18 +48,21 @@
 static int iwl4965_send_tx_power(struct iwl_priv *priv);
 static int iwl4965_hw_get_temperature(const struct iwl_priv *priv);
 
-/* Change firmware file name, using "-" and incrementing number,
- *   *only* when uCode interface or architecture changes so that it
- *   is not compatible with earlier drivers.
- * This number will also appear in << 8 position of 1st dword of uCode file */
-#define IWL4965_UCODE_API "-2"
+/* Highest firmware API version supported */
+#define IWL4965_UCODE_API_MAX 2
+
+/* Lowest firmware API version supported */
+#define IWL4965_UCODE_API_MIN 2
+
+#define IWL4965_FW_PRE "iwlwifi-4965-"
+#define _IWL4965_MODULE_FIRMWARE(api) IWL4965_FW_PRE #api ".ucode"
+#define IWL4965_MODULE_FIRMWARE(api) _IWL4965_MODULE_FIRMWARE(api)
 
 
 /* module parameters */
 static struct iwl_mod_params iwl4965_mod_params = {
 	.num_of_queues = IWL49_NUM_QUEUES,
 	.num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
-	.enable_qos = 1,
 	.amsdu_size_8K = 1,
 	.restart_fw = 1,
 	/* the rest are 0 by default */
@@ -246,7 +249,7 @@
 	iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
 				 priv->ucode_data.len);
 
-	/* Inst bytecount must be last to set up, bit 31 signals uCode
+	/* Inst byte count must be last to set up, bit 31 signals uCode
 	 *   that all new ptr/size info is in place */
 	iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
 				 priv->ucode_code.len | BSM_DRAM_INST_LOAD);
@@ -318,31 +321,13 @@
 /*
  * EEPROM handlers
  */
-
-static int iwl4965_eeprom_check_version(struct iwl_priv *priv)
+static u16 iwl4965_eeprom_calib_version(struct iwl_priv *priv)
 {
-	u16 eeprom_ver;
-	u16 calib_ver;
-
-	eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-
-	calib_ver = iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET);
-
-	if (eeprom_ver < EEPROM_4965_EEPROM_VERSION ||
-	    calib_ver < EEPROM_4965_TX_POWER_VERSION)
-		goto err;
-
-	return 0;
-err:
-	IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
-		  eeprom_ver, EEPROM_4965_EEPROM_VERSION,
-		  calib_ver, EEPROM_4965_TX_POWER_VERSION);
-	return -EINVAL;
-
+	return iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET);
 }
 
 /*
- * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask
+ * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
  * must be called under priv->lock and mac access
  */
 static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask)
@@ -366,9 +351,8 @@
 	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
 	/* wait for clock stabilization */
-	ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
-			   CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-			   CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+	ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+			CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 	if (ret < 0) {
 		IWL_DEBUG_INFO("Failed to init the card\n");
 		goto out;
@@ -414,7 +398,7 @@
 
 	/* L1 is enabled by BIOS */
 	if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
-		/* diable L0S disabled L1A enabled */
+		/* disable L0S disabled L1A enabled */
 		iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
 	else
 		/* L0S enabled L1A disabled */
@@ -442,7 +426,6 @@
 
 static int iwl4965_apm_stop_master(struct iwl_priv *priv)
 {
-	int ret = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -450,17 +433,13 @@
 	/* set stop master bit */
 	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 
-	ret = iwl_poll_bit(priv, CSR_RESET,
-				  CSR_RESET_REG_FLAG_MASTER_DISABLED,
-				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-	if (ret < 0)
-		goto out;
+	iwl_poll_direct_bit(priv, CSR_RESET,
+			CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
 
-out:
 	spin_unlock_irqrestore(&priv->lock, flags);
 	IWL_DEBUG_INFO("stop master\n");
 
-	return ret;
+	return 0;
 }
 
 static void iwl4965_apm_stop(struct iwl_priv *priv)
@@ -496,11 +475,9 @@
 
 	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
-	ret = iwl_poll_bit(priv, CSR_RESET,
-			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);
-
-	if (ret)
+	ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+			CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+	if (ret < 0)
 		goto out;
 
 	udelay(10);
@@ -537,10 +514,10 @@
 	struct iwl_chain_noise_data *data = &(priv->chain_noise_data);
 
 	if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
-		struct iwl4965_calibration_cmd cmd;
+		struct iwl_calib_diff_gain_cmd cmd;
 
 		memset(&cmd, 0, sizeof(cmd));
-		cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+		cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD;
 		cmd.diff_gain_a = 0;
 		cmd.diff_gain_b = 0;
 		cmd.diff_gain_c = 0;
@@ -587,11 +564,11 @@
 
 	/* Differential gain gets sent to uCode only once */
 	if (!data->radio_write) {
-		struct iwl4965_calibration_cmd cmd;
+		struct iwl_calib_diff_gain_cmd cmd;
 		data->radio_write = 1;
 
 		memset(&cmd, 0, sizeof(cmd));
-		cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+		cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD;
 		cmd.diff_gain_a = data->delta_gain_code[0];
 		cmd.diff_gain_b = data->delta_gain_code[1];
 		cmd.diff_gain_c = data->delta_gain_code[2];
@@ -619,10 +596,10 @@
 static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
 			__le32 *tx_flags)
 {
-	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
 		*tx_flags |= TX_CMD_FLG_RTS_MSK;
 		*tx_flags &= ~TX_CMD_FLG_CTS_MSK;
-	} else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+	} else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
 		*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
 		*tx_flags |= TX_CMD_FLG_CTS_MSK;
 	}
@@ -643,7 +620,7 @@
 
 	mutex_lock(&priv->mutex);
 
-	/* Regardless of if we are assocaited, we must reconfigure the
+	/* Regardless of if we are associated, we must reconfigure the
 	 * TX power since frames can be sent on non-radar channels while
 	 * not associated */
 	iwl4965_send_tx_power(priv);
@@ -679,7 +656,7 @@
 	int txq_id = txq->q.id;
 
 	/* Find out whether to activate Tx queue */
-	int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+	int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
 
 	/* Set up and activate */
 	iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id),
@@ -709,9 +686,10 @@
 static int iwl4965_alive_notify(struct iwl_priv *priv)
 {
 	u32 a;
-	int i = 0;
 	unsigned long flags;
 	int ret;
+	int i, chan;
+	u32 reg_val;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -733,8 +711,18 @@
 
 	/* Tel 4965 where to find Tx byte count tables */
 	iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR,
-		(priv->shared_phys +
-		 offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10);
+			priv->scd_bc_tbls.dma >> 10);
+
+	/* Enable DMA channel */
+	for (chan = 0; chan < FH49_TCSR_CHNL_NUM ; chan++)
+		iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+				FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+				FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+	/* Update FH chicken bits */
+	reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
+	iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
+			   reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
 
 	/* Disable chain mode for all queues */
 	iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0);
@@ -766,7 +754,7 @@
 				 (1 << priv->hw_params.max_txq_num) - 1);
 
 	/* Activate all Tx DMA/FIFO channels */
-	priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
+	priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 6));
 
 	iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
 
@@ -822,7 +810,9 @@
 	}
 
 	priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
-	priv->hw_params.first_ampdu_q = IWL49_FIRST_AMPDU_QUEUE;
+	priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM;
+	priv->hw_params.scd_bc_tbls_size =
+			IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl);
 	priv->hw_params.max_stations = IWL4965_STATION_COUNT;
 	priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
 	priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE;
@@ -1650,36 +1640,6 @@
 }
 #endif
 
-static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv)
-{
-	struct iwl4965_shared *s = priv->shared_virt;
-	return le32_to_cpu(s->rb_closed) & 0xFFF;
-}
-
-static int iwl4965_alloc_shared_mem(struct iwl_priv *priv)
-{
-	priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
-					sizeof(struct iwl4965_shared),
-					&priv->shared_phys);
-	if (!priv->shared_virt)
-		return -ENOMEM;
-
-	memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared));
-
-	priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed);
-
-	return 0;
-}
-
-static void iwl4965_free_shared_mem(struct iwl_priv *priv)
-{
-	if (priv->shared_virt)
-		pci_free_consistent(priv->pci_dev,
-				    sizeof(struct iwl4965_shared),
-				    priv->shared_virt,
-				    priv->shared_phys);
-}
-
 /**
  * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
  */
@@ -1687,21 +1647,22 @@
 					    struct iwl_tx_queue *txq,
 					    u16 byte_cnt)
 {
-	int len;
+	struct iwl4965_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
 	int txq_id = txq->q.id;
-	struct iwl4965_shared *shared_data = priv->shared_virt;
+	int write_ptr = txq->q.write_ptr;
+	int len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+	__le16 bc_ent;
 
-	len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+	WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
 
+	bc_ent = cpu_to_le16(len & 0xFFF);
 	/* Set up byte count within first 256 entries */
-	IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
-		       tfd_offset[txq->q.write_ptr], byte_cnt, len);
+	scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
 
 	/* If within first 64 entries, duplicate at end */
-	if (txq->q.write_ptr < IWL49_MAX_WIN_SIZE)
-		IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
-			tfd_offset[IWL49_QUEUE_SIZE + txq->q.write_ptr],
-			byte_cnt, len);
+	if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+		scd_bc_tbl[txq_id].
+			tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
 }
 
 /**
@@ -1956,7 +1917,7 @@
 	ra_tid = BUILD_RAxTID(sta_id, tid);
 
 	/* Modify device's station table to Tx this TID */
-	iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+	iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	ret = iwl_grab_nic_access(priv);
@@ -2037,7 +1998,7 @@
 }
 
 /**
- * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue
+ * iwl4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue
  */
 static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
 				      struct iwl_ht_agg *agg,
@@ -2059,7 +2020,7 @@
 	agg->rate_n_flags = rate_n_flags;
 	agg->bitmap = 0;
 
-	/* # frames attempted by Tx command */
+	/* num frames attempted by Tx command */
 	if (agg->frame_count == 1) {
 		/* Only one frame was attempted; no block-ack will arrive */
 		status = le16_to_cpu(frame_status[0].status);
@@ -2070,9 +2031,9 @@
 				   agg->frame_count, agg->start_idx, idx);
 
 		info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
-		info->status.retry_count = tx_resp->failure_frame;
+		info->status.rates[0].count = tx_resp->failure_frame + 1;
 		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-		info->flags |= iwl_is_tx_success(status)?
+		info->flags |= iwl_is_tx_success(status) ?
 			IEEE80211_TX_STAT_ACK : 0;
 		iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
 		/* FIXME: code repetition end */
@@ -2158,12 +2119,13 @@
 	int txq_id = SEQ_TO_QUEUE(sequence);
 	int index = SEQ_TO_INDEX(sequence);
 	struct iwl_tx_queue *txq = &priv->txq[txq_id];
+	struct ieee80211_hdr *hdr;
 	struct ieee80211_tx_info *info;
 	struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
 	u32  status = le32_to_cpu(tx_resp->u.status);
-	int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
-	__le16 fc;
-	struct ieee80211_hdr *hdr;
+	int tid = MAX_TID_COUNT;
+	int sta_id;
+	int freed;
 	u8 *qc = NULL;
 
 	if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
@@ -2178,8 +2140,7 @@
 	memset(&info->status, 0, sizeof(info->status));
 
 	hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
-	fc = hdr->frame_control;
-	if (ieee80211_is_data_qos(fc)) {
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
 		qc = ieee80211_get_qos_ctl(hdr);
 		tid = qc[0] & 0xf;
 	}
@@ -2194,8 +2155,7 @@
 		const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
 		struct iwl_ht_agg *agg = NULL;
 
-		if (!qc)
-			return;
+		WARN_ON(!qc);
 
 		agg = &priv->stations[sta_id].tid[tid].agg;
 
@@ -2206,54 +2166,49 @@
 			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
 
 		if (txq->q.read_ptr != (scd_ssn & 0xff)) {
-			int freed, ampdu_q;
 			index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
 			IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
 					   "%d index %d\n", scd_ssn , index);
 			freed = iwl_tx_queue_reclaim(priv, txq_id, index);
 			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
 
-			if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
-			    txq_id >= 0 && priv->mac80211_registered &&
-			    agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
-				/* calculate mac80211 ampdu sw queue to wake */
-				ampdu_q = txq_id - IWL49_FIRST_AMPDU_QUEUE +
-					  priv->hw->queues;
+			if (priv->mac80211_registered &&
+			    (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
+			    (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
 				if (agg->state == IWL_AGG_OFF)
 					ieee80211_wake_queue(priv->hw, txq_id);
 				else
-					ieee80211_wake_queue(priv->hw, ampdu_q);
+					ieee80211_wake_queue(priv->hw,
+							     txq->swq_id);
 			}
-			iwl_txq_check_empty(priv, sta_id, tid, txq_id);
 		}
 	} else {
-		info->status.retry_count = tx_resp->failure_frame;
-		info->flags |=
-			iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
+		info->status.rates[0].count = tx_resp->failure_frame + 1;
+		info->flags |= iwl_is_tx_success(status) ?
+					IEEE80211_TX_STAT_ACK : 0;
 		iwl_hwrate_to_tx_control(priv,
 					le32_to_cpu(tx_resp->rate_n_flags),
 					info);
 
-		IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags "
-			     "0x%x retries %d\n", txq_id,
-				iwl_get_tx_fail_reason(status),
-				status, le32_to_cpu(tx_resp->rate_n_flags),
-				tx_resp->failure_frame);
+		IWL_DEBUG_TX_REPLY("TXQ %d status %s (0x%08x) "
+				   "rate_n_flags 0x%x retries %d\n",
+				   txq_id,
+				   iwl_get_tx_fail_reason(status), status,
+				   le32_to_cpu(tx_resp->rate_n_flags),
+				   tx_resp->failure_frame);
 
-		IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
-
-		if (index != -1) {
-		    int freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-		    if (tid != MAX_TID_COUNT)
+		freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+		if (qc && likely(sta_id != IWL_INVALID_STATION))
 			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
-		    if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
-			(txq_id >= 0) && priv->mac80211_registered)
+
+		if (priv->mac80211_registered &&
+		    (iwl_queue_space(&txq->q) > txq->q.low_mark))
 			ieee80211_wake_queue(priv->hw, txq_id);
-		    if (tid != MAX_TID_COUNT)
-			iwl_txq_check_empty(priv, sta_id, tid, txq_id);
-		}
 	}
 
+	if (qc && likely(sta_id != IWL_INVALID_STATION))
+		iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+
 	if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
 		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
 }
@@ -2328,9 +2283,6 @@
 
 static struct iwl_lib_ops iwl4965_lib = {
 	.set_hw_params = iwl4965_hw_set_hw_params,
-	.alloc_shared_mem = iwl4965_alloc_shared_mem,
-	.free_shared_mem = iwl4965_free_shared_mem,
-	.shared_mem_rx_idx = iwl4965_shared_mem_rx_idx,
 	.txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl,
 	.txq_set_sched = iwl4965_txq_set_sched,
 	.txq_agg_enable = iwl4965_txq_agg_enable,
@@ -2347,7 +2299,7 @@
 		.reset = iwl4965_apm_reset,
 		.stop = iwl4965_apm_stop,
 		.config = iwl4965_nic_config,
-		.set_pwr_src = iwl4965_set_pwr_src,
+		.set_pwr_src = iwl_set_pwr_src,
 	},
 	.eeprom_ops = {
 		.regulatory_bands = {
@@ -2362,11 +2314,11 @@
 		.verify_signature  = iwlcore_eeprom_verify_signature,
 		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
 		.release_semaphore = iwlcore_eeprom_release_semaphore,
-		.check_version = iwl4965_eeprom_check_version,
+		.calib_version = iwl4965_eeprom_calib_version,
 		.query_addr = iwlcore_eeprom_query_addr,
 	},
 	.send_tx_power	= iwl4965_send_tx_power,
-	.update_chain_flags = iwl4965_update_chain_flags,
+	.update_chain_flags = iwl_update_chain_flags,
 	.temperature = iwl4965_temperature_calib,
 };
 
@@ -2378,15 +2330,19 @@
 
 struct iwl_cfg iwl4965_agn_cfg = {
 	.name = "4965AGN",
-	.fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode",
+	.fw_name_pre = IWL4965_FW_PRE,
+	.ucode_api_max = IWL4965_UCODE_API_MAX,
+	.ucode_api_min = IWL4965_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
 	.eeprom_size = IWL4965_EEPROM_IMG_SIZE,
+	.eeprom_ver = EEPROM_4965_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
 	.ops = &iwl4965_ops,
 	.mod_params = &iwl4965_mod_params,
 };
 
 /* Module firmware */
-MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode");
+MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX));
 
 module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
 MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
@@ -2394,7 +2350,7 @@
 MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
 module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
 MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(debug, iwl4965_mod_params.debug, int, 0444);
+module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
 module_param_named(
 	disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
@@ -2402,9 +2358,6 @@
 
 module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444);
 MODULE_PARM_DESC(queues_num, "number of hw queues.");
-/* QoS */
-module_param_named(qos_enable, iwl4965_mod_params.enable_qos, int, 0444);
-MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
 /* 11n */
 module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, 0444);
 MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
index c479ee2..82c3859 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -73,69 +73,27 @@
 #define IWL50_RTC_INST_SIZE (IWL50_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
 #define IWL50_RTC_DATA_SIZE (IWL50_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
 
-/* EERPROM */
+/* EEPROM */
 #define IWL_5000_EEPROM_IMG_SIZE			2048
 
-
-#define IWL50_MAX_WIN_SIZE                64
-#define IWL50_QUEUE_SIZE                 256
 #define IWL50_CMD_FIFO_NUM                 7
 #define IWL50_NUM_QUEUES                  20
 #define IWL50_NUM_AMPDU_QUEUES		  10
 #define IWL50_FIRST_AMPDU_QUEUE		  10
 
-#define IWL_sta_id_POS 12
-#define IWL_sta_id_LEN 4
-#define IWL_sta_id_SYM val
-
 /* Fixed (non-configurable) rx data from phy */
 
-/* Base physical address of iwl5000_shared is provided to SCD_DRAM_BASE_ADDR
- * and &iwl5000_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */
-struct iwl5000_sched_queue_byte_cnt_tbl {
-	struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL50_QUEUE_SIZE +
-						       IWL50_MAX_WIN_SIZE];
+/**
+ * struct iwl5000_schedq_bc_tbl scheduler byte count table
+ * 	base physical address of iwl5000_shared
+ * 	is provided to SCD_DRAM_BASE_ADDR
+ * @tfd_offset  0-12 - tx command byte count
+ *	       12-16 - station index
+ */
+struct iwl5000_scd_bc_tbl {
+	__le16 tfd_offset[TFD_QUEUE_BC_SIZE];
 } __attribute__ ((packed));
 
-struct iwl5000_shared {
-	struct iwl5000_sched_queue_byte_cnt_tbl
-	 queues_byte_cnt_tbls[IWL50_NUM_QUEUES];
-	__le32 rb_closed;
-
-	/* __le32 rb_closed_stts_rb_num:12; */
-#define IWL_rb_closed_stts_rb_num_POS 0
-#define IWL_rb_closed_stts_rb_num_LEN 12
-#define IWL_rb_closed_stts_rb_num_SYM rb_closed
-	/* __le32 rsrv1:4; */
-	/* __le32 rb_closed_stts_rx_frame_num:12; */
-#define IWL_rb_closed_stts_rx_frame_num_POS 16
-#define IWL_rb_closed_stts_rx_frame_num_LEN 12
-#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed
-	/* __le32 rsrv2:4; */
-
-	__le32 frm_finished;
-	/* __le32 frame_finished_stts_rb_num:12; */
-#define IWL_frame_finished_stts_rb_num_POS 0
-#define IWL_frame_finished_stts_rb_num_LEN 12
-#define IWL_frame_finished_stts_rb_num_SYM frm_finished
-	/* __le32 rsrv3:4; */
-	/* __le32 frame_finished_stts_rx_frame_num:12; */
-#define IWL_frame_finished_stts_rx_frame_num_POS 16
-#define IWL_frame_finished_stts_rx_frame_num_LEN 12
-#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished
-	/* __le32 rsrv4:4; */
-
-	__le32 padding1;  /* so that allocation will be aligned to 16B */
-	__le32 padding2;
-} __attribute__ ((packed));
-
-/* calibrations defined for 5000 */
-/* defines the order in which results should be sent to the runtime uCode */
-enum iwl5000_calib {
-	IWL5000_CALIB_LO,
-	IWL5000_CALIB_TX_IQ,
-	IWL5000_CALIB_TX_IQ_PERD,
-};
 
 #endif /* __iwl_5000_hw_h__ */
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 5155b8a..66d053d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -44,7 +44,21 @@
 #include "iwl-helpers.h"
 #include "iwl-5000-hw.h"
 
-#define IWL5000_UCODE_API  "-1"
+/* Highest firmware API version supported */
+#define IWL5000_UCODE_API_MAX 1
+#define IWL5150_UCODE_API_MAX 1
+
+/* Lowest firmware API version supported */
+#define IWL5000_UCODE_API_MIN 1
+#define IWL5150_UCODE_API_MIN 1
+
+#define IWL5000_FW_PRE "iwlwifi-5000-"
+#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode"
+#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api)
+
+#define IWL5150_FW_PRE "iwlwifi-5150-"
+#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode"
+#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api)
 
 static const u16 iwl5000_default_queue_to_tx_fifo[] = {
 	IWL_TX_FIFO_AC3,
@@ -59,7 +73,6 @@
 /* FIXME: same implementation as 4965 */
 static int iwl5000_apm_stop_master(struct iwl_priv *priv)
 {
-	int ret = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -67,17 +80,13 @@
 	/* set stop master bit */
 	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 
-	ret = iwl_poll_bit(priv, CSR_RESET,
-				  CSR_RESET_REG_FLAG_MASTER_DISABLED,
+	iwl_poll_direct_bit(priv, CSR_RESET,
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-	if (ret < 0)
-		goto out;
 
-out:
 	spin_unlock_irqrestore(&priv->lock, flags);
 	IWL_DEBUG_INFO("stop master\n");
 
-	return ret;
+	return 0;
 }
 
 
@@ -92,7 +101,7 @@
 	iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
 		    CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
 
-	/* Set FH wait treshold to maximum (HW error during stress W/A) */
+	/* Set FH wait threshold to maximum (HW error during stress W/A) */
 	iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
 
 	/* enable HAP INTA to move device L1a -> L0s */
@@ -106,9 +115,8 @@
 	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
 	/* wait for clock stabilization */
-	ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
-			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+	ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+			CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 	if (ret < 0) {
 		IWL_DEBUG_INFO("Failed to init the card\n");
 		return ret;
@@ -132,7 +140,7 @@
 	return ret;
 }
 
-/* FIXME: this is indentical to 4965 */
+/* FIXME: this is identical to 4965 */
 static void iwl5000_apm_stop(struct iwl_priv *priv)
 {
 	unsigned long flags;
@@ -175,9 +183,8 @@
 	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
 	/* wait for clock stabilization */
-	ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
-			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+	ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+			CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 	if (ret < 0) {
 		IWL_DEBUG_INFO("Failed to init the card\n");
 		goto out;
@@ -217,7 +224,7 @@
 
 	/* L1 is enabled by BIOS */
 	if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
-		/* diable L0S disabled L1A enabled */
+		/* disable L0S disabled L1A enabled */
 		iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
 	else
 		/* L0S enabled L1A disabled */
@@ -291,30 +298,17 @@
 	return (address & ADDRESS_MSK) + (offset << 1);
 }
 
-static int iwl5000_eeprom_check_version(struct iwl_priv *priv)
+static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
 {
-	u16 eeprom_ver;
 	struct iwl_eeprom_calib_hdr {
 		u8 version;
 		u8 pa_type;
 		u16 voltage;
 	} *hdr;
 
-	eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-
 	hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
 							EEPROM_5000_CALIB_ALL);
-
-	if (eeprom_ver < EEPROM_5000_EEPROM_VERSION ||
-	    hdr->version < EEPROM_5000_TX_POWER_VERSION)
-		goto err;
-
-	return 0;
-err:
-	IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
-		  eeprom_ver, EEPROM_5000_EEPROM_VERSION,
-		  hdr->version, EEPROM_5000_TX_POWER_VERSION);
-	return -EINVAL;
+	return hdr->version;
 
 }
 
@@ -348,10 +342,14 @@
 			data->delta_gain_code[1], data->delta_gain_code[2]);
 
 	if (!data->radio_write) {
-		struct iwl5000_calibration_chain_noise_gain_cmd cmd;
+		struct iwl_calib_chain_noise_gain_cmd cmd;
+
 		memset(&cmd, 0, sizeof(cmd));
 
-		cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
+		cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
+		cmd.hdr.first_group = 0;
+		cmd.hdr.groups_num = 1;
+		cmd.hdr.data_valid = 1;
 		cmd.delta_gain_1 = data->delta_gain_code[1];
 		cmd.delta_gain_2 = data->delta_gain_code[2];
 		iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
@@ -373,14 +371,19 @@
 static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
 {
 	struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+	int ret;
 
 	if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
-		struct iwl5000_calibration_chain_noise_reset_cmd cmd;
-
+		struct iwl_calib_chain_noise_reset_cmd cmd;
 		memset(&cmd, 0, sizeof(cmd));
-		cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
-		if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
-			sizeof(cmd), &cmd))
+
+		cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
+		cmd.hdr.first_group = 0;
+		cmd.hdr.groups_num = 1;
+		cmd.hdr.data_valid = 1;
+		ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+					sizeof(cmd), &cmd);
+		if (ret)
 			IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n");
 		data->state = IWL_CHAIN_NOISE_ACCUMULATE;
 		IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
@@ -390,8 +393,8 @@
 static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
 			__le32 *tx_flags)
 {
-	if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
-	    (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
+	if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+	    (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
 		*tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
 	else
 		*tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
@@ -426,31 +429,41 @@
 	return &priv->eeprom[address];
 }
 
+static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv)
+{
+	const s32 volt2temp_coef = -5;
+	u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv,
+						EEPROM_5000_TEMPERATURE);
+	/* offset =  temperate -  voltage / coef */
+	s32 offset = temp_calib[0] - temp_calib[1] / volt2temp_coef;
+	s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - offset;
+	return threshold * volt2temp_coef;
+}
+
 /*
  *  Calibration
  */
-static int iwl5000_send_Xtal_calib(struct iwl_priv *priv)
+static int iwl5000_set_Xtal_calib(struct iwl_priv *priv)
 {
+	struct iwl_calib_xtal_freq_cmd cmd;
 	u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL);
 
-	struct iwl5000_calibration cal_cmd = {
-		.op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD,
-		.data = {
-			(u8)xtal_calib[0],
-			(u8)xtal_calib[1],
-		}
-	};
-
-	return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
-				sizeof(cal_cmd), &cal_cmd);
+	cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
+	cmd.hdr.first_group = 0;
+	cmd.hdr.groups_num = 1;
+	cmd.hdr.data_valid = 1;
+	cmd.cap_pin1 = (u8)xtal_calib[0];
+	cmd.cap_pin2 = (u8)xtal_calib[1];
+	return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL],
+			     (u8 *)&cmd, sizeof(cmd));
 }
 
 static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
 {
-	struct iwl5000_calib_cfg_cmd calib_cfg_cmd;
+	struct iwl_calib_cfg_cmd calib_cfg_cmd;
 	struct iwl_host_cmd cmd = {
 		.id = CALIBRATION_CFG_CMD,
-		.len = sizeof(struct iwl5000_calib_cfg_cmd),
+		.len = sizeof(struct iwl_calib_cfg_cmd),
 		.data = &calib_cfg_cmd,
 	};
 
@@ -467,7 +480,7 @@
 			     struct iwl_rx_mem_buffer *rxb)
 {
 	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw;
+	struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
 	int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
 	int index;
 
@@ -478,14 +491,20 @@
 	 * uCode. iwl_send_calib_results sends them in a row according to their
 	 * index. We sort them here */
 	switch (hdr->op_code) {
-	case IWL5000_PHY_CALIBRATE_LO_CMD:
-		index = IWL5000_CALIB_LO;
+	case IWL_PHY_CALIBRATE_DC_CMD:
+		index = IWL_CALIB_DC;
 		break;
-	case IWL5000_PHY_CALIBRATE_TX_IQ_CMD:
-		index = IWL5000_CALIB_TX_IQ;
+	case IWL_PHY_CALIBRATE_LO_CMD:
+		index = IWL_CALIB_LO;
 		break;
-	case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD:
-		index = IWL5000_CALIB_TX_IQ_PERD;
+	case IWL_PHY_CALIBRATE_TX_IQ_CMD:
+		index = IWL_CALIB_TX_IQ;
+		break;
+	case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD:
+		index = IWL_CALIB_TX_IQ_PERD;
+		break;
+	case IWL_PHY_CALIBRATE_BASE_BAND_CMD:
+		index = IWL_CALIB_BASE_BAND;
 		break;
 	default:
 		IWL_ERROR("Unknown calibration notification %d\n",
@@ -535,7 +554,7 @@
 
 	iwl_write_direct32(priv,
 		FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
-		(iwl_get_dma_hi_address(phy_addr)
+		(iwl_get_dma_hi_addr(phy_addr)
 			<< FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
 
 	iwl_write_direct32(priv,
@@ -547,7 +566,7 @@
 	iwl_write_direct32(priv,
 		FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
 		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE	|
-		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
+		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE	|
 		FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
 	iwl_release_nic_access(priv);
@@ -561,14 +580,13 @@
 {
 	int ret = 0;
 
-	ret = iwl5000_load_section(
-		priv, inst_image, RTC_INST_LOWER_BOUND);
+	ret = iwl5000_load_section(priv, inst_image, RTC_INST_LOWER_BOUND);
 	if (ret)
 		return ret;
 
 	IWL_DEBUG_INFO("INST uCode section being loaded...\n");
 	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
-				priv->ucode_write_complete, 5 * HZ);
+					priv->ucode_write_complete, 5 * HZ);
 	if (ret == -ERESTARTSYS) {
 		IWL_ERROR("Could not load the INST uCode section due "
 			"to interrupt\n");
@@ -682,7 +700,7 @@
 					int tx_fifo_id, int scd_retry)
 {
 	int txq_id = txq->q.id;
-	int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+	int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
 
 	iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
 			(active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
@@ -710,9 +728,10 @@
 static int iwl5000_alive_notify(struct iwl_priv *priv)
 {
 	u32 a;
-	int i = 0;
 	unsigned long flags;
 	int ret;
+	int i, chan;
+	u32 reg_val;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
@@ -734,11 +753,21 @@
 		iwl_write_targ_mem(priv, a, 0);
 
 	iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
-		(priv->shared_phys +
-		 offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10);
+		       priv->scd_bc_tbls.dma >> 10);
+
+	/* Enable DMA channel */
+	for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++)
+		iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+				FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+				FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+	/* Update FH chicken bits */
+	reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
+	iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
+			   reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
 	iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL,
-		IWL50_SCD_QUEUECHAIN_SEL_ALL(
-			priv->hw_params.max_txq_num));
+		IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
 	iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0);
 
 	/* initiate the queues */
@@ -765,6 +794,7 @@
 	priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
 
 	iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+
 	/* map qos queues to fifos one-to-one */
 	for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
 		int ac = iwl5000_default_queue_to_tx_fifo[i];
@@ -784,10 +814,8 @@
 
 	iwl5000_send_wimax_coex(priv);
 
-	iwl5000_send_Xtal_calib(priv);
-
-	if (priv->ucode_type == UCODE_RT)
-		iwl_send_calib_results(priv);
+	iwl5000_set_Xtal_calib(priv);
+	iwl_send_calib_results(priv);
 
 	return 0;
 }
@@ -802,7 +830,9 @@
 	}
 
 	priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
-	priv->hw_params.first_ampdu_q = IWL50_FIRST_AMPDU_QUEUE;
+	priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
+	priv->hw_params.scd_bc_tbls_size =
+			IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl);
 	priv->hw_params.max_stations = IWL5000_STATION_COUNT;
 	priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
 	priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
@@ -814,10 +844,14 @@
 
 	switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
 	case CSR_HW_REV_TYPE_5100:
+		priv->hw_params.tx_chains_num = 1;
+		priv->hw_params.rx_chains_num = 2;
+		priv->hw_params.valid_tx_ant = ANT_B;
+		priv->hw_params.valid_rx_ant = ANT_AB;
+		break;
 	case CSR_HW_REV_TYPE_5150:
 		priv->hw_params.tx_chains_num = 1;
 		priv->hw_params.rx_chains_num = 2;
-		/* FIXME: move to ANT_A, ANT_B, ANT_C enum */
 		priv->hw_params.valid_tx_ant = ANT_A;
 		priv->hw_params.valid_rx_ant = ANT_AB;
 		break;
@@ -840,43 +874,36 @@
 	case CSR_HW_REV_TYPE_5150:
 		/* 5150 wants in Kelvin */
 		priv->hw_params.ct_kill_threshold =
-				CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
+				iwl5150_get_ct_threshold(priv);
 		break;
 	}
 
-	return 0;
-}
+	/* Set initial calibration set */
+	switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+	case CSR_HW_REV_TYPE_5100:
+	case CSR_HW_REV_TYPE_5300:
+	case CSR_HW_REV_TYPE_5350:
+		priv->hw_params.calib_init_cfg =
+			BIT(IWL_CALIB_XTAL)		|
+			BIT(IWL_CALIB_LO)		|
+			BIT(IWL_CALIB_TX_IQ) 		|
+			BIT(IWL_CALIB_TX_IQ_PERD)	|
+			BIT(IWL_CALIB_BASE_BAND);
+		break;
+	case CSR_HW_REV_TYPE_5150:
+		priv->hw_params.calib_init_cfg =
+			BIT(IWL_CALIB_DC)		|
+			BIT(IWL_CALIB_LO)		|
+			BIT(IWL_CALIB_TX_IQ) 		|
+			BIT(IWL_CALIB_BASE_BAND);
 
-static int iwl5000_alloc_shared_mem(struct iwl_priv *priv)
-{
-	priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
-					sizeof(struct iwl5000_shared),
-					&priv->shared_phys);
-	if (!priv->shared_virt)
-		return -ENOMEM;
+		break;
+	}
 
-	memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared));
-
-	priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed);
 
 	return 0;
 }
 
-static void iwl5000_free_shared_mem(struct iwl_priv *priv)
-{
-	if (priv->shared_virt)
-		pci_free_consistent(priv->pci_dev,
-				    sizeof(struct iwl5000_shared),
-				    priv->shared_virt,
-				    priv->shared_phys);
-}
-
-static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv)
-{
-	struct iwl5000_shared *s = priv->shared_virt;
-	return le32_to_cpu(s->rb_closed) & 0xFFF;
-}
-
 /**
  * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
  */
@@ -884,16 +911,18 @@
 					    struct iwl_tx_queue *txq,
 					    u16 byte_cnt)
 {
-	struct iwl5000_shared *shared_data = priv->shared_virt;
+	struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
+	int write_ptr = txq->q.write_ptr;
 	int txq_id = txq->q.id;
 	u8 sec_ctl = 0;
-	u8 sta = 0;
-	int len;
+	u8 sta_id = 0;
+	u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+	__le16 bc_ent;
 
-	len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+	WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
 
 	if (txq_id != IWL_CMD_QUEUE_NUM) {
-		sta = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
+		sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
 		sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
 
 		switch (sec_ctl & TX_CMD_SEC_MSK) {
@@ -909,40 +938,35 @@
 		}
 	}
 
-	IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
-		       tfd_offset[txq->q.write_ptr], byte_cnt, len);
+	bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
 
-	IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
-		       tfd_offset[txq->q.write_ptr], sta_id, sta);
+	scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
 
-	if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) {
-		IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
-			tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr],
-			byte_cnt, len);
-		IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
-			tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr],
-			sta_id, sta);
-	}
+	if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+		scd_bc_tbl[txq_id].
+			tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
 }
 
 static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
 					   struct iwl_tx_queue *txq)
 {
+	struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
 	int txq_id = txq->q.id;
-	struct iwl5000_shared *shared_data = priv->shared_virt;
-	u8 sta = 0;
+	int read_ptr = txq->q.read_ptr;
+	u8 sta_id = 0;
+	__le16 bc_ent;
+
+	WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
 
 	if (txq_id != IWL_CMD_QUEUE_NUM)
-		sta = txq->cmd[txq->q.read_ptr]->cmd.tx.sta_id;
+		sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
 
-	shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr].
-					val = cpu_to_le16(1 | (sta << 12));
+	bc_ent =  cpu_to_le16(1 | (sta_id << 12));
+	scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
 
-	if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) {
-		shared_data->queues_byte_cnt_tbls[txq_id].
-			tfd_offset[IWL50_QUEUE_SIZE + txq->q.read_ptr].
-				val = cpu_to_le16(1 | (sta << 12));
-	}
+	if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+		scd_bc_tbl[txq_id].
+			tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] =  bc_ent;
 }
 
 static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
@@ -996,7 +1020,7 @@
 	ra_tid = BUILD_RAxTID(sta_id, tid);
 
 	/* Modify device's station table to Tx this TID */
-	iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+	iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	ret = iwl_grab_nic_access(priv);
@@ -1089,7 +1113,7 @@
 
 
 /*
- * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask
+ * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
  * must be called under priv->lock and mac access
  */
 static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
@@ -1136,10 +1160,10 @@
 				   agg->frame_count, agg->start_idx, idx);
 
 		info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
-		info->status.retry_count = tx_resp->failure_frame;
+		info->status.rates[0].count = tx_resp->failure_frame + 1;
 		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-		info->flags |= iwl_is_tx_success(status)?
-			IEEE80211_TX_STAT_ACK : 0;
+		info->flags |= iwl_is_tx_success(status) ?
+					IEEE80211_TX_STAT_ACK : 0;
 		iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
 
 		/* FIXME: code repetition end */
@@ -1225,9 +1249,9 @@
 	struct ieee80211_tx_info *info;
 	struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
 	u32  status = le16_to_cpu(tx_resp->status.status);
-	int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
-	struct ieee80211_hdr *hdr;
-	u8 *qc = NULL;
+	int tid;
+	int sta_id;
+	int freed;
 
 	if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
 		IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
@@ -1240,25 +1264,13 @@
 	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
 	memset(&info->status, 0, sizeof(info->status));
 
-	hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
-	if (ieee80211_is_data_qos(hdr->frame_control)) {
-		qc = ieee80211_get_qos_ctl(hdr);
-		tid = qc[0] & 0xf;
-	}
-
-	sta_id = iwl_get_ra_sta_id(priv, hdr);
-	if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
-		IWL_ERROR("Station not known\n");
-		return;
-	}
+	tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
+	sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;
 
 	if (txq->sched_retry) {
 		const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp);
 		struct iwl_ht_agg *agg = NULL;
 
-		if (!qc)
-			return;
-
 		agg = &priv->stations[sta_id].tid[tid].agg;
 
 		iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
@@ -1268,58 +1280,58 @@
 			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
 
 		if (txq->q.read_ptr != (scd_ssn & 0xff)) {
-			int freed, ampdu_q;
 			index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
-			IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
-					   "%d index %d\n", scd_ssn , index);
+			IWL_DEBUG_TX_REPLY("Retry scheduler reclaim "
+					"scd_ssn=%d idx=%d txq=%d swq=%d\n",
+					scd_ssn , index, txq_id, txq->swq_id);
+
 			freed = iwl_tx_queue_reclaim(priv, txq_id, index);
 			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
 
-			if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
-			    txq_id >= 0 && priv->mac80211_registered &&
-			    agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
-				/* calculate mac80211 ampdu sw queue to wake */
-				ampdu_q = txq_id - IWL50_FIRST_AMPDU_QUEUE +
-					  priv->hw->queues;
+			if (priv->mac80211_registered &&
+			    (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
+			    (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
 				if (agg->state == IWL_AGG_OFF)
 					ieee80211_wake_queue(priv->hw, txq_id);
 				else
-					ieee80211_wake_queue(priv->hw, ampdu_q);
+					ieee80211_wake_queue(priv->hw,
+							     txq->swq_id);
 			}
-			iwl_txq_check_empty(priv, sta_id, tid, txq_id);
 		}
 	} else {
-		info->status.retry_count = tx_resp->failure_frame;
-		info->flags =
-			iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
+		BUG_ON(txq_id != txq->swq_id);
+
+		info->status.rates[0].count = tx_resp->failure_frame + 1;
+		info->flags |= iwl_is_tx_success(status) ?
+					IEEE80211_TX_STAT_ACK : 0;
 		iwl_hwrate_to_tx_control(priv,
 					le32_to_cpu(tx_resp->rate_n_flags),
 					info);
 
-		IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags "
-			     "0x%x retries %d\n", txq_id,
-				iwl_get_tx_fail_reason(status),
-				status, le32_to_cpu(tx_resp->rate_n_flags),
-				tx_resp->failure_frame);
+		IWL_DEBUG_TX_REPLY("TXQ %d status %s (0x%08x) rate_n_flags "
+				   "0x%x retries %d\n",
+				   txq_id,
+				   iwl_get_tx_fail_reason(status), status,
+				   le32_to_cpu(tx_resp->rate_n_flags),
+				   tx_resp->failure_frame);
 
-		IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
-		if (index != -1) {
-		    int freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-		    if (tid != MAX_TID_COUNT)
+		freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+		if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
 			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
-		    if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
-			(txq_id >= 0) && priv->mac80211_registered)
+
+		if (priv->mac80211_registered &&
+		    (iwl_queue_space(&txq->q) > txq->q.low_mark))
 			ieee80211_wake_queue(priv->hw, txq_id);
-		    if (tid != MAX_TID_COUNT)
-			iwl_txq_check_empty(priv, sta_id, tid, txq_id);
-		}
 	}
 
+	if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
+		iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+
 	if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
 		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
 }
 
-/* Currently 5000 is the supperset of everything */
+/* Currently 5000 is the superset of everything */
 static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
 {
 	return len;
@@ -1466,9 +1478,6 @@
 
 static struct iwl_lib_ops iwl5000_lib = {
 	.set_hw_params = iwl5000_hw_set_hw_params,
-	.alloc_shared_mem = iwl5000_alloc_shared_mem,
-	.free_shared_mem = iwl5000_free_shared_mem,
-	.shared_mem_rx_idx = iwl5000_shared_mem_rx_idx,
 	.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
 	.txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
 	.txq_set_sched = iwl5000_txq_set_sched,
@@ -1482,13 +1491,13 @@
 	.alive_notify = iwl5000_alive_notify,
 	.send_tx_power = iwl5000_send_tx_power,
 	.temperature = iwl5000_temperature,
-	.update_chain_flags = iwl4965_update_chain_flags,
+	.update_chain_flags = iwl_update_chain_flags,
 	.apm_ops = {
 		.init =	iwl5000_apm_init,
 		.reset = iwl5000_apm_reset,
 		.stop = iwl5000_apm_stop,
 		.config = iwl5000_nic_config,
-		.set_pwr_src = iwl4965_set_pwr_src,
+		.set_pwr_src = iwl_set_pwr_src,
 	},
 	.eeprom_ops = {
 		.regulatory_bands = {
@@ -1503,7 +1512,7 @@
 		.verify_signature  = iwlcore_eeprom_verify_signature,
 		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
 		.release_semaphore = iwlcore_eeprom_release_semaphore,
-		.check_version	= iwl5000_eeprom_check_version,
+		.calib_version	= iwl5000_eeprom_calib_version,
 		.query_addr = iwl5000_eeprom_query_addr,
 	},
 };
@@ -1517,7 +1526,6 @@
 static struct iwl_mod_params iwl50_mod_params = {
 	.num_of_queues = IWL50_NUM_QUEUES,
 	.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-	.enable_qos = 1,
 	.amsdu_size_8K = 1,
 	.restart_fw = 1,
 	/* the rest are 0 by default */
@@ -1526,50 +1534,84 @@
 
 struct iwl_cfg iwl5300_agn_cfg = {
 	.name = "5300AGN",
-	.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+	.fw_name_pre = IWL5000_FW_PRE,
+	.ucode_api_max = IWL5000_UCODE_API_MAX,
+	.ucode_api_min = IWL5000_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
 	.ops = &iwl5000_ops,
 	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
 	.mod_params = &iwl50_mod_params,
 };
 
 struct iwl_cfg iwl5100_bg_cfg = {
 	.name = "5100BG",
-	.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+	.fw_name_pre = IWL5000_FW_PRE,
+	.ucode_api_max = IWL5000_UCODE_API_MAX,
+	.ucode_api_min = IWL5000_UCODE_API_MIN,
 	.sku = IWL_SKU_G,
 	.ops = &iwl5000_ops,
 	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
 	.mod_params = &iwl50_mod_params,
 };
 
 struct iwl_cfg iwl5100_abg_cfg = {
 	.name = "5100ABG",
-	.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+	.fw_name_pre = IWL5000_FW_PRE,
+	.ucode_api_max = IWL5000_UCODE_API_MAX,
+	.ucode_api_min = IWL5000_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G,
 	.ops = &iwl5000_ops,
 	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
 	.mod_params = &iwl50_mod_params,
 };
 
 struct iwl_cfg iwl5100_agn_cfg = {
 	.name = "5100AGN",
-	.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+	.fw_name_pre = IWL5000_FW_PRE,
+	.ucode_api_max = IWL5000_UCODE_API_MAX,
+	.ucode_api_min = IWL5000_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
 	.ops = &iwl5000_ops,
 	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
 	.mod_params = &iwl50_mod_params,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
 	.name = "5350AGN",
-	.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+	.fw_name_pre = IWL5000_FW_PRE,
+	.ucode_api_max = IWL5000_UCODE_API_MAX,
+	.ucode_api_min = IWL5000_UCODE_API_MIN,
 	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
 	.ops = &iwl5000_ops,
 	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
 	.mod_params = &iwl50_mod_params,
 };
 
-MODULE_FIRMWARE("iwlwifi-5000" IWL5000_UCODE_API ".ucode");
+struct iwl_cfg iwl5150_agn_cfg = {
+	.name = "5150AGN",
+	.fw_name_pre = IWL5150_FW_PRE,
+	.ucode_api_max = IWL5150_UCODE_API_MAX,
+	.ucode_api_min = IWL5150_UCODE_API_MIN,
+	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+	.ops = &iwl5000_ops,
+	.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
+	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+	.mod_params = &iwl50_mod_params,
+};
+
+MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
 
 module_param_named(disable50, iwl50_mod_params.disable, int, 0444);
 MODULE_PARM_DESC(disable50,
@@ -1577,12 +1619,10 @@
 module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
 MODULE_PARM_DESC(swcrypto50,
 		  "using software crypto engine (default 0 [hardware])\n");
-module_param_named(debug50, iwl50_mod_params.debug, int, 0444);
+module_param_named(debug50, iwl50_mod_params.debug, uint, 0444);
 MODULE_PARM_DESC(debug50, "50XX debug output mask");
 module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
 MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
-module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444);
-MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality");
 module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);
 MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality");
 module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c
new file mode 100644
index 0000000..b8137ee
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c
@@ -0,0 +1,108 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <net/mac80211.h>
+#include "iwl-dev.h"
+#include "iwl-debug.h"
+#include "iwl-commands.h"
+
+
+/**
+ * iwl_check_rxon_cmd - validate RXON structure is valid
+ *
+ * NOTE:  This is really only useful during development and can eventually
+ * be #ifdef'd out once the driver is stable and folks aren't actively
+ * making changes
+ */
+int iwl_agn_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
+{
+	int error = 0;
+	int counter = 1;
+
+	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+		error |= le32_to_cpu(rxon->flags &
+				(RXON_FLG_TGJ_NARROW_BAND_MSK |
+				 RXON_FLG_RADAR_DETECT_MSK));
+		if (error)
+			IWL_WARNING("check 24G fields %d | %d\n",
+				    counter++, error);
+	} else {
+		error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
+				0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
+		if (error)
+			IWL_WARNING("check 52 fields %d | %d\n",
+				    counter++, error);
+		error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
+		if (error)
+			IWL_WARNING("check 52 CCK %d | %d\n",
+				    counter++, error);
+	}
+	error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
+	if (error)
+		IWL_WARNING("check mac addr %d | %d\n", counter++, error);
+
+	/* make sure basic rates 6Mbps and 1Mbps are supported */
+	error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
+		  ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
+	if (error)
+		IWL_WARNING("check basic rate %d | %d\n", counter++, error);
+
+	error |= (le16_to_cpu(rxon->assoc_id) > 2007);
+	if (error)
+		IWL_WARNING("check assoc id %d | %d\n", counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
+	if (error)
+		IWL_WARNING("check CCK and short slot %d | %d\n",
+			    counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
+	if (error)
+		IWL_WARNING("check CCK & auto detect %d | %d\n",
+			    counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+			RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
+	if (error)
+		IWL_WARNING("check TGG and auto detect %d | %d\n",
+			    counter++, error);
+
+	if (error)
+		IWL_WARNING("Tuning to channel %d\n",
+			    le16_to_cpu(rxon->channel));
+
+	if (error) {
+		IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n");
+		return -1;
+	}
+	return 0;
+}
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index e2a58e4..f3f1792 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -38,7 +38,6 @@
 #include "iwl-dev.h"
 #include "iwl-sta.h"
 #include "iwl-core.h"
-#include "iwl-helpers.h"
 
 #define RS_NAME "iwl-agn-rs"
 
@@ -188,7 +187,7 @@
  * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
  * "G" is the only table that supports CCK (the first 4 rates).
  */
-/*FIXME:RS:need to spearate tables for MIMO2/MIMO3*/
+/*FIXME:RS:need to separate tables for MIMO2/MIMO3*/
 static s32 expected_tpt_A[IWL_RATE_COUNT] = {
 	0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
 };
@@ -281,10 +280,9 @@
 	u32 time_diff;
 	s32 index;
 	struct iwl_traffic_load *tl = NULL;
-	__le16 fc = hdr->frame_control;
 	u8 tid;
 
-	if (ieee80211_is_data_qos(fc)) {
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
 		u8 *qc = ieee80211_get_qos_ctl(hdr);
 		tid = qc[0] & 0xf;
 	} else
@@ -357,11 +355,9 @@
 				      struct iwl_lq_sta *lq_data, u8 tid,
 				      struct ieee80211_sta *sta)
 {
-	DECLARE_MAC_BUF(mac);
-
 	if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
-		IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n",
-				print_mac(mac, sta->addr), tid);
+		IWL_DEBUG_HT("Starting Tx agg: STA: %pM tid: %d\n",
+				sta->addr, tid);
 		ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid);
 	}
 }
@@ -775,7 +771,7 @@
 	int status;
 	u8 retries;
 	int rs_index, index = 0;
-	struct iwl_lq_sta *lq_sta;
+	struct iwl_lq_sta *lq_sta = priv_sta;
 	struct iwl_link_quality_cmd *table;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
@@ -787,12 +783,12 @@
 	struct iwl_scale_tbl_info tbl_type;
 	struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
 	u8 active_index = 0;
-	__le16 fc = hdr->frame_control;
 	s32 tpt = 0;
 
 	IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n");
 
-	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    is_multicast_ether_addr(hdr->addr1))
 		return;
 
 	/* This packet was aggregated but doesn't carry rate scale info */
@@ -800,13 +796,11 @@
 	    !(info->flags & IEEE80211_TX_STAT_AMPDU))
 		return;
 
-	retries = info->status.retry_count;
+	retries = info->status.rates[0].count - 1;
 
 	if (retries > 15)
 		retries = 15;
 
-	lq_sta = (struct iwl_lq_sta *)priv_sta;
-
 	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
 	    !lq_sta->ibss_sta_added)
 		goto out;
@@ -832,21 +826,20 @@
 	if (priv->band == IEEE80211_BAND_5GHZ)
 		rs_index -= IWL_FIRST_OFDM_RATE;
 
-	if ((info->tx_rate_idx < 0) ||
-	    (tbl_type.is_SGI ^
-		!!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) ||
-	    (tbl_type.is_fat ^
-		!!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) ||
-	    (tbl_type.is_dup ^
-		!!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) ||
-	    (tbl_type.ant_type ^ info->antenna_sel_tx) ||
-	    (!!(tx_rate & RATE_MCS_HT_MSK) ^
-		!!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) ||
-	    (!!(tx_rate & RATE_MCS_GF_MSK) ^
-		!!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) ||
+	if ((info->status.rates[0].idx < 0) ||
+	    (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) ||
+	    (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
+	    (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) ||
+	    (tbl_type.ant_type != info->antenna_sel_tx) ||
+	    (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) ||
+	    (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
 	    (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
-	     hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) {
+	     hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) {
 		IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
+		/* the last LQ command could failed so the LQ in ucode not
+		 * the same in driver sync up
+		 */
+		iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
 		goto out;
 	}
 
@@ -1135,11 +1128,10 @@
 	s32 rate;
 	s8 is_green = lq_sta->is_green;
 
-	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
-	    !sta->ht_info.ht_supported)
+	if (!conf->ht.enabled || !sta->ht_cap.ht_supported)
 		return -1;
 
-	if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
+	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
 						== WLAN_HT_CAP_SM_PS_STATIC)
 		return -1;
 
@@ -1203,8 +1195,7 @@
 	u8 is_green = lq_sta->is_green;
 	s32 rate;
 
-	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
-	    !sta->ht_info.ht_supported)
+	if (!conf->ht.enabled || !sta->ht_cap.ht_supported)
 		return -1;
 
 	IWL_DEBUG_RATE("LQ: try to switch to SISO\n");
@@ -1684,7 +1675,6 @@
 	int high_tpt = IWL_INVALID_VALUE;
 	u32 fail_count;
 	s8 scale_action = 0;
-	__le16 fc;
 	u16 rate_mask;
 	u8 update_lq = 0;
 	struct iwl_scale_tbl_info *tbl, *tbl1;
@@ -1699,13 +1689,12 @@
 
 	IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
 
-	fc = hdr->frame_control;
-	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
-		/* Send management frames and broadcast/multicast data using
-		 * lowest rate. */
-		/* TODO: this could probably be improved.. */
+	/* Send management frames and broadcast/multicast data using
+	 * lowest rate. */
+	/* TODO: this could probably be improved.. */
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    is_multicast_ether_addr(hdr->addr1))
 		return;
-	}
 
 	if (!sta || !lq_sta)
 		return;
@@ -2003,9 +1992,8 @@
 		 * stay with best antenna legacy modulation for a while
 		 * before next round of mode comparisons. */
 		tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
-		if (is_legacy(tbl1->lq_type) &&
-		   (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) &&
-		    (lq_sta->action_counter >= 1)) {
+		if (is_legacy(tbl1->lq_type) && !conf->ht.enabled &&
+		    lq_sta->action_counter >= 1) {
 			lq_sta->action_counter = 0;
 			IWL_DEBUG_RATE("LQ: STAY in legacy table\n");
 			rs_set_stay_in_table(priv, 1, lq_sta);
@@ -2081,15 +2069,13 @@
 	if ((i < 0) || (i >= IWL_RATE_COUNT))
 		i = 0;
 
-	/* FIXME:RS: This is also wrong in 4965 */
 	rate = iwl_rates[i].plcp;
-	rate |= RATE_MCS_ANT_B_MSK;
-	rate &= ~RATE_MCS_ANT_A_MSK;
+	tbl->ant_type = first_antenna(valid_tx_ant);
+	rate |= tbl->ant_type << RATE_MCS_ANT_POS;
 
 	if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
 		rate |= RATE_MCS_CCK_MSK;
 
-	tbl->ant_type = ANT_B;
 	rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx);
 	if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
 	    rs_toggle_antenna(valid_tx_ant, &rate, tbl);
@@ -2103,40 +2089,38 @@
 	return;
 }
 
-static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
-			struct ieee80211_sta *sta, void *priv_sta,
-			struct sk_buff *skb, struct rate_selection *sel)
+static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
+			struct ieee80211_tx_rate_control *txrc)
 {
 
-	int i;
+	struct sk_buff *skb = txrc->skb;
+	struct ieee80211_supported_band *sband = txrc->sband;
 	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
 	struct ieee80211_conf *conf = &priv->hw->conf;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	__le16 fc;
-	struct iwl_lq_sta *lq_sta;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct iwl_lq_sta *lq_sta = priv_sta;
+	int rate_idx;
 
 	IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
 
 	/* Send management frames and broadcast/multicast data using lowest
 	 * rate. */
-	fc = hdr->frame_control;
-	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
-	    !sta || !priv_sta) {
-		sel->rate_idx = rate_lowest_index(sband, sta);
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    is_multicast_ether_addr(hdr->addr1) || !sta || !lq_sta) {
+		info->control.rates[0].idx = rate_lowest_index(sband, sta);
 		return;
 	}
 
-	lq_sta = (struct iwl_lq_sta *)priv_sta;
-	i = lq_sta->last_txrate_idx;
+	rate_idx  = lq_sta->last_txrate_idx;
 
 	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
 	    !lq_sta->ibss_sta_added) {
 		u8 sta_id = iwl_find_station(priv, hdr->addr1);
-		DECLARE_MAC_BUF(mac);
 
 		if (sta_id == IWL_INVALID_STATION) {
-			IWL_DEBUG_RATE("LQ: ADD station %s\n",
-				       print_mac(mac, hdr->addr1));
+			IWL_DEBUG_RATE("LQ: ADD station %pM\n",
+				       hdr->addr1);
 			sta_id = iwl_add_station_flags(priv, hdr->addr1,
 							0, CMD_ASYNC, NULL);
 		}
@@ -2148,14 +2132,12 @@
 		}
 	}
 
-	if ((i < 0) || (i > IWL_RATE_COUNT)) {
-		sel->rate_idx = rate_lowest_index(sband, sta);
-		return;
-	}
+	if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT)
+		rate_idx = rate_lowest_index(sband, sta);
+	else if (sband->band == IEEE80211_BAND_5GHZ)
+		rate_idx -= IWL_FIRST_OFDM_RATE;
 
-	if (sband->band == IEEE80211_BAND_5GHZ)
-		i -= IWL_FIRST_OFDM_RATE;
-	sel->rate_idx = i;
+	info->control.rates[0].idx = rate_idx;
 }
 
 static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
@@ -2189,6 +2171,7 @@
 	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
 	struct ieee80211_conf *conf = &priv->hw->conf;
 	struct iwl_lq_sta *lq_sta = priv_sta;
+	u16 mask_bit = 0;
 
 	lq_sta->flush_timer = 0;
 	lq_sta->supp_rates = sta->supp_rates[sband->band];
@@ -2205,15 +2188,12 @@
 	lq_sta->ibss_sta_added = 0;
 	if (priv->iw_mode == NL80211_IFTYPE_AP) {
 		u8 sta_id = iwl_find_station(priv, sta->addr);
-		DECLARE_MAC_BUF(mac);
 
 		/* for IBSS the call are from tasklet */
-		IWL_DEBUG_RATE("LQ: ADD station %s\n",
-			     print_mac(mac, sta->addr));
+		IWL_DEBUG_RATE("LQ: ADD station %pM\n", sta->addr);
 
 		if (sta_id == IWL_INVALID_STATION) {
-			IWL_DEBUG_RATE("LQ: ADD station %s\n",
-				       print_mac(mac, sta->addr));
+			IWL_DEBUG_RATE("LQ: ADD station %pM\n", sta->addr);
 			sta_id = iwl_add_station_flags(priv, sta->addr,
 							0, CMD_ASYNC, NULL);
 		}
@@ -2225,16 +2205,6 @@
 		priv->assoc_station_added = 1;
 	}
 
-	/* Find highest tx rate supported by hardware and destination station */
-	lq_sta->last_txrate_idx = 3;
-	for (i = 0; i < sband->n_bitrates; i++)
-		if (sta->supp_rates[sband->band] & BIT(i))
-			lq_sta->last_txrate_idx = i;
-
-	/* For MODE_IEEE80211A, skip over cck rates in global rate table */
-	if (sband->band == IEEE80211_BAND_5GHZ)
-		lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
-
 	lq_sta->is_dup = 0;
 	lq_sta->is_green = rs_use_green(priv, conf);
 	lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
@@ -2244,19 +2214,19 @@
 	 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
 	 * supp_rates[] does not; shift to convert format, force 9 MBits off.
 	 */
-	lq_sta->active_siso_rate = conf->ht_conf.supp_mcs_set[0] << 1;
-	lq_sta->active_siso_rate |= conf->ht_conf.supp_mcs_set[0] & 0x1;
+	lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1;
+	lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1;
 	lq_sta->active_siso_rate &= ~((u16)0x2);
 	lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
 
 	/* Same here */
-	lq_sta->active_mimo2_rate = conf->ht_conf.supp_mcs_set[1] << 1;
-	lq_sta->active_mimo2_rate |= conf->ht_conf.supp_mcs_set[1] & 0x1;
+	lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1;
+	lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1;
 	lq_sta->active_mimo2_rate &= ~((u16)0x2);
 	lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
 
-	lq_sta->active_mimo3_rate = conf->ht_conf.supp_mcs_set[2] << 1;
-	lq_sta->active_mimo3_rate |= conf->ht_conf.supp_mcs_set[2] & 0x1;
+	lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1;
+	lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1;
 	lq_sta->active_mimo3_rate &= ~((u16)0x2);
 	lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
 
@@ -2265,7 +2235,7 @@
 		     lq_sta->active_mimo2_rate,
 		     lq_sta->active_mimo3_rate);
 
-	/* These values will be overriden later */
+	/* These values will be overridden later */
 	lq_sta->lq.general_params.single_stream_ant_msk = ANT_A;
 	lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
 
@@ -2273,6 +2243,17 @@
 	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
 	lq_sta->drv = priv;
 
+	/* Find highest tx rate supported by hardware and destination station */
+	mask_bit = sta->supp_rates[sband->band] & lq_sta->active_legacy_rate;
+	lq_sta->last_txrate_idx = 3;
+	for (i = 0; i < sband->n_bitrates; i++)
+		if (mask_bit & BIT(i))
+			lq_sta->last_txrate_idx = i;
+
+	/* For MODE_IEEE80211A, skip over cck rates in global rate table */
+	if (sband->band == IEEE80211_BAND_5GHZ)
+		lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+
 	rs_initialize_lq(priv, conf, sta, lq_sta);
 }
 
@@ -2405,19 +2386,6 @@
 	return;
 }
 
-static void rs_clear(void *priv_rate)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_priv *priv = (struct iwl_priv *) priv_rate;
-
-	IWL_DEBUG_RATE("enter\n");
-
-	/* TODO - add rate scale state reset */
-
-	IWL_DEBUG_RATE("leave\n");
-#endif /* CONFIG_IWLWIFI_DEBUG */
-}
-
 static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
 			void *priv_sta)
 {
@@ -2552,7 +2520,7 @@
 	for (i = 0; i < LQ_SIZE; i++) {
 		desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
 				"rate=0x%X\n",
-				lq_sta->active_tbl == i?"*":"x",
+				lq_sta->active_tbl == i ? "*" : "x",
 				lq_sta->lq_info[i].lq_type,
 				lq_sta->lq_info[i].is_SGI,
 				lq_sta->lq_info[i].is_fat,
@@ -2605,7 +2573,6 @@
 	.tx_status = rs_tx_status,
 	.get_rate = rs_get_rate,
 	.rate_init = rs_rate_init,
-	.clear = rs_clear,
 	.alloc = rs_alloc,
 	.free = rs_free,
 	.alloc_sta = rs_alloc_sta,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index d148d73..78ee83a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -229,7 +229,7 @@
 #define IWL_MIMO2_SWITCH_SISO_C         4
 #define IWL_MIMO2_SWITCH_GI             5
 
-/*FIXME:RS:add posible acctions for MIMO3*/
+/*FIXME:RS:add possible actions for MIMO3*/
 
 #define IWL_ACTION_LIMIT		3	/* # possible actions */
 
@@ -284,7 +284,17 @@
 		!!((mask) & ANT_C);
 }
 
-static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
+static inline u8 first_antenna(u8 mask)
+{
+	if (mask & ANT_A)
+		return ANT_A;
+	if (mask & ANT_B)
+		return ANT_B;
+	return ANT_C;
+}
+
+
+static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
 {
 	u8 rate = iwl_rates[rate_index].prev_ieee;
 
@@ -294,11 +304,11 @@
 }
 
 /**
- * iwl4965_rate_control_register - Register the rate control algorithm callbacks
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
  *
  * Since the rate control algorithm is hardware specific, there is no need
  * or reason to place it as a stand alone module.  The driver can call
- * iwl4965_rate_control_register in order to register the rate control callbacks
+ * iwl_rate_control_register in order to register the rate control callbacks
  * with the mac80211 subsystem.  This should be performed prior to calling
  * ieee80211_register_hw
  *
@@ -306,7 +316,7 @@
 extern int iwlagn_rate_control_register(void);
 
 /**
- * iwl4965_rate_control_unregister - Unregister the rate control callbacks
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
  *
  * This should be called after calling ieee80211_unregister_hw, but before
  * the driver is unloaded.
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index c4c0371..5da6b35 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -83,7 +83,7 @@
 
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
 MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("iwl4965");
 
@@ -96,7 +96,7 @@
 
 
 
-static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
 {
 	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
 
@@ -108,79 +108,6 @@
 }
 
 /**
- * iwl4965_check_rxon_cmd - validate RXON structure is valid
- *
- * NOTE:  This is really only useful during development and can eventually
- * be #ifdef'd out once the driver is stable and folks aren't actively
- * making changes
- */
-static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
-{
-	int error = 0;
-	int counter = 1;
-
-	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
-		error |= le32_to_cpu(rxon->flags &
-				(RXON_FLG_TGJ_NARROW_BAND_MSK |
-				 RXON_FLG_RADAR_DETECT_MSK));
-		if (error)
-			IWL_WARNING("check 24G fields %d | %d\n",
-				    counter++, error);
-	} else {
-		error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
-				0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
-		if (error)
-			IWL_WARNING("check 52 fields %d | %d\n",
-				    counter++, error);
-		error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
-		if (error)
-			IWL_WARNING("check 52 CCK %d | %d\n",
-				    counter++, error);
-	}
-	error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
-	if (error)
-		IWL_WARNING("check mac addr %d | %d\n", counter++, error);
-
-	/* make sure basic rates 6Mbps and 1Mbps are supported */
-	error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
-		  ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
-	if (error)
-		IWL_WARNING("check basic rate %d | %d\n", counter++, error);
-
-	error |= (le16_to_cpu(rxon->assoc_id) > 2007);
-	if (error)
-		IWL_WARNING("check assoc id %d | %d\n", counter++, error);
-
-	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
-			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
-	if (error)
-		IWL_WARNING("check CCK and short slot %d | %d\n",
-			    counter++, error);
-
-	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
-			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
-	if (error)
-		IWL_WARNING("check CCK & auto detect %d | %d\n",
-			    counter++, error);
-
-	error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
-			RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
-	if (error)
-		IWL_WARNING("check TGG and auto detect %d | %d\n",
-			    counter++, error);
-
-	if (error)
-		IWL_WARNING("Tuning to channel %d\n",
-			    le16_to_cpu(rxon->channel));
-
-	if (error) {
-		IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n");
-		return -1;
-	}
-	return 0;
-}
-
-/**
  * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
  * @priv: staging_rxon is compared to active_rxon
  *
@@ -228,18 +155,17 @@
 }
 
 /**
- * iwl4965_commit_rxon - commit staging_rxon to hardware
+ * iwl_commit_rxon - commit staging_rxon to hardware
  *
  * The RXON command in staging_rxon is committed to the hardware and
  * the active_rxon structure is updated with the new data.  This
  * function correctly transitions out of the RXON_ASSOC_MSK state if
  * a HW tune is required based on the RXON structure changes.
  */
-static int iwl4965_commit_rxon(struct iwl_priv *priv)
+static int iwl_commit_rxon(struct iwl_priv *priv)
 {
 	/* cast away the const for active_rxon in this function */
 	struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
-	DECLARE_MAC_BUF(mac);
 	int ret;
 	bool new_assoc =
 		!!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
@@ -253,14 +179,14 @@
 	 * 5000, but will not damage 4965 */
 	priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
 
-	ret = iwl4965_check_rxon_cmd(&priv->staging_rxon);
+	ret = iwl_agn_check_rxon_cmd(&priv->staging_rxon);
 	if (ret) {
 		IWL_ERROR("Invalid RXON configuration.  Not committing.\n");
 		return -EINVAL;
 	}
 
 	/* If we don't need to send a full RXON, we can use
-	 * iwl4965_rxon_assoc_cmd which is used to reconfigure filter
+	 * iwl_rxon_assoc_cmd which is used to reconfigure filter
 	 * and other flags for the current radio configuration. */
 	if (!iwl_full_rxon_required(priv)) {
 		ret = iwl_send_rxon_assoc(priv);
@@ -300,12 +226,12 @@
 	IWL_DEBUG_INFO("Sending RXON\n"
 		       "* with%s RXON_FILTER_ASSOC_MSK\n"
 		       "* channel = %d\n"
-		       "* bssid = %s\n",
+		       "* bssid = %pM\n",
 		       (new_assoc ? "" : "out"),
 		       le16_to_cpu(priv->staging_rxon.channel),
-		       print_mac(mac, priv->staging_rxon.bssid_addr));
+		       priv->staging_rxon.bssid_addr);
 
-	iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+	iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
 
 	/* Apply the new configuration
 	 * RXON unassoc clears the station table in uCode, send it before
@@ -375,16 +301,16 @@
 	return 0;
 }
 
-void iwl4965_update_chain_flags(struct iwl_priv *priv)
+void iwl_update_chain_flags(struct iwl_priv *priv)
 {
 
 	iwl_set_rxon_chain(priv);
-	iwl4965_commit_rxon(priv);
+	iwl_commit_rxon(priv);
 }
 
-static int iwl4965_send_bt_config(struct iwl_priv *priv)
+static int iwl_send_bt_config(struct iwl_priv *priv)
 {
-	struct iwl4965_bt_cmd bt_cmd = {
+	struct iwl_bt_cmd bt_cmd = {
 		.flags = 3,
 		.lead_time = 0xAA,
 		.max_kill = 1,
@@ -393,7 +319,7 @@
 	};
 
 	return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-				sizeof(struct iwl4965_bt_cmd), &bt_cmd);
+				sizeof(struct iwl_bt_cmd), &bt_cmd);
 }
 
 static void iwl_clear_free_frames(struct iwl_priv *priv)
@@ -445,7 +371,7 @@
 
 static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
 					  struct ieee80211_hdr *hdr,
-					  const u8 *dest, int left)
+					  int left)
 {
 	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
 	    ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
@@ -460,16 +386,16 @@
 	return priv->ibss_beacon->len;
 }
 
-static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv)
+static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
 {
 	int i;
 	int rate_mask;
 
 	/* Set rate mask*/
 	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
-		rate_mask = priv->active_rate_basic & 0xF;
+		rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK;
 	else
-		rate_mask = priv->active_rate_basic & 0xFF0;
+		rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK;
 
 	/* Find lowest valid rate */
 	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
@@ -485,7 +411,7 @@
 		return IWL_RATE_6M_PLCP;
 }
 
-static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
+static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
 				       struct iwl_frame *frame, u8 rate)
 {
 	struct iwl_tx_beacon_cmd *tx_beacon_cmd;
@@ -498,7 +424,6 @@
 	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
 	frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
-				iwl_bcast_addr,
 				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
 
 	BUG_ON(frame_size > MAX_MPDU_SIZE);
@@ -517,7 +442,7 @@
 
 	return sizeof(*tx_beacon_cmd) + frame_size;
 }
-static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
+static int iwl_send_beacon_cmd(struct iwl_priv *priv)
 {
 	struct iwl_frame *frame;
 	unsigned int frame_size;
@@ -532,9 +457,9 @@
 		return -ENOMEM;
 	}
 
-	rate = iwl4965_rate_get_lowest_plcp(priv);
+	rate = iwl_rate_get_lowest_plcp(priv);
 
-	frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate);
+	frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
 
 	rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
 			      &frame->u.cmd[0]);
@@ -550,20 +475,33 @@
  *
  ******************************************************************************/
 
-static void iwl4965_ht_conf(struct iwl_priv *priv,
+static void iwl_ht_conf(struct iwl_priv *priv,
 			    struct ieee80211_bss_conf *bss_conf)
 {
-	struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf;
-	struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf;
+	struct ieee80211_sta_ht_cap *ht_conf;
 	struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+	struct ieee80211_sta *sta;
 
 	IWL_DEBUG_MAC80211("enter: \n");
 
-	iwl_conf->is_ht = bss_conf->assoc_ht;
-
 	if (!iwl_conf->is_ht)
 		return;
 
+
+	/*
+	 * It is totally wrong to base global information on something
+	 * that is valid only when associated, alas, this driver works
+	 * that way and I don't know how to fix it.
+	 */
+
+	rcu_read_lock();
+	sta = ieee80211_find_sta(priv->hw, priv->bssid);
+	if (!sta) {
+		rcu_read_unlock();
+		return;
+	}
+	ht_conf = &sta->ht_cap;
+
 	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
 		iwl_conf->sgf |= HT_SHORT_GI_20MHZ;
 	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
@@ -574,29 +512,36 @@
 		!!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
 
 	iwl_conf->supported_chan_width =
-		!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
-	iwl_conf->extension_chan_offset =
-		ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
+		!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+
+	/*
+	 * XXX: The HT configuration needs to be moved into iwl_mac_config()
+	 *	to be done there correctly.
+	 */
+
+	iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+	if (priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40MINUS)
+		iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+	else if(priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40PLUS)
+		iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+
 	/* If no above or below channel supplied disable FAT channel */
-	if (iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_ABOVE &&
-	    iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_BELOW) {
-		iwl_conf->extension_chan_offset = IEEE80211_HT_IE_CHA_SEC_NONE;
+	if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
+	    iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW)
 		iwl_conf->supported_chan_width = 0;
-	}
 
 	iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
 
-	memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
+	memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
 
-	iwl_conf->control_channel = ht_bss_conf->primary_channel;
-	iwl_conf->tx_chan_width =
-		!!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
+	iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0;
 	iwl_conf->ht_protection =
-		ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
+		bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
 	iwl_conf->non_GF_STA_present =
-		!!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
+		!!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
 
-	IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel);
+	rcu_read_unlock();
+
 	IWL_DEBUG_MAC80211("leave\n");
 }
 
@@ -608,9 +553,6 @@
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
-	if (!priv->qos_data.qos_enable)
-		return;
-
 	priv->qos_data.def_qos_parm.qos_flags = 0;
 
 	if (priv->qos_data.qos_cap.q_AP.queue_request &&
@@ -637,23 +579,22 @@
 
 #define MAX_UCODE_BEACON_INTERVAL	4096
 
-static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val)
+static u16 iwl_adjust_beacon_interval(u16 beacon_val)
 {
 	u16 new_val = 0;
 	u16 beacon_factor = 0;
 
-	beacon_factor =
-	    (beacon_val + MAX_UCODE_BEACON_INTERVAL)
-		/ MAX_UCODE_BEACON_INTERVAL;
+	beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL)
+					/ MAX_UCODE_BEACON_INTERVAL;
 	new_val = beacon_val / beacon_factor;
 
-	return cpu_to_le16(new_val);
+	return new_val;
 }
 
-static void iwl4965_setup_rxon_timing(struct iwl_priv *priv)
+static void iwl_setup_rxon_timing(struct iwl_priv *priv)
 {
-	u64 interval_tm_unit;
-	u64 tsf, result;
+	u64 tsf;
+	s32 interval_tm, rem;
 	unsigned long flags;
 	struct ieee80211_conf *conf = NULL;
 	u16 beacon_int = 0;
@@ -661,49 +602,32 @@
 	conf = ieee80211_get_hw_conf(priv->hw);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp >> 32);
-	priv->rxon_timing.timestamp.dw[0] =
-				cpu_to_le32(priv->timestamp & 0xFFFFFFFF);
-
+	priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
 	priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
 
-	tsf = priv->timestamp;
-
-	beacon_int = priv->beacon_int;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	if (priv->iw_mode == NL80211_IFTYPE_STATION) {
-		if (beacon_int == 0) {
-			priv->rxon_timing.beacon_interval = cpu_to_le16(100);
-			priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
-		} else {
-			priv->rxon_timing.beacon_interval =
-				cpu_to_le16(beacon_int);
-			priv->rxon_timing.beacon_interval =
-			    iwl4965_adjust_beacon_interval(
-				le16_to_cpu(priv->rxon_timing.beacon_interval));
-		}
-
+		beacon_int = iwl_adjust_beacon_interval(priv->beacon_int);
 		priv->rxon_timing.atim_window = 0;
 	} else {
-		priv->rxon_timing.beacon_interval =
-			iwl4965_adjust_beacon_interval(conf->beacon_int);
+		beacon_int = iwl_adjust_beacon_interval(conf->beacon_int);
+
 		/* TODO: we need to get atim_window from upper stack
 		 * for now we set to 0 */
 		priv->rxon_timing.atim_window = 0;
 	}
 
-	interval_tm_unit =
-		(le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
-	result = do_div(tsf, interval_tm_unit);
-	priv->rxon_timing.beacon_init_val =
-	    cpu_to_le32((u32) ((u64) interval_tm_unit - result));
+	priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
 
-	IWL_DEBUG_ASSOC
-	    ("beacon interval %d beacon timer %d beacon tim %d\n",
-		le16_to_cpu(priv->rxon_timing.beacon_interval),
-		le32_to_cpu(priv->rxon_timing.beacon_init_val),
-		le16_to_cpu(priv->rxon_timing.atim_window));
+	tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
+	interval_tm = beacon_int * 1024;
+	rem = do_div(tsf, interval_tm);
+	priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	IWL_DEBUG_ASSOC("beacon interval %d beacon timer %d beacon tim %d\n",
+			le16_to_cpu(priv->rxon_timing.beacon_interval),
+			le32_to_cpu(priv->rxon_timing.beacon_init_val),
+			le16_to_cpu(priv->rxon_timing.atim_window));
 }
 
 static void iwl_set_flags_for_band(struct iwl_priv *priv,
@@ -715,7 +639,7 @@
 		      | RXON_FLG_CCK_MSK);
 		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
 	} else {
-		/* Copied from iwl4965_post_associate() */
+		/* Copied from iwl_post_associate() */
 		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
 			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
 		else
@@ -733,13 +657,13 @@
 /*
  * initialize rxon structure with default values from eeprom
  */
-static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
+static void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
 {
 	const struct iwl_channel_info *ch_info;
 
 	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
 
-	switch (priv->iw_mode) {
+	switch (mode) {
 	case NL80211_IFTYPE_AP:
 		priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
 		break;
@@ -762,7 +686,7 @@
 		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
 		break;
 	default:
-		IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode);
+		IWL_ERROR("Unsupported interface type %d\n", mode);
 		break;
 	}
 
@@ -808,11 +732,9 @@
 	iwl_set_rxon_chain(priv);
 }
 
-static int iwl4965_set_mode(struct iwl_priv *priv, int mode)
+static int iwl_set_mode(struct iwl_priv *priv, int mode)
 {
-	priv->iw_mode = mode;
-
-	iwl4965_connection_init_rx_config(priv);
+	iwl_connection_init_rx_config(priv, mode);
 	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 
 	iwl_clear_stations_table(priv);
@@ -828,12 +750,12 @@
 		return -EAGAIN;
 	}
 
-	iwl4965_commit_rxon(priv);
+	iwl_commit_rxon(priv);
 
 	return 0;
 }
 
-static void iwl4965_set_rate(struct iwl_priv *priv)
+static void iwl_set_rate(struct iwl_priv *priv)
 {
 	const struct ieee80211_supported_band *hw = NULL;
 	struct ieee80211_rate *rate;
@@ -880,138 +802,6 @@
 		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
 }
 
-#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
-
-#include "iwl-spectrum.h"
-
-#define BEACON_TIME_MASK_LOW	0x00FFFFFF
-#define BEACON_TIME_MASK_HIGH	0xFF000000
-#define TIME_UNIT		1024
-
-/*
- * extended beacon time format
- * time in usec will be changed into a 32-bit value in 8:24 format
- * the high 1 byte is the beacon counts
- * the lower 3 bytes is the time in usec within one beacon interval
- */
-
-static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval)
-{
-	u32 quot;
-	u32 rem;
-	u32 interval = beacon_interval * 1024;
-
-	if (!interval || !usec)
-		return 0;
-
-	quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
-	rem = (usec % interval) & BEACON_TIME_MASK_LOW;
-
-	return (quot << 24) + rem;
-}
-
-/* base is usually what we get from ucode with each received frame,
- * the same as HW timer counter counting down
- */
-
-static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
-{
-	u32 base_low = base & BEACON_TIME_MASK_LOW;
-	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
-	u32 interval = beacon_interval * TIME_UNIT;
-	u32 res = (base & BEACON_TIME_MASK_HIGH) +
-	    (addon & BEACON_TIME_MASK_HIGH);
-
-	if (base_low > addon_low)
-		res += base_low - addon_low;
-	else if (base_low < addon_low) {
-		res += interval + base_low - addon_low;
-		res += (1 << 24);
-	} else
-		res += (1 << 24);
-
-	return cpu_to_le32(res);
-}
-
-static int iwl4965_get_measurement(struct iwl_priv *priv,
-			       struct ieee80211_measurement_params *params,
-			       u8 type)
-{
-	struct iwl4965_spectrum_cmd spectrum;
-	struct iwl_rx_packet *res;
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
-		.data = (void *)&spectrum,
-		.meta.flags = CMD_WANT_SKB,
-	};
-	u32 add_time = le64_to_cpu(params->start_time);
-	int rc;
-	int spectrum_resp_status;
-	int duration = le16_to_cpu(params->duration);
-
-	if (iwl_is_associated(priv))
-		add_time =
-		    iwl4965_usecs_to_beacons(
-			le64_to_cpu(params->start_time) - priv->last_tsf,
-			le16_to_cpu(priv->rxon_timing.beacon_interval));
-
-	memset(&spectrum, 0, sizeof(spectrum));
-
-	spectrum.channel_count = cpu_to_le16(1);
-	spectrum.flags =
-	    RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
-	spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
-	cmd.len = sizeof(spectrum);
-	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
-
-	if (iwl_is_associated(priv))
-		spectrum.start_time =
-		    iwl4965_add_beacon_time(priv->last_beacon_time,
-				add_time,
-				le16_to_cpu(priv->rxon_timing.beacon_interval));
-	else
-		spectrum.start_time = 0;
-
-	spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
-	spectrum.channels[0].channel = params->channel;
-	spectrum.channels[0].type = type;
-	if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
-		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
-		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
-
-	rc = iwl_send_cmd_sync(priv, &cmd);
-	if (rc)
-		return rc;
-
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
-	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
-		IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
-		rc = -EIO;
-	}
-
-	spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
-	switch (spectrum_resp_status) {
-	case 0:		/* Command will be handled */
-		if (res->u.spectrum.id != 0xff) {
-			IWL_DEBUG_INFO
-			    ("Replaced existing measurement: %d\n",
-			     res->u.spectrum.id);
-			priv->measurement_status &= ~MEASUREMENT_READY;
-		}
-		priv->measurement_status |= MEASUREMENT_ACTIVE;
-		rc = 0;
-		break;
-
-	case 1:		/* Command will not be handled */
-		rc = -EAGAIN;
-		break;
-	}
-
-	dev_kfree_skb_any(cmd.meta.u.skb);
-
-	return rc;
-}
-#endif
 
 /******************************************************************************
  *
@@ -1054,7 +844,7 @@
 		IWL_WARNING("uCode did not respond OK.\n");
 }
 
-static void iwl4965_rx_reply_error(struct iwl_priv *priv,
+static void iwl_rx_reply_error(struct iwl_priv *priv,
 				   struct iwl_rx_mem_buffer *rxb)
 {
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
@@ -1070,47 +860,29 @@
 
 #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
 
-static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 {
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
 	struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
-	struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif);
+	struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
 	IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
 		      le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
 	rxon->channel = csa->channel;
 	priv->staging_rxon.channel = csa->channel;
 }
 
-static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv,
-					  struct iwl_rx_mem_buffer *rxb)
-{
-#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
-	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-	struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif);
-
-	if (!report->state) {
-		IWL_DEBUG(IWL_DL_11H,
-			"Spectrum Measure Notification: Start\n");
-		return;
-	}
-
-	memcpy(&priv->measure_report, report, sizeof(*report));
-	priv->measurement_status |= MEASUREMENT_READY;
-#endif
-}
-
-static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv,
+static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
 				      struct iwl_rx_mem_buffer *rxb)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-	struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif);
+	struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
 	IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
 		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
 #endif
 }
 
-static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
 					     struct iwl_rx_mem_buffer *rxb)
 {
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
@@ -1120,7 +892,7 @@
 	iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
 }
 
-static void iwl4965_bg_beacon_update(struct work_struct *work)
+static void iwl_bg_beacon_update(struct work_struct *work)
 {
 	struct iwl_priv *priv =
 		container_of(work, struct iwl_priv, beacon_update);
@@ -1142,11 +914,11 @@
 	priv->ibss_beacon = beacon;
 	mutex_unlock(&priv->mutex);
 
-	iwl4965_send_beacon_cmd(priv);
+	iwl_send_beacon_cmd(priv);
 }
 
 /**
- * iwl4965_bg_statistics_periodic - Timer callback to queue statistics
+ * iwl_bg_statistics_periodic - Timer callback to queue statistics
  *
  * This callback is provided in order to send a statistics request.
  *
@@ -1155,22 +927,27 @@
  * was received.  We need to ensure we receive the statistics in order
  * to update the temperature used for calibrating the TXPOWER.
  */
-static void iwl4965_bg_statistics_periodic(unsigned long data)
+static void iwl_bg_statistics_periodic(unsigned long data)
 {
 	struct iwl_priv *priv = (struct iwl_priv *)data;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
+	/* dont send host command if rf-kill is on */
+	if (!iwl_is_ready_rf(priv))
+		return;
+
 	iwl_send_statistics_request(priv, CMD_ASYNC);
 }
 
-static void iwl4965_rx_beacon_notif(struct iwl_priv *priv,
+static void iwl_rx_beacon_notif(struct iwl_priv *priv,
 				struct iwl_rx_mem_buffer *rxb)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-	struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status);
+	struct iwl4965_beacon_notif *beacon =
+		(struct iwl4965_beacon_notif *)pkt->u.raw;
 	u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
 
 	IWL_DEBUG_RX("beacon status %x retries %d iss %d "
@@ -1189,7 +966,7 @@
 
 /* Handle notification from uCode that card's power state is changing
  * due to software, hardware, or critical temperature RFKILL */
-static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
+static void iwl_rx_card_state_notif(struct iwl_priv *priv,
 				    struct iwl_rx_mem_buffer *rxb)
 {
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
@@ -1258,7 +1035,7 @@
 		wake_up_interruptible(&priv->wait_command_queue);
 }
 
-int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
+int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
 {
 	int ret;
 	unsigned long flags;
@@ -1290,7 +1067,7 @@
 }
 
 /**
- * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks
+ * iwl_setup_rx_handlers - Initialize Rx handler callbacks
  *
  * Setup the RX handlers for each of the reply types sent from the uCode
  * to the host.
@@ -1301,14 +1078,12 @@
 static void iwl_setup_rx_handlers(struct iwl_priv *priv)
 {
 	priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
-	priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error;
-	priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa;
-	priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
-	    iwl4965_rx_spectrum_measure_notif;
-	priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif;
+	priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
+	priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+	priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
 	priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
-	    iwl4965_rx_pm_debug_statistics_notif;
-	priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif;
+	    iwl_rx_pm_debug_statistics_notif;
+	priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
 
 	/*
 	 * The same handler is used for both the REPLY to a discrete
@@ -1318,10 +1093,11 @@
 	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics;
 	priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics;
 
+	iwl_setup_spectrum_handlers(priv);
 	iwl_setup_rx_scan_handlers(priv);
 
 	/* status change handler */
-	priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif;
+	priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
 
 	priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
 	    iwl_rx_missed_beacon_notif;
@@ -1334,16 +1110,6 @@
 	priv->cfg->ops->lib->rx_handler_setup(priv);
 }
 
-/*
- * this should be called while priv->lock is locked
-*/
-static void __iwl_rx_replenish(struct iwl_priv *priv)
-{
-	iwl_rx_allocate(priv);
-	iwl_rx_queue_restock(priv);
-}
-
-
 /**
  * iwl_rx_handle - Main entry function for receiving responses from uCode
  *
@@ -1364,7 +1130,7 @@
 
 	/* uCode's read index (stored in shared DRAM) indicates the last Rx
 	 * buffer that the driver may process (last buffer filled by ucode). */
-	r = priv->cfg->ops->lib->shared_mem_rx_idx(priv);
+	r = le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF;
 	i = rxq->read;
 
 	/* Rx interrupt, but nothing sent from uCode */
@@ -1400,13 +1166,14 @@
 		reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
 			(pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
 			(pkt->hdr.cmd != REPLY_RX) &&
+			(pkt->hdr.cmd != REPLY_RX_MPDU_CMD) &&
 			(pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
 			(pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
 			(pkt->hdr.cmd != REPLY_TX);
 
 		/* Based on type of command response or notification,
 		 *   handle those that need handling via function in
-		 *   rx_handlers table.  See iwl4965_setup_rx_handlers() */
+		 *   rx_handlers table.  See iwl_setup_rx_handlers() */
 		if (priv->rx_handlers[pkt->hdr.cmd]) {
 			IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r,
 				i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
@@ -1451,7 +1218,7 @@
 			count++;
 			if (count >= 8) {
 				priv->rxq.read = i;
-				__iwl_rx_replenish(priv);
+				iwl_rx_queue_restock(priv);
 				count = 0;
 			}
 		}
@@ -1463,10 +1230,9 @@
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv)
+static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
 {
 	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
-	DECLARE_MAC_BUF(mac);
 
 	IWL_DEBUG_RADIO("RX CONFIG:\n");
 	iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
@@ -1478,50 +1244,26 @@
 	IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
 			rxon->ofdm_basic_rates);
 	IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
-	IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
-			print_mac(mac, rxon->node_addr));
-	IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
-			print_mac(mac, rxon->bssid_addr));
+	IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr);
+	IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
 	IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
 }
 #endif
 
-static void iwl4965_enable_interrupts(struct iwl_priv *priv)
-{
-	IWL_DEBUG_ISR("Enabling interrupts\n");
-	set_bit(STATUS_INT_ENABLED, &priv->status);
-	iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
-}
-
 /* call this function to flush any scheduled tasklet */
 static inline void iwl_synchronize_irq(struct iwl_priv *priv)
 {
-	/* wait to make sure we flush pedding tasklet*/
+	/* wait to make sure we flush pending tasklet*/
 	synchronize_irq(priv->pci_dev->irq);
 	tasklet_kill(&priv->irq_tasklet);
 }
 
-static inline void iwl4965_disable_interrupts(struct iwl_priv *priv)
-{
-	clear_bit(STATUS_INT_ENABLED, &priv->status);
-
-	/* disable interrupts from uCode/NIC to host */
-	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
-	/* acknowledge/clear/reset any interrupts still pending
-	 * from uCode or flow handler (Rx/Tx DMA) */
-	iwl_write32(priv, CSR_INT, 0xffffffff);
-	iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
-	IWL_DEBUG_ISR("Disabled interrupts\n");
-}
-
-
 /**
- * iwl4965_irq_handle_error - called for HW or SW error interrupt from card
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
  */
-static void iwl4965_irq_handle_error(struct iwl_priv *priv)
+static void iwl_irq_handle_error(struct iwl_priv *priv)
 {
-	/* Set the FW error flag -- cleared on iwl4965_down */
+	/* Set the FW error flag -- cleared on iwl_down */
 	set_bit(STATUS_FW_ERROR, &priv->status);
 
 	/* Cancel currently queued command. */
@@ -1531,7 +1273,7 @@
 	if (priv->debug_level & IWL_DL_FW_ERRORS) {
 		iwl_dump_nic_error_log(priv);
 		iwl_dump_nic_event_log(priv);
-		iwl4965_print_rx_config_cmd(priv);
+		iwl_print_rx_config_cmd(priv);
 	}
 #endif
 
@@ -1555,14 +1297,14 @@
 	}
 }
 
-static void iwl4965_error_recovery(struct iwl_priv *priv)
+static void iwl_error_recovery(struct iwl_priv *priv)
 {
 	unsigned long flags;
 
 	memcpy(&priv->staging_rxon, &priv->recovery_rxon,
 	       sizeof(priv->staging_rxon));
 	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl4965_commit_rxon(priv);
+	iwl_commit_rxon(priv);
 
 	iwl_rxon_add_station(priv, priv->bssid, 1);
 
@@ -1572,7 +1314,7 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static void iwl4965_irq_tasklet(struct iwl_priv *priv)
+static void iwl_irq_tasklet(struct iwl_priv *priv)
 {
 	u32 inta, handled = 0;
 	u32 inta_fh;
@@ -1618,9 +1360,9 @@
 		IWL_ERROR("Microcode HW error detected.  Restarting.\n");
 
 		/* Tell the device to stop sending interrupts */
-		iwl4965_disable_interrupts(priv);
+		iwl_disable_interrupts(priv);
 
-		iwl4965_irq_handle_error(priv);
+		iwl_irq_handle_error(priv);
 
 		handled |= CSR_INT_BIT_HW_ERR;
 
@@ -1652,14 +1394,17 @@
 			hw_rf_kill = 1;
 
 		IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n",
-				hw_rf_kill ? "disable radio":"enable radio");
+				hw_rf_kill ? "disable radio" : "enable radio");
 
 		/* driver only loads ucode once setting the interface up.
 		 * the driver as well won't allow loading if RFKILL is set
 		 * therefore no need to restart the driver from this handler
 		 */
-		if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status))
+		if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) {
 			clear_bit(STATUS_RF_KILL_HW, &priv->status);
+			if (priv->is_open && !iwl_is_rfkill(priv))
+				queue_work(priv->workqueue, &priv->up);
+		}
 
 		handled |= CSR_INT_BIT_RF_KILL;
 	}
@@ -1674,7 +1419,7 @@
 	if (inta & CSR_INT_BIT_SW_ERR) {
 		IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
 			  inta);
-		iwl4965_irq_handle_error(priv);
+		iwl_irq_handle_error(priv);
 		handled |= CSR_INT_BIT_SW_ERR;
 	}
 
@@ -1720,7 +1465,7 @@
 	/* Re-enable all interrupts */
 	/* only Re-enable if diabled by irq */
 	if (test_bit(STATUS_INT_ENABLED, &priv->status))
-		iwl4965_enable_interrupts(priv);
+		iwl_enable_interrupts(priv);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 	if (priv->debug_level & (IWL_DL_ISR)) {
@@ -1734,7 +1479,7 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static irqreturn_t iwl4965_isr(int irq, void *data)
+static irqreturn_t iwl_isr(int irq, void *data)
 {
 	struct iwl_priv *priv = data;
 	u32 inta, inta_mask;
@@ -1766,7 +1511,7 @@
 	if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
 		/* Hardware disappeared. It might have already raised
 		 * an interrupt */
-		IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+		IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta);
 		goto unplugged;
 	}
 
@@ -1775,7 +1520,7 @@
 
 	inta &= ~CSR_INT_BIT_SCD;
 
-	/* iwl4965_irq_tasklet() will service interrupts and re-enable them */
+	/* iwl_irq_tasklet() will service interrupts and re-enable them */
 	if (likely(inta || inta_fh))
 		tasklet_schedule(&priv->irq_tasklet);
 
@@ -1787,7 +1532,7 @@
 	/* re-enable interrupts here since we don't have anything to service. */
 	/* only Re-enable if diabled by irq */
 	if (test_bit(STATUS_INT_ENABLED, &priv->status))
-		iwl4965_enable_interrupts(priv);
+		iwl_enable_interrupts(priv);
 	spin_unlock(&priv->lock);
 	return IRQ_NONE;
 }
@@ -1798,7 +1543,7 @@
  *
  ******************************************************************************/
 
-static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv)
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
 {
 	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
 	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
@@ -1808,7 +1553,7 @@
 	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
 }
 
-static void iwl4965_nic_start(struct iwl_priv *priv)
+static void iwl_nic_start(struct iwl_priv *priv)
 {
 	/* Remove all resets to allow NIC to operate */
 	iwl_write32(priv, CSR_RESET, 0);
@@ -1816,31 +1561,47 @@
 
 
 /**
- * iwl4965_read_ucode - Read uCode images from disk file.
+ * iwl_read_ucode - Read uCode images from disk file.
  *
  * Copy into buffers for card to fetch via bus-mastering
  */
-static int iwl4965_read_ucode(struct iwl_priv *priv)
+static int iwl_read_ucode(struct iwl_priv *priv)
 {
 	struct iwl_ucode *ucode;
-	int ret;
+	int ret = -EINVAL, index;
 	const struct firmware *ucode_raw;
-	const char *name = priv->cfg->fw_name;
+	const char *name_pre = priv->cfg->fw_name_pre;
+	const unsigned int api_max = priv->cfg->ucode_api_max;
+	const unsigned int api_min = priv->cfg->ucode_api_min;
+	char buf[25];
 	u8 *src;
 	size_t len;
-	u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+	u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
 
 	/* Ask kernel firmware_class module to get the boot firmware off disk.
 	 * request_firmware() is synchronous, file is in memory on return. */
-	ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
-	if (ret < 0) {
-		IWL_ERROR("%s firmware file req failed: Reason %d\n",
-					name, ret);
-		goto error;
+	for (index = api_max; index >= api_min; index--) {
+		sprintf(buf, "%s%d%s", name_pre, index, ".ucode");
+		ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev);
+		if (ret < 0) {
+			IWL_ERROR("%s firmware file req failed: Reason %d\n",
+				  buf, ret);
+			if (ret == -ENOENT)
+				continue;
+			else
+				goto error;
+		} else {
+			if (index < api_max)
+				IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n",
+					  buf, api_max);
+			IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+				       buf, ucode_raw->size);
+			break;
+		}
 	}
 
-	IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
-		       name, ucode_raw->size);
+	if (ret < 0)
+		goto error;
 
 	/* Make sure that we got at least our header! */
 	if (ucode_raw->size < sizeof(*ucode)) {
@@ -1852,14 +1613,40 @@
 	/* Data from ucode file:  header followed by uCode images */
 	ucode = (void *)ucode_raw->data;
 
-	ver = le32_to_cpu(ucode->ver);
+	priv->ucode_ver = le32_to_cpu(ucode->ver);
+	api_ver = IWL_UCODE_API(priv->ucode_ver);
 	inst_size = le32_to_cpu(ucode->inst_size);
 	data_size = le32_to_cpu(ucode->data_size);
 	init_size = le32_to_cpu(ucode->init_size);
 	init_data_size = le32_to_cpu(ucode->init_data_size);
 	boot_size = le32_to_cpu(ucode->boot_size);
 
-	IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+	/* api_ver should match the api version forming part of the
+	 * firmware filename ... but we don't check for that and only rely
+	 * on the API version read from firware header from here on forward */
+
+	if (api_ver < api_min || api_ver > api_max) {
+		IWL_ERROR("Driver unable to support your firmware API. "
+			  "Driver supports v%u, firmware is v%u.\n",
+			  api_max, api_ver);
+		priv->ucode_ver = 0;
+		ret = -EINVAL;
+		goto err_release;
+	}
+	if (api_ver != api_max)
+		IWL_ERROR("Firmware has old API version. Expected v%u, "
+			  "got v%u. New firmware can be obtained "
+			  "from http://www.intellinuxwireless.org.\n",
+			  api_max, api_ver);
+
+	printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n",
+		       IWL_UCODE_MAJOR(priv->ucode_ver),
+		       IWL_UCODE_MINOR(priv->ucode_ver),
+		       IWL_UCODE_API(priv->ucode_ver),
+		       IWL_UCODE_SERIAL(priv->ucode_ver));
+
+	IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n",
+		       priv->ucode_ver);
 	IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n",
 		       inst_size);
 	IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n",
@@ -1964,7 +1751,7 @@
 		priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
 
 	/* Runtime data (2nd block)
-	 * NOTE:  Copy into backup buffer will be done in iwl4965_up()  */
+	 * NOTE:  Copy into backup buffer will be done in iwl_up()  */
 	src = &ucode->data[inst_size];
 	len = priv->ucode_data.len;
 	IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len);
@@ -2002,7 +1789,7 @@
  err_pci_alloc:
 	IWL_ERROR("failed to allocate pci memory\n");
 	ret = -ENOMEM;
-	iwl4965_dealloc_ucode_pci(priv);
+	iwl_dealloc_ucode_pci(priv);
 
  err_release:
 	release_firmware(ucode_raw);
@@ -2011,6 +1798,10 @@
 	return ret;
 }
 
+/* temporary */
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw,
+				 struct sk_buff *skb);
+
 /**
  * iwl_alive_start - called after REPLY_ALIVE notification received
  *                   from protocol/runtime uCode (initialization uCode's
@@ -2047,7 +1838,7 @@
 		goto restart;
 	}
 
-	/* After the ALIVE response, we can send host commands to 4965 uCode */
+	/* After the ALIVE response, we can send host commands to the uCode */
 	set_bit(STATUS_ALIVE, &priv->status);
 
 	if (iwl_is_rfkill(priv))
@@ -2067,17 +1858,17 @@
 		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 	} else {
 		/* Initialize our rx_config data */
-		iwl4965_connection_init_rx_config(priv);
+		iwl_connection_init_rx_config(priv, priv->iw_mode);
 		memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 	}
 
 	/* Configure Bluetooth device coexistence support */
-	iwl4965_send_bt_config(priv);
+	iwl_send_bt_config(priv);
 
 	iwl_reset_run_time_calib(priv);
 
 	/* Configure the adapter for unassociated operation */
-	iwl4965_commit_rxon(priv);
+	iwl_commit_rxon(priv);
 
 	/* At this point, the NIC is initialized and operational */
 	iwl_rf_kill_ct_config(priv);
@@ -2089,12 +1880,21 @@
 	wake_up_interruptible(&priv->wait_command_queue);
 
 	if (priv->error_recovering)
-		iwl4965_error_recovery(priv);
+		iwl_error_recovery(priv);
 
 	iwl_power_update_mode(priv, 1);
 
+	/* reassociate for ADHOC mode */
+	if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
+		struct sk_buff *beacon = ieee80211_beacon_get(priv->hw,
+								priv->vif);
+		if (beacon)
+			iwl_mac_beacon_update(priv->hw, beacon);
+	}
+
+
 	if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status))
-		iwl4965_set_mode(priv, priv->iw_mode);
+		iwl_set_mode(priv, priv->iw_mode);
 
 	return;
 
@@ -2104,7 +1904,7 @@
 
 static void iwl_cancel_deferred_work(struct iwl_priv *priv);
 
-static void __iwl4965_down(struct iwl_priv *priv)
+static void __iwl_down(struct iwl_priv *priv)
 {
 	unsigned long flags;
 	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
@@ -2131,14 +1931,14 @@
 
 	/* tell the device to stop sending interrupts */
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl4965_disable_interrupts(priv);
+	iwl_disable_interrupts(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 	iwl_synchronize_irq(priv);
 
 	if (priv->mac80211_registered)
 		ieee80211_stop_queues(priv->hw);
 
-	/* If we have not previously called iwl4965_init() then
+	/* If we have not previously called iwl_init() then
 	 * clear all bits but the RF Kill and SUSPEND bits and return */
 	if (!iwl_is_init(priv)) {
 		priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
@@ -2192,8 +1992,6 @@
 		priv->cfg->ops->lib->apm_ops.stop(priv);
 	else
 		priv->cfg->ops->lib->apm_ops.reset(priv);
-	priv->cfg->ops->lib->free_shared_mem(priv);
-
  exit:
 	memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
 
@@ -2205,10 +2003,10 @@
 	iwl_clear_free_frames(priv);
 }
 
-static void iwl4965_down(struct iwl_priv *priv)
+static void iwl_down(struct iwl_priv *priv)
 {
 	mutex_lock(&priv->mutex);
-	__iwl4965_down(priv);
+	__iwl_down(priv);
 	mutex_unlock(&priv->mutex);
 
 	iwl_cancel_deferred_work(priv);
@@ -2216,7 +2014,7 @@
 
 #define MAX_HW_RESTARTS 5
 
-static int __iwl4965_up(struct iwl_priv *priv)
+static int __iwl_up(struct iwl_priv *priv)
 {
 	int i;
 	int ret;
@@ -2238,7 +2036,7 @@
 		set_bit(STATUS_RF_KILL_HW, &priv->status);
 
 	if (iwl_is_rfkill(priv)) {
-		iwl4965_enable_interrupts(priv);
+		iwl_enable_interrupts(priv);
 		IWL_WARNING("Radio disabled by %s RF Kill switch\n",
 		    test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW");
 		return 0;
@@ -2246,12 +2044,6 @@
 
 	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
 
-	ret = priv->cfg->ops->lib->alloc_shared_mem(priv);
-	if (ret) {
-		IWL_ERROR("Unable to allocate shared memory\n");
-		return ret;
-	}
-
 	ret = iwl_hw_nic_init(priv);
 	if (ret) {
 		IWL_ERROR("Unable to init nic\n");
@@ -2265,7 +2057,7 @@
 
 	/* clear (again), then enable host interrupts */
 	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-	iwl4965_enable_interrupts(priv);
+	iwl_enable_interrupts(priv);
 
 	/* really make sure rfkill handshake bits are cleared */
 	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
@@ -2295,7 +2087,7 @@
 		clear_bit(STATUS_FW_ERROR, &priv->status);
 
 		/* start card; "initialize" will load runtime ucode */
-		iwl4965_nic_start(priv);
+		iwl_nic_start(priv);
 
 		IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
 
@@ -2303,7 +2095,7 @@
 	}
 
 	set_bit(STATUS_EXIT_PENDING, &priv->status);
-	__iwl4965_down(priv);
+	__iwl_down(priv);
 	clear_bit(STATUS_EXIT_PENDING, &priv->status);
 
 	/* tried to restart and config the device for as long as our
@@ -2345,7 +2137,7 @@
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl4965_bg_rf_kill(struct work_struct *work)
+static void iwl_bg_rf_kill(struct work_struct *work)
 {
 	struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
 
@@ -2379,28 +2171,6 @@
 	iwl_rfkill_set_hw_state(priv);
 }
 
-static void iwl4965_bg_set_monitor(struct work_struct *work)
-{
-	struct iwl_priv *priv = container_of(work,
-				struct iwl_priv, set_monitor);
-	int ret;
-
-	IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
-
-	mutex_lock(&priv->mutex);
-
-	ret = iwl4965_set_mode(priv, NL80211_IFTYPE_MONITOR);
-
-	if (ret) {
-		if (ret == -EAGAIN)
-			IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
-		else
-			IWL_ERROR("iwl4965_set_mode() failed ret = %d\n", ret);
-	}
-
-	mutex_unlock(&priv->mutex);
-}
-
 static void iwl_bg_run_time_calib_work(struct work_struct *work)
 {
 	struct iwl_priv *priv = container_of(work, struct iwl_priv,
@@ -2424,7 +2194,7 @@
 	return;
 }
 
-static void iwl4965_bg_up(struct work_struct *data)
+static void iwl_bg_up(struct work_struct *data)
 {
 	struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
 
@@ -2432,23 +2202,23 @@
 		return;
 
 	mutex_lock(&priv->mutex);
-	__iwl4965_up(priv);
+	__iwl_up(priv);
 	mutex_unlock(&priv->mutex);
 	iwl_rfkill_set_hw_state(priv);
 }
 
-static void iwl4965_bg_restart(struct work_struct *data)
+static void iwl_bg_restart(struct work_struct *data)
 {
 	struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
-	iwl4965_down(priv);
+	iwl_down(priv);
 	queue_work(priv->workqueue, &priv->up);
 }
 
-static void iwl4965_bg_rx_replenish(struct work_struct *data)
+static void iwl_bg_rx_replenish(struct work_struct *data)
 {
 	struct iwl_priv *priv =
 	    container_of(data, struct iwl_priv, rx_replenish);
@@ -2463,11 +2233,10 @@
 
 #define IWL_DELAY_NEXT_SCAN (HZ*2)
 
-static void iwl4965_post_associate(struct iwl_priv *priv)
+static void iwl_post_associate(struct iwl_priv *priv)
 {
 	struct ieee80211_conf *conf = NULL;
 	int ret = 0;
-	DECLARE_MAC_BUF(mac);
 	unsigned long flags;
 
 	if (priv->iw_mode == NL80211_IFTYPE_AP) {
@@ -2475,9 +2244,8 @@
 		return;
 	}
 
-	IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
-			priv->assoc_id,
-			print_mac(mac, priv->active_rxon.bssid_addr));
+	IWL_DEBUG_ASSOC("Associated as %d to: %pM\n",
+			priv->assoc_id, priv->active_rxon.bssid_addr);
 
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -2493,10 +2261,9 @@
 	conf = ieee80211_get_hw_conf(priv->hw);
 
 	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl4965_commit_rxon(priv);
+	iwl_commit_rxon(priv);
 
-	memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd));
-	iwl4965_setup_rxon_timing(priv);
+	iwl_setup_rxon_timing(priv);
 	ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
 			      sizeof(priv->rxon_timing), &priv->rxon_timing);
 	if (ret)
@@ -2529,7 +2296,7 @@
 
 	}
 
-	iwl4965_commit_rxon(priv);
+	iwl_commit_rxon(priv);
 
 	switch (priv->iw_mode) {
 	case NL80211_IFTYPE_STATION:
@@ -2541,7 +2308,7 @@
 		priv->assoc_id = 1;
 
 		iwl_rxon_add_station(priv, priv->bssid, 0);
-		iwl4965_send_beacon_cmd(priv);
+		iwl_send_beacon_cmd(priv);
 
 		break;
 
@@ -2578,7 +2345,7 @@
 
 #define UCODE_READY_TIMEOUT	(4 * HZ)
 
-static int iwl4965_mac_start(struct ieee80211_hw *hw)
+static int iwl_mac_start(struct ieee80211_hw *hw)
 {
 	struct iwl_priv *priv = hw->priv;
 	int ret;
@@ -2600,7 +2367,7 @@
 		pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
 	}
 
-	ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED,
+	ret = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED,
 			  DRV_NAME, priv);
 	if (ret) {
 		IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq);
@@ -2615,7 +2382,7 @@
 	 * ucode filename and max sizes are card-specific. */
 
 	if (!priv->ucode_code.len) {
-		ret = iwl4965_read_ucode(priv);
+		ret = iwl_read_ucode(priv);
 		if (ret) {
 			IWL_ERROR("Could not read microcode: %d\n", ret);
 			mutex_unlock(&priv->mutex);
@@ -2623,7 +2390,7 @@
 		}
 	}
 
-	ret = __iwl4965_up(priv);
+	ret = __iwl_up(priv);
 
 	mutex_unlock(&priv->mutex);
 
@@ -2669,7 +2436,7 @@
 	return ret;
 }
 
-static void iwl4965_mac_stop(struct ieee80211_hw *hw)
+static void iwl_mac_stop(struct ieee80211_hw *hw)
 {
 	struct iwl_priv *priv = hw->priv;
 
@@ -2691,7 +2458,7 @@
 		mutex_unlock(&priv->mutex);
 	}
 
-	iwl4965_down(priv);
+	iwl_down(priv);
 
 	flush_workqueue(priv->workqueue);
 	free_irq(priv->pci_dev->irq, priv);
@@ -2702,7 +2469,7 @@
 	IWL_DEBUG_MAC80211("leave\n");
 }
 
-static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
 	struct iwl_priv *priv = hw->priv;
 
@@ -2718,12 +2485,11 @@
 	return 0;
 }
 
-static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
+static int iwl_mac_add_interface(struct ieee80211_hw *hw,
 				 struct ieee80211_if_init_conf *conf)
 {
 	struct iwl_priv *priv = hw->priv;
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
 
 	IWL_DEBUG_MAC80211("enter: type %d\n", conf->type);
 
@@ -2734,17 +2500,18 @@
 
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->vif = conf->vif;
+	priv->iw_mode = conf->type;
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	mutex_lock(&priv->mutex);
 
 	if (conf->mac_addr) {
-		IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr));
+		IWL_DEBUG_MAC80211("Set %pM\n", conf->mac_addr);
 		memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
 	}
 
-	if (iwl4965_set_mode(priv, conf->type) == -EAGAIN)
+	if (iwl_set_mode(priv, conf->type) == -EAGAIN)
 		/* we are not ready, will run again when ready */
 		set_bit(STATUS_MODE_PENDING, &priv->status);
 
@@ -2755,16 +2522,17 @@
 }
 
 /**
- * iwl4965_mac_config - mac80211 config callback
+ * iwl_mac_config - mac80211 config callback
  *
  * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
  * be set inappropriately and the driver currently sets the hardware up to
  * use it whenever needed.
  */
-static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct iwl_priv *priv = hw->priv;
 	const struct iwl_channel_info *ch_info;
+	struct ieee80211_conf *conf = &hw->conf;
 	unsigned long flags;
 	int ret = 0;
 	u16 channel;
@@ -2772,6 +2540,8 @@
 	mutex_lock(&priv->mutex);
 	IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value);
 
+	priv->current_ht_config.is_ht = conf->ht.enabled;
+
 	if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n");
 		goto out;
@@ -2829,13 +2599,13 @@
 	/* The list of supported rates and rate mask can be different
 	 * for each band; since the band may have changed, reset
 	 * the rate mask to what mac80211 lists */
-	iwl4965_set_rate(priv);
+	iwl_set_rate(priv);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 #ifdef IEEE80211_CONF_CHANNEL_SWITCH
 	if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
-		iwl4965_hw_channel_switch(priv, conf->channel);
+		iwl_hw_channel_switch(priv, conf->channel);
 		goto out;
 	}
 #endif
@@ -2863,11 +2633,11 @@
 
 	iwl_set_tx_power(priv, conf->power_level, false);
 
-	iwl4965_set_rate(priv);
+	iwl_set_rate(priv);
 
 	if (memcmp(&priv->active_rxon,
 		   &priv->staging_rxon, sizeof(priv->staging_rxon)))
-		iwl4965_commit_rxon(priv);
+		iwl_commit_rxon(priv);
 	else
 		IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
 
@@ -2878,7 +2648,7 @@
 	return ret;
 }
 
-static void iwl4965_config_ap(struct iwl_priv *priv)
+static void iwl_config_ap(struct iwl_priv *priv)
 {
 	int ret = 0;
 	unsigned long flags;
@@ -2887,15 +2657,14 @@
 		return;
 
 	/* The following should be done only at AP bring up */
-	if (!(iwl_is_associated(priv))) {
+	if (!iwl_is_associated(priv)) {
 
 		/* RXON - unassoc (to set timing command) */
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		iwl4965_commit_rxon(priv);
+		iwl_commit_rxon(priv);
 
 		/* RXON Timing */
-		memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd));
-		iwl4965_setup_rxon_timing(priv);
+		iwl_setup_rxon_timing(priv);
 		ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
 				sizeof(priv->rxon_timing), &priv->rxon_timing);
 		if (ret)
@@ -2928,29 +2697,25 @@
 		}
 		/* restore RXON assoc */
 		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
-		iwl4965_commit_rxon(priv);
+		iwl_commit_rxon(priv);
 		spin_lock_irqsave(&priv->lock, flags);
 		iwl_activate_qos(priv, 1);
 		spin_unlock_irqrestore(&priv->lock, flags);
 		iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
 	}
-	iwl4965_send_beacon_cmd(priv);
+	iwl_send_beacon_cmd(priv);
 
 	/* FIXME - we need to add code here to detect a totally new
 	 * configuration, reset the AP, unassoc, rxon timing, assoc,
 	 * clear sta table, add BCAST sta... */
 }
 
-/* temporary */
-static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
 
-static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
+static int iwl_mac_config_interface(struct ieee80211_hw *hw,
 					struct ieee80211_vif *vif,
 				    struct ieee80211_if_conf *conf)
 {
 	struct iwl_priv *priv = hw->priv;
-	DECLARE_MAC_BUF(mac);
-	unsigned long flags;
 	int rc;
 
 	if (conf == NULL)
@@ -2966,26 +2731,20 @@
 		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
 		if (!beacon)
 			return -ENOMEM;
-		rc = iwl4965_mac_beacon_update(hw, beacon);
+		mutex_lock(&priv->mutex);
+		rc = iwl_mac_beacon_update(hw, beacon);
+		mutex_unlock(&priv->mutex);
 		if (rc)
 			return rc;
 	}
 
-	if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
-	    (!conf->ssid_len)) {
-		IWL_DEBUG_MAC80211
-		    ("Leaving in AP mode because HostAPD is not ready.\n");
-		return 0;
-	}
-
 	if (!iwl_is_alive(priv))
 		return -EAGAIN;
 
 	mutex_lock(&priv->mutex);
 
 	if (conf->bssid)
-		IWL_DEBUG_MAC80211("bssid: %s\n",
-				   print_mac(mac, conf->bssid));
+		IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid);
 
 /*
  * very dubious code was here; the probe filtering flag is never set:
@@ -2998,8 +2757,8 @@
 		if (!conf->bssid) {
 			conf->bssid = priv->mac_addr;
 			memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
-			IWL_DEBUG_MAC80211("bssid was set to: %s\n",
-					   print_mac(mac, conf->bssid));
+			IWL_DEBUG_MAC80211("bssid was set to: %pM\n",
+					   conf->bssid);
 		}
 		if (priv->ibss_beacon)
 			dev_kfree_skb(priv->ibss_beacon);
@@ -3030,9 +2789,9 @@
 		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 
 		if (priv->iw_mode == NL80211_IFTYPE_AP)
-			iwl4965_config_ap(priv);
+			iwl_config_ap(priv);
 		else {
-			rc = iwl4965_commit_rxon(priv);
+			rc = iwl_commit_rxon(priv);
 			if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc)
 				iwl_rxon_add_station(
 					priv, priv->active_rxon.bssid_addr, 1);
@@ -3041,45 +2800,63 @@
 	} else {
 		iwl_scan_cancel_timeout(priv, 100);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		iwl4965_commit_rxon(priv);
+		iwl_commit_rxon(priv);
 	}
 
  done:
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!conf->ssid_len)
-		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-	else
-		memcpy(priv->essid, conf->ssid, conf->ssid_len);
-
-	priv->essid_len = conf->ssid_len;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	IWL_DEBUG_MAC80211("leave\n");
 	mutex_unlock(&priv->mutex);
 
 	return 0;
 }
 
-static void iwl4965_configure_filter(struct ieee80211_hw *hw,
+static void iwl_configure_filter(struct ieee80211_hw *hw,
 				 unsigned int changed_flags,
 				 unsigned int *total_flags,
 				 int mc_count, struct dev_addr_list *mc_list)
 {
 	struct iwl_priv *priv = hw->priv;
+	__le32 *filter_flags = &priv->staging_rxon.filter_flags;
 
-	if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
-		IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
-				   NL80211_IFTYPE_MONITOR,
-				   changed_flags, *total_flags);
-		/* queue work 'cuz mac80211 is holding a lock which
-		 * prevents us from issuing (synchronous) f/w cmds */
-		queue_work(priv->workqueue, &priv->set_monitor);
+	IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n",
+			changed_flags, *total_flags);
+
+	if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
+		if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
+			*filter_flags |= RXON_FILTER_PROMISC_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_PROMISC_MSK;
 	}
-	*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
+	if (changed_flags & FIF_ALLMULTI) {
+		if (*total_flags & FIF_ALLMULTI)
+			*filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK;
+	}
+	if (changed_flags & FIF_CONTROL) {
+		if (*total_flags & FIF_CONTROL)
+			*filter_flags |= RXON_FILTER_CTL2HOST_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_CTL2HOST_MSK;
+	}
+	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+			*filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK;
+	}
+
+	/* We avoid iwl_commit_rxon here to commit the new filter flags
+	 * since mac80211 will call ieee80211_hw_config immediately.
+	 * (mc_list is not supported at this time). Otherwise, we need to
+	 * queue a background iwl_commit_rxon work.
+	 */
+
+	*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
 			FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
-static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
+static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 				     struct ieee80211_if_init_conf *conf)
 {
 	struct iwl_priv *priv = hw->priv;
@@ -3091,13 +2868,11 @@
 	if (iwl_is_ready_rf(priv)) {
 		iwl_scan_cancel_timeout(priv, 100);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		iwl4965_commit_rxon(priv);
+		iwl_commit_rxon(priv);
 	}
 	if (priv->vif == conf->vif) {
 		priv->vif = NULL;
 		memset(priv->bssid, 0, ETH_ALEN);
-		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-		priv->essid_len = 0;
 	}
 	mutex_unlock(&priv->mutex);
 
@@ -3106,7 +2881,7 @@
 }
 
 #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
-static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
+static void iwl_bss_info_changed(struct ieee80211_hw *hw,
 				     struct ieee80211_vif *vif,
 				     struct ieee80211_bss_conf *bss_conf,
 				     u32 changes)
@@ -3133,8 +2908,7 @@
 	}
 
 	if (changes & BSS_CHANGED_HT) {
-		IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht);
-		iwl4965_ht_conf(priv, bss_conf);
+		iwl_ht_conf(priv, bss_conf);
 		iwl_set_rxon_chain(priv);
 	}
 
@@ -3157,7 +2931,7 @@
 			priv->next_scan_jiffies = jiffies +
 					IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
 			mutex_lock(&priv->mutex);
-			iwl4965_post_associate(priv);
+			iwl_post_associate(priv);
 			mutex_unlock(&priv->mutex);
 		} else {
 			priv->assoc_id = 0;
@@ -3187,12 +2961,6 @@
 		goto out_unlock;
 	}
 
-	if (priv->iw_mode == NL80211_IFTYPE_AP) {	/* APs don't scan */
-		ret = -EIO;
-		IWL_ERROR("ERROR: APs don't scan\n");
-		goto out_unlock;
-	}
-
 	/* We don't schedule scan within next_scan_jiffies period.
 	 * Avoid scanning during possible EAPOL exchange, return
 	 * success immediately.
@@ -3233,64 +3001,24 @@
 	return ret;
 }
 
-static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
+static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
 			struct ieee80211_key_conf *keyconf, const u8 *addr,
 			u32 iv32, u16 *phase1key)
 {
-	struct iwl_priv *priv = hw->priv;
-	u8 sta_id = IWL_INVALID_STATION;
-	unsigned long flags;
-	__le16 key_flags = 0;
-	int i;
-	DECLARE_MAC_BUF(mac);
 
+	struct iwl_priv *priv = hw->priv;
 	IWL_DEBUG_MAC80211("enter\n");
 
-	sta_id = iwl_find_station(priv, addr);
-	if (sta_id == IWL_INVALID_STATION) {
-		IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
-				   print_mac(mac, addr));
-		return;
-	}
-
-	if (iwl_scan_cancel(priv)) {
-		/* cancel scan failed, just live w/ bad key and rely
-		   briefly on SW decryption */
-		return;
-	}
-
-	key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
-	key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
-	key_flags &= ~STA_KEY_FLG_INVALID;
-
-	if (sta_id == priv->hw_params.bcast_sta_id)
-		key_flags |= STA_KEY_MULTICAST_MSK;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-
-	priv->stations[sta_id].sta.key.key_flags = key_flags;
-	priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
-
-	for (i = 0; i < 5; i++)
-		priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
-			cpu_to_le16(phase1key[i]);
-
-	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
-	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-
-	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
+	iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key);
 
 	IWL_DEBUG_MAC80211("leave\n");
 }
 
-static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 			   const u8 *local_addr, const u8 *addr,
 			   struct ieee80211_key_conf *key)
 {
 	struct iwl_priv *priv = hw->priv;
-	DECLARE_MAC_BUF(mac);
 	int ret = 0;
 	u8 sta_id = IWL_INVALID_STATION;
 	u8 is_default_wep_key = 0;
@@ -3308,8 +3036,8 @@
 
 	sta_id = iwl_find_station(priv, addr);
 	if (sta_id == IWL_INVALID_STATION) {
-		IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
-				   print_mac(mac, addr));
+		IWL_DEBUG_MAC80211("leave - %pM not in station map.\n",
+				   addr);
 		return -EINVAL;
 
 	}
@@ -3357,7 +3085,7 @@
 	return ret;
 }
 
-static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
 			   const struct ieee80211_tx_queue_params *params)
 {
 	struct iwl_priv *priv = hw->priv;
@@ -3376,11 +3104,6 @@
 		return 0;
 	}
 
-	if (!priv->qos_data.qos_enable) {
-		priv->qos_data.qos_active = 0;
-		IWL_DEBUG_MAC80211("leave - qos not enabled\n");
-		return 0;
-	}
 	q = AC_NUM - 1 - queue;
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -3405,15 +3128,14 @@
 	return 0;
 }
 
-static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
+static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
 			     enum ieee80211_ampdu_mlme_action action,
 			     struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
 	struct iwl_priv *priv = hw->priv;
-	DECLARE_MAC_BUF(mac);
 
-	IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n",
-		     print_mac(mac, sta->addr), tid);
+	IWL_DEBUG_HT("A-MPDU action on addr %pM tid %d\n",
+		     sta->addr, tid);
 
 	if (!(priv->cfg->sku & IWL_SKU_N))
 		return -EACCES;
@@ -3421,10 +3143,10 @@
 	switch (action) {
 	case IEEE80211_AMPDU_RX_START:
 		IWL_DEBUG_HT("start Rx\n");
-		return iwl_rx_agg_start(priv, sta->addr, tid, *ssn);
+		return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn);
 	case IEEE80211_AMPDU_RX_STOP:
 		IWL_DEBUG_HT("stop Rx\n");
-		return iwl_rx_agg_stop(priv, sta->addr, tid);
+		return iwl_sta_rx_agg_stop(priv, sta->addr, tid);
 	case IEEE80211_AMPDU_TX_START:
 		IWL_DEBUG_HT("start Tx\n");
 		return iwl_tx_agg_start(priv, sta->addr, tid, ssn);
@@ -3438,7 +3160,8 @@
 	}
 	return 0;
 }
-static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
+
+static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
 				struct ieee80211_tx_queue_stats *stats)
 {
 	struct iwl_priv *priv = hw->priv;
@@ -3473,7 +3196,7 @@
 	return 0;
 }
 
-static int iwl4965_mac_get_stats(struct ieee80211_hw *hw,
+static int iwl_mac_get_stats(struct ieee80211_hw *hw,
 			     struct ieee80211_low_level_stats *stats)
 {
 	struct iwl_priv *priv = hw->priv;
@@ -3485,7 +3208,7 @@
 	return 0;
 }
 
-static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
+static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
 {
 	struct iwl_priv *priv = hw->priv;
 	unsigned long flags;
@@ -3529,7 +3252,7 @@
 	if (priv->iw_mode != NL80211_IFTYPE_AP) {
 		iwl_scan_cancel_timeout(priv, 100);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		iwl4965_commit_rxon(priv);
+		iwl_commit_rxon(priv);
 	}
 
 	iwl_power_update_mode(priv, 0);
@@ -3552,31 +3275,28 @@
 		return;
 	}
 
-	iwl4965_set_rate(priv);
+	iwl_set_rate(priv);
 
 	mutex_unlock(&priv->mutex);
 
 	IWL_DEBUG_MAC80211("leave\n");
 }
 
-static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
 	struct iwl_priv *priv = hw->priv;
 	unsigned long flags;
 	__le64 timestamp;
 
-	mutex_lock(&priv->mutex);
 	IWL_DEBUG_MAC80211("enter\n");
 
 	if (!iwl_is_ready_rf(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF not ready\n");
-		mutex_unlock(&priv->mutex);
 		return -EIO;
 	}
 
 	if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
 		IWL_DEBUG_MAC80211("leave - not IBSS\n");
-		mutex_unlock(&priv->mutex);
 		return -EIO;
 	}
 
@@ -3596,9 +3316,8 @@
 
 	iwl_reset_qos(priv);
 
-	iwl4965_post_associate(priv);
+	iwl_post_associate(priv);
 
-	mutex_unlock(&priv->mutex);
 
 	return 0;
 }
@@ -3613,7 +3332,7 @@
 
 /*
  * The following adds a new attribute to the sysfs representation
- * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/)
+ * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
  * used for controlling the debug level.
  *
  * See the level definitions in iwl for details.
@@ -3699,7 +3418,11 @@
 			     struct device_attribute *attr, char *buf)
 {
 	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
+
+	if (!iwl_is_ready_rf(priv))
+		return sprintf(buf, "off\n");
+	else
+		return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
 }
 
 static ssize_t store_tx_power(struct device *d,
@@ -3750,7 +3473,7 @@
 		else {
 			IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags);
 			priv->staging_rxon.flags = cpu_to_le32(flags);
-			iwl4965_commit_rxon(priv);
+			iwl_commit_rxon(priv);
 		}
 	}
 	mutex_unlock(&priv->mutex);
@@ -3791,7 +3514,7 @@
 				       "0x%04X\n", filter_flags);
 			priv->staging_rxon.filter_flags =
 				cpu_to_le32(filter_flags);
-			iwl4965_commit_rxon(priv);
+			iwl_commit_rxon(priv);
 		}
 	}
 	mutex_unlock(&priv->mutex);
@@ -3802,79 +3525,6 @@
 static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
 		   store_filter_flags);
 
-#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
-
-static ssize_t show_measurement(struct device *d,
-				struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	struct iwl4965_spectrum_notification measure_report;
-	u32 size = sizeof(measure_report), len = 0, ofs = 0;
-	u8 *data = (u8 *)&measure_report;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!(priv->measurement_status & MEASUREMENT_READY)) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return 0;
-	}
-	memcpy(&measure_report, &priv->measure_report, size);
-	priv->measurement_status = 0;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	while (size && (PAGE_SIZE - len)) {
-		hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
-				   PAGE_SIZE - len, 1);
-		len = strlen(buf);
-		if (PAGE_SIZE - len)
-			buf[len++] = '\n';
-
-		ofs += 16;
-		size -= min(size, 16U);
-	}
-
-	return len;
-}
-
-static ssize_t store_measurement(struct device *d,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	struct ieee80211_measurement_params params = {
-		.channel = le16_to_cpu(priv->active_rxon.channel),
-		.start_time = cpu_to_le64(priv->last_tsf),
-		.duration = cpu_to_le16(1),
-	};
-	u8 type = IWL_MEASURE_BASIC;
-	u8 buffer[32];
-	u8 channel;
-
-	if (count) {
-		char *p = buffer;
-		strncpy(buffer, buf, min(sizeof(buffer), count));
-		channel = simple_strtoul(p, NULL, 0);
-		if (channel)
-			params.channel = channel;
-
-		p = buffer;
-		while (*p && *p != ' ')
-			p++;
-		if (*p)
-			type = simple_strtoul(p + 1, NULL, 0);
-	}
-
-	IWL_DEBUG_INFO("Invoking measurement of type %d on "
-		       "channel %d (for '%s')\n", type, params.channel, buf);
-	iwl4965_get_measurement(priv, &params, type);
-
-	return count;
-}
-
-static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
-		   show_measurement, store_measurement);
-#endif /* CONFIG_IWLAGN_SPECTRUM_MEASUREMENT */
-
 static ssize_t store_retry_rate(struct device *d,
 				struct device_attribute *attr,
 				const char *buf, size_t count)
@@ -3953,7 +3603,8 @@
 		break;
 	}
 
-	p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto");
+	p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ?
+			"fixed" : "auto");
 	p += sprintf(p, "\tINDEX:%d", level);
 	p += sprintf(p, "\n");
 	return p - buf + 1;
@@ -3962,68 +3613,6 @@
 static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
 		   store_power_level);
 
-static ssize_t show_channels(struct device *d,
-			     struct device_attribute *attr, char *buf)
-{
-
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	struct ieee80211_channel *channels = NULL;
-	const struct ieee80211_supported_band *supp_band = NULL;
-	int len = 0, i;
-	int count = 0;
-
-	if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
-		return -EAGAIN;
-
-	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
-	channels = supp_band->channels;
-	count = supp_band->n_channels;
-
-	len += sprintf(&buf[len],
-			"Displaying %d channels in 2.4GHz band "
-			"(802.11bg):\n", count);
-
-	for (i = 0; i < count; i++)
-		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
-				ieee80211_frequency_to_channel(
-				channels[i].center_freq),
-				channels[i].max_power,
-				channels[i].flags & IEEE80211_CHAN_RADAR ?
-				" (IEEE 802.11h required)" : "",
-				(!(channels[i].flags & IEEE80211_CHAN_NO_IBSS)
-				|| (channels[i].flags &
-				IEEE80211_CHAN_RADAR)) ? "" :
-				", IBSS",
-				channels[i].flags &
-				IEEE80211_CHAN_PASSIVE_SCAN ?
-				"passive only" : "active/passive");
-
-	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
-	channels = supp_band->channels;
-	count = supp_band->n_channels;
-
-	len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
-			"(802.11a):\n", count);
-
-	for (i = 0; i < count; i++)
-		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
-				ieee80211_frequency_to_channel(
-				channels[i].center_freq),
-				channels[i].max_power,
-				channels[i].flags & IEEE80211_CHAN_RADAR ?
-				" (IEEE 802.11h required)" : "",
-				((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
-				|| (channels[i].flags &
-				IEEE80211_CHAN_RADAR)) ? "" :
-				", IBSS",
-				channels[i].flags &
-				IEEE80211_CHAN_PASSIVE_SCAN ?
-				"passive only" : "active/passive");
-
-	return len;
-}
-
-static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
 
 static ssize_t show_statistics(struct device *d,
 			       struct device_attribute *attr, char *buf)
@@ -4086,12 +3675,11 @@
 
 	init_waitqueue_head(&priv->wait_command_queue);
 
-	INIT_WORK(&priv->up, iwl4965_bg_up);
-	INIT_WORK(&priv->restart, iwl4965_bg_restart);
-	INIT_WORK(&priv->rx_replenish, iwl4965_bg_rx_replenish);
-	INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill);
-	INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update);
-	INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor);
+	INIT_WORK(&priv->up, iwl_bg_up);
+	INIT_WORK(&priv->restart, iwl_bg_restart);
+	INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
+	INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
+	INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
 	INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
 	INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
 	INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
@@ -4104,10 +3692,10 @@
 
 	init_timer(&priv->statistics_periodic);
 	priv->statistics_periodic.data = (unsigned long)priv;
-	priv->statistics_periodic.function = iwl4965_bg_statistics_periodic;
+	priv->statistics_periodic.function = iwl_bg_statistics_periodic;
 
 	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
-		     iwl4965_irq_tasklet, (unsigned long)priv);
+		     iwl_irq_tasklet, (unsigned long)priv);
 }
 
 static void iwl_cancel_deferred_work(struct iwl_priv *priv)
@@ -4123,13 +3711,9 @@
 	del_timer_sync(&priv->statistics_periodic);
 }
 
-static struct attribute *iwl4965_sysfs_entries[] = {
-	&dev_attr_channels.attr,
+static struct attribute *iwl_sysfs_entries[] = {
 	&dev_attr_flags.attr,
 	&dev_attr_filter_flags.attr,
-#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
-	&dev_attr_measurement.attr,
-#endif
 	&dev_attr_power_level.attr,
 	&dev_attr_retry_rate.attr,
 	&dev_attr_statistics.attr,
@@ -4144,39 +3728,38 @@
 	NULL
 };
 
-static struct attribute_group iwl4965_attribute_group = {
+static struct attribute_group iwl_attribute_group = {
 	.name = NULL,		/* put in device directory */
-	.attrs = iwl4965_sysfs_entries,
+	.attrs = iwl_sysfs_entries,
 };
 
-static struct ieee80211_ops iwl4965_hw_ops = {
-	.tx = iwl4965_mac_tx,
-	.start = iwl4965_mac_start,
-	.stop = iwl4965_mac_stop,
-	.add_interface = iwl4965_mac_add_interface,
-	.remove_interface = iwl4965_mac_remove_interface,
-	.config = iwl4965_mac_config,
-	.config_interface = iwl4965_mac_config_interface,
-	.configure_filter = iwl4965_configure_filter,
-	.set_key = iwl4965_mac_set_key,
-	.update_tkip_key = iwl4965_mac_update_tkip_key,
-	.get_stats = iwl4965_mac_get_stats,
-	.get_tx_stats = iwl4965_mac_get_tx_stats,
-	.conf_tx = iwl4965_mac_conf_tx,
-	.reset_tsf = iwl4965_mac_reset_tsf,
-	.bss_info_changed = iwl4965_bss_info_changed,
-	.ampdu_action = iwl4965_mac_ampdu_action,
+static struct ieee80211_ops iwl_hw_ops = {
+	.tx = iwl_mac_tx,
+	.start = iwl_mac_start,
+	.stop = iwl_mac_stop,
+	.add_interface = iwl_mac_add_interface,
+	.remove_interface = iwl_mac_remove_interface,
+	.config = iwl_mac_config,
+	.config_interface = iwl_mac_config_interface,
+	.configure_filter = iwl_configure_filter,
+	.set_key = iwl_mac_set_key,
+	.update_tkip_key = iwl_mac_update_tkip_key,
+	.get_stats = iwl_mac_get_stats,
+	.get_tx_stats = iwl_mac_get_tx_stats,
+	.conf_tx = iwl_mac_conf_tx,
+	.reset_tsf = iwl_mac_reset_tsf,
+	.bss_info_changed = iwl_bss_info_changed,
+	.ampdu_action = iwl_mac_ampdu_action,
 	.hw_scan = iwl_mac_hw_scan
 };
 
-static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	int err = 0;
 	struct iwl_priv *priv;
 	struct ieee80211_hw *hw;
 	struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
 
 	/************************
 	 * 1. Allocating HW data
@@ -4188,10 +3771,10 @@
 		if (cfg->mod_params->debug & IWL_DL_INFO)
 			dev_printk(KERN_DEBUG, &(pdev->dev),
 				   "Disabling hw_scan\n");
-		iwl4965_hw_ops.hw_scan = NULL;
+		iwl_hw_ops.hw_scan = NULL;
 	}
 
-	hw = iwl_alloc_all(cfg, &iwl4965_hw_ops);
+	hw = iwl_alloc_all(cfg, &iwl_hw_ops);
 	if (!hw) {
 		err = -ENOMEM;
 		goto out;
@@ -4285,7 +3868,7 @@
 
 	/* extract MAC Address */
 	iwl_eeprom_get_mac(priv, priv->mac_addr);
-	IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
+	IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr);
 	SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 
 	/************************
@@ -4319,10 +3902,10 @@
 	 * 8. Setup services
 	 ********************/
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl4965_disable_interrupts(priv);
+	iwl_disable_interrupts(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+	err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
 	if (err) {
 		IWL_ERROR("failed to create sysfs device attributes\n");
 		goto out_uninit_drv;
@@ -4358,7 +3941,7 @@
 	return 0;
 
  out_remove_sysfs:
-	sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
  out_uninit_drv:
 	iwl_uninit_drv(priv);
  out_free_eeprom:
@@ -4376,7 +3959,7 @@
 	return err;
 }
 
-static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
+static void __devexit iwl_pci_remove(struct pci_dev *pdev)
 {
 	struct iwl_priv *priv = pci_get_drvdata(pdev);
 	unsigned long flags;
@@ -4387,10 +3970,10 @@
 	IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
 
 	iwl_dbgfs_unregister(priv);
-	sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
 
-	/* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to
-	 * to be called and iwl4965_down since we are removing the device
+	/* ieee80211_unregister_hw call wil cause iwl_mac_stop to
+	 * to be called and iwl_down since we are removing the device
 	 * we need to set STATUS_EXIT_PENDING bit.
 	 */
 	set_bit(STATUS_EXIT_PENDING, &priv->status);
@@ -4398,20 +3981,20 @@
 		ieee80211_unregister_hw(priv->hw);
 		priv->mac80211_registered = 0;
 	} else {
-		iwl4965_down(priv);
+		iwl_down(priv);
 	}
 
 	/* make sure we flush any pending irq or
 	 * tasklet for the driver
 	 */
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl4965_disable_interrupts(priv);
+	iwl_disable_interrupts(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	iwl_synchronize_irq(priv);
 
 	iwl_rfkill_unregister(priv);
-	iwl4965_dealloc_ucode_pci(priv);
+	iwl_dealloc_ucode_pci(priv);
 
 	if (priv->rxq.bd)
 		iwl_rx_queue_free(priv, &priv->rxq);
@@ -4424,7 +4007,7 @@
 	/*netif_stop_queue(dev); */
 	flush_workqueue(priv->workqueue);
 
-	/* ieee80211_unregister_hw calls iwl4965_mac_stop, which flushes
+	/* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
 	 * priv->workqueue... so we can't take down the workqueue
 	 * until now... */
 	destroy_workqueue(priv->workqueue);
@@ -4445,13 +4028,13 @@
 
 #ifdef CONFIG_PM
 
-static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct iwl_priv *priv = pci_get_drvdata(pdev);
 
 	if (priv->is_open) {
 		set_bit(STATUS_IN_SUSPEND, &priv->status);
-		iwl4965_mac_stop(priv->hw);
+		iwl_mac_stop(priv->hw);
 		priv->is_open = 1;
 	}
 
@@ -4460,14 +4043,14 @@
 	return 0;
 }
 
-static int iwl4965_pci_resume(struct pci_dev *pdev)
+static int iwl_pci_resume(struct pci_dev *pdev)
 {
 	struct iwl_priv *priv = pci_get_drvdata(pdev);
 
 	pci_set_power_state(pdev, PCI_D0);
 
 	if (priv->is_open)
-		iwl4965_mac_start(priv->hw);
+		iwl_mac_start(priv->hw);
 
 	clear_bit(STATUS_IN_SUSPEND, &priv->status);
 	return 0;
@@ -4502,7 +4085,11 @@
 	{IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)},
 	{IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)},
 	{IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)},
+/* 5150 Wifi/WiMax */
+	{IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)},
+	{IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)},
 #endif /* CONFIG_IWL5000 */
+
 	{0}
 };
 MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
@@ -4510,15 +4097,15 @@
 static struct pci_driver iwl_driver = {
 	.name = DRV_NAME,
 	.id_table = iwl_hw_card_ids,
-	.probe = iwl4965_pci_probe,
-	.remove = __devexit_p(iwl4965_pci_remove),
+	.probe = iwl_pci_probe,
+	.remove = __devexit_p(iwl_pci_remove),
 #ifdef CONFIG_PM
-	.suspend = iwl4965_pci_suspend,
-	.resume = iwl4965_pci_resume,
+	.suspend = iwl_pci_suspend,
+	.resume = iwl_pci_resume,
 #endif
 };
 
-static int __init iwl4965_init(void)
+static int __init iwl_init(void)
 {
 
 	int ret;
@@ -4544,11 +4131,11 @@
 	return ret;
 }
 
-static void __exit iwl4965_exit(void)
+static void __exit iwl_exit(void)
 {
 	pci_unregister_driver(&iwl_driver);
 	iwlagn_rate_control_unregister();
 }
 
-module_exit(iwl4965_exit);
-module_init(iwl4965_init);
+module_exit(iwl_exit);
+module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index 72fbf47..f836ecc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -70,7 +70,16 @@
  * INIT calibrations framework
  *****************************************************************************/
 
- int iwl_send_calib_results(struct iwl_priv *priv)
+struct statistics_general_data {
+	u32 beacon_silence_rssi_a;
+	u32 beacon_silence_rssi_b;
+	u32 beacon_silence_rssi_c;
+	u32 beacon_energy_a;
+	u32 beacon_energy_b;
+	u32 beacon_energy_c;
+};
+
+int iwl_send_calib_results(struct iwl_priv *priv)
 {
 	int ret = 0;
 	int i = 0;
@@ -80,14 +89,16 @@
 		.meta.flags = CMD_SIZE_HUGE,
 	};
 
-	for (i = 0; i < IWL_CALIB_MAX; i++)
-		if (priv->calib_results[i].buf) {
+	for (i = 0; i < IWL_CALIB_MAX; i++) {
+		if ((BIT(i) & priv->hw_params.calib_init_cfg) &&
+		    priv->calib_results[i].buf) {
 			hcmd.len = priv->calib_results[i].buf_len;
 			hcmd.data = priv->calib_results[i].buf;
 			ret = iwl_send_cmd_sync(priv, &hcmd);
 			if (ret)
 				goto err;
 		}
+	}
 
 	return 0;
 err:
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h
index 94c8e31..1abe84b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.h
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 8d04e96..52966ff 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -66,8 +66,14 @@
  * Please use iwl-dev.h for driver implementation definitions.
  */
 
-#ifndef __iwl4965_commands_h__
-#define __iwl4965_commands_h__
+#ifndef __iwl_commands_h__
+#define __iwl_commands_h__
+
+/* uCode version contains 4 values: Major/Minor/API/Serial */
+#define IWL_UCODE_MAJOR(ver)	(((ver) & 0xFF000000) >> 24)
+#define IWL_UCODE_MINOR(ver)	(((ver) & 0x00FF0000) >> 16)
+#define IWL_UCODE_API(ver)	(((ver) & 0x0000FF00) >> 8)
+#define IWL_UCODE_SERIAL(ver)	((ver) & 0x000000FF)
 
 enum {
 	REPLY_ALIVE = 0x1,
@@ -88,6 +94,7 @@
 	REPLY_WEPKEY = 0x20,
 
 	/* RX, TX, LEDs */
+	REPLY_3945_RX = 0x1b,           /* 3945 only */
 	REPLY_TX = 0x1c,
 	REPLY_RATE_SCALE = 0x47,	/* 3945 only */
 	REPLY_LEDS_CMD = 0x48,
@@ -98,6 +105,11 @@
 	COEX_MEDIUM_NOTIFICATION = 0x5b,
 	COEX_EVENT_CMD = 0x5c,
 
+	/* Calibration */
+	CALIBRATION_CFG_CMD = 0x65,
+	CALIBRATION_RES_NOTIFICATION = 0x66,
+	CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
+
 	/* 802.11h related */
 	RADAR_NOTIFICATION = 0x70,	/* not used */
 	REPLY_QUIET_CMD = 0x71,		/* not used */
@@ -129,7 +141,7 @@
 	REPLY_TX_POWER_DBM_CMD = 0x98,
 	MEASURE_ABORT_NOTIFICATION = 0x99,	/* not used */
 
-	/* Bluetooth device coexistance config command */
+	/* Bluetooth device coexistence config command */
 	REPLY_BT_CONFIG = 0x9b,
 
 	/* Statistics */
@@ -167,8 +179,8 @@
 #define QUEUE_TO_SEQ(q)	(((q) & 0x1f) << 8)
 #define SEQ_TO_INDEX(s)	((s) & 0xff)
 #define INDEX_TO_SEQ(i)	((i) & 0xff)
-#define SEQ_HUGE_FRAME	__constant_cpu_to_le16(0x4000)
-#define SEQ_RX_FRAME	__constant_cpu_to_le16(0x8000)
+#define SEQ_HUGE_FRAME	cpu_to_le16(0x4000)
+#define SEQ_RX_FRAME	cpu_to_le16(0x8000)
 
 /**
  * struct iwl_cmd_header
@@ -180,7 +192,7 @@
 	u8 cmd;		/* Command ID:  REPLY_RXON, etc. */
 	u8 flags;	/* 0:5 reserved, 6 abort, 7 internal */
 	/*
-	 * The driver sets up the sequence number to values of its chosing.
+	 * The driver sets up the sequence number to values of its choosing.
 	 * uCode does not use this value, but passes it back to the driver
 	 * when sending the response to each driver-originated command, so
 	 * the driver can match the response to the command.  Since the values
@@ -208,10 +220,11 @@
 } __attribute__ ((packed));
 
 /**
- * 4965 rate_n_flags bit fields
+ * iwlagn rate_n_flags bit fields
  *
- * rate_n_flags format is used in following 4965 commands:
+ * rate_n_flags format is used in following iwlagn commands:
  *  REPLY_RX (response only)
+ *  REPLY_RX_MPDU (response only)
  *  REPLY_TX (both command and response)
  *  REPLY_TX_LINK_QUALITY_CMD
  *
@@ -225,8 +238,9 @@
  *        6)  54 Mbps
  *        7)  60 Mbps
  *
- *    3:  0)  Single stream (SISO)
+ *  4-3:  0)  Single stream (SISO)
  *        1)  Dual stream (MIMO)
+ *        2)  Triple stream (MIMO)
  *
  *    5:  Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data
  *
@@ -247,8 +261,8 @@
  *        110)  11 Mbps
  */
 #define RATE_MCS_CODE_MSK 0x7
-#define RATE_MCS_MIMO_POS 3
-#define RATE_MCS_MIMO_MSK 0x8
+#define RATE_MCS_SPATIAL_POS 3
+#define RATE_MCS_SPATIAL_MSK 0x18
 #define RATE_MCS_HT_DUP_POS 5
 #define RATE_MCS_HT_DUP_MSK 0x20
 
@@ -278,18 +292,20 @@
 #define RATE_MCS_SGI_MSK 0x2000
 
 /**
- * rate_n_flags Tx antenna masks (4965 has 2 transmitters):
- * bit14:15 01 B inactive, A active
- *          10 B active, A inactive
- *          11 Both active
+ * rate_n_flags Tx antenna masks
+ * 4965 has 2 transmitters
+ * 5100 has 1 transmitter B
+ * 5150 has 1 transmitter A
+ * 5300 has 3 transmitters
+ * 5350 has 3 transmitters
+ * bit14:16
  */
 #define RATE_MCS_ANT_POS      14
 #define RATE_MCS_ANT_A_MSK    0x04000
 #define RATE_MCS_ANT_B_MSK    0x08000
 #define RATE_MCS_ANT_C_MSK    0x10000
 #define RATE_MCS_ANT_ABC_MSK  0x1C000
-
-#define RATE_MCS_ANT_INIT_IND   1
+#define RATE_ANT_NUM 3
 
 #define POWER_TABLE_NUM_ENTRIES			33
 #define POWER_TABLE_NUM_HT_OFDM_ENTRIES		32
@@ -340,7 +356,7 @@
 } __attribute__ ((packed));
 
 /**
- * Commad REPLY_TX_POWER_DBM_CMD = 0x98
+ * Command REPLY_TX_POWER_DBM_CMD = 0x98
  * struct iwl5000_tx_power_dbm_cmd
  */
 #define IWL50_TX_POWER_AUTO 0x7f
@@ -359,7 +375,7 @@
  *
  *****************************************************************************/
 
-#define UCODE_VALID_OK	__constant_cpu_to_le32(0x1)
+#define UCODE_VALID_OK	cpu_to_le32(0x1)
 #define INITIALIZE_SUBTYPE    (9)
 
 /*
@@ -376,7 +392,7 @@
  * calculating txpower settings:
  *
  * 1)  Power supply voltage indication.  The voltage sensor outputs higher
- *     values for lower voltage, and vice versa.
+ *     values for lower voltage, and vice verse.
  *
  * 2)  Temperature measurement parameters, for each of two channel widths
  *     (20 MHz and 40 MHz) supported by the radios.  Temperature sensing
@@ -477,11 +493,6 @@
 } __attribute__ ((packed));
 
 
-union tsf {
-	u8 byte[8];
-	__le16 word[4];
-	__le32 dw[2];
-};
 
 /*
  * REPLY_ERROR = 0x2 (response only, not a command)
@@ -492,7 +503,7 @@
 	u8 reserved1;
 	__le16 bad_cmd_seq_num;
 	__le32 error_info;
-	union tsf timestamp;
+	__le64 timestamp;
 } __attribute__ ((packed));
 
 /******************************************************************************
@@ -513,75 +524,75 @@
 };
 
 
-#define RXON_RX_CHAIN_DRIVER_FORCE_MSK		__constant_cpu_to_le16(0x1 << 0)
-#define RXON_RX_CHAIN_VALID_MSK			__constant_cpu_to_le16(0x7 << 1)
+#define RXON_RX_CHAIN_DRIVER_FORCE_MSK		cpu_to_le16(0x1 << 0)
+#define RXON_RX_CHAIN_VALID_MSK			cpu_to_le16(0x7 << 1)
 #define RXON_RX_CHAIN_VALID_POS			(1)
-#define RXON_RX_CHAIN_FORCE_SEL_MSK		__constant_cpu_to_le16(0x7 << 4)
+#define RXON_RX_CHAIN_FORCE_SEL_MSK		cpu_to_le16(0x7 << 4)
 #define RXON_RX_CHAIN_FORCE_SEL_POS		(4)
-#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK	__constant_cpu_to_le16(0x7 << 7)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK	cpu_to_le16(0x7 << 7)
 #define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS	(7)
-#define RXON_RX_CHAIN_CNT_MSK			__constant_cpu_to_le16(0x3 << 10)
+#define RXON_RX_CHAIN_CNT_MSK			cpu_to_le16(0x3 << 10)
 #define RXON_RX_CHAIN_CNT_POS			(10)
-#define RXON_RX_CHAIN_MIMO_CNT_MSK		__constant_cpu_to_le16(0x3 << 12)
+#define RXON_RX_CHAIN_MIMO_CNT_MSK		cpu_to_le16(0x3 << 12)
 #define RXON_RX_CHAIN_MIMO_CNT_POS		(12)
-#define RXON_RX_CHAIN_MIMO_FORCE_MSK		__constant_cpu_to_le16(0x1 << 14)
+#define RXON_RX_CHAIN_MIMO_FORCE_MSK		cpu_to_le16(0x1 << 14)
 #define RXON_RX_CHAIN_MIMO_FORCE_POS		(14)
 
 /* rx_config flags */
 /* band & modulation selection */
-#define RXON_FLG_BAND_24G_MSK           __constant_cpu_to_le32(1 << 0)
-#define RXON_FLG_CCK_MSK                __constant_cpu_to_le32(1 << 1)
+#define RXON_FLG_BAND_24G_MSK           cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK                cpu_to_le32(1 << 1)
 /* auto detection enable */
-#define RXON_FLG_AUTO_DETECT_MSK        __constant_cpu_to_le32(1 << 2)
+#define RXON_FLG_AUTO_DETECT_MSK        cpu_to_le32(1 << 2)
 /* TGg protection when tx */
-#define RXON_FLG_TGG_PROTECT_MSK        __constant_cpu_to_le32(1 << 3)
+#define RXON_FLG_TGG_PROTECT_MSK        cpu_to_le32(1 << 3)
 /* cck short slot & preamble */
-#define RXON_FLG_SHORT_SLOT_MSK          __constant_cpu_to_le32(1 << 4)
-#define RXON_FLG_SHORT_PREAMBLE_MSK     __constant_cpu_to_le32(1 << 5)
+#define RXON_FLG_SHORT_SLOT_MSK          cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK     cpu_to_le32(1 << 5)
 /* antenna selection */
-#define RXON_FLG_DIS_DIV_MSK            __constant_cpu_to_le32(1 << 7)
-#define RXON_FLG_ANT_SEL_MSK            __constant_cpu_to_le32(0x0f00)
-#define RXON_FLG_ANT_A_MSK              __constant_cpu_to_le32(1 << 8)
-#define RXON_FLG_ANT_B_MSK              __constant_cpu_to_le32(1 << 9)
+#define RXON_FLG_DIS_DIV_MSK            cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK            cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK              cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK              cpu_to_le32(1 << 9)
 /* radar detection enable */
-#define RXON_FLG_RADAR_DETECT_MSK       __constant_cpu_to_le32(1 << 12)
-#define RXON_FLG_TGJ_NARROW_BAND_MSK    __constant_cpu_to_le32(1 << 13)
+#define RXON_FLG_RADAR_DETECT_MSK       cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK    cpu_to_le32(1 << 13)
 /* rx response to host with 8-byte TSF
 * (according to ON_AIR deassertion) */
-#define RXON_FLG_TSF2HOST_MSK           __constant_cpu_to_le32(1 << 15)
+#define RXON_FLG_TSF2HOST_MSK           cpu_to_le32(1 << 15)
 
 
 /* HT flags */
 #define RXON_FLG_CTRL_CHANNEL_LOC_POS		(22)
-#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK	__constant_cpu_to_le32(0x1 << 22)
+#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK	cpu_to_le32(0x1 << 22)
 
 #define RXON_FLG_HT_OPERATING_MODE_POS		(23)
 
-#define RXON_FLG_HT_PROT_MSK			__constant_cpu_to_le32(0x1 << 23)
-#define RXON_FLG_FAT_PROT_MSK			__constant_cpu_to_le32(0x2 << 23)
+#define RXON_FLG_HT_PROT_MSK			cpu_to_le32(0x1 << 23)
+#define RXON_FLG_FAT_PROT_MSK			cpu_to_le32(0x2 << 23)
 
 #define RXON_FLG_CHANNEL_MODE_POS		(25)
-#define RXON_FLG_CHANNEL_MODE_MSK		__constant_cpu_to_le32(0x3 << 25)
-#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK	__constant_cpu_to_le32(0x1 << 25)
-#define RXON_FLG_CHANNEL_MODE_MIXED_MSK		__constant_cpu_to_le32(0x2 << 25)
+#define RXON_FLG_CHANNEL_MODE_MSK		cpu_to_le32(0x3 << 25)
+#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK	cpu_to_le32(0x1 << 25)
+#define RXON_FLG_CHANNEL_MODE_MIXED_MSK		cpu_to_le32(0x2 << 25)
 /* CTS to self (if spec allows) flag */
-#define RXON_FLG_SELF_CTS_EN			__constant_cpu_to_le32(0x1<<30)
+#define RXON_FLG_SELF_CTS_EN			cpu_to_le32(0x1<<30)
 
 /* rx_config filter flags */
 /* accept all data frames */
-#define RXON_FILTER_PROMISC_MSK         __constant_cpu_to_le32(1 << 0)
+#define RXON_FILTER_PROMISC_MSK         cpu_to_le32(1 << 0)
 /* pass control & management to host */
-#define RXON_FILTER_CTL2HOST_MSK        __constant_cpu_to_le32(1 << 1)
+#define RXON_FILTER_CTL2HOST_MSK        cpu_to_le32(1 << 1)
 /* accept multi-cast */
-#define RXON_FILTER_ACCEPT_GRP_MSK      __constant_cpu_to_le32(1 << 2)
+#define RXON_FILTER_ACCEPT_GRP_MSK      cpu_to_le32(1 << 2)
 /* don't decrypt uni-cast frames */
-#define RXON_FILTER_DIS_DECRYPT_MSK     __constant_cpu_to_le32(1 << 3)
+#define RXON_FILTER_DIS_DECRYPT_MSK     cpu_to_le32(1 << 3)
 /* don't decrypt multi-cast frames */
-#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4)
 /* STA is associated */
-#define RXON_FILTER_ASSOC_MSK           __constant_cpu_to_le32(1 << 5)
+#define RXON_FILTER_ASSOC_MSK           cpu_to_le32(1 << 5)
 /* transfer to host non bssid beacons in associated state */
-#define RXON_FILTER_BCON_AWARE_MSK      __constant_cpu_to_le32(1 << 6)
+#define RXON_FILTER_BCON_AWARE_MSK      cpu_to_le32(1 << 6)
 
 /**
  * REPLY_RXON = 0x10 (command, has simple generic response)
@@ -620,7 +631,7 @@
 	u8 ofdm_ht_dual_stream_basic_rates;
 } __attribute__ ((packed));
 
-/* 5000 HW just extend this cmmand */
+/* 5000 HW just extend this command */
 struct iwl_rxon_cmd {
 	u8 node_addr[6];
 	__le16 reserved1;
@@ -679,8 +690,8 @@
 /*
  * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
  */
-struct iwl4965_rxon_time_cmd {
-	union tsf timestamp;
+struct iwl_rxon_time_cmd {
+	__le64 timestamp;
 	__le16 beacon_interval;
 	__le16 atim_window;
 	__le32 beacon_init_val;
@@ -691,7 +702,7 @@
 /*
  * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
  */
-struct iwl4965_channel_switch_cmd {
+struct iwl_channel_switch_cmd {
 	u8 band;
 	u8 expect_beacon;
 	__le16 channel;
@@ -704,7 +715,7 @@
 /*
  * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
  */
-struct iwl4965_csa_notification {
+struct iwl_csa_notification {
 	__le16 band;
 	__le16 channel;
 	__le32 status;		/* 0 - OK, 1 - fail */
@@ -741,9 +752,9 @@
 } __attribute__ ((packed));
 
 /* QoS flags defines */
-#define QOS_PARAM_FLG_UPDATE_EDCA_MSK	__constant_cpu_to_le32(0x01)
-#define QOS_PARAM_FLG_TGN_MSK		__constant_cpu_to_le32(0x02)
-#define QOS_PARAM_FLG_TXOP_TYPE_MSK	__constant_cpu_to_le32(0x10)
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK	cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK		cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK	cpu_to_le32(0x10)
 
 /* Number of Access Categories (AC) (EDCA), queues 0..3 */
 #define AC_NUM                4
@@ -780,34 +791,34 @@
 #define	IWL_STATION_COUNT	32 	/* MAX(3945,4965)*/
 #define	IWL_INVALID_STATION 	255
 
-#define STA_FLG_PWR_SAVE_MSK		__constant_cpu_to_le32(1 << 8);
-#define STA_FLG_RTS_MIMO_PROT_MSK	__constant_cpu_to_le32(1 << 17)
-#define STA_FLG_AGG_MPDU_8US_MSK	__constant_cpu_to_le32(1 << 18)
+#define STA_FLG_PWR_SAVE_MSK		cpu_to_le32(1 << 8);
+#define STA_FLG_RTS_MIMO_PROT_MSK	cpu_to_le32(1 << 17)
+#define STA_FLG_AGG_MPDU_8US_MSK	cpu_to_le32(1 << 18)
 #define STA_FLG_MAX_AGG_SIZE_POS	(19)
-#define STA_FLG_MAX_AGG_SIZE_MSK	__constant_cpu_to_le32(3 << 19)
-#define STA_FLG_FAT_EN_MSK		__constant_cpu_to_le32(1 << 21)
-#define STA_FLG_MIMO_DIS_MSK		__constant_cpu_to_le32(1 << 22)
+#define STA_FLG_MAX_AGG_SIZE_MSK	cpu_to_le32(3 << 19)
+#define STA_FLG_FAT_EN_MSK		cpu_to_le32(1 << 21)
+#define STA_FLG_MIMO_DIS_MSK		cpu_to_le32(1 << 22)
 #define STA_FLG_AGG_MPDU_DENSITY_POS	(23)
-#define STA_FLG_AGG_MPDU_DENSITY_MSK	__constant_cpu_to_le32(7 << 23)
+#define STA_FLG_AGG_MPDU_DENSITY_MSK	cpu_to_le32(7 << 23)
 
 /* Use in mode field.  1: modify existing entry, 0: add new station entry */
 #define STA_CONTROL_MODIFY_MSK		0x01
 
 /* key flags __le16*/
-#define STA_KEY_FLG_ENCRYPT_MSK	__constant_cpu_to_le16(0x0007)
-#define STA_KEY_FLG_NO_ENC	__constant_cpu_to_le16(0x0000)
-#define STA_KEY_FLG_WEP		__constant_cpu_to_le16(0x0001)
-#define STA_KEY_FLG_CCMP	__constant_cpu_to_le16(0x0002)
-#define STA_KEY_FLG_TKIP	__constant_cpu_to_le16(0x0003)
+#define STA_KEY_FLG_ENCRYPT_MSK	cpu_to_le16(0x0007)
+#define STA_KEY_FLG_NO_ENC	cpu_to_le16(0x0000)
+#define STA_KEY_FLG_WEP		cpu_to_le16(0x0001)
+#define STA_KEY_FLG_CCMP	cpu_to_le16(0x0002)
+#define STA_KEY_FLG_TKIP	cpu_to_le16(0x0003)
 
 #define STA_KEY_FLG_KEYID_POS	8
-#define STA_KEY_FLG_INVALID 	__constant_cpu_to_le16(0x0800)
+#define STA_KEY_FLG_INVALID 	cpu_to_le16(0x0800)
 /* wep key is either from global key (0) or from station info array (1) */
-#define STA_KEY_FLG_MAP_KEY_MSK	__constant_cpu_to_le16(0x0008)
+#define STA_KEY_FLG_MAP_KEY_MSK	cpu_to_le16(0x0008)
 
 /* wep key in STA: 5-bytes (0) or 13-bytes (1) */
-#define STA_KEY_FLG_KEY_SIZE_MSK     __constant_cpu_to_le16(0x1000)
-#define STA_KEY_MULTICAST_MSK        __constant_cpu_to_le16(0x4000)
+#define STA_KEY_FLG_KEY_SIZE_MSK     cpu_to_le16(0x1000)
+#define STA_KEY_MULTICAST_MSK        cpu_to_le16(0x4000)
 #define STA_KEY_MAX_NUM		8
 
 /* Flags indicate whether to modify vs. don't change various station params */
@@ -1013,33 +1024,14 @@
  *
  *****************************************************************************/
 
-struct iwl4965_rx_frame_stats {
-	u8 phy_count;
-	u8 id;
-	u8 rssi;
-	u8 agc;
-	__le16 sig_avg;
-	__le16 noise_diff;
-	u8 payload[0];
-} __attribute__ ((packed));
+#define RX_RES_STATUS_NO_CRC32_ERROR	cpu_to_le32(1 << 0)
+#define RX_RES_STATUS_NO_RXE_OVERFLOW	cpu_to_le32(1 << 1)
 
-struct iwl4965_rx_frame_hdr {
-	__le16 channel;
-	__le16 phy_flags;
-	u8 reserved1;
-	u8 rate;
-	__le16 len;
-	u8 payload[0];
-} __attribute__ ((packed));
-
-#define RX_RES_STATUS_NO_CRC32_ERROR	__constant_cpu_to_le32(1 << 0)
-#define RX_RES_STATUS_NO_RXE_OVERFLOW	__constant_cpu_to_le32(1 << 1)
-
-#define RX_RES_PHY_FLAGS_BAND_24_MSK	__constant_cpu_to_le16(1 << 0)
-#define RX_RES_PHY_FLAGS_MOD_CCK_MSK		__constant_cpu_to_le16(1 << 1)
-#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	__constant_cpu_to_le16(1 << 2)
-#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK	__constant_cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK		__constant_cpu_to_le16(0xf0)
+#define RX_RES_PHY_FLAGS_BAND_24_MSK	cpu_to_le16(1 << 0)
+#define RX_RES_PHY_FLAGS_MOD_CCK_MSK		cpu_to_le16(1 << 1)
+#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	cpu_to_le16(1 << 2)
+#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK	cpu_to_le16(1 << 3)
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK		cpu_to_le16(0xf0)
 
 #define RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
 #define RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
@@ -1062,26 +1054,6 @@
 #define RX_MPDU_RES_STATUS_TTAK_OK	(1 << 7)
 #define RX_MPDU_RES_STATUS_DEC_DONE_MSK	(0x800)
 
-struct iwl4965_rx_frame_end {
-	__le32 status;
-	__le64 timestamp;
-	__le32 beacon_timestamp;
-} __attribute__ ((packed));
-
-/*
- * REPLY_3945_RX = 0x1b (response only, not a command)
- *
- * NOTE:  DO NOT dereference from casts to this structure
- * It is provided only for calculating minimum data set size.
- * The actual offsets of the hdr and end are dynamic based on
- * stats.phy_count
- */
-struct iwl4965_rx_frame {
-	struct iwl4965_rx_frame_stats stats;
-	struct iwl4965_rx_frame_hdr hdr;
-	struct iwl4965_rx_frame_end end;
-} __attribute__ ((packed));
-
 /* Fixed (non-configurable) rx data from phy */
 
 #define IWL49_RX_RES_PHY_CNT 14
@@ -1111,7 +1083,7 @@
 #define IWL50_OFDM_RSSI_C_BIT_POS 0
 
 struct iwl5000_non_cfg_phy {
-	__le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT];  /* upto 8 phy entries */
+	__le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT];  /* up to 8 phy entries */
 } __attribute__ ((packed));
 
 
@@ -1167,24 +1139,24 @@
 
 /* REPLY_TX Tx flags field */
 
-/* 1: Use RTS/CTS protocol or CTS-to-self if spec alows it
+/* 1: Use RTS/CTS protocol or CTS-to-self if spec allows it
  * before this frame. if CTS-to-self required check
  * RXON_FLG_SELF_CTS_EN status. */
-#define TX_CMD_FLG_RTS_CTS_MSK __constant_cpu_to_le32(1 << 0)
+#define TX_CMD_FLG_RTS_CTS_MSK cpu_to_le32(1 << 0)
 
 /* 1: Use Request-To-Send protocol before this frame.
  * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
-#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1)
 
 /* 1: Transmit Clear-To-Send to self before this frame.
  * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
  * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
-#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2)
 
 /* 1: Expect ACK from receiving station
  * 0: Don't expect ACK (MAC header's duration field s/b 0)
  * Set this for unicast frames, but not broadcast/multicast. */
-#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
+#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3)
 
 /* For 4965:
  * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
@@ -1192,40 +1164,40 @@
  *    uCode walks through table for additional Tx attempts.
  * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
  *    This rate will be used for all Tx attempts; it will not be scaled. */
-#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
+#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4)
 
 /* 1: Expect immediate block-ack.
  * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
-#define TX_CMD_FLG_IMM_BA_RSP_MASK  __constant_cpu_to_le32(1 << 6)
+#define TX_CMD_FLG_IMM_BA_RSP_MASK  cpu_to_le32(1 << 6)
 
 /* 1: Frame requires full Tx-Op protection.
  * Set this if either RTS or CTS Tx Flag gets set. */
-#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7)
 
 /* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
  * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
-#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
-#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
-#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK cpu_to_le32(1 << 9)
 
 /* 1: Ignore Bluetooth priority for this frame.
  * 0: Delay Tx until Bluetooth device is done (normal usage). */
-#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+#define TX_CMD_FLG_BT_DIS_MSK cpu_to_le32(1 << 12)
 
 /* 1: uCode overrides sequence control field in MAC header.
  * 0: Driver provides sequence control field in MAC header.
  * Set this for management frames, non-QOS data frames, non-unicast frames,
  * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
-#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
+#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13)
 
 /* 1: This frame is non-last MPDU; more fragments are coming.
  * 0: Last fragment, or not using fragmentation. */
-#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
+#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14)
 
 /* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
  * 0: No TSF required in outgoing frame.
  * Set this for transmitting beacons and probe responses. */
-#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
+#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16)
 
 /* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
  *    alignment of frame's payload data field.
@@ -1233,14 +1205,14 @@
  * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
  * field (but not both).  Driver must align frame data (i.e. data following
  * MAC header) to DWORD boundary. */
-#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
+#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20)
 
 /* accelerate aggregation support
  * 0 - no CCMP encryption; 1 - CCMP encryption */
-#define TX_CMD_FLG_AGG_CCMP_MSK __constant_cpu_to_le32(1 << 22)
+#define TX_CMD_FLG_AGG_CCMP_MSK cpu_to_le32(1 << 22)
 
 /* HCCA-AP - disable duration overwriting. */
-#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25)
 
 
 /*
@@ -1266,7 +1238,7 @@
  * Used for managing Tx retries when expecting block-acks.
  * Driver should set these fields to 0.
  */
-struct iwl4965_dram_scratch {
+struct iwl_dram_scratch {
 	u8 try_cnt;		/* Tx attempts */
 	u8 bt_kill_cnt;		/* Tx attempts blocked by Bluetooth device */
 	__le16 reserved;
@@ -1297,9 +1269,9 @@
 
 	__le32 tx_flags;	/* TX_CMD_FLG_* */
 
-	/* 4965's uCode may modify this field of the Tx command (in host DRAM!).
+	/* uCode may modify this field of the Tx command (in host DRAM!).
 	 * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */
-	struct iwl4965_dram_scratch scratch;
+	struct iwl_dram_scratch scratch;
 
 	/* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */
 	__le32 rate_n_flags;	/* RATE_MCS_* */
@@ -1411,21 +1383,21 @@
 };
 
 enum {
-	TX_STATUS_MSK = 0x000000ff,	/* bits 0:7 */
+	TX_STATUS_MSK = 0x000000ff,		/* bits 0:7 */
 	TX_STATUS_DELAY_MSK = 0x00000040,
 	TX_STATUS_ABORT_MSK = 0x00000080,
 	TX_PACKET_MODE_MSK = 0x0000ff00,	/* bits 8:15 */
 	TX_FIFO_NUMBER_MSK = 0x00070000,	/* bits 16:18 */
-	TX_RESERVED = 0x00780000,	/* bits 19:22 */
+	TX_RESERVED = 0x00780000,		/* bits 19:22 */
 	TX_POWER_PA_DETECT_MSK = 0x7f800000,	/* bits 23:30 */
 	TX_ABORT_REQUIRED_MSK = 0x80000000,	/* bits 31:31 */
 };
 
-static inline int iwl_is_tx_success(u32 status)
+static inline bool iwl_is_tx_success(u32 status)
 {
 	status &= TX_STATUS_MSK;
-	return (status == TX_STATUS_SUCCESS)
-	    || (status == TX_STATUS_DIRECT_DONE);
+	return (status == TX_STATUS_SUCCESS) ||
+	       (status == TX_STATUS_DIRECT_DONE);
 }
 
 
@@ -1450,10 +1422,9 @@
 	AGG_TX_STATE_DELAY_TX_MSK = 0x400
 };
 
-#define AGG_TX_STATE_LAST_SENT_MSK \
-(AGG_TX_STATE_LAST_SENT_TTL_MSK | \
- AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
- AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
+#define AGG_TX_STATE_LAST_SENT_MSK  (AGG_TX_STATE_LAST_SENT_TTL_MSK | \
+				     AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
+				     AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
 
 /* # tx attempts for first frame in aggregation */
 #define AGG_TX_STATE_TRY_CNT_POS 12
@@ -1526,6 +1497,28 @@
 	} u;
 } __attribute__ ((packed));
 
+/*
+ * definitions for initial rate index field
+ * bits [3:0] initial rate index
+ * bits [6:4] rate table color, used for the initial rate
+ * bit-7 invalid rate indication
+ *   i.e. rate was not chosen from rate table
+ *   or rate table color was changed during frame retries
+ * refer tlc rate info
+ */
+
+#define IWL50_TX_RES_INIT_RATE_INDEX_POS	0
+#define IWL50_TX_RES_INIT_RATE_INDEX_MSK	0x0f
+#define IWL50_TX_RES_RATE_TABLE_COLOR_POS	4
+#define IWL50_TX_RES_RATE_TABLE_COLOR_MSK	0x70
+#define IWL50_TX_RES_INV_RATE_INDEX_MSK	0x80
+
+/* refer to ra_tid */
+#define IWL50_TX_RES_TID_POS	0
+#define IWL50_TX_RES_TID_MSK	0x0f
+#define IWL50_TX_RES_RA_POS	4
+#define IWL50_TX_RES_RA_MSK	0xf0
+
 struct iwl5000_tx_resp {
 	u8 frame_count;		/* 1 no aggregation, >1 aggregation */
 	u8 bt_kill_count;	/* # blocked by bluetooth (unused for agg) */
@@ -1540,14 +1533,17 @@
 	 * For agg:  RTS + CTS + aggregation tx time + block-ack time. */
 	__le16 wireless_media_time;	/* uSecs */
 
-	__le16 reserved;
-	__le32 pa_power1;	/* RF power amplifier measurement (not used) */
-	__le32 pa_power2;
+	u8 pa_status;		/* RF power amplifier measurement (not used) */
+	u8 pa_integ_res_a[3];
+	u8 pa_integ_res_b[3];
+	u8 pa_integ_res_C[3];
 
 	__le32 tfd_info;
 	__le16 seq_ctl;
 	__le16 byte_cnt;
-	__le32 tlc_info;
+	u8 tlc_info;
+	u8 ra_tid;		/* tid (0:3), sta_id (4:7) */
+	__le16 frame_ctrl;
 	/*
 	 * For non-agg:  frame status TX_STATUS_*
 	 * For agg:  status of 1st frame, AGG_TX_STATE_*; other frame status
@@ -1742,7 +1738,7 @@
  * match the modulation characteristics of the history set.
  *
  * When using block-ack (aggregation), all frames are transmitted at the same
- * rate, since there is no per-attempt acknowledgement from the destination
+ * rate, since there is no per-attempt acknowledgment from the destination
  * station.  The Tx response struct iwl_tx_resp indicates the Tx rate in
  * rate_n_flags field.  After receiving a block-ack, the driver can update
  * history for the entire block all at once.
@@ -1881,9 +1877,9 @@
  *
  * 3945 and 4965 support hardware handshake with Bluetooth device on
  * same platform.  Bluetooth device alerts wireless device when it will Tx;
- * wireless device can delay or kill its own Tx to accomodate.
+ * wireless device can delay or kill its own Tx to accommodate.
  */
-struct iwl4965_bt_cmd {
+struct iwl_bt_cmd {
 	u8 flags;
 	u8 lead_time;
 	u8 max_kill;
@@ -1909,18 +1905,18 @@
 				 RXON_FILTER_ASSOC_MSK           | \
 				 RXON_FILTER_BCON_AWARE_MSK)
 
-struct iwl4965_measure_channel {
+struct iwl_measure_channel {
 	__le32 duration;	/* measurement duration in extended beacon
 				 * format */
 	u8 channel;		/* channel to measure */
-	u8 type;		/* see enum iwl4965_measure_type */
+	u8 type;		/* see enum iwl_measure_type */
 	__le16 reserved;
 } __attribute__ ((packed));
 
 /*
  * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
  */
-struct iwl4965_spectrum_cmd {
+struct iwl_spectrum_cmd {
 	__le16 len;		/* number of bytes starting from token */
 	u8 token;		/* token id */
 	u8 id;			/* measurement id -- 0 or 1 */
@@ -1933,13 +1929,13 @@
 	__le32 filter_flags;	/* rxon filter flags */
 	__le16 channel_count;	/* minimum 1, maximum 10 */
 	__le16 reserved3;
-	struct iwl4965_measure_channel channels[10];
+	struct iwl_measure_channel channels[10];
 } __attribute__ ((packed));
 
 /*
  * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
  */
-struct iwl4965_spectrum_resp {
+struct iwl_spectrum_resp {
 	u8 token;
 	u8 id;			/* id of the prior command replaced, or 0xff */
 	__le16 status;		/* 0 - command will be handled
@@ -1947,12 +1943,12 @@
 				 *     measurement) */
 } __attribute__ ((packed));
 
-enum iwl4965_measurement_state {
+enum iwl_measurement_state {
 	IWL_MEASUREMENT_START = 0,
 	IWL_MEASUREMENT_STOP = 1,
 };
 
-enum iwl4965_measurement_status {
+enum iwl_measurement_status {
 	IWL_MEASUREMENT_OK = 0,
 	IWL_MEASUREMENT_CONCURRENT = 1,
 	IWL_MEASUREMENT_CSA_CONFLICT = 2,
@@ -1965,18 +1961,18 @@
 
 #define NUM_ELEMENTS_IN_HISTOGRAM 8
 
-struct iwl4965_measurement_histogram {
+struct iwl_measurement_histogram {
 	__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 0.8usec counts */
 	__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 1usec counts */
 } __attribute__ ((packed));
 
 /* clear channel availability counters */
-struct iwl4965_measurement_cca_counters {
+struct iwl_measurement_cca_counters {
 	__le32 ofdm;
 	__le32 cck;
 } __attribute__ ((packed));
 
-enum iwl4965_measure_type {
+enum iwl_measure_type {
 	IWL_MEASURE_BASIC = (1 << 0),
 	IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
 	IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
@@ -1989,7 +1985,7 @@
 /*
  * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
  */
-struct iwl4965_spectrum_notification {
+struct iwl_spectrum_notification {
 	u8 id;			/* measurement id -- 0 or 1 */
 	u8 token;
 	u8 channel_index;	/* index in measurement channel list */
@@ -1997,7 +1993,7 @@
 	__le32 start_time;	/* lower 32-bits of TSF */
 	u8 band;		/* 0 - 5.2GHz, 1 - 2.4GHz */
 	u8 channel;
-	u8 type;		/* see enum iwl4965_measurement_type */
+	u8 type;		/* see enum iwl_measurement_type */
 	u8 reserved1;
 	/* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
 	 * valid if applicable for measurement type requested. */
@@ -2007,9 +2003,9 @@
 	u8 basic_type;		/* 0 - bss, 1 - ofdm preamble, 2 -
 				 * unidentified */
 	u8 reserved2[3];
-	struct iwl4965_measurement_histogram histogram;
+	struct iwl_measurement_histogram histogram;
 	__le32 stop_time;	/* lower 32-bits of TSF */
-	__le32 status;		/* see iwl4965_measurement_status */
+	__le32 status;		/* see iwl_measurement_status */
 } __attribute__ ((packed));
 
 /******************************************************************************
@@ -2043,15 +2039,15 @@
  *              '11' Illegal set
  *
  * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
- * ucode assume sleep over DTIM is allowed and we don't need to wakeup
+ * ucode assume sleep over DTIM is allowed and we don't need to wake up
  * for every DTIM.
  */
 #define IWL_POWER_VEC_SIZE 5
 
-#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le16(1 << 0)
-#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le16(1 << 2)
-#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le16(1 << 3)
-#define IWL_POWER_FAST_PD			__constant_cpu_to_le16(1 << 4)
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	cpu_to_le16(1 << 0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK		cpu_to_le16(1 << 2)
+#define IWL_POWER_PCI_PM_MSK			cpu_to_le16(1 << 3)
+#define IWL_POWER_FAST_PD			cpu_to_le16(1 << 4)
 
 struct iwl_powertable_cmd {
 	__le16 flags;
@@ -2067,7 +2063,7 @@
  * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
  * 3945 and 4965 identical.
  */
-struct iwl4965_sleep_notification {
+struct iwl_sleep_notification {
 	u8 pm_sleep_mode;
 	u8 pm_wakeup_src;
 	__le16 reserved;
@@ -2097,14 +2093,14 @@
 #define CARD_STATE_CMD_DISABLE 0x00	/* Put card to sleep */
 #define CARD_STATE_CMD_ENABLE  0x01	/* Wake up card */
 #define CARD_STATE_CMD_HALT    0x02	/* Power down permanently */
-struct iwl4965_card_state_cmd {
+struct iwl_card_state_cmd {
 	__le32 status;		/* CARD_STATE_CMD_* request new power state */
 } __attribute__ ((packed));
 
 /*
  * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
  */
-struct iwl4965_card_state_notif {
+struct iwl_card_state_notif {
 	__le32 flags;
 } __attribute__ ((packed));
 
@@ -2125,8 +2121,8 @@
  *
  *****************************************************************************/
 
-#define SCAN_CHANNEL_TYPE_PASSIVE __constant_cpu_to_le32(0)
-#define SCAN_CHANNEL_TYPE_ACTIVE  __constant_cpu_to_le32(1)
+#define SCAN_CHANNEL_TYPE_PASSIVE cpu_to_le32(0)
+#define SCAN_CHANNEL_TYPE_ACTIVE  cpu_to_le32(1)
 
 /**
  * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
@@ -2167,7 +2163,7 @@
  * struct iwl_ssid_ie - directed scan network information element
  *
  * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field
- * in struct iwl4965_scan_channel; each channel may select different ssids from
+ * in struct iwl_scan_channel; each channel may select different ssids from
  * among the 4 entries.  SSID IEs get transmitted in reverse order of entry.
  */
 struct iwl_ssid_ie {
@@ -2177,8 +2173,8 @@
 } __attribute__ ((packed));
 
 #define PROBE_OPTION_MAX        	0x14
-#define TX_CMD_LIFE_TIME_INFINITE	__constant_cpu_to_le32(0xFFFFFFFF)
-#define IWL_GOOD_CRC_TH			__constant_cpu_to_le16(1)
+#define TX_CMD_LIFE_TIME_INFINITE	cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH			cpu_to_le16(1)
 #define IWL_MAX_SCAN_SIZE 1024
 
 /*
@@ -2267,7 +2263,7 @@
 	 * Number of channels in list is specified by channel_count.
 	 * Each channel in list is of type:
 	 *
-	 * struct iwl4965_scan_channel channels[0];
+	 * struct iwl_scan_channel channels[0];
 	 *
 	 * NOTE:  Only one band of channels can be scanned per pass.  You
 	 * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
@@ -2278,7 +2274,7 @@
 } __attribute__ ((packed));
 
 /* Can abort will notify by complete notification with abort status. */
-#define CAN_ABORT_STATUS	__constant_cpu_to_le32(0x1)
+#define CAN_ABORT_STATUS	cpu_to_le32(0x1)
 /* complete notification statuses */
 #define ABORT_STATUS            0x2
 
@@ -2422,6 +2418,8 @@
 	__le32 reserved2;
 } __attribute__ ((packed));
 
+#define INTERFERENCE_DATA_AVAILABLE      __constant_cpu_to_le32(1)
+
 struct statistics_rx_non_phy {
 	__le32 bogus_cts;	/* CTS received when not expecting CTS */
 	__le32 bogus_ack;	/* ACK received when not expecting ACK */
@@ -2540,8 +2538,8 @@
  * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
  * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
  */
-#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1)	/* see above */
-#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1)	/* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */
 struct iwl_statistics_cmd {
 	__le32 configuration_flags;	/* IWL_STATS_CONF_* */
 } __attribute__ ((packed));
@@ -2561,8 +2559,8 @@
  * appropriately so that each notification contains statistics for only the
  * one channel that has just been scanned.
  */
-#define STATISTICS_REPLY_FLG_BAND_24G_MSK         __constant_cpu_to_le32(0x2)
-#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         __constant_cpu_to_le32(0x8)
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK         cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         cpu_to_le32(0x8)
 struct iwl_notif_statistics {
 	__le32 flag;
 	struct statistics_rx rx;
@@ -2578,7 +2576,7 @@
  * then this notification will be sent. */
 #define CONSECUTIVE_MISSED_BCONS_TH 20
 
-struct iwl4965_missed_beacon_notif {
+struct iwl_missed_beacon_notif {
 	__le32 consequtive_missed_beacons;
 	__le32 total_missed_becons;
 	__le32 num_expected_beacons;
@@ -2778,8 +2776,8 @@
 #define HD_OFDM_ENERGY_TH_IN_INDEX                  (10)
 
 /* Control field in struct iwl_sensitivity_cmd */
-#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE	__constant_cpu_to_le16(0)
-#define SENSITIVITY_CMD_CONTROL_WORK_TABLE	__constant_cpu_to_le16(1)
+#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE	cpu_to_le16(0)
+#define SENSITIVITY_CMD_CONTROL_WORK_TABLE	cpu_to_le16(1)
 
 /**
  * struct iwl_sensitivity_cmd
@@ -2849,56 +2847,26 @@
  * 1-0: amount of gain, units of 1.5 dB
  */
 
-/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */
-#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
-
-struct iwl4965_calibration_cmd {
-	u8 opCode;		/* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */
-	u8 flags;		/* not used */
-	__le16 reserved;
-	s8 diff_gain_a;		/* see above */
-	s8 diff_gain_b;
-	s8 diff_gain_c;
-	u8 reserved1;
-} __attribute__ ((packed));
-
-/* Phy calibration command for 5000 series */
+/* Phy calibration command for series */
 
 enum {
-	IWL5000_PHY_CALIBRATE_DC_CMD		= 8,
-	IWL5000_PHY_CALIBRATE_LO_CMD		= 9,
-	IWL5000_PHY_CALIBRATE_RX_BB_CMD		= 10,
-	IWL5000_PHY_CALIBRATE_TX_IQ_CMD		= 11,
-	IWL5000_PHY_CALIBRATE_RX_IQ_CMD		= 12,
-	IWL5000_PHY_CALIBRATION_NOISE_CMD	= 13,
-	IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD	= 14,
-	IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD	= 15,
-	IWL5000_PHY_CALIBRATE_BASE_BAND_CMD	= 16,
-	IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD	= 17,
-	IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18,
-	IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19,
+	IWL_PHY_CALIBRATE_DIFF_GAIN_CMD		= 7,
+	IWL_PHY_CALIBRATE_DC_CMD		= 8,
+	IWL_PHY_CALIBRATE_LO_CMD		= 9,
+	IWL_PHY_CALIBRATE_RX_BB_CMD		= 10,
+	IWL_PHY_CALIBRATE_TX_IQ_CMD		= 11,
+	IWL_PHY_CALIBRATE_RX_IQ_CMD		= 12,
+	IWL_PHY_CALIBRATION_NOISE_CMD		= 13,
+	IWL_PHY_CALIBRATE_AGC_TABLE_CMD		= 14,
+	IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD	= 15,
+	IWL_PHY_CALIBRATE_BASE_BAND_CMD		= 16,
+	IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD	= 17,
+	IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD	= 18,
+	IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD	= 19,
 };
 
-enum {
-	CALIBRATION_CFG_CMD = 0x65,
-	CALIBRATION_RES_NOTIFICATION = 0x66,
-	CALIBRATION_COMPLETE_NOTIFICATION = 0x67
-};
 
-struct iwl_cal_crystal_freq_cmd {
-	u8 cap_pin1;
-	u8 cap_pin2;
-} __attribute__ ((packed));
-
-struct iwl5000_calibration {
-	u8 op_code;
-	u8 first_group;
-	u8 num_groups;
-	u8 all_data_valid;
-	struct iwl_cal_crystal_freq_cmd data;
-} __attribute__ ((packed));
-
-#define IWL_CALIB_INIT_CFG_ALL	__constant_cpu_to_le32(0xffffffff)
+#define IWL_CALIB_INIT_CFG_ALL	cpu_to_le32(0xffffffff)
 
 struct iwl_calib_cfg_elmnt_s {
 	__le32 is_enable;
@@ -2914,32 +2882,52 @@
 	__le32 flags;
 } __attribute__ ((packed));
 
-struct iwl5000_calib_cfg_cmd {
+struct iwl_calib_cfg_cmd {
 	struct iwl_calib_cfg_status_s ucd_calib_cfg;
 	struct iwl_calib_cfg_status_s drv_calib_cfg;
 	__le32 reserved1;
 } __attribute__ ((packed));
 
-struct iwl5000_calib_hdr {
+struct iwl_calib_hdr {
 	u8 op_code;
 	u8 first_group;
 	u8 groups_num;
 	u8 data_valid;
 } __attribute__ ((packed));
 
-struct iwl5000_calibration_chain_noise_reset_cmd {
-	u8 op_code;	/* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
-	u8 flags;	/* not used */
-	__le16 reserved;
+struct iwl_calib_cmd {
+	struct iwl_calib_hdr hdr;
+	u8 data[0];
 } __attribute__ ((packed));
 
-struct iwl5000_calibration_chain_noise_gain_cmd {
-	u8 op_code;	/* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */
-	u8 flags;	/* not used */
-	__le16 reserved;
+/* IWL_PHY_CALIBRATE_DIFF_GAIN_CMD (7) */
+struct iwl_calib_diff_gain_cmd {
+	struct iwl_calib_hdr hdr;
+	s8 diff_gain_a;		/* see above */
+	s8 diff_gain_b;
+	s8 diff_gain_c;
+	u8 reserved1;
+} __attribute__ ((packed));
+
+struct iwl_calib_xtal_freq_cmd {
+	struct iwl_calib_hdr hdr;
+	u8 cap_pin1;
+	u8 cap_pin2;
+	u8 pad[2];
+} __attribute__ ((packed));
+
+/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
+struct iwl_calib_chain_noise_reset_cmd {
+	struct iwl_calib_hdr hdr;
+	u8 data[0];
+};
+
+/* IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */
+struct iwl_calib_chain_noise_gain_cmd {
+	struct iwl_calib_hdr hdr;
 	u8 delta_gain_1;
 	u8 delta_gain_2;
-	__le16 reserved1;
+	u8 pad[2];
 } __attribute__ ((packed));
 
 /******************************************************************************
@@ -2999,11 +2987,11 @@
 
 /* COEX flag masks */
 
-/* Staion table is valid */
+/* Station table is valid */
 #define COEX_FLAGS_STA_TABLE_VALID_MSK      (0x1)
-/* UnMask wakeup src at unassociated sleep */
+/* UnMask wake up src at unassociated sleep */
 #define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK    (0x4)
-/* UnMask wakeup src at associated sleep */
+/* UnMask wake up src at associated sleep */
 #define COEX_FLAGS_ASSOC_WA_UNMASK_MSK      (0x8)
 /* Enable CoEx feature. */
 #define COEX_FLAGS_COEX_ENABLE_MSK          (0x80)
@@ -3025,26 +3013,22 @@
 	struct iwl_cmd_header hdr;
 	union {
 		struct iwl_alive_resp alive_frame;
-		struct iwl4965_rx_frame rx_frame;
-		struct iwl4965_tx_resp tx_resp;
-		struct iwl4965_spectrum_notification spectrum_notif;
-		struct iwl4965_csa_notification csa_notif;
+		struct iwl_spectrum_notification spectrum_notif;
+		struct iwl_csa_notification csa_notif;
 		struct iwl_error_resp err_resp;
-		struct iwl4965_card_state_notif card_state_notif;
-		struct iwl4965_beacon_notif beacon_status;
+		struct iwl_card_state_notif card_state_notif;
 		struct iwl_add_sta_resp add_sta;
 		struct iwl_rem_sta_resp rem_sta;
-		struct iwl4965_sleep_notification sleep_notif;
-		struct iwl4965_spectrum_resp spectrum;
+		struct iwl_sleep_notification sleep_notif;
+		struct iwl_spectrum_resp spectrum;
 		struct iwl_notif_statistics stats;
 		struct iwl_compressed_ba_resp compressed_ba;
-		struct iwl4965_missed_beacon_notif missed_beacon;
-		struct iwl5000_calibration calib;
+		struct iwl_missed_beacon_notif missed_beacon;
 		__le32 status;
 		u8 raw[0];
 	} u;
 } __attribute__ ((packed));
 
-#define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl4965_rx_frame))
+int iwl_agn_check_rxon_cmd(struct iwl_rxon_cmd *rxon);
 
-#endif				/* __iwl4965_commands_h__ */
+#endif				/* __iwl_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 01a8458..73d7973 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -22,7 +22,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
 
@@ -30,19 +30,19 @@
 #include <linux/module.h>
 #include <net/mac80211.h>
 
-struct iwl_priv; /* FIXME: remove */
-#include "iwl-debug.h"
 #include "iwl-eeprom.h"
 #include "iwl-dev.h" /* FIXME: remove */
+#include "iwl-debug.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-rfkill.h"
 #include "iwl-power.h"
+#include "iwl-sta.h"
 
 
 MODULE_DESCRIPTION("iwl core");
 MODULE_VERSION(IWLWIFI_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 
 #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
@@ -88,26 +88,27 @@
  * translate ucode response to mac80211 tx status control values
  */
 void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
-				  struct ieee80211_tx_info *control)
+				  struct ieee80211_tx_info *info)
 {
 	int rate_index;
+	struct ieee80211_tx_rate *r = &info->control.rates[0];
 
-	control->antenna_sel_tx =
+	info->antenna_sel_tx =
 		((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
 	if (rate_n_flags & RATE_MCS_HT_MSK)
-		control->flags |= IEEE80211_TX_CTL_OFDM_HT;
+		r->flags |= IEEE80211_TX_RC_MCS;
 	if (rate_n_flags & RATE_MCS_GF_MSK)
-		control->flags |= IEEE80211_TX_CTL_GREEN_FIELD;
+		r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
 	if (rate_n_flags & RATE_MCS_FAT_MSK)
-		control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH;
+		r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
 	if (rate_n_flags & RATE_MCS_DUP_MSK)
-		control->flags |= IEEE80211_TX_CTL_DUP_DATA;
+		r->flags |= IEEE80211_TX_RC_DUP_DATA;
 	if (rate_n_flags & RATE_MCS_SGI_MSK)
-		control->flags |= IEEE80211_TX_CTL_SHORT_GI;
+		r->flags |= IEEE80211_TX_RC_SHORT_GI;
 	rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags);
-	if (control->band == IEEE80211_BAND_5GHZ)
+	if (info->band == IEEE80211_BAND_5GHZ)
 		rate_index -= IWL_FIRST_OFDM_RATE;
-	control->tx_rate_idx = rate_index;
+	r->idx = rate_index;
 }
 EXPORT_SYMBOL(iwl_hwrate_to_tx_control);
 
@@ -119,7 +120,9 @@
 	if (rate_n_flags & RATE_MCS_HT_MSK) {
 		idx = (rate_n_flags & 0xff);
 
-		if (idx >= IWL_RATE_MIMO2_6M_PLCP)
+		if (idx >= IWL_RATE_MIMO3_6M_PLCP)
+			idx = idx - IWL_RATE_MIMO3_6M_PLCP;
+		else if (idx >= IWL_RATE_MIMO2_6M_PLCP)
 			idx = idx - IWL_RATE_MIMO2_6M_PLCP;
 
 		idx += IWL_FIRST_OFDM_RATE;
@@ -140,7 +143,17 @@
 }
 EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx);
 
-
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
+{
+	int i;
+	u8 ind = ant;
+	for (i = 0; i < RATE_ANT_NUM - 1; i++) {
+		ind = (ind + 1) < RATE_ANT_NUM ?  ind + 1 : 0;
+		if (priv->hw_params.valid_tx_ant & BIT(ind))
+			return ind;
+	}
+	return ant;
+}
 
 const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 EXPORT_SYMBOL(iwl_bcast_addr);
@@ -177,52 +190,6 @@
 }
 EXPORT_SYMBOL(iwl_hw_detect);
 
-/* Tell nic where to find the "keep warm" buffer */
-int iwl_kw_init(struct iwl_priv *priv)
-{
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	ret = iwl_grab_nic_access(priv);
-	if (ret)
-		goto out;
-
-	iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG,
-			     priv->kw.dma_addr >> 4);
-	iwl_release_nic_access(priv);
-out:
-	spin_unlock_irqrestore(&priv->lock, flags);
-	return ret;
-}
-
-int iwl_kw_alloc(struct iwl_priv *priv)
-{
-	struct pci_dev *dev = priv->pci_dev;
-	struct iwl_kw *kw = &priv->kw;
-
-	kw->size = IWL_KW_SIZE;
-	kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
-	if (!kw->v_addr)
-		return -ENOMEM;
-
-	return 0;
-}
-
-/**
- * iwl_kw_free - Free the "keep warm" buffer
- */
-void iwl_kw_free(struct iwl_priv *priv)
-{
-	struct pci_dev *dev = priv->pci_dev;
-	struct iwl_kw *kw = &priv->kw;
-
-	if (kw->v_addr) {
-		pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
-		memset(kw, 0, sizeof(*kw));
-	}
-}
-
 int iwl_hw_nic_init(struct iwl_priv *priv)
 {
 	unsigned long flags;
@@ -271,55 +238,30 @@
 }
 EXPORT_SYMBOL(iwl_hw_nic_init);
 
-/**
- * iwl_clear_stations_table - Clear the driver's station table
- *
- * NOTE:  This does not clear or otherwise alter the device's station table.
- */
-void iwl_clear_stations_table(struct iwl_priv *priv)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-
-	if (iwl_is_alive(priv) &&
-	   !test_bit(STATUS_EXIT_PENDING, &priv->status) &&
-	   iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL))
-		IWL_ERROR("Couldn't clear the station table\n");
-
-	priv->num_stations = 0;
-	memset(priv->stations, 0, sizeof(priv->stations));
-
-	/* clean ucode key table bit map */
-	priv->ucode_key_table = 0;
-
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-}
-EXPORT_SYMBOL(iwl_clear_stations_table);
-
 void iwl_reset_qos(struct iwl_priv *priv)
 {
 	u16 cw_min = 15;
 	u16 cw_max = 1023;
 	u8 aifs = 2;
-	u8 is_legacy = 0;
+	bool is_legacy = false;
 	unsigned long flags;
 	int i;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	priv->qos_data.qos_active = 0;
+	/* QoS always active in AP and ADHOC mode
+	 * In STA mode wait for association
+	 */
+	if (priv->iw_mode == NL80211_IFTYPE_ADHOC ||
+	    priv->iw_mode == NL80211_IFTYPE_AP)
+		priv->qos_data.qos_active = 1;
+	else
+		priv->qos_data.qos_active = 0;
 
-	if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
-		if (priv->qos_data.qos_enable)
-			priv->qos_data.qos_active = 1;
-		if (!(priv->active_rate & 0xfff0)) {
-			cw_min = 31;
-			is_legacy = 1;
-		}
-	} else if (priv->iw_mode == NL80211_IFTYPE_AP) {
-		if (priv->qos_data.qos_enable)
-			priv->qos_data.qos_active = 1;
-	} else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+	/* check for legacy mode */
+	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+	    (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) ||
+	    (priv->iw_mode == NL80211_IFTYPE_STATION &&
+	    (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) {
 		cw_min = 31;
 		is_legacy = 1;
 	}
@@ -385,10 +327,10 @@
 }
 EXPORT_SYMBOL(iwl_reset_qos);
 
-#define MAX_BIT_RATE_40_MHZ 0x96 /* 150 Mbps */
-#define MAX_BIT_RATE_20_MHZ 0x48 /* 72 Mbps */
+#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
+#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
 static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
-			      struct ieee80211_ht_info *ht_info,
+			      struct ieee80211_sta_ht_cap *ht_info,
 			      enum ieee80211_band band)
 {
 	u16 max_bit_rate = 0;
@@ -396,45 +338,46 @@
 	u8 tx_chains_num = priv->hw_params.tx_chains_num;
 
 	ht_info->cap = 0;
-	memset(ht_info->supp_mcs_set, 0, 16);
+	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
 
-	ht_info->ht_supported = 1;
+	ht_info->ht_supported = true;
 
-	ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD;
-	ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
-	ht_info->cap |= (u16)(IEEE80211_HT_CAP_SM_PS &
+	ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+	ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+	ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
 			     (WLAN_HT_CAP_SM_PS_DISABLED << 2));
 
 	max_bit_rate = MAX_BIT_RATE_20_MHZ;
 	if (priv->hw_params.fat_channel & BIT(band)) {
-		ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
-		ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
-		ht_info->supp_mcs_set[4] = 0x01;
+		ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+		ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
+		ht_info->mcs.rx_mask[4] = 0x01;
 		max_bit_rate = MAX_BIT_RATE_40_MHZ;
 	}
 
 	if (priv->cfg->mod_params->amsdu_size_8K)
-		ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU;
+		ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
 
 	ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
 	ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
 
-	ht_info->supp_mcs_set[0] = 0xFF;
+	ht_info->mcs.rx_mask[0] = 0xFF;
 	if (rx_chains_num >= 2)
-		ht_info->supp_mcs_set[1] = 0xFF;
+		ht_info->mcs.rx_mask[1] = 0xFF;
 	if (rx_chains_num >= 3)
-		ht_info->supp_mcs_set[2] = 0xFF;
+		ht_info->mcs.rx_mask[2] = 0xFF;
 
 	/* Highest supported Rx data rate */
 	max_bit_rate *= rx_chains_num;
-	ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF);
-	ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8);
+	WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK);
+	ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate);
 
 	/* Tx MCS capabilities */
-	ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED;
+	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
 	if (tx_chains_num != rx_chains_num) {
-		ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF;
-		ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2);
+		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+		ht_info->mcs.tx_params |= ((tx_chains_num - 1) <<
+				IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
 	}
 }
 
@@ -498,7 +441,7 @@
 	sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
 
 	if (priv->cfg->sku & IWL_SKU_N)
-		iwlcore_init_ht_hw_capab(priv, &sband->ht_info,
+		iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
 					 IEEE80211_BAND_5GHZ);
 
 	sband = &priv->bands[IEEE80211_BAND_2GHZ];
@@ -508,7 +451,7 @@
 	sband->n_bitrates = IWL_RATE_COUNT;
 
 	if (priv->cfg->sku & IWL_SKU_N)
-		iwlcore_init_ht_hw_capab(priv, &sband->ht_info,
+		iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
 					 IEEE80211_BAND_2GHZ);
 
 	priv->ieee_channels = channels;
@@ -598,8 +541,8 @@
 static bool is_single_rx_stream(struct iwl_priv *priv)
 {
 	return !priv->current_ht_config.is_ht ||
-	       ((priv->current_ht_config.supp_mcs_set[1] == 0) &&
-		(priv->current_ht_config.supp_mcs_set[2] == 0));
+	       ((priv->current_ht_config.mcs.rx_mask[1] == 0) &&
+		(priv->current_ht_config.mcs.rx_mask[2] == 0));
 }
 
 static u8 iwl_is_channel_extension(struct iwl_priv *priv,
@@ -612,10 +555,10 @@
 	if (!is_channel_valid(ch_info))
 		return 0;
 
-	if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE)
+	if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
 		return !(ch_info->fat_extension_channel &
 					IEEE80211_CHAN_NO_FAT_ABOVE);
-	else if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW)
+	else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
 		return !(ch_info->fat_extension_channel &
 					IEEE80211_CHAN_NO_FAT_BELOW);
 
@@ -623,24 +566,24 @@
 }
 
 u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
-			     struct ieee80211_ht_info *sta_ht_inf)
+			 struct ieee80211_sta_ht_cap *sta_ht_inf)
 {
 	struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
 
 	if ((!iwl_ht_conf->is_ht) ||
 	   (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
-	   (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE))
+	   (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE))
 		return 0;
 
 	if (sta_ht_inf) {
 		if ((!sta_ht_inf->ht_supported) ||
-		   (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH)))
+		   (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)))
 			return 0;
 	}
 
 	return iwl_is_channel_extension(priv, priv->band,
-					 iwl_ht_conf->control_channel,
-					 iwl_ht_conf->extension_chan_offset);
+					le16_to_cpu(priv->staging_rxon.channel),
+					iwl_ht_conf->extension_chan_offset);
 }
 EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
 
@@ -665,22 +608,15 @@
 		rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
 				 RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
 
-	if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
-		IWL_DEBUG_ASSOC("control diff than current %d %d\n",
-				le16_to_cpu(rxon->channel),
-				ht_info->control_channel);
-		return;
-	}
-
 	/* Note: control channel is opposite of extension channel */
 	switch (ht_info->extension_chan_offset) {
-	case IEEE80211_HT_IE_CHA_SEC_ABOVE:
+	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
 		rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
 		break;
-	case IEEE80211_HT_IE_CHA_SEC_BELOW:
+	case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
 		rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
 		break;
-	case IEEE80211_HT_IE_CHA_SEC_NONE:
+	case IEEE80211_HT_PARAM_CHA_SEC_NONE:
 	default:
 		rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
 		break;
@@ -694,14 +630,12 @@
 
 	IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X "
 			"rxon flags 0x%X operation mode :0x%X "
-			"extension channel offset 0x%x "
-			"control chan %d\n",
-			ht_info->supp_mcs_set[0],
-			ht_info->supp_mcs_set[1],
-			ht_info->supp_mcs_set[2],
+			"extension channel offset 0x%x\n",
+			ht_info->mcs.rx_mask[0],
+			ht_info->mcs.rx_mask[1],
+			ht_info->mcs.rx_mask[2],
 			le32_to_cpu(rxon->flags), ht_info->ht_protection,
-			ht_info->extension_chan_offset,
-			ht_info->control_channel);
+			ht_info->extension_chan_offset);
 	return;
 }
 EXPORT_SYMBOL(iwl_set_rxon_ht);
@@ -745,7 +679,7 @@
 		break;
 	case WLAN_HT_CAP_SM_PS_INVALID:
 	default:
-		IWL_ERROR("invalide mimo ps mode %d\n",
+		IWL_ERROR("invalid mimo ps mode %d\n",
 			   priv->current_ht_config.sm_ps);
 		WARN_ON(1);
 		idle_cnt = -1;
@@ -871,11 +805,14 @@
 
 	/* Tell mac80211 our characteristics */
 	hw->flags = IEEE80211_HW_SIGNAL_DBM |
-		    IEEE80211_HW_NOISE_DBM;
+		    IEEE80211_HW_NOISE_DBM |
+		    IEEE80211_HW_AMPDU_AGGREGATION;
 	hw->wiphy->interface_modes =
-		BIT(NL80211_IFTYPE_AP) |
 		BIT(NL80211_IFTYPE_STATION) |
 		BIT(NL80211_IFTYPE_ADHOC);
+
+	hw->wiphy->fw_handles_regulatory = true;
+
 	/* Default value; 4 EDCA QOS priorities */
 	hw->queues = 4;
 	/* queues to support 11n aggregation */
@@ -948,16 +885,12 @@
 
 	priv->iw_mode = NL80211_IFTYPE_STATION;
 
-	priv->use_ant_b_for_management_frame = 1; /* start with ant B */
 	priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED;
 
 	/* Choose which receivers/antennas to use */
 	iwl_set_rxon_chain(priv);
 	iwl_init_scan_params(priv);
 
-	if (priv->cfg->mod_params->enable_qos)
-		priv->qos_data.qos_enable = 1;
-
 	iwl_reset_qos(priv);
 
 	priv->qos_data.qos_active = 0;
@@ -1025,6 +958,30 @@
 }
 EXPORT_SYMBOL(iwl_uninit_drv);
 
+
+void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+	clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+	/* disable interrupts from uCode/NIC to host */
+	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+	/* acknowledge/clear/reset any interrupts still pending
+	 * from uCode or flow handler (Rx/Tx DMA) */
+	iwl_write32(priv, CSR_INT, 0xffffffff);
+	iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+	IWL_DEBUG_ISR("Disabled interrupts\n");
+}
+EXPORT_SYMBOL(iwl_disable_interrupts);
+
+void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+	IWL_DEBUG_ISR("Enabling interrupts\n");
+	set_bit(STATUS_INT_ENABLED, &priv->status);
+	iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+}
+EXPORT_SYMBOL(iwl_enable_interrupts);
+
 int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
 {
 	u32 stat_flags = 0;
@@ -1172,24 +1129,47 @@
 }
 EXPORT_SYMBOL(iwl_verify_ucode);
 
+
+static const char *desc_lookup_text[] = {
+	"OK",
+	"FAIL",
+	"BAD_PARAM",
+	"BAD_CHECKSUM",
+	"NMI_INTERRUPT_WDG",
+	"SYSASSERT",
+	"FATAL_ERROR",
+	"BAD_COMMAND",
+	"HW_ERROR_TUNE_LOCK",
+	"HW_ERROR_TEMPERATURE",
+	"ILLEGAL_CHAN_FREQ",
+	"VCC_NOT_STABLE",
+	"FH_ERROR",
+	"NMI_INTERRUPT_HOST",
+	"NMI_INTERRUPT_ACTION_PT",
+	"NMI_INTERRUPT_UNKNOWN",
+	"UCODE_VERSION_MISMATCH",
+	"HW_ERROR_ABS_LOCK",
+	"HW_ERROR_CAL_LOCK_FAIL",
+	"NMI_INTERRUPT_INST_ACTION_PT",
+	"NMI_INTERRUPT_DATA_ACTION_PT",
+	"NMI_TRM_HW_ER",
+	"NMI_INTERRUPT_TRM",
+	"NMI_INTERRUPT_BREAK_POINT"
+	"DEBUG_0",
+	"DEBUG_1",
+	"DEBUG_2",
+	"DEBUG_3",
+	"UNKNOWN"
+};
+
 static const char *desc_lookup(int i)
 {
-	switch (i) {
-	case 1:
-		return "FAIL";
-	case 2:
-		return "BAD_PARAM";
-	case 3:
-		return "BAD_CHECKSUM";
-	case 4:
-		return "NMI_INTERRUPT";
-	case 5:
-		return "SYSASSERT";
-	case 6:
-		return "FATAL_ERROR";
-	}
+	int max = ARRAY_SIZE(desc_lookup_text) - 1;
 
-	return "UNKNOWN";
+	if (i < 0 || i > max)
+		i = max;
+
+	return desc_lookup_text[i];
 }
 
 #define ERROR_START_OFFSET  (1 * sizeof(u32))
@@ -1235,9 +1215,9 @@
 	line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
 	time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
 
-	IWL_ERROR("Desc        Time       "
+	IWL_ERROR("Desc                               Time       "
 		"data1      data2      line\n");
-	IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
+	IWL_ERROR("%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
 		desc_lookup(desc), desc, time, data1, data2, line);
 	IWL_ERROR("blink1  blink2  ilink1  ilink2\n");
 	IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
@@ -1377,6 +1357,7 @@
 }
 EXPORT_SYMBOL(iwl_rf_kill_ct_config);
 
+
 /*
  * CARD_STATE_CMD
  *
@@ -1465,6 +1446,16 @@
 		return 0;
 	}
 
+	/* when driver is up while rfkill is on, it wont receive
+	 * any CARD_STATE_NOTIFICATION notifications so we have to
+	 * restart it in here
+	 */
+	if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) {
+		clear_bit(STATUS_RF_KILL_SW, &priv->status);
+		if (!iwl_is_rfkill(priv))
+			queue_work(priv->workqueue, &priv->up);
+	}
+
 	/* If the driver is already loaded, it will receive
 	 * CARD_STATE_NOTIFICATION notifications and the handler will
 	 * call restart to reload the driver.
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 288b6a8..7c3a20a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -72,6 +72,7 @@
 
 #define IWLWIFI_VERSION "1.3.27k"
 #define DRV_COPYRIGHT	"Copyright(c) 2003-2008 Intel Corporation"
+#define DRV_AUTHOR     "<ilw@linux.intel.com>"
 
 #define IWL_PCI_DEVICE(dev, subdev, cfg) \
 	.vendor = PCI_VENDOR_ID_INTEL,  .device = (dev), \
@@ -100,12 +101,8 @@
 };
 
 struct iwl_lib_ops {
-	/* set hw dependant perameters */
+	/* set hw dependent parameters */
 	int (*set_hw_params)(struct iwl_priv *priv);
-	/* ucode shared memory */
-	int (*alloc_shared_mem)(struct iwl_priv *priv);
-	void (*free_shared_mem)(struct iwl_priv *priv);
-	int (*shared_mem_rx_idx)(struct iwl_priv *priv);
 	/* Handling TX */
 	void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
 					struct iwl_tx_queue *txq,
@@ -157,22 +154,53 @@
 struct iwl_mod_params {
 	int disable;		/* def: 0 = enable radio */
 	int sw_crypto;		/* def: 0 = using hardware encryption */
-	int debug;		/* def: 0 = minimal debug log messages */
+	u32 debug;		/* def: 0 = minimal debug log messages */
 	int disable_hw_scan;	/* def: 0 = use h/w scan */
 	int num_of_queues;	/* def: HW dependent */
 	int num_of_ampdu_queues;/* def: HW dependent */
-	int enable_qos;		/* def: 1 = use quality of service */
 	int disable_11n;	/* def: 0 = disable 11n capabilities */
 	int amsdu_size_8K;	/* def: 1 = enable 8K amsdu size */
 	int antenna;  		/* def: 0 = both antennas (use diversity) */
 	int restart_fw;		/* def: 1 = restart firmware */
 };
 
+/**
+ * struct iwl_cfg
+ * @fw_name_pre: Firmware filename prefix. The api version and extension
+ * 	(.ucode) will be added to filename before loading from disk. The
+ * 	filename is constructed as fw_name_pre<api>.ucode.
+ * @ucode_api_max: Highest version of uCode API supported by driver.
+ * @ucode_api_min: Lowest version of uCode API supported by driver.
+ *
+ * We enable the driver to be backward compatible wrt API version. The
+ * driver specifies which APIs it supports (with @ucode_api_max being the
+ * highest and @ucode_api_min the lowest). Firmware will only be loaded if
+ * it has a supported API version. The firmware's API version will be
+ * stored in @iwl_priv, enabling the driver to make runtime changes based
+ * on firmware version used.
+ *
+ * For example,
+ * if (IWL_UCODE_API(priv->ucode_ver) >= 2) {
+ * 	Driver interacts with Firmware API version >= 2.
+ * } else {
+ * 	Driver interacts with Firmware API version 1.
+ * }
+ *
+ * The ideal usage of this infrastructure is to treat a new ucode API
+ * release as a new hardware revision. That is, through utilizing the
+ * iwl_hcmd_utils_ops etc. we accommodate different command structures
+ * and flows between hardware versions (4965/5000) as well as their API
+ * versions.
+ */
 struct iwl_cfg {
 	const char *name;
-	const char *fw_name;
+	const char *fw_name_pre;
+	const unsigned int ucode_api_max;
+	const unsigned int ucode_api_min;
 	unsigned int sku;
 	int eeprom_size;
+	u16  eeprom_ver;
+	u16  eeprom_calib_ver;
 	const struct iwl_ops *ops;
 	const struct iwl_mod_params *mod_params;
 };
@@ -184,22 +212,17 @@
 struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
 		struct ieee80211_ops *hw_ops);
 void iwl_hw_detect(struct iwl_priv *priv);
-void iwl_clear_stations_table(struct iwl_priv *priv);
 void iwl_reset_qos(struct iwl_priv *priv);
 void iwl_set_rxon_chain(struct iwl_priv *priv);
 int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
 void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
 u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
-			 struct ieee80211_ht_info *sta_ht_inf);
+			 struct ieee80211_sta_ht_cap *sta_ht_inf);
 int iwl_hw_nic_init(struct iwl_priv *priv);
 int iwl_setup_mac(struct iwl_priv *priv);
 int iwl_set_hw_params(struct iwl_priv *priv);
 int iwl_init_drv(struct iwl_priv *priv);
 void iwl_uninit_drv(struct iwl_priv *priv);
-/* "keep warm" functions */
-int iwl_kw_init(struct iwl_priv *priv);
-int iwl_kw_alloc(struct iwl_priv *priv);
-void iwl_kw_free(struct iwl_priv *priv);
 
 /*****************************************************
 * RX
@@ -212,8 +235,6 @@
 void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 void iwl_rx_replenish(struct iwl_priv *priv);
 int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
-int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn);
-int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
 int iwl_rx_queue_restock(struct iwl_priv *priv);
 int iwl_rx_queue_space(const struct iwl_rx_queue *q);
 void iwl_rx_allocate(struct iwl_priv *priv);
@@ -237,7 +258,6 @@
 int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
 int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
 int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id);
-
 /*****************************************************
  * TX power
  ****************************************************/
@@ -259,6 +279,13 @@
 			      struct ieee80211_tx_info *info);
 int iwl_hwrate_to_plcp_idx(u32 rate_n_flags);
 
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx);
+
+static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
+{
+	return BIT(ant_idx) << RATE_MCS_ANT_POS;
+}
+
 static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
 {
 	return le32_to_cpu(rate_n_flags) & 0xFF;
@@ -289,6 +316,14 @@
 int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
 void iwl_calib_free_results(struct iwl_priv *priv);
 
+/*******************************************************************************
+ * Spectrum Measureemtns in  iwl-spectrum.c
+ ******************************************************************************/
+#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
+void iwl_setup_spectrum_handlers(struct iwl_priv *priv);
+#else
+static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {}
+#endif
 /*****************************************************
  *   S e n d i n g     H o s t     C o m m a n d s   *
  *****************************************************/
@@ -308,11 +343,18 @@
 int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
 
 /*****************************************************
+ * PCI						     *
+ *****************************************************/
+void iwl_disable_interrupts(struct iwl_priv *priv);
+void iwl_enable_interrupts(struct iwl_priv *priv);
+
+/*****************************************************
 *  Error Handling Debugging
 ******************************************************/
 void iwl_dump_nic_error_log(struct iwl_priv *priv);
 void iwl_dump_nic_event_log(struct iwl_priv *priv);
 
+
 /*************** DRIVER STATUS FUNCTIONS   *****/
 
 #define STATUS_HCMD_ACTIVE	0	/* host command in progress */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 662edf4..f34ede4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -60,6 +60,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  *****************************************************************************/
+#ifndef __iwl_csr_h__
+#define __iwl_csr_h__
 /*=== CSR (control and status registers) ===*/
 #define CSR_BASE    (0x000)
 
@@ -214,6 +216,8 @@
 /* EEPROM REG */
 #define CSR_EEPROM_REG_READ_VALID_MSK	(0x00000001)
 #define CSR_EEPROM_REG_BIT_CMD		(0x00000002)
+#define CSR_EEPROM_REG_MSK_ADDR		(0x0000FFFC)
+#define CSR_EEPROM_REG_MSK_DATA		(0xFFFF0000)
 
 /* EEPROM GP */
 #define CSR_EEPROM_GP_VALID_MSK		(0x00000006)
@@ -286,4 +290,4 @@
 #define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED         (0x00000004)
 
 
-
+#endif /* !__iwl_csr_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index e548d67..56c13b4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -21,7 +21,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -40,6 +40,13 @@
   dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \
 	 in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
 
+#define iwl_print_hex_dump(priv, level, p, len) 			\
+do {                                            			\
+	if (priv->debug_level & level)          			\
+		print_hex_dump(KERN_DEBUG, "iwl data: ",		\
+			       DUMP_PREFIX_OFFSET, 16, 1, p, len, 1);	\
+} while (0)
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 struct iwl_debugfs {
 	const char *name;
@@ -53,6 +60,7 @@
 		struct dentry *file_rx_statistics;
 		struct dentry *file_tx_statistics;
 		struct dentry *file_log_event;
+		struct dentry *file_channels;
 	} dbgfs_data_files;
 	struct dir_rf_files {
 		struct dentry *file_disable_sensitivity;
@@ -70,6 +78,9 @@
 #else
 #define IWL_DEBUG(level, fmt, args...)
 #define IWL_DEBUG_LIMIT(level, fmt, args...)
+static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
+				      void *p, u32 len)
+{}
 #endif				/* CONFIG_IWLWIFI_DEBUG */
 
 
@@ -85,29 +96,25 @@
 #endif				/* CONFIG_IWLWIFI_DEBUGFS */
 
 /*
- * To use the debug system;
+ * To use the debug system:
  *
  * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
+ * list here in the form of
  *
  * #define IWL_DL_xxxx VALUE
  *
- * shifting value to the left one bit from the previous entry.  xxxx should be
- * the name of the classification (for example, WEP)
+ * where xxxx should be the name of the classification (for example, WEP).
  *
  * You then need to either add a IWL_xxxx_DEBUG() macro definition for your
  * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want
  * to send output to that classification.
  *
- * To add your debug level to the list of levels seen when you perform
+ * The active debug levels can be accessed via files
  *
- * % cat /proc/net/iwl/debug_level
+ * 	/sys/module/iwlagn/parameters/debug{50}
+ * 	/sys/class/net/wlan0/device/debug_level
  *
- * you simply need to add your entry to the iwl_debug_levels array.
- *
- * If you do not see debug_level in /proc/net/iwl then you do not have
- * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration
- *
+ * when CONFIG_IWLWIFI_DEBUG=y.
  */
 
 #define IWL_DL_INFO		(1 << 0)
@@ -183,6 +190,8 @@
 #define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a)
 #define IWL_DEBUG_STATS_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_STATS, f, ## a)
 #define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a)
+#define IWL_DEBUG_TX_REPLY_LIMIT(f, a...) \
+	IWL_DEBUG_LIMIT(IWL_DL_TX_REPLY, f, ## a)
 #define IWL_DEBUG_QOS(f, a...)   IWL_DEBUG(IWL_DL_QOS, f, ## a)
 #define IWL_DEBUG_RADIO(f, a...)  IWL_DEBUG(IWL_DL_RADIO, f, ## a)
 #define IWL_DEBUG_POWER(f, a...)  IWL_DEBUG(IWL_DL_POWER, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 20db0eb..d5253a1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -22,7 +22,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
 
@@ -58,7 +58,8 @@
 #define DEBUGFS_ADD_BOOL(name, parent, ptr) do {                        \
 	dbgfs->dbgfs_##parent##_files.file_##name =                     \
 	debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr);     \
-	if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name))          \
+	if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)		\
+			|| !dbgfs->dbgfs_##parent##_files.file_##name)	\
 		goto err;                                               \
 } while (0)
 
@@ -228,7 +229,6 @@
 	ssize_t ret;
 	/* Add 30 for initial string */
 	const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
-	DECLARE_MAC_BUF(mac);
 
 	buf = kmalloc(bufsz, GFP_KERNEL);
 	if (!buf)
@@ -242,7 +242,6 @@
 		if (station->used) {
 			pos += scnprintf(buf + pos, bufsz - pos,
 					"station %d:\ngeneral data:\n", i+1);
-			print_mac(mac, station->sta.sta.addr);
 			pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n",
 					station->sta.sta.sta_id);
 			pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n",
@@ -349,12 +348,86 @@
 	return count;
 }
 
+
+
+static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+	struct ieee80211_channel *channels = NULL;
+	const struct ieee80211_supported_band *supp_band = NULL;
+	int pos = 0, i, bufsz = PAGE_SIZE;
+	char *buf;
+	ssize_t ret;
+
+	if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
+		return -EAGAIN;
+
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf) {
+		IWL_ERROR("Can not allocate Buffer\n");
+		return -ENOMEM;
+	}
+
+	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
+	channels = supp_band->channels;
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"Displaying %d channels in 2.4GHz band 802.11bg):\n",
+			 supp_band->n_channels);
+
+	for (i = 0; i < supp_band->n_channels; i++)
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"%d: %ddBm: BSS%s%s, %s.\n",
+				ieee80211_frequency_to_channel(
+				channels[i].center_freq),
+				channels[i].max_power,
+				channels[i].flags & IEEE80211_CHAN_RADAR ?
+				" (IEEE 802.11h required)" : "",
+				(!(channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+				|| (channels[i].flags &
+				IEEE80211_CHAN_RADAR)) ? "" :
+				", IBSS",
+				channels[i].flags &
+				IEEE80211_CHAN_PASSIVE_SCAN ?
+				"passive only" : "active/passive");
+
+	supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
+	channels = supp_band->channels;
+
+	pos += scnprintf(buf + pos, bufsz - pos,
+			"Displaying %d channels in 5.2GHz band (802.11a)\n",
+			supp_band->n_channels);
+
+	for (i = 0; i < supp_band->n_channels; i++)
+		pos += scnprintf(buf + pos, bufsz - pos,
+				"%d: %ddBm: BSS%s%s, %s.\n",
+				ieee80211_frequency_to_channel(
+				channels[i].center_freq),
+				channels[i].max_power,
+				channels[i].flags & IEEE80211_CHAN_RADAR ?
+				" (IEEE 802.11h required)" : "",
+				((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+				|| (channels[i].flags &
+				IEEE80211_CHAN_RADAR)) ? "" :
+				", IBSS",
+				channels[i].flags &
+				IEEE80211_CHAN_PASSIVE_SCAN ?
+				"passive only" : "active/passive");
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+	kfree(buf);
+	return ret;
+}
+
+
 DEBUGFS_READ_WRITE_FILE_OPS(sram);
 DEBUGFS_WRITE_FILE_OPS(log_event);
 DEBUGFS_READ_FILE_OPS(eeprom);
 DEBUGFS_READ_FILE_OPS(stations);
 DEBUGFS_READ_FILE_OPS(rx_statistics);
 DEBUGFS_READ_FILE_OPS(tx_statistics);
+DEBUGFS_READ_FILE_OPS(channels);
 
 /*
  * Create the debugfs files and directories
@@ -388,6 +461,7 @@
 	DEBUGFS_ADD_FILE(stations, data);
 	DEBUGFS_ADD_FILE(rx_statistics, data);
 	DEBUGFS_ADD_FILE(tx_statistics, data);
+	DEBUGFS_ADD_FILE(channels, data);
 	DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
 	DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
 			 &priv->disable_chain_noise_cal);
@@ -416,6 +490,7 @@
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event);
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations);
+	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
 	DEBUGFS_REMOVE(priv->dbgfs->dir_data);
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 9966d4e..0468fcc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -54,6 +54,7 @@
 extern struct iwl_cfg iwl5350_agn_cfg;
 extern struct iwl_cfg iwl5100_bg_cfg;
 extern struct iwl_cfg iwl5100_abg_cfg;
+extern struct iwl_cfg iwl5150_agn_cfg;
 
 /* CT-KILL constants */
 #define CT_KILL_THRESHOLD	110 /* in Celsius */
@@ -113,11 +114,9 @@
 				* space less than this */
 } __attribute__ ((packed));
 
-#define MAX_NUM_OF_TBS          (20)
-
 /* One for each TFD */
 struct iwl_tx_info {
-	struct sk_buff *skb[MAX_NUM_OF_TBS];
+	struct sk_buff *skb[IWL_NUM_OF_TBS - 1];
 };
 
 /**
@@ -135,12 +134,13 @@
  */
 struct iwl_tx_queue {
 	struct iwl_queue q;
-	struct iwl_tfd_frame *bd;
+	struct iwl_tfd *tfds;
 	struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS];
 	struct iwl_tx_info *txb;
-	int need_update;
-	int sched_retry;
-	int active;
+	u8 need_update;
+	u8 sched_retry;
+	u8 active;
+	u8 swq_id;
 };
 
 #define IWL_NUM_SCAN_RATES         (2)
@@ -186,12 +186,6 @@
 	u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */
 };
 
-struct iwl4965_clip_group {
-	/* maximum power level to prevent clipping for each rate, derived by
-	 *   us from this band's saturation power in EEPROM */
-	const s8 clip_powers[IWL_MAX_RATES];
-};
-
 
 #define IWL_TX_FIFO_AC0	0
 #define IWL_TX_FIFO_AC1	1
@@ -253,7 +247,8 @@
 	/* The CMD_SIZE_HUGE flag bit indicates that the command
 	 * structure is stored at the end of the shared queue memory. */
 	u32 flags;
-
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+	DECLARE_PCI_UNMAP_LEN(len)
 } __attribute__ ((packed));
 
 #define IWL_CMD_MAX_PAYLOAD 320
@@ -269,24 +264,16 @@
 	struct iwl_cmd_meta meta;	/* driver data */
 	struct iwl_cmd_header hdr;	/* uCode API */
 	union {
-		struct iwl_addsta_cmd addsta;
-		struct iwl_led_cmd led;
 		u32 flags;
 		u8 val8;
 		u16 val16;
 		u32 val32;
-		struct iwl4965_bt_cmd bt;
-		struct iwl4965_rxon_time_cmd rxon_time;
-		struct iwl_powertable_cmd powertable;
-		struct iwl_qosparam_cmd qosparam;
 		struct iwl_tx_cmd tx;
-		struct iwl4965_rxon_assoc_cmd rxon_assoc;
-		struct iwl_rem_sta_cmd rm_sta;
-		u8 *indirect;
 		u8 payload[IWL_CMD_MAX_PAYLOAD];
 	} __attribute__ ((packed)) cmd;
 } __attribute__ ((packed));
 
+
 struct iwl_host_cmd {
 	u8 id;
 	u16 len;
@@ -309,7 +296,6 @@
 
 /**
  * struct iwl_rx_queue - Rx queue
- * @processed: Internal index to last handled Rx packet
  * @read: Shared index to newest available Rx buffer
  * @write: Shared index to oldest written Rx packet
  * @free_count: Number of pre-allocated buffers in rx_free
@@ -324,26 +310,19 @@
 	dma_addr_t dma_addr;
 	struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
 	struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
-	u32 processed;
 	u32 read;
 	u32 write;
 	u32 free_count;
 	struct list_head rx_free;
 	struct list_head rx_used;
 	int need_update;
+	struct iwl_rb_status *rb_stts;
+	dma_addr_t rb_stts_dma;
 	spinlock_t lock;
 };
 
 #define IWL_SUPPORTED_RATES_IE_LEN         8
 
-#define SCAN_INTERVAL 100
-
-#define MAX_A_CHANNELS  252
-#define MIN_A_CHANNELS  7
-
-#define MAX_B_CHANNELS  14
-#define MIN_B_CHANNELS  1
-
 #define MAX_TID_COUNT        9
 
 #define IWL_INVALID_RATE     0xFF
@@ -413,9 +392,8 @@
 	u8 max_amsdu_size;
 	u8 ampdu_factor;
 	u8 mpdu_density;
-	u8 supp_mcs_set[16];
+	struct ieee80211_mcs_info mcs;
 	/* BSS related data */
-	u8 control_channel;
 	u8 extension_chan_offset;
 	u8 tx_chan_width;
 	u8 ht_protection;
@@ -444,7 +422,6 @@
 
 /* QoS structures */
 struct iwl_qos_info {
-	int qos_enable;
 	int qos_active;
 	union iwl_qos_capabity qos_cap;
 	struct iwl_qosparam_cmd def_qos_parm;
@@ -470,7 +447,7 @@
 
 /* uCode file layout */
 struct iwl_ucode {
-	__le32 ver;		/* major/minor/subminor */
+	__le32 ver;		/* major/minor/API/serial */
 	__le32 inst_size;	/* bytes of runtime instructions */
 	__le32 data_size;	/* bytes of runtime data */
 	__le32 init_size;	/* bytes of initialization instructions */
@@ -511,11 +488,15 @@
 };
 
 
-#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ)
+#define KELVIN_TO_CELSIUS(x) ((x)-273)
+#define CELSIUS_TO_KELVIN(x) ((x)+273)
+
 
 /**
  * struct iwl_hw_params
  * @max_txq_num: Max # Tx queues supported
+ * @dma_chnl_num: Number of Tx DMA/FIFO channels
+ * @scd_bc_tbls_size: size of scheduler byte count tables
  * @tx/rx_chains_num: Number of TX/RX chains
  * @valid_tx/rx_ant: usable antennas
  * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
@@ -528,11 +509,13 @@
  * @sw_crypto: 0 for hw, 1 for sw
  * @max_xxx_size: for ucode uses
  * @ct_kill_threshold: temperature threshold
+ * @calib_init_cfg: setup initial calibrations for the hw
  * @struct iwl_sensitivity_ranges: range of sensitivity values
- * @first_ampdu_q: first HW queue available for ampdu
  */
 struct iwl_hw_params {
-	u16 max_txq_num;
+	u8 max_txq_num;
+	u8 dma_chnl_num;
+	u16 scd_bc_tbls_size;
 	u8  tx_chains_num;
 	u8  rx_chains_num;
 	u8  valid_tx_ant;
@@ -549,22 +532,10 @@
 	u32 max_data_size;
 	u32 max_bsm_size;
 	u32 ct_kill_threshold; /* value in hw-dependent units */
+	u32 calib_init_cfg;
 	const struct iwl_sensitivity_ranges *sens;
-	u8 first_ampdu_q;
 };
 
-#define HT_SHORT_GI_20MHZ	(1 << 0)
-#define HT_SHORT_GI_40MHZ	(1 << 1)
-
-
-#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\
-		       x->u.rx_frame.stats.payload + \
-		       x->u.rx_frame.stats.phy_count))
-#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\
-		       IWL_RX_HDR(x)->payload + \
-		       le16_to_cpu(IWL_RX_HDR(x)->len)))
-#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
-#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
 
 /******************************************************************************
  *
@@ -581,13 +552,8 @@
  * iwl4965_mac_     <-- mac80211 callback
  *
  ****************************************************************************/
-struct iwl_addsta_cmd;
-extern int iwl_send_add_sta(struct iwl_priv *priv,
-			    struct iwl_addsta_cmd *sta, u8 flags);
-extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
-			int is_ap, u8 flags, struct ieee80211_ht_info *ht_info);
-extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
-extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
+extern void iwl_update_chain_flags(struct iwl_priv *priv);
+extern int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
 extern const u8 iwl_bcast_addr[ETH_ALEN];
 extern int iwl_rxq_stop(struct iwl_priv *priv);
 extern void iwl_txq_ctx_stop(struct iwl_priv *priv);
@@ -611,19 +577,15 @@
 }
 
 
-struct iwl_priv;
-
-
-/* Structures, enum, and defines specific to the 4965 */
-
-#define IWL_KW_SIZE 0x1000	/*4k */
-
-struct iwl_kw {
-	dma_addr_t dma_addr;
-	void *v_addr;
+struct iwl_dma_ptr {
+	dma_addr_t dma;
+	void *addr;
 	size_t size;
 };
 
+#define HT_SHORT_GI_20MHZ	(1 << 0)
+#define HT_SHORT_GI_40MHZ	(1 << 1)
+
 #define IWL_CHANNEL_WIDTH_20MHZ   0
 #define IWL_CHANNEL_WIDTH_40MHZ   1
 
@@ -638,7 +600,6 @@
 #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
 
 /* Sensitivity and chain noise calibration */
-#define INTERFERENCE_DATA_AVAILABLE	__constant_cpu_to_le32(1)
 #define INITIALIZATION_VALUE		0xFFFF
 #define CAL_NUM_OF_BEACONS		20
 #define MAXIMUM_ALLOWED_PATHLOSS	15
@@ -691,13 +652,20 @@
 	IWL_CALIB_ENABLED = 1,
 };
 
-struct statistics_general_data {
-	u32 beacon_silence_rssi_a;
-	u32 beacon_silence_rssi_b;
-	u32 beacon_silence_rssi_c;
-	u32 beacon_energy_a;
-	u32 beacon_energy_b;
-	u32 beacon_energy_c;
+
+/*
+ * enum iwl_calib
+ * defines the order in which results of initial calibrations
+ * should be sent to the runtime uCode
+ */
+enum iwl_calib {
+	IWL_CALIB_XTAL,
+	IWL_CALIB_DC,
+	IWL_CALIB_LO,
+	IWL_CALIB_TX_IQ,
+	IWL_CALIB_TX_IQ_PERD,
+	IWL_CALIB_BASE_BAND,
+	IWL_CALIB_MAX
 };
 
 /* Opaque calibration results */
@@ -766,7 +734,6 @@
 
 
 #define IWL_MAX_NUM_QUEUES	20 /* FIXME: do dynamic allocation */
-#define IWL_CALIB_MAX  3
 
 struct iwl_priv {
 
@@ -790,7 +757,7 @@
 
 #ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
 	/* spectrum measurement report caching */
-	struct iwl4965_spectrum_notification measure_report;
+	struct iwl_spectrum_notification measure_report;
 	u8 measurement_status;
 #endif
 	/* ucode beacon time */
@@ -801,10 +768,6 @@
 	struct iwl_channel_info *channel_info;	/* channel info array */
 	u8 channel_count;	/* # of channels */
 
-	/* each calibration channel group in the EEPROM has a derived
-	 * clip setting for each rate. */
-	const struct iwl4965_clip_group clip_groups[5];
-
 	/* thermal calibration */
 	s32 temperature;	/* degrees Kelvin */
 	s32 last_temperature;
@@ -818,12 +781,13 @@
 	unsigned long scan_start;
 	unsigned long scan_pass_start;
 	unsigned long scan_start_tsf;
+	struct iwl_scan_cmd *scan;
 	int scan_bands;
 	int one_direct_scan;
 	u8 direct_ssid_len;
 	u8 direct_ssid[IW_ESSID_MAX_SIZE];
-	struct iwl_scan_cmd *scan;
-	u32 scan_tx_ant[IEEE80211_NUM_BANDS];
+	u8 scan_tx_ant[IEEE80211_NUM_BANDS];
+	u8 mgmt_tx_ant;
 
 	/* spinlock */
 	spinlock_t lock;	/* protect general shared data */
@@ -840,6 +804,8 @@
 	u8   rev_id;
 
 	/* uCode images, save to reload in case of failure */
+	u32 ucode_ver;			/* version of ucode, copy of
+					   iwl_ucode.ver */
 	struct fw_desc ucode_code;	/* runtime inst */
 	struct fw_desc ucode_data;	/* runtime data original */
 	struct fw_desc ucode_data_backup;	/* runtime data save/restore */
@@ -850,7 +816,7 @@
 	u8 ucode_write_complete;	/* the image write is complete */
 
 
-	struct iwl4965_rxon_time_cmd rxon_timing;
+	struct iwl_rxon_time_cmd rxon_timing;
 
 	/* We declare this const so it can only be
 	 * changed via explicit cast within the
@@ -882,7 +848,6 @@
 	u16 active_rate_basic;
 
 	u8 assoc_station_added;
-	u8 use_ant_b_for_management_frame;	/* Tx antenna selection */
 	u8 start_calib;
 	struct iwl_sensitivity_data sensitivity_data;
 	struct iwl_chain_noise_data chain_noise_data;
@@ -903,12 +868,14 @@
 	struct iwl_rx_queue rxq;
 	struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
 	unsigned long txq_ctx_active_msk;
-	struct iwl_kw kw;	/* keep warm address */
+	struct iwl_dma_ptr  kw;	/* keep warm address */
+	struct iwl_dma_ptr  scd_bc_tbls;
+
 	u32 scd_base_addr;	/* scheduler sram base address */
 
 	unsigned long status;
 
-	int last_rx_rssi;	/* From Rx packet statisitics */
+	int last_rx_rssi;	/* From Rx packet statistics */
 	int last_rx_noise;	/* From beacon statistics */
 
 	/* counts mgmt, ctl, and data packets */
@@ -923,8 +890,6 @@
 	unsigned long last_statistics_time;
 
 	/* context information */
-	u8 essid[IW_ESSID_MAX_SIZE];
-	u8 essid_len;
 	u16 rates_mask;
 
 	u32 power_mode;
@@ -965,11 +930,7 @@
 	struct ieee80211_vif *vif;
 
 	struct iwl_hw_params hw_params;
-	/* driver/uCode shared Tx Byte Counts and Rx status */
-	void *shared_virt;
-	int rb_closed_offset;
-	/* Physical Pointer to Tx Byte Counts and Rx status */
-	dma_addr_t shared_phys;
+
 
 	/* Current association information needed to configure the
 	 * hardware */
@@ -992,7 +953,6 @@
 	struct work_struct report_work;
 	struct work_struct request_scan;
 	struct work_struct beacon_update;
-	struct work_struct set_monitor;
 
 	struct tasklet_struct irq_tasklet;
 
@@ -1004,9 +964,6 @@
 	s8 tx_power_user_lmt;
 	s8 tx_power_channel_lmt;
 
-#ifdef CONFIG_PM
-	u32 pm_state[16];
-#endif
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 	/* debugging info */
@@ -1091,26 +1048,4 @@
 	return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
-				      void *p, u32 len)
-{
-	if (!(priv->debug_level & level))
-		return;
-
-	print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
-			p, len, 1);
-}
-#else
-static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
-				      void *p, u32 len)
-{
-}
-#endif
-
-extern const struct iwl_channel_info *iwl_get_channel_info(
-	const struct iwl_priv *priv, enum ieee80211_band band, u16 channel);
-
-/* Requires full declaration of iwl_priv before including */
-
 #endif				/* __iwl_dev_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 3715575..ce2f473 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -169,10 +169,9 @@
 			    CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 
 		/* See if we got it */
-		ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
-				   CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
-				   CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
-				   EEPROM_SEM_TIMEOUT);
+		ret = iwl_poll_direct_bit(priv, CSR_HW_IF_CONFIG_REG,
+				CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+				EEPROM_SEM_TIMEOUT);
 		if (ret >= 0) {
 			IWL_DEBUG_IO("Acquired semaphore after %d tries.\n",
 				count+1);
@@ -210,10 +209,8 @@
 {
 	u16 *e;
 	u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
-	u32 r;
 	int sz = priv->cfg->eeprom_size;
 	int ret;
-	int i;
 	u16 addr;
 
 	/* allocate eeprom */
@@ -241,22 +238,19 @@
 
 	/* eeprom is an array of 16bit values */
 	for (addr = 0; addr < sz; addr += sizeof(u16)) {
-		_iwl_write32(priv, CSR_EEPROM_REG, addr << 1);
-		_iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+		u32 r;
 
-		for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
-					i += IWL_EEPROM_ACCESS_DELAY) {
-			r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
-			if (r & CSR_EEPROM_REG_READ_VALID_MSK)
-				break;
-			udelay(IWL_EEPROM_ACCESS_DELAY);
-		}
+		_iwl_write32(priv, CSR_EEPROM_REG,
+			     CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
 
-		if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+		ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+					  CSR_EEPROM_REG_READ_VALID_MSK,
+					  IWL_EEPROM_ACCESS_TIMEOUT);
+		if (ret < 0) {
 			IWL_ERROR("Time out reading EEPROM[%d]\n", addr);
-			ret = -ETIMEDOUT;
 			goto done;
 		}
+		r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
 		e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
 	}
 	ret = 0;
@@ -279,7 +273,23 @@
 
 int iwl_eeprom_check_version(struct iwl_priv *priv)
 {
-	return priv->cfg->ops->lib->eeprom_ops.check_version(priv);
+	u16 eeprom_ver;
+	u16 calib_ver;
+
+	eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
+	calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv);
+
+	if (eeprom_ver < priv->cfg->eeprom_ver ||
+	    calib_ver < priv->cfg->eeprom_calib_ver)
+		goto err;
+
+	return 0;
+err:
+	IWL_ERROR("Unsupported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
+		  eeprom_ver, priv->cfg->eeprom_ver,
+		  calib_ver,  priv->cfg->eeprom_calib_ver);
+	return -EINVAL;
+
 }
 EXPORT_SYMBOL(iwl_eeprom_check_version);
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index d3a2a5b..603c84b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -68,17 +68,14 @@
 /*
  * EEPROM access time values:
  *
- * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG,
- *   then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit
- *   CSR_EEPROM_REG_BIT_CMD (0x2).
+ * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG.
  * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
  * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
  * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
  */
 #define IWL_EEPROM_ACCESS_TIMEOUT	5000 /* uSec */
-#define IWL_EEPROM_ACCESS_DELAY		10   /* uSec */
 
-#define IWL_EEPROM_SEM_TIMEOUT 		10   /* milliseconds */
+#define IWL_EEPROM_SEM_TIMEOUT 		10   /* microseconds */
 #define IWL_EEPROM_SEM_RETRY_LIMIT	1000 /* number of attempts (not time) */
 
 
@@ -147,6 +144,7 @@
 /*5000 calibrations */
 #define EEPROM_5000_CALIB_ALL	(INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
 #define EEPROM_5000_XTAL	((2*0x128) | EEPROM_5000_CALIB_ALL)
+#define EEPROM_5000_TEMPERATURE ((2*0x12A) | EEPROM_5000_CALIB_ALL)
 
 /* 5000 links */
 #define EEPROM_5000_LINK_HOST             (2*0x64)
@@ -174,6 +172,9 @@
 #define EEPROM_5000_REG_BAND_52_FAT_CHANNELS  ((0x92)\
 		| INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22  bytes */
 
+/* 5050 Specific */
+#define EEPROM_5050_TX_POWER_VERSION    (4)
+#define EEPROM_5050_EEPROM_VERSION	(0x21E)
 
 /* 2.4 GHz */
 extern const u8 iwl_eeprom_band_1[14];
@@ -371,7 +372,7 @@
 	int (*verify_signature) (struct iwl_priv *priv);
 	int (*acquire_semaphore) (struct iwl_priv *priv);
 	void (*release_semaphore) (struct iwl_priv *priv);
-	int (*check_version) (struct iwl_priv *priv);
+	u16 (*calib_version) (struct iwl_priv *priv);
 	const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset);
 };
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index a72efdf..d7da198 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -60,6 +60,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  *****************************************************************************/
+#ifndef __iwl_fh_h__
+#define __iwl_fh_h__
 
 /****************************/
 /* Flow Handler Definitions */
@@ -70,7 +72,7 @@
  * Addresses are offsets from device's PCI hardware base address.
  */
 #define FH_MEM_LOWER_BOUND                   (0x1000)
-#define FH_MEM_UPPER_BOUND                   (0x1EF0)
+#define FH_MEM_UPPER_BOUND                   (0x2000)
 
 /**
  * Keep-Warm (KW) buffer base address.
@@ -264,6 +266,7 @@
 #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL    (0x00000000)
 #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL  (0x00001000)
 
+#define FH_RSCSR_FRAME_SIZE_MSK	(0x00003FFF)	/* bits 0-13 */
 
 /**
  * Rx Shared Status Registers (RSSR)
@@ -290,6 +293,13 @@
 
 #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT	28
 
+/* TFDB  Area - TFDs buffer table */
+#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK      (0xFFFFFFFF)
+#define FH_TFDIB_LOWER_BOUND       (FH_MEM_LOWER_BOUND + 0x900)
+#define FH_TFDIB_UPPER_BOUND       (FH_MEM_LOWER_BOUND + 0x958)
+#define FH_TFDIB_CTRL0_REG(_chnl)  (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl))
+#define FH_TFDIB_CTRL1_REG(_chnl)  (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4)
+
 /**
  * Transmit DMA Channel Control/Status Registers (TCSR)
  *
@@ -316,34 +326,41 @@
 #define FH_TCSR_UPPER_BOUND  (FH_MEM_LOWER_BOUND + 0xE60)
 
 /* Find Control/Status reg for given Tx DMA/FIFO channel */
-#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
-	(FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
+#define FH49_TCSR_CHNL_NUM                            (7)
+#define FH50_TCSR_CHNL_NUM                            (8)
 
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
+/* TCSR: tx_config register values */
+#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl)	\
+		(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl))
+#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl)	\
+		(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x4)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl)	\
+		(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x8)
 
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF        (0x40000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF		(0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRV		(0x00000001)
 
-#define FH_TCSR_CHNL_NUM                            (7)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE	(0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE	(0x00000008)
 
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY          (0x00000000)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT           (0x00002000)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID          (0x00000003)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT	(0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD	(0x00100000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD	(0x00200000)
 
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT           (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD          (0x00100000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD           (0x00200000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT	(0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD	(0x00400000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD	(0x00800000)
 
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM      (20)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX      (12)
-#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
-	(FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
-#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \
-	  (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \
-	 (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE	(0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF	(0x40000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE	(0x80000000)
+
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY	(0x00000000)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT	(0x00002000)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID	(0x00000003)
+
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM		(20)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX		(12)
 
 /**
  * Tx Shared Status Registers (TSSR)
@@ -360,7 +377,7 @@
 #define FH_TSSR_LOWER_BOUND		(FH_MEM_LOWER_BOUND + 0xEA0)
 #define FH_TSSR_UPPER_BOUND		(FH_MEM_LOWER_BOUND + 0xEC0)
 
-#define FH_TSSR_TX_STATUS_REG	(FH_TSSR_LOWER_BOUND + 0x010)
+#define FH_TSSR_TX_STATUS_REG		(FH_TSSR_LOWER_BOUND + 0x010)
 
 #define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24)
 #define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16)
@@ -369,25 +386,99 @@
 	(FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
 	FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
 
-
-
-#define FH_REGS_LOWER_BOUND		     (0x1000)
-#define FH_REGS_UPPER_BOUND		     (0x2000)
-
 /* Tx service channels */
-#define FH_SRVC_CHNL                                (9)
-#define FH_SRVC_LOWER_BOUND          (FH_REGS_LOWER_BOUND + 0x9C8)
-#define FH_SRVC_UPPER_BOUND          (FH_REGS_LOWER_BOUND + 0x9D0)
+#define FH_SRVC_CHNL		(9)
+#define FH_SRVC_LOWER_BOUND	(FH_MEM_LOWER_BOUND + 0x9C8)
+#define FH_SRVC_UPPER_BOUND	(FH_MEM_LOWER_BOUND + 0x9D0)
 #define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \
 		(FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4)
 
-/* TFDB  Area - TFDs buffer table */
-#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK      (0xFFFFFFFF)
-#define FH_TFDIB_LOWER_BOUND       (FH_REGS_LOWER_BOUND + 0x900)
-#define FH_TFDIB_UPPER_BOUND       (FH_REGS_LOWER_BOUND + 0x958)
-#define FH_TFDIB_CTRL0_REG(_chnl)  (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl))
-#define FH_TFDIB_CTRL1_REG(_chnl)  (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4)
+#define FH_TX_CHICKEN_BITS_REG	(FH_MEM_LOWER_BOUND + 0xE98)
+/* Instruct FH to increment the retry count of a packet when
+ * it is brought from the memory to TX-FIFO
+ */
+#define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN	(0x00000002)
 
-/* TCSR: tx_config register values */
-#define FH_RSCSR_FRAME_SIZE_MSK	(0x00003FFF)	/* bits 0-13 */
+/**
+ * struct iwl_rb_status - reseve buffer status
+ * 	host memory mapped FH registers
+ * @closed_rb_num [0:11] - Indicates the index of the RB which was closed
+ * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed
+ * @finished_rb_num [0:11] - Indicates the index of the current RB
+ * 	in which the last frame was written to
+ * @finished_fr_num [0:11] - Indicates the index of the RX Frame
+ * 	which was transfered
+ */
+struct iwl_rb_status {
+	__le16 closed_rb_num;
+	__le16 closed_fr_num;
+	__le16 finished_rb_num;
+	__le16 finished_fr_nam;
+} __attribute__ ((packed));
 
+
+#define TFD_QUEUE_SIZE_MAX      (256)
+#define TFD_QUEUE_SIZE_BC_DUP	(64)
+#define TFD_QUEUE_BC_SIZE	(TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP)
+#define IWL_TX_DMA_MASK        DMA_BIT_MASK(36)
+#define IWL_NUM_OF_TBS		20
+
+static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr)
+{
+	return (sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0) & 0xF;
+}
+/**
+ * struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor
+ *
+ * This structure contains dma address and length of transmission address
+ *
+ * @lo: low [31:0] portion of the dma address of TX buffer
+ * 	every even is unaligned on 16 bit boundary
+ * @hi_n_len 0-3 [35:32] portion of dma
+ *	     4-15 length of the tx buffer
+ */
+struct iwl_tfd_tb {
+	__le32 lo;
+	__le16 hi_n_len;
+} __attribute__((packed));
+
+/**
+ * struct iwl_tfd
+ *
+ * Transmit Frame Descriptor (TFD)
+ *
+ * @ __reserved1[3] reserved
+ * @ num_tbs 0-4 number of active tbs
+ *	     5   reserved
+ * 	     6-7 padding (not used)
+ * @ tbs[20]	transmit frame buffer descriptors
+ * @ __pad 	padding
+ *
+ * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM.
+ * Both driver and device share these circular buffers, each of which must be
+ * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes
+ *
+ * Driver must indicate the physical address of the base of each
+ * circular buffer via the FH_MEM_CBBC_QUEUE registers.
+ *
+ * Each TFD contains pointer/size information for up to 20 data buffers
+ * in host DRAM.  These buffers collectively contain the (one) frame described
+ * by the TFD.  Each buffer must be a single contiguous block of memory within
+ * itself, but buffers may be scattered in host DRAM.  Each buffer has max size
+ * of (4K - 4).  The concatenates all of a TFD's buffers into a single
+ * Tx frame, up to 8 KBytes in size.
+ *
+ * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
+ */
+struct iwl_tfd {
+	u8 __reserved1[3];
+	u8 num_tbs;
+	struct iwl_tfd_tb tbs[IWL_NUM_OF_TBS];
+	__le32 __pad;
+} __attribute__ ((packed));
+
+
+/* Keep Warm Size */
+#define IWL_KW_SIZE 0x1000	/* 4k */
+
+#endif /* !__iwl_fh_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 8300f3d..01a2169 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -22,7 +22,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
 
@@ -36,7 +36,7 @@
 #include "iwl-core.h"
 
 
-#define IWL_CMD(x) case x : return #x
+#define IWL_CMD(x) case x: return #x
 
 const char *get_cmd_string(u8 cmd)
 {
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index 41eed67..ca4f638 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -32,110 +32,6 @@
 
 #include <linux/ctype.h>
 
-/*
- * The structures defined by the hardware/uCode interface
- * have bit-wise operations.  For each bit-field there is
- * a data symbol in the structure, the start bit position
- * and the length of the bit-field.
- *
- * iwl_get_bits and iwl_set_bits will return or set the
- * appropriate bits on a 32-bit value.
- *
- * IWL_GET_BITS and IWL_SET_BITS use symbol expansion to
- * expand out to the appropriate call to iwl_get_bits
- * and iwl_set_bits without having to reference all of the
- * numerical constants and defines provided in the hardware
- * definition
- */
-
-/**
- * iwl_get_bits - Extract a hardware bit-field value
- * @src: source hardware value (__le32)
- * @pos: bit-position (0-based) of first bit of value
- * @len: length of bit-field
- *
- * iwl_get_bits will return the bit-field in cpu endian ordering.
- *
- * NOTE:  If used from IWL_GET_BITS then pos and len are compile-constants and
- *        will collapse to minimal code by the compiler.
- */
-static inline u32 iwl_get_bits(__le32 src, u8 pos, u8 len)
-{
-	u32 tmp = le32_to_cpu(src);
-
-	tmp >>= pos;
-	tmp &= (1UL << len) - 1;
-	return tmp;
-}
-
-/**
- * iwl_set_bits - Set a hardware bit-field value
- * @dst: Address of __le32 hardware value
- * @pos: bit-position (0-based) of first bit of value
- * @len: length of bit-field
- * @val: cpu endian value to encode into the bit-field
- *
- * iwl_set_bits will encode val into dst, masked to be len bits long at bit
- * position pos.
- *
- * NOTE:  If used IWL_SET_BITS pos and len will be compile-constants and
- *        will collapse to minimal code by the compiler.
- */
-static inline void iwl_set_bits(__le32 *dst, u8 pos, u8 len, int val)
-{
-	u32 tmp = le32_to_cpu(*dst);
-
-	tmp &= ~(((1UL << len) - 1) << pos);
-	tmp |= (val & ((1UL << len) - 1)) << pos;
-	*dst = cpu_to_le32(tmp);
-}
-
-static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val)
-{
-	u16 tmp = le16_to_cpu(*dst);
-
-	tmp &= ~((1UL << (pos + len)) - (1UL << pos));
-	tmp |= (val & ((1UL << len) - 1)) << pos;
-	*dst = cpu_to_le16(tmp);
-}
-
-/*
- * The bit-field definitions in iwl-xxxx-hw.h are in the form of:
- *
- * struct example {
- *         __le32 val1;
- * #define IWL_name_POS 8
- * #define IWL_name_LEN 4
- * #define IWL_name_SYM val1
- * };
- *
- * The IWL_SET_BITS and IWL_GET_BITS macros are provided to allow the driver
- * to call:
- *
- * struct example bar;
- * u32 val = IWL_GET_BITS(bar, name);
- * val = val * 2;
- * IWL_SET_BITS(bar, name, val);
- *
- * All cpu / host ordering, masking, and shifts are performed by the macros
- * and iwl_{get,set}_bits.
- *
- */
-#define IWL_SET_BITS(s, sym, v) \
-	iwl_set_bits(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
-		     IWL_ ## sym ## _LEN, (v))
-
-#define IWL_SET_BITS16(s, sym, v) \
-	iwl_set_bits16(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
-		       IWL_ ## sym ## _LEN, (v))
-
-#define IWL_GET_BITS(s, sym) \
-	iwl_get_bits((s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
-		      IWL_ ## sym ## _LEN)
-
-
-#define KELVIN_TO_CELSIUS(x) ((x)-273)
-#define CELSIUS_TO_KELVIN(x) ((x)+273)
 #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
 
 
@@ -159,11 +55,6 @@
 	return end + (MAX_JIFFY_OFFSET - start) + 1;
 }
 
-static inline u8 iwl_get_dma_hi_address(dma_addr_t addr)
-{
-	return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0;
-}
-
 /**
  * iwl_queue_inc_wrap - increment queue index, wrap back to beginning
  * @index -- current index
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 9740fcc..0a92e74 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -21,7 +21,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -55,7 +55,7 @@
  * _iwl_read32.)
  *
  * These declarations are *extremely* useful in quickly isolating code deltas
- * which result in misconfiguring of the hardware I/O.  In combination with
+ * which result in misconfiguration of the hardware I/O.  In combination with
  * git-bisect and the IO debug level you can quickly determine the specific
  * commit which breaks the IO sequence to the hardware.
  *
@@ -87,17 +87,18 @@
 #define iwl_read32(p, o) _iwl_read32(p, o)
 #endif
 
+#define IWL_POLL_INTERVAL 10	/* microseconds */
 static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
 				u32 bits, u32 mask, int timeout)
 {
-	int i = 0;
+	int t = 0;
 
 	do {
 		if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
-			return i;
-		mdelay(10);
-		i += 10;
-	} while (i < timeout);
+			return t;
+		udelay(IWL_POLL_INTERVAL);
+		t += IWL_POLL_INTERVAL;
+	} while (t < timeout);
 
 	return -ETIMEDOUT;
 }
@@ -109,7 +110,7 @@
 	int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout);
 	IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
 		     addr, bits, mask,
-		     unlikely(ret  == -ETIMEDOUT)?"timeout":"", f, l);
+		     unlikely(ret  == -ETIMEDOUT) ? "timeout" : "", f, l);
 	return ret;
 }
 #define iwl_poll_bit(priv, addr, bits, mask, timeout) \
@@ -269,19 +270,10 @@
 	}
 }
 
-static inline int _iwl_poll_direct_bit(struct iwl_priv *priv,
-					   u32 addr, u32 mask, int timeout)
+static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr,
+				       u32 mask, int timeout)
 {
-	int i = 0;
-
-	do {
-		if ((_iwl_read_direct32(priv, addr) & mask) == mask)
-			return i;
-		mdelay(10);
-		i += 10;
-	} while (i < timeout);
-
-	return -ETIMEDOUT;
+	return _iwl_poll_bit(priv, addr, mask, mask, timeout);
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -308,6 +300,7 @@
 static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg)
 {
 	_iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+	rmb();
 	return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
 }
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -330,6 +323,7 @@
 {
 	_iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR,
 			      ((addr & 0x0000FFFF) | (3 << 24)));
+	wmb();
 	_iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
 }
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -392,12 +386,14 @@
 static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
 {
 	iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
+	rmb();
 	return iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
 }
 
 static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val)
 {
 	iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	wmb();
 	iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
 }
 
@@ -405,6 +401,7 @@
 					  u32 len, u32 *values)
 {
 	iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	wmb();
 	for (; 0 < len; len -= sizeof(u32), values++)
 		iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 4eee1b1..11eccd7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -41,7 +41,6 @@
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
-#include "iwl-helpers.h"
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 static const char *led_type_str[] = {
@@ -278,7 +277,7 @@
 	/* FIXME: + priv->rx_stats[2].bytes; */
 	s64 tpt = current_tpt - priv->led_tpt;
 
-	if (tpt < 0) /* wrapparound */
+	if (tpt < 0) /* wraparound */
 		tpt = -tpt;
 
 	IWL_DEBUG_LED("tpt %lld current_tpt %llu\n",
@@ -293,7 +292,7 @@
 			if (tpt  > (blink_tbl[i].tpt * IWL_1MB_RATE))
 				break;
 
-	IWL_DEBUG_LED("LED BLINK IDX=%d", i);
+	IWL_DEBUG_LED("LED BLINK IDX=%d\n", i);
 	return i;
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index 588c9ad..021e00b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 60a03d2..75ca6a5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
 
@@ -39,7 +39,6 @@
 #include "iwl-commands.h"
 #include "iwl-debug.h"
 #include "iwl-power.h"
-#include "iwl-helpers.h"
 
 /*
  * Setting power level allow the card to go to sleep when not busy
@@ -80,7 +79,7 @@
 #define IWL_REDUCED_POWER_TEMPERATURE	95
 
 /* default power management (not Tx power) table values */
-/* for tim  0-10 */
+/* for TIM  0-10 */
 static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = {
 	{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
 	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
@@ -91,7 +90,7 @@
 };
 
 
-/* for tim = 3-10 */
+/* for TIM = 3-10 */
 static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = {
 	{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
 	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
@@ -101,7 +100,7 @@
 	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2}
 };
 
-/* for tim > 11 */
+/* for TIM > 11 */
 static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = {
 	{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
 	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
@@ -183,7 +182,7 @@
 	return 0;
 }
 
-/* adjust power command according to dtim period and power level*/
+/* adjust power command according to DTIM period and power level*/
 static int iwl_update_power_command(struct iwl_priv *priv,
 				    struct iwl_powertable_cmd *cmd,
 				    u16 mode)
@@ -257,15 +256,11 @@
 	struct iwl_power_mgr *setting = &(priv->power_data);
 	int ret = 0;
 	u16 uninitialized_var(final_mode);
+	bool update_chains;
 
 	/* Don't update the RX chain when chain noise calibration is running */
-	if (priv->chain_noise_data.state != IWL_CHAIN_NOISE_DONE &&
-	    priv->chain_noise_data.state != IWL_CHAIN_NOISE_ALIVE) {
-		IWL_DEBUG_POWER("Cannot update the power, chain noise "
-			"calibration running: %d\n",
-			priv->chain_noise_data.state);
-		return -EAGAIN;
-	}
+	update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
+			priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
 
 	/* If on battery, set to 3,
 	 * if plugged into AC power, set to CAM ("continuously aware mode"),
@@ -313,9 +308,12 @@
 		else
 			set_bit(STATUS_POWER_PMI, &priv->status);
 
-		if (priv->cfg->ops->lib->update_chain_flags)
+		if (priv->cfg->ops->lib->update_chain_flags && update_chains)
 			priv->cfg->ops->lib->update_chain_flags(priv);
-
+		else
+			IWL_DEBUG_POWER("Cannot update the power, chain noise "
+					"calibration running: %d\n",
+					priv->chain_noise_data.state);
 		if (!ret)
 			setting->power_mode = final_mode;
 	}
@@ -325,7 +323,7 @@
 EXPORT_SYMBOL(iwl_power_update_mode);
 
 /* Allow other iwl code to disable/enable power management active
- * this will be usefull for rate scale to disable PM during heavy
+ * this will be useful for rate scale to disable PM during heavy
  * Tx/Rx activities
  */
 int iwl_power_disable_management(struct iwl_priv *priv, u32 ms)
@@ -352,8 +350,8 @@
 EXPORT_SYMBOL(iwl_power_disable_management);
 
 /* Allow other iwl code to disable/enable power management active
- * this will be usefull for rate scale to disable PM during hight
- * valume activities
+ * this will be useful for rate scale to disable PM during high
+ * volume activities
  */
 int iwl_power_enable_management(struct iwl_priv *priv)
 {
@@ -391,7 +389,7 @@
 }
 EXPORT_SYMBOL(iwl_power_set_system_mode);
 
-/* initilize to default */
+/* initialize to default */
 void iwl_power_initialize(struct iwl_priv *priv)
 {
 
@@ -443,7 +441,7 @@
 
 	mutex_lock(&priv->mutex);
 
-	/* on starting association we disable power managment
+	/* on starting association we disable power management
 	 * until association, if association failed then this
 	 * timer will expire and enable PM again.
 	 */
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index df484a9..fa098d8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
 #ifndef __iwl_power_setting_h__
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index ee5afd4..b7a5f23 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -25,7 +25,7 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -158,9 +158,9 @@
  *
  * 4)  Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction
  *     images in host DRAM.  The last register loaded must be the instruction
- *     bytecount register ("1" in MSbit tells initialization uCode to load
+ *     byte count register ("1" in MSbit tells initialization uCode to load
  *     the runtime uCode):
- *     BSM_DRAM_INST_BYTECOUNT_REG = bytecount | BSM_DRAM_INST_LOAD
+ *     BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD
  *
  * 5)  Wait for "alive" notification, then issue normal runtime commands.
  *
@@ -244,7 +244,7 @@
 /**
  * Tx Scheduler
  *
- * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs
+ * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs
  * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in
  * host DRAM.  It steers each frame's Tx command (which contains the frame
  * data) into one of up to 7 prioritized Tx DMA FIFO channels within the
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
index 5d64229..4b69da3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
 #include <linux/kernel.h>
@@ -34,8 +34,6 @@
 #include "iwl-eeprom.h"
 #include "iwl-dev.h"
 #include "iwl-core.h"
-#include "iwl-helpers.h"
-
 
 /* software rf-kill from user */
 static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
@@ -64,7 +62,7 @@
 		iwl_radio_kill_sw_disable_radio(priv);
 		break;
 	default:
-		IWL_WARNING("we recieved unexpected RFKILL state %d\n", state);
+		IWL_WARNING("we received unexpected RFKILL state %d\n", state);
 		break;
 	}
 out_unlock:
@@ -83,7 +81,7 @@
 	IWL_DEBUG_RF_KILL("Initializing RFKILL.\n");
 	priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
 	if (!priv->rfkill) {
-		IWL_ERROR("Unable to allocate rfkill device.\n");
+		IWL_ERROR("Unable to allocate RFKILL device.\n");
 		ret = -ENOMEM;
 		goto error;
 	}
@@ -99,7 +97,7 @@
 
 	ret = rfkill_register(priv->rfkill);
 	if (ret) {
-		IWL_ERROR("Unable to register rfkill: %d\n", ret);
+		IWL_ERROR("Unable to register RFKILL: %d\n", ret);
 		goto free_rfkill;
 	}
 
@@ -127,7 +125,7 @@
 }
 EXPORT_SYMBOL(iwl_rfkill_unregister);
 
-/* set rf-kill to the right state. */
+/* set RFKILL to the right state. */
 void iwl_rfkill_set_hw_state(struct iwl_priv *priv)
 {
 	if (!priv->rfkill)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h
index 402fd4c..86dc055 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h
+++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
 #ifndef __iwl_rf_kill_h__
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 0509c16..c5f1aa0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -218,8 +218,7 @@
 
 	/* If we've added more space for the firmware to place data, tell it.
 	 * Increment device's write pointer in multiples of 8. */
-	if ((write != (rxq->write & ~0x7))
-	    || (abs(rxq->write - rxq->read) > 7)) {
+	if (write != (rxq->write & ~0x7)) {
 		spin_lock_irqsave(&rxq->lock, flags);
 		rxq->need_update = 1;
 		spin_unlock_irqrestore(&rxq->lock, flags);
@@ -245,25 +244,31 @@
 	struct list_head *element;
 	struct iwl_rx_mem_buffer *rxb;
 	unsigned long flags;
-	spin_lock_irqsave(&rxq->lock, flags);
-	while (!list_empty(&rxq->rx_used)) {
+
+	while (1) {
+		spin_lock_irqsave(&rxq->lock, flags);
+
+		if (list_empty(&rxq->rx_used)) {
+			spin_unlock_irqrestore(&rxq->lock, flags);
+			return;
+		}
 		element = rxq->rx_used.next;
 		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		list_del(element);
+
+		spin_unlock_irqrestore(&rxq->lock, flags);
 
 		/* Alloc a new receive buffer */
 		rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
-				__GFP_NOWARN | GFP_ATOMIC);
+				     GFP_KERNEL);
 		if (!rxb->skb) {
-			if (net_ratelimit())
-				printk(KERN_CRIT DRV_NAME
-				       ": Can not allocate SKB buffers\n");
+			printk(KERN_CRIT DRV_NAME
+				   "Can not allocate SKB buffers\n");
 			/* We don't reschedule replenish work here -- we will
 			 * call the restock method and if it still needs
 			 * more buffers it will schedule replenish */
 			break;
 		}
-		priv->alloc_rxb_skb++;
-		list_del(element);
 
 		/* Get physical address of RB/SKB */
 		rxb->real_dma_addr = pci_map_single(
@@ -277,12 +282,15 @@
 		rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256);
 		skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr);
 
+		spin_lock_irqsave(&rxq->lock, flags);
+
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		rxq->free_count++;
+		priv->alloc_rxb_skb++;
+
+		spin_unlock_irqrestore(&rxq->lock, flags);
 	}
-	spin_unlock_irqrestore(&rxq->lock, flags);
 }
-EXPORT_SYMBOL(iwl_rx_allocate);
 
 void iwl_rx_replenish(struct iwl_priv *priv)
 {
@@ -317,7 +325,10 @@
 
 	pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
 			    rxq->dma_addr);
+	pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status),
+			    rxq->rb_stts, rxq->rb_stts_dma);
 	rxq->bd = NULL;
+	rxq->rb_stts  = NULL;
 }
 EXPORT_SYMBOL(iwl_rx_queue_free);
 
@@ -334,7 +345,12 @@
 	/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
 	rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
 	if (!rxq->bd)
-		return -ENOMEM;
+		goto err_bd;
+
+	rxq->rb_stts = pci_alloc_consistent(dev, sizeof(struct iwl_rb_status),
+					&rxq->rb_stts_dma);
+	if (!rxq->rb_stts)
+		goto err_rb;
 
 	/* Fill the rx_used queue with _all_ of the Rx buffers */
 	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
@@ -346,6 +362,12 @@
 	rxq->free_count = 0;
 	rxq->need_update = 0;
 	return 0;
+
+err_rb:
+	pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+			    rxq->dma_addr);
+err_bd:
+	return -ENOMEM;
 }
 EXPORT_SYMBOL(iwl_rx_queue_alloc);
 
@@ -412,10 +434,10 @@
 
 	/* Tell device where in DRAM to update its Rx status */
 	iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
-			   (priv->shared_phys + priv->rb_closed_offset) >> 4);
+			   rxq->rb_stts_dma >> 4);
 
 	/* Enable Rx DMA
-	 * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set becuase of HW bug in
+	 * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
 	 *      the credit mechanism in 5000 HW RX FIFO
 	 * Direct rx interrupts to hosts
 	 * Rx buffer size 4 or 8k
@@ -426,6 +448,7 @@
 			   FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
 			   FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
 			   FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+			   FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
 			   rb_size|
 			   (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
 			   (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
@@ -453,10 +476,8 @@
 
 	/* stop Rx DMA */
 	iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-	ret = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
-				     (1 << 24), 1000);
-	if (ret < 0)
-		IWL_ERROR("Can't stop Rx DMA.\n");
+	iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+			    FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
 
 	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -470,7 +491,7 @@
 
 {
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-	struct iwl4965_missed_beacon_notif *missed_beacon;
+	struct iwl_missed_beacon_notif *missed_beacon;
 
 	missed_beacon = &pkt->u.missed_beacon;
 	if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
@@ -485,49 +506,6 @@
 }
 EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
 
-int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn)
-{
-	unsigned long flags;
-	int sta_id;
-
-	sta_id = iwl_find_station(priv, addr);
-	if (sta_id == IWL_INVALID_STATION)
-		return -ENXIO;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-	priv->stations[sta_id].sta.station_flags_msk = 0;
-	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
-	priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
-	priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
-	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
-					CMD_ASYNC);
-}
-EXPORT_SYMBOL(iwl_rx_agg_start);
-
-int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
-{
-	unsigned long flags;
-	int sta_id;
-
-	sta_id = iwl_find_station(priv, addr);
-	if (sta_id == IWL_INVALID_STATION)
-		return -ENXIO;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-	priv->stations[sta_id].sta.station_flags_msk = 0;
-	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
-	priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
-	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
-					CMD_ASYNC);
-}
-EXPORT_SYMBOL(iwl_rx_agg_stop);
-
 
 /* Calculate noise level, based on measurements during network silence just
  *   before arriving beacon.  This measurement can be done only if we know
@@ -651,20 +629,24 @@
 	return sig_qual;
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUG
+/* Calc max signal level (dBm) among 3 possible receivers */
+static inline int iwl_calc_rssi(struct iwl_priv *priv,
+				struct iwl_rx_phy_res *rx_resp)
+{
+	return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
+}
 
+#ifdef CONFIG_IWLWIFI_DEBUG
 /**
  * iwl_dbg_report_frame - dump frame to syslog during debug sessions
  *
  * You may hack this function to show different aspects of received frames,
  * including selective frame dumps.
- * group100 parameter selects whether to show 1 out of 100 good frames.
- *
- * TODO:  This was originally written for 3945, need to audit for
- *        proper operation with 4965.
+ * group100 parameter selects whether to show 1 out of 100 good data frames.
+ *    All beacon and probe response frames are printed.
  */
 static void iwl_dbg_report_frame(struct iwl_priv *priv,
-		      struct iwl_rx_packet *pkt,
+		      struct iwl_rx_phy_res *phy_res, u16 length,
 		      struct ieee80211_hdr *header, int group100)
 {
 	u32 to_us;
@@ -676,20 +658,9 @@
 	u16 seq_ctl;
 	u16 channel;
 	u16 phy_flags;
-	int rate_sym;
-	u16 length;
-	u16 status;
-	u16 bcn_tmr;
+	u32 rate_n_flags;
 	u32 tsf_low;
-	u64 tsf;
-	u8 rssi;
-	u8 agc;
-	u16 sig_avg;
-	u16 noise_diff;
-	struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
-	struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
-	struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt);
-	u8 *data = IWL_RX_DATA(pkt);
+	int rssi;
 
 	if (likely(!(priv->debug_level & IWL_DL_RX)))
 		return;
@@ -699,22 +670,13 @@
 	seq_ctl = le16_to_cpu(header->seq_ctrl);
 
 	/* metadata */
-	channel = le16_to_cpu(rx_hdr->channel);
-	phy_flags = le16_to_cpu(rx_hdr->phy_flags);
-	rate_sym = rx_hdr->rate;
-	length = le16_to_cpu(rx_hdr->len);
-
-	/* end-of-frame status and timestamp */
-	status = le32_to_cpu(rx_end->status);
-	bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
-	tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
-	tsf = le64_to_cpu(rx_end->timestamp);
+	channel = le16_to_cpu(phy_res->channel);
+	phy_flags = le16_to_cpu(phy_res->phy_flags);
+	rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
 
 	/* signal statistics */
-	rssi = rx_stats->rssi;
-	agc = rx_stats->agc;
-	sig_avg = le16_to_cpu(rx_stats->sig_avg);
-	noise_diff = le16_to_cpu(rx_stats->noise_diff);
+	rssi = iwl_calc_rssi(priv, phy_res);
+	tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff;
 
 	to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
 
@@ -768,11 +730,13 @@
 		else
 			title = "Frame";
 
-		rate_idx = iwl_hwrate_to_plcp_idx(rate_sym);
-		if (unlikely(rate_idx == -1))
+		rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
+		if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) {
 			bitrate = 0;
-		else
+			WARN_ON_ONCE(1);
+		} else {
 			bitrate = iwl_rates[rate_idx].ieee / 2;
+		}
 
 		/* print frame summary.
 		 * MAC addresses show just the last byte (for brevity),
@@ -784,24 +748,17 @@
 				     length, rssi, channel, bitrate);
 		else {
 			/* src/dst addresses assume managed mode */
-			IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
-				     "src=0x%02x, rssi=%u, tim=%lu usec, "
+			IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, src=0x%02x, "
+				     "len=%u, rssi=%d, tim=%lu usec, "
 				     "phy=0x%02x, chnl=%d\n",
 				     title, le16_to_cpu(fc), header->addr1[5],
-				     header->addr3[5], rssi,
+				     header->addr3[5], length, rssi,
 				     tsf_low - priv->scan_start_tsf,
 				     phy_flags, channel);
 		}
 	}
 	if (print_dump)
-		iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
-}
-#else
-static inline void iwl_dbg_report_frame(struct iwl_priv *priv,
-					    struct iwl_rx_packet *pkt,
-					    struct ieee80211_hdr *header,
-					    int group100)
-{
+		iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
 }
 #endif
 
@@ -995,46 +952,6 @@
 	rxb->skb = NULL;
 }
 
-/* Calc max signal level (dBm) among 3 possible receivers */
-static inline int iwl_calc_rssi(struct iwl_priv *priv,
-				struct iwl_rx_phy_res *rx_resp)
-{
-	return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
-}
-
-
-static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-	priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
-	priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
-	priv->stations[sta_id].sta.sta.modify_mask = 0;
-	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-}
-
-static void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
-{
-	/* FIXME: need locking over ps_status ??? */
-	u8 sta_id = iwl_find_station(priv, addr);
-
-	if (sta_id != IWL_INVALID_STATION) {
-		u8 sta_awake = priv->stations[sta_id].
-				ps_status == STA_PS_STATUS_WAKE;
-
-		if (sta_awake && ps_bit)
-			priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
-		else if (!sta_awake && !ps_bit) {
-			iwl_sta_modify_ps_wake(priv, sta_id);
-			priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
-		}
-	}
-}
-
 /* This is necessary only for a number of statistics, see the caller. */
 static int iwl_is_network_packet(struct iwl_priv *priv,
 		struct ieee80211_hdr *header)
@@ -1157,9 +1074,10 @@
 		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
 
 	/* Set "1" to report good data frames in groups of 100 */
-	/* FIXME: need to optimze the call: */
-	iwl_dbg_report_frame(priv, pkt, header, 1);
-
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (unlikely(priv->debug_level & IWL_DL_RX))
+		iwl_dbg_report_frame(priv, rx_start, len, header, 1);
+#endif
 	IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n",
 		rx_status.signal, rx_status.noise, rx_status.signal,
 		(unsigned long long)rx_status.mactime);
@@ -1168,12 +1086,12 @@
 	 * "antenna number"
 	 *
 	 * It seems that the antenna field in the phy flags value
-	 * is actually a bitfield. This is undefined by radiotap,
+	 * is actually a bit field. This is undefined by radiotap,
 	 * it wants an actual antenna number but I always get "7"
 	 * for most legacy frames I receive indicating that the
 	 * same frame was received on all three RX chains.
 	 *
-	 * I think this field should be removed in favour of a
+	 * I think this field should be removed in favor of a
 	 * new 802.11n radiotap field "RX chains" that is defined
 	 * as a bitmask.
 	 */
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index c89365e..3c803f6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -22,11 +22,13 @@
  * in the file called LICENSE.GPL.
  *
  * Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
-#include <net/mac80211.h>
+#include <linux/types.h>
 #include <linux/etherdevice.h>
+#include <net/lib80211.h>
+#include <net/mac80211.h>
 
 #include "iwl-eeprom.h"
 #include "iwl-dev.h"
@@ -64,54 +66,6 @@
 #define IWL_SCAN_PROBE_MASK(n) 	cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
 
 
-static int scan_tx_ant[3] = {
-	RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK
-};
-
-
-
-static int iwl_is_empty_essid(const char *essid, int essid_len)
-{
-	/* Single white space is for Linksys APs */
-	if (essid_len == 1 && essid[0] == ' ')
-		return 1;
-
-	/* Otherwise, if the entire essid is 0, we assume it is hidden */
-	while (essid_len) {
-		essid_len--;
-		if (essid[essid_len] != '\0')
-			return 0;
-	}
-
-	return 1;
-}
-
-
-
-static const char *iwl_escape_essid(const char *essid, u8 essid_len)
-{
-	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-	const char *s = essid;
-	char *d = escaped;
-
-	if (iwl_is_empty_essid(essid, essid_len)) {
-		memcpy(escaped, "<hidden>", sizeof("<hidden>"));
-		return escaped;
-	}
-
-	essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
-	while (essid_len--) {
-		if (*s == '\0') {
-			*d++ = '\\';
-			*d++ = '0';
-			s++;
-		} else
-			*d++ = *s++;
-	}
-	*d = '\0';
-	return escaped;
-}
-
 /**
  * iwl_scan_cancel - Cancel any currently executing HW scan
  *
@@ -455,10 +409,11 @@
 
 void iwl_init_scan_params(struct iwl_priv *priv)
 {
+	u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1;
 	if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
-		priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = RATE_MCS_ANT_INIT_IND;
+		priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
 	if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
-		priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = RATE_MCS_ANT_INIT_IND;
+		priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
 }
 
 int iwl_scan_initiate(struct iwl_priv *priv)
@@ -550,7 +505,7 @@
 {
 	struct ieee80211_ht_cap *ht_cap;
 
-	if (!sband || !sband->ht_info.ht_supported)
+	if (!sband || !sband->ht_cap.ht_supported)
 		return;
 
 	if (*left < sizeof(struct ieee80211_ht_cap))
@@ -559,12 +514,12 @@
 	*pos++ = sizeof(struct ieee80211_ht_cap);
 	ht_cap = (struct ieee80211_ht_cap *) pos;
 
-	ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap);
-	memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16);
+	ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap);
+	memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16);
 	ht_cap->ampdu_params_info =
-		(sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) |
-		((sband->ht_info.ampdu_density << 2) &
-			IEEE80211_HT_CAP_AMPDU_DENSITY);
+		(sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) |
+		((sband->ht_cap.ampdu_density << 2) &
+			IEEE80211_HT_AMPDU_PARM_DENSITY);
 	*left -= sizeof(struct ieee80211_ht_cap);
 }
 
@@ -670,23 +625,6 @@
 	return (u16)len;
 }
 
-static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band)
-{
-	int i, ind;
-
-	ind = priv->scan_tx_ant[band];
-	for (i = 0; i < priv->hw_params.tx_chains_num; i++) {
-		ind = (ind+1) >= priv->hw_params.tx_chains_num ? 0 : ind+1;
-		if (priv->hw_params.valid_tx_ant & (1 << ind)) {
-			priv->scan_tx_ant[band] = ind;
-			break;
-		}
-	}
-	IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind);
-	return scan_tx_ant[ind];
-}
-
-
 static void iwl_bg_request_scan(struct work_struct *data)
 {
 	struct iwl_priv *priv =
@@ -699,11 +637,13 @@
 	struct iwl_scan_cmd *scan;
 	struct ieee80211_conf *conf = NULL;
 	int ret = 0;
-	u32 tx_ant;
+	u32 rate_flags = 0;
 	u16 cmd_len;
 	enum ieee80211_band band;
 	u8 n_probes = 2;
 	u8 rx_chain = priv->hw_params.valid_rx_ant;
+	u8 rate;
+	DECLARE_SSID_BUF(ssid);
 
 	conf = ieee80211_get_hw_conf(priv->hw);
 
@@ -714,7 +654,7 @@
 		goto done;
 	}
 
-	/* Make sure the scan wasn't cancelled before this queued work
+	/* Make sure the scan wasn't canceled before this queued work
 	 * was given the chance to run... */
 	if (!test_bit(STATUS_SCANNING, &priv->status))
 		goto done;
@@ -796,20 +736,13 @@
 	/* We should add the ability for user to lock to PASSIVE ONLY */
 	if (priv->one_direct_scan) {
 		IWL_DEBUG_SCAN("Start direct scan for '%s'\n",
-				iwl_escape_essid(priv->direct_ssid,
-				priv->direct_ssid_len));
+				print_ssid(ssid, priv->direct_ssid,
+					   priv->direct_ssid_len));
 		scan->direct_scan[0].id = WLAN_EID_SSID;
 		scan->direct_scan[0].len = priv->direct_ssid_len;
 		memcpy(scan->direct_scan[0].ssid,
 		       priv->direct_ssid, priv->direct_ssid_len);
 		n_probes++;
-	} else if (!iwl_is_associated(priv) && priv->essid_len) {
-		IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n",
-				iwl_escape_essid(priv->essid, priv->essid_len));
-		scan->direct_scan[0].id = WLAN_EID_SSID;
-		scan->direct_scan[0].len = priv->essid_len;
-		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-		n_probes++;
 	} else {
 		IWL_DEBUG_SCAN("Start indirect scan.\n");
 	}
@@ -822,23 +755,16 @@
 	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
 		band = IEEE80211_BAND_2GHZ;
 		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
-		tx_ant = iwl_scan_tx_ant(priv, band);
-		if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK)
-			scan->tx_cmd.rate_n_flags =
-				iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
-							tx_ant);
-		else
-			scan->tx_cmd.rate_n_flags =
-				iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
-							tx_ant |
-							RATE_MCS_CCK_MSK);
+		if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) {
+			rate = IWL_RATE_6M_PLCP;
+		} else {
+			rate = IWL_RATE_1M_PLCP;
+			rate_flags = RATE_MCS_CCK_MSK;
+		}
 		scan->good_CRC_th = 0;
 	} else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
 		band = IEEE80211_BAND_5GHZ;
-		tx_ant = iwl_scan_tx_ant(priv, band);
-		scan->tx_cmd.rate_n_flags =
-				iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
-							tx_ant);
+		rate = IWL_RATE_6M_PLCP;
 		scan->good_CRC_th = IWL_GOOD_CRC_TH;
 
 		/* Force use of chains B and C (0x6) for scan Rx for 4965
@@ -851,6 +777,11 @@
 		goto done;
 	}
 
+	priv->scan_tx_ant[band] =
+			 iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]);
+	rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
+	scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
+
 	/* MIMO is not used here, but value is required */
 	scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
 				cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
new file mode 100644
index 0000000..836c3c8
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
@@ -0,0 +1,198 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+
+#include <net/mac80211.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-spectrum.h"
+
+#define BEACON_TIME_MASK_LOW	0x00FFFFFF
+#define BEACON_TIME_MASK_HIGH	0xFF000000
+#define TIME_UNIT		1024
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in 8:24 format
+ * the high 1 byte is the beacon counts
+ * the lower 3 bytes is the time in usec within one beacon interval
+ */
+
+/* TOOD: was used in sysfs debug interface need to add to mac */
+#if 0
+static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+{
+	u32 quot;
+	u32 rem;
+	u32 interval = beacon_interval * 1024;
+
+	if (!interval || !usec)
+		return 0;
+
+	quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
+	rem = (usec % interval) & BEACON_TIME_MASK_LOW;
+
+	return (quot << 24) + rem;
+}
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+
+static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+{
+	u32 base_low = base & BEACON_TIME_MASK_LOW;
+	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
+	u32 interval = beacon_interval * TIME_UNIT;
+	u32 res = (base & BEACON_TIME_MASK_HIGH) +
+	    (addon & BEACON_TIME_MASK_HIGH);
+
+	if (base_low > addon_low)
+		res += base_low - addon_low;
+	else if (base_low < addon_low) {
+		res += interval + base_low - addon_low;
+		res += (1 << 24);
+	} else
+		res += (1 << 24);
+
+	return cpu_to_le32(res);
+}
+static int iwl_get_measurement(struct iwl_priv *priv,
+			       struct ieee80211_measurement_params *params,
+			       u8 type)
+{
+	struct iwl4965_spectrum_cmd spectrum;
+	struct iwl_rx_packet *res;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
+		.data = (void *)&spectrum,
+		.meta.flags = CMD_WANT_SKB,
+	};
+	u32 add_time = le64_to_cpu(params->start_time);
+	int rc;
+	int spectrum_resp_status;
+	int duration = le16_to_cpu(params->duration);
+
+	if (iwl_is_associated(priv))
+		add_time =
+		    iwl_usecs_to_beacons(
+			le64_to_cpu(params->start_time) - priv->last_tsf,
+			le16_to_cpu(priv->rxon_timing.beacon_interval));
+
+	memset(&spectrum, 0, sizeof(spectrum));
+
+	spectrum.channel_count = cpu_to_le16(1);
+	spectrum.flags =
+	    RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
+	spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
+	cmd.len = sizeof(spectrum);
+	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
+
+	if (iwl_is_associated(priv))
+		spectrum.start_time =
+		    iwl_add_beacon_time(priv->last_beacon_time,
+				add_time,
+				le16_to_cpu(priv->rxon_timing.beacon_interval));
+	else
+		spectrum.start_time = 0;
+
+	spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
+	spectrum.channels[0].channel = params->channel;
+	spectrum.channels[0].type = type;
+	if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
+		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
+
+	rc = iwl_send_cmd_sync(priv, &cmd);
+	if (rc)
+		return rc;
+
+	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
+		rc = -EIO;
+	}
+
+	spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+	switch (spectrum_resp_status) {
+	case 0:		/* Command will be handled */
+		if (res->u.spectrum.id != 0xff) {
+			IWL_DEBUG_INFO
+			    ("Replaced existing measurement: %d\n",
+			     res->u.spectrum.id);
+			priv->measurement_status &= ~MEASUREMENT_READY;
+		}
+		priv->measurement_status |= MEASUREMENT_ACTIVE;
+		rc = 0;
+		break;
+
+	case 1:		/* Command will not be handled */
+		rc = -EAGAIN;
+		break;
+	}
+
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+#endif
+
+static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+					  struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+	struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+	if (!report->state) {
+		IWL_DEBUG(IWL_DL_11H,
+			"Spectrum Measure Notification: Start\n");
+		return;
+	}
+
+	memcpy(&priv->measure_report, report, sizeof(*report));
+	priv->measurement_status |= MEASUREMENT_READY;
+}
+
+void iwl_setup_spectrum_handlers(struct iwl_priv *priv)
+{
+	priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+			iwl_rx_spectrum_measure_notif;
+}
+EXPORT_SYMBOL(iwl_setup_spectrum_handlers);
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
index a40a217..b7d7943 100644
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
@@ -21,7 +21,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -88,4 +88,5 @@
 		struct ieee80211_basic_report basic[0];
 	} u;
 } __attribute__ ((packed));
+
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 26f7084..412f66b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -33,8 +33,6 @@
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-sta.h"
-#include "iwl-helpers.h"
-
 
 #define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
 #define IWL_STA_UCODE_ACTIVE  BIT(1) /* ucode entry is active */
@@ -45,7 +43,6 @@
 	int start = 0;
 	int ret = IWL_INVALID_STATION;
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
 
 	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
 	    (priv->iw_mode == NL80211_IFTYPE_AP))
@@ -63,8 +60,8 @@
 			goto out;
 		}
 
-	IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
-			      print_mac(mac, addr), priv->num_stations);
+	IWL_DEBUG_ASSOC_LIMIT("can not find STA %pM total %d\n",
+			      addr, priv->num_stations);
 
  out:
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
@@ -86,7 +83,6 @@
 static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
 {
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
 
 	spin_lock_irqsave(&priv->sta_lock, flags);
 
@@ -94,8 +90,8 @@
 		IWL_ERROR("ACTIVATE a non DRIVER active station %d\n", sta_id);
 
 	priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
-	IWL_DEBUG_ASSOC("Added STA to Ucode: %s\n",
-			print_mac(mac, priv->stations[sta_id].sta.sta.addr));
+	IWL_DEBUG_ASSOC("Added STA to Ucode: %pM\n",
+			priv->stations[sta_id].sta.sta.addr);
 
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
@@ -104,7 +100,9 @@
 				   struct iwl_cmd *cmd, struct sk_buff *skb)
 {
 	struct iwl_rx_packet *res = NULL;
-	u8 sta_id = cmd->cmd.addsta.sta.sta_id;
+	struct iwl_addsta_cmd *addsta =
+		(struct iwl_addsta_cmd *)cmd->cmd.payload;
+	u8 sta_id = addsta->sta.sta_id;
 
 	if (!skb) {
 		IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
@@ -132,7 +130,7 @@
 	return 1;
 }
 
-int iwl_send_add_sta(struct iwl_priv *priv,
+static int iwl_send_add_sta(struct iwl_priv *priv,
 		     struct iwl_addsta_cmd *sta, u8 flags)
 {
 	struct iwl_rx_packet *res = NULL;
@@ -180,10 +178,9 @@
 
 	return ret;
 }
-EXPORT_SYMBOL(iwl_send_add_sta);
 
 static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
-				   struct ieee80211_ht_info *sta_ht_inf)
+				   struct ieee80211_sta_ht_cap *sta_ht_inf)
 {
 	__le32 sta_flags;
 	u8 mimo_ps_mode;
@@ -231,13 +228,12 @@
  * iwl_add_station_flags - Add station to tables in driver and device
  */
 u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
-			 u8 flags, struct ieee80211_ht_info *ht_info)
+			 u8 flags, struct ieee80211_sta_ht_cap *ht_info)
 {
 	int i;
 	int sta_id = IWL_INVALID_STATION;
 	struct iwl_station_entry *station;
 	unsigned long flags_spin;
-	DECLARE_MAC_BUF(mac);
 
 	spin_lock_irqsave(&priv->sta_lock, flags_spin);
 	if (is_ap)
@@ -273,8 +269,8 @@
 
 	station = &priv->stations[sta_id];
 	station->used = IWL_STA_DRIVER_ACTIVE;
-	IWL_DEBUG_ASSOC("Add STA to driver ID %d: %s\n",
-			sta_id, print_mac(mac, addr));
+	IWL_DEBUG_ASSOC("Add STA to driver ID %d: %pM\n",
+			sta_id, addr);
 	priv->num_stations++;
 
 	/* Set up the REPLY_ADD_STA command to send to device */
@@ -301,14 +297,11 @@
 static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
 {
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
-
 	u8 sta_id = iwl_find_station(priv, addr);
 
 	BUG_ON(sta_id == IWL_INVALID_STATION);
 
-	IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n",
-			print_mac(mac, addr));
+	IWL_DEBUG_ASSOC("Removed STA from Ucode: %pM\n", addr);
 
 	spin_lock_irqsave(&priv->sta_lock, flags);
 
@@ -326,7 +319,9 @@
 				   struct iwl_cmd *cmd, struct sk_buff *skb)
 {
 	struct iwl_rx_packet *res = NULL;
-	const char *addr = cmd->cmd.rm_sta.addr;
+	struct iwl_rem_sta_cmd *rm_sta =
+		 (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
+	const char *addr = rm_sta->addr;
 
 	if (!skb) {
 		IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n");
@@ -415,7 +410,6 @@
 	int sta_id = IWL_INVALID_STATION;
 	int i, ret = -EINVAL;
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
 
 	spin_lock_irqsave(&priv->sta_lock, flags);
 
@@ -435,18 +429,18 @@
 	if (unlikely(sta_id == IWL_INVALID_STATION))
 		goto out;
 
-	IWL_DEBUG_ASSOC("Removing STA from driver:%d  %s\n",
-		sta_id, print_mac(mac, addr));
+	IWL_DEBUG_ASSOC("Removing STA from driver:%d  %pM\n",
+		sta_id, addr);
 
 	if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
-		IWL_ERROR("Removing %s but non DRIVER active\n",
-				print_mac(mac, addr));
+		IWL_ERROR("Removing %pM but non DRIVER active\n",
+				addr);
 		goto out;
 	}
 
 	if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
-		IWL_ERROR("Removing %s but non UCODE active\n",
-				print_mac(mac, addr));
+		IWL_ERROR("Removing %pM but non UCODE active\n",
+				addr);
 		goto out;
 	}
 
@@ -467,6 +461,29 @@
 }
 EXPORT_SYMBOL(iwl_remove_station);
 
+/**
+ * iwl_clear_stations_table - Clear the driver's station table
+ *
+ * NOTE:  This does not clear or otherwise alter the device's station table.
+ */
+void iwl_clear_stations_table(struct iwl_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	if (iwl_is_alive(priv) &&
+	   !test_bit(STATUS_EXIT_PENDING, &priv->status) &&
+	   iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL))
+		IWL_ERROR("Couldn't clear the station table\n");
+
+	priv->num_stations = 0;
+	memset(priv->stations, 0, sizeof(priv->stations));
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+EXPORT_SYMBOL(iwl_clear_stations_table);
+
 static int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 {
 	int i;
@@ -717,6 +734,55 @@
 	return ret;
 }
 
+void iwl_update_tkip_key(struct iwl_priv *priv,
+			struct ieee80211_key_conf *keyconf,
+			const u8 *addr, u32 iv32, u16 *phase1key)
+{
+	u8 sta_id = IWL_INVALID_STATION;
+	unsigned long flags;
+	__le16 key_flags = 0;
+	int i;
+	DECLARE_MAC_BUF(mac);
+
+	sta_id = iwl_find_station(priv, addr);
+	if (sta_id == IWL_INVALID_STATION) {
+		IWL_DEBUG_MAC80211("leave - %pM not in station map.\n",
+				   addr);
+		return;
+	}
+
+	if (iwl_scan_cancel(priv)) {
+		/* cancel scan failed, just live w/ bad key and rely
+		   briefly on SW decryption */
+		return;
+	}
+
+	key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
+	key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+	key_flags &= ~STA_KEY_FLG_INVALID;
+
+	if (sta_id == priv->hw_params.bcast_sta_id)
+		key_flags |= STA_KEY_MULTICAST_MSK;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	priv->stations[sta_id].sta.key.key_flags = key_flags;
+	priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
+
+	for (i = 0; i < 5; i++)
+		priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
+			cpu_to_le16(phase1key[i]);
+
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+}
+EXPORT_SYMBOL(iwl_update_tkip_key);
+
 int iwl_remove_dynamic_key(struct iwl_priv *priv,
 				struct ieee80211_key_conf *keyconf,
 				u8 sta_id)
@@ -809,7 +875,7 @@
 {
 	int i;
 	IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
-	IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
+	IWL_DEBUG_RATE("lq ant 0x%X 0x%X\n",
 		       lq->general_params.single_stream_ant_msk,
 		       lq->general_params.dual_stream_ant_msk);
 
@@ -870,7 +936,7 @@
 	struct iwl_link_quality_cmd link_cmd = {
 		.reserved1 = 0,
 	};
-	u16 rate_flags;
+	u32 rate_flags;
 
 	/* Set up the rate scaling to start at selected rate, fall back
 	 * all the way down to 1M in IEEE order, and then spin on 1M */
@@ -886,15 +952,16 @@
 		if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
 			rate_flags |= RATE_MCS_CCK_MSK;
 
-		/* Use Tx antenna B only */
-		rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/
+		rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
+				RATE_MCS_ANT_POS;
 
 		link_cmd.rs_table[i].rate_n_flags =
 			iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
-		r = iwl4965_get_prev_ieee_rate(r);
+		r = iwl_get_prev_ieee_rate(r);
 	}
 
-	link_cmd.general_params.single_stream_ant_msk = 2;
+	link_cmd.general_params.single_stream_ant_msk =
+				first_antenna(priv->hw_params.valid_tx_ant);
 	link_cmd.general_params.dual_stream_ant_msk = 3;
 	link_cmd.agg_params.agg_dis_start_th = 3;
 	link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
@@ -910,24 +977,35 @@
  * iwl_rxon_add_station - add station into station table.
  *
  * there is only one AP station with id= IWL_AP_ID
- * NOTE: mutex must be held before calling this fnction
+ * NOTE: mutex must be held before calling this function
  */
 int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
 {
+	struct ieee80211_sta *sta;
+	struct ieee80211_sta_ht_cap ht_config;
+	struct ieee80211_sta_ht_cap *cur_ht_config = NULL;
 	u8 sta_id;
 
 	/* Add station to device's station table */
-	struct ieee80211_conf *conf = &priv->hw->conf;
-	struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
 
-	if ((is_ap) &&
-	    (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
-	    (priv->iw_mode == NL80211_IFTYPE_STATION))
-		sta_id = iwl_add_station_flags(priv, addr, is_ap,
-						   0, cur_ht_config);
-	else
-		sta_id = iwl_add_station_flags(priv, addr, is_ap,
-						   0, NULL);
+	/*
+	 * XXX: This check is definitely not correct, if we're an AP
+	 *	it'll always be false which is not what we want, but
+	 *	it doesn't look like iwlagn is prepared to be an HT
+	 *	AP anyway.
+	 */
+	if (priv->current_ht_config.is_ht) {
+		rcu_read_lock();
+		sta = ieee80211_find_sta(priv->hw, addr);
+		if (sta) {
+			memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config));
+			cur_ht_config = &ht_config;
+		}
+		rcu_read_unlock();
+	}
+
+	sta_id = iwl_add_station_flags(priv, addr, is_ap,
+				       0, cur_ht_config);
 
 	/* Set up default rate scaling table in device's station table */
 	iwl_sta_init_lq(priv, addr, is_ap);
@@ -945,7 +1023,6 @@
 {
 	int sta_id;
 	u16 fc = le16_to_cpu(hdr->frame_control);
-	DECLARE_MAC_BUF(mac);
 
 	/* If this frame is broadcast or management, use broadcast station id */
 	if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
@@ -980,9 +1057,9 @@
 		if (sta_id != IWL_INVALID_STATION)
 			return sta_id;
 
-		IWL_DEBUG_DROP("Station %s not in station map. "
+		IWL_DEBUG_DROP("Station %pM not in station map. "
 			       "Defaulting to broadcast...\n",
-			       print_mac(mac, hdr->addr1));
+			       hdr->addr1);
 		iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
 		return priv->hw_params.bcast_sta_id;
 
@@ -999,9 +1076,9 @@
 EXPORT_SYMBOL(iwl_get_sta_id);
 
 /**
- * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
+ * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
  */
-void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid)
+void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
 {
 	unsigned long flags;
 
@@ -1014,5 +1091,81 @@
 
 	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
-EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx);
+EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
+
+int iwl_sta_rx_agg_start(struct iwl_priv *priv,
+			 const u8 *addr, int tid, u16 ssn)
+{
+	unsigned long flags;
+	int sta_id;
+
+	sta_id = iwl_find_station(priv, addr);
+	if (sta_id == IWL_INVALID_STATION)
+		return -ENXIO;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.station_flags_msk = 0;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
+	priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
+	priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+					CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_sta_rx_agg_start);
+
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
+{
+	unsigned long flags;
+	int sta_id;
+
+	sta_id = iwl_find_station(priv, addr);
+	if (sta_id == IWL_INVALID_STATION)
+		return -ENXIO;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.station_flags_msk = 0;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
+	priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+					CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
+
+static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
+	priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+	priv->stations[sta_id].sta.sta.modify_mask = 0;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
+{
+	/* FIXME: need locking over ps_status ??? */
+	u8 sta_id = iwl_find_station(priv, addr);
+
+	if (sta_id != IWL_INVALID_STATION) {
+		u8 sta_awake = priv->stations[sta_id].
+				ps_status == STA_PS_STATUS_WAKE;
+
+		if (sta_awake && ps_bit)
+			priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
+		else if (!sta_awake && !ps_bit) {
+			iwl_sta_modify_ps_wake(priv, sta_id);
+			priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
+		}
+	}
+}
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index 221b93e..9bb7cef 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -47,9 +47,21 @@
 			struct ieee80211_key_conf *key, u8 sta_id);
 int iwl_remove_dynamic_key(struct iwl_priv *priv,
 			   struct ieee80211_key_conf *key, u8 sta_id);
+void iwl_update_tkip_key(struct iwl_priv *priv,
+			struct ieee80211_key_conf *keyconf,
+			const u8 *addr, u32 iv32, u16 *phase1key);
+
 int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
 int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
+void iwl_clear_stations_table(struct iwl_priv *priv);
 int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
-void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid);
 int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
+u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
+			int is_ap, u8 flags,
+			struct ieee80211_sta_ht_cap *ht_info);
+void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
+int iwl_sta_rx_agg_start(struct iwl_priv *priv,
+			 const u8 *addr, int tid, u16 ssn);
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
+void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr);
 #endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 907a53e..b0ee86c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -56,96 +56,132 @@
 	IWL_TX_FIFO_AC3
 };
 
+static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv,
+				    struct iwl_dma_ptr *ptr, size_t size)
+{
+	ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma);
+	if (!ptr->addr)
+		return -ENOMEM;
+	ptr->size = size;
+	return 0;
+}
+
+static inline void iwl_free_dma_ptr(struct iwl_priv *priv,
+				    struct iwl_dma_ptr *ptr)
+{
+	if (unlikely(!ptr->addr))
+		return;
+
+	pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma);
+	memset(ptr, 0, sizeof(*ptr));
+}
+
+static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
+{
+	struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+	dma_addr_t addr = get_unaligned_le32(&tb->lo);
+	if (sizeof(dma_addr_t) > sizeof(u32))
+		addr |=
+		((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
+
+	return addr;
+}
+
+static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
+{
+	struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+	return le16_to_cpu(tb->hi_n_len) >> 4;
+}
+
+static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
+				  dma_addr_t addr, u16 len)
+{
+	struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+	u16 hi_n_len = len << 4;
+
+	put_unaligned_le32(addr, &tb->lo);
+	if (sizeof(dma_addr_t) > sizeof(u32))
+		hi_n_len |= ((addr >> 16) >> 16) & 0xF;
+
+	tb->hi_n_len = cpu_to_le16(hi_n_len);
+
+	tfd->num_tbs = idx + 1;
+}
+
+static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
+{
+	return tfd->num_tbs & 0x1f;
+}
 
 /**
  * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
+ * @priv - driver private data
+ * @txq - tx queue
  *
  * Does NOT advance any TFD circular buffer read/write indexes
  * Does NOT free the TFD itself (which is within circular buffer)
  */
-static int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+static void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 {
-	struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
-	struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
+	struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)&txq->tfds[0];
+	struct iwl_tfd *tfd;
 	struct pci_dev *dev = priv->pci_dev;
+	int index = txq->q.read_ptr;
 	int i;
-	int counter = 0;
-	int index, is_odd;
+	int num_tbs;
 
-	/* Host command buffers stay mapped in memory, nothing to clean */
-	if (txq->q.id == IWL_CMD_QUEUE_NUM)
-		return 0;
+	tfd = &tfd_tmp[index];
 
 	/* Sanity check on number of chunks */
-	counter = IWL_GET_BITS(*bd, num_tbs);
-	if (counter > MAX_NUM_OF_TBS) {
-		IWL_ERROR("Too many chunks: %i\n", counter);
+	num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+	if (num_tbs >= IWL_NUM_OF_TBS) {
+		IWL_ERROR("Too many chunks: %i\n", num_tbs);
 		/* @todo issue fatal error, it is quite serious situation */
-		return 0;
+		return;
 	}
 
-	/* Unmap chunks, if any.
-	 * TFD info for odd chunks is different format than for even chunks. */
-	for (i = 0; i < counter; i++) {
-		index = i / 2;
-		is_odd = i & 0x1;
-
-		if (is_odd)
-			pci_unmap_single(
-				dev,
-				IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
-				(IWL_GET_BITS(bd->pa[index],
-					      tb2_addr_hi20) << 16),
-				IWL_GET_BITS(bd->pa[index], tb2_len),
+	/* Unmap tx_cmd */
+	if (num_tbs)
+		pci_unmap_single(dev,
+				pci_unmap_addr(&txq->cmd[index]->meta, mapping),
+				pci_unmap_len(&txq->cmd[index]->meta, len),
 				PCI_DMA_TODEVICE);
 
-		else if (i > 0)
-			pci_unmap_single(dev,
-					 le32_to_cpu(bd->pa[index].tb1_addr),
-					 IWL_GET_BITS(bd->pa[index], tb1_len),
-					 PCI_DMA_TODEVICE);
+	/* Unmap chunks, if any. */
+	for (i = 1; i < num_tbs; i++) {
+		pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
+				iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
 
-		/* Free SKB, if any, for this chunk */
-		if (txq->txb[txq->q.read_ptr].skb[i]) {
-			struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i];
-
-			dev_kfree_skb(skb);
-			txq->txb[txq->q.read_ptr].skb[i] = NULL;
+		if (txq->txb) {
+			dev_kfree_skb(txq->txb[txq->q.read_ptr].skb[i - 1]);
+			txq->txb[txq->q.read_ptr].skb[i - 1] = NULL;
 		}
 	}
-	return 0;
 }
 
-static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
-				 dma_addr_t addr, u16 len)
+static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
+					struct iwl_tfd *tfd,
+					dma_addr_t addr, u16 len)
 {
-	int index, is_odd;
-	struct iwl_tfd_frame *tfd = ptr;
-	u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
+
+	u32 num_tbs = iwl_tfd_get_num_tbs(tfd);
 
 	/* Each TFD can point to a maximum 20 Tx buffers */
-	if (num_tbs >= MAX_NUM_OF_TBS) {
+	if (num_tbs >= IWL_NUM_OF_TBS) {
 		IWL_ERROR("Error can not send more than %d chunks\n",
-			  MAX_NUM_OF_TBS);
+			  IWL_NUM_OF_TBS);
 		return -EINVAL;
 	}
 
-	index = num_tbs / 2;
-	is_odd = num_tbs & 0x1;
+	BUG_ON(addr & ~DMA_BIT_MASK(36));
+	if (unlikely(addr & ~IWL_TX_DMA_MASK))
+		IWL_ERROR("Unaligned address = %llx\n",
+			  (unsigned long long)addr);
 
-	if (!is_odd) {
-		tfd->pa[index].tb1_addr = cpu_to_le32(addr);
-		IWL_SET_BITS(tfd->pa[index], tb1_addr_hi,
-			     iwl_get_dma_hi_address(addr));
-		IWL_SET_BITS(tfd->pa[index], tb1_len, len);
-	} else {
-		IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16,
-			     (u32) (addr & 0xffff));
-		IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16);
-		IWL_SET_BITS(tfd->pa[index], tb2_len, len);
-	}
-
-	IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1);
+	iwl_tfd_set_tb(tfd, num_tbs, addr, len);
 
 	return 0;
 }
@@ -210,7 +246,7 @@
 	struct iwl_tx_queue *txq = &priv->txq[txq_id];
 	struct iwl_queue *q = &txq->q;
 	struct pci_dev *dev = priv->pci_dev;
-	int i, slots_num, len;
+	int i, len;
 
 	if (q->n_bd == 0)
 		return;
@@ -221,21 +257,15 @@
 		iwl_hw_txq_free_tfd(priv, txq);
 
 	len = sizeof(struct iwl_cmd) * q->n_window;
-	if (q->id == IWL_CMD_QUEUE_NUM)
-		len += IWL_MAX_SCAN_SIZE;
 
 	/* De-alloc array of command/tx buffers */
-	slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
-			TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-	for (i = 0; i < slots_num; i++)
+	for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
 		kfree(txq->cmd[i]);
-	if (txq_id == IWL_CMD_QUEUE_NUM)
-		kfree(txq->cmd[slots_num]);
 
 	/* De-alloc circular buffer of TFDs */
 	if (txq->q.n_bd)
-		pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
-				    txq->q.n_bd, txq->bd, txq->q.dma_addr);
+		pci_free_consistent(dev, sizeof(struct iwl_tfd) *
+				    txq->q.n_bd, txq->tfds, txq->q.dma_addr);
 
 	/* De-alloc array of per-TFD driver data */
 	kfree(txq->txb);
@@ -245,6 +275,40 @@
 	memset(txq, 0, sizeof(*txq));
 }
 
+
+/**
+ * iwl_cmd_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
+ */
+static void iwl_cmd_queue_free(struct iwl_priv *priv)
+{
+	struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+	struct iwl_queue *q = &txq->q;
+	struct pci_dev *dev = priv->pci_dev;
+	int i, len;
+
+	if (q->n_bd == 0)
+		return;
+
+	len = sizeof(struct iwl_cmd) * q->n_window;
+	len += IWL_MAX_SCAN_SIZE;
+
+	/* De-alloc array of command/tx buffers */
+	for (i = 0; i <= TFD_CMD_SLOTS; i++)
+		kfree(txq->cmd[i]);
+
+	/* De-alloc circular buffer of TFDs */
+	if (txq->q.n_bd)
+		pci_free_consistent(dev, sizeof(struct iwl_tfd) *
+				    txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+
+	/* 0-fill queue descriptor structure */
+	memset(txq, 0, sizeof(*txq));
+}
 /*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
  * DMA services
  *
@@ -340,13 +404,13 @@
 
 	/* Circular buffer of transmit frame descriptors (TFDs),
 	 * shared with device */
-	txq->bd = pci_alloc_consistent(dev,
-			sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+	txq->tfds = pci_alloc_consistent(dev,
+			sizeof(txq->tfds[0]) * TFD_QUEUE_SIZE_MAX,
 			&txq->q.dma_addr);
 
-	if (!txq->bd) {
+	if (!txq->tfds) {
 		IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
-			  sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+			  sizeof(txq->tfds[0]) * TFD_QUEUE_SIZE_MAX);
 		goto error;
 	}
 	txq->q.id = id;
@@ -370,26 +434,21 @@
 static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
 				struct iwl_tx_queue *txq)
 {
-	int rc;
+	int ret;
 	unsigned long flags;
 	int txq_id = txq->q.id;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_nic_access(priv);
-	if (rc) {
+	ret = iwl_grab_nic_access(priv);
+	if (ret) {
 		spin_unlock_irqrestore(&priv->lock, flags);
-		return rc;
+		return ret;
 	}
 
 	/* Circular buffer (TFD queue in DRAM) physical base address */
 	iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
 			     txq->q.dma_addr >> 8);
 
-	/* Enable DMA channel, using same id as for TFD queue */
-	iwl_write_direct32(
-		priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
-		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
-		FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
 	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -468,16 +527,20 @@
 
 	/* Tx queues */
 	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-		iwl_tx_queue_free(priv, txq_id);
+		if (txq_id == IWL_CMD_QUEUE_NUM)
+			iwl_cmd_queue_free(priv);
+		else
+			iwl_tx_queue_free(priv, txq_id);
 
-	/* Keep-warm buffer */
-	iwl_kw_free(priv);
+	iwl_free_dma_ptr(priv, &priv->kw);
+
+	iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
 }
 EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
 
 /**
  * iwl_txq_ctx_reset - Reset TX queue context
- * Destroys all DMA structures and initialise them again
+ * Destroys all DMA structures and initialize them again
  *
  * @param priv
  * @return error code
@@ -488,13 +551,17 @@
 	int txq_id, slots_num;
 	unsigned long flags;
 
-	iwl_kw_free(priv);
-
 	/* Free all tx/cmd queues and keep-warm buffer */
 	iwl_hw_txq_ctx_free(priv);
 
+	ret = iwl_alloc_dma_ptr(priv, &priv->scd_bc_tbls,
+				priv->hw_params.scd_bc_tbls_size);
+	if (ret) {
+		IWL_ERROR("Scheduler BC Table allocation failed\n");
+		goto error_bc_tbls;
+	}
 	/* Alloc keep-warm buffer */
-	ret = iwl_kw_alloc(priv);
+	ret = iwl_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE);
 	if (ret) {
 		IWL_ERROR("Keep Warm allocation failed\n");
 		goto error_kw;
@@ -509,17 +576,12 @@
 	/* Turn off all Tx DMA fifos */
 	priv->cfg->ops->lib->txq_set_sched(priv, 0);
 
+	/* Tell NIC where to find the "keep warm" buffer */
+	iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
+
 	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-
-	/* Tell nic where to find the keep-warm buffer */
-	ret = iwl_kw_init(priv);
-	if (ret) {
-		IWL_ERROR("kw_init failed\n");
-		goto error_reset;
-	}
-
 	/* Alloc and init all Tx queues, including the command queue (#4) */
 	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
 		slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
@@ -537,8 +599,10 @@
  error:
 	iwl_hw_txq_ctx_free(priv);
  error_reset:
-	iwl_kw_free(priv);
+	iwl_free_dma_ptr(priv, &priv->kw);
  error_kw:
+	iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
+ error_bc_tbls:
 	return ret;
 }
 
@@ -547,11 +611,9 @@
  */
 void iwl_txq_ctx_stop(struct iwl_priv *priv)
 {
-
-	int txq_id;
+	int ch;
 	unsigned long flags;
 
-
 	/* Turn off all Tx DMA fifos */
 	spin_lock_irqsave(&priv->lock, flags);
 	if (iwl_grab_nic_access(priv)) {
@@ -562,12 +624,11 @@
 	priv->cfg->ops->lib->txq_set_sched(priv, 0);
 
 	/* Stop each Tx DMA channel, and wait for it to be idle */
-	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-		iwl_write_direct32(priv,
-				   FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0);
+	for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
+		iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
 		iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
-				    FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
-				    (txq_id), 200);
+				    FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+				    1000);
 	}
 	iwl_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -584,7 +645,7 @@
 				  struct iwl_tx_cmd *tx_cmd,
 				  struct ieee80211_tx_info *info,
 				  struct ieee80211_hdr *hdr,
-				  int is_unicast, u8 std_id)
+				  u8 std_id)
 {
 	__le16 fc = hdr->frame_control;
 	__le32 tx_flags = tx_cmd->tx_flags;
@@ -647,11 +708,11 @@
 			      __le16 fc, int sta_id,
 			      int is_hcca)
 {
+	u32 rate_flags = 0;
+	int rate_idx;
 	u8 rts_retry_limit = 0;
 	u8 data_retry_limit = 0;
 	u8 rate_plcp;
-	u16 rate_flags = 0;
-	int rate_idx;
 
 	rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff,
 			IWL_RATE_COUNT - 1);
@@ -694,14 +755,8 @@
 			break;
 		}
 
-		/* Alternate between antenna A and B for successive frames */
-		if (priv->use_ant_b_for_management_frame) {
-			priv->use_ant_b_for_management_frame = 0;
-			rate_flags |= RATE_MCS_ANT_B_MSK;
-		} else {
-			priv->use_ant_b_for_management_frame = 1;
-			rate_flags |= RATE_MCS_ANT_A_MSK;
-		}
+		priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+		rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
 	}
 
 	tx_cmd->rts_retry_limit = rts_retry_limit;
@@ -723,7 +778,7 @@
 		memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
 		if (info->flags & IEEE80211_TX_CTL_AMPDU)
 			tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
-		IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+		IWL_DEBUG_TX("tx_cmd with AES hwcrypto\n");
 		break;
 
 	case ALG_TKIP:
@@ -767,7 +822,7 @@
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct iwl_tfd_frame *tfd;
+	struct iwl_tfd *tfd;
 	struct iwl_tx_queue *txq;
 	struct iwl_queue *q;
 	struct iwl_cmd *out_cmd;
@@ -776,10 +831,10 @@
 	dma_addr_t phys_addr;
 	dma_addr_t txcmd_phys;
 	dma_addr_t scratch_phys;
-	u16 len, idx, len_org;
+	u16 len, len_org;
 	u16 seq_number = 0;
 	__le16 fc;
-	u8 hdr_len, unicast;
+	u8 hdr_len;
 	u8 sta_id;
 	u8 wait_write_ptr = 0;
 	u8 tid = 0;
@@ -799,8 +854,6 @@
 		goto drop_unlock;
 	}
 
-	unicast = !is_multicast_ether_addr(hdr->addr1);
-
 	fc = hdr->frame_control;
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -830,10 +883,8 @@
 	/* Find (or create) index into station table for destination station */
 	sta_id = iwl_get_sta_id(priv, hdr);
 	if (sta_id == IWL_INVALID_STATION) {
-		DECLARE_MAC_BUF(mac);
-
-		IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
-			       print_mac(mac, hdr->addr1));
+		IWL_DEBUG_DROP("Dropping - INVALID STATION: %pM\n",
+			       hdr->addr1);
 		goto drop;
 	}
 
@@ -856,23 +907,22 @@
 		priv->stations[sta_id].tid[tid].tfds_in_queue++;
 	}
 
-	/* Descriptor for chosen Tx queue */
 	txq = &priv->txq[txq_id];
 	q = &txq->q;
+	txq->swq_id = swq_id;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
 	/* Set up first empty TFD within this queue's circular TFD buffer */
-	tfd = &txq->bd[q->write_ptr];
+	tfd = &txq->tfds[q->write_ptr];
 	memset(tfd, 0, sizeof(*tfd));
-	idx = get_cmd_index(q, q->write_ptr, 0);
 
 	/* Set up driver data for this TFD */
 	memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
 	txq->txb[q->write_ptr].skb[0] = skb;
 
 	/* Set up first empty entry in queue's array of Tx/cmd buffers */
-	out_cmd = txq->cmd[idx];
+	out_cmd = txq->cmd[q->write_ptr];
 	tx_cmd = &out_cmd->cmd.tx;
 	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
 	memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
@@ -912,12 +962,14 @@
 
 	/* Physical address of this Tx command's header (not MAC header!),
 	 * within command buffer array. */
-	txcmd_phys = pci_map_single(priv->pci_dev, out_cmd,
-				sizeof(struct iwl_cmd), PCI_DMA_TODEVICE);
-	txcmd_phys += offsetof(struct iwl_cmd, hdr);
-
+	txcmd_phys = pci_map_single(priv->pci_dev,
+				    out_cmd, sizeof(struct iwl_cmd),
+				    PCI_DMA_TODEVICE);
+	pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
+	pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd));
 	/* Add buffer containing Tx command and MAC(!) header to TFD's
 	 * first entry */
+	txcmd_phys += offsetof(struct iwl_cmd, hdr);
 	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
 
 	if (info->control.hw_key)
@@ -940,7 +992,7 @@
 	len = (u16)skb->len;
 	tx_cmd->len = cpu_to_le16(len);
 	/* TODO need this for burst mode later on */
-	iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id);
+	iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
 
 	/* set is_hcca to 0; it probably will never be implemented */
 	iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);
@@ -950,7 +1002,7 @@
 	scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
 		offsetof(struct iwl_tx_cmd, scratch);
 	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
-	tx_cmd->dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
+	tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
 
 	if (!ieee80211_has_morefrags(hdr->frame_control)) {
 		txq->need_update = 1;
@@ -983,7 +1035,7 @@
 			iwl_txq_update_write_ptr(priv, txq);
 			spin_unlock_irqrestore(&priv->lock, flags);
 		} else {
-			ieee80211_stop_queue(priv->hw, swq_id);
+			ieee80211_stop_queue(priv->hw, txq->swq_id);
 		}
 	}
 
@@ -1011,7 +1063,7 @@
 {
 	struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
 	struct iwl_queue *q = &txq->q;
-	struct iwl_tfd_frame *tfd;
+	struct iwl_tfd *tfd;
 	struct iwl_cmd *out_cmd;
 	dma_addr_t phys_addr;
 	unsigned long flags;
@@ -1040,7 +1092,7 @@
 
 	spin_lock_irqsave(&priv->hcmd_lock, flags);
 
-	tfd = &txq->bd[q->write_ptr];
+	tfd = &txq->tfds[q->write_ptr];
 	memset(tfd, 0, sizeof(*tfd));
 
 
@@ -1061,9 +1113,13 @@
 		out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
 	len = (idx == TFD_CMD_SLOTS) ?
 			IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd);
-	phys_addr = pci_map_single(priv->pci_dev, out_cmd, len,
-						PCI_DMA_TODEVICE);
+
+	phys_addr = pci_map_single(priv->pci_dev, out_cmd,
+				   len, PCI_DMA_TODEVICE);
+	pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr);
+	pci_unmap_len_set(&out_cmd->meta, len, len);
 	phys_addr += offsetof(struct iwl_cmd, hdr);
+
 	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -1113,8 +1169,9 @@
 		return 0;
 	}
 
-	for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
-		q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+	for (index = iwl_queue_inc_wrap(index, q->n_bd);
+	     q->read_ptr != index;
+	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
 		tx_info = &txq->txb[txq->q.read_ptr];
 		ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
@@ -1138,44 +1195,34 @@
  * need to be reclaimed. As result, some free space forms.  If there is
  * enough free space (> low mark), wake the stack that feeds us.
  */
-static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
+				   int idx, int cmd_idx)
 {
 	struct iwl_tx_queue *txq = &priv->txq[txq_id];
 	struct iwl_queue *q = &txq->q;
-	struct iwl_tfd_frame *bd = &txq->bd[index];
-	dma_addr_t dma_addr;
-	int is_odd, buf_len;
 	int nfreed = 0;
 
-	if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
+	if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) {
 		IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
 			  "is out of range [0-%d] %d %d.\n", txq_id,
-			  index, q->n_bd, q->write_ptr, q->read_ptr);
+			  idx, q->n_bd, q->write_ptr, q->read_ptr);
 		return;
 	}
 
-	for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
-		q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+	pci_unmap_single(priv->pci_dev,
+		pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping),
+		pci_unmap_len(&txq->cmd[cmd_idx]->meta, len),
+		PCI_DMA_TODEVICE);
 
-		if (nfreed > 1) {
-			IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+	for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
+	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+		if (nfreed++ > 0) {
+			IWL_ERROR("HCMD skipped: index (%d) %d %d\n", idx,
 					q->write_ptr, q->read_ptr);
 			queue_work(priv->workqueue, &priv->restart);
 		}
-		is_odd = (index/2) & 0x1;
-		if (is_odd) {
-			dma_addr = IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
-					(IWL_GET_BITS(bd->pa[index],
-							tb2_addr_hi20) << 16);
-			buf_len = IWL_GET_BITS(bd->pa[index], tb2_len);
-		} else {
-			dma_addr = le32_to_cpu(bd->pa[index].tb1_addr);
-			buf_len = IWL_GET_BITS(bd->pa[index], tb1_len);
-		}
 
-		pci_unmap_single(priv->pci_dev, dma_addr, buf_len,
-				 PCI_DMA_TODEVICE);
-		nfreed++;
 	}
 }
 
@@ -1201,8 +1248,13 @@
 	 * command queue then there a command routing bug has been introduced
 	 * in the queue management code. */
 	if (WARN(txq_id != IWL_CMD_QUEUE_NUM,
-		 "wrong command queue %d, command id 0x%X\n", txq_id, pkt->hdr.cmd))
+		 "wrong command queue %d, sequence 0x%X readp=%d writep=%d\n",
+		  txq_id, sequence,
+		  priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
+		  priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
+		iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32);
 		return;
+	}
 
 	cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
 	cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
@@ -1215,7 +1267,7 @@
 		   !cmd->meta.u.callback(priv, cmd, rxb->skb))
 		rxb->skb = NULL;
 
-	iwl_hcmd_queue_reclaim(priv, txq_id, index);
+	iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
 
 	if (!(cmd->meta.flags & CMD_ASYNC)) {
 		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
@@ -1248,15 +1300,14 @@
 	int ret;
 	unsigned long flags;
 	struct iwl_tid_data *tid_data;
-	DECLARE_MAC_BUF(mac);
 
 	if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
 		tx_fifo = default_tid_to_tx_fifo[tid];
 	else
 		return -EINVAL;
 
-	IWL_WARNING("%s on ra = %s tid = %d\n",
-			__func__, print_mac(mac, ra), tid);
+	IWL_WARNING("%s on ra = %pM tid = %d\n",
+			__func__, ra, tid);
 
 	sta_id = iwl_find_station(priv, ra);
 	if (sta_id == IWL_INVALID_STATION)
@@ -1301,7 +1352,6 @@
 	struct iwl_tid_data *tid_data;
 	int ret, write_ptr, read_ptr;
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
 
 	if (!ra) {
 		IWL_ERROR("ra = NULL\n");
@@ -1362,8 +1412,8 @@
 	case IWL_EMPTYING_HW_QUEUE_DELBA:
 		/* We are reclaiming the last packet of the */
 		/* aggregated HW queue */
-		if (txq_id  == tid_data->agg.txq_id &&
-		    q->read_ptr == q->write_ptr) {
+		if ((txq_id  == tid_data->agg.txq_id) &&
+		    (q->read_ptr == q->write_ptr)) {
 			u16 ssn = SEQ_TO_SN(tid_data->seq_number);
 			int tx_fifo = default_tid_to_tx_fifo[tid];
 			IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n");
@@ -1414,7 +1464,7 @@
 	IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->seq_ctl);
 
 	/* Calculate shift to align block-ack bits with our Tx window bits */
-	sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl>>4);
+	sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
 	if (sh < 0) /* tbw something is wrong with indices */
 		sh += 0x100;
 
@@ -1436,7 +1486,7 @@
 		ack = bitmap & (1ULL << i);
 		successes += !!ack;
 		IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
-			ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff,
+			ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
 			agg->start_idx + i);
 	}
 
@@ -1464,10 +1514,11 @@
 {
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
 	struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
-	int index;
 	struct iwl_tx_queue *txq = NULL;
 	struct iwl_ht_agg *agg;
-	DECLARE_MAC_BUF(mac);
+	int index;
+	int sta_id;
+	int tid;
 
 	/* "flow" corresponds to Tx queue */
 	u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
@@ -1482,17 +1533,19 @@
 	}
 
 	txq = &priv->txq[scd_flow];
-	agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg;
+	sta_id = ba_resp->sta_id;
+	tid = ba_resp->tid;
+	agg = &priv->stations[sta_id].tid[tid].agg;
 
 	/* Find index just before block-ack window */
 	index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
 
 	/* TODO: Need to get this copy more safely - now good for debug */
 
-	IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, "
+	IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d] Received from %pM, "
 			   "sta_id = %d\n",
 			   agg->wait_for_ba,
-			   print_mac(mac, (u8 *) &ba_resp->sta_addr_lo32),
+			   (u8 *) &ba_resp->sta_addr_lo32,
 			   ba_resp->sta_id);
 	IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = "
 			   "%d, scd_ssn = %d\n",
@@ -1513,18 +1566,15 @@
 	 * transmitted ... if not, it's too late anyway). */
 	if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
 		/* calculate mac80211 ampdu sw queue to wake */
-		int ampdu_q =
-		   scd_flow - priv->hw_params.first_ampdu_q + priv->hw->queues;
 		int freed = iwl_tx_queue_reclaim(priv, scd_flow, index);
-		priv->stations[ba_resp->sta_id].
-			tid[ba_resp->tid].tfds_in_queue -= freed;
-		if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
-			priv->mac80211_registered &&
-			agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
-			ieee80211_wake_queue(priv->hw, ampdu_q);
+		priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
 
-		iwl_txq_check_empty(priv, ba_resp->sta_id,
-				    ba_resp->tid, scd_flow);
+		if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
+		    priv->mac80211_registered &&
+		    (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
+			ieee80211_wake_queue(priv->hw, txq->swq_id);
+
+		iwl_txq_check_empty(priv, sta_id, tid, scd_flow);
 	}
 }
 EXPORT_SYMBOL(iwl_rx_reply_compressed_ba);
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 45a6b0c..d645808 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -41,6 +41,7 @@
 #include <linux/if_arp.h>
 
 #include <net/ieee80211_radiotap.h>
+#include <net/lib80211.h>
 #include <net/mac80211.h>
 
 #include <asm/div64.h>
@@ -64,11 +65,10 @@
 
 /* module parameters */
 static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */
-static int iwl3945_param_debug;    /* def: 0 = minimal debug log messages */
+static u32 iwl3945_param_debug;    /* def: 0 = minimal debug log messages */
 static int iwl3945_param_disable;  /* def: 0 = enable radio */
 static int iwl3945_param_antenna;  /* def: 0 = both antennas (use diversity) */
 int iwl3945_param_hwcrypto;        /* def: 0 = use software encryption */
-static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */
 int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */
 
 /*
@@ -93,12 +93,13 @@
 
 #define IWLWIFI_VERSION "1.2.26k" VD VS
 #define DRV_COPYRIGHT	"Copyright(c) 2003-2008 Intel Corporation"
+#define DRV_AUTHOR     "<ilw@linux.intel.com>"
 #define DRV_VERSION     IWLWIFI_VERSION
 
 
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
 MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 
 static const struct ieee80211_supported_band *iwl3945_get_band(
@@ -107,46 +108,6 @@
 	return priv->hw->wiphy->bands[band];
 }
 
-static int iwl3945_is_empty_essid(const char *essid, int essid_len)
-{
-	/* Single white space is for Linksys APs */
-	if (essid_len == 1 && essid[0] == ' ')
-		return 1;
-
-	/* Otherwise, if the entire essid is 0, we assume it is hidden */
-	while (essid_len) {
-		essid_len--;
-		if (essid[essid_len] != '\0')
-			return 0;
-	}
-
-	return 1;
-}
-
-static const char *iwl3945_escape_essid(const char *essid, u8 essid_len)
-{
-	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-	const char *s = essid;
-	char *d = escaped;
-
-	if (iwl3945_is_empty_essid(essid, essid_len)) {
-		memcpy(escaped, "<hidden>", sizeof("<hidden>"));
-		return escaped;
-	}
-
-	essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
-	while (essid_len--) {
-		if (*s == '\0') {
-			*d++ = '\\';
-			*d++ = '0';
-			s++;
-		} else
-			*d++ = *s++;
-	}
-	*d = '\0';
-	return escaped;
-}
-
 /*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
  * DMA services
  *
@@ -446,7 +407,6 @@
 	int index = IWL_INVALID_STATION;
 	struct iwl3945_station_entry *station;
 	unsigned long flags_spin;
-	DECLARE_MAC_BUF(mac);
 	u8 rate;
 
 	spin_lock_irqsave(&priv->sta_lock, flags_spin);
@@ -480,7 +440,7 @@
 		return index;
 	}
 
-	IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+	IWL_DEBUG_ASSOC("Add STA ID %d: %pM\n", index, addr);
 	station = &priv->stations[index];
 	station->used = 1;
 	priv->num_stations++;
@@ -559,7 +519,7 @@
 
 /*************** HOST COMMAND QUEUE FUNCTIONS   *****/
 
-#define IWL_CMD(x) case x : return #x
+#define IWL_CMD(x) case x: return #x
 
 static const char *get_cmd_string(u8 cmd)
 {
@@ -1063,7 +1023,6 @@
 	/* cast away the const for active_rxon in this function */
 	struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
 	int rc = 0;
-	DECLARE_MAC_BUF(mac);
 
 	if (!iwl3945_is_alive(priv))
 		return -1;
@@ -1124,11 +1083,11 @@
 	IWL_DEBUG_INFO("Sending RXON\n"
 		       "* with%s RXON_FILTER_ASSOC_MSK\n"
 		       "* channel = %d\n"
-		       "* bssid = %s\n",
+		       "* bssid = %pM\n",
 		       ((priv->staging_rxon.filter_flags &
 			 RXON_FILTER_ASSOC_MSK) ? "" : "out"),
 		       le16_to_cpu(priv->staging_rxon.channel),
-		       print_mac(mac, priv->staging_rxon.bssid_addr));
+		       priv->staging_rxon.bssid_addr);
 
 	/* Apply the new configuration */
 	rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON,
@@ -1443,7 +1402,7 @@
 
 unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
 				struct ieee80211_hdr *hdr,
-				const u8 *dest, int left)
+				int left)
 {
 
 	if (!iwl3945_is_associated(priv) || !priv->ibss_beacon ||
@@ -1459,9 +1418,16 @@
 	return priv->ibss_beacon->len;
 }
 
-static u8 iwl3945_rate_get_lowest_plcp(int rate_mask)
+static u8 iwl3945_rate_get_lowest_plcp(struct iwl3945_priv *priv)
 {
 	u8 i;
+	int rate_mask;
+
+	/* Set rate mask*/
+	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
+		rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK;
+	else
+		rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK;
 
 	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
 	     i = iwl3945_rates[i].next_ieee) {
@@ -1469,7 +1435,11 @@
 			return iwl3945_rates[i].plcp;
 	}
 
-	return IWL_RATE_INVALID;
+	/* No valid rate was found. Assign the lowest one */
+	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
+		return IWL_RATE_1M_PLCP;
+	else
+		return IWL_RATE_6M_PLCP;
 }
 
 static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv)
@@ -1487,16 +1457,7 @@
 		return -ENOMEM;
 	}
 
-	if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
-		rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic &
-						0xFF0);
-		if (rate == IWL_INVALID_RATE)
-			rate = IWL_RATE_6M_PLCP;
-	} else {
-		rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
-		if (rate == IWL_INVALID_RATE)
-			rate = IWL_RATE_1M_PLCP;
-	}
+	rate = iwl3945_rate_get_lowest_plcp(priv);
 
 	frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate);
 
@@ -1544,10 +1505,8 @@
 {
 	u16 *e = (u16 *)&priv->eeprom;
 	u32 gp = iwl3945_read32(priv, CSR_EEPROM_GP);
-	u32 r;
 	int sz = sizeof(priv->eeprom);
-	int rc;
-	int i;
+	int ret;
 	u16 addr;
 
 	/* The EEPROM structure has several padding buffers within it
@@ -1562,29 +1521,28 @@
 	}
 
 	/* Make sure driver (instead of uCode) is allowed to read EEPROM */
-	rc = iwl3945_eeprom_acquire_semaphore(priv);
-	if (rc < 0) {
+	ret = iwl3945_eeprom_acquire_semaphore(priv);
+	if (ret < 0) {
 		IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
 		return -ENOENT;
 	}
 
 	/* eeprom is an array of 16bit values */
 	for (addr = 0; addr < sz; addr += sizeof(u16)) {
-		_iwl3945_write32(priv, CSR_EEPROM_REG, addr << 1);
+		u32 r;
+
+		_iwl3945_write32(priv, CSR_EEPROM_REG,
+				 CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
 		_iwl3945_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
-
-		for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
-					i += IWL_EEPROM_ACCESS_DELAY) {
-			r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG);
-			if (r & CSR_EEPROM_REG_READ_VALID_MSK)
-				break;
-			udelay(IWL_EEPROM_ACCESS_DELAY);
-		}
-
-		if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+		ret = iwl3945_poll_direct_bit(priv, CSR_EEPROM_REG,
+					      CSR_EEPROM_REG_READ_VALID_MSK,
+					      IWL_EEPROM_ACCESS_TIMEOUT);
+		if (ret < 0) {
 			IWL_ERROR("Time out reading EEPROM[%d]\n", addr);
-			return -ETIMEDOUT;
+			return ret;
 		}
+
+		r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG);
 		e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
 	}
 
@@ -1634,7 +1592,7 @@
  */
 static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv,
 			      struct ieee80211_mgmt *frame,
-			      int left, int is_direct)
+			      int left)
 {
 	int len = 0;
 	u8 *pos = NULL;
@@ -1664,20 +1622,6 @@
 	*pos++ = WLAN_EID_SSID;
 	*pos++ = 0;
 
-	/* fill in our direct SSID IE... */
-	if (is_direct) {
-		/* ...next IE... */
-		left -= 2 + priv->essid_len;
-		if (left < 0)
-			return 0;
-		/* ... fill it in... */
-		*pos++ = WLAN_EID_SSID;
-		*pos++ = priv->essid_len;
-		memcpy(pos, priv->essid, priv->essid_len);
-		pos += priv->essid_len;
-		len += 2 + priv->essid_len;
-	}
-
 	/* fill in supported rate */
 	/* ...next IE... */
 	left -= 2;
@@ -1746,17 +1690,21 @@
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->qos_data.qos_active = 0;
 
-	if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
-		if (priv->qos_data.qos_enable)
-			priv->qos_data.qos_active = 1;
-		if (!(priv->active_rate & 0xfff0)) {
-			cw_min = 31;
-			is_legacy = 1;
-		}
-	} else if (priv->iw_mode == NL80211_IFTYPE_AP) {
-		if (priv->qos_data.qos_enable)
-			priv->qos_data.qos_active = 1;
-	} else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+	/* QoS always active in AP and ADHOC mode
+	 * In STA mode wait for association
+	 */
+	if (priv->iw_mode == NL80211_IFTYPE_ADHOC ||
+	    priv->iw_mode == NL80211_IFTYPE_AP)
+		priv->qos_data.qos_active = 1;
+	else
+		priv->qos_data.qos_active = 0;
+
+
+	/* check for legacy mode */
+	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+	     (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) ||
+	    (priv->iw_mode == NL80211_IFTYPE_STATION &&
+	     (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) {
 		cw_min = 31;
 		is_legacy = 1;
 	}
@@ -1828,9 +1776,6 @@
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
-	if (!priv->qos_data.qos_enable)
-		return;
-
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->qos_data.def_qos_parm.qos_flags = 0;
 
@@ -1846,7 +1791,7 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	if (force || iwl3945_is_associated(priv)) {
-		IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n",
+		IWL_DEBUG_QOS("send QoS cmd with QoS active %d \n",
 			      priv->qos_data.qos_active);
 
 		iwl3945_send_qos_params_command(priv,
@@ -1870,7 +1815,7 @@
 
 
 /* default power management (not Tx power) table values */
-/* for tim  0-10 */
+/* for TIM  0-10 */
 static struct iwl3945_power_vec_entry range_0[IWL_POWER_AC] = {
 	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
 	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
@@ -1880,7 +1825,7 @@
 	{{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
 };
 
-/* for tim > 10 */
+/* for TIM > 10 */
 static struct iwl3945_power_vec_entry range_1[IWL_POWER_AC] = {
 	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
 	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
@@ -2156,11 +2101,6 @@
 
 static int iwl3945_scan_initiate(struct iwl3945_priv *priv)
 {
-	if (priv->iw_mode == NL80211_IFTYPE_AP) {
-		IWL_ERROR("APs don't scan.\n");
-		return 0;
-	}
-
 	if (!iwl3945_is_ready_rf(priv)) {
 		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
 		return -EIO;
@@ -2230,13 +2170,14 @@
 /*
  * initialize rxon structure with default values from eeprom
  */
-static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
+static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv,
+					      int mode)
 {
 	const struct iwl3945_channel_info *ch_info;
 
 	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
 
-	switch (priv->iw_mode) {
+	switch (mode) {
 	case NL80211_IFTYPE_AP:
 		priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
 		break;
@@ -2259,7 +2200,7 @@
 		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
 		break;
 	default:
-		IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode);
+		IWL_ERROR("Unsupported interface type %d\n", mode);
 		break;
 	}
 
@@ -2282,8 +2223,7 @@
 	 * in some case A channels are all non IBSS
 	 * in this case force B/G channel
 	 */
-	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
-	    !(is_channel_ibss(ch_info)))
+	if ((mode == NL80211_IFTYPE_ADHOC) && !(is_channel_ibss(ch_info)))
 		ch_info = &priv->channel_info[0];
 
 	priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
@@ -2316,14 +2256,12 @@
 		}
 	}
 
-	priv->iw_mode = mode;
-
-	iwl3945_connection_init_rx_config(priv);
+	iwl3945_connection_init_rx_config(priv, mode);
 	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 
 	iwl3945_clear_stations_table(priv);
 
-	/* dont commit rxon if rf-kill is on*/
+	/* don't commit rxon if rf-kill is on*/
 	if (!iwl3945_is_ready_rf(priv))
 		return -EAGAIN;
 
@@ -2352,7 +2290,7 @@
 	case ALG_CCMP:
 		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
 		memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
-		IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+		IWL_DEBUG_TX("tx_cmd with AES hwcrypto\n");
 		break;
 
 	case ALG_TKIP:
@@ -2397,6 +2335,7 @@
 {
 	__le16 fc = hdr->frame_control;
 	__le32 tx_flags = cmd->cmd.tx.tx_flags;
+	u8 rc_flags = info->control.rates[0].flags;
 
 	cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
@@ -2423,10 +2362,10 @@
 		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
 	}
 
-	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+	if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
 		tx_flags |= TX_CMD_FLG_RTS_MSK;
 		tx_flags &= ~TX_CMD_FLG_CTS_MSK;
-	} else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+	} else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
 		tx_flags &= ~TX_CMD_FLG_RTS_MSK;
 		tx_flags |= TX_CMD_FLG_CTS_MSK;
 	}
@@ -2482,8 +2421,6 @@
 	/* If this frame is going out to an IBSS network, find the station,
 	 * or create a new station table entry */
 	case NL80211_IFTYPE_ADHOC: {
-		DECLARE_MAC_BUF(mac);
-
 		/* Create new station table entry */
 		sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
 		if (sta_id != IWL_INVALID_STATION)
@@ -2494,9 +2431,9 @@
 		if (sta_id != IWL_INVALID_STATION)
 			return sta_id;
 
-		IWL_DEBUG_DROP("Station %s not in station map. "
+		IWL_DEBUG_DROP("Station %pM not in station map. "
 			       "Defaulting to broadcast...\n",
-			       print_mac(mac, hdr->addr1));
+			       hdr->addr1);
 		iwl3945_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
 		return priv->hw_setting.bcast_sta_id;
 	}
@@ -2579,10 +2516,8 @@
 	/* Find (or create) index into station table for destination station */
 	sta_id = iwl3945_get_sta_id(priv, hdr);
 	if (sta_id == IWL_INVALID_STATION) {
-		DECLARE_MAC_BUF(mac);
-
-		IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
-			       print_mac(mac, hdr->addr1));
+		IWL_DEBUG_DROP("Dropping - INVALID STATION: %pM\n",
+			       hdr->addr1);
 		goto drop;
 	}
 
@@ -4019,8 +3954,6 @@
 #ifdef CONFIG_IWL3945_DEBUG
 static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon)
 {
-	DECLARE_MAC_BUF(mac);
-
 	IWL_DEBUG_RADIO("RX CONFIG:\n");
 	iwl3945_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
 	IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
@@ -4031,10 +3964,8 @@
 	IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
 			rxon->ofdm_basic_rates);
 	IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
-	IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
-			print_mac(mac, rxon->node_addr));
-	IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
-			print_mac(mac, rxon->bssid_addr));
+	IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr);
+	IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
 	IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
 }
 #endif
@@ -4050,7 +3981,7 @@
 /* call this function to flush any scheduled tasklet */
 static inline void iwl_synchronize_irq(struct iwl3945_priv *priv)
 {
-	/* wait to make sure we flush pedding tasklet*/
+	/* wait to make sure we flush pending tasklet*/
 	synchronize_irq(priv->pci_dev->irq);
 	tasklet_kill(&priv->irq_tasklet);
 }
@@ -4373,35 +4304,6 @@
 	/* Safely ignore these bits for debug checks below */
 	inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
 
-	/* HW RF KILL switch toggled (4965 only) */
-	if (inta & CSR_INT_BIT_RF_KILL) {
-		int hw_rf_kill = 0;
-		if (!(iwl3945_read32(priv, CSR_GP_CNTRL) &
-				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
-			hw_rf_kill = 1;
-
-		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
-				"RF_KILL bit toggled to %s.\n",
-				hw_rf_kill ? "disable radio":"enable radio");
-
-		/* Queue restart only if RF_KILL switch was set to "kill"
-		 *   when we loaded driver, and is now set to "enable".
-		 * After we're Alive, RF_KILL gets handled by
-		 *   iwl3945_rx_card_state_notif() */
-		if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) {
-			clear_bit(STATUS_RF_KILL_HW, &priv->status);
-			queue_work(priv->workqueue, &priv->restart);
-		}
-
-		handled |= CSR_INT_BIT_RF_KILL;
-	}
-
-	/* Chip got too hot and stopped itself (4965 only) */
-	if (inta & CSR_INT_BIT_CT_KILL) {
-		IWL_ERROR("Microcode CT kill error detected.\n");
-		handled |= CSR_INT_BIT_CT_KILL;
-	}
-
 	/* Error detected by uCode */
 	if (inta & CSR_INT_BIT_SW_ERR) {
 		IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
@@ -4502,7 +4404,7 @@
 
 	if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
 		/* Hardware disappeared */
-		IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+		IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta);
 		goto unplugged;
 	}
 
@@ -4805,7 +4707,7 @@
 #define IWL_PASSIVE_DWELL_BASE      (100)
 #define IWL_CHANNEL_TUNE_TIME       5
 
-#define IWL_SCAN_PROBE_MASK(n)	 cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
+#define IWL_SCAN_PROBE_MASK(n)	 (BIT(n) | (BIT(n) - BIT(1)))
 
 static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv,
 						enum ieee80211_band band,
@@ -4876,17 +4778,33 @@
 			continue;
 		}
 
-		if (!is_active || is_channel_passive(ch_info) ||
-		    (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
-			scan_ch->type = 0;	/* passive */
-		else
-			scan_ch->type = 1;	/* active */
-
-		if ((scan_ch->type & 1) && n_probes)
-			scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
-
 		scan_ch->active_dwell = cpu_to_le16(active_dwell);
 		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+		/* If passive , set up for auto-switch
+		 *  and use long active_dwell time.
+		 */
+		if (!is_active || is_channel_passive(ch_info) ||
+		    (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
+			scan_ch->type = 0;	/* passive */
+			if (IWL_UCODE_API(priv->ucode_ver) == 1)
+				scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1);
+		} else {
+			scan_ch->type = 1;	/* active */
+		}
+
+		/* Set direct probe bits. These may be used both for active
+		 * scan channels (probes gets sent right away),
+		 * or for passive channels (probes get se sent only after
+		 * hearing clear Rx packet).*/
+		if (IWL_UCODE_API(priv->ucode_ver) >= 2) {
+			if (n_probes)
+				scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
+		} else {
+			/* uCode v1 does not allow setting direct probe bits on
+			 * passive channel. */
+			if ((scan_ch->type & 1) && n_probes)
+				scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
+		}
 
 		/* Set txpower levels to defaults */
 		scan_ch->tpc.dsp_atten = 110;
@@ -5387,25 +5305,41 @@
 static int iwl3945_read_ucode(struct iwl3945_priv *priv)
 {
 	struct iwl3945_ucode *ucode;
-	int ret = 0;
+	int ret = -EINVAL, index;
 	const struct firmware *ucode_raw;
 	/* firmware file name contains uCode/driver compatibility version */
-	const char *name = priv->cfg->fw_name;
+	const char *name_pre = priv->cfg->fw_name_pre;
+	const unsigned int api_max = priv->cfg->ucode_api_max;
+	const unsigned int api_min = priv->cfg->ucode_api_min;
+	char buf[25];
 	u8 *src;
 	size_t len;
-	u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+	u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
 
 	/* Ask kernel firmware_class module to get the boot firmware off disk.
 	 * request_firmware() is synchronous, file is in memory on return. */
-	ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
-	if (ret < 0) {
-		IWL_ERROR("%s firmware file req failed: Reason %d\n",
-				name, ret);
-		goto error;
+	for (index = api_max; index >= api_min; index--) {
+		sprintf(buf, "%s%u%s", name_pre, index, ".ucode");
+		ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev);
+		if (ret < 0) {
+			IWL_ERROR("%s firmware file req failed: Reason %d\n",
+				  buf, ret);
+			if (ret == -ENOENT)
+				continue;
+			else
+				goto error;
+		} else {
+			if (index < api_max)
+				IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n",
+					  buf, api_max);
+			IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+				       buf, ucode_raw->size);
+			break;
+		}
 	}
 
-	IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
-		       name, ucode_raw->size);
+	if (ret < 0)
+		goto error;
 
 	/* Make sure that we got at least our header! */
 	if (ucode_raw->size < sizeof(*ucode)) {
@@ -5417,20 +5351,46 @@
 	/* Data from ucode file:  header followed by uCode images */
 	ucode = (void *)ucode_raw->data;
 
-	ver = le32_to_cpu(ucode->ver);
+	priv->ucode_ver = le32_to_cpu(ucode->ver);
+	api_ver = IWL_UCODE_API(priv->ucode_ver);
 	inst_size = le32_to_cpu(ucode->inst_size);
 	data_size = le32_to_cpu(ucode->data_size);
 	init_size = le32_to_cpu(ucode->init_size);
 	init_data_size = le32_to_cpu(ucode->init_data_size);
 	boot_size = le32_to_cpu(ucode->boot_size);
 
-	IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+	/* api_ver should match the api version forming part of the
+	 * firmware filename ... but we don't check for that and only rely
+	 * on the API version read from firware header from here on forward */
+
+	if (api_ver < api_min || api_ver > api_max) {
+		IWL_ERROR("Driver unable to support your firmware API. "
+			  "Driver supports v%u, firmware is v%u.\n",
+			  api_max, api_ver);
+		priv->ucode_ver = 0;
+		ret = -EINVAL;
+		goto err_release;
+	}
+	if (api_ver != api_max)
+		IWL_ERROR("Firmware has old API version. Expected %u, "
+			  "got %u. New firmware can be obtained "
+			  "from http://www.intellinuxwireless.org.\n",
+			  api_max, api_ver);
+
+	printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n",
+		       IWL_UCODE_MAJOR(priv->ucode_ver),
+		       IWL_UCODE_MINOR(priv->ucode_ver),
+		       IWL_UCODE_API(priv->ucode_ver),
+		       IWL_UCODE_SERIAL(priv->ucode_ver));
+	IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n",
+		       priv->ucode_ver);
 	IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size);
 	IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", data_size);
 	IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", init_size);
 	IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", init_data_size);
 	IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", boot_size);
 
+
 	/* Verify size of file vs. image size info in file's header */
 	if (ucode_raw->size < sizeof(*ucode) +
 		inst_size + data_size + init_size +
@@ -5607,7 +5567,7 @@
 	iwl3945_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
 				 priv->ucode_data.len);
 
-	/* Inst bytecount must be last to set up, bit 31 signals uCode
+	/* Inst byte count must be last to set up, bit 31 signals uCode
 	 *   that all new ptr/size info is in place */
 	iwl3945_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
 				 priv->ucode_code.len | BSM_DRAM_INST_LOAD);
@@ -5665,6 +5625,10 @@
 }
 
 
+/* temporary */
+static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw,
+				     struct sk_buff *skb);
+
 /**
  * iwl3945_alive_start - called after REPLY_ALIVE notification received
  *                   from protocol/runtime uCode (initialization uCode's
@@ -5699,7 +5663,7 @@
 
 	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
-		IWL_WARNING("Can not read rfkill status from adapter\n");
+		IWL_WARNING("Can not read RFKILL status from adapter\n");
 		return;
 	}
 
@@ -5709,7 +5673,7 @@
 
 	if (rfkill & 0x1) {
 		clear_bit(STATUS_RF_KILL_HW, &priv->status);
-		/* if rfkill is not on, then wait for thermal
+		/* if RFKILL is not on, then wait for thermal
 		 * sensor in adapter to kick in */
 		while (iwl3945_hw_get_temperature(priv) == 0) {
 			thermal_spin++;
@@ -5747,7 +5711,7 @@
 		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 	} else {
 		/* Initialize our rx_config data */
-		iwl3945_connection_init_rx_config(priv);
+		iwl3945_connection_init_rx_config(priv, priv->iw_mode);
 		memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 	}
 
@@ -5768,6 +5732,14 @@
 	if (priv->error_recovering)
 		iwl3945_error_recovery(priv);
 
+	/* reassociate for ADHOC mode */
+	if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
+		struct sk_buff *beacon = ieee80211_beacon_get(priv->hw,
+								priv->vif);
+		if (beacon)
+			iwl3945_mac_beacon_update(priv->hw, beacon);
+	}
+
 	return;
 
  restart:
@@ -5902,7 +5874,7 @@
 	}
 
 	if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
-		IWL_ERROR("ucode not available for device bringup\n");
+		IWL_ERROR("ucode not available for device bring up\n");
 		return -EIO;
 	}
 
@@ -6046,24 +6018,6 @@
 	iwl3945_rfkill_set_hw_state(priv);
 }
 
-static void iwl3945_bg_set_monitor(struct work_struct *work)
-{
-	struct iwl3945_priv *priv = container_of(work,
-				struct iwl3945_priv, set_monitor);
-
-	IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
-
-	mutex_lock(&priv->mutex);
-
-	if (!iwl3945_is_ready(priv))
-		IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
-	else
-		if (iwl3945_set_mode(priv, NL80211_IFTYPE_MONITOR) != 0)
-			IWL_ERROR("iwl3945_set_mode() failed\n");
-
-	mutex_unlock(&priv->mutex);
-}
-
 #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
 
 static void iwl3945_bg_scan_check(struct work_struct *data)
@@ -6101,6 +6055,7 @@
 	struct ieee80211_conf *conf = NULL;
 	u8 n_probes = 2;
 	enum ieee80211_band band;
+	DECLARE_SSID_BUF(ssid);
 
 	conf = ieee80211_get_hw_conf(priv->hw);
 
@@ -6111,7 +6066,7 @@
 		goto done;
 	}
 
-	/* Make sure the scan wasn't cancelled before this queued work
+	/* Make sure the scan wasn't canceled before this queued work
 	 * was given the chance to run... */
 	if (!test_bit(STATUS_SCANNING, &priv->status))
 		goto done;
@@ -6201,21 +6156,13 @@
 	if (priv->one_direct_scan) {
 		IWL_DEBUG_SCAN
 		    ("Kicking off one direct scan for '%s'\n",
-		     iwl3945_escape_essid(priv->direct_ssid,
-				      priv->direct_ssid_len));
+		     print_ssid(ssid, priv->direct_ssid,
+				priv->direct_ssid_len));
 		scan->direct_scan[0].id = WLAN_EID_SSID;
 		scan->direct_scan[0].len = priv->direct_ssid_len;
 		memcpy(scan->direct_scan[0].ssid,
 		       priv->direct_ssid, priv->direct_ssid_len);
 		n_probes++;
-	} else if (!iwl3945_is_associated(priv) && priv->essid_len) {
-		IWL_DEBUG_SCAN
-		  ("Kicking off one direct scan for '%s' when not associated\n",
-		   iwl3945_escape_essid(priv->essid, priv->essid_len));
-		scan->direct_scan[0].id = WLAN_EID_SSID;
-		scan->direct_scan[0].len = priv->essid_len;
-		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-		n_probes++;
 	} else
 		IWL_DEBUG_SCAN("Kicking off one indirect scan.\n");
 
@@ -6223,7 +6170,7 @@
 	 * that based on the direct_mask added to each channel entry */
 	scan->tx_cmd.len = cpu_to_le16(
 		iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
-			IWL_MAX_SCAN_SIZE - sizeof(*scan), 0));
+			IWL_MAX_SCAN_SIZE - sizeof(*scan)));
 	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
 	scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
 	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
@@ -6333,7 +6280,6 @@
 {
 	int rc = 0;
 	struct ieee80211_conf *conf = NULL;
-	DECLARE_MAC_BUF(mac);
 
 	if (priv->iw_mode == NL80211_IFTYPE_AP) {
 		IWL_ERROR("%s Should not be called in AP mode\n", __func__);
@@ -6341,9 +6287,8 @@
 	}
 
 
-	IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
-			priv->assoc_id,
-			print_mac(mac, priv->active_rxon.bssid_addr));
+	IWL_DEBUG_ASSOC("Associated as %d to: %pM\n",
+			priv->assoc_id, priv->active_rxon.bssid_addr);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
@@ -6398,10 +6343,7 @@
 
 	case NL80211_IFTYPE_ADHOC:
 
-		/* clear out the station table */
-		iwl3945_clear_stations_table(priv);
-
-		iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0);
+		priv->assoc_id = 1;
 		iwl3945_add_station(priv, priv->bssid, 0, 0);
 		iwl3945_sync_sta(priv, IWL_STA_ID,
 				 (priv->band == IEEE80211_BAND_5GHZ) ?
@@ -6439,7 +6381,7 @@
 	mutex_unlock(&priv->mutex);
 }
 
-static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed);
 
 static void iwl3945_bg_scan_completed(struct work_struct *work)
 {
@@ -6452,7 +6394,7 @@
 		return;
 
 	if (test_bit(STATUS_CONF_PENDING, &priv->status))
-		iwl3945_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw));
+		iwl3945_mac_config(priv->hw, 0);
 
 	ieee80211_scan_completed(priv->hw);
 
@@ -6604,7 +6546,6 @@
 {
 	struct iwl3945_priv *priv = hw->priv;
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
 
 	IWL_DEBUG_MAC80211("enter: type %d\n", conf->type);
 
@@ -6615,13 +6556,14 @@
 
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->vif = conf->vif;
+	priv->iw_mode = conf->type;
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	mutex_lock(&priv->mutex);
 
 	if (conf->mac_addr) {
-		IWL_DEBUG_MAC80211("Set: %s\n", print_mac(mac, conf->mac_addr));
+		IWL_DEBUG_MAC80211("Set: %pM\n", conf->mac_addr);
 		memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
 	}
 
@@ -6641,10 +6583,11 @@
  * be set inappropriately and the driver currently sets the hardware up to
  * use it whenever needed.
  */
-static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct iwl3945_priv *priv = hw->priv;
 	const struct iwl3945_channel_info *ch_info;
+	struct ieee80211_conf *conf = &hw->conf;
 	unsigned long flags;
 	int ret = 0;
 
@@ -6782,16 +6725,11 @@
 	 * clear sta table, add BCAST sta... */
 }
 
-/* temporary */
-static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
-
 static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
 					struct ieee80211_vif *vif,
 				    struct ieee80211_if_conf *conf)
 {
 	struct iwl3945_priv *priv = hw->priv;
-	DECLARE_MAC_BUF(mac);
-	unsigned long flags;
 	int rc;
 
 	if (conf == NULL)
@@ -6808,28 +6746,20 @@
 		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
 		if (!beacon)
 			return -ENOMEM;
+		mutex_lock(&priv->mutex);
 		rc = iwl3945_mac_beacon_update(hw, beacon);
+		mutex_unlock(&priv->mutex);
 		if (rc)
 			return rc;
 	}
 
-	/* XXX: this MUST use conf->mac_addr */
-
-	if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
-	    (!conf->ssid_len)) {
-		IWL_DEBUG_MAC80211
-		    ("Leaving in AP mode because HostAPD is not ready.\n");
-		return 0;
-	}
-
 	if (!iwl3945_is_alive(priv))
 		return -EAGAIN;
 
 	mutex_lock(&priv->mutex);
 
 	if (conf->bssid)
-		IWL_DEBUG_MAC80211("bssid: %s\n",
-				   print_mac(mac, conf->bssid));
+		IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid);
 
 /*
  * very dubious code was here; the probe filtering flag is never set:
@@ -6842,8 +6772,8 @@
 		if (!conf->bssid) {
 			conf->bssid = priv->mac_addr;
 			memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
-			IWL_DEBUG_MAC80211("bssid was set to: %s\n",
-					   print_mac(mac, conf->bssid));
+			IWL_DEBUG_MAC80211("bssid was set to: %pM\n",
+					   conf->bssid);
 		}
 		if (priv->ibss_beacon)
 			dev_kfree_skb(priv->ibss_beacon);
@@ -6889,15 +6819,6 @@
 	}
 
  done:
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!conf->ssid_len)
-		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-	else
-		memcpy(priv->essid, conf->ssid, conf->ssid_len);
-
-	priv->essid_len = conf->ssid_len;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	IWL_DEBUG_MAC80211("leave\n");
 	mutex_unlock(&priv->mutex);
 
@@ -6910,16 +6831,43 @@
 				 int mc_count, struct dev_addr_list *mc_list)
 {
 	struct iwl3945_priv *priv = hw->priv;
+	__le32 *filter_flags = &priv->staging_rxon.filter_flags;
 
-	if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
-		IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
-				   NL80211_IFTYPE_MONITOR,
-				   changed_flags, *total_flags);
-		/* queue work 'cuz mac80211 is holding a lock which
-		 * prevents us from issuing (synchronous) f/w cmds */
-		queue_work(priv->workqueue, &priv->set_monitor);
+	IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n",
+			changed_flags, *total_flags);
+
+	if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
+		if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
+			*filter_flags |= RXON_FILTER_PROMISC_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_PROMISC_MSK;
 	}
-	*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
+	if (changed_flags & FIF_ALLMULTI) {
+		if (*total_flags & FIF_ALLMULTI)
+			*filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK;
+	}
+	if (changed_flags & FIF_CONTROL) {
+		if (*total_flags & FIF_CONTROL)
+			*filter_flags |= RXON_FILTER_CTL2HOST_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_CTL2HOST_MSK;
+	}
+	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+			*filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+		else
+			*filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK;
+	}
+
+	/* We avoid iwl_commit_rxon here to commit the new filter flags
+	 * since mac80211 will call ieee80211_hw_config immediately.
+	 * (mc_list is not supported at this time). Otherwise, we need to
+	 * queue a background iwl_commit_rxon work.
+	 */
+
+	*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
 			FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
@@ -6940,8 +6888,6 @@
 	if (priv->vif == conf->vif) {
 		priv->vif = NULL;
 		memset(priv->bssid, 0, ETH_ALEN);
-		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-		priv->essid_len = 0;
 	}
 	mutex_unlock(&priv->mutex);
 
@@ -7010,6 +6956,7 @@
 	int rc = 0;
 	unsigned long flags;
 	struct iwl3945_priv *priv = hw->priv;
+	DECLARE_SSID_BUF(ssid_buf);
 
 	IWL_DEBUG_MAC80211("enter\n");
 
@@ -7022,12 +6969,6 @@
 		goto out_unlock;
 	}
 
-	if (priv->iw_mode == NL80211_IFTYPE_AP) {	/* APs don't scan */
-		rc = -EIO;
-		IWL_ERROR("ERROR: APs don't scan\n");
-		goto out_unlock;
-	}
-
 	/* we don't schedule scan within next_scan_jiffies period */
 	if (priv->next_scan_jiffies &&
 			time_after(priv->next_scan_jiffies, jiffies)) {
@@ -7043,7 +6984,7 @@
 	}
 	if (len) {
 		IWL_DEBUG_SCAN("direct scan for %s [%d]\n ",
-			       iwl3945_escape_essid(ssid, len), (int)len);
+			       print_ssid(ssid_buf, ssid, len), (int)len);
 
 		priv->one_direct_scan = 1;
 		priv->direct_ssid_len = (u8)
@@ -7084,10 +7025,8 @@
 
 	sta_id = iwl3945_hw_find_station(priv, addr);
 	if (sta_id == IWL_INVALID_STATION) {
-		DECLARE_MAC_BUF(mac);
-
-		IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
-				   print_mac(mac, addr));
+		IWL_DEBUG_MAC80211("leave - %pM not in station map.\n",
+				   addr);
 		return -EINVAL;
 	}
 
@@ -7143,11 +7082,6 @@
 		return 0;
 	}
 
-	if (!priv->qos_data.qos_enable) {
-		priv->qos_data.qos_active = 0;
-		IWL_DEBUG_MAC80211("leave - qos not enabled\n");
-		return 0;
-	}
 	q = AC_NUM - 1 - queue;
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -7219,14 +7153,6 @@
 	return 0;
 }
 
-static u64 iwl3945_mac_get_tsf(struct ieee80211_hw *hw)
-{
-	IWL_DEBUG_MAC80211("enter\n");
-	IWL_DEBUG_MAC80211("leave\n");
-
-	return 0;
-}
-
 static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
 {
 	struct iwl3945_priv *priv = hw->priv;
@@ -7292,18 +7218,15 @@
 	struct iwl3945_priv *priv = hw->priv;
 	unsigned long flags;
 
-	mutex_lock(&priv->mutex);
 	IWL_DEBUG_MAC80211("enter\n");
 
 	if (!iwl3945_is_ready_rf(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF not ready\n");
-		mutex_unlock(&priv->mutex);
 		return -EIO;
 	}
 
 	if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
 		IWL_DEBUG_MAC80211("leave - not IBSS\n");
-		mutex_unlock(&priv->mutex);
 		return -EIO;
 	}
 
@@ -7323,7 +7246,6 @@
 
 	iwl3945_post_associate(priv);
 
-	mutex_unlock(&priv->mutex);
 
 	return 0;
 }
@@ -7792,7 +7714,7 @@
 
 /*****************************************************************************
  *
- * driver setup and teardown
+ * driver setup and tear down
  *
  *****************************************************************************/
 
@@ -7810,7 +7732,6 @@
 	INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan);
 	INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
 	INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
-	INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor);
 	INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
 	INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
 	INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check);
@@ -7869,7 +7790,6 @@
 	.get_stats = iwl3945_mac_get_stats,
 	.get_tx_stats = iwl3945_mac_get_tx_stats,
 	.conf_tx = iwl3945_mac_conf_tx,
-	.get_tsf = iwl3945_mac_get_tsf,
 	.reset_tsf = iwl3945_mac_reset_tsf,
 	.bss_info_changed = iwl3945_bss_info_changed,
 	.hw_scan = iwl3945_mac_hw_scan
@@ -7882,7 +7802,10 @@
 	struct ieee80211_hw *hw;
 	struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
 	unsigned long flags;
-	DECLARE_MAC_BUF(mac);
+
+	/***********************
+	 * 1. Allocating HW data
+	 * ********************/
 
 	/* Disabling hardware scan means that mac80211 will perform scans
 	 * "the hard way", rather than using device's scan. */
@@ -7907,48 +7830,41 @@
 		err = -ENOMEM;
 		goto out;
 	}
+
 	SET_IEEE80211_DEV(hw, &pdev->dev);
 
-	hw->rate_control_algorithm = "iwl-3945-rs";
-	hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
-
-	IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
 	priv = hw->priv;
 	priv->hw = hw;
-
 	priv->pci_dev = pdev;
 	priv->cfg = cfg;
 
+	IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+	hw->rate_control_algorithm = "iwl-3945-rs";
+	hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
+
 	/* Select antenna (may be helpful if only one antenna is connected) */
 	priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna;
 #ifdef CONFIG_IWL3945_DEBUG
 	iwl3945_debug_level = iwl3945_param_debug;
 	atomic_set(&priv->restrict_refcnt, 0);
 #endif
-	priv->retry_rate = 1;
-
-	priv->ibss_beacon = NULL;
 
 	/* Tell mac80211 our characteristics */
 	hw->flags = IEEE80211_HW_SIGNAL_DBM |
 		    IEEE80211_HW_NOISE_DBM;
 
 	hw->wiphy->interface_modes =
-		BIT(NL80211_IFTYPE_AP) |
 		BIT(NL80211_IFTYPE_STATION) |
 		BIT(NL80211_IFTYPE_ADHOC);
 
+	hw->wiphy->fw_handles_regulatory = true;
+
 	/* 4 EDCA QOS priorities */
 	hw->queues = 4;
 
-	spin_lock_init(&priv->lock);
-	spin_lock_init(&priv->power_data.lock);
-	spin_lock_init(&priv->sta_lock);
-	spin_lock_init(&priv->hcmd_lock);
-
-	INIT_LIST_HEAD(&priv->free_frames);
-
-	mutex_init(&priv->mutex);
+	/***************************
+	 * 2. Initializing PCI bus
+	 * *************************/
 	if (pci_enable_device(pdev)) {
 		err = -ENODEV;
 		goto out_ieee80211_free_hw;
@@ -7956,14 +7872,6 @@
 
 	pci_set_master(pdev);
 
-	/* Clear the driver's (not device's) station table */
-	iwl3945_clear_stations_table(priv);
-
-	priv->data_retry_limit = -1;
-	priv->ieee_channels = NULL;
-	priv->ieee_rates = NULL;
-	priv->band = IEEE80211_BAND_2GHZ;
-
 	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 	if (!err)
 		err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
@@ -7977,10 +7885,9 @@
 	if (err)
 		goto out_pci_disable_device;
 
-	/* We disable the RETRY_TIMEOUT register (0x41) to keep
-	 * PCI Tx retries from interfering with C3 CPU state */
-	pci_write_config_byte(pdev, 0x41, 0x00);
-
+	/***********************
+	 * 3. Read REV Register
+	 * ********************/
 	priv->hw_base = pci_iomap(pdev, 0, 0);
 	if (!priv->hw_base) {
 		err = -ENODEV;
@@ -7991,64 +7898,25 @@
 			(unsigned long long) pci_resource_len(pdev, 0));
 	IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
 
-	/* Initialize module parameter values here */
-
-	/* Disable radio (SW RF KILL) via parameter when loading driver */
-	if (iwl3945_param_disable) {
-		set_bit(STATUS_RF_KILL_SW, &priv->status);
-		IWL_DEBUG_INFO("Radio disabled.\n");
-	}
-
-	priv->iw_mode = NL80211_IFTYPE_STATION;
-
-	printk(KERN_INFO DRV_NAME
-		": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
-
-	/* Device-specific setup */
-	if (iwl3945_hw_set_hw_setting(priv)) {
-		IWL_ERROR("failed to set hw settings\n");
-		goto out_iounmap;
-	}
-
-	if (iwl3945_param_qos_enable)
-		priv->qos_data.qos_enable = 1;
-
-	iwl3945_reset_qos(priv);
-
-	priv->qos_data.qos_active = 0;
-	priv->qos_data.qos_cap.val = 0;
-
-	iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
-	iwl3945_setup_deferred_work(priv);
-	iwl3945_setup_rx_handlers(priv);
-
-	priv->rates_mask = IWL_RATES_MASK;
-	/* If power management is turned on, default to AC mode */
-	priv->power_mode = IWL_POWER_AC;
-	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	iwl3945_disable_interrupts(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
-	if (err) {
-		IWL_ERROR("failed to create sysfs device attributes\n");
-		goto out_release_irq;
-	}
+	/* We disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state */
+	pci_write_config_byte(pdev, 0x41, 0x00);
 
 	/* nic init */
 	iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
 			CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
 
 	iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-	err = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
-			       CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-			       CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+	err = iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL,
+				CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 	if (err < 0) {
 		IWL_DEBUG_INFO("Failed to init the card\n");
 		goto out_remove_sysfs;
 	}
+
+	/***********************
+	 * 4. Read EEPROM
+	 * ********************/
 	/* Read the EEPROM */
 	err = iwl3945_eeprom_init(priv);
 	if (err) {
@@ -8057,13 +7925,57 @@
 	}
 	/* MAC Address location in EEPROM same for 3945/4965 */
 	get_eeprom_mac(priv, priv->mac_addr);
-	IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
+	IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr);
 	SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 
+	/***********************
+	 * 5. Setup HW Constants
+	 * ********************/
+	/* Device-specific setup */
+	if (iwl3945_hw_set_hw_setting(priv)) {
+		IWL_ERROR("failed to set hw settings\n");
+		goto out_iounmap;
+	}
+
+	/***********************
+	 * 6. Setup priv
+	 * ********************/
+	priv->retry_rate = 1;
+	priv->ibss_beacon = NULL;
+
+	spin_lock_init(&priv->lock);
+	spin_lock_init(&priv->power_data.lock);
+	spin_lock_init(&priv->sta_lock);
+	spin_lock_init(&priv->hcmd_lock);
+
+	INIT_LIST_HEAD(&priv->free_frames);
+	mutex_init(&priv->mutex);
+
+	/* Clear the driver's (not device's) station table */
+	iwl3945_clear_stations_table(priv);
+
+	priv->data_retry_limit = -1;
+	priv->ieee_channels = NULL;
+	priv->ieee_rates = NULL;
+	priv->band = IEEE80211_BAND_2GHZ;
+
+	priv->iw_mode = NL80211_IFTYPE_STATION;
+
+	iwl3945_reset_qos(priv);
+
+	priv->qos_data.qos_active = 0;
+	priv->qos_data.qos_cap.val = 0;
+
+
+	priv->rates_mask = IWL_RATES_MASK;
+	/* If power management is turned on, default to AC mode */
+	priv->power_mode = IWL_POWER_AC;
+	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+
 	err = iwl3945_init_channel_map(priv);
 	if (err) {
 		IWL_ERROR("initializing regulatory failed: %d\n", err);
-		goto out_remove_sysfs;
+		goto out_release_irq;
 	}
 
 	err = iwl3945_init_geos(priv);
@@ -8072,16 +7984,58 @@
 		goto out_free_channel_map;
 	}
 
+	printk(KERN_INFO DRV_NAME
+		": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
+
+	/***********************************
+	 * 7. Initialize Module Parameters
+	 * **********************************/
+
+	/* Initialize module parameter values here */
+	/* Disable radio (SW RF KILL) via parameter when loading driver */
+	if (iwl3945_param_disable) {
+		set_bit(STATUS_RF_KILL_SW, &priv->status);
+		IWL_DEBUG_INFO("Radio disabled.\n");
+	}
+
+
+	/***********************
+	 * 8. Setup Services
+	 * ********************/
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl3945_disable_interrupts(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+	if (err) {
+		IWL_ERROR("failed to create sysfs device attributes\n");
+		goto out_free_geos;
+	}
+
+	iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
+	iwl3945_setup_deferred_work(priv);
+	iwl3945_setup_rx_handlers(priv);
+
+	/***********************
+	 * 9. Conclude
+	 * ********************/
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+
+	/*********************************
+	 * 10. Setup and Register mac80211
+	 * *******************************/
+
 	err = ieee80211_register_hw(priv->hw);
 	if (err) {
 		IWL_ERROR("Failed to register network device (error %d)\n", err);
-		goto out_free_geos;
+		goto  out_remove_sysfs;
 	}
 
 	priv->hw->conf.beacon_int = 100;
 	priv->mac80211_registered = 1;
-	pci_save_state(pdev);
-	pci_disable_device(pdev);
+
 
 	err = iwl3945_rfkill_init(priv);
 	if (err)
@@ -8090,12 +8044,13 @@
 
 	return 0;
 
+ out_remove_sysfs:
+	sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
  out_free_geos:
 	iwl3945_free_geos(priv);
  out_free_channel_map:
 	iwl3945_free_channel_map(priv);
- out_remove_sysfs:
-	sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+
 
  out_release_irq:
 	destroy_workqueue(priv->workqueue);
@@ -8222,7 +8177,7 @@
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return 0;
 
-	IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state);
+	IWL_DEBUG_RF_KILL("we received soft RFKILL set to state %d\n", state);
 	mutex_lock(&priv->mutex);
 
 	switch (state) {
@@ -8237,7 +8192,7 @@
 		iwl3945_radio_kill_sw(priv, 1);
 		break;
 	default:
-		IWL_WARNING("we recieved unexpected RFKILL state %d\n", state);
+		IWL_WARNING("we received unexpected RFKILL state %d\n", state);
 		break;
 	}
 out_unlock:
@@ -8379,7 +8334,7 @@
 	iwl3945_rate_control_unregister();
 }
 
-MODULE_FIRMWARE("iwlwifi-3945" IWL3945_UCODE_API ".ucode");
+MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX));
 
 module_param_named(antenna, iwl3945_param_antenna, int, 0444);
 MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
@@ -8388,7 +8343,7 @@
 module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444);
 MODULE_PARM_DESC(hwcrypto,
 		 "using hardware crypto engine (default 0 [software])\n");
-module_param_named(debug, iwl3945_param_debug, int, 0444);
+module_param_named(debug, iwl3945_param_debug, uint, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
 module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444);
 MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
@@ -8396,9 +8351,5 @@
 module_param_named(queues_num, iwl3945_param_queues_num, int, 0444);
 MODULE_PARM_DESC(queues_num, "number of hw queues.");
 
-/* QoS */
-module_param_named(qos_enable, iwl3945_param_qos_enable, int, 0444);
-MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
-
 module_exit(iwl3945_exit);
 module_init(iwl3945_init);
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index 92be604..a0e440c 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -1,6 +1,10 @@
 /* Copyright (C) 2006, Red Hat, Inc. */
 
+#include <linux/types.h>
 #include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+#include <linux/if_arp.h>
+#include <net/lib80211.h>
 
 #include "assoc.h"
 #include "decl.h"
@@ -151,18 +155,18 @@
 	struct cmd_ds_802_11_ad_hoc_join cmd;
 	struct bss_descriptor *bss = &assoc_req->bss;
 	u8 preamble = RADIO_PREAMBLE_LONG;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 	u16 ratesize = 0;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
 	lbs_deb_join("current SSID '%s', ssid length %u\n",
-		escape_essid(priv->curbssparams.ssid,
+		print_ssid(ssid, priv->curbssparams.ssid,
 		priv->curbssparams.ssid_len),
 		priv->curbssparams.ssid_len);
 	lbs_deb_join("requested ssid '%s', ssid length %u\n",
-		escape_essid(bss->ssid, bss->ssid_len),
+		print_ssid(ssid, bss->ssid, bss->ssid_len),
 		bss->ssid_len);
 
 	/* check if the requested SSID is already joined */
@@ -226,8 +230,8 @@
 	       bss->capability, CAPINFO_MASK);
 
 	/* information on BSSID descriptor passed to FW */
-	lbs_deb_join("ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
-			print_mac(mac, cmd.bss.bssid), cmd.bss.ssid);
+	lbs_deb_join("ADHOC_J_CMD: BSSID = %pM, SSID = '%s'\n",
+			cmd.bss.bssid, cmd.bss.ssid);
 
 	/* Only v8 and below support setting these */
 	if (priv->fwrelease < 0x09000000) {
@@ -307,6 +311,7 @@
 	size_t ratesize = 0;
 	u16 tmpcap = 0;
 	int ret = 0;
+	DECLARE_SSID_BUF(ssid);
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
@@ -326,7 +331,7 @@
 	memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len);
 
 	lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n",
-		escape_essid(assoc_req->ssid, assoc_req->ssid_len),
+		print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
 		assoc_req->ssid_len);
 
 	cmd.bsstype = CMD_BSS_TYPE_IBSS;
@@ -338,12 +343,12 @@
 	WARN_ON(!assoc_req->channel);
 
 	/* set Physical parameter set */
-	cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET;
+	cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS;
 	cmd.phyparamset.dsparamset.len = 1;
 	cmd.phyparamset.dsparamset.currentchan = assoc_req->channel;
 
 	/* set IBSS parameter set */
-	cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET;
+	cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS;
 	cmd.ssparamset.ibssparamset.len = 2;
 	cmd.ssparamset.ibssparamset.atimwindow = 0;
 
@@ -427,8 +432,8 @@
 {
 	if (!secinfo->wep_enabled  && !secinfo->WPAenabled
 	    && !secinfo->WPA2enabled
-	    && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC
-	    && match_bss->rsn_ie[0] != MFIE_TYPE_RSN
+	    && match_bss->wpa_ie[0] != WLAN_EID_GENERIC
+	    && match_bss->rsn_ie[0] != WLAN_EID_RSN
 	    && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
 		return 1;
 	else
@@ -450,7 +455,7 @@
 				struct bss_descriptor *match_bss)
 {
 	if (!secinfo->wep_enabled && secinfo->WPAenabled
-	    && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
+	    && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
 	    /* privacy bit may NOT be set in some APs like LinkSys WRT54G
 	    && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
 	   )
@@ -463,7 +468,7 @@
 				 struct bss_descriptor *match_bss)
 {
 	if (!secinfo->wep_enabled && secinfo->WPA2enabled &&
-	    (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
+	    (match_bss->rsn_ie[0] == WLAN_EID_RSN)
 	    /* privacy bit may NOT be set in some APs like LinkSys WRT54G
 	    (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
 	   )
@@ -477,8 +482,8 @@
 {
 	if (!secinfo->wep_enabled && !secinfo->WPAenabled
 	    && !secinfo->WPA2enabled
-	    && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
-	    && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
+	    && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC)
+	    && (match_bss->rsn_ie[0] != WLAN_EID_RSN)
 	    && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
 		return 1;
 	else
@@ -694,6 +699,7 @@
 	int ret = 0;
 	struct bss_descriptor * bss;
 	int channel = -1;
+	DECLARE_SSID_BUF(ssid);
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
@@ -705,7 +711,7 @@
 		channel = assoc_req->channel;
 
 	lbs_deb_assoc("SSID '%s' requested\n",
-	              escape_essid(assoc_req->ssid, assoc_req->ssid_len));
+	              print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len));
 	if (assoc_req->mode == IW_MODE_INFRA) {
 		lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
 			assoc_req->ssid_len);
@@ -752,17 +758,15 @@
 {
 	int ret = 0;
 	struct bss_descriptor * bss;
-	DECLARE_MAC_BUF(mac);
 
-	lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s",
-		print_mac(mac, assoc_req->bssid));
+	lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid);
 
 	/* Search for index position in list for requested MAC */
 	bss = lbs_find_bssid_in_list(priv, assoc_req->bssid,
 			    assoc_req->mode);
 	if (bss == NULL) {
-		lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, "
-			"cannot associate.\n", print_mac(mac, assoc_req->bssid));
+		lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, "
+			"cannot associate.\n", assoc_req->bssid);
 		goto out;
 	}
 
@@ -1208,7 +1212,7 @@
 	struct assoc_request * assoc_req = NULL;
 	int ret = 0;
 	int find_any_ssid = 0;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
@@ -1228,13 +1232,13 @@
 		"    chann:     %d\n"
 		"    band:      %d\n"
 		"    mode:      %d\n"
-		"    BSSID:     %s\n"
+		"    BSSID:     %pM\n"
 		"    secinfo:  %s%s%s\n"
 		"    auth_mode: %d\n",
 		assoc_req->flags,
-		escape_essid(assoc_req->ssid, assoc_req->ssid_len),
+		print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
 		assoc_req->channel, assoc_req->band, assoc_req->mode,
-		print_mac(mac, assoc_req->bssid),
+		assoc_req->bssid,
 		assoc_req->secinfo.WPAenabled ? " WPA" : "",
 		assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
 		assoc_req->secinfo.wep_enabled ? " WEP" : "",
@@ -1357,8 +1361,8 @@
 		}
 
 		if (success) {
-			lbs_deb_assoc("associated to %s\n",
-				print_mac(mac, priv->curbssparams.bssid));
+			lbs_deb_assoc("associated to %pM\n",
+				priv->curbssparams.bssid);
 			lbs_prepare_and_send_command(priv,
 				CMD_802_11_RSSI,
 				0, CMD_OPTION_WAITFORRSP, 0, NULL);
@@ -1478,7 +1482,6 @@
 	struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
 	int ret = -1;
 	u8 *bssid = pdata_buf;
-	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
@@ -1505,8 +1508,8 @@
 
 	memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
 
-	lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
-		print_mac(mac, bssid), pauthenticate->authtype);
+	lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
+		bssid, pauthenticate->authtype);
 	ret = 0;
 
 out:
@@ -1770,7 +1773,7 @@
 	struct cmd_ds_802_11_ad_hoc_result *adhoc_resp;
 	union iwreq_data wrqu;
 	struct bss_descriptor *bss;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
@@ -1819,9 +1822,9 @@
 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
 
-	lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %s, channel %d\n",
-		     escape_essid(bss->ssid, bss->ssid_len),
-		     print_mac(mac, priv->curbssparams.bssid),
+	lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
+		     print_ssid(ssid, bss->ssid, bss->ssid_len),
+		     priv->curbssparams.bssid,
 		     priv->curbssparams.channel);
 
 done:
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 8265c7d..639dd02 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -4,7 +4,7 @@
   */
 
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
+#include <net/lib80211.h>
 #include <linux/kfifo.h>
 #include "host.h"
 #include "hostcmd.h"
@@ -87,7 +87,6 @@
 	struct cmd_ds_get_hw_spec cmd;
 	int ret = -1;
 	u32 i;
-	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
@@ -110,8 +109,8 @@
 	 * CF card    firmware 5.0.16p0:   cap 0x00000303
 	 * USB dongle firmware 5.110.17p2: cap 0x00000303
 	 */
-	lbs_pr_info("%s, fw %u.%u.%up%u, cap 0x%08x\n",
-		print_mac(mac, cmd.permanentaddr),
+	lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
+		cmd.permanentaddr,
 		priv->fwrelease >> 24 & 0xff,
 		priv->fwrelease >> 16 & 0xff,
 		priv->fwrelease >>  8 & 0xff,
@@ -160,7 +159,8 @@
 	return ret;
 }
 
-int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria)
+int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
+		struct wol_config *p_wol_config)
 {
 	struct cmd_ds_host_sleep cmd_config;
 	int ret;
@@ -170,10 +170,21 @@
 	cmd_config.gpio = priv->wol_gpio;
 	cmd_config.gap = priv->wol_gap;
 
+	if (p_wol_config != NULL)
+		memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config,
+				sizeof(struct wol_config));
+	else
+		cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
+
 	ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
 	if (!ret) {
-		lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
-		priv->wol_criteria = criteria;
+		if (criteria) {
+			lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
+			priv->wol_criteria = criteria;
+		} else
+			memcpy((uint8_t *) p_wol_config,
+					(uint8_t *)&cmd_config.wol_conf,
+					sizeof(struct wol_config));
 	} else {
 		lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
 	}
@@ -1063,6 +1074,7 @@
 {
 	struct cmd_ds_mesh_config cmd;
 	struct mrvl_meshie *ie;
+	DECLARE_SSID_BUF(ssid);
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.channel = cpu_to_le16(chan);
@@ -1070,7 +1082,7 @@
 
 	switch (action) {
 	case CMD_ACT_MESH_CONFIG_START:
-		ie->hdr.id = MFIE_TYPE_GENERIC;
+		ie->id = WLAN_EID_GENERIC;
 		ie->val.oui[0] = 0x00;
 		ie->val.oui[1] = 0x50;
 		ie->val.oui[2] = 0x43;
@@ -1082,7 +1094,7 @@
 		ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
 		ie->val.mesh_id_len = priv->mesh_ssid_len;
 		memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
-		ie->hdr.len = sizeof(struct mrvl_meshie_val) -
+		ie->len = sizeof(struct mrvl_meshie_val) -
 			IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
 		cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
 		break;
@@ -1093,7 +1105,7 @@
 	}
 	lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
 		    action, priv->mesh_tlv, chan,
-		    escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
+		    print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
 
 	return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
 }
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 36be4c9..392e578 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -56,7 +56,8 @@
 			 uint16_t action, uint16_t type);
 int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
 
-int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria);
+int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
+		struct wol_config *p_wol_config);
 int lbs_suspend(struct lbs_private *priv);
 void lbs_resume(struct lbs_private *priv);
 
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 0aa0ce3..ec4efd7 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -5,6 +5,7 @@
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <net/iw_handler.h>
+#include <net/lib80211.h>
 
 #include "dev.h"
 #include "decl.h"
@@ -65,7 +66,7 @@
 	int numscansdone = 0, res;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 	struct bss_descriptor * iter_bss;
 
 	pos += snprintf(buf+pos, len-pos,
@@ -77,17 +78,17 @@
 		u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
 		u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
 
-		pos += snprintf(buf+pos, len-pos,
-			"%02u| %03d | %04d | %s |",
+		pos += snprintf(buf+pos, len-pos, "%02u| %03d | %04d | %pM |",
 			numscansdone, iter_bss->channel, iter_bss->rssi,
-			print_mac(mac, iter_bss->bssid));
+			iter_bss->bssid);
 		pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
 		pos += snprintf(buf+pos, len-pos, "%c%c%c |",
 				ibss ? 'A' : 'I', privacy ? 'P' : ' ',
 				spectrum_mgmt ? 'S' : ' ');
 		pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
 		pos += snprintf(buf+pos, len-pos, " %s\n",
-		                escape_essid(iter_bss->ssid, iter_bss->ssid_len));
+		                print_ssid(ssid, iter_bss->ssid,
+					   iter_bss->ssid_len));
 
 		numscansdone++;
 	}
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 1a8888c..0b84bdc 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -74,8 +74,4 @@
 
 int lbs_update_channel(struct lbs_private *priv);
 
-#ifndef CONFIG_IEEE80211
-const char *escape_essid(const char *essid, u8 essid_len);
-#endif
-
 #endif
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 076a636..c364e4c 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -79,7 +79,7 @@
 #define lbs_deb_tx(fmt, args...)        LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args)
 #define lbs_deb_fw(fmt, args...)        LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args)
 #define lbs_deb_usb(fmt, args...)       LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args)
-#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
+#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, dev_name(dev), ##args)
 #define lbs_deb_cs(fmt, args...)        LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
 #define lbs_deb_thread(fmt, args...)    LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
 #define lbs_deb_sdio(fmt, args...)      LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
@@ -149,6 +149,18 @@
 #define EHS_WAKE_ON_MAC_EVENT		0x0004
 #define EHS_WAKE_ON_MULTICAST_DATA	0x0008
 #define EHS_REMOVE_WAKEUP		0xFFFFFFFF
+/* Wake rules for Host_Sleep_CFG command */
+#define WOL_RULE_NET_TYPE_INFRA_OR_IBSS	0x00
+#define WOL_RULE_NET_TYPE_MESH		0x10
+#define WOL_RULE_ADDR_TYPE_BCAST	0x01
+#define WOL_RULE_ADDR_TYPE_MCAST	0x08
+#define WOL_RULE_ADDR_TYPE_UCAST	0x02
+#define WOL_RULE_OP_AND			0x01
+#define WOL_RULE_OP_OR			0x02
+#define WOL_RULE_OP_INVALID		0xFF
+#define WOL_RESULT_VALID_CMD		0
+#define WOL_RESULT_NOSPC_ERR		1
+#define WOL_RESULT_EEXIST_ERR		2
 
 /** Misc constants */
 /* This section defines 802.11 specific contants */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index f6f3753..dd682c4 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -10,7 +10,6 @@
 #include <linux/wireless.h>
 #include <linux/ethtool.h>
 #include <linux/debugfs.h>
-#include <net/ieee80211.h>
 
 #include "defs.h"
 #include "hostcmd.h"
@@ -278,6 +277,12 @@
 	struct enc_key wpa_mcast_key;
 	struct enc_key wpa_unicast_key;
 
+/*
+ * In theory, the IE is limited to the IE length, 255,
+ * but in practice 64 bytes are enough.
+ */
+#define MAX_WPA_IE_LEN 64
+
 	/** WPA Information Elements*/
 	u8 wpa_ie[MAX_WPA_IE_LEN];
 	u8 wpa_ie_len;
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 688d60d..61d2f50 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -23,7 +23,7 @@
 static void lbs_ethtool_get_drvinfo(struct net_device *dev,
 					 struct ethtool_drvinfo *info)
 {
-	struct lbs_private *priv = (struct lbs_private *) dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	snprintf(info->fw_version, 32, "%u.%u.%u.p%u",
 		priv->fwrelease >> 24 & 0xff,
@@ -47,7 +47,7 @@
 static int lbs_ethtool_get_eeprom(struct net_device *dev,
                                   struct ethtool_eeprom *eeprom, u8 * bytes)
 {
-	struct lbs_private *priv = (struct lbs_private *) dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct cmd_ds_802_11_eeprom_access cmd;
 	int ret;
 
@@ -76,7 +76,7 @@
 static void lbs_ethtool_get_stats(struct net_device *dev,
 				  struct ethtool_stats *stats, uint64_t *data)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct cmd_ds_mesh_access mesh_access;
 	int ret;
 
@@ -113,7 +113,7 @@
 
 static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
 		return MESH_STATS_NUM;
@@ -143,7 +143,7 @@
 static void lbs_ethtool_get_wol(struct net_device *dev,
 				struct ethtool_wolinfo *wol)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	if (priv->wol_criteria == 0xffffffff) {
 		/* Interface driver didn't configure wake */
@@ -166,7 +166,7 @@
 static int lbs_ethtool_set_wol(struct net_device *dev,
 			       struct ethtool_wolinfo *wol)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	uint32_t criteria = 0;
 
 	if (priv->wol_criteria == 0xffffffff && wol->wolopts)
@@ -180,7 +180,7 @@
 	if (wol->wolopts & WAKE_BCAST) criteria |= EHS_WAKE_ON_BROADCAST_DATA;
 	if (wol->wolopts & WAKE_PHY)   criteria |= EHS_WAKE_ON_MAC_EVENT;
 
-	return lbs_host_sleep_cfg(priv, criteria);
+	return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL);
 }
 
 struct ethtool_ops lbs_ethtool_ops = {
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 5004d76..277ff19 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -220,6 +220,14 @@
 	CMD_ACT_FWT_ACCESS_TIME,
 };
 
+/* Define action or option for CMD_802_11_HOST_SLEEP_CFG */
+enum cmd_wol_cfg_opts {
+	CMD_ACT_ACTION_NONE = 0,
+	CMD_ACT_SET_WOL_RULE,
+	CMD_ACT_GET_WOL_RULE,
+	CMD_ACT_RESET_WOL_RULE,
+};
+
 /* Define action or option for CMD_MESH_ACCESS */
 enum cmd_mesh_access_opts {
 	CMD_ACT_MESH_GET_TTL = 1,
@@ -237,6 +245,7 @@
 	CMD_ACT_MESH_GET_ROUTE_EXP,
 	CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
 	CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
+	CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT = 17,
 };
 
 /* Define actions and types for CMD_MESH_CONFIG */
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index d9f9a12..e173b1b 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -580,13 +580,37 @@
 	u8 key[32];
 };
 
+#define MAX_WOL_RULES 		16
+
+struct host_wol_rule {
+	uint8_t rule_no;
+	uint8_t rule_ops;
+	__le16 sig_offset;
+	__le16 sig_length;
+	__le16 reserve;
+	__be32 sig_mask;
+	__be32 signature;
+};
+
+struct wol_config {
+	uint8_t action;
+	uint8_t pattern;
+	uint8_t no_rules_in_cmd;
+	uint8_t result;
+	struct host_wol_rule rule[MAX_WOL_RULES];
+};
+
+
 struct cmd_ds_host_sleep {
 	struct cmd_header hdr;
 	__le32 criteria;
 	uint8_t gpio;
-	uint8_t gap;
+	uint16_t gap;
+	struct wol_config wol_conf;
 } __attribute__ ((packed));
 
+
+
 struct cmd_ds_802_11_key_material {
 	struct cmd_header hdr;
 
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index b54e2ea..4519d73 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -26,6 +26,7 @@
  * if_sdio_card_to_host() to pad the data.
  */
 
+#include <linux/kernel.h>
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <linux/netdevice.h>
@@ -581,7 +582,7 @@
 				chunk_size, (chunk_size + 31) / 32 * 32);
 */
 			ret = sdio_writesb(card->func, card->ioport,
-				chunk_buffer, (chunk_size + 31) / 32 * 32);
+				chunk_buffer, roundup(chunk_size, 32));
 			if (ret)
 				goto release;
 
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index cafbccb..2fc637a 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -59,7 +59,7 @@
 static ssize_t if_usb_firmware_set(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	struct if_usb_card *cardp = priv->card;
 	char fwname[FIRMWARE_NAME_MAX];
 	int ret;
@@ -86,7 +86,7 @@
 static ssize_t if_usb_boot2_set(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	struct if_usb_card *cardp = priv->card;
 	char fwname[FIRMWARE_NAME_MAX];
 	int ret;
@@ -178,7 +178,8 @@
 
 	priv->wol_gpio = 2; /* Wake via GPIO2... */
 	priv->wol_gap = 20; /* ... after 20ms    */
-	lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA);
+	lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA,
+			(struct wol_config *) NULL);
 
 	wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
 	wake_method.action = cpu_to_le16(CMD_ACT_GET);
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 73dc8c7..3dba836 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -12,9 +12,8 @@
 #include <linux/kthread.h>
 #include <linux/kfifo.h>
 #include <linux/stddef.h>
-
+#include <linux/ieee80211.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 
 #include "host.h"
 #include "decl.h"
@@ -223,7 +222,7 @@
 static ssize_t lbs_anycast_get(struct device *dev,
 		struct device_attribute *attr, char * buf)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	struct cmd_ds_mesh_access mesh_access;
 	int ret;
 
@@ -242,7 +241,7 @@
 static ssize_t lbs_anycast_set(struct device *dev,
 		struct device_attribute *attr, const char * buf, size_t count)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	struct cmd_ds_mesh_access mesh_access;
 	uint32_t datum;
 	int ret;
@@ -258,6 +257,58 @@
 	return strlen(buf);
 }
 
+/**
+ * @brief Get function for sysfs attribute prb_rsp_limit
+ */
+static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+	struct cmd_ds_mesh_access mesh_access;
+	int ret;
+	u32 retry_limit;
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+	mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
+
+	ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
+			&mesh_access);
+	if (ret)
+		return ret;
+
+	retry_limit = le32_to_cpu(mesh_access.data[1]);
+	return snprintf(buf, 10, "%d\n", retry_limit);
+}
+
+/**
+ * @brief Set function for sysfs attribute prb_rsp_limit
+ */
+static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+	struct cmd_ds_mesh_access mesh_access;
+	int ret;
+	unsigned long retry_limit;
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+	mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
+
+	if (!strict_strtoul(buf, 10, &retry_limit))
+		return -ENOTSUPP;
+	if (retry_limit > 15)
+		return -ENOTSUPP;
+
+	mesh_access.data[1] = cpu_to_le32(retry_limit);
+
+	ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
+			&mesh_access);
+	if (ret)
+		return ret;
+
+	return strlen(buf);
+}
+
 static int lbs_add_rtap(struct lbs_private *priv);
 static void lbs_remove_rtap(struct lbs_private *priv);
 static int lbs_add_mesh(struct lbs_private *priv);
@@ -270,7 +321,7 @@
 static ssize_t lbs_rtap_get(struct device *dev,
 		struct device_attribute *attr, char * buf)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	return snprintf(buf, 5, "0x%X\n", priv->monitormode);
 }
 
@@ -281,7 +332,7 @@
 		struct device_attribute *attr, const char * buf, size_t count)
 {
 	int monitor_mode;
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 
 	sscanf(buf, "%x", &monitor_mode);
 	if (monitor_mode) {
@@ -332,7 +383,7 @@
 static ssize_t lbs_mesh_get(struct device *dev,
 		struct device_attribute *attr, char * buf)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
 }
 
@@ -342,7 +393,7 @@
 static ssize_t lbs_mesh_set(struct device *dev,
 		struct device_attribute *attr, const char * buf, size_t count)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	int enable;
 	int ret, action = CMD_ACT_MESH_CONFIG_STOP;
 
@@ -376,8 +427,16 @@
  */
 static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
 
+/**
+ * prb_rsp_limit attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
+ */
+static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
+		lbs_prb_rsp_limit_set);
+
 static struct attribute *lbs_mesh_sysfs_entries[] = {
 	&dev_attr_anycast_mask.attr,
+	&dev_attr_prb_rsp_limit.attr,
 	NULL,
 };
 
@@ -393,7 +452,7 @@
  */
 static int lbs_dev_open(struct net_device *dev)
 {
-	struct lbs_private *priv = (struct lbs_private *) dev->priv ;
+	struct lbs_private *priv = netdev_priv(dev) ;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_NET);
@@ -435,7 +494,7 @@
  */
 static int lbs_mesh_stop(struct net_device *dev)
 {
-	struct lbs_private *priv = (struct lbs_private *) (dev->priv);
+	struct lbs_private *priv = dev->ml_priv;
 
 	lbs_deb_enter(LBS_DEB_MESH);
 	spin_lock_irq(&priv->driver_lock);
@@ -462,7 +521,7 @@
  */
 static int lbs_eth_stop(struct net_device *dev)
 {
-	struct lbs_private *priv = (struct lbs_private *) dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_NET);
 
@@ -479,7 +538,7 @@
 
 static void lbs_tx_timeout(struct net_device *dev)
 {
-	struct lbs_private *priv = (struct lbs_private *) dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_TX);
 
@@ -531,7 +590,7 @@
  */
 static struct net_device_stats *lbs_get_stats(struct net_device *dev)
 {
-	struct lbs_private *priv = (struct lbs_private *) dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_NET);
 	return &priv->stats;
@@ -540,7 +599,7 @@
 static int lbs_set_mac_address(struct net_device *dev, void *addr)
 {
 	int ret = 0;
-	struct lbs_private *priv = (struct lbs_private *) dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct sockaddr *phwaddr = addr;
 	struct cmd_ds_802_11_mac_address cmd;
 
@@ -588,7 +647,6 @@
 {
 	int i = nr_addrs;
 	struct dev_mc_list *mc_list;
-	DECLARE_MAC_BUF(mac);
 
 	if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST))
 		return nr_addrs;
@@ -596,16 +654,16 @@
 	netif_addr_lock_bh(dev);
 	for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
 		if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) {
-			lbs_deb_net("mcast address %s:%s skipped\n", dev->name,
-				    print_mac(mac, mc_list->dmi_addr));
+			lbs_deb_net("mcast address %s:%pM skipped\n", dev->name,
+				    mc_list->dmi_addr);
 			continue;
 		}
 
 		if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE)
 			break;
 		memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN);
-		lbs_deb_net("mcast address %s:%s added to filter\n", dev->name,
-			    print_mac(mac, mc_list->dmi_addr));
+		lbs_deb_net("mcast address %s:%pM added to filter\n", dev->name,
+			    mc_list->dmi_addr);
 		i++;
 	}
 	netif_addr_unlock_bh(dev);
@@ -674,7 +732,7 @@
 
 static void lbs_set_multicast_list(struct net_device *dev)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	schedule_work(&priv->mcast_work);
 }
@@ -690,7 +748,7 @@
 static int lbs_thread(void *data)
 {
 	struct net_device *dev = data;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	wait_queue_t wait;
 
 	lbs_deb_enter(LBS_DEB_THREAD);
@@ -1125,7 +1183,7 @@
 		lbs_pr_err("init ethX device failed\n");
 		goto done;
 	}
-	priv = dev->priv;
+	priv = netdev_priv(dev);
 
 	if (lbs_init_adapter(priv)) {
 		lbs_pr_err("failed to initialize adapter structure.\n");
@@ -1378,7 +1436,7 @@
 		ret = -ENOMEM;
 		goto done;
 	}
-	mesh_dev->priv = priv;
+	mesh_dev->ml_priv = priv;
 	priv->mesh_dev = mesh_dev;
 
 	mesh_dev->open = lbs_dev_open;
@@ -1591,7 +1649,7 @@
 
 static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = dev->ml_priv;
 	lbs_deb_enter(LBS_DEB_NET);
 	return &priv->stats;
 }
@@ -1632,7 +1690,7 @@
 	rtap_dev->stop = lbs_rtap_stop;
 	rtap_dev->get_stats = lbs_rtap_get_stats;
 	rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
-	rtap_dev->priv = priv;
+	rtap_dev->ml_priv = priv;
 	SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
 
 	ret = register_netdev(rtap_dev);
@@ -1647,33 +1705,6 @@
 	return ret;
 }
 
-#ifndef CONFIG_IEEE80211
-const char *escape_essid(const char *essid, u8 essid_len)
-{
-	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-	const char *s = essid;
-	char *d = escaped;
-
-	if (ieee80211_is_empty_essid(essid, essid_len)) {
-		memcpy(escaped, "<hidden>", sizeof("<hidden>"));
-		return escaped;
-	}
-
-	essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
-	while (essid_len--) {
-		if (*s == '\0') {
-			*d++ = '\\';
-			*d++ = '0';
-			s++;
-		} else {
-			*d++ = *s++;
-		}
-	}
-	*d = '\0';
-	return escaped;
-}
-#endif
-
 module_init(lbs_init_module);
 module_exit(lbs_exit_module);
 
diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c
index 3309a9c..d42b7a5 100644
--- a/drivers/net/wireless/libertas/persistcfg.c
+++ b/drivers/net/wireless/libertas/persistcfg.c
@@ -18,7 +18,7 @@
 static int mesh_get_default_parameters(struct device *dev,
 				       struct mrvl_mesh_defaults *defs)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	struct cmd_ds_mesh_config cmd;
 	int ret;
 
@@ -57,7 +57,7 @@
 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	struct cmd_ds_mesh_config cmd;
 	uint32_t datum;
 	int ret;
@@ -100,7 +100,7 @@
 static ssize_t boottime_set(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	struct cmd_ds_mesh_config cmd;
 	uint32_t datum;
 	int ret;
@@ -152,7 +152,7 @@
 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
 			   const char *buf, size_t count)
 {
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	struct cmd_ds_mesh_config cmd;
 	uint32_t datum;
 	int ret;
@@ -210,7 +210,7 @@
 	struct cmd_ds_mesh_config cmd;
 	struct mrvl_mesh_defaults defs;
 	struct mrvl_meshie *ie;
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	int len;
 	int ret;
 
@@ -233,7 +233,7 @@
 	/* SSID len */
 	ie->val.mesh_id_len = len;
 	/* IE len */
-	ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
+	ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
 
 	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
 				   CMD_TYPE_MESH_SET_MESH_IE);
@@ -269,7 +269,7 @@
 	struct cmd_ds_mesh_config cmd;
 	struct mrvl_mesh_defaults defs;
 	struct mrvl_meshie *ie;
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	uint32_t datum;
 	int ret;
 
@@ -323,7 +323,7 @@
 	struct cmd_ds_mesh_config cmd;
 	struct mrvl_mesh_defaults defs;
 	struct mrvl_meshie *ie;
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	uint32_t datum;
 	int ret;
 
@@ -377,7 +377,7 @@
 	struct cmd_ds_mesh_config cmd;
 	struct mrvl_mesh_defaults defs;
 	struct mrvl_meshie *ie;
-	struct lbs_private *priv = to_net_dev(dev)->priv;
+	struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 	uint32_t datum;
 	int ret;
 
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
index 5d118f4..f8eb9097 100644
--- a/drivers/net/wireless/libertas/radiotap.h
+++ b/drivers/net/wireless/libertas/radiotap.h
@@ -6,9 +6,6 @@
 	u8 txpower;
 	u8 rts_retries;
 	u8 data_retries;
-#if 0
-	u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12];
-#endif
 } __attribute__ ((packed));
 
 #define TX_RADIOTAP_PRESENT (				\
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 22c4c61..57f6c12 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -4,8 +4,11 @@
   * IOCTL handlers as well as command preperation and response routines
   *  for sending scan commands to the firmware.
   */
+#include <linux/types.h>
 #include <linux/etherdevice.h>
+#include <linux/if_arp.h>
 #include <asm/unaligned.h>
+#include <net/lib80211.h>
 
 #include "host.h"
 #include "decl.h"
@@ -52,6 +55,8 @@
 //! Scan time specified in the channel TLV for each channel for active scans
 #define MRVDRV_ACTIVE_SCAN_CHAN_TIME   100
 
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+
 static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
 			      struct cmd_header *resp);
 
@@ -359,7 +364,7 @@
 #ifdef CONFIG_LIBERTAS_DEBUG
 	struct bss_descriptor *iter;
 	int i = 0;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 #endif
 
 	lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
@@ -451,9 +456,9 @@
 	mutex_lock(&priv->lock);
 	lbs_deb_scan("scan table:\n");
 	list_for_each_entry(iter, &priv->network_list, list)
-		lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n",
-			     i++, print_mac(mac, iter->bssid), iter->rssi,
-			     escape_essid(iter->ssid, iter->ssid_len));
+		lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n",
+			     i++, iter->bssid, iter->rssi,
+			     print_ssid(ssid, iter->ssid, iter->ssid_len));
 	mutex_unlock(&priv->lock);
 #endif
 
@@ -512,7 +517,7 @@
 	struct ieeetypes_dsparamset *pDS;
 	struct ieeetypes_cfparamset *pCF;
 	struct ieeetypes_ibssparamset *pibss;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_SSID_BUF(ssid);
 	struct ieeetypes_countryinfoset *pcountryinfo;
 	uint8_t *pos, *end, *p;
 	uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
@@ -544,7 +549,7 @@
 	*bytesleft -= beaconsize;
 
 	memcpy(bss->bssid, pos, ETH_ALEN);
-	lbs_deb_scan("process_bss: BSSID %s\n", print_mac(mac, bss->bssid));
+	lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid);
 	pos += ETH_ALEN;
 
 	if ((end - pos) < 12) {
@@ -588,38 +593,36 @@
 
 	/* process variable IE */
 	while (pos <= end - 2) {
-		struct ieee80211_info_element * elem = (void *)pos;
-
-		if (pos + elem->len > end) {
+		if (pos + pos[1] > end) {
 			lbs_deb_scan("process_bss: error in processing IE, "
 				     "bytes left < IE length\n");
 			break;
 		}
 
-		switch (elem->id) {
-		case MFIE_TYPE_SSID:
-			bss->ssid_len = min_t(int, 32, elem->len);
-			memcpy(bss->ssid, elem->data, bss->ssid_len);
+		switch (pos[0]) {
+		case WLAN_EID_SSID:
+			bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]);
+			memcpy(bss->ssid, pos + 2, bss->ssid_len);
 			lbs_deb_scan("got SSID IE: '%s', len %u\n",
-			             escape_essid(bss->ssid, bss->ssid_len),
+			             print_ssid(ssid, bss->ssid, bss->ssid_len),
 			             bss->ssid_len);
 			break;
 
-		case MFIE_TYPE_RATES:
-			n_basic_rates = min_t(uint8_t, MAX_RATES, elem->len);
-			memcpy(bss->rates, elem->data, n_basic_rates);
+		case WLAN_EID_SUPP_RATES:
+			n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]);
+			memcpy(bss->rates, pos + 2, n_basic_rates);
 			got_basic_rates = 1;
 			lbs_deb_scan("got RATES IE\n");
 			break;
 
-		case MFIE_TYPE_FH_SET:
+		case WLAN_EID_FH_PARAMS:
 			pFH = (struct ieeetypes_fhparamset *) pos;
 			memmove(&bss->phyparamset.fhparamset, pFH,
 				sizeof(struct ieeetypes_fhparamset));
 			lbs_deb_scan("got FH IE\n");
 			break;
 
-		case MFIE_TYPE_DS_SET:
+		case WLAN_EID_DS_PARAMS:
 			pDS = (struct ieeetypes_dsparamset *) pos;
 			bss->channel = pDS->currentchan;
 			memcpy(&bss->phyparamset.dsparamset, pDS,
@@ -627,14 +630,14 @@
 			lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
 			break;
 
-		case MFIE_TYPE_CF_SET:
+		case WLAN_EID_CF_PARAMS:
 			pCF = (struct ieeetypes_cfparamset *) pos;
 			memcpy(&bss->ssparamset.cfparamset, pCF,
 			       sizeof(struct ieeetypes_cfparamset));
 			lbs_deb_scan("got CF IE\n");
 			break;
 
-		case MFIE_TYPE_IBSS_SET:
+		case WLAN_EID_IBSS_PARAMS:
 			pibss = (struct ieeetypes_ibssparamset *) pos;
 			bss->atimwindow = le16_to_cpu(pibss->atimwindow);
 			memmove(&bss->ssparamset.ibssparamset, pibss,
@@ -642,7 +645,7 @@
 			lbs_deb_scan("got IBSS IE\n");
 			break;
 
-		case MFIE_TYPE_COUNTRY:
+		case WLAN_EID_COUNTRY:
 			pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
 			lbs_deb_scan("got COUNTRY IE\n");
 			if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
@@ -659,7 +662,7 @@
 				    (int) (pcountryinfo->len + 2));
 			break;
 
-		case MFIE_TYPE_RATES_EX:
+		case WLAN_EID_EXT_SUPP_RATES:
 			/* only process extended supported rate if data rate is
 			 * already found. Data rate IE should come before
 			 * extended supported rate IE
@@ -670,50 +673,51 @@
 				break;
 			}
 
-			n_ex_rates = elem->len;
+			n_ex_rates = pos[1];
 			if (n_basic_rates + n_ex_rates > MAX_RATES)
 				n_ex_rates = MAX_RATES - n_basic_rates;
 
 			p = bss->rates + n_basic_rates;
-			memcpy(p, elem->data, n_ex_rates);
+			memcpy(p, pos + 2, n_ex_rates);
 			break;
 
-		case MFIE_TYPE_GENERIC:
-			if (elem->len >= 4 &&
-			    elem->data[0] == 0x00 && elem->data[1] == 0x50 &&
-			    elem->data[2] == 0xf2 && elem->data[3] == 0x01) {
-				bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
-				memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
+		case WLAN_EID_GENERIC:
+			if (pos[1] >= 4 &&
+			    pos[2] == 0x00 && pos[3] == 0x50 &&
+			    pos[4] == 0xf2 && pos[5] == 0x01) {
+				bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
+				memcpy(bss->wpa_ie, pos, bss->wpa_ie_len);
 				lbs_deb_scan("got WPA IE\n");
-				lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, elem->len);
-			} else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
-				   elem->data[0] == 0x00 && elem->data[1] == 0x50 &&
-				   elem->data[2] == 0x43 && elem->data[3] == 0x04) {
+				lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
+					    bss->wpa_ie_len);
+			} else if (pos[1] >= MARVELL_MESH_IE_LENGTH &&
+				   pos[2] == 0x00 && pos[3] == 0x50 &&
+				   pos[4] == 0x43 && pos[4] == 0x04) {
 				lbs_deb_scan("got mesh IE\n");
 				bss->mesh = 1;
 			} else {
 				lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n",
-					elem->data[0], elem->data[1],
-					elem->data[2], elem->data[3],
-					elem->len);
+					pos[2], pos[3],
+					pos[4], pos[5],
+					pos[1]);
 			}
 			break;
 
-		case MFIE_TYPE_RSN:
+		case WLAN_EID_RSN:
 			lbs_deb_scan("got RSN IE\n");
-			bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
-			memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
+			bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
+			memcpy(bss->rsn_ie, pos, bss->rsn_ie_len);
 			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
-				    bss->rsn_ie, elem->len);
+				    bss->rsn_ie, bss->rsn_ie_len);
 			break;
 
 		default:
 			lbs_deb_scan("got IE 0x%04x, len %d\n",
-				     elem->id, elem->len);
+				     pos[0], pos[1]);
 			break;
 		}
 
-		pos += elem->len + 2;
+		pos += pos[1] + 2;
 	}
 
 	/* Timestamp */
@@ -741,10 +745,11 @@
 int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid,
 				uint8_t ssid_len)
 {
+	DECLARE_SSID_BUF(ssid_buf);
 	int ret = 0;
 
 	lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n",
-			   escape_essid(ssid, ssid_len));
+			   print_ssid(ssid_buf, ssid, ssid_len));
 
 	if (!ssid_len)
 		goto out;
@@ -939,7 +944,8 @@
 int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
 		 union iwreq_data *wrqu, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	DECLARE_SSID_BUF(ssid);
+	struct lbs_private *priv = netdev_priv(dev);
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
@@ -968,7 +974,7 @@
 		priv->scan_ssid_len = req->essid_len;
 		memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len);
 		lbs_deb_wext("set_scan, essid '%s'\n",
-			escape_essid(priv->scan_ssid, priv->scan_ssid_len));
+			print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len));
 	} else {
 		priv->scan_ssid_len = 0;
 	}
@@ -1002,7 +1008,7 @@
 		 struct iw_point *dwrq, char *extra)
 {
 #define SCAN_ITEM_SIZE 128
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	int err = 0;
 	char *ev = extra;
 	char *stop = ev + dwrq->length;
@@ -1151,7 +1157,6 @@
 		struct bss_descriptor new;
 		struct bss_descriptor *found = NULL;
 		struct bss_descriptor *oldest = NULL;
-		DECLARE_MAC_BUF(mac);
 
 		/* Process the data fields and IEs returned for this BSS */
 		memset(&new, 0, sizeof (struct bss_descriptor));
@@ -1190,7 +1195,7 @@
 			continue;
 		}
 
-		lbs_deb_scan("SCAN_RESP: BSSID %s\n", print_mac(mac, new.bssid));
+		lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid);
 
 		/* Copy the locally created newbssentry to the scan table */
 		memcpy(found, &new, offsetof(struct bss_descriptor, list));
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
index 9e07b04..fab7d5d 100644
--- a/drivers/net/wireless/libertas/scan.h
+++ b/drivers/net/wireless/libertas/scan.h
@@ -7,6 +7,10 @@
 #ifndef _LBS_SCAN_H
 #define _LBS_SCAN_H
 
+#include <net/iw_handler.h>
+
+#define MAX_NETWORK_COUNT 128
+
 /**
  *  @brief Maximum number of channels that can be sent in a setuserscan ioctl
  */
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index a4972fe..dac4626 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -60,7 +60,7 @@
 int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	unsigned long flags;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct txpd *txpd;
 	char *p802x_hdr;
 	uint16_t pkt_len;
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index e0c2599..fb7a2d1 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -7,7 +7,6 @@
 #include <linux/if_ether.h>
 #include <asm/byteorder.h>
 #include <linux/wireless.h>
-#include <net/ieee80211.h>
 
 struct ieeetypes_cfparamset {
 	u8 elementid;
@@ -258,7 +257,7 @@
  * Note that the len member of the ieee80211_info_element varies depending on
  * the mesh_id_len */
 struct mrvl_meshie_val {
-	uint8_t oui[P80211_OUI_LEN];
+	uint8_t oui[3];
 	uint8_t type;
 	uint8_t subtype;
 	uint8_t version;
@@ -270,7 +269,7 @@
 } __attribute__ ((packed));
 
 struct mrvl_meshie {
-	struct ieee80211_info_element hdr;
+	u8 id, len;
 	struct mrvl_meshie_val val;
 } __attribute__ ((packed));
 
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 82c3e5a5..c6102e0 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -8,7 +8,7 @@
 #include <linux/wireless.h>
 #include <linux/bitops.h>
 
-#include <net/ieee80211.h>
+#include <net/lib80211.h>
 #include <net/iw_handler.h>
 
 #include "host.h"
@@ -163,7 +163,7 @@
 static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_freq *fwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct chan_freq_power *cfp;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
@@ -189,7 +189,7 @@
 static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
 			struct sockaddr *awrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -207,7 +207,7 @@
 static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_point *dwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -231,7 +231,7 @@
 static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_point *dwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -248,7 +248,7 @@
 static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_point *dwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -273,7 +273,7 @@
 			struct iw_param *vwrq, char *extra)
 {
 	int ret = 0;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	u32 val = vwrq->value;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
@@ -293,7 +293,7 @@
 static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
 			struct iw_param *vwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	int ret = 0;
 	u16 val = 0;
 
@@ -315,7 +315,7 @@
 static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_param *vwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	int ret = 0;
 	u32 val = vwrq->value;
 
@@ -336,7 +336,7 @@
 static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_param *vwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	int ret = 0;
 	u16 val = 0;
 
@@ -359,7 +359,7 @@
 static int lbs_get_mode(struct net_device *dev,
 			 struct iw_request_info *info, u32 * uwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -385,7 +385,7 @@
 			  struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	s16 curlevel = 0;
 	int ret = 0;
 
@@ -418,7 +418,7 @@
 static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	int ret = 0;
 	u16 slimit = 0, llimit = 0;
 
@@ -466,7 +466,7 @@
 static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	int ret = 0;
 	u16 val = 0;
 
@@ -542,7 +542,7 @@
 			  struct iw_point *dwrq, char *extra)
 {
 	int i, j;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct iw_range *range = (struct iw_range *)extra;
 	struct chan_freq_power *cfp;
 	u8 rates[MAX_RATES + 1];
@@ -708,7 +708,7 @@
 static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -758,7 +758,7 @@
 static int lbs_get_power(struct net_device *dev, struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -781,7 +781,7 @@
 		EXCELLENT = 95,
 		PERFECT = 100
 	};
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	u32 rssi_qual;
 	u32 tx_qual;
 	u32 quality = 0;
@@ -886,7 +886,7 @@
 		  struct iw_freq *fwrq, char *extra)
 {
 	int ret = -EINVAL;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct chan_freq_power *cfp;
 	struct assoc_request * assoc_req;
 
@@ -943,7 +943,7 @@
 			     struct iw_request_info *info,
 			     struct iw_freq *fwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct chan_freq_power *cfp;
 	int ret = -EINVAL;
 
@@ -994,7 +994,7 @@
 static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
 		  struct iw_param *vwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	u8 new_rate = 0;
 	int ret = -EINVAL;
 	u8 rates[MAX_RATES + 1];
@@ -1054,7 +1054,7 @@
 static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
 		  struct iw_param *vwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -1079,7 +1079,7 @@
 		  struct iw_request_info *info, u32 * uwrq, char *extra)
 {
 	int ret = 0;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct assoc_request * assoc_req;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
@@ -1124,7 +1124,7 @@
 			   struct iw_request_info *info,
 			   struct iw_point *dwrq, u8 * extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
@@ -1319,7 +1319,7 @@
 		    struct iw_point *dwrq, char *extra)
 {
 	int ret = 0;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct assoc_request * assoc_req;
 	u16 is_default = 0, index = 0, set_tx_key = 0;
 
@@ -1395,7 +1395,7 @@
 			      char *extra)
 {
 	int ret = -EINVAL;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 	int index, max_key_len;
 
@@ -1501,7 +1501,7 @@
 			      char *extra)
 {
 	int ret = 0;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 	int alg = ext->alg;
 	struct assoc_request * assoc_req;
@@ -1639,7 +1639,7 @@
 			  struct iw_point *dwrq,
 			  char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	int ret = 0;
 	struct assoc_request * assoc_req;
 
@@ -1685,7 +1685,7 @@
 			  char *extra)
 {
 	int ret = 0;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -1713,7 +1713,7 @@
 			 struct iw_param *dwrq,
 			 char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct assoc_request * assoc_req;
 	int ret = 0;
 	int updated = 0;
@@ -1816,7 +1816,7 @@
 			 char *extra)
 {
 	int ret = 0;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -1857,7 +1857,7 @@
 		   struct iw_param *vwrq, char *extra)
 {
 	int ret = 0;
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	s16 dbm = (s16) vwrq->value;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
@@ -1936,7 +1936,7 @@
 static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
 		   struct iw_point *dwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -1971,12 +1971,13 @@
 static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
 		   struct iw_point *dwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	int ret = 0;
 	u8 ssid[IW_ESSID_MAX_SIZE];
 	u8 ssid_len = 0;
 	struct assoc_request * assoc_req;
 	int in_ssid_len = dwrq->length;
+	DECLARE_SSID_BUF(ssid_buf);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -2005,7 +2006,7 @@
 		lbs_deb_wext("requested any SSID\n");
 	} else {
 		lbs_deb_wext("requested SSID '%s'\n",
-		             escape_essid(ssid, ssid_len));
+		             print_ssid(ssid_buf, ssid, ssid_len));
 	}
 
 out:
@@ -2039,7 +2040,7 @@
 			      struct iw_request_info *info,
 			      struct iw_point *dwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -2057,7 +2058,7 @@
 			      struct iw_request_info *info,
 			      struct iw_point *dwrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
@@ -2101,10 +2102,9 @@
 static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
 		 struct sockaddr *awrq, char *extra)
 {
-	struct lbs_private *priv = dev->priv;
+	struct lbs_private *priv = netdev_priv(dev);
 	struct assoc_request * assoc_req;
 	int ret = 0;
-	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -2114,7 +2114,7 @@
 	if (awrq->sa_family != ARPHRD_ETHER)
 		return -EINVAL;
 
-	lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data));
+	lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data);
 
 	mutex_lock(&priv->lock);
 
diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c
index fdbcf8b..3d3914c 100644
--- a/drivers/net/wireless/libertas_tf/cmd.c
+++ b/drivers/net/wireless/libertas_tf/cmd.c
@@ -79,7 +79,6 @@
 	struct cmd_ds_get_hw_spec cmd;
 	int ret = -1;
 	u32 i;
-	DECLARE_MAC_BUF(mac);
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
@@ -96,8 +95,8 @@
 	priv->fwrelease = (priv->fwrelease << 8) |
 		(priv->fwrelease >> 24 & 0xff);
 
-	printk(KERN_INFO "libertastf: %s, fw %u.%u.%up%u, cap 0x%08x\n",
-		print_mac(mac, cmd.permanentaddr),
+	printk(KERN_INFO "libertastf: %pM, fw %u.%u.%up%u, cap 0x%08x\n",
+		cmd.permanentaddr,
 		priv->fwrelease >> 24 & 0xff,
 		priv->fwrelease >> 16 & 0xff,
 		priv->fwrelease >>  8 & 0xff,
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index feff945..d1fc305 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -354,9 +354,11 @@
 	priv->vif = NULL;
 }
 
-static int lbtf_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct lbtf_private *priv = hw->priv;
+	struct ieee80211_conf *conf = &hw->conf;
+
 	if (conf->channel->center_freq != priv->cur_freq) {
 		priv->cur_freq = conf->channel->center_freq;
 		lbtf_set_channel(priv, conf->channel->hw_value);
@@ -590,14 +592,14 @@
 void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb);
-	memset(&info->status, 0, sizeof(info->status));
+
+	ieee80211_tx_info_clear_status(info);
 	/*
 	 * Commented out, otherwise we never go beyond 1Mbit/s using mac80211
 	 * default pid rc algorithm.
 	 *
 	 * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt;
 	 */
-	info->status.excessive_retries = fail ? 1 : 0;
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail)
 		info->flags |= IEEE80211_TX_STAT_ACK;
 	skb_pull(priv->tx_skb, sizeof(struct txpd));
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 1a019e9..f83d69e 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -21,6 +21,7 @@
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/etherdevice.h>
+#include <linux/debugfs.h>
 
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211");
@@ -32,6 +33,9 @@
 
 struct hwsim_vif_priv {
 	u32 magic;
+	u8 bssid[ETH_ALEN];
+	bool assoc;
+	u16 aid;
 };
 
 #define HWSIM_VIF_MAGIC	0x69537748
@@ -63,13 +67,13 @@
 static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta)
 {
 	struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
-	WARN_ON(sp->magic != HWSIM_VIF_MAGIC);
+	WARN_ON(sp->magic != HWSIM_STA_MAGIC);
 }
 
 static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta)
 {
 	struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
-	sp->magic = HWSIM_VIF_MAGIC;
+	sp->magic = HWSIM_STA_MAGIC;
 }
 
 static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta)
@@ -132,6 +136,12 @@
 	unsigned int rx_filter;
 	int started;
 	struct timer_list beacon_timer;
+	enum ps_mode {
+		PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
+	} ps;
+	bool ps_poll_pending;
+	struct dentry *debugfs;
+	struct dentry *debugfs_ps;
 };
 
 
@@ -196,6 +206,34 @@
 }
 
 
+static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
+			   struct sk_buff *skb)
+{
+	switch (data->ps) {
+	case PS_DISABLED:
+		return true;
+	case PS_ENABLED:
+		return false;
+	case PS_AUTO_POLL:
+		/* TODO: accept (some) Beacons by default and other frames only
+		 * if pending PS-Poll has been sent */
+		return true;
+	case PS_MANUAL_POLL:
+		/* Allow unicast frames to own address if there is a pending
+		 * PS-Poll */
+		if (data->ps_poll_pending &&
+		    memcmp(data->hw->wiphy->perm_addr, skb->data + 4,
+			   ETH_ALEN) == 0) {
+			data->ps_poll_pending = false;
+			return true;
+		}
+		return false;
+	}
+
+	return true;
+}
+
+
 static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
 				    struct sk_buff *skb)
 {
@@ -209,9 +247,12 @@
 	/* TODO: set mactime */
 	rx_status.freq = data->channel->center_freq;
 	rx_status.band = data->channel->band;
-	rx_status.rate_idx = info->tx_rate_idx;
+	rx_status.rate_idx = info->control.rates[0].idx;
 	/* TODO: simulate signal strength (and optional packet drop) */
 
+	if (data->ps != PS_DISABLED)
+		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+
 	/* Copy skb to all enabled radios that are on the current frequency */
 	spin_lock(&hwsim_radio_lock);
 	list_for_each_entry(data2, &hwsim_radios, list) {
@@ -221,6 +262,7 @@
 			continue;
 
 		if (!data2->started || !data2->radio_enabled ||
+		    !hwsim_ps_rx_ok(data2, skb) ||
 		    data->channel->center_freq != data2->channel->center_freq)
 			continue;
 
@@ -269,13 +311,9 @@
 	if (txi->control.sta)
 		hwsim_check_sta_magic(txi->control.sta);
 
-	memset(&txi->status, 0, sizeof(txi->status));
-	if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
-		if (ack)
-			txi->flags |= IEEE80211_TX_STAT_ACK;
-		else
-			txi->status.excessive_retries = 1;
-	}
+	ieee80211_tx_info_clear_status(txi);
+	if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
+		txi->flags |= IEEE80211_TX_STAT_ACK;
 	ieee80211_tx_status_irqsafe(hw, skb);
 	return NETDEV_TX_OK;
 }
@@ -294,6 +332,7 @@
 {
 	struct mac80211_hwsim_data *data = hw->priv;
 	data->started = 0;
+	del_timer(&data->beacon_timer);
 	printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
 }
 
@@ -301,10 +340,9 @@
 static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
 					struct ieee80211_if_init_conf *conf)
 {
-	DECLARE_MAC_BUF(mac);
-	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
+	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
 	       wiphy_name(hw->wiphy), __func__, conf->type,
-	       print_mac(mac, conf->mac_addr));
+	       conf->mac_addr);
 	hwsim_set_magic(conf->vif);
 	return 0;
 }
@@ -313,10 +351,9 @@
 static void mac80211_hwsim_remove_interface(
 	struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf)
 {
-	DECLARE_MAC_BUF(mac);
-	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
+	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
 	       wiphy_name(hw->wiphy), __func__, conf->type,
-	       print_mac(mac, conf->mac_addr));
+	       conf->mac_addr);
 	hwsim_check_magic(conf->vif);
 	hwsim_clear_magic(conf->vif);
 }
@@ -331,7 +368,8 @@
 
 	hwsim_check_magic(vif);
 
-	if (vif->type != NL80211_IFTYPE_AP)
+	if (vif->type != NL80211_IFTYPE_AP &&
+	    vif->type != NL80211_IFTYPE_MESH_POINT)
 		return;
 
 	skb = ieee80211_beacon_get(hw, vif);
@@ -361,10 +399,10 @@
 }
 
 
-static int mac80211_hwsim_config(struct ieee80211_hw *hw,
-				 struct ieee80211_conf *conf)
+static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct mac80211_hwsim_data *data = hw->priv;
+	struct ieee80211_conf *conf = &hw->conf;
 
 	printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n",
 	       wiphy_name(hw->wiphy), __func__,
@@ -409,7 +447,16 @@
 					   struct ieee80211_vif *vif,
 					   struct ieee80211_if_conf *conf)
 {
+	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+
 	hwsim_check_magic(vif);
+	if (conf->changed & IEEE80211_IFCC_BSSID) {
+		DECLARE_MAC_BUF(mac);
+		printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n",
+		       wiphy_name(hw->wiphy), __func__,
+		       conf->bssid);
+		memcpy(vp->bssid, conf->bssid, ETH_ALEN);
+	}
 	return 0;
 }
 
@@ -418,7 +465,46 @@
 					    struct ieee80211_bss_conf *info,
 					    u32 changed)
 {
+	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+
 	hwsim_check_magic(vif);
+
+	printk(KERN_DEBUG "%s:%s(changed=0x%x)\n",
+	       wiphy_name(hw->wiphy), __func__, changed);
+
+	if (changed & BSS_CHANGED_ASSOC) {
+		printk(KERN_DEBUG "  %s: ASSOC: assoc=%d aid=%d\n",
+		       wiphy_name(hw->wiphy), info->assoc, info->aid);
+		vp->assoc = info->assoc;
+		vp->aid = info->aid;
+	}
+
+	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+		printk(KERN_DEBUG "  %s: ERP_CTS_PROT: %d\n",
+		       wiphy_name(hw->wiphy), info->use_cts_prot);
+	}
+
+	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+		printk(KERN_DEBUG "  %s: ERP_PREAMBLE: %d\n",
+		       wiphy_name(hw->wiphy), info->use_short_preamble);
+	}
+
+	if (changed & BSS_CHANGED_ERP_SLOT) {
+		printk(KERN_DEBUG "  %s: ERP_SLOT: %d\n",
+		       wiphy_name(hw->wiphy), info->use_short_slot);
+	}
+
+	if (changed & BSS_CHANGED_HT) {
+		printk(KERN_DEBUG "  %s: HT: op_mode=0x%x\n",
+		       wiphy_name(hw->wiphy),
+		       info->ht.operation_mode);
+	}
+
+	if (changed & BSS_CHANGED_BASIC_RATES) {
+		printk(KERN_DEBUG "  %s: BASIC_RATES: 0x%llx\n",
+		       wiphy_name(hw->wiphy),
+		       (unsigned long long) info->basic_rates);
+	}
 }
 
 static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw,
@@ -434,6 +520,10 @@
 	case STA_NOTIFY_REMOVE:
 		hwsim_clear_sta_magic(sta);
 		break;
+	case STA_NOTIFY_SLEEP:
+	case STA_NOTIFY_AWAKE:
+		/* TODO: make good use of these flags */
+		break;
 	}
 }
 
@@ -445,6 +535,17 @@
 	return 0;
 }
 
+static int mac80211_hwsim_conf_tx(
+	struct ieee80211_hw *hw, u16 queue,
+	const struct ieee80211_tx_queue_params *params)
+{
+	printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d "
+	       "aifs=%d)\n",
+	       wiphy_name(hw->wiphy), __func__, queue,
+	       params->txop, params->cw_min, params->cw_max, params->aifs);
+	return 0;
+}
+
 static const struct ieee80211_ops mac80211_hwsim_ops =
 {
 	.tx = mac80211_hwsim_tx,
@@ -458,6 +559,7 @@
 	.bss_info_changed = mac80211_hwsim_bss_info_changed,
 	.sta_notify = mac80211_hwsim_sta_notify,
 	.set_tim = mac80211_hwsim_set_tim,
+	.conf_tx = mac80211_hwsim_conf_tx,
 };
 
 
@@ -474,6 +576,8 @@
 	spin_unlock_bh(&hwsim_radio_lock);
 
 	list_for_each_entry(data, &tmplist, list) {
+		debugfs_remove(data->debugfs_ps);
+		debugfs_remove(data->debugfs);
 		ieee80211_unregister_hw(data->hw);
 		device_unregister(data->dev);
 		ieee80211_free_hw(data->hw);
@@ -499,13 +603,131 @@
 }
 
 
+static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
+{
+	struct mac80211_hwsim_data *data = dat;
+	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+	DECLARE_MAC_BUF(buf);
+	struct sk_buff *skb;
+	struct ieee80211_pspoll *pspoll;
+
+	if (!vp->assoc)
+		return;
+
+	printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n",
+	       wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid);
+
+	skb = dev_alloc_skb(sizeof(*pspoll));
+	if (!skb)
+		return;
+	pspoll = (void *) skb_put(skb, sizeof(*pspoll));
+	pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+					    IEEE80211_STYPE_PSPOLL |
+					    IEEE80211_FCTL_PM);
+	pspoll->aid = cpu_to_le16(0xc000 | vp->aid);
+	memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
+	memcpy(pspoll->ta, mac, ETH_ALEN);
+	if (data->radio_enabled &&
+	    !mac80211_hwsim_tx_frame(data->hw, skb))
+		printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__);
+	dev_kfree_skb(skb);
+}
+
+
+static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
+				struct ieee80211_vif *vif, int ps)
+{
+	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+	DECLARE_MAC_BUF(buf);
+	struct sk_buff *skb;
+	struct ieee80211_hdr *hdr;
+
+	if (!vp->assoc)
+		return;
+
+	printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n",
+	       wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps);
+
+	skb = dev_alloc_skb(sizeof(*hdr));
+	if (!skb)
+		return;
+	hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN);
+	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+					 IEEE80211_STYPE_NULLFUNC |
+					 (ps ? IEEE80211_FCTL_PM : 0));
+	hdr->duration_id = cpu_to_le16(0);
+	memcpy(hdr->addr1, vp->bssid, ETH_ALEN);
+	memcpy(hdr->addr2, mac, ETH_ALEN);
+	memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
+	if (data->radio_enabled &&
+	    !mac80211_hwsim_tx_frame(data->hw, skb))
+		printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__);
+	dev_kfree_skb(skb);
+}
+
+
+static void hwsim_send_nullfunc_ps(void *dat, u8 *mac,
+				   struct ieee80211_vif *vif)
+{
+	struct mac80211_hwsim_data *data = dat;
+	hwsim_send_nullfunc(data, mac, vif, 1);
+}
+
+
+static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac,
+				      struct ieee80211_vif *vif)
+{
+	struct mac80211_hwsim_data *data = dat;
+	hwsim_send_nullfunc(data, mac, vif, 0);
+}
+
+
+static int hwsim_fops_ps_read(void *dat, u64 *val)
+{
+	struct mac80211_hwsim_data *data = dat;
+	*val = data->ps;
+	return 0;
+}
+
+static int hwsim_fops_ps_write(void *dat, u64 val)
+{
+	struct mac80211_hwsim_data *data = dat;
+	enum ps_mode old_ps;
+
+	if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL &&
+	    val != PS_MANUAL_POLL)
+		return -EINVAL;
+
+	old_ps = data->ps;
+	data->ps = val;
+
+	if (val == PS_MANUAL_POLL) {
+		ieee80211_iterate_active_interfaces(data->hw,
+						    hwsim_send_ps_poll, data);
+		data->ps_poll_pending = true;
+	} else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
+		ieee80211_iterate_active_interfaces(data->hw,
+						    hwsim_send_nullfunc_ps,
+						    data);
+	} else if (old_ps != PS_DISABLED && val == PS_DISABLED) {
+		ieee80211_iterate_active_interfaces(data->hw,
+						    hwsim_send_nullfunc_no_ps,
+						    data);
+	}
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write,
+			"%llu\n");
+
+
 static int __init init_mac80211_hwsim(void)
 {
 	int i, err = 0;
 	u8 addr[ETH_ALEN];
 	struct mac80211_hwsim_data *data;
 	struct ieee80211_hw *hw;
-	DECLARE_MAC_BUF(mac);
 
 	if (radios < 1 || radios > 100)
 		return -EINVAL;
@@ -553,7 +775,8 @@
 		hw->queues = 4;
 		hw->wiphy->interface_modes =
 			BIT(NL80211_IFTYPE_STATION) |
-			BIT(NL80211_IFTYPE_AP);
+			BIT(NL80211_IFTYPE_AP) |
+			BIT(NL80211_IFTYPE_MESH_POINT);
 		hw->ampdu_queues = 1;
 
 		/* ask mac80211 to reserve space for magic */
@@ -566,19 +789,18 @@
 		data->band.n_channels = ARRAY_SIZE(hwsim_channels);
 		data->band.bitrates = data->rates;
 		data->band.n_bitrates = ARRAY_SIZE(hwsim_rates);
-		data->band.ht_info.ht_supported = 1;
-		data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH |
+		data->band.ht_cap.ht_supported = true;
+		data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 			IEEE80211_HT_CAP_GRN_FLD |
 			IEEE80211_HT_CAP_SGI_40 |
 			IEEE80211_HT_CAP_DSSSCCK40;
-		data->band.ht_info.ampdu_factor = 0x3;
-		data->band.ht_info.ampdu_density = 0x6;
-		memset(data->band.ht_info.supp_mcs_set, 0,
-		       sizeof(data->band.ht_info.supp_mcs_set));
-		data->band.ht_info.supp_mcs_set[0] = 0xff;
-		data->band.ht_info.supp_mcs_set[1] = 0xff;
-		data->band.ht_info.supp_mcs_set[12] =
-			IEEE80211_HT_CAP_MCS_TX_DEFINED;
+		data->band.ht_cap.ampdu_factor = 0x3;
+		data->band.ht_cap.ampdu_density = 0x6;
+		memset(&data->band.ht_cap.mcs, 0,
+		       sizeof(data->band.ht_cap.mcs));
+		data->band.ht_cap.mcs.rx_mask[0] = 0xff;
+		data->band.ht_cap.mcs.rx_mask[1] = 0xff;
+		data->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
 		hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band;
 
 		err = ieee80211_register_hw(hw);
@@ -588,9 +810,15 @@
 			goto failed_hw;
 		}
 
-		printk(KERN_DEBUG "%s: hwaddr %s registered\n",
+		printk(KERN_DEBUG "%s: hwaddr %pM registered\n",
 		       wiphy_name(hw->wiphy),
-		       print_mac(mac, hw->wiphy->perm_addr));
+		       hw->wiphy->perm_addr);
+
+		data->debugfs = debugfs_create_dir("hwsim",
+						   hw->wiphy->debugfsdir);
+		data->debugfs_ps = debugfs_create_file("ps", 0666,
+						       data->debugfs, data,
+						       &hwsim_fops_ps);
 
 		setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
 			    (unsigned long) hw);
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index a670f36b..24caec6 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -737,7 +737,6 @@
     win_req_t req;
     memreq_t mem;
     u_char __iomem *ramBase = NULL;
-    DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link);
 
@@ -808,12 +807,12 @@
 	dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i);
 
     printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx, "
-	   "id %c%c, hw_addr %s\n",
+	   "id %c%c, hw_addr %pM\n",
 	   dev->name, dev->base_addr, dev->irq,
 	   (u_long) ramBase,
 	   (int) readb(ramBase+NETWAVE_EREG_NI),
 	   (int) readb(ramBase+NETWAVE_EREG_NI+1),
-	   print_mac(mac, dev->dev_addr));
+	   dev->dev_addr);
 
     /* get revision words */
     printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", 
@@ -1308,7 +1307,6 @@
 	/* Queue packet for network layer */
 	netif_rx(skb);
 
-	dev->last_rx = jiffies;
 	priv->stats.rx_packets++;
 	priv->stats.rx_bytes += rcvLen;
 
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile
new file mode 100644
index 0000000..791366e
--- /dev/null
+++ b/drivers/net/wireless/orinoco/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the orinoco wireless device drivers.
+#
+
+obj-$(CONFIG_HERMES)		+= orinoco.o hermes.o hermes_dld.o
+obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o
+obj-$(CONFIG_APPLE_AIRPORT)	+= airport.o
+obj-$(CONFIG_PLX_HERMES)	+= orinoco_plx.o
+obj-$(CONFIG_PCI_HERMES)	+= orinoco_pci.o
+obj-$(CONFIG_TMD_HERMES)	+= orinoco_tmd.o
+obj-$(CONFIG_NORTEL_HERMES)	+= orinoco_nortel.o
+obj-$(CONFIG_PCMCIA_SPECTRUM)	+= spectrum_cs.o
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/orinoco/airport.c
similarity index 98%
rename from drivers/net/wireless/airport.c
rename to drivers/net/wireless/orinoco/airport.c
index ce03a2e..28f1cae 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/orinoco/airport.c
@@ -279,7 +279,7 @@
 static void __exit
 exit_airport(void)
 {
-	return macio_unregister_driver(&airport_driver);
+	macio_unregister_driver(&airport_driver);
 }
 
 module_init(init_airport);
diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/orinoco/hermes.c
similarity index 100%
rename from drivers/net/wireless/hermes.c
rename to drivers/net/wireless/orinoco/hermes.c
diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/orinoco/hermes.h
similarity index 100%
rename from drivers/net/wireless/hermes.h
rename to drivers/net/wireless/orinoco/hermes.h
diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
similarity index 100%
rename from drivers/net/wireless/hermes_dld.c
rename to drivers/net/wireless/orinoco/hermes_dld.c
diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/orinoco/hermes_dld.h
similarity index 100%
rename from drivers/net/wireless/hermes_dld.h
rename to drivers/net/wireless/orinoco/hermes_dld.h
diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/orinoco/hermes_rid.h
similarity index 100%
rename from drivers/net/wireless/hermes_rid.h
rename to drivers/net/wireless/orinoco/hermes_rid.h
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c
similarity index 96%
rename from drivers/net/wireless/orinoco.c
rename to drivers/net/wireless/orinoco/orinoco.c
index e0512e4..bc84e27 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco/orinoco.c
@@ -84,10 +84,11 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/firmware.h>
+#include <linux/suspend.h>
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 
 #include <linux/scatterlist.h>
 #include <linux/crypto.h>
@@ -143,7 +144,7 @@
 #define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
 
 #define ORINOCO_MIN_MTU		256
-#define ORINOCO_MAX_MTU		(IEEE80211_DATA_LEN - ENCAPS_OVERHEAD)
+#define ORINOCO_MAX_MTU		(IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
 
 #define SYMBOL_MAX_VER_LEN	(14)
 #define USER_BAP		0
@@ -392,7 +393,7 @@
 }
 
 static inline u8 *orinoco_get_ie(u8 *data, size_t len,
-				 enum ieee80211_mfie eid)
+				 enum ieee80211_eid eid)
 {
 	u8 *p = data;
 	while ((p + 2) < (data + len)) {
@@ -409,7 +410,7 @@
 {
 	u8 *p = data;
 	while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
-		if ((p[0] == MFIE_TYPE_GENERIC) &&
+		if ((p[0] == WLAN_EID_GENERIC) &&
 		    (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
 			return p;
 		p += p[1] + 2;
@@ -431,9 +432,9 @@
 };
 
 const static struct fw_info orinoco_fw[] = {
-	{ "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
-	{ "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
-	{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 }
+	{ NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
+	{ NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
+	{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
 };
 
 /* Structure used to access fields in FW
@@ -487,13 +488,17 @@
 	if (err)
 		goto free;
 
-	err = request_firmware(&fw_entry, firmware, priv->dev);
-	if (err) {
-		printk(KERN_ERR "%s: Cannot find firmware %s\n",
-		       dev->name, firmware);
-		err = -ENOENT;
-		goto free;
-	}
+	if (!priv->cached_fw) {
+		err = request_firmware(&fw_entry, firmware, priv->dev);
+
+		if (err) {
+			printk(KERN_ERR "%s: Cannot find firmware %s\n",
+			       dev->name, firmware);
+			err = -ENOENT;
+			goto free;
+		}
+	} else
+		fw_entry = priv->cached_fw;
 
 	hdr = (const struct orinoco_fw_header *) fw_entry->data;
 
@@ -535,7 +540,9 @@
 	       dev->name, hermes_present(hw));
 
 abort:
-	release_firmware(fw_entry);
+	/* If we requested the firmware, release it. */
+	if (!priv->cached_fw)
+		release_firmware(fw_entry);
 
 free:
 	kfree(pda);
@@ -639,34 +646,41 @@
 	int ret;
 	const struct firmware *fw_entry;
 
-	if (request_firmware(&fw_entry, fw->pri_fw,
-			     priv->dev) != 0) {
-		printk(KERN_ERR "%s: Cannot find firmware: %s\n",
-		       dev->name, fw->pri_fw);
-		return -ENOENT;
-	}
+	if (!priv->cached_pri_fw) {
+		if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
+			printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+			       dev->name, fw->pri_fw);
+			return -ENOENT;
+		}
+	} else
+		fw_entry = priv->cached_pri_fw;
 
 	/* Load primary firmware */
 	ret = symbol_dl_image(priv, fw, fw_entry->data,
 			      fw_entry->data + fw_entry->size, 0);
-	release_firmware(fw_entry);
+
+	if (!priv->cached_pri_fw)
+		release_firmware(fw_entry);
 	if (ret) {
 		printk(KERN_ERR "%s: Primary firmware download failed\n",
 		       dev->name);
 		return ret;
 	}
 
-	if (request_firmware(&fw_entry, fw->sta_fw,
-			     priv->dev) != 0) {
-		printk(KERN_ERR "%s: Cannot find firmware: %s\n",
-		       dev->name, fw->sta_fw);
-		return -ENOENT;
-	}
+	if (!priv->cached_fw) {
+		if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
+			printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+			       dev->name, fw->sta_fw);
+			return -ENOENT;
+		}
+	} else
+		fw_entry = priv->cached_fw;
 
 	/* Load secondary firmware */
 	ret = symbol_dl_image(priv, fw, fw_entry->data,
 			      fw_entry->data + fw_entry->size, 1);
-	release_firmware(fw_entry);
+	if (!priv->cached_fw)
+		release_firmware(fw_entry);
 	if (ret) {
 		printk(KERN_ERR "%s: Secondary firmware download failed\n",
 		       dev->name);
@@ -699,6 +713,45 @@
 	return err;
 }
 
+#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
+static void orinoco_cache_fw(struct orinoco_private *priv, int ap)
+{
+	const struct firmware *fw_entry = NULL;
+	const char *pri_fw;
+	const char *fw;
+
+	pri_fw = orinoco_fw[priv->firmware_type].pri_fw;
+	if (ap)
+		fw = orinoco_fw[priv->firmware_type].ap_fw;
+	else
+		fw = orinoco_fw[priv->firmware_type].sta_fw;
+
+	if (pri_fw) {
+		if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0)
+			priv->cached_pri_fw = fw_entry;
+	}
+
+	if (fw) {
+		if (request_firmware(&fw_entry, fw, priv->dev) == 0)
+			priv->cached_fw = fw_entry;
+	}
+}
+
+static void orinoco_uncache_fw(struct orinoco_private *priv)
+{
+	if (priv->cached_pri_fw)
+		release_firmware(priv->cached_pri_fw);
+	if (priv->cached_fw)
+		release_firmware(priv->cached_fw);
+
+	priv->cached_pri_fw = NULL;
+	priv->cached_fw = NULL;
+}
+#else
+#define orinoco_cache_fw(priv, ap)
+#define orinoco_uncache_fw(priv)
+#endif
+
 /********************************************************************/
 /* Device methods                                                   */
 /********************************************************************/
@@ -800,7 +853,7 @@
 			wstats->qual.qual = (int)le16_to_cpu(cq.qual);
 			wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
 			wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
-			wstats->qual.updated = 7;
+			wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 		}
 	}
 
@@ -830,7 +883,8 @@
 	if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
 		return -EINVAL;
 
-	if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) >
+	/* MTU + encapsulation + header length */
+	if ( (new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) >
 	     (priv->nicbuf_size - ETH_HLEN) )
 		return -EINVAL;
 
@@ -1158,7 +1212,7 @@
 	wstats.level = level - 0x95;
 	wstats.noise = noise - 0x95;
 	wstats.qual = (level > noise) ? (level - noise) : 0;
-	wstats.updated = 7;
+	wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 	/* Update spy records */
 	wireless_spy_update(dev, mac, &wstats);
 }
@@ -1245,7 +1299,7 @@
 	}
 
 	/* sanity check the length */
-	if (datalen > IEEE80211_DATA_LEN + 12) {
+	if (datalen > IEEE80211_MAX_DATA_LEN + 12) {
 		printk(KERN_DEBUG "%s: oversized monitor frame, "
 		       "data length = %d\n", dev->name, datalen);
 		stats->rx_length_errors++;
@@ -1280,7 +1334,6 @@
 	skb->pkt_type = PACKET_OTHERHOST;
 	skb->protocol = __constant_htons(ETH_P_802_2);
 	
-	dev->last_rx = jiffies;
 	stats->rx_packets++;
 	stats->rx_bytes += skb->len;
 
@@ -1374,7 +1427,7 @@
                    data. */
 		goto out;
 	}
-	if (length > IEEE80211_DATA_LEN) {
+	if (length > IEEE80211_MAX_DATA_LEN) {
 		printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
 		       dev->name, length);
 		stats->rx_length_errors++;
@@ -1477,12 +1530,11 @@
 			   MICHAEL_MIC_LEN)) {
 			union iwreq_data wrqu;
 			struct iw_michaelmicfailure wxmic;
-			DECLARE_MAC_BUF(mac);
 
 			printk(KERN_WARNING "%s: "
-			       "Invalid Michael MIC in data frame from %s, "
+			       "Invalid Michael MIC in data frame from %pM, "
 			       "using key %i\n",
-			       dev->name, print_mac(mac, src), key_id);
+			       dev->name, src, key_id);
 
 			/* TODO: update stats */
 
@@ -1530,7 +1582,6 @@
 	else
 		memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
 
-	dev->last_rx = jiffies;
 	skb->protocol = eth_type_trans(skb, dev);
 	skb->ip_summed = CHECKSUM_NONE;
 	if (fc & IEEE80211_FCTL_TODS)
@@ -1699,7 +1750,7 @@
 	union iwreq_data wrqu;
 	int err;
 
-	err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
 			      ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
 	if (err != 0)
 		return;
@@ -1722,7 +1773,7 @@
 	if (!priv->has_wpa)
 		return;
 
-	err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
 			      sizeof(buf), NULL, &buf);
 	if (err != 0)
 		return;
@@ -1752,7 +1803,7 @@
 	if (!priv->has_wpa)
 		return;
 
-	err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
 			      sizeof(buf), NULL, &buf);
 	if (err != 0)
 		return;
@@ -2301,6 +2352,11 @@
 	int err;
 
 	err = hermes_init(hw);
+	if (priv->do_fw_download && !err) {
+		err = orinoco_download(priv);
+		if (err)
+			priv->do_fw_download = 0;
+	}
 	if (!err)
 		err = orinoco_allocate_fid(dev);
 
@@ -2926,12 +2982,6 @@
 		}
 	}
 
-	if (priv->do_fw_download) {
-		err = orinoco_download(priv);
-		if (err)
-			priv->do_fw_download = 0;
-	}
-
 	err = orinoco_reinit_firmware(dev);
 	if (err) {
 		printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
@@ -3056,6 +3106,50 @@
 }
 
 /********************************************************************/
+/* Power management                                                 */
+/********************************************************************/
+#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT)
+static int orinoco_pm_notifier(struct notifier_block *notifier,
+			       unsigned long pm_event,
+			       void *unused)
+{
+	struct orinoco_private *priv = container_of(notifier,
+						    struct orinoco_private,
+						    pm_notifier);
+
+	/* All we need to do is cache the firmware before suspend, and
+	 * release it when we come out.
+	 *
+	 * Only need to do this if we're downloading firmware. */
+	if (!priv->do_fw_download)
+		return NOTIFY_DONE;
+
+	switch (pm_event) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		orinoco_cache_fw(priv, 0);
+		break;
+
+	case PM_POST_RESTORE:
+		/* Restore from hibernation failed. We need to clean
+		 * up in exactly the same way, so fall through. */
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		orinoco_uncache_fw(priv);
+		break;
+
+	case PM_RESTORE_PREPARE:
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */
+#define orinoco_pm_notifier NULL
+#endif
+
+/********************************************************************/
 /* Initialization                                                   */
 /********************************************************************/
 
@@ -3277,11 +3371,10 @@
 	struct hermes_idstring nickbuf;
 	u16 reclen;
 	int len;
-	DECLARE_MAC_BUF(mac);
 
 	/* No need to lock, the hw_unavailable flag is already set in
 	 * alloc_orinocodev() */
-	priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
+	priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
 
 	/* Initialize the firmware */
 	err = hermes_init(hw);
@@ -3299,6 +3392,10 @@
 	}
 
 	if (priv->do_fw_download) {
+#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT
+		orinoco_cache_fw(priv, 0);
+#endif
+
 		err = orinoco_download(priv);
 		if (err)
 			priv->do_fw_download = 0;
@@ -3348,8 +3445,8 @@
 		goto out;
 	}
 
-	printk(KERN_DEBUG "%s: MAC address %s\n",
-	       dev->name, print_mac(mac, dev->dev_addr));
+	printk(KERN_DEBUG "%s: MAC address %pM\n",
+	       dev->name, dev->dev_addr);
 
 	/* Get the station name */
 	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
@@ -3535,6 +3632,13 @@
 	netif_carrier_off(dev);
 	priv->last_linkstatus = 0xffff;
 
+	priv->cached_pri_fw = NULL;
+	priv->cached_fw = NULL;
+
+	/* Register PM notifiers */
+	priv->pm_notifier.notifier_call = orinoco_pm_notifier;
+	register_pm_notifier(&priv->pm_notifier);
+
 	return dev;
 }
 
@@ -3546,6 +3650,10 @@
 	 * when we call tasklet_kill it will run one final time,
 	 * emptying the list */
 	tasklet_kill(&priv->rx_tasklet);
+
+	unregister_pm_notifier(&priv->pm_notifier);
+	orinoco_uncache_fw(priv);
+
 	priv->wpa_ie_len = 0;
 	kfree(priv->wpa_ie);
 	orinoco_mic_free(priv);
@@ -4672,7 +4780,7 @@
 	/* Determine and validate the key index */
 	idx = encoding->flags & IW_ENCODE_INDEX;
 	if (idx) {
-		if ((idx < 1) || (idx > WEP_KEYS))
+		if ((idx < 1) || (idx > 4))
 			goto out;
 		idx--;
 	} else
@@ -4777,7 +4885,7 @@
 
 	idx = encoding->flags & IW_ENCODE_INDEX;
 	if (idx) {
-		if ((idx < 1) || (idx > WEP_KEYS))
+		if ((idx < 1) || (idx > 4))
 			goto out;
 		idx--;
 	} else
@@ -4940,7 +5048,8 @@
 	unsigned long flags;
 	int err = 0;
 
-	if ((wrqu->data.length > MAX_WPA_IE_LEN) ||
+	/* cut off at IEEE80211_MAX_DATA_LEN */
+	if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
 	    (wrqu->data.length && (extra == NULL)))
 		return -EINVAL;
 
@@ -5433,7 +5542,7 @@
 					   char *current_ev,
 					   char *end_buf,
 					   union hermes_scan_info *bss,
-					   unsigned int last_scanned)
+					   unsigned long last_scanned)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	u16			capabilities;
@@ -5580,7 +5689,7 @@
 					       char *current_ev,
 					       char *end_buf,
 					       struct agere_ext_scan_info *bss,
-					       unsigned int last_scanned)
+					       unsigned long last_scanned)
 {
 	u16			capabilities;
 	u16			channel;
@@ -5623,7 +5732,7 @@
 						  &iwe, IW_EV_UINT_LEN);
 	}
 
-	ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_DS_SET);
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS);
 	channel = ie ? ie[2] : 0;
 	if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
 		/* Add channel and frequency */
@@ -5673,7 +5782,7 @@
 	}
 
 	/* RSN IE */
-	ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RSN);
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN);
 	if (ie) {
 		iwe.cmd = IWEVGENIE;
 		iwe.u.data.length = ie[1] + 2;
@@ -5681,7 +5790,7 @@
 						  &iwe, ie);
 	}
 
-	ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RATES);
+	ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES);
 	if (ie) {
 		char *p = current_ev + iwe_stream_lcp_len(info);
 		int i;
@@ -5976,7 +6085,7 @@
 	strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
 	strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
 	if (dev->dev.parent)
-		strncpy(info->bus_info, dev->dev.parent->bus_id,
+		strncpy(info->bus_info, dev_name(dev->dev.parent),
 			sizeof(info->bus_info) - 1);
 	else
 		snprintf(info->bus_info, sizeof(info->bus_info) - 1,
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
similarity index 95%
rename from drivers/net/wireless/orinoco.h
rename to drivers/net/wireless/orinoco/orinoco.h
index 981570b..00750c8 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -10,6 +10,7 @@
 #define DRIVER_VERSION "0.15"
 
 #include <linux/interrupt.h>
+#include <linux/suspend.h>
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
@@ -66,6 +67,8 @@
 	struct list_head list;
 };
 
+struct firmware;
+
 struct orinoco_private {
 	void *card;	/* Pointer to card dependent structure */
 	struct device *dev;
@@ -164,6 +167,12 @@
 	unsigned int wpa_enabled:1;
 	unsigned int tkip_cm_active:1;
 	unsigned int key_mgmt:3;
+
+	/* Cached in memory firmware to use during ->resume. */
+	const struct firmware *cached_pri_fw;
+	const struct firmware *cached_fw;
+
+	struct notifier_block pm_notifier;
 };
 
 #ifdef ORINOCO_DEBUG
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
similarity index 98%
rename from drivers/net/wireless/orinoco_cs.c
rename to drivers/net/wireless/orinoco/orinoco_cs.c
index 6fcf2bd..f127602 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -178,13 +178,17 @@
 	/* Note that the CIS values need to be rescaled */
 	if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
 		if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-			DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+			DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
+			      __func__, vcc,
+			      cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
 			if (!ignore_cis_vcc)
 				goto next_entry;
 		}
 	} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
 		if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-			DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
+			DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
+			      __func__, vcc,
+			      dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
 			if (!ignore_cis_vcc)
 				goto next_entry;
 		}
@@ -308,7 +312,7 @@
 
 	/* Finally, report what we've done */
 	printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
-	       "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
+	       "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
 	       link->irq.AssignedIRQ, link->io.BasePort1,
 	       link->io.BasePort1 + link->io.NumPorts1 - 1);
 	return 0;
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c
similarity index 100%
rename from drivers/net/wireless/orinoco_nortel.c
rename to drivers/net/wireless/orinoco/orinoco_nortel.c
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c
similarity index 100%
rename from drivers/net/wireless/orinoco_pci.c
rename to drivers/net/wireless/orinoco/orinoco_pci.c
diff --git a/drivers/net/wireless/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h
similarity index 100%
rename from drivers/net/wireless/orinoco_pci.h
rename to drivers/net/wireless/orinoco/orinoco_pci.h
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c
similarity index 100%
rename from drivers/net/wireless/orinoco_plx.c
rename to drivers/net/wireless/orinoco/orinoco_plx.c
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
similarity index 100%
rename from drivers/net/wireless/orinoco_tmd.c
rename to drivers/net/wireless/orinoco/orinoco_tmd.c
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
similarity index 94%
rename from drivers/net/wireless/spectrum_cs.c
rename to drivers/net/wireless/orinoco/spectrum_cs.c
index 852789a..b2ca2e3 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -248,13 +248,17 @@
 	/* Note that the CIS values need to be rescaled */
 	if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
 		if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-			DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+			DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
+			      __func__, vcc,
+			      cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
 			if (!ignore_cis_vcc)
 				goto next_entry;
 		}
 	} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
 		if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-			DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
+			DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
+			      __func__, vcc,
+			      dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
 			if (!ignore_cis_vcc)
 				goto next_entry;
 		}
@@ -383,7 +387,7 @@
 
 	/* Finally, report what we've done */
 	printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
-	       "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
+	       "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
 	       link->irq.AssignedIRQ, link->io.BasePort1,
 	       link->io.BasePort1 + link->io.NumPorts1 - 1);
 
@@ -450,10 +454,29 @@
 {
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = netdev_priv(dev);
+	unsigned long flags;
+	int err;
+
+	err = orinoco_reinit_firmware(dev);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+		       dev->name, err);
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
 
 	netif_device_attach(dev);
 	priv->hw_unavailable--;
-	schedule_work(&priv->reset_work);
+
+	if (priv->open && !priv->hw_unavailable) {
+		err = __orinoco_up(dev);
+		if (err)
+			printk(KERN_ERR "%s: Error %d restarting card\n",
+			       dev->name, err);
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 1d0704f..ab79e32 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -14,17 +14,17 @@
  * published by the Free Software Foundation.
  */
 
-enum control_frame_types {
-	P54_CONTROL_TYPE_FILTER_SET = 0,
-	P54_CONTROL_TYPE_CHANNEL_CHANGE,
-	P54_CONTROL_TYPE_FREQDONE,
+enum p54_control_frame_types {
+	P54_CONTROL_TYPE_SETUP = 0,
+	P54_CONTROL_TYPE_SCAN,
+	P54_CONTROL_TYPE_TRAP,
 	P54_CONTROL_TYPE_DCFINIT,
-	P54_CONTROL_TYPE_ENCRYPTION,
+	P54_CONTROL_TYPE_RX_KEYCACHE,
 	P54_CONTROL_TYPE_TIM,
-	P54_CONTROL_TYPE_POWERMGT,
-	P54_CONTROL_TYPE_FREEQUEUE,
+	P54_CONTROL_TYPE_PSM,
+	P54_CONTROL_TYPE_TXCANCEL,
 	P54_CONTROL_TYPE_TXDONE,
-	P54_CONTROL_TYPE_PING,
+	P54_CONTROL_TYPE_BURST,
 	P54_CONTROL_TYPE_STAT_READBACK,
 	P54_CONTROL_TYPE_BBP,
 	P54_CONTROL_TYPE_EEPROM_READBACK,
@@ -37,18 +37,44 @@
 	P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
 	P54_CONTROL_TYPE_CCE_QUIET,
 	P54_CONTROL_TYPE_PSM_STA_UNLOCK,
+	P54_CONTROL_TYPE_PCS,
+	P54_CONTROL_TYPE_BT_BALANCER = 28,
+	P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
+	P54_CONTROL_TYPE_ARPTABLE = 31,
+	P54_CONTROL_TYPE_BT_OPTIONS = 35
 };
 
-struct p54_control_hdr {
-	__le16 magic1;
+#define P54_HDR_FLAG_CONTROL		BIT(15)
+#define P54_HDR_FLAG_CONTROL_OPSET	(BIT(15) + BIT(0))
+
+struct p54_hdr {
+	__le16 flags;
 	__le16 len;
 	__le32 req_id;
-	__le16 type;	/* enum control_frame_types */
-	u8 retry1;
-	u8 retry2;
+	__le16 type;	/* enum p54_control_frame_types */
+	u8 rts_tries;
+	u8 tries;
 	u8 data[0];
 } __attribute__ ((packed));
 
+#define FREE_AFTER_TX(skb)						\
+	((((struct p54_hdr *) ((struct sk_buff *) skb)->data)->		\
+	flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+
+struct p54_edcf_queue_param {
+	__le16 aifs;
+	__le16 cwmin;
+	__le16 cwmax;
+	__le16 txop;
+} __attribute__ ((packed));
+
+struct p54_rssi_linear_approximation {
+	s16 mul;
+	s16 add;
+	s16 longbow_unkn;
+	s16 longbow_unk2;
+};
+
 #define EEPROM_READBACK_LEN 0x3fc
 
 #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
@@ -59,49 +85,53 @@
 #define FW_LM20 0x4c4d3230
 
 struct p54_common {
+	struct ieee80211_hw *hw;
 	u32 rx_start;
 	u32 rx_end;
 	struct sk_buff_head tx_queue;
-	void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data,
-		   size_t len, int free_on_tx);
+	void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
 	int (*open)(struct ieee80211_hw *dev);
 	void (*stop)(struct ieee80211_hw *dev);
 	int mode;
-	u16 seqno;
 	u16 rx_mtu;
 	u8 headroom;
 	u8 tailroom;
 	struct mutex conf_mutex;
 	u8 mac_addr[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
-	__le16 filter_type;
 	struct pda_iq_autocal_entry *iq_autocal;
 	unsigned int iq_autocal_len;
 	struct pda_channel_output_limit *output_limit;
 	unsigned int output_limit_len;
 	struct pda_pa_curve_data *curve_data;
+	struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
 	unsigned int filter_flags;
+	bool use_short_slot;
 	u16 rxhw;
 	u8 version;
-	u8 rx_antenna;
 	unsigned int tx_hdr_len;
-	void *cached_vdcf;
 	unsigned int fw_var;
 	unsigned int fw_interface;
 	unsigned int output_power;
 	u32 tsf_low32;
 	u32 tsf_high32;
+	u64 basic_rate_mask;
+	u16 wakeup_timer;
+	u16 aid;
 	struct ieee80211_tx_queue_stats tx_stats[8];
+	struct p54_edcf_queue_param qos_params[8];
 	struct ieee80211_low_level_stats stats;
-	struct timer_list stats_timer;
-	struct completion stats_comp;
-	void *cached_stats;
+	struct delayed_work work;
+	struct sk_buff *cached_beacon;
 	int noise;
 	void *eeprom;
 	struct completion eeprom_comp;
+	u8 privacy_caps;
+	u8 rx_keycache_size;
 };
 
 int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
+void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
 int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
 int p54_read_eeprom(struct ieee80211_hw *dev);
 struct ieee80211_hw *p54_init_common(size_t priv_data_len);
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 827ca03..82354b9 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -1,12 +1,15 @@
-
 /*
  * Common code for mac80211 Prism54 drivers
  *
  * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
  * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
  *
- * Based on the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -22,6 +25,9 @@
 #include "p54.h"
 #include "p54common.h"
 
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
 MODULE_DESCRIPTION("Softmac Prism54 common code");
 MODULE_LICENSE("GPL");
@@ -152,21 +158,21 @@
 			priv->fw_interface = be32_to_cpup((__be32 *)
 					     bootrec->data);
 			switch (priv->fw_interface) {
-			case FW_FMAC:
-				printk(KERN_INFO "p54: FreeMAC firmware\n");
-				break;
-			case FW_LM20:
-				printk(KERN_INFO "p54: LM20 firmware\n");
-				break;
 			case FW_LM86:
-				printk(KERN_INFO "p54: LM86 firmware\n");
+			case FW_LM20:
+			case FW_LM87: {
+				char *iftype = (char *)bootrec->data;
+				printk(KERN_INFO "%s: p54 detected a LM%c%c "
+						 "firmware\n",
+					wiphy_name(dev->wiphy),
+					iftype[2], iftype[3]);
 				break;
-			case FW_LM87:
-				printk(KERN_INFO "p54: LM87 firmware\n");
-				break;
+				}
+			case FW_FMAC:
 			default:
-				printk(KERN_INFO "p54: unknown firmware\n");
-				break;
+				printk(KERN_ERR "%s: unsupported firmware\n",
+					wiphy_name(dev->wiphy));
+				return -ENODEV;
 			}
 			break;
 		case BR_CODE_COMPONENT_VERSION:
@@ -182,8 +188,10 @@
 			priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
 			priv->headroom = desc->headroom;
 			priv->tailroom = desc->tailroom;
+			priv->privacy_caps = desc->privacy_caps;
+			priv->rx_keycache_size = desc->rx_keycache_size;
 			if (le32_to_cpu(bootrec->len) == 11)
-				priv->rx_mtu = le16_to_cpu(bootrec->rx_mtu);
+				priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
 			else
 				priv->rx_mtu = (size_t)
 					0x620 - priv->tx_hdr_len;
@@ -208,18 +216,35 @@
 	}
 
 	if (fw_version)
-		printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n",
-			fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
+		printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
+			wiphy_name(dev->wiphy), fw_version,
+			priv->fw_var >> 8, priv->fw_var & 0xff);
+
+	if (priv->fw_var < 0x500)
+		printk(KERN_INFO "%s: you are using an obsolete firmware. "
+		       "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+		       "and grab one for \"kernel >= 2.6.28\"!\n",
+			wiphy_name(dev->wiphy));
 
 	if (priv->fw_var >= 0x300) {
 		/* Firmware supports QoS, use it! */
-		priv->tx_stats[4].limit = 3;
-		priv->tx_stats[5].limit = 4;
-		priv->tx_stats[6].limit = 3;
-		priv->tx_stats[7].limit = 1;
+		priv->tx_stats[4].limit = 3;		/* AC_VO */
+		priv->tx_stats[5].limit = 4;		/* AC_VI */
+		priv->tx_stats[6].limit = 3;		/* AC_BE */
+		priv->tx_stats[7].limit = 2;		/* AC_BK */
 		dev->queues = 4;
 	}
 
+	if (!modparam_nohwcrypt)
+		printk(KERN_INFO "%s: cryptographic accelerator "
+				 "WEP:%s, TKIP:%s, CCMP:%s\n",
+			wiphy_name(dev->wiphy),
+			(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
+			"no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
+			 BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
+			(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
+			"YES" : "no");
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(p54_parse_firmware);
@@ -310,6 +335,36 @@
                               "Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
 static int p54_init_xbow_synth(struct ieee80211_hw *dev);
 
+static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
+			     u16 type)
+{
+	struct p54_common *priv = dev->priv;
+	int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
+	int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
+	int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
+	int i;
+
+	if (len != (entry_size * num_entries)) {
+		printk(KERN_ERR "%s: unknown rssi calibration data packing "
+				 " type:(%x) len:%d.\n",
+		       wiphy_name(dev->wiphy), type, len);
+
+		print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
+				     data, len);
+
+		printk(KERN_ERR "%s: please report this issue.\n",
+			wiphy_name(dev->wiphy));
+		return;
+	}
+
+	for (i = 0; i < num_entries; i++) {
+		struct pda_rssi_cal_entry *cal = data +
+						 (offset + i * entry_size);
+		priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
+		priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
+	}
+}
+
 static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 {
 	struct p54_common *priv = dev->priv;
@@ -320,7 +375,6 @@
 	int err;
 	u8 *end = (u8 *)eeprom + len;
 	u16 synth = 0;
-	DECLARE_MAC_BUF(mac);
 
 	wrap = (struct eeprom_pda_wrap *) eeprom;
 	entry = (void *)wrap->data + le16_to_cpu(wrap->len);
@@ -377,8 +431,9 @@
 				err = p54_convert_rev1(dev, curve_data);
 				break;
 			default:
-				printk(KERN_ERR "p54: unknown curve data "
+				printk(KERN_ERR "%s: unknown curve data "
 						"revision %d\n",
+						wiphy_name(dev->wiphy),
 						curve_data->cal_method_rev);
 				err = -ENODEV;
 				break;
@@ -409,12 +464,40 @@
 		case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
 			priv->version = *(u8 *)(entry->data + 1);
 			break;
+		case PDR_RSSI_LINEAR_APPROXIMATION:
+		case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
+		case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+			p54_parse_rssical(dev, entry->data, data_len,
+					  le16_to_cpu(entry->code));
+			break;
 		case PDR_END:
 			/* make it overrun */
 			entry_len = len;
 			break;
+		case PDR_MANUFACTURING_PART_NUMBER:
+		case PDR_PDA_VERSION:
+		case PDR_NIC_SERIAL_NUMBER:
+		case PDR_REGULATORY_DOMAIN_LIST:
+		case PDR_TEMPERATURE_TYPE:
+		case PDR_PRISM_PCI_IDENTIFIER:
+		case PDR_COUNTRY_INFORMATION:
+		case PDR_OEM_NAME:
+		case PDR_PRODUCT_NAME:
+		case PDR_UTF8_OEM_NAME:
+		case PDR_UTF8_PRODUCT_NAME:
+		case PDR_COUNTRY_LIST:
+		case PDR_DEFAULT_COUNTRY:
+		case PDR_ANTENNA_GAIN:
+		case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
+		case PDR_REGULATORY_POWER_LIMITS:
+		case PDR_RADIATED_TRANSMISSION_CORRECTION:
+		case PDR_PRISM_TX_IQ_CALIBRATION:
+		case PDR_BASEBAND_REGISTERS:
+		case PDR_PER_CHANNEL_BASEBAND_REGISTERS:
+			break;
 		default:
-			printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n",
+			printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n",
+				wiphy_name(dev->wiphy),
 				le16_to_cpu(entry->code));
 			break;
 		}
@@ -424,17 +507,18 @@
 
 	if (!synth || !priv->iq_autocal || !priv->output_limit ||
 	    !priv->curve_data) {
-		printk(KERN_ERR "p54: not all required entries found in eeprom!\n");
+		printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
+			wiphy_name(dev->wiphy));
 		err = -EINVAL;
 		goto err;
 	}
 
-	priv->rxhw = synth & 0x07;
+	priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
 	if (priv->rxhw == 4)
 		p54_init_xbow_synth(dev);
-	if (!(synth & 0x40))
+	if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
 		dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
-	if (!(synth & 0x80))
+	if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
 		dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
 
 	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
@@ -446,9 +530,9 @@
 		SET_IEEE80211_PERM_ADDR(dev, perm_addr);
 	}
 
-	printk(KERN_INFO "%s: hwaddr %s, MAC:isl38%02x RF:%s\n",
+	printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
 		wiphy_name(dev->wiphy),
-		print_mac(mac, dev->wiphy->perm_addr),
+		dev->wiphy->perm_addr,
 		priv->version, p54_rf_chips[priv->rxhw]);
 
 	return 0;
@@ -469,36 +553,56 @@
 		priv->curve_data = NULL;
 	}
 
-	printk(KERN_ERR "p54: eeprom parse failed!\n");
+	printk(KERN_ERR "%s: eeprom parse failed!\n",
+		wiphy_name(dev->wiphy));
 	return err;
 }
 
 static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
 {
-	/* TODO: get the rssi_add & rssi_mul data from the eeprom */
-	return ((rssi * 0x83) / 64 - 400) / 4;
+	struct p54_common *priv = dev->priv;
+	int band = dev->conf.channel->band;
+
+	return ((rssi * priv->rssical_db[band].mul) / 64 +
+			 priv->rssical_db[band].add) / 4;
 }
 
 static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct p54_common *priv = dev->priv;
-	struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data;
+	struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
 	struct ieee80211_rx_status rx_status = {0};
 	u16 freq = le16_to_cpu(hdr->freq);
 	size_t header_len = sizeof(*hdr);
 	u32 tsf32;
 
-	if (!(hdr->magic & cpu_to_le16(0x0001))) {
+	/*
+	 * If the device is in a unspecified state we have to
+	 * ignore all data frames. Else we could end up with a
+	 * nasty crash.
+	 */
+	if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+		return 0;
+
+	if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) {
 		if (priv->filter_flags & FIF_FCSFAIL)
 			rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
 		else
 			return 0;
 	}
 
+	if (hdr->decrypt_status == P54_DECRYPT_OK)
+		rx_status.flag |= RX_FLAG_DECRYPTED;
+	if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
+	    (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
+		rx_status.flag |= RX_FLAG_MMIC_ERROR;
+
 	rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi);
 	rx_status.noise = priv->noise;
 	/* XX correct? */
 	rx_status.qual = (100 * hdr->rssi) / 127;
+	if (hdr->rate & 0x10)
+		rx_status.flag |= RX_FLAG_SHORTPRE;
 	rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ?
 			hdr->rate : (hdr->rate - 4)) & 0xf;
 	rx_status.freq = freq;
@@ -513,7 +617,7 @@
 
 	rx_status.flag |= RX_FLAG_TSFT;
 
-	if (hdr->magic & cpu_to_le16(0x4000))
+	if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
 		header_len += hdr->align[0];
 
 	skb_pull(skb, header_len);
@@ -521,6 +625,9 @@
 
 	ieee80211_rx_irqsafe(dev, skb, &rx_status);
 
+	queue_delayed_work(dev->workqueue, &priv->work,
+			   msecs_to_jiffies(P54_STATISTICS_UPDATE));
+
 	return -1;
 }
 
@@ -529,88 +636,197 @@
 	struct p54_common *priv = dev->priv;
 	int i;
 
+	if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+		return ;
+
 	for (i = 0; i < dev->queues; i++)
 		if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit)
 			ieee80211_wake_queue(dev, i);
 }
 
+void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+	struct p54_common *priv = dev->priv;
+	struct ieee80211_tx_info *info;
+	struct memrecord *range;
+	unsigned long flags;
+	u32 freed = 0, last_addr = priv->rx_start;
+
+	if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
+		return;
+
+	/*
+	 * don't try to free an already unlinked skb
+	 */
+	if (unlikely((!skb->next) || (!skb->prev)))
+		return;
+
+	spin_lock_irqsave(&priv->tx_queue.lock, flags);
+	info = IEEE80211_SKB_CB(skb);
+	range = (void *)info->rate_driver_data;
+	if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
+		struct ieee80211_tx_info *ni;
+		struct memrecord *mr;
+
+		ni = IEEE80211_SKB_CB(skb->prev);
+		mr = (struct memrecord *)ni->rate_driver_data;
+		last_addr = mr->end_addr;
+	}
+	if (skb->next != (struct sk_buff *)&priv->tx_queue) {
+		struct ieee80211_tx_info *ni;
+		struct memrecord *mr;
+
+		ni = IEEE80211_SKB_CB(skb->next);
+		mr = (struct memrecord *)ni->rate_driver_data;
+		freed = mr->start_addr - last_addr;
+	} else
+		freed = priv->rx_end - last_addr;
+	__skb_unlink(skb, &priv->tx_queue);
+	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+	dev_kfree_skb_any(skb);
+
+	if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 +
+		     IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
+		p54_wake_free_queues(dev);
+}
+EXPORT_SYMBOL_GPL(p54_free_skb);
+
+static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
+					   __le32 req_id)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *entry = priv->tx_queue.next;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->tx_queue.lock, flags);
+	while (entry != (struct sk_buff *)&priv->tx_queue) {
+		struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
+
+		if (hdr->req_id == req_id) {
+			spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+			return entry;
+		}
+		entry = entry->next;
+	}
+	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+	return NULL;
+}
+
 static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct p54_common *priv = dev->priv;
-	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
-	struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data;
+	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+	struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
 	struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next;
 	u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
 	struct memrecord *range = NULL;
 	u32 freed = 0;
 	u32 last_addr = priv->rx_start;
 	unsigned long flags;
+	int count, idx;
 
 	spin_lock_irqsave(&priv->tx_queue.lock, flags);
 	while (entry != (struct sk_buff *)&priv->tx_queue) {
 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
-		range = (void *)info->driver_data;
-		if (range->start_addr == addr) {
-			struct p54_control_hdr *entry_hdr;
-			struct p54_tx_control_allocdata *entry_data;
-			int pad = 0;
+		struct p54_hdr *entry_hdr;
+		struct p54_tx_data *entry_data;
+		int pad = 0;
 
-			if (entry->next != (struct sk_buff *)&priv->tx_queue) {
-				struct ieee80211_tx_info *ni;
-				struct memrecord *mr;
-
-				ni = IEEE80211_SKB_CB(entry->next);
-				mr = (struct memrecord *)ni->driver_data;
-				freed = mr->start_addr - last_addr;
-			} else
-				freed = priv->rx_end - last_addr;
-
+		range = (void *)info->rate_driver_data;
+		if (range->start_addr != addr) {
 			last_addr = range->end_addr;
-			__skb_unlink(entry, &priv->tx_queue);
-			spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+			entry = entry->next;
+			continue;
+		}
 
-			memset(&info->status, 0, sizeof(info->status));
-			entry_hdr = (struct p54_control_hdr *) entry->data;
-			entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
-			if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
-				pad = entry_data->align[0];
+		if (entry->next != (struct sk_buff *)&priv->tx_queue) {
+			struct ieee80211_tx_info *ni;
+			struct memrecord *mr;
 
-			priv->tx_stats[entry_data->hw_queue].len--;
-			if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-				if (!(payload->status & 0x01))
-					info->flags |= IEEE80211_TX_STAT_ACK;
-				else
-					info->status.excessive_retries = 1;
-			}
-			info->status.retry_count = payload->retries - 1;
-			info->status.ack_signal = p54_rssi_to_dbm(dev,
-					le16_to_cpu(payload->ack_rssi));
-			skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
-			ieee80211_tx_status_irqsafe(dev, entry);
-			goto out;
+			ni = IEEE80211_SKB_CB(entry->next);
+			mr = (struct memrecord *)ni->rate_driver_data;
+			freed = mr->start_addr - last_addr;
 		} else
-			last_addr = range->end_addr;
-		entry = entry->next;
+			freed = priv->rx_end - last_addr;
+
+		last_addr = range->end_addr;
+		__skb_unlink(entry, &priv->tx_queue);
+		spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+
+		entry_hdr = (struct p54_hdr *) entry->data;
+		entry_data = (struct p54_tx_data *) entry_hdr->data;
+		priv->tx_stats[entry_data->hw_queue].len--;
+		priv->stats.dot11ACKFailureCount += payload->tries - 1;
+
+		if (unlikely(entry == priv->cached_beacon)) {
+			kfree_skb(entry);
+			priv->cached_beacon = NULL;
+			goto out;
+		}
+
+		/*
+		 * Clear manually, ieee80211_tx_info_clear_status would
+		 * clear the counts too and we need them.
+		 */
+		memset(&info->status.ampdu_ack_len, 0,
+		       sizeof(struct ieee80211_tx_info) -
+		       offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
+		BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
+				      status.ampdu_ack_len) != 23);
+
+		if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+			pad = entry_data->align[0];
+
+		/* walk through the rates array and adjust the counts */
+		count = payload->tries;
+		for (idx = 0; idx < 4; idx++) {
+			if (count >= info->status.rates[idx].count) {
+				count -= info->status.rates[idx].count;
+			} else if (count > 0) {
+				info->status.rates[idx].count = count;
+				count = 0;
+			} else {
+				info->status.rates[idx].idx = -1;
+				info->status.rates[idx].count = 0;
+			}
+		}
+
+		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+		     (!payload->status))
+			info->flags |= IEEE80211_TX_STAT_ACK;
+		if (payload->status & P54_TX_PSM_CANCELLED)
+			info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+		info->status.ack_signal = p54_rssi_to_dbm(dev,
+				(int)payload->ack_rssi);
+		skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+		ieee80211_tx_status_irqsafe(dev, entry);
+		goto out;
 	}
 	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
 out:
-	if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
-	    sizeof(struct p54_control_hdr))
+	if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 +
+		     IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
 		p54_wake_free_queues(dev);
 }
 
 static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
 				   struct sk_buff *skb)
 {
-	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
 	struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
 	struct p54_common *priv = dev->priv;
 
 	if (!priv->eeprom)
 		return ;
 
-	memcpy(priv->eeprom, eeprom->data, le16_to_cpu(eeprom->len));
+	if (priv->fw_var >= 0x509) {
+		memcpy(priv->eeprom, eeprom->v2.data,
+		       le16_to_cpu(eeprom->v2.len));
+	} else {
+		memcpy(priv->eeprom, eeprom->v1.data,
+		       le16_to_cpu(eeprom->v1.len));
+	}
 
 	complete(&priv->eeprom_comp);
 }
@@ -618,10 +834,14 @@
 static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct p54_common *priv = dev->priv;
-	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
 	struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
-	u32 tsf32 = le32_to_cpu(stats->tsf32);
+	u32 tsf32;
 
+	if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+		return ;
+
+	tsf32 = le32_to_cpu(stats->tsf32);
 	if (tsf32 < priv->tsf_low32)
 		priv->tsf_high32++;
 	priv->tsf_low32 = tsf32;
@@ -631,19 +851,50 @@
 	priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
 
 	priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
-	complete(&priv->stats_comp);
 
-	mod_timer(&priv->stats_timer, jiffies + 5 * HZ);
+	p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id));
+}
+
+static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+	struct p54_trap *trap = (struct p54_trap *) hdr->data;
+	u16 event = le16_to_cpu(trap->event);
+	u16 freq = le16_to_cpu(trap->frequency);
+
+	switch (event) {
+	case P54_TRAP_BEACON_TX:
+		break;
+	case P54_TRAP_RADAR:
+		printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
+			wiphy_name(dev->wiphy), freq);
+		break;
+	case P54_TRAP_NO_BEACON:
+		break;
+	case P54_TRAP_SCAN:
+		break;
+	case P54_TRAP_TBTT:
+		break;
+	case P54_TRAP_TIMER:
+		break;
+	default:
+		printk(KERN_INFO "%s: received event:%x freq:%d\n",
+		       wiphy_name(dev->wiphy), event, freq);
+		break;
+	}
 }
 
 static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
-	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+	struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
 
 	switch (le16_to_cpu(hdr->type)) {
 	case P54_CONTROL_TYPE_TXDONE:
 		p54_rx_frame_sent(dev, skb);
 		break;
+	case P54_CONTROL_TYPE_TRAP:
+		p54_rx_trap(dev, skb);
+		break;
 	case P54_CONTROL_TYPE_BBP:
 		break;
 	case P54_CONTROL_TYPE_STAT_READBACK:
@@ -664,9 +915,9 @@
 /* returns zero if skb can be reused */
 int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
-	u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8;
+	u16 type = le16_to_cpu(*((__le16 *)skb->data));
 
-	if (type == 0x80)
+	if (type & P54_HDR_FLAG_CONTROL)
 		return p54_rx_control(dev, skb);
 	else
 		return p54_rx_data(dev, skb);
@@ -682,12 +933,14 @@
  * marks allocated areas as reserved if necessary. p54_rx_frame_sent frees
  * allocated areas.
  */
-static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
-			       struct p54_control_hdr *data, u32 len)
+static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
+			       struct p54_hdr *data, u32 len)
 {
 	struct p54_common *priv = dev->priv;
 	struct sk_buff *entry = priv->tx_queue.next;
 	struct sk_buff *target_skb = NULL;
+	struct ieee80211_tx_info *info;
+	struct memrecord *range;
 	u32 last_addr = priv->rx_start;
 	u32 largest_hole = 0;
 	u32 target_addr = priv->rx_start;
@@ -695,12 +948,37 @@
 	unsigned int left;
 	len = (len + priv->headroom + priv->tailroom + 3) & ~0x3;
 
+	if (!skb)
+		return -EINVAL;
+
 	spin_lock_irqsave(&priv->tx_queue.lock, flags);
+
 	left = skb_queue_len(&priv->tx_queue);
+	if (unlikely(left >= 28)) {
+		/*
+		 * The tx_queue is nearly full!
+		 * We have throttle normal data traffic, because we must
+		 * have a few spare slots for control frames left.
+		 */
+		ieee80211_stop_queues(dev);
+		queue_delayed_work(dev->workqueue, &priv->work,
+				   msecs_to_jiffies(P54_TX_TIMEOUT));
+
+		if (unlikely(left == 32)) {
+			/*
+			 * The tx_queue is now really full.
+			 *
+			 * TODO: check if the device has crashed and reset it.
+			 */
+			spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+			return -ENOSPC;
+		}
+	}
+
 	while (left--) {
 		u32 hole_size;
-		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
-		struct memrecord *range = (void *)info->driver_data;
+		info = IEEE80211_SKB_CB(entry);
+		range = (void *)info->rate_driver_data;
 		hole_size = range->start_addr - last_addr;
 		if (!target_skb && hole_size >= len) {
 			target_skb = entry->prev;
@@ -715,64 +993,102 @@
 		target_skb = priv->tx_queue.prev;
 		largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
 		if (!skb_queue_empty(&priv->tx_queue)) {
-			struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb);
-			struct memrecord *range = (void *)info->driver_data;
+			info = IEEE80211_SKB_CB(target_skb);
+			range = (void *)info->rate_driver_data;
 			target_addr = range->end_addr;
 		}
 	} else
 		largest_hole = max(largest_hole, priv->rx_end - last_addr);
 
-	if (skb) {
-		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-		struct memrecord *range = (void *)info->driver_data;
-		range->start_addr = target_addr;
-		range->end_addr = target_addr + len;
-		__skb_queue_after(&priv->tx_queue, target_skb, skb);
-		if (largest_hole < priv->rx_mtu + priv->headroom +
-				   priv->tailroom +
-				   sizeof(struct p54_control_hdr))
-			ieee80211_stop_queues(dev);
+	if (!target_skb) {
+		spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+		ieee80211_stop_queues(dev);
+		return -ENOSPC;
 	}
+
+	info = IEEE80211_SKB_CB(skb);
+	range = (void *)info->rate_driver_data;
+	range->start_addr = target_addr;
+	range->end_addr = target_addr + len;
+	__skb_queue_after(&priv->tx_queue, target_skb, skb);
 	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
+	if (largest_hole < priv->headroom + sizeof(struct p54_hdr) +
+			   48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
+		ieee80211_stop_queues(dev);
+
 	data->req_id = cpu_to_le32(target_addr + priv->headroom);
+	return 0;
+}
+
+static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev,
+		u16 hdr_flags, u16 len, u16 type, gfp_t memflags)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_hdr *hdr;
+	struct sk_buff *skb;
+
+	skb = __dev_alloc_skb(len + priv->tx_hdr_len, memflags);
+	if (!skb)
+		return NULL;
+	skb_reserve(skb, priv->tx_hdr_len);
+
+	hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
+	hdr->flags = cpu_to_le16(hdr_flags);
+	hdr->len = cpu_to_le16(len - sizeof(*hdr));
+	hdr->type = cpu_to_le16(type);
+	hdr->tries = hdr->rts_tries = 0;
+
+	if (unlikely(p54_assign_address(dev, skb, hdr, len))) {
+		kfree_skb(skb);
+		return NULL;
+	}
+	return skb;
 }
 
 int p54_read_eeprom(struct ieee80211_hw *dev)
 {
 	struct p54_common *priv = dev->priv;
-	struct p54_control_hdr *hdr = NULL;
+	struct p54_hdr *hdr = NULL;
 	struct p54_eeprom_lm86 *eeprom_hdr;
-	size_t eeprom_size = 0x2020, offset = 0, blocksize;
+	struct sk_buff *skb;
+	size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
 	int ret = -ENOMEM;
 	void *eeprom = NULL;
 
-	hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) +
-		sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL);
-	if (!hdr)
-		goto free;
+	maxblocksize = EEPROM_READBACK_LEN;
+	if (priv->fw_var >= 0x509)
+		maxblocksize -= 0xc;
+	else
+		maxblocksize -= 0x4;
 
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*hdr) +
+			    sizeof(*eeprom_hdr) + maxblocksize,
+			    P54_CONTROL_TYPE_EEPROM_READBACK, GFP_KERNEL);
+	if (!skb)
+		goto free;
 	priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
 	if (!priv->eeprom)
 		goto free;
-
 	eeprom = kzalloc(eeprom_size, GFP_KERNEL);
 	if (!eeprom)
 		goto free;
 
-	hdr->magic1 = cpu_to_le16(0x8000);
-	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK);
-	hdr->retry1 = hdr->retry2 = 0;
-	eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data;
+	eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
+		     sizeof(*eeprom_hdr) + maxblocksize);
 
 	while (eeprom_size) {
-		blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN);
-		hdr->len = cpu_to_le16(blocksize + sizeof(*eeprom_hdr));
-		eeprom_hdr->offset = cpu_to_le16(offset);
-		eeprom_hdr->len = cpu_to_le16(blocksize);
-		p54_assign_address(dev, NULL, hdr, le16_to_cpu(hdr->len) +
-				   sizeof(*hdr));
-		priv->tx(dev, hdr, le16_to_cpu(hdr->len) + sizeof(*hdr), 0);
+		blocksize = min(eeprom_size, maxblocksize);
+		if (priv->fw_var < 0x509) {
+			eeprom_hdr->v1.offset = cpu_to_le16(offset);
+			eeprom_hdr->v1.len = cpu_to_le16(blocksize);
+		} else {
+			eeprom_hdr->v2.offset = cpu_to_le32(offset);
+			eeprom_hdr->v2.len = cpu_to_le16(blocksize);
+			eeprom_hdr->v2.magic2 = 0xf;
+			memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
+		}
+		priv->tx(dev, skb);
 
 		if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
 			printk(KERN_ERR "%s: device does not respond!\n",
@@ -790,166 +1106,422 @@
 free:
 	kfree(priv->eeprom);
 	priv->eeprom = NULL;
-	kfree(hdr);
+	p54_free_skb(dev, skb);
 	kfree(eeprom);
 
 	return ret;
 }
 EXPORT_SYMBOL_GPL(p54_read_eeprom);
 
+static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
+		bool set)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *skb;
+	struct p54_tim *tim;
+
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+		      sizeof(struct p54_hdr) + sizeof(*tim),
+		      P54_CONTROL_TYPE_TIM, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
+	tim->count = 1;
+	tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
+	priv->tx(dev, skb);
+	return 0;
+}
+
+static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *skb;
+	struct p54_sta_unlock *sta;
+
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+		sizeof(struct p54_hdr) + sizeof(*sta),
+		P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
+	memcpy(sta->addr, addr, ETH_ALEN);
+	priv->tx(dev, skb);
+	return 0;
+}
+
+static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
+			      enum sta_notify_cmd notify_cmd,
+			      struct ieee80211_sta *sta)
+{
+	switch (notify_cmd) {
+	case STA_NOTIFY_ADD:
+	case STA_NOTIFY_REMOVE:
+		/*
+		 * Notify the firmware that we don't want or we don't
+		 * need to buffer frames for this station anymore.
+		 */
+
+		p54_sta_unlock(dev, sta->addr);
+		break;
+	case STA_NOTIFY_AWAKE:
+		/* update the firmware's filter table */
+		p54_sta_unlock(dev, sta->addr);
+		break;
+	default:
+		break;
+	}
+}
+
+static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *skb;
+	struct p54_hdr *hdr;
+	struct p54_txcancel *cancel;
+
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+		sizeof(struct p54_hdr) + sizeof(*cancel),
+		P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	hdr = (void *)entry->data;
+	cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
+	cancel->req_id = hdr->req_id;
+	priv->tx(dev, skb);
+	return 0;
+}
+
+static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
+		struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len,
+		u16 *flags, u16 *aid)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct p54_common *priv = dev->priv;
+	int ret = 0;
+
+	if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
+		if (ieee80211_is_beacon(hdr->frame_control)) {
+			*aid = 0;
+			*queue = 0;
+			*extra_len = IEEE80211_MAX_TIM_LEN;
+			*flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
+			return 0;
+		} else if (ieee80211_is_probe_resp(hdr->frame_control)) {
+			*aid = 0;
+			*queue = 2;
+			*flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
+				 P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+			return 0;
+		} else {
+			*queue = 2;
+			ret = 0;
+		}
+	} else {
+		*queue += 4;
+		ret = 1;
+	}
+
+	switch (priv->mode) {
+	case NL80211_IFTYPE_STATION:
+		*aid = 1;
+		break;
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
+		if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+			*aid = 0;
+			*queue = 3;
+			return 0;
+		}
+		if (info->control.sta)
+			*aid = info->control.sta->aid;
+		else
+			*flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+	}
+	return ret;
+}
+
+static u8 p54_convert_algo(enum ieee80211_key_alg alg)
+{
+	switch (alg) {
+	case ALG_WEP:
+		return P54_CRYPTO_WEP;
+	case ALG_TKIP:
+		return P54_CRYPTO_TKIPMICHAEL;
+	case ALG_CCMP:
+		return P54_CRYPTO_AESCCMP;
+	default:
+		return 0;
+	}
+}
+
 static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_tx_queue_stats *current_queue;
+	struct ieee80211_tx_queue_stats *current_queue = NULL;
 	struct p54_common *priv = dev->priv;
-	struct p54_control_hdr *hdr;
-	struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
-	struct p54_tx_control_allocdata *txhdr;
-	size_t padding, len;
-	u8 rate;
+	struct p54_hdr *hdr;
+	struct p54_tx_data *txhdr;
+	size_t padding, len, tim_len = 0;
+	int i, j, ridx, ret;
+	u16 hdr_flags = 0, aid = 0;
+	u8 rate, queue, crypt_offset = 0;
 	u8 cts_rate = 0x20;
+	u8 rc_flags;
+	u8 calculated_tries[4];
+	u8 nrates = 0, nremaining = 8;
 
-	current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4];
-	if (unlikely(current_queue->len > current_queue->limit))
+	queue = skb_get_queue_mapping(skb);
+
+	ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid);
+	current_queue = &priv->tx_stats[queue];
+	if (unlikely((current_queue->len > current_queue->limit) && ret))
 		return NETDEV_TX_BUSY;
 	current_queue->len++;
 	current_queue->count++;
-	if (current_queue->len == current_queue->limit)
+	if ((current_queue->len == current_queue->limit) && ret)
 		ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
 
 	padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
 	len = skb->len;
 
-	txhdr = (struct p54_tx_control_allocdata *)
-			skb_push(skb, sizeof(*txhdr) + padding);
-	hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr));
+	if (info->control.hw_key) {
+		crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
+		if (info->control.hw_key->alg == ALG_TKIP) {
+			u8 *iv = (u8 *)(skb->data + crypt_offset);
+			/*
+			 * The firmware excepts that the IV has to have
+			 * this special format
+			 */
+			iv[1] = iv[0];
+			iv[0] = iv[2];
+			iv[2] = 0;
+		}
+	}
+
+	txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
+	hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
 
 	if (padding)
-		hdr->magic1 = cpu_to_le16(0x4010);
-	else
-		hdr->magic1 = cpu_to_le16(0x0010);
-	hdr->len = cpu_to_le16(len);
-	hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
-	hdr->retry1 = hdr->retry2 = info->control.retry_limit;
+		hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
+	hdr->type = cpu_to_le16(aid);
+	hdr->rts_tries = info->control.rates[0].count;
 
-	/* TODO: add support for alternate retry TX rates */
-	rate = ieee80211_get_tx_rate(dev, info)->hw_value;
-	if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) {
-		rate |= 0x10;
-		cts_rate |= 0x10;
+	/*
+	 * we register the rates in perfect order, and
+	 * RTS/CTS won't happen on 5 GHz
+	 */
+	cts_rate = info->control.rts_cts_rate_idx;
+
+	memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
+
+	/* see how many rates got used */
+	for (i = 0; i < 4; i++) {
+		if (info->control.rates[i].idx < 0)
+			break;
+		nrates++;
 	}
-	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
-		rate |= 0x40;
-		cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
-	} else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
-		rate |= 0x20;
-		cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
+
+	/* limit tries to 8/nrates per rate */
+	for (i = 0; i < nrates; i++) {
+		/*
+		 * The magic expression here is equivalent to 8/nrates for
+		 * all values that matter, but avoids division and jumps.
+		 * Note that nrates can only take the values 1 through 4.
+		 */
+		calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
+						 info->control.rates[i].count);
+		nremaining -= calculated_tries[i];
 	}
-	memset(txhdr->rateset, rate, 8);
-	txhdr->key_type = 0;
-	txhdr->key_len = 0;
-	txhdr->hw_queue = skb_get_queue_mapping(skb) + 4;
+
+	/* if there are tries left, distribute from back to front */
+	for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
+		int tmp = info->control.rates[i].count - calculated_tries[i];
+
+		if (tmp <= 0)
+			continue;
+		/* RC requested more tries at this rate */
+
+		tmp = min_t(int, tmp, nremaining);
+		calculated_tries[i] += tmp;
+		nremaining -= tmp;
+	}
+
+	ridx = 0;
+	for (i = 0; i < nrates && ridx < 8; i++) {
+		/* we register the rates in perfect order */
+		rate = info->control.rates[i].idx;
+		if (info->band == IEEE80211_BAND_5GHZ)
+			rate += 4;
+
+		/* store the count we actually calculated for TX status */
+		info->control.rates[i].count = calculated_tries[i];
+
+		rc_flags = info->control.rates[i].flags;
+		if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
+			rate |= 0x10;
+			cts_rate |= 0x10;
+		}
+		if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
+			rate |= 0x40;
+		else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
+			rate |= 0x20;
+		for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
+			txhdr->rateset[ridx] = rate;
+			ridx++;
+		}
+	}
+
+	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+		hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
+
+	/* TODO: enable bursting */
+	hdr->flags = cpu_to_le16(hdr_flags);
+	hdr->tries = ridx;
+	txhdr->rts_rate_idx = 0;
+	if (info->control.hw_key) {
+		crypt_offset += info->control.hw_key->iv_len;
+		txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
+		txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
+		memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
+		if (info->control.hw_key->alg == ALG_TKIP) {
+			if (unlikely(skb_tailroom(skb) < 12))
+				goto err;
+			/* reserve space for the MIC key */
+			len += 8;
+			memcpy(skb_put(skb, 8), &(info->control.hw_key->key
+				[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
+		}
+		/* reserve some space for ICV */
+		len += info->control.hw_key->icv_len;
+	} else {
+		txhdr->key_type = 0;
+		txhdr->key_len = 0;
+	}
+	txhdr->crypt_offset = crypt_offset;
+	txhdr->hw_queue = queue;
+	if (current_queue)
+		txhdr->backlog = current_queue->len;
+	else
+		txhdr->backlog = 0;
+	memset(txhdr->durations, 0, sizeof(txhdr->durations));
 	txhdr->tx_antenna = (info->antenna_sel_tx == 0) ?
 		2 : info->antenna_sel_tx - 1;
 	txhdr->output_power = priv->output_power;
-	txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
-			  0 : cts_rate;
+	txhdr->cts_rate = cts_rate;
 	if (padding)
 		txhdr->align[0] = padding;
 
-	/* FIXME: The sequence that follows is needed for this driver to
-	 * work with mac80211 since "mac80211: fix TX sequence numbers".
-	 * As with the temporary code in rt2x00, changes will be needed
-	 * to get proper sequence numbers on beacons. In addition, this
-	 * patch places the sequence number in the hardware state, which
-	 * limits us to a single virtual state.
-	 */
-	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-		if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
-			priv->seqno += 0x10;
-		ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-		ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
-	}
+	hdr->len = cpu_to_le16(len);
 	/* modifies skb->cb and with it info, so must be last! */
-	p54_assign_address(dev, skb, hdr, skb->len);
+	if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
+		goto err;
+	priv->tx(dev, skb);
 
-	priv->tx(dev, hdr, skb->len, 0);
+	queue_delayed_work(dev->workqueue, &priv->work,
+			   msecs_to_jiffies(P54_TX_FRAME_LIFETIME));
+
 	return 0;
-}
 
-static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
-			  const u8 *bssid)
-{
-	struct p54_common *priv = dev->priv;
-	struct p54_control_hdr *hdr;
-	struct p54_tx_control_filter *filter;
-	size_t data_len;
-
-	hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) +
-		      priv->tx_hdr_len, GFP_ATOMIC);
-	if (!hdr)
-		return -ENOMEM;
-
-	hdr = (void *)hdr + priv->tx_hdr_len;
-
-	filter = (struct p54_tx_control_filter *) hdr->data;
-	hdr->magic1 = cpu_to_le16(0x8001);
-	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
-
-	priv->filter_type = filter->filter_type = cpu_to_le16(filter_type);
-	memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN);
-	if (!bssid)
-		memset(filter->bssid, ~0, ETH_ALEN);
-	else
-		memcpy(filter->bssid, bssid, ETH_ALEN);
-
-	filter->rx_antenna = priv->rx_antenna;
-
-	if (priv->fw_var < 0x500) {
-		data_len = P54_TX_CONTROL_FILTER_V1_LEN;
-		filter->v1.basic_rate_mask = cpu_to_le32(0x15F);
-		filter->v1.rx_addr = cpu_to_le32(priv->rx_end);
-		filter->v1.max_rx = cpu_to_le16(priv->rx_mtu);
-		filter->v1.rxhw = cpu_to_le16(priv->rxhw);
-		filter->v1.wakeup_timer = cpu_to_le16(500);
-	} else {
-		data_len = P54_TX_CONTROL_FILTER_V2_LEN;
-		filter->v2.rx_addr = cpu_to_le32(priv->rx_end);
-		filter->v2.max_rx = cpu_to_le16(priv->rx_mtu);
-		filter->v2.rxhw = cpu_to_le16(priv->rxhw);
-		filter->v2.timer = cpu_to_le16(1000);
+ err:
+	skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding);
+	if (current_queue) {
+		current_queue->len--;
+		current_queue->count--;
 	}
+	return NETDEV_TX_BUSY;
+}
 
-	hdr->len = cpu_to_le16(data_len);
-	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
-	priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
+static int p54_setup_mac(struct ieee80211_hw *dev)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *skb;
+	struct p54_setup_mac *setup;
+	u16 mode;
+
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup) +
+			    sizeof(struct p54_hdr), P54_CONTROL_TYPE_SETUP,
+			    GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
+	if (dev->conf.radio_enabled) {
+		switch (priv->mode) {
+		case NL80211_IFTYPE_STATION:
+			mode = P54_FILTER_TYPE_STATION;
+			break;
+		case NL80211_IFTYPE_AP:
+			mode = P54_FILTER_TYPE_AP;
+			break;
+		case NL80211_IFTYPE_ADHOC:
+		case NL80211_IFTYPE_MESH_POINT:
+			mode = P54_FILTER_TYPE_IBSS;
+			break;
+		default:
+			mode = P54_FILTER_TYPE_NONE;
+			break;
+		}
+		if (priv->filter_flags & FIF_PROMISC_IN_BSS)
+			mode |= P54_FILTER_TYPE_TRANSPARENT;
+	} else
+		mode = P54_FILTER_TYPE_RX_DISABLED;
+
+	setup->mac_mode = cpu_to_le16(mode);
+	memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
+	memcpy(setup->bssid, priv->bssid, ETH_ALEN);
+	setup->rx_antenna = 2; /* automatic */
+	setup->rx_align = 0;
+	if (priv->fw_var < 0x500) {
+		setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+		memset(setup->v1.rts_rates, 0, 8);
+		setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
+		setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
+		setup->v1.rxhw = cpu_to_le16(priv->rxhw);
+		setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
+		setup->v1.unalloc0 = cpu_to_le16(0);
+	} else {
+		setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
+		setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
+		setup->v2.rxhw = cpu_to_le16(priv->rxhw);
+		setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
+		setup->v2.truncate = cpu_to_le16(48896);
+		setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+		setup->v2.sbss_offset = 0;
+		setup->v2.mcast_window = 0;
+		setup->v2.rx_rssi_threshold = 0;
+		setup->v2.rx_ed_threshold = 0;
+		setup->v2.ref_clock = cpu_to_le32(644245094);
+		setup->v2.lpf_bandwidth = cpu_to_le16(65535);
+		setup->v2.osc_start_delay = cpu_to_le16(65535);
+	}
+	priv->tx(dev, skb);
 	return 0;
 }
 
-static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
+static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
 {
 	struct p54_common *priv = dev->priv;
-	struct p54_control_hdr *hdr;
-	struct p54_tx_control_channel *chan;
+	struct sk_buff *skb;
+	struct p54_scan *chan;
 	unsigned int i;
-	size_t data_len;
 	void *entry;
+	__le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
+	int band = dev->conf.channel->band;
 
-	hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) +
-		      priv->tx_hdr_len, GFP_KERNEL);
-	if (!hdr)
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) +
+			    sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN,
+			    GFP_ATOMIC);
+	if (!skb)
 		return -ENOMEM;
 
-	hdr = (void *)hdr + priv->tx_hdr_len;
-
-	chan = (struct p54_tx_control_channel *) hdr->data;
-
-	hdr->magic1 = cpu_to_le16(0x8001);
-
-	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
-
-	chan->flags = cpu_to_le16(0x1);
-	chan->dwell = cpu_to_le16(0x0);
+	chan = (struct p54_scan *) skb_put(skb, sizeof(*chan));
+	memset(chan->padding1, 0, sizeof(chan->padding1));
+	chan->mode = cpu_to_le16(mode);
+	chan->dwell = cpu_to_le16(dwell);
 
 	for (i = 0; i < priv->iq_autocal_len; i++) {
 		if (priv->iq_autocal[i].freq != freq)
@@ -990,61 +1562,50 @@
 		}
 
 		entry += sizeof(__le16);
-		chan->pa_points_per_curve =
-			min(priv->curve_data->points_per_channel, (u8) 8);
-
-		memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) *
-		       chan->pa_points_per_curve);
+		chan->pa_points_per_curve = 8;
+		memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+		memcpy(chan->curve_data, entry,
+		       sizeof(struct p54_pa_curve_data_sample) *
+		       min((u8)8, priv->curve_data->points_per_channel));
 		break;
 	}
 
 	if (priv->fw_var < 0x500) {
-		data_len = P54_TX_CONTROL_CHANNEL_V1_LEN;
-		chan->v1.rssical_mul = cpu_to_le16(130);
-		chan->v1.rssical_add = cpu_to_le16(0xfe70);
+		chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
+		chan->v1_rssi.add = cpu_to_le16(priv->rssical_db[band].add);
 	} else {
-		data_len = P54_TX_CONTROL_CHANNEL_V2_LEN;
-		chan->v2.rssical_mul = cpu_to_le16(130);
-		chan->v2.rssical_add = cpu_to_le16(0xfe70);
-		chan->v2.basic_rate_mask = cpu_to_le32(0x15f);
+		chan->v2.rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
+		chan->v2.rssi.add = cpu_to_le16(priv->rssical_db[band].add);
+		chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+		memset(chan->v2.rts_rates, 0, 8);
 	}
-
-	hdr->len = cpu_to_le16(data_len);
-	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
-	priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
+	priv->tx(dev, skb);
 	return 0;
 
  err:
 	printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy));
-	kfree(hdr);
+	kfree_skb(skb);
 	return -EINVAL;
 }
 
 static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
 {
 	struct p54_common *priv = dev->priv;
-	struct p54_control_hdr *hdr;
-	struct p54_tx_control_led *led;
+	struct sk_buff *skb;
+	struct p54_led *led;
 
-	hdr = kzalloc(sizeof(*hdr) + sizeof(*led) +
-		      priv->tx_hdr_len, GFP_KERNEL);
-	if (!hdr)
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led) +
+			sizeof(struct p54_hdr),	P54_CONTROL_TYPE_LED,
+			GFP_ATOMIC);
+	if (!skb)
 		return -ENOMEM;
 
-	hdr = (void *)hdr + priv->tx_hdr_len;
-	hdr->magic1 = cpu_to_le16(0x8001);
-	hdr->len = cpu_to_le16(sizeof(*led));
-	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED);
-	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led));
-
-	led = (struct p54_tx_control_led *) hdr->data;
+	led = (struct p54_led *)skb_put(skb, sizeof(*led));
 	led->mode = cpu_to_le16(mode);
 	led->led_permanent = cpu_to_le16(link);
 	led->led_temporary = cpu_to_le16(act);
 	led->duration = cpu_to_le16(1000);
-
-	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1);
-
+	priv->tx(dev, skb);
 	return 0;
 }
 
@@ -1056,53 +1617,113 @@
 	queue.txop = cpu_to_le16(_txop);			\
 } while(0)
 
-static void p54_init_vdcf(struct ieee80211_hw *dev)
+static int p54_set_edcf(struct ieee80211_hw *dev)
 {
 	struct p54_common *priv = dev->priv;
-	struct p54_control_hdr *hdr;
-	struct p54_tx_control_vdcf *vdcf;
+	struct sk_buff *skb;
+	struct p54_edcf *edcf;
 
-	/* all USB V1 adapters need a extra headroom */
-	hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
-	hdr->magic1 = cpu_to_le16(0x8001);
-	hdr->len = cpu_to_le16(sizeof(*vdcf));
-	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT);
-	hdr->req_id = cpu_to_le32(priv->rx_start);
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf) +
+			sizeof(struct p54_hdr), P54_CONTROL_TYPE_DCFINIT,
+			GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
 
-	vdcf = (struct p54_tx_control_vdcf *) hdr->data;
-
-	P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 47);
-	P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 94);
-	P54_SET_QUEUE(vdcf->queue[2], 0x0003, 0x000f, 0x03ff, 0);
-	P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0);
+	edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
+	if (priv->use_short_slot) {
+		edcf->slottime = 9;
+		edcf->sifs = 0x10;
+		edcf->eofpad = 0x00;
+	} else {
+		edcf->slottime = 20;
+		edcf->sifs = 0x0a;
+		edcf->eofpad = 0x06;
+	}
+	/* (see prism54/isl_oid.h for further details) */
+	edcf->frameburst = cpu_to_le16(0);
+	edcf->round_trip_delay = cpu_to_le16(0);
+	edcf->flags = 0;
+	memset(edcf->mapping, 0, sizeof(edcf->mapping));
+	memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
+	priv->tx(dev, skb);
+	return 0;
 }
 
-static void p54_set_vdcf(struct ieee80211_hw *dev)
+static int p54_beacon_tim(struct sk_buff *skb)
+{
+	/*
+	 * the good excuse for this mess is ... the firmware.
+	 * The dummy TIM MUST be at the end of the beacon frame,
+	 * because it'll be overwritten!
+	 */
+
+	struct ieee80211_mgmt *mgmt = (void *)skb->data;
+	u8 *pos, *end;
+
+	if (skb->len <= sizeof(mgmt))
+		return -EINVAL;
+
+	pos = (u8 *)mgmt->u.beacon.variable;
+	end = skb->data + skb->len;
+	while (pos < end) {
+		if (pos + 2 + pos[1] > end)
+			return -EINVAL;
+
+		if (pos[0] == WLAN_EID_TIM) {
+			u8 dtim_len = pos[1];
+			u8 dtim_period = pos[3];
+			u8 *next = pos + 2 + dtim_len;
+
+			if (dtim_len < 3)
+				return -EINVAL;
+
+			memmove(pos, next, end - next);
+
+			if (dtim_len > 3)
+				skb_trim(skb, skb->len - (dtim_len - 3));
+
+			pos = end - (dtim_len + 2);
+
+			/* add the dummy at the end */
+			pos[0] = WLAN_EID_TIM;
+			pos[1] = 3;
+			pos[2] = 0;
+			pos[3] = dtim_period;
+			pos[4] = 0;
+			return 0;
+		}
+		pos += 2 + pos[1];
+	}
+	return 0;
+}
+
+static int p54_beacon_update(struct ieee80211_hw *dev,
+			struct ieee80211_vif *vif)
 {
 	struct p54_common *priv = dev->priv;
-	struct p54_control_hdr *hdr;
-	struct p54_tx_control_vdcf *vdcf;
+	struct sk_buff *beacon;
+	int ret;
 
-	hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
-
-	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf));
-
-	vdcf = (struct p54_tx_control_vdcf *) hdr->data;
-
-	if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
-		vdcf->slottime = 9;
-		vdcf->magic1 = 0x10;
-		vdcf->magic2 = 0x00;
-	} else {
-		vdcf->slottime = 20;
-		vdcf->magic1 = 0x0a;
-		vdcf->magic2 = 0x06;
+	if (priv->cached_beacon) {
+		p54_tx_cancel(dev, priv->cached_beacon);
+		/* wait for the last beacon the be freed */
+		msleep(10);
 	}
 
-	/* (see prism54/isl_oid.h for further details) */
-	vdcf->frameburst = cpu_to_le16(0);
+	beacon = ieee80211_beacon_get(dev, vif);
+	if (!beacon)
+		return -ENOMEM;
+	ret = p54_beacon_tim(beacon);
+	if (ret)
+		return ret;
+	ret = p54_tx(dev, beacon);
+	if (ret)
+		return ret;
+	priv->cached_beacon = beacon;
+	priv->tsf_high32 = 0;
+	priv->tsf_low32 = 0;
 
-	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0);
+	return 0;
 }
 
 static int p54_start(struct ieee80211_hw *dev)
@@ -1110,34 +1731,30 @@
 	struct p54_common *priv = dev->priv;
 	int err;
 
-	if (!priv->cached_vdcf) {
-		priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf)+
-			priv->tx_hdr_len + sizeof(struct p54_control_hdr),
-			GFP_KERNEL);
-
-		if (!priv->cached_vdcf)
-			return -ENOMEM;
-	}
-
-	if (!priv->cached_stats) {
-		priv->cached_stats = kzalloc(sizeof(struct p54_statistics) +
-			priv->tx_hdr_len + sizeof(struct p54_control_hdr),
-			GFP_KERNEL);
-
-		if (!priv->cached_stats) {
-			kfree(priv->cached_vdcf);
-			priv->cached_vdcf = NULL;
-			return -ENOMEM;
-		}
-	}
-
+	mutex_lock(&priv->conf_mutex);
 	err = priv->open(dev);
-	if (!err)
-		priv->mode = NL80211_IFTYPE_MONITOR;
+	if (err)
+		goto out;
+	P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
+	P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
+	P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
+	P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
+	err = p54_set_edcf(dev);
+	if (err)
+		goto out;
 
-	p54_init_vdcf(dev);
+	memset(priv->bssid, ~0, ETH_ALEN);
+	priv->mode = NL80211_IFTYPE_MONITOR;
+	err = p54_setup_mac(dev);
+	if (err) {
+		priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+		goto out;
+	}
 
-	mod_timer(&priv->stats_timer, jiffies + HZ);
+	queue_delayed_work(dev->workqueue, &priv->work, 0);
+
+out:
+	mutex_unlock(&priv->conf_mutex);
 	return err;
 }
 
@@ -1146,12 +1763,18 @@
 	struct p54_common *priv = dev->priv;
 	struct sk_buff *skb;
 
-	del_timer(&priv->stats_timer);
+	mutex_lock(&priv->conf_mutex);
+	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+	cancel_delayed_work_sync(&priv->work);
+	if (priv->cached_beacon)
+		p54_tx_cancel(dev, priv->cached_beacon);
+
+	priv->stop(dev);
 	while ((skb = skb_dequeue(&priv->tx_queue)))
 		kfree_skb(skb);
-	priv->stop(dev);
+	priv->cached_beacon = NULL;
 	priv->tsf_high32 = priv->tsf_low32 = 0;
-	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+	mutex_unlock(&priv->conf_mutex);
 }
 
 static int p54_add_interface(struct ieee80211_hw *dev,
@@ -1159,32 +1782,28 @@
 {
 	struct p54_common *priv = dev->priv;
 
-	if (priv->mode != NL80211_IFTYPE_MONITOR)
+	mutex_lock(&priv->conf_mutex);
+	if (priv->mode != NL80211_IFTYPE_MONITOR) {
+		mutex_unlock(&priv->conf_mutex);
 		return -EOPNOTSUPP;
+	}
 
 	switch (conf->type) {
 	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_MESH_POINT:
 		priv->mode = conf->type;
 		break;
 	default:
+		mutex_unlock(&priv->conf_mutex);
 		return -EOPNOTSUPP;
 	}
 
 	memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
-
-	p54_set_filter(dev, 0, NULL);
-
-	switch (conf->type) {
-	case NL80211_IFTYPE_STATION:
-		p54_set_filter(dev, 1, NULL);
-		break;
-	default:
-		BUG();	/* impossible */
-		break;
-	}
-
+	p54_setup_mac(dev);
 	p54_set_leds(dev, 1, 0, 0);
-
+	mutex_unlock(&priv->conf_mutex);
 	return 0;
 }
 
@@ -1192,22 +1811,38 @@
 				 struct ieee80211_if_init_conf *conf)
 {
 	struct p54_common *priv = dev->priv;
+
+	mutex_lock(&priv->conf_mutex);
+	if (priv->cached_beacon)
+		p54_tx_cancel(dev, priv->cached_beacon);
 	priv->mode = NL80211_IFTYPE_MONITOR;
 	memset(priv->mac_addr, 0, ETH_ALEN);
-	p54_set_filter(dev, 0, NULL);
+	memset(priv->bssid, 0, ETH_ALEN);
+	p54_setup_mac(dev);
+	mutex_unlock(&priv->conf_mutex);
 }
 
-static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+static int p54_config(struct ieee80211_hw *dev, u32 changed)
 {
 	int ret;
 	struct p54_common *priv = dev->priv;
+	struct ieee80211_conf *conf = &dev->conf;
 
 	mutex_lock(&priv->conf_mutex);
-	priv->rx_antenna = (conf->antenna_sel_rx == 0) ?
-		2 : conf->antenna_sel_tx - 1;
-	priv->output_power = conf->power_level << 2;
-	ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq));
-	p54_set_vdcf(dev);
+	if (changed & IEEE80211_CONF_CHANGE_POWER)
+		priv->output_power = conf->power_level << 2;
+	if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
+		ret = p54_setup_mac(dev);
+		if (ret)
+			goto out;
+	}
+	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+		ret = p54_scan(dev, P54_SCAN_EXIT, 0);
+		if (ret)
+			goto out;
+	}
+
+out:
 	mutex_unlock(&priv->conf_mutex);
 	return ret;
 }
@@ -1217,13 +1852,36 @@
 				struct ieee80211_if_conf *conf)
 {
 	struct p54_common *priv = dev->priv;
+	int ret = 0;
 
 	mutex_lock(&priv->conf_mutex);
-	p54_set_filter(dev, 0, conf->bssid);
-	p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
-	memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+	if (conf->changed & IEEE80211_IFCC_BSSID) {
+		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+		ret = p54_setup_mac(dev);
+		if (ret)
+			goto out;
+	}
+
+	if (conf->changed & IEEE80211_IFCC_BEACON) {
+		ret = p54_scan(dev, P54_SCAN_EXIT, 0);
+		if (ret)
+			goto out;
+		ret = p54_setup_mac(dev);
+		if (ret)
+			goto out;
+		ret = p54_beacon_update(dev, vif);
+		if (ret)
+			goto out;
+		ret = p54_set_edcf(dev);
+		if (ret)
+			goto out;
+	}
+
+	ret = p54_set_leds(dev, 1, !is_multicast_ether_addr(priv->bssid), 0);
+
+out:
 	mutex_unlock(&priv->conf_mutex);
-	return 0;
+	return ret;
 }
 
 static void p54_configure_filter(struct ieee80211_hw *dev,
@@ -1233,94 +1891,78 @@
 {
 	struct p54_common *priv = dev->priv;
 
-	*total_flags &= FIF_BCN_PRBRESP_PROMISC |
-			FIF_PROMISC_IN_BSS |
-			FIF_FCSFAIL;
+	*total_flags &= FIF_PROMISC_IN_BSS |
+			(*total_flags & FIF_PROMISC_IN_BSS) ?
+				FIF_FCSFAIL : 0;
 
 	priv->filter_flags = *total_flags;
 
-	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
-		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
-			p54_set_filter(dev, le16_to_cpu(priv->filter_type),
-				 NULL);
-		else
-			p54_set_filter(dev, le16_to_cpu(priv->filter_type),
-				 priv->bssid);
-	}
-
-	if (changed_flags & FIF_PROMISC_IN_BSS) {
-		if (*total_flags & FIF_PROMISC_IN_BSS)
-			p54_set_filter(dev, le16_to_cpu(priv->filter_type) |
-				0x8, NULL);
-		else
-			p54_set_filter(dev, le16_to_cpu(priv->filter_type) &
-				~0x8, priv->bssid);
-	}
+	if (changed_flags & FIF_PROMISC_IN_BSS)
+		p54_setup_mac(dev);
 }
 
 static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
 		       const struct ieee80211_tx_queue_params *params)
 {
 	struct p54_common *priv = dev->priv;
-	struct p54_tx_control_vdcf *vdcf;
+	int ret;
 
-	vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *)
-		((void *)priv->cached_vdcf + priv->tx_hdr_len))->data);
-
+	mutex_lock(&priv->conf_mutex);
 	if ((params) && !(queue > 4)) {
-		P54_SET_QUEUE(vdcf->queue[queue], params->aifs,
+		P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
 			params->cw_min, params->cw_max, params->txop);
+		ret = p54_set_edcf(dev);
 	} else
-		return -EINVAL;
-
-	p54_set_vdcf(dev);
-
-	return 0;
+		ret = -EINVAL;
+	mutex_unlock(&priv->conf_mutex);
+	return ret;
 }
 
 static int p54_init_xbow_synth(struct ieee80211_hw *dev)
 {
 	struct p54_common *priv = dev->priv;
-	struct p54_control_hdr *hdr;
-	struct p54_tx_control_xbow_synth *xbow;
+	struct sk_buff *skb;
+	struct p54_xbow_synth *xbow;
 
-	hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) +
-		      priv->tx_hdr_len, GFP_KERNEL);
-	if (!hdr)
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow) +
+			    sizeof(struct p54_hdr),
+			    P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
+			    GFP_KERNEL);
+	if (!skb)
 		return -ENOMEM;
 
-	hdr = (void *)hdr + priv->tx_hdr_len;
-	hdr->magic1 = cpu_to_le16(0x8001);
-	hdr->len = cpu_to_le16(sizeof(*xbow));
-	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_XBOW_SYNTH_CFG);
-	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*xbow));
-
-	xbow = (struct p54_tx_control_xbow_synth *) hdr->data;
+	xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
 	xbow->magic1 = cpu_to_le16(0x1);
 	xbow->magic2 = cpu_to_le16(0x2);
 	xbow->freq = cpu_to_le16(5390);
-
-	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*xbow), 1);
-
+	memset(xbow->padding, 0, sizeof(xbow->padding));
+	priv->tx(dev, skb);
 	return 0;
 }
 
-static void p54_statistics_timer(unsigned long data)
+static void p54_work(struct work_struct *work)
 {
-	struct ieee80211_hw *dev = (struct ieee80211_hw *) data;
-	struct p54_common *priv = dev->priv;
-	struct p54_control_hdr *hdr;
-	struct p54_statistics *stats;
+	struct p54_common *priv = container_of(work, struct p54_common,
+					       work.work);
+	struct ieee80211_hw *dev = priv->hw;
+	struct sk_buff *skb;
 
-	BUG_ON(!priv->cached_stats);
+	if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+		return ;
 
-	hdr = (void *)priv->cached_stats + priv->tx_hdr_len;
-	hdr->magic1 = cpu_to_le16(0x8000);
-	hdr->len = cpu_to_le16(sizeof(*stats));
-	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK);
-	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats));
+	/*
+	 * TODO: walk through tx_queue and do the following tasks
+	 * 	1. initiate bursts.
+	 *      2. cancel stuck frames / reset the device if necessary.
+	 */
 
-	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0);
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(struct p54_hdr) +
+			    sizeof(struct p54_statistics),
+			    P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
+	if (!skb)
+		return ;
+
+	priv->tx(dev, skb);
 }
 
 static int p54_get_stats(struct ieee80211_hw *dev,
@@ -1328,17 +1970,7 @@
 {
 	struct p54_common *priv = dev->priv;
 
-	del_timer(&priv->stats_timer);
-	p54_statistics_timer((unsigned long)dev);
-
-	if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) {
-		printk(KERN_ERR "%s: device does not respond!\n",
-			wiphy_name(dev->wiphy));
-		return -EBUSY;
-	}
-
 	memcpy(stats, &priv->stats, sizeof(*stats));
-
 	return 0;
 }
 
@@ -1352,14 +1984,133 @@
 	return 0;
 }
 
+static void p54_bss_info_changed(struct ieee80211_hw *dev,
+				 struct ieee80211_vif *vif,
+				 struct ieee80211_bss_conf *info,
+				 u32 changed)
+{
+	struct p54_common *priv = dev->priv;
+
+	if (changed & BSS_CHANGED_ERP_SLOT) {
+		priv->use_short_slot = info->use_short_slot;
+		p54_set_edcf(dev);
+	}
+	if (changed & BSS_CHANGED_BASIC_RATES) {
+		if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+			priv->basic_rate_mask = (info->basic_rates << 4);
+		else
+			priv->basic_rate_mask = info->basic_rates;
+		p54_setup_mac(dev);
+		if (priv->fw_var >= 0x500)
+			p54_scan(dev, P54_SCAN_EXIT, 0);
+	}
+	if (changed & BSS_CHANGED_ASSOC) {
+		if (info->assoc) {
+			priv->aid = info->aid;
+			priv->wakeup_timer = info->beacon_int *
+					     info->dtim_period * 5;
+			p54_setup_mac(dev);
+		}
+	}
+
+}
+
+static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
+		       const u8 *local_address, const u8 *address,
+		       struct ieee80211_key_conf *key)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *skb;
+	struct p54_keycache *rxkey;
+	u8 algo = 0;
+
+	if (modparam_nohwcrypt)
+		return -EOPNOTSUPP;
+
+	if (cmd == DISABLE_KEY)
+		algo = 0;
+	else {
+		switch (key->alg) {
+		case ALG_TKIP:
+			if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
+			      BR_DESC_PRIV_CAP_TKIP)))
+				return -EOPNOTSUPP;
+			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+			algo = P54_CRYPTO_TKIPMICHAEL;
+			break;
+		case ALG_WEP:
+			if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP))
+				return -EOPNOTSUPP;
+			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+			algo = P54_CRYPTO_WEP;
+			break;
+		case ALG_CCMP:
+			if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP))
+				return -EOPNOTSUPP;
+			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+			algo = P54_CRYPTO_AESCCMP;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	if (key->keyidx > priv->rx_keycache_size) {
+		/*
+		 * The device supports the choosen algorithm, but the firmware
+		 * does not provide enough key slots to store all of them.
+		 * So, incoming frames have to be decoded by the mac80211 stack,
+		 * but we can still offload encryption for outgoing frames.
+		 */
+
+		return 0;
+	}
+
+	mutex_lock(&priv->conf_mutex);
+	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey) +
+			sizeof(struct p54_hdr),	P54_CONTROL_TYPE_RX_KEYCACHE,
+			GFP_ATOMIC);
+	if (!skb) {
+		mutex_unlock(&priv->conf_mutex);
+		return -ENOMEM;
+	}
+
+	/* TODO: some devices have 4 more free slots for rx keys */
+	rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
+	rxkey->entry = key->keyidx;
+	rxkey->key_id = key->keyidx;
+	rxkey->key_type = algo;
+	if (address)
+		memcpy(rxkey->mac, address, ETH_ALEN);
+	else
+		memset(rxkey->mac, ~0, ETH_ALEN);
+	if (key->alg != ALG_TKIP) {
+		rxkey->key_len = min((u8)16, key->keylen);
+		memcpy(rxkey->key, key->key, rxkey->key_len);
+	} else {
+		rxkey->key_len = 24;
+		memcpy(rxkey->key, key->key, 16);
+		memcpy(&(rxkey->key[16]), &(key->key
+			[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
+	}
+
+	priv->tx(dev, skb);
+	mutex_unlock(&priv->conf_mutex);
+	return 0;
+}
+
 static const struct ieee80211_ops p54_ops = {
 	.tx			= p54_tx,
 	.start			= p54_start,
 	.stop			= p54_stop,
 	.add_interface		= p54_add_interface,
 	.remove_interface	= p54_remove_interface,
+	.set_tim		= p54_set_tim,
+	.sta_notify		= p54_sta_notify,
+	.set_key		= p54_set_key,
 	.config			= p54_config,
 	.config_interface	= p54_config_interface,
+	.bss_info_changed	= p54_bss_info_changed,
 	.configure_filter	= p54_configure_filter,
 	.conf_tx		= p54_conf_tx,
 	.get_stats		= p54_get_stats,
@@ -1376,32 +2127,43 @@
 		return NULL;
 
 	priv = dev->priv;
+	priv->hw = dev;
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+	priv->basic_rate_mask = 0x15f;
 	skb_queue_head_init(&priv->tx_queue);
-	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
-		     IEEE80211_HW_RX_INCLUDES_FCS |
+	dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
 		     IEEE80211_HW_SIGNAL_DBM |
 		     IEEE80211_HW_NOISE_DBM;
 
-	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+				      BIT(NL80211_IFTYPE_ADHOC) |
+				      BIT(NL80211_IFTYPE_AP) |
+				      BIT(NL80211_IFTYPE_MESH_POINT);
 
 	dev->channel_change_time = 1000;	/* TODO: find actual value */
-
-	priv->tx_stats[0].limit = 1;
-	priv->tx_stats[1].limit = 1;
-	priv->tx_stats[2].limit = 1;
-	priv->tx_stats[3].limit = 1;
-	priv->tx_stats[4].limit = 5;
+	priv->tx_stats[0].limit = 1;		/* Beacon queue */
+	priv->tx_stats[1].limit = 1;		/* Probe queue for HW scan */
+	priv->tx_stats[2].limit = 3;		/* queue for MLMEs */
+	priv->tx_stats[3].limit = 3;		/* Broadcast / MC queue */
+	priv->tx_stats[4].limit = 5;		/* Data */
 	dev->queues = 1;
 	priv->noise = -94;
-	dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
-				 sizeof(struct p54_tx_control_allocdata);
+	/*
+	 * We support at most 8 tries no matter which rate they're at,
+	 * we cannot support max_rates * max_rate_tries as we set it
+	 * here, but setting it correctly to 4/2 or so would limit us
+	 * artificially if the RC algorithm wants just two rates, so
+	 * let's say 4/7, we'll redistribute it at TX time, see the
+	 * comments there.
+	 */
+	dev->max_rates = 4;
+	dev->max_rate_tries = 7;
+	dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
+				 sizeof(struct p54_tx_data);
 
 	mutex_init(&priv->conf_mutex);
 	init_completion(&priv->eeprom_comp);
-	init_completion(&priv->stats_comp);
-	setup_timer(&priv->stats_timer, p54_statistics_timer,
-		(unsigned long)dev);
+	INIT_DELAYED_WORK(&priv->work, p54_work);
 
 	return dev;
 }
@@ -1410,11 +2172,9 @@
 void p54_free_common(struct ieee80211_hw *dev)
 {
 	struct p54_common *priv = dev->priv;
-	kfree(priv->cached_stats);
 	kfree(priv->iq_autocal);
 	kfree(priv->output_limit);
 	kfree(priv->curve_data);
-	kfree(priv->cached_vdcf);
 }
 EXPORT_SYMBOL_GPL(p54_free_common);
 
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
index 2fa994c..f5729de 100644
--- a/drivers/net/wireless/p54/p54common.h
+++ b/drivers/net/wireless/p54/p54common.h
@@ -7,8 +7,12 @@
  * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
  * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
  *
- * Based on the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ *   Copyright (C) 2007 Conexant Systems, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -19,9 +23,24 @@
 	__le32 code;
 	__le32 len;
 	u32 data[10];
-	__le16 rx_mtu;
 } __attribute__((packed));
 
+#define PDR_SYNTH_FRONTEND_MASK		0x0007
+#define PDR_SYNTH_IQ_CAL_MASK		0x0018
+#define PDR_SYNTH_IQ_CAL_PA_DETECTOR	0x0000
+#define PDR_SYNTH_IQ_CAL_DISABLED	0x0008
+#define PDR_SYNTH_IQ_CAL_ZIF		0x0010
+#define PDR_SYNTH_FAA_SWITCH_MASK	0x0020
+#define PDR_SYNTH_FAA_SWITCH_ENABLED	0x0001
+#define PDR_SYNTH_24_GHZ_MASK		0x0040
+#define PDR_SYNTH_24_GHZ_DISABLED	0x0040
+#define PDR_SYNTH_5_GHZ_MASK		0x0080
+#define PDR_SYNTH_5_GHZ_DISABLED	0x0080
+#define PDR_SYNTH_RX_DIV_MASK		0x0100
+#define PDR_SYNTH_RX_DIV_SUPPORTED	0x0100
+#define PDR_SYNTH_TX_DIV_MASK		0x0200
+#define PDR_SYNTH_TX_DIV_SUPPORTED	0x0200
+
 struct bootrec_exp_if {
 	__le16 role;
 	__le16 if_id;
@@ -30,6 +49,13 @@
 	__le16 top_compat;
 } __attribute__((packed));
 
+#define BR_DESC_PRIV_CAP_WEP		BIT(0)
+#define BR_DESC_PRIV_CAP_TKIP		BIT(1)
+#define BR_DESC_PRIV_CAP_MICHAEL	BIT(2)
+#define BR_DESC_PRIV_CAP_CCX_CP		BIT(3)
+#define BR_DESC_PRIV_CAP_CCX_MIC	BIT(4)
+#define BR_DESC_PRIV_CAP_AESCCMP	BIT(5)
+
 struct bootrec_desc {
 	__le16 modes;
 	__le16 flags;
@@ -37,8 +63,15 @@
 	__le32 rx_end;
 	u8 headroom;
 	u8 tailroom;
-	u8 unimportant[6];
+	u8 tx_queues;
+	u8 tx_depth;
+	u8 privacy_caps;
+	u8 rx_keycache_size;
+	u8 time_size;
+	u8 padding;
 	u8 rates[16];
+	u8 padding2[4];
+	__le16 rx_mtu;
 } __attribute__((packed));
 
 #define BR_CODE_MIN			0x80000000
@@ -51,6 +84,31 @@
 #define BR_CODE_END_OF_BRA		0xFF0000FF
 #define LEGACY_BR_CODE_END_OF_BRA	0xFFFFFFFF
 
+#define P54_HDR_FLAG_DATA_ALIGN		BIT(14)
+#define P54_HDR_FLAG_DATA_OUT_PROMISC	BIT(0)
+#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
+#define P54_HDR_FLAG_DATA_OUT_SEQNR	BIT(2)
+#define P54_HDR_FLAG_DATA_OUT_BIT3	BIT(3)
+#define P54_HDR_FLAG_DATA_OUT_BURST	BIT(4)
+#define P54_HDR_FLAG_DATA_OUT_NOCANCEL	BIT(5)
+#define P54_HDR_FLAG_DATA_OUT_CLEARTIM	BIT(6)
+#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE	BIT(7)
+#define P54_HDR_FLAG_DATA_OUT_COMPRESS	BIT(8)
+#define P54_HDR_FLAG_DATA_OUT_CONCAT	BIT(9)
+#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10)
+#define P54_HDR_FLAG_DATA_OUT_WAITEOSP	BIT(11)
+
+#define P54_HDR_FLAG_DATA_IN_FCS_GOOD	BIT(0)
+#define P54_HDR_FLAG_DATA_IN_MATCH_MAC	BIT(1)
+#define P54_HDR_FLAG_DATA_IN_MCBC	BIT(2)
+#define P54_HDR_FLAG_DATA_IN_BEACON	BIT(3)
+#define P54_HDR_FLAG_DATA_IN_MATCH_BSS	BIT(4)
+#define P54_HDR_FLAG_DATA_IN_BCAST_BSS	BIT(5)
+#define P54_HDR_FLAG_DATA_IN_DATA	BIT(6)
+#define P54_HDR_FLAG_DATA_IN_TRUNCATED	BIT(7)
+#define P54_HDR_FLAG_DATA_IN_BIT8	BIT(8)
+#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9)
+
 /* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
 
 struct pda_entry {
@@ -117,6 +175,11 @@
 	u8 data[0];
 } __attribute__ ((packed));
 
+struct pda_rssi_cal_entry {
+	__le16 mul;
+	__le16 add;
+} __attribute__ ((packed));
+
 /*
  * this defines the PDR codes used to build PDAs as defined in document
  * number 553155. The current implementation mirrors version 1.1 of the
@@ -165,6 +228,19 @@
 #define PDR_BASEBAND_REGISTERS			0x8000
 #define PDR_PER_CHANNEL_BASEBAND_REGISTERS	0x8001
 
+/* PDR definitions for default country & country list */
+#define PDR_COUNTRY_CERT_CODE		0x80
+#define PDR_COUNTRY_CERT_CODE_REAL	0x00
+#define PDR_COUNTRY_CERT_CODE_PSEUDO	0x80
+#define PDR_COUNTRY_CERT_BAND		0x40
+#define PDR_COUNTRY_CERT_BAND_2GHZ	0x00
+#define PDR_COUNTRY_CERT_BAND_5GHZ	0x40
+#define PDR_COUNTRY_CERT_IODOOR		0x30
+#define PDR_COUNTRY_CERT_IODOOR_BOTH	0x00
+#define PDR_COUNTRY_CERT_IODOOR_INDOOR	0x20
+#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR	0x30
+#define PDR_COUNTRY_CERT_INDEX		0x0F
+
 /* stored in skb->cb */
 struct memrecord {
 	u32 start_addr;
@@ -172,41 +248,108 @@
 };
 
 struct p54_eeprom_lm86 {
-	__le16 offset;
-	__le16 len;
-	u8 data[0];
+	union {
+		struct {
+			__le16 offset;
+			__le16 len;
+			u8 data[0];
+		} v1;
+		struct {
+			__le32 offset;
+			__le16 len;
+			u8 magic2;
+			u8 pad;
+			u8 magic[4];
+			u8 data[0];
+		} v2;
+	}  __attribute__ ((packed));
 } __attribute__ ((packed));
 
-struct p54_rx_hdr {
-	__le16 magic;
+enum p54_rx_decrypt_status {
+	P54_DECRYPT_NONE = 0,
+	P54_DECRYPT_OK,
+	P54_DECRYPT_NOKEY,
+	P54_DECRYPT_NOMICHAEL,
+	P54_DECRYPT_NOCKIPMIC,
+	P54_DECRYPT_FAIL_WEP,
+	P54_DECRYPT_FAIL_TKIP,
+	P54_DECRYPT_FAIL_MICHAEL,
+	P54_DECRYPT_FAIL_CKIPKP,
+	P54_DECRYPT_FAIL_CKIPMIC,
+	P54_DECRYPT_FAIL_AESCCMP
+};
+
+struct p54_rx_data {
+	__le16 flags;
 	__le16 len;
 	__le16 freq;
 	u8 antenna;
 	u8 rate;
 	u8 rssi;
 	u8 quality;
-	u16 unknown2;
+	u8 decrypt_status;
+	u8 rssi_raw;
 	__le32 tsf32;
 	__le32 unalloc0;
 	u8 align[0];
 } __attribute__ ((packed));
 
-struct p54_frame_sent_hdr {
-	u8 status;
-	u8 retries;
-	__le16 ack_rssi;
-	__le16 seq;
-	u16 rate;
+enum p54_trap_type {
+	P54_TRAP_SCAN = 0,
+	P54_TRAP_TIMER,
+	P54_TRAP_BEACON_TX,
+	P54_TRAP_FAA_RADIO_ON,
+	P54_TRAP_FAA_RADIO_OFF,
+	P54_TRAP_RADAR,
+	P54_TRAP_NO_BEACON,
+	P54_TRAP_TBTT,
+	P54_TRAP_SCO_ENTER,
+	P54_TRAP_SCO_EXIT
+};
+
+struct p54_trap {
+	__le16 event;
+	__le16 frequency;
 } __attribute__ ((packed));
 
-struct p54_tx_control_allocdata {
+enum p54_frame_sent_status {
+	P54_TX_OK = 0,
+	P54_TX_FAILED,
+	P54_TX_PSM,
+	P54_TX_PSM_CANCELLED = 4
+};
+
+struct p54_frame_sent {
+	u8 status;
+	u8 tries;
+	u8 ack_rssi;
+	u8 quality;
+	__le16 seq;
+	u8 antenna;
+	u8 padding;
+} __attribute__ ((packed));
+
+enum  p54_tx_data_crypt {
+	P54_CRYPTO_NONE = 0,
+	P54_CRYPTO_WEP,
+	P54_CRYPTO_TKIP,
+	P54_CRYPTO_TKIPMICHAEL,
+	P54_CRYPTO_CCX_WEPMIC,
+	P54_CRYPTO_CCX_KPMIC,
+	P54_CRYPTO_CCX_KP,
+	P54_CRYPTO_AESCCMP
+};
+
+struct p54_tx_data {
 	u8 rateset[8];
-	u8 unalloc0[2];
+	u8 rts_rate_idx;
+	u8 crypt_offset;
 	u8 key_type;
 	u8 key_len;
 	u8 key[16];
 	u8 hw_queue;
-	u8 unalloc1[9];
+	u8 backlog;
+	__le16 durations[4];
 	u8 tx_antenna;
 	u8 output_power;
 	u8 cts_rate;
@@ -214,8 +357,23 @@
 	u8 align[0];
 } __attribute__ ((packed));
 
-struct p54_tx_control_filter {
-	__le16 filter_type;
+/* unit is ms */
+#define P54_TX_FRAME_LIFETIME 2000
+#define P54_TX_TIMEOUT 4000
+#define P54_STATISTICS_UPDATE 5000
+
+#define P54_FILTER_TYPE_NONE		0
+#define P54_FILTER_TYPE_STATION		BIT(0)
+#define P54_FILTER_TYPE_IBSS		BIT(1)
+#define P54_FILTER_TYPE_AP		BIT(2)
+#define P54_FILTER_TYPE_TRANSPARENT	BIT(3)
+#define P54_FILTER_TYPE_PROMISCUOUS	BIT(4)
+#define P54_FILTER_TYPE_HIBERNATE	BIT(5)
+#define P54_FILTER_TYPE_NOACK		BIT(6)
+#define P54_FILTER_TYPE_RX_DISABLED	BIT(7)
+
+struct p54_setup_mac {
+	__le16 mac_mode;
 	u8 mac_addr[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
 	u8 rx_antenna;
@@ -235,17 +393,29 @@
 			__le16 max_rx;
 			__le16 rxhw;
 			__le16 timer;
-			__le16 unalloc0;
-			__le32 unalloc1;
+			__le16 truncate;
+			__le32 basic_rate_mask;
+			u8 sbss_offset;
+			u8 mcast_window;
+			u8 rx_rssi_threshold;
+			u8 rx_ed_threshold;
+			__le32 ref_clock;
+			__le16 lpf_bandwidth;
+			__le16 osc_start_delay;
 		} v2 __attribute__ ((packed));
 	} __attribute__ ((packed));
 } __attribute__ ((packed));
 
-#define P54_TX_CONTROL_FILTER_V1_LEN (sizeof(struct p54_tx_control_filter))
-#define P54_TX_CONTROL_FILTER_V2_LEN (sizeof(struct p54_tx_control_filter)-8)
+#define P54_SETUP_V1_LEN 40
+#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
 
-struct p54_tx_control_channel {
-	__le16 flags;
+#define P54_SCAN_EXIT	BIT(0)
+#define P54_SCAN_TRAP	BIT(1)
+#define P54_SCAN_ACTIVE BIT(2)
+#define P54_SCAN_FILTER BIT(3)
+
+struct p54_scan {
+	__le16 mode;
 	__le16 dwell;
 	u8 padding1[20];
 	struct pda_iq_autocal_entry iq_autocal;
@@ -261,45 +431,35 @@
 	u8 dup_16qam;
 	u8 dup_64qam;
 	union {
-		struct {
-			__le16 rssical_mul;
-			__le16 rssical_add;
-		} v1 __attribute__ ((packed));
+		struct pda_rssi_cal_entry v1_rssi;
 
 		struct {
 			__le32 basic_rate_mask;
-			 u8 rts_rates[8];
-			__le16 rssical_mul;
-			__le16 rssical_add;
+			u8 rts_rates[8];
+			struct pda_rssi_cal_entry rssi;
 		} v2 __attribute__ ((packed));
 	} __attribute__ ((packed));
 } __attribute__ ((packed));
 
-#define P54_TX_CONTROL_CHANNEL_V1_LEN (sizeof(struct p54_tx_control_channel)-12)
-#define P54_TX_CONTROL_CHANNEL_V2_LEN (sizeof(struct p54_tx_control_channel))
+#define P54_SCAN_V1_LEN 0x70
+#define P54_SCAN_V2_LEN 0x7c
 
-struct p54_tx_control_led {
+struct p54_led {
 	__le16 mode;
 	__le16 led_temporary;
 	__le16 led_permanent;
 	__le16 duration;
 } __attribute__ ((packed));
 
-struct p54_tx_vdcf_queues {
-	__le16 aifs;
-	__le16 cwmin;
-	__le16 cwmax;
-	__le16 txop;
-} __attribute__ ((packed));
-
-struct p54_tx_control_vdcf {
-	u8 padding;
+struct p54_edcf {
+	u8 flags;
 	u8 slottime;
-	u8 magic1;
-	u8 magic2;
-	struct p54_tx_vdcf_queues queue[8];
-	u8 pad2[4];
+	u8 sifs;
+	u8 eofpad;
+	struct p54_edcf_queue_param queue[8];
+	u8 mapping[4];
 	__le16 frameburst;
+	__le16 round_trip_delay;
 } __attribute__ ((packed));
 
 struct p54_statistics {
@@ -312,14 +472,103 @@
 	__le32 tsf32;
 	__le32 airtime;
 	__le32 noise;
-	__le32 unkn[10]; /* CCE / CCA / RADAR */
+	__le32 sample_noise[8];
+	__le32 sample_cca;
+	__le32 sample_tx;
 } __attribute__ ((packed));
 
-struct p54_tx_control_xbow_synth {
+struct p54_xbow_synth {
 	__le16 magic1;
 	__le16 magic2;
 	__le16 freq;
 	u32 padding[5];
 } __attribute__ ((packed));
 
+struct p54_timer {
+	__le32 interval;
+} __attribute__ ((packed));
+
+struct p54_keycache {
+	u8 entry;
+	u8 key_id;
+	u8 mac[ETH_ALEN];
+	u8 padding[2];
+	u8 key_type;
+	u8 key_len;
+	u8 key[24];
+} __attribute__ ((packed));
+
+struct p54_burst {
+	u8 flags;
+	u8 queue;
+	u8 backlog;
+	u8 pad;
+	__le16 durations[32];
+} __attribute__ ((packed));
+
+struct p54_psm_interval {
+	__le16 interval;
+	__le16 periods;
+} __attribute__ ((packed));
+
+#define P54_PSM				BIT(0)
+#define P54_PSM_DTIM			BIT(1)
+#define P54_PSM_MCBC			BIT(2)
+#define P54_PSM_CHECKSUM		BIT(3)
+#define P54_PSM_SKIP_MORE_DATA		BIT(4)
+#define P54_PSM_BEACON_TIMEOUT		BIT(5)
+#define P54_PSM_HFOSLEEP		BIT(6)
+#define P54_PSM_AUTOSWITCH_SLEEP	BIT(7)
+#define P54_PSM_LPIT			BIT(8)
+#define P54_PSM_BF_UCAST_SKIP		BIT(9)
+#define P54_PSM_BF_MCAST_SKIP		BIT(10)
+
+struct p54_psm {
+	__le16 mode;
+	__le16 aid;
+	struct p54_psm_interval intervals[4];
+	u8 beacon_rssi_skip_max;
+	u8 rssi_delta_threshold;
+	u8 nr;
+	u8 exclude[1];
+} __attribute__ ((packed));
+
+#define MC_FILTER_ADDRESS_NUM 4
+
+struct p54_group_address_table {
+	__le16 filter_enable;
+	__le16 num_address;
+	u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
+} __attribute__ ((packed));
+
+struct p54_txcancel {
+	__le32 req_id;
+} __attribute__ ((packed));
+
+struct p54_sta_unlock {
+	u8 addr[ETH_ALEN];
+	u16 padding;
+} __attribute__ ((packed));
+
+#define P54_TIM_CLEAR BIT(15)
+struct p54_tim {
+	u8 count;
+	u8 padding[3];
+	__le16 entry[8];
+} __attribute__ ((packed));
+
+struct p54_cce_quiet {
+	__le32 period;
+} __attribute__ ((packed));
+
+struct p54_bt_balancer {
+	__le16 prio_thresh;
+	__le16 acl_thresh;
+} __attribute__ ((packed));
+
+struct p54_arp_table {
+	__le16 filter_enable;
+	u8 ipv4_addr[4];
+} __attribute__ ((packed));
+
 #endif /* P54COMMON_H */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 88b3cad..aa367a0 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -28,6 +28,7 @@
 MODULE_DESCRIPTION("Prism54 PCI wireless driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("prism54pci");
+MODULE_FIRMWARE("isl3886pci");
 
 static struct pci_device_id p54p_table[] __devinitdata = {
 	/* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
@@ -46,7 +47,6 @@
 static int p54p_upload_firmware(struct ieee80211_hw *dev)
 {
 	struct p54p_priv *priv = dev->priv;
-	const struct firmware *fw_entry = NULL;
 	__le32 reg;
 	int err;
 	__le32 *data;
@@ -72,21 +72,15 @@
 	P54P_WRITE(ctrl_stat, reg);
 	wmb();
 
-	err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
-	if (err) {
-		printk(KERN_ERR "%s (p54pci): cannot find firmware "
-		       "(isl3886)\n", pci_name(priv->pdev));
-		return err;
-	}
+	/* wait for the firmware to reset properly */
+	mdelay(10);
 
-	err = p54_parse_firmware(dev, fw_entry);
-	if (err) {
-		release_firmware(fw_entry);
+	err = p54_parse_firmware(dev, priv->firmware);
+	if (err)
 		return err;
-	}
 
-	data = (__le32 *) fw_entry->data;
-	remains = fw_entry->size;
+	data = (__le32 *) priv->firmware->data;
+	remains = priv->firmware->size;
 	device_addr = ISL38XX_DEV_FIRMWARE_ADDR;
 	while (remains) {
 		u32 i = 0;
@@ -104,8 +98,6 @@
 		P54P_READ(int_enable);
 	}
 
-	release_firmware(fw_entry);
-
 	reg = P54P_READ(ctrl_stat);
 	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
 	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
@@ -235,7 +227,9 @@
 
 	while (i != idx) {
 		desc = &ring[i];
-		kfree(tx_buf[i]);
+		if (tx_buf[i])
+			if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i]))
+				p54_free_skb(dev, tx_buf[i]);
 		tx_buf[i] = NULL;
 
 		pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
@@ -306,8 +300,7 @@
 	return reg ? IRQ_HANDLED : IRQ_NONE;
 }
 
-static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
-		    size_t len, int free_on_tx)
+static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct p54p_priv *priv = dev->priv;
 	struct p54p_ring_control *ring_control = priv->ring_control;
@@ -322,28 +315,21 @@
 	idx = le32_to_cpu(ring_control->host_idx[1]);
 	i = idx % ARRAY_SIZE(ring_control->tx_data);
 
-	mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE);
+	priv->tx_buf_data[i] = skb;
+	mapping = pci_map_single(priv->pdev, skb->data, skb->len,
+				 PCI_DMA_TODEVICE);
 	desc = &ring_control->tx_data[i];
 	desc->host_addr = cpu_to_le32(mapping);
-	desc->device_addr = data->req_id;
-	desc->len = cpu_to_le16(len);
+	desc->device_addr = ((struct p54_hdr *)skb->data)->req_id;
+	desc->len = cpu_to_le16(skb->len);
 	desc->flags = 0;
 
 	wmb();
 	ring_control->host_idx[1] = cpu_to_le32(idx + 1);
-
-	if (free_on_tx)
-		priv->tx_buf_data[i] = data;
-
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
 	P54P_READ(dev_int);
-
-	/* FIXME: unlikely to happen because the device usually runs out of
-	   memory before we fill the ring up, but we can make it impossible */
-	if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2)
-		printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy));
 }
 
 static void p54p_stop(struct ieee80211_hw *dev)
@@ -393,7 +379,7 @@
 					 le16_to_cpu(desc->len),
 					 PCI_DMA_TODEVICE);
 
-		kfree(priv->tx_buf_data[i]);
+		p54_free_skb(dev, priv->tx_buf_data[i]);
 		priv->tx_buf_data[i] = NULL;
 	}
 
@@ -405,7 +391,7 @@
 					 le16_to_cpu(desc->len),
 					 PCI_DMA_TODEVICE);
 
-		kfree(priv->tx_buf_mgmt[i]);
+		p54_free_skb(dev, priv->tx_buf_mgmt[i]);
 		priv->tx_buf_mgmt[i] = NULL;
 	}
 
@@ -481,7 +467,6 @@
 	struct ieee80211_hw *dev;
 	unsigned long mem_addr, mem_len;
 	int err;
-	DECLARE_MAC_BUF(mac);
 
 	err = pci_enable_device(pdev);
 	if (err) {
@@ -495,15 +480,14 @@
 	if (mem_len < sizeof(struct p54p_csr)) {
 		printk(KERN_ERR "%s (p54pci): Too short PCI resources\n",
 		       pci_name(pdev));
-		pci_disable_device(pdev);
-		return err;
+		goto err_disable_dev;
 	}
 
 	err = pci_request_regions(pdev, "p54pci");
 	if (err) {
 		printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n",
 		       pci_name(pdev));
-		return err;
+		goto err_disable_dev;
 	}
 
 	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
@@ -556,6 +540,17 @@
 	spin_lock_init(&priv->lock);
 	tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev);
 
+	err = request_firmware(&priv->firmware, "isl3886pci",
+			       &priv->pdev->dev);
+	if (err) {
+		printk(KERN_ERR "%s (p54pci): cannot find firmware "
+			"(isl3886pci)\n", pci_name(priv->pdev));
+		err = request_firmware(&priv->firmware, "isl3886",
+				       &priv->pdev->dev);
+		if (err)
+			goto err_free_common;
+	}
+
 	err = p54p_open(dev);
 	if (err)
 		goto err_free_common;
@@ -574,6 +569,7 @@
 	return 0;
 
  err_free_common:
+	release_firmware(priv->firmware);
 	p54_free_common(dev);
 	pci_free_consistent(pdev, sizeof(*priv->ring_control),
 			    priv->ring_control, priv->ring_control_dma);
@@ -587,6 +583,7 @@
 
  err_free_reg:
 	pci_release_regions(pdev);
+ err_disable_dev:
 	pci_disable_device(pdev);
 	return err;
 }
@@ -601,6 +598,7 @@
 
 	ieee80211_unregister_hw(dev);
 	priv = dev->priv;
+	release_firmware(priv->firmware);
 	pci_free_consistent(pdev, sizeof(*priv->ring_control),
 			    priv->ring_control, priv->ring_control_dma);
 	p54_free_common(dev);
diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h
index 4a67780..fbb6839 100644
--- a/drivers/net/wireless/p54/p54pci.h
+++ b/drivers/net/wireless/p54/p54pci.h
@@ -93,7 +93,7 @@
 	struct pci_dev *pdev;
 	struct p54p_csr __iomem *map;
 	struct tasklet_struct rx_tasklet;
-
+	const struct firmware *firmware;
 	spinlock_t lock;
 	struct p54p_ring_control *ring_control;
 	dma_addr_t ring_control_dma;
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 75d749b..c44a200 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -28,6 +28,8 @@
 MODULE_DESCRIPTION("Prism54 USB wireless driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("prism54usb");
+MODULE_FIRMWARE("isl3886usb");
+MODULE_FIRMWARE("isl3887usb");
 
 static struct usb_device_id p54u_table[] __devinitdata = {
 	/* Version 1 devices (pci chip + net2280) */
@@ -84,13 +86,13 @@
 	struct ieee80211_hw *dev = info->dev;
 	struct p54u_priv *priv = dev->priv;
 
+	skb_unlink(skb, &priv->rx_queue);
+
 	if (unlikely(urb->status)) {
-		info->urb = NULL;
-		usb_free_urb(urb);
+		dev_kfree_skb_irq(skb);
 		return;
 	}
 
-	skb_unlink(skb, &priv->rx_queue);
 	skb_put(skb, urb->actual_length);
 
 	if (priv->hw_type == P54U_NET2280)
@@ -103,7 +105,6 @@
 	if (p54_rx(dev, skb)) {
 		skb = dev_alloc_skb(priv->common.rx_mtu + 32);
 		if (unlikely(!skb)) {
-			usb_free_urb(urb);
 			/* TODO check rx queue length and refill *somewhere* */
 			return;
 		}
@@ -113,7 +114,6 @@
 		info->dev = dev;
 		urb->transfer_buffer = skb_tail_pointer(skb);
 		urb->context = skb;
-		skb_queue_tail(&priv->rx_queue, skb);
 	} else {
 		if (priv->hw_type == P54U_NET2280)
 			skb_push(skb, priv->common.tx_hdr_len);
@@ -128,40 +128,56 @@
 			WARN_ON(1);
 			urb->transfer_buffer = skb_tail_pointer(skb);
 		}
-
-		skb_queue_tail(&priv->rx_queue, skb);
 	}
-
-	usb_submit_urb(urb, GFP_ATOMIC);
+	skb_queue_tail(&priv->rx_queue, skb);
+	usb_anchor_urb(urb, &priv->submitted);
+	if (usb_submit_urb(urb, GFP_ATOMIC)) {
+		skb_unlink(skb, &priv->rx_queue);
+		usb_unanchor_urb(urb);
+		dev_kfree_skb_irq(skb);
+	}
 }
 
 static void p54u_tx_cb(struct urb *urb)
 {
-	usb_free_urb(urb);
+	struct sk_buff *skb = urb->context;
+	struct ieee80211_hw *dev = (struct ieee80211_hw *)
+		usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+	struct p54u_priv *priv = dev->priv;
+
+	skb_pull(skb, priv->common.tx_hdr_len);
+	if (FREE_AFTER_TX(skb))
+		p54_free_skb(dev, skb);
 }
 
-static void p54u_tx_free_cb(struct urb *urb)
+static void p54u_tx_dummy_cb(struct urb *urb) { }
+
+static void p54u_free_urbs(struct ieee80211_hw *dev)
 {
-	kfree(urb->transfer_buffer);
-	usb_free_urb(urb);
+	struct p54u_priv *priv = dev->priv;
+	usb_kill_anchored_urbs(&priv->submitted);
 }
 
 static int p54u_init_urbs(struct ieee80211_hw *dev)
 {
 	struct p54u_priv *priv = dev->priv;
-	struct urb *entry;
+	struct urb *entry = NULL;
 	struct sk_buff *skb;
 	struct p54u_rx_info *info;
+	int ret = 0;
 
 	while (skb_queue_len(&priv->rx_queue) < 32) {
 		skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
-		if (!skb)
-			break;
+		if (!skb) {
+			ret = -ENOMEM;
+			goto err;
+		}
 		entry = usb_alloc_urb(0, GFP_KERNEL);
 		if (!entry) {
-			kfree_skb(skb);
-			break;
+			ret = -ENOMEM;
+			goto err;
 		}
+
 		usb_fill_bulk_urb(entry, priv->udev,
 				  usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
 				  skb_tail_pointer(skb),
@@ -170,33 +186,32 @@
 		info->urb = entry;
 		info->dev = dev;
 		skb_queue_tail(&priv->rx_queue, skb);
-		usb_submit_urb(entry, GFP_KERNEL);
+
+		usb_anchor_urb(entry, &priv->submitted);
+		ret = usb_submit_urb(entry, GFP_KERNEL);
+		if (ret) {
+			skb_unlink(skb, &priv->rx_queue);
+			usb_unanchor_urb(entry);
+			goto err;
+		}
+		usb_free_urb(entry);
+		entry = NULL;
 	}
 
 	return 0;
+
+ err:
+	usb_free_urb(entry);
+	kfree_skb(skb);
+	p54u_free_urbs(dev);
+	return ret;
 }
 
-static void p54u_free_urbs(struct ieee80211_hw *dev)
-{
-	struct p54u_priv *priv = dev->priv;
-	struct p54u_rx_info *info;
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&priv->rx_queue))) {
-		info = (struct p54u_rx_info *) skb->cb;
-		if (!info->urb)
-			continue;
-
-		usb_kill_urb(info->urb);
-		kfree_skb(skb);
-	}
-}
-
-static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data,
-			 size_t len, int free_on_tx)
+static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct p54u_priv *priv = dev->priv;
 	struct urb *addr_urb, *data_urb;
+	int err = 0;
 
 	addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!addr_urb)
@@ -209,59 +224,85 @@
 	}
 
 	usb_fill_bulk_urb(addr_urb, priv->udev,
-		usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id,
-		sizeof(data->req_id), p54u_tx_cb, dev);
+			  usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
+			  &((struct p54_hdr *)skb->data)->req_id, 4,
+			  p54u_tx_dummy_cb, dev);
 	usb_fill_bulk_urb(data_urb, priv->udev,
-		usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len,
-		free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
+			  usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
+			  skb->data, skb->len, p54u_tx_cb, skb);
 
-	usb_submit_urb(addr_urb, GFP_ATOMIC);
-	usb_submit_urb(data_urb, GFP_ATOMIC);
+	usb_anchor_urb(addr_urb, &priv->submitted);
+	err = usb_submit_urb(addr_urb, GFP_ATOMIC);
+	if (err) {
+		usb_unanchor_urb(addr_urb);
+		goto out;
+	}
+
+	usb_anchor_urb(addr_urb, &priv->submitted);
+	err = usb_submit_urb(data_urb, GFP_ATOMIC);
+	if (err)
+		usb_unanchor_urb(data_urb);
+
+ out:
+	usb_free_urb(addr_urb);
+	usb_free_urb(data_urb);
+
+	if (err)
+		p54_free_skb(dev, skb);
 }
 
-static __le32 p54u_lm87_chksum(const u32 *data, size_t length)
+static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
 {
 	u32 chk = 0;
 
 	length >>= 2;
 	while (length--) {
-		chk ^= *data++;
+		chk ^= le32_to_cpu(*data++);
 		chk = (chk >> 5) ^ (chk << 3);
 	}
 
 	return cpu_to_le32(chk);
 }
 
-static void p54u_tx_lm87(struct ieee80211_hw *dev,
-			 struct p54_control_hdr *data,
-			 size_t len, int free_on_tx)
+static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct p54u_priv *priv = dev->priv;
 	struct urb *data_urb;
-	struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr);
+	struct lm87_tx_hdr *hdr;
+	__le32 checksum;
+	__le32 addr = ((struct p54_hdr *)skb->data)->req_id;
 
 	data_urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!data_urb)
 		return;
 
-	hdr->chksum = p54u_lm87_chksum((u32 *)data, len);
-	hdr->device_addr = data->req_id;
+	checksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
+	hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr));
+	hdr->chksum = checksum;
+	hdr->device_addr = addr;
 
 	usb_fill_bulk_urb(data_urb, priv->udev,
-		usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr,
-		len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb,
-		dev);
+			  usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
+			  skb->data, skb->len, p54u_tx_cb, skb);
 
-	usb_submit_urb(data_urb, GFP_ATOMIC);
+	usb_anchor_urb(data_urb, &priv->submitted);
+	if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
+		usb_unanchor_urb(data_urb);
+		skb_pull(skb, sizeof(*hdr));
+		p54_free_skb(dev, skb);
+	}
+	usb_free_urb(data_urb);
 }
 
-static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data,
-			    size_t len, int free_on_tx)
+static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct p54u_priv *priv = dev->priv;
 	struct urb *int_urb, *data_urb;
 	struct net2280_tx_hdr *hdr;
 	struct net2280_reg_write *reg;
+	int err = 0;
+	__le32 addr = ((struct p54_hdr *) skb->data)->req_id;
+	__le16 len = cpu_to_le16(skb->len);
 
 	reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
 	if (!reg)
@@ -284,21 +325,47 @@
 	reg->addr = cpu_to_le32(P54U_DEV_BASE);
 	reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
 
-	len += sizeof(*data);
-	hdr = (void *)data - sizeof(*hdr);
+	hdr = (void *)skb_push(skb, sizeof(*hdr));
 	memset(hdr, 0, sizeof(*hdr));
-	hdr->device_addr = data->req_id;
-	hdr->len = cpu_to_le16(len);
+	hdr->len = len;
+	hdr->device_addr = addr;
 
 	usb_fill_bulk_urb(int_urb, priv->udev,
 		usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
-		p54u_tx_free_cb, dev);
-	usb_submit_urb(int_urb, GFP_ATOMIC);
+		p54u_tx_dummy_cb, dev);
+
+	/*
+	 * This flag triggers a code path in the USB subsystem that will
+	 * free what's inside the transfer_buffer after the callback routine
+	 * has completed.
+	 */
+	int_urb->transfer_flags |= URB_FREE_BUFFER;
 
 	usb_fill_bulk_urb(data_urb, priv->udev,
-		usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr),
-		free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
-	usb_submit_urb(data_urb, GFP_ATOMIC);
+			  usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
+			  skb->data, skb->len, p54u_tx_cb, skb);
+
+	usb_anchor_urb(int_urb, &priv->submitted);
+	err = usb_submit_urb(int_urb, GFP_ATOMIC);
+	if (err) {
+		usb_unanchor_urb(int_urb);
+		goto out;
+	}
+
+	usb_anchor_urb(data_urb, &priv->submitted);
+	err = usb_submit_urb(data_urb, GFP_ATOMIC);
+	if (err) {
+		usb_unanchor_urb(data_urb);
+		goto out;
+	}
+ out:
+	usb_free_urb(int_urb);
+	usb_free_urb(data_urb);
+
+	if (err) {
+		skb_pull(skb, sizeof(*hdr));
+		p54_free_skb(dev, skb);
+	}
 }
 
 static int p54u_write(struct p54u_priv *priv,
@@ -375,7 +442,8 @@
 
 	tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
 	if (!buf) {
-		printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n");
+		dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
+					  "upload buffer!\n");
 		err = -ENOMEM;
 		goto err_bufalloc;
 	}
@@ -383,14 +451,18 @@
 	memcpy(buf, start_string, 4);
 	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
 	if (err) {
-		printk(KERN_ERR "p54usb: reset failed! (%d)\n", err);
+		dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err);
 		goto err_reset;
 	}
 
-	err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev);
+	err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
 	if (err) {
-		printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n");
-		goto err_req_fw_failed;
+		dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
+					  "(isl3887usb)\n");
+		err = request_firmware(&fw_entry, "isl3887usb_bare",
+			&priv->udev->dev);
+		if (err)
+			goto err_req_fw_failed;
 	}
 
 	err = p54_parse_firmware(dev, fw_entry);
@@ -441,7 +513,8 @@
 
 		err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
 		if (err) {
-			printk(KERN_ERR "p54usb: firmware upload failed!\n");
+			dev_err(&priv->udev->dev, "(p54usb) firmware "
+						  "upload failed!\n");
 			goto err_upload_failed;
 		}
 
@@ -452,10 +525,9 @@
 	*((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
 	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
 	if (err) {
-		printk(KERN_ERR "p54usb: firmware upload failed!\n");
+		dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
 		goto err_upload_failed;
 	}
-
 	timeout = jiffies + msecs_to_jiffies(1000);
 	while (!(err = usb_bulk_msg(priv->udev,
 		usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
@@ -463,25 +535,27 @@
 			break;
 
 		if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
-			printk(KERN_INFO "p54usb: firmware upload failed!\n");
 			err = -EINVAL;
 			break;
 		}
 
 		if (time_after(jiffies, timeout)) {
-			printk(KERN_ERR "p54usb: firmware boot timed out!\n");
+			dev_err(&priv->udev->dev, "(p54usb) firmware boot "
+						  "timed out!\n");
 			err = -ETIMEDOUT;
 			break;
 		}
 	}
-	if (err)
+	if (err) {
+		dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
 		goto err_upload_failed;
+	}
 
 	buf[0] = 'g';
 	buf[1] = '\r';
 	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
 	if (err) {
-		printk(KERN_ERR "p54usb: firmware boot failed!\n");
+		dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
 		goto err_upload_failed;
 	}
 
@@ -521,15 +595,21 @@
 
 	buf = kmalloc(512, GFP_KERNEL);
 	if (!buf) {
-		printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n");
+		dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
+					  "alloc failed!\n");
 		return -ENOMEM;
 	}
 
-	err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev);
+	err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
 	if (err) {
-		printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n");
-		kfree(buf);
-		return err;
+		dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
+					  "(isl3886usb)\n");
+		err = request_firmware(&fw_entry, "isl3890usb",
+			&priv->udev->dev);
+		if (err) {
+			kfree(buf);
+			return err;
+			}
 	}
 
 	err = p54_parse_firmware(dev, fw_entry);
@@ -648,8 +728,8 @@
 
 		err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
 		if (err) {
-			printk(KERN_ERR "p54usb: firmware block upload "
-			       "failed\n");
+			dev_err(&priv->udev->dev, "(p54usb) firmware block "
+						  "upload failed\n");
 			goto fail;
 		}
 
@@ -682,8 +762,8 @@
 			  0x002C | (unsigned long)&devreg->direct_mem_win);
 		if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
 		    !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
-			printk(KERN_ERR "p54usb: firmware DMA transfer "
-			       "failed\n");
+			dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
+						  "transfer failed\n");
 			goto fail;
 		}
 
@@ -786,11 +866,11 @@
 	struct p54u_priv *priv;
 	int err;
 	unsigned int i, recognized_pipes;
-	DECLARE_MAC_BUF(mac);
 
 	dev = p54_init_common(sizeof(*priv));
+
 	if (!dev) {
-		printk(KERN_ERR "p54usb: ieee80211 alloc failed\n");
+		dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
 		return -ENOMEM;
 	}
 
@@ -842,6 +922,7 @@
 		goto err_free_dev;
 
 	skb_queue_head_init(&priv->rx_queue);
+	init_usb_anchor(&priv->submitted);
 
 	p54u_open(dev);
 	err = p54_read_eeprom(dev);
@@ -851,7 +932,7 @@
 
 	err = ieee80211_register_hw(dev);
 	if (err) {
-		printk(KERN_ERR "p54usb: Cannot register netdevice\n");
+		dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n");
 		goto err_free_dev;
 	}
 
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
index 5b8fe91..54ee738 100644
--- a/drivers/net/wireless/p54/p54usb.h
+++ b/drivers/net/wireless/p54/p54usb.h
@@ -133,6 +133,7 @@
 
 	spinlock_t lock;
 	struct sk_buff_head rx_queue;
+	struct usb_anchor submitted;
 };
 
 #endif /* P54USB_H */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 16e68f4..57a150a 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -2028,12 +2028,11 @@
 format_event(islpci_private *priv, char *dest, const char *str,
 	     const struct obj_mlme *mlme, u16 *length, int error)
 {
-	DECLARE_MAC_BUF(mac);
 	int n = snprintf(dest, IW_CUSTOM_MAX,
-			 "%s %s %s %s (%2.2X)",
+			 "%s %s %pM %s (%2.2X)",
 			 str,
 			 ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),
-			 print_mac(mac, mlme->address),
+			 mlme->address,
 			 (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
 			  : ""), mlme->code);
 	BUG_ON(n > IW_CUSTOM_MAX);
@@ -2113,7 +2112,6 @@
 {
 	struct list_head *ptr;
 	struct islpci_bss_wpa_ie *bss = NULL;
-	DECLARE_MAC_BUF(mac);
 
 	if (wpa_ie_len > MAX_WPA_IE_LEN)
 		wpa_ie_len = MAX_WPA_IE_LEN;
@@ -2154,7 +2152,7 @@
 		bss->last_update = jiffies;
 	} else {
 		printk(KERN_DEBUG "Failed to add BSS WPA entry for "
-		       "%s\n", print_mac(mac, bssid));
+		       "%pM\n", bssid);
 	}
 
 	/* expire old entries from WPA list */
@@ -2219,7 +2217,6 @@
 {
 	struct ieee80211_beacon_phdr *hdr;
 	u8 *pos, *end;
-	DECLARE_MAC_BUF(mac);
 
 	if (!priv->wpa)
 		return;
@@ -2230,7 +2227,7 @@
 	while (pos < end) {
 		if (pos + 2 + pos[1] > end) {
 			printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
-			       "for %s\n", print_mac(mac, addr));
+			       "for %pM\n", addr);
 			return;
 		}
 		if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
@@ -2269,7 +2266,6 @@
 	size_t len = 0; /* u16, better? */
 	u8 *payload = NULL, *pos = NULL;
 	int ret;
-	DECLARE_MAC_BUF(mac);
 
 	/* I think all trapable objects are listed here.
 	 * Some oids have a EX version. The difference is that they are emitted
@@ -2358,8 +2354,8 @@
 			break;
 
 		memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
-		printk(KERN_DEBUG "Authenticate from: address:\t%s\n",
-		       print_mac(mac, mlmeex->address));
+		printk(KERN_DEBUG "Authenticate from: address:\t%pM\n",
+		       mlmeex->address);
 		confirm->id = -1; /* or mlmeex->id ? */
 		confirm->state = 0; /* not used */
 		confirm->code = 0;
@@ -2404,8 +2400,8 @@
 		wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
 
 		if (!wpa_ie_len) {
-			printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
-			       print_mac(mac, mlmeex->address));
+			printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n",
+			       mlmeex->address);
 			kfree(confirm);
 			break;
 		}
@@ -2441,8 +2437,8 @@
 		wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
 
 		if (!wpa_ie_len) {
-			printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
-			       print_mac(mac, mlmeex->address));
+			printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n",
+			       mlmeex->address);
 			kfree(confirm);
 			break;
 		}
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index af2e4f2..9a72b1e 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -93,7 +93,7 @@
     Module initialization functions
 ******************************************************************************/
 
-int
+static int
 prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct net_device *ndev;
@@ -216,7 +216,7 @@
 static volatile int __in_cleanup_module = 0;
 
 /* this one removes one(!!) instance only */
-void
+static void
 prism54_remove(struct pci_dev *pdev)
 {
 	struct net_device *ndev = pci_get_drvdata(pdev);
@@ -259,7 +259,7 @@
 	pci_disable_device(pdev);
 }
 
-int
+static int
 prism54_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *ndev = pci_get_drvdata(pdev);
@@ -282,7 +282,7 @@
 	return 0;
 }
 
-int
+static int
 prism54_resume(struct pci_dev *pdev)
 {
 	struct net_device *ndev = pci_get_drvdata(pdev);
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 1404a57..99ec7d6 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -414,7 +414,6 @@
     memreq_t mem;
     struct net_device *dev = (struct net_device *)link->priv;
     ray_dev_t *local = netdev_priv(dev);
-    DECLARE_MAC_BUF(mac);
 
     DEBUG(1, "ray_config(0x%p)\n", link);
 
@@ -485,8 +484,8 @@
     strcpy(local->node.dev_name, dev->name);
     link->dev_node = &local->node;
 
-    printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %s\n",
-       dev->name, dev->irq, print_mac(mac, dev->dev_addr));
+    printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n",
+       dev->name, dev->irq, dev->dev_addr);
 
     return 0;
 
@@ -829,7 +828,7 @@
 }
 
 /*===========================================================================*/
-int ray_dev_init(struct net_device *dev)
+static int ray_dev_init(struct net_device *dev)
 {
 #ifdef RAY_IMMEDIATE_INIT
     int i;
@@ -2285,7 +2284,6 @@
 
     skb->protocol = eth_type_trans(skb,dev);
     netif_rx(skb);
-    dev->last_rx = jiffies;
     local->stats.rx_packets++;
     local->stats.rx_bytes += total_len;
 
@@ -2595,7 +2593,6 @@
     UCHAR *p;
     struct freq_hop_element *pfh;
     UCHAR c[33];
-    DECLARE_MAC_BUF(mac);
 
     link = this_device;
     if (!link)
@@ -2623,8 +2620,7 @@
                    nettype[local->sparm.b5.a_network_type], c);
 
     p = local->bss_id;
-    seq_printf(m, "BSSID                = %s\n",
-                   print_mac(mac, p));
+    seq_printf(m, "BSSID                = %pM\n", p);
 
     seq_printf(m, "Country code         = %d\n",
                    local->sparm.b5.a_curr_country_code);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 2b41489..607ce9f 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -37,11 +37,11 @@
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
 #include <linux/if_arp.h>
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 #include <linux/usb/usbnet.h>
 #include <linux/usb/rndis_host.h>
 
@@ -1104,7 +1104,7 @@
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
 	struct iw_range *range = (struct iw_range *)extra;
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	int len, ret, i, j, num, has_80211g_rates;
 	u8 rates[8];
@@ -1210,7 +1210,7 @@
 static int rndis_iw_get_name(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 
 	strcpy(wrqu->name, priv->name);
@@ -1223,7 +1223,7 @@
 {
 	struct ndis_80211_ssid ssid;
 	int length = wrqu->essid.length;
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 
 	devdbg(usbdev, "SIOCSIWESSID: [flags:%d,len:%d] '%.32s'",
 		wrqu->essid.flags, wrqu->essid.length, essid);
@@ -1250,7 +1250,7 @@
     struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
 {
 	struct ndis_80211_ssid ssid;
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	int ret;
 
 	ret = get_essid(usbdev, &ssid);
@@ -1273,15 +1273,14 @@
 static int rndis_iw_get_bssid(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	unsigned char bssid[ETH_ALEN];
 	int ret;
-	DECLARE_MAC_BUF(mac);
 
 	ret = get_bssid(usbdev, bssid);
 
 	if (ret == 0)
-		devdbg(usbdev, "SIOCGIWAP: %s", print_mac(mac, bssid));
+		devdbg(usbdev, "SIOCGIWAP: %pM", bssid);
 	else
 		devdbg(usbdev, "SIOCGIWAP: <not associated>");
 
@@ -1295,12 +1294,11 @@
 static int rndis_iw_set_bssid(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	u8 *bssid = (u8 *)wrqu->ap_addr.sa_data;
-	DECLARE_MAC_BUF(mac);
 	int ret;
 
-	devdbg(usbdev, "SIOCSIWAP: %s", print_mac(mac, bssid));
+	devdbg(usbdev, "SIOCSIWAP: %pM", bssid);
 
 	ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN);
 
@@ -1318,7 +1316,7 @@
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
 	struct iw_param *p = &wrqu->param;
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	int ret = -ENOTSUPP;
 
@@ -1399,7 +1397,7 @@
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
 	struct iw_param *p = &wrqu->param;
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 
 	switch (p->flags & IW_AUTH_INDEX) {
@@ -1431,7 +1429,7 @@
 				struct iw_request_info *info,
 				union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 
 	switch (priv->infra_mode) {
@@ -1454,7 +1452,7 @@
 static int rndis_iw_set_mode(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	int mode;
 
 	devdbg(usbdev, "SIOCSIWMODE: %08x", wrqu->mode);
@@ -1479,7 +1477,7 @@
 static int rndis_iw_set_encode(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	int ret, index, key_len;
 	u8 *key;
@@ -1542,7 +1540,7 @@
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	struct ndis_80211_key ndis_key;
 	int keyidx, ret;
@@ -1627,7 +1625,7 @@
 static int rndis_iw_set_scan(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	union iwreq_data evt;
 	int ret = -EINVAL;
 	__le32 tmp;
@@ -1652,19 +1650,18 @@
 				  struct ndis_80211_bssid_ex *bssid)
 {
 #ifdef DEBUG
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 #endif
-	struct ieee80211_info_element *ie;
+	u8 *ie;
 	char *current_val;
 	int bssid_len, ie_len, i;
 	u32 beacon, atim;
 	struct iw_event iwe;
 	unsigned char sbuf[32];
-	DECLARE_MAC_BUF(mac);
 
 	bssid_len = le32_to_cpu(bssid->length);
 
-	devdbg(usbdev, "BSSID %s", print_mac(mac, bssid->mac));
+	devdbg(usbdev, "BSSID %pM", bssid->mac);
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN);
@@ -1753,20 +1750,20 @@
 	ie_len = min(bssid_len - (int)sizeof(*bssid),
 					(int)le32_to_cpu(bssid->ie_length));
 	ie_len -= sizeof(struct ndis_80211_fixed_ies);
-	while (ie_len >= sizeof(*ie) && sizeof(*ie) + ie->len <= ie_len) {
-		if ((ie->id == MFIE_TYPE_GENERIC && ie->len >= 4 &&
-				memcmp(ie->data, "\x00\x50\xf2\x01", 4) == 0) ||
-				ie->id == MFIE_TYPE_RSN) {
+	while (ie_len >= 2 && 2 + ie[1] <= ie_len) {
+		if ((ie[0] == WLAN_EID_GENERIC && ie[1] >= 4 &&
+		     memcmp(ie + 2, "\x00\x50\xf2\x01", 4) == 0) ||
+		    ie[0] == WLAN_EID_RSN) {
 			devdbg(usbdev, "IE: WPA%d",
-					(ie->id == MFIE_TYPE_RSN) ? 2 : 1);
+					(ie[0] == WLAN_EID_RSN) ? 2 : 1);
 			iwe.cmd = IWEVGENIE;
-			iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN);
-			cev = iwe_stream_add_point(info, cev, end_buf, &iwe,
-								(u8 *)ie);
+			/* arbitrary cut-off at 64 */
+			iwe.u.data.length = min(ie[1] + 2, 64);
+			cev = iwe_stream_add_point(info, cev, end_buf, &iwe, ie);
 		}
 
-		ie_len -= sizeof(*ie) + ie->len;
-		ie = (struct ieee80211_info_element *)&ie->data[ie->len];
+		ie_len -= 2 + ie[1];
+		ie += 2 + ie[1];
 	}
 
 	return cev;
@@ -1776,7 +1773,7 @@
 static int rndis_iw_get_scan(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	void *buf = NULL;
 	char *cev = extra;
 	struct ndis_80211_bssid_list_ex *bssid_list;
@@ -1822,7 +1819,7 @@
 static int rndis_iw_set_genie(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	int ret = 0;
 
@@ -1856,7 +1853,7 @@
 static int rndis_iw_get_genie(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 
 	devdbg(usbdev, "SIOCGIWGENIE");
@@ -1879,7 +1876,7 @@
 static int rndis_iw_set_rts(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	__le32 tmp;
 	devdbg(usbdev, "SIOCSIWRTS");
 
@@ -1892,7 +1889,7 @@
 static int rndis_iw_get_rts(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	__le32 tmp;
 	int len, ret;
 
@@ -1913,7 +1910,7 @@
 static int rndis_iw_set_frag(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	__le32 tmp;
 
 	devdbg(usbdev, "SIOCSIWFRAG");
@@ -1927,7 +1924,7 @@
 static int rndis_iw_get_frag(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	__le32 tmp;
 	int len, ret;
 
@@ -1947,7 +1944,7 @@
 static int rndis_iw_set_nick(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 
 	devdbg(usbdev, "SIOCSIWNICK");
@@ -1964,7 +1961,7 @@
 static int rndis_iw_get_nick(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 
 	wrqu->data.flags = 1;
@@ -1980,7 +1977,7 @@
 static int rndis_iw_set_freq(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct ndis_80211_conf config;
 	unsigned int dsconfig;
 	int len, ret;
@@ -2011,7 +2008,7 @@
 static int rndis_iw_get_freq(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct ndis_80211_conf config;
 	int len, ret;
 
@@ -2028,7 +2025,7 @@
 static int rndis_iw_get_txpower(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	__le32 tx_power;
 	int ret = 0, len;
@@ -2062,7 +2059,7 @@
 static int rndis_iw_set_txpower(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	__le32 tx_power = 0;
 	int ret = 0;
@@ -2114,7 +2111,7 @@
 static int rndis_iw_get_rate(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	__le32 tmp;
 	int ret, len;
 
@@ -2132,7 +2129,7 @@
 static int rndis_iw_set_mlme(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	struct iw_mlme *mlme = (struct iw_mlme *)extra;
 	unsigned char bssid[ETH_ALEN];
@@ -2157,7 +2154,7 @@
 
 static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	unsigned long flags;
 
@@ -2287,7 +2284,7 @@
 
 static void rndis_wext_set_multicast_list(struct net_device *dev)
 {
-	struct usbnet *usbdev = dev->priv;
+	struct usbnet *usbdev = netdev_priv(dev);
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 
 	if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index 95511ac..178b313 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -57,6 +57,7 @@
 	tristate "Ralink rt2500 (USB) support"
 	depends on USB
 	select RT2X00_LIB_USB
+	select RT2X00_LIB_CRYPTO
 	---help---
 	  This adds support for rt2500 wireless chipset family.
 	  Supported chips: RT2571 & RT2572.
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 08cb9ee..6a97767 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -49,45 +49,33 @@
  * the access attempt is considered to have failed,
  * and we will print an error.
  */
-static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
-	u32 reg;
-	unsigned int i;
-
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
-		if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
-			break;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
 
 static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, const u8 value)
 {
 	u32 reg;
 
+	mutex_lock(&rt2x00dev->csr_mutex);
+
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	reg = rt2400pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
-		ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
-		return;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+		rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+		rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+		rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+		rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
 	}
 
-	/*
-	 * Write the data into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
-	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
-	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
-	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
-
-	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -95,66 +83,58 @@
 {
 	u32 reg;
 
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt2400pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
-		ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
-		return;
-	}
+	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Write the request into the BBP.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the read request into the register.
+	 * After the data has been written, we wait until hardware
+	 * returns the correct value, if at any time the register
+	 * doesn't become available in time, reg will be 0xffffffff
+	 * which means we return 0xff to the caller.
 	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
-	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
-	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+		rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+		rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
 
-	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+		rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
 
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt2400pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
-		ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
-		*value = 0xff;
-		return;
+		WAIT_FOR_BBP(rt2x00dev, &reg);
 	}
 
 	*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
+
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, const u32 value)
 {
 	u32 reg;
-	unsigned int i;
 
 	if (!word)
 		return;
 
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
-		if (!rt2x00_get_field32(reg, RFCSR_BUSY))
-			goto rf_write;
-		udelay(REGISTER_BUSY_DELAY);
+	mutex_lock(&rt2x00dev->csr_mutex);
+
+	/*
+	 * Wait until the RF becomes available, afterwards we
+	 * can safely write the new data into the register.
+	 */
+	if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+		rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+		rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+		rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+		rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+		rt2x00_rf_write(rt2x00dev, word, value);
 	}
 
-	ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
-	return;
-
-rf_write:
-	reg = 0;
-	rt2x00_set_field32(&reg, RFCSR_VALUE, value);
-	rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
-	rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
-	rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
-
-	rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
-	rt2x00_rf_write(rt2x00dev, word, value);
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
@@ -188,43 +168,34 @@
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt2400pci_read_csr(struct rt2x00_dev *rt2x00dev,
-			       const unsigned int word, u32 *data)
-{
-	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt2400pci_write_csr(struct rt2x00_dev *rt2x00dev,
-				const unsigned int word, u32 data)
-{
-	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt2400pci_rt2x00debug = {
 	.owner	= THIS_MODULE,
 	.csr	= {
-		.read		= rt2400pci_read_csr,
-		.write		= rt2400pci_write_csr,
+		.read		= rt2x00pci_register_read,
+		.write		= rt2x00pci_register_write,
+		.flags		= RT2X00DEBUGFS_OFFSET,
+		.word_base	= CSR_REG_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= CSR_REG_SIZE / sizeof(u32),
 	},
 	.eeprom	= {
 		.read		= rt2x00_eeprom_read,
 		.write		= rt2x00_eeprom_write,
+		.word_base	= EEPROM_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= EEPROM_SIZE / sizeof(u16),
 	},
 	.bbp	= {
 		.read		= rt2400pci_bbp_read,
 		.write		= rt2400pci_bbp_write,
+		.word_base	= BBP_BASE,
 		.word_size	= sizeof(u8),
 		.word_count	= BBP_SIZE / sizeof(u8),
 	},
 	.rf	= {
 		.read		= rt2x00_rf_read,
 		.write		= rt2400pci_rf_write,
+		.word_base	= RF_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= RF_SIZE / sizeof(u32),
 	},
@@ -331,7 +302,7 @@
 		/*
 		 * Enable beacon config
 		 */
-		bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20);
+		bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20);
 		rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
 		rt2x00_set_field32(&reg, BCNCSR1_PRELOAD, bcn_preload);
 		rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
@@ -376,32 +347,94 @@
 	rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
 	rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
 	rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
-	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10));
 	rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
 
 	rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
 	rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
 	rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
-	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20));
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20));
 	rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
 
 	rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
 	rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
 	rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
-	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55));
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55));
 	rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
 
 	rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
 	rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
 	rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
-	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110));
 	rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+
+	rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+	rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
+	rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
+	rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+	rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
+	rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
+	rt2x00pci_register_write(rt2x00dev, CSR19, reg);
 }
 
-static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev,
-				     const int basic_rate_mask)
+static void rt2400pci_config_ant(struct rt2x00_dev *rt2x00dev,
+				 struct antenna_setup *ant)
 {
-	rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+	u8 r1;
+	u8 r4;
+
+	/*
+	 * We should never come here because rt2x00lib is supposed
+	 * to catch this and send us the correct antenna explicitely.
+	 */
+	BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+	       ant->tx == ANTENNA_SW_DIVERSITY);
+
+	rt2400pci_bbp_read(rt2x00dev, 4, &r4);
+	rt2400pci_bbp_read(rt2x00dev, 1, &r1);
+
+	/*
+	 * Configure the TX antenna.
+	 */
+	switch (ant->tx) {
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
+		break;
+	case ANTENNA_B:
+	default:
+		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
+		break;
+	}
+
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (ant->rx) {
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
+		break;
+	case ANTENNA_B:
+	default:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		break;
+	}
+
+	rt2400pci_bbp_write(rt2x00dev, 4, r4);
+	rt2400pci_bbp_write(rt2x00dev, 1, r1);
 }
 
 static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
@@ -460,56 +493,17 @@
 	rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower));
 }
 
-static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-				     struct antenna_setup *ant)
+static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+					 struct rt2x00lib_conf *libconf)
 {
-	u8 r1;
-	u8 r4;
+	u32 reg;
 
-	/*
-	 * We should never come here because rt2x00lib is supposed
-	 * to catch this and send us the correct antenna explicitely.
-	 */
-	BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
-	       ant->tx == ANTENNA_SW_DIVERSITY);
-
-	rt2400pci_bbp_read(rt2x00dev, 4, &r4);
-	rt2400pci_bbp_read(rt2x00dev, 1, &r1);
-
-	/*
-	 * Configure the TX antenna.
-	 */
-	switch (ant->tx) {
-	case ANTENNA_HW_DIVERSITY:
-		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
-		break;
-	case ANTENNA_A:
-		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
-		break;
-	case ANTENNA_B:
-	default:
-		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
-		break;
-	}
-
-	/*
-	 * Configure the RX antenna.
-	 */
-	switch (ant->rx) {
-	case ANTENNA_HW_DIVERSITY:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
-		break;
-	case ANTENNA_A:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
-		break;
-	case ANTENNA_B:
-	default:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
-		break;
-	}
-
-	rt2400pci_bbp_write(rt2x00dev, 4, r4);
-	rt2400pci_bbp_write(rt2x00dev, 1, r1);
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_LONG_RETRY,
+			   libconf->conf->long_frame_max_tx_count);
+	rt2x00_set_field32(&reg, CSR11_SHORT_RETRY,
+			   libconf->conf->short_frame_max_tx_count);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
 }
 
 static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,
@@ -517,20 +511,6 @@
 {
 	u32 reg;
 
-	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
-	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
-	rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
-	rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
-	rt2x00pci_register_write(rt2x00dev, CSR18, reg);
-
-	rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
-	rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
-	rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
-	rt2x00pci_register_write(rt2x00dev, CSR19, reg);
-
 	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
 	rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
 	rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
@@ -548,16 +528,14 @@
 			     struct rt2x00lib_conf *libconf,
 			     const unsigned int flags)
 {
-	if (flags & CONFIG_UPDATE_PHYMODE)
-		rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates);
-	if (flags & CONFIG_UPDATE_CHANNEL)
+	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt2400pci_config_channel(rt2x00dev, &libconf->rf);
-	if (flags & CONFIG_UPDATE_TXPOWER)
+	if (flags & IEEE80211_CONF_CHANGE_POWER)
 		rt2400pci_config_txpower(rt2x00dev,
 					 libconf->conf->power_level);
-	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt2400pci_config_antenna(rt2x00dev, &libconf->ant);
-	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+		rt2400pci_config_retry_limit(rt2x00dev, libconf);
+	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
 		rt2400pci_config_duration(rt2x00dev, libconf);
 }
 
@@ -628,36 +606,47 @@
 /*
  * Initialization functions.
  */
-static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
-				   struct queue_entry *entry)
+static bool rt2400pci_get_entry_state(struct queue_entry *entry)
+{
+	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+	u32 word;
+
+	if (entry->queue->qid == QID_RX) {
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+
+		return rt2x00_get_field32(word, RXD_W0_OWNER_NIC);
+	} else {
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+
+		return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+		        rt2x00_get_field32(word, TXD_W0_VALID));
+	}
+}
+
+static void rt2400pci_clear_entry(struct queue_entry *entry)
 {
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	u32 word;
 
-	rt2x00_desc_read(entry_priv->desc, 2, &word);
-	rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len);
-	rt2x00_desc_write(entry_priv->desc, 2, word);
+	if (entry->queue->qid == QID_RX) {
+		rt2x00_desc_read(entry_priv->desc, 2, &word);
+		rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len);
+		rt2x00_desc_write(entry_priv->desc, 2, word);
 
-	rt2x00_desc_read(entry_priv->desc, 1, &word);
-	rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
-	rt2x00_desc_write(entry_priv->desc, 1, word);
+		rt2x00_desc_read(entry_priv->desc, 1, &word);
+		rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
+		rt2x00_desc_write(entry_priv->desc, 1, word);
 
-	rt2x00_desc_read(entry_priv->desc, 0, &word);
-	rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
-	rt2x00_desc_write(entry_priv->desc, 0, word);
-}
-
-static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev,
-				   struct queue_entry *entry)
-{
-	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
-	u32 word;
-
-	rt2x00_desc_read(entry_priv->desc, 0, &word);
-	rt2x00_set_field32(&word, TXD_W0_VALID, 0);
-	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
-	rt2x00_desc_write(entry_priv->desc, 0, word);
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+		rt2x00_desc_write(entry_priv->desc, 0, word);
+	} else {
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+		rt2x00_desc_write(entry_priv->desc, 0, word);
+	}
 }
 
 static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev)
@@ -1313,10 +1302,8 @@
 	 */
 	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
 	if (!is_valid_ether_addr(mac)) {
-		DECLARE_MAC_BUF(macbuf);
-
 		random_ether_addr(mac);
-		EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+		EEPROM(rt2x00dev, "MAC: %pM\n", mac);
 	}
 
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -1504,20 +1491,6 @@
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw,
-				     u32 short_retry, u32 long_retry)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	u32 reg;
-
-	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-	rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
-	rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
-	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-	return 0;
-}
-
 static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
 			     const struct ieee80211_tx_queue_params *params)
 {
@@ -1576,7 +1549,6 @@
 	.config_interface	= rt2x00mac_config_interface,
 	.configure_filter	= rt2x00mac_configure_filter,
 	.get_stats		= rt2x00mac_get_stats,
-	.set_retry_limit	= rt2400pci_set_retry_limit,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2400pci_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
@@ -1589,8 +1561,8 @@
 	.probe_hw		= rt2400pci_probe_hw,
 	.initialize		= rt2x00pci_initialize,
 	.uninitialize		= rt2x00pci_uninitialize,
-	.init_rxentry		= rt2400pci_init_rxentry,
-	.init_txentry		= rt2400pci_init_txentry,
+	.get_entry_state	= rt2400pci_get_entry_state,
+	.clear_entry		= rt2400pci_clear_entry,
 	.set_device_state	= rt2400pci_set_device_state,
 	.rfkill_poll		= rt2400pci_rfkill_poll,
 	.link_stats		= rt2400pci_link_stats,
@@ -1604,6 +1576,7 @@
 	.config_filter		= rt2400pci_config_filter,
 	.config_intf		= rt2400pci_config_intf,
 	.config_erp		= rt2400pci_config_erp,
+	.config_ant		= rt2400pci_config_ant,
 	.config			= rt2400pci_config,
 };
 
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index bbff381..9aefda4 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -46,7 +46,9 @@
 #define CSR_REG_SIZE			0x014c
 #define EEPROM_BASE			0x0000
 #define EEPROM_SIZE			0x0100
+#define BBP_BASE			0x0000
 #define BBP_SIZE			0x0020
+#define RF_BASE				0x0000
 #define RF_SIZE				0x0010
 
 /*
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index ef42cc0..d3bc218 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -49,45 +49,33 @@
  * the access attempt is considered to have failed,
  * and we will print an error.
  */
-static u32 rt2500pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
-	u32 reg;
-	unsigned int i;
-
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
-		if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
-			break;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
 
 static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, const u8 value)
 {
 	u32 reg;
 
+	mutex_lock(&rt2x00dev->csr_mutex);
+
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	reg = rt2500pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
-		ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
-		return;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+		rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+		rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+		rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+		rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
 	}
 
-	/*
-	 * Write the data into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
-	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
-	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
-	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
-
-	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -95,66 +83,58 @@
 {
 	u32 reg;
 
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt2500pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
-		ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
-		return;
-	}
+	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Write the request into the BBP.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the read request into the register.
+	 * After the data has been written, we wait until hardware
+	 * returns the correct value, if at any time the register
+	 * doesn't become available in time, reg will be 0xffffffff
+	 * which means we return 0xff to the caller.
 	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
-	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
-	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+		rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+		rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
 
-	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+		rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
 
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt2500pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
-		ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
-		*value = 0xff;
-		return;
+		WAIT_FOR_BBP(rt2x00dev, &reg);
 	}
 
 	*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
+
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, const u32 value)
 {
 	u32 reg;
-	unsigned int i;
 
 	if (!word)
 		return;
 
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
-		if (!rt2x00_get_field32(reg, RFCSR_BUSY))
-			goto rf_write;
-		udelay(REGISTER_BUSY_DELAY);
+	mutex_lock(&rt2x00dev->csr_mutex);
+
+	/*
+	 * Wait until the RF becomes available, afterwards we
+	 * can safely write the new data into the register.
+	 */
+	if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+		rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+		rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+		rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+		rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+		rt2x00_rf_write(rt2x00dev, word, value);
 	}
 
-	ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
-	return;
-
-rf_write:
-	reg = 0;
-	rt2x00_set_field32(&reg, RFCSR_VALUE, value);
-	rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
-	rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
-	rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
-
-	rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
-	rt2x00_rf_write(rt2x00dev, word, value);
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
@@ -188,43 +168,34 @@
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt2500pci_read_csr(struct rt2x00_dev *rt2x00dev,
-			       const unsigned int word, u32 *data)
-{
-	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt2500pci_write_csr(struct rt2x00_dev *rt2x00dev,
-				const unsigned int word, u32 data)
-{
-	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt2500pci_rt2x00debug = {
 	.owner	= THIS_MODULE,
 	.csr	= {
-		.read		= rt2500pci_read_csr,
-		.write		= rt2500pci_write_csr,
+		.read		= rt2x00pci_register_read,
+		.write		= rt2x00pci_register_write,
+		.flags		= RT2X00DEBUGFS_OFFSET,
+		.word_base	= CSR_REG_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= CSR_REG_SIZE / sizeof(u32),
 	},
 	.eeprom	= {
 		.read		= rt2x00_eeprom_read,
 		.write		= rt2x00_eeprom_write,
+		.word_base	= EEPROM_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= EEPROM_SIZE / sizeof(u16),
 	},
 	.bbp	= {
 		.read		= rt2500pci_bbp_read,
 		.write		= rt2500pci_bbp_write,
+		.word_base	= BBP_BASE,
 		.word_size	= sizeof(u8),
 		.word_count	= BBP_SIZE / sizeof(u8),
 	},
 	.rf	= {
 		.read		= rt2x00_rf_read,
 		.write		= rt2500pci_rf_write,
+		.word_base	= RF_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= RF_SIZE / sizeof(u32),
 	},
@@ -336,7 +307,7 @@
 		/*
 		 * Enable beacon config
 		 */
-		bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20);
+		bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20);
 		rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
 		rt2x00_set_field32(&reg, BCNCSR1_PRELOAD, bcn_preload);
 		rt2x00_set_field32(&reg, BCNCSR1_BEACON_CWMIN, queue->cw_min);
@@ -382,32 +353,114 @@
 	rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
 	rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
 	rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
-	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10));
 	rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
 
 	rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
 	rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
 	rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
-	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20));
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20));
 	rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
 
 	rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
 	rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
 	rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
-	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55));
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55));
 	rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
 
 	rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
 	rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
 	rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
-	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110));
 	rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+
+	rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+	rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
+	rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
+	rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+	rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
+	rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
+	rt2x00pci_register_write(rt2x00dev, CSR19, reg);
 }
 
-static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev,
-				     const int basic_rate_mask)
+static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
+				 struct antenna_setup *ant)
 {
-	rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+	u32 reg;
+	u8 r14;
+	u8 r2;
+
+	/*
+	 * We should never come here because rt2x00lib is supposed
+	 * to catch this and send us the correct antenna explicitely.
+	 */
+	BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+	       ant->tx == ANTENNA_SW_DIVERSITY);
+
+	rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
+	rt2500pci_bbp_read(rt2x00dev, 14, &r14);
+	rt2500pci_bbp_read(rt2x00dev, 2, &r2);
+
+	/*
+	 * Configure the TX antenna.
+	 */
+	switch (ant->tx) {
+	case ANTENNA_A:
+		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
+		rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
+		break;
+	case ANTENNA_B:
+	default:
+		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+		rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
+		break;
+	}
+
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (ant->rx) {
+	case ANTENNA_A:
+		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
+		break;
+	case ANTENNA_B:
+	default:
+		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+		break;
+	}
+
+	/*
+	 * RT2525E and RT5222 need to flip TX I/Q
+	 */
+	if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
+	    rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
+		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
+
+		/*
+		 * RT2525E does not need RX I/Q Flip.
+		 */
+		if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
+	} else {
+		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
+	}
+
+	rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
+	rt2500pci_bbp_write(rt2x00dev, 14, r14);
+	rt2500pci_bbp_write(rt2x00dev, 2, r2);
 }
 
 static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
@@ -489,76 +542,17 @@
 	rt2500pci_rf_write(rt2x00dev, 3, rf3);
 }
 
-static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-				     struct antenna_setup *ant)
+static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+					 struct rt2x00lib_conf *libconf)
 {
 	u32 reg;
-	u8 r14;
-	u8 r2;
 
-	/*
-	 * We should never come here because rt2x00lib is supposed
-	 * to catch this and send us the correct antenna explicitely.
-	 */
-	BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
-	       ant->tx == ANTENNA_SW_DIVERSITY);
-
-	rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
-	rt2500pci_bbp_read(rt2x00dev, 14, &r14);
-	rt2500pci_bbp_read(rt2x00dev, 2, &r2);
-
-	/*
-	 * Configure the TX antenna.
-	 */
-	switch (ant->tx) {
-	case ANTENNA_A:
-		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
-		rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
-		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
-		break;
-	case ANTENNA_B:
-	default:
-		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
-		rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
-		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
-		break;
-	}
-
-	/*
-	 * Configure the RX antenna.
-	 */
-	switch (ant->rx) {
-	case ANTENNA_A:
-		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
-		break;
-	case ANTENNA_B:
-	default:
-		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
-		break;
-	}
-
-	/*
-	 * RT2525E and RT5222 need to flip TX I/Q
-	 */
-	if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
-	    rt2x00_rf(&rt2x00dev->chip, RF5222)) {
-		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
-		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
-		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
-
-		/*
-		 * RT2525E does not need RX I/Q Flip.
-		 */
-		if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
-			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
-	} else {
-		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
-		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
-	}
-
-	rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
-	rt2500pci_bbp_write(rt2x00dev, 14, r14);
-	rt2500pci_bbp_write(rt2x00dev, 2, r2);
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_LONG_RETRY,
+			   libconf->conf->long_frame_max_tx_count);
+	rt2x00_set_field32(&reg, CSR11_SHORT_RETRY,
+			   libconf->conf->short_frame_max_tx_count);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
 }
 
 static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,
@@ -566,20 +560,6 @@
 {
 	u32 reg;
 
-	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
-	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
-	rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
-	rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
-	rt2x00pci_register_write(rt2x00dev, CSR18, reg);
-
-	rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
-	rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
-	rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
-	rt2x00pci_register_write(rt2x00dev, CSR19, reg);
-
 	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
 	rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
 	rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
@@ -597,17 +577,16 @@
 			     struct rt2x00lib_conf *libconf,
 			     const unsigned int flags)
 {
-	if (flags & CONFIG_UPDATE_PHYMODE)
-		rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates);
-	if (flags & CONFIG_UPDATE_CHANNEL)
+	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt2500pci_config_channel(rt2x00dev, &libconf->rf,
 					 libconf->conf->power_level);
-	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+	if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+	    !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
 		rt2500pci_config_txpower(rt2x00dev,
 					 libconf->conf->power_level);
-	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt2500pci_config_antenna(rt2x00dev, &libconf->ant);
-	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+		rt2500pci_config_retry_limit(rt2x00dev, libconf);
+	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
 		rt2500pci_config_duration(rt2x00dev, libconf);
 }
 
@@ -723,32 +702,43 @@
 /*
  * Initialization functions.
  */
-static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
-				   struct queue_entry *entry)
+static bool rt2500pci_get_entry_state(struct queue_entry *entry)
+{
+	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+	u32 word;
+
+	if (entry->queue->qid == QID_RX) {
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+
+		return rt2x00_get_field32(word, RXD_W0_OWNER_NIC);
+	} else {
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+
+		return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+		        rt2x00_get_field32(word, TXD_W0_VALID));
+	}
+}
+
+static void rt2500pci_clear_entry(struct queue_entry *entry)
 {
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	u32 word;
 
-	rt2x00_desc_read(entry_priv->desc, 1, &word);
-	rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
-	rt2x00_desc_write(entry_priv->desc, 1, word);
+	if (entry->queue->qid == QID_RX) {
+		rt2x00_desc_read(entry_priv->desc, 1, &word);
+		rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
+		rt2x00_desc_write(entry_priv->desc, 1, word);
 
-	rt2x00_desc_read(entry_priv->desc, 0, &word);
-	rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
-	rt2x00_desc_write(entry_priv->desc, 0, word);
-}
-
-static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev,
-				   struct queue_entry *entry)
-{
-	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
-	u32 word;
-
-	rt2x00_desc_read(entry_priv->desc, 0, &word);
-	rt2x00_set_field32(&word, TXD_W0_VALID, 0);
-	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
-	rt2x00_desc_write(entry_priv->desc, 0, word);
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+		rt2x00_desc_write(entry_priv->desc, 0, word);
+	} else {
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+		rt2x00_desc_write(entry_priv->desc, 0, word);
+	}
 }
 
 static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev)
@@ -1451,11 +1441,8 @@
 	 */
 	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
 	if (!is_valid_ether_addr(mac)) {
-		DECLARE_MAC_BUF(macbuf);
-
 		random_ether_addr(mac);
-		EEPROM(rt2x00dev, "MAC: %s\n",
-		       print_mac(macbuf, mac));
+		EEPROM(rt2x00dev, "MAC: %pM\n", mac);
 	}
 
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -1830,20 +1817,6 @@
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw,
-				     u32 short_retry, u32 long_retry)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	u32 reg;
-
-	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-	rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
-	rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
-	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-	return 0;
-}
-
 static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1877,7 +1850,6 @@
 	.config_interface	= rt2x00mac_config_interface,
 	.configure_filter	= rt2x00mac_configure_filter,
 	.get_stats		= rt2x00mac_get_stats,
-	.set_retry_limit	= rt2500pci_set_retry_limit,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
@@ -1890,8 +1862,8 @@
 	.probe_hw		= rt2500pci_probe_hw,
 	.initialize		= rt2x00pci_initialize,
 	.uninitialize		= rt2x00pci_uninitialize,
-	.init_rxentry		= rt2500pci_init_rxentry,
-	.init_txentry		= rt2500pci_init_txentry,
+	.get_entry_state	= rt2500pci_get_entry_state,
+	.clear_entry		= rt2500pci_clear_entry,
 	.set_device_state	= rt2500pci_set_device_state,
 	.rfkill_poll		= rt2500pci_rfkill_poll,
 	.link_stats		= rt2500pci_link_stats,
@@ -1905,6 +1877,7 @@
 	.config_filter		= rt2500pci_config_filter,
 	.config_intf		= rt2500pci_config_intf,
 	.config_erp		= rt2500pci_config_erp,
+	.config_ant		= rt2500pci_config_ant,
 	.config			= rt2500pci_config,
 };
 
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index 8c26bef..e135247 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -57,7 +57,9 @@
 #define CSR_REG_SIZE			0x0174
 #define EEPROM_BASE			0x0000
 #define EEPROM_SIZE			0x0200
+#define BBP_BASE			0x0000
 #define BBP_SIZE			0x0040
+#define RF_BASE				0x0000
 #define RF_SIZE				0x0014
 
 /*
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index d3bf7bb..30028e2 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -36,6 +36,13 @@
 #include "rt2500usb.h"
 
 /*
+ * Allow hardware encryption to be disabled.
+ */
+static int modparam_nohwcrypt = 1;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+
+/*
  * Register access.
  * All access to the CSR registers will go through the methods
  * rt2500usb_register_read and rt2500usb_register_write.
@@ -47,7 +54,7 @@
  * between each attampt. When the busy bit is still set at that time,
  * the access attempt is considered to have failed,
  * and we will print an error.
- * If the usb_cache_mutex is already held then the _lock variants must
+ * If the csr_mutex is already held then the _lock variants must
  * be used instead.
  */
 static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
@@ -57,7 +64,7 @@
 	__le16 reg;
 	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
 				      USB_VENDOR_REQUEST_IN, offset,
-				      &reg, sizeof(u16), REGISTER_TIMEOUT);
+				      &reg, sizeof(reg), REGISTER_TIMEOUT);
 	*value = le16_to_cpu(reg);
 }
 
@@ -68,7 +75,7 @@
 	__le16 reg;
 	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
 				       USB_VENDOR_REQUEST_IN, offset,
-				       &reg, sizeof(u16), REGISTER_TIMEOUT);
+				       &reg, sizeof(reg), REGISTER_TIMEOUT);
 	*value = le16_to_cpu(reg);
 }
 
@@ -89,7 +96,7 @@
 	__le16 reg = cpu_to_le16(value);
 	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
 				      USB_VENDOR_REQUEST_OUT, offset,
-				      &reg, sizeof(u16), REGISTER_TIMEOUT);
+				      &reg, sizeof(reg), REGISTER_TIMEOUT);
 }
 
 static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
@@ -99,7 +106,7 @@
 	__le16 reg = cpu_to_le16(value);
 	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
 				       USB_VENDOR_REQUEST_OUT, offset,
-				       &reg, sizeof(u16), REGISTER_TIMEOUT);
+				       &reg, sizeof(reg), REGISTER_TIMEOUT);
 }
 
 static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
@@ -112,53 +119,53 @@
 				      REGISTER_TIMEOUT16(length));
 }
 
-static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev)
+static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+				  const unsigned int offset,
+				  struct rt2x00_field16 field,
+				  u16 *reg)
 {
-	u16 reg;
 	unsigned int i;
 
 	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, &reg);
-		if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
-			break;
+		rt2500usb_register_read_lock(rt2x00dev, offset, reg);
+		if (!rt2x00_get_field16(*reg, field))
+			return 1;
 		udelay(REGISTER_BUSY_DELAY);
 	}
 
-	return reg;
+	ERROR(rt2x00dev, "Indirect register access failed: "
+	      "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+	*reg = ~0;
+
+	return 0;
 }
 
+#define WAIT_FOR_BBP(__dev, __reg) \
+	rt2500usb_regbusy_read((__dev), PHY_CSR8, PHY_CSR8_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+	rt2500usb_regbusy_read((__dev), PHY_CSR10, PHY_CSR10_RF_BUSY, (__reg))
+
 static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, const u8 value)
 {
 	u16 reg;
 
-	mutex_lock(&rt2x00dev->usb_cache_mutex);
+	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
-		goto exit_fail;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field16(&reg, PHY_CSR7_DATA, value);
+		rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+		rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
 
-	/*
-	 * Write the data into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field16(&reg, PHY_CSR7_DATA, value);
-	rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
-	rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
+		rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+	}
 
-	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
-
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
-	return;
-
-exit_fail:
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
-	ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -166,122 +173,107 @@
 {
 	u16 reg;
 
-	mutex_lock(&rt2x00dev->usb_cache_mutex);
+	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the read request into the register.
+	 * After the data has been written, we wait until hardware
+	 * returns the correct value, if at any time the register
+	 * doesn't become available in time, reg will be 0xffffffff
+	 * which means we return 0xff to the caller.
 	 */
-	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
-		goto exit_fail;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+		rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
 
-	/*
-	 * Write the request into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
-	rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
+		rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
 
-	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+		if (WAIT_FOR_BBP(rt2x00dev, &reg))
+			rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
+	}
 
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
-		goto exit_fail;
-
-	rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
 	*value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
 
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
-	return;
-
-exit_fail:
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
-	ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
-	*value = 0xff;
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, const u32 value)
 {
 	u16 reg;
-	unsigned int i;
 
 	if (!word)
 		return;
 
-	mutex_lock(&rt2x00dev->usb_cache_mutex);
+	mutex_lock(&rt2x00dev->csr_mutex);
 
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, &reg);
-		if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
-			goto rf_write;
-		udelay(REGISTER_BUSY_DELAY);
+	/*
+	 * Wait until the RF becomes available, afterwards we
+	 * can safely write the new data into the register.
+	 */
+	if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
+		rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
+
+		reg = 0;
+		rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
+		rt2x00_set_field16(&reg, PHY_CSR10_RF_NUMBER_OF_BITS, 20);
+		rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
+		rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
+
+		rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
+		rt2x00_rf_write(rt2x00dev, word, value);
 	}
 
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
-	ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
-	return;
-
-rf_write:
-	reg = 0;
-	rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
-	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
-
-	reg = 0;
-	rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
-	rt2x00_set_field16(&reg, PHY_CSR10_RF_NUMBER_OF_BITS, 20);
-	rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
-	rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
-
-	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
-	rt2x00_rf_write(rt2x00dev, word, value);
-
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u16)) )
-
-static void rt2500usb_read_csr(struct rt2x00_dev *rt2x00dev,
-			       const unsigned int word, u32 *data)
+static void _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
+				     const unsigned int offset,
+				     u32 *value)
 {
-	rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data);
+	rt2500usb_register_read(rt2x00dev, offset, (u16 *)value);
 }
 
-static void rt2500usb_write_csr(struct rt2x00_dev *rt2x00dev,
-				const unsigned int word, u32 data)
+static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
+				      const unsigned int offset,
+				      u32 value)
 {
-	rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
+	rt2500usb_register_write(rt2x00dev, offset, value);
 }
 
 static const struct rt2x00debug rt2500usb_rt2x00debug = {
 	.owner	= THIS_MODULE,
 	.csr	= {
-		.read		= rt2500usb_read_csr,
-		.write		= rt2500usb_write_csr,
+		.read		= _rt2500usb_register_read,
+		.write		= _rt2500usb_register_write,
+		.flags		= RT2X00DEBUGFS_OFFSET,
+		.word_base	= CSR_REG_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= CSR_REG_SIZE / sizeof(u16),
 	},
 	.eeprom	= {
 		.read		= rt2x00_eeprom_read,
 		.write		= rt2x00_eeprom_write,
+		.word_base	= EEPROM_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= EEPROM_SIZE / sizeof(u16),
 	},
 	.bbp	= {
 		.read		= rt2500usb_bbp_read,
 		.write		= rt2500usb_bbp_write,
+		.word_base	= BBP_BASE,
 		.word_size	= sizeof(u8),
 		.word_count	= BBP_SIZE / sizeof(u8),
 	},
 	.rf	= {
 		.read		= rt2x00_rf_read,
 		.write		= rt2500usb_rf_write,
+		.word_base	= RF_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= RF_SIZE / sizeof(u32),
 	},
@@ -338,6 +330,82 @@
 /*
  * Configuration handlers.
  */
+
+/*
+ * rt2500usb does not differentiate between shared and pairwise
+ * keys, so we should use the same function for both key types.
+ */
+static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
+				struct rt2x00lib_crypto *crypto,
+				struct ieee80211_key_conf *key)
+{
+	int timeout;
+	u32 mask;
+	u16 reg;
+
+	if (crypto->cmd == SET_KEY) {
+		/*
+		 * Pairwise key will always be entry 0, but this
+		 * could collide with a shared key on the same
+		 * position...
+		 */
+		mask = TXRX_CSR0_KEY_ID.bit_mask;
+
+		rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+		reg &= mask;
+
+		if (reg && reg == mask)
+			return -ENOSPC;
+
+		reg = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID);
+
+		key->hw_key_idx += reg ? ffz(reg) : 0;
+
+		/*
+		 * The encryption key doesn't fit within the CSR cache,
+		 * this means we should allocate it seperately and use
+		 * rt2x00usb_vendor_request() to send the key to the hardware.
+		 */
+		reg = KEY_ENTRY(key->hw_key_idx);
+		timeout = REGISTER_TIMEOUT32(sizeof(crypto->key));
+		rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
+						    USB_VENDOR_REQUEST_OUT, reg,
+						    crypto->key,
+						    sizeof(crypto->key),
+						    timeout);
+
+		/*
+		 * The driver does not support the IV/EIV generation
+		 * in hardware. However it doesn't support the IV/EIV
+		 * inside the ieee80211 frame either, but requires it
+		 * to be provided seperately for the descriptor.
+		 * rt2x00lib will cut the IV/EIV data out of all frames
+		 * given to us by mac80211, but we must tell mac80211
+		 * to generate the IV/EIV data.
+		 */
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+	}
+
+	/*
+	 * TXRX_CSR0_KEY_ID contains only single-bit fields to indicate
+	 * a particular key is valid.
+	 */
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR0_ALGORITHM, crypto->cipher);
+	rt2x00_set_field16(&reg, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER);
+
+	mask = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID);
+	if (crypto->cmd == SET_KEY)
+		mask |= 1 << key->hw_key_idx;
+	else if (crypto->cmd == DISABLE_KEY)
+		mask &= ~(1 << key->hw_key_idx);
+	rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, mask);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+	return 0;
+}
+
 static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev,
 				    const unsigned int filter_flags)
 {
@@ -380,7 +448,7 @@
 		/*
 		 * Enable beacon config
 		 */
-		bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20);
+		bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20);
 		rt2500usb_register_read(rt2x00dev, TXRX_CSR20, &reg);
 		rt2x00_set_field16(&reg, TXRX_CSR20_OFFSET, bcn_preload >> 6);
 		rt2x00_set_field16(&reg, TXRX_CSR20_BCN_EXPECT_WINDOW,
@@ -423,57 +491,16 @@
 	rt2x00_set_field16(&reg, TXRX_CSR10_AUTORESPOND_PREAMBLE,
 			   !!erp->short_preamble);
 	rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg);
+
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates);
+
+	rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs);
 }
 
-static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev,
-				     const int basic_rate_mask)
-{
-	rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask);
-}
-
-static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
-				     struct rf_channel *rf, const int txpower)
-{
-	/*
-	 * Set TXpower.
-	 */
-	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
-
-	/*
-	 * For RT2525E we should first set the channel to half band higher.
-	 */
-	if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
-		static const u32 vals[] = {
-			0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
-			0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
-			0x000008ba, 0x000008be, 0x000008b7, 0x00000902,
-			0x00000902, 0x00000906
-		};
-
-		rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
-		if (rf->rf4)
-			rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
-	}
-
-	rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
-	rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
-	rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
-	if (rf->rf4)
-		rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
-}
-
-static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
-				     const int txpower)
-{
-	u32 rf3;
-
-	rt2x00_rf_read(rt2x00dev, 3, &rf3);
-	rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
-	rt2500usb_rf_write(rt2x00dev, 3, rf3);
-}
-
-static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
-				     struct antenna_setup *ant)
+static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
+				 struct antenna_setup *ant)
 {
 	u8 r2;
 	u8 r14;
@@ -555,15 +582,52 @@
 	rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6);
 }
 
+static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
+				     struct rf_channel *rf, const int txpower)
+{
+	/*
+	 * Set TXpower.
+	 */
+	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+
+	/*
+	 * For RT2525E we should first set the channel to half band higher.
+	 */
+	if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+		static const u32 vals[] = {
+			0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
+			0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
+			0x000008ba, 0x000008be, 0x000008b7, 0x00000902,
+			0x00000902, 0x00000906
+		};
+
+		rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
+		if (rf->rf4)
+			rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+	}
+
+	rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
+	if (rf->rf4)
+		rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+}
+
+static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+				     const int txpower)
+{
+	u32 rf3;
+
+	rt2x00_rf_read(rt2x00dev, 3, &rf3);
+	rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+	rt2500usb_rf_write(rt2x00dev, 3, rf3);
+}
+
 static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev,
 				      struct rt2x00lib_conf *libconf)
 {
 	u16 reg;
 
-	rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time);
-	rt2500usb_register_write(rt2x00dev, MAC_CSR11, libconf->sifs);
-	rt2500usb_register_write(rt2x00dev, MAC_CSR12, libconf->eifs);
-
 	rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
 	rt2x00_set_field16(&reg, TXRX_CSR18_INTERVAL,
 			   libconf->conf->beacon_int * 4);
@@ -574,17 +638,14 @@
 			     struct rt2x00lib_conf *libconf,
 			     const unsigned int flags)
 {
-	if (flags & CONFIG_UPDATE_PHYMODE)
-		rt2500usb_config_phymode(rt2x00dev, libconf->basic_rates);
-	if (flags & CONFIG_UPDATE_CHANNEL)
+	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt2500usb_config_channel(rt2x00dev, &libconf->rf,
 					 libconf->conf->power_level);
-	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+	if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+	    !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
 		rt2500usb_config_txpower(rt2x00dev,
 					 libconf->conf->power_level);
-	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt2500usb_config_antenna(rt2x00dev, &libconf->ant);
-	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
 		rt2500usb_config_duration(rt2x00dev, libconf);
 }
 
@@ -866,7 +927,7 @@
 
 	rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field16(&reg, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER);
-	rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, 0xff);
+	rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, 0);
 	rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 
 	rt2500usb_register_read(rt2x00dev, MAC_CSR18, &reg);
@@ -1088,7 +1149,7 @@
 	 * Start writing the descriptor words.
 	 */
 	rt2x00_desc_read(txd, 1, &word);
-	rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
 	rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs);
 	rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
 	rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
@@ -1101,6 +1162,11 @@
 	rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
 	rt2x00_desc_write(txd, 2, word);
 
+	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
+		_rt2x00_desc_write(txd, 3, skbdesc->iv[0]);
+		_rt2x00_desc_write(txd, 4, skbdesc->iv[1]);
+	}
+
 	rt2x00_desc_read(txd, 0, &word);
 	rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
 	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
@@ -1115,7 +1181,8 @@
 			   test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
 	rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
 	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
-	rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
+	rt2x00_set_field32(&word, TXD_W0_CIPHER, txdesc->cipher);
+	rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx);
 	rt2x00_desc_write(txd, 0, word);
 }
 
@@ -1130,7 +1197,7 @@
 	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
 	struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
-	int pipe = usb_sndbulkpipe(usb_dev, 1);
+	int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint);
 	int length;
 	u16 reg;
 
@@ -1156,7 +1223,7 @@
 	 * length of the data to usb_fill_bulk_urb. Pass the skb
 	 * to the driver to determine what the length should be.
 	 */
-	length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+	length = rt2x00dev->ops->lib->get_tx_data_len(entry);
 
 	usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
 			  entry->skb->data, length, rt2500usb_beacondone,
@@ -1178,8 +1245,7 @@
 	usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
 }
 
-static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
-				     struct sk_buff *skb)
+static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
 {
 	int length;
 
@@ -1187,8 +1253,8 @@
 	 * The length _must_ be a multiple of 2,
 	 * but it must _not_ be a multiple of the USB packet size.
 	 */
-	length = roundup(skb->len, 2);
-	length += (2 * !(length % rt2x00dev->usb_maxpacket));
+	length = roundup(entry->skb->len, 2);
+	length += (2 * !(length % entry->queue->usb_maxpacket));
 
 	return length;
 }
@@ -1227,6 +1293,7 @@
 static void rt2500usb_fill_rxdone(struct queue_entry *entry,
 				  struct rxdone_entry_desc *rxdesc)
 {
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct queue_entry_priv_usb *entry_priv = entry->priv_data;
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	__le32 *rxd =
@@ -1254,6 +1321,33 @@
 	if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
 		rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC;
 
+	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+		rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER);
+		if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
+			rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY;
+	}
+
+	if (rxdesc->cipher != CIPHER_NONE) {
+		_rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]);
+		_rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]);
+		rxdesc->dev_flags |= RXDONE_CRYPTO_IV;
+
+		/* ICV is located at the end of frame */
+
+		/*
+		 * Hardware has stripped IV/EIV data from 802.11 frame during
+		 * decryption. It has provided the data seperately but rt2x00lib
+		 * should decide if it should be reinserted.
+		 */
+		rxdesc->flags |= RX_FLAG_IV_STRIPPED;
+		if (rxdesc->cipher != CIPHER_TKIP)
+			rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+		if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
+			rxdesc->flags |= RX_FLAG_DECRYPTED;
+		else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
+			rxdesc->flags |= RX_FLAG_MMIC_ERROR;
+	}
+
 	/*
 	 * Obtain the status about this packet.
 	 * When frame was received with an OFDM bitrate,
@@ -1261,8 +1355,8 @@
 	 * a CCK bitrate the signal is the rate in 100kbit/s.
 	 */
 	rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
-	rxdesc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
-	    entry->queue->rt2x00dev->rssi_offset;
+	rxdesc->rssi =
+	    rt2x00_get_field32(word1, RXD_W1_RSSI) - rt2x00dev->rssi_offset;
 	rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
 	if (rt2x00_get_field32(word0, RXD_W0_OFDM))
@@ -1319,10 +1413,8 @@
 	 */
 	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
 	if (!is_valid_ether_addr(mac)) {
-		DECLARE_MAC_BUF(macbuf);
-
 		random_ether_addr(mac);
-		EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+		EEPROM(rt2x00dev, "MAC: %pM\n", mac);
 	}
 
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -1752,6 +1844,10 @@
 	__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
 	__set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
+	if (!modparam_nohwcrypt) {
+		__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+		__set_bit(CONFIG_CRYPTO_COPY_IV, &rt2x00dev->flags);
+	}
 	__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
 
 	/*
@@ -1771,6 +1867,7 @@
 	.config			= rt2x00mac_config,
 	.config_interface	= rt2x00mac_config_interface,
 	.configure_filter	= rt2x00mac_configure_filter,
+	.set_key		= rt2x00mac_set_key,
 	.get_stats		= rt2x00mac_get_stats,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2x00mac_conf_tx,
@@ -1781,8 +1878,7 @@
 	.probe_hw		= rt2500usb_probe_hw,
 	.initialize		= rt2x00usb_initialize,
 	.uninitialize		= rt2x00usb_uninitialize,
-	.init_rxentry		= rt2x00usb_init_rxentry,
-	.init_txentry		= rt2x00usb_init_txentry,
+	.clear_entry		= rt2x00usb_clear_entry,
 	.set_device_state	= rt2500usb_set_device_state,
 	.link_stats		= rt2500usb_link_stats,
 	.reset_tuner		= rt2500usb_reset_tuner,
@@ -1793,9 +1889,12 @@
 	.get_tx_data_len	= rt2500usb_get_tx_data_len,
 	.kick_tx_queue		= rt2500usb_kick_tx_queue,
 	.fill_rxdone		= rt2500usb_fill_rxdone,
+	.config_shared_key	= rt2500usb_config_key,
+	.config_pairwise_key	= rt2500usb_config_key,
 	.config_filter		= rt2500usb_config_filter,
 	.config_intf		= rt2500usb_config_intf,
 	.config_erp		= rt2500usb_config_erp,
+	.config_ant		= rt2500usb_config_ant,
 	.config			= rt2500usb_config,
 };
 
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index 89e5ed2..4347dfd 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -57,7 +57,9 @@
 #define CSR_REG_SIZE			0x0100
 #define EEPROM_BASE			0x0000
 #define EEPROM_SIZE			0x006a
+#define BBP_BASE			0x0000
 #define BBP_SIZE			0x0060
+#define RF_BASE				0x0000
 #define RF_SIZE				0x0014
 
 /*
@@ -445,6 +447,9 @@
 #define SEC_CSR30			0x04bc
 #define SEC_CSR31			0x04be
 
+#define KEY_ENTRY(__idx) \
+	( SEC_CSR0 + ((__idx) * 16) )
+
 /*
  * PHY control registers.
  */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 1359a37..39ecf3b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -44,7 +44,7 @@
 /*
  * Module information.
  */
-#define DRV_VERSION	"2.2.1"
+#define DRV_VERSION	"2.2.3"
 #define DRV_PROJECT	"http://rt2x00.serialmonkey.com"
 
 /*
@@ -92,6 +92,16 @@
 	DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args)
 
 /*
+ * Duration calculations
+ * The rate variable passed is: 100kbs.
+ * To convert from bytes to bits we multiply size with 8,
+ * then the size is multiplied with 10 to make the
+ * real rate -> rate argument correction.
+ */
+#define GET_DURATION(__size, __rate)	(((__size) * 8 * 10) / (__rate))
+#define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate))
+
+/*
  * Standard timing and size defines.
  * These values should follow the ieee80211 specifications.
  */
@@ -109,9 +119,9 @@
 #define DIFS			( PIFS + SLOT_TIME )
 #define SHORT_DIFS		( SHORT_PIFS + SHORT_SLOT_TIME )
 #define EIFS			( SIFS + DIFS + \
-				  (8 * (IEEE80211_HEADER + ACK_SIZE)) )
+				  GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
 #define SHORT_EIFS		( SIFS + SHORT_DIFS + \
-				  (8 * (IEEE80211_HEADER + ACK_SIZE)) )
+				  GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
 
 /*
  * Chipset identification
@@ -348,13 +358,6 @@
 	spinlock_t lock;
 
 	/*
-	 * BSS configuration. Copied from the structure
-	 * passed to us through the bss_info_changed()
-	 * callback funtion.
-	 */
-	struct ieee80211_bss_conf conf;
-
-	/*
 	 * MAC of the device.
 	 */
 	u8 mac[ETH_ALEN];
@@ -433,18 +436,6 @@
 
 	struct rf_channel rf;
 	struct channel_info channel;
-
-	struct antenna_setup ant;
-
-	enum ieee80211_band band;
-
-	u32 basic_rates;
-	u32 slot_time;
-
-	short sifs;
-	short pifs;
-	short difs;
-	short eifs;
 };
 
 /*
@@ -456,6 +447,15 @@
 
 	int ack_timeout;
 	int ack_consume_time;
+
+	u64 basic_rates;
+
+	int slot_time;
+
+	short sifs;
+	short pifs;
+	short difs;
+	short eifs;
 };
 
 /*
@@ -533,10 +533,8 @@
 	/*
 	 * queue initialization handlers
 	 */
-	void (*init_rxentry) (struct rt2x00_dev *rt2x00dev,
-			      struct queue_entry *entry);
-	void (*init_txentry) (struct rt2x00_dev *rt2x00dev,
-			      struct queue_entry *entry);
+	bool (*get_entry_state) (struct queue_entry *entry);
+	void (*clear_entry) (struct queue_entry *entry);
 
 	/*
 	 * Radio control handlers.
@@ -557,8 +555,7 @@
 			       struct txentry_desc *txdesc);
 	int (*write_tx_data) (struct queue_entry *entry);
 	void (*write_beacon) (struct queue_entry *entry);
-	int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
-				struct sk_buff *skb);
+	int (*get_tx_data_len) (struct queue_entry *entry);
 	void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
 			       const enum data_queue_qid queue);
 
@@ -589,16 +586,11 @@
 
 	void (*config_erp) (struct rt2x00_dev *rt2x00dev,
 			    struct rt2x00lib_erp *erp);
+	void (*config_ant) (struct rt2x00_dev *rt2x00dev,
+			    struct antenna_setup *ant);
 	void (*config) (struct rt2x00_dev *rt2x00dev,
 			struct rt2x00lib_conf *libconf,
-			const unsigned int flags);
-#define CONFIG_UPDATE_PHYMODE		( 1 << 1 )
-#define CONFIG_UPDATE_CHANNEL		( 1 << 2 )
-#define CONFIG_UPDATE_TXPOWER		( 1 << 3 )
-#define CONFIG_UPDATE_ANTENNA		( 1 << 4 )
-#define CONFIG_UPDATE_SLOT_TIME 	( 1 << 5 )
-#define CONFIG_UPDATE_BEACON_INT	( 1 << 6 )
-#define CONFIG_UPDATE_ALL		0xffff
+			const unsigned int changed_flags);
 };
 
 /*
@@ -661,6 +653,7 @@
 	CONFIG_EXTERNAL_LNA_BG,
 	CONFIG_DOUBLE_ANTENNA,
 	CONFIG_DISABLE_LINK_TUNING,
+	CONFIG_CRYPTO_COPY_IV,
 };
 
 /*
@@ -738,8 +731,7 @@
 
 	/*
 	 * This is the default TX/RX antenna setup as indicated
-	 * by the device's EEPROM. When mac80211 sets its
-	 * antenna value to 0 we should be using these values.
+	 * by the device's EEPROM.
 	 */
 	struct antenna_setup default_ant;
 
@@ -754,16 +746,15 @@
 	} csr;
 
 	/*
-	 * Mutex to protect register accesses on USB devices.
-	 * There are 2 reasons this is needed, one is to ensure
-	 * use of the csr_cache (for USB devices) by one thread
-	 * isn't corrupted by another thread trying to access it.
-	 * The other is that access to BBP and RF registers
-	 * require multiple BUS transactions and if another thread
-	 * attempted to access one of those registers at the same
-	 * time one of the writes could silently fail.
+	 * Mutex to protect register accesses.
+	 * For PCI and USB devices it protects against concurrent indirect
+	 * register access (BBP, RF, MCU) since accessing those
+	 * registers require multiple calls to the CSR registers.
+	 * For USB devices it also protects the csr_cache since that
+	 * field is used for normal CSR access and it cannot support
+	 * multiple callers simultaneously.
 	 */
-	struct mutex usb_cache_mutex;
+	struct mutex csr_mutex;
 
 	/*
 	 * Current packet filter configuration for the device.
@@ -808,16 +799,17 @@
 	short lna_gain;
 
 	/*
-	 * USB Max frame size (for rt2500usb & rt73usb).
-	 */
-	u16 usb_maxpacket;
-
-	/*
 	 * Current TX power value.
 	 */
 	u16 tx_power;
 
 	/*
+	 * Current retry values.
+	 */
+	u8 short_retry;
+	u8 long_retry;
+
+	/*
 	 * Rssi <-> Dbm offset
 	 */
 	u8 rssi_offset;
@@ -938,23 +930,6 @@
 		!!(chipset->rev & 0x0000f));
 }
 
-/*
- * Duration calculations
- * The rate variable passed is: 100kbs.
- * To convert from bytes to bits we multiply size with 8,
- * then the size is multiplied with 10 to make the
- * real rate -> rate argument correction.
- */
-static inline u16 get_duration(const unsigned int size, const u8 rate)
-{
-	return ((size * 8 * 10) / rate);
-}
-
-static inline u16 get_duration_res(const unsigned int size, const u8 rate)
-{
-	return ((size * 8 * 10) % rate);
-}
-
 /**
  * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
@@ -997,7 +972,7 @@
 			    struct ieee80211_if_init_conf *conf);
 void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
 				struct ieee80211_if_init_conf *conf);
-int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
 int rt2x00mac_config_interface(struct ieee80211_hw *hw,
 			       struct ieee80211_vif *vif,
 			       struct ieee80211_if_conf *conf);
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 4d5e87b..e66fb31 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -86,13 +86,14 @@
 	erp.short_preamble = bss_conf->use_short_preamble;
 	erp.cts_protection = bss_conf->use_cts_prot;
 
-	erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10);
-	erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
+	erp.slot_time = bss_conf->use_short_slot ? SHORT_SLOT_TIME : SLOT_TIME;
+	erp.sifs = SIFS;
+	erp.pifs = bss_conf->use_short_slot ? SHORT_PIFS : PIFS;
+	erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS;
+	erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS;
 
-	if (rt2x00dev->hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME)
-		erp.ack_timeout += SHORT_DIFS;
-	else
-		erp.ack_timeout += DIFS;
+	erp.ack_timeout = PLCP + erp.difs + GET_DURATION(ACK_SIZE, 10);
+	erp.ack_consume_time = SIFS + PLCP + GET_DURATION(ACK_SIZE, 10);
 
 	if (bss_conf->use_short_preamble) {
 		erp.ack_timeout += SHORT_PREAMBLE;
@@ -102,19 +103,39 @@
 		erp.ack_consume_time += PREAMBLE;
 	}
 
+	erp.basic_rates = bss_conf->basic_rates;
+
 	rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp);
 }
 
-void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
-			      enum antenna rx, enum antenna tx)
+static inline
+enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant,
+					    enum antenna default_ant)
 {
-	struct rt2x00lib_conf libconf;
+	if (current_ant != ANTENNA_SW_DIVERSITY)
+		return current_ant;
+	return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B;
+}
 
-	libconf.ant.rx = rx;
-	libconf.ant.tx = tx;
+void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
+			      struct antenna_setup *ant)
+{
+	struct antenna_setup *def = &rt2x00dev->default_ant;
+	struct antenna_setup *active = &rt2x00dev->link.ant.active;
 
-	if (rx == rt2x00dev->link.ant.active.rx &&
-	    tx == rt2x00dev->link.ant.active.tx)
+	/*
+	 * Failsafe: Make sure we are not sending the
+	 * ANTENNA_SW_DIVERSITY state to the driver.
+	 * If that happes fallback to hardware default,
+	 * or our own default.
+	 * The calls to rt2x00lib_config_antenna_check()
+	 * might have caused that we restore back to the already
+	 * active setting. If that has happened we can quit.
+	 */
+	ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx);
+	ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx);
+
+	if (ant->rx == active->rx && ant->tx == active->tx)
 		return;
 
 	/*
@@ -129,119 +150,28 @@
 	 * The latter is required since we need to recalibrate the
 	 * noise-sensitivity ratio for the new setup.
 	 */
-	rt2x00dev->ops->lib->config(rt2x00dev, &libconf, CONFIG_UPDATE_ANTENNA);
+	rt2x00dev->ops->lib->config_ant(rt2x00dev, ant);
+
 	rt2x00lib_reset_link_tuner(rt2x00dev);
 	rt2x00_reset_link_ant_rssi(&rt2x00dev->link);
 
-	rt2x00dev->link.ant.active.rx = libconf.ant.rx;
-	rt2x00dev->link.ant.active.tx = libconf.ant.tx;
+	memcpy(active, ant, sizeof(*ant));
 
 	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
 }
 
-static u32 rt2x00lib_get_basic_rates(struct ieee80211_supported_band *band)
-{
-	const struct rt2x00_rate *rate;
-	unsigned int i;
-	u32 mask = 0;
-
-	for (i = 0; i < band->n_bitrates; i++) {
-		rate = rt2x00_get_rate(band->bitrates[i].hw_value);
-		if (rate->flags & DEV_RATE_BASIC)
-			mask |= rate->ratemask;
-	}
-
-	return mask;
-}
-
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
-		      struct ieee80211_conf *conf, const int force_config)
+		      struct ieee80211_conf *conf,
+		      unsigned int ieee80211_flags)
 {
 	struct rt2x00lib_conf libconf;
-	struct ieee80211_supported_band *band;
-	struct antenna_setup *default_ant = &rt2x00dev->default_ant;
-	struct antenna_setup *active_ant = &rt2x00dev->link.ant.active;
-	int flags = 0;
-	int short_slot_time;
 
-	/*
-	 * In some situations we want to force all configurations
-	 * to be reloaded (When resuming for instance).
-	 */
-	if (force_config) {
-		flags = CONFIG_UPDATE_ALL;
-		goto config;
-	}
-
-	/*
-	 * Check which configuration options have been
-	 * updated and should be send to the device.
-	 */
-	if (rt2x00dev->rx_status.band != conf->channel->band)
-		flags |= CONFIG_UPDATE_PHYMODE;
-	if (rt2x00dev->rx_status.freq != conf->channel->center_freq)
-		flags |= CONFIG_UPDATE_CHANNEL;
-	if (rt2x00dev->tx_power != conf->power_level)
-		flags |= CONFIG_UPDATE_TXPOWER;
-
-	/*
-	 * Determining changes in the antenna setups request several checks:
-	 * antenna_sel_{r,t}x = 0
-	 *    -> Does active_{r,t}x match default_{r,t}x
-	 *    -> Is default_{r,t}x SW_DIVERSITY
-	 * antenna_sel_{r,t}x = 1/2
-	 *    -> Does active_{r,t}x match antenna_sel_{r,t}x
-	 * The reason for not updating the antenna while SW diversity
-	 * should be used is simple: Software diversity means that
-	 * we should switch between the antenna's based on the
-	 * quality. This means that the current antenna is good enough
-	 * to work with untill the link tuner decides that an antenna
-	 * switch should be performed.
-	 */
-	if (!conf->antenna_sel_rx &&
-	    default_ant->rx != ANTENNA_SW_DIVERSITY &&
-	    default_ant->rx != active_ant->rx)
-		flags |= CONFIG_UPDATE_ANTENNA;
-	else if (conf->antenna_sel_rx &&
-		 conf->antenna_sel_rx != active_ant->rx)
-		flags |= CONFIG_UPDATE_ANTENNA;
-	else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
-		flags |= CONFIG_UPDATE_ANTENNA;
-
-	if (!conf->antenna_sel_tx &&
-	    default_ant->tx != ANTENNA_SW_DIVERSITY &&
-	    default_ant->tx != active_ant->tx)
-		flags |= CONFIG_UPDATE_ANTENNA;
-	else if (conf->antenna_sel_tx &&
-		 conf->antenna_sel_tx != active_ant->tx)
-		flags |= CONFIG_UPDATE_ANTENNA;
-	else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
-		flags |= CONFIG_UPDATE_ANTENNA;
-
-	/*
-	 * The following configuration options are never
-	 * stored anywhere and will always be updated.
-	 */
-	flags |= CONFIG_UPDATE_SLOT_TIME;
-	flags |= CONFIG_UPDATE_BEACON_INT;
-
-	/*
-	 * We have determined what options should be updated,
-	 * now precalculate device configuration values depending
-	 * on what configuration options need to be updated.
-	 */
-config:
 	memset(&libconf, 0, sizeof(libconf));
 
-	if (flags & CONFIG_UPDATE_PHYMODE) {
-		band = &rt2x00dev->bands[conf->channel->band];
+	libconf.conf = conf;
 
-		libconf.band = conf->channel->band;
-		libconf.basic_rates = rt2x00lib_get_basic_rates(band);
-	}
-
-	if (flags & CONFIG_UPDATE_CHANNEL) {
+	if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
 		memcpy(&libconf.rf,
 		       &rt2x00dev->spec.channels[conf->channel->hw_value],
 		       sizeof(libconf.rf));
@@ -251,61 +181,23 @@
 		       sizeof(libconf.channel));
 	}
 
-	if (flags & CONFIG_UPDATE_ANTENNA) {
-		if (conf->antenna_sel_rx)
-			libconf.ant.rx = conf->antenna_sel_rx;
-		else if (default_ant->rx != ANTENNA_SW_DIVERSITY)
-			libconf.ant.rx = default_ant->rx;
-		else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
-			libconf.ant.rx = ANTENNA_B;
-		else
-			libconf.ant.rx = active_ant->rx;
-
-		if (conf->antenna_sel_tx)
-			libconf.ant.tx = conf->antenna_sel_tx;
-		else if (default_ant->tx != ANTENNA_SW_DIVERSITY)
-			libconf.ant.tx = default_ant->tx;
-		else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
-			libconf.ant.tx = ANTENNA_B;
-		else
-			libconf.ant.tx = active_ant->tx;
-	}
-
-	if (flags & CONFIG_UPDATE_SLOT_TIME) {
-		short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME;
-
-		libconf.slot_time =
-		    short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME;
-		libconf.sifs = SIFS;
-		libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS;
-		libconf.difs = short_slot_time ? SHORT_DIFS : DIFS;
-		libconf.eifs = short_slot_time ? SHORT_EIFS : EIFS;
-	}
-
-	libconf.conf = conf;
-
 	/*
 	 * Start configuration.
 	 */
-	rt2x00dev->ops->lib->config(rt2x00dev, &libconf, flags);
+	rt2x00dev->ops->lib->config(rt2x00dev, &libconf, ieee80211_flags);
 
 	/*
 	 * Some configuration changes affect the link quality
 	 * which means we need to reset the link tuner.
 	 */
-	if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA))
+	if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt2x00lib_reset_link_tuner(rt2x00dev);
 
-	if (flags & CONFIG_UPDATE_PHYMODE) {
-		rt2x00dev->curr_band = conf->channel->band;
-		rt2x00dev->rx_status.band = conf->channel->band;
-	}
-
-	rt2x00dev->rx_status.freq = conf->channel->center_freq;
+	rt2x00dev->curr_band = conf->channel->band;
 	rt2x00dev->tx_power = conf->power_level;
+	rt2x00dev->short_retry = conf->short_frame_max_tx_count;
+	rt2x00dev->long_retry = conf->long_frame_max_tx_count;
 
-	if (flags & CONFIG_UPDATE_ANTENNA) {
-		rt2x00dev->link.ant.active.rx = libconf.ant.rx;
-		rt2x00dev->link.ant.active.tx = libconf.ant.tx;
-	}
+	rt2x00dev->rx_status.band = conf->channel->band;
+	rt2x00dev->rx_status.freq = conf->channel->center_freq;
 }
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index 5a858e5..37ad0d2 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -46,6 +46,29 @@
 	}
 }
 
+void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
+				       struct txentry_desc *txdesc)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+	struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
+
+	__set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
+
+	txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);
+
+	if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+		__set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags);
+
+	txdesc->key_idx = hw_key->hw_key_idx;
+	txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb);
+
+	if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
+		__set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags);
+
+	if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
+		__set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags);
+}
+
 unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info)
 {
 	struct ieee80211_key_conf *key = tx_info->control.hw_key;
@@ -69,6 +92,18 @@
 	return overhead;
 }
 
+void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len)
+{
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+	unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb);
+
+	if (unlikely(!iv_len))
+		return;
+
+	/* Copy IV/EIV data */
+	memcpy(skbdesc->iv, skb->data + header_length, iv_len);
+}
+
 void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len)
 {
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
@@ -78,10 +113,7 @@
 		return;
 
 	/* Copy IV/EIV data */
-	if (iv_len >= 4)
-		memcpy(&skbdesc->iv, skb->data + header_length, 4);
-	if (iv_len >= 8)
-		memcpy(&skbdesc->eiv, skb->data + header_length + 4, 4);
+	memcpy(skbdesc->iv, skb->data + header_length, iv_len);
 
 	/* Move ieee80211 header */
 	memmove(skb->data + iv_len, skb->data, header_length);
@@ -98,7 +130,7 @@
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
 	unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb);
 	const unsigned int iv_len =
-	    ((!!(skbdesc->iv)) * 4) + ((!!(skbdesc->eiv)) * 4);
+	    ((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4);
 
 	if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED))
 		return;
@@ -109,10 +141,7 @@
 	memmove(skb->data, skb->data + iv_len, header_length);
 
 	/* Copy IV/EIV data */
-	if (iv_len >= 4)
-		memcpy(skb->data + header_length, &skbdesc->iv, 4);
-	if (iv_len >= 8)
-		memcpy(skb->data + header_length + 4, &skbdesc->eiv, 4);
+	memcpy(skb->data + header_length, skbdesc->iv, iv_len);
 
 	/* IV/EIV data has returned into the frame */
 	skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED;
@@ -172,17 +201,9 @@
 		header_length);
 	transfer += header_length;
 
-	/* Copy IV data */
-	if (iv_len >= 4) {
-		memcpy(skb->data + transfer, &rxdesc->iv, 4);
-		transfer += 4;
-	}
-
-	/* Copy EIV data */
-	if (iv_len >= 8) {
-		memcpy(skb->data + transfer, &rxdesc->eiv, 4);
-		transfer += 4;
-	}
+	/* Copy IV/EIV data */
+	memcpy(skb->data + transfer, rxdesc->iv, iv_len);
+	transfer += iv_len;
 
 	/* Move payload */
 	if (align) {
@@ -198,16 +219,14 @@
 	 */
 	transfer += payload_len;
 
-	/* Copy ICV data */
-	if (icv_len >= 4) {
-		memcpy(skb->data + transfer, &rxdesc->icv, 4);
-		/*
-		 * AES appends 8 bytes, we can't fill the upper
-		 * 4 bytes, but mac80211 doesn't care about what
-		 * we provide here anyway and strips it immediately.
-		 */
-		transfer += icv_len;
-	}
+	/*
+	 * Copy ICV data
+	 * AES appends 8 bytes, we can't fill the upper
+	 * 4 bytes, but mac80211 doesn't care about what
+	 * we provide here anyway and strips it immediately.
+	 */
+	memcpy(skb->data + transfer, &rxdesc->icv, 4);
+	transfer += icv_len;
 
 	/* IV/EIV/ICV has been inserted into frame */
 	rxdesc->size = transfer;
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 5cf4c85..54dd100 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -285,7 +285,7 @@
 }
 
 static unsigned int rt2x00debug_poll_queue_dump(struct file *file,
-					        poll_table *wait)
+						poll_table *wait)
 {
 	struct rt2x00debug_intf *intf = file->private_data;
 
@@ -377,7 +377,7 @@
 	if (*offset)
 		return 0;
 
-	data = kzalloc((1 + CIPHER_MAX)* MAX_LINE_LENGTH, GFP_KERNEL);
+	data = kzalloc((1 + CIPHER_MAX) * MAX_LINE_LENGTH, GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -424,16 +424,21 @@
 	const struct rt2x00debug *debug = intf->debug;		\
 	char line[16];						\
 	size_t size;						\
+	unsigned int index = intf->offset_##__name;		\
 	__type value;						\
 								\
 	if (*offset)						\
 		return 0;					\
 								\
-	if (intf->offset_##__name >= debug->__name.word_count)	\
+	if (index >= debug->__name.word_count)			\
 		return -EINVAL;					\
 								\
-	debug->__name.read(intf->rt2x00dev,			\
-			   intf->offset_##__name, &value);	\
+	if (debug->__name.flags & RT2X00DEBUGFS_OFFSET)		\
+		index *= debug->__name.word_size;		\
+								\
+	index += debug->__name.word_base;			\
+								\
+	debug->__name.read(intf->rt2x00dev, index, &value);	\
 								\
 	size = sprintf(line, __format, value);			\
 								\
@@ -454,12 +459,13 @@
 	const struct rt2x00debug *debug = intf->debug;		\
 	char line[16];						\
 	size_t size;						\
+	unsigned int index = intf->offset_##__name;		\
 	__type value;						\
 								\
 	if (*offset)						\
 		return 0;					\
 								\
-	if (intf->offset_##__name >= debug->__name.word_count)	\
+	if (index >= debug->__name.word_count)			\
 		return -EINVAL;					\
 								\
 	if (copy_from_user(line, buf, length))			\
@@ -468,8 +474,12 @@
 	size = strlen(line);					\
 	value = simple_strtoul(line, NULL, 0);			\
 								\
-	debug->__name.write(intf->rt2x00dev,			\
-			    intf->offset_##__name, value);	\
+	if (debug->__name.flags & RT2X00DEBUGFS_OFFSET)		\
+		index *= debug->__name.word_size;		\
+								\
+	index += debug->__name.word_base;			\
+								\
+	debug->__name.write(intf->rt2x00dev, index, value);	\
 								\
 	*offset += size;					\
 	return size;						\
@@ -587,29 +597,29 @@
 	intf->driver_folder =
 	    debugfs_create_dir(intf->rt2x00dev->ops->name,
 			       rt2x00dev->hw->wiphy->debugfsdir);
-	if (IS_ERR(intf->driver_folder))
+	if (IS_ERR(intf->driver_folder) || !intf->driver_folder)
 		goto exit;
 
 	intf->driver_entry =
 	    rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);
-	if (IS_ERR(intf->driver_entry))
+	if (IS_ERR(intf->driver_entry) || !intf->driver_entry)
 		goto exit;
 
 	intf->chipset_entry =
 	    rt2x00debug_create_file_chipset("chipset",
 					    intf, &intf->chipset_blob);
-	if (IS_ERR(intf->chipset_entry))
+	if (IS_ERR(intf->chipset_entry) || !intf->chipset_entry)
 		goto exit;
 
 	intf->dev_flags = debugfs_create_file("dev_flags", S_IRUSR,
 					      intf->driver_folder, intf,
 					      &rt2x00debug_fop_dev_flags);
-	if (IS_ERR(intf->dev_flags))
+	if (IS_ERR(intf->dev_flags) || !intf->dev_flags)
 		goto exit;
 
 	intf->register_folder =
 	    debugfs_create_dir("register", intf->driver_folder);
-	if (IS_ERR(intf->register_folder))
+	if (IS_ERR(intf->register_folder) || !intf->register_folder)
 		goto exit;
 
 #define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name)	\
@@ -619,7 +629,8 @@
 			       S_IRUSR | S_IWUSR,		\
 			       (__intf)->register_folder,	\
 			       &(__intf)->offset_##__name);	\
-	if (IS_ERR((__intf)->__name##_off_entry))		\
+	if (IS_ERR((__intf)->__name##_off_entry)		\
+			|| !(__intf)->__name##_off_entry)	\
 		goto exit;					\
 								\
 	(__intf)->__name##_val_entry =				\
@@ -627,7 +638,8 @@
 				S_IRUSR | S_IWUSR,		\
 				(__intf)->register_folder,	\
 				(__intf), &rt2x00debug_fop_##__name);\
-	if (IS_ERR((__intf)->__name##_val_entry))		\
+	if (IS_ERR((__intf)->__name##_val_entry)		\
+			|| !(__intf)->__name##_val_entry)	\
 		goto exit;					\
 })
 
@@ -640,13 +652,14 @@
 
 	intf->queue_folder =
 	    debugfs_create_dir("queue", intf->driver_folder);
-	if (IS_ERR(intf->queue_folder))
+	if (IS_ERR(intf->queue_folder) || !intf->queue_folder)
 		goto exit;
 
 	intf->queue_frame_dump_entry =
 	    debugfs_create_file("dump", S_IRUSR, intf->queue_folder,
 				intf, &rt2x00debug_fop_queue_dump);
-	if (IS_ERR(intf->queue_frame_dump_entry))
+	if (IS_ERR(intf->queue_frame_dump_entry)
+		|| !intf->queue_frame_dump_entry)
 		goto exit;
 
 	skb_queue_head_init(&intf->frame_dump_skbqueue);
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h
index c4ce895..a92104d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.h
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.h
@@ -28,6 +28,16 @@
 
 struct rt2x00_dev;
 
+/**
+ * enum rt2x00debugfs_entry_flags: Flags for debugfs registry entry
+ *
+ * @RT2X00DEBUGFS_OFFSET: rt2x00lib should pass the register offset
+ *	as argument when using the callback function read()/write()
+ */
+enum rt2x00debugfs_entry_flags {
+	RT2X00DEBUGFS_OFFSET	= (1 << 0),
+};
+
 #define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type)		\
 struct reg##__name {						\
 	void (*read)(struct rt2x00_dev *rt2x00dev,		\
@@ -35,6 +45,9 @@
 	void (*write)(struct rt2x00_dev *rt2x00dev,		\
 		      const unsigned int word, __type data);	\
 								\
+	unsigned int flags;					\
+								\
+	unsigned int word_base;					\
 	unsigned int word_size;					\
 	unsigned int word_count;				\
 } __name
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 86840e3..6d92542 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -101,8 +101,7 @@
 	/*
 	 * Initialize all data queues.
 	 */
-	rt2x00queue_init_rx(rt2x00dev);
-	rt2x00queue_init_tx(rt2x00dev);
+	rt2x00queue_init_queues(rt2x00dev);
 
 	/*
 	 * Enable radio.
@@ -176,13 +175,14 @@
 
 static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev)
 {
-	enum antenna rx = rt2x00dev->link.ant.active.rx;
-	enum antenna tx = rt2x00dev->link.ant.active.tx;
+	struct antenna_setup ant;
 	int sample_a =
 	    rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_A);
 	int sample_b =
 	    rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_B);
 
+	memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant));
+
 	/*
 	 * We are done sampling. Now we should evaluate the results.
 	 */
@@ -200,21 +200,22 @@
 		return;
 
 	if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY)
-		rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
+		ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
 
 	if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)
-		tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
+		ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
 
-	rt2x00lib_config_antenna(rt2x00dev, rx, tx);
+	rt2x00lib_config_antenna(rt2x00dev, &ant);
 }
 
 static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev)
 {
-	enum antenna rx = rt2x00dev->link.ant.active.rx;
-	enum antenna tx = rt2x00dev->link.ant.active.tx;
+	struct antenna_setup ant;
 	int rssi_curr = rt2x00_get_link_ant_rssi(&rt2x00dev->link);
 	int rssi_old = rt2x00_update_ant_rssi(&rt2x00dev->link, rssi_curr);
 
+	memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant));
+
 	/*
 	 * Legacy driver indicates that we should swap antenna's
 	 * when the difference in RSSI is greater that 5. This
@@ -230,12 +231,12 @@
 	rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE;
 
 	if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY)
-		rx = (rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
+		ant.rx = (ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
 
 	if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)
-		tx = (tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
+		ant.tx = (ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
 
-	rt2x00lib_config_antenna(rt2x00dev, rx, tx);
+	rt2x00lib_config_antenna(rt2x00dev, &ant);
 }
 
 static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev)
@@ -249,11 +250,9 @@
 	rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY;
 	rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY;
 
-	if (rt2x00dev->hw->conf.antenna_sel_rx == 0 &&
-	    rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
+	if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
 		rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY;
-	if (rt2x00dev->hw->conf.antenna_sel_tx == 0 &&
-	    rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
+	if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
 		rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY;
 
 	if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) &&
@@ -419,7 +418,7 @@
 	 */
 	spin_lock(&intf->lock);
 
-	memcpy(&conf, &intf->conf, sizeof(conf));
+	memcpy(&conf, &vif->bss_conf, sizeof(conf));
 	delayed_flags = intf->delayed_flags;
 	intf->delayed_flags = 0;
 
@@ -500,7 +499,9 @@
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
+	u8 rate_idx, rate_flags;
 
 	/*
 	 * Unmap the skb.
@@ -530,14 +531,18 @@
 	rt2x00dev->link.qual.tx_failed +=
 	    test_bit(TXDONE_FAILURE, &txdesc->flags);
 
+	rate_idx = skbdesc->tx_rate_idx;
+	rate_flags = skbdesc->tx_rate_flags;
+
 	/*
 	 * Initialize TX status
 	 */
 	memset(&tx_info->status, 0, sizeof(tx_info->status));
 	tx_info->status.ack_signal = 0;
-	tx_info->status.excessive_retries =
-	    test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags);
-	tx_info->status.retry_count = txdesc->retry;
+	tx_info->status.rates[0].idx = rate_idx;
+	tx_info->status.rates[0].flags = rate_flags;
+	tx_info->status.rates[0].count = txdesc->retry + 1;
+	tx_info->status.rates[1].idx = -1; /* terminate */
 
 	if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
 		if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
@@ -546,7 +551,7 @@
 			rt2x00dev->low_level_stats.dot11ACKFailureCount++;
 	}
 
-	if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+	if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
 		if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
 			rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
 		else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
@@ -570,7 +575,7 @@
 	entry->skb = NULL;
 	entry->flags = 0;
 
-	rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry);
+	rt2x00dev->ops->lib->clear_entry(entry);
 
 	clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
 	rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
@@ -631,7 +636,8 @@
 	 * provided seperately (through hardware descriptor)
 	 * in which case we should reinsert the data into the frame.
 	 */
-	if ((rxdesc.flags & RX_FLAG_IV_STRIPPED)) {
+	if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) &&
+	    (rxdesc.flags & RX_FLAG_IV_STRIPPED)) {
 		rt2x00crypto_rx_insert_iv(entry->skb, align,
 					  header_length, &rxdesc);
 	} else if (align) {
@@ -702,7 +708,7 @@
 	entry->skb = skb;
 	entry->flags = 0;
 
-	rt2x00dev->ops->lib->init_rxentry(rt2x00dev, entry);
+	rt2x00dev->ops->lib->clear_entry(entry);
 
 	rt2x00queue_index_inc(entry->queue, Q_INDEX);
 }
@@ -713,31 +719,31 @@
  */
 const struct rt2x00_rate rt2x00_supported_rates[12] = {
 	{
-		.flags = DEV_RATE_CCK | DEV_RATE_BASIC,
+		.flags = DEV_RATE_CCK,
 		.bitrate = 10,
 		.ratemask = BIT(0),
 		.plcp = 0x00,
 	},
 	{
-		.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC,
+		.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
 		.bitrate = 20,
 		.ratemask = BIT(1),
 		.plcp = 0x01,
 	},
 	{
-		.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC,
+		.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
 		.bitrate = 55,
 		.ratemask = BIT(2),
 		.plcp = 0x02,
 	},
 	{
-		.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC,
+		.flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
 		.bitrate = 110,
 		.ratemask = BIT(3),
 		.plcp = 0x03,
 	},
 	{
-		.flags = DEV_RATE_OFDM | DEV_RATE_BASIC,
+		.flags = DEV_RATE_OFDM,
 		.bitrate = 60,
 		.ratemask = BIT(4),
 		.plcp = 0x0b,
@@ -749,7 +755,7 @@
 		.plcp = 0x0f,
 	},
 	{
-		.flags = DEV_RATE_OFDM | DEV_RATE_BASIC,
+		.flags = DEV_RATE_OFDM,
 		.bitrate = 120,
 		.ratemask = BIT(6),
 		.plcp = 0x0a,
@@ -761,7 +767,7 @@
 		.plcp = 0x0e,
 	},
 	{
-		.flags = DEV_RATE_OFDM | DEV_RATE_BASIC,
+		.flags = DEV_RATE_OFDM,
 		.bitrate = 240,
 		.ratemask = BIT(8),
 		.plcp = 0x09,
@@ -1046,16 +1052,24 @@
 {
 	int retval = -ENOMEM;
 
+	mutex_init(&rt2x00dev->csr_mutex);
+
 	/*
 	 * Make room for rt2x00_intf inside the per-interface
 	 * structure ieee80211_vif.
 	 */
 	rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf);
 
-	rt2x00dev->hw->wiphy->interface_modes =
-	    BIT(NL80211_IFTYPE_AP) |
-	    BIT(NL80211_IFTYPE_STATION) |
-	    BIT(NL80211_IFTYPE_ADHOC);
+	/*
+	 * Determine which operating modes are supported, all modes
+	 * which require beaconing, depend on the availability of
+	 * beacon entries.
+	 */
+	rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+	if (rt2x00dev->ops->bcn->entry_num > 0)
+		rt2x00dev->hw->wiphy->interface_modes |=
+		    BIT(NL80211_IFTYPE_ADHOC) |
+		    BIT(NL80211_IFTYPE_AP);
 
 	/*
 	 * Let the driver probe the device to detect the capabilities.
@@ -1247,7 +1261,7 @@
 	/*
 	 * Reconfigure device.
 	 */
-	retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf);
+	retval = rt2x00mac_config(rt2x00dev->hw, ~0);
 	if (retval)
 		goto exit;
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c
index b362a1c..68f4e0f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00leds.c
+++ b/drivers/net/wireless/rt2x00/rt2x00leds.c
@@ -72,49 +72,33 @@
 	}
 }
 
-void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled)
+static void rt2x00led_led_simple(struct rt2x00_led *led, bool enabled)
 {
-	struct rt2x00_led *led = &rt2x00dev->led_qual;
-	unsigned int brightness;
+	unsigned int brightness = enabled ? LED_FULL : LED_OFF;
 
-	if ((led->type != LED_TYPE_ACTIVITY) || !(led->flags & LED_REGISTERED))
+	if (!(led->flags & LED_REGISTERED))
 		return;
 
-	brightness = enabled ? LED_FULL : LED_OFF;
-	if (brightness != led->led_dev.brightness) {
-		led->led_dev.brightness_set(&led->led_dev, brightness);
-		led->led_dev.brightness = brightness;
-	}
+	led->led_dev.brightness_set(&led->led_dev, brightness);
+	led->led_dev.brightness = brightness;
+}
+
+void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled)
+{
+	if (rt2x00dev->led_qual.type == LED_TYPE_ACTIVITY)
+		rt2x00led_led_simple(&rt2x00dev->led_qual, enabled);
 }
 
 void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled)
 {
-	struct rt2x00_led *led = &rt2x00dev->led_assoc;
-	unsigned int brightness;
-
-	if ((led->type != LED_TYPE_ASSOC) || !(led->flags & LED_REGISTERED))
-		return;
-
-	brightness = enabled ? LED_FULL : LED_OFF;
-	if (brightness != led->led_dev.brightness) {
-		led->led_dev.brightness_set(&led->led_dev, brightness);
-		led->led_dev.brightness = brightness;
-	}
+	if (rt2x00dev->led_assoc.type == LED_TYPE_ASSOC)
+		rt2x00led_led_simple(&rt2x00dev->led_assoc, enabled);
 }
 
 void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled)
 {
-	struct rt2x00_led *led = &rt2x00dev->led_radio;
-	unsigned int brightness;
-
-	if ((led->type != LED_TYPE_RADIO) || !(led->flags & LED_REGISTERED))
-		return;
-
-	brightness = enabled ? LED_FULL : LED_OFF;
-	if (brightness != led->led_dev.brightness) {
-		led->led_dev.brightness_set(&led->led_dev, brightness);
-		led->led_dev.brightness = brightness;
-	}
+	if (rt2x00dev->led_radio.type == LED_TYPE_ASSOC)
+		rt2x00led_led_simple(&rt2x00dev->led_radio, enabled);
 }
 
 static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
@@ -125,6 +109,7 @@
 	int retval;
 
 	led->led_dev.name = name;
+	led->led_dev.brightness = LED_OFF;
 
 	retval = led_classdev_register(device, &led->led_dev);
 	if (retval) {
@@ -199,7 +184,16 @@
 static void rt2x00leds_unregister_led(struct rt2x00_led *led)
 {
 	led_classdev_unregister(&led->led_dev);
-	led->led_dev.brightness_set(&led->led_dev, LED_OFF);
+
+	/*
+	 * This might look weird, but when we are unregistering while
+	 * suspended the led is already off, and since we haven't
+	 * fully resumed yet, access to the device might not be
+	 * possible yet.
+	 */
+	if (!(led->led_dev.flags & LED_SUSPENDED))
+		led->led_dev.brightness_set(&led->led_dev, LED_OFF);
+
 	led->flags &= ~LED_REGISTERED;
 }
 
@@ -213,22 +207,40 @@
 		rt2x00leds_unregister_led(&rt2x00dev->led_radio);
 }
 
+static inline void rt2x00leds_suspend_led(struct rt2x00_led *led)
+{
+	led_classdev_suspend(&led->led_dev);
+
+	/* This shouldn't be needed, but just to be safe */
+	led->led_dev.brightness_set(&led->led_dev, LED_OFF);
+	led->led_dev.brightness = LED_OFF;
+}
+
 void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev)
 {
 	if (rt2x00dev->led_qual.flags & LED_REGISTERED)
-		led_classdev_suspend(&rt2x00dev->led_qual.led_dev);
+		rt2x00leds_suspend_led(&rt2x00dev->led_qual);
 	if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
-		led_classdev_suspend(&rt2x00dev->led_assoc.led_dev);
+		rt2x00leds_suspend_led(&rt2x00dev->led_assoc);
 	if (rt2x00dev->led_radio.flags & LED_REGISTERED)
-		led_classdev_suspend(&rt2x00dev->led_radio.led_dev);
+		rt2x00leds_suspend_led(&rt2x00dev->led_radio);
+}
+
+static inline void rt2x00leds_resume_led(struct rt2x00_led *led)
+{
+	led_classdev_resume(&led->led_dev);
+
+	/* Device might have enabled the LEDS during resume */
+	led->led_dev.brightness_set(&led->led_dev, LED_OFF);
+	led->led_dev.brightness = LED_OFF;
 }
 
 void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev)
 {
 	if (rt2x00dev->led_radio.flags & LED_REGISTERED)
-		led_classdev_resume(&rt2x00dev->led_radio.led_dev);
+		rt2x00leds_resume_led(&rt2x00dev->led_radio);
 	if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
-		led_classdev_resume(&rt2x00dev->led_assoc.led_dev);
+		rt2x00leds_resume_led(&rt2x00dev->led_assoc);
 	if (rt2x00dev->led_qual.flags & LED_REGISTERED)
-		led_classdev_resume(&rt2x00dev->led_qual.led_dev);
+		rt2x00leds_resume_led(&rt2x00dev->led_qual);
 }
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 797eb61..0302432 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -43,7 +43,6 @@
 #define DEV_RATE_CCK			0x0001
 #define DEV_RATE_OFDM			0x0002
 #define DEV_RATE_SHORT_PREAMBLE		0x0004
-#define DEV_RATE_BASIC			0x0008
 
 	unsigned short bitrate; /* In 100kbit/s */
 	unsigned short ratemask;
@@ -94,9 +93,10 @@
 			  struct rt2x00_intf *intf,
 			  struct ieee80211_bss_conf *conf);
 void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
-			      enum antenna rx, enum antenna tx);
+			      struct antenna_setup *ant);
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
-		      struct ieee80211_conf *conf, const int force_config);
+		      struct ieee80211_conf *conf,
+		      const unsigned int changed_flags);
 
 /**
  * DOC: Queue handlers
@@ -150,8 +150,16 @@
  */
 void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
 
-void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev);
-void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev);
+/**
+ * rt2x00queue_init_queues - Initialize all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * This function will loop through all available queues to clear all
+ * index numbers and set the queue entry to the correct initialization
+ * state.
+ */
+void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev);
+
 int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev);
 void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev);
 int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev);
@@ -210,7 +218,10 @@
  */
 #ifdef CONFIG_RT2X00_LIB_CRYPTO
 enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key);
+void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
+				       struct txentry_desc *txdesc);
 unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info);
+void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len);
 void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len);
 void rt2x00crypto_tx_insert_iv(struct sk_buff *skb);
 void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align,
@@ -222,11 +233,21 @@
 	return CIPHER_NONE;
 }
 
+static inline void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
+						     struct txentry_desc *txdesc)
+{
+}
+
 static inline unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info)
 {
 	return 0;
 }
 
+static inline void rt2x00crypto_tx_copy_iv(struct sk_buff *skb,
+					   unsigned int iv_len)
+{
+}
+
 static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb,
 					     unsigned int iv_len)
 {
@@ -242,7 +263,7 @@
 					     struct rxdone_entry_desc *rxdesc)
 {
 }
-#endif
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */
 
 /*
  * RFkill handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 2c6cc5c..38edee5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -39,7 +39,7 @@
 	unsigned int data_length;
 	int retval = 0;
 
-	if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
 		data_length = sizeof(struct ieee80211_cts);
 	else
 		data_length = sizeof(struct ieee80211_rts);
@@ -64,11 +64,11 @@
 	 */
 	memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
 	rts_info = IEEE80211_SKB_CB(skb);
-	rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS;
-	rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
+	rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS;
+	rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT;
 	rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
 
-	if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
 		rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
 	else
 		rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
@@ -79,12 +79,10 @@
 	 * RTS/CTS frame should use the length of the frame plus any
 	 * encryption overhead that will be added by the hardware.
 	 */
-#ifdef CONFIG_RT2X00_LIB_CRYPTO
 	if (!frag_skb->do_not_encrypt)
 		data_length += rt2x00crypto_tx_overhead(tx_info);
-#endif /* CONFIG_RT2X00_LIB_CRYPTO */
 
-	if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
 		ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
 					frag_skb->data, data_length, tx_info,
 					(struct ieee80211_cts *)(skb->data));
@@ -132,8 +130,7 @@
 		ERROR(rt2x00dev,
 		      "Attempt to send packet over invalid queue %d.\n"
 		      "Please file bug report to %s.\n", qid, DRV_PROJECT);
-		dev_kfree_skb_any(skb);
-		return NETDEV_TX_OK;
+		goto exit_fail;
 	}
 
 	/*
@@ -146,8 +143,8 @@
 	 * inside the hardware.
 	 */
 	frame_control = le16_to_cpu(ieee80211hdr->frame_control);
-	if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS |
-			       IEEE80211_TX_CTL_USE_CTS_PROTECT)) &&
+	if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS |
+						IEEE80211_TX_RC_USE_CTS_PROTECT)) &&
 	    !rt2x00dev->ops->hw->set_rts_threshold) {
 		if (rt2x00queue_available(queue) <= 1)
 			goto exit_fail;
@@ -335,10 +332,10 @@
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
 
-int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	int radio_on;
+	struct ieee80211_conf *conf = &hw->conf;
 	int status;
 
 	/*
@@ -355,7 +352,6 @@
 	 * some configuration parameters (e.g. channel and antenna values) can
 	 * only be set when the radio is enabled.
 	 */
-	radio_on = test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags);
 	if (conf->radio_enabled) {
 		/* For programming the values, we have to turn RX off */
 		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
@@ -369,7 +365,18 @@
 		 * When we've just turned on the radio, we want to reprogram
 		 * everything to ensure a consistent state
 		 */
-		rt2x00lib_config(rt2x00dev, conf, !radio_on);
+		rt2x00lib_config(rt2x00dev, conf, changed);
+
+		/*
+		 * The radio was enabled, configure the antenna to the
+		 * default settings, the link tuner will later start
+		 * continue configuring the antenna based on the software
+		 * diversity. But for non-diversity configurations, we need
+		 * to have configured the correct state now.
+		 */
+		if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED)
+			rt2x00lib_config_antenna(rt2x00dev,
+						 &rt2x00dev->default_ant);
 
 		/* Turn RX back on */
 		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
@@ -480,12 +487,15 @@
 		      struct ieee80211_key_conf *key)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct ieee80211_sta *sta;
 	int (*set_key) (struct rt2x00_dev *rt2x00dev,
 			struct rt2x00lib_crypto *crypto,
 			struct ieee80211_key_conf *key);
 	struct rt2x00lib_crypto crypto;
 
-	if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+		return 0;
+	else if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
 		return -EOPNOTSUPP;
 	else if (key->keylen > 32)
 		return -ENOSPC;
@@ -528,6 +538,17 @@
 		memcpy(&crypto.key, &key->key[0], key->keylen);
 
 	/*
+	 * Discover the Association ID from mac80211.
+	 * Some drivers need this information when updating the
+	 * hardware key (either adding or removing).
+	 */
+	rcu_read_lock();
+	sta = ieee80211_find_sta(hw, address);
+	if (sta)
+		crypto.aid = sta->aid;
+	rcu_read_unlock();
+
+	/*
 	 * Each BSS has a maximum of 4 shared keys.
 	 * Shared key index values:
 	 *	0) BSS0 key0
@@ -625,7 +646,7 @@
 	 * When the erp information has changed, we should perform
 	 * additional configuration steps. For all other changes we are done.
 	 */
-	if (changes & (BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_CTS_PROT)) {
+	if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
 		if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
 			rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
 		else
@@ -633,7 +654,6 @@
 	}
 
 	spin_lock(&intf->lock);
-	memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
 	if (delayed) {
 		intf->delayed_flags |= delayed;
 		schedule_work(&rt2x00dev->intf_work);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index adf2876..d52b22b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -32,24 +32,46 @@
 #include "rt2x00pci.h"
 
 /*
+ * Register access.
+ */
+int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
+			   const unsigned int offset,
+			   const struct rt2x00_field32 field,
+			   u32 *reg)
+{
+	unsigned int i;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00pci_register_read(rt2x00dev, offset, reg);
+		if (!rt2x00_get_field32(*reg, field))
+			return 1;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "Indirect register access failed: "
+	      "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+	*reg = ~0;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
+
+/*
  * TX data handlers.
  */
 int rt2x00pci_write_tx_data(struct queue_entry *entry)
 {
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
 	struct skb_frame_desc *skbdesc;
-	u32 word;
-
-	rt2x00_desc_read(entry_priv->desc, 0, &word);
 
 	/*
 	 * This should not happen, we already checked the entry
 	 * was ours. When the hardware disagrees there has been
 	 * a queue corruption!
 	 */
-	if (unlikely(rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
-		     rt2x00_get_field32(word, TXD_ENTRY_VALID))) {
-		ERROR(entry->queue->rt2x00dev,
+	if (unlikely(rt2x00dev->ops->lib->get_entry_state(entry))) {
+		ERROR(rt2x00dev,
 		      "Corrupt queue %d, accessing entry which is not ours.\n"
 		      "Please file bug report to %s.\n",
 		      entry->queue->qid, DRV_PROJECT);
@@ -76,14 +98,12 @@
 	struct queue_entry *entry;
 	struct queue_entry_priv_pci *entry_priv;
 	struct skb_frame_desc *skbdesc;
-	u32 word;
 
 	while (1) {
 		entry = rt2x00queue_get_entry(queue, Q_INDEX);
 		entry_priv = entry->priv_data;
-		rt2x00_desc_read(entry_priv->desc, 0, &word);
 
-		if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
+		if (rt2x00dev->ops->lib->get_entry_state(entry))
 			break;
 
 		/*
@@ -222,8 +242,7 @@
 {
 	struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
 
-	rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0),
-				      pci_resource_len(pci_dev, 0));
+	rt2x00dev->csr.base = pci_ioremap_bar(pci_dev, 0);
 	if (!rt2x00dev->csr.base)
 		goto exit;
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 80bf97c..9c0a4d7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -44,21 +44,10 @@
 #define REGISTER_BUSY_DELAY	100
 
 /*
- * Descriptor availability flags.
- * All PCI device descriptors have these 2 flags
- * with the exact same definition.
- * By storing them here we can use them inside rt2x00pci
- * for some simple entry availability checking.
- */
-#define TXD_ENTRY_OWNER_NIC	FIELD32(0x00000001)
-#define TXD_ENTRY_VALID		FIELD32(0x00000002)
-#define RXD_ENTRY_OWNER_NIC	FIELD32(0x00000001)
-
-/*
  * Register access.
  */
 static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
-					   const unsigned long offset,
+					   const unsigned int offset,
 					   u32 *value)
 {
 	*value = readl(rt2x00dev->csr.base + offset);
@@ -66,14 +55,14 @@
 
 static inline void
 rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev,
-			     const unsigned long offset,
+			     const unsigned int offset,
 			     void *value, const u16 length)
 {
 	memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
 }
 
 static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
-					    const unsigned long offset,
+					    const unsigned int offset,
 					    u32 value)
 {
 	writel(value, rt2x00dev->csr.base + offset);
@@ -81,13 +70,31 @@
 
 static inline void
 rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
-			      const unsigned long offset,
+			      const unsigned int offset,
 			      const void *value, const u16 length)
 {
 	memcpy_toio(rt2x00dev->csr.base + offset, value, length);
 }
 
 /**
+ * rt2x00pci_regbusy_read - Read from register with busy check
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @field: Field to check if register is busy
+ * @reg: Pointer to where register contents should be stored
+ *
+ * This function will read the given register, and checks if the
+ * register is busy. If it is, it will sleep for a couple of
+ * microseconds before reading the register again. If the register
+ * is not read after a certain timeout, this function will return
+ * FALSE.
+ */
+int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
+			   const unsigned int offset,
+			   const struct rt2x00_field32 field,
+			   u32 *reg);
+
+/**
  * rt2x00pci_write_tx_data - Initialize data for TX operation
  * @entry: The entry where the frame is located
  *
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 451d410..eaec6bd 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -55,14 +55,12 @@
 	/*
 	 * For IV/EIV/ICV assembly we must make sure there is
 	 * at least 8 bytes bytes available in headroom for IV/EIV
-	 * and 4 bytes for ICV data as tailroon.
+	 * and 8 bytes for ICV data as tailroon.
 	 */
-#ifdef CONFIG_RT2X00_LIB_CRYPTO
 	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
 		head_size += 8;
-		tail_size += 4;
+		tail_size += 8;
 	}
-#endif /* CONFIG_RT2X00_LIB_CRYPTO */
 
 	/*
 	 * Allocate skbuffer.
@@ -174,7 +172,7 @@
 	txdesc->cw_max = entry->queue->cw_max;
 	txdesc->aifs = entry->queue->aifs;
 
-	/* Data length + CRC + IV/EIV/ICV/MMIC (when using encryption) */
+	/* Data length + CRC */
 	data_length = entry->skb->len + 4;
 
 	/*
@@ -183,34 +181,17 @@
 	if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK))
 		__set_bit(ENTRY_TXD_ACK, &txdesc->flags);
 
-#ifdef CONFIG_RT2X00_LIB_CRYPTO
 	if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) &&
 	    !entry->skb->do_not_encrypt) {
-		struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
-
-		__set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
-
-		txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);
-
-		if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
-			__set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags);
-
-		txdesc->key_idx = hw_key->hw_key_idx;
-		txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb);
+		/* Apply crypto specific descriptor information */
+		rt2x00crypto_create_tx_descriptor(entry, txdesc);
 
 		/*
 		 * Extend frame length to include all encryption overhead
 		 * that will be added by the hardware.
 		 */
 		data_length += rt2x00crypto_tx_overhead(tx_info);
-
-		if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
-			__set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags);
-
-		if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
-			__set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags);
 	}
-#endif /* CONFIG_RT2X00_LIB_CRYPTO */
 
 	/*
 	 * Check if this is a RTS/CTS frame
@@ -230,8 +211,8 @@
 	/*
 	 * Determine retry information.
 	 */
-	txdesc->retry_limit = tx_info->control.retry_limit;
-	if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
+	txdesc->retry_limit = tx_info->control.rates[0].count - 1;
+	if (txdesc->retry_limit >= rt2x00dev->long_retry)
 		__set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags);
 
 	/*
@@ -312,8 +293,8 @@
 		/*
 		 * Convert length to microseconds.
 		 */
-		residual = get_duration_res(data_length, hwrate->bitrate);
-		duration = get_duration(data_length, hwrate->bitrate);
+		residual = GET_DURATION_RES(data_length, hwrate->bitrate);
+		duration = GET_DURATION(data_length, hwrate->bitrate);
 
 		if (residual != 0) {
 			duration++;
@@ -371,13 +352,15 @@
 
 int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
 {
+	struct ieee80211_tx_info *tx_info;
 	struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
 	struct txentry_desc txdesc;
 	struct skb_frame_desc *skbdesc;
 	unsigned int iv_len = 0;
+	u8 rate_idx, rate_flags;
 
 	if (unlikely(rt2x00queue_full(queue)))
-		return -EINVAL;
+		return -ENOBUFS;
 
 	if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
 		ERROR(queue->rt2x00dev,
@@ -399,13 +382,18 @@
 		iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len;
 
 	/*
-	 * All information is retreived from the skb->cb array,
+	 * All information is retrieved from the skb->cb array,
 	 * now we should claim ownership of the driver part of that
-	 * array.
+	 * array, preserving the bitrate index and flags.
 	 */
-	skbdesc = get_skb_frame_desc(entry->skb);
+	tx_info = IEEE80211_SKB_CB(skb);
+	rate_idx = tx_info->control.rates[0].idx;
+	rate_flags = tx_info->control.rates[0].flags;
+	skbdesc = get_skb_frame_desc(skb);
 	memset(skbdesc, 0, sizeof(*skbdesc));
 	skbdesc->entry = entry;
+	skbdesc->tx_rate_idx = rate_idx;
+	skbdesc->tx_rate_flags = rate_flags;
 
 	/*
 	 * When hardware encryption is supported, and this frame
@@ -414,19 +402,21 @@
 	 */
 	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
 	    !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) {
-		rt2x00crypto_tx_remove_iv(skb, iv_len);
+		if (test_bit(CONFIG_CRYPTO_COPY_IV, &queue->rt2x00dev->flags))
+			rt2x00crypto_tx_copy_iv(skb, iv_len);
+		else
+			rt2x00crypto_tx_remove_iv(skb, iv_len);
 	}
 
 	/*
 	 * It could be possible that the queue was corrupted and this
-	 * call failed. Just drop the frame, we cannot rollback and pass
-	 * the frame to mac80211 because the skb->cb has now been tainted.
+	 * call failed. Since we always return NETDEV_TX_OK to mac80211,
+	 * this frame will simply be dropped.
 	 */
 	if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
 		clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-		dev_kfree_skb_any(entry->skb);
 		entry->skb = NULL;
-		return 0;
+		return -EIO;
 	}
 
 	if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
@@ -556,7 +546,7 @@
 		queue->length++;
 	} else if (index == Q_INDEX_DONE) {
 		queue->length--;
-		queue->count ++;
+		queue->count++;
 	}
 
 	spin_unlock_irqrestore(&queue->lock, irqflags);
@@ -575,40 +565,18 @@
 	spin_unlock_irqrestore(&queue->lock, irqflags);
 }
 
-void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev)
-{
-	struct data_queue *queue = rt2x00dev->rx;
-	unsigned int i;
-
-	rt2x00queue_reset(queue);
-
-	if (!rt2x00dev->ops->lib->init_rxentry)
-		return;
-
-	for (i = 0; i < queue->limit; i++) {
-		queue->entries[i].flags = 0;
-
-		rt2x00dev->ops->lib->init_rxentry(rt2x00dev,
-						  &queue->entries[i]);
-	}
-}
-
-void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev)
+void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
 {
 	struct data_queue *queue;
 	unsigned int i;
 
-	txall_queue_for_each(rt2x00dev, queue) {
+	queue_for_each(rt2x00dev, queue) {
 		rt2x00queue_reset(queue);
 
-		if (!rt2x00dev->ops->lib->init_txentry)
-			continue;
-
 		for (i = 0; i < queue->limit; i++) {
 			queue->entries[i].flags = 0;
 
-			rt2x00dev->ops->lib->init_txentry(rt2x00dev,
-							  &queue->entries[i]);
+			rt2x00dev->ops->lib->clear_entry(&queue->entries[i]);
 		}
 	}
 }
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 9dbf04f..28293715 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -104,22 +104,25 @@
  *
  * @flags: Frame flags, see &enum skb_frame_desc_flags.
  * @desc_len: Length of the frame descriptor.
+ * @tx_rate_idx: the index of the TX rate, used for TX status reporting
+ * @tx_rate_flags: the TX rate flags, used for TX status reporting
  * @desc: Pointer to descriptor part of the frame.
  *	Note that this pointer could point to something outside
  *	of the scope of the skb->data pointer.
- * @iv: IV data used during encryption/decryption.
- * @eiv: EIV data used during encryption/decryption.
+ * @iv: IV/EIV data used during encryption/decryption.
  * @skb_dma: (PCI-only) the DMA address associated with the sk buffer.
  * @entry: The entry to which this sk buffer belongs.
  */
 struct skb_frame_desc {
-	unsigned int flags;
+	u8 flags;
 
-	unsigned int desc_len;
+	u8 desc_len;
+	u8 tx_rate_idx;
+	u8 tx_rate_flags;
+
 	void *desc;
 
-	__le32 iv;
-	__le32 eiv;
+	__le32 iv[2];
 
 	dma_addr_t skb_dma;
 
@@ -143,11 +146,15 @@
  * @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value.
  * @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value.
  * @RXDONE_MY_BSS: Does this frame originate from device's BSS.
+ * @RXDONE_CRYPTO_IV: Driver provided IV/EIV data.
+ * @RXDONE_CRYPTO_ICV: Driver provided ICV data.
  */
 enum rxdone_entry_desc_flags {
 	RXDONE_SIGNAL_PLCP = 1 << 0,
 	RXDONE_SIGNAL_BITRATE = 1 << 1,
 	RXDONE_MY_BSS = 1 << 2,
+	RXDONE_CRYPTO_IV = 1 << 3,
+	RXDONE_CRYPTO_ICV = 1 << 4,
 };
 
 /**
@@ -163,8 +170,7 @@
  * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags).
  * @cipher: Cipher type used during decryption.
  * @cipher_status: Decryption status.
- * @iv: IV data used during decryption.
- * @eiv: EIV data used during decryption.
+ * @iv: IV/EIV data used during decryption.
  * @icv: ICV data used during decryption.
  */
 struct rxdone_entry_desc {
@@ -177,8 +183,7 @@
 	u8 cipher;
 	u8 cipher_status;
 
-	__le32 iv;
-	__le32 eiv;
+	__le32 iv[2];
 	__le32 icv;
 };
 
@@ -375,6 +380,8 @@
  * @cw_max: The cw max value for outgoing frames (field ignored in RX queue).
  * @data_size: Maximum data size for the frames in this queue.
  * @desc_size: Hardware descriptor size for the data in this queue.
+ * @usb_endpoint: Device endpoint used for communication (USB only)
+ * @usb_maxpacket: Max packet size for given endpoint (USB only)
  */
 struct data_queue {
 	struct rt2x00_dev *rt2x00dev;
@@ -396,6 +403,9 @@
 
 	unsigned short data_size;
 	unsigned short desc_size;
+
+	unsigned short usb_endpoint;
+	unsigned short usb_maxpacket;
 };
 
 /**
@@ -439,6 +449,19 @@
 	&(__dev)->tx[(__dev)->ops->tx_queues]
 
 /**
+ * queue_next - Return pointer to next queue in list (HELPER MACRO).
+ * @__queue: Current queue for which we need the next queue
+ *
+ * Using the current queue address we take the address directly
+ * after the queue to take the next queue. Note that this macro
+ * should be used carefully since it does not protect against
+ * moving past the end of the list. (See macros &queue_end and
+ * &tx_queue_end for determining the end of the queue).
+ */
+#define queue_next(__queue) \
+	&(__queue)[1]
+
+/**
  * queue_loop - Loop through the queues within a specific range (HELPER MACRO).
  * @__entry: Pointer where the current queue entry will be stored in.
  * @__start: Start queue pointer.
@@ -448,8 +471,8 @@
  */
 #define queue_loop(__entry, __start, __end)			\
 	for ((__entry) = (__start);				\
-	     prefetch(&(__entry)[1]), (__entry) != (__end);	\
-	     (__entry) = &(__entry)[1])
+	     prefetch(queue_next(__entry)), (__entry) != (__end);\
+	     (__entry) = queue_next(__entry))
 
 /**
  * queue_for_each - Loop through all queues
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index b73a7e0..83df312 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -79,7 +79,7 @@
 {
 	int status;
 
-	BUG_ON(!mutex_is_locked(&rt2x00dev->usb_cache_mutex));
+	BUG_ON(!mutex_is_locked(&rt2x00dev->csr_mutex));
 
 	/*
 	 * Check for Cache availability.
@@ -110,13 +110,13 @@
 {
 	int status;
 
-	mutex_lock(&rt2x00dev->usb_cache_mutex);
+	mutex_lock(&rt2x00dev->csr_mutex);
 
 	status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
 						requesttype, offset, buffer,
 						buffer_length, timeout);
 
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+	mutex_unlock(&rt2x00dev->csr_mutex);
 
 	return status;
 }
@@ -132,7 +132,7 @@
 	unsigned char *tb;
 	u16 off, len, bsize;
 
-	mutex_lock(&rt2x00dev->usb_cache_mutex);
+	mutex_lock(&rt2x00dev->csr_mutex);
 
 	tb  = (char *)buffer;
 	off = offset;
@@ -148,12 +148,34 @@
 		off += bsize;
 	}
 
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+	mutex_unlock(&rt2x00dev->csr_mutex);
 
 	return status;
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff);
 
+int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+			   const unsigned int offset,
+			   struct rt2x00_field32 field,
+			   u32 *reg)
+{
+	unsigned int i;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00usb_register_read_lock(rt2x00dev, offset, reg);
+		if (!rt2x00_get_field32(*reg, field))
+			return 1;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "Indirect register access failed: "
+	      "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+	*reg = ~0;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
+
 /*
  * TX data handlers.
  */
@@ -212,10 +234,10 @@
 	 * length of the data to usb_fill_bulk_urb. Pass the skb
 	 * to the driver to determine what the length should be.
 	 */
-	length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+	length = rt2x00dev->ops->lib->get_tx_data_len(entry);
 
 	usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-			  usb_sndbulkpipe(usb_dev, 1),
+			  usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
 			  entry->skb->data, length,
 			  rt2x00usb_interrupt_txdone, entry);
 
@@ -351,28 +373,96 @@
 /*
  * Device initialization handlers.
  */
-void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
-			    struct queue_entry *entry)
+void rt2x00usb_clear_entry(struct queue_entry *entry)
 {
-	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+	struct usb_device *usb_dev =
+	    to_usb_device_intf(entry->queue->rt2x00dev->dev);
 	struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+	int pipe;
 
-	usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-			  usb_rcvbulkpipe(usb_dev, 1),
-			  entry->skb->data, entry->skb->len,
-			  rt2x00usb_interrupt_rxdone, entry);
+	if (entry->queue->qid == QID_RX) {
+		pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
+		usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
+				entry->skb->data, entry->skb->len,
+				rt2x00usb_interrupt_rxdone, entry);
 
-	set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-	usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+		set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+		usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+	} else {
+		entry->flags = 0;
+	}
 }
-EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry);
+EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
 
-void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev,
-			    struct queue_entry *entry)
+static void rt2x00usb_assign_endpoint(struct data_queue *queue,
+				      struct usb_endpoint_descriptor *ep_desc)
 {
-	entry->flags = 0;
+	struct usb_device *usb_dev = to_usb_device_intf(queue->rt2x00dev->dev);
+	int pipe;
+
+	queue->usb_endpoint = usb_endpoint_num(ep_desc);
+
+	if (queue->qid == QID_RX) {
+		pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint);
+		queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0);
+	} else {
+		pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint);
+		queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1);
+	}
+
+	if (!queue->usb_maxpacket)
+		queue->usb_maxpacket = 1;
 }
-EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry);
+
+static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)
+{
+	struct usb_interface *intf = to_usb_interface(rt2x00dev->dev);
+	struct usb_host_interface *intf_desc = intf->cur_altsetting;
+	struct usb_endpoint_descriptor *ep_desc;
+	struct data_queue *queue = rt2x00dev->tx;
+	struct usb_endpoint_descriptor *tx_ep_desc = NULL;
+	unsigned int i;
+
+	/*
+	 * Walk through all available endpoints to search for "bulk in"
+	 * and "bulk out" endpoints. When we find such endpoints collect
+	 * the information we need from the descriptor and assign it
+	 * to the queue.
+	 */
+	for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+		ep_desc = &intf_desc->endpoint[i].desc;
+
+		if (usb_endpoint_is_bulk_in(ep_desc)) {
+			rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc);
+		} else if (usb_endpoint_is_bulk_out(ep_desc)) {
+			rt2x00usb_assign_endpoint(queue, ep_desc);
+
+			if (queue != queue_end(rt2x00dev))
+				queue = queue_next(queue);
+			tx_ep_desc = ep_desc;
+		}
+	}
+
+	/*
+	 * At least 1 endpoint for RX and 1 endpoint for TX must be available.
+	 */
+	if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) {
+		ERROR(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n");
+		return -EPIPE;
+	}
+
+	/*
+	 * It might be possible not all queues have a dedicated endpoint.
+	 * Loop through all TX queues and copy the endpoint information
+	 * which we have gathered from already assigned endpoints.
+	 */
+	txall_queue_for_each(rt2x00dev, queue) {
+		if (!queue->usb_endpoint)
+			rt2x00usb_assign_endpoint(queue, tx_ep_desc);
+	}
+
+	return 0;
+}
 
 static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
 			       struct data_queue *queue)
@@ -445,6 +535,13 @@
 	int status;
 
 	/*
+	 * Find endpoints for each queue
+	 */
+	status = rt2x00usb_find_endpoints(rt2x00dev);
+	if (status)
+		goto exit;
+
+	/*
 	 * Allocate DMA
 	 */
 	queue_for_each(rt2x00dev, queue) {
@@ -534,12 +631,6 @@
 	rt2x00dev->dev = &usb_intf->dev;
 	rt2x00dev->ops = ops;
 	rt2x00dev->hw = hw;
-	mutex_init(&rt2x00dev->usb_cache_mutex);
-
-	rt2x00dev->usb_maxpacket =
-	    usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1);
-	if (!rt2x00dev->usb_maxpacket)
-		rt2x00dev->usb_maxpacket = 1;
 
 	retval = rt2x00usb_alloc_reg(rt2x00dev);
 	if (retval)
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 3b4a674..2bd4ac8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -231,6 +231,142 @@
 					REGISTER_TIMEOUT16(length));
 }
 
+/**
+ * rt2x00usb_regbusy_read - Read 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev,
+					   const unsigned int offset,
+					   u32 *value)
+{
+	__le32 reg;
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+				      USB_VENDOR_REQUEST_IN, offset,
+				      &reg, sizeof(reg), REGISTER_TIMEOUT);
+	*value = le32_to_cpu(reg);
+}
+
+/**
+ * rt2x00usb_register_read_lock - Read 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_req_buff_lock().
+ */
+static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
+						const unsigned int offset,
+						u32 *value)
+{
+	__le32 reg;
+	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
+				       USB_VENDOR_REQUEST_IN, offset,
+				       &reg, sizeof(reg), REGISTER_TIMEOUT);
+	*value = le32_to_cpu(reg);
+}
+
+/**
+ * rt2x00usb_register_multiread - Read 32bit register words
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ * @length: Length of the data
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_multiread(struct rt2x00_dev *rt2x00dev,
+						const unsigned int offset,
+						void *value, const u32 length)
+{
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+				      USB_VENDOR_REQUEST_IN, offset,
+				      value, length,
+				      REGISTER_TIMEOUT32(length));
+}
+
+/**
+ * rt2x00usb_register_write - Write 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_write(struct rt2x00_dev *rt2x00dev,
+					    const unsigned int offset,
+					    u32 value)
+{
+	__le32 reg = cpu_to_le32(value);
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+				      USB_VENDOR_REQUEST_OUT, offset,
+				      &reg, sizeof(reg), REGISTER_TIMEOUT);
+}
+
+/**
+ * rt2x00usb_register_write_lock - Write 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_req_buff_lock().
+ */
+static inline void rt2x00usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
+						 const unsigned int offset,
+						 u32 value)
+{
+	__le32 reg = cpu_to_le32(value);
+	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
+				       USB_VENDOR_REQUEST_OUT, offset,
+				       &reg, sizeof(reg), REGISTER_TIMEOUT);
+}
+
+/**
+ * rt2x00usb_register_multiwrite - Write 32bit register words
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ * @length: Length of the data
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
+					       const unsigned int offset,
+					       void *value, const u32 length)
+{
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+				      USB_VENDOR_REQUEST_OUT, offset,
+				      value, length,
+				      REGISTER_TIMEOUT32(length));
+}
+
+/**
+ * rt2x00usb_regbusy_read - Read from register with busy check
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @field: Field to check if register is busy
+ * @reg: Pointer to where register contents should be stored
+ *
+ * This function will read the given register, and checks if the
+ * register is busy. If it is, it will sleep for a couple of
+ * microseconds before reading the register again. If the register
+ * is not read after a certain timeout, this function will return
+ * FALSE.
+ */
+int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+			   const unsigned int offset,
+			   struct rt2x00_field32 field,
+			   u32 *reg);
+
 /*
  * Radio handlers
  */
@@ -286,10 +422,7 @@
 /*
  * Device initialization handlers.
  */
-void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
-			    struct queue_entry *entry);
-void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev,
-			    struct queue_entry *entry);
+void rt2x00usb_clear_entry(struct queue_entry *entry);
 int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev);
 void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
 
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index a461620..987e890 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -55,45 +55,36 @@
  * the access attempt is considered to have failed,
  * and we will print an error.
  */
-static u32 rt61pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
-	u32 reg;
-	unsigned int i;
-
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, PHY_CSR3, &reg);
-		if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-			break;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
+#define WAIT_FOR_MCU(__dev, __reg) \
+	rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \
+			       H2M_MAILBOX_CSR_OWNER, (__reg))
 
 static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 			      const unsigned int word, const u8 value)
 {
 	u32 reg;
 
+	mutex_lock(&rt2x00dev->csr_mutex);
+
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	reg = rt61pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
-		return;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+		rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+		rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+		rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+
+		rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
 	}
 
-	/*
-	 * Write the data into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
-	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
-	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
-	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
-
-	rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -101,66 +92,58 @@
 {
 	u32 reg;
 
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt61pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
-		return;
-	}
+	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Write the request into the BBP.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the read request into the register.
+	 * After the data has been written, we wait until hardware
+	 * returns the correct value, if at any time the register
+	 * doesn't become available in time, reg will be 0xffffffff
+	 * which means we return 0xff to the caller.
 	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
-	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
-	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+		rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+		rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
 
-	rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+		rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
 
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt61pci_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
-		*value = 0xff;
-		return;
+		WAIT_FOR_BBP(rt2x00dev, &reg);
 	}
 
 	*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
+
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
 			     const unsigned int word, const u32 value)
 {
 	u32 reg;
-	unsigned int i;
 
 	if (!word)
 		return;
 
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2x00pci_register_read(rt2x00dev, PHY_CSR4, &reg);
-		if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
-			goto rf_write;
-		udelay(REGISTER_BUSY_DELAY);
+	mutex_lock(&rt2x00dev->csr_mutex);
+
+	/*
+	 * Wait until the RF becomes available, afterwards we
+	 * can safely write the new data into the register.
+	 */
+	if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+		rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
+		rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+		rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+
+		rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
+		rt2x00_rf_write(rt2x00dev, word, value);
 	}
 
-	ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
-	return;
-
-rf_write:
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
-	rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
-	rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
-	rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
-
-	rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
-	rt2x00_rf_write(rt2x00dev, word, value);
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 #ifdef CONFIG_RT2X00_LIB_LEDS
@@ -175,25 +158,27 @@
 {
 	u32 reg;
 
-	rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, &reg);
+	mutex_lock(&rt2x00dev->csr_mutex);
 
-	if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) {
-		ERROR(rt2x00dev, "mcu request error. "
-		      "Request 0x%02x failed for token 0x%02x.\n",
-		      command, token);
-		return;
+	/*
+	 * Wait until the MCU becomes available, afterwards we
+	 * can safely write the new data into the register.
+	 */
+	if (WAIT_FOR_MCU(rt2x00dev, &reg)) {
+		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
+		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
+		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
+		rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
+		rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
+
+		rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
+		rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
+		rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
+		rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
 	}
 
-	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
-	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
-	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
-	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
-	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
+	mutex_unlock(&rt2x00dev->csr_mutex);
 
-	rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
-	rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
-	rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
-	rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
 }
 #endif /* CONFIG_RT2X00_LIB_LEDS */
 
@@ -228,43 +213,34 @@
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt61pci_read_csr(struct rt2x00_dev *rt2x00dev,
-			     const unsigned int word, u32 *data)
-{
-	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt61pci_write_csr(struct rt2x00_dev *rt2x00dev,
-			      const unsigned int word, u32 data)
-{
-	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt61pci_rt2x00debug = {
 	.owner	= THIS_MODULE,
 	.csr	= {
-		.read		= rt61pci_read_csr,
-		.write		= rt61pci_write_csr,
+		.read		= rt2x00pci_register_read,
+		.write		= rt2x00pci_register_write,
+		.flags		= RT2X00DEBUGFS_OFFSET,
+		.word_base	= CSR_REG_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= CSR_REG_SIZE / sizeof(u32),
 	},
 	.eeprom	= {
 		.read		= rt2x00_eeprom_read,
 		.write		= rt2x00_eeprom_write,
+		.word_base	= EEPROM_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= EEPROM_SIZE / sizeof(u16),
 	},
 	.bbp	= {
 		.read		= rt61pci_bbp_read,
 		.write		= rt61pci_bbp_write,
+		.word_base	= BBP_BASE,
 		.word_size	= sizeof(u8),
 		.word_count	= BBP_SIZE / sizeof(u8),
 	},
 	.rf	= {
 		.read		= rt2x00_rf_read,
 		.write		= rt61pci_rf_write,
+		.word_base	= RF_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= RF_SIZE / sizeof(u32),
 	},
@@ -643,95 +619,18 @@
 	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
 			   !!erp->short_preamble);
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
-}
 
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
 
-static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
-				    struct rt2x00lib_conf *libconf)
-{
-	u16 eeprom;
-	short lna_gain = 0;
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
 
-	if (libconf->band == IEEE80211_BAND_2GHZ) {
-		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
-			lna_gain += 14;
-
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
-		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
-	} else {
-		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
-			lna_gain += 14;
-
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
-		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
-	}
-
-	rt2x00dev->lna_gain = lna_gain;
-}
-
-static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev,
-				   const int basic_rate_mask)
-{
-	rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
-}
-
-static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
-				   struct rf_channel *rf, const int txpower)
-{
-	u8 r3;
-	u8 r94;
-	u8 smart;
-
-	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
-	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
-
-	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-		  rt2x00_rf(&rt2x00dev->chip, RF2527));
-
-	rt61pci_bbp_read(rt2x00dev, 3, &r3);
-	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
-	rt61pci_bbp_write(rt2x00dev, 3, r3);
-
-	r94 = 6;
-	if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
-		r94 += txpower - MAX_TXPOWER;
-	else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
-		r94 += txpower;
-	rt61pci_bbp_write(rt2x00dev, 94, r94);
-
-	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
-	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
-	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
-	udelay(200);
-
-	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
-	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
-	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
-	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
-	udelay(200);
-
-	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
-	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
-	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
-	msleep(1);
-}
-
-static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
-				   const int txpower)
-{
-	struct rf_channel rf;
-
-	rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
-	rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
-	rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
-	rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
-
-	rt61pci_config_channel(rt2x00dev, &rf, txpower);
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+	rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
 }
 
 static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -906,8 +805,8 @@
 	{ 98,  { 0x48, 0x48 } },
 };
 
-static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-				   struct antenna_setup *ant)
+static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
+			       struct antenna_setup *ant)
 {
 	const struct antenna_sel *sel;
 	unsigned int lna;
@@ -954,20 +853,105 @@
 	}
 }
 
-static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
+static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
+				    struct rt2x00lib_conf *libconf)
+{
+	u16 eeprom;
+	short lna_gain = 0;
+
+	if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+			lna_gain += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+	} else {
+		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+			lna_gain += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+	}
+
+	rt2x00dev->lna_gain = lna_gain;
+}
+
+static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
+				   struct rf_channel *rf, const int txpower)
+{
+	u8 r3;
+	u8 r94;
+	u8 smart;
+
+	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+		  rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+	rt61pci_bbp_read(rt2x00dev, 3, &r3);
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+	rt61pci_bbp_write(rt2x00dev, 3, r3);
+
+	r94 = 6;
+	if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+		r94 += txpower - MAX_TXPOWER;
+	else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+		r94 += txpower;
+	rt61pci_bbp_write(rt2x00dev, 94, r94);
+
+	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+	udelay(200);
+
+	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+	udelay(200);
+
+	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+	msleep(1);
+}
+
+static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+				   const int txpower)
+{
+	struct rf_channel rf;
+
+	rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+	rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+	rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+	rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+	rt61pci_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
 				    struct rt2x00lib_conf *libconf)
 {
 	u32 reg;
 
-	rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
-	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
-	rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
+			   libconf->conf->long_frame_max_tx_count);
+	rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
+			   libconf->conf->short_frame_max_tx_count);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
 
-	rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
-	rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
-	rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
-	rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
-	rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
+static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
+				    struct rt2x00lib_conf *libconf)
+{
+	u32 reg;
 
 	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
@@ -990,16 +974,15 @@
 	/* Always recalculate LNA gain before changing configuration */
 	rt61pci_config_lna_gain(rt2x00dev, libconf);
 
-	if (flags & CONFIG_UPDATE_PHYMODE)
-		rt61pci_config_phymode(rt2x00dev, libconf->basic_rates);
-	if (flags & CONFIG_UPDATE_CHANNEL)
+	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt61pci_config_channel(rt2x00dev, &libconf->rf,
 				       libconf->conf->power_level);
-	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+	if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+	    !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
 		rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level);
-	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt61pci_config_antenna(rt2x00dev, &libconf->ant);
-	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+		rt61pci_config_retry_limit(rt2x00dev, libconf);
+	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
 		rt61pci_config_duration(rt2x00dev, libconf);
 }
 
@@ -1263,33 +1246,44 @@
 /*
  * Initialization functions.
  */
-static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
-				 struct queue_entry *entry)
+static bool rt61pci_get_entry_state(struct queue_entry *entry)
+{
+	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+	u32 word;
+
+	if (entry->queue->qid == QID_RX) {
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+
+		return rt2x00_get_field32(word, RXD_W0_OWNER_NIC);
+	} else {
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+
+		return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+		        rt2x00_get_field32(word, TXD_W0_VALID));
+	}
+}
+
+static void rt61pci_clear_entry(struct queue_entry *entry)
 {
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 	u32 word;
 
-	rt2x00_desc_read(entry_priv->desc, 5, &word);
-	rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
-			   skbdesc->skb_dma);
-	rt2x00_desc_write(entry_priv->desc, 5, word);
+	if (entry->queue->qid == QID_RX) {
+		rt2x00_desc_read(entry_priv->desc, 5, &word);
+		rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
+				   skbdesc->skb_dma);
+		rt2x00_desc_write(entry_priv->desc, 5, word);
 
-	rt2x00_desc_read(entry_priv->desc, 0, &word);
-	rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
-	rt2x00_desc_write(entry_priv->desc, 0, word);
-}
-
-static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev,
-				 struct queue_entry *entry)
-{
-	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
-	u32 word;
-
-	rt2x00_desc_read(entry_priv->desc, 0, &word);
-	rt2x00_set_field32(&word, TXD_W0_VALID, 0);
-	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
-	rt2x00_desc_write(entry_priv->desc, 0, word);
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+		rt2x00_desc_write(entry_priv->desc, 0, word);
+	} else {
+		rt2x00_desc_read(entry_priv->desc, 0, &word);
+		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+		rt2x00_desc_write(entry_priv->desc, 0, word);
+	}
 }
 
 static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
@@ -1784,8 +1778,8 @@
 	rt2x00_desc_write(txd, 2, word);
 
 	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
-		_rt2x00_desc_write(txd, 3, skbdesc->iv);
-		_rt2x00_desc_write(txd, 4, skbdesc->eiv);
+		_rt2x00_desc_write(txd, 3, skbdesc->iv[0]);
+		_rt2x00_desc_write(txd, 4, skbdesc->iv[1]);
 	}
 
 	rt2x00_desc_read(txd, 5, &word);
@@ -1934,7 +1928,7 @@
 }
 
 static void rt61pci_fill_rxdone(struct queue_entry *entry,
-			        struct rxdone_entry_desc *rxdesc)
+				struct rxdone_entry_desc *rxdesc)
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct queue_entry_priv_pci *entry_priv = entry->priv_data;
@@ -1955,9 +1949,12 @@
 	}
 
 	if (rxdesc->cipher != CIPHER_NONE) {
-		_rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv);
-		_rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->eiv);
+		_rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv[0]);
+		_rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->iv[1]);
+		rxdesc->dev_flags |= RXDONE_CRYPTO_IV;
+
 		_rt2x00_desc_read(entry_priv->desc, 4, &rxdesc->icv);
+		rxdesc->dev_flags |= RXDONE_CRYPTO_ICV;
 
 		/*
 		 * Hardware has stripped IV/EIV data from 802.11 frame during
@@ -2175,10 +2172,8 @@
 	 */
 	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
 	if (!is_valid_ether_addr(mac)) {
-		DECLARE_MAC_BUF(macbuf);
-
 		random_ether_addr(mac);
-		EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+		EEPROM(rt2x00dev, "MAC: %pM\n", mac);
 	}
 
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -2630,20 +2625,6 @@
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt61pci_set_retry_limit(struct ieee80211_hw *hw,
-				   u32 short_retry, u32 long_retry)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	u32 reg;
-
-	rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
-	rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
-	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
-
-	return 0;
-}
-
 static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
 			   const struct ieee80211_tx_queue_params *params)
 {
@@ -2726,7 +2707,6 @@
 	.configure_filter	= rt2x00mac_configure_filter,
 	.set_key		= rt2x00mac_set_key,
 	.get_stats		= rt2x00mac_get_stats,
-	.set_retry_limit	= rt61pci_set_retry_limit,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt61pci_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
@@ -2741,8 +2721,8 @@
 	.load_firmware		= rt61pci_load_firmware,
 	.initialize		= rt2x00pci_initialize,
 	.uninitialize		= rt2x00pci_uninitialize,
-	.init_rxentry		= rt61pci_init_rxentry,
-	.init_txentry		= rt61pci_init_txentry,
+	.get_entry_state	= rt61pci_get_entry_state,
+	.clear_entry		= rt61pci_clear_entry,
 	.set_device_state	= rt61pci_set_device_state,
 	.rfkill_poll		= rt61pci_rfkill_poll,
 	.link_stats		= rt61pci_link_stats,
@@ -2758,6 +2738,7 @@
 	.config_filter		= rt61pci_config_filter,
 	.config_intf		= rt61pci_config_intf,
 	.config_erp		= rt61pci_config_erp,
+	.config_ant		= rt61pci_config_ant,
 	.config			= rt61pci_config,
 };
 
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 8ec1451..65fe333 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -48,7 +48,9 @@
 #define CSR_REG_SIZE			0x04b0
 #define EEPROM_BASE			0x0000
 #define EEPROM_SIZE			0x0100
+#define BBP_BASE			0x0000
 #define BBP_SIZE			0x0080
+#define RF_BASE				0x0000
 #define RF_SIZE				0x0014
 
 /*
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 934f8e03..d638a8a 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -46,7 +46,7 @@
 /*
  * Register access.
  * All access to the CSR registers will go through the methods
- * rt73usb_register_read and rt73usb_register_write.
+ * rt2x00usb_register_read and rt2x00usb_register_write.
  * BBP and RF register require indirect register access,
  * and use the CSR registers BBPCSR and RFCSR to achieve this.
  * These indirect registers work with busy bits,
@@ -55,113 +55,35 @@
  * between each attampt. When the busy bit is still set at that time,
  * the access attempt is considered to have failed,
  * and we will print an error.
- * The _lock versions must be used if you already hold the usb_cache_mutex
+ * The _lock versions must be used if you already hold the csr_mutex
  */
-static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev,
-					 const unsigned int offset, u32 *value)
-{
-	__le32 reg;
-	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
-				      USB_VENDOR_REQUEST_IN, offset,
-				      &reg, sizeof(u32), REGISTER_TIMEOUT);
-	*value = le32_to_cpu(reg);
-}
-
-static inline void rt73usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
-					      const unsigned int offset, u32 *value)
-{
-	__le32 reg;
-	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
-				       USB_VENDOR_REQUEST_IN, offset,
-				       &reg, sizeof(u32), REGISTER_TIMEOUT);
-	*value = le32_to_cpu(reg);
-}
-
-static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev,
-					      const unsigned int offset,
-					      void *value, const u32 length)
-{
-	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
-				      USB_VENDOR_REQUEST_IN, offset,
-				      value, length,
-				      REGISTER_TIMEOUT32(length));
-}
-
-static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev,
-					  const unsigned int offset, u32 value)
-{
-	__le32 reg = cpu_to_le32(value);
-	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
-				      USB_VENDOR_REQUEST_OUT, offset,
-				      &reg, sizeof(u32), REGISTER_TIMEOUT);
-}
-
-static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
-					       const unsigned int offset, u32 value)
-{
-	__le32 reg = cpu_to_le32(value);
-	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
-				       USB_VENDOR_REQUEST_OUT, offset,
-				      &reg, sizeof(u32), REGISTER_TIMEOUT);
-}
-
-static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
-					       const unsigned int offset,
-					       void *value, const u32 length)
-{
-	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
-				      USB_VENDOR_REQUEST_OUT, offset,
-				      value, length,
-				      REGISTER_TIMEOUT32(length));
-}
-
-static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
-	u32 reg;
-	unsigned int i;
-
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt73usb_register_read_lock(rt2x00dev, PHY_CSR3, &reg);
-		if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-			break;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+	rt2x00usb_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+	rt2x00usb_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
 
 static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 			      const unsigned int word, const u8 value)
 {
 	u32 reg;
 
-	mutex_lock(&rt2x00dev->usb_cache_mutex);
+	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-		goto exit_fail;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+		rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+		rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+		rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
 
-	/*
-	 * Write the data into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
-	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
-	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
-	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+		rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
+	}
 
-	rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
-	return;
-
-exit_fail:
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
-	ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -169,123 +91,95 @@
 {
 	u32 reg;
 
-	mutex_lock(&rt2x00dev->usb_cache_mutex);
+	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * Wait until the BBP becomes ready.
+	 * Wait until the BBP becomes available, afterwards we
+	 * can safely write the read request into the register.
+	 * After the data has been written, we wait until hardware
+	 * returns the correct value, if at any time the register
+	 * doesn't become available in time, reg will be 0xffffffff
+	 * which means we return 0xff to the caller.
 	 */
-	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-		goto exit_fail;
+	if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+		rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+		rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
 
-	/*
-	 * Write the request into the BBP.
-	 */
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
-	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
-	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+		rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
 
-	rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
-
-	/*
-	 * Wait until the BBP becomes ready.
-	 */
-	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
-		goto exit_fail;
+		WAIT_FOR_BBP(rt2x00dev, &reg);
+	}
 
 	*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
 
-	return;
-
-exit_fail:
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
-	ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
-	*value = 0xff;
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
 			     const unsigned int word, const u32 value)
 {
 	u32 reg;
-	unsigned int i;
 
 	if (!word)
 		return;
 
-	mutex_lock(&rt2x00dev->usb_cache_mutex);
-
-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt73usb_register_read_lock(rt2x00dev, PHY_CSR4, &reg);
-		if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
-			goto rf_write;
-		udelay(REGISTER_BUSY_DELAY);
-	}
-
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
-	ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
-	return;
-
-rf_write:
-	reg = 0;
-	rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+	mutex_lock(&rt2x00dev->csr_mutex);
 
 	/*
-	 * RF5225 and RF2527 contain 21 bits per RF register value,
-	 * all others contain 20 bits.
+	 * Wait until the RF becomes available, afterwards we
+	 * can safely write the new data into the register.
 	 */
-	rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
-			   20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-				 rt2x00_rf(&rt2x00dev->chip, RF2527)));
-	rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
-	rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+	if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+		reg = 0;
+		rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+		/*
+		 * RF5225 and RF2527 contain 21 bits per RF register value,
+		 * all others contain 20 bits.
+		 */
+		rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
+				   20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+					 rt2x00_rf(&rt2x00dev->chip, RF2527)));
+		rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+		rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
 
-	rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg);
-	rt2x00_rf_write(rt2x00dev, word, value);
-	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+		rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR4, reg);
+		rt2x00_rf_write(rt2x00dev, word, value);
+	}
+
+	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt73usb_read_csr(struct rt2x00_dev *rt2x00dev,
-			     const unsigned int word, u32 *data)
-{
-	rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt73usb_write_csr(struct rt2x00_dev *rt2x00dev,
-			      const unsigned int word, u32 data)
-{
-	rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt73usb_rt2x00debug = {
 	.owner	= THIS_MODULE,
 	.csr	= {
-		.read		= rt73usb_read_csr,
-		.write		= rt73usb_write_csr,
+		.read		= rt2x00usb_register_read,
+		.write		= rt2x00usb_register_write,
+		.flags		= RT2X00DEBUGFS_OFFSET,
+		.word_base	= CSR_REG_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= CSR_REG_SIZE / sizeof(u32),
 	},
 	.eeprom	= {
 		.read		= rt2x00_eeprom_read,
 		.write		= rt2x00_eeprom_write,
+		.word_base	= EEPROM_BASE,
 		.word_size	= sizeof(u16),
 		.word_count	= EEPROM_SIZE / sizeof(u16),
 	},
 	.bbp	= {
 		.read		= rt73usb_bbp_read,
 		.write		= rt73usb_bbp_write,
+		.word_base	= BBP_BASE,
 		.word_size	= sizeof(u8),
 		.word_count	= BBP_SIZE / sizeof(u8),
 	},
 	.rf	= {
 		.read		= rt2x00_rf_read,
 		.write		= rt73usb_rf_write,
+		.word_base	= RF_BASE,
 		.word_size	= sizeof(u32),
 		.word_count	= RF_SIZE / sizeof(u32),
 	},
@@ -341,10 +235,10 @@
 	    container_of(led_cdev, struct rt2x00_led, led_dev);
 	u32 reg;
 
-	rt73usb_register_read(led->rt2x00dev, MAC_CSR14, &reg);
+	rt2x00usb_register_read(led->rt2x00dev, MAC_CSR14, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, *delay_on);
 	rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, *delay_off);
-	rt73usb_register_write(led->rt2x00dev, MAC_CSR14, reg);
+	rt2x00usb_register_write(led->rt2x00dev, MAC_CSR14, reg);
 
 	return 0;
 }
@@ -387,7 +281,7 @@
 		 */
 		mask = (0xf << crypto->bssidx);
 
-		rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+		rt2x00usb_register_read(rt2x00dev, SEC_CSR0, &reg);
 		reg &= mask;
 
 		if (reg && reg == mask)
@@ -424,16 +318,16 @@
 			field.bit_offset = (3 * key->hw_key_idx);
 			field.bit_mask = 0x7 << field.bit_offset;
 
-			rt73usb_register_read(rt2x00dev, SEC_CSR1, &reg);
+			rt2x00usb_register_read(rt2x00dev, SEC_CSR1, &reg);
 			rt2x00_set_field32(&reg, field, crypto->cipher);
-			rt73usb_register_write(rt2x00dev, SEC_CSR1, reg);
+			rt2x00usb_register_write(rt2x00dev, SEC_CSR1, reg);
 		} else {
 			field.bit_offset = (3 * (key->hw_key_idx - 8));
 			field.bit_mask = 0x7 << field.bit_offset;
 
-			rt73usb_register_read(rt2x00dev, SEC_CSR5, &reg);
+			rt2x00usb_register_read(rt2x00dev, SEC_CSR5, &reg);
 			rt2x00_set_field32(&reg, field, crypto->cipher);
-			rt73usb_register_write(rt2x00dev, SEC_CSR5, reg);
+			rt2x00usb_register_write(rt2x00dev, SEC_CSR5, reg);
 		}
 
 		/*
@@ -456,12 +350,12 @@
 	 */
 	mask = 1 << key->hw_key_idx;
 
-	rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, SEC_CSR0, &reg);
 	if (crypto->cmd == SET_KEY)
 		reg |= mask;
 	else if (crypto->cmd == DISABLE_KEY)
 		reg &= ~mask;
-	rt73usb_register_write(rt2x00dev, SEC_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, SEC_CSR0, reg);
 
 	return 0;
 }
@@ -486,10 +380,10 @@
 		 * When both registers are full, we drop the key,
 		 * otherwise we use the first invalid entry.
 		 */
-		rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+		rt2x00usb_register_read(rt2x00dev, SEC_CSR2, &reg);
 		if (reg && reg == ~0) {
 			key->hw_key_idx = 32;
-			rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+			rt2x00usb_register_read(rt2x00dev, SEC_CSR3, &reg);
 			if (reg && reg == ~0)
 				return -ENOSPC;
 		}
@@ -517,14 +411,14 @@
 		/*
 		 * Send the address and cipher type to the hardware register.
 		 * This data fits within the CSR cache size, so we can use
-		 * rt73usb_register_multiwrite() directly.
+		 * rt2x00usb_register_multiwrite() directly.
 		 */
 		memset(&addr_entry, 0, sizeof(addr_entry));
 		memcpy(&addr_entry, crypto->address, ETH_ALEN);
 		addr_entry.cipher = crypto->cipher;
 
 		reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
-		rt73usb_register_multiwrite(rt2x00dev, reg,
+		rt2x00usb_register_multiwrite(rt2x00dev, reg,
 					    &addr_entry, sizeof(addr_entry));
 
 		/*
@@ -532,9 +426,9 @@
 		 * without this received frames will not be decrypted
 		 * by the hardware.
 		 */
-		rt73usb_register_read(rt2x00dev, SEC_CSR4, &reg);
+		rt2x00usb_register_read(rt2x00dev, SEC_CSR4, &reg);
 		reg |= (1 << crypto->bssidx);
-		rt73usb_register_write(rt2x00dev, SEC_CSR4, reg);
+		rt2x00usb_register_write(rt2x00dev, SEC_CSR4, reg);
 
 		/*
 		 * The driver does not support the IV/EIV generation
@@ -557,21 +451,21 @@
 	if (key->hw_key_idx < 32) {
 		mask = 1 << key->hw_key_idx;
 
-		rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+		rt2x00usb_register_read(rt2x00dev, SEC_CSR2, &reg);
 		if (crypto->cmd == SET_KEY)
 			reg |= mask;
 		else if (crypto->cmd == DISABLE_KEY)
 			reg &= ~mask;
-		rt73usb_register_write(rt2x00dev, SEC_CSR2, reg);
+		rt2x00usb_register_write(rt2x00dev, SEC_CSR2, reg);
 	} else {
 		mask = 1 << (key->hw_key_idx - 32);
 
-		rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+		rt2x00usb_register_read(rt2x00dev, SEC_CSR3, &reg);
 		if (crypto->cmd == SET_KEY)
 			reg |= mask;
 		else if (crypto->cmd == DISABLE_KEY)
 			reg &= ~mask;
-		rt73usb_register_write(rt2x00dev, SEC_CSR3, reg);
+		rt2x00usb_register_write(rt2x00dev, SEC_CSR3, reg);
 	}
 
 	return 0;
@@ -588,7 +482,7 @@
 	 * and broadcast frames will always be accepted since
 	 * there is no filter for it at this time.
 	 */
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
 			   !(filter_flags & FIF_FCSFAIL));
 	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
@@ -606,7 +500,7 @@
 	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BROADCAST, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS,
 			   !(filter_flags & FIF_CONTROL));
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 }
 
 static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
@@ -625,16 +519,16 @@
 		 * bits which (when set to 0) will invalidate the entire beacon.
 		 */
 		beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
-		rt73usb_register_write(rt2x00dev, beacon_base, 0);
+		rt2x00usb_register_write(rt2x00dev, beacon_base, 0);
 
 		/*
 		 * Enable synchronisation.
 		 */
-		rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+		rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
 		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
 		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
 		rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
-		rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+		rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 	}
 
 	if (flags & CONFIG_UPDATE_MAC) {
@@ -642,7 +536,7 @@
 		rt2x00_set_field32(&reg, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
 		conf->mac[1] = cpu_to_le32(reg);
 
-		rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2,
+		rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR2,
 					    conf->mac, sizeof(conf->mac));
 	}
 
@@ -651,7 +545,7 @@
 		rt2x00_set_field32(&reg, MAC_CSR5_BSS_ID_MASK, 3);
 		conf->bssid[1] = cpu_to_le32(reg);
 
-		rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4,
+		rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR4,
 					    conf->bssid, sizeof(conf->bssid));
 	}
 }
@@ -661,95 +555,26 @@
 {
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
 			   !!erp->short_preamble);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
-}
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
 
-static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
-				    struct rt2x00lib_conf *libconf)
-{
-	u16 eeprom;
-	short lna_gain = 0;
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
 
-	if (libconf->band == IEEE80211_BAND_2GHZ) {
-		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
-			lna_gain += 14;
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg);
 
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
-		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
-	} else {
-		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
-		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
-	}
-
-	rt2x00dev->lna_gain = lna_gain;
-}
-
-static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev,
-				   const int basic_rate_mask)
-{
-	rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
-}
-
-static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
-				   struct rf_channel *rf, const int txpower)
-{
-	u8 r3;
-	u8 r94;
-	u8 smart;
-
-	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
-	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
-
-	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-		  rt2x00_rf(&rt2x00dev->chip, RF2527));
-
-	rt73usb_bbp_read(rt2x00dev, 3, &r3);
-	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
-	rt73usb_bbp_write(rt2x00dev, 3, r3);
-
-	r94 = 6;
-	if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
-		r94 += txpower - MAX_TXPOWER;
-	else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
-		r94 += txpower;
-	rt73usb_bbp_write(rt2x00dev, 94, r94);
-
-	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
-	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
-	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
-
-	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
-	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
-	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
-	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
-
-	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
-	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
-	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
-
-	udelay(10);
-}
-
-static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
-				   const int txpower)
-{
-	struct rf_channel rf;
-
-	rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
-	rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
-	rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
-	rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
-
-	rt73usb_config_channel(rt2x00dev, &rf, txpower);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+	rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR8, reg);
 }
 
 static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -869,8 +694,8 @@
 	{ 98,  { 0x48, 0x48 } },
 };
 
-static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
-				   struct antenna_setup *ant)
+static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
+			       struct antenna_setup *ant)
 {
 	const struct antenna_sel *sel;
 	unsigned int lna;
@@ -895,14 +720,14 @@
 	for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
 		rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
 
-	rt73usb_register_read(rt2x00dev, PHY_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, PHY_CSR0, &reg);
 
 	rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG,
 			   (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ));
 	rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A,
 			   (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ));
 
-	rt73usb_register_write(rt2x00dev, PHY_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg);
 
 	if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
 	    rt2x00_rf(&rt2x00dev->chip, RF5225))
@@ -912,33 +737,111 @@
 		rt73usb_config_antenna_2x(rt2x00dev, ant);
 }
 
+static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
+				    struct rt2x00lib_conf *libconf)
+{
+	u16 eeprom;
+	short lna_gain = 0;
+
+	if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+			lna_gain += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+	} else {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+		lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+	}
+
+	rt2x00dev->lna_gain = lna_gain;
+}
+
+static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
+				   struct rf_channel *rf, const int txpower)
+{
+	u8 r3;
+	u8 r94;
+	u8 smart;
+
+	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+		  rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+	rt73usb_bbp_read(rt2x00dev, 3, &r3);
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+	rt73usb_bbp_write(rt2x00dev, 3, r3);
+
+	r94 = 6;
+	if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+		r94 += txpower - MAX_TXPOWER;
+	else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+		r94 += txpower;
+	rt73usb_bbp_write(rt2x00dev, 94, r94);
+
+	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+	udelay(10);
+}
+
+static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+				   const int txpower)
+{
+	struct rf_channel rf;
+
+	rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+	rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+	rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+	rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+	rt73usb_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+				       struct rt2x00lib_conf *libconf)
+{
+	u32 reg;
+
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
+			   libconf->conf->long_frame_max_tx_count);
+	rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
+			   libconf->conf->short_frame_max_tx_count);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
+
 static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
 				    struct rt2x00lib_conf *libconf)
 {
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
-	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
-	rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
-
-	rt73usb_register_read(rt2x00dev, MAC_CSR8, &reg);
-	rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
-	rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
-	rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
-	rt73usb_register_write(rt2x00dev, MAC_CSR8, reg);
-
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
 			   libconf->conf->beacon_int * 16);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 }
 
 static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
@@ -948,16 +851,15 @@
 	/* Always recalculate LNA gain before changing configuration */
 	rt73usb_config_lna_gain(rt2x00dev, libconf);
 
-	if (flags & CONFIG_UPDATE_PHYMODE)
-		rt73usb_config_phymode(rt2x00dev, libconf->basic_rates);
-	if (flags & CONFIG_UPDATE_CHANNEL)
+	if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
 		rt73usb_config_channel(rt2x00dev, &libconf->rf,
 				       libconf->conf->power_level);
-	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+	if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+	    !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
 		rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level);
-	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt73usb_config_antenna(rt2x00dev, &libconf->ant);
-	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+	if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+		rt73usb_config_retry_limit(rt2x00dev, libconf);
+	if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
 		rt73usb_config_duration(rt2x00dev, libconf);
 }
 
@@ -972,13 +874,13 @@
 	/*
 	 * Update FCS error count from register.
 	 */
-	rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, STA_CSR0, &reg);
 	qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
 
 	/*
 	 * Update False CCA count from register.
 	 */
-	rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, STA_CSR1, &reg);
 	qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
 }
 
@@ -1138,7 +1040,7 @@
 	 * Wait for stable hardware.
 	 */
 	for (i = 0; i < 100; i++) {
-		rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+		rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
 		if (reg)
 			break;
 		msleep(1);
@@ -1180,13 +1082,13 @@
 {
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
@@ -1195,12 +1097,12 @@
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
 	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR1, reg);
 
 	/*
 	 * CCK TXD BBP registers
 	 */
-	rt73usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
@@ -1209,77 +1111,77 @@
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
 	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR2, reg);
 
 	/*
 	 * OFDM TXD BBP registers
 	 */
-	rt73usb_register_read(rt2x00dev, TXRX_CSR3, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR3, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
 	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR3, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
 	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
 	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
 	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR7, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
 	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
 	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
 	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR8, reg);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 
-	rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR6, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR6, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR6_MAX_FRAME_UNIT, 0xfff);
-	rt73usb_register_write(rt2x00dev, MAC_CSR6, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR6, reg);
 
-	rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
 
 	if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
 		return -EBUSY;
 
-	rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
 
 	/*
 	 * Invalidate all Shared Keys (SEC_CSR0),
 	 * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
 	 */
-	rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
-	rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
-	rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
+	rt2x00usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
+	rt2x00usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
+	rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
 
 	reg = 0x000023b0;
 	if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
 	    rt2x00_rf(&rt2x00dev->chip, RF2527))
 		rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
-	rt73usb_register_write(rt2x00dev, PHY_CSR1, reg);
+	rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg);
 
-	rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
-	rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
-	rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
+	rt2x00usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
+	rt2x00usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
+	rt2x00usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR9, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
-	rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg);
 
 	/*
 	 * Clear all beacons
@@ -1287,36 +1189,36 @@
 	 * the first byte since that byte contains the VALID and OWNER
 	 * bits which (when set to 0) will invalidate the entire beacon.
 	 */
-	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
-	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
-	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
-	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+	rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+	rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+	rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+	rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
 
 	/*
 	 * We must clear the error counters.
 	 * These registers are cleared on read,
 	 * so we may pass a useless variable to store the value.
 	 */
-	rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
-	rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
-	rt73usb_register_read(rt2x00dev, STA_CSR2, &reg);
+	rt2x00usb_register_read(rt2x00dev, STA_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, STA_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, STA_CSR2, &reg);
 
 	/*
 	 * Reset MAC and BBP registers.
 	 */
-	rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
 	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
-	rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
 	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
-	rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
-	rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
 
 	return 0;
 }
@@ -1394,11 +1296,11 @@
 {
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
 			   (state == STATE_RADIO_RX_OFF) ||
 			   (state == STATE_RADIO_RX_OFF_LINK));
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
 }
 
 static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -1415,12 +1317,12 @@
 
 static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev)
 {
-	rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
 
 	/*
 	 * Disable synchronisation.
 	 */
-	rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, 0);
 
 	rt2x00usb_disable_radio(rt2x00dev);
 }
@@ -1433,10 +1335,10 @@
 
 	put_to_sleep = (state != STATE_AWAKE);
 
-	rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR12, &reg);
 	rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
 	rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
-	rt73usb_register_write(rt2x00dev, MAC_CSR12, reg);
+	rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg);
 
 	/*
 	 * Device is not guaranteed to be in the requested state yet.
@@ -1444,7 +1346,7 @@
 	 * device has entered the correct state.
 	 */
 	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+		rt2x00usb_register_read(rt2x00dev, MAC_CSR12, &reg);
 		state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
 		if (state == !put_to_sleep)
 			return 0;
@@ -1526,8 +1428,8 @@
 	rt2x00_desc_write(txd, 2, word);
 
 	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
-		_rt2x00_desc_write(txd, 3, skbdesc->iv);
-		_rt2x00_desc_write(txd, 4, skbdesc->eiv);
+		_rt2x00_desc_write(txd, 3, skbdesc->iv[0]);
+		_rt2x00_desc_write(txd, 4, skbdesc->iv[1]);
 	}
 
 	rt2x00_desc_read(txd, 5, &word);
@@ -1584,11 +1486,11 @@
 	 * Disable beaconing while we are reloading the beacon data,
 	 * otherwise we might be sending out invalid data.
 	 */
-	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 
 	/*
 	 * Write entire beacon with descriptor to register.
@@ -1606,8 +1508,7 @@
 	entry->skb = NULL;
 }
 
-static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
-				   struct sk_buff *skb)
+static int rt73usb_get_tx_data_len(struct queue_entry *entry)
 {
 	int length;
 
@@ -1615,8 +1516,8 @@
 	 * The length _must_ be a multiple of 4,
 	 * but it must _not_ be a multiple of the USB packet size.
 	 */
-	length = roundup(skb->len, 4);
-	length += (4 * !(length % rt2x00dev->usb_maxpacket));
+	length = roundup(entry->skb->len, 4);
+	length += (4 * !(length % entry->queue->usb_maxpacket));
 
 	return length;
 }
@@ -1635,14 +1536,14 @@
 	 * For Wi-Fi faily generated beacons between participating stations.
 	 * Set TBTT phase adaptive adjustment step to 8us (default 16us)
 	 */
-	rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+	rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
 	if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
 		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
 		rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
 		rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
-		rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+		rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 	}
 }
 
@@ -1685,7 +1586,7 @@
 }
 
 static void rt73usb_fill_rxdone(struct queue_entry *entry,
-			        struct rxdone_entry_desc *rxdesc)
+				struct rxdone_entry_desc *rxdesc)
 {
 	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
@@ -1717,9 +1618,12 @@
 	}
 
 	if (rxdesc->cipher != CIPHER_NONE) {
-		_rt2x00_desc_read(rxd, 2, &rxdesc->iv);
-		_rt2x00_desc_read(rxd, 3, &rxdesc->eiv);
+		_rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]);
+		_rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]);
+		rxdesc->dev_flags |= RXDONE_CRYPTO_IV;
+
 		_rt2x00_desc_read(rxd, 4, &rxdesc->icv);
+		rxdesc->dev_flags |= RXDONE_CRYPTO_ICV;
 
 		/*
 		 * Hardware has stripped IV/EIV data from 802.11 frame during
@@ -1781,10 +1685,8 @@
 	 */
 	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
 	if (!is_valid_ether_addr(mac)) {
-		DECLARE_MAC_BUF(macbuf);
-
 		random_ether_addr(mac);
-		EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+		EEPROM(rt2x00dev, "MAC: %pM\n", mac);
 	}
 
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -1883,7 +1785,7 @@
 	 * Identify RF chipset.
 	 */
 	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
-	rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+	rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
 	rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
 
 	if (!rt2x00_check_rev(&rt2x00dev->chip, 0x25730)) {
@@ -2211,20 +2113,6 @@
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt73usb_set_retry_limit(struct ieee80211_hw *hw,
-				   u32 short_retry, u32 long_retry)
-{
-	struct rt2x00_dev *rt2x00dev = hw->priv;
-	u32 reg;
-
-	rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
-	rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
-	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
-
-	return 0;
-}
-
 static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
 			   const struct ieee80211_tx_queue_params *params)
 {
@@ -2251,33 +2139,33 @@
 		field.bit_offset = queue_idx * 16;
 		field.bit_mask = 0xffff << field.bit_offset;
 
-		rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+		rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
 		rt2x00_set_field32(&reg, field, queue->txop);
-		rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+		rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
 	} else if (queue_idx < 4) {
 		field.bit_offset = (queue_idx - 2) * 16;
 		field.bit_mask = 0xffff << field.bit_offset;
 
-		rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+		rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
 		rt2x00_set_field32(&reg, field, queue->txop);
-		rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+		rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
 	}
 
 	/* Update WMM registers */
 	field.bit_offset = queue_idx * 4;
 	field.bit_mask = 0xf << field.bit_offset;
 
-	rt73usb_register_read(rt2x00dev, AIFSN_CSR, &reg);
+	rt2x00usb_register_read(rt2x00dev, AIFSN_CSR, &reg);
 	rt2x00_set_field32(&reg, field, queue->aifs);
-	rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg);
+	rt2x00usb_register_write(rt2x00dev, AIFSN_CSR, reg);
 
-	rt73usb_register_read(rt2x00dev, CWMIN_CSR, &reg);
+	rt2x00usb_register_read(rt2x00dev, CWMIN_CSR, &reg);
 	rt2x00_set_field32(&reg, field, queue->cw_min);
-	rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg);
+	rt2x00usb_register_write(rt2x00dev, CWMIN_CSR, reg);
 
-	rt73usb_register_read(rt2x00dev, CWMAX_CSR, &reg);
+	rt2x00usb_register_read(rt2x00dev, CWMAX_CSR, &reg);
 	rt2x00_set_field32(&reg, field, queue->cw_max);
-	rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg);
+	rt2x00usb_register_write(rt2x00dev, CWMAX_CSR, reg);
 
 	return 0;
 }
@@ -2295,9 +2183,9 @@
 	u64 tsf;
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, TXRX_CSR13, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR13, &reg);
 	tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
-	rt73usb_register_read(rt2x00dev, TXRX_CSR12, &reg);
+	rt2x00usb_register_read(rt2x00dev, TXRX_CSR12, &reg);
 	tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
 
 	return tsf;
@@ -2317,7 +2205,6 @@
 	.configure_filter	= rt2x00mac_configure_filter,
 	.set_key		= rt2x00mac_set_key,
 	.get_stats		= rt2x00mac_get_stats,
-	.set_retry_limit	= rt73usb_set_retry_limit,
 	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt73usb_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
@@ -2331,8 +2218,7 @@
 	.load_firmware		= rt73usb_load_firmware,
 	.initialize		= rt2x00usb_initialize,
 	.uninitialize		= rt2x00usb_uninitialize,
-	.init_rxentry		= rt2x00usb_init_rxentry,
-	.init_txentry		= rt2x00usb_init_txentry,
+	.clear_entry		= rt2x00usb_clear_entry,
 	.set_device_state	= rt73usb_set_device_state,
 	.link_stats		= rt73usb_link_stats,
 	.reset_tuner		= rt73usb_reset_tuner,
@@ -2348,6 +2234,7 @@
 	.config_filter		= rt73usb_config_filter,
 	.config_intf		= rt73usb_config_intf,
 	.config_erp		= rt73usb_config_erp,
+	.config_ant		= rt73usb_config_ant,
 	.config			= rt73usb_config,
 };
 
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 868386c..46e1405 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -48,7 +48,9 @@
 #define CSR_REG_SIZE			0x04b0
 #define EEPROM_BASE			0x0000
 #define EEPROM_SIZE			0x0100
+#define BBP_BASE			0x0000
 #define BBP_SIZE			0x0080
+#define RF_BASE				0x0000
 #define RF_SIZE				0x0014
 
 /*
diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile
new file mode 100644
index 0000000..c113b3e
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/Makefile
@@ -0,0 +1,7 @@
+rtl8180-objs		:= rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
+rtl8187-objs		:= rtl8187_dev.o rtl8187_rtl8225.o
+
+obj-$(CONFIG_RTL8180)	+= rtl8180.o
+obj-$(CONFIG_RTL8187)	+= rtl8187.o
+
+
diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h
similarity index 100%
rename from drivers/net/wireless/rtl8180.h
rename to drivers/net/wireless/rtl818x/rtl8180.h
diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
similarity index 96%
rename from drivers/net/wireless/rtl8180_dev.c
rename to drivers/net/wireless/rtl818x/rtl8180_dev.c
index df7e78e..5f887fb 100644
--- a/drivers/net/wireless/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -182,15 +182,13 @@
 				 skb->len, PCI_DMA_TODEVICE);
 
 		info = IEEE80211_SKB_CB(skb);
-		memset(&info->status, 0, sizeof(info->status));
+		ieee80211_tx_info_clear_status(info);
 
-		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-			if (flags & RTL818X_TX_DESC_FLAG_TX_OK)
-				info->flags |= IEEE80211_TX_STAT_ACK;
-			else
-				info->status.excessive_retries = 1;
-		}
-		info->status.retry_count = flags & 0xFF;
+		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+		    (flags & RTL818X_TX_DESC_FLAG_TX_OK))
+			info->flags |= IEEE80211_TX_STAT_ACK;
+
+		info->status.rates[0].count = (flags & 0xFF) + 1;
 
 		ieee80211_tx_status_irqsafe(dev, skb);
 		if (ring->entries - skb_queue_len(&ring->queue) == 2)
@@ -243,6 +241,7 @@
 	unsigned int idx, prio;
 	dma_addr_t mapping;
 	u32 tx_flags;
+	u8 rc_flags;
 	u16 plcp_len = 0;
 	__le16 rts_duration = 0;
 
@@ -261,15 +260,16 @@
 		tx_flags |= RTL818X_TX_DESC_FLAG_DMA |
 			    RTL818X_TX_DESC_FLAG_NO_ENC;
 
-	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+	rc_flags = info->control.rates[0].flags;
+	if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
 		tx_flags |= RTL818X_TX_DESC_FLAG_RTS;
 		tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
-	} else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+	} else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
 		tx_flags |= RTL818X_TX_DESC_FLAG_CTS;
 		tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
 	}
 
-	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+	if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
 		rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len,
 						      info);
 
@@ -292,9 +292,9 @@
 	entry->plcp_len = cpu_to_le16(plcp_len);
 	entry->tx_buf = cpu_to_le32(mapping);
 	entry->frame_len = cpu_to_le32(skb->len);
-	entry->flags2 = info->control.retries[0].rate_idx >= 0 ?
+	entry->flags2 = info->control.rates[1].idx >= 0 ?
 		ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0;
-	entry->retry_limit = info->control.retry_limit;
+	entry->retry_limit = info->control.rates[0].count;
 	entry->flags = cpu_to_le32(tx_flags);
 	__skb_queue_tail(&ring->queue, skb);
 	if (ring->entries - skb_queue_len(&ring->queue) < 2)
@@ -692,9 +692,10 @@
 	priv->vif = NULL;
 }
 
-static int rtl8180_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+static int rtl8180_config(struct ieee80211_hw *dev, u32 changed)
 {
 	struct rtl8180_priv *priv = dev->priv;
+	struct ieee80211_conf *conf = &dev->conf;
 
 	priv->rf->set_chan(dev, conf);
 
@@ -719,6 +720,17 @@
 	return 0;
 }
 
+static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
+				     struct ieee80211_vif *vif,
+				     struct ieee80211_bss_conf *info,
+				     u32 changed)
+{
+	struct rtl8180_priv *priv = dev->priv;
+
+	if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp)
+	        priv->rf->conf_erp(dev, info);
+}
+
 static void rtl8180_configure_filter(struct ieee80211_hw *dev,
 				     unsigned int changed_flags,
 				     unsigned int *total_flags,
@@ -759,6 +771,7 @@
 	.remove_interface	= rtl8180_remove_interface,
 	.config			= rtl8180_config,
 	.config_interface	= rtl8180_config_interface,
+	.bss_info_changed	= rtl8180_bss_info_changed,
 	.configure_filter	= rtl8180_configure_filter,
 };
 
@@ -806,7 +819,6 @@
 	const char *chip_name, *rf_name = NULL;
 	u32 reg;
 	u16 eeprom_val;
-	DECLARE_MAC_BUF(mac);
 
 	err = pci_enable_device(pdev);
 	if (err) {
@@ -855,7 +867,7 @@
 	priv = dev->priv;
 	priv->pdev = pdev;
 
-	dev->max_altrates = 1;
+	dev->max_rates = 2;
 	SET_IEEE80211_DEV(dev, &pdev->dev);
 	pci_set_drvdata(pdev, dev);
 
@@ -1002,8 +1014,8 @@
 		goto err_iounmap;
 	}
 
-	printk(KERN_INFO "%s: hwaddr %s, %s + %s\n",
-	       wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
+	printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n",
+	       wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
 	       chip_name, priv->rf->name);
 
 	return 0;
diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
similarity index 100%
rename from drivers/net/wireless/rtl8180_grf5101.c
rename to drivers/net/wireless/rtl818x/rtl8180_grf5101.c
diff --git a/drivers/net/wireless/rtl8180_grf5101.h b/drivers/net/wireless/rtl818x/rtl8180_grf5101.h
similarity index 100%
rename from drivers/net/wireless/rtl8180_grf5101.h
rename to drivers/net/wireless/rtl818x/rtl8180_grf5101.h
diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl818x/rtl8180_max2820.c
similarity index 100%
rename from drivers/net/wireless/rtl8180_max2820.c
rename to drivers/net/wireless/rtl818x/rtl8180_max2820.c
diff --git a/drivers/net/wireless/rtl8180_max2820.h b/drivers/net/wireless/rtl818x/rtl8180_max2820.h
similarity index 100%
rename from drivers/net/wireless/rtl8180_max2820.h
rename to drivers/net/wireless/rtl818x/rtl8180_max2820.h
diff --git a/drivers/net/wireless/rtl8180_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
similarity index 98%
rename from drivers/net/wireless/rtl8180_rtl8225.c
rename to drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
index cd22781..4d2be0d 100644
--- a/drivers/net/wireless/rtl8180_rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
@@ -725,8 +725,14 @@
 
 	rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);
 	msleep(10);
+}
 
-	if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
+static void rtl8225_rf_conf_erp(struct ieee80211_hw *dev,
+				struct ieee80211_bss_conf *info)
+{
+	struct rtl8180_priv *priv = dev->priv;
+
+	if (info->use_short_slot) {
 		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
 		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
 		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
@@ -745,14 +751,16 @@
 	.name		= "rtl8225",
 	.init		= rtl8225_rf_init,
 	.stop		= rtl8225_rf_stop,
-	.set_chan	= rtl8225_rf_set_channel
+	.set_chan	= rtl8225_rf_set_channel,
+	.conf_erp	= rtl8225_rf_conf_erp,
 };
 
 static const struct rtl818x_rf_ops rtl8225z2_ops = {
 	.name		= "rtl8225z2",
 	.init		= rtl8225z2_rf_init,
 	.stop		= rtl8225_rf_stop,
-	.set_chan	= rtl8225_rf_set_channel
+	.set_chan	= rtl8225_rf_set_channel,
+	.conf_erp	= rtl8225_rf_conf_erp,
 };
 
 const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev)
diff --git a/drivers/net/wireless/rtl8180_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h
similarity index 100%
rename from drivers/net/wireless/rtl8180_rtl8225.h
rename to drivers/net/wireless/rtl818x/rtl8180_rtl8225.h
diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
similarity index 100%
rename from drivers/net/wireless/rtl8180_sa2400.c
rename to drivers/net/wireless/rtl818x/rtl8180_sa2400.c
diff --git a/drivers/net/wireless/rtl8180_sa2400.h b/drivers/net/wireless/rtl818x/rtl8180_sa2400.h
similarity index 100%
rename from drivers/net/wireless/rtl8180_sa2400.h
rename to drivers/net/wireless/rtl818x/rtl8180_sa2400.h
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
similarity index 97%
rename from drivers/net/wireless/rtl8187.h
rename to drivers/net/wireless/rtl818x/rtl8187.h
index e82bb4d..3b1e1c2 100644
--- a/drivers/net/wireless/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187.h
@@ -99,8 +99,8 @@
 	struct ieee80211_supported_band band;
 	struct usb_device *udev;
 	u32 rx_conf;
+	struct usb_anchor anchored;
 	u16 txpwr_base;
-	u16 seqno;
 	u8 asic_rev;
 	u8 is_rtl8187b;
 	enum {
@@ -112,6 +112,12 @@
 	u8 signal;
 	u8 quality;
 	u8 noise;
+	u8 slot_time;
+	u8 aifsn[4];
+	struct {
+		__le64 buf;
+		struct sk_buff_head queue;
+	} b_tx_status;
 };
 
 void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
similarity index 78%
rename from drivers/net/wireless/rtl8187_dev.c
rename to drivers/net/wireless/rtl818x/rtl8187_dev.c
index 69eb013..00ce3ef 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -7,6 +7,11 @@
  * Based on the r8187 driver, which is:
  * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
  *
+ * The driver was extended to the RTL8187B in 2008 by:
+ * 	Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ *	Hin-Tak Leung <htl10@users.sourceforge.net>
+ *	Larry Finger <Larry.Finger@lwfinger.net>
+ *
  * Magic delays and register offsets below are taken from the original
  * r8187 driver sources.  Thanks to Realtek for their support!
  *
@@ -27,6 +32,9 @@
 
 MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
 MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
+MODULE_AUTHOR("Herton Ronaldo Krzesinski <herton@mandriva.com.br>");
+MODULE_AUTHOR("Hin-Tak Leung <htl10@users.sourceforge.net>");
+MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>");
 MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver");
 MODULE_LICENSE("GPL");
 
@@ -91,7 +99,6 @@
 static void rtl8187_iowrite_async_cb(struct urb *urb)
 {
 	kfree(urb->context);
-	usb_free_urb(urb);
 }
 
 static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
@@ -128,11 +135,13 @@
 	usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0),
 			     (unsigned char *)dr, buf, len,
 			     rtl8187_iowrite_async_cb, buf);
+	usb_anchor_urb(urb, &priv->anchored);
 	rc = usb_submit_urb(urb, GFP_ATOMIC);
 	if (rc < 0) {
 		kfree(buf);
-		usb_free_urb(urb);
+		usb_unanchor_urb(urb);
 	}
+	usb_free_urb(urb);
 }
 
 static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv,
@@ -155,30 +164,45 @@
 	rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF);
 	rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF);
 	rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF);
-
-	msleep(1);
 }
 
 static void rtl8187_tx_cb(struct urb *urb)
 {
 	struct sk_buff *skb = (struct sk_buff *)urb->context;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_hw *hw = info->driver_data[0];
+	struct ieee80211_hw *hw = info->rate_driver_data[0];
 	struct rtl8187_priv *priv = hw->priv;
 
-	usb_free_urb(info->driver_data[1]);
 	skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
 					  sizeof(struct rtl8187_tx_hdr));
-	memset(&info->status, 0, sizeof(info->status));
-	info->flags |= IEEE80211_TX_STAT_ACK;
-	ieee80211_tx_status_irqsafe(hw, skb);
+	ieee80211_tx_info_clear_status(info);
+
+	if (!urb->status &&
+	    !(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+	    priv->is_rtl8187b) {
+		skb_queue_tail(&priv->b_tx_status.queue, skb);
+
+		/* queue is "full", discard last items */
+		while (skb_queue_len(&priv->b_tx_status.queue) > 5) {
+			struct sk_buff *old_skb;
+
+			dev_dbg(&priv->udev->dev,
+				"transmit status queue full\n");
+
+			old_skb = skb_dequeue(&priv->b_tx_status.queue);
+			ieee80211_tx_status_irqsafe(hw, old_skb);
+		}
+	} else {
+		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !urb->status)
+			info->flags |= IEEE80211_TX_STAT_ACK;
+		ieee80211_tx_status_irqsafe(hw, skb);
+	}
 }
 
 static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct rtl8187_priv *priv = dev->priv;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
 	unsigned int ep;
 	void *buf;
 	struct urb *urb;
@@ -189,7 +213,7 @@
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!urb) {
 		kfree_skb(skb);
-		return 0;
+		return -ENOMEM;
 	}
 
 	flags = skb->len;
@@ -198,12 +222,12 @@
 	flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
 	if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control))
 		flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;
-	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
 		flags |= RTL818X_TX_DESC_FLAG_RTS;
 		flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
 		rts_dur = ieee80211_rts_duration(dev, priv->vif,
 						 skb->len, info);
-	} else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+	} else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
 		flags |= RTL818X_TX_DESC_FLAG_CTS;
 		flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
 	}
@@ -214,7 +238,7 @@
 		hdr->flags = cpu_to_le32(flags);
 		hdr->len = 0;
 		hdr->rts_duration = rts_dur;
-		hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
+		hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
 		buf = hdr;
 
 		ep = 2;
@@ -232,7 +256,7 @@
 		memset(hdr, 0, sizeof(*hdr));
 		hdr->flags = cpu_to_le32(flags);
 		hdr->rts_duration = rts_dur;
-		hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
+		hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
 		hdr->tx_duration =
 			ieee80211_generic_frame_duration(dev, priv->vif,
 							 skb->len, txrate);
@@ -244,32 +268,20 @@
 			ep = epmap[skb_get_queue_mapping(skb)];
 	}
 
-	/* FIXME: The sequence that follows is needed for this driver to
-	 * work with mac80211 since "mac80211: fix TX sequence numbers".
-	 * As with the temporary code in rt2x00, changes will be needed
-	 * to get proper sequence numbers on beacons. In addition, this
-	 * patch places the sequence number in the hardware state, which
-	 * limits us to a single virtual state.
-	 */
-	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-		if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
-			priv->seqno += 0x10;
-		ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-		ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
-	}
-
-	info->driver_data[0] = dev;
-	info->driver_data[1] = urb;
+	info->rate_driver_data[0] = dev;
+	info->rate_driver_data[1] = urb;
 
 	usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep),
 			  buf, skb->len, rtl8187_tx_cb, skb);
+	usb_anchor_urb(urb, &priv->anchored);
 	rc = usb_submit_urb(urb, GFP_ATOMIC);
 	if (rc < 0) {
-		usb_free_urb(urb);
+		usb_unanchor_urb(urb);
 		kfree_skb(skb);
 	}
+	usb_free_urb(urb);
 
-	return 0;
+	return rc;
 }
 
 static void rtl8187_rx_cb(struct urb *urb)
@@ -282,50 +294,35 @@
 	int rate, signal;
 	u32 flags;
 	u32 quality;
+	unsigned long f;
 
-	spin_lock(&priv->rx_queue.lock);
+	spin_lock_irqsave(&priv->rx_queue.lock, f);
 	if (skb->next)
 		__skb_unlink(skb, &priv->rx_queue);
 	else {
-		spin_unlock(&priv->rx_queue.lock);
+		spin_unlock_irqrestore(&priv->rx_queue.lock, f);
 		return;
 	}
-	spin_unlock(&priv->rx_queue.lock);
+	spin_unlock_irqrestore(&priv->rx_queue.lock, f);
+	skb_put(skb, urb->actual_length);
 
 	if (unlikely(urb->status)) {
-		usb_free_urb(urb);
 		dev_kfree_skb_irq(skb);
 		return;
 	}
 
-	skb_put(skb, urb->actual_length);
 	if (!priv->is_rtl8187b) {
 		struct rtl8187_rx_hdr *hdr =
 			(typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
 		flags = le32_to_cpu(hdr->flags);
-		signal = hdr->signal & 0x7f;
+		/* As with the RTL8187B below, the AGC is used to calculate
+		 * signal strength and quality. In this case, the scaling
+		 * constants are derived from the output of p54usb.
+		 */
+		quality = 130 - ((41 * hdr->agc) >> 6);
+		signal = -4 - ((27 * hdr->agc) >> 6);
 		rx_status.antenna = (hdr->signal >> 7) & 1;
-		rx_status.noise = hdr->noise;
 		rx_status.mactime = le64_to_cpu(hdr->mac_time);
-		priv->quality = signal;
-		rx_status.qual = priv->quality;
-		priv->noise = hdr->noise;
-		rate = (flags >> 20) & 0xF;
-		if (rate > 3) { /* OFDM rate */
-			if (signal > 90)
-				signal = 90;
-			else if (signal < 25)
-				signal = 25;
-			signal = 90 - signal;
-		} else {	/* CCK rate */
-			if (signal > 95)
-				signal = 95;
-			else if (signal < 30)
-				signal = 30;
-			signal = 95 - signal;
-		}
-		rx_status.signal = signal;
-		priv->signal = signal;
 	} else {
 		struct rtl8187b_rx_hdr *hdr =
 			(typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
@@ -343,18 +340,18 @@
 		 */
 		flags = le32_to_cpu(hdr->flags);
 		quality = 170 - hdr->agc;
-		if (quality > 100)
-			quality = 100;
 		signal = 14 - hdr->agc / 2;
-		rx_status.qual = quality;
-		priv->quality = quality;
-		rx_status.signal = signal;
-		priv->signal = signal;
 		rx_status.antenna = (hdr->rssi >> 7) & 1;
 		rx_status.mactime = le64_to_cpu(hdr->mac_time);
-		rate = (flags >> 20) & 0xF;
 	}
 
+	if (quality > 100)
+		quality = 100;
+	rx_status.qual = quality;
+	priv->quality = quality;
+	rx_status.signal = signal;
+	priv->signal = signal;
+	rate = (flags >> 20) & 0xF;
 	skb_trim(skb, flags & 0x0FFF);
 	rx_status.rate_idx = rate;
 	rx_status.freq = dev->conf.channel->center_freq;
@@ -366,7 +363,6 @@
 
 	skb = dev_alloc_skb(RTL8187_MAX_RX);
 	if (unlikely(!skb)) {
-		usb_free_urb(urb);
 		/* TODO check rx queue length and refill *somewhere* */
 		return;
 	}
@@ -378,24 +374,32 @@
 	urb->context = skb;
 	skb_queue_tail(&priv->rx_queue, skb);
 
-	usb_submit_urb(urb, GFP_ATOMIC);
+	usb_anchor_urb(urb, &priv->anchored);
+	if (usb_submit_urb(urb, GFP_ATOMIC)) {
+		usb_unanchor_urb(urb);
+		skb_unlink(skb, &priv->rx_queue);
+		dev_kfree_skb_irq(skb);
+	}
 }
 
 static int rtl8187_init_urbs(struct ieee80211_hw *dev)
 {
 	struct rtl8187_priv *priv = dev->priv;
-	struct urb *entry;
+	struct urb *entry = NULL;
 	struct sk_buff *skb;
 	struct rtl8187_rx_info *info;
+	int ret = 0;
 
 	while (skb_queue_len(&priv->rx_queue) < 8) {
 		skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);
-		if (!skb)
-			break;
+		if (!skb) {
+			ret = -ENOMEM;
+			goto err;
+		}
 		entry = usb_alloc_urb(0, GFP_KERNEL);
 		if (!entry) {
-			kfree_skb(skb);
-			break;
+			ret = -ENOMEM;
+			goto err;
 		}
 		usb_fill_bulk_urb(entry, priv->udev,
 				  usb_rcvbulkpipe(priv->udev,
@@ -406,10 +410,129 @@
 		info->urb = entry;
 		info->dev = dev;
 		skb_queue_tail(&priv->rx_queue, skb);
-		usb_submit_urb(entry, GFP_KERNEL);
+		usb_anchor_urb(entry, &priv->anchored);
+		ret = usb_submit_urb(entry, GFP_KERNEL);
+		if (ret) {
+			skb_unlink(skb, &priv->rx_queue);
+			usb_unanchor_urb(entry);
+			goto err;
+		}
+		usb_free_urb(entry);
+	}
+	return ret;
+
+err:
+	usb_free_urb(entry);
+	kfree_skb(skb);
+	usb_kill_anchored_urbs(&priv->anchored);
+	return ret;
+}
+
+static void rtl8187b_status_cb(struct urb *urb)
+{
+	struct ieee80211_hw *hw = (struct ieee80211_hw *)urb->context;
+	struct rtl8187_priv *priv = hw->priv;
+	u64 val;
+	unsigned int cmd_type;
+
+	if (unlikely(urb->status))
+		return;
+
+	/*
+	 * Read from status buffer:
+	 *
+	 * bits [30:31] = cmd type:
+	 * - 0 indicates tx beacon interrupt
+	 * - 1 indicates tx close descriptor
+	 *
+	 * In the case of tx beacon interrupt:
+	 * [0:9] = Last Beacon CW
+	 * [10:29] = reserved
+	 * [30:31] = 00b
+	 * [32:63] = Last Beacon TSF
+	 *
+	 * If it's tx close descriptor:
+	 * [0:7] = Packet Retry Count
+	 * [8:14] = RTS Retry Count
+	 * [15] = TOK
+	 * [16:27] = Sequence No
+	 * [28] = LS
+	 * [29] = FS
+	 * [30:31] = 01b
+	 * [32:47] = unused (reserved?)
+	 * [48:63] = MAC Used Time
+	 */
+	val = le64_to_cpu(priv->b_tx_status.buf);
+
+	cmd_type = (val >> 30) & 0x3;
+	if (cmd_type == 1) {
+		unsigned int pkt_rc, seq_no;
+		bool tok;
+		struct sk_buff *skb;
+		struct ieee80211_hdr *ieee80211hdr;
+		unsigned long flags;
+
+		pkt_rc = val & 0xFF;
+		tok = val & (1 << 15);
+		seq_no = (val >> 16) & 0xFFF;
+
+		spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags);
+		skb_queue_reverse_walk(&priv->b_tx_status.queue, skb) {
+			ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+
+			/*
+			 * While testing, it was discovered that the seq_no
+			 * doesn't actually contains the sequence number.
+			 * Instead of returning just the 12 bits of sequence
+			 * number, hardware is returning entire sequence control
+			 * (fragment number plus sequence number) in a 12 bit
+			 * only field overflowing after some time. As a
+			 * workaround, just consider the lower bits, and expect
+			 * it's unlikely we wrongly ack some sent data
+			 */
+			if ((le16_to_cpu(ieee80211hdr->seq_ctrl)
+			    & 0xFFF) == seq_no)
+				break;
+		}
+		if (skb != (struct sk_buff *) &priv->b_tx_status.queue) {
+			struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+			__skb_unlink(skb, &priv->b_tx_status.queue);
+			if (tok)
+				info->flags |= IEEE80211_TX_STAT_ACK;
+			info->status.rates[0].count = pkt_rc + 1;
+
+			ieee80211_tx_status_irqsafe(hw, skb);
+		}
+		spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
 	}
 
-	return 0;
+	usb_anchor_urb(urb, &priv->anchored);
+	if (usb_submit_urb(urb, GFP_ATOMIC))
+		usb_unanchor_urb(urb);
+}
+
+static int rtl8187b_init_status_urb(struct ieee80211_hw *dev)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	struct urb *entry;
+	int ret = 0;
+
+	entry = usb_alloc_urb(0, GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9),
+			  &priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf),
+			  rtl8187b_status_cb, dev);
+
+	usb_anchor_urb(entry, &priv->anchored);
+	ret = usb_submit_urb(entry, GFP_KERNEL);
+	if (ret)
+		usb_unanchor_urb(entry);
+	usb_free_urb(entry);
+
+	return ret;
 }
 
 static int rtl8187_cmd_reset(struct ieee80211_hw *dev)
@@ -687,7 +810,7 @@
 	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
 	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488);
 	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
-	msleep(1100);
+	msleep(100);
 
 	priv->rf->init(dev);
 
@@ -721,6 +844,13 @@
 
 	rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1);
 
+	priv->slot_time = 0x9;
+	priv->aifsn[0] = 2; /* AIFSN[AC_VO] */
+	priv->aifsn[1] = 2; /* AIFSN[AC_VI] */
+	priv->aifsn[2] = 7; /* AIFSN[AC_BK] */
+	priv->aifsn[3] = 3; /* AIFSN[AC_BE] */
+	rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
+
 	return 0;
 }
 
@@ -736,6 +866,9 @@
 		return ret;
 
 	mutex_lock(&priv->conf_mutex);
+
+	init_usb_anchor(&priv->anchored);
+
 	if (priv->is_rtl8187b) {
 		reg = RTL818X_RX_CONF_MGMT |
 		      RTL818X_RX_CONF_DATA |
@@ -757,6 +890,7 @@
 				  (7 << 0  /* long retry limit */) |
 				  (7 << 21 /* MAX TX DMA */));
 		rtl8187_init_urbs(dev);
+		rtl8187b_init_status_urb(dev);
 		mutex_unlock(&priv->conf_mutex);
 		return 0;
 	}
@@ -809,7 +943,6 @@
 static void rtl8187_stop(struct ieee80211_hw *dev)
 {
 	struct rtl8187_priv *priv = dev->priv;
-	struct rtl8187_rx_info *info;
 	struct sk_buff *skb;
 	u32 reg;
 
@@ -828,11 +961,10 @@
 	rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
-	while ((skb = skb_dequeue(&priv->rx_queue))) {
-		info = (struct rtl8187_rx_info *)skb->cb;
-		usb_kill_urb(info->urb);
-		kfree_skb(skb);
-	}
+	while ((skb = skb_dequeue(&priv->b_tx_status.queue)))
+		dev_kfree_skb_any(skb);
+
+	usb_kill_anchored_urbs(&priv->anchored);
 	mutex_unlock(&priv->conf_mutex);
 }
 
@@ -876,9 +1008,10 @@
 	mutex_unlock(&priv->conf_mutex);
 }
 
-static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+static int rtl8187_config(struct ieee80211_hw *dev, u32 changed)
 {
 	struct rtl8187_priv *priv = dev->priv;
+	struct ieee80211_conf *conf = &dev->conf;
 	u32 reg;
 
 	mutex_lock(&priv->conf_mutex);
@@ -889,27 +1022,10 @@
 	 */
 	rtl818x_iowrite32(priv, &priv->map->TX_CONF,
 			  reg | RTL818X_TX_CONF_LOOPBACK_MAC);
-	msleep(10);
 	priv->rf->set_chan(dev, conf);
 	msleep(10);
 	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
 
-	if (!priv->is_rtl8187b) {
-		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
-
-		if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
-			rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
-			rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
-			rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
-			rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
-		} else {
-			rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
-			rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
-			rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
-			rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
-		}
-	}
-
 	rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2);
 	rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
 	rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
@@ -944,6 +1060,89 @@
 	return 0;
 }
 
+/*
+ * With 8187B, AC_*_PARAM clashes with FEMR definition in struct rtl818x_csr for
+ * example. Thus we have to use raw values for AC_*_PARAM register addresses.
+ */
+static __le32 *rtl8187b_ac_addr[4] = {
+	(__le32 *) 0xFFF0, /* AC_VO */
+	(__le32 *) 0xFFF4, /* AC_VI */
+	(__le32 *) 0xFFFC, /* AC_BK */
+	(__le32 *) 0xFFF8, /* AC_BE */
+};
+
+#define SIFS_TIME 0xa
+
+static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot,
+			     bool use_short_preamble)
+{
+	if (priv->is_rtl8187b) {
+		u8 difs, eifs;
+		u16 ack_timeout;
+		int queue;
+
+		if (use_short_slot) {
+			priv->slot_time = 0x9;
+			difs = 0x1c;
+			eifs = 0x53;
+		} else {
+			priv->slot_time = 0x14;
+			difs = 0x32;
+			eifs = 0x5b;
+		}
+		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
+		rtl818x_iowrite8(priv, &priv->map->SLOT, priv->slot_time);
+		rtl818x_iowrite8(priv, &priv->map->DIFS, difs);
+
+		/*
+		 * BRSR+1 on 8187B is in fact EIFS register
+		 * Value in units of 4 us
+		 */
+		rtl818x_iowrite8(priv, (u8 *)&priv->map->BRSR + 1, eifs);
+
+		/*
+		 * For 8187B, CARRIER_SENSE_COUNTER is in fact ack timeout
+		 * register. In units of 4 us like eifs register
+		 * ack_timeout = ack duration + plcp + difs + preamble
+		 */
+		ack_timeout = 112 + 48 + difs;
+		if (use_short_preamble)
+			ack_timeout += 72;
+		else
+			ack_timeout += 144;
+		rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER,
+				 DIV_ROUND_UP(ack_timeout, 4));
+
+		for (queue = 0; queue < 4; queue++)
+			rtl818x_iowrite8(priv, (u8 *) rtl8187b_ac_addr[queue],
+					 priv->aifsn[queue] * priv->slot_time +
+					 SIFS_TIME);
+	} else {
+		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
+		if (use_short_slot) {
+			rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
+			rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
+			rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
+		} else {
+			rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
+			rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
+			rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
+		}
+	}
+}
+
+static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
+				     struct ieee80211_vif *vif,
+				     struct ieee80211_bss_conf *info,
+				     u32 changed)
+{
+	struct rtl8187_priv *priv = dev->priv;
+
+	if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE))
+		rtl8187_conf_erp(priv, info->use_short_slot,
+				 info->use_short_preamble);
+}
+
 static void rtl8187_configure_filter(struct ieee80211_hw *dev,
 				     unsigned int changed_flags,
 				     unsigned int *total_flags,
@@ -976,6 +1175,42 @@
 	rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf);
 }
 
+static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue,
+			   const struct ieee80211_tx_queue_params *params)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	u8 cw_min, cw_max;
+
+	if (queue > 3)
+		return -EINVAL;
+
+	cw_min = fls(params->cw_min);
+	cw_max = fls(params->cw_max);
+
+	if (priv->is_rtl8187b) {
+		priv->aifsn[queue] = params->aifs;
+
+		/*
+		 * This is the structure of AC_*_PARAM registers in 8187B:
+		 * - TXOP limit field, bit offset = 16
+		 * - ECWmax, bit offset = 12
+		 * - ECWmin, bit offset = 8
+		 * - AIFS, bit offset = 0
+		 */
+		rtl818x_iowrite32(priv, rtl8187b_ac_addr[queue],
+				  (params->txop << 16) | (cw_max << 12) |
+				  (cw_min << 8) | (params->aifs *
+				  priv->slot_time + SIFS_TIME));
+	} else {
+		if (queue != 0)
+			return -EINVAL;
+
+		rtl818x_iowrite8(priv, &priv->map->CW_VAL,
+				 cw_min | (cw_max << 4));
+	}
+	return 0;
+}
+
 static const struct ieee80211_ops rtl8187_ops = {
 	.tx			= rtl8187_tx,
 	.start			= rtl8187_start,
@@ -984,7 +1219,9 @@
 	.remove_interface	= rtl8187_remove_interface,
 	.config			= rtl8187_config,
 	.config_interface	= rtl8187_config_interface,
+	.bss_info_changed	= rtl8187_bss_info_changed,
 	.configure_filter	= rtl8187_configure_filter,
+	.conf_tx		= rtl8187_conf_tx
 };
 
 static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -1029,7 +1266,6 @@
 	const char *chip_name;
 	u16 txpwr, reg;
 	int err, i;
-	DECLARE_MAC_BUF(mac);
 
 	dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
 	if (!dev) {
@@ -1065,6 +1301,7 @@
 
 	priv->mode = NL80211_IFTYPE_MONITOR;
 	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+		     IEEE80211_HW_SIGNAL_DBM |
 		     IEEE80211_HW_RX_INCLUDES_FCS;
 
 	eeprom.data = dev;
@@ -1180,16 +1417,13 @@
 		(*channel++).hw_value = txpwr >> 8;
 	}
 
-	if (priv->is_rtl8187b) {
-		printk(KERN_WARNING "rtl8187: 8187B chip detected. Support "
-			"is EXPERIMENTAL, and could damage your\n"
-			"         hardware, use at your own risk\n");
-		dev->flags |= IEEE80211_HW_SIGNAL_DBM;
-	} else {
-		dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
-		dev->max_signal = 65;
-	}
+	if (priv->is_rtl8187b)
+		printk(KERN_WARNING "rtl8187: 8187B chip detected.\n");
 
+	/*
+	 * XXX: Once this driver supports anything that requires
+	 *	beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ.
+	 */
 	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
 
 	if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
@@ -1211,9 +1445,10 @@
 		goto err_free_dev;
 	}
 	mutex_init(&priv->conf_mutex);
+	skb_queue_head_init(&priv->b_tx_status.queue);
 
-	printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n",
-	       wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
+	printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n",
+	       wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
 	       chip_name, priv->asic_rev, priv->rf->name);
 
 	return 0;
diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
similarity index 69%
rename from drivers/net/wireless/rtl8187_rtl8225.c
rename to drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
index 1bae899..4e75e8e 100644
--- a/drivers/net/wireless/rtl8187_rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
@@ -64,7 +64,6 @@
 
 	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
 	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
-	msleep(2);
 }
 
 static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
@@ -98,7 +97,6 @@
 
 	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
 	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
-	msleep(2);
 }
 
 static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
@@ -333,21 +331,21 @@
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
 
-	rtl8225_write(dev, 0x0, 0x067); msleep(1);
-	rtl8225_write(dev, 0x1, 0xFE0); msleep(1);
-	rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-	rtl8225_write(dev, 0x3, 0x441); msleep(1);
-	rtl8225_write(dev, 0x4, 0x486); msleep(1);
-	rtl8225_write(dev, 0x5, 0xBC0); msleep(1);
-	rtl8225_write(dev, 0x6, 0xAE6); msleep(1);
-	rtl8225_write(dev, 0x7, 0x82A); msleep(1);
-	rtl8225_write(dev, 0x8, 0x01F); msleep(1);
-	rtl8225_write(dev, 0x9, 0x334); msleep(1);
-	rtl8225_write(dev, 0xA, 0xFD4); msleep(1);
-	rtl8225_write(dev, 0xB, 0x391); msleep(1);
-	rtl8225_write(dev, 0xC, 0x050); msleep(1);
-	rtl8225_write(dev, 0xD, 0x6DB); msleep(1);
-	rtl8225_write(dev, 0xE, 0x029); msleep(1);
+	rtl8225_write(dev, 0x0, 0x067);
+	rtl8225_write(dev, 0x1, 0xFE0);
+	rtl8225_write(dev, 0x2, 0x44D);
+	rtl8225_write(dev, 0x3, 0x441);
+	rtl8225_write(dev, 0x4, 0x486);
+	rtl8225_write(dev, 0x5, 0xBC0);
+	rtl8225_write(dev, 0x6, 0xAE6);
+	rtl8225_write(dev, 0x7, 0x82A);
+	rtl8225_write(dev, 0x8, 0x01F);
+	rtl8225_write(dev, 0x9, 0x334);
+	rtl8225_write(dev, 0xA, 0xFD4);
+	rtl8225_write(dev, 0xB, 0x391);
+	rtl8225_write(dev, 0xC, 0x050);
+	rtl8225_write(dev, 0xD, 0x6DB);
+	rtl8225_write(dev, 0xE, 0x029);
 	rtl8225_write(dev, 0xF, 0x914); msleep(100);
 
 	rtl8225_write(dev, 0x2, 0xC4D); msleep(200);
@@ -375,91 +373,89 @@
 
 	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
 		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
-		msleep(1);
 		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
-		msleep(1);
 	}
 
 	msleep(1);
 
-	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
+	rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
+	rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
+	rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
+	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09);
+	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
+	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
+	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
+	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
+	rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
+	rtl8225_write_phy_ofdm(dev, 0x11, 0x06);
+	rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
+	rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
+	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76);
+	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
+	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
+	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
+	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
+	rtl8225_write_phy_ofdm(dev, 0x21, 0x27);
+	rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
+	rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
+	rtl8225_write_phy_ofdm(dev, 0x25, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
+	rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
 
 	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
 	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
 	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
 	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
 
-	rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x00, 0x98);
+	rtl8225_write_phy_cck(dev, 0x03, 0x20);
+	rtl8225_write_phy_cck(dev, 0x04, 0x7e);
+	rtl8225_write_phy_cck(dev, 0x05, 0x12);
+	rtl8225_write_phy_cck(dev, 0x06, 0xfc);
+	rtl8225_write_phy_cck(dev, 0x07, 0x78);
+	rtl8225_write_phy_cck(dev, 0x08, 0x2e);
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b);
+	rtl8225_write_phy_cck(dev, 0x11, 0x88);
+	rtl8225_write_phy_cck(dev, 0x12, 0x47);
 	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
 	rtl8225_write_phy_cck(dev, 0x19, 0x00);
 	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
 	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
 	rtl8225_write_phy_cck(dev, 0x40, 0x86);
-	rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x41, 0x8d);
+	rtl8225_write_phy_cck(dev, 0x42, 0x15);
+	rtl8225_write_phy_cck(dev, 0x43, 0x18);
+	rtl8225_write_phy_cck(dev, 0x44, 0x1f);
+	rtl8225_write_phy_cck(dev, 0x45, 0x1e);
+	rtl8225_write_phy_cck(dev, 0x46, 0x1a);
+	rtl8225_write_phy_cck(dev, 0x47, 0x15);
+	rtl8225_write_phy_cck(dev, 0x48, 0x10);
+	rtl8225_write_phy_cck(dev, 0x49, 0x0a);
+	rtl8225_write_phy_cck(dev, 0x4a, 0x05);
+	rtl8225_write_phy_cck(dev, 0x4b, 0x02);
+	rtl8225_write_phy_cck(dev, 0x4c, 0x05);
 
 	rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
 
 	rtl8225_rf_set_tx_power(dev, 1);
 
 	/* RX antenna default to A */
-	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);	/* B: 0xDB */
-	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);	/* B: 0x10 */
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b);			/* B: 0xDB */
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);		/* B: 0x10 */
 
 	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
 	msleep(1);
@@ -629,7 +625,7 @@
 		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
 
 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
-			 rtl8225z2_tx_gain_cck_ofdm[cck_power]);
+			 rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1);
 	msleep(1);
 
 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
@@ -687,22 +683,23 @@
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
 
-	rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
-	rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
-	rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-	rtl8225_write(dev, 0x3, 0x441); msleep(1);
-	rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
-	rtl8225_write(dev, 0x5, 0xC72); msleep(1);
-	rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
-	rtl8225_write(dev, 0x7, 0x82A); msleep(1);
-	rtl8225_write(dev, 0x8, 0x03F); msleep(1);
-	rtl8225_write(dev, 0x9, 0x335); msleep(1);
-	rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
-	rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
-	rtl8225_write(dev, 0xc, 0x850); msleep(1);
-	rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
-	rtl8225_write(dev, 0xe, 0x02B); msleep(1);
-	rtl8225_write(dev, 0xf, 0x114); msleep(100);
+	rtl8225_write(dev, 0x0, 0x2BF);
+	rtl8225_write(dev, 0x1, 0xEE0);
+	rtl8225_write(dev, 0x2, 0x44D);
+	rtl8225_write(dev, 0x3, 0x441);
+	rtl8225_write(dev, 0x4, 0x8C3);
+	rtl8225_write(dev, 0x5, 0xC72);
+	rtl8225_write(dev, 0x6, 0x0E6);
+	rtl8225_write(dev, 0x7, 0x82A);
+	rtl8225_write(dev, 0x8, 0x03F);
+	rtl8225_write(dev, 0x9, 0x335);
+	rtl8225_write(dev, 0xa, 0x9D4);
+	rtl8225_write(dev, 0xb, 0x7BB);
+	rtl8225_write(dev, 0xc, 0x850);
+	rtl8225_write(dev, 0xd, 0xCDF);
+	rtl8225_write(dev, 0xe, 0x02B);
+	rtl8225_write(dev, 0xf, 0x114);
+	msleep(100);
 
 	rtl8225_write(dev, 0x0, 0x1B7);
 
@@ -736,94 +733,92 @@
 
 	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
 		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
-		msleep(1);
 		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
-		msleep(1);
 	}
 
 	msleep(1);
 
-	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
+	rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
+	rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
+	rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
+	rtl8225_write_phy_ofdm(dev, 0x0a, 0x08);
+	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
+	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
 	rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
-	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed?
-	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
+	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
+	rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
+	rtl8225_write_phy_ofdm(dev, 0x11, 0x07);
+	rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
+	rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
+	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
+	rtl8225_write_phy_ofdm(dev, 0x1b, 0x15);
+	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
+	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5);
+	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
+	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
+	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
+	rtl8225_write_phy_ofdm(dev, 0x21, 0x17);
+	rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
+	rtl8225_write_phy_ofdm(dev, 0x23, 0x80);
+	rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
+	rtl8225_write_phy_ofdm(dev, 0x25, 0x00);
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
+	rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
 
 	rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
 	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
 	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
 	rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
 
-	rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x00, 0x98);
+	rtl8225_write_phy_cck(dev, 0x03, 0x20);
+	rtl8225_write_phy_cck(dev, 0x04, 0x7e);
+	rtl8225_write_phy_cck(dev, 0x05, 0x12);
+	rtl8225_write_phy_cck(dev, 0x06, 0xfc);
+	rtl8225_write_phy_cck(dev, 0x07, 0x78);
+	rtl8225_write_phy_cck(dev, 0x08, 0x2e);
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b);
+	rtl8225_write_phy_cck(dev, 0x11, 0x88);
+	rtl8225_write_phy_cck(dev, 0x12, 0x47);
 	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
 	rtl8225_write_phy_cck(dev, 0x19, 0x00);
 	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
 	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
 	rtl8225_write_phy_cck(dev, 0x40, 0x86);
-	rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1);
-	rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x41, 0x8d);
+	rtl8225_write_phy_cck(dev, 0x42, 0x15);
+	rtl8225_write_phy_cck(dev, 0x43, 0x18);
+	rtl8225_write_phy_cck(dev, 0x44, 0x36);
+	rtl8225_write_phy_cck(dev, 0x45, 0x35);
+	rtl8225_write_phy_cck(dev, 0x46, 0x2e);
+	rtl8225_write_phy_cck(dev, 0x47, 0x25);
+	rtl8225_write_phy_cck(dev, 0x48, 0x1c);
+	rtl8225_write_phy_cck(dev, 0x49, 0x12);
+	rtl8225_write_phy_cck(dev, 0x4a, 0x09);
+	rtl8225_write_phy_cck(dev, 0x4b, 0x04);
+	rtl8225_write_phy_cck(dev, 0x4c, 0x05);
 
 	rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1);
 
 	rtl8225z2_rf_set_tx_power(dev, 1);
 
 	/* RX antenna default to A */
-	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);	/* B: 0xDB */
-	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);	/* B: 0x10 */
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b);			/* B: 0xDB */
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);		/* B: 0x10 */
 
 	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
 	msleep(1);
@@ -835,40 +830,38 @@
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
 
-	rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
-	rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
-	rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-	rtl8225_write(dev, 0x3, 0x441); msleep(1);
-	rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
-	rtl8225_write(dev, 0x5, 0xC72); msleep(1);
-	rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
-	rtl8225_write(dev, 0x7, 0x82A); msleep(1);
-	rtl8225_write(dev, 0x8, 0x03F); msleep(1);
-	rtl8225_write(dev, 0x9, 0x335); msleep(1);
-	rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
-	rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
-	rtl8225_write(dev, 0xc, 0x850); msleep(1);
-	rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
-	rtl8225_write(dev, 0xe, 0x02B); msleep(1);
-	rtl8225_write(dev, 0xf, 0x114); msleep(1);
+	rtl8225_write(dev, 0x0, 0x0B7);
+	rtl8225_write(dev, 0x1, 0xEE0);
+	rtl8225_write(dev, 0x2, 0x44D);
+	rtl8225_write(dev, 0x3, 0x441);
+	rtl8225_write(dev, 0x4, 0x8C3);
+	rtl8225_write(dev, 0x5, 0xC72);
+	rtl8225_write(dev, 0x6, 0x0E6);
+	rtl8225_write(dev, 0x7, 0x82A);
+	rtl8225_write(dev, 0x8, 0x03F);
+	rtl8225_write(dev, 0x9, 0x335);
+	rtl8225_write(dev, 0xa, 0x9D4);
+	rtl8225_write(dev, 0xb, 0x7BB);
+	rtl8225_write(dev, 0xc, 0x850);
+	rtl8225_write(dev, 0xd, 0xCDF);
+	rtl8225_write(dev, 0xe, 0x02B);
+	rtl8225_write(dev, 0xf, 0x114);
 
-	rtl8225_write(dev, 0x0, 0x1B7); msleep(1);
+	rtl8225_write(dev, 0x0, 0x1B7);
 
 	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
-		rtl8225_write(dev, 0x1, i + 1); msleep(1);
-		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); msleep(1);
+		rtl8225_write(dev, 0x1, i + 1);
+		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
 	}
 
-	rtl8225_write(dev, 0x3, 0x080); msleep(1);
-	rtl8225_write(dev, 0x5, 0x004); msleep(1);
-	rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
-	msleep(3000);
+	rtl8225_write(dev, 0x3, 0x080);
+	rtl8225_write(dev, 0x5, 0x004);
+	rtl8225_write(dev, 0x0, 0x0B7);
 
-	rtl8225_write(dev, 0x2, 0xC4D); msleep(1);
-	msleep(2000);
+	rtl8225_write(dev, 0x2, 0xC4D);
 
-	rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-	rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
+	rtl8225_write(dev, 0x2, 0x44D);
+	rtl8225_write(dev, 0x0, 0x2BF);
 
 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03);
 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07);
@@ -885,24 +878,10 @@
 	for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++)
 		rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]);
 
-	rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
-	rtl818x_iowrite8(priv, &priv->map->SLOT, 9);
-	rtl818x_iowrite8(priv, (u8 *)0xFFF0, 28);
-	rtl818x_iowrite8(priv, (u8 *)0xFFF4, 28);
-	rtl818x_iowrite8(priv, (u8 *)0xFFF8, 28);
-	rtl818x_iowrite8(priv, (u8 *)0xFFFC, 28);
-	rtl818x_iowrite8(priv, (u8 *)0xFF2D, 0x5B);
-	rtl818x_iowrite8(priv, (u8 *)0xFF79, 0x5B);
-	rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28);
-	rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28);
-	rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28);
-	rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28);
-	rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
-
-	rtl8225_write_phy_ofdm(dev, 0x97, 0x46); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); msleep(1);
-	rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); msleep(1);
-	rtl8225_write_phy_cck(dev, 0xc1, 0x88); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x97, 0x46);
+	rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6);
+	rtl8225_write_phy_ofdm(dev, 0x85, 0xfc);
+	rtl8225_write_phy_cck(dev, 0xc1, 0x88);
 }
 
 static void rtl8225_rf_stop(struct ieee80211_hw *dev)
@@ -910,7 +889,7 @@
 	u8 reg;
 	struct rtl8187_priv *priv = dev->priv;
 
-	rtl8225_write(dev, 0x4, 0x1f); msleep(1);
+	rtl8225_write(dev, 0x4, 0x1f);
 
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
similarity index 100%
rename from drivers/net/wireless/rtl8187_rtl8225.h
rename to drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h
similarity index 98%
rename from drivers/net/wireless/rtl818x.h
rename to drivers/net/wireless/rtl818x/rtl818x.h
index 3538b15..34a5555 100644
--- a/drivers/net/wireless/rtl818x.h
+++ b/drivers/net/wireless/rtl818x/rtl818x.h
@@ -191,6 +191,7 @@
 	void (*init)(struct ieee80211_hw *);
 	void (*stop)(struct ieee80211_hw *);
 	void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *);
+	void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *);
 };
 
 /* Tx/Rx flags are common between RTL818X chips */
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 417e9e6..dd0de3a 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1234,7 +1234,7 @@
 
 static void strip_write_some_more(struct tty_struct *tty)
 {
-	struct strip *strip_info = (struct strip *) tty->disc_data;
+	struct strip *strip_info = tty->disc_data;
 
 	/* First make sure we're connected. */
 	if (!strip_info || strip_info->magic != STRIP_MAGIC ||
@@ -1252,7 +1252,7 @@
 #endif
 	} else {		/* Else start transmission of another packet */
 
-		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 		strip_unlock(strip_info);
 	}
 }
@@ -1455,8 +1455,7 @@
 	 */
 	strip_info->tx_head = strip_info->tx_buff;
 	strip_info->tx_left = ptr - strip_info->tx_buff;
-	strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-
+	set_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags);
 	/*
 	 * 4. Debugging check to make sure we're not overflowing the buffer.
 	 */
@@ -1997,7 +1996,6 @@
 #ifdef EXT_COUNTERS
 		strip_info->rx_bytes += packetlen;
 #endif
-		skb->dev->last_rx = jiffies;
 		netif_rx(skb);
 	}
 }
@@ -2261,7 +2259,7 @@
 static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 		  char *fp, int count)
 {
-	struct strip *strip_info = (struct strip *) tty->disc_data;
+	struct strip *strip_info = tty->disc_data;
 	const unsigned char *end = cp + count;
 
 	if (!strip_info || strip_info->magic != STRIP_MAGIC
@@ -2455,8 +2453,7 @@
 
 	if (strip_info->tty == NULL)
 		return -EBUSY;
-	strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-
+	clear_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags);
 	netif_stop_queue(dev);
 
 	/*
@@ -2490,7 +2487,6 @@
 	 */
 
 	dev->trans_start = 0;
-	dev->last_rx = 0;
 	dev->tx_queue_len = 30;	/* Drop after 30 frames queued */
 
 	dev->flags = 0;
@@ -2498,7 +2494,7 @@
 	dev->type = ARPHRD_METRICOM;	/* dtang */
 	dev->hard_header_len = sizeof(STRIP_Header);
 	/*
-	 *  dev->priv             Already holds a pointer to our struct strip
+	 *  netdev_priv(dev) Already holds a pointer to our struct strip
 	 */
 
 	*(MetricomAddress *) & dev->broadcast = broadcast_address;
@@ -2598,7 +2594,7 @@
 
 static int strip_open(struct tty_struct *tty)
 {
-	struct strip *strip_info = (struct strip *) tty->disc_data;
+	struct strip *strip_info = tty->disc_data;
 
 	/*
 	 * First make sure we're not already connected.
@@ -2669,7 +2665,7 @@
 
 static void strip_close(struct tty_struct *tty)
 {
-	struct strip *strip_info = (struct strip *) tty->disc_data;
+	struct strip *strip_info = tty->disc_data;
 
 	/*
 	 * First make sure we're connected.
@@ -2695,7 +2691,7 @@
 static int strip_ioctl(struct tty_struct *tty, struct file *file,
 		       unsigned int cmd, unsigned long arg)
 {
-	struct strip *strip_info = (struct strip *) tty->disc_data;
+	struct strip *strip_info = tty->disc_data;
 
 	/*
 	 * First make sure we're connected.
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index e939a73..8326793 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -134,7 +134,7 @@
  */
 static inline void wv_ints_off(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	
 	lp->hacr &= ~HACR_INTRON;
@@ -148,7 +148,7 @@
  */
 static inline void wv_ints_on(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 
 	lp->hacr |= HACR_INTRON;
@@ -526,7 +526,7 @@
  */
 static void wv_ack(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	u16 scb_cs;
 	int i;
@@ -568,7 +568,7 @@
  */
 static int wv_synchronous_cmd(struct net_device * dev, const char *str)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	u16 scb_cmd;
 	ach_t cb;
@@ -824,7 +824,7 @@
  */
 static void wv_82586_reconfig(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	/* Arm the flag, will be cleard in wv_82586_config() */
@@ -859,8 +859,6 @@
  */
 static void wv_psa_show(psa_t * p)
 {
-	DECLARE_MAC_BUF(mac);
-
 	printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
 	printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
 	       p->psa_io_base_addr_1,
@@ -872,13 +870,10 @@
 	printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
 	printk("psa_int_req_no: %d\n", p->psa_int_req_no);
 #ifdef DEBUG_SHOW_UNUSED
-	printk(KERN_DEBUG "psa_unused0[]: %s\n",
-	       print_mac(mac, p->psa_unused0));
+	printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0);
 #endif				/* DEBUG_SHOW_UNUSED */
-	printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n",
-	       print_mac(mac, p->psa_univ_mac_addr));
-	printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n",
-	       print_mac(mac, p->psa_local_mac_addr));
+	printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr);
+	printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr);
 	printk(KERN_DEBUG "psa_univ_local_sel: %d, ",
 	       p->psa_univ_local_sel);
 	printk("psa_comp_number: %d, ", p->psa_comp_number);
@@ -927,7 +922,7 @@
 static void wv_mmc_show(struct net_device * dev)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	mmr_t m;
 
 	/* Basic check */
@@ -1107,8 +1102,6 @@
  */
 static void wv_ru_show(struct net_device * dev)
 {
-	/* net_local *lp = (net_local *) dev->priv; */
-
 	printk(KERN_DEBUG
 	       "##### WaveLAN i82586 receiver unit status: #####\n");
 	printk(KERN_DEBUG "ru:");
@@ -1153,7 +1146,7 @@
  */
 static void wv_cu_show(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned int i;
 	u16 p;
 
@@ -1195,7 +1188,7 @@
 {
 	net_local *lp;
 
-	lp = (net_local *) dev->priv;
+	lp = netdev_priv(dev);
 
 	printk(KERN_DEBUG "local:");
 	printk(" tx_n_in_use=%d,", lp->tx_n_in_use);
@@ -1220,14 +1213,13 @@
 {				/* Name of the function */
 	int i;
 	int maxi;
-	DECLARE_MAC_BUF(mac);
 
 	printk(KERN_DEBUG
-	       "%s: %s(): dest %s, length %d\n",
-	       msg1, msg2, print_mac(mac, p), length);
+	       "%s: %s(): dest %pM, length %d\n",
+	       msg1, msg2, p, length);
 	printk(KERN_DEBUG
-	       "%s: %s(): src %s, type 0x%02X%02X\n",
-	       msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]);
+	       "%s: %s(): src %pM, type 0x%02X%02X\n",
+	       msg1, msg2, &p[6], p[12], p[13]);
 
 #ifdef DEBUG_PACKET_DUMP
 
@@ -1256,11 +1248,8 @@
 static void wv_init_info(struct net_device * dev)
 {
 	short ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	psa_t psa;
-#ifdef DEBUG_BASIC_SHOW
-	DECLARE_MAC_BUF(mac);
-#endif
 
 	/* Read the parameter storage area */
 	psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
@@ -1277,8 +1266,8 @@
 
 #ifdef DEBUG_BASIC_SHOW
 	/* Now, let's go for the basic stuff. */
-	printk(KERN_NOTICE "%s: WaveLAN at %#x, %s, IRQ %d",
-	       dev->name, ioaddr, print_mac(mac, dev->dev_addr), dev->irq);
+	printk(KERN_NOTICE "%s: WaveLAN at %#x, %pM, IRQ %d",
+	       dev->name, ioaddr, dev->dev_addr, dev->irq);
 
 	/* Print current network ID. */
 	if (psa.psa_nwid_select)
@@ -1369,7 +1358,7 @@
 	printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
 #endif
 
-	return (&((net_local *) dev->priv)->stats);
+	return &((net_local *)netdev_priv(dev))->stats;
 }
 
 /*------------------------------------------------------------------*/
@@ -1382,7 +1371,7 @@
  */
 static void wavelan_set_multicast_list(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 
 #ifdef DEBUG_IOCTL_TRACE
 	printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n",
@@ -1716,7 +1705,7 @@
  */
 static inline void wl_his_gather(struct net_device * dev, u8 * stats)
 {				/* Statistics to gather */
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	u8 level = stats[0] & MMR_SIGNAL_LVL;
 	int i;
 
@@ -1753,7 +1742,7 @@
 			    char *extra)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 	psa_t psa;
 	mm_t m;
 	unsigned long flags;
@@ -1812,7 +1801,7 @@
 			    char *extra)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 	psa_t psa;
 	unsigned long flags;
 	int ret = 0;
@@ -1844,7 +1833,7 @@
 			    char *extra)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 	unsigned long flags;
 	int ret;
 
@@ -1874,7 +1863,7 @@
 			    char *extra)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 	psa_t psa;
 	unsigned long flags;
 	int ret = 0;
@@ -1920,7 +1909,7 @@
 			    char *extra)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 	psa_t psa;
 	unsigned long flags;
 	int ret = 0;
@@ -1956,7 +1945,7 @@
 			    char *extra)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 	psa_t psa;
 	unsigned long flags;
 	int ret = 0;
@@ -1987,7 +1976,7 @@
 			      char *extra)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 	unsigned long flags;
 	psa_t psa;
 	int ret = 0;
@@ -2057,7 +2046,7 @@
 			      char *extra)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 	psa_t psa;
 	unsigned long flags;
 	int ret = 0;
@@ -2104,7 +2093,7 @@
 			     char *extra)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 	struct iw_range *range = (struct iw_range *) extra;
 	unsigned long flags;
 	int ret = 0;
@@ -2179,7 +2168,7 @@
 			    char *extra)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 	psa_t psa;
 	unsigned long flags;
 
@@ -2211,7 +2200,7 @@
 			    char *extra)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 	psa_t psa;
 	unsigned long flags;
 
@@ -2239,7 +2228,7 @@
 			     union iwreq_data *wrqu,
 			     char *extra)
 {
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 
 	/* Check the number of intervals. */
 	if (wrqu->data.length > 16) {
@@ -2282,7 +2271,7 @@
 			     union iwreq_data *wrqu,
 			     char *extra)
 {
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);	/* lp is not unused */
 
 	/* Set the number of intervals. */
 	wrqu->data.length = lp->his_number;
@@ -2386,7 +2375,7 @@
 static iw_stats *wavelan_get_wireless_stats(struct net_device * dev)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	mmr_t m;
 	iw_stats *wstats;
 	unsigned long flags;
@@ -2461,7 +2450,7 @@
 static void
 wv_packet_read(struct net_device * dev, u16 buf_off, int sksize)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	struct sk_buff *skb;
 
@@ -2537,7 +2526,6 @@
 	netif_rx(skb);
 
 	/* Keep statistics up to date */
-	dev->last_rx = jiffies;
 	lp->stats.rx_packets++;
 	lp->stats.rx_bytes += sksize;
 
@@ -2556,7 +2544,7 @@
 static void wv_receive(struct net_device * dev)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	fd_t fd;
 	rbd_t rbd;
 	int nreaped = 0;
@@ -2738,7 +2726,7 @@
  */
 static int wv_packet_write(struct net_device * dev, void *buf, short length)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	unsigned short txblock;
 	unsigned short txpred;
@@ -2869,7 +2857,7 @@
  */
 static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 	char data[ETH_ZLEN];
 
@@ -2937,7 +2925,7 @@
 static int wv_mmc_init(struct net_device * dev)
 {
 	unsigned long ioaddr = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	psa_t psa;
 	mmw_t m;
 	int configured;
@@ -3108,7 +3096,7 @@
  */
 static int wv_ru_start(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	u16 scb_cs;
 	fd_t fd;
@@ -3200,7 +3188,7 @@
  */
 static int wv_cu_start(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	int i;
 	u16 txblock;
@@ -3301,7 +3289,7 @@
  */
 static int wv_82586_start(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	scp_t scp;		/* system configuration pointer */
 	iscp_t iscp;		/* intermediate scp */
@@ -3433,7 +3421,7 @@
  */
 static void wv_82586_config(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	unsigned short txblock;
 	unsigned short txpred;
@@ -3565,15 +3553,11 @@
 			      WAVELAN_ADDR_SIZE >> 1);
 
 #ifdef DEBUG_CONFIG_INFO
- {
-		DECLARE_MAC_BUF(mac);
 		printk(KERN_DEBUG
 		       "%s: wv_82586_config(): set %d multicast addresses:\n",
 		       dev->name, lp->mc_count);
 		for (dmi = dev->mc_list; dmi; dmi = dmi->next)
-			printk(KERN_DEBUG " %s\n",
-			       print_mac(mac, dmi->dmi_addr));
- }
+			printk(KERN_DEBUG " %pM\n", dmi->dmi_addr);
 #endif
 	}
 
@@ -3613,7 +3597,7 @@
  */
 static void wv_82586_stop(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	u16 scb_cmd;
 
@@ -3650,7 +3634,7 @@
  */
 static int wv_hw_reset(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3751,7 +3735,7 @@
 	printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
 #endif
 
-	lp = (net_local *) dev->priv;
+	lp = netdev_priv(dev);
 	ioaddr = dev->base_addr;
 
 #ifdef DEBUG_INTERRUPT_INFO
@@ -3894,7 +3878,7 @@
  */
 static void wavelan_watchdog(struct net_device *	dev)
 {
-	net_local *	lp = (net_local *)dev->priv;
+	net_local *lp = netdev_priv(dev);
 	u_long		ioaddr = dev->base_addr;
 	unsigned long	flags;
 	unsigned int	nreaped;
@@ -3974,7 +3958,7 @@
  */
 static int wavelan_open(struct net_device * dev)
 {
-	net_local *	lp = (net_local *)dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long	flags;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4029,7 +4013,7 @@
  */
 static int wavelan_close(struct net_device * dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+	net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4128,8 +4112,8 @@
 	dev->if_port = 0;
 
 	/* Initialize device structures */
-	memset(dev->priv, 0, sizeof(net_local));
-	lp = (net_local *) dev->priv;
+	memset(netdev_priv(dev), 0, sizeof(net_local));
+	lp = netdev_priv(dev);
 
 	/* Back link to the device structure. */
 	lp->dev = dev;
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index e124b1d..de717f8 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -1020,7 +1020,6 @@
 static void
 wv_psa_show(psa_t *	p)
 {
-  DECLARE_MAC_BUF(mac);
   printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
   printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
 	 p->psa_io_base_addr_1,
@@ -1034,13 +1033,10 @@
   printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
   printk("psa_int_req_no: %d\n", p->psa_int_req_no);
 #ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "psa_unused0[]: %s\n",
-	 print_mac(mac, p->psa_unused0));
+  printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0);
 #endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n",
-	 print_mac(mac, p->psa_univ_mac_addr));
-  printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n",
-	 print_mac(mac, p->psa_local_mac_addr));
+  printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr);
+  printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr);
   printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel);
   printk("psa_comp_number: %d, ", p->psa_comp_number);
   printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
@@ -1238,12 +1234,11 @@
 {
   int		i;
   int		maxi;
-  DECLARE_MAC_BUF(mac);
 
-  printk(KERN_DEBUG "%s: %s(): dest %s, length %d\n",
-	 msg1, msg2, print_mac(mac, p), length);
-  printk(KERN_DEBUG "%s: %s(): src %s, type 0x%02X%02X\n",
-	 msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]);
+  printk(KERN_DEBUG "%s: %s(): dest %pM, length %d\n",
+	 msg1, msg2, p, length);
+  printk(KERN_DEBUG "%s: %s(): src %pM, type 0x%02X%02X\n",
+	 msg1, msg2, &p[6], p[12], p[13]);
 
 #ifdef DEBUG_PACKET_DUMP
 
@@ -1274,7 +1269,6 @@
 {
   unsigned int	base = dev->base_addr;
   psa_t		psa;
-  DECLARE_MAC_BUF(mac);
 
   /* Read the parameter storage area */
   psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
@@ -1291,10 +1285,8 @@
 
 #ifdef DEBUG_BASIC_SHOW
   /* Now, let's go for the basic stuff */
-  printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, "
-	 "hw_addr %s",
-	 dev->name, base, dev->irq,
-	 print_mac(mac, dev->dev_addr));
+  printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr %pM",
+	 dev->name, base, dev->irq, dev->dev_addr);
 
   /* Print current network id */
   if(psa.psa_nwid_select)
@@ -2243,13 +2235,7 @@
 			   char *extra)
 {
 #ifdef DEBUG_IOCTL_INFO
-	printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
-	       wrqu->ap_addr.sa_data[0],
-	       wrqu->ap_addr.sa_data[1],
-	       wrqu->ap_addr.sa_data[2],
-	       wrqu->ap_addr.sa_data[3],
-	       wrqu->ap_addr.sa_data[4],
-	       wrqu->ap_addr.sa_data[5]);
+	printk(KERN_DEBUG "Set AP to : %pM\n", wrqu->ap_addr.sa_data);
 #endif	/* DEBUG_IOCTL_INFO */
 
 	return -EOPNOTSUPP;
@@ -2892,7 +2878,6 @@
   netif_rx(skb);
 
   /* Keep stats up to date */
-  dev->last_rx = jiffies;
   lp->stats.rx_packets++;
   lp->stats.rx_bytes += sksize;
 
@@ -3647,12 +3632,10 @@
       int			addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count;
 
 #ifdef DEBUG_CONFIG_INFO
-      DECLARE_MAC_BUF(mac);
       printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n",
 	     dev->name, lp->mc_count);
       for(dmi=dev->mc_list; dmi; dmi=dmi->next)
-	printk(KERN_DEBUG " %s\n",
-	       print_mac(mac, dmi->dmi_addr));
+	printk(KERN_DEBUG " %pM\n", dmi->dmi_addr);
 #endif
 
       /* Initialize adapter's ethernet multicast addresses */
diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h
index 65ceb08..59bb3a5 100644
--- a/drivers/net/wireless/wl3501.h
+++ b/drivers/net/wireless/wl3501.h
@@ -2,7 +2,7 @@
 #define __WL3501_H__
 
 #include <linux/spinlock.h>
-#include <net/ieee80211.h>
+#include <linux/ieee80211.h>
 
 /* define for WLA 2.0 */
 #define WL3501_BLKSZ 256
@@ -548,7 +548,7 @@
 
 struct wl3501_80211_tx_hdr {
 	struct wl3501_80211_tx_plcp_hdr	pclp_hdr;
-	struct ieee80211_hdr_4addr		mac_hdr;
+	struct ieee80211_hdr		mac_hdr;
 } __attribute__ ((packed));
 
 /*
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 68789c6..c99a1b6 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -860,10 +860,9 @@
 static void wl3501_online(struct net_device *dev)
 {
 	struct wl3501_card *this = netdev_priv(dev);
-	DECLARE_MAC_BUF(mac);
 
-	printk(KERN_INFO "%s: Wireless LAN online. BSSID: %s\n",
-	       dev->name, print_mac(mac, this->bssid));
+	printk(KERN_INFO "%s: Wireless LAN online. BSSID: %pM\n",
+	       dev->name, this->bssid);
 	netif_wake_queue(dev);
 }
 
@@ -1014,7 +1013,6 @@
 		wl3501_receive(this, skb->data, pkt_len);
 		skb_put(skb, pkt_len);
 		skb->protocol	= eth_type_trans(skb, dev);
-		dev->last_rx	= jiffies;
 		this->stats.rx_packets++;
 		this->stats.rx_bytes += skb->len;
 		netif_rx(skb);
@@ -1965,7 +1963,6 @@
 	struct net_device *dev = link->priv;
 	int i = 0, j, last_fn, last_ret;
 	struct wl3501_card *this;
-	DECLARE_MAC_BUF(mac);
 
 	/* Try allocating IO ports.  This tries a few fixed addresses.  If you
 	 * want, you can also read the card's config table to pick addresses --
@@ -2024,9 +2021,9 @@
 
 	/* print probe information */
 	printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, "
-	       "MAC addr in flash ROM:%s\n",
+	       "MAC addr in flash ROM:%pM\n",
 	       dev->name, this->base_addr, (int)dev->irq,
-	       print_mac(mac, dev->dev_addr));
+	       dev->dev_addr);
 	/*
 	 * Initialize card parameters - added by jss
 	 */
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index b16ec6e..b45c27d 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -17,11 +17,11 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
 #include <net/iw_handler.h>
 #include <linux/string.h>
 #include <linux/if_arp.h>
 #include <linux/firmware.h>
-#include <net/ieee80211.h>
 #include "zd1201.h"
 
 static struct usb_device_id zd1201_table[] = {
@@ -328,7 +328,6 @@
 			memcpy(skb_put(skb, 2), &data[datalen-24], 2);
 			memcpy(skb_put(skb, len), data, len);
 			skb->protocol = eth_type_trans(skb, zd->dev);
-			skb->dev->last_rx = jiffies;
 			zd->stats.rx_packets++;
 			zd->stats.rx_bytes += skb->len;
 			netif_rx(skb);
@@ -346,7 +345,7 @@
 				frag = kmalloc(sizeof(*frag), GFP_ATOMIC);
 				if (!frag)
 					goto resubmit;
-				skb = dev_alloc_skb(IEEE80211_DATA_LEN +14+2);
+				skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2);
 				if (!skb) {
 					kfree(frag);
 					goto resubmit;
@@ -385,7 +384,6 @@
 			memcpy(skb_put(skb, len), data+8, len);
 		}
 		skb->protocol = eth_type_trans(skb, zd->dev);
-		skb->dev->last_rx = jiffies;
 		zd->stats.rx_packets++;
 		zd->stats.rx_bytes += skb->len;
 		netif_rx(skb);
@@ -745,7 +743,7 @@
 
 static int zd1201_net_open(struct net_device *dev)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 
 	/* Start MAC with wildcard if no essid set */
 	if (!zd->mac_enabled)
@@ -783,7 +781,7 @@
  */
 static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	unsigned char *txbuf = zd->txdata;
 	int txbuflen, pad = 0, err;
 	struct urb *urb = zd->tx_urb;
@@ -833,7 +831,7 @@
 
 static void zd1201_tx_timeout(struct net_device *dev)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 
 	if (!zd)
 		return;
@@ -848,7 +846,7 @@
 static int zd1201_set_mac_address(struct net_device *dev, void *p)
 {
 	struct sockaddr *addr = p;
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	int err;
 
 	if (!zd)
@@ -865,21 +863,21 @@
 
 static struct net_device_stats *zd1201_get_stats(struct net_device *dev)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 
 	return &zd->stats;
 }
 
 static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 
 	return &zd->iwstats;
 }
 
 static void zd1201_set_multicast(struct net_device *dev)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	struct dev_mc_list *mc = dev->mc_list;
 	unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI];
 	int i;
@@ -899,7 +897,7 @@
 static int zd1201_config_commit(struct net_device *dev, 
     struct iw_request_info *info, struct iw_point *data, char *essid)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 
 	return zd1201_mac_reset(zd);
 }
@@ -914,7 +912,7 @@
 static int zd1201_set_freq(struct net_device *dev,
     struct iw_request_info *info, struct iw_freq *freq, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short channel = 0;
 	int err;
 
@@ -939,7 +937,7 @@
 static int zd1201_get_freq(struct net_device *dev,
     struct iw_request_info *info, struct iw_freq *freq, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short channel;
 	int err;
 
@@ -955,7 +953,7 @@
 static int zd1201_set_mode(struct net_device *dev,
     struct iw_request_info *info, __u32 *mode, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short porttype, monitor = 0;
 	unsigned char buffer[IW_ESSID_MAX_SIZE+2];
 	int err;
@@ -1017,7 +1015,7 @@
 static int zd1201_get_mode(struct net_device *dev,
     struct iw_request_info *info, __u32 *mode, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short porttype;
 	int err;
 
@@ -1093,7 +1091,7 @@
 static int zd1201_get_wap(struct net_device *dev,
     struct iw_request_info *info, struct sockaddr *ap_addr, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	unsigned char buffer[6];
 
 	if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) {
@@ -1121,7 +1119,7 @@
 static int zd1201_get_scan(struct net_device *dev,
     struct iw_request_info *info, struct iw_point *srq, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	int err, i, j, enabled_save;
 	struct iw_event iwe;
 	char *cev = extra;
@@ -1213,7 +1211,7 @@
 static int zd1201_set_essid(struct net_device *dev,
     struct iw_request_info *info, struct iw_point *data, char *essid)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 
 	if (data->length > IW_ESSID_MAX_SIZE)
 		return -EINVAL;
@@ -1228,7 +1226,7 @@
 static int zd1201_get_essid(struct net_device *dev,
     struct iw_request_info *info, struct iw_point *data, char *essid)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 
 	memcpy(essid, zd->essid, zd->essidlen);
 	data->flags = 1;
@@ -1249,7 +1247,7 @@
 static int zd1201_set_rate(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short rate;
 	int err;
 
@@ -1282,7 +1280,7 @@
 static int zd1201_get_rate(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short rate;
 	int err;
 
@@ -1315,7 +1313,7 @@
 static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info,
     struct iw_param *rts, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	int err;
 	short val = rts->value;
 
@@ -1335,7 +1333,7 @@
 static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info,
     struct iw_param *rts, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short rtst;
 	int err;
 
@@ -1352,7 +1350,7 @@
 static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info,
     struct iw_param *frag, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	int err;
 	short val = frag->value;
 
@@ -1373,7 +1371,7 @@
 static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info,
     struct iw_param *frag, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short fragt;
 	int err;
 
@@ -1402,7 +1400,7 @@
 static int zd1201_set_encode(struct net_device *dev,
     struct iw_request_info *info, struct iw_point *erq, char *key)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short i;
 	int err, rid;
 
@@ -1459,7 +1457,7 @@
 static int zd1201_get_encode(struct net_device *dev,
     struct iw_request_info *info, struct iw_point *erq, char *key)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short i;
 	int err;
 
@@ -1492,7 +1490,7 @@
 static int zd1201_set_power(struct net_device *dev, 
     struct iw_request_info *info, struct iw_param *vwrq, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short enabled, duration, level;
 	int err;
 
@@ -1531,7 +1529,7 @@
 static int zd1201_get_power(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *vwrq, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short enabled, level, duration;
 	int err;
 
@@ -1618,7 +1616,7 @@
 static int zd1201_set_hostauth(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 
 	if (!zd->ap)
 		return -EOPNOTSUPP;
@@ -1629,7 +1627,7 @@
 static int zd1201_get_hostauth(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short hostauth;
 	int err;
 
@@ -1648,7 +1646,7 @@
 static int zd1201_auth_sta(struct net_device *dev,
     struct iw_request_info *info, struct sockaddr *sta, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	unsigned char buffer[10];
 
 	if (!zd->ap)
@@ -1664,7 +1662,7 @@
 static int zd1201_set_maxassoc(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	int err;
 
 	if (!zd->ap)
@@ -1679,7 +1677,7 @@
 static int zd1201_get_maxassoc(struct net_device *dev,
     struct iw_request_info *info, struct iw_param *rrq, char *extra)
 {
-	struct zd1201 *zd = (struct zd1201 *)dev->priv;
+	struct zd1201 *zd = netdev_priv(dev);
 	short maxassoc;
 	int err;
 
@@ -1731,6 +1729,7 @@
 			const struct usb_device_id *id)
 {
 	struct zd1201 *zd;
+	struct net_device *dev;
 	struct usb_device *usb;
 	int err;
 	short porttype;
@@ -1738,9 +1737,12 @@
 
 	usb = interface_to_usbdev(interface);
 
-	zd = kzalloc(sizeof(struct zd1201), GFP_KERNEL);
-	if (!zd)
+	dev = alloc_etherdev(sizeof(*zd));
+	if (!dev)
 		return -ENOMEM;
+	zd = netdev_priv(dev);
+	zd->dev = dev;
+
 	zd->ap = ap;
 	zd->usb = usb;
 	zd->removed = 0;
@@ -1775,34 +1777,29 @@
 	if (err)
 		goto err_start;
 
-	zd->dev = alloc_etherdev(0);
-	if (!zd->dev)
-		goto err_start;
-
-	zd->dev->priv = zd;
-	zd->dev->open = zd1201_net_open;
-	zd->dev->stop = zd1201_net_stop;
-	zd->dev->get_stats = zd1201_get_stats;
-	zd->dev->wireless_handlers =
+	dev->open = zd1201_net_open;
+	dev->stop = zd1201_net_stop;
+	dev->get_stats = zd1201_get_stats;
+	dev->wireless_handlers =
 	    (struct iw_handler_def *)&zd1201_iw_handlers;
-	zd->dev->hard_start_xmit = zd1201_hard_start_xmit;
-	zd->dev->watchdog_timeo = ZD1201_TX_TIMEOUT;
-	zd->dev->tx_timeout = zd1201_tx_timeout;
-	zd->dev->set_multicast_list = zd1201_set_multicast;
-	zd->dev->set_mac_address = zd1201_set_mac_address;
-	strcpy(zd->dev->name, "wlan%d");
+	dev->hard_start_xmit = zd1201_hard_start_xmit;
+	dev->watchdog_timeo = ZD1201_TX_TIMEOUT;
+	dev->tx_timeout = zd1201_tx_timeout;
+	dev->set_multicast_list = zd1201_set_multicast;
+	dev->set_mac_address = zd1201_set_mac_address;
+	strcpy(dev->name, "wlan%d");
 
 	err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, 
-	    zd->dev->dev_addr, zd->dev->addr_len);
+	    dev->dev_addr, dev->addr_len);
 	if (err)
-		goto err_net;
+		goto err_start;
 
 	/* Set wildcard essid to match zd->essid */
 	*(__le16 *)buf = cpu_to_le16(0);
 	err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,
 	    IW_ESSID_MAX_SIZE+2, 1);
 	if (err)
-		goto err_net;
+		goto err_start;
 
 	if (zd->ap)
 		porttype = ZD1201_PORTTYPE_AP;
@@ -1810,30 +1807,28 @@
 		porttype = ZD1201_PORTTYPE_BSS;
 	err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype);
 	if (err)
-		goto err_net;
+		goto err_start;
 
-	SET_NETDEV_DEV(zd->dev, &usb->dev);
+	SET_NETDEV_DEV(dev, &usb->dev);
 
-	err = register_netdev(zd->dev);
+	err = register_netdev(dev);
 	if (err)
-		goto err_net;
+		goto err_start;
 	dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n",
-	    zd->dev->name);
+	    dev->name);
 
 	usb_set_intfdata(interface, zd);
 	zd1201_enable(zd);	/* zd1201 likes to startup enabled, */
 	zd1201_disable(zd);	/* interfering with all the wifis in range */
 	return 0;
 
-err_net:
-	free_netdev(zd->dev);
 err_start:
 	/* Leave the device in reset state */
 	zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
 err_zd:
 	usb_free_urb(zd->tx_urb);
 	usb_free_urb(zd->rx_urb);
-	kfree(zd);
+	free_netdev(dev);
 	return err;
 }
 
@@ -1846,10 +1841,6 @@
 	if (!zd)
 		return;
 	usb_set_intfdata(interface, NULL);
-	if (zd->dev) {
-		unregister_netdev(zd->dev);
-		free_netdev(zd->dev);
-	}
 
 	hlist_for_each_entry_safe(frag, node, node2, &zd->fraglist, fnode) {
 		hlist_del_init(&frag->fnode);
@@ -1865,7 +1856,11 @@
 		usb_kill_urb(zd->rx_urb);
 		usb_free_urb(zd->rx_urb);
 	}
-	kfree(zd);
+
+	if (zd->dev) {
+		unregister_netdev(zd->dev);
+		free_netdev(zd->dev);
+	}
 }
 
 #ifdef CONFIG_PM
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index e0ac58b..f151914 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -378,7 +378,6 @@
 		[0] = { .addr = CR_MAC_ADDR_P1 },
 		[1] = { .addr = CR_MAC_ADDR_P2 },
 	};
-	DECLARE_MAC_BUF(mac);
 
 	if (mac_addr) {
 		reqs[0].value = (mac_addr[3] << 24)
@@ -387,8 +386,7 @@
 			      |  mac_addr[0];
 		reqs[1].value = (mac_addr[5] <<  8)
 			      |  mac_addr[4];
-		dev_dbg_f(zd_chip_dev(chip),
-			"mac addr %s\n", print_mac(mac, mac_addr));
+		dev_dbg_f(zd_chip_dev(chip), "mac addr %pM\n", mac_addr);
 	} else {
 		dev_dbg_f(zd_chip_dev(chip), "set NULL mac\n");
 	}
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index cac732f..9caa96a 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -171,7 +171,7 @@
 
 	r = zd_reg2alpha2(mac->regdomain, alpha2);
 	if (!r)
-		regulatory_hint(hw->wiphy, alpha2, NULL);
+		regulatory_hint(hw->wiphy, alpha2);
 
 	r = 0;
 disable_int:
@@ -296,15 +296,14 @@
  * If no status information has been requested, the skb is freed.
  */
 static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
-		      u32 flags, int ackssi, bool success)
+		      int ackssi, bool success)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
-	memset(&info->status, 0, sizeof(info->status));
+	ieee80211_tx_info_clear_status(info);
 
-	if (!success)
-		info->status.excessive_retries = 1;
-	info->flags |= flags;
+	if (success)
+		info->flags |= IEEE80211_TX_STAT_ACK;
 	info->status.ack_signal = ackssi;
 	ieee80211_tx_status_irqsafe(hw, skb);
 }
@@ -326,7 +325,7 @@
 	if (skb == NULL)
 		return;
 
-	tx_status(hw, skb, 0, 0, 0);
+	tx_status(hw, skb, 0, 0);
 }
 
 /**
@@ -342,12 +341,12 @@
 void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_hw *hw = info->driver_data[0];
+	struct ieee80211_hw *hw = info->rate_driver_data[0];
 
 	skb_pull(skb, sizeof(struct zd_ctrlset));
 	if (unlikely(error ||
 	    (info->flags & IEEE80211_TX_CTL_NO_ACK))) {
-		tx_status(hw, skb, 0, 0, !error);
+		tx_status(hw, skb, 0, !error);
 	} else {
 		struct sk_buff_head *q =
 			&zd_hw_mac(hw)->ack_wait_queue;
@@ -406,7 +405,8 @@
 }
 
 static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
-	                   struct ieee80211_hdr *header, u32 flags)
+	                   struct ieee80211_hdr *header,
+	                   struct ieee80211_tx_info *info)
 {
 	/*
 	 * CONTROL TODO:
@@ -417,7 +417,7 @@
 	cs->control = 0;
 
 	/* First fragment */
-	if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
 		cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
 
 	/* Multicast */
@@ -428,10 +428,10 @@
 	if (ieee80211_is_pspoll(header->frame_control))
 		cs->control |= ZD_CS_PS_POLL_FRAME;
 
-	if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
 		cs->control |= ZD_CS_RTS;
 
-	if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
 		cs->control |= ZD_CS_SELF_CTS;
 
 	/* FIXME: Management frame? */
@@ -517,12 +517,12 @@
 	txrate = ieee80211_get_tx_rate(mac->hw, info);
 
 	cs->modulation = txrate->hw_value;
-	if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
 		cs->modulation = txrate->hw_value_short;
 
 	cs->tx_length = cpu_to_le16(frag_len);
 
-	cs_set_control(mac, cs, hdr, info->flags);
+	cs_set_control(mac, cs, hdr, info);
 
 	packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
 	ZD_ASSERT(packet_length <= 0xffff);
@@ -577,7 +577,7 @@
 	if (r)
 		return r;
 
-	info->driver_data[0] = hw;
+	info->rate_driver_data[0] = hw;
 
 	r = zd_usb_tx(&mac->chip.usb, skb);
 	if (r)
@@ -618,7 +618,7 @@
 		if (likely(!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN)))
 		{
 			__skb_unlink(skb, q);
-			tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1);
+			tx_status(hw, skb, stats->signal, 1);
 			goto out;
 		}
 	}
@@ -743,9 +743,11 @@
 	zd_write_mac_addr(&mac->chip, NULL);
 }
 
-static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int zd_op_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct zd_mac *mac = zd_hw_mac(hw);
+	struct ieee80211_conf *conf = &hw->conf;
+
 	return zd_chip_set_channel(&mac->chip, conf->channel->hw_value);
 }
 
@@ -852,14 +854,12 @@
 	if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) {
 		zd_mc_add_all(&hash);
 	} else {
-		DECLARE_MAC_BUF(macbuf);
-
 		zd_mc_clear(&hash);
 		for (i = 0; i < mc_count; i++) {
 			if (!mclist)
 				break;
-			dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n",
-				  print_mac(macbuf, mclist->dmi_addr));
+			dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n",
+				  mclist->dmi_addr);
 			zd_mc_add_addr(&hash, mclist->dmi_addr);
 			mclist = mclist->next;
 		}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index a3ccd8c..04c1396 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -909,7 +909,7 @@
 	 * it might be freed by zd_mac_tx_to_dev or mac80211)
 	 */
 	info = IEEE80211_SKB_CB(skb);
-	usb = &zd_hw_mac(info->driver_data[0])->chip.usb;
+	usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb;
 	zd_mac_tx_to_dev(skb, urb->status);
 	free_tx_urb(usb, urb);
 	tx_dec_submitted_urbs(usb);
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 6d017ad..761635b 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -196,7 +196,7 @@
 {
 	struct net_device *dev = (struct net_device *)data;
 	struct netfront_info *np = netdev_priv(dev);
-	netif_rx_schedule(dev, &np->napi);
+	netif_rx_schedule(&np->napi);
 }
 
 static int netfront_tx_slot_available(struct netfront_info *np)
@@ -328,7 +328,7 @@
 		xennet_alloc_rx_buffers(dev);
 		np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
 		if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
-			netif_rx_schedule(dev, &np->napi);
+			netif_rx_schedule(&np->napi);
 	}
 	spin_unlock_bh(&np->rx_lock);
 
@@ -841,7 +841,6 @@
 
 		/* Pass it up. */
 		netif_receive_skb(skb);
-		dev->last_rx = jiffies;
 	}
 
 	return packets_dropped;
@@ -980,7 +979,7 @@
 
 		RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
 		if (!more_to_do)
-			__netif_rx_complete(dev, napi);
+			__netif_rx_complete(napi);
 
 		local_irq_restore(flags);
 	}
@@ -1311,7 +1310,7 @@
 		xennet_tx_buf_gc(dev);
 		/* Under tx_lock: protects access to rx shared-ring indexes. */
 		if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
-			netif_rx_schedule(dev, &np->napi);
+			netif_rx_schedule(&np->napi);
 	}
 
 	spin_unlock_irqrestore(&np->tx_lock, flags);
diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c
index da42aa0..03a3f34 100644
--- a/drivers/net/xtsonic.c
+++ b/drivers/net/xtsonic.c
@@ -239,8 +239,6 @@
 	struct resource *resmem, *resirq;
 	int err = 0;
 
-	DECLARE_MAC_BUF(mac);
-
 	if ((resmem = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == NULL)
 		return -ENODEV;
 
@@ -263,8 +261,8 @@
 	if ((err = register_netdev(dev)))
 		goto out1;
 
-	printk("%s: SONIC ethernet @%08lx, MAC %s, IRQ %d\n", dev->name,
-	       dev->base_addr, print_mac(mac, dev->dev_addr), dev->irq);
+	printk("%s: SONIC ethernet @%08lx, MAC %pM, IRQ %d\n", dev->name,
+	       dev->base_addr, dev->dev_addr, dev->irq);
 
 	return 0;
 
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 57e1f49..cf97129 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -355,6 +355,16 @@
 static void set_rx_mode(struct net_device *dev);
 static const struct ethtool_ops ethtool_ops;
 
+static const struct net_device_ops netdev_ops = {
+	.ndo_open 		= yellowfin_open,
+	.ndo_stop 		= yellowfin_close,
+	.ndo_start_xmit 	= yellowfin_start_xmit,
+	.ndo_set_multicast_list = set_rx_mode,
+	.ndo_change_mtu		= eth_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl 		= netdev_ioctl,
+	.ndo_tx_timeout 	= yellowfin_tx_timeout,
+};
 
 static int __devinit yellowfin_init_one(struct pci_dev *pdev,
 					const struct pci_device_id *ent)
@@ -374,7 +384,6 @@
 #else
 	int bar = 1;
 #endif
-	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -465,13 +474,8 @@
 		np->duplex_lock = 1;
 
 	/* The Yellowfin-specific entries in the device structure. */
-	dev->open = &yellowfin_open;
-	dev->hard_start_xmit = &yellowfin_start_xmit;
-	dev->stop = &yellowfin_close;
-	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &netdev_ioctl;
+	dev->netdev_ops = &netdev_ops;
 	SET_ETHTOOL_OPS(dev, &ethtool_ops);
-	dev->tx_timeout = yellowfin_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
 	if (mtu)
@@ -481,10 +485,10 @@
 	if (i)
 		goto err_out_unmap_status;
 
-	printk(KERN_INFO "%s: %s type %8x at %p, %s, IRQ %d.\n",
+	printk(KERN_INFO "%s: %s type %8x at %p, %pM, IRQ %d.\n",
 		   dev->name, pci_id_tbl[chip_idx].name,
 		   ioread32(ioaddr + ChipRev), ioaddr,
-		   print_mac(mac, dev->dev_addr), irq);
+		   dev->dev_addr, irq);
 
 	if (np->drv_flags & HasMII) {
 		int phy, phy_idx = 0;
@@ -1100,11 +1104,9 @@
 			memcmp(le32_to_cpu(yp->rx_ring_dma +
 				entry*sizeof(struct yellowfin_desc)),
 				"\377\377\377\377\377\377", 6) != 0) {
-			if (bogus_rx++ == 0) {
-				DECLARE_MAC_BUF(mac);
-				printk(KERN_WARNING "%s: Bad frame to %s\n",
-					   dev->name, print_mac(mac, buf_addr));
-			}
+			if (bogus_rx++ == 0)
+				printk(KERN_WARNING "%s: Bad frame to %pM\n",
+					   dev->name, buf_addr);
 #endif
 		} else {
 			struct sk_buff *skb;
@@ -1141,7 +1143,6 @@
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			dev->last_rx = jiffies;
 			dev->stats.rx_packets++;
 			dev->stats.rx_bytes += pkt_len;
 		}
@@ -1423,14 +1424,3 @@
 
 module_init(yellowfin_init);
 module_exit(yellowfin_cleanup);
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c yellowfin.c"
- *  compile-command-alphaLX: "gcc -DMODULE -Wall -Wstrict-prototypes -O2 -c yellowfin.c -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED"
- *  simple-compile-command: "gcc -DMODULE -O6 -c yellowfin.c"
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index a86c022..f0b15c9 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -167,7 +167,7 @@
 /* Request needed resources */
 static int znet_request_resources (struct net_device *dev)
 {
-	struct znet_private *znet = dev->priv;
+	struct znet_private *znet = netdev_priv(dev);
 	unsigned long flags;
 
 	if (request_irq (dev->irq, &znet_interrupt, 0, "ZNet", dev))
@@ -201,7 +201,7 @@
 
 static void znet_release_resources (struct net_device *dev)
 {
-	struct znet_private *znet = dev->priv;
+	struct znet_private *znet = netdev_priv(dev);
 	unsigned long flags;
 
 	release_region (znet->sia_base, znet->sia_size);
@@ -216,7 +216,7 @@
 /* Keep the magical SIA stuff in a single function... */
 static void znet_transceiver_power (struct net_device *dev, int on)
 {
-	struct znet_private *znet = dev->priv;
+	struct znet_private *znet = netdev_priv(dev);
 	unsigned char v;
 
 	/* Turn on/off the 82501 SIA, using zenith-specific magic. */
@@ -235,7 +235,7 @@
    Also used from hardware_init. */
 static void znet_set_multicast_list (struct net_device *dev)
 {
-	struct znet_private *znet = dev->priv;
+	struct znet_private *znet = netdev_priv(dev);
 	short ioaddr = dev->base_addr;
 	struct i82593_conf_block *cfblk = &znet->i593_init;
 
@@ -370,7 +370,6 @@
 	struct net_device *dev;
 	char *p;
 	int err = -ENOMEM;
-	DECLARE_MAC_BUF(mac);
 
 	/* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
 	for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++)
@@ -387,7 +386,7 @@
 	if (!dev)
 		return -ENOMEM;
 
-	znet = dev->priv;
+	znet = netdev_priv(dev);
 
 	netinfo = (struct netidblk *)p;
 	dev->base_addr = netinfo->iobase1;
@@ -397,9 +396,9 @@
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = netinfo->netid[i];
 
-	printk(KERN_INFO "%s: ZNET at %#3lx, %s"
+	printk(KERN_INFO "%s: ZNET at %#3lx, %pM"
 	       ", using IRQ %d DMA %d and %d.\n",
-	       dev->name, dev->base_addr, print_mac(mac, dev->dev_addr),
+	       dev->name, dev->base_addr, dev->dev_addr,
 	       dev->irq, netinfo->dma1, netinfo->dma2);
 
 	if (znet_debug > 1) {
@@ -531,7 +530,7 @@
 static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
-	struct znet_private *znet = dev->priv;
+	struct znet_private *znet = netdev_priv(dev);
 	unsigned long flags;
 	short length = skb->len;
 
@@ -601,7 +600,7 @@
 static irqreturn_t znet_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
-	struct znet_private *znet = dev->priv;
+	struct znet_private *znet = netdev_priv(dev);
 	int ioaddr;
 	int boguscnt = 20;
 	int handled = 0;
@@ -679,7 +678,7 @@
 
 static void znet_rx(struct net_device *dev)
 {
-	struct znet_private *znet = dev->priv;
+	struct znet_private *znet = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int boguscount = 1;
 	short next_frame_end_offset = 0; 		/* Offset of next frame start. */
@@ -786,7 +785,6 @@
 		  }
 		  skb->protocol=eth_type_trans(skb,dev);
 		  netif_rx(skb);
-		  dev->last_rx = jiffies;
 		  dev->stats.rx_packets++;
 		  dev->stats.rx_bytes += pkt_len;
 		}
@@ -829,7 +827,7 @@
 {
 	short ioaddr = dev->base_addr;
 	unsigned char stat = inb (ioaddr);
-	struct znet_private *znet = dev->priv;
+	struct znet_private *znet = netdev_priv(dev);
 	unsigned long flags;
 	short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE;
 	unsigned addr = inb(dma_port);
@@ -852,7 +850,7 @@
 {
 	unsigned long flags;
 	short ioaddr = dev->base_addr;
-	struct znet_private *znet = dev->priv;
+	struct znet_private *znet = netdev_priv(dev);
 
 	znet->rx_cur = znet->rx_start;
 	znet->tx_cur = znet->tx_start;
@@ -914,7 +912,7 @@
 static __exit void znet_cleanup (void)
 {
 	if (znet_dev) {
-		struct znet_private *znet = znet_dev->priv;
+		struct znet_private *znet = netdev_priv(znet_dev);
 
 		unregister_netdev (znet_dev);
 		kfree (znet->rx_start);
diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c
index 3926b2a..affd904 100644
--- a/drivers/net/zorro8390.c
+++ b/drivers/net/zorro8390.c
@@ -122,7 +122,7 @@
 	    break;
     board = z->resource.start;
     ioaddr = board+cards[i].offset;
-    dev = ____alloc_ei_netdev(0);
+    dev = alloc_ei_netdev();
     if (!dev)
 	return -ENOMEM;
     if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) {
@@ -139,6 +139,20 @@
     return 0;
 }
 
+static const struct net_device_ops zorro8390_netdev_ops = {
+	.ndo_open		= zorro8390_open,
+	.ndo_stop		= zorro8390_close,
+	.ndo_start_xmit		= ei_start_xmit,
+	.ndo_tx_timeout		= ei_tx_timeout,
+	.ndo_get_stats		= ei_get_stats,
+	.ndo_set_multicast_list = ei_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= ei_poll,
+#endif
+};
+
 static int __devinit zorro8390_init(struct net_device *dev,
 				    unsigned long board, const char *name,
 				    unsigned long ioaddr)
@@ -151,7 +165,6 @@
 	0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
 	0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
     };
-    DECLARE_MAC_BUF(mac);
 
     /* Reset card. Who knows what dain-bramaged state it was left in. */
     {
@@ -216,7 +229,7 @@
 	dev->dev_addr[i] = SA_prom[i];
 
 #ifdef DEBUG
-    printk("%s", print_mac(mac, dev->dev_addr));
+    printk("%pM", dev->dev_addr);
 #endif
 
     ei_status.name = name;
@@ -231,12 +244,8 @@
     ei_status.block_output = &zorro8390_block_output;
     ei_status.get_8390_hdr = &zorro8390_get_8390_hdr;
     ei_status.reg_offset = zorro8390_offsets;
-    dev->open = &zorro8390_open;
-    dev->stop = &zorro8390_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-    dev->poll_controller = __ei_poll;
-#endif
 
+    dev->netdev_ops = &zorro8390_netdev_ops;
     __NS8390_init(dev, 0);
     err = register_netdev(dev);
     if (err) {
@@ -244,8 +253,8 @@
 	return err;
     }
 
-    printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address %s\n",
-	   dev->name, name, board, print_mac(mac, dev->dev_addr));
+    printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address %pM\n",
+	   dev->name, name, board, dev->dev_addr);
 
     return 0;
 }
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 7c79e94..cd17092 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -329,6 +329,41 @@
 EXPORT_SYMBOL(of_find_compatible_node);
 
 /**
+ *	of_find_node_with_property - Find a node which has a property with
+ *                                   the given name.
+ *	@from:		The node to start searching from or NULL, the node
+ *			you pass will not be searched, only the next one
+ *			will; typically, you pass what the previous call
+ *			returned. of_node_put() will be called on it
+ *	@prop_name:	The name of the property to look for.
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_find_node_with_property(struct device_node *from,
+	const char *prop_name)
+{
+	struct device_node *np;
+	struct property *pp;
+
+	read_lock(&devtree_lock);
+	np = from ? from->allnext : allnodes;
+	for (; np; np = np->allnext) {
+		for (pp = np->properties; pp != 0; pp = pp->next) {
+			if (of_prop_cmp(pp->name, prop_name) == 0) {
+				of_node_get(np);
+				goto out;
+			}
+		}
+	}
+out:
+	of_node_put(from);
+	read_unlock(&devtree_lock);
+	return np;
+}
+EXPORT_SYMBOL(of_find_node_with_property);
+
+/**
  * of_match_node - Tell if an device_node has a matching of_match structure
  *	@matches:	array of of device match structures to search in
  *	@node:		the of device structure to match against
@@ -464,8 +499,8 @@
  * @list_name:	property name that contains a list
  * @cells_name:	property name that specifies phandles' arguments count
  * @index:	index of a phandle to parse out
- * @out_node:	pointer to device_node struct pointer (will be filled)
- * @out_args:	pointer to arguments pointer (will be filled)
+ * @out_node:	optional pointer to device_node struct pointer (will be filled)
+ * @out_args:	optional pointer to arguments pointer (will be filled)
  *
  * This function is useful to parse lists of phandles and their arguments.
  * Returns 0 on success and fills out_node and out_args, on error returns
@@ -499,7 +534,7 @@
 	int size;
 	int cur_index = 0;
 	struct device_node *node = NULL;
-	const void *args;
+	const void *args = NULL;
 
 	list = of_get_property(np, list_name, &size);
 	if (!list) {
@@ -512,14 +547,12 @@
 		const u32 *cells;
 		const phandle *phandle;
 
-		phandle = list;
-		args = list + 1;
+		phandle = list++;
+		args = list;
 
 		/* one cell hole in the list = <>; */
-		if (!*phandle) {
-			list++;
+		if (!*phandle)
 			goto next;
-		}
 
 		node = of_find_node_by_phandle(*phandle);
 		if (!node) {
@@ -535,8 +568,7 @@
 			goto err1;
 		}
 
-		/* Next phandle is at offset of one phandle cell + #cells */
-		list += 1 + *cells;
+		list += *cells;
 		if (list > list_end) {
 			pr_debug("%s: insufficient arguments length\n",
 				 np->full_name);
@@ -548,16 +580,26 @@
 
 		of_node_put(node);
 		node = NULL;
+		args = NULL;
 		cur_index++;
 	}
 
 	if (!node) {
-		ret = -ENOENT;
+		/*
+		 * args w/o node indicates that the loop above has stopped at
+		 * the 'hole' cell. Report this differently.
+		 */
+		if (args)
+			ret = -EEXIST;
+		else
+			ret = -ENOENT;
 		goto err0;
 	}
 
-	*out_node = node;
-	*out_args = args;
+	if (out_node)
+		*out_node = node;
+	if (out_args)
+		*out_args = args;
 
 	return 0;
 err1:
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index 7cd7301..6eea601 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -19,14 +19,17 @@
 #include <asm/prom.h>
 
 /**
- * of_get_gpio - Get a GPIO number from the device tree to use with GPIO API
+ * of_get_gpio_flags - Get a GPIO number and flags to use with GPIO API
  * @np:		device node to get GPIO from
  * @index:	index of the GPIO
+ * @flags:	a flags pointer to fill in
  *
  * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
- * value on the error condition.
+ * value on the error condition. If @flags is not NULL the function also fills
+ * in flags for the GPIO.
  */
-int of_get_gpio(struct device_node *np, int index)
+int of_get_gpio_flags(struct device_node *np, int index,
+		      enum of_gpio_flags *flags)
 {
 	int ret;
 	struct device_node *gc;
@@ -59,7 +62,11 @@
 		goto err1;
 	}
 
-	ret = of_gc->xlate(of_gc, np, gpio_spec);
+	/* .xlate might decide to not fill in the flags, so clear it. */
+	if (flags)
+		*flags = 0;
+
+	ret = of_gc->xlate(of_gc, np, gpio_spec, flags);
 	if (ret < 0)
 		goto err1;
 
@@ -70,26 +77,75 @@
 	pr_debug("%s exited with status %d\n", __func__, ret);
 	return ret;
 }
-EXPORT_SYMBOL(of_get_gpio);
+EXPORT_SYMBOL(of_get_gpio_flags);
 
 /**
- * of_gpio_simple_xlate - translate gpio_spec to the GPIO number
+ * of_gpio_count - Count GPIOs for a device
+ * @np:		device node to count GPIOs for
+ *
+ * The function returns the count of GPIOs specified for a node.
+ *
+ * Note that the empty GPIO specifiers counts too. For example,
+ *
+ * gpios = <0
+ *          &pio1 1 2
+ *          0
+ *          &pio2 3 4>;
+ *
+ * defines four GPIOs (so this function will return 4), two of which
+ * are not specified.
+ */
+unsigned int of_gpio_count(struct device_node *np)
+{
+	unsigned int cnt = 0;
+
+	do {
+		int ret;
+
+		ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells",
+						  cnt, NULL, NULL);
+		/* A hole in the gpios = <> counts anyway. */
+		if (ret < 0 && ret != -EEXIST)
+			break;
+	} while (++cnt);
+
+	return cnt;
+}
+EXPORT_SYMBOL(of_gpio_count);
+
+/**
+ * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
  * @of_gc:	pointer to the of_gpio_chip structure
  * @np:		device node of the GPIO chip
  * @gpio_spec:	gpio specifier as found in the device tree
+ * @flags:	a flags pointer to fill in
  *
  * This is simple translation function, suitable for the most 1:1 mapped
  * gpio chips. This function performs only one sanity check: whether gpio
  * is less than ngpios (that is specified in the gpio_chip).
  */
 int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np,
-			 const void *gpio_spec)
+			 const void *gpio_spec, enum of_gpio_flags *flags)
 {
 	const u32 *gpio = gpio_spec;
 
+	/*
+	 * We're discouraging gpio_cells < 2, since that way you'll have to
+	 * write your own xlate function (that will have to retrive the GPIO
+	 * number and the flags from a single gpio cell -- this is possible,
+	 * but not recommended).
+	 */
+	if (of_gc->gpio_cells < 2) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
 	if (*gpio > of_gc->gc.ngpio)
 		return -EINVAL;
 
+	if (flags)
+		*flags = gpio[1];
+
 	return *gpio;
 }
 EXPORT_SYMBOL(of_gpio_simple_xlate);
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index 24bbef7..e1b0ad6 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -24,6 +24,7 @@
 
 	for_each_child_of_node(adap_node, node) {
 		struct i2c_board_info info = {};
+		struct dev_archdata dev_ad = {};
 		const u32 *addr;
 		int len;
 
@@ -41,6 +42,9 @@
 
 		info.addr = *addr;
 
+		dev_archdata_set_node(&dev_ad, node);
+		info.archdata = &dev_ad;
+
 		request_module("%s", info.type);
 
 		result = i2c_new_device(adap, &info);
@@ -51,6 +55,13 @@
 			irq_dispose_mapping(info.irq);
 			continue;
 		}
+
+		/*
+		 * Get the node to not lose the dev_archdata->of_node.
+		 * Currently there is no way to put it back, as well as no
+		 * of_unregister_i2c_devices() call.
+		 */
+		of_node_get(node);
 	}
 }
 EXPORT_SYMBOL(of_register_i2c_devices);
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index f9b1266..454b653 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -360,13 +360,13 @@
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
 	for_each_netdev(&init_net, dev) {
-	    struct net_device_stats *stats;
+	    const struct net_device_stats *stats;
 	    struct in_device *in_dev = __in_dev_get_rcu(dev);
 	    if (!in_dev || !in_dev->ifa_list)
 		continue;
 	    if (ipv4_is_loopback(in_dev->ifa_list->ifa_local))
 		continue;
-	    stats = dev->get_stats(dev);
+	    stats = dev_get_stats(dev);
 	    rx_total += stats->rx_packets;
 	    tx_total += stats->tx_packets;
 	}
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index 9c2a22f..4e3e038 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -14,6 +14,9 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  */
+
+#undef DEBUG
+
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/string.h>
@@ -151,20 +154,20 @@
 		return;
 	}
 
+	/* Scan below the new bridge */
 	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
 	    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 		of_scan_pci_bridge(dn, dev);
 
-	pcibios_fixup_new_pci_devices(dev->subordinate);
-
-	/* Claim new bus resources */
-	pcibios_claim_one_bus(dev->bus);
-
 	/* Map IO space for child bus, which may or may not succeed */
 	pcibios_map_io_space(dev->subordinate);
 
-	/* Add new devices to global lists.  Register in proc, sysfs. */
-	pci_bus_add_devices(phb->bus);
+	/* Finish adding it : resource allocation, adding devices, etc...
+	 * Note that we need to perform the finish pass on the -parent-
+	 * bus of the EADS bridge so the bridge device itself gets
+	 * properly added
+	 */
+	pcibios_finish_adding_to_bus(phb->bus);
 }
 
 static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
@@ -203,27 +206,6 @@
 	return 0;
 }
 
-static int dlpar_remove_root_bus(struct pci_controller *phb)
-{
-	struct pci_bus *phb_bus;
-	int rc;
-
-	phb_bus = phb->bus;
-	if (!(list_empty(&phb_bus->children) &&
-	      list_empty(&phb_bus->devices))) {
-		return -EBUSY;
-	}
-
-	rc = pcibios_remove_root_bus(phb);
-	if (rc)
-		return -EIO;
-
-	device_unregister(phb_bus->bridge);
-	pci_remove_bus(phb_bus);
-
-	return 0;
-}
-
 static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
 {
 	struct slot *slot;
@@ -235,18 +217,15 @@
 
 	/* If pci slot is hotplugable, use hotplug to remove it */
 	slot = find_php_slot(dn);
-	if (slot) {
-		if (rpaphp_deregister_slot(slot)) {
-			printk(KERN_ERR
-				"%s: unable to remove hotplug slot %s\n",
-				__func__, drc_name);
-			return -EIO;
-		}
+	if (slot && rpaphp_deregister_slot(slot)) {
+		printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
+		       __func__, drc_name);
+		return -EIO;
 	}
 
 	pdn = dn->data;
 	BUG_ON(!pdn || !pdn->phb);
-	rc = dlpar_remove_root_bus(pdn->phb);
+	rc = remove_phb_dynamic(pdn->phb);
 	if (rc < 0)
 		return rc;
 
@@ -378,26 +357,38 @@
 	if (!bus)
 		return -EINVAL;
 
-	/* If pci slot is hotplugable, use hotplug to remove it */
+	pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
+		 bus->self ? pci_name(bus->self) : "<!PHB!>");
+
 	slot = find_php_slot(dn);
 	if (slot) {
+		pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n",
+			 pci_domain_nr(bus), bus->number);
+
 		if (rpaphp_deregister_slot(slot)) {
 			printk(KERN_ERR
 				"%s: unable to remove hotplug slot %s\n",
 				__func__, drc_name);
 			return -EIO;
 		}
-	} else
-		pcibios_remove_pci_devices(bus);
+	}
 
+	/* Remove all devices below slot */
+	pcibios_remove_pci_devices(bus);
+
+	/* Unmap PCI IO space */
 	if (pcibios_unmap_io_space(bus)) {
 		printk(KERN_ERR "%s: failed to unmap bus range\n",
 			__func__);
 		return -ERANGE;
 	}
 
+	/* Remove the EADS bridge device itself */
 	BUG_ON(!bus->self);
+	pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
+	eeh_remove_bus_device(bus->self);
 	pci_remove_bus_device(bus->self);
+
 	return 0;
 }
 
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 5f4f85f..ce09856 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -606,27 +606,6 @@
 		sis_apic_bug = 1;
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_ANY_ID,			quirk_ioapic_rmw);
-
-#define AMD8131_revA0        0x01
-#define AMD8131_revB0        0x11
-#define AMD8131_MISC         0x40
-#define AMD8131_NIOAMODE_BIT 0
-static void quirk_amd_8131_ioapic(struct pci_dev *dev)
-{ 
-        unsigned char tmp;
-        
-        if (nr_ioapics == 0) 
-                return;
-
-        if (dev->revision == AMD8131_revA0 || dev->revision == AMD8131_revB0) {
-                dev_info(&dev->dev, "Fixing up AMD8131 IOAPIC mode\n");
-                pci_read_config_byte( dev, AMD8131_MISC, &tmp);
-                tmp &= ~(1 << AMD8131_NIOAMODE_BIT);
-                pci_write_config_byte( dev, AMD8131_MISC, tmp);
-        }
-} 
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic);
-DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic);
 #endif /* CONFIG_X86_IO_APIC */
 
 /*
@@ -1423,6 +1402,155 @@
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x260a, quirk_intel_pcie_pm);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x260b, quirk_intel_pcie_pm);
 
+#ifdef CONFIG_X86_IO_APIC
+/*
+ * Boot interrupts on some chipsets cannot be turned off. For these chipsets,
+ * remap the original interrupt in the linux kernel to the boot interrupt, so
+ * that a PCI device's interrupt handler is installed on the boot interrupt
+ * line instead.
+ */
+static void quirk_reroute_to_boot_interrupts_intel(struct pci_dev *dev)
+{
+	if (noioapicquirk || noioapicreroute)
+		return;
+
+	dev->irq_reroute_variant = INTEL_IRQ_REROUTE_VARIANT;
+
+	printk(KERN_INFO "PCI quirk: reroute interrupts for 0x%04x:0x%04x\n",
+			dev->vendor, dev->device);
+	return;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_80333_0,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_80333_1,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ESB2_0,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXH_0,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXH_1,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXHV,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_80332_0,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_80332_1,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_80333_0,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_80333_1,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ESB2_0,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXH_0,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXH_1,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXHV,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_80332_0,	quirk_reroute_to_boot_interrupts_intel);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_80332_1,	quirk_reroute_to_boot_interrupts_intel);
+
+/*
+ * On some chipsets we can disable the generation of legacy INTx boot
+ * interrupts.
+ */
+
+/*
+ * IO-APIC1 on 6300ESB generates boot interrupts, see intel order no
+ * 300641-004US, section 5.7.3.
+ */
+#define INTEL_6300_IOAPIC_ABAR		0x40
+#define INTEL_6300_DISABLE_BOOT_IRQ	(1<<14)
+
+static void quirk_disable_intel_boot_interrupt(struct pci_dev *dev)
+{
+	u16 pci_config_word;
+
+	if (noioapicquirk)
+		return;
+
+	pci_read_config_word(dev, INTEL_6300_IOAPIC_ABAR, &pci_config_word);
+	pci_config_word |= INTEL_6300_DISABLE_BOOT_IRQ;
+	pci_write_config_word(dev, INTEL_6300_IOAPIC_ABAR, pci_config_word);
+
+	printk(KERN_INFO "disabled boot interrupt on device 0x%04x:0x%04x\n",
+		dev->vendor, dev->device);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_ESB_10, 	quirk_disable_intel_boot_interrupt);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_ESB_10, 	quirk_disable_intel_boot_interrupt);
+
+/*
+ * disable boot interrupts on HT-1000
+ */
+#define BC_HT1000_FEATURE_REG		0x64
+#define BC_HT1000_PIC_REGS_ENABLE	(1<<0)
+#define BC_HT1000_MAP_IDX		0xC00
+#define BC_HT1000_MAP_DATA		0xC01
+
+static void quirk_disable_broadcom_boot_interrupt(struct pci_dev *dev)
+{
+	u32 pci_config_dword;
+	u8 irq;
+
+	if (noioapicquirk)
+		return;
+
+	pci_read_config_dword(dev, BC_HT1000_FEATURE_REG, &pci_config_dword);
+	pci_write_config_dword(dev, BC_HT1000_FEATURE_REG, pci_config_dword |
+			BC_HT1000_PIC_REGS_ENABLE);
+
+	for (irq = 0x10; irq < 0x10 + 32; irq++) {
+		outb(irq, BC_HT1000_MAP_IDX);
+		outb(0x00, BC_HT1000_MAP_DATA);
+	}
+
+	pci_write_config_dword(dev, BC_HT1000_FEATURE_REG, pci_config_dword);
+
+	printk(KERN_INFO "disabled boot interrupts on PCI device"
+			"0x%04x:0x%04x\n", dev->vendor, dev->device);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS,   PCI_DEVICE_ID_SERVERWORKS_HT1000SB, 	quirk_disable_broadcom_boot_interrupt);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SERVERWORKS,   PCI_DEVICE_ID_SERVERWORKS_HT1000SB, 	quirk_disable_broadcom_boot_interrupt);
+
+/*
+ * disable boot interrupts on AMD and ATI chipsets
+ */
+/*
+ * NOIOAMODE needs to be disabled to disable "boot interrupts". For AMD 8131
+ * rev. A0 and B0, NOIOAMODE needs to be disabled anyway to fix IO-APIC mode
+ * (due to an erratum).
+ */
+#define AMD_813X_MISC			0x40
+#define AMD_813X_NOIOAMODE		(1<<0)
+
+static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev)
+{
+	u32 pci_config_dword;
+
+	if (noioapicquirk)
+		return;
+
+	pci_read_config_dword(dev, AMD_813X_MISC, &pci_config_dword);
+	pci_config_dword &= ~AMD_813X_NOIOAMODE;
+	pci_write_config_dword(dev, AMD_813X_MISC, pci_config_dword);
+
+	printk(KERN_INFO "disabled boot interrupts on PCI device "
+			"0x%04x:0x%04x\n", dev->vendor, dev->device);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,   PCI_DEVICE_ID_AMD_8131_BRIDGE, 	quirk_disable_amd_813x_boot_interrupt);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD,   PCI_DEVICE_ID_AMD_8132_BRIDGE, 	quirk_disable_amd_813x_boot_interrupt);
+
+#define AMD_8111_PCI_IRQ_ROUTING	0x56
+
+static void quirk_disable_amd_8111_boot_interrupt(struct pci_dev *dev)
+{
+	u16 pci_config_word;
+
+	if (noioapicquirk)
+		return;
+
+	pci_read_config_word(dev, AMD_8111_PCI_IRQ_ROUTING, &pci_config_word);
+	if (!pci_config_word) {
+		printk(KERN_INFO "boot interrupts on PCI device 0x%04x:0x%04x "
+				"already disabled\n",
+				dev->vendor, dev->device);
+		return;
+	}
+	pci_write_config_word(dev, AMD_8111_PCI_IRQ_ROUTING, 0);
+	printk(KERN_INFO "disabled boot interrupts on PCI device "
+			"0x%04x:0x%04x\n", dev->vendor, dev->device);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,   PCI_DEVICE_ID_AMD_8111_SMBUS, 	quirk_disable_amd_8111_boot_interrupt);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD,   PCI_DEVICE_ID_AMD_8111_SMBUS, 	quirk_disable_amd_8111_boot_interrupt);
+#endif /* CONFIG_X86_IO_APIC */
+
 /*
  * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
  * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index 06848b2..5324978 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -59,8 +59,6 @@
 		struct ps3av_reply_hdr reply_hdr;
 		u8 raw[PS3AV_BUF_SIZE];
 	} recv_buf;
-	void (*flip_ctl)(int on, void *data);
-	void *flip_data;
 } *ps3av;
 
 /* color space */
@@ -939,24 +937,6 @@
 
 EXPORT_SYMBOL_GPL(ps3av_audio_mute);
 
-void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data),
-			     void *flip_data)
-{
-	mutex_lock(&ps3av->mutex);
-	ps3av->flip_ctl = flip_ctl;
-	ps3av->flip_data = flip_data;
-	mutex_unlock(&ps3av->mutex);
-}
-EXPORT_SYMBOL_GPL(ps3av_register_flip_ctl);
-
-void ps3av_flip_ctl(int on)
-{
-	mutex_lock(&ps3av->mutex);
-	if (ps3av->flip_ctl)
-		ps3av->flip_ctl(on, ps3av->flip_data);
-	mutex_unlock(&ps3av->mutex);
-}
-
 static int ps3av_probe(struct ps3_system_bus_device *dev)
 {
 	int res;
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
index 11eb503..716596e 100644
--- a/drivers/ps3/ps3av_cmd.c
+++ b/drivers/ps3/ps3av_cmd.c
@@ -864,7 +864,7 @@
 {
 	int res;
 
-	ps3av_flip_ctl(0);	/* flip off */
+	mutex_lock(&ps3_gpu_mutex);
 
 	/* avb packet */
 	res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb),
@@ -878,7 +878,7 @@
 			 res);
 
       out:
-	ps3av_flip_ctl(1);	/* flip on */
+	mutex_unlock(&ps3_gpu_mutex);
 	return res;
 }
 
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 643a6b9..5c13f61 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -365,15 +365,15 @@
 				rdid++)
 			rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
 		rdev->rswitch = rswitch;
-		sprintf(rio_name(rdev), "%02x:s:%04x", rdev->net->id,
-			rdev->rswitch->switchid);
+		dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
+			     rdev->rswitch->switchid);
 		rio_route_set_ops(rdev);
 
 		list_add_tail(&rswitch->node, &rio_switches);
 
 	} else
-		sprintf(rio_name(rdev), "%02x:e:%04x", rdev->net->id,
-			rdev->destid);
+		dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id,
+			     rdev->destid);
 
 	rdev->dev.bus = &rio_bus_type;
 
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index 2cd77ab..054e052 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -328,6 +328,13 @@
 	int sr;
 	u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
 
+	/* The clock has an 8 bit wide bcd-coded register (they never learn)
+	 * for the year. tm_year is an offset from 1900 and we are interested
+	 * in the 2000-2099 range, so any value less than 100 is invalid.
+	 */
+	if (tm->tm_year < 100)
+		return -EINVAL;
+
 	regs[ISL1208_REG_SC] = bin2bcd(tm->tm_sec);
 	regs[ISL1208_REG_MN] = bin2bcd(tm->tm_min);
 	regs[ISL1208_REG_HR] = bin2bcd(tm->tm_hour) | ISL1208_REG_HR_MIL;
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 363bd13..570ae59 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1898,15 +1898,19 @@
 		wait_event(dasd_flush_wq, (cqr->status < DASD_CQR_QUEUED));
 		/* Process finished ERP request. */
 		if (cqr->refers) {
+			spin_lock_bh(&block->queue_lock);
 			__dasd_block_process_erp(block, cqr);
+			spin_unlock_bh(&block->queue_lock);
 			/* restart list_for_xx loop since dasd_process_erp
 			 * might remove multiple elements */
 			goto restart_cb;
 		}
 		/* call the callback function */
+		spin_lock_irq(&block->request_queue_lock);
 		cqr->endclk = get_clock();
 		list_del_init(&cqr->blocklist);
 		__dasd_cleanup_cqr(cqr);
+		spin_unlock_irq(&block->request_queue_lock);
 	}
 	return rc;
 }
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 921443b..2ef2573 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -23,6 +23,7 @@
 
 /* This is ugly... */
 #define PRINTK_HEADER "dasd_devmap:"
+#define DASD_BUS_ID_SIZE 20
 
 #include "dasd_int.h"
 
@@ -41,7 +42,7 @@
  */
 struct dasd_devmap {
 	struct list_head list;
-	char bus_id[BUS_ID_SIZE];
+	char bus_id[DASD_BUS_ID_SIZE];
         unsigned int devindex;
         unsigned short features;
 	struct dasd_device *device;
@@ -94,7 +95,7 @@
 	int hash, i;
 
 	hash = 0;
-	for (i = 0; (i < BUS_ID_SIZE) && *bus_id; i++, bus_id++)
+	for (i = 0; (i < DASD_BUS_ID_SIZE) && *bus_id; i++, bus_id++)
 		hash += *bus_id;
 	return hash & 0xff;
 }
@@ -301,7 +302,7 @@
 	int from, from_id0, from_id1;
 	int to, to_id0, to_id1;
 	int features, rc;
-	char bus_id[BUS_ID_SIZE+1], *str;
+	char bus_id[DASD_BUS_ID_SIZE+1], *str;
 
 	str = parsestring;
 	rc = dasd_busid(&str, &from_id0, &from_id1, &from);
@@ -407,14 +408,14 @@
 	devmap = NULL;
 	hash = dasd_hash_busid(bus_id);
 	list_for_each_entry(tmp, &dasd_hashlists[hash], list)
-		if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
+		if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) {
 			devmap = tmp;
 			break;
 		}
 	if (!devmap) {
 		/* This bus_id is new. */
 		new->devindex = dasd_max_devindex++;
-		strncpy(new->bus_id, bus_id, BUS_ID_SIZE);
+		strncpy(new->bus_id, bus_id, DASD_BUS_ID_SIZE);
 		new->features = features;
 		new->device = NULL;
 		list_add(&new->list, &dasd_hashlists[hash]);
@@ -439,7 +440,7 @@
 	devmap = ERR_PTR(-ENODEV);
 	hash = dasd_hash_busid(bus_id);
 	list_for_each_entry(tmp, &dasd_hashlists[hash], list) {
-		if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
+		if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) {
 			devmap = tmp;
 			break;
 		}
@@ -561,7 +562,7 @@
 	}
 
 	spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-	cdev->dev.driver_data = device;
+	dev_set_drvdata(&cdev->dev, device);
 	spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
 
 	return device;
@@ -597,7 +598,7 @@
 
 	/* Disconnect dasd_device structure from ccw_device structure. */
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	device->cdev->dev.driver_data = NULL;
+	dev_set_drvdata(&device->cdev->dev, NULL);
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 
 	/*
@@ -638,7 +639,7 @@
 struct dasd_device *
 dasd_device_from_cdev_locked(struct ccw_device *cdev)
 {
-	struct dasd_device *device = cdev->dev.driver_data;
+	struct dasd_device *device = dev_get_drvdata(&cdev->dev);
 
 	if (!device)
 		return ERR_PTR(-ENODEV);
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 2e60d5f..bd2c52e 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1496,7 +1496,7 @@
 
 
 	/* service information message SIM */
-	if (irb->esw.esw0.erw.cons && (irb->ecw[27] & DASD_SENSE_BIT_0) &&
+	if (irb->esw.esw0.erw.cons && !(irb->ecw[27] & DASD_SENSE_BIT_0) &&
 	    ((irb->ecw[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) {
 		dasd_3990_erp_handle_sim(device, irb->ecw);
 		dasd_schedule_device_bh(device);
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 9088de8..bf6fd34 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -180,12 +180,12 @@
 
 #ifdef CONFIG_DASD_PROFILE
 static char *
-dasd_statistics_array(char *str, unsigned int *array, int shift)
+dasd_statistics_array(char *str, unsigned int *array, int factor)
 {
 	int i;
 
 	for (i = 0; i < 32; i++) {
-		str += sprintf(str, "%7d ", array[i] >> shift);
+		str += sprintf(str, "%7d ", array[i] / factor);
 		if (i == 15)
 			str += sprintf(str, "\n");
 	}
@@ -202,7 +202,7 @@
 #ifdef CONFIG_DASD_PROFILE
 	struct dasd_profile_info_t *prof;
 	char *str;
-	int shift;
+	int factor;
 
 	/* check for active profiling */
 	if (dasd_profile_level == DASD_PROFILE_OFF) {
@@ -214,12 +214,14 @@
 
 	prof = &dasd_global_profile;
 	/* prevent couter 'overflow' on output */
-	for (shift = 0; (prof->dasd_io_reqs >> shift) > 9999999; shift++);
+	for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999;
+	     factor *= 10);
 
 	str = page;
 	str += sprintf(str, "%d dasd I/O requests\n", prof->dasd_io_reqs);
-	str += sprintf(str, "with %d sectors(512B each)\n",
+	str += sprintf(str, "with %u sectors(512B each)\n",
 		       prof->dasd_io_sects);
+	str += sprintf(str, "Scale Factor is  %d\n", factor);
 	str += sprintf(str,
 		       "   __<4	   ___8	   __16	   __32	   __64	   _128	"
 		       "   _256	   _512	   __1k	   __2k	   __4k	   __8k	"
@@ -230,22 +232,22 @@
 		       "   __1G	   __2G	   __4G " "   _>4G\n");
 
 	str += sprintf(str, "Histogram of sizes (512B secs)\n");
-	str = dasd_statistics_array(str, prof->dasd_io_secs, shift);
+	str = dasd_statistics_array(str, prof->dasd_io_secs, factor);
 	str += sprintf(str, "Histogram of I/O times (microseconds)\n");
-	str = dasd_statistics_array(str, prof->dasd_io_times, shift);
+	str = dasd_statistics_array(str, prof->dasd_io_times, factor);
 	str += sprintf(str, "Histogram of I/O times per sector\n");
-	str = dasd_statistics_array(str, prof->dasd_io_timps, shift);
+	str = dasd_statistics_array(str, prof->dasd_io_timps, factor);
 	str += sprintf(str, "Histogram of I/O time till ssch\n");
-	str = dasd_statistics_array(str, prof->dasd_io_time1, shift);
+	str = dasd_statistics_array(str, prof->dasd_io_time1, factor);
 	str += sprintf(str, "Histogram of I/O time between ssch and irq\n");
-	str = dasd_statistics_array(str, prof->dasd_io_time2, shift);
+	str = dasd_statistics_array(str, prof->dasd_io_time2, factor);
 	str += sprintf(str, "Histogram of I/O time between ssch "
 			    "and irq per sector\n");
-	str = dasd_statistics_array(str, prof->dasd_io_time2ps, shift);
+	str = dasd_statistics_array(str, prof->dasd_io_time2ps, factor);
 	str += sprintf(str, "Histogram of I/O time between irq and end\n");
-	str = dasd_statistics_array(str, prof->dasd_io_time3, shift);
+	str = dasd_statistics_array(str, prof->dasd_io_time3, factor);
 	str += sprintf(str, "# of req in chanq at enqueuing (1..32) \n");
-	str = dasd_statistics_array(str, prof->dasd_io_nr_req, shift);
+	str = dasd_statistics_array(str, prof->dasd_io_nr_req, factor);
 	len = str - page;
 #else
 	len = sprintf(page, "Statistics are not activated in this kernel\n");
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 63f26a1..26ffc6a 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -4,6 +4,9 @@
  * Authors: Carsten Otte, Stefan Weinhuber, Gerald Schaefer
  */
 
+#define KMSG_COMPONENT "dcssblk"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/ctype.h>
@@ -17,19 +20,10 @@
 #include <linux/interrupt.h>
 #include <asm/s390_rdev.h>
 
-//#define DCSSBLK_DEBUG		/* Debug messages on/off */
 #define DCSSBLK_NAME "dcssblk"
 #define DCSSBLK_MINORS_PER_DISK 1
 #define DCSSBLK_PARM_LEN 400
-
-#ifdef DCSSBLK_DEBUG
-#define PRINT_DEBUG(x...) printk(KERN_DEBUG DCSSBLK_NAME " debug: " x)
-#else
-#define PRINT_DEBUG(x...) do {} while (0)
-#endif
-#define PRINT_INFO(x...)  printk(KERN_INFO DCSSBLK_NAME " info: " x)
-#define PRINT_WARN(x...)  printk(KERN_WARNING DCSSBLK_NAME " warning: " x)
-#define PRINT_ERR(x...)	  printk(KERN_ERR DCSSBLK_NAME " error: " x)
+#define DCSS_BUS_ID_SIZE 20
 
 static int dcssblk_open(struct block_device *bdev, fmode_t mode);
 static int dcssblk_release(struct gendisk *disk, fmode_t mode);
@@ -50,7 +44,7 @@
 struct dcssblk_dev_info {
 	struct list_head lh;
 	struct device dev;
-	char segment_name[BUS_ID_SIZE];
+	char segment_name[DCSS_BUS_ID_SIZE];
 	atomic_t use_count;
 	struct gendisk *gd;
 	unsigned long start;
@@ -65,7 +59,7 @@
 
 struct segment_info {
 	struct list_head lh;
-	char segment_name[BUS_ID_SIZE];
+	char segment_name[DCSS_BUS_ID_SIZE];
 	unsigned long start;
 	unsigned long end;
 	int segment_type;
@@ -261,10 +255,9 @@
 	/* check continuity */
 	for (i = 0; i < dev_info->num_of_segments - 1; i++) {
 		if ((sort_list[i].end + 1) != sort_list[i+1].start) {
-			PRINT_ERR("Segment %s is not contiguous with "
-				"segment %s\n",
-				sort_list[i].segment_name,
-				sort_list[i+1].segment_name);
+			pr_err("Adjacent DCSSs %s and %s are not "
+			       "contiguous\n", sort_list[i].segment_name,
+			       sort_list[i+1].segment_name);
 			rc = -EINVAL;
 			goto out;
 		}
@@ -275,10 +268,10 @@
 				!(sort_list[i+1].segment_type &
 				SEGMENT_EXCLUSIVE) ||
 				(sort_list[i+1].segment_type == SEG_TYPE_ER)) {
-				PRINT_ERR("Segment %s has different type from "
-					"segment %s\n",
-					sort_list[i].segment_name,
-					sort_list[i+1].segment_name);
+				pr_err("DCSS %s and DCSS %s have "
+				       "incompatible types\n",
+				       sort_list[i].segment_name,
+				       sort_list[i+1].segment_name);
 				rc = -EINVAL;
 				goto out;
 			}
@@ -380,8 +373,9 @@
 	} else if (inbuf[0] == '0') {
 		/* reload segments in exclusive mode */
 		if (dev_info->segment_type == SEG_TYPE_SC) {
-			PRINT_ERR("Segment type SC (%s) cannot be loaded in "
-				"non-shared mode\n", dev_info->segment_name);
+			pr_err("DCSS %s is of type SC and cannot be "
+			       "loaded as exclusive-writable\n",
+			       dev_info->segment_name);
 			rc = -EINVAL;
 			goto out;
 		}
@@ -404,9 +398,8 @@
 	goto out;
 
 removeseg:
-	PRINT_ERR("Could not reload segment(s) of the device %s, removing "
-		"segment(s) now!\n",
-		dev_info->segment_name);
+	pr_err("DCSS device %s is removed after a failed access mode "
+	       "change\n", dev_info->segment_name);
 	temp = entry;
 	list_for_each_entry(entry, &dev_info->seg_list, lh) {
 		if (entry != temp)
@@ -454,17 +447,17 @@
 	if (inbuf[0] == '1') {
 		if (atomic_read(&dev_info->use_count) == 0) {
 			// device is idle => we save immediately
-			PRINT_INFO("Saving segment(s) of the device %s\n",
-				   dev_info->segment_name);
+			pr_info("All DCSSs that map to device %s are "
+				"saved\n", dev_info->segment_name);
 			list_for_each_entry(entry, &dev_info->seg_list, lh) {
 				segment_save(entry->segment_name);
 			}
 		}  else {
 			// device is busy => we save it when it becomes
 			// idle in dcssblk_release
-			PRINT_INFO("Device %s is currently busy, segment(s) "
-				   "will be saved when it becomes idle...\n",
-				   dev_info->segment_name);
+			pr_info("Device %s is in use, its DCSSs will be "
+				"saved when it becomes idle\n",
+				dev_info->segment_name);
 			dev_info->save_pending = 1;
 		}
 	} else if (inbuf[0] == '0') {
@@ -472,9 +465,9 @@
 			// device is busy & the user wants to undo his save
 			// request
 			dev_info->save_pending = 0;
-			PRINT_INFO("Pending save for segment(s) of the device "
-					"%s deactivated\n",
-					dev_info->segment_name);
+			pr_info("A pending save request for device %s "
+				"has been canceled\n",
+				dev_info->segment_name);
 		}
 	} else {
 		up_write(&dcssblk_devices_sem);
@@ -614,9 +607,8 @@
 
 	seg_byte_size = (dev_info->end - dev_info->start + 1);
 	set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
-	PRINT_INFO("Loaded segment(s) %s, size = %lu Byte, "
-		   "capacity = %lu (512 Byte) sectors\n", local_buf,
-		   seg_byte_size, seg_byte_size >> 9);
+	pr_info("Loaded %s with total size %lu bytes and capacity %lu "
+		"sectors\n", local_buf, seg_byte_size, seg_byte_size >> 9);
 
 	dev_info->save_pending = 0;
 	dev_info->is_shared = 1;
@@ -744,13 +736,15 @@
 	dev_info = dcssblk_get_device_by_name(local_buf);
 	if (dev_info == NULL) {
 		up_write(&dcssblk_devices_sem);
-		PRINT_WARN("Device %s is not loaded!\n", local_buf);
+		pr_warning("Device %s cannot be removed because it is not a "
+			   "known device\n", local_buf);
 		rc = -ENODEV;
 		goto out_buf;
 	}
 	if (atomic_read(&dev_info->use_count) != 0) {
 		up_write(&dcssblk_devices_sem);
-		PRINT_WARN("Device %s is in use!\n", local_buf);
+		pr_warning("Device %s cannot be removed while it is in "
+			   "use\n", local_buf);
 		rc = -EBUSY;
 		goto out_buf;
 	}
@@ -807,8 +801,8 @@
 	down_write(&dcssblk_devices_sem);
 	if (atomic_dec_and_test(&dev_info->use_count)
 	    && (dev_info->save_pending)) {
-		PRINT_INFO("Device %s became idle and is being saved now\n",
-			    dev_info->segment_name);
+		pr_info("Device %s has become idle and is being saved "
+			"now\n", dev_info->segment_name);
 		list_for_each_entry(entry, &dev_info->seg_list, lh) {
 			segment_save(entry->segment_name);
 		}
@@ -851,7 +845,8 @@
 		case SEG_TYPE_SC:
 			/* cannot write to these segments */
 			if (bio_data_dir(bio) == WRITE) {
-				PRINT_WARN("rejecting write to ro device %s\n",
+				pr_warning("Writing to %s failed because it "
+					   "is a read-only device\n",
 					   dev_name(&dev_info->dev));
 				goto fail;
 			}
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 0391698..76814f3 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -25,6 +25,9 @@
  *   generic hard disk support to replace ad-hoc partitioning
  */
 
+#define KMSG_COMPONENT "xpram"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/ctype.h>  /* isdigit, isxdigit */
@@ -42,12 +45,6 @@
 #define XPRAM_DEVS	1	/* one partition */
 #define XPRAM_MAX_DEVS	32	/* maximal number of devices (partitions) */
 
-#define PRINT_DEBUG(x...)	printk(KERN_DEBUG XPRAM_NAME " debug:" x)
-#define PRINT_INFO(x...)	printk(KERN_INFO XPRAM_NAME " info:" x)
-#define PRINT_WARN(x...)	printk(KERN_WARNING XPRAM_NAME " warning:" x)
-#define PRINT_ERR(x...)		printk(KERN_ERR XPRAM_NAME " error:" x)
-
-
 typedef struct {
 	unsigned int	size;		/* size of xpram segment in pages */
 	unsigned int	offset;		/* start page of xpram segment */
@@ -264,7 +261,7 @@
 
 	/* Check number of devices. */
 	if (devs <= 0 || devs > XPRAM_MAX_DEVS) {
-		PRINT_ERR("invalid number %d of devices\n",devs);
+		pr_err("%d is not a valid number of XPRAM devices\n",devs);
 		return -EINVAL;
 	}
 	xpram_devs = devs;
@@ -295,22 +292,22 @@
 			mem_auto_no++;
 	}
 	
-	PRINT_INFO("  number of devices (partitions): %d \n", xpram_devs);
+	pr_info("  number of devices (partitions): %d \n", xpram_devs);
 	for (i = 0; i < xpram_devs; i++) {
 		if (xpram_sizes[i])
-			PRINT_INFO("  size of partition %d: %u kB\n",
-				   i, xpram_sizes[i]);
+			pr_info("  size of partition %d: %u kB\n",
+				i, xpram_sizes[i]);
 		else
-			PRINT_INFO("  size of partition %d to be set "
-				   "automatically\n",i);
+			pr_info("  size of partition %d to be set "
+				"automatically\n",i);
 	}
-	PRINT_DEBUG("  memory needed (for sized partitions): %lu kB\n",
-		    mem_needed);
-	PRINT_DEBUG("  partitions to be sized automatically: %d\n",
-		    mem_auto_no);
+	pr_info("  memory needed (for sized partitions): %lu kB\n",
+		mem_needed);
+	pr_info("  partitions to be sized automatically: %d\n",
+		mem_auto_no);
 
 	if (mem_needed > pages * 4) {
-		PRINT_ERR("Not enough expanded memory available\n");
+		pr_err("Not enough expanded memory available\n");
 		return -EINVAL;
 	}
 
@@ -322,8 +319,8 @@
 	 */
 	if (mem_auto_no) {
 		mem_auto = ((pages - mem_needed / 4) / mem_auto_no) * 4;
-		PRINT_INFO("  automatically determined "
-			   "partition size: %lu kB\n", mem_auto);
+		pr_info("  automatically determined "
+			"partition size: %lu kB\n", mem_auto);
 		for (i = 0; i < xpram_devs; i++)
 			if (xpram_sizes[i] == 0)
 				xpram_sizes[i] = mem_auto;
@@ -405,12 +402,12 @@
 
 	/* Find out size of expanded memory. */
 	if (xpram_present() != 0) {
-		PRINT_WARN("No expanded memory available\n");
+		pr_err("No expanded memory available\n");
 		return -ENODEV;
 	}
 	xpram_pages = xpram_highest_page_index() + 1;
-	PRINT_INFO("  %u pages expanded memory found (%lu KB).\n",
-		   xpram_pages, (unsigned long) xpram_pages*4);
+	pr_info("  %u pages expanded memory found (%lu KB).\n",
+		xpram_pages, (unsigned long) xpram_pages*4);
 	rc = xpram_setup_sizes(xpram_pages);
 	if (rc)
 		return rc;
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index 35fd8df..97e63cf 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -7,6 +7,9 @@
  *   Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "monreader"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -24,19 +27,6 @@
 #include <asm/ebcdic.h>
 #include <asm/extmem.h>
 
-//#define MON_DEBUG			/* Debug messages on/off */
-
-#define MON_NAME "monreader"
-
-#define P_INFO(x...)	printk(KERN_INFO MON_NAME " info: " x)
-#define P_ERROR(x...)	printk(KERN_ERR MON_NAME " error: " x)
-#define P_WARNING(x...)	printk(KERN_WARNING MON_NAME " warning: " x)
-
-#ifdef MON_DEBUG
-#define P_DEBUG(x...)   printk(KERN_DEBUG MON_NAME " debug: " x)
-#else
-#define P_DEBUG(x...)   do {} while (0)
-#endif
 
 #define MON_COLLECT_SAMPLE 0x80
 #define MON_COLLECT_EVENT  0x40
@@ -172,7 +162,7 @@
 	} else
 		monmsg->replied_msglim = 1;
 	if (rc) {
-		P_ERROR("read, IUCV reply failed with rc = %i\n\n", rc);
+		pr_err("Reading monitor data failed with rc=%i\n", rc);
 		return -EIO;
 	}
 	return 0;
@@ -251,7 +241,8 @@
 {
 	struct mon_private *monpriv = path->private;
 
-	P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]);
+	pr_err("z/VM *MONITOR system service disconnected with rc=%i\n",
+	       ipuser[0]);
 	iucv_path_sever(path, NULL);
 	atomic_set(&monpriv->iucv_severed, 1);
 	wake_up(&mon_conn_wait_queue);
@@ -266,8 +257,7 @@
 	memcpy(&monpriv->msg_array[monpriv->write_index]->msg,
 	       msg, sizeof(*msg));
 	if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) {
-		P_WARNING("IUCV message pending, message limit (%i) reached\n",
-			  MON_MSGLIM);
+		pr_warning("The read queue for monitor data is full\n");
 		monpriv->msg_array[monpriv->write_index]->msglim_reached = 1;
 	}
 	monpriv->write_index = (monpriv->write_index + 1) % MON_MSGLIM;
@@ -311,8 +301,8 @@
 	rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
 			       MON_SERVICE, NULL, user_data_connect, monpriv);
 	if (rc) {
-		P_ERROR("iucv connection to *MONITOR failed with "
-			"IPUSER SEVER code = %i\n", rc);
+		pr_err("Connecting to the z/VM *MONITOR system service "
+		       "failed with rc=%i\n", rc);
 		rc = -EIO;
 		goto out_path;
 	}
@@ -353,7 +343,8 @@
 	 */
 	rc = iucv_path_sever(monpriv->path, user_data_sever);
 	if (rc)
-		P_ERROR("close, iucv_sever failed with rc = %i\n", rc);
+		pr_warning("Disconnecting the z/VM *MONITOR system service "
+			   "failed with rc=%i\n", rc);
 
 	atomic_set(&monpriv->iucv_severed, 0);
 	atomic_set(&monpriv->iucv_connected, 0);
@@ -469,7 +460,8 @@
 	int rc;
 
 	if (!MACHINE_IS_VM) {
-		P_ERROR("not running under z/VM, driver not loaded\n");
+		pr_err("The z/VM *MONITOR record device driver cannot be "
+		       "loaded without z/VM\n");
 		return -ENODEV;
 	}
 
@@ -478,7 +470,8 @@
 	 */
 	rc = iucv_register(&monreader_iucv_handler, 1);
 	if (rc) {
-		P_ERROR("failed to register with iucv driver\n");
+		pr_err("The z/VM *MONITOR record device driver failed to "
+		       "register with IUCV\n");
 		return rc;
 	}
 
@@ -488,8 +481,8 @@
 		goto out_iucv;
 	}
 	if (rc != SEG_TYPE_SC) {
-		P_ERROR("segment %s has unsupported type, should be SC\n",
-			mon_dcss_name);
+		pr_err("The specified *MONITOR DCSS %s does not have the "
+		       "required type SC\n", mon_dcss_name);
 		rc = -EINVAL;
 		goto out_iucv;
 	}
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index 4d71aa8..c7d7483 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -8,6 +8,9 @@
  * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com>
  */
 
+#define KMSG_COMPONENT "monwriter"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -64,9 +67,9 @@
 	rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen);
 	if (rc <= 0)
 		return rc;
+	pr_err("Writing monitor data failed with rc=%i\n", rc);
 	if (rc == 5)
 		return -EPERM;
-	printk("DIAG X'DC' error with return code: %i\n", rc);
 	return -EINVAL;
 }
 
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index ec9c0bc..5063904 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -6,6 +6,9 @@
  *		 Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "sclp_cmd"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/completion.h>
 #include <linux/init.h>
 #include <linux/errno.h>
@@ -16,9 +19,8 @@
 #include <linux/memory.h>
 #include <asm/chpid.h>
 #include <asm/sclp.h>
-#include "sclp.h"
 
-#define TAG	"sclp_cmd: "
+#include "sclp.h"
 
 #define SCLP_CMDW_READ_SCP_INFO		0x00020001
 #define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
@@ -169,8 +171,8 @@
 
 	/* Check response. */
 	if (request->status != SCLP_REQ_DONE) {
-		printk(KERN_WARNING TAG "sync request failed "
-		       "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status);
+		pr_warning("sync request failed (cmd=0x%08x, "
+			   "status=0x%02x)\n", cmd, request->status);
 		rc = -EIO;
 	}
 out:
@@ -224,8 +226,8 @@
 	if (rc)
 		goto out;
 	if (sccb->header.response_code != 0x0010) {
-		printk(KERN_WARNING TAG "readcpuinfo failed "
-		       "(response=0x%04x)\n", sccb->header.response_code);
+		pr_warning("readcpuinfo failed (response=0x%04x)\n",
+			   sccb->header.response_code);
 		rc = -EIO;
 		goto out;
 	}
@@ -262,8 +264,9 @@
 	case 0x0120:
 		break;
 	default:
-		printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, "
-		       "response=0x%04x)\n", cmd, sccb->header.response_code);
+		pr_warning("configure cpu failed (cmd=0x%08x, "
+			   "response=0x%04x)\n", cmd,
+			   sccb->header.response_code);
 		rc = -EIO;
 		break;
 	}
@@ -626,9 +629,9 @@
 	case 0x0450:
 		break;
 	default:
-		printk(KERN_WARNING TAG "configure channel-path failed "
-		       "(cmd=0x%08x, response=0x%04x)\n", cmd,
-		       sccb->header.response_code);
+		pr_warning("configure channel-path failed "
+			   "(cmd=0x%08x, response=0x%04x)\n", cmd,
+			   sccb->header.response_code);
 		rc = -EIO;
 		break;
 	}
@@ -695,8 +698,8 @@
 	if (rc)
 		goto out;
 	if (sccb->header.response_code != 0x0010) {
-		printk(KERN_WARNING TAG "read channel-path info failed "
-		       "(response=0x%04x)\n", sccb->header.response_code);
+		pr_warning("read channel-path info failed "
+			   "(response=0x%04x)\n", sccb->header.response_code);
 		rc = -EIO;
 		goto out;
 	}
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index 4cebd6e..b497afe 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -5,15 +5,17 @@
  *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "sclp_config"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/cpu.h>
 #include <linux/sysdev.h>
 #include <linux/workqueue.h>
 #include <asm/smp.h>
-#include "sclp.h"
 
-#define TAG	"sclp_config: "
+#include "sclp.h"
 
 struct conf_mgm_data {
 	u8 reserved;
@@ -31,7 +33,7 @@
 	int cpu;
 	struct sys_device *sysdev;
 
-	printk(KERN_WARNING TAG "cpu capability changed.\n");
+	pr_warning("cpu capability changed.\n");
 	get_online_cpus();
 	for_each_online_cpu(cpu) {
 		sysdev = get_cpu_sysdev(cpu);
@@ -78,7 +80,7 @@
 		return rc;
 
 	if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) {
-		printk(KERN_WARNING TAG "no configuration management.\n");
+		pr_warning("no configuration management.\n");
 		sclp_unregister(&sclp_conf_register);
 		rc = -ENOSYS;
 	}
diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c
index d887bd2..62c2647 100644
--- a/drivers/s390/char/sclp_cpi_sys.c
+++ b/drivers/s390/char/sclp_cpi_sys.c
@@ -7,6 +7,9 @@
  *		 Michael Ernst <mernst@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "sclp_cpi"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/stat.h>
@@ -20,6 +23,7 @@
 #include <linux/completion.h>
 #include <asm/ebcdic.h>
 #include <asm/sclp.h>
+
 #include "sclp.h"
 #include "sclp_rw.h"
 #include "sclp_cpi_sys.h"
@@ -150,16 +154,16 @@
 	wait_for_completion(&completion);
 
 	if (req->status != SCLP_REQ_DONE) {
-		printk(KERN_WARNING "cpi: request failed (status=0x%02x)\n",
-			req->status);
+		pr_warning("request failed (status=0x%02x)\n",
+			   req->status);
 		rc = -EIO;
 		goto out_free_req;
 	}
 
 	response = ((struct cpi_sccb *) req->sccb)->header.response_code;
 	if (response != 0x0020) {
-		printk(KERN_WARNING "cpi: failed with "
-			"response code 0x%x\n", response);
+		pr_warning("request failed with response code 0x%x\n",
+			   response);
 		rc = -EIO;
 	}
 
diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c
index 8b85485..6a1c58d 100644
--- a/drivers/s390/char/sclp_sdias.c
+++ b/drivers/s390/char/sclp_sdias.c
@@ -5,15 +5,18 @@
  * Author(s): Michael Holzheu
  */
 
+#define KMSG_COMPONENT "sclp_sdias"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/sched.h>
 #include <asm/sclp.h>
 #include <asm/debug.h>
 #include <asm/ipl.h>
+
 #include "sclp.h"
 #include "sclp_rw.h"
 
 #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x)
-#define ERROR_MSG(x...) printk ( KERN_ALERT "SDIAS: " x )
 
 #define SDIAS_RETRIES 300
 #define SDIAS_SLEEP_TICKS 50
@@ -131,7 +134,7 @@
 
 	rc = sdias_sclp_send(&request);
 	if (rc) {
-		ERROR_MSG("sclp_send failed for get_nr_blocks\n");
+		pr_err("sclp_send failed for get_nr_blocks\n");
 		goto out;
 	}
 	if (sccb.hdr.response_code != 0x0020) {
@@ -145,7 +148,8 @@
 			rc = sccb.evbuf.blk_cnt;
 			break;
 		default:
-			ERROR_MSG("SCLP error: %x\n", sccb.evbuf.event_status);
+			pr_err("SCLP error: %x\n",
+			       sccb.evbuf.event_status);
 			rc = -EIO;
 			goto out;
 	}
@@ -201,7 +205,7 @@
 
 	rc = sdias_sclp_send(&request);
 	if (rc) {
-		ERROR_MSG("sclp_send failed: %x\n", rc);
+		pr_err("sclp_send failed: %x\n", rc);
 		goto out;
 	}
 	if (sccb.hdr.response_code != 0x0020) {
@@ -219,9 +223,9 @@
 		case EVSTATE_NO_DATA:
 			TRACE("no data\n");
 		default:
-			ERROR_MSG("Error from SCLP while copying hsa. "
-				  "Event status = %x\n",
-				sccb.evbuf.event_status);
+			pr_err("Error from SCLP while copying hsa. "
+			       "Event status = %x\n",
+			       sccb.evbuf.event_status);
 			rc = -EIO;
 	}
 out:
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 9854f19..a839aa5 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -583,23 +583,6 @@
 	return count;
 }
 
-static void
-__sclp_vt220_flush_buffer(void)
-{
-	unsigned long flags;
-
-	sclp_vt220_emit_current();
-	spin_lock_irqsave(&sclp_vt220_lock, flags);
-	if (timer_pending(&sclp_vt220_timer))
-		del_timer(&sclp_vt220_timer);
-	while (sclp_vt220_outqueue_count > 0) {
-		spin_unlock_irqrestore(&sclp_vt220_lock, flags);
-		sclp_sync_wait();
-		spin_lock_irqsave(&sclp_vt220_lock, flags);
-	}
-	spin_unlock_irqrestore(&sclp_vt220_lock, flags);
-}
-
 /*
  * Pass on all buffers to the hardware. Return only when there are no more
  * buffers pending.
@@ -745,6 +728,22 @@
 	return sclp_vt220_driver;
 }
 
+static void __sclp_vt220_flush_buffer(void)
+{
+	unsigned long flags;
+
+	sclp_vt220_emit_current();
+	spin_lock_irqsave(&sclp_vt220_lock, flags);
+	if (timer_pending(&sclp_vt220_timer))
+		del_timer(&sclp_vt220_timer);
+	while (sclp_vt220_outqueue_count > 0) {
+		spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+		sclp_sync_wait();
+		spin_lock_irqsave(&sclp_vt220_lock, flags);
+	}
+	spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+}
+
 static int
 sclp_vt220_notify(struct notifier_block *self,
 			  unsigned long event, void *data)
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 09e7d9b..a6087ce 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -11,12 +11,14 @@
  * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS
  */
 
+#define KMSG_COMPONENT "vmcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <asm/cpcmd.h>
 #include <asm/debug.h>
 #include <asm/uaccess.h>
@@ -26,8 +28,6 @@
 MODULE_AUTHOR("Christian Borntraeger <borntraeger@de.ibm.com>");
 MODULE_DESCRIPTION("z/VM CP interface");
 
-#define PRINTK_HEADER "vmcp: "
-
 static debug_info_t *vmcp_debug;
 
 static int vmcp_open(struct inode *inode, struct file *file)
@@ -41,13 +41,11 @@
 	if (!session)
 		return -ENOMEM;
 
-	lock_kernel();
 	session->bufsize = PAGE_SIZE;
 	session->response = NULL;
 	session->resp_size = 0;
 	mutex_init(&session->mutex);
 	file->private_data = session;
-	unlock_kernel();
 	return nonseekable_open(inode, file);
 }
 
@@ -193,7 +191,8 @@
 	int ret;
 
 	if (!MACHINE_IS_VM) {
-		PRINT_WARN("z/VM CP interface is only available under z/VM\n");
+		pr_warning("The z/VM CP interface device driver cannot be "
+			   "loaded without z/VM\n");
 		return -ENODEV;
 	}
 
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 2476272..aabbeb9 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -10,6 +10,10 @@
  *		   Stefan Weinhuber <wein@de.ibm.com>
  *
  */
+
+#define KMSG_COMPONENT "vmlogrdr"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/errno.h>
@@ -28,8 +32,6 @@
 #include <linux/smp_lock.h>
 #include <linux/string.h>
 
-
-
 MODULE_AUTHOR
 	("(C) 2004 IBM Corporation by Xenia Tkatschow (xenia@us.ibm.com)\n"
 	 "                            Stefan Weinhuber (wein@de.ibm.com)");
@@ -174,8 +176,7 @@
 	struct vmlogrdr_priv_t * logptr = path->private;
 	u8 reason = (u8) ipuser[8];
 
-	printk (KERN_ERR "vmlogrdr: connection severed with"
-		" reason %i\n", reason);
+	pr_err("vmlogrdr: connection severed with reason %i\n", reason);
 
 	iucv_path_sever(path, NULL);
 	kfree(path);
@@ -333,8 +334,8 @@
 	if (logptr->autorecording) {
 		ret = vmlogrdr_recording(logptr,1,logptr->autopurge);
 		if (ret)
-			printk (KERN_WARNING "vmlogrdr: failed to start "
-				"recording automatically\n");
+			pr_warning("vmlogrdr: failed to start "
+				   "recording automatically\n");
 	}
 
 	/* create connection to the system service */
@@ -345,9 +346,9 @@
 				       logptr->system_service, NULL, NULL,
 				       logptr);
 	if (connect_rc) {
-		printk (KERN_ERR "vmlogrdr: iucv connection to %s "
-			"failed with rc %i \n", logptr->system_service,
-			connect_rc);
+		pr_err("vmlogrdr: iucv connection to %s "
+		       "failed with rc %i \n",
+		       logptr->system_service, connect_rc);
 		goto out_path;
 	}
 
@@ -388,8 +389,8 @@
 	if (logptr->autorecording) {
 		ret = vmlogrdr_recording(logptr,0,logptr->autopurge);
 		if (ret)
-			printk (KERN_WARNING "vmlogrdr: failed to stop "
-				"recording automatically\n");
+			pr_warning("vmlogrdr: failed to stop "
+				   "recording automatically\n");
 	}
 	logptr->dev_in_use = 0;
 
@@ -823,8 +824,7 @@
 	dev_t dev;
 
 	if (! MACHINE_IS_VM) {
-		printk (KERN_ERR "vmlogrdr: not running under VM, "
-				"driver not loaded.\n");
+		pr_err("not running under VM, driver not loaded.\n");
 		return -ENODEV;
 	}
 
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index 9020eba..5dcef81 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -8,6 +8,9 @@
  *	    Frank Munzert <munzert@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "vmur"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/cdev.h>
 #include <linux/smp_lock.h>
 
@@ -40,8 +43,6 @@
 MODULE_DESCRIPTION("s390 z/VM virtual unit record device driver");
 MODULE_LICENSE("GPL");
 
-#define PRINTK_HEADER "vmur: "
-
 static dev_t ur_first_dev_maj_min;
 static struct class *vmur_class;
 static struct debug_info *vmur_dbf;
@@ -987,7 +988,8 @@
 	dev_t dev;
 
 	if (!MACHINE_IS_VM) {
-		PRINT_ERR("%s is only available under z/VM.\n", ur_banner);
+		pr_err("The %s cannot be loaded without z/VM\n",
+		       ur_banner);
 		return -ENODEV;
 	}
 
@@ -1006,7 +1008,8 @@
 
 	rc = alloc_chrdev_region(&dev, 0, NUM_MINORS, "vmur");
 	if (rc) {
-		PRINT_ERR("alloc_chrdev_region failed: err = %d\n", rc);
+		pr_err("Kernel function alloc_chrdev_region failed with "
+		       "error code %d\n", rc);
 		goto fail_unregister_driver;
 	}
 	ur_first_dev_maj_min = MKDEV(MAJOR(dev), 0);
@@ -1016,7 +1019,7 @@
 		rc = PTR_ERR(vmur_class);
 		goto fail_unregister_region;
 	}
-	PRINT_INFO("%s loaded.\n", ur_banner);
+	pr_info("%s loaded.\n", ur_banner);
 	return 0;
 
 fail_unregister_region:
@@ -1034,7 +1037,7 @@
 	unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS);
 	ccw_driver_unregister(&ur_driver);
 	debug_unregister(vmur_dbf);
-	PRINT_INFO("%s unloaded.\n", ur_banner);
+	pr_info("%s unloaded.\n", ur_banner);
 }
 
 module_init(ur_init);
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 7fd84be..eefc661 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -9,6 +9,9 @@
  * Author(s): Michael Holzheu
  */
 
+#define KMSG_COMPONENT "zdump"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/utsname.h>
@@ -24,8 +27,6 @@
 #include "sclp.h"
 
 #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
-#define MSG(x...) printk( KERN_ALERT x )
-#define ERROR_MSG(x...) printk ( KERN_ALERT "DUMP: " x )
 
 #define TO_USER		0
 #define TO_KERNEL	1
@@ -563,19 +564,19 @@
 
 	switch (arch) {
 	case ARCH_S390X:
-		MSG("DETECTED 'S390X (64 bit) OS'\n");
+		pr_alert("DETECTED 'S390X (64 bit) OS'\n");
 		sys_info.sa_base = SAVE_AREA_BASE_S390X;
 		sys_info.sa_size = sizeof(struct save_area_s390x);
 		set_s390x_lc_mask(&sys_info.lc_mask);
 		break;
 	case ARCH_S390:
-		MSG("DETECTED 'S390 (32 bit) OS'\n");
+		pr_alert("DETECTED 'S390 (32 bit) OS'\n");
 		sys_info.sa_base = SAVE_AREA_BASE_S390;
 		sys_info.sa_size = sizeof(struct save_area_s390);
 		set_s390_lc_mask(&sys_info.lc_mask);
 		break;
 	default:
-		ERROR_MSG("unknown architecture 0x%x.\n",arch);
+		pr_alert("0x%x is an unknown architecture.\n",arch);
 		return -EINVAL;
 	}
 	sys_info.arch = arch;
@@ -674,7 +675,8 @@
 
 #ifndef __s390x__
 	if (arch == ARCH_S390X) {
-		ERROR_MSG("32 bit dumper can't dump 64 bit system!\n");
+		pr_alert("The 32-bit dump tool cannot be used for a "
+			 "64-bit system\n");
 		rc = -EINVAL;
 		goto fail;
 	}
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 2f547b8..fe00be3 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -9,6 +9,9 @@
  *		 Arnd Bergmann (arndb@de.ibm.com)
  */
 
+#define KMSG_COMPONENT "cio"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
@@ -50,9 +53,10 @@
 {
 	if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) {
 		if (msgtrigger)
-			printk(KERN_WARNING "cio: Invalid cio_ignore range "
-			       "0.%x.%04x-0.%x.%04x\n", from_ssid, from,
-			       to_ssid, to);
+			pr_warning("0.%x.%04x to 0.%x.%04x is not a valid "
+				   "range for cio_ignore\n", from_ssid, from,
+				   to_ssid, to);
+
 		return 1;
 	}
 
@@ -140,8 +144,8 @@
 	rc = 0;
 out:
 	if (rc && msgtrigger)
-		printk(KERN_WARNING "cio: Invalid cio_ignore device '%s'\n",
-		       str);
+		pr_warning("%s is not a valid device for the cio_ignore "
+			   "kernel parameter\n", str);
 
 	return rc;
 }
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 3ac2c20..918e6fc 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -19,6 +19,8 @@
 #include <asm/ccwdev.h>
 #include <asm/ccwgroup.h>
 
+#define CCW_BUS_ID_SIZE		20
+
 /* In Linux 2.4, we had a channel device layer called "chandev"
  * that did all sorts of obscure stuff for networking devices.
  * This is another driver that serves as a replacement for just
@@ -89,15 +91,23 @@
 
 	gdev = to_ccwgroupdev(dev);
 
-	if (gdev->state != CCWGROUP_OFFLINE)
-		return -EINVAL;
-
+	/* Prevent concurrent online/offline processing and ungrouping. */
+	if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0)
+		return -EAGAIN;
+	if (gdev->state != CCWGROUP_OFFLINE) {
+		rc = -EINVAL;
+		goto out;
+	}
 	/* Note that we cannot unregister the device from one of its
 	 * attribute methods, so we have to use this roundabout approach.
 	 */
 	rc = device_schedule_callback(dev, ccwgroup_ungroup_callback);
-	if (rc)
-		count = rc;
+out:
+	if (rc) {
+		/* Release onoff "lock" when ungrouping failed. */
+		atomic_set(&gdev->onoff, 0);
+		return rc;
+	}
 	return count;
 }
 
@@ -172,7 +182,7 @@
 		len = end - start + 1;
 		end++;
 	}
-	if (len < BUS_ID_SIZE) {
+	if (len < CCW_BUS_ID_SIZE) {
 		strlcpy(bus_id, start, len);
 		rc = 0;
 	} else
@@ -181,7 +191,7 @@
 	return rc;
 }
 
-static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE])
+static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE])
 {
 	int cssid, ssid, devno;
 
@@ -213,7 +223,7 @@
 {
 	struct ccwgroup_device *gdev;
 	int rc, i;
-	char tmp_bus_id[BUS_ID_SIZE];
+	char tmp_bus_id[CCW_BUS_ID_SIZE];
 	const char *curr_buf;
 
 	gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 29826fd..ebab6ea 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -8,6 +8,9 @@
  *		 Arnd Bergmann (arndb@de.ibm.com)
  */
 
+#define KMSG_COMPONENT "cio"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -333,6 +336,7 @@
 	struct chp_config_data *data;
 	struct chp_id chpid;
 	int num;
+	char *events[3] = {"configure", "deconfigure", "cancel deconfigure"};
 
 	CIO_CRW_EVENT(4, "chsc: channel-path-configuration notification\n");
 	if (sei_area->rs != 0)
@@ -343,8 +347,8 @@
 		if (!chp_test_bit(data->map, num))
 			continue;
 		chpid.id = num;
-		printk(KERN_WARNING "cio: processing configure event %d for "
-		       "chpid %x.%02x\n", data->op, chpid.cssid, chpid.id);
+		pr_notice("Processing %s for channel path %x.%02x\n",
+			  events[data->op], chpid.cssid, chpid.id);
 		switch (data->op) {
 		case 0:
 			chp_cfg_schedule(chpid, 1);
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index f49f0e5..0a2f2ed 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -61,7 +61,7 @@
 	}
 	private->request = NULL;
 	memcpy(&request->irb, irb, sizeof(*irb));
-	stsch(sch->schid, &sch->schib);
+	cio_update_schib(sch);
 	complete(&request->completion);
 	put_device(&sch->dev);
 }
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 3db2c38..8a8df75 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -9,6 +9,9 @@
  *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
+#define KMSG_COMPONENT "cio"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -104,44 +107,6 @@
        return flags;
 }
 
-/*
- * Use tpi to get a pending interrupt, call the interrupt handler and
- * return a pointer to the subchannel structure.
- */
-static int
-cio_tpi(void)
-{
-	struct tpi_info *tpi_info;
-	struct subchannel *sch;
-	struct irb *irb;
-	int irq_context;
-
-	tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID;
-	if (tpi (NULL) != 1)
-		return 0;
-	irb = (struct irb *) __LC_IRB;
-	/* Store interrupt response block to lowcore. */
-	if (tsch (tpi_info->schid, irb) != 0)
-		/* Not status pending or not operational. */
-		return 1;
-	sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
-	if (!sch)
-		return 1;
-	irq_context = in_interrupt();
-	if (!irq_context)
-		local_bh_disable();
-	irq_enter ();
-	spin_lock(sch->lock);
-	memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
-	if (sch->driver && sch->driver->irq)
-		sch->driver->irq(sch);
-	spin_unlock(sch->lock);
-	irq_exit ();
-	if (!irq_context)
-		_local_bh_enable();
-	return 1;
-}
-
 static int
 cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
 {
@@ -152,11 +117,13 @@
 	else
 		sch->lpm = 0;
 
-	stsch (sch->schid, &sch->schib);
-
 	CIO_MSG_EVENT(2, "cio_start: 'not oper' status for "
 		      "subchannel 0.%x.%04x!\n", sch->schid.ssid,
 		      sch->schid.sch_no);
+
+	if (cio_update_schib(sch))
+		return -ENODEV;
+
 	sprintf(dbf_text, "no%s", dev_name(&sch->dev));
 	CIO_TRACE_EVENT(0, dbf_text);
 	CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
@@ -354,7 +321,8 @@
 	switch (ccode) {
 	case 0:		/* success */
 		/* Update information in scsw. */
-		stsch (sch->schid, &sch->schib);
+		if (cio_update_schib(sch))
+			return -ENODEV;
 		return 0;
 	case 1:		/* status pending */
 		return -EBUSY;
@@ -365,30 +333,70 @@
 	}
 }
 
-/*
- * Function: cio_modify
- * Issues a "Modify Subchannel" on the specified subchannel
- */
-int
-cio_modify (struct subchannel *sch)
-{
-	int ccode, retry, ret;
 
-	ret = 0;
+static void cio_apply_config(struct subchannel *sch, struct schib *schib)
+{
+	schib->pmcw.intparm = sch->config.intparm;
+	schib->pmcw.mbi = sch->config.mbi;
+	schib->pmcw.isc = sch->config.isc;
+	schib->pmcw.ena = sch->config.ena;
+	schib->pmcw.mme = sch->config.mme;
+	schib->pmcw.mp = sch->config.mp;
+	schib->pmcw.csense = sch->config.csense;
+	schib->pmcw.mbfc = sch->config.mbfc;
+	if (sch->config.mbfc)
+		schib->mba = sch->config.mba;
+}
+
+static int cio_check_config(struct subchannel *sch, struct schib *schib)
+{
+	return (schib->pmcw.intparm == sch->config.intparm) &&
+		(schib->pmcw.mbi == sch->config.mbi) &&
+		(schib->pmcw.isc == sch->config.isc) &&
+		(schib->pmcw.ena == sch->config.ena) &&
+		(schib->pmcw.mme == sch->config.mme) &&
+		(schib->pmcw.mp == sch->config.mp) &&
+		(schib->pmcw.csense == sch->config.csense) &&
+		(schib->pmcw.mbfc == sch->config.mbfc) &&
+		(!sch->config.mbfc || (schib->mba == sch->config.mba));
+}
+
+/*
+ * cio_commit_config - apply configuration to the subchannel
+ */
+int cio_commit_config(struct subchannel *sch)
+{
+	struct schib schib;
+	int ccode, retry, ret = 0;
+
+	if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
+		return -ENODEV;
+
 	for (retry = 0; retry < 5; retry++) {
-		ccode = msch_err (sch->schid, &sch->schib);
-		if (ccode < 0)	/* -EIO if msch gets a program check. */
+		/* copy desired changes to local schib */
+		cio_apply_config(sch, &schib);
+		ccode = msch_err(sch->schid, &schib);
+		if (ccode < 0) /* -EIO if msch gets a program check. */
 			return ccode;
 		switch (ccode) {
 		case 0: /* successfull */
-			return 0;
-		case 1:	/* status pending */
+			if (stsch(sch->schid, &schib) ||
+			    !css_sch_is_valid(&schib))
+				return -ENODEV;
+			if (cio_check_config(sch, &schib)) {
+				/* commit changes from local schib */
+				memcpy(&sch->schib, &schib, sizeof(schib));
+				return 0;
+			}
+			ret = -EAGAIN;
+			break;
+		case 1: /* status pending */
 			return -EBUSY;
-		case 2:	/* busy */
-			udelay (100);	/* allow for recovery */
+		case 2: /* busy */
+			udelay(100); /* allow for recovery */
 			ret = -EBUSY;
 			break;
-		case 3:	/* not operational */
+		case 3: /* not operational */
 			return -ENODEV;
 		}
 	}
@@ -396,6 +404,23 @@
 }
 
 /**
+ * cio_update_schib - Perform stsch and update schib if subchannel is valid.
+ * @sch: subchannel on which to perform stsch
+ * Return zero on success, -ENODEV otherwise.
+ */
+int cio_update_schib(struct subchannel *sch)
+{
+	struct schib schib;
+
+	if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
+		return -ENODEV;
+
+	memcpy(&sch->schib, &schib, sizeof(schib));
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cio_update_schib);
+
+/**
  * cio_enable_subchannel - enable a subchannel.
  * @sch: subchannel to be enabled
  * @intparm: interruption parameter to set
@@ -403,7 +428,6 @@
 int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
 {
 	char dbf_txt[15];
-	int ccode;
 	int retry;
 	int ret;
 
@@ -412,33 +436,27 @@
 
 	if (sch_is_pseudo_sch(sch))
 		return -EINVAL;
-	ccode = stsch (sch->schid, &sch->schib);
-	if (ccode)
+	if (cio_update_schib(sch))
 		return -ENODEV;
 
-	for (retry = 5, ret = 0; retry > 0; retry--) {
-		sch->schib.pmcw.ena = 1;
-		sch->schib.pmcw.isc = sch->isc;
-		sch->schib.pmcw.intparm = intparm;
-		ret = cio_modify(sch);
-		if (ret == -ENODEV)
-			break;
-		if (ret == -EIO)
+	sch->config.ena = 1;
+	sch->config.isc = sch->isc;
+	sch->config.intparm = intparm;
+
+	for (retry = 0; retry < 3; retry++) {
+		ret = cio_commit_config(sch);
+		if (ret == -EIO) {
 			/*
-			 * Got a program check in cio_modify. Try without
+			 * Got a program check in msch. Try without
 			 * the concurrent sense bit the next time.
 			 */
-			sch->schib.pmcw.csense = 0;
-		if (ret == 0) {
-			stsch (sch->schid, &sch->schib);
-			if (sch->schib.pmcw.ena)
-				break;
-		}
-		if (ret == -EBUSY) {
+			sch->config.csense = 0;
+		} else if (ret == -EBUSY) {
 			struct irb irb;
 			if (tsch(sch->schid, &irb) != 0)
 				break;
-		}
+		} else
+			break;
 	}
 	sprintf (dbf_txt, "ret:%d", ret);
 	CIO_TRACE_EVENT (2, dbf_txt);
@@ -453,8 +471,6 @@
 int cio_disable_subchannel(struct subchannel *sch)
 {
 	char dbf_txt[15];
-	int ccode;
-	int retry;
 	int ret;
 
 	CIO_TRACE_EVENT (2, "dissch");
@@ -462,8 +478,7 @@
 
 	if (sch_is_pseudo_sch(sch))
 		return 0;
-	ccode = stsch (sch->schid, &sch->schib);
-	if (ccode == 3)		/* Not operational. */
+	if (cio_update_schib(sch))
 		return -ENODEV;
 
 	if (scsw_actl(&sch->schib.scsw) != 0)
@@ -473,24 +488,9 @@
 		 */
 		return -EBUSY;
 
-	for (retry = 5, ret = 0; retry > 0; retry--) {
-		sch->schib.pmcw.ena = 0;
-		ret = cio_modify(sch);
-		if (ret == -ENODEV)
-			break;
-		if (ret == -EBUSY)
-			/*
-			 * The subchannel is busy or status pending.
-			 * We'll disable when the next interrupt was delivered
-			 * via the state machine.
-			 */
-			break;
-		if (ret == 0) {
-			stsch (sch->schid, &sch->schib);
-			if (!sch->schib.pmcw.ena)
-				break;
-		}
-	}
+	sch->config.ena = 0;
+	ret = cio_commit_config(sch);
+
 	sprintf (dbf_txt, "ret:%d", ret);
 	CIO_TRACE_EVENT (2, dbf_txt);
 	return ret;
@@ -687,6 +687,43 @@
 static struct io_subchannel_private console_priv;
 static int console_subchannel_in_use;
 
+/*
+ * Use tpi to get a pending interrupt, call the interrupt handler and
+ * return a pointer to the subchannel structure.
+ */
+static int cio_tpi(void)
+{
+	struct tpi_info *tpi_info;
+	struct subchannel *sch;
+	struct irb *irb;
+	int irq_context;
+
+	tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID;
+	if (tpi(NULL) != 1)
+		return 0;
+	irb = (struct irb *) __LC_IRB;
+	/* Store interrupt response block to lowcore. */
+	if (tsch(tpi_info->schid, irb) != 0)
+		/* Not status pending or not operational. */
+		return 1;
+	sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
+	if (!sch)
+		return 1;
+	irq_context = in_interrupt();
+	if (!irq_context)
+		local_bh_disable();
+	irq_enter();
+	spin_lock(sch->lock);
+	memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
+	if (sch->driver && sch->driver->irq)
+		sch->driver->irq(sch);
+	spin_unlock(sch->lock);
+	irq_exit();
+	if (!irq_context)
+		_local_bh_enable();
+	return 1;
+}
+
 void *cio_get_console_priv(void)
 {
 	return &console_priv;
@@ -780,7 +817,7 @@
 	sch_no = cio_get_console_sch_no();
 	if (sch_no == -1) {
 		console_subchannel_in_use = 0;
-		printk(KERN_WARNING "cio: No ccw console found!\n");
+		pr_warning("No CCW console was found\n");
 		return ERR_PTR(-ENODEV);
 	}
 	memset(&console_subchannel, 0, sizeof(struct subchannel));
@@ -796,10 +833,9 @@
 	 * enable console I/O-interrupt subclass
 	 */
 	isc_register(CONSOLE_ISC);
-	console_subchannel.schib.pmcw.isc = CONSOLE_ISC;
-	console_subchannel.schib.pmcw.intparm =
-		(u32)(addr_t)&console_subchannel;
-	ret = cio_modify(&console_subchannel);
+	console_subchannel.config.isc = CONSOLE_ISC;
+	console_subchannel.config.intparm = (u32)(addr_t)&console_subchannel;
+	ret = cio_commit_config(&console_subchannel);
 	if (ret) {
 		isc_unregister(CONSOLE_ISC);
 		console_subchannel_in_use = 0;
@@ -811,8 +847,8 @@
 void
 cio_release_console(void)
 {
-	console_subchannel.schib.pmcw.intparm = 0;
-	cio_modify(&console_subchannel);
+	console_subchannel.config.intparm = 0;
+	cio_commit_config(&console_subchannel);
 	isc_unregister(CONSOLE_ISC);
 	console_subchannel_in_use = 0;
 }
@@ -852,7 +888,8 @@
 		cc = msch(schid, schib);
 		if (cc)
 			return (cc==3?-ENODEV:-EBUSY);
-		stsch(schid, schib);
+		if (stsch(schid, schib) || !css_sch_is_valid(schib))
+			return -ENODEV;
 		if (!schib->pmcw.ena)
 			return 0;
 	}
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 0fb2478..5150fba 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -45,6 +45,19 @@
 				/*  ... in an operand exception.       */
 } __attribute__ ((packed));
 
+/* Target SCHIB configuration. */
+struct schib_config {
+	u64 mba;
+	u32 intparm;
+	u16 mbi;
+	u32 isc:3;
+	u32 ena:1;
+	u32 mme:2;
+	u32 mp:1;
+	u32 csense:1;
+	u32 mbfc:1;
+} __attribute__ ((packed));
+
 /*
  * subchannel information block
  */
@@ -82,6 +95,8 @@
 	struct device dev;	/* entry in device tree */
 	struct css_driver *driver;
 	void *private; /* private per subchannel type data */
+	struct work_struct work;
+	struct schib_config config;
 } __attribute__ ((aligned(8)));
 
 #define IO_INTERRUPT_TYPE	   0 /* I/O interrupt type */
@@ -100,7 +115,8 @@
 extern int cio_cancel (struct subchannel *);
 extern int cio_set_options (struct subchannel *, int);
 extern int cio_get_options (struct subchannel *);
-extern int cio_modify (struct subchannel *);
+extern int cio_update_schib(struct subchannel *sch);
+extern int cio_commit_config(struct subchannel *sch);
 
 int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
 int cio_tm_intrg(struct subchannel *sch);
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index a90b28c..dc98b2c 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -25,6 +25,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define KMSG_COMPONENT "cio"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/bootmem.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -185,56 +188,19 @@
 static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
 		     unsigned long address)
 {
-	int ret;
-	int retry;
 	struct subchannel *sch;
-	struct schib *schib;
 
 	sch = to_subchannel(cdev->dev.parent);
-	schib = &sch->schib;
-	/* msch can silently fail, so do it again if necessary */
-	for (retry = 0; retry < 3; retry++) {
-		/* prepare schib */
-		stsch(sch->schid, schib);
-		schib->pmcw.mme  = mme;
-		schib->pmcw.mbfc = mbfc;
-		/* address can be either a block address or a block index */
-		if (mbfc)
-			schib->mba = address;
-		else
-			schib->pmcw.mbi = address;
 
-		/* try to submit it */
-		switch(ret = msch_err(sch->schid, schib)) {
-			case 0:
-				break;
-			case 1:
-			case 2: /* in I/O or status pending */
-				ret = -EBUSY;
-				break;
-			case 3: /* subchannel is no longer valid */
-				ret = -ENODEV;
-				break;
-			default: /* msch caught an exception */
-				ret = -EINVAL;
-				break;
-		}
-		stsch(sch->schid, schib); /* restore the schib */
+	sch->config.mme = mme;
+	sch->config.mbfc = mbfc;
+	/* address can be either a block address or a block index */
+	if (mbfc)
+		sch->config.mba = address;
+	else
+		sch->config.mbi = address;
 
-		if (ret)
-			break;
-
-		/* check if it worked */
-		if (schib->pmcw.mme  == mme &&
-		    schib->pmcw.mbfc == mbfc &&
-		    (mbfc ? (schib->mba == address)
-			  : (schib->pmcw.mbi == address)))
-			return 0;
-
-		ret = -EINVAL;
-	}
-
-	return ret;
+	return cio_commit_config(sch);
 }
 
 struct set_schib_struct {
@@ -338,7 +304,7 @@
 
 	sch = to_subchannel(cdev->dev.parent);
 
-	if (stsch(sch->schid, &sch->schib))
+	if (cio_update_schib(sch))
 		return -ENODEV;
 
 	if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) {
@@ -1359,9 +1325,8 @@
 	default:
 		return 1;
 	}
-
-	printk(KERN_INFO "cio: Channel measurement facility using %s "
-	       "format (%s)\n", format_string, detect_string);
+	pr_info("Channel measurement facility initialized using format "
+		"%s (mode %s)\n", format_string, detect_string);
 	return 0;
 }
 
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 76bbb1e..8019288 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -6,6 +6,10 @@
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
  *		 Cornelia Huck (cornelia.huck@de.ibm.com)
  */
+
+#define KMSG_COMPONENT "cio"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
@@ -128,8 +132,8 @@
 {
 	if (sch) {
 		/* Reset intparm to zeroes. */
-		sch->schib.pmcw.intparm = 0;
-		cio_modify(sch);
+		sch->config.intparm = 0;
+		cio_commit_config(sch);
 		kfree(sch->lock);
 		kfree(sch);
 	}
@@ -844,8 +848,8 @@
 	s390_unregister_crw_handler(CRW_RSC_CSS);
 	chsc_free_sei_area();
 	kfree(slow_subchannel_set);
-	printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n",
-	       ret);
+	pr_alert("The CSS device driver initialization failed with "
+		 "errno=%d\n", ret);
 	return ret;
 }
 
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 4e40083..23d5752 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -376,19 +376,23 @@
 			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
 		}
 		spin_unlock_irq(cdev->ccwlock);
+		/* Give up reference from ccw_device_set_online(). */
+		put_device(&cdev->dev);
 		return ret;
 	}
 	spin_unlock_irq(cdev->ccwlock);
-	if (ret == 0)
+	if (ret == 0) {
 		wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
-	else {
+		/* Give up reference from ccw_device_set_online(). */
+		put_device(&cdev->dev);
+	} else {
 		CIO_MSG_EVENT(0, "ccw_device_offline returned %d, "
 			      "device 0.%x.%04x\n",
 			      ret, cdev->private->dev_id.ssid,
 			      cdev->private->dev_id.devno);
 		cdev->online = 1;
 	}
- 	return ret;
+	return ret;
 }
 
 /**
@@ -411,6 +415,9 @@
 		return -ENODEV;
 	if (cdev->online || !cdev->drv)
 		return -EINVAL;
+	/* Hold on to an extra reference while device is online. */
+	if (!get_device(&cdev->dev))
+		return -ENODEV;
 
 	spin_lock_irq(cdev->ccwlock);
 	ret = ccw_device_online(cdev);
@@ -422,10 +429,15 @@
 			      "device 0.%x.%04x\n",
 			      ret, cdev->private->dev_id.ssid,
 			      cdev->private->dev_id.devno);
+		/* Give up online reference since onlining failed. */
+		put_device(&cdev->dev);
 		return ret;
 	}
-	if (cdev->private->state != DEV_STATE_ONLINE)
+	if (cdev->private->state != DEV_STATE_ONLINE) {
+		/* Give up online reference since onlining failed. */
+		put_device(&cdev->dev);
 		return -ENODEV;
+	}
 	if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) {
 		cdev->online = 1;
 		return 0;
@@ -440,6 +452,8 @@
 			      "device 0.%x.%04x\n",
 			      ret, cdev->private->dev_id.ssid,
 			      cdev->private->dev_id.devno);
+	/* Give up online reference since onlining failed. */
+	put_device(&cdev->dev);
 	return (ret == 0) ? -ENODEV : ret;
 }
 
@@ -704,6 +718,8 @@
 	struct ccw_device *cdev;
 
 	cdev = to_ccwdev(dev);
+	/* Release reference of parent subchannel. */
+	put_device(cdev->dev.parent);
 	kfree(cdev->private);
 	kfree(cdev);
 }
@@ -735,8 +751,8 @@
 	/* Do first half of device_register. */
 	device_initialize(&cdev->dev);
 	if (!get_device(&sch->dev)) {
-		if (cdev->dev.release)
-			cdev->dev.release(&cdev->dev);
+		/* Release reference from device_initialize(). */
+		put_device(&cdev->dev);
 		return -ENODEV;
 	}
 	return 0;
@@ -778,37 +794,55 @@
 	struct subchannel *other_sch;
 	int ret;
 
-	other_sch = to_subchannel(get_device(cdev->dev.parent));
+	/* Get reference for new parent. */
+	if (!get_device(&sch->dev))
+		return;
+	other_sch = to_subchannel(cdev->dev.parent);
+	/* Note: device_move() changes cdev->dev.parent */
 	ret = device_move(&cdev->dev, &sch->dev);
 	if (ret) {
 		CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed "
 			      "(ret=%d)!\n", cdev->private->dev_id.ssid,
 			      cdev->private->dev_id.devno, ret);
-		put_device(&other_sch->dev);
+		/* Put reference for new parent. */
+		put_device(&sch->dev);
 		return;
 	}
 	sch_set_cdev(other_sch, NULL);
 	/* No need to keep a subchannel without ccw device around. */
 	css_sch_device_unregister(other_sch);
-	put_device(&other_sch->dev);
 	sch_attach_device(sch, cdev);
+	/* Put reference for old parent. */
+	put_device(&other_sch->dev);
 }
 
 static void sch_attach_orphaned_device(struct subchannel *sch,
 				       struct ccw_device *cdev)
 {
 	int ret;
+	struct subchannel *pseudo_sch;
 
-	/* Try to move the ccw device to its new subchannel. */
+	/* Get reference for new parent. */
+	if (!get_device(&sch->dev))
+		return;
+	pseudo_sch = to_subchannel(cdev->dev.parent);
+	/*
+	 * Try to move the ccw device to its new subchannel.
+	 * Note: device_move() changes cdev->dev.parent
+	 */
 	ret = device_move(&cdev->dev, &sch->dev);
 	if (ret) {
 		CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage "
 			      "failed (ret=%d)!\n",
 			      cdev->private->dev_id.ssid,
 			      cdev->private->dev_id.devno, ret);
+		/* Put reference for new parent. */
+		put_device(&sch->dev);
 		return;
 	}
 	sch_attach_device(sch, cdev);
+	/* Put reference on pseudo subchannel. */
+	put_device(&pseudo_sch->dev);
 }
 
 static void sch_create_and_recog_new_device(struct subchannel *sch)
@@ -830,9 +864,11 @@
 		spin_lock_irq(sch->lock);
 		sch_set_cdev(sch, NULL);
 		spin_unlock_irq(sch->lock);
-		if (cdev->dev.release)
-			cdev->dev.release(&cdev->dev);
 		css_sch_device_unregister(sch);
+		/* Put reference from io_subchannel_create_ccwdev(). */
+		put_device(&sch->dev);
+		/* Give up initial reference. */
+		put_device(&cdev->dev);
 	}
 }
 
@@ -854,15 +890,20 @@
 	dev_id.devno = sch->schib.pmcw.dev;
 	dev_id.ssid = sch->schid.ssid;
 
+	/* Increase refcount for pseudo subchannel. */
+	get_device(&css->pseudo_subchannel->dev);
 	/*
 	 * Move the orphaned ccw device to the orphanage so the replacing
 	 * ccw device can take its place on the subchannel.
+	 * Note: device_move() changes cdev->dev.parent
 	 */
 	ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev);
 	if (ret) {
 		CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed "
 			      "(ret=%d)!\n", cdev->private->dev_id.ssid,
 			      cdev->private->dev_id.devno, ret);
+		/* Decrease refcount for pseudo subchannel again. */
+		put_device(&css->pseudo_subchannel->dev);
 		return;
 	}
 	cdev->ccwlock = css->pseudo_subchannel->lock;
@@ -875,17 +916,23 @@
 	if (replacing_cdev) {
 		sch_attach_disconnected_device(sch, replacing_cdev);
 		/* Release reference from get_disc_ccwdev_by_dev_id() */
-		put_device(&cdev->dev);
+		put_device(&replacing_cdev->dev);
+		/* Release reference of subchannel from old cdev. */
+		put_device(&sch->dev);
 		return;
 	}
 	replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id);
 	if (replacing_cdev) {
 		sch_attach_orphaned_device(sch, replacing_cdev);
 		/* Release reference from get_orphaned_ccwdev_by_dev_id() */
-		put_device(&cdev->dev);
+		put_device(&replacing_cdev->dev);
+		/* Release reference of subchannel from old cdev. */
+		put_device(&sch->dev);
 		return;
 	}
 	sch_create_and_recog_new_device(sch);
+	/* Release reference of subchannel from old cdev. */
+	put_device(&sch->dev);
 }
 
 /*
@@ -903,6 +950,14 @@
 	priv = container_of(work, struct ccw_device_private, kick_work);
 	cdev = priv->cdev;
 	sch = to_subchannel(cdev->dev.parent);
+	/*
+	 * Check if subchannel is still registered. It may have become
+	 * unregistered if a machine check hit us after finishing
+	 * device recognition but before the register work could be
+	 * queued.
+	 */
+	if (!device_is_registered(&sch->dev))
+		goto out_err;
 	css_update_ssd_info(sch);
 	/*
 	 * io_subchannel_register() will also be called after device
@@ -910,7 +965,7 @@
 	 * be registered). We need to reprobe since we may now have sense id
 	 * information.
 	 */
-	if (klist_node_attached(&cdev->dev.knode_parent)) {
+	if (device_is_registered(&cdev->dev)) {
 		if (!cdev->drv) {
 			ret = device_reprobe(&cdev->dev);
 			if (ret)
@@ -934,22 +989,19 @@
 		CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n",
 			      cdev->private->dev_id.ssid,
 			      cdev->private->dev_id.devno, ret);
-		put_device(&cdev->dev);
 		spin_lock_irqsave(sch->lock, flags);
 		sch_set_cdev(sch, NULL);
 		spin_unlock_irqrestore(sch->lock, flags);
-		kfree (cdev->private);
-		kfree (cdev);
-		put_device(&sch->dev);
-		if (atomic_dec_and_test(&ccw_device_init_count))
-			wake_up(&ccw_device_init_wq);
-		return;
+		/* Release initial device reference. */
+		put_device(&cdev->dev);
+		goto out_err;
 	}
-	put_device(&cdev->dev);
 out:
 	cdev->private->flags.recog_done = 1;
-	put_device(&sch->dev);
 	wake_up(&cdev->private->wait_q);
+out_err:
+	/* Release reference for workqueue processing. */
+	put_device(&cdev->dev);
 	if (atomic_dec_and_test(&ccw_device_init_count))
 		wake_up(&ccw_device_init_wq);
 }
@@ -968,8 +1020,8 @@
 	sch = to_subchannel(cdev->dev.parent);
 	css_sch_device_unregister(sch);
 	/* Reset intparm to zeroes. */
-	sch->schib.pmcw.intparm = 0;
-	cio_modify(sch);
+	sch->config.intparm = 0;
+	cio_commit_config(sch);
 	/* Release cdev reference for workqueue processing.*/
 	put_device(&cdev->dev);
 	/* Release subchannel reference for local processing. */
@@ -998,8 +1050,6 @@
 		PREPARE_WORK(&cdev->private->kick_work,
 			     ccw_device_call_sch_unregister);
 		queue_work(slow_path_wq, &cdev->private->kick_work);
-		/* Release subchannel reference for asynchronous recognition. */
-		put_device(&sch->dev);
 		if (atomic_dec_and_test(&ccw_device_init_count))
 			wake_up(&ccw_device_init_wq);
 		break;
@@ -1070,10 +1120,15 @@
 	priv = container_of(work, struct ccw_device_private, kick_work);
 	sch = priv->sch;
 	cdev = priv->cdev;
-	former_parent = ccw_device_is_orphan(cdev) ?
-		NULL : to_subchannel(get_device(cdev->dev.parent));
+	former_parent = to_subchannel(cdev->dev.parent);
+	/* Get reference for new parent. */
+	if (!get_device(&sch->dev))
+		return;
 	mutex_lock(&sch->reg_mutex);
-	/* Try to move the ccw device to its new subchannel. */
+	/*
+	 * Try to move the ccw device to its new subchannel.
+	 * Note: device_move() changes cdev->dev.parent
+	 */
 	rc = device_move(&cdev->dev, &sch->dev);
 	mutex_unlock(&sch->reg_mutex);
 	if (rc) {
@@ -1083,21 +1138,23 @@
 			      cdev->private->dev_id.devno, sch->schid.ssid,
 			      sch->schid.sch_no, rc);
 		css_sch_device_unregister(sch);
+		/* Put reference for new parent again. */
+		put_device(&sch->dev);
 		goto out;
 	}
-	if (former_parent) {
+	if (!sch_is_pseudo_sch(former_parent)) {
 		spin_lock_irq(former_parent->lock);
 		sch_set_cdev(former_parent, NULL);
 		spin_unlock_irq(former_parent->lock);
 		css_sch_device_unregister(former_parent);
 		/* Reset intparm to zeroes. */
-		former_parent->schib.pmcw.intparm = 0;
-		cio_modify(former_parent);
+		former_parent->config.intparm = 0;
+		cio_commit_config(former_parent);
 	}
 	sch_attach_device(sch, cdev);
 out:
-	if (former_parent)
-		put_device(&former_parent->dev);
+	/* Put reference for old parent. */
+	put_device(&former_parent->dev);
 	put_device(&cdev->dev);
 }
 
@@ -1113,6 +1170,15 @@
 		dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
 }
 
+void io_subchannel_init_config(struct subchannel *sch)
+{
+	memset(&sch->config, 0, sizeof(sch->config));
+	sch->config.csense = 1;
+	/* Use subchannel mp mode when there is more than 1 installed CHPID. */
+	if ((sch->schib.pmcw.pim & (sch->schib.pmcw.pim - 1)) != 0)
+		sch->config.mp = 1;
+}
+
 static void io_subchannel_init_fields(struct subchannel *sch)
 {
 	if (cio_is_console(sch->schid))
@@ -1127,18 +1193,34 @@
 		      sch->schib.pmcw.dev, sch->schid.ssid,
 		      sch->schid.sch_no, sch->schib.pmcw.pim,
 		      sch->schib.pmcw.pam, sch->schib.pmcw.pom);
-	/* Initially set up some fields in the pmcw. */
-	sch->schib.pmcw.ena = 0;
-	sch->schib.pmcw.csense = 1;	/* concurrent sense */
-	if ((sch->lpm & (sch->lpm - 1)) != 0)
-		sch->schib.pmcw.mp = 1; /* multipath mode */
-	/* clean up possible residual cmf stuff */
-	sch->schib.pmcw.mme = 0;
-	sch->schib.pmcw.mbfc = 0;
-	sch->schib.pmcw.mbi = 0;
-	sch->schib.mba = 0;
+
+	io_subchannel_init_config(sch);
 }
 
+static void io_subchannel_do_unreg(struct work_struct *work)
+{
+	struct subchannel *sch;
+
+	sch = container_of(work, struct subchannel, work);
+	css_sch_device_unregister(sch);
+	/* Reset intparm to zeroes. */
+	sch->config.intparm = 0;
+	cio_commit_config(sch);
+	put_device(&sch->dev);
+}
+
+/* Schedule unregister if we have no cdev. */
+static void io_subchannel_schedule_removal(struct subchannel *sch)
+{
+	get_device(&sch->dev);
+	INIT_WORK(&sch->work, io_subchannel_do_unreg);
+	queue_work(slow_path_wq, &sch->work);
+}
+
+/*
+ * Note: We always return 0 so that we bind to the device even on error.
+ * This is needed so that our remove function is called on unregister.
+ */
 static int io_subchannel_probe(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
@@ -1168,9 +1250,8 @@
 		ccw_device_register(cdev);
 		/*
 		 * Check if the device is already online. If it is
-		 * the reference count needs to be corrected
-		 * (see ccw_device_online and css_init_done for the
-		 * ugly details).
+		 * the reference count needs to be corrected since we
+		 * didn't obtain a reference in ccw_device_set_online.
 		 */
 		if (cdev->private->state != DEV_STATE_NOT_OPER &&
 		    cdev->private->state != DEV_STATE_OFFLINE &&
@@ -1179,23 +1260,24 @@
 		return 0;
 	}
 	io_subchannel_init_fields(sch);
+	rc = cio_commit_config(sch);
+	if (rc)
+		goto out_schedule;
+	rc = sysfs_create_group(&sch->dev.kobj,
+				&io_subchannel_attr_group);
+	if (rc)
+		goto out_schedule;
+	/* Allocate I/O subchannel private data. */
+	sch->private = kzalloc(sizeof(struct io_subchannel_private),
+			       GFP_KERNEL | GFP_DMA);
+	if (!sch->private)
+		goto out_err;
 	/*
 	 * First check if a fitting device may be found amongst the
 	 * disconnected devices or in the orphanage.
 	 */
 	dev_id.devno = sch->schib.pmcw.dev;
 	dev_id.ssid = sch->schid.ssid;
-	rc = sysfs_create_group(&sch->dev.kobj,
-				&io_subchannel_attr_group);
-	if (rc)
-		return rc;
-	/* Allocate I/O subchannel private data. */
-	sch->private = kzalloc(sizeof(struct io_subchannel_private),
-			       GFP_KERNEL | GFP_DMA);
-	if (!sch->private) {
-		rc = -ENOMEM;
-		goto out_err;
-	}
 	cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
 	if (!cdev)
 		cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
@@ -1213,24 +1295,21 @@
 		return 0;
 	}
 	cdev = io_subchannel_create_ccwdev(sch);
-	if (IS_ERR(cdev)) {
-		rc = PTR_ERR(cdev);
+	if (IS_ERR(cdev))
 		goto out_err;
-	}
 	rc = io_subchannel_recog(cdev, sch);
 	if (rc) {
 		spin_lock_irqsave(sch->lock, flags);
-		sch_set_cdev(sch, NULL);
+		io_subchannel_recog_done(cdev);
 		spin_unlock_irqrestore(sch->lock, flags);
-		if (cdev->dev.release)
-			cdev->dev.release(&cdev->dev);
-		goto out_err;
 	}
 	return 0;
 out_err:
 	kfree(sch->private);
 	sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
-	return rc;
+out_schedule:
+	io_subchannel_schedule_removal(sch);
+	return 0;
 }
 
 static int
@@ -1275,10 +1354,7 @@
 
 static int check_for_io_on_path(struct subchannel *sch, int mask)
 {
-	int cc;
-
-	cc = stsch(sch->schid, &sch->schib);
-	if (cc)
+	if (cio_update_schib(sch))
 		return 0;
 	if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask)
 		return 1;
@@ -1347,15 +1423,13 @@
 		io_subchannel_verify(sch);
 		break;
 	case CHP_OFFLINE:
-		if (stsch(sch->schid, &sch->schib))
-			return -ENXIO;
-		if (!css_sch_is_valid(&sch->schib))
+		if (cio_update_schib(sch))
 			return -ENODEV;
 		io_subchannel_terminate_path(sch, mask);
 		break;
 	case CHP_ONLINE:
-		if (stsch(sch->schid, &sch->schib))
-			return -ENXIO;
+		if (cio_update_schib(sch))
+			return -ENODEV;
 		sch->lpm |= mask & sch->opm;
 		io_subchannel_verify(sch);
 		break;
@@ -1610,8 +1684,8 @@
 		spin_lock_irqsave(sch->lock, flags);
 
 		/* Reset intparm to zeroes. */
-		sch->schib.pmcw.intparm = 0;
-		cio_modify(sch);
+		sch->config.intparm = 0;
+		cio_commit_config(sch);
 		break;
 	case REPROBE:
 		ccw_device_trigger_reprobe(cdev);
@@ -1652,6 +1726,9 @@
 	sch->private = cio_get_console_priv();
 	memset(sch->private, 0, sizeof(struct io_subchannel_private));
 	io_subchannel_init_fields(sch);
+	rc = cio_commit_config(sch);
+	if (rc)
+		return rc;
 	sch->driver = &io_subchannel_driver;
 	/* Initialize the ccw_device structure. */
 	cdev->dev.parent= &sch->dev;
@@ -1723,7 +1800,7 @@
 
 	bus_id = id;
 
-	return (strncmp(bus_id, dev_name(dev), BUS_ID_SIZE) == 0);
+	return (strcmp(bus_id, dev_name(dev)) == 0);
 }
 
 
@@ -1806,6 +1883,8 @@
 				      "device 0.%x.%04x\n",
 				      ret, cdev->private->dev_id.ssid,
 				      cdev->private->dev_id.devno);
+		/* Give up reference obtained in ccw_device_set_online(). */
+		put_device(&cdev->dev);
 	}
 	ccw_device_set_timeout(cdev, 0);
 	cdev->drv = NULL;
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 104ed66..0f2e63e 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -76,6 +76,7 @@
 extern atomic_t ccw_device_init_count;
 
 void io_subchannel_recog_done(struct ccw_device *cdev);
+void io_subchannel_init_config(struct subchannel *sch);
 
 int ccw_device_cancel_halt_clear(struct ccw_device *);
 
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 10bc039..8df5eaa 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -140,8 +140,7 @@
 	int ret;
 
 	sch = to_subchannel(cdev->dev.parent);
-	ret = stsch(sch->schid, &sch->schib);
-	if (ret || !sch->schib.pmcw.dnv)
+	if (cio_update_schib(sch))
 		return -ENODEV; 
 	if (!sch->schib.pmcw.ena)
 		/* Not operational -> done. */
@@ -245,11 +244,13 @@
 	 * through ssch() and the path information is up to date.
 	 */
 	old_lpm = sch->lpm;
-	stsch(sch->schid, &sch->schib);
-	sch->lpm = sch->schib.pmcw.pam & sch->opm;
+
 	/* Check since device may again have become not operational. */
-	if (!sch->schib.pmcw.dnv)
+	if (cio_update_schib(sch))
 		state = DEV_STATE_NOT_OPER;
+	else
+		sch->lpm = sch->schib.pmcw.pam & sch->opm;
+
 	if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID)
 		/* Force reprobe on all chpids. */
 		old_lpm = 0;
@@ -399,9 +400,6 @@
 		ccw_device_oper_notify(cdev);
 	}
 	wake_up(&cdev->private->wait_q);
-
-	if (css_init_done && state != DEV_STATE_ONLINE)
-		put_device (&cdev->dev);
 }
 
 static int cmp_pgid(struct pgid *p1, struct pgid *p2)
@@ -552,7 +550,11 @@
 
 	sch = to_subchannel(cdev->dev.parent);
 	/* Update schib - pom may have changed. */
-	stsch(sch->schid, &sch->schib);
+	if (cio_update_schib(sch)) {
+		cdev->private->flags.donotify = 0;
+		ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+		return;
+	}
 	/* Update lpm with verified path mask. */
 	sch->lpm = sch->vpm;
 	/* Repeat path verification? */
@@ -611,8 +613,6 @@
 	    (cdev->private->state != DEV_STATE_BOXED))
 		return -EINVAL;
 	sch = to_subchannel(cdev->dev.parent);
-	if (css_init_done && !get_device(&cdev->dev))
-		return -ENODEV;
 	ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
 	if (ret != 0) {
 		/* Couldn't enable the subchannel for i/o. Sick device. */
@@ -672,7 +672,7 @@
 		return 0;
 	}
 	sch = to_subchannel(cdev->dev.parent);
-	if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv)
+	if (cio_update_schib(sch))
 		return -ENODEV;
 	if (scsw_actl(&sch->schib.scsw) != 0)
 		return -EBUSY;
@@ -750,7 +750,10 @@
 	 * Since we might not just be coming from an interrupt from the
 	 * subchannel we have to update the schib.
 	 */
-	stsch(sch->schid, &sch->schib);
+	if (cio_update_schib(sch)) {
+		ccw_device_verify_done(cdev, -ENODEV);
+		return;
+	}
 
 	if (scsw_actl(&sch->schib.scsw) != 0 ||
 	    (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) ||
@@ -1016,20 +1019,21 @@
 
 	sch = to_subchannel(cdev->dev.parent);
 	/* Update some values. */
-	if (stsch(sch->schid, &sch->schib))
-		return;
-	if (!sch->schib.pmcw.dnv)
+	if (cio_update_schib(sch))
 		return;
 	/*
 	 * The pim, pam, pom values may not be accurate, but they are the best
 	 * we have before performing device selection :/
 	 */
 	sch->lpm = sch->schib.pmcw.pam & sch->opm;
-	/* Re-set some bits in the pmcw that were lost. */
-	sch->schib.pmcw.csense = 1;
-	sch->schib.pmcw.ena = 0;
-	if ((sch->lpm & (sch->lpm - 1)) != 0)
-		sch->schib.pmcw.mp = 1;
+	/*
+	 * Use the initial configuration since we can't be shure that the old
+	 * paths are valid.
+	 */
+	io_subchannel_init_config(sch);
+	if (cio_commit_config(sch))
+		return;
+
 	/* We should also udate ssd info, but this has to wait. */
 	/* Check if this is another device which appeared on the same sch. */
 	if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 86bc94e..fc5ca1d 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -504,7 +504,7 @@
 	sch->vpm = 0;
 
 	/* Get current pam. */
-	if (stsch(sch->schid, &sch->schib)) {
+	if (cio_update_schib(sch)) {
 		ccw_device_verify_done(cdev, -ENODEV);
 		return;
 	}
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index 1b03c54..5814dbe 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -56,7 +56,8 @@
 	struct subchannel *sch;
 
 	sch = to_subchannel(cdev->dev.parent);
-	stsch (sch->schid, &sch->schib);
+	if (cio_update_schib(sch))
+		goto doverify;
 
 	CIO_MSG_EVENT(0, "%s(0.%x.%04x) - path(s) %02x are "
 		      "not operational \n", __func__,
@@ -64,6 +65,7 @@
 		      sch->schib.pmcw.pnom);
 
 	sch->lpm &= ~sch->schib.pmcw.pnom;
+doverify:
 	cdev->private->flags.doverify = 1;
 }
 
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index e3ea1d5..42f2b09 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -10,10 +10,10 @@
 
 #include <asm/page.h>
 #include <asm/schid.h>
+#include <asm/debug.h>
 #include "chsc.h"
 
 #define QDIO_BUSY_BIT_PATIENCE		100	/* 100 microseconds */
-#define QDIO_BUSY_BIT_GIVE_UP		2000000	/* 2 seconds = eternity */
 #define QDIO_INPUT_THRESHOLD		500	/* 500 microseconds */
 
 /*
@@ -111,12 +111,12 @@
 }
 
 static inline int do_eqbs(u64 token, unsigned char *state, int queue,
-			  int *start, int *count)
+			  int *start, int *count, int ack)
 {
 	register unsigned long _ccq asm ("0") = *count;
 	register unsigned long _token asm ("1") = token;
 	unsigned long _queuestart = ((unsigned long)queue << 32) | *start;
-	unsigned long _state = 0;
+	unsigned long _state = (unsigned long)ack << 63;
 
 	asm volatile(
 		"	.insn	rrf,0xB99c0000,%1,%2,0,0"
@@ -133,7 +133,7 @@
 static inline int do_sqbs(u64 token, unsigned char state, int queue,
 			  int *start, int *count) { return 0; }
 static inline int do_eqbs(u64 token, unsigned char *state, int queue,
-			  int *start, int *count) { return 0; }
+			  int *start, int *count, int ack) { return 0; }
 #endif /* CONFIG_64BIT */
 
 struct qdio_irq;
@@ -186,20 +186,14 @@
 	/* input buffer acknowledgement flag */
 	int polling;
 
+	/* how much sbals are acknowledged with qebsm */
+	int ack_count;
+
 	/* last time of noticing incoming data */
 	u64 timestamp;
-
-	/* lock for clearing the acknowledgement */
-	spinlock_t lock;
 };
 
 struct qdio_output_q {
-	/* failed siga-w attempts*/
-	atomic_t busy_siga_counter;
-
-	/* start time of busy condition */
-	u64 timestamp;
-
 	/* PCIs are enabled for the queue */
 	int pci_out_enabled;
 
@@ -250,6 +244,7 @@
 
 	struct qdio_irq *irq_ptr;
 	struct tasklet_struct tasklet;
+	spinlock_t lock;
 
 	/* error condition during a data transfer */
 	unsigned int qdio_error;
@@ -300,11 +295,13 @@
 	struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ];
 	struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ];
 
+	debug_info_t *debug_area;
 	struct mutex setup_mutex;
 };
 
 /* helper functions */
 #define queue_type(q)	q->irq_ptr->qib.qfmt
+#define SCH_NO(q)	(q->irq_ptr->schid.sch_no)
 
 #define is_thinint_irq(irq) \
 	(irq->qib.qfmt == QDIO_IQDIO_QFMT || \
@@ -348,10 +345,13 @@
 	((bufnr + 1) & QDIO_MAX_BUFFERS_MASK)
 #define add_buf(bufnr, inc) \
 	((bufnr + inc) & QDIO_MAX_BUFFERS_MASK)
+#define sub_buf(bufnr, dec) \
+	((bufnr - dec) & QDIO_MAX_BUFFERS_MASK)
 
 /* prototypes for thin interrupt */
 void qdio_sync_after_thinint(struct qdio_q *q);
-int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state);
+int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state,
+		  int auto_ack);
 void qdio_check_outbound_after_thinint(struct qdio_q *q);
 int qdio_inbound_q_moved(struct qdio_q *q);
 void qdio_kick_inbound_handler(struct qdio_q *q);
@@ -378,10 +378,15 @@
 int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs,
 		     int nr_output_qs);
 void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr);
+int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr,
+			struct subchannel_id *schid,
+			struct qdio_ssqd_desc *data);
 int qdio_setup_irq(struct qdio_initialize *init_data);
 void qdio_print_subchannel_info(struct qdio_irq *irq_ptr,
 				struct ccw_device *cdev);
 void qdio_release_memory(struct qdio_irq *irq_ptr);
+int qdio_setup_create_sysfs(struct ccw_device *cdev);
+void qdio_setup_destroy_sysfs(struct ccw_device *cdev);
 int qdio_setup_init(void);
 void qdio_setup_exit(void);
 
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index f055903..f8a3b69 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -14,7 +14,7 @@
 #include "qdio.h"
 
 debug_info_t *qdio_dbf_setup;
-debug_info_t *qdio_dbf_trace;
+debug_info_t *qdio_dbf_error;
 
 static struct dentry *debugfs_root;
 #define MAX_DEBUGFS_QUEUES	32
@@ -22,59 +22,33 @@
 static DEFINE_MUTEX(debugfs_mutex);
 #define QDIO_DEBUGFS_NAME_LEN	40
 
-void qdio_allocate_do_dbf(struct qdio_initialize *init_data)
+void qdio_allocate_dbf(struct qdio_initialize *init_data,
+		       struct qdio_irq *irq_ptr)
 {
-	char dbf_text[20];
+	char text[20];
 
-	sprintf(dbf_text, "qfmt:%x", init_data->q_format);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
-	QDIO_DBF_HEX0(0, setup, init_data->adapter_name, 8);
-	sprintf(dbf_text, "qpff%4x", init_data->qib_param_field_format);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
-	QDIO_DBF_HEX0(0, setup, &init_data->qib_param_field, sizeof(void *));
-	QDIO_DBF_HEX0(0, setup, &init_data->input_slib_elements, sizeof(void *));
-	QDIO_DBF_HEX0(0, setup, &init_data->output_slib_elements, sizeof(void *));
-	sprintf(dbf_text, "niq:%4x", init_data->no_input_qs);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
-	sprintf(dbf_text, "noq:%4x", init_data->no_output_qs);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
-	QDIO_DBF_HEX0(0, setup, &init_data->input_handler, sizeof(void *));
-	QDIO_DBF_HEX0(0, setup, &init_data->output_handler, sizeof(void *));
-	QDIO_DBF_HEX0(0, setup, &init_data->int_parm, sizeof(long));
-	QDIO_DBF_HEX0(0, setup, &init_data->flags, sizeof(long));
-	QDIO_DBF_HEX0(0, setup, &init_data->input_sbal_addr_array, sizeof(void *));
-	QDIO_DBF_HEX0(0, setup, &init_data->output_sbal_addr_array, sizeof(void *));
-}
+	DBF_EVENT("qfmt:%1d", init_data->q_format);
+	DBF_HEX(init_data->adapter_name, 8);
+	DBF_EVENT("qpff%4x", init_data->qib_param_field_format);
+	DBF_HEX(&init_data->qib_param_field, sizeof(void *));
+	DBF_HEX(&init_data->input_slib_elements, sizeof(void *));
+	DBF_HEX(&init_data->output_slib_elements, sizeof(void *));
+	DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs,
+		  init_data->no_output_qs);
+	DBF_HEX(&init_data->input_handler, sizeof(void *));
+	DBF_HEX(&init_data->output_handler, sizeof(void *));
+	DBF_HEX(&init_data->int_parm, sizeof(long));
+	DBF_HEX(&init_data->flags, sizeof(long));
+	DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
+	DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
+	DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
 
-static void qdio_unregister_dbf_views(void)
-{
-	if (qdio_dbf_setup)
-		debug_unregister(qdio_dbf_setup);
-	if (qdio_dbf_trace)
-		debug_unregister(qdio_dbf_trace);
-}
-
-static int qdio_register_dbf_views(void)
-{
-	qdio_dbf_setup = debug_register("qdio_setup", QDIO_DBF_SETUP_PAGES,
-					QDIO_DBF_SETUP_NR_AREAS,
-					QDIO_DBF_SETUP_LEN);
-	if (!qdio_dbf_setup)
-		goto oom;
-	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
-	debug_set_level(qdio_dbf_setup, QDIO_DBF_SETUP_LEVEL);
-
-	qdio_dbf_trace = debug_register("qdio_trace", QDIO_DBF_TRACE_PAGES,
-					QDIO_DBF_TRACE_NR_AREAS,
-					QDIO_DBF_TRACE_LEN);
-	if (!qdio_dbf_trace)
-		goto oom;
-	debug_register_view(qdio_dbf_trace, &debug_hex_ascii_view);
-	debug_set_level(qdio_dbf_trace, QDIO_DBF_TRACE_LEVEL);
-	return 0;
-oom:
-	qdio_unregister_dbf_views();
-	return -ENOMEM;
+	/* allocate trace view for the interface */
+	snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev));
+	irq_ptr->debug_area = debug_register(text, 2, 1, 16);
+	debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view);
+	debug_set_level(irq_ptr->debug_area, DBF_WARN);
+	DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
 }
 
 static int qstat_show(struct seq_file *m, void *v)
@@ -86,16 +60,18 @@
 	if (!q)
 		return 0;
 
-	seq_printf(m, "device state indicator: %d\n", *q->irq_ptr->dsci);
+	seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci);
 	seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used));
 	seq_printf(m, "ftc: %d\n", q->first_to_check);
 	seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc);
 	seq_printf(m, "polling: %d\n", q->u.in.polling);
+	seq_printf(m, "ack count: %d\n", q->u.in.ack_count);
 	seq_printf(m, "slsb buffer states:\n");
+	seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
 
 	qdio_siga_sync_q(q);
 	for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
-		get_buf_state(q, i, &state);
+		get_buf_state(q, i, &state, 0);
 		switch (state) {
 		case SLSB_P_INPUT_NOT_INIT:
 		case SLSB_P_OUTPUT_NOT_INIT:
@@ -127,6 +103,7 @@
 			seq_printf(m, "\n");
 	}
 	seq_printf(m, "\n");
+	seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
 	return 0;
 }
 
@@ -223,11 +200,24 @@
 int __init qdio_debug_init(void)
 {
 	debugfs_root = debugfs_create_dir("qdio_queues", NULL);
-	return qdio_register_dbf_views();
+
+	qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
+	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
+	debug_set_level(qdio_dbf_setup, DBF_INFO);
+	DBF_EVENT("dbf created\n");
+
+	qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
+	debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
+	debug_set_level(qdio_dbf_error, DBF_INFO);
+	DBF_ERROR("dbf created\n");
+	return 0;
 }
 
 void qdio_debug_exit(void)
 {
 	debugfs_remove(debugfs_root);
-	qdio_unregister_dbf_views();
+	if (qdio_dbf_setup)
+		debug_unregister(qdio_dbf_setup);
+	if (qdio_dbf_error)
+		debug_unregister(qdio_dbf_error);
 }
diff --git a/drivers/s390/cio/qdio_debug.h b/drivers/s390/cio/qdio_debug.h
index 5a4d85b..5d70bd1 100644
--- a/drivers/s390/cio/qdio_debug.h
+++ b/drivers/s390/cio/qdio_debug.h
@@ -12,80 +12,72 @@
 #include <asm/qdio.h>
 #include "qdio.h"
 
-#define QDIO_DBF_HEX(ex, name, level, addr, len) \
-	do { \
-	if (ex) \
-		debug_exception(qdio_dbf_##name, level, (void *)(addr), len); \
-	else \
-		debug_event(qdio_dbf_##name, level, (void *)(addr), len); \
-	} while (0)
-#define QDIO_DBF_TEXT(ex, name, level, text) \
-	do { \
-	if (ex) \
-		debug_text_exception(qdio_dbf_##name, level, text); \
-	else \
-		debug_text_event(qdio_dbf_##name, level, text); \
-	} while (0)
-
-#define QDIO_DBF_HEX0(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 0, addr, len)
-#define QDIO_DBF_HEX1(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 1, addr, len)
-#define QDIO_DBF_HEX2(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 2, addr, len)
-
-#ifdef CONFIG_QDIO_DEBUG
-#define QDIO_DBF_HEX3(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 3, addr, len)
-#define QDIO_DBF_HEX4(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 4, addr, len)
-#define QDIO_DBF_HEX5(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 5, addr, len)
-#define QDIO_DBF_HEX6(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 6, addr, len)
-#else
-#define QDIO_DBF_HEX3(ex, name, addr, len) do {} while (0)
-#define QDIO_DBF_HEX4(ex, name, addr, len) do {} while (0)
-#define QDIO_DBF_HEX5(ex, name, addr, len) do {} while (0)
-#define QDIO_DBF_HEX6(ex, name, addr, len) do {} while (0)
-#endif /* CONFIG_QDIO_DEBUG */
-
-#define QDIO_DBF_TEXT0(ex, name, text) QDIO_DBF_TEXT(ex, name, 0, text)
-#define QDIO_DBF_TEXT1(ex, name, text) QDIO_DBF_TEXT(ex, name, 1, text)
-#define QDIO_DBF_TEXT2(ex, name, text) QDIO_DBF_TEXT(ex, name, 2, text)
-
-#ifdef CONFIG_QDIO_DEBUG
-#define QDIO_DBF_TEXT3(ex, name, text) QDIO_DBF_TEXT(ex, name, 3, text)
-#define QDIO_DBF_TEXT4(ex, name, text) QDIO_DBF_TEXT(ex, name, 4, text)
-#define QDIO_DBF_TEXT5(ex, name, text) QDIO_DBF_TEXT(ex, name, 5, text)
-#define QDIO_DBF_TEXT6(ex, name, text) QDIO_DBF_TEXT(ex, name, 6, text)
-#else
-#define QDIO_DBF_TEXT3(ex, name, text) do {} while (0)
-#define QDIO_DBF_TEXT4(ex, name, text) do {} while (0)
-#define QDIO_DBF_TEXT5(ex, name, text) do {} while (0)
-#define QDIO_DBF_TEXT6(ex, name, text) do {} while (0)
-#endif /* CONFIG_QDIO_DEBUG */
-
-/* s390dbf views */
-#define QDIO_DBF_SETUP_LEN		8
-#define QDIO_DBF_SETUP_PAGES		8
-#define QDIO_DBF_SETUP_NR_AREAS		1
-
-#define QDIO_DBF_TRACE_LEN		8
-#define QDIO_DBF_TRACE_NR_AREAS		2
-
-#ifdef CONFIG_QDIO_DEBUG
-#define QDIO_DBF_TRACE_PAGES		32
-#define QDIO_DBF_SETUP_LEVEL		6
-#define QDIO_DBF_TRACE_LEVEL		4
-#else /* !CONFIG_QDIO_DEBUG */
-#define QDIO_DBF_TRACE_PAGES		8
-#define QDIO_DBF_SETUP_LEVEL		2
-#define QDIO_DBF_TRACE_LEVEL		2
-#endif /* CONFIG_QDIO_DEBUG */
+/* that gives us 15 characters in the text event views */
+#define QDIO_DBF_LEN	16
 
 extern debug_info_t *qdio_dbf_setup;
-extern debug_info_t *qdio_dbf_trace;
+extern debug_info_t *qdio_dbf_error;
 
-void qdio_allocate_do_dbf(struct qdio_initialize *init_data);
-void debug_print_bstat(struct qdio_q *q);
+/* sort out low debug levels early to avoid wasted sprints */
+static inline int qdio_dbf_passes(debug_info_t *dbf_grp, int level)
+{
+	return (level <= dbf_grp->level);
+}
+
+#define DBF_ERR		3	/* error conditions	*/
+#define DBF_WARN	4	/* warning conditions	*/
+#define DBF_INFO	6	/* informational	*/
+
+#undef DBF_EVENT
+#undef DBF_ERROR
+#undef DBF_DEV_EVENT
+
+#define DBF_EVENT(text...) \
+	do { \
+		char debug_buffer[QDIO_DBF_LEN]; \
+		snprintf(debug_buffer, QDIO_DBF_LEN, text); \
+		debug_text_event(qdio_dbf_setup, DBF_ERR, debug_buffer); \
+	} while (0)
+
+#define DBF_HEX(addr, len) \
+	do { \
+		debug_event(qdio_dbf_setup, DBF_ERR, (void*)(addr), len); \
+	} while (0)
+
+#define DBF_ERROR(text...) \
+	do { \
+		char debug_buffer[QDIO_DBF_LEN]; \
+		snprintf(debug_buffer, QDIO_DBF_LEN, text); \
+		debug_text_event(qdio_dbf_error, DBF_ERR, debug_buffer); \
+	} while (0)
+
+#define DBF_ERROR_HEX(addr, len) \
+	do { \
+		debug_event(qdio_dbf_error, DBF_ERR, (void*)(addr), len); \
+	} while (0)
+
+
+#define DBF_DEV_EVENT(level, device, text...) \
+	do { \
+		char debug_buffer[QDIO_DBF_LEN]; \
+		if (qdio_dbf_passes(device->debug_area, level)) { \
+			snprintf(debug_buffer, QDIO_DBF_LEN, text); \
+			debug_text_event(device->debug_area, level, debug_buffer); \
+		} \
+	} while (0)
+
+#define DBF_DEV_HEX(level, device, addr, len) \
+	do { \
+		debug_event(device->debug_area, level, (void*)(addr), len); \
+	} while (0)
+
+void qdio_allocate_dbf(struct qdio_initialize *init_data,
+		       struct qdio_irq *irq_ptr);
 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr,
 			      struct ccw_device *cdev);
 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr,
 				 struct ccw_device *cdev);
 int qdio_debug_init(void);
 void qdio_debug_exit(void);
+
 #endif
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 7c86591..744f928 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -74,7 +74,7 @@
  * Note: For IQDC unicast queues only the highest priority queue is processed.
  */
 static inline int do_siga_output(unsigned long schid, unsigned long mask,
-				 u32 *bb, unsigned int fc)
+				 unsigned int *bb, unsigned int fc)
 {
 	register unsigned long __fc asm("0") = fc;
 	register unsigned long __schid asm("1") = schid;
@@ -95,8 +95,6 @@
 
 static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
 {
-	char dbf_text[15];
-
 	/* all done or next buffer state different */
 	if (ccq == 0 || ccq == 32)
 		return 0;
@@ -104,8 +102,7 @@
 	if (ccq == 96 || ccq == 97)
 		return 1;
 	/* notify devices immediately */
-	sprintf(dbf_text, "%d", ccq);
-	QDIO_DBF_TEXT2(1, trace, dbf_text);
+	DBF_ERROR("%4x ccq:%3d", SCH_NO(q), ccq);
 	return -EIO;
 }
 
@@ -115,41 +112,45 @@
  * @state: state of the extracted buffers
  * @start: buffer number to start at
  * @count: count of buffers to examine
+ * @auto_ack: automatically acknowledge buffers
  *
  * Returns the number of successfull extracted equal buffer states.
  * Stops processing if a state is different from the last buffers state.
  */
 static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
-			int start, int count)
+			int start, int count, int auto_ack)
 {
 	unsigned int ccq = 0;
 	int tmp_count = count, tmp_start = start;
 	int nr = q->nr;
 	int rc;
-	char dbf_text[15];
 
 	BUG_ON(!q->irq_ptr->sch_token);
+	qdio_perf_stat_inc(&perf_stats.debug_eqbs_all);
 
 	if (!q->is_input_q)
 		nr += q->irq_ptr->nr_input_qs;
 again:
-	ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count);
+	ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count,
+		      auto_ack);
 	rc = qdio_check_ccq(q, ccq);
 
 	/* At least one buffer was processed, return and extract the remaining
 	 * buffers later.
 	 */
-	if ((ccq == 96) && (count != tmp_count))
+	if ((ccq == 96) && (count != tmp_count)) {
+		qdio_perf_stat_inc(&perf_stats.debug_eqbs_incomplete);
 		return (count - tmp_count);
+	}
+
 	if (rc == 1) {
-		QDIO_DBF_TEXT5(1, trace, "eqAGAIN");
+		DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS again:%2d", ccq);
 		goto again;
 	}
 
 	if (rc < 0) {
-		QDIO_DBF_TEXT2(1, trace, "eqberr");
-		sprintf(dbf_text, "%2x,%2x,%d,%d", count, tmp_count, ccq, nr);
-		QDIO_DBF_TEXT2(1, trace, dbf_text);
+		DBF_ERROR("%4x EQBS ERROR", SCH_NO(q));
+		DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
 		q->handler(q->irq_ptr->cdev,
 			   QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
 			   0, -1, -1, q->irq_ptr->int_parm);
@@ -176,9 +177,12 @@
 	int tmp_count = count, tmp_start = start;
 	int nr = q->nr;
 	int rc;
-	char dbf_text[15];
+
+	if (!count)
+		return 0;
 
 	BUG_ON(!q->irq_ptr->sch_token);
+	qdio_perf_stat_inc(&perf_stats.debug_sqbs_all);
 
 	if (!q->is_input_q)
 		nr += q->irq_ptr->nr_input_qs;
@@ -186,16 +190,13 @@
 	ccq = do_sqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count);
 	rc = qdio_check_ccq(q, ccq);
 	if (rc == 1) {
-		QDIO_DBF_TEXT5(1, trace, "sqAGAIN");
+		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq);
+		qdio_perf_stat_inc(&perf_stats.debug_sqbs_incomplete);
 		goto again;
 	}
 	if (rc < 0) {
-		QDIO_DBF_TEXT3(1, trace, "sqberr");
-		sprintf(dbf_text, "%2x,%2x", count, tmp_count);
-		QDIO_DBF_TEXT3(1, trace, dbf_text);
-		sprintf(dbf_text, "%d,%d", ccq, nr);
-		QDIO_DBF_TEXT3(1, trace, dbf_text);
-
+		DBF_ERROR("%4x SQBS ERROR", SCH_NO(q));
+		DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
 		q->handler(q->irq_ptr->cdev,
 			   QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
 			   0, -1, -1, q->irq_ptr->int_parm);
@@ -207,7 +208,8 @@
 
 /* returns number of examined buffers and their common state in *state */
 static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
-				 unsigned char *state, unsigned int count)
+				 unsigned char *state, unsigned int count,
+				 int auto_ack)
 {
 	unsigned char __state = 0;
 	int i;
@@ -216,7 +218,7 @@
 	BUG_ON(count > QDIO_MAX_BUFFERS_PER_Q);
 
 	if (is_qebsm(q))
-		return qdio_do_eqbs(q, state, bufnr, count);
+		return qdio_do_eqbs(q, state, bufnr, count, auto_ack);
 
 	for (i = 0; i < count; i++) {
 		if (!__state)
@@ -230,9 +232,9 @@
 }
 
 inline int get_buf_state(struct qdio_q *q, unsigned int bufnr,
-		  unsigned char *state)
+		  unsigned char *state, int auto_ack)
 {
-	return get_buf_states(q, bufnr, state, 1);
+	return get_buf_states(q, bufnr, state, 1, auto_ack);
 }
 
 /* wrap-around safe setting of slsb states, returns number of changed buffers */
@@ -282,14 +284,12 @@
 	if (!need_siga_sync(q))
 		return 0;
 
+	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr);
 	qdio_perf_stat_inc(&perf_stats.siga_sync);
 
 	cc = do_siga_sync(q->irq_ptr->schid, output, input);
-	if (cc) {
-		QDIO_DBF_TEXT4(0, trace, "sigasync");
-		QDIO_DBF_HEX4(0, trace, &q, sizeof(void *));
-		QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *));
-	}
+	if (cc)
+		DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc);
 	return cc;
 }
 
@@ -311,50 +311,37 @@
 	return qdio_siga_sync(q, ~0U, ~0U);
 }
 
-static inline int qdio_do_siga_output(struct qdio_q *q, unsigned int *busy_bit)
+static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
 {
-	unsigned int fc = 0;
 	unsigned long schid;
+	unsigned int fc = 0;
+	u64 start_time = 0;
+	int cc;
 
-	if (q->u.out.use_enh_siga) {
+	if (q->u.out.use_enh_siga)
 		fc = 3;
-	}
-	if (!is_qebsm(q))
-		schid = *((u32 *)&q->irq_ptr->schid);
-	else {
+
+	if (is_qebsm(q)) {
 		schid = q->irq_ptr->sch_token;
 		fc |= 0x80;
 	}
-	return do_siga_output(schid, q->mask, busy_bit, fc);
-}
+	else
+		schid = *((u32 *)&q->irq_ptr->schid);
 
-static int qdio_siga_output(struct qdio_q *q)
-{
-	int cc;
-	u32 busy_bit;
-	u64 start_time = 0;
-	char dbf_text[15];
-
-	QDIO_DBF_TEXT5(0, trace, "sigaout");
-	QDIO_DBF_HEX5(0, trace, &q, sizeof(void *));
-
-	qdio_perf_stat_inc(&perf_stats.siga_out);
 again:
-	cc = qdio_do_siga_output(q, &busy_bit);
-	if (queue_type(q) == QDIO_IQDIO_QFMT && cc == 2 && busy_bit) {
-		sprintf(dbf_text, "bb%4x%2x", q->irq_ptr->schid.sch_no, q->nr);
-		QDIO_DBF_TEXT3(0, trace, dbf_text);
+	cc = do_siga_output(schid, q->mask, busy_bit, fc);
 
-		if (!start_time)
+	/* hipersocket busy condition */
+	if (*busy_bit) {
+		WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
+
+		if (!start_time) {
 			start_time = get_usecs();
-		else if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE)
+			goto again;
+		}
+		if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE)
 			goto again;
 	}
-
-	if (cc == 2 && busy_bit)
-		cc |= QDIO_ERROR_SIGA_BUSY;
-	if (cc)
-		QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *));
 	return cc;
 }
 
@@ -362,14 +349,12 @@
 {
 	int cc;
 
-	QDIO_DBF_TEXT4(0, trace, "sigain");
-	QDIO_DBF_HEX4(0, trace, &q, sizeof(void *));
-
+	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr);
 	qdio_perf_stat_inc(&perf_stats.siga_in);
 
 	cc = do_siga_input(q->irq_ptr->schid, q->mask);
 	if (cc)
-		QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *));
+		DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc);
 	return cc;
 }
 
@@ -387,35 +372,91 @@
 
 inline void qdio_stop_polling(struct qdio_q *q)
 {
-	spin_lock_bh(&q->u.in.lock);
-	if (!q->u.in.polling) {
-		spin_unlock_bh(&q->u.in.lock);
+	if (!q->u.in.polling)
 		return;
-	}
+
 	q->u.in.polling = 0;
 	qdio_perf_stat_inc(&perf_stats.debug_stop_polling);
 
 	/* show the card that we are not polling anymore */
-	set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
-	spin_unlock_bh(&q->u.in.lock);
+	if (is_qebsm(q)) {
+		set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT,
+			       q->u.in.ack_count);
+		q->u.in.ack_count = 0;
+	} else
+		set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
 }
 
-static void announce_buffer_error(struct qdio_q *q)
+static void announce_buffer_error(struct qdio_q *q, int count)
 {
-	char dbf_text[15];
+	q->qdio_error |= QDIO_ERROR_SLSB_STATE;
 
-	if (q->is_input_q)
-		QDIO_DBF_TEXT3(1, trace, "inperr");
-	else
-		QDIO_DBF_TEXT3(0, trace, "outperr");
+	/* special handling for no target buffer empty */
+	if ((!q->is_input_q &&
+	    (q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) {
+		qdio_perf_stat_inc(&perf_stats.outbound_target_full);
+		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%3d",
+			      q->first_to_check);
+		return;
+	}
 
-	sprintf(dbf_text, "%x-%x-%x", q->first_to_check,
-		q->sbal[q->first_to_check]->element[14].flags,
-		q->sbal[q->first_to_check]->element[15].flags);
-	QDIO_DBF_TEXT3(1, trace, dbf_text);
-	QDIO_DBF_HEX2(1, trace, q->sbal[q->first_to_check], 256);
+	DBF_ERROR("%4x BUF ERROR", SCH_NO(q));
+	DBF_ERROR((q->is_input_q) ? "IN:%2d" : "OUT:%2d", q->nr);
+	DBF_ERROR("FTC:%3d C:%3d", q->first_to_check, count);
+	DBF_ERROR("F14:%2x F15:%2x",
+		  q->sbal[q->first_to_check]->element[14].flags & 0xff,
+		  q->sbal[q->first_to_check]->element[15].flags & 0xff);
+}
 
-	q->qdio_error = QDIO_ERROR_SLSB_STATE;
+static inline void inbound_primed(struct qdio_q *q, int count)
+{
+	int new;
+
+	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %3d", count);
+
+	/* for QEBSM the ACK was already set by EQBS */
+	if (is_qebsm(q)) {
+		if (!q->u.in.polling) {
+			q->u.in.polling = 1;
+			q->u.in.ack_count = count;
+			q->last_move_ftc = q->first_to_check;
+			return;
+		}
+
+		/* delete the previous ACK's */
+		set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT,
+			       q->u.in.ack_count);
+		q->u.in.ack_count = count;
+		q->last_move_ftc = q->first_to_check;
+		return;
+	}
+
+	/*
+	 * ACK the newest buffer. The ACK will be removed in qdio_stop_polling
+	 * or by the next inbound run.
+	 */
+	new = add_buf(q->first_to_check, count - 1);
+	if (q->u.in.polling) {
+		/* reset the previous ACK but first set the new one */
+		set_buf_state(q, new, SLSB_P_INPUT_ACK);
+		set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
+	}
+	else {
+		q->u.in.polling = 1;
+		set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK);
+	}
+
+	q->last_move_ftc = new;
+	count--;
+	if (!count)
+		return;
+
+	/*
+	 * Need to change all PRIMED buffers to NOT_INIT, otherwise
+	 * we're loosing initiative in the thinint code.
+	 */
+	set_buf_states(q, next_buf(q->first_to_check), SLSB_P_INPUT_NOT_INIT,
+		       count);
 }
 
 static int get_inbound_buffer_frontier(struct qdio_q *q)
@@ -424,13 +465,6 @@
 	unsigned char state;
 
 	/*
-	 * If we still poll don't update last_move_ftc, keep the
-	 * previously ACK buffer there.
-	 */
-	if (!q->u.in.polling)
-		q->last_move_ftc = q->first_to_check;
-
-	/*
 	 * Don't check 128 buffers, as otherwise qdio_inbound_q_moved
 	 * would return 0.
 	 */
@@ -450,34 +484,13 @@
 	if (q->first_to_check == stop)
 		goto out;
 
-	count = get_buf_states(q, q->first_to_check, &state, count);
+	count = get_buf_states(q, q->first_to_check, &state, count, 1);
 	if (!count)
 		goto out;
 
 	switch (state) {
 	case SLSB_P_INPUT_PRIMED:
-		QDIO_DBF_TEXT5(0, trace, "inptprim");
-
-		/*
-		 * Only ACK the first buffer. The ACK will be removed in
-		 * qdio_stop_polling.
-		 */
-		if (q->u.in.polling)
-			state = SLSB_P_INPUT_NOT_INIT;
-		else {
-			q->u.in.polling = 1;
-			state = SLSB_P_INPUT_ACK;
-		}
-		set_buf_state(q, q->first_to_check, state);
-
-		/*
-		 * Need to change all PRIMED buffers to NOT_INIT, otherwise
-		 * we're loosing initiative in the thinint code.
-		 */
-		if (count > 1)
-			set_buf_states(q, next_buf(q->first_to_check),
-				       SLSB_P_INPUT_NOT_INIT, count - 1);
-
+		inbound_primed(q, count);
 		/*
 		 * No siga-sync needed for non-qebsm here, as the inbound queue
 		 * will be synced on the next siga-r, resp.
@@ -487,7 +500,7 @@
 		atomic_sub(count, &q->nr_buf_used);
 		goto check_next;
 	case SLSB_P_INPUT_ERROR:
-		announce_buffer_error(q);
+		announce_buffer_error(q, count);
 		/* process the buffer, the upper layer will take care of it */
 		q->first_to_check = add_buf(q->first_to_check, count);
 		atomic_sub(count, &q->nr_buf_used);
@@ -495,13 +508,12 @@
 	case SLSB_CU_INPUT_EMPTY:
 	case SLSB_P_INPUT_NOT_INIT:
 	case SLSB_P_INPUT_ACK:
-		QDIO_DBF_TEXT5(0, trace, "inpnipro");
+		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in nop");
 		break;
 	default:
 		BUG();
 	}
 out:
-	QDIO_DBF_HEX4(0, trace, &q->first_to_check, sizeof(int));
 	return q->first_to_check;
 }
 
@@ -515,8 +527,7 @@
 		if (!need_siga_sync(q) && !pci_out_supported(q))
 			q->u.in.timestamp = get_usecs();
 
-		QDIO_DBF_TEXT4(0, trace, "inhasmvd");
-		QDIO_DBF_HEX4(0, trace, &q, sizeof(void *));
+		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in moved");
 		return 1;
 	} else
 		return 0;
@@ -524,10 +535,7 @@
 
 static int qdio_inbound_q_done(struct qdio_q *q)
 {
-	unsigned char state;
-#ifdef CONFIG_QDIO_DEBUG
-	char dbf_text[15];
-#endif
+	unsigned char state = 0;
 
 	if (!atomic_read(&q->nr_buf_used))
 		return 1;
@@ -538,7 +546,7 @@
 	 */
 	qdio_siga_sync_q(q);
 
-	get_buf_state(q, q->first_to_check, &state);
+	get_buf_state(q, q->first_to_check, &state, 0);
 	if (state == SLSB_P_INPUT_PRIMED)
 		/* we got something to do */
 		return 0;
@@ -552,20 +560,12 @@
 	 * has (probably) not moved (see qdio_inbound_processing).
 	 */
 	if (get_usecs() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) {
-#ifdef CONFIG_QDIO_DEBUG
-		QDIO_DBF_TEXT4(0, trace, "inqisdon");
-		QDIO_DBF_HEX4(0, trace, &q, sizeof(void *));
-		sprintf(dbf_text, "pf%02x", q->first_to_check);
-		QDIO_DBF_TEXT4(0, trace, dbf_text);
-#endif /* CONFIG_QDIO_DEBUG */
+		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%3d",
+			      q->first_to_check);
 		return 1;
 	} else {
-#ifdef CONFIG_QDIO_DEBUG
-		QDIO_DBF_TEXT4(0, trace, "inqisntd");
-		QDIO_DBF_HEX4(0, trace, &q, sizeof(void *));
-		sprintf(dbf_text, "pf%02x", q->first_to_check);
-		QDIO_DBF_TEXT4(0, trace, dbf_text);
-#endif /* CONFIG_QDIO_DEBUG */
+		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in notd:%3d",
+			      q->first_to_check);
 		return 0;
 	}
 }
@@ -573,9 +573,6 @@
 void qdio_kick_inbound_handler(struct qdio_q *q)
 {
 	int count, start, end;
-#ifdef CONFIG_QDIO_DEBUG
-	char dbf_text[15];
-#endif
 
 	qdio_perf_stat_inc(&perf_stats.inbound_handler);
 
@@ -586,10 +583,7 @@
 	else
 		count = end + QDIO_MAX_BUFFERS_PER_Q - start;
 
-#ifdef CONFIG_QDIO_DEBUG
-	sprintf(dbf_text, "s=%2xc=%2x", start, count);
-	QDIO_DBF_TEXT4(0, trace, dbf_text);
-#endif /* CONFIG_QDIO_DEBUG */
+	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count);
 
 	if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))
 		return;
@@ -655,14 +649,14 @@
 	if (q->first_to_check == stop)
 		return q->first_to_check;
 
-	count = get_buf_states(q, q->first_to_check, &state, count);
+	count = get_buf_states(q, q->first_to_check, &state, count, 0);
 	if (!count)
 		return q->first_to_check;
 
 	switch (state) {
 	case SLSB_P_OUTPUT_EMPTY:
 		/* the adapter got it */
-		QDIO_DBF_TEXT5(0, trace, "outpempt");
+		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out empty:%1d %3d", q->nr, count);
 
 		atomic_sub(count, &q->nr_buf_used);
 		q->first_to_check = add_buf(q->first_to_check, count);
@@ -674,14 +668,14 @@
 			break;
 		goto check_next;
 	case SLSB_P_OUTPUT_ERROR:
-		announce_buffer_error(q);
+		announce_buffer_error(q, count);
 		/* process the buffer, the upper layer will take care of it */
 		q->first_to_check = add_buf(q->first_to_check, count);
 		atomic_sub(count, &q->nr_buf_used);
 		break;
 	case SLSB_CU_OUTPUT_PRIMED:
 		/* the adapter has not fetched the output yet */
-		QDIO_DBF_TEXT5(0, trace, "outpprim");
+		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out primed:%1d", q->nr);
 		break;
 	case SLSB_P_OUTPUT_NOT_INIT:
 	case SLSB_P_OUTPUT_HALTED:
@@ -706,99 +700,48 @@
 
 	if ((bufnr != q->last_move_ftc) || q->qdio_error) {
 		q->last_move_ftc = bufnr;
-		QDIO_DBF_TEXT4(0, trace, "oqhasmvd");
-		QDIO_DBF_HEX4(0, trace, &q, sizeof(void *));
+		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr);
 		return 1;
 	} else
 		return 0;
 }
 
-/*
- * VM could present us cc=2 and busy bit set on SIGA-write
- * during reconfiguration of their Guest LAN (only in iqdio mode,
- * otherwise qdio is asynchronous and cc=2 and busy bit there will take
- * the queues down immediately).
- *
- * Therefore qdio_siga_output will try for a short time constantly,
- * if such a condition occurs. If it doesn't change, it will
- * increase the busy_siga_counter and save the timestamp, and
- * schedule the queue for later processing. qdio_outbound_processing
- * will check out the counter. If non-zero, it will call qdio_kick_outbound_q
- * as often as the value of the counter. This will attempt further SIGA
- * instructions. For each successful SIGA, the counter is
- * decreased, for failing SIGAs the counter remains the same, after
- * all. After some time of no movement, qdio_kick_outbound_q will
- * finally fail and reflect corresponding error codes to call
- * the upper layer module and have it take the queues down.
- *
- * Note that this is a change from the original HiperSockets design
- * (saying cc=2 and busy bit means take the queues down), but in
- * these days Guest LAN didn't exist... excessive cc=2 with busy bit
- * conditions will still take the queues down, but the threshold is
- * higher due to the Guest LAN environment.
- *
- * Called from outbound tasklet and do_QDIO handler.
- */
 static void qdio_kick_outbound_q(struct qdio_q *q)
 {
-	int rc;
-#ifdef CONFIG_QDIO_DEBUG
-	char dbf_text[15];
-
-	QDIO_DBF_TEXT5(0, trace, "kickoutq");
-	QDIO_DBF_HEX5(0, trace, &q, sizeof(void *));
-#endif /* CONFIG_QDIO_DEBUG */
+	unsigned int busy_bit;
+	int cc;
 
 	if (!need_siga_out(q))
 		return;
 
-	rc = qdio_siga_output(q);
-	switch (rc) {
+	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
+	qdio_perf_stat_inc(&perf_stats.siga_out);
+
+	cc = qdio_siga_output(q, &busy_bit);
+	switch (cc) {
 	case 0:
-		/* TODO: improve error handling for CC=0 case */
-#ifdef CONFIG_QDIO_DEBUG
-		if (q->u.out.timestamp) {
-			QDIO_DBF_TEXT3(0, trace, "cc2reslv");
-			sprintf(dbf_text, "%4x%2x%2x", q->irq_ptr->schid.sch_no,
-				q->nr,
-				atomic_read(&q->u.out.busy_siga_counter));
-			QDIO_DBF_TEXT3(0, trace, dbf_text);
-		}
-#endif /* CONFIG_QDIO_DEBUG */
-		/* went smooth this time, reset timestamp */
-		q->u.out.timestamp = 0;
 		break;
-	/* cc=2 and busy bit */
-	case (2 | QDIO_ERROR_SIGA_BUSY):
-		atomic_inc(&q->u.out.busy_siga_counter);
-
-		/* if the last siga was successful, save timestamp here */
-		if (!q->u.out.timestamp)
-			q->u.out.timestamp = get_usecs();
-
-		/* if we're in time, don't touch qdio_error */
-		if (get_usecs() - q->u.out.timestamp < QDIO_BUSY_BIT_GIVE_UP) {
-			tasklet_schedule(&q->tasklet);
-			break;
+	case 2:
+		if (busy_bit) {
+			DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
+			q->qdio_error = cc | QDIO_ERROR_SIGA_BUSY;
+		} else {
+			DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d",
+				      q->nr);
+			q->qdio_error = cc;
 		}
-		QDIO_DBF_TEXT2(0, trace, "cc2REPRT");
-#ifdef CONFIG_QDIO_DEBUG
-		sprintf(dbf_text, "%4x%2x%2x", q->irq_ptr->schid.sch_no, q->nr,
-			atomic_read(&q->u.out.busy_siga_counter));
-		QDIO_DBF_TEXT3(0, trace, dbf_text);
-#endif /* CONFIG_QDIO_DEBUG */
-	default:
-		/* for plain cc=1, 2 or 3 */
-		q->qdio_error = rc;
+		break;
+	case 1:
+	case 3:
+		DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
+		q->qdio_error = cc;
+		break;
 	}
 }
 
 static void qdio_kick_outbound_handler(struct qdio_q *q)
 {
 	int start, end, count;
-#ifdef CONFIG_QDIO_DEBUG
-	char dbf_text[15];
-#endif
 
 	start = q->first_to_kick;
 	end = q->last_move_ftc;
@@ -807,13 +750,8 @@
 	else
 		count = end + QDIO_MAX_BUFFERS_PER_Q - start;
 
-#ifdef CONFIG_QDIO_DEBUG
-	QDIO_DBF_TEXT4(0, trace, "kickouth");
-	QDIO_DBF_HEX4(0, trace, &q, sizeof(void *));
-
-	sprintf(dbf_text, "s=%2xc=%2x", start, count);
-	QDIO_DBF_TEXT4(0, trace, dbf_text);
-#endif /* CONFIG_QDIO_DEBUG */
+	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickouth: %1d", q->nr);
+	DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count);
 
 	if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))
 		return;
@@ -828,22 +766,18 @@
 
 static void __qdio_outbound_processing(struct qdio_q *q)
 {
-	int siga_attempts;
+	unsigned long flags;
 
 	qdio_perf_stat_inc(&perf_stats.tasklet_outbound);
-
-	/* see comment in qdio_kick_outbound_q */
-	siga_attempts = atomic_read(&q->u.out.busy_siga_counter);
-	while (siga_attempts--) {
-		atomic_dec(&q->u.out.busy_siga_counter);
-		qdio_kick_outbound_q(q);
-	}
+	spin_lock_irqsave(&q->lock, flags);
 
 	BUG_ON(atomic_read(&q->nr_buf_used) < 0);
 
 	if (qdio_outbound_q_moved(q))
 		qdio_kick_outbound_handler(q);
 
+	spin_unlock_irqrestore(&q->lock, flags);
+
 	if (queue_type(q) == QDIO_ZFCP_QFMT) {
 		if (!pci_out_supported(q) && !qdio_outbound_q_done(q))
 			tasklet_schedule(&q->tasklet);
@@ -908,27 +842,18 @@
 static inline void qdio_set_state(struct qdio_irq *irq_ptr,
 				  enum qdio_irq_states state)
 {
-#ifdef CONFIG_QDIO_DEBUG
-	char dbf_text[15];
-
-	QDIO_DBF_TEXT5(0, trace, "newstate");
-	sprintf(dbf_text, "%4x%4x", irq_ptr->schid.sch_no, state);
-	QDIO_DBF_TEXT5(0, trace, dbf_text);
-#endif /* CONFIG_QDIO_DEBUG */
+	DBF_DEV_EVENT(DBF_INFO, irq_ptr, "newstate: %1d", state);
 
 	irq_ptr->state = state;
 	mb();
 }
 
-static void qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
+static void qdio_irq_check_sense(struct qdio_irq *irq_ptr, struct irb *irb)
 {
-	char dbf_text[15];
-
 	if (irb->esw.esw0.erw.cons) {
-		sprintf(dbf_text, "sens%4x", schid.sch_no);
-		QDIO_DBF_TEXT2(1, trace, dbf_text);
-		QDIO_DBF_HEX0(0, trace, irb, 64);
-		QDIO_DBF_HEX0(0, trace, irb->ecw, 64);
+		DBF_ERROR("%4x sense:", irq_ptr->schid.sch_no);
+		DBF_ERROR_HEX(irb, 64);
+		DBF_ERROR_HEX(irb->ecw, 64);
 	}
 }
 
@@ -962,14 +887,10 @@
 {
 	struct qdio_irq *irq_ptr = cdev->private->qdio_data;
 	struct qdio_q *q;
-	char dbf_text[15];
 
-	QDIO_DBF_TEXT2(1, trace, "ick2");
-	sprintf(dbf_text, "%s", dev_name(&cdev->dev));
-	QDIO_DBF_TEXT2(1, trace, dbf_text);
-	QDIO_DBF_HEX2(0, trace, &intparm, sizeof(int));
-	QDIO_DBF_HEX2(0, trace, &dstat, sizeof(int));
-	QDIO_DBF_HEX2(0, trace, &cstat, sizeof(int));
+	DBF_ERROR("%4x ACT CHECK", irq_ptr->schid.sch_no);
+	DBF_ERROR("intp :%lx", intparm);
+	DBF_ERROR("ds: %2x cs:%2x", dstat, cstat);
 
 	if (irq_ptr->nr_input_qs) {
 		q = irq_ptr->input_qs[0];
@@ -1022,28 +943,29 @@
 }
 
 static int qdio_establish_check_errors(struct ccw_device *cdev, int cstat,
-					   int dstat)
+				       int dstat)
 {
 	struct qdio_irq *irq_ptr = cdev->private->qdio_data;
 
 	if (cstat || (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))) {
-		QDIO_DBF_TEXT2(1, setup, "eq:ckcon");
+		DBF_ERROR("EQ:ck con");
 		goto error;
 	}
 
 	if (!(dstat & DEV_STAT_DEV_END)) {
-		QDIO_DBF_TEXT2(1, setup, "eq:no de");
+		DBF_ERROR("EQ:no dev");
 		goto error;
 	}
 
 	if (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) {
-		QDIO_DBF_TEXT2(1, setup, "eq:badio");
+		DBF_ERROR("EQ: bad io");
 		goto error;
 	}
 	return 0;
 error:
-	QDIO_DBF_HEX2(0, trace, &cstat, sizeof(int));
-	QDIO_DBF_HEX2(0, trace, &dstat, sizeof(int));
+	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;
 }
@@ -1052,12 +974,8 @@
 				      int dstat)
 {
 	struct qdio_irq *irq_ptr = cdev->private->qdio_data;
-	char dbf_text[15];
 
-	sprintf(dbf_text, "qehi%4x", cdev->private->schid.sch_no);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
-	QDIO_DBF_TEXT0(0, trace, dbf_text);
-
+	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);
 }
@@ -1068,25 +986,21 @@
 {
 	struct qdio_irq *irq_ptr = cdev->private->qdio_data;
 	int cstat, dstat;
-	char dbf_text[15];
 
 	qdio_perf_stat_inc(&perf_stats.qdio_int);
 
 	if (!intparm || !irq_ptr) {
-		sprintf(dbf_text, "qihd%4x", cdev->private->schid.sch_no);
-		QDIO_DBF_TEXT2(1, setup, dbf_text);
+		DBF_ERROR("qint:%4x", cdev->private->schid.sch_no);
 		return;
 	}
 
 	if (IS_ERR(irb)) {
 		switch (PTR_ERR(irb)) {
 		case -EIO:
-			sprintf(dbf_text, "ierr%4x", irq_ptr->schid.sch_no);
-			QDIO_DBF_TEXT2(1, setup, dbf_text);
+			DBF_ERROR("%4x IO error", irq_ptr->schid.sch_no);
 			return;
 		case -ETIMEDOUT:
-			sprintf(dbf_text, "qtoh%4x", irq_ptr->schid.sch_no);
-			QDIO_DBF_TEXT2(1, setup, dbf_text);
+			DBF_ERROR("%4x IO timeout", irq_ptr->schid.sch_no);
 			qdio_int_error(cdev);
 			return;
 		default:
@@ -1094,7 +1008,7 @@
 			return;
 		}
 	}
-	qdio_irq_check_sense(irq_ptr->schid, irb);
+	qdio_irq_check_sense(irq_ptr, irb);
 
 	cstat = irb->scsw.cmd.cstat;
 	dstat = irb->scsw.cmd.dstat;
@@ -1129,23 +1043,20 @@
 /**
  * qdio_get_ssqd_desc - get qdio subchannel description
  * @cdev: ccw device to get description for
+ * @data: where to store the ssqd
  *
- * Returns a pointer to the saved qdio subchannel description,
- * or NULL for not setup qdio devices.
+ * Returns 0 or an error code. The results of the chsc are stored in the
+ * specified structure.
  */
-struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev)
+int qdio_get_ssqd_desc(struct ccw_device *cdev,
+		       struct qdio_ssqd_desc *data)
 {
-	struct qdio_irq *irq_ptr;
-	char dbf_text[15];
 
-	sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
+	if (!cdev || !cdev->private)
+		return -EINVAL;
 
-	irq_ptr = cdev->private->qdio_data;
-	if (!irq_ptr)
-		return NULL;
-
-	return &irq_ptr->ssqd_desc;
+	DBF_EVENT("get ssqd:%4x", cdev->private->schid.sch_no);
+	return qdio_setup_get_ssqd(NULL, &cdev->private->schid, data);
 }
 EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc);
 
@@ -1159,14 +1070,9 @@
  */
 int qdio_cleanup(struct ccw_device *cdev, int how)
 {
-	struct qdio_irq *irq_ptr;
-	char dbf_text[15];
+	struct qdio_irq *irq_ptr = cdev->private->qdio_data;
 	int rc;
 
-	sprintf(dbf_text, "qcln%4x", cdev->private->schid.sch_no);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
-
-	irq_ptr = cdev->private->qdio_data;
 	if (!irq_ptr)
 		return -ENODEV;
 
@@ -1199,18 +1105,15 @@
  */
 int qdio_shutdown(struct ccw_device *cdev, int how)
 {
-	struct qdio_irq *irq_ptr;
+	struct qdio_irq *irq_ptr = cdev->private->qdio_data;
 	int rc;
 	unsigned long flags;
-	char dbf_text[15];
 
-	sprintf(dbf_text, "qshu%4x", cdev->private->schid.sch_no);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
-
-	irq_ptr = cdev->private->qdio_data;
 	if (!irq_ptr)
 		return -ENODEV;
 
+	DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no);
+
 	mutex_lock(&irq_ptr->setup_mutex);
 	/*
 	 * Subchannel was already shot down. We cannot prevent being called
@@ -1234,10 +1137,8 @@
 		/* default behaviour is halt */
 		rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP);
 	if (rc) {
-		sprintf(dbf_text, "sher%4x", irq_ptr->schid.sch_no);
-		QDIO_DBF_TEXT0(0, setup, dbf_text);
-		sprintf(dbf_text, "rc=%d", rc);
-		QDIO_DBF_TEXT0(0, setup, dbf_text);
+		DBF_ERROR("%4x SHUTD ERR", irq_ptr->schid.sch_no);
+		DBF_ERROR("rc:%4d", rc);
 		goto no_cleanup;
 	}
 
@@ -1271,17 +1172,18 @@
  */
 int qdio_free(struct ccw_device *cdev)
 {
-	struct qdio_irq *irq_ptr;
-	char dbf_text[15];
+	struct qdio_irq *irq_ptr = cdev->private->qdio_data;
 
-	sprintf(dbf_text, "qfre%4x", cdev->private->schid.sch_no);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
-
-	irq_ptr = cdev->private->qdio_data;
 	if (!irq_ptr)
 		return -ENODEV;
 
+	DBF_EVENT("qfree:%4x", cdev->private->schid.sch_no);
 	mutex_lock(&irq_ptr->setup_mutex);
+
+	if (irq_ptr->debug_area != NULL) {
+		debug_unregister(irq_ptr->debug_area);
+		irq_ptr->debug_area = NULL;
+	}
 	cdev->private->qdio_data = NULL;
 	mutex_unlock(&irq_ptr->setup_mutex);
 
@@ -1300,10 +1202,6 @@
 int qdio_initialize(struct qdio_initialize *init_data)
 {
 	int rc;
-	char dbf_text[15];
-
-	sprintf(dbf_text, "qini%4x", init_data->cdev->private->schid.sch_no);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
 
 	rc = qdio_allocate(init_data);
 	if (rc)
@@ -1323,10 +1221,8 @@
 int qdio_allocate(struct qdio_initialize *init_data)
 {
 	struct qdio_irq *irq_ptr;
-	char dbf_text[15];
 
-	sprintf(dbf_text, "qalc%4x", init_data->cdev->private->schid.sch_no);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
+	DBF_EVENT("qallocate:%4x", init_data->cdev->private->schid.sch_no);
 
 	if ((init_data->no_input_qs && !init_data->input_handler) ||
 	    (init_data->no_output_qs && !init_data->output_handler))
@@ -1340,16 +1236,13 @@
 	    (!init_data->output_sbal_addr_array))
 		return -EINVAL;
 
-	qdio_allocate_do_dbf(init_data);
-
 	/* irq_ptr must be in GFP_DMA since it contains ccw1.cda */
 	irq_ptr = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
 	if (!irq_ptr)
 		goto out_err;
-	QDIO_DBF_TEXT0(0, setup, "irq_ptr:");
-	QDIO_DBF_HEX0(0, setup, &irq_ptr, sizeof(void *));
 
 	mutex_init(&irq_ptr->setup_mutex);
+	qdio_allocate_dbf(init_data, irq_ptr);
 
 	/*
 	 * Allocate a page for the chsc calls in qdio_establish.
@@ -1367,9 +1260,6 @@
 		goto out_rel;
 	WARN_ON((unsigned long)irq_ptr->qdr & 0xfff);
 
-	QDIO_DBF_TEXT0(0, setup, "qdr:");
-	QDIO_DBF_HEX0(0, setup, &irq_ptr->qdr, sizeof(void *));
-
 	if (qdio_allocate_qs(irq_ptr, init_data->no_input_qs,
 			     init_data->no_output_qs))
 		goto out_rel;
@@ -1390,14 +1280,12 @@
  */
 int qdio_establish(struct qdio_initialize *init_data)
 {
-	char dbf_text[20];
 	struct qdio_irq *irq_ptr;
 	struct ccw_device *cdev = init_data->cdev;
 	unsigned long saveflags;
 	int rc;
 
-	sprintf(dbf_text, "qest%4x", cdev->private->schid.sch_no);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
+	DBF_EVENT("qestablish:%4x", cdev->private->schid.sch_no);
 
 	irq_ptr = cdev->private->qdio_data;
 	if (!irq_ptr)
@@ -1427,10 +1315,8 @@
 
 	rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ESTABLISH, 0, 0);
 	if (rc) {
-		sprintf(dbf_text, "eq:io%4x", irq_ptr->schid.sch_no);
-		QDIO_DBF_TEXT2(1, setup, dbf_text);
-		sprintf(dbf_text, "eq:rc%4x", rc);
-		QDIO_DBF_TEXT2(1, setup, dbf_text);
+		DBF_ERROR("%4x est IO ERR", irq_ptr->schid.sch_no);
+		DBF_ERROR("rc:%4x", rc);
 	}
 	spin_unlock_irqrestore(get_ccwdev_lock(cdev), saveflags);
 
@@ -1451,10 +1337,8 @@
 	}
 
 	qdio_setup_ssqd_info(irq_ptr);
-	sprintf(dbf_text, "qDmmwc%2x", irq_ptr->ssqd_desc.mmwc);
-	QDIO_DBF_TEXT2(0, setup, dbf_text);
-	sprintf(dbf_text, "qib ac%2x", irq_ptr->qib.ac);
-	QDIO_DBF_TEXT2(0, setup, dbf_text);
+	DBF_EVENT("qDmmwc:%2x", irq_ptr->ssqd_desc.mmwc);
+	DBF_EVENT("qib ac:%4x", irq_ptr->qib.ac);
 
 	/* qebsm is now setup if available, initialize buffer states */
 	qdio_init_buf_states(irq_ptr);
@@ -1475,10 +1359,8 @@
 	struct qdio_irq *irq_ptr;
 	int rc;
 	unsigned long saveflags;
-	char dbf_text[20];
 
-	sprintf(dbf_text, "qact%4x", cdev->private->schid.sch_no);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
+	DBF_EVENT("qactivate:%4x", cdev->private->schid.sch_no);
 
 	irq_ptr = cdev->private->qdio_data;
 	if (!irq_ptr)
@@ -1504,10 +1386,8 @@
 	rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ACTIVATE,
 			      0, DOIO_DENY_PREFETCH);
 	if (rc) {
-		sprintf(dbf_text, "aq:io%4x", irq_ptr->schid.sch_no);
-		QDIO_DBF_TEXT2(1, setup, dbf_text);
-		sprintf(dbf_text, "aq:rc%4x", rc);
-		QDIO_DBF_TEXT2(1, setup, dbf_text);
+		DBF_ERROR("%4x act IO ERR", irq_ptr->schid.sch_no);
+		DBF_ERROR("rc:%4x", rc);
 	}
 	spin_unlock_irqrestore(get_ccwdev_lock(cdev), saveflags);
 
@@ -1565,23 +1445,38 @@
 static void handle_inbound(struct qdio_q *q, unsigned int callflags,
 			   int bufnr, int count)
 {
-	unsigned long flags;
-	int used, rc;
+	int used, cc, diff;
 
-	/*
-	 * do_QDIO could run in parallel with the queue tasklet so the
-	 * upper-layer programm could empty the ACK'ed buffer here.
-	 * If that happens we must clear the polling flag, otherwise
-	 * qdio_stop_polling() could set the buffer to NOT_INIT after
-	 * it was set to EMPTY which would kill us.
-	 */
-	spin_lock_irqsave(&q->u.in.lock, flags);
-	if (q->u.in.polling)
-		if (buf_in_between(q->last_move_ftc, bufnr, count))
+	if (!q->u.in.polling)
+		goto set;
+
+	/* protect against stop polling setting an ACK for an emptied slsb */
+	if (count == QDIO_MAX_BUFFERS_PER_Q) {
+		/* overwriting everything, just delete polling status */
+		q->u.in.polling = 0;
+		q->u.in.ack_count = 0;
+		goto set;
+	} else if (buf_in_between(q->last_move_ftc, bufnr, count)) {
+		if (is_qebsm(q)) {
+			/* partial overwrite, just update last_move_ftc */
+			diff = add_buf(bufnr, count);
+			diff = sub_buf(diff, q->last_move_ftc);
+			q->u.in.ack_count -= diff;
+			if (q->u.in.ack_count <= 0) {
+				q->u.in.polling = 0;
+				q->u.in.ack_count = 0;
+				/* TODO: must we set last_move_ftc to something meaningful? */
+				goto set;
+			}
+			q->last_move_ftc = add_buf(q->last_move_ftc, diff);
+		}
+		else
+			/* the only ACK will be deleted, so stop polling */
 			q->u.in.polling = 0;
+	}
 
+set:
 	count = set_buf_states(q, bufnr, SLSB_CU_INPUT_EMPTY, count);
-	spin_unlock_irqrestore(&q->u.in.lock, flags);
 
 	used = atomic_add_return(count, &q->nr_buf_used) - count;
 	BUG_ON(used + count > QDIO_MAX_BUFFERS_PER_Q);
@@ -1591,9 +1486,9 @@
 		return;
 
 	if (need_siga_in(q)) {
-		rc = qdio_siga_input(q);
-		if (rc)
-			q->qdio_error = rc;
+		cc = qdio_siga_input(q);
+		if (cc)
+			q->qdio_error = cc;
 	}
 }
 
@@ -1640,6 +1535,10 @@
 				while (count--)
 					qdio_kick_outbound_q(q);
 			}
+
+		/* report CC=2 conditions synchronously */
+		if (q->qdio_error)
+			__qdio_outbound_processing(q);
 		goto out;
 	}
 
@@ -1649,11 +1548,11 @@
 	}
 
 	/* try to fast requeue buffers */
-	get_buf_state(q, prev_buf(bufnr), &state);
+	get_buf_state(q, prev_buf(bufnr), &state, 0);
 	if (state != SLSB_CU_OUTPUT_PRIMED)
 		qdio_kick_outbound_q(q);
 	else {
-		QDIO_DBF_TEXT5(0, trace, "fast-req");
+		DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req");
 		qdio_perf_stat_inc(&perf_stats.fast_requeue);
 	}
 out:
@@ -1673,12 +1572,6 @@
 	    int q_nr, int bufnr, int count)
 {
 	struct qdio_irq *irq_ptr;
-#ifdef CONFIG_QDIO_DEBUG
-	char dbf_text[20];
-
-	sprintf(dbf_text, "doQD%4x", cdev->private->schid.sch_no);
-	QDIO_DBF_TEXT3(0, trace, dbf_text);
-#endif /* CONFIG_QDIO_DEBUG */
 
 	if ((bufnr > QDIO_MAX_BUFFERS_PER_Q) ||
 	    (count > QDIO_MAX_BUFFERS_PER_Q) ||
@@ -1692,33 +1585,24 @@
 	if (!irq_ptr)
 		return -ENODEV;
 
-#ifdef CONFIG_QDIO_DEBUG
 	if (callflags & QDIO_FLAG_SYNC_INPUT)
-		QDIO_DBF_HEX3(0, trace, &irq_ptr->input_qs[q_nr],
-			      sizeof(void *));
+		DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO input");
 	else
-		QDIO_DBF_HEX3(0, trace, &irq_ptr->output_qs[q_nr],
-			      sizeof(void *));
-
-	sprintf(dbf_text, "flag%04x", callflags);
-	QDIO_DBF_TEXT3(0, trace, dbf_text);
-	sprintf(dbf_text, "qi%02xct%02x", bufnr, count);
-	QDIO_DBF_TEXT3(0, trace, dbf_text);
-#endif /* CONFIG_QDIO_DEBUG */
+		DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO output");
+	DBF_DEV_EVENT(DBF_INFO, irq_ptr, "q:%1d flag:%4x", q_nr, callflags);
+	DBF_DEV_EVENT(DBF_INFO, irq_ptr, "buf:%2d cnt:%3d", bufnr, count);
 
 	if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)
 		return -EBUSY;
 
 	if (callflags & QDIO_FLAG_SYNC_INPUT)
-		handle_inbound(irq_ptr->input_qs[q_nr],
-			       callflags, bufnr, count);
+		handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr,
+			       count);
 	else if (callflags & QDIO_FLAG_SYNC_OUTPUT)
-		handle_outbound(irq_ptr->output_qs[q_nr],
-				callflags, bufnr, count);
-	else {
-		QDIO_DBF_TEXT3(1, trace, "doQD:inv");
+		handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr,
+				count);
+	else
 		return -EINVAL;
-	}
 	return 0;
 }
 EXPORT_SYMBOL_GPL(do_QDIO);
diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c
index ec5c4a4..136d0f0 100644
--- a/drivers/s390/cio/qdio_perf.c
+++ b/drivers/s390/cio/qdio_perf.c
@@ -74,12 +74,20 @@
 	seq_printf(m, "\n");
 	seq_printf(m, "Number of fast requeues (outg. SBAL w/o SIGA)\t: %li\n",
 		   (long)atomic_long_read(&perf_stats.fast_requeue));
+	seq_printf(m, "Number of outbound target full condition\t: %li\n",
+		   (long)atomic_long_read(&perf_stats.outbound_target_full));
 	seq_printf(m, "Number of outbound tasklet mod_timer calls\t: %li\n",
 		   (long)atomic_long_read(&perf_stats.debug_tl_out_timer));
 	seq_printf(m, "Number of stop polling calls\t\t\t: %li\n",
 		   (long)atomic_long_read(&perf_stats.debug_stop_polling));
 	seq_printf(m, "AI inbound tasklet loops after stop polling\t: %li\n",
 		   (long)atomic_long_read(&perf_stats.thinint_inbound_loop2));
+	seq_printf(m, "QEBSM EQBS total/incomplete\t\t\t: %li/%li\n",
+		   (long)atomic_long_read(&perf_stats.debug_eqbs_all),
+		   (long)atomic_long_read(&perf_stats.debug_eqbs_incomplete));
+	seq_printf(m, "QEBSM SQBS total/incomplete\t\t\t: %li/%li\n",
+		   (long)atomic_long_read(&perf_stats.debug_sqbs_all),
+		   (long)atomic_long_read(&perf_stats.debug_sqbs_incomplete));
 	seq_printf(m, "\n");
 	return 0;
 }
diff --git a/drivers/s390/cio/qdio_perf.h b/drivers/s390/cio/qdio_perf.h
index 5c406a8..7821ac4 100644
--- a/drivers/s390/cio/qdio_perf.h
+++ b/drivers/s390/cio/qdio_perf.h
@@ -36,10 +36,15 @@
 	atomic_long_t inbound_handler;
 	atomic_long_t outbound_handler;
 	atomic_long_t fast_requeue;
+	atomic_long_t outbound_target_full;
 
 	/* for debugging */
 	atomic_long_t debug_tl_out_timer;
 	atomic_long_t debug_stop_polling;
+	atomic_long_t debug_eqbs_all;
+	atomic_long_t debug_eqbs_incomplete;
+	atomic_long_t debug_sqbs_all;
+	atomic_long_t debug_sqbs_incomplete;
 };
 
 extern struct qdio_perf_stats perf_stats;
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index a0b6b46..c08356b 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -117,17 +117,16 @@
 	q->mask = 1 << (31 - i);
 	q->nr = i;
 	q->handler = handler;
+	spin_lock_init(&q->lock);
 }
 
 static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,
-				void **sbals_array, char *dbf_text, int i)
+				void **sbals_array, int i)
 {
 	struct qdio_q *prev;
 	int j;
 
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
-	QDIO_DBF_HEX0(0, setup, &q, sizeof(void *));
-
+	DBF_HEX(&q, sizeof(void *));
 	q->sl = (struct sl *)((char *)q->slib + PAGE_SIZE / 2);
 
 	/* fill in sbal */
@@ -150,31 +149,26 @@
 	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
 		q->sl->element[j].sbal = (unsigned long)q->sbal[j];
 
-	QDIO_DBF_TEXT2(0, setup, "sl-sb-b0");
-	QDIO_DBF_HEX2(0, setup, q->sl, sizeof(void *));
-	QDIO_DBF_HEX2(0, setup, &q->slsb, sizeof(void *));
-	QDIO_DBF_HEX2(0, setup, q->sbal, sizeof(void *));
+	DBF_EVENT("sl-slsb-sbal");
+	DBF_HEX(q->sl, sizeof(void *));
+	DBF_HEX(&q->slsb, sizeof(void *));
+	DBF_HEX(q->sbal, sizeof(void *));
 }
 
 static void setup_queues(struct qdio_irq *irq_ptr,
 			 struct qdio_initialize *qdio_init)
 {
-	char dbf_text[20];
 	struct qdio_q *q;
 	void **input_sbal_array = qdio_init->input_sbal_addr_array;
 	void **output_sbal_array = qdio_init->output_sbal_addr_array;
 	int i;
 
-	sprintf(dbf_text, "qset%4x", qdio_init->cdev->private->schid.sch_no);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
-
 	for_each_input_queue(irq_ptr, q, i) {
-		sprintf(dbf_text, "in-q%4x", i);
+		DBF_EVENT("in-q:%1d", i);
 		setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i);
 
 		q->is_input_q = 1;
-		spin_lock_init(&q->u.in.lock);
-		setup_storage_lists(q, irq_ptr, input_sbal_array, dbf_text, i);
+		setup_storage_lists(q, irq_ptr, input_sbal_array, i);
 		input_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
 
 		if (is_thinint_irq(irq_ptr))
@@ -186,12 +180,11 @@
 	}
 
 	for_each_output_queue(irq_ptr, q, i) {
-		sprintf(dbf_text, "outq%4x", i);
+		DBF_EVENT("outq:%1d", i);
 		setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i);
 
 		q->is_input_q = 0;
-		setup_storage_lists(q, irq_ptr, output_sbal_array,
-				    dbf_text, i);
+		setup_storage_lists(q, irq_ptr, output_sbal_array, i);
 		output_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
 
 		tasklet_init(&q->tasklet, qdio_outbound_processing,
@@ -222,8 +215,6 @@
 static void check_and_setup_qebsm(struct qdio_irq *irq_ptr,
 				  unsigned char qdioac, unsigned long token)
 {
-	char dbf_text[15];
-
 	if (!(irq_ptr->qib.rflags & QIB_RFLAGS_ENABLE_QEBSM))
 		goto no_qebsm;
 	if (!(qdioac & AC1_SC_QEBSM_AVAILABLE) ||
@@ -232,33 +223,41 @@
 
 	irq_ptr->sch_token = token;
 
-	QDIO_DBF_TEXT0(0, setup, "V=V:1");
-	sprintf(dbf_text, "%8lx", irq_ptr->sch_token);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
+	DBF_EVENT("V=V:1");
+	DBF_EVENT("%8lx", irq_ptr->sch_token);
 	return;
 
 no_qebsm:
 	irq_ptr->sch_token = 0;
 	irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM;
-	QDIO_DBF_TEXT0(0, setup, "noV=V");
+	DBF_EVENT("noV=V");
 }
 
-static int __get_ssqd_info(struct qdio_irq *irq_ptr)
+/*
+ * If there is a qdio_irq we use the chsc_page and store the information
+ * in the qdio_irq, otherwise we copy it to the specified structure.
+ */
+int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr,
+			struct subchannel_id *schid,
+			struct qdio_ssqd_desc *data)
 {
 	struct chsc_ssqd_area *ssqd;
 	int rc;
 
-	QDIO_DBF_TEXT0(0, setup, "getssqd");
-	ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page;
+	DBF_EVENT("getssqd:%4x", schid->sch_no);
+	if (irq_ptr != NULL)
+		ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page;
+	else
+		ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL);
 	memset(ssqd, 0, PAGE_SIZE);
 
 	ssqd->request = (struct chsc_header) {
 		.length = 0x0010,
 		.code	= 0x0024,
 	};
-	ssqd->first_sch = irq_ptr->schid.sch_no;
-	ssqd->last_sch = irq_ptr->schid.sch_no;
-	ssqd->ssid = irq_ptr->schid.ssid;
+	ssqd->first_sch = schid->sch_no;
+	ssqd->last_sch = schid->sch_no;
+	ssqd->ssid = schid->ssid;
 
 	if (chsc(ssqd))
 		return -EIO;
@@ -268,27 +267,29 @@
 
 	if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) ||
 	    !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) ||
-	    (ssqd->qdio_ssqd.sch != irq_ptr->schid.sch_no))
+	    (ssqd->qdio_ssqd.sch != schid->sch_no))
 		return -EINVAL;
 
-	memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd,
-	       sizeof(struct qdio_ssqd_desc));
+	if (irq_ptr != NULL)
+		memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd,
+		       sizeof(struct qdio_ssqd_desc));
+	else {
+		memcpy(data, &ssqd->qdio_ssqd,
+		       sizeof(struct qdio_ssqd_desc));
+		free_page((unsigned long)ssqd);
+	}
 	return 0;
 }
 
 void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr)
 {
 	unsigned char qdioac;
-	char dbf_text[15];
 	int rc;
 
-	rc = __get_ssqd_info(irq_ptr);
+	rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL);
 	if (rc) {
-		QDIO_DBF_TEXT2(0, setup, "ssqdasig");
-		sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no);
-		QDIO_DBF_TEXT2(0, setup, dbf_text);
-		sprintf(dbf_text, "rc:%d", rc);
-		QDIO_DBF_TEXT2(0, setup, dbf_text);
+		DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no);
+		DBF_ERROR("rc:%x", rc);
 		/* all flags set, worst case */
 		qdioac = AC1_SIGA_INPUT_NEEDED | AC1_SIGA_OUTPUT_NEEDED |
 			 AC1_SIGA_SYNC_NEEDED;
@@ -297,9 +298,7 @@
 
 	check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token);
 	process_ac_flags(irq_ptr, qdioac);
-
-	sprintf(dbf_text, "qdioac%2x", qdioac);
-	QDIO_DBF_TEXT2(0, setup, dbf_text);
+	DBF_EVENT("qdioac:%4x", qdioac);
 }
 
 void qdio_release_memory(struct qdio_irq *irq_ptr)
@@ -419,7 +418,7 @@
 	/* get qdio commands */
 	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE);
 	if (!ciw) {
-		QDIO_DBF_TEXT2(1, setup, "no eq");
+		DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no);
 		rc = -EINVAL;
 		goto out_err;
 	}
@@ -427,7 +426,7 @@
 
 	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE);
 	if (!ciw) {
-		QDIO_DBF_TEXT2(1, setup, "no aq");
+		DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no);
 		rc = -EINVAL;
 		goto out_err;
 	}
@@ -447,56 +446,38 @@
 {
 	char s[80];
 
-	sprintf(s, "qdio: %s ", dev_name(&cdev->dev));
-	switch (irq_ptr->qib.qfmt) {
-	case QDIO_QETH_QFMT:
-		sprintf(s + strlen(s), "OSA ");
-		break;
-	case QDIO_ZFCP_QFMT:
-		sprintf(s + strlen(s), "ZFCP ");
-		break;
-	case QDIO_IQDIO_QFMT:
-		sprintf(s + strlen(s), "HS ");
-		break;
-	}
-	sprintf(s + strlen(s), "on SC %x using ", irq_ptr->schid.sch_no);
-	sprintf(s + strlen(s), "AI:%d ", is_thinint_irq(irq_ptr));
-	sprintf(s + strlen(s), "QEBSM:%d ", (irq_ptr->sch_token) ? 1 : 0);
-	sprintf(s + strlen(s), "PCI:%d ",
-		(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0);
-	sprintf(s + strlen(s), "TDD:%d ", css_general_characteristics.aif_tdd);
-	sprintf(s + strlen(s), "SIGA:");
-	sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.input) ? "R" : " ");
-	sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.output) ? "W" : " ");
-	sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.sync) ? "S" : " ");
-	sprintf(s + strlen(s), "%s",
-		(!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ");
-	sprintf(s + strlen(s), "%s",
-		(!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ");
-	sprintf(s + strlen(s), "%s",
-		(!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " ");
-	sprintf(s + strlen(s), "\n");
+	snprintf(s, 80, "qdio: %s %s on SC %x using "
+		 "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s%s\n",
+		 dev_name(&cdev->dev),
+		 (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" :
+			((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"),
+		 irq_ptr->schid.sch_no,
+		 is_thinint_irq(irq_ptr),
+		 (irq_ptr->sch_token) ? 1 : 0,
+		 (irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0,
+		 css_general_characteristics.aif_tdd,
+		 (irq_ptr->siga_flag.input) ? "R" : " ",
+		 (irq_ptr->siga_flag.output) ? "W" : " ",
+		 (irq_ptr->siga_flag.sync) ? "S" : " ",
+		 (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ",
+		 (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ",
+		 (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " ");
 	printk(KERN_INFO "%s", s);
 }
 
 int __init qdio_setup_init(void)
 {
-	char dbf_text[15];
-
 	qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q),
 					 256, 0, NULL);
 	if (!qdio_q_cache)
 		return -ENOMEM;
 
 	/* Check for OSA/FCP thin interrupts (bit 67). */
-	sprintf(dbf_text, "thini%1x",
-		(css_general_characteristics.aif_osa) ? 1 : 0);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
+	DBF_EVENT("thinint:%1d",
+		  (css_general_characteristics.aif_osa) ? 1 : 0);
 
 	/* Check for QEBSM support in general (bit 58). */
-	sprintf(dbf_text, "cssQBS:%1x",
-		(qebsm_possible()) ? 1 : 0);
-	QDIO_DBF_TEXT0(0, setup, dbf_text);
+	DBF_EVENT("cssQEBSM:%1d", (qebsm_possible()) ? 1 : 0);
 	return 0;
 }
 
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index ea7f614..8e90e14 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -125,13 +125,13 @@
 
 static inline int tiqdio_inbound_q_done(struct qdio_q *q)
 {
-	unsigned char state;
+	unsigned char state = 0;
 
 	if (!atomic_read(&q->nr_buf_used))
 		return 1;
 
 	qdio_siga_sync_q(q);
-	get_buf_state(q, q->first_to_check, &state);
+	get_buf_state(q, q->first_to_check, &state, 0);
 
 	if (state == SLSB_P_INPUT_PRIMED)
 		/* more work coming */
@@ -258,8 +258,6 @@
 static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset)
 {
 	struct scssc_area *scssc_area;
-	char dbf_text[15];
-	void *ptr;
 	int rc;
 
 	scssc_area = (struct scssc_area *)irq_ptr->chsc_page;
@@ -294,19 +292,15 @@
 
 	rc = chsc_error_from_response(scssc_area->response.code);
 	if (rc) {
-		sprintf(dbf_text, "sidR%4x", scssc_area->response.code);
-		QDIO_DBF_TEXT1(0, trace, dbf_text);
-		QDIO_DBF_TEXT1(0, setup, dbf_text);
-		ptr = &scssc_area->response;
-		QDIO_DBF_HEX2(1, setup, &ptr, QDIO_DBF_SETUP_LEN);
+		DBF_ERROR("%4x SSI r:%4x", irq_ptr->schid.sch_no,
+			  scssc_area->response.code);
+		DBF_ERROR_HEX(&scssc_area->response, sizeof(void *));
 		return rc;
 	}
 
-	QDIO_DBF_TEXT2(0, setup, "setscind");
-	QDIO_DBF_HEX2(0, setup, &scssc_area->summary_indicator_addr,
-		      sizeof(unsigned long));
-	QDIO_DBF_HEX2(0, setup, &scssc_area->subchannel_indicator_addr,
-		      sizeof(unsigned long));
+	DBF_EVENT("setscind");
+	DBF_HEX(&scssc_area->summary_indicator_addr, sizeof(unsigned long));
+	DBF_HEX(&scssc_area->subchannel_indicator_addr,	sizeof(unsigned long));
 	return 0;
 }
 
@@ -327,14 +321,11 @@
 
 int __init tiqdio_register_thinints(void)
 {
-	char dbf_text[20];
-
 	isc_register(QDIO_AIRQ_ISC);
 	tiqdio_alsi = s390_register_adapter_interrupt(&tiqdio_thinint_handler,
 						      NULL, QDIO_AIRQ_ISC);
 	if (IS_ERR(tiqdio_alsi)) {
-		sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_alsi));
-		QDIO_DBF_TEXT0(0, setup, dbf_text);
+		DBF_EVENT("RTI:%lx", PTR_ERR(tiqdio_alsi));
 		tiqdio_alsi = NULL;
 		isc_unregister(QDIO_AIRQ_ISC);
 		return -ENOMEM;
@@ -360,7 +351,7 @@
 	if (!is_thinint_irq(irq_ptr))
 		return;
 	irq_ptr->dsci = get_indicator();
-	QDIO_DBF_HEX1(0, setup, &irq_ptr->dsci, sizeof(void *));
+	DBF_HEX(&irq_ptr->dsci, sizeof(void *));
 }
 
 void qdio_shutdown_thinint(struct qdio_irq *irq_ptr)
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index e3fe683..1f5f5d2 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -5,6 +5,7 @@
  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
  *	      Martin Schwidefsky <schwidefsky@de.ibm.com>
  *	      Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *	      Felix Beck <felix.beck@de.ibm.com>
  *
  * Adjunct processor bus.
  *
@@ -23,6 +24,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define KMSG_COMPONENT "ap"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -34,6 +38,10 @@
 #include <linux/mutex.h>
 #include <asm/s390_rdev.h>
 #include <asm/reset.h>
+#include <asm/airq.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/isc.h>
 #include <linux/hrtimer.h>
 #include <linux/ktime.h>
 
@@ -46,6 +54,7 @@
 static int ap_poll_thread_start(void);
 static void ap_poll_thread_stop(void);
 static void ap_request_timeout(unsigned long);
+static inline void ap_schedule_poll_timer(void);
 
 /*
  * Module description.
@@ -68,7 +77,7 @@
 MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off).");
 
 static struct device *ap_root_device = NULL;
-static DEFINE_SPINLOCK(ap_device_lock);
+static DEFINE_SPINLOCK(ap_device_list_lock);
 static LIST_HEAD(ap_device_list);
 
 /*
@@ -80,19 +89,29 @@
 static DECLARE_WORK(ap_config_work, ap_scan_bus);
 
 /*
- * Tasklet & timer for AP request polling.
+ * Tasklet & timer for AP request polling and interrupts
  */
 static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0);
 static atomic_t ap_poll_requests = ATOMIC_INIT(0);
 static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait);
 static struct task_struct *ap_poll_kthread = NULL;
 static DEFINE_MUTEX(ap_poll_thread_mutex);
+static void *ap_interrupt_indicator;
 static struct hrtimer ap_poll_timer;
 /* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds.
  * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/
 static unsigned long long poll_timeout = 250000;
 
 /**
+ * ap_using_interrupts() - Returns non-zero if interrupt support is
+ * available.
+ */
+static inline int ap_using_interrupts(void)
+{
+	return ap_interrupt_indicator != NULL;
+}
+
+/**
  * ap_intructions_available() - Test if AP instructions are available.
  *
  * Returns 0 if the AP instructions are installed.
@@ -113,6 +132,23 @@
 }
 
 /**
+ * ap_interrupts_available(): Test if AP interrupts are available.
+ *
+ * Returns 1 if AP interrupts are available.
+ */
+static int ap_interrupts_available(void)
+{
+	unsigned long long facility_bits[2];
+
+	if (stfle(facility_bits, 2) <= 1)
+		return 0;
+	if (!(facility_bits[0] & (1ULL << 61)) ||
+	    !(facility_bits[1] & (1ULL << 62)))
+		return 0;
+	return 1;
+}
+
+/**
  * ap_test_queue(): Test adjunct processor queue.
  * @qid: The AP queue number
  * @queue_depth: Pointer to queue depth value
@@ -152,6 +188,80 @@
 	return reg1;
 }
 
+#ifdef CONFIG_64BIT
+/**
+ * ap_queue_interruption_control(): Enable interruption for a specific AP.
+ * @qid: The AP queue number
+ * @ind: The notification indicator byte
+ *
+ * Returns AP queue status.
+ */
+static inline struct ap_queue_status
+ap_queue_interruption_control(ap_qid_t qid, void *ind)
+{
+	register unsigned long reg0 asm ("0") = qid | 0x03000000UL;
+	register unsigned long reg1_in asm ("1") = 0x0000800000000000UL | AP_ISC;
+	register struct ap_queue_status reg1_out asm ("1");
+	register void *reg2 asm ("2") = ind;
+	asm volatile(
+		".long 0xb2af0000"		/* PQAP(RAPQ) */
+		: "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2)
+		:
+		: "cc" );
+	return reg1_out;
+}
+#endif
+
+/**
+ * ap_queue_enable_interruption(): Enable interruption on an AP.
+ * @qid: The AP queue number
+ * @ind: the notification indicator byte
+ *
+ * Enables interruption on AP queue via ap_queue_interruption_control(). Based
+ * on the return value it waits a while and tests the AP queue if interrupts
+ * have been switched on using ap_test_queue().
+ */
+static int ap_queue_enable_interruption(ap_qid_t qid, void *ind)
+{
+#ifdef CONFIG_64BIT
+	struct ap_queue_status status;
+	int t_depth, t_device_type, rc, i;
+
+	rc = -EBUSY;
+	status = ap_queue_interruption_control(qid, ind);
+
+	for (i = 0; i < AP_MAX_RESET; i++) {
+		switch (status.response_code) {
+		case AP_RESPONSE_NORMAL:
+			if (status.int_enabled)
+				return 0;
+			break;
+		case AP_RESPONSE_RESET_IN_PROGRESS:
+		case AP_RESPONSE_BUSY:
+			break;
+		case AP_RESPONSE_Q_NOT_AVAIL:
+		case AP_RESPONSE_DECONFIGURED:
+		case AP_RESPONSE_CHECKSTOPPED:
+		case AP_RESPONSE_INVALID_ADDRESS:
+			return -ENODEV;
+		case AP_RESPONSE_OTHERWISE_CHANGED:
+			if (status.int_enabled)
+				return 0;
+			break;
+		default:
+			break;
+		}
+		if (i < AP_MAX_RESET - 1) {
+			udelay(5);
+			status = ap_test_queue(qid, &t_depth, &t_device_type);
+		}
+	}
+	return rc;
+#else
+	return -EINVAL;
+#endif
+}
+
 /**
  * __ap_send(): Send message to adjunct processor queue.
  * @qid: The AP queue number
@@ -295,6 +405,11 @@
 		case AP_RESPONSE_CHECKSTOPPED:
 			rc = -ENODEV;
 			break;
+		case AP_RESPONSE_INVALID_ADDRESS:
+			rc = -ENODEV;
+			break;
+		case AP_RESPONSE_OTHERWISE_CHANGED:
+			break;
 		case AP_RESPONSE_BUSY:
 			break;
 		default:
@@ -345,6 +460,15 @@
 			status = ap_test_queue(qid, &dummy, &dummy);
 		}
 	}
+	if (rc == 0 && ap_using_interrupts()) {
+		rc = ap_queue_enable_interruption(qid, ap_interrupt_indicator);
+		/* If interruption mode is supported by the machine,
+		* but an AP can not be enabled for interruption then
+		* the AP will be discarded.    */
+		if (rc)
+			pr_err("Registering adapter interrupts for "
+			       "AP %d failed\n", AP_QID_DEVICE(qid));
+	}
 	return rc;
 }
 
@@ -397,16 +521,16 @@
 	struct ap_device *ap_dev = to_ap_dev(dev);
 	return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->device_type);
 }
-static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL);
 
+static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL);
 static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
 {
 	struct ap_device *ap_dev = to_ap_dev(dev);
 	return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->queue_depth);
 }
-static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL);
 
+static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL);
 static ssize_t ap_request_count_show(struct device *dev,
 				     struct device_attribute *attr,
 				     char *buf)
@@ -509,9 +633,9 @@
 	ap_dev->drv = ap_drv;
 	rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;
 	if (!rc) {
-		spin_lock_bh(&ap_device_lock);
+		spin_lock_bh(&ap_device_list_lock);
 		list_add(&ap_dev->list, &ap_device_list);
-		spin_unlock_bh(&ap_device_lock);
+		spin_unlock_bh(&ap_device_list_lock);
 	}
 	return rc;
 }
@@ -553,9 +677,9 @@
 
 	ap_flush_queue(ap_dev);
 	del_timer_sync(&ap_dev->timeout);
-	spin_lock_bh(&ap_device_lock);
+	spin_lock_bh(&ap_device_list_lock);
 	list_del_init(&ap_dev->list);
-	spin_unlock_bh(&ap_device_lock);
+	spin_unlock_bh(&ap_device_list_lock);
 	if (ap_drv->remove)
 		ap_drv->remove(ap_dev);
 	spin_lock_bh(&ap_dev->lock);
@@ -599,6 +723,14 @@
 	return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time);
 }
 
+static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			ap_using_interrupts() ? 1 : 0);
+}
+
+static BUS_ATTR(ap_interrupts, 0444, ap_interrupts_show, NULL);
+
 static ssize_t ap_config_time_store(struct bus_type *bus,
 				    const char *buf, size_t count)
 {
@@ -653,7 +785,8 @@
 	ktime_t hr_time;
 
 	/* 120 seconds = maximum poll interval */
-	if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || time > 120000000000)
+	if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 ||
+	    time > 120000000000ULL)
 		return -EINVAL;
 	poll_timeout = time;
 	hr_time = ktime_set(0, poll_timeout);
@@ -672,6 +805,7 @@
 	&bus_attr_ap_domain,
 	&bus_attr_config_time,
 	&bus_attr_poll_thread,
+	&bus_attr_ap_interrupts,
 	&bus_attr_poll_timeout,
 	NULL,
 };
@@ -814,6 +948,11 @@
 	return rc;
 }
 
+static void ap_interrupt_handler(void *unused1, void *unused2)
+{
+	tasklet_schedule(&ap_tasklet);
+}
+
 /**
  * __ap_scan_bus(): Scan the AP bus.
  * @dev: Pointer to device
@@ -928,6 +1067,8 @@
  */
 static inline void ap_schedule_poll_timer(void)
 {
+	if (ap_using_interrupts())
+		return;
 	if (hrtimer_is_queued(&ap_poll_timer))
 		return;
 	hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout),
@@ -1181,7 +1322,7 @@
 		ap_dev->unregistered = 1;
 }
 
-static int __ap_poll_all(struct ap_device *ap_dev, unsigned long *flags)
+static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags)
 {
 	spin_lock(&ap_dev->lock);
 	if (!ap_dev->unregistered) {
@@ -1207,13 +1348,19 @@
 	unsigned long flags;
 	struct ap_device *ap_dev;
 
+	/* Reset the indicator if interrupts are used. Thus new interrupts can
+	 * be received. Doing it in the beginning of the tasklet is therefor
+	 * important that no requests on any AP get lost.
+	 */
+	if (ap_using_interrupts())
+		xchg((u8 *)ap_interrupt_indicator, 0);
 	do {
 		flags = 0;
-		spin_lock(&ap_device_lock);
+		spin_lock(&ap_device_list_lock);
 		list_for_each_entry(ap_dev, &ap_device_list, list) {
-			__ap_poll_all(ap_dev, &flags);
+			__ap_poll_device(ap_dev, &flags);
 		}
-		spin_unlock(&ap_device_lock);
+		spin_unlock(&ap_device_list_lock);
 	} while (flags & 1);
 	if (flags & 2)
 		ap_schedule_poll_timer();
@@ -1253,11 +1400,11 @@
 		remove_wait_queue(&ap_poll_wait, &wait);
 
 		flags = 0;
-		spin_lock_bh(&ap_device_lock);
+		spin_lock_bh(&ap_device_list_lock);
 		list_for_each_entry(ap_dev, &ap_device_list, list) {
-			__ap_poll_all(ap_dev, &flags);
+			__ap_poll_device(ap_dev, &flags);
 		}
-		spin_unlock_bh(&ap_device_lock);
+		spin_unlock_bh(&ap_device_list_lock);
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&ap_poll_wait, &wait);
@@ -1268,6 +1415,8 @@
 {
 	int rc;
 
+	if (ap_using_interrupts())
+		return 0;
 	mutex_lock(&ap_poll_thread_mutex);
 	if (!ap_poll_kthread) {
 		ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll");
@@ -1301,8 +1450,12 @@
 {
 	struct ap_device *ap_dev = (struct ap_device *) data;
 
-	if (ap_dev->reset == AP_RESET_ARMED)
+	if (ap_dev->reset == AP_RESET_ARMED) {
 		ap_dev->reset = AP_RESET_DO;
+
+		if (ap_using_interrupts())
+			tasklet_schedule(&ap_tasklet);
+	}
 }
 
 static void ap_reset_domain(void)
@@ -1337,14 +1490,25 @@
 	int rc, i;
 
 	if (ap_domain_index < -1 || ap_domain_index >= AP_DOMAINS) {
-		printk(KERN_WARNING "Invalid param: domain = %d. "
-		       " Not loading.\n", ap_domain_index);
+		pr_warning("%d is not a valid cryptographic domain\n",
+			   ap_domain_index);
 		return -EINVAL;
 	}
 	if (ap_instructions_available() != 0) {
-		printk(KERN_WARNING "AP instructions not installed.\n");
+		pr_warning("The hardware system does not support "
+			   "AP instructions\n");
 		return -ENODEV;
 	}
+	if (ap_interrupts_available()) {
+		isc_register(AP_ISC);
+		ap_interrupt_indicator = s390_register_adapter_interrupt(
+			&ap_interrupt_handler, NULL, AP_ISC);
+		if (IS_ERR(ap_interrupt_indicator)) {
+			ap_interrupt_indicator = NULL;
+			isc_unregister(AP_ISC);
+		}
+	}
+
 	register_reset_call(&ap_reset_call);
 
 	/* Create /sys/bus/ap. */
@@ -1408,6 +1572,10 @@
 	bus_unregister(&ap_bus_type);
 out:
 	unregister_reset_call(&ap_reset_call);
+	if (ap_using_interrupts()) {
+		s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC);
+		isc_unregister(AP_ISC);
+	}
 	return rc;
 }
 
@@ -1443,6 +1611,10 @@
 		bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
 	bus_unregister(&ap_bus_type);
 	unregister_reset_call(&ap_reset_call);
+	if (ap_using_interrupts()) {
+		s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC);
+		isc_unregister(AP_ISC);
+	}
 }
 
 #ifndef CONFIG_ZCRYPT_MONOLITHIC
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 446378b..a353622 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -5,6 +5,7 @@
  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
  *	      Martin Schwidefsky <schwidefsky@de.ibm.com>
  *	      Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *	      Felix Beck <felix.beck@de.ibm.com>
  *
  * Adjunct processor bus header file.
  *
@@ -67,7 +68,8 @@
 	unsigned int queue_empty	: 1;
 	unsigned int replies_waiting	: 1;
 	unsigned int queue_full		: 1;
-	unsigned int pad1		: 5;
+	unsigned int pad1		: 4;
+	unsigned int int_enabled	: 1;
 	unsigned int response_code	: 8;
 	unsigned int pad2		: 16;
 };
@@ -78,6 +80,8 @@
 #define AP_RESPONSE_DECONFIGURED	0x03
 #define AP_RESPONSE_CHECKSTOPPED	0x04
 #define AP_RESPONSE_BUSY		0x05
+#define AP_RESPONSE_INVALID_ADDRESS	0x06
+#define AP_RESPONSE_OTHERWISE_CHANGED	0x07
 #define AP_RESPONSE_Q_FULL		0x10
 #define AP_RESPONSE_NO_PENDING_REPLY	0x10
 #define AP_RESPONSE_INDEX_TOO_BIG	0x11
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index 54f4cbc..326ea08 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -264,17 +264,21 @@
 		.type = TYPE82_RSP_CODE,
 		.reply_code = REP82_ERROR_MACHINE_FAILURE,
 	};
-	struct type80_hdr *t80h = reply->message;
+	struct type80_hdr *t80h;
 	int length;
 
 	/* Copy the reply message to the request message buffer. */
-	if (IS_ERR(reply))
+	if (IS_ERR(reply)) {
 		memcpy(msg->message, &error_reply, sizeof(error_reply));
-	else if (t80h->type == TYPE80_RSP_CODE) {
+		goto out;
+	}
+	t80h = reply->message;
+	if (t80h->type == TYPE80_RSP_CODE) {
 		length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len);
 		memcpy(msg->message, reply->message, length);
 	} else
 		memcpy(msg->message, reply->message, sizeof error_reply);
+out:
 	complete((struct completion *) msg->private);
 }
 
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c
index 12da481..17ba81b 100644
--- a/drivers/s390/crypto/zcrypt_pcica.c
+++ b/drivers/s390/crypto/zcrypt_pcica.c
@@ -247,17 +247,21 @@
 		.type = TYPE82_RSP_CODE,
 		.reply_code = REP82_ERROR_MACHINE_FAILURE,
 	};
-	struct type84_hdr *t84h = reply->message;
+	struct type84_hdr *t84h;
 	int length;
 
 	/* Copy the reply message to the request message buffer. */
-	if (IS_ERR(reply))
+	if (IS_ERR(reply)) {
 		memcpy(msg->message, &error_reply, sizeof(error_reply));
-	else if (t84h->code == TYPE84_RSP_CODE) {
+		goto out;
+	}
+	t84h = reply->message;
+	if (t84h->code == TYPE84_RSP_CODE) {
 		length = min(PCICA_MAX_RESPONSE_SIZE, (int) t84h->len);
 		memcpy(msg->message, reply->message, length);
 	} else
 		memcpy(msg->message, reply->message, sizeof error_reply);
+out:
 	complete((struct completion *) msg->private);
 }
 
diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c
index 779952c..f4b0c47 100644
--- a/drivers/s390/crypto/zcrypt_pcicc.c
+++ b/drivers/s390/crypto/zcrypt_pcicc.c
@@ -447,19 +447,23 @@
 		.type = TYPE82_RSP_CODE,
 		.reply_code = REP82_ERROR_MACHINE_FAILURE,
 	};
-	struct type86_reply *t86r = reply->message;
+	struct type86_reply *t86r;
 	int length;
 
 	/* Copy the reply message to the request message buffer. */
-	if (IS_ERR(reply))
+	if (IS_ERR(reply)) {
 		memcpy(msg->message, &error_reply, sizeof(error_reply));
-	else if (t86r->hdr.type == TYPE86_RSP_CODE &&
+		goto out;
+	}
+	t86r = reply->message;
+	if (t86r->hdr.type == TYPE86_RSP_CODE &&
 		 t86r->cprb.cprb_ver_id == 0x01) {
 		length = sizeof(struct type86_reply) + t86r->length - 2;
 		length = min(PCICC_MAX_RESPONSE_SIZE, length);
 		memcpy(msg->message, reply->message, length);
 	} else
 		memcpy(msg->message, reply->message, sizeof error_reply);
+out:
 	complete((struct completion *) msg->private);
 }
 
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index d8ad36f..e7a1e22 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -635,13 +635,16 @@
 	};
 	struct response_type *resp_type =
 		(struct response_type *) msg->private;
-	struct type86x_reply *t86r = reply->message;
+	struct type86x_reply *t86r;
 	int length;
 
 	/* Copy the reply message to the request message buffer. */
-	if (IS_ERR(reply))
+	if (IS_ERR(reply)) {
 		memcpy(msg->message, &error_reply, sizeof(error_reply));
-	else if (t86r->hdr.type == TYPE86_RSP_CODE &&
+		goto out;
+	}
+	t86r = reply->message;
+	if (t86r->hdr.type == TYPE86_RSP_CODE &&
 		 t86r->cprbx.cprb_ver_id == 0x02) {
 		switch (resp_type->type) {
 		case PCIXCC_RESPONSE_TYPE_ICA:
@@ -660,6 +663,7 @@
 		}
 	} else
 		memcpy(msg->message, reply->message, sizeof error_reply);
+out:
 	complete(&(resp_type->work));
 }
 
diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c
index 4277655..f29c708 100644
--- a/drivers/s390/net/ctcm_fsms.c
+++ b/drivers/s390/net/ctcm_fsms.c
@@ -13,6 +13,9 @@
 #undef DEBUGDATA
 #undef DEBUGCCW
 
+#define KMSG_COMPONENT "ctcm"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -190,21 +193,22 @@
 void ctcm_ccw_check_rc(struct channel *ch, int rc, char *msg)
 {
 	CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR,
-			"%s(%s): %s: %04x\n",
-				CTCM_FUNTAIL, ch->id, msg, rc);
+		"%s(%s): %s: %04x\n",
+		CTCM_FUNTAIL, ch->id, msg, rc);
 	switch (rc) {
 	case -EBUSY:
-		ctcm_pr_warn("%s (%s): Busy !\n", ch->id, msg);
+		pr_info("%s: The communication peer is busy\n",
+			ch->id);
 		fsm_event(ch->fsm, CTC_EVENT_IO_EBUSY, ch);
 		break;
 	case -ENODEV:
-		ctcm_pr_emerg("%s (%s): Invalid device called for IO\n",
-			     ch->id, msg);
+		pr_err("%s: The specified target device is not valid\n",
+		       ch->id);
 		fsm_event(ch->fsm, CTC_EVENT_IO_ENODEV, ch);
 		break;
 	default:
-		ctcm_pr_emerg("%s (%s): Unknown error in do_IO %04x\n",
-			     ch->id, msg, rc);
+		pr_err("An I/O operation resulted in error %04x\n",
+		       rc);
 		fsm_event(ch->fsm, CTC_EVENT_IO_UNKNOWN, ch);
 	}
 }
@@ -886,8 +890,15 @@
 			fsm_newstate(fi, CTC_STATE_RXERR);
 			fsm_event(priv->fsm, DEV_EVENT_RXDOWN, dev);
 		}
-	} else
-		ctcm_pr_warn("%s: Error during RX init handshake\n", dev->name);
+	} else {
+		CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR,
+			"%s(%s): %s in %s", CTCM_FUNTAIL, ch->id,
+			ctc_ch_event_names[event], fsm_getstate_str(fi));
+
+		dev_warn(&dev->dev,
+			"Initialization failed with RX/TX init handshake "
+			"error %s\n", ctc_ch_event_names[event]);
+	}
 }
 
 /**
@@ -969,7 +980,9 @@
 			"%s(%s): %s in %s", CTCM_FUNTAIL, ch->id,
 			ctc_ch_event_names[event], fsm_getstate_str(fi));
 
-		ctcm_pr_warn("%s: Error during TX init handshake\n", dev->name);
+		dev_warn(&dev->dev,
+			"Initialization failed with RX/TX init handshake "
+			"error %s\n", ctc_ch_event_names[event]);
 	}
 }
 
@@ -2101,14 +2114,11 @@
 	CTCMY_DBF_DEV_NAME(TRACE, dev, "");
 
 	if (IS_MPC(priv)) {
-		ctcm_pr_info("ctcm: %s Restarting Device and "
-		       "MPC Group in 5 seconds\n",
-		       dev->name);
 		restart_timer = CTCM_TIME_1_SEC;
 	} else {
-		ctcm_pr_info("%s: Restarting\n", dev->name);
 		restart_timer = CTCM_TIME_5_SEC;
 	}
+	dev_info(&dev->dev, "Restarting device\n");
 
 	dev_action_stop(fi, event, arg);
 	fsm_event(priv->fsm, DEV_EVENT_STOP, dev);
@@ -2150,16 +2160,16 @@
 	case DEV_STATE_STARTWAIT_RX:
 		if (event == DEV_EVENT_RXUP) {
 			fsm_newstate(fi, DEV_STATE_RUNNING);
-			ctcm_pr_info("%s: connected with remote side\n",
-				    dev->name);
+			dev_info(&dev->dev,
+				"Connected with remote side\n");
 			ctcm_clear_busy(dev);
 		}
 		break;
 	case DEV_STATE_STARTWAIT_TX:
 		if (event == DEV_EVENT_TXUP) {
 			fsm_newstate(fi, DEV_STATE_RUNNING);
-			ctcm_pr_info("%s: connected with remote side\n",
-				    dev->name);
+			dev_info(&dev->dev,
+				"Connected with remote side\n");
 			ctcm_clear_busy(dev);
 		}
 		break;
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index a4e29836..2678573 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -21,6 +21,9 @@
 #undef DEBUGDATA
 #undef DEBUGCCW
 
+#define KMSG_COMPONENT "ctcm"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -281,14 +284,16 @@
 
 	switch (PTR_ERR(irb)) {
 	case -EIO:
-		ctcm_pr_warn("i/o-error on device %s\n", dev_name(&cdev->dev));
+		dev_err(&cdev->dev,
+			"An I/O-error occurred on the CTCM device\n");
 		break;
 	case -ETIMEDOUT:
-		ctcm_pr_warn("timeout on device %s\n", dev_name(&cdev->dev));
+		dev_err(&cdev->dev,
+			"An adapter hardware operation timed out\n");
 		break;
 	default:
-		ctcm_pr_warn("unknown error %ld on device %s\n",
-				PTR_ERR(irb), dev_name(&cdev->dev));
+		dev_err(&cdev->dev,
+			"An error occurred on the adapter hardware\n");
 	}
 	return PTR_ERR(irb);
 }
@@ -309,15 +314,17 @@
 	if (sense & SNS0_INTERVENTION_REQ) {
 		if (sense & 0x01) {
 			if (ch->sense_rc != 0x01) {
-				ctcm_pr_debug("%s: Interface disc. or Sel. "
-					      "reset (remote)\n", ch->id);
+				pr_notice(
+					"%s: The communication peer has "
+					"disconnected\n", ch->id);
 				ch->sense_rc = 0x01;
 			}
 			fsm_event(ch->fsm, CTC_EVENT_UC_RCRESET, ch);
 		} else {
 			if (ch->sense_rc != SNS0_INTERVENTION_REQ) {
-				ctcm_pr_debug("%s: System reset (remote)\n",
-					      ch->id);
+				pr_notice(
+					"%s: The remote operating system is "
+					"not available\n", ch->id);
 				ch->sense_rc = SNS0_INTERVENTION_REQ;
 			}
 			fsm_event(ch->fsm, CTC_EVENT_UC_RSRESET, ch);
@@ -1194,8 +1201,11 @@
 
 	/* Check for unsolicited interrupts. */
 	if (cgdev == NULL) {
-		ctcm_pr_warn("ctcm: Got unsolicited irq: c-%02x d-%02x\n",
-			     cstat, dstat);
+		CTCM_DBF_TEXT_(TRACE, CTC_DBF_ERROR,
+			"%s(%s) unsolicited irq: c-%02x d-%02x\n",
+			CTCM_FUNTAIL, dev_name(&cdev->dev), cstat, dstat);
+		dev_warn(&cdev->dev,
+			"The adapter received a non-specific IRQ\n");
 		return;
 	}
 
@@ -1207,31 +1217,34 @@
 	else if (priv->channel[WRITE]->cdev == cdev)
 		ch = priv->channel[WRITE];
 	else {
-		ctcm_pr_err("ctcm: Can't determine channel for interrupt, "
-			   "device %s\n", dev_name(&cdev->dev));
+		dev_err(&cdev->dev,
+			"%s: Internal error: Can't determine channel for "
+			"interrupt device %s\n",
+			__func__, dev_name(&cdev->dev));
+			/* Explain: inconsistent internal structures */
 		return;
 	}
 
 	dev = ch->netdev;
 	if (dev == NULL) {
-		ctcm_pr_crit("ctcm: %s dev=NULL bus_id=%s, ch=0x%p\n",
-				__func__, dev_name(&cdev->dev), ch);
+		dev_err(&cdev->dev,
+			"%s Internal error: net_device is NULL, ch = 0x%p\n",
+			__func__, ch);
+			/* Explain: inconsistent internal structures */
 		return;
 	}
 
-	CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG,
-		"%s(%s): int. for %s: cstat=%02x dstat=%02x",
-			CTCM_FUNTAIL, dev->name, ch->id, cstat, dstat);
-
 	/* Copy interruption response block. */
 	memcpy(ch->irb, irb, sizeof(struct irb));
 
+	/* Issue error message and return on subchannel error code */
 	if (irb->scsw.cmd.cstat) {
-	/* Check for good subchannel return code, otherwise error message */
 		fsm_event(ch->fsm, CTC_EVENT_SC_UNKNOWN, ch);
-		ctcm_pr_warn("%s: subchannel check for dev: %s - %02x %02x\n",
-			    dev->name, ch->id, irb->scsw.cmd.cstat,
-			    irb->scsw.cmd.dstat);
+		CTCM_DBF_TEXT_(TRACE, CTC_DBF_WARN,
+			"%s(%s): sub-ch check %s: cs=%02x ds=%02x",
+				CTCM_FUNTAIL, dev->name, ch->id, cstat, dstat);
+		dev_warn(&cdev->dev,
+				"A check occurred on the subchannel\n");
 		return;
 	}
 
@@ -1239,7 +1252,7 @@
 	if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
 		if ((irb->ecw[0] & ch->sense_rc) == 0)
 			/* print it only once */
-			CTCM_DBF_TEXT_(TRACE, CTC_DBF_INFO,
+			CTCM_DBF_TEXT_(TRACE, CTC_DBF_WARN,
 				"%s(%s): sense=%02x, ds=%02x",
 				CTCM_FUNTAIL, ch->id, irb->ecw[0], dstat);
 		ccw_unit_check(ch, irb->ecw[0]);
@@ -1574,6 +1587,11 @@
 
 	strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name));
 
+	dev_info(&dev->dev,
+		"setup OK : r/w = %s/%s, protocol : %d\n",
+			priv->channel[READ]->id,
+			priv->channel[WRITE]->id, priv->protocol);
+
 	CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO,
 		"setup(%s) OK : r/w = %s/%s, protocol : %d", dev->name,
 			priv->channel[READ]->id,
@@ -1687,7 +1705,7 @@
 {
 	unregister_cu3088_discipline(&ctcm_group_driver);
 	ctcm_unregister_dbf_views();
-	ctcm_pr_info("CTCM driver unloaded\n");
+	pr_info("CTCM driver unloaded\n");
 }
 
 /*
@@ -1695,7 +1713,7 @@
  */
 static void print_banner(void)
 {
-	printk(KERN_INFO "CTCM driver initialized\n");
+	pr_info("CTCM driver initialized\n");
 }
 
 /**
@@ -1717,8 +1735,8 @@
 	ret = register_cu3088_discipline(&ctcm_group_driver);
 	if (ret) {
 		ctcm_unregister_dbf_views();
-		ctcm_pr_crit("ctcm_init failed with register_cu3088_discipline "
-				"(rc = %d)\n", ret);
+		pr_err("%s / register_cu3088_discipline failed, ret = %d\n",
+			__func__, ret);
 		return ret;
 	}
 	print_banner();
diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h
index d77cce3..d925e73 100644
--- a/drivers/s390/net/ctcm_main.h
+++ b/drivers/s390/net/ctcm_main.h
@@ -41,12 +41,6 @@
 #define LOG_FLAG_NOMEM		8
 
 #define ctcm_pr_debug(fmt, arg...) printk(KERN_DEBUG fmt, ##arg)
-#define ctcm_pr_info(fmt, arg...) printk(KERN_INFO fmt, ##arg)
-#define ctcm_pr_notice(fmt, arg...) printk(KERN_NOTICE fmt, ##arg)
-#define ctcm_pr_warn(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
-#define ctcm_pr_emerg(fmt, arg...) printk(KERN_EMERG fmt, ##arg)
-#define ctcm_pr_err(fmt, arg...) printk(KERN_ERR fmt, ##arg)
-#define ctcm_pr_crit(fmt, arg...) printk(KERN_CRIT fmt, ##arg)
 
 #define CTCM_PR_DEBUG(fmt, arg...) \
 	do { \
diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c
index 19f5d5e..3db5f84 100644
--- a/drivers/s390/net/ctcm_mpc.c
+++ b/drivers/s390/net/ctcm_mpc.c
@@ -19,6 +19,9 @@
 #undef DEBUGDATA
 #undef DEBUGCCW
 
+#define KMSG_COMPONENT "ctcm"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -386,7 +389,7 @@
 		if (grp->allocchan_callback_retries < 4) {
 			if (grp->allochanfunc)
 				grp->allochanfunc(grp->port_num,
-					      grp->group_max_buflen);
+						  grp->group_max_buflen);
 		} else {
 			/* there are problems...bail out	    */
 			/* there may be a state mismatch so restart */
@@ -1232,8 +1235,9 @@
 
 	dev_kfree_skb_any(pskb);
 	if (sendrc == NET_RX_DROP) {
-		printk(KERN_WARNING "%s %s() NETWORK BACKLOG EXCEEDED"
-		       " - PACKET DROPPED\n", dev->name, __func__);
+		dev_warn(&dev->dev,
+			"The network backlog for %s is exceeded, "
+			"package dropped\n", __func__);
 		fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
 	}
 
@@ -1670,10 +1674,11 @@
 					CTCM_FUNTAIL, ch->id);
 		}
 	}
-
 done:
 	if (rc) {
-		ctcm_pr_info("ctcmpc	   :  %s() failed\n", __func__);
+		dev_warn(&dev->dev,
+			"The XID used in the MPC protocol is not valid, "
+			"rc = %d\n", rc);
 		priv->xid->xid2_flag2 = 0x40;
 		grp->saved_xid2->xid2_flag2 = 0x40;
 	}
diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c
index bb2d137..8452bb0 100644
--- a/drivers/s390/net/ctcm_sysfs.c
+++ b/drivers/s390/net/ctcm_sysfs.c
@@ -10,6 +10,9 @@
 #undef DEBUGDATA
 #undef DEBUGCCW
 
+#define KMSG_COMPONENT "ctcm"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/sysfs.h>
 #include "ctcm_main.h"
 
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 0825be8..acca667 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -26,6 +26,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define KMSG_COMPONENT		"lcs"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/if.h>
 #include <linux/netdevice.h>
@@ -54,8 +57,6 @@
 #error Cannot compile lcs.c without some net devices switched on.
 #endif
 
-#define PRINTK_HEADER		" lcs: "
-
 /**
  * initialization string for output
  */
@@ -96,7 +97,7 @@
 	lcs_dbf_setup = debug_register("lcs_setup", 2, 1, 8);
 	lcs_dbf_trace = debug_register("lcs_trace", 4, 1, 8);
 	if (lcs_dbf_setup == NULL || lcs_dbf_trace == NULL) {
-		PRINT_ERR("Not enough memory for debug facility.\n");
+		pr_err("Not enough memory for debug facility.\n");
 		lcs_unregister_debug_facility();
 		return -ENOMEM;
 	}
@@ -503,7 +504,9 @@
 	if (rc) {
 		LCS_DBF_TEXT_(4,trace,"essh%s",
 			      dev_name(&channel->ccwdev->dev));
-		PRINT_ERR("Error in starting channel, rc=%d!\n", rc);
+		dev_err(&channel->ccwdev->dev,
+			"Starting an LCS device resulted in an error,"
+			" rc=%d!\n", rc);
 	}
 	return rc;
 }
@@ -640,7 +643,9 @@
 	if (rc) {
 		LCS_DBF_TEXT_(4, trace, "ersc%s",
 			      dev_name(&channel->ccwdev->dev));
-		PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc);
+		dev_err(&channel->ccwdev->dev,
+			"Sending data from the LCS device to the LAN failed"
+			" with rc=%d\n",rc);
 	} else
 		channel->state = LCS_CH_STATE_RUNNING;
 	return rc;
@@ -1086,7 +1091,7 @@
 	cmd->cmd.lcs_qipassist.num_ip_pairs = 1;
 	rc = lcs_send_lancmd(card, buffer, __lcs_check_multicast_cb);
 	if (rc != 0) {
-		PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n");
+		pr_err("Query IPAssist failed. Assuming unsupported!\n");
 		return -EOPNOTSUPP;
 	}
 	if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT)
@@ -1119,8 +1124,8 @@
 			rc = lcs_send_setipm(card, ipm);
 			spin_lock_irqsave(&card->ipm_lock, flags);
 			if (rc) {
-				PRINT_INFO("Adding multicast address failed. "
-					   "Table possibly full!\n");
+				pr_info("Adding multicast address failed."
+					" Table possibly full!\n");
 				/* store ipm in failed list -> will be added
 				 * to ipm_list again, so a retry will be done
 				 * during the next call of this function */
@@ -1231,8 +1236,8 @@
 		ipm = (struct lcs_ipm_list *)
 			kzalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC);
 		if (ipm == NULL) {
-			PRINT_INFO("Not enough memory to add "
-				   "new multicast entry!\n");
+			pr_info("Not enough memory to add"
+				" new multicast entry!\n");
 			break;
 		}
 		memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH);
@@ -1290,7 +1295,7 @@
         struct lcs_card *card;
 
         LCS_DBF_TEXT(4, trace, "setmulti");
-        card = (struct lcs_card *) dev->priv;
+        card = (struct lcs_card *) dev->ml_priv;
 
         if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD))
 		schedule_work(&card->kernel_thread_starter);
@@ -1306,18 +1311,21 @@
 
 	switch (PTR_ERR(irb)) {
 	case -EIO:
-		PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev));
+		dev_warn(&cdev->dev,
+			"An I/O-error occurred on the LCS device\n");
 		LCS_DBF_TEXT(2, trace, "ckirberr");
 		LCS_DBF_TEXT_(2, trace, "  rc%d", -EIO);
 		break;
 	case -ETIMEDOUT:
-		PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev));
+		dev_warn(&cdev->dev,
+			"A command timed out on the LCS device\n");
 		LCS_DBF_TEXT(2, trace, "ckirberr");
 		LCS_DBF_TEXT_(2, trace, "  rc%d", -ETIMEDOUT);
 		break;
 	default:
-		PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
-			   dev_name(&cdev->dev));
+		dev_warn(&cdev->dev,
+			"An error occurred on the LCS device, rc=%ld\n",
+			PTR_ERR(irb));
 		LCS_DBF_TEXT(2, trace, "ckirberr");
 		LCS_DBF_TEXT(2, trace, "  rc???");
 	}
@@ -1403,8 +1411,10 @@
 	/* Check for channel and device errors presented */
 	rc = lcs_get_problem(cdev, irb);
 	if (rc || (dstat & DEV_STAT_UNIT_EXCEP)) {
-		PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n",
-			    dev_name(&cdev->dev), dstat, cstat);
+		dev_warn(&cdev->dev,
+			"The LCS device stopped because of an error,"
+			" dstat=0x%X, cstat=0x%X \n",
+			    dstat, cstat);
 		if (rc) {
 			channel->state = LCS_CH_STATE_ERROR;
 		}
@@ -1607,7 +1617,7 @@
 	int rc;
 
 	LCS_DBF_TEXT(5, trace, "pktxmit");
-	card = (struct lcs_card *) dev->priv;
+	card = (struct lcs_card *) dev->ml_priv;
 	rc = __lcs_start_xmit(card, skb, dev);
 	return rc;
 }
@@ -1761,8 +1771,8 @@
 			lcs_schedule_recovery(card);
 			break;
 		case LCS_CMD_STOPLAN:
-			PRINT_WARN("Stoplan for %s initiated by LGW.\n",
-					card->dev->name);
+			pr_warning("Stoplan for %s initiated by LGW.\n",
+				   card->dev->name);
 			if (card->dev)
 				netif_carrier_off(card->dev);
 			break;
@@ -1790,7 +1800,8 @@
 
 	skb = dev_alloc_skb(skb_len);
 	if (skb == NULL) {
-		PRINT_ERR("LCS: alloc_skb failed for device=%s\n",
+		dev_err(&card->dev->dev,
+			" Allocating a socket buffer to interface %s failed\n",
 			  card->dev->name);
 		card->stats.rx_dropped++;
 		return;
@@ -1863,7 +1874,7 @@
 	struct lcs_card *card;
 
 	LCS_DBF_TEXT(4, trace, "netstats");
-	card = (struct lcs_card *) dev->priv;
+	card = (struct lcs_card *) dev->ml_priv;
 	return &card->stats;
 }
 
@@ -1878,7 +1889,7 @@
 	int rc;
 
 	LCS_DBF_TEXT(2, trace, "stopdev");
-	card   = (struct lcs_card *) dev->priv;
+	card   = (struct lcs_card *) dev->ml_priv;
 	netif_carrier_off(dev);
 	netif_tx_disable(dev);
 	dev->flags &= ~IFF_UP;
@@ -1886,7 +1897,8 @@
 		(card->write.state != LCS_CH_STATE_RUNNING));
 	rc = lcs_stopcard(card);
 	if (rc)
-		PRINT_ERR("Try it again!\n ");
+		dev_err(&card->dev->dev,
+			" Shutting down the LCS device failed\n ");
 	return rc;
 }
 
@@ -1901,11 +1913,11 @@
 	int rc;
 
 	LCS_DBF_TEXT(2, trace, "opendev");
-	card = (struct lcs_card *) dev->priv;
+	card = (struct lcs_card *) dev->ml_priv;
 	/* initialize statistics */
 	rc = lcs_detect(card);
 	if (rc) {
-		PRINT_ERR("LCS:Error in opening device!\n");
+		pr_err("Error in opening device!\n");
 
 	} else {
 		dev->flags |= IFF_UP;
@@ -2113,8 +2125,9 @@
 	rc = lcs_detect(card);
 	if (rc) {
 		LCS_DBF_TEXT(2, setup, "dtctfail");
-		PRINT_WARN("Detection of LCS card failed with return code "
-			   "%d (0x%x)\n", rc, rc);
+		dev_err(&card->dev->dev,
+			"Detecting a network adapter for LCS devices"
+			" failed with rc=%d (0x%x)\n", rc, rc);
 		lcs_stopcard(card);
 		goto out;
 	}
@@ -2144,13 +2157,13 @@
 #endif
 	default:
 		LCS_DBF_TEXT(3, setup, "errinit");
-		PRINT_ERR("LCS: Initialization failed\n");
+		pr_err(" Initialization failed\n");
 		goto out;
 	}
 	if (!dev)
 		goto out;
 	card->dev = dev;
-	card->dev->priv = card;
+	card->dev->ml_priv = card;
 	card->dev->open = lcs_open_device;
 	card->dev->stop = lcs_stop_device;
 	card->dev->hard_start_xmit = lcs_start_xmit;
@@ -2176,13 +2189,13 @@
 		goto out;
 
 	/* Print out supported assists: IPv6 */
-	PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name,
-		   (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ?
-		   "with" : "without");
+	pr_info("LCS device %s %s IPv6 support\n", card->dev->name,
+		(card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ?
+		"with" : "without");
 	/* Print out supported assist: Multicast */
-	PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name,
-		   (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ?
-		   "with" : "without");
+	pr_info("LCS device %s %s Multicast support\n", card->dev->name,
+		(card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ?
+		"with" : "without");
 	return 0;
 out:
 
@@ -2248,15 +2261,16 @@
 		return 0;
 	LCS_DBF_TEXT(4, trace, "recover2");
 	gdev = card->gdev;
-	PRINT_WARN("Recovery of device %s started...\n", dev_name(&gdev->dev));
+	dev_warn(&gdev->dev,
+		"A recovery process has been started for the LCS device\n");
 	rc = __lcs_shutdown_device(gdev, 1);
 	rc = lcs_new_device(gdev);
 	if (!rc)
-		PRINT_INFO("Device %s successfully recovered!\n",
-				card->dev->name);
+		pr_info("Device %s successfully recovered!\n",
+			card->dev->name);
 	else
-		PRINT_INFO("Device %s could not be recovered!\n",
-				card->dev->name);
+		pr_info("Device %s could not be recovered!\n",
+			card->dev->name);
 	lcs_clear_thread_running_bit(card, LCS_RECOVERY_THREAD);
 	return 0;
 }
@@ -2308,17 +2322,17 @@
 {
 	int rc;
 
-	PRINT_INFO("Loading %s\n",version);
+	pr_info("Loading %s\n", version);
 	rc = lcs_register_debug_facility();
 	LCS_DBF_TEXT(0, setup, "lcsinit");
 	if (rc) {
-		PRINT_ERR("Initialization failed\n");
+		pr_err("Initialization failed\n");
 		return rc;
 	}
 
 	rc = register_cu3088_discipline(&lcs_group_driver);
 	if (rc) {
-		PRINT_ERR("Initialization failed\n");
+		pr_err("Initialization failed\n");
 		return rc;
 	}
 	return 0;
@@ -2331,7 +2345,7 @@
 static void
 __exit lcs_cleanup_module(void)
 {
-	PRINT_INFO("Terminating lcs module.\n");
+	pr_info("Terminating lcs module.\n");
 	LCS_DBF_TEXT(0, trace, "cleanup");
 	unregister_cu3088_discipline(&lcs_group_driver);
 	lcs_unregister_debug_facility();
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 0fea51e..930e2fc 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -31,6 +31,9 @@
  *
  */
 
+#define KMSG_COMPONENT "netiucv"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #undef DEBUG
 
 #include <linux/module.h>
@@ -846,7 +849,8 @@
 
 	fsm_deltimer(&conn->timer);
 	iucv_path_sever(conn->path, NULL);
-	PRINT_INFO("%s: Remote dropped connection\n", netdev->name);
+	dev_info(privptr->dev, "The peer interface of the IUCV device"
+		" has closed the connection\n");
 	IUCV_DBF_TEXT(data, 2,
 		      "conn_action_connsever: Remote dropped connection\n");
 	fsm_newstate(fi, CONN_STATE_STARTWAIT);
@@ -856,13 +860,15 @@
 static void conn_action_start(fsm_instance *fi, int event, void *arg)
 {
 	struct iucv_connection *conn = arg;
+	struct net_device *netdev = conn->netdev;
+	struct netiucv_priv *privptr = netdev_priv(netdev);
 	int rc;
 
 	IUCV_DBF_TEXT(trace, 3, __func__);
 
 	fsm_newstate(fi, CONN_STATE_STARTWAIT);
 	IUCV_DBF_TEXT_(setup, 2, "%s('%s'): connecting ...\n",
-		    conn->netdev->name, conn->userid);
+		netdev->name, conn->userid);
 
 	/*
 	 * We must set the state before calling iucv_connect because the
@@ -876,41 +882,45 @@
 			       NULL, iucvMagic, conn);
 	switch (rc) {
 	case 0:
-		conn->netdev->tx_queue_len = conn->path->msglim;
+		netdev->tx_queue_len = conn->path->msglim;
 		fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
 			     CONN_EVENT_TIMER, conn);
 		return;
 	case 11:
-		PRINT_INFO("%s: User %s is currently not available.\n",
-			   conn->netdev->name,
-			   netiucv_printname(conn->userid));
+		dev_warn(privptr->dev,
+			"The IUCV device failed to connect to z/VM guest %s\n",
+			netiucv_printname(conn->userid));
 		fsm_newstate(fi, CONN_STATE_STARTWAIT);
 		break;
 	case 12:
-		PRINT_INFO("%s: User %s is currently not ready.\n",
-			   conn->netdev->name,
-			   netiucv_printname(conn->userid));
+		dev_warn(privptr->dev,
+			"The IUCV device failed to connect to the peer on z/VM"
+			" guest %s\n", netiucv_printname(conn->userid));
 		fsm_newstate(fi, CONN_STATE_STARTWAIT);
 		break;
 	case 13:
-		PRINT_WARN("%s: Too many IUCV connections.\n",
-			   conn->netdev->name);
+		dev_err(privptr->dev,
+			"Connecting the IUCV device would exceed the maximum"
+			" number of IUCV connections\n");
 		fsm_newstate(fi, CONN_STATE_CONNERR);
 		break;
 	case 14:
-		PRINT_WARN("%s: User %s has too many IUCV connections.\n",
-			   conn->netdev->name,
-			   netiucv_printname(conn->userid));
+		dev_err(privptr->dev,
+			"z/VM guest %s has too many IUCV connections"
+			" to connect with the IUCV device\n",
+			netiucv_printname(conn->userid));
 		fsm_newstate(fi, CONN_STATE_CONNERR);
 		break;
 	case 15:
-		PRINT_WARN("%s: No IUCV authorization in CP directory.\n",
-			   conn->netdev->name);
+		dev_err(privptr->dev,
+			"The IUCV device cannot connect to a z/VM guest with no"
+			" IUCV authorization\n");
 		fsm_newstate(fi, CONN_STATE_CONNERR);
 		break;
 	default:
-		PRINT_WARN("%s: iucv_connect returned error %d\n",
-			   conn->netdev->name, rc);
+		dev_err(privptr->dev,
+			"Connecting the IUCV device failed with error %d\n",
+			rc);
 		fsm_newstate(fi, CONN_STATE_CONNERR);
 		break;
 	}
@@ -1059,8 +1069,9 @@
 	switch (fsm_getstate(fi)) {
 		case DEV_STATE_STARTWAIT:
 			fsm_newstate(fi, DEV_STATE_RUNNING);
-			PRINT_INFO("%s: connected with remote side %s\n",
-			       dev->name, privptr->conn->userid);
+			dev_info(privptr->dev,
+				"The IUCV device has been connected"
+				" successfully to %s\n", privptr->conn->userid);
 			IUCV_DBF_TEXT(setup, 3,
 				"connection is up and running\n");
 			break;
@@ -1982,6 +1993,8 @@
 	if (rc)
 		goto out_unreg;
 
+	dev_info(priv->dev, "The IUCV interface to %s has been"
+		" established successfully\n", netiucv_printname(username));
 
 	return count;
 
@@ -2027,10 +2040,9 @@
 			continue;
 		read_unlock_bh(&iucv_connection_rwlock);
                 if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
-			PRINT_WARN("netiucv: net device %s active with peer "
-				   "%s\n", ndev->name, priv->conn->userid);
-                        PRINT_WARN("netiucv: %s cannot be removed\n",
-				   ndev->name);
+			dev_warn(dev, "The IUCV device is connected"
+				" to %s and cannot be removed\n",
+				priv->conn->userid);
 			IUCV_DBF_TEXT(data, 2, "remove_write: still active\n");
 			return -EPERM;
                 }
@@ -2062,7 +2074,7 @@
 
 static void netiucv_banner(void)
 {
-	PRINT_INFO("NETIUCV driver initialized\n");
+	pr_info("driver initialized\n");
 }
 
 static void __exit netiucv_exit(void)
@@ -2088,7 +2100,7 @@
 	iucv_unregister(&netiucv_handler, 1);
 	iucv_unregister_dbf_views();
 
-	PRINT_INFO("NETIUCV driver unloaded\n");
+	pr_info("driver unloaded\n");
 	return;
 }
 
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index af6d604..d5ccce1 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -31,11 +31,10 @@
 #include <asm/qdio.h>
 #include <asm/ccwdev.h>
 #include <asm/ccwgroup.h>
+#include <asm/sysinfo.h>
 
 #include "qeth_core_mpc.h"
 
-#define KMSG_COMPONENT "qeth"
-
 /**
  * Debug Facility stuff
  */
@@ -74,11 +73,6 @@
 #define QETH_DBF_TEXT_(name, level, text...) \
 	qeth_dbf_longtext(QETH_DBF_##name, level, text)
 
-/**
- * some more debug stuff
- */
-#define PRINTK_HEADER	"qeth: "
-
 #define SENSE_COMMAND_REJECT_BYTE 0
 #define SENSE_COMMAND_REJECT_FLAG 0x80
 #define SENSE_RESETTING_EVENT_BYTE 1
@@ -733,6 +727,7 @@
 	struct qeth_osn_info osn_info;
 	struct qeth_discipline discipline;
 	atomic_t force_alloc_skb;
+	struct service_level qeth_service_level;
 };
 
 struct qeth_card_list_struct {
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 52d2659..e783644 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -8,6 +8,9 @@
  *		 Frank Blaschka <frank.blaschka@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "qeth"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/string.h>
@@ -319,7 +322,10 @@
 		return -EIO;
 	iob = qeth_get_buffer(&card->read);
 	if (!iob) {
-		PRINT_WARN("issue_next_read failed: no iob available!\n");
+		dev_warn(&card->gdev->dev, "The qeth device driver "
+			"failed to recover an error on the device\n");
+		QETH_DBF_MESSAGE(2, "%s issue_next_read failed: no iob "
+			"available\n", dev_name(&card->gdev->dev));
 		return -ENOMEM;
 	}
 	qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE);
@@ -327,7 +333,8 @@
 	rc = ccw_device_start(card->read.ccwdev, &card->read.ccw,
 			      (addr_t) iob, 0, 0);
 	if (rc) {
-		PRINT_ERR("Error in starting next read ccw! rc=%i\n", rc);
+		QETH_DBF_MESSAGE(2, "%s error in starting next read ccw! "
+			"rc=%i\n", dev_name(&card->gdev->dev), rc);
 		atomic_set(&card->read.irq_pending, 0);
 		qeth_schedule_recovery(card);
 		wake_up(&card->wait_q);
@@ -393,10 +400,9 @@
 		} else {
 			switch (cmd->hdr.command) {
 			case IPA_CMD_STOPLAN:
-				PRINT_WARN("Link failure on %s (CHPID 0x%X) - "
-					   "there is a network problem or "
-					   "someone pulled the cable or "
-					   "disabled the port.\n",
+				dev_warn(&card->gdev->dev,
+					   "The link for interface %s on CHPID"
+					   " 0x%X failed\n",
 					   QETH_CARD_IFNAME(card),
 					   card->info.chpid);
 				card->lan_online = 0;
@@ -404,9 +410,9 @@
 					netif_carrier_off(card->dev);
 				return NULL;
 			case IPA_CMD_STARTLAN:
-				PRINT_INFO("Link reestablished on %s "
-					   "(CHPID 0x%X). Scheduling "
-					   "IP address reset.\n",
+				dev_info(&card->gdev->dev,
+					   "The link for %s on CHPID 0x%X has"
+					   " been restored\n",
 					   QETH_CARD_IFNAME(card),
 					   card->info.chpid);
 				netif_carrier_on(card->dev);
@@ -458,7 +464,7 @@
 
 	QETH_DBF_HEX(CTRL, 2, buffer, QETH_DBF_CTRL_LEN);
 	if ((buffer[2] & 0xc0) == 0xc0) {
-		PRINT_WARN("received an IDX TERMINATE "
+		QETH_DBF_MESSAGE(2, "received an IDX TERMINATE "
 			   "with cause code 0x%02x%s\n",
 			   buffer[4],
 			   ((buffer[4] == 0x22) ?
@@ -744,8 +750,10 @@
 		     SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK |
 		     SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) {
 		QETH_DBF_TEXT(TRACE, 2, "CGENCHK");
-		PRINT_WARN("check on device %s, dstat=x%x, cstat=x%x ",
-			   dev_name(&cdev->dev), dstat, cstat);
+		dev_warn(&cdev->dev, "The qeth device driver "
+			"failed to recover an error on the device\n");
+		QETH_DBF_MESSAGE(2, "%s check on device dstat=x%x, cstat=x%x ",
+			dev_name(&cdev->dev), dstat, cstat);
 		print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET,
 				16, 1, irb, 64, 1);
 		return 1;
@@ -784,12 +792,14 @@
 
 	switch (PTR_ERR(irb)) {
 	case -EIO:
-		PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev));
+		QETH_DBF_MESSAGE(2, "%s i/o-error on device\n",
+			dev_name(&cdev->dev));
 		QETH_DBF_TEXT(TRACE, 2, "ckirberr");
 		QETH_DBF_TEXT_(TRACE, 2, "  rc%d", -EIO);
 		break;
 	case -ETIMEDOUT:
-		PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev));
+		dev_warn(&cdev->dev, "A hardware operation timed out"
+			" on the device\n");
 		QETH_DBF_TEXT(TRACE, 2, "ckirberr");
 		QETH_DBF_TEXT_(TRACE, 2, "  rc%d", -ETIMEDOUT);
 		if (intparm == QETH_RCD_PARM) {
@@ -802,8 +812,8 @@
 		}
 		break;
 	default:
-		PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
-			   dev_name(&cdev->dev));
+		QETH_DBF_MESSAGE(2, "%s unknown error %ld on device\n",
+			dev_name(&cdev->dev), PTR_ERR(irb));
 		QETH_DBF_TEXT(TRACE, 2, "ckirberr");
 		QETH_DBF_TEXT(TRACE, 2, "  rc???");
 	}
@@ -869,10 +879,12 @@
 	    (dstat & DEV_STAT_UNIT_CHECK) ||
 	    (cstat)) {
 		if (irb->esw.esw0.erw.cons) {
-			/* TODO: we should make this s390dbf */
-			PRINT_WARN("sense data available on channel %s.\n",
-				   CHANNEL_ID(channel));
-			PRINT_WARN(" cstat 0x%X\n dstat 0x%X\n", cstat, dstat);
+			dev_warn(&channel->ccwdev->dev,
+				"The qeth device driver failed to recover "
+				"an error on the device\n");
+			QETH_DBF_MESSAGE(2, "%s sense data available. cstat "
+				"0x%X dstat 0x%X\n",
+				dev_name(&channel->ccwdev->dev), cstat, dstat);
 			print_hex_dump(KERN_WARNING, "qeth: irb ",
 				DUMP_PREFIX_OFFSET, 16, 1, irb, 32, 1);
 			print_hex_dump(KERN_WARNING, "qeth: sense data ",
@@ -1138,6 +1150,14 @@
 	return 0;
 }
 
+static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr)
+{
+	struct qeth_card *card = container_of(slr, struct qeth_card,
+					qeth_service_level);
+	seq_printf(m, "qeth: %s firmware level %s\n", CARD_BUS_ID(card),
+			card->info.mcl_level);
+}
+
 static struct qeth_card *qeth_alloc_card(void)
 {
 	struct qeth_card *card;
@@ -1157,6 +1177,8 @@
 		return NULL;
 	}
 	card->options.layer2 = -1;
+	card->qeth_service_level.seq_print = qeth_core_sl_print;
+	register_service_level(&card->qeth_service_level);
 	return card;
 }
 
@@ -1175,8 +1197,8 @@
 			card->qdio.no_out_queues = known_devices[i][8];
 			card->info.is_multicast_different = known_devices[i][9];
 			if (qeth_is_1920_device(card)) {
-				PRINT_INFO("Priority Queueing not able "
-					   "due to hardware limitations!\n");
+				dev_info(&card->gdev->dev,
+					"Priority Queueing not supported\n");
 				card->qdio.no_out_queues = 1;
 				card->qdio.default_out_queue = 0;
 			}
@@ -1185,7 +1207,8 @@
 		i++;
 	}
 	card->info.type = QETH_CARD_TYPE_UNKNOWN;
-	PRINT_ERR("unknown card type on device %s\n", CARD_BUS_ID(card));
+	dev_err(&card->gdev->dev, "The adapter hardware is of an "
+		"unknown type\n");
 	return -ENOENT;
 }
 
@@ -1368,8 +1391,8 @@
 	QETH_DBF_TEXT(SETUP, 2, "getunit");
 	rc = qeth_read_conf_data(card, (void **) &prcd, &length);
 	if (rc) {
-		PRINT_ERR("qeth_read_conf_data for device %s returned %i\n",
-			CARD_DDEV_ID(card), rc);
+		QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
+			dev_name(&card->gdev->dev), rc);
 		return rc;
 	}
 	card->info.chpid = prcd[30];
@@ -1519,7 +1542,10 @@
 	if (rc == -ERESTARTSYS)
 		return rc;
 	if (channel->state != CH_STATE_ACTIVATING) {
-		PRINT_WARN("IDX activate timed out!\n");
+		dev_warn(&channel->ccwdev->dev, "The qeth device driver"
+			" failed to recover an error on the device\n");
+		QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n",
+			dev_name(&channel->ccwdev->dev));
 		QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME);
 		qeth_clear_cmd_buffers(channel);
 		return -ETIME;
@@ -1552,20 +1578,21 @@
 
 	if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
 		if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)
-			PRINT_ERR("IDX_ACTIVATE on write channel device %s: "
-				"adapter exclusively used by another host\n",
-			CARD_WDEV_ID(card));
+			dev_err(&card->write.ccwdev->dev,
+				"The adapter is used exclusively by another "
+				"host\n");
 		else
-			PRINT_ERR("IDX_ACTIVATE on write channel device %s: "
-				"negative reply\n", CARD_WDEV_ID(card));
+			QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel:"
+				" negative reply\n",
+				dev_name(&card->write.ccwdev->dev));
 		goto out;
 	}
 	memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
 	if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) {
-		PRINT_WARN("IDX_ACTIVATE on write channel device %s: "
-			   "function level mismatch "
-			   "(sent: 0x%x, received: 0x%x)\n",
-			   CARD_WDEV_ID(card), card->info.func_level, temp);
+		QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel: "
+			"function level mismatch (sent: 0x%x, received: "
+			"0x%x)\n", dev_name(&card->write.ccwdev->dev),
+			card->info.func_level, temp);
 		goto out;
 	}
 	channel->state = CH_STATE_UP;
@@ -1591,12 +1618,13 @@
 
 	if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
 		if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)
-			PRINT_ERR("IDX_ACTIVATE on read channel device %s: "
-				"adapter exclusively used by another host\n",
-				CARD_RDEV_ID(card));
+			dev_err(&card->write.ccwdev->dev,
+				"The adapter is used exclusively by another "
+				"host\n");
 		else
-			PRINT_ERR("IDX_ACTIVATE on read channel device %s: "
-				"negative reply\n", CARD_RDEV_ID(card));
+			QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel:"
+				" negative reply\n",
+				dev_name(&card->read.ccwdev->dev));
 		goto out;
 	}
 
@@ -1610,9 +1638,10 @@
 
 	memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
 	if (temp != qeth_peer_func_level(card->info.func_level)) {
-		PRINT_WARN("IDX_ACTIVATE on read channel device %s: function "
-			   "level mismatch (sent: 0x%x, received: 0x%x)\n",
-			   CARD_RDEV_ID(card), card->info.func_level, temp);
+		QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel: function "
+			"level mismatch (sent: 0x%x, received: 0x%x)\n",
+			dev_name(&card->read.ccwdev->dev),
+			card->info.func_level, temp);
 		goto out;
 	}
 	memcpy(&card->token.issuer_rm_r,
@@ -1686,8 +1715,9 @@
 			      (addr_t) iob, 0, 0);
 	spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
 	if (rc) {
-		PRINT_WARN("qeth_send_control_data: "
-			   "ccw_device_start rc = %i\n", rc);
+		QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: "
+			"ccw_device_start rc = %i\n",
+			dev_name(&card->write.ccwdev->dev), rc);
 		QETH_DBF_TEXT_(TRACE, 2, " err%d", rc);
 		spin_lock_irqsave(&card->lock, flags);
 		list_del_init(&reply->list);
@@ -2170,11 +2200,8 @@
 		dbf_text[i] =
 			(char) _ebcasc[(__u8) dbf_text[i]];
 	dbf_text[8] = 0;
-	PRINT_INFO("Device %s/%s/%s is a%s card%s%s%s\n"
+	dev_info(&card->gdev->dev, "Device is a%s card%s%s%s\n"
 	       "with link type %s (portname: %s)\n",
-	       CARD_RDEV_ID(card),
-	       CARD_WDEV_ID(card),
-	       CARD_DDEV_ID(card),
 	       qeth_get_cardname(card),
 	       (card->info.mcl_level[0]) ? " (level: " : "",
 	       (card->info.mcl_level[0]) ? card->info.mcl_level : "",
@@ -2187,23 +2214,17 @@
 static void qeth_print_status_no_portname(struct qeth_card *card)
 {
 	if (card->info.portname[0])
-		PRINT_INFO("Device %s/%s/%s is a%s "
+		dev_info(&card->gdev->dev, "Device is a%s "
 		       "card%s%s%s\nwith link type %s "
 		       "(no portname needed by interface).\n",
-		       CARD_RDEV_ID(card),
-		       CARD_WDEV_ID(card),
-		       CARD_DDEV_ID(card),
 		       qeth_get_cardname(card),
 		       (card->info.mcl_level[0]) ? " (level: " : "",
 		       (card->info.mcl_level[0]) ? card->info.mcl_level : "",
 		       (card->info.mcl_level[0]) ? ")" : "",
 		       qeth_get_cardname_short(card));
 	else
-		PRINT_INFO("Device %s/%s/%s is a%s "
+		dev_info(&card->gdev->dev, "Device is a%s "
 		       "card%s%s%s\nwith link type %s.\n",
-		       CARD_RDEV_ID(card),
-		       CARD_WDEV_ID(card),
-		       CARD_DDEV_ID(card),
 		       qeth_get_cardname(card),
 		       (card->info.mcl_level[0]) ? " (level: " : "",
 		       (card->info.mcl_level[0]) ? card->info.mcl_level : "",
@@ -2325,7 +2346,6 @@
 	 * the QETH_IN_BUF_REQUEUE_THRESHOLD we should never run  out off
 	 * buffers
 	 */
-	BUG_ON(!pool_entry);
 
 	buf->pool_entry = pool_entry;
 	for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
@@ -2630,9 +2650,8 @@
 				qeth_get_micros() -
 				card->perf_stats.inbound_do_qdio_start_time;
 		if (rc) {
-			PRINT_WARN("qeth_queue_input_buffer's do_QDIO "
-				   "return %i (device %s).\n",
-				   rc, CARD_DDEV_ID(card));
+			dev_warn(&card->gdev->dev,
+				"QDIO reported an error, rc=%i\n", rc);
 			QETH_DBF_TEXT(TRACE, 2, "qinberr");
 			QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_BUS_ID(card));
 		}
@@ -3730,6 +3749,7 @@
 		free_netdev(card->dev);
 	kfree(card->ip_tbd_list);
 	qeth_free_qdio_buffers(card);
+	unregister_service_level(&card->qeth_service_level);
 	kfree(card);
 }
 
@@ -3757,7 +3777,7 @@
 
 int qeth_core_hardsetup_card(struct qeth_card *card)
 {
-	struct qdio_ssqd_desc *qdio_ssqd;
+	struct qdio_ssqd_desc *ssqd;
 	int retries = 3;
 	int mpno = 0;
 	int rc;
@@ -3766,7 +3786,8 @@
 	atomic_set(&card->force_alloc_skb, 0);
 retry:
 	if (retries < 3) {
-		PRINT_WARN("Retrying to do IDX activates.\n");
+		QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
+			dev_name(&card->gdev->dev));
 		ccw_device_set_offline(CARD_DDEV(card));
 		ccw_device_set_offline(CARD_WDEV(card));
 		ccw_device_set_offline(CARD_RDEV(card));
@@ -3792,9 +3813,16 @@
 		return rc;
 	}
 
-	qdio_ssqd = qdio_get_ssqd_desc(CARD_DDEV(card));
-	if (qdio_ssqd)
-		mpno = qdio_ssqd->pcnt;
+	ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL);
+	if (!ssqd) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd);
+	if (rc == 0)
+		mpno = ssqd->pcnt;
+	kfree(ssqd);
+
 	if (mpno)
 		mpno = min(mpno - 1, QETH_MAX_PORTNO);
 	if (card->info.portno > mpno) {
@@ -3834,7 +3862,10 @@
 	}
 	return 0;
 out:
-	PRINT_ERR("Initialization in hardsetup failed! rc=%d\n", rc);
+	dev_warn(&card->gdev->dev, "The qeth device driver failed to recover "
+		"an error on the device\n");
+	QETH_DBF_MESSAGE(2, "%s Initialization in hardsetup failed! rc=%d\n",
+		dev_name(&card->gdev->dev), rc);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card);
@@ -4054,8 +4085,8 @@
 		break;
 	}
 	if (!card->discipline.ccwgdriver) {
-		PRINT_ERR("Support for discipline %d not present\n",
-				discipline);
+		dev_err(&card->gdev->dev, "There is no kernel module to "
+			"support discipline %d\n", discipline);
 		rc = -EINVAL;
 	}
 	return rc;
@@ -4448,7 +4479,7 @@
 {
 	int rc;
 
-	PRINT_INFO("loading core functions\n");
+	pr_info("loading core functions\n");
 	INIT_LIST_HEAD(&qeth_core_card_list.list);
 	rwlock_init(&qeth_core_card_list.rwlock);
 
@@ -4488,9 +4519,10 @@
 ccwgroup_err:
 	ccw_driver_unregister(&qeth_ccw_driver);
 ccw_err:
+	QETH_DBF_MESSAGE(2, "Initialization failed with code %d\n", rc);
 	qeth_unregister_dbf_views();
 out_err:
-	PRINT_ERR("Initialization failed with code %d\n", rc);
+	pr_err("Initializing the qeth device driver failed\n");
 	return rc;
 }
 
@@ -4503,7 +4535,7 @@
 	ccw_driver_unregister(&qeth_ccw_driver);
 	kmem_cache_destroy(qeth_core_header_cache);
 	qeth_unregister_dbf_views();
-	PRINT_INFO("core functions removed\n");
+	pr_info("core functions removed\n");
 }
 
 module_init(qeth_core_init);
diff --git a/drivers/s390/net/qeth_core_offl.c b/drivers/s390/net/qeth_core_offl.c
index 452874e..4080126 100644
--- a/drivers/s390/net/qeth_core_offl.c
+++ b/drivers/s390/net/qeth_core_offl.c
@@ -350,7 +350,7 @@
 	phcsum = csum_tcpudp_nofold(eddp->nh.ip4.h.saddr, eddp->nh.ip4.h.daddr,
 				    eddp->thl + data_len, IPPROTO_TCP, 0);
 	/* compute checksum of tcp header */
-	return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum);
+	return csum_partial(&eddp->th, eddp->thl, phcsum);
 }
 
 static __wsum qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp,
@@ -362,12 +362,12 @@
 	QETH_DBF_TEXT(TRACE, 5, "eddpckt6");
 	eddp->th.tcp.h.check = 0;
 	/* compute pseudo header checksum */
-	phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.saddr,
+	phcsum = csum_partial(&eddp->nh.ip6.h.saddr,
 			      sizeof(struct in6_addr), 0);
-	phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.daddr,
+	phcsum = csum_partial(&eddp->nh.ip6.h.daddr,
 			      sizeof(struct in6_addr), phcsum);
 	proto = htonl(IPPROTO_TCP);
-	phcsum = csum_partial((u8 *)&proto, sizeof(u32), phcsum);
+	phcsum = csum_partial(&proto, sizeof(u32), phcsum);
 	return phcsum;
 }
 
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 1b1e803..2c48591 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -8,6 +8,9 @@
  *		 Frank Blaschka <frank.blaschka@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "qeth"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/string.h>
@@ -131,17 +134,13 @@
 	mac = &cmd->data.setdelmac.mac[0];
 	/* MAC already registered, needed in couple/uncouple case */
 	if (cmd->hdr.return_code == 0x2005) {
-		QETH_DBF_MESSAGE(2, "Group MAC %02x:%02x:%02x:%02x:%02x:%02x "
-			  "already existing on %s \n",
-			  mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
-			  QETH_CARD_IFNAME(card));
+		QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n",
+			  mac, QETH_CARD_IFNAME(card));
 		cmd->hdr.return_code = 0;
 	}
 	if (cmd->hdr.return_code)
-		QETH_DBF_MESSAGE(2, "Could not set group MAC "
-			  "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n",
-			  mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
-			  QETH_CARD_IFNAME(card), cmd->hdr.return_code);
+		QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %x\n",
+			  mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code);
 	return 0;
 }
 
@@ -163,10 +162,8 @@
 	cmd = (struct qeth_ipa_cmd *) data;
 	mac = &cmd->data.setdelmac.mac[0];
 	if (cmd->hdr.return_code)
-		QETH_DBF_MESSAGE(2, "Could not delete group MAC "
-			  "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n",
-			  mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
-			  QETH_CARD_IFNAME(card), cmd->hdr.return_code);
+		QETH_DBF_MESSAGE(2, "Could not delete group MAC %pM on %s: %x\n",
+			  mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code);
 	return 0;
 }
 
@@ -503,12 +500,13 @@
 		card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
 		memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac,
 		       OSA_ADDR_LEN);
-		PRINT_INFO("MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
-			   "successfully registered on device %s\n",
-			   card->dev->dev_addr[0], card->dev->dev_addr[1],
-			   card->dev->dev_addr[2], card->dev->dev_addr[3],
-			   card->dev->dev_addr[4], card->dev->dev_addr[5],
-			   card->dev->name);
+		dev_info(&card->gdev->dev,
+			"MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
+			"successfully registered on device %s\n",
+			card->dev->dev_addr[0], card->dev->dev_addr[1],
+			card->dev->dev_addr[2], card->dev->dev_addr[3],
+			card->dev->dev_addr[4], card->dev->dev_addr[5],
+			card->dev->name);
 	}
 	return 0;
 }
@@ -1015,9 +1013,8 @@
 	if (rc) {
 		QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
 		if (rc == 0xe080) {
-			PRINT_WARN("LAN on card %s if offline! "
-				   "Waiting for STARTLAN from card.\n",
-				   CARD_BUS_ID(card));
+			dev_warn(&card->gdev->dev,
+				"The LAN is offline\n");
 			card->lan_online = 0;
 		}
 		return rc;
@@ -1117,8 +1114,8 @@
 	if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))
 		return 0;
 	QETH_DBF_TEXT(TRACE, 2, "recover2");
-	PRINT_WARN("Recovery of device %s started ...\n",
-		   CARD_BUS_ID(card));
+	dev_warn(&card->gdev->dev,
+		"A recovery process has been started for the device\n");
 	card->use_hard_stop = 1;
 	__qeth_l2_set_offline(card->gdev, 1);
 	rc = __qeth_l2_set_online(card->gdev, 1);
@@ -1126,27 +1123,27 @@
 	qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
 	qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
 	if (!rc)
-		PRINT_INFO("Device %s successfully recovered!\n",
-			   CARD_BUS_ID(card));
+		dev_info(&card->gdev->dev,
+			"Device successfully recovered!\n");
 	else {
 		rtnl_lock();
 		dev_close(card->dev);
 		rtnl_unlock();
-		PRINT_INFO("Device %s could not be recovered!\n",
-			   CARD_BUS_ID(card));
+		dev_warn(&card->gdev->dev, "The qeth device driver "
+			"failed to recover an error on the device\n");
 	}
 	return 0;
 }
 
 static int __init qeth_l2_init(void)
 {
-	PRINT_INFO("register layer 2 discipline\n");
+	pr_info("register layer 2 discipline\n");
 	return 0;
 }
 
 static void __exit qeth_l2_exit(void)
 {
-	PRINT_INFO("unregister layer 2 discipline\n");
+	pr_info("unregister layer 2 discipline\n");
 }
 
 static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index ed59fed..c0b30b2 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -8,6 +8,9 @@
  *		 Frank Blaschka <frank.blaschka@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "qeth"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/string.h>
@@ -917,8 +920,8 @@
 	if (rc) {
 		QETH_DBF_TEXT(TRACE, 2, "FAILED");
 		qeth_l3_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf);
-		PRINT_WARN("Could not register IP address %s (rc=0x%x/%d)\n",
-			   buf, rc, rc);
+		dev_warn(&card->gdev->dev,
+			"Registering IP address %s failed\n", buf);
 	}
 	return rc;
 }
@@ -1029,24 +1032,22 @@
 	QETH_DBF_TEXT(SETUP, 2, "setadprm");
 
 	if (!qeth_is_supported(card, IPA_SETADAPTERPARMS)) {
-		PRINT_WARN("set adapter parameters not supported "
-			   "on device %s.\n",
-			   CARD_BUS_ID(card));
+		dev_info(&card->gdev->dev,
+			"set adapter parameters not supported.\n");
 		QETH_DBF_TEXT(SETUP, 2, " notsupp");
 		return 0;
 	}
 	rc = qeth_query_setadapterparms(card);
 	if (rc) {
-		PRINT_WARN("couldn't set adapter parameters on device %s: "
-			   "x%x\n", CARD_BUS_ID(card), rc);
+		QETH_DBF_MESSAGE(2, "%s couldn't set adapter parameters: "
+			"0x%x\n", card->gdev->dev.bus_id, rc);
 		return rc;
 	}
 	if (qeth_adp_supported(card, IPA_SETADP_ALTER_MAC_ADDRESS)) {
 		rc = qeth_setadpparms_change_macaddr(card);
 		if (rc)
-			PRINT_WARN("couldn't get MAC address on "
-				   "device %s: x%x\n",
-				   CARD_BUS_ID(card), rc);
+			dev_warn(&card->gdev->dev, "Reading the adapter MAC"
+				" address failed\n", rc);
 	}
 
 	if ((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
@@ -1160,16 +1161,17 @@
 	QETH_DBF_TEXT(TRACE, 3, "ipaarp");
 
 	if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
-		PRINT_WARN("ARP processing not supported "
-			   "on %s!\n", QETH_CARD_IFNAME(card));
+		dev_info(&card->gdev->dev,
+			"ARP processing not supported on %s!\n",
+			QETH_CARD_IFNAME(card));
 		return 0;
 	}
 	rc = qeth_l3_send_simple_setassparms(card, IPA_ARP_PROCESSING,
 					IPA_CMD_ASS_START, 0);
 	if (rc) {
-		PRINT_WARN("Could not start ARP processing "
-			   "assist on %s: 0x%x\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_warn(&card->gdev->dev,
+			"Starting ARP processing support for %s failed\n",
+			QETH_CARD_IFNAME(card));
 	}
 	return rc;
 }
@@ -1181,19 +1183,21 @@
 	QETH_DBF_TEXT(TRACE, 3, "ipaipfrg");
 
 	if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) {
-		PRINT_INFO("Hardware IP fragmentation not supported on %s\n",
-			   QETH_CARD_IFNAME(card));
+		dev_info(&card->gdev->dev,
+			"Hardware IP fragmentation not supported on %s\n",
+			QETH_CARD_IFNAME(card));
 		return  -EOPNOTSUPP;
 	}
 
 	rc = qeth_l3_send_simple_setassparms(card, IPA_IP_FRAGMENTATION,
 					  IPA_CMD_ASS_START, 0);
 	if (rc) {
-		PRINT_WARN("Could not start Hardware IP fragmentation "
-			   "assist on %s: 0x%x\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_warn(&card->gdev->dev,
+			"Starting IP fragmentation support for %s failed\n",
+			QETH_CARD_IFNAME(card));
 	} else
-		PRINT_INFO("Hardware IP fragmentation enabled \n");
+		dev_info(&card->gdev->dev,
+			"Hardware IP fragmentation enabled \n");
 	return rc;
 }
 
@@ -1207,17 +1211,18 @@
 		return -EOPNOTSUPP;
 
 	if (!qeth_is_supported(card, IPA_SOURCE_MAC)) {
-		PRINT_INFO("Inbound source address not "
-			   "supported on %s\n", QETH_CARD_IFNAME(card));
+		dev_info(&card->gdev->dev,
+			"Inbound source address not supported on %s\n",
+			QETH_CARD_IFNAME(card));
 		return -EOPNOTSUPP;
 	}
 
 	rc = qeth_l3_send_simple_setassparms(card, IPA_SOURCE_MAC,
 					  IPA_CMD_ASS_START, 0);
 	if (rc)
-		PRINT_WARN("Could not start inbound source "
-			   "assist on %s: 0x%x\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_warn(&card->gdev->dev,
+			"Starting proxy ARP support for %s failed\n",
+			QETH_CARD_IFNAME(card));
 	return rc;
 }
 
@@ -1228,19 +1233,19 @@
 	QETH_DBF_TEXT(TRACE, 3, "strtvlan");
 
 	if (!qeth_is_supported(card, IPA_FULL_VLAN)) {
-		PRINT_WARN("VLAN not supported on %s\n",
-				QETH_CARD_IFNAME(card));
+		dev_info(&card->gdev->dev,
+			"VLAN not supported on %s\n", QETH_CARD_IFNAME(card));
 		return -EOPNOTSUPP;
 	}
 
 	rc = qeth_l3_send_simple_setassparms(card, IPA_VLAN_PRIO,
 					  IPA_CMD_ASS_START, 0);
 	if (rc) {
-		PRINT_WARN("Could not start vlan "
-			   "assist on %s: 0x%x\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_warn(&card->gdev->dev,
+			"Starting VLAN support for %s failed\n",
+			QETH_CARD_IFNAME(card));
 	} else {
-		PRINT_INFO("VLAN enabled \n");
+		dev_info(&card->gdev->dev, "VLAN enabled\n");
 	}
 	return rc;
 }
@@ -1252,19 +1257,20 @@
 	QETH_DBF_TEXT(TRACE, 3, "stmcast");
 
 	if (!qeth_is_supported(card, IPA_MULTICASTING)) {
-		PRINT_WARN("Multicast not supported on %s\n",
-			   QETH_CARD_IFNAME(card));
+		dev_info(&card->gdev->dev,
+			"Multicast not supported on %s\n",
+			QETH_CARD_IFNAME(card));
 		return -EOPNOTSUPP;
 	}
 
 	rc = qeth_l3_send_simple_setassparms(card, IPA_MULTICASTING,
 					  IPA_CMD_ASS_START, 0);
 	if (rc) {
-		PRINT_WARN("Could not start multicast "
-			   "assist on %s: rc=%i\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_warn(&card->gdev->dev,
+			"Starting multicast support for %s failed\n",
+			QETH_CARD_IFNAME(card));
 	} else {
-		PRINT_INFO("Multicast enabled\n");
+		dev_info(&card->gdev->dev, "Multicast enabled\n");
 		card->dev->flags |= IFF_MULTICAST;
 	}
 	return rc;
@@ -1315,36 +1321,37 @@
 
 	rc = qeth_l3_query_ipassists(card, QETH_PROT_IPV6);
 	if (rc) {
-		PRINT_ERR("IPv6 query ipassist failed on %s\n",
-			  QETH_CARD_IFNAME(card));
+		dev_err(&card->gdev->dev,
+			"Activating IPv6 support for %s failed\n",
+			QETH_CARD_IFNAME(card));
 		return rc;
 	}
 	rc = qeth_l3_send_simple_setassparms(card, IPA_IPV6,
 					  IPA_CMD_ASS_START, 3);
 	if (rc) {
-		PRINT_WARN("IPv6 start assist (version 4) failed "
-			   "on %s: 0x%x\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_err(&card->gdev->dev,
+			"Activating IPv6 support for %s failed\n",
+			QETH_CARD_IFNAME(card));
 		return rc;
 	}
 	rc = qeth_l3_send_simple_setassparms_ipv6(card, IPA_IPV6,
 					       IPA_CMD_ASS_START);
 	if (rc) {
-		PRINT_WARN("IPV6 start assist (version 6) failed  "
-			   "on %s: 0x%x\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_err(&card->gdev->dev,
+			"Activating IPv6 support for %s failed\n",
+			 QETH_CARD_IFNAME(card));
 		return rc;
 	}
 	rc = qeth_l3_send_simple_setassparms_ipv6(card, IPA_PASSTHRU,
 					       IPA_CMD_ASS_START);
 	if (rc) {
-		PRINT_WARN("Could not enable passthrough "
-			   "on %s: 0x%x\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_warn(&card->gdev->dev,
+			"Enabling the passthrough mode for %s failed\n",
+			QETH_CARD_IFNAME(card));
 		return rc;
 	}
 out:
-	PRINT_INFO("IPV6 enabled \n");
+	dev_info(&card->gdev->dev, "IPV6 enabled\n");
 	return 0;
 }
 #endif
@@ -1356,8 +1363,8 @@
 	QETH_DBF_TEXT(TRACE, 3, "strtipv6");
 
 	if (!qeth_is_supported(card, IPA_IPV6)) {
-		PRINT_WARN("IPv6 not supported on %s\n",
-			   QETH_CARD_IFNAME(card));
+		dev_info(&card->gdev->dev,
+			"IPv6 not supported on %s\n", QETH_CARD_IFNAME(card));
 		return 0;
 	}
 #ifdef CONFIG_QETH_IPV6
@@ -1373,34 +1380,35 @@
 	QETH_DBF_TEXT(TRACE, 3, "stbrdcst");
 	card->info.broadcast_capable = 0;
 	if (!qeth_is_supported(card, IPA_FILTERING)) {
-		PRINT_WARN("Broadcast not supported on %s\n",
-			   QETH_CARD_IFNAME(card));
+		dev_info(&card->gdev->dev,
+			"Broadcast not supported on %s\n",
+			QETH_CARD_IFNAME(card));
 		rc = -EOPNOTSUPP;
 		goto out;
 	}
 	rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING,
 					  IPA_CMD_ASS_START, 0);
 	if (rc) {
-		PRINT_WARN("Could not enable broadcasting filtering "
-			   "on %s: 0x%x\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_warn(&card->gdev->dev, "Enabling broadcast filtering for "
+			"%s failed\n", QETH_CARD_IFNAME(card));
 		goto out;
 	}
 
 	rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING,
 					  IPA_CMD_ASS_CONFIGURE, 1);
 	if (rc) {
-		PRINT_WARN("Could not set up broadcast filtering on %s: 0x%x\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_warn(&card->gdev->dev,
+			"Setting up broadcast filtering for %s failed\n",
+			QETH_CARD_IFNAME(card));
 		goto out;
 	}
 	card->info.broadcast_capable = QETH_BROADCAST_WITH_ECHO;
-	PRINT_INFO("Broadcast enabled \n");
+	dev_info(&card->gdev->dev, "Broadcast enabled\n");
 	rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING,
 					  IPA_CMD_ASS_ENABLE, 1);
 	if (rc) {
-		PRINT_WARN("Could not set up broadcast echo filtering on "
-			   "%s: 0x%x\n", QETH_CARD_IFNAME(card), rc);
+		dev_warn(&card->gdev->dev, "Setting up broadcast echo "
+			"filtering for %s failed\n", QETH_CARD_IFNAME(card));
 		goto out;
 	}
 	card->info.broadcast_capable = QETH_BROADCAST_WITHOUT_ECHO;
@@ -1419,18 +1427,18 @@
 	rc = qeth_l3_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
 					  IPA_CMD_ASS_START, 0);
 	if (rc) {
-		PRINT_WARN("Starting Inbound HW Checksumming failed on %s: "
-			   "0x%x,\ncontinuing using Inbound SW Checksumming\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_warn(&card->gdev->dev, "Starting HW checksumming for %s "
+			"failed, using SW checksumming\n",
+			QETH_CARD_IFNAME(card));
 		return rc;
 	}
 	rc = qeth_l3_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
 					  IPA_CMD_ASS_ENABLE,
 					  card->info.csum_mask);
 	if (rc) {
-		PRINT_WARN("Enabling Inbound HW Checksumming failed on %s: "
-			   "0x%x,\ncontinuing using Inbound SW Checksumming\n",
-			   QETH_CARD_IFNAME(card), rc);
+		dev_warn(&card->gdev->dev, "Enabling HW checksumming for %s "
+			"failed, using SW checksumming\n",
+			QETH_CARD_IFNAME(card));
 		return rc;
 	}
 	return 0;
@@ -1443,26 +1451,30 @@
 	QETH_DBF_TEXT(TRACE, 3, "strtcsum");
 
 	if (card->options.checksum_type == NO_CHECKSUMMING) {
-		PRINT_WARN("Using no checksumming on %s.\n",
-			   QETH_CARD_IFNAME(card));
+		dev_info(&card->gdev->dev,
+			"Using no checksumming on %s.\n",
+			QETH_CARD_IFNAME(card));
 		return 0;
 	}
 	if (card->options.checksum_type == SW_CHECKSUMMING) {
-		PRINT_WARN("Using SW checksumming on %s.\n",
-			   QETH_CARD_IFNAME(card));
+		dev_info(&card->gdev->dev,
+			"Using SW checksumming on %s.\n",
+			QETH_CARD_IFNAME(card));
 		return 0;
 	}
 	if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) {
-		PRINT_WARN("Inbound HW Checksumming not "
-			   "supported on %s,\ncontinuing "
-			   "using Inbound SW Checksumming\n",
-			   QETH_CARD_IFNAME(card));
+		dev_info(&card->gdev->dev,
+			"Inbound HW Checksumming not "
+			"supported on %s,\ncontinuing "
+			"using Inbound SW Checksumming\n",
+			QETH_CARD_IFNAME(card));
 		card->options.checksum_type = SW_CHECKSUMMING;
 		return 0;
 	}
 	rc = qeth_l3_send_checksum_command(card);
 	if (!rc)
-		PRINT_INFO("HW Checksumming (inbound) enabled \n");
+		dev_info(&card->gdev->dev,
+			"HW Checksumming (inbound) enabled\n");
 
 	return rc;
 }
@@ -1474,18 +1486,20 @@
 	QETH_DBF_TEXT(TRACE, 3, "sttso");
 
 	if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
-		PRINT_WARN("Outbound TSO not supported on %s\n",
-			   QETH_CARD_IFNAME(card));
+		dev_info(&card->gdev->dev,
+			"Outbound TSO not supported on %s\n",
+			QETH_CARD_IFNAME(card));
 		rc = -EOPNOTSUPP;
 	} else {
 		rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
 						IPA_CMD_ASS_START, 0);
 		if (rc)
-			PRINT_WARN("Could not start outbound TSO "
-				   "assist on %s: rc=%i\n",
-				   QETH_CARD_IFNAME(card), rc);
+			dev_warn(&card->gdev->dev, "Starting outbound TCP "
+				"segmentation offload for %s failed\n",
+				QETH_CARD_IFNAME(card));
 		else
-			PRINT_INFO("Outbound TSO enabled\n");
+			dev_info(&card->gdev->dev,
+				"Outbound TSO enabled\n");
 	}
 	if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)) {
 		card->options.large_send = QETH_LARGE_SEND_NO;
@@ -1578,12 +1592,8 @@
 	else {
 		card->info.unique_id =  UNIQUE_ID_IF_CREATE_ADDR_FAILED |
 					UNIQUE_ID_NOT_BY_CARD;
-		PRINT_WARN("couldn't get a unique id from the card on device "
-			   "%s (result=x%x), using default id. ipv6 "
-			   "autoconfig on other lpars may lead to duplicate "
-			   "ip addresses. please use manually "
-			   "configured ones.\n",
-			   CARD_BUS_ID(card), cmd->hdr.return_code);
+		dev_warn(&card->gdev->dev, "The network adapter failed to "
+			"generate a unique ID\n");
 	}
 	return 0;
 }
@@ -3086,9 +3096,8 @@
 	if (rc) {
 		QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
 		if (rc == 0xe080) {
-			PRINT_WARN("LAN on card %s if offline! "
-				   "Waiting for STARTLAN from card.\n",
-				   CARD_BUS_ID(card));
+			dev_warn(&card->gdev->dev,
+				"The LAN is offline\n");
 			card->lan_online = 0;
 		}
 		return rc;
@@ -3194,8 +3203,8 @@
 	if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))
 		return 0;
 	QETH_DBF_TEXT(TRACE, 2, "recover2");
-	PRINT_WARN("Recovery of device %s started ...\n",
-		   CARD_BUS_ID(card));
+	dev_warn(&card->gdev->dev,
+		"A recovery process has been started for the device\n");
 	card->use_hard_stop = 1;
 	__qeth_l3_set_offline(card->gdev, 1);
 	rc = __qeth_l3_set_online(card->gdev, 1);
@@ -3203,14 +3212,14 @@
 	qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
 	qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
 	if (!rc)
-		PRINT_INFO("Device %s successfully recovered!\n",
-			   CARD_BUS_ID(card));
+		dev_info(&card->gdev->dev,
+			"Device successfully recovered!\n");
 	else {
 		rtnl_lock();
 		dev_close(card->dev);
 		rtnl_unlock();
-		PRINT_INFO("Device %s could not be recovered!\n",
-			   CARD_BUS_ID(card));
+		dev_warn(&card->gdev->dev, "The qeth device driver "
+			"failed to recover an error on the device\n");
 	}
 	return 0;
 }
@@ -3344,7 +3353,7 @@
 		return rc;
 	}
 #else
-	PRINT_WARN("layer 3 discipline no IPv6 support\n");
+	pr_warning("There is no IPv6 support for the layer 3 discipline\n");
 #endif
 	return 0;
 }
@@ -3363,7 +3372,7 @@
 {
 	int rc = 0;
 
-	PRINT_INFO("register layer 3 discipline\n");
+	pr_info("register layer 3 discipline\n");
 	rc = qeth_l3_register_notifiers();
 	return rc;
 }
@@ -3371,7 +3380,7 @@
 static void __exit qeth_l3_exit(void)
 {
 	qeth_l3_unregister_notifiers();
-	PRINT_INFO("unregister layer 3 discipline\n");
+	pr_info("unregister layer 3 discipline\n");
 }
 
 module_init(qeth_l3_init);
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 3d4e3e3..e529b55 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -25,9 +25,15 @@
  *            Sven Schuetz
  */
 
+#define KMSG_COMPONENT "zfcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/miscdevice.h>
+#include <linux/seq_file.h>
 #include "zfcp_ext.h"
 
+#define ZFCP_BUS_ID_SIZE	20
+
 static char *device;
 
 MODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com");
@@ -83,9 +89,9 @@
 	strcpy(str, devstr);
 
 	token = strsep(&str, ",");
-	if (!token || strlen(token) >= BUS_ID_SIZE)
+	if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE)
 		goto err_out;
-	strncpy(zfcp_data.init_busid, token, BUS_ID_SIZE);
+	strncpy(zfcp_data.init_busid, token, ZFCP_BUS_ID_SIZE);
 
 	token = strsep(&str, ",");
 	if (!token || strict_strtoull(token, 0,
@@ -102,7 +108,7 @@
 
  err_out:
 	kfree(str);
-	pr_err("zfcp: %s is not a valid SCSI device\n", devstr);
+	pr_err("%s is not a valid SCSI device\n", devstr);
 	return 0;
 }
 
@@ -186,13 +192,13 @@
 
 	retval = misc_register(&zfcp_cfdc_misc);
 	if (retval) {
-		pr_err("zfcp: Registering the misc device zfcp_cfdc failed\n");
+		pr_err("Registering the misc device zfcp_cfdc failed\n");
 		goto out_misc;
 	}
 
 	retval = zfcp_ccw_register();
 	if (retval) {
-		pr_err("zfcp: The zfcp device driver could not register with "
+		pr_err("The zfcp device driver could not register with "
 		       "the common I/O layer\n");
 		goto out_ccw_register;
 	}
@@ -436,6 +442,16 @@
 					     stat_work));
 }
 
+static void zfcp_print_sl(struct seq_file *m, struct service_level *sl)
+{
+	struct zfcp_adapter *adapter =
+		container_of(sl, struct zfcp_adapter, service_level);
+
+	seq_printf(m, "zfcp: %s microcode level %x\n",
+		   dev_name(&adapter->ccw_device->dev),
+		   adapter->fsf_lic_version);
+}
+
 /**
  * zfcp_adapter_enqueue - enqueue a new adapter to the list
  * @ccw_device: pointer to the struct cc_device
@@ -500,6 +516,8 @@
 	INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
 	INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later);
 
+	adapter->service_level.seq_print = zfcp_print_sl;
+
 	/* mark adapter unusable as long as sysfs registration is not complete */
 	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
 
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 951a8d4..7281471 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -6,6 +6,9 @@
  * Copyright IBM Corporation 2002, 2008
  */
 
+#define KMSG_COMPONENT "zfcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include "zfcp_ext.h"
 
 /**
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c
index ec2abce..f1a7518 100644
--- a/drivers/s390/scsi/zfcp_cfdc.c
+++ b/drivers/s390/scsi/zfcp_cfdc.c
@@ -7,6 +7,9 @@
  * Copyright IBM Corporation 2008
  */
 
+#define KMSG_COMPONENT "zfcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/types.h>
 #include <linux/miscdevice.h>
 #include <asm/ccwdev.h>
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 31012d5..735d675 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -6,6 +6,9 @@
  * Copyright IBM Corporation 2002, 2008
  */
 
+#define KMSG_COMPONENT "zfcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/ctype.h>
 #include <asm/debug.h>
 #include "zfcp_ext.h"
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 9ce4c75..e19e46a 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -33,6 +33,7 @@
 #include <asm/qdio.h>
 #include <asm/debug.h>
 #include <asm/ebcdic.h>
+#include <asm/sysinfo.h>
 #include "zfcp_dbf.h"
 #include "zfcp_fsf.h"
 
@@ -515,6 +516,7 @@
 	struct fsf_qtcb_bottom_port *stats_reset_data;
 	unsigned long		stats_reset;
 	struct work_struct	scan_work;
+	struct service_level	service_level;
 	atomic_t		qdio_outb_full;	   /* queue full incidents */
 };
 
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index c557ba3..4ed4950 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -6,6 +6,9 @@
  * Copyright IBM Corporation 2002, 2008
  */
 
+#define KMSG_COMPONENT "zfcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include "zfcp_ext.h"
 
 #define ZFCP_MAX_ERPS                   3
@@ -1281,10 +1284,13 @@
 		break;
 
 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
-		if (result != ZFCP_ERP_SUCCEEDED)
+		if (result != ZFCP_ERP_SUCCEEDED) {
+			unregister_service_level(&adapter->service_level);
 			zfcp_erp_rports_del(adapter);
-		else
+		} else {
+			register_service_level(&adapter->service_level);
 			schedule_work(&adapter->scan_work);
+		}
 		zfcp_adapter_put(adapter);
 		break;
 	}
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 8aab309..f009f2a 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -6,6 +6,9 @@
  * Copyright IBM Corporation 2008
  */
 
+#define KMSG_COMPONENT "zfcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include "zfcp_ext.h"
 
 struct ct_iu_gpn_ft_req {
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index dc03676..9c72e08 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -6,6 +6,9 @@
  * Copyright IBM Corporation 2002, 2008
  */
 
+#define KMSG_COMPONENT "zfcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/blktrace_api.h>
 #include "zfcp_ext.h"
 
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 664752f..d3b55fb6 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -6,6 +6,9 @@
  * Copyright IBM Corporation 2002, 2008
  */
 
+#define KMSG_COMPONENT "zfcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include "zfcp_ext.h"
 
 /* FIXME(tune): free space should be one max. SBAL chain plus what? */
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 468c880..9dc42a6 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -6,6 +6,9 @@
  * Copyright IBM Corporation 2002, 2008
  */
 
+#define KMSG_COMPONENT "zfcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include "zfcp_ext.h"
 #include <asm/atomic.h>
 
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index ca9293b..899af2b 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -6,6 +6,9 @@
  * Copyright IBM Corporation 2008
  */
 
+#define KMSG_COMPONENT "zfcp"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include "zfcp_ext.h"
 
 #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \
diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
index c3e4ab0..0eea907 100644
--- a/drivers/s390/sysinfo.c
+++ b/drivers/s390/sysinfo.c
@@ -1,17 +1,21 @@
 /*
  *  drivers/s390/sysinfo.c
  *
- *    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com)
+ *  Copyright IBM Corp. 2001, 2008
+ *  Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com)
+ *	       Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <asm/ebcdic.h>
 #include <asm/sysinfo.h>
+#include <asm/cpcmd.h>
 
 /* Sigh, math-emu. Don't ask. */
 #include <asm/sfp-util.h>
@@ -271,6 +275,125 @@
 
 __initcall(create_proc_sysinfo);
 
+/*
+ * Service levels interface.
+ */
+
+static DECLARE_RWSEM(service_level_sem);
+static LIST_HEAD(service_level_list);
+
+int register_service_level(struct service_level *slr)
+{
+	struct service_level *ptr;
+
+	down_write(&service_level_sem);
+	list_for_each_entry(ptr, &service_level_list, list)
+		if (ptr == slr) {
+			up_write(&service_level_sem);
+			return -EEXIST;
+		}
+	list_add_tail(&slr->list, &service_level_list);
+	up_write(&service_level_sem);
+	return 0;
+}
+EXPORT_SYMBOL(register_service_level);
+
+int unregister_service_level(struct service_level *slr)
+{
+	struct service_level *ptr, *next;
+	int rc = -ENOENT;
+
+	down_write(&service_level_sem);
+	list_for_each_entry_safe(ptr, next, &service_level_list, list) {
+		if (ptr != slr)
+			continue;
+		list_del(&ptr->list);
+		rc = 0;
+		break;
+	}
+	up_write(&service_level_sem);
+	return rc;
+}
+EXPORT_SYMBOL(unregister_service_level);
+
+static void *service_level_start(struct seq_file *m, loff_t *pos)
+{
+	down_read(&service_level_sem);
+	return seq_list_start(&service_level_list, *pos);
+}
+
+static void *service_level_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	return seq_list_next(p, &service_level_list, pos);
+}
+
+static void service_level_stop(struct seq_file *m, void *p)
+{
+	up_read(&service_level_sem);
+}
+
+static int service_level_show(struct seq_file *m, void *p)
+{
+	struct service_level *slr;
+
+	slr = list_entry(p, struct service_level, list);
+	slr->seq_print(m, slr);
+	return 0;
+}
+
+static const struct seq_operations service_level_seq_ops = {
+	.start		= service_level_start,
+	.next		= service_level_next,
+	.stop		= service_level_stop,
+	.show		= service_level_show
+};
+
+static int service_level_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &service_level_seq_ops);
+}
+
+static const struct file_operations service_level_ops = {
+	.open		= service_level_open,
+	.read		= seq_read,
+	.llseek 	= seq_lseek,
+	.release	= seq_release
+};
+
+static void service_level_vm_print(struct seq_file *m,
+				   struct service_level *slr)
+{
+	char *query_buffer, *str;
+
+	query_buffer = kmalloc(1024, GFP_KERNEL | GFP_DMA);
+	if (!query_buffer)
+		return;
+	cpcmd("QUERY CPLEVEL", query_buffer, 1024, NULL);
+	str = strchr(query_buffer, '\n');
+	if (str)
+		*str = 0;
+	seq_printf(m, "VM: %s\n", query_buffer);
+	kfree(query_buffer);
+}
+
+static struct service_level service_level_vm = {
+	.seq_print = service_level_vm_print
+};
+
+static __init int create_proc_service_level(void)
+{
+	proc_create("service_levels", 0, NULL, &service_level_ops);
+	if (MACHINE_IS_VM)
+		register_service_level(&service_level_vm);
+	return 0;
+}
+
+subsys_initcall(create_proc_service_level);
+
+/*
+ * Bogomips calculation based on cpu capability.
+ */
+
 int get_cpu_capability(unsigned int *capability)
 {
 	struct sysinfo_1_2_2 *info;
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index ed6c54c..e11bce6 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -1601,14 +1601,14 @@
 	case AF_INET:
 		sin = (struct sockaddr_in *)addr;
 		spin_lock_bh(&conn->session->lock);
-		sprintf(buf, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
+		sprintf(buf, "%pI4", &sin->sin_addr.s_addr);
 		*port = be16_to_cpu(sin->sin_port);
 		spin_unlock_bh(&conn->session->lock);
 		break;
 	case AF_INET6:
 		sin6 = (struct sockaddr_in6 *)addr;
 		spin_lock_bh(&conn->session->lock);
-		sprintf(buf, NIP6_FMT, NIP6(sin6->sin6_addr));
+		sprintf(buf, "%pI6", &sin6->sin6_addr);
 		*port = be16_to_cpu(sin6->sin6_port);
 		spin_unlock_bh(&conn->session->lock);
 		break;
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 0248919..bf2a1c5 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -47,7 +47,6 @@
 
 #include <asm/macintosh.h>
 #include <asm/macints.h>
-#include <asm/machw.h>
 #include <asm/mac_via.h>
 
 #include "scsi.h"
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index db7ea3b..eb3a414 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -206,8 +206,7 @@
 		break;
 	case ISCSI_PARAM_CONN_ADDRESS:
 		/* TODO: what are the ipv6 bits */
-		len = sprintf(buf, "%u.%u.%u.%u\n",
-			      NIPQUAD(ddb_entry->ip_addr));
+		len = sprintf(buf, "%pI4\n", &ddb_entry->ip_addr);
 		break;
 	default:
 		return -ENOSYS;
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 28c00c3..0c3a2ab 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -429,14 +429,24 @@
 static void
 mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-	/* Not implemented */
+	if (mctrl & TIOCM_RTS)
+		out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS);
+	else
+		out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS);
 }
 
 static unsigned int
 mpc52xx_uart_get_mctrl(struct uart_port *port)
 {
-	/* Not implemented */
-	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+	unsigned int ret = TIOCM_DSR;
+	u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+
+	if (!(status & MPC52xx_PSC_CTS))
+		ret |= TIOCM_CTS;
+	if (!(status & MPC52xx_PSC_DCD))
+		ret |= TIOCM_CAR;
+
+	return ret;
 }
 
 static void
@@ -479,7 +489,15 @@
 static void
 mpc52xx_uart_enable_ms(struct uart_port *port)
 {
-	/* Not implemented */
+	struct mpc52xx_psc __iomem *psc = PSC(port);
+
+	/* clear D_*-bits by reading them */
+	in_8(&psc->mpc52xx_psc_ipcr);
+	/* enable CTS and DCD as IPC interrupts */
+	out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
+
+	port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
+	out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
 }
 
 static void
@@ -580,6 +598,10 @@
 			MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
 			MPC52xx_PSC_MODE_ONE_STOP;
 
+	if (new->c_cflag & CRTSCTS) {
+		mr1 |= MPC52xx_PSC_MODE_RXRTS;
+		mr2 |= MPC52xx_PSC_MODE_TXCTS;
+	}
 
 	baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
 	quot = uart_get_divisor(port, baud);
@@ -617,6 +639,9 @@
 	out_8(&psc->ctur, ctr >> 8);
 	out_8(&psc->ctlr, ctr & 0xff);
 
+	if (UART_ENABLE_MS(port, new->c_cflag))
+		mpc52xx_uart_enable_ms(port);
+
 	/* Reenable TX & RX */
 	out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
 	out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
@@ -752,10 +777,15 @@
 			if (status & MPC52xx_PSC_SR_RB) {
 				flag = TTY_BREAK;
 				uart_handle_break(port);
-			} else if (status & MPC52xx_PSC_SR_PE)
+				port->icount.brk++;
+			} else if (status & MPC52xx_PSC_SR_PE) {
 				flag = TTY_PARITY;
-			else if (status & MPC52xx_PSC_SR_FE)
+				port->icount.parity++;
+			}
+			else if (status & MPC52xx_PSC_SR_FE) {
 				flag = TTY_FRAME;
+				port->icount.frame++;
+			}
 
 			/* Clear error condition */
 			out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
@@ -769,6 +799,7 @@
 			 * affect the current character
 			 */
 			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+			port->icount.overrun++;
 		}
 	}
 
@@ -826,6 +857,7 @@
 	struct uart_port *port = dev_id;
 	unsigned long pass = ISR_PASS_LIMIT;
 	unsigned int keepgoing;
+	u8 status;
 
 	spin_lock(&port->lock);
 
@@ -842,6 +874,13 @@
 		if (psc_ops->tx_rdy(port))
 			keepgoing |= mpc52xx_uart_int_tx_chars(port);
 
+		status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+		if (status & MPC52xx_PSC_D_DCD)
+			uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD));
+
+		if (status & MPC52xx_PSC_D_CTS)
+			uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS));
+
 		/* Limit number of iteration */
 		if (!(--pass))
 			keepgoing = 0;
@@ -1109,22 +1148,29 @@
 		return ret;
 
 	port->mapbase = res.start;
+	if (!port->mapbase) {
+		dev_dbg(&op->dev, "Could not allocate resources for PSC\n");
+		return -EINVAL;
+	}
+
 	port->irq = irq_of_parse_and_map(op->node, 0);
+	if (port->irq == NO_IRQ) {
+		dev_dbg(&op->dev, "Could not get irq\n");
+		return -EINVAL;
+	}
 
 	dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
 		(void *)port->mapbase, port->irq, port->uartclk);
 
-	if ((port->irq == NO_IRQ) || !port->mapbase) {
-		printk(KERN_ERR "Could not allocate resources for PSC\n");
-		return -EINVAL;
-	}
-
 	/* Add the port to the uart sub-system */
 	ret = uart_add_one_port(&mpc52xx_uart_driver, port);
-	if (!ret)
-		dev_set_drvdata(&op->dev, (void *)port);
+	if (ret) {
+		irq_dispose_mapping(port->irq);
+		return ret;
+	}
 
-	return ret;
+	dev_set_drvdata(&op->dev, (void *)port);
+	return 0;
 }
 
 static int
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 317b061..ad34885 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1383,6 +1383,29 @@
 	return -EINVAL;
 }
 
+#ifdef CONFIG_CONSOLE_POLL
+
+static int pmz_poll_get_char(struct uart_port *port)
+{
+	struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+	while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0)
+		udelay(5);
+	return read_zsdata(uap);
+}
+
+static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
+{
+	struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+	/* Wait for the transmit buffer to empty. */
+	while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
+		udelay(5);
+	write_zsdata(uap, c);
+}
+
+#endif
+
 static struct uart_ops pmz_pops = {
 	.tx_empty	=	pmz_tx_empty,
 	.set_mctrl	=	pmz_set_mctrl,
@@ -1400,6 +1423,10 @@
 	.request_port	=	pmz_request_port,
 	.config_port	=	pmz_config_port,
 	.verify_port	=	pmz_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_get_char	=	pmz_poll_get_char,
+	.poll_put_char	=	pmz_poll_put_char,
+#endif
 };
 
 /*
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 165fc01..557b54a 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -51,7 +51,6 @@
 #ifdef CONFIG_SUPERH
 #include <asm/clock.h>
 #include <asm/sh_bios.h>
-#include <asm/kgdb.h>
 #endif
 
 #include "sh-sci.h"
@@ -65,10 +64,6 @@
 	/* Port IRQs: ERI, RXI, TXI, BRI (optional) */
 	unsigned int		irqs[SCIx_NR_IRQS];
 
-	/* Port pin configuration */
-	void			(*init_pins)(struct uart_port *port,
-					     unsigned int cflag);
-
 	/* Port enable callback */
 	void			(*enable)(struct uart_port *port);
 
@@ -85,10 +80,6 @@
 #endif
 };
 
-#ifdef CONFIG_SH_KGDB
-static struct sci_port *kgdb_sci_port;
-#endif
-
 #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
 static struct sci_port *serial_console_port;
 #endif
@@ -101,21 +92,26 @@
 static struct sci_port sci_ports[SCI_NPORTS];
 static struct uart_driver sci_uart_driver;
 
-#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && \
-    defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+static inline struct sci_port *
+to_sci_port(struct uart_port *uart)
+{
+	return container_of(uart, struct sci_port, port);
+}
+
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+
+#ifdef CONFIG_CONSOLE_POLL
 static inline void handle_error(struct uart_port *port)
 {
 	/* Clear error flags */
 	sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
 }
 
-static int get_char(struct uart_port *port)
+static int sci_poll_get_char(struct uart_port *port)
 {
-	unsigned long flags;
 	unsigned short status;
 	int c;
 
-	spin_lock_irqsave(&port->lock, flags);
 	do {
 		status = sci_in(port, SCxSR);
 		if (status & SCxSR_ERRORS(port)) {
@@ -123,23 +119,21 @@
 			continue;
 		}
 	} while (!(status & SCxSR_RDxF(port)));
+
 	c = sci_in(port, SCxRDR);
-	sci_in(port, SCxSR);            /* Dummy read */
+
+	/* Dummy read */
+	sci_in(port, SCxSR);
 	sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-	spin_unlock_irqrestore(&port->lock, flags);
 
 	return c;
 }
-#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
+#endif
 
-#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || defined(CONFIG_SH_KGDB)
-static void put_char(struct uart_port *port, char c)
+static void sci_poll_put_char(struct uart_port *port, unsigned char c)
 {
-	unsigned long flags;
 	unsigned short status;
 
-	spin_lock_irqsave(&port->lock, flags);
-
 	do {
 		status = sci_in(port, SCxSR);
 	} while (!(status & SCxSR_TDxE(port)));
@@ -147,96 +141,22 @@
 	sci_in(port, SCxSR);            /* Dummy read */
 	sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
 	sci_out(port, SCxTDR, c);
-
-	spin_unlock_irqrestore(&port->lock, flags);
 }
-#endif
-
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
-static void put_string(struct sci_port *sci_port, const char *buffer, int count)
-{
-	struct uart_port *port = &sci_port->port;
-	const unsigned char *p = buffer;
-	int i;
-
-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
-	int checksum;
-	int usegdb=0;
-
-#ifdef CONFIG_SH_STANDARD_BIOS
-	/* This call only does a trap the first time it is
-	 * called, and so is safe to do here unconditionally
-	 */
-	usegdb |= sh_bios_in_gdb_mode();
-#endif
-#ifdef CONFIG_SH_KGDB
-	usegdb |= (kgdb_in_gdb_mode && (sci_port == kgdb_sci_port));
-#endif
-
-	if (usegdb) {
-	    /*  $<packet info>#<checksum>. */
-	    do {
-		unsigned char c;
-		put_char(port, '$');
-		put_char(port, 'O'); /* 'O'utput to console */
-		checksum = 'O';
-
-		for (i=0; i<count; i++) { /* Don't use run length encoding */
-			int h, l;
-
-			c = *p++;
-			h = hex_asc_hi(c);
-			l = hex_asc_lo(c);
-			put_char(port, h);
-			put_char(port, l);
-			checksum += h + l;
-		}
-		put_char(port, '#');
-		put_char(port, hex_asc_hi(checksum));
-		put_char(port, hex_asc_lo(checksum));
-	    } while  (get_char(port) != '+');
-	} else
-#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
-	for (i=0; i<count; i++) {
-		if (*p == 10)
-			put_char(port, '\r');
-		put_char(port, *p++);
-	}
-}
-#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
-
-#ifdef CONFIG_SH_KGDB
-static int kgdb_sci_getchar(void)
-{
-        int c;
-
-        /* Keep trying to read a character, this could be neater */
-        while ((c = get_char(&kgdb_sci_port->port)) < 0)
-		cpu_relax();
-
-        return c;
-}
-
-static inline void kgdb_sci_putchar(int c)
-{
-        put_char(&kgdb_sci_port->port, c);
-}
-#endif /* CONFIG_SH_KGDB */
+#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
 
 #if defined(__H8300S__)
 enum { sci_disable, sci_enable };
 
-static void h8300_sci_config(struct uart_port* port, unsigned int ctrl)
+static void h8300_sci_config(struct uart_port *port, unsigned int ctrl)
 {
-	volatile unsigned char *mstpcrl=(volatile unsigned char *)MSTPCRL;
+	volatile unsigned char *mstpcrl = (volatile unsigned char *)MSTPCRL;
 	int ch = (port->mapbase  - SMR0) >> 3;
 	unsigned char mask = 1 << (ch+1);
 
-	if (ctrl == sci_disable) {
+	if (ctrl == sci_disable)
 		*mstpcrl |= mask;
-	} else {
+	else
 		*mstpcrl &= ~mask;
-	}
 }
 
 static inline void h8300_sci_enable(struct uart_port *port)
@@ -251,7 +171,7 @@
 #endif
 
 #if defined(__H8300H__) || defined(__H8300S__)
-static void sci_init_pins_sci(struct uart_port* port, unsigned int cflag)
+static void sci_init_pins(struct uart_port *port, unsigned int cflag)
 {
 	int ch = (port->mapbase - SMR0) >> 3;
 
@@ -266,141 +186,99 @@
 	/* tx mark output*/
 	H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
 }
-#else
-#define sci_init_pins_sci NULL
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
-static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
 {
-	unsigned int fcr_val = 0;
-
-	if (cflag & CRTSCTS)
-		fcr_val |= SCFCR_MCE;
-
-	sci_out(port, SCFCR, fcr_val);
-}
-#else
-#define sci_init_pins_irda NULL
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag)
-{
-	unsigned int fcr_val = 0;
-
-	set_sh771x_scif_pfc(port);
-	if (cflag & CRTSCTS) {
-		fcr_val |= SCFCR_MCE;
-	}
-	sci_out(port, SCFCR, fcr_val);
+	if (port->mapbase == 0xA4400000) {
+		__raw_writew(__raw_readw(PACR) & 0xffc0, PACR);
+		__raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR);
+	} else if (port->mapbase == 0xA4410000)
+		__raw_writew(__raw_readw(PBCR) & 0xf003, PBCR);
 }
 #elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721)
-static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
 {
-	unsigned int fcr_val = 0;
 	unsigned short data;
 
 	if (cflag & CRTSCTS) {
 		/* enable RTS/CTS */
 		if (port->mapbase == 0xa4430000) { /* SCIF0 */
 			/* Clear PTCR bit 9-2; enable all scif pins but sck */
-			data = ctrl_inw(PORT_PTCR);
-			ctrl_outw((data & 0xfc03), PORT_PTCR);
+			data = __raw_readw(PORT_PTCR);
+			__raw_writew((data & 0xfc03), PORT_PTCR);
 		} else if (port->mapbase == 0xa4438000) { /* SCIF1 */
 			/* Clear PVCR bit 9-2 */
-			data = ctrl_inw(PORT_PVCR);
-			ctrl_outw((data & 0xfc03), PORT_PVCR);
+			data = __raw_readw(PORT_PVCR);
+			__raw_writew((data & 0xfc03), PORT_PVCR);
 		}
-		fcr_val |= SCFCR_MCE;
 	} else {
 		if (port->mapbase == 0xa4430000) { /* SCIF0 */
 			/* Clear PTCR bit 5-2; enable only tx and rx  */
-			data = ctrl_inw(PORT_PTCR);
-			ctrl_outw((data & 0xffc3), PORT_PTCR);
+			data = __raw_readw(PORT_PTCR);
+			__raw_writew((data & 0xffc3), PORT_PTCR);
 		} else if (port->mapbase == 0xa4438000) { /* SCIF1 */
 			/* Clear PVCR bit 5-2 */
-			data = ctrl_inw(PORT_PVCR);
-			ctrl_outw((data & 0xffc3), PORT_PVCR);
+			data = __raw_readw(PORT_PVCR);
+			__raw_writew((data & 0xffc3), PORT_PVCR);
 		}
 	}
-	sci_out(port, SCFCR, fcr_val);
 }
 #elif defined(CONFIG_CPU_SH3)
 /* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
-static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
 {
-	unsigned int fcr_val = 0;
 	unsigned short data;
 
 	/* We need to set SCPCR to enable RTS/CTS */
-	data = ctrl_inw(SCPCR);
+	data = __raw_readw(SCPCR);
 	/* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
-	ctrl_outw(data & 0x0fcf, SCPCR);
+	__raw_writew(data & 0x0fcf, SCPCR);
 
-	if (cflag & CRTSCTS)
-		fcr_val |= SCFCR_MCE;
-	else {
+	if (!(cflag & CRTSCTS)) {
 		/* We need to set SCPCR to enable RTS/CTS */
-		data = ctrl_inw(SCPCR);
+		data = __raw_readw(SCPCR);
 		/* Clear out SCP7MD1,0, SCP4MD1,0,
 		   Set SCP6MD1,0 = {01} (output)  */
-		ctrl_outw((data & 0x0fcf) | 0x1000, SCPCR);
+		__raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
 
 		data = ctrl_inb(SCPDR);
 		/* Set /RTS2 (bit6) = 0 */
 		ctrl_outb(data & 0xbf, SCPDR);
 	}
-
-	sci_out(port, SCFCR, fcr_val);
 }
 #elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
 {
-	unsigned int fcr_val = 0;
 	unsigned short data;
 
 	if (port->mapbase == 0xffe00000) {
-		data = ctrl_inw(PSCR);
+		data = __raw_readw(PSCR);
 		data &= ~0x03cf;
-		if (cflag & CRTSCTS)
-			fcr_val |= SCFCR_MCE;
-		else
+		if (!(cflag & CRTSCTS))
 			data |= 0x0340;
 
-		ctrl_outw(data, PSCR);
+		__raw_writew(data, PSCR);
 	}
-	/* SCIF1 and SCIF2 should be setup by board code */
-
-	sci_out(port, SCFCR, fcr_val);
 }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
-static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
-{
-	/* Nothing to do here.. */
-	sci_out(port, SCFCR, 0);
-}
-#else
-/* For SH7750 */
-static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
-{
-	unsigned int fcr_val = 0;
-
-	if (cflag & CRTSCTS) {
-		fcr_val |= SCFCR_MCE;
-	} else {
-#if defined(CONFIG_CPU_SUBTYPE_SH7343) || defined(CONFIG_CPU_SUBTYPE_SH7366)
-		/* Nothing */
 #elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
       defined(CONFIG_CPU_SUBTYPE_SH7780) || \
       defined(CONFIG_CPU_SUBTYPE_SH7785) || \
       defined(CONFIG_CPU_SUBTYPE_SHX3)
-		ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+	if (!(cflag & CRTSCTS))
+		__raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */
+}
+#elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A)
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+	if (!(cflag & CRTSCTS))
+		__raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */
+}
 #else
-		ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
-#endif
-	}
-	sci_out(port, SCFCR, fcr_val);
+static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+	/* Nothing to do */
 }
 #endif
 
@@ -419,18 +297,26 @@
 #elif defined(CONFIG_CPU_SUBTYPE_SH7763)
 static inline int scif_txroom(struct uart_port *port)
 {
-	if((port->mapbase == 0xffe00000) || (port->mapbase == 0xffe08000)) /* SCIF0/1*/
+	if ((port->mapbase == 0xffe00000) ||
+	    (port->mapbase == 0xffe08000)) {
+		/* SCIF0/1*/
 		return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff);
-	else /* SCIF2 */
+	} else {
+		/* SCIF2 */
 		return SCIF2_TXROOM_MAX - (sci_in(port, SCFDR) >> 8);
+	}
 }
 
 static inline int scif_rxroom(struct uart_port *port)
 {
-	if((port->mapbase == 0xffe00000) || (port->mapbase == 0xffe08000)) /* SCIF0/1*/
+	if ((port->mapbase == 0xffe00000) ||
+	    (port->mapbase == 0xffe08000)) {
+		/* SCIF0/1*/
 		return sci_in(port, SCRFDR) & 0xff;
-	else /* SCIF2 */
+	} else {
+		/* SCIF2 */
 		return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
+	}
 }
 #else
 static inline int scif_txroom(struct uart_port *port)
@@ -446,12 +332,12 @@
 
 static inline int sci_txroom(struct uart_port *port)
 {
-	return ((sci_in(port, SCxSR) & SCI_TDRE) != 0);
+	return (sci_in(port, SCxSR) & SCI_TDRE) != 0;
 }
 
 static inline int sci_rxroom(struct uart_port *port)
 {
-	return ((sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0);
+	return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
 }
 
 /* ********************************************************************** *
@@ -469,11 +355,10 @@
 	status = sci_in(port, SCxSR);
 	if (!(status & SCxSR_TDxE(port))) {
 		ctrl = sci_in(port, SCSCR);
-		if (uart_circ_empty(xmit)) {
+		if (uart_circ_empty(xmit))
 			ctrl &= ~SCI_CTRL_FLAGS_TIE;
-		} else {
+		else
 			ctrl |= SCI_CTRL_FLAGS_TIE;
-		}
 		sci_out(port, SCSCR, ctrl);
 		return;
 	}
@@ -521,11 +406,11 @@
 }
 
 /* On SH3, SCIF may read end-of-break as a space->mark char */
-#define STEPFN(c)  ({int __c=(c); (((__c-1)|(__c)) == -1); })
+#define STEPFN(c)  ({int __c = (c); (((__c-1)|(__c)) == -1); })
 
 static inline void sci_receive_chars(struct uart_port *port)
 {
-	struct sci_port *sci_port = (struct sci_port *)port;
+	struct sci_port *sci_port = to_sci_port(port);
 	struct tty_struct *tty = port->info->port.tty;
 	int i, count, copied = 0;
 	unsigned short status;
@@ -550,13 +435,13 @@
 
 		if (port->type == PORT_SCI) {
 			char c = sci_in(port, SCxRDR);
-			if (uart_handle_sysrq_char(port, c) || sci_port->break_flag)
+			if (uart_handle_sysrq_char(port, c) ||
+			    sci_port->break_flag)
 				count = 0;
-			else {
+			else
 				tty_insert_flip_char(tty, c, TTY_NORMAL);
-			}
 		} else {
-			for (i=0; i<count; i++) {
+			for (i = 0; i < count; i++) {
 				char c = sci_in(port, SCxRDR);
 				status = sci_in(port, SCxSR);
 #if defined(CONFIG_CPU_SH3)
@@ -569,7 +454,7 @@
 					}
 
 					/* Nonzero => end-of-break */
-					pr_debug("scif: debounce<%02x>\n", c);
+					dev_dbg(port->dev, "debounce<%02x>\n", c);
 					sci_port->break_flag = 0;
 
 					if (STEPFN(c)) {
@@ -586,12 +471,13 @@
 				/* Store data and status */
 				if (status&SCxSR_FER(port)) {
 					flag = TTY_FRAME;
-					pr_debug("sci: frame error\n");
+					dev_notice(port->dev, "frame error\n");
 				} else if (status&SCxSR_PER(port)) {
 					flag = TTY_PARITY;
-					pr_debug("sci: parity error\n");
+					dev_notice(port->dev, "parity error\n");
 				} else
 					flag = TTY_NORMAL;
+
 				tty_insert_flip_char(tty, c, flag);
 			}
 		}
@@ -651,13 +537,14 @@
 		/* overrun error */
 		if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
 			copied++;
-		pr_debug("sci: overrun error\n");
+
+		dev_notice(port->dev, "overrun error");
 	}
 
 	if (status & SCxSR_FER(port)) {
 		if (sci_rxd_in(port) == 0) {
 			/* Notify of BREAK */
-			struct sci_port *sci_port = (struct sci_port *)port;
+			struct sci_port *sci_port = to_sci_port(port);
 
 			if (!sci_port->break_flag) {
 				sci_port->break_flag = 1;
@@ -666,15 +553,19 @@
 				/* Do sysrq handling. */
 				if (uart_handle_break(port))
 					return 0;
-			        pr_debug("sci: BREAK detected\n");
+
+				dev_dbg(port->dev, "BREAK detected\n");
+
 				if (tty_insert_flip_char(tty, 0, TTY_BREAK))
-				        copied++;
-                       }
+					copied++;
+			}
+
 		} else {
 			/* frame error */
 			if (tty_insert_flip_char(tty, 0, TTY_FRAME))
 				copied++;
-			pr_debug("sci: frame error\n");
+
+			dev_notice(port->dev, "frame error\n");
 		}
 	}
 
@@ -682,7 +573,8 @@
 		/* parity error */
 		if (tty_insert_flip_char(tty, 0, TTY_PARITY))
 			copied++;
-		pr_debug("sci: parity error\n");
+
+		dev_notice(port->dev, "parity error");
 	}
 
 	if (copied)
@@ -691,6 +583,27 @@
 	return copied;
 }
 
+static inline int sci_handle_fifo_overrun(struct uart_port *port)
+{
+	struct tty_struct *tty = port->info->port.tty;
+	int copied = 0;
+
+	if (port->type != PORT_SCIF)
+		return 0;
+
+	if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) {
+		sci_out(port, SCLSR, 0);
+
+		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+		tty_flip_buffer_push(tty);
+
+		dev_notice(port->dev, "overrun error\n");
+		copied++;
+	}
+
+	return copied;
+}
+
 static inline int sci_handle_breaks(struct uart_port *port)
 {
 	int copied = 0;
@@ -709,23 +622,15 @@
 		/* Notify of BREAK */
 		if (tty_insert_flip_char(tty, 0, TTY_BREAK))
 			copied++;
-		pr_debug("sci: BREAK detected\n");
-	}
 
-#if defined(SCIF_ORER)
-	/* XXX: Handle SCIF overrun error */
-	if (port->type != PORT_SCI && (sci_in(port, SCLSR) & SCIF_ORER) != 0) {
-		sci_out(port, SCLSR, 0);
-		if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) {
-			copied++;
-			pr_debug("sci: overrun error\n");
-		}
+		dev_dbg(port->dev, "BREAK detected\n");
 	}
-#endif
 
 	if (copied)
 		tty_flip_buffer_push(tty);
 
+	copied += sci_handle_fifo_overrun(port);
+
 	return copied;
 }
 
@@ -763,16 +668,7 @@
 			sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
 		}
 	} else {
-#if defined(SCIF_ORER)
-		if((sci_in(port, SCLSR) & SCIF_ORER) != 0) {
-			struct tty_struct *tty = port->info->port.tty;
-
-			sci_out(port, SCLSR, 0);
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-			tty_flip_buffer_push(tty);
-			pr_debug("scif: overrun error\n");
-		}
-#endif
+		sci_handle_fifo_overrun(port);
 		sci_rx_interrupt(irq, ptr);
 	}
 
@@ -801,8 +697,8 @@
 	struct uart_port *port = ptr;
 	irqreturn_t ret = IRQ_NONE;
 
-        ssr_status = sci_in(port,SCxSR);
-        scr_status = sci_in(port,SCSCR);
+	ssr_status = sci_in(port, SCxSR);
+	scr_status = sci_in(port, SCSCR);
 
 	/* Tx Interrupt */
 	if ((ssr_status & 0x0020) && (scr_status & SCI_CTRL_FLAGS_TIE))
@@ -820,7 +716,7 @@
 	return ret;
 }
 
-#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
 /*
  * Here we define a transistion notifier so that we can update all of our
  * ports' baud rate when the peripheral clock changes.
@@ -828,41 +724,20 @@
 static int sci_notifier(struct notifier_block *self,
 			unsigned long phase, void *p)
 {
-	struct cpufreq_freqs *freqs = p;
 	int i;
 
 	if ((phase == CPUFREQ_POSTCHANGE) ||
-	    (phase == CPUFREQ_RESUMECHANGE)){
+	    (phase == CPUFREQ_RESUMECHANGE))
 		for (i = 0; i < SCI_NPORTS; i++) {
-			struct uart_port *port = &sci_ports[i].port;
-			struct clk *clk;
-
-			/*
-			 * Update the uartclk per-port if frequency has
-			 * changed, since it will no longer necessarily be
-			 * consistent with the old frequency.
-			 *
-			 * Really we want to be able to do something like
-			 * uart_change_speed() or something along those lines
-			 * here to implicitly reset the per-port baud rate..
-			 *
-			 * Clean this up later..
-			 */
-			clk = clk_get(NULL, "module_clk");
-			port->uartclk = clk_get_rate(clk);
-			clk_put(clk);
+			struct sci_port *s = &sci_ports[i];
+			s->port.uartclk = clk_get_rate(s->clk);
 		}
 
-		printk(KERN_INFO "%s: got a postchange notification "
-		       "for cpu %d (old %d, new %d)\n",
-		       __func__, freqs->cpu, freqs->old, freqs->new);
-	}
-
 	return NOTIFY_OK;
 }
 
 static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 };
-#endif /* CONFIG_CPU_FREQ && CONFIG_HAVE_CLK */
+#endif
 
 static int sci_request_irq(struct sci_port *port)
 {
@@ -875,23 +750,22 @@
 			       "SCI Transmit Data Empty", "SCI Break" };
 
 	if (port->irqs[0] == port->irqs[1]) {
-		if (!port->irqs[0]) {
-			printk(KERN_ERR "sci: Cannot allocate irq.(IRQ=0)\n");
+		if (unlikely(!port->irqs[0]))
 			return -ENODEV;
-		}
 
 		if (request_irq(port->irqs[0], sci_mpxed_interrupt,
 				IRQF_DISABLED, "sci", port)) {
-			printk(KERN_ERR "sci: Cannot allocate irq.\n");
+			dev_err(port->port.dev, "Can't allocate IRQ\n");
 			return -ENODEV;
 		}
 	} else {
 		for (i = 0; i < ARRAY_SIZE(handlers); i++) {
-			if (!port->irqs[i])
+			if (unlikely(!port->irqs[i]))
 				continue;
+
 			if (request_irq(port->irqs[i], handlers[i],
 					IRQF_DISABLED, desc[i], port)) {
-				printk(KERN_ERR "sci: Cannot allocate irq.\n");
+				dev_err(port->port.dev, "Can't allocate IRQ\n");
 				return -ENODEV;
 			}
 		}
@@ -904,12 +778,9 @@
 {
 	int i;
 
-        if (port->irqs[0] == port->irqs[1]) {
-                if (!port->irqs[0])
-                        printk("sci: sci_free_irq error\n");
-		else
-                        free_irq(port->irqs[0], port);
-        } else {
+	if (port->irqs[0] == port->irqs[1])
+		free_irq(port->irqs[0], port);
+	else {
 		for (i = 0; i < ARRAY_SIZE(port->irqs); i++) {
 			if (!port->irqs[i])
 				continue;
@@ -1028,7 +899,6 @@
 static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
 			    struct ktermios *old)
 {
-	struct sci_port *s = &sci_ports[port->line];
 	unsigned int status, baud, smr_val;
 	int t = -1;
 
@@ -1060,32 +930,36 @@
 	sci_out(port, SCSMR, smr_val);
 
 	if (t > 0) {
-		if(t >= 256) {
+		if (t >= 256) {
 			sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
 			t >>= 2;
-		} else {
+		} else
 			sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3);
-		}
+
 		sci_out(port, SCBRR, t);
 		udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
 	}
 
-	if (likely(s->init_pins))
-		s->init_pins(port, termios->c_cflag);
+	sci_init_pins(port, termios->c_cflag);
+	sci_out(port, SCFCR, (termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0);
 
 	sci_out(port, SCSCR, SCSCR_INIT(port));
 
 	if ((termios->c_cflag & CREAD) != 0)
-              sci_start_rx(port,0);
+		sci_start_rx(port, 0);
 }
 
 static const char *sci_type(struct uart_port *port)
 {
 	switch (port->type) {
-		case PORT_SCI:	return "sci";
-		case PORT_SCIF:	return "scif";
-		case PORT_IRDA: return "irda";
-		case PORT_SCIFA:	return "scifa";
+	case PORT_IRDA:
+		return "irda";
+	case PORT_SCI:
+		return "sci";
+	case PORT_SCIF:
+		return "scif";
+	case PORT_SCIFA:
+		return "scifa";
 	}
 
 	return NULL;
@@ -1108,19 +982,6 @@
 
 	port->type = s->type;
 
-	switch (port->type) {
-	case PORT_SCI:
-		s->init_pins = sci_init_pins_sci;
-		break;
-	case PORT_SCIF:
-	case PORT_SCIFA:
-		s->init_pins = sci_init_pins_scif;
-		break;
-	case PORT_IRDA:
-		s->init_pins = sci_init_pins_irda;
-		break;
-	}
-
 	if (port->flags & UPF_IOREMAP && !port->membase) {
 #if defined(CONFIG_SUPERH64)
 		port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF");
@@ -1129,7 +990,7 @@
 		port->membase = ioremap_nocache(port->mapbase, 0x40);
 #endif
 
-		printk(KERN_ERR "sci: can't remap port#%d\n", port->line);
+		dev_err(port->dev, "can't remap port#%d\n", port->line);
 	}
 }
 
@@ -1163,6 +1024,10 @@
 	.request_port	= sci_request_port,
 	.config_port	= sci_config_port,
 	.verify_port	= sci_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_get_char	= sci_poll_get_char,
+	.poll_put_char	= sci_poll_put_char,
+#endif
 };
 
 static void __init sci_init_ports(void)
@@ -1229,7 +1094,15 @@
 static void serial_console_write(struct console *co, const char *s,
 				 unsigned count)
 {
-	put_string(serial_console_port, s, count);
+	struct uart_port *port = &serial_console_port->port;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (*s == 10)
+			sci_poll_put_char(port, '\r');
+
+		sci_poll_put_char(port, *s++);
+	}
 }
 
 static int __init serial_console_setup(struct console *co, char *options)
@@ -1307,89 +1180,8 @@
 console_initcall(sci_console_init);
 #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
 
-#ifdef CONFIG_SH_KGDB_CONSOLE
-/*
- * FIXME: Most of this can go away.. at the moment, we rely on
- * arch/sh/kernel/setup.c to do the command line parsing for kgdb, though
- * most of that can easily be done here instead.
- *
- * For the time being, just accept the values that were parsed earlier..
- */
-static void __init kgdb_console_get_options(struct uart_port *port, int *baud,
-					    int *parity, int *bits)
-{
-	*baud = kgdb_baud;
-	*parity = tolower(kgdb_parity);
-	*bits = kgdb_bits - '0';
-}
-
-/*
- * The naming here is somewhat misleading, since kgdb_console_setup() takes
- * care of the early-on initialization for kgdb, regardless of whether we
- * actually use kgdb as a console or not.
- *
- * On the plus side, this lets us kill off the old kgdb_sci_setup() nonsense.
- */
-int __init kgdb_console_setup(struct console *co, char *options)
-{
-	struct uart_port *port = &sci_ports[kgdb_portnum].port;
-	int baud = 38400;
-	int bits = 8;
-	int parity = 'n';
-	int flow = 'n';
-
-	if (co->index != kgdb_portnum)
-		co->index = kgdb_portnum;
-
-	kgdb_sci_port = &sci_ports[co->index];
-	port = &kgdb_sci_port->port;
-
-	/*
-	 * Also need to check port->type, we don't actually have any
-	 * UPIO_PORT ports, but uart_report_port() handily misreports
-	 * it anyways if we don't have a port available by the time this is
-	 * called.
-	 */
-	if (!port->type)
-		return -ENODEV;
-	if (!port->membase || !port->mapbase)
-		return -ENODEV;
-
-	if (options)
-		uart_parse_options(options, &baud, &parity, &bits, &flow);
-	else
-		kgdb_console_get_options(port, &baud, &parity, &bits);
-
-	kgdb_getchar = kgdb_sci_getchar;
-	kgdb_putchar = kgdb_sci_putchar;
-
-	return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct console kgdb_console = {
-	.name		= "ttySC",
-	.device		= uart_console_device,
-	.write		= kgdb_console_write,
-	.setup		= kgdb_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &sci_uart_driver,
-};
-
-/* Register the KGDB console so we get messages (d'oh!) */
-static int __init kgdb_console_init(void)
-{
-	sci_init_ports();
-	register_console(&kgdb_console);
-	return 0;
-}
-console_initcall(kgdb_console_init);
-#endif /* CONFIG_SH_KGDB_CONSOLE */
-
-#if defined(CONFIG_SH_KGDB_CONSOLE)
-#define SCI_CONSOLE	&kgdb_console
-#elif defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
-#define SCI_CONSOLE	&serial_console
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+#define SCI_CONSOLE	(&serial_console)
 #else
 #define SCI_CONSOLE	0
 #endif
@@ -1463,15 +1255,8 @@
 		uart_add_one_port(&sci_uart_driver, &sciport->port);
 	}
 
-#if defined(CONFIG_SH_KGDB) && !defined(CONFIG_SH_KGDB_CONSOLE)
-	kgdb_sci_port	= &sci_ports[kgdb_portnum];
-	kgdb_getchar	= kgdb_sci_getchar;
-	kgdb_putchar	= kgdb_sci_putchar;
-#endif
-
-#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
 	cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
-	dev_info(&dev->dev, "CPU frequency notifier registered\n");
 #endif
 
 #ifdef CONFIG_SH_STANDARD_BIOS
@@ -1491,6 +1276,10 @@
 {
 	int i;
 
+#ifdef CONFIG_HAVE_CLK
+	cpufreq_unregister_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+
 	for (i = 0; i < SCI_NPORTS; i++)
 		uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port);
 
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 9f33b06..38c600c 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -133,13 +133,20 @@
 # define SCSPTR5	0xffef0024	/* 16 bit SCIF */
 # define SCIF_OPER	0x0001		/* Overrun error bit */
 # define SCSCR_INIT(port)	0x3a	/* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \
+#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7203) || \
       defined(CONFIG_CPU_SUBTYPE_SH7206) || \
       defined(CONFIG_CPU_SUBTYPE_SH7263)
 # define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
 # define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
 # define SCSPTR2 0xfffe9020 /* 16 bit SCIF */
 # define SCSPTR3 0xfffe9820 /* 16 bit SCIF */
+# if defined(CONFIG_CPU_SUBTYPE_SH7201)
+#  define SCSPTR4 0xfffeA020 /* 16 bit SCIF */
+#  define SCSPTR5 0xfffeA820 /* 16 bit SCIF */
+#  define SCSPTR6 0xfffeB020 /* 16 bit SCIF */
+#  define SCSPTR7 0xfffeB820 /* 16 bit SCIF */
+# endif
 # define SCSCR_INIT(port)	0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
 #elif defined(CONFIG_CPU_SUBTYPE_SH7619)
 # define SCSPTR0 0xf8400020 /* 16 bit SCIF */
@@ -225,6 +232,10 @@
 # define SCIF_TXROOM_MAX 16
 #endif
 
+#ifndef SCIF_ORER
+#define SCIF_ORER	0x0000
+#endif
+
 #define SCxSR_TEND(port)	(((port)->type == PORT_SCI) ? SCI_TEND   : SCIF_TEND)
 #define SCxSR_ERRORS(port)	(((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
 #define SCxSR_RDxF(port)	(((port)->type == PORT_SCI) ? SCI_RDRF   : SCIF_RDF)
@@ -232,12 +243,7 @@
 #define SCxSR_FER(port)		(((port)->type == PORT_SCI) ? SCI_FER    : SCIF_FER)
 #define SCxSR_PER(port)		(((port)->type == PORT_SCI) ? SCI_PER    : SCIF_PER)
 #define SCxSR_BRK(port)		(((port)->type == PORT_SCI) ? 0x00       : SCIF_BRK)
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
-# define SCxSR_ORER(port)	(((port)->type == PORT_SCI) ? SCI_ORER : SCIF_ORER)
-#else
-# define SCxSR_ORER(port)	(((port)->type == PORT_SCI) ? SCI_ORER : 0x0000)
-#endif
+#define SCxSR_ORER(port)	(((port)->type == PORT_SCI) ? SCI_ORER	 : SCIF_ORER)
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
     defined(CONFIG_CPU_SUBTYPE_SH7720) || \
@@ -501,18 +507,6 @@
 {
 	  return sci_in(port,SCxSR)&0x0010 ? 1 : 0;
 }
-static inline void set_sh771x_scif_pfc(struct uart_port *port)
-{
-	if (port->mapbase == 0xA4400000){
-		ctrl_outw(ctrl_inw(PACR)&0xffc0,PACR);
-		ctrl_outw(ctrl_inw(PBCR)&0x0fff,PBCR);
-		return;
-	}
-	if (port->mapbase == 0xA4410000){
-		ctrl_outw(ctrl_inw(PBCR)&0xf003,PBCR);
-		return;
-	}
-}
 #elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
       defined(CONFIG_CPU_SUBTYPE_SH7721)
 static inline int sci_rxd_in(struct uart_port *port)
@@ -664,7 +658,8 @@
 		return ctrl_inw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */
 	return 1;
 }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \
+#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7203) || \
       defined(CONFIG_CPU_SUBTYPE_SH7206) || \
       defined(CONFIG_CPU_SUBTYPE_SH7263)
 static inline int sci_rxd_in(struct uart_port *port)
@@ -677,6 +672,16 @@
 		return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
 	if (port->mapbase == 0xfffe9800)
 		return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+#if defined(CONFIG_CPU_SUBTYPE_SH7201)
+	if (port->mapbase == 0xfffeA000)
+		return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xfffeA800)
+		return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xfffeB000)
+		return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xfffeB800)
+		return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+#endif
 	return 1;
 }
 #elif defined(CONFIG_CPU_SUBTYPE_SH7619)
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 0ffabf5..65a1ed9 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -226,7 +226,7 @@
 		err = drv->suspend(dev, state);
 		if (err) {
 			ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n",
-				   dev->dev->bus_id);
+				   dev_name(dev->dev));
 			goto err_unwind;
 		}
 	}
@@ -269,7 +269,7 @@
 		err = drv->resume(dev);
 		if (err) {
 			ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
-				   dev->dev->bus_id);
+				   dev_name(dev->dev));
 		}
 	}
 
@@ -454,8 +454,7 @@
 
 		dev->release = ssb_release_dev;
 		dev->bus = &ssb_bustype;
-		snprintf(dev->bus_id, sizeof(dev->bus_id),
-			 "ssb%u:%d", bus->busnumber, dev_idx);
+		dev_set_name(dev, "ssb%u:%d", bus->busnumber, dev_idx);
 
 		switch (bus->bustype) {
 		case SSB_BUSTYPE_PCI:
@@ -480,7 +479,7 @@
 		if (err) {
 			ssb_printk(KERN_ERR PFX
 				   "Could not register %s\n",
-				   dev->bus_id);
+				   dev_name(dev));
 			/* Set dev to NULL to not unregister
 			 * dev on error unwinding. */
 			sdev->dev = NULL;
@@ -796,7 +795,7 @@
 	err = ssb_bus_register(bus, ssb_pci_get_invariants, 0);
 	if (!err) {
 		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
-			   "PCI device %s\n", host_pci->dev.bus_id);
+			   "PCI device %s\n", dev_name(&host_pci->dev));
 	}
 
 	return err;
diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c
index e82db4a..26737a0 100644
--- a/drivers/ssb/pcihost_wrapper.c
+++ b/drivers/ssb/pcihost_wrapper.c
@@ -65,7 +65,7 @@
 	err = pci_enable_device(dev);
 	if (err)
 		goto err_kfree_ssb;
-	name = dev->dev.bus_id;
+	name = dev_name(&dev->dev);
 	if (dev->driver && dev->driver->name)
 		name = dev->driver->name;
 	err = pci_request_regions(dev, name);
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index 8fa9490..0039036 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -765,8 +765,7 @@
 #ifdef SLIC_USER_REQUEST_DUMP_ENABLED
 	case SIOCSLICDUMPCARD:
 		{
-			struct adapter *adapter = (struct adapter *)
-							dev->priv;
+			struct adapter *adapter = netdev_priv(dev);
 			struct sliccard *card;
 
 			ASSERT(adapter);
@@ -1685,7 +1684,7 @@
 	struct sliccard *card;
 
 	ASSERT(dev);
-	adapter = (struct adapter *)((struct net_device *) dev)->priv;
+	adapter = netdev_priv((struct net_device *)dev);
 	ASSERT(adapter);
 	card = adapter->card;
 	ASSERT(card);
@@ -3136,7 +3135,7 @@
 	struct slic_shmem *pshmem;
 
 	ASSERT(dev);
-	adapter = (struct adapter *)((struct net_device *)dev)->priv;
+	adapter = netdev_priv((struct net_device *)dev);
 	ASSERT(adapter);
 	card = adapter->card;
 	ASSERT(card);
diff --git a/drivers/staging/winbond/linux/wbusb.c b/drivers/staging/winbond/linux/wbusb.c
index f4a7875..39ca9b9 100644
--- a/drivers/staging/winbond/linux/wbusb.c
+++ b/drivers/staging/winbond/linux/wbusb.c
@@ -336,7 +336,11 @@
 
 int wb35_open(struct net_device *netdev)
 {
-	PADAPTER Adapter = (PADAPTER)netdev->priv;
+	/* netdev_priv() or netdev->ml_priv should reference to the address of
+	 * private data(PADAPTER). It depends on whether private data memory is
+	 * allocated when alloc_netdev().
+	 */
+	PADAPTER Adapter = (PADAPTER)netdev_priv(netdev);
 	phw_data_t pHwData = &Adapter->sHwData;
 
         netif_start_queue(netdev);
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 11f84a8..2b705ea 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -244,7 +244,7 @@
 static struct net_device_stats*
 p80211knetdev_get_stats(netdevice_t *netdev)
 {
-	wlandevice_t	*wlandev = (wlandevice_t*)netdev->priv;
+	wlandevice_t	*wlandev = netdev->ml_priv;
 	DBFENTER;
 
 	/* TODO: review the MIB stats for items that correspond to
@@ -272,7 +272,7 @@
 static int p80211knetdev_open( netdevice_t *netdev )
 {
 	int 		result = 0; /* success */
-	wlandevice_t	*wlandev = (wlandevice_t*)(netdev->priv);
+	wlandevice_t	*wlandev = netdev->ml_priv;
 
 	DBFENTER;
 
@@ -315,7 +315,7 @@
 static int p80211knetdev_stop( netdevice_t *netdev )
 {
 	int		result = 0;
-	wlandevice_t	*wlandev = (wlandevice_t*)(netdev->priv);
+	wlandevice_t	*wlandev = netdev->ml_priv;
 
 	DBFENTER;
 
@@ -460,7 +460,7 @@
 {
 	int		result = 0;
 	int		txresult = -1;
-	wlandevice_t	*wlandev = (wlandevice_t*)netdev->priv;
+	wlandevice_t	*wlandev = netdev->ml_priv;
 	p80211_hdr_t    p80211_hdr;
 	p80211_metawep_t p80211_wep;
 
@@ -603,7 +603,7 @@
 ----------------------------------------------------------------*/
 static void p80211knetdev_set_multicast_list(netdevice_t *dev)
 {
-	wlandevice_t	*wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t	*wlandev = dev->ml_priv;
 
 	DBFENTER;
 
@@ -696,7 +696,7 @@
 {
 	int			result = 0;
 	p80211ioctl_req_t	*req = (p80211ioctl_req_t*)ifr;
-	wlandevice_t		*wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t		*wlandev = dev->ml_priv;
 	UINT8			*msgbuf;
 	DBFENTER;
 
@@ -812,7 +812,7 @@
 	dot11req.msgcode = DIDmsg_dot11req_mibset;
 	dot11req.msglen = sizeof(p80211msg_dot11req_mibset_t);
 	memcpy(dot11req.devname,
-		((wlandevice_t*)(dev->priv))->name,
+		((wlandevice_t *)dev->ml_priv)->name,
 		WLAN_DEVNAMELEN_MAX - 1);
 
 	/* Set up the mibattribute argument */
@@ -833,7 +833,7 @@
 	resultcode->data = 0;
 
 	/* now fire the request */
-	result = p80211req_dorequest(dev->priv, (UINT8*)&dot11req);
+	result = p80211req_dorequest(dev->ml_priv, (UINT8 *)&dot11req);
 
 	/* If the request wasn't successful, report an error and don't
 	 * change the netdev address
@@ -917,7 +917,7 @@
 		memset( dev, 0, sizeof(netdevice_t));
 		ether_setup(dev);
 		wlandev->netdev = dev;
-		dev->priv = wlandev;
+		dev->ml_priv = wlandev;
 		dev->hard_start_xmit =	p80211knetdev_hard_start_xmit;
 		dev->get_stats =	p80211knetdev_get_stats;
 #ifdef HAVE_PRIVATE_IOCTL
@@ -1487,7 +1487,7 @@
 
 static void p80211knetdev_tx_timeout( netdevice_t *netdev)
 {
-	wlandevice_t	*wlandev = (wlandevice_t*)netdev->priv;
+	wlandevice_t	*wlandev = netdev->ml_priv;
 	DBFENTER;
 
 	if (wlandev->tx_timeout) {
diff --git a/drivers/staging/wlan-ng/p80211wext.c b/drivers/staging/wlan-ng/p80211wext.c
index 906ba43..b2c9ea2 100644
--- a/drivers/staging/wlan-ng/p80211wext.c
+++ b/drivers/staging/wlan-ng/p80211wext.c
@@ -218,7 +218,7 @@
 struct iw_statistics* p80211wext_get_wireless_stats (netdevice_t *dev)
 {
 	p80211msg_lnxreq_commsquality_t  quality;
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	struct iw_statistics* wstats = &wlandev->wstats;
 	int retval;
 
@@ -301,7 +301,7 @@
 			      struct iw_request_info *info,
 			      struct iw_freq *freq, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211item_uint32_t             mibitem;
 	p80211msg_dot11req_mibset_t     msg;
 	int result;
@@ -339,7 +339,7 @@
 			      struct iw_request_info *info,
 			      struct iw_freq *freq, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211item_uint32_t             mibitem;
 	p80211msg_dot11req_mibset_t     msg;
 	int result;
@@ -380,7 +380,7 @@
 			      struct iw_request_info *info,
 			      __u32 *mode, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 
 	DBFENTER;
 
@@ -407,7 +407,7 @@
 			      struct iw_request_info *info,
 			      __u32 *mode, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211item_uint32_t             mibitem;
 	p80211msg_dot11req_mibset_t     msg;
 	int 	result;
@@ -550,7 +550,7 @@
 			    struct sockaddr *ap_addr, char *extra)
 {
 
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 
 	DBFENTER;
 
@@ -566,7 +566,7 @@
 				struct iw_request_info *info,
 				struct iw_point *erq, char *key)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	int err = 0;
 	int i;
 
@@ -607,7 +607,7 @@
 				struct iw_request_info *info,
 				struct iw_point *erq, char *key)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211msg_dot11req_mibset_t	msg;
 	p80211item_pstr32_t		pstr;
 
@@ -736,7 +736,7 @@
 			       struct iw_request_info *info,
 			       struct iw_point *data, char *essid)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 
 	DBFENTER;
 
@@ -762,7 +762,7 @@
 			       struct iw_request_info *info,
 			       struct iw_point *data, char *essid)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211msg_lnxreq_autojoin_t     msg;
 
 	int result;
@@ -816,7 +816,7 @@
 				struct iw_request_info *info,
 				struct iw_point *data, char *essid)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	int err = 0;
 
 	DBFENTER;
@@ -839,7 +839,7 @@
 			      struct iw_request_info *info,
 			      struct iw_param *rrq, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211item_uint32_t             mibitem;
 	p80211msg_dot11req_mibset_t     msg;
 	int result;
@@ -893,7 +893,7 @@
 			     struct iw_request_info *info,
 			     struct iw_param *rts, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211item_uint32_t             mibitem;
 	p80211msg_dot11req_mibset_t     msg;
 	int result;
@@ -927,7 +927,7 @@
 			     struct iw_request_info *info,
 			     struct iw_param *rts, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211item_uint32_t             mibitem;
 	p80211msg_dot11req_mibset_t     msg;
 	int result;
@@ -964,7 +964,7 @@
 			      struct iw_request_info *info,
 			      struct iw_param *frag, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211item_uint32_t             mibitem;
 	p80211msg_dot11req_mibset_t     msg;
 	int result;
@@ -997,7 +997,7 @@
 			      struct iw_request_info *info,
 			      struct iw_param *frag, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211item_uint32_t             mibitem;
 	p80211msg_dot11req_mibset_t     msg;
 	int result;
@@ -1047,7 +1047,7 @@
 			       struct iw_request_info *info,
 			       struct iw_param *rrq, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211item_uint32_t             mibitem;
 	p80211msg_dot11req_mibset_t     msg;
 	int result;
@@ -1126,7 +1126,7 @@
 			       struct iw_request_info *info,
 			       struct iw_param *rrq, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211item_uint32_t             mibitem;
 	p80211msg_dot11req_mibset_t     msg;
 	int result;
@@ -1198,7 +1198,7 @@
                                struct iw_request_info *info,
                                struct iw_param *rrq, char *extra)
 {
-        wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
         p80211item_uint32_t             mibitem;
         p80211msg_dot11req_mibset_t     msg;
         int result;
@@ -1243,7 +1243,7 @@
 			       struct iw_request_info *info,
 			       struct iw_param *rrq, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211item_uint32_t             mibitem;
 	p80211msg_dot11req_mibset_t     msg;
 	int result;
@@ -1281,7 +1281,7 @@
 			     struct iw_request_info *info,
 			     struct iw_point *srq, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
         struct sockaddr address[IW_MAX_SPY];
         int number = srq->length;
         int i;
@@ -1317,7 +1317,7 @@
 			     struct iw_request_info *info,
 			     struct iw_point *srq, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 
         struct sockaddr address[IW_MAX_SPY];
         struct iw_quality spy_stat[IW_MAX_SPY];
@@ -1378,7 +1378,7 @@
 			     struct iw_request_info *info,
 			     struct iw_point *srq, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211msg_dot11req_scan_t	msg;
 	int result;
 	int err = 0;
@@ -1501,7 +1501,7 @@
 			     struct iw_request_info *info,
 			     struct iw_point *srq, char *extra)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	p80211msg_dot11req_scan_results_t	msg;
 	int result = 0;
 	int err = 0;
@@ -1551,7 +1551,7 @@
 				struct iw_request_info *info,
 				union iwreq_data *wrqu, char *extra)
 {
-  wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+  wlandevice_t *wlandev = dev->ml_priv;
   struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 	p80211msg_dot11req_mibset_t	msg;
 	p80211item_pstr32_t		*pstr;
@@ -1627,7 +1627,7 @@
 				union iwreq_data *wrqu, char *extra)
 
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 
 	struct iw_point *encoding = &wrqu->encoding;
@@ -1682,7 +1682,7 @@
 				   struct iw_request_info *info,
 				   union iwreq_data *wrqu, char *extra)
 {
-  wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+  wlandevice_t *wlandev = dev->ml_priv;
   struct iw_param *param = &wrqu->param;
   int result =0;
 
@@ -1734,7 +1734,7 @@
 				   struct iw_request_info *info,
 				   union iwreq_data *wrqu, char *extra)
 {
-  wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+  wlandevice_t *wlandev = dev->ml_priv;
   struct iw_param *param = &wrqu->param;
   int result =0;
 
@@ -1868,7 +1868,7 @@
 /* wireless extensions' ioctls */
 int p80211wext_support_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd)
 {
-	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
+	wlandevice_t *wlandev = dev->ml_priv;
 
 #if WIRELESS_EXT < 13
 	struct iwreq *iwr = (struct iwreq*)ifr;
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 9aea43a..5ed4ae0 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -286,9 +286,7 @@
 	struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
 	struct atm_dev *atm_dev = usbatm_instance->atm_dev;
 
-	return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
-			atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2],
-			atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]);
+	return snprintf(buf, PAGE_SIZE, "%pM\n", atm_dev->esi);
 }
 
 static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 06dd114..fbea856 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -770,10 +770,7 @@
 		return sprintf(page, "%s\n", instance->description);
 
 	if (!left--)
-		return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
-			       atm_dev->esi[0], atm_dev->esi[1],
-			       atm_dev->esi[2], atm_dev->esi[3],
-			       atm_dev->esi[4], atm_dev->esi[5]);
+		return sprintf(page, "MAC: %pM\n", atm_dev->esi);
 
 	if (!left--)
 		return sprintf(page,
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 2bccefe..aa79280 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -574,6 +574,7 @@
 {
 	struct usb_device *dev = NULL;
 	struct dev_state *ps;
+	const struct cred *cred = current_cred();
 	int ret;
 
 	lock_kernel();
@@ -617,8 +618,8 @@
 	init_waitqueue_head(&ps->wait);
 	ps->discsignr = 0;
 	ps->disc_pid = get_pid(task_pid(current));
-	ps->disc_uid = current->uid;
-	ps->disc_euid = current->euid;
+	ps->disc_uid = cred->uid;
+	ps->disc_euid = cred->euid;
 	ps->disccontext = NULL;
 	ps->ifclaimed = 0;
 	security_task_getsecid(current, &ps->secid);
@@ -967,6 +968,7 @@
 	struct usb_host_endpoint *ep;
 	struct async *as;
 	struct usb_ctrlrequest *dr = NULL;
+	const struct cred *cred = current_cred();
 	unsigned int u, totlen, isofrmlen;
 	int ret, ifnum = -1;
 	int is_in;
@@ -1174,8 +1176,8 @@
 	as->signr = uurb->signr;
 	as->ifnum = ifnum;
 	as->pid = get_pid(task_pid(current));
-	as->uid = current->uid;
-	as->euid = current->euid;
+	as->uid = cred->uid;
+	as->euid = cred->euid;
 	security_task_getsecid(current, &as->secid);
 	if (!is_in) {
 		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 9463226..185be76 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -277,8 +277,8 @@
 
 	if (inode) {
 		inode->i_mode = mode;
-		inode->i_uid = current->fsuid;
-		inode->i_gid = current->fsgid;
+		inode->i_uid = current_fsuid();
+		inode->i_gid = current_fsgid();
 		inode->i_blocks = 0;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 		switch (mode & S_IFMT) {
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
new file mode 100644
index 0000000..d8fc9b3
--- /dev/null
+++ b/drivers/usb/gadget/f_phonet.c
@@ -0,0 +1,621 @@
+/*
+ * f_phonet.c -- USB CDC Phonet function
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation. All rights reserved.
+ *
+ * Author: Rémi Denis-Courmont
+ *
+ * This program is free software; you can 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/kernel.h>
+#include <linux/device.h>
+
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_phonet.h>
+#include <linux/if_arp.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/composite.h>
+
+#include "u_phonet.h"
+
+#define PN_MEDIA_USB	0x1B
+
+/*-------------------------------------------------------------------------*/
+
+struct phonet_port {
+	struct f_phonet			*usb;
+	spinlock_t			lock;
+};
+
+struct f_phonet {
+	struct usb_function		function;
+	struct net_device		*dev;
+	struct usb_ep			*in_ep, *out_ep;
+
+	struct usb_request		*in_req;
+	struct usb_request		*out_reqv[0];
+};
+
+static int phonet_rxq_size = 2;
+
+static inline struct f_phonet *func_to_pn(struct usb_function *f)
+{
+	return container_of(f, struct f_phonet, function);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define USB_CDC_SUBCLASS_PHONET	0xfe
+#define USB_CDC_PHONET_TYPE	0xab
+
+static struct usb_interface_descriptor
+pn_control_intf_desc = {
+	.bLength =		sizeof pn_control_intf_desc,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	/* .bInterfaceNumber =	DYNAMIC, */
+	.bInterfaceClass =	USB_CLASS_COMM,
+	.bInterfaceSubClass =	USB_CDC_SUBCLASS_PHONET,
+};
+
+static const struct usb_cdc_header_desc
+pn_header_desc = {
+	.bLength =		sizeof pn_header_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
+	.bcdCDC =		__constant_cpu_to_le16(0x0110),
+};
+
+static const struct usb_cdc_header_desc
+pn_phonet_desc = {
+	.bLength =		sizeof pn_phonet_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_PHONET_TYPE,
+	.bcdCDC =		__constant_cpu_to_le16(0x1505), /* ??? */
+};
+
+static struct usb_cdc_union_desc
+pn_union_desc = {
+	.bLength =		sizeof pn_union_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
+
+	/* .bMasterInterface0 =	DYNAMIC, */
+	/* .bSlaveInterface0 =	DYNAMIC, */
+};
+
+static struct usb_interface_descriptor
+pn_data_nop_intf_desc = {
+	.bLength =		sizeof pn_data_nop_intf_desc,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	/* .bInterfaceNumber =	DYNAMIC, */
+	.bAlternateSetting =	0,
+	.bNumEndpoints =	0,
+	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+};
+
+static struct usb_interface_descriptor
+pn_data_intf_desc = {
+	.bLength =		sizeof pn_data_intf_desc,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	/* .bInterfaceNumber =	DYNAMIC, */
+	.bAlternateSetting =	1,
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+};
+
+static struct usb_endpoint_descriptor
+pn_fs_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor
+pn_hs_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor
+pn_fs_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor
+pn_hs_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *fs_pn_function[] = {
+	(struct usb_descriptor_header *) &pn_control_intf_desc,
+	(struct usb_descriptor_header *) &pn_header_desc,
+	(struct usb_descriptor_header *) &pn_phonet_desc,
+	(struct usb_descriptor_header *) &pn_union_desc,
+	(struct usb_descriptor_header *) &pn_data_nop_intf_desc,
+	(struct usb_descriptor_header *) &pn_data_intf_desc,
+	(struct usb_descriptor_header *) &pn_fs_sink_desc,
+	(struct usb_descriptor_header *) &pn_fs_source_desc,
+	NULL,
+};
+
+static struct usb_descriptor_header *hs_pn_function[] = {
+	(struct usb_descriptor_header *) &pn_control_intf_desc,
+	(struct usb_descriptor_header *) &pn_header_desc,
+	(struct usb_descriptor_header *) &pn_phonet_desc,
+	(struct usb_descriptor_header *) &pn_union_desc,
+	(struct usb_descriptor_header *) &pn_data_nop_intf_desc,
+	(struct usb_descriptor_header *) &pn_data_intf_desc,
+	(struct usb_descriptor_header *) &pn_hs_sink_desc,
+	(struct usb_descriptor_header *) &pn_hs_source_desc,
+	NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int pn_net_open(struct net_device *dev)
+{
+	if (netif_carrier_ok(dev))
+		netif_wake_queue(dev);
+	return 0;
+}
+
+static int pn_net_close(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return 0;
+}
+
+static void pn_tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_phonet *fp = ep->driver_data;
+	struct net_device *dev = fp->dev;
+	struct sk_buff *skb = req->context;
+
+	switch (req->status) {
+	case 0:
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += skb->len;
+		break;
+
+	case -ESHUTDOWN: /* disconnected */
+	case -ECONNRESET: /* disabled */
+		dev->stats.tx_aborted_errors++;
+	default:
+		dev->stats.tx_errors++;
+	}
+
+	dev_kfree_skb_any(skb);
+	if (netif_carrier_ok(dev))
+		netif_wake_queue(dev);
+}
+
+static int pn_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct phonet_port *port = netdev_priv(dev);
+	struct f_phonet *fp;
+	struct usb_request *req;
+	unsigned long flags;
+
+	if (skb->protocol != htons(ETH_P_PHONET))
+		goto out;
+
+	spin_lock_irqsave(&port->lock, flags);
+	fp = port->usb;
+	if (unlikely(!fp)) /* race with carrier loss */
+		goto out_unlock;
+
+	req = fp->in_req;
+	req->buf = skb->data;
+	req->length = skb->len;
+	req->complete = pn_tx_complete;
+	req->zero = 1;
+	req->context = skb;
+
+	if (unlikely(usb_ep_queue(fp->in_ep, req, GFP_ATOMIC)))
+		goto out_unlock;
+
+	netif_stop_queue(dev);
+	skb = NULL;
+
+out_unlock:
+	spin_unlock_irqrestore(&port->lock, flags);
+out:
+	if (unlikely(skb)) {
+		dev_kfree_skb_any(skb);
+		dev->stats.tx_dropped++;
+	}
+	return 0;
+}
+
+static int pn_net_mtu(struct net_device *dev, int new_mtu)
+{
+	struct phonet_port *port = netdev_priv(dev);
+	unsigned long flags;
+	int err = -EBUSY;
+
+	if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU))
+		return -EINVAL;
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (!netif_carrier_ok(dev)) {
+		dev->mtu = new_mtu;
+		err = 0;
+	}
+	spin_unlock_irqrestore(&port->lock, flags);
+	return err;
+}
+
+static void pn_net_setup(struct net_device *dev)
+{
+	dev->features		= 0;
+	dev->type		= ARPHRD_PHONET;
+	dev->flags		= IFF_POINTOPOINT | IFF_NOARP;
+	dev->mtu		= PHONET_DEV_MTU;
+	dev->hard_header_len	= 1;
+	dev->dev_addr[0]	= PN_MEDIA_USB;
+	dev->addr_len		= 1;
+	dev->tx_queue_len	= 1;
+
+	dev->destructor		= free_netdev;
+	dev->header_ops		= &phonet_header_ops;
+	dev->open		= pn_net_open;
+	dev->stop		= pn_net_close;
+	dev->hard_start_xmit	= pn_net_xmit; /* mandatory */
+	dev->change_mtu		= pn_net_mtu;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Queue buffer for data from the host
+ */
+static int
+pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags)
+{
+	struct sk_buff *skb;
+	const size_t size = fp->dev->mtu;
+	int err;
+
+	skb = alloc_skb(size, gfp_flags);
+	if (!skb)
+		return -ENOMEM;
+
+	req->buf = skb->data;
+	req->length = size;
+	req->context = skb;
+
+	err = usb_ep_queue(fp->out_ep, req, gfp_flags);
+	if (unlikely(err))
+		dev_kfree_skb_any(skb);
+	return err;
+}
+
+static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_phonet *fp = ep->driver_data;
+	struct net_device *dev = fp->dev;
+	struct sk_buff *skb = req->context;
+	int status = req->status;
+
+	switch (status) {
+	case 0:
+		if (unlikely(!netif_running(dev)))
+			break;
+		if (unlikely(req->actual < 1))
+			break;
+		skb_put(skb, req->actual);
+		skb->protocol = htons(ETH_P_PHONET);
+		skb_reset_mac_header(skb);
+		__skb_pull(skb, 1);
+		skb->dev = dev;
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += skb->len;
+
+		netif_rx(skb);
+		skb = NULL;
+		break;
+
+	/* Do not resubmit in these cases: */
+	case -ESHUTDOWN: /* disconnect */
+	case -ECONNABORTED: /* hw reset */
+	case -ECONNRESET: /* dequeued (unlink or netif down) */
+		req = NULL;
+		break;
+
+	/* Do resubmit in these cases: */
+	case -EOVERFLOW: /* request buffer overflow */
+		dev->stats.rx_over_errors++;
+	default:
+		dev->stats.rx_errors++;
+		break;
+	}
+
+	if (skb)
+		dev_kfree_skb_any(skb);
+	if (req)
+		pn_rx_submit(fp, req, GFP_ATOMIC);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void __pn_reset(struct usb_function *f)
+{
+	struct f_phonet *fp = func_to_pn(f);
+	struct net_device *dev = fp->dev;
+	struct phonet_port *port = netdev_priv(dev);
+
+	netif_carrier_off(dev);
+	netif_stop_queue(dev);
+	port->usb = NULL;
+
+	usb_ep_disable(fp->out_ep);
+	usb_ep_disable(fp->in_ep);
+}
+
+static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_phonet *fp = func_to_pn(f);
+	struct usb_gadget *gadget = fp->function.config->cdev->gadget;
+
+	if (intf == pn_control_intf_desc.bInterfaceNumber)
+		/* control interface, no altsetting */
+		return (alt > 0) ? -EINVAL : 0;
+
+	if (intf == pn_data_intf_desc.bInterfaceNumber) {
+		struct net_device *dev = fp->dev;
+		struct phonet_port *port = netdev_priv(dev);
+
+		/* data intf (0: inactive, 1: active) */
+		if (alt > 1)
+			return -EINVAL;
+
+		spin_lock(&port->lock);
+		__pn_reset(f);
+		if (alt == 1) {
+			struct usb_endpoint_descriptor *out, *in;
+			int i;
+
+			out = ep_choose(gadget,
+					&pn_hs_sink_desc,
+					&pn_fs_sink_desc);
+			in = ep_choose(gadget,
+					&pn_hs_source_desc,
+					&pn_fs_source_desc);
+			usb_ep_enable(fp->out_ep, out);
+			usb_ep_enable(fp->in_ep, in);
+
+			port->usb = fp;
+			fp->out_ep->driver_data = fp;
+			fp->in_ep->driver_data = fp;
+
+			netif_carrier_on(dev);
+			if (netif_running(dev))
+				netif_wake_queue(dev);
+			for (i = 0; i < phonet_rxq_size; i++)
+				pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC);
+		}
+		spin_unlock(&port->lock);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int pn_get_alt(struct usb_function *f, unsigned intf)
+{
+	struct f_phonet *fp = func_to_pn(f);
+
+	if (intf == pn_control_intf_desc.bInterfaceNumber)
+		return 0;
+
+	if (intf == pn_data_intf_desc.bInterfaceNumber) {
+		struct phonet_port *port = netdev_priv(fp->dev);
+		u8 alt;
+
+		spin_lock(&port->lock);
+		alt = port->usb != NULL;
+		spin_unlock(&port->lock);
+		return alt;
+	}
+
+	return -EINVAL;
+}
+
+static void pn_disconnect(struct usb_function *f)
+{
+	struct f_phonet *fp = func_to_pn(f);
+	struct phonet_port *port = netdev_priv(fp->dev);
+	unsigned long flags;
+
+	/* remain disabled until set_alt */
+	spin_lock_irqsave(&port->lock, flags);
+	__pn_reset(f);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static __init
+int pn_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = c->cdev;
+	struct usb_gadget *gadget = cdev->gadget;
+	struct f_phonet *fp = func_to_pn(f);
+	struct usb_ep *ep;
+	int status, i;
+
+	/* Reserve interface IDs */
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto err;
+	pn_control_intf_desc.bInterfaceNumber = status;
+	pn_union_desc.bMasterInterface0 = status;
+
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto err;
+	pn_data_nop_intf_desc.bInterfaceNumber = status;
+	pn_data_intf_desc.bInterfaceNumber = status;
+	pn_union_desc.bSlaveInterface0 = status;
+
+	/* Reserve endpoints */
+	status = -ENODEV;
+	ep = usb_ep_autoconfig(gadget, &pn_fs_sink_desc);
+	if (!ep)
+		goto err;
+	fp->out_ep = ep;
+	ep->driver_data = fp; /* Claim */
+
+	ep = usb_ep_autoconfig(gadget, &pn_fs_source_desc);
+	if (!ep)
+		goto err;
+	fp->in_ep = ep;
+	ep->driver_data = fp; /* Claim */
+
+	pn_hs_sink_desc.bEndpointAddress =
+		pn_fs_sink_desc.bEndpointAddress;
+	pn_hs_source_desc.bEndpointAddress =
+		pn_fs_source_desc.bEndpointAddress;
+
+	/* Do not try to bind Phonet twice... */
+	fp->function.descriptors = fs_pn_function;
+	fp->function.hs_descriptors = hs_pn_function;
+
+	/* Incoming USB requests */
+	status = -ENOMEM;
+	for (i = 0; i < phonet_rxq_size; i++) {
+		struct usb_request *req;
+
+		req = usb_ep_alloc_request(fp->out_ep, GFP_KERNEL);
+		if (!req)
+			goto err;
+
+		req->complete = pn_rx_complete;
+		fp->out_reqv[i] = req;
+	}
+
+	/* Outgoing USB requests */
+	fp->in_req = usb_ep_alloc_request(fp->in_ep, GFP_KERNEL);
+	if (!fp->in_req)
+		goto err;
+
+	INFO(cdev, "USB CDC Phonet function\n");
+	INFO(cdev, "using %s, OUT %s, IN %s\n", cdev->gadget->name,
+		fp->out_ep->name, fp->in_ep->name);
+	return 0;
+
+err:
+	if (fp->out_ep)
+		fp->out_ep->driver_data = NULL;
+	if (fp->in_ep)
+		fp->in_ep->driver_data = NULL;
+	ERROR(cdev, "USB CDC Phonet: cannot autoconfigure\n");
+	return status;
+}
+
+static void
+pn_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_phonet *fp = func_to_pn(f);
+	int i;
+
+	/* We are already disconnected */
+	if (fp->in_req)
+		usb_ep_free_request(fp->in_ep, fp->in_req);
+	for (i = 0; i < phonet_rxq_size; i++)
+		if (fp->out_reqv[i])
+			usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
+
+	kfree(fp);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct net_device *dev;
+
+int __init phonet_bind_config(struct usb_configuration *c)
+{
+	struct f_phonet *fp;
+	int err;
+
+	fp = kzalloc(sizeof(*fp), GFP_KERNEL);
+	if (!fp)
+		return -ENOMEM;
+
+	fp->dev = dev;
+	fp->function.name = "phonet";
+	fp->function.bind = pn_bind;
+	fp->function.unbind = pn_unbind;
+	fp->function.set_alt = pn_set_alt;
+	fp->function.get_alt = pn_get_alt;
+	fp->function.disable = pn_disconnect;
+
+	err = usb_add_function(c, &fp->function);
+	if (err)
+		kfree(fp);
+	return err;
+}
+
+int __init gphonet_setup(struct usb_gadget *gadget)
+{
+	struct phonet_port *port;
+	int err;
+
+	/* Create net device */
+	BUG_ON(dev);
+	dev = alloc_netdev(sizeof(*port)
+		+ (phonet_rxq_size * sizeof(struct usb_request *)),
+				"upnlink%d", pn_net_setup);
+	if (!dev)
+		return -ENOMEM;
+
+	port = netdev_priv(dev);
+	spin_lock_init(&port->lock);
+	netif_carrier_off(dev);
+	netif_stop_queue(dev);
+	SET_NETDEV_DEV(dev, &gadget->dev);
+
+	err = register_netdev(dev);
+	if (err)
+		free_netdev(dev);
+	return err;
+}
+
+void gphonet_cleanup(void)
+{
+	unregister_netdev(dev);
+}
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 77b44fb..3a8879e 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -623,7 +623,6 @@
 #if defined(CONFIG_SUPERH_BUILT_IN_M66592)
 static void init_controller(struct m66592 *m66592)
 {
-	usbf_start_clock();
 	m66592_bset(m66592, M66592_HSE, M66592_SYSCFG);		/* High spd */
 	m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
 	m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
@@ -671,9 +670,7 @@
 
 static void disable_controller(struct m66592 *m66592)
 {
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
-	usbf_stop_clock();
-#else
+#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
 	m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
 	udelay(1);
 	m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
@@ -686,9 +683,7 @@
 
 static void m66592_start_xclock(struct m66592 *m66592)
 {
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
-	usbf_start_clock();
-#else
+#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
 	u16 tmp;
 
 	tmp = m66592_read(m66592, M66592_SYSCFG);
@@ -1539,7 +1534,10 @@
 	iounmap(m66592->reg);
 	free_irq(platform_get_irq(pdev, 0), m66592);
 	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
-	usbf_stop_clock();
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+	clk_disable(m66592->clk);
+	clk_put(m66592->clk);
+#endif
 	kfree(m66592);
 	return 0;
 }
@@ -1556,6 +1554,9 @@
 	int irq;
 	void __iomem *reg = NULL;
 	struct m66592 *m66592 = NULL;
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+	char clk_name[8];
+#endif
 	int ret = 0;
 	int i;
 
@@ -1614,6 +1615,16 @@
 		goto clean_up;
 	}
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+	snprintf(clk_name, sizeof(clk_name), "usbf%d", pdev->id);
+	m66592->clk = clk_get(&pdev->dev, clk_name);
+	if (IS_ERR(m66592->clk)) {
+		dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+		ret = PTR_ERR(m66592->clk);
+		goto clean_up2;
+	}
+	clk_enable(m66592->clk);
+#endif
 	INIT_LIST_HEAD(&m66592->gadget.ep_list);
 	m66592->gadget.ep0 = &m66592->ep[0].ep;
 	INIT_LIST_HEAD(&m66592->gadget.ep0->ep_list);
@@ -1645,7 +1656,7 @@
 
 	m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
 	if (m66592->ep0_req == NULL)
-		goto clean_up2;
+		goto clean_up3;
 	m66592->ep0_req->complete = nop_completion;
 
 	init_controller(m66592);
@@ -1653,7 +1664,12 @@
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 	return 0;
 
+clean_up3:
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+	clk_disable(m66592->clk);
+	clk_put(m66592->clk);
 clean_up2:
+#endif
 	free_irq(irq, m66592);
 clean_up:
 	if (m66592) {
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index f118f00..286ce07 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -23,6 +23,10 @@
 #ifndef __M66592_UDC_H__
 #define __M66592_UDC_H__
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+#include <linux/clk.h>
+#endif
+
 #define M66592_SYSCFG		0x00
 #define M66592_XTAL		0xC000	/* b15-14: Crystal selection */
 #define   M66592_XTAL48		 0x8000		/* 48MHz */
@@ -476,6 +480,9 @@
 struct m66592 {
 	spinlock_t		lock;
 	void __iomem		*reg;
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+	struct clk *clk;
+#endif
 
 	struct usb_gadget		gadget;
 	struct usb_gadget_driver	*driver;
@@ -604,26 +611,6 @@
 #define m66592_bset(m66592, val, offset)	\
 			m66592_mdfy(m66592, val, 0, offset)
 
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
-#include <asm/io.h>
-#define MSTPCR2		0xA4150038	/* for SH7722 */
-#define MSTPCR2_USB	0x00000800
-
-static inline void usbf_start_clock(void)
-{
-	ctrl_outl(ctrl_inl(MSTPCR2) & ~MSTPCR2_USB, MSTPCR2);
-}
-
-static inline void usbf_stop_clock(void)
-{
-	ctrl_outl(ctrl_inl(MSTPCR2) | MSTPCR2_USB, MSTPCR2);
-}
-
-#else
-#define usbf_start_clock(x)
-#define usbf_stop_clock(x)
-#endif	/* if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
-
 #endif	/* ifndef __M66592_UDC_H__ */
 
 
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 66948b7..d9739d5 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -146,7 +146,7 @@
 
 /* NETWORK DRIVER HOOKUP (to the layer above this driver) */
 
-static int eth_change_mtu(struct net_device *net, int new_mtu)
+static int ueth_change_mtu(struct net_device *net, int new_mtu)
 {
 	struct eth_dev	*dev = netdev_priv(net);
 	unsigned long	flags;
@@ -764,7 +764,7 @@
 	if (ethaddr)
 		memcpy(ethaddr, dev->host_mac, ETH_ALEN);
 
-	net->change_mtu = eth_change_mtu;
+	net->change_mtu = ueth_change_mtu;
 	net->hard_start_xmit = eth_start_xmit;
 	net->open = eth_open;
 	net->stop = eth_stop;
@@ -787,10 +787,8 @@
 		dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
 		free_netdev(net);
 	} else {
-		DECLARE_MAC_BUF(tmp);
-
-		INFO(dev, "MAC %s\n", print_mac(tmp, net->dev_addr));
-		INFO(dev, "HOST MAC %s\n", print_mac(tmp, dev->host_mac));
+		INFO(dev, "MAC %pM\n", net->dev_addr);
+		INFO(dev, "HOST MAC %pM\n", dev->host_mac);
 
 		the_dev = dev;
 	}
diff --git a/drivers/usb/gadget/u_phonet.h b/drivers/usb/gadget/u_phonet.h
new file mode 100644
index 0000000..09a7525
--- /dev/null
+++ b/drivers/usb/gadget/u_phonet.h
@@ -0,0 +1,21 @@
+/*
+ * u_phonet.h - interface to Phonet
+ *
+ * Copyright (C) 2007-2008 by Nokia Corporation
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * either version 2 of that License or (at your option) any later version.
+ */
+
+#ifndef __U_PHONET_H
+#define __U_PHONET_H
+
+#include <linux/usb/composite.h>
+#include <linux/usb/cdc.h>
+
+int gphonet_setup(struct usb_gadget *gadget);
+int phonet_bind_config(struct usb_configuration *c);
+void gphonet_cleanup(void);
+
+#endif /* __U_PHONET_H */
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 2376f24..c21f14e 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -114,6 +114,9 @@
 	int i = 0;
 
 #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+#if defined(CONFIG_HAVE_CLK)
+	clk_enable(r8a66597->clk);
+#endif
 	do {
 		r8a66597_write(r8a66597, SCKE, SYSCFG0);
 		tmp = r8a66597_read(r8a66597, SYSCFG0);
@@ -154,7 +157,11 @@
 {
 	r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
 	udelay(1);
-#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+#if defined(CONFIG_HAVE_CLK)
+	clk_disable(r8a66597->clk);
+#endif
+#else
 	r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
 	r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
 	r8a66597_bclr(r8a66597, USBE, SYSCFG0);
@@ -2261,6 +2268,9 @@
 	del_timer_sync(&r8a66597->rh_timer);
 	usb_remove_hcd(hcd);
 	iounmap((void *)r8a66597->reg);
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+	clk_put(r8a66597->clk);
+#endif
 	usb_put_hcd(hcd);
 	return 0;
 }
@@ -2268,6 +2278,9 @@
 #define resource_len(r) (((r)->end - (r)->start) + 1)
 static int __init r8a66597_probe(struct platform_device *pdev)
 {
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+	char clk_name[8];
+#endif
 	struct resource *res = NULL, *ires;
 	int irq = -1;
 	void __iomem *reg = NULL;
@@ -2320,6 +2333,16 @@
 	memset(r8a66597, 0, sizeof(struct r8a66597));
 	dev_set_drvdata(&pdev->dev, r8a66597);
 
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+	snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
+	r8a66597->clk = clk_get(&pdev->dev, clk_name);
+	if (IS_ERR(r8a66597->clk)) {
+		dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+		ret = PTR_ERR(r8a66597->clk);
+		goto clean_up2;
+	}
+#endif
+
 	spin_lock_init(&r8a66597->lock);
 	init_timer(&r8a66597->rh_timer);
 	r8a66597->rh_timer.function = r8a66597_timer;
@@ -2365,11 +2388,18 @@
 	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "Failed to add hcd\n");
-		goto clean_up;
+		goto clean_up3;
 	}
 
 	return 0;
 
+clean_up3:
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+	clk_put(r8a66597->clk);
+clean_up2:
+#endif
+	usb_put_hcd(hcd);
+
 clean_up:
 	if (reg)
 		iounmap(reg);
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index 84ee014..ecacde4 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -26,6 +26,10 @@
 #ifndef __R8A66597_H__
 #define __R8A66597_H__
 
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+#include <linux/clk.h>
+#endif
+
 #define SYSCFG0		0x00
 #define SYSCFG1		0x02
 #define SYSSTS0		0x04
@@ -481,7 +485,9 @@
 struct r8a66597 {
 	spinlock_t lock;
 	unsigned long reg;
-
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+	struct clk *clk;
+#endif
 	struct r8a66597_device		device0;
 	struct r8a66597_root_hub	root_hub[R8A66597_MAX_ROOT_HUB];
 	struct list_head		pipe_queue[R8A66597_MAX_NUM_PIPE];
diff --git a/drivers/uwb/wlp/eda.c b/drivers/uwb/wlp/eda.c
index cdfe8df..10985fa 100644
--- a/drivers/uwb/wlp/eda.c
+++ b/drivers/uwb/wlp/eda.c
@@ -313,12 +313,9 @@
 	list_for_each_entry(itr, &eda->cache, list_node) {
 		if (!memcmp(itr->virt_addr, virt_addr,
 			   sizeof(itr->virt_addr))) {
-			d_printf(6, dev, "EDA: looking for "
-			       "%02x:%02x:%02x:%02x:%02x:%02x hit %02x:%02x "
+			d_printf(6, dev, "EDA: looking for %pM hit %02x:%02x "
 			       "wss %p tag 0x%02x state %u\n",
-			       virt_addr[0], virt_addr[1],
-			       virt_addr[2], virt_addr[3],
-			       virt_addr[4], virt_addr[5],
+			       virt_addr,
 			       itr->dev_addr.data[1],
 			       itr->dev_addr.data[0], itr->wss,
 			       itr->tag, itr->state);
@@ -327,24 +324,13 @@
 			found = 1;
 			break;
 		} else
-			d_printf(6, dev, "EDA: looking for "
-			       "%02x:%02x:%02x:%02x:%02x:%02x "
-			       "against "
-			       "%02x:%02x:%02x:%02x:%02x:%02x miss\n",
-			       virt_addr[0], virt_addr[1],
-			       virt_addr[2], virt_addr[3],
-			       virt_addr[4], virt_addr[5],
-			       itr->virt_addr[0], itr->virt_addr[1],
-			       itr->virt_addr[2], itr->virt_addr[3],
-			       itr->virt_addr[4], itr->virt_addr[5]);
+			d_printf(6, dev, "EDA: looking for %pM against %pM miss\n",
+			         virt_addr, itr->virt_addr);
 	}
 	if (!found) {
 		if (printk_ratelimit())
-			dev_err(dev, "EDA: Eth addr %02x:%02x:%02x"
-				":%02x:%02x:%02x not found.\n",
-				virt_addr[0], virt_addr[1],
-				virt_addr[2], virt_addr[3],
-				virt_addr[4], virt_addr[5]);
+			dev_err(dev, "EDA: Eth addr %pM not found.\n",
+				virt_addr);
 		result = -ENODEV;
 	}
 	spin_unlock_irqrestore(&eda->lock, flags);
@@ -380,19 +366,13 @@
 			   "tag state virt_addr\n");
 	list_for_each_entry(entry, &eda->cache, list_node) {
 		result += scnprintf(buf + result, PAGE_SIZE - result,
-				    "%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x "
-				    "%p 0x%02x %s "
-				    "%02x:%02x:%02x:%02x:%02x:%02x\n",
-				    entry->eth_addr[0], entry->eth_addr[1],
-				    entry->eth_addr[2], entry->eth_addr[3],
-				    entry->eth_addr[4], entry->eth_addr[5],
+				    "%pM %02x:%02x %p 0x%02x %s %pM\n",
+				    entry->eth_addr,
 				    entry->dev_addr.data[1],
 				    entry->dev_addr.data[0], entry->wss,
 				    entry->tag,
 				    wlp_wss_connect_state_str(entry->state),
-				    entry->virt_addr[0], entry->virt_addr[1],
-				    entry->virt_addr[2], entry->virt_addr[3],
-				    entry->virt_addr[4], entry->virt_addr[5]);
+				    entry->virt_addr);
 		if (result >= PAGE_SIZE)
 			break;
 	}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3f3ce13..d0c8219 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1889,10 +1889,11 @@
 config FB_SH_MOBILE_LCDC
 	tristate "SuperH Mobile LCDC framebuffer support"
 	depends on FB && SUPERH
-	select FB_CFB_FILLRECT
-	select FB_CFB_COPYAREA
-	select FB_CFB_IMAGEBLIT
-	default m
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	select FB_SYS_FOPS
+	select FB_DEFERRED_IO
 	---help---
 	  Frame buffer driver for the on-chip SH-Mobile LCD controller.
 
@@ -2021,17 +2022,19 @@
 	depends on FB && MIPS_COBALT
 
 config FB_SH7760
-       bool "SH7760/SH7763 LCDC support"
-       depends on FB && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763)
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
-       help
-         Support for the SH7760/SH7763 integrated (D)STN/TFT LCD Controller.
-         Supports display resolutions up to 1024x1024 pixel, grayscale and
-         color operation, with depths ranging from 1 bpp to 8 bpp monochrome
-         and 8, 15 or 16 bpp color; 90 degrees clockwise display rotation for
-         panels <= 320 pixel horizontal resolution.
+	bool "SH7760/SH7763/SH7720/SH7721 LCDC support"
+	depends on FB && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763 \
+		|| CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	---help---
+	  Support for the SH7760/SH7763/SH7720/SH7721 integrated
+	  (D)STN/TFT LCD Controller.
+	  Supports display resolutions up to 1024x1024 pixel, grayscale and
+	  color operation, with depths ranging from 1 bpp to 8 bpp monochrome
+	  and 8, 15 or 16 bpp color; 90 degrees clockwise display rotation for
+	  panels <= 320 pixel horizontal resolution.
 
 config FB_VIRTUAL
 	tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 0b2adef..4bcff81 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -81,9 +81,6 @@
 #ifdef CONFIG_ATARI
 #include <asm/atariints.h>
 #endif
-#ifdef CONFIG_MAC
-#include <asm/macints.h>
-#endif
 #if defined(__mc68000__)
 #include <asm/machdep.h>
 #include <asm/setup.h>
@@ -160,8 +157,6 @@
 
 /* # VBL ints between cursor state changes */
 #define ATARI_CURSOR_BLINK_RATE		(42)
-#define MAC_CURSOR_BLINK_RATE		(32)
-#define DEFAULT_CURSOR_BLINK_RATE	(20)
 
 static int vbl_cursor_cnt;
 static int fbcon_cursor_noblink;
@@ -210,19 +205,6 @@
 static void fbcon_exit(void);
 static struct device *fbcon_device;
 
-#ifdef CONFIG_MAC
-/*
- * On the Macintoy, there may or may not be a working VBL int. We need to probe
- */
-static int vbl_detected;
-
-static irqreturn_t fb_vbl_detect(int irq, void *dummy)
-{
-	vbl_detected++;
-	return IRQ_HANDLED;
-}
-#endif
-
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
 static inline void fbcon_set_rotation(struct fb_info *info)
 {
@@ -421,7 +403,7 @@
 	release_console_sem();
 }
 
-#if defined(CONFIG_ATARI) || defined(CONFIG_MAC)
+#ifdef CONFIG_ATARI
 static int cursor_blink_rate;
 static irqreturn_t fb_vbl_handler(int irq, void *dev_id)
 {
@@ -949,9 +931,7 @@
 	struct fb_info *info = NULL;
 	struct fbcon_ops *ops;
 	int rows, cols;
-	int irqres;
 
-	irqres = 1;
 	/*
 	 *  If num_registered_fb is zero, this is a call for the dummy part.
 	 *  The frame buffer devices weren't initialized yet.
@@ -1040,56 +1020,11 @@
 #ifdef CONFIG_ATARI
 	if (MACH_IS_ATARI) {
 		cursor_blink_rate = ATARI_CURSOR_BLINK_RATE;
-		irqres =
-		    request_irq(IRQ_AUTO_4, fb_vbl_handler,
+		(void)request_irq(IRQ_AUTO_4, fb_vbl_handler,
 				IRQ_TYPE_PRIO, "framebuffer vbl",
 				info);
 	}
-#endif				/* CONFIG_ATARI */
-
-#ifdef CONFIG_MAC
-	/*
-	 * On a Macintoy, the VBL interrupt may or may not be active. 
-	 * As interrupt based cursor is more reliable and race free, we 
-	 * probe for VBL interrupts.
-	 */
-	if (MACH_IS_MAC) {
-		int ct = 0;
-		/*
-		 * Probe for VBL: set temp. handler ...
-		 */
-		irqres = request_irq(IRQ_MAC_VBL, fb_vbl_detect, 0,
-				     "framebuffer vbl", info);
-		vbl_detected = 0;
-
-		/*
-		 * ... and spin for 20 ms ...
-		 */
-		while (!vbl_detected && ++ct < 1000)
-			udelay(20);
-
-		if (ct == 1000)
-			printk
-			    ("fbcon_startup: No VBL detected, using timer based cursor.\n");
-
-		free_irq(IRQ_MAC_VBL, fb_vbl_detect);
-
-		if (vbl_detected) {
-			/*
-			 * interrupt based cursor ok
-			 */
-			cursor_blink_rate = MAC_CURSOR_BLINK_RATE;
-			irqres =
-			    request_irq(IRQ_MAC_VBL, fb_vbl_handler, 0,
-					"framebuffer vbl", info);
-		} else {
-			/*
-			 * VBL not detected: fall through, use timer based cursor
-			 */
-			irqres = 1;
-		}
-	}
-#endif				/* CONFIG_MAC */
+#endif /* CONFIG_ATARI */
 
 	fbcon_add_cursor_timer(info);
 	fbcon_has_exited = 0;
@@ -3520,11 +3455,8 @@
 		return;
 
 #ifdef CONFIG_ATARI
-	free_irq(IRQ_AUTO_4, fb_vbl_handler);
-#endif
-#ifdef CONFIG_MAC
-	if (MACH_IS_MAC && vbl_detected)
-		free_irq(IRQ_MAC_VBL, fb_vbl_handler);
+	if (MACH_IS_ATARI)
+		free_irq(IRQ_AUTO_4, fb_vbl_handler);
 #endif
 
 	kfree((void *)softback_buf);
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index b0be7ea..49fcbe8 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -298,10 +298,10 @@
                        return -EINVAL;
                start = info->fix.mmio_start;
                len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.mmio_len);
-               pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
+	       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        } else {
                /* framebuffer */
-               pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU;
+	       vma->vm_page_prot = pgprot_cached_wthru(vma->vm_page_prot);
        }
        start &= PAGE_MASK;
        if ((vma->vm_end - vma->vm_start + off) > len)
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index 4835bdc..0820265 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -24,6 +24,19 @@
 #include <linux/rmap.h>
 #include <linux/pagemap.h>
 
+struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs)
+{
+	void *screen_base = (void __force *) info->screen_base;
+	struct page *page;
+
+	if (is_vmalloc_addr(screen_base + offs))
+		page = vmalloc_to_page(screen_base + offs);
+	else
+		page = pfn_to_page((info->fix.smem_start + offs) >> PAGE_SHIFT);
+
+	return page;
+}
+
 /* this is to find and return the vmalloc-ed fb pages */
 static int fb_deferred_io_fault(struct vm_area_struct *vma,
 				struct vm_fault *vmf)
@@ -31,14 +44,12 @@
 	unsigned long offset;
 	struct page *page;
 	struct fb_info *info = vma->vm_private_data;
-	/* info->screen_base is virtual memory */
-	void *screen_base = (void __force *) info->screen_base;
 
 	offset = vmf->pgoff << PAGE_SHIFT;
 	if (offset >= info->fix.smem_len)
 		return VM_FAULT_SIGBUS;
 
-	page = vmalloc_to_page(screen_base + offset);
+	page = fb_deferred_io_page(info, offset);
 	if (!page)
 		return VM_FAULT_SIGBUS;
 
@@ -60,6 +71,10 @@
 {
 	struct fb_info *info = file->private_data;
 
+	/* Skip if deferred io is complied-in but disabled on this fbdev */
+	if (!info->fbdefio)
+		return 0;
+
 	/* Kill off the delayed work */
 	cancel_rearming_delayed_work(&info->deferred_work);
 
@@ -184,7 +199,6 @@
 
 void fb_deferred_io_cleanup(struct fb_info *info)
 {
-	void *screen_base = (void __force *) info->screen_base;
 	struct fb_deferred_io *fbdefio = info->fbdefio;
 	struct page *page;
 	int i;
@@ -195,9 +209,12 @@
 
 	/* clear out the mapping that we setup */
 	for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) {
-		page = vmalloc_to_page(screen_base + i);
+		page = fb_deferred_io_page(info, i);
 		page->mapping = NULL;
 	}
+
+	info->fbops->fb_mmap = NULL;
+	mutex_destroy(&fbdefio->lock);
 }
 EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);
 
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index ee380d5..d66887e 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -36,7 +36,6 @@
 #include <asm/irq.h>
 #include <asm/macintosh.h>
 #include <asm/io.h>
-#include <asm/machw.h>
 
 /* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */
 #define DAC_BASE 0x50f24000
@@ -78,34 +77,34 @@
 			   unsigned int green, unsigned int blue,
 			   struct fb_info *fb_info);
 
-static volatile struct {
+static struct {
 	unsigned char addr;
 	/* Note: word-aligned */
 	char pad[3];
 	unsigned char lut;
-} *valkyrie_cmap_regs;
+} __iomem *valkyrie_cmap_regs;
 
-static volatile struct {
+static struct {
 	unsigned char addr;
 	unsigned char lut;
-} *v8_brazil_cmap_regs;
+} __iomem *v8_brazil_cmap_regs;
 
-static volatile struct {
+static struct {
 	unsigned char addr;
 	char pad1[3]; /* word aligned */
 	unsigned char lut;
 	char pad2[3]; /* word aligned */
 	unsigned char cntl; /* a guess as to purpose */
-} *rbv_cmap_regs;
+} __iomem *rbv_cmap_regs;
 
-static volatile struct {
+static struct {
 	unsigned long reset;
 	unsigned long pad1[3];
 	unsigned char pad2[3];
 	unsigned char lut;
-} *dafb_cmap_regs;
+} __iomem *dafb_cmap_regs;
 
-static volatile struct {
+static struct {
 	unsigned char addr;	/* OFFSET: 0x00 */
 	unsigned char pad1[15];
 	unsigned char lut;	/* OFFSET: 0x10 */
@@ -114,16 +113,16 @@
 	unsigned char pad3[7];
 	unsigned long vbl_addr;	/* OFFSET: 0x28 */
 	unsigned int  status2;	/* OFFSET: 0x2C */
-} *civic_cmap_regs;
+} __iomem *civic_cmap_regs;
 
-static volatile struct {
+static struct {
 	char    pad1[0x40];
         unsigned char	clut_waddr;	/* 0x40 */
         char    pad2;
         unsigned char	clut_data;	/* 0x42 */
         char	pad3[0x3];
         unsigned char	clut_raddr;	/* 0x46 */
-} *csc_cmap_regs;
+} __iomem *csc_cmap_regs;
 
 /* We will leave these the way they are for the time being */
 struct mdc_cmap_regs {
@@ -507,10 +506,10 @@
 			   struct fb_info *info)
 {
 	mdelay(1);
-	csc_cmap_regs->clut_waddr = regno;
-	csc_cmap_regs->clut_data = red;
-	csc_cmap_regs->clut_data = green;
-	csc_cmap_regs->clut_data = blue;
+	nubus_writeb(regno, &csc_cmap_regs->clut_waddr);
+	nubus_writeb(red,   &csc_cmap_regs->clut_data);
+	nubus_writeb(green, &csc_cmap_regs->clut_data);
+	nubus_writeb(blue,  &csc_cmap_regs->clut_data);
 	return 0;
 }
 
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 4b5d807..38ac805 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -460,12 +460,16 @@
 		line_length |= (u64)src_line_length << 32;
 
 	src_offset += GPU_FB_START;
+
+	mutex_lock(&ps3_gpu_mutex);
 	status = lv1_gpu_context_attribute(ps3fb.context_handle,
 					   L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
 					   dst_offset, GPU_IOIF + src_offset,
 					   L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
 					   (width << 16) | height,
 					   line_length);
+	mutex_unlock(&ps3_gpu_mutex);
+
 	if (status)
 		dev_err(dev,
 			"%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
@@ -784,15 +788,6 @@
 	return 0;
 }
 
-static void ps3fb_flip_ctl(int on, void *data)
-{
-	struct ps3fb_priv *priv = data;
-	if (on)
-		atomic_dec_if_positive(&priv->ext_flip);
-	else
-		atomic_inc(&priv->ext_flip);
-}
-
 
     /*
      * ioctl
@@ -1228,7 +1223,6 @@
 	}
 
 	ps3fb.task = task;
-	ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb);
 
 	return 0;
 
@@ -1258,10 +1252,9 @@
 
 	dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
 
-	ps3fb_flip_ctl(0, &ps3fb);	/* flip off */
+	atomic_inc(&ps3fb.ext_flip);	/* flip off */
 	ps3fb.dinfo->irq.mask = 0;
 
-	ps3av_register_flip_ctl(NULL, NULL);
 	if (ps3fb.task) {
 		struct task_struct *task = ps3fb.task;
 		ps3fb.task = NULL;
@@ -1296,8 +1289,8 @@
 }
 
 static struct ps3_system_bus_driver ps3fb_driver = {
-	.match_id	= PS3_MATCH_ID_GRAPHICS,
-	.match_sub_id	= PS3_MATCH_SUB_ID_FB,
+	.match_id	= PS3_MATCH_ID_GPU,
+	.match_sub_id	= PS3_MATCH_SUB_ID_GPU_FB,
 	.core.name	= DEVICE_NAME,
 	.core.owner	= THIS_MODULE,
 	.probe		= ps3fb_probe,
@@ -1355,4 +1348,4 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver");
 MODULE_AUTHOR("Sony Computer Entertainment Inc.");
-MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS);
+MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_FB);
diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c
index 8d0212d..653bdfe 100644
--- a/drivers/video/sh7760fb.c
+++ b/drivers/video/sh7760fb.c
@@ -13,6 +13,8 @@
  *
  * Thanks to Siegfried Schaefer <s.schaefer at schaefer-edv.de>
  *     for his original source and testing!
+ *
+ * sh7760_setcolreg get from drivers/video/sh_mobile_lcdcfb.c
  */
 
 #include <linux/completion.h>
@@ -53,29 +55,6 @@
 	return IRQ_HANDLED;
 }
 
-static void sh7760fb_wait_vsync(struct fb_info *info)
-{
-	struct sh7760fb_par *par = info->par;
-
-	if (par->pd->novsync)
-		return;
-
-	iowrite16(ioread16(par->base + LDINTR) & ~VINT_CHECK,
-		  par->base + LDINTR);
-
-	if (par->irq < 0) {
-		/* poll for vert. retrace: status bit is sticky */
-		while (!(ioread16(par->base + LDINTR) & VINT_CHECK))
-			cpu_relax();
-	} else {
-		/* a "wait_for_irq_event(par->irq)" would be extremely nice */
-		init_completion(&par->vsync);
-		enable_irq(par->irq);
-		wait_for_completion(&par->vsync);
-		disable_irq_nosync(par->irq);
-	}
-}
-
 /* wait_for_lps - wait until power supply has reached a certain state. */
 static int wait_for_lps(struct sh7760fb_par *par, int val)
 {
@@ -117,55 +96,28 @@
 	return wait_for_lps(par, lps);
 }
 
-/* set color registers */
-static int sh7760fb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+static int sh7760_setcolreg (u_int regno,
+	u_int red, u_int green, u_int blue,
+	u_int transp, struct fb_info *info)
 {
-	struct sh7760fb_par *par = info->par;
-	u32 s = cmap->start;
-	u32 l = cmap->len;
-	u16 *r = cmap->red;
-	u16 *g = cmap->green;
-	u16 *b = cmap->blue;
-	u32 col, tmo;
-	int ret;
+	u32 *palette = info->pseudo_palette;
 
-	ret = 0;
+	if (regno >= 16)
+		return -EINVAL;
 
-	sh7760fb_wait_vsync(info);
+	/* only FB_VISUAL_TRUECOLOR supported */
 
-	/* request palette access */
-	iowrite16(LDPALCR_PALEN, par->base + LDPALCR);
+	red >>= 16 - info->var.red.length;
+	green >>= 16 - info->var.green.length;
+	blue >>= 16 - info->var.blue.length;
+	transp >>= 16 - info->var.transp.length;
 
-	/* poll for access grant */
-	tmo = 100;
-	while (!(ioread16(par->base + LDPALCR) & LDPALCR_PALS) && (--tmo))
-		cpu_relax();
+	palette[regno] = (red << info->var.red.offset) |
+		(green << info->var.green.offset) |
+		(blue << info->var.blue.offset) |
+		(transp << info->var.transp.offset);
 
-	if (!tmo) {
-		ret = 1;
-		dev_dbg(info->dev, "no palette access!\n");
-		goto out;
-	}
-
-	while (l && (s < 256)) {
-		col = ((*r) & 0xff) << 16;
-		col |= ((*g) & 0xff) << 8;
-		col |= ((*b) & 0xff);
-		col &= SH7760FB_PALETTE_MASK;
-		iowrite32(col, par->base + LDPR(s));
-
-		if (s < 16)
-			((u32 *) (info->pseudo_palette))[s] = s;
-
-		s++;
-		l--;
-		r++;
-		g++;
-		b++;
-	}
-out:
-	iowrite16(0, par->base + LDPALCR);
-	return ret;
+	return 0;
 }
 
 static void encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info,
@@ -406,7 +358,7 @@
 	.owner = THIS_MODULE,
 	.fb_blank = sh7760fb_blank,
 	.fb_check_var = sh7760fb_check_var,
-	.fb_setcmap = sh7760fb_setcmap,
+	.fb_setcolreg = sh7760_setcolreg,
 	.fb_set_par = sh7760fb_set_par,
 	.fb_fillrect = cfb_fillrect,
 	.fb_copyarea = cfb_copyarea,
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index efff672..0e2b8fd 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -16,7 +16,9 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
 #include <video/sh_mobile_lcdc.h>
+#include <asm/atomic.h>
 
 #define PALETTE_NR 16
 
@@ -30,11 +32,15 @@
 	u32 pseudo_palette[PALETTE_NR];
 	struct fb_info info;
 	dma_addr_t dma_handle;
+	struct fb_deferred_io defio;
 };
 
 struct sh_mobile_lcdc_priv {
 	void __iomem *base;
+	int irq;
 #ifdef CONFIG_HAVE_CLK
+	atomic_t clk_usecnt;
+	struct clk *dot_clk;
 	struct clk *clk;
 #endif
 	unsigned long lddckr;
@@ -56,7 +62,7 @@
 
 /* per-channel registers */
 enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R,
-       LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR };
+       LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR };
 
 static unsigned long lcdc_offs_mainlcd[] = {
 	[LDDCKPAT1R] = 0x400,
@@ -66,6 +72,7 @@
 	[LDMT3R] = 0x420,
 	[LDDFR] = 0x424,
 	[LDSM1R] = 0x428,
+	[LDSM2R] = 0x42c,
 	[LDSA1R] = 0x430,
 	[LDMLSR] = 0x438,
 	[LDHCNR] = 0x448,
@@ -83,6 +90,7 @@
 	[LDMT3R] = 0x608,
 	[LDDFR] = 0x60c,
 	[LDSM1R] = 0x610,
+	[LDSM2R] = 0x614,
 	[LDSA1R] = 0x618,
 	[LDMLSR] = 0x620,
 	[LDHCNR] = 0x624,
@@ -96,6 +104,8 @@
 #define LCDC_RESET	0x00000100
 #define DISPLAY_BEU	0x00000008
 #define LCDC_ENABLE	0x00000001
+#define LDINTR_FE	0x00000400
+#define LDINTR_FS	0x00000004
 
 static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,
 			    int reg_nr, unsigned long data)
@@ -170,6 +180,65 @@
 	lcdc_sys_read_data,
 };
 
+#ifdef CONFIG_HAVE_CLK
+static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
+{
+	if (atomic_inc_and_test(&priv->clk_usecnt)) {
+		clk_enable(priv->clk);
+		if (priv->dot_clk)
+			clk_enable(priv->dot_clk);
+	}
+}
+
+static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
+{
+	if (atomic_sub_return(1, &priv->clk_usecnt) == -1) {
+		if (priv->dot_clk)
+			clk_disable(priv->dot_clk);
+		clk_disable(priv->clk);
+	}
+}
+#else
+static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {}
+static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {}
+#endif
+
+static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
+				       struct list_head *pagelist)
+{
+	struct sh_mobile_lcdc_chan *ch = info->par;
+
+	/* enable clocks before accessing hardware */
+	sh_mobile_lcdc_clk_on(ch->lcdc);
+
+	/* trigger panel update */
+	lcdc_write_chan(ch, LDSM2R, 1);
+}
+
+static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
+{
+	struct fb_deferred_io *fbdefio = info->fbdefio;
+
+	if (fbdefio)
+		schedule_delayed_work(&info->deferred_work, fbdefio->delay);
+}
+
+static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
+{
+	struct sh_mobile_lcdc_priv *priv = data;
+	unsigned long tmp;
+
+	/* acknowledge interrupt */
+	tmp = lcdc_read(priv, _LDINTR);
+	tmp &= 0xffffff00; /* mask in high 24 bits */
+	tmp |= 0x000000ff ^ LDINTR_FS; /* status in low 8 */
+	lcdc_write(priv, _LDINTR, tmp);
+
+	/* disable clocks */
+	sh_mobile_lcdc_clk_off(priv);
+	return IRQ_HANDLED;
+}
+
 static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
 				      int start)
 {
@@ -207,6 +276,11 @@
 	int k, m;
 	int ret = 0;
 
+	/* enable clocks before accessing the hardware */
+	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
+		if (priv->ch[k].enabled)
+			sh_mobile_lcdc_clk_on(priv);
+
 	/* reset */
 	lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET);
 	lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0);
@@ -249,7 +323,7 @@
 	lcdc_write(priv, _LDDCKSTPR, 0);
 	lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0);
 
-	/* interrupts are disabled */
+	/* interrupts are disabled to begin with */
 	lcdc_write(priv, _LDINTR, 0);
 
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
@@ -310,9 +384,6 @@
 			return ret;
 	}
 
-	/* --- display_lcdc_data() --- */
-	lcdc_write(priv, _LDINTR, 0x00000f00);
-
 	/* word and long word swap */
 	lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
 
@@ -334,8 +405,24 @@
 		/* set line size */
 		lcdc_write_chan(ch, LDMLSR, ch->info.fix.line_length);
 
-		/* continuous read mode */
-		lcdc_write_chan(ch, LDSM1R, 0);
+		/* setup deferred io if SYS bus */
+		tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
+		if (ch->ldmt1r_value & (1 << 12) && tmp) {
+			ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
+			ch->defio.delay = msecs_to_jiffies(tmp);
+			ch->info.fbdefio = &ch->defio;
+			fb_deferred_io_init(&ch->info);
+
+			/* one-shot mode */
+			lcdc_write_chan(ch, LDSM1R, 1);
+
+			/* enable "Frame End Interrupt Enable" bit */
+			lcdc_write(priv, _LDINTR, LDINTR_FE);
+
+		} else {
+			/* continuous read mode */
+			lcdc_write_chan(ch, LDSM1R, 0);
+		}
 	}
 
 	/* display output */
@@ -359,6 +446,7 @@
 {
 	struct sh_mobile_lcdc_chan *ch;
 	struct sh_mobile_lcdc_board_cfg	*board_cfg;
+	unsigned long tmp;
 	int k;
 
 	/* tell the board code to disable the panel */
@@ -367,10 +455,22 @@
 		board_cfg = &ch->cfg.board_cfg;
 		if (board_cfg->display_off)
 			board_cfg->display_off(board_cfg->board_data);
+
+		/* cleanup deferred io if SYS bus */
+		tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
+		if (ch->ldmt1r_value & (1 << 12) && tmp) {
+			fb_deferred_io_cleanup(&ch->info);
+			ch->info.fbdefio = NULL;
+		}
 	}
 
 	/* stop the lcdc */
 	sh_mobile_lcdc_start_stop(priv, 0);
+
+	/* stop clocks */
+	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
+		if (priv->ch[k].enabled)
+			sh_mobile_lcdc_clk_off(priv);
 }
 
 static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
@@ -413,9 +513,13 @@
 	return -EINVAL;
 }
 
-static int sh_mobile_lcdc_setup_clocks(struct device *dev, int clock_source,
+static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
+				       int clock_source,
 				       struct sh_mobile_lcdc_priv *priv)
 {
+#ifdef CONFIG_HAVE_CLK
+	char clk_name[8];
+#endif
 	char *str;
 	int icksel;
 
@@ -430,14 +534,21 @@
 	priv->lddckr = icksel << 16;
 
 #ifdef CONFIG_HAVE_CLK
+	atomic_set(&priv->clk_usecnt, -1);
+	snprintf(clk_name, sizeof(clk_name), "lcdc%d", pdev->id);
+	priv->clk = clk_get(&pdev->dev, clk_name);
+	if (IS_ERR(priv->clk)) {
+		dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+		return PTR_ERR(priv->clk);
+	}
+	
 	if (str) {
-		priv->clk = clk_get(dev, str);
-		if (IS_ERR(priv->clk)) {
-			dev_err(dev, "cannot get clock %s\n", str);
-			return PTR_ERR(priv->clk);
+		priv->dot_clk = clk_get(&pdev->dev, str);
+		if (IS_ERR(priv->dot_clk)) {
+			dev_err(&pdev->dev, "cannot get dot clock %s\n", str);
+			clk_put(priv->clk);
+			return PTR_ERR(priv->dot_clk);
 		}
-
-		clk_enable(priv->clk);
 	}
 #endif
 
@@ -475,11 +586,34 @@
 	.accel =	FB_ACCEL_NONE,
 };
 
+static void sh_mobile_lcdc_fillrect(struct fb_info *info,
+				    const struct fb_fillrect *rect)
+{
+	sys_fillrect(info, rect);
+	sh_mobile_lcdc_deferred_io_touch(info);
+}
+
+static void sh_mobile_lcdc_copyarea(struct fb_info *info,
+				    const struct fb_copyarea *area)
+{
+	sys_copyarea(info, area);
+	sh_mobile_lcdc_deferred_io_touch(info);
+}
+
+static void sh_mobile_lcdc_imageblit(struct fb_info *info,
+				     const struct fb_image *image)
+{
+	sys_imageblit(info, image);
+	sh_mobile_lcdc_deferred_io_touch(info);
+}
+
 static struct fb_ops sh_mobile_lcdc_ops = {
 	.fb_setcolreg	= sh_mobile_lcdc_setcolreg,
-	.fb_fillrect	= cfb_fillrect,
-	.fb_copyarea	= cfb_copyarea,
-	.fb_imageblit	= cfb_imageblit,
+	.fb_read        = fb_sys_read,
+	.fb_write       = fb_sys_write,
+	.fb_fillrect	= sh_mobile_lcdc_fillrect,
+	.fb_copyarea	= sh_mobile_lcdc_copyarea,
+	.fb_imageblit	= sh_mobile_lcdc_imageblit,
 };
 
 static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp)
@@ -540,8 +674,9 @@
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
-		dev_err(&pdev->dev, "cannot find IO resource\n");
+	i = platform_get_irq(pdev, 0);
+	if (!res || i < 0) {
+		dev_err(&pdev->dev, "cannot get platform resources\n");
 		error = -ENOENT;
 		goto err0;
 	}
@@ -553,6 +688,14 @@
 		goto err0;
 	}
 
+	error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED,
+			    pdev->dev.bus_id, priv);
+	if (error) {
+		dev_err(&pdev->dev, "unable to request irq\n");
+		goto err1;
+	}
+
+	priv->irq = i;
 	platform_set_drvdata(pdev, priv);
 	pdata = pdev->dev.platform_data;
 
@@ -587,8 +730,7 @@
 		goto err1;
 	}
 
-	error = sh_mobile_lcdc_setup_clocks(&pdev->dev,
-					    pdata->clock_source, priv);
+	error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv);
 	if (error) {
 		dev_err(&pdev->dev, "unable to setup clocks\n");
 		goto err1;
@@ -637,6 +779,7 @@
 		info->fix.smem_start = priv->ch[i].dma_handle;
 		info->screen_base = buf;
 		info->device = &pdev->dev;
+		info->par = &priv->ch[i];
 	}
 
 	if (error)
@@ -664,6 +807,10 @@
 			 (int) priv->ch[i].cfg.lcd_cfg.xres,
 			 (int) priv->ch[i].cfg.lcd_cfg.yres,
 			 priv->ch[i].cfg.bpp);
+
+		/* deferred io mode: disable clock to save power */
+		if (info->fbdefio)
+			sh_mobile_lcdc_clk_off(priv);
 	}
 
 	return 0;
@@ -697,15 +844,16 @@
 	}
 
 #ifdef CONFIG_HAVE_CLK
-	if (priv->clk) {
-		clk_disable(priv->clk);
-		clk_put(priv->clk);
-	}
+	if (priv->dot_clk)
+		clk_put(priv->dot_clk);
+	clk_put(priv->clk);
 #endif
 
 	if (priv->base)
 		iounmap(priv->base);
 
+	if (priv->irq)
+		free_irq(priv->irq, priv);
 	kfree(priv);
 	return 0;
 }
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index 0d15b0e..5139c25 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -356,7 +356,9 @@
 		w1_write_8(sl->master, W1_SKIP_ROM);
 	else {
 		u8 match[9] = {W1_MATCH_ROM, };
-		memcpy(&match[1], (u8 *)&sl->reg_num, 8);
+		u64 rn = le64_to_cpu(*((u64*)&sl->reg_num));
+
+		memcpy(&match[1], &rn, 8);
 		w1_write_block(sl->master, match, 9);
 	}
 	return 0;
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 526c191..8dc7109 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -44,13 +44,15 @@
 #include <linux/list.h>
 #include <linux/sysdev.h>
 
-#include <asm/xen/hypervisor.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/tlb.h>
 
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+#include <xen/interface/xen.h>
 #include <xen/interface/memory.h>
 #include <xen/xenbus.h>
 #include <xen/features.h>
diff --git a/drivers/xen/features.c b/drivers/xen/features.c
index 0707714..99eda16 100644
--- a/drivers/xen/features.c
+++ b/drivers/xen/features.c
@@ -8,7 +8,11 @@
 #include <linux/types.h>
 #include <linux/cache.h>
 #include <linux/module.h>
-#include <asm/xen/hypervisor.h>
+
+#include <asm/xen/hypercall.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/version.h>
 #include <xen/features.h>
 
 u8 xen_features[XENFEAT_NR_SUBMAPS * 32] __read_mostly;
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 06592b9..7d8f531 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -40,6 +40,7 @@
 #include <xen/interface/xen.h>
 #include <xen/page.h>
 #include <xen/grant_table.h>
+#include <asm/xen/hypercall.h>
 
 #include <asm/pgtable.h>
 #include <asm/sync_bitops.h>
diff --git a/firmware/Makefile b/firmware/Makefile
index ca8cd30..4993a4b 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -24,6 +24,9 @@
 fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw
 fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin
 fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin
+fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \
+				   cxgb3/t3c_psram-1.1.0.bin \
+				   cxgb3/t3fw-7.0.0.bin
 fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin
 fw-shipped-$(CONFIG_SMCTR) += tr_smctr.bin
 fw-shipped-$(CONFIG_SND_KORG1212) += korg/k1212.dsp
diff --git a/firmware/WHENCE b/firmware/WHENCE
index 57002cd..8f06639 100644
--- a/firmware/WHENCE
+++ b/firmware/WHENCE
@@ -349,3 +349,14 @@
 Found in hex form in kernel source.
 
 --------------------------------------------------------------------------
+
+Driver: cxgb3 - Chelsio Terminator 3 1G/10G Ethernet adapter
+
+File: cxgb3/t3b_psram-1.1.0.bin.ihex
+File: cxgb3/t3c_psram-1.1.0.bin.ihex
+file: cxgb3/t3fw-7.0.0.bin.ihex
+
+License: GPLv2 or OpenIB.org BSD license, no source visible
+
+--------------------------------------------------------------------------
+
diff --git a/firmware/cxgb3/t3b_psram-1.1.0.bin.ihex b/firmware/cxgb3/t3b_psram-1.1.0.bin.ihex
new file mode 100644
index 0000000..1408930
--- /dev/null
+++ b/firmware/cxgb3/t3b_psram-1.1.0.bin.ihex
@@ -0,0 +1,162 @@
+:10000000FFFFFFFC000000000000000300000000F4
+:1000100000010100FFFFFFFC0000000000000003E2
+:100020000000000000000000FFFFFFFC00000000D7
+:10003000000000030000000000000000FFFFFFFCC4
+:1000400000000000000000030000000000000000AD
+:10005000FFFFFFFC000000000000000300000000A4
+:1000600000000000FFFFFFFC000000000000000394
+:100070000000000000000000FFFFFFFC0000000087
+:10008000000000030000000000000000FFFFFFFC74
+:10009000000000000000000300000000000000005D
+:1000A000FFFFFFFC00000000000000030000000054
+:1000B00000000000FFFFFFFC000000000000000344
+:1000C0000000000000000000FFFFFFFC0000000037
+:1000D000000000030000000000000000FFFFFFFC24
+:1000E000000000000000000300000000000000000D
+:1000F000FFFFFFFC00000000000000030000000004
+:1001000000000000FFFFFFFC0000000000000003F3
+:100110000000000000000000FFFFFFFBD03403E6FA
+:1001200080262A430000000000000000FFFFFFF8C7
+:10013000007000000000000200000081C604000002
+:10014000FFFFFFFC000000000000000300000000B3
+:1001500000000000FFFFFFFC0000000000000003A3
+:100160000000000000000000FFFFFFFC0000000096
+:10017000000000030000000000000000FFFFFFFC83
+:10018000000000000000000300000000000000006C
+:10019000FFFFFFFC00000000000000030000000063
+:1001A00000000000FFFFFFFC000000000000000353
+:1001B0000000000000000000FFFFFFFBD03403E25E
+:1001C000802829230000000000000000FFFFFFF846
+:1001D0000600023701C5C00013940481C6057000F3
+:1001E000FFFFFFF88200020637030803000000004B
+:1001F00000000000FFFFFFFC000000000000000204
+:10020000208000818DF40000FFFFFFFC0000000053
+:10021000000000030000000000000000FFFFFFFCE2
+:1002200000000000000000030000000000000000CB
+:10023000FFFFFFFC000000000000000300000000C2
+:1002400000000000FFFFFFFC0000000000000003B2
+:100250000000000000000000FFFFFFF9C4310000B3
+:1002600000282C830000000000000000FFFFFFF0CA
+:100270004E70021D00C5C00000000001C118000042
+:10028000FFFFFFFC00000000000000030000000072
+:1002900000000000FFFFFFFC000000000000000362
+:1002A0000000000000000000FFFFFFFC0000000055
+:1002B000000000030000000000000000FFFFFFFC42
+:1002C000000000000000000300000000000000002B
+:1002D000FFFFFFFC00000000000000030000000022
+:1002E00000000000FFFFFFFC000000000000000312
+:1002F0000000000000000000FFFFFFF1C00003E667
+:10030000802828230000000000000000FFFFFFFC01
+:1003100000000000000000021394040000017000BF
+:10032000FFFFFFFC000000000000000300000000D1
+:1003300000000000FFFFFFFC0000000000000003C1
+:100340000000000000000000FFFFFFFC00000000B4
+:10035000000000030000000000000000FFFFFFFCA1
+:10036000000000000000000300000000000000008A
+:10037000FFFFFFFC00000000000000030000000081
+:1003800000000000FFFFFFFC000000000000000371
+:100390000000000000000000FFFFFFFA103400041E
+:1003A000000001030000000000000000FFFFFFF05C
+:1003B0006000000620030802700000F080259A907B
+:1003C000FFFFFFFC00000000000000030000000031
+:1003D00000000000FFFFFFFC000000000000000321
+:1003E0000000000000000000FFFFFFFC0000000014
+:1003F000000000030000000000000000FFFFFFFC01
+:1004000000000000000000030000000000000000E9
+:10041000FFFFFFF1C83102060A000242000000811E
+:1004200080000000FFFFFFF9C83103C60A962A4288
+:100430000000008180000000FFFFFFF00431000495
+:10044000000004030000000000000000FFFFFFF0B8
+:1004500020B000000000000213940401C1197000D4
+:10046000FFFFFFFC00000000000000000000000192
+:1004700000001000FFFFFFFC000000000000000370
+:100480000000000000000000FFFFFFFC0000000073
+:10049000000000030000000000000000FFFFFFFC60
+:1004A0000000000000000003000000000000000049
+:1004B000FFFFFFF00000000400004000680C200176
+:1004C00000001090FFFFFFF9C031C3E600266A402C
+:1004D0000000000100001000FFFFFFFA10F4000010
+:1004E000000002430000000000000000FFFFFFF8D2
+:1004F0006050080000000000700C20F080259A90E9
+:10050000FFFFFFF0060000000100400000000001B6
+:1005100000001000FFFFFFFC0000000000000002D0
+:10052000288C108085C01000FFFFFFFC0000000039
+:10053000000000030000000000000000FFFFFFFCBF
+:1005400000000000000000030000000000000000A8
+:10055000FFFFFFFC0000000000000003000000009F
+:1005600000000000FFFFFFFC00000000000000038F
+:100570000000000000000000FFFFFFF04E00000040
+:10058000000000030000000000000000FFFFFFF17A
+:10059000C00002DE00061A40000000829035C00054
+:1005A000FFFFFFFC0000000000000003000000004F
+:1005B00000000000FFFFFFFC00000000000000033F
+:1005C0000000000000000000FFFFFFFC0000000032
+:1005D000000000030000000000000000FFFFFFFC1F
+:1005E0000000000000000003000000000000000008
+:1005F000FFFFFFFC000000000000000300000000FF
+:1006000000000000FFFFFFF1CA31C3C20A966A432F
+:100610000000000000000000FFFFFFF84E501439FA
+:100620001CC5C0030000000000000000FFFFFFF039
+:100630000000000000000002288C108085C010001F
+:10064000FFFFFFFC000000000000000300000000AE
+:1006500000000000FFFFFFFC00000000000000039E
+:100660000000000000000000FFFFFFFC0000000091
+:10067000000000030000000000000000FFFFFFFC7E
+:100680000000000000000003000000000000000067
+:10069000FFFFFFFC0000000000000003000000005E
+:1006A00000000000FFFFFFF3CA3323D60E966A4313
+:1006B0000000000000000000FFFFFFF8000004063B
+:1006C00020D002430000000000000000FFFFFFF800
+:1006D00000D0000000000000000000839031C00046
+:1006E000FFFFFFFC0000000000000003000000000E
+:1006F00000000000FFFFFFFC0000000000000003FE
+:100700000000000000000000FFFFFFFC00000000F0
+:10071000000000030000000000000000FFFFFFFCDD
+:1007200000000000000000030000000000000000C6
+:10073000FFFFFFFC000000000000000300000000BD
+:1007400000000000FFFFFFF3CA33E3D60E966A43B2
+:100750000000000000000000FFFFFFF000501A1032
+:10076000003002430000000000000000FFFFFFF81F
+:100770000000020620030800700000F990118A9022
+:10078000FFFFFFFC0000000000000003000000006D
+:1007900000000000FFFFFFFC00000000000000035D
+:1007A0000000000000000000FFFFFFFC0000000050
+:1007B000000000030000000000000000FFFFFFFC3D
+:1007C0000000000000000003000000000000000026
+:1007D000FFFFFFFC0000000000000003000000001D
+:1007E00000000000FFFFFFFC00000000000000030D
+:1007F0000000000000000000FFFFFFF9C0501BA632
+:1008000000D202430000000000000000FFFFFFF0E4
+:100810004000020700100002700000E890344A9087
+:10082000FFFFFFFC000000000000000300000000CC
+:1008300000000000FFFFFFFC0000000000000003BC
+:100840000000000000000000FFFFFFFC00000000AF
+:10085000000000030000000000000000FFFFFFFC9C
+:100860000000000000000003000000000000000085
+:10087000FFFFFFFC0000000000000003000000007C
+:1008800000000000FFFFFFFC00000000000000036C
+:100890000000000000000000FFFFFFFA10F4020853
+:1008A00000C002430000000000000000FFFFFFF056
+:1008B0000000000000000000728CC8D893891090DE
+:1008C000FFFFFFF082900000030000030000000023
+:1008D00000000000FFFFFFFC00000000000000031C
+:1008E0000000000000000000FFFFFFFC000000000F
+:1008F000000000030000000000000000FFFFFFFCFC
+:1009000000000000000000030000000000000000E4
+:10091000FFFFFFFC000000000000000300000000DB
+:1009200000000000FFFFFFFC0000000000000003CB
+:100930000000000000000000FFFFFFF000000000CA
+:10094000000000030000000000000000FFFFFFF2B5
+:1009500000000320002612430000000000000000F9
+:10096000FFFFFFF040000203101000030000000032
+:1009700000000000FFFFFFFC00000000000000037B
+:100980000000000000000000FFFFFFFC000000006E
+:10099000000000030000000000000000FFFFFFFC5B
+:1009A0000000000000000003000000000000000044
+:1009B000FFFFFFFC0000000000000003000000003B
+:1009C00000000000FFFFFFFC00000000000000032B
+:1009D0000000000000000000FFFFFFF1D03403E63C
+:1009E00080262A430000000000000000FFFFFFF205
+:1009F0000834023000C005030000000000000000C1
+:040A000070EAA57F74
+:00000001FF
diff --git a/firmware/cxgb3/t3c_psram-1.1.0.bin.ihex b/firmware/cxgb3/t3c_psram-1.1.0.bin.ihex
new file mode 100644
index 0000000..c650480
--- /dev/null
+++ b/firmware/cxgb3/t3c_psram-1.1.0.bin.ihex
@@ -0,0 +1,162 @@
+:10000000FFFFFFF4000000040000000100000001F9
+:1000100000010100FFFFFFF40000000400000001E8
+:100020000000000100000000FFFFFFF400000004DA
+:10003000000000010000000100000000FFFFFFF4CD
+:1000400000000004000000010000000100000000AA
+:10005000FFFFFFF4000000040000000100000001A9
+:1000600000000000FFFFFFF400000004000000019A
+:100070000000000100000000FFFFFFF4000000048A
+:10008000000000010000000100000000FFFFFFF47D
+:10009000000000040000000100000001000000005A
+:1000A000FFFFFFF400000004000000010000000159
+:1000B00000000000FFFFFFF400000004000000014A
+:1000C0000000000100000000FFFFFFF4000000043A
+:1000D000000000010000000100000000FFFFFFF42D
+:1000E000000000040000000100000001000000000A
+:1000F000FFFFFFF400000004000000010000000109
+:1001000000000000FFFFFFF40000000400000001F9
+:100110000000000100000000FFFFFFF3D03403E205
+:1001200080262A410000000100000000FFFFFFF8C8
+:10013000007000000000000000000080C604000005
+:10014000FFFFFFF4000000040000000100000001B8
+:1001500000000000FFFFFFF40000000400000001A9
+:100160000000000100000000FFFFFFF40000000499
+:10017000000000010000000100000000FFFFFFF48C
+:100180000000000400000001000000010000000069
+:10019000FFFFFFF400000004000000010000000168
+:1001A00000000000FFFFFFF4000000040000000159
+:1001B0000000000100000000FFFFFFFBD03403E25D
+:1001C000802829210000000100000000FFFFFFF847
+:1001D0000600023701C5C00213940480C6057000F2
+:1001E000FFFFFFF88200020637030801000000014C
+:1001F00000000000FFFFFFF400000004000000000A
+:10020000208000808DF40000FFFFFFF40000000458
+:10021000000000010000000100000000FFFFFFF4EB
+:1002200000000004000000010000000100000000C8
+:10023000FFFFFFF4000000040000000100000001C7
+:1002400000000000FFFFFFF40000000400000001B8
+:100250000000000100000000FFFFFFF9C4310000B2
+:1002600000282C810000000100000000FFFFFFF0CB
+:100270004E70021D00C5C00200000000C118000041
+:10028000FFFFFFF400000004000000010000000177
+:1002900000000000FFFFFFF4000000040000000168
+:1002A0000000000100000000FFFFFFF40000000458
+:1002B000000000010000000100000000FFFFFFF44B
+:1002C0000000000400000001000000010000000028
+:1002D000FFFFFFF400000004000000010000000127
+:1002E00000000000FFFFFFF4000000040000000118
+:1002F0000000000100000000FFFFFFF1C00003E666
+:10030000802828210000000100000000FFFFFFF40A
+:1003100000000004000000021394040000017000BB
+:10032000FFFFFFF4000000040000000100000001D6
+:1003300000000000FFFFFFF40000000400000001C7
+:100340000000000100000000FFFFFFF400000004B7
+:10035000000000010000000100000000FFFFFFF4AA
+:100360000000000400000001000000010000000087
+:10037000FFFFFFF400000004000000010000000186
+:1003800000000000FFFFFFF4000000040000000177
+:100390000000000100000000FFFFFFFA103400041D
+:1003A000000001010000000100000000FFFFFFF05D
+:1003B0006000000620030802700000F080259A907B
+:1003C000FFFFFFF400000004000000010000000136
+:1003D00000000000FFFFFFF4000000040000000127
+:1003E0000000000100000000FFFFFFF40000000417
+:1003F000000000010000000100000000FFFFFFF40A
+:1004000000000004000000010000000100000000E6
+:10041000FFFFFFF9C83102020A000242000000811A
+:1004200080000000FFFFFFF1C83103C20A962A4294
+:100430000000008180000000FFFFFFF00431000495
+:10044000000004010000000100000000FFFFFFF8B1
+:1004500020B000040000000013940400C1197000D3
+:10046000FFFFFFF400000004000000020000000095
+:1004700000001000FFFFFFF4000000040000000176
+:100480000000000100000000FFFFFFF40000000476
+:10049000000000010000000100000000FFFFFFF469
+:1004A0000000000400000001000000010000000046
+:1004B000FFFFFFF80000000000004000680C200172
+:1004C00000001090FFFFFFF9C031C3E600266A422A
+:1004D0000000000000001000FFFFFFF210F4000415
+:1004E000000002410000000100000000FFFFFFF0DB
+:1004F0006050080400000002700C20F180259A90E2
+:10050000FFFFFFF8060000040100400200000000A9
+:1005100000001000FFFFFFF40000000400000002D4
+:10052000288C108085C01000FFFFFFF4000000043D
+:10053000000000010000000100000000FFFFFFF4C8
+:1005400000000004000000010000000100000000A5
+:10055000FFFFFFF4000000040000000100000001A4
+:1005600000000000FFFFFFF4000000040000000195
+:100570000000000100000000FFFFFFF04E0000003F
+:10058000000000010000000100000000FFFFFFF973
+:10059000C00002DA00061A42000000839035C00055
+:1005A000FFFFFFF400000004000000010000000154
+:1005B00000000000FFFFFFF4000000040000000145
+:1005C0000000000100000000FFFFFFF40000000435
+:1005D000000000010000000100000000FFFFFFF428
+:1005E0000000000400000001000000010000000005
+:1005F000FFFFFFF400000004000000010000000104
+:1006000000000000FFFFFFF9CA31C3C60A966A4125
+:100610000000000100000000FFFFFFF84E501439F9
+:100620001CC5C0010000000100000000FFFFFFF03A
+:100630000000000000000002288C108085C010001F
+:10064000FFFFFFF4000000040000000100000001B3
+:1006500000000000FFFFFFF40000000400000001A4
+:100660000000000100000000FFFFFFF40000000494
+:10067000000000010000000100000000FFFFFFF487
+:100680000000000400000001000000010000000064
+:10069000FFFFFFF400000004000000010000000163
+:1006A00000000000FFFFFFF3CA3323D60E966A4115
+:1006B0000000000100000000FFFFFFF8000004063A
+:1006C00020D002410000000100000000FFFFFFF801
+:1006D00000D0000000000000000000839031C00046
+:1006E000FFFFFFF400000004000000010000000113
+:1006F00000000000FFFFFFF4000000040000000104
+:100700000000000100000000FFFFFFF400000004F3
+:10071000000000010000000100000000FFFFFFF4E6
+:1007200000000004000000010000000100000000C3
+:10073000FFFFFFF4000000040000000100000001C2
+:1007400000000000FFFFFFFBCA33E3D20E966A41B0
+:100750000000000100000000FFFFFFF000501A1031
+:10076000003002410000000100000000FFFFFFF028
+:100770000000020220030800700000F990118A9026
+:10078000FFFFFFF400000004000000010000000172
+:1007900000000000FFFFFFF4000000040000000163
+:1007A0000000000100000000FFFFFFF40000000453
+:1007B000000000010000000100000000FFFFFFF446
+:1007C0000000000400000001000000010000000023
+:1007D000FFFFFFF400000004000000010000000122
+:1007E00000000000FFFFFFF4000000040000000113
+:1007F0000000000100000000FFFFFFF1C0501BA23D
+:1008000000D202410000000100000000FFFFFFF8DD
+:100810004000020300100002700000E890344A908B
+:10082000FFFFFFF4000000040000000100000001D1
+:1008300000000000FFFFFFF40000000400000001C2
+:100840000000000100000000FFFFFFF400000004B2
+:10085000000000010000000100000000FFFFFFF4A5
+:100860000000000400000001000000010000000082
+:10087000FFFFFFF400000004000000010000000181
+:1008800000000000FFFFFFF4000000040000000172
+:100890000000000100000000FFFFFFFA10F4020852
+:1008A00000C002410000000100000000FFFFFFF057
+:1008B0000000000000000002728CC8D993891090DB
+:1008C000FFFFFFF082900000030000010000000124
+:1008D00000000000FFFFFFF4000000040000000122
+:1008E0000000000100000000FFFFFFF40000000412
+:1008F000000000010000000100000000FFFFFFF405
+:1009000000000004000000010000000100000000E1
+:10091000FFFFFFF4000000040000000100000001E0
+:1009200000000000FFFFFFF40000000400000001D1
+:100930000000000100000000FFFFFFF000000000C9
+:10094000000000010000000100000000FFFFFFF2B6
+:1009500000000320002612410000000100000000FA
+:10096000FFFFFFF040000203101000010000000133
+:1009700000000000FFFFFFF4000000040000000181
+:100980000000000100000000FFFFFFF40000000471
+:10099000000000010000000100000000FFFFFFF464
+:1009A0000000000400000001000000010000000041
+:1009B000FFFFFFF400000004000000010000000140
+:1009C00000000000FFFFFFF4000000040000000131
+:1009D0000000000100000000FFFFFFF9D03403E237
+:1009E00080262A410000000100000000FFFFFFF206
+:1009F0000834023000C005010000000100000000C2
+:040A000070EAA741B0
+:00000001FF
diff --git a/firmware/cxgb3/t3fw-7.0.0.bin.ihex b/firmware/cxgb3/t3fw-7.0.0.bin.ihex
new file mode 100644
index 0000000..e661179
--- /dev/null
+++ b/firmware/cxgb3/t3fw-7.0.0.bin.ihex
@@ -0,0 +1,1881 @@
+:1000000060007400200380002003700000001000D6
+:1000100000002000E100028400070000E1000288E7
+:1000200000010000E0000000E00000A0010000006E
+:1000300044444440E3000183200200002001E0002A
+:100040002001FF101FFFD0001FFFC000E300043C91
+:1000500002000000200069541FFFC5802000699C39
+:100060001FFFC584200069DC1FFFC58820006A507F
+:100070001FFFC58C200003C0C00000E43100EA313E
+:1000800000A13100A03103020002ED306E2A05000C
+:10009000ED3100020002160012FFDBC03014FFDA5F
+:1000A000D30FD30FD30F03431F244C107249F0D347
+:1000B0000FD30FD30F12FFD5230A00240A00D30F4A
+:1000C000D30FD30F03431F244C107249F0D30FD327
+:1000D0000FD30F14FFCE03421F14FFCB03421F1296
+:1000E000FFCCC0302D37302D37342D37382D373CED
+:1000F000233D017233ED00020012FFC4C0302F37E0
+:10010000002F37102F37202F3730233D017233ED6A
+:1001100000020012FFBEC0302737002737102737F4
+:1001200020273730233D017233ED03020012FFB95F
+:1001300013FFBA0C0200932012FFB913FFB90C028F
+:1001400000932012FFB8C0319320822012FFB71312
+:10015000FFB7932012FFB715FFB316FFB6C030D715
+:100160002005660160001B00000000000000000088
+:10017000043605000200D30FD30F7531140747145E
+:1001800005330C0704437631E60436057539ED0076
+:10019000020012FFA715FFA3C030D72060000600A1
+:1001A00007471405330C070443043E057539F00373
+:1001B000020012FFA1C03014FFA1D30FD30FD30F41
+:1001C0009340B4447249F2D30FD30FD30F14FF9B63
+:1001D000834014FF9B834012FF9B230A0014FF9A65
+:1001E000D30FD30FD30F9340B4447249F2D30FD33C
+:1001F0000FD30F14FF95834012FF95CA20832084EC
+:10020000218522BC22743B108650B4559630B433FD
+:100210007433F463FFE6000000653FE0655FDD12C4
+:10022000FF7CC03028374028374428374828374CCF
+:10023000233D017233ED03020000020012FF7AC079
+:1002400032032E0503020012FF7813FF819320C0B2
+:1002500011014931004831010200C00014FF7E0441
+:10026000D23115FF7D945014FF7D04D33115FF7CEE
+:10027000945014FF7C04D43115FF7C24560014FFE5
+:100280007B04D53115FF7B24560010FF7A03000054
+:10029000000000000000000000000000000000005E
+:1002A000000000000000000000000000000000004E
+:1002B000000000000000000000000000000000003E
+:1002C000000000000000000000000000000000002E
+:1002D000000000000000000000000000000000001E
+:1002E000000000000000000000000000000000000E
+:1002F00000000000000000000000000000000000FE
+:1003000000000000000000000000000000000000ED
+:1003100000000000000000000000000000000000DD
+:1003200000000000000000000000000000000000CD
+:1003300000000000000000000000000000000000BD
+:1003400000000000000000000000000000000000AD
+:10035000000000000000000000000000000000009D
+:10036000000000000000000000000000000000008D
+:10037000000000000000000000000000000000007D
+:10038000000000000000000000000000000000006D
+:10039000000000000000000000000000000000005D
+:1003A000000000000000000000000000000000004D
+:1003B000000000000000000000000000000000003D
+:1003C000000000000000000000000000000000002D
+:1003D000000000000000000000000000000000001D
+:1003E000000000000000000000000000000000000D
+:1003F00000000000000000000000000000000000FD
+:1004000000000000000000000000000000000000EC
+:1004100000000000000000000000000000000000DC
+:1004200063FFFC000000000000000000000000006E
+:100430000000000000000000000000001FFC0000A1
+:100440001FFC0000E30005C81FFC00001FFC0000AB
+:10045000E30005C81FFC00001FFC0000E30005C806
+:100460001FFFC0001FFFC000E30005C81FFFC00042
+:100470001FFFC018E30005C81FFFC0181FFFC018EA
+:10048000E30005E01FFFC0181FFFC288E30005E07E
+:100490001FFFC2881FFFC288E30008501FFFC290E1
+:1004A0001FFFC57CE3000850200000002000016A07
+:1004B000E3000B3C2000018020000180E3000CA839
+:1004C0002000020020000203E3000CA82000021C10
+:1004D00020000220E3000CAC2000022020000226B5
+:1004E000E3000CB02000023C20000240E3000CB806
+:1004F0002000024020000249E3000CBC2000024C16
+:1005000020000250E3000CC82000025020000259D5
+:10051000E3000CCC2000025C20000260E3000CD859
+:100520002000026020000269E3000CDC2000026C65
+:1005300020000270E3000CE8200002702000027925
+:10054000E3000CEC2000028C2000028CE3000CF88D
+:100550002000029020000293E3000CF8200002AC7F
+:10056000200002B0E3000CFC200002D0200002F2C8
+:10057000E3000D00200003B0200003B0E3000D24D1
+:10058000200003B0200003B0E3000D24200003B0DE
+:10059000200003B0E3000D24200003B0200003B0CE
+:1005A000E3000D24200003B020006B74E3000D2451
+:1005B00020006B7420006B74E30074E800000000FE
+:1005C00000000000000000001FFC00001FFC0000F5
+:1005D0001FFFC5801FFFC67020006B7820006B785E
+:1005E000DEFFFE000000080CDEADBEEF1FFFC29074
+:1005F0001FFCFE001FFFC0841FFFC5C030000000AD
+:10060000003FFFFF8040000010000000080FFFFFC8
+:100610001FFFC25D000FFFFF804FFFFF8000000043
+:1006200000000880B000000560500000600000007D
+:1006300040000011350000004100000010000001E2
+:1006400020000000000010007FFFFFFF40000000BE
+:1006500005000000800000190400000000000800F0
+:1006600010000005806000007000000020000009FC
+:10067000001FF8008000001EA0000000F80000002D
+:100680000800000007FFFFFF1800000001008001C4
+:10069000420000001FFFC20D1FFFC0CC0001008000
+:1006A000604000001A0000000C0000000000300054
+:1006B000600008008000001C000100008000001A9B
+:1006C00080000018FC0000008000000100004000D5
+:1006D000800004000300000050000003FFFFBFFF84
+:1006E00000000FFF1FFFC390FFFFF000000016D0B7
+:1006F0000000FFF7A50000001FFFC4A01FFFC451AA
+:100700000001000800000B20202FFF801FFFC445C0
+:1007100000002C00FFFEFFF800FFFFFF1FFFC56871
+:1007200000002000FFFFDFFF0000FFEF01001100CD
+:100730001FFFC4611FFFC3C21FFFC4101FFFC5906E
+:10074000FFFFEFFF0000FFFB1FFFBE90FFFFF7FF63
+:100750001FFFC0540000FFFD0001FBD01FFFC5B00C
+:100760001FFFC6601FFFC591E0FFFE000000800074
+:100770001FFFC52C1FFFC5B41FFFC0581FFFC4D0EB
+:100780001FFCFFD800010081E100060000002710D7
+:100790001FFCFE301FFCFE70E10002001FFFC52899
+:1007A0001FFFC5400003D0901FFFC5542B5063802E
+:1007B0002B5079802B5090802B50A6801FFFC4595E
+:1007C0000100110F202FFE0020300080202FFF009D
+:1007D0000000FFFF0001FFF82B50B2002B50B208C1
+:1007E000000100102B50B1802B50B2802B50BA006A
+:1007F000000100112B50BD282B50BC802B50BDA0F8
+:1008000020300000DFFFFE005000000200C00000AA
+:1008100002000000FFFFF7F41FFFC05C000FF800AC
+:1008200004400000001000000C4000001C400000CC
+:10083000E00000A01FFFC5301FFD00081FFFC544DA
+:100840001FFFC5581FFFC56CE1000690E10006ECD4
+:100850000100000000000000000000000000000097
+:100860002010004020100040201000402014008084
+:10087000200C0000200C0000200C00002010004084
+:10088000201400802014008020140080201800C054
+:10089000201C0100201C0100201C01002020014020
+:1008A000201800C0201800C0201800C0201C010023
+:1008B000201800C0201800C0201800C0201C010013
+:1008C000202001402020014020200140202009401C
+:1008D00020200940202009402020094020240980B0
+:1008E000FFFFFFFFFFFFFFFFFFFFFFFF0000000014
+:1008F00000000000000000000000000000000000F8
+:100900002000525420005124200052542000525400
+:1009100020005060200050602000506020004E9465
+:1009200020004E9420004E8C20004DFC20004CA056
+:1009300020004A88200048880000000000000000D5
+:1009400020005224200050F02000519420005194A7
+:1009500020004F3820004F3820004F3820004F38FB
+:1009600020004F3820004E8420004F3820004BC418
+:1009700020004A3C20004838000000000000000031
+:1009800020000B702000384C200004C02000442CB4
+:1009900020000B6820003F40200003F0200043ECC3
+:1009A0002000481420003C5020003B6C200037C839
+:1009B00020003654200033CC20002EF8200039CC03
+:1009C00020002B5C200027942000648C2000232032
+:1009D0002000200420001FB820001CA4200017B015
+:1009E000200014F020000D8C20000BB4200010BC5F
+:1009F000200012A02000413020003C0420000B7891
+:100A0000200004C000000000000000000000000002
+:100A100000000000000000000000000000000000D6
+:100A200000000000000000000000000000000000C6
+:100A300000000000000000000000000000000000B6
+:100A400000000000000000000000000000000000A6
+:100A50000000000000000000000000000000000096
+:100A60000000000000000000000000000000000086
+:100A70000000000000000000000000000000000076
+:100A8000000000003264000000000000326400003A
+:100A90006400640064006400640064006400640036
+:100AA0000000000000000000000000000000000046
+:100AB0000000000000000000000000000000000036
+:100AC0000000000000000000000000000000000026
+:100AD0000000000000000000000000000000000016
+:100AE00000000000000000000000100000000000F6
+:100AF00000000000000000000000000000000000F6
+:100B000000001000000000000000000000000000D5
+:100B100000000000004323800000000000000000EF
+:100B200000000000000000000000000000000000C5
+:100B3000000000000000000000000000005C9401C4
+:100B40005D94025E94035F94004300000000000087
+:100B50000000000000000000000000000000000095
+:100B60000000000000000000000000000000000085
+:100B7000000000000000000000000000005C900188
+:100B80005D90025E90035F90005300000000000043
+:100B90000000000000000000000000000000000055
+:100BA0000000000000000000000000000000000045
+:100BB000000000000000000000000000009C940005
+:100BC0001D90019D94029E94039F9404089405092E
+:100BD00094060A94070B94004300000000000000F4
+:100BE0000000000000000000000000000000000005
+:100BF000000000000000000000000000009C9001C8
+:100C00009D90029E90071D90039F90047890057917
+:100C100090067A90077B90005300000000000000CF
+:100C200000000000000000000000000000000000C4
+:100C300000000000000000000000000000DC940044
+:100C40001D9001DD9402DE9403DF940404940505F5
+:100C5000940606940707940808940909940A0A94CC
+:100C60000B0B940043000000000000000000000097
+:100C700000000000000000000000000000DC900107
+:100C8000DD9002DE900B1D9003DF9004B49005B55B
+:100C90009006B69007B79008B89009B9900ABA9034
+:100CA0000BBB90005300000063FFFC002000693084
+:100CB00010FFFF0A000000002000695400D231102C
+:100CC000FFFE0A00000000002000699C00D33110E4
+:100CD000FFFE0A0000000000200069DC00D4311093
+:100CE000FFFE0A000000000020006A5000D531100D
+:100CF000FFFE0A000000000063FFFC00E00000A00F
+:100D000012FFF78220028257C82163FFFC12FFF313
+:100D100003E83004EE3005C030932094219522631F
+:100D2000FFFC00001FFFD000000400201FFFC58053
+:100D30001FFFC670200A0011FFFB13FFFB03E63103
+:100D400001020016FFFA17FFFAD30F776B069060C7
+:100D5000B4667763F85415265419D90F140063FF4D
+:100D6000F90000006C1004C020D10F006C1006C008
+:100D7000C71AEF060D4911D830D7201BEF05BC224A
+:100D80008572AB76837105450B957209330C23761A
+:100D900001723B05233D08237601A39D19EEFE7DDC
+:100DA0006326C021C0E0032E380E0E42C8EE29A6ED
+:100DB0007E6D4A0500808800308C8271D10FC0F0B2
+:100DC000082F387FC0EA63FFE49210037F0CABFF6B
+:100DD0000F3D12DB802EDC100E4E36C021C05003BA
+:100DE0002538221200050542CB5029A67E6DEA0562
+:100DF00000B08800308CBC76C050A8F3C081068556
+:100E000038050542CA5129A67E0D480CD30F6D8ABC
+:100E10000500308800208C8271D10F00C061C05065
+:100E200008653875C0C663FFC0C0B0038B387BC08F
+:100E3000D763FFD16C101216EED82A221E2E221D67
+:100E4000C0D07AE11B2CA000D7A028CCE96481484F
+:100E500029CCE8649341C1B97BC12569CC1B6000F2
+:100E6000222CD000D7D028CCE964815429CCE86466
+:100E700093BAC1B97BC10968CC09C020D10F000069
+:100E8000002D25028C32C0900C6F5065F586292408
+:100E900067090847658582B44927200C18EEC00C05
+:100EA0007F11A8FF28F286DB707893026005541941
+:100EB000EEBC09790A2992A36890082822000988C3
+:100EC0000C65853F29F28564953929161A655563A5
+:100ED0007AE104DBA0600001C0B022161B8DB412C1
+:100EE000EEB10D881482240D0D47A82218EEAF092B
+:100EF000DD10082202929018EEAD12EEAE08C80185
+:100F00000D88020242021DEEAA92910D880298926B
+:100F100022B0232DB02204281006DD100242120850
+:100F2000DD0228B0210722100C88100288020D88EB
+:100F30000212EEA18D3302DD0182340D88029893F6
+:100F400092B992948DB582399D9588B68D389896D0
+:100F500088B792999D989897C0D028F28512EE97FD
+:100F600008480BA2722D24CF28F68522121B655447
+:100F7000DE7AE104DBA0600001C0B064BEFB2CB0EF
+:100F80000728B000DA2006880A28824CC0D10B80DE
+:100F900000DBA065AFE763FEE02EA0032B2067D93E
+:100FA000E0D4E065B1AB8B320BFC5064C4B218EEF8
+:100FB000848F2A08B80108FF0C64F2CDC09260014A
+:100FC0008A2AD003292067D4A06594C98B320BFCF0
+:100FD0005064C48C1FEE7B8E2A0FBF017FE9DC8C2E
+:100FE000330CE8506484B4C0B00CA5118F592B1693
+:100FF000128A578E582A1611DBE0AAFA7FAB01B18C
+:10100000EB75CE599E1F8937951CAF98981D798B2B
+:101010000825160C29EC0129160F9A168A1D851F22
+:101020002A16192A0A007BE30A7BE9052B12067FA0
+:10103000BB01C0A165A4698B35C0A0C08078E30462
+:1010400064E3B5C0A165A458891C2916170C4A543D
+:101050002A1616BCAA2A16186000AF0000008837AE
+:10106000893628161429161508F80C09E90C2916D2
+:1010700013981E78FB07281213B088281613891EB0
+:101080009A189F172A1213C0F02916197BE30C7BBC
+:10109000E9078E172B12087EBB01C0F165F406C06C
+:1010A000B02F121988352E12129819281211AAEE93
+:1010B000AF8F78FB022EEC019F138F199F12C0F0A7
+:1010C0007BE30C7EB9078913281202798B01C0F1EA
+:1010D00065F3D22516172912150C4F54C0E12F16AF
+:1010E00016BCFF2F161800F10400EE1A2F1214B0D0
+:1010F000EE0EF8130988010FEE012F1219A8AAAEFF
+:10110000FE7FEB01B1AAD5A02E16192B1219DA50C9
+:101110002C12185818D3C0D0C0902E121907480AA4
+:101120002C1218DAB08F34C0B1AAFF00C1042A1201
+:10113000162F86162C121700BB1AB0BB0EBE019ECE
+:10114000C90BFB1305BB019BC82A7410292467290E
+:1011500070038E75B19F2F7403B0EE0E4E0C65EDCB
+:10116000182820672D25026583132A221E29221D97
+:101170007A9104DBA0600001C0B064BCFC2CB00715
+:1011800028B000DA2006880A28824CC0D10B8000E3
+:10119000DBA065AFE763FCE189AAB199659094890A
+:1011A000341BEE0899AA88331FEE0208485428A47D
+:1011B0002C8E2A8C320FEE020BCB017EB9640C4BC5
+:1011C000516FB25E8B3375B6592CA0130BEE510ED6
+:1011D000CE010E0E410C0C417EC9472FA012B0FF6C
+:1011E00065F2DD8E378CA88B368FA97CB3077BC95F
+:1011F000027EFB01C0D1CED98835DDB00E8E0878D5
+:10120000EB01B1BD89A7DAC00F9B0879BB022ACCDC
+:1012100001DCB0C0B07DA3077AD9027CEB01C0B17C
+:1012200064B163C091292467C020D10F008BDAB16B
+:10123000BB64B0C02C20672D250265C2281DEDDCE3
+:101240008C321FEDE10DCD010FDD0C65D1C10C4FCE
+:10125000516FF2026001B8C0902924670908476500
+:10126000820F7AE104DBA0600001C0B064BC0A2CEC
+:10127000B00728B000DA2006880A28824CC0D10BBB
+:101280008000DBA065AFE763FBEF8C330CE95064B3
+:1012900092090CEF11AFAF2F16178EF885F7DBE030
+:1012A0008FF9251610A5F57F5B022BEC010CA850D9
+:1012B0006580DD8837DAE0AF8929160A789B022A33
+:1012C000EC019514891AD5A02916192A0A007BE386
+:1012D0000A7BE9052B12047FBB01C0A165A1C18B6C
+:1012E00035C0A0C08078E30464E104C0A164AD5CB3
+:1012F0006001AD00008E3419EDB39EDA8C331BED26
+:10130000AC0C4C542CD42C8A2A8C320BAA0209C95E
+:10131000010A990C659F0B0C4F516EF20263FF029C
+:101320008B330BA850648EFA29D0130BEA510A9A1A
+:10133000010A0A410909410A990C659EE52BD01260
+:10134000B0BB65B188C0A08E378CD82B32062FD2A7
+:10135000097CB3077BC9027EFB01C0A165AEC388CF
+:1013600035D3B0AE8E78EB01B1B389D7DAC0AF9B7D
+:1013700079BB01B1CADCB0C0B073A3077A39027C73
+:10138000EB01C0B165BE9BC090292467C020D10F7E
+:10139000008A3688372A16152816140AEA0C08F827
+:1013A0000C981B78FB01B0AA9F158F1B2F16192FC5
+:1013B0000A007BE30A7BE905281205785B01C0F18E
+:1013C00065F0E2AADE8B352F1219291210C050AF3A
+:1013D0009F79FB01B1EE9F11C0F075E30A7E5905BC
+:1013E00028120178BB01C0F164FCEA6000B700007C
+:1013F0007FB30263FEF663FEF17FB30263FC4563D5
+:10140000FC4000006450A4DA205815C8C020D10F59
+:10141000C09163FE43C09163FA73DA20DB70C0D1E0
+:101420002E0A80C09A2924682C70075814B8D2A0BC
+:10143000D10F000019ED6603480B9810088B0209C4
+:1014400029087983022B8DF829121A63FA8B000080
+:101450002A2C74DB40580E442E221D2A221E63FBC8
+:101460000FC09163FCE5022A0258024C0AA2020650
+:101470000000022A025802490AA202060000DB709C
+:10148000DA20C0D12E0A80C0CE2C24682C700758D8
+:10149000149FC020D10FD9A063FCB600C09463FC98
+:1014A000AAC09663FCA5C09663FCA0002A2C74DB3E
+:1014B00030DC405BFE2EC2D02DA4002B200C63FF3D
+:1014C000458F358EA77FEB0263FEBB63FD548935E4
+:1014D00088D7798B0263FEAE63FD47006C1004C0B1
+:1014E00020D10F006C1004C020D10F006C10042B11
+:1014F000221E28221DC0A0C0942924062A25027B72
+:101500008901DBA0C9B913ED24DA2028B0002CB082
+:101510000703880A28824CC0D10B8000DBA065AF8E
+:10152000E7C020D10F0000006C100602260229201F
+:1015300006C0E0689805289CF96581202A61021799
+:10154000ED170A0A4C65A0F02B729E1AED136FB8C6
+:10155000026000F42AA22668A0098B60D30F0ABBA0
+:101560000C65B0E42A729D64A0DE2B600C0CBC11EB
+:1015700007CC082DC2866FD9026000D71DED090D7A
+:10158000BD0A2DD2A368D0078F600DFF0C65F0C394
+:1015900022C285C0F06420BB1DED0E68434D18EDDE
+:1015A0000D8C6B08CC029C208A6008AA110DAA023F
+:1015B0009A21896A9924883298252C610408CC11D3
+:1015C0009C271CECFE0CBA11A7AA29A285ACBC2F43
+:1015D000C4CF299C2829A685C85A2A6C74DB405898
+:1015E0000DE2D2A0D10FD2E0D10F0000289CF96407
+:1015F00080912C60668931B1CC0C0C472C64666FED
+:10160000C669709E661AECF48C30896B0C8C400BAA
+:10161000CC100C99020A9902992088600888110D53
+:10162000880298218C339C238A329A22896A9924D1
+:101630008834982563FF820000CC57DA60DB30DC09
+:10164000405814A7C020D10F00DA60C0B658153733
+:1016500063FFE500DA6058153563FFDC00DA20DB54
+:1016600030DC40DD505815B7D2A0D10F9E102B6151
+:10167000045813C81DECD78E102B600CC0F02F64DB
+:101680006663FF80296123C08879830263FF752E1A
+:1016900016002C60662B61042CCC010C0C472C64CA
+:1016A000665813BC1DECCB8E102B600CC0F02F6461
+:1016B0006663FF506C1004C0B7C0A116ECC815ECEF
+:1016C000BAD720D840B822C040053502967195702F
+:1016D00002A438040442C94B1AECAD19ECAE29A699
+:1016E0007EC140D30F6D4A0500808800208C220AFD
+:1016F00088A272D10FC05008A53875B0E363FFD738
+:101700006C100893149412292006655270C07168F9
+:1017100098052A9CF965A28016ECA12921028A1459
+:1017200009094C6590C78AA00A6A512AACFD65A0D8
+:10173000BCCC5FDB30DA208C12581469C0519A148B
+:10174000C7BF9BA98E142EE20968E0602F629E1D20
+:10175000EC926FF8026000812DD22668D0052F220E
+:10176000007DF9752C629DC79064C06D9C118A1430
+:101770002B200C2AA0200CBD11A6DD0A4F14BFA8F7
+:1017800009880129D286AF88288C09798B551FECEE
+:10179000840FBF0A2FF2A368F0052822007F894337
+:1017A00029D285D49065907760003D00002B200CF5
+:1017B0001FEC7C0CBD11A6DD29D2860FBF0A6E96E8
+:1017C000102FF2A368F00488207F890529D285654F
+:1017D0009155DA205814D5600013DA20C0B6581499
+:1017E000D3600009C09063FFB9DA205814D089147F
+:1017F000899109FE506551CC8C128D14DA20DBD012
+:101800008DD09E100D6D515813419A1464A1F0C7EC
+:101810005F8FA195A9C0510F0F479F1263FEFB0078
+:10182000C091C0F12820062C2066288CF9A7CC0C8A
+:101830000C472C24666FC6088D148DD170DE01C054
+:1018400090DD90648141C9D28A112B210458135133
+:101850008A14C0B02B24668EA92AA020C1701CEC6B
+:101860005B0E281415EC508E148556AC2C9C132E50
+:10187000EC28A855DDE07CE3022DEDF8D3D00A7703
+:1018800036DA40DB50DC305BFF8BD4A02E200CB46A
+:1018900055290A88C0C01BEC490CEF11A6FF28F29D
+:1018A00085ABEE2CE4CFA98828F685290A80881319
+:1018B000A933DD3089147833022D3DF8289020D3E8
+:1018C000D007880CC170080847289420087736652F
+:1018D0007FAE891413EC438990C0D477973D18EC00
+:1018E00041C1BA2721048514099C4006CC118653B6
+:1018F00004771185520C77020B7702C0C098A09D27
+:10190000A18D2B9CA597A496A795A603DD029DA269
+:101910002BF2852CE4CF2BBC202BF6852A2C748B44
+:1019200012580D11D2A0D10F28203DC0E07C87773E
+:101930002E24670E0A4765A07318EC2B8F201CEC31
+:10194000198E148CC48EE408FF1108FF020E8E1449
+:10195000AECC1EEC269F910ECC029C90C0801EEC5B
+:10196000242C21021AEC162FD285AABAB8FF2FD642
+:10197000850ECC0228A4CF2C2502C020D10F8714BD
+:10198000877007074763FD86282123C099798B025A
+:1019900063FEB2DDF063FEAD00DA20DB308C12DDD9
+:1019A000505814E8D2A0D10FC0E163FF828B148C91
+:1019B00012DD50C0AA2E0A802A2468DA2058135358
+:1019C000D2A0D10F007096552B629E6EB8531DEBBE
+:1019D000F22DD22668D0048E207DE9452A629DCB67
+:1019E000AF2B21042C20665812EBC090292466826C
+:1019F0001418EC008F2108FF019F21C020D10F0097
+:101A00008B10C9B88CA00C6C51CCCC8E241FEBEE83
+:101A10008DE19E140FDD029DE18810658FA9C02025
+:101A2000D10FDA20C0B6581441C020D10F000000F9
+:101A30006C1006C0D02A2102941175A70E89347F3C
+:101A400097098B357FBF042D2502DAD00A0C4C652F
+:101A5000C17B16EBD21FEBD028629EC0EA78E3026E
+:101A600060018129F2266890078A2009AA0C65A1E5
+:101A7000732A629DDEA064A1702B200CC0700CBC88
+:101A80001106CC0829C286280A0C79830260014C11
+:101A900019EBC409B90A2992A3689007882009881C
+:101AA0000C65813824C2851CEBC664412F8931093D
+:101AB0008B140CBB016FB11D2C20669E10B1CC0C99
+:101AC0000C472C24666EC60260013409FE5065E1A5
+:101AD0002E8A102AAC188934C0E47F973617EBC7DA
+:101AE000C0821BEBC58C359E419B408B2098459D49
+:101AF0004418EBC307BB029B420C07400F771198B9
+:101B0000439747D7E07FC70B2C2102284A0008CC17
+:101B1000022C25027E97048B362B25227D97048C80
+:101B2000372C25217C973A0AAB022C0A01C0800A87
+:101B3000C8382A3C200808426480821CEB9419EBC8
+:101B40009529C67E00A08800B08C00A08800B08CCB
+:101B500000A08800B08C28629D2DF4A2288C182843
+:101B6000669D89307797351FEB9F8C338832047BD5
+:101B70000B2A2104B47704AA119EB19FB08F2B9D2C
+:101B8000B598B69CB718EB96099C4006CC110CAAE8
+:101B90000208FF029FB2C1CC0CAA029AB4C9772AEC
+:101BA000200C1BEB860CA911A699289285ABAA2DB7
+:101BB000A4CF08780B289685CF58C020D10FC087B6
+:101BC000C0900AC93879880263FF7863FF6CCC57EC
+:101BD000DA20DB308C11581342C020D10FDA2058A4
+:101BE00013D363FFE8C0A063FE89DA20C0B65813A0
+:101BF000CF63FFD92A2C748B11580C5BD2A0D10F64
+:101C00008A102B21045812631FEB64C0D02D246668
+:101C100063FEBD006C1006D62019EB5F1EEB612839
+:101C2000610217EB5E08084C65805F8A300A6A51D2
+:101C300069A3572B729E6EB83F2A922668A0048C27
+:101C4000607AC9342A729D2C4CFECAAB2B600CB64C
+:101C50004F0CBD11A7DD28D2860EBE0A78FB269C4C
+:101C6000112EE2A32C160068E0052F62007EF91504
+:101C700022D285CF2560000D00DA60C0B65813ABC4
+:101C8000C85A60010F00DA605813A8655106DC409D
+:101C9000DB308D30DA600D6D5158121CD3A064A07A
+:101CA000F384A1C05104044763FF6D00C0B02C60F1
+:101CB000668931B1CC0C0C472C64666FC6027096F5
+:101CC0000A2B6104581233C0B02B64666550B42AE5
+:101CD0003C10C0E7DC20C0D1C0F002DF380F0F425B
+:101CE00064F09019EB2A18EB2B28967E8D106DDA94
+:101CF0000500A08800C08CC0A089301DEB3A779702
+:101D00005388328C108F3302CE0BC02492E12261B3
+:101D1000049DE00422118D6B9BE59FE798E61FEB85
+:101D2000300998400688110822020FDD02C18D9DFE
+:101D3000E208220292E4B4C22E600C1FEB200CE8F1
+:101D400011A7882C8285AFEE0C220B2BE4CF2286C4
+:101D500085D2A0D10F28600CD2A08C1119EB180CE1
+:101D60008D11A7DD2ED285A9882B84CF0ECC0B2C0C
+:101D7000D685D10FC0F00ADF387FE80263FF6C63BD
+:101D8000FF6000002A6C74C0B2DC20DD40581211E4
+:101D9000C0B063FF63C020D10F0000006C10042CA2
+:101DA000221D2A221EC049D320293006243468C0AF
+:101DB000407AC105DDA060000200C0D06E9738C037
+:101DC0008F2E0A802B3014C0962934060EBB022EAB
+:101DD00031022B34147E8004243502DE407AC10E99
+:101DE000C8ABDBD0DA302C0A00580A792E31020E4B
+:101DF0000F4CC8FEC020D10F6895F82831020808A2
+:101E00004C658FEF1AEAE61CEAE42BA29EC09A7B8F
+:101E10009B462BC22668B0048D307BD93B29A29DFE
+:101E2000C0E3CB9394901BEAF72D31049B9608DD19
+:101E3000110EDD029D979D9124C4A212EAF32F3169
+:101E40000228A29DC0E52E3406288C3028A69D02CB
+:101E5000FF022F3502C020D10FDA30C0B65813333D
+:101E6000C020D10F6C10062A2006941168A80528FE
+:101E7000ACF965824F29210209094C659206CC5FB5
+:101E8000DB30DA208C11581296C051D3A0C7AF9A1C
+:101E90003AC0E019EAC31DEAC91AEAC28F3A16EA43
+:101EA000BFB1FB64B1352C629E6FC8026001E927A7
+:101EB000DC33277226687007882007880C6581D874
+:101EC00024629DC0766441D02B200C0CBC11A6CCA2
+:101ED00028C286C09E7893026001C819EAB109B988
+:101EE0000A2992A39410689007882009880C6581BC
+:101EF000B224C2856441AC292006299CF96491DF93
+:101F00002C20668931B1CC0C0C472C24666EC6029D
+:101F100060019809F8506581921AEAA38C3619EA93
+:101F2000A10C881489940C0C4709CC10A8990A9923
+:101F30000218EAB62A210499409841882A19EAB47D
+:101F40000C8802098802984228302C2C3013293042
+:101F50001204CC100699100C88109F4408A8020C9B
+:101F6000990209880298438F379F458C389C46898F
+:101F700039C0F1994719EAA788359F4B98480888D6
+:101F800014098802984A8F3018EA9777F732C0749C
+:101F900089328C33984C974D0F9740882B2E4611E1
+:101FA0000677112C461329461204AC1119EA8D0745
+:101FB000CC02C179098802984E07CC022C4610C089
+:101FC0007AADBC0CBA11A6AA29A2852EC4CF097974
+:101FD0000B29A6856550FCC020D10F002B200C0CCE
+:101FE000BC1106CC082FC28609B90A6FF90260013C
+:101FF0001E2992A36890082F220009FF0C65F10F9B
+:102000002FC28564F10928203D082840648084841B
+:102010003504841464407C85A57453778436048425
+:102020001464406F74536C293013C08C798864C079
+:10203000902924670908476580DD882089A48435B4
+:102040001AEA6B048414A4940A440294F014EA6615
+:1020500008881104880298F1843698F3048414A443
+:10206000990A990299F21AEA6229210224C285ADDD
+:10207000B82E84CF244C1024C6850A990229250243
+:10208000C020D10F00CC57DA20DB308C115812144D
+:10209000C020D10FC09163FF97DA20C0B65812A3B9
+:1020A00063FFE100DA205812A163FFD88A102B21C8
+:1020B000045811381DEA422B200CC0E02E24668FF4
+:1020C0003A63FE5400DA20DB30DC40DD5058131D4B
+:1020D000D2A0D10F2A2C748B11580B23D2A0D10F70
+:1020E000292123C08879830263FE2D2A12002C2027
+:1020F000662B21042CCC010C0C472C24665811258E
+:102100001DEA2F2B200CC0E02E24668F3A63FE08B8
+:10211000DA2058128663FF6CDA205BFF20D2A0D150
+:102120000F0000006C100A9516C061C1B0D9402A9A
+:10213000203DC0400BAA010A64382A200629160750
+:1021400068A8052CACF965C33B1DEA16C8442F12DC
+:102150000664F29B2621021EEA12961406064C65BE
+:1021600062DE15EA0E6440CF8A352930039A150ADB
+:10217000990C6490C22C200C8B159C120CCC11A5D0
+:10218000CC9C132CC286B4BB7CB3026002CE8F12EF
+:102190000EFE0A2EE2A368E0082622000E660C65F9
+:1021A00062BA88132882856482B2891564905EDAE7
+:1021B00080D9308C201EEA0C1FEA0D1DE9FA8B1520
+:1021C0008DD4D4B07FB718B88A293C10853608C69C
+:1021D000110E66029681058514A5D50F55029580CE
+:1021E0000418146D8927889608CB110888140EBB33
+:1021F00002A8D8299C200F88029BA198A088929BB6
+:10220000A3088814A8D80F880298A22AAC10C0D0BE
+:102210008A151FE9EA8E1219E9F68B1388142CB27D
+:1022200085098802AFEE0CAA0B2DE4CF2AB68528CB
+:102230002502C020D10F000026529E18E9D76F68F2
+:102240000260020D2882266880098920D30F089930
+:102250000C6591FD2A529DC0FD9A1164A1F32B20BB
+:102260000CC1CA0CB8110588082D82860EBE0A7DE5
+:10227000C30260020A2EE2A368E0082622000E666E
+:102280000C6561FB288285DE806482072920069820
+:1022900010299CF96492042C20668831B1CC0C0C76
+:1022A000472C24666EC6026001BD08FD5065D1B79B
+:1022B00017E9DA1CE9BD19E9C42A21048B2D28305D
+:1022C000102D211D0C88100BDB090A8802098802D9
+:1022D0000CBB0264415589109B909791989284356C
+:1022E000D9E064406FD730DB40D8307F4715273CBA
+:1022F00010BCE92632168C3996E69CE78A37283CD2
+:10230000042AE6080B131464304A2A821686799A46
+:102310009696978C778A7D9C982B82172C7C209A96
+:102320009A2A9C189B99867BB03B298C086DB92111
+:102330008BC996A52692162AAC18B8999BA196A08F
+:102340008BC786CD9BA22B921596A49BA386CB2CE4
+:10235000CC2026A605C0346B4420043B0C0448095D
+:102360000E880A7FB705C0909988BC88C0900B1A68
+:10237000126DAA069988998B288C181CE9A81BE96C
+:10238000A816E99DB1DD2A211C23E6130D0D4F2669
+:10239000E6122D251DC06087207DA907C0D0280A20
+:1023A0000028251D26E6172CE6162BE61505D81164
+:1023B0001AE99328E6180A7A022AE614292006293F
+:1023C0009CF96491062A200CC0901BE97C0CAD118D
+:1023D000A5DD2CD285ABAAC0B029A4CF0CFC0B2C58
+:1023E000D685DA208C172D120658110DD2A0D10FE8
+:1023F0008A356FA546D8308BD56DA90C8A860A8A96
+:1024000014CBA77AB335288C10C080282467080B1A
+:102410004765B11CDA20DB308C17581131D3A0C0CE
+:10242000C1C0D02DA4039C1663FD280086366461CC
+:102430001689109B909791989263FEA1C08163FFCB
+:10244000C98A16CCA7DA20DB308C17581125C0209A
+:10245000D10FDA20C0B65811B563FFE400DA208B43
+:10246000125811B263FFD9009F189E198A112B21AF
+:10247000045810488E198F18C0B02B246663FE2FA5
+:10248000C08063FE01DA20DB308C17DD5058122D3E
+:10249000D2A0D10FDA205811A563FFA42D2123C0AB
+:1024A000C87DC30263FE089F188A112B21042C20CB
+:1024B000669819B1CC0C0C472C24665810368E192E
+:1024C0008F18C0D02D246663FDE50000262123B0BF
+:1024D0006606064F262523656EEA28206A7F870553
+:1024E0000829416490FDC0D01BE93F19E94E262020
+:1024F0000723E61BB166097A022BE61A28200A2D6B
+:10250000E61D2AE61E09880228E61C8826060647DC
+:1025100028E6208B2826E53E2BE6212D24072C20BB
+:10252000062A20642CCCFD64C09DB4FF63FE950098
+:1025300000DB30DA208D16C0CE2E0A802C24688C69
+:1025400017581072D2A0D10F8E102632161FE9151F
+:102550000626148FF62BE61297E127E61328E614D9
+:10256000A6FF0CFF029FE0C1F62EEC4826ECC064EB
+:102570006D6B8435C080644DDBD9E0DC30DBE0DDA1
+:1025800030B18814E92986C98AC8279DFF2CCC1050
+:10259000299C102A76322A76300464011AE9242410
+:1025A0007631AA442476332AD21617E9219AB6073F
+:1025B000660196B784C3BCBB94B58435B4DD74831F
+:1025C000BF2D211D63FD8D0064AF5E1DE8F62C203C
+:1025D000168DD20ACC0C00D10400CC1AACBC9C29BC
+:1025E00063FF46002B21046EB8222C2066B8CC0C69
+:1025F0000C472C2466C9C49F189E198A11580FE5F0
+:102600008E198F18C0348720C0D02D2466C068264C
+:10261000240663FED00000006C1008292006289CC8
+:10262000F86582C3292102C0AA09094C6590E62BEE
+:10263000200C16E8DA0CBC11A6CC2EC286C1D27EC4
+:10264000D30260028E19E8D609B90A2992A32A1684
+:10265000026890078A2009AA0C65A27729C28564BE
+:1026600092712B629E1AE8CC6FB80260026E2AA2A9
+:102670002629160168A0082B22000ABB0C65B25C53
+:1026800029629DC18C6492542A21200A806099108D
+:102690002C203CC7EF000F3E010B3EB1BD0FDB39D4
+:1026A0000BBB098F260DBD112DDC1C0D0D410EDD60
+:1026B000038E27B1DD0D0D410FEE0C0DBB0B2BBCB6
+:1026C0001C0BB7027EC71C2C21257BCB162D1AFCB8
+:1026D0000CBA0C0DA16000093E01073EB1780987D4
+:1026E000390B770A77EB026002062B212328212180
+:1026F000B1BB0B0B4F2B25237B8B29B0BD2D252385
+:10270000C855DA20DB30580FF0292102CC96C0E8FA
+:102710000E9E022E2502CC57DA20DB30DC4058100A
+:1027200070C020D10F2C20668931B1CC0C0C472C05
+:1027300024666EC6026001CF09FD5065D1C92F0A1B
+:10274000012830112922146480112A221B090C440B
+:1027500000C10400FB1A0BAA022A261B2D3010C050
+:10276000A0C0E088301BE88F94139514240A01253B
+:10277000203C2BB022088C14778704C0F10BFA3868
+:10278000C0F2C0840858010F5F010F4E3805354074
+:1027900007EE10C0F0084F3808FF100FEE0228DCDB
+:1027A000FEC0F0084F38842B0BA8100AFF102A2116
+:1027B000200F88020E880208440218E89E8F110834
+:1027C00044022821250A2A140828140488110A889A
+:1027D000022A210494F08E2004D41008EE1104EE95
+:1027E00002C04A04EE029EF1842A08AE110EDE02F7
+:1027F00094F40A54110E44020555100C1E4094F72F
+:1028000007EE100E5502085502C08195F68433C0BC
+:102810005094F3B1948E3295F898F99EF2C080C12D
+:10282000EC24261498FB9EF599FA853895FC843A99
+:1028300094FD8E3B9EFE883998FF853525F61084E1
+:1028400036851424F6118E3784132EF612C0E064F8
+:10285000B04989307797442B301088338C111FE8AA
+:10286000618D322FC614C0F42FC6158F2B2EC619BA
+:102870002DC61A28C61B04AD1109984006881108F8
+:10288000DD020DBB0218E856C1D00DBB0208FF02E5
+:102890002FC6162BC618280A0E2816022B200C88C5
+:1028A000121CE8460CB911A6992A9285ACBB2EB42D
+:1028B000CF0A880B289685C9718B268A2907BB0801
+:1028C0002B26060BAA0C0A0A482A2525655048C063
+:1028D00020D10F00DA2058109563FE3900DA20C0AD
+:1028E000B658109263FE2E00689738C020D10F00B2
+:1028F00000DA20DB7058104FC0C0C0D10ADA390AA4
+:10290000DC3865CDE463FE0D8A102B2104580F21BD
+:10291000C0E02E246663FE25DB402A2C7458091281
+:10292000D2A0D10FDA20580F2663FCF76C1004C038
+:1029300020D10F006C1004270A801CE83F1DE83FDF
+:102940001AE8170C2911AA992A2CFC2B92850DAA9A
+:10295000029CB19AB0C05113E83C28928516E83821
+:1029600014E839A62604240AB888289685234691B7
+:10297000A76625649FD10F006C100AD6302830104E
+:10298000292006288CF964829768980B2A9CF9659F
+:10299000A1B2022A02580F0A89371BE802C89164C3
+:1029A000520E2A21020A0C4C65C2558D3019E7FBE4
+:1029B00074D7052E212365E29A2F929E1AE7F76FAE
+:1029C000F8026002502AA22668A0082C22000ACC35
+:1029D0000C65C2412A929D64A23B9A151FE7F18DB6
+:1029E00067C1E6C8DD2B620618E7EF64B0052880F2
+:1029F000217B8B432B200C18E7E90CBC11A8CC29B8
+:102A0000C28679EB460FBE0A2EE2A368E0052F22AC
+:102A1000007EF9372CC2859C1864C22F2B212F878A
+:102A2000660B7B360B790C6F9D266ED2462C203DB3
+:102A30007BC740CE5560001E2A200CC1B28C2058A6
+:102A4000106F9A1864A2418D6763FFCFC0C063FF07
+:102A5000C5D7B063FFD300C0E06000022E60030E54
+:102A6000DB0C6EB20EDC700CEA11AA6A2AAC20589C
+:102A70000198D7A0DA20DB70C1C82D21205810158D
+:102A80008C268B279A160CBB0C7AB3348F1889636B
+:102A900099F3886298F28E659EF82D60108A189DD1
+:102AA0001768D729C0D09DA92C22182B22139CABC4
+:102AB0009BAA97A58E667E7302600097CF58600030
+:102AC0001FDA208B16580FDB65A13563FFBDC0816F
+:102AD000C0908F18C0A29AF999FB98FA97F563FFF6
+:102AE000D2DB30DA20DC40580F7EC051D6A0C0C007
+:102AF0002BA0102CA4039B172C1208022A02066B91
+:102B000002DF702D60038E179D149E100CDD11C026
+:102B1000E0AD6D2DDC205801178C148B16ACAC2C5D
+:102B200064038A268929ABAA0A990C9A2688660921
+:102B3000094829252507880C98662F2218A7FF2FFA
+:102B4000261863FE96DA20DB30DC40DD5058107D1D
+:102B5000D2A0D10FC0302C20668961B1CC0C0C47BB
+:102B60002C24666EC6026000CEC03009FD5065D0D0
+:102B7000C68E6764E069647066DB608C18DF70DAAB
+:102B8000202D60038E170CDD119E10AD6D2DDC2005
+:102B90001EE7A75800F8232618DA208B16DC402FF2
+:102BA0002213DD50B1FF2F2613580F1DD2A0D10FD5
+:102BB0000028203D084840658DE76F953EDA308D4E
+:102BC000B56D990C8CA80C8C14CACF7CD32D2AAC73
+:102BD00010C090292467090D4764DDC560008E0090
+:102BE0002C1208066B022D6C20077F028E17DA204C
+:102BF0009E101EE78E58007C63FF9A00C09163FF11
+:102C0000D1655080DA20DB60DC40580F35C020C031
+:102C1000F02FA403D10FDA20C0B6580FC463FFE031
+:102C2000006F950263FD70DA20DB30DC40DD50C4BC
+:102C3000E0580EB6D2A0D10F8A152B2104580E559C
+:102C4000232466286010981763FF2500DA20580FA8
+:102C5000B763FFACC858DB30DA20580E9B2A21023C
+:102C600065AF9DC09409A90229250263FF92DB305C
+:102C7000DC40DD50C0A32E0A802A2468DA20580EDA
+:102C8000A3D2A0D10FC020D10FDA202B200C580FD7
+:102C9000C063FF6C6C1004282006C062288CF865A5
+:102CA0008125C050C7DF2B221BC0E12A206B2921C0
+:102CB0002300A104B099292523B1AA00EC1A0BC462
+:102CC000010A0A442A246B04E4390DCC030CBB012D
+:102CD0002B261B64406929200C1BE7300C9A110B32
+:102CE000AA082FA2861BE72E6FF9026000B60B9B85
+:102CF0000A2BB2A368B0082C22000BCC0C65C0A430
+:102D00002BA2851CE75264B09B882B2F21040C88D2
+:102D10000298B08420C08508441108440294B1840C
+:102D20002A08FF1194B48E349FB79EB5C0401DE7AA
+:102D3000232EA2850D9D082EEC282EA68525D4CF06
+:102D400029210209094C68941A689820C9402A214F
+:102D50000265A00B2A221E2B221D7AB10265A079E2
+:102D6000C020D10F2C212365CFDE6000082E212149
+:102D70002D21237EDBD52B221E2F221D2525027B14
+:102D8000F901C0B064BFC413E7042CB00728B00039
+:102D9000DA2003880A28824CC0D10B8000DBA065B2
+:102DA000AFE763FFA62A2C74C0B02C0A02580D8D21
+:102DB0001CE7289CA08B2008BB1106BB029BA189A5
+:102DC0003499A263FF790000262468DA20DB30DC26
+:102DD00040DD50580FDCD2A0D10FDA202B200C5848
+:102DE0000F53C020D10F00006C1006073D14C080A7
+:102DF000DC30DB40DA20C047C02123BC3003283858
+:102E00000808427740022DDC016481571EE6E01974
+:102E1000E6E129E67E6DDA0500508800308CC0E0DE
+:102E2000C02025A03C14E6DFB6D38FC0C0D00F87EA
+:102E3000142440220F8940941077F704C081048243
+:102E400038C0F10B2810C044C02204540104FD38DE
+:102E500002520102FE3808DD10821C07EE100E6ED1
+:102E6000020EDD02242CFEC0E004FE380AEE100E35
+:102E700088020D88028DAB1EE6CF08D8020E8802AC
+:102E800098B0C0E80428100E5E0184A025A1250892
+:102E90004411084402052514045511043402C0816C
+:102EA0000E8E3994B18FAA84109FB475660A26A13C
+:102EB0001FC0F206261460000726A120C0F20626D5
+:102EC000140565020F770107873905E610077810AA
+:102ED00008660206550295B625A1040AE6110858AF
+:102EE0001108280208660296B7C0606440566490D4
+:102EF00053067E11C0F489C288C30B340B964598E3
+:102F000047994618E6B79F410459110E99021FE6EA
+:102F1000B5020E4708D8029F4098420E9902B43875
+:102F2000C1E00E990299442FA00C0CF91114E6A3EC
+:102F30001EE69BA4FFAE992E928526F4CF0E880B39
+:102F4000289685D10F2BA00C0CBE111CE69C1FE609
+:102F500093ACBBAFEE2DE28526B4CF0D3D0B2DE635
+:102F600085D10F00C08005283878480263FEA5632C
+:102F7000FE9900006C1006C0B0C0A6C0C06570F01D
+:102F80008830C0300887140888406580D3C0E0C00E
+:102F900091C0D4C08225203C0B3F109712831CC0E7
+:102FA000700858010D5D01089738C0800B983807EC
+:102FB0007710048810086802087702C0800D9838DE
+:102FC0002D3CFE0888100D9E388D2B0AEE1008EE61
+:102FD0000207EE020CB8100FDD02053B400EDD02C9
+:102FE0009D408920043D100899110D99022D21045E
+:102FF00009A90208DD119941872A05B9100D3D0282
+:103000000ABB110DBB0208770297442821258712BD
+:10301000082814048811071E4007EE100E99027547
+:10302000660926211F0626146000060026212006B8
+:1030300026140868029B47098802984629200CD26A
+:10304000C0C0800C9E111BE65D1FE654AB99AFEE2D
+:103050002DE2852894CF0DAD0B2DE685D10F000014
+:10306000001FE6502FF022C03065FF20C03163FF03
+:103070001BDD408E51CAE00E7836981008770CB2EE
+:10308000AAB1BB8F502DDC1098D99FD889538F528D
+:10309000991199DB9FDA7E830AB1CC255C10C9783F
+:1030A00063FFCF0088108D1108E70C9751AD8DD7C5
+:1030B000F078DB01B1F79D5397528830C030088714
+:1030C00014088840648EC565BFA163FF93000000AB
+:1030D0006C1004D720B03A8820C0308221CAA17475
+:1030E0002B1F2972046D080FC981C9928575B133F0
+:1030F000A2527A3B0C742B0963FFE90000649FEB3A
+:10310000D10FD240D10F00006C1008D630C070959E
+:1031100015DA408E3914E6239A1464E0026451F8FB
+:103120002920062A9CF865A25B2A21020A0B4C651D
+:10313000B21B2C320015E61974C7052D212365D367
+:10314000202E529E1AE6156FE8026002172AA22668
+:1031500068A0082B22000ABB0C65B2082E529D1DE8
+:10316000E61064E1FF8B3864B2299E16C8BC8D69F5
+:103170001EE60D64D0052EE0217BEB492E200C18B5
+:10318000E6070CEF11A8FF29F286C186798B4A1752
+:10319000E60407E70A2772A3687004882077893954
+:1031A00025F28564529E27212E07B73607B90C6F8A
+:1031B0009D01D7B089696E924228203D7B873C8A69
+:1031C00015CDAF600018C1B28C202A200C580E8B90
+:1031D000D5A064A2A88B6863FFCBC05063FFC3C0B7
+:1031E000E06000022E60030E9B0C6EB20EDC700CD1
+:1031F000EA11AA6A2AAC285BFFB6D7A0DA20DB70F6
+:10320000C1C42D211F580E338C268B27D4A00CBB94
+:103210000C7AB3258A63C0909A5388629958985261
+:103220008F659F598E679E5B8D6697559D5A8B68FB
+:103230007B7B748B15CEB360000DDA20DB40580D1C
+:10324000FD65A10963FFCC00DA20DB308C14580D3A
+:10325000A4D6A0C0C0C0D19D152CA403DA20DB6089
+:10326000DF70DC50C0E02560039E101EE5E60C5DBB
+:1032700011AD6D2DDC285BFF3F8E66A5A88F6728FA
+:103280006403AF7F77FB01B1EE9E669F678D268C4E
+:1032900029A4DD0DCC0C9D268B680C0C482C252513
+:1032A00007BB0C9B6863FEC32C20668961B1CC0C04
+:1032B0000C472C24666EC6026000B409FD5065D030
+:1032C000AECBBB8E69CBE7DB60DC50DF70DA201E53
+:1032D000E5E12D6003C08098100CDD11AD6D2DDC93
+:1032E000285BFF248B15C84F8A268929A4AA9A2611
+:1032F0000A990C09094829252565B13BC020D10F41
+:10330000DB602D6C28DF70DA20C0C01EE5D29C1077
+:10331000DC505BFEB563FFCB002D203D0D4D4065BD
+:10332000DDFD6FE522DA308F456DE90C8EAA0E8E39
+:1033300014C9E37EF3112AAC10C090292467090F49
+:103340004764FDDB60014100C09163FFED0088151B
+:1033500065814CDA20DB608C14580D61C020C09070
+:1033600029A403D10FDA20C0B6580DF063FFDE00A8
+:103370008A162B2104580C87C0A02A24668B686308
+:10338000FF3E0000002B9CF965B0C5DA20580C8C7C
+:1033900063FD95002B200C0CBA11A5AA2FA286C1A3
+:1033A000C27FC3026000FC0DB90A2992A36890078E
+:1033B0008C2009CC0C65C0EB26A2856460E52C202E
+:1033C000668931B1CC0C0C472C24666FC60270960E
+:1033D0000ADAE02B2104580C6F272466893077978E
+:1033E0004B18E57F1DE5808A328B33C0F42C210415
+:1033F000099E4006EE1104CC110ECC029F61C1E083
+:103400000ECC029D608F2B9A669B679C6497650823
+:10341000FF029F622F200C18E5690CFE11A5EE2D0E
+:10342000E285A8FF27F4CF2DDC202DE6858F1565DA
+:10343000F091C020D10F00002A2C748B1458064A3A
+:10344000D2A0D10F00DA20DBE0580DB863FEFE00F9
+:1034500000DA20DB308C148D15580E3AD2A0D10F33
+:1034600000008815C888DA20DB30580C972A210222
+:1034700065AEDAC09409A90229250263FECFDA20DD
+:103480002B200C580DC363FEC4272468DA20DB30E0
+:103490002C12042D12052E0A80580C9C63FC80000F
+:1034A000C020D10FDA20580DA18A15CDA1DA200352
+:1034B0003B022C1204580D0A27A403C020D10F0090
+:1034C000C020D10F2A2C748B14580627D2A0D10FFC
+:1034D0006C100E282102941008084C65835E1FE5CD
+:1034E0002F29F29E6F98026003621DE52B29D226D8
+:1034F0006890082A220009AA0C65A3502CF29D644A
+:10350000C34A2B200C0CB611AF66286286C1EC783A
+:10351000E30260034219E52209B90A2992A36890DF
+:10352000078A2009AA0C65A32E246285644328C05B
+:10353000E12A3109C07027246689359A12992A88B0
+:10354000369913982B89379814992C88389915082F
+:1035500058149816982D89392A25042E251D2925B9
+:103560001C283028C09228243C2A30290808479873
+:10357000170989012A243D2A311599180A09410998
+:10358000A90C299CEC29251F7E87192D2A000DA046
+:103590006000083E010A3EB1AD08DA390EAA110AF0
+:1035A000990C29251F27211F18E52C078160010888
+:1035B0003E000D3EB18A0DA8392D9CFC2D2520C161
+:1035C0009009883608DD1C08771C893D8A3C2E2628
+:1035D000132E26142E26152E246B2925222A25216A
+:1035E000282014C0A027252E2D252F0808432D2183
+:1035F0001C282414C07027252427252527252C279F
+:10360000261827261B2724672724682932112725F7
+:103610002399196ED2156D080AB1AA00A10400E918
+:103620001A7D9B0563FFEE00000089191DE4FDC0B3
+:10363000E0C0729B1D8813951B9F1F9C1E961C1C2F
+:10364000E50826203DC0F006054008DB14076601AA
+:103650000D8810C071057E38067F3885120BFF106B
+:1036600016E4E60AEE1096400FEE020D5511B0AFCB
+:1036700009FF110FEE021FE4F90855020FEE02C018
+:10368000F49F418A209F4996489C4B9B4E9D439EA8
+:10369000468D161EE4DA8B15C7CF9C4D9C4C9C457D
+:1036A0009C440BD8140EAE020DBB109E4A9E4208DD
+:1036B0005502954F0D181415E4CD0D88110588029B
+:1036C000984718E4E885262E46122E461A2E4622E2
+:1036D0002646102646182646202F46112F46192F1B
+:1036E00046212846242846262C46142C461595119A
+:1036F0008C1718E4DD0505488F1805551109064893
+:1037000028461389140E66110655020F7F390C3EA8
+:103710004002EE1017E4D60D99110C26400F6611E9
+:103720000B99020C0C408B1D01CC1006FF022746A2
+:103730001B294616C07029311616E4CD0ECC0205A1
+:10374000FF021EE49C15E4CB2F461726461CC0F052
+:10375000861C2F461D2F461F2F46272546230ECC9D
+:1037600002851B2C461E1EE4C41CE48E8F1F8CC7D2
+:103770002E4625ADCC28200629246A2431179C2DFD
+:103780002425238C1ECC81272407C0D77F97188E31
+:10379000110928419E2964808E644098C098094987
+:1037A000362D240660000B00644075C09809493628
+:1037B0002D240601C4042D0AA02E210428628508A8
+:1037C000EE11AD88286685863F843E2D321006486E
+:1037D0001898C300C40406461818E47804C45300BB
+:1037E000661106DD02A8B82784CF9DC409064E964F
+:1037F000C51DE4A305A61106440216E4A09DC0065B
+:10380000440294C2C04304EE029EC114E46326F253
+:103810009D2744A2266C1826F69D655042C020D1F3
+:103820000FC09063FF890000654F70C098C0E82EFC
+:10383000240663FF7D2D2406C09063FF75CC57DA04
+:1038400020DB308C10580C26C020D10F00DA20C0AD
+:10385000B6580CB663FFE500DA20580CB463FFDC01
+:103860002A2C748B10580540D2A0D10F6C1006285A
+:1038700020068A336F8202600161C05013E4472939
+:10388000210216E446699204252502D9502C201500
+:103890009A2814E4448F2627200B0AFE0C0477098B
+:1038A0002B711C64E1398E428D436FBC0260016F45
+:1038B00000E104B0C800881A08A80808D8029827B0
+:1038C0002B200668B32ECE972B221E2C221D011111
+:1038D000027BC901C0B064B0172CB00728B000DA71
+:1038E0002003880A28824CC0D10B8000DBA065AF82
+:1038F000E7C020D10F2D206464DFCA8B29C0F10BF3
+:10390000AB0C66BFC02B200C0CBC11A6CC28C28609
+:103910002E0A0878EB611EE4220EBE0A2EE2A3688E
+:10392000E0052822007E894F29C2851EE42E64907E
+:10393000461FE43C9E90C084989128200A95930FDE
+:10394000880298928E200FEE029E942F20078826E0
+:103950002F950A98969A972E200625240768E34308
+:103960002921021AE4162DC285AABA2DDC202DC603
+:103970008525A4CF63FF4E002B2065CBBDC0C22C94
+:103980002465C9F605E4310002002E62821FE41EA0
+:103990002D41020FEE022E66820DE43129210263D1
+:1039A000FF23000064DFB889422820160091040D2F
+:1039B000880C00881AA8A8982963FFA38C202D32B0
+:1039C00021B1CC9CD02B32212A3223B4BB2B3621FF
+:1039D0007BA9A92D32222D362163FFA0C020D10F53
+:1039E0009F27252415ACB828751C2B2006C0C12E96
+:1039F000BCFE64E0AB68B7772DBCFD65DEC72D204B
+:103A000064C0F064D0868E290EAE0C66E089C0F1E9
+:103A100028205A288CFE08CF3865FEE863FF58003E
+:103A200000E0049310C0810AF30C038339C78F08A8
+:103A3000D80308A80108F80C080819A83303C80C13
+:103A4000A8B828751C030B472B24158310CBB7008F
+:103A5000E104B0BC00CC1AACAC0CDC029C27659E27
+:103A60005EC0B20B990209094F29250263FE50007E
+:103A70002D206A0D2D4165DF7EDA20C0B0580C7212
+:103A800064AF18C0F163FEEF9F2763FFD02E221FA3
+:103A900065EE3263FF79000028221F658E2763FFE1
+:103AA0006E252406252502C09063FE196C1006655C
+:103AB00071332B4C18C0C7293C18C0A1C08009A87D
+:103AC000380808426481101CE3B11AE3B22AC67EAA
+:103AD0002A5CFDD30F6DAA0500B08800908C884049
+:103AE000C0A00889471FE3DB090B47084C50080DAD
+:103AF0005304DD10B4CC04CC100D5D029D310CBB21
+:103B0000029B3088438E2098350FEE029E328D2620
+:103B1000D850A6DD9D268E40C0900E5E5064E09782
+:103B20001CE3C11EE3B0038B0BC0F49FB19EB02D0C
+:103B3000200A99B30CDD029DB28F200CFF029FB4C6
+:103B40008E262D20079EB68C282DB50A9CB72924D9
+:103B5000072F20062B206469F339CBB61DE392238F
+:103B600020168DD20B330C00D10400331AA3C3B43A
+:103B70008D932922200C13E3911FE3880C2E11AFA3
+:103B8000EEA3222924CF2FE285D2A00FDD0B2DE654
+:103B900085D10F00B48C2E200C0CEB111FE3881D77
+:103BA000E37FAFEEADBB22B28529E4CF02C20B2288
+:103BB000B685D2A0D10F00002E200C0CEB111FE314
+:103BC0007F1CE376AFEEACBB22B28529E4CF028244
+:103BD0000B22B685D2A0D10FC0D00BAD387DC80264
+:103BE00063FEEC63FEE08E40272C747BEE12DA70ED
+:103BF000C0B32C3C18DD50580A77C090884063FE53
+:103C0000E3066E02022A02033B02DC40DD5058004C
+:103C1000049A10DB50DA70580454881063FEF600E2
+:103C20006C10082E3C18C0A092161FE3688C40AFA1
+:103C30002F0C8C47C02304CB0BDDB07FB3022DBD0E
+:103C4000F8D9D0C0B075C30260008D9F146D084FC5
+:103C50008D900D6D36ADAA0D660C0EB70B0EBF0A1A
+:103C60009DF0B877B89FD8F000808800708C9711CD
+:103C700087909810971568B12AB22277D32D889132
+:103C8000C0D0CB8F9890279C10007088971200F0BE
+:103C90008C9F139D916460A0C08108BB0375CB38D5
+:103CA00063FFA900B1222EEC1863FFCE85920D7739
+:103CB0000C86939790A6D67D6B01B15595929693FD
+:103CC0008942600017B3CC299C188814DD90789342
+:103CD000022D9DF8D9D063FFBB8942DA9085160C7E
+:103CE0000D472D44021BE36792319B3086437A9146
+:103CF000261BE3581EE36589500E660196350B9925
+:103D000002993288420A880C98428756A7A797568C
+:103D10008F44AFAF9F44D10F1BE34F895096350BB3
+:103D20009902993288420A880C98428756A7A79729
+:103D3000568F44AFAF9F44D10F894263FF9E00006E
+:103D40006C10061FE3529310D6308830C091086380
+:103D5000510808470598389811282102293CFD0888
+:103D6000084C6581576591542A62030A2B5065B14E
+:103D70007E0A68142E0AFF7CA60A2C205ACCC42D79
+:103D80000A022D245A78E0026002088A288926183F
+:103D9000E3400A990C6592032E200B1CE33F08EECA
+:103DA0000B2EED012DE0322EE03308DD110EDD0289
+:103DB0001EE339AFDD0EDD010DCC372D200C8960FF
+:103DC000C1E07B96231AE2F78B622AA0219C127B2A
+:103DD000A316DAD0C1B00B4B37B4BB8C20580B877D
+:103DE0008C12DBA0CEAB6001BF0E4E371BE2EC0C99
+:103DF000DA11ABAA28A286B8EE78EB351EE2E90EFE
+:103E0000DE0A2EE2A368E00488207E89242BA285A6
+:103E100064B0A28762DE700C79369B1388268D27EA
+:103E2000097A0C08DD0C6FAD0E77D3107E7B6960CC
+:103E3000001FC0B063FFD800D79063FFEB9C12DA7D
+:103E400020DB70580AFC8B138C1265A06F8E627E8B
+:103E50007B469C129B13CC5FDA208B10044C0258DB
+:103E60000AA0D6A08B13250A01DE70DA20DC60DD03
+:103E7000405BFF6B8C12D9A02D200CC0E01BE2C769
+:103E800017E2CF0CDA11A7D7ABAA2BA2852E74CFDD
+:103E90000B990B29A68563FF24DA20DC60DD40DE68
+:103EA000708911282007DF50A9882824075BFEFFAE
+:103EB000D2A0D10F0000DBD0DA20580B1C6550F3E4
+:103EC0002A20140A3A4065A0EEDB60DC40DD30DADF
+:103ED0002058098E1FE2EED6A064A0D784A183A04B
+:103EE0000404470305479511036351C05163FE68FD
+:103EF0002C200628CCFD6480A868C704C093292420
+:103F000006C0C18E6419E2A79E269E299E2889922A
+:103F10009E2700910400CC1A009004B0C88D65085B
+:103F2000EE01AECC0D0E5E01EE11AECCB0CC2E0A81
+:103F3000FE0C0C190ECC36C0E20C0C470ECC372C04
+:103F40002416C0B02B24072C20061BE29F0A0E4526
+:103F50000D084228240B2E240AB48929240C7DB88C
+:103F60005A2920160A5D52B09E0EDD362D24642B90
+:103F7000CCFD65BDFB0D0C4764CDF51DE28A88289C
+:103F80008DD20C9B0C00D10400BB1AAB889829631E
+:103F9000FDDE00001CE2B963FE2000001CE2AF63FE
+:103FA000FE188D6563FFA20000DA202B200C580A52
+:103FB000F8645F0BC020D10FC020D10FC093C0E3C5
+:103FC0002E241663FF9D00006C1004C06017E2727F
+:103FD0001DE275C3812931012A300829240A78A1FC
+:103FE00008C3B27BA172D260D10FC0C16550512607
+:103FF00025022AD0202F200B290AFB2B20142E204B
+:104000001526241509BB010DFF0928F11C2B2414CA
+:10401000A8EE2EF51C64A0B52B221E28221D01112E
+:10402000027B8901DB6064B0172CB00728B000DA8E
+:104030002007880A28824CC0D10B8000DBA065AF26
+:10404000E7DB30DC40DD50DA205800D829210209B6
+:104050000B4CCAB2D2A0D10F00CC5A2C30087BC175
+:10406000372ED02064E02D022A02033B02DC40DD23
+:10407000505800CED2A0D10F2B2014B0BB2B24144B
+:104080000B0F4164F0827CB7CAC0C10C9C022C2586
+:1040900002D2A0D10FC020D10F2E200669E2C12F7D
+:1040A00021020F0F4C69F1B82624062625022B2287
+:1040B0001E28221D2A200B2920150DAA092CA11C1F
+:1040C000262415AC9929A51C7B814A600049B0BB08
+:1040D0002B24140B0D41CBD67CB7022C25022B22AE
+:1040E0001E2E221D7BE9022B0A0064B0172CB0079C
+:1040F00028B000DA2007880A28824CC0D10B800043
+:10410000DBA065AFE7C020D10F262406D2A0D10FD7
+:1041100026240663FFC7DB601DE22364BF422CB088
+:104120000728B000DA2007880A28824CC0D10B800B
+:1041300000DBA065AFE71DE21B63FF246C100428C1
+:104140002006C0646F8564CA5B2920147D9726DA37
+:1041500020DB30DC40055D02580019292102090AE4
+:104160004CC8A3C020D10F00C0B10B9B022B25026D
+:10417000C020D10F0000022A02033B022C0A015882
+:1041800000C9C9AADA20DB30DC405809D529A011C2
+:10419000D3A07E97082C0AFD0C9C012CA411C051C1
+:1041A0002D201406DD022D241463FFA2DA20DB305B
+:1041B000DC40DD50C0E0580955D2A0D10F0000000E
+:1041C0006C100616E1F61CE1F665513BC0E117E103
+:1041D000F22821028B2008084C65807C29320009D6
+:1041E00069516993732A629E6EA8482A722668A054
+:1041F000027AB93F2A629DB44FCBA72B200C0CBD8D
+:104200001106DD0828D28678FB150CBF0A2FF2A311
+:1042100068F00488207F89072DD285D30F65D06090
+:104220002A210419E21ED30F7A9B1DDA2058085365
+:10423000600025002C21041BE2197CBB14DA20C08D
+:10424000B658084EC9546000EFDA20580A386000AA
+:104250000700DA20C0B6580A356550DCDC40DB3098
+:104260008D30DA200D6D515808A9D3A064A0C91C67
+:10427000E1CCC05184A18EA00404470E0E4763FF19
+:104280004F2B2104C08C8931C070DF7009F95009AF
+:104290008F386EB8172C2066AECC0C0C472C2466D9
+:1042A0007CFB099D105808BB8D1027246694D11EF5
+:1042B000E1D2B8DC9ED0655056C0D7B83AC0B1C084
+:1042C000F00CBF380F0F42CBF119E1B018E1B22862
+:1042D000967EB04BD30F6DBA0500A08800C08C2C21
+:1042E000200CC0201DE1B60CCF11A6FF2EF285AD2B
+:1042F000CC27C4CF0E4E0B2EF685D10FC0800AB846
+:104300003878D0CD63FFC1008E300E0E4763FEBDFE
+:104310002A2C742B0A01044D025808AE2F200C12CF
+:10432000E1A70CF911A699289285A2FF27F4CFD214
+:10433000A008480B289685D10FC020D10F0000009F
+:104340006C1004C060CB55DB30DC40055D02022AF6
+:10435000025BFF9B29210209084CC882D2A0D10F21
+:104360002B2014B0BB2B24140B0C41CBC57DB7EB19
+:10437000C0C10C9C022C2502D2A0D10F0000022A41
+:1043800002033B02066C02C0D0C7F72E201428316E
+:104390000126250228240A0FEE012E241458010CB0
+:1043A00063FFA300262406D2A0D10F006C100628BC
+:1043B0002102D62008084C6580992B200C12E17749
+:1043C0000CB811A2882A8286B5497A9302600093BC
+:1043D00019E17409B90A2992A36890082A620009B0
+:1043E000AA0C65A07E2882851CE17F6480759C8074
+:1043F000B887B14B9B819B10655072C0A7D97028BC
+:104400000A01C0D0078D380D0D42CBDB1FE1601EC5
+:10441000E1612EF67ED830D30F6D4A05008088000A
+:10442000908CC0802F30082F740029600C1AE16333
+:104430000C9D11A2DD2CD285C020AA992294CF0C0C
+:10444000BC0B2CD685D280D10FC0E0038E387EA065
+:10445000C363FFB7CC582A6C74DB30DC405807E1EB
+:10446000C020D10FDA605809B163FFE70000DD40DA
+:1044700085102A6C74C0B0DC705808562F30082F95
+:10448000740028600CC0F00C8B11A2BB29B28512FD
+:10449000E14B09590BA2822F24CF29B685D2A0D196
+:1044A0000F0000006C1004292014282006B199295F
+:1044B0002414688124C0AF2C0A012B21022C24066D
+:1044C0007BA004C0D02D2502022A02033B02044C2B
+:1044D00002C0D05800BFD2A0D10FC020D10F000021
+:1044E0006C1004293101C2B429240A2A3011C28374
+:1044F00078A16C7BA1696450472C2006C0686FC509
+:1045000062CA572D20147CD722DA20DB30DC40DD54
+:10451000505BFFA6292102090E4CC8E2C020D10F32
+:10452000C0F10F9F022F2502C020D10FDA20DB300F
+:10453000C0C05BFFDC28201406880228241463FF17
+:10454000C72920151BE1182A200BC0C09C240BAAE8
+:10455000092BA11C2C2415AB9929A51C63FF9900DC
+:10456000C020D10FDA20DB30DC40DD50C0E058083D
+:1045700067D2A0D10F0000006C1004CB5513E113DB
+:1045800025221F0D461106550CA32326221E252683
+:104590001F06440B24261E734B1DC852D240D10F58
+:1045A000280A80C04024261FA82828261E28261D49
+:1045B000D240D10FC020D10F244DF824261E63FF16
+:1045C000D80000006C1004282006D6206E850260FA
+:1045D00000DE17E0F21DE0F919E0F2C0C1C0202AA8
+:1045E0008CFC64A1322B6102B44E0B0B4C65B0A85D
+:1045F0002B600C2A62000CB8110788082F828609EC
+:10460000B90A7FE30260009F2992A368900509AA76
+:104610000C65A09328828564808DB8891BE0F7948F
+:10462000819B8065514DC0B7B838C0A1C0E009AECC
+:10463000380E0E4264E0481AE0D51FE0D62FA67E61
+:10464000B04A6DAA0500808800908CC0A02E600C36
+:104650000CE811A7882F8285ADEE0F4F0B2F8685B2
+:104660002B600622E4CF68B12A296015C0B2C99A2E
+:10467000D2A02D61022B64060CDD022D6502D10F44
+:10468000C0E008AE387EB0B763FFAB00226406D24C
+:10469000A0D10F00D2A0D10F00CC57DA60DB30DC04
+:1046A0004058088FC020D10FDA6058092063FFE816
+:1046B0000028221E29221D789902280A00C176C1ED
+:1046C000C1C1D21BE0C2C124AB6B6480437891406E
+:1046D0002A80000CAF0C64F0AE0DAE0C64E0A802B2
+:1046E000AF0C64F0A207AE0C64E09C2FACE864F061
+:1046F000962EACE764E0902FACE664F08A2A80073F
+:1047000008A80B088A027B83022A8DF8D8A065AF1F
+:10471000BBC09060007300002B600C0CB811A78820
+:104720002E82866EE87909BA0A2AA2A368A0048EAE
+:10473000607AE96B2A828564A0651FE0AAC0E32E37
+:1047400064069EA19FA01FE0D62E600A92A30FEEE2
+:10475000029EA28E600FEE029EA42F60147AFF4785
+:1047600022A4172F8285ADBE22E4CF2FFC182F86FE
+:104770008563FE702A6C74C0B1DC90DD40580795EB
+:104780001DE08FC0C163FEC4D9A0DA60DB30DC401D
+:10479000DD50C2F0C1E009FE395807DCD2A0D10FCC
+:1047A000DA605808E263FEF02CA4172982850DBE5A
+:1047B0000822E4CF299C1829868564500C2A6C7441
+:1047C000044B02580169D2A0D10FC020D10F0000C4
+:1047D0006C10062B221E28221D93107B8901C0B06D
+:1047E000C0C9C03BC1F20406401DE078C0E2C074FD
+:1047F0000747010E4E01AD2D9E11C0402E0A1464D4
+:10480000B06E6D084428221D7B81652AB0007EA110
+:104810003B7FA1477B51207CA14968A91768AA1456
+:1048200073A111C09F79A10CC18B78A107C1AE29DA
+:104830000A1E29B4007CA12B2AB0070BAB0BDAB0FF
+:104840007DB3022ABDF8DBA0CAA563FFB428B0106F
+:1048500089116987BB649FB863FFDC00647FB46320
+:10486000FFD50000646FD0C041C1AE2AB40063FF21
+:10487000C62B2102CEBE2A221D2B221E7AB12A8CE3
+:10488000107CB1217AB901C0B0C9B913E043DA2074
+:1048900028B0002CB00703880A28824CC0D10B80B6
+:1048A00000DBA065AFE7D240D10F8910659FD463CC
+:1048B000FFF300006C1008C0706451718F30292123
+:1048C000020F0F4716E036090C4C65C08F8D300D76
+:1048D0006E5168E30260008428629E1AE02F6E88A1
+:1048E000522AA22668A0048B207AB9472A629DB07A
+:1048F0004ECBAF9A102B200C9E110CBC11A6CC29CC
+:10490000C286B748798B4117E02607B70A2772A3FA
+:1049100068700488207789302CC2859C12D7C065C6
+:10492000C0622C21041AE05D7CAB22DA2058069389
+:10493000600029002E21041DE0597EDB18DA20C01A
+:10494000B658068EC958600156C0C063FFCCDA2045
+:10495000580876600006DA20C0B658087465513FE2
+:10496000DC40DB308D30DA200D6D515806E8D3A0E5
+:1049700064A12CC05129210284A18FA00404470FF7
+:104980000F4763FF412B2104C08C8931C0A009F976
+:1049900050098A386EB81E2C2066AFCC0C0C472C00
+:1049A00024667CAB109E142A12005806FA8E14C09E
+:1049B000D02D24668D30C0921BE010C1F87FD60C3C
+:1049C00087129B702976012F7408277C106550B7D9
+:1049D000B83AC0D7DC70C051C080075838080842C8
+:1049E0006480791DDFEA19DFEB29D67E6A420AD39B
+:1049F0000F6DE90500A08800C08CC0A08830C0926F
+:104A00007F863807E80B2F84089B809981B4E82CB7
+:104A1000200CC0901DDFEA0CC311A633223285ADF5
+:104A2000CC02820B29C4CF223685D2A0D10F8A3086
+:104A3000C0F17EAE3229210263FE88002C200C8E4C
+:104A400011C0B01DDFDE0CCF11A6FF22F285ADCC68
+:104A50002BC4CF02EE0B2EF685D2A0D10FC0800A58
+:104A6000583878D08663FF7A9F13DB30DA20C0C1D4
+:104A7000DD705BFF572921028F132A9CFE65AE4330
+:104A8000272502C09063FE3B9E142A2C74C0B1DC23
+:104A900070DD405806D08E141BDFD8C1F863FF5B71
+:104AA000C020D10F6C100628210216DFBC08084C6C
+:104AB00065821529629E6F980260021C19DFB72972
+:104AC00092266890078A2009AA0C65A20B27629D8E
+:104AD000C0CC6472032B21048E31C0A0DDA00EFE79
+:104AE000500ECD386EB8112C20662CCC010C0C4722
+:104AF0002C24667CDB026001EAC0C12930081BDF80
+:104B0000A96490972F0AFFC0D3B09E64E0FD68921D
+:104B10000E6450832A2C74DB40580093D2A0D10F2E
+:104B20002B200C2721040CBC11A6CC29C286280AF4
+:104B3000087983026001B919DF9A09B90A2992A399
+:104B40006890082E220009EE0C65E1A42EC285644F
+:104B5000E19E26200713DFA36E7B0260019A17DF18
+:104B60009A1FDFA319DFD0C0D228200A93E09DE16D
+:104B7000A9690F880298E22F90802A9480B1FF07DC
+:104B8000FF029FE31EDF8E2FC285AEBE0FDF0B2F0D
+:104B9000C6852AE4CF655F7BC020D10F2F30102956
+:104BA00030112E301300993200ED3264F0EE2A30CD
+:104BB000141FDFBD00AA3278EF050F9E092DE47F98
+:104BC0001EDFBB66A0050F98092A8480B4A718DFF2
+:104BD000B8C76F009104AE9EDDE000AF1A00C31AA3
+:104BE0006EE1052DB2000DED0C1EDFB208D81C06DB
+:104BF0003303AE882A848B2EB02E27848C03EE01DB
+:104C00000FEE022EB42E58018F63FF0429310829BC
+:104C100025042830142E3109B0886480A32E240A7C
+:104C2000C0812E30162CB4232E240BB4EF2F240C6D
+:104C30008C378B36292504DEB0DFC00F8F390E8EFE
+:104C4000390FEE0264EEC9089F1101C4048D380CBF
+:104C5000B81800C4040CBE1800EE110EDD02C0E34B
+:104C60000EFF021EDF879F719E701EDF848F2098CB
+:104C7000739D7405FF110BCD53C18098750FDD0234
+:104C80000EDD029D722A24661EDF442F629D2AE4F7
+:104C9000A22FFC182F669D63FE760000002F3012B5
+:104CA0001BDF8600FA3278FF050B980B2A847F669B
+:104CB000D0050B9A0B2DA4802A301100AA3263FF75
+:104CC000442F240A9E2B63FF56CC57DA20DB30DCBE
+:104CD00040580703C020D10F00DA20C0B658079310
+:104CE00063FFE500DA7058062BC0A02A246663FE35
+:104CF00007DA2058078E63FFCFB16928200A862083
+:104D0000090947991129240798107F812693E027E4
+:104D1000E50A9AE388109DE119DF628D11096F029F
+:104D20009FE42DE416098802C0D398E22A24076381
+:104D3000FE5100001FDF2B08691188118D2B93E0B5
+:104D4000098802C09F98E50FDD020478119DE2C03A
+:104D5000F49FE1C0D409880298E463FFCE0000000C
+:104D60006C1004C020D10F006C100485210D381187
+:104D700014DF088622A42408660C962205330B93C0
+:104D800021743B13C862D230D10FC030BC299921A5
+:104D900099209322D230D10F233DF8932163FFE372
+:104DA0006C100AD620941817DEFDD930B83898193F
+:104DB0009914655252C0E1D2E02E61021DDEFA0E56
+:104DC0000E4C65E1638F308E190F6F512FFCFD651E
+:104DD000F1568EE129D0230E8F5077E66B8F181E87
+:104DE000DF37B0FF0FF4110F1F146590CE18DF34BA
+:104DF0008C60A8CCC0B119DEE828600B09CC0B0D83
+:104E0000880929811C28811A2A0A0009880C08BAF5
+:104E1000381BDF2A0CA90A2992947B9B0260008C24
+:104E20002B600C94160CBD11A7DD29D286B84879E9
+:104E300083026000D219DEDA09B80A2882A3981723
+:104E40006880026000A36000A51ADF1E84180AEEC5
+:104E500001CA981BDED18C192BB0008CC06EB31325
+:104E60001DDECE0C1C520DCC0B2DC295C0A17EDBDD
+:104E7000AE6000380C0C5360000900000018DF1011
+:104E80008C60A8CCC0B119DEC428600B09CC0B0D16
+:104E9000880929811C28811A2A0A0009880C08BA65
+:104EA000380CA90A2992947E930263FF72DA60C0DB
+:104EB000BA58071E64507460026600001ADEB78C90
+:104EC000192AA0008CC06EA31A18DEB30C1C52085D
+:104ED000CC0B18DEFA2BC295C0A178B30263FF3F5A
+:104EE00063FFC9000C0C5363FF0989607899182986
+:104EF000D285C9922B729E1DDEA86EB8242DD226B3
+:104F0000991369D00C60000EDA6058070860001829
+:104F1000000088607D890A9A1A29729D9C12991551
+:104F2000CF94DA60C0B65807016551F48D148C181F
+:104F3000DBD08DD0DA600D6D51580574D3A09A1472
+:104F400064A1DD82A085A1B8AF9F190505470202C3
+:104F5000479518C05163FE602B6104C08C8931C035
+:104F6000A009F950098A386EB81F2C6066A2CC0CD3
+:104F70000C472C64667CAB119F119E1B8A1558054B
+:104F8000858E1B8F11C0A02A64669F1164F0E18991
+:104F9000138819DEF06DE9172F810300908DAEFEA6
+:104FA0000080889F9200908C008088B89900908C37
+:104FB00065514E8A10851A8B301FDE8A881229604F
+:104FC0000708580A2C82942D61040ECC0C2C869470
+:104FD0006FDB3C1CDEB4AC9C29C0800B5D50A299F9
+:104FE00009094729C48065D0DA2E600CC0D01FDEC5
+:104FF000730CE811A788228285AFEE02420B2DE4E4
+:10500000CF228685D2A0D10F8E300E0E4763FDA62B
+:10501000A29C0C0C472C64077AB6CD8B602E600ADC
+:10502000280AFF08E80C64810E18DE9D831682139F
+:10503000B33902330B2C34162D350AC02392319F1D
+:1050400030C020923308B20208E80292349832C08D
+:10505000802B600C286407D2A01CDE580CBE11A760
+:10506000EE2DE285ACBB28B4CF0D9D0B2DE685D18E
+:105070000F8B1888138D30B88C0D8F470D4950B4A5
+:10508000990499100D0D5F04DD1009FF029F800D3A
+:10509000BB029B8165508D851AB83AC0F1C0800C67
+:1050A000F83808084264806B1BDE3919DE3A29B6ED
+:1050B0007E8D18B0DD6DDA0500A08800C08CC0A020
+:1050C00063FEF3001DDE4B28600A82138B16C0E0DE
+:1050D0002EC48002B20B0D8802B2BB99239F20C060
+:1050E000D298229D2122600C0C2D11A7DD28D2859B
+:1050F00008BB0B18DE322BD685A8222E24CFD2A0D7
+:10510000D10F9E1B851A2A6C748B185BFF178E1BA0
+:1051100063FEA300C087C0900AF93879809263FFCC
+:1051200086C020D10F9E1B2A6C74C0B18D18580503
+:10513000298E1B851A63FE7E886B8213891608BE32
+:10514000110ECE0202920B9E25B4991EDE259F20E1
+:105150000E88029822C0EF04D8110E88029824C04D
+:10516000E49E21C080D2A02B600C2864071CDE13B3
+:105170000CBE11A7EE2DE285ACBB28B4CF0D9D0B64
+:105180002DE685D10F0000006C1004C020D10F0067
+:105190006C10048633C071C030600001B13300313F
+:1051A0000400741A0462017460F1D10F6C100402DF
+:1051B0002A02033B025BFFF61DDDFB1BDE43C79F9C
+:1051C00088B009A903098A019AB02BD10279801B02
+:1051D0001CDDF3C0E00EE4310002002AC2821DDEB5
+:1051E0003B0DAA022AC6820BE431D10FC1F00FBFDA
+:1051F000020F0F4F2FD5020FE431D10F6C100412A4
+:10520000DDE91ADDE6C0C00CE43100020029A2820B
+:1052100018DE311BDE2F2621020B990108660129B9
+:10522000A68226250206E43114DE2C15DE27236A29
+:10523000902326128550242611252613222C40D196
+:105240000F0000006C100816DE252B0A642C1AB41F
+:1052500017DDD51DDDD118DE220F2E110D2A11B25A
+:10526000E90EEE11A8A80E9911ADAAA799A7EE9E76
+:10527000169911ACAA9A152C80FF2A80FE288D0160
+:1052800029800108AA112880000CAA0208881109A7
+:10529000880208AA1CB88828160058085D297116CB
+:1052A0009A122916038A158B122AA0800BAA288B22
+:1052B00010580857D4708C168B1315DE0A0BAB28C8
+:1052C000235C419B142BC6282C308072C9158C148A
+:1052D0002A50C02B3A200CAA2858084DC0D10ADD0C
+:1052E000372D4540B444B255B2337639DAB2778FB0
+:1052F000118E168815B4EEB18898159E167FE9A414
+:10530000D10F00006C1004C021D10F006C1006C03A
+:10531000701ADDA21EDDAD1DDDB31CDDB51BDD9EEB
+:1053200013DDE1220A0818DD9F14DDEF28802E240A
+:1053300040002816006D2A70A349289080C0F164AF
+:1053400080598510004104C06100661A06550105A8
+:10535000F5390C56110A66082F62966EF74D0B5FF1
+:105360000A2FF22468F00812DDD102420872F93BDC
+:105370002362950C4202CB349232C0F29D309F31B1
+:105380000E8F029F33236295AB522F0A002F948019
+:105390002F24A0233C1023669513DDC2B17712DDC4
+:1053A000D2B144040442242400D10F00D10FD10F04
+:1053B0006C10041ADD792AA00058021B5BFFD3028F
+:1053C0002A02033B025BFFCF1BDD77C0C429B10279
+:1053D000C8AC0C9C020C0C4F2CB5020CE431D10F64
+:1053E0001EDD6FC08008E4310002002DE2821FDD67
+:1053F000800FDD022DE68209E431D10F6C10041517
+:10540000DD6716DD68C02002E4310002002452820C
+:10541000226102734F0602E431C020D10F18DDB4BF
+:1054200019DDB308280109490129568228650208B7
+:10543000E43113DDA9226C7023661DD10F0000003A
+:105440006C1004292006289CF96480A02A9CFD6524
+:10545000A0968A288D262F0A087AD9042B221FC8E5
+:10546000BD2C206464C0812E22090EAE0C66E0784B
+:105470002B200C1EDD4A0CBC11AECC28C28619DDD7
+:105480004878F3026000A909B90A2992A368900834
+:105490002E220009EE0C65E09729C2851FDD5264BB
+:1054A000908E9F90C0E41FDD5F9E9128200AC0E08F
+:1054B0009E930F8802989288200F880298942F203C
+:1054C000079A979D962F950A2E24072820062920B3
+:1054D0006468832F28C28512DD39288C20A2B22E61
+:1054E00024CF28C685C020D10FC020D10F2A206A22
+:1054F0000A2A4165AF55DA20C0B05805D364AFE839
+:10550000C021D10F649FCC1FDD272D20168FF209FB
+:10551000DD0C00F10400DD1AADAD9D2928C2851215
+:10552000DD27288C20A2B22E24CF28C685C020D10A
+:105530000FC021D10F0000006C1004260A001BDDF3
+:105540006D15DD1828206517DD15288CFE64809404
+:105550000C4D11ADBD2CD2F52BD2F42A51027CB1E9
+:10556000422A5102B4BB2ED2F72BD6F47BE9052B8D
+:10557000D2F62BD6F47CB92B29D2F629D6F529D62A
+:10558000F406E4310002002F7282C79F004104C07C
+:105590008100881A09880308FF012F76820AE43106
+:1055A000600000002624652BD2F48E5A2CD2F5B070
+:1055B000EE9E5A7BCB1629D2F62FD2F70CB80C09E7
+:1055C000FF0C08FF0C0F2F14C8F960002F0BCD0C37
+:1055D0000D2D14CED6C0E20EAE020E0E4F2E550289
+:1055E0000EE431D10FDB30DA205BFF951BDD426426
+:1055F000AF5D2A51020C4D11ADBD63FFA906E43128
+:105600000002002E72821FDD000FEE022E76820A4B
+:10561000E431D10F6C100416DCE115DCE2C030037C
+:10562000E43100020024628274472118DD33875A76
+:10563000084801286682CD7319DD310C2A11AA9918
+:105640002292832992847291038220CC292B5102C9
+:105650000BE431C020D10F001FDD2A2E51020FEEC6
+:10566000012E55020EE431B02DB17C9C5A225C60B3
+:1056700008DD112D5619D10F6C100A1ADCC71DDC7C
+:10568000C923A00019DD206F33791CDD07C0281560
+:10569000DD1F1EDD1D2B1C10D4B083E0005086954D
+:1056A0001000408A94186D2A4F0F35110C340924CC
+:1056B00040800A560A2862940D55092F51400F4424
+:1056C000110B440A08970C0F77368F400F7736225C
+:1056D000514107FF0C9F40A8772F62952766940FD2
+:1056E000980C0288368741078836B13308770CAFAB
+:1056F0008F2F66959741030342B13808084298E01E
+:10570000D10F00001CDD0314DD03BFC52442B564C6
+:105710003055C091C0D016DD000488432BC000C0B6
+:10572000406D393E00410400971A7780162FA295EC
+:105730008E50AFEE2EED2006EE369E502DA69560D3
+:10574000001A000077B00983509D5023A695600091
+:105750000223A295223D2006223622A695B144B40A
+:1057600055B8AA28C400D10F04884328C400D10F1B
+:105770006C100415DCEA13DCEAC04004E4310002DA
+:10578000008850CB815BFFBC1CDCE70C2D11ADCC3D
+:105790002BC2822AC28394507BAB142EC28429C2AE
+:1057A000850ABD0C0E990C0D990C09291460000591
+:1057B0000BA90C092914993015DC7B2A51020AE443
+:1057C000312A2CFC5800492B32001EDC742BBCFF04
+:1057D0002B3600CCB5C8A3D2A0D10F00D2A004E4D0
+:1057E000310002002DE2822C51022FBAFF0FDD01A1
+:1057F0002DE6820CE431D10F6C1004D10F000000B3
+:105800006C1004C020D10F006C100413DCC7C0D191
+:1058100003230923318DC0A06F34026000891BDC93
+:1058200061C7CF18DCC00C2911A988268283258284
+:105830008219DC5A7651442752002E8285255C0459
+:1058400025868275E9052582842586827659542627
+:105850008284D5602686822686830AE4310002008F
+:105860002392822FB10200210400D41A0C440304B5
+:1058700033012396820FE43160000200D7A07659ED
+:10588000220AE4310002002E928200210428B10293
+:1058900000DF1A0CFF030FEE012E968208E431D2CE
+:1058A00070D10F00D270D10FC020D10F6C1004DB6B
+:1058B00030862015DC39280A00282502DA2028B095
+:1058C000002CB00705880A28824C2D0A010B8000A5
+:1058D000DBA065AFE61ADC320A4A0A29A2A3C7BFD9
+:1058E000769101D10F2BA6A3D10F00006C1004C03C
+:1058F000D1C7CF1BDC2CC0A018DC280C2911A9882B
+:105900008785858419DC2677517986508E87B45532
+:10591000958475E9038586958477596C8F869F8574
+:105920009F840AE431000200239282B42E00E10435
+:105930002FB10200D41A0C44030433012396820FC2
+:10594000E4310AE43100020023928200D41A0C44AC
+:10595000030433012396820FE431D260D10F00009B
+:105960000AE431000200239282B42800810422B1AB
+:105970000200D41A0C440304330123968202E4315A
+:10598000D2A0D10FD6A07751D6D260D10F0000009F
+:105990006C1004270A801CDC281DDC281ADC000C93
+:1059A0002911AA992A2CFC2B92850DAA029CB19A46
+:1059B000B0C05113DC2528928516DC2114DC22A608
+:1059C0002604240AB888289685234691A76625646C
+:1059D0009FD10F006C100419DC550C2A11A9A9895C
+:1059E00090C484798B761BDC45ABAC2AC2832CC275
+:1059F000847AC1688AA02BBC30D3A064A05E0B2B34
+:105A00000A2CB2A319DC0F68C0071DDC49D30F7D37
+:105A1000C94AA929299D0129901F68913270A603BE
+:105A2000D3A0CA9E689210C7AF2AB6A32A2CFC5BEB
+:105A3000FFAFD230D10F000013DBEF03A3018C3195
+:105A40001DDBE00C8C140DCC012CB6A363FFDC0035
+:105A5000C020D10FDA205BFFCEC020D10FC020D1F3
+:105A60000F0000006C1004DB30C0D019DBCBDA2053
+:105A700028300022300708481209880A28824CDCA6
+:105A8000200B80001BDBC60C4A11ABAA29A284099B
+:105A9000290B29A684D10F006C1004C04118DBBF6C
+:105AA00017DBC10C2611A727277030A86625628650
+:105AB000007104A35500441A75414822628415DB25
+:105AC000E202320BC922882117DBBE088414074486
+:105AD00001754905C834C020D10FD10F1DDC15C098
+:105AE000B28E201FDBAD0E0E43AFEC0FEE0A2BC4BF
+:105AF000A02DE624C0202A62840809470A990B29B0
+:105B00006684D10FC020D10F6C1004DB30C0D018D8
+:105B1000DBA2DA2025300022300708580A28824C00
+:105B2000DC200B80008931709E121BDB9C0C4A111B
+:105B3000ABAA29A28409290B29A684D10F09C9522D
+:105B400068532600910418DB97C0A12F811200AA88
+:105B50001A0AFF022F85121EDB910C4D11AEDD2CAF
+:105B6000D2840C2C0B2CD684D10FC0811FDB8EB8B5
+:105B70009A0A0A4700A1042EF11200881A08EE02C0
+:105B80002EF5121DDB860C4C11ADCC2BC2840B2BD9
+:105B90000B2BC684D10F00006C1004DB30C0D01971
+:105BA000DB7EDA2028300022300709880A28824C60
+:105BB000DC200B80001CDB790C4B11ACBB2AB284BF
+:105BC0000A2A0B2AB684D10F6C1004C04118DB736B
+:105BD00016DB750C2711A626266030A872252286B2
+:105BE000006104A35500441A754108222284023240
+:105BF0000BD10F00C020D10F6C100415DBCE024971
+:105C000014295611245212C0730208430F88110040
+:105C1000810400361AC78F00771A087703074401FA
+:105C2000064402245612D10F6C1006C0B06E230237
+:105C30006000A264209D851013DBAA16DBBEC04065
+:105C4000A6BA2BA2AE0B194164905E68915568927A
+:105C50004A6893372930FF2830FE2AA2AA08881103
+:105C60000A0A4D2AACF20988027589442B3D0129A4
+:105C7000B0002BB0010899110B99027A9932B83310
+:105C80002B2A00B1447249B7600048007FBF051558
+:105C9000DBAA63FFBE253AE863FFB800253AE86354
+:105CA000FFB10000250A6463FFA9C05A63FFA40086
+:105CB00000705F082534FF058C142C34FE70AF0B88
+:105CC0000A8D142E3D012AE4012DE400DA405BFD2B
+:105CD0005D63FFA9D10FD10F6C10041ADB3219DB01
+:105CE0002F1CDB961BDB97C080C07160000D00008D
+:105CF0000022A430B1AA299C107B915F269286795C
+:105D0000C215C0206E62E96D080AB12200210400AC
+:105D1000741A764BDB63FFEE2292850D6311032527
+:105D200014645FCFD650032D436DD9039820B4225D
+:105D30000644146D4922982098219822982398248B
+:105D400098259826982798289829982A982B982C4F
+:105D5000982D982E982F222C4063FF971EDB10273A
+:105D6000E68027E681D10F006C1004C062C04112AA
+:105D7000DB0D13DB7423322D1ADB0819DB6E2AA02E
+:105D8000002992AE6EA30260009128ACFE090D407E
+:105D90002C1AC2C2BD0DCB392B25166480895BFF3E
+:105DA000A215DB691ADB142B3AE80A3A0158059868
+:105DB0002B21160ABB28D3A02B56005805AF8B50B9
+:105DC0000ABB082A0A005805AE15DB602D21022CFB
+:105DD0003AE80C3C2804DD022D25029C505805A60B
+:105DE0008B50AABBC0A15805A61CDB592D21020C63
+:105DF0003C2806DD0213DB572D25029C3058059EFA
+:105E00008B30AABBC0A258059E2A2102C0B40BAA9F
+:105E1000020A0A4F2A25025805B2D10F242423C3AF
+:105E2000CC2C251663FF760018DB4F1CDB4B19DBEF
+:105E30004C1BDB4A17DB1F85202E0AFD1FDB4B2D79
+:105E4000202E24F47A24F47E24F4820EDD0124F43E
+:105E5000862E0AF707552806DD02C0750EDD0105FE
+:105E60000506AB5BA959C0E8AC5C24C4AB0EDD02EF
+:105E700027C4AC2E0ADFA85527B4EC0EDD0124B4EC
+:105E8000EBC2E027942C0EDD0224942B2E0A800D09
+:105E90000D4627546C24546B0EDD022D242E63FE18
+:105EA000FC0000006C1004C3A0C0B35BFF53C04AE9
+:105EB00012DB21C380282616242617C3A1C0B35B9A
+:105EC000FF4EC03CC3A12A261619DAB6299020231A
+:105ED000261764908F2A0A322B0A015BFF47C3A260
+:105EE0002B0A015BFF45C3B22B2616232617C2AF30
+:105EF000C0B15BFF41C2FF2F2616C0EE2E2617C28F
+:105F0000D22D2616C0C82C26172426112A2212C7E5
+:105F1000B30BAA01C0B40BAA022A2612290AA1298E
+:105F20002616C182282617C0B32B26112E22121F37
+:105F3000DACA0FEE022E2612C3D62D26162A0AA280
+:105F4000C1C32C26175BFF2C2C0AA22C2616C1B528
+:105F50002B2617C2AB2A2616C09729261718DB0353
+:105F6000282610D10FC3A2C0B35BFF2363FF6E00CE
+:105F70006C10041CDACE1BDABB18DAFD17DAFE1639
+:105F8000DAFE15DAFEC0E0C0D414DACA1FDA8622BF
+:105F90000A082FF2006D2A36DAC0D9C07C5B020FE6
+:105FA000C90C1CDAC30C9C28A8C3A6C22A36802AB6
+:105FB0002584A4C2A7CC2D248C2B248A2B24872EA5
+:105FC000248BB1BB2E369F2C369E2C369DB1AC1C3B
+:105FD000DAA51BDAEBC0286D2A33DAC0D9C07C5BA6
+:105FE000020FC90C1CDAB30C9C28A8C3A6C22A361F
+:105FF000802B2584A4C2B1BBA7CC2D248C2E248B4E
+:106000002A248A2E369F2C369E2C369DB1ACC07920
+:1060100019DAA31BDADE13DADB1ADADB18DADD149D
+:10602000DAA416DADC04F42812DADC04660C0405BF
+:1060300006A252A858AA5AA3539B3029A500278428
+:106040008AC091C0A52A848C29848B17DAD518DAE6
+:10605000D3A75726361D26361E2E361F16DAD21324
+:10606000DAD2A65504330C2826C82E75002D54AC60
+:106070002E54AB2E54AA2326E62326E52E26E7D15E
+:106080000F0000006C100613DAAF17DAAA24723D75
+:106090002232937F2F0B6D08052832937F8F026386
+:1060A000FFF3C0C4C0B01EDA3FC061D940096939EE
+:1060B00029E4206E4401D6B0C328DFB026E42206CE
+:1060C0002F392FE421C0501FDAB919DAAA16DAAB3A
+:1060D00018DA7994102A72458DE017DAA59D111D02
+:1060E000DAB46DA94BD450255C037A5B18DE507589
+:1060F0006B052E12010E5E0C12DA6E02E2280111FF
+:1061000002AF2222D681D54013DA6A746B052512BC
+:106110000105450C035328B145A83EA932A73322F7
+:10612000369D22369E2436802B369F2BE48B2CE422
+:106130008C14DA8424424DC030041414C84C6D0809
+:1061400006B133041414C84263FFF20016DA13C414
+:1061500040C1580031041ADA13C0B193A200BB1A2F
+:10616000B0BB9BA318DA7829824D23824E28825334
+:106170007A871C2C64008C106FC4481EDA0A043D18
+:106180000C2DE51C2FE11D2DE51A2FE51BD10F006D
+:10619000C07212DA6882207E27DB03034F27640077
+:1061A0008810C0616F8430C0A00319140A54391AD2
+:1061B000D9FD04990C29A51C29A51D29A51A29A5D5
+:1061C0001BD10F001CD9F8053B0C2BC51C2DC11D84
+:1061D0002BC51A2DC51BD10F065439031E1404EE0E
+:1061E0000C2EA51C2EA51D2EA51A2EA51BD10F0009
+:1061F0006C10081AD9EC14DA4F13DA52C72FC050BA
+:1062000016DA6C2566A82566A92566AA2566AB223E
+:1062100036292B424519DA13D8101CDA66C0D49DF2
+:10622000119C100080890B990C99A02816025BFF25
+:10623000952A32E31FD9DC0A5A149AF42932E4B1C0
+:10624000990959140A990C99F52832E508581498B7
+:10625000F62E32CD0E5E142EF6075BFF455BFF1166
+:1062600022463B1CD9D02AC102C1B00BAA021BDABC
+:106270002A0A0A4F2AC5022B463A5804995BFEBAED
+:106280005BFE95C0B0861317D9C525362DC74EC005
+:10629000309414C05014D9CA60004300007F9F0F8F
+:1062A000B155091914659FF4C0500AA9027FA7EFE0
+:1062B00018D9BADA5008580A28822C2B0A000B8009
+:1062C00000005104D2A0C091C7AF00991A0A9903E7
+:1062D000291604CE33642063D3202B2007D6508C9C
+:1062E000142A72827CA85C18D9AC08580A28822C1F
+:1062F000DA500B8000D2A0643FDA8A310A8A140493
+:10630000AA01C82A2B22010B8B1404BB017AB940C5
+:10631000DDA06EA1081DD9A32DD2000DAD0CDB3080
+:10632000DC601AD9E318D99C0ADA2808680A1DDA51
+:106330001F28823CADAA0B8000652F9BD320C0B0E4
+:1063400063FF9B00CA5CB1550050040A091963FF42
+:106350004BDCB06EB1091CD9938CC0D30F0CBC0CB4
+:106360001DD9D41EDA120DCD28AEDD1EDA112DE6B0
+:106370008163FF9B7FA7CE63FF6C00006C10041B42
+:10638000D98727221EC08008E4310002002AB28289
+:1063900019D985003104C06100661A2991020A6A80
+:1063A000022AB68209E43115D9DF0C3811A8532826
+:1063B00032822432842A8CFC7841102921022A3628
+:1063C0008297A0096902292502D10F002B21022CF6
+:1063D00032850B6B022CCCFC2C368297C02B25020D
+:1063E000D10F00006C1006C0C71BD9681AD96A0DFE
+:1063F0004E11D72088208522D98005450B02820CBA
+:106400009572222CF4C8346F2E026000AB1FD96045
+:10641000A9E2AF7D72D334C93DC0212F0A00092FF4
+:10642000380F0F42C9F92AB67E6D4A050030880040
+:10643000908C22720002E20872D1749270D280D1E4
+:106440000FC05003253875C0DF63FFD9097D0CAF3D
+:10645000DD0DEE0C64304ED2300D3F1296112F162A
+:10646000002FFC100F4F36260A01250A0009653857
+:106470000505426450712AB67E6DFA050020880039
+:10648000908CC050A3D28910237C0C09440C290A9B
+:106490000103953805054264505A2AB67E6D4A05B7
+:1064A00000208800308CD280A7EABCAA9A70D10F55
+:1064B000D280BC7B9B70D10F00023F14C1D0D23080
+:1064C0000FDD0C0D4D36298D08C0F1250A0009F5A8
+:1064D00038050542CA582AB67E6DDA0500208800C4
+:1064E000908C897063FF2500C061C05003653875CA
+:1064F000C08663FF80C0D0029D387DC09F63FF9936
+:10650000C05003F53875C0D063FFCA006C1004D6C4
+:106510002068520F695324DA20DB30DC405800F049
+:10652000D2A0D10FDA20DB30DC405800ED9A2424D1
+:10653000240EC02122640FC020D10F00B83BB04C04
+:106540002A2C7489242D200E2E200FA4DDB1EE2ECE
+:10655000240FB0DD2D240E2890072D9003A488B0C1
+:1065600088B1DD2D94032894075BFF9E69511DC0FF
+:10657000E082242A600F18D9902A240329600E8F04
+:106580002029240708FF029F209E64D10FC020D13C
+:106590000F0000006C1004942319D988C0B3083A86
+:1065A000110BAA02992019D8FD9A2128929D16D87C
+:1065B000FAC0502564A2288C1828969DD10F00009F
+:1065C0006C1004282066C038232406B78828246667
+:1065D000D10F00006C1006035A0C0D36110D5C1122
+:1065E000D8208B2282210CBB0C06550F9B820232D5
+:1065F0000B928113D8E7D920A38F6450531CD8E3A2
+:10660000C0D71BD8E4A256C0E1290A0004E9380922
+:10661000094276F34A044302C99E2BC67E6DAA0541
+:1066200000208800308C8981A95909FA0C64A0796E
+:1066300099818A82C8ADD290D10FC06002E63876C7
+:10664000D0DA63FFD4C020BC89998199809282D12D
+:106650000F7F2304292DF8998165BFD963FFE500D9
+:10666000028F0CA3FF0F3312931003AA0CD340CB5D
+:106670009E2BC67E86106D6A0500208800308CBC7B
+:1066800082290A0004F308240A010349380909424F
+:10669000CA982BC67E6DAA0500208800308C0F5941
+:1066A0000CA989BC99998163FF87BC89998163FF93
+:1066B00080C06002E63876D0BA63FFB4C07002478B
+:1066C0003877D0D063FFCA006C100414D8C0C15210
+:1066D000A424C93E28221D738119292102CD932AA1
+:1066E000300075A912DA20DB302C3007C0D25801F7
+:1066F000C4653FDFD10F00002B300703BB0BDAB0BE
+:1067000074B3022ABDF8D3A063FFC6006C1004293D
+:106710002006C0706E9741292102C08F2A2014C024
+:10672000B62B240606AA022A241479800227250201
+:106730002A221E2C221D7AC10EC8ABDA20DB302C97
+:106740000A00033D025BF8226450752D21020D0DF5
+:106750004CC9D3C020D10F00002E9CFB64E0822FD7
+:1067600021020F0F4C65F0911AD88D1CD88B29A2ED
+:106770009EC08A798B5D2BC22668B0048D207BD9A0
+:106780005229A29DC0F364904A97901DD89E2E2155
+:10679000049D9608EE110FEE029E979E9127C4A2CB
+:1067A00018D89A2F21022BA29DC0E52E24062BBCBF
+:1067B0003008FF022BA69D2F2502C020D10F00001C
+:1067C000002F300068F938DA20DB30DC4058004414
+:1067D00063FF7700022A022B0A065800D4220A001F
+:1067E000D10F655010283000688924022A02033B2B
+:1067F00002DC4058003BC020D10FD270D10F000006
+:106800002A2C74033B02044C025BFEF663FF3B0040
+:10681000DB30DC402A2C745BFEF3C020D10F00007B
+:106820006C1004C83F89268829A399992609880CE9
+:10683000080848282525CC52C020D10FDB402A2C3F
+:10684000745BF949D2A0D10F6C1004D820D73082E4
+:10685000220D451105220C928264207407420B130D
+:10686000D84CD420A383732302242DF8858074513F
+:106870004CBC82C0906D081600408800708C77393F
+:1068800003D720C0918680743901D42074610263DB
+:10689000FFE2CA98C097C0411BD8CAC0A00B8B0C9E
+:1068A0000B4A380A0A42C9AA1DD8391CD83A2CD634
+:1068B0007EC140D30F6D4A0500208800308C978040
+:1068C000D270D10FBC8FC0E00F4E387E90E263FFD4
+:1068D000D6BC8292819280C0209282D10F000000AB
+:1068E0006C1006C0D71CD8291BD82B0D4911D720F6
+:1068F0002A221F28221D0A4A0BD28007860C2A76DC
+:106900001F266C80C8346F6E026000D02F0A801A78
+:10691000D82FA29EAA7A7EA33FC93FC0E1C05002F1
+:10692000E538050542CA552BC67EDB20D30F6D4ADC
+:106930000500308800B08C2E721DAE9E0EA50C6432
+:10694000508AD2802E761DC091298403D10FC05069
+:1069500003E53875D0D363FFCD15D81C027E0CA596
+:10696000EE643055DA300E351296129511255C1012
+:10697000054536C0619510C0500265380505426472
+:1069800050892BC67E8510D30F6D5A0500A0880054
+:10699000208CC0A1A3E2C05023FA8003730C03A58E
+:1069A00038AF730505426450722BC67E85110545CC
+:1069B0000C6D5A0500208800308CD280C0A10E9B3F
+:1069C0000CAB7BAFBB2B761D2A8403D10FD280C0CA
+:1069D000C1AF7D2D761D2C8403D10F0000063F141E
+:1069E000C1E0D2300FEE0C0E4E362A8D08C0F125D4
+:1069F0000A000AF538050542CA5C2BC67E6DEA0519
+:106A000000208800A08C22721D63FEFFC061C05070
+:106A100003653875D80263FF6B63FF65C05002A53C
+:106A20003875D08763FF8100C06003F63876D0CC1C
+:106A300063FFC6006C10042A201529201614D7D92C
+:106A40000A990CCB9D2E200B04ED092BD11C09BCFF
+:106A500036ACAA0CBB0C2BD51C0A0A472A2415CB32
+:106A6000A18B438F288942B0A800910400881AA8FE
+:106A7000FF0FBB029B278F260FB80C783B1AC02054
+:106A8000D10F0000292102C0A20A9902292502C0C3
+:106A900021D10F008B2763FFDC2BD11C0CAA0C0A21
+:106AA0000A472A2415ACBB2BD51CC9AE8B438C28B6
+:106AB0008F42B0AD00F10400DD1AADCC0CBB029BDF
+:106AC00027DA20B7EB580019C021D10F9F2763FFA9
+:106AD000EF0000006C100428203C64304705306053
+:106AE00000073E01053EB156076539054928C77FB5
+:106AF000A933030641076603B166060641A6337E45
+:106B0000871E222125291AFC732B1502380C0981B6
+:106B10006000063E01023EB12406423903220AD13A
+:106B20000FD230D10FC05163FFC000006C10041DA4
+:106B3000D79B27221EC08008E4310002002CD2829D
+:106B40001BD799003104C06100661A2BB1020C6C8E
+:106B5000022CD6820BE43119D81B0C3A11AA9328C7
+:106B600032829780253282243284B455253682754C
+:106B7000410A292102096902292502D10F2A21028D
+:106B80002B32830A6A022B36822A2502D10F00009B
+:106B90006C10041DD78219D78C27221EC08009775C
+:106BA0000208E4310002002CD2821BD77E0031049F
+:106BB000C06100661A2BB1020C6C022CD6820BE469
+:106BC0003119D8000C3A11AA9328328297802532C5
+:106BD00082243284B45525368275410B2A21020A5B
+:106BE0006A022A2502D10F002B21022C32830B6B63
+:106BF000022C36822B2502D10F0000006C10041BE2
+:106C0000D7670C2A11ABAA29A286B438798B221B2C
+:106C1000D76419D78B0B2B0A2BB2A309290868B0AC
+:106C20000274B90D299D0129901F6E920822A28538
+:106C3000D10FC020D10FC892C020D10FDA205BEF56
+:106C40003DC020D10F0000006C100414D75428421E
+:106C50009E19D7516F88026000B929922668900763
+:106C60008A2009AA0C65A0AB2A429DC0DC64A0A3BF
+:106C70002B200C19D74B0CBC11A4CC2EC28609B901
+:106C80000A7ED3026000992992A36890078D20099B
+:106C9000DD0C65D08B25C2856450852D2104C03064
+:106CA0006ED80D2C2066B8CC0C0C472C246665C021
+:106CB0007A1AD7521CD75B1DD7481ED74FC084986D
+:106CC000519E5089209D569D54935793559C530A2D
+:106CD00099021CD7BD1AD76499528F26995A985990
+:106CE0009E58935E9C5D935C9A5B0F0D4805DD1189
+:106CF0009D5FC0D81ED7320CB911A499289285AED9
+:106D0000BE23E4CF288C402896859F292D2406C0D9
+:106D100020D10F00CA32DA20C0B65BFF84C72FD162
+:106D20000FC939DA205BFF81C72FD10FDBD05BFEA3
+:106D3000192324662B200C63FF76C72FD10FC72F92
+:106D4000D10F00006C1004C85B29200668941C68F1
+:106D50009607C020D10FC020D10FDA20DB30DC40F5
+:106D6000DD502E0A005BFE69D2A0D10F2E200C1838
+:106D7000D70B0CEF11A8FF29F286C088798B751A02
+:106D8000D7080AEA0A2AA2A368A0048B207AB96469
+:106D900023F28564305E1CD7122A0A802D206829D0
+:106DA00020672821040B991104881109880208DD45
+:106DB00002C094284A1008DD0218D70A9931983089
+:106DC0008B2B9A379D340CBB029B32C0C09C359CE8
+:106DD000362A2C74DB40C0D318D6F929F285A8EEE8
+:106DE000299C2029F6852CE4CF2D2406DD405BFD6F
+:106DF000F9D2A0D10FDA20DBE05BFF4CC020D10F2D
+:106E00006C100AD6302A2006941028ACF86583FF4F
+:106E10002B2122270A022A2124CC572AAC010A0A54
+:106E20004F2A25247ABB026003F72C21022A200C6A
+:106E30000C0C4C65C38E2E22158D32C0F10EDD0C6C
+:106E400065D40488381ED6D56483E18F37C0C8C0A6
+:106E5000960FC9399914B49B9B110D99119913C9B7
+:106E6000FB19D6D02990217F93138B148C205BFFC4
+:106E7000631ED6CADDA064A41C8F676000298C1134
+:106E80000CAD11AEDD28D2860AAB0278CB621AD6E1
+:106E9000C40ABA0A2AA2A368A0052C22007AC95003
+:106EA0002AD285DDA064A3D729212E09F9362A200C
+:106EB0003C09F80C6F8D3ED7F0CB7F28211F08705E
+:106EC00060010B3E00043EB1BC04CB39C74F0BBB85
+:106ED0000A07BB0A0B0C4104CC03B1CC0C0C41AC2F
+:106EE000BBD4B0C0C27CA04C2A21257BAB4660003D
+:106EF0002CC0A063FFACD79063FFBD00C092C74F0A
+:106F00002C7C140C0B4104BB03B1BB0B0B41AB74C9
+:106F1000244C1479A01E2A212574AB18ACBB241A6A
+:106F2000FC0ABC0C04C16000093E01043EB14809E2
+:106F300084390B440A8926882709880C74831DC06C
+:106F40008098D88C649CD98B668A659BDB9ADA978B
+:106F5000D57F730260013ACE5E600016009D15DA9F
+:106F600020DB405BFEB48D151ED68D65A2568F6763
+:106F700063FFCB9D15DA20DB308C105BFE598D153D
+:106F80001ED687C051D6A08FA7C0C08A6897DD9A49
+:106F9000DC8869896A98DE99DF8B6A8A69AB7B77BE
+:106FA000BB022AAC019B6A9A698860C0A0088B1456
+:106FB000778701C0A1C09028203C9417951893169C
+:106FC000C050C031C044048401043938089910C04D
+:106FD00042048401043538083840832B0BA4100781
+:106FE00055102A211F0955020544020B19400A2A8F
+:106FF000140799100585100433020A881114D6F37A
+:10700000095502292104043302089911098802C094
+:107010009209880229212593D00929140499110A7B
+:1070200099020955028A20891408AA110A99021A9C
+:10703000D66F14D6E70A990299D1832A95D698D7A4
+:10704000851804330293D4841783168A658D66AA43
+:10705000CAAD7D77DB01B1AA07FF0C9A659D6688F2
+:10706000268C29A48808CC0C98260C0C482C2525A5
+:107070009F672A200CC0C01BD6510CA911AE99AB3A
+:10708000AB2892852CB4CF8B13AB8828968563FDF3
+:10709000CD00C091C0F0C0B2C0C4886023203C982D
+:1070A000120C3C010B3A010888140B88010A9F3826
+:1070B00007FF10089839C0A00C9A3807881008AA52
+:1070C000100AFF02C0A80A33010393392A210429B8
+:1070D0002125053C1008CC020A331108AA11092900
+:1070E0001403AA020499110BAA022B211F83140B6B
+:1070F0002B140B99020C99028B201CD63C08BB1157
+:1071000003BB020CBB02832A8C2B647084886897B3
+:10711000DD98DC8769886A97DE98DF8812C070770F
+:107120008701C0719BD199D60B78109AD717D6A931
+:1071300008F80208C80207880217D6A598D00737B2
+:107140000297D428200C295CFE2B2124C0F01AD6EB
+:107150001B0C8D11AEDD2CD285AA882F84CF8F1306
+:10716000B0BBAFCC2CD6852A22152B2524B1AA2A58
+:1071700026156490DCC84F8C268B29A4CC9C260C49
+:10718000BB0C0B0B482B25256550E8C020D10F0008
+:107190000000C0709BD199D69AD7881293D4778774
+:1071A0000E18D600921A288022C021082738821A89
+:1071B00018D68A0B731003F30203C3020833029339
+:1071C000D063FF7E00CC57DA20DB608C105BFDC4FF
+:1071D000292102689806689403C020D10F2B221E33
+:1071E000C09028221D2925027B8901C0B064BFE818
+:1071F00013D5EA2CB00728B000DA2003880A2882C9
+:107200004CC0D10B8000DBA065AFE763FFCA000074
+:1072100068A775DA20DB30DC40DD505BFECAD2A007
+:10722000D10FC1FDC19D29252C600003002F252C05
+:107230002F2467272468DA20DB308C10DD502E0ADB
+:10724000805BFD32D2A0D10FC1F8C1A82A252C63E2
+:10725000FFDDC84F8C268B29A4CC9C260CBB0C0BC5
+:107260000B482B25252A2C74DB602C12005BFD7645
+:10727000D2A0D10F2A2C748B105BF6BBD2A0D10FF9
+:10728000DA205BFE2A63FF3C00DA20C0B15BFE6EB1
+:1072900065AF3163FB79DA202B200C5BFE3D63FF89
+:1072A0002300000012D64E8220028257C82163FFBD
+:1072B000FC12D64A03E83004EE3005B13093209436
+:1072C00021952263FFFC000010D6469100920193A5
+:1072D00002940311D61D821001EA30A21101F0318F
+:1072E000C04004E41600020011D63F8210234A0079
+:1072F000032202921011D609C021921004E43184B5
+:107300000383028201810000D230012300000000CB
+:1073100010D636910092019302940311D60C82107C
+:1073200001EA30A21101F131C04004E4160002006C
+:1073300011D62D821013D5B4032202921004E43129
+:10734000840383028201810000D3300133000000F6
+:1073500010D6279100810165104981026510448192
+:1073600003CF1F92019302940311D5FA821001EA10
+:1073700030A21101F231C04004E41600020011D61F
+:1073800019821013D59B032202921004E431840366
+:1073900083028201C010910391029101810000D407
+:1073A0003001430012D5CAC030283740283744285E
+:1073B000374828374C233D017233ED03020063FF49
+:1073C000FC00000010D60B9100920193029403116F
+:1073D000D6098210921011D5BC831003220292109C
+:1073E00011D60612D5CD9210C04004E4160002005A
+:1073F00011D5FD821013D5B5032202921004E43199
+:10740000840383028201810000D530015300000013
+:107410006C10026E322FD620056F04043F04745B9B
+:107420002A05440C00410400331A220A006D490D5C
+:1074300073630403660CB1220F22110313147363E8
+:1074400002222C01D10FC83BD10F000073630CC086
+:1074500021D10F000000000044495630C020D10F58
+:107460006C10020040046B4C07032318020219D170
+:107470000F020319C020D10F6C100202EA30D10FA5
+:107480006C1002CC2503F03160000F006F22050361
+:10749000F1316000056F230503F231000200D10FC6
+:1074A0006C1002CC2502F030D10F00006F220402D4
+:1074B000F130D10F6F230402F230D10FC020D10F71
+:1074C0006C1002220A20230A006D280E283740285B
+:1074D000374428374828374C233D01030200D10F99
+:1074E0006C100202E431D10F0A004368656C7369C5
+:1074F0006F2046572044454255473D30202842756D
+:10750000696C7420547565204175672031322030D4
+:10751000393A34333A303420504454203230303801
+:10752000206F6E2066656C69782E6173696364658F
+:107530007369676E6572732E636F6D3A2F686F6D36
+:10754000652F66656C69782F772F66775F362E30EA
+:10755000292C2056657273696F6E20543378782019
+:107560003030372E30302E3030202D203130303733
+:0C7570003030303010070000CC44A0D6B2
+:00000001FF
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 2a983d4..14d9442 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -120,7 +120,7 @@
 	switch (access) {
 	case V9FS_ACCESS_SINGLE:
 	case V9FS_ACCESS_USER:
-		uid = current->fsuid;
+		uid = current_fsuid();
 		any = 0;
 		break;
 
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 2dfcf54..81f8bbf 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -215,8 +215,8 @@
 	inode = new_inode(sb);
 	if (inode) {
 		inode->i_mode = mode;
-		inode->i_uid = current->fsuid;
-		inode->i_gid = current->fsgid;
+		inode->i_uid = current_fsuid();
+		inode->i_gid = current_fsgid();
 		inode->i_blocks = 0;
 		inode->i_rdev = 0;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index d6cb1a0..93212e4 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -113,8 +113,8 @@
 	struct v9fs_session_info *v9ses = NULL;
 	struct p9_wstat *st = NULL;
 	int mode = S_IRWXUGO | S_ISVTX;
-	uid_t uid = current->fsuid;
-	gid_t gid = current->fsgid;
+	uid_t uid = current_fsuid();
+	gid_t gid = current_fsgid();
 	struct p9_fid *fid;
 	int retval = 0;
 
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index a13b334..415d9c6 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -293,8 +293,8 @@
 	mark_buffer_dirty_inode(bh, inode);
 	affs_brelse(bh);
 
-	inode->i_uid     = current->fsuid;
-	inode->i_gid     = current->fsgid;
+	inode->i_uid     = current_fsuid();
+	inode->i_gid     = current_fsgid();
 	inode->i_ino     = block;
 	inode->i_nlink   = 1;
 	inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 8989c93..a19d64b 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -163,8 +163,8 @@
 
 	/* Fill in defaults */
 
-	*uid        = current->uid;
-	*gid        = current->gid;
+	*uid        = current_uid();
+	*gid        = current_gid();
 	*reserved   = 2;
 	*root       = -1;
 	*blocksize  = -1;
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 9f7d1ae..7578c1a 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -646,7 +646,7 @@
 	}
 
 	/* display one cell per line on subsequent lines */
-	seq_printf(m, "%u.%u.%u.%u\n", NIPQUAD(addr->s_addr));
+	seq_printf(m, "%pI4\n", &addr->s_addr);
 	return 0;
 }
 
@@ -737,7 +737,7 @@
 	}
 
 	/* display one cell per line on subsequent lines */
-	sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(server->addr));
+	sprintf(ipaddr, "%pI4", &server->addr);
 	seq_printf(m, "%3d %-15.15s %5d\n",
 		   atomic_read(&server->usage), ipaddr, server->fs_state);
 
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 28f2451..f490995 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -105,7 +105,7 @@
 {
 	struct afs_server *server, *candidate;
 
-	_enter("%p,"NIPQUAD_FMT, cell, NIPQUAD(addr->s_addr));
+	_enter("%p,%pI4", cell, &addr->s_addr);
 
 	/* quick scan of the list to see if we already have the server */
 	read_lock(&cell->servers_lock);
@@ -168,9 +168,8 @@
 server_in_two_cells:
 	write_unlock(&cell->servers_lock);
 	kfree(candidate);
-	printk(KERN_NOTICE "kAFS:"
-	       " Server "NIPQUAD_FMT" appears to be in two cells\n",
-	       NIPQUAD(*addr));
+	printk(KERN_NOTICE "kAFS: Server %pI4 appears to be in two cells\n",
+	       addr);
 	_leave(" = -EEXIST");
 	return ERR_PTR(-EEXIST);
 }
@@ -184,7 +183,7 @@
 	struct rb_node *p;
 	struct in_addr addr = *_addr;
 
-	_enter(NIPQUAD_FMT, NIPQUAD(addr.s_addr));
+	_enter("%pI4", &addr.s_addr);
 
 	read_lock(&afs_servers_lock);
 
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 3662dd4..c16d9be 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -154,8 +154,8 @@
 	 */
 	inode->i_state = I_DIRTY;
 	inode->i_mode = S_IRUSR | S_IWUSR;
-	inode->i_uid = current->fsuid;
-	inode->i_gid = current->fsgid;
+	inode->i_uid = current_fsuid();
+	inode->i_gid = current_fsgid();
 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	return inode;
 }
diff --git a/fs/attr.c b/fs/attr.c
index 7a83819..f436019 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -29,13 +29,13 @@
 
 	/* Make sure a caller can chown. */
 	if ((ia_valid & ATTR_UID) &&
-	    (current->fsuid != inode->i_uid ||
+	    (current_fsuid() != inode->i_uid ||
 	     attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
 		goto error;
 
 	/* Make sure caller can chgrp. */
 	if ((ia_valid & ATTR_GID) &&
-	    (current->fsuid != inode->i_uid ||
+	    (current_fsuid() != inode->i_uid ||
 	    (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
 	    !capable(CAP_CHOWN))
 		goto error;
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index b70eea1..c773680 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -76,8 +76,8 @@
 	substring_t args[MAX_OPT_ARGS];
 	int option;
 
-	*uid = current->uid;
-	*gid = current->gid;
+	*uid = current_uid();
+	*gid = current_gid();
 	*pgrp = task_pgrp_nr(current);
 
 	*minproto = *maxproto = AUTOFS_PROTO_VERSION;
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
index 33bf8cb..63b7c7a 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -308,7 +308,8 @@
 			goto out;
 		}
 
-		filp = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY);
+		filp = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY,
+				   current_cred());
 		if (IS_ERR(filp)) {
 			err = PTR_ERR(filp);
 			goto out;
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index c7e65bb..7b19802 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -235,8 +235,8 @@
 	substring_t args[MAX_OPT_ARGS];
 	int option;
 
-	*uid = current->uid;
-	*gid = current->gid;
+	*uid = current_uid();
+	*gid = current_gid();
 	*pgrp = task_pgrp_nr(current);
 
 	*minproto = AUTOFS_MIN_PROTO_VERSION;
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 4b67c2a..e02cc8a 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -391,8 +391,8 @@
 		memcpy(&wq->name, &qstr, sizeof(struct qstr));
 		wq->dev = autofs4_get_dev(sbi);
 		wq->ino = autofs4_get_ino(sbi);
-		wq->uid = current->uid;
-		wq->gid = current->gid;
+		wq->uid = current_uid();
+		wq->gid = current_gid();
 		wq->pid = current->pid;
 		wq->tgid = current->tgid;
 		wq->status = -EINTR; /* Status return if interrupted */
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index daae463..4dd1b62 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -106,8 +106,8 @@
 	}
 	set_bit(ino, info->si_imap);
 	info->si_freei--;
-	inode->i_uid = current->fsuid;
-	inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+	inode->i_uid = current_fsuid();
+	inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current_fsgid();
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 	inode->i_blocks = 0;
 	inode->i_op = &bfs_file_inops;
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 204cfd1..f1f3f41 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -320,7 +320,7 @@
 	current->mm->free_area_cache = current->mm->mmap_base;
 	current->mm->cached_hole_size = 0;
 
-	compute_creds(bprm);
+	install_exec_creds(bprm);
  	current->flags &= ~PF_FORKNOEXEC;
 #ifdef __sparc__
 	if (N_MAGIC(ex) == NMAGIC) {
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 8fcfa39..c41fa2a 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -157,7 +157,7 @@
 	int items;
 	elf_addr_t *elf_info;
 	int ei_index = 0;
-	struct task_struct *tsk = current;
+	const struct cred *cred = current_cred();
 	struct vm_area_struct *vma;
 
 	/*
@@ -223,10 +223,10 @@
 	NEW_AUX_ENT(AT_BASE, interp_load_addr);
 	NEW_AUX_ENT(AT_FLAGS, 0);
 	NEW_AUX_ENT(AT_ENTRY, exec->e_entry);
-	NEW_AUX_ENT(AT_UID, tsk->uid);
-	NEW_AUX_ENT(AT_EUID, tsk->euid);
-	NEW_AUX_ENT(AT_GID, tsk->gid);
-	NEW_AUX_ENT(AT_EGID, tsk->egid);
+	NEW_AUX_ENT(AT_UID, cred->uid);
+	NEW_AUX_ENT(AT_EUID, cred->euid);
+	NEW_AUX_ENT(AT_GID, cred->gid);
+	NEW_AUX_ENT(AT_EGID, cred->egid);
  	NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
 	NEW_AUX_ENT(AT_EXECFN, bprm->exec);
 	if (k_platform) {
@@ -949,14 +949,14 @@
 	set_binfmt(&elf_format);
 
 #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
-	retval = arch_setup_additional_pages(bprm, executable_stack);
+	retval = arch_setup_additional_pages(bprm, !!elf_interpreter);
 	if (retval < 0) {
 		send_sig(SIGKILL, current, 0);
 		goto out;
 	}
 #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
 
-	compute_creds(bprm);
+	install_exec_creds(bprm);
 	current->flags &= ~PF_FORKNOEXEC;
 	retval = create_elf_tables(bprm, &loc->elf_ex,
 			  load_addr, interp_load_addr);
@@ -1361,6 +1361,7 @@
 static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
 		       struct mm_struct *mm)
 {
+	const struct cred *cred;
 	unsigned int i, len;
 	
 	/* first copy the parameters from user space */
@@ -1388,8 +1389,11 @@
 	psinfo->pr_zomb = psinfo->pr_sname == 'Z';
 	psinfo->pr_nice = task_nice(p);
 	psinfo->pr_flag = p->flags;
-	SET_UID(psinfo->pr_uid, p->uid);
-	SET_GID(psinfo->pr_gid, p->gid);
+	rcu_read_lock();
+	cred = __task_cred(p);
+	SET_UID(psinfo->pr_uid, cred->uid);
+	SET_GID(psinfo->pr_gid, cred->gid);
+	rcu_read_unlock();
 	strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
 	
 	return 0;
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 5b5424c..aa5b432 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -404,7 +404,7 @@
 	current->mm->start_stack = current->mm->start_brk + stack_size;
 #endif
 
-	compute_creds(bprm);
+	install_exec_creds(bprm);
 	current->flags &= ~PF_FORKNOEXEC;
 	if (create_elf_fdpic_tables(bprm, current->mm,
 				    &exec_params, &interp_params) < 0)
@@ -475,6 +475,7 @@
 				   struct elf_fdpic_params *exec_params,
 				   struct elf_fdpic_params *interp_params)
 {
+	const struct cred *cred = current_cred();
 	unsigned long sp, csp, nitems;
 	elf_caddr_t __user *argv, *envp;
 	size_t platform_len = 0, len;
@@ -623,10 +624,10 @@
 	NEW_AUX_ENT(AT_BASE,	interp_params->elfhdr_addr);
 	NEW_AUX_ENT(AT_FLAGS,	0);
 	NEW_AUX_ENT(AT_ENTRY,	exec_params->entry_addr);
-	NEW_AUX_ENT(AT_UID,	(elf_addr_t) current->uid);
-	NEW_AUX_ENT(AT_EUID,	(elf_addr_t) current->euid);
-	NEW_AUX_ENT(AT_GID,	(elf_addr_t) current->gid);
-	NEW_AUX_ENT(AT_EGID,	(elf_addr_t) current->egid);
+	NEW_AUX_ENT(AT_UID,	(elf_addr_t) cred->uid);
+	NEW_AUX_ENT(AT_EUID,	(elf_addr_t) cred->euid);
+	NEW_AUX_ENT(AT_GID,	(elf_addr_t) cred->gid);
+	NEW_AUX_ENT(AT_EGID,	(elf_addr_t) cred->egid);
 	NEW_AUX_ENT(AT_SECURE,	security_bprm_secureexec(bprm));
 	NEW_AUX_ENT(AT_EXECFN,	bprm->exec);
 
@@ -1413,6 +1414,7 @@
 static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
 		       struct mm_struct *mm)
 {
+	const struct cred *cred;
 	unsigned int i, len;
 
 	/* first copy the parameters from user space */
@@ -1440,8 +1442,11 @@
 	psinfo->pr_zomb = psinfo->pr_sname == 'Z';
 	psinfo->pr_nice = task_nice(p);
 	psinfo->pr_flag = p->flags;
-	SET_UID(psinfo->pr_uid, p->uid);
-	SET_GID(psinfo->pr_gid, p->gid);
+	rcu_read_lock();
+	cred = __task_cred(p);
+	SET_UID(psinfo->pr_uid, cred->uid);
+	SET_GID(psinfo->pr_gid, cred->gid);
+	rcu_read_unlock();
 	strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
 
 	return 0;
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index ccb781a..7bbd5c6 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -880,7 +880,7 @@
 					(libinfo.lib_list[j].loaded)?
 						libinfo.lib_list[j].start_data:UNLOADED_LIB;
 
-	compute_creds(bprm);
+	install_exec_creds(bprm);
  	current->flags &= ~PF_FORKNOEXEC;
 
 	set_binfmt(&flat_format);
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
index 74e587a..08644a6 100644
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -255,7 +255,7 @@
 	kfree(hpuxhdr);
 
 	set_binfmt(&som_format);
-	compute_creds(bprm);
+	install_exec_creds(bprm);
 	setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
 
 	create_som_tables(bprm);
diff --git a/fs/bio.c b/fs/bio.c
index 77a55bc..df99c88 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -26,8 +26,11 @@
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
 #include <linux/blktrace_api.h>
+#include <trace/block.h>
 #include <scsi/sg.h>		/* for struct sg_iovec */
 
+DEFINE_TRACE(block_split);
+
 static struct kmem_cache *bio_slab __read_mostly;
 
 static mempool_t *bio_split_pool __read_mostly;
@@ -1263,7 +1266,7 @@
 	if (!bp)
 		return bp;
 
-	blk_add_trace_pdu_int(bdev_get_queue(bi->bi_bdev), BLK_TA_SPLIT, bi,
+	trace_block_split(bdev_get_queue(bi->bi_bdev), bi,
 				bi->bi_sector + first_sectors);
 
 	BUG_ON(bi->bi_vcnt != 1);
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS
index 9c136d7..7f7fa3c 100644
--- a/fs/cifs/AUTHORS
+++ b/fs/cifs/AUTHORS
@@ -36,7 +36,9 @@
 Kazeon team for various fixes especially for 2.4 version.
 Asser Ferno (Change Notify support)
 Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
+Gunter Kukkukk (testing and suggestions for support of old servers)
 Igor Mammedov (DFS support)
+Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code)
 
 Test case and Bug Report contributors
 -------------------------------------
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index e078b7a..080703a 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,12 @@
+Version 1.56
+------------
+Add "forcemandatorylock" mount option to allow user to use mandatory
+rather than posix (advisory) byte range locks, even though server would
+support posix byte range locks.  Fix query of root inode when prefixpath
+specified and user does not have access to query information about the
+top of the share.  Fix problem in 2.6.28 resolving DFS paths to
+Samba servers (worked to Windows).
+
 Version 1.55
 ------------
 Various fixes to make delete of open files behavior more predictable
diff --git a/fs/cifs/README b/fs/cifs/README
index a439dc1..da4515e 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -463,9 +463,19 @@
 		with cifs style mandatory byte range locks (and most
 		cifs servers do not yet support requesting advisory
 		byte range locks).
+ forcemandatorylock Even if the server supports posix (advisory) byte range
+		locking, send only mandatory lock requests.  For some
+		(presumably rare) applications, originally coded for
+		DOS/Windows, which require Windows style mandatory byte range
+		locking, they may be able to take advantage of this option,
+		forcing the cifs client to only send mandatory locks
+		even if the cifs server would support posix advisory locks.
+		"forcemand" is accepted as a shorter form of this mount
+		option.
  nodfs          Disable DFS (global name space support) even if the
 		server claims to support it.  This can help work around
-		a problem with parsing of DFS paths with Samba 3.0.24 server.
+		a problem with parsing of DFS paths with Samba server
+		versions 3.0.24 and 3.0.25.
  remount        remount the share (often used to change from ro to rw mounts
 	        or vice versa)
  cifsacl        Report mode bits (e.g. on stat) based on the Windows ACL for
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index e1c1836..85c0a74 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -122,7 +122,7 @@
 				   char **devname)
 {
 	int rc;
-	char *mountdata;
+	char *mountdata = NULL;
 	int md_len;
 	char *tkn_e;
 	char *srvIP = NULL;
@@ -136,10 +136,9 @@
 	*devname = cifs_get_share_name(ref->node_name);
 	rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
 	if (rc != 0) {
-		cERROR(1, ("%s: Failed to resolve server part of %s to IP",
-			  __func__, *devname));
-		mountdata = ERR_PTR(rc);
-		goto compose_mount_options_out;
+		cERROR(1, ("%s: Failed to resolve server part of %s to IP: %d",
+			  __func__, *devname, rc));;
+		goto compose_mount_options_err;
 	}
 	/* md_len = strlen(...) + 12 for 'sep+prefixpath='
 	 * assuming that we have 'unc=' and 'ip=' in
@@ -149,8 +148,8 @@
 		strlen(ref->node_name) + 12;
 	mountdata = kzalloc(md_len+1, GFP_KERNEL);
 	if (mountdata == NULL) {
-		mountdata = ERR_PTR(-ENOMEM);
-		goto compose_mount_options_out;
+		rc = -ENOMEM;
+		goto compose_mount_options_err;
 	}
 
 	/* copy all options except of unc,ip,prefixpath */
@@ -197,18 +196,32 @@
 
 	/* find & copy prefixpath */
 	tkn_e = strchr(ref->node_name + 2, '\\');
-	if (tkn_e == NULL) /* invalid unc, missing share name*/
-		goto compose_mount_options_out;
+	if (tkn_e == NULL) {
+		/* invalid unc, missing share name*/
+		rc = -EINVAL;
+		goto compose_mount_options_err;
+	}
 
+	/*
+	 * this function gives us a path with a double backslash prefix. We
+	 * require a single backslash for DFS. Temporarily increment fullpath
+	 * to put it in the proper form and decrement before freeing it.
+	 */
 	fullpath = build_path_from_dentry(dentry);
+	if (!fullpath) {
+		rc = -ENOMEM;
+		goto compose_mount_options_err;
+	}
+	++fullpath;
 	tkn_e = strchr(tkn_e + 1, '\\');
-	if (tkn_e || strlen(fullpath) - (ref->path_consumed)) {
+	if (tkn_e || (strlen(fullpath) - ref->path_consumed)) {
 		strncat(mountdata, &sep, 1);
 		strcat(mountdata, "prefixpath=");
 		if (tkn_e)
 			strcat(mountdata, tkn_e + 1);
-		strcat(mountdata, fullpath + (ref->path_consumed));
+		strcat(mountdata, fullpath + ref->path_consumed);
 	}
+	--fullpath;
 	kfree(fullpath);
 
 	/*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
@@ -217,6 +230,11 @@
 compose_mount_options_out:
 	kfree(srvIP);
 	return mountdata;
+
+compose_mount_options_err:
+	kfree(mountdata);
+	mountdata = ERR_PTR(rc);
+	goto compose_mount_options_out;
 }
 
 
@@ -309,13 +327,19 @@
 		goto out_err;
 	}
 
+	/*
+	 * The MSDFS spec states that paths in DFS referral requests and
+	 * responses must be prefixed by a single '\' character instead of
+	 * the double backslashes usually used in the UNC. This function
+	 * gives us the latter, so we must adjust the result.
+	 */
 	full_path = build_path_from_dentry(dentry);
 	if (full_path == NULL) {
 		rc = -ENOMEM;
 		goto out_err;
 	}
 
-	rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls,
+	rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb->local_nls,
 		&num_referrals, &referrals,
 		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 877c854..c4c306f 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -19,8 +19,8 @@
 #define _CIFS_FS_SB_H
 
 #define CIFS_MOUNT_NO_PERM      1 /* do not do client vfs_perm check */
-#define CIFS_MOUNT_SET_UID      2 /* set current->euid in create etc. */
-#define CIFS_MOUNT_SERVER_INUM  4 /* inode numbers from uniqueid from server */
+#define CIFS_MOUNT_SET_UID      2 /* set current's euid in create etc. */
+#define CIFS_MOUNT_SERVER_INUM  4 /* inode numbers from uniqueid from server  */
 #define CIFS_MOUNT_DIRECT_IO    8 /* do not write nor read through page cache */
 #define CIFS_MOUNT_NO_XATTR     0x10  /* if set - disable xattr support       */
 #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames   */
@@ -30,7 +30,8 @@
 #define CIFS_MOUNT_CIFS_ACL     0x200 /* send ACL requests to non-POSIX srv   */
 #define CIFS_MOUNT_OVERR_UID    0x400 /* override uid returned from server    */
 #define CIFS_MOUNT_OVERR_GID    0x800 /* override gid returned from server    */
-#define CIFS_MOUNT_DYNPERM	0x1000 /* allow in-memory only mode setting */
+#define CIFS_MOUNT_DYNPERM      0x1000 /* allow in-memory only mode setting   */
+#define CIFS_MOUNT_NOPOSIXBRL   0x2000 /* mandatory not posix byte range lock */
 
 struct cifs_sb_info {
 	struct cifsTconInfo *tcon;	/* primary mount */
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
index 0ab2fb5..3fd3a9d 100644
--- a/fs/cifs/cifs_spnego.c
+++ b/fs/cifs/cifs_spnego.c
@@ -121,11 +121,9 @@
 
 	/* add the server address */
 	if (server->addr.sockAddr.sin_family == AF_INET)
-		sprintf(dp, "ip4=" NIPQUAD_FMT,
-			NIPQUAD(server->addr.sockAddr.sin_addr));
+		sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr);
 	else if (server->addr.sockAddr.sin_family == AF_INET6)
-		sprintf(dp, "ip6=" NIP6_SEQFMT,
-			NIP6(server->addr.sockAddr6.sin6_addr));
+		sprintf(dp, "ip6=%pi6", &server->addr.sockAddr6.sin6_addr);
 	else
 		goto out;
 
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index bd5f13d..d4839cf 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -37,7 +37,7 @@
 
 extern void mdfour(unsigned char *out, unsigned char *in, int n);
 extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
-extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
+extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
 		       unsigned char *p24);
 
 static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
@@ -280,25 +280,22 @@
 }
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
-void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
+void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
+			char *lnm_session_key)
 {
 	int i;
 	char password_with_pad[CIFS_ENCPWD_SIZE];
 
-	if (ses->server == NULL)
-		return;
-
 	memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
-	if (ses->password)
-		strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
+	if (password)
+		strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
 
-	if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
-		if (extended_security & CIFSSEC_MAY_PLNTXT) {
-			memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
-			memcpy(lnm_session_key, password_with_pad,
-				CIFS_ENCPWD_SIZE);
-			return;
-		}
+	if (!encrypt && extended_security & CIFSSEC_MAY_PLNTXT) {
+		memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
+		memcpy(lnm_session_key, password_with_pad,
+			CIFS_ENCPWD_SIZE);
+		return;
+	}
 
 	/* calculate old style session key */
 	/* calling toupper is less broken than repeatedly
@@ -314,7 +311,8 @@
 	for (i = 0; i < CIFS_ENCPWD_SIZE; i++)
 		password_with_pad[i] = toupper(password_with_pad[i]);
 
-	SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key);
+	SMBencrypt(password_with_pad, cryptkey, lnm_session_key);
+
 	/* clear password before we return/free memory */
 	memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
 }
diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h
index 152fa2d..15d2ec0 100644
--- a/fs/cifs/cifsencrypt.h
+++ b/fs/cifs/cifsencrypt.h
@@ -26,7 +26,8 @@
 extern void mdfour(unsigned char *out, unsigned char *in, int n);
 /* smbdes.c */
 extern void E_P16(unsigned char *p14, unsigned char *p16);
-extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
+extern void E_P24(unsigned char *p21, const unsigned char *c8,
+		  unsigned char *p24);
 
 
 
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index d9cf467..0005a19 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -66,7 +66,9 @@
 extern struct task_struct *oplockThread; /* remove sparse warning */
 struct task_struct *oplockThread = NULL;
 /* extern struct task_struct * dnotifyThread; remove sparse warning */
+#ifdef CONFIG_CIFS_EXPERIMENTAL
 static struct task_struct *dnotifyThread = NULL;
+#endif
 static const struct super_operations cifs_super_ops;
 unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
 module_param(CIFSMaxBufSize, int, 0);
@@ -337,39 +339,58 @@
 cifs_show_options(struct seq_file *s, struct vfsmount *m)
 {
 	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *tcon;
+	struct TCP_Server_Info *server;
 
 	cifs_sb = CIFS_SB(m->mnt_sb);
 
 	if (cifs_sb) {
-		if (cifs_sb->tcon) {
-/* BB add prepath to mount options displayed */
+		tcon = cifs_sb->tcon;
+		if (tcon) {
 			seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
-			if (cifs_sb->tcon->ses) {
-				if (cifs_sb->tcon->ses->userName)
+			if (tcon->ses) {
+				if (tcon->ses->userName)
 					seq_printf(s, ",username=%s",
-					   cifs_sb->tcon->ses->userName);
-				if (cifs_sb->tcon->ses->domainName)
+					   tcon->ses->userName);
+				if (tcon->ses->domainName)
 					seq_printf(s, ",domain=%s",
-					   cifs_sb->tcon->ses->domainName);
+					   tcon->ses->domainName);
+				server = tcon->ses->server;
+				if (server) {
+					seq_printf(s, ",addr=");
+					switch (server->addr.sockAddr6.
+						sin6_family) {
+					case AF_INET6:
+						seq_printf(s, "%pI6",
+							   &server->addr.sockAddr6.sin6_addr);
+						break;
+					case AF_INET:
+						seq_printf(s, "%pI4",
+							   &server->addr.sockAddr.sin_addr.s_addr);
+						break;
+					}
+				}
 			}
 			if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
-			   !(cifs_sb->tcon->unix_ext))
+			   !(tcon->unix_ext))
 				seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
 			if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
-			   !(cifs_sb->tcon->unix_ext))
+			   !(tcon->unix_ext))
 				seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
-			if (!cifs_sb->tcon->unix_ext) {
+			if (!tcon->unix_ext) {
 				seq_printf(s, ",file_mode=0%o,dir_mode=0%o",
 					   cifs_sb->mnt_file_mode,
 					   cifs_sb->mnt_dir_mode);
 			}
-			if (cifs_sb->tcon->seal)
+			if (tcon->seal)
 				seq_printf(s, ",seal");
-			if (cifs_sb->tcon->nocase)
+			if (tcon->nocase)
 				seq_printf(s, ",nocase");
-			if (cifs_sb->tcon->retry)
+			if (tcon->retry)
 				seq_printf(s, ",hard");
 		}
+		if (cifs_sb->prepath)
+			seq_printf(s, ",prepath=%s", cifs_sb->prepath);
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
 			seq_printf(s, ",posixpaths");
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
@@ -417,9 +438,8 @@
 	xid = GetXid();
 	if (pTcon) {
 		cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
-	} else {
+	} else
 		rc = -EIO;
-	}
 
 	FreeXid(xid);
 	return rc;
@@ -441,9 +461,8 @@
 	xid = GetXid();
 	if (pTcon) {
 		cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
-	} else {
+	} else
 		rc = -EIO;
-	}
 
 	FreeXid(xid);
 	return rc;
@@ -464,9 +483,8 @@
 	xid = GetXid();
 	if (pTcon) {
 		cFYI(1, ("flags: 0x%x operation: 0x%x", flags, operation));
-	} else {
+	} else
 		rc = -EIO;
-	}
 
 	FreeXid(xid);
 	return rc;
@@ -479,17 +497,16 @@
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifsTconInfo *pTcon;
 
-	if (cifs_sb) {
+	if (cifs_sb)
 		pTcon = cifs_sb->tcon;
-	} else {
+	else
 		return -EIO;
-	}
+
 	xid = GetXid();
 	if (pTcon) {
 		cFYI(1, ("pqstats %p", qstats));
-	} else {
+	} else
 		rc = -EIO;
-	}
 
 	FreeXid(xid);
 	return rc;
@@ -1029,6 +1046,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_CIFS_EXPERIMENTAL
 static int cifs_dnotify_thread(void *dummyarg)
 {
 	struct list_head *tmp;
@@ -1054,6 +1072,7 @@
 
 	return 0;
 }
+#endif
 
 static int __init
 init_cifs(void)
@@ -1131,16 +1150,20 @@
 		goto out_unregister_dfs_key_type;
 	}
 
+#ifdef CONFIG_CIFS_EXPERIMENTAL
 	dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
 	if (IS_ERR(dnotifyThread)) {
 		rc = PTR_ERR(dnotifyThread);
 		cERROR(1, ("error %d create dnotify thread", rc));
 		goto out_stop_oplock_thread;
 	}
+#endif
 
 	return 0;
 
+#ifdef CONFIG_CIFS_EXPERIMENTAL
  out_stop_oplock_thread:
+#endif
 	kthread_stop(oplockThread);
  out_unregister_dfs_key_type:
 #ifdef CONFIG_CIFS_DFS_UPCALL
@@ -1179,8 +1202,10 @@
 	cifs_destroy_inodecache();
 	cifs_destroy_mids();
 	cifs_destroy_request_bufs();
-	kthread_stop(oplockThread);
+#ifdef CONFIG_CIFS_EXPERIMENTAL
 	kthread_stop(dnotifyThread);
+#endif
+	kthread_stop(oplockThread);
 }
 
 MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 074de0b..2ce04c7 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -101,5 +101,5 @@
 extern const struct export_operations cifs_export_ops;
 #endif /* EXPERIMENTAL */
 
-#define CIFS_VERSION   "1.55"
+#define CIFS_VERSION   "1.56"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index c57c056..94c1ca0 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -47,7 +47,11 @@
  */
 #define CIFS_MAX_REQ 50
 
-#define SERVER_NAME_LENGTH 15
+#define RFC1001_NAME_LEN 15
+#define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
+
+/* currently length of NIP6_FMT */
+#define SERVER_NAME_LENGTH 40
 #define SERVER_NAME_LEN_WITH_NULL     (SERVER_NAME_LENGTH + 1)
 
 /* used to define string lengths for reversing unicode strings */
@@ -125,8 +129,7 @@
 	struct list_head smb_ses_list;
 	int srv_count; /* reference counter */
 	/* 15 character server name + 0x20 16th byte indicating type = srv */
-	char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
-	char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
+	char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
 	char *hostname; /* hostname portion of UNC string */
 	struct socket *ssocket;
 	union {
@@ -151,7 +154,7 @@
 	atomic_t num_waiters;   /* blocked waiting to get in sendrecv */
 #endif
 	enum statusEnum tcpStatus; /* what we think the status is */
-	struct semaphore tcpSem;
+	struct mutex srv_mutex;
 	struct task_struct *tsk;
 	char server_GUID[16];
 	char secMode;
@@ -171,7 +174,7 @@
 	__u16 CurrentMid;         /* multiplex id - rotating counter */
 	char cryptKey[CIFS_CRYPTO_KEY_SIZE];
 	/* 16th byte of RFC1001 workstation name is always null */
-	char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
+	char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
 	__u32 sequence_number; /* needed for CIFS PDU signature */
 	struct mac_key mac_signing_key;
 	char ntlmv2_hash[16];
@@ -239,6 +242,7 @@
 	struct cifsSesInfo *ses;	/* pointer to session associated with */
 	char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
 	char *nativeFileSystem;
+	char *password;		/* for share-level security */
 	__u16 tid;		/* The 2 byte tree id */
 	__u16 Flags;		/* optional support bits */
 	enum statusEnum tidStatus;
@@ -422,7 +426,6 @@
 	unsigned long when_sent; /* time when smb send finished */
 	unsigned long when_received; /* when demux complete (taken off wire) */
 #endif
-	struct cifsSesInfo *ses;	/* smb was sent to this server */
 	struct task_struct *tsk;	/* task waiting for response */
 	struct smb_hdr *resp_buf;	/* response buffer */
 	int midState;	/* wish this were enum but can not pass to wait_event */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index d2a073e..b4e2e9f 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1922,7 +1922,7 @@
 /* DFS server target type */
 #define DFS_TYPE_LINK 0x0000  /* also for sysvol targets */
 #define DFS_TYPE_ROOT 0x0001
- 
+
 /* Referral Entry Flags */
 #define DFS_NAME_LIST_REF 0x0200
 
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6f21ecb..06f6779 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -39,7 +39,7 @@
 			unsigned int /* length */ , struct sockaddr *, bool);
 extern unsigned int _GetXid(void);
 extern void _FreeXid(unsigned int);
-#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid));
+#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current_fsuid()));
 #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));}
 extern char *build_path_from_dentry(struct dentry *);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
@@ -330,7 +330,8 @@
 extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
 			     const struct nls_table *);
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
-extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key);
+extern void calc_lanman_hash(const char *password, const char *cryptkey,
+				bool encrypt, char *lnm_session_key);
 #endif /* CIFS_WEAK_PW_HASH */
 extern int CIFSSMBCopy(int xid,
 			struct cifsTconInfo *source_tcon,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 6d51696..552642a 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1382,13 +1382,13 @@
 		if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
 			*pOplock |= CIFS_CREATE_ACTION;
 		if (pfile_info) {
-		    memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
-			36 /* CreationTime to Attributes */);
-		    /* the file_info buf is endian converted by caller */
-		    pfile_info->AllocationSize = pSMBr->AllocationSize;
-		    pfile_info->EndOfFile = pSMBr->EndOfFile;
-		    pfile_info->NumberOfLinks = cpu_to_le32(1);
-		    pfile_info->DeletePending = 0;
+			memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
+				36 /* CreationTime to Attributes */);
+			/* the file_info buf is endian converted by caller */
+			pfile_info->AllocationSize = pSMBr->AllocationSize;
+			pfile_info->EndOfFile = pSMBr->EndOfFile;
+			pfile_info->NumberOfLinks = cpu_to_le32(1);
+			pfile_info->DeletePending = 0;
 		}
 	}
 
@@ -1414,8 +1414,13 @@
 	cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
 	if (tcon->ses->capabilities & CAP_LARGE_FILES)
 		wct = 12;
-	else
+	else {
 		wct = 10; /* old style read */
+		if ((lseek >> 32) > 0)  {
+			/* can not handle this big offset for old */
+			return -EIO;
+		}
+	}
 
 	*nbytes = 0;
 	rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
@@ -1431,8 +1436,6 @@
 	pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
 	if (wct == 12)
 		pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
-	else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
-		return -EIO;
 
 	pSMB->Remaining = 0;
 	pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
@@ -1519,8 +1522,13 @@
 
 	if (tcon->ses->capabilities & CAP_LARGE_FILES)
 		wct = 14;
-	else
+	else {
 		wct = 12;
+		if ((offset >> 32) > 0) {
+			/* can not handle big offset for old srv */
+			return -EIO;
+		}
+	}
 
 	rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
@@ -1535,8 +1543,6 @@
 	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
 	if (wct == 14)
 		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
-	else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
-		return -EIO;
 
 	pSMB->Reserved = 0xFFFFFFFF;
 	pSMB->WriteMode = 0;
@@ -1558,7 +1564,7 @@
 	pSMB->DataOffset =
 		cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
 	if (buf)
-	    memcpy(pSMB->Data, buf, bytes_sent);
+		memcpy(pSMB->Data, buf, bytes_sent);
 	else if (ubuf) {
 		if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
 			cifs_buf_release(pSMB);
@@ -1621,10 +1627,15 @@
 
 	cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
 
-	if (tcon->ses->capabilities & CAP_LARGE_FILES)
+	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
 		wct = 14;
-	else
+	} else {
 		wct = 12;
+		if ((offset >> 32) > 0) {
+			/* can not handle big offset for old srv */
+			return -EIO;
+		}
+	}
 	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
 	if (rc)
 		return rc;
@@ -1637,8 +1648,6 @@
 	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
 	if (wct == 14)
 		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
-	else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
-		return -EIO;
 	pSMB->Reserved = 0xFFFFFFFF;
 	pSMB->WriteMode = 0;
 	pSMB->Remaining = 0;
@@ -1862,10 +1871,6 @@
 			rc = -EIO;      /* bad smb */
 			goto plk_err_exit;
 		}
-		if (pLockData == NULL) {
-			rc = -EINVAL;
-			goto plk_err_exit;
-		}
 		data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
 		data_count  = le16_to_cpu(pSMBr->t2.DataCount);
 		if (data_count < sizeof(struct cifs_posix_lock)) {
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c7d3417..e9ea394 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -89,6 +89,7 @@
 	bool nullauth:1;   /* attempt to authenticate with null user */
 	bool nocase:1;     /* request case insensitive filenames */
 	bool nobrl:1;      /* disable sending byte range locks to srv */
+	bool mand_lock:1;  /* send mandatory not posix byte range lock reqs */
 	bool seal:1;       /* request transport encryption on share */
 	bool nodfs:1;      /* Do not request DFS, even if available */
 	bool local_lease:1; /* check leases only on local system, not remote */
@@ -101,25 +102,17 @@
 	char *prepath;
 };
 
-static int ipv4_connect(struct sockaddr_in *psin_server,
-			struct socket **csocket,
-			char *netb_name,
-			char *server_netb_name,
-			bool noblocksnd,
-			bool nosndbuf); /* ipv6 never set sndbuf size */
-static int ipv6_connect(struct sockaddr_in6 *psin_server,
-			struct socket **csocket, bool noblocksnd);
+static int ipv4_connect(struct TCP_Server_Info *server);
+static int ipv6_connect(struct TCP_Server_Info *server);
 
-
-	/*
-	 * cifs tcp session reconnection
-	 *
-	 * mark tcp session as reconnecting so temporarily locked
-	 * mark all smb sessions as reconnecting for tcp session
-	 * reconnect tcp session
-	 * wake up waiters on reconnection? - (not needed currently)
-	 */
-
+/*
+ * cifs tcp session reconnection
+ *
+ * mark tcp session as reconnecting so temporarily locked
+ * mark all smb sessions as reconnecting for tcp session
+ * reconnect tcp session
+ * wake up waiters on reconnection? - (not needed currently)
+ */
 static int
 cifs_reconnect(struct TCP_Server_Info *server)
 {
@@ -156,7 +149,7 @@
 	}
 	read_unlock(&cifs_tcp_ses_lock);
 	/* do not want to be sending data on a socket we are freeing */
-	down(&server->tcpSem);
+	mutex_lock(&server->srv_mutex);
 	if (server->ssocket) {
 		cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
 			server->ssocket->flags));
@@ -182,21 +175,15 @@
 		}
 	}
 	spin_unlock(&GlobalMid_Lock);
-	up(&server->tcpSem);
+	mutex_unlock(&server->srv_mutex);
 
 	while ((server->tcpStatus != CifsExiting) &&
 	       (server->tcpStatus != CifsGood)) {
 		try_to_freeze();
-		if (server->addr.sockAddr6.sin6_family == AF_INET6) {
-			rc = ipv6_connect(&server->addr.sockAddr6,
-					  &server->ssocket, server->noautotune);
-		} else {
-			rc = ipv4_connect(&server->addr.sockAddr,
-					&server->ssocket,
-					server->workstation_RFC1001_name,
-					server->server_RFC1001_name,
-					server->noblocksnd, server->noautotune);
-		}
+		if (server->addr.sockAddr6.sin6_family == AF_INET6)
+			rc = ipv6_connect(server);
+		else
+			rc = ipv4_connect(server);
 		if (rc) {
 			cFYI(1, ("reconnect error %d", rc));
 			msleep(3000);
@@ -776,7 +763,7 @@
 		set_current_state(TASK_RUNNING);
 	}
 
-	return 0;
+	module_put_and_exit(0);
 }
 
 /* extract the host portion of the UNC string */
@@ -836,8 +823,8 @@
 	/* null target name indicates to use *SMBSERVR default called name
 	   if we end up sending RFC1001 session initialize */
 	vol->target_rfc1001_name[0] = 0;
-	vol->linux_uid = current->uid;	/* current->euid instead? */
-	vol->linux_gid = current->gid;
+	vol->linux_uid = current_uid();  /* use current_euid() instead? */
+	vol->linux_gid = current_gid();
 	vol->dir_mode = S_IRWXUGO;
 	/* 2767 perms indicate mandatory locking support */
 	vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
@@ -1260,6 +1247,17 @@
 			if (vol->file_mode ==
 				(S_IALLUGO & ~(S_ISUID | S_IXGRP)))
 				vol->file_mode = S_IALLUGO;
+		} else if (strnicmp(data, "forcemandatorylock", 9) == 0) {
+			/* will take the shorter form "forcemand" as well */
+			/* This mount option will force use of mandatory
+			  (DOS/Windows style) byte range locks, instead of
+			  using posix advisory byte range locks, even if the
+			  Unix extensions are available and posix locks would
+			  be supported otherwise. If Unix extensions are not
+			  negotiated this has no effect since mandatory locks
+			  would be used (mandatory locks is all that those
+			  those servers support) */
+			vol->mand_lock = 1;
 		} else if (strnicmp(data, "setuids", 7) == 0) {
 			vol->setuids = 1;
 		} else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -1417,6 +1415,143 @@
 		force_sig(SIGKILL, task);
 }
 
+static struct TCP_Server_Info *
+cifs_get_tcp_session(struct smb_vol *volume_info)
+{
+	struct TCP_Server_Info *tcp_ses = NULL;
+	struct sockaddr addr;
+	struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
+	struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
+	int rc;
+
+	memset(&addr, 0, sizeof(struct sockaddr));
+
+	if (volume_info->UNCip && volume_info->UNC) {
+		rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
+				    &sin_server->sin_addr.s_addr);
+
+		if (rc <= 0) {
+			/* not ipv4 address, try ipv6 */
+			rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
+					    &sin_server6->sin6_addr.in6_u);
+			if (rc > 0)
+				addr.sa_family = AF_INET6;
+		} else {
+			addr.sa_family = AF_INET;
+		}
+
+		if (rc <= 0) {
+			/* we failed translating address */
+			rc = -EINVAL;
+			goto out_err;
+		}
+
+		cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
+			 volume_info->UNCip));
+	} else if (volume_info->UNCip) {
+		/* BB using ip addr as tcp_ses name to connect to the
+		   DFS root below */
+		cERROR(1, ("Connecting to DFS root not implemented yet"));
+		rc = -EINVAL;
+		goto out_err;
+	} else /* which tcp_sess DFS root would we conect to */ {
+		cERROR(1,
+		       ("CIFS mount error: No UNC path (e.g. -o "
+			"unc=//192.168.1.100/public) specified"));
+		rc = -EINVAL;
+		goto out_err;
+	}
+
+	/* see if we already have a matching tcp_ses */
+	tcp_ses = cifs_find_tcp_session(&addr);
+	if (tcp_ses)
+		return tcp_ses;
+
+	tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
+	if (!tcp_ses) {
+		rc = -ENOMEM;
+		goto out_err;
+	}
+
+	tcp_ses->hostname = extract_hostname(volume_info->UNC);
+	if (IS_ERR(tcp_ses->hostname)) {
+		rc = PTR_ERR(tcp_ses->hostname);
+		goto out_err;
+	}
+
+	tcp_ses->noblocksnd = volume_info->noblocksnd;
+	tcp_ses->noautotune = volume_info->noautotune;
+	atomic_set(&tcp_ses->inFlight, 0);
+	init_waitqueue_head(&tcp_ses->response_q);
+	init_waitqueue_head(&tcp_ses->request_q);
+	INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
+	mutex_init(&tcp_ses->srv_mutex);
+	memcpy(tcp_ses->workstation_RFC1001_name,
+		volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
+	memcpy(tcp_ses->server_RFC1001_name,
+		volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
+	tcp_ses->sequence_number = 0;
+	INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
+	INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
+
+	/*
+	 * at this point we are the only ones with the pointer
+	 * to the struct since the kernel thread not created yet
+	 * no need to spinlock this init of tcpStatus or srv_count
+	 */
+	tcp_ses->tcpStatus = CifsNew;
+	++tcp_ses->srv_count;
+
+	if (addr.sa_family == AF_INET6) {
+		cFYI(1, ("attempting ipv6 connect"));
+		/* BB should we allow ipv6 on port 139? */
+		/* other OS never observed in Wild doing 139 with v6 */
+		memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
+			sizeof(struct sockaddr_in6));
+		sin_server6->sin6_port = htons(volume_info->port);
+		rc = ipv6_connect(tcp_ses);
+	} else {
+		memcpy(&tcp_ses->addr.sockAddr, sin_server,
+			sizeof(struct sockaddr_in));
+		sin_server->sin_port = htons(volume_info->port);
+		rc = ipv4_connect(tcp_ses);
+	}
+	if (rc < 0) {
+		cERROR(1, ("Error connecting to socket. Aborting operation"));
+		goto out_err;
+	}
+
+	/*
+	 * since we're in a cifs function already, we know that
+	 * this will succeed. No need for try_module_get().
+	 */
+	__module_get(THIS_MODULE);
+	tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
+				  tcp_ses, "cifsd");
+	if (IS_ERR(tcp_ses->tsk)) {
+		rc = PTR_ERR(tcp_ses->tsk);
+		cERROR(1, ("error %d create cifsd thread", rc));
+		module_put(THIS_MODULE);
+		goto out_err;
+	}
+
+	/* thread spawned, put it on the list */
+	write_lock(&cifs_tcp_ses_lock);
+	list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
+	write_unlock(&cifs_tcp_ses_lock);
+
+	return tcp_ses;
+
+out_err:
+	if (tcp_ses) {
+		kfree(tcp_ses->hostname);
+		if (tcp_ses->ssocket)
+			sock_release(tcp_ses->ssocket);
+		kfree(tcp_ses);
+	}
+	return ERR_PTR(rc);
+}
+
 static struct cifsSesInfo *
 cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
 {
@@ -1593,93 +1728,96 @@
 
 
 static int
-ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
-	     char *netbios_name, char *target_name,
-	     bool noblocksnd, bool noautotune)
+ipv4_connect(struct TCP_Server_Info *server)
 {
 	int rc = 0;
-	int connected = 0;
+	bool connected = false;
 	__be16 orig_port = 0;
+	struct socket *socket = server->ssocket;
 
-	if (*csocket == NULL) {
+	if (socket == NULL) {
 		rc = sock_create_kern(PF_INET, SOCK_STREAM,
-				      IPPROTO_TCP, csocket);
+				      IPPROTO_TCP, &socket);
 		if (rc < 0) {
 			cERROR(1, ("Error %d creating socket", rc));
-			*csocket = NULL;
 			return rc;
-		} else {
-		/* BB other socket options to set KEEPALIVE, NODELAY? */
-			cFYI(1, ("Socket created"));
-			(*csocket)->sk->sk_allocation = GFP_NOFS;
-			cifs_reclassify_socket4(*csocket);
 		}
+
+		/* BB other socket options to set KEEPALIVE, NODELAY? */
+		cFYI(1, ("Socket created"));
+		server->ssocket = socket;
+		socket->sk->sk_allocation = GFP_NOFS;
+		cifs_reclassify_socket4(socket);
 	}
 
-	psin_server->sin_family = AF_INET;
-	if (psin_server->sin_port) { /* user overrode default port */
-		rc = (*csocket)->ops->connect(*csocket,
-				(struct sockaddr *) psin_server,
-				sizeof(struct sockaddr_in), 0);
+	/* user overrode default port */
+	if (server->addr.sockAddr.sin_port) {
+		rc = socket->ops->connect(socket, (struct sockaddr *)
+					  &server->addr.sockAddr,
+					  sizeof(struct sockaddr_in), 0);
 		if (rc >= 0)
-			connected = 1;
+			connected = true;
 	}
 
 	if (!connected) {
 		/* save original port so we can retry user specified port
 			later if fall back ports fail this time  */
-		orig_port = psin_server->sin_port;
+		orig_port = server->addr.sockAddr.sin_port;
 
 		/* do not retry on the same port we just failed on */
-		if (psin_server->sin_port != htons(CIFS_PORT)) {
-			psin_server->sin_port = htons(CIFS_PORT);
-
-			rc = (*csocket)->ops->connect(*csocket,
-					(struct sockaddr *) psin_server,
-					sizeof(struct sockaddr_in), 0);
+		if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
+			server->addr.sockAddr.sin_port = htons(CIFS_PORT);
+			rc = socket->ops->connect(socket,
+						(struct sockaddr *)
+						&server->addr.sockAddr,
+						sizeof(struct sockaddr_in), 0);
 			if (rc >= 0)
-				connected = 1;
+				connected = true;
 		}
 	}
 	if (!connected) {
-		psin_server->sin_port = htons(RFC1001_PORT);
-		rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
-					      psin_server,
+		server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
+		rc = socket->ops->connect(socket, (struct sockaddr *)
+					      &server->addr.sockAddr,
 					      sizeof(struct sockaddr_in), 0);
 		if (rc >= 0)
-			connected = 1;
+			connected = true;
 	}
 
 	/* give up here - unless we want to retry on different
 		protocol families some day */
 	if (!connected) {
 		if (orig_port)
-			psin_server->sin_port = orig_port;
+			server->addr.sockAddr.sin_port = orig_port;
 		cFYI(1, ("Error %d connecting to server via ipv4", rc));
-		sock_release(*csocket);
-		*csocket = NULL;
+		sock_release(socket);
+		server->ssocket = NULL;
 		return rc;
 	}
-	/* Eventually check for other socket options to change from
-		the default. sock_setsockopt not used because it expects
-		user space buffer */
-	 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
-		 (*csocket)->sk->sk_sndbuf,
-		 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
-	(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
-	if (!noblocksnd)
-		(*csocket)->sk->sk_sndtimeo = 3 * HZ;
+
+
+	/*
+	 * Eventually check for other socket options to change from
+	 *  the default. sock_setsockopt not used because it expects
+	 *  user space buffer
+	 */
+	socket->sk->sk_rcvtimeo = 7 * HZ;
+	socket->sk->sk_sndtimeo = 3 * HZ;
 
 	/* make the bufsizes depend on wsize/rsize and max requests */
-	if (noautotune) {
-		if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
-			(*csocket)->sk->sk_sndbuf = 200 * 1024;
-		if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
-			(*csocket)->sk->sk_rcvbuf = 140 * 1024;
+	if (server->noautotune) {
+		if (socket->sk->sk_sndbuf < (200 * 1024))
+			socket->sk->sk_sndbuf = 200 * 1024;
+		if (socket->sk->sk_rcvbuf < (140 * 1024))
+			socket->sk->sk_rcvbuf = 140 * 1024;
 	}
 
+	 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
+		 socket->sk->sk_sndbuf,
+		 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo));
+
 	/* send RFC1001 sessinit */
-	if (psin_server->sin_port == htons(RFC1001_PORT)) {
+	if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
 		/* some servers require RFC1001 sessinit before sending
 		negprot - BB check reconnection in case where second
 		sessinit is sent but no second negprot */
@@ -1689,31 +1827,42 @@
 				       GFP_KERNEL);
 		if (ses_init_buf) {
 			ses_init_buf->trailer.session_req.called_len = 32;
-			if (target_name && (target_name[0] != 0)) {
-				rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
-					target_name, 16);
-			} else {
-				rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
-					DEFAULT_CIFS_CALLED_NAME, 16);
-			}
+			if (server->server_RFC1001_name &&
+			    server->server_RFC1001_name[0] != 0)
+				rfc1002mangle(ses_init_buf->trailer.
+						session_req.called_name,
+					      server->server_RFC1001_name,
+					      RFC1001_NAME_LEN_WITH_NULL);
+			else
+				rfc1002mangle(ses_init_buf->trailer.
+						session_req.called_name,
+					      DEFAULT_CIFS_CALLED_NAME,
+					      RFC1001_NAME_LEN_WITH_NULL);
 
 			ses_init_buf->trailer.session_req.calling_len = 32;
+
 			/* calling name ends in null (byte 16) from old smb
 			convention. */
-			if (netbios_name && (netbios_name[0] != 0)) {
-				rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
-					netbios_name, 16);
-			} else {
-				rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
-					"LINUX_CIFS_CLNT", 16);
-			}
+			if (server->workstation_RFC1001_name &&
+			    server->workstation_RFC1001_name[0] != 0)
+				rfc1002mangle(ses_init_buf->trailer.
+						session_req.calling_name,
+					      server->workstation_RFC1001_name,
+					      RFC1001_NAME_LEN_WITH_NULL);
+			else
+				rfc1002mangle(ses_init_buf->trailer.
+						session_req.calling_name,
+					      "LINUX_CIFS_CLNT",
+					      RFC1001_NAME_LEN_WITH_NULL);
+
 			ses_init_buf->trailer.session_req.scope1 = 0;
 			ses_init_buf->trailer.session_req.scope2 = 0;
 			smb_buf = (struct smb_hdr *)ses_init_buf;
 			/* sizeof RFC1002_SESSION_REQUEST with no scope */
 			smb_buf->smb_buf_length = 0x81000044;
-			rc = smb_send(*csocket, smb_buf, 0x44,
-				(struct sockaddr *)psin_server, noblocksnd);
+			rc = smb_send(socket, smb_buf, 0x44,
+				(struct sockaddr *) &server->addr.sockAddr,
+				server->noblocksnd);
 			kfree(ses_init_buf);
 			msleep(1); /* RFC1001 layer in at least one server
 				      requires very short break before negprot
@@ -1733,79 +1882,81 @@
 }
 
 static int
-ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket,
-	     bool noblocksnd)
+ipv6_connect(struct TCP_Server_Info *server)
 {
 	int rc = 0;
-	int connected = 0;
+	bool connected = false;
 	__be16 orig_port = 0;
+	struct socket *socket = server->ssocket;
 
-	if (*csocket == NULL) {
+	if (socket == NULL) {
 		rc = sock_create_kern(PF_INET6, SOCK_STREAM,
-				      IPPROTO_TCP, csocket);
+				      IPPROTO_TCP, &socket);
 		if (rc < 0) {
 			cERROR(1, ("Error %d creating ipv6 socket", rc));
-			*csocket = NULL;
+			socket = NULL;
 			return rc;
-		} else {
-		/* BB other socket options to set KEEPALIVE, NODELAY? */
-			 cFYI(1, ("ipv6 Socket created"));
-			(*csocket)->sk->sk_allocation = GFP_NOFS;
-			cifs_reclassify_socket6(*csocket);
 		}
+
+		/* BB other socket options to set KEEPALIVE, NODELAY? */
+		cFYI(1, ("ipv6 Socket created"));
+		server->ssocket = socket;
+		socket->sk->sk_allocation = GFP_NOFS;
+		cifs_reclassify_socket6(socket);
 	}
 
-	psin_server->sin6_family = AF_INET6;
-
-	if (psin_server->sin6_port) { /* user overrode default port */
-		rc = (*csocket)->ops->connect(*csocket,
-				(struct sockaddr *) psin_server,
+	/* user overrode default port */
+	if (server->addr.sockAddr6.sin6_port) {
+		rc = socket->ops->connect(socket,
+				(struct sockaddr *) &server->addr.sockAddr6,
 				sizeof(struct sockaddr_in6), 0);
 		if (rc >= 0)
-			connected = 1;
+			connected = true;
 	}
 
 	if (!connected) {
 		/* save original port so we can retry user specified port
 			later if fall back ports fail this time  */
 
-		orig_port = psin_server->sin6_port;
+		orig_port = server->addr.sockAddr6.sin6_port;
 		/* do not retry on the same port we just failed on */
-		if (psin_server->sin6_port != htons(CIFS_PORT)) {
-			psin_server->sin6_port = htons(CIFS_PORT);
-
-			rc = (*csocket)->ops->connect(*csocket,
-					(struct sockaddr *) psin_server,
+		if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
+			server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
+			rc = socket->ops->connect(socket, (struct sockaddr *)
+					&server->addr.sockAddr6,
 					sizeof(struct sockaddr_in6), 0);
 			if (rc >= 0)
-				connected = 1;
+				connected = true;
 		}
 	}
 	if (!connected) {
-		psin_server->sin6_port = htons(RFC1001_PORT);
-		rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
-				 psin_server, sizeof(struct sockaddr_in6), 0);
+		server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
+		rc = socket->ops->connect(socket, (struct sockaddr *)
+				&server->addr.sockAddr6,
+				sizeof(struct sockaddr_in6), 0);
 		if (rc >= 0)
-			connected = 1;
+			connected = true;
 	}
 
 	/* give up here - unless we want to retry on different
 		protocol families some day */
 	if (!connected) {
 		if (orig_port)
-			psin_server->sin6_port = orig_port;
+			server->addr.sockAddr6.sin6_port = orig_port;
 		cFYI(1, ("Error %d connecting to server via ipv6", rc));
-		sock_release(*csocket);
-		*csocket = NULL;
+		sock_release(socket);
+		server->ssocket = NULL;
 		return rc;
 	}
-	/* Eventually check for other socket options to change from
-		the default. sock_setsockopt not used because it expects
-		user space buffer */
-	(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
-	if (!noblocksnd)
-		(*csocket)->sk->sk_sndtimeo = 3 * HZ;
 
+	/*
+	 * Eventually check for other socket options to change from
+	 * the default. sock_setsockopt not used because it expects
+	 * user space buffer
+	 */
+	socket->sk->sk_rcvtimeo = 7 * HZ;
+	socket->sk->sk_sndtimeo = 3 * HZ;
+	server->ssocket = socket;
 
 	return rc;
 }
@@ -2011,6 +2162,8 @@
 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
 	if (pvolume_info->nobrl)
 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
+	if (pvolume_info->mand_lock)
+		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
 	if (pvolume_info->cifs_acl)
 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
 	if (pvolume_info->override_uid)
@@ -2035,32 +2188,30 @@
 {
 	int rc = 0;
 	int xid;
-	struct socket *csocket = NULL;
-	struct sockaddr addr;
-	struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
-	struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
-	struct smb_vol volume_info;
+	struct smb_vol *volume_info;
 	struct cifsSesInfo *pSesInfo = NULL;
 	struct cifsTconInfo *tcon = NULL;
 	struct TCP_Server_Info *srvTcp = NULL;
 
 	xid = GetXid();
 
-/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
+	volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
+	if (!volume_info) {
+		rc = -ENOMEM;
+		goto out;
+	}
 
-	memset(&addr, 0, sizeof(struct sockaddr));
-	memset(&volume_info, 0, sizeof(struct smb_vol));
-	if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
+	if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
 		rc = -EINVAL;
 		goto out;
 	}
 
-	if (volume_info.nullauth) {
+	if (volume_info->nullauth) {
 		cFYI(1, ("null user"));
-		volume_info.username = "";
-	} else if (volume_info.username) {
+		volume_info->username = "";
+	} else if (volume_info->username) {
 		/* BB fixme parse for domain name here */
-		cFYI(1, ("Username: %s", volume_info.username));
+		cFYI(1, ("Username: %s", volume_info->username));
 	} else {
 		cifserror("No username specified");
 	/* In userspace mount helper we can get user name from alternate
@@ -2069,139 +2220,29 @@
 		goto out;
 	}
 
-	if (volume_info.UNCip && volume_info.UNC) {
-		rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
-				    &sin_server->sin_addr.s_addr);
-
-		if (rc <= 0) {
-			/* not ipv4 address, try ipv6 */
-			rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
-					    &sin_server6->sin6_addr.in6_u);
-			if (rc > 0)
-				addr.sa_family = AF_INET6;
-		} else {
-			addr.sa_family = AF_INET;
-		}
-
-		if (rc <= 0) {
-			/* we failed translating address */
-			rc = -EINVAL;
-			goto out;
-		}
-
-		cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
-		/* success */
-		rc = 0;
-	} else if (volume_info.UNCip) {
-		/* BB using ip addr as server name to connect to the
-		   DFS root below */
-		cERROR(1, ("Connecting to DFS root not implemented yet"));
-		rc = -EINVAL;
-		goto out;
-	} else /* which servers DFS root would we conect to */ {
-		cERROR(1,
-		       ("CIFS mount error: No UNC path (e.g. -o "
-			"unc=//192.168.1.100/public) specified"));
-		rc = -EINVAL;
-		goto out;
-	}
 
 	/* this is needed for ASCII cp to Unicode converts */
-	if (volume_info.iocharset == NULL) {
+	if (volume_info->iocharset == NULL) {
 		cifs_sb->local_nls = load_nls_default();
 	/* load_nls_default can not return null */
 	} else {
-		cifs_sb->local_nls = load_nls(volume_info.iocharset);
+		cifs_sb->local_nls = load_nls(volume_info->iocharset);
 		if (cifs_sb->local_nls == NULL) {
 			cERROR(1, ("CIFS mount error: iocharset %s not found",
-				 volume_info.iocharset));
+				 volume_info->iocharset));
 			rc = -ELIBACC;
 			goto out;
 		}
 	}
 
-	srvTcp = cifs_find_tcp_session(&addr);
-	if (!srvTcp) { /* create socket */
-		if (addr.sa_family == AF_INET6) {
-			cFYI(1, ("attempting ipv6 connect"));
-			/* BB should we allow ipv6 on port 139? */
-			/* other OS never observed in Wild doing 139 with v6 */
-			sin_server6->sin6_port = htons(volume_info.port);
-			rc = ipv6_connect(sin_server6, &csocket,
-					volume_info.noblocksnd);
-		} else {
-			sin_server->sin_port = htons(volume_info.port);
-			rc = ipv4_connect(sin_server, &csocket,
-				  volume_info.source_rfc1001_name,
-				  volume_info.target_rfc1001_name,
-				  volume_info.noblocksnd,
-				  volume_info.noautotune);
-		}
-		if (rc < 0) {
-			cERROR(1, ("Error connecting to socket. "
-				   "Aborting operation"));
-			if (csocket != NULL)
-				sock_release(csocket);
-			goto out;
-		}
-
-		srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
-		if (!srvTcp) {
-			rc = -ENOMEM;
-			sock_release(csocket);
-			goto out;
-		} else {
-			srvTcp->noblocksnd = volume_info.noblocksnd;
-			srvTcp->noautotune = volume_info.noautotune;
-			if (addr.sa_family == AF_INET6)
-				memcpy(&srvTcp->addr.sockAddr6, sin_server6,
-					sizeof(struct sockaddr_in6));
-			else
-				memcpy(&srvTcp->addr.sockAddr, sin_server,
-					sizeof(struct sockaddr_in));
-			atomic_set(&srvTcp->inFlight, 0);
-			/* BB Add code for ipv6 case too */
-			srvTcp->ssocket = csocket;
-			srvTcp->hostname = extract_hostname(volume_info.UNC);
-			if (IS_ERR(srvTcp->hostname)) {
-				rc = PTR_ERR(srvTcp->hostname);
-				sock_release(csocket);
-				goto out;
-			}
-			init_waitqueue_head(&srvTcp->response_q);
-			init_waitqueue_head(&srvTcp->request_q);
-			INIT_LIST_HEAD(&srvTcp->pending_mid_q);
-			/* at this point we are the only ones with the pointer
-			to the struct since the kernel thread not created yet
-			so no need to spinlock this init of tcpStatus */
-			srvTcp->tcpStatus = CifsNew;
-			init_MUTEX(&srvTcp->tcpSem);
-			srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
-			if (IS_ERR(srvTcp->tsk)) {
-				rc = PTR_ERR(srvTcp->tsk);
-				cERROR(1, ("error %d create cifsd thread", rc));
-				srvTcp->tsk = NULL;
-				sock_release(csocket);
-				kfree(srvTcp->hostname);
-				goto out;
-			}
-			rc = 0;
-			memcpy(srvTcp->workstation_RFC1001_name,
-				volume_info.source_rfc1001_name, 16);
-			memcpy(srvTcp->server_RFC1001_name,
-				volume_info.target_rfc1001_name, 16);
-			srvTcp->sequence_number = 0;
-			INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
-			INIT_LIST_HEAD(&srvTcp->smb_ses_list);
-			++srvTcp->srv_count;
-			write_lock(&cifs_tcp_ses_lock);
-			list_add(&srvTcp->tcp_ses_list,
-				 &cifs_tcp_ses_list);
-			write_unlock(&cifs_tcp_ses_lock);
-		}
+	/* get a reference to a tcp session */
+	srvTcp = cifs_get_tcp_session(volume_info);
+	if (IS_ERR(srvTcp)) {
+		rc = PTR_ERR(srvTcp);
+		goto out;
 	}
 
-	pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
+	pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username);
 	if (pSesInfo) {
 		cFYI(1, ("Existing smb sess found (status=%d)",
 			pSesInfo->status));
@@ -2228,31 +2269,38 @@
 
 		/* new SMB session uses our srvTcp ref */
 		pSesInfo->server = srvTcp;
-		sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
-			NIPQUAD(sin_server->sin_addr.s_addr));
+		if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
+			sprintf(pSesInfo->serverName, "%pI6",
+				&srvTcp->addr.sockAddr6.sin6_addr);
+		else
+			sprintf(pSesInfo->serverName, "%pI4",
+				&srvTcp->addr.sockAddr.sin_addr.s_addr);
 
 		write_lock(&cifs_tcp_ses_lock);
 		list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
 		write_unlock(&cifs_tcp_ses_lock);
 
-		/* volume_info.password freed at unmount */
-		if (volume_info.password) {
-			pSesInfo->password = volume_info.password;
-			/* set to NULL to prevent freeing on exit */
-			volume_info.password = NULL;
+		/* volume_info->password freed at unmount */
+		if (volume_info->password) {
+			pSesInfo->password = kstrdup(volume_info->password,
+						     GFP_KERNEL);
+			if (!pSesInfo->password) {
+				rc = -ENOMEM;
+				goto mount_fail_check;
+			}
 		}
-		if (volume_info.username)
-			strncpy(pSesInfo->userName, volume_info.username,
+		if (volume_info->username)
+			strncpy(pSesInfo->userName, volume_info->username,
 				MAX_USERNAME_SIZE);
-		if (volume_info.domainname) {
-			int len = strlen(volume_info.domainname);
+		if (volume_info->domainname) {
+			int len = strlen(volume_info->domainname);
 			pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
 			if (pSesInfo->domainName)
 				strcpy(pSesInfo->domainName,
-					volume_info.domainname);
+					volume_info->domainname);
 		}
-		pSesInfo->linux_uid = volume_info.linux_uid;
-		pSesInfo->overrideSecFlg = volume_info.secFlg;
+		pSesInfo->linux_uid = volume_info->linux_uid;
+		pSesInfo->overrideSecFlg = volume_info->secFlg;
 		down(&pSesInfo->sesSem);
 
 		/* BB FIXME need to pass vol->secFlgs BB */
@@ -2263,14 +2311,14 @@
 
 	/* search for existing tcon to this server share */
 	if (!rc) {
-		setup_cifs_sb(&volume_info, cifs_sb);
+		setup_cifs_sb(volume_info, cifs_sb);
 
-		tcon = cifs_find_tcon(pSesInfo, volume_info.UNC);
+		tcon = cifs_find_tcon(pSesInfo, volume_info->UNC);
 		if (tcon) {
 			cFYI(1, ("Found match on UNC path"));
 			/* existing tcon already has a reference */
 			cifs_put_smb_ses(pSesInfo);
-			if (tcon->seal != volume_info.seal)
+			if (tcon->seal != volume_info->seal)
 				cERROR(1, ("transport encryption setting "
 					   "conflicts with existing tid"));
 		} else {
@@ -2279,11 +2327,20 @@
 				rc = -ENOMEM;
 				goto mount_fail_check;
 			}
+
 			tcon->ses = pSesInfo;
+			if (volume_info->password) {
+				tcon->password = kstrdup(volume_info->password,
+							 GFP_KERNEL);
+				if (!tcon->password) {
+					rc = -ENOMEM;
+					goto mount_fail_check;
+				}
+			}
 
 			/* check for null share name ie connect to dfs root */
-			if ((strchr(volume_info.UNC + 3, '\\') == NULL)
-			    && (strchr(volume_info.UNC + 3, '/') == NULL)) {
+			if ((strchr(volume_info->UNC + 3, '\\') == NULL)
+			    && (strchr(volume_info->UNC + 3, '/') == NULL)) {
 				/* rc = connect_to_dfs_path(...) */
 				cFYI(1, ("DFS root not supported"));
 				rc = -ENODEV;
@@ -2292,10 +2349,10 @@
 				/* BB Do we need to wrap sesSem around
 				 * this TCon call and Unix SetFS as
 				 * we do on SessSetup and reconnect? */
-				rc = CIFSTCon(xid, pSesInfo, volume_info.UNC,
+				rc = CIFSTCon(xid, pSesInfo, volume_info->UNC,
 					      tcon, cifs_sb->local_nls);
 				cFYI(1, ("CIFS Tcon rc = %d", rc));
-				if (volume_info.nodfs) {
+				if (volume_info->nodfs) {
 					tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
 					cFYI(1, ("DFS disabled (%d)",
 						tcon->Flags));
@@ -2303,7 +2360,7 @@
 			}
 			if (rc)
 				goto mount_fail_check;
-			tcon->seal = volume_info.seal;
+			tcon->seal = volume_info->seal;
 			write_lock(&cifs_tcp_ses_lock);
 			list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
 			write_unlock(&cifs_tcp_ses_lock);
@@ -2313,9 +2370,9 @@
 		   to a share so for resources mounted more than once
 		   to the same server share the last value passed in
 		   for the retry flag is used */
-		tcon->retry = volume_info.retry;
-		tcon->nocase = volume_info.nocase;
-		tcon->local_lease = volume_info.local_lease;
+		tcon->retry = volume_info->retry;
+		tcon->nocase = volume_info->nocase;
+		tcon->local_lease = volume_info->local_lease;
 	}
 	if (pSesInfo) {
 		if (pSesInfo->capabilities & CAP_LARGE_FILES) {
@@ -2352,7 +2409,7 @@
 	if (tcon->ses->capabilities & CAP_UNIX)
 		/* reset of caps checks mount to see if unix extensions
 		   disabled for just this mount */
-		reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
+		reset_cifs_unix_caps(xid, tcon, sb, volume_info);
 	else
 		tcon->unix_ext = 0; /* server does not support them */
 
@@ -2371,18 +2428,22 @@
 		cifs_sb->rsize = min(cifs_sb->rsize,
 			       (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
 
-	/* volume_info.password is freed above when existing session found
+	/* volume_info->password is freed above when existing session found
 	(in which case it is not needed anymore) but when new sesion is created
 	the password ptr is put in the new session structure (in which case the
 	password will be freed at unmount time) */
 out:
 	/* zero out password before freeing */
-	if (volume_info.password != NULL) {
-		memset(volume_info.password, 0, strlen(volume_info.password));
-		kfree(volume_info.password);
+	if (volume_info) {
+		if (volume_info->password != NULL) {
+			memset(volume_info->password, 0,
+				strlen(volume_info->password));
+			kfree(volume_info->password);
+		}
+		kfree(volume_info->UNC);
+		kfree(volume_info->prepath);
+		kfree(volume_info);
 	}
-	kfree(volume_info.UNC);
-	kfree(volume_info.prepath);
 	FreeXid(xid);
 	return rc;
 }
@@ -2533,7 +2594,7 @@
 		__u16 action = le16_to_cpu(pSMBr->resp.Action);
 		__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
 		if (action & GUEST_LOGIN)
-			cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
+			cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */
 		ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
 							 (little endian) */
 		cFYI(1, ("UID = %d ", ses->Suid));
@@ -2679,13 +2740,11 @@
 					      len));
 			}
 		} else {
-			cERROR(1,
-			       (" Security Blob Length extends beyond "
+			cERROR(1, ("Security Blob Length extends beyond "
 				"end of SMB"));
 		}
 	} else {
-		cERROR(1,
-		       (" Invalid Word count %d: ",
+		cERROR(1, ("Invalid Word count %d: ",
 			smb_buffer_response->WordCount));
 		rc = -EIO;
 	}
@@ -2843,7 +2902,7 @@
 		__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
 
 		if (action & GUEST_LOGIN)
-			cFYI(1, (" Guest login"));
+			cFYI(1, ("Guest login"));
 	/* Do we want to set anything in SesInfo struct when guest login? */
 
 		bcc_ptr = pByteArea(smb_buffer_response);
@@ -2851,8 +2910,7 @@
 
 		SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
 		if (SecurityBlob2->MessageType != NtLmChallenge) {
-			cFYI(1,
-			     ("Unexpected NTLMSSP message type received %d",
+			cFYI(1, ("Unexpected NTLMSSP message type received %d",
 			      SecurityBlob2->MessageType));
 		} else if (ses) {
 			ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
@@ -3024,8 +3082,7 @@
 			cERROR(1, ("No session structure passed in."));
 		}
 	} else {
-		cERROR(1,
-		       (" Invalid Word count %d:",
+		cERROR(1, ("Invalid Word count %d:",
 			smb_buffer_response->WordCount));
 		rc = -EIO;
 	}
@@ -3264,7 +3321,7 @@
 		__u16 action = le16_to_cpu(pSMBr->resp.Action);
 		__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
 		if (action & GUEST_LOGIN)
-			cFYI(1, (" Guest login")); /* BB Should we set anything
+			cFYI(1, ("Guest login")); /* BB Should we set anything
 							 in SesInfo struct ? */
 /*		if (SecurityBlob2->MessageType != NtLm??) {
 			cFYI("Unexpected message type on auth response is %d"));
@@ -3487,12 +3544,14 @@
 		   NTLMv2 password here) */
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 		if ((extended_security & CIFSSEC_MAY_LANMAN) &&
-			(ses->server->secType == LANMAN))
-			calc_lanman_hash(ses, bcc_ptr);
+		    (ses->server->secType == LANMAN))
+			calc_lanman_hash(tcon->password, ses->server->cryptKey,
+					 ses->server->secMode &
+					    SECMODE_PW_ENCRYPT ? true : false,
+					 bcc_ptr);
 		else
 #endif /* CIFS_WEAK_PW_HASH */
-		SMBNTencrypt(ses->password,
-			     ses->server->cryptKey,
+		SMBNTencrypt(tcon->password, ses->server->cryptKey,
 			     bcc_ptr);
 
 		bcc_ptr += CIFS_SESS_KEY_SIZE;
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index e962e75..838d9c7 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -235,11 +235,11 @@
 			};
 
 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-				args.uid = (__u64) current->fsuid;
+				args.uid = (__u64) current_fsuid();
 				if (inode->i_mode & S_ISGID)
 					args.gid = (__u64) inode->i_gid;
 				else
-					args.gid = (__u64) current->fsgid;
+					args.gid = (__u64) current_fsgid();
 			} else {
 				args.uid = NO_CHANGE_64;
 				args.gid = NO_CHANGE_64;
@@ -271,13 +271,13 @@
 				if ((oplock & CIFS_CREATE_ACTION) &&
 				    (cifs_sb->mnt_cifs_flags &
 				     CIFS_MOUNT_SET_UID)) {
-					newinode->i_uid = current->fsuid;
+					newinode->i_uid = current_fsuid();
 					if (inode->i_mode & S_ISGID)
 						newinode->i_gid =
 							inode->i_gid;
 					else
 						newinode->i_gid =
-							current->fsgid;
+							current_fsgid();
 				}
 			}
 		}
@@ -375,8 +375,8 @@
 			.device	= device_number,
 		};
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-			args.uid = (__u64) current->fsuid;
-			args.gid = (__u64) current->fsgid;
+			args.uid = (__u64) current_fsuid();
+			args.gid = (__u64) current_fsgid();
 		} else {
 			args.uid = NO_CHANGE_64;
 			args.gid = NO_CHANGE_64;
@@ -483,7 +483,7 @@
 
 	xid = GetXid();
 
-	cFYI(1, (" parent inode = 0x%p name is: %s and dentry = 0x%p",
+	cFYI(1, ("parent inode = 0x%p name is: %s and dentry = 0x%p",
 	      parent_dir_inode, direntry->d_name.name, direntry));
 
 	/* check whether path exists */
@@ -515,12 +515,11 @@
 	}
 
 	if (direntry->d_inode != NULL) {
-		cFYI(1, (" non-NULL inode in lookup"));
+		cFYI(1, ("non-NULL inode in lookup"));
 	} else {
-		cFYI(1, (" NULL inode in lookup"));
+		cFYI(1, ("NULL inode in lookup"));
 	}
-	cFYI(1,
-	     (" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
+	cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
 
 	if (pTcon->unix_ext)
 		rc = cifs_get_inode_info_unix(&newInode, full_path,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index f0a81e6..b1e1fc6 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -644,10 +644,10 @@
 	__u64 length;
 	bool wait_flag = false;
 	struct cifs_sb_info *cifs_sb;
-	struct cifsTconInfo *pTcon;
+	struct cifsTconInfo *tcon;
 	__u16 netfid;
 	__u8 lockType = LOCKING_ANDX_LARGE_FILES;
-	bool posix_locking;
+	bool posix_locking = 0;
 
 	length = 1 + pfLock->fl_end - pfLock->fl_start;
 	rc = -EACCES;
@@ -698,7 +698,7 @@
 		cFYI(1, ("Unknown type of lock"));
 
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	pTcon = cifs_sb->tcon;
+	tcon = cifs_sb->tcon;
 
 	if (file->private_data == NULL) {
 		FreeXid(xid);
@@ -706,9 +706,10 @@
 	}
 	netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
 
-	posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
-			(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));
-
+	if ((tcon->ses->capabilities & CAP_UNIX) &&
+	    (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
+	    ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+		posix_locking = 1;
 	/* BB add code here to normalize offset and length to
 	account for negative length which we can not accept over the
 	wire */
@@ -719,7 +720,7 @@
 				posix_lock_type = CIFS_RDLCK;
 			else
 				posix_lock_type = CIFS_WRLCK;
-			rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
+			rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
 					length,	pfLock,
 					posix_lock_type, wait_flag);
 			FreeXid(xid);
@@ -727,10 +728,10 @@
 		}
 
 		/* BB we could chain these into one lock request BB */
-		rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+		rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
 				 0, 1, lockType, 0 /* wait flag */ );
 		if (rc == 0) {
-			rc = CIFSSMBLock(xid, pTcon, netfid, length,
+			rc = CIFSSMBLock(xid, tcon, netfid, length,
 					 pfLock->fl_start, 1 /* numUnlock */ ,
 					 0 /* numLock */ , lockType,
 					 0 /* wait flag */ );
@@ -767,7 +768,7 @@
 		if (numUnlock == 1)
 			posix_lock_type = CIFS_UNLCK;
 
-		rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
+		rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
 				      length, pfLock,
 				      posix_lock_type, wait_flag);
 	} else {
@@ -775,7 +776,7 @@
 			(struct cifsFileInfo *)file->private_data;
 
 		if (numLock) {
-			rc = CIFSSMBLock(xid, pTcon, netfid, length,
+			rc = CIFSSMBLock(xid, tcon, netfid, length,
 					pfLock->fl_start,
 					0, numLock, lockType, wait_flag);
 
@@ -796,7 +797,7 @@
 				if (pfLock->fl_start <= li->offset &&
 						(pfLock->fl_start + length) >=
 						(li->offset + li->length)) {
-					stored_rc = CIFSSMBLock(xid, pTcon,
+					stored_rc = CIFSSMBLock(xid, tcon,
 							netfid,
 							li->length, li->offset,
 							1, 0, li->type, false);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index ff8c68d..f247da9 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/inode.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2007
+ *   Copyright (C) International Business Machines  Corp., 2002,2008
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -621,6 +621,47 @@
 	.lookup = cifs_lookup,
 };
 
+static char *build_path_to_root(struct cifs_sb_info *cifs_sb)
+{
+	int pplen = cifs_sb->prepathlen;
+	int dfsplen;
+	char *full_path = NULL;
+
+	/* if no prefix path, simply set path to the root of share to "" */
+	if (pplen == 0) {
+		full_path = kmalloc(1, GFP_KERNEL);
+		if (full_path)
+			full_path[0] = 0;
+		return full_path;
+	}
+
+	if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
+		dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
+	else
+		dfsplen = 0;
+
+	full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
+	if (full_path == NULL)
+		return full_path;
+
+	if (dfsplen) {
+		strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
+		/* switch slash direction in prepath depending on whether
+		 * windows or posix style path names
+		 */
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
+			int i;
+			for (i = 0; i < dfsplen; i++) {
+				if (full_path[i] == '\\')
+					full_path[i] = '/';
+			}
+		}
+	}
+	strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
+	full_path[dfsplen + pplen] = 0; /* add trailing null */
+	return full_path;
+}
+
 /* gets root inode */
 struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
 {
@@ -628,6 +669,7 @@
 	struct cifs_sb_info *cifs_sb;
 	struct inode *inode;
 	long rc;
+	char *full_path;
 
 	inode = iget_locked(sb, ino);
 	if (!inode)
@@ -636,13 +678,17 @@
 		return inode;
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	xid = GetXid();
+	full_path = build_path_to_root(cifs_sb);
+	if (full_path == NULL)
+		return ERR_PTR(-ENOMEM);
 
+	xid = GetXid();
 	if (cifs_sb->tcon->unix_ext)
-		rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
+		rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
+						xid);
 	else
-		rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid,
-					 NULL);
+		rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
+						xid, NULL);
 	if (rc && cifs_sb->tcon->ipc) {
 		cFYI(1, ("ipc connection - fake read inode"));
 		inode->i_mode |= S_IFDIR;
@@ -652,6 +698,7 @@
 		inode->i_uid = cifs_sb->mnt_uid;
 		inode->i_gid = cifs_sb->mnt_gid;
 	} else if (rc) {
+		kfree(full_path);
 		_FreeXid(xid);
 		iget_failed(inode);
 		return ERR_PTR(rc);
@@ -659,6 +706,7 @@
 
 	unlock_new_inode(inode);
 
+	kfree(full_path);
 	/* can not call macro FreeXid here since in a void func
 	 * TODO: This is no longer true
 	 */
@@ -1143,11 +1191,11 @@
 				.device	= 0,
 			};
 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-				args.uid = (__u64)current->fsuid;
+				args.uid = (__u64)current_fsuid();
 				if (inode->i_mode & S_ISGID)
 					args.gid = (__u64)inode->i_gid;
 				else
-					args.gid = (__u64)current->fsgid;
+					args.gid = (__u64)current_fsgid();
 			} else {
 				args.uid = NO_CHANGE_64;
 				args.gid = NO_CHANGE_64;
@@ -1184,13 +1232,13 @@
 				if (cifs_sb->mnt_cifs_flags &
 				     CIFS_MOUNT_SET_UID) {
 					direntry->d_inode->i_uid =
-						current->fsuid;
+						current_fsuid();
 					if (inode->i_mode & S_ISGID)
 						direntry->d_inode->i_gid =
 							inode->i_gid;
 					else
 						direntry->d_inode->i_gid =
-							current->fsgid;
+							current_fsgid();
 				}
 			}
 		}
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 0088a5b..f946506 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -65,7 +65,7 @@
 	switch (command) {
 		case CIFS_IOC_CHECKUMOUNT:
 			cFYI(1, ("User unmount attempted"));
-			if (cifs_sb->mnt_uid == current->uid)
+			if (cifs_sb->mnt_uid == current_uid())
 				rc = 0;
 			else {
 				rc = -EACCES;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 9ee3f68..4c89c57 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -97,7 +97,10 @@
 	kfree(buf_to_free->serverOS);
 	kfree(buf_to_free->serverDomain);
 	kfree(buf_to_free->serverNOS);
-	kfree(buf_to_free->password);
+	if (buf_to_free->password) {
+		memset(buf_to_free->password, 0, strlen(buf_to_free->password));
+		kfree(buf_to_free->password);
+	}
 	kfree(buf_to_free->domainName);
 	kfree(buf_to_free);
 }
@@ -129,6 +132,10 @@
 	}
 	atomic_dec(&tconInfoAllocCount);
 	kfree(buf_to_free->nativeFileSystem);
+	if (buf_to_free->password) {
+		memset(buf_to_free->password, 0, strlen(buf_to_free->password));
+		kfree(buf_to_free->password);
+	}
 	kfree(buf_to_free);
 }
 
@@ -338,13 +345,13 @@
 		/*  BB Add support for establishing new tCon and SMB Session  */
 		/*      with userid/password pairs found on the smb session   */
 		/*	for other target tcp/ip addresses 		BB    */
-				if (current->fsuid != treeCon->ses->linux_uid) {
+				if (current_fsuid() != treeCon->ses->linux_uid) {
 					cFYI(1, ("Multiuser mode and UID "
 						 "did not match tcon uid"));
 					read_lock(&cifs_tcp_ses_lock);
 					list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
 						ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
-						if (ses->linux_uid == current->fsuid) {
+						if (ses->linux_uid == current_fsuid()) {
 							if (ses->server == treeCon->ses->server) {
 								cFYI(1, ("found matching uid substitute right smb_uid"));
 								buffer->Uid = ses->Suid;
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 2851d5d..5f22de7 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -417,7 +417,10 @@
 		/* BB calculate hash with password */
 		/* and copy into bcc */
 
-		calc_lanman_hash(ses, lnm_session_key);
+		calc_lanman_hash(ses->password, ses->server->cryptKey,
+				 ses->server->secMode & SECMODE_PW_ENCRYPT ?
+					true : false, lnm_session_key);
+
 		ses->flags |= CIFS_SES_LANMAN;
 		memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
 		bcc_ptr += CIFS_SESS_KEY_SIZE;
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
index 04943c9..224a1f4 100644
--- a/fs/cifs/smbdes.c
+++ b/fs/cifs/smbdes.c
@@ -318,7 +318,8 @@
 }
 
 static void
-smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
+smbhash(unsigned char *out, const unsigned char *in, unsigned char *key,
+	int forw)
 {
 	int i;
 	char *outb; /* outb[64] */
@@ -363,7 +364,7 @@
 }
 
 void
-E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
+E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24)
 {
 	smbhash(p24, c8, p21, 1);
 	smbhash(p24 + 8, c8, p21 + 7, 1);
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index ff3232f..93fb09a 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -49,9 +49,10 @@
 
 /*The following definitions come from  libsmb/smbencrypt.c  */
 
-void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
+		unsigned char *p24);
 void E_md4hash(const unsigned char *passwd, unsigned char *p16);
-static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
+static void SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
 		   unsigned char p24[24]);
 void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
 
@@ -61,7 +62,7 @@
    encrypted password into p24 */
 /* Note that password must be uppercased and null terminated */
 void
-SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
+SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24)
 {
 	unsigned char p14[15], p21[21];
 
@@ -212,7 +213,7 @@
 
 /* Does the des encryption from the NT or LM MD4 hash. */
 static void
-SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
+SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
 	      unsigned char p24[24])
 {
 	unsigned char p21[21];
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index ff8243a..7ebe659 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -37,15 +37,11 @@
 extern struct kmem_cache *cifs_oplock_cachep;
 
 static struct mid_q_entry *
-AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
+AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 {
 	struct mid_q_entry *temp;
 
-	if (ses == NULL) {
-		cERROR(1, ("Null session passed in to AllocMidQEntry"));
-		return NULL;
-	}
-	if (ses->server == NULL) {
+	if (server == NULL) {
 		cERROR(1, ("Null TCP session in AllocMidQEntry"));
 		return NULL;
 	}
@@ -62,12 +58,11 @@
 	/*	do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
 		/* when mid allocated can be before when sent */
 		temp->when_alloc = jiffies;
-		temp->ses = ses;
 		temp->tsk = current;
 	}
 
 	spin_lock(&GlobalMid_Lock);
-	list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
+	list_add_tail(&temp->qhead, &server->pending_mid_q);
 	atomic_inc(&midCount);
 	temp->midState = MID_REQUEST_ALLOCATED;
 	spin_unlock(&GlobalMid_Lock);
@@ -349,37 +344,38 @@
 	if (long_op == CIFS_ASYNC_OP) {
 		/* oplock breaks must not be held up */
 		atomic_inc(&ses->server->inFlight);
-	} else {
-		spin_lock(&GlobalMid_Lock);
-		while (1) {
-			if (atomic_read(&ses->server->inFlight) >=
-					cifs_max_pending){
-				spin_unlock(&GlobalMid_Lock);
-#ifdef CONFIG_CIFS_STATS2
-				atomic_inc(&ses->server->num_waiters);
-#endif
-				wait_event(ses->server->request_q,
-					atomic_read(&ses->server->inFlight)
-					 < cifs_max_pending);
-#ifdef CONFIG_CIFS_STATS2
-				atomic_dec(&ses->server->num_waiters);
-#endif
-				spin_lock(&GlobalMid_Lock);
-			} else {
-				if (ses->server->tcpStatus == CifsExiting) {
-					spin_unlock(&GlobalMid_Lock);
-					return -ENOENT;
-				}
+		return 0;
+	}
 
-				/* can not count locking commands against total
-				   as they are allowed to block on server */
-
-				/* update # of requests on the wire to server */
-				if (long_op != CIFS_BLOCKING_OP)
-					atomic_inc(&ses->server->inFlight);
+	spin_lock(&GlobalMid_Lock);
+	while (1) {
+		if (atomic_read(&ses->server->inFlight) >=
+				cifs_max_pending){
+			spin_unlock(&GlobalMid_Lock);
+#ifdef CONFIG_CIFS_STATS2
+			atomic_inc(&ses->server->num_waiters);
+#endif
+			wait_event(ses->server->request_q,
+				   atomic_read(&ses->server->inFlight)
+				     < cifs_max_pending);
+#ifdef CONFIG_CIFS_STATS2
+			atomic_dec(&ses->server->num_waiters);
+#endif
+			spin_lock(&GlobalMid_Lock);
+		} else {
+			if (ses->server->tcpStatus == CifsExiting) {
 				spin_unlock(&GlobalMid_Lock);
-				break;
+				return -ENOENT;
 			}
+
+			/* can not count locking commands against total
+			   as they are allowed to block on server */
+
+			/* update # of requests on the wire to server */
+			if (long_op != CIFS_BLOCKING_OP)
+				atomic_inc(&ses->server->inFlight);
+			spin_unlock(&GlobalMid_Lock);
+			break;
 		}
 	}
 	return 0;
@@ -390,17 +386,21 @@
 {
 	if (ses->server->tcpStatus == CifsExiting) {
 		return -ENOENT;
-	} else if (ses->server->tcpStatus == CifsNeedReconnect) {
+	}
+
+	if (ses->server->tcpStatus == CifsNeedReconnect) {
 		cFYI(1, ("tcp session dead - return to caller to retry"));
 		return -EAGAIN;
-	} else if (ses->status != CifsGood) {
+	}
+
+	if (ses->status != CifsGood) {
 		/* check if SMB session is bad because we are setting it up */
 		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
 			(in_buf->Command != SMB_COM_NEGOTIATE))
 			return -EAGAIN;
 		/* else ok - we are setting up session */
 	}
-	*ppmidQ = AllocMidQEntry(in_buf, ses);
+	*ppmidQ = AllocMidQEntry(in_buf, ses->server);
 	if (*ppmidQ == NULL)
 		return -ENOMEM;
 	return 0;
@@ -415,11 +415,8 @@
 
 	for (;;) {
 		curr_timeout = timeout + jiffies;
-		wait_event(ses->server->response_q,
-			(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
-			time_after(jiffies, curr_timeout) ||
-			((ses->server->tcpStatus != CifsGood) &&
-			 (ses->server->tcpStatus != CifsNew)));
+		wait_event_timeout(ses->server->response_q,
+			midQ->midState != MID_REQUEST_SUBMITTED, timeout);
 
 		if (time_after(jiffies, curr_timeout) &&
 			(midQ->midState == MID_REQUEST_SUBMITTED) &&
@@ -521,11 +518,11 @@
 	   and avoid races inside tcp sendmsg code that could cause corruption
 	   of smb data */
 
-	down(&ses->server->tcpSem);
+	mutex_lock(&ses->server->srv_mutex);
 
 	rc = allocate_mid(ses, in_buf, &midQ);
 	if (rc) {
-		up(&ses->server->tcpSem);
+		mutex_unlock(&ses->server->srv_mutex);
 		cifs_small_buf_release(in_buf);
 		/* Update # of requests on wire to server */
 		atomic_dec(&ses->server->inFlight);
@@ -533,6 +530,11 @@
 		return rc;
 	}
 	rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
+	if (rc) {
+		mutex_unlock(&ses->server->srv_mutex);
+		cifs_small_buf_release(in_buf);
+		goto out;
+	}
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
 #ifdef CONFIG_CIFS_STATS2
@@ -546,7 +548,7 @@
 	midQ->when_sent = jiffies;
 #endif
 
-	up(&ses->server->tcpSem);
+	mutex_unlock(&ses->server->srv_mutex);
 	cifs_small_buf_release(in_buf);
 
 	if (rc < 0)
@@ -581,10 +583,8 @@
 	wait_for_response(ses, midQ, timeout, 10 * HZ);
 
 	spin_lock(&GlobalMid_Lock);
-	if (midQ->resp_buf) {
-		spin_unlock(&GlobalMid_Lock);
-		receive_len = midQ->resp_buf->smb_buf_length;
-	} else {
+
+	if (midQ->resp_buf == NULL) {
 		cERROR(1, ("No response to cmd %d mid %d",
 			midQ->command, midQ->mid));
 		if (midQ->midState == MID_REQUEST_SUBMITTED) {
@@ -612,53 +612,59 @@
 		return rc;
 	}
 
+	spin_unlock(&GlobalMid_Lock);
+	receive_len = midQ->resp_buf->smb_buf_length;
+
 	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
 		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
 			receive_len, xid));
 		rc = -EIO;
-	} else {		/* rcvd frame is ok */
-		if (midQ->resp_buf &&
-			(midQ->midState == MID_RESPONSE_RECEIVED)) {
+		goto out;
+	}
 
-			iov[0].iov_base = (char *)midQ->resp_buf;
-			if (midQ->largeBuf)
-				*pRespBufType = CIFS_LARGE_BUFFER;
-			else
-				*pRespBufType = CIFS_SMALL_BUFFER;
-			iov[0].iov_len = receive_len + 4;
+	/* rcvd frame is ok */
 
-			dump_smb(midQ->resp_buf, 80);
-			/* convert the length into a more usable form */
-			if ((receive_len > 24) &&
-			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-					SECMODE_SIGN_ENABLED))) {
-				rc = cifs_verify_signature(midQ->resp_buf,
+	if (midQ->resp_buf &&
+	    (midQ->midState == MID_RESPONSE_RECEIVED)) {
+
+		iov[0].iov_base = (char *)midQ->resp_buf;
+		if (midQ->largeBuf)
+			*pRespBufType = CIFS_LARGE_BUFFER;
+		else
+			*pRespBufType = CIFS_SMALL_BUFFER;
+		iov[0].iov_len = receive_len + 4;
+
+		dump_smb(midQ->resp_buf, 80);
+		/* convert the length into a more usable form */
+		if ((receive_len > 24) &&
+		    (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+					     SECMODE_SIGN_ENABLED))) {
+			rc = cifs_verify_signature(midQ->resp_buf,
 						&ses->server->mac_signing_key,
 						midQ->sequence_number+1);
-				if (rc) {
-					cERROR(1, ("Unexpected SMB signature"));
-					/* BB FIXME add code to kill session */
-				}
+			if (rc) {
+				cERROR(1, ("Unexpected SMB signature"));
+				/* BB FIXME add code to kill session */
 			}
-
-			/* BB special case reconnect tid and uid here? */
-			rc = map_smb_to_linux_error(midQ->resp_buf,
-						flags & CIFS_LOG_ERROR);
-
-			/* convert ByteCount if necessary */
-			if (receive_len >= sizeof(struct smb_hdr) - 4
-			    /* do not count RFC1001 header */  +
-			    (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
-				BCC(midQ->resp_buf) =
-					le16_to_cpu(BCC_LE(midQ->resp_buf));
-			if ((flags & CIFS_NO_RESP) == 0)
-				midQ->resp_buf = NULL;  /* mark it so buf will
-							   not be freed by
-							   DeleteMidQEntry */
-		} else {
-			rc = -EIO;
-			cFYI(1, ("Bad MID state?"));
 		}
+
+		/* BB special case reconnect tid and uid here? */
+		rc = map_smb_to_linux_error(midQ->resp_buf,
+					    flags & CIFS_LOG_ERROR);
+
+		/* convert ByteCount if necessary */
+		if (receive_len >= sizeof(struct smb_hdr) - 4
+		    /* do not count RFC1001 header */  +
+		    (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
+			BCC(midQ->resp_buf) =
+				le16_to_cpu(BCC_LE(midQ->resp_buf));
+		if ((flags & CIFS_NO_RESP) == 0)
+			midQ->resp_buf = NULL;  /* mark it so buf will
+						   not be freed by
+						   DeleteMidQEntry */
+	} else {
+		rc = -EIO;
+		cFYI(1, ("Bad MID state?"));
 	}
 
 out:
@@ -695,6 +701,12 @@
 	   to the same server. We may make this configurable later or
 	   use ses->maxReq */
 
+	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+		cERROR(1, ("Illegal length, greater than maximum frame, %d",
+			   in_buf->smb_buf_length));
+		return -EIO;
+	}
+
 	rc = wait_for_free_request(ses, long_op);
 	if (rc)
 		return rc;
@@ -703,29 +715,22 @@
 	   and avoid races inside tcp sendmsg code that could cause corruption
 	   of smb data */
 
-	down(&ses->server->tcpSem);
+	mutex_lock(&ses->server->srv_mutex);
 
 	rc = allocate_mid(ses, in_buf, &midQ);
 	if (rc) {
-		up(&ses->server->tcpSem);
+		mutex_unlock(&ses->server->srv_mutex);
 		/* Update # of requests on wire to server */
 		atomic_dec(&ses->server->inFlight);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
 
-	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
-		cERROR(1, ("Illegal length, greater than maximum frame, %d",
-			in_buf->smb_buf_length));
-		DeleteMidQEntry(midQ);
-		up(&ses->server->tcpSem);
-		/* Update # of requests on wire to server */
-		atomic_dec(&ses->server->inFlight);
-		wake_up(&ses->server->request_q);
-		return -EIO;
-	}
-
 	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
+	if (rc) {
+		mutex_unlock(&ses->server->srv_mutex);
+		goto out;
+	}
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
 #ifdef CONFIG_CIFS_STATS2
@@ -738,7 +743,7 @@
 	atomic_dec(&ses->server->inSend);
 	midQ->when_sent = jiffies;
 #endif
-	up(&ses->server->tcpSem);
+	mutex_unlock(&ses->server->srv_mutex);
 
 	if (rc < 0)
 		goto out;
@@ -772,10 +777,7 @@
 	wait_for_response(ses, midQ, timeout, 10 * HZ);
 
 	spin_lock(&GlobalMid_Lock);
-	if (midQ->resp_buf) {
-		spin_unlock(&GlobalMid_Lock);
-		receive_len = midQ->resp_buf->smb_buf_length;
-	} else {
+	if (midQ->resp_buf == NULL) {
 		cERROR(1, ("No response for cmd %d mid %d",
 			  midQ->command, midQ->mid));
 		if (midQ->midState == MID_REQUEST_SUBMITTED) {
@@ -803,47 +805,52 @@
 		return rc;
 	}
 
+	spin_unlock(&GlobalMid_Lock);
+	receive_len = midQ->resp_buf->smb_buf_length;
+
 	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
 		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
 			receive_len, xid));
 		rc = -EIO;
-	} else {		/* rcvd frame is ok */
+		goto out;
+	}
 
-		if (midQ->resp_buf && out_buf
-		    && (midQ->midState == MID_RESPONSE_RECEIVED)) {
-			out_buf->smb_buf_length = receive_len;
-			memcpy((char *)out_buf + 4,
-			       (char *)midQ->resp_buf + 4,
-			       receive_len);
+	/* rcvd frame is ok */
 
-			dump_smb(out_buf, 92);
-			/* convert the length into a more usable form */
-			if ((receive_len > 24) &&
-			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-					SECMODE_SIGN_ENABLED))) {
-				rc = cifs_verify_signature(out_buf,
+	if (midQ->resp_buf && out_buf
+	    && (midQ->midState == MID_RESPONSE_RECEIVED)) {
+		out_buf->smb_buf_length = receive_len;
+		memcpy((char *)out_buf + 4,
+		       (char *)midQ->resp_buf + 4,
+		       receive_len);
+
+		dump_smb(out_buf, 92);
+		/* convert the length into a more usable form */
+		if ((receive_len > 24) &&
+		    (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+					     SECMODE_SIGN_ENABLED))) {
+			rc = cifs_verify_signature(out_buf,
 						&ses->server->mac_signing_key,
 						midQ->sequence_number+1);
-				if (rc) {
-					cERROR(1, ("Unexpected SMB signature"));
-					/* BB FIXME add code to kill session */
-				}
+			if (rc) {
+				cERROR(1, ("Unexpected SMB signature"));
+				/* BB FIXME add code to kill session */
 			}
-
-			*pbytes_returned = out_buf->smb_buf_length;
-
-			/* BB special case reconnect tid and uid here? */
-			rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
-
-			/* convert ByteCount if necessary */
-			if (receive_len >= sizeof(struct smb_hdr) - 4
-			    /* do not count RFC1001 header */  +
-			    (2 * out_buf->WordCount) + 2 /* bcc */ )
-				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
-		} else {
-			rc = -EIO;
-			cERROR(1, ("Bad MID state?"));
 		}
+
+		*pbytes_returned = out_buf->smb_buf_length;
+
+		/* BB special case reconnect tid and uid here? */
+		rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
+
+		/* convert ByteCount if necessary */
+		if (receive_len >= sizeof(struct smb_hdr) - 4
+		    /* do not count RFC1001 header */  +
+		    (2 * out_buf->WordCount) + 2 /* bcc */ )
+			BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
+	} else {
+		rc = -EIO;
+		cERROR(1, ("Bad MID state?"));
 	}
 
 out:
@@ -866,16 +873,16 @@
 
 	header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
 	in_buf->Mid = mid;
-	down(&ses->server->tcpSem);
+	mutex_lock(&ses->server->srv_mutex);
 	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 	if (rc) {
-		up(&ses->server->tcpSem);
+		mutex_unlock(&ses->server->srv_mutex);
 		return rc;
 	}
 	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
 	      (struct sockaddr *) &(ses->server->addr.sockAddr),
 	      ses->server->noblocksnd);
-	up(&ses->server->tcpSem);
+	mutex_unlock(&ses->server->srv_mutex);
 	return rc;
 }
 
@@ -933,6 +940,12 @@
 	   to the same server. We may make this configurable later or
 	   use ses->maxReq */
 
+	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+		cERROR(1, ("Illegal length, greater than maximum frame, %d",
+			   in_buf->smb_buf_length));
+		return -EIO;
+	}
+
 	rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
 	if (rc)
 		return rc;
@@ -941,23 +954,20 @@
 	   and avoid races inside tcp sendmsg code that could cause corruption
 	   of smb data */
 
-	down(&ses->server->tcpSem);
+	mutex_lock(&ses->server->srv_mutex);
 
 	rc = allocate_mid(ses, in_buf, &midQ);
 	if (rc) {
-		up(&ses->server->tcpSem);
+		mutex_unlock(&ses->server->srv_mutex);
 		return rc;
 	}
 
-	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
-		up(&ses->server->tcpSem);
-		cERROR(1, ("Illegal length, greater than maximum frame, %d",
-			in_buf->smb_buf_length));
-		DeleteMidQEntry(midQ);
-		return -EIO;
-	}
-
 	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
+	if (rc) {
+		DeleteMidQEntry(midQ);
+		mutex_unlock(&ses->server->srv_mutex);
+		return rc;
+	}
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
 #ifdef CONFIG_CIFS_STATS2
@@ -970,7 +980,7 @@
 	atomic_dec(&ses->server->inSend);
 	midQ->when_sent = jiffies;
 #endif
-	up(&ses->server->tcpSem);
+	mutex_unlock(&ses->server->srv_mutex);
 
 	if (rc < 0) {
 		DeleteMidQEntry(midQ);
@@ -1052,44 +1062,48 @@
 		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
 			receive_len, xid));
 		rc = -EIO;
-	} else {		/* rcvd frame is ok */
+		goto out;
+	}
 
-		if (midQ->resp_buf && out_buf
-		    && (midQ->midState == MID_RESPONSE_RECEIVED)) {
-			out_buf->smb_buf_length = receive_len;
-			memcpy((char *)out_buf + 4,
-			       (char *)midQ->resp_buf + 4,
-			       receive_len);
+	/* rcvd frame is ok */
 
-			dump_smb(out_buf, 92);
-			/* convert the length into a more usable form */
-			if ((receive_len > 24) &&
-			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
-					SECMODE_SIGN_ENABLED))) {
-				rc = cifs_verify_signature(out_buf,
-						&ses->server->mac_signing_key,
-						midQ->sequence_number+1);
-				if (rc) {
-					cERROR(1, ("Unexpected SMB signature"));
-					/* BB FIXME add code to kill session */
-				}
-			}
+	if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
+		rc = -EIO;
+		cERROR(1, ("Bad MID state?"));
+		goto out;
+	}
 
-			*pbytes_returned = out_buf->smb_buf_length;
+	out_buf->smb_buf_length = receive_len;
+	memcpy((char *)out_buf + 4,
+	       (char *)midQ->resp_buf + 4,
+	       receive_len);
 
-			/* BB special case reconnect tid and uid here? */
-			rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
-
-			/* convert ByteCount if necessary */
-			if (receive_len >= sizeof(struct smb_hdr) - 4
-			    /* do not count RFC1001 header */  +
-			    (2 * out_buf->WordCount) + 2 /* bcc */ )
-				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
-		} else {
-			rc = -EIO;
-			cERROR(1, ("Bad MID state?"));
+	dump_smb(out_buf, 92);
+	/* convert the length into a more usable form */
+	if ((receive_len > 24) &&
+	    (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+				     SECMODE_SIGN_ENABLED))) {
+		rc = cifs_verify_signature(out_buf,
+					   &ses->server->mac_signing_key,
+					   midQ->sequence_number+1);
+		if (rc) {
+			cERROR(1, ("Unexpected SMB signature"));
+			/* BB FIXME add code to kill session */
 		}
 	}
+
+	*pbytes_returned = out_buf->smb_buf_length;
+
+	/* BB special case reconnect tid and uid here? */
+	rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
+
+	/* convert ByteCount if necessary */
+	if (receive_len >= sizeof(struct smb_hdr) - 4
+	    /* do not count RFC1001 header */  +
+	    (2 * out_buf->WordCount) + 2 /* bcc */ )
+		BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
+
+out:
 	DeleteMidQEntry(midQ);
 	if (rstart && rc == -EACCES)
 		return -ERESTARTSYS;
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 8a23703..a5bf577 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -32,8 +32,8 @@
 	struct coda_inode_info *cii = ITOC(inode);
 
 	cii->c_cached_epoch = atomic_read(&permission_epoch);
-	if (cii->c_uid != current->fsuid) {
-                cii->c_uid = current->fsuid;
+	if (cii->c_uid != current_fsuid()) {
+		cii->c_uid = current_fsuid();
                 cii->c_cached_perm = mask;
         } else
                 cii->c_cached_perm |= mask;
@@ -60,7 +60,7 @@
         int hit;
 	
         hit = (mask & cii->c_cached_perm) == mask &&
-		cii->c_uid == current->fsuid &&
+		cii->c_uid == current_fsuid() &&
 		cii->c_cached_epoch == atomic_read(&permission_epoch);
 
         return hit;
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 29137ff..466303d 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -13,6 +13,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
+#include <linux/cred.h>
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
 #include <linux/string.h>
@@ -174,7 +175,7 @@
 	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
 
 	err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
-			  coda_flags, coda_file->f_uid);
+			  coda_flags, coda_file->f_cred->fsuid);
 
 	host_inode = cfi->cfi_container->f_path.dentry->d_inode;
 	cii = ITOC(coda_inode);
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index ce432bc..c274d94 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -52,7 +52,7 @@
         inp->ih.opcode = opcode;
 	inp->ih.pid = current->pid;
 	inp->ih.pgid = task_pgrp_nr(current);
-	inp->ih.uid = current->fsuid;
+	inp->ih.uid = current_fsuid();
 
 	return (void*)inp;
 }
diff --git a/fs/compat.c b/fs/compat.c
index e5f49f5..d1ece79 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1393,10 +1393,20 @@
 	if (!bprm)
 		goto out_ret;
 
+	retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+	if (retval < 0)
+		goto out_free;
+
+	retval = -ENOMEM;
+	bprm->cred = prepare_exec_creds();
+	if (!bprm->cred)
+		goto out_unlock;
+	check_unsafe_exec(bprm);
+
 	file = open_exec(filename);
 	retval = PTR_ERR(file);
 	if (IS_ERR(file))
-		goto out_kfree;
+		goto out_unlock;
 
 	sched_exec();
 
@@ -1410,14 +1420,10 @@
 
 	bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
 	if ((retval = bprm->argc) < 0)
-		goto out_mm;
+		goto out;
 
 	bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
 	if ((retval = bprm->envc) < 0)
-		goto out_mm;
-
-	retval = security_bprm_alloc(bprm);
-	if (retval)
 		goto out;
 
 	retval = prepare_binprm(bprm);
@@ -1438,19 +1444,16 @@
 		goto out;
 
 	retval = search_binary_handler(bprm, regs);
-	if (retval >= 0) {
-		/* execve success */
-		security_bprm_free(bprm);
-		acct_update_integrals(current);
-		free_bprm(bprm);
-		return retval;
-	}
+	if (retval < 0)
+		goto out;
+
+	/* execve succeeded */
+	mutex_unlock(&current->cred_exec_mutex);
+	acct_update_integrals(current);
+	free_bprm(bprm);
+	return retval;
 
 out:
-	if (bprm->security)
-		security_bprm_free(bprm);
-
-out_mm:
 	if (bprm->mm)
 		mmput(bprm->mm);
 
@@ -1460,7 +1463,10 @@
 		fput(bprm->file);
 	}
 
-out_kfree:
+out_unlock:
+	mutex_unlock(&current->cred_exec_mutex);
+
+out_free:
 	free_bprm(bprm);
 
 out_ret:
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 4a714f6c..5d61b7c 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -222,8 +222,8 @@
 		return -ENOMEM;
 
 	inode->i_ino = number+2;
-	inode->i_uid = config.setuid ? config.uid : current->fsuid;
-	inode->i_gid = config.setgid ? config.gid : current->fsgid;
+	inode->i_uid = config.setuid ? config.uid : current_fsuid();
+	inode->i_gid = config.setgid ? config.gid : current_fsgid();
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	init_special_inode(inode, S_IFCHR|config.mode, device);
 	inode->i_private = tty;
diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c
index 18bda83..aa2a577 100644
--- a/fs/dlm/netlink.c
+++ b/fs/dlm/netlink.c
@@ -127,8 +127,8 @@
 
 void dlm_timeout_warn(struct dlm_lkb *lkb)
 {
+	struct sk_buff *uninitialized_var(send_skb);
 	struct dlm_lock_data *data;
-	struct sk_buff *send_skb;
 	size_t size;
 	int rv;
 
diff --git a/fs/dquot.c b/fs/dquot.c
index 5e95261..c237ccc 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -874,7 +874,7 @@
 
 	switch (dquot->dq_type) {
 		case USRQUOTA:
-			return current->fsuid == dquot->dq_id;
+			return current_fsuid() == dquot->dq_id;
 		case GRPQUOTA:
 			return in_group_p(dquot->dq_id);
 	}
@@ -981,7 +981,7 @@
 		MINOR(dquot->dq_sb->s_dev));
 	if (ret)
 		goto attr_err_out;
-	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current->user->uid);
+	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
 	if (ret)
 		goto attr_err_out;
 	genlmsg_end(skb, msg_head);
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 3504cf9..a75026d 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -691,7 +691,8 @@
 void ecryptfs_destroy_kthread(void);
 int ecryptfs_privileged_open(struct file **lower_file,
 			     struct dentry *lower_dentry,
-			     struct vfsmount *lower_mnt);
+			     struct vfsmount *lower_mnt,
+			     const struct cred *cred);
 int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry);
 
 #endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c
index c440c6b..c6d7a4d 100644
--- a/fs/ecryptfs/kthread.c
+++ b/fs/ecryptfs/kthread.c
@@ -73,7 +73,7 @@
 				mntget(req->lower_mnt);
 				(*req->lower_file) = dentry_open(
 					req->lower_dentry, req->lower_mnt,
-					(O_RDWR | O_LARGEFILE));
+					(O_RDWR | O_LARGEFILE), current_cred());
 				req->flags |= ECRYPTFS_REQ_PROCESSED;
 			}
 			wake_up(&req->wait);
@@ -132,7 +132,8 @@
  */
 int ecryptfs_privileged_open(struct file **lower_file,
 			     struct dentry *lower_dentry,
-			     struct vfsmount *lower_mnt)
+			     struct vfsmount *lower_mnt,
+			     const struct cred *cred)
 {
 	struct ecryptfs_open_req *req;
 	int rc = 0;
@@ -143,7 +144,7 @@
 	dget(lower_dentry);
 	mntget(lower_mnt);
 	(*lower_file) = dentry_open(lower_dentry, lower_mnt,
-				    (O_RDWR | O_LARGEFILE));
+				    (O_RDWR | O_LARGEFILE), cred);
 	if (!IS_ERR(*lower_file))
 		goto out;
 	req = kmem_cache_alloc(ecryptfs_open_req_cache, GFP_KERNEL);
@@ -184,7 +185,7 @@
 		dget(lower_dentry);
 		mntget(lower_mnt);
 		(*lower_file) = dentry_open(lower_dentry, lower_mnt,
-					    (O_RDONLY | O_LARGEFILE));
+					    (O_RDONLY | O_LARGEFILE), cred);
 		if (IS_ERR(*lower_file)) {
 			rc = PTR_ERR(*req->lower_file);
 			(*lower_file) = NULL;
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 64d2ba9..fd63071 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -115,6 +115,7 @@
  */
 int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
 {
+	const struct cred *cred = current_cred();
 	struct ecryptfs_inode_info *inode_info =
 		ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
 	int rc = 0;
@@ -127,7 +128,7 @@
 
 		lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
 		rc = ecryptfs_privileged_open(&inode_info->lower_file,
-						     lower_dentry, lower_mnt);
+					      lower_dentry, lower_mnt, cred);
 		if (rc || IS_ERR(inode_info->lower_file)) {
 			printk(KERN_ERR "Error opening lower persistent file "
 			       "for lower_dentry [0x%p] and lower_mnt [0x%p]; "
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c
index c698397..6913f72 100644
--- a/fs/ecryptfs/messaging.c
+++ b/fs/ecryptfs/messaging.c
@@ -360,7 +360,8 @@
 	struct ecryptfs_msg_ctx *msg_ctx;
 	size_t msg_size;
 	struct nsproxy *nsproxy;
-	struct user_namespace *current_user_ns;
+	struct user_namespace *tsk_user_ns;
+	uid_t ctx_euid;
 	int rc;
 
 	if (msg->index >= ecryptfs_message_buf_len) {
@@ -384,9 +385,9 @@
 		mutex_unlock(&ecryptfs_daemon_hash_mux);
 		goto wake_up;
 	}
-	current_user_ns = nsproxy->user_ns;
-	rc = ecryptfs_find_daemon_by_euid(&daemon, msg_ctx->task->euid,
-					  current_user_ns);
+	tsk_user_ns = __task_cred(msg_ctx->task)->user->user_ns;
+	ctx_euid = task_euid(msg_ctx->task);
+	rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns);
 	rcu_read_unlock();
 	mutex_unlock(&ecryptfs_daemon_hash_mux);
 	if (rc) {
@@ -394,28 +395,28 @@
 		printk(KERN_WARNING "%s: User [%d] received a "
 		       "message response from process [0x%p] but does "
 		       "not have a registered daemon\n", __func__,
-		       msg_ctx->task->euid, pid);
+		       ctx_euid, pid);
 		goto wake_up;
 	}
-	if (msg_ctx->task->euid != euid) {
+	if (ctx_euid != euid) {
 		rc = -EBADMSG;
 		printk(KERN_WARNING "%s: Received message from user "
 		       "[%d]; expected message from user [%d]\n", __func__,
-		       euid, msg_ctx->task->euid);
+		       euid, ctx_euid);
 		goto unlock;
 	}
-	if (current_user_ns != user_ns) {
+	if (tsk_user_ns != user_ns) {
 		rc = -EBADMSG;
 		printk(KERN_WARNING "%s: Received message from user_ns "
 		       "[0x%p]; expected message from user_ns [0x%p]\n",
-		       __func__, user_ns, nsproxy->user_ns);
+		       __func__, user_ns, tsk_user_ns);
 		goto unlock;
 	}
 	if (daemon->pid != pid) {
 		rc = -EBADMSG;
 		printk(KERN_ERR "%s: User [%d] sent a message response "
 		       "from an unrecognized process [0x%p]\n",
-		       __func__, msg_ctx->task->euid, pid);
+		       __func__, ctx_euid, pid);
 		goto unlock;
 	}
 	if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
@@ -464,14 +465,14 @@
 			     struct ecryptfs_msg_ctx **msg_ctx)
 {
 	struct ecryptfs_daemon *daemon;
+	uid_t euid = current_euid();
 	int rc;
 
-	rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
-					  current->nsproxy->user_ns);
+	rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
 	if (rc || !daemon) {
 		rc = -ENOTCONN;
 		printk(KERN_ERR "%s: User [%d] does not have a daemon "
-		       "registered\n", __func__, current->euid);
+		       "registered\n", __func__, euid);
 		goto out;
 	}
 	mutex_lock(&ecryptfs_msg_ctx_lists_mux);
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c
index b484792..efd95a0 100644
--- a/fs/ecryptfs/miscdev.c
+++ b/fs/ecryptfs/miscdev.c
@@ -42,12 +42,12 @@
 {
 	struct ecryptfs_daemon *daemon;
 	unsigned int mask = 0;
+	uid_t euid = current_euid();
 	int rc;
 
 	mutex_lock(&ecryptfs_daemon_hash_mux);
 	/* TODO: Just use file->private_data? */
-	rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
-					  current->nsproxy->user_ns);
+	rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
 	BUG_ON(rc || !daemon);
 	mutex_lock(&daemon->mux);
 	mutex_unlock(&ecryptfs_daemon_hash_mux);
@@ -83,6 +83,7 @@
 ecryptfs_miscdev_open(struct inode *inode, struct file *file)
 {
 	struct ecryptfs_daemon *daemon = NULL;
+	uid_t euid = current_euid();
 	int rc;
 
 	mutex_lock(&ecryptfs_daemon_hash_mux);
@@ -93,11 +94,9 @@
 		       "count; rc = [%d]\n", __func__, rc);
 		goto out_unlock_daemon_list;
 	}
-	rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
-					  current->nsproxy->user_ns);
+	rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
 	if (rc || !daemon) {
-		rc = ecryptfs_spawn_daemon(&daemon, current->euid,
-					   current->nsproxy->user_ns,
+		rc = ecryptfs_spawn_daemon(&daemon, euid, current_user_ns(),
 					   task_pid(current));
 		if (rc) {
 			printk(KERN_ERR "%s: Error attempting to spawn daemon; "
@@ -147,11 +146,11 @@
 ecryptfs_miscdev_release(struct inode *inode, struct file *file)
 {
 	struct ecryptfs_daemon *daemon = NULL;
+	uid_t euid = current_euid();
 	int rc;
 
 	mutex_lock(&ecryptfs_daemon_hash_mux);
-	rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
-					  current->nsproxy->user_ns);
+	rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
 	BUG_ON(rc || !daemon);
 	mutex_lock(&daemon->mux);
 	BUG_ON(daemon->pid != task_pid(current));
@@ -246,12 +245,12 @@
 	char packet_length[3];
 	size_t i;
 	size_t total_length;
+	uid_t euid = current_euid();
 	int rc;
 
 	mutex_lock(&ecryptfs_daemon_hash_mux);
 	/* TODO: Just use file->private_data? */
-	rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
-					  current->nsproxy->user_ns);
+	rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
 	BUG_ON(rc || !daemon);
 	mutex_lock(&daemon->mux);
 	if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
@@ -290,8 +289,8 @@
 		 * message from the queue; try again */
 		goto check_list;
 	}
-	BUG_ON(current->euid != daemon->euid);
-	BUG_ON(current->nsproxy->user_ns != daemon->user_ns);
+	BUG_ON(euid != daemon->euid);
+	BUG_ON(current_user_ns() != daemon->user_ns);
 	BUG_ON(task_pid(current) != daemon->pid);
 	msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
 				   struct ecryptfs_msg_ctx, daemon_out_list);
@@ -414,6 +413,7 @@
 	size_t packet_size, packet_size_length, i;
 	ssize_t sz = 0;
 	char *data;
+	uid_t euid = current_euid();
 	int rc;
 
 	if (count == 0)
@@ -463,8 +463,7 @@
 			goto out_free;
 		}
 		rc = ecryptfs_miscdev_response(&data[i], packet_size,
-					       current->euid,
-					       current->nsproxy->user_ns,
+					       euid, current_user_ns(),
 					       task_pid(current), seq);
 		if (rc)
 			printk(KERN_WARNING "%s: Failed to deliver miscdev "
diff --git a/fs/exec.c b/fs/exec.c
index ec5df9a..1f59ea0 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -55,6 +55,7 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/tlb.h>
+#include "internal.h"
 
 #ifdef __alpha__
 /* for /sbin/loader handling in search_binary_handler() */
@@ -980,7 +981,7 @@
 	/* This is the point of no return */
 	current->sas_ss_sp = current->sas_ss_size = 0;
 
-	if (current->euid == current->uid && current->egid == current->gid)
+	if (current_euid() == current_uid() && current_egid() == current_gid())
 		set_dumpable(current->mm, 1);
 	else
 		set_dumpable(current->mm, suid_dumpable);
@@ -1007,16 +1008,17 @@
 	 */
 	current->mm->task_size = TASK_SIZE;
 
-	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) {
-		suid_keys(current);
-		set_dumpable(current->mm, suid_dumpable);
+	/* install the new credentials */
+	if (bprm->cred->uid != current_euid() ||
+	    bprm->cred->gid != current_egid()) {
 		current->pdeath_signal = 0;
 	} else if (file_permission(bprm->file, MAY_READ) ||
-			(bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
-		suid_keys(current);
+		   bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) {
 		set_dumpable(current->mm, suid_dumpable);
 	}
 
+	current->personality &= ~bprm->per_clear;
+
 	/* An exec changes our domain. We are no longer part of the thread
 	   group */
 
@@ -1033,13 +1035,50 @@
 
 EXPORT_SYMBOL(flush_old_exec);
 
+/*
+ * install the new credentials for this executable
+ */
+void install_exec_creds(struct linux_binprm *bprm)
+{
+	security_bprm_committing_creds(bprm);
+
+	commit_creds(bprm->cred);
+	bprm->cred = NULL;
+
+	/* cred_exec_mutex must be held at least to this point to prevent
+	 * ptrace_attach() from altering our determination of the task's
+	 * credentials; any time after this it may be unlocked */
+
+	security_bprm_committed_creds(bprm);
+}
+EXPORT_SYMBOL(install_exec_creds);
+
+/*
+ * determine how safe it is to execute the proposed program
+ * - the caller must hold current->cred_exec_mutex to protect against
+ *   PTRACE_ATTACH
+ */
+void check_unsafe_exec(struct linux_binprm *bprm)
+{
+	struct task_struct *p = current;
+
+	bprm->unsafe = tracehook_unsafe_exec(p);
+
+	if (atomic_read(&p->fs->count) > 1 ||
+	    atomic_read(&p->files->count) > 1 ||
+	    atomic_read(&p->sighand->count) > 1)
+		bprm->unsafe |= LSM_UNSAFE_SHARE;
+}
+
 /* 
  * Fill the binprm structure from the inode. 
  * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
+ *
+ * This may be called multiple times for binary chains (scripts for example).
  */
 int prepare_binprm(struct linux_binprm *bprm)
 {
-	int mode;
+	umode_t mode;
 	struct inode * inode = bprm->file->f_path.dentry->d_inode;
 	int retval;
 
@@ -1047,14 +1086,15 @@
 	if (bprm->file->f_op == NULL)
 		return -EACCES;
 
-	bprm->e_uid = current->euid;
-	bprm->e_gid = current->egid;
+	/* clear any previous set[ug]id data from a previous binary */
+	bprm->cred->euid = current_euid();
+	bprm->cred->egid = current_egid();
 
-	if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
+	if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
 		/* Set-uid? */
 		if (mode & S_ISUID) {
-			current->personality &= ~PER_CLEAR_ON_SETID;
-			bprm->e_uid = inode->i_uid;
+			bprm->per_clear |= PER_CLEAR_ON_SETID;
+			bprm->cred->euid = inode->i_uid;
 		}
 
 		/* Set-gid? */
@@ -1064,52 +1104,23 @@
 		 * executable.
 		 */
 		if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
-			current->personality &= ~PER_CLEAR_ON_SETID;
-			bprm->e_gid = inode->i_gid;
+			bprm->per_clear |= PER_CLEAR_ON_SETID;
+			bprm->cred->egid = inode->i_gid;
 		}
 	}
 
 	/* fill in binprm security blob */
-	retval = security_bprm_set(bprm);
+	retval = security_bprm_set_creds(bprm);
 	if (retval)
 		return retval;
+	bprm->cred_prepared = 1;
 
-	memset(bprm->buf,0,BINPRM_BUF_SIZE);
-	return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);
+	memset(bprm->buf, 0, BINPRM_BUF_SIZE);
+	return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
 }
 
 EXPORT_SYMBOL(prepare_binprm);
 
-static int unsafe_exec(struct task_struct *p)
-{
-	int unsafe = tracehook_unsafe_exec(p);
-
-	if (atomic_read(&p->fs->count) > 1 ||
-	    atomic_read(&p->files->count) > 1 ||
-	    atomic_read(&p->sighand->count) > 1)
-		unsafe |= LSM_UNSAFE_SHARE;
-
-	return unsafe;
-}
-
-void compute_creds(struct linux_binprm *bprm)
-{
-	int unsafe;
-
-	if (bprm->e_uid != current->uid) {
-		suid_keys(current);
-		current->pdeath_signal = 0;
-	}
-	exec_keys(current);
-
-	task_lock(current);
-	unsafe = unsafe_exec(current);
-	security_bprm_apply_creds(bprm, unsafe);
-	task_unlock(current);
-	security_bprm_post_apply_creds(bprm);
-}
-EXPORT_SYMBOL(compute_creds);
-
 /*
  * Arguments are '\0' separated strings found at the location bprm->p
  * points to; chop off the first by relocating brpm->p to right after
@@ -1270,6 +1281,8 @@
 void free_bprm(struct linux_binprm *bprm)
 {
 	free_arg_pages(bprm);
+	if (bprm->cred)
+		abort_creds(bprm->cred);
 	kfree(bprm);
 }
 
@@ -1295,10 +1308,20 @@
 	if (!bprm)
 		goto out_files;
 
+	retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+	if (retval < 0)
+		goto out_free;
+
+	retval = -ENOMEM;
+	bprm->cred = prepare_exec_creds();
+	if (!bprm->cred)
+		goto out_unlock;
+	check_unsafe_exec(bprm);
+
 	file = open_exec(filename);
 	retval = PTR_ERR(file);
 	if (IS_ERR(file))
-		goto out_kfree;
+		goto out_unlock;
 
 	sched_exec();
 
@@ -1312,14 +1335,10 @@
 
 	bprm->argc = count(argv, MAX_ARG_STRINGS);
 	if ((retval = bprm->argc) < 0)
-		goto out_mm;
+		goto out;
 
 	bprm->envc = count(envp, MAX_ARG_STRINGS);
 	if ((retval = bprm->envc) < 0)
-		goto out_mm;
-
-	retval = security_bprm_alloc(bprm);
-	if (retval)
 		goto out;
 
 	retval = prepare_binprm(bprm);
@@ -1341,21 +1360,18 @@
 
 	current->flags &= ~PF_KTHREAD;
 	retval = search_binary_handler(bprm,regs);
-	if (retval >= 0) {
-		/* execve success */
-		security_bprm_free(bprm);
-		acct_update_integrals(current);
-		free_bprm(bprm);
-		if (displaced)
-			put_files_struct(displaced);
-		return retval;
-	}
+	if (retval < 0)
+		goto out;
+
+	/* execve succeeded */
+	mutex_unlock(&current->cred_exec_mutex);
+	acct_update_integrals(current);
+	free_bprm(bprm);
+	if (displaced)
+		put_files_struct(displaced);
+	return retval;
 
 out:
-	if (bprm->security)
-		security_bprm_free(bprm);
-
-out_mm:
 	if (bprm->mm)
 		mmput (bprm->mm);
 
@@ -1364,7 +1380,11 @@
 		allow_write_access(bprm->file);
 		fput(bprm->file);
 	}
-out_kfree:
+
+out_unlock:
+	mutex_unlock(&current->cred_exec_mutex);
+
+out_free:
 	free_bprm(bprm);
 
 out_files:
@@ -1396,6 +1416,7 @@
  */
 static int format_corename(char *corename, long signr)
 {
+	const struct cred *cred = current_cred();
 	const char *pat_ptr = core_pattern;
 	int ispipe = (*pat_ptr == '|');
 	char *out_ptr = corename;
@@ -1432,7 +1453,7 @@
 			/* uid */
 			case 'u':
 				rc = snprintf(out_ptr, out_end - out_ptr,
-					      "%d", current->uid);
+					      "%d", cred->uid);
 				if (rc > out_end - out_ptr)
 					goto out;
 				out_ptr += rc;
@@ -1440,7 +1461,7 @@
 			/* gid */
 			case 'g':
 				rc = snprintf(out_ptr, out_end - out_ptr,
-					      "%d", current->gid);
+					      "%d", cred->gid);
 				if (rc > out_end - out_ptr)
 					goto out;
 				out_ptr += rc;
@@ -1716,8 +1737,9 @@
 	struct linux_binfmt * binfmt;
 	struct inode * inode;
 	struct file * file;
+	const struct cred *old_cred;
+	struct cred *cred;
 	int retval = 0;
-	int fsuid = current->fsuid;
 	int flag = 0;
 	int ispipe = 0;
 	unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
@@ -1730,12 +1752,20 @@
 	binfmt = current->binfmt;
 	if (!binfmt || !binfmt->core_dump)
 		goto fail;
+
+	cred = prepare_creds();
+	if (!cred) {
+		retval = -ENOMEM;
+		goto fail;
+	}
+
 	down_write(&mm->mmap_sem);
 	/*
 	 * If another thread got here first, or we are not dumpable, bail out.
 	 */
 	if (mm->core_state || !get_dumpable(mm)) {
 		up_write(&mm->mmap_sem);
+		put_cred(cred);
 		goto fail;
 	}
 
@@ -1746,12 +1776,16 @@
 	 */
 	if (get_dumpable(mm) == 2) {	/* Setuid core dump mode */
 		flag = O_EXCL;		/* Stop rewrite attacks */
-		current->fsuid = 0;	/* Dump root private */
+		cred->fsuid = 0;	/* Dump root private */
 	}
 
 	retval = coredump_wait(exit_code, &core_state);
-	if (retval < 0)
+	if (retval < 0) {
+		put_cred(cred);
 		goto fail;
+	}
+
+	old_cred = override_creds(cred);
 
 	/*
 	 * Clear any false indication of pending signals that might
@@ -1823,7 +1857,7 @@
 	 * Dont allow local users get cute and trick others to coredump
 	 * into their pre-created files:
 	 */
-	if (inode->i_uid != current->fsuid)
+	if (inode->i_uid != current_fsuid())
 		goto close_fail;
 	if (!file->f_op)
 		goto close_fail;
@@ -1842,7 +1876,8 @@
 	if (helper_argv)
 		argv_free(helper_argv);
 
-	current->fsuid = fsuid;
+	revert_creds(old_cred);
+	put_cred(cred);
 	coredump_finish(mm);
 fail:
 	return retval;
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 890e018..197c7db 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
+#include <linux/sched.h>
 
 #define dprintk(fmt, args...) do{}while(0)
 
@@ -249,6 +250,7 @@
 static int get_name(struct vfsmount *mnt, struct dentry *dentry,
 		char *name, struct dentry *child)
 {
+	const struct cred *cred = current_cred();
 	struct inode *dir = dentry->d_inode;
 	int error;
 	struct file *file;
@@ -263,7 +265,7 @@
 	/*
 	 * Open the directory ...
 	 */
-	file = dentry_open(dget(dentry), mntget(mnt), O_RDONLY);
+	file = dentry_open(dget(dentry), mntget(mnt), O_RDONLY, cred);
 	error = PTR_ERR(file);
 	if (IS_ERR(file))
 		goto out;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 6dac7ba..4a29d63 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -1193,7 +1193,7 @@
 	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
 	root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
 	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
-		sbi->s_resuid != current->fsuid &&
+		sbi->s_resuid != current_fsuid() &&
 		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
 		return 0;
 	}
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index f597413..8d0add6 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -550,7 +550,7 @@
 
 	sb->s_dirt = 1;
 	mark_buffer_dirty(bh2);
-	inode->i_uid = current->fsuid;
+	inode->i_uid = current_fsuid();
 	if (test_opt (sb, GRPID))
 		inode->i_gid = dir->i_gid;
 	else if (dir->i_mode & S_ISGID) {
@@ -558,7 +558,7 @@
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
 	} else
-		inode->i_gid = current->fsgid;
+		inode->i_gid = current_fsgid();
 	inode->i_mode = mode;
 
 	inode->i_ino = ino;
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index f5b57a2..0dbf1c0 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -1422,7 +1422,7 @@
 	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
 	root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
 	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
-		sbi->s_resuid != current->fsuid &&
+		sbi->s_resuid != current_fsuid() &&
 		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
 		return 0;
 	}
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index 47b678d..490bd0e 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -539,7 +539,7 @@
 		percpu_counter_inc(&sbi->s_dirs_counter);
 	sb->s_dirt = 1;
 
-	inode->i_uid = current->fsuid;
+	inode->i_uid = current_fsuid();
 	if (test_opt (sb, GRPID))
 		inode->i_gid = dir->i_gid;
 	else if (dir->i_mode & S_ISGID) {
@@ -547,7 +547,7 @@
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
 	} else
-		inode->i_gid = current->fsgid;
+		inode->i_gid = current_fsgid();
 	inode->i_mode = mode;
 
 	inode->i_ino = ino;
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index db35cfd..38b3acf 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -624,7 +624,7 @@
 		return 1;
 
 	/* Hm, nope.  Are (enough) root reserved blocks available? */
-	if (sbi->s_resuid == current->fsuid ||
+	if (sbi->s_resuid == current_fsuid() ||
 	    ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) ||
 	    capable(CAP_SYS_RESOURCE)) {
 		if (free_blocks >= (nblocks + dirty_blocks))
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 2a117e2..08cac9f 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -787,7 +787,7 @@
 		spin_unlock(sb_bgl_lock(sbi, flex_group));
 	}
 
-	inode->i_uid = current->fsuid;
+	inode->i_uid = current_fsuid();
 	if (test_opt(sb, GRPID))
 		inode->i_gid = dir->i_gid;
 	else if (dir->i_mode & S_ISGID) {
@@ -795,7 +795,7 @@
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
 	} else
-		inode->i_gid = current->fsgid;
+		inode->i_gid = current_fsgid();
 	inode->i_mode = mode;
 
 	inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb);
diff --git a/fs/fat/file.c b/fs/fat/file.c
index f06a4e5..0a7f4a9 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -304,7 +304,7 @@
 {
 	mode_t allow_utime = sbi->options.allow_utime;
 
-	if (current->fsuid != inode->i_uid) {
+	if (current_fsuid() != inode->i_uid) {
 		if (in_group_p(inode->i_gid))
 			allow_utime >>= 3;
 		if (allow_utime & MAY_WRITE)
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index bdd8fb7..d937aaf 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -926,8 +926,8 @@
 
 	opts->isvfat = is_vfat;
 
-	opts->fs_uid = current->uid;
-	opts->fs_gid = current->gid;
+	opts->fs_uid = current_uid();
+	opts->fs_gid = current_gid();
 	opts->fs_fmask = opts->fs_dmask = current->fs->umask;
 	opts->allow_utime = -1;
 	opts->codepage = fat_default_codepage;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 549daf8..cdc1419 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -212,13 +212,14 @@
 int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
 		int force)
 {
+	const struct cred *cred = current_cred();
 	int err;
 	
 	err = security_file_set_fowner(filp);
 	if (err)
 		return err;
 
-	f_modown(filp, pid, type, current->uid, current->euid, force);
+	f_modown(filp, pid, type, cred->uid, cred->euid, force);
 	return 0;
 }
 EXPORT_SYMBOL(__f_setown);
@@ -407,10 +408,17 @@
 static inline int sigio_perm(struct task_struct *p,
                              struct fown_struct *fown, int sig)
 {
-	return (((fown->euid == 0) ||
-		 (fown->euid == p->suid) || (fown->euid == p->uid) ||
-		 (fown->uid == p->suid) || (fown->uid == p->uid)) &&
-		!security_file_send_sigiotask(p, fown, sig));
+	const struct cred *cred;
+	int ret;
+
+	rcu_read_lock();
+	cred = __task_cred(p);
+	ret = ((fown->euid == 0 ||
+		fown->euid == cred->suid || fown->euid == cred->uid ||
+		fown->uid  == cred->suid || fown->uid  == cred->uid) &&
+	       !security_file_send_sigiotask(p, fown, sig));
+	rcu_read_unlock();
+	return ret;
 }
 
 static void send_sigio_to_task(struct task_struct *p,
diff --git a/fs/file_table.c b/fs/file_table.c
index 5ad0eca..0fbcacc 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -36,7 +36,9 @@
 
 static inline void file_free_rcu(struct rcu_head *head)
 {
-	struct file *f =  container_of(head, struct file, f_u.fu_rcuhead);
+	struct file *f = container_of(head, struct file, f_u.fu_rcuhead);
+
+	put_cred(f->f_cred);
 	kmem_cache_free(filp_cachep, f);
 }
 
@@ -94,7 +96,7 @@
  */
 struct file *get_empty_filp(void)
 {
-	struct task_struct *tsk;
+	const struct cred *cred = current_cred();
 	static int old_max;
 	struct file * f;
 
@@ -118,12 +120,10 @@
 	if (security_file_alloc(f))
 		goto fail_sec;
 
-	tsk = current;
 	INIT_LIST_HEAD(&f->f_u.fu_list);
 	atomic_long_set(&f->f_count, 1);
 	rwlock_init(&f->f_owner.lock);
-	f->f_uid = tsk->fsuid;
-	f->f_gid = tsk->fsgid;
+	f->f_cred = get_cred(cred);
 	eventpoll_init_file(f);
 	/* f->f_version: 0 */
 	return f;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index b723614..fba5716 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -87,8 +87,8 @@
 
 static void fuse_req_init_context(struct fuse_req *req)
 {
-	req->in.h.uid = current->fsuid;
-	req->in.h.gid = current->fsgid;
+	req->in.h.uid = current_fsuid();
+	req->in.h.gid = current_fsgid();
 	req->in.h.pid = current->pid;
 }
 
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index fd03330..95bc22b 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -869,18 +869,25 @@
  */
 int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
 {
+	const struct cred *cred;
+	int ret;
+
 	if (fc->flags & FUSE_ALLOW_OTHER)
 		return 1;
 
-	if (task->euid == fc->user_id &&
-	    task->suid == fc->user_id &&
-	    task->uid == fc->user_id &&
-	    task->egid == fc->group_id &&
-	    task->sgid == fc->group_id &&
-	    task->gid == fc->group_id)
-		return 1;
+	rcu_read_lock();
+	ret = 0;
+	cred = __task_cred(task);
+	if (cred->euid == fc->user_id &&
+	    cred->suid == fc->user_id &&
+	    cred->uid  == fc->user_id &&
+	    cred->egid == fc->group_id &&
+	    cred->sgid == fc->group_id &&
+	    cred->gid  == fc->group_id)
+		ret = 1;
+	rcu_read_unlock();
 
-	return 0;
+	return ret;
 }
 
 static int fuse_access(struct inode *inode, int mask)
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 7cee695..d576168 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -705,18 +705,18 @@
 	    (dip->i_inode.i_mode & S_ISUID) && dip->i_inode.i_uid) {
 		if (S_ISDIR(*mode))
 			*mode |= S_ISUID;
-		else if (dip->i_inode.i_uid != current->fsuid)
+		else if (dip->i_inode.i_uid != current_fsuid())
 			*mode &= ~07111;
 		*uid = dip->i_inode.i_uid;
 	} else
-		*uid = current->fsuid;
+		*uid = current_fsuid();
 
 	if (dip->i_inode.i_mode & S_ISGID) {
 		if (S_ISDIR(*mode))
 			*mode |= S_ISGID;
 		*gid = dip->i_inode.i_gid;
 	} else
-		*gid = current->fsgid;
+		*gid = current_fsgid();
 }
 
 static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
@@ -1124,8 +1124,8 @@
 		return -EPERM;
 
 	if ((dip->i_inode.i_mode & S_ISVTX) &&
-	    dip->i_inode.i_uid != current->fsuid &&
-	    ip->i_inode.i_uid != current->fsuid && !capable(CAP_FOWNER))
+	    dip->i_inode.i_uid != current_fsuid() &&
+	    ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER))
 		return -EPERM;
 
 	if (IS_APPEND(&dip->i_inode))
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index c69b7ac..9435dda 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -155,8 +155,8 @@
 	hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
 	inode->i_ino = HFS_SB(sb)->next_id++;
 	inode->i_mode = mode;
-	inode->i_uid = current->fsuid;
-	inode->i_gid = current->fsgid;
+	inode->i_uid = current_fsuid();
+	inode->i_gid = current_fsgid();
 	inode->i_nlink = 1;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 	HFS_I(inode)->flags = 0;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 3c7c763..c8b5acf 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -210,8 +210,8 @@
 	int tmp, token;
 
 	/* initialize the sb with defaults */
-	hsb->s_uid = current->uid;
-	hsb->s_gid = current->gid;
+	hsb->s_uid = current_uid();
+	hsb->s_gid = current_gid();
 	hsb->s_file_umask = 0133;
 	hsb->s_dir_umask = 0022;
 	hsb->s_type = hsb->s_creator = cpu_to_be32(0x3f3f3f3f);	/* == '????' */
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index b207f0e..f105ee9 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -296,8 +296,8 @@
 
 	inode->i_ino = HFSPLUS_SB(sb).next_cnid++;
 	inode->i_mode = mode;
-	inode->i_uid = current->fsuid;
-	inode->i_gid = current->fsgid;
+	inode->i_uid = current_fsuid();
+	inode->i_gid = current_fsgid();
 	inode->i_nlink = 1;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 	INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index 9699c56..bab7f8d 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -49,8 +49,8 @@
 	opts->creator = HFSPLUS_DEF_CR_TYPE;
 	opts->type = HFSPLUS_DEF_CR_TYPE;
 	opts->umask = current->fs->umask;
-	opts->uid = current->uid;
-	opts->gid = current->gid;
+	opts->uid = current_uid();
+	opts->gid = current_gid();
 	opts->part = -1;
 	opts->session = -1;
 }
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 10783f3..b649232 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -92,11 +92,11 @@
 	inc_nlink(dir);
 	insert_inode_hash(result);
 
-	if (result->i_uid != current->fsuid ||
-	    result->i_gid != current->fsgid ||
+	if (result->i_uid != current_fsuid() ||
+	    result->i_gid != current_fsgid() ||
 	    result->i_mode != (mode | S_IFDIR)) {
-		result->i_uid = current->fsuid;
-		result->i_gid = current->fsgid;
+		result->i_uid = current_fsuid();
+		result->i_gid = current_fsgid();
 		result->i_mode = mode | S_IFDIR;
 		hpfs_write_inode_nolock(result);
 	}
@@ -184,11 +184,11 @@
 
 	insert_inode_hash(result);
 
-	if (result->i_uid != current->fsuid ||
-	    result->i_gid != current->fsgid ||
+	if (result->i_uid != current_fsuid() ||
+	    result->i_gid != current_fsgid() ||
 	    result->i_mode != (mode | S_IFREG)) {
-		result->i_uid = current->fsuid;
-		result->i_gid = current->fsgid;
+		result->i_uid = current_fsuid();
+		result->i_gid = current_fsgid();
 		result->i_mode = mode | S_IFREG;
 		hpfs_write_inode_nolock(result);
 	}
@@ -247,8 +247,8 @@
 	result->i_mtime.tv_nsec = 0;
 	result->i_atime.tv_nsec = 0;
 	hpfs_i(result)->i_ea_size = 0;
-	result->i_uid = current->fsuid;
-	result->i_gid = current->fsgid;
+	result->i_uid = current_fsuid();
+	result->i_gid = current_fsgid();
 	result->i_nlink = 1;
 	result->i_size = 0;
 	result->i_blocks = 1;
@@ -325,8 +325,8 @@
 	result->i_atime.tv_nsec = 0;
 	hpfs_i(result)->i_ea_size = 0;
 	result->i_mode = S_IFLNK | 0777;
-	result->i_uid = current->fsuid;
-	result->i_gid = current->fsgid;
+	result->i_uid = current_fsuid();
+	result->i_gid = current_fsgid();
 	result->i_blocks = 1;
 	result->i_nlink = 1;
 	result->i_size = strlen(symlink);
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 29ad461..0d049b8 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -475,8 +475,8 @@
 
 	init_MUTEX(&sbi->hpfs_creation_de);
 
-	uid = current->uid;
-	gid = current->gid;
+	uid = current_uid();
+	gid = current_gid();
 	umask = current->fs->umask;
 	lowercase = 0;
 	conv = CONV_BINARY;
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index 2b3d182..b278f7f 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -426,6 +426,7 @@
 
 static int hppfs_open(struct inode *inode, struct file *file)
 {
+	const struct cred *cred = file->f_cred;
 	struct hppfs_private *data;
 	struct vfsmount *proc_mnt;
 	struct dentry *proc_dentry;
@@ -446,7 +447,7 @@
 
 	/* XXX This isn't closed anywhere */
 	data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt),
-				      file_mode(file->f_mode));
+				      file_mode(file->f_mode), cred);
 	err = PTR_ERR(data->proc_file);
 	if (IS_ERR(data->proc_file))
 		goto out_free1;
@@ -489,6 +490,7 @@
 
 static int hppfs_dir_open(struct inode *inode, struct file *file)
 {
+	const struct cred *cred = file->f_cred;
 	struct hppfs_private *data;
 	struct vfsmount *proc_mnt;
 	struct dentry *proc_dentry;
@@ -502,7 +504,7 @@
 	proc_dentry = HPPFS_I(inode)->proc_dentry;
 	proc_mnt = inode->i_sb->s_fs_info;
 	data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt),
-				      file_mode(file->f_mode));
+				      file_mode(file->f_mode), cred);
 	err = PTR_ERR(data->proc_file);
 	if (IS_ERR(data->proc_file))
 		goto out_free;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 61edc70..7d479ce 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -551,9 +551,9 @@
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
 	} else {
-		gid = current->fsgid;
+		gid = current_fsgid();
 	}
-	inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, gid, mode, dev);
+	inode = hugetlbfs_get_inode(dir->i_sb, current_fsuid(), gid, mode, dev);
 	if (inode) {
 		dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 		d_instantiate(dentry, inode);
@@ -586,9 +586,9 @@
 	if (dir->i_mode & S_ISGID)
 		gid = dir->i_gid;
 	else
-		gid = current->fsgid;
+		gid = current_fsgid();
 
-	inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid,
+	inode = hugetlbfs_get_inode(dir->i_sb, current_fsuid(),
 					gid, S_IFLNK|S_IRWXUGO, 0);
 	if (inode) {
 		int l = strlen(symname)+1;
@@ -854,8 +854,8 @@
 
 	config.nr_blocks = -1; /* No limit on size by default */
 	config.nr_inodes = -1; /* No limit on number of inodes by default */
-	config.uid = current->fsuid;
-	config.gid = current->fsgid;
+	config.uid = current_fsuid();
+	config.gid = current_fsgid();
 	config.mode = 0755;
 	config.hstate = &default_hstate;
 	ret = hugetlbfs_parse_options(data, &config);
@@ -951,6 +951,7 @@
 	struct inode *inode;
 	struct dentry *dentry, *root;
 	struct qstr quick_string;
+	struct user_struct *user = current_user();
 
 	if (!hugetlbfs_vfsmount)
 		return ERR_PTR(-ENOENT);
@@ -958,7 +959,7 @@
 	if (!can_do_hugetlb_shm())
 		return ERR_PTR(-EPERM);
 
-	if (!user_shm_lock(size, current->user))
+	if (!user_shm_lock(size, user))
 		return ERR_PTR(-ENOMEM);
 
 	root = hugetlbfs_vfsmount->mnt_root;
@@ -970,8 +971,8 @@
 		goto out_shm_unlock;
 
 	error = -ENOSPC;
-	inode = hugetlbfs_get_inode(root->d_sb, current->fsuid,
-				current->fsgid, S_IFREG | S_IRWXUGO, 0);
+	inode = hugetlbfs_get_inode(root->d_sb, current_fsuid(),
+				current_fsgid(), S_IFREG | S_IRWXUGO, 0);
 	if (!inode)
 		goto out_dentry;
 
@@ -998,7 +999,7 @@
 out_dentry:
 	dput(dentry);
 out_shm_unlock:
-	user_shm_unlock(size, current->user);
+	user_shm_unlock(size, user);
 	return ERR_PTR(error);
 }
 
diff --git a/fs/inotify_user.c b/fs/inotify_user.c
index d367e9b..e2425bb 100644
--- a/fs/inotify_user.c
+++ b/fs/inotify_user.c
@@ -601,7 +601,7 @@
 		goto out_put_fd;
 	}
 
-	user = get_uid(current->user);
+	user = get_current_user();
 	if (unlikely(atomic_read(&user->inotify_devs) >=
 			inotify_max_user_instances)) {
 		ret = -EMFILE;
diff --git a/fs/internal.h b/fs/internal.h
index 80aa9a0..53af885 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -10,6 +10,7 @@
  */
 
 struct super_block;
+struct linux_binprm;
 
 /*
  * block_dev.c
@@ -40,6 +41,11 @@
 extern void __init chrdev_init(void);
 
 /*
+ * exec.c
+ */
+extern void check_unsafe_exec(struct linux_binprm *);
+
+/*
  * namespace.c
  */
 extern int copy_mount_options(const void __user *, unsigned long *);
diff --git a/fs/ioprio.c b/fs/ioprio.c
index da3cc46..3569e0a 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -31,10 +31,16 @@
 {
 	int err;
 	struct io_context *ioc;
+	const struct cred *cred = current_cred(), *tcred;
 
-	if (task->uid != current->euid &&
-	    task->uid != current->uid && !capable(CAP_SYS_NICE))
+	rcu_read_lock();
+	tcred = __task_cred(task);
+	if (tcred->uid != cred->euid &&
+	    tcred->uid != cred->uid && !capable(CAP_SYS_NICE)) {
+		rcu_read_unlock();
 		return -EPERM;
+	}
+	rcu_read_unlock();
 
 	err = security_task_setioprio(task, ioprio);
 	if (err)
@@ -123,7 +129,7 @@
 			break;
 		case IOPRIO_WHO_USER:
 			if (!who)
-				user = current->user;
+				user = current_user();
 			else
 				user = find_user(who);
 
@@ -131,7 +137,7 @@
 				break;
 
 			do_each_thread(g, p) {
-				if (p->uid != who)
+				if (__task_cred(p)->uid != who)
 					continue;
 				ret = set_task_ioprio(p, ioprio);
 				if (ret)
@@ -216,7 +222,7 @@
 			break;
 		case IOPRIO_WHO_USER:
 			if (!who)
-				user = current->user;
+				user = current_user();
 			else
 				user = find_user(who);
 
@@ -224,7 +230,7 @@
 				break;
 
 			do_each_thread(g, p) {
-				if (p->uid != user->uid)
+				if (__task_cred(p)->uid != user->uid)
 					continue;
 				tmpio = get_task_ioprio(p);
 				if (tmpio < 0)
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index ed6574b..70022fd 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -93,13 +93,13 @@
 		return ERR_PTR(rc);
 	}
 
-	inode->i_uid = current->fsuid;
+	inode->i_uid = current_fsuid();
 	if (parent->i_mode & S_ISGID) {
 		inode->i_gid = parent->i_gid;
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
 	} else
-		inode->i_gid = current->fsgid;
+		inode->i_gid = current_fsgid();
 
 	/*
 	 * New inodes need to save sane values on disk when
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 70fc63a..e05d044 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -115,14 +115,14 @@
 		snprintf(buf, len, "unspecified");
 		break;
 	case AF_INET:
-		snprintf(buf, len, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
+		snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr);
 		break;
 	case AF_INET6:
 		if (ipv6_addr_v4mapped(&sin6->sin6_addr))
-			snprintf(buf, len, NIPQUAD_FMT,
-				 NIPQUAD(sin6->sin6_addr.s6_addr32[3]));
+			snprintf(buf, len, "%pI4",
+				 &sin6->sin6_addr.s6_addr32[3]);
 		else
-			snprintf(buf, len, NIP6_FMT, NIP6(sin6->sin6_addr));
+			snprintf(buf, len, "%pI6", &sin6->sin6_addr);
 		break;
 	default:
 		snprintf(buf, len, "unsupported address family");
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 4e7e958..ffd3461 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -179,7 +179,7 @@
 
 	if (!nsm_use_hostnames) {
 		snprintf(buffer, XDR_ADDRBUF_LEN,
-			 NIPQUAD_FMT, NIPQUAD(argp->addr));
+			 "%pI4", &argp->addr);
 		name = buffer;
 	}
 
diff --git a/fs/locks.c b/fs/locks.c
index 09062e3..46a2e12 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1349,7 +1349,7 @@
 	struct inode *inode = dentry->d_inode;
 	int error, rdlease_count = 0, wrlease_count = 0;
 
-	if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
+	if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE))
 		return -EACCES;
 	if (!S_ISREG(inode->i_mode))
 		return -EINVAL;
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 703cc35..3aebe32 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -262,8 +262,8 @@
 		iput(inode);
 		return NULL;
 	}
-	inode->i_uid = current->fsuid;
-	inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+	inode->i_uid = current_fsuid();
+	inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current_fsgid();
 	inode->i_ino = j;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 	inode->i_blocks = 0;
diff --git a/fs/namei.c b/fs/namei.c
index d34e0f9..af3783f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -186,7 +186,7 @@
 
 	mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
 
-	if (current->fsuid == inode->i_uid)
+	if (current_fsuid() == inode->i_uid)
 		mode >>= 6;
 	else {
 		if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
@@ -441,7 +441,7 @@
 	if (inode->i_op && inode->i_op->permission)
 		return -EAGAIN;
 
-	if (current->fsuid == inode->i_uid)
+	if (current_fsuid() == inode->i_uid)
 		mode >>= 6;
 	else if (in_group_p(inode->i_gid))
 		mode >>= 3;
@@ -1334,11 +1334,13 @@
  */
 static inline int check_sticky(struct inode *dir, struct inode *inode)
 {
+	uid_t fsuid = current_fsuid();
+
 	if (!(dir->i_mode & S_ISVTX))
 		return 0;
-	if (inode->i_uid == current->fsuid)
+	if (inode->i_uid == fsuid)
 		return 0;
-	if (dir->i_uid == current->fsuid)
+	if (dir->i_uid == fsuid)
 		return 0;
 	return !capable(CAP_FOWNER);
 }
diff --git a/fs/namespace.c b/fs/namespace.c
index 65b3dc8..1c09cab 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1176,7 +1176,7 @@
 	if (S_ISLNK(path->dentry->d_inode->i_mode))
 		return -EPERM;
 	if (path->dentry->d_inode->i_mode & S_ISVTX) {
-		if (current->uid != path->dentry->d_inode->i_uid)
+		if (current_uid() != path->dentry->d_inode->i_uid)
 			return -EPERM;
 	}
 	if (inode_permission(path->dentry->d_inode, MAY_WRITE))
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 3a97c95..6d04e05 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -40,10 +40,10 @@
 	struct inode *inode = file->f_path.dentry->d_inode;
 	struct ncp_fs_info info;
 
-	if ((file_permission(file, MAY_WRITE) != 0)
-	    && (current->uid != server->m.mounted_uid)) {
+	if (file_permission(file, MAY_WRITE) != 0
+	    && current_uid() != server->m.mounted_uid)
 		return -EACCES;
-	}
+
 	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
@@ -70,10 +70,10 @@
 	struct inode *inode = file->f_path.dentry->d_inode;
 	struct ncp_fs_info_v2 info2;
 
-	if ((file_permission(file, MAY_WRITE) != 0)
-	    && (current->uid != server->m.mounted_uid)) {
+	if (file_permission(file, MAY_WRITE) != 0
+	    && current_uid() != server->m.mounted_uid)
 		return -EACCES;
-	}
+
 	if (copy_from_user(&info2, arg, sizeof(info2)))
 		return -EFAULT;
 
@@ -141,10 +141,10 @@
 	struct inode *inode = file->f_path.dentry->d_inode;
 	struct compat_ncp_fs_info_v2 info2;
 
-	if ((file_permission(file, MAY_WRITE) != 0)
-	    && (current->uid != server->m.mounted_uid)) {
+	if (file_permission(file, MAY_WRITE) != 0
+	    && current_uid() != server->m.mounted_uid)
 		return -EACCES;
-	}
+
 	if (copy_from_user(&info2, arg, sizeof(info2)))
 		return -EFAULT;
 
@@ -270,16 +270,17 @@
 	struct ncp_ioctl_request request;
 	char* bouncebuffer;
 	void __user *argp = (void __user *)arg;
+	uid_t uid = current_uid();
 
 	switch (cmd) {
 #ifdef CONFIG_COMPAT
 	case NCP_IOC_NCPREQUEST_32:
 #endif
 	case NCP_IOC_NCPREQUEST:
-		if ((file_permission(filp, MAY_WRITE) != 0)
-		    && (current->uid != server->m.mounted_uid)) {
+		if (file_permission(filp, MAY_WRITE) != 0
+		    && uid != server->m.mounted_uid)
 			return -EACCES;
-		}
+
 #ifdef CONFIG_COMPAT
 		if (cmd == NCP_IOC_NCPREQUEST_32) {
 			struct compat_ncp_ioctl_request request32;
@@ -356,10 +357,10 @@
 	case NCP_IOC_GETMOUNTUID16:
 	case NCP_IOC_GETMOUNTUID32:
 	case NCP_IOC_GETMOUNTUID64:
-		if ((file_permission(filp, MAY_READ) != 0)
-			&& (current->uid != server->m.mounted_uid)) {
+		if (file_permission(filp, MAY_READ) != 0
+			&& uid != server->m.mounted_uid)
 			return -EACCES;
-		}
+
 		if (cmd == NCP_IOC_GETMOUNTUID16) {
 			u16 uid;
 			SET_UID(uid, server->m.mounted_uid);
@@ -380,11 +381,10 @@
 		{
 			struct ncp_setroot_ioctl sr;
 
-			if ((file_permission(filp, MAY_READ) != 0)
-			    && (current->uid != server->m.mounted_uid))
-			{
+			if (file_permission(filp, MAY_READ) != 0
+			    && uid != server->m.mounted_uid)
 				return -EACCES;
-			}
+
 			if (server->m.mounted_vol[0]) {
 				struct dentry* dentry = inode->i_sb->s_root;
 
@@ -408,6 +408,7 @@
 				return -EFAULT;
 			return 0;
 		}
+
 	case NCP_IOC_SETROOT:
 		{
 			struct ncp_setroot_ioctl sr;
@@ -455,11 +456,10 @@
 
 #ifdef CONFIG_NCPFS_PACKET_SIGNING	
 	case NCP_IOC_SIGN_INIT:
-		if ((file_permission(filp, MAY_WRITE) != 0)
-		    && (current->uid != server->m.mounted_uid))
-		{
+		if (file_permission(filp, MAY_WRITE) != 0
+		    && uid != server->m.mounted_uid)
 			return -EACCES;
-		}
+
 		if (argp) {
 			if (server->sign_wanted)
 			{
@@ -478,24 +478,22 @@
 		return 0;		
 		
         case NCP_IOC_SIGN_WANTED:
-		if ((file_permission(filp, MAY_READ) != 0)
-		    && (current->uid != server->m.mounted_uid))
-		{
+		if (file_permission(filp, MAY_READ) != 0
+		    && uid != server->m.mounted_uid)
 			return -EACCES;
-		}
 		
                 if (put_user(server->sign_wanted, (int __user *)argp))
 			return -EFAULT;
                 return 0;
+
 	case NCP_IOC_SET_SIGN_WANTED:
 		{
 			int newstate;
 
-			if ((file_permission(filp, MAY_WRITE) != 0)
-			    && (current->uid != server->m.mounted_uid))
-			{
+			if (file_permission(filp, MAY_WRITE) != 0
+			    && uid != server->m.mounted_uid)
 				return -EACCES;
-			}
+
 			/* get only low 8 bits... */
 			if (get_user(newstate, (unsigned char __user *)argp))
 				return -EFAULT;
@@ -512,11 +510,10 @@
 
 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
 	case NCP_IOC_LOCKUNLOCK:
-		if ((file_permission(filp, MAY_WRITE) != 0)
-		    && (current->uid != server->m.mounted_uid))
-		{
+		if (file_permission(filp, MAY_WRITE) != 0
+		    && uid != server->m.mounted_uid)
 			return -EACCES;
-		}
+
 		{
 			struct ncp_lock_ioctl	 rqdata;
 
@@ -585,9 +582,8 @@
 
 #ifdef CONFIG_COMPAT
 	case NCP_IOC_GETOBJECTNAME_32:
-		if (current->uid != server->m.mounted_uid) {
+		if (uid != server->m.mounted_uid)
 			return -EACCES;
-		}
 		{
 			struct compat_ncp_objectname_ioctl user;
 			size_t outl;
@@ -609,10 +605,10 @@
 			return 0;
 		}
 #endif
+
 	case NCP_IOC_GETOBJECTNAME:
-		if (current->uid != server->m.mounted_uid) {
+		if (uid != server->m.mounted_uid)
 			return -EACCES;
-		}
 		{
 			struct ncp_objectname_ioctl user;
 			size_t outl;
@@ -633,13 +629,13 @@
 				return -EFAULT;
 			return 0;
 		}
+
 #ifdef CONFIG_COMPAT
 	case NCP_IOC_SETOBJECTNAME_32:
 #endif
 	case NCP_IOC_SETOBJECTNAME:
-		if (current->uid != server->m.mounted_uid) {
+		if (uid != server->m.mounted_uid)
 			return -EACCES;
-		}
 		{
 			struct ncp_objectname_ioctl user;
 			void* newname;
@@ -691,13 +687,13 @@
 			kfree(oldname);
 			return 0;
 		}
+
 #ifdef CONFIG_COMPAT
 	case NCP_IOC_GETPRIVATEDATA_32:
 #endif
 	case NCP_IOC_GETPRIVATEDATA:
-		if (current->uid != server->m.mounted_uid) {
+		if (uid != server->m.mounted_uid)
 			return -EACCES;
-		}
 		{
 			struct ncp_privatedata_ioctl user;
 			size_t outl;
@@ -736,13 +732,13 @@
 
 			return 0;
 		}
+
 #ifdef CONFIG_COMPAT
 	case NCP_IOC_SETPRIVATEDATA_32:
 #endif
 	case NCP_IOC_SETPRIVATEDATA:
-		if (current->uid != server->m.mounted_uid) {
+		if (uid != server->m.mounted_uid)
 			return -EACCES;
-		}
 		{
 			struct ncp_privatedata_ioctl user;
 			void* new;
@@ -794,9 +790,10 @@
 #endif /* CONFIG_NCPFS_NLS */
 
 	case NCP_IOC_SETDENTRYTTL:
-		if ((file_permission(filp, MAY_WRITE) != 0) &&
-				 (current->uid != server->m.mounted_uid))
+		if (file_permission(filp, MAY_WRITE) != 0 &&
+		    uid != server->m.mounted_uid)
 			return -EACCES;
+
 		{
 			u_int32_t user;
 
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 8478fc2..d74d16c 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -329,7 +329,7 @@
 	}
 
 	snprintf(nfs_data.hostname, sizeof(nfs_data.hostname),
-		 "%u.%u.%u.%u", NIPQUAD(servaddr));
+		 "%pI4", &servaddr);
 	return 0;
 }
 
@@ -421,8 +421,8 @@
 {
 	struct sockaddr_in sin;
 
-	printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n",
-		program, version, NIPQUAD(servaddr));
+	printk(KERN_NOTICE "Looking up port of RPC %d/%d on %pI4\n",
+		program, version, &servaddr);
 	set_sockaddr(&sin, servaddr, 0);
 	return rpcb_getport_sync(&sin, program, version, proto);
 }
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index f48db67..bb0313ac 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -462,14 +462,12 @@
 	switch (sap->sa_family) {
 	case AF_INET: {
 		struct sockaddr_in *sin = (struct sockaddr_in *)sap;
-		seq_printf(m, ",mountaddr=" NIPQUAD_FMT,
-				NIPQUAD(sin->sin_addr.s_addr));
+		seq_printf(m, ",mountaddr=%pI4", &sin->sin_addr.s_addr);
 		break;
 	}
 	case AF_INET6: {
 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
-		seq_printf(m, ",mountaddr=" NIP6_FMT,
-				NIP6(sin6->sin6_addr));
+		seq_printf(m, ",mountaddr=%pI6", &sin6->sin6_addr);
 		break;
 	}
 	default:
diff --git a/fs/nfsctl.c b/fs/nfsctl.c
index aed8145..b1acbd6 100644
--- a/fs/nfsctl.c
+++ b/fs/nfsctl.c
@@ -10,6 +10,8 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/syscall.h>
+#include <linux/cred.h>
+#include <linux/sched.h>
 #include <linux/linkage.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
@@ -41,7 +43,8 @@
 		error = may_open(&nd, MAY_WRITE, FMODE_WRITE);
 
 	if (!error)
-		return dentry_open(nd.path.dentry, nd.path.mnt, flags);
+		return dentry_open(nd.path.dentry, nd.path.mnt, flags,
+				   current_cred());
 
 	path_put(&nd.path);
 	return ERR_PTR(error);
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 294992e..0184fe9 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -27,53 +27,70 @@
 
 int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
 {
-	struct svc_cred	cred = rqstp->rq_cred;
+	struct group_info *rqgi;
+	struct group_info *gi;
+	struct cred *new;
 	int i;
 	int flags = nfsexp_flags(rqstp, exp);
 	int ret;
 
-	if (flags & NFSEXP_ALLSQUASH) {
-		cred.cr_uid = exp->ex_anon_uid;
-		cred.cr_gid = exp->ex_anon_gid;
-		cred.cr_group_info = groups_alloc(0);
-	} else if (flags & NFSEXP_ROOTSQUASH) {
-		struct group_info *gi;
-		if (!cred.cr_uid)
-			cred.cr_uid = exp->ex_anon_uid;
-		if (!cred.cr_gid)
-			cred.cr_gid = exp->ex_anon_gid;
-		gi = groups_alloc(cred.cr_group_info->ngroups);
-		if (gi)
-			for (i = 0; i < cred.cr_group_info->ngroups; i++) {
-				if (!GROUP_AT(cred.cr_group_info, i))
-					GROUP_AT(gi, i) = exp->ex_anon_gid;
-				else
-					GROUP_AT(gi, i) = GROUP_AT(cred.cr_group_info, i);
-			}
-		cred.cr_group_info = gi;
-	} else
-		get_group_info(cred.cr_group_info);
-
-	if (cred.cr_uid != (uid_t) -1)
-		current->fsuid = cred.cr_uid;
-	else
-		current->fsuid = exp->ex_anon_uid;
-	if (cred.cr_gid != (gid_t) -1)
-		current->fsgid = cred.cr_gid;
-	else
-		current->fsgid = exp->ex_anon_gid;
-
-	if (!cred.cr_group_info)
+	/* discard any old override before preparing the new set */
+	revert_creds(get_cred(current->real_cred));
+	new = prepare_creds();
+	if (!new)
 		return -ENOMEM;
-	ret = set_current_groups(cred.cr_group_info);
-	put_group_info(cred.cr_group_info);
-	if ((cred.cr_uid)) {
-		current->cap_effective =
-			cap_drop_nfsd_set(current->cap_effective);
+
+	new->fsuid = rqstp->rq_cred.cr_uid;
+	new->fsgid = rqstp->rq_cred.cr_gid;
+
+	rqgi = rqstp->rq_cred.cr_group_info;
+
+	if (flags & NFSEXP_ALLSQUASH) {
+		new->fsuid = exp->ex_anon_uid;
+		new->fsgid = exp->ex_anon_gid;
+		gi = groups_alloc(0);
+	} else if (flags & NFSEXP_ROOTSQUASH) {
+		if (!new->fsuid)
+			new->fsuid = exp->ex_anon_uid;
+		if (!new->fsgid)
+			new->fsgid = exp->ex_anon_gid;
+
+		gi = groups_alloc(rqgi->ngroups);
+		if (!gi)
+			goto oom;
+
+		for (i = 0; i < rqgi->ngroups; i++) {
+			if (!GROUP_AT(rqgi, i))
+				GROUP_AT(gi, i) = exp->ex_anon_gid;
+			else
+				GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
+		}
 	} else {
-		current->cap_effective =
-			cap_raise_nfsd_set(current->cap_effective,
-					   current->cap_permitted);
+		gi = get_group_info(rqgi);
 	}
+
+	if (new->fsuid == (uid_t) -1)
+		new->fsuid = exp->ex_anon_uid;
+	if (new->fsgid == (gid_t) -1)
+		new->fsgid = exp->ex_anon_gid;
+
+	ret = set_groups(new, gi);
+	put_group_info(gi);
+	if (!ret)
+		goto error;
+
+	if (new->uid)
+		new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
+	else
+		new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
+							new->cap_permitted);
+	put_cred(override_creds(new));
+	return 0;
+
+oom:
+	ret = -ENOMEM;
+error:
+	abort_creds(new);
 	return ret;
 }
+
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index b79ec93..0f9d6ef 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -54,20 +54,26 @@
 static struct path rec_dir;
 static int rec_dir_init = 0;
 
-static void
-nfs4_save_user(uid_t *saveuid, gid_t *savegid)
+static int
+nfs4_save_creds(const struct cred **original_creds)
 {
-	*saveuid = current->fsuid;
-	*savegid = current->fsgid;
-	current->fsuid = 0;
-	current->fsgid = 0;
+	struct cred *new;
+
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+
+	new->fsuid = 0;
+	new->fsgid = 0;
+	*original_creds = override_creds(new);
+	put_cred(new);
+	return 0;
 }
 
 static void
-nfs4_reset_user(uid_t saveuid, gid_t savegid)
+nfs4_reset_creds(const struct cred *original)
 {
-	current->fsuid = saveuid;
-	current->fsgid = savegid;
+	revert_creds(original);
 }
 
 static void
@@ -129,10 +135,9 @@
 int
 nfsd4_create_clid_dir(struct nfs4_client *clp)
 {
+	const struct cred *original_cred;
 	char *dname = clp->cl_recdir;
 	struct dentry *dentry;
-	uid_t uid;
-	gid_t gid;
 	int status;
 
 	dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
@@ -140,7 +145,9 @@
 	if (!rec_dir_init || clp->cl_firststate)
 		return 0;
 
-	nfs4_save_user(&uid, &gid);
+	status = nfs4_save_creds(&original_cred);
+	if (status < 0)
+		return status;
 
 	/* lock the parent */
 	mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
@@ -168,7 +175,7 @@
 		clp->cl_firststate = 1;
 		nfsd4_sync_rec_dir();
 	}
-	nfs4_reset_user(uid, gid);
+	nfs4_reset_creds(original_cred);
 	dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
 	return status;
 }
@@ -211,26 +218,29 @@
 static int
 nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
 {
+	const struct cred *original_cred;
 	struct file *filp;
 	struct dentry_list_arg dla = {
 		.parent = dir,
 	};
 	struct list_head *dentries = &dla.dentries;
 	struct dentry_list *child;
-	uid_t uid;
-	gid_t gid;
 	int status;
 
 	if (!rec_dir_init)
 		return 0;
 
-	nfs4_save_user(&uid, &gid);
+	status = nfs4_save_creds(&original_cred);
+	if (status < 0)
+		return status;
 	INIT_LIST_HEAD(dentries);
 
-	filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY);
+	filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY,
+			   current_cred());
 	status = PTR_ERR(filp);
 	if (IS_ERR(filp))
 		goto out;
+	INIT_LIST_HEAD(dentries);
 	status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla);
 	fput(filp);
 	while (!list_empty(dentries)) {
@@ -249,7 +259,7 @@
 		dput(child->dentry);
 		kfree(child);
 	}
-	nfs4_reset_user(uid, gid);
+	nfs4_reset_creds(original_cred);
 	return status;
 }
 
@@ -311,8 +321,7 @@
 void
 nfsd4_remove_clid_dir(struct nfs4_client *clp)
 {
-	uid_t uid;
-	gid_t gid;
+	const struct cred *original_cred;
 	int status;
 
 	if (!rec_dir_init || !clp->cl_firststate)
@@ -322,9 +331,13 @@
 	if (status)
 		goto out;
 	clp->cl_firststate = 0;
-	nfs4_save_user(&uid, &gid);
+
+	status = nfs4_save_creds(&original_cred);
+	if (status < 0)
+		goto out;
+
 	status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
-	nfs4_reset_user(uid, gid);
+	nfs4_reset_creds(original_cred);
 	if (status == 0)
 		nfsd4_sync_rec_dir();
 	mnt_drop_write(rec_dir.mnt);
@@ -401,16 +414,21 @@
 void
 nfsd4_init_recdir(char *rec_dirname)
 {
-	uid_t			uid = 0;
-	gid_t			gid = 0;
-	int 			status;
+	const struct cred *original_cred;
+	int status;
 
 	printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
 			rec_dirname);
 
 	BUG_ON(rec_dir_init);
 
-	nfs4_save_user(&uid, &gid);
+	status = nfs4_save_creds(&original_cred);
+	if (status < 0) {
+		printk("NFSD: Unable to change credentials to find recovery"
+		       " directory: error %d\n",
+		       status);
+		return;
+	}
 
 	status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
 			&rec_dir);
@@ -420,7 +438,7 @@
 
 	if (!status)
 		rec_dir_init = 1;
-	nfs4_reset_user(uid, gid);
+	nfs4_reset_creds(original_cred);
 }
 
 void
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 1a052ac..bf4cd46 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -719,8 +719,8 @@
 		status = nfserr_clid_inuse;
 		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)
 				|| conf->cl_addr != sin->sin_addr.s_addr) {
-			dprintk("NFSD: setclientid: string in use by client"
-				"at %u.%u.%u.%u\n", NIPQUAD(conf->cl_addr));
+			dprintk("NFSD: setclientid: string in use by clientat %pI4\n",
+				&conf->cl_addr);
 			goto out;
 		}
 	}
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index e3f9783..77d7b8c 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -330,7 +330,7 @@
 		return -EINVAL;
 
 	/* get ipv4 address */
-	if (sscanf(fo_path, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) != 4)
+	if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
 		return -EINVAL;
 	if (b1 > 255 || b2 > 255 || b3 > 255 || b4 > 255)
 		return -EINVAL;
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index cd25d91..f0da7d9 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -186,9 +186,14 @@
 		 * access control settings being in effect, we cannot
 		 * fix that case easily.
 		 */
-		current->cap_effective =
-			cap_raise_nfsd_set(current->cap_effective,
-					   current->cap_permitted);
+		struct cred *new = prepare_creds();
+		if (!new)
+			return nfserrno(-ENOMEM);
+		new->cap_effective =
+			cap_raise_nfsd_set(new->cap_effective,
+					   new->cap_permitted);
+		put_cred(override_creds(new));
+		put_cred(new);
 	} else {
 		error = nfsd_setuser_and_check_port(rqstp, exp);
 		if (error)
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 4433c8f..d1c5f78 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -671,6 +671,7 @@
 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
 			int access, struct file **filp)
 {
+	const struct cred *cred = current_cred();
 	struct dentry	*dentry;
 	struct inode	*inode;
 	int		flags = O_RDONLY|O_LARGEFILE;
@@ -725,7 +726,7 @@
 		DQUOT_INIT(inode);
 	}
 	*filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt),
-				flags);
+			    flags, cred);
 	if (IS_ERR(*filp))
 		host_err = PTR_ERR(*filp);
 out_nfserr:
@@ -1169,7 +1170,7 @@
 	 * send along the gid on create when it tries to implement
 	 * setgid directories via NFS:
 	 */
-	if (current->fsuid != 0)
+	if (current_fsuid() != 0)
 		iap->ia_valid &= ~(ATTR_UID|ATTR_GID);
 	if (iap->ia_valid)
 		return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
@@ -2001,7 +2002,7 @@
 		IS_APPEND(inode)?	" append" : "",
 		__mnt_is_readonly(exp->ex_path.mnt)?	" ro" : "");
 	dprintk("      owner %d/%d user %d/%d\n",
-		inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
+		inode->i_uid, inode->i_gid, current_fsuid(), current_fsgid());
 #endif
 
 	/* Normally we reject any write/sattr etc access on a read-only file
@@ -2044,7 +2045,7 @@
 	 * with NFSv3.
 	 */
 	if ((acc & NFSD_MAY_OWNER_OVERRIDE) &&
-	    inode->i_uid == current->fsuid)
+	    inode->i_uid == current_fsuid())
 		return 0;
 
 	/* This assumes  NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */
diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c
index 52276c0..f842487 100644
--- a/fs/ocfs2/cluster/netdebug.c
+++ b/fs/ocfs2/cluster/netdebug.c
@@ -304,8 +304,8 @@
 		 * use of it here generates a warning with -Wbitwise */
 		seq_printf(seq, "%p:\n"
 			   "  krefs:           %d\n"
-			   "  sock:            %u.%u.%u.%u:%u -> "
-					      "%u.%u.%u.%u:%u\n"
+			   "  sock:            %pI4:%u -> "
+					      "%pI4:%u\n"
 			   "  remote node:     %s\n"
 			   "  page off:        %zu\n"
 			   "  handshake ok:    %u\n"
@@ -319,8 +319,8 @@
 			   "  func type:       %u\n",
 			   sc,
 			   atomic_read(&sc->sc_kref.refcount),
-			   NIPQUAD(saddr), inet ? ntohs(sport) : 0,
-			   NIPQUAD(daddr), inet ? ntohs(dport) : 0,
+			   &saddr, inet ? ntohs(sport) : 0,
+			   &daddr, inet ? ntohs(dport) : 0,
 			   sc->sc_node->nd_name,
 			   sc->sc_page_off,
 			   sc->sc_handshake_ok,
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index 816a3f6..70e8fa9 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -250,7 +250,7 @@
 
 static ssize_t o2nm_node_ipv4_address_read(struct o2nm_node *node, char *page)
 {
-	return sprintf(page, "%u.%u.%u.%u\n", NIPQUAD(node->nd_ipv4_address));
+	return sprintf(page, "%pI4\n", &node->nd_ipv4_address);
 }
 
 static ssize_t o2nm_node_ipv4_address_write(struct o2nm_node *node,
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 2bcf706..9fbe849 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -1597,8 +1597,8 @@
 	ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr,
 			      sizeof(myaddr));
 	if (ret) {
-		mlog(ML_ERROR, "bind failed with %d at address %u.%u.%u.%u\n",
-		     ret, NIPQUAD(mynode->nd_ipv4_address));
+		mlog(ML_ERROR, "bind failed with %d at address %pI4\n",
+		     ret, &mynode->nd_ipv4_address);
 		goto out;
 	}
 
@@ -1790,17 +1790,16 @@
 
 	node = o2nm_get_node_by_ip(sin.sin_addr.s_addr);
 	if (node == NULL) {
-		mlog(ML_NOTICE, "attempt to connect from unknown node at "
-		     "%u.%u.%u.%u:%d\n", NIPQUAD(sin.sin_addr.s_addr),
-		     ntohs(sin.sin_port));
+		mlog(ML_NOTICE, "attempt to connect from unknown node at %pI4:%d\n",
+		     &sin.sin_addr.s_addr, ntohs(sin.sin_port));
 		ret = -EINVAL;
 		goto out;
 	}
 
 	if (o2nm_this_node() > node->nd_num) {
 		mlog(ML_NOTICE, "unexpected connect attempted from a lower "
-		     "numbered node '%s' at " "%u.%u.%u.%u:%d with num %u\n",
-		     node->nd_name, NIPQUAD(sin.sin_addr.s_addr),
+		     "numbered node '%s' at " "%pI4:%d with num %u\n",
+		     node->nd_name, &sin.sin_addr.s_addr,
 		     ntohs(sin.sin_port), node->nd_num);
 		ret = -EINVAL;
 		goto out;
@@ -1810,8 +1809,8 @@
 	 * and tries to connect before we see their heartbeat */
 	if (!o2hb_check_node_heartbeating_from_callback(node->nd_num)) {
 		mlog(ML_CONN, "attempt to connect from node '%s' at "
-		     "%u.%u.%u.%u:%d but it isn't heartbeating\n",
-		     node->nd_name, NIPQUAD(sin.sin_addr.s_addr),
+		     "%pI4:%d but it isn't heartbeating\n",
+		     node->nd_name, &sin.sin_addr.s_addr,
 		     ntohs(sin.sin_port));
 		ret = -EINVAL;
 		goto out;
@@ -1827,8 +1826,8 @@
 	spin_unlock(&nn->nn_lock);
 	if (ret) {
 		mlog(ML_NOTICE, "attempt to connect from node '%s' at "
-		     "%u.%u.%u.%u:%d but it already has an open connection\n",
-		     node->nd_name, NIPQUAD(sin.sin_addr.s_addr),
+		     "%pI4:%d but it already has an open connection\n",
+		     node->nd_name, &sin.sin_addr.s_addr,
 		     ntohs(sin.sin_port));
 		goto out;
 	}
@@ -1924,15 +1923,15 @@
 	sock->sk->sk_reuse = 1;
 	ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
 	if (ret < 0) {
-		mlog(ML_ERROR, "unable to bind socket at %u.%u.%u.%u:%u, "
-		     "ret=%d\n", NIPQUAD(addr), ntohs(port), ret);
+		mlog(ML_ERROR, "unable to bind socket at %pI4:%u, "
+		     "ret=%d\n", &addr, ntohs(port), ret);
 		goto out;
 	}
 
 	ret = sock->ops->listen(sock, 64);
 	if (ret < 0) {
-		mlog(ML_ERROR, "unable to listen on %u.%u.%u.%u:%u, ret=%d\n",
-		     NIPQUAD(addr), ntohs(port), ret);
+		mlog(ML_ERROR, "unable to listen on %pI4:%u, ret=%d\n",
+		     &addr, ntohs(port), ret);
 	}
 
 out:
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index ba962d7..6f7a77d 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -339,8 +339,8 @@
 		ip = DLMFS_I(inode);
 
 		inode->i_mode = mode;
-		inode->i_uid = current->fsuid;
-		inode->i_gid = current->fsgid;
+		inode->i_uid = current_fsuid();
+		inode->i_gid = current_fsgid();
 		inode->i_blocks = 0;
 		inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -365,8 +365,8 @@
 		return NULL;
 
 	inode->i_mode = mode;
-	inode->i_uid = current->fsuid;
-	inode->i_gid = current->fsgid;
+	inode->i_uid = current_fsuid();
+	inode->i_gid = current_fsgid();
 	inode->i_blocks = 0;
 	inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index f4967e6..2545e74 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -421,13 +421,13 @@
 	fe->i_blkno = cpu_to_le64(fe_blkno);
 	fe->i_suballoc_bit = cpu_to_le16(suballoc_bit);
 	fe->i_suballoc_slot = cpu_to_le16(inode_ac->ac_alloc_slot);
-	fe->i_uid = cpu_to_le32(current->fsuid);
+	fe->i_uid = cpu_to_le32(current_fsuid());
 	if (dir->i_mode & S_ISGID) {
 		fe->i_gid = cpu_to_le32(dir->i_gid);
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
 	} else
-		fe->i_gid = cpu_to_le32(current->fsgid);
+		fe->i_gid = cpu_to_le32(current_fsgid());
 	fe->i_mode = cpu_to_le16(mode);
 	if (S_ISCHR(mode) || S_ISBLK(mode))
 		fe->id1.dev1.i_rdev = cpu_to_le64(huge_encode_dev(dev));
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
index cbf047a..6afe57c 100644
--- a/fs/omfs/inode.c
+++ b/fs/omfs/inode.c
@@ -37,8 +37,8 @@
 
 	inode->i_ino = new_block;
 	inode->i_mode = mode;
-	inode->i_uid = current->fsuid;
-	inode->i_gid = current->fsgid;
+	inode->i_uid = current_fsuid();
+	inode->i_gid = current_fsgid();
 	inode->i_blocks = 0;
 	inode->i_mapping->a_ops = &omfs_aops;
 
@@ -420,8 +420,8 @@
 
 	sb->s_fs_info = sbi;
 
-	sbi->s_uid = current->uid;
-	sbi->s_gid = current->gid;
+	sbi->s_uid = current_uid();
+	sbi->s_gid = current_gid();
 	sbi->s_dmask = sbi->s_fmask = current->fs->umask;
 
 	if (!parse_options((char *) data, sbi))
diff --git a/fs/open.c b/fs/open.c
index 83cdb9d..c0a426d 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -425,39 +425,33 @@
  */
 asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
 {
+	const struct cred *old_cred;
+	struct cred *override_cred;
 	struct path path;
 	struct inode *inode;
-	int old_fsuid, old_fsgid;
-	kernel_cap_t uninitialized_var(old_cap);  /* !SECURE_NO_SETUID_FIXUP */
 	int res;
 
 	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
 		return -EINVAL;
 
-	old_fsuid = current->fsuid;
-	old_fsgid = current->fsgid;
+	override_cred = prepare_creds();
+	if (!override_cred)
+		return -ENOMEM;
 
-	current->fsuid = current->uid;
-	current->fsgid = current->gid;
+	override_cred->fsuid = override_cred->uid;
+	override_cred->fsgid = override_cred->gid;
 
 	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
-		/*
-		 * Clear the capabilities if we switch to a non-root user
-		 */
-#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
-		/*
-		 * FIXME: There is a race here against sys_capset.  The
-		 * capabilities can change yet we will restore the old
-		 * value below.  We should hold task_capabilities_lock,
-		 * but we cannot because user_path_at can sleep.
-		 */
-#endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */
-		if (current->uid)
-			old_cap = cap_set_effective(__cap_empty_set);
+		/* Clear the capabilities if we switch to a non-root user */
+		if (override_cred->uid)
+			cap_clear(override_cred->cap_effective);
 		else
-			old_cap = cap_set_effective(current->cap_permitted);
+			override_cred->cap_effective =
+				override_cred->cap_permitted;
 	}
 
+	old_cred = override_creds(override_cred);
+
 	res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
 	if (res)
 		goto out;
@@ -494,12 +488,8 @@
 out_path_release:
 	path_put(&path);
 out:
-	current->fsuid = old_fsuid;
-	current->fsgid = old_fsgid;
-
-	if (!issecure(SECURE_NO_SETUID_FIXUP))
-		cap_set_effective(old_cap);
-
+	revert_creds(old_cred);
+	put_cred(override_cred);
 	return res;
 }
 
@@ -792,7 +782,8 @@
 
 static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 					int flags, struct file *f,
-					int (*open)(struct inode *, struct file *))
+					int (*open)(struct inode *, struct file *),
+					const struct cred *cred)
 {
 	struct inode *inode;
 	int error;
@@ -816,7 +807,7 @@
 	f->f_op = fops_get(inode->i_fop);
 	file_move(f, &inode->i_sb->s_files);
 
-	error = security_dentry_open(f);
+	error = security_dentry_open(f, cred);
 	if (error)
 		goto cleanup_all;
 
@@ -891,6 +882,8 @@
 struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
 		int (*open)(struct inode *, struct file *))
 {
+	const struct cred *cred = current_cred();
+
 	if (IS_ERR(nd->intent.open.file))
 		goto out;
 	if (IS_ERR(dentry))
@@ -898,7 +891,7 @@
 	nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
 					     nd->intent.open.flags - 1,
 					     nd->intent.open.file,
-					     open);
+					     open, cred);
 out:
 	return nd->intent.open.file;
 out_err:
@@ -917,6 +910,7 @@
  */
 struct file *nameidata_to_filp(struct nameidata *nd, int flags)
 {
+	const struct cred *cred = current_cred();
 	struct file *filp;
 
 	/* Pick up the filp from the open intent */
@@ -924,7 +918,7 @@
 	/* Has the filesystem initialised the file for us? */
 	if (filp->f_path.dentry == NULL)
 		filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp,
-				     NULL);
+				     NULL, cred);
 	else
 		path_put(&nd->path);
 	return filp;
@@ -934,7 +928,8 @@
  * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an
  * error.
  */
-struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
+struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
+			 const struct cred *cred)
 {
 	int error;
 	struct file *f;
@@ -959,7 +954,7 @@
 		return ERR_PTR(error);
 	}
 
-	return __dentry_open(dentry, mnt, flags, f, NULL);
+	return __dentry_open(dentry, mnt, flags, f, NULL, cred);
 }
 EXPORT_SYMBOL(dentry_open);
 
diff --git a/fs/pipe.c b/fs/pipe.c
index 7aea8b8..aaf797b 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -899,8 +899,8 @@
 	 */
 	inode->i_state = I_DIRTY;
 	inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
-	inode->i_uid = current->fsuid;
-	inode->i_gid = current->fsgid;
+	inode->i_uid = current_fsuid();
+	inode->i_gid = current_fsgid();
 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 
 	return inode;
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index aec931e..39df95a 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -217,11 +217,11 @@
                 switch(pa->e_tag) {
                         case ACL_USER_OBJ:
 				/* (May have been checked already) */
-                                if (inode->i_uid == current->fsuid)
+				if (inode->i_uid == current_fsuid())
                                         goto check_perm;
                                 break;
                         case ACL_USER:
-                                if (pa->e_id == current->fsuid)
+				if (pa->e_id == current_fsuid())
                                         goto mask;
 				break;
                         case ACL_GROUP_OBJ:
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 6af7fba..7e4877d 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -159,6 +159,7 @@
 	struct group_info *group_info;
 	int g;
 	struct fdtable *fdt = NULL;
+	const struct cred *cred;
 	pid_t ppid, tpid;
 
 	rcu_read_lock();
@@ -170,6 +171,7 @@
 		if (tracer)
 			tpid = task_pid_nr_ns(tracer, ns);
 	}
+	cred = get_cred((struct cred *) __task_cred(p));
 	seq_printf(m,
 		"State:\t%s\n"
 		"Tgid:\t%d\n"
@@ -182,8 +184,8 @@
 		task_tgid_nr_ns(p, ns),
 		pid_nr_ns(pid, ns),
 		ppid, tpid,
-		p->uid, p->euid, p->suid, p->fsuid,
-		p->gid, p->egid, p->sgid, p->fsgid);
+		cred->uid, cred->euid, cred->suid, cred->fsuid,
+		cred->gid, cred->egid, cred->sgid, cred->fsgid);
 
 	task_lock(p);
 	if (p->files)
@@ -194,13 +196,12 @@
 		fdt ? fdt->max_fds : 0);
 	rcu_read_unlock();
 
-	group_info = p->group_info;
-	get_group_info(group_info);
+	group_info = cred->group_info;
 	task_unlock(p);
 
 	for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++)
 		seq_printf(m, "%d ", GROUP_AT(group_info, g));
-	put_group_info(group_info);
+	put_cred(cred);
 
 	seq_printf(m, "\n");
 }
@@ -262,7 +263,7 @@
 		blocked = p->blocked;
 		collect_sigign_sigcatch(p, &ignored, &caught);
 		num_threads = atomic_read(&p->signal->count);
-		qsize = atomic_read(&p->user->sigpending);
+		qsize = atomic_read(&__task_cred(p)->user->sigpending);
 		qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
 		unlock_task_sighand(p, &flags);
 	}
@@ -293,10 +294,21 @@
 
 static inline void task_cap(struct seq_file *m, struct task_struct *p)
 {
-	render_cap_t(m, "CapInh:\t", &p->cap_inheritable);
-	render_cap_t(m, "CapPrm:\t", &p->cap_permitted);
-	render_cap_t(m, "CapEff:\t", &p->cap_effective);
-	render_cap_t(m, "CapBnd:\t", &p->cap_bset);
+	const struct cred *cred;
+	kernel_cap_t cap_inheritable, cap_permitted, cap_effective, cap_bset;
+
+	rcu_read_lock();
+	cred = __task_cred(p);
+	cap_inheritable	= cred->cap_inheritable;
+	cap_permitted	= cred->cap_permitted;
+	cap_effective	= cred->cap_effective;
+	cap_bset	= cred->cap_bset;
+	rcu_read_unlock();
+
+	render_cap_t(m, "CapInh:\t", &cap_inheritable);
+	render_cap_t(m, "CapPrm:\t", &cap_permitted);
+	render_cap_t(m, "CapEff:\t", &cap_effective);
+	render_cap_t(m, "CapBnd:\t", &cap_bset);
 }
 
 static inline void task_context_switch_counts(struct seq_file *m,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index d467760..cad92c1 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -347,8 +347,8 @@
 static int proc_pid_schedstat(struct task_struct *task, char *buffer)
 {
 	return sprintf(buffer, "%llu %llu %lu\n",
-			task->sched_info.cpu_time,
-			task->sched_info.run_delay,
+			(unsigned long long)task->se.sum_exec_runtime,
+			(unsigned long long)task->sched_info.run_delay,
 			task->sched_info.pcount);
 }
 #endif
@@ -1406,6 +1406,7 @@
 {
 	struct inode * inode;
 	struct proc_inode *ei;
+	const struct cred *cred;
 
 	/* We need a new inode */
 
@@ -1428,8 +1429,11 @@
 	inode->i_uid = 0;
 	inode->i_gid = 0;
 	if (task_dumpable(task)) {
-		inode->i_uid = task->euid;
-		inode->i_gid = task->egid;
+		rcu_read_lock();
+		cred = __task_cred(task);
+		inode->i_uid = cred->euid;
+		inode->i_gid = cred->egid;
+		rcu_read_unlock();
 	}
 	security_task_to_inode(task, inode);
 
@@ -1445,6 +1449,8 @@
 {
 	struct inode *inode = dentry->d_inode;
 	struct task_struct *task;
+	const struct cred *cred;
+
 	generic_fillattr(inode, stat);
 
 	rcu_read_lock();
@@ -1454,8 +1460,9 @@
 	if (task) {
 		if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
 		    task_dumpable(task)) {
-			stat->uid = task->euid;
-			stat->gid = task->egid;
+			cred = __task_cred(task);
+			stat->uid = cred->euid;
+			stat->gid = cred->egid;
 		}
 	}
 	rcu_read_unlock();
@@ -1483,11 +1490,16 @@
 {
 	struct inode *inode = dentry->d_inode;
 	struct task_struct *task = get_proc_task(inode);
+	const struct cred *cred;
+
 	if (task) {
 		if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
 		    task_dumpable(task)) {
-			inode->i_uid = task->euid;
-			inode->i_gid = task->egid;
+			rcu_read_lock();
+			cred = __task_cred(task);
+			inode->i_uid = cred->euid;
+			inode->i_gid = cred->egid;
+			rcu_read_unlock();
 		} else {
 			inode->i_uid = 0;
 			inode->i_gid = 0;
@@ -1649,6 +1661,7 @@
 	struct task_struct *task = get_proc_task(inode);
 	int fd = proc_fd(inode);
 	struct files_struct *files;
+	const struct cred *cred;
 
 	if (task) {
 		files = get_files_struct(task);
@@ -1658,8 +1671,11 @@
 				rcu_read_unlock();
 				put_files_struct(files);
 				if (task_dumpable(task)) {
-					inode->i_uid = task->euid;
-					inode->i_gid = task->egid;
+					rcu_read_lock();
+					cred = __task_cred(task);
+					inode->i_uid = cred->euid;
+					inode->i_gid = cred->egid;
+					rcu_read_unlock();
 				} else {
 					inode->i_uid = 0;
 					inode->i_gid = 0;
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index d777789..de2bba5 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -218,8 +218,7 @@
 void __init proc_device_tree_init(void)
 {
 	struct device_node *root;
-	if ( !have_of )
-		return;
+
 	proc_device_tree = proc_mkdir("device-tree", NULL);
 	if (proc_device_tree == 0)
 		return;
diff --git a/fs/quota.c b/fs/quota.c
index 7f4386e..b7fe44e 100644
--- a/fs/quota.c
+++ b/fs/quota.c
@@ -79,7 +79,7 @@
 
 	/* Check privileges */
 	if (cmd == Q_GETQUOTA) {
-		if (((type == USRQUOTA && current->euid != id) ||
+		if (((type == USRQUOTA && current_euid() != id) ||
 		     (type == GRPQUOTA && !in_egroup_p(id))) &&
 		    !capable(CAP_SYS_ADMIN))
 			return -EPERM;
@@ -130,7 +130,7 @@
 
 	/* Check privileges */
 	if (cmd == Q_XGETQUOTA) {
-		if (((type == XQM_USRQUOTA && current->euid != id) ||
+		if (((type == XQM_USRQUOTA && current_euid() != id) ||
 		     (type == XQM_GRPQUOTA && !in_egroup_p(id))) &&
 		     !capable(CAP_SYS_ADMIN))
 			return -EPERM;
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index f031d1c..a83a351 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -55,8 +55,8 @@
 
 	if (inode) {
 		inode->i_mode = mode;
-		inode->i_uid = current->fsuid;
-		inode->i_gid = current->fsgid;
+		inode->i_uid = current_fsuid();
+		inode->i_gid = current_fsgid();
 		inode->i_blocks = 0;
 		inode->i_mapping->a_ops = &ramfs_aops;
 		inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index f89ebb9..4f322e5 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -573,7 +573,7 @@
 	/* the quota init calls have to know who to charge the quota to, so
 	 ** we have to set uid and gid here
 	 */
-	inode->i_uid = current->fsuid;
+	inode->i_uid = current_fsuid();
 	inode->i_mode = mode;
 	/* Make inode invalid - just in case we are going to drop it before
 	 * the initialization happens */
@@ -584,7 +584,7 @@
 		if (S_ISDIR(mode))
 			inode->i_mode |= S_ISGID;
 	} else {
-		inode->i_gid = current->fsgid;
+		inode->i_gid = current_fsgid();
 	}
 	DQUOT_INIT(inode);
 	return 0;
diff --git a/fs/seq_file.c b/fs/seq_file.c
index eba2eab..16c2115 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -357,7 +357,18 @@
 }
 EXPORT_SYMBOL(seq_printf);
 
-static char *mangle_path(char *s, char *p, char *esc)
+/**
+ *	mangle_path -	mangle and copy path to buffer beginning
+ *	@s: buffer start
+ *	@p: beginning of path in above buffer
+ *	@esc: set of characters that need escaping
+ *
+ *      Copy the path from @p to @s, replacing each occurrence of character from
+ *      @esc with usual octal escape.
+ *      Returns pointer past last written character in @s, or NULL in case of
+ *      failure.
+ */
+char *mangle_path(char *s, char *p, char *esc)
 {
 	while (s <= p) {
 		char c = *p++;
@@ -376,6 +387,7 @@
 	}
 	return NULL;
 }
+EXPORT_SYMBOL(mangle_path);
 
 /*
  * return the absolute path of 'dentry' residing in mount 'mnt'.
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 48da4fa..e7ddd03 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -667,8 +667,7 @@
 
 	attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
 	attr.ia_mode = mode;
-	attr.ia_uid = current->euid;
-	attr.ia_gid = current->egid;
+	current_euid_egid(&attr.ia_uid, &attr.ia_gid);
 
 	if (!new_valid_dev(dev))
 		return -EINVAL;
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 3528f40..fc27fbf 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -586,7 +586,7 @@
 		if (parse_options(mnt, raw_data))
 			goto out_bad_option;
 	}
-	mnt->mounted_uid = current->uid;
+	mnt->mounted_uid = current_uid();
 	smb_setcodepage(server, &mnt->codepage);
 
 	/*
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index ee536e8..9468168 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -864,7 +864,7 @@
 		goto out;
 
 	error = -EACCES;
-	if (current->uid != server->mnt->mounted_uid && 
+	if (current_uid() != server->mnt->mounted_uid &&
 	    !capable(CAP_SYS_ADMIN))
 		goto out;
 
diff --git a/fs/super.c b/fs/super.c
index 400a760..ddba069 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -914,7 +914,7 @@
 		goto out_free_secdata;
 	BUG_ON(!mnt->mnt_sb);
 
- 	error = security_sb_kern_mount(mnt->mnt_sb, secdata);
+ 	error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
  	if (error)
  		goto out_sb;
 
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index 115ab0d..241e976 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -165,9 +165,9 @@
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
 	} else
-		inode->i_gid = current->fsgid;
+		inode->i_gid = current_fsgid();
 
-	inode->i_uid = current->fsuid;
+	inode->i_uid = current_fsuid();
 	inode->i_ino = fs16_to_cpu(sbi, ino);
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 	inode->i_blocks = 0;
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
index 1a4973e..4a18f08 100644
--- a/fs/ubifs/budget.c
+++ b/fs/ubifs/budget.c
@@ -363,7 +363,7 @@
  */
 static int can_use_rp(struct ubifs_info *c)
 {
-	if (current->fsuid == c->rp_uid || capable(CAP_SYS_RESOURCE) ||
+	if (current_fsuid() == c->rp_uid || capable(CAP_SYS_RESOURCE) ||
 	    (c->rp_gid != 0 && in_group_p(c->rp_gid)))
 		return 1;
 	return 0;
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 0422c98..f448ab1 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -104,13 +104,13 @@
 	 */
 	inode->i_flags |= (S_NOCMTIME);
 
-	inode->i_uid = current->fsuid;
+	inode->i_uid = current_fsuid();
 	if (dir->i_mode & S_ISGID) {
 		inode->i_gid = dir->i_gid;
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
 	} else
-		inode->i_gid = current->fsgid;
+		inode->i_gid = current_fsgid();
 	inode->i_mode = mode;
 	inode->i_mtime = inode->i_atime = inode->i_ctime =
 			 ubifs_current_time(inode);
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index a4f2b3c..31fc842 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -126,13 +126,13 @@
 	}
 	mutex_unlock(&sbi->s_alloc_mutex);
 	inode->i_mode = mode;
-	inode->i_uid = current->fsuid;
+	inode->i_uid = current_fsuid();
 	if (dir->i_mode & S_ISGID) {
 		inode->i_gid = dir->i_gid;
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
 	} else {
-		inode->i_gid = current->fsgid;
+		inode->i_gid = current_fsgid();
 	}
 
 	iinfo->i_location.logicalBlockNum = block;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 082409c..f84bfaa 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -604,7 +604,7 @@
 		goto out;
 
 	iinfo = UDF_I(inode);
-	inode->i_uid = current->fsuid;
+	inode->i_uid = current_fsuid();
 	init_special_inode(inode, mode, rdev);
 	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
 	if (!fi) {
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index ac181f6..6f5dcf0 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -304,13 +304,13 @@
 
 	inode->i_ino = cg * uspi->s_ipg + bit;
 	inode->i_mode = mode;
-	inode->i_uid = current->fsuid;
+	inode->i_uid = current_fsuid();
 	if (dir->i_mode & S_ISGID) {
 		inode->i_gid = dir->i_gid;
 		if (S_ISDIR(mode))
 			inode->i_mode |= S_ISGID;
 	} else
-		inode->i_gid = current->fsgid;
+		inode->i_gid = current_fsgid();
 
 	inode->i_blocks = 0;
 	inode->i_generation = 0;
diff --git a/fs/xfs/linux-2.6/xfs_cred.h b/fs/xfs/linux-2.6/xfs_cred.h
index e279d00..55bddf3 100644
--- a/fs/xfs/linux-2.6/xfs_cred.h
+++ b/fs/xfs/linux-2.6/xfs_cred.h
@@ -23,8 +23,6 @@
 /*
  * Credentials
  */
-typedef struct cred {
-       /* EMPTY */
-} cred_t;
+typedef const struct cred cred_t;
 
 #endif  /* __XFS_CRED_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index 0264c87..67205f6 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -252,6 +252,7 @@
 	struct file		*parfilp,
 	struct inode		*parinode)
 {
+	const struct cred	*cred = current_cred();
 	int			error;
 	int			new_fd;
 	int			permflag;
@@ -314,7 +315,7 @@
 	mntget(parfilp->f_path.mnt);
 
 	/* Create file pointer. */
-	filp = dentry_open(dentry, parfilp->f_path.mnt, hreq->oflags);
+	filp = dentry_open(dentry, parfilp->f_path.mnt, hreq->oflags, cred);
 	if (IS_ERR(filp)) {
 		put_unused_fd(new_fd);
 		return -XFS_ERROR(-PTR_ERR(filp));
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index f0e4d79..1f175fa 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -503,7 +503,7 @@
  * xfs_inode.c prototypes.
  */
 int		xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t,
-			   xfs_nlink_t, xfs_dev_t, struct cred *, xfs_prid_t,
+			   xfs_nlink_t, xfs_dev_t, cred_t *, xfs_prid_t,
 			   int, struct xfs_buf **, boolean_t *, xfs_inode_t **);
 
 uint		xfs_ip2xflags(struct xfs_inode *);
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h
index 55d955e..76df328 100644
--- a/fs/xfs/xfs_vnodeops.h
+++ b/fs/xfs/xfs_vnodeops.h
@@ -26,18 +26,18 @@
 int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name,
 		struct xfs_inode **ipp, struct xfs_name *ci_name);
 int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode,
-		xfs_dev_t rdev, struct xfs_inode **ipp, struct cred *credp);
+		xfs_dev_t rdev, struct xfs_inode **ipp, cred_t *credp);
 int xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
 		struct xfs_inode *ip);
 int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
 		struct xfs_name *target_name);
 int xfs_mkdir(struct xfs_inode *dp, struct xfs_name *dir_name,
-		mode_t mode, struct xfs_inode **ipp, struct cred *credp);
+		mode_t mode, struct xfs_inode **ipp, cred_t *credp);
 int xfs_readdir(struct xfs_inode	*dp, void *dirent, size_t bufsize,
 		       xfs_off_t *offset, filldir_t filldir);
 int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name,
 		const char *target_path, mode_t mode, struct xfs_inode **ipp,
-		struct cred *credp);
+		cred_t *credp);
 int xfs_inode_flush(struct xfs_inode *ip, int flags);
 int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state);
 int xfs_reclaim(struct xfs_inode *ip);
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index 09d33c7..db8852d 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -172,7 +172,7 @@
 
 /* Defaults for debug_level, debug and normal */
 
-#define ACPI_DEBUG_DEFAULT          (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT)
+#define ACPI_DEBUG_DEFAULT          (ACPI_LV_INFO)
 #define ACPI_NORMAL_DEFAULT         (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT)
 #define ACPI_DEBUG_ALL              (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL)
 
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 029c8c0..0515e75 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -141,6 +141,10 @@
 /*
  * We need to show where it is safe to preempt execution of ACPICA
  */
-#define ACPI_PREEMPTION_POINT()	cond_resched()
+#define ACPI_PREEMPTION_POINT()		\
+	do {				\
+		if (!irqs_disabled())	\
+			cond_resched();	\
+	} while (0)
 
 #endif				/* __ACLINUX_H__ */
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 12c07c1..4c794d7 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -8,9 +8,17 @@
 #ifdef CONFIG_GENERIC_BUG
 #ifndef __ASSEMBLY__
 struct bug_entry {
+#ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
 	unsigned long	bug_addr;
+#else
+	signed int	bug_addr_disp;
+#endif
 #ifdef CONFIG_DEBUG_BUGVERBOSE
+#ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
 	const char	*file;
+#else
+	signed int	file_disp;
+#endif
 	unsigned short	line;
 #endif
 	unsigned short	flags;
diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h
index 18546d8..36fa286 100644
--- a/include/asm-generic/memory_model.h
+++ b/include/asm-generic/memory_model.h
@@ -49,7 +49,7 @@
 
 /* memmap is virtually contigious.  */
 #define __pfn_to_page(pfn)	(vmemmap + (pfn))
-#define __page_to_pfn(page)	((page) - vmemmap)
+#define __page_to_pfn(page)	(unsigned long)((page) - vmemmap)
 
 #elif defined(CONFIG_SPARSEMEM)
 /*
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index ef87f88..72ebe91 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -129,6 +129,10 @@
 #define move_pte(pte, prot, old_addr, new_addr)	(pte)
 #endif
 
+#ifndef pgprot_writecombine
+#define pgprot_writecombine pgprot_noncached
+#endif
+
 /*
  * When walking page tables, get the address of the next boundary,
  * or the end address of the range if that comes earlier.  Although no
@@ -289,6 +293,52 @@
 #define arch_flush_lazy_cpu_mode()	do {} while (0)
 #endif
 
+#ifndef __HAVE_PFNMAP_TRACKING
+/*
+ * Interface that can be used by architecture code to keep track of
+ * memory type of pfn mappings (remap_pfn_range, vm_insert_pfn)
+ *
+ * track_pfn_vma_new is called when a _new_ pfn mapping is being established
+ * for physical range indicated by pfn and size.
+ */
+static inline int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t prot,
+					unsigned long pfn, unsigned long size)
+{
+	return 0;
+}
+
+/*
+ * Interface that can be used by architecture code to keep track of
+ * memory type of pfn mappings (remap_pfn_range, vm_insert_pfn)
+ *
+ * track_pfn_vma_copy is called when vma that is covering the pfnmap gets
+ * copied through copy_page_range().
+ */
+static inline int track_pfn_vma_copy(struct vm_area_struct *vma)
+{
+	return 0;
+}
+
+/*
+ * Interface that can be used by architecture code to keep track of
+ * memory type of pfn mappings (remap_pfn_range, vm_insert_pfn)
+ *
+ * untrack_pfn_vma is called while unmapping a pfnmap for a region.
+ * untrack can be called for a specific region indicated by pfn and size or
+ * can be for the entire vma (in which case size can be zero).
+ */
+static inline void untrack_pfn_vma(struct vm_area_struct *vma,
+					unsigned long pfn, unsigned long size)
+{
+}
+#else
+extern int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t prot,
+				unsigned long pfn, unsigned long size);
+extern int track_pfn_vma_copy(struct vm_area_struct *vma);
+extern void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn,
+				unsigned long size);
+#endif
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_GENERIC_PGTABLE_H */
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8074460..c61fab1 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -45,6 +45,22 @@
 #define MCOUNT_REC()
 #endif
 
+#ifdef CONFIG_TRACE_BRANCH_PROFILING
+#define LIKELY_PROFILE()	VMLINUX_SYMBOL(__start_annotated_branch_profile) = .; \
+				*(_ftrace_annotated_branch)			      \
+				VMLINUX_SYMBOL(__stop_annotated_branch_profile) = .;
+#else
+#define LIKELY_PROFILE()
+#endif
+
+#ifdef CONFIG_PROFILE_ALL_BRANCHES
+#define BRANCH_PROFILE()	VMLINUX_SYMBOL(__start_branch_profile) = .;   \
+				*(_ftrace_branch)			      \
+				VMLINUX_SYMBOL(__stop_branch_profile) = .;
+#else
+#define BRANCH_PROFILE()
+#endif
+
 /* .data section */
 #define DATA_DATA							\
 	*(.data)							\
@@ -60,9 +76,12 @@
 	VMLINUX_SYMBOL(__start___markers) = .;				\
 	*(__markers)							\
 	VMLINUX_SYMBOL(__stop___markers) = .;				\
+	. = ALIGN(32);							\
 	VMLINUX_SYMBOL(__start___tracepoints) = .;			\
 	*(__tracepoints)						\
-	VMLINUX_SYMBOL(__stop___tracepoints) = .;
+	VMLINUX_SYMBOL(__stop___tracepoints) = .;			\
+	LIKELY_PROFILE()		       				\
+	BRANCH_PROFILE()
 
 #define RO_DATA(align)							\
 	. = ALIGN((align));						\
@@ -269,6 +288,16 @@
 		*(.kprobes.text)					\
 		VMLINUX_SYMBOL(__kprobes_text_end) = .;
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#define IRQENTRY_TEXT							\
+		ALIGN_FUNCTION();					\
+		VMLINUX_SYMBOL(__irqentry_text_start) = .;		\
+		*(.irqentry.text)					\
+		VMLINUX_SYMBOL(__irqentry_text_end) = .;
+#else
+#define IRQENTRY_TEXT
+#endif
+
 /* Section used for early init (in .S files) */
 #define HEAD_TEXT  *(.head.text)
 
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
index 70a57c8..c980f5b 100644
--- a/include/asm-m32r/system.h
+++ b/include/asm-m32r/system.h
@@ -23,7 +23,7 @@
  */
 
 #if defined(CONFIG_FRAME_POINTER) || \
-	!defined(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER)
+	!defined(CONFIG_SCHED_OMIT_FRAME_POINTER)
 #define M32R_PUSH_FP "	push fp\n"
 #define M32R_POP_FP  "	pop  fp\n"
 #else
diff --git a/include/asm-m68k/byteorder.h b/include/asm-m68k/byteorder.h
index 81d420b..b354acd 100644
--- a/include/asm-m68k/byteorder.h
+++ b/include/asm-m68k/byteorder.h
@@ -4,22 +4,16 @@
 #include <asm/types.h>
 #include <linux/compiler.h>
 
-#ifdef __GNUC__
+#define __BIG_ENDIAN
+#define __SWAB_64_THRU_32__
 
-static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 val)
+static inline __attribute_const__ __u32 __arch_swab32(__u32 val)
 {
 	__asm__("rolw #8,%0; swap %0; rolw #8,%0" : "=d" (val) : "0" (val));
 	return val;
 }
-#define __arch__swab32(x) ___arch__swab32(x)
+#define __arch_swab32 __arch_swab32
 
-#endif
-
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-#  define __BYTEORDER_HAS_U64__
-#  define __SWAB_64_THRU_32__
-#endif
-
-#include <linux/byteorder/big_endian.h>
+#include <linux/byteorder.h>
 
 #endif /* _M68K_BYTEORDER_H */
diff --git a/include/asm-m68k/machw.h b/include/asm-m68k/machw.h
index 3562499..2b4de0c 100644
--- a/include/asm-m68k/machw.h
+++ b/include/asm-m68k/machw.h
@@ -26,28 +26,6 @@
 #include <linux/types.h>
 
 #if 0
-/* Mac SCSI Controller 5380 */
-
-#define	MAC_5380_BAS	(0x50F10000) /* This is definitely wrong!! */
-struct MAC_5380 {
-	u_char	scsi_data;
-	u_char	char_dummy1;
-	u_char	scsi_icr;
-	u_char	char_dummy2;
-	u_char	scsi_mode;
-	u_char	char_dummy3;
-	u_char	scsi_tcr;
-	u_char	char_dummy4;
-	u_char	scsi_idstat;
-	u_char	char_dummy5;
-	u_char	scsi_dmastat;
-	u_char	char_dummy6;
-	u_char	scsi_targrcv;
-	u_char	char_dummy7;
-	u_char	scsi_inircv;
-};
-#define	mac_scsi       ((*(volatile struct MAC_5380 *)MAC_5380_BAS))
-
 /*
 ** SCC Z8530
 */
diff --git a/include/crypto/aes.h b/include/crypto/aes.h
index 40008d6..656a4c6 100644
--- a/include/crypto/aes.h
+++ b/include/crypto/aes.h
@@ -23,10 +23,10 @@
 	u32 key_dec[AES_MAX_KEYLENGTH_U32];
 };
 
-extern u32 crypto_ft_tab[4][256];
-extern u32 crypto_fl_tab[4][256];
-extern u32 crypto_it_tab[4][256];
-extern u32 crypto_il_tab[4][256];
+extern const u32 crypto_ft_tab[4][256];
+extern const u32 crypto_fl_tab[4][256];
+extern const u32 crypto_it_tab[4][256];
+extern const u32 crypto_il_tab[4][256];
 
 int crypto_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 		unsigned int key_len);
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 60d06e7..0105454 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -22,9 +22,18 @@
 
 struct crypto_type {
 	unsigned int (*ctxsize)(struct crypto_alg *alg, u32 type, u32 mask);
+	unsigned int (*extsize)(struct crypto_alg *alg,
+				const struct crypto_type *frontend);
 	int (*init)(struct crypto_tfm *tfm, u32 type, u32 mask);
-	void (*exit)(struct crypto_tfm *tfm);
+	int (*init_tfm)(struct crypto_tfm *tfm,
+		        const struct crypto_type *frontend);
 	void (*show)(struct seq_file *m, struct crypto_alg *alg);
+	struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask);
+
+	unsigned int type;
+	unsigned int maskclear;
+	unsigned int maskset;
+	unsigned int tfmsize;
 };
 
 struct crypto_instance {
@@ -239,6 +248,11 @@
 	return __crypto_hash_cast(crypto_spawn_tfm(spawn, type, mask));
 }
 
+static inline void *crypto_hash_ctx(struct crypto_hash *tfm)
+{
+	return crypto_tfm_ctx(&tfm->base);
+}
+
 static inline void *crypto_hash_ctx_aligned(struct crypto_hash *tfm)
 {
 	return crypto_tfm_ctx_aligned(&tfm->base);
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index ee48ef8..cd16d6e 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -15,10 +15,40 @@
 
 #include <linux/crypto.h>
 
+struct shash_desc {
+	struct crypto_shash *tfm;
+	u32 flags;
+
+	void *__ctx[] CRYPTO_MINALIGN_ATTR;
+};
+
+struct shash_alg {
+	int (*init)(struct shash_desc *desc);
+	int (*reinit)(struct shash_desc *desc);
+	int (*update)(struct shash_desc *desc, const u8 *data,
+		      unsigned int len);
+	int (*final)(struct shash_desc *desc, u8 *out);
+	int (*finup)(struct shash_desc *desc, const u8 *data,
+		     unsigned int len, u8 *out);
+	int (*digest)(struct shash_desc *desc, const u8 *data,
+		      unsigned int len, u8 *out);
+	int (*setkey)(struct crypto_shash *tfm, const u8 *key,
+		      unsigned int keylen);
+
+	unsigned int descsize;
+	unsigned int digestsize;
+
+	struct crypto_alg base;
+};
+
 struct crypto_ahash {
 	struct crypto_tfm base;
 };
 
+struct crypto_shash {
+	struct crypto_tfm base;
+};
+
 static inline struct crypto_ahash *__crypto_ahash_cast(struct crypto_tfm *tfm)
 {
 	return (struct crypto_ahash *)tfm;
@@ -87,6 +117,11 @@
 	return crypto_ahash_crt(tfm)->reqsize;
 }
 
+static inline void *ahash_request_ctx(struct ahash_request *req)
+{
+	return req->__ctx;
+}
+
 static inline int crypto_ahash_setkey(struct crypto_ahash *tfm,
 				      const u8 *key, unsigned int keylen)
 {
@@ -101,6 +136,14 @@
 	return crt->digest(req);
 }
 
+static inline void crypto_ahash_export(struct ahash_request *req, u8 *out)
+{
+	memcpy(out, ahash_request_ctx(req),
+	       crypto_ahash_reqsize(crypto_ahash_reqtfm(req)));
+}
+
+int crypto_ahash_import(struct ahash_request *req, const u8 *in);
+
 static inline int crypto_ahash_init(struct ahash_request *req)
 {
 	struct ahash_tfm *crt = crypto_ahash_crt(crypto_ahash_reqtfm(req));
@@ -169,4 +212,86 @@
 	req->result = result;
 }
 
+struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type,
+					u32 mask);
+
+static inline struct crypto_tfm *crypto_shash_tfm(struct crypto_shash *tfm)
+{
+	return &tfm->base;
+}
+
+static inline void crypto_free_shash(struct crypto_shash *tfm)
+{
+	crypto_free_tfm(crypto_shash_tfm(tfm));
+}
+
+static inline unsigned int crypto_shash_alignmask(
+	struct crypto_shash *tfm)
+{
+	return crypto_tfm_alg_alignmask(crypto_shash_tfm(tfm));
+}
+
+static inline struct shash_alg *__crypto_shash_alg(struct crypto_alg *alg)
+{
+	return container_of(alg, struct shash_alg, base);
+}
+
+static inline struct shash_alg *crypto_shash_alg(struct crypto_shash *tfm)
+{
+	return __crypto_shash_alg(crypto_shash_tfm(tfm)->__crt_alg);
+}
+
+static inline unsigned int crypto_shash_digestsize(struct crypto_shash *tfm)
+{
+	return crypto_shash_alg(tfm)->digestsize;
+}
+
+static inline u32 crypto_shash_get_flags(struct crypto_shash *tfm)
+{
+	return crypto_tfm_get_flags(crypto_shash_tfm(tfm));
+}
+
+static inline void crypto_shash_set_flags(struct crypto_shash *tfm, u32 flags)
+{
+	crypto_tfm_set_flags(crypto_shash_tfm(tfm), flags);
+}
+
+static inline void crypto_shash_clear_flags(struct crypto_shash *tfm, u32 flags)
+{
+	crypto_tfm_clear_flags(crypto_shash_tfm(tfm), flags);
+}
+
+static inline unsigned int crypto_shash_descsize(struct crypto_shash *tfm)
+{
+	return crypto_shash_alg(tfm)->descsize;
+}
+
+static inline void *shash_desc_ctx(struct shash_desc *desc)
+{
+	return desc->__ctx;
+}
+
+int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key,
+			unsigned int keylen);
+int crypto_shash_digest(struct shash_desc *desc, const u8 *data,
+			unsigned int len, u8 *out);
+
+static inline void crypto_shash_export(struct shash_desc *desc, u8 *out)
+{
+	memcpy(out, shash_desc_ctx(desc), crypto_shash_descsize(desc->tfm));
+}
+
+int crypto_shash_import(struct shash_desc *desc, const u8 *in);
+
+static inline int crypto_shash_init(struct shash_desc *desc)
+{
+	return crypto_shash_alg(desc->tfm)->init(desc);
+}
+
+int crypto_shash_update(struct shash_desc *desc, const u8 *data,
+			unsigned int len);
+int crypto_shash_final(struct shash_desc *desc, u8 *out);
+int crypto_shash_finup(struct shash_desc *desc, const u8 *data,
+		       unsigned int len, u8 *out);
+
 #endif	/* _CRYPTO_HASH_H */
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
index 917ae57..82b7056 100644
--- a/include/crypto/internal/hash.h
+++ b/include/crypto/internal/hash.h
@@ -39,6 +39,12 @@
 int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err);
 int crypto_hash_walk_first(struct ahash_request *req,
 			   struct crypto_hash_walk *walk);
+int crypto_hash_walk_first_compat(struct hash_desc *hdesc,
+				  struct crypto_hash_walk *walk,
+				  struct scatterlist *sg, unsigned int len);
+
+int crypto_register_shash(struct shash_alg *alg);
+int crypto_unregister_shash(struct shash_alg *alg);
 
 static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm)
 {
@@ -63,16 +69,16 @@
 	return ahash_request_cast(crypto_dequeue_request(queue));
 }
 
-static inline void *ahash_request_ctx(struct ahash_request *req)
-{
-	return req->__ctx;
-}
-
 static inline int ahash_tfm_in_queue(struct crypto_queue *queue,
 					  struct crypto_ahash *tfm)
 {
 	return crypto_tfm_in_queue(queue, crypto_ahash_tfm(tfm));
 }
 
+static inline void *crypto_shash_ctx(struct crypto_shash *tfm)
+{
+	return crypto_tfm_ctx(&tfm->base);
+}
+
 #endif	/* _CRYPTO_INTERNAL_HASH_H */
 
diff --git a/include/keys/keyring-type.h b/include/keys/keyring-type.h
new file mode 100644
index 0000000..843f872
--- /dev/null
+++ b/include/keys/keyring-type.h
@@ -0,0 +1,31 @@
+/* Keyring key type
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _KEYS_KEYRING_TYPE_H
+#define _KEYS_KEYRING_TYPE_H
+
+#include <linux/key.h>
+#include <linux/rcupdate.h>
+
+/*
+ * the keyring payload contains a list of the keys to which the keyring is
+ * subscribed
+ */
+struct keyring_list {
+	struct rcu_head	rcu;		/* RCU deletion hook */
+	unsigned short	maxkeys;	/* max keys this list can hold */
+	unsigned short	nkeys;		/* number of keys currently held */
+	unsigned short	delkey;		/* key to be unlinked by RCU */
+	struct key	*keys[0];
+};
+
+
+#endif /* _KEYS_KEYRING_TYPE_H */
diff --git a/include/linux/atm.h b/include/linux/atm.h
index c791ddd..d3b2921 100644
--- a/include/linux/atm.h
+++ b/include/linux/atm.h
@@ -231,10 +231,21 @@
  */
 
 struct atmif_sioc {
-    int number;
-    int length;
-    void __user *arg;
+	int number;
+	int length;
+	void __user *arg;
 };
 
+#ifdef __KERNEL__
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+struct compat_atmif_sioc {
+	int number;
+	int length;
+	compat_uptr_t arg;
+};
+#endif
+#endif
+
 typedef unsigned short atm_backend_t;
 #endif
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
index a3d07c2..086e5c3 100644
--- a/include/linux/atmdev.h
+++ b/include/linux/atmdev.h
@@ -100,6 +100,10 @@
 					/* use backend to make new if */
 #define ATM_ADDPARTY  	_IOW('a', ATMIOC_SPECIAL+4,struct atm_iobuf)
  					/* add party to p2mp call */
+#ifdef CONFIG_COMPAT
+/* It actually takes struct sockaddr_atmsvc, not struct atm_iobuf */
+#define COMPAT_ATM_ADDPARTY  	_IOW('a', ATMIOC_SPECIAL+4,struct compat_atm_iobuf)
+#endif
 #define ATM_DROPPARTY 	_IOW('a', ATMIOC_SPECIAL+5,int)
 					/* drop party from p2mp call */
 
@@ -224,6 +228,13 @@
 extern struct proc_dir_entry *atm_proc_root;
 #endif
 
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+struct compat_atm_iobuf {
+	int length;
+	compat_uptr_t buffer;
+};
+#endif
 
 struct k_atm_aal_stats {
 #define __HANDLE_ITEM(i) atomic_t i
@@ -379,6 +390,10 @@
 	int (*open)(struct atm_vcc *vcc);
 	void (*close)(struct atm_vcc *vcc);
 	int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void __user *arg);
+#ifdef CONFIG_COMPAT
+	int (*compat_ioctl)(struct atm_dev *dev,unsigned int cmd,
+			    void __user *arg);
+#endif
 	int (*getsockopt)(struct atm_vcc *vcc,int level,int optname,
 	    void __user *optval,int optlen);
 	int (*setsockopt)(struct atm_vcc *vcc,int level,int optname,
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 8f0672d..26c4f6f 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -99,6 +99,8 @@
 #define AUDIT_OBJ_PID		1318	/* ptrace target */
 #define AUDIT_TTY		1319	/* Input on an administrative TTY */
 #define AUDIT_EOE		1320	/* End of multi-record event */
+#define AUDIT_BPRM_FCAPS	1321	/* Information about fcaps increasing perms */
+#define AUDIT_CAPSET		1322	/* Record showing argument to sys_capset */
 
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
@@ -453,6 +455,10 @@
 extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout);
 extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification);
 extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat);
+extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
+				  const struct cred *new,
+				  const struct cred *old);
+extern int __audit_log_capset(pid_t pid, const struct cred *new, const struct cred *old);
 
 static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp)
 {
@@ -502,6 +508,24 @@
 		return __audit_mq_getsetattr(mqdes, mqstat);
 	return 0;
 }
+
+static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm,
+				       const struct cred *new,
+				       const struct cred *old)
+{
+	if (unlikely(!audit_dummy_context()))
+		return __audit_log_bprm_fcaps(bprm, new, old);
+	return 0;
+}
+
+static inline int audit_log_capset(pid_t pid, const struct cred *new,
+				   const struct cred *old)
+{
+	if (unlikely(!audit_dummy_context()))
+		return __audit_log_capset(pid, new, old);
+	return 0;
+}
+
 extern int audit_n_rules;
 extern int audit_signals;
 #else
@@ -534,6 +558,8 @@
 #define audit_mq_timedreceive(d,l,p,t) ({ 0; })
 #define audit_mq_notify(d,n) ({ 0; })
 #define audit_mq_getsetattr(d,s) ({ 0; })
+#define audit_log_bprm_fcaps(b, ncr, ocr) ({ 0; })
+#define audit_log_capset(pid, ncr, ocr) ({ 0; })
 #define audit_ptrace(t) ((void)0)
 #define audit_n_rules 0
 #define audit_signals 0
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 7394b5b..6cbfbe2 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -35,16 +35,20 @@
 	struct mm_struct *mm;
 	unsigned long p; /* current top of mem */
 	unsigned int sh_bang:1,
-		     misc_bang:1;
+		misc_bang:1,
+		cred_prepared:1,/* true if creds already prepared (multiple
+				 * preps happen for interpreters) */
+		cap_effective:1;/* true if has elevated effective capabilities,
+				 * false if not; except for init which inherits
+				 * its parent's caps anyway */
 #ifdef __alpha__
 	unsigned int taso:1;
 #endif
 	unsigned int recursion_depth;
 	struct file * file;
-	int e_uid, e_gid;
-	kernel_cap_t cap_post_exec_permitted;
-	bool cap_effective;
-	void *security;
+	struct cred *cred;	/* new credentials */
+	int unsafe;		/* how unsafe this exec is (mask of LSM_UNSAFE_*) */
+	unsigned int per_clear;	/* bits to clear in current->personality */
 	int argc, envc;
 	char * filename;	/* Name of binary as seen by procps */
 	char * interp;		/* Name of the binary really executed. Most
@@ -101,7 +105,7 @@
 			   int executable_stack);
 extern int bprm_mm_init(struct linux_binprm *bprm);
 extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
-extern void compute_creds(struct linux_binprm *binprm);
+extern void install_exec_creds(struct linux_binprm *bprm);
 extern int do_coredump(long signr, int exit_code, struct pt_regs * regs);
 extern int set_binfmt(struct linux_binfmt *new);
 extern void free_bprm(struct linux_binprm *);
diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h
index bdf505d..1dba349 100644
--- a/include/linux/blktrace_api.h
+++ b/include/linux/blktrace_api.h
@@ -160,7 +160,6 @@
 
 extern int blk_trace_ioctl(struct block_device *, unsigned, char __user *);
 extern void blk_trace_shutdown(struct request_queue *);
-extern void __blk_add_trace(struct blk_trace *, sector_t, int, int, u32, int, int, void *);
 extern int do_blk_trace_setup(struct request_queue *q,
 	char *name, dev_t dev, struct blk_user_trace_setup *buts);
 extern void __trace_note_message(struct blk_trace *, const char *fmt, ...);
@@ -186,168 +185,8 @@
 	} while (0)
 #define BLK_TN_MAX_MSG		128
 
-/**
- * blk_add_trace_rq - Add a trace for a request oriented action
- * @q:		queue the io is for
- * @rq:		the source request
- * @what:	the action
- *
- * Description:
- *     Records an action against a request. Will log the bio offset + size.
- *
- **/
-static inline void blk_add_trace_rq(struct request_queue *q, struct request *rq,
-				    u32 what)
-{
-	struct blk_trace *bt = q->blk_trace;
-	int rw = rq->cmd_flags & 0x03;
-
-	if (likely(!bt))
-		return;
-
-	if (blk_discard_rq(rq))
-		rw |= (1 << BIO_RW_DISCARD);
-
-	if (blk_pc_request(rq)) {
-		what |= BLK_TC_ACT(BLK_TC_PC);
-		__blk_add_trace(bt, 0, rq->data_len, rw, what, rq->errors, sizeof(rq->cmd), rq->cmd);
-	} else  {
-		what |= BLK_TC_ACT(BLK_TC_FS);
-		__blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9, rw, what, rq->errors, 0, NULL);
-	}
-}
-
-/**
- * blk_add_trace_bio - Add a trace for a bio oriented action
- * @q:		queue the io is for
- * @bio:	the source bio
- * @what:	the action
- *
- * Description:
- *     Records an action against a bio. Will log the bio offset + size.
- *
- **/
-static inline void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
-				     u32 what)
-{
-	struct blk_trace *bt = q->blk_trace;
-
-	if (likely(!bt))
-		return;
-
-	__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, !bio_flagged(bio, BIO_UPTODATE), 0, NULL);
-}
-
-/**
- * blk_add_trace_generic - Add a trace for a generic action
- * @q:		queue the io is for
- * @bio:	the source bio
- * @rw:		the data direction
- * @what:	the action
- *
- * Description:
- *     Records a simple trace
- *
- **/
-static inline void blk_add_trace_generic(struct request_queue *q,
-					 struct bio *bio, int rw, u32 what)
-{
-	struct blk_trace *bt = q->blk_trace;
-
-	if (likely(!bt))
-		return;
-
-	if (bio)
-		blk_add_trace_bio(q, bio, what);
-	else
-		__blk_add_trace(bt, 0, 0, rw, what, 0, 0, NULL);
-}
-
-/**
- * blk_add_trace_pdu_int - Add a trace for a bio with an integer payload
- * @q:		queue the io is for
- * @what:	the action
- * @bio:	the source bio
- * @pdu:	the integer payload
- *
- * Description:
- *     Adds a trace with some integer payload. This might be an unplug
- *     option given as the action, with the depth at unplug time given
- *     as the payload
- *
- **/
-static inline void blk_add_trace_pdu_int(struct request_queue *q, u32 what,
-					 struct bio *bio, unsigned int pdu)
-{
-	struct blk_trace *bt = q->blk_trace;
-	__be64 rpdu = cpu_to_be64(pdu);
-
-	if (likely(!bt))
-		return;
-
-	if (bio)
-		__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, !bio_flagged(bio, BIO_UPTODATE), sizeof(rpdu), &rpdu);
-	else
-		__blk_add_trace(bt, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu);
-}
-
-/**
- * blk_add_trace_remap - Add a trace for a remap operation
- * @q:		queue the io is for
- * @bio:	the source bio
- * @dev:	target device
- * @from:	source sector
- * @to:		target sector
- *
- * Description:
- *     Device mapper or raid target sometimes need to split a bio because
- *     it spans a stripe (or similar). Add a trace for that action.
- *
- **/
-static inline void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
-				       dev_t dev, sector_t from, sector_t to)
-{
-	struct blk_trace *bt = q->blk_trace;
-	struct blk_io_trace_remap r;
-
-	if (likely(!bt))
-		return;
-
-	r.device = cpu_to_be32(dev);
-	r.device_from = cpu_to_be32(bio->bi_bdev->bd_dev);
-	r.sector = cpu_to_be64(to);
-
-	__blk_add_trace(bt, from, bio->bi_size, bio->bi_rw, BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r);
-}
-
-/**
- * blk_add_driver_data - Add binary message with driver-specific data
- * @q:		queue the io is for
- * @rq:		io request
- * @data:	driver-specific data
- * @len:	length of driver-specific data
- *
- * Description:
- *     Some drivers might want to write driver-specific data per request.
- *
- **/
-static inline void blk_add_driver_data(struct request_queue *q,
-				       struct request *rq,
-				       void *data, size_t len)
-{
-	struct blk_trace *bt = q->blk_trace;
-
-	if (likely(!bt))
-		return;
-
-	if (blk_pc_request(rq))
-		__blk_add_trace(bt, 0, rq->data_len, 0, BLK_TA_DRV_DATA,
-				rq->errors, len, data);
-	else
-		__blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9,
-				0, BLK_TA_DRV_DATA, rq->errors, len, data);
-}
-
+extern void blk_add_driver_data(struct request_queue *q, struct request *rq,
+				void *data, size_t len);
 extern int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
 			   char __user *arg);
 extern int blk_trace_startstop(struct request_queue *q, int start);
@@ -356,13 +195,8 @@
 #else /* !CONFIG_BLK_DEV_IO_TRACE */
 #define blk_trace_ioctl(bdev, cmd, arg)		(-ENOTTY)
 #define blk_trace_shutdown(q)			do { } while (0)
-#define blk_add_trace_rq(q, rq, what)		do { } while (0)
-#define blk_add_trace_bio(q, rq, what)		do { } while (0)
-#define blk_add_trace_generic(q, rq, rw, what)	do { } while (0)
-#define blk_add_trace_pdu_int(q, what, bio, pdu)	do { } while (0)
-#define blk_add_trace_remap(q, bio, dev, f, t)	do {} while (0)
-#define blk_add_driver_data(q, rq, data, len)	do {} while (0)
 #define do_blk_trace_setup(q, name, dev, buts)	(-ENOTTY)
+#define blk_add_driver_data(q, rq, data, len)	do {} while (0)
 #define blk_trace_setup(q, name, dev, arg)	(-ENOTTY)
 #define blk_trace_startstop(q, start)		(-ENOTTY)
 #define blk_trace_remove(q)			(-ENOTTY)
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 9d1fe30..e22f48c 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -53,6 +53,7 @@
 #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
 
 #define VFS_CAP_REVISION_MASK	0xFF000000
+#define VFS_CAP_REVISION_SHIFT	24
 #define VFS_CAP_FLAGS_MASK	~VFS_CAP_REVISION_MASK
 #define VFS_CAP_FLAGS_EFFECTIVE	0x000001
 
@@ -68,6 +69,9 @@
 #define VFS_CAP_U32             VFS_CAP_U32_2
 #define VFS_CAP_REVISION	VFS_CAP_REVISION_2
 
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
+extern int file_caps_enabled;
+#endif
 
 struct vfs_cap_data {
 	__le32 magic_etc;            /* Little endian */
@@ -96,6 +100,13 @@
 	__u32 cap[_KERNEL_CAPABILITY_U32S];
 } kernel_cap_t;
 
+/* exact same as vfs_cap_data but in cpu endian and always filled completely */
+struct cpu_vfs_cap_data {
+	__u32 magic_etc;
+	kernel_cap_t permitted;
+	kernel_cap_t inheritable;
+};
+
 #define _USER_CAP_HEADER_SIZE  (sizeof(struct __user_cap_header_struct))
 #define _KERNEL_CAP_T_SIZE     (sizeof(kernel_cap_t))
 
@@ -454,6 +465,13 @@
 	return 1;
 }
 
+/*
+ * Check if "a" is a subset of "set".
+ * return 1 if ALL of the capabilities in "a" are also in "set"
+ *	cap_issubset(0101, 1111) will return 1
+ * return 0 if ANY of the capabilities in "a" are not in "set"
+ *	cap_issubset(1111, 0101) will return 0
+ */
 static inline int cap_issubset(const kernel_cap_t a, const kernel_cap_t set)
 {
 	kernel_cap_t dest;
@@ -501,8 +519,6 @@
 extern const kernel_cap_t __cap_full_set;
 extern const kernel_cap_t __cap_init_eff_set;
 
-kernel_cap_t cap_set_effective(const kernel_cap_t pE_new);
-
 /**
  * has_capability - Determine if a task has a superior capability available
  * @t: The task in question
@@ -514,9 +530,14 @@
  * Note that this does not set PF_SUPERPRIV on the task.
  */
 #define has_capability(t, cap) (security_capable((t), (cap)) == 0)
+#define has_capability_noaudit(t, cap) (security_capable_noaudit((t), (cap)) == 0)
 
 extern int capable(int cap);
 
+/* audit system wants to get cap info from files as well */
+struct dentry;
+extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
+
 #endif /* __KERNEL__ */
 
 #endif /* !_LINUX_CAPABILITY_H */
diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h
index 9c22396..9c8d31b 100644
--- a/include/linux/cgroup_subsys.h
+++ b/include/linux/cgroup_subsys.h
@@ -54,3 +54,9 @@
 #endif
 
 /* */
+
+#ifdef CONFIG_NET_CLS_CGROUP
+SUBSYS(net_cls)
+#endif
+
+/* */
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 98115d9..ea7c6be 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -59,8 +59,88 @@
  * specific implementations come from the above header files
  */
 
-#define likely(x)	__builtin_expect(!!(x), 1)
-#define unlikely(x)	__builtin_expect(!!(x), 0)
+struct ftrace_branch_data {
+	const char *func;
+	const char *file;
+	unsigned line;
+	union {
+		struct {
+			unsigned long correct;
+			unsigned long incorrect;
+		};
+		struct {
+			unsigned long miss;
+			unsigned long hit;
+		};
+	};
+};
+
+/*
+ * Note: DISABLE_BRANCH_PROFILING can be used by special lowlevel code
+ * to disable branch tracing on a per file basis.
+ */
+#if defined(CONFIG_TRACE_BRANCH_PROFILING) && !defined(DISABLE_BRANCH_PROFILING)
+void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+
+#define likely_notrace(x)	__builtin_expect(!!(x), 1)
+#define unlikely_notrace(x)	__builtin_expect(!!(x), 0)
+
+#define __branch_check__(x, expect) ({					\
+			int ______r;					\
+			static struct ftrace_branch_data		\
+				__attribute__((__aligned__(4)))		\
+				__attribute__((section("_ftrace_annotated_branch"))) \
+				______f = {				\
+				.func = __func__,			\
+				.file = __FILE__,			\
+				.line = __LINE__,			\
+			};						\
+			______r = likely_notrace(x);			\
+			ftrace_likely_update(&______f, ______r, expect); \
+			______r;					\
+		})
+
+/*
+ * Using __builtin_constant_p(x) to ignore cases where the return
+ * value is always the same.  This idea is taken from a similar patch
+ * written by Daniel Walker.
+ */
+# ifndef likely
+#  define likely(x)	(__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1))
+# endif
+# ifndef unlikely
+#  define unlikely(x)	(__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
+# endif
+
+#ifdef CONFIG_PROFILE_ALL_BRANCHES
+/*
+ * "Define 'is'", Bill Clinton
+ * "Define 'if'", Steven Rostedt
+ */
+#define if(cond) if (__builtin_constant_p((cond)) ? !!(cond) :		\
+	({								\
+		int ______r;						\
+		static struct ftrace_branch_data			\
+			__attribute__((__aligned__(4)))			\
+			__attribute__((section("_ftrace_branch")))	\
+			______f = {					\
+				.func = __func__,			\
+				.file = __FILE__,			\
+				.line = __LINE__,			\
+			};						\
+		______r = !!(cond);					\
+		if (______r)						\
+			______f.hit++;					\
+		else							\
+			______f.miss++;					\
+		______r;						\
+	}))
+#endif /* CONFIG_PROFILE_ALL_BRANCHES */
+
+#else
+# define likely(x)	__builtin_expect(!!(x), 1)
+# define unlikely(x)	__builtin_expect(!!(x), 0)
+#endif
 
 /* Optimization barrier */
 #ifndef barrier
diff --git a/include/linux/crc32c.h b/include/linux/crc32c.h
index 508f512..bd8b44d 100644
--- a/include/linux/crc32c.h
+++ b/include/linux/crc32c.h
@@ -3,9 +3,9 @@
 
 #include <linux/types.h>
 
-extern u32 crc32c_le(u32 crc, unsigned char const *address, size_t length);
-extern u32 crc32c_be(u32 crc, unsigned char const *address, size_t length);
+extern u32 crc32c(u32 crc, const void *address, unsigned int length);
 
-#define crc32c(seed, data, length)  crc32c_le(seed, (unsigned char const *)data, length)
+/* This macro exists for backwards-compatibility. */
+#define crc32c_le crc32c
 
 #endif	/* _LINUX_CRC32C_H */
diff --git a/include/linux/cred.h b/include/linux/cred.h
index b69222c..3282ee4 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -1,4 +1,4 @@
-/* Credentials management
+/* Credentials management - see Documentation/credentials.txt
  *
  * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -12,39 +12,335 @@
 #ifndef _LINUX_CRED_H
 #define _LINUX_CRED_H
 
-#define get_current_user()	(get_uid(current->user))
+#include <linux/capability.h>
+#include <linux/key.h>
+#include <asm/atomic.h>
 
-#define task_uid(task)		((task)->uid)
-#define task_gid(task)		((task)->gid)
-#define task_euid(task)		((task)->euid)
-#define task_egid(task)		((task)->egid)
+struct user_struct;
+struct cred;
+struct inode;
 
-#define current_uid()		(current->uid)
-#define current_gid()		(current->gid)
-#define current_euid()		(current->euid)
-#define current_egid()		(current->egid)
-#define current_suid()		(current->suid)
-#define current_sgid()		(current->sgid)
-#define current_fsuid()		(current->fsuid)
-#define current_fsgid()		(current->fsgid)
-#define current_cap()		(current->cap_effective)
+/*
+ * COW Supplementary groups list
+ */
+#define NGROUPS_SMALL		32
+#define NGROUPS_PER_BLOCK	((unsigned int)(PAGE_SIZE / sizeof(gid_t)))
+
+struct group_info {
+	atomic_t	usage;
+	int		ngroups;
+	int		nblocks;
+	gid_t		small_block[NGROUPS_SMALL];
+	gid_t		*blocks[0];
+};
+
+/**
+ * get_group_info - Get a reference to a group info structure
+ * @group_info: The group info to reference
+ *
+ * This gets a reference to a set of supplementary groups.
+ *
+ * If the caller is accessing a task's credentials, they must hold the RCU read
+ * lock when reading.
+ */
+static inline struct group_info *get_group_info(struct group_info *gi)
+{
+	atomic_inc(&gi->usage);
+	return gi;
+}
+
+/**
+ * put_group_info - Release a reference to a group info structure
+ * @group_info: The group info to release
+ */
+#define put_group_info(group_info)			\
+do {							\
+	if (atomic_dec_and_test(&(group_info)->usage))	\
+		groups_free(group_info);		\
+} while (0)
+
+extern struct group_info *groups_alloc(int);
+extern struct group_info init_groups;
+extern void groups_free(struct group_info *);
+extern int set_current_groups(struct group_info *);
+extern int set_groups(struct cred *, struct group_info *);
+extern int groups_search(const struct group_info *, gid_t);
+
+/* access the groups "array" with this macro */
+#define GROUP_AT(gi, i) \
+	((gi)->blocks[(i) / NGROUPS_PER_BLOCK][(i) % NGROUPS_PER_BLOCK])
+
+extern int in_group_p(gid_t);
+extern int in_egroup_p(gid_t);
+
+/*
+ * The common credentials for a thread group
+ * - shared by CLONE_THREAD
+ */
+#ifdef CONFIG_KEYS
+struct thread_group_cred {
+	atomic_t	usage;
+	pid_t		tgid;			/* thread group process ID */
+	spinlock_t	lock;
+	struct key	*session_keyring;	/* keyring inherited over fork */
+	struct key	*process_keyring;	/* keyring private to this process */
+	struct rcu_head	rcu;			/* RCU deletion hook */
+};
+#endif
+
+/*
+ * The security context of a task
+ *
+ * The parts of the context break down into two categories:
+ *
+ *  (1) The objective context of a task.  These parts are used when some other
+ *	task is attempting to affect this one.
+ *
+ *  (2) The subjective context.  These details are used when the task is acting
+ *	upon another object, be that a file, a task, a key or whatever.
+ *
+ * Note that some members of this structure belong to both categories - the
+ * LSM security pointer for instance.
+ *
+ * A task has two security pointers.  task->real_cred points to the objective
+ * context that defines that task's actual details.  The objective part of this
+ * context is used whenever that task is acted upon.
+ *
+ * task->cred points to the subjective context that defines the details of how
+ * that task is going to act upon another object.  This may be overridden
+ * temporarily to point to another security context, but normally points to the
+ * same context as task->real_cred.
+ */
+struct cred {
+	atomic_t	usage;
+	uid_t		uid;		/* real UID of the task */
+	gid_t		gid;		/* real GID of the task */
+	uid_t		suid;		/* saved UID of the task */
+	gid_t		sgid;		/* saved GID of the task */
+	uid_t		euid;		/* effective UID of the task */
+	gid_t		egid;		/* effective GID of the task */
+	uid_t		fsuid;		/* UID for VFS ops */
+	gid_t		fsgid;		/* GID for VFS ops */
+	unsigned	securebits;	/* SUID-less security management */
+	kernel_cap_t	cap_inheritable; /* caps our children can inherit */
+	kernel_cap_t	cap_permitted;	/* caps we're permitted */
+	kernel_cap_t	cap_effective;	/* caps we can actually use */
+	kernel_cap_t	cap_bset;	/* capability bounding set */
+#ifdef CONFIG_KEYS
+	unsigned char	jit_keyring;	/* default keyring to attach requested
+					 * keys to */
+	struct key	*thread_keyring; /* keyring private to this thread */
+	struct key	*request_key_auth; /* assumed request_key authority */
+	struct thread_group_cred *tgcred; /* thread-group shared credentials */
+#endif
+#ifdef CONFIG_SECURITY
+	void		*security;	/* subjective LSM security */
+#endif
+	struct user_struct *user;	/* real user ID subscription */
+	struct group_info *group_info;	/* supplementary groups for euid/fsgid */
+	struct rcu_head	rcu;		/* RCU deletion hook */
+};
+
+extern void __put_cred(struct cred *);
+extern int copy_creds(struct task_struct *, unsigned long);
+extern struct cred *prepare_creds(void);
+extern struct cred *prepare_exec_creds(void);
+extern struct cred *prepare_usermodehelper_creds(void);
+extern int commit_creds(struct cred *);
+extern void abort_creds(struct cred *);
+extern const struct cred *override_creds(const struct cred *);
+extern void revert_creds(const struct cred *);
+extern struct cred *prepare_kernel_cred(struct task_struct *);
+extern int change_create_files_as(struct cred *, struct inode *);
+extern int set_security_override(struct cred *, u32);
+extern int set_security_override_from_ctx(struct cred *, const char *);
+extern int set_create_files_as(struct cred *, struct inode *);
+extern void __init cred_init(void);
+
+/**
+ * get_new_cred - Get a reference on a new set of credentials
+ * @cred: The new credentials to reference
+ *
+ * Get a reference on the specified set of new credentials.  The caller must
+ * release the reference.
+ */
+static inline struct cred *get_new_cred(struct cred *cred)
+{
+	atomic_inc(&cred->usage);
+	return cred;
+}
+
+/**
+ * get_cred - Get a reference on a set of credentials
+ * @cred: The credentials to reference
+ *
+ * Get a reference on the specified set of credentials.  The caller must
+ * release the reference.
+ *
+ * This is used to deal with a committed set of credentials.  Although the
+ * pointer is const, this will temporarily discard the const and increment the
+ * usage count.  The purpose of this is to attempt to catch at compile time the
+ * accidental alteration of a set of credentials that should be considered
+ * immutable.
+ */
+static inline const struct cred *get_cred(const struct cred *cred)
+{
+	return get_new_cred((struct cred *) cred);
+}
+
+/**
+ * put_cred - Release a reference to a set of credentials
+ * @cred: The credentials to release
+ *
+ * Release a reference to a set of credentials, deleting them when the last ref
+ * is released.
+ *
+ * This takes a const pointer to a set of credentials because the credentials
+ * on task_struct are attached by const pointers to prevent accidental
+ * alteration of otherwise immutable credential sets.
+ */
+static inline void put_cred(const struct cred *_cred)
+{
+	struct cred *cred = (struct cred *) _cred;
+
+	BUG_ON(atomic_read(&(cred)->usage) <= 0);
+	if (atomic_dec_and_test(&(cred)->usage))
+		__put_cred(cred);
+}
+
+/**
+ * current_cred - Access the current task's subjective credentials
+ *
+ * Access the subjective credentials of the current task.
+ */
+#define current_cred() \
+	(current->cred)
+
+/**
+ * __task_cred - Access a task's objective credentials
+ * @task: The task to query
+ *
+ * Access the objective credentials of a task.  The caller must hold the RCU
+ * readlock.
+ *
+ * The caller must make sure task doesn't go away, either by holding a ref on
+ * task or by holding tasklist_lock to prevent it from being unlinked.
+ */
+#define __task_cred(task) \
+	((const struct cred *)(rcu_dereference((task)->real_cred)))
+
+/**
+ * get_task_cred - Get another task's objective credentials
+ * @task: The task to query
+ *
+ * Get the objective credentials of a task, pinning them so that they can't go
+ * away.  Accessing a task's credentials directly is not permitted.
+ *
+ * The caller must make sure task doesn't go away, either by holding a ref on
+ * task or by holding tasklist_lock to prevent it from being unlinked.
+ */
+#define get_task_cred(task)				\
+({							\
+	struct cred *__cred;				\
+	rcu_read_lock();				\
+	__cred = (struct cred *) __task_cred((task));	\
+	get_cred(__cred);				\
+	rcu_read_unlock();				\
+	__cred;						\
+})
+
+/**
+ * get_current_cred - Get the current task's subjective credentials
+ *
+ * Get the subjective credentials of the current task, pinning them so that
+ * they can't go away.  Accessing the current task's credentials directly is
+ * not permitted.
+ */
+#define get_current_cred()				\
+	(get_cred(current_cred()))
+
+/**
+ * get_current_user - Get the current task's user_struct
+ *
+ * Get the user record of the current task, pinning it so that it can't go
+ * away.
+ */
+#define get_current_user()				\
+({							\
+	struct user_struct *__u;			\
+	struct cred *__cred;				\
+	__cred = (struct cred *) current_cred();	\
+	__u = get_uid(__cred->user);			\
+	__u;						\
+})
+
+/**
+ * get_current_groups - Get the current task's supplementary group list
+ *
+ * Get the supplementary group list of the current task, pinning it so that it
+ * can't go away.
+ */
+#define get_current_groups()				\
+({							\
+	struct group_info *__groups;			\
+	struct cred *__cred;				\
+	__cred = (struct cred *) current_cred();	\
+	__groups = get_group_info(__cred->group_info);	\
+	__groups;					\
+})
+
+#define task_cred_xxx(task, xxx)			\
+({							\
+	__typeof__(((struct cred *)NULL)->xxx) ___val;	\
+	rcu_read_lock();				\
+	___val = __task_cred((task))->xxx;		\
+	rcu_read_unlock();				\
+	___val;						\
+})
+
+#define task_uid(task)		(task_cred_xxx((task), uid))
+#define task_euid(task)		(task_cred_xxx((task), euid))
+
+#define current_cred_xxx(xxx)			\
+({						\
+	current->cred->xxx;			\
+})
+
+#define current_uid()		(current_cred_xxx(uid))
+#define current_gid()		(current_cred_xxx(gid))
+#define current_euid()		(current_cred_xxx(euid))
+#define current_egid()		(current_cred_xxx(egid))
+#define current_suid()		(current_cred_xxx(suid))
+#define current_sgid()		(current_cred_xxx(sgid))
+#define current_fsuid() 	(current_cred_xxx(fsuid))
+#define current_fsgid() 	(current_cred_xxx(fsgid))
+#define current_cap()		(current_cred_xxx(cap_effective))
+#define current_user()		(current_cred_xxx(user))
+#define current_user_ns()	(current_cred_xxx(user)->user_ns)
+#define current_security()	(current_cred_xxx(security))
 
 #define current_uid_gid(_uid, _gid)		\
 do {						\
-	*(_uid) = current->uid;			\
-	*(_gid) = current->gid;			\
+	const struct cred *__cred;		\
+	__cred = current_cred();		\
+	*(_uid) = __cred->uid;			\
+	*(_gid) = __cred->gid;			\
 } while(0)
 
-#define current_euid_egid(_uid, _gid)		\
+#define current_euid_egid(_euid, _egid)		\
 do {						\
-	*(_uid) = current->euid;		\
-	*(_gid) = current->egid;		\
+	const struct cred *__cred;		\
+	__cred = current_cred();		\
+	*(_euid) = __cred->euid;		\
+	*(_egid) = __cred->egid;		\
 } while(0)
 
-#define current_fsuid_fsgid(_uid, _gid)		\
+#define current_fsuid_fsgid(_fsuid, _fsgid)	\
 do {						\
-	*(_uid) = current->fsuid;		\
-	*(_gid) = current->fsgid;		\
+	const struct cred *__cred;		\
+	__cred = current_cred();		\
+	*(_fsuid) = __cred->fsuid;		\
+	*(_fsgid) = __cred->fsgid;		\
 } while(0)
 
 #endif /* _LINUX_CRED_H */
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 3d2317e..3bacd71 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -36,7 +36,8 @@
 #define CRYPTO_ALG_TYPE_ABLKCIPHER	0x00000005
 #define CRYPTO_ALG_TYPE_GIVCIPHER	0x00000006
 #define CRYPTO_ALG_TYPE_DIGEST		0x00000008
-#define CRYPTO_ALG_TYPE_HASH		0x00000009
+#define CRYPTO_ALG_TYPE_HASH		0x00000008
+#define CRYPTO_ALG_TYPE_SHASH		0x00000009
 #define CRYPTO_ALG_TYPE_AHASH		0x0000000a
 #define CRYPTO_ALG_TYPE_RNG		0x0000000c
 
@@ -220,6 +221,7 @@
 
 struct ahash_alg {
 	int (*init)(struct ahash_request *req);
+	int (*reinit)(struct ahash_request *req);
 	int (*update)(struct ahash_request *req);
 	int (*final)(struct ahash_request *req);
 	int (*digest)(struct ahash_request *req);
@@ -480,6 +482,8 @@
 		struct compress_tfm compress;
 		struct rng_tfm rng;
 	} crt_u;
+
+	void (*exit)(struct crypto_tfm *tfm);
 	
 	struct crypto_alg *__crt_alg;
 
@@ -544,7 +548,9 @@
  * Transform user interface.
  */
  
-struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags);
+struct crypto_tfm *crypto_alloc_tfm(const char *alg_name,
+				    const struct crypto_type *frontend,
+				    u32 type, u32 mask);
 struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask);
 void crypto_free_tfm(struct crypto_tfm *tfm);
 
diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h
new file mode 100644
index 0000000..b0ef274
--- /dev/null
+++ b/include/linux/dcbnl.h
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Lucy Liu <lucy.liu@intel.com>
+ */
+
+#ifndef __LINUX_DCBNL_H__
+#define __LINUX_DCBNL_H__
+
+#define DCB_PROTO_VERSION 1
+
+struct dcbmsg {
+	unsigned char      dcb_family;
+	__u8               cmd;
+	__u16              dcb_pad;
+};
+
+/**
+ * enum dcbnl_commands - supported DCB commands
+ *
+ * @DCB_CMD_UNDEFINED: unspecified command to catch errors
+ * @DCB_CMD_GSTATE: request the state of DCB in the device
+ * @DCB_CMD_SSTATE: set the state of DCB in the device
+ * @DCB_CMD_PGTX_GCFG: request the priority group configuration for Tx
+ * @DCB_CMD_PGTX_SCFG: set the priority group configuration for Tx
+ * @DCB_CMD_PGRX_GCFG: request the priority group configuration for Rx
+ * @DCB_CMD_PGRX_SCFG: set the priority group configuration for Rx
+ * @DCB_CMD_PFC_GCFG: request the priority flow control configuration
+ * @DCB_CMD_PFC_SCFG: set the priority flow control configuration
+ * @DCB_CMD_SET_ALL: apply all changes to the underlying device
+ * @DCB_CMD_GPERM_HWADDR: get the permanent MAC address of the underlying
+ *                        device.  Only useful when using bonding.
+ * @DCB_CMD_GCAP: request the DCB capabilities of the device
+ * @DCB_CMD_GNUMTCS: get the number of traffic classes currently supported
+ * @DCB_CMD_SNUMTCS: set the number of traffic classes
+ * @DCB_CMD_GBCN: set backward congestion notification configuration
+ * @DCB_CMD_SBCN: get backward congestion notification configration.
+ */
+enum dcbnl_commands {
+	DCB_CMD_UNDEFINED,
+
+	DCB_CMD_GSTATE,
+	DCB_CMD_SSTATE,
+
+	DCB_CMD_PGTX_GCFG,
+	DCB_CMD_PGTX_SCFG,
+	DCB_CMD_PGRX_GCFG,
+	DCB_CMD_PGRX_SCFG,
+
+	DCB_CMD_PFC_GCFG,
+	DCB_CMD_PFC_SCFG,
+
+	DCB_CMD_SET_ALL,
+
+	DCB_CMD_GPERM_HWADDR,
+
+	DCB_CMD_GCAP,
+
+	DCB_CMD_GNUMTCS,
+	DCB_CMD_SNUMTCS,
+
+	DCB_CMD_PFC_GSTATE,
+	DCB_CMD_PFC_SSTATE,
+
+	DCB_CMD_BCN_GCFG,
+	DCB_CMD_BCN_SCFG,
+
+	__DCB_CMD_ENUM_MAX,
+	DCB_CMD_MAX = __DCB_CMD_ENUM_MAX - 1,
+};
+
+/**
+ * enum dcbnl_attrs - DCB top-level netlink attributes
+ *
+ * @DCB_ATTR_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_ATTR_IFNAME: interface name of the underlying device (NLA_STRING)
+ * @DCB_ATTR_STATE: enable state of DCB in the device (NLA_U8)
+ * @DCB_ATTR_PFC_STATE: enable state of PFC in the device (NLA_U8)
+ * @DCB_ATTR_PFC_CFG: priority flow control configuration (NLA_NESTED)
+ * @DCB_ATTR_NUM_TC: number of traffic classes supported in the device (NLA_U8)
+ * @DCB_ATTR_PG_CFG: priority group configuration (NLA_NESTED)
+ * @DCB_ATTR_SET_ALL: bool to commit changes to hardware or not (NLA_U8)
+ * @DCB_ATTR_PERM_HWADDR: MAC address of the physical device (NLA_NESTED)
+ * @DCB_ATTR_CAP: DCB capabilities of the device (NLA_NESTED)
+ * @DCB_ATTR_NUMTCS: number of traffic classes supported (NLA_NESTED)
+ * @DCB_ATTR_BCN: backward congestion notification configuration (NLA_NESTED)
+ */
+enum dcbnl_attrs {
+	DCB_ATTR_UNDEFINED,
+
+	DCB_ATTR_IFNAME,
+	DCB_ATTR_STATE,
+	DCB_ATTR_PFC_STATE,
+	DCB_ATTR_PFC_CFG,
+	DCB_ATTR_NUM_TC,
+	DCB_ATTR_PG_CFG,
+	DCB_ATTR_SET_ALL,
+	DCB_ATTR_PERM_HWADDR,
+	DCB_ATTR_CAP,
+	DCB_ATTR_NUMTCS,
+	DCB_ATTR_BCN,
+
+	__DCB_ATTR_ENUM_MAX,
+	DCB_ATTR_MAX = __DCB_ATTR_ENUM_MAX - 1,
+};
+
+/**
+ * enum dcbnl_pfc_attrs - DCB Priority Flow Control user priority nested attrs
+ *
+ * @DCB_PFC_UP_ATTR_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_PFC_UP_ATTR_0: Priority Flow Control value for User Priority 0 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_1: Priority Flow Control value for User Priority 1 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_2: Priority Flow Control value for User Priority 2 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_3: Priority Flow Control value for User Priority 3 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_4: Priority Flow Control value for User Priority 4 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_5: Priority Flow Control value for User Priority 5 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_6: Priority Flow Control value for User Priority 6 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_7: Priority Flow Control value for User Priority 7 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_MAX: highest attribute number currently defined
+ * @DCB_PFC_UP_ATTR_ALL: apply to all priority flow control attrs (NLA_FLAG)
+ *
+ */
+enum dcbnl_pfc_up_attrs {
+	DCB_PFC_UP_ATTR_UNDEFINED,
+
+	DCB_PFC_UP_ATTR_0,
+	DCB_PFC_UP_ATTR_1,
+	DCB_PFC_UP_ATTR_2,
+	DCB_PFC_UP_ATTR_3,
+	DCB_PFC_UP_ATTR_4,
+	DCB_PFC_UP_ATTR_5,
+	DCB_PFC_UP_ATTR_6,
+	DCB_PFC_UP_ATTR_7,
+	DCB_PFC_UP_ATTR_ALL,
+
+	__DCB_PFC_UP_ATTR_ENUM_MAX,
+	DCB_PFC_UP_ATTR_MAX = __DCB_PFC_UP_ATTR_ENUM_MAX - 1,
+};
+
+/**
+ * enum dcbnl_pg_attrs - DCB Priority Group attributes
+ *
+ * @DCB_PG_ATTR_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_PG_ATTR_TC_0: Priority Group Traffic Class 0 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_1: Priority Group Traffic Class 1 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_2: Priority Group Traffic Class 2 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_3: Priority Group Traffic Class 3 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_4: Priority Group Traffic Class 4 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_5: Priority Group Traffic Class 5 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_6: Priority Group Traffic Class 6 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_7: Priority Group Traffic Class 7 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_MAX: highest attribute number currently defined
+ * @DCB_PG_ATTR_TC_ALL: apply to all traffic classes (NLA_NESTED)
+ * @DCB_PG_ATTR_BW_ID_0: Percent of link bandwidth for Priority Group 0 (NLA_U8)
+ * @DCB_PG_ATTR_BW_ID_1: Percent of link bandwidth for Priority Group 1 (NLA_U8)
+ * @DCB_PG_ATTR_BW_ID_2: Percent of link bandwidth for Priority Group 2 (NLA_U8)
+ * @DCB_PG_ATTR_BW_ID_3: Percent of link bandwidth for Priority Group 3 (NLA_U8)
+ * @DCB_PG_ATTR_BW_ID_4: Percent of link bandwidth for Priority Group 4 (NLA_U8)
+ * @DCB_PG_ATTR_BW_ID_5: Percent of link bandwidth for Priority Group 5 (NLA_U8)
+ * @DCB_PG_ATTR_BW_ID_6: Percent of link bandwidth for Priority Group 6 (NLA_U8)
+ * @DCB_PG_ATTR_BW_ID_7: Percent of link bandwidth for Priority Group 7 (NLA_U8)
+ * @DCB_PG_ATTR_BW_ID_MAX: highest attribute number currently defined
+ * @DCB_PG_ATTR_BW_ID_ALL: apply to all priority groups (NLA_FLAG)
+ *
+ */
+enum dcbnl_pg_attrs {
+	DCB_PG_ATTR_UNDEFINED,
+
+	DCB_PG_ATTR_TC_0,
+	DCB_PG_ATTR_TC_1,
+	DCB_PG_ATTR_TC_2,
+	DCB_PG_ATTR_TC_3,
+	DCB_PG_ATTR_TC_4,
+	DCB_PG_ATTR_TC_5,
+	DCB_PG_ATTR_TC_6,
+	DCB_PG_ATTR_TC_7,
+	DCB_PG_ATTR_TC_MAX,
+	DCB_PG_ATTR_TC_ALL,
+
+	DCB_PG_ATTR_BW_ID_0,
+	DCB_PG_ATTR_BW_ID_1,
+	DCB_PG_ATTR_BW_ID_2,
+	DCB_PG_ATTR_BW_ID_3,
+	DCB_PG_ATTR_BW_ID_4,
+	DCB_PG_ATTR_BW_ID_5,
+	DCB_PG_ATTR_BW_ID_6,
+	DCB_PG_ATTR_BW_ID_7,
+	DCB_PG_ATTR_BW_ID_MAX,
+	DCB_PG_ATTR_BW_ID_ALL,
+
+	__DCB_PG_ATTR_ENUM_MAX,
+	DCB_PG_ATTR_MAX = __DCB_PG_ATTR_ENUM_MAX - 1,
+};
+
+/**
+ * enum dcbnl_tc_attrs - DCB Traffic Class attributes
+ *
+ * @DCB_TC_ATTR_PARAM_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_TC_ATTR_PARAM_PGID: (NLA_U8) Priority group the traffic class belongs to
+ *                          Valid values are:  0-7
+ * @DCB_TC_ATTR_PARAM_UP_MAPPING: (NLA_U8) Traffic class to user priority map
+ *                                Some devices may not support changing the
+ *                                user priority map of a TC.
+ * @DCB_TC_ATTR_PARAM_STRICT_PRIO: (NLA_U8) Strict priority setting
+ *                                 0 - none
+ *                                 1 - group strict
+ *                                 2 - link strict
+ * @DCB_TC_ATTR_PARAM_BW_PCT: optional - (NLA_U8) If supported by the device and
+ *                            not configured to use link strict priority,
+ *                            this is the percentage of bandwidth of the
+ *                            priority group this traffic class belongs to
+ * @DCB_TC_ATTR_PARAM_ALL: (NLA_FLAG) all traffic class parameters
+ *
+ */
+enum dcbnl_tc_attrs {
+	DCB_TC_ATTR_PARAM_UNDEFINED,
+
+	DCB_TC_ATTR_PARAM_PGID,
+	DCB_TC_ATTR_PARAM_UP_MAPPING,
+	DCB_TC_ATTR_PARAM_STRICT_PRIO,
+	DCB_TC_ATTR_PARAM_BW_PCT,
+	DCB_TC_ATTR_PARAM_ALL,
+
+	__DCB_TC_ATTR_PARAM_ENUM_MAX,
+	DCB_TC_ATTR_PARAM_MAX = __DCB_TC_ATTR_PARAM_ENUM_MAX - 1,
+};
+
+/**
+ * enum dcbnl_cap_attrs - DCB Capability attributes
+ *
+ * @DCB_CAP_ATTR_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_CAP_ATTR_ALL: (NLA_FLAG) all capability parameters
+ * @DCB_CAP_ATTR_PG: (NLA_U8) device supports Priority Groups
+ * @DCB_CAP_ATTR_PFC: (NLA_U8) device supports Priority Flow Control
+ * @DCB_CAP_ATTR_UP2TC: (NLA_U8) device supports user priority to
+ *                               traffic class mapping
+ * @DCB_CAP_ATTR_PG_TCS: (NLA_U8) bitmap where each bit represents a
+ *                                number of traffic classes the device
+ *                                can be configured to use for Priority Groups
+ * @DCB_CAP_ATTR_PFC_TCS: (NLA_U8) bitmap where each bit represents a
+ *                                 number of traffic classes the device can be
+ *                                 configured to use for Priority Flow Control
+ * @DCB_CAP_ATTR_GSP: (NLA_U8) device supports group strict priority
+ * @DCB_CAP_ATTR_BCN: (NLA_U8) device supports Backwards Congestion
+ *                             Notification
+ */
+enum dcbnl_cap_attrs {
+	DCB_CAP_ATTR_UNDEFINED,
+	DCB_CAP_ATTR_ALL,
+	DCB_CAP_ATTR_PG,
+	DCB_CAP_ATTR_PFC,
+	DCB_CAP_ATTR_UP2TC,
+	DCB_CAP_ATTR_PG_TCS,
+	DCB_CAP_ATTR_PFC_TCS,
+	DCB_CAP_ATTR_GSP,
+	DCB_CAP_ATTR_BCN,
+
+	__DCB_CAP_ATTR_ENUM_MAX,
+	DCB_CAP_ATTR_MAX = __DCB_CAP_ATTR_ENUM_MAX - 1,
+};
+
+/**
+ * enum dcbnl_numtcs_attrs - number of traffic classes
+ *
+ * @DCB_NUMTCS_ATTR_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_NUMTCS_ATTR_ALL: (NLA_FLAG) all traffic class attributes
+ * @DCB_NUMTCS_ATTR_PG: (NLA_U8) number of traffic classes used for
+ *                               priority groups
+ * @DCB_NUMTCS_ATTR_PFC: (NLA_U8) number of traffic classes which can
+ *                                support priority flow control
+ */
+enum dcbnl_numtcs_attrs {
+	DCB_NUMTCS_ATTR_UNDEFINED,
+	DCB_NUMTCS_ATTR_ALL,
+	DCB_NUMTCS_ATTR_PG,
+	DCB_NUMTCS_ATTR_PFC,
+
+	__DCB_NUMTCS_ATTR_ENUM_MAX,
+	DCB_NUMTCS_ATTR_MAX = __DCB_NUMTCS_ATTR_ENUM_MAX - 1,
+};
+
+enum dcbnl_bcn_attrs{
+	DCB_BCN_ATTR_UNDEFINED = 0,
+
+	DCB_BCN_ATTR_RP_0,
+	DCB_BCN_ATTR_RP_1,
+	DCB_BCN_ATTR_RP_2,
+	DCB_BCN_ATTR_RP_3,
+	DCB_BCN_ATTR_RP_4,
+	DCB_BCN_ATTR_RP_5,
+	DCB_BCN_ATTR_RP_6,
+	DCB_BCN_ATTR_RP_7,
+	DCB_BCN_ATTR_RP_ALL,
+
+	DCB_BCN_ATTR_BCNA_0,
+	DCB_BCN_ATTR_BCNA_1,
+	DCB_BCN_ATTR_ALPHA,
+	DCB_BCN_ATTR_BETA,
+	DCB_BCN_ATTR_GD,
+	DCB_BCN_ATTR_GI,
+	DCB_BCN_ATTR_TMAX,
+	DCB_BCN_ATTR_TD,
+	DCB_BCN_ATTR_RMIN,
+	DCB_BCN_ATTR_W,
+	DCB_BCN_ATTR_RD,
+	DCB_BCN_ATTR_RU,
+	DCB_BCN_ATTR_WRTT,
+	DCB_BCN_ATTR_RI,
+	DCB_BCN_ATTR_C,
+	DCB_BCN_ATTR_ALL,
+
+	__DCB_BCN_ATTR_ENUM_MAX,
+	DCB_BCN_ATTR_MAX = __DCB_BCN_ATTR_ENUM_MAX - 1,
+};
+
+/**
+ * enum dcb_general_attr_values - general DCB attribute values
+ *
+ * @DCB_ATTR_UNDEFINED: value used to indicate an attribute is not supported
+ *
+ */
+enum dcb_general_attr_values {
+	DCB_ATTR_VALUE_UNDEFINED = 0xff
+};
+
+
+#endif /* __LINUX_DCBNL_H__ */
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 6080449..61734e2 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -168,6 +168,8 @@
 	DCCPO_MIN_CCID_SPECIFIC = 128,
 	DCCPO_MAX_CCID_SPECIFIC = 255,
 };
+/* maximum size of a single TLV-encoded DCCP option (sans type/len bytes) */
+#define DCCP_SINGLE_OPT_MAXLEN	253
 
 /* DCCP CCIDS */
 enum {
@@ -176,29 +178,23 @@
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
-/* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
-struct dccp_so_feat {
-	__u8 dccpsf_feat;
-	__u8 __user *dccpsf_val;
-	__u8 dccpsf_len;
-};
-
 /* DCCP socket options */
 #define DCCP_SOCKOPT_PACKET_SIZE	1 /* XXX deprecated, without effect */
 #define DCCP_SOCKOPT_SERVICE		2
@@ -208,6 +204,10 @@
 #define DCCP_SOCKOPT_SERVER_TIMEWAIT	6
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
+#define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
+#define DCCP_SOCKOPT_CCID		13
+#define DCCP_SOCKOPT_TX_CCID		14
+#define DCCP_SOCKOPT_RX_CCID		15
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
@@ -360,7 +360,6 @@
 #define DCCPF_INITIAL_SEQUENCE_WINDOW		100
 #define DCCPF_INITIAL_ACK_RATIO			2
 #define DCCPF_INITIAL_CCID			DCCPC_CCID2
-#define DCCPF_INITIAL_SEND_ACK_VECTOR		1
 /* FIXME: for now we're default to 1 but it should really be 0 */
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
@@ -370,20 +369,11 @@
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
-  * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
-  * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
-  * @dccpms_ack_ratio - Ack Ratio Feature (section 11.3)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	__u8			dccpms_rx_ccid;
-	__u8			dccpms_tx_ccid;
-	__u8			dccpms_send_ack_vector;
-	__u8			dccpms_send_ndp_count;
-	__u8			dccpms_ack_ratio;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
@@ -411,6 +401,7 @@
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
  * @dreq_isr: initial sequence number received on the Request
  * @dreq_service: service code present on the Request (there is just one)
+ * @dreq_featneg: feature negotiation options for this connection
  * The following two fields are analogous to the ones in dccp_sock:
  * @dreq_timestamp_echo: last received timestamp to echo (13.1)
  * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
@@ -420,6 +411,7 @@
 	__u64			 dreq_iss;
 	__u64			 dreq_isr;
 	__be32			 dreq_service;
+	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
 };
@@ -493,10 +485,12 @@
  * @dccps_r_ack_ratio - feature-remote Ack Ratio
  * @dccps_pcslen - sender   partial checksum coverage (via sockopt)
  * @dccps_pcrlen - receiver partial checksum coverage (via sockopt)
+ * @dccps_send_ndp_count - local Send NDP Count feature (7.7.2)
  * @dccps_ndp_count - number of Non Data Packets since last data packet
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
  * @dccps_minisock - associated minisock (accessed via dccp_msk)
+ * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
  * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
@@ -529,11 +523,13 @@
 	__u32				dccps_timestamp_time;
 	__u16				dccps_l_ack_ratio;
 	__u16				dccps_r_ack_ratio;
-	__u16				dccps_pcslen;
-	__u16				dccps_pcrlen;
+	__u8				dccps_pcslen:4;
+	__u8				dccps_pcrlen:4;
+	__u8				dccps_send_ndp_count:1;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
+	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
 	struct ccid			*dccps_hc_tx_ccid;
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index e5084eb..2bfda17 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -44,6 +44,7 @@
 extern void dmi_scan_machine(void);
 extern int dmi_get_year(int field);
 extern int dmi_name_in_vendors(const char *str);
+extern int dmi_name_in_serial(const char *str);
 extern int dmi_available;
 extern int dmi_walk(void (*decode)(const struct dmi_header *));
 
@@ -56,6 +57,7 @@
 static inline void dmi_scan_machine(void) { return; }
 static inline int dmi_get_year(int year) { return 0; }
 static inline int dmi_name_in_vendors(const char *s) { return 0; }
+static inline int dmi_name_in_serial(const char *s) { return 0; }
 #define dmi_available 0
 static inline int dmi_walk(void (*decode)(const struct dmi_header *))
 	{ return -1; }
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 25d62e6..1cb0f0b 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -27,6 +27,7 @@
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/random.h>
+#include <asm/unaligned.h>
 
 #ifdef __KERNEL__
 extern __be16		eth_type_trans(struct sk_buff *skb, struct net_device *dev);
@@ -41,6 +42,10 @@
 extern void eth_header_cache_update(struct hh_cache *hh,
 				    const struct net_device *dev,
 				    const unsigned char *haddr);
+extern int eth_mac_addr(struct net_device *dev, void *p);
+extern int eth_change_mtu(struct net_device *dev, int new_mtu);
+extern int eth_validate_addr(struct net_device *dev);
+
 
 
 extern struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count);
@@ -136,6 +141,47 @@
 	BUILD_BUG_ON(ETH_ALEN != 6);
 	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
 }
+
+static inline unsigned long zap_last_2bytes(unsigned long value)
+{
+#ifdef __BIG_ENDIAN
+	return value >> 16;
+#else
+	return value << 16;
+#endif
+}
+
+/**
+ * compare_ether_addr_64bits - Compare two Ethernet addresses
+ * @addr1: Pointer to an array of 8 bytes
+ * @addr2: Pointer to an other array of 8 bytes
+ *
+ * Compare two ethernet addresses, returns 0 if equal.
+ * Same result than "memcmp(addr1, addr2, ETH_ALEN)" but without conditional
+ * branches, and possibly long word memory accesses on CPU allowing cheap
+ * unaligned memory reads.
+ * arrays = { byte1, byte2, byte3, byte4, byte6, byte7, pad1, pad2}
+ *
+ * Please note that alignment of addr1 & addr2 is only guaranted to be 16 bits.
+ */
+
+static inline unsigned compare_ether_addr_64bits(const u8 addr1[6+2],
+						 const u8 addr2[6+2])
+{
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+	unsigned long fold = ((*(unsigned long *)addr1) ^
+			      (*(unsigned long *)addr2));
+
+	if (sizeof(fold) == 8)
+		return zap_last_2bytes(fold) != 0;
+
+	fold |= zap_last_2bytes((*(unsigned long *)(addr1 + 4)) ^
+				(*(unsigned long *)(addr2 + 4)));
+	return fold != 0;
+#else
+	return compare_ether_addr(addr1, addr2);
+#endif
+}
 #endif	/* __KERNEL__ */
 
 #endif	/* _LINUX_ETHERDEVICE_H */
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index b4b038b..27c67a5 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -467,6 +467,8 @@
 
 #define	ETHTOOL_GRXFH		0x00000029 /* Get RX flow hash configuration */
 #define	ETHTOOL_SRXFH		0x0000002a /* Set RX flow hash configuration */
+#define ETHTOOL_GGRO		0x0000002b /* Get GRO enable (ethtool_value) */
+#define ETHTOOL_SGRO		0x0000002c /* Set GRO enable (ethtool_value) */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET		ETHTOOL_GSET
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 75a81ea..1ee63df 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -888,7 +888,7 @@
 #define fb_writeq sbus_writeq
 #define fb_memset sbus_memset_io
 
-#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__) || defined(__avr32__)
+#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || defined(__avr32__)
 
 #define fb_readb __raw_readb
 #define fb_readw __raw_readw
diff --git a/include/linux/fddidevice.h b/include/linux/fddidevice.h
index e61e42d..155bafd 100644
--- a/include/linux/fddidevice.h
+++ b/include/linux/fddidevice.h
@@ -27,6 +27,7 @@
 #ifdef __KERNEL__
 extern __be16	fddi_type_trans(struct sk_buff *skb,
 				struct net_device *dev);
+extern int fddi_change_mtu(struct net_device *dev, int new_mtu);
 extern struct net_device *alloc_fddidev(int sizeof_priv);
 #endif
 
diff --git a/include/linux/filter.h b/include/linux/filter.h
index b6ea9aa..1354aaf 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -122,7 +122,8 @@
 #define SKF_AD_PKTTYPE 	4
 #define SKF_AD_IFINDEX 	8
 #define SKF_AD_NLATTR	12
-#define SKF_AD_MAX 	16
+#define SKF_AD_NLATTR_NEST	16
+#define SKF_AD_MAX	20
 #define SKF_NET_OFF   (-0x100000)
 #define SKF_LL_OFF    (-0x200000)
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 1ba7630..001ded4 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -324,6 +324,7 @@
 struct kstatfs;
 struct vm_area_struct;
 struct vfsmount;
+struct cred;
 
 extern void __init inode_init(void);
 extern void __init inode_init_early(void);
@@ -835,7 +836,7 @@
 	fmode_t			f_mode;
 	loff_t			f_pos;
 	struct fown_struct	f_owner;
-	unsigned int		f_uid, f_gid;
+	const struct cred	*f_cred;
 	struct file_ra_state	f_ra;
 
 	u64			f_version;
@@ -1202,7 +1203,7 @@
 #define has_fs_excl() atomic_read(&current->fs_excl)
 
 #define is_owner_or_cap(inode)	\
-	((current->fsuid == (inode)->i_uid) || capable(CAP_FOWNER))
+	((current_fsuid() == (inode)->i_uid) || capable(CAP_FOWNER))
 
 /* not quite ready to be deprecated, but... */
 extern void lock_super(struct super_block *);
@@ -1682,7 +1683,8 @@
 extern long do_sys_open(int dfd, const char __user *filename, int flags,
 			int mode);
 extern struct file *filp_open(const char *, int, int);
-extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
+extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
+				 const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
 extern char * getname(const char __user *);
 
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 708bab5..d9051d7 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -47,12 +47,7 @@
 struct gianfar_platform_data {
 	/* device specific information */
 	u32	device_flags;
-	/* board specific information */
-	u32	board_flags;
-	int	mdio_bus;			/* Bus controlled by us */
-	char	bus_id[MII_BUS_ID_SIZE];	/* Bus PHY is on */
-	u32	phy_id;
-	u8	mac_addr[6];
+	char	bus_id[BUS_ID_SIZE];
 	phy_interface_t interface;
 };
 
@@ -61,17 +56,6 @@
 	int	irq[32];
 };
 
-/* Flags related to gianfar device features */
-#define FSL_GIANFAR_DEV_HAS_GIGABIT		0x00000001
-#define FSL_GIANFAR_DEV_HAS_COALESCE		0x00000002
-#define FSL_GIANFAR_DEV_HAS_RMON		0x00000004
-#define FSL_GIANFAR_DEV_HAS_MULTI_INTR		0x00000008
-#define FSL_GIANFAR_DEV_HAS_CSUM		0x00000010
-#define FSL_GIANFAR_DEV_HAS_VLAN		0x00000020
-#define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH	0x00000040
-#define FSL_GIANFAR_DEV_HAS_PADDING		0x00000080
-#define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET	0x00000100
-
 /* Flags in gianfar_platform_data */
 #define FSL_GIANFAR_BRD_HAS_PHY_INTR	0x00000001 /* set or use a timer */
 #define FSL_GIANFAR_BRD_IS_REDUCED	0x00000002 /* Set if RGMII, RMII */
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 9c5bc6b..677432b 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -8,6 +8,8 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/bitops.h>
+#include <linux/sched.h>
 
 #ifdef CONFIG_FUNCTION_TRACER
 
@@ -24,6 +26,45 @@
 	struct ftrace_ops *next;
 };
 
+extern int function_trace_stop;
+
+/*
+ * Type of the current tracing.
+ */
+enum ftrace_tracing_type_t {
+	FTRACE_TYPE_ENTER = 0, /* Hook the call of the function */
+	FTRACE_TYPE_RETURN,	/* Hook the return of the function */
+};
+
+/* Current tracing type, default is FTRACE_TYPE_ENTER */
+extern enum ftrace_tracing_type_t ftrace_tracing_type;
+
+/**
+ * ftrace_stop - stop function tracer.
+ *
+ * A quick way to stop the function tracer. Note this an on off switch,
+ * it is not something that is recursive like preempt_disable.
+ * This does not disable the calling of mcount, it only stops the
+ * calling of functions from mcount.
+ */
+static inline void ftrace_stop(void)
+{
+	function_trace_stop = 1;
+}
+
+/**
+ * ftrace_start - start the function tracer.
+ *
+ * This function is the inverse of ftrace_stop. This does not enable
+ * the function tracing if the function tracer is disabled. This only
+ * sets the function tracer flag to continue calling the functions
+ * from mcount.
+ */
+static inline void ftrace_start(void)
+{
+	function_trace_stop = 0;
+}
+
 /*
  * The ftrace_ops must be a static and should also
  * be read_mostly.  These functions do modify read_mostly variables
@@ -42,9 +83,21 @@
 # define unregister_ftrace_function(ops) do { } while (0)
 # define clear_ftrace_function(ops) do { } while (0)
 static inline void ftrace_kill(void) { }
+static inline void ftrace_stop(void) { }
+static inline void ftrace_start(void) { }
 #endif /* CONFIG_FUNCTION_TRACER */
 
+#ifdef CONFIG_STACK_TRACER
+extern int stack_tracer_enabled;
+int
+stack_trace_sysctl(struct ctl_table *table, int write,
+		   struct file *file, void __user *buffer, size_t *lenp,
+		   loff_t *ppos);
+#endif
+
 #ifdef CONFIG_DYNAMIC_FTRACE
+/* asm/ftrace.h must be defined for archs supporting dynamic ftrace */
+#include <asm/ftrace.h>
 
 enum {
 	FTRACE_FL_FREE		= (1 << 0),
@@ -60,6 +113,7 @@
 	struct list_head	list;
 	unsigned long		ip; /* address of mcount call-site */
 	unsigned long		flags;
+	struct dyn_arch_ftrace	arch;
 };
 
 int ftrace_force_update(void);
@@ -67,19 +121,25 @@
 
 /* defined in arch */
 extern int ftrace_ip_converted(unsigned long ip);
-extern unsigned char *ftrace_nop_replace(void);
-extern unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr);
 extern int ftrace_dyn_arch_init(void *data);
 extern int ftrace_update_ftrace_func(ftrace_func_t func);
 extern void ftrace_caller(void);
 extern void ftrace_call(void);
 extern void mcount_call(void);
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+extern void ftrace_graph_caller(void);
+extern int ftrace_enable_ftrace_graph_caller(void);
+extern int ftrace_disable_ftrace_graph_caller(void);
+#else
+static inline int ftrace_enable_ftrace_graph_caller(void) { return 0; }
+static inline int ftrace_disable_ftrace_graph_caller(void) { return 0; }
+#endif
 
 /**
- * ftrace_modify_code - modify code segment
- * @ip: the address of the code segment
- * @old_code: the contents of what is expected to be there
- * @new_code: the code to patch in
+ * ftrace_make_nop - convert code into top
+ * @mod: module structure if called by module load initialization
+ * @rec: the mcount call site record
+ * @addr: the address that the call site should be calling
  *
  * This is a very sensitive operation and great care needs
  * to be taken by the arch.  The operation should carefully
@@ -87,6 +147,8 @@
  * what we expect it to be, and then on success of the compare,
  * it should write to the location.
  *
+ * The code segment at @rec->ip should be a caller to @addr
+ *
  * Return must be:
  *  0 on success
  *  -EFAULT on error reading the location
@@ -94,8 +156,34 @@
  *  -EPERM  on error writing to the location
  * Any other value will be considered a failure.
  */
-extern int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
-			      unsigned char *new_code);
+extern int ftrace_make_nop(struct module *mod,
+			   struct dyn_ftrace *rec, unsigned long addr);
+
+/**
+ * ftrace_make_call - convert a nop call site into a call to addr
+ * @rec: the mcount call site record
+ * @addr: the address that the call site should call
+ *
+ * This is a very sensitive operation and great care needs
+ * to be taken by the arch.  The operation should carefully
+ * read the location, check to see if what is read is indeed
+ * what we expect it to be, and then on success of the compare,
+ * it should write to the location.
+ *
+ * The code segment at @rec->ip should be a nop
+ *
+ * Return must be:
+ *  0 on success
+ *  -EFAULT on error reading the location
+ *  -EINVAL on a failed compare of the contents
+ *  -EPERM  on error writing to the location
+ * Any other value will be considered a failure.
+ */
+extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
+
+
+/* May be defined in arch */
+extern int ftrace_arch_read_dyn_info(char *buf, int size);
 
 extern int skip_trace(unsigned long ip);
 
@@ -103,7 +191,6 @@
 
 extern void ftrace_disable_daemon(void);
 extern void ftrace_enable_daemon(void);
-
 #else
 # define skip_trace(ip)				({ 0; })
 # define ftrace_force_update()			({ 0; })
@@ -182,6 +269,12 @@
 #endif
 
 #ifdef CONFIG_TRACING
+extern int ftrace_dump_on_oops;
+
+extern void tracing_start(void);
+extern void tracing_stop(void);
+extern void ftrace_off_permanent(void);
+
 extern void
 ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3);
 
@@ -210,8 +303,11 @@
 static inline void
 ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { }
 static inline int
-ftrace_printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 0)));
+ftrace_printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
 
+static inline void tracing_start(void) { }
+static inline void tracing_stop(void) { }
+static inline void ftrace_off_permanent(void) { }
 static inline int
 ftrace_printk(const char *fmt, ...)
 {
@@ -222,33 +318,178 @@
 
 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
 extern void ftrace_init(void);
-extern void ftrace_init_module(unsigned long *start, unsigned long *end);
+extern void ftrace_init_module(struct module *mod,
+			       unsigned long *start, unsigned long *end);
 #else
 static inline void ftrace_init(void) { }
 static inline void
-ftrace_init_module(unsigned long *start, unsigned long *end) { }
+ftrace_init_module(struct module *mod,
+		   unsigned long *start, unsigned long *end) { }
 #endif
 
-
-struct boot_trace {
-	pid_t			caller;
-	char			func[KSYM_SYMBOL_LEN];
-	int			result;
-	unsigned long long	duration;		/* usecs */
-	ktime_t			calltime;
-	ktime_t			rettime;
+enum {
+	POWER_NONE = 0,
+	POWER_CSTATE = 1,
+	POWER_PSTATE = 2,
 };
 
-#ifdef CONFIG_BOOT_TRACER
-extern void trace_boot(struct boot_trace *it, initcall_t fn);
-extern void start_boot_trace(void);
-extern void stop_boot_trace(void);
+struct power_trace {
+#ifdef CONFIG_POWER_TRACER
+	ktime_t			stamp;
+	ktime_t			end;
+	int			type;
+	int			state;
+#endif
+};
+
+#ifdef CONFIG_POWER_TRACER
+extern void trace_power_start(struct power_trace *it, unsigned int type,
+					unsigned int state);
+extern void trace_power_mark(struct power_trace *it, unsigned int type,
+					unsigned int state);
+extern void trace_power_end(struct power_trace *it);
 #else
-static inline void trace_boot(struct boot_trace *it, initcall_t fn) { }
-static inline void start_boot_trace(void) { }
-static inline void stop_boot_trace(void) { }
+static inline void trace_power_start(struct power_trace *it, unsigned int type,
+					unsigned int state) { }
+static inline void trace_power_mark(struct power_trace *it, unsigned int type,
+					unsigned int state) { }
+static inline void trace_power_end(struct power_trace *it) { }
 #endif
 
 
+/*
+ * Structure that defines an entry function trace.
+ */
+struct ftrace_graph_ent {
+	unsigned long func; /* Current function */
+	int depth;
+};
+
+/*
+ * Structure that defines a return function trace.
+ */
+struct ftrace_graph_ret {
+	unsigned long func; /* Current function */
+	unsigned long long calltime;
+	unsigned long long rettime;
+	/* Number of functions that overran the depth limit for current task */
+	unsigned long overrun;
+	int depth;
+};
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+/*
+ * Sometimes we don't want to trace a function with the function
+ * graph tracer but we want them to keep traced by the usual function
+ * tracer if the function graph tracer is not configured.
+ */
+#define __notrace_funcgraph		notrace
+
+/*
+ * We want to which function is an entrypoint of a hardirq.
+ * That will help us to put a signal on output.
+ */
+#define __irq_entry		 __attribute__((__section__(".irqentry.text")))
+
+/* Limits of hardirq entrypoints */
+extern char __irqentry_text_start[];
+extern char __irqentry_text_end[];
+
+#define FTRACE_RETFUNC_DEPTH 50
+#define FTRACE_RETSTACK_ALLOC_SIZE 32
+/* Type of the callback handlers for tracing function graph*/
+typedef void (*trace_func_graph_ret_t)(struct ftrace_graph_ret *); /* return */
+typedef int (*trace_func_graph_ent_t)(struct ftrace_graph_ent *); /* entry */
+
+extern int register_ftrace_graph(trace_func_graph_ret_t retfunc,
+				trace_func_graph_ent_t entryfunc);
+
+extern void ftrace_graph_stop(void);
+
+/* The current handlers in use */
+extern trace_func_graph_ret_t ftrace_graph_return;
+extern trace_func_graph_ent_t ftrace_graph_entry;
+
+extern void unregister_ftrace_graph(void);
+
+extern void ftrace_graph_init_task(struct task_struct *t);
+extern void ftrace_graph_exit_task(struct task_struct *t);
+
+static inline int task_curr_ret_stack(struct task_struct *t)
+{
+	return t->curr_ret_stack;
+}
+
+static inline void pause_graph_tracing(void)
+{
+	atomic_inc(&current->tracing_graph_pause);
+}
+
+static inline void unpause_graph_tracing(void)
+{
+	atomic_dec(&current->tracing_graph_pause);
+}
+#else
+
+#define __notrace_funcgraph
+#define __irq_entry
+
+static inline void ftrace_graph_init_task(struct task_struct *t) { }
+static inline void ftrace_graph_exit_task(struct task_struct *t) { }
+
+static inline int task_curr_ret_stack(struct task_struct *tsk)
+{
+	return -1;
+}
+
+static inline void pause_graph_tracing(void) { }
+static inline void unpause_graph_tracing(void) { }
+#endif
+
+#ifdef CONFIG_TRACING
+#include <linux/sched.h>
+
+/* flags for current->trace */
+enum {
+	TSK_TRACE_FL_TRACE_BIT	= 0,
+	TSK_TRACE_FL_GRAPH_BIT	= 1,
+};
+enum {
+	TSK_TRACE_FL_TRACE	= 1 << TSK_TRACE_FL_TRACE_BIT,
+	TSK_TRACE_FL_GRAPH	= 1 << TSK_TRACE_FL_GRAPH_BIT,
+};
+
+static inline void set_tsk_trace_trace(struct task_struct *tsk)
+{
+	set_bit(TSK_TRACE_FL_TRACE_BIT, &tsk->trace);
+}
+
+static inline void clear_tsk_trace_trace(struct task_struct *tsk)
+{
+	clear_bit(TSK_TRACE_FL_TRACE_BIT, &tsk->trace);
+}
+
+static inline int test_tsk_trace_trace(struct task_struct *tsk)
+{
+	return tsk->trace & TSK_TRACE_FL_TRACE;
+}
+
+static inline void set_tsk_trace_graph(struct task_struct *tsk)
+{
+	set_bit(TSK_TRACE_FL_GRAPH_BIT, &tsk->trace);
+}
+
+static inline void clear_tsk_trace_graph(struct task_struct *tsk)
+{
+	clear_bit(TSK_TRACE_FL_GRAPH_BIT, &tsk->trace);
+}
+
+static inline int test_tsk_trace_graph(struct task_struct *tsk)
+{
+	return tsk->trace & TSK_TRACE_FL_GRAPH;
+}
+
+#endif /* CONFIG_TRACING */
 
 #endif /* _LINUX_FTRACE_H */
diff --git a/include/linux/ftrace_irq.h b/include/linux/ftrace_irq.h
new file mode 100644
index 0000000..366a054
--- /dev/null
+++ b/include/linux/ftrace_irq.h
@@ -0,0 +1,13 @@
+#ifndef _LINUX_FTRACE_IRQ_H
+#define _LINUX_FTRACE_IRQ_H
+
+
+#if defined(CONFIG_DYNAMIC_FTRACE) || defined(CONFIG_FUNCTION_GRAPH_TRACER)
+extern void ftrace_nmi_enter(void);
+extern void ftrace_nmi_exit(void);
+#else
+static inline void ftrace_nmi_enter(void) { }
+static inline void ftrace_nmi_exit(void) { }
+#endif
+
+#endif /* _LINUX_FTRACE_IRQ_H */
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 181006c..89a56d7 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -4,6 +4,7 @@
 #include <linux/preempt.h>
 #include <linux/smp_lock.h>
 #include <linux/lockdep.h>
+#include <linux/ftrace_irq.h>
 #include <asm/hardirq.h>
 #include <asm/system.h>
 
@@ -161,7 +162,17 @@
  */
 extern void irq_exit(void);
 
-#define nmi_enter()		do { lockdep_off(); __irq_enter(); } while (0)
-#define nmi_exit()		do { __irq_exit(); lockdep_on(); } while (0)
+#define nmi_enter()				\
+	do {					\
+		ftrace_nmi_enter();		\
+		lockdep_off();			\
+		__irq_enter();			\
+	} while (0)
+#define nmi_exit()				\
+	do {					\
+		__irq_exit();			\
+		lockdep_on();			\
+		ftrace_nmi_exit();		\
+	} while (0)
 
 #endif /* LINUX_HARDIRQ_H */
diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h
index c597696..fd47a15 100644
--- a/include/linux/hdlc.h
+++ b/include/linux/hdlc.h
@@ -43,7 +43,7 @@
 };
 
 
-/* Pointed to by dev->priv */
+/* Pointed to by netdev_priv(dev) */
 typedef struct hdlc_device {
 	/* used by HDLC layer to take control over HDLC device from hw driver*/
 	int (*attach)(struct net_device *dev,
@@ -80,7 +80,7 @@
 
 static inline struct hdlc_device* dev_to_hdlc(struct net_device *dev)
 {
-	return dev->priv;
+	return netdev_priv(dev);
 }
 
 static __inline__ void debug_frame(const struct sk_buff *skb)
diff --git a/include/linux/hippidevice.h b/include/linux/hippidevice.h
index bab303d..f148e49 100644
--- a/include/linux/hippidevice.h
+++ b/include/linux/hippidevice.h
@@ -32,7 +32,9 @@
 };
 
 extern __be16 hippi_type_trans(struct sk_buff *skb, struct net_device *dev);
-
+extern int hippi_change_mtu(struct net_device *dev, int new_mtu);
+extern int hippi_mac_addr(struct net_device *dev, void *p);
+extern int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p);
 extern struct net_device *alloc_hippi_dev(int sizeof_priv);
 #endif
 
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 14126bc..c4e6ca1 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -12,8 +12,8 @@
  * published by the Free Software Foundation.
  */
 
-#ifndef IEEE80211_H
-#define IEEE80211_H
+#ifndef LINUX_IEEE80211_H
+#define LINUX_IEEE80211_H
 
 #include <linux/types.h>
 #include <asm/byteorder.h>
@@ -97,7 +97,10 @@
 #define IEEE80211_MAX_FRAME_LEN		2352
 
 #define IEEE80211_MAX_SSID_LEN		32
+
 #define IEEE80211_MAX_MESH_ID_LEN	32
+#define IEEE80211_MESH_CONFIG_LEN	19
+
 #define IEEE80211_QOS_CTL_LEN		2
 #define IEEE80211_QOS_CTL_TID_MASK	0x000F
 #define IEEE80211_QOS_CTL_TAG1D_MASK	0x0007
@@ -666,6 +669,13 @@
 	u8 ra[6];
 } __attribute__ ((packed));
 
+struct ieee80211_pspoll {
+	__le16 frame_control;
+	__le16 aid;
+	u8 bssid[6];
+	u8 ta[6];
+} __attribute__ ((packed));
+
 /**
  * struct ieee80211_bar - HT Block Ack Request
  *
@@ -685,28 +695,88 @@
 #define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL     0x0000
 #define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA  0x0004
 
+
+#define IEEE80211_HT_MCS_MASK_LEN		10
+
+/**
+ * struct ieee80211_mcs_info - MCS information
+ * @rx_mask: RX mask
+ * @rx_highest: highest supported RX rate
+ * @tx_params: TX parameters
+ */
+struct ieee80211_mcs_info {
+	u8 rx_mask[IEEE80211_HT_MCS_MASK_LEN];
+	__le16 rx_highest;
+	u8 tx_params;
+	u8 reserved[3];
+} __attribute__((packed));
+
+/* 802.11n HT capability MSC set */
+#define IEEE80211_HT_MCS_RX_HIGHEST_MASK	0x3ff
+#define IEEE80211_HT_MCS_TX_DEFINED		0x01
+#define IEEE80211_HT_MCS_TX_RX_DIFF		0x02
+/* value 0 == 1 stream etc */
+#define IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK	0x0C
+#define IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT	2
+#define		IEEE80211_HT_MCS_TX_MAX_STREAMS	4
+#define IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION	0x10
+
+/*
+ * 802.11n D5.0 20.3.5 / 20.6 says:
+ * - indices 0 to 7 and 32 are single spatial stream
+ * - 8 to 31 are multiple spatial streams using equal modulation
+ *   [8..15 for two streams, 16..23 for three and 24..31 for four]
+ * - remainder are multiple spatial streams using unequal modulation
+ */
+#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START 33
+#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE \
+	(IEEE80211_HT_MCS_UNEQUAL_MODULATION_START / 8)
+
 /**
  * struct ieee80211_ht_cap - HT capabilities
  *
- * This structure refers to "HT capabilities element" as
- * described in 802.11n draft section 7.3.2.52
+ * This structure is the "HT capabilities element" as
+ * described in 802.11n D5.0 7.3.2.57
  */
 struct ieee80211_ht_cap {
 	__le16 cap_info;
 	u8 ampdu_params_info;
-	u8 supp_mcs_set[16];
+
+	/* 16 bytes MCS information */
+	struct ieee80211_mcs_info mcs;
+
 	__le16 extended_ht_cap_info;
 	__le32 tx_BF_cap_info;
 	u8 antenna_selection_info;
 } __attribute__ ((packed));
 
+/* 802.11n HT capabilities masks (for cap_info) */
+#define IEEE80211_HT_CAP_LDPC_CODING		0x0001
+#define IEEE80211_HT_CAP_SUP_WIDTH_20_40	0x0002
+#define IEEE80211_HT_CAP_SM_PS			0x000C
+#define IEEE80211_HT_CAP_GRN_FLD		0x0010
+#define IEEE80211_HT_CAP_SGI_20			0x0020
+#define IEEE80211_HT_CAP_SGI_40			0x0040
+#define IEEE80211_HT_CAP_TX_STBC		0x0080
+#define IEEE80211_HT_CAP_RX_STBC		0x0300
+#define IEEE80211_HT_CAP_DELAY_BA		0x0400
+#define IEEE80211_HT_CAP_MAX_AMSDU		0x0800
+#define IEEE80211_HT_CAP_DSSSCCK40		0x1000
+#define IEEE80211_HT_CAP_PSMP_SUPPORT		0x2000
+#define IEEE80211_HT_CAP_40MHZ_INTOLERANT	0x4000
+#define IEEE80211_HT_CAP_LSIG_TXOP_PROT		0x8000
+
+/* 802.11n HT capability AMPDU settings (for ampdu_params_info) */
+#define IEEE80211_HT_AMPDU_PARM_FACTOR		0x03
+#define IEEE80211_HT_AMPDU_PARM_DENSITY		0x1C
+
 /**
- * struct ieee80211_ht_cap - HT additional information
+ * struct ieee80211_ht_info - HT information
  *
- * This structure refers to "HT information element" as
- * described in 802.11n draft section 7.3.2.53
+ * This structure is the "HT information element" as
+ * described in 802.11n D5.0 7.3.2.58
  */
-struct ieee80211_ht_addt_info {
+struct ieee80211_ht_info {
 	u8 control_chan;
 	u8 ht_param;
 	__le16 operation_mode;
@@ -714,36 +784,33 @@
 	u8 basic_set[16];
 } __attribute__ ((packed));
 
-/* 802.11n HT capabilities masks */
-#define IEEE80211_HT_CAP_SUP_WIDTH		0x0002
-#define IEEE80211_HT_CAP_SM_PS			0x000C
-#define IEEE80211_HT_CAP_GRN_FLD		0x0010
-#define IEEE80211_HT_CAP_SGI_20			0x0020
-#define IEEE80211_HT_CAP_SGI_40			0x0040
-#define IEEE80211_HT_CAP_DELAY_BA		0x0400
-#define IEEE80211_HT_CAP_MAX_AMSDU		0x0800
-#define IEEE80211_HT_CAP_DSSSCCK40		0x1000
-/* 802.11n HT capability AMPDU settings */
-#define IEEE80211_HT_CAP_AMPDU_FACTOR		0x03
-#define IEEE80211_HT_CAP_AMPDU_DENSITY		0x1C
-/* 802.11n HT capability MSC set */
-#define IEEE80211_SUPP_MCS_SET_UEQM		4
-#define IEEE80211_HT_CAP_MAX_STREAMS		4
-#define IEEE80211_SUPP_MCS_SET_LEN		10
-/* maximum streams the spec allows */
-#define IEEE80211_HT_CAP_MCS_TX_DEFINED		0x01
-#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF		0x02
-#define IEEE80211_HT_CAP_MCS_TX_STREAMS		0x0C
-#define IEEE80211_HT_CAP_MCS_TX_UEQM		0x10
-/* 802.11n HT IE masks */
-#define IEEE80211_HT_IE_CHA_SEC_OFFSET		0x03
-#define IEEE80211_HT_IE_CHA_SEC_NONE	 	0x00
-#define IEEE80211_HT_IE_CHA_SEC_ABOVE 		0x01
-#define IEEE80211_HT_IE_CHA_SEC_BELOW 		0x03
-#define IEEE80211_HT_IE_CHA_WIDTH		0x04
-#define IEEE80211_HT_IE_HT_PROTECTION		0x0003
-#define IEEE80211_HT_IE_NON_GF_STA_PRSNT	0x0004
-#define IEEE80211_HT_IE_NON_HT_STA_PRSNT	0x0010
+/* for ht_param */
+#define IEEE80211_HT_PARAM_CHA_SEC_OFFSET		0x03
+#define		IEEE80211_HT_PARAM_CHA_SEC_NONE		0x00
+#define		IEEE80211_HT_PARAM_CHA_SEC_ABOVE	0x01
+#define		IEEE80211_HT_PARAM_CHA_SEC_BELOW	0x03
+#define IEEE80211_HT_PARAM_CHAN_WIDTH_ANY		0x04
+#define IEEE80211_HT_PARAM_RIFS_MODE			0x08
+#define IEEE80211_HT_PARAM_SPSMP_SUPPORT		0x10
+#define IEEE80211_HT_PARAM_SERV_INTERVAL_GRAN		0xE0
+
+/* for operation_mode */
+#define IEEE80211_HT_OP_MODE_PROTECTION			0x0003
+#define		IEEE80211_HT_OP_MODE_PROTECTION_NONE		0
+#define		IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER	1
+#define		IEEE80211_HT_OP_MODE_PROTECTION_20MHZ		2
+#define		IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED	3
+#define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT		0x0004
+#define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT		0x0010
+
+/* for stbc_param */
+#define IEEE80211_HT_STBC_PARAM_DUAL_BEACON		0x0040
+#define IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT		0x0080
+#define IEEE80211_HT_STBC_PARAM_STBC_BEACON		0x0100
+#define IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT	0x0200
+#define IEEE80211_HT_STBC_PARAM_PCO_ACTIVE		0x0400
+#define IEEE80211_HT_STBC_PARAM_PCO_PHASE		0x0800
+
 
 /* block-ack parameters */
 #define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
@@ -769,7 +836,6 @@
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
 #define WLAN_AUTH_SHARED_KEY 1
-#define WLAN_AUTH_FAST_BSS_TRANSITION 2
 #define WLAN_AUTH_LEAP 128
 
 #define WLAN_AUTH_CHALLENGE_LEN 128
@@ -949,7 +1015,7 @@
 	WLAN_EID_EXT_SUPP_RATES = 50,
 	/* 802.11n */
 	WLAN_EID_HT_CAPABILITY = 45,
-	WLAN_EID_HT_EXTRA_INFO = 61,
+	WLAN_EID_HT_INFORMATION = 61,
 	/* 802.11i */
 	WLAN_EID_RSN = 48,
 	WLAN_EID_WPA = 221,
@@ -976,6 +1042,68 @@
 	WLAN_ACTION_SPCT_CHL_SWITCH = 4,
 };
 
+/*
+ * IEEE 802.11-2007 7.3.2.9 Country information element
+ *
+ * Minimum length is 8 octets, ie len must be evenly
+ * divisible by 2
+ */
+
+/* Although the spec says 8 I'm seeing 6 in practice */
+#define IEEE80211_COUNTRY_IE_MIN_LEN	6
+
+/*
+ * For regulatory extension stuff see IEEE 802.11-2007
+ * Annex I (page 1141) and Annex J (page 1147). Also
+ * review 7.3.2.9.
+ *
+ * When dot11RegulatoryClassesRequired is true and the
+ * first_channel/reg_extension_id is >= 201 then the IE
+ * compromises of the 'ext' struct represented below:
+ *
+ *  - Regulatory extension ID - when generating IE this just needs
+ *    to be monotonically increasing for each triplet passed in
+ *    the IE
+ *  - Regulatory class - index into set of rules
+ *  - Coverage class - index into air propagation time (Table 7-27),
+ *    in microseconds, you can compute the air propagation time from
+ *    the index by multiplying by 3, so index 10 yields a propagation
+ *    of 10 us. Valid values are 0-31, values 32-255 are not defined
+ *    yet. A value of 0 inicates air propagation of <= 1 us.
+ *
+ *  See also Table I.2 for Emission limit sets and table
+ *  I.3 for Behavior limit sets. Table J.1 indicates how to map
+ *  a reg_class to an emission limit set and behavior limit set.
+ */
+#define IEEE80211_COUNTRY_EXTENSION_ID 201
+
+/*
+ *  Channels numbers in the IE must be monotonically increasing
+ *  if dot11RegulatoryClassesRequired is not true.
+ *
+ *  If dot11RegulatoryClassesRequired is true consecutive
+ *  subband triplets following a regulatory triplet shall
+ *  have monotonically increasing first_channel number fields.
+ *
+ *  Channel numbers shall not overlap.
+ *
+ *  Note that max_power is signed.
+ */
+struct ieee80211_country_ie_triplet {
+	union {
+		struct {
+			u8 first_channel;
+			u8 num_channels;
+			s8 max_power;
+		} __attribute__ ((packed)) chans;
+		struct {
+			u8 reg_extension_id;
+			u8 reg_class;
+			u8 coverage_class;
+		} __attribute__ ((packed)) ext;
+	};
+} __attribute__ ((packed));
+
 /* BACK action code */
 enum ieee80211_back_actioncode {
 	WLAN_ACTION_ADDBA_REQ = 0,
@@ -1057,4 +1185,4 @@
 		return hdr->addr1;
 }
 
-#endif /* IEEE80211_H */
+#endif /* LINUX_IEEE80211_H */
diff --git a/include/linux/if.h b/include/linux/if.h
index 6524684..2a6e296 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -65,6 +65,7 @@
 #define IFF_BONDING	0x20		/* bonding master or slave	*/
 #define IFF_SLAVE_NEEDARP 0x40		/* need ARPs for validation	*/
 #define IFF_ISATAP	0x80		/* ISATAP interface (RFC4214)	*/
+#define IFF_MASTER_ARPMON 0x100		/* bonding master, ARP mon in use */
 
 #define IF_GET_IFACE	0x0001		/* for querying only */
 #define IF_GET_PROTO	0x0002
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index 4d34018..5ff8980 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -87,6 +87,9 @@
 #define ARPHRD_IEEE80211_PRISM 802	/* IEEE 802.11 + Prism2 header  */
 #define ARPHRD_IEEE80211_RADIOTAP 803	/* IEEE 802.11 + radiotap header */
 
+#define ARPHRD_PHONET	820		/* PhoNet media type		*/
+#define ARPHRD_PHONET_PIPE 821		/* PhoNet pipe header		*/
+
 #define ARPHRD_VOID	  0xFFFF	/* Void type, nothing is known */
 #define ARPHRD_NONE	  0xFFFE	/* zero header length */
 
diff --git a/include/linux/in.h b/include/linux/in.h
index db458be..d60122a 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -80,6 +80,10 @@
 /* BSD compatibility */
 #define IP_RECVRETOPTS	IP_RETOPTS
 
+/* TProxy original addresses */
+#define IP_ORIGDSTADDR       20
+#define IP_RECVORIGDSTADDR   IP_ORIGDSTADDR
+
 /* IP_MTU_DISCOVER values */
 #define IP_PMTUDISC_DONT		0	/* Never send DF frames */
 #define IP_PMTUDISC_WANT		1	/* Use per route hints	*/
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 23fd890..959f552 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -57,7 +57,6 @@
 	.mnt_ns		= NULL,						\
 	INIT_NET_NS(net_ns)                                             \
 	INIT_IPC_NS(ipc_ns)						\
-	.user_ns	= &init_user_ns,				\
 }
 
 #define INIT_SIGHAND(sighand) {						\
@@ -113,6 +112,8 @@
 # define CAP_INIT_BSET  CAP_INIT_EFF_SET
 #endif
 
+extern struct cred init_cred;
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -147,13 +148,10 @@
 	.children	= LIST_HEAD_INIT(tsk.children),			\
 	.sibling	= LIST_HEAD_INIT(tsk.sibling),			\
 	.group_leader	= &tsk,						\
-	.group_info	= &init_groups,					\
-	.cap_effective	= CAP_INIT_EFF_SET,				\
-	.cap_inheritable = CAP_INIT_INH_SET,				\
-	.cap_permitted	= CAP_FULL_SET,					\
-	.cap_bset 	= CAP_INIT_BSET,				\
-	.securebits     = SECUREBITS_DEFAULT,				\
-	.user		= INIT_USER,					\
+	.real_cred	= &init_cred,					\
+	.cred		= &init_cred,					\
+	.cred_exec_mutex =						\
+		 __MUTEX_INITIALIZER(tsk.cred_exec_mutex),		\
 	.comm		= "swapper",					\
 	.thread		= INIT_THREAD,					\
 	.fs		= &init_fs,					\
diff --git a/include/linux/input.h b/include/linux/input.h
index 5341e82..9a6355f 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -659,6 +659,8 @@
 #define SW_RADIO		SW_RFKILL_ALL	/* deprecated */
 #define SW_MICROPHONE_INSERT	0x04  /* set = inserted */
 #define SW_DOCK			0x05  /* set = plugged into dock */
+#define SW_LINEOUT_INSERT	0x06  /* set = inserted */
+#define SW_JACK_PHYSICAL_INSERT 0x07  /* set = mechanical switch set */
 #define SW_MAX			0x0f
 #define SW_CNT			(SW_MAX+1)
 
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 641e026..0b816cae 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -278,6 +278,7 @@
 	struct in6_addr 	saddr;
 	struct in6_addr 	rcv_saddr;
 	struct in6_addr		daddr;
+	struct in6_pktinfo	sticky_pktinfo;
 	struct in6_addr		*daddr_cache;
 #ifdef CONFIG_IPV6_SUBTREES
 	struct in6_addr		*saddr_cache;
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index dc7e0d0..6002ae7 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -361,18 +361,6 @@
 	((unsigned char *)&addr)[3]
 #define NIPQUAD_FMT "%u.%u.%u.%u"
 
-#define NIP6(addr) \
-	ntohs((addr).s6_addr16[0]), \
-	ntohs((addr).s6_addr16[1]), \
-	ntohs((addr).s6_addr16[2]), \
-	ntohs((addr).s6_addr16[3]), \
-	ntohs((addr).s6_addr16[4]), \
-	ntohs((addr).s6_addr16[5]), \
-	ntohs((addr).s6_addr16[6]), \
-	ntohs((addr).s6_addr16[7])
-#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-#define NIP6_SEQFMT "%04x%04x%04x%04x%04x%04x%04x%04x"
-
 #if defined(__LITTLE_ENDIAN)
 #define HIPQUAD(addr) \
 	((unsigned char *)&addr)[3], \
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 17f76fc..adc34f2 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -100,6 +100,10 @@
 #define KEXEC_TYPE_DEFAULT 0
 #define KEXEC_TYPE_CRASH   1
 	unsigned int preserve_context : 1;
+
+#ifdef ARCH_HAS_KIMAGE_ARCH
+	struct kimage_arch arch;
+#endif
 };
 
 
diff --git a/include/linux/key-ui.h b/include/linux/key-ui.h
deleted file mode 100644
index e8b8a7a..0000000
--- a/include/linux/key-ui.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* key-ui.h: key userspace interface stuff
- *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_KEY_UI_H
-#define _LINUX_KEY_UI_H
-
-#include <linux/key.h>
-
-/* the key tree */
-extern struct rb_root key_serial_tree;
-extern spinlock_t key_serial_lock;
-
-/* required permissions */
-#define	KEY_VIEW	0x01	/* require permission to view attributes */
-#define	KEY_READ	0x02	/* require permission to read content */
-#define	KEY_WRITE	0x04	/* require permission to update / modify */
-#define	KEY_SEARCH	0x08	/* require permission to search (keyring) or find (key) */
-#define	KEY_LINK	0x10	/* require permission to link */
-#define	KEY_SETATTR	0x20	/* require permission to change attributes */
-#define	KEY_ALL		0x3f	/* all the above permissions */
-
-/*
- * the keyring payload contains a list of the keys to which the keyring is
- * subscribed
- */
-struct keyring_list {
-	struct rcu_head	rcu;		/* RCU deletion hook */
-	unsigned short	maxkeys;	/* max keys this list can hold */
-	unsigned short	nkeys;		/* number of keys currently held */
-	unsigned short	delkey;		/* key to be unlinked by RCU */
-	struct key	*keys[0];
-};
-
-/*
- * check to see whether permission is granted to use a key in the desired way
- */
-extern int key_task_permission(const key_ref_t key_ref,
-			       struct task_struct *context,
-			       key_perm_t perm);
-
-static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
-{
-	return key_task_permission(key_ref, current, perm);
-}
-
-extern key_ref_t lookup_user_key(struct task_struct *context,
-				 key_serial_t id, int create, int partial,
-				 key_perm_t perm);
-
-extern long join_session_keyring(const char *name);
-
-extern struct key_type *key_type_lookup(const char *type);
-extern void key_type_put(struct key_type *ktype);
-
-#define key_negative_timeout	60	/* default timeout on a negative key's existence */
-
-
-#endif /* _LINUX_KEY_UI_H */
diff --git a/include/linux/key.h b/include/linux/key.h
index 1b70e35..21d32a1 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -73,6 +73,7 @@
 struct seq_file;
 struct user_struct;
 struct signal_struct;
+struct cred;
 
 struct key_type;
 struct key_owner;
@@ -181,7 +182,7 @@
 extern struct key *key_alloc(struct key_type *type,
 			     const char *desc,
 			     uid_t uid, gid_t gid,
-			     struct task_struct *ctx,
+			     const struct cred *cred,
 			     key_perm_t perm,
 			     unsigned long flags);
 
@@ -249,7 +250,7 @@
 		      struct key *key);
 
 extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
-				 struct task_struct *ctx,
+				 const struct cred *cred,
 				 unsigned long flags,
 				 struct key *dest);
 
@@ -276,24 +277,11 @@
 /*
  * the userspace interface
  */
-extern void switch_uid_keyring(struct user_struct *new_user);
-extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
-extern int copy_thread_group_keys(struct task_struct *tsk);
-extern void exit_keys(struct task_struct *tsk);
-extern void exit_thread_group_keys(struct signal_struct *tg);
-extern int suid_keys(struct task_struct *tsk);
-extern int exec_keys(struct task_struct *tsk);
+extern int install_thread_keyring_to_cred(struct cred *cred);
 extern void key_fsuid_changed(struct task_struct *tsk);
 extern void key_fsgid_changed(struct task_struct *tsk);
 extern void key_init(void);
 
-#define __install_session_keyring(tsk, keyring)			\
-({								\
-	struct key *old_session = tsk->signal->session_keyring;	\
-	tsk->signal->session_keyring = keyring;			\
-	old_session;						\
-})
-
 #else /* CONFIG_KEYS */
 
 #define key_validate(k)			0
@@ -302,17 +290,9 @@
 #define key_revoke(k)			do { } while(0)
 #define key_put(k)			do { } while(0)
 #define key_ref_put(k)			do { } while(0)
-#define make_key_ref(k, p)			({ NULL; })
-#define key_ref_to_ptr(k)		({ NULL; })
+#define make_key_ref(k, p)		NULL
+#define key_ref_to_ptr(k)		NULL
 #define is_key_possessed(k)		0
-#define switch_uid_keyring(u)		do { } while(0)
-#define __install_session_keyring(t, k)	({ NULL; })
-#define copy_keys(f,t)			0
-#define copy_thread_group_keys(t)	0
-#define exit_keys(t)			do { } while(0)
-#define exit_thread_group_keys(tg)	do { } while(0)
-#define suid_keys(t)			do { } while(0)
-#define exec_keys(t)			do { } while(0)
 #define key_fsuid_changed(t)		do { } while(0)
 #define key_fsgid_changed(t)		do { } while(0)
 #define key_init()			do { } while(0)
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h
index 656ee6b..c0688eb 100644
--- a/include/linux/keyctl.h
+++ b/include/linux/keyctl.h
@@ -1,6 +1,6 @@
 /* keyctl.h: keyctl command IDs
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004, 2008 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -20,6 +20,7 @@
 #define KEY_SPEC_USER_SESSION_KEYRING	-5	/* - key ID for UID-session keyring */
 #define KEY_SPEC_GROUP_KEYRING		-6	/* - key ID for GID-specific keyring */
 #define KEY_SPEC_REQKEY_AUTH_KEY	-7	/* - key ID for assumed request_key auth key */
+#define KEY_SPEC_REQUESTOR_KEYRING	-8	/* - key ID for request_key() dest keyring */
 
 /* request-key default keyrings */
 #define KEY_REQKEY_DEFL_NO_CHANGE		-1
@@ -30,6 +31,7 @@
 #define KEY_REQKEY_DEFL_USER_KEYRING		4
 #define KEY_REQKEY_DEFL_USER_SESSION_KEYRING	5
 #define KEY_REQKEY_DEFL_GROUP_KEYRING		6
+#define KEY_REQKEY_DEFL_REQUESTOR_KEYRING	7
 
 /* keyctl commands */
 #define KEYCTL_GET_KEYRING_ID		0	/* ask for a keyring's ID */
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 9fd1f85..fee9e59 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -64,14 +64,6 @@
 	name:
 #endif
 
-#define KPROBE_ENTRY(name) \
-  .pushsection .kprobes.text, "ax"; \
-  ENTRY(name)
-
-#define KPROBE_END(name) \
-  END(name);		 \
-  .popsection
-
 #ifndef END
 #define END(name) \
   .size name, .-name
diff --git a/include/linux/list_nulls.h b/include/linux/list_nulls.h
new file mode 100644
index 0000000..93150ec
--- /dev/null
+++ b/include/linux/list_nulls.h
@@ -0,0 +1,94 @@
+#ifndef _LINUX_LIST_NULLS_H
+#define _LINUX_LIST_NULLS_H
+
+/*
+ * Special version of lists, where end of list is not a NULL pointer,
+ * but a 'nulls' marker, which can have many different values.
+ * (up to 2^31 different values guaranteed on all platforms)
+ *
+ * In the standard hlist, termination of a list is the NULL pointer.
+ * In this special 'nulls' variant, we use the fact that objects stored in
+ * a list are aligned on a word (4 or 8 bytes alignment).
+ * We therefore use the last significant bit of 'ptr' :
+ * Set to 1 : This is a 'nulls' end-of-list marker (ptr >> 1)
+ * Set to 0 : This is a pointer to some object (ptr)
+ */
+
+struct hlist_nulls_head {
+	struct hlist_nulls_node *first;
+};
+
+struct hlist_nulls_node {
+	struct hlist_nulls_node *next, **pprev;
+};
+#define INIT_HLIST_NULLS_HEAD(ptr, nulls) \
+	((ptr)->first = (struct hlist_nulls_node *) (1UL | (((long)nulls) << 1)))
+
+#define hlist_nulls_entry(ptr, type, member) container_of(ptr,type,member)
+/**
+ * ptr_is_a_nulls - Test if a ptr is a nulls
+ * @ptr: ptr to be tested
+ *
+ */
+static inline int is_a_nulls(const struct hlist_nulls_node *ptr)
+{
+	return ((unsigned long)ptr & 1);
+}
+
+/**
+ * get_nulls_value - Get the 'nulls' value of the end of chain
+ * @ptr: end of chain
+ *
+ * Should be called only if is_a_nulls(ptr);
+ */
+static inline unsigned long get_nulls_value(const struct hlist_nulls_node *ptr)
+{
+	return ((unsigned long)ptr) >> 1;
+}
+
+static inline int hlist_nulls_unhashed(const struct hlist_nulls_node *h)
+{
+	return !h->pprev;
+}
+
+static inline int hlist_nulls_empty(const struct hlist_nulls_head *h)
+{
+	return is_a_nulls(h->first);
+}
+
+static inline void __hlist_nulls_del(struct hlist_nulls_node *n)
+{
+	struct hlist_nulls_node *next = n->next;
+	struct hlist_nulls_node **pprev = n->pprev;
+	*pprev = next;
+	if (!is_a_nulls(next))
+		next->pprev = pprev;
+}
+
+/**
+ * hlist_nulls_for_each_entry	- iterate over list of given type
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the hlist_node within the struct.
+ *
+ */
+#define hlist_nulls_for_each_entry(tpos, pos, head, member)		       \
+	for (pos = (head)->first;					       \
+	     (!is_a_nulls(pos)) &&					       \
+		({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = pos->next)
+
+/**
+ * hlist_nulls_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @member:	the name of the hlist_node within the struct.
+ *
+ */
+#define hlist_nulls_for_each_entry_from(tpos, pos, member)	\
+	for (; (!is_a_nulls(pos)) && 				\
+		({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = pos->next)
+
+#endif
diff --git a/include/linux/marker.h b/include/linux/marker.h
index 889196c..b85e74c 100644
--- a/include/linux/marker.h
+++ b/include/linux/marker.h
@@ -12,6 +12,7 @@
  * See the file COPYING for more details.
  */
 
+#include <stdarg.h>
 #include <linux/types.h>
 
 struct module;
@@ -48,10 +49,28 @@
 	void (*call)(const struct marker *mdata, void *call_private, ...);
 	struct marker_probe_closure single;
 	struct marker_probe_closure *multi;
+	const char *tp_name;	/* Optional tracepoint name */
+	void *tp_cb;		/* Optional tracepoint callback */
 } __attribute__((aligned(8)));
 
 #ifdef CONFIG_MARKERS
 
+#define _DEFINE_MARKER(name, tp_name_str, tp_cb, format)		\
+		static const char __mstrtab_##name[]			\
+		__attribute__((section("__markers_strings")))		\
+		= #name "\0" format;					\
+		static struct marker __mark_##name			\
+		__attribute__((section("__markers"), aligned(8))) =	\
+		{ __mstrtab_##name, &__mstrtab_##name[sizeof(#name)],	\
+		  0, 0, marker_probe_cb, { __mark_empty_function, NULL},\
+		  NULL, tp_name_str, tp_cb }
+
+#define DEFINE_MARKER(name, format)					\
+		_DEFINE_MARKER(name, NULL, NULL, format)
+
+#define DEFINE_MARKER_TP(name, tp_name, tp_cb, format)			\
+		_DEFINE_MARKER(name, #tp_name, tp_cb, format)
+
 /*
  * Note : the empty asm volatile with read constraint is used here instead of a
  * "used" attribute to fix a gcc 4.1.x bug.
@@ -65,14 +84,7 @@
  */
 #define __trace_mark(generic, name, call_private, format, args...)	\
 	do {								\
-		static const char __mstrtab_##name[]			\
-		__attribute__((section("__markers_strings")))		\
-		= #name "\0" format;					\
-		static struct marker __mark_##name			\
-		__attribute__((section("__markers"), aligned(8))) =	\
-		{ __mstrtab_##name, &__mstrtab_##name[sizeof(#name)],	\
-		0, 0, marker_probe_cb,					\
-		{ __mark_empty_function, NULL}, NULL };			\
+		DEFINE_MARKER(name, format);				\
 		__mark_check_format(format, ## args);			\
 		if (unlikely(__mark_##name.state)) {			\
 			(*__mark_##name.call)				\
@@ -80,14 +92,39 @@
 		}							\
 	} while (0)
 
+#define __trace_mark_tp(name, call_private, tp_name, tp_cb, format, args...) \
+	do {								\
+		void __check_tp_type(void)				\
+		{							\
+			register_trace_##tp_name(tp_cb);		\
+		}							\
+		DEFINE_MARKER_TP(name, tp_name, tp_cb, format);		\
+		__mark_check_format(format, ## args);			\
+		(*__mark_##name.call)(&__mark_##name, call_private,	\
+					## args);			\
+	} while (0)
+
 extern void marker_update_probe_range(struct marker *begin,
 	struct marker *end);
+
+#define GET_MARKER(name)	(__mark_##name)
+
 #else /* !CONFIG_MARKERS */
+#define DEFINE_MARKER(name, tp_name, tp_cb, format)
 #define __trace_mark(generic, name, call_private, format, args...) \
 		__mark_check_format(format, ## args)
+#define __trace_mark_tp(name, call_private, tp_name, tp_cb, format, args...) \
+	do {								\
+		void __check_tp_type(void)				\
+		{							\
+			register_trace_##tp_name(tp_cb);		\
+		}							\
+		__mark_check_format(format, ## args);			\
+	} while (0)
 static inline void marker_update_probe_range(struct marker *begin,
 	struct marker *end)
 { }
+#define GET_MARKER(name)
 #endif /* CONFIG_MARKERS */
 
 /**
@@ -117,6 +154,20 @@
 	__trace_mark(1, name, NULL, format, ## args)
 
 /**
+ * trace_mark_tp - Marker in a tracepoint callback
+ * @name: marker name, not quoted.
+ * @tp_name: tracepoint name, not quoted.
+ * @tp_cb: tracepoint callback. Should have an associated global symbol so it
+ *         is not optimized away by the compiler (should not be static).
+ * @format: format string
+ * @args...: variable argument list
+ *
+ * Places a marker in a tracepoint callback.
+ */
+#define trace_mark_tp(name, tp_name, tp_cb, format, args...)	\
+	__trace_mark_tp(name, NULL, tp_name, tp_cb, format, ## args)
+
+/**
  * MARK_NOARGS - Format string for a marker with no argument.
  */
 #define MARK_NOARGS " "
@@ -136,8 +187,6 @@
 
 extern void marker_probe_cb(const struct marker *mdata,
 	void *call_private, ...);
-extern void marker_probe_cb_noarg(const struct marker *mdata,
-	void *call_private, ...);
 
 /*
  * Connect a probe to a marker.
@@ -162,8 +211,10 @@
 
 /*
  * marker_synchronize_unregister must be called between the last marker probe
- * unregistration and the end of module exit to make sure there is no caller
- * executing a probe when it is freed.
+ * unregistration and the first one of
+ * - the end of module exit function
+ * - the free of any resource used by the probes
+ * to ensure the code and data are valid for any possibly running probes.
  */
 #define marker_synchronize_unregister() synchronize_sched()
 
diff --git a/include/linux/mdio-gpio.h b/include/linux/mdio-gpio.h
new file mode 100644
index 0000000..e9d3fdf
--- /dev/null
+++ b/include/linux/mdio-gpio.h
@@ -0,0 +1,25 @@
+/*
+ * MDIO-GPIO bus platform data structures
+ *
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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 __LINUX_MDIO_GPIO_H
+#define __LINUX_MDIO_GPIO_H
+
+#include <linux/mdio-bitbang.h>
+
+struct mdio_gpio_platform_data {
+	/* GPIO numbers for bus pins */
+	unsigned int mdc;
+	unsigned int mdio;
+
+	unsigned int phy_mask;
+	int irqs[PHY_MAX_ADDR];
+};
+
+#endif /* __LINUX_MDIO_GPIO_H */
diff --git a/include/linux/mfd/wm8350/audio.h b/include/linux/mfd/wm8350/audio.h
index 217bb22..af95a1d 100644
--- a/include/linux/mfd/wm8350/audio.h
+++ b/include/linux/mfd/wm8350/audio.h
@@ -1,7 +1,7 @@
 /*
  * audio.h  --  Audio Driver for Wolfson WM8350 PMIC
  *
- * Copyright 2007 Wolfson Microelectronics PLC
+ * Copyright 2007, 2008 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 as published by the
@@ -70,9 +70,9 @@
 #define WM8350_CODEC_ISEL_0_5                   3	/* x0.5 */
 
 #define WM8350_VMID_OFF                         0
-#define WM8350_VMID_500K                        1
-#define WM8350_VMID_100K                        2
-#define WM8350_VMID_10K                         3
+#define WM8350_VMID_300K                        1
+#define WM8350_VMID_50K                         2
+#define WM8350_VMID_5K                          3
 
 /*
  * R40 (0x28) - Clock Control 1
@@ -591,8 +591,38 @@
 #define WM8350_IRQ_CODEC_MICSCD			41
 #define WM8350_IRQ_CODEC_MICD			42
 
+/*
+ * WM8350 Platform data.
+ *
+ * This must be initialised per platform for best audio performance.
+ * Please see WM8350 datasheet for information.
+ */
+struct wm8350_audio_platform_data {
+	int vmid_discharge_msecs;	/* VMID --> OFF discharge time */
+	int drain_msecs;	/* OFF drain time */
+	int cap_discharge_msecs;	/* Cap ON (from OFF) discharge time */
+	int vmid_charge_msecs;	/* vmid power up time */
+	u32 vmid_s_curve:2;	/* vmid enable s curve speed */
+	u32 dis_out4:2;		/* out4 discharge speed */
+	u32 dis_out3:2;		/* out3 discharge speed */
+	u32 dis_out2:2;		/* out2 discharge speed */
+	u32 dis_out1:2;		/* out1 discharge speed */
+	u32 vroi_out4:1;	/* out4 tie off */
+	u32 vroi_out3:1;	/* out3 tie off */
+	u32 vroi_out2:1;	/* out2 tie off */
+	u32 vroi_out1:1;	/* out1 tie off */
+	u32 vroi_enable:1;	/* enable tie off */
+	u32 codec_current_on:2;	/* current level ON */
+	u32 codec_current_standby:2;	/* current level STANDBY */
+	u32 codec_current_charge:2;	/* codec current @ vmid charge */
+};
+
+struct snd_soc_codec;
+
 struct wm8350_codec {
 	struct platform_device *pdev;
+	struct snd_soc_codec *codec;
+	struct wm8350_audio_platform_data *platform_data;
 };
 
 #endif
diff --git a/include/linux/mii.h b/include/linux/mii.h
index 151b7e0..ad74858 100644
--- a/include/linux/mii.h
+++ b/include/linux/mii.h
@@ -135,6 +135,10 @@
 #define LPA_1000FULL            0x0800  /* Link partner 1000BASE-T full duplex */
 #define LPA_1000HALF            0x0400  /* Link partner 1000BASE-T half duplex */
 
+/* Flow control flags */
+#define FLOW_CTRL_TX		0x01
+#define FLOW_CTRL_RX		0x02
+
 /* This structure is used in all SIOCxMIIxxx ioctl calls */
 struct mii_ioctl_data {
 	__u16		phy_id;
@@ -235,5 +239,34 @@
 	return 0;
 }
 
+/**
+ * mii_resolve_flowctrl_fdx
+ * @lcladv: value of MII ADVERTISE register
+ * @rmtadv: value of MII LPA register
+ *
+ * Resolve full duplex flow control as per IEEE 802.3-2005 table 28B-3
+ */
+static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv)
+{
+	u8 cap = 0;
+
+	if (lcladv & ADVERTISE_PAUSE_CAP) {
+		if (lcladv & ADVERTISE_PAUSE_ASYM) {
+			if (rmtadv & LPA_PAUSE_CAP)
+				cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
+			else if (rmtadv & LPA_PAUSE_ASYM)
+				cap = FLOW_CTRL_RX;
+		} else {
+			if (rmtadv & LPA_PAUSE_CAP)
+				cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
+		}
+	} else if (lcladv & ADVERTISE_PAUSE_ASYM) {
+		if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
+			cap = FLOW_CTRL_TX;
+	}
+
+	return cap;
+}
+
 #endif /* __KERNEL__ */
 #endif /* __LINUX_MII_H__ */
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 371086f..8f659cc 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -206,6 +206,7 @@
 	int			reserved_cqs;
 	int			num_eqs;
 	int			reserved_eqs;
+	int			num_comp_vectors;
 	int			num_mpts;
 	int			num_mtt_segs;
 	int			fmr_reserved_mtts;
@@ -328,6 +329,7 @@
 	int			arm_sn;
 
 	int			cqn;
+	unsigned		vector;
 
 	atomic_t		refcount;
 	struct completion	free;
@@ -437,7 +439,7 @@
 
 int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
 		  struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
-		  int collapsed);
+		  unsigned vector, int collapsed);
 void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq);
 
 int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index ffee2f7..aaa8b84 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -145,6 +145,23 @@
 #define FAULT_FLAG_WRITE	0x01	/* Fault was a write access */
 #define FAULT_FLAG_NONLINEAR	0x02	/* Fault was via a nonlinear mapping */
 
+/*
+ * This interface is used by x86 PAT code to identify a pfn mapping that is
+ * linear over entire vma. This is to optimize PAT code that deals with
+ * marking the physical region with a particular prot. This is not for generic
+ * mm use. Note also that this check will not work if the pfn mapping is
+ * linear for a vma starting at physical address 0. In which case PAT code
+ * falls back to slow path of reserving physical range page by page.
+ */
+static inline int is_linear_pfn_mapping(struct vm_area_struct *vma)
+{
+	return ((vma->vm_flags & VM_PFNMAP) && vma->vm_pgoff);
+}
+
+static inline int is_pfn_mapping(struct vm_area_struct *vma)
+{
+	return (vma->vm_flags & VM_PFNMAP);
+}
 
 /*
  * vm_fault is filled by the the pagefault handler and passed to the vma's
@@ -781,6 +798,8 @@
 			struct vm_area_struct *vma);
 void unmap_mapping_range(struct address_space *mapping,
 		loff_t const holebegin, loff_t const holelen, int even_cows);
+int follow_phys(struct vm_area_struct *vma, unsigned long address,
+		unsigned int flags, unsigned long *prot, resource_size_t *phys);
 int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
 			void *buf, int len, int write);
 
@@ -1286,5 +1305,7 @@
 int vmemmap_populate(struct page *start_page, unsigned long pages, int node);
 void vmemmap_populate_print_last(void);
 
+extern void *alloc_locked_buffer(size_t size);
+extern void free_locked_buffer(void *buffer, size_t size);
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MM_H */
diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h
index 6f4c180..5375fac 100644
--- a/include/linux/mroute6.h
+++ b/include/linux/mroute6.h
@@ -117,6 +117,7 @@
 
 #include <linux/pim.h>
 #include <linux/skbuff.h>	/* for struct sk_buff_head */
+#include <net/net_namespace.h>
 
 #ifdef CONFIG_IPV6_MROUTE
 static inline int ip6_mroute_opt(int opt)
@@ -187,6 +188,9 @@
 struct mfc6_cache
 {
 	struct mfc6_cache *next;		/* Next entry on cache line 	*/
+#ifdef CONFIG_NET_NS
+	struct net *mfc6_net;
+#endif
 	struct in6_addr mf6c_mcastgrp;			/* Group the entry belongs to 	*/
 	struct in6_addr mf6c_origin;			/* Source of packet 		*/
 	mifi_t mf6c_parent;			/* Source interface		*/
@@ -209,6 +213,18 @@
 	} mfc_un;
 };
 
+static inline
+struct net *mfc6_net(const struct mfc6_cache *mfc)
+{
+	return read_pnet(&mfc->mfc6_net);
+}
+
+static inline
+void mfc6_net_set(struct mfc6_cache *mfc, struct net *net)
+{
+	write_pnet(&mfc->mfc6_net, hold_net(net));
+}
+
 #define MFC_STATIC		1
 #define MFC_NOTIFY		2
 
@@ -229,13 +245,17 @@
 
 #ifdef __KERNEL__
 struct rtmsg;
-extern int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait);
+extern int ip6mr_get_route(struct net *net, struct sk_buff *skb,
+			   struct rtmsg *rtm, int nowait);
 
 #ifdef CONFIG_IPV6_MROUTE
-extern struct sock *mroute6_socket;
+static inline struct sock *mroute6_socket(struct net *net)
+{
+	return net->ipv6.mroute6_sk;
+}
 extern int ip6mr_sk_done(struct sock *sk);
 #else
-#define mroute6_socket NULL
+static inline struct sock *mroute6_socket(struct net *net) { return NULL; }
 static inline int ip6mr_sk_done(struct sock *sk) { return 0; }
 #endif
 #endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e26f549..41e1224 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -43,6 +43,9 @@
 
 #include <net/net_namespace.h>
 #include <net/dsa.h>
+#ifdef CONFIG_DCB
+#include <net/dcbnl.h>
+#endif
 
 struct vlan_group;
 struct ethtool_ops;
@@ -311,8 +314,9 @@
 	spinlock_t		poll_lock;
 	int			poll_owner;
 	struct net_device	*dev;
-	struct list_head	dev_list;
 #endif
+	struct list_head	dev_list;
+	struct sk_buff		*gro_list;
 };
 
 enum
@@ -373,22 +377,8 @@
  *
  * Mark NAPI processing as complete.
  */
-static inline void __napi_complete(struct napi_struct *n)
-{
-	BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
-	list_del(&n->poll_list);
-	smp_mb__before_clear_bit();
-	clear_bit(NAPI_STATE_SCHED, &n->state);
-}
-
-static inline void napi_complete(struct napi_struct *n)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	__napi_complete(n);
-	local_irq_restore(flags);
-}
+extern void __napi_complete(struct napi_struct *n);
+extern void napi_complete(struct napi_struct *n);
 
 /**
  *	napi_disable - prevent NAPI from scheduling
@@ -452,6 +442,147 @@
 	struct Qdisc		*qdisc_sleeping;
 } ____cacheline_aligned_in_smp;
 
+
+/*
+ * This structure defines the management hooks for network devices.
+ * The following hooks can be defined; unless noted otherwise, they are
+ * optional and can be filled with a null pointer.
+ *
+ * int (*ndo_init)(struct net_device *dev);
+ *     This function is called once when network device is registered.
+ *     The network device can use this to any late stage initializaton
+ *     or semantic validattion. It can fail with an error code which will
+ *     be propogated back to register_netdev
+ *
+ * void (*ndo_uninit)(struct net_device *dev);
+ *     This function is called when device is unregistered or when registration
+ *     fails. It is not called if init fails.
+ *
+ * int (*ndo_open)(struct net_device *dev);
+ *     This function is called when network device transistions to the up
+ *     state.
+ *
+ * int (*ndo_stop)(struct net_device *dev);
+ *     This function is called when network device transistions to the down
+ *     state.
+ *
+ * int (*ndo_hard_start_xmit)(struct sk_buff *skb, struct net_device *dev);
+ *	Called when a packet needs to be transmitted.
+ *	Must return NETDEV_TX_OK , NETDEV_TX_BUSY, or NETDEV_TX_LOCKED,
+ *	Required can not be NULL.
+ *
+ * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb);
+ *	Called to decide which queue to when device supports multiple
+ *	transmit queues.
+ *
+ * void (*ndo_change_rx_flags)(struct net_device *dev, int flags);
+ *	This function is called to allow device receiver to make
+ *	changes to configuration when multicast or promiscious is enabled.
+ *
+ * void (*ndo_set_rx_mode)(struct net_device *dev);
+ *	This function is called device changes address list filtering.
+ *
+ * void (*ndo_set_multicast_list)(struct net_device *dev);
+ *	This function is called when the multicast address list changes.
+ *
+ * int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
+ *	This function  is called when the Media Access Control address
+ *	needs to be changed. If not this interface is not defined, the
+ *	mac address can not be changed.
+ *
+ * int (*ndo_validate_addr)(struct net_device *dev);
+ *	Test if Media Access Control address is valid for the device.
+ *
+ * int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
+ *	Called when a user request an ioctl which can't be handled by
+ *	the generic interface code. If not defined ioctl's return
+ *	not supported error code.
+ *
+ * int (*ndo_set_config)(struct net_device *dev, struct ifmap *map);
+ *	Used to set network devices bus interface parameters. This interface
+ *	is retained for legacy reason, new devices should use the bus
+ *	interface (PCI) for low level management.
+ *
+ * int (*ndo_change_mtu)(struct net_device *dev, int new_mtu);
+ *	Called when a user wants to change the Maximum Transfer Unit
+ *	of a device. If not defined, any request to change MTU will
+ *	will return an error.
+ *
+ * void (*ndo_tx_timeout)(struct net_device *dev);
+ *	Callback uses when the transmitter has not made any progress
+ *	for dev->watchdog ticks.
+ *
+ * struct net_device_stats* (*get_stats)(struct net_device *dev);
+ *	Called when a user wants to get the network device usage
+ *	statistics. If not defined, the counters in dev->stats will
+ *	be used.
+ *
+ * void (*ndo_vlan_rx_register)(struct net_device *dev, struct vlan_group *grp);
+ *	If device support VLAN receive accleration
+ *	(ie. dev->features & NETIF_F_HW_VLAN_RX), then this function is called
+ *	when vlan groups for the device changes.  Note: grp is NULL
+ *	if no vlan's groups are being used.
+ *
+ * void (*ndo_vlan_rx_add_vid)(struct net_device *dev, unsigned short vid);
+ *	If device support VLAN filtering (dev->features & NETIF_F_HW_VLAN_FILTER)
+ *	this function is called when a VLAN id is registered.
+ *
+ * void (*ndo_vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid);
+ *	If device support VLAN filtering (dev->features & NETIF_F_HW_VLAN_FILTER)
+ *	this function is called when a VLAN id is unregistered.
+ *
+ * void (*ndo_poll_controller)(struct net_device *dev);
+ */
+#define HAVE_NET_DEVICE_OPS
+struct net_device_ops {
+	int			(*ndo_init)(struct net_device *dev);
+	void			(*ndo_uninit)(struct net_device *dev);
+	int			(*ndo_open)(struct net_device *dev);
+	int			(*ndo_stop)(struct net_device *dev);
+	int			(*ndo_start_xmit) (struct sk_buff *skb,
+						   struct net_device *dev);
+	u16			(*ndo_select_queue)(struct net_device *dev,
+						    struct sk_buff *skb);
+#define HAVE_CHANGE_RX_FLAGS
+	void			(*ndo_change_rx_flags)(struct net_device *dev,
+						       int flags);
+#define HAVE_SET_RX_MODE
+	void			(*ndo_set_rx_mode)(struct net_device *dev);
+#define HAVE_MULTICAST
+	void			(*ndo_set_multicast_list)(struct net_device *dev);
+#define HAVE_SET_MAC_ADDR
+	int			(*ndo_set_mac_address)(struct net_device *dev,
+						       void *addr);
+#define HAVE_VALIDATE_ADDR
+	int			(*ndo_validate_addr)(struct net_device *dev);
+#define HAVE_PRIVATE_IOCTL
+	int			(*ndo_do_ioctl)(struct net_device *dev,
+					        struct ifreq *ifr, int cmd);
+#define HAVE_SET_CONFIG
+	int			(*ndo_set_config)(struct net_device *dev,
+					          struct ifmap *map);
+#define HAVE_CHANGE_MTU
+	int			(*ndo_change_mtu)(struct net_device *dev,
+						  int new_mtu);
+	int			(*ndo_neigh_setup)(struct net_device *dev,
+						   struct neigh_parms *);
+#define HAVE_TX_TIMEOUT
+	void			(*ndo_tx_timeout) (struct net_device *dev);
+
+	struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
+
+	void			(*ndo_vlan_rx_register)(struct net_device *dev,
+						        struct vlan_group *grp);
+	void			(*ndo_vlan_rx_add_vid)(struct net_device *dev,
+						       unsigned short vid);
+	void			(*ndo_vlan_rx_kill_vid)(struct net_device *dev,
+						        unsigned short vid);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+#define HAVE_NETDEV_POLL
+	void                    (*ndo_poll_controller)(struct net_device *dev);
+#endif
+};
+
 /*
  *	The DEVICE structure.
  *	Actually, this whole structure is a big mistake.  It mixes I/O
@@ -496,14 +627,7 @@
 	unsigned long		state;
 
 	struct list_head	dev_list;
-#ifdef CONFIG_NETPOLL
 	struct list_head	napi_list;
-#endif
-	
-	/* The device initialization function. Called only once. */
-	int			(*init)(struct net_device *dev);
-
-	/* ------- Fields preinitialized in Space.c finish here ------- */
 
 	/* Net device features */
 	unsigned long		features;
@@ -522,6 +646,7 @@
 #define NETIF_F_LLTX		4096	/* LockLess TX - deprecated. Please */
 					/* do not use LLTX in new drivers */
 #define NETIF_F_NETNS_LOCAL	8192	/* Does not change network namespaces */
+#define NETIF_F_GRO		16384	/* Generic receive offload */
 #define NETIF_F_LRO		32768	/* large receive offload */
 
 	/* Segmentation offload features */
@@ -547,15 +672,13 @@
 	 * for all in netdev_increment_features.
 	 */
 #define NETIF_F_ONE_FOR_ALL	(NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \
-				 NETIF_F_SG | NETIF_F_HIGHDMA | \
+				 NETIF_F_SG | NETIF_F_HIGHDMA |		\
 				 NETIF_F_FRAGLIST)
 
 	/* Interface index. Unique device identifier	*/
 	int			ifindex;
 	int			iflink;
 
-
-	struct net_device_stats* (*get_stats)(struct net_device *dev);
 	struct net_device_stats	stats;
 
 #ifdef CONFIG_WIRELESS_EXT
@@ -565,18 +688,13 @@
 	/* Instance data managed by the core of Wireless Extensions. */
 	struct iw_public_data *	wireless_data;
 #endif
+	/* Management operations */
+	const struct net_device_ops *netdev_ops;
 	const struct ethtool_ops *ethtool_ops;
 
 	/* Hardware header description */
 	const struct header_ops *header_ops;
 
-	/*
-	 * This marks the end of the "visible" part of the structure. All
-	 * fields hereafter are internal to the system, and may change at
-	 * will (read: may be cleaned up at will).
-	 */
-
-
 	unsigned int		flags;	/* interface flags (a la BSD)	*/
 	unsigned short		gflags;
         unsigned short          priv_flags; /* Like 'flags' but invisible to userspace. */
@@ -635,7 +753,7 @@
 	unsigned long		last_rx;	/* Time of last Rx	*/
 	/* Interface address info used in eth_type_trans() */
 	unsigned char		dev_addr[MAX_ADDR_LEN];	/* hw address, (before bcast 
-							because most packets are unicast) */
+							   because most packets are unicast) */
 
 	unsigned char		broadcast[MAX_ADDR_LEN];	/* hw bcast add	*/
 
@@ -654,18 +772,12 @@
 /*
  * One part is mostly used on xmit path (device)
  */
-	void			*priv;	/* pointer to private data	*/
-	int			(*hard_start_xmit) (struct sk_buff *skb,
-						    struct net_device *dev);
 	/* These may be needed for future network-power-down code. */
 	unsigned long		trans_start;	/* Time (in jiffies) of last Tx	*/
 
 	int			watchdog_timeo; /* used by dev_watchdog() */
 	struct timer_list	watchdog_timer;
 
-/*
- * refcnt is a very hot point, so align it on SMP
- */
 	/* Number of references to this device */
 	atomic_t		refcnt ____cacheline_aligned_in_smp;
 
@@ -684,56 +796,12 @@
 	       NETREG_RELEASED,		/* called free_netdev */
 	} reg_state;
 
-	/* Called after device is detached from network. */
-	void			(*uninit)(struct net_device *dev);
-	/* Called after last user reference disappears. */
-	void			(*destructor)(struct net_device *dev);
+	/* Called from unregister, can be used to call free_netdev */
+	void (*destructor)(struct net_device *dev);
 
-	/* Pointers to interface service routines.	*/
-	int			(*open)(struct net_device *dev);
-	int			(*stop)(struct net_device *dev);
-#define HAVE_NETDEV_POLL
-#define HAVE_CHANGE_RX_FLAGS
-	void			(*change_rx_flags)(struct net_device *dev,
-						   int flags);
-#define HAVE_SET_RX_MODE
-	void			(*set_rx_mode)(struct net_device *dev);
-#define HAVE_MULTICAST			 
-	void			(*set_multicast_list)(struct net_device *dev);
-#define HAVE_SET_MAC_ADDR  		 
-	int			(*set_mac_address)(struct net_device *dev,
-						   void *addr);
-#define HAVE_VALIDATE_ADDR
-	int			(*validate_addr)(struct net_device *dev);
-#define HAVE_PRIVATE_IOCTL
-	int			(*do_ioctl)(struct net_device *dev,
-					    struct ifreq *ifr, int cmd);
-#define HAVE_SET_CONFIG
-	int			(*set_config)(struct net_device *dev,
-					      struct ifmap *map);
-#define HAVE_CHANGE_MTU
-	int			(*change_mtu)(struct net_device *dev, int new_mtu);
-
-#define HAVE_TX_TIMEOUT
-	void			(*tx_timeout) (struct net_device *dev);
-
-	void			(*vlan_rx_register)(struct net_device *dev,
-						    struct vlan_group *grp);
-	void			(*vlan_rx_add_vid)(struct net_device *dev,
-						   unsigned short vid);
-	void			(*vlan_rx_kill_vid)(struct net_device *dev,
-						    unsigned short vid);
-
-	int			(*neigh_setup)(struct net_device *dev, struct neigh_parms *);
 #ifdef CONFIG_NETPOLL
 	struct netpoll_info	*npinfo;
 #endif
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	void                    (*poll_controller)(struct net_device *dev);
-#endif
-
-	u16			(*select_queue)(struct net_device *dev,
-						struct sk_buff *skb);
 
 #ifdef CONFIG_NET_NS
 	/* Network namespace this network device is inside */
@@ -764,6 +832,49 @@
 	/* for setting kernel sock attribute on TCP connection setup */
 #define GSO_MAX_SIZE		65536
 	unsigned int		gso_max_size;
+
+#ifdef CONFIG_DCB
+	/* Data Center Bridging netlink ops */
+	struct dcbnl_rtnl_ops *dcbnl_ops;
+#endif
+
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
+	struct {
+		int			(*init)(struct net_device *dev);
+		void			(*uninit)(struct net_device *dev);
+		int			(*open)(struct net_device *dev);
+		int			(*stop)(struct net_device *dev);
+		int			(*hard_start_xmit) (struct sk_buff *skb,
+							    struct net_device *dev);
+		u16			(*select_queue)(struct net_device *dev,
+							struct sk_buff *skb);
+		void			(*change_rx_flags)(struct net_device *dev,
+							   int flags);
+		void			(*set_rx_mode)(struct net_device *dev);
+		void			(*set_multicast_list)(struct net_device *dev);
+		int			(*set_mac_address)(struct net_device *dev,
+							   void *addr);
+		int			(*validate_addr)(struct net_device *dev);
+		int			(*do_ioctl)(struct net_device *dev,
+						    struct ifreq *ifr, int cmd);
+		int			(*set_config)(struct net_device *dev,
+						      struct ifmap *map);
+		int			(*change_mtu)(struct net_device *dev, int new_mtu);
+		int			(*neigh_setup)(struct net_device *dev,
+						       struct neigh_parms *);
+		void			(*tx_timeout) (struct net_device *dev);
+		struct net_device_stats* (*get_stats)(struct net_device *dev);
+		void			(*vlan_rx_register)(struct net_device *dev,
+							    struct vlan_group *grp);
+		void			(*vlan_rx_add_vid)(struct net_device *dev,
+							   unsigned short vid);
+		void			(*vlan_rx_kill_vid)(struct net_device *dev,
+							    unsigned short vid);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+		void                    (*poll_controller)(struct net_device *dev);
+#endif
+	};
+#endif
 };
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
@@ -859,22 +970,8 @@
  * netif_napi_add() must be used to initialize a napi context prior to calling
  * *any* of the other napi related functions.
  */
-static inline void netif_napi_add(struct net_device *dev,
-				  struct napi_struct *napi,
-				  int (*poll)(struct napi_struct *, int),
-				  int weight)
-{
-	INIT_LIST_HEAD(&napi->poll_list);
-	napi->poll = poll;
-	napi->weight = weight;
-#ifdef CONFIG_NETPOLL
-	napi->dev = dev;
-	list_add(&napi->dev_list, &dev->napi_list);
-	spin_lock_init(&napi->poll_lock);
-	napi->poll_owner = -1;
-#endif
-	set_bit(NAPI_STATE_SCHED, &napi->state);
-}
+void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
+		    int (*poll)(struct napi_struct *, int), int weight);
 
 /**
  *  netif_napi_del - remove a napi context
@@ -882,12 +979,20 @@
  *
  *  netif_napi_del() removes a napi context from the network device napi list
  */
-static inline void netif_napi_del(struct napi_struct *napi)
-{
-#ifdef CONFIG_NETPOLL
-	list_del(&napi->dev_list);
-#endif
-}
+void netif_napi_del(struct napi_struct *napi);
+
+struct napi_gro_cb {
+	/* This is non-zero if the packet may be of the same flow. */
+	int same_flow;
+
+	/* This is non-zero if the packet cannot be merged with the new skb. */
+	int flush;
+
+	/* Number of segments aggregated. */
+	int count;
+};
+
+#define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
 
 struct packet_type {
 	__be16			type;	/* This is really htons(ether_type). */
@@ -899,6 +1004,9 @@
 	struct sk_buff		*(*gso_segment)(struct sk_buff *skb,
 						int features);
 	int			(*gso_send_check)(struct sk_buff *skb);
+	struct sk_buff		**(*gro_receive)(struct sk_buff **head,
+					       struct sk_buff *skb);
+	int			(*gro_complete)(struct sk_buff *skb);
 	void			*af_packet_priv;
 	struct list_head	list;
 };
@@ -1252,6 +1360,9 @@
 extern int		netif_rx_ni(struct sk_buff *skb);
 #define HAVE_NETIF_RECEIVE_SKB 1
 extern int		netif_receive_skb(struct sk_buff *skb);
+extern void		napi_gro_flush(struct napi_struct *napi);
+extern int		napi_gro_receive(struct napi_struct *napi,
+					 struct sk_buff *skb);
 extern void		netif_nit_deliver(struct sk_buff *skb);
 extern int		dev_valid_name(const char *name);
 extern int		dev_ioctl(struct net *net, unsigned int cmd, void __user *);
@@ -1444,8 +1555,7 @@
 }
 
 /* Test if receive needs to be scheduled but only if up */
-static inline int netif_rx_schedule_prep(struct net_device *dev,
-					 struct napi_struct *napi)
+static inline int netif_rx_schedule_prep(struct napi_struct *napi)
 {
 	return napi_schedule_prep(napi);
 }
@@ -1453,27 +1563,24 @@
 /* Add interface to tail of rx poll list. This assumes that _prep has
  * already been called and returned 1.
  */
-static inline void __netif_rx_schedule(struct net_device *dev,
-				       struct napi_struct *napi)
+static inline void __netif_rx_schedule(struct napi_struct *napi)
 {
 	__napi_schedule(napi);
 }
 
 /* Try to reschedule poll. Called by irq handler. */
 
-static inline void netif_rx_schedule(struct net_device *dev,
-				     struct napi_struct *napi)
+static inline void netif_rx_schedule(struct napi_struct *napi)
 {
-	if (netif_rx_schedule_prep(dev, napi))
-		__netif_rx_schedule(dev, napi);
+	if (netif_rx_schedule_prep(napi))
+		__netif_rx_schedule(napi);
 }
 
 /* Try to reschedule poll. Called by dev->poll() after netif_rx_complete().  */
-static inline int netif_rx_reschedule(struct net_device *dev,
-				      struct napi_struct *napi)
+static inline int netif_rx_reschedule(struct napi_struct *napi)
 {
 	if (napi_schedule_prep(napi)) {
-		__netif_rx_schedule(dev, napi);
+		__netif_rx_schedule(napi);
 		return 1;
 	}
 	return 0;
@@ -1482,8 +1589,7 @@
 /* same as netif_rx_complete, except that local_irq_save(flags)
  * has already been issued
  */
-static inline void __netif_rx_complete(struct net_device *dev,
-				       struct napi_struct *napi)
+static inline void __netif_rx_complete(struct napi_struct *napi)
 {
 	__napi_complete(napi);
 }
@@ -1493,20 +1599,9 @@
  * it completes the work. The device cannot be out of poll list at this
  * moment, it is BUG().
  */
-static inline void netif_rx_complete(struct net_device *dev,
-				     struct napi_struct *napi)
+static inline void netif_rx_complete(struct napi_struct *napi)
 {
-	unsigned long flags;
-
-	/*
-	 * don't let napi dequeue from the cpu poll list
-	 * just in case its running on a different cpu
-	 */
-	if (unlikely(test_bit(NAPI_STATE_NPSVC, &napi->state)))
-		return;
-	local_irq_save(flags);
-	__netif_rx_complete(dev, napi);
-	local_irq_restore(flags);
+	napi_complete(napi);
 }
 
 static inline void __netif_tx_lock(struct netdev_queue *txq, int cpu)
@@ -1683,6 +1778,8 @@
 /* Load a device via the kmod */
 extern void		dev_load(struct net *net, const char *name);
 extern void		dev_mcast_init(void);
+extern const struct net_device_stats *dev_get_stats(struct net_device *dev);
+
 extern int		netdev_max_backlog;
 extern int		weight_p;
 extern int		netdev_set_master(struct net_device *dev, struct net_device *master);
@@ -1731,6 +1828,8 @@
 {
 	return skb_is_gso(skb) &&
 	       (!skb_gso_ok(skb, dev->features) ||
+	        (skb_shinfo(skb)->frag_list &&
+	         !(dev->features & NETIF_F_FRAGLIST)) ||
 		unlikely(skb->ip_summed != CHECKSUM_PARTIAL));
 }
 
@@ -1749,26 +1848,31 @@
 	struct net_device *dev = skb->dev;
 	struct net_device *master = dev->master;
 
-	if (master &&
-	    (dev->priv_flags & IFF_SLAVE_INACTIVE)) {
-		if ((dev->priv_flags & IFF_SLAVE_NEEDARP) &&
-		    skb->protocol == __constant_htons(ETH_P_ARP))
-			return 0;
+	if (master) {
+		if (master->priv_flags & IFF_MASTER_ARPMON)
+			dev->last_rx = jiffies;
 
-		if (master->priv_flags & IFF_MASTER_ALB) {
-			if (skb->pkt_type != PACKET_BROADCAST &&
-			    skb->pkt_type != PACKET_MULTICAST)
+		if (dev->priv_flags & IFF_SLAVE_INACTIVE) {
+			if ((dev->priv_flags & IFF_SLAVE_NEEDARP) &&
+			    skb->protocol == __constant_htons(ETH_P_ARP))
 				return 0;
-		}
-		if (master->priv_flags & IFF_MASTER_8023AD &&
-		    skb->protocol == __constant_htons(ETH_P_SLOW))
-			return 0;
 
-		return 1;
+			if (master->priv_flags & IFF_MASTER_ALB) {
+				if (skb->pkt_type != PACKET_BROADCAST &&
+				    skb->pkt_type != PACKET_MULTICAST)
+					return 0;
+			}
+			if (master->priv_flags & IFF_MASTER_8023AD &&
+			    skb->protocol == __constant_htons(ETH_P_SLOW))
+				return 0;
+
+			return 1;
+		}
 	}
 	return 0;
 }
 
+extern struct pernet_operations __net_initdata loopback_net_ops;
 #endif /* __KERNEL__ */
 
 #endif	/* _LINUX_DEV_H */
diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
index d45e29c..e40ddb9 100644
--- a/include/linux/netfilter_bridge/ebtables.h
+++ b/include/linux/netfilter_bridge/ebtables.h
@@ -300,7 +300,8 @@
 
 #define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \
 		     ~(__alignof__(struct ebt_replace)-1))
-extern int ebt_register_table(struct ebt_table *table);
+extern struct ebt_table *ebt_register_table(struct net *net,
+					    struct ebt_table *table);
 extern void ebt_unregister_table(struct ebt_table *table);
 extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb,
    const struct net_device *in, const struct net_device *out,
diff --git a/include/linux/netfilter_ipv4/ipt_policy.h b/include/linux/netfilter_ipv4/ipt_policy.h
index b9478a2..1037fb2 100644
--- a/include/linux/netfilter_ipv4/ipt_policy.h
+++ b/include/linux/netfilter_ipv4/ipt_policy.h
@@ -1,6 +1,8 @@
 #ifndef _IPT_POLICY_H
 #define _IPT_POLICY_H
 
+#include <linux/netfilter/xt_policy.h>
+
 #define IPT_POLICY_MAX_ELEM		XT_POLICY_MAX_ELEM
 
 /* ipt_policy_flags */
diff --git a/include/linux/netfilter_ipv6/ip6t_policy.h b/include/linux/netfilter_ipv6/ip6t_policy.h
index 6bab316..b1c449d 100644
--- a/include/linux/netfilter_ipv6/ip6t_policy.h
+++ b/include/linux/netfilter_ipv6/ip6t_policy.h
@@ -1,6 +1,8 @@
 #ifndef _IP6T_POLICY_H
 #define _IP6T_POLICY_H
 
+#include <linux/netfilter/xt_policy.h>
+
 #define IP6T_POLICY_MAX_ELEM		XT_POLICY_MAX_ELEM
 
 /* ip6t_policy_flags */
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 9ff1b54..51b09a1 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -242,7 +242,8 @@
 	nlh->nlmsg_flags = flags;
 	nlh->nlmsg_pid = pid;
 	nlh->nlmsg_seq = seq;
-	memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size);
+	if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0)
+		memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size);
 	return nlh;
 }
 
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index e3d7959..e38d3c9 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -94,11 +94,6 @@
 	rcu_read_unlock();
 }
 
-static inline void netpoll_netdev_init(struct net_device *dev)
-{
-	INIT_LIST_HEAD(&dev->napi_list);
-}
-
 #else
 static inline int netpoll_rx(struct sk_buff *skb)
 {
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 9bad6540..e86ed59 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -3,7 +3,26 @@
 /*
  * 802.11 netlink interface public header
  *
- * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006, 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2008 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
+ * Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ * Copyright 2008 Luis R. Rodriguez <lrodriguez@atheros.com>
+ * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
+ * Copyright 2008 Colin McCabe <colin@cozybit.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
  */
 
 /**
@@ -25,8 +44,10 @@
  *
  * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
  *	to get a list of all present wiphys.
- * @NL80211_CMD_SET_WIPHY: set wiphy name, needs %NL80211_ATTR_WIPHY and
- *	%NL80211_ATTR_WIPHY_NAME.
+ * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
+ *	%NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
+ *	%NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or
+ *	%NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET.
  * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
  *	or rename notification. Has attributes %NL80211_ATTR_WIPHY and
  *	%NL80211_ATTR_WIPHY_NAME.
@@ -106,6 +127,12 @@
  * 	to the the specified ISO/IEC 3166-1 alpha2 country code. The core will
  * 	store this as a valid request and then query userspace for it.
  *
+ * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
+ *	interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
+ *      interface identified by %NL80211_ATTR_IFINDEX
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -148,6 +175,9 @@
 	NL80211_CMD_SET_REG,
 	NL80211_CMD_REQ_SET_REG,
 
+	NL80211_CMD_GET_MESH_PARAMS,
+	NL80211_CMD_SET_MESH_PARAMS,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -169,6 +199,15 @@
  * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
  *	/sys/class/ieee80211/<phyname>/index
  * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
+ * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
+ *	if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ *	NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
+ *		this attribute)
+ *	NL80211_CHAN_HT20 = HT20 only
+ *	NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
+ *	NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
  *
  * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
  * @NL80211_ATTR_IFNAME: network interface name
@@ -234,6 +273,9 @@
  *	(u8, 0 or 1)
  * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
  *	(u8, 0 or 1)
+ * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic
+ *	rates in format defined by IEEE 802.11 7.3.2.2 but without the length
+ *	restriction (at most %NL80211_MAX_SUPP_RATES).
  *
  * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
  *	association request when used with NL80211_CMD_NEW_STATION)
@@ -296,6 +338,14 @@
 	NL80211_ATTR_REG_ALPHA2,
 	NL80211_ATTR_REG_RULES,
 
+	NL80211_ATTR_MESH_PARAMS,
+
+	NL80211_ATTR_BSS_BASIC_RATES,
+
+	NL80211_ATTR_WIPHY_TXQ_PARAMS,
+	NL80211_ATTR_WIPHY_FREQ,
+	NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -307,6 +357,10 @@
  * here
  */
 #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
+#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
+#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
+#define NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET
 
 #define NL80211_MAX_SUPP_RATES			32
 #define NL80211_MAX_SUPP_REG_RULES		32
@@ -371,6 +425,32 @@
 };
 
 /**
+ * enum nl80211_rate_info - bitrate information
+ *
+ * These attribute types are used with %NL80211_STA_INFO_TXRATE
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
+ * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @__NL80211_RATE_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_rate_info {
+	__NL80211_RATE_INFO_INVALID,
+	NL80211_RATE_INFO_BITRATE,
+	NL80211_RATE_INFO_MCS,
+	NL80211_RATE_INFO_40_MHZ_WIDTH,
+	NL80211_RATE_INFO_SHORT_GI,
+
+	/* keep last */
+	__NL80211_RATE_INFO_AFTER_LAST,
+	NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_sta_info - station information
  *
  * These attribute types are used with %NL80211_ATTR_STA_INFO
@@ -382,6 +462,9 @@
  * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
+ * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
+ * 	containing info as possible, see &enum nl80211_sta_info_txrate.
  */
 enum nl80211_sta_info {
 	__NL80211_STA_INFO_INVALID,
@@ -391,6 +474,8 @@
 	NL80211_STA_INFO_LLID,
 	NL80211_STA_INFO_PLID,
 	NL80211_STA_INFO_PLINK_STATE,
+	NL80211_STA_INFO_SIGNAL,
+	NL80211_STA_INFO_TX_BITRATE,
 
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
@@ -452,17 +537,29 @@
  *	an array of nested frequency attributes
  * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
  *	an array of nested bitrate attributes
+ * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as
+ *	defined in 802.11n
+ * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
+ * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
  */
 enum nl80211_band_attr {
 	__NL80211_BAND_ATTR_INVALID,
 	NL80211_BAND_ATTR_FREQS,
 	NL80211_BAND_ATTR_RATES,
 
+	NL80211_BAND_ATTR_HT_MCS_SET,
+	NL80211_BAND_ATTR_HT_CAPA,
+	NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+	NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+
 	/* keep last */
 	__NL80211_BAND_ATTR_AFTER_LAST,
 	NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
 };
 
+#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
+
 /**
  * enum nl80211_frequency_attr - frequency attributes
  * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
@@ -474,6 +571,8 @@
  *	on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
  *	on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
+ *	(100 * dBm).
  */
 enum nl80211_frequency_attr {
 	__NL80211_FREQUENCY_ATTR_INVALID,
@@ -482,12 +581,15 @@
 	NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
 	NL80211_FREQUENCY_ATTR_NO_IBSS,
 	NL80211_FREQUENCY_ATTR_RADAR,
+	NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
 
 	/* keep last */
 	__NL80211_FREQUENCY_ATTR_AFTER_LAST,
 	NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
 };
 
+#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+
 /**
  * enum nl80211_bitrate_attr - bitrate attributes
  * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
@@ -594,4 +696,119 @@
 	NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_meshconf_params - mesh configuration parameters
+ *
+ * Mesh configuration parameters
+ *
+ * @__NL80211_MESHCONF_INVALID: internal use
+ *
+ * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
+ * millisecond units, used by the Peer Link Open message
+ *
+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in
+ * millisecond units, used by the peer link management to close a peer link
+ *
+ * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
+ * millisecond units
+ *
+ * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
+ * on this mesh interface
+ *
+ * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
+ * open retries that can be sent to establish a new peer link instance in a
+ * mesh
+ *
+ * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
+ * point.
+ *
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
+ * open peer links when we detect compatible mesh peers.
+ *
+ * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
+ * containing a PREQ that an MP can send to a particular destination (path
+ * target)
+ *
+ * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
+ * (in milliseconds)
+ *
+ * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
+ * until giving up on a path discovery (in milliseconds)
+ *
+ * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
+ * points receiving a PREQ shall consider the forwarding information from the
+ * root to be valid. (TU = time unit)
+ *
+ * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
+ * TUs) during which an MP can send only one action frame containing a PREQ
+ * reference element
+ *
+ * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
+ * that it takes for an HWMP information element to propagate across the mesh
+ *
+ * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
+ *
+ * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_meshconf_params {
+	__NL80211_MESHCONF_INVALID,
+	NL80211_MESHCONF_RETRY_TIMEOUT,
+	NL80211_MESHCONF_CONFIRM_TIMEOUT,
+	NL80211_MESHCONF_HOLDING_TIMEOUT,
+	NL80211_MESHCONF_MAX_PEER_LINKS,
+	NL80211_MESHCONF_MAX_RETRIES,
+	NL80211_MESHCONF_TTL,
+	NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+	NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+	NL80211_MESHCONF_PATH_REFRESH_TIME,
+	NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+	NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+	NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+	NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+
+	/* keep last */
+	__NL80211_MESHCONF_ATTR_AFTER_LAST,
+	NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_txq_attr - TX queue parameter attributes
+ * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
+ * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
+ * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
+ *	disabled
+ * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
+ *	2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form
+ *	2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255]
+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
+ * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number
+ */
+enum nl80211_txq_attr {
+	__NL80211_TXQ_ATTR_INVALID,
+	NL80211_TXQ_ATTR_QUEUE,
+	NL80211_TXQ_ATTR_TXOP,
+	NL80211_TXQ_ATTR_CWMIN,
+	NL80211_TXQ_ATTR_CWMAX,
+	NL80211_TXQ_ATTR_AIFS,
+
+	/* keep last */
+	__NL80211_TXQ_ATTR_AFTER_LAST,
+	NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
+};
+
+enum nl80211_txq_q {
+	NL80211_TXQ_Q_VO,
+	NL80211_TXQ_Q_VI,
+	NL80211_TXQ_Q_BE,
+	NL80211_TXQ_Q_BK
+};
+
+enum nl80211_channel_type {
+	NL80211_CHAN_NO_HT,
+	NL80211_CHAN_HT20,
+	NL80211_CHAN_HT40MINUS,
+	NL80211_CHAN_HT40PLUS
+};
 #endif /* __LINUX_NL80211_H */
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index c8a768e..afad7de 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -27,7 +27,6 @@
 	struct ipc_namespace *ipc_ns;
 	struct mnt_namespace *mnt_ns;
 	struct pid_namespace *pid_ns;
-	struct user_namespace *user_ns;
 	struct net 	     *net_ns;
 };
 extern struct nsproxy init_nsproxy;
diff --git a/include/linux/of.h b/include/linux/of.h
index e2488f5..6a7efa2 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -57,6 +57,12 @@
 	for (child = of_get_next_child(parent, NULL); child != NULL; \
 	     child = of_get_next_child(parent, child))
 
+extern struct device_node *of_find_node_with_property(
+	struct device_node *from, const char *prop_name);
+#define for_each_node_with_property(dn, prop_name) \
+	for (dn = of_find_node_with_property(NULL, prop_name); dn; \
+	     dn = of_find_node_with_property(dn, prop_name))
+
 extern struct property *of_find_property(const struct device_node *np,
 					 const char *name,
 					 int *lenp);
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index 67db101..fc2472c 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -14,9 +14,22 @@
 #ifndef __LINUX_OF_GPIO_H
 #define __LINUX_OF_GPIO_H
 
+#include <linux/compiler.h>
+#include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/gpio.h>
 
+struct device_node;
+
+/*
+ * This is Linux-specific flags. By default controllers' and Linux' mapping
+ * match, but GPIO controllers are free to translate their own flags to
+ * Linux-specific in their .xlate callback. Though, 1:1 mapping is recommended.
+ */
+enum of_gpio_flags {
+	OF_GPIO_ACTIVE_LOW = 0x1,
+};
+
 #ifdef CONFIG_OF_GPIO
 
 /*
@@ -26,7 +39,7 @@
 	struct gpio_chip gc;
 	int gpio_cells;
 	int (*xlate)(struct of_gpio_chip *of_gc, struct device_node *np,
-		     const void *gpio_spec);
+		     const void *gpio_spec, enum of_gpio_flags *flags);
 };
 
 static inline struct of_gpio_chip *to_of_gpio_chip(struct gpio_chip *gc)
@@ -50,20 +63,43 @@
 	return container_of(of_gc, struct of_mm_gpio_chip, of_gc);
 }
 
-extern int of_get_gpio(struct device_node *np, int index);
+extern int of_get_gpio_flags(struct device_node *np, int index,
+			     enum of_gpio_flags *flags);
+extern unsigned int of_gpio_count(struct device_node *np);
+
 extern int of_mm_gpiochip_add(struct device_node *np,
 			      struct of_mm_gpio_chip *mm_gc);
 extern int of_gpio_simple_xlate(struct of_gpio_chip *of_gc,
 				struct device_node *np,
-				const void *gpio_spec);
+				const void *gpio_spec,
+				enum of_gpio_flags *flags);
 #else
 
 /* Drivers may not strictly depend on the GPIO support, so let them link. */
-static inline int of_get_gpio(struct device_node *np, int index)
+static inline int of_get_gpio_flags(struct device_node *np, int index,
+				    enum of_gpio_flags *flags)
 {
 	return -ENOSYS;
 }
 
+static inline unsigned int of_gpio_count(struct device_node *np)
+{
+	return 0;
+}
+
 #endif /* CONFIG_OF_GPIO */
 
+/**
+ * of_get_gpio - Get a GPIO number to use with GPIO API
+ * @np:		device node to get GPIO from
+ * @index:	index of the GPIO
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
+ * value on the error condition.
+ */
+static inline int of_get_gpio(struct device_node *np, int index)
+{
+	return of_get_gpio_flags(np, index, NULL);
+}
+
 #endif /* __LINUX_OF_GPIO_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index feb4657..03b0b8c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -134,6 +134,11 @@
 	PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
 };
 
+enum pci_irq_reroute_variant {
+	INTEL_IRQ_REROUTE_VARIANT = 1,
+	MAX_IRQ_REROUTE_VARIANTS = 3
+};
+
 typedef unsigned short __bitwise pci_bus_flags_t;
 enum pci_bus_flags {
 	PCI_BUS_FLAGS_NO_MSI   = (__force pci_bus_flags_t) 1,
@@ -218,6 +223,7 @@
 	unsigned int	no_msi:1;	/* device may not use msi */
 	unsigned int	block_ucfg_access:1;	/* userspace config space access is blocked */
 	unsigned int	broken_parity_status:1;	/* Device generates false positive parity */
+	unsigned int	irq_reroute_variant:2;	/* device needs IRQ rerouting variant */
 	unsigned int 	msi_enabled:1;
 	unsigned int	msix_enabled:1;
 	unsigned int	ari_enabled:1;	/* ARI forwarding */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 1800f1d..b6e6944 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2304,6 +2304,10 @@
 #define PCI_DEVICE_ID_INTEL_PXH_0	0x0329
 #define PCI_DEVICE_ID_INTEL_PXH_1	0x032A
 #define PCI_DEVICE_ID_INTEL_PXHV	0x032C
+#define PCI_DEVICE_ID_INTEL_80332_0	0x0330
+#define PCI_DEVICE_ID_INTEL_80332_1	0x0332
+#define PCI_DEVICE_ID_INTEL_80333_0	0x0370
+#define PCI_DEVICE_ID_INTEL_80333_1	0x0372
 #define PCI_DEVICE_ID_INTEL_82375	0x0482
 #define PCI_DEVICE_ID_INTEL_82424	0x0483
 #define PCI_DEVICE_ID_INTEL_82378	0x0484
@@ -2376,6 +2380,7 @@
 #define PCI_DEVICE_ID_INTEL_ESB_4	0x25a4
 #define PCI_DEVICE_ID_INTEL_ESB_5	0x25a6
 #define PCI_DEVICE_ID_INTEL_ESB_9	0x25ab
+#define PCI_DEVICE_ID_INTEL_ESB_10	0x25ac
 #define PCI_DEVICE_ID_INTEL_82820_HB	0x2500
 #define PCI_DEVICE_ID_INTEL_82820_UP_HB	0x2501
 #define PCI_DEVICE_ID_INTEL_82850_HB	0x2530
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 77c4ed6..d7e54d9 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -467,6 +467,8 @@
 int genphy_config_aneg(struct phy_device *phydev);
 int genphy_update_link(struct phy_device *phydev);
 int genphy_read_status(struct phy_device *phydev);
+int genphy_suspend(struct phy_device *phydev);
+int genphy_resume(struct phy_device *phydev);
 void phy_driver_unregister(struct phy_driver *drv);
 int phy_driver_register(struct phy_driver *new_driver);
 void phy_prepare_link(struct phy_device *phydev,
diff --git a/include/linux/pid.h b/include/linux/pid.h
index d7e98ff..bb206c5 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -147,9 +147,9 @@
 #define do_each_pid_task(pid, type, task)				\
 	do {								\
 		struct hlist_node *pos___;				\
-		if (pid != NULL)					\
+		if ((pid) != NULL)					\
 			hlist_for_each_entry_rcu((task), pos___,	\
-				&pid->tasks[type], pids[type].node) {
+				&(pid)->tasks[type], pids[type].node) {
 
 			/*
 			 * Both old and new leaders may be attached to
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index 7cf7824d..e6aa848 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -394,6 +394,20 @@
 
 #define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1)
 
+
+/* Cgroup classifier */
+
+enum
+{
+	TCA_CGROUP_UNSPEC,
+	TCA_CGROUP_ACT,
+	TCA_CGROUP_POLICE,
+	TCA_CGROUP_EMATCHES,
+	__TCA_CGROUP_MAX,
+};
+
+#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1)
+
 /* Extended Matches */
 
 struct tcf_ematch_tree_hdr
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index 5d921fa..e3f133a 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -500,4 +500,20 @@
 
 #define NETEM_DIST_SCALE	8192
 
+/* DRR */
+
+enum
+{
+	TCA_DRR_UNSPEC,
+	TCA_DRR_QUANTUM,
+	__TCA_DRR_MAX
+};
+
+#define TCA_DRR_MAX	(__TCA_DRR_MAX - 1)
+
+struct tc_drr_stats
+{
+	u32	deficit;
+};
+
 #endif
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 22641d5..98b93ca 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -94,6 +94,7 @@
 extern void __ptrace_link(struct task_struct *child,
 			  struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
+extern void ptrace_fork(struct task_struct *task, unsigned long clone_flags);
 #define PTRACE_MODE_READ   1
 #define PTRACE_MODE_ATTACH 2
 /* Returns 0 on success, -errno on denial. */
@@ -313,6 +314,27 @@
 #define arch_ptrace_stop(code, info)		do { } while (0)
 #endif
 
+#ifndef arch_ptrace_untrace
+/*
+ * Do machine-specific work before untracing child.
+ *
+ * This is called for a normal detach as well as from ptrace_exit()
+ * when the tracing task dies.
+ *
+ * Called with write_lock(&tasklist_lock) held.
+ */
+#define arch_ptrace_untrace(task)		do { } while (0)
+#endif
+
+#ifndef arch_ptrace_fork
+/*
+ * Do machine-specific work to initialize a new task.
+ *
+ * This is called from copy_process().
+ */
+#define arch_ptrace_fork(child, clone_flags)	do { } while (0)
+#endif
+
 extern int task_current_syscall(struct task_struct *target, long *callno,
 				unsigned long args[6], unsigned int maxargs,
 				unsigned long *sp, unsigned long *pc);
diff --git a/include/linux/rculist_nulls.h b/include/linux/rculist_nulls.h
new file mode 100644
index 0000000..f9ddd03
--- /dev/null
+++ b/include/linux/rculist_nulls.h
@@ -0,0 +1,110 @@
+#ifndef _LINUX_RCULIST_NULLS_H
+#define _LINUX_RCULIST_NULLS_H
+
+#ifdef __KERNEL__
+
+/*
+ * RCU-protected list version
+ */
+#include <linux/list_nulls.h>
+#include <linux/rcupdate.h>
+
+/**
+ * hlist_nulls_del_init_rcu - deletes entry from hash list with re-initialization
+ * @n: the element to delete from the hash list.
+ *
+ * Note: hlist_nulls_unhashed() on the node return true after this. It is
+ * useful for RCU based read lockfree traversal if the writer side
+ * must know if the list entry is still hashed or already unhashed.
+ *
+ * In particular, it means that we can not poison the forward pointers
+ * that may still be used for walking the hash list and we can only
+ * zero the pprev pointer so list_unhashed() will return true after
+ * this.
+ *
+ * The caller must take whatever precautions are necessary (such as
+ * holding appropriate locks) to avoid racing with another
+ * list-mutation primitive, such as hlist_nulls_add_head_rcu() or
+ * hlist_nulls_del_rcu(), running on this same list.  However, it is
+ * perfectly legal to run concurrently with the _rcu list-traversal
+ * primitives, such as hlist_nulls_for_each_entry_rcu().
+ */
+static inline void hlist_nulls_del_init_rcu(struct hlist_nulls_node *n)
+{
+	if (!hlist_nulls_unhashed(n)) {
+		__hlist_nulls_del(n);
+		n->pprev = NULL;
+	}
+}
+
+/**
+ * hlist_nulls_del_rcu - deletes entry from hash list without re-initialization
+ * @n: the element to delete from the hash list.
+ *
+ * Note: hlist_nulls_unhashed() on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the hash list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_nulls_add_head_rcu()
+ * or hlist_nulls_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_nulls_for_each_entry().
+ */
+static inline void hlist_nulls_del_rcu(struct hlist_nulls_node *n)
+{
+	__hlist_nulls_del(n);
+	n->pprev = LIST_POISON2;
+}
+
+/**
+ * hlist_nulls_add_head_rcu
+ * @n: the element to add to the hash list.
+ * @h: the list to add to.
+ *
+ * Description:
+ * Adds the specified element to the specified hlist_nulls,
+ * while permitting racing traversals.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_nulls_add_head_rcu()
+ * or hlist_nulls_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_nulls_for_each_entry_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs.  Regardless of the type of CPU, the
+ * list-traversal primitive must be guarded by rcu_read_lock().
+ */
+static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n,
+					struct hlist_nulls_head *h)
+{
+	struct hlist_nulls_node *first = h->first;
+
+	n->next = first;
+	n->pprev = &h->first;
+	rcu_assign_pointer(h->first, n);
+	if (!is_a_nulls(first))
+		first->pprev = &n->next;
+}
+/**
+ * hlist_nulls_for_each_entry_rcu - iterate over rcu list of given type
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_nulls_node to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the hlist_nulls_node within the struct.
+ *
+ */
+#define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member) \
+	for (pos = rcu_dereference((head)->first);			 \
+		(!is_a_nulls(pos)) && 			\
+		({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1; }); \
+		pos = rcu_dereference(pos->next))
+
+#endif
+#endif
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 86f1f5e..895dc9c 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -142,6 +142,7 @@
  * on the write-side to insure proper synchronization.
  */
 #define rcu_read_lock_sched() preempt_disable()
+#define rcu_read_lock_sched_notrace() preempt_disable_notrace()
 
 /*
  * rcu_read_unlock_sched - marks the end of a RCU-classic critical section
@@ -149,6 +150,7 @@
  * See rcu_read_lock_sched for more information.
  */
 #define rcu_read_unlock_sched() preempt_enable()
+#define rcu_read_unlock_sched_notrace() preempt_enable_notrace()
 
 
 
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index 4cd64b0..164332c 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -108,6 +108,7 @@
 
 	struct device dev;
 	struct list_head node;
+	enum rfkill_state state_for_resume;
 };
 #define to_rfkill(d)	container_of(d, struct rfkill, dev)
 
@@ -148,11 +149,4 @@
 #endif
 }
 
-/* rfkill notification chain */
-#define RFKILL_STATE_CHANGED		0x0001	/* state of a normal rfkill
-						   switch has changed */
-
-int register_rfkill_notifier(struct notifier_block *nb);
-int unregister_rfkill_notifier(struct notifier_block *nb);
-
 #endif /* RFKILL_H */
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index e097c2e..d363467 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -28,17 +28,19 @@
  *				 size = 8 bytes
  *
  * @RINGBUF_TYPE_TIME_STAMP:	Sync time stamp with external clock
- *				 array[0] = tv_nsec
- *				 array[1] = tv_sec
+ *				 array[0]    = tv_nsec
+ *				 array[1..2] = tv_sec
  *				 size = 16 bytes
  *
  * @RINGBUF_TYPE_DATA:		Data record
  *				 If len is zero:
  *				  array[0] holds the actual length
- *				  array[1..(length+3)/4-1] holds data
+ *				  array[1..(length+3)/4] holds data
+ *				  size = 4 + 4 + length (bytes)
  *				 else
  *				  length = len << 2
- *				  array[0..(length+3)/4] holds data
+ *				  array[0..(length+3)/4-1] holds data
+ *				  size = 4 + length (bytes)
  */
 enum ring_buffer_type {
 	RINGBUF_TYPE_PADDING,
@@ -122,6 +124,12 @@
 
 void tracing_on(void);
 void tracing_off(void);
+void tracing_off_permanent(void);
+
+void *ring_buffer_alloc_read_page(struct ring_buffer *buffer);
+void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data);
+int ring_buffer_read_page(struct ring_buffer *buffer,
+			  void **data_page, int cpu, int full);
 
 enum ring_buffer_flags {
 	RB_FL_OVERWRITE		= 1 << 0,
diff --git a/include/linux/rio_drv.h b/include/linux/rio_drv.h
index 90987b7..32c0547 100644
--- a/include/linux/rio_drv.h
+++ b/include/linux/rio_drv.h
@@ -427,9 +427,9 @@
  * Get the unique RIO device identifier. Returns the device
  * identifier string.
  */
-static inline char *rio_name(struct rio_dev *rdev)
+static inline const char *rio_name(struct rio_dev *rdev)
 {
-	return rdev->dev.bus_id;
+	return dev_name(&rdev->dev);
 }
 
 /**
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 2b3d51c..e88f705 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -107,6 +107,11 @@
 	RTM_GETADDRLABEL,
 #define RTM_GETADDRLABEL RTM_GETADDRLABEL
 
+	RTM_GETDCB = 78,
+#define RTM_GETDCB RTM_GETDCB
+	RTM_SETDCB,
+#define RTM_SETDCB RTM_SETDCB
+
 	__RTM_MAX,
 #define RTM_MAX		(((__RTM_MAX + 3) & ~3) - 1)
 };
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 55e30d1..8395e71 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -96,6 +96,7 @@
 struct futex_pi_state;
 struct robust_list_head;
 struct bio;
+struct bts_tracer;
 
 /*
  * List of flags we want to share for kernel threads,
@@ -259,8 +260,6 @@
 }
 #endif
 
-extern unsigned long rt_needs_cpu(int cpu);
-
 /*
  * Only dump TASK_* tasks. (0 for all tasks)
  */
@@ -572,12 +571,6 @@
 	 */
 	struct rlimit rlim[RLIM_NLIMITS];
 
-	/* keep the process-shared keyrings here so that they do the right
-	 * thing in threads created with CLONE_THREAD */
-#ifdef CONFIG_KEYS
-	struct key *session_keyring;	/* keyring inherited over fork */
-	struct key *process_keyring;	/* keyring private to this process */
-#endif
 #ifdef CONFIG_BSD_PROCESS_ACCT
 	struct pacct_struct pacct;	/* per-process accounting information */
 #endif
@@ -648,6 +641,7 @@
 	/* Hash table maintenance information */
 	struct hlist_node uidhash_node;
 	uid_t uid;
+	struct user_namespace *user_ns;
 
 #ifdef CONFIG_USER_SCHED
 	struct task_group *tg;
@@ -665,6 +659,7 @@
 extern struct user_struct root_user;
 #define INIT_USER (&root_user)
 
+
 struct backing_dev_info;
 struct reclaim_state;
 
@@ -672,8 +667,7 @@
 struct sched_info {
 	/* cumulative counters */
 	unsigned long pcount;	      /* # of times run on this cpu */
-	unsigned long long cpu_time,  /* time spent on the cpu */
-			   run_delay; /* time spent waiting on a runqueue */
+	unsigned long long run_delay; /* time spent waiting on a runqueue */
 
 	/* timestamps */
 	unsigned long long last_arrival,/* when we last ran on a cpu */
@@ -888,38 +882,7 @@
 #endif	/* !CONFIG_SMP */
 
 struct io_context;			/* See blkdev.h */
-#define NGROUPS_SMALL		32
-#define NGROUPS_PER_BLOCK	((unsigned int)(PAGE_SIZE / sizeof(gid_t)))
-struct group_info {
-	int ngroups;
-	atomic_t usage;
-	gid_t small_block[NGROUPS_SMALL];
-	int nblocks;
-	gid_t *blocks[0];
-};
 
-/*
- * get_group_info() must be called with the owning task locked (via task_lock())
- * when task != current.  The reason being that the vast majority of callers are
- * looking at current->group_info, which can not be changed except by the
- * current task.  Changing current->group_info requires the task lock, too.
- */
-#define get_group_info(group_info) do { \
-	atomic_inc(&(group_info)->usage); \
-} while (0)
-
-#define put_group_info(group_info) do { \
-	if (atomic_dec_and_test(&(group_info)->usage)) \
-		groups_free(group_info); \
-} while (0)
-
-extern struct group_info *groups_alloc(int gidsetsize);
-extern void groups_free(struct group_info *group_info);
-extern int set_current_groups(struct group_info *group_info);
-extern int groups_search(struct group_info *group_info, gid_t grp);
-/* access the groups "array" with this macro */
-#define GROUP_AT(gi, i) \
-    ((gi)->blocks[(i)/NGROUPS_PER_BLOCK][(i)%NGROUPS_PER_BLOCK])
 
 #ifdef ARCH_HAS_PREFETCH_SWITCH_STACK
 extern void prefetch_stack(struct task_struct *t);
@@ -1165,6 +1128,19 @@
 	struct list_head ptraced;
 	struct list_head ptrace_entry;
 
+#ifdef CONFIG_X86_PTRACE_BTS
+	/*
+	 * This is the tracer handle for the ptrace BTS extension.
+	 * This field actually belongs to the ptracer task.
+	 */
+	struct bts_tracer *bts;
+	/*
+	 * The buffer to hold the BTS data.
+	 */
+	void *bts_buffer;
+	size_t bts_size;
+#endif /* CONFIG_X86_PTRACE_BTS */
+
 	/* PID/PID hash table linkage. */
 	struct pid_link pids[PIDTYPE_MAX];
 	struct list_head thread_group;
@@ -1186,17 +1162,12 @@
 	struct list_head cpu_timers[3];
 
 /* process credentials */
-	uid_t uid,euid,suid,fsuid;
-	gid_t gid,egid,sgid,fsgid;
-	struct group_info *group_info;
-	kernel_cap_t   cap_effective, cap_inheritable, cap_permitted, cap_bset;
-	struct user_struct *user;
-	unsigned securebits;
-#ifdef CONFIG_KEYS
-	unsigned char jit_keyring;	/* default keyring to attach requested keys to */
-	struct key *request_key_auth;	/* assumed request_key authority */
-	struct key *thread_keyring;	/* keyring private to this thread */
-#endif
+	const struct cred *real_cred;	/* objective and real subjective task
+					 * credentials (COW) */
+	const struct cred *cred;	/* effective (overridable) subjective task
+					 * credentials (COW) */
+	struct mutex cred_exec_mutex;	/* execve vs ptrace cred calculation mutex */
+
 	char comm[TASK_COMM_LEN]; /* executable name excluding path
 				     - access with [gs]et_task_comm (which lock
 				       it with task_lock())
@@ -1233,9 +1204,6 @@
 	int (*notifier)(void *priv);
 	void *notifier_data;
 	sigset_t *notifier_mask;
-#ifdef CONFIG_SECURITY
-	void *security;
-#endif
 	struct audit_context *audit_context;
 #ifdef CONFIG_AUDITSYSCALL
 	uid_t loginuid;
@@ -1356,6 +1324,23 @@
 	unsigned long default_timer_slack_ns;
 
 	struct list_head	*scm_work_list;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	/* Index of current stored adress in ret_stack */
+	int curr_ret_stack;
+	/* Stack of return addresses for return function tracing */
+	struct ftrace_ret_stack	*ret_stack;
+	/*
+	 * Number of functions that haven't been traced
+	 * because of depth overrun.
+	 */
+	atomic_t trace_overrun;
+	/* Pause for the tracing */
+	atomic_t tracing_graph_pause;
+#endif
+#ifdef CONFIG_TRACING
+	/* state flags for use by tracers */
+	unsigned long trace;
+#endif
 };
 
 /*
@@ -1775,7 +1760,6 @@
 	return u;
 }
 extern void free_uid(struct user_struct *);
-extern void switch_uid(struct user_struct *);
 extern void release_uids(struct user_namespace *ns);
 
 #include <asm/current.h>
@@ -1794,9 +1778,6 @@
 extern void sched_fork(struct task_struct *p, int clone_flags);
 extern void sched_dead(struct task_struct *p);
 
-extern int in_group_p(gid_t);
-extern int in_egroup_p(gid_t);
-
 extern void proc_caches_init(void);
 extern void flush_signals(struct task_struct *);
 extern void ignore_signals(struct task_struct *);
@@ -1928,6 +1909,8 @@
 #define for_each_process(p) \
 	for (p = &init_task ; (p = next_task(p)) != &init_task ; )
 
+extern bool is_single_threaded(struct task_struct *);
+
 /*
  * Careful: do_each_thread/while_each_thread is a double loop so
  *          'break' will not work as expected - use goto instead.
@@ -2224,6 +2207,7 @@
 extern struct task_group init_task_group;
 #ifdef CONFIG_USER_SCHED
 extern struct task_group root_task_group;
+extern void set_tg_uid(struct user_struct *user);
 #endif
 
 extern struct task_group *sched_create_group(struct task_group *parent);
diff --git a/include/linux/securebits.h b/include/linux/securebits.h
index 92f09bd..d2c5ed8 100644
--- a/include/linux/securebits.h
+++ b/include/linux/securebits.h
@@ -32,7 +32,7 @@
    setting is locked or not. A setting which is locked cannot be
    changed from user-level. */
 #define issecure_mask(X)	(1 << (X))
-#define issecure(X)		(issecure_mask(X) & current->securebits)
+#define issecure(X)		(issecure_mask(X) & current_cred_xxx(securebits))
 
 #define SECURE_ALL_BITS		(issecure_mask(SECURE_NOROOT) | \
 				 issecure_mask(SECURE_NO_SETUID_FIXUP) | \
diff --git a/include/linux/security.h b/include/linux/security.h
index e3d4ecd..3416cb8 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -37,6 +37,10 @@
 /* Maximum number of letters for an LSM name string */
 #define SECURITY_NAME_MAX	10
 
+/* If capable should audit the security request */
+#define SECURITY_CAP_NOAUDIT 0
+#define SECURITY_CAP_AUDIT 1
+
 struct ctl_table;
 struct audit_krule;
 
@@ -44,25 +48,25 @@
  * These functions are in security/capability.c and are used
  * as the default capabilities functions
  */
-extern int cap_capable(struct task_struct *tsk, int cap);
+extern int cap_capable(struct task_struct *tsk, int cap, int audit);
 extern int cap_settime(struct timespec *ts, struct timezone *tz);
 extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
 extern int cap_ptrace_traceme(struct task_struct *parent);
 extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern int cap_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern void cap_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern int cap_bprm_set_security(struct linux_binprm *bprm);
-extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
+extern int cap_capset(struct cred *new, const struct cred *old,
+		      const kernel_cap_t *effective,
+		      const kernel_cap_t *inheritable,
+		      const kernel_cap_t *permitted);
+extern int cap_bprm_set_creds(struct linux_binprm *bprm);
 extern int cap_bprm_secureexec(struct linux_binprm *bprm);
 extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
 			      const void *value, size_t size, int flags);
 extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
 extern int cap_inode_need_killpriv(struct dentry *dentry);
 extern int cap_inode_killpriv(struct dentry *dentry);
-extern int cap_task_post_setuid(uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
-extern void cap_task_reparent_to_init(struct task_struct *p);
+extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags);
 extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
-			  unsigned long arg4, unsigned long arg5, long *rc_p);
+			  unsigned long arg4, unsigned long arg5);
 extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp);
 extern int cap_task_setioprio(struct task_struct *p, int ioprio);
 extern int cap_task_setnice(struct task_struct *p, int nice);
@@ -105,7 +109,7 @@
 struct sched_param;
 struct request_sock;
 
-/* bprm_apply_creds unsafe reasons */
+/* bprm->unsafe reasons */
 #define LSM_UNSAFE_SHARE	1
 #define LSM_UNSAFE_PTRACE	2
 #define LSM_UNSAFE_PTRACE_CAP	4
@@ -149,36 +153,7 @@
  *
  * Security hooks for program execution operations.
  *
- * @bprm_alloc_security:
- *	Allocate and attach a security structure to the @bprm->security field.
- *	The security field is initialized to NULL when the bprm structure is
- *	allocated.
- *	@bprm contains the linux_binprm structure to be modified.
- *	Return 0 if operation was successful.
- * @bprm_free_security:
- *	@bprm contains the linux_binprm structure to be modified.
- *	Deallocate and clear the @bprm->security field.
- * @bprm_apply_creds:
- *	Compute and set the security attributes of a process being transformed
- *	by an execve operation based on the old attributes (current->security)
- *	and the information saved in @bprm->security by the set_security hook.
- *	Since this hook function (and its caller) are void, this hook can not
- *	return an error.  However, it can leave the security attributes of the
- *	process unchanged if an access failure occurs at this point.
- *	bprm_apply_creds is called under task_lock.  @unsafe indicates various
- *	reasons why it may be unsafe to change security state.
- *	@bprm contains the linux_binprm structure.
- * @bprm_post_apply_creds:
- *	Runs after bprm_apply_creds with the task_lock dropped, so that
- *	functions which cannot be called safely under the task_lock can
- *	be used.  This hook is a good place to perform state changes on
- *	the process such as closing open file descriptors to which access
- *	is no longer granted if the attributes were changed.
- *	Note that a security module might need to save state between
- *	bprm_apply_creds and bprm_post_apply_creds to store the decision
- *	on whether the process may proceed.
- *	@bprm contains the linux_binprm structure.
- * @bprm_set_security:
+ * @bprm_set_creds:
  *	Save security information in the bprm->security field, typically based
  *	on information about the bprm->file, for later use by the apply_creds
  *	hook.  This hook may also optionally check permissions (e.g. for
@@ -191,15 +166,30 @@
  *	@bprm contains the linux_binprm structure.
  *	Return 0 if the hook is successful and permission is granted.
  * @bprm_check_security:
- *	This hook mediates the point when a search for a binary handler	will
- *	begin.  It allows a check the @bprm->security value which is set in
- *	the preceding set_security call.  The primary difference from
- *	set_security is that the argv list and envp list are reliably
- *	available in @bprm.  This hook may be called multiple times
- *	during a single execve; and in each pass set_security is called
- *	first.
+ *	This hook mediates the point when a search for a binary handler will
+ *	begin.  It allows a check the @bprm->security value which is set in the
+ *	preceding set_creds call.  The primary difference from set_creds is
+ *	that the argv list and envp list are reliably available in @bprm.  This
+ *	hook may be called multiple times during a single execve; and in each
+ *	pass set_creds is called first.
  *	@bprm contains the linux_binprm structure.
  *	Return 0 if the hook is successful and permission is granted.
+ * @bprm_committing_creds:
+ *	Prepare to install the new security attributes of a process being
+ *	transformed by an execve operation, based on the old credentials
+ *	pointed to by @current->cred and the information set in @bprm->cred by
+ *	the bprm_set_creds hook.  @bprm points to the linux_binprm structure.
+ *	This hook is a good place to perform state changes on the process such
+ *	as closing open file descriptors to which access will no longer be
+ *	granted when the attributes are changed.  This is called immediately
+ *	before commit_creds().
+ * @bprm_committed_creds:
+ *	Tidy up after the installation of the new security attributes of a
+ *	process being transformed by an execve operation.  The new credentials
+ *	have, by this point, been set to @current->cred.  @bprm points to the
+ *	linux_binprm structure.  This hook is a good place to perform state
+ *	changes on the process such as clearing out non-inheritable signal
+ *	state.  This is called immediately after commit_creds().
  * @bprm_secureexec:
  *	Return a boolean value (0 or 1) indicating whether a "secure exec"
  *	is required.  The flag is passed in the auxiliary table
@@ -585,15 +575,31 @@
  *	manual page for definitions of the @clone_flags.
  *	@clone_flags contains the flags indicating what should be shared.
  *	Return 0 if permission is granted.
- * @task_alloc_security:
- *	@p contains the task_struct for child process.
- *	Allocate and attach a security structure to the p->security field. The
- *	security field is initialized to NULL when the task structure is
- *	allocated.
- *	Return 0 if operation was successful.
- * @task_free_security:
- *	@p contains the task_struct for process.
- *	Deallocate and clear the p->security field.
+ * @cred_free:
+ *	@cred points to the credentials.
+ *	Deallocate and clear the cred->security field in a set of credentials.
+ * @cred_prepare:
+ *	@new points to the new credentials.
+ *	@old points to the original credentials.
+ *	@gfp indicates the atomicity of any memory allocations.
+ *	Prepare a new set of credentials by copying the data from the old set.
+ * @cred_commit:
+ *	@new points to the new credentials.
+ *	@old points to the original credentials.
+ *	Install a new set of credentials.
+ * @kernel_act_as:
+ *	Set the credentials for a kernel service to act as (subjective context).
+ *	@new points to the credentials to be modified.
+ *	@secid specifies the security ID to be set
+ *	The current task must be the one that nominated @secid.
+ *	Return 0 if successful.
+ * @kernel_create_files_as:
+ *	Set the file creation context in a set of credentials to be the same as
+ *	the objective context of the specified inode.
+ *	@new points to the credentials to be modified.
+ *	@inode points to the inode to use as a reference.
+ *	The current task must be the one that nominated @inode.
+ *	Return 0 if successful.
  * @task_setuid:
  *	Check permission before setting one or more of the user identity
  *	attributes of the current process.  The @flags parameter indicates
@@ -606,15 +612,13 @@
  *	@id2 contains a uid.
  *	@flags contains one of the LSM_SETID_* values.
  *	Return 0 if permission is granted.
- * @task_post_setuid:
+ * @task_fix_setuid:
  *	Update the module's state after setting one or more of the user
  *	identity attributes of the current process.  The @flags parameter
  *	indicates which of the set*uid system calls invoked this hook.  If
- *	@flags is LSM_SETID_FS, then @old_ruid is the old fs uid and the other
- *	parameters are not used.
- *	@old_ruid contains the old real uid (or fs uid if LSM_SETID_FS).
- *	@old_euid contains the old effective uid (or -1 if LSM_SETID_FS).
- *	@old_suid contains the old saved uid (or -1 if LSM_SETID_FS).
+ *	@new is the set of credentials that will be installed.  Modifications
+ *	should be made to this rather than to @current->cred.
+ *	@old is the set of credentials that are being replaces
  *	@flags contains one of the LSM_SETID_* values.
  *	Return 0 on success.
  * @task_setgid:
@@ -717,13 +721,8 @@
  *	@arg3 contains a argument.
  *	@arg4 contains a argument.
  *	@arg5 contains a argument.
- *      @rc_p contains a pointer to communicate back the forced return code
- *	Return 0 if permission is granted, and non-zero if the security module
- *      has taken responsibility (setting *rc_p) for the prctl call.
- * @task_reparent_to_init:
- *	Set the security attributes in @p->security for a kernel thread that
- *	is being reparented to the init task.
- *	@p contains the task_struct for the kernel thread.
+ *	Return -ENOSYS if no-one wanted to handle this op, any other value to
+ *	cause prctl() to return immediately with that value.
  * @task_to_inode:
  *	Set the security attributes for an inode based on an associated task's
  *	security attributes, e.g. for /proc/pid inodes.
@@ -1000,7 +999,7 @@
  *	See whether a specific operational right is granted to a process on a
  *	key.
  *	@key_ref refers to the key (key pointer + possession attribute bit).
- *	@context points to the process to provide the context against which to
+ *	@cred points to the credentials to provide the context against which to
  *	evaluate the security data on the key.
  *	@perm describes the combination of permissions required of this key.
  *	Return 1 if permission granted, 0 if permission denied and -ve it the
@@ -1162,6 +1161,7 @@
  *	@child process.
  *	Security modules may also want to perform a process tracing check
  *	during an execve in the set_security or apply_creds hooks of
+ *	tracing check during an execve in the bprm_set_creds hook of
  *	binprm_security_ops if the process is being traced and its security
  *	attributes would be changed by the execve.
  *	@child contains the task_struct structure for the target process.
@@ -1185,29 +1185,15 @@
  *	@inheritable contains the inheritable capability set.
  *	@permitted contains the permitted capability set.
  *	Return 0 if the capability sets were successfully obtained.
- * @capset_check:
- *	Check permission before setting the @effective, @inheritable, and
- *	@permitted capability sets for the @target process.
- *	Caveat:  @target is also set to current if a set of processes is
- *	specified (i.e. all processes other than current and init or a
- *	particular process group).  Hence, the capset_set hook may need to
- *	revalidate permission to the actual target process.
- *	@target contains the task_struct structure for target process.
- *	@effective contains the effective capability set.
- *	@inheritable contains the inheritable capability set.
- *	@permitted contains the permitted capability set.
- *	Return 0 if permission is granted.
- * @capset_set:
+ * @capset:
  *	Set the @effective, @inheritable, and @permitted capability sets for
- *	the @target process.  Since capset_check cannot always check permission
- *	to the real @target process, this hook may also perform permission
- *	checking to determine if the current process is allowed to set the
- *	capability sets of the @target process.  However, this hook has no way
- *	of returning an error due to the structure of the sys_capset code.
- *	@target contains the task_struct structure for target process.
+ *	the current process.
+ *	@new contains the new credentials structure for target process.
+ *	@old contains the current credentials structure for target process.
  *	@effective contains the effective capability set.
  *	@inheritable contains the inheritable capability set.
  *	@permitted contains the permitted capability set.
+ *	Return 0 and update @new if permission is granted.
  * @capable:
  *	Check whether the @tsk process has the @cap capability.
  *	@tsk contains the task_struct for the process.
@@ -1299,15 +1285,12 @@
 	int (*capget) (struct task_struct *target,
 		       kernel_cap_t *effective,
 		       kernel_cap_t *inheritable, kernel_cap_t *permitted);
-	int (*capset_check) (struct task_struct *target,
-			     kernel_cap_t *effective,
-			     kernel_cap_t *inheritable,
-			     kernel_cap_t *permitted);
-	void (*capset_set) (struct task_struct *target,
-			    kernel_cap_t *effective,
-			    kernel_cap_t *inheritable,
-			    kernel_cap_t *permitted);
-	int (*capable) (struct task_struct *tsk, int cap);
+	int (*capset) (struct cred *new,
+		       const struct cred *old,
+		       const kernel_cap_t *effective,
+		       const kernel_cap_t *inheritable,
+		       const kernel_cap_t *permitted);
+	int (*capable) (struct task_struct *tsk, int cap, int audit);
 	int (*acct) (struct file *file);
 	int (*sysctl) (struct ctl_table *table, int op);
 	int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
@@ -1316,18 +1299,16 @@
 	int (*settime) (struct timespec *ts, struct timezone *tz);
 	int (*vm_enough_memory) (struct mm_struct *mm, long pages);
 
-	int (*bprm_alloc_security) (struct linux_binprm *bprm);
-	void (*bprm_free_security) (struct linux_binprm *bprm);
-	void (*bprm_apply_creds) (struct linux_binprm *bprm, int unsafe);
-	void (*bprm_post_apply_creds) (struct linux_binprm *bprm);
-	int (*bprm_set_security) (struct linux_binprm *bprm);
+	int (*bprm_set_creds) (struct linux_binprm *bprm);
 	int (*bprm_check_security) (struct linux_binprm *bprm);
 	int (*bprm_secureexec) (struct linux_binprm *bprm);
+	void (*bprm_committing_creds) (struct linux_binprm *bprm);
+	void (*bprm_committed_creds) (struct linux_binprm *bprm);
 
 	int (*sb_alloc_security) (struct super_block *sb);
 	void (*sb_free_security) (struct super_block *sb);
 	int (*sb_copy_data) (char *orig, char *copy);
-	int (*sb_kern_mount) (struct super_block *sb, void *data);
+	int (*sb_kern_mount) (struct super_block *sb, int flags, void *data);
 	int (*sb_show_options) (struct seq_file *m, struct super_block *sb);
 	int (*sb_statfs) (struct dentry *dentry);
 	int (*sb_mount) (char *dev_name, struct path *path,
@@ -1406,14 +1387,18 @@
 	int (*file_send_sigiotask) (struct task_struct *tsk,
 				    struct fown_struct *fown, int sig);
 	int (*file_receive) (struct file *file);
-	int (*dentry_open) (struct file *file);
+	int (*dentry_open) (struct file *file, const struct cred *cred);
 
 	int (*task_create) (unsigned long clone_flags);
-	int (*task_alloc_security) (struct task_struct *p);
-	void (*task_free_security) (struct task_struct *p);
+	void (*cred_free) (struct cred *cred);
+	int (*cred_prepare)(struct cred *new, const struct cred *old,
+			    gfp_t gfp);
+	void (*cred_commit)(struct cred *new, const struct cred *old);
+	int (*kernel_act_as)(struct cred *new, u32 secid);
+	int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
 	int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags);
-	int (*task_post_setuid) (uid_t old_ruid /* or fsuid */ ,
-				 uid_t old_euid, uid_t old_suid, int flags);
+	int (*task_fix_setuid) (struct cred *new, const struct cred *old,
+				int flags);
 	int (*task_setgid) (gid_t id0, gid_t id1, gid_t id2, int flags);
 	int (*task_setpgid) (struct task_struct *p, pid_t pgid);
 	int (*task_getpgid) (struct task_struct *p);
@@ -1433,8 +1418,7 @@
 	int (*task_wait) (struct task_struct *p);
 	int (*task_prctl) (int option, unsigned long arg2,
 			   unsigned long arg3, unsigned long arg4,
-			   unsigned long arg5, long *rc_p);
-	void (*task_reparent_to_init) (struct task_struct *p);
+			   unsigned long arg5);
 	void (*task_to_inode) (struct task_struct *p, struct inode *inode);
 
 	int (*ipc_permission) (struct kern_ipc_perm *ipcp, short flag);
@@ -1539,10 +1523,10 @@
 
 	/* key management security hooks */
 #ifdef CONFIG_KEYS
-	int (*key_alloc) (struct key *key, struct task_struct *tsk, unsigned long flags);
+	int (*key_alloc) (struct key *key, const struct cred *cred, unsigned long flags);
 	void (*key_free) (struct key *key);
 	int (*key_permission) (key_ref_t key_ref,
-			       struct task_struct *context,
+			       const struct cred *cred,
 			       key_perm_t perm);
 	int (*key_getsecurity)(struct key *key, char **_buffer);
 #endif	/* CONFIG_KEYS */
@@ -1568,15 +1552,12 @@
 		    kernel_cap_t *effective,
 		    kernel_cap_t *inheritable,
 		    kernel_cap_t *permitted);
-int security_capset_check(struct task_struct *target,
-			  kernel_cap_t *effective,
-			  kernel_cap_t *inheritable,
-			  kernel_cap_t *permitted);
-void security_capset_set(struct task_struct *target,
-			 kernel_cap_t *effective,
-			 kernel_cap_t *inheritable,
-			 kernel_cap_t *permitted);
+int security_capset(struct cred *new, const struct cred *old,
+		    const kernel_cap_t *effective,
+		    const kernel_cap_t *inheritable,
+		    const kernel_cap_t *permitted);
 int security_capable(struct task_struct *tsk, int cap);
+int security_capable_noaudit(struct task_struct *tsk, int cap);
 int security_acct(struct file *file);
 int security_sysctl(struct ctl_table *table, int op);
 int security_quotactl(int cmds, int type, int id, struct super_block *sb);
@@ -1586,17 +1567,15 @@
 int security_vm_enough_memory(long pages);
 int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
 int security_vm_enough_memory_kern(long pages);
-int security_bprm_alloc(struct linux_binprm *bprm);
-void security_bprm_free(struct linux_binprm *bprm);
-void security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
-void security_bprm_post_apply_creds(struct linux_binprm *bprm);
-int security_bprm_set(struct linux_binprm *bprm);
+int security_bprm_set_creds(struct linux_binprm *bprm);
 int security_bprm_check(struct linux_binprm *bprm);
+void security_bprm_committing_creds(struct linux_binprm *bprm);
+void security_bprm_committed_creds(struct linux_binprm *bprm);
 int security_bprm_secureexec(struct linux_binprm *bprm);
 int security_sb_alloc(struct super_block *sb);
 void security_sb_free(struct super_block *sb);
 int security_sb_copy_data(char *orig, char *copy);
-int security_sb_kern_mount(struct super_block *sb, void *data);
+int security_sb_kern_mount(struct super_block *sb, int flags, void *data);
 int security_sb_show_options(struct seq_file *m, struct super_block *sb);
 int security_sb_statfs(struct dentry *dentry);
 int security_sb_mount(char *dev_name, struct path *path,
@@ -1663,13 +1642,16 @@
 int security_file_send_sigiotask(struct task_struct *tsk,
 				 struct fown_struct *fown, int sig);
 int security_file_receive(struct file *file);
-int security_dentry_open(struct file *file);
+int security_dentry_open(struct file *file, const struct cred *cred);
 int security_task_create(unsigned long clone_flags);
-int security_task_alloc(struct task_struct *p);
-void security_task_free(struct task_struct *p);
+void security_cred_free(struct cred *cred);
+int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
+void security_commit_creds(struct cred *new, const struct cred *old);
+int security_kernel_act_as(struct cred *new, u32 secid);
+int security_kernel_create_files_as(struct cred *new, struct inode *inode);
 int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags);
-int security_task_post_setuid(uid_t old_ruid, uid_t old_euid,
-			      uid_t old_suid, int flags);
+int security_task_fix_setuid(struct cred *new, const struct cred *old,
+			     int flags);
 int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags);
 int security_task_setpgid(struct task_struct *p, pid_t pgid);
 int security_task_getpgid(struct task_struct *p);
@@ -1688,8 +1670,7 @@
 			int sig, u32 secid);
 int security_task_wait(struct task_struct *p);
 int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
-			 unsigned long arg4, unsigned long arg5, long *rc_p);
-void security_task_reparent_to_init(struct task_struct *p);
+			unsigned long arg4, unsigned long arg5);
 void security_task_to_inode(struct task_struct *p, struct inode *inode);
 int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag);
 void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid);
@@ -1764,25 +1745,23 @@
 	return cap_capget(target, effective, inheritable, permitted);
 }
 
-static inline int security_capset_check(struct task_struct *target,
-					 kernel_cap_t *effective,
-					 kernel_cap_t *inheritable,
-					 kernel_cap_t *permitted)
+static inline int security_capset(struct cred *new,
+				   const struct cred *old,
+				   const kernel_cap_t *effective,
+				   const kernel_cap_t *inheritable,
+				   const kernel_cap_t *permitted)
 {
-	return cap_capset_check(target, effective, inheritable, permitted);
-}
-
-static inline void security_capset_set(struct task_struct *target,
-					kernel_cap_t *effective,
-					kernel_cap_t *inheritable,
-					kernel_cap_t *permitted)
-{
-	cap_capset_set(target, effective, inheritable, permitted);
+	return cap_capset(new, old, effective, inheritable, permitted);
 }
 
 static inline int security_capable(struct task_struct *tsk, int cap)
 {
-	return cap_capable(tsk, cap);
+	return cap_capable(tsk, cap, SECURITY_CAP_AUDIT);
+}
+
+static inline int security_capable_noaudit(struct task_struct *tsk, int cap)
+{
+	return cap_capable(tsk, cap, SECURITY_CAP_NOAUDIT);
 }
 
 static inline int security_acct(struct file *file)
@@ -1835,27 +1814,9 @@
 	return cap_vm_enough_memory(current->mm, pages);
 }
 
-static inline int security_bprm_alloc(struct linux_binprm *bprm)
+static inline int security_bprm_set_creds(struct linux_binprm *bprm)
 {
-	return 0;
-}
-
-static inline void security_bprm_free(struct linux_binprm *bprm)
-{ }
-
-static inline void security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
-{
-	cap_bprm_apply_creds(bprm, unsafe);
-}
-
-static inline void security_bprm_post_apply_creds(struct linux_binprm *bprm)
-{
-	return;
-}
-
-static inline int security_bprm_set(struct linux_binprm *bprm)
-{
-	return cap_bprm_set_security(bprm);
+	return cap_bprm_set_creds(bprm);
 }
 
 static inline int security_bprm_check(struct linux_binprm *bprm)
@@ -1863,6 +1824,14 @@
 	return 0;
 }
 
+static inline void security_bprm_committing_creds(struct linux_binprm *bprm)
+{
+}
+
+static inline void security_bprm_committed_creds(struct linux_binprm *bprm)
+{
+}
+
 static inline int security_bprm_secureexec(struct linux_binprm *bprm)
 {
 	return cap_bprm_secureexec(bprm);
@@ -1881,7 +1850,7 @@
 	return 0;
 }
 
-static inline int security_sb_kern_mount(struct super_block *sb, void *data)
+static inline int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
 {
 	return 0;
 }
@@ -2177,7 +2146,8 @@
 	return 0;
 }
 
-static inline int security_dentry_open(struct file *file)
+static inline int security_dentry_open(struct file *file,
+				       const struct cred *cred)
 {
 	return 0;
 }
@@ -2187,13 +2157,31 @@
 	return 0;
 }
 
-static inline int security_task_alloc(struct task_struct *p)
+static inline void security_cred_free(struct cred *cred)
+{ }
+
+static inline int security_prepare_creds(struct cred *new,
+					 const struct cred *old,
+					 gfp_t gfp)
 {
 	return 0;
 }
 
-static inline void security_task_free(struct task_struct *p)
-{ }
+static inline void security_commit_creds(struct cred *new,
+					 const struct cred *old)
+{
+}
+
+static inline int security_kernel_act_as(struct cred *cred, u32 secid)
+{
+	return 0;
+}
+
+static inline int security_kernel_create_files_as(struct cred *cred,
+						  struct inode *inode)
+{
+	return 0;
+}
 
 static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2,
 				       int flags)
@@ -2201,10 +2189,11 @@
 	return 0;
 }
 
-static inline int security_task_post_setuid(uid_t old_ruid, uid_t old_euid,
-					    uid_t old_suid, int flags)
+static inline int security_task_fix_setuid(struct cred *new,
+					   const struct cred *old,
+					   int flags)
 {
-	return cap_task_post_setuid(old_ruid, old_euid, old_suid, flags);
+	return cap_task_fix_setuid(new, old, flags);
 }
 
 static inline int security_task_setgid(gid_t id0, gid_t id1, gid_t id2,
@@ -2291,14 +2280,9 @@
 static inline int security_task_prctl(int option, unsigned long arg2,
 				      unsigned long arg3,
 				      unsigned long arg4,
-				      unsigned long arg5, long *rc_p)
+				      unsigned long arg5)
 {
-	return cap_task_prctl(option, arg2, arg3, arg3, arg5, rc_p);
-}
-
-static inline void security_task_reparent_to_init(struct task_struct *p)
-{
-	cap_task_reparent_to_init(p);
+	return cap_task_prctl(option, arg2, arg3, arg3, arg5);
 }
 
 static inline void security_task_to_inode(struct task_struct *p, struct inode *inode)
@@ -2724,16 +2708,16 @@
 #ifdef CONFIG_KEYS
 #ifdef CONFIG_SECURITY
 
-int security_key_alloc(struct key *key, struct task_struct *tsk, unsigned long flags);
+int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags);
 void security_key_free(struct key *key);
 int security_key_permission(key_ref_t key_ref,
-			    struct task_struct *context, key_perm_t perm);
+			    const struct cred *cred, key_perm_t perm);
 int security_key_getsecurity(struct key *key, char **_buffer);
 
 #else
 
 static inline int security_key_alloc(struct key *key,
-				     struct task_struct *tsk,
+				     const struct cred *cred,
 				     unsigned long flags)
 {
 	return 0;
@@ -2744,7 +2728,7 @@
 }
 
 static inline int security_key_permission(key_ref_t key_ref,
-					  struct task_struct *context,
+					  const struct cred *cred,
 					  key_perm_t perm)
 {
 	return 0;
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index dc50bcc..b3dfa72 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -34,6 +34,7 @@
 
 #define SEQ_SKIP 1
 
+char *mangle_path(char *s, char *p, char *esc);
 int seq_open(struct file *, const struct seq_operations *);
 ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
 loff_t seq_lseek(struct file *, loff_t, int);
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 2725f4e..cf2cb50 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -250,6 +250,9 @@
  *	@tc_verd: traffic control verdict
  *	@ndisc_nodetype: router type (from link layer)
  *	@do_not_encrypt: set to prevent encryption of this frame
+ *	@requeue: set to indicate that the wireless core should attempt
+ *		a software retry on this frame if we failed to
+ *		receive an ACK for it
  *	@dma_cookie: a cookie to one of several possible DMA operations
  *		done by skb DMA functions
  *	@secmark: security marking
@@ -269,8 +272,9 @@
 		struct  dst_entry	*dst;
 		struct  rtable		*rtable;
 	};
+#ifdef CONFIG_XFRM
 	struct	sec_path	*sp;
-
+#endif
 	/*
 	 * This is the control buffer. It is free to use for every
 	 * layer. Please put your private variables there. If you
@@ -325,6 +329,7 @@
 #endif
 #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
 	__u8			do_not_encrypt:1;
+	__u8			requeue:1;
 #endif
 	/* 0/13/14 bit hole */
 
@@ -488,6 +493,19 @@
 }
 
 /**
+ *	skb_queue_is_first - check if skb is the first entry in the queue
+ *	@list: queue head
+ *	@skb: buffer
+ *
+ *	Returns true if @skb is the first buffer on the list.
+ */
+static inline bool skb_queue_is_first(const struct sk_buff_head *list,
+				      const struct sk_buff *skb)
+{
+	return (skb->prev == (struct sk_buff *) list);
+}
+
+/**
  *	skb_queue_next - return the next packet in the queue
  *	@list: queue head
  *	@skb: current buffer
@@ -506,6 +524,24 @@
 }
 
 /**
+ *	skb_queue_prev - return the prev packet in the queue
+ *	@list: queue head
+ *	@skb: current buffer
+ *
+ *	Return the prev packet in @list before @skb.  It is only valid to
+ *	call this if skb_queue_is_first() evaluates to false.
+ */
+static inline struct sk_buff *skb_queue_prev(const struct sk_buff_head *list,
+					     const struct sk_buff *skb)
+{
+	/* This BUG_ON may seem severe, but if we just return then we
+	 * are going to dereference garbage.
+	 */
+	BUG_ON(skb_queue_is_first(list, skb));
+	return skb->prev;
+}
+
+/**
  *	skb_get - reference buffer
  *	@skb: buffer to reference
  *
@@ -1647,8 +1683,12 @@
 extern void	       skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
 extern void	       skb_split(struct sk_buff *skb,
 				 struct sk_buff *skb1, const u32 len);
+extern int	       skb_shift(struct sk_buff *tgt, struct sk_buff *skb,
+				 int shiftlen);
 
 extern struct sk_buff *skb_segment(struct sk_buff *skb, int features);
+extern int	       skb_gro_receive(struct sk_buff **head,
+				       struct sk_buff *skb);
 
 static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
 				       int len, void *buffer)
@@ -1864,6 +1904,18 @@
 	to->queue_mapping = from->queue_mapping;
 }
 
+#ifdef CONFIG_XFRM
+static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
+{
+	return skb->sp;
+}
+#else
+static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
+{
+	return NULL;
+}
+#endif
+
 static inline int skb_is_gso(const struct sk_buff *skb)
 {
 	return skb_shinfo(skb)->gso_size;
diff --git a/include/linux/smsc911x.h b/include/linux/smsc911x.h
new file mode 100644
index 0000000..1cbf031
--- /dev/null
+++ b/include/linux/smsc911x.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2004-2008 SMSC
+ * Copyright (C) 2005-2008 ARM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ ***************************************************************************/
+#ifndef __LINUX_SMSC911X_H__
+#define __LINUX_SMSC911X_H__
+
+#include <linux/phy.h>
+
+/* platform_device configuration data, should be assigned to
+ * the platform_device's dev.platform_data */
+struct smsc911x_platform_config {
+	unsigned int irq_polarity;
+	unsigned int irq_type;
+	unsigned int flags;
+	phy_interface_t phy_interface;
+};
+
+/* Constants for platform_device irq polarity configuration */
+#define SMSC911X_IRQ_POLARITY_ACTIVE_LOW	0
+#define SMSC911X_IRQ_POLARITY_ACTIVE_HIGH	1
+
+/* Constants for platform_device irq type configuration */
+#define SMSC911X_IRQ_TYPE_OPEN_DRAIN		0
+#define SMSC911X_IRQ_TYPE_PUSH_PULL		1
+
+/* Constants for flags */
+#define SMSC911X_USE_16BIT 			(BIT(0))
+#define SMSC911X_USE_32BIT 			(BIT(1))
+
+#endif /* __LINUX_SMSC911X_H__ */
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
index 7a6e6bb..aee3f1e 100644
--- a/include/linux/snmp.h
+++ b/include/linux/snmp.h
@@ -216,6 +216,9 @@
 	LINUX_MIB_TCPSPURIOUSRTOS,		/* TCPSpuriousRTOs */
 	LINUX_MIB_TCPMD5NOTFOUND,		/* TCPMD5NotFound */
 	LINUX_MIB_TCPMD5UNEXPECTED,		/* TCPMD5Unexpected */
+	LINUX_MIB_SACKSHIFTED,
+	LINUX_MIB_SACKMERGED,
+	LINUX_MIB_SACKSHIFTFALLBACK,
 	__LINUX_MIB_MAX
 };
 
diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h
index b106fd8..1a8cecc 100644
--- a/include/linux/stacktrace.h
+++ b/include/linux/stacktrace.h
@@ -15,9 +15,17 @@
 				struct stack_trace *trace);
 
 extern void print_stack_trace(struct stack_trace *trace, int spaces);
+
+#ifdef CONFIG_USER_STACKTRACE_SUPPORT
+extern void save_stack_trace_user(struct stack_trace *trace);
+#else
+# define save_stack_trace_user(trace)              do { } while (0)
+#endif
+
 #else
 # define save_stack_trace(trace)			do { } while (0)
 # define save_stack_trace_tsk(tsk, trace)		do { } while (0)
+# define save_stack_trace_user(trace)			do { } while (0)
 # define print_stack_trace(trace, spaces)		do { } while (0)
 #endif
 
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index 6fd7b01..0127dac 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -139,14 +139,14 @@
 {
 	switch (addr->sa_family) {
 	case AF_INET:
-		snprintf(buf, len, "%u.%u.%u.%u, port=%u",
-			NIPQUAD(((struct sockaddr_in *) addr)->sin_addr),
+		snprintf(buf, len, "%pI4, port=%u",
+			&((struct sockaddr_in *)addr)->sin_addr,
 			ntohs(((struct sockaddr_in *) addr)->sin_port));
 		break;
 
 	case AF_INET6:
-		snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x, port=%u",
-			NIP6(((struct sockaddr_in6 *) addr)->sin6_addr),
+		snprintf(buf, len, "%pI6, port=%u",
+			 &((struct sockaddr_in6 *)addr)->sin6_addr,
 			ntohs(((struct sockaddr_in6 *) addr)->sin6_port));
 		break;
 
diff --git a/include/linux/topology.h b/include/linux/topology.h
index 117f1b7..0c5b5ac 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -49,7 +49,7 @@
 	for_each_online_node(node)			\
 		if (nr_cpus_node(node))
 
-void arch_update_cpu_topology(void);
+int arch_update_cpu_topology(void);
 
 /* Conform to ACPI 2.0 SLIT distance definitions */
 #define LOCAL_DISTANCE		10
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index c5bb39c..7570054 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -24,8 +24,12 @@
 	const char *name;		/* Tracepoint name */
 	int state;			/* State. */
 	void **funcs;
-} __attribute__((aligned(8)));
-
+} __attribute__((aligned(32)));		/*
+					 * Aligned on 32 bytes because it is
+					 * globally visible and gcc happily
+					 * align these on the structure size.
+					 * Keep in sync with vmlinux.lds.h.
+					 */
 
 #define TPPROTO(args...)	args
 #define TPARGS(args...)		args
@@ -40,14 +44,14 @@
 	do {								\
 		void **it_func;						\
 									\
-		rcu_read_lock_sched();					\
+		rcu_read_lock_sched_notrace();				\
 		it_func = rcu_dereference((tp)->funcs);			\
 		if (it_func) {						\
 			do {						\
 				((void(*)(proto))(*it_func))(args);	\
 			} while (*(++it_func));				\
 		}							\
-		rcu_read_unlock_sched();				\
+		rcu_read_unlock_sched_notrace();			\
 	} while (0)
 
 /*
@@ -55,35 +59,40 @@
  * not add unwanted padding between the beginning of the section and the
  * structure. Force alignment to the same alignment as the section start.
  */
-#define DEFINE_TRACE(name, proto, args)					\
+#define DECLARE_TRACE(name, proto, args)				\
+	extern struct tracepoint __tracepoint_##name;			\
 	static inline void trace_##name(proto)				\
 	{								\
-		static const char __tpstrtab_##name[]			\
-		__attribute__((section("__tracepoints_strings")))	\
-		= #name ":" #proto;					\
-		static struct tracepoint __tracepoint_##name		\
-		__attribute__((section("__tracepoints"), aligned(8))) =	\
-		{ __tpstrtab_##name, 0, NULL };				\
 		if (unlikely(__tracepoint_##name.state))		\
 			__DO_TRACE(&__tracepoint_##name,		\
 				TPPROTO(proto), TPARGS(args));		\
 	}								\
 	static inline int register_trace_##name(void (*probe)(proto))	\
 	{								\
-		return tracepoint_probe_register(#name ":" #proto,	\
-			(void *)probe);					\
+		return tracepoint_probe_register(#name, (void *)probe);	\
 	}								\
-	static inline void unregister_trace_##name(void (*probe)(proto))\
+	static inline int unregister_trace_##name(void (*probe)(proto))	\
 	{								\
-		tracepoint_probe_unregister(#name ":" #proto,		\
-			(void *)probe);					\
+		return tracepoint_probe_unregister(#name, (void *)probe);\
 	}
 
+#define DEFINE_TRACE(name)						\
+	static const char __tpstrtab_##name[]				\
+	__attribute__((section("__tracepoints_strings"))) = #name;	\
+	struct tracepoint __tracepoint_##name				\
+	__attribute__((section("__tracepoints"), aligned(32))) =	\
+		{ __tpstrtab_##name, 0, NULL }
+
+#define EXPORT_TRACEPOINT_SYMBOL_GPL(name)				\
+	EXPORT_SYMBOL_GPL(__tracepoint_##name)
+#define EXPORT_TRACEPOINT_SYMBOL(name)					\
+	EXPORT_SYMBOL(__tracepoint_##name)
+
 extern void tracepoint_update_probe_range(struct tracepoint *begin,
 	struct tracepoint *end);
 
 #else /* !CONFIG_TRACEPOINTS */
-#define DEFINE_TRACE(name, proto, args)			\
+#define DECLARE_TRACE(name, proto, args)				\
 	static inline void _do_trace_##name(struct tracepoint *tp, proto) \
 	{ }								\
 	static inline void trace_##name(proto)				\
@@ -92,8 +101,14 @@
 	{								\
 		return -ENOSYS;						\
 	}								\
-	static inline void unregister_trace_##name(void (*probe)(proto))\
-	{ }
+	static inline int unregister_trace_##name(void (*probe)(proto))	\
+	{								\
+		return -ENOSYS;						\
+	}
+
+#define DEFINE_TRACE(name)
+#define EXPORT_TRACEPOINT_SYMBOL_GPL(name)
+#define EXPORT_TRACEPOINT_SYMBOL(name)
 
 static inline void tracepoint_update_probe_range(struct tracepoint *begin,
 	struct tracepoint *end)
@@ -112,6 +127,10 @@
  */
 extern int tracepoint_probe_unregister(const char *name, void *probe);
 
+extern int tracepoint_probe_register_noupdate(const char *name, void *probe);
+extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe);
+extern void tracepoint_probe_update_all(void);
+
 struct tracepoint_iter {
 	struct module *module;
 	struct tracepoint *tracepoint;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 3b8121d..3f4954c 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -325,7 +325,7 @@
  *	go away
  */
 
-extern inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
+static inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
 {
 	if (tty)
 		kref_get(&tty->kref);
@@ -442,6 +442,7 @@
 			       size_t size);
 extern void tty_audit_exit(void);
 extern void tty_audit_fork(struct signal_struct *sig);
+extern void tty_audit_tiocsti(struct tty_struct *tty, char ch);
 extern void tty_audit_push(struct tty_struct *tty);
 extern void tty_audit_push_task(struct task_struct *tsk,
 					uid_t loginuid, u32 sessionid);
@@ -450,6 +451,9 @@
 				      unsigned char *data, size_t size)
 {
 }
+static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch)
+{
+}
 static inline void tty_audit_exit(void)
 {
 }
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index b5f41d4..315bcd3 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -12,7 +12,7 @@
 struct user_namespace {
 	struct kref		kref;
 	struct hlist_head	uidhash_table[UIDHASH_SZ];
-	struct user_struct	*root_user;
+	struct user_struct	*creator;
 };
 
 extern struct user_namespace init_user_ns;
@@ -26,8 +26,7 @@
 	return ns;
 }
 
-extern struct user_namespace *copy_user_ns(int flags,
-					   struct user_namespace *old_ns);
+extern int create_user_ns(struct cred *new);
 extern void free_user_ns(struct kref *kref);
 
 static inline void put_user_ns(struct user_namespace *ns)
@@ -43,13 +42,9 @@
 	return &init_user_ns;
 }
 
-static inline struct user_namespace *copy_user_ns(int flags,
-						  struct user_namespace *old_ns)
+static inline int create_user_ns(struct cred *new)
 {
-	if (flags & CLONE_NEWUSER)
-		return ERR_PTR(-EINVAL);
-
-	return old_ns;
+	return -EINVAL;
 }
 
 static inline void put_user_ns(struct user_namespace *ns)
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 5e33761..5cdd0aa 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -20,6 +20,7 @@
 #define VIRTIO_NET_F_HOST_TSO6	12	/* Host can handle TSOv6 in. */
 #define VIRTIO_NET_F_HOST_ECN	13	/* Host can handle TSO[6] w/ ECN in. */
 #define VIRTIO_NET_F_HOST_UFO	14	/* Host can handle UFO in. */
+#define VIRTIO_NET_F_MRG_RXBUF	15	/* Host can merge receive buffers. */
 
 struct virtio_net_config
 {
@@ -44,4 +45,12 @@
 	__u16 csum_start;	/* Position to start checksumming from */
 	__u16 csum_offset;	/* Offset after that to place checksum */
 };
+
+/* This is the version of the header to use when the MRG_RXBUF
+ * feature has been negotiated. */
+struct virtio_net_hdr_mrg_rxbuf {
+	struct virtio_net_hdr hdr;
+	__u16 num_buffers;	/* Number of merged rx buffers */
+};
+
 #endif /* _LINUX_VIRTIO_NET_H */
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 4bc1e6b..52f3abd 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -199,6 +199,9 @@
 #define XFRM_MSG_NEWSPDINFO XFRM_MSG_NEWSPDINFO
 	XFRM_MSG_GETSPDINFO,
 #define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO
+
+	XFRM_MSG_MAPPING,
+#define XFRM_MSG_MAPPING XFRM_MSG_MAPPING
 	__XFRM_MSG_MAX
 };
 #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -438,6 +441,15 @@
 	__u16				new_family;
 };
 
+struct xfrm_user_mapping {
+	struct xfrm_usersa_id		id;
+	__u32				reqid;
+	xfrm_address_t			old_saddr;
+	xfrm_address_t			new_saddr;
+	__be16				old_sport;
+	__be16				new_sport;
+};
+
 #ifndef __KERNEL__
 /* backwards compatibility for userspace */
 #define XFRMGRP_ACQUIRE		1
@@ -464,6 +476,8 @@
 #define XFRMNLGRP_REPORT	XFRMNLGRP_REPORT
 	XFRMNLGRP_MIGRATE,
 #define XFRMNLGRP_MIGRATE	XFRMNLGRP_MIGRATE
+	XFRMNLGRP_MAPPING,
+#define XFRMNLGRP_MAPPING	XFRMNLGRP_MAPPING
 	__XFRMNLGRP_MAX
 };
 #define XFRMNLGRP_MAX	(__XFRMNLGRP_MAX - 1)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 996d12d..a04f846 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -54,8 +54,8 @@
 #define SOL_RFCOMM	18
 
 #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
-#define BT_DBG(fmt, arg...)  printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg)
-#define BT_ERR(fmt, arg...)  printk(KERN_ERR  "%s: " fmt "\n" , __func__ , ## arg)
+#define BT_ERR(fmt, arg...)  printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
+#define BT_DBG(fmt, arg...)  pr_debug("%s: " fmt "\n" , __func__ , ## arg)
 
 /* Connection and socket states */
 enum {
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 3cc2949..3645139 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -54,7 +54,7 @@
 
 /* HCI device quirks */
 enum {
-	HCI_QUIRK_RESET_ON_INIT,
+	HCI_QUIRK_NO_RESET,
 	HCI_QUIRK_RAW_DEVICE,
 	HCI_QUIRK_FIXUP_BUFFER_SIZE
 };
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0e85ec3..23c0ab7 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5,6 +5,8 @@
 #include <linux/skbuff.h>
 #include <linux/nl80211.h>
 #include <net/genetlink.h>
+/* remove once we remove the wext stuff */
+#include <net/iw_handler.h>
 
 /*
  * 802.11 configuration in-kernel interface
@@ -167,6 +169,9 @@
  * @STATION_INFO_LLID: @llid filled
  * @STATION_INFO_PLID: @plid filled
  * @STATION_INFO_PLINK_STATE: @plink_state filled
+ * @STATION_INFO_SIGNAL: @signal filled
+ * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled
+ *  (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
  */
 enum station_info_flags {
 	STATION_INFO_INACTIVE_TIME	= 1<<0,
@@ -175,6 +180,39 @@
 	STATION_INFO_LLID		= 1<<3,
 	STATION_INFO_PLID		= 1<<4,
 	STATION_INFO_PLINK_STATE	= 1<<5,
+	STATION_INFO_SIGNAL		= 1<<6,
+	STATION_INFO_TX_BITRATE		= 1<<7,
+};
+
+/**
+ * enum station_info_rate_flags - bitrate info flags
+ *
+ * Used by the driver to indicate the specific rate transmission
+ * type for 802.11n transmissions.
+ *
+ * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
+ * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
+ * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
+ */
+enum rate_info_flags {
+	RATE_INFO_FLAGS_MCS		= 1<<0,
+	RATE_INFO_FLAGS_40_MHZ_WIDTH	= 1<<1,
+	RATE_INFO_FLAGS_SHORT_GI	= 1<<2,
+};
+
+/**
+ * struct rate_info - bitrate information
+ *
+ * Information about a receiving or transmitting bitrate
+ *
+ * @flags: bitflag of flags from &enum rate_info_flags
+ * @mcs: mcs index if struct describes a 802.11n bitrate
+ * @legacy: bitrate in 100kbit/s for 802.11abg
+ */
+struct rate_info {
+	u8 flags;
+	u8 mcs;
+	u16 legacy;
 };
 
 /**
@@ -189,6 +227,8 @@
  * @llid: mesh local link id
  * @plid: mesh peer link id
  * @plink_state: mesh peer link state
+ * @signal: signal strength of last received packet in dBm
+ * @txrate: current unicast bitrate to this station
  */
 struct station_info {
 	u32 filled;
@@ -198,6 +238,8 @@
 	u16 llid;
 	u16 plid;
 	u8 plink_state;
+	s8 signal;
+	struct rate_info txrate;
 };
 
 /**
@@ -280,11 +322,16 @@
  *	(0 = no, 1 = yes, -1 = do not change)
  * @use_short_slot_time: Whether the use of short slot time is allowed
  *	(0 = no, 1 = yes, -1 = do not change)
+ * @basic_rates: basic rates in IEEE 802.11 format
+ *	(or NULL for no change)
+ * @basic_rates_len: number of basic rates
  */
 struct bss_parameters {
 	int use_cts_prot;
 	int use_short_preamble;
 	int use_short_slot_time;
+	u8 *basic_rates;
+	u8 basic_rates_len;
 };
 
 /**
@@ -331,25 +378,65 @@
 	struct ieee80211_reg_rule reg_rules[];
 };
 
-#define MHZ_TO_KHZ(freq) (freq * 1000)
-#define KHZ_TO_MHZ(freq) (freq / 1000)
-#define DBI_TO_MBI(gain) (gain * 100)
-#define MBI_TO_DBI(gain) (gain / 100)
-#define DBM_TO_MBM(gain) (gain * 100)
-#define MBM_TO_DBM(gain) (gain / 100)
+#define MHZ_TO_KHZ(freq) ((freq) * 1000)
+#define KHZ_TO_MHZ(freq) ((freq) / 1000)
+#define DBI_TO_MBI(gain) ((gain) * 100)
+#define MBI_TO_DBI(gain) ((gain) / 100)
+#define DBM_TO_MBM(gain) ((gain) * 100)
+#define MBM_TO_DBM(gain) ((gain) / 100)
 
 #define REG_RULE(start, end, bw, gain, eirp, reg_flags) { \
-	.freq_range.start_freq_khz = (start) * 1000, \
-	.freq_range.end_freq_khz = (end) * 1000, \
-	.freq_range.max_bandwidth_khz = (bw) * 1000, \
-	.power_rule.max_antenna_gain = (gain) * 100, \
-	.power_rule.max_eirp = (eirp) * 100, \
+	.freq_range.start_freq_khz = MHZ_TO_KHZ(start), \
+	.freq_range.end_freq_khz = MHZ_TO_KHZ(end), \
+	.freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \
+	.power_rule.max_antenna_gain = DBI_TO_MBI(gain), \
+	.power_rule.max_eirp = DBM_TO_MBM(eirp), \
 	.flags = reg_flags, \
 	}
 
+struct mesh_config {
+	/* Timeouts in ms */
+	/* Mesh plink management parameters */
+	u16 dot11MeshRetryTimeout;
+	u16 dot11MeshConfirmTimeout;
+	u16 dot11MeshHoldingTimeout;
+	u16 dot11MeshMaxPeerLinks;
+	u8  dot11MeshMaxRetries;
+	u8  dot11MeshTTL;
+	bool auto_open_plinks;
+	/* HWMP parameters */
+	u8  dot11MeshHWMPmaxPREQretries;
+	u32 path_refresh_time;
+	u16 min_discovery_timeout;
+	u32 dot11MeshHWMPactivePathTimeout;
+	u16 dot11MeshHWMPpreqMinInterval;
+	u16 dot11MeshHWMPnetDiameterTraversalTime;
+};
+
+/**
+ * struct ieee80211_txq_params - TX queue parameters
+ * @queue: TX queue identifier (NL80211_TXQ_Q_*)
+ * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled
+ * @cwmin: Minimum contention window [a value of the form 2^n-1 in the range
+ *	1..32767]
+ * @cwmax: Maximum contention window [a value of the form 2^n-1 in the range
+ *	1..32767]
+ * @aifs: Arbitration interframe space [0..255]
+ */
+struct ieee80211_txq_params {
+	enum nl80211_txq_q queue;
+	u16 txop;
+	u16 cwmin;
+	u16 cwmax;
+	u8 aifs;
+};
+
 /* from net/wireless.h */
 struct wiphy;
 
+/* from net/ieee80211.h */
+struct ieee80211_channel;
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -397,9 +484,19 @@
  *
  * @change_station: Modify a given station.
  *
+ * @get_mesh_params: Put the current mesh parameters into *params
+ *
+ * @set_mesh_params: Set mesh parameters.
+ *	The mask is a bitfield which tells us which parameters to
+ *	set, and which to leave alone.
+ *
  * @set_mesh_cfg: set mesh parameters (by now, just mesh id)
  *
  * @change_bss: Modify parameters for a given BSS.
+ *
+ * @set_txq_params: Set TX queue parameters
+ *
+ * @set_channel: Set channel
  */
 struct cfg80211_ops {
 	int	(*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -452,9 +549,30 @@
 	int	(*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
 			       int idx, u8 *dst, u8 *next_hop,
 			       struct mpath_info *pinfo);
-
+	int	(*get_mesh_params)(struct wiphy *wiphy,
+				struct net_device *dev,
+				struct mesh_config *conf);
+	int	(*set_mesh_params)(struct wiphy *wiphy,
+				struct net_device *dev,
+				const struct mesh_config *nconf, u32 mask);
 	int	(*change_bss)(struct wiphy *wiphy, struct net_device *dev,
 			      struct bss_parameters *params);
+
+	int	(*set_txq_params)(struct wiphy *wiphy,
+				  struct ieee80211_txq_params *params);
+
+	int	(*set_channel)(struct wiphy *wiphy,
+			       struct ieee80211_channel *chan,
+			       enum nl80211_channel_type channel_type);
 };
 
+/* temporary wext handlers */
+int cfg80211_wext_giwname(struct net_device *dev,
+			  struct iw_request_info *info,
+			  char *name, char *extra);
+int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
+			  u32 *mode, char *extra);
+int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
+			  u32 *mode, char *extra);
+
 #endif /* __NET_CFG80211_H */
diff --git a/include/net/checksum.h b/include/net/checksum.h
index 07602b7..ba55d8b 100644
--- a/include/net/checksum.h
+++ b/include/net/checksum.h
@@ -98,7 +98,7 @@
 {
 	__be32 diff[] = { ~from, to };
 
-	*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
+	*sum = csum_fold(csum_partial(diff, sizeof(diff), ~csum_unfold(*sum)));
 }
 
 static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to)
diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h
new file mode 100644
index 0000000..775cfc8
--- /dev/null
+++ b/include/net/dcbnl.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Lucy Liu <lucy.liu@intel.com>
+ */
+
+#ifndef __NET_DCBNL_H__
+#define __NET_DCBNL_H__
+
+/*
+ * Ops struct for the netlink callbacks.  Used by DCB-enabled drivers through
+ * the netdevice struct.
+ */
+struct dcbnl_rtnl_ops {
+	u8   (*getstate)(struct net_device *);
+	u8   (*setstate)(struct net_device *, u8);
+	void (*getpermhwaddr)(struct net_device *, u8 *);
+	void (*setpgtccfgtx)(struct net_device *, int, u8, u8, u8, u8);
+	void (*setpgbwgcfgtx)(struct net_device *, int, u8);
+	void (*setpgtccfgrx)(struct net_device *, int, u8, u8, u8, u8);
+	void (*setpgbwgcfgrx)(struct net_device *, int, u8);
+	void (*getpgtccfgtx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *);
+	void (*getpgbwgcfgtx)(struct net_device *, int, u8 *);
+	void (*getpgtccfgrx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *);
+	void (*getpgbwgcfgrx)(struct net_device *, int, u8 *);
+	void (*setpfccfg)(struct net_device *, int, u8);
+	void (*getpfccfg)(struct net_device *, int, u8 *);
+	u8   (*setall)(struct net_device *);
+	u8   (*getcap)(struct net_device *, int, u8 *);
+	u8   (*getnumtcs)(struct net_device *, int, u8 *);
+	u8   (*setnumtcs)(struct net_device *, int, u8);
+	u8   (*getpfcstate)(struct net_device *);
+	void (*setpfcstate)(struct net_device *, u8);
+	void (*getbcncfg)(struct net_device *, int, u32 *);
+	void (*setbcncfg)(struct net_device *, int, u32);
+	void (*getbcnrp)(struct net_device *, int, u8 *);
+	void (*setbcnrp)(struct net_device *, int, u8);
+};
+
+#endif /* __NET_DCBNL_H__ */
diff --git a/include/net/dn.h b/include/net/dn.h
index 6277783..e5469f7 100644
--- a/include/net/dn.h
+++ b/include/net/dn.h
@@ -4,9 +4,7 @@
 #include <linux/dn.h>
 #include <net/sock.h>
 #include <asm/byteorder.h>
-
-#define dn_ntohs(x) le16_to_cpu(x)
-#define dn_htons(x) cpu_to_le16(x)
+#include <asm/unaligned.h>
 
 struct dn_scp                                   /* Session Control Port */
 {
@@ -175,7 +173,7 @@
 
 static inline __le16 dn_eth2dn(unsigned char *ethaddr)
 {
-	return dn_htons(ethaddr[4] | (ethaddr[5] << 8));
+	return get_unaligned((__le16 *)(ethaddr + 4));
 }
 
 static inline __le16 dn_saddr2dn(struct sockaddr_dn *saddr)
@@ -185,7 +183,7 @@
 
 static inline void dn_dn2eth(unsigned char *ethaddr, __le16 addr)
 {
-	__u16 a = dn_ntohs(addr);
+	__u16 a = le16_to_cpu(addr);
 	ethaddr[0] = 0xAA;
 	ethaddr[1] = 0x00;
 	ethaddr[2] = 0x04;
diff --git a/include/net/dn_fib.h b/include/net/dn_fib.h
index 3012511..c378be7 100644
--- a/include/net/dn_fib.h
+++ b/include/net/dn_fib.h
@@ -181,9 +181,9 @@
 
 static inline __le16 dnet_make_mask(int n)
 {
-        if (n)
-                return dn_htons(~((1<<(16-n))-1));
-        return 0;
+	if (n)
+		return cpu_to_le16(~((1 << (16 - n)) - 1));
+	return cpu_to_le16(0);
 }
 
 #endif /* _NET_DN_FIB_H */
diff --git a/include/net/dst.h b/include/net/dst.h
index 8a8b71e..6be3b08 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -59,8 +59,11 @@
 
 	struct neighbour	*neighbour;
 	struct hh_cache		*hh;
+#ifdef CONFIG_XFRM
 	struct xfrm_state	*xfrm;
-
+#else
+	void			*__pad1;
+#endif
 	int			(*input)(struct sk_buff*);
 	int			(*output)(struct sk_buff*);
 
@@ -70,8 +73,20 @@
 
 #ifdef CONFIG_NET_CLS_ROUTE
 	__u32			tclassid;
+#else
+	__u32			__pad2;
 #endif
 
+
+	/*
+	 * Align __refcnt to a 64 bytes alignment
+	 * (L1_CACHE_SIZE would be too much)
+	 */
+#ifdef CONFIG_64BIT
+	long			__pad_to_align_refcnt[2];
+#else
+	long			__pad_to_align_refcnt[1];
+#endif
 	/*
 	 * __refcnt wants to be on a different cache line from
 	 * input/output/ops or performance tanks badly
@@ -103,7 +118,6 @@
 	void			(*link_failure)(struct sk_buff *);
 	void			(*update_pmtu)(struct dst_entry *dst, u32 mtu);
 	int			(*local_out)(struct sk_buff *skb);
-	int			entry_size;
 
 	atomic_t		entries;
 	struct kmem_cache 		*kmem_cachep;
@@ -157,6 +171,11 @@
 
 static inline void dst_hold(struct dst_entry * dst)
 {
+	/*
+	 * If your kernel compilation stops here, please check
+	 * __pad_to_align_refcnt declaration in struct dst_entry
+	 */
+	BUILD_BUG_ON(offsetof(struct dst_entry, __refcnt) & 63);
 	atomic_inc(&dst->__refcnt);
 }
 
@@ -272,21 +291,21 @@
 
 struct flowi;
 #ifndef CONFIG_XFRM
-static inline int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
-		       struct sock *sk, int flags)
+static inline int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
+			      struct flowi *fl, struct sock *sk, int flags)
 {
 	return 0;
 } 
-static inline int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
-				struct sock *sk, int flags)
+static inline int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
+				struct flowi *fl, struct sock *sk, int flags)
 {
 	return 0;
 }
 #else
-extern int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
-		       struct sock *sk, int flags);
-extern int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
-			 struct sock *sk, int flags);
+extern int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
+		       struct flowi *fl, struct sock *sk, int flags);
+extern int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
+			 struct flowi *fl, struct sock *sk, int flags);
 #endif
 #endif
 
diff --git a/include/net/flow.h b/include/net/flow.h
index b45a5e4..809970b 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -84,12 +84,13 @@
 #define FLOW_DIR_OUT	1
 #define FLOW_DIR_FWD	2
 
+struct net;
 struct sock;
-typedef int (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir,
-			       void **objp, atomic_t **obj_refp);
+typedef int (*flow_resolve_t)(struct net *net, struct flowi *key, u16 family,
+			      u8 dir, void **objp, atomic_t **obj_refp);
 
-extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
-	 		       flow_resolve_t resolver);
+extern void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family,
+			       u8 dir, flow_resolve_t resolver);
 extern void flow_cache_flush(void);
 extern atomic_t flow_cache_genid;
 
diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h
index 8cd8185..d136b52 100644
--- a/include/net/gen_stats.h
+++ b/include/net/gen_stats.h
@@ -45,5 +45,6 @@
 extern int gen_replace_estimator(struct gnet_stats_basic *bstats,
 				 struct gnet_stats_rate_est *rate_est,
 				 spinlock_t *stats_lock, struct nlattr *opt);
-
+extern bool gen_estimator_active(const struct gnet_stats_basic *bstats,
+				 const struct gnet_stats_rate_est *rate_est);
 #endif
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index 93a56de..adb7cf3 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -28,6 +28,9 @@
 #include <linux/if_ether.h>	/* ETH_ALEN */
 #include <linux/kernel.h>	/* ARRAY_SIZE */
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
+
+#include <net/lib80211.h>
 
 #define IEEE80211_VERSION "git-1.1.13"
 
@@ -127,10 +130,6 @@
 }
 #endif				/* CONFIG_IEEE80211_DEBUG */
 
-/* escape_essid() is intended to be used in debug (and possibly error)
- * messages. It should never be used for passing essid to user space. */
-const char *escape_essid(const char *essid, u8 essid_len);
-
 /*
  * To use the debug system:
  *
@@ -218,94 +217,6 @@
 #define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
 #define WLAN_GET_SEQ_SEQ(seq)  (((seq) & IEEE80211_SCTL_SEQ) >> 4)
 
-/* Authentication algorithms */
-#define WLAN_AUTH_OPEN 0
-#define WLAN_AUTH_SHARED_KEY 1
-#define WLAN_AUTH_LEAP 2
-
-#define WLAN_AUTH_CHALLENGE_LEN 128
-
-#define WLAN_CAPABILITY_ESS (1<<0)
-#define WLAN_CAPABILITY_IBSS (1<<1)
-#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
-#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
-#define WLAN_CAPABILITY_PRIVACY (1<<4)
-#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
-#define WLAN_CAPABILITY_PBCC (1<<6)
-#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
-#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
-#define WLAN_CAPABILITY_QOS (1<<9)
-#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
-#define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
-
-/* 802.11g ERP information element */
-#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
-#define WLAN_ERP_USE_PROTECTION (1<<1)
-#define WLAN_ERP_BARKER_PREAMBLE (1<<2)
-
-/* Status codes */
-enum ieee80211_statuscode {
-	WLAN_STATUS_SUCCESS = 0,
-	WLAN_STATUS_UNSPECIFIED_FAILURE = 1,
-	WLAN_STATUS_CAPS_UNSUPPORTED = 10,
-	WLAN_STATUS_REASSOC_NO_ASSOC = 11,
-	WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12,
-	WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13,
-	WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14,
-	WLAN_STATUS_CHALLENGE_FAIL = 15,
-	WLAN_STATUS_AUTH_TIMEOUT = 16,
-	WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17,
-	WLAN_STATUS_ASSOC_DENIED_RATES = 18,
-	/* 802.11b */
-	WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19,
-	WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20,
-	WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21,
-	/* 802.11h */
-	WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22,
-	WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23,
-	WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24,
-	/* 802.11g */
-	WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25,
-	WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26,
-	/* 802.11i */
-	WLAN_STATUS_INVALID_IE = 40,
-	WLAN_STATUS_INVALID_GROUP_CIPHER = 41,
-	WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42,
-	WLAN_STATUS_INVALID_AKMP = 43,
-	WLAN_STATUS_UNSUPP_RSN_VERSION = 44,
-	WLAN_STATUS_INVALID_RSN_IE_CAP = 45,
-	WLAN_STATUS_CIPHER_SUITE_REJECTED = 46,
-};
-
-/* Reason codes */
-enum ieee80211_reasoncode {
-	WLAN_REASON_UNSPECIFIED = 1,
-	WLAN_REASON_PREV_AUTH_NOT_VALID = 2,
-	WLAN_REASON_DEAUTH_LEAVING = 3,
-	WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4,
-	WLAN_REASON_DISASSOC_AP_BUSY = 5,
-	WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6,
-	WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7,
-	WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8,
-	WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9,
-	/* 802.11h */
-	WLAN_REASON_DISASSOC_BAD_POWER = 10,
-	WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11,
-	/* 802.11i */
-	WLAN_REASON_INVALID_IE = 13,
-	WLAN_REASON_MIC_FAILURE = 14,
-	WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15,
-	WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16,
-	WLAN_REASON_IE_DIFFERENT = 17,
-	WLAN_REASON_INVALID_GROUP_CIPHER = 18,
-	WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19,
-	WLAN_REASON_INVALID_AKMP = 20,
-	WLAN_REASON_UNSUPP_RSN_VERSION = 21,
-	WLAN_REASON_INVALID_RSN_IE_CAP = 22,
-	WLAN_REASON_IEEE8021X_FAILED = 23,
-	WLAN_REASON_CIPHER_SUITE_REJECTED = 24,
-};
-
 /* Action categories - 802.11h */
 enum ieee80211_actioncategories {
 	WLAN_ACTION_SPECTRUM_MGMT = 0,
@@ -446,8 +357,6 @@
 
 struct ieee80211_device;
 
-#include "ieee80211_crypt.h"
-
 #define SEC_KEY_1		(1<<0)
 #define SEC_KEY_2		(1<<1)
 #define SEC_KEY_3		(1<<2)
@@ -476,9 +385,8 @@
 #define SCM_TEMPORAL_KEY_LENGTH	16
 
 struct ieee80211_security {
-	u16 active_key:2,
-	    enabled:1,
-	    auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1;
+	u16 active_key:2, enabled:1, unicast_uses_group:1, encrypt:1;
+	u8 auth_mode;
 	u8 encode_alg[WEP_KEYS];
 	u8 key_sizes[WEP_KEYS];
 	u8 keys[WEP_KEYS][SCM_KEY_LEN];
@@ -534,15 +442,6 @@
 	MFIE_TYPE_QOS_PARAMETER = 222,
 };
 
-/* Minimal header; can be used for passing 802.11 frames with sufficient
- * information to determine what type of underlying data type is actually
- * stored in the data. */
-struct ieee80211_hdr {
-	__le16 frame_ctl;
-	__le16 duration_id;
-	u8 payload[0];
-} __attribute__ ((packed));
-
 struct ieee80211_hdr_1addr {
 	__le16 frame_ctl;
 	__le16 duration_id;
@@ -590,18 +489,6 @@
 	__le16 qos_ctl;
 } __attribute__ ((packed));
 
-struct ieee80211_hdr_4addrqos {
-	__le16 frame_ctl;
-	__le16 duration_id;
-	u8 addr1[ETH_ALEN];
-	u8 addr2[ETH_ALEN];
-	u8 addr3[ETH_ALEN];
-	__le16 seq_ctl;
-	u8 addr4[ETH_ALEN];
-	u8 payload[0];
-	__le16 qos_ctl;
-} __attribute__ ((packed));
-
 struct ieee80211_info_element {
 	u8 id;
 	u8 len;
@@ -733,7 +620,6 @@
 
 #define MAX_WPA_IE_LEN 64
 
-#define NETWORK_EMPTY_ESSID    (1<<0)
 #define NETWORK_HAS_OFDM       (1<<1)
 #define NETWORK_HAS_CCK        (1<<2)
 
@@ -1050,11 +936,7 @@
 	size_t wpa_ie_len;
 	u8 *wpa_ie;
 
-	struct list_head crypt_deinit_list;
-	struct ieee80211_crypt_data *crypt[WEP_KEYS];
-	int tx_keyidx;		/* default TX key index (crypt[tx_keyidx]) */
-	struct timer_list crypt_deinit_timer;
-	int crypt_quiesced;
+	struct lib80211_crypt_info crypt_info;
 
 	int bcrx_sta_key;	/* use individual keys to override default keys even
 				 * with RX of broad/multicast frames */
@@ -1135,22 +1017,6 @@
 	return ((struct ieee80211_device *)netdev_priv(dev))->priv;
 }
 
-static inline int ieee80211_is_empty_essid(const char *essid, int essid_len)
-{
-	/* Single white space is for Linksys APs */
-	if (essid_len == 1 && essid[0] == ' ')
-		return 1;
-
-	/* Otherwise, if the entire essid is 0, we assume it is hidden */
-	while (essid_len) {
-		essid_len--;
-		if (essid[essid_len] != '\0')
-			return 0;
-	}
-
-	return 1;
-}
-
 static inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee,
 					  int mode)
 {
@@ -1208,7 +1074,7 @@
 
 static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr)
 {
-	switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl))) {
+	switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control))) {
 	case IEEE80211_1ADDR_LEN:
 		return ((struct ieee80211_hdr_1addr *)hdr)->payload;
 	case IEEE80211_2ADDR_LEN:
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h
deleted file mode 100644
index b3d65e0..0000000
--- a/include/net/ieee80211_crypt.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Original code based on Host AP (software wireless LAN access point) driver
- * for Intersil Prism2/2.5/3.
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <j@w1.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
- *
- * Adaption to a generic IEEE 802.11 stack by James Ketrenos
- * <jketreno@linux.intel.com>
- *
- * Copyright (c) 2004, Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation. See README and COPYING for
- * more details.
- */
-
-/*
- * This file defines the interface to the ieee80211 crypto module.
- */
-#ifndef IEEE80211_CRYPT_H
-#define IEEE80211_CRYPT_H
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <net/ieee80211.h>
-#include <asm/atomic.h>
-
-enum {
-	IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0),
-};
-
-struct sk_buff;
-struct module;
-
-struct ieee80211_crypto_ops {
-	const char *name;
-	struct list_head list;
-
-	/* init new crypto context (e.g., allocate private data space,
-	 * select IV, etc.); returns NULL on failure or pointer to allocated
-	 * private data on success */
-	void *(*init) (int keyidx);
-
-	/* deinitialize crypto context and free allocated private data */
-	void (*deinit) (void *priv);
-
-	int (*build_iv) (struct sk_buff * skb, int hdr_len,
-			 u8 *key, int keylen, void *priv);
-
-	/* encrypt/decrypt return < 0 on error or >= 0 on success. The return
-	 * value from decrypt_mpdu is passed as the keyidx value for
-	 * decrypt_msdu. skb must have enough head and tail room for the
-	 * encryption; if not, error will be returned; these functions are
-	 * called for all MPDUs (i.e., fragments).
-	 */
-	int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
-	int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
-
-	/* These functions are called for full MSDUs, i.e. full frames.
-	 * These can be NULL if full MSDU operations are not needed. */
-	int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv);
-	int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len,
-			     void *priv);
-
-	int (*set_key) (void *key, int len, u8 * seq, void *priv);
-	int (*get_key) (void *key, int len, u8 * seq, void *priv);
-
-	/* procfs handler for printing out key information and possible
-	 * statistics */
-	char *(*print_stats) (char *p, void *priv);
-
-	/* Crypto specific flag get/set for configuration settings */
-	unsigned long (*get_flags) (void *priv);
-	unsigned long (*set_flags) (unsigned long flags, void *priv);
-
-	/* maximum number of bytes added by encryption; encrypt buf is
-	 * allocated with extra_prefix_len bytes, copy of in_buf, and
-	 * extra_postfix_len; encrypt need not use all this space, but
-	 * the result must start at the beginning of the buffer and correct
-	 * length must be returned */
-	int extra_mpdu_prefix_len, extra_mpdu_postfix_len;
-	int extra_msdu_prefix_len, extra_msdu_postfix_len;
-
-	struct module *owner;
-};
-
-struct ieee80211_crypt_data {
-	struct list_head list;	/* delayed deletion list */
-	struct ieee80211_crypto_ops *ops;
-	void *priv;
-	atomic_t refcnt;
-};
-
-struct ieee80211_device;
-
-int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops);
-int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops);
-struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name);
-void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int);
-void ieee80211_crypt_deinit_handler(unsigned long);
-void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
-				    struct ieee80211_crypt_data **crypt);
-void ieee80211_crypt_quiescing(struct ieee80211_device *ieee);
-
-#endif
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index d364fd5..384698c 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -1,7 +1,4 @@
-/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
-/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
-
-/*-
+/*
  * Copyright (c) 2003, 2004 David Young.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,8 +39,6 @@
 #include <linux/kernel.h>
 #include <asm/unaligned.h>
 
-/* Radiotap header version (from official NetBSD feed) */
-#define IEEE80211RADIOTAP_VERSION	"1.5"
 /* Base version of the radiotap packet header data */
 #define PKTHDR_RADIOTAP_VERSION		0
 
@@ -62,12 +57,8 @@
  * readers.
  */
 
-/* XXX tcpdump/libpcap do not tolerate variable-length headers,
- * yet, so we pad every radiotap header to 64 bytes. Ugh.
- */
-#define IEEE80211_RADIOTAP_HDRLEN	64
-
-/* The radio capture header precedes the 802.11 header.
+/*
+ * The radio capture header precedes the 802.11 header.
  * All data in the header is little endian on all platforms.
  */
 struct ieee80211_radiotap_header {
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 5cc182f..f44bb5c 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -41,8 +41,8 @@
  * I'll experiment with dynamic table growth later.
  */
 struct inet_ehash_bucket {
-	struct hlist_head chain;
-	struct hlist_head twchain;
+	struct hlist_nulls_head chain;
+	struct hlist_nulls_head twchain;
 };
 
 /* There are a few simple rules, which allow for local port reuse by
@@ -77,13 +77,20 @@
  * ports are created in O(1) time?  I thought so. ;-)	-DaveM
  */
 struct inet_bind_bucket {
+#ifdef CONFIG_NET_NS
 	struct net		*ib_net;
+#endif
 	unsigned short		port;
 	signed short		fastreuse;
 	struct hlist_node	node;
 	struct hlist_head	owners;
 };
 
+static inline struct net *ib_net(struct inet_bind_bucket *ib)
+{
+	return read_pnet(&ib->ib_net);
+}
+
 #define inet_bind_bucket_for_each(tb, node, head) \
 	hlist_for_each_entry(tb, node, head, node)
 
@@ -92,6 +99,18 @@
 	struct hlist_head	chain;
 };
 
+/*
+ * Sockets can be hashed in established or listening table
+ * We must use different 'nulls' end-of-chain value for listening
+ * hash table, or we might find a socket that was closed and
+ * reallocated/inserted into established hash table
+ */
+#define LISTENING_NULLS_BASE (1U << 29)
+struct inet_listen_hashbucket {
+	spinlock_t		lock;
+	struct hlist_nulls_head	head;
+};
+
 /* This is for listening sockets, thus all sockets which possess wildcards. */
 #define INET_LHTABLE_SIZE	32	/* Yes, really, this is all you need. */
 
@@ -104,7 +123,7 @@
 	 * TIME_WAIT sockets use a separate chain (twchain).
 	 */
 	struct inet_ehash_bucket	*ehash;
-	rwlock_t			*ehash_locks;
+	spinlock_t			*ehash_locks;
 	unsigned int			ehash_size;
 	unsigned int			ehash_locks_mask;
 
@@ -116,22 +135,21 @@
 	unsigned int			bhash_size;
 	/* Note : 4 bytes padding on 64 bit arches */
 
-	/* All sockets in TCP_LISTEN state will be in here.  This is the only
-	 * table where wildcard'd TCP sockets can exist.  Hash function here
-	 * is just local port number.
-	 */
-	struct hlist_head		listening_hash[INET_LHTABLE_SIZE];
+	struct kmem_cache		*bind_bucket_cachep;
 
 	/* All the above members are written once at bootup and
 	 * never written again _or_ are predominantly read-access.
 	 *
 	 * Now align to a new cache line as all the following members
-	 * are often dirty.
+	 * might be often dirty.
 	 */
-	rwlock_t			lhash_lock ____cacheline_aligned;
-	atomic_t			lhash_users;
-	wait_queue_head_t		lhash_wait;
-	struct kmem_cache			*bind_bucket_cachep;
+	/* All sockets in TCP_LISTEN state will be in here.  This is the only
+	 * table where wildcard'd TCP sockets can exist.  Hash function here
+	 * is just local port number.
+	 */
+	struct inet_listen_hashbucket	listening_hash[INET_LHTABLE_SIZE]
+					____cacheline_aligned_in_smp;
+
 };
 
 static inline struct inet_ehash_bucket *inet_ehash_bucket(
@@ -141,7 +159,7 @@
 	return &hashinfo->ehash[hash & (hashinfo->ehash_size - 1)];
 }
 
-static inline rwlock_t *inet_ehash_lockp(
+static inline spinlock_t *inet_ehash_lockp(
 	struct inet_hashinfo *hashinfo,
 	unsigned int hash)
 {
@@ -166,16 +184,16 @@
 		size = 4096;
 	if (sizeof(rwlock_t) != 0) {
 #ifdef CONFIG_NUMA
-		if (size * sizeof(rwlock_t) > PAGE_SIZE)
-			hashinfo->ehash_locks = vmalloc(size * sizeof(rwlock_t));
+		if (size * sizeof(spinlock_t) > PAGE_SIZE)
+			hashinfo->ehash_locks = vmalloc(size * sizeof(spinlock_t));
 		else
 #endif
-		hashinfo->ehash_locks =	kmalloc(size * sizeof(rwlock_t),
+		hashinfo->ehash_locks =	kmalloc(size * sizeof(spinlock_t),
 						GFP_KERNEL);
 		if (!hashinfo->ehash_locks)
 			return ENOMEM;
 		for (i = 0; i < size; i++)
-			rwlock_init(&hashinfo->ehash_locks[i]);
+			spin_lock_init(&hashinfo->ehash_locks[i]);
 	}
 	hashinfo->ehash_locks_mask = size - 1;
 	return 0;
@@ -186,7 +204,7 @@
 	if (hashinfo->ehash_locks) {
 #ifdef CONFIG_NUMA
 		unsigned int size = (hashinfo->ehash_locks_mask + 1) *
-							sizeof(rwlock_t);
+							sizeof(spinlock_t);
 		if (size > PAGE_SIZE)
 			vfree(hashinfo->ehash_locks);
 		else
@@ -229,26 +247,7 @@
 
 extern void inet_put_port(struct sock *sk);
 
-extern void inet_listen_wlock(struct inet_hashinfo *hashinfo);
-
-/*
- * - We may sleep inside this lock.
- * - If sleeping is not required (or called from BH),
- *   use plain read_(un)lock(&inet_hashinfo.lhash_lock).
- */
-static inline void inet_listen_lock(struct inet_hashinfo *hashinfo)
-{
-	/* read_lock synchronizes to candidates to writers */
-	read_lock(&hashinfo->lhash_lock);
-	atomic_inc(&hashinfo->lhash_users);
-	read_unlock(&hashinfo->lhash_lock);
-}
-
-static inline void inet_listen_unlock(struct inet_hashinfo *hashinfo)
-{
-	if (atomic_dec_and_test(&hashinfo->lhash_users))
-		wake_up(&hashinfo->lhash_wait);
-}
+void inet_hashinfo_init(struct inet_hashinfo *h);
 
 extern void __inet_hash_nolisten(struct sock *sk);
 extern void inet_hash(struct sock *sk);
@@ -299,25 +298,25 @@
 				   ((__force __u64)(__be32)(__saddr)));
 #endif /* __BIG_ENDIAN */
 #define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
-	(((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net)	&&	\
+	(((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) &&	\
 	 ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie))	&&	\
 	 ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports))	&&	\
 	 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
 #define INET_TW_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
-	(((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net)	&&	\
+	(((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) &&	\
 	 ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) &&	\
 	 ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) &&	\
 	 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
 #else /* 32-bit arch */
 #define INET_ADDR_COOKIE(__name, __saddr, __daddr)
 #define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)	\
-	(((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net)	&&	\
+	(((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net))	&&	\
 	 (inet_sk(__sk)->daddr		== (__saddr))		&&	\
 	 (inet_sk(__sk)->rcv_saddr	== (__daddr))		&&	\
 	 ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports))	&&	\
 	 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
 #define INET_TW_MATCH(__sk, __net, __hash,__cookie, __saddr, __daddr, __ports, __dif)	\
-	(((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net)	&&	\
+	(((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net))	&&	\
 	 (inet_twsk(__sk)->tw_daddr	== (__saddr))		&&	\
 	 (inet_twsk(__sk)->tw_rcv_saddr	== (__daddr))		&&	\
 	 ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) &&	\
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index 80e4977..4b8ece2 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -110,7 +110,7 @@
 #define tw_state		__tw_common.skc_state
 #define tw_reuse		__tw_common.skc_reuse
 #define tw_bound_dev_if		__tw_common.skc_bound_dev_if
-#define tw_node			__tw_common.skc_node
+#define tw_node			__tw_common.skc_nulls_node
 #define tw_bind_node		__tw_common.skc_bind_node
 #define tw_refcnt		__tw_common.skc_refcnt
 #define tw_hash			__tw_common.skc_hash
@@ -137,10 +137,10 @@
 	struct hlist_node	tw_death_node;
 };
 
-static inline void inet_twsk_add_node(struct inet_timewait_sock *tw,
-				      struct hlist_head *list)
+static inline void inet_twsk_add_node_rcu(struct inet_timewait_sock *tw,
+				      struct hlist_nulls_head *list)
 {
-	hlist_add_head(&tw->tw_node, list);
+	hlist_nulls_add_head_rcu(&tw->tw_node, list);
 }
 
 static inline void inet_twsk_add_bind_node(struct inet_timewait_sock *tw,
@@ -175,7 +175,7 @@
 }
 
 #define inet_twsk_for_each(tw, node, head) \
-	hlist_for_each_entry(tw, node, head, tw_node)
+	hlist_nulls_for_each_entry(tw, node, head, tw_node)
 
 #define inet_twsk_for_each_inmate(tw, node, jail) \
 	hlist_for_each_entry(tw, node, jail, tw_death_node)
diff --git a/include/net/ip.h b/include/net/ip.h
index bc026ec..1086813 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -110,7 +110,7 @@
 						   int odd, struct sk_buff *skb),
 				void *from, int len, int protolen,
 				struct ipcm_cookie *ipc,
-				struct rtable *rt,
+				struct rtable **rt,
 				unsigned int flags);
 extern int		ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb);
 extern ssize_t		ip_append_page(struct sock *sk, struct page *page,
@@ -187,6 +187,7 @@
 extern int sysctl_ip_default_ttl;
 extern int sysctl_ip_nonlocal_bind;
 
+extern struct ctl_path net_core_path[];
 extern struct ctl_path net_ipv4_ctl_path[];
 
 /* From inetpeer.c */
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index fe9fcf7..ab9b003 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -87,12 +87,12 @@
 	int len;
 #ifdef CONFIG_IP_VS_IPV6
 	if (af == AF_INET6)
-		len = snprintf(&buf[*idx], buf_len - *idx, "[" NIP6_FMT "]",
-			       NIP6(addr->in6)) + 1;
+		len = snprintf(&buf[*idx], buf_len - *idx, "[%pI6]",
+			       &addr->in6) + 1;
 	else
 #endif
-		len = snprintf(&buf[*idx], buf_len - *idx, NIPQUAD_FMT,
-			       NIPQUAD(addr->ip)) + 1;
+		len = snprintf(&buf[*idx], buf_len - *idx, "%pI4",
+			       &addr->ip) + 1;
 
 	*idx += len;
 	BUG_ON(*idx > buf_len + 1);
@@ -503,9 +503,6 @@
 	char			*name;		/* scheduler name */
 	atomic_t		refcnt;		/* reference counter */
 	struct module		*module;	/* THIS_MODULE/NULL */
-#ifdef CONFIG_IP_VS_IPV6
-	int			supports_ipv6;	/* scheduler has IPv6 support */
-#endif
 
 	/* scheduler initializing service */
 	int (*init_service)(struct ip_vs_service *svc);
@@ -916,7 +913,7 @@
 {
 	__be32 diff[2] = { ~old, new };
 
-	return csum_partial((char *) diff, sizeof(diff), oldsum);
+	return csum_partial(diff, sizeof(diff), oldsum);
 }
 
 #ifdef CONFIG_IP_VS_IPV6
@@ -926,7 +923,7 @@
 	__be32 diff[8] = { ~old[3], ~old[2], ~old[1], ~old[0],
 			    new[3],  new[2],  new[1],  new[0] };
 
-	return csum_partial((char *) diff, sizeof(diff), oldsum);
+	return csum_partial(diff, sizeof(diff), oldsum);
 }
 #endif
 
@@ -934,7 +931,7 @@
 {
 	__be16 diff[2] = { ~old, new };
 
-	return csum_partial((char *) diff, sizeof(diff), oldsum);
+	return csum_partial(diff, sizeof(diff), oldsum);
 }
 
 #endif /* __KERNEL__ */
diff --git a/include/net/iucv/iucv.h b/include/net/iucv/iucv.h
index fd70adb..5e310c8 100644
--- a/include/net/iucv/iucv.h
+++ b/include/net/iucv/iucv.h
@@ -337,12 +337,35 @@
  * established paths. This function will deal with RMDATA messages
  * embedded in struct iucv_message as well.
  *
+ * Locking:	local_bh_enable/local_bh_disable
+ *
  * Returns the result from the CP IUCV call.
  */
 int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
 			 u8 flags, void *buffer, size_t size, size_t *residual);
 
 /**
+ * __iucv_message_receive
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: flags that affect how the message is received (IUCV_IPBUFLST)
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of data buffer
+ * @residual:
+ *
+ * This function receives messages that are being sent to you over
+ * established paths. This function will deal with RMDATA messages
+ * embedded in struct iucv_message as well.
+ *
+ * Locking:	no locking.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
+			   u8 flags, void *buffer, size_t size,
+			   size_t *residual);
+
+/**
  * iucv_message_reject
  * @path: address of iucv path structure
  * @msg: address of iucv msg structure
@@ -386,12 +409,34 @@
  * transmitted is in a buffer and this is a one-way message and the
  * receiver will not reply to the message.
  *
+ * Locking:	local_bh_enable/local_bh_disable
+ *
  * Returns the result from the CP IUCV call.
  */
 int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
 		      u8 flags, u32 srccls, void *buffer, size_t size);
 
 /**
+ * __iucv_message_send
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
+ * @srccls: source class of message
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of send buffer
+ *
+ * This function transmits data to another application. Data to be
+ * transmitted is in a buffer and this is a one-way message and the
+ * receiver will not reply to the message.
+ *
+ * Locking:	no locking.
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
+			u8 flags, u32 srccls, void *buffer, size_t size);
+
+/**
  * iucv_message_send2way
  * @path: address of iucv path structure
  * @msg: address of iucv msg structure
diff --git a/include/net/lib80211.h b/include/net/lib80211.h
new file mode 100644
index 0000000..fb4e278
--- /dev/null
+++ b/include/net/lib80211.h
@@ -0,0 +1,129 @@
+/*
+ * lib80211.h -- common bits for IEEE802.11 wireless drivers
+ *
+ * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
+ *
+ * Some bits copied from old ieee80211 component, w/ original copyright
+ * notices below:
+ *
+ * Original code based on Host AP (software wireless LAN access point) driver
+ * for Intersil Prism2/2.5/3.
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
+ *
+ * Adaption to a generic IEEE 802.11 stack by James Ketrenos
+ * <jketreno@linux.intel.com>
+ *
+ * Copyright (c) 2004, Intel Corporation
+ *
+ */
+
+#ifndef LIB80211_H
+#define LIB80211_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <asm/atomic.h>
+#include <linux/if.h>
+#include <linux/skbuff.h>
+#include <linux/ieee80211.h>
+#include <linux/timer.h>
+/* print_ssid() is intended to be used in debug (and possibly error)
+ * messages. It should never be used for passing ssid to user space. */
+const char *print_ssid(char *buf, const char *ssid, u8 ssid_len);
+#define DECLARE_SSID_BUF(var) char var[IEEE80211_MAX_SSID_LEN * 4 + 1] __maybe_unused
+
+#define NUM_WEP_KEYS	4
+
+enum {
+	IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0),
+};
+
+struct lib80211_crypto_ops {
+	const char *name;
+	struct list_head list;
+
+	/* init new crypto context (e.g., allocate private data space,
+	 * select IV, etc.); returns NULL on failure or pointer to allocated
+	 * private data on success */
+	void *(*init) (int keyidx);
+
+	/* deinitialize crypto context and free allocated private data */
+	void (*deinit) (void *priv);
+
+	int (*build_iv) (struct sk_buff * skb, int hdr_len,
+			 u8 *key, int keylen, void *priv);
+
+	/* encrypt/decrypt return < 0 on error or >= 0 on success. The return
+	 * value from decrypt_mpdu is passed as the keyidx value for
+	 * decrypt_msdu. skb must have enough head and tail room for the
+	 * encryption; if not, error will be returned; these functions are
+	 * called for all MPDUs (i.e., fragments).
+	 */
+	int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
+	int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
+
+	/* These functions are called for full MSDUs, i.e. full frames.
+	 * These can be NULL if full MSDU operations are not needed. */
+	int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv);
+	int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len,
+			     void *priv);
+
+	int (*set_key) (void *key, int len, u8 * seq, void *priv);
+	int (*get_key) (void *key, int len, u8 * seq, void *priv);
+
+	/* procfs handler for printing out key information and possible
+	 * statistics */
+	char *(*print_stats) (char *p, void *priv);
+
+	/* Crypto specific flag get/set for configuration settings */
+	unsigned long (*get_flags) (void *priv);
+	unsigned long (*set_flags) (unsigned long flags, void *priv);
+
+	/* maximum number of bytes added by encryption; encrypt buf is
+	 * allocated with extra_prefix_len bytes, copy of in_buf, and
+	 * extra_postfix_len; encrypt need not use all this space, but
+	 * the result must start at the beginning of the buffer and correct
+	 * length must be returned */
+	int extra_mpdu_prefix_len, extra_mpdu_postfix_len;
+	int extra_msdu_prefix_len, extra_msdu_postfix_len;
+
+	struct module *owner;
+};
+
+struct lib80211_crypt_data {
+	struct list_head list;	/* delayed deletion list */
+	struct lib80211_crypto_ops *ops;
+	void *priv;
+	atomic_t refcnt;
+};
+
+struct lib80211_crypt_info {
+	char *name;
+	/* Most clients will already have a lock,
+	   so just point to that. */
+	spinlock_t *lock;
+
+	struct lib80211_crypt_data *crypt[NUM_WEP_KEYS];
+	int tx_keyidx;		/* default TX key index (crypt[tx_keyidx]) */
+	struct list_head crypt_deinit_list;
+	struct timer_list crypt_deinit_timer;
+	int crypt_quiesced;
+};
+
+int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name,
+                                spinlock_t *lock);
+void lib80211_crypt_info_free(struct lib80211_crypt_info *info);
+int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops);
+int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops);
+struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name);
+void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *, int);
+void lib80211_crypt_deinit_handler(unsigned long);
+void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
+				    struct lib80211_crypt_data **crypt);
+void lib80211_crypt_quiescing(struct lib80211_crypt_info *info);
+
+#endif /* LIB80211_H */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 73d81bc..b3bd00a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3,7 +3,7 @@
  *
  * Copyright 2002-2005, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
- * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2007-2008	Johannes Berg <johannes@sipsolutions.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -107,7 +107,7 @@
  * The information provided in this structure is required for QoS
  * transmit queue configuration. Cf. IEEE 802.11 7.3.2.29.
  *
- * @aifs: arbitration interface space [0..255]
+ * @aifs: arbitration interframe space [0..255]
  * @cw_min: minimum contention window [a value of the form
  *	2^n-1 in the range 1..32767]
  * @cw_max: maximum contention window [like @cw_min]
@@ -164,6 +164,14 @@
 };
 
 /**
+ * struct ieee80211_bss_ht_conf - BSS's changing HT configuration
+ * @operation_mode: HT operation mode (like in &struct ieee80211_ht_info)
+ */
+struct ieee80211_bss_ht_conf {
+	u16 operation_mode;
+};
+
+/**
  * struct ieee80211_bss_conf - holds the BSS's changing parameters
  *
  * This structure keeps information about a BSS (and an association
@@ -172,15 +180,17 @@
  * @assoc: association status
  * @aid: association ID number, valid only when @assoc is true
  * @use_cts_prot: use CTS protection
- * @use_short_preamble: use 802.11b short preamble
- * @use_short_slot: use short slot time (only relevant for ERP)
+ * @use_short_preamble: use 802.11b short preamble;
+ *	if the hardware cannot handle this it must set the
+ *	IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE hardware flag
+ * @use_short_slot: use short slot time (only relevant for ERP);
+ *	if the hardware cannot handle this it must set the
+ *	IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
  * @dtim_period: num of beacons before the next DTIM, for PSM
  * @timestamp: beacon timestamp
  * @beacon_int: beacon interval
  * @assoc_capability: capabilities taken from assoc resp
- * @assoc_ht: association in HT mode
- * @ht_conf: ht capabilities
- * @ht_bss_conf: ht extended capabilities
+ * @ht: BSS's HT configuration
  * @basic_rates: bitmap of basic rates, each bit stands for an
  *	index into the rate table configured by the driver in
  *	the current band.
@@ -198,10 +208,7 @@
 	u16 assoc_capability;
 	u64 timestamp;
 	u64 basic_rates;
-	/* ht related data */
-	bool assoc_ht;
-	struct ieee80211_ht_info *ht_conf;
-	struct ieee80211_ht_bss_info *ht_bss_conf;
+	struct ieee80211_bss_ht_conf ht;
 };
 
 /**
@@ -210,29 +217,24 @@
  * These flags are used with the @flags member of &ieee80211_tx_info.
  *
  * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame.
- * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame
- * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g.,
- *	for combined 802.11g / 802.11b networks)
+ * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
+ *	number to this frame, taking care of not overwriting the fragment
+ *	number and increasing the sequence number only when the
+ *	IEEE80211_TX_CTL_FIRST_FRAGMENT flag is set. mac80211 will properly
+ *	assign sequence numbers to QoS-data frames but cannot do so correctly
+ *	for non-QoS-data and management frames because beacons need them from
+ *	that counter as well and mac80211 cannot guarantee proper sequencing.
+ *	If this flag is set, the driver should instruct the hardware to
+ *	assign a sequence number to the frame or assign one itself. Cf. IEEE
+ *	802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for
+ *	beacons and always be clear for frames without a sequence number field.
  * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack
- * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: TBD
  * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination
  *	station
- * @IEEE80211_TX_CTL_REQUEUE: TBD
  * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame
- * @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD
- * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the
- *	through set_retry_limit configured long retry value
  * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon
  * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU
- * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number
- *	of streams when this flag is on can be extracted from antenna_sel_tx,
- *	so if 1 antenna is marked use SISO, 2 antennas marked use MIMO, n
- *	antennas marked use MIMO_n.
- * @IEEE80211_TX_CTL_GREEN_FIELD: use green field protection for this frame
- * @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width
- * @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels
- * @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval
- * @IEEE80211_TX_CTL_INJECTED: TBD
+ * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211.
  * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted
  *	because the destination STA was in powersave mode.
  * @IEEE80211_TX_STAT_ACK: Frame was acknowledged
@@ -240,63 +242,67 @@
  * 	is for the whole aggregation.
  * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned,
  * 	so consider using block ack request (BAR).
- * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
- *	number to this frame, taking care of not overwriting the fragment
- *	number and increasing the sequence number only when the
- *	IEEE80211_TX_CTL_FIRST_FRAGMENT flags is set. mac80211 will properly
- *	assign sequence numbers to QoS-data frames but cannot do so correctly
- *	for non-QoS-data and management frames because beacons need them from
- *	that counter as well and mac80211 cannot guarantee proper sequencing.
- *	If this flag is set, the driver should instruct the hardware to
- *	assign a sequence number to the frame or assign one itself. Cf. IEEE
- *	802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for
- *	beacons always be clear for frames without a sequence number field.
+ * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be
+ *	set by rate control algorithms to indicate probe rate, will
+ *	be cleared for fragmented frames (except on the last fragment)
  */
 enum mac80211_tx_control_flags {
 	IEEE80211_TX_CTL_REQ_TX_STATUS		= BIT(0),
-	IEEE80211_TX_CTL_USE_RTS_CTS		= BIT(2),
-	IEEE80211_TX_CTL_USE_CTS_PROTECT	= BIT(3),
-	IEEE80211_TX_CTL_NO_ACK			= BIT(4),
-	IEEE80211_TX_CTL_RATE_CTRL_PROBE	= BIT(5),
-	IEEE80211_TX_CTL_CLEAR_PS_FILT		= BIT(6),
-	IEEE80211_TX_CTL_REQUEUE		= BIT(7),
-	IEEE80211_TX_CTL_FIRST_FRAGMENT		= BIT(8),
-	IEEE80211_TX_CTL_SHORT_PREAMBLE		= BIT(9),
-	IEEE80211_TX_CTL_LONG_RETRY_LIMIT	= BIT(10),
-	IEEE80211_TX_CTL_SEND_AFTER_DTIM	= BIT(12),
-	IEEE80211_TX_CTL_AMPDU			= BIT(13),
-	IEEE80211_TX_CTL_OFDM_HT		= BIT(14),
-	IEEE80211_TX_CTL_GREEN_FIELD		= BIT(15),
-	IEEE80211_TX_CTL_40_MHZ_WIDTH		= BIT(16),
-	IEEE80211_TX_CTL_DUP_DATA		= BIT(17),
-	IEEE80211_TX_CTL_SHORT_GI		= BIT(18),
-	IEEE80211_TX_CTL_INJECTED		= BIT(19),
-	IEEE80211_TX_STAT_TX_FILTERED		= BIT(20),
-	IEEE80211_TX_STAT_ACK			= BIT(21),
-	IEEE80211_TX_STAT_AMPDU			= BIT(22),
-	IEEE80211_TX_STAT_AMPDU_NO_BACK		= BIT(23),
-	IEEE80211_TX_CTL_ASSIGN_SEQ		= BIT(24),
+	IEEE80211_TX_CTL_ASSIGN_SEQ		= BIT(1),
+	IEEE80211_TX_CTL_NO_ACK			= BIT(2),
+	IEEE80211_TX_CTL_CLEAR_PS_FILT		= BIT(3),
+	IEEE80211_TX_CTL_FIRST_FRAGMENT		= BIT(4),
+	IEEE80211_TX_CTL_SEND_AFTER_DTIM	= BIT(5),
+	IEEE80211_TX_CTL_AMPDU			= BIT(6),
+	IEEE80211_TX_CTL_INJECTED		= BIT(7),
+	IEEE80211_TX_STAT_TX_FILTERED		= BIT(8),
+	IEEE80211_TX_STAT_ACK			= BIT(9),
+	IEEE80211_TX_STAT_AMPDU			= BIT(10),
+	IEEE80211_TX_STAT_AMPDU_NO_BACK		= BIT(11),
+	IEEE80211_TX_CTL_RATE_CTRL_PROBE	= BIT(12),
+};
+
+enum mac80211_rate_control_flags {
+	IEEE80211_TX_RC_USE_RTS_CTS		= BIT(0),
+	IEEE80211_TX_RC_USE_CTS_PROTECT		= BIT(1),
+	IEEE80211_TX_RC_USE_SHORT_PREAMBLE	= BIT(2),
+
+	/* rate index is an MCS rate number instead of an index */
+	IEEE80211_TX_RC_MCS			= BIT(3),
+	IEEE80211_TX_RC_GREEN_FIELD		= BIT(4),
+	IEEE80211_TX_RC_40_MHZ_WIDTH		= BIT(5),
+	IEEE80211_TX_RC_DUP_DATA		= BIT(6),
+	IEEE80211_TX_RC_SHORT_GI		= BIT(7),
 };
 
 
-#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE \
-	(sizeof(((struct sk_buff *)0)->cb) - 8)
-#define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \
-	(IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *))
+/* there are 40 bytes if you don't need the rateset to be kept */
+#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40
 
-/* maximum number of alternate rate retry stages */
-#define IEEE80211_TX_MAX_ALTRATE	3
+/* if you do need the rateset, then you have less space */
+#define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24
+
+/* maximum number of rate stages */
+#define IEEE80211_TX_MAX_RATES	5
 
 /**
- * struct ieee80211_tx_altrate - alternate rate selection/status
+ * struct ieee80211_tx_rate - rate selection/status
  *
- * @rate_idx: rate index to attempt to send with
- * @limit: number of retries before fallback
+ * @idx: rate index to attempt to send with
+ * @flags: rate control flags (&enum mac80211_rate_control_flags)
+ * @count: number of tries in this rate before going to the next rate
+ *
+ * A value of -1 for @idx indicates an invalid rate and, if used
+ * in an array of retry rates, that no more rates should be tried.
+ *
+ * When used for transmit status reporting, the driver should
+ * always report the rate along with the flags it used.
  */
-struct ieee80211_tx_altrate {
-	s8 rate_idx;
-	u8 limit;
-};
+struct ieee80211_tx_rate {
+	s8 idx;
+	u8 count;
+	u8 flags;
+} __attribute__((packed));
 
 /**
  * struct ieee80211_tx_info - skb transmit information
@@ -310,15 +316,13 @@
  * it may be NULL.
  *
  * @flags: transmit info flags, defined above
- * @band: TBD
- * @tx_rate_idx: TBD
- * @antenna_sel_tx: TBD
+ * @band: the band to transmit on (use for checking for races)
+ * @antenna_sel_tx: antenna to use, 0 for automatic diversity
+ * @pad: padding, ignore
  * @control: union for control data
  * @status: union for status data
  * @driver_data: array of driver_data pointers
  * @retry_count: number of retries
- * @excessive_retries: set to 1 if the frame was retried many times
- *	but not acknowledged
  * @ampdu_ack_len: number of aggregated frames.
  * 	relevant only if IEEE80211_TX_STATUS_AMPDU was set.
  * @ampdu_ack_map: block ack bit map for the aggregation.
@@ -329,31 +333,44 @@
 	/* common information */
 	u32 flags;
 	u8 band;
-	s8 tx_rate_idx;
+
 	u8 antenna_sel_tx;
 
-	/* 1 byte hole */
+	/* 2 byte hole */
+	u8 pad[2];
 
 	union {
 		struct {
+			union {
+				/* rate control */
+				struct {
+					struct ieee80211_tx_rate rates[
+						IEEE80211_TX_MAX_RATES];
+					s8 rts_cts_rate_idx;
+				};
+				/* only needed before rate control */
+				unsigned long jiffies;
+			};
 			/* NB: vif can be NULL for injected frames */
 			struct ieee80211_vif *vif;
 			struct ieee80211_key_conf *hw_key;
 			struct ieee80211_sta *sta;
-			unsigned long jiffies;
-			s8 rts_cts_rate_idx;
-			u8 retry_limit;
-			struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE];
 		} control;
 		struct {
+			struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
+			u8 ampdu_ack_len;
 			u64 ampdu_ack_map;
 			int ack_signal;
-			struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE + 1];
-			u8 retry_count;
-			bool excessive_retries;
-			u8 ampdu_ack_len;
+			/* 8 bytes free */
 		} status;
-		void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_PTRS];
+		struct {
+			struct ieee80211_tx_rate driver_rates[
+				IEEE80211_TX_MAX_RATES];
+			void *rate_driver_data[
+				IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)];
+		};
+		void *driver_data[
+			IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)];
 	};
 };
 
@@ -362,6 +379,41 @@
 	return (struct ieee80211_tx_info *)skb->cb;
 }
 
+/**
+ * ieee80211_tx_info_clear_status - clear TX status
+ *
+ * @info: The &struct ieee80211_tx_info to be cleared.
+ *
+ * When the driver passes an skb back to mac80211, it must report
+ * a number of things in TX status. This function clears everything
+ * in the TX status but the rate control information (it does clear
+ * the count since you need to fill that in anyway).
+ *
+ * NOTE: You can only use this function if you do NOT use
+ *	 info->driver_data! Use info->rate_driver_data
+ *	 instead if you need only the less space that allows.
+ */
+static inline void
+ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
+{
+	int i;
+
+	BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) !=
+		     offsetof(struct ieee80211_tx_info, control.rates));
+	BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) !=
+		     offsetof(struct ieee80211_tx_info, driver_rates));
+	BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != 8);
+	/* clear the rate counts */
+	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++)
+		info->status.rates[i].count = 0;
+
+	BUILD_BUG_ON(
+	    offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23);
+	memset(&info->status.ampdu_ack_len, 0,
+	       sizeof(struct ieee80211_tx_info) -
+	       offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
+}
+
 
 /**
  * enum mac80211_rx_flags - receive flags
@@ -384,6 +436,9 @@
  *	is valid. This is useful in monitor mode and necessary for beacon frames
  *	to enable IBSS merging.
  * @RX_FLAG_SHORTPRE: Short preamble was used for this frame
+ * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
+ * @RX_FLAG_40MHZ: HT40 (40 MHz) was used
+ * @RX_FLAG_SHORT_GI: Short guard interval was used
  */
 enum mac80211_rx_flags {
 	RX_FLAG_MMIC_ERROR	= 1<<0,
@@ -394,7 +449,10 @@
 	RX_FLAG_FAILED_FCS_CRC	= 1<<5,
 	RX_FLAG_FAILED_PLCP_CRC = 1<<6,
 	RX_FLAG_TSFT		= 1<<7,
-	RX_FLAG_SHORTPRE	= 1<<8
+	RX_FLAG_SHORTPRE	= 1<<8,
+	RX_FLAG_HT		= 1<<9,
+	RX_FLAG_40MHZ		= 1<<10,
+	RX_FLAG_SHORT_GI	= 1<<11,
 };
 
 /**
@@ -414,7 +472,8 @@
  * @noise: noise when receiving this frame, in dBm.
  * @qual: overall signal quality indication, in percent (0-100).
  * @antenna: antenna used
- * @rate_idx: index of data rate into band's supported rates
+ * @rate_idx: index of data rate into band's supported rates or MCS index if
+ *	HT rates are use (RX_FLAG_HT)
  * @flag: %RX_FLAG_*
  */
 struct ieee80211_rx_status {
@@ -434,21 +493,49 @@
  *
  * Flags to define PHY configuration options
  *
- * @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time
  * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported)
- * @IEEE80211_CONF_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported)
  * @IEEE80211_CONF_PS: Enable 802.11 power save mode
  */
 enum ieee80211_conf_flags {
-	/*
-	 * TODO: IEEE80211_CONF_SHORT_SLOT_TIME will be removed once drivers
-	 * have been converted to use bss_info_changed() for slot time
-	 * configuration
-	 */
-	IEEE80211_CONF_SHORT_SLOT_TIME	= (1<<0),
-	IEEE80211_CONF_RADIOTAP		= (1<<1),
-	IEEE80211_CONF_SUPPORT_HT_MODE	= (1<<2),
-	IEEE80211_CONF_PS		= (1<<3),
+	IEEE80211_CONF_RADIOTAP		= (1<<0),
+	IEEE80211_CONF_PS		= (1<<1),
+};
+
+/* XXX: remove all this once drivers stop trying to use it */
+static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void)
+{
+	return 0;
+}
+#define IEEE80211_CONF_SHORT_SLOT_TIME (__IEEE80211_CONF_SHORT_SLOT_TIME())
+
+struct ieee80211_ht_conf {
+	bool enabled;
+	enum nl80211_channel_type channel_type;
+};
+
+/**
+ * enum ieee80211_conf_changed - denotes which configuration changed
+ *
+ * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed
+ * @IEEE80211_CONF_CHANGE_BEACON_INTERVAL: the beacon interval changed
+ * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed
+ * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed
+ * @IEEE80211_CONF_CHANGE_PS: the PS flag changed
+ * @IEEE80211_CONF_CHANGE_POWER: the TX power changed
+ * @IEEE80211_CONF_CHANGE_CHANNEL: the channel changed
+ * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
+ * @IEEE80211_CONF_CHANGE_HT: HT configuration changed
+ */
+enum ieee80211_conf_changed {
+	IEEE80211_CONF_CHANGE_RADIO_ENABLED	= BIT(0),
+	IEEE80211_CONF_CHANGE_BEACON_INTERVAL	= BIT(1),
+	IEEE80211_CONF_CHANGE_LISTEN_INTERVAL	= BIT(2),
+	IEEE80211_CONF_CHANGE_RADIOTAP		= BIT(3),
+	IEEE80211_CONF_CHANGE_PS		= BIT(4),
+	IEEE80211_CONF_CHANGE_POWER		= BIT(5),
+	IEEE80211_CONF_CHANGE_CHANNEL		= BIT(6),
+	IEEE80211_CONF_CHANGE_RETRY_LIMITS	= BIT(7),
+	IEEE80211_CONF_CHANGE_HT		= BIT(8),
 };
 
 /**
@@ -457,34 +544,31 @@
  * This struct indicates how the driver shall configure the hardware.
  *
  * @radio_enabled: when zero, driver is required to switch off the radio.
- *	TODO make a flag
  * @beacon_int: beacon interval (TODO make interface config)
  * @listen_interval: listen interval in units of beacon interval
  * @flags: configuration flags defined above
  * @power_level: requested transmit power (in dBm)
- * @max_antenna_gain: maximum antenna gain (in dBi)
- * @antenna_sel_tx: transmit antenna selection, 0: default/diversity,
- *	1/2: antenna 0/1
- * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx
- * @ht_conf: describes current self configuration of 802.11n HT capabilies
- * @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters
  * @channel: the channel to tune to
+ * @ht: the HT configuration for the device
+ * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame
+ *    (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11,
+ *    but actually means the number of transmissions not the number of retries
+ * @short_frame_max_tx_count: Maximum number of transmissions for a "short"
+ *    frame, called "dot11ShortRetryLimit" in 802.11, but actually means the
+ *    number of transmissions not the number of retries
  */
 struct ieee80211_conf {
-	int radio_enabled;
-
 	int beacon_int;
-	u16 listen_interval;
 	u32 flags;
 	int power_level;
-	int max_antenna_gain;
-	u8 antenna_sel_tx;
-	u8 antenna_sel_rx;
+
+	u16 listen_interval;
+	bool radio_enabled;
+
+	u8 long_frame_max_tx_count, short_frame_max_tx_count;
 
 	struct ieee80211_channel *channel;
-
-	struct ieee80211_ht_info ht_conf;
-	struct ieee80211_ht_bss_info ht_bss_conf;
+	struct ieee80211_ht_conf ht;
 };
 
 /**
@@ -494,11 +578,14 @@
  * use during the life of a virtual interface.
  *
  * @type: type of this virtual interface
+ * @bss_conf: BSS configuration for this interface, either our own
+ *	or the BSS we're associated to
  * @drv_priv: data area for driver use, will always be aligned to
  *	sizeof(void *).
  */
 struct ieee80211_vif {
 	enum nl80211_iftype type;
+	struct ieee80211_bss_conf bss_conf;
 	/* must be last */
 	u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
 };
@@ -542,14 +629,12 @@
  * enum ieee80211_if_conf_change - interface config change flags
  *
  * @IEEE80211_IFCC_BSSID: The BSSID changed.
- * @IEEE80211_IFCC_SSID: The SSID changed.
  * @IEEE80211_IFCC_BEACON: The beacon for this interface changed
  *	(currently AP and MESH only), use ieee80211_beacon_get().
  */
 enum ieee80211_if_conf_change {
 	IEEE80211_IFCC_BSSID	= BIT(0),
-	IEEE80211_IFCC_SSID	= BIT(1),
-	IEEE80211_IFCC_BEACON	= BIT(2),
+	IEEE80211_IFCC_BEACON	= BIT(1),
 };
 
 /**
@@ -557,11 +642,6 @@
  *
  * @changed: parameters that have changed, see &enum ieee80211_if_conf_change.
  * @bssid: BSSID of the network we are associated to/creating.
- * @ssid: used (together with @ssid_len) by drivers for hardware that
- *	generate beacons independently. The pointer is valid only during the
- *	config_interface() call, so copy the value somewhere if you need
- *	it.
- * @ssid_len: length of the @ssid field.
  *
  * This structure is passed to the config_interface() callback of
  * &struct ieee80211_hw.
@@ -569,8 +649,6 @@
 struct ieee80211_if_conf {
 	u32 changed;
 	u8 *bssid;
-	u8 *ssid;
-	size_t ssid_len;
 };
 
 /**
@@ -677,7 +755,7 @@
  * @addr: MAC address
  * @aid: AID we assigned to the station if we're an AP
  * @supp_rates: Bitmap of supported rates (per band)
- * @ht_info: HT capabilities of this STA
+ * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities
  * @drv_priv: data area for driver use, will always be aligned to
  *	sizeof(void *), size is determined in hw information.
  */
@@ -685,7 +763,7 @@
 	u64 supp_rates[IEEE80211_NUM_BANDS];
 	u8 addr[ETH_ALEN];
 	u16 aid;
-	struct ieee80211_ht_info ht_info;
+	struct ieee80211_sta_ht_cap ht_cap;
 
 	/* must be last */
 	u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
@@ -695,13 +773,17 @@
  * enum sta_notify_cmd - sta notify command
  *
  * Used with the sta_notify() callback in &struct ieee80211_ops, this
- * indicates addition and removal of a station to station table.
+ * indicates addition and removal of a station to station table,
+ * or if a associated station made a power state transition.
  *
  * @STA_NOTIFY_ADD: a station was added to the station table
  * @STA_NOTIFY_REMOVE: a station being removed from the station table
+ * @STA_NOTIFY_SLEEP: a station is now sleeping
+ * @STA_NOTIFY_AWAKE: a sleeping station woke up
  */
 enum sta_notify_cmd {
-	STA_NOTIFY_ADD, STA_NOTIFY_REMOVE
+	STA_NOTIFY_ADD, STA_NOTIFY_REMOVE,
+	STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE,
 };
 
 /**
@@ -769,6 +851,14 @@
  * @IEEE80211_HW_SPECTRUM_MGMT:
  * 	Hardware supports spectrum management defined in 802.11h
  * 	Measurement, Channel Switch, Quieting, TPC
+ *
+ * @IEEE80211_HW_AMPDU_AGGREGATION:
+ *	Hardware supports 11n A-MPDU aggregation.
+ *
+ * @IEEE80211_HW_NO_STACK_DYNAMIC_PS:
+ *	Hardware which has dynamic power save support, meaning
+ *	that power save is enabled in idle periods, and don't need support
+ *	from stack.
  */
 enum ieee80211_hw_flags {
 	IEEE80211_HW_RX_INCLUDES_FCS			= 1<<1,
@@ -780,6 +870,8 @@
 	IEEE80211_HW_SIGNAL_DBM				= 1<<7,
 	IEEE80211_HW_NOISE_DBM				= 1<<8,
 	IEEE80211_HW_SPECTRUM_MGMT			= 1<<9,
+	IEEE80211_HW_AMPDU_AGGREGATION			= 1<<10,
+	IEEE80211_HW_NO_STACK_DYNAMIC_PS		= 1<<11,
 };
 
 /**
@@ -838,8 +930,8 @@
  * @sta_data_size: size (in bytes) of the drv_priv data area
  *	within &struct ieee80211_sta.
  *
- * @max_altrates: maximum number of alternate rate retry stages
- * @max_altrate_tries: maximum number of tries for each stage
+ * @max_rates: maximum number of alternate rate retry stages
+ * @max_rate_tries: maximum number of tries for each stage
  */
 struct ieee80211_hw {
 	struct ieee80211_conf conf;
@@ -856,12 +948,10 @@
 	u16 ampdu_queues;
 	u16 max_listen_interval;
 	s8 max_signal;
-	u8 max_altrates;
-	u8 max_altrate_tries;
+	u8 max_rates;
+	u8 max_rate_tries;
 };
 
-struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy);
-
 /**
  * SET_IEEE80211_DEV - set device for 802.11 hardware
  *
@@ -874,7 +964,7 @@
 }
 
 /**
- * SET_IEEE80211_PERM_ADDR - set the permanenet MAC address for 802.11 hardware
+ * SET_IEEE80211_PERM_ADDR - set the permanent MAC address for 802.11 hardware
  *
  * @hw: the &struct ieee80211_hw to set the MAC address for
  * @addr: the address to set
@@ -898,9 +988,9 @@
 ieee80211_get_tx_rate(const struct ieee80211_hw *hw,
 		      const struct ieee80211_tx_info *c)
 {
-	if (WARN_ON(c->tx_rate_idx < 0))
+	if (WARN_ON(c->control.rates[0].idx < 0))
 		return NULL;
-	return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx];
+	return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx];
 }
 
 static inline struct ieee80211_rate *
@@ -916,9 +1006,9 @@
 ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
 			     const struct ieee80211_tx_info *c, int idx)
 {
-	if (c->control.retries[idx].rate_idx < 0)
+	if (c->control.rates[idx + 1].idx < 0)
 		return NULL;
-	return &hw->wiphy->bands[c->band]->bitrates[c->control.retries[idx].rate_idx];
+	return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx];
 }
 
 /**
@@ -967,7 +1057,7 @@
  * This happens everytime the iv16 wraps around (every 65536 packets). The
  * set_key() call will happen only once for each key (unless the AP did
  * rekeying), it will not include a valid phase 1 key. The valid phase 1 key is
- * provided by udpate_tkip_key only. The trigger that makes mac80211 call this
+ * provided by update_tkip_key only. The trigger that makes mac80211 call this
  * handler is software decryption with wrap around of iv16.
  */
 
@@ -1060,12 +1150,14 @@
  * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation
  * @IEEE80211_AMPDU_TX_START: start Tx aggregation
  * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation
+ * @IEEE80211_AMPDU_TX_RESUME: resume TX aggregation
  */
 enum ieee80211_ampdu_mlme_action {
 	IEEE80211_AMPDU_RX_START,
 	IEEE80211_AMPDU_RX_STOP,
 	IEEE80211_AMPDU_TX_START,
 	IEEE80211_AMPDU_TX_STOP,
+	IEEE80211_AMPDU_TX_RESUME,
 };
 
 /**
@@ -1101,7 +1193,7 @@
  *	Must be implemented.
  *
  * @add_interface: Called when a netdevice attached to the hardware is
- *	enabled. Because it is not called for monitor mode devices, @open
+ *	enabled. Because it is not called for monitor mode devices, @start
  *	and @stop must be implemented.
  *	The driver should perform any initialization it needs before
  *	the device can be enabled. The initial configuration for the
@@ -1163,14 +1255,9 @@
  *
  * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
  *
- * @set_frag_threshold: Configuration of fragmentation threshold. Assign this if
- *	the device does fragmentation by itself; if this method is assigned then
- *	the stack will not do fragmentation.
- *
- * @set_retry_limit: Configuration of retry limits (if device needs it)
- *
- * @sta_notify: Notifies low level driver about addition or removal
- *	of assocaited station or AP.
+ * @sta_notify: Notifies low level driver about addition, removal or power
+ *	state transition of an associated station, AP,  IBSS/WDS/mesh peer etc.
+ *	Must be atomic.
  *
  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
  *	bursting) for a hardware TX queue.
@@ -1194,8 +1281,6 @@
  *	This is needed only for IBSS mode and the result of this function is
  *	used to determine whether to reply to Probe Requests.
  *
- * @conf_ht: Configures low level driver with 802.11n HT data. Must be atomic.
- *
  * @ampdu_action: Perform a certain A-MPDU action
  * 	The RA/TID combination determines the destination and TID we want
  * 	the ampdu action to be performed for. The action is defined through
@@ -1211,7 +1296,7 @@
 			     struct ieee80211_if_init_conf *conf);
 	void (*remove_interface)(struct ieee80211_hw *hw,
 				 struct ieee80211_if_init_conf *conf);
-	int (*config)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+	int (*config)(struct ieee80211_hw *hw, u32 changed);
 	int (*config_interface)(struct ieee80211_hw *hw,
 				struct ieee80211_vif *vif,
 				struct ieee80211_if_conf *conf);
@@ -1237,9 +1322,6 @@
 	void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
 			     u32 *iv32, u16 *iv16);
 	int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
-	int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
-	int (*set_retry_limit)(struct ieee80211_hw *hw,
-			       u32 short_retry, u32 long_retr);
 	void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			enum sta_notify_cmd, struct ieee80211_sta *sta);
 	int (*conf_tx)(struct ieee80211_hw *hw, u16 queue,
@@ -1472,7 +1554,7 @@
  * the next beacon frame from the 802.11 code. The low-level is responsible
  * for calling this function before beacon data is needed (e.g., based on
  * hardware interrupt). Returned skb is used only once and low-level driver
- * is responsible of freeing it.
+ * is responsible for freeing it.
  */
 struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 				     struct ieee80211_vif *vif);
@@ -1803,24 +1885,38 @@
 
 
 /* Rate control API */
+
 /**
- * struct rate_selection - rate information for/from rate control algorithms
+ * struct ieee80211_tx_rate_control - rate control information for/from RC algo
  *
- * @rate_idx: selected transmission rate index
- * @nonerp_idx: Non-ERP rate to use instead if ERP cannot be used
- * @probe_idx: rate for probing (or -1)
- * @max_rate_idx: maximum rate index that can be used, this is
- *	input to the algorithm and will be enforced
+ * @hw: The hardware the algorithm is invoked for.
+ * @sband: The band this frame is being transmitted on.
+ * @bss_conf: the current BSS configuration
+ * @reported_rate: The rate control algorithm can fill this in to indicate
+ *	which rate should be reported to userspace as the current rate and
+ *	used for rate calculations in the mesh network.
+ * @rts: whether RTS will be used for this frame because it is longer than the
+ *	RTS threshold
+ * @short_preamble: whether mac80211 will request short-preamble transmission
+ *	if the selected rate supports it
+ * @max_rate_idx: user-requested maximum rate (not MCS for now)
+ * @skb: the skb that will be transmitted, the control information in it needs
+ *	to be filled in
  */
-struct rate_selection {
-	s8 rate_idx, nonerp_idx, probe_idx, max_rate_idx;
+struct ieee80211_tx_rate_control {
+	struct ieee80211_hw *hw;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_bss_conf *bss_conf;
+	struct sk_buff *skb;
+	struct ieee80211_tx_rate reported_rate;
+	bool rts, short_preamble;
+	u8 max_rate_idx;
 };
 
 struct rate_control_ops {
 	struct module *module;
 	const char *name;
 	void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir);
-	void (*clear)(void *priv);
 	void (*free)(void *priv);
 
 	void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp);
@@ -1832,10 +1928,8 @@
 	void (*tx_status)(void *priv, struct ieee80211_supported_band *sband,
 			  struct ieee80211_sta *sta, void *priv_sta,
 			  struct sk_buff *skb);
-	void (*get_rate)(void *priv, struct ieee80211_supported_band *sband,
-			 struct ieee80211_sta *sta, void *priv_sta,
-			 struct sk_buff *skb,
-			 struct rate_selection *sel);
+	void (*get_rate)(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+			 struct ieee80211_tx_rate_control *txrc);
 
 	void (*add_sta_debugfs)(void *priv, void *priv_sta,
 				struct dentry *dir);
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 11dd013..ce532f2 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -108,6 +108,20 @@
 
 extern int			ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir);
 
+extern struct sk_buff		*ndisc_build_skb(struct net_device *dev,
+						 const struct in6_addr *daddr,
+						 const struct in6_addr *saddr,
+						 struct icmp6hdr *icmp6h,
+						 const struct in6_addr *target,
+						 int llinfo);
+
+extern void			ndisc_send_skb(struct sk_buff *skb,
+					       struct net_device *dev,
+					       struct neighbour *neigh,
+					       const struct in6_addr *daddr,
+					       const struct in6_addr *saddr,
+					       struct icmp6hdr *icmp6h);
+
 
 
 /*
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index aa4b708..d8d790e 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -180,9 +180,6 @@
 	__u32			hash_rnd;
 	unsigned int		hash_chain_gc;
 	struct pneigh_entry	**phash_buckets;
-#ifdef CONFIG_PROC_FS
-	struct proc_dir_entry	*pde;
-#endif
 };
 
 /* flags for neigh_update() */
@@ -223,11 +220,7 @@
 static inline
 struct net			*neigh_parms_net(const struct neigh_parms *parms)
 {
-#ifdef CONFIG_NET_NS
-	return parms->net;
-#else
-	return &init_net;
-#endif
+	return read_pnet(&parms->net);
 }
 
 extern unsigned long		neigh_rand_reach_time(unsigned long base);
@@ -244,11 +237,7 @@
 static inline
 struct net			*pneigh_net(const struct pneigh_entry *pneigh)
 {
-#ifdef CONFIG_NET_NS
-	return pneigh->net;
-#else
-	return &init_net;
-#endif
+	return read_pnet(&pneigh->net);
 }
 
 extern void neigh_app_ns(struct neighbour *n);
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 700c53a..6fc13d9 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -19,6 +19,7 @@
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 #include <net/netns/conntrack.h>
 #endif
+#include <net/netns/xfrm.h>
 
 struct proc_dir_entry;
 struct net_device;
@@ -74,6 +75,9 @@
 	struct netns_ct		ct;
 #endif
 #endif
+#ifdef CONFIG_XFRM
+	struct netns_xfrm	xfrm;
+#endif
 	struct net_generic	*gen;
 };
 
@@ -192,6 +196,24 @@
 }
 #endif
 
+#ifdef CONFIG_NET_NS
+
+static inline void write_pnet(struct net **pnet, struct net *net)
+{
+	*pnet = net;
+}
+
+static inline struct net *read_pnet(struct net * const *pnet)
+{
+	return *pnet;
+}
+
+#else
+
+#define write_pnet(pnet, net)	do { (void)(net);} while (0)
+#define read_pnet(pnet)		(&init_net)
+
+#endif
 
 #define for_each_net(VAR)				\
 	list_for_each_entry(VAR, &net_namespace_list, list)
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index b76a868..2e0c536 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -199,7 +199,7 @@
 
 extern void nf_conntrack_hash_insert(struct nf_conn *ct);
 
-extern void nf_conntrack_flush(struct net *net);
+extern void nf_conntrack_flush(struct net *net, u32 pid, int report);
 
 extern bool nf_ct_get_tuplepr(const struct sk_buff *skb,
 			      unsigned int nhoff, u_int16_t l3num,
@@ -298,5 +298,8 @@
 	local_bh_enable();				\
 } while (0)
 
+#define MODULE_ALIAS_NFCT_HELPER(helper) \
+        MODULE_ALIAS("nfct-helper-" helper)
+
 #endif /* __KERNEL__ */
 #endif /* _NF_CONNTRACK_H */
diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h
index 1285ff2..0ff0dc6 100644
--- a/include/net/netfilter/nf_conntrack_ecache.h
+++ b/include/net/netfilter/nf_conntrack_ecache.h
@@ -17,6 +17,13 @@
 	unsigned int events;
 };
 
+/* This structure is passed to event handler */
+struct nf_ct_event {
+	struct nf_conn *ct;
+	u32 pid;
+	int report;
+};
+
 extern struct atomic_notifier_head nf_conntrack_chain;
 extern int nf_conntrack_register_notifier(struct notifier_block *nb);
 extern int nf_conntrack_unregister_notifier(struct notifier_block *nb);
@@ -39,22 +46,56 @@
 	local_bh_enable();
 }
 
-static inline void nf_conntrack_event(enum ip_conntrack_events event,
-				      struct nf_conn *ct)
+static inline void
+nf_conntrack_event_report(enum ip_conntrack_events event,
+			  struct nf_conn *ct,
+			  u32 pid,
+			  int report)
 {
+	struct nf_ct_event item = {
+		.ct 	= ct,
+		.pid	= pid,
+		.report = report
+	};
 	if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct))
-		atomic_notifier_call_chain(&nf_conntrack_chain, event, ct);
+		atomic_notifier_call_chain(&nf_conntrack_chain, event, &item);
 }
 
+static inline void
+nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct)
+{
+	nf_conntrack_event_report(event, ct, 0, 0);
+}
+
+struct nf_exp_event {
+	struct nf_conntrack_expect *exp;
+	u32 pid;
+	int report;
+};
+
 extern struct atomic_notifier_head nf_ct_expect_chain;
 extern int nf_ct_expect_register_notifier(struct notifier_block *nb);
 extern int nf_ct_expect_unregister_notifier(struct notifier_block *nb);
 
 static inline void
+nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
+			  struct nf_conntrack_expect *exp,
+			  u32 pid,
+			  int report)
+{
+	struct nf_exp_event item = {
+		.exp	= exp,
+		.pid	= pid,
+		.report = report
+	};
+	atomic_notifier_call_chain(&nf_ct_expect_chain, event, &item);
+}
+
+static inline void
 nf_ct_expect_event(enum ip_conntrack_expect_events event,
 		   struct nf_conntrack_expect *exp)
 {
-	atomic_notifier_call_chain(&nf_ct_expect_chain, event, exp);
+	nf_ct_expect_event_report(event, exp, 0, 0);
 }
 
 extern int nf_conntrack_ecache_init(struct net *net);
@@ -66,9 +107,17 @@
 					    struct nf_conn *ct) {}
 static inline void nf_conntrack_event(enum ip_conntrack_events event,
 				      struct nf_conn *ct) {}
+static inline void nf_conntrack_event_report(enum ip_conntrack_events event,
+					     struct nf_conn *ct,
+					     u32 pid,
+					     int report) {}
 static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {}
 static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event,
 				      struct nf_conntrack_expect *exp) {}
+static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e,
+					     struct nf_conntrack_expect *exp,
+ 					     u32 pid,
+ 					     int report) {}
 static inline void nf_ct_event_cache_flush(struct net *net) {}
 
 static inline int nf_conntrack_ecache_init(struct net *net)
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index 37a7fc1..ab17a15 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -100,6 +100,8 @@
 		       u_int8_t, const __be16 *, const __be16 *);
 void nf_ct_expect_put(struct nf_conntrack_expect *exp);
 int nf_ct_expect_related(struct nf_conntrack_expect *expect);
+int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, 
+				u32 pid, int report);
 
 #endif /*_NF_CONNTRACK_EXPECT_H*/
 
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index f8060ab..66d65a7 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -39,9 +39,6 @@
 };
 
 extern struct nf_conntrack_helper *
-__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple);
-
-extern struct nf_conntrack_helper *
 __nf_conntrack_helper_find_byname(const char *name);
 
 extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
@@ -49,6 +46,8 @@
 
 extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp);
 
+extern int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags);
+
 static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
 {
 	return nf_ct_ext_find(ct, NF_CT_EXT_HELPER);
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index 7f2f43c..debdaf7 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -129,7 +129,7 @@
 	 && net_ratelimit())
 #endif
 #else
-#define LOG_INVALID(net, proto) 0
+static inline int LOG_INVALID(struct net *net, int proto) { return 0; }
 #endif /* CONFIG_SYSCTL */
 
 #endif /*_NF_CONNTRACK_PROTOCOL_H*/
diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h
index a6874ba2..f2f6aa7 100644
--- a/include/net/netfilter/nf_conntrack_tuple.h
+++ b/include/net/netfilter/nf_conntrack_tuple.h
@@ -112,20 +112,20 @@
 static inline void nf_ct_dump_tuple_ip(const struct nf_conntrack_tuple *t)
 {
 #ifdef DEBUG
-	printk("tuple %p: %u " NIPQUAD_FMT ":%hu -> " NIPQUAD_FMT ":%hu\n",
+	printk("tuple %p: %u %pI4:%hu -> %pI4:%hu\n",
 	       t, t->dst.protonum,
-	       NIPQUAD(t->src.u3.ip), ntohs(t->src.u.all),
-	       NIPQUAD(t->dst.u3.ip), ntohs(t->dst.u.all));
+	       &t->src.u3.ip, ntohs(t->src.u.all),
+	       &t->dst.u3.ip, ntohs(t->dst.u.all));
 #endif
 }
 
 static inline void nf_ct_dump_tuple_ipv6(const struct nf_conntrack_tuple *t)
 {
 #ifdef DEBUG
-	printk("tuple %p: %u " NIP6_FMT " %hu -> " NIP6_FMT " %hu\n",
+	printk("tuple %p: %u %pI6 %hu -> %pI6 %hu\n",
 	       t, t->dst.protonum,
-	       NIP6(*(struct in6_addr *)t->src.u3.all), ntohs(t->src.u.all),
-	       NIP6(*(struct in6_addr *)t->dst.u3.all), ntohs(t->dst.u.all));
+	       t->src.u3.all, ntohs(t->src.u.all),
+	       t->dst.u3.all, ntohs(t->dst.u.all));
 #endif
 }
 
diff --git a/include/net/netfilter/nfnetlink_log.h b/include/net/netfilter/nfnetlink_log.h
new file mode 100644
index 0000000..b0569ff
--- /dev/null
+++ b/include/net/netfilter/nfnetlink_log.h
@@ -0,0 +1,14 @@
+#ifndef _KER_NFNETLINK_LOG_H
+#define _KER_NFNETLINK_LOG_H
+
+void
+nfulnl_log_packet(u_int8_t pf,
+		  unsigned int hooknum,
+		  const struct sk_buff *skb,
+		  const struct net_device *in,
+		  const struct net_device *out,
+		  const struct nf_loginfo *li_user,
+		  const char *prefix);
+
+#endif /* _KER_NFNETLINK_LOG_H */
+
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 3643bbb..8a6150a 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -233,7 +233,7 @@
 extern struct nlattr *	nla_find(struct nlattr *head, int len, int attrtype);
 extern size_t		nla_strlcpy(char *dst, const struct nlattr *nla,
 				    size_t dstsize);
-extern int		nla_memcpy(void *dest, struct nlattr *src, int count);
+extern int		nla_memcpy(void *dest, const struct nlattr *src, int count);
 extern int		nla_memcmp(const struct nlattr *nla, const void *data,
 				   size_t size);
 extern int		nla_strcmp(const struct nlattr *nla, const char *str);
@@ -332,7 +332,7 @@
  */
 static inline int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
 {
-	return (remaining >= sizeof(struct nlmsghdr) &&
+	return (remaining >= (int) sizeof(struct nlmsghdr) &&
 		nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
 		nlh->nlmsg_len <= remaining);
 }
@@ -741,7 +741,7 @@
  * See nla_parse()
  */
 static inline int nla_parse_nested(struct nlattr *tb[], int maxtype,
-				   struct nlattr *nla,
+				   const struct nlattr *nla,
 				   const struct nla_policy *policy)
 {
 	return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
@@ -875,7 +875,7 @@
  * nla_get_u32 - return payload of u32 attribute
  * @nla: u32 netlink attribute
  */
-static inline u32 nla_get_u32(struct nlattr *nla)
+static inline u32 nla_get_u32(const struct nlattr *nla)
 {
 	return *(u32 *) nla_data(nla);
 }
@@ -884,7 +884,7 @@
  * nla_get_be32 - return payload of __be32 attribute
  * @nla: __be32 netlink attribute
  */
-static inline __be32 nla_get_be32(struct nlattr *nla)
+static inline __be32 nla_get_be32(const struct nlattr *nla)
 {
 	return *(__be32 *) nla_data(nla);
 }
@@ -893,7 +893,7 @@
  * nla_get_u16 - return payload of u16 attribute
  * @nla: u16 netlink attribute
  */
-static inline u16 nla_get_u16(struct nlattr *nla)
+static inline u16 nla_get_u16(const struct nlattr *nla)
 {
 	return *(u16 *) nla_data(nla);
 }
@@ -902,7 +902,7 @@
  * nla_get_be16 - return payload of __be16 attribute
  * @nla: __be16 netlink attribute
  */
-static inline __be16 nla_get_be16(struct nlattr *nla)
+static inline __be16 nla_get_be16(const struct nlattr *nla)
 {
 	return *(__be16 *) nla_data(nla);
 }
@@ -911,7 +911,7 @@
  * nla_get_le16 - return payload of __le16 attribute
  * @nla: __le16 netlink attribute
  */
-static inline __le16 nla_get_le16(struct nlattr *nla)
+static inline __le16 nla_get_le16(const struct nlattr *nla)
 {
 	return *(__le16 *) nla_data(nla);
 }
@@ -920,7 +920,7 @@
  * nla_get_u8 - return payload of u8 attribute
  * @nla: u8 netlink attribute
  */
-static inline u8 nla_get_u8(struct nlattr *nla)
+static inline u8 nla_get_u8(const struct nlattr *nla)
 {
 	return *(u8 *) nla_data(nla);
 }
@@ -929,7 +929,7 @@
  * nla_get_u64 - return payload of u64 attribute
  * @nla: u64 netlink attribute
  */
-static inline u64 nla_get_u64(struct nlattr *nla)
+static inline u64 nla_get_u64(const struct nlattr *nla)
 {
 	u64 tmp;
 
@@ -942,7 +942,7 @@
  * nla_get_flag - return payload of flag attribute
  * @nla: flag netlink attribute
  */
-static inline int nla_get_flag(struct nlattr *nla)
+static inline int nla_get_flag(const struct nlattr *nla)
 {
 	return !!nla;
 }
@@ -953,7 +953,7 @@
  *
  * Returns the number of milliseconds in jiffies.
  */
-static inline unsigned long nla_get_msecs(struct nlattr *nla)
+static inline unsigned long nla_get_msecs(const struct nlattr *nla)
 {
 	u64 msecs = nla_get_u64(nla);
 
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index ece1c92..977f482 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -49,6 +49,8 @@
 	int sysctl_icmp_ratelimit;
 	int sysctl_icmp_ratemask;
 	int sysctl_icmp_errors_use_inbound_ifaddr;
+	int sysctl_rt_cache_rebuild_count;
+	int current_rt_cache_rebuild_count;
 
 	struct timer_list rt_secret_timer;
 	atomic_t rt_genid;
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 2932721..afab4e4 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -55,5 +55,17 @@
 	struct sock             *ndisc_sk;
 	struct sock             *tcp_sk;
 	struct sock             *igmp_sk;
+#ifdef CONFIG_IPV6_MROUTE
+	struct sock		*mroute6_sk;
+	struct mfc6_cache	**mfc6_cache_array;
+	struct mif_device	*vif6_table;
+	int			maxvif;
+	atomic_t		cache_resolve_queue_len;
+	int			mroute_do_assert;
+	int			mroute_do_pim;
+#ifdef CONFIG_IPV6_PIMSM_V2
+	int			mroute_reg_vif_num;
+#endif
+#endif
 };
 #endif
diff --git a/include/net/netns/mib.h b/include/net/netns/mib.h
index 10cb7c3..0b44112 100644
--- a/include/net/netns/mib.h
+++ b/include/net/netns/mib.h
@@ -20,6 +20,9 @@
 	DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
 	DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics);
 #endif
+#ifdef CONFIG_XFRM_STATISTICS
+	DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics);
+#endif
 };
 
 #endif
diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
index b809397..9554a64 100644
--- a/include/net/netns/x_tables.h
+++ b/include/net/netns/x_tables.h
@@ -4,7 +4,12 @@
 #include <linux/list.h>
 #include <linux/netfilter.h>
 
+struct ebt_table;
+
 struct netns_xt {
 	struct list_head tables[NFPROTO_NUMPROTO];
+	struct ebt_table *broute_table;
+	struct ebt_table *frame_filter;
+	struct ebt_table *frame_nat;
 };
 #endif
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h
new file mode 100644
index 0000000..1ba9127
--- /dev/null
+++ b/include/net/netns/xfrm.h
@@ -0,0 +1,56 @@
+#ifndef __NETNS_XFRM_H
+#define __NETNS_XFRM_H
+
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/xfrm.h>
+
+struct ctl_table_header;
+
+struct xfrm_policy_hash {
+	struct hlist_head	*table;
+	unsigned int		hmask;
+};
+
+struct netns_xfrm {
+	struct list_head	state_all;
+	/*
+	 * Hash table to find appropriate SA towards given target (endpoint of
+	 * tunnel or destination of transport mode) allowed by selector.
+	 *
+	 * Main use is finding SA after policy selected tunnel or transport
+	 * mode. Also, it can be used by ah/esp icmp error handler to find
+	 * offending SA.
+	 */
+	struct hlist_head	*state_bydst;
+	struct hlist_head	*state_bysrc;
+	struct hlist_head	*state_byspi;
+	unsigned int		state_hmask;
+	unsigned int		state_num;
+	struct work_struct	state_hash_work;
+	struct hlist_head	state_gc_list;
+	struct work_struct	state_gc_work;
+
+	wait_queue_head_t	km_waitq;
+
+	struct list_head	policy_all;
+	struct hlist_head	*policy_byidx;
+	unsigned int		policy_idx_hmask;
+	struct hlist_head	policy_inexact[XFRM_POLICY_MAX * 2];
+	struct xfrm_policy_hash	policy_bydst[XFRM_POLICY_MAX * 2];
+	unsigned int		policy_count[XFRM_POLICY_MAX * 2];
+	struct work_struct	policy_hash_work;
+
+	struct sock		*nlsk;
+
+	u32			sysctl_aevent_etime;
+	u32			sysctl_aevent_rseqth;
+	int			sysctl_larval_drop;
+	u32			sysctl_acq_expires;
+#ifdef CONFIG_SYSCTL
+	struct ctl_table_header	*sysctl_hdr;
+#endif
+};
+
+#endif
diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h
index fcd7930..4c61cdc 100644
--- a/include/net/phonet/pep.h
+++ b/include/net/phonet/pep.h
@@ -35,12 +35,12 @@
 	struct sock		*listener;
 	struct sk_buff_head	ctrlreq_queue;
 #define PNPIPE_CTRLREQ_MAX	10
+	atomic_t		tx_credits;
 	int			ifindex;
 	u16			peer_type;	/* peer type/subtype */
 	u8			pipe_handle;
 
 	u8			rx_credits;
-	u8			tx_credits;
 	u8			rx_fc;	/* RX flow control */
 	u8			tx_fc;	/* TX flow control */
 	u8			init_enable;	/* auto-enable at creation */
diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h
index c6a2451..057b0a8 100644
--- a/include/net/phonet/phonet.h
+++ b/include/net/phonet/phonet.h
@@ -46,7 +46,7 @@
 
 extern const struct proto_ops phonet_dgram_ops;
 
-struct sock *pn_find_sock_by_sa(const struct sockaddr_pn *sa);
+struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *sa);
 void phonet_get_local_port_range(int *min, int *max);
 void pn_sock_hash(struct sock *sk);
 void pn_sock_unhash(struct sock *sk);
diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h
index bbd2a83..aa1c59a 100644
--- a/include/net/phonet/pn_dev.h
+++ b/include/net/phonet/pn_dev.h
@@ -43,7 +43,7 @@
 int phonet_address_add(struct net_device *dev, u8 addr);
 int phonet_address_del(struct net_device *dev, u8 addr);
 u8 phonet_address_get(struct net_device *dev, u8 addr);
-int phonet_address_lookup(u8 addr);
+int phonet_address_lookup(struct net *net, u8 addr);
 
 #define PN_NO_ADDR	0xff
 
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index aa9e282..d1ca314 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -246,7 +246,7 @@
 };
 
 extern int tcf_em_register(struct tcf_ematch_ops *);
-extern int tcf_em_unregister(struct tcf_ematch_ops *);
+extern void tcf_em_unregister(struct tcf_ematch_ops *);
 extern int tcf_em_tree_validate(struct tcf_proto *, struct nlattr *,
 				struct tcf_ematch_tree *);
 extern void tcf_em_tree_destroy(struct tcf_proto *, struct tcf_ematch_tree *);
diff --git a/include/net/protocol.h b/include/net/protocol.h
index 8d024d7..cb2965a 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -39,6 +39,9 @@
 	int			(*gso_send_check)(struct sk_buff *skb);
 	struct sk_buff	       *(*gso_segment)(struct sk_buff *skb,
 					       int features);
+	struct sk_buff	      **(*gro_receive)(struct sk_buff **head,
+					       struct sk_buff *skb);
+	int			(*gro_complete)(struct sk_buff *skb);
 	unsigned int		no_policy:1,
 				netns_ok:1;
 };
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 3fe49d8..f8c4742 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -53,7 +53,6 @@
 	atomic_t		refcnt;
 	unsigned long		state;
 	struct sk_buff		*gso_skb;
-	struct sk_buff_head	requeue;
 	struct sk_buff_head	q;
 	struct netdev_queue	*dev_queue;
 	struct Qdisc		*next_sched;
@@ -111,7 +110,7 @@
 
 	int 			(*enqueue)(struct sk_buff *, struct Qdisc *);
 	struct sk_buff *	(*dequeue)(struct Qdisc *);
-	int 			(*requeue)(struct sk_buff *, struct Qdisc *);
+	struct sk_buff *	(*peek)(struct Qdisc *);
 	unsigned int		(*drop)(struct Qdisc *);
 
 	int			(*init)(struct Qdisc *, struct nlattr *arg);
@@ -432,19 +431,38 @@
 	return __qdisc_dequeue_tail(sch, &sch->q);
 }
 
-static inline int __qdisc_requeue(struct sk_buff *skb, struct Qdisc *sch,
-				  struct sk_buff_head *list)
+static inline struct sk_buff *qdisc_peek_head(struct Qdisc *sch)
 {
-	__skb_queue_head(list, skb);
-	sch->qstats.backlog += qdisc_pkt_len(skb);
-	sch->qstats.requeues++;
-
-	return NET_XMIT_SUCCESS;
+	return skb_peek(&sch->q);
 }
 
-static inline int qdisc_requeue(struct sk_buff *skb, struct Qdisc *sch)
+/* generic pseudo peek method for non-work-conserving qdisc */
+static inline struct sk_buff *qdisc_peek_dequeued(struct Qdisc *sch)
 {
-	return __qdisc_requeue(skb, sch, &sch->q);
+	/* we can reuse ->gso_skb because peek isn't called for root qdiscs */
+	if (!sch->gso_skb) {
+		sch->gso_skb = sch->dequeue(sch);
+		if (sch->gso_skb)
+			/* it's still part of the queue */
+			sch->q.qlen++;
+	}
+
+	return sch->gso_skb;
+}
+
+/* use instead of qdisc->dequeue() for all qdiscs queried with ->peek() */
+static inline struct sk_buff *qdisc_dequeue_peeked(struct Qdisc *sch)
+{
+	struct sk_buff *skb = sch->gso_skb;
+
+	if (skb) {
+		sch->gso_skb = NULL;
+		sch->q.qlen--;
+	} else {
+		skb = sch->dequeue(sch);
+	}
+
+	return skb;
 }
 
 static inline void __qdisc_reset_queue(struct Qdisc *sch,
diff --git a/include/net/scm.h b/include/net/scm.h
index 33e9986..f45bb6e 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -55,8 +55,8 @@
 			       struct scm_cookie *scm)
 {
 	struct task_struct *p = current;
-	scm->creds.uid = p->uid;
-	scm->creds.gid = p->gid;
+	scm->creds.uid = current_uid();
+	scm->creds.gid = current_gid();
 	scm->creds.pid = task_tgid_vnr(p);
 	scm->fp = NULL;
 	scm->seq = 0;
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index ed71b11..bbb7742 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -138,6 +138,7 @@
 unsigned int sctp_poll(struct file *file, struct socket *sock,
 		poll_table *wait);
 void sctp_sock_rfree(struct sk_buff *skb);
+extern struct percpu_counter sctp_sockets_allocated;
 
 /*
  * sctp/primitive.c
@@ -285,15 +286,15 @@
 	if (sctp_debug_flag) { \
 		if (saddr->sa.sa_family == AF_INET6) { \
 			printk(KERN_DEBUG \
-			       lead NIP6_FMT trail, \
+			       lead "%pI6" trail, \
 			       leadparm, \
-			       NIP6(saddr->v6.sin6_addr), \
+			       &saddr->v6.sin6_addr, \
 			       otherparms); \
 		} else { \
 			printk(KERN_DEBUG \
-			       lead NIPQUAD_FMT trail, \
+			       lead "%pI4" trail, \
 			       leadparm, \
-			       NIPQUAD(saddr->v4.sin_addr.s_addr), \
+			       &saddr->v4.sin_addr.s_addr, \
 			       otherparms); \
 		} \
 	}
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
index f205b10..b259fc5 100644
--- a/include/net/sctp/user.h
+++ b/include/net/sctp/user.h
@@ -118,6 +118,8 @@
 #define SCTP_PEER_AUTH_CHUNKS SCTP_PEER_AUTH_CHUNKS
 	SCTP_LOCAL_AUTH_CHUNKS,		/* Read only */
 #define SCTP_LOCAL_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS
+	SCTP_GET_ASSOC_NUMBER,		/* Read only */
+#define SCTP_GET_ASSOC_NUMBER SCTP_GET_ASSOC_NUMBER
 
 
 	/* Internal Socket Options. Some of the sctp library functions are 
diff --git a/include/net/sock.h b/include/net/sock.h
index 2f47107..5a3a151 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -42,6 +42,7 @@
 
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/list_nulls.h>
 #include <linux/timer.h>
 #include <linux/cache.h>
 #include <linux/module.h>
@@ -52,6 +53,7 @@
 #include <linux/security.h>
 
 #include <linux/filter.h>
+#include <linux/rculist_nulls.h>
 
 #include <asm/atomic.h>
 #include <net/dst.h>
@@ -106,6 +108,7 @@
  *	@skc_reuse: %SO_REUSEADDR setting
  *	@skc_bound_dev_if: bound device index if != 0
  *	@skc_node: main hash linkage for various protocol lookup tables
+ *	@skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol
  *	@skc_bind_node: bind hash linkage for various protocol lookup tables
  *	@skc_refcnt: reference count
  *	@skc_hash: hash value used with various protocol lookup tables
@@ -120,7 +123,10 @@
 	volatile unsigned char	skc_state;
 	unsigned char		skc_reuse;
 	int			skc_bound_dev_if;
-	struct hlist_node	skc_node;
+	union {
+		struct hlist_node	skc_node;
+		struct hlist_nulls_node skc_nulls_node;
+	};
 	struct hlist_node	skc_bind_node;
 	atomic_t		skc_refcnt;
 	unsigned int		skc_hash;
@@ -206,6 +212,7 @@
 #define sk_reuse		__sk_common.skc_reuse
 #define sk_bound_dev_if		__sk_common.skc_bound_dev_if
 #define sk_node			__sk_common.skc_node
+#define sk_nulls_node		__sk_common.skc_nulls_node
 #define sk_bind_node		__sk_common.skc_bind_node
 #define sk_refcnt		__sk_common.skc_refcnt
 #define sk_hash			__sk_common.skc_hash
@@ -229,7 +236,9 @@
 	} sk_backlog;
 	wait_queue_head_t	*sk_sleep;
 	struct dst_entry	*sk_dst_cache;
+#ifdef CONFIG_XFRM
 	struct xfrm_policy	*sk_policy[2];
+#endif
 	rwlock_t		sk_dst_lock;
 	atomic_t		sk_rmem_alloc;
 	atomic_t		sk_wmem_alloc;
@@ -237,7 +246,9 @@
 	int			sk_sndbuf;
 	struct sk_buff_head	sk_receive_queue;
 	struct sk_buff_head	sk_write_queue;
+#ifdef CONFIG_NET_DMA
 	struct sk_buff_head	sk_async_wait_queue;
+#endif
 	int			sk_wmem_queued;
 	int			sk_forward_alloc;
 	gfp_t			sk_allocation;
@@ -269,7 +280,9 @@
 	struct sk_buff		*sk_send_head;
 	__u32			sk_sndmsg_off;
 	int			sk_write_pending;
+#ifdef CONFIG_SECURITY
 	void			*sk_security;
+#endif
 	__u32			sk_mark;
 	/* XXX 4 bytes hole on 64 bit */
 	void			(*sk_state_change)(struct sock *sk);
@@ -294,12 +307,30 @@
 	return hlist_empty(head) ? NULL : __sk_head(head);
 }
 
+static inline struct sock *__sk_nulls_head(const struct hlist_nulls_head *head)
+{
+	return hlist_nulls_entry(head->first, struct sock, sk_nulls_node);
+}
+
+static inline struct sock *sk_nulls_head(const struct hlist_nulls_head *head)
+{
+	return hlist_nulls_empty(head) ? NULL : __sk_nulls_head(head);
+}
+
 static inline struct sock *sk_next(const struct sock *sk)
 {
 	return sk->sk_node.next ?
 		hlist_entry(sk->sk_node.next, struct sock, sk_node) : NULL;
 }
 
+static inline struct sock *sk_nulls_next(const struct sock *sk)
+{
+	return (!is_a_nulls(sk->sk_nulls_node.next)) ?
+		hlist_nulls_entry(sk->sk_nulls_node.next,
+				  struct sock, sk_nulls_node) :
+		NULL;
+}
+
 static inline int sk_unhashed(const struct sock *sk)
 {
 	return hlist_unhashed(&sk->sk_node);
@@ -315,6 +346,11 @@
 	node->pprev = NULL;
 }
 
+static __inline__ void sk_nulls_node_init(struct hlist_nulls_node *node)
+{
+	node->pprev = NULL;
+}
+
 static __inline__ void __sk_del_node(struct sock *sk)
 {
 	__hlist_del(&sk->sk_node);
@@ -361,6 +397,27 @@
 	return rc;
 }
 
+static __inline__ int __sk_nulls_del_node_init_rcu(struct sock *sk)
+{
+	if (sk_hashed(sk)) {
+		hlist_nulls_del_init_rcu(&sk->sk_nulls_node);
+		return 1;
+	}
+	return 0;
+}
+
+static __inline__ int sk_nulls_del_node_init_rcu(struct sock *sk)
+{
+	int rc = __sk_nulls_del_node_init_rcu(sk);
+
+	if (rc) {
+		/* paranoid for a while -acme */
+		WARN_ON(atomic_read(&sk->sk_refcnt) == 1);
+		__sock_put(sk);
+	}
+	return rc;
+}
+
 static __inline__ void __sk_add_node(struct sock *sk, struct hlist_head *list)
 {
 	hlist_add_head(&sk->sk_node, list);
@@ -372,6 +429,17 @@
 	__sk_add_node(sk, list);
 }
 
+static __inline__ void __sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list)
+{
+	hlist_nulls_add_head_rcu(&sk->sk_nulls_node, list);
+}
+
+static __inline__ void sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list)
+{
+	sock_hold(sk);
+	__sk_nulls_add_node_rcu(sk, list);
+}
+
 static __inline__ void __sk_del_bind_node(struct sock *sk)
 {
 	__hlist_del(&sk->sk_bind_node);
@@ -385,9 +453,16 @@
 
 #define sk_for_each(__sk, node, list) \
 	hlist_for_each_entry(__sk, node, list, sk_node)
+#define sk_nulls_for_each(__sk, node, list) \
+	hlist_nulls_for_each_entry(__sk, node, list, sk_nulls_node)
+#define sk_nulls_for_each_rcu(__sk, node, list) \
+	hlist_nulls_for_each_entry_rcu(__sk, node, list, sk_nulls_node)
 #define sk_for_each_from(__sk, node) \
 	if (__sk && ({ node = &(__sk)->sk_node; 1; })) \
 		hlist_for_each_entry_from(__sk, node, sk_node)
+#define sk_nulls_for_each_from(__sk, node) \
+	if (__sk && ({ node = &(__sk)->sk_nulls_node; 1; })) \
+		hlist_nulls_for_each_entry_from(__sk, node, sk_nulls_node)
 #define sk_for_each_continue(__sk, node) \
 	if (__sk && ({ node = &(__sk)->sk_node; 1; })) \
 		hlist_for_each_entry_continue(__sk, node, sk_node)
@@ -574,7 +649,7 @@
 	/* Memory pressure */
 	void			(*enter_memory_pressure)(struct sock *sk);
 	atomic_t		*memory_allocated;	/* Current allocated memory. */
-	atomic_t		*sockets_allocated;	/* Current number of sockets. */
+	struct percpu_counter	*sockets_allocated;	/* Current number of sockets. */
 	/*
 	 * Pressure flag: try to collapse.
 	 * Technical note: it is used by multiple contexts non atomically.
@@ -587,17 +662,18 @@
 	int			*sysctl_rmem;
 	int			max_header;
 
-	struct kmem_cache		*slab;
+	struct kmem_cache	*slab;
 	unsigned int		obj_size;
+	int			slab_flags;
 
-	atomic_t		*orphan_count;
+	struct percpu_counter	*orphan_count;
 
 	struct request_sock_ops	*rsk_prot;
 	struct timewait_sock_ops *twsk_prot;
 
 	union {
 		struct inet_hashinfo	*hashinfo;
-		struct hlist_head	*udp_hash;
+		struct udp_table	*udp_table;
 		struct raw_hashinfo	*raw_hash;
 	} h;
 
diff --git a/include/net/syncppp.h b/include/net/syncppp.h
deleted file mode 100644
index 9e306f7..0000000
--- a/include/net/syncppp.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Defines for synchronous PPP/Cisco link level subroutines.
- *
- * Copyright (C) 1994 Cronyx Ltd.
- * Author: Serge Vakulenko, <vak@zebub.msk.su>
- *
- * This software is distributed with NO WARRANTIES, not even the implied
- * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Authors grant any other persons or organizations permission to use
- * or modify this software as long as this message is kept with the software,
- * all derivative works or modified versions.
- *
- * Version 1.7, Wed Jun  7 22:12:02 MSD 1995
- *
- *
- *
- */
-
-#ifndef _SYNCPPP_H_
-#define _SYNCPPP_H_ 1
-
-#ifdef __KERNEL__
-struct slcp {
-	u16	state;          /* state machine */
-	u32	magic;          /* local magic number */
-	u_char	echoid;         /* id of last keepalive echo request */
-	u_char	confid;         /* id of last configuration request */
-};
-
-struct sipcp {
-	u16	state;          /* state machine */
-	u_char  confid;         /* id of last configuration request */
-};
-
-struct sppp 
-{
-	struct sppp *	pp_next;	/* next interface in keepalive list */
-	u32		pp_flags;	/* use Cisco protocol instead of PPP */
-	u16		pp_alivecnt;	/* keepalive packets counter */
-	u16		pp_loopcnt;	/* loopback detection counter */
-	u32		pp_seq;		/* local sequence number */
-	u32		pp_rseq;	/* remote sequence number */
-	struct slcp	lcp;		/* LCP params */
-	struct sipcp	ipcp;		/* IPCP params */
-	struct timer_list	pp_timer;
-	struct net_device	*pp_if;
-	char		pp_link_state;	/* Link status */
-	spinlock_t      lock;
-};
-
-struct ppp_device
-{	
-	struct net_device *dev;	/* Network device pointer */
-	struct sppp sppp;	/* Synchronous PPP */
-};
-
-static inline struct sppp *sppp_of(struct net_device *dev) 
-{
-	struct ppp_device **ppp = dev->ml_priv;
-	BUG_ON((*ppp)->dev != dev);
-	return &(*ppp)->sppp;
-}
-
-#define PP_KEEPALIVE    0x01    /* use keepalive protocol */
-#define PP_CISCO        0x02    /* use Cisco protocol instead of PPP */
-#define PP_TIMO         0x04    /* cp_timeout routine active */
-#define PP_DEBUG	0x08
-
-#define PPP_MTU          1500    /* max. transmit unit */
-
-#define LCP_STATE_CLOSED        0       /* LCP state: closed (conf-req sent) */
-#define LCP_STATE_ACK_RCVD      1       /* LCP state: conf-ack received */
-#define LCP_STATE_ACK_SENT      2       /* LCP state: conf-ack sent */
-#define LCP_STATE_OPENED        3       /* LCP state: opened */
-
-#define IPCP_STATE_CLOSED       0       /* IPCP state: closed (conf-req sent) */
-#define IPCP_STATE_ACK_RCVD     1       /* IPCP state: conf-ack received */
-#define IPCP_STATE_ACK_SENT     2       /* IPCP state: conf-ack sent */
-#define IPCP_STATE_OPENED       3       /* IPCP state: opened */
-
-#define SPPP_LINK_DOWN		0	/* link down - no keepalive */
-#define SPPP_LINK_UP		1	/* link is up - keepalive ok */
-
-void sppp_attach (struct ppp_device *pd);
-void sppp_detach (struct net_device *dev);
-int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
-struct sk_buff *sppp_dequeue (struct net_device *dev);
-int sppp_isempty (struct net_device *dev);
-void sppp_flush (struct net_device *dev);
-int sppp_open (struct net_device *dev);
-int sppp_reopen (struct net_device *dev);
-int sppp_close (struct net_device *dev);
-#endif
-
-#define SPPPIOCCISCO	(SIOCDEVPRIVATE)
-#define SPPPIOCPPP	(SIOCDEVPRIVATE+1)
-#define SPPPIOCDEBUG	(SIOCDEVPRIVATE+2)
-#define SPPPIOCSFLAGS	(SIOCDEVPRIVATE+3)
-#define SPPPIOCGFLAGS	(SIOCDEVPRIVATE+4)
-
-#endif /* _SYNCPPP_H_ */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 438014d..218235d 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -46,7 +46,7 @@
 
 extern struct inet_hashinfo tcp_hashinfo;
 
-extern atomic_t tcp_orphan_count;
+extern struct percpu_counter tcp_orphan_count;
 extern void tcp_time_wait(struct sock *sk, int state, int timeo);
 
 #define MAX_TCP_HEADER	(128 + MAX_HEADER)
@@ -238,7 +238,7 @@
 extern int sysctl_tcp_max_ssthresh;
 
 extern atomic_t tcp_memory_allocated;
-extern atomic_t tcp_sockets_allocated;
+extern struct percpu_counter tcp_sockets_allocated;
 extern int tcp_memory_pressure;
 
 /*
@@ -472,8 +472,6 @@
 
 /* tcp_input.c */
 extern void tcp_cwnd_application_limited(struct sock *sk);
-extern void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp,
-					    struct sk_buff *skb);
 
 /* tcp_timer.c */
 extern void tcp_init_xmit_timers(struct sock *);
@@ -590,7 +588,6 @@
 #define TCPCB_EVER_RETRANS	0x80	/* Ever retransmitted frame	*/
 #define TCPCB_RETRANS		(TCPCB_SACKED_RETRANS|TCPCB_EVER_RETRANS)
 
-	__u16		urg_ptr;	/* Valid w/URG flags is set.	*/
 	__u32		ack_seq;	/* Sequence number ACK'd	*/
 };
 
@@ -764,8 +761,6 @@
 	return tp->packets_out - tcp_left_out(tp) + tp->retrans_out;
 }
 
-extern int tcp_limit_reno_sacked(struct tcp_sock *tp);
-
 /* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd.
  * The exception is rate halving phase, when cwnd is decreasing towards
  * ssthresh.
@@ -1195,6 +1190,11 @@
 	return skb_queue_next(&sk->sk_write_queue, skb);
 }
 
+static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_buff *skb)
+{
+	return skb_queue_prev(&sk->sk_write_queue, skb);
+}
+
 #define tcp_for_write_queue(skb, sk)					\
 	skb_queue_walk(&(sk)->sk_write_queue, skb)
 
@@ -1358,6 +1358,12 @@
 
 extern int tcp_v4_gso_send_check(struct sk_buff *skb);
 extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features);
+extern struct sk_buff **tcp_gro_receive(struct sk_buff **head,
+					struct sk_buff *skb);
+extern struct sk_buff **tcp4_gro_receive(struct sk_buff **head,
+					 struct sk_buff *skb);
+extern int tcp_gro_complete(struct sk_buff *skb);
+extern int tcp4_gro_complete(struct sk_buff *skb);
 
 #ifdef CONFIG_PROC_FS
 extern int  tcp4_proc_init(void);
diff --git a/include/net/udp.h b/include/net/udp.h
index 1e20509..90e6ce5 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -50,8 +50,15 @@
 };
 #define UDP_SKB_CB(__skb)	((struct udp_skb_cb *)((__skb)->cb))
 
-extern struct hlist_head udp_hash[UDP_HTABLE_SIZE];
-extern rwlock_t udp_hash_lock;
+struct udp_hslot {
+	struct hlist_nulls_head	head;
+	spinlock_t		lock;
+} __attribute__((aligned(2 * sizeof(long))));
+struct udp_table {
+	struct udp_hslot	hash[UDP_HTABLE_SIZE];
+};
+extern struct udp_table udp_table;
+extern void udp_table_init(struct udp_table *);
 
 
 /* Note: this must match 'valbool' in sock_setsockopt */
@@ -110,15 +117,7 @@
 	BUG();
 }
 
-static inline void udp_lib_unhash(struct sock *sk)
-{
-	write_lock_bh(&udp_hash_lock);
-	if (sk_del_node_init(sk)) {
-		inet_sk(sk)->num = 0;
-		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
-	}
-	write_unlock_bh(&udp_hash_lock);
-}
+extern void udp_lib_unhash(struct sock *sk);
 
 static inline void udp_lib_close(struct sock *sk, long timeout)
 {
@@ -187,7 +186,7 @@
 struct udp_seq_afinfo {
 	char			*name;
 	sa_family_t		family;
-	struct hlist_head	*hashtable;
+	struct udp_table	*udp_table;
 	struct file_operations	seq_fops;
 	struct seq_operations	seq_ops;
 };
@@ -196,7 +195,7 @@
 	struct seq_net_private  p;
 	sa_family_t		family;
 	int			bucket;
-	struct hlist_head	*hashtable;
+	struct udp_table	*udp_table;
 };
 
 #ifdef CONFIG_PROC_FS
diff --git a/include/net/udplite.h b/include/net/udplite.h
index b76b2e3..afdffe6 100644
--- a/include/net/udplite.h
+++ b/include/net/udplite.h
@@ -11,7 +11,7 @@
 #define UDPLITE_RECV_CSCOV   11 /* receiver partial coverage (threshold ) */
 
 extern struct proto 		udplite_prot;
-extern struct hlist_head 	udplite_hash[UDP_HTABLE_SIZE];
+extern struct udp_table		udplite_table;
 
 /*
  *	Checksum computation is all in software, hence simpler getfrag.
diff --git a/include/net/wireless.h b/include/net/wireless.h
index 721efb3..21c5d96 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -10,6 +10,7 @@
 #include <linux/netdevice.h>
 #include <linux/debugfs.h>
 #include <linux/list.h>
+#include <linux/ieee80211.h>
 #include <net/cfg80211.h>
 
 /**
@@ -133,23 +134,23 @@
 };
 
 /**
- * struct ieee80211_ht_info - describing STA's HT capabilities
+ * struct ieee80211_sta_ht_cap - STA's HT capabilities
  *
  * This structure describes most essential parameters needed
  * to describe 802.11n HT capabilities for an STA.
  *
- * @ht_supported: is HT supported by STA, 0: no, 1: yes
+ * @ht_supported: is HT supported by the STA
  * @cap: HT capabilities map as described in 802.11n spec
  * @ampdu_factor: Maximum A-MPDU length factor
  * @ampdu_density: Minimum A-MPDU spacing
- * @supp_mcs_set: Supported MCS set as described in 802.11n spec
+ * @mcs: Supported MCS rates
  */
-struct ieee80211_ht_info {
+struct ieee80211_sta_ht_cap {
 	u16 cap; /* use IEEE80211_HT_CAP_ */
-	u8 ht_supported;
+	bool ht_supported;
 	u8 ampdu_factor;
 	u8 ampdu_density;
-	u8 supp_mcs_set[16];
+	struct ieee80211_mcs_info mcs;
 };
 
 /**
@@ -173,13 +174,18 @@
 	enum ieee80211_band band;
 	int n_channels;
 	int n_bitrates;
-	struct ieee80211_ht_info ht_info;
+	struct ieee80211_sta_ht_cap ht_cap;
 };
 
 /**
  * struct wiphy - wireless hardware description
  * @idx: the wiphy index assigned to this item
  * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
+ * @fw_handles_regulatory: tells us the firmware for this device
+ * 	has its own regulatory solution and cannot identify the
+ * 	ISO / IEC 3166 alpha2 it belongs to. When this is enabled
+ * 	we will disregard the first regulatory hint (when the
+ * 	initiator is %REGDOM_SET_BY_CORE).
  * @reg_notifier: the driver's regulatory notification callback
  */
 struct wiphy {
@@ -191,6 +197,8 @@
 	/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
 	u16 interface_modes;
 
+	bool fw_handles_regulatory;
+
 	/* If multiple wiphys are registered and you're handed e.g.
 	 * a regular netdev with assigned ieee80211_ptr, you won't
 	 * know whether it points to a wiphy your driver has registered
@@ -262,9 +270,9 @@
 /**
  * wiphy_name - get wiphy name
  */
-static inline char *wiphy_name(struct wiphy *wiphy)
+static inline const char *wiphy_name(struct wiphy *wiphy)
 {
-	return wiphy->dev.bus_id;
+	return dev_name(&wiphy->dev);
 }
 
 /**
@@ -340,55 +348,51 @@
 }
 
 /**
- * __regulatory_hint - hint to the wireless core a regulatory domain
- * @wiphy: if a driver is providing the hint this is the driver's very
- * 	own &struct wiphy
- * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain
- * 	should be in. If @rd is set this should be NULL
- * @rd: a complete regulatory domain, if passed the caller need not worry
- * 	about freeing it
+ * ieee80211_get_response_rate - get basic rate for a given rate
  *
- * The Wireless subsystem can use this function to hint to the wireless core
- * what it believes should be the current regulatory domain by
- * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory
- * domain should be in or by providing a completely build regulatory domain.
+ * @sband: the band to look for rates in
+ * @basic_rates: bitmap of basic rates
+ * @bitrate: the bitrate for which to find the basic rate
  *
- * Returns -EALREADY if *a regulatory domain* has already been set. Note that
- * this could be by another driver. It is safe for drivers to continue if
- * -EALREADY is returned, if drivers are not capable of world roaming they
- * should not register more channels than they support. Right now we only
- * support listening to the first driver hint. If the driver is capable
- * of world roaming but wants to respect its own EEPROM mappings for
- * specific regulatory domains it should register the @reg_notifier callback
- * on the &struct wiphy. Returns 0 if the hint went through fine or through an
- * intersection operation. Otherwise a standard error code is returned.
- *
+ * This function returns the basic rate corresponding to a given
+ * bitrate, that is the next lower bitrate contained in the basic
+ * rate map, which is, for this function, given as a bitmap of
+ * indices of rates in the band's bitrate table.
  */
-extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
-		const char *alpha2, struct ieee80211_regdomain *rd);
+struct ieee80211_rate *
+ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
+			    u64 basic_rates, int bitrate);
+
 /**
  * regulatory_hint - driver hint to the wireless core a regulatory domain
- * @wiphy: the driver's very own &struct wiphy
+ * @wiphy: the wireless device giving the hint (used only for reporting
+ *	conflicts)
  * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain
  * 	should be in. If @rd is set this should be NULL. Note that if you
  * 	set this to NULL you should still set rd->alpha2 to some accepted
  * 	alpha2.
- * @rd: a complete regulatory domain provided by the driver. If passed
- * 	the driver does not need to worry about freeing it.
  *
  * Wireless drivers can use this function to hint to the wireless core
  * what it believes should be the current regulatory domain by
  * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory
  * domain should be in or by providing a completely build regulatory domain.
  * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried
- * for a regulatory domain structure for the respective country. If
- * a regulatory domain is build and passed you should set the alpha2
- * if possible, otherwise set it to the special value of "99" which tells
- * the wireless core it is unknown. If you pass a built regulatory domain
- * and we return non zero you are in charge of kfree()'ing the structure.
- *
- * See __regulatory_hint() documentation for possible return values.
+ * for a regulatory domain structure for the respective country.
  */
-extern int regulatory_hint(struct wiphy *wiphy,
-		const char *alpha2, struct ieee80211_regdomain *rd);
+extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2);
+
+/**
+ * regulatory_hint_11d - hints a country IE as a regulatory domain
+ * @wiphy: the wireless device giving the hint (used only for reporting
+ *	conflicts)
+ * @country_ie: pointer to the country IE
+ * @country_ie_len: length of the country IE
+ *
+ * We will intersect the rd with the what CRDA tells us should apply
+ * for the alpha2 this country IE belongs to, this prevents APs from
+ * sending us incorrect or outdated information against a country.
+ */
+extern void regulatory_hint_11d(struct wiphy *wiphy,
+				u8 *country_ie,
+				u8 country_ie_len);
 #endif /* __NET_WIRELESS_H */
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 11c890a..2e9f5c0 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -38,22 +38,15 @@
 	MODULE_ALIAS("xfrm-type-" __stringify(family) "-" __stringify(proto))
 
 #ifdef CONFIG_XFRM_STATISTICS
-DECLARE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics);
-#define XFRM_INC_STATS(field)		SNMP_INC_STATS(xfrm_statistics, field)
-#define XFRM_INC_STATS_BH(field)	SNMP_INC_STATS_BH(xfrm_statistics, field)
-#define XFRM_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(xfrm_statistics, field)
+#define XFRM_INC_STATS(net, field)	SNMP_INC_STATS((net)->mib.xfrm_statistics, field)
+#define XFRM_INC_STATS_BH(net, field)	SNMP_INC_STATS_BH((net)->mib.xfrm_statistics, field)
+#define XFRM_INC_STATS_USER(net, field)	SNMP_INC_STATS_USER((net)-mib.xfrm_statistics, field)
 #else
-#define XFRM_INC_STATS(field)
-#define XFRM_INC_STATS_BH(field)
-#define XFRM_INC_STATS_USER(field)
+#define XFRM_INC_STATS(net, field)	((void)(net))
+#define XFRM_INC_STATS_BH(net, field)	((void)(net))
+#define XFRM_INC_STATS_USER(net, field)	((void)(net))
 #endif
 
-extern struct sock *xfrm_nl;
-extern u32 sysctl_xfrm_aevent_etime;
-extern u32 sysctl_xfrm_aevent_rseqth;
-extern int sysctl_xfrm_larval_drop;
-extern u32 sysctl_xfrm_acq_expires;
-
 extern struct mutex xfrm_cfg_mutex;
 
 /* Organization of SPD aka "XFRM rules"
@@ -130,6 +123,9 @@
 /* Full description of state of transformer. */
 struct xfrm_state
 {
+#ifdef CONFIG_NET_NS
+	struct net		*xs_net;
+#endif
 	union {
 		struct hlist_node	gclist;
 		struct hlist_node	bydst;
@@ -223,6 +219,11 @@
 	void			*data;
 };
 
+static inline struct net *xs_net(struct xfrm_state *x)
+{
+	return read_pnet(&x->xs_net);
+}
+
 /* xflags - make enum if more show up */
 #define XFRM_TIME_DEFER	1
 
@@ -249,6 +250,7 @@
 	u32	seq;
 	u32	pid;
 	u32	event;
+	struct net *net;
 };
 
 struct net_device;
@@ -257,10 +259,11 @@
 struct xfrm_policy_afinfo {
 	unsigned short		family;
 	struct dst_ops		*dst_ops;
-	void			(*garbage_collect)(void);
-	struct dst_entry	*(*dst_lookup)(int tos, xfrm_address_t *saddr,
+	void			(*garbage_collect)(struct net *net);
+	struct dst_entry	*(*dst_lookup)(struct net *net, int tos,
+					       xfrm_address_t *saddr,
 					       xfrm_address_t *daddr);
-	int			(*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr);
+	int			(*get_saddr)(struct net *net, xfrm_address_t *saddr, xfrm_address_t *daddr);
 	struct dst_entry	*(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
 	void			(*decode_session)(struct sk_buff *skb,
 						  struct flowi *fl,
@@ -467,7 +470,9 @@
 
 struct xfrm_policy
 {
-	struct xfrm_policy	*next;
+#ifdef CONFIG_NET_NS
+	struct net		*xp_net;
+#endif
 	struct hlist_node	bydst;
 	struct hlist_node	byidx;
 
@@ -492,6 +497,11 @@
 	struct xfrm_tmpl       	xfrm_vec[XFRM_MAX_DEPTH];
 };
 
+static inline struct net *xp_net(struct xfrm_policy *xp)
+{
+	return read_pnet(&xp->xp_net);
+}
+
 struct xfrm_kmaddress {
 	xfrm_address_t          local;
 	xfrm_address_t          remote;
@@ -537,15 +547,13 @@
 	struct xfrm_policy	*(*compile_policy)(struct sock *sk, int opt, u8 *data, int len, int *dir);
 	int			(*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
 	int			(*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
-	int			(*report)(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
+	int			(*report)(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
 	int			(*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles, struct xfrm_kmaddress *k);
 };
 
 extern int xfrm_register_km(struct xfrm_mgr *km);
 extern int xfrm_unregister_km(struct xfrm_mgr *km);
 
-extern unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
-
 /*
  * This structure is used for the duration where packets are being
  * transformed by IPsec.  As soon as the packet leaves IPsec the
@@ -882,6 +890,7 @@
 	u32 path_cookie;
 };
 
+#ifdef CONFIG_XFRM
 static inline void xfrm_dst_destroy(struct xfrm_dst *xdst)
 {
 	dst_release(xdst->route);
@@ -894,6 +903,7 @@
 	xdst->partner = NULL;
 #endif
 }
+#endif
 
 extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev);
 
@@ -977,12 +987,13 @@
 				       struct sk_buff *skb,
 				       unsigned int family, int reverse)
 {
+	struct net *net = dev_net(skb->dev);
 	int ndir = dir | (reverse ? XFRM_POLICY_MASK + 1 : 0);
 
 	if (sk && sk->sk_policy[XFRM_POLICY_IN])
 		return __xfrm_policy_check(sk, ndir, skb, family);
 
-	return	(!xfrm_policy_count[dir] && !skb->sp) ||
+	return	(!net->xfrm.policy_count[dir] && !skb->sp) ||
 		(skb->dst->flags & DST_NOPOLICY) ||
 		__xfrm_policy_check(sk, ndir, skb, family);
 }
@@ -1034,7 +1045,9 @@
 
 static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family)
 {
-	return	!xfrm_policy_count[XFRM_POLICY_OUT] ||
+	struct net *net = dev_net(skb->dev);
+
+	return	!net->xfrm.policy_count[XFRM_POLICY_OUT] ||
 		(skb->dst->flags & DST_NOXFRM) ||
 		__xfrm_route_forward(skb, family);
 }
@@ -1268,7 +1281,8 @@
 
 extern void xfrm_init(void);
 extern void xfrm4_init(void);
-extern void xfrm_state_init(void);
+extern int xfrm_state_init(struct net *net);
+extern void xfrm_state_fini(struct net *net);
 extern void xfrm4_state_init(void);
 #ifdef CONFIG_XFRM
 extern int xfrm6_init(void);
@@ -1287,19 +1301,30 @@
 #endif
 
 #ifdef CONFIG_XFRM_STATISTICS
-extern int xfrm_proc_init(void);
+extern int xfrm_proc_init(struct net *net);
+extern void xfrm_proc_fini(struct net *net);
+#endif
+
+extern int xfrm_sysctl_init(struct net *net);
+#ifdef CONFIG_SYSCTL
+extern void xfrm_sysctl_fini(struct net *net);
+#else
+static inline void xfrm_sysctl_fini(struct net *net)
+{
+}
 #endif
 
 extern void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto);
-extern int xfrm_state_walk(struct xfrm_state_walk *walk,
+extern int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
 			   int (*func)(struct xfrm_state *, int, void*), void *);
 extern void xfrm_state_walk_done(struct xfrm_state_walk *walk);
-extern struct xfrm_state *xfrm_state_alloc(void);
+extern struct xfrm_state *xfrm_state_alloc(struct net *net);
 extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 
 					  struct flowi *fl, struct xfrm_tmpl *tmpl,
 					  struct xfrm_policy *pol, int *err,
 					  unsigned short family);
-extern struct xfrm_state * xfrm_stateonly_find(xfrm_address_t *daddr,
+extern struct xfrm_state * xfrm_stateonly_find(struct net *net,
+					       xfrm_address_t *daddr,
 					       xfrm_address_t *saddr,
 					       unsigned short family,
 					       u8 mode, u8 proto, u32 reqid);
@@ -1307,8 +1332,8 @@
 extern void xfrm_state_insert(struct xfrm_state *x);
 extern int xfrm_state_add(struct xfrm_state *x);
 extern int xfrm_state_update(struct xfrm_state *x);
-extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family);
-extern struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family);
+extern struct xfrm_state *xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family);
+extern struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family);
 #ifdef CONFIG_XFRM_SUB_POLICY
 extern int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src,
 			  int n, unsigned short family);
@@ -1345,9 +1370,9 @@
 	u32 spdhmcnt;
 };
 
-extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
+extern struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 seq);
 extern int xfrm_state_delete(struct xfrm_state *x);
-extern int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info);
+extern int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info);
 extern void xfrm_sad_getinfo(struct xfrmk_sadinfo *si);
 extern void xfrm_spd_getinfo(struct xfrmk_spdinfo *si);
 extern int xfrm_replay_check(struct xfrm_state *x,
@@ -1415,22 +1440,22 @@
 }
 #endif
 
-struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
+struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp);
 
 extern void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type);
-extern int xfrm_policy_walk(struct xfrm_policy_walk *walk,
+extern int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
 	int (*func)(struct xfrm_policy *, int, int, void*), void *);
 extern void xfrm_policy_walk_done(struct xfrm_policy_walk *walk);
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
-struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
+struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir,
 					  struct xfrm_selector *sel,
 					  struct xfrm_sec_ctx *ctx, int delete,
 					  int *err);
-struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete, int *err);
-int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info);
+struct xfrm_policy *xfrm_policy_byid(struct net *net, u8, int dir, u32 id, int delete, int *err);
+int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info);
 u32 xfrm_get_acqseq(void);
 extern int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
-struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
+struct xfrm_state * xfrm_find_acq(struct net *net, u8 mode, u32 reqid, u8 proto,
 				  xfrm_address_t *daddr, xfrm_address_t *saddr,
 				  int create, unsigned short family);
 extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
@@ -1449,10 +1474,9 @@
 			struct xfrm_kmaddress *k);
 #endif
 
-extern wait_queue_head_t km_waitq;
 extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
 extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid);
-extern int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
+extern int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
 
 extern void xfrm_input_init(void);
 extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq);
@@ -1497,18 +1521,20 @@
 	return index & 7;
 }
 
-static inline int xfrm_aevent_is_on(void)
+#ifdef CONFIG_XFRM
+static inline int xfrm_aevent_is_on(struct net *net)
 {
 	struct sock *nlsk;
 	int ret = 0;
 
 	rcu_read_lock();
-	nlsk = rcu_dereference(xfrm_nl);
+	nlsk = rcu_dereference(net->xfrm.nlsk);
 	if (nlsk)
 		ret = netlink_has_listeners(nlsk, XFRMNLGRP_AEVENTS);
 	rcu_read_unlock();
 	return ret;
 }
+#endif
 
 static inline int xfrm_alg_len(struct xfrm_algo *alg)
 {
@@ -1536,9 +1562,11 @@
 }
 #endif
 
+#ifdef CONFIG_XFRM
 static inline struct xfrm_state *xfrm_input_state(struct sk_buff *skb)
 {
 	return skb->sp->xvec[skb->sp->len - 1];
 }
+#endif
 
 #endif	/* _NET_XFRM_H */
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 9c309da..251fc1c 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -281,10 +281,12 @@
 /* specific - Analog Devices */
 #define AC97_AD_TEST		0x5a	/* test register */
 #define AC97_AD_TEST2		0x5c	/* undocumented test register 2 */
+#define AC97_AD_HPFD_SHIFT	12	/* High Pass Filter Disable */
 #define AC97_AD_CODEC_CFG	0x70	/* codec configuration */
 #define AC97_AD_JACK_SPDIF	0x72	/* Jack Sense & S/PDIF */
 #define AC97_AD_SERIAL_CFG	0x74	/* Serial Configuration */
 #define AC97_AD_MISC		0x76	/* Misc Control Bits */
+#define AC97_AD_VREFD_SHIFT	2	/* V_REFOUT Disable (AD1888) */
 
 /* specific - Cirrus Logic */
 #define AC97_CSR_ACMODE		0x5e	/* AC Mode Register */
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 2c4dc90..1c02ed1 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -575,6 +575,7 @@
 #define SNDRV_TIMER_GLOBAL_SYSTEM	0
 #define SNDRV_TIMER_GLOBAL_RTC		1
 #define SNDRV_TIMER_GLOBAL_HPET		2
+#define SNDRV_TIMER_GLOBAL_HRTIMER	3
 
 /* info flags */
 #define SNDRV_TIMER_FLG_SLAVE		(1<<0)	/* cannot be controlled */
diff --git a/include/sound/core.h b/include/sound/core.h
index 1508c4e..f632484 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -353,7 +353,7 @@
  * snd_printk - printk wrapper
  * @fmt: format string
  *
- * Works like print() but prints the file and the line of the caller
+ * Works like printk() but prints the file and the line of the caller
  * when configured with CONFIG_SND_VERBOSE_PRINTK.
  */
 #define snd_printk(fmt, args...) \
@@ -380,18 +380,40 @@
 	printk(fmt ,##args)
 #endif
 
+/**
+ * snd_BUG - give a BUG warning message and stack trace
+ *
+ * Calls WARN() if CONFIG_SND_DEBUG is set.
+ * Ignored when CONFIG_SND_DEBUG is not set.
+ */
 #define snd_BUG()		WARN(1, "BUG?\n")
+
+/**
+ * snd_BUG_ON - debugging check macro
+ * @cond: condition to evaluate
+ *
+ * When CONFIG_SND_DEBUG is set, this macro evaluates the given condition,
+ * and call WARN() and returns the value if it's non-zero.
+ * 
+ * When CONFIG_SND_DEBUG is not set, this just returns zero, and the given
+ * condition is ignored.
+ *
+ * NOTE: the argument won't be evaluated at all when CONFIG_SND_DEBUG=n.
+ * Thus, don't put any statement that influences on the code behavior,
+ * such as pre/post increment, to the argument of this macro.
+ * If you want to evaluate and give a warning, use standard WARN_ON().
+ */
 #define snd_BUG_ON(cond)	WARN((cond), "BUG? (%s)\n", __stringify(cond))
 
 #else /* !CONFIG_SND_DEBUG */
 
 #define snd_printd(fmt, args...)	do { } while (0)
 #define snd_BUG()			do { } while (0)
-static inline int __snd_bug_on(void)
+static inline int __snd_bug_on(int cond)
 {
 	return 0;
 }
-#define snd_BUG_ON(cond)		__snd_bug_on()  /* always false */
+#define snd_BUG_ON(cond)	__snd_bug_on(0 && (cond))  /* always false */
 
 #endif /* CONFIG_SND_DEBUG */
 
diff --git a/include/sound/info.h b/include/sound/info.h
index 8ae72e7..7c2ee1a2 100644
--- a/include/sound/info.h
+++ b/include/sound/info.h
@@ -40,30 +40,34 @@
 struct snd_info_entry;
 
 struct snd_info_entry_text {
-	void (*read) (struct snd_info_entry *entry, struct snd_info_buffer *buffer);
-	void (*write) (struct snd_info_entry *entry, struct snd_info_buffer *buffer);
+	void (*read)(struct snd_info_entry *entry,
+		     struct snd_info_buffer *buffer);
+	void (*write)(struct snd_info_entry *entry,
+		      struct snd_info_buffer *buffer);
 };
 
 struct snd_info_entry_ops {
-	int (*open) (struct snd_info_entry *entry,
-		     unsigned short mode, void **file_private_data);
-	int (*release) (struct snd_info_entry * entry,
-			unsigned short mode, void *file_private_data);
-	long (*read) (struct snd_info_entry *entry, void *file_private_data,
-		      struct file * file, char __user *buf,
+	int (*open)(struct snd_info_entry *entry,
+		    unsigned short mode, void **file_private_data);
+	int (*release)(struct snd_info_entry *entry,
+		       unsigned short mode, void *file_private_data);
+	long (*read)(struct snd_info_entry *entry, void *file_private_data,
+		     struct file *file, char __user *buf,
+		     unsigned long count, unsigned long pos);
+	long (*write)(struct snd_info_entry *entry, void *file_private_data,
+		      struct file *file, const char __user *buf,
 		      unsigned long count, unsigned long pos);
-	long (*write) (struct snd_info_entry *entry, void *file_private_data,
-		       struct file * file, const char __user *buf,
-		       unsigned long count, unsigned long pos);
-	long long (*llseek) (struct snd_info_entry *entry, void *file_private_data,
-			    struct file * file, long long offset, int orig);
-	unsigned int (*poll) (struct snd_info_entry *entry, void *file_private_data,
-			      struct file * file, poll_table * wait);
-	int (*ioctl) (struct snd_info_entry *entry, void *file_private_data,
-		      struct file * file, unsigned int cmd, unsigned long arg);
-	int (*mmap) (struct snd_info_entry *entry, void *file_private_data,
-		     struct inode * inode, struct file * file,
-		     struct vm_area_struct * vma);
+	long long (*llseek)(struct snd_info_entry *entry,
+			    void *file_private_data, struct file *file,
+			    long long offset, int orig);
+	unsigned int(*poll)(struct snd_info_entry *entry,
+			    void *file_private_data, struct file *file,
+			    poll_table *wait);
+	int (*ioctl)(struct snd_info_entry *entry, void *file_private_data,
+		     struct file *file, unsigned int cmd, unsigned long arg);
+	int (*mmap)(struct snd_info_entry *entry, void *file_private_data,
+		    struct inode *inode, struct file *file,
+		    struct vm_area_struct *vma);
 };
 
 struct snd_info_entry {
@@ -106,34 +110,37 @@
 static inline void snd_card_info_read_oss(struct snd_info_buffer *buffer) {}
 #endif
 
-int snd_iprintf(struct snd_info_buffer * buffer, char *fmt,...) __attribute__ ((format (printf, 2, 3)));
+int snd_iprintf(struct snd_info_buffer *buffer, char *fmt, ...) \
+				__attribute__ ((format (printf, 2, 3)));
 int snd_info_init(void);
 int snd_info_done(void);
 
-int snd_info_get_line(struct snd_info_buffer * buffer, char *line, int len);
+int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len);
 char *snd_info_get_str(char *dest, char *src, int len);
-struct snd_info_entry *snd_info_create_module_entry(struct module * module,
+struct snd_info_entry *snd_info_create_module_entry(struct module *module,
 					       const char *name,
-					       struct snd_info_entry * parent);
-struct snd_info_entry *snd_info_create_card_entry(struct snd_card * card,
+					       struct snd_info_entry *parent);
+struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
 					     const char *name,
-					     struct snd_info_entry * parent);
-void snd_info_free_entry(struct snd_info_entry * entry);
-int snd_info_store_text(struct snd_info_entry * entry);
-int snd_info_restore_text(struct snd_info_entry * entry);
+					     struct snd_info_entry *parent);
+void snd_info_free_entry(struct snd_info_entry *entry);
+int snd_info_store_text(struct snd_info_entry *entry);
+int snd_info_restore_text(struct snd_info_entry *entry);
 
-int snd_info_card_create(struct snd_card * card);
-int snd_info_card_register(struct snd_card * card);
-int snd_info_card_free(struct snd_card * card);
-void snd_info_card_disconnect(struct snd_card * card);
-int snd_info_register(struct snd_info_entry * entry);
+int snd_info_card_create(struct snd_card *card);
+int snd_info_card_register(struct snd_card *card);
+int snd_info_card_free(struct snd_card *card);
+void snd_info_card_disconnect(struct snd_card *card);
+void snd_info_card_id_change(struct snd_card *card);
+int snd_info_register(struct snd_info_entry *entry);
 
 /* for card drivers */
-int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp);
+int snd_card_proc_new(struct snd_card *card, const char *name,
+		      struct snd_info_entry **entryp);
 
 static inline void snd_info_set_text_ops(struct snd_info_entry *entry, 
-					 void *private_data,
-					 void (*read)(struct snd_info_entry *, struct snd_info_buffer *))
+	void *private_data,
+	void (*read)(struct snd_info_entry *, struct snd_info_buffer *))
 {
 	entry->private_data = private_data;
 	entry->c.text.read = read;
@@ -146,21 +153,22 @@
 #define snd_seq_root NULL
 #define snd_oss_root NULL
 
-static inline int snd_iprintf(struct snd_info_buffer * buffer, char *fmt,...) { return 0; }
+static inline int snd_iprintf(struct snd_info_buffer *buffer, char *fmt, ...) { return 0; }
 static inline int snd_info_init(void) { return 0; }
 static inline int snd_info_done(void) { return 0; }
 
-static inline int snd_info_get_line(struct snd_info_buffer * buffer, char *line, int len) { return 0; }
+static inline int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) { return 0; }
 static inline char *snd_info_get_str(char *dest, char *src, int len) { return NULL; }
-static inline struct snd_info_entry *snd_info_create_module_entry(struct module * module, const char *name, struct snd_info_entry * parent) { return NULL; }
-static inline struct snd_info_entry *snd_info_create_card_entry(struct snd_card * card, const char *name, struct snd_info_entry * parent) { return NULL; }
-static inline void snd_info_free_entry(struct snd_info_entry * entry) { ; }
+static inline struct snd_info_entry *snd_info_create_module_entry(struct module *module, const char *name, struct snd_info_entry *parent) { return NULL; }
+static inline struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry *parent) { return NULL; }
+static inline void snd_info_free_entry(struct snd_info_entry *entry) { ; }
 
-static inline int snd_info_card_create(struct snd_card * card) { return 0; }
-static inline int snd_info_card_register(struct snd_card * card) { return 0; }
-static inline int snd_info_card_free(struct snd_card * card) { return 0; }
-static inline void snd_info_card_disconnect(struct snd_card * card) { }
-static inline int snd_info_register(struct snd_info_entry * entry) { return 0; }
+static inline int snd_info_card_create(struct snd_card *card) { return 0; }
+static inline int snd_info_card_register(struct snd_card *card) { return 0; }
+static inline int snd_info_card_free(struct snd_card *card) { return 0; }
+static inline void snd_info_card_disconnect(struct snd_card *card) { }
+static inline void snd_info_card_id_change(struct snd_card *card) { }
+static inline int snd_info_register(struct snd_info_entry *entry) { return 0; }
 
 static inline int snd_card_proc_new(struct snd_card *card, const char *name,
 				    struct snd_info_entry **entryp) { return -EINVAL; }
diff --git a/include/sound/jack.h b/include/sound/jack.h
index b1b2b8b..2e0315c 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -35,6 +35,8 @@
 	SND_JACK_HEADPHONE	= 0x0001,
 	SND_JACK_MICROPHONE	= 0x0002,
 	SND_JACK_HEADSET	= SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
+	SND_JACK_LINEOUT	= 0x0004,
+	SND_JACK_MECHANICAL	= 0x0008, /* If detected separately */
 };
 
 struct snd_jack {
diff --git a/include/sound/l3.h b/include/sound/l3.h
new file mode 100644
index 0000000..423a08f
--- /dev/null
+++ b/include/sound/l3.h
@@ -0,0 +1,18 @@
+#ifndef _L3_H_
+#define _L3_H_ 1
+
+struct l3_pins {
+	void (*setdat)(int);
+	void (*setclk)(int);
+	void (*setmode)(int);
+	int data_hold;
+	int data_setup;
+	int clock_high;
+	int mode_hold;
+	int mode;
+	int mode_setup;
+};
+
+int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len);
+
+#endif
diff --git a/include/sound/s3c24xx_uda134x.h b/include/sound/s3c24xx_uda134x.h
new file mode 100644
index 0000000..33df4cb
--- /dev/null
+++ b/include/sound/s3c24xx_uda134x.h
@@ -0,0 +1,14 @@
+#ifndef _S3C24XX_UDA134X_H_
+#define _S3C24XX_UDA134X_H_ 1
+
+#include <sound/uda134x.h>
+
+struct s3c24xx_uda134x_platform_data {
+	int l3_clk;
+	int l3_mode;
+	int l3_data;
+	void (*power) (int);
+	int model;
+};
+
+#endif
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
new file mode 100644
index 0000000..24247f7
--- /dev/null
+++ b/include/sound/soc-dai.h
@@ -0,0 +1,231 @@
+/*
+ * linux/sound/soc-dai.h -- ALSA SoC Layer
+ *
+ * Copyright:	2005-2008 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.
+ *
+ * Digital Audio Interface (DAI) API.
+ */
+
+#ifndef __LINUX_SND_SOC_DAI_H
+#define __LINUX_SND_SOC_DAI_H
+
+
+#include <linux/list.h>
+
+struct snd_pcm_substream;
+
+/*
+ * DAI hardware audio formats.
+ *
+ * Describes the physical PCM data formating and clocking. Add new formats
+ * to the end.
+ */
+#define SND_SOC_DAIFMT_I2S		0 /* I2S mode */
+#define SND_SOC_DAIFMT_RIGHT_J		1 /* Right Justified mode */
+#define SND_SOC_DAIFMT_LEFT_J		2 /* Left Justified mode */
+#define SND_SOC_DAIFMT_DSP_A		3 /* L data msb after FRM LRC */
+#define SND_SOC_DAIFMT_DSP_B		4 /* L data msb during FRM LRC */
+#define SND_SOC_DAIFMT_AC97		5 /* AC97 */
+
+/* left and right justified also known as MSB and LSB respectively */
+#define SND_SOC_DAIFMT_MSB		SND_SOC_DAIFMT_LEFT_J
+#define SND_SOC_DAIFMT_LSB		SND_SOC_DAIFMT_RIGHT_J
+
+/*
+ * DAI Clock gating.
+ *
+ * DAI bit clocks can be be gated (disabled) when not the DAI is not
+ * sending or receiving PCM data in a frame. This can be used to save power.
+ */
+#define SND_SOC_DAIFMT_CONT		(0 << 4) /* continuous clock */
+#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
+ * format.
+ */
+#define SND_SOC_DAIFMT_NB_NF		(0 << 8) /* normal bit clock + frame */
+#define SND_SOC_DAIFMT_NB_IF		(1 << 8) /* normal bclk + inv frm */
+#define SND_SOC_DAIFMT_IB_NF		(2 << 8) /* invert bclk + nor frm */
+#define SND_SOC_DAIFMT_IB_IF		(3 << 8) /* invert bclk + frm */
+
+/*
+ * DAI hardware clock masters.
+ *
+ * This is wrt the codec, the inverse is true for the interface
+ * i.e. if the codec is clk and frm master then the interface is
+ * clk and frame slave.
+ */
+#define SND_SOC_DAIFMT_CBM_CFM		(0 << 12) /* codec clk & frm master */
+#define SND_SOC_DAIFMT_CBS_CFM		(1 << 12) /* codec clk slave & frm master */
+#define SND_SOC_DAIFMT_CBM_CFS		(2 << 12) /* codec clk master & frame slave */
+#define SND_SOC_DAIFMT_CBS_CFS		(3 << 12) /* codec clk & frm slave */
+
+#define SND_SOC_DAIFMT_FORMAT_MASK	0x000f
+#define SND_SOC_DAIFMT_CLOCK_MASK	0x00f0
+#define SND_SOC_DAIFMT_INV_MASK		0x0f00
+#define SND_SOC_DAIFMT_MASTER_MASK	0xf000
+
+/*
+ * Master Clock Directions
+ */
+#define SND_SOC_CLOCK_IN		0
+#define SND_SOC_CLOCK_OUT		1
+
+struct snd_soc_dai_ops;
+struct snd_soc_dai;
+struct snd_ac97_bus_ops;
+
+/* Digital Audio Interface registration */
+int snd_soc_register_dai(struct snd_soc_dai *dai);
+void snd_soc_unregister_dai(struct snd_soc_dai *dai);
+int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count);
+void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count);
+
+/* Digital Audio Interface clocking API.*/
+int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+	unsigned int freq, int dir);
+
+int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
+	int div_id, int div);
+
+int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
+	int pll_id, unsigned int freq_in, unsigned int freq_out);
+
+/* Digital Audio interface formatting */
+int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
+
+int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
+	unsigned int mask, int slots);
+
+int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
+
+/* Digital Audio Interface mute */
+int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
+
+/*
+ * Digital Audio Interface.
+ *
+ * Describes the Digital Audio Interface in terms of it's ALSA, DAI and AC97
+ * operations an capabilities. Codec and platfom drivers will register a this
+ * structure for every DAI they have.
+ *
+ * This structure covers the clocking, formating and ALSA operations for each
+ * interface a
+ */
+struct snd_soc_dai_ops {
+	/*
+	 * DAI clocking configuration, all optional.
+	 * Called by soc_card drivers, normally in their hw_params.
+	 */
+	int (*set_sysclk)(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir);
+	int (*set_pll)(struct snd_soc_dai *dai,
+		int pll_id, unsigned int freq_in, unsigned int freq_out);
+	int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
+
+	/*
+	 * DAI format configuration
+	 * Called by soc_card drivers, normally in their hw_params.
+	 */
+	int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
+	int (*set_tdm_slot)(struct snd_soc_dai *dai,
+		unsigned int mask, int slots);
+	int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
+
+	/*
+	 * DAI digital mute - optional.
+	 * Called by soc-core to minimise any pops.
+	 */
+	int (*digital_mute)(struct snd_soc_dai *dai, int mute);
+
+	/*
+	 * ALSA PCM audio operations - all optional.
+	 * Called by soc-core during audio PCM operations.
+	 */
+	int (*startup)(struct snd_pcm_substream *,
+		struct snd_soc_dai *);
+	void (*shutdown)(struct snd_pcm_substream *,
+		struct snd_soc_dai *);
+	int (*hw_params)(struct snd_pcm_substream *,
+		struct snd_pcm_hw_params *, struct snd_soc_dai *);
+	int (*hw_free)(struct snd_pcm_substream *,
+		struct snd_soc_dai *);
+	int (*prepare)(struct snd_pcm_substream *,
+		struct snd_soc_dai *);
+	int (*trigger)(struct snd_pcm_substream *, int,
+		struct snd_soc_dai *);
+};
+
+/*
+ * Digital Audio Interface runtime data.
+ *
+ * Holds runtime data for a DAI.
+ */
+struct snd_soc_dai {
+	/* DAI description */
+	char *name;
+	unsigned int id;
+	int ac97_control;
+
+	struct device *dev;
+
+	/* DAI callbacks */
+	int (*probe)(struct platform_device *pdev,
+		     struct snd_soc_dai *dai);
+	void (*remove)(struct platform_device *pdev,
+		       struct snd_soc_dai *dai);
+	int (*suspend)(struct snd_soc_dai *dai);
+	int (*resume)(struct snd_soc_dai *dai);
+
+	/* ops */
+	struct snd_soc_dai_ops ops;
+
+	/* DAI capabilities */
+	struct snd_soc_pcm_stream capture;
+	struct snd_soc_pcm_stream playback;
+
+	/* DAI runtime info */
+	struct snd_pcm_runtime *runtime;
+	struct snd_soc_codec *codec;
+	unsigned int active;
+	unsigned char pop_wait:1;
+	void *dma_data;
+
+	/* DAI private data */
+	void *private_data;
+
+	/* parent codec/platform */
+	union {
+		struct snd_soc_codec *codec;
+		struct snd_soc_platform *platform;
+	};
+
+	struct list_head list;
+};
+
+#endif
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index ca699a3..7ee2f70 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -221,8 +221,6 @@
 	int num);
 
 /* dapm path setup */
-int  __deprecated snd_soc_dapm_connect_input(struct snd_soc_codec *codec,
-	const char *sink_name, const char *control_name, const char *src_name);
 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
 void snd_soc_dapm_free(struct snd_soc_device *socdev);
 int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 5e01898..f86e455 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -21,8 +21,6 @@
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
 
-#define SND_SOC_VERSION "0.13.2"
-
 /*
  * Convenience kcontrol builders
  */
@@ -145,105 +143,31 @@
 	SND_SOC_BIAS_OFF,
 };
 
-/*
- * Digital Audio Interface (DAI) types
- */
-#define SND_SOC_DAI_AC97	0x1
-#define SND_SOC_DAI_I2S		0x2
-#define SND_SOC_DAI_PCM		0x4
-#define SND_SOC_DAI_AC97_BUS	0x8	/* for custom i.e. non ac97_codec.c */
-
-/*
- * DAI hardware audio formats
- */
-#define SND_SOC_DAIFMT_I2S		0	/* I2S mode */
-#define SND_SOC_DAIFMT_RIGHT_J	1	/* Right justified mode */
-#define SND_SOC_DAIFMT_LEFT_J	2	/* Left Justified mode */
-#define SND_SOC_DAIFMT_DSP_A	3	/* L data msb after FRM or LRC */
-#define SND_SOC_DAIFMT_DSP_B	4	/* L data msb during FRM or LRC */
-#define SND_SOC_DAIFMT_AC97		5	/* AC97 */
-
-#define SND_SOC_DAIFMT_MSB 	SND_SOC_DAIFMT_LEFT_J
-#define SND_SOC_DAIFMT_LSB	SND_SOC_DAIFMT_RIGHT_J
-
-/*
- * DAI Gating
- */
-#define SND_SOC_DAIFMT_CONT			(0 << 4)	/* continuous clock */
-#define SND_SOC_DAIFMT_GATED		(1 << 4)	/* clock is gated when not Tx/Rx */
-
-/*
- * DAI Sync
- * Synchronous LR (Left Right) clocks and Frame signals.
- */
-#define SND_SOC_DAIFMT_SYNC		(0 << 5)	/* Tx FRM = Rx FRM */
-#define SND_SOC_DAIFMT_ASYNC		(1 << 5)	/* Tx FRM ~ Rx FRM */
-
-/*
- * TDM
- */
-#define SND_SOC_DAIFMT_TDM		(1 << 6)
-
-/*
- * DAI hardware signal inversions
- */
-#define SND_SOC_DAIFMT_NB_NF		(0 << 8)	/* normal bclk + frm */
-#define SND_SOC_DAIFMT_NB_IF		(1 << 8)	/* normal bclk + inv frm */
-#define SND_SOC_DAIFMT_IB_NF		(2 << 8)	/* invert bclk + nor frm */
-#define SND_SOC_DAIFMT_IB_IF		(3 << 8)	/* invert bclk + frm */
-
-/*
- * DAI hardware clock masters
- * This is wrt the codec, the inverse is true for the interface
- * i.e. if the codec is clk and frm master then the interface is
- * clk and frame slave.
- */
-#define SND_SOC_DAIFMT_CBM_CFM	(0 << 12) /* codec clk & frm master */
-#define SND_SOC_DAIFMT_CBS_CFM	(1 << 12) /* codec clk slave & frm master */
-#define SND_SOC_DAIFMT_CBM_CFS	(2 << 12) /* codec clk master & frame slave */
-#define SND_SOC_DAIFMT_CBS_CFS	(3 << 12) /* codec clk & frm slave */
-
-#define SND_SOC_DAIFMT_FORMAT_MASK		0x000f
-#define SND_SOC_DAIFMT_CLOCK_MASK		0x00f0
-#define SND_SOC_DAIFMT_INV_MASK			0x0f00
-#define SND_SOC_DAIFMT_MASTER_MASK		0xf000
-
-
-/*
- * Master Clock Directions
- */
-#define SND_SOC_CLOCK_IN	0
-#define SND_SOC_CLOCK_OUT	1
-
-/*
- * AC97 codec ID's bitmask
- */
-#define SND_SOC_DAI_AC97_ID0	(1 << 0)
-#define SND_SOC_DAI_AC97_ID1	(1 << 1)
-#define SND_SOC_DAI_AC97_ID2	(1 << 2)
-#define SND_SOC_DAI_AC97_ID3	(1 << 3)
-
 struct snd_soc_device;
 struct snd_soc_pcm_stream;
 struct snd_soc_ops;
 struct snd_soc_dai_mode;
 struct snd_soc_pcm_runtime;
 struct snd_soc_dai;
+struct snd_soc_platform;
 struct snd_soc_codec;
-struct snd_soc_machine_config;
 struct soc_enum;
 struct snd_soc_ac97_ops;
-struct snd_soc_clock_info;
 
 typedef int (*hw_write_t)(void *,const char* ,int);
 typedef int (*hw_read_t)(void *,char* ,int);
 
 extern struct snd_ac97_bus_ops soc_ac97_ops;
 
+int snd_soc_register_platform(struct snd_soc_platform *platform);
+void snd_soc_unregister_platform(struct snd_soc_platform *platform);
+int snd_soc_register_codec(struct snd_soc_codec *codec);
+void snd_soc_unregister_codec(struct snd_soc_codec *codec);
+
 /* pcm <-> DAI connect */
 void snd_soc_free_pcms(struct snd_soc_device *socdev);
 int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
-int snd_soc_register_card(struct snd_soc_device *socdev);
+int snd_soc_init_card(struct snd_soc_device *socdev);
 
 /* set runtime hw params */
 int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
@@ -263,27 +187,6 @@
 	struct snd_ac97_bus_ops *ops, int num);
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
 
-/* Digital Audio Interface clocking API.*/
-int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
-	unsigned int freq, int dir);
-
-int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
-	int div_id, int div);
-
-int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
-	int pll_id, unsigned int freq_in, unsigned int freq_out);
-
-/* Digital Audio interface formatting */
-int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
-
-int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
-	unsigned int mask, int slots);
-
-int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
-
-/* Digital Audio Interface mute */
-int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
-
 /*
  *Controls
  */
@@ -341,66 +244,14 @@
 	int (*trigger)(struct snd_pcm_substream *, int);
 };
 
-/* ASoC DAI ops */
-struct snd_soc_dai_ops {
-	/* DAI clocking configuration */
-	int (*set_sysclk)(struct snd_soc_dai *dai,
-		int clk_id, unsigned int freq, int dir);
-	int (*set_pll)(struct snd_soc_dai *dai,
-		int pll_id, unsigned int freq_in, unsigned int freq_out);
-	int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
-
-	/* DAI format configuration */
-	int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
-	int (*set_tdm_slot)(struct snd_soc_dai *dai,
-		unsigned int mask, int slots);
-	int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
-
-	/* digital mute */
-	int (*digital_mute)(struct snd_soc_dai *dai, int mute);
-};
-
-/* SoC  DAI (Digital Audio Interface) */
-struct snd_soc_dai {
-	/* DAI description */
-	char *name;
-	unsigned int id;
-	unsigned char type;
-
-	/* DAI callbacks */
-	int (*probe)(struct platform_device *pdev,
-		     struct snd_soc_dai *dai);
-	void (*remove)(struct platform_device *pdev,
-		       struct snd_soc_dai *dai);
-	int (*suspend)(struct platform_device *pdev,
-		struct snd_soc_dai *dai);
-	int (*resume)(struct platform_device *pdev,
-		struct snd_soc_dai *dai);
-
-	/* ops */
-	struct snd_soc_ops ops;
-	struct snd_soc_dai_ops dai_ops;
-
-	/* DAI capabilities */
-	struct snd_soc_pcm_stream capture;
-	struct snd_soc_pcm_stream playback;
-
-	/* DAI runtime info */
-	struct snd_pcm_runtime *runtime;
-	struct snd_soc_codec *codec;
-	unsigned int active;
-	unsigned char pop_wait:1;
-	void *dma_data;
-
-	/* DAI private data */
-	void *private_data;
-};
-
 /* SoC Audio Codec */
 struct snd_soc_codec {
 	char *name;
 	struct module *owner;
 	struct mutex mutex;
+	struct device *dev;
+
+	struct list_head list;
 
 	/* callbacks */
 	int (*set_bias_level)(struct snd_soc_codec *,
@@ -426,6 +277,7 @@
 	short reg_cache_step;
 
 	/* dapm */
+	u32 pop_time;
 	struct list_head dapm_widgets;
 	struct list_head dapm_paths;
 	enum snd_soc_bias_level bias_level;
@@ -435,6 +287,11 @@
 	/* codec DAI's */
 	struct snd_soc_dai *dai;
 	unsigned int num_dai;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_reg;
+	struct dentry *debugfs_pop_time;
+#endif
 };
 
 /* codec device */
@@ -448,13 +305,12 @@
 /* SoC platform interface */
 struct snd_soc_platform {
 	char *name;
+	struct list_head list;
 
 	int (*probe)(struct platform_device *pdev);
 	int (*remove)(struct platform_device *pdev);
-	int (*suspend)(struct platform_device *pdev,
-		struct snd_soc_dai *dai);
-	int (*resume)(struct platform_device *pdev,
-		struct snd_soc_dai *dai);
+	int (*suspend)(struct snd_soc_dai *dai);
+	int (*resume)(struct snd_soc_dai *dai);
 
 	/* pcm creation and destruction */
 	int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
@@ -484,9 +340,14 @@
 	struct snd_pcm *pcm;
 };
 
-/* SoC machine */
-struct snd_soc_machine {
+/* SoC card */
+struct snd_soc_card {
 	char *name;
+	struct device *dev;
+
+	struct list_head list;
+
+	int instantiated;
 
 	int (*probe)(struct platform_device *pdev);
 	int (*remove)(struct platform_device *pdev);
@@ -499,23 +360,26 @@
 	int (*resume_post)(struct platform_device *pdev);
 
 	/* callbacks */
-	int (*set_bias_level)(struct snd_soc_machine *,
+	int (*set_bias_level)(struct snd_soc_card *,
 			      enum snd_soc_bias_level level);
 
 	/* CPU <--> Codec DAI links  */
 	struct snd_soc_dai_link *dai_link;
 	int num_links;
+
+	struct snd_soc_device *socdev;
+
+	struct snd_soc_platform *platform;
+	struct delayed_work delayed_work;
+	struct work_struct deferred_resume_work;
 };
 
 /* SoC Device - the audio subsystem */
 struct snd_soc_device {
 	struct device *dev;
-	struct snd_soc_machine *machine;
-	struct snd_soc_platform *platform;
+	struct snd_soc_card *card;
 	struct snd_soc_codec *codec;
 	struct snd_soc_codec_device *codec_dev;
-	struct delayed_work delayed_work;
-	struct work_struct deferred_resume_work;
 	void *codec_data;
 };
 
@@ -542,4 +406,6 @@
 	void *dapm;
 };
 
+#include <sound/soc-dai.h>
+
 #endif
diff --git a/include/sound/uda134x.h b/include/sound/uda134x.h
new file mode 100644
index 0000000..475ef8b
--- /dev/null
+++ b/include/sound/uda134x.h
@@ -0,0 +1,26 @@
+/*
+ * uda134x.h  --  UDA134x ALSA SoC Codec driver
+ *
+ * Copyright 2007 Dension Audio Systems Ltd.
+ * Author: Zoltan Devai
+ *
+ * This program is free software; you can 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 _UDA134X_H
+#define _UDA134X_H
+
+#include <sound/l3.h>
+
+struct uda134x_platform_data {
+	struct l3_pins l3;
+	void (*power) (int);
+	int model;
+#define UDA134X_UDA1340 1
+#define UDA134X_UDA1341 2
+#define UDA134X_UDA1344 3
+};
+
+#endif /* _UDA134X_H */
diff --git a/include/sound/version.h b/include/sound/version.h
index 4aafeda..2b48237 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
 /* include/version.h */
-#define CONFIG_SND_VERSION "1.0.18rc3"
+#define CONFIG_SND_VERSION "1.0.18a"
 #define CONFIG_SND_DATE ""
diff --git a/include/trace/block.h b/include/trace/block.h
new file mode 100644
index 0000000..25c6a1f
--- /dev/null
+++ b/include/trace/block.h
@@ -0,0 +1,76 @@
+#ifndef _TRACE_BLOCK_H
+#define _TRACE_BLOCK_H
+
+#include <linux/blkdev.h>
+#include <linux/tracepoint.h>
+
+DECLARE_TRACE(block_rq_abort,
+	TPPROTO(struct request_queue *q, struct request *rq),
+		TPARGS(q, rq));
+
+DECLARE_TRACE(block_rq_insert,
+	TPPROTO(struct request_queue *q, struct request *rq),
+		TPARGS(q, rq));
+
+DECLARE_TRACE(block_rq_issue,
+	TPPROTO(struct request_queue *q, struct request *rq),
+		TPARGS(q, rq));
+
+DECLARE_TRACE(block_rq_requeue,
+	TPPROTO(struct request_queue *q, struct request *rq),
+		TPARGS(q, rq));
+
+DECLARE_TRACE(block_rq_complete,
+	TPPROTO(struct request_queue *q, struct request *rq),
+		TPARGS(q, rq));
+
+DECLARE_TRACE(block_bio_bounce,
+	TPPROTO(struct request_queue *q, struct bio *bio),
+		TPARGS(q, bio));
+
+DECLARE_TRACE(block_bio_complete,
+	TPPROTO(struct request_queue *q, struct bio *bio),
+		TPARGS(q, bio));
+
+DECLARE_TRACE(block_bio_backmerge,
+	TPPROTO(struct request_queue *q, struct bio *bio),
+		TPARGS(q, bio));
+
+DECLARE_TRACE(block_bio_frontmerge,
+	TPPROTO(struct request_queue *q, struct bio *bio),
+		TPARGS(q, bio));
+
+DECLARE_TRACE(block_bio_queue,
+	TPPROTO(struct request_queue *q, struct bio *bio),
+		TPARGS(q, bio));
+
+DECLARE_TRACE(block_getrq,
+	TPPROTO(struct request_queue *q, struct bio *bio, int rw),
+		TPARGS(q, bio, rw));
+
+DECLARE_TRACE(block_sleeprq,
+	TPPROTO(struct request_queue *q, struct bio *bio, int rw),
+		TPARGS(q, bio, rw));
+
+DECLARE_TRACE(block_plug,
+	TPPROTO(struct request_queue *q),
+		TPARGS(q));
+
+DECLARE_TRACE(block_unplug_timer,
+	TPPROTO(struct request_queue *q),
+		TPARGS(q));
+
+DECLARE_TRACE(block_unplug_io,
+	TPPROTO(struct request_queue *q),
+		TPARGS(q));
+
+DECLARE_TRACE(block_split,
+	TPPROTO(struct request_queue *q, struct bio *bio, unsigned int pdu),
+		TPARGS(q, bio, pdu));
+
+DECLARE_TRACE(block_remap,
+	TPPROTO(struct request_queue *q, struct bio *bio, dev_t dev,
+		sector_t from, sector_t to),
+		TPARGS(q, bio, dev, from, to));
+
+#endif
diff --git a/include/trace/boot.h b/include/trace/boot.h
new file mode 100644
index 0000000..088ea08
--- /dev/null
+++ b/include/trace/boot.h
@@ -0,0 +1,60 @@
+#ifndef _LINUX_TRACE_BOOT_H
+#define _LINUX_TRACE_BOOT_H
+
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/init.h>
+
+/*
+ * Structure which defines the trace of an initcall
+ * while it is called.
+ * You don't have to fill the func field since it is
+ * only used internally by the tracer.
+ */
+struct boot_trace_call {
+	pid_t			caller;
+	char			func[KSYM_SYMBOL_LEN];
+};
+
+/*
+ * Structure which defines the trace of an initcall
+ * while it returns.
+ */
+struct boot_trace_ret {
+	char			func[KSYM_SYMBOL_LEN];
+	int				result;
+	unsigned long long	duration;		/* nsecs */
+};
+
+#ifdef CONFIG_BOOT_TRACER
+/* Append the traces on the ring-buffer */
+extern void trace_boot_call(struct boot_trace_call *bt, initcall_t fn);
+extern void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn);
+
+/* Tells the tracer that smp_pre_initcall is finished.
+ * So we can start the tracing
+ */
+extern void start_boot_trace(void);
+
+/* Resume the tracing of other necessary events
+ * such as sched switches
+ */
+extern void enable_boot_trace(void);
+
+/* Suspend this tracing. Actually, only sched_switches tracing have
+ * to be suspended. Initcalls doesn't need it.)
+ */
+extern void disable_boot_trace(void);
+#else
+static inline
+void trace_boot_call(struct boot_trace_call *bt, initcall_t fn) { }
+
+static inline
+void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn) { }
+
+static inline void start_boot_trace(void) { }
+static inline void enable_boot_trace(void) { }
+static inline void disable_boot_trace(void) { }
+#endif /* CONFIG_BOOT_TRACER */
+
+#endif /* __LINUX_TRACE_BOOT_H */
diff --git a/include/trace/sched.h b/include/trace/sched.h
index ad47369..0d81098 100644
--- a/include/trace/sched.h
+++ b/include/trace/sched.h
@@ -4,52 +4,52 @@
 #include <linux/sched.h>
 #include <linux/tracepoint.h>
 
-DEFINE_TRACE(sched_kthread_stop,
+DECLARE_TRACE(sched_kthread_stop,
 	TPPROTO(struct task_struct *t),
 		TPARGS(t));
 
-DEFINE_TRACE(sched_kthread_stop_ret,
+DECLARE_TRACE(sched_kthread_stop_ret,
 	TPPROTO(int ret),
 		TPARGS(ret));
 
-DEFINE_TRACE(sched_wait_task,
+DECLARE_TRACE(sched_wait_task,
 	TPPROTO(struct rq *rq, struct task_struct *p),
 		TPARGS(rq, p));
 
-DEFINE_TRACE(sched_wakeup,
-	TPPROTO(struct rq *rq, struct task_struct *p),
-		TPARGS(rq, p));
+DECLARE_TRACE(sched_wakeup,
+	TPPROTO(struct rq *rq, struct task_struct *p, int success),
+		TPARGS(rq, p, success));
 
-DEFINE_TRACE(sched_wakeup_new,
-	TPPROTO(struct rq *rq, struct task_struct *p),
-		TPARGS(rq, p));
+DECLARE_TRACE(sched_wakeup_new,
+	TPPROTO(struct rq *rq, struct task_struct *p, int success),
+		TPARGS(rq, p, success));
 
-DEFINE_TRACE(sched_switch,
+DECLARE_TRACE(sched_switch,
 	TPPROTO(struct rq *rq, struct task_struct *prev,
 		struct task_struct *next),
 		TPARGS(rq, prev, next));
 
-DEFINE_TRACE(sched_migrate_task,
-	TPPROTO(struct rq *rq, struct task_struct *p, int dest_cpu),
-		TPARGS(rq, p, dest_cpu));
+DECLARE_TRACE(sched_migrate_task,
+	TPPROTO(struct task_struct *p, int orig_cpu, int dest_cpu),
+		TPARGS(p, orig_cpu, dest_cpu));
 
-DEFINE_TRACE(sched_process_free,
+DECLARE_TRACE(sched_process_free,
 	TPPROTO(struct task_struct *p),
 		TPARGS(p));
 
-DEFINE_TRACE(sched_process_exit,
+DECLARE_TRACE(sched_process_exit,
 	TPPROTO(struct task_struct *p),
 		TPARGS(p));
 
-DEFINE_TRACE(sched_process_wait,
+DECLARE_TRACE(sched_process_wait,
 	TPPROTO(struct pid *pid),
 		TPARGS(pid));
 
-DEFINE_TRACE(sched_process_fork,
+DECLARE_TRACE(sched_process_fork,
 	TPPROTO(struct task_struct *parent, struct task_struct *child),
 		TPARGS(parent, child));
 
-DEFINE_TRACE(sched_signal_send,
+DECLARE_TRACE(sched_signal_send,
 	TPPROTO(int sig, struct task_struct *p),
 		TPARGS(sig, p));
 
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
index 1a4bc6a..25144ab 100644
--- a/include/video/sh_mobile_lcdc.h
+++ b/include/video/sh_mobile_lcdc.h
@@ -37,6 +37,7 @@
 struct sh_mobile_lcdc_sys_bus_cfg {
 	unsigned long ldmt2r;
 	unsigned long ldmt3r;
+	unsigned long deferred_io_msec;
 };
 
 struct sh_mobile_lcdc_sys_bus_ops {
diff --git a/include/xen/interface/event_channel.h b/include/xen/interface/event_channel.h
index 919b5bd..2090881 100644
--- a/include/xen/interface/event_channel.h
+++ b/include/xen/interface/event_channel.h
@@ -9,6 +9,8 @@
 #ifndef __XEN_PUBLIC_EVENT_CHANNEL_H__
 #define __XEN_PUBLIC_EVENT_CHANNEL_H__
 
+#include <xen/interface/xen.h>
+
 typedef uint32_t evtchn_port_t;
 DEFINE_GUEST_HANDLE(evtchn_port_t);
 
diff --git a/init/Kconfig b/init/Kconfig
index f763762..8a63c40 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -588,6 +588,13 @@
 
 	   Say N.
 
+config KALLSYMS_STRIP_GENERATED
+	bool "Strip machine generated symbols from kallsyms"
+	depends on KALLSYMS_ALL
+	default y
+	help
+	  Say N if you want kallsyms to retain even machine generated symbols.
+
 config KALLSYMS_EXTRA_PASS
 	bool "Do an extra kallsyms pass"
 	depends on KALLSYMS
@@ -808,6 +815,7 @@
 
 config MARKERS
 	bool "Activate markers"
+	depends on TRACEPOINTS
 	help
 	  Place an empty function call at each marker site. Can be
 	  dynamically changed for a probe function.
diff --git a/init/main.c b/init/main.c
index 7e117a2..17e9757b 100644
--- a/init/main.c
+++ b/init/main.c
@@ -63,6 +63,7 @@
 #include <linux/signal.h>
 #include <linux/idr.h>
 #include <linux/ftrace.h>
+#include <trace/boot.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -669,6 +670,7 @@
 		efi_enter_virtual_mode();
 #endif
 	thread_info_cache_init();
+	cred_init();
 	fork_init(num_physpages);
 	proc_caches_init();
 	buffer_init();
@@ -703,31 +705,35 @@
 int do_one_initcall(initcall_t fn)
 {
 	int count = preempt_count();
-	ktime_t delta;
+	ktime_t calltime, delta, rettime;
 	char msgbuf[64];
-	struct boot_trace it;
+	struct boot_trace_call call;
+	struct boot_trace_ret ret;
 
 	if (initcall_debug) {
-		it.caller = task_pid_nr(current);
-		printk("calling  %pF @ %i\n", fn, it.caller);
-		it.calltime = ktime_get();
+		call.caller = task_pid_nr(current);
+		printk("calling  %pF @ %i\n", fn, call.caller);
+		calltime = ktime_get();
+		trace_boot_call(&call, fn);
+		enable_boot_trace();
 	}
 
-	it.result = fn();
+	ret.result = fn();
 
 	if (initcall_debug) {
-		it.rettime = ktime_get();
-		delta = ktime_sub(it.rettime, it.calltime);
-		it.duration = (unsigned long long) delta.tv64 >> 10;
+		disable_boot_trace();
+		rettime = ktime_get();
+		delta = ktime_sub(rettime, calltime);
+		ret.duration = (unsigned long long) ktime_to_ns(delta) >> 10;
+		trace_boot_ret(&ret, fn);
 		printk("initcall %pF returned %d after %Ld usecs\n", fn,
-			it.result, it.duration);
-		trace_boot(&it, fn);
+			ret.result, ret.duration);
 	}
 
 	msgbuf[0] = 0;
 
-	if (it.result && it.result != -ENODEV && initcall_debug)
-		sprintf(msgbuf, "error code %d ", it.result);
+	if (ret.result && ret.result != -ENODEV && initcall_debug)
+		sprintf(msgbuf, "error code %d ", ret.result);
 
 	if (preempt_count() != count) {
 		strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));
@@ -741,7 +747,7 @@
 		printk("initcall %pF returned with %s\n", fn, msgbuf);
 	}
 
-	return it.result;
+	return ret.result;
 }
 
 
@@ -882,7 +888,7 @@
 	 * we're essentially up and running. Get rid of the
 	 * initmem segments and start the user-mode stuff..
 	 */
-	stop_boot_trace();
+
 	init_post();
 	return 0;
 }
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 68eb857..d9393f8 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -112,13 +112,14 @@
 static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
 							struct mq_attr *attr)
 {
+	struct user_struct *u = current_user();
 	struct inode *inode;
 
 	inode = new_inode(sb);
 	if (inode) {
 		inode->i_mode = mode;
-		inode->i_uid = current->fsuid;
-		inode->i_gid = current->fsgid;
+		inode->i_uid = current_fsuid();
+		inode->i_gid = current_fsgid();
 		inode->i_blocks = 0;
 		inode->i_mtime = inode->i_ctime = inode->i_atime =
 				CURRENT_TIME;
@@ -126,7 +127,6 @@
 		if (S_ISREG(mode)) {
 			struct mqueue_inode_info *info;
 			struct task_struct *p = current;
-			struct user_struct *u = p->user;
 			unsigned long mq_bytes, mq_msg_tblsz;
 
 			inode->i_fop = &mqueue_file_operations;
@@ -507,7 +507,7 @@
 			sig_i.si_code = SI_MESGQ;
 			sig_i.si_value = info->notify.sigev_value;
 			sig_i.si_pid = task_tgid_vnr(current);
-			sig_i.si_uid = current->uid;
+			sig_i.si_uid = current_uid();
 
 			kill_pid_info(info->notify.sigev_signo,
 				      &sig_i, info->notify_owner);
@@ -594,6 +594,7 @@
 static struct file *do_create(struct dentry *dir, struct dentry *dentry,
 			int oflag, mode_t mode, struct mq_attr __user *u_attr)
 {
+	const struct cred *cred = current_cred();
 	struct mq_attr attr;
 	struct file *result;
 	int ret;
@@ -618,7 +619,7 @@
 	if (ret)
 		goto out_drop_write;
 
-	result = dentry_open(dentry, mqueue_mnt, oflag);
+	result = dentry_open(dentry, mqueue_mnt, oflag, cred);
 	/*
 	 * dentry_open() took a persistent mnt_want_write(),
 	 * so we can now drop this one.
@@ -637,8 +638,10 @@
 /* Opens existing queue */
 static struct file *do_open(struct dentry *dentry, int oflag)
 {
-static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
-					MAY_READ | MAY_WRITE };
+	const struct cred *cred = current_cred();
+
+	static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
+						  MAY_READ | MAY_WRITE };
 
 	if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
 		dput(dentry);
@@ -652,7 +655,7 @@
 		return ERR_PTR(-EACCES);
 	}
 
-	return dentry_open(dentry, mqueue_mnt, oflag);
+	return dentry_open(dentry, mqueue_mnt, oflag, cred);
 }
 
 asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
diff --git a/ipc/shm.c b/ipc/shm.c
index 867e5d6..38a0557 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -366,7 +366,7 @@
 	if (shmflg & SHM_HUGETLB) {
 		/* hugetlb_file_setup takes care of mlock user accounting */
 		file = hugetlb_file_setup(name, size);
-		shp->mlock_user = current->user;
+		shp->mlock_user = current_user();
 	} else {
 		int acctflag = VM_ACCOUNT;
 		/*
@@ -752,9 +752,10 @@
 			goto out_unlock;
 
 		if (!capable(CAP_IPC_LOCK)) {
+			uid_t euid = current_euid();
 			err = -EPERM;
-			if (current->euid != shp->shm_perm.uid &&
-			    current->euid != shp->shm_perm.cuid)
+			if (euid != shp->shm_perm.uid &&
+			    euid != shp->shm_perm.cuid)
 				goto out_unlock;
 			if (cmd == SHM_LOCK &&
 			    !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
@@ -766,7 +767,7 @@
 			goto out_unlock;
 		
 		if(cmd==SHM_LOCK) {
-			struct user_struct * user = current->user;
+			struct user_struct *user = current_user();
 			if (!is_file_hugepages(shp->shm_file)) {
 				err = shmem_lock(shp->shm_file, 1, user);
 				if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
diff --git a/ipc/util.c b/ipc/util.c
index 361fd1c..5a1808c 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -258,6 +258,8 @@
  
 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
 {
+	uid_t euid;
+	gid_t egid;
 	int id, err;
 
 	if (size > IPCMNI)
@@ -280,8 +282,9 @@
 
 	ids->in_use++;
 
-	new->cuid = new->uid = current->euid;
-	new->gid = new->cgid = current->egid;
+	current_euid_egid(&euid, &egid);
+	new->cuid = new->uid = euid;
+	new->gid = new->cgid = egid;
 
 	new->seq = ids->seq++;
 	if(ids->seq > ids->seq_max)
@@ -620,13 +623,15 @@
  
 int ipcperms (struct kern_ipc_perm *ipcp, short flag)
 {	/* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
+	uid_t euid = current_euid();
 	int requested_mode, granted_mode, err;
 
 	if (unlikely((err = audit_ipc_obj(ipcp))))
 		return err;
 	requested_mode = (flag >> 6) | (flag >> 3) | flag;
 	granted_mode = ipcp->mode;
-	if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
+	if (euid == ipcp->cuid ||
+	    euid == ipcp->uid)
 		granted_mode >>= 6;
 	else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
 		granted_mode >>= 3;
@@ -788,6 +793,7 @@
 				      struct ipc64_perm *perm, int extra_perm)
 {
 	struct kern_ipc_perm *ipcp;
+	uid_t euid;
 	int err;
 
 	down_write(&ids->rw_mutex);
@@ -807,8 +813,10 @@
 		if (err)
 			goto out_unlock;
 	}
-	if (current->euid == ipcp->cuid ||
-	    current->euid == ipcp->uid || capable(CAP_SYS_ADMIN))
+
+	euid = current_euid();
+	if (euid == ipcp->cuid ||
+	    euid == ipcp->uid  || capable(CAP_SYS_ADMIN))
 		return ipcp;
 
 	err = -EPERM;
diff --git a/kernel/Makefile b/kernel/Makefile
index 19fad00..027edda 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,7 @@
 	    rcupdate.o extable.o params.o posix-timers.o \
 	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
 	    hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
-	    notifier.o ksysfs.o pm_qos_params.o sched_clock.o
+	    notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o
 
 ifdef CONFIG_FUNCTION_TRACER
 # Do not trace debug files and internal ftrace files
@@ -19,7 +19,6 @@
 CFLAGS_REMOVE_rtmutex-debug.o = -pg
 CFLAGS_REMOVE_cgroup-debug.o = -pg
 CFLAGS_REMOVE_sched_clock.o = -pg
-CFLAGS_REMOVE_sched.o = -pg
 endif
 
 obj-$(CONFIG_FREEZER) += freezer.o
@@ -90,7 +89,7 @@
 obj-$(CONFIG_TRACING) += trace/
 obj-$(CONFIG_SMP) += sched_cpupri.o
 
-ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
+ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
 # needed for x86 only.  Why this used to be enabled for all architectures is beyond
 # me.  I suspect most platforms don't need this, but until we know that for sure
diff --git a/kernel/acct.c b/kernel/acct.c
index f6006a6..d57b7cb 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -530,15 +530,14 @@
 	do_div(elapsed, AHZ);
 	ac.ac_btime = get_seconds() - elapsed;
 	/* we really need to bite the bullet and change layout */
-	ac.ac_uid = current->uid;
-	ac.ac_gid = current->gid;
+	current_uid_gid(&ac.ac_uid, &ac.ac_gid);
 #if ACCT_VERSION==2
 	ac.ac_ahz = AHZ;
 #endif
 #if ACCT_VERSION==1 || ACCT_VERSION==2
 	/* backward-compatible 16 bit fields */
-	ac.ac_uid16 = current->uid;
-	ac.ac_gid16 = current->gid;
+	ac.ac_uid16 = ac.ac_uid;
+	ac.ac_gid16 = ac.ac_gid;
 #endif
 #if ACCT_VERSION==3
 	ac.ac_pid = task_tgid_nr_ns(current, ns);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 2a3f0af..4819f37 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -65,6 +65,7 @@
 #include <linux/highmem.h>
 #include <linux/syscalls.h>
 #include <linux/inotify.h>
+#include <linux/capability.h>
 
 #include "audit.h"
 
@@ -84,6 +85,15 @@
 /* determines whether we collect data for signals sent */
 int audit_signals;
 
+struct audit_cap_data {
+	kernel_cap_t		permitted;
+	kernel_cap_t		inheritable;
+	union {
+		unsigned int	fE;		/* effective bit of a file capability */
+		kernel_cap_t	effective;	/* effective set of a process */
+	};
+};
+
 /* When fs/namei.c:getname() is called, we store the pointer in name and
  * we don't let putname() free it (instead we free all of the saved
  * pointers at syscall exit time).
@@ -100,6 +110,8 @@
 	gid_t		gid;
 	dev_t		rdev;
 	u32		osid;
+	struct audit_cap_data fcap;
+	unsigned int	fcap_ver;
 };
 
 struct audit_aux_data {
@@ -184,6 +196,20 @@
 	int			pid_count;
 };
 
+struct audit_aux_data_bprm_fcaps {
+	struct audit_aux_data	d;
+	struct audit_cap_data	fcap;
+	unsigned int		fcap_ver;
+	struct audit_cap_data	old_pcap;
+	struct audit_cap_data	new_pcap;
+};
+
+struct audit_aux_data_capset {
+	struct audit_aux_data	d;
+	pid_t			pid;
+	struct audit_cap_data	cap;
+};
+
 struct audit_tree_refs {
 	struct audit_tree_refs *next;
 	struct audit_chunk *c[31];
@@ -421,6 +447,7 @@
 			      struct audit_names *name,
 			      enum audit_state *state)
 {
+	const struct cred *cred = get_task_cred(tsk);
 	int i, j, need_sid = 1;
 	u32 sid;
 
@@ -440,28 +467,28 @@
 			}
 			break;
 		case AUDIT_UID:
-			result = audit_comparator(tsk->uid, f->op, f->val);
+			result = audit_comparator(cred->uid, f->op, f->val);
 			break;
 		case AUDIT_EUID:
-			result = audit_comparator(tsk->euid, f->op, f->val);
+			result = audit_comparator(cred->euid, f->op, f->val);
 			break;
 		case AUDIT_SUID:
-			result = audit_comparator(tsk->suid, f->op, f->val);
+			result = audit_comparator(cred->suid, f->op, f->val);
 			break;
 		case AUDIT_FSUID:
-			result = audit_comparator(tsk->fsuid, f->op, f->val);
+			result = audit_comparator(cred->fsuid, f->op, f->val);
 			break;
 		case AUDIT_GID:
-			result = audit_comparator(tsk->gid, f->op, f->val);
+			result = audit_comparator(cred->gid, f->op, f->val);
 			break;
 		case AUDIT_EGID:
-			result = audit_comparator(tsk->egid, f->op, f->val);
+			result = audit_comparator(cred->egid, f->op, f->val);
 			break;
 		case AUDIT_SGID:
-			result = audit_comparator(tsk->sgid, f->op, f->val);
+			result = audit_comparator(cred->sgid, f->op, f->val);
 			break;
 		case AUDIT_FSGID:
-			result = audit_comparator(tsk->fsgid, f->op, f->val);
+			result = audit_comparator(cred->fsgid, f->op, f->val);
 			break;
 		case AUDIT_PERS:
 			result = audit_comparator(tsk->personality, f->op, f->val);
@@ -615,8 +642,10 @@
 			break;
 		}
 
-		if (!result)
+		if (!result) {
+			put_cred(cred);
 			return 0;
+		}
 	}
 	if (rule->filterkey && ctx)
 		ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
@@ -624,6 +653,7 @@
 	case AUDIT_NEVER:    *state = AUDIT_DISABLED;	    break;
 	case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
 	}
+	put_cred(cred);
 	return 1;
 }
 
@@ -1171,8 +1201,38 @@
 	kfree(buf);
 }
 
+static void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
+{
+	int i;
+
+	audit_log_format(ab, " %s=", prefix);
+	CAP_FOR_EACH_U32(i) {
+		audit_log_format(ab, "%08x", cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]);
+	}
+}
+
+static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
+{
+	kernel_cap_t *perm = &name->fcap.permitted;
+	kernel_cap_t *inh = &name->fcap.inheritable;
+	int log = 0;
+
+	if (!cap_isclear(*perm)) {
+		audit_log_cap(ab, "cap_fp", perm);
+		log = 1;
+	}
+	if (!cap_isclear(*inh)) {
+		audit_log_cap(ab, "cap_fi", inh);
+		log = 1;
+	}
+
+	if (log)
+		audit_log_format(ab, " cap_fe=%d cap_fver=%x", name->fcap.fE, name->fcap_ver);
+}
+
 static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
+	const struct cred *cred;
 	int i, call_panic = 0;
 	struct audit_buffer *ab;
 	struct audit_aux_data *aux;
@@ -1182,14 +1242,15 @@
 	context->pid = tsk->pid;
 	if (!context->ppid)
 		context->ppid = sys_getppid();
-	context->uid = tsk->uid;
-	context->gid = tsk->gid;
-	context->euid = tsk->euid;
-	context->suid = tsk->suid;
-	context->fsuid = tsk->fsuid;
-	context->egid = tsk->egid;
-	context->sgid = tsk->sgid;
-	context->fsgid = tsk->fsgid;
+	cred = current_cred();
+	context->uid   = cred->uid;
+	context->gid   = cred->gid;
+	context->euid  = cred->euid;
+	context->suid  = cred->suid;
+	context->fsuid = cred->fsuid;
+	context->egid  = cred->egid;
+	context->sgid  = cred->sgid;
+	context->fsgid = cred->fsgid;
 	context->personality = tsk->personality;
 
 	ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
@@ -1334,6 +1395,28 @@
 			audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]);
 			break; }
 
+		case AUDIT_BPRM_FCAPS: {
+			struct audit_aux_data_bprm_fcaps *axs = (void *)aux;
+			audit_log_format(ab, "fver=%x", axs->fcap_ver);
+			audit_log_cap(ab, "fp", &axs->fcap.permitted);
+			audit_log_cap(ab, "fi", &axs->fcap.inheritable);
+			audit_log_format(ab, " fe=%d", axs->fcap.fE);
+			audit_log_cap(ab, "old_pp", &axs->old_pcap.permitted);
+			audit_log_cap(ab, "old_pi", &axs->old_pcap.inheritable);
+			audit_log_cap(ab, "old_pe", &axs->old_pcap.effective);
+			audit_log_cap(ab, "new_pp", &axs->new_pcap.permitted);
+			audit_log_cap(ab, "new_pi", &axs->new_pcap.inheritable);
+			audit_log_cap(ab, "new_pe", &axs->new_pcap.effective);
+			break; }
+
+		case AUDIT_CAPSET: {
+			struct audit_aux_data_capset *axs = (void *)aux;
+			audit_log_format(ab, "pid=%d", axs->pid);
+			audit_log_cap(ab, "cap_pi", &axs->cap.inheritable);
+			audit_log_cap(ab, "cap_pp", &axs->cap.permitted);
+			audit_log_cap(ab, "cap_pe", &axs->cap.effective);
+			break; }
+
 		}
 		audit_log_end(ab);
 	}
@@ -1421,6 +1504,8 @@
 			}
 		}
 
+		audit_log_fcaps(ab, n);
+
 		audit_log_end(ab);
 	}
 
@@ -1802,8 +1887,36 @@
 	return 0;
 }
 
+
+static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry)
+{
+	struct cpu_vfs_cap_data caps;
+	int rc;
+
+	memset(&name->fcap.permitted, 0, sizeof(kernel_cap_t));
+	memset(&name->fcap.inheritable, 0, sizeof(kernel_cap_t));
+	name->fcap.fE = 0;
+	name->fcap_ver = 0;
+
+	if (!dentry)
+		return 0;
+
+	rc = get_vfs_caps_from_disk(dentry, &caps);
+	if (rc)
+		return rc;
+
+	name->fcap.permitted = caps.permitted;
+	name->fcap.inheritable = caps.inheritable;
+	name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
+	name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT;
+
+	return 0;
+}
+
+
 /* Copy inode data into an audit_names. */
-static void audit_copy_inode(struct audit_names *name, const struct inode *inode)
+static void audit_copy_inode(struct audit_names *name, const struct dentry *dentry,
+			     const struct inode *inode)
 {
 	name->ino   = inode->i_ino;
 	name->dev   = inode->i_sb->s_dev;
@@ -1812,6 +1925,7 @@
 	name->gid   = inode->i_gid;
 	name->rdev  = inode->i_rdev;
 	security_inode_getsecid(inode, &name->osid);
+	audit_copy_fcaps(name, dentry);
 }
 
 /**
@@ -1846,7 +1960,7 @@
 		context->names[idx].name = NULL;
 	}
 	handle_path(dentry);
-	audit_copy_inode(&context->names[idx], inode);
+	audit_copy_inode(&context->names[idx], dentry, inode);
 }
 
 /**
@@ -1907,7 +2021,7 @@
 		if (!strcmp(dname, n->name) ||
 		     !audit_compare_dname_path(dname, n->name, &dirlen)) {
 			if (inode)
-				audit_copy_inode(n, inode);
+				audit_copy_inode(n, NULL, inode);
 			else
 				n->ino = (unsigned long)-1;
 			found_child = n->name;
@@ -1921,7 +2035,7 @@
 			return;
 		idx = context->name_count - 1;
 		context->names[idx].name = NULL;
-		audit_copy_inode(&context->names[idx], parent);
+		audit_copy_inode(&context->names[idx], NULL, parent);
 	}
 
 	if (!found_child) {
@@ -1942,7 +2056,7 @@
 		}
 
 		if (inode)
-			audit_copy_inode(&context->names[idx], inode);
+			audit_copy_inode(&context->names[idx], NULL, inode);
 		else
 			context->names[idx].ino = (unsigned long)-1;
 	}
@@ -1996,7 +2110,7 @@
 			audit_log_format(ab, "login pid=%d uid=%u "
 				"old auid=%u new auid=%u"
 				" old ses=%u new ses=%u",
-				task->pid, task->uid,
+				task->pid, task_uid(task),
 				task->loginuid, loginuid,
 				task->sessionid, sessionid);
 			audit_log_end(ab);
@@ -2379,7 +2493,7 @@
 
 	context->target_pid = t->pid;
 	context->target_auid = audit_get_loginuid(t);
-	context->target_uid = t->uid;
+	context->target_uid = task_uid(t);
 	context->target_sessionid = audit_get_sessionid(t);
 	security_task_getsecid(t, &context->target_sid);
 	memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
@@ -2398,6 +2512,7 @@
 	struct audit_aux_data_pids *axp;
 	struct task_struct *tsk = current;
 	struct audit_context *ctx = tsk->audit_context;
+	uid_t uid = current_uid(), t_uid = task_uid(t);
 
 	if (audit_pid && t->tgid == audit_pid) {
 		if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1 || sig == SIGUSR2) {
@@ -2405,7 +2520,7 @@
 			if (tsk->loginuid != -1)
 				audit_sig_uid = tsk->loginuid;
 			else
-				audit_sig_uid = tsk->uid;
+				audit_sig_uid = uid;
 			security_task_getsecid(tsk, &audit_sig_sid);
 		}
 		if (!audit_signals || audit_dummy_context())
@@ -2417,7 +2532,7 @@
 	if (!ctx->target_pid) {
 		ctx->target_pid = t->tgid;
 		ctx->target_auid = audit_get_loginuid(t);
-		ctx->target_uid = t->uid;
+		ctx->target_uid = t_uid;
 		ctx->target_sessionid = audit_get_sessionid(t);
 		security_task_getsecid(t, &ctx->target_sid);
 		memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
@@ -2438,7 +2553,7 @@
 
 	axp->target_pid[axp->pid_count] = t->tgid;
 	axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
-	axp->target_uid[axp->pid_count] = t->uid;
+	axp->target_uid[axp->pid_count] = t_uid;
 	axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
 	security_task_getsecid(t, &axp->target_sid[axp->pid_count]);
 	memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
@@ -2448,6 +2563,86 @@
 }
 
 /**
+ * __audit_log_bprm_fcaps - store information about a loading bprm and relevant fcaps
+ * @bprm: pointer to the bprm being processed
+ * @new: the proposed new credentials
+ * @old: the old credentials
+ *
+ * Simply check if the proc already has the caps given by the file and if not
+ * store the priv escalation info for later auditing at the end of the syscall
+ *
+ * -Eric
+ */
+int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
+			   const struct cred *new, const struct cred *old)
+{
+	struct audit_aux_data_bprm_fcaps *ax;
+	struct audit_context *context = current->audit_context;
+	struct cpu_vfs_cap_data vcaps;
+	struct dentry *dentry;
+
+	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+	if (!ax)
+		return -ENOMEM;
+
+	ax->d.type = AUDIT_BPRM_FCAPS;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+
+	dentry = dget(bprm->file->f_dentry);
+	get_vfs_caps_from_disk(dentry, &vcaps);
+	dput(dentry);
+
+	ax->fcap.permitted = vcaps.permitted;
+	ax->fcap.inheritable = vcaps.inheritable;
+	ax->fcap.fE = !!(vcaps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
+	ax->fcap_ver = (vcaps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT;
+
+	ax->old_pcap.permitted   = old->cap_permitted;
+	ax->old_pcap.inheritable = old->cap_inheritable;
+	ax->old_pcap.effective   = old->cap_effective;
+
+	ax->new_pcap.permitted   = new->cap_permitted;
+	ax->new_pcap.inheritable = new->cap_inheritable;
+	ax->new_pcap.effective   = new->cap_effective;
+	return 0;
+}
+
+/**
+ * __audit_log_capset - store information about the arguments to the capset syscall
+ * @pid: target pid of the capset call
+ * @new: the new credentials
+ * @old: the old (current) credentials
+ *
+ * Record the aguments userspace sent to sys_capset for later printing by the
+ * audit system if applicable
+ */
+int __audit_log_capset(pid_t pid,
+		       const struct cred *new, const struct cred *old)
+{
+	struct audit_aux_data_capset *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (likely(!audit_enabled || !context || context->dummy))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+	if (!ax)
+		return -ENOMEM;
+
+	ax->d.type = AUDIT_CAPSET;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+
+	ax->pid = pid;
+	ax->cap.effective   = new->cap_effective;
+	ax->cap.inheritable = new->cap_effective;
+	ax->cap.permitted   = new->cap_permitted;
+
+	return 0;
+}
+
+/**
  * audit_core_dumps - record information about processes that end abnormally
  * @signr: signal value
  *
@@ -2458,7 +2653,8 @@
 {
 	struct audit_buffer *ab;
 	u32 sid;
-	uid_t auid = audit_get_loginuid(current);
+	uid_t auid = audit_get_loginuid(current), uid;
+	gid_t gid;
 	unsigned int sessionid = audit_get_sessionid(current);
 
 	if (!audit_enabled)
@@ -2468,8 +2664,9 @@
 		return;
 
 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
+	current_uid_gid(&uid, &gid);
 	audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
-			auid, current->uid, current->gid, sessionid);
+			 auid, uid, gid, sessionid);
 	security_task_getsecid(current, &sid);
 	if (sid) {
 		char *ctx = NULL;
diff --git a/kernel/capability.c b/kernel/capability.c
index 33e51e7..36b4b4d 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -7,6 +7,7 @@
  * 30 May 2002:	Cleanup, Robert M. Love <rml@tech9.net>
  */
 
+#include <linux/audit.h>
 #include <linux/capability.h>
 #include <linux/mm.h>
 #include <linux/module.h>
@@ -14,12 +15,7 @@
 #include <linux/syscalls.h>
 #include <linux/pid_namespace.h>
 #include <asm/uaccess.h>
-
-/*
- * This lock protects task->cap_* for all tasks including current.
- * Locking rule: acquire this prior to tasklist_lock.
- */
-static DEFINE_SPINLOCK(task_capability_lock);
+#include "cred-internals.h"
 
 /*
  * Leveraged for setting/resetting capabilities
@@ -33,6 +29,17 @@
 EXPORT_SYMBOL(__cap_full_set);
 EXPORT_SYMBOL(__cap_init_eff_set);
 
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
+int file_caps_enabled = 1;
+
+static int __init file_caps_disable(char *str)
+{
+	file_caps_enabled = 0;
+	return 1;
+}
+__setup("no_file_caps", file_caps_disable);
+#endif
+
 /*
  * More recent versions of libcap are available from:
  *
@@ -115,167 +122,12 @@
 	return 0;
 }
 
-#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
-
 /*
- * Without filesystem capability support, we nominally support one process
- * setting the capabilities of another
- */
-static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
-				     kernel_cap_t *pIp, kernel_cap_t *pPp)
-{
-	struct task_struct *target;
-	int ret;
-
-	spin_lock(&task_capability_lock);
-	read_lock(&tasklist_lock);
-
-	if (pid && pid != task_pid_vnr(current)) {
-		target = find_task_by_vpid(pid);
-		if (!target) {
-			ret = -ESRCH;
-			goto out;
-		}
-	} else
-		target = current;
-
-	ret = security_capget(target, pEp, pIp, pPp);
-
-out:
-	read_unlock(&tasklist_lock);
-	spin_unlock(&task_capability_lock);
-
-	return ret;
-}
-
-/*
- * cap_set_pg - set capabilities for all processes in a given process
- * group.  We call this holding task_capability_lock and tasklist_lock.
- */
-static inline int cap_set_pg(int pgrp_nr, kernel_cap_t *effective,
-			     kernel_cap_t *inheritable,
-			     kernel_cap_t *permitted)
-{
-	struct task_struct *g, *target;
-	int ret = -EPERM;
-	int found = 0;
-	struct pid *pgrp;
-
-	spin_lock(&task_capability_lock);
-	read_lock(&tasklist_lock);
-
-	pgrp = find_vpid(pgrp_nr);
-	do_each_pid_task(pgrp, PIDTYPE_PGID, g) {
-		target = g;
-		while_each_thread(g, target) {
-			if (!security_capset_check(target, effective,
-						   inheritable, permitted)) {
-				security_capset_set(target, effective,
-						    inheritable, permitted);
-				ret = 0;
-			}
-			found = 1;
-		}
-	} while_each_pid_task(pgrp, PIDTYPE_PGID, g);
-
-	read_unlock(&tasklist_lock);
-	spin_unlock(&task_capability_lock);
-
-	if (!found)
-		ret = 0;
-	return ret;
-}
-
-/*
- * cap_set_all - set capabilities for all processes other than init
- * and self.  We call this holding task_capability_lock and tasklist_lock.
- */
-static inline int cap_set_all(kernel_cap_t *effective,
-			      kernel_cap_t *inheritable,
-			      kernel_cap_t *permitted)
-{
-	struct task_struct *g, *target;
-	int ret = -EPERM;
-	int found = 0;
-
-	spin_lock(&task_capability_lock);
-	read_lock(&tasklist_lock);
-
-	do_each_thread(g, target) {
-		if (target == current
-		    || is_container_init(target->group_leader))
-			continue;
-		found = 1;
-		if (security_capset_check(target, effective, inheritable,
-					  permitted))
-			continue;
-		ret = 0;
-		security_capset_set(target, effective, inheritable, permitted);
-	} while_each_thread(g, target);
-
-	read_unlock(&tasklist_lock);
-	spin_unlock(&task_capability_lock);
-
-	if (!found)
-		ret = 0;
-
-	return ret;
-}
-
-/*
- * Given the target pid does not refer to the current process we
- * need more elaborate support... (This support is not present when
- * filesystem capabilities are configured.)
- */
-static inline int do_sys_capset_other_tasks(pid_t pid, kernel_cap_t *effective,
-					    kernel_cap_t *inheritable,
-					    kernel_cap_t *permitted)
-{
-	struct task_struct *target;
-	int ret;
-
-	if (!capable(CAP_SETPCAP))
-		return -EPERM;
-
-	if (pid == -1)	          /* all procs other than current and init */
-		return cap_set_all(effective, inheritable, permitted);
-
-	else if (pid < 0)                    /* all procs in process group */
-		return cap_set_pg(-pid, effective, inheritable, permitted);
-
-	/* target != current */
-	spin_lock(&task_capability_lock);
-	read_lock(&tasklist_lock);
-
-	target = find_task_by_vpid(pid);
-	if (!target)
-		ret = -ESRCH;
-	else {
-		ret = security_capset_check(target, effective, inheritable,
-					    permitted);
-
-		/* having verified that the proposed changes are legal,
-		   we now put them into effect. */
-		if (!ret)
-			security_capset_set(target, effective, inheritable,
-					    permitted);
-	}
-
-	read_unlock(&tasklist_lock);
-	spin_unlock(&task_capability_lock);
-
-	return ret;
-}
-
-#else /* ie., def CONFIG_SECURITY_FILE_CAPABILITIES */
-
-/*
- * If we have configured with filesystem capability support, then the
- * only thing that can change the capabilities of the current process
- * is the current process. As such, we can't be in this code at the
- * same time as we are in the process of setting capabilities in this
- * process. The net result is that we can limit our use of locks to
- * when we are reading the caps of another process.
+ * The only thing that can change the capabilities of the current
+ * process is the current process. As such, we can't be in this code
+ * at the same time as we are in the process of setting capabilities
+ * in this process. The net result is that we can limit our use of
+ * locks to when we are reading the caps of another process.
  */
 static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
 				     kernel_cap_t *pIp, kernel_cap_t *pPp)
@@ -285,7 +137,6 @@
 	if (pid && (pid != task_pid_vnr(current))) {
 		struct task_struct *target;
 
-		spin_lock(&task_capability_lock);
 		read_lock(&tasklist_lock);
 
 		target = find_task_by_vpid(pid);
@@ -295,50 +146,12 @@
 			ret = security_capget(target, pEp, pIp, pPp);
 
 		read_unlock(&tasklist_lock);
-		spin_unlock(&task_capability_lock);
 	} else
 		ret = security_capget(current, pEp, pIp, pPp);
 
 	return ret;
 }
 
-/*
- * With filesystem capability support configured, the kernel does not
- * permit the changing of capabilities in one process by another
- * process. (CAP_SETPCAP has much less broad semantics when configured
- * this way.)
- */
-static inline int do_sys_capset_other_tasks(pid_t pid,
-					    kernel_cap_t *effective,
-					    kernel_cap_t *inheritable,
-					    kernel_cap_t *permitted)
-{
-	return -EPERM;
-}
-
-#endif /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */
-
-/*
- * Atomically modify the effective capabilities returning the original
- * value. No permission check is performed here - it is assumed that the
- * caller is permitted to set the desired effective capabilities.
- */
-kernel_cap_t cap_set_effective(const kernel_cap_t pE_new)
-{
-	kernel_cap_t pE_old;
-
-	spin_lock(&task_capability_lock);
-
-	pE_old = current->cap_effective;
-	current->cap_effective = pE_new;
-
-	spin_unlock(&task_capability_lock);
-
-	return pE_old;
-}
-
-EXPORT_SYMBOL(cap_set_effective);
-
 /**
  * sys_capget - get the capabilities of a given process.
  * @header: pointer to struct that contains capability version and
@@ -366,7 +179,6 @@
 		return -EINVAL;
 
 	ret = cap_get_target_pid(pid, &pE, &pI, &pP);
-
 	if (!ret) {
 		struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
 		unsigned i;
@@ -412,16 +224,14 @@
  * @data: pointer to struct that contains the effective, permitted,
  *	and inheritable capabilities
  *
- * Set capabilities for a given process, all processes, or all
- * processes in a given process group.
+ * Set capabilities for the current process only.  The ability to any other
+ * process(es) has been deprecated and removed.
  *
  * The restrictions on setting capabilities are specified as:
  *
- * [pid is for the 'target' task.  'current' is the calling task.]
- *
- * I: any raised capabilities must be a subset of the (old current) permitted
- * P: any raised capabilities must be a subset of the (old current) permitted
- * E: must be set to a subset of (new target) permitted
+ * I: any raised capabilities must be a subset of the old permitted
+ * P: any raised capabilities must be a subset of the old permitted
+ * E: must be set to a subset of new permitted
  *
  * Returns 0 on success and < 0 on error.
  */
@@ -430,6 +240,7 @@
 	struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
 	unsigned i, tocopy;
 	kernel_cap_t inheritable, permitted, effective;
+	struct cred *new;
 	int ret;
 	pid_t pid;
 
@@ -440,10 +251,13 @@
 	if (get_user(pid, &header->pid))
 		return -EFAULT;
 
-	if (copy_from_user(&kdata, data, tocopy
-			   * sizeof(struct __user_cap_data_struct))) {
+	/* may only affect current now */
+	if (pid != 0 && pid != task_pid_vnr(current))
+		return -EPERM;
+
+	if (copy_from_user(&kdata, data,
+			   tocopy * sizeof(struct __user_cap_data_struct)))
 		return -EFAULT;
-	}
 
 	for (i = 0; i < tocopy; i++) {
 		effective.cap[i] = kdata[i].effective;
@@ -457,32 +271,23 @@
 		i++;
 	}
 
-	if (pid && (pid != task_pid_vnr(current)))
-		ret = do_sys_capset_other_tasks(pid, &effective, &inheritable,
-						&permitted);
-	else {
-		/*
-		 * This lock is required even when filesystem
-		 * capability support is configured - it protects the
-		 * sys_capget() call from returning incorrect data in
-		 * the case that the targeted process is not the
-		 * current one.
-		 */
-		spin_lock(&task_capability_lock);
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
 
-		ret = security_capset_check(current, &effective, &inheritable,
-					    &permitted);
-		/*
-		 * Having verified that the proposed changes are
-		 * legal, we now put them into effect.
-		 */
-		if (!ret)
-			security_capset_set(current, &effective, &inheritable,
-					    &permitted);
-		spin_unlock(&task_capability_lock);
-	}
+	ret = security_capset(new, current_cred(),
+			      &effective, &inheritable, &permitted);
+	if (ret < 0)
+		goto error;
 
+	ret = audit_log_capset(pid, new, current_cred());
+	if (ret < 0)
+		return ret;
 
+	return commit_creds(new);
+
+error:
+	abort_creds(new);
 	return ret;
 }
 
@@ -498,6 +303,11 @@
  */
 int capable(int cap)
 {
+	if (unlikely(!cap_valid(cap))) {
+		printk(KERN_CRIT "capable() called with invalid cap=%u\n", cap);
+		BUG();
+	}
+
 	if (has_capability(current, cap)) {
 		current->flags |= PF_SUPERPRIV;
 		return 1;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 8185a0f..48348dd 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -571,8 +571,8 @@
 
 	if (inode) {
 		inode->i_mode = mode;
-		inode->i_uid = current->fsuid;
-		inode->i_gid = current->fsgid;
+		inode->i_uid = current_fsuid();
+		inode->i_gid = current_fsgid();
 		inode->i_blocks = 0;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 		inode->i_mapping->backing_dev_info = &cgroup_backing_dev_info;
@@ -1024,7 +1024,7 @@
 		if (ret == -EBUSY) {
 			mutex_unlock(&cgroup_mutex);
 			mutex_unlock(&inode->i_mutex);
-			goto drop_new_super;
+			goto free_cg_links;
 		}
 
 		/* EBUSY should be the only error here */
@@ -1073,10 +1073,11 @@
 
 	return simple_set_mnt(mnt, sb);
 
+ free_cg_links:
+	free_cg_links(&tmp_cg_links);
  drop_new_super:
 	up_write(&sb->s_umount);
 	deactivate_super(sb);
-	free_cg_links(&tmp_cg_links);
 	return ret;
 }
 
@@ -1279,6 +1280,7 @@
 static int attach_task_by_pid(struct cgroup *cgrp, u64 pid)
 {
 	struct task_struct *tsk;
+	const struct cred *cred = current_cred(), *tcred;
 	int ret;
 
 	if (pid) {
@@ -1288,14 +1290,16 @@
 			rcu_read_unlock();
 			return -ESRCH;
 		}
-		get_task_struct(tsk);
-		rcu_read_unlock();
 
-		if ((current->euid) && (current->euid != tsk->uid)
-		    && (current->euid != tsk->suid)) {
-			put_task_struct(tsk);
+		tcred = __task_cred(tsk);
+		if (cred->euid &&
+		    cred->euid != tcred->uid &&
+		    cred->euid != tcred->suid) {
+			rcu_read_unlock();
 			return -EACCES;
 		}
+		get_task_struct(tsk);
+		rcu_read_unlock();
 	} else {
 		tsk = current;
 		get_task_struct(tsk);
@@ -2934,9 +2938,6 @@
  again:
 	root = subsys->root;
 	if (root == &rootnode) {
-		printk(KERN_INFO
-		       "Not cloning cgroup for unused subsystem %s\n",
-		       subsys->name);
 		mutex_unlock(&cgroup_mutex);
 		return 0;
 	}
diff --git a/kernel/cred-internals.h b/kernel/cred-internals.h
new file mode 100644
index 0000000..2dc4fc2
--- /dev/null
+++ b/kernel/cred-internals.h
@@ -0,0 +1,21 @@
+/* Internal credentials stuff
+ *
+ * Copyright (C) 2008 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.
+ */
+
+/*
+ * user.c
+ */
+static inline void sched_switch_user(struct task_struct *p)
+{
+#ifdef CONFIG_USER_SCHED
+	sched_move_task(p);
+#endif	/* CONFIG_USER_SCHED */
+}
+
diff --git a/kernel/cred.c b/kernel/cred.c
new file mode 100644
index 0000000..ff7bc07
--- /dev/null
+++ b/kernel/cred.c
@@ -0,0 +1,588 @@
+/* Task credentials management - see Documentation/credentials.txt
+ *
+ * Copyright (C) 2008 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.
+ */
+#include <linux/module.h>
+#include <linux/cred.h>
+#include <linux/sched.h>
+#include <linux/key.h>
+#include <linux/keyctl.h>
+#include <linux/init_task.h>
+#include <linux/security.h>
+#include <linux/cn_proc.h>
+#include "cred-internals.h"
+
+static struct kmem_cache *cred_jar;
+
+/*
+ * The common credentials for the initial task's thread group
+ */
+#ifdef CONFIG_KEYS
+static struct thread_group_cred init_tgcred = {
+	.usage	= ATOMIC_INIT(2),
+	.tgid	= 0,
+	.lock	= SPIN_LOCK_UNLOCKED,
+};
+#endif
+
+/*
+ * The initial credentials for the initial task
+ */
+struct cred init_cred = {
+	.usage			= ATOMIC_INIT(4),
+	.securebits		= SECUREBITS_DEFAULT,
+	.cap_inheritable	= CAP_INIT_INH_SET,
+	.cap_permitted		= CAP_FULL_SET,
+	.cap_effective		= CAP_INIT_EFF_SET,
+	.cap_bset		= CAP_INIT_BSET,
+	.user			= INIT_USER,
+	.group_info		= &init_groups,
+#ifdef CONFIG_KEYS
+	.tgcred			= &init_tgcred,
+#endif
+};
+
+/*
+ * Dispose of the shared task group credentials
+ */
+#ifdef CONFIG_KEYS
+static void release_tgcred_rcu(struct rcu_head *rcu)
+{
+	struct thread_group_cred *tgcred =
+		container_of(rcu, struct thread_group_cred, rcu);
+
+	BUG_ON(atomic_read(&tgcred->usage) != 0);
+
+	key_put(tgcred->session_keyring);
+	key_put(tgcred->process_keyring);
+	kfree(tgcred);
+}
+#endif
+
+/*
+ * Release a set of thread group credentials.
+ */
+static void release_tgcred(struct cred *cred)
+{
+#ifdef CONFIG_KEYS
+	struct thread_group_cred *tgcred = cred->tgcred;
+
+	if (atomic_dec_and_test(&tgcred->usage))
+		call_rcu(&tgcred->rcu, release_tgcred_rcu);
+#endif
+}
+
+/*
+ * The RCU callback to actually dispose of a set of credentials
+ */
+static void put_cred_rcu(struct rcu_head *rcu)
+{
+	struct cred *cred = container_of(rcu, struct cred, rcu);
+
+	if (atomic_read(&cred->usage) != 0)
+		panic("CRED: put_cred_rcu() sees %p with usage %d\n",
+		      cred, atomic_read(&cred->usage));
+
+	security_cred_free(cred);
+	key_put(cred->thread_keyring);
+	key_put(cred->request_key_auth);
+	release_tgcred(cred);
+	put_group_info(cred->group_info);
+	free_uid(cred->user);
+	kmem_cache_free(cred_jar, cred);
+}
+
+/**
+ * __put_cred - Destroy a set of credentials
+ * @cred: The record to release
+ *
+ * Destroy a set of credentials on which no references remain.
+ */
+void __put_cred(struct cred *cred)
+{
+	BUG_ON(atomic_read(&cred->usage) != 0);
+
+	call_rcu(&cred->rcu, put_cred_rcu);
+}
+EXPORT_SYMBOL(__put_cred);
+
+/**
+ * prepare_creds - Prepare a new set of credentials for modification
+ *
+ * Prepare a new set of task credentials for modification.  A task's creds
+ * shouldn't generally be modified directly, therefore this function is used to
+ * prepare a new copy, which the caller then modifies and then commits by
+ * calling commit_creds().
+ *
+ * Preparation involves making a copy of the objective creds for modification.
+ *
+ * Returns a pointer to the new creds-to-be if successful, NULL otherwise.
+ *
+ * Call commit_creds() or abort_creds() to clean up.
+ */
+struct cred *prepare_creds(void)
+{
+	struct task_struct *task = current;
+	const struct cred *old;
+	struct cred *new;
+
+	BUG_ON(atomic_read(&task->real_cred->usage) < 1);
+
+	new = kmem_cache_alloc(cred_jar, GFP_KERNEL);
+	if (!new)
+		return NULL;
+
+	old = task->cred;
+	memcpy(new, old, sizeof(struct cred));
+
+	atomic_set(&new->usage, 1);
+	get_group_info(new->group_info);
+	get_uid(new->user);
+
+#ifdef CONFIG_KEYS
+	key_get(new->thread_keyring);
+	key_get(new->request_key_auth);
+	atomic_inc(&new->tgcred->usage);
+#endif
+
+#ifdef CONFIG_SECURITY
+	new->security = NULL;
+#endif
+
+	if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
+		goto error;
+	return new;
+
+error:
+	abort_creds(new);
+	return NULL;
+}
+EXPORT_SYMBOL(prepare_creds);
+
+/*
+ * Prepare credentials for current to perform an execve()
+ * - The caller must hold current->cred_exec_mutex
+ */
+struct cred *prepare_exec_creds(void)
+{
+	struct thread_group_cred *tgcred = NULL;
+	struct cred *new;
+
+#ifdef CONFIG_KEYS
+	tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
+	if (!tgcred)
+		return NULL;
+#endif
+
+	new = prepare_creds();
+	if (!new) {
+		kfree(tgcred);
+		return new;
+	}
+
+#ifdef CONFIG_KEYS
+	/* newly exec'd tasks don't get a thread keyring */
+	key_put(new->thread_keyring);
+	new->thread_keyring = NULL;
+
+	/* create a new per-thread-group creds for all this set of threads to
+	 * share */
+	memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred));
+
+	atomic_set(&tgcred->usage, 1);
+	spin_lock_init(&tgcred->lock);
+
+	/* inherit the session keyring; new process keyring */
+	key_get(tgcred->session_keyring);
+	tgcred->process_keyring = NULL;
+
+	release_tgcred(new);
+	new->tgcred = tgcred;
+#endif
+
+	return new;
+}
+
+/*
+ * prepare new credentials for the usermode helper dispatcher
+ */
+struct cred *prepare_usermodehelper_creds(void)
+{
+#ifdef CONFIG_KEYS
+	struct thread_group_cred *tgcred = NULL;
+#endif
+	struct cred *new;
+
+#ifdef CONFIG_KEYS
+	tgcred = kzalloc(sizeof(*new->tgcred), GFP_ATOMIC);
+	if (!tgcred)
+		return NULL;
+#endif
+
+	new = kmem_cache_alloc(cred_jar, GFP_ATOMIC);
+	if (!new)
+		return NULL;
+
+	memcpy(new, &init_cred, sizeof(struct cred));
+
+	atomic_set(&new->usage, 1);
+	get_group_info(new->group_info);
+	get_uid(new->user);
+
+#ifdef CONFIG_KEYS
+	new->thread_keyring = NULL;
+	new->request_key_auth = NULL;
+	new->jit_keyring = KEY_REQKEY_DEFL_DEFAULT;
+
+	atomic_set(&tgcred->usage, 1);
+	spin_lock_init(&tgcred->lock);
+	new->tgcred = tgcred;
+#endif
+
+#ifdef CONFIG_SECURITY
+	new->security = NULL;
+#endif
+	if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0)
+		goto error;
+
+	BUG_ON(atomic_read(&new->usage) != 1);
+	return new;
+
+error:
+	put_cred(new);
+	return NULL;
+}
+
+/*
+ * Copy credentials for the new process created by fork()
+ *
+ * We share if we can, but under some circumstances we have to generate a new
+ * set.
+ *
+ * The new process gets the current process's subjective credentials as its
+ * objective and subjective credentials
+ */
+int copy_creds(struct task_struct *p, unsigned long clone_flags)
+{
+#ifdef CONFIG_KEYS
+	struct thread_group_cred *tgcred;
+#endif
+	struct cred *new;
+	int ret;
+
+	mutex_init(&p->cred_exec_mutex);
+
+	if (
+#ifdef CONFIG_KEYS
+		!p->cred->thread_keyring &&
+#endif
+		clone_flags & CLONE_THREAD
+	    ) {
+		p->real_cred = get_cred(p->cred);
+		get_cred(p->cred);
+		atomic_inc(&p->cred->user->processes);
+		return 0;
+	}
+
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+
+	if (clone_flags & CLONE_NEWUSER) {
+		ret = create_user_ns(new);
+		if (ret < 0)
+			goto error_put;
+	}
+
+#ifdef CONFIG_KEYS
+	/* new threads get their own thread keyrings if their parent already
+	 * had one */
+	if (new->thread_keyring) {
+		key_put(new->thread_keyring);
+		new->thread_keyring = NULL;
+		if (clone_flags & CLONE_THREAD)
+			install_thread_keyring_to_cred(new);
+	}
+
+	/* we share the process and session keyrings between all the threads in
+	 * a process - this is slightly icky as we violate COW credentials a
+	 * bit */
+	if (!(clone_flags & CLONE_THREAD)) {
+		tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
+		if (!tgcred) {
+			ret = -ENOMEM;
+			goto error_put;
+		}
+		atomic_set(&tgcred->usage, 1);
+		spin_lock_init(&tgcred->lock);
+		tgcred->process_keyring = NULL;
+		tgcred->session_keyring = key_get(new->tgcred->session_keyring);
+
+		release_tgcred(new);
+		new->tgcred = tgcred;
+	}
+#endif
+
+	atomic_inc(&new->user->processes);
+	p->cred = p->real_cred = get_cred(new);
+	return 0;
+
+error_put:
+	put_cred(new);
+	return ret;
+}
+
+/**
+ * commit_creds - Install new credentials upon the current task
+ * @new: The credentials to be assigned
+ *
+ * Install a new set of credentials to the current task, using RCU to replace
+ * the old set.  Both the objective and the subjective credentials pointers are
+ * updated.  This function may not be called if the subjective credentials are
+ * in an overridden state.
+ *
+ * This function eats the caller's reference to the new credentials.
+ *
+ * Always returns 0 thus allowing this function to be tail-called at the end
+ * of, say, sys_setgid().
+ */
+int commit_creds(struct cred *new)
+{
+	struct task_struct *task = current;
+	const struct cred *old;
+
+	BUG_ON(task->cred != task->real_cred);
+	BUG_ON(atomic_read(&task->real_cred->usage) < 2);
+	BUG_ON(atomic_read(&new->usage) < 1);
+
+	old = task->real_cred;
+	security_commit_creds(new, old);
+
+	get_cred(new); /* we will require a ref for the subj creds too */
+
+	/* dumpability changes */
+	if (old->euid != new->euid ||
+	    old->egid != new->egid ||
+	    old->fsuid != new->fsuid ||
+	    old->fsgid != new->fsgid ||
+	    !cap_issubset(new->cap_permitted, old->cap_permitted)) {
+		set_dumpable(task->mm, suid_dumpable);
+		task->pdeath_signal = 0;
+		smp_wmb();
+	}
+
+	/* alter the thread keyring */
+	if (new->fsuid != old->fsuid)
+		key_fsuid_changed(task);
+	if (new->fsgid != old->fsgid)
+		key_fsgid_changed(task);
+
+	/* do it
+	 * - What if a process setreuid()'s and this brings the
+	 *   new uid over his NPROC rlimit?  We can check this now
+	 *   cheaply with the new uid cache, so if it matters
+	 *   we should be checking for it.  -DaveM
+	 */
+	if (new->user != old->user)
+		atomic_inc(&new->user->processes);
+	rcu_assign_pointer(task->real_cred, new);
+	rcu_assign_pointer(task->cred, new);
+	if (new->user != old->user)
+		atomic_dec(&old->user->processes);
+
+	sched_switch_user(task);
+
+	/* send notifications */
+	if (new->uid   != old->uid  ||
+	    new->euid  != old->euid ||
+	    new->suid  != old->suid ||
+	    new->fsuid != old->fsuid)
+		proc_id_connector(task, PROC_EVENT_UID);
+
+	if (new->gid   != old->gid  ||
+	    new->egid  != old->egid ||
+	    new->sgid  != old->sgid ||
+	    new->fsgid != old->fsgid)
+		proc_id_connector(task, PROC_EVENT_GID);
+
+	/* release the old obj and subj refs both */
+	put_cred(old);
+	put_cred(old);
+	return 0;
+}
+EXPORT_SYMBOL(commit_creds);
+
+/**
+ * abort_creds - Discard a set of credentials and unlock the current task
+ * @new: The credentials that were going to be applied
+ *
+ * Discard a set of credentials that were under construction and unlock the
+ * current task.
+ */
+void abort_creds(struct cred *new)
+{
+	BUG_ON(atomic_read(&new->usage) < 1);
+	put_cred(new);
+}
+EXPORT_SYMBOL(abort_creds);
+
+/**
+ * override_creds - Override the current process's subjective credentials
+ * @new: The credentials to be assigned
+ *
+ * Install a set of temporary override subjective credentials on the current
+ * process, returning the old set for later reversion.
+ */
+const struct cred *override_creds(const struct cred *new)
+{
+	const struct cred *old = current->cred;
+
+	rcu_assign_pointer(current->cred, get_cred(new));
+	return old;
+}
+EXPORT_SYMBOL(override_creds);
+
+/**
+ * revert_creds - Revert a temporary subjective credentials override
+ * @old: The credentials to be restored
+ *
+ * Revert a temporary set of override subjective credentials to an old set,
+ * discarding the override set.
+ */
+void revert_creds(const struct cred *old)
+{
+	const struct cred *override = current->cred;
+
+	rcu_assign_pointer(current->cred, old);
+	put_cred(override);
+}
+EXPORT_SYMBOL(revert_creds);
+
+/*
+ * initialise the credentials stuff
+ */
+void __init cred_init(void)
+{
+	/* allocate a slab in which we can store credentials */
+	cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred),
+				     0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+}
+
+/**
+ * prepare_kernel_cred - Prepare a set of credentials for a kernel service
+ * @daemon: A userspace daemon to be used as a reference
+ *
+ * Prepare a set of credentials for a kernel service.  This can then be used to
+ * override a task's own credentials so that work can be done on behalf of that
+ * task that requires a different subjective context.
+ *
+ * @daemon is used to provide a base for the security record, but can be NULL.
+ * If @daemon is supplied, then the security data will be derived from that;
+ * otherwise they'll be set to 0 and no groups, full capabilities and no keys.
+ *
+ * The caller may change these controls afterwards if desired.
+ *
+ * Returns the new credentials or NULL if out of memory.
+ *
+ * Does not take, and does not return holding current->cred_replace_mutex.
+ */
+struct cred *prepare_kernel_cred(struct task_struct *daemon)
+{
+	const struct cred *old;
+	struct cred *new;
+
+	new = kmem_cache_alloc(cred_jar, GFP_KERNEL);
+	if (!new)
+		return NULL;
+
+	if (daemon)
+		old = get_task_cred(daemon);
+	else
+		old = get_cred(&init_cred);
+
+	get_uid(new->user);
+	get_group_info(new->group_info);
+
+#ifdef CONFIG_KEYS
+	atomic_inc(&init_tgcred.usage);
+	new->tgcred = &init_tgcred;
+	new->request_key_auth = NULL;
+	new->thread_keyring = NULL;
+	new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
+#endif
+
+#ifdef CONFIG_SECURITY
+	new->security = NULL;
+#endif
+	if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
+		goto error;
+
+	atomic_set(&new->usage, 1);
+	put_cred(old);
+	return new;
+
+error:
+	put_cred(new);
+	return NULL;
+}
+EXPORT_SYMBOL(prepare_kernel_cred);
+
+/**
+ * set_security_override - Set the security ID in a set of credentials
+ * @new: The credentials to alter
+ * @secid: The LSM security ID to set
+ *
+ * Set the LSM security ID in a set of credentials so that the subjective
+ * security is overridden when an alternative set of credentials is used.
+ */
+int set_security_override(struct cred *new, u32 secid)
+{
+	return security_kernel_act_as(new, secid);
+}
+EXPORT_SYMBOL(set_security_override);
+
+/**
+ * set_security_override_from_ctx - Set the security ID in a set of credentials
+ * @new: The credentials to alter
+ * @secctx: The LSM security context to generate the security ID from.
+ *
+ * Set the LSM security ID in a set of credentials so that the subjective
+ * security is overridden when an alternative set of credentials is used.  The
+ * security ID is specified in string form as a security context to be
+ * interpreted by the LSM.
+ */
+int set_security_override_from_ctx(struct cred *new, const char *secctx)
+{
+	u32 secid;
+	int ret;
+
+	ret = security_secctx_to_secid(secctx, strlen(secctx), &secid);
+	if (ret < 0)
+		return ret;
+
+	return set_security_override(new, secid);
+}
+EXPORT_SYMBOL(set_security_override_from_ctx);
+
+/**
+ * set_create_files_as - Set the LSM file create context in a set of credentials
+ * @new: The credentials to alter
+ * @inode: The inode to take the context from
+ *
+ * Change the LSM file creation context in a set of credentials to be the same
+ * as the object context of the specified inode, so that the new inodes have
+ * the same MAC context as that inode.
+ */
+int set_create_files_as(struct cred *new, struct inode *inode)
+{
+	new->fsuid = inode->i_uid;
+	new->fsgid = inode->i_gid;
+	return security_kernel_create_files_as(new, inode);
+}
+EXPORT_SYMBOL(set_create_files_as);
diff --git a/kernel/delayacct.c b/kernel/delayacct.c
index b3179da..abb6e17 100644
--- a/kernel/delayacct.c
+++ b/kernel/delayacct.c
@@ -127,7 +127,7 @@
 	 */
 	t1 = tsk->sched_info.pcount;
 	t2 = tsk->sched_info.run_delay;
-	t3 = tsk->sched_info.cpu_time;
+	t3 = tsk->se.sum_exec_runtime;
 
 	d->cpu_count += t1;
 
diff --git a/kernel/exit.c b/kernel/exit.c
index 2d8be7e..c7422ca 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -46,12 +46,18 @@
 #include <linux/blkdev.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/tracehook.h>
+#include <linux/init_task.h>
 #include <trace/sched.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
+#include "cred-internals.h"
+
+DEFINE_TRACE(sched_process_free);
+DEFINE_TRACE(sched_process_exit);
+DEFINE_TRACE(sched_process_wait);
 
 static void exit_mm(struct task_struct * tsk);
 
@@ -164,7 +170,10 @@
 	int zap_leader;
 repeat:
 	tracehook_prepare_release_task(p);
-	atomic_dec(&p->user->processes);
+	/* don't need to get the RCU readlock here - the process is dead and
+	 * can't be modifying its own credentials */
+	atomic_dec(&__task_cred(p)->user->processes);
+
 	proc_flush_task(p);
 	write_lock_irq(&tasklist_lock);
 	tracehook_finish_release_task(p);
@@ -339,12 +348,12 @@
 	/* cpus_allowed? */
 	/* rt_priority? */
 	/* signals? */
-	security_task_reparent_to_init(current);
 	memcpy(current->signal->rlim, init_task.signal->rlim,
 	       sizeof(current->signal->rlim));
-	atomic_inc(&(INIT_USER->__count));
+
+	atomic_inc(&init_cred.usage);
+	commit_creds(&init_cred);
 	write_unlock_irq(&tasklist_lock);
-	switch_uid(INIT_USER);
 }
 
 void __set_special_pids(struct pid *pid)
@@ -1078,7 +1087,6 @@
 	check_stack_usage();
 	exit_thread();
 	cgroup_exit(tsk, 1);
-	exit_keys(tsk);
 
 	if (group_dead && tsk->signal->leader)
 		disassociate_ctty(1);
@@ -1123,7 +1131,6 @@
 	preempt_disable();
 	/* causes final put_task_struct in finish_task_switch(). */
 	tsk->state = TASK_DEAD;
-
 	schedule();
 	BUG();
 	/* Avoid "noreturn function does return".  */
@@ -1263,12 +1270,12 @@
 	unsigned long state;
 	int retval, status, traced;
 	pid_t pid = task_pid_vnr(p);
+	uid_t uid = __task_cred(p)->uid;
 
 	if (!likely(options & WEXITED))
 		return 0;
 
 	if (unlikely(options & WNOWAIT)) {
-		uid_t uid = p->uid;
 		int exit_code = p->exit_code;
 		int why, status;
 
@@ -1389,7 +1396,7 @@
 	if (!retval && infop)
 		retval = put_user(pid, &infop->si_pid);
 	if (!retval && infop)
-		retval = put_user(p->uid, &infop->si_uid);
+		retval = put_user(uid, &infop->si_uid);
 	if (!retval)
 		retval = pid;
 
@@ -1454,7 +1461,8 @@
 	if (!unlikely(options & WNOWAIT))
 		p->exit_code = 0;
 
-	uid = p->uid;
+	/* don't need the RCU readlock here as we're holding a spinlock */
+	uid = __task_cred(p)->uid;
 unlock_sig:
 	spin_unlock_irq(&p->sighand->siglock);
 	if (!exit_code)
@@ -1528,10 +1536,10 @@
 	}
 	if (!unlikely(options & WNOWAIT))
 		p->signal->flags &= ~SIGNAL_STOP_CONTINUED;
+	uid = __task_cred(p)->uid;
 	spin_unlock_irq(&p->sighand->siglock);
 
 	pid = task_pid_vnr(p);
-	uid = p->uid;
 	get_task_struct(p);
 	read_unlock(&tasklist_lock);
 
diff --git a/kernel/extable.c b/kernel/extable.c
index a26cb2e..feb0317 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -17,6 +17,7 @@
 */
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/ftrace.h>
 #include <asm/uaccess.h>
 #include <asm/sections.h>
 
@@ -40,7 +41,7 @@
 	return e;
 }
 
-int core_kernel_text(unsigned long addr)
+__notrace_funcgraph int core_kernel_text(unsigned long addr)
 {
 	if (addr >= (unsigned long)_stext &&
 	    addr <= (unsigned long)_etext)
@@ -53,7 +54,7 @@
 	return 0;
 }
 
-int __kernel_text_address(unsigned long addr)
+__notrace_funcgraph int __kernel_text_address(unsigned long addr)
 {
 	if (core_kernel_text(addr))
 		return 1;
diff --git a/kernel/fork.c b/kernel/fork.c
index 495da2e..6144b36 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -47,6 +47,7 @@
 #include <linux/mount.h>
 #include <linux/audit.h>
 #include <linux/memcontrol.h>
+#include <linux/ftrace.h>
 #include <linux/profile.h>
 #include <linux/rmap.h>
 #include <linux/acct.h>
@@ -80,6 +81,8 @@
 
 __cacheline_aligned DEFINE_RWLOCK(tasklist_lock);  /* outer */
 
+DEFINE_TRACE(sched_process_fork);
+
 int nr_processes(void)
 {
 	int cpu;
@@ -137,6 +140,7 @@
 	prop_local_destroy_single(&tsk->dirties);
 	free_thread_info(tsk->stack);
 	rt_mutex_debug_task_free(tsk);
+	ftrace_graph_exit_task(tsk);
 	free_task_struct(tsk);
 }
 EXPORT_SYMBOL(free_task);
@@ -147,9 +151,8 @@
 	WARN_ON(atomic_read(&tsk->usage));
 	WARN_ON(tsk == current);
 
-	security_task_free(tsk);
-	free_uid(tsk->user);
-	put_group_info(tsk->group_info);
+	put_cred(tsk->real_cred);
+	put_cred(tsk->cred);
 	delayacct_tsk_free(tsk);
 
 	if (!profile_handoff_task(tsk))
@@ -818,12 +821,6 @@
 	if (!sig)
 		return -ENOMEM;
 
-	ret = copy_thread_group_keys(tsk);
-	if (ret < 0) {
-		kmem_cache_free(signal_cachep, sig);
-		return ret;
-	}
-
 	atomic_set(&sig->count, 1);
 	atomic_set(&sig->live, 1);
 	init_waitqueue_head(&sig->wait_chldexit);
@@ -868,7 +865,6 @@
 void __cleanup_signal(struct signal_struct *sig)
 {
 	thread_group_cputime_free(sig);
-	exit_thread_group_keys(sig);
 	tty_kref_put(sig->tty);
 	kmem_cache_free(signal_cachep, sig);
 }
@@ -984,16 +980,16 @@
 	DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
 #endif
 	retval = -EAGAIN;
-	if (atomic_read(&p->user->processes) >=
+	if (atomic_read(&p->real_cred->user->processes) >=
 			p->signal->rlim[RLIMIT_NPROC].rlim_cur) {
 		if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
-		    p->user != current->nsproxy->user_ns->root_user)
+		    p->real_cred->user != INIT_USER)
 			goto bad_fork_free;
 	}
 
-	atomic_inc(&p->user->__count);
-	atomic_inc(&p->user->processes);
-	get_group_info(p->group_info);
+	retval = copy_creds(p, clone_flags);
+	if (retval < 0)
+		goto bad_fork_free;
 
 	/*
 	 * If multiple threads are within copy_process(), then this check
@@ -1048,10 +1044,6 @@
 	do_posix_clock_monotonic_gettime(&p->start_time);
 	p->real_start_time = p->start_time;
 	monotonic_to_bootbased(&p->real_start_time);
-#ifdef CONFIG_SECURITY
-	p->security = NULL;
-#endif
-	p->cap_bset = current->cap_bset;
 	p->io_context = NULL;
 	p->audit_context = NULL;
 	cgroup_fork(p);
@@ -1092,14 +1084,14 @@
 #ifdef CONFIG_DEBUG_MUTEXES
 	p->blocked_on = NULL; /* not blocked yet */
 #endif
+	if (unlikely(ptrace_reparented(current)))
+		ptrace_fork(p, clone_flags);
 
 	/* Perform scheduler related setup. Assign this task to a CPU. */
 	sched_fork(p, clone_flags);
 
-	if ((retval = security_task_alloc(p)))
-		goto bad_fork_cleanup_policy;
 	if ((retval = audit_alloc(p)))
-		goto bad_fork_cleanup_security;
+		goto bad_fork_cleanup_policy;
 	/* copy all the process information */
 	if ((retval = copy_semundo(clone_flags, p)))
 		goto bad_fork_cleanup_audit;
@@ -1113,10 +1105,8 @@
 		goto bad_fork_cleanup_sighand;
 	if ((retval = copy_mm(clone_flags, p)))
 		goto bad_fork_cleanup_signal;
-	if ((retval = copy_keys(clone_flags, p)))
-		goto bad_fork_cleanup_mm;
 	if ((retval = copy_namespaces(clone_flags, p)))
-		goto bad_fork_cleanup_keys;
+		goto bad_fork_cleanup_mm;
 	if ((retval = copy_io(clone_flags, p)))
 		goto bad_fork_cleanup_namespaces;
 	retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
@@ -1136,6 +1126,8 @@
 		}
 	}
 
+	ftrace_graph_init_task(p);
+
 	p->pid = pid_nr(pid);
 	p->tgid = p->pid;
 	if (clone_flags & CLONE_THREAD)
@@ -1144,7 +1136,7 @@
 	if (current->nsproxy != p->nsproxy) {
 		retval = ns_cgroup_clone(p, pid);
 		if (retval)
-			goto bad_fork_free_pid;
+			goto bad_fork_free_graph;
 	}
 
 	p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
@@ -1237,7 +1229,7 @@
 		spin_unlock(&current->sighand->siglock);
 		write_unlock_irq(&tasklist_lock);
 		retval = -ERESTARTNOINTR;
-		goto bad_fork_free_pid;
+		goto bad_fork_free_graph;
 	}
 
 	if (clone_flags & CLONE_THREAD) {
@@ -1274,6 +1266,8 @@
 	cgroup_post_fork(p);
 	return p;
 
+bad_fork_free_graph:
+	ftrace_graph_exit_task(p);
 bad_fork_free_pid:
 	if (pid != &init_struct_pid)
 		free_pid(pid);
@@ -1281,8 +1275,6 @@
 	put_io_context(p->io_context);
 bad_fork_cleanup_namespaces:
 	exit_task_namespaces(p);
-bad_fork_cleanup_keys:
-	exit_keys(p);
 bad_fork_cleanup_mm:
 	if (p->mm)
 		mmput(p->mm);
@@ -1298,8 +1290,6 @@
 	exit_sem(p);
 bad_fork_cleanup_audit:
 	audit_free(p);
-bad_fork_cleanup_security:
-	security_task_free(p);
 bad_fork_cleanup_policy:
 #ifdef CONFIG_NUMA
 	mpol_put(p->mempolicy);
@@ -1312,9 +1302,9 @@
 bad_fork_cleanup_put_domain:
 	module_put(task_thread_info(p)->exec_domain->module);
 bad_fork_cleanup_count:
-	put_group_info(p->group_info);
-	atomic_dec(&p->user->processes);
-	free_uid(p->user);
+	atomic_dec(&p->cred->user->processes);
+	put_cred(p->real_cred);
+	put_cred(p->cred);
 bad_fork_free:
 	free_task(p);
 fork_out:
@@ -1358,6 +1348,21 @@
 	long nr;
 
 	/*
+	 * Do some preliminary argument and permissions checking before we
+	 * actually start allocating stuff
+	 */
+	if (clone_flags & CLONE_NEWUSER) {
+		if (clone_flags & CLONE_THREAD)
+			return -EINVAL;
+		/* hopefully this check will go away when userns support is
+		 * complete
+		 */
+		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) ||
+				!capable(CAP_SETGID))
+			return -EPERM;
+	}
+
+	/*
 	 * We hope to recycle these flags after 2.6.26
 	 */
 	if (unlikely(clone_flags & CLONE_STOPPED)) {
@@ -1605,8 +1610,7 @@
 	err = -EINVAL;
 	if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
 				CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
-				CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER|
-				CLONE_NEWNET))
+				CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET))
 		goto bad_unshare_out;
 
 	/*
diff --git a/kernel/futex.c b/kernel/futex.c
index 8af1002..4fe790e 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -439,13 +439,20 @@
 static struct task_struct * futex_find_get_task(pid_t pid)
 {
 	struct task_struct *p;
+	const struct cred *cred = current_cred(), *pcred;
 
 	rcu_read_lock();
 	p = find_task_by_vpid(pid);
-	if (!p || ((current->euid != p->euid) && (current->euid != p->uid)))
+	if (!p) {
 		p = ERR_PTR(-ESRCH);
-	else
-		get_task_struct(p);
+	} else {
+		pcred = __task_cred(p);
+		if (cred->euid != pcred->euid &&
+		    cred->euid != pcred->uid)
+			p = ERR_PTR(-ESRCH);
+		else
+			get_task_struct(p);
+	}
 
 	rcu_read_unlock();
 
@@ -1829,6 +1836,7 @@
 {
 	struct robust_list_head __user *head;
 	unsigned long ret;
+	const struct cred *cred = current_cred(), *pcred;
 
 	if (!futex_cmpxchg_enabled)
 		return -ENOSYS;
@@ -1844,8 +1852,10 @@
 		if (!p)
 			goto err_unlock;
 		ret = -EPERM;
-		if ((current->euid != p->euid) && (current->euid != p->uid) &&
-				!capable(CAP_SYS_PTRACE))
+		pcred = __task_cred(p);
+		if (cred->euid != pcred->euid &&
+		    cred->euid != pcred->uid &&
+		    !capable(CAP_SYS_PTRACE))
 			goto err_unlock;
 		head = p->robust_list;
 		rcu_read_unlock();
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index 04ac3a9..d607a5b 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -135,6 +135,7 @@
 {
 	struct compat_robust_list_head __user *head;
 	unsigned long ret;
+	const struct cred *cred = current_cred(), *pcred;
 
 	if (!futex_cmpxchg_enabled)
 		return -ENOSYS;
@@ -150,8 +151,10 @@
 		if (!p)
 			goto err_unlock;
 		ret = -EPERM;
-		if ((current->euid != p->euid) && (current->euid != p->uid) &&
-				!capable(CAP_SYS_PTRACE))
+		pcred = __task_cred(p);
+		if (cred->euid != pcred->euid &&
+		    cred->euid != pcred->uid &&
+		    !capable(CAP_SYS_PTRACE))
 			goto err_unlock;
 		head = p->compat_robust_list;
 		read_unlock(&tasklist_lock);
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 7b8b0f2..e694afa 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -30,20 +30,19 @@
 #define all_var 0
 #endif
 
-/* These will be re-linked against their real values during the second link stage */
-extern const unsigned long kallsyms_addresses[] __attribute__((weak));
-extern const u8 kallsyms_names[] __attribute__((weak));
+extern const unsigned long kallsyms_addresses[];
+extern const u8 kallsyms_names[];
 
 /* tell the compiler that the count isn't in the small data section if the arch
  * has one (eg: FRV)
  */
 extern const unsigned long kallsyms_num_syms
-__attribute__((weak, section(".rodata")));
+	__attribute__((__section__(".rodata")));
 
-extern const u8 kallsyms_token_table[] __attribute__((weak));
-extern const u16 kallsyms_token_index[] __attribute__((weak));
+extern const u8 kallsyms_token_table[];
+extern const u16 kallsyms_token_index[];
 
-extern const unsigned long kallsyms_markers[] __attribute__((weak));
+extern const unsigned long kallsyms_markers[];
 
 static inline int is_kernel_inittext(unsigned long addr)
 {
@@ -168,9 +167,6 @@
 	unsigned long symbol_start = 0, symbol_end = 0;
 	unsigned long i, low, high, mid;
 
-	/* This kernel should never had been booted. */
-	BUG_ON(!kallsyms_addresses);
-
 	/* do a binary search on the sorted kallsyms_addresses array */
 	low = 0;
 	high = kallsyms_num_syms;
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 3d3c3ea..b46dbb9 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -118,10 +118,10 @@
 struct subprocess_info {
 	struct work_struct work;
 	struct completion *complete;
+	struct cred *cred;
 	char *path;
 	char **argv;
 	char **envp;
-	struct key *ring;
 	enum umh_wait wait;
 	int retval;
 	struct file *stdin;
@@ -134,19 +134,20 @@
 static int ____call_usermodehelper(void *data)
 {
 	struct subprocess_info *sub_info = data;
-	struct key *new_session, *old_session;
 	int retval;
 
-	/* Unblock all signals and set the session keyring. */
-	new_session = key_get(sub_info->ring);
+	BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
+
+	/* Unblock all signals */
 	spin_lock_irq(&current->sighand->siglock);
-	old_session = __install_session_keyring(current, new_session);
 	flush_signal_handlers(current, 1);
 	sigemptyset(&current->blocked);
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	key_put(old_session);
+	/* Install the credentials */
+	commit_creds(sub_info->cred);
+	sub_info->cred = NULL;
 
 	/* Install input pipe when needed */
 	if (sub_info->stdin) {
@@ -185,6 +186,8 @@
 {
 	if (info->cleanup)
 		(*info->cleanup)(info->argv, info->envp);
+	if (info->cred)
+		put_cred(info->cred);
 	kfree(info);
 }
 EXPORT_SYMBOL(call_usermodehelper_freeinfo);
@@ -240,6 +243,8 @@
 	pid_t pid;
 	enum umh_wait wait = sub_info->wait;
 
+	BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
+
 	/* CLONE_VFORK: wait until the usermode helper has execve'd
 	 * successfully We need the data structures to stay around
 	 * until that is done.  */
@@ -362,6 +367,9 @@
 	sub_info->path = path;
 	sub_info->argv = argv;
 	sub_info->envp = envp;
+	sub_info->cred = prepare_usermodehelper_creds();
+	if (!sub_info->cred)
+		return NULL;
 
   out:
 	return sub_info;
@@ -376,7 +384,13 @@
 void call_usermodehelper_setkeys(struct subprocess_info *info,
 				 struct key *session_keyring)
 {
-	info->ring = session_keyring;
+#ifdef CONFIG_KEYS
+	struct thread_group_cred *tgcred = info->cred->tgcred;
+	key_put(tgcred->session_keyring);
+	tgcred->session_keyring = key_get(session_keyring);
+#else
+	BUG();
+#endif
 }
 EXPORT_SYMBOL(call_usermodehelper_setkeys);
 
@@ -444,6 +458,8 @@
 	DECLARE_COMPLETION_ONSTACK(done);
 	int retval = 0;
 
+	BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
+
 	helper_lock();
 	if (sub_info->path[0] == '\0')
 		goto out;
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 8e7a7ce..4fbc456 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -21,6 +21,9 @@
 static LIST_HEAD(kthread_create_list);
 struct task_struct *kthreadd_task;
 
+DEFINE_TRACE(sched_kthread_stop);
+DEFINE_TRACE(sched_kthread_stop_ret);
+
 struct kthread_create_info
 {
 	/* Information passed to kthread() from kthreadd. */
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 46a4041..74b1878 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -25,6 +25,7 @@
  * Thanks to Arjan van de Ven for coming up with the initial idea of
  * mapping lock dependencies runtime.
  */
+#define DISABLE_BRANCH_PROFILING
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
diff --git a/kernel/marker.c b/kernel/marker.c
index e9c6b2b..ea54f26 100644
--- a/kernel/marker.c
+++ b/kernel/marker.c
@@ -43,6 +43,7 @@
  */
 #define MARKER_HASH_BITS 6
 #define MARKER_TABLE_SIZE (1 << MARKER_HASH_BITS)
+static struct hlist_head marker_table[MARKER_TABLE_SIZE];
 
 /*
  * Note about RCU :
@@ -64,11 +65,10 @@
 	void *oldptr;
 	int rcu_pending;
 	unsigned char ptype:1;
+	unsigned char format_allocated:1;
 	char name[0];	/* Contains name'\0'format'\0' */
 };
 
-static struct hlist_head marker_table[MARKER_TABLE_SIZE];
-
 /**
  * __mark_empty_function - Empty probe callback
  * @probe_private: probe private data
@@ -81,7 +81,7 @@
  * though the function pointer change and the marker enabling are two distinct
  * operations that modifies the execution flow of preemptible code.
  */
-void __mark_empty_function(void *probe_private, void *call_private,
+notrace void __mark_empty_function(void *probe_private, void *call_private,
 	const char *fmt, va_list *args)
 {
 }
@@ -97,7 +97,8 @@
  * need to put a full smp_rmb() in this branch. This is why we do not use
  * rcu_dereference() for the pointer read.
  */
-void marker_probe_cb(const struct marker *mdata, void *call_private, ...)
+notrace void marker_probe_cb(const struct marker *mdata,
+		void *call_private, ...)
 {
 	va_list args;
 	char ptype;
@@ -107,7 +108,7 @@
 	 * sure the teardown of the callbacks can be done correctly when they
 	 * are in modules and they insure RCU read coherency.
 	 */
-	rcu_read_lock_sched();
+	rcu_read_lock_sched_notrace();
 	ptype = mdata->ptype;
 	if (likely(!ptype)) {
 		marker_probe_func *func;
@@ -145,7 +146,7 @@
 			va_end(args);
 		}
 	}
-	rcu_read_unlock_sched();
+	rcu_read_unlock_sched_notrace();
 }
 EXPORT_SYMBOL_GPL(marker_probe_cb);
 
@@ -157,12 +158,13 @@
  *
  * Should be connected to markers "MARK_NOARGS".
  */
-void marker_probe_cb_noarg(const struct marker *mdata, void *call_private, ...)
+static notrace void marker_probe_cb_noarg(const struct marker *mdata,
+		void *call_private, ...)
 {
 	va_list args;	/* not initialized */
 	char ptype;
 
-	rcu_read_lock_sched();
+	rcu_read_lock_sched_notrace();
 	ptype = mdata->ptype;
 	if (likely(!ptype)) {
 		marker_probe_func *func;
@@ -195,9 +197,8 @@
 			multi[i].func(multi[i].probe_private, call_private,
 				mdata->format, &args);
 	}
-	rcu_read_unlock_sched();
+	rcu_read_unlock_sched_notrace();
 }
-EXPORT_SYMBOL_GPL(marker_probe_cb_noarg);
 
 static void free_old_closure(struct rcu_head *head)
 {
@@ -416,6 +417,7 @@
 	e->single.probe_private = NULL;
 	e->multi = NULL;
 	e->ptype = 0;
+	e->format_allocated = 0;
 	e->refcount = 0;
 	e->rcu_pending = 0;
 	hlist_add_head(&e->hlist, head);
@@ -447,6 +449,8 @@
 	if (e->single.func != __mark_empty_function)
 		return -EBUSY;
 	hlist_del(&e->hlist);
+	if (e->format_allocated)
+		kfree(e->format);
 	/* Make sure the call_rcu has been executed */
 	if (e->rcu_pending)
 		rcu_barrier_sched();
@@ -457,57 +461,34 @@
 /*
  * Set the mark_entry format to the format found in the element.
  */
-static int marker_set_format(struct marker_entry **entry, const char *format)
+static int marker_set_format(struct marker_entry *entry, const char *format)
 {
-	struct marker_entry *e;
-	size_t name_len = strlen((*entry)->name) + 1;
-	size_t format_len = strlen(format) + 1;
-
-
-	e = kmalloc(sizeof(struct marker_entry) + name_len + format_len,
-			GFP_KERNEL);
-	if (!e)
+	entry->format = kstrdup(format, GFP_KERNEL);
+	if (!entry->format)
 		return -ENOMEM;
-	memcpy(&e->name[0], (*entry)->name, name_len);
-	e->format = &e->name[name_len];
-	memcpy(e->format, format, format_len);
-	if (strcmp(e->format, MARK_NOARGS) == 0)
-		e->call = marker_probe_cb_noarg;
-	else
-		e->call = marker_probe_cb;
-	e->single = (*entry)->single;
-	e->multi = (*entry)->multi;
-	e->ptype = (*entry)->ptype;
-	e->refcount = (*entry)->refcount;
-	e->rcu_pending = 0;
-	hlist_add_before(&e->hlist, &(*entry)->hlist);
-	hlist_del(&(*entry)->hlist);
-	/* Make sure the call_rcu has been executed */
-	if ((*entry)->rcu_pending)
-		rcu_barrier_sched();
-	kfree(*entry);
-	*entry = e;
+	entry->format_allocated = 1;
+
 	trace_mark(core_marker_format, "name %s format %s",
-			e->name, e->format);
+			entry->name, entry->format);
 	return 0;
 }
 
 /*
  * Sets the probe callback corresponding to one marker.
  */
-static int set_marker(struct marker_entry **entry, struct marker *elem,
+static int set_marker(struct marker_entry *entry, struct marker *elem,
 		int active)
 {
-	int ret;
-	WARN_ON(strcmp((*entry)->name, elem->name) != 0);
+	int ret = 0;
+	WARN_ON(strcmp(entry->name, elem->name) != 0);
 
-	if ((*entry)->format) {
-		if (strcmp((*entry)->format, elem->format) != 0) {
+	if (entry->format) {
+		if (strcmp(entry->format, elem->format) != 0) {
 			printk(KERN_NOTICE
 				"Format mismatch for probe %s "
 				"(%s), marker (%s)\n",
-				(*entry)->name,
-				(*entry)->format,
+				entry->name,
+				entry->format,
 				elem->format);
 			return -EPERM;
 		}
@@ -523,37 +504,67 @@
 	 * pass from a "safe" callback (with argument) to an "unsafe"
 	 * callback (does not set arguments).
 	 */
-	elem->call = (*entry)->call;
+	elem->call = entry->call;
 	/*
 	 * Sanity check :
 	 * We only update the single probe private data when the ptr is
 	 * set to a _non_ single probe! (0 -> 1 and N -> 1, N != 1)
 	 */
 	WARN_ON(elem->single.func != __mark_empty_function
-		&& elem->single.probe_private
-		!= (*entry)->single.probe_private &&
-		!elem->ptype);
-	elem->single.probe_private = (*entry)->single.probe_private;
+		&& elem->single.probe_private != entry->single.probe_private
+		&& !elem->ptype);
+	elem->single.probe_private = entry->single.probe_private;
 	/*
 	 * Make sure the private data is valid when we update the
 	 * single probe ptr.
 	 */
 	smp_wmb();
-	elem->single.func = (*entry)->single.func;
+	elem->single.func = entry->single.func;
 	/*
 	 * We also make sure that the new probe callbacks array is consistent
 	 * before setting a pointer to it.
 	 */
-	rcu_assign_pointer(elem->multi, (*entry)->multi);
+	rcu_assign_pointer(elem->multi, entry->multi);
 	/*
 	 * Update the function or multi probe array pointer before setting the
 	 * ptype.
 	 */
 	smp_wmb();
-	elem->ptype = (*entry)->ptype;
+	elem->ptype = entry->ptype;
+
+	if (elem->tp_name && (active ^ elem->state)) {
+		WARN_ON(!elem->tp_cb);
+		/*
+		 * It is ok to directly call the probe registration because type
+		 * checking has been done in the __trace_mark_tp() macro.
+		 */
+
+		if (active) {
+			/*
+			 * try_module_get should always succeed because we hold
+			 * lock_module() to get the tp_cb address.
+			 */
+			ret = try_module_get(__module_text_address(
+				(unsigned long)elem->tp_cb));
+			BUG_ON(!ret);
+			ret = tracepoint_probe_register_noupdate(
+				elem->tp_name,
+				elem->tp_cb);
+		} else {
+			ret = tracepoint_probe_unregister_noupdate(
+				elem->tp_name,
+				elem->tp_cb);
+			/*
+			 * tracepoint_probe_update_all() must be called
+			 * before the module containing tp_cb is unloaded.
+			 */
+			module_put(__module_text_address(
+				(unsigned long)elem->tp_cb));
+		}
+	}
 	elem->state = active;
 
-	return 0;
+	return ret;
 }
 
 /*
@@ -564,7 +575,24 @@
  */
 static void disable_marker(struct marker *elem)
 {
+	int ret;
+
 	/* leave "call" as is. It is known statically. */
+	if (elem->tp_name && elem->state) {
+		WARN_ON(!elem->tp_cb);
+		/*
+		 * It is ok to directly call the probe registration because type
+		 * checking has been done in the __trace_mark_tp() macro.
+		 */
+		ret = tracepoint_probe_unregister_noupdate(elem->tp_name,
+			elem->tp_cb);
+		WARN_ON(ret);
+		/*
+		 * tracepoint_probe_update_all() must be called
+		 * before the module containing tp_cb is unloaded.
+		 */
+		module_put(__module_text_address((unsigned long)elem->tp_cb));
+	}
 	elem->state = 0;
 	elem->single.func = __mark_empty_function;
 	/* Update the function before setting the ptype */
@@ -594,8 +622,7 @@
 	for (iter = begin; iter < end; iter++) {
 		mark_entry = get_marker(iter->name);
 		if (mark_entry) {
-			set_marker(&mark_entry, iter,
-					!!mark_entry->refcount);
+			set_marker(mark_entry, iter, !!mark_entry->refcount);
 			/*
 			 * ignore error, continue
 			 */
@@ -629,6 +656,7 @@
 	marker_update_probe_range(__start___markers, __stop___markers);
 	/* Markers in modules. */
 	module_update_markers();
+	tracepoint_probe_update_all();
 }
 
 /**
@@ -657,7 +685,7 @@
 			ret = PTR_ERR(entry);
 	} else if (format) {
 		if (!entry->format)
-			ret = marker_set_format(&entry, format);
+			ret = marker_set_format(entry, format);
 		else if (strcmp(entry->format, format))
 			ret = -EPERM;
 	}
@@ -676,10 +704,11 @@
 		goto end;
 	}
 	mutex_unlock(&markers_mutex);
-	marker_update_probes();		/* may update entry */
+	marker_update_probes();
 	mutex_lock(&markers_mutex);
 	entry = get_marker(name);
-	WARN_ON(!entry);
+	if (!entry)
+		goto end;
 	if (entry->rcu_pending)
 		rcu_barrier_sched();
 	entry->oldptr = old;
@@ -720,7 +749,7 @@
 		rcu_barrier_sched();
 	old = marker_entry_remove_probe(entry, probe, probe_private);
 	mutex_unlock(&markers_mutex);
-	marker_update_probes();		/* may update entry */
+	marker_update_probes();
 	mutex_lock(&markers_mutex);
 	entry = get_marker(name);
 	if (!entry)
@@ -801,10 +830,11 @@
 		rcu_barrier_sched();
 	old = marker_entry_remove_probe(entry, NULL, probe_private);
 	mutex_unlock(&markers_mutex);
-	marker_update_probes();		/* may update entry */
+	marker_update_probes();
 	mutex_lock(&markers_mutex);
 	entry = get_marker_from_private_data(probe, probe_private);
-	WARN_ON(!entry);
+	if (!entry)
+		goto end;
 	if (entry->rcu_pending)
 		rcu_barrier_sched();
 	entry->oldptr = old;
@@ -848,8 +878,6 @@
 			if (!e->ptype) {
 				if (num == 0 && e->single.func == probe)
 					return e->single.probe_private;
-				else
-					break;
 			} else {
 				struct marker_probe_closure *closure;
 				int match = 0;
@@ -861,8 +889,42 @@
 						return closure[i].probe_private;
 				}
 			}
+			break;
 		}
 	}
 	return ERR_PTR(-ENOENT);
 }
 EXPORT_SYMBOL_GPL(marker_get_private_data);
+
+#ifdef CONFIG_MODULES
+
+int marker_module_notify(struct notifier_block *self,
+			 unsigned long val, void *data)
+{
+	struct module *mod = data;
+
+	switch (val) {
+	case MODULE_STATE_COMING:
+		marker_update_probe_range(mod->markers,
+			mod->markers + mod->num_markers);
+		break;
+	case MODULE_STATE_GOING:
+		marker_update_probe_range(mod->markers,
+			mod->markers + mod->num_markers);
+		break;
+	}
+	return 0;
+}
+
+struct notifier_block marker_module_nb = {
+	.notifier_call = marker_module_notify,
+	.priority = 0,
+};
+
+static int init_markers(void)
+{
+	return register_module_notifier(&marker_module_nb);
+}
+__initcall(init_markers);
+
+#endif /* CONFIG_MODULES */
diff --git a/kernel/module.c b/kernel/module.c
index 1f4cc00..dd2a541 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2184,24 +2184,15 @@
 		struct mod_debug *debug;
 		unsigned int num_debug;
 
-#ifdef CONFIG_MARKERS
-		marker_update_probe_range(mod->markers,
-			mod->markers + mod->num_markers);
-#endif
 		debug = section_objs(hdr, sechdrs, secstrings, "__verbose",
 				     sizeof(*debug), &num_debug);
 		dynamic_printk_setup(debug, num_debug);
-
-#ifdef CONFIG_TRACEPOINTS
-		tracepoint_update_probe_range(mod->tracepoints,
-			mod->tracepoints + mod->num_tracepoints);
-#endif
 	}
 
 	/* sechdrs[0].sh_size is always zero */
 	mseg = section_objs(hdr, sechdrs, secstrings, "__mcount_loc",
 			    sizeof(*mseg), &num_mcount);
-	ftrace_init_module(mseg, mseg + num_mcount);
+	ftrace_init_module(mod, mseg, mseg + num_mcount);
 
 	err = module_finalize(hdr, sechdrs, mod);
 	if (err < 0)
@@ -2713,7 +2704,7 @@
 
 
 /* Is this a valid kernel address? */
-struct module *__module_text_address(unsigned long addr)
+__notrace_funcgraph struct module *__module_text_address(unsigned long addr)
 {
 	struct module *mod;
 
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index 1d3ef29..63598dc 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -80,12 +80,6 @@
 		goto out_pid;
 	}
 
-	new_nsp->user_ns = copy_user_ns(flags, tsk->nsproxy->user_ns);
-	if (IS_ERR(new_nsp->user_ns)) {
-		err = PTR_ERR(new_nsp->user_ns);
-		goto out_user;
-	}
-
 	new_nsp->net_ns = copy_net_ns(flags, tsk->nsproxy->net_ns);
 	if (IS_ERR(new_nsp->net_ns)) {
 		err = PTR_ERR(new_nsp->net_ns);
@@ -95,9 +89,6 @@
 	return new_nsp;
 
 out_net:
-	if (new_nsp->user_ns)
-		put_user_ns(new_nsp->user_ns);
-out_user:
 	if (new_nsp->pid_ns)
 		put_pid_ns(new_nsp->pid_ns);
 out_pid:
@@ -130,7 +121,7 @@
 	get_nsproxy(old_ns);
 
 	if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-				CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET)))
+				CLONE_NEWPID | CLONE_NEWNET)))
 		return 0;
 
 	if (!capable(CAP_SYS_ADMIN)) {
@@ -173,8 +164,6 @@
 		put_ipc_ns(ns->ipc_ns);
 	if (ns->pid_ns)
 		put_pid_ns(ns->pid_ns);
-	if (ns->user_ns)
-		put_user_ns(ns->user_ns);
 	put_net(ns->net_ns);
 	kmem_cache_free(nsproxy_cachep, ns);
 }
@@ -189,7 +178,7 @@
 	int err = 0;
 
 	if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-			       CLONE_NEWUSER | CLONE_NEWNET)))
+			       CLONE_NEWNET)))
 		return 0;
 
 	if (!capable(CAP_SYS_ADMIN))
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index c9d7408..f77d381 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -22,7 +22,6 @@
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/freezer.h>
-#include <linux/ftrace.h>
 
 #include "power.h"
 
@@ -257,7 +256,7 @@
 
 int hibernation_snapshot(int platform_mode)
 {
-	int error, ftrace_save;
+	int error;
 
 	/* Free memory before shutting down devices. */
 	error = swsusp_shrink_memory();
@@ -269,7 +268,6 @@
 		goto Close;
 
 	suspend_console();
-	ftrace_save = __ftrace_enabled_save();
 	error = device_suspend(PMSG_FREEZE);
 	if (error)
 		goto Recover_platform;
@@ -299,7 +297,6 @@
  Resume_devices:
 	device_resume(in_suspend ?
 		(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
-	__ftrace_enabled_restore(ftrace_save);
 	resume_console();
  Close:
 	platform_end(platform_mode);
@@ -370,11 +367,10 @@
 
 int hibernation_restore(int platform_mode)
 {
-	int error, ftrace_save;
+	int error;
 
 	pm_prepare_console();
 	suspend_console();
-	ftrace_save = __ftrace_enabled_save();
 	error = device_suspend(PMSG_QUIESCE);
 	if (error)
 		goto Finish;
@@ -389,7 +385,6 @@
 	platform_restore_cleanup(platform_mode);
 	device_resume(PMSG_RECOVER);
  Finish:
-	__ftrace_enabled_restore(ftrace_save);
 	resume_console();
 	pm_restore_console();
 	return error;
@@ -402,7 +397,7 @@
 
 int hibernation_platform_enter(void)
 {
-	int error, ftrace_save;
+	int error;
 
 	if (!hibernation_ops)
 		return -ENOSYS;
@@ -417,7 +412,6 @@
 		goto Close;
 
 	suspend_console();
-	ftrace_save = __ftrace_enabled_save();
 	error = device_suspend(PMSG_HIBERNATE);
 	if (error) {
 		if (hibernation_ops->recover)
@@ -452,7 +446,6 @@
 	hibernation_ops->finish();
  Resume_devices:
 	device_resume(PMSG_RESTORE);
-	__ftrace_enabled_restore(ftrace_save);
 	resume_console();
  Close:
 	hibernation_ops->end();
diff --git a/kernel/power/main.c b/kernel/power/main.c
index b8f7ce9..613f169 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -22,7 +22,6 @@
 #include <linux/freezer.h>
 #include <linux/vmstat.h>
 #include <linux/syscalls.h>
-#include <linux/ftrace.h>
 
 #include "power.h"
 
@@ -317,7 +316,7 @@
  */
 int suspend_devices_and_enter(suspend_state_t state)
 {
-	int error, ftrace_save;
+	int error;
 
 	if (!suspend_ops)
 		return -ENOSYS;
@@ -328,7 +327,6 @@
 			goto Close;
 	}
 	suspend_console();
-	ftrace_save = __ftrace_enabled_save();
 	suspend_test_start();
 	error = device_suspend(PMSG_SUSPEND);
 	if (error) {
@@ -360,7 +358,6 @@
 	suspend_test_start();
 	device_resume(PMSG_RESUME);
 	suspend_test_finish("resume devices");
-	__ftrace_enabled_restore(ftrace_save);
 	resume_console();
  Close:
 	if (suspend_ops->end)
diff --git a/kernel/profile.c b/kernel/profile.c
index dc41827..60adefb 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -544,7 +544,7 @@
 };
 
 #ifdef CONFIG_SMP
-static inline void profile_nop(void *unused)
+static void profile_nop(void *unused)
 {
 }
 
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 4c8bcd7..29dc700 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -25,6 +25,17 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
+
+/*
+ * Initialize a new task whose father had been ptraced.
+ *
+ * Called from copy_process().
+ */
+void ptrace_fork(struct task_struct *child, unsigned long clone_flags)
+{
+	arch_ptrace_fork(child, clone_flags);
+}
+
 /*
  * ptrace a task: make the debugger its new parent and
  * move it to the ptrace list.
@@ -72,6 +83,7 @@
 	child->parent = child->real_parent;
 	list_del_init(&child->ptrace_entry);
 
+	arch_ptrace_untrace(child);
 	if (task_is_traced(child))
 		ptrace_untrace(child);
 }
@@ -115,6 +127,8 @@
 
 int __ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
+	const struct cred *cred = current_cred(), *tcred;
+
 	/* May we inspect the given task?
 	 * This check is used both for attaching with ptrace
 	 * and for allowing access to sensitive information in /proc.
@@ -127,13 +141,19 @@
 	/* Don't let security modules deny introspection */
 	if (task == current)
 		return 0;
-	if (((current->uid != task->euid) ||
-	     (current->uid != task->suid) ||
-	     (current->uid != task->uid) ||
-	     (current->gid != task->egid) ||
-	     (current->gid != task->sgid) ||
-	     (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
+	rcu_read_lock();
+	tcred = __task_cred(task);
+	if ((cred->uid != tcred->euid ||
+	     cred->uid != tcred->suid ||
+	     cred->uid != tcred->uid  ||
+	     cred->gid != tcred->egid ||
+	     cred->gid != tcred->sgid ||
+	     cred->gid != tcred->gid) &&
+	    !capable(CAP_SYS_PTRACE)) {
+		rcu_read_unlock();
 		return -EPERM;
+	}
+	rcu_read_unlock();
 	smp_rmb();
 	if (task->mm)
 		dumpable = get_dumpable(task->mm);
@@ -163,6 +183,14 @@
 	if (same_thread_group(task, current))
 		goto out;
 
+	/* Protect exec's credential calculations against our interference;
+	 * SUID, SGID and LSM creds get determined differently under ptrace.
+	 */
+	retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+	if (retval  < 0)
+		goto out;
+
+	retval = -EPERM;
 repeat:
 	/*
 	 * Nasty, nasty.
@@ -202,6 +230,7 @@
 bad:
 	write_unlock_irqrestore(&tasklist_lock, flags);
 	task_unlock(task);
+	mutex_unlock(&current->cred_exec_mutex);
 out:
 	return retval;
 }
diff --git a/kernel/sched.c b/kernel/sched.c
index e4bb1dd..748ff92 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -118,6 +118,12 @@
  */
 #define RUNTIME_INF	((u64)~0ULL)
 
+DEFINE_TRACE(sched_wait_task);
+DEFINE_TRACE(sched_wakeup);
+DEFINE_TRACE(sched_wakeup_new);
+DEFINE_TRACE(sched_switch);
+DEFINE_TRACE(sched_migrate_task);
+
 #ifdef CONFIG_SMP
 /*
  * Divide a load by a sched group cpu_power : (load / sg->__cpu_power)
@@ -261,6 +267,10 @@
 	struct cgroup_subsys_state css;
 #endif
 
+#ifdef CONFIG_USER_SCHED
+	uid_t uid;
+#endif
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
 	/* schedulable entities of this group on each cpu */
 	struct sched_entity **se;
@@ -286,6 +296,12 @@
 
 #ifdef CONFIG_USER_SCHED
 
+/* Helper function to pass uid information to create_sched_user() */
+void set_tg_uid(struct user_struct *user)
+{
+	user->tg->uid = user->uid;
+}
+
 /*
  * Root task group.
  * 	Every UID task group (including init_task_group aka UID-0) will
@@ -345,7 +361,9 @@
 	struct task_group *tg;
 
 #ifdef CONFIG_USER_SCHED
-	tg = p->user->tg;
+	rcu_read_lock();
+	tg = __task_cred(p)->user->tg;
+	rcu_read_unlock();
 #elif defined(CONFIG_CGROUP_SCHED)
 	tg = container_of(task_subsys_state(p, cpu_cgroup_subsys_id),
 				struct task_group, css);
@@ -586,6 +604,8 @@
 #ifdef CONFIG_SCHEDSTATS
 	/* latency stats */
 	struct sched_info rq_sched_info;
+	unsigned long long rq_cpu_time;
+	/* could above be rq->cfs_rq.exec_clock + rq->rt_rq.rt_runtime ? */
 
 	/* sys_sched_yield() stats */
 	unsigned int yld_exp_empty;
@@ -703,45 +723,18 @@
 
 #undef SCHED_FEAT
 
-static int sched_feat_open(struct inode *inode, struct file *filp)
+static int sched_feat_show(struct seq_file *m, void *v)
 {
-	filp->private_data = inode->i_private;
-	return 0;
-}
-
-static ssize_t
-sched_feat_read(struct file *filp, char __user *ubuf,
-		size_t cnt, loff_t *ppos)
-{
-	char *buf;
-	int r = 0;
-	int len = 0;
 	int i;
 
 	for (i = 0; sched_feat_names[i]; i++) {
-		len += strlen(sched_feat_names[i]);
-		len += 4;
+		if (!(sysctl_sched_features & (1UL << i)))
+			seq_puts(m, "NO_");
+		seq_printf(m, "%s ", sched_feat_names[i]);
 	}
+	seq_puts(m, "\n");
 
-	buf = kmalloc(len + 2, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	for (i = 0; sched_feat_names[i]; i++) {
-		if (sysctl_sched_features & (1UL << i))
-			r += sprintf(buf + r, "%s ", sched_feat_names[i]);
-		else
-			r += sprintf(buf + r, "NO_%s ", sched_feat_names[i]);
-	}
-
-	r += sprintf(buf + r, "\n");
-	WARN_ON(r >= len + 2);
-
-	r = simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
-
-	kfree(buf);
-
-	return r;
+	return 0;
 }
 
 static ssize_t
@@ -786,10 +779,17 @@
 	return cnt;
 }
 
+static int sched_feat_open(struct inode *inode, struct file *filp)
+{
+	return single_open(filp, sched_feat_show, NULL);
+}
+
 static struct file_operations sched_feat_fops = {
-	.open	= sched_feat_open,
-	.read	= sched_feat_read,
-	.write	= sched_feat_write,
+	.open		= sched_feat_open,
+	.write		= sched_feat_write,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
 };
 
 static __init int sched_init_debug(void)
@@ -1474,27 +1474,13 @@
 update_group_shares_cpu(struct task_group *tg, int cpu,
 			unsigned long sd_shares, unsigned long sd_rq_weight)
 {
-	int boost = 0;
 	unsigned long shares;
 	unsigned long rq_weight;
 
 	if (!tg->se[cpu])
 		return;
 
-	rq_weight = tg->cfs_rq[cpu]->load.weight;
-
-	/*
-	 * If there are currently no tasks on the cpu pretend there is one of
-	 * average load so that when a new task gets to run here it will not
-	 * get delayed by group starvation.
-	 */
-	if (!rq_weight) {
-		boost = 1;
-		rq_weight = NICE_0_LOAD;
-	}
-
-	if (unlikely(rq_weight > sd_rq_weight))
-		rq_weight = sd_rq_weight;
+	rq_weight = tg->cfs_rq[cpu]->rq_weight;
 
 	/*
 	 *           \Sum shares * rq_weight
@@ -1502,7 +1488,7 @@
 	 *               \Sum rq_weight
 	 *
 	 */
-	shares = (sd_shares * rq_weight) / (sd_rq_weight + 1);
+	shares = (sd_shares * rq_weight) / sd_rq_weight;
 	shares = clamp_t(unsigned long, shares, MIN_SHARES, MAX_SHARES);
 
 	if (abs(shares - tg->se[cpu]->load.weight) >
@@ -1511,11 +1497,7 @@
 		unsigned long flags;
 
 		spin_lock_irqsave(&rq->lock, flags);
-		/*
-		 * record the actual number of shares, not the boosted amount.
-		 */
-		tg->cfs_rq[cpu]->shares = boost ? 0 : shares;
-		tg->cfs_rq[cpu]->rq_weight = rq_weight;
+		tg->cfs_rq[cpu]->shares = shares;
 
 		__set_se_shares(tg->se[cpu], shares);
 		spin_unlock_irqrestore(&rq->lock, flags);
@@ -1529,13 +1511,23 @@
  */
 static int tg_shares_up(struct task_group *tg, void *data)
 {
-	unsigned long rq_weight = 0;
+	unsigned long weight, rq_weight = 0;
 	unsigned long shares = 0;
 	struct sched_domain *sd = data;
 	int i;
 
 	for_each_cpu_mask(i, sd->span) {
-		rq_weight += tg->cfs_rq[i]->load.weight;
+		/*
+		 * If there are currently no tasks on the cpu pretend there
+		 * is one of average load so that when a new task gets to
+		 * run here it will not get delayed by group starvation.
+		 */
+		weight = tg->cfs_rq[i]->load.weight;
+		if (!weight)
+			weight = NICE_0_LOAD;
+
+		tg->cfs_rq[i]->rq_weight = weight;
+		rq_weight += weight;
 		shares += tg->cfs_rq[i]->shares;
 	}
 
@@ -1545,9 +1537,6 @@
 	if (!sd->parent || !(sd->parent->flags & SD_LOAD_BALANCE))
 		shares = tg->shares;
 
-	if (!rq_weight)
-		rq_weight = cpus_weight(sd->span) * NICE_0_LOAD;
-
 	for_each_cpu_mask(i, sd->span)
 		update_group_shares_cpu(tg, i, shares, rq_weight);
 
@@ -1612,6 +1601,39 @@
 
 #endif
 
+/*
+ * double_lock_balance - lock the busiest runqueue, this_rq is locked already.
+ */
+static int double_lock_balance(struct rq *this_rq, struct rq *busiest)
+	__releases(this_rq->lock)
+	__acquires(busiest->lock)
+	__acquires(this_rq->lock)
+{
+	int ret = 0;
+
+	if (unlikely(!irqs_disabled())) {
+		/* printk() doesn't work good under rq->lock */
+		spin_unlock(&this_rq->lock);
+		BUG_ON(1);
+	}
+	if (unlikely(!spin_trylock(&busiest->lock))) {
+		if (busiest < this_rq) {
+			spin_unlock(&this_rq->lock);
+			spin_lock(&busiest->lock);
+			spin_lock_nested(&this_rq->lock, SINGLE_DEPTH_NESTING);
+			ret = 1;
+		} else
+			spin_lock_nested(&busiest->lock, SINGLE_DEPTH_NESTING);
+	}
+	return ret;
+}
+
+static inline void double_unlock_balance(struct rq *this_rq, struct rq *busiest)
+	__releases(busiest->lock)
+{
+	spin_unlock(&busiest->lock);
+	lock_set_subclass(&this_rq->lock.dep_map, 0, _RET_IP_);
+}
 #endif
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -1845,6 +1867,8 @@
 
 	clock_offset = old_rq->clock - new_rq->clock;
 
+	trace_sched_migrate_task(p, task_cpu(p), new_cpu);
+
 #ifdef CONFIG_SCHEDSTATS
 	if (p->se.wait_start)
 		p->se.wait_start -= clock_offset;
@@ -2254,6 +2278,7 @@
 
 	smp_wmb();
 	rq = task_rq_lock(p, &flags);
+	update_rq_clock(rq);
 	old_state = p->state;
 	if (!(old_state & state))
 		goto out;
@@ -2311,12 +2336,11 @@
 		schedstat_inc(p, se.nr_wakeups_local);
 	else
 		schedstat_inc(p, se.nr_wakeups_remote);
-	update_rq_clock(rq);
 	activate_task(rq, p, 1);
 	success = 1;
 
 out_running:
-	trace_sched_wakeup(rq, p);
+	trace_sched_wakeup(rq, p, success);
 	check_preempt_curr(rq, p, sync);
 
 	p->state = TASK_RUNNING;
@@ -2449,7 +2473,7 @@
 		p->sched_class->task_new(rq, p);
 		inc_nr_running(rq);
 	}
-	trace_sched_wakeup_new(rq, p);
+	trace_sched_wakeup_new(rq, p, 1);
 	check_preempt_curr(rq, p, 0);
 #ifdef CONFIG_SMP
 	if (p->sched_class->task_wake_up)
@@ -2812,40 +2836,6 @@
 }
 
 /*
- * double_lock_balance - lock the busiest runqueue, this_rq is locked already.
- */
-static int double_lock_balance(struct rq *this_rq, struct rq *busiest)
-	__releases(this_rq->lock)
-	__acquires(busiest->lock)
-	__acquires(this_rq->lock)
-{
-	int ret = 0;
-
-	if (unlikely(!irqs_disabled())) {
-		/* printk() doesn't work good under rq->lock */
-		spin_unlock(&this_rq->lock);
-		BUG_ON(1);
-	}
-	if (unlikely(!spin_trylock(&busiest->lock))) {
-		if (busiest < this_rq) {
-			spin_unlock(&this_rq->lock);
-			spin_lock(&busiest->lock);
-			spin_lock_nested(&this_rq->lock, SINGLE_DEPTH_NESTING);
-			ret = 1;
-		} else
-			spin_lock_nested(&busiest->lock, SINGLE_DEPTH_NESTING);
-	}
-	return ret;
-}
-
-static void double_unlock_balance(struct rq *this_rq, struct rq *busiest)
-	__releases(busiest->lock)
-{
-	spin_unlock(&busiest->lock);
-	lock_set_subclass(&this_rq->lock.dep_map, 0, _RET_IP_);
-}
-
-/*
  * If dest_cpu is allowed for this process, migrate the task to it.
  * This is accomplished by forcing the cpu_allowed mask to only
  * allow dest_cpu, which will force the cpu onto dest_cpu. Then
@@ -2862,7 +2852,6 @@
 	    || unlikely(!cpu_active(dest_cpu)))
 		goto out;
 
-	trace_sched_migrate_task(rq, p, dest_cpu);
 	/* force the process onto the specified CPU */
 	if (migrate_task(p, dest_cpu, &req)) {
 		/* Need to wait for migration thread (might exit: take ref). */
@@ -3707,7 +3696,7 @@
 static void idle_balance(int this_cpu, struct rq *this_rq)
 {
 	struct sched_domain *sd;
-	int pulled_task = -1;
+	int pulled_task = 0;
 	unsigned long next_balance = jiffies + HZ;
 	cpumask_t tmpmask;
 
@@ -5134,6 +5123,22 @@
 	set_load_weight(p);
 }
 
+/*
+ * check the target process has a UID that matches the current process's
+ */
+static bool check_same_owner(struct task_struct *p)
+{
+	const struct cred *cred = current_cred(), *pcred;
+	bool match;
+
+	rcu_read_lock();
+	pcred = __task_cred(p);
+	match = (cred->euid == pcred->euid ||
+		 cred->euid == pcred->uid);
+	rcu_read_unlock();
+	return match;
+}
+
 static int __sched_setscheduler(struct task_struct *p, int policy,
 				struct sched_param *param, bool user)
 {
@@ -5193,8 +5198,7 @@
 			return -EPERM;
 
 		/* can't change other user's priorities */
-		if ((current->euid != p->euid) &&
-		    (current->euid != p->uid))
+		if (!check_same_owner(p))
 			return -EPERM;
 	}
 
@@ -5426,8 +5430,7 @@
 	read_unlock(&tasklist_lock);
 
 	retval = -EPERM;
-	if ((current->euid != p->euid) && (current->euid != p->uid) &&
-			!capable(CAP_SYS_NICE))
+	if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
 		goto out_unlock;
 
 	retval = security_task_setscheduler(p, 0, NULL);
@@ -5896,6 +5899,7 @@
 	 * The idle tasks have their own, simple scheduling class:
 	 */
 	idle->sched_class = &idle_sched_class;
+	ftrace_graph_init_task(idle);
 }
 
 /*
@@ -6126,7 +6130,6 @@
 
 /*
  * Figure out where task on dead CPU should go, use force if necessary.
- * NOTE: interrupts should be disabled by the caller
  */
 static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *p)
 {
@@ -6638,28 +6641,6 @@
 
 #ifdef CONFIG_SCHED_DEBUG
 
-static inline const char *sd_level_to_string(enum sched_domain_level lvl)
-{
-	switch (lvl) {
-	case SD_LV_NONE:
-			return "NONE";
-	case SD_LV_SIBLING:
-			return "SIBLING";
-	case SD_LV_MC:
-			return "MC";
-	case SD_LV_CPU:
-			return "CPU";
-	case SD_LV_NODE:
-			return "NODE";
-	case SD_LV_ALLNODES:
-			return "ALLNODES";
-	case SD_LV_MAX:
-			return "MAX";
-
-	}
-	return "MAX";
-}
-
 static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level,
 				  cpumask_t *groupmask)
 {
@@ -6679,8 +6660,7 @@
 		return -1;
 	}
 
-	printk(KERN_CONT "span %s level %s\n",
-		str, sd_level_to_string(sd->level));
+	printk(KERN_CONT "span %s level %s\n", str, sd->name);
 
 	if (!cpu_isset(cpu, sd->span)) {
 		printk(KERN_ERR "ERROR: domain->span does not contain "
@@ -6816,6 +6796,8 @@
 				SD_BALANCE_EXEC |
 				SD_SHARE_CPUPOWER |
 				SD_SHARE_PKG_RESOURCES);
+		if (nr_node_ids == 1)
+			pflags &= ~SD_SERIALIZE;
 	}
 	if (~cflags & pflags)
 		return 0;
@@ -7336,13 +7318,21 @@
 };
 
 #if	NR_CPUS > 128
-#define	SCHED_CPUMASK_ALLOC		1
-#define	SCHED_CPUMASK_FREE(v)		kfree(v)
-#define	SCHED_CPUMASK_DECLARE(v)	struct allmasks *v
+#define SCHED_CPUMASK_DECLARE(v)	struct allmasks *v
+static inline void sched_cpumask_alloc(struct allmasks **masks)
+{
+	*masks = kmalloc(sizeof(**masks), GFP_KERNEL);
+}
+static inline void sched_cpumask_free(struct allmasks *masks)
+{
+	kfree(masks);
+}
 #else
-#define	SCHED_CPUMASK_ALLOC		0
-#define	SCHED_CPUMASK_FREE(v)
-#define	SCHED_CPUMASK_DECLARE(v)	struct allmasks _v, *v = &_v
+#define SCHED_CPUMASK_DECLARE(v)	struct allmasks _v, *v = &_v
+static inline void sched_cpumask_alloc(struct allmasks **masks)
+{ }
+static inline void sched_cpumask_free(struct allmasks *masks)
+{ }
 #endif
 
 #define	SCHED_CPUMASK_VAR(v, a) 	cpumask_t *v = (cpumask_t *) \
@@ -7418,9 +7408,8 @@
 		return -ENOMEM;
 	}
 
-#if SCHED_CPUMASK_ALLOC
 	/* get space for all scratch cpumask variables */
-	allmasks = kmalloc(sizeof(*allmasks), GFP_KERNEL);
+	sched_cpumask_alloc(&allmasks);
 	if (!allmasks) {
 		printk(KERN_WARNING "Cannot alloc cpumask array\n");
 		kfree(rd);
@@ -7429,7 +7418,7 @@
 #endif
 		return -ENOMEM;
 	}
-#endif
+
 	tmpmask = (cpumask_t *)allmasks;
 
 
@@ -7683,13 +7672,13 @@
 		cpu_attach_domain(sd, rd, i);
 	}
 
-	SCHED_CPUMASK_FREE((void *)allmasks);
+	sched_cpumask_free(allmasks);
 	return 0;
 
 #ifdef CONFIG_NUMA
 error:
 	free_sched_groups(cpu_map, tmpmask);
-	SCHED_CPUMASK_FREE((void *)allmasks);
+	sched_cpumask_free(allmasks);
 	kfree(rd);
 	return -ENOMEM;
 #endif
@@ -7712,8 +7701,14 @@
  */
 static cpumask_t fallback_doms;
 
-void __attribute__((weak)) arch_update_cpu_topology(void)
+/*
+ * arch_update_cpu_topology lets virtualized architectures update the
+ * cpu core maps. It is supposed to return 1 if the topology changed
+ * or 0 if it stayed the same.
+ */
+int __attribute__((weak)) arch_update_cpu_topology(void)
 {
+	return 0;
 }
 
 /*
@@ -7753,8 +7748,6 @@
 	cpumask_t tmpmask;
 	int i;
 
-	unregister_sched_domain_sysctl();
-
 	for_each_cpu_mask_nr(i, *cpu_map)
 		cpu_attach_domain(NULL, &def_root_domain, i);
 	synchronize_sched();
@@ -7807,17 +7800,21 @@
 			     struct sched_domain_attr *dattr_new)
 {
 	int i, j, n;
+	int new_topology;
 
 	mutex_lock(&sched_domains_mutex);
 
 	/* always unregister in case we don't destroy any domains */
 	unregister_sched_domain_sysctl();
 
+	/* Let architecture update cpu core mappings. */
+	new_topology = arch_update_cpu_topology();
+
 	n = doms_new ? ndoms_new : 0;
 
 	/* Destroy deleted domains */
 	for (i = 0; i < ndoms_cur; i++) {
-		for (j = 0; j < n; j++) {
+		for (j = 0; j < n && !new_topology; j++) {
 			if (cpus_equal(doms_cur[i], doms_new[j])
 			    && dattrs_equal(dattr_cur, i, dattr_new, j))
 				goto match1;
@@ -7832,12 +7829,12 @@
 		ndoms_cur = 0;
 		doms_new = &fallback_doms;
 		cpus_andnot(doms_new[0], cpu_online_map, cpu_isolated_map);
-		dattr_new = NULL;
+		WARN_ON_ONCE(dattr_new);
 	}
 
 	/* Build new domains */
 	for (i = 0; i < ndoms_new; i++) {
-		for (j = 0; j < ndoms_cur; j++) {
+		for (j = 0; j < ndoms_cur && !new_topology; j++) {
 			if (cpus_equal(doms_new[i], doms_cur[j])
 			    && dattrs_equal(dattr_new, i, dattr_cur, j))
 				goto match2;
@@ -8492,7 +8489,7 @@
 int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
 {
 	struct cfs_rq *cfs_rq;
-	struct sched_entity *se, *parent_se;
+	struct sched_entity *se;
 	struct rq *rq;
 	int i;
 
@@ -8508,18 +8505,17 @@
 	for_each_possible_cpu(i) {
 		rq = cpu_rq(i);
 
-		cfs_rq = kmalloc_node(sizeof(struct cfs_rq),
-				GFP_KERNEL|__GFP_ZERO, cpu_to_node(i));
+		cfs_rq = kzalloc_node(sizeof(struct cfs_rq),
+				      GFP_KERNEL, cpu_to_node(i));
 		if (!cfs_rq)
 			goto err;
 
-		se = kmalloc_node(sizeof(struct sched_entity),
-				GFP_KERNEL|__GFP_ZERO, cpu_to_node(i));
+		se = kzalloc_node(sizeof(struct sched_entity),
+				  GFP_KERNEL, cpu_to_node(i));
 		if (!se)
 			goto err;
 
-		parent_se = parent ? parent->se[i] : NULL;
-		init_tg_cfs_entry(tg, cfs_rq, se, i, 0, parent_se);
+		init_tg_cfs_entry(tg, cfs_rq, se, i, 0, parent->se[i]);
 	}
 
 	return 1;
@@ -8580,7 +8576,7 @@
 int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
 {
 	struct rt_rq *rt_rq;
-	struct sched_rt_entity *rt_se, *parent_se;
+	struct sched_rt_entity *rt_se;
 	struct rq *rq;
 	int i;
 
@@ -8597,18 +8593,17 @@
 	for_each_possible_cpu(i) {
 		rq = cpu_rq(i);
 
-		rt_rq = kmalloc_node(sizeof(struct rt_rq),
-				GFP_KERNEL|__GFP_ZERO, cpu_to_node(i));
+		rt_rq = kzalloc_node(sizeof(struct rt_rq),
+				     GFP_KERNEL, cpu_to_node(i));
 		if (!rt_rq)
 			goto err;
 
-		rt_se = kmalloc_node(sizeof(struct sched_rt_entity),
-				GFP_KERNEL|__GFP_ZERO, cpu_to_node(i));
+		rt_se = kzalloc_node(sizeof(struct sched_rt_entity),
+				     GFP_KERNEL, cpu_to_node(i));
 		if (!rt_se)
 			goto err;
 
-		parent_se = parent ? parent->rt_se[i] : NULL;
-		init_tg_rt_entry(tg, rt_rq, rt_se, i, 0, parent_se);
+		init_tg_rt_entry(tg, rt_rq, rt_se, i, 0, parent->rt_se[i]);
 	}
 
 	return 1;
@@ -9251,11 +9246,12 @@
  * (balbir@in.ibm.com).
  */
 
-/* track cpu usage of a group of tasks */
+/* track cpu usage of a group of tasks and its child groups */
 struct cpuacct {
 	struct cgroup_subsys_state css;
 	/* cpuusage holds pointer to a u64-type object on every cpu */
 	u64 *cpuusage;
+	struct cpuacct *parent;
 };
 
 struct cgroup_subsys cpuacct_subsys;
@@ -9289,6 +9285,9 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
+	if (cgrp->parent)
+		ca->parent = cgroup_ca(cgrp->parent);
+
 	return &ca->css;
 }
 
@@ -9302,6 +9301,41 @@
 	kfree(ca);
 }
 
+static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu)
+{
+	u64 *cpuusage = percpu_ptr(ca->cpuusage, cpu);
+	u64 data;
+
+#ifndef CONFIG_64BIT
+	/*
+	 * Take rq->lock to make 64-bit read safe on 32-bit platforms.
+	 */
+	spin_lock_irq(&cpu_rq(cpu)->lock);
+	data = *cpuusage;
+	spin_unlock_irq(&cpu_rq(cpu)->lock);
+#else
+	data = *cpuusage;
+#endif
+
+	return data;
+}
+
+static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val)
+{
+	u64 *cpuusage = percpu_ptr(ca->cpuusage, cpu);
+
+#ifndef CONFIG_64BIT
+	/*
+	 * Take rq->lock to make 64-bit write safe on 32-bit platforms.
+	 */
+	spin_lock_irq(&cpu_rq(cpu)->lock);
+	*cpuusage = val;
+	spin_unlock_irq(&cpu_rq(cpu)->lock);
+#else
+	*cpuusage = val;
+#endif
+}
+
 /* return total cpu usage (in nanoseconds) of a group */
 static u64 cpuusage_read(struct cgroup *cgrp, struct cftype *cft)
 {
@@ -9309,17 +9343,8 @@
 	u64 totalcpuusage = 0;
 	int i;
 
-	for_each_possible_cpu(i) {
-		u64 *cpuusage = percpu_ptr(ca->cpuusage, i);
-
-		/*
-		 * Take rq->lock to make 64-bit addition safe on 32-bit
-		 * platforms.
-		 */
-		spin_lock_irq(&cpu_rq(i)->lock);
-		totalcpuusage += *cpuusage;
-		spin_unlock_irq(&cpu_rq(i)->lock);
-	}
+	for_each_present_cpu(i)
+		totalcpuusage += cpuacct_cpuusage_read(ca, i);
 
 	return totalcpuusage;
 }
@@ -9336,23 +9361,39 @@
 		goto out;
 	}
 
-	for_each_possible_cpu(i) {
-		u64 *cpuusage = percpu_ptr(ca->cpuusage, i);
+	for_each_present_cpu(i)
+		cpuacct_cpuusage_write(ca, i, 0);
 
-		spin_lock_irq(&cpu_rq(i)->lock);
-		*cpuusage = 0;
-		spin_unlock_irq(&cpu_rq(i)->lock);
-	}
 out:
 	return err;
 }
 
+static int cpuacct_percpu_seq_read(struct cgroup *cgroup, struct cftype *cft,
+				   struct seq_file *m)
+{
+	struct cpuacct *ca = cgroup_ca(cgroup);
+	u64 percpu;
+	int i;
+
+	for_each_present_cpu(i) {
+		percpu = cpuacct_cpuusage_read(ca, i);
+		seq_printf(m, "%llu ", (unsigned long long) percpu);
+	}
+	seq_printf(m, "\n");
+	return 0;
+}
+
 static struct cftype files[] = {
 	{
 		.name = "usage",
 		.read_u64 = cpuusage_read,
 		.write_u64 = cpuusage_write,
 	},
+	{
+		.name = "usage_percpu",
+		.read_seq_string = cpuacct_percpu_seq_read,
+	},
+
 };
 
 static int cpuacct_populate(struct cgroup_subsys *ss, struct cgroup *cgrp)
@@ -9368,14 +9409,16 @@
 static void cpuacct_charge(struct task_struct *tsk, u64 cputime)
 {
 	struct cpuacct *ca;
+	int cpu;
 
 	if (!cpuacct_subsys.active)
 		return;
 
+	cpu = task_cpu(tsk);
 	ca = task_ca(tsk);
-	if (ca) {
-		u64 *cpuusage = percpu_ptr(ca->cpuusage, task_cpu(tsk));
 
+	for (; ca; ca = ca->parent) {
+		u64 *cpuusage = percpu_ptr(ca->cpuusage, cpu);
 		*cpuusage += cputime;
 	}
 }
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
index 26ed8e3..4293cfa 100644
--- a/kernel/sched_debug.c
+++ b/kernel/sched_debug.c
@@ -53,6 +53,40 @@
 
 #define SPLIT_NS(x) nsec_high(x), nsec_low(x)
 
+#ifdef CONFIG_FAIR_GROUP_SCHED
+static void print_cfs_group_stats(struct seq_file *m, int cpu,
+		struct task_group *tg)
+{
+	struct sched_entity *se = tg->se[cpu];
+	if (!se)
+		return;
+
+#define P(F) \
+	SEQ_printf(m, "  .%-30s: %lld\n", #F, (long long)F)
+#define PN(F) \
+	SEQ_printf(m, "  .%-30s: %lld.%06ld\n", #F, SPLIT_NS((long long)F))
+
+	PN(se->exec_start);
+	PN(se->vruntime);
+	PN(se->sum_exec_runtime);
+#ifdef CONFIG_SCHEDSTATS
+	PN(se->wait_start);
+	PN(se->sleep_start);
+	PN(se->block_start);
+	PN(se->sleep_max);
+	PN(se->block_max);
+	PN(se->exec_max);
+	PN(se->slice_max);
+	PN(se->wait_max);
+	PN(se->wait_sum);
+	P(se->wait_count);
+#endif
+	P(se->load.weight);
+#undef PN
+#undef P
+}
+#endif
+
 static void
 print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
 {
@@ -121,20 +155,19 @@
 
 #if defined(CONFIG_CGROUP_SCHED) && defined(CONFIG_FAIR_GROUP_SCHED)
 	char path[128] = "";
-	struct cgroup *cgroup = NULL;
 	struct task_group *tg = cfs_rq->tg;
 
-	if (tg)
-		cgroup = tg->css.cgroup;
-
-	if (cgroup)
-		cgroup_path(cgroup, path, sizeof(path));
+	cgroup_path(tg->css.cgroup, path, sizeof(path));
 
 	SEQ_printf(m, "\ncfs_rq[%d]:%s\n", cpu, path);
+#elif defined(CONFIG_USER_SCHED) && defined(CONFIG_FAIR_GROUP_SCHED)
+	{
+		uid_t uid = cfs_rq->tg->uid;
+		SEQ_printf(m, "\ncfs_rq[%d] for UID: %u\n", cpu, uid);
+	}
 #else
 	SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu);
 #endif
-
 	SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "exec_clock",
 			SPLIT_NS(cfs_rq->exec_clock));
 
@@ -168,6 +201,7 @@
 #ifdef CONFIG_SMP
 	SEQ_printf(m, "  .%-30s: %lu\n", "shares", cfs_rq->shares);
 #endif
+	print_cfs_group_stats(m, cpu, cfs_rq->tg);
 #endif
 }
 
@@ -175,14 +209,9 @@
 {
 #if defined(CONFIG_CGROUP_SCHED) && defined(CONFIG_RT_GROUP_SCHED)
 	char path[128] = "";
-	struct cgroup *cgroup = NULL;
 	struct task_group *tg = rt_rq->tg;
 
-	if (tg)
-		cgroup = tg->css.cgroup;
-
-	if (cgroup)
-		cgroup_path(cgroup, path, sizeof(path));
+	cgroup_path(tg->css.cgroup, path, sizeof(path));
 
 	SEQ_printf(m, "\nrt_rq[%d]:%s\n", cpu, path);
 #else
@@ -272,7 +301,7 @@
 	u64 now = ktime_to_ns(ktime_get());
 	int cpu;
 
-	SEQ_printf(m, "Sched Debug Version: v0.07, %s %.*s\n",
+	SEQ_printf(m, "Sched Debug Version: v0.08, %s %.*s\n",
 		init_utsname()->release,
 		(int)strcspn(init_utsname()->version, " "),
 		init_utsname()->version);
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index 98345e4..5ad4440 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -492,6 +492,8 @@
 	 * overflow on 32 bits):
 	 */
 	delta_exec = (unsigned long)(now - curr->exec_start);
+	if (!delta_exec)
+		return;
 
 	__update_curr(cfs_rq, curr, delta_exec);
 	curr->exec_start = now;
@@ -1345,12 +1347,11 @@
 {
 	struct task_struct *curr = rq->curr;
 	struct sched_entity *se = &curr->se, *pse = &p->se;
+	struct cfs_rq *cfs_rq = task_cfs_rq(curr);
+
+	update_curr(cfs_rq);
 
 	if (unlikely(rt_prio(p->prio))) {
-		struct cfs_rq *cfs_rq = task_cfs_rq(curr);
-
-		update_rq_clock(rq);
-		update_curr(cfs_rq);
 		resched_task(curr);
 		return;
 	}
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
index d9ba9d5..51d2af3 100644
--- a/kernel/sched_rt.c
+++ b/kernel/sched_rt.c
@@ -77,7 +77,7 @@
 }
 
 #define for_each_leaf_rt_rq(rt_rq, rq) \
-	list_for_each_entry(rt_rq, &rq->leaf_rt_rq_list, leaf_rt_rq_list)
+	list_for_each_entry_rcu(rt_rq, &rq->leaf_rt_rq_list, leaf_rt_rq_list)
 
 static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq)
 {
@@ -537,13 +537,13 @@
 	for_each_sched_rt_entity(rt_se) {
 		rt_rq = rt_rq_of_se(rt_se);
 
-		spin_lock(&rt_rq->rt_runtime_lock);
 		if (sched_rt_runtime(rt_rq) != RUNTIME_INF) {
+			spin_lock(&rt_rq->rt_runtime_lock);
 			rt_rq->rt_time += delta_exec;
 			if (sched_rt_runtime_exceeded(rt_rq))
 				resched_task(curr);
+			spin_unlock(&rt_rq->rt_runtime_lock);
 		}
-		spin_unlock(&rt_rq->rt_runtime_lock);
 	}
 }
 
@@ -909,9 +909,6 @@
 /* Only try algorithms three times */
 #define RT_MAX_TRIES 3
 
-static int double_lock_balance(struct rq *this_rq, struct rq *busiest);
-static void double_unlock_balance(struct rq *this_rq, struct rq *busiest);
-
 static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep);
 
 static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu)
diff --git a/kernel/sched_stats.h b/kernel/sched_stats.h
index 7dbf72a..3b01098 100644
--- a/kernel/sched_stats.h
+++ b/kernel/sched_stats.h
@@ -31,7 +31,7 @@
 		    rq->yld_act_empty, rq->yld_exp_empty, rq->yld_count,
 		    rq->sched_switch, rq->sched_count, rq->sched_goidle,
 		    rq->ttwu_count, rq->ttwu_local,
-		    rq->rq_sched_info.cpu_time,
+		    rq->rq_cpu_time,
 		    rq->rq_sched_info.run_delay, rq->rq_sched_info.pcount);
 
 		seq_printf(seq, "\n");
@@ -123,7 +123,7 @@
 rq_sched_info_depart(struct rq *rq, unsigned long long delta)
 {
 	if (rq)
-		rq->rq_sched_info.cpu_time += delta;
+		rq->rq_cpu_time += delta;
 }
 
 static inline void
@@ -236,7 +236,6 @@
 	unsigned long long delta = task_rq(t)->clock -
 					t->sched_info.last_arrival;
 
-	t->sched_info.cpu_time += delta;
 	rq_sched_info_depart(task_rq(t), delta);
 
 	if (t->state == TASK_RUNNING)
diff --git a/kernel/signal.c b/kernel/signal.c
index 4530fc6..8e95855 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -41,6 +41,8 @@
 
 static struct kmem_cache *sigqueue_cachep;
 
+DEFINE_TRACE(sched_signal_send);
+
 static void __user *sig_handler(struct task_struct *t, int sig)
 {
 	return t->sighand->action[sig - 1].sa.sa_handler;
@@ -177,6 +179,11 @@
 	return sig;
 }
 
+/*
+ * allocate a new signal queue record
+ * - this may be called without locks if and only if t == current, otherwise an
+ *   appopriate lock must be held to stop the target task from exiting
+ */
 static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
 					 int override_rlimit)
 {
@@ -184,11 +191,12 @@
 	struct user_struct *user;
 
 	/*
-	 * In order to avoid problems with "switch_user()", we want to make
-	 * sure that the compiler doesn't re-load "t->user"
+	 * We won't get problems with the target's UID changing under us
+	 * because changing it requires RCU be used, and if t != current, the
+	 * caller must be holding the RCU readlock (by way of a spinlock) and
+	 * we use RCU protection here
 	 */
-	user = t->user;
-	barrier();
+	user = get_uid(__task_cred(t)->user);
 	atomic_inc(&user->sigpending);
 	if (override_rlimit ||
 	    atomic_read(&user->sigpending) <=
@@ -196,12 +204,14 @@
 		q = kmem_cache_alloc(sigqueue_cachep, flags);
 	if (unlikely(q == NULL)) {
 		atomic_dec(&user->sigpending);
+		free_uid(user);
 	} else {
 		INIT_LIST_HEAD(&q->list);
 		q->flags = 0;
-		q->user = get_uid(user);
+		q->user = user;
 	}
-	return(q);
+
+	return q;
 }
 
 static void __sigqueue_free(struct sigqueue *q)
@@ -562,10 +572,12 @@
 
 /*
  * Bad permissions for sending the signal
+ * - the caller must hold at least the RCU read lock
  */
 static int check_kill_permission(int sig, struct siginfo *info,
 				 struct task_struct *t)
 {
+	const struct cred *cred = current_cred(), *tcred;
 	struct pid *sid;
 	int error;
 
@@ -579,8 +591,11 @@
 	if (error)
 		return error;
 
-	if ((current->euid ^ t->suid) && (current->euid ^ t->uid) &&
-	    (current->uid  ^ t->suid) && (current->uid  ^ t->uid) &&
+	tcred = __task_cred(t);
+	if ((cred->euid ^ tcred->suid) &&
+	    (cred->euid ^ tcred->uid) &&
+	    (cred->uid  ^ tcred->suid) &&
+	    (cred->uid  ^ tcred->uid) &&
 	    !capable(CAP_KILL)) {
 		switch (sig) {
 		case SIGCONT:
@@ -844,7 +859,7 @@
 			q->info.si_errno = 0;
 			q->info.si_code = SI_USER;
 			q->info.si_pid = task_pid_vnr(current);
-			q->info.si_uid = current->uid;
+			q->info.si_uid = current_uid();
 			break;
 		case (unsigned long) SEND_SIG_PRIV:
 			q->info.si_signo = sig;
@@ -1008,6 +1023,10 @@
 	return sighand;
 }
 
+/*
+ * send signal info to all the members of a group
+ * - the caller must hold the RCU read lock at least
+ */
 int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
 {
 	unsigned long flags;
@@ -1029,8 +1048,8 @@
 /*
  * __kill_pgrp_info() sends a signal to a process group: this is what the tty
  * control characters do (^C, ^Z etc)
+ * - the caller must hold at least a readlock on tasklist_lock
  */
-
 int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
 {
 	struct task_struct *p = NULL;
@@ -1086,6 +1105,7 @@
 {
 	int ret = -EINVAL;
 	struct task_struct *p;
+	const struct cred *pcred;
 
 	if (!valid_signal(sig))
 		return ret;
@@ -1096,9 +1116,11 @@
 		ret = -ESRCH;
 		goto out_unlock;
 	}
-	if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info)))
-	    && (euid != p->suid) && (euid != p->uid)
-	    && (uid != p->suid) && (uid != p->uid)) {
+	pcred = __task_cred(p);
+	if ((info == SEND_SIG_NOINFO ||
+	     (!is_si_special(info) && SI_FROMUSER(info))) &&
+	    euid != pcred->suid && euid != pcred->uid &&
+	    uid  != pcred->suid && uid  != pcred->uid) {
 		ret = -EPERM;
 		goto out_unlock;
 	}
@@ -1369,10 +1391,9 @@
 	 */
 	rcu_read_lock();
 	info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
+	info.si_uid = __task_cred(tsk)->uid;
 	rcu_read_unlock();
 
-	info.si_uid = tsk->uid;
-
 	thread_group_cputime(tsk, &cputime);
 	info.si_utime = cputime_to_jiffies(cputime.utime);
 	info.si_stime = cputime_to_jiffies(cputime.stime);
@@ -1440,10 +1461,9 @@
 	 */
 	rcu_read_lock();
 	info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
+	info.si_uid = __task_cred(tsk)->uid;
 	rcu_read_unlock();
 
-	info.si_uid = tsk->uid;
-
 	info.si_utime = cputime_to_clock_t(tsk->utime);
 	info.si_stime = cputime_to_clock_t(tsk->stime);
 
@@ -1598,7 +1618,7 @@
 	info.si_signo = SIGTRAP;
 	info.si_code = exit_code;
 	info.si_pid = task_pid_vnr(current);
-	info.si_uid = current->uid;
+	info.si_uid = current_uid();
 
 	/* Let the debugger run.  */
 	spin_lock_irq(&current->sighand->siglock);
@@ -1710,7 +1730,7 @@
 		info->si_errno = 0;
 		info->si_code = SI_USER;
 		info->si_pid = task_pid_vnr(current->parent);
-		info->si_uid = current->parent->uid;
+		info->si_uid = task_uid(current->parent);
 	}
 
 	/* If the (new) signal is now blocked, requeue it.  */
@@ -2211,7 +2231,7 @@
 	info.si_errno = 0;
 	info.si_code = SI_USER;
 	info.si_pid = task_tgid_vnr(current);
-	info.si_uid = current->uid;
+	info.si_uid = current_uid();
 
 	return kill_something_info(sig, &info, pid);
 }
@@ -2228,7 +2248,7 @@
 	info.si_errno = 0;
 	info.si_code = SI_TKILL;
 	info.si_pid = task_tgid_vnr(current);
-	info.si_uid = current->uid;
+	info.si_uid = current_uid();
 
 	rcu_read_lock();
 	p = find_task_by_vpid(pid);
diff --git a/kernel/sys.c b/kernel/sys.c
index 31deba8..ebe65c2 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -112,12 +112,17 @@
 
 void (*pm_power_off_prepare)(void);
 
+/*
+ * set the priority of a task
+ * - the caller must hold the RCU read lock
+ */
 static int set_one_prio(struct task_struct *p, int niceval, int error)
 {
+	const struct cred *cred = current_cred(), *pcred = __task_cred(p);
 	int no_nice;
 
-	if (p->uid != current->euid &&
-		p->euid != current->euid && !capable(CAP_SYS_NICE)) {
+	if (pcred->uid  != cred->euid &&
+	    pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) {
 		error = -EPERM;
 		goto out;
 	}
@@ -141,6 +146,7 @@
 {
 	struct task_struct *g, *p;
 	struct user_struct *user;
+	const struct cred *cred = current_cred();
 	int error = -EINVAL;
 	struct pid *pgrp;
 
@@ -174,18 +180,18 @@
 			} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
 			break;
 		case PRIO_USER:
-			user = current->user;
+			user = (struct user_struct *) cred->user;
 			if (!who)
-				who = current->uid;
-			else
-				if ((who != current->uid) && !(user = find_user(who)))
-					goto out_unlock;	/* No processes for this user */
+				who = cred->uid;
+			else if ((who != cred->uid) &&
+				 !(user = find_user(who)))
+				goto out_unlock;	/* No processes for this user */
 
 			do_each_thread(g, p)
-				if (p->uid == who)
+				if (__task_cred(p)->uid == who)
 					error = set_one_prio(p, niceval, error);
 			while_each_thread(g, p);
-			if (who != current->uid)
+			if (who != cred->uid)
 				free_uid(user);		/* For find_user() */
 			break;
 	}
@@ -205,6 +211,7 @@
 {
 	struct task_struct *g, *p;
 	struct user_struct *user;
+	const struct cred *cred = current_cred();
 	long niceval, retval = -ESRCH;
 	struct pid *pgrp;
 
@@ -236,21 +243,21 @@
 			} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
 			break;
 		case PRIO_USER:
-			user = current->user;
+			user = (struct user_struct *) cred->user;
 			if (!who)
-				who = current->uid;
-			else
-				if ((who != current->uid) && !(user = find_user(who)))
-					goto out_unlock;	/* No processes for this user */
+				who = cred->uid;
+			else if ((who != cred->uid) &&
+				 !(user = find_user(who)))
+				goto out_unlock;	/* No processes for this user */
 
 			do_each_thread(g, p)
-				if (p->uid == who) {
+				if (__task_cred(p)->uid == who) {
 					niceval = 20 - task_nice(p);
 					if (niceval > retval)
 						retval = niceval;
 				}
 			while_each_thread(g, p);
-			if (who != current->uid)
+			if (who != cred->uid)
 				free_uid(user);		/* for find_user() */
 			break;
 	}
@@ -472,46 +479,48 @@
  */
 asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
 {
-	int old_rgid = current->gid;
-	int old_egid = current->egid;
-	int new_rgid = old_rgid;
-	int new_egid = old_egid;
+	const struct cred *old;
+	struct cred *new;
 	int retval;
 
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+	old = current_cred();
+
 	retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE);
 	if (retval)
-		return retval;
+		goto error;
 
+	retval = -EPERM;
 	if (rgid != (gid_t) -1) {
-		if ((old_rgid == rgid) ||
-		    (current->egid==rgid) ||
+		if (old->gid == rgid ||
+		    old->egid == rgid ||
 		    capable(CAP_SETGID))
-			new_rgid = rgid;
+			new->gid = rgid;
 		else
-			return -EPERM;
+			goto error;
 	}
 	if (egid != (gid_t) -1) {
-		if ((old_rgid == egid) ||
-		    (current->egid == egid) ||
-		    (current->sgid == egid) ||
+		if (old->gid == egid ||
+		    old->egid == egid ||
+		    old->sgid == egid ||
 		    capable(CAP_SETGID))
-			new_egid = egid;
+			new->egid = egid;
 		else
-			return -EPERM;
+			goto error;
 	}
-	if (new_egid != old_egid) {
-		set_dumpable(current->mm, suid_dumpable);
-		smp_wmb();
-	}
+
 	if (rgid != (gid_t) -1 ||
-	    (egid != (gid_t) -1 && egid != old_rgid))
-		current->sgid = new_egid;
-	current->fsgid = new_egid;
-	current->egid = new_egid;
-	current->gid = new_rgid;
-	key_fsgid_changed(current);
-	proc_id_connector(current, PROC_EVENT_GID);
-	return 0;
+	    (egid != (gid_t) -1 && egid != old->gid))
+		new->sgid = new->egid;
+	new->fsgid = new->egid;
+
+	return commit_creds(new);
+
+error:
+	abort_creds(new);
+	return retval;
 }
 
 /*
@@ -521,56 +530,54 @@
  */
 asmlinkage long sys_setgid(gid_t gid)
 {
-	int old_egid = current->egid;
+	const struct cred *old;
+	struct cred *new;
 	int retval;
 
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+	old = current_cred();
+
 	retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID);
 	if (retval)
-		return retval;
+		goto error;
 
-	if (capable(CAP_SETGID)) {
-		if (old_egid != gid) {
-			set_dumpable(current->mm, suid_dumpable);
-			smp_wmb();
-		}
-		current->gid = current->egid = current->sgid = current->fsgid = gid;
-	} else if ((gid == current->gid) || (gid == current->sgid)) {
-		if (old_egid != gid) {
-			set_dumpable(current->mm, suid_dumpable);
-			smp_wmb();
-		}
-		current->egid = current->fsgid = gid;
-	}
+	retval = -EPERM;
+	if (capable(CAP_SETGID))
+		new->gid = new->egid = new->sgid = new->fsgid = gid;
+	else if (gid == old->gid || gid == old->sgid)
+		new->egid = new->fsgid = gid;
 	else
-		return -EPERM;
+		goto error;
 
-	key_fsgid_changed(current);
-	proc_id_connector(current, PROC_EVENT_GID);
-	return 0;
+	return commit_creds(new);
+
+error:
+	abort_creds(new);
+	return retval;
 }
   
-static int set_user(uid_t new_ruid, int dumpclear)
+/*
+ * change the user struct in a credentials set to match the new UID
+ */
+static int set_user(struct cred *new)
 {
 	struct user_struct *new_user;
 
-	new_user = alloc_uid(current->nsproxy->user_ns, new_ruid);
+	new_user = alloc_uid(current_user_ns(), new->uid);
 	if (!new_user)
 		return -EAGAIN;
 
 	if (atomic_read(&new_user->processes) >=
 				current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
-			new_user != current->nsproxy->user_ns->root_user) {
+			new_user != INIT_USER) {
 		free_uid(new_user);
 		return -EAGAIN;
 	}
 
-	switch_uid(new_user);
-
-	if (dumpclear) {
-		set_dumpable(current->mm, suid_dumpable);
-		smp_wmb();
-	}
-	current->uid = new_ruid;
+	free_uid(new->user);
+	new->user = new_user;
 	return 0;
 }
 
@@ -591,54 +598,56 @@
  */
 asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
 {
-	int old_ruid, old_euid, old_suid, new_ruid, new_euid;
+	const struct cred *old;
+	struct cred *new;
 	int retval;
 
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+	old = current_cred();
+
 	retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE);
 	if (retval)
-		return retval;
+		goto error;
 
-	new_ruid = old_ruid = current->uid;
-	new_euid = old_euid = current->euid;
-	old_suid = current->suid;
-
+	retval = -EPERM;
 	if (ruid != (uid_t) -1) {
-		new_ruid = ruid;
-		if ((old_ruid != ruid) &&
-		    (current->euid != ruid) &&
+		new->uid = ruid;
+		if (old->uid != ruid &&
+		    old->euid != ruid &&
 		    !capable(CAP_SETUID))
-			return -EPERM;
+			goto error;
 	}
 
 	if (euid != (uid_t) -1) {
-		new_euid = euid;
-		if ((old_ruid != euid) &&
-		    (current->euid != euid) &&
-		    (current->suid != euid) &&
+		new->euid = euid;
+		if (old->uid != euid &&
+		    old->euid != euid &&
+		    old->suid != euid &&
 		    !capable(CAP_SETUID))
-			return -EPERM;
+			goto error;
 	}
 
-	if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
-		return -EAGAIN;
+	retval = -EAGAIN;
+	if (new->uid != old->uid && set_user(new) < 0)
+		goto error;
 
-	if (new_euid != old_euid) {
-		set_dumpable(current->mm, suid_dumpable);
-		smp_wmb();
-	}
-	current->fsuid = current->euid = new_euid;
 	if (ruid != (uid_t) -1 ||
-	    (euid != (uid_t) -1 && euid != old_ruid))
-		current->suid = current->euid;
-	current->fsuid = current->euid;
+	    (euid != (uid_t) -1 && euid != old->uid))
+		new->suid = new->euid;
+	new->fsuid = new->euid;
 
-	key_fsuid_changed(current);
-	proc_id_connector(current, PROC_EVENT_UID);
+	retval = security_task_fix_setuid(new, old, LSM_SETID_RE);
+	if (retval < 0)
+		goto error;
 
-	return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);
+	return commit_creds(new);
+
+error:
+	abort_creds(new);
+	return retval;
 }
-
-
 		
 /*
  * setuid() is implemented like SysV with SAVED_IDS 
@@ -653,36 +662,41 @@
  */
 asmlinkage long sys_setuid(uid_t uid)
 {
-	int old_euid = current->euid;
-	int old_ruid, old_suid, new_suid;
+	const struct cred *old;
+	struct cred *new;
 	int retval;
 
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+	old = current_cred();
+
 	retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID);
 	if (retval)
-		return retval;
+		goto error;
 
-	old_ruid = current->uid;
-	old_suid = current->suid;
-	new_suid = old_suid;
-	
+	retval = -EPERM;
 	if (capable(CAP_SETUID)) {
-		if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
-			return -EAGAIN;
-		new_suid = uid;
-	} else if ((uid != current->uid) && (uid != new_suid))
-		return -EPERM;
-
-	if (old_euid != uid) {
-		set_dumpable(current->mm, suid_dumpable);
-		smp_wmb();
+		new->suid = new->uid = uid;
+		if (uid != old->uid && set_user(new) < 0) {
+			retval = -EAGAIN;
+			goto error;
+		}
+	} else if (uid != old->uid && uid != new->suid) {
+		goto error;
 	}
-	current->fsuid = current->euid = uid;
-	current->suid = new_suid;
 
-	key_fsuid_changed(current);
-	proc_id_connector(current, PROC_EVENT_UID);
+	new->fsuid = new->euid = uid;
 
-	return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
+	retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
+	if (retval < 0)
+		goto error;
+
+	return commit_creds(new);
+
+error:
+	abort_creds(new);
+	return retval;
 }
 
 
@@ -692,54 +706,63 @@
  */
 asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
 {
-	int old_ruid = current->uid;
-	int old_euid = current->euid;
-	int old_suid = current->suid;
+	const struct cred *old;
+	struct cred *new;
 	int retval;
 
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+
 	retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
 	if (retval)
-		return retval;
+		goto error;
+	old = current_cred();
 
+	retval = -EPERM;
 	if (!capable(CAP_SETUID)) {
-		if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
-		    (ruid != current->euid) && (ruid != current->suid))
-			return -EPERM;
-		if ((euid != (uid_t) -1) && (euid != current->uid) &&
-		    (euid != current->euid) && (euid != current->suid))
-			return -EPERM;
-		if ((suid != (uid_t) -1) && (suid != current->uid) &&
-		    (suid != current->euid) && (suid != current->suid))
-			return -EPERM;
+		if (ruid != (uid_t) -1 && ruid != old->uid &&
+		    ruid != old->euid  && ruid != old->suid)
+			goto error;
+		if (euid != (uid_t) -1 && euid != old->uid &&
+		    euid != old->euid  && euid != old->suid)
+			goto error;
+		if (suid != (uid_t) -1 && suid != old->uid &&
+		    suid != old->euid  && suid != old->suid)
+			goto error;
 	}
+
+	retval = -EAGAIN;
 	if (ruid != (uid_t) -1) {
-		if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0)
-			return -EAGAIN;
+		new->uid = ruid;
+		if (ruid != old->uid && set_user(new) < 0)
+			goto error;
 	}
-	if (euid != (uid_t) -1) {
-		if (euid != current->euid) {
-			set_dumpable(current->mm, suid_dumpable);
-			smp_wmb();
-		}
-		current->euid = euid;
-	}
-	current->fsuid = current->euid;
+	if (euid != (uid_t) -1)
+		new->euid = euid;
 	if (suid != (uid_t) -1)
-		current->suid = suid;
+		new->suid = suid;
+	new->fsuid = new->euid;
 
-	key_fsuid_changed(current);
-	proc_id_connector(current, PROC_EVENT_UID);
+	retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
+	if (retval < 0)
+		goto error;
 
-	return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES);
+	return commit_creds(new);
+
+error:
+	abort_creds(new);
+	return retval;
 }
 
 asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid)
 {
+	const struct cred *cred = current_cred();
 	int retval;
 
-	if (!(retval = put_user(current->uid, ruid)) &&
-	    !(retval = put_user(current->euid, euid)))
-		retval = put_user(current->suid, suid);
+	if (!(retval   = put_user(cred->uid,  ruid)) &&
+	    !(retval   = put_user(cred->euid, euid)))
+		retval = put_user(cred->suid, suid);
 
 	return retval;
 }
@@ -749,48 +772,55 @@
  */
 asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
 {
+	const struct cred *old;
+	struct cred *new;
 	int retval;
 
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+	old = current_cred();
+
 	retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
 	if (retval)
-		return retval;
+		goto error;
 
+	retval = -EPERM;
 	if (!capable(CAP_SETGID)) {
-		if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
-		    (rgid != current->egid) && (rgid != current->sgid))
-			return -EPERM;
-		if ((egid != (gid_t) -1) && (egid != current->gid) &&
-		    (egid != current->egid) && (egid != current->sgid))
-			return -EPERM;
-		if ((sgid != (gid_t) -1) && (sgid != current->gid) &&
-		    (sgid != current->egid) && (sgid != current->sgid))
-			return -EPERM;
+		if (rgid != (gid_t) -1 && rgid != old->gid &&
+		    rgid != old->egid  && rgid != old->sgid)
+			goto error;
+		if (egid != (gid_t) -1 && egid != old->gid &&
+		    egid != old->egid  && egid != old->sgid)
+			goto error;
+		if (sgid != (gid_t) -1 && sgid != old->gid &&
+		    sgid != old->egid  && sgid != old->sgid)
+			goto error;
 	}
-	if (egid != (gid_t) -1) {
-		if (egid != current->egid) {
-			set_dumpable(current->mm, suid_dumpable);
-			smp_wmb();
-		}
-		current->egid = egid;
-	}
-	current->fsgid = current->egid;
-	if (rgid != (gid_t) -1)
-		current->gid = rgid;
-	if (sgid != (gid_t) -1)
-		current->sgid = sgid;
 
-	key_fsgid_changed(current);
-	proc_id_connector(current, PROC_EVENT_GID);
-	return 0;
+	if (rgid != (gid_t) -1)
+		new->gid = rgid;
+	if (egid != (gid_t) -1)
+		new->egid = egid;
+	if (sgid != (gid_t) -1)
+		new->sgid = sgid;
+	new->fsgid = new->egid;
+
+	return commit_creds(new);
+
+error:
+	abort_creds(new);
+	return retval;
 }
 
 asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid)
 {
+	const struct cred *cred = current_cred();
 	int retval;
 
-	if (!(retval = put_user(current->gid, rgid)) &&
-	    !(retval = put_user(current->egid, egid)))
-		retval = put_user(current->sgid, sgid);
+	if (!(retval   = put_user(cred->gid,  rgid)) &&
+	    !(retval   = put_user(cred->egid, egid)))
+		retval = put_user(cred->sgid, sgid);
 
 	return retval;
 }
@@ -804,27 +834,35 @@
  */
 asmlinkage long sys_setfsuid(uid_t uid)
 {
-	int old_fsuid;
+	const struct cred *old;
+	struct cred *new;
+	uid_t old_fsuid;
 
-	old_fsuid = current->fsuid;
-	if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS))
-		return old_fsuid;
+	new = prepare_creds();
+	if (!new)
+		return current_fsuid();
+	old = current_cred();
+	old_fsuid = old->fsuid;
 
-	if (uid == current->uid || uid == current->euid ||
-	    uid == current->suid || uid == current->fsuid || 
+	if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0)
+		goto error;
+
+	if (uid == old->uid  || uid == old->euid  ||
+	    uid == old->suid || uid == old->fsuid ||
 	    capable(CAP_SETUID)) {
 		if (uid != old_fsuid) {
-			set_dumpable(current->mm, suid_dumpable);
-			smp_wmb();
+			new->fsuid = uid;
+			if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
+				goto change_okay;
 		}
-		current->fsuid = uid;
 	}
 
-	key_fsuid_changed(current);
-	proc_id_connector(current, PROC_EVENT_UID);
+error:
+	abort_creds(new);
+	return old_fsuid;
 
-	security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS);
-
+change_okay:
+	commit_creds(new);
 	return old_fsuid;
 }
 
@@ -833,23 +871,34 @@
  */
 asmlinkage long sys_setfsgid(gid_t gid)
 {
-	int old_fsgid;
+	const struct cred *old;
+	struct cred *new;
+	gid_t old_fsgid;
 
-	old_fsgid = current->fsgid;
+	new = prepare_creds();
+	if (!new)
+		return current_fsgid();
+	old = current_cred();
+	old_fsgid = old->fsgid;
+
 	if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
-		return old_fsgid;
+		goto error;
 
-	if (gid == current->gid || gid == current->egid ||
-	    gid == current->sgid || gid == current->fsgid || 
+	if (gid == old->gid  || gid == old->egid  ||
+	    gid == old->sgid || gid == old->fsgid ||
 	    capable(CAP_SETGID)) {
 		if (gid != old_fsgid) {
-			set_dumpable(current->mm, suid_dumpable);
-			smp_wmb();
+			new->fsgid = gid;
+			goto change_okay;
 		}
-		current->fsgid = gid;
-		key_fsgid_changed(current);
-		proc_id_connector(current, PROC_EVENT_GID);
 	}
+
+error:
+	abort_creds(new);
+	return old_fsgid;
+
+change_okay:
+	commit_creds(new);
 	return old_fsgid;
 }
 
@@ -1118,7 +1167,7 @@
 
 /* export the group_info to a user-space array */
 static int groups_to_user(gid_t __user *grouplist,
-    struct group_info *group_info)
+			  const struct group_info *group_info)
 {
 	int i;
 	unsigned int count = group_info->ngroups;
@@ -1186,7 +1235,7 @@
 }
 
 /* a simple bsearch */
-int groups_search(struct group_info *group_info, gid_t grp)
+int groups_search(const struct group_info *group_info, gid_t grp)
 {
 	unsigned int left, right;
 
@@ -1208,51 +1257,74 @@
 	return 0;
 }
 
-/* validate and set current->group_info */
-int set_current_groups(struct group_info *group_info)
+/**
+ * set_groups - Change a group subscription in a set of credentials
+ * @new: The newly prepared set of credentials to alter
+ * @group_info: The group list to install
+ *
+ * Validate a group subscription and, if valid, insert it into a set
+ * of credentials.
+ */
+int set_groups(struct cred *new, struct group_info *group_info)
 {
 	int retval;
-	struct group_info *old_info;
 
 	retval = security_task_setgroups(group_info);
 	if (retval)
 		return retval;
 
+	put_group_info(new->group_info);
 	groups_sort(group_info);
 	get_group_info(group_info);
-
-	task_lock(current);
-	old_info = current->group_info;
-	current->group_info = group_info;
-	task_unlock(current);
-
-	put_group_info(old_info);
-
+	new->group_info = group_info;
 	return 0;
 }
 
+EXPORT_SYMBOL(set_groups);
+
+/**
+ * set_current_groups - Change current's group subscription
+ * @group_info: The group list to impose
+ *
+ * Validate a group subscription and, if valid, impose it upon current's task
+ * security record.
+ */
+int set_current_groups(struct group_info *group_info)
+{
+	struct cred *new;
+	int ret;
+
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+
+	ret = set_groups(new, group_info);
+	if (ret < 0) {
+		abort_creds(new);
+		return ret;
+	}
+
+	return commit_creds(new);
+}
+
 EXPORT_SYMBOL(set_current_groups);
 
 asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
 {
-	int i = 0;
-
-	/*
-	 *	SMP: Nobody else can change our grouplist. Thus we are
-	 *	safe.
-	 */
+	const struct cred *cred = current_cred();
+	int i;
 
 	if (gidsetsize < 0)
 		return -EINVAL;
 
 	/* no need to grab task_lock here; it cannot change */
-	i = current->group_info->ngroups;
+	i = cred->group_info->ngroups;
 	if (gidsetsize) {
 		if (i > gidsetsize) {
 			i = -EINVAL;
 			goto out;
 		}
-		if (groups_to_user(grouplist, current->group_info)) {
+		if (groups_to_user(grouplist, cred->group_info)) {
 			i = -EFAULT;
 			goto out;
 		}
@@ -1296,9 +1368,11 @@
  */
 int in_group_p(gid_t grp)
 {
+	const struct cred *cred = current_cred();
 	int retval = 1;
-	if (grp != current->fsgid)
-		retval = groups_search(current->group_info, grp);
+
+	if (grp != cred->fsgid)
+		retval = groups_search(cred->group_info, grp);
 	return retval;
 }
 
@@ -1306,9 +1380,11 @@
 
 int in_egroup_p(gid_t grp)
 {
+	const struct cred *cred = current_cred();
 	int retval = 1;
-	if (grp != current->egid)
-		retval = groups_search(current->group_info, grp);
+
+	if (grp != cred->egid)
+		retval = groups_search(cred->group_info, grp);
 	return retval;
 }
 
@@ -1624,50 +1700,56 @@
 asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
 			  unsigned long arg4, unsigned long arg5)
 {
-	long error = 0;
+	struct task_struct *me = current;
+	unsigned char comm[sizeof(me->comm)];
+	long error;
 
-	if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error))
+	error = security_task_prctl(option, arg2, arg3, arg4, arg5);
+	if (error != -ENOSYS)
 		return error;
 
+	error = 0;
 	switch (option) {
 		case PR_SET_PDEATHSIG:
 			if (!valid_signal(arg2)) {
 				error = -EINVAL;
 				break;
 			}
-			current->pdeath_signal = arg2;
+			me->pdeath_signal = arg2;
+			error = 0;
 			break;
 		case PR_GET_PDEATHSIG:
-			error = put_user(current->pdeath_signal, (int __user *)arg2);
+			error = put_user(me->pdeath_signal, (int __user *)arg2);
 			break;
 		case PR_GET_DUMPABLE:
-			error = get_dumpable(current->mm);
+			error = get_dumpable(me->mm);
 			break;
 		case PR_SET_DUMPABLE:
 			if (arg2 < 0 || arg2 > 1) {
 				error = -EINVAL;
 				break;
 			}
-			set_dumpable(current->mm, arg2);
+			set_dumpable(me->mm, arg2);
+			error = 0;
 			break;
 
 		case PR_SET_UNALIGN:
-			error = SET_UNALIGN_CTL(current, arg2);
+			error = SET_UNALIGN_CTL(me, arg2);
 			break;
 		case PR_GET_UNALIGN:
-			error = GET_UNALIGN_CTL(current, arg2);
+			error = GET_UNALIGN_CTL(me, arg2);
 			break;
 		case PR_SET_FPEMU:
-			error = SET_FPEMU_CTL(current, arg2);
+			error = SET_FPEMU_CTL(me, arg2);
 			break;
 		case PR_GET_FPEMU:
-			error = GET_FPEMU_CTL(current, arg2);
+			error = GET_FPEMU_CTL(me, arg2);
 			break;
 		case PR_SET_FPEXC:
-			error = SET_FPEXC_CTL(current, arg2);
+			error = SET_FPEXC_CTL(me, arg2);
 			break;
 		case PR_GET_FPEXC:
-			error = GET_FPEXC_CTL(current, arg2);
+			error = GET_FPEXC_CTL(me, arg2);
 			break;
 		case PR_GET_TIMING:
 			error = PR_TIMING_STATISTICAL;
@@ -1675,33 +1757,28 @@
 		case PR_SET_TIMING:
 			if (arg2 != PR_TIMING_STATISTICAL)
 				error = -EINVAL;
+			else
+				error = 0;
 			break;
 
-		case PR_SET_NAME: {
-			struct task_struct *me = current;
-			unsigned char ncomm[sizeof(me->comm)];
-
-			ncomm[sizeof(me->comm)-1] = 0;
-			if (strncpy_from_user(ncomm, (char __user *)arg2,
-						sizeof(me->comm)-1) < 0)
+		case PR_SET_NAME:
+			comm[sizeof(me->comm)-1] = 0;
+			if (strncpy_from_user(comm, (char __user *)arg2,
+					      sizeof(me->comm) - 1) < 0)
 				return -EFAULT;
-			set_task_comm(me, ncomm);
+			set_task_comm(me, comm);
 			return 0;
-		}
-		case PR_GET_NAME: {
-			struct task_struct *me = current;
-			unsigned char tcomm[sizeof(me->comm)];
-
-			get_task_comm(tcomm, me);
-			if (copy_to_user((char __user *)arg2, tcomm, sizeof(tcomm)))
+		case PR_GET_NAME:
+			get_task_comm(comm, me);
+			if (copy_to_user((char __user *)arg2, comm,
+					 sizeof(comm)))
 				return -EFAULT;
 			return 0;
-		}
 		case PR_GET_ENDIAN:
-			error = GET_ENDIAN(current, arg2);
+			error = GET_ENDIAN(me, arg2);
 			break;
 		case PR_SET_ENDIAN:
-			error = SET_ENDIAN(current, arg2);
+			error = SET_ENDIAN(me, arg2);
 			break;
 
 		case PR_GET_SECCOMP:
@@ -1725,6 +1802,7 @@
 					current->default_timer_slack_ns;
 			else
 				current->timer_slack_ns = arg2;
+			error = 0;
 			break;
 		default:
 			error = -EINVAL;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 3d56fe7..0b627d9 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -487,6 +487,26 @@
 		.proc_handler	= &ftrace_enable_sysctl,
 	},
 #endif
+#ifdef CONFIG_STACK_TRACER
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "stack_tracer_enabled",
+		.data		= &stack_tracer_enabled,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &stack_trace_sysctl,
+	},
+#endif
+#ifdef CONFIG_TRACING
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "ftrace_dump_on_oops",
+		.data		= &ftrace_dump_on_oops,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+#endif
 #ifdef CONFIG_MODULES
 	{
 		.ctl_name	= KERN_MODPROBE,
@@ -1651,7 +1671,7 @@
 
 static int test_perm(int mode, int op)
 {
-	if (!current->euid)
+	if (!current_euid())
 		mode >>= 6;
 	else if (in_egroup_p(0))
 		mode >>= 3;
diff --git a/kernel/timer.c b/kernel/timer.c
index dbd50fa..566257d 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1192,25 +1192,25 @@
 asmlinkage long sys_getuid(void)
 {
 	/* Only we change this so SMP safe */
-	return current->uid;
+	return current_uid();
 }
 
 asmlinkage long sys_geteuid(void)
 {
 	/* Only we change this so SMP safe */
-	return current->euid;
+	return current_euid();
 }
 
 asmlinkage long sys_getgid(void)
 {
 	/* Only we change this so SMP safe */
-	return current->gid;
+	return current_gid();
 }
 
 asmlinkage long sys_getegid(void)
 {
 	/* Only we change this so SMP safe */
-	return  current->egid;
+	return  current_egid();
 }
 
 #endif
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 33dbefd..e2a4ff6 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -3,18 +3,34 @@
 #  select HAVE_FUNCTION_TRACER:
 #
 
+config USER_STACKTRACE_SUPPORT
+	bool
+
 config NOP_TRACER
 	bool
 
 config HAVE_FUNCTION_TRACER
 	bool
 
+config HAVE_FUNCTION_GRAPH_TRACER
+	bool
+
+config HAVE_FUNCTION_TRACE_MCOUNT_TEST
+	bool
+	help
+	 This gets selected when the arch tests the function_trace_stop
+	 variable at the mcount call site. Otherwise, this variable
+	 is tested by the called function.
+
 config HAVE_DYNAMIC_FTRACE
 	bool
 
 config HAVE_FTRACE_MCOUNT_RECORD
 	bool
 
+config HAVE_HW_BRANCH_TRACER
+	bool
+
 config TRACER_MAX_TRACE
 	bool
 
@@ -47,6 +63,20 @@
 	  (the bootup default), then the overhead of the instructions is very
 	  small and not measurable even in micro-benchmarks.
 
+config FUNCTION_GRAPH_TRACER
+	bool "Kernel Function Graph Tracer"
+	depends on HAVE_FUNCTION_GRAPH_TRACER
+	depends on FUNCTION_TRACER
+	default y
+	help
+	  Enable the kernel to trace a function at both its return
+	  and its entry.
+	  It's first purpose is to trace the duration of functions and
+	  draw a call graph for each thread with some informations like
+	  the return value.
+	  This is done by setting the current return address on the current
+	  task structure into a stack of calls.
+
 config IRQSOFF_TRACER
 	bool "Interrupts-off Latency Tracer"
 	default n
@@ -138,6 +168,70 @@
 	    selected, because the self-tests are an initcall as well and that
 	    would invalidate the boot trace. )
 
+config TRACE_BRANCH_PROFILING
+	bool "Trace likely/unlikely profiler"
+	depends on DEBUG_KERNEL
+	select TRACING
+	help
+	  This tracer profiles all the the likely and unlikely macros
+	  in the kernel. It will display the results in:
+
+	  /debugfs/tracing/profile_annotated_branch
+
+	  Note: this will add a significant overhead, only turn this
+	  on if you need to profile the system's use of these macros.
+
+	  Say N if unsure.
+
+config PROFILE_ALL_BRANCHES
+	bool "Profile all if conditionals"
+	depends on TRACE_BRANCH_PROFILING
+	help
+	  This tracer profiles all branch conditions. Every if ()
+	  taken in the kernel is recorded whether it hit or miss.
+	  The results will be displayed in:
+
+	  /debugfs/tracing/profile_branch
+
+	  This configuration, when enabled, will impose a great overhead
+	  on the system. This should only be enabled when the system
+	  is to be analyzed
+
+	  Say N if unsure.
+
+config TRACING_BRANCHES
+	bool
+	help
+	  Selected by tracers that will trace the likely and unlikely
+	  conditions. This prevents the tracers themselves from being
+	  profiled. Profiling the tracing infrastructure can only happen
+	  when the likelys and unlikelys are not being traced.
+
+config BRANCH_TRACER
+	bool "Trace likely/unlikely instances"
+	depends on TRACE_BRANCH_PROFILING
+	select TRACING_BRANCHES
+	help
+	  This traces the events of likely and unlikely condition
+	  calls in the kernel.  The difference between this and the
+	  "Trace likely/unlikely profiler" is that this is not a
+	  histogram of the callers, but actually places the calling
+	  events into a running trace buffer to see when and where the
+	  events happened, as well as their results.
+
+	  Say N if unsure.
+
+config POWER_TRACER
+	bool "Trace power consumption behavior"
+	depends on DEBUG_KERNEL
+	depends on X86
+	select TRACING
+	help
+	  This tracer helps developers to analyze and optimize the kernels
+	  power management decisions, specifically the C-state and P-state
+	  behavior.
+
+
 config STACK_TRACER
 	bool "Trace max stack"
 	depends on HAVE_FUNCTION_TRACER
@@ -150,13 +244,26 @@
 
 	  This tracer works by hooking into every function call that the
 	  kernel executes, and keeping a maximum stack depth value and
-	  stack-trace saved. Because this logic has to execute in every
-	  kernel function, all the time, this option can slow down the
-	  kernel measurably and is generally intended for kernel
-	  developers only.
+	  stack-trace saved.  If this is configured with DYNAMIC_FTRACE
+	  then it will not have any overhead while the stack tracer
+	  is disabled.
+
+	  To enable the stack tracer on bootup, pass in 'stacktrace'
+	  on the kernel command line.
+
+	  The stack tracer can also be enabled or disabled via the
+	  sysctl kernel.stack_tracer_enabled
 
 	  Say N if unsure.
 
+config HW_BRANCH_TRACER
+	depends on HAVE_HW_BRANCH_TRACER
+	bool "Trace hw branches"
+	select TRACING
+	help
+	  This tracer records all branches on the system in a circular
+	  buffer giving access to the last N branches for each cpu.
+
 config DYNAMIC_FTRACE
 	bool "enable/disable ftrace tracepoints dynamically"
 	depends on FUNCTION_TRACER
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index c8228b1..349d5a9 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -10,6 +10,11 @@
 obj-y += trace_selftest_dynamic.o
 endif
 
+# If unlikely tracing is enabled, do not trace these files
+ifdef CONFIG_TRACING_BRANCHES
+KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
+endif
+
 obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o
 obj-$(CONFIG_RING_BUFFER) += ring_buffer.o
 
@@ -24,5 +29,9 @@
 obj-$(CONFIG_STACK_TRACER) += trace_stack.o
 obj-$(CONFIG_MMIOTRACE) += trace_mmiotrace.o
 obj-$(CONFIG_BOOT_TRACER) += trace_boot.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o
+obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o
+obj-$(CONFIG_HW_BRANCH_TRACER) += trace_hw_branches.o
+obj-$(CONFIG_POWER_TRACER) += trace_power.o
 
 libftrace-y := ftrace.o
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 78db083..2f32969 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -47,6 +47,13 @@
 int ftrace_enabled __read_mostly;
 static int last_ftrace_enabled;
 
+/* set when tracing only a pid */
+struct pid *ftrace_pid_trace;
+static struct pid * const ftrace_swapper_pid = &init_struct_pid;
+
+/* Quick disabling of function tracer. */
+int function_trace_stop;
+
 /*
  * ftrace_disabled is set when an anomaly is discovered.
  * ftrace_disabled is much stronger than ftrace_enabled.
@@ -55,6 +62,7 @@
 
 static DEFINE_SPINLOCK(ftrace_lock);
 static DEFINE_MUTEX(ftrace_sysctl_lock);
+static DEFINE_MUTEX(ftrace_start_lock);
 
 static struct ftrace_ops ftrace_list_end __read_mostly =
 {
@@ -63,6 +71,8 @@
 
 static struct ftrace_ops *ftrace_list __read_mostly = &ftrace_list_end;
 ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
+ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub;
+ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub;
 
 static void ftrace_list_func(unsigned long ip, unsigned long parent_ip)
 {
@@ -79,6 +89,21 @@
 	};
 }
 
+static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip)
+{
+	if (!test_tsk_trace_trace(current))
+		return;
+
+	ftrace_pid_function(ip, parent_ip);
+}
+
+static void set_ftrace_pid_function(ftrace_func_t func)
+{
+	/* do not set ftrace_pid_function to itself! */
+	if (func != ftrace_pid_func)
+		ftrace_pid_function = func;
+}
+
 /**
  * clear_ftrace_function - reset the ftrace function
  *
@@ -88,8 +113,24 @@
 void clear_ftrace_function(void)
 {
 	ftrace_trace_function = ftrace_stub;
+	__ftrace_trace_function = ftrace_stub;
+	ftrace_pid_function = ftrace_stub;
 }
 
+#ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
+/*
+ * For those archs that do not test ftrace_trace_stop in their
+ * mcount call site, we need to do it from C.
+ */
+static void ftrace_test_stop_func(unsigned long ip, unsigned long parent_ip)
+{
+	if (function_trace_stop)
+		return;
+
+	__ftrace_trace_function(ip, parent_ip);
+}
+#endif
+
 static int __register_ftrace_function(struct ftrace_ops *ops)
 {
 	/* should not be called from interrupt context */
@@ -106,14 +147,28 @@
 	ftrace_list = ops;
 
 	if (ftrace_enabled) {
+		ftrace_func_t func;
+
+		if (ops->next == &ftrace_list_end)
+			func = ops->func;
+		else
+			func = ftrace_list_func;
+
+		if (ftrace_pid_trace) {
+			set_ftrace_pid_function(func);
+			func = ftrace_pid_func;
+		}
+
 		/*
 		 * For one func, simply call it directly.
 		 * For more than one func, call the chain.
 		 */
-		if (ops->next == &ftrace_list_end)
-			ftrace_trace_function = ops->func;
-		else
-			ftrace_trace_function = ftrace_list_func;
+#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
+		ftrace_trace_function = func;
+#else
+		__ftrace_trace_function = func;
+		ftrace_trace_function = ftrace_test_stop_func;
+#endif
 	}
 
 	spin_unlock(&ftrace_lock);
@@ -152,9 +207,19 @@
 
 	if (ftrace_enabled) {
 		/* If we only have one func left, then call that directly */
-		if (ftrace_list == &ftrace_list_end ||
-		    ftrace_list->next == &ftrace_list_end)
-			ftrace_trace_function = ftrace_list->func;
+		if (ftrace_list->next == &ftrace_list_end) {
+			ftrace_func_t func = ftrace_list->func;
+
+			if (ftrace_pid_trace) {
+				set_ftrace_pid_function(func);
+				func = ftrace_pid_func;
+			}
+#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
+			ftrace_trace_function = func;
+#else
+			__ftrace_trace_function = func;
+#endif
+		}
 	}
 
  out:
@@ -163,6 +228,36 @@
 	return ret;
 }
 
+static void ftrace_update_pid_func(void)
+{
+	ftrace_func_t func;
+
+	/* should not be called from interrupt context */
+	spin_lock(&ftrace_lock);
+
+	if (ftrace_trace_function == ftrace_stub)
+		goto out;
+
+	func = ftrace_trace_function;
+
+	if (ftrace_pid_trace) {
+		set_ftrace_pid_function(func);
+		func = ftrace_pid_func;
+	} else {
+		if (func == ftrace_pid_func)
+			func = ftrace_pid_function;
+	}
+
+#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
+	ftrace_trace_function = func;
+#else
+	__ftrace_trace_function = func;
+#endif
+
+ out:
+	spin_unlock(&ftrace_lock);
+}
+
 #ifdef CONFIG_DYNAMIC_FTRACE
 #ifndef CONFIG_FTRACE_MCOUNT_RECORD
 # error Dynamic ftrace depends on MCOUNT_RECORD
@@ -182,6 +277,8 @@
 	FTRACE_UPDATE_TRACE_FUNC	= (1 << 2),
 	FTRACE_ENABLE_MCOUNT		= (1 << 3),
 	FTRACE_DISABLE_MCOUNT		= (1 << 4),
+	FTRACE_START_FUNC_RET		= (1 << 5),
+	FTRACE_STOP_FUNC_RET		= (1 << 6),
 };
 
 static int ftrace_filtered;
@@ -308,7 +405,7 @@
 {
 	struct dyn_ftrace *rec;
 
-	if (!ftrace_enabled || ftrace_disabled)
+	if (ftrace_disabled)
 		return NULL;
 
 	rec = ftrace_alloc_dyn_node(ip);
@@ -322,14 +419,51 @@
 	return rec;
 }
 
-#define FTRACE_ADDR ((long)(ftrace_caller))
+static void print_ip_ins(const char *fmt, unsigned char *p)
+{
+	int i;
+
+	printk(KERN_CONT "%s", fmt);
+
+	for (i = 0; i < MCOUNT_INSN_SIZE; i++)
+		printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
+}
+
+static void ftrace_bug(int failed, unsigned long ip)
+{
+	switch (failed) {
+	case -EFAULT:
+		FTRACE_WARN_ON_ONCE(1);
+		pr_info("ftrace faulted on modifying ");
+		print_ip_sym(ip);
+		break;
+	case -EINVAL:
+		FTRACE_WARN_ON_ONCE(1);
+		pr_info("ftrace failed to modify ");
+		print_ip_sym(ip);
+		print_ip_ins(" actual: ", (unsigned char *)ip);
+		printk(KERN_CONT "\n");
+		break;
+	case -EPERM:
+		FTRACE_WARN_ON_ONCE(1);
+		pr_info("ftrace faulted on writing ");
+		print_ip_sym(ip);
+		break;
+	default:
+		FTRACE_WARN_ON_ONCE(1);
+		pr_info("ftrace faulted on unknown error ");
+		print_ip_sym(ip);
+	}
+}
+
 
 static int
-__ftrace_replace_code(struct dyn_ftrace *rec,
-		      unsigned char *nop, int enable)
+__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
 {
 	unsigned long ip, fl;
-	unsigned char *call, *old, *new;
+	unsigned long ftrace_addr;
+
+	ftrace_addr = (unsigned long)ftrace_caller;
 
 	ip = rec->ip;
 
@@ -388,34 +522,28 @@
 		}
 	}
 
-	call = ftrace_call_replace(ip, FTRACE_ADDR);
-
-	if (rec->flags & FTRACE_FL_ENABLED) {
-		old = nop;
-		new = call;
-	} else {
-		old = call;
-		new = nop;
-	}
-
-	return ftrace_modify_code(ip, old, new);
+	if (rec->flags & FTRACE_FL_ENABLED)
+		return ftrace_make_call(rec, ftrace_addr);
+	else
+		return ftrace_make_nop(NULL, rec, ftrace_addr);
 }
 
 static void ftrace_replace_code(int enable)
 {
 	int i, failed;
-	unsigned char *nop = NULL;
 	struct dyn_ftrace *rec;
 	struct ftrace_page *pg;
 
-	nop = ftrace_nop_replace();
-
 	for (pg = ftrace_pages_start; pg; pg = pg->next) {
 		for (i = 0; i < pg->index; i++) {
 			rec = &pg->records[i];
 
-			/* don't modify code that has already faulted */
-			if (rec->flags & FTRACE_FL_FAILED)
+			/*
+			 * Skip over free records and records that have
+			 * failed.
+			 */
+			if (rec->flags & FTRACE_FL_FREE ||
+			    rec->flags & FTRACE_FL_FAILED)
 				continue;
 
 			/* ignore updates to this record's mcount site */
@@ -426,68 +554,30 @@
 				unfreeze_record(rec);
 			}
 
-			failed = __ftrace_replace_code(rec, nop, enable);
+			failed = __ftrace_replace_code(rec, enable);
 			if (failed && (rec->flags & FTRACE_FL_CONVERTED)) {
 				rec->flags |= FTRACE_FL_FAILED;
 				if ((system_state == SYSTEM_BOOTING) ||
 				    !core_kernel_text(rec->ip)) {
 					ftrace_free_rec(rec);
-				}
+				} else
+					ftrace_bug(failed, rec->ip);
 			}
 		}
 	}
 }
 
-static void print_ip_ins(const char *fmt, unsigned char *p)
-{
-	int i;
-
-	printk(KERN_CONT "%s", fmt);
-
-	for (i = 0; i < MCOUNT_INSN_SIZE; i++)
-		printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
-}
-
 static int
-ftrace_code_disable(struct dyn_ftrace *rec)
+ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec)
 {
 	unsigned long ip;
-	unsigned char *nop, *call;
 	int ret;
 
 	ip = rec->ip;
 
-	nop = ftrace_nop_replace();
-	call = ftrace_call_replace(ip, mcount_addr);
-
-	ret = ftrace_modify_code(ip, call, nop);
+	ret = ftrace_make_nop(mod, rec, mcount_addr);
 	if (ret) {
-		switch (ret) {
-		case -EFAULT:
-			FTRACE_WARN_ON_ONCE(1);
-			pr_info("ftrace faulted on modifying ");
-			print_ip_sym(ip);
-			break;
-		case -EINVAL:
-			FTRACE_WARN_ON_ONCE(1);
-			pr_info("ftrace failed to modify ");
-			print_ip_sym(ip);
-			print_ip_ins(" expected: ", call);
-			print_ip_ins(" actual: ", (unsigned char *)ip);
-			print_ip_ins(" replace: ", nop);
-			printk(KERN_CONT "\n");
-			break;
-		case -EPERM:
-			FTRACE_WARN_ON_ONCE(1);
-			pr_info("ftrace faulted on writing ");
-			print_ip_sym(ip);
-			break;
-		default:
-			FTRACE_WARN_ON_ONCE(1);
-			pr_info("ftrace faulted on unknown error ");
-			print_ip_sym(ip);
-		}
-
+		ftrace_bug(ret, ip);
 		rec->flags |= FTRACE_FL_FAILED;
 		return 0;
 	}
@@ -506,6 +596,11 @@
 	if (*command & FTRACE_UPDATE_TRACE_FUNC)
 		ftrace_update_ftrace_func(ftrace_trace_function);
 
+	if (*command & FTRACE_START_FUNC_RET)
+		ftrace_enable_ftrace_graph_caller();
+	else if (*command & FTRACE_STOP_FUNC_RET)
+		ftrace_disable_ftrace_graph_caller();
+
 	return 0;
 }
 
@@ -515,43 +610,43 @@
 }
 
 static ftrace_func_t saved_ftrace_func;
-static int ftrace_start;
-static DEFINE_MUTEX(ftrace_start_lock);
+static int ftrace_start_up;
 
-static void ftrace_startup(void)
+static void ftrace_startup_enable(int command)
 {
-	int command = 0;
-
-	if (unlikely(ftrace_disabled))
-		return;
-
-	mutex_lock(&ftrace_start_lock);
-	ftrace_start++;
-	command |= FTRACE_ENABLE_CALLS;
-
 	if (saved_ftrace_func != ftrace_trace_function) {
 		saved_ftrace_func = ftrace_trace_function;
 		command |= FTRACE_UPDATE_TRACE_FUNC;
 	}
 
 	if (!command || !ftrace_enabled)
-		goto out;
+		return;
 
 	ftrace_run_update_code(command);
- out:
-	mutex_unlock(&ftrace_start_lock);
 }
 
-static void ftrace_shutdown(void)
+static void ftrace_startup(int command)
 {
-	int command = 0;
-
 	if (unlikely(ftrace_disabled))
 		return;
 
 	mutex_lock(&ftrace_start_lock);
-	ftrace_start--;
-	if (!ftrace_start)
+	ftrace_start_up++;
+	command |= FTRACE_ENABLE_CALLS;
+
+	ftrace_startup_enable(command);
+
+	mutex_unlock(&ftrace_start_lock);
+}
+
+static void ftrace_shutdown(int command)
+{
+	if (unlikely(ftrace_disabled))
+		return;
+
+	mutex_lock(&ftrace_start_lock);
+	ftrace_start_up--;
+	if (!ftrace_start_up)
 		command |= FTRACE_DISABLE_CALLS;
 
 	if (saved_ftrace_func != ftrace_trace_function) {
@@ -577,8 +672,8 @@
 	mutex_lock(&ftrace_start_lock);
 	/* Force update next time */
 	saved_ftrace_func = NULL;
-	/* ftrace_start is true if we want ftrace running */
-	if (ftrace_start)
+	/* ftrace_start_up is true if we want ftrace running */
+	if (ftrace_start_up)
 		command |= FTRACE_ENABLE_CALLS;
 
 	ftrace_run_update_code(command);
@@ -593,8 +688,8 @@
 		return;
 
 	mutex_lock(&ftrace_start_lock);
-	/* ftrace_start is true if ftrace is running */
-	if (ftrace_start)
+	/* ftrace_start_up is true if ftrace is running */
+	if (ftrace_start_up)
 		command |= FTRACE_DISABLE_CALLS;
 
 	ftrace_run_update_code(command);
@@ -605,7 +700,7 @@
 static unsigned long	ftrace_update_cnt;
 unsigned long		ftrace_update_tot_cnt;
 
-static int ftrace_update_code(void)
+static int ftrace_update_code(struct module *mod)
 {
 	struct dyn_ftrace *p, *t;
 	cycle_t start, stop;
@@ -622,7 +717,7 @@
 		list_del_init(&p->list);
 
 		/* convert record (i.e, patch mcount-call with NOP) */
-		if (ftrace_code_disable(p)) {
+		if (ftrace_code_disable(mod, p)) {
 			p->flags |= FTRACE_FL_CONVERTED;
 			ftrace_update_cnt++;
 		} else
@@ -690,7 +785,6 @@
 #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */
 
 struct ftrace_iterator {
-	loff_t			pos;
 	struct ftrace_page	*pg;
 	unsigned		idx;
 	unsigned		flags;
@@ -715,6 +809,8 @@
 			iter->pg = iter->pg->next;
 			iter->idx = 0;
 			goto retry;
+		} else {
+			iter->idx = -1;
 		}
 	} else {
 		rec = &iter->pg->records[iter->idx++];
@@ -737,8 +833,6 @@
 	}
 	spin_unlock(&ftrace_lock);
 
-	iter->pos = *pos;
-
 	return rec;
 }
 
@@ -746,13 +840,15 @@
 {
 	struct ftrace_iterator *iter = m->private;
 	void *p = NULL;
-	loff_t l = -1;
 
-	if (*pos > iter->pos)
-		*pos = iter->pos;
+	if (*pos > 0) {
+		if (iter->idx < 0)
+			return p;
+		(*pos)--;
+		iter->idx--;
+	}
 
-	l = *pos;
-	p = t_next(m, p, &l);
+	p = t_next(m, p, pos);
 
 	return p;
 }
@@ -763,21 +859,15 @@
 
 static int t_show(struct seq_file *m, void *v)
 {
-	struct ftrace_iterator *iter = m->private;
 	struct dyn_ftrace *rec = v;
 	char str[KSYM_SYMBOL_LEN];
-	int ret = 0;
 
 	if (!rec)
 		return 0;
 
 	kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
 
-	ret = seq_printf(m, "%s\n", str);
-	if (ret < 0) {
-		iter->pos--;
-		iter->idx--;
-	}
+	seq_printf(m, "%s\n", str);
 
 	return 0;
 }
@@ -803,7 +893,6 @@
 		return -ENOMEM;
 
 	iter->pg = ftrace_pages_start;
-	iter->pos = 0;
 
 	ret = seq_open(file, &show_ftrace_seq_ops);
 	if (!ret) {
@@ -890,7 +979,6 @@
 
 	if (file->f_mode & FMODE_READ) {
 		iter->pg = ftrace_pages_start;
-		iter->pos = 0;
 		iter->flags = enable ? FTRACE_ITER_FILTER :
 			FTRACE_ITER_NOTRACE;
 
@@ -959,6 +1047,13 @@
 	int type = MATCH_FULL;
 	unsigned long flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
 	unsigned i, match = 0, search_len = 0;
+	int not = 0;
+
+	if (buff[0] == '!') {
+		not = 1;
+		buff++;
+		len--;
+	}
 
 	for (i = 0; i < len; i++) {
 		if (buff[i] == '*') {
@@ -1012,8 +1107,12 @@
 					matched = 1;
 				break;
 			}
-			if (matched)
-				rec->flags |= flag;
+			if (matched) {
+				if (not)
+					rec->flags &= ~flag;
+				else
+					rec->flags |= flag;
+			}
 		}
 		pg = pg->next;
 	}
@@ -1181,7 +1280,7 @@
 
 	mutex_lock(&ftrace_sysctl_lock);
 	mutex_lock(&ftrace_start_lock);
-	if (ftrace_start && ftrace_enabled)
+	if (ftrace_start_up && ftrace_enabled)
 		ftrace_run_update_code(FTRACE_ENABLE_CALLS);
 	mutex_unlock(&ftrace_start_lock);
 	mutex_unlock(&ftrace_sysctl_lock);
@@ -1233,12 +1332,233 @@
 	.release = ftrace_notrace_release,
 };
 
-static __init int ftrace_init_debugfs(void)
-{
-	struct dentry *d_tracer;
-	struct dentry *entry;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
-	d_tracer = tracing_init_dentry();
+static DEFINE_MUTEX(graph_lock);
+
+int ftrace_graph_count;
+unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly;
+
+static void *
+g_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	unsigned long *array = m->private;
+	int index = *pos;
+
+	(*pos)++;
+
+	if (index >= ftrace_graph_count)
+		return NULL;
+
+	return &array[index];
+}
+
+static void *g_start(struct seq_file *m, loff_t *pos)
+{
+	void *p = NULL;
+
+	mutex_lock(&graph_lock);
+
+	p = g_next(m, p, pos);
+
+	return p;
+}
+
+static void g_stop(struct seq_file *m, void *p)
+{
+	mutex_unlock(&graph_lock);
+}
+
+static int g_show(struct seq_file *m, void *v)
+{
+	unsigned long *ptr = v;
+	char str[KSYM_SYMBOL_LEN];
+
+	if (!ptr)
+		return 0;
+
+	kallsyms_lookup(*ptr, NULL, NULL, NULL, str);
+
+	seq_printf(m, "%s\n", str);
+
+	return 0;
+}
+
+static struct seq_operations ftrace_graph_seq_ops = {
+	.start = g_start,
+	.next = g_next,
+	.stop = g_stop,
+	.show = g_show,
+};
+
+static int
+ftrace_graph_open(struct inode *inode, struct file *file)
+{
+	int ret = 0;
+
+	if (unlikely(ftrace_disabled))
+		return -ENODEV;
+
+	mutex_lock(&graph_lock);
+	if ((file->f_mode & FMODE_WRITE) &&
+	    !(file->f_flags & O_APPEND)) {
+		ftrace_graph_count = 0;
+		memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs));
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		ret = seq_open(file, &ftrace_graph_seq_ops);
+		if (!ret) {
+			struct seq_file *m = file->private_data;
+			m->private = ftrace_graph_funcs;
+		}
+	} else
+		file->private_data = ftrace_graph_funcs;
+	mutex_unlock(&graph_lock);
+
+	return ret;
+}
+
+static ssize_t
+ftrace_graph_read(struct file *file, char __user *ubuf,
+		       size_t cnt, loff_t *ppos)
+{
+	if (file->f_mode & FMODE_READ)
+		return seq_read(file, ubuf, cnt, ppos);
+	else
+		return -EPERM;
+}
+
+static int
+ftrace_set_func(unsigned long *array, int idx, char *buffer)
+{
+	char str[KSYM_SYMBOL_LEN];
+	struct dyn_ftrace *rec;
+	struct ftrace_page *pg;
+	int found = 0;
+	int i, j;
+
+	if (ftrace_disabled)
+		return -ENODEV;
+
+	/* should not be called from interrupt context */
+	spin_lock(&ftrace_lock);
+
+	for (pg = ftrace_pages_start; pg; pg = pg->next) {
+		for (i = 0; i < pg->index; i++) {
+			rec = &pg->records[i];
+
+			if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE))
+				continue;
+
+			kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
+			if (strcmp(str, buffer) == 0) {
+				found = 1;
+				for (j = 0; j < idx; j++)
+					if (array[j] == rec->ip) {
+						found = 0;
+						break;
+					}
+				if (found)
+					array[idx] = rec->ip;
+				break;
+			}
+		}
+	}
+	spin_unlock(&ftrace_lock);
+
+	return found ? 0 : -EINVAL;
+}
+
+static ssize_t
+ftrace_graph_write(struct file *file, const char __user *ubuf,
+		   size_t cnt, loff_t *ppos)
+{
+	unsigned char buffer[FTRACE_BUFF_MAX+1];
+	unsigned long *array;
+	size_t read = 0;
+	ssize_t ret;
+	int index = 0;
+	char ch;
+
+	if (!cnt || cnt < 0)
+		return 0;
+
+	mutex_lock(&graph_lock);
+
+	if (ftrace_graph_count >= FTRACE_GRAPH_MAX_FUNCS) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		struct seq_file *m = file->private_data;
+		array = m->private;
+	} else
+		array = file->private_data;
+
+	ret = get_user(ch, ubuf++);
+	if (ret)
+		goto out;
+	read++;
+	cnt--;
+
+	/* skip white space */
+	while (cnt && isspace(ch)) {
+		ret = get_user(ch, ubuf++);
+		if (ret)
+			goto out;
+		read++;
+		cnt--;
+	}
+
+	if (isspace(ch)) {
+		*ppos += read;
+		ret = read;
+		goto out;
+	}
+
+	while (cnt && !isspace(ch)) {
+		if (index < FTRACE_BUFF_MAX)
+			buffer[index++] = ch;
+		else {
+			ret = -EINVAL;
+			goto out;
+		}
+		ret = get_user(ch, ubuf++);
+		if (ret)
+			goto out;
+		read++;
+		cnt--;
+	}
+	buffer[index] = 0;
+
+	/* we allow only one at a time */
+	ret = ftrace_set_func(array, ftrace_graph_count, buffer);
+	if (ret)
+		goto out;
+
+	ftrace_graph_count++;
+
+	file->f_pos += read;
+
+	ret = read;
+ out:
+	mutex_unlock(&graph_lock);
+
+	return ret;
+}
+
+static const struct file_operations ftrace_graph_fops = {
+	.open = ftrace_graph_open,
+	.read = ftrace_graph_read,
+	.write = ftrace_graph_write,
+};
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
+{
+	struct dentry *entry;
 
 	entry = debugfs_create_file("available_filter_functions", 0444,
 				    d_tracer, NULL, &ftrace_avail_fops);
@@ -1263,12 +1583,20 @@
 		pr_warning("Could not create debugfs "
 			   "'set_ftrace_notrace' entry\n");
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	entry = debugfs_create_file("set_graph_function", 0444, d_tracer,
+				    NULL,
+				    &ftrace_graph_fops);
+	if (!entry)
+		pr_warning("Could not create debugfs "
+			   "'set_graph_function' entry\n");
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
 	return 0;
 }
 
-fs_initcall(ftrace_init_debugfs);
-
-static int ftrace_convert_nops(unsigned long *start,
+static int ftrace_convert_nops(struct module *mod,
+			       unsigned long *start,
 			       unsigned long *end)
 {
 	unsigned long *p;
@@ -1279,23 +1607,32 @@
 	p = start;
 	while (p < end) {
 		addr = ftrace_call_adjust(*p++);
+		/*
+		 * Some architecture linkers will pad between
+		 * the different mcount_loc sections of different
+		 * object files to satisfy alignments.
+		 * Skip any NULL pointers.
+		 */
+		if (!addr)
+			continue;
 		ftrace_record_ip(addr);
 	}
 
 	/* disable interrupts to prevent kstop machine */
 	local_irq_save(flags);
-	ftrace_update_code();
+	ftrace_update_code(mod);
 	local_irq_restore(flags);
 	mutex_unlock(&ftrace_start_lock);
 
 	return 0;
 }
 
-void ftrace_init_module(unsigned long *start, unsigned long *end)
+void ftrace_init_module(struct module *mod,
+			unsigned long *start, unsigned long *end)
 {
 	if (ftrace_disabled || start == end)
 		return;
-	ftrace_convert_nops(start, end);
+	ftrace_convert_nops(mod, start, end);
 }
 
 extern unsigned long __start_mcount_loc[];
@@ -1325,7 +1662,8 @@
 
 	last_ftrace_enabled = ftrace_enabled = 1;
 
-	ret = ftrace_convert_nops(__start_mcount_loc,
+	ret = ftrace_convert_nops(NULL,
+				  __start_mcount_loc,
 				  __stop_mcount_loc);
 
 	return;
@@ -1342,12 +1680,186 @@
 }
 device_initcall(ftrace_nodyn_init);
 
-# define ftrace_startup()		do { } while (0)
-# define ftrace_shutdown()		do { } while (0)
+static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; }
+static inline void ftrace_startup_enable(int command) { }
+/* Keep as macros so we do not need to define the commands */
+# define ftrace_startup(command)	do { } while (0)
+# define ftrace_shutdown(command)	do { } while (0)
 # define ftrace_startup_sysctl()	do { } while (0)
 # define ftrace_shutdown_sysctl()	do { } while (0)
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
+static ssize_t
+ftrace_pid_read(struct file *file, char __user *ubuf,
+		       size_t cnt, loff_t *ppos)
+{
+	char buf[64];
+	int r;
+
+	if (ftrace_pid_trace == ftrace_swapper_pid)
+		r = sprintf(buf, "swapper tasks\n");
+	else if (ftrace_pid_trace)
+		r = sprintf(buf, "%u\n", pid_nr(ftrace_pid_trace));
+	else
+		r = sprintf(buf, "no pid\n");
+
+	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+}
+
+static void clear_ftrace_swapper(void)
+{
+	struct task_struct *p;
+	int cpu;
+
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		p = idle_task(cpu);
+		clear_tsk_trace_trace(p);
+	}
+	put_online_cpus();
+}
+
+static void set_ftrace_swapper(void)
+{
+	struct task_struct *p;
+	int cpu;
+
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		p = idle_task(cpu);
+		set_tsk_trace_trace(p);
+	}
+	put_online_cpus();
+}
+
+static void clear_ftrace_pid(struct pid *pid)
+{
+	struct task_struct *p;
+
+	do_each_pid_task(pid, PIDTYPE_PID, p) {
+		clear_tsk_trace_trace(p);
+	} while_each_pid_task(pid, PIDTYPE_PID, p);
+	put_pid(pid);
+}
+
+static void set_ftrace_pid(struct pid *pid)
+{
+	struct task_struct *p;
+
+	do_each_pid_task(pid, PIDTYPE_PID, p) {
+		set_tsk_trace_trace(p);
+	} while_each_pid_task(pid, PIDTYPE_PID, p);
+}
+
+static void clear_ftrace_pid_task(struct pid **pid)
+{
+	if (*pid == ftrace_swapper_pid)
+		clear_ftrace_swapper();
+	else
+		clear_ftrace_pid(*pid);
+
+	*pid = NULL;
+}
+
+static void set_ftrace_pid_task(struct pid *pid)
+{
+	if (pid == ftrace_swapper_pid)
+		set_ftrace_swapper();
+	else
+		set_ftrace_pid(pid);
+}
+
+static ssize_t
+ftrace_pid_write(struct file *filp, const char __user *ubuf,
+		   size_t cnt, loff_t *ppos)
+{
+	struct pid *pid;
+	char buf[64];
+	long val;
+	int ret;
+
+	if (cnt >= sizeof(buf))
+		return -EINVAL;
+
+	if (copy_from_user(&buf, ubuf, cnt))
+		return -EFAULT;
+
+	buf[cnt] = 0;
+
+	ret = strict_strtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&ftrace_start_lock);
+	if (val < 0) {
+		/* disable pid tracing */
+		if (!ftrace_pid_trace)
+			goto out;
+
+		clear_ftrace_pid_task(&ftrace_pid_trace);
+
+	} else {
+		/* swapper task is special */
+		if (!val) {
+			pid = ftrace_swapper_pid;
+			if (pid == ftrace_pid_trace)
+				goto out;
+		} else {
+			pid = find_get_pid(val);
+
+			if (pid == ftrace_pid_trace) {
+				put_pid(pid);
+				goto out;
+			}
+		}
+
+		if (ftrace_pid_trace)
+			clear_ftrace_pid_task(&ftrace_pid_trace);
+
+		if (!pid)
+			goto out;
+
+		ftrace_pid_trace = pid;
+
+		set_ftrace_pid_task(ftrace_pid_trace);
+	}
+
+	/* update the function call */
+	ftrace_update_pid_func();
+	ftrace_startup_enable(0);
+
+ out:
+	mutex_unlock(&ftrace_start_lock);
+
+	return cnt;
+}
+
+static struct file_operations ftrace_pid_fops = {
+	.read = ftrace_pid_read,
+	.write = ftrace_pid_write,
+};
+
+static __init int ftrace_init_debugfs(void)
+{
+	struct dentry *d_tracer;
+	struct dentry *entry;
+
+	d_tracer = tracing_init_dentry();
+	if (!d_tracer)
+		return 0;
+
+	ftrace_init_dyn_debugfs(d_tracer);
+
+	entry = debugfs_create_file("set_ftrace_pid", 0644, d_tracer,
+				    NULL, &ftrace_pid_fops);
+	if (!entry)
+		pr_warning("Could not create debugfs "
+			   "'set_ftrace_pid' entry\n");
+	return 0;
+}
+
+fs_initcall(ftrace_init_debugfs);
+
 /**
  * ftrace_kill - kill ftrace
  *
@@ -1381,10 +1893,11 @@
 		return -1;
 
 	mutex_lock(&ftrace_sysctl_lock);
-	ret = __register_ftrace_function(ops);
-	ftrace_startup();
-	mutex_unlock(&ftrace_sysctl_lock);
 
+	ret = __register_ftrace_function(ops);
+	ftrace_startup(0);
+
+	mutex_unlock(&ftrace_sysctl_lock);
 	return ret;
 }
 
@@ -1400,7 +1913,7 @@
 
 	mutex_lock(&ftrace_sysctl_lock);
 	ret = __unregister_ftrace_function(ops);
-	ftrace_shutdown();
+	ftrace_shutdown(0);
 	mutex_unlock(&ftrace_sysctl_lock);
 
 	return ret;
@@ -1449,3 +1962,153 @@
 	return ret;
 }
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+static atomic_t ftrace_graph_active;
+
+int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
+{
+	return 0;
+}
+
+/* The callbacks that hook a function */
+trace_func_graph_ret_t ftrace_graph_return =
+			(trace_func_graph_ret_t)ftrace_stub;
+trace_func_graph_ent_t ftrace_graph_entry = ftrace_graph_entry_stub;
+
+/* Try to assign a return stack array on FTRACE_RETSTACK_ALLOC_SIZE tasks. */
+static int alloc_retstack_tasklist(struct ftrace_ret_stack **ret_stack_list)
+{
+	int i;
+	int ret = 0;
+	unsigned long flags;
+	int start = 0, end = FTRACE_RETSTACK_ALLOC_SIZE;
+	struct task_struct *g, *t;
+
+	for (i = 0; i < FTRACE_RETSTACK_ALLOC_SIZE; i++) {
+		ret_stack_list[i] = kmalloc(FTRACE_RETFUNC_DEPTH
+					* sizeof(struct ftrace_ret_stack),
+					GFP_KERNEL);
+		if (!ret_stack_list[i]) {
+			start = 0;
+			end = i;
+			ret = -ENOMEM;
+			goto free;
+		}
+	}
+
+	read_lock_irqsave(&tasklist_lock, flags);
+	do_each_thread(g, t) {
+		if (start == end) {
+			ret = -EAGAIN;
+			goto unlock;
+		}
+
+		if (t->ret_stack == NULL) {
+			t->curr_ret_stack = -1;
+			/* Make sure IRQs see the -1 first: */
+			barrier();
+			t->ret_stack = ret_stack_list[start++];
+			atomic_set(&t->tracing_graph_pause, 0);
+			atomic_set(&t->trace_overrun, 0);
+		}
+	} while_each_thread(g, t);
+
+unlock:
+	read_unlock_irqrestore(&tasklist_lock, flags);
+free:
+	for (i = start; i < end; i++)
+		kfree(ret_stack_list[i]);
+	return ret;
+}
+
+/* Allocate a return stack for each task */
+static int start_graph_tracing(void)
+{
+	struct ftrace_ret_stack **ret_stack_list;
+	int ret;
+
+	ret_stack_list = kmalloc(FTRACE_RETSTACK_ALLOC_SIZE *
+				sizeof(struct ftrace_ret_stack *),
+				GFP_KERNEL);
+
+	if (!ret_stack_list)
+		return -ENOMEM;
+
+	do {
+		ret = alloc_retstack_tasklist(ret_stack_list);
+	} while (ret == -EAGAIN);
+
+	kfree(ret_stack_list);
+	return ret;
+}
+
+int register_ftrace_graph(trace_func_graph_ret_t retfunc,
+			trace_func_graph_ent_t entryfunc)
+{
+	int ret = 0;
+
+	mutex_lock(&ftrace_sysctl_lock);
+
+	atomic_inc(&ftrace_graph_active);
+	ret = start_graph_tracing();
+	if (ret) {
+		atomic_dec(&ftrace_graph_active);
+		goto out;
+	}
+
+	ftrace_graph_return = retfunc;
+	ftrace_graph_entry = entryfunc;
+
+	ftrace_startup(FTRACE_START_FUNC_RET);
+
+out:
+	mutex_unlock(&ftrace_sysctl_lock);
+	return ret;
+}
+
+void unregister_ftrace_graph(void)
+{
+	mutex_lock(&ftrace_sysctl_lock);
+
+	atomic_dec(&ftrace_graph_active);
+	ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;
+	ftrace_graph_entry = ftrace_graph_entry_stub;
+	ftrace_shutdown(FTRACE_STOP_FUNC_RET);
+
+	mutex_unlock(&ftrace_sysctl_lock);
+}
+
+/* Allocate a return stack for newly created task */
+void ftrace_graph_init_task(struct task_struct *t)
+{
+	if (atomic_read(&ftrace_graph_active)) {
+		t->ret_stack = kmalloc(FTRACE_RETFUNC_DEPTH
+				* sizeof(struct ftrace_ret_stack),
+				GFP_KERNEL);
+		if (!t->ret_stack)
+			return;
+		t->curr_ret_stack = -1;
+		atomic_set(&t->tracing_graph_pause, 0);
+		atomic_set(&t->trace_overrun, 0);
+	} else
+		t->ret_stack = NULL;
+}
+
+void ftrace_graph_exit_task(struct task_struct *t)
+{
+	struct ftrace_ret_stack	*ret_stack = t->ret_stack;
+
+	t->ret_stack = NULL;
+	/* NULL must become visible to IRQs before we free it: */
+	barrier();
+
+	kfree(ret_stack);
+}
+
+void ftrace_graph_stop(void)
+{
+	ftrace_stop();
+}
+#endif
+
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 668bbb5..76f34c0 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -18,8 +18,46 @@
 
 #include "trace.h"
 
-/* Global flag to disable all recording to ring buffers */
-static int ring_buffers_off __read_mostly;
+/*
+ * A fast way to enable or disable all ring buffers is to
+ * call tracing_on or tracing_off. Turning off the ring buffers
+ * prevents all ring buffers from being recorded to.
+ * Turning this switch on, makes it OK to write to the
+ * ring buffer, if the ring buffer is enabled itself.
+ *
+ * There's three layers that must be on in order to write
+ * to the ring buffer.
+ *
+ * 1) This global flag must be set.
+ * 2) The ring buffer must be enabled for recording.
+ * 3) The per cpu buffer must be enabled for recording.
+ *
+ * In case of an anomaly, this global flag has a bit set that
+ * will permantly disable all ring buffers.
+ */
+
+/*
+ * Global flag to disable all recording to ring buffers
+ *  This has two bits: ON, DISABLED
+ *
+ *  ON   DISABLED
+ * ---- ----------
+ *   0      0        : ring buffers are off
+ *   1      0        : ring buffers are on
+ *   X      1        : ring buffers are permanently disabled
+ */
+
+enum {
+	RB_BUFFERS_ON_BIT	= 0,
+	RB_BUFFERS_DISABLED_BIT	= 1,
+};
+
+enum {
+	RB_BUFFERS_ON		= 1 << RB_BUFFERS_ON_BIT,
+	RB_BUFFERS_DISABLED	= 1 << RB_BUFFERS_DISABLED_BIT,
+};
+
+static long ring_buffer_flags __read_mostly = RB_BUFFERS_ON;
 
 /**
  * tracing_on - enable all tracing buffers
@@ -29,7 +67,7 @@
  */
 void tracing_on(void)
 {
-	ring_buffers_off = 0;
+	set_bit(RB_BUFFERS_ON_BIT, &ring_buffer_flags);
 }
 
 /**
@@ -42,9 +80,22 @@
  */
 void tracing_off(void)
 {
-	ring_buffers_off = 1;
+	clear_bit(RB_BUFFERS_ON_BIT, &ring_buffer_flags);
 }
 
+/**
+ * tracing_off_permanent - permanently disable ring buffers
+ *
+ * This function, once called, will disable all ring buffers
+ * permanenty.
+ */
+void tracing_off_permanent(void)
+{
+	set_bit(RB_BUFFERS_DISABLED_BIT, &ring_buffer_flags);
+}
+
+#include "trace.h"
+
 /* Up this if you want to test the TIME_EXTENTS and normalization */
 #define DEBUG_SHIFT 0
 
@@ -56,7 +107,7 @@
 	preempt_disable_notrace();
 	/* shift to debug/test normalization and TIME_EXTENTS */
 	time = sched_clock() << DEBUG_SHIFT;
-	preempt_enable_notrace();
+	preempt_enable_no_resched_notrace();
 
 	return time;
 }
@@ -144,20 +195,24 @@
 #define TS_MASK		((1ULL << TS_SHIFT) - 1)
 #define TS_DELTA_TEST	(~TS_MASK)
 
-/*
- * This hack stolen from mm/slob.c.
- * We can store per page timing information in the page frame of the page.
- * Thanks to Peter Zijlstra for suggesting this idea.
- */
-struct buffer_page {
+struct buffer_data_page {
 	u64		 time_stamp;	/* page time stamp */
-	local_t		 write;		/* index for next write */
 	local_t		 commit;	/* write commited index */
+	unsigned char	 data[];	/* data of buffer page */
+};
+
+struct buffer_page {
+	local_t		 write;		/* index for next write */
 	unsigned	 read;		/* index for next read */
 	struct list_head list;		/* list of free pages */
-	void *page;			/* Actual data page */
+	struct buffer_data_page *page;	/* Actual data page */
 };
 
+static void rb_init_page(struct buffer_data_page *bpage)
+{
+	local_set(&bpage->commit, 0);
+}
+
 /*
  * Also stolen from mm/slob.c. Thanks to Mathieu Desnoyers for pointing
  * this issue out.
@@ -179,7 +234,7 @@
 	return 0;
 }
 
-#define BUF_PAGE_SIZE PAGE_SIZE
+#define BUF_PAGE_SIZE (PAGE_SIZE - sizeof(struct buffer_data_page))
 
 /*
  * head_page == tail_page && head == tail then buffer is empty.
@@ -187,7 +242,8 @@
 struct ring_buffer_per_cpu {
 	int				cpu;
 	struct ring_buffer		*buffer;
-	spinlock_t			lock;
+	spinlock_t			reader_lock; /* serialize readers */
+	raw_spinlock_t			lock;
 	struct lock_class_key		lock_key;
 	struct list_head		pages;
 	struct buffer_page		*head_page;	/* read from head */
@@ -202,7 +258,6 @@
 };
 
 struct ring_buffer {
-	unsigned long			size;
 	unsigned			pages;
 	unsigned			flags;
 	int				cpus;
@@ -221,32 +276,16 @@
 	u64				read_stamp;
 };
 
+/* buffer may be either ring_buffer or ring_buffer_per_cpu */
 #define RB_WARN_ON(buffer, cond)				\
-	do {							\
-		if (unlikely(cond)) {				\
+	({							\
+		int _____ret = unlikely(cond);			\
+		if (_____ret) {					\
 			atomic_inc(&buffer->record_disabled);	\
 			WARN_ON(1);				\
 		}						\
-	} while (0)
-
-#define RB_WARN_ON_RET(buffer, cond)				\
-	do {							\
-		if (unlikely(cond)) {				\
-			atomic_inc(&buffer->record_disabled);	\
-			WARN_ON(1);				\
-			return -1;				\
-		}						\
-	} while (0)
-
-#define RB_WARN_ON_ONCE(buffer, cond)				\
-	do {							\
-		static int once;				\
-		if (unlikely(cond) && !once) {			\
-			once++;					\
-			atomic_inc(&buffer->record_disabled);	\
-			WARN_ON(1);				\
-		}						\
-	} while (0)
+		_____ret;					\
+	})
 
 /**
  * check_pages - integrity check of buffer pages
@@ -258,16 +297,20 @@
 static int rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer)
 {
 	struct list_head *head = &cpu_buffer->pages;
-	struct buffer_page *page, *tmp;
+	struct buffer_page *bpage, *tmp;
 
-	RB_WARN_ON_RET(cpu_buffer, head->next->prev != head);
-	RB_WARN_ON_RET(cpu_buffer, head->prev->next != head);
+	if (RB_WARN_ON(cpu_buffer, head->next->prev != head))
+		return -1;
+	if (RB_WARN_ON(cpu_buffer, head->prev->next != head))
+		return -1;
 
-	list_for_each_entry_safe(page, tmp, head, list) {
-		RB_WARN_ON_RET(cpu_buffer,
-			       page->list.next->prev != &page->list);
-		RB_WARN_ON_RET(cpu_buffer,
-			       page->list.prev->next != &page->list);
+	list_for_each_entry_safe(bpage, tmp, head, list) {
+		if (RB_WARN_ON(cpu_buffer,
+			       bpage->list.next->prev != &bpage->list))
+			return -1;
+		if (RB_WARN_ON(cpu_buffer,
+			       bpage->list.prev->next != &bpage->list))
+			return -1;
 	}
 
 	return 0;
@@ -277,22 +320,23 @@
 			     unsigned nr_pages)
 {
 	struct list_head *head = &cpu_buffer->pages;
-	struct buffer_page *page, *tmp;
+	struct buffer_page *bpage, *tmp;
 	unsigned long addr;
 	LIST_HEAD(pages);
 	unsigned i;
 
 	for (i = 0; i < nr_pages; i++) {
-		page = kzalloc_node(ALIGN(sizeof(*page), cache_line_size()),
+		bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
 				    GFP_KERNEL, cpu_to_node(cpu_buffer->cpu));
-		if (!page)
+		if (!bpage)
 			goto free_pages;
-		list_add(&page->list, &pages);
+		list_add(&bpage->list, &pages);
 
 		addr = __get_free_page(GFP_KERNEL);
 		if (!addr)
 			goto free_pages;
-		page->page = (void *)addr;
+		bpage->page = (void *)addr;
+		rb_init_page(bpage->page);
 	}
 
 	list_splice(&pages, head);
@@ -302,9 +346,9 @@
 	return 0;
 
  free_pages:
-	list_for_each_entry_safe(page, tmp, &pages, list) {
-		list_del_init(&page->list);
-		free_buffer_page(page);
+	list_for_each_entry_safe(bpage, tmp, &pages, list) {
+		list_del_init(&bpage->list);
+		free_buffer_page(bpage);
 	}
 	return -ENOMEM;
 }
@@ -313,7 +357,7 @@
 rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
-	struct buffer_page *page;
+	struct buffer_page *bpage;
 	unsigned long addr;
 	int ret;
 
@@ -324,19 +368,21 @@
 
 	cpu_buffer->cpu = cpu;
 	cpu_buffer->buffer = buffer;
-	spin_lock_init(&cpu_buffer->lock);
+	spin_lock_init(&cpu_buffer->reader_lock);
+	cpu_buffer->lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
 	INIT_LIST_HEAD(&cpu_buffer->pages);
 
-	page = kzalloc_node(ALIGN(sizeof(*page), cache_line_size()),
+	bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
 			    GFP_KERNEL, cpu_to_node(cpu));
-	if (!page)
+	if (!bpage)
 		goto fail_free_buffer;
 
-	cpu_buffer->reader_page = page;
+	cpu_buffer->reader_page = bpage;
 	addr = __get_free_page(GFP_KERNEL);
 	if (!addr)
 		goto fail_free_reader;
-	page->page = (void *)addr;
+	bpage->page = (void *)addr;
+	rb_init_page(bpage->page);
 
 	INIT_LIST_HEAD(&cpu_buffer->reader_page->list);
 
@@ -361,14 +407,14 @@
 static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
 {
 	struct list_head *head = &cpu_buffer->pages;
-	struct buffer_page *page, *tmp;
+	struct buffer_page *bpage, *tmp;
 
 	list_del_init(&cpu_buffer->reader_page->list);
 	free_buffer_page(cpu_buffer->reader_page);
 
-	list_for_each_entry_safe(page, tmp, head, list) {
-		list_del_init(&page->list);
-		free_buffer_page(page);
+	list_for_each_entry_safe(bpage, tmp, head, list) {
+		list_del_init(&bpage->list);
+		free_buffer_page(bpage);
 	}
 	kfree(cpu_buffer);
 }
@@ -465,7 +511,7 @@
 static void
 rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned nr_pages)
 {
-	struct buffer_page *page;
+	struct buffer_page *bpage;
 	struct list_head *p;
 	unsigned i;
 
@@ -473,13 +519,15 @@
 	synchronize_sched();
 
 	for (i = 0; i < nr_pages; i++) {
-		BUG_ON(list_empty(&cpu_buffer->pages));
+		if (RB_WARN_ON(cpu_buffer, list_empty(&cpu_buffer->pages)))
+			return;
 		p = cpu_buffer->pages.next;
-		page = list_entry(p, struct buffer_page, list);
-		list_del_init(&page->list);
-		free_buffer_page(page);
+		bpage = list_entry(p, struct buffer_page, list);
+		list_del_init(&bpage->list);
+		free_buffer_page(bpage);
 	}
-	BUG_ON(list_empty(&cpu_buffer->pages));
+	if (RB_WARN_ON(cpu_buffer, list_empty(&cpu_buffer->pages)))
+		return;
 
 	rb_reset_cpu(cpu_buffer);
 
@@ -493,7 +541,7 @@
 rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer,
 		struct list_head *pages, unsigned nr_pages)
 {
-	struct buffer_page *page;
+	struct buffer_page *bpage;
 	struct list_head *p;
 	unsigned i;
 
@@ -501,11 +549,12 @@
 	synchronize_sched();
 
 	for (i = 0; i < nr_pages; i++) {
-		BUG_ON(list_empty(pages));
+		if (RB_WARN_ON(cpu_buffer, list_empty(pages)))
+			return;
 		p = pages->next;
-		page = list_entry(p, struct buffer_page, list);
-		list_del_init(&page->list);
-		list_add_tail(&page->list, &cpu_buffer->pages);
+		bpage = list_entry(p, struct buffer_page, list);
+		list_del_init(&bpage->list);
+		list_add_tail(&bpage->list, &cpu_buffer->pages);
 	}
 	rb_reset_cpu(cpu_buffer);
 
@@ -532,7 +581,7 @@
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
 	unsigned nr_pages, rm_pages, new_pages;
-	struct buffer_page *page, *tmp;
+	struct buffer_page *bpage, *tmp;
 	unsigned long buffer_size;
 	unsigned long addr;
 	LIST_HEAD(pages);
@@ -562,7 +611,10 @@
 	if (size < buffer_size) {
 
 		/* easy case, just free pages */
-		BUG_ON(nr_pages >= buffer->pages);
+		if (RB_WARN_ON(buffer, nr_pages >= buffer->pages)) {
+			mutex_unlock(&buffer->mutex);
+			return -1;
+		}
 
 		rm_pages = buffer->pages - nr_pages;
 
@@ -581,21 +633,26 @@
 	 * add these pages to the cpu_buffers. Otherwise we just free
 	 * them all and return -ENOMEM;
 	 */
-	BUG_ON(nr_pages <= buffer->pages);
+	if (RB_WARN_ON(buffer, nr_pages <= buffer->pages)) {
+		mutex_unlock(&buffer->mutex);
+		return -1;
+	}
+
 	new_pages = nr_pages - buffer->pages;
 
 	for_each_buffer_cpu(buffer, cpu) {
 		for (i = 0; i < new_pages; i++) {
-			page = kzalloc_node(ALIGN(sizeof(*page),
+			bpage = kzalloc_node(ALIGN(sizeof(*bpage),
 						  cache_line_size()),
 					    GFP_KERNEL, cpu_to_node(cpu));
-			if (!page)
+			if (!bpage)
 				goto free_pages;
-			list_add(&page->list, &pages);
+			list_add(&bpage->list, &pages);
 			addr = __get_free_page(GFP_KERNEL);
 			if (!addr)
 				goto free_pages;
-			page->page = (void *)addr;
+			bpage->page = (void *)addr;
+			rb_init_page(bpage->page);
 		}
 	}
 
@@ -604,7 +661,10 @@
 		rb_insert_pages(cpu_buffer, &pages, new_pages);
 	}
 
-	BUG_ON(!list_empty(&pages));
+	if (RB_WARN_ON(buffer, !list_empty(&pages))) {
+		mutex_unlock(&buffer->mutex);
+		return -1;
+	}
 
  out:
 	buffer->pages = nr_pages;
@@ -613,9 +673,9 @@
 	return size;
 
  free_pages:
-	list_for_each_entry_safe(page, tmp, &pages, list) {
-		list_del_init(&page->list);
-		free_buffer_page(page);
+	list_for_each_entry_safe(bpage, tmp, &pages, list) {
+		list_del_init(&bpage->list);
+		free_buffer_page(bpage);
 	}
 	mutex_unlock(&buffer->mutex);
 	return -ENOMEM;
@@ -626,9 +686,15 @@
 	return event->type == RINGBUF_TYPE_PADDING;
 }
 
-static inline void *__rb_page_index(struct buffer_page *page, unsigned index)
+static inline void *
+__rb_data_page_index(struct buffer_data_page *bpage, unsigned index)
 {
-	return page->page + index;
+	return bpage->data + index;
+}
+
+static inline void *__rb_page_index(struct buffer_page *bpage, unsigned index)
+{
+	return bpage->page->data + index;
 }
 
 static inline struct ring_buffer_event *
@@ -658,7 +724,7 @@
 
 static inline unsigned rb_page_commit(struct buffer_page *bpage)
 {
-	return local_read(&bpage->commit);
+	return local_read(&bpage->page->commit);
 }
 
 /* Size is determined by what has been commited */
@@ -693,7 +759,8 @@
 	     head += rb_event_length(event)) {
 
 		event = __rb_page_index(cpu_buffer->head_page, head);
-		BUG_ON(rb_null_event(event));
+		if (RB_WARN_ON(cpu_buffer, rb_null_event(event)))
+			return;
 		/* Only count data entries */
 		if (event->type != RINGBUF_TYPE_DATA)
 			continue;
@@ -703,14 +770,14 @@
 }
 
 static inline void rb_inc_page(struct ring_buffer_per_cpu *cpu_buffer,
-			       struct buffer_page **page)
+			       struct buffer_page **bpage)
 {
-	struct list_head *p = (*page)->list.next;
+	struct list_head *p = (*bpage)->list.next;
 
 	if (p == &cpu_buffer->pages)
 		p = p->next;
 
-	*page = list_entry(p, struct buffer_page, list);
+	*bpage = list_entry(p, struct buffer_page, list);
 }
 
 static inline unsigned
@@ -746,16 +813,18 @@
 	addr &= PAGE_MASK;
 
 	while (cpu_buffer->commit_page->page != (void *)addr) {
-		RB_WARN_ON(cpu_buffer,
-			   cpu_buffer->commit_page == cpu_buffer->tail_page);
-		cpu_buffer->commit_page->commit =
+		if (RB_WARN_ON(cpu_buffer,
+			  cpu_buffer->commit_page == cpu_buffer->tail_page))
+			return;
+		cpu_buffer->commit_page->page->commit =
 			cpu_buffer->commit_page->write;
 		rb_inc_page(cpu_buffer, &cpu_buffer->commit_page);
-		cpu_buffer->write_stamp = cpu_buffer->commit_page->time_stamp;
+		cpu_buffer->write_stamp =
+			cpu_buffer->commit_page->page->time_stamp;
 	}
 
 	/* Now set the commit to the event's index */
-	local_set(&cpu_buffer->commit_page->commit, index);
+	local_set(&cpu_buffer->commit_page->page->commit, index);
 }
 
 static inline void
@@ -769,25 +838,38 @@
 	 * back to us). This allows us to do a simple loop to
 	 * assign the commit to the tail.
 	 */
+ again:
 	while (cpu_buffer->commit_page != cpu_buffer->tail_page) {
-		cpu_buffer->commit_page->commit =
+		cpu_buffer->commit_page->page->commit =
 			cpu_buffer->commit_page->write;
 		rb_inc_page(cpu_buffer, &cpu_buffer->commit_page);
-		cpu_buffer->write_stamp = cpu_buffer->commit_page->time_stamp;
+		cpu_buffer->write_stamp =
+			cpu_buffer->commit_page->page->time_stamp;
 		/* add barrier to keep gcc from optimizing too much */
 		barrier();
 	}
 	while (rb_commit_index(cpu_buffer) !=
 	       rb_page_write(cpu_buffer->commit_page)) {
-		cpu_buffer->commit_page->commit =
+		cpu_buffer->commit_page->page->commit =
 			cpu_buffer->commit_page->write;
 		barrier();
 	}
+
+	/* again, keep gcc from optimizing */
+	barrier();
+
+	/*
+	 * If an interrupt came in just after the first while loop
+	 * and pushed the tail page forward, we will be left with
+	 * a dangling commit that will never go forward.
+	 */
+	if (unlikely(cpu_buffer->commit_page != cpu_buffer->tail_page))
+		goto again;
 }
 
 static void rb_reset_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
 {
-	cpu_buffer->read_stamp = cpu_buffer->reader_page->time_stamp;
+	cpu_buffer->read_stamp = cpu_buffer->reader_page->page->time_stamp;
 	cpu_buffer->reader_page->read = 0;
 }
 
@@ -806,7 +888,7 @@
 	else
 		rb_inc_page(cpu_buffer, &iter->head_page);
 
-	iter->read_stamp = iter->head_page->time_stamp;
+	iter->read_stamp = iter->head_page->page->time_stamp;
 	iter->head = 0;
 }
 
@@ -880,12 +962,15 @@
 __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
 		  unsigned type, unsigned long length, u64 *ts)
 {
-	struct buffer_page *tail_page, *head_page, *reader_page;
+	struct buffer_page *tail_page, *head_page, *reader_page, *commit_page;
 	unsigned long tail, write;
 	struct ring_buffer *buffer = cpu_buffer->buffer;
 	struct ring_buffer_event *event;
 	unsigned long flags;
 
+	commit_page = cpu_buffer->commit_page;
+	/* we just need to protect against interrupts */
+	barrier();
 	tail_page = cpu_buffer->tail_page;
 	write = local_add_return(length, &tail_page->write);
 	tail = write - length;
@@ -894,7 +979,8 @@
 	if (write > BUF_PAGE_SIZE) {
 		struct buffer_page *next_page = tail_page;
 
-		spin_lock_irqsave(&cpu_buffer->lock, flags);
+		local_irq_save(flags);
+		__raw_spin_lock(&cpu_buffer->lock);
 
 		rb_inc_page(cpu_buffer, &next_page);
 
@@ -902,14 +988,15 @@
 		reader_page = cpu_buffer->reader_page;
 
 		/* we grabbed the lock before incrementing */
-		RB_WARN_ON(cpu_buffer, next_page == reader_page);
+		if (RB_WARN_ON(cpu_buffer, next_page == reader_page))
+			goto out_unlock;
 
 		/*
 		 * If for some reason, we had an interrupt storm that made
 		 * it all the way around the buffer, bail, and warn
 		 * about it.
 		 */
-		if (unlikely(next_page == cpu_buffer->commit_page)) {
+		if (unlikely(next_page == commit_page)) {
 			WARN_ON_ONCE(1);
 			goto out_unlock;
 		}
@@ -940,12 +1027,12 @@
 		 */
 		if (tail_page == cpu_buffer->tail_page) {
 			local_set(&next_page->write, 0);
-			local_set(&next_page->commit, 0);
+			local_set(&next_page->page->commit, 0);
 			cpu_buffer->tail_page = next_page;
 
 			/* reread the time stamp */
 			*ts = ring_buffer_time_stamp(cpu_buffer->cpu);
-			cpu_buffer->tail_page->time_stamp = *ts;
+			cpu_buffer->tail_page->page->time_stamp = *ts;
 		}
 
 		/*
@@ -970,7 +1057,8 @@
 			rb_set_commit_to_write(cpu_buffer);
 		}
 
-		spin_unlock_irqrestore(&cpu_buffer->lock, flags);
+		__raw_spin_unlock(&cpu_buffer->lock);
+		local_irq_restore(flags);
 
 		/* fail and let the caller try again */
 		return ERR_PTR(-EAGAIN);
@@ -978,7 +1066,8 @@
 
 	/* We reserved something on the buffer */
 
-	BUG_ON(write > BUF_PAGE_SIZE);
+	if (RB_WARN_ON(cpu_buffer, write > BUF_PAGE_SIZE))
+		return NULL;
 
 	event = __rb_page_index(tail_page, tail);
 	rb_update_event(event, type, length);
@@ -988,12 +1077,13 @@
 	 * this page's time stamp.
 	 */
 	if (!tail && rb_is_commit(cpu_buffer, event))
-		cpu_buffer->commit_page->time_stamp = *ts;
+		cpu_buffer->commit_page->page->time_stamp = *ts;
 
 	return event;
 
  out_unlock:
-	spin_unlock_irqrestore(&cpu_buffer->lock, flags);
+	__raw_spin_unlock(&cpu_buffer->lock);
+	local_irq_restore(flags);
 	return NULL;
 }
 
@@ -1038,7 +1128,7 @@
 			event->time_delta = *delta & TS_MASK;
 			event->array[0] = *delta >> TS_SHIFT;
 		} else {
-			cpu_buffer->commit_page->time_stamp = *ts;
+			cpu_buffer->commit_page->page->time_stamp = *ts;
 			event->time_delta = 0;
 			event->array[0] = 0;
 		}
@@ -1076,10 +1166,8 @@
 	 * storm or we have something buggy.
 	 * Bail!
 	 */
-	if (unlikely(++nr_loops > 1000)) {
-		RB_WARN_ON(cpu_buffer, 1);
+	if (RB_WARN_ON(cpu_buffer, ++nr_loops > 1000))
 		return NULL;
-	}
 
 	ts = ring_buffer_time_stamp(cpu_buffer->cpu);
 
@@ -1175,15 +1263,14 @@
 	struct ring_buffer_event *event;
 	int cpu, resched;
 
-	if (ring_buffers_off)
+	if (ring_buffer_flags != RB_BUFFERS_ON)
 		return NULL;
 
 	if (atomic_read(&buffer->record_disabled))
 		return NULL;
 
 	/* If we are tracing schedule, we don't want to recurse */
-	resched = need_resched();
-	preempt_disable_notrace();
+	resched = ftrace_preempt_disable();
 
 	cpu = raw_smp_processor_id();
 
@@ -1214,10 +1301,7 @@
 	return event;
 
  out:
-	if (resched)
-		preempt_enable_no_resched_notrace();
-	else
-		preempt_enable_notrace();
+	ftrace_preempt_enable(resched);
 	return NULL;
 }
 
@@ -1259,12 +1343,9 @@
 	/*
 	 * Only the last preempt count needs to restore preemption.
 	 */
-	if (preempt_count() == 1) {
-		if (per_cpu(rb_need_resched, cpu))
-			preempt_enable_no_resched_notrace();
-		else
-			preempt_enable_notrace();
-	} else
+	if (preempt_count() == 1)
+		ftrace_preempt_enable(per_cpu(rb_need_resched, cpu));
+	else
 		preempt_enable_no_resched_notrace();
 
 	return 0;
@@ -1294,14 +1375,13 @@
 	int ret = -EBUSY;
 	int cpu, resched;
 
-	if (ring_buffers_off)
+	if (ring_buffer_flags != RB_BUFFERS_ON)
 		return -EBUSY;
 
 	if (atomic_read(&buffer->record_disabled))
 		return -EBUSY;
 
-	resched = need_resched();
-	preempt_disable_notrace();
+	resched = ftrace_preempt_disable();
 
 	cpu = raw_smp_processor_id();
 
@@ -1327,10 +1407,7 @@
 
 	ret = 0;
  out:
-	if (resched)
-		preempt_enable_no_resched_notrace();
-	else
-		preempt_enable_notrace();
+	ftrace_preempt_enable(resched);
 
 	return ret;
 }
@@ -1489,14 +1566,7 @@
 	return overruns;
 }
 
-/**
- * ring_buffer_iter_reset - reset an iterator
- * @iter: The iterator to reset
- *
- * Resets the iterator, so that it will start from the beginning
- * again.
- */
-void ring_buffer_iter_reset(struct ring_buffer_iter *iter)
+static void rb_iter_reset(struct ring_buffer_iter *iter)
 {
 	struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer;
 
@@ -1511,7 +1581,24 @@
 	if (iter->head)
 		iter->read_stamp = cpu_buffer->read_stamp;
 	else
-		iter->read_stamp = iter->head_page->time_stamp;
+		iter->read_stamp = iter->head_page->page->time_stamp;
+}
+
+/**
+ * ring_buffer_iter_reset - reset an iterator
+ * @iter: The iterator to reset
+ *
+ * Resets the iterator, so that it will start from the beginning
+ * again.
+ */
+void ring_buffer_iter_reset(struct ring_buffer_iter *iter)
+{
+	struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
+	rb_iter_reset(iter);
+	spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 }
 
 /**
@@ -1597,7 +1684,8 @@
 	unsigned long flags;
 	int nr_loops = 0;
 
-	spin_lock_irqsave(&cpu_buffer->lock, flags);
+	local_irq_save(flags);
+	__raw_spin_lock(&cpu_buffer->lock);
 
  again:
 	/*
@@ -1606,8 +1694,7 @@
 	 * a case where we will loop three times. There should be no
 	 * reason to loop four times (that I know of).
 	 */
-	if (unlikely(++nr_loops > 3)) {
-		RB_WARN_ON(cpu_buffer, 1);
+	if (RB_WARN_ON(cpu_buffer, ++nr_loops > 3)) {
 		reader = NULL;
 		goto out;
 	}
@@ -1619,8 +1706,9 @@
 		goto out;
 
 	/* Never should we have an index greater than the size */
-	RB_WARN_ON(cpu_buffer,
-		   cpu_buffer->reader_page->read > rb_page_size(reader));
+	if (RB_WARN_ON(cpu_buffer,
+		       cpu_buffer->reader_page->read > rb_page_size(reader)))
+		goto out;
 
 	/* check if we caught up to the tail */
 	reader = NULL;
@@ -1637,7 +1725,7 @@
 	cpu_buffer->reader_page->list.prev = reader->list.prev;
 
 	local_set(&cpu_buffer->reader_page->write, 0);
-	local_set(&cpu_buffer->reader_page->commit, 0);
+	local_set(&cpu_buffer->reader_page->page->commit, 0);
 
 	/* Make the reader page now replace the head */
 	reader->list.prev->next = &cpu_buffer->reader_page->list;
@@ -1659,7 +1747,8 @@
 	goto again;
 
  out:
-	spin_unlock_irqrestore(&cpu_buffer->lock, flags);
+	__raw_spin_unlock(&cpu_buffer->lock);
+	local_irq_restore(flags);
 
 	return reader;
 }
@@ -1673,7 +1762,8 @@
 	reader = rb_get_reader_page(cpu_buffer);
 
 	/* This function should not be called when buffer is empty */
-	BUG_ON(!reader);
+	if (RB_WARN_ON(cpu_buffer, !reader))
+		return;
 
 	event = rb_reader_event(cpu_buffer);
 
@@ -1700,7 +1790,9 @@
 	 * Check if we are at the end of the buffer.
 	 */
 	if (iter->head >= rb_page_size(iter->head_page)) {
-		BUG_ON(iter->head_page == cpu_buffer->commit_page);
+		if (RB_WARN_ON(buffer,
+			       iter->head_page == cpu_buffer->commit_page))
+			return;
 		rb_inc_iter(iter);
 		return;
 	}
@@ -1713,8 +1805,10 @@
 	 * This should not be called to advance the header if we are
 	 * at the tail of the buffer.
 	 */
-	BUG_ON((iter->head_page == cpu_buffer->commit_page) &&
-	       (iter->head + length > rb_commit_index(cpu_buffer)));
+	if (RB_WARN_ON(cpu_buffer,
+		       (iter->head_page == cpu_buffer->commit_page) &&
+		       (iter->head + length > rb_commit_index(cpu_buffer))))
+		return;
 
 	rb_update_iter_read_stamp(iter, event);
 
@@ -1726,17 +1820,8 @@
 		rb_advance_iter(iter);
 }
 
-/**
- * ring_buffer_peek - peek at the next event to be read
- * @buffer: The ring buffer to read
- * @cpu: The cpu to peak at
- * @ts: The timestamp counter of this event.
- *
- * This will return the event that will be read next, but does
- * not consume the data.
- */
-struct ring_buffer_event *
-ring_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts)
+static struct ring_buffer_event *
+rb_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
 	struct ring_buffer_event *event;
@@ -1757,10 +1842,8 @@
 	 * can have.  Nesting 10 deep of interrupts is clearly
 	 * an anomaly.
 	 */
-	if (unlikely(++nr_loops > 10)) {
-		RB_WARN_ON(cpu_buffer, 1);
+	if (RB_WARN_ON(cpu_buffer, ++nr_loops > 10))
 		return NULL;
-	}
 
 	reader = rb_get_reader_page(cpu_buffer);
 	if (!reader)
@@ -1798,16 +1881,8 @@
 	return NULL;
 }
 
-/**
- * ring_buffer_iter_peek - peek at the next event to be read
- * @iter: The ring buffer iterator
- * @ts: The timestamp counter of this event.
- *
- * This will return the event that will be read next, but does
- * not increment the iterator.
- */
-struct ring_buffer_event *
-ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
+static struct ring_buffer_event *
+rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
 {
 	struct ring_buffer *buffer;
 	struct ring_buffer_per_cpu *cpu_buffer;
@@ -1829,10 +1904,8 @@
 	 * can have. Nesting 10 deep of interrupts is clearly
 	 * an anomaly.
 	 */
-	if (unlikely(++nr_loops > 10)) {
-		RB_WARN_ON(cpu_buffer, 1);
+	if (RB_WARN_ON(cpu_buffer, ++nr_loops > 10))
 		return NULL;
-	}
 
 	if (rb_per_cpu_empty(cpu_buffer))
 		return NULL;
@@ -1869,6 +1942,51 @@
 }
 
 /**
+ * ring_buffer_peek - peek at the next event to be read
+ * @buffer: The ring buffer to read
+ * @cpu: The cpu to peak at
+ * @ts: The timestamp counter of this event.
+ *
+ * This will return the event that will be read next, but does
+ * not consume the data.
+ */
+struct ring_buffer_event *
+ring_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts)
+{
+	struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu];
+	struct ring_buffer_event *event;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
+	event = rb_buffer_peek(buffer, cpu, ts);
+	spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
+
+	return event;
+}
+
+/**
+ * ring_buffer_iter_peek - peek at the next event to be read
+ * @iter: The ring buffer iterator
+ * @ts: The timestamp counter of this event.
+ *
+ * This will return the event that will be read next, but does
+ * not increment the iterator.
+ */
+struct ring_buffer_event *
+ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
+{
+	struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer;
+	struct ring_buffer_event *event;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
+	event = rb_iter_peek(iter, ts);
+	spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
+
+	return event;
+}
+
+/**
  * ring_buffer_consume - return an event and consume it
  * @buffer: The ring buffer to get the next event from
  *
@@ -1879,19 +1997,24 @@
 struct ring_buffer_event *
 ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts)
 {
-	struct ring_buffer_per_cpu *cpu_buffer;
+	struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu];
 	struct ring_buffer_event *event;
+	unsigned long flags;
 
 	if (!cpu_isset(cpu, buffer->cpumask))
 		return NULL;
 
-	event = ring_buffer_peek(buffer, cpu, ts);
-	if (!event)
-		return NULL;
+	spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
 
-	cpu_buffer = buffer->buffers[cpu];
+	event = rb_buffer_peek(buffer, cpu, ts);
+	if (!event)
+		goto out;
+
 	rb_advance_reader(cpu_buffer);
 
+ out:
+	spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
+
 	return event;
 }
 
@@ -1928,9 +2051,11 @@
 	atomic_inc(&cpu_buffer->record_disabled);
 	synchronize_sched();
 
-	spin_lock_irqsave(&cpu_buffer->lock, flags);
-	ring_buffer_iter_reset(iter);
-	spin_unlock_irqrestore(&cpu_buffer->lock, flags);
+	spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
+	__raw_spin_lock(&cpu_buffer->lock);
+	rb_iter_reset(iter);
+	__raw_spin_unlock(&cpu_buffer->lock);
+	spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 
 	return iter;
 }
@@ -1962,12 +2087,17 @@
 ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts)
 {
 	struct ring_buffer_event *event;
+	struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer;
+	unsigned long flags;
 
-	event = ring_buffer_iter_peek(iter, ts);
+	spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
+	event = rb_iter_peek(iter, ts);
 	if (!event)
-		return NULL;
+		goto out;
 
 	rb_advance_iter(iter);
+ out:
+	spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 
 	return event;
 }
@@ -1987,7 +2117,7 @@
 	cpu_buffer->head_page
 		= list_entry(cpu_buffer->pages.next, struct buffer_page, list);
 	local_set(&cpu_buffer->head_page->write, 0);
-	local_set(&cpu_buffer->head_page->commit, 0);
+	local_set(&cpu_buffer->head_page->page->commit, 0);
 
 	cpu_buffer->head_page->read = 0;
 
@@ -1996,7 +2126,7 @@
 
 	INIT_LIST_HEAD(&cpu_buffer->reader_page->list);
 	local_set(&cpu_buffer->reader_page->write, 0);
-	local_set(&cpu_buffer->reader_page->commit, 0);
+	local_set(&cpu_buffer->reader_page->page->commit, 0);
 	cpu_buffer->reader_page->read = 0;
 
 	cpu_buffer->overrun = 0;
@@ -2016,11 +2146,15 @@
 	if (!cpu_isset(cpu, buffer->cpumask))
 		return;
 
-	spin_lock_irqsave(&cpu_buffer->lock, flags);
+	spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
+
+	__raw_spin_lock(&cpu_buffer->lock);
 
 	rb_reset_cpu(cpu_buffer);
 
-	spin_unlock_irqrestore(&cpu_buffer->lock, flags);
+	__raw_spin_unlock(&cpu_buffer->lock);
+
+	spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 }
 
 /**
@@ -2090,8 +2224,7 @@
 		return -EINVAL;
 
 	/* At least make sure the two buffers are somewhat the same */
-	if (buffer_a->size != buffer_b->size ||
-	    buffer_a->pages != buffer_b->pages)
+	if (buffer_a->pages != buffer_b->pages)
 		return -EINVAL;
 
 	cpu_buffer_a = buffer_a->buffers[cpu];
@@ -2118,16 +2251,178 @@
 	return 0;
 }
 
+static void rb_remove_entries(struct ring_buffer_per_cpu *cpu_buffer,
+			      struct buffer_data_page *bpage)
+{
+	struct ring_buffer_event *event;
+	unsigned long head;
+
+	__raw_spin_lock(&cpu_buffer->lock);
+	for (head = 0; head < local_read(&bpage->commit);
+	     head += rb_event_length(event)) {
+
+		event = __rb_data_page_index(bpage, head);
+		if (RB_WARN_ON(cpu_buffer, rb_null_event(event)))
+			return;
+		/* Only count data entries */
+		if (event->type != RINGBUF_TYPE_DATA)
+			continue;
+		cpu_buffer->entries--;
+	}
+	__raw_spin_unlock(&cpu_buffer->lock);
+}
+
+/**
+ * ring_buffer_alloc_read_page - allocate a page to read from buffer
+ * @buffer: the buffer to allocate for.
+ *
+ * This function is used in conjunction with ring_buffer_read_page.
+ * When reading a full page from the ring buffer, these functions
+ * can be used to speed up the process. The calling function should
+ * allocate a few pages first with this function. Then when it
+ * needs to get pages from the ring buffer, it passes the result
+ * of this function into ring_buffer_read_page, which will swap
+ * the page that was allocated, with the read page of the buffer.
+ *
+ * Returns:
+ *  The page allocated, or NULL on error.
+ */
+void *ring_buffer_alloc_read_page(struct ring_buffer *buffer)
+{
+	unsigned long addr;
+	struct buffer_data_page *bpage;
+
+	addr = __get_free_page(GFP_KERNEL);
+	if (!addr)
+		return NULL;
+
+	bpage = (void *)addr;
+
+	return bpage;
+}
+
+/**
+ * ring_buffer_free_read_page - free an allocated read page
+ * @buffer: the buffer the page was allocate for
+ * @data: the page to free
+ *
+ * Free a page allocated from ring_buffer_alloc_read_page.
+ */
+void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data)
+{
+	free_page((unsigned long)data);
+}
+
+/**
+ * ring_buffer_read_page - extract a page from the ring buffer
+ * @buffer: buffer to extract from
+ * @data_page: the page to use allocated from ring_buffer_alloc_read_page
+ * @cpu: the cpu of the buffer to extract
+ * @full: should the extraction only happen when the page is full.
+ *
+ * This function will pull out a page from the ring buffer and consume it.
+ * @data_page must be the address of the variable that was returned
+ * from ring_buffer_alloc_read_page. This is because the page might be used
+ * to swap with a page in the ring buffer.
+ *
+ * for example:
+ *	rpage = ring_buffer_alloc_page(buffer);
+ *	if (!rpage)
+ *		return error;
+ *	ret = ring_buffer_read_page(buffer, &rpage, cpu, 0);
+ *	if (ret)
+ *		process_page(rpage);
+ *
+ * When @full is set, the function will not return true unless
+ * the writer is off the reader page.
+ *
+ * Note: it is up to the calling functions to handle sleeps and wakeups.
+ *  The ring buffer can be used anywhere in the kernel and can not
+ *  blindly call wake_up. The layer that uses the ring buffer must be
+ *  responsible for that.
+ *
+ * Returns:
+ *  1 if data has been transferred
+ *  0 if no data has been transferred.
+ */
+int ring_buffer_read_page(struct ring_buffer *buffer,
+			    void **data_page, int cpu, int full)
+{
+	struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu];
+	struct ring_buffer_event *event;
+	struct buffer_data_page *bpage;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!data_page)
+		return 0;
+
+	bpage = *data_page;
+	if (!bpage)
+		return 0;
+
+	spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
+
+	/*
+	 * rb_buffer_peek will get the next ring buffer if
+	 * the current reader page is empty.
+	 */
+	event = rb_buffer_peek(buffer, cpu, NULL);
+	if (!event)
+		goto out;
+
+	/* check for data */
+	if (!local_read(&cpu_buffer->reader_page->page->commit))
+		goto out;
+	/*
+	 * If the writer is already off of the read page, then simply
+	 * switch the read page with the given page. Otherwise
+	 * we need to copy the data from the reader to the writer.
+	 */
+	if (cpu_buffer->reader_page == cpu_buffer->commit_page) {
+		unsigned int read = cpu_buffer->reader_page->read;
+
+		if (full)
+			goto out;
+		/* The writer is still on the reader page, we must copy */
+		bpage = cpu_buffer->reader_page->page;
+		memcpy(bpage->data,
+		       cpu_buffer->reader_page->page->data + read,
+		       local_read(&bpage->commit) - read);
+
+		/* consume what was read */
+		cpu_buffer->reader_page += read;
+
+	} else {
+		/* swap the pages */
+		rb_init_page(bpage);
+		bpage = cpu_buffer->reader_page->page;
+		cpu_buffer->reader_page->page = *data_page;
+		cpu_buffer->reader_page->read = 0;
+		*data_page = bpage;
+	}
+	ret = 1;
+
+	/* update the entry counter */
+	rb_remove_entries(cpu_buffer, bpage);
+ out:
+	spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
+
+	return ret;
+}
+
 static ssize_t
 rb_simple_read(struct file *filp, char __user *ubuf,
 	       size_t cnt, loff_t *ppos)
 {
-	int *p = filp->private_data;
+	long *p = filp->private_data;
 	char buf[64];
 	int r;
 
-	/* !ring_buffers_off == tracing_on */
-	r = sprintf(buf, "%d\n", !*p);
+	if (test_bit(RB_BUFFERS_DISABLED_BIT, p))
+		r = sprintf(buf, "permanently disabled\n");
+	else
+		r = sprintf(buf, "%d\n", test_bit(RB_BUFFERS_ON_BIT, p));
 
 	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
 }
@@ -2136,7 +2431,7 @@
 rb_simple_write(struct file *filp, const char __user *ubuf,
 		size_t cnt, loff_t *ppos)
 {
-	int *p = filp->private_data;
+	long *p = filp->private_data;
 	char buf[64];
 	long val;
 	int ret;
@@ -2153,8 +2448,10 @@
 	if (ret < 0)
 		return ret;
 
-	/* !ring_buffers_off == tracing_on */
-	*p = !val;
+	if (val)
+		set_bit(RB_BUFFERS_ON_BIT, p);
+	else
+		clear_bit(RB_BUFFERS_ON_BIT, p);
 
 	(*ppos)++;
 
@@ -2176,7 +2473,7 @@
 	d_tracer = tracing_init_dentry();
 
 	entry = debugfs_create_file("tracing_on", 0644, d_tracer,
-				    &ring_buffers_off, &rb_simple_fops);
+				    &ring_buffer_flags, &rb_simple_fops);
 	if (!entry)
 		pr_warning("Could not create debugfs 'tracing_on' entry\n");
 
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index d86e325..f4bb380 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -30,6 +30,7 @@
 #include <linux/gfp.h>
 #include <linux/fs.h>
 #include <linux/kprobes.h>
+#include <linux/seq_file.h>
 #include <linux/writeback.h>
 
 #include <linux/stacktrace.h>
@@ -43,6 +44,38 @@
 unsigned long __read_mostly	tracing_max_latency = (cycle_t)ULONG_MAX;
 unsigned long __read_mostly	tracing_thresh;
 
+/*
+ * We need to change this state when a selftest is running.
+ * A selftest will lurk into the ring-buffer to count the
+ * entries inserted during the selftest although some concurrent
+ * insertions into the ring-buffer such as ftrace_printk could occurred
+ * at the same time, giving false positive or negative results.
+ */
+static bool __read_mostly tracing_selftest_running;
+
+/* For tracers that don't implement custom flags */
+static struct tracer_opt dummy_tracer_opt[] = {
+	{ }
+};
+
+static struct tracer_flags dummy_tracer_flags = {
+	.val = 0,
+	.opts = dummy_tracer_opt
+};
+
+static int dummy_set_flag(u32 old_flags, u32 bit, int set)
+{
+	return 0;
+}
+
+/*
+ * Kill all tracing for good (never come back).
+ * It is initialized to 1 but will turn to zero if the initialization
+ * of the tracer is successful. But that is the only place that sets
+ * this back to zero.
+ */
+int tracing_disabled = 1;
+
 static DEFINE_PER_CPU(local_t, ftrace_cpu_disabled);
 
 static inline void ftrace_disable_cpu(void)
@@ -62,7 +95,36 @@
 #define for_each_tracing_cpu(cpu)	\
 	for_each_cpu_mask(cpu, tracing_buffer_mask)
 
-static int tracing_disabled = 1;
+/*
+ * ftrace_dump_on_oops - variable to dump ftrace buffer on oops
+ *
+ * If there is an oops (or kernel panic) and the ftrace_dump_on_oops
+ * is set, then ftrace_dump is called. This will output the contents
+ * of the ftrace buffers to the console.  This is very useful for
+ * capturing traces that lead to crashes and outputing it to a
+ * serial console.
+ *
+ * It is default off, but you can enable it with either specifying
+ * "ftrace_dump_on_oops" in the kernel command line, or setting
+ * /proc/sys/kernel/ftrace_dump_on_oops to true.
+ */
+int ftrace_dump_on_oops;
+
+static int tracing_set_tracer(char *buf);
+
+static int __init set_ftrace(char *str)
+{
+	tracing_set_tracer(str);
+	return 1;
+}
+__setup("ftrace", set_ftrace);
+
+static int __init set_ftrace_dump_on_oops(char *str)
+{
+	ftrace_dump_on_oops = 1;
+	return 1;
+}
+__setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops);
 
 long
 ns2usecs(cycle_t nsec)
@@ -112,6 +174,19 @@
 /* tracer_enabled is used to toggle activation of a tracer */
 static int			tracer_enabled = 1;
 
+/**
+ * tracing_is_enabled - return tracer_enabled status
+ *
+ * This function is used by other tracers to know the status
+ * of the tracer_enabled flag.  Tracers may use this function
+ * to know if it should enable their features when starting
+ * up. See irqsoff tracer for an example (start_irqsoff_tracer).
+ */
+int tracing_is_enabled(void)
+{
+	return tracer_enabled;
+}
+
 /* function tracing enabled */
 int				ftrace_function_enabled;
 
@@ -153,8 +228,9 @@
 /* trace_wait is a waitqueue for tasks blocked on trace_poll */
 static DECLARE_WAIT_QUEUE_HEAD(trace_wait);
 
-/* trace_flags holds iter_ctrl options */
-unsigned long trace_flags = TRACE_ITER_PRINT_PARENT;
+/* trace_flags holds trace_options default values */
+unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
+	TRACE_ITER_ANNOTATE;
 
 /**
  * trace_wake_up - wake up tasks waiting for trace input
@@ -193,13 +269,6 @@
 	return nsecs / 1000;
 }
 
-/*
- * TRACE_ITER_SYM_MASK masks the options in trace_flags that
- * control the output of kernel symbols.
- */
-#define TRACE_ITER_SYM_MASK \
-	(TRACE_ITER_PRINT_PARENT|TRACE_ITER_SYM_OFFSET|TRACE_ITER_SYM_ADDR)
-
 /* These must match the bit postions in trace_iterator_flags */
 static const char *trace_options[] = {
 	"print-parent",
@@ -213,6 +282,12 @@
 	"stacktrace",
 	"sched-tree",
 	"ftrace_printk",
+	"ftrace_preempt",
+	"branch",
+	"annotate",
+	"userstacktrace",
+	"sym-userobj",
+	"printk-msg-only",
 	NULL
 };
 
@@ -246,7 +321,7 @@
 
 	memcpy(data->comm, tsk->comm, TASK_COMM_LEN);
 	data->pid = tsk->pid;
-	data->uid = tsk->uid;
+	data->uid = task_uid(tsk);
 	data->nice = tsk->static_prio - 20 - MAX_RT_PRIO;
 	data->policy = tsk->policy;
 	data->rt_priority = tsk->rt_priority;
@@ -359,6 +434,28 @@
 	return trace_seq_putmem(s, hex, j);
 }
 
+static int
+trace_seq_path(struct trace_seq *s, struct path *path)
+{
+	unsigned char *p;
+
+	if (s->len >= (PAGE_SIZE - 1))
+		return 0;
+	p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
+	if (!IS_ERR(p)) {
+		p = mangle_path(s->buffer + s->len, p, "\n");
+		if (p) {
+			s->len = p - s->buffer;
+			return 1;
+		}
+	} else {
+		s->buffer[s->len++] = '?';
+		return 1;
+	}
+
+	return 0;
+}
+
 static void
 trace_seq_reset(struct trace_seq *s)
 {
@@ -470,7 +567,17 @@
 		return -1;
 	}
 
+	/*
+	 * When this gets called we hold the BKL which means that
+	 * preemption is disabled. Various trace selftests however
+	 * need to disable and enable preemption for successful tests.
+	 * So we drop the BKL here and grab it after the tests again.
+	 */
+	unlock_kernel();
 	mutex_lock(&trace_types_lock);
+
+	tracing_selftest_running = true;
+
 	for (t = trace_types; t; t = t->next) {
 		if (strcmp(type->name, t->name) == 0) {
 			/* already found */
@@ -481,12 +588,20 @@
 		}
 	}
 
+	if (!type->set_flag)
+		type->set_flag = &dummy_set_flag;
+	if (!type->flags)
+		type->flags = &dummy_tracer_flags;
+	else
+		if (!type->flags->opts)
+			type->flags->opts = dummy_tracer_opt;
+
 #ifdef CONFIG_FTRACE_STARTUP_TEST
 	if (type->selftest) {
 		struct tracer *saved_tracer = current_trace;
 		struct trace_array *tr = &global_trace;
-		int saved_ctrl = tr->ctrl;
 		int i;
+
 		/*
 		 * Run a selftest on this tracer.
 		 * Here we reset the trace buffer, and set the current
@@ -494,25 +609,23 @@
 		 * internal tracing to verify that everything is in order.
 		 * If we fail, we do not register this tracer.
 		 */
-		for_each_tracing_cpu(i) {
+		for_each_tracing_cpu(i)
 			tracing_reset(tr, i);
-		}
+
 		current_trace = type;
-		tr->ctrl = 0;
 		/* the test is responsible for initializing and enabling */
 		pr_info("Testing tracer %s: ", type->name);
 		ret = type->selftest(type, tr);
 		/* the test is responsible for resetting too */
 		current_trace = saved_tracer;
-		tr->ctrl = saved_ctrl;
 		if (ret) {
 			printk(KERN_CONT "FAILED!\n");
 			goto out;
 		}
 		/* Only reset on passing, to avoid touching corrupted buffers */
-		for_each_tracing_cpu(i) {
+		for_each_tracing_cpu(i)
 			tracing_reset(tr, i);
-		}
+
 		printk(KERN_CONT "PASSED\n");
 	}
 #endif
@@ -524,7 +637,9 @@
 		max_tracer_type_len = len;
 
  out:
+	tracing_selftest_running = false;
 	mutex_unlock(&trace_types_lock);
+	lock_kernel();
 
 	return ret;
 }
@@ -564,6 +679,16 @@
 	ftrace_enable_cpu();
 }
 
+void tracing_reset_online_cpus(struct trace_array *tr)
+{
+	int cpu;
+
+	tr->time_start = ftrace_now(tr->cpu);
+
+	for_each_online_cpu(cpu)
+		tracing_reset(tr, cpu);
+}
+
 #define SAVED_CMDLINES 128
 static unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
 static unsigned map_cmdline_to_pid[SAVED_CMDLINES];
@@ -581,6 +706,91 @@
 	cmdline_idx = 0;
 }
 
+static int trace_stop_count;
+static DEFINE_SPINLOCK(tracing_start_lock);
+
+/**
+ * ftrace_off_permanent - disable all ftrace code permanently
+ *
+ * This should only be called when a serious anomally has
+ * been detected.  This will turn off the function tracing,
+ * ring buffers, and other tracing utilites. It takes no
+ * locks and can be called from any context.
+ */
+void ftrace_off_permanent(void)
+{
+	tracing_disabled = 1;
+	ftrace_stop();
+	tracing_off_permanent();
+}
+
+/**
+ * tracing_start - quick start of the tracer
+ *
+ * If tracing is enabled but was stopped by tracing_stop,
+ * this will start the tracer back up.
+ */
+void tracing_start(void)
+{
+	struct ring_buffer *buffer;
+	unsigned long flags;
+
+	if (tracing_disabled)
+		return;
+
+	spin_lock_irqsave(&tracing_start_lock, flags);
+	if (--trace_stop_count)
+		goto out;
+
+	if (trace_stop_count < 0) {
+		/* Someone screwed up their debugging */
+		WARN_ON_ONCE(1);
+		trace_stop_count = 0;
+		goto out;
+	}
+
+
+	buffer = global_trace.buffer;
+	if (buffer)
+		ring_buffer_record_enable(buffer);
+
+	buffer = max_tr.buffer;
+	if (buffer)
+		ring_buffer_record_enable(buffer);
+
+	ftrace_start();
+ out:
+	spin_unlock_irqrestore(&tracing_start_lock, flags);
+}
+
+/**
+ * tracing_stop - quick stop of the tracer
+ *
+ * Light weight way to stop tracing. Use in conjunction with
+ * tracing_start.
+ */
+void tracing_stop(void)
+{
+	struct ring_buffer *buffer;
+	unsigned long flags;
+
+	ftrace_stop();
+	spin_lock_irqsave(&tracing_start_lock, flags);
+	if (trace_stop_count++)
+		goto out;
+
+	buffer = global_trace.buffer;
+	if (buffer)
+		ring_buffer_record_disable(buffer);
+
+	buffer = max_tr.buffer;
+	if (buffer)
+		ring_buffer_record_disable(buffer);
+
+ out:
+	spin_unlock_irqrestore(&tracing_start_lock, flags);
+}
+
 void trace_stop_cmdline_recording(void);
 
 static void trace_save_cmdline(struct task_struct *tsk)
@@ -618,7 +828,7 @@
 	spin_unlock(&trace_cmdline_lock);
 }
 
-static char *trace_find_cmdline(int pid)
+char *trace_find_cmdline(int pid)
 {
 	char *cmdline = "<...>";
 	unsigned map;
@@ -655,6 +865,7 @@
 
 	entry->preempt_count		= pc & 0xff;
 	entry->pid			= (tsk) ? tsk->pid : 0;
+	entry->tgid               	= (tsk) ? tsk->tgid : 0;
 	entry->flags =
 #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
 		(irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) |
@@ -691,6 +902,56 @@
 	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
 }
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+static void __trace_graph_entry(struct trace_array *tr,
+				struct trace_array_cpu *data,
+				struct ftrace_graph_ent *trace,
+				unsigned long flags,
+				int pc)
+{
+	struct ring_buffer_event *event;
+	struct ftrace_graph_ent_entry *entry;
+	unsigned long irq_flags;
+
+	if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
+		return;
+
+	event = ring_buffer_lock_reserve(global_trace.buffer, sizeof(*entry),
+					 &irq_flags);
+	if (!event)
+		return;
+	entry	= ring_buffer_event_data(event);
+	tracing_generic_entry_update(&entry->ent, flags, pc);
+	entry->ent.type			= TRACE_GRAPH_ENT;
+	entry->graph_ent			= *trace;
+	ring_buffer_unlock_commit(global_trace.buffer, event, irq_flags);
+}
+
+static void __trace_graph_return(struct trace_array *tr,
+				struct trace_array_cpu *data,
+				struct ftrace_graph_ret *trace,
+				unsigned long flags,
+				int pc)
+{
+	struct ring_buffer_event *event;
+	struct ftrace_graph_ret_entry *entry;
+	unsigned long irq_flags;
+
+	if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
+		return;
+
+	event = ring_buffer_lock_reserve(global_trace.buffer, sizeof(*entry),
+					 &irq_flags);
+	if (!event)
+		return;
+	entry	= ring_buffer_event_data(event);
+	tracing_generic_entry_update(&entry->ent, flags, pc);
+	entry->ent.type			= TRACE_GRAPH_RET;
+	entry->ret				= *trace;
+	ring_buffer_unlock_commit(global_trace.buffer, event, irq_flags);
+}
+#endif
+
 void
 ftrace(struct trace_array *tr, struct trace_array_cpu *data,
        unsigned long ip, unsigned long parent_ip, unsigned long flags,
@@ -742,6 +1003,46 @@
 	ftrace_trace_stack(tr, data, flags, skip, preempt_count());
 }
 
+static void ftrace_trace_userstack(struct trace_array *tr,
+		   struct trace_array_cpu *data,
+		   unsigned long flags, int pc)
+{
+#ifdef CONFIG_STACKTRACE
+	struct ring_buffer_event *event;
+	struct userstack_entry *entry;
+	struct stack_trace trace;
+	unsigned long irq_flags;
+
+	if (!(trace_flags & TRACE_ITER_USERSTACKTRACE))
+		return;
+
+	event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
+					 &irq_flags);
+	if (!event)
+		return;
+	entry	= ring_buffer_event_data(event);
+	tracing_generic_entry_update(&entry->ent, flags, pc);
+	entry->ent.type		= TRACE_USER_STACK;
+
+	memset(&entry->caller, 0, sizeof(entry->caller));
+
+	trace.nr_entries	= 0;
+	trace.max_entries	= FTRACE_STACK_ENTRIES;
+	trace.skip		= 0;
+	trace.entries		= entry->caller;
+
+	save_stack_trace_user(&trace);
+	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
+#endif
+}
+
+void __trace_userstack(struct trace_array *tr,
+		   struct trace_array_cpu *data,
+		   unsigned long flags)
+{
+	ftrace_trace_userstack(tr, data, flags, preempt_count());
+}
+
 static void
 ftrace_trace_special(void *__tr, void *__data,
 		     unsigned long arg1, unsigned long arg2, unsigned long arg3,
@@ -765,6 +1066,7 @@
 	entry->arg3			= arg3;
 	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
 	ftrace_trace_stack(tr, data, irq_flags, 4, pc);
+	ftrace_trace_userstack(tr, data, irq_flags, pc);
 
 	trace_wake_up();
 }
@@ -803,6 +1105,7 @@
 	entry->next_cpu	= task_cpu(next);
 	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
 	ftrace_trace_stack(tr, data, flags, 5, pc);
+	ftrace_trace_userstack(tr, data, flags, pc);
 }
 
 void
@@ -832,6 +1135,7 @@
 	entry->next_cpu			= task_cpu(wakee);
 	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
 	ftrace_trace_stack(tr, data, flags, 6, pc);
+	ftrace_trace_userstack(tr, data, flags, pc);
 
 	trace_wake_up();
 }
@@ -841,26 +1145,28 @@
 {
 	struct trace_array *tr = &global_trace;
 	struct trace_array_cpu *data;
+	unsigned long flags;
 	int cpu;
 	int pc;
 
-	if (tracing_disabled || !tr->ctrl)
+	if (tracing_disabled)
 		return;
 
 	pc = preempt_count();
-	preempt_disable_notrace();
+	local_irq_save(flags);
 	cpu = raw_smp_processor_id();
 	data = tr->data[cpu];
 
-	if (likely(!atomic_read(&data->disabled)))
+	if (likely(atomic_inc_return(&data->disabled) == 1))
 		ftrace_trace_special(tr, data, arg1, arg2, arg3, pc);
 
-	preempt_enable_notrace();
+	atomic_dec(&data->disabled);
+	local_irq_restore(flags);
 }
 
 #ifdef CONFIG_FUNCTION_TRACER
 static void
-function_trace_call(unsigned long ip, unsigned long parent_ip)
+function_trace_call_preempt_only(unsigned long ip, unsigned long parent_ip)
 {
 	struct trace_array *tr = &global_trace;
 	struct trace_array_cpu *data;
@@ -873,8 +1179,7 @@
 		return;
 
 	pc = preempt_count();
-	resched = need_resched();
-	preempt_disable_notrace();
+	resched = ftrace_preempt_disable();
 	local_save_flags(flags);
 	cpu = raw_smp_processor_id();
 	data = tr->data[cpu];
@@ -884,12 +1189,97 @@
 		trace_function(tr, data, ip, parent_ip, flags, pc);
 
 	atomic_dec(&data->disabled);
-	if (resched)
-		preempt_enable_no_resched_notrace();
-	else
-		preempt_enable_notrace();
+	ftrace_preempt_enable(resched);
 }
 
+static void
+function_trace_call(unsigned long ip, unsigned long parent_ip)
+{
+	struct trace_array *tr = &global_trace;
+	struct trace_array_cpu *data;
+	unsigned long flags;
+	long disabled;
+	int cpu;
+	int pc;
+
+	if (unlikely(!ftrace_function_enabled))
+		return;
+
+	/*
+	 * Need to use raw, since this must be called before the
+	 * recursive protection is performed.
+	 */
+	local_irq_save(flags);
+	cpu = raw_smp_processor_id();
+	data = tr->data[cpu];
+	disabled = atomic_inc_return(&data->disabled);
+
+	if (likely(disabled == 1)) {
+		pc = preempt_count();
+		trace_function(tr, data, ip, parent_ip, flags, pc);
+	}
+
+	atomic_dec(&data->disabled);
+	local_irq_restore(flags);
+}
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+int trace_graph_entry(struct ftrace_graph_ent *trace)
+{
+	struct trace_array *tr = &global_trace;
+	struct trace_array_cpu *data;
+	unsigned long flags;
+	long disabled;
+	int cpu;
+	int pc;
+
+	if (!ftrace_trace_task(current))
+		return 0;
+
+	if (!ftrace_graph_addr(trace->func))
+		return 0;
+
+	local_irq_save(flags);
+	cpu = raw_smp_processor_id();
+	data = tr->data[cpu];
+	disabled = atomic_inc_return(&data->disabled);
+	if (likely(disabled == 1)) {
+		pc = preempt_count();
+		__trace_graph_entry(tr, data, trace, flags, pc);
+	}
+	/* Only do the atomic if it is not already set */
+	if (!test_tsk_trace_graph(current))
+		set_tsk_trace_graph(current);
+	atomic_dec(&data->disabled);
+	local_irq_restore(flags);
+
+	return 1;
+}
+
+void trace_graph_return(struct ftrace_graph_ret *trace)
+{
+	struct trace_array *tr = &global_trace;
+	struct trace_array_cpu *data;
+	unsigned long flags;
+	long disabled;
+	int cpu;
+	int pc;
+
+	local_irq_save(flags);
+	cpu = raw_smp_processor_id();
+	data = tr->data[cpu];
+	disabled = atomic_inc_return(&data->disabled);
+	if (likely(disabled == 1)) {
+		pc = preempt_count();
+		__trace_graph_return(tr, data, trace, flags, pc);
+	}
+	if (!trace->depth)
+		clear_tsk_trace_graph(current);
+	atomic_dec(&data->disabled);
+	local_irq_restore(flags);
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
 static struct ftrace_ops trace_ops __read_mostly =
 {
 	.func = function_trace_call,
@@ -898,9 +1288,14 @@
 void tracing_start_function_trace(void)
 {
 	ftrace_function_enabled = 0;
+
+	if (trace_flags & TRACE_ITER_PREEMPTONLY)
+		trace_ops.func = function_trace_call_preempt_only;
+	else
+		trace_ops.func = function_trace_call;
+
 	register_ftrace_function(&trace_ops);
-	if (tracer_enabled)
-		ftrace_function_enabled = 1;
+	ftrace_function_enabled = 1;
 }
 
 void tracing_stop_function_trace(void)
@@ -912,6 +1307,7 @@
 
 enum trace_file_type {
 	TRACE_FILE_LAT_FMT	= 1,
+	TRACE_FILE_ANNOTATE	= 2,
 };
 
 static void trace_iterator_increment(struct trace_iterator *iter, int cpu)
@@ -1047,10 +1443,6 @@
 
 	atomic_inc(&trace_record_cmdline_disabled);
 
-	/* let the tracer grab locks here if needed */
-	if (current_trace->start)
-		current_trace->start(iter);
-
 	if (*pos != iter->pos) {
 		iter->ent = NULL;
 		iter->cpu = 0;
@@ -1077,14 +1469,7 @@
 
 static void s_stop(struct seq_file *m, void *p)
 {
-	struct trace_iterator *iter = m->private;
-
 	atomic_dec(&trace_record_cmdline_disabled);
-
-	/* let the tracer release locks here if needed */
-	if (current_trace && current_trace == iter->trace && iter->trace->stop)
-		iter->trace->stop(iter);
-
 	mutex_unlock(&trace_types_lock);
 }
 
@@ -1143,7 +1528,7 @@
 # define IP_FMT "%016lx"
 #endif
 
-static int
+int
 seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
 {
 	int ret;
@@ -1164,6 +1549,78 @@
 	return ret;
 }
 
+static inline int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
+				    unsigned long ip, unsigned long sym_flags)
+{
+	struct file *file = NULL;
+	unsigned long vmstart = 0;
+	int ret = 1;
+
+	if (mm) {
+		const struct vm_area_struct *vma;
+
+		down_read(&mm->mmap_sem);
+		vma = find_vma(mm, ip);
+		if (vma) {
+			file = vma->vm_file;
+			vmstart = vma->vm_start;
+		}
+		if (file) {
+			ret = trace_seq_path(s, &file->f_path);
+			if (ret)
+				ret = trace_seq_printf(s, "[+0x%lx]", ip - vmstart);
+		}
+		up_read(&mm->mmap_sem);
+	}
+	if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file))
+		ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
+	return ret;
+}
+
+static int
+seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
+		      unsigned long sym_flags)
+{
+	struct mm_struct *mm = NULL;
+	int ret = 1;
+	unsigned int i;
+
+	if (trace_flags & TRACE_ITER_SYM_USEROBJ) {
+		struct task_struct *task;
+		/*
+		 * we do the lookup on the thread group leader,
+		 * since individual threads might have already quit!
+		 */
+		rcu_read_lock();
+		task = find_task_by_vpid(entry->ent.tgid);
+		if (task)
+			mm = get_task_mm(task);
+		rcu_read_unlock();
+	}
+
+	for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
+		unsigned long ip = entry->caller[i];
+
+		if (ip == ULONG_MAX || !ret)
+			break;
+		if (i && ret)
+			ret = trace_seq_puts(s, " <- ");
+		if (!ip) {
+			if (ret)
+				ret = trace_seq_puts(s, "??");
+			continue;
+		}
+		if (!ret)
+			break;
+		if (ret)
+			ret = seq_print_user_ip(s, mm, ip, sym_flags);
+	}
+
+	if (mm)
+		mmput(mm);
+	return ret;
+}
+
 static void print_lat_help_header(struct seq_file *m)
 {
 	seq_puts(m, "#                  _------=> CPU#            \n");
@@ -1301,6 +1758,13 @@
 
 static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
 
+static int task_state_char(unsigned long state)
+{
+	int bit = state ? __ffs(state) + 1 : 0;
+
+	return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
+}
+
 /*
  * The message is supposed to contain an ending newline.
  * If the printing stops prematurely, try to add a newline of our own.
@@ -1338,6 +1802,23 @@
 		trace_seq_putc(s, '\n');
 }
 
+static void test_cpu_buff_start(struct trace_iterator *iter)
+{
+	struct trace_seq *s = &iter->seq;
+
+	if (!(trace_flags & TRACE_ITER_ANNOTATE))
+		return;
+
+	if (!(iter->iter_flags & TRACE_FILE_ANNOTATE))
+		return;
+
+	if (cpu_isset(iter->cpu, iter->started))
+		return;
+
+	cpu_set(iter->cpu, iter->started);
+	trace_seq_printf(s, "##### CPU %u buffer started ####\n", iter->cpu);
+}
+
 static enum print_line_t
 print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
 {
@@ -1352,11 +1833,12 @@
 	char *comm;
 	int S, T;
 	int i;
-	unsigned state;
 
 	if (entry->type == TRACE_CONT)
 		return TRACE_TYPE_HANDLED;
 
+	test_cpu_buff_start(iter);
+
 	next_entry = find_next_entry(iter, NULL, &next_ts);
 	if (!next_entry)
 		next_ts = iter->ts;
@@ -1396,12 +1878,8 @@
 
 		trace_assign_type(field, entry);
 
-		T = field->next_state < sizeof(state_to_char) ?
-			state_to_char[field->next_state] : 'X';
-
-		state = field->prev_state ?
-			__ffs(field->prev_state) + 1 : 0;
-		S = state < sizeof(state_to_char) - 1 ? state_to_char[state] : 'X';
+		T = task_state_char(field->next_state);
+		S = task_state_char(field->prev_state);
 		comm = trace_find_cmdline(field->next_pid);
 		trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
 				 field->prev_pid,
@@ -1448,6 +1926,27 @@
 			trace_seq_print_cont(s, iter);
 		break;
 	}
+	case TRACE_BRANCH: {
+		struct trace_branch *field;
+
+		trace_assign_type(field, entry);
+
+		trace_seq_printf(s, "[%s] %s:%s:%d\n",
+				 field->correct ? "  ok  " : " MISS ",
+				 field->func,
+				 field->file,
+				 field->line);
+		break;
+	}
+	case TRACE_USER_STACK: {
+		struct userstack_entry *field;
+
+		trace_assign_type(field, entry);
+
+		seq_print_userip_objs(field, s, sym_flags);
+		trace_seq_putc(s, '\n');
+		break;
+	}
 	default:
 		trace_seq_printf(s, "Unknown type %d\n", entry->type);
 	}
@@ -1472,6 +1971,8 @@
 	if (entry->type == TRACE_CONT)
 		return TRACE_TYPE_HANDLED;
 
+	test_cpu_buff_start(iter);
+
 	comm = trace_find_cmdline(iter->ent->pid);
 
 	t = ns2usecs(iter->ts);
@@ -1519,10 +2020,8 @@
 
 		trace_assign_type(field, entry);
 
-		S = field->prev_state < sizeof(state_to_char) ?
-			state_to_char[field->prev_state] : 'X';
-		T = field->next_state < sizeof(state_to_char) ?
-			state_to_char[field->next_state] : 'X';
+		T = task_state_char(field->next_state);
+		S = task_state_char(field->prev_state);
 		ret = trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c\n",
 				       field->prev_pid,
 				       field->prev_prio,
@@ -1581,6 +2080,37 @@
 			trace_seq_print_cont(s, iter);
 		break;
 	}
+	case TRACE_GRAPH_RET: {
+		return print_graph_function(iter);
+	}
+	case TRACE_GRAPH_ENT: {
+		return print_graph_function(iter);
+	}
+	case TRACE_BRANCH: {
+		struct trace_branch *field;
+
+		trace_assign_type(field, entry);
+
+		trace_seq_printf(s, "[%s] %s:%s:%d\n",
+				 field->correct ? "  ok  " : " MISS ",
+				 field->func,
+				 field->file,
+				 field->line);
+		break;
+	}
+	case TRACE_USER_STACK: {
+		struct userstack_entry *field;
+
+		trace_assign_type(field, entry);
+
+		ret = seq_print_userip_objs(field, s, sym_flags);
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+		ret = trace_seq_putc(s, '\n');
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+		break;
+	}
 	}
 	return TRACE_TYPE_HANDLED;
 }
@@ -1621,12 +2151,9 @@
 
 		trace_assign_type(field, entry);
 
-		S = field->prev_state < sizeof(state_to_char) ?
-			state_to_char[field->prev_state] : 'X';
-		T = field->next_state < sizeof(state_to_char) ?
-			state_to_char[field->next_state] : 'X';
-		if (entry->type == TRACE_WAKE)
-			S = '+';
+		T = task_state_char(field->next_state);
+		S = entry->type == TRACE_WAKE ? '+' :
+			task_state_char(field->prev_state);
 		ret = trace_seq_printf(s, "%d %d %c %d %d %d %c\n",
 				       field->prev_pid,
 				       field->prev_prio,
@@ -1640,6 +2167,7 @@
 		break;
 	}
 	case TRACE_SPECIAL:
+	case TRACE_USER_STACK:
 	case TRACE_STACK: {
 		struct special_entry *field;
 
@@ -1712,12 +2240,9 @@
 
 		trace_assign_type(field, entry);
 
-		S = field->prev_state < sizeof(state_to_char) ?
-			state_to_char[field->prev_state] : 'X';
-		T = field->next_state < sizeof(state_to_char) ?
-			state_to_char[field->next_state] : 'X';
-		if (entry->type == TRACE_WAKE)
-			S = '+';
+		T = task_state_char(field->next_state);
+		S = entry->type == TRACE_WAKE ? '+' :
+			task_state_char(field->prev_state);
 		SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid);
 		SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio);
 		SEQ_PUT_HEX_FIELD_RET(s, S);
@@ -1728,6 +2253,7 @@
 		break;
 	}
 	case TRACE_SPECIAL:
+	case TRACE_USER_STACK:
 	case TRACE_STACK: {
 		struct special_entry *field;
 
@@ -1744,6 +2270,25 @@
 	return TRACE_TYPE_HANDLED;
 }
 
+static enum print_line_t print_printk_msg_only(struct trace_iterator *iter)
+{
+	struct trace_seq *s = &iter->seq;
+	struct trace_entry *entry = iter->ent;
+	struct print_entry *field;
+	int ret;
+
+	trace_assign_type(field, entry);
+
+	ret = trace_seq_printf(s, field->buf);
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	if (entry->flags & TRACE_FLAG_CONT)
+		trace_seq_print_cont(s, iter);
+
+	return TRACE_TYPE_HANDLED;
+}
+
 static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
 {
 	struct trace_seq *s = &iter->seq;
@@ -1782,6 +2327,7 @@
 		break;
 	}
 	case TRACE_SPECIAL:
+	case TRACE_USER_STACK:
 	case TRACE_STACK: {
 		struct special_entry *field;
 
@@ -1823,6 +2369,11 @@
 			return ret;
 	}
 
+	if (iter->ent->type == TRACE_PRINT &&
+			trace_flags & TRACE_ITER_PRINTK &&
+			trace_flags & TRACE_ITER_PRINTK_MSGONLY)
+		return print_printk_msg_only(iter);
+
 	if (trace_flags & TRACE_ITER_BIN)
 		return print_bin_fmt(iter);
 
@@ -1847,7 +2398,9 @@
 			seq_printf(m, "# tracer: %s\n", iter->trace->name);
 			seq_puts(m, "#\n");
 		}
-		if (iter->iter_flags & TRACE_FILE_LAT_FMT) {
+		if (iter->trace && iter->trace->print_header)
+			iter->trace->print_header(m);
+		else if (iter->iter_flags & TRACE_FILE_LAT_FMT) {
 			/* print nothing if the buffers are empty */
 			if (trace_empty(iter))
 				return 0;
@@ -1899,6 +2452,15 @@
 	iter->trace = current_trace;
 	iter->pos = -1;
 
+	/* Notify the tracer early; before we stop tracing. */
+	if (iter->trace && iter->trace->open)
+		iter->trace->open(iter);
+
+	/* Annotate start of buffers if we had overruns */
+	if (ring_buffer_overruns(iter->tr->buffer))
+		iter->iter_flags |= TRACE_FILE_ANNOTATE;
+
+
 	for_each_tracing_cpu(cpu) {
 
 		iter->buffer_iter[cpu] =
@@ -1917,13 +2479,7 @@
 	m->private = iter;
 
 	/* stop the trace while dumping */
-	if (iter->tr->ctrl) {
-		tracer_enabled = 0;
-		ftrace_function_enabled = 0;
-	}
-
-	if (iter->trace && iter->trace->open)
-			iter->trace->open(iter);
+	tracing_stop();
 
 	mutex_unlock(&trace_types_lock);
 
@@ -1966,14 +2522,7 @@
 		iter->trace->close(iter);
 
 	/* reenable tracing if it was previously enabled */
-	if (iter->tr->ctrl) {
-		tracer_enabled = 1;
-		/*
-		 * It is safe to enable function tracing even if it
-		 * isn't used
-		 */
-		ftrace_function_enabled = 1;
-	}
+	tracing_start();
 	mutex_unlock(&trace_types_lock);
 
 	seq_release(inode, file);
@@ -2151,7 +2700,7 @@
 	if (err)
 		goto err_unlock;
 
-	raw_local_irq_disable();
+	local_irq_disable();
 	__raw_spin_lock(&ftrace_max_lock);
 	for_each_tracing_cpu(cpu) {
 		/*
@@ -2168,7 +2717,7 @@
 		}
 	}
 	__raw_spin_unlock(&ftrace_max_lock);
-	raw_local_irq_enable();
+	local_irq_enable();
 
 	tracing_cpumask = tracing_cpumask_new;
 
@@ -2189,13 +2738,16 @@
 };
 
 static ssize_t
-tracing_iter_ctrl_read(struct file *filp, char __user *ubuf,
+tracing_trace_options_read(struct file *filp, char __user *ubuf,
 		       size_t cnt, loff_t *ppos)
 {
+	int i;
 	char *buf;
 	int r = 0;
 	int len = 0;
-	int i;
+	u32 tracer_flags = current_trace->flags->val;
+	struct tracer_opt *trace_opts = current_trace->flags->opts;
+
 
 	/* calulate max size */
 	for (i = 0; trace_options[i]; i++) {
@@ -2203,6 +2755,15 @@
 		len += 3; /* "no" and space */
 	}
 
+	/*
+	 * Increase the size with names of options specific
+	 * of the current tracer.
+	 */
+	for (i = 0; trace_opts[i].name; i++) {
+		len += strlen(trace_opts[i].name);
+		len += 3; /* "no" and space */
+	}
+
 	/* +2 for \n and \0 */
 	buf = kmalloc(len + 2, GFP_KERNEL);
 	if (!buf)
@@ -2215,6 +2776,15 @@
 			r += sprintf(buf + r, "no%s ", trace_options[i]);
 	}
 
+	for (i = 0; trace_opts[i].name; i++) {
+		if (tracer_flags & trace_opts[i].bit)
+			r += sprintf(buf + r, "%s ",
+				trace_opts[i].name);
+		else
+			r += sprintf(buf + r, "no%s ",
+				trace_opts[i].name);
+	}
+
 	r += sprintf(buf + r, "\n");
 	WARN_ON(r >= len + 2);
 
@@ -2225,13 +2795,48 @@
 	return r;
 }
 
+/* Try to assign a tracer specific option */
+static int set_tracer_option(struct tracer *trace, char *cmp, int neg)
+{
+	struct tracer_flags *trace_flags = trace->flags;
+	struct tracer_opt *opts = NULL;
+	int ret = 0, i = 0;
+	int len;
+
+	for (i = 0; trace_flags->opts[i].name; i++) {
+		opts = &trace_flags->opts[i];
+		len = strlen(opts->name);
+
+		if (strncmp(cmp, opts->name, len) == 0) {
+			ret = trace->set_flag(trace_flags->val,
+				opts->bit, !neg);
+			break;
+		}
+	}
+	/* Not found */
+	if (!trace_flags->opts[i].name)
+		return -EINVAL;
+
+	/* Refused to handle */
+	if (ret)
+		return ret;
+
+	if (neg)
+		trace_flags->val &= ~opts->bit;
+	else
+		trace_flags->val |= opts->bit;
+
+	return 0;
+}
+
 static ssize_t
-tracing_iter_ctrl_write(struct file *filp, const char __user *ubuf,
+tracing_trace_options_write(struct file *filp, const char __user *ubuf,
 			size_t cnt, loff_t *ppos)
 {
 	char buf[64];
 	char *cmp = buf;
 	int neg = 0;
+	int ret;
 	int i;
 
 	if (cnt >= sizeof(buf))
@@ -2258,11 +2863,13 @@
 			break;
 		}
 	}
-	/*
-	 * If no option could be set, return an error:
-	 */
-	if (!trace_options[i])
-		return -EINVAL;
+
+	/* If no option could be set, test the specific tracer options */
+	if (!trace_options[i]) {
+		ret = set_tracer_option(current_trace, cmp, neg);
+		if (ret)
+			return ret;
+	}
 
 	filp->f_pos += cnt;
 
@@ -2271,8 +2878,8 @@
 
 static struct file_operations tracing_iter_fops = {
 	.open		= tracing_open_generic,
-	.read		= tracing_iter_ctrl_read,
-	.write		= tracing_iter_ctrl_write,
+	.read		= tracing_trace_options_read,
+	.write		= tracing_trace_options_write,
 };
 
 static const char readme_msg[] =
@@ -2286,9 +2893,9 @@
 	"# echo sched_switch > /debug/tracing/current_tracer\n"
 	"# cat /debug/tracing/current_tracer\n"
 	"sched_switch\n"
-	"# cat /debug/tracing/iter_ctrl\n"
+	"# cat /debug/tracing/trace_options\n"
 	"noprint-parent nosym-offset nosym-addr noverbose\n"
-	"# echo print-parent > /debug/tracing/iter_ctrl\n"
+	"# echo print-parent > /debug/tracing/trace_options\n"
 	"# echo 1 > /debug/tracing/tracing_enabled\n"
 	"# cat /debug/tracing/trace > /tmp/trace.txt\n"
 	"echo 0 > /debug/tracing/tracing_enabled\n"
@@ -2311,11 +2918,10 @@
 tracing_ctrl_read(struct file *filp, char __user *ubuf,
 		  size_t cnt, loff_t *ppos)
 {
-	struct trace_array *tr = filp->private_data;
 	char buf[64];
 	int r;
 
-	r = sprintf(buf, "%ld\n", tr->ctrl);
+	r = sprintf(buf, "%u\n", tracer_enabled);
 	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
 }
 
@@ -2343,16 +2949,18 @@
 	val = !!val;
 
 	mutex_lock(&trace_types_lock);
-	if (tr->ctrl ^ val) {
-		if (val)
+	if (tracer_enabled ^ val) {
+		if (val) {
 			tracer_enabled = 1;
-		else
+			if (current_trace->start)
+				current_trace->start(tr);
+			tracing_start();
+		} else {
 			tracer_enabled = 0;
-
-		tr->ctrl = val;
-
-		if (current_trace && current_trace->ctrl_update)
-			current_trace->ctrl_update(tr);
+			tracing_stop();
+			if (current_trace->stop)
+				current_trace->stop(tr);
+		}
 	}
 	mutex_unlock(&trace_types_lock);
 
@@ -2378,15 +2986,50 @@
 	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
 }
 
+static int tracing_set_tracer(char *buf)
+{
+	struct trace_array *tr = &global_trace;
+	struct tracer *t;
+	int ret = 0;
+
+	mutex_lock(&trace_types_lock);
+	for (t = trace_types; t; t = t->next) {
+		if (strcmp(t->name, buf) == 0)
+			break;
+	}
+	if (!t) {
+		ret = -EINVAL;
+		goto out;
+	}
+	if (t == current_trace)
+		goto out;
+
+	trace_branch_disable();
+	if (current_trace && current_trace->reset)
+		current_trace->reset(tr);
+
+	current_trace = t;
+	if (t->init) {
+		ret = t->init(tr);
+		if (ret)
+			goto out;
+	}
+
+	trace_branch_enable(tr);
+ out:
+	mutex_unlock(&trace_types_lock);
+
+	return ret;
+}
+
 static ssize_t
 tracing_set_trace_write(struct file *filp, const char __user *ubuf,
 			size_t cnt, loff_t *ppos)
 {
-	struct trace_array *tr = &global_trace;
-	struct tracer *t;
 	char buf[max_tracer_type_len+1];
 	int i;
 	size_t ret;
+	int err;
 
 	ret = cnt;
 
@@ -2402,30 +3045,11 @@
 	for (i = cnt - 1; i > 0 && isspace(buf[i]); i--)
 		buf[i] = 0;
 
-	mutex_lock(&trace_types_lock);
-	for (t = trace_types; t; t = t->next) {
-		if (strcmp(t->name, buf) == 0)
-			break;
-	}
-	if (!t) {
-		ret = -EINVAL;
-		goto out;
-	}
-	if (t == current_trace)
-		goto out;
+	err = tracing_set_tracer(buf);
+	if (err)
+		return err;
 
-	if (current_trace && current_trace->reset)
-		current_trace->reset(tr);
-
-	current_trace = t;
-	if (t->init)
-		t->init(tr);
-
- out:
-	mutex_unlock(&trace_types_lock);
-
-	if (ret > 0)
-		filp->f_pos += ret;
+	filp->f_pos += ret;
 
 	return ret;
 }
@@ -2492,6 +3116,10 @@
 		return -ENOMEM;
 
 	mutex_lock(&trace_types_lock);
+
+	/* trace pipe does not show start of buffer */
+	cpus_setall(iter->started);
+
 	iter->tr = &global_trace;
 	iter->trace = current_trace;
 	filp->private_data = iter;
@@ -2667,7 +3295,7 @@
 	char buf[64];
 	int r;
 
-	r = sprintf(buf, "%lu\n", tr->entries);
+	r = sprintf(buf, "%lu\n", tr->entries >> 10);
 	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
 }
 
@@ -2678,7 +3306,6 @@
 	unsigned long val;
 	char buf[64];
 	int ret, cpu;
-	struct trace_array *tr = filp->private_data;
 
 	if (cnt >= sizeof(buf))
 		return -EINVAL;
@@ -2698,12 +3325,7 @@
 
 	mutex_lock(&trace_types_lock);
 
-	if (tr->ctrl) {
-		cnt = -EBUSY;
-		pr_info("ftrace: please disable tracing"
-			" before modifying buffer size\n");
-		goto out;
-	}
+	tracing_stop();
 
 	/* disable all cpu buffers */
 	for_each_tracing_cpu(cpu) {
@@ -2713,6 +3335,9 @@
 			atomic_inc(&max_tr.data[cpu]->disabled);
 	}
 
+	/* value is in KB */
+	val <<= 10;
+
 	if (val != global_trace.entries) {
 		ret = ring_buffer_resize(global_trace.buffer, val);
 		if (ret < 0) {
@@ -2751,6 +3376,7 @@
 			atomic_dec(&max_tr.data[cpu]->disabled);
 	}
 
+	tracing_start();
 	max_tr.entries = global_trace.entries;
 	mutex_unlock(&trace_types_lock);
 
@@ -2762,7 +3388,7 @@
 	int ret;
 	va_list args;
 	va_start(args, fmt);
-	ret = trace_vprintk(0, fmt, args);
+	ret = trace_vprintk(0, -1, fmt, args);
 	va_end(args);
 	return ret;
 }
@@ -2773,9 +3399,8 @@
 {
 	char *buf;
 	char *end;
-	struct trace_array *tr = &global_trace;
 
-	if (!tr->ctrl || tracing_disabled)
+	if (tracing_disabled)
 		return -EINVAL;
 
 	if (cnt > TRACE_BUF_SIZE)
@@ -2841,22 +3466,38 @@
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
-static ssize_t
-tracing_read_long(struct file *filp, char __user *ubuf,
-		  size_t cnt, loff_t *ppos)
+int __weak ftrace_arch_read_dyn_info(char *buf, int size)
 {
-	unsigned long *p = filp->private_data;
-	char buf[64];
-	int r;
-
-	r = sprintf(buf, "%ld\n", *p);
-
-	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+	return 0;
 }
 
-static struct file_operations tracing_read_long_fops = {
+static ssize_t
+tracing_read_dyn_info(struct file *filp, char __user *ubuf,
+		  size_t cnt, loff_t *ppos)
+{
+	static char ftrace_dyn_info_buffer[1024];
+	static DEFINE_MUTEX(dyn_info_mutex);
+	unsigned long *p = filp->private_data;
+	char *buf = ftrace_dyn_info_buffer;
+	int size = ARRAY_SIZE(ftrace_dyn_info_buffer);
+	int r;
+
+	mutex_lock(&dyn_info_mutex);
+	r = sprintf(buf, "%ld ", *p);
+
+	r += ftrace_arch_read_dyn_info(buf+r, (size-1)-r);
+	buf[r++] = '\n';
+
+	r = simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+
+	mutex_unlock(&dyn_info_mutex);
+
+	return r;
+}
+
+static struct file_operations tracing_dyn_info_fops = {
 	.open		= tracing_open_generic,
-	.read		= tracing_read_long,
+	.read		= tracing_read_dyn_info,
 };
 #endif
 
@@ -2897,10 +3538,10 @@
 	if (!entry)
 		pr_warning("Could not create debugfs 'tracing_enabled' entry\n");
 
-	entry = debugfs_create_file("iter_ctrl", 0644, d_tracer,
+	entry = debugfs_create_file("trace_options", 0644, d_tracer,
 				    NULL, &tracing_iter_fops);
 	if (!entry)
-		pr_warning("Could not create debugfs 'iter_ctrl' entry\n");
+		pr_warning("Could not create debugfs 'trace_options' entry\n");
 
 	entry = debugfs_create_file("tracing_cpumask", 0644, d_tracer,
 				    NULL, &tracing_cpumask_fops);
@@ -2950,11 +3591,11 @@
 		pr_warning("Could not create debugfs "
 			   "'trace_pipe' entry\n");
 
-	entry = debugfs_create_file("trace_entries", 0644, d_tracer,
+	entry = debugfs_create_file("buffer_size_kb", 0644, d_tracer,
 				    &global_trace, &tracing_entries_fops);
 	if (!entry)
 		pr_warning("Could not create debugfs "
-			   "'trace_entries' entry\n");
+			   "'buffer_size_kb' entry\n");
 
 	entry = debugfs_create_file("trace_marker", 0220, d_tracer,
 				    NULL, &tracing_mark_fops);
@@ -2965,7 +3606,7 @@
 #ifdef CONFIG_DYNAMIC_FTRACE
 	entry = debugfs_create_file("dyn_ftrace_total_info", 0444, d_tracer,
 				    &ftrace_update_tot_cnt,
-				    &tracing_read_long_fops);
+				    &tracing_dyn_info_fops);
 	if (!entry)
 		pr_warning("Could not create debugfs "
 			   "'dyn_ftrace_total_info' entry\n");
@@ -2976,7 +3617,7 @@
 	return 0;
 }
 
-int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
+int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args)
 {
 	static DEFINE_SPINLOCK(trace_buf_lock);
 	static char trace_buf[TRACE_BUF_SIZE];
@@ -2984,11 +3625,11 @@
 	struct ring_buffer_event *event;
 	struct trace_array *tr = &global_trace;
 	struct trace_array_cpu *data;
-	struct print_entry *entry;
-	unsigned long flags, irq_flags;
 	int cpu, len = 0, size, pc;
+	struct print_entry *entry;
+	unsigned long irq_flags;
 
-	if (!tr->ctrl || tracing_disabled)
+	if (tracing_disabled || tracing_selftest_running)
 		return 0;
 
 	pc = preempt_count();
@@ -2999,7 +3640,8 @@
 	if (unlikely(atomic_read(&data->disabled)))
 		goto out;
 
-	spin_lock_irqsave(&trace_buf_lock, flags);
+	pause_graph_tracing();
+	spin_lock_irqsave(&trace_buf_lock, irq_flags);
 	len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args);
 
 	len = min(len, TRACE_BUF_SIZE-1);
@@ -3010,17 +3652,18 @@
 	if (!event)
 		goto out_unlock;
 	entry = ring_buffer_event_data(event);
-	tracing_generic_entry_update(&entry->ent, flags, pc);
+	tracing_generic_entry_update(&entry->ent, irq_flags, pc);
 	entry->ent.type			= TRACE_PRINT;
 	entry->ip			= ip;
+	entry->depth			= depth;
 
 	memcpy(&entry->buf, trace_buf, len);
 	entry->buf[len] = 0;
 	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
 
  out_unlock:
-	spin_unlock_irqrestore(&trace_buf_lock, flags);
-
+	spin_unlock_irqrestore(&trace_buf_lock, irq_flags);
+	unpause_graph_tracing();
  out:
 	preempt_enable_notrace();
 
@@ -3037,7 +3680,7 @@
 		return 0;
 
 	va_start(ap, fmt);
-	ret = trace_vprintk(ip, fmt, ap);
+	ret = trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap);
 	va_end(ap);
 	return ret;
 }
@@ -3046,7 +3689,8 @@
 static int trace_panic_handler(struct notifier_block *this,
 			       unsigned long event, void *unused)
 {
-	ftrace_dump();
+	if (ftrace_dump_on_oops)
+		ftrace_dump();
 	return NOTIFY_OK;
 }
 
@@ -3062,7 +3706,8 @@
 {
 	switch (val) {
 	case DIE_OOPS:
-		ftrace_dump();
+		if (ftrace_dump_on_oops)
+			ftrace_dump();
 		break;
 	default:
 		break;
@@ -3103,7 +3748,6 @@
 	trace_seq_reset(s);
 }
 
-
 void ftrace_dump(void)
 {
 	static DEFINE_SPINLOCK(ftrace_dump_lock);
@@ -3128,6 +3772,9 @@
 		atomic_inc(&global_trace.data[cpu]->disabled);
 	}
 
+	/* don't look at user memory in panic mode */
+	trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
+
 	printk(KERN_TRACE "Dumping ftrace buffer:\n");
 
 	iter.tr = &global_trace;
@@ -3221,7 +3868,6 @@
 #endif
 
 	/* All seems OK, enable tracing */
-	global_trace.ctrl = tracer_enabled;
 	tracing_disabled = 0;
 
 	atomic_notifier_chain_register(&panic_notifier_list,
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 8465ad0..cc7a4f8 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -8,6 +8,7 @@
 #include <linux/ring_buffer.h>
 #include <linux/mmiotrace.h>
 #include <linux/ftrace.h>
+#include <trace/boot.h>
 
 enum trace_type {
 	__TRACE_FIRST_TYPE = 0,
@@ -21,7 +22,14 @@
 	TRACE_SPECIAL,
 	TRACE_MMIO_RW,
 	TRACE_MMIO_MAP,
-	TRACE_BOOT,
+	TRACE_BRANCH,
+	TRACE_BOOT_CALL,
+	TRACE_BOOT_RET,
+	TRACE_GRAPH_RET,
+	TRACE_GRAPH_ENT,
+	TRACE_USER_STACK,
+	TRACE_HW_BRANCHES,
+	TRACE_POWER,
 
 	__TRACE_LAST_TYPE
 };
@@ -38,6 +46,7 @@
 	unsigned char		flags;
 	unsigned char		preempt_count;
 	int			pid;
+	int			tgid;
 };
 
 /*
@@ -48,6 +57,18 @@
 	unsigned long		ip;
 	unsigned long		parent_ip;
 };
+
+/* Function call entry */
+struct ftrace_graph_ent_entry {
+	struct trace_entry			ent;
+	struct ftrace_graph_ent		graph_ent;
+};
+
+/* Function return entry */
+struct ftrace_graph_ret_entry {
+	struct trace_entry			ent;
+	struct ftrace_graph_ret		ret;
+};
 extern struct tracer boot_tracer;
 
 /*
@@ -85,12 +106,18 @@
 	unsigned long		caller[FTRACE_STACK_ENTRIES];
 };
 
+struct userstack_entry {
+	struct trace_entry	ent;
+	unsigned long		caller[FTRACE_STACK_ENTRIES];
+};
+
 /*
  * ftrace_printk entry:
  */
 struct print_entry {
 	struct trace_entry	ent;
 	unsigned long		ip;
+	int			depth;
 	char			buf[];
 };
 
@@ -112,9 +139,35 @@
 	struct mmiotrace_map	map;
 };
 
-struct trace_boot {
+struct trace_boot_call {
 	struct trace_entry	ent;
-	struct boot_trace	initcall;
+	struct boot_trace_call boot_call;
+};
+
+struct trace_boot_ret {
+	struct trace_entry	ent;
+	struct boot_trace_ret boot_ret;
+};
+
+#define TRACE_FUNC_SIZE 30
+#define TRACE_FILE_SIZE 20
+struct trace_branch {
+	struct trace_entry	ent;
+	unsigned	        line;
+	char			func[TRACE_FUNC_SIZE+1];
+	char			file[TRACE_FILE_SIZE+1];
+	char			correct;
+};
+
+struct hw_branch_entry {
+	struct trace_entry	ent;
+	u64			from;
+	u64			to;
+};
+
+struct trace_power {
+	struct trace_entry	ent;
+	struct power_trace	state_data;
 };
 
 /*
@@ -172,7 +225,6 @@
 struct trace_array {
 	struct ring_buffer	*buffer;
 	unsigned long		entries;
-	long			ctrl;
 	int			cpu;
 	cycle_t			time_start;
 	struct task_struct	*waiter;
@@ -212,13 +264,22 @@
 		IF_ASSIGN(var, ent, struct ctx_switch_entry, 0);	\
 		IF_ASSIGN(var, ent, struct trace_field_cont, TRACE_CONT); \
 		IF_ASSIGN(var, ent, struct stack_entry, TRACE_STACK);	\
+		IF_ASSIGN(var, ent, struct userstack_entry, TRACE_USER_STACK);\
 		IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT);	\
 		IF_ASSIGN(var, ent, struct special_entry, 0);		\
 		IF_ASSIGN(var, ent, struct trace_mmiotrace_rw,		\
 			  TRACE_MMIO_RW);				\
 		IF_ASSIGN(var, ent, struct trace_mmiotrace_map,		\
 			  TRACE_MMIO_MAP);				\
-		IF_ASSIGN(var, ent, struct trace_boot, TRACE_BOOT);	\
+		IF_ASSIGN(var, ent, struct trace_boot_call, TRACE_BOOT_CALL);\
+		IF_ASSIGN(var, ent, struct trace_boot_ret, TRACE_BOOT_RET);\
+		IF_ASSIGN(var, ent, struct trace_branch, TRACE_BRANCH); \
+		IF_ASSIGN(var, ent, struct ftrace_graph_ent_entry,	\
+			  TRACE_GRAPH_ENT);		\
+		IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry,	\
+			  TRACE_GRAPH_RET);		\
+		IF_ASSIGN(var, ent, struct hw_branch_entry, TRACE_HW_BRANCHES);\
+ 		IF_ASSIGN(var, ent, struct trace_power, TRACE_POWER); \
 		__ftrace_bad_type();					\
 	} while (0)
 
@@ -229,29 +290,56 @@
 	TRACE_TYPE_UNHANDLED	= 2	/* Relay to other output functions */
 };
 
+
+/*
+ * An option specific to a tracer. This is a boolean value.
+ * The bit is the bit index that sets its value on the
+ * flags value in struct tracer_flags.
+ */
+struct tracer_opt {
+	const char 	*name; /* Will appear on the trace_options file */
+	u32 		bit; /* Mask assigned in val field in tracer_flags */
+};
+
+/*
+ * The set of specific options for a tracer. Your tracer
+ * have to set the initial value of the flags val.
+ */
+struct tracer_flags {
+	u32			val;
+	struct tracer_opt 	*opts;
+};
+
+/* Makes more easy to define a tracer opt */
+#define TRACER_OPT(s, b)	.name = #s, .bit = b
+
 /*
  * A specific tracer, represented by methods that operate on a trace array:
  */
 struct tracer {
 	const char		*name;
-	void			(*init)(struct trace_array *tr);
+	/* Your tracer should raise a warning if init fails */
+	int			(*init)(struct trace_array *tr);
 	void			(*reset)(struct trace_array *tr);
+	void			(*start)(struct trace_array *tr);
+	void			(*stop)(struct trace_array *tr);
 	void			(*open)(struct trace_iterator *iter);
 	void			(*pipe_open)(struct trace_iterator *iter);
 	void			(*close)(struct trace_iterator *iter);
-	void			(*start)(struct trace_iterator *iter);
-	void			(*stop)(struct trace_iterator *iter);
 	ssize_t			(*read)(struct trace_iterator *iter,
 					struct file *filp, char __user *ubuf,
 					size_t cnt, loff_t *ppos);
-	void			(*ctrl_update)(struct trace_array *tr);
 #ifdef CONFIG_FTRACE_STARTUP_TEST
 	int			(*selftest)(struct tracer *trace,
 					    struct trace_array *tr);
 #endif
+	void			(*print_header)(struct seq_file *m);
 	enum print_line_t	(*print_line)(struct trace_iterator *iter);
+	/* If you handled the flag setting, return 0 */
+	int			(*set_flag)(u32 old_flags, u32 bit, int set);
 	struct tracer		*next;
 	int			print_max;
+	struct tracer_flags 	*flags;
 };
 
 struct trace_seq {
@@ -279,10 +367,14 @@
 	unsigned long		iter_flags;
 	loff_t			pos;
 	long			idx;
+
+	cpumask_t		started;
 };
 
+int tracing_is_enabled(void);
 void trace_wake_up(void);
 void tracing_reset(struct trace_array *tr, int cpu);
+void tracing_reset_online_cpus(struct trace_array *tr);
 int tracing_open_generic(struct inode *inode, struct file *filp);
 struct dentry *tracing_init_dentry(void);
 void init_tracer_sysprof_debugfs(struct dentry *d_tracer);
@@ -321,8 +413,15 @@
 		    unsigned long parent_ip,
 		    unsigned long flags, int pc);
 
+void trace_graph_return(struct ftrace_graph_ret *trace);
+int trace_graph_entry(struct ftrace_graph_ent *trace);
+void trace_hw_branch(struct trace_array *tr, u64 from, u64 to);
+
 void tracing_start_cmdline_record(void);
 void tracing_stop_cmdline_record(void);
+void tracing_sched_switch_assign_trace(struct trace_array *tr);
+void tracing_stop_sched_switch_record(void);
+void tracing_start_sched_switch_record(void);
 int register_tracer(struct tracer *type);
 void unregister_tracer(struct tracer *type);
 
@@ -358,6 +457,7 @@
 	struct tracer_switch_ops	*next;
 };
 
+char *trace_find_cmdline(int pid);
 #endif /* CONFIG_CONTEXT_SWITCH_TRACER */
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -383,19 +483,79 @@
 					       struct trace_array *tr);
 extern int trace_selftest_startup_sysprof(struct tracer *trace,
 					       struct trace_array *tr);
+extern int trace_selftest_startup_branch(struct tracer *trace,
+					 struct trace_array *tr);
 #endif /* CONFIG_FTRACE_STARTUP_TEST */
 
 extern void *head_page(struct trace_array_cpu *data);
 extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...);
 extern void trace_seq_print_cont(struct trace_seq *s,
 				 struct trace_iterator *iter);
+
+extern int
+seq_print_ip_sym(struct trace_seq *s, unsigned long ip,
+		unsigned long sym_flags);
 extern ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf,
 				 size_t cnt);
 extern long ns2usecs(cycle_t nsec);
-extern int trace_vprintk(unsigned long ip, const char *fmt, va_list args);
+extern int
+trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args);
 
 extern unsigned long trace_flags;
 
+/* Standard output formatting function used for function return traces */
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+extern enum print_line_t print_graph_function(struct trace_iterator *iter);
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+/* TODO: make this variable */
+#define FTRACE_GRAPH_MAX_FUNCS		32
+extern int ftrace_graph_count;
+extern unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS];
+
+static inline int ftrace_graph_addr(unsigned long addr)
+{
+	int i;
+
+	if (!ftrace_graph_count || test_tsk_trace_graph(current))
+		return 1;
+
+	for (i = 0; i < ftrace_graph_count; i++) {
+		if (addr == ftrace_graph_funcs[i])
+			return 1;
+	}
+
+	return 0;
+}
+#else
+static inline int ftrace_trace_addr(unsigned long addr)
+{
+	return 1;
+}
+static inline int ftrace_graph_addr(unsigned long addr)
+{
+	return 1;
+}
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#else /* CONFIG_FUNCTION_GRAPH_TRACER */
+static inline enum print_line_t
+print_graph_function(struct trace_iterator *iter)
+{
+	return TRACE_TYPE_UNHANDLED;
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+extern struct pid *ftrace_pid_trace;
+
+static inline int ftrace_trace_task(struct task_struct *task)
+{
+	if (!ftrace_pid_trace)
+		return 1;
+
+	return test_tsk_trace_trace(task);
+}
+
 /*
  * trace_iterator_flags is an enumeration that defines bit
  * positions into trace_flags that controls the output.
@@ -415,8 +575,93 @@
 	TRACE_ITER_STACKTRACE		= 0x100,
 	TRACE_ITER_SCHED_TREE		= 0x200,
 	TRACE_ITER_PRINTK		= 0x400,
+	TRACE_ITER_PREEMPTONLY		= 0x800,
+	TRACE_ITER_BRANCH		= 0x1000,
+	TRACE_ITER_ANNOTATE		= 0x2000,
+	TRACE_ITER_USERSTACKTRACE       = 0x4000,
+	TRACE_ITER_SYM_USEROBJ          = 0x8000,
+	TRACE_ITER_PRINTK_MSGONLY	= 0x10000
 };
 
+/*
+ * TRACE_ITER_SYM_MASK masks the options in trace_flags that
+ * control the output of kernel symbols.
+ */
+#define TRACE_ITER_SYM_MASK \
+	(TRACE_ITER_PRINT_PARENT|TRACE_ITER_SYM_OFFSET|TRACE_ITER_SYM_ADDR)
+
 extern struct tracer nop_trace;
 
+/**
+ * ftrace_preempt_disable - disable preemption scheduler safe
+ *
+ * When tracing can happen inside the scheduler, there exists
+ * cases that the tracing might happen before the need_resched
+ * flag is checked. If this happens and the tracer calls
+ * preempt_enable (after a disable), a schedule might take place
+ * causing an infinite recursion.
+ *
+ * To prevent this, we read the need_recshed flag before
+ * disabling preemption. When we want to enable preemption we
+ * check the flag, if it is set, then we call preempt_enable_no_resched.
+ * Otherwise, we call preempt_enable.
+ *
+ * The rational for doing the above is that if need resched is set
+ * and we have yet to reschedule, we are either in an atomic location
+ * (where we do not need to check for scheduling) or we are inside
+ * the scheduler and do not want to resched.
+ */
+static inline int ftrace_preempt_disable(void)
+{
+	int resched;
+
+	resched = need_resched();
+	preempt_disable_notrace();
+
+	return resched;
+}
+
+/**
+ * ftrace_preempt_enable - enable preemption scheduler safe
+ * @resched: the return value from ftrace_preempt_disable
+ *
+ * This is a scheduler safe way to enable preemption and not miss
+ * any preemption checks. The disabled saved the state of preemption.
+ * If resched is set, then we were either inside an atomic or
+ * are inside the scheduler (we would have already scheduled
+ * otherwise). In this case, we do not want to call normal
+ * preempt_enable, but preempt_enable_no_resched instead.
+ */
+static inline void ftrace_preempt_enable(int resched)
+{
+	if (resched)
+		preempt_enable_no_resched_notrace();
+	else
+		preempt_enable_notrace();
+}
+
+#ifdef CONFIG_BRANCH_TRACER
+extern int enable_branch_tracing(struct trace_array *tr);
+extern void disable_branch_tracing(void);
+static inline int trace_branch_enable(struct trace_array *tr)
+{
+	if (trace_flags & TRACE_ITER_BRANCH)
+		return enable_branch_tracing(tr);
+	return 0;
+}
+static inline void trace_branch_disable(void)
+{
+	/* due to races, always disable */
+	disable_branch_tracing();
+}
+#else
+static inline int trace_branch_enable(struct trace_array *tr)
+{
+	return 0;
+}
+static inline void trace_branch_disable(void)
+{
+}
+#endif /* CONFIG_BRANCH_TRACER */
+
 #endif /* _LINUX_KERNEL_TRACE_H */
diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c
index d0a5e50..3ccebde 100644
--- a/kernel/trace/trace_boot.c
+++ b/kernel/trace/trace_boot.c
@@ -13,101 +13,132 @@
 #include "trace.h"
 
 static struct trace_array *boot_trace;
-static int trace_boot_enabled;
+static bool pre_initcalls_finished;
 
-
-/* Should be started after do_pre_smp_initcalls() in init/main.c */
+/* Tells the boot tracer that the pre_smp_initcalls are finished.
+ * So we are ready .
+ * It doesn't enable sched events tracing however.
+ * You have to call enable_boot_trace to do so.
+ */
 void start_boot_trace(void)
 {
-	trace_boot_enabled = 1;
+	pre_initcalls_finished = true;
 }
 
-void stop_boot_trace(void)
+void enable_boot_trace(void)
 {
-	trace_boot_enabled = 0;
+	if (pre_initcalls_finished)
+		tracing_start_sched_switch_record();
 }
 
-void reset_boot_trace(struct trace_array *tr)
+void disable_boot_trace(void)
 {
-	stop_boot_trace();
+	if (pre_initcalls_finished)
+		tracing_stop_sched_switch_record();
 }
 
-static void boot_trace_init(struct trace_array *tr)
+static int boot_trace_init(struct trace_array *tr)
 {
 	int cpu;
 	boot_trace = tr;
 
-	trace_boot_enabled = 0;
-
 	for_each_cpu_mask(cpu, cpu_possible_map)
 		tracing_reset(tr, cpu);
+
+	tracing_sched_switch_assign_trace(tr);
+	return 0;
 }
 
-static void boot_trace_ctrl_update(struct trace_array *tr)
+static enum print_line_t
+initcall_call_print_line(struct trace_iterator *iter)
 {
-	if (tr->ctrl)
-		start_boot_trace();
+	struct trace_entry *entry = iter->ent;
+	struct trace_seq *s = &iter->seq;
+	struct trace_boot_call *field;
+	struct boot_trace_call *call;
+	u64 ts;
+	unsigned long nsec_rem;
+	int ret;
+
+	trace_assign_type(field, entry);
+	call = &field->boot_call;
+	ts = iter->ts;
+	nsec_rem = do_div(ts, 1000000000);
+
+	ret = trace_seq_printf(s, "[%5ld.%09ld] calling  %s @ %i\n",
+			(unsigned long)ts, nsec_rem, call->func, call->caller);
+
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
 	else
-		stop_boot_trace();
+		return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t
+initcall_ret_print_line(struct trace_iterator *iter)
+{
+	struct trace_entry *entry = iter->ent;
+	struct trace_seq *s = &iter->seq;
+	struct trace_boot_ret *field;
+	struct boot_trace_ret *init_ret;
+	u64 ts;
+	unsigned long nsec_rem;
+	int ret;
+
+	trace_assign_type(field, entry);
+	init_ret = &field->boot_ret;
+	ts = iter->ts;
+	nsec_rem = do_div(ts, 1000000000);
+
+	ret = trace_seq_printf(s, "[%5ld.%09ld] initcall %s "
+			"returned %d after %llu msecs\n",
+			(unsigned long) ts,
+			nsec_rem,
+			init_ret->func, init_ret->result, init_ret->duration);
+
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+	else
+		return TRACE_TYPE_HANDLED;
 }
 
 static enum print_line_t initcall_print_line(struct trace_iterator *iter)
 {
-	int ret;
 	struct trace_entry *entry = iter->ent;
-	struct trace_boot *field = (struct trace_boot *)entry;
-	struct boot_trace *it = &field->initcall;
-	struct trace_seq *s = &iter->seq;
-	struct timespec calltime = ktime_to_timespec(it->calltime);
-	struct timespec rettime = ktime_to_timespec(it->rettime);
 
-	if (entry->type == TRACE_BOOT) {
-		ret = trace_seq_printf(s, "[%5ld.%09ld] calling  %s @ %i\n",
-					  calltime.tv_sec,
-					  calltime.tv_nsec,
-					  it->func, it->caller);
-		if (!ret)
-			return TRACE_TYPE_PARTIAL_LINE;
-
-		ret = trace_seq_printf(s, "[%5ld.%09ld] initcall %s "
-					  "returned %d after %lld msecs\n",
-					  rettime.tv_sec,
-					  rettime.tv_nsec,
-					  it->func, it->result, it->duration);
-
-		if (!ret)
-			return TRACE_TYPE_PARTIAL_LINE;
-		return TRACE_TYPE_HANDLED;
+	switch (entry->type) {
+	case TRACE_BOOT_CALL:
+		return initcall_call_print_line(iter);
+	case TRACE_BOOT_RET:
+		return initcall_ret_print_line(iter);
+	default:
+		return TRACE_TYPE_UNHANDLED;
 	}
-	return TRACE_TYPE_UNHANDLED;
 }
 
 struct tracer boot_tracer __read_mostly =
 {
 	.name		= "initcall",
 	.init		= boot_trace_init,
-	.reset		= reset_boot_trace,
-	.ctrl_update	= boot_trace_ctrl_update,
+	.reset		= tracing_reset_online_cpus,
 	.print_line	= initcall_print_line,
 };
 
-void trace_boot(struct boot_trace *it, initcall_t fn)
+void trace_boot_call(struct boot_trace_call *bt, initcall_t fn)
 {
 	struct ring_buffer_event *event;
-	struct trace_boot *entry;
-	struct trace_array_cpu *data;
+	struct trace_boot_call *entry;
 	unsigned long irq_flags;
 	struct trace_array *tr = boot_trace;
 
-	if (!trace_boot_enabled)
+	if (!pre_initcalls_finished)
 		return;
 
 	/* Get its name now since this function could
 	 * disappear because it is in the .init section.
 	 */
-	sprint_symbol(it->func, (unsigned long)fn);
+	sprint_symbol(bt->func, (unsigned long)fn);
 	preempt_disable();
-	data = tr->data[smp_processor_id()];
 
 	event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
 					 &irq_flags);
@@ -115,8 +146,37 @@
 		goto out;
 	entry	= ring_buffer_event_data(event);
 	tracing_generic_entry_update(&entry->ent, 0, 0);
-	entry->ent.type = TRACE_BOOT;
-	entry->initcall = *it;
+	entry->ent.type = TRACE_BOOT_CALL;
+	entry->boot_call = *bt;
+	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
+
+	trace_wake_up();
+
+ out:
+	preempt_enable();
+}
+
+void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn)
+{
+	struct ring_buffer_event *event;
+	struct trace_boot_ret *entry;
+	unsigned long irq_flags;
+	struct trace_array *tr = boot_trace;
+
+	if (!pre_initcalls_finished)
+		return;
+
+	sprint_symbol(bt->func, (unsigned long)fn);
+	preempt_disable();
+
+	event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
+					 &irq_flags);
+	if (!event)
+		goto out;
+	entry	= ring_buffer_event_data(event);
+	tracing_generic_entry_update(&entry->ent, 0, 0);
+	entry->ent.type = TRACE_BOOT_RET;
+	entry->boot_ret = *bt;
 	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
 
 	trace_wake_up();
diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c
new file mode 100644
index 0000000..6c00feb
--- /dev/null
+++ b/kernel/trace/trace_branch.c
@@ -0,0 +1,342 @@
+/*
+ * unlikely profiler
+ *
+ * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com>
+ */
+#include <linux/kallsyms.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+#include <linux/irqflags.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/ftrace.h>
+#include <linux/hash.h>
+#include <linux/fs.h>
+#include <asm/local.h>
+#include "trace.h"
+
+#ifdef CONFIG_BRANCH_TRACER
+
+static int branch_tracing_enabled __read_mostly;
+static DEFINE_MUTEX(branch_tracing_mutex);
+static struct trace_array *branch_tracer;
+
+static void
+probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
+{
+	struct trace_array *tr = branch_tracer;
+	struct ring_buffer_event *event;
+	struct trace_branch *entry;
+	unsigned long flags, irq_flags;
+	int cpu, pc;
+	const char *p;
+
+	/*
+	 * I would love to save just the ftrace_likely_data pointer, but
+	 * this code can also be used by modules. Ugly things can happen
+	 * if the module is unloaded, and then we go and read the
+	 * pointer.  This is slower, but much safer.
+	 */
+
+	if (unlikely(!tr))
+		return;
+
+	local_irq_save(flags);
+	cpu = raw_smp_processor_id();
+	if (atomic_inc_return(&tr->data[cpu]->disabled) != 1)
+		goto out;
+
+	event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
+					 &irq_flags);
+	if (!event)
+		goto out;
+
+	pc = preempt_count();
+	entry	= ring_buffer_event_data(event);
+	tracing_generic_entry_update(&entry->ent, flags, pc);
+	entry->ent.type		= TRACE_BRANCH;
+
+	/* Strip off the path, only save the file */
+	p = f->file + strlen(f->file);
+	while (p >= f->file && *p != '/')
+		p--;
+	p++;
+
+	strncpy(entry->func, f->func, TRACE_FUNC_SIZE);
+	strncpy(entry->file, p, TRACE_FILE_SIZE);
+	entry->func[TRACE_FUNC_SIZE] = 0;
+	entry->file[TRACE_FILE_SIZE] = 0;
+	entry->line = f->line;
+	entry->correct = val == expect;
+
+	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
+
+ out:
+	atomic_dec(&tr->data[cpu]->disabled);
+	local_irq_restore(flags);
+}
+
+static inline
+void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect)
+{
+	if (!branch_tracing_enabled)
+		return;
+
+	probe_likely_condition(f, val, expect);
+}
+
+int enable_branch_tracing(struct trace_array *tr)
+{
+	int ret = 0;
+
+	mutex_lock(&branch_tracing_mutex);
+	branch_tracer = tr;
+	/*
+	 * Must be seen before enabling. The reader is a condition
+	 * where we do not need a matching rmb()
+	 */
+	smp_wmb();
+	branch_tracing_enabled++;
+	mutex_unlock(&branch_tracing_mutex);
+
+	return ret;
+}
+
+void disable_branch_tracing(void)
+{
+	mutex_lock(&branch_tracing_mutex);
+
+	if (!branch_tracing_enabled)
+		goto out_unlock;
+
+	branch_tracing_enabled--;
+
+ out_unlock:
+	mutex_unlock(&branch_tracing_mutex);
+}
+
+static void start_branch_trace(struct trace_array *tr)
+{
+	enable_branch_tracing(tr);
+}
+
+static void stop_branch_trace(struct trace_array *tr)
+{
+	disable_branch_tracing();
+}
+
+static int branch_trace_init(struct trace_array *tr)
+{
+	int cpu;
+
+	for_each_online_cpu(cpu)
+		tracing_reset(tr, cpu);
+
+	start_branch_trace(tr);
+	return 0;
+}
+
+static void branch_trace_reset(struct trace_array *tr)
+{
+	stop_branch_trace(tr);
+}
+
+struct tracer branch_trace __read_mostly =
+{
+	.name		= "branch",
+	.init		= branch_trace_init,
+	.reset		= branch_trace_reset,
+#ifdef CONFIG_FTRACE_SELFTEST
+	.selftest	= trace_selftest_startup_branch,
+#endif
+};
+
+__init static int init_branch_trace(void)
+{
+	return register_tracer(&branch_trace);
+}
+
+device_initcall(init_branch_trace);
+#else
+static inline
+void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect)
+{
+}
+#endif /* CONFIG_BRANCH_TRACER */
+
+void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect)
+{
+	/*
+	 * I would love to have a trace point here instead, but the
+	 * trace point code is so inundated with unlikely and likely
+	 * conditions that the recursive nightmare that exists is too
+	 * much to try to get working. At least for now.
+	 */
+	trace_likely_condition(f, val, expect);
+
+	/* FIXME: Make this atomic! */
+	if (val == expect)
+		f->correct++;
+	else
+		f->incorrect++;
+}
+EXPORT_SYMBOL(ftrace_likely_update);
+
+struct ftrace_pointer {
+	void		*start;
+	void		*stop;
+	int		hit;
+};
+
+static void *
+t_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	const struct ftrace_pointer *f = m->private;
+	struct ftrace_branch_data *p = v;
+
+	(*pos)++;
+
+	if (v == (void *)1)
+		return f->start;
+
+	++p;
+
+	if ((void *)p >= (void *)f->stop)
+		return NULL;
+
+	return p;
+}
+
+static void *t_start(struct seq_file *m, loff_t *pos)
+{
+	void *t = (void *)1;
+	loff_t l = 0;
+
+	for (; t && l < *pos; t = t_next(m, t, &l))
+		;
+
+	return t;
+}
+
+static void t_stop(struct seq_file *m, void *p)
+{
+}
+
+static int t_show(struct seq_file *m, void *v)
+{
+	const struct ftrace_pointer *fp = m->private;
+	struct ftrace_branch_data *p = v;
+	const char *f;
+	long percent;
+
+	if (v == (void *)1) {
+		if (fp->hit)
+			seq_printf(m, "   miss      hit    %% ");
+		else
+			seq_printf(m, " correct incorrect  %% ");
+		seq_printf(m, "       Function                "
+			      "  File              Line\n"
+			      " ------- ---------  - "
+			      "       --------                "
+			      "  ----              ----\n");
+		return 0;
+	}
+
+	/* Only print the file, not the path */
+	f = p->file + strlen(p->file);
+	while (f >= p->file && *f != '/')
+		f--;
+	f++;
+
+	/*
+	 * The miss is overlayed on correct, and hit on incorrect.
+	 */
+	if (p->correct) {
+		percent = p->incorrect * 100;
+		percent /= p->correct + p->incorrect;
+	} else
+		percent = p->incorrect ? 100 : -1;
+
+	seq_printf(m, "%8lu %8lu ",  p->correct, p->incorrect);
+	if (percent < 0)
+		seq_printf(m, "  X ");
+	else
+		seq_printf(m, "%3ld ", percent);
+	seq_printf(m, "%-30.30s %-20.20s %d\n", p->func, f, p->line);
+	return 0;
+}
+
+static struct seq_operations tracing_likely_seq_ops = {
+	.start		= t_start,
+	.next		= t_next,
+	.stop		= t_stop,
+	.show		= t_show,
+};
+
+static int tracing_branch_open(struct inode *inode, struct file *file)
+{
+	int ret;
+
+	ret = seq_open(file, &tracing_likely_seq_ops);
+	if (!ret) {
+		struct seq_file *m = file->private_data;
+		m->private = (void *)inode->i_private;
+	}
+
+	return ret;
+}
+
+static const struct file_operations tracing_branch_fops = {
+	.open		= tracing_branch_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+};
+
+#ifdef CONFIG_PROFILE_ALL_BRANCHES
+extern unsigned long __start_branch_profile[];
+extern unsigned long __stop_branch_profile[];
+
+static const struct ftrace_pointer ftrace_branch_pos = {
+	.start			= __start_branch_profile,
+	.stop			= __stop_branch_profile,
+	.hit			= 1,
+};
+
+#endif /* CONFIG_PROFILE_ALL_BRANCHES */
+
+extern unsigned long __start_annotated_branch_profile[];
+extern unsigned long __stop_annotated_branch_profile[];
+
+static const struct ftrace_pointer ftrace_annotated_branch_pos = {
+	.start			= __start_annotated_branch_profile,
+	.stop			= __stop_annotated_branch_profile,
+};
+
+static __init int ftrace_branch_init(void)
+{
+	struct dentry *d_tracer;
+	struct dentry *entry;
+
+	d_tracer = tracing_init_dentry();
+
+	entry = debugfs_create_file("profile_annotated_branch", 0444, d_tracer,
+				    (void *)&ftrace_annotated_branch_pos,
+				    &tracing_branch_fops);
+	if (!entry)
+		pr_warning("Could not create debugfs "
+			   "'profile_annotatet_branch' entry\n");
+
+#ifdef CONFIG_PROFILE_ALL_BRANCHES
+	entry = debugfs_create_file("profile_branch", 0444, d_tracer,
+				    (void *)&ftrace_branch_pos,
+				    &tracing_branch_fops);
+	if (!entry)
+		pr_warning("Could not create debugfs"
+			   " 'profile_branch' entry\n");
+#endif
+
+	return 0;
+}
+
+device_initcall(ftrace_branch_init);
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 0f85a64..9236d7e 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -16,20 +16,10 @@
 
 #include "trace.h"
 
-static void function_reset(struct trace_array *tr)
-{
-	int cpu;
-
-	tr->time_start = ftrace_now(tr->cpu);
-
-	for_each_online_cpu(cpu)
-		tracing_reset(tr, cpu);
-}
-
 static void start_function_trace(struct trace_array *tr)
 {
 	tr->cpu = get_cpu();
-	function_reset(tr);
+	tracing_reset_online_cpus(tr);
 	put_cpu();
 
 	tracing_start_cmdline_record();
@@ -42,24 +32,20 @@
 	tracing_stop_cmdline_record();
 }
 
-static void function_trace_init(struct trace_array *tr)
+static int function_trace_init(struct trace_array *tr)
 {
-	if (tr->ctrl)
-		start_function_trace(tr);
+	start_function_trace(tr);
+	return 0;
 }
 
 static void function_trace_reset(struct trace_array *tr)
 {
-	if (tr->ctrl)
-		stop_function_trace(tr);
+	stop_function_trace(tr);
 }
 
-static void function_trace_ctrl_update(struct trace_array *tr)
+static void function_trace_start(struct trace_array *tr)
 {
-	if (tr->ctrl)
-		start_function_trace(tr);
-	else
-		stop_function_trace(tr);
+	tracing_reset_online_cpus(tr);
 }
 
 static struct tracer function_trace __read_mostly =
@@ -67,7 +53,7 @@
 	.name	     = "function",
 	.init	     = function_trace_init,
 	.reset	     = function_trace_reset,
-	.ctrl_update = function_trace_ctrl_update,
+	.start	     = function_trace_start,
 #ifdef CONFIG_FTRACE_SELFTEST
 	.selftest    = trace_selftest_startup_function,
 #endif
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
new file mode 100644
index 0000000..4bf39fc
--- /dev/null
+++ b/kernel/trace/trace_functions_graph.c
@@ -0,0 +1,669 @@
+/*
+ *
+ * Function graph tracer.
+ * Copyright (c) 2008 Frederic Weisbecker <fweisbec@gmail.com>
+ * Mostly borrowed from function tracer which
+ * is Copyright (c) Steven Rostedt <srostedt@redhat.com>
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/ftrace.h>
+#include <linux/fs.h>
+
+#include "trace.h"
+
+#define TRACE_GRAPH_INDENT	2
+
+/* Flag options */
+#define TRACE_GRAPH_PRINT_OVERRUN	0x1
+#define TRACE_GRAPH_PRINT_CPU		0x2
+#define TRACE_GRAPH_PRINT_OVERHEAD	0x4
+#define TRACE_GRAPH_PRINT_PROC		0x8
+
+static struct tracer_opt trace_opts[] = {
+	/* Display overruns ? */
+	{ TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) },
+	/* Display CPU ? */
+	{ TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) },
+	/* Display Overhead ? */
+	{ TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) },
+	/* Display proc name/pid */
+	{ TRACER_OPT(funcgraph-proc, TRACE_GRAPH_PRINT_PROC) },
+	{ } /* Empty entry */
+};
+
+static struct tracer_flags tracer_flags = {
+	/* Don't display overruns and proc by default */
+	.val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD,
+	.opts = trace_opts
+};
+
+/* pid on the last trace processed */
+static pid_t last_pid[NR_CPUS] = { [0 ... NR_CPUS-1] = -1 };
+
+static int graph_trace_init(struct trace_array *tr)
+{
+	int cpu, ret;
+
+	for_each_online_cpu(cpu)
+		tracing_reset(tr, cpu);
+
+	ret = register_ftrace_graph(&trace_graph_return,
+					&trace_graph_entry);
+	if (ret)
+		return ret;
+	tracing_start_cmdline_record();
+
+	return 0;
+}
+
+static void graph_trace_reset(struct trace_array *tr)
+{
+	tracing_stop_cmdline_record();
+	unregister_ftrace_graph();
+}
+
+static inline int log10_cpu(int nb)
+{
+	if (nb / 100)
+		return 3;
+	if (nb / 10)
+		return 2;
+	return 1;
+}
+
+static enum print_line_t
+print_graph_cpu(struct trace_seq *s, int cpu)
+{
+	int i;
+	int ret;
+	int log10_this = log10_cpu(cpu);
+	int log10_all = log10_cpu(cpus_weight_nr(cpu_online_map));
+
+
+	/*
+	 * Start with a space character - to make it stand out
+	 * to the right a bit when trace output is pasted into
+	 * email:
+	 */
+	ret = trace_seq_printf(s, " ");
+
+	/*
+	 * Tricky - we space the CPU field according to the max
+	 * number of online CPUs. On a 2-cpu system it would take
+	 * a maximum of 1 digit - on a 128 cpu system it would
+	 * take up to 3 digits:
+	 */
+	for (i = 0; i < log10_all - log10_this; i++) {
+		ret = trace_seq_printf(s, " ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+	ret = trace_seq_printf(s, "%d) ", cpu);
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	return TRACE_TYPE_HANDLED;
+}
+
+#define TRACE_GRAPH_PROCINFO_LENGTH	14
+
+static enum print_line_t
+print_graph_proc(struct trace_seq *s, pid_t pid)
+{
+	int i;
+	int ret;
+	int len;
+	char comm[8];
+	int spaces = 0;
+	/* sign + log10(MAX_INT) + '\0' */
+	char pid_str[11];
+
+	strncpy(comm, trace_find_cmdline(pid), 7);
+	comm[7] = '\0';
+	sprintf(pid_str, "%d", pid);
+
+	/* 1 stands for the "-" character */
+	len = strlen(comm) + strlen(pid_str) + 1;
+
+	if (len < TRACE_GRAPH_PROCINFO_LENGTH)
+		spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
+
+	/* First spaces to align center */
+	for (i = 0; i < spaces / 2; i++) {
+		ret = trace_seq_printf(s, " ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	ret = trace_seq_printf(s, "%s-%s", comm, pid_str);
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	/* Last spaces to align center */
+	for (i = 0; i < spaces - (spaces / 2); i++) {
+		ret = trace_seq_printf(s, " ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+	return TRACE_TYPE_HANDLED;
+}
+
+
+/* If the pid changed since the last trace, output this event */
+static enum print_line_t
+verif_pid(struct trace_seq *s, pid_t pid, int cpu)
+{
+	pid_t prev_pid;
+	int ret;
+
+	if (last_pid[cpu] != -1 && last_pid[cpu] == pid)
+		return TRACE_TYPE_HANDLED;
+
+	prev_pid = last_pid[cpu];
+	last_pid[cpu] = pid;
+
+/*
+ * Context-switch trace line:
+
+ ------------------------------------------
+ | 1)  migration/0--1  =>  sshd-1755
+ ------------------------------------------
+
+ */
+	ret = trace_seq_printf(s,
+		" ------------------------------------------\n");
+	if (!ret)
+		TRACE_TYPE_PARTIAL_LINE;
+
+	ret = print_graph_cpu(s, cpu);
+	if (ret == TRACE_TYPE_PARTIAL_LINE)
+		TRACE_TYPE_PARTIAL_LINE;
+
+	ret = print_graph_proc(s, prev_pid);
+	if (ret == TRACE_TYPE_PARTIAL_LINE)
+		TRACE_TYPE_PARTIAL_LINE;
+
+	ret = trace_seq_printf(s, " => ");
+	if (!ret)
+		TRACE_TYPE_PARTIAL_LINE;
+
+	ret = print_graph_proc(s, pid);
+	if (ret == TRACE_TYPE_PARTIAL_LINE)
+		TRACE_TYPE_PARTIAL_LINE;
+
+	ret = trace_seq_printf(s,
+		"\n ------------------------------------------\n\n");
+	if (!ret)
+		TRACE_TYPE_PARTIAL_LINE;
+
+	return ret;
+}
+
+static bool
+trace_branch_is_leaf(struct trace_iterator *iter,
+		struct ftrace_graph_ent_entry *curr)
+{
+	struct ring_buffer_iter *ring_iter;
+	struct ring_buffer_event *event;
+	struct ftrace_graph_ret_entry *next;
+
+	ring_iter = iter->buffer_iter[iter->cpu];
+
+	if (!ring_iter)
+		return false;
+
+	event = ring_buffer_iter_peek(ring_iter, NULL);
+
+	if (!event)
+		return false;
+
+	next = ring_buffer_event_data(event);
+
+	if (next->ent.type != TRACE_GRAPH_RET)
+		return false;
+
+	if (curr->ent.pid != next->ent.pid ||
+			curr->graph_ent.func != next->ret.func)
+		return false;
+
+	return true;
+}
+
+static enum print_line_t
+print_graph_irq(struct trace_seq *s, unsigned long addr,
+				enum trace_type type, int cpu, pid_t pid)
+{
+	int ret;
+
+	if (addr < (unsigned long)__irqentry_text_start ||
+		addr >= (unsigned long)__irqentry_text_end)
+		return TRACE_TYPE_UNHANDLED;
+
+	if (type == TRACE_GRAPH_ENT) {
+		ret = trace_seq_printf(s, "==========> |  ");
+	} else {
+		/* Cpu */
+		if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
+			ret = print_graph_cpu(s, cpu);
+			if (ret == TRACE_TYPE_PARTIAL_LINE)
+				return TRACE_TYPE_PARTIAL_LINE;
+		}
+		/* Proc */
+		if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
+			ret = print_graph_proc(s, pid);
+			if (ret == TRACE_TYPE_PARTIAL_LINE)
+				return TRACE_TYPE_PARTIAL_LINE;
+
+			ret = trace_seq_printf(s, " | ");
+			if (!ret)
+				return TRACE_TYPE_PARTIAL_LINE;
+		}
+
+		/* No overhead */
+		if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
+			ret = trace_seq_printf(s, "  ");
+			if (!ret)
+				return TRACE_TYPE_PARTIAL_LINE;
+		}
+
+		ret = trace_seq_printf(s, "<========== |\n");
+	}
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+	return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t
+print_graph_duration(unsigned long long duration, struct trace_seq *s)
+{
+	unsigned long nsecs_rem = do_div(duration, 1000);
+	/* log10(ULONG_MAX) + '\0' */
+	char msecs_str[21];
+	char nsecs_str[5];
+	int ret, len;
+	int i;
+
+	sprintf(msecs_str, "%lu", (unsigned long) duration);
+
+	/* Print msecs */
+	ret = trace_seq_printf(s, msecs_str);
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	len = strlen(msecs_str);
+
+	/* Print nsecs (we don't want to exceed 7 numbers) */
+	if (len < 7) {
+		snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
+		ret = trace_seq_printf(s, ".%s", nsecs_str);
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+		len += strlen(nsecs_str);
+	}
+
+	ret = trace_seq_printf(s, " us ");
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	/* Print remaining spaces to fit the row's width */
+	for (i = len; i < 7; i++) {
+		ret = trace_seq_printf(s, " ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	ret = trace_seq_printf(s, "|  ");
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+	return TRACE_TYPE_HANDLED;
+
+}
+
+/* Signal a overhead of time execution to the output */
+static int
+print_graph_overhead(unsigned long long duration, struct trace_seq *s)
+{
+	/* Duration exceeded 100 msecs */
+	if (duration > 100000ULL)
+		return trace_seq_printf(s, "! ");
+
+	/* Duration exceeded 10 msecs */
+	if (duration > 10000ULL)
+		return trace_seq_printf(s, "+ ");
+
+	return trace_seq_printf(s, "  ");
+}
+
+/* Case of a leaf function on its call entry */
+static enum print_line_t
+print_graph_entry_leaf(struct trace_iterator *iter,
+		struct ftrace_graph_ent_entry *entry, struct trace_seq *s)
+{
+	struct ftrace_graph_ret_entry *ret_entry;
+	struct ftrace_graph_ret *graph_ret;
+	struct ring_buffer_event *event;
+	struct ftrace_graph_ent *call;
+	unsigned long long duration;
+	int ret;
+	int i;
+
+	event = ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
+	ret_entry = ring_buffer_event_data(event);
+	graph_ret = &ret_entry->ret;
+	call = &entry->graph_ent;
+	duration = graph_ret->rettime - graph_ret->calltime;
+
+	/* Overhead */
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
+		ret = print_graph_overhead(duration, s);
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	/* Duration */
+	ret = print_graph_duration(duration, s);
+	if (ret == TRACE_TYPE_PARTIAL_LINE)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	/* Function */
+	for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
+		ret = trace_seq_printf(s, " ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	ret = seq_print_ip_sym(s, call->func, 0);
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	ret = trace_seq_printf(s, "();\n");
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t
+print_graph_entry_nested(struct ftrace_graph_ent_entry *entry,
+			struct trace_seq *s, pid_t pid, int cpu)
+{
+	int i;
+	int ret;
+	struct ftrace_graph_ent *call = &entry->graph_ent;
+
+	/* No overhead */
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
+		ret = trace_seq_printf(s, "  ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	/* Interrupt */
+	ret = print_graph_irq(s, call->func, TRACE_GRAPH_ENT, cpu, pid);
+	if (ret == TRACE_TYPE_UNHANDLED) {
+		/* No time */
+		ret = trace_seq_printf(s, "            |  ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	} else {
+		if (ret == TRACE_TYPE_PARTIAL_LINE)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+
+	/* Function */
+	for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
+		ret = trace_seq_printf(s, " ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	ret = seq_print_ip_sym(s, call->func, 0);
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	ret = trace_seq_printf(s, "() {\n");
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t
+print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
+			struct trace_iterator *iter, int cpu)
+{
+	int ret;
+	struct trace_entry *ent = iter->ent;
+
+	/* Pid */
+	if (verif_pid(s, ent->pid, cpu) == TRACE_TYPE_PARTIAL_LINE)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	/* Cpu */
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
+		ret = print_graph_cpu(s, cpu);
+		if (ret == TRACE_TYPE_PARTIAL_LINE)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	/* Proc */
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
+		ret = print_graph_proc(s, ent->pid);
+		if (ret == TRACE_TYPE_PARTIAL_LINE)
+			return TRACE_TYPE_PARTIAL_LINE;
+
+		ret = trace_seq_printf(s, " | ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	if (trace_branch_is_leaf(iter, field))
+		return print_graph_entry_leaf(iter, field, s);
+	else
+		return print_graph_entry_nested(field, s, iter->ent->pid, cpu);
+
+}
+
+static enum print_line_t
+print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
+		   struct trace_entry *ent, int cpu)
+{
+	int i;
+	int ret;
+	unsigned long long duration = trace->rettime - trace->calltime;
+
+	/* Pid */
+	if (verif_pid(s, ent->pid, cpu) == TRACE_TYPE_PARTIAL_LINE)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	/* Cpu */
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
+		ret = print_graph_cpu(s, cpu);
+		if (ret == TRACE_TYPE_PARTIAL_LINE)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	/* Proc */
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
+		ret = print_graph_proc(s, ent->pid);
+		if (ret == TRACE_TYPE_PARTIAL_LINE)
+			return TRACE_TYPE_PARTIAL_LINE;
+
+		ret = trace_seq_printf(s, " | ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	/* Overhead */
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
+		ret = print_graph_overhead(duration, s);
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	/* Duration */
+	ret = print_graph_duration(duration, s);
+	if (ret == TRACE_TYPE_PARTIAL_LINE)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	/* Closing brace */
+	for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) {
+		ret = trace_seq_printf(s, " ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	ret = trace_seq_printf(s, "}\n");
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	/* Overrun */
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERRUN) {
+		ret = trace_seq_printf(s, " (Overruns: %lu)\n",
+					trace->overrun);
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	ret = print_graph_irq(s, trace->func, TRACE_GRAPH_RET, cpu, ent->pid);
+	if (ret == TRACE_TYPE_PARTIAL_LINE)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	return TRACE_TYPE_HANDLED;
+}
+
+static enum print_line_t
+print_graph_comment(struct print_entry *trace, struct trace_seq *s,
+		   struct trace_entry *ent, struct trace_iterator *iter)
+{
+	int i;
+	int ret;
+
+	/* Pid */
+	if (verif_pid(s, ent->pid, iter->cpu) == TRACE_TYPE_PARTIAL_LINE)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	/* Cpu */
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
+		ret = print_graph_cpu(s, iter->cpu);
+		if (ret == TRACE_TYPE_PARTIAL_LINE)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	/* Proc */
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
+		ret = print_graph_proc(s, ent->pid);
+		if (ret == TRACE_TYPE_PARTIAL_LINE)
+			return TRACE_TYPE_PARTIAL_LINE;
+
+		ret = trace_seq_printf(s, " | ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	/* No overhead */
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
+		ret = trace_seq_printf(s, "  ");
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+	}
+
+	/* No time */
+	ret = trace_seq_printf(s, "            |  ");
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	/* Indentation */
+	if (trace->depth > 0)
+		for (i = 0; i < (trace->depth + 1) * TRACE_GRAPH_INDENT; i++) {
+			ret = trace_seq_printf(s, " ");
+			if (!ret)
+				return TRACE_TYPE_PARTIAL_LINE;
+		}
+
+	/* The comment */
+	ret = trace_seq_printf(s, "/* %s", trace->buf);
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	if (ent->flags & TRACE_FLAG_CONT)
+		trace_seq_print_cont(s, iter);
+
+	ret = trace_seq_printf(s, " */\n");
+	if (!ret)
+		return TRACE_TYPE_PARTIAL_LINE;
+
+	return TRACE_TYPE_HANDLED;
+}
+
+
+enum print_line_t
+print_graph_function(struct trace_iterator *iter)
+{
+	struct trace_seq *s = &iter->seq;
+	struct trace_entry *entry = iter->ent;
+
+	switch (entry->type) {
+	case TRACE_GRAPH_ENT: {
+		struct ftrace_graph_ent_entry *field;
+		trace_assign_type(field, entry);
+		return print_graph_entry(field, s, iter,
+					 iter->cpu);
+	}
+	case TRACE_GRAPH_RET: {
+		struct ftrace_graph_ret_entry *field;
+		trace_assign_type(field, entry);
+		return print_graph_return(&field->ret, s, entry, iter->cpu);
+	}
+	case TRACE_PRINT: {
+		struct print_entry *field;
+		trace_assign_type(field, entry);
+		return print_graph_comment(field, s, entry, iter);
+	}
+	default:
+		return TRACE_TYPE_UNHANDLED;
+	}
+}
+
+static void print_graph_headers(struct seq_file *s)
+{
+	/* 1st line */
+	seq_printf(s, "# ");
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU)
+		seq_printf(s, "CPU ");
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC)
+		seq_printf(s, "TASK/PID     ");
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD)
+		seq_printf(s, "OVERHEAD/");
+	seq_printf(s, "DURATION            FUNCTION CALLS\n");
+
+	/* 2nd line */
+	seq_printf(s, "# ");
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU)
+		seq_printf(s, "|   ");
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC)
+		seq_printf(s, "|      |     ");
+	if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
+		seq_printf(s, "|        ");
+		seq_printf(s, "|                   |   |   |   |\n");
+	} else
+		seq_printf(s, "    |               |   |   |   |\n");
+}
+static struct tracer graph_trace __read_mostly = {
+	.name	     	= "function_graph",
+	.init	     	= graph_trace_init,
+	.reset	     	= graph_trace_reset,
+	.print_line	= print_graph_function,
+	.print_header	= print_graph_headers,
+	.flags		= &tracer_flags,
+};
+
+static __init int init_graph_trace(void)
+{
+	return register_tracer(&graph_trace);
+}
+
+device_initcall(init_graph_trace);
diff --git a/kernel/trace/trace_hw_branches.c b/kernel/trace/trace_hw_branches.c
new file mode 100644
index 0000000..b6a3e20
--- /dev/null
+++ b/kernel/trace/trace_hw_branches.c
@@ -0,0 +1,195 @@
+/*
+ * h/w branch tracer for x86 based on bts
+ *
+ * Copyright (C) 2008 Markus Metzger <markus.t.metzger@gmail.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/ftrace.h>
+#include <linux/kallsyms.h>
+
+#include <asm/ds.h>
+
+#include "trace.h"
+
+
+#define SIZEOF_BTS (1 << 13)
+
+static DEFINE_PER_CPU(struct bts_tracer *, tracer);
+static DEFINE_PER_CPU(unsigned char[SIZEOF_BTS], buffer);
+
+#define this_tracer per_cpu(tracer, smp_processor_id())
+#define this_buffer per_cpu(buffer, smp_processor_id())
+
+
+static void bts_trace_start_cpu(void *arg)
+{
+	if (this_tracer)
+		ds_release_bts(this_tracer);
+
+	this_tracer =
+		ds_request_bts(/* task = */ NULL, this_buffer, SIZEOF_BTS,
+			       /* ovfl = */ NULL, /* th = */ (size_t)-1,
+			       BTS_KERNEL);
+	if (IS_ERR(this_tracer)) {
+		this_tracer = NULL;
+		return;
+	}
+}
+
+static void bts_trace_start(struct trace_array *tr)
+{
+	int cpu;
+
+	tracing_reset_online_cpus(tr);
+
+	for_each_cpu_mask(cpu, cpu_possible_map)
+		smp_call_function_single(cpu, bts_trace_start_cpu, NULL, 1);
+}
+
+static void bts_trace_stop_cpu(void *arg)
+{
+	if (this_tracer) {
+		ds_release_bts(this_tracer);
+		this_tracer = NULL;
+	}
+}
+
+static void bts_trace_stop(struct trace_array *tr)
+{
+	int cpu;
+
+	for_each_cpu_mask(cpu, cpu_possible_map)
+		smp_call_function_single(cpu, bts_trace_stop_cpu, NULL, 1);
+}
+
+static int bts_trace_init(struct trace_array *tr)
+{
+	tracing_reset_online_cpus(tr);
+	bts_trace_start(tr);
+
+	return 0;
+}
+
+static void bts_trace_print_header(struct seq_file *m)
+{
+	seq_puts(m,
+		 "# CPU#        FROM                   TO         FUNCTION\n");
+	seq_puts(m,
+		 "#  |           |                     |             |\n");
+}
+
+static enum print_line_t bts_trace_print_line(struct trace_iterator *iter)
+{
+	struct trace_entry *entry = iter->ent;
+	struct trace_seq *seq = &iter->seq;
+	struct hw_branch_entry *it;
+
+	trace_assign_type(it, entry);
+
+	if (entry->type == TRACE_HW_BRANCHES) {
+		if (trace_seq_printf(seq, "%4d  ", entry->cpu) &&
+		    trace_seq_printf(seq, "0x%016llx -> 0x%016llx ",
+				     it->from, it->to) &&
+		    (!it->from ||
+		     seq_print_ip_sym(seq, it->from, /* sym_flags = */ 0)) &&
+		    trace_seq_printf(seq, "\n"))
+			return TRACE_TYPE_HANDLED;
+		return TRACE_TYPE_PARTIAL_LINE;;
+	}
+	return TRACE_TYPE_UNHANDLED;
+}
+
+void trace_hw_branch(struct trace_array *tr, u64 from, u64 to)
+{
+	struct ring_buffer_event *event;
+	struct hw_branch_entry *entry;
+	unsigned long irq;
+
+	event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), &irq);
+	if (!event)
+		return;
+	entry	= ring_buffer_event_data(event);
+	tracing_generic_entry_update(&entry->ent, 0, from);
+	entry->ent.type = TRACE_HW_BRANCHES;
+	entry->ent.cpu = smp_processor_id();
+	entry->from = from;
+	entry->to   = to;
+	ring_buffer_unlock_commit(tr->buffer, event, irq);
+}
+
+static void trace_bts_at(struct trace_array *tr,
+			 const struct bts_trace *trace, void *at)
+{
+	struct bts_struct bts;
+	int err = 0;
+
+	WARN_ON_ONCE(!trace->read);
+	if (!trace->read)
+		return;
+
+	err = trace->read(this_tracer, at, &bts);
+	if (err < 0)
+		return;
+
+	switch (bts.qualifier) {
+	case BTS_BRANCH:
+		trace_hw_branch(tr, bts.variant.lbr.from, bts.variant.lbr.to);
+		break;
+	}
+}
+
+static void trace_bts_cpu(void *arg)
+{
+	struct trace_array *tr = (struct trace_array *) arg;
+	const struct bts_trace *trace;
+	unsigned char *at;
+
+	if (!this_tracer)
+		return;
+
+	ds_suspend_bts(this_tracer);
+	trace = ds_read_bts(this_tracer);
+	if (!trace)
+		goto out;
+
+	for (at = trace->ds.top; (void *)at < trace->ds.end;
+	     at += trace->ds.size)
+		trace_bts_at(tr, trace, at);
+
+	for (at = trace->ds.begin; (void *)at < trace->ds.top;
+	     at += trace->ds.size)
+		trace_bts_at(tr, trace, at);
+
+out:
+	ds_resume_bts(this_tracer);
+}
+
+static void trace_bts_prepare(struct trace_iterator *iter)
+{
+	int cpu;
+
+	for_each_cpu_mask(cpu, cpu_possible_map)
+		smp_call_function_single(cpu, trace_bts_cpu, iter->tr, 1);
+}
+
+struct tracer bts_tracer __read_mostly =
+{
+	.name		= "hw-branch-tracer",
+	.init		= bts_trace_init,
+	.reset		= bts_trace_stop,
+	.print_header	= bts_trace_print_header,
+	.print_line	= bts_trace_print_line,
+	.start		= bts_trace_start,
+	.stop		= bts_trace_stop,
+	.open		= trace_bts_prepare
+};
+
+__init static int init_bts_trace(void)
+{
+	return register_tracer(&bts_tracer);
+}
+device_initcall(init_bts_trace);
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 9c74071..7c2e326 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -353,15 +353,28 @@
 }
 #endif /* CONFIG_PREEMPT_TRACER */
 
+/*
+ * save_tracer_enabled is used to save the state of the tracer_enabled
+ * variable when we disable it when we open a trace output file.
+ */
+static int save_tracer_enabled;
+
 static void start_irqsoff_tracer(struct trace_array *tr)
 {
 	register_ftrace_function(&trace_ops);
-	tracer_enabled = 1;
+	if (tracing_is_enabled()) {
+		tracer_enabled = 1;
+		save_tracer_enabled = 1;
+	} else {
+		tracer_enabled = 0;
+		save_tracer_enabled = 0;
+	}
 }
 
 static void stop_irqsoff_tracer(struct trace_array *tr)
 {
 	tracer_enabled = 0;
+	save_tracer_enabled = 0;
 	unregister_ftrace_function(&trace_ops);
 }
 
@@ -370,53 +383,55 @@
 	irqsoff_trace = tr;
 	/* make sure that the tracer is visible */
 	smp_wmb();
-
-	if (tr->ctrl)
-		start_irqsoff_tracer(tr);
+	start_irqsoff_tracer(tr);
 }
 
 static void irqsoff_tracer_reset(struct trace_array *tr)
 {
-	if (tr->ctrl)
-		stop_irqsoff_tracer(tr);
+	stop_irqsoff_tracer(tr);
 }
 
-static void irqsoff_tracer_ctrl_update(struct trace_array *tr)
+static void irqsoff_tracer_start(struct trace_array *tr)
 {
-	if (tr->ctrl)
-		start_irqsoff_tracer(tr);
-	else
-		stop_irqsoff_tracer(tr);
+	tracer_enabled = 1;
+	save_tracer_enabled = 1;
+}
+
+static void irqsoff_tracer_stop(struct trace_array *tr)
+{
+	tracer_enabled = 0;
+	save_tracer_enabled = 0;
 }
 
 static void irqsoff_tracer_open(struct trace_iterator *iter)
 {
 	/* stop the trace while dumping */
-	if (iter->tr->ctrl)
-		stop_irqsoff_tracer(iter->tr);
+	tracer_enabled = 0;
 }
 
 static void irqsoff_tracer_close(struct trace_iterator *iter)
 {
-	if (iter->tr->ctrl)
-		start_irqsoff_tracer(iter->tr);
+	/* restart tracing */
+	tracer_enabled = save_tracer_enabled;
 }
 
 #ifdef CONFIG_IRQSOFF_TRACER
-static void irqsoff_tracer_init(struct trace_array *tr)
+static int irqsoff_tracer_init(struct trace_array *tr)
 {
 	trace_type = TRACER_IRQS_OFF;
 
 	__irqsoff_tracer_init(tr);
+	return 0;
 }
 static struct tracer irqsoff_tracer __read_mostly =
 {
 	.name		= "irqsoff",
 	.init		= irqsoff_tracer_init,
 	.reset		= irqsoff_tracer_reset,
+	.start		= irqsoff_tracer_start,
+	.stop		= irqsoff_tracer_stop,
 	.open		= irqsoff_tracer_open,
 	.close		= irqsoff_tracer_close,
-	.ctrl_update	= irqsoff_tracer_ctrl_update,
 	.print_max	= 1,
 #ifdef CONFIG_FTRACE_SELFTEST
 	.selftest    = trace_selftest_startup_irqsoff,
@@ -428,11 +443,12 @@
 #endif
 
 #ifdef CONFIG_PREEMPT_TRACER
-static void preemptoff_tracer_init(struct trace_array *tr)
+static int preemptoff_tracer_init(struct trace_array *tr)
 {
 	trace_type = TRACER_PREEMPT_OFF;
 
 	__irqsoff_tracer_init(tr);
+	return 0;
 }
 
 static struct tracer preemptoff_tracer __read_mostly =
@@ -440,9 +456,10 @@
 	.name		= "preemptoff",
 	.init		= preemptoff_tracer_init,
 	.reset		= irqsoff_tracer_reset,
+	.start		= irqsoff_tracer_start,
+	.stop		= irqsoff_tracer_stop,
 	.open		= irqsoff_tracer_open,
 	.close		= irqsoff_tracer_close,
-	.ctrl_update	= irqsoff_tracer_ctrl_update,
 	.print_max	= 1,
 #ifdef CONFIG_FTRACE_SELFTEST
 	.selftest    = trace_selftest_startup_preemptoff,
@@ -456,11 +473,12 @@
 #if defined(CONFIG_IRQSOFF_TRACER) && \
 	defined(CONFIG_PREEMPT_TRACER)
 
-static void preemptirqsoff_tracer_init(struct trace_array *tr)
+static int preemptirqsoff_tracer_init(struct trace_array *tr)
 {
 	trace_type = TRACER_IRQS_OFF | TRACER_PREEMPT_OFF;
 
 	__irqsoff_tracer_init(tr);
+	return 0;
 }
 
 static struct tracer preemptirqsoff_tracer __read_mostly =
@@ -468,9 +486,10 @@
 	.name		= "preemptirqsoff",
 	.init		= preemptirqsoff_tracer_init,
 	.reset		= irqsoff_tracer_reset,
+	.start		= irqsoff_tracer_start,
+	.stop		= irqsoff_tracer_stop,
 	.open		= irqsoff_tracer_open,
 	.close		= irqsoff_tracer_close,
-	.ctrl_update	= irqsoff_tracer_ctrl_update,
 	.print_max	= 1,
 #ifdef CONFIG_FTRACE_SELFTEST
 	.selftest    = trace_selftest_startup_preemptirqsoff,
diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c
index e62cbf7..fffcb06 100644
--- a/kernel/trace/trace_mmiotrace.c
+++ b/kernel/trace/trace_mmiotrace.c
@@ -22,44 +22,35 @@
 
 static void mmio_reset_data(struct trace_array *tr)
 {
-	int cpu;
-
 	overrun_detected = false;
 	prev_overruns = 0;
-	tr->time_start = ftrace_now(tr->cpu);
 
-	for_each_online_cpu(cpu)
-		tracing_reset(tr, cpu);
+	tracing_reset_online_cpus(tr);
 }
 
-static void mmio_trace_init(struct trace_array *tr)
+static int mmio_trace_init(struct trace_array *tr)
 {
 	pr_debug("in %s\n", __func__);
 	mmio_trace_array = tr;
-	if (tr->ctrl) {
-		mmio_reset_data(tr);
-		enable_mmiotrace();
-	}
+
+	mmio_reset_data(tr);
+	enable_mmiotrace();
+	return 0;
 }
 
 static void mmio_trace_reset(struct trace_array *tr)
 {
 	pr_debug("in %s\n", __func__);
-	if (tr->ctrl)
-		disable_mmiotrace();
+
+	disable_mmiotrace();
 	mmio_reset_data(tr);
 	mmio_trace_array = NULL;
 }
 
-static void mmio_trace_ctrl_update(struct trace_array *tr)
+static void mmio_trace_start(struct trace_array *tr)
 {
 	pr_debug("in %s\n", __func__);
-	if (tr->ctrl) {
-		mmio_reset_data(tr);
-		enable_mmiotrace();
-	} else {
-		disable_mmiotrace();
-	}
+	mmio_reset_data(tr);
 }
 
 static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev)
@@ -296,10 +287,10 @@
 	.name		= "mmiotrace",
 	.init		= mmio_trace_init,
 	.reset		= mmio_trace_reset,
+	.start		= mmio_trace_start,
 	.pipe_open	= mmio_pipe_open,
 	.close		= mmio_close,
 	.read		= mmio_read,
-	.ctrl_update	= mmio_trace_ctrl_update,
 	.print_line	= mmio_print_line,
 };
 
@@ -371,5 +362,5 @@
 
 int mmio_trace_printk(const char *fmt, va_list args)
 {
-	return trace_vprintk(0, fmt, args);
+	return trace_vprintk(0, -1, fmt, args);
 }
diff --git a/kernel/trace/trace_nop.c b/kernel/trace/trace_nop.c
index 4592b48..b9767ac 100644
--- a/kernel/trace/trace_nop.c
+++ b/kernel/trace/trace_nop.c
@@ -12,6 +12,27 @@
 
 #include "trace.h"
 
+/* Our two options */
+enum {
+	TRACE_NOP_OPT_ACCEPT = 0x1,
+	TRACE_NOP_OPT_REFUSE = 0x2
+};
+
+/* Options for the tracer (see trace_options file) */
+static struct tracer_opt nop_opts[] = {
+	/* Option that will be accepted by set_flag callback */
+	{ TRACER_OPT(test_nop_accept, TRACE_NOP_OPT_ACCEPT) },
+	/* Option that will be refused by set_flag callback */
+	{ TRACER_OPT(test_nop_refuse, TRACE_NOP_OPT_REFUSE) },
+	{ } /* Always set a last empty entry */
+};
+
+static struct tracer_flags nop_flags = {
+	/* You can check your flags value here when you want. */
+	.val = 0, /* By default: all flags disabled */
+	.opts = nop_opts
+};
+
 static struct trace_array	*ctx_trace;
 
 static void start_nop_trace(struct trace_array *tr)
@@ -24,7 +45,7 @@
 	/* Nothing to do! */
 }
 
-static void nop_trace_init(struct trace_array *tr)
+static int nop_trace_init(struct trace_array *tr)
 {
 	int cpu;
 	ctx_trace = tr;
@@ -32,33 +53,53 @@
 	for_each_online_cpu(cpu)
 		tracing_reset(tr, cpu);
 
-	if (tr->ctrl)
-		start_nop_trace(tr);
+	start_nop_trace(tr);
+	return 0;
 }
 
 static void nop_trace_reset(struct trace_array *tr)
 {
-	if (tr->ctrl)
-		stop_nop_trace(tr);
+	stop_nop_trace(tr);
 }
 
-static void nop_trace_ctrl_update(struct trace_array *tr)
+/* It only serves as a signal handler and a callback to
+ * accept or refuse tthe setting of a flag.
+ * If you don't implement it, then the flag setting will be
+ * automatically accepted.
+ */
+static int nop_set_flag(u32 old_flags, u32 bit, int set)
 {
-	/* When starting a new trace, reset the buffers */
-	if (tr->ctrl)
-		start_nop_trace(tr);
-	else
-		stop_nop_trace(tr);
+	/*
+	 * Note that you don't need to update nop_flags.val yourself.
+	 * The tracing Api will do it automatically if you return 0
+	 */
+	if (bit == TRACE_NOP_OPT_ACCEPT) {
+		printk(KERN_DEBUG "nop_test_accept flag set to %d: we accept."
+			" Now cat trace_options to see the result\n",
+			set);
+		return 0;
+	}
+
+	if (bit == TRACE_NOP_OPT_REFUSE) {
+		printk(KERN_DEBUG "nop_test_refuse flag set to %d: we refuse."
+			"Now cat trace_options to see the result\n",
+			set);
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
+
 struct tracer nop_trace __read_mostly =
 {
 	.name		= "nop",
 	.init		= nop_trace_init,
 	.reset		= nop_trace_reset,
-	.ctrl_update	= nop_trace_ctrl_update,
 #ifdef CONFIG_FTRACE_SELFTEST
 	.selftest	= trace_selftest_startup_nop,
 #endif
+	.flags		= &nop_flags,
+	.set_flag	= nop_set_flag
 };
 
diff --git a/kernel/trace/trace_power.c b/kernel/trace/trace_power.c
new file mode 100644
index 0000000..a7172a3
--- /dev/null
+++ b/kernel/trace/trace_power.c
@@ -0,0 +1,179 @@
+/*
+ * ring buffer based C-state tracer
+ *
+ * Arjan van de Ven <arjan@linux.intel.com>
+ * Copyright (C) 2008 Intel Corporation
+ *
+ * Much is borrowed from trace_boot.c which is
+ * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/ftrace.h>
+#include <linux/kallsyms.h>
+#include <linux/module.h>
+
+#include "trace.h"
+
+static struct trace_array *power_trace;
+static int __read_mostly trace_power_enabled;
+
+
+static void start_power_trace(struct trace_array *tr)
+{
+	trace_power_enabled = 1;
+}
+
+static void stop_power_trace(struct trace_array *tr)
+{
+	trace_power_enabled = 0;
+}
+
+
+static int power_trace_init(struct trace_array *tr)
+{
+	int cpu;
+	power_trace = tr;
+
+	trace_power_enabled = 1;
+
+	for_each_cpu_mask(cpu, cpu_possible_map)
+		tracing_reset(tr, cpu);
+	return 0;
+}
+
+static enum print_line_t power_print_line(struct trace_iterator *iter)
+{
+	int ret = 0;
+	struct trace_entry *entry = iter->ent;
+	struct trace_power *field ;
+	struct power_trace *it;
+	struct trace_seq *s = &iter->seq;
+	struct timespec stamp;
+	struct timespec duration;
+
+	trace_assign_type(field, entry);
+	it = &field->state_data;
+	stamp = ktime_to_timespec(it->stamp);
+	duration = ktime_to_timespec(ktime_sub(it->end, it->stamp));
+
+	if (entry->type == TRACE_POWER) {
+		if (it->type == POWER_CSTATE)
+			ret = trace_seq_printf(s, "[%5ld.%09ld] CSTATE: Going to C%i on cpu %i for %ld.%09ld\n",
+					  stamp.tv_sec,
+					  stamp.tv_nsec,
+					  it->state, iter->cpu,
+					  duration.tv_sec,
+					  duration.tv_nsec);
+		if (it->type == POWER_PSTATE)
+			ret = trace_seq_printf(s, "[%5ld.%09ld] PSTATE: Going to P%i on cpu %i\n",
+					  stamp.tv_sec,
+					  stamp.tv_nsec,
+					  it->state, iter->cpu);
+		if (!ret)
+			return TRACE_TYPE_PARTIAL_LINE;
+		return TRACE_TYPE_HANDLED;
+	}
+	return TRACE_TYPE_UNHANDLED;
+}
+
+static struct tracer power_tracer __read_mostly =
+{
+	.name		= "power",
+	.init		= power_trace_init,
+	.start		= start_power_trace,
+	.stop		= stop_power_trace,
+	.reset		= stop_power_trace,
+	.print_line	= power_print_line,
+};
+
+static int init_power_trace(void)
+{
+	return register_tracer(&power_tracer);
+}
+device_initcall(init_power_trace);
+
+void trace_power_start(struct power_trace *it, unsigned int type,
+			 unsigned int level)
+{
+	if (!trace_power_enabled)
+		return;
+
+	memset(it, 0, sizeof(struct power_trace));
+	it->state = level;
+	it->type = type;
+	it->stamp = ktime_get();
+}
+EXPORT_SYMBOL_GPL(trace_power_start);
+
+
+void trace_power_end(struct power_trace *it)
+{
+	struct ring_buffer_event *event;
+	struct trace_power *entry;
+	struct trace_array_cpu *data;
+	unsigned long irq_flags;
+	struct trace_array *tr = power_trace;
+
+	if (!trace_power_enabled)
+		return;
+
+	preempt_disable();
+	it->end = ktime_get();
+	data = tr->data[smp_processor_id()];
+
+	event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
+					 &irq_flags);
+	if (!event)
+		goto out;
+	entry	= ring_buffer_event_data(event);
+	tracing_generic_entry_update(&entry->ent, 0, 0);
+	entry->ent.type = TRACE_POWER;
+	entry->state_data = *it;
+	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
+
+	trace_wake_up();
+
+ out:
+	preempt_enable();
+}
+EXPORT_SYMBOL_GPL(trace_power_end);
+
+void trace_power_mark(struct power_trace *it, unsigned int type,
+			 unsigned int level)
+{
+	struct ring_buffer_event *event;
+	struct trace_power *entry;
+	struct trace_array_cpu *data;
+	unsigned long irq_flags;
+	struct trace_array *tr = power_trace;
+
+	if (!trace_power_enabled)
+		return;
+
+	memset(it, 0, sizeof(struct power_trace));
+	it->state = level;
+	it->type = type;
+	it->stamp = ktime_get();
+	preempt_disable();
+	it->end = it->stamp;
+	data = tr->data[smp_processor_id()];
+
+	event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
+					 &irq_flags);
+	if (!event)
+		goto out;
+	entry	= ring_buffer_event_data(event);
+	tracing_generic_entry_update(&entry->ent, 0, 0);
+	entry->ent.type = TRACE_POWER;
+	entry->state_data = *it;
+	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
+
+	trace_wake_up();
+
+ out:
+	preempt_enable();
+}
+EXPORT_SYMBOL_GPL(trace_power_mark);
diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c
index b8f56be..df175cb 100644
--- a/kernel/trace/trace_sched_switch.c
+++ b/kernel/trace/trace_sched_switch.c
@@ -16,7 +16,8 @@
 
 static struct trace_array	*ctx_trace;
 static int __read_mostly	tracer_enabled;
-static atomic_t			sched_ref;
+static int			sched_ref;
+static DEFINE_MUTEX(sched_register_mutex);
 
 static void
 probe_sched_switch(struct rq *__rq, struct task_struct *prev,
@@ -27,7 +28,7 @@
 	int cpu;
 	int pc;
 
-	if (!atomic_read(&sched_ref))
+	if (!sched_ref)
 		return;
 
 	tracing_record_cmdline(prev);
@@ -48,7 +49,7 @@
 }
 
 static void
-probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee)
+probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee, int success)
 {
 	struct trace_array_cpu *data;
 	unsigned long flags;
@@ -71,16 +72,6 @@
 	local_irq_restore(flags);
 }
 
-static void sched_switch_reset(struct trace_array *tr)
-{
-	int cpu;
-
-	tr->time_start = ftrace_now(tr->cpu);
-
-	for_each_online_cpu(cpu)
-		tracing_reset(tr, cpu);
-}
-
 static int tracing_sched_register(void)
 {
 	int ret;
@@ -123,20 +114,18 @@
 
 static void tracing_start_sched_switch(void)
 {
-	long ref;
-
-	ref = atomic_inc_return(&sched_ref);
-	if (ref == 1)
+	mutex_lock(&sched_register_mutex);
+	if (!(sched_ref++))
 		tracing_sched_register();
+	mutex_unlock(&sched_register_mutex);
 }
 
 static void tracing_stop_sched_switch(void)
 {
-	long ref;
-
-	ref = atomic_dec_and_test(&sched_ref);
-	if (ref)
+	mutex_lock(&sched_register_mutex);
+	if (!(--sched_ref))
 		tracing_sched_unregister();
+	mutex_unlock(&sched_register_mutex);
 }
 
 void tracing_start_cmdline_record(void)
@@ -149,40 +138,86 @@
 	tracing_stop_sched_switch();
 }
 
+/**
+ * tracing_start_sched_switch_record - start tracing context switches
+ *
+ * Turns on context switch tracing for a tracer.
+ */
+void tracing_start_sched_switch_record(void)
+{
+	if (unlikely(!ctx_trace)) {
+		WARN_ON(1);
+		return;
+	}
+
+	tracing_start_sched_switch();
+
+	mutex_lock(&sched_register_mutex);
+	tracer_enabled++;
+	mutex_unlock(&sched_register_mutex);
+}
+
+/**
+ * tracing_stop_sched_switch_record - start tracing context switches
+ *
+ * Turns off context switch tracing for a tracer.
+ */
+void tracing_stop_sched_switch_record(void)
+{
+	mutex_lock(&sched_register_mutex);
+	tracer_enabled--;
+	WARN_ON(tracer_enabled < 0);
+	mutex_unlock(&sched_register_mutex);
+
+	tracing_stop_sched_switch();
+}
+
+/**
+ * tracing_sched_switch_assign_trace - assign a trace array for ctx switch
+ * @tr: trace array pointer to assign
+ *
+ * Some tracers might want to record the context switches in their
+ * trace. This function lets those tracers assign the trace array
+ * to use.
+ */
+void tracing_sched_switch_assign_trace(struct trace_array *tr)
+{
+	ctx_trace = tr;
+}
+
 static void start_sched_trace(struct trace_array *tr)
 {
-	sched_switch_reset(tr);
-	tracing_start_cmdline_record();
-	tracer_enabled = 1;
+	tracing_reset_online_cpus(tr);
+	tracing_start_sched_switch_record();
 }
 
 static void stop_sched_trace(struct trace_array *tr)
 {
-	tracer_enabled = 0;
-	tracing_stop_cmdline_record();
+	tracing_stop_sched_switch_record();
 }
 
-static void sched_switch_trace_init(struct trace_array *tr)
+static int sched_switch_trace_init(struct trace_array *tr)
 {
 	ctx_trace = tr;
-
-	if (tr->ctrl)
-		start_sched_trace(tr);
+	start_sched_trace(tr);
+	return 0;
 }
 
 static void sched_switch_trace_reset(struct trace_array *tr)
 {
-	if (tr->ctrl)
+	if (sched_ref)
 		stop_sched_trace(tr);
 }
 
-static void sched_switch_trace_ctrl_update(struct trace_array *tr)
+static void sched_switch_trace_start(struct trace_array *tr)
 {
-	/* When starting a new trace, reset the buffers */
-	if (tr->ctrl)
-		start_sched_trace(tr);
-	else
-		stop_sched_trace(tr);
+	tracing_reset_online_cpus(tr);
+	tracing_start_sched_switch();
+}
+
+static void sched_switch_trace_stop(struct trace_array *tr)
+{
+	tracing_stop_sched_switch();
 }
 
 static struct tracer sched_switch_trace __read_mostly =
@@ -190,7 +225,8 @@
 	.name		= "sched_switch",
 	.init		= sched_switch_trace_init,
 	.reset		= sched_switch_trace_reset,
-	.ctrl_update	= sched_switch_trace_ctrl_update,
+	.start		= sched_switch_trace_start,
+	.stop		= sched_switch_trace_stop,
 #ifdef CONFIG_FTRACE_SELFTEST
 	.selftest    = trace_selftest_startup_sched_switch,
 #endif
@@ -198,14 +234,7 @@
 
 __init static int init_sched_switch_trace(void)
 {
-	int ret = 0;
-
-	if (atomic_read(&sched_ref))
-		ret = tracing_sched_register();
-	if (ret) {
-		pr_info("error registering scheduler trace\n");
-		return ret;
-	}
 	return register_tracer(&sched_switch_trace);
 }
 device_initcall(init_sched_switch_trace);
+
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
index 3ae93f1..43586b6 100644
--- a/kernel/trace/trace_sched_wakeup.c
+++ b/kernel/trace/trace_sched_wakeup.c
@@ -50,8 +50,7 @@
 		return;
 
 	pc = preempt_count();
-	resched = need_resched();
-	preempt_disable_notrace();
+	resched = ftrace_preempt_disable();
 
 	cpu = raw_smp_processor_id();
 	data = tr->data[cpu];
@@ -81,15 +80,7 @@
  out:
 	atomic_dec(&data->disabled);
 
-	/*
-	 * To prevent recursion from the scheduler, if the
-	 * resched flag was set before we entered, then
-	 * don't reschedule.
-	 */
-	if (resched)
-		preempt_enable_no_resched_notrace();
-	else
-		preempt_enable_notrace();
+	ftrace_preempt_enable(resched);
 }
 
 static struct ftrace_ops trace_ops __read_mostly =
@@ -220,7 +211,7 @@
 }
 
 static void
-probe_wakeup(struct rq *rq, struct task_struct *p)
+probe_wakeup(struct rq *rq, struct task_struct *p, int success)
 {
 	int cpu = smp_processor_id();
 	unsigned long flags;
@@ -271,6 +262,12 @@
 	atomic_dec(&wakeup_trace->data[cpu]->disabled);
 }
 
+/*
+ * save_tracer_enabled is used to save the state of the tracer_enabled
+ * variable when we disable it when we open a trace output file.
+ */
+static int save_tracer_enabled;
+
 static void start_wakeup_tracer(struct trace_array *tr)
 {
 	int ret;
@@ -309,7 +306,13 @@
 
 	register_ftrace_function(&trace_ops);
 
-	tracer_enabled = 1;
+	if (tracing_is_enabled()) {
+		tracer_enabled = 1;
+		save_tracer_enabled = 1;
+	} else {
+		tracer_enabled = 0;
+		save_tracer_enabled = 0;
+	}
 
 	return;
 fail_deprobe_wake_new:
@@ -321,49 +324,53 @@
 static void stop_wakeup_tracer(struct trace_array *tr)
 {
 	tracer_enabled = 0;
+	save_tracer_enabled = 0;
 	unregister_ftrace_function(&trace_ops);
 	unregister_trace_sched_switch(probe_wakeup_sched_switch);
 	unregister_trace_sched_wakeup_new(probe_wakeup);
 	unregister_trace_sched_wakeup(probe_wakeup);
 }
 
-static void wakeup_tracer_init(struct trace_array *tr)
+static int wakeup_tracer_init(struct trace_array *tr)
 {
 	wakeup_trace = tr;
-
-	if (tr->ctrl)
-		start_wakeup_tracer(tr);
+	start_wakeup_tracer(tr);
+	return 0;
 }
 
 static void wakeup_tracer_reset(struct trace_array *tr)
 {
-	if (tr->ctrl) {
-		stop_wakeup_tracer(tr);
-		/* make sure we put back any tasks we are tracing */
-		wakeup_reset(tr);
-	}
+	stop_wakeup_tracer(tr);
+	/* make sure we put back any tasks we are tracing */
+	wakeup_reset(tr);
 }
 
-static void wakeup_tracer_ctrl_update(struct trace_array *tr)
+static void wakeup_tracer_start(struct trace_array *tr)
 {
-	if (tr->ctrl)
-		start_wakeup_tracer(tr);
-	else
-		stop_wakeup_tracer(tr);
+	wakeup_reset(tr);
+	tracer_enabled = 1;
+	save_tracer_enabled = 1;
+}
+
+static void wakeup_tracer_stop(struct trace_array *tr)
+{
+	tracer_enabled = 0;
+	save_tracer_enabled = 0;
 }
 
 static void wakeup_tracer_open(struct trace_iterator *iter)
 {
 	/* stop the trace while dumping */
-	if (iter->tr->ctrl)
-		stop_wakeup_tracer(iter->tr);
+	tracer_enabled = 0;
 }
 
 static void wakeup_tracer_close(struct trace_iterator *iter)
 {
 	/* forget about any processes we were recording */
-	if (iter->tr->ctrl)
-		start_wakeup_tracer(iter->tr);
+	if (save_tracer_enabled) {
+		wakeup_reset(iter->tr);
+		tracer_enabled = 1;
+	}
 }
 
 static struct tracer wakeup_tracer __read_mostly =
@@ -371,9 +378,10 @@
 	.name		= "wakeup",
 	.init		= wakeup_tracer_init,
 	.reset		= wakeup_tracer_reset,
+	.start		= wakeup_tracer_start,
+	.stop		= wakeup_tracer_stop,
 	.open		= wakeup_tracer_open,
 	.close		= wakeup_tracer_close,
-	.ctrl_update	= wakeup_tracer_ctrl_update,
 	.print_max	= 1,
 #ifdef CONFIG_FTRACE_SELFTEST
 	.selftest    = trace_selftest_startup_wakeup,
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c
index 90bc752..88c8eb7 100644
--- a/kernel/trace/trace_selftest.c
+++ b/kernel/trace/trace_selftest.c
@@ -13,6 +13,7 @@
 	case TRACE_STACK:
 	case TRACE_PRINT:
 	case TRACE_SPECIAL:
+	case TRACE_BRANCH:
 		return 1;
 	}
 	return 0;
@@ -51,7 +52,7 @@
 	int cpu, ret = 0;
 
 	/* Don't allow flipping of max traces now */
-	raw_local_irq_save(flags);
+	local_irq_save(flags);
 	__raw_spin_lock(&ftrace_max_lock);
 
 	cnt = ring_buffer_entries(tr->buffer);
@@ -62,7 +63,7 @@
 			break;
 	}
 	__raw_spin_unlock(&ftrace_max_lock);
-	raw_local_irq_restore(flags);
+	local_irq_restore(flags);
 
 	if (count)
 		*count = cnt;
@@ -70,6 +71,11 @@
 	return ret;
 }
 
+static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret)
+{
+	printk(KERN_WARNING "Failed to init %s tracer, init returned %d\n",
+		trace->name, init_ret);
+}
 #ifdef CONFIG_FUNCTION_TRACER
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -110,8 +116,11 @@
 	ftrace_set_filter(func_name, strlen(func_name), 1);
 
 	/* enable tracing */
-	tr->ctrl = 1;
-	trace->init(tr);
+	ret = trace->init(tr);
+	if (ret) {
+		warn_failed_init_tracer(trace, ret);
+		goto out;
+	}
 
 	/* Sleep for a 1/10 of a second */
 	msleep(100);
@@ -134,13 +143,13 @@
 	msleep(100);
 
 	/* stop the tracing. */
-	tr->ctrl = 0;
-	trace->ctrl_update(tr);
+	tracing_stop();
 	ftrace_enabled = 0;
 
 	/* check the trace buffer */
 	ret = trace_test_buffer(tr, &count);
 	trace->reset(tr);
+	tracing_start();
 
 	/* we should only have one item */
 	if (!ret && count != 1) {
@@ -148,6 +157,7 @@
 		ret = -1;
 		goto out;
 	}
+
  out:
 	ftrace_enabled = save_ftrace_enabled;
 	tracer_enabled = save_tracer_enabled;
@@ -180,18 +190,22 @@
 	ftrace_enabled = 1;
 	tracer_enabled = 1;
 
-	tr->ctrl = 1;
-	trace->init(tr);
+	ret = trace->init(tr);
+	if (ret) {
+		warn_failed_init_tracer(trace, ret);
+		goto out;
+	}
+
 	/* Sleep for a 1/10 of a second */
 	msleep(100);
 	/* stop the tracing. */
-	tr->ctrl = 0;
-	trace->ctrl_update(tr);
+	tracing_stop();
 	ftrace_enabled = 0;
 
 	/* check the trace buffer */
 	ret = trace_test_buffer(tr, &count);
 	trace->reset(tr);
+	tracing_start();
 
 	if (!ret && !count) {
 		printk(KERN_CONT ".. no entries found ..");
@@ -223,8 +237,12 @@
 	int ret;
 
 	/* start the tracing */
-	tr->ctrl = 1;
-	trace->init(tr);
+	ret = trace->init(tr);
+	if (ret) {
+		warn_failed_init_tracer(trace, ret);
+		return ret;
+	}
+
 	/* reset the max latency */
 	tracing_max_latency = 0;
 	/* disable interrupts for a bit */
@@ -232,13 +250,13 @@
 	udelay(100);
 	local_irq_enable();
 	/* stop the tracing. */
-	tr->ctrl = 0;
-	trace->ctrl_update(tr);
+	tracing_stop();
 	/* check both trace buffers */
 	ret = trace_test_buffer(tr, NULL);
 	if (!ret)
 		ret = trace_test_buffer(&max_tr, &count);
 	trace->reset(tr);
+	tracing_start();
 
 	if (!ret && !count) {
 		printk(KERN_CONT ".. no entries found ..");
@@ -259,9 +277,26 @@
 	unsigned long count;
 	int ret;
 
+	/*
+	 * Now that the big kernel lock is no longer preemptable,
+	 * and this is called with the BKL held, it will always
+	 * fail. If preemption is already disabled, simply
+	 * pass the test. When the BKL is removed, or becomes
+	 * preemptible again, we will once again test this,
+	 * so keep it in.
+	 */
+	if (preempt_count()) {
+		printk(KERN_CONT "can not test ... force ");
+		return 0;
+	}
+
 	/* start the tracing */
-	tr->ctrl = 1;
-	trace->init(tr);
+	ret = trace->init(tr);
+	if (ret) {
+		warn_failed_init_tracer(trace, ret);
+		return ret;
+	}
+
 	/* reset the max latency */
 	tracing_max_latency = 0;
 	/* disable preemption for a bit */
@@ -269,13 +304,13 @@
 	udelay(100);
 	preempt_enable();
 	/* stop the tracing. */
-	tr->ctrl = 0;
-	trace->ctrl_update(tr);
+	tracing_stop();
 	/* check both trace buffers */
 	ret = trace_test_buffer(tr, NULL);
 	if (!ret)
 		ret = trace_test_buffer(&max_tr, &count);
 	trace->reset(tr);
+	tracing_start();
 
 	if (!ret && !count) {
 		printk(KERN_CONT ".. no entries found ..");
@@ -296,9 +331,25 @@
 	unsigned long count;
 	int ret;
 
+	/*
+	 * Now that the big kernel lock is no longer preemptable,
+	 * and this is called with the BKL held, it will always
+	 * fail. If preemption is already disabled, simply
+	 * pass the test. When the BKL is removed, or becomes
+	 * preemptible again, we will once again test this,
+	 * so keep it in.
+	 */
+	if (preempt_count()) {
+		printk(KERN_CONT "can not test ... force ");
+		return 0;
+	}
+
 	/* start the tracing */
-	tr->ctrl = 1;
-	trace->init(tr);
+	ret = trace->init(tr);
+	if (ret) {
+		warn_failed_init_tracer(trace, ret);
+		goto out;
+	}
 
 	/* reset the max latency */
 	tracing_max_latency = 0;
@@ -312,27 +363,30 @@
 	local_irq_enable();
 
 	/* stop the tracing. */
-	tr->ctrl = 0;
-	trace->ctrl_update(tr);
+	tracing_stop();
 	/* check both trace buffers */
 	ret = trace_test_buffer(tr, NULL);
-	if (ret)
+	if (ret) {
+		tracing_start();
 		goto out;
+	}
 
 	ret = trace_test_buffer(&max_tr, &count);
-	if (ret)
+	if (ret) {
+		tracing_start();
 		goto out;
+	}
 
 	if (!ret && !count) {
 		printk(KERN_CONT ".. no entries found ..");
 		ret = -1;
+		tracing_start();
 		goto out;
 	}
 
 	/* do the test by disabling interrupts first this time */
 	tracing_max_latency = 0;
-	tr->ctrl = 1;
-	trace->ctrl_update(tr);
+	tracing_start();
 	preempt_disable();
 	local_irq_disable();
 	udelay(100);
@@ -341,8 +395,7 @@
 	local_irq_enable();
 
 	/* stop the tracing. */
-	tr->ctrl = 0;
-	trace->ctrl_update(tr);
+	tracing_stop();
 	/* check both trace buffers */
 	ret = trace_test_buffer(tr, NULL);
 	if (ret)
@@ -358,6 +411,7 @@
 
  out:
 	trace->reset(tr);
+	tracing_start();
 	tracing_max_latency = save_max;
 
 	return ret;
@@ -423,8 +477,12 @@
 	wait_for_completion(&isrt);
 
 	/* start the tracing */
-	tr->ctrl = 1;
-	trace->init(tr);
+	ret = trace->init(tr);
+	if (ret) {
+		warn_failed_init_tracer(trace, ret);
+		return ret;
+	}
+
 	/* reset the max latency */
 	tracing_max_latency = 0;
 
@@ -448,8 +506,7 @@
 	msleep(100);
 
 	/* stop the tracing. */
-	tr->ctrl = 0;
-	trace->ctrl_update(tr);
+	tracing_stop();
 	/* check both trace buffers */
 	ret = trace_test_buffer(tr, NULL);
 	if (!ret)
@@ -457,6 +514,7 @@
 
 
 	trace->reset(tr);
+	tracing_start();
 
 	tracing_max_latency = save_max;
 
@@ -480,16 +538,20 @@
 	int ret;
 
 	/* start the tracing */
-	tr->ctrl = 1;
-	trace->init(tr);
+	ret = trace->init(tr);
+	if (ret) {
+		warn_failed_init_tracer(trace, ret);
+		return ret;
+	}
+
 	/* Sleep for a 1/10 of a second */
 	msleep(100);
 	/* stop the tracing. */
-	tr->ctrl = 0;
-	trace->ctrl_update(tr);
+	tracing_stop();
 	/* check the trace buffer */
 	ret = trace_test_buffer(tr, &count);
 	trace->reset(tr);
+	tracing_start();
 
 	if (!ret && !count) {
 		printk(KERN_CONT ".. no entries found ..");
@@ -508,17 +570,48 @@
 	int ret;
 
 	/* start the tracing */
-	tr->ctrl = 1;
-	trace->init(tr);
+	ret = trace->init(tr);
+	if (ret) {
+		warn_failed_init_tracer(trace, ret);
+		return 0;
+	}
+
 	/* Sleep for a 1/10 of a second */
 	msleep(100);
 	/* stop the tracing. */
-	tr->ctrl = 0;
-	trace->ctrl_update(tr);
+	tracing_stop();
 	/* check the trace buffer */
 	ret = trace_test_buffer(tr, &count);
 	trace->reset(tr);
+	tracing_start();
 
 	return ret;
 }
 #endif /* CONFIG_SYSPROF_TRACER */
+
+#ifdef CONFIG_BRANCH_TRACER
+int
+trace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr)
+{
+	unsigned long count;
+	int ret;
+
+	/* start the tracing */
+	ret = trace->init(tr);
+	if (ret) {
+		warn_failed_init_tracer(trace, ret);
+		return ret;
+	}
+
+	/* Sleep for a 1/10 of a second */
+	msleep(100);
+	/* stop the tracing. */
+	tracing_stop();
+	/* check the trace buffer */
+	ret = trace_test_buffer(tr, &count);
+	trace->reset(tr);
+	tracing_start();
+
+	return ret;
+}
+#endif /* CONFIG_BRANCH_TRACER */
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index 3bdb44b..d0871bc 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -10,6 +10,7 @@
 #include <linux/debugfs.h>
 #include <linux/ftrace.h>
 #include <linux/module.h>
+#include <linux/sysctl.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include "trace.h"
@@ -31,6 +32,10 @@
 
 static int stack_trace_disabled __read_mostly;
 static DEFINE_PER_CPU(int, trace_active);
+static DEFINE_MUTEX(stack_sysctl_mutex);
+
+int stack_tracer_enabled;
+static int last_stack_tracer_enabled;
 
 static inline void check_stack(void)
 {
@@ -48,7 +53,7 @@
 	if (!object_is_on_stack(&this_size))
 		return;
 
-	raw_local_irq_save(flags);
+	local_irq_save(flags);
 	__raw_spin_lock(&max_stack_lock);
 
 	/* a race could have already updated it */
@@ -78,6 +83,7 @@
 	 * on a new max, so it is far from a fast path.
 	 */
 	while (i < max_stack_trace.nr_entries) {
+		int found = 0;
 
 		stack_dump_index[i] = this_size;
 		p = start;
@@ -86,17 +92,19 @@
 			if (*p == stack_dump_trace[i]) {
 				this_size = stack_dump_index[i++] =
 					(top - p) * sizeof(unsigned long);
+				found = 1;
 				/* Start the search from here */
 				start = p + 1;
 			}
 		}
 
-		i++;
+		if (!found)
+			i++;
 	}
 
  out:
 	__raw_spin_unlock(&max_stack_lock);
-	raw_local_irq_restore(flags);
+	local_irq_restore(flags);
 }
 
 static void
@@ -107,8 +115,7 @@
 	if (unlikely(!ftrace_enabled || stack_trace_disabled))
 		return;
 
-	resched = need_resched();
-	preempt_disable_notrace();
+	resched = ftrace_preempt_disable();
 
 	cpu = raw_smp_processor_id();
 	/* no atomic needed, we only modify this variable by this cpu */
@@ -120,10 +127,7 @@
  out:
 	per_cpu(trace_active, cpu)--;
 	/* prevent recursion in schedule */
-	if (resched)
-		preempt_enable_no_resched_notrace();
-	else
-		preempt_enable_notrace();
+	ftrace_preempt_enable(resched);
 }
 
 static struct ftrace_ops trace_ops __read_mostly =
@@ -166,16 +170,16 @@
 	if (ret < 0)
 		return ret;
 
-	raw_local_irq_save(flags);
+	local_irq_save(flags);
 	__raw_spin_lock(&max_stack_lock);
 	*ptr = val;
 	__raw_spin_unlock(&max_stack_lock);
-	raw_local_irq_restore(flags);
+	local_irq_restore(flags);
 
 	return count;
 }
 
-static struct file_operations stack_max_size_fops = {
+static const struct file_operations stack_max_size_fops = {
 	.open		= tracing_open_generic,
 	.read		= stack_max_size_read,
 	.write		= stack_max_size_write,
@@ -273,7 +277,7 @@
 	return 0;
 }
 
-static struct seq_operations stack_trace_seq_ops = {
+static const struct seq_operations stack_trace_seq_ops = {
 	.start		= t_start,
 	.next		= t_next,
 	.stop		= t_stop,
@@ -289,12 +293,47 @@
 	return ret;
 }
 
-static struct file_operations stack_trace_fops = {
+static const struct file_operations stack_trace_fops = {
 	.open		= stack_trace_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
 };
 
+int
+stack_trace_sysctl(struct ctl_table *table, int write,
+		   struct file *file, void __user *buffer, size_t *lenp,
+		   loff_t *ppos)
+{
+	int ret;
+
+	mutex_lock(&stack_sysctl_mutex);
+
+	ret = proc_dointvec(table, write, file, buffer, lenp, ppos);
+
+	if (ret || !write ||
+	    (last_stack_tracer_enabled == stack_tracer_enabled))
+		goto out;
+
+	last_stack_tracer_enabled = stack_tracer_enabled;
+
+	if (stack_tracer_enabled)
+		register_ftrace_function(&trace_ops);
+	else
+		unregister_ftrace_function(&trace_ops);
+
+ out:
+	mutex_unlock(&stack_sysctl_mutex);
+	return ret;
+}
+
+static __init int enable_stacktrace(char *str)
+{
+	stack_tracer_enabled = 1;
+	last_stack_tracer_enabled = 1;
+	return 1;
+}
+__setup("stacktrace", enable_stacktrace);
+
 static __init int stack_trace_init(void)
 {
 	struct dentry *d_tracer;
@@ -312,7 +351,8 @@
 	if (!entry)
 		pr_warning("Could not create debugfs 'stack_trace' entry\n");
 
-	register_ftrace_function(&trace_ops);
+	if (stack_tracer_enabled)
+		register_ftrace_function(&trace_ops);
 
 	return 0;
 }
diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c
index 9587d3b..01becf1 100644
--- a/kernel/trace/trace_sysprof.c
+++ b/kernel/trace/trace_sysprof.c
@@ -234,20 +234,10 @@
 		stop_stack_timer(cpu);
 }
 
-static void stack_reset(struct trace_array *tr)
-{
-	int cpu;
-
-	tr->time_start = ftrace_now(tr->cpu);
-
-	for_each_online_cpu(cpu)
-		tracing_reset(tr, cpu);
-}
-
 static void start_stack_trace(struct trace_array *tr)
 {
 	mutex_lock(&sample_timer_lock);
-	stack_reset(tr);
+	tracing_reset_online_cpus(tr);
 	start_stack_timers();
 	tracer_enabled = 1;
 	mutex_unlock(&sample_timer_lock);
@@ -261,27 +251,17 @@
 	mutex_unlock(&sample_timer_lock);
 }
 
-static void stack_trace_init(struct trace_array *tr)
+static int stack_trace_init(struct trace_array *tr)
 {
 	sysprof_trace = tr;
 
-	if (tr->ctrl)
-		start_stack_trace(tr);
+	start_stack_trace(tr);
+	return 0;
 }
 
 static void stack_trace_reset(struct trace_array *tr)
 {
-	if (tr->ctrl)
-		stop_stack_trace(tr);
-}
-
-static void stack_trace_ctrl_update(struct trace_array *tr)
-{
-	/* When starting a new trace, reset the buffers */
-	if (tr->ctrl)
-		start_stack_trace(tr);
-	else
-		stop_stack_trace(tr);
+	stop_stack_trace(tr);
 }
 
 static struct tracer stack_trace __read_mostly =
@@ -289,7 +269,6 @@
 	.name		= "sysprof",
 	.init		= stack_trace_init,
 	.reset		= stack_trace_reset,
-	.ctrl_update	= stack_trace_ctrl_update,
 #ifdef CONFIG_FTRACE_SELFTEST
 	.selftest    = trace_selftest_startup_sysprof,
 #endif
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
index af8c856..7960274 100644
--- a/kernel/tracepoint.c
+++ b/kernel/tracepoint.c
@@ -43,6 +43,7 @@
  */
 #define TRACEPOINT_HASH_BITS 6
 #define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS)
+static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
 
 /*
  * Note about RCU :
@@ -54,40 +55,43 @@
 	struct hlist_node hlist;
 	void **funcs;
 	int refcount;	/* Number of times armed. 0 if disarmed. */
-	struct rcu_head rcu;
-	void *oldptr;
-	unsigned char rcu_pending:1;
 	char name[0];
 };
 
-static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
+struct tp_probes {
+	union {
+		struct rcu_head rcu;
+		struct list_head list;
+	} u;
+	void *probes[0];
+};
 
-static void free_old_closure(struct rcu_head *head)
+static inline void *allocate_probes(int count)
 {
-	struct tracepoint_entry *entry = container_of(head,
-		struct tracepoint_entry, rcu);
-	kfree(entry->oldptr);
-	/* Make sure we free the data before setting the pending flag to 0 */
-	smp_wmb();
-	entry->rcu_pending = 0;
+	struct tp_probes *p  = kmalloc(count * sizeof(void *)
+			+ sizeof(struct tp_probes), GFP_KERNEL);
+	return p == NULL ? NULL : p->probes;
 }
 
-static void tracepoint_entry_free_old(struct tracepoint_entry *entry, void *old)
+static void rcu_free_old_probes(struct rcu_head *head)
 {
-	if (!old)
-		return;
-	entry->oldptr = old;
-	entry->rcu_pending = 1;
-	/* write rcu_pending before calling the RCU callback */
-	smp_wmb();
-	call_rcu_sched(&entry->rcu, free_old_closure);
+	kfree(container_of(head, struct tp_probes, u.rcu));
+}
+
+static inline void release_probes(void *old)
+{
+	if (old) {
+		struct tp_probes *tp_probes = container_of(old,
+			struct tp_probes, probes[0]);
+		call_rcu_sched(&tp_probes->u.rcu, rcu_free_old_probes);
+	}
 }
 
 static void debug_print_probes(struct tracepoint_entry *entry)
 {
 	int i;
 
-	if (!tracepoint_debug)
+	if (!tracepoint_debug || !entry->funcs)
 		return;
 
 	for (i = 0; entry->funcs[i]; i++)
@@ -111,12 +115,13 @@
 				return ERR_PTR(-EEXIST);
 	}
 	/* + 2 : one for new probe, one for NULL func */
-	new = kzalloc((nr_probes + 2) * sizeof(void *), GFP_KERNEL);
+	new = allocate_probes(nr_probes + 2);
 	if (new == NULL)
 		return ERR_PTR(-ENOMEM);
 	if (old)
 		memcpy(new, old, nr_probes * sizeof(void *));
 	new[nr_probes] = probe;
+	new[nr_probes + 1] = NULL;
 	entry->refcount = nr_probes + 1;
 	entry->funcs = new;
 	debug_print_probes(entry);
@@ -132,7 +137,7 @@
 	old = entry->funcs;
 
 	if (!old)
-		return NULL;
+		return ERR_PTR(-ENOENT);
 
 	debug_print_probes(entry);
 	/* (N -> M), (N > 1, M >= 0) probes */
@@ -151,13 +156,13 @@
 		int j = 0;
 		/* N -> M, (N > 1, M > 0) */
 		/* + 1 for NULL */
-		new = kzalloc((nr_probes - nr_del + 1)
-			* sizeof(void *), GFP_KERNEL);
+		new = allocate_probes(nr_probes - nr_del + 1);
 		if (new == NULL)
 			return ERR_PTR(-ENOMEM);
 		for (i = 0; old[i]; i++)
 			if ((probe && old[i] != probe))
 				new[j++] = old[i];
+		new[nr_probes - nr_del] = NULL;
 		entry->refcount = nr_probes - nr_del;
 		entry->funcs = new;
 	}
@@ -215,7 +220,6 @@
 	memcpy(&e->name[0], name, name_len);
 	e->funcs = NULL;
 	e->refcount = 0;
-	e->rcu_pending = 0;
 	hlist_add_head(&e->hlist, head);
 	return e;
 }
@@ -224,32 +228,10 @@
  * Remove the tracepoint from the tracepoint hash table. Must be called with
  * mutex_lock held.
  */
-static int remove_tracepoint(const char *name)
+static inline void remove_tracepoint(struct tracepoint_entry *e)
 {
-	struct hlist_head *head;
-	struct hlist_node *node;
-	struct tracepoint_entry *e;
-	int found = 0;
-	size_t len = strlen(name) + 1;
-	u32 hash = jhash(name, len-1, 0);
-
-	head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
-	hlist_for_each_entry(e, node, head, hlist) {
-		if (!strcmp(name, e->name)) {
-			found = 1;
-			break;
-		}
-	}
-	if (!found)
-		return -ENOENT;
-	if (e->refcount)
-		return -EBUSY;
 	hlist_del(&e->hlist);
-	/* Make sure the call_rcu_sched has been executed */
-	if (e->rcu_pending)
-		rcu_barrier_sched();
 	kfree(e);
-	return 0;
 }
 
 /*
@@ -280,6 +262,7 @@
 static void disable_tracepoint(struct tracepoint *elem)
 {
 	elem->state = 0;
+	rcu_assign_pointer(elem->funcs, NULL);
 }
 
 /**
@@ -320,6 +303,23 @@
 	module_update_tracepoints();
 }
 
+static void *tracepoint_add_probe(const char *name, void *probe)
+{
+	struct tracepoint_entry *entry;
+	void *old;
+
+	entry = get_tracepoint(name);
+	if (!entry) {
+		entry = add_tracepoint(name);
+		if (IS_ERR(entry))
+			return entry;
+	}
+	old = tracepoint_entry_add_probe(entry, probe);
+	if (IS_ERR(old) && !entry->refcount)
+		remove_tracepoint(entry);
+	return old;
+}
+
 /**
  * tracepoint_probe_register -  Connect a probe to a tracepoint
  * @name: tracepoint name
@@ -330,44 +330,36 @@
  */
 int tracepoint_probe_register(const char *name, void *probe)
 {
-	struct tracepoint_entry *entry;
-	int ret = 0;
 	void *old;
 
 	mutex_lock(&tracepoints_mutex);
-	entry = get_tracepoint(name);
-	if (!entry) {
-		entry = add_tracepoint(name);
-		if (IS_ERR(entry)) {
-			ret = PTR_ERR(entry);
-			goto end;
-		}
-	}
-	/*
-	 * If we detect that a call_rcu_sched is pending for this tracepoint,
-	 * make sure it's executed now.
-	 */
-	if (entry->rcu_pending)
-		rcu_barrier_sched();
-	old = tracepoint_entry_add_probe(entry, probe);
-	if (IS_ERR(old)) {
-		ret = PTR_ERR(old);
-		goto end;
-	}
+	old = tracepoint_add_probe(name, probe);
 	mutex_unlock(&tracepoints_mutex);
+	if (IS_ERR(old))
+		return PTR_ERR(old);
+
 	tracepoint_update_probes();		/* may update entry */
-	mutex_lock(&tracepoints_mutex);
-	entry = get_tracepoint(name);
-	WARN_ON(!entry);
-	if (entry->rcu_pending)
-		rcu_barrier_sched();
-	tracepoint_entry_free_old(entry, old);
-end:
-	mutex_unlock(&tracepoints_mutex);
-	return ret;
+	release_probes(old);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(tracepoint_probe_register);
 
+static void *tracepoint_remove_probe(const char *name, void *probe)
+{
+	struct tracepoint_entry *entry;
+	void *old;
+
+	entry = get_tracepoint(name);
+	if (!entry)
+		return ERR_PTR(-ENOENT);
+	old = tracepoint_entry_remove_probe(entry, probe);
+	if (IS_ERR(old))
+		return old;
+	if (!entry->refcount)
+		remove_tracepoint(entry);
+	return old;
+}
+
 /**
  * tracepoint_probe_unregister -  Disconnect a probe from a tracepoint
  * @name: tracepoint name
@@ -380,39 +372,105 @@
  */
 int tracepoint_probe_unregister(const char *name, void *probe)
 {
-	struct tracepoint_entry *entry;
 	void *old;
-	int ret = -ENOENT;
 
 	mutex_lock(&tracepoints_mutex);
-	entry = get_tracepoint(name);
-	if (!entry)
-		goto end;
-	if (entry->rcu_pending)
-		rcu_barrier_sched();
-	old = tracepoint_entry_remove_probe(entry, probe);
-	if (!old) {
-		printk(KERN_WARNING "Warning: Trying to unregister a probe"
-				    "that doesn't exist\n");
-		goto end;
-	}
+	old = tracepoint_remove_probe(name, probe);
 	mutex_unlock(&tracepoints_mutex);
+	if (IS_ERR(old))
+		return PTR_ERR(old);
+
 	tracepoint_update_probes();		/* may update entry */
-	mutex_lock(&tracepoints_mutex);
-	entry = get_tracepoint(name);
-	if (!entry)
-		goto end;
-	if (entry->rcu_pending)
-		rcu_barrier_sched();
-	tracepoint_entry_free_old(entry, old);
-	remove_tracepoint(name);	/* Ignore busy error message */
-	ret = 0;
-end:
-	mutex_unlock(&tracepoints_mutex);
-	return ret;
+	release_probes(old);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(tracepoint_probe_unregister);
 
+static LIST_HEAD(old_probes);
+static int need_update;
+
+static void tracepoint_add_old_probes(void *old)
+{
+	need_update = 1;
+	if (old) {
+		struct tp_probes *tp_probes = container_of(old,
+			struct tp_probes, probes[0]);
+		list_add(&tp_probes->u.list, &old_probes);
+	}
+}
+
+/**
+ * tracepoint_probe_register_noupdate -  register a probe but not connect
+ * @name: tracepoint name
+ * @probe: probe handler
+ *
+ * caller must call tracepoint_probe_update_all()
+ */
+int tracepoint_probe_register_noupdate(const char *name, void *probe)
+{
+	void *old;
+
+	mutex_lock(&tracepoints_mutex);
+	old = tracepoint_add_probe(name, probe);
+	if (IS_ERR(old)) {
+		mutex_unlock(&tracepoints_mutex);
+		return PTR_ERR(old);
+	}
+	tracepoint_add_old_probes(old);
+	mutex_unlock(&tracepoints_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tracepoint_probe_register_noupdate);
+
+/**
+ * tracepoint_probe_unregister_noupdate -  remove a probe but not disconnect
+ * @name: tracepoint name
+ * @probe: probe function pointer
+ *
+ * caller must call tracepoint_probe_update_all()
+ */
+int tracepoint_probe_unregister_noupdate(const char *name, void *probe)
+{
+	void *old;
+
+	mutex_lock(&tracepoints_mutex);
+	old = tracepoint_remove_probe(name, probe);
+	if (IS_ERR(old)) {
+		mutex_unlock(&tracepoints_mutex);
+		return PTR_ERR(old);
+	}
+	tracepoint_add_old_probes(old);
+	mutex_unlock(&tracepoints_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tracepoint_probe_unregister_noupdate);
+
+/**
+ * tracepoint_probe_update_all -  update tracepoints
+ */
+void tracepoint_probe_update_all(void)
+{
+	LIST_HEAD(release_probes);
+	struct tp_probes *pos, *next;
+
+	mutex_lock(&tracepoints_mutex);
+	if (!need_update) {
+		mutex_unlock(&tracepoints_mutex);
+		return;
+	}
+	if (!list_empty(&old_probes))
+		list_replace_init(&old_probes, &release_probes);
+	need_update = 0;
+	mutex_unlock(&tracepoints_mutex);
+
+	tracepoint_update_probes();
+	list_for_each_entry_safe(pos, next, &release_probes, u.list) {
+		list_del(&pos->u.list);
+		call_rcu_sched(&pos->u.rcu, rcu_free_old_probes);
+	}
+}
+EXPORT_SYMBOL_GPL(tracepoint_probe_update_all);
+
 /**
  * tracepoint_get_iter_range - Get a next tracepoint iterator given a range.
  * @tracepoint: current tracepoints (in), next tracepoint (out)
@@ -483,3 +541,36 @@
 	iter->tracepoint = NULL;
 }
 EXPORT_SYMBOL_GPL(tracepoint_iter_reset);
+
+#ifdef CONFIG_MODULES
+
+int tracepoint_module_notify(struct notifier_block *self,
+			     unsigned long val, void *data)
+{
+	struct module *mod = data;
+
+	switch (val) {
+	case MODULE_STATE_COMING:
+		tracepoint_update_probe_range(mod->tracepoints,
+			mod->tracepoints + mod->num_tracepoints);
+		break;
+	case MODULE_STATE_GOING:
+		tracepoint_update_probe_range(mod->tracepoints,
+			mod->tracepoints + mod->num_tracepoints);
+		break;
+	}
+	return 0;
+}
+
+struct notifier_block tracepoint_module_nb = {
+	.notifier_call = tracepoint_module_notify,
+	.priority = 0,
+};
+
+static int init_tracepoints(void)
+{
+	return register_module_notifier(&tracepoint_module_nb);
+}
+__initcall(init_tracepoints);
+
+#endif /* CONFIG_MODULES */
diff --git a/kernel/tsacct.c b/kernel/tsacct.c
index 8ebcd85..2dc06ab 100644
--- a/kernel/tsacct.c
+++ b/kernel/tsacct.c
@@ -27,6 +27,7 @@
  */
 void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
 {
+	const struct cred *tcred;
 	struct timespec uptime, ts;
 	u64 ac_etime;
 
@@ -53,10 +54,11 @@
 		stats->ac_flag |= AXSIG;
 	stats->ac_nice	 = task_nice(tsk);
 	stats->ac_sched	 = tsk->policy;
-	stats->ac_uid	 = tsk->uid;
-	stats->ac_gid	 = tsk->gid;
 	stats->ac_pid	 = tsk->pid;
 	rcu_read_lock();
+	tcred = __task_cred(tsk);
+	stats->ac_uid	 = tcred->uid;
+	stats->ac_gid	 = tcred->gid;
 	stats->ac_ppid	 = pid_alive(tsk) ?
 				rcu_dereference(tsk->real_parent)->tgid : 0;
 	rcu_read_unlock();
diff --git a/kernel/uid16.c b/kernel/uid16.c
index 3e41c16..2460c31 100644
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -84,11 +84,12 @@
 
 asmlinkage long sys_getresuid16(old_uid_t __user *ruid, old_uid_t __user *euid, old_uid_t __user *suid)
 {
+	const struct cred *cred = current_cred();
 	int retval;
 
-	if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
-	    !(retval = put_user(high2lowuid(current->euid), euid)))
-		retval = put_user(high2lowuid(current->suid), suid);
+	if (!(retval   = put_user(high2lowuid(cred->uid),  ruid)) &&
+	    !(retval   = put_user(high2lowuid(cred->euid), euid)))
+		retval = put_user(high2lowuid(cred->suid), suid);
 
 	return retval;
 }
@@ -104,11 +105,12 @@
 
 asmlinkage long sys_getresgid16(old_gid_t __user *rgid, old_gid_t __user *egid, old_gid_t __user *sgid)
 {
+	const struct cred *cred = current_cred();
 	int retval;
 
-	if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
-	    !(retval = put_user(high2lowgid(current->egid), egid)))
-		retval = put_user(high2lowgid(current->sgid), sgid);
+	if (!(retval   = put_user(high2lowgid(cred->gid),  rgid)) &&
+	    !(retval   = put_user(high2lowgid(cred->egid), egid)))
+		retval = put_user(high2lowgid(cred->sgid), sgid);
 
 	return retval;
 }
@@ -161,25 +163,24 @@
 
 asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist)
 {
-	int i = 0;
+	const struct cred *cred = current_cred();
+	int i;
 
 	if (gidsetsize < 0)
 		return -EINVAL;
 
-	get_group_info(current->group_info);
-	i = current->group_info->ngroups;
+	i = cred->group_info->ngroups;
 	if (gidsetsize) {
 		if (i > gidsetsize) {
 			i = -EINVAL;
 			goto out;
 		}
-		if (groups16_to_user(grouplist, current->group_info)) {
+		if (groups16_to_user(grouplist, cred->group_info)) {
 			i = -EFAULT;
 			goto out;
 		}
 	}
 out:
-	put_group_info(current->group_info);
 	return i;
 }
 
@@ -210,20 +211,20 @@
 
 asmlinkage long sys_getuid16(void)
 {
-	return high2lowuid(current->uid);
+	return high2lowuid(current_uid());
 }
 
 asmlinkage long sys_geteuid16(void)
 {
-	return high2lowuid(current->euid);
+	return high2lowuid(current_euid());
 }
 
 asmlinkage long sys_getgid16(void)
 {
-	return high2lowgid(current->gid);
+	return high2lowgid(current_gid());
 }
 
 asmlinkage long sys_getegid16(void)
 {
-	return high2lowgid(current->egid);
+	return high2lowgid(current_egid());
 }
diff --git a/kernel/user.c b/kernel/user.c
index 39d6159..477b666 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -16,12 +16,13 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/user_namespace.h>
+#include "cred-internals.h"
 
 struct user_namespace init_user_ns = {
 	.kref = {
-		.refcount	= ATOMIC_INIT(2),
+		.refcount	= ATOMIC_INIT(1),
 	},
-	.root_user = &root_user,
+	.creator = &root_user,
 };
 EXPORT_SYMBOL_GPL(init_user_ns);
 
@@ -47,12 +48,14 @@
  */
 static DEFINE_SPINLOCK(uidhash_lock);
 
+/* root_user.__count is 2, 1 for init task cred, 1 for init_user_ns->creator */
 struct user_struct root_user = {
-	.__count	= ATOMIC_INIT(1),
+	.__count	= ATOMIC_INIT(2),
 	.processes	= ATOMIC_INIT(1),
 	.files		= ATOMIC_INIT(0),
 	.sigpending	= ATOMIC_INIT(0),
 	.locked_shm     = 0,
+	.user_ns	= &init_user_ns,
 #ifdef CONFIG_USER_SCHED
 	.tg		= &init_task_group,
 #endif
@@ -101,19 +104,15 @@
 	if (IS_ERR(up->tg))
 		rc = -ENOMEM;
 
-	return rc;
-}
+	set_tg_uid(up);
 
-static void sched_switch_user(struct task_struct *p)
-{
-	sched_move_task(p);
+	return rc;
 }
 
 #else	/* CONFIG_USER_SCHED */
 
 static void sched_destroy_user(struct user_struct *up) { }
 static int sched_create_user(struct user_struct *up) { return 0; }
-static void sched_switch_user(struct task_struct *p) { }
 
 #endif	/* CONFIG_USER_SCHED */
 
@@ -242,13 +241,21 @@
 	.release = uids_release,
 };
 
-/* create /sys/kernel/uids/<uid>/cpu_share file for this user */
+/*
+ * Create /sys/kernel/uids/<uid>/cpu_share file for this user
+ * We do not create this file for users in a user namespace (until
+ * sysfs tagging is implemented).
+ *
+ * See Documentation/scheduler/sched-design-CFS.txt for ramifications.
+ */
 static int uids_user_create(struct user_struct *up)
 {
 	struct kobject *kobj = &up->kobj;
 	int error;
 
 	memset(kobj, 0, sizeof(struct kobject));
+	if (up->user_ns != &init_user_ns)
+		return 0;
 	kobj->kset = uids_kset;
 	error = kobject_init_and_add(kobj, &uids_ktype, NULL, "%d", up->uid);
 	if (error) {
@@ -284,6 +291,8 @@
 	unsigned long flags;
 	int remove_user = 0;
 
+	if (up->user_ns != &init_user_ns)
+		return;
 	/* Make uid_hash_remove() + sysfs_remove_file() + kobject_del()
 	 * atomic.
 	 */
@@ -319,12 +328,13 @@
  * IRQ state (as stored in flags) is restored and uidhash_lock released
  * upon function exit.
  */
-static inline void free_user(struct user_struct *up, unsigned long flags)
+static void free_user(struct user_struct *up, unsigned long flags)
 {
 	/* restore back the count */
 	atomic_inc(&up->__count);
 	spin_unlock_irqrestore(&uidhash_lock, flags);
 
+	put_user_ns(up->user_ns);
 	INIT_WORK(&up->work, remove_user_sysfs_dir);
 	schedule_work(&up->work);
 }
@@ -340,13 +350,14 @@
  * IRQ state (as stored in flags) is restored and uidhash_lock released
  * upon function exit.
  */
-static inline void free_user(struct user_struct *up, unsigned long flags)
+static void free_user(struct user_struct *up, unsigned long flags)
 {
 	uid_hash_remove(up);
 	spin_unlock_irqrestore(&uidhash_lock, flags);
 	sched_destroy_user(up);
 	key_put(up->uid_keyring);
 	key_put(up->session_keyring);
+	put_user_ns(up->user_ns);
 	kmem_cache_free(uid_cachep, up);
 }
 
@@ -362,7 +373,7 @@
 {
 	struct user_struct *ret;
 	unsigned long flags;
-	struct user_namespace *ns = current->nsproxy->user_ns;
+	struct user_namespace *ns = current_user_ns();
 
 	spin_lock_irqsave(&uidhash_lock, flags);
 	ret = uid_hash_find(uid, uidhashentry(ns, uid));
@@ -409,6 +420,8 @@
 		if (sched_create_user(new) < 0)
 			goto out_free_user;
 
+		new->user_ns = get_user_ns(ns);
+
 		if (uids_user_create(new))
 			goto out_destoy_sched;
 
@@ -432,7 +445,6 @@
 			up = new;
 		}
 		spin_unlock_irq(&uidhash_lock);
-
 	}
 
 	uids_mutex_unlock();
@@ -441,6 +453,7 @@
 
 out_destoy_sched:
 	sched_destroy_user(new);
+	put_user_ns(new->user_ns);
 out_free_user:
 	kmem_cache_free(uid_cachep, new);
 out_unlock:
@@ -448,63 +461,6 @@
 	return NULL;
 }
 
-void switch_uid(struct user_struct *new_user)
-{
-	struct user_struct *old_user;
-
-	/* What if a process setreuid()'s and this brings the
-	 * new uid over his NPROC rlimit?  We can check this now
-	 * cheaply with the new uid cache, so if it matters
-	 * we should be checking for it.  -DaveM
-	 */
-	old_user = current->user;
-	atomic_inc(&new_user->processes);
-	atomic_dec(&old_user->processes);
-	switch_uid_keyring(new_user);
-	current->user = new_user;
-	sched_switch_user(current);
-
-	/*
-	 * We need to synchronize with __sigqueue_alloc()
-	 * doing a get_uid(p->user).. If that saw the old
-	 * user value, we need to wait until it has exited
-	 * its critical region before we can free the old
-	 * structure.
-	 */
-	smp_mb();
-	spin_unlock_wait(&current->sighand->siglock);
-
-	free_uid(old_user);
-	suid_keys(current);
-}
-
-#ifdef CONFIG_USER_NS
-void release_uids(struct user_namespace *ns)
-{
-	int i;
-	unsigned long flags;
-	struct hlist_head *head;
-	struct hlist_node *nd;
-
-	spin_lock_irqsave(&uidhash_lock, flags);
-	/*
-	 * collapse the chains so that the user_struct-s will
-	 * be still alive, but not in hashes. subsequent free_uid()
-	 * will free them.
-	 */
-	for (i = 0; i < UIDHASH_SZ; i++) {
-		head = ns->uidhash_table + i;
-		while (!hlist_empty(head)) {
-			nd = head->first;
-			hlist_del_init(nd);
-		}
-	}
-	spin_unlock_irqrestore(&uidhash_lock, flags);
-
-	free_uid(ns->root_user);
-}
-#endif
-
 static int __init uid_cache_init(void)
 {
 	int n;
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 532858f..7908431 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -9,60 +9,55 @@
 #include <linux/nsproxy.h>
 #include <linux/slab.h>
 #include <linux/user_namespace.h>
+#include <linux/cred.h>
 
 /*
- * Clone a new ns copying an original user ns, setting refcount to 1
- * @old_ns: namespace to clone
- * Return NULL on error (failure to kmalloc), new ns otherwise
+ * Create a new user namespace, deriving the creator from the user in the
+ * passed credentials, and replacing that user with the new root user for the
+ * new namespace.
+ *
+ * This is called by copy_creds(), which will finish setting the target task's
+ * credentials.
  */
-static struct user_namespace *clone_user_ns(struct user_namespace *old_ns)
+int create_user_ns(struct cred *new)
 {
 	struct user_namespace *ns;
-	struct user_struct *new_user;
+	struct user_struct *root_user;
 	int n;
 
 	ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL);
 	if (!ns)
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 
 	kref_init(&ns->kref);
 
 	for (n = 0; n < UIDHASH_SZ; ++n)
 		INIT_HLIST_HEAD(ns->uidhash_table + n);
 
-	/* Insert new root user.  */
-	ns->root_user = alloc_uid(ns, 0);
-	if (!ns->root_user) {
+	/* Alloc new root user.  */
+	root_user = alloc_uid(ns, 0);
+	if (!root_user) {
 		kfree(ns);
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 	}
 
-	/* Reset current->user with a new one */
-	new_user = alloc_uid(ns, current->uid);
-	if (!new_user) {
-		free_uid(ns->root_user);
-		kfree(ns);
-		return ERR_PTR(-ENOMEM);
-	}
+	/* set the new root user in the credentials under preparation */
+	ns->creator = new->user;
+	new->user = root_user;
+	new->uid = new->euid = new->suid = new->fsuid = 0;
+	new->gid = new->egid = new->sgid = new->fsgid = 0;
+	put_group_info(new->group_info);
+	new->group_info = get_group_info(&init_groups);
+#ifdef CONFIG_KEYS
+	key_put(new->request_key_auth);
+	new->request_key_auth = NULL;
+#endif
+	/* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
 
-	switch_uid(new_user);
-	return ns;
-}
+	/* alloc_uid() incremented the userns refcount.  Just set it to 1 */
+	kref_set(&ns->kref, 1);
 
-struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns)
-{
-	struct user_namespace *new_ns;
-
-	BUG_ON(!old_ns);
-	get_user_ns(old_ns);
-
-	if (!(flags & CLONE_NEWUSER))
-		return old_ns;
-
-	new_ns = clone_user_ns(old_ns);
-
-	put_user_ns(old_ns);
-	return new_ns;
+	return 0;
 }
 
 void free_user_ns(struct kref *kref)
@@ -70,7 +65,7 @@
 	struct user_namespace *ns;
 
 	ns = container_of(kref, struct user_namespace, kref);
-	release_uids(ns);
+	free_uid(ns->creator);
 	kfree(ns);
 }
 EXPORT_SYMBOL(free_user_ns);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index d4dc69d..4952322 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -84,21 +84,21 @@
 static cpumask_t cpu_populated_map __read_mostly;
 
 /* If it's single threaded, it isn't in the list of workqueues. */
-static inline int is_single_threaded(struct workqueue_struct *wq)
+static inline int is_wq_single_threaded(struct workqueue_struct *wq)
 {
 	return wq->singlethread;
 }
 
 static const cpumask_t *wq_cpu_map(struct workqueue_struct *wq)
 {
-	return is_single_threaded(wq)
+	return is_wq_single_threaded(wq)
 		? &cpu_singlethread_map : &cpu_populated_map;
 }
 
 static
 struct cpu_workqueue_struct *wq_per_cpu(struct workqueue_struct *wq, int cpu)
 {
-	if (unlikely(is_single_threaded(wq)))
+	if (unlikely(is_wq_single_threaded(wq)))
 		cpu = singlethread_cpu;
 	return per_cpu_ptr(wq->cpu_wq, cpu);
 }
@@ -769,7 +769,7 @@
 {
 	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
 	struct workqueue_struct *wq = cwq->wq;
-	const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d";
+	const char *fmt = is_wq_single_threaded(wq) ? "%s" : "%s/%d";
 	struct task_struct *p;
 
 	p = kthread_create(worker_thread, cwq, fmt, wq->name, cpu);
diff --git a/lib/Kconfig b/lib/Kconfig
index 85cf7ea..fd4118e 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -64,6 +64,8 @@
 
 config LIBCRC32C
 	tristate "CRC32c (Castagnoli, et al) Cyclic Redundancy-Check"
+	select CRYPTO
+	select CRYPTO_CRC32C
 	help
 	  This option is provided for the case where no in-kernel-tree
 	  modules require CRC32c functions, but a module built outside the
diff --git a/lib/Makefile b/lib/Makefile
index 7cb65d8..80fe8a3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -11,7 +11,7 @@
 	 rbtree.o radix-tree.o dump_stack.o \
 	 idr.o int_sqrt.o extable.o prio_tree.o \
 	 sha1.o irq_regs.o reciprocal_div.o argv_split.o \
-	 proportions.o prio_heap.o ratelimit.o show_mem.o
+	 proportions.o prio_heap.o ratelimit.o show_mem.o is_single_threaded.o
 
 lib-$(CONFIG_MMU) += ioremap.o
 lib-$(CONFIG_SMP) += cpumask.o
diff --git a/lib/bug.c b/lib/bug.c
index bfeafd6..300e41a 100644
--- a/lib/bug.c
+++ b/lib/bug.c
@@ -5,6 +5,8 @@
 
   CONFIG_BUG - emit BUG traps.  Nothing happens without this.
   CONFIG_GENERIC_BUG - enable this code.
+  CONFIG_GENERIC_BUG_RELATIVE_POINTERS - use 32-bit pointers relative to
+	the containing struct bug_entry for bug_addr and file.
   CONFIG_DEBUG_BUGVERBOSE - emit full file+line information for each BUG
 
   CONFIG_BUG and CONFIG_DEBUG_BUGVERBOSE are potentially user-settable
@@ -43,6 +45,15 @@
 
 extern const struct bug_entry __start___bug_table[], __stop___bug_table[];
 
+static inline unsigned long bug_addr(const struct bug_entry *bug)
+{
+#ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
+	return bug->bug_addr;
+#else
+	return (unsigned long)bug + bug->bug_addr_disp;
+#endif
+}
+
 #ifdef CONFIG_MODULES
 static LIST_HEAD(module_bug_list);
 
@@ -55,7 +66,7 @@
 		unsigned i;
 
 		for (i = 0; i < mod->num_bugs; ++i, ++bug)
-			if (bugaddr == bug->bug_addr)
+			if (bugaddr == bug_addr(bug))
 				return bug;
 	}
 	return NULL;
@@ -108,7 +119,7 @@
 	const struct bug_entry *bug;
 
 	for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
-		if (bugaddr == bug->bug_addr)
+		if (bugaddr == bug_addr(bug))
 			return bug;
 
 	return module_find_bug(bugaddr);
@@ -133,7 +144,11 @@
 
 	if (bug) {
 #ifdef CONFIG_DEBUG_BUGVERBOSE
+#ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
 		file = bug->file;
+#else
+		file = (const char *)bug + bug->file_disp;
+#endif
 		line = bug->line;
 #endif
 		warning = (bug->flags & BUGFLAG_WARNING) != 0;
diff --git a/lib/is_single_threaded.c b/lib/is_single_threaded.c
new file mode 100644
index 0000000..f1ed2fe
--- /dev/null
+++ b/lib/is_single_threaded.c
@@ -0,0 +1,45 @@
+/* Function to determine if a thread group is single threaded or not
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ * - Derived from security/selinux/hooks.c
+ *
+ * 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.
+ */
+
+#include <linux/sched.h>
+
+/**
+ * is_single_threaded - Determine if a thread group is single-threaded or not
+ * @p: A task in the thread group in question
+ *
+ * This returns true if the thread group to which a task belongs is single
+ * threaded, false if it is not.
+ */
+bool is_single_threaded(struct task_struct *p)
+{
+	struct task_struct *g, *t;
+	struct mm_struct *mm = p->mm;
+
+	if (atomic_read(&p->signal->count) != 1)
+		goto no;
+
+	if (atomic_read(&p->mm->mm_users) != 1) {
+		read_lock(&tasklist_lock);
+		do_each_thread(g, t) {
+			if (t->mm == mm && t != p)
+				goto no_unlock;
+		} while_each_thread(g, t);
+		read_unlock(&tasklist_lock);
+	}
+
+	return true;
+
+no_unlock:
+	read_unlock(&tasklist_lock);
+no:
+	return false;
+}
diff --git a/lib/libcrc32c.c b/lib/libcrc32c.c
index b5c3287..244f548 100644
--- a/lib/libcrc32c.c
+++ b/lib/libcrc32c.c
@@ -30,168 +30,52 @@
  * any later version.
  *
  */
-#include <linux/crc32c.h>
-#include <linux/compiler.h>
+
+#include <crypto/hash.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 
+static struct crypto_shash *tfm;
+
+u32 crc32c(u32 crc, const void *address, unsigned int length)
+{
+	struct {
+		struct shash_desc shash;
+		char ctx[crypto_shash_descsize(tfm)];
+	} desc;
+	int err;
+
+	desc.shash.tfm = tfm;
+	desc.shash.flags = 0;
+	*(u32 *)desc.ctx = crc;
+
+	err = crypto_shash_update(&desc.shash, address, length);
+	BUG_ON(err);
+
+	return *(u32 *)desc.ctx;
+}
+
+EXPORT_SYMBOL(crc32c);
+
+static int __init libcrc32c_mod_init(void)
+{
+	tfm = crypto_alloc_shash("crc32c", 0, 0);
+	if (IS_ERR(tfm))
+		return PTR_ERR(tfm);
+
+	return 0;
+}
+
+static void __exit libcrc32c_mod_fini(void)
+{
+	crypto_free_shash(tfm);
+}
+
+module_init(libcrc32c_mod_init);
+module_exit(libcrc32c_mod_fini);
+
 MODULE_AUTHOR("Clay Haapala <chaapala@cisco.com>");
 MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations");
 MODULE_LICENSE("GPL");
-
-#define CRC32C_POLY_BE 0x1EDC6F41
-#define CRC32C_POLY_LE 0x82F63B78
-
-#ifndef CRC_LE_BITS 
-# define CRC_LE_BITS 8
-#endif
-
-
-/*
- * Haven't generated a big-endian table yet, but the bit-wise version
- * should at least work.
- */
-#if defined CRC_BE_BITS && CRC_BE_BITS != 1
-#undef CRC_BE_BITS
-#endif
-#ifndef CRC_BE_BITS
-# define CRC_BE_BITS 1
-#endif
-
-EXPORT_SYMBOL(crc32c_le);
-
-#if CRC_LE_BITS == 1
-/*
- * Compute things bit-wise, as done in crc32.c.  We could share the tight 
- * loop below with crc32 and vary the POLY if we don't find value in terms
- * of space and maintainability in keeping the two modules separate.
- */
-u32 __pure
-crc32c_le(u32 crc, unsigned char const *p, size_t len)
-{
-	int i;
-	while (len--) {
-		crc ^= *p++;
-		for (i = 0; i < 8; i++)
-			crc = (crc >> 1) ^ ((crc & 1) ? CRC32C_POLY_LE : 0);
-	}
-	return crc;
-}
-#else
-
-/*
- * This is the CRC-32C table
- * Generated with:
- * width = 32 bits
- * poly = 0x1EDC6F41
- * reflect input bytes = true
- * reflect output bytes = true
- */
-
-static const u32 crc32c_table[256] = {
-	0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
-	0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
-	0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
-	0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
-	0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
-	0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
-	0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
-	0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
-	0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
-	0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
-	0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
-	0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
-	0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
-	0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
-	0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
-	0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
-	0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
-	0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
-	0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
-	0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
-	0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
-	0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
-	0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
-	0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
-	0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
-	0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
-	0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
-	0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
-	0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
-	0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
-	0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
-	0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
-	0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
-	0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
-	0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
-	0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
-	0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
-	0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
-	0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
-	0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
-	0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
-	0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
-	0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
-	0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
-	0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
-	0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
-	0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
-	0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
-	0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
-	0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
-	0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
-	0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
-	0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
-	0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
-	0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
-	0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
-	0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
-	0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
-	0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
-	0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
-	0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
-	0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
-	0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
-	0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
-};
-
-/*
- * Steps through buffer one byte at at time, calculates reflected 
- * crc using table.
- */
-
-u32 __pure
-crc32c_le(u32 crc, unsigned char const *data, size_t length)
-{
-	while (length--)
-		crc =
-		    crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8);
-
-	return crc;
-}
-
-#endif	/* CRC_LE_BITS == 8 */
-
-EXPORT_SYMBOL(crc32c_be);
-
-#if CRC_BE_BITS == 1
-u32 __pure
-crc32c_be(u32 crc, unsigned char const *p, size_t len)
-{
-	int i;
-	while (len--) {
-		crc ^= *p++ << 24;
-		for (i = 0; i < 8; i++)
-			crc =
-			    (crc << 1) ^ ((crc & 0x80000000) ? CRC32C_POLY_BE :
-					  0);
-	}
-	return crc;
-}
-#endif
-
-/*
- * Unit test
- *
- * A small unit test suite is implemented as part of the crypto suite.
- * Select CRYPTO_CRC32C and use the tcrypt module to run the tests.
- */
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index a013bbc..3b77702 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -581,6 +581,62 @@
 	return string(buf, end, sym, field_width, precision, flags);
 }
 
+static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
+				int precision, int flags)
+{
+	char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */
+	char *p = mac_addr;
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		p = pack_hex_byte(p, addr[i]);
+		if (!(flags & SPECIAL) && i != 5)
+			*p++ = ':';
+	}
+	*p = '\0';
+
+	return string(buf, end, mac_addr, field_width, precision, flags & ~SPECIAL);
+}
+
+static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
+			 int precision, int flags)
+{
+	char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */
+	char *p = ip6_addr;
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		p = pack_hex_byte(p, addr[2 * i]);
+		p = pack_hex_byte(p, addr[2 * i + 1]);
+		if (!(flags & SPECIAL) && i != 7)
+			*p++ = ':';
+	}
+	*p = '\0';
+
+	return string(buf, end, ip6_addr, field_width, precision, flags & ~SPECIAL);
+}
+
+static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
+			 int precision, int flags)
+{
+	char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */
+	char temp[3];	/* hold each IP quad in reverse order */
+	char *p = ip4_addr;
+	int i, digits;
+
+	for (i = 0; i < 4; i++) {
+		digits = put_dec_trunc(temp, addr[i]) - temp;
+		/* reverse the digits in the quad */
+		while (digits--)
+			*p++ = temp[digits];
+		if (i != 3)
+			*p++ = '.';
+	}
+	*p = '\0';
+
+	return string(buf, end, ip4_addr, field_width, precision, flags & ~SPECIAL);
+}
+
 /*
  * Show a '%p' thing.  A kernel extension is that the '%p' is followed
  * by an extra set of alphanumeric characters that are extended format
@@ -592,6 +648,12 @@
  * - 'S' For symbolic direct pointers
  * - 'R' For a struct resource pointer, it prints the range of
  *       addresses (not the name nor the flags)
+ * - 'M' For a 6-byte MAC address, it prints the address in the
+ *       usual colon-separated hex notation
+ * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated
+ *       decimal for v4 and colon separated network-order 16 bit hex for v6)
+ * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is
+ *       currently the same
  *
  * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
  * function pointers are really function descriptors, which contain a
@@ -607,6 +669,21 @@
 		return symbol_string(buf, end, ptr, field_width, precision, flags);
 	case 'R':
 		return resource_string(buf, end, ptr, field_width, precision, flags);
+	case 'm':
+		flags |= SPECIAL;
+		/* Fallthrough */
+	case 'M':
+		return mac_address_string(buf, end, ptr, field_width, precision, flags);
+	case 'i':
+		flags |= SPECIAL;
+		/* Fallthrough */
+	case 'I':
+		if (fmt[1] == '6')
+			return ip6_addr_string(buf, end, ptr, field_width, precision, flags);
+		if (fmt[1] == '4')
+			return ip4_addr_string(buf, end, ptr, field_width, precision, flags);
+		flags &= ~SPECIAL;
+		break;
 	}
 	flags |= SMALL;
 	if (field_width == -1) {
diff --git a/mm/bounce.c b/mm/bounce.c
index 06722c4..bf0cf7c 100644
--- a/mm/bounce.c
+++ b/mm/bounce.c
@@ -14,6 +14,7 @@
 #include <linux/hash.h>
 #include <linux/highmem.h>
 #include <linux/blktrace_api.h>
+#include <trace/block.h>
 #include <asm/tlbflush.h>
 
 #define POOL_SIZE	64
@@ -21,6 +22,8 @@
 
 static mempool_t *page_pool, *isa_page_pool;
 
+DEFINE_TRACE(block_bio_bounce);
+
 #ifdef CONFIG_HIGHMEM
 static __init int init_emergency_pool(void)
 {
@@ -222,7 +225,7 @@
 	if (!bio)
 		return;
 
-	blk_add_trace_bio(q, *bio_orig, BLK_TA_BOUNCE);
+	trace_block_bio_bounce(q, *bio_orig);
 
 	/*
 	 * at least one page was bounced, fill in possible non-highmem
diff --git a/mm/memory.c b/mm/memory.c
index 164951c..f01b7ee 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -669,6 +669,16 @@
 	if (is_vm_hugetlb_page(vma))
 		return copy_hugetlb_page_range(dst_mm, src_mm, vma);
 
+	if (unlikely(is_pfn_mapping(vma))) {
+		/*
+		 * We do not free on error cases below as remove_vma
+		 * gets called on error from higher level routine
+		 */
+		ret = track_pfn_vma_copy(vma);
+		if (ret)
+			return ret;
+	}
+
 	/*
 	 * We need to invalidate the secondary MMU mappings only when
 	 * there could be a permission downgrade on the ptes of the
@@ -915,6 +925,9 @@
 		if (vma->vm_flags & VM_ACCOUNT)
 			*nr_accounted += (end - start) >> PAGE_SHIFT;
 
+		if (unlikely(is_pfn_mapping(vma)))
+			untrack_pfn_vma(vma, 0, 0);
+
 		while (start != end) {
 			if (!tlb_start_valid) {
 				tlb_start = start;
@@ -1430,6 +1443,7 @@
 int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
 			unsigned long pfn)
 {
+	int ret;
 	/*
 	 * Technically, architectures with pte_special can avoid all these
 	 * restrictions (same for remap_pfn_range).  However we would like
@@ -1444,7 +1458,15 @@
 
 	if (addr < vma->vm_start || addr >= vma->vm_end)
 		return -EFAULT;
-	return insert_pfn(vma, addr, pfn, vma->vm_page_prot);
+	if (track_pfn_vma_new(vma, vma->vm_page_prot, pfn, PAGE_SIZE))
+		return -EINVAL;
+
+	ret = insert_pfn(vma, addr, pfn, vma->vm_page_prot);
+
+	if (ret)
+		untrack_pfn_vma(vma, pfn, PAGE_SIZE);
+
+	return ret;
 }
 EXPORT_SYMBOL(vm_insert_pfn);
 
@@ -1575,14 +1597,17 @@
 	 * behaviour that some programs depend on. We mark the "original"
 	 * un-COW'ed pages by matching them up with "vma->vm_pgoff".
 	 */
-	if (is_cow_mapping(vma->vm_flags)) {
-		if (addr != vma->vm_start || end != vma->vm_end)
-			return -EINVAL;
+	if (addr == vma->vm_start && end == vma->vm_end)
 		vma->vm_pgoff = pfn;
-	}
+	else if (is_cow_mapping(vma->vm_flags))
+		return -EINVAL;
 
 	vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
 
+	err = track_pfn_vma_new(vma, prot, pfn, PAGE_ALIGN(size));
+	if (err)
+		return -EINVAL;
+
 	BUG_ON(addr >= end);
 	pfn -= addr >> PAGE_SHIFT;
 	pgd = pgd_offset(mm, addr);
@@ -1594,6 +1619,10 @@
 		if (err)
 			break;
 	} while (pgd++, addr = next, addr != end);
+
+	if (err)
+		untrack_pfn_vma(vma, pfn, PAGE_ALIGN(size));
+
 	return err;
 }
 EXPORT_SYMBOL(remap_pfn_range);
@@ -2865,9 +2894,9 @@
 #endif	/* __HAVE_ARCH_GATE_AREA */
 
 #ifdef CONFIG_HAVE_IOREMAP_PROT
-static resource_size_t follow_phys(struct vm_area_struct *vma,
-			unsigned long address, unsigned int flags,
-			unsigned long *prot)
+int follow_phys(struct vm_area_struct *vma,
+		unsigned long address, unsigned int flags,
+		unsigned long *prot, resource_size_t *phys)
 {
 	pgd_t *pgd;
 	pud_t *pud;
@@ -2876,24 +2905,26 @@
 	spinlock_t *ptl;
 	resource_size_t phys_addr = 0;
 	struct mm_struct *mm = vma->vm_mm;
+	int ret = -EINVAL;
 
-	VM_BUG_ON(!(vma->vm_flags & (VM_IO | VM_PFNMAP)));
+	if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
+		goto out;
 
 	pgd = pgd_offset(mm, address);
 	if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
-		goto no_page_table;
+		goto out;
 
 	pud = pud_offset(pgd, address);
 	if (pud_none(*pud) || unlikely(pud_bad(*pud)))
-		goto no_page_table;
+		goto out;
 
 	pmd = pmd_offset(pud, address);
 	if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
-		goto no_page_table;
+		goto out;
 
 	/* We cannot handle huge page PFN maps. Luckily they don't exist. */
 	if (pmd_huge(*pmd))
-		goto no_page_table;
+		goto out;
 
 	ptep = pte_offset_map_lock(mm, pmd, address, &ptl);
 	if (!ptep)
@@ -2908,13 +2939,13 @@
 	phys_addr <<= PAGE_SHIFT; /* Shift here to avoid overflow on PAE */
 
 	*prot = pgprot_val(pte_pgprot(pte));
+	*phys = phys_addr;
+	ret = 0;
 
 unlock:
 	pte_unmap_unlock(ptep, ptl);
 out:
-	return phys_addr;
-no_page_table:
-	return 0;
+	return ret;
 }
 
 int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
@@ -2925,12 +2956,7 @@
 	void *maddr;
 	int offset = addr & (PAGE_SIZE-1);
 
-	if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
-		return -EINVAL;
-
-	phys_addr = follow_phys(vma, addr, write, &prot);
-
-	if (!phys_addr)
+	if (follow_phys(vma, addr, write, &prot, &phys_addr))
 		return -EINVAL;
 
 	maddr = ioremap_prot(phys_addr, PAGE_SIZE, prot);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index e9493b1..e412ffa 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1114,6 +1114,7 @@
 		const unsigned long __user *old_nodes,
 		const unsigned long __user *new_nodes)
 {
+	const struct cred *cred = current_cred(), *tcred;
 	struct mm_struct *mm;
 	struct task_struct *task;
 	nodemask_t old;
@@ -1148,12 +1149,16 @@
 	 * capabilities, superuser privileges or the same
 	 * userid as the target process.
 	 */
-	if ((current->euid != task->suid) && (current->euid != task->uid) &&
-	    (current->uid != task->suid) && (current->uid != task->uid) &&
+	rcu_read_lock();
+	tcred = __task_cred(task);
+	if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
+	    cred->uid  != tcred->suid && cred->uid  != tcred->uid &&
 	    !capable(CAP_SYS_NICE)) {
+		rcu_read_unlock();
 		err = -EPERM;
 		goto out;
 	}
+	rcu_read_unlock();
 
 	task_nodes = cpuset_mems_allowed(task);
 	/* Is the user allowed to access the target nodes? */
diff --git a/mm/migrate.c b/mm/migrate.c
index 037b096..21631ab 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1075,6 +1075,7 @@
 			const int __user *nodes,
 			int __user *status, int flags)
 {
+	const struct cred *cred = current_cred(), *tcred;
 	struct task_struct *task;
 	struct mm_struct *mm;
 	int err;
@@ -1105,12 +1106,16 @@
 	 * capabilities, superuser privileges or the same
 	 * userid as the target process.
 	 */
-	if ((current->euid != task->suid) && (current->euid != task->uid) &&
-	    (current->uid != task->suid) && (current->uid != task->uid) &&
+	rcu_read_lock();
+	tcred = __task_cred(task);
+	if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
+	    cred->uid  != tcred->suid && cred->uid  != tcred->uid &&
 	    !capable(CAP_SYS_NICE)) {
+		rcu_read_unlock();
 		err = -EPERM;
 		goto out;
 	}
+	rcu_read_unlock();
 
  	err = security_task_movememory(task);
  	if (err)
diff --git a/mm/mlock.c b/mm/mlock.c
index 1ada366..3035a56 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -667,3 +667,48 @@
 	spin_unlock(&shmlock_user_lock);
 	free_uid(user);
 }
+
+void *alloc_locked_buffer(size_t size)
+{
+	unsigned long rlim, vm, pgsz;
+	void *buffer = NULL;
+
+	pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+	down_write(&current->mm->mmap_sem);
+
+	rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
+	vm   = current->mm->total_vm + pgsz;
+	if (rlim < vm)
+		goto out;
+
+	rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
+	vm   = current->mm->locked_vm + pgsz;
+	if (rlim < vm)
+		goto out;
+
+	buffer = kzalloc(size, GFP_KERNEL);
+	if (!buffer)
+		goto out;
+
+	current->mm->total_vm  += pgsz;
+	current->mm->locked_vm += pgsz;
+
+ out:
+	up_write(&current->mm->mmap_sem);
+	return buffer;
+}
+
+void free_locked_buffer(void *buffer, size_t size)
+{
+	unsigned long pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+	down_write(&current->mm->mmap_sem);
+
+	current->mm->total_vm  -= pgsz;
+	current->mm->locked_vm -= pgsz;
+
+	up_write(&current->mm->mmap_sem);
+
+	kfree(buffer);
+}
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index a0a0190..558f9af 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -128,8 +128,8 @@
 	 * Superuser processes are usually more important, so we make it
 	 * less likely that we kill those.
 	 */
-	if (has_capability(p, CAP_SYS_ADMIN) ||
-	    has_capability(p, CAP_SYS_RESOURCE))
+	if (has_capability_noaudit(p, CAP_SYS_ADMIN) ||
+	    has_capability_noaudit(p, CAP_SYS_RESOURCE))
 		points /= 4;
 
 	/*
@@ -138,7 +138,7 @@
 	 * tend to only have this flag set on applications they think
 	 * of as important.
 	 */
-	if (has_capability(p, CAP_SYS_RAWIO))
+	if (has_capability_noaudit(p, CAP_SYS_RAWIO))
 		points /= 4;
 
 	/*
@@ -299,9 +299,9 @@
 
 		task_lock(p);
 		printk(KERN_INFO "[%5d] %5d %5d %8lu %8lu %3d     %3d %s\n",
-		       p->pid, p->uid, p->tgid, p->mm->total_vm,
-		       get_mm_rss(p->mm), (int)task_cpu(p), p->oomkilladj,
-		       p->comm);
+		       p->pid, __task_cred(p)->uid, p->tgid,
+		       p->mm->total_vm, get_mm_rss(p->mm), (int)task_cpu(p),
+		       p->oomkilladj, p->comm);
 		task_unlock(p);
 	} while_each_thread(g, p);
 }
diff --git a/mm/shmem.c b/mm/shmem.c
index 0ed0752..f1b0d48 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1513,8 +1513,8 @@
 	inode = new_inode(sb);
 	if (inode) {
 		inode->i_mode = mode;
-		inode->i_uid = current->fsuid;
-		inode->i_gid = current->fsgid;
+		inode->i_uid = current_fsuid();
+		inode->i_gid = current_fsgid();
 		inode->i_blocks = 0;
 		inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -2278,8 +2278,8 @@
 	sbinfo->max_blocks = 0;
 	sbinfo->max_inodes = 0;
 	sbinfo->mode = S_IRWXUGO | S_ISVTX;
-	sbinfo->uid = current->fsuid;
-	sbinfo->gid = current->fsgid;
+	sbinfo->uid = current_fsuid();
+	sbinfo->gid = current_fsgid();
 	sbinfo->mpol = NULL;
 	sb->s_fs_info = sbinfo;
 
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 90cb67a..54a9f87 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1462,6 +1462,15 @@
 __initcall(procswaps_init);
 #endif /* CONFIG_PROC_FS */
 
+#ifdef MAX_SWAPFILES_CHECK
+static int __init max_swapfiles_check(void)
+{
+	MAX_SWAPFILES_CHECK();
+	return 0;
+}
+late_initcall(max_swapfiles_check);
+#endif
+
 /*
  * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
  *
diff --git a/net/802/fddi.c b/net/802/fddi.c
index 0549317..f1611a1 100644
--- a/net/802/fddi.c
+++ b/net/802/fddi.c
@@ -167,23 +167,27 @@
 
 EXPORT_SYMBOL(fddi_type_trans);
 
-static int fddi_change_mtu(struct net_device *dev, int new_mtu)
+int fddi_change_mtu(struct net_device *dev, int new_mtu)
 {
 	if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN))
 		return(-EINVAL);
 	dev->mtu = new_mtu;
 	return(0);
 }
+EXPORT_SYMBOL(fddi_change_mtu);
 
 static const struct header_ops fddi_header_ops = {
 	.create		= fddi_header,
 	.rebuild	= fddi_rebuild_header,
 };
 
+
 static void fddi_setup(struct net_device *dev)
 {
-	dev->change_mtu		= fddi_change_mtu;
 	dev->header_ops		= &fddi_header_ops;
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
+	dev->change_mtu		= fddi_change_mtu,
+#endif
 
 	dev->type		= ARPHRD_FDDI;
 	dev->hard_header_len	= FDDI_K_SNAP_HLEN+3;	/* Assume 802.2 SNAP hdr len + 3 pad bytes */
diff --git a/net/802/hippi.c b/net/802/hippi.c
index e35dc1e..313b9eb 100644
--- a/net/802/hippi.c
+++ b/net/802/hippi.c
@@ -144,7 +144,7 @@
 
 EXPORT_SYMBOL(hippi_type_trans);
 
-static int hippi_change_mtu(struct net_device *dev, int new_mtu)
+int hippi_change_mtu(struct net_device *dev, int new_mtu)
 {
 	/*
 	 * HIPPI's got these nice large MTUs.
@@ -154,12 +154,13 @@
 	dev->mtu = new_mtu;
 	return(0);
 }
+EXPORT_SYMBOL(hippi_change_mtu);
 
 /*
  * For HIPPI we will actually use the lower 4 bytes of the hardware
  * address as the I-FIELD rather than the actual hardware address.
  */
-static int hippi_mac_addr(struct net_device *dev, void *p)
+int hippi_mac_addr(struct net_device *dev, void *p)
 {
 	struct sockaddr *addr = p;
 	if (netif_running(dev))
@@ -167,8 +168,9 @@
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 	return 0;
 }
+EXPORT_SYMBOL(hippi_mac_addr);
 
-static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
+int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
 {
 	/* Never send broadcast/multicast ARP messages */
 	p->mcast_probes = 0;
@@ -181,6 +183,7 @@
 		p->ucast_probes = 0;
 	return 0;
 }
+EXPORT_SYMBOL(hippi_neigh_setup_dev);
 
 static const struct header_ops hippi_header_ops = {
 	.create		= hippi_header,
@@ -190,11 +193,12 @@
 
 static void hippi_setup(struct net_device *dev)
 {
-	dev->set_multicast_list		= NULL;
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
 	dev->change_mtu			= hippi_change_mtu;
-	dev->header_ops			= &hippi_header_ops;
 	dev->set_mac_address 		= hippi_mac_addr;
 	dev->neigh_setup 		= hippi_neigh_setup_dev;
+#endif
+	dev->header_ops			= &hippi_header_ops;
 
 	/*
 	 * We don't support HIPPI `ARP' for the time being, and probably
diff --git a/net/802/tr.c b/net/802/tr.c
index 18c6647..158150f 100644
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -285,10 +285,7 @@
 		if(entry)
 		{
 #if TR_SR_DEBUG
-{
-DECLARE_MAC_BUF(mac);
-printk("source routing for %s\n",print_mac(mac, trh->daddr));
-}
+printk("source routing for %pM\n", trh->daddr);
 #endif
 			if(!entry->local_ring && (ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8)
 			{
@@ -370,9 +367,8 @@
 	if(entry==NULL)
 	{
 #if TR_SR_DEBUG
-		DECLARE_MAC_BUF(mac);
-		printk("adding rif_entry: addr:%s rcf:%04X\n",
-		       print_mac(mac, trh->saddr), ntohs(trh->rcf));
+		printk("adding rif_entry: addr:%pM rcf:%04X\n",
+		       trh->saddr, ntohs(trh->rcf));
 #endif
 		/*
 		 *	Allocate our new entry. A failure to allocate loses
@@ -417,11 +413,8 @@
 			 !(trh->rcf & htons(TR_RCF_BROADCAST_MASK)))
 		    {
 #if TR_SR_DEBUG
-{
-DECLARE_MAC_BUF(mac);
-printk("updating rif_entry: addr:%s rcf:%04X\n",
-		print_mac(mac, trh->saddr), ntohs(trh->rcf));
-}
+printk("updating rif_entry: addr:%pM rcf:%04X\n",
+		trh->saddr, ntohs(trh->rcf));
 #endif
 			    entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK);
 			    memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
@@ -532,7 +525,6 @@
 {
 	int j, rcf_len, segment, brdgnmb;
 	struct rif_cache *entry = v;
-	DECLARE_MAC_BUF(mac);
 
 	if (v == SEQ_START_TOKEN)
 		seq_puts(seq,
@@ -542,9 +534,9 @@
 		long ttl = (long) (entry->last_used + sysctl_tr_rif_timeout)
 				- (long) jiffies;
 
-		seq_printf(seq, "%s %s %7li ",
+		seq_printf(seq, "%s %pM %7li ",
 			   dev?dev->name:"?",
-			   print_mac(mac, entry->addr),
+			   entry->addr,
 			   ttl/HZ);
 
 			if (entry->local_ring)
@@ -643,7 +635,7 @@
 		.data		= &sysctl_tr_rif_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{ 0 },
 };
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index f0e335a..41e8f65 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -46,10 +46,10 @@
 /* Our listing of VLAN group(s) */
 static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE];
 
-static char vlan_fullname[] = "802.1Q VLAN Support";
-static char vlan_version[] = DRV_VERSION;
-static char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
-static char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
+const char vlan_fullname[] = "802.1Q VLAN Support";
+const char vlan_version[] = DRV_VERSION;
+static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
+static const char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
 
 static struct packet_type vlan_packet_type = {
 	.type = __constant_htons(ETH_P_8021Q),
@@ -144,6 +144,7 @@
 {
 	struct vlan_dev_info *vlan = vlan_dev_info(dev);
 	struct net_device *real_dev = vlan->real_dev;
+	const struct net_device_ops *ops = real_dev->netdev_ops;
 	struct vlan_group *grp;
 	u16 vlan_id = vlan->vlan_id;
 
@@ -156,7 +157,7 @@
 	 * HW accelerating devices or SW vlan input packet processing.
 	 */
 	if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
-		real_dev->vlan_rx_kill_vid(real_dev, vlan_id);
+		ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id);
 
 	vlan_group_set_device(grp, vlan_id, NULL);
 	grp->nr_vlans--;
@@ -170,7 +171,7 @@
 		vlan_gvrp_uninit_applicant(real_dev);
 
 		if (real_dev->features & NETIF_F_HW_VLAN_RX)
-			real_dev->vlan_rx_register(real_dev, NULL);
+			ops->ndo_vlan_rx_register(real_dev, NULL);
 
 		hlist_del_rcu(&grp->hlist);
 
@@ -205,21 +206,21 @@
 
 int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
 {
-	char *name = real_dev->name;
+	const char *name = real_dev->name;
+	const struct net_device_ops *ops = real_dev->netdev_ops;
 
 	if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
 		pr_info("8021q: VLANs not supported on %s\n", name);
 		return -EOPNOTSUPP;
 	}
 
-	if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&
-	    !real_dev->vlan_rx_register) {
+	if ((real_dev->features & NETIF_F_HW_VLAN_RX) && !ops->ndo_vlan_rx_register) {
 		pr_info("8021q: device %s has buggy VLAN hw accel\n", name);
 		return -EOPNOTSUPP;
 	}
 
 	if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
-	    (!real_dev->vlan_rx_add_vid || !real_dev->vlan_rx_kill_vid)) {
+	    (!ops->ndo_vlan_rx_add_vid || !ops->ndo_vlan_rx_kill_vid)) {
 		pr_info("8021q: Device %s has buggy VLAN hw accel\n", name);
 		return -EOPNOTSUPP;
 	}
@@ -240,6 +241,7 @@
 {
 	struct vlan_dev_info *vlan = vlan_dev_info(dev);
 	struct net_device *real_dev = vlan->real_dev;
+	const struct net_device_ops *ops = real_dev->netdev_ops;
 	u16 vlan_id = vlan->vlan_id;
 	struct vlan_group *grp, *ngrp = NULL;
 	int err;
@@ -275,9 +277,9 @@
 	grp->nr_vlans++;
 
 	if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX)
-		real_dev->vlan_rx_register(real_dev, ngrp);
+		ops->ndo_vlan_rx_register(real_dev, ngrp);
 	if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
-		real_dev->vlan_rx_add_vid(real_dev, vlan_id);
+		ops->ndo_vlan_rx_add_vid(real_dev, vlan_id);
 
 	return 0;
 
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index a6603a4..82570bc 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -108,8 +108,10 @@
 static inline void vlan_gvrp_uninit(void) {}
 #endif
 
-int vlan_netlink_init(void);
-void vlan_netlink_fini(void);
+extern const char vlan_fullname[];
+extern const char vlan_version[];
+extern int vlan_netlink_init(void);
+extern void vlan_netlink_fini(void);
 
 extern struct rtnl_link_ops vlan_link_ops;
 
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 68ced4b..dd86a1d 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -47,8 +47,6 @@
 	skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci);
 	skb->vlan_tci = 0;
 
-	dev->last_rx = jiffies;
-
 	stats = &dev->stats;
 	stats->rx_packets++;
 	stats->rx_bytes += skb->len;
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 8883e9c..89a3bbd 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -163,8 +163,6 @@
 		goto err_unlock;
 	}
 
-	skb->dev->last_rx = jiffies;
-
 	stats = &skb->dev->stats;
 	stats->rx_packets++;
 	stats->rx_bytes += skb->len;
@@ -526,6 +524,7 @@
 static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
+	const struct net_device_ops *ops = real_dev->netdev_ops;
 	struct ifreq ifrr;
 	int err = -EOPNOTSUPP;
 
@@ -536,8 +535,8 @@
 	case SIOCGMIIPHY:
 	case SIOCGMIIREG:
 	case SIOCSMIIREG:
-		if (real_dev->do_ioctl && netif_device_present(real_dev))
-			err = real_dev->do_ioctl(real_dev, &ifrr, cmd);
+		if (netif_device_present(real_dev) && ops->ndo_do_ioctl)
+			err = ops->ndo_do_ioctl(real_dev, &ifrr, cmd);
 		break;
 	}
 
@@ -594,6 +593,8 @@
 	.parse	 = eth_header_parse,
 };
 
+static const struct net_device_ops vlan_netdev_ops, vlan_netdev_accel_ops;
+
 static int vlan_dev_init(struct net_device *dev)
 {
 	struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
@@ -620,11 +621,11 @@
 	if (real_dev->features & NETIF_F_HW_VLAN_TX) {
 		dev->header_ops      = real_dev->header_ops;
 		dev->hard_header_len = real_dev->hard_header_len;
-		dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit;
+		dev->netdev_ops         = &vlan_netdev_accel_ops;
 	} else {
 		dev->header_ops      = &vlan_header_ops;
 		dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
-		dev->hard_start_xmit = vlan_dev_hard_start_xmit;
+		dev->netdev_ops         = &vlan_netdev_ops;
 	}
 
 	if (is_vlan_dev(real_dev))
@@ -648,6 +649,26 @@
 	}
 }
 
+static int vlan_ethtool_get_settings(struct net_device *dev,
+				     struct ethtool_cmd *cmd)
+{
+	const struct vlan_dev_info *vlan = vlan_dev_info(dev);
+	struct net_device *real_dev = vlan->real_dev;
+
+	if (!real_dev->ethtool_ops->get_settings)
+		return -EOPNOTSUPP;
+
+	return real_dev->ethtool_ops->get_settings(real_dev, cmd);
+}
+
+static void vlan_ethtool_get_drvinfo(struct net_device *dev,
+				     struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, vlan_fullname);
+	strcpy(info->version, vlan_version);
+	strcpy(info->fw_version, "N/A");
+}
+
 static u32 vlan_ethtool_get_rx_csum(struct net_device *dev)
 {
 	const struct vlan_dev_info *vlan = vlan_dev_info(dev);
@@ -672,11 +693,43 @@
 }
 
 static const struct ethtool_ops vlan_ethtool_ops = {
+	.get_settings	        = vlan_ethtool_get_settings,
+	.get_drvinfo	        = vlan_ethtool_get_drvinfo,
 	.get_link		= ethtool_op_get_link,
 	.get_rx_csum		= vlan_ethtool_get_rx_csum,
 	.get_flags		= vlan_ethtool_get_flags,
 };
 
+static const struct net_device_ops vlan_netdev_ops = {
+	.ndo_change_mtu		= vlan_dev_change_mtu,
+	.ndo_init		= vlan_dev_init,
+	.ndo_uninit		= vlan_dev_uninit,
+	.ndo_open		= vlan_dev_open,
+	.ndo_stop		= vlan_dev_stop,
+	.ndo_start_xmit =  vlan_dev_hard_start_xmit,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= vlan_dev_set_mac_address,
+	.ndo_set_rx_mode	= vlan_dev_set_rx_mode,
+	.ndo_set_multicast_list	= vlan_dev_set_rx_mode,
+	.ndo_change_rx_flags	= vlan_dev_change_rx_flags,
+	.ndo_do_ioctl		= vlan_dev_ioctl,
+};
+
+static const struct net_device_ops vlan_netdev_accel_ops = {
+	.ndo_change_mtu		= vlan_dev_change_mtu,
+	.ndo_init		= vlan_dev_init,
+	.ndo_uninit		= vlan_dev_uninit,
+	.ndo_open		= vlan_dev_open,
+	.ndo_stop		= vlan_dev_stop,
+	.ndo_start_xmit =  vlan_dev_hwaccel_hard_start_xmit,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= vlan_dev_set_mac_address,
+	.ndo_set_rx_mode	= vlan_dev_set_rx_mode,
+	.ndo_set_multicast_list	= vlan_dev_set_rx_mode,
+	.ndo_change_rx_flags	= vlan_dev_change_rx_flags,
+	.ndo_do_ioctl		= vlan_dev_ioctl,
+};
+
 void vlan_setup(struct net_device *dev)
 {
 	ether_setup(dev);
@@ -684,16 +737,7 @@
 	dev->priv_flags		|= IFF_802_1Q_VLAN;
 	dev->tx_queue_len	= 0;
 
-	dev->change_mtu		= vlan_dev_change_mtu;
-	dev->init		= vlan_dev_init;
-	dev->uninit		= vlan_dev_uninit;
-	dev->open		= vlan_dev_open;
-	dev->stop		= vlan_dev_stop;
-	dev->set_mac_address	= vlan_dev_set_mac_address;
-	dev->set_rx_mode	= vlan_dev_set_rx_mode;
-	dev->set_multicast_list	= vlan_dev_set_rx_mode;
-	dev->change_rx_flags	= vlan_dev_change_rx_flags;
-	dev->do_ioctl		= vlan_dev_ioctl;
+	dev->netdev_ops		= &vlan_netdev_ops;
 	dev->destructor		= free_netdev;
 	dev->ethtool_ops	= &vlan_ethtool_ops;
 
diff --git a/net/9p/client.c b/net/9p/client.c
index 4b52945..821f1ec 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -627,7 +627,7 @@
 	memset(&fid->qid, 0, sizeof(struct p9_qid));
 	fid->mode = -1;
 	fid->rdir_fpos = 0;
-	fid->uid = current->fsuid;
+	fid->uid = current_fsuid();
 	fid->clnt = clnt;
 	fid->aux = NULL;
 
diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
index 2f1fe5f..7fa0eb2 100644
--- a/net/9p/trans_rdma.c
+++ b/net/9p/trans_rdma.c
@@ -528,8 +528,6 @@
 
 /**
  * alloc_rdma - Allocate and initialize the rdma transport structure
- * @msize: MTU
- * @dotu: Extension attribute
  * @opts: Mount options structure
  */
 static struct p9_trans_rdma *alloc_rdma(struct p9_rdma_opts *opts)
diff --git a/net/Kconfig b/net/Kconfig
index d789d79..6ec2cce 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -27,11 +27,14 @@
 config NET_NS
 	bool "Network namespace support"
 	default n
-	depends on EXPERIMENTAL && !SYSFS && NAMESPACES
+	depends on EXPERIMENTAL && NAMESPACES
 	help
 	  Allow user space to create what appear to be multiple instances
 	  of the network stack.
 
+config COMPAT_NET_DEV_OPS
+       def_bool y
+
 source "net/packet/Kconfig"
 source "net/unix/Kconfig"
 source "net/xfrm/Kconfig"
@@ -191,6 +194,7 @@
 source "net/econet/Kconfig"
 source "net/wanrouter/Kconfig"
 source "net/sched/Kconfig"
+source "net/dcb/Kconfig"
 
 menu "Network testing"
 
@@ -247,7 +251,6 @@
 
 source "net/wireless/Kconfig"
 source "net/mac80211/Kconfig"
-source "net/ieee80211/Kconfig"
 
 endif # WIRELESS
 
diff --git a/net/Makefile b/net/Makefile
index 27d1f10..ba44604 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -51,12 +51,14 @@
 obj-$(CONFIG_IP_SCTP)		+= sctp/
 obj-y				+= wireless/
 obj-$(CONFIG_MAC80211)		+= mac80211/
-obj-$(CONFIG_IEEE80211)		+= ieee80211/
 obj-$(CONFIG_TIPC)		+= tipc/
 obj-$(CONFIG_NETLABEL)		+= netlabel/
 obj-$(CONFIG_IUCV)		+= iucv/
 obj-$(CONFIG_RFKILL)		+= rfkill/
 obj-$(CONFIG_NET_9P)		+= 9p/
+ifneq ($(CONFIG_DCB),)
+obj-y				+= dcb/
+endif
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c
index b25c1e9..b03ff58 100644
--- a/net/appletalk/aarp.c
+++ b/net/appletalk/aarp.c
@@ -995,7 +995,6 @@
 	struct aarp_iter_state *iter = seq->private;
 	struct aarp_entry *entry = v;
 	unsigned long now = jiffies;
-	DECLARE_MAC_BUF(mac);
 
 	if (v == SEQ_START_TOKEN)
 		seq_puts(seq,
@@ -1006,7 +1005,7 @@
 			   ntohs(entry->target_addr.s_net),
 			   (unsigned int) entry->target_addr.s_node,
 			   entry->dev ? entry->dev->name : "????");
-		seq_printf(seq, "%s", print_mac(mac, entry->hwaddr));
+		seq_printf(seq, "%pM", entry->hwaddr);
 		seq_printf(seq, " %8s",
 			   dt2str((long)entry->expires_at - (long)now));
 		if (iter->table == unresolved)
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index d3134e7..5abce07 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -815,9 +815,6 @@
 				return -EPERM;
 			if (sa->sat_family != AF_APPLETALK)
 				return -EINVAL;
-			if (!atif)
-				return -EADDRNOTAVAIL;
-
 			/*
 			 * for now, we only support proxy AARP on ELAP;
 			 * we should be able to do it for LocalTalk, too.
@@ -1284,7 +1281,7 @@
 	skb->dev   = dev;
 	skb_reset_transport_header(skb);
 
-	stats = dev->priv;
+	stats = netdev_priv(dev);
 	stats->rx_packets++;
 	stats->rx_bytes += skb->len + 13;
 	netif_rx(skb);  /* Send the SKB up to a higher place. */
diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c
index 621805d..8d237b1 100644
--- a/net/appletalk/sysctl_net_atalk.c
+++ b/net/appletalk/sysctl_net_atalk.c
@@ -17,8 +17,8 @@
 		.data		= &sysctl_aarp_expiry_time,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies,
 	},
 	{
 		.ctl_name	= NET_ATALK_AARP_TICK_TIME,
@@ -26,8 +26,8 @@
 		.data		= &sysctl_aarp_tick_time,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies,
 	},
 	{
 		.ctl_name	= NET_ATALK_AARP_RETRANSMIT_LIMIT,
@@ -35,7 +35,7 @@
 		.data		= &sysctl_aarp_retransmit_limit,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_ATALK_AARP_RESOLVE_TIME,
@@ -43,8 +43,8 @@
 		.data		= &sysctl_aarp_resolve_time,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies,
 	},
 	{ 0 },
 };
diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c
index 1b88311..b5674dc 100644
--- a/net/atm/atm_sysfs.c
+++ b/net/atm/atm_sysfs.c
@@ -149,7 +149,7 @@
 	cdev->class = &atm_class;
 	dev_set_drvdata(cdev, adev);
 
-	snprintf(cdev->bus_id, BUS_ID_SIZE, "%s%d", adev->type, adev->number);
+	dev_set_name(cdev, "%s%d", adev->type, adev->number);
 	err = device_register(cdev);
 	if (err < 0)
 		return err;
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 280de48..ea9438f 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -101,7 +101,7 @@
 
 static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev)
 {
-	return (struct br2684_dev *)net_dev->priv;
+	return (struct br2684_dev *)netdev_priv(net_dev);
 }
 
 static inline struct net_device *list_entry_brdev(const struct list_head *le)
@@ -698,12 +698,11 @@
 						    br2684_devs);
 	const struct net_device *net_dev = brdev->net_dev;
 	const struct br2684_vcc *brvcc;
-	DECLARE_MAC_BUF(mac);
 
-	seq_printf(seq, "dev %.16s: num=%d, mac=%s (%s)\n",
+	seq_printf(seq, "dev %.16s: num=%d, mac=%pM (%s)\n",
 		   net_dev->name,
 		   brdev->number,
-		   print_mac(mac, net_dev->dev_addr),
+		   net_dev->dev_addr,
 		   brdev->mac_was_set ? "set" : "auto");
 
 	list_for_each_entry(brvcc, &brdev->brvccs, brvccs) {
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 5b5b963..2d33a83 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -822,8 +822,8 @@
 	seq_printf(seq, "%-6s%-4s%-4s%5ld ",
 		   dev->name, svc ? "SVC" : "PVC", llc ? "LLC" : "NULL", exp);
 
-	off = scnprintf(buf, sizeof(buf) - 1, "%d.%d.%d.%d",
-			NIPQUAD(entry->ip));
+	off = scnprintf(buf, sizeof(buf) - 1, "%pI4",
+			&entry->ip);
 	while (off < 16)
 		buf[off++] = ' ';
 	buf[off] = '\0';
diff --git a/net/atm/common.h b/net/atm/common.h
index 16f32c1..92e2981 100644
--- a/net/atm/common.h
+++ b/net/atm/common.h
@@ -19,6 +19,7 @@
 		size_t total_len);
 unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait);
 int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
 int vcc_setsockopt(struct socket *sock, int level, int optname,
 		   char __user *optval, int optlen);
 int vcc_getsockopt(struct socket *sock, int level, int optname,
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
index 7afd8e7..76ed3c8 100644
--- a/net/atm/ioctl.c
+++ b/net/atm/ioctl.c
@@ -19,6 +19,7 @@
 #include <linux/atmlec.h>
 #include <linux/mutex.h>
 #include <asm/ioctls.h>
+#include <net/compat.h>
 
 #include "resources.h"
 #include "signaling.h"		/* for WAITING and sigd_attach */
@@ -46,7 +47,7 @@
 EXPORT_SYMBOL(register_atm_ioctl);
 EXPORT_SYMBOL(deregister_atm_ioctl);
 
-int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg, int compat)
 {
 	struct sock *sk = sock->sk;
 	struct atm_vcc *vcc;
@@ -80,13 +81,25 @@
 				goto done;
 			}
 		case SIOCGSTAMP: /* borrowed from IP */
-			error = sock_get_timestamp(sk, argp);
+#ifdef CONFIG_COMPAT
+			if (compat)
+				error = compat_sock_get_timestamp(sk, argp);
+			else
+#endif
+				error = sock_get_timestamp(sk, argp);
 			goto done;
 		case SIOCGSTAMPNS: /* borrowed from IP */
-			error = sock_get_timestampns(sk, argp);
+#ifdef CONFIG_COMPAT
+			if (compat)
+				error = compat_sock_get_timestampns(sk, argp);
+			else
+#endif
+				error = sock_get_timestampns(sk, argp);
 			goto done;
 		case ATM_SETSC:
-			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
+			if (net_ratelimit())
+				printk(KERN_WARNING "ATM_SETSC is obsolete; used by %s:%d\n",
+				       current->comm, task_pid_nr(current));
 			error = 0;
 			goto done;
 		case ATMSIGD_CTRL:
@@ -99,12 +112,23 @@
 			 * info uses kernel pointers as opaque references,
 			 * so the holder of the file descriptor can scribble
 			 * on the kernel... so we should make sure that we
-			 * have the same privledges that /proc/kcore needs
+			 * have the same privileges that /proc/kcore needs
 			 */
 			if (!capable(CAP_SYS_RAWIO)) {
 				error = -EPERM;
 				goto done;
 			}
+#ifdef CONFIG_COMPAT
+			/* WTF? I don't even want to _think_ about making this
+			   work for 32-bit userspace. TBH I don't really want
+			   to think about it at all. dwmw2. */
+			if (compat) {
+				if (net_ratelimit())
+					printk(KERN_WARNING "32-bit task cannot be atmsigd\n");
+				error = -EINVAL;
+				goto done;
+			}
+#endif
 			error = sigd_attach(vcc);
 			if (!error)
 				sock->state = SS_CONNECTED;
@@ -155,8 +179,21 @@
 	if (error != -ENOIOCTLCMD)
 		goto done;
 
-	error = atm_dev_ioctl(cmd, argp);
+	error = atm_dev_ioctl(cmd, argp, compat);
 
 done:
 	return error;
 }
+
+
+int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	return do_vcc_ioctl(sock, cmd, arg, 0);
+}
+
+#ifdef CONFIG_COMPAT
+int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	return do_vcc_ioctl(sock, cmd, arg, 1);
+}
+#endif
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 8f701cd..e5e3015 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -152,7 +152,7 @@
 		buff += 4;
 		mesg->content.normal.flag = *buff & 0x01;	/* 0x01 is topology change */
 
-		priv = (struct lec_priv *)dev->priv;
+		priv = netdev_priv(dev);
 		atm_force_charge(priv->lecd, skb2->truesize);
 		sk = sk_atm(priv->lecd);
 		skb_queue_tail(&sk->sk_receive_queue, skb2);
@@ -218,7 +218,7 @@
 
 static int lec_open(struct net_device *dev)
 {
-	struct lec_priv *priv = (struct lec_priv *)dev->priv;
+	struct lec_priv *priv = netdev_priv(dev);
 
 	netif_start_queue(dev);
 	memset(&priv->stats, 0, sizeof(struct net_device_stats));
@@ -252,7 +252,7 @@
 static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct sk_buff *skb2;
-	struct lec_priv *priv = (struct lec_priv *)dev->priv;
+	struct lec_priv *priv = netdev_priv(dev);
 	struct lecdatahdr_8023 *lec_h;
 	struct atm_vcc *vcc;
 	struct lec_arp_table *entry;
@@ -373,19 +373,13 @@
 		if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
 			pr_debug("%s:lec_start_xmit: queuing packet, ",
 				dev->name);
-			pr_debug("MAC address " MAC_FMT "\n",
-				 lec_h->h_dest[0], lec_h->h_dest[1],
-				 lec_h->h_dest[2], lec_h->h_dest[3],
-				 lec_h->h_dest[4], lec_h->h_dest[5]);
+			pr_debug("MAC address %pM\n", lec_h->h_dest);
 			skb_queue_tail(&entry->tx_wait, skb);
 		} else {
 			pr_debug
 			    ("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ",
 			     dev->name);
-			pr_debug("MAC address " MAC_FMT "\n",
-				 lec_h->h_dest[0], lec_h->h_dest[1],
-				 lec_h->h_dest[2], lec_h->h_dest[3],
-				 lec_h->h_dest[4], lec_h->h_dest[5]);
+			pr_debug("MAC address %pM\n", lec_h->h_dest);
 			priv->stats.tx_dropped++;
 			dev_kfree_skb(skb);
 		}
@@ -397,10 +391,7 @@
 
 	while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
 		pr_debug("lec.c: emptying tx queue, ");
-		pr_debug("MAC address " MAC_FMT "\n",
-			 lec_h->h_dest[0], lec_h->h_dest[1],
-			 lec_h->h_dest[2], lec_h->h_dest[3],
-			 lec_h->h_dest[4], lec_h->h_dest[5]);
+		pr_debug("MAC address %pM\n", lec_h->h_dest);
 		lec_send(vcc, skb2, priv);
 	}
 
@@ -442,14 +433,14 @@
  */
 static struct net_device_stats *lec_get_stats(struct net_device *dev)
 {
-	return &((struct lec_priv *)dev->priv)->stats;
+	return &((struct lec_priv *)netdev_priv(dev))->stats;
 }
 
 static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
 {
 	unsigned long flags;
 	struct net_device *dev = (struct net_device *)vcc->proto_data;
-	struct lec_priv *priv = (struct lec_priv *)dev->priv;
+	struct lec_priv *priv = netdev_priv(dev);
 	struct atmlec_msg *mesg;
 	struct lec_arp_table *entry;
 	int i;
@@ -539,15 +530,8 @@
 		{
 			struct net_bridge_fdb_entry *f;
 
-			pr_debug
-			    ("%s: bridge zeppelin asks about " MAC_FMT "\n",
-			     dev->name,
-			     mesg->content.proxy.mac_addr[0],
-			     mesg->content.proxy.mac_addr[1],
-			     mesg->content.proxy.mac_addr[2],
-			     mesg->content.proxy.mac_addr[3],
-			     mesg->content.proxy.mac_addr[4],
-			     mesg->content.proxy.mac_addr[5]);
+			pr_debug("%s: bridge zeppelin asks about %pM\n",
+				 dev->name, mesg->content.proxy.mac_addr);
 
 			if (br_fdb_get_hook == NULL || dev->br_port == NULL)
 				break;
@@ -596,7 +580,7 @@
 {
 	struct sk_buff *skb;
 	struct net_device *dev = (struct net_device *)vcc->proto_data;
-	struct lec_priv *priv = (struct lec_priv *)dev->priv;
+	struct lec_priv *priv = netdev_priv(dev);
 
 	priv->lecd = NULL;
 	/* Do something needful? */
@@ -727,7 +711,7 @@
 {
 	unsigned long flags;
 	struct net_device *dev = (struct net_device *)vcc->proto_data;
-	struct lec_priv *priv = (struct lec_priv *)dev->priv;
+	struct lec_priv *priv = netdev_priv(dev);
 
 #if DUMP_PACKETS >0
 	int i = 0;
@@ -874,7 +858,7 @@
 	vpriv->old_pop = vcc->pop;
 	vcc->user_back = vpriv;
 	vcc->pop = lec_pop;
-	lec_vcc_added(dev_lec[ioc_data.dev_num]->priv,
+	lec_vcc_added(netdev_priv(dev_lec[ioc_data.dev_num]),
 		      &ioc_data, vcc, vcc->push);
 	vcc->proto_data = dev_lec[ioc_data.dev_num];
 	vcc->push = lec_push;
@@ -886,7 +870,8 @@
 	if (arg < 0 || arg >= MAX_LEC_ITF || !dev_lec[arg])
 		return -EINVAL;
 	vcc->proto_data = dev_lec[arg];
-	return (lec_mcast_make((struct lec_priv *)dev_lec[arg]->priv, vcc));
+	return lec_mcast_make((struct lec_priv *)netdev_priv(dev_lec[arg]),
+				vcc);
 }
 
 /* Initialize device. */
@@ -928,11 +913,11 @@
 			return -EINVAL;
 		}
 
-		priv = dev_lec[i]->priv;
+		priv = netdev_priv(dev_lec[i]);
 		priv->is_trdev = is_trdev;
 		lec_init(dev_lec[i]);
 	} else {
-		priv = dev_lec[i]->priv;
+		priv = netdev_priv(dev_lec[i]);
 		if (priv->lecd)
 			return -EADDRINUSE;
 	}
@@ -1093,7 +1078,8 @@
 	void *v;
 
 	dev = state->dev ? state->dev : dev_lec[state->itf];
-	v = (dev && dev->priv) ? lec_priv_walk(state, l, dev->priv) : NULL;
+	v = (dev && netdev_priv(dev)) ?
+		lec_priv_walk(state, l, netdev_priv(dev)) : NULL;
 	if (!v && dev) {
 		dev_put(dev);
 		/* Partial state reset for the next time we get called */
@@ -1255,7 +1241,7 @@
 
 	for (i = 0; i < MAX_LEC_ITF; i++) {
 		if (dev_lec[i] != NULL) {
-			priv = (struct lec_priv *)dev_lec[i]->priv;
+			priv = netdev_priv(dev_lec[i]);
 			unregister_netdev(dev_lec[i]);
 			free_netdev(dev_lec[i]);
 			dev_lec[i] = NULL;
@@ -1279,7 +1265,7 @@
 			 u8 **tlvs, u32 *sizeoftlvs)
 {
 	unsigned long flags;
-	struct lec_priv *priv = (struct lec_priv *)dev->priv;
+	struct lec_priv *priv = netdev_priv(dev);
 	struct lec_arp_table *table;
 	struct sk_buff *skb;
 	int retval;
@@ -1326,7 +1312,7 @@
 {
 	int retval;
 	struct sk_buff *skb;
-	struct lec_priv *priv = (struct lec_priv *)dev->priv;
+	struct lec_priv *priv = netdev_priv(dev);
 
 	if (compare_ether_addr(lan_dst, dev->dev_addr))
 		return (0);	/* not our mac address */
@@ -1363,7 +1349,7 @@
 #if 0
 	int i = 0;
 #endif
-	struct lec_priv *priv = (struct lec_priv *)dev->priv;
+	struct lec_priv *priv = netdev_priv(dev);
 #if 0				/*
 				 * Why have the TLVs in LE_ARP entries
 				 * since we do not use them? When you
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index 11b16d1..039d5cc 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -232,8 +232,8 @@
 	seq_printf(m, "IP address\n  TX:max_pcr pcr     min_pcr max_cdv max_sdu\n  RX:max_pcr pcr     min_pcr max_cdv max_sdu\n");
 
 	while (qos != NULL) {
-		seq_printf(m, "%u.%u.%u.%u\n     %-7d %-7d %-7d %-7d %-7d\n     %-7d %-7d %-7d %-7d %-7d\n",
-				NIPQUAD(qos->ipaddr),
+		seq_printf(m, "%pI4\n     %-7d %-7d %-7d %-7d %-7d\n     %-7d %-7d %-7d %-7d %-7d\n",
+				&qos->ipaddr,
 				qos->qos.txtp.max_pcr, qos->qos.txtp.pcr, qos->qos.txtp.min_pcr, qos->qos.txtp.max_cdv, qos->qos.txtp.max_sdu,
 				qos->qos.rxtp.max_pcr, qos->qos.rxtp.pcr, qos->qos.rxtp.min_pcr, qos->qos.rxtp.max_cdv, qos->qos.rxtp.max_sdu);
 		qos = qos->next;
@@ -341,8 +341,8 @@
 }
 
 /*
- * lec device calls this via its dev->priv->lane2_ops->associate_indicator()
- * when it sees a TLV in LE_ARP packet.
+ * lec device calls this via its netdev_priv(dev)->lane2_ops
+ * ->associate_indicator() when it sees a TLV in LE_ARP packet.
  * We fill in the pointer above when we see a LANE2 lec initializing
  * See LANE2 spec 3.1.5
  *
@@ -595,8 +595,8 @@
 			if (in_entry != NULL) mpc->in_ops->put(in_entry);
 			return -EINVAL;
 		}
-		printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %u.%u.%u.%u\n",
-		       mpc->dev->name, NIPQUAD(in_entry->ctrl_info.in_dst_ip));
+		printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %pI4\n",
+		       mpc->dev->name, &in_entry->ctrl_info.in_dst_ip);
 		in_entry->shortcut = vcc;
 		mpc->in_ops->put(in_entry);
 	} else {
@@ -627,8 +627,8 @@
 	dprintk("mpoa: (%s) mpc_vcc_close:\n", dev->name);
 	in_entry = mpc->in_ops->get_by_vcc(vcc, mpc);
 	if (in_entry) {
-		dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %u.%u.%u.%u\n",
-		       mpc->dev->name, NIPQUAD(in_entry->ctrl_info.in_dst_ip));
+		dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %pI4\n",
+		       mpc->dev->name, &in_entry->ctrl_info.in_dst_ip);
 		in_entry->shortcut = NULL;
 		mpc->in_ops->put(in_entry);
 	}
@@ -785,7 +785,7 @@
 	}
 
 	if (mpc->dev) { /* check if the lec is LANE2 capable */
-		priv = (struct lec_priv *)mpc->dev->priv;
+		priv = netdev_priv(mpc->dev);
 		if (priv->lane_version < 2) {
 			dev_put(mpc->dev);
 			mpc->dev = NULL;
@@ -845,7 +845,7 @@
 
 	mpc->mpoad_vcc = NULL;
 	if (mpc->dev) {
-		struct lec_priv *priv = (struct lec_priv *)mpc->dev->priv;
+		struct lec_priv *priv = netdev_priv(mpc->dev);
 		priv->lane2_ops->associate_indicator = NULL;
 		stop_mpc(mpc);
 		dev_put(mpc->dev);
@@ -976,7 +976,7 @@
 
 	switch (event) {
 	case NETDEV_REGISTER:       /* a new lec device was allocated */
-		priv = (struct lec_priv *)dev->priv;
+		priv = netdev_priv(dev);
 		if (priv->lane_version < 2)
 			break;
 		priv->lane2_ops->associate_indicator = lane2_assoc_ind;
@@ -1098,7 +1098,8 @@
 				    entry->shortcut = eg_entry->shortcut;
 		}
 		if(entry->shortcut){
-			dprintk("mpoa: (%s) using egress SVC to reach %u.%u.%u.%u\n",client->dev->name, NIPQUAD(dst_ip));
+			dprintk("mpoa: (%s) using egress SVC to reach %pI4\n",
+				client->dev->name, &dst_ip);
 			client->eg_ops->put(eg_entry);
 			return;
 		}
@@ -1123,7 +1124,8 @@
 	__be32 dst_ip = msg->content.in_info.in_dst_ip;
 	in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc);
 
-	dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(dst_ip));
+	dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %pI4\n",
+		mpc->dev->name, &dst_ip);
 	ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", mpc->dev->name, entry);
 	if(entry == NULL){
 		printk("\nmpoa: (%s) ARGH, received res. reply for an entry that doesn't exist.\n", mpc->dev->name);
@@ -1171,14 +1173,14 @@
 	in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask);
 
 	if(entry == NULL){
-		printk("mpoa: (%s) ingress_purge_rcvd: purge for a non-existing entry, ", mpc->dev->name);
-		printk("ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip));
+		printk("mpoa: (%s) ingress_purge_rcvd: purge for a non-existing entry, ip = %pI4\n",
+		       mpc->dev->name, &dst_ip);
 		return;
 	}
 
 	do {
-		dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %u.%u.%u.%u\n" ,
-			mpc->dev->name, NIPQUAD(dst_ip));
+		dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %pI4\n",
+			mpc->dev->name, &dst_ip);
 		write_lock_bh(&mpc->ingress_lock);
 		mpc->in_ops->remove_entry(entry, mpc);
 		write_unlock_bh(&mpc->ingress_lock);
@@ -1322,7 +1324,7 @@
 	dprintk("\n");
 
 	if (mpc->dev) {
-		priv = (struct lec_priv *)mpc->dev->priv;
+		priv = netdev_priv(mpc->dev);
 		retval = priv->lane2_ops->associate_req(mpc->dev, mpc->dev->dev_addr, tlv, sizeof(tlv));
 		if (retval == 0)
 			printk("mpoa: (%s) MPOA device type TLV association failed\n", mpc->dev->name);
@@ -1472,7 +1474,7 @@
 		tmp = mpc->next;
 		if (mpc->dev != NULL) {
 			stop_mpc(mpc);
-			priv = (struct lec_priv *)mpc->dev->priv;
+			priv = netdev_priv(mpc->dev);
 			if (priv->lane2_ops != NULL)
 				priv->lane2_ops->associate_indicator = NULL;
 		}
diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c
index 24799e3..4504a4b 100644
--- a/net/atm/mpoa_caches.c
+++ b/net/atm/mpoa_caches.c
@@ -94,7 +94,7 @@
 		return NULL;
 	}
 
-	dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip));
+	dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %pI4\n", &dst_ip);
 
 	atomic_set(&entry->use, 1);
 	dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lock\n");
@@ -150,7 +150,8 @@
 
 	if( entry->count > mpc->parameters.mpc_p1 &&
 	    entry->entry_state == INGRESS_INVALID){
-		dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, NIPQUAD(entry->ctrl_info.in_dst_ip));
+		dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %pI4, sending MPOA res req\n",
+			mpc->dev->name, &entry->ctrl_info.in_dst_ip);
 		entry->entry_state = INGRESS_RESOLVING;
 		msg.type =  SND_MPOA_RES_RQST;
 		memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN );
@@ -184,7 +185,8 @@
 	struct k_message msg;
 
 	vcc = entry->shortcut;
-	dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",NIPQUAD(entry->ctrl_info.in_dst_ip));
+	dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %pI4\n",
+		&entry->ctrl_info.in_dst_ip);
 
 	if (entry->prev != NULL)
 		entry->prev->next = entry->next;
@@ -228,7 +230,8 @@
 		next_entry = entry->next;
 		if((now.tv_sec - entry->tv.tv_sec)
 		   > entry->ctrl_info.holding_time){
-			dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %u.%u.%u.%u\n", NIPQUAD(entry->ctrl_info.in_dst_ip));
+			dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %pI4\n",
+				&entry->ctrl_info.in_dst_ip);
 			client->in_ops->remove_entry(entry, client);
 		}
 		entry = next_entry;
@@ -453,7 +456,8 @@
 		return NULL;
 	}
 
-	dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %u.%u.%u.%u, this should be our IP\n", NIPQUAD(msg->content.eg_info.eg_dst_ip));
+	dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %pI4, this should be our IP\n",
+		&msg->content.eg_info.eg_dst_ip);
 
 	atomic_set(&entry->use, 1);
 	dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lock\n");
@@ -469,8 +473,8 @@
 	do_gettimeofday(&(entry->tv));
 	entry->entry_state = EGRESS_RESOLVED;
 	dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id));
-	dprintk("mpoa: mpoa_caches.c: mps_ip = %u.%u.%u.%u\n",
-		NIPQUAD(entry->ctrl_info.mps_ip));
+	dprintk("mpoa: mpoa_caches.c: mps_ip = %pI4\n",
+		&entry->ctrl_info.mps_ip);
 	atomic_inc(&entry->use);
 
 	write_unlock_irq(&client->egress_lock);
diff --git a/net/atm/pvc.c b/net/atm/pvc.c
index 43e8bf5..e1d22d9 100644
--- a/net/atm/pvc.c
+++ b/net/atm/pvc.c
@@ -113,6 +113,9 @@
 	.getname =	pvc_getname,
 	.poll =		vcc_poll,
 	.ioctl =	vcc_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = vcc_compat_ioctl,
+#endif
 	.listen =	sock_no_listen,
 	.shutdown =	pvc_shutdown,
 	.setsockopt =	pvc_setsockopt,
diff --git a/net/atm/resources.c b/net/atm/resources.c
index a34ba94..56b7322 100644
--- a/net/atm/resources.c
+++ b/net/atm/resources.c
@@ -195,20 +195,39 @@
 }
 
 
-int atm_dev_ioctl(unsigned int cmd, void __user *arg)
+int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)
 {
 	void __user *buf;
 	int error, len, number, size = 0;
 	struct atm_dev *dev;
 	struct list_head *p;
 	int *tmp_buf, *tmp_p;
-	struct atm_iobuf __user *iobuf = arg;
-	struct atmif_sioc __user *sioc = arg;
+	int __user *sioc_len;
+	int __user *iobuf_len;
+
+#ifndef CONFIG_COMPAT
+	compat = 0; /* Just so the compiler _knows_ */
+#endif
+
 	switch (cmd) {
 		case ATM_GETNAMES:
-			if (get_user(buf, &iobuf->buffer))
-				return -EFAULT;
-			if (get_user(len, &iobuf->length))
+
+			if (compat) {
+#ifdef CONFIG_COMPAT
+				struct compat_atm_iobuf __user *ciobuf = arg;
+				compat_uptr_t cbuf;
+				iobuf_len = &ciobuf->length;
+				if (get_user(cbuf, &ciobuf->buffer))
+					return -EFAULT;
+				buf = compat_ptr(cbuf);
+#endif
+			} else {
+				struct atm_iobuf __user *iobuf = arg;
+				iobuf_len = &iobuf->length;
+				if (get_user(buf, &iobuf->buffer))
+					return -EFAULT;
+			}
+			if (get_user(len, iobuf_len))
 				return -EFAULT;
 			mutex_lock(&atm_dev_mutex);
 			list_for_each(p, &atm_devs)
@@ -229,7 +248,7 @@
 			}
 			mutex_unlock(&atm_dev_mutex);
 			error = ((copy_to_user(buf, tmp_buf, size)) ||
-					put_user(size, &iobuf->length))
+					put_user(size, iobuf_len))
 						? -EFAULT : 0;
 			kfree(tmp_buf);
 			return error;
@@ -237,13 +256,32 @@
 			break;
 	}
 
-	if (get_user(buf, &sioc->arg))
-		return -EFAULT;
-	if (get_user(len, &sioc->length))
-		return -EFAULT;
-	if (get_user(number, &sioc->number))
-		return -EFAULT;
+	if (compat) {
+#ifdef CONFIG_COMPAT
+		struct compat_atmif_sioc __user *csioc = arg;
+		compat_uptr_t carg;
 
+		sioc_len = &csioc->length;
+		if (get_user(carg, &csioc->arg))
+			return -EFAULT;
+		buf = compat_ptr(carg);
+
+		if (get_user(len, &csioc->length))
+			return -EFAULT;
+		if (get_user(number, &csioc->number))
+			return -EFAULT;
+#endif
+	} else {
+		struct atmif_sioc __user *sioc = arg;
+
+		sioc_len = &sioc->length;
+		if (get_user(buf, &sioc->arg))
+			return -EFAULT;
+		if (get_user(len, &sioc->length))
+			return -EFAULT;
+		if (get_user(number, &sioc->number))
+			return -EFAULT;
+	}
 	if (!(dev = try_then_request_module(atm_dev_lookup(number),
 					    "atm-device-%d", number)))
 		return -ENODEV;
@@ -358,7 +396,7 @@
 			size = error;
 			/* may return 0, but later on size == 0 means "don't
 			   write the length" */
-			error = put_user(size, &sioc->length)
+			error = put_user(size, sioc_len)
 				? -EFAULT : 0;
 			goto done;
 		case ATM_SETLOOP:
@@ -380,11 +418,21 @@
 			}
 			/* fall through */
 		default:
-			if (!dev->ops->ioctl) {
-				error = -EINVAL;
-				goto done;
+			if (compat) {
+#ifdef CONFIG_COMPAT
+				if (!dev->ops->compat_ioctl) {
+					error = -EINVAL;
+					goto done;
+				}
+				size = dev->ops->compat_ioctl(dev, cmd, buf);
+#endif
+			} else {
+				if (!dev->ops->ioctl) {
+					error = -EINVAL;
+					goto done;
+				}
+				size = dev->ops->ioctl(dev, cmd, buf);
 			}
-			size = dev->ops->ioctl(dev, cmd, buf);
 			if (size < 0) {
 				error = (size == -ENOIOCTLCMD ? -EINVAL : size);
 				goto done;
@@ -392,7 +440,7 @@
 	}
 
 	if (size)
-		error = put_user(size, &sioc->length)
+		error = put_user(size, sioc_len)
 			? -EFAULT : 0;
 	else
 		error = 0;
diff --git a/net/atm/resources.h b/net/atm/resources.h
index 1d004aa..126fb18 100644
--- a/net/atm/resources.h
+++ b/net/atm/resources.h
@@ -13,7 +13,7 @@
 extern struct list_head atm_devs;
 extern struct mutex atm_dev_mutex;
 
-int atm_dev_ioctl(unsigned int cmd, void __user *arg);
+int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat);
 
 
 #ifdef CONFIG_PROC_FS
diff --git a/net/atm/svc.c b/net/atm/svc.c
index 8fb54dc..7b831b5 100644
--- a/net/atm/svc.c
+++ b/net/atm/svc.c
@@ -608,6 +608,22 @@
 	return error;
 }
 
+#ifdef CONFIG_COMPAT
+static int svc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	/* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf.
+	   But actually it takes a struct sockaddr_atmsvc, which doesn't need
+	   compat handling. So all we have to do is fix up cmd... */
+	if (cmd == COMPAT_ATM_ADDPARTY)
+		cmd = ATM_ADDPARTY;
+
+	if (cmd == ATM_ADDPARTY || cmd == ATM_DROPPARTY)
+		return svc_ioctl(sock, cmd, arg);
+	else
+		return vcc_compat_ioctl(sock, cmd, arg);
+}
+#endif /* CONFIG_COMPAT */
+
 static const struct proto_ops svc_proto_ops = {
 	.family =	PF_ATMSVC,
 	.owner =	THIS_MODULE,
@@ -620,6 +636,9 @@
 	.getname =	svc_getname,
 	.poll =		vcc_poll,
 	.ioctl =	svc_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl =	svc_compat_ioctl,
+#endif
 	.listen =	svc_listen,
 	.shutdown =	svc_shutdown,
 	.setsockopt =	svc_setsockopt,
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 28c7157..00d9e5e 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1045,7 +1045,7 @@
 	if (addr->fsa_ax25.sax25_family != AF_AX25)
 		return -EINVAL;
 
-	user = ax25_findbyuid(current->euid);
+	user = ax25_findbyuid(current_euid());
 	if (user) {
 		call = user->call;
 		ax25_uid_put(user);
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
index 4a5ba97..5f1d210 100644
--- a/net/ax25/ax25_in.c
+++ b/net/ax25/ax25_in.c
@@ -200,19 +200,15 @@
 
 	skb_reset_transport_header(skb);
 
-	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
-		kfree_skb(skb);
-		return 0;
-	}
+	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
+		goto free;
 
 	/*
 	 *	Parse the address header.
 	 */
 
-	if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) {
-		kfree_skb(skb);
-		return 0;
-	}
+	if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL)
+		goto free;
 
 	/*
 	 *	Ours perhaps ?
@@ -239,10 +235,8 @@
 
 		ax25_send_to_raw(&dest, skb, skb->data[1]);
 
-		if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) {
-			kfree_skb(skb);
-			return 0;
-		}
+		if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0)
+			goto free;
 
 		/* Now we are pointing at the pid byte */
 		switch (skb->data[1]) {
@@ -301,10 +295,8 @@
 	 *	If not, should we DM the incoming frame (except DMs) or
 	 *	silently ignore them. For now we stay quiet.
 	 */
-	if (ax25_dev->values[AX25_VALUES_CONMODE] == 0) {
-		kfree_skb(skb);
-		return 0;
-	}
+	if (ax25_dev->values[AX25_VALUES_CONMODE] == 0)
+		goto free;
 
 	/* LAPB */
 
@@ -339,8 +331,7 @@
 		if ((*skb->data & ~AX25_PF) != AX25_DM && mine)
 			ax25_return_dm(dev, &src, &dest, &dp);
 
-		kfree_skb(skb);
-		return 0;
+		goto free;
 	}
 
 	/* b) received SABM(E) */
@@ -372,15 +363,12 @@
 		sk->sk_ack_backlog++;
 		bh_unlock_sock(sk);
 	} else {
-		if (!mine) {
-			kfree_skb(skb);
-			return 0;
-		}
+		if (!mine)
+			goto free;
 
 		if ((ax25 = ax25_create_cb()) == NULL) {
 			ax25_return_dm(dev, &src, &dest, &dp);
-			kfree_skb(skb);
-			return 0;
+			goto free;
 		}
 
 		ax25_fillin_cb(ax25, ax25_dev);
@@ -436,9 +424,10 @@
 		if (!sock_flag(sk, SOCK_DEAD))
 			sk->sk_data_ready(sk, skb->len);
 		sock_put(sk);
-	} else
+	} else {
+free:
 		kfree_skb(skb);
-
+	}
 	return 0;
 }
 
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 8672cd8..c833ba4 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -421,7 +421,7 @@
 		goto put;
 	}
 
-	user = ax25_findbyuid(current->euid);
+	user = ax25_findbyuid(current_euid());
 	if (user) {
 		ax25->source_addr = user->call;
 		ax25_uid_put(user);
diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c
index f288fc4..62ee3fb 100644
--- a/net/ax25/sysctl_net_ax25.c
+++ b/net/ax25/sysctl_net_ax25.c
@@ -24,7 +24,9 @@
 static int min_n2[] = {1},		max_n2[] = {31};
 static int min_paclen[] = {1},		max_paclen[] = {512};
 static int min_proto[1],		max_proto[] = { AX25_PROTO_MAX };
+#ifdef CONFIG_AX25_DAMA_SLAVE
 static int min_ds_timeout[1],		max_ds_timeout[] = {65535000};
+#endif
 
 static struct ctl_table_header *ax25_table_header;
 
@@ -43,8 +45,8 @@
 		.procname	= "ip_default_mode",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_ipdefmode,
 		.extra2		= &max_ipdefmode
 	},
@@ -53,8 +55,8 @@
 		.procname	= "ax25_default_mode",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_axdefmode,
 		.extra2		= &max_axdefmode
 	},
@@ -63,8 +65,8 @@
 		.procname	= "backoff_type",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_backoff,
 		.extra2		= &max_backoff
 	},
@@ -73,8 +75,8 @@
 		.procname	= "connect_mode",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_conmode,
 		.extra2		= &max_conmode
 	},
@@ -83,8 +85,8 @@
 		.procname	= "standard_window_size",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_window,
 		.extra2		= &max_window
 	},
@@ -93,8 +95,8 @@
 		.procname	= "extended_window_size",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_ewindow,
 		.extra2		= &max_ewindow
 	},
@@ -103,8 +105,8 @@
 		.procname	= "t1_timeout",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_t1,
 		.extra2		= &max_t1
 	},
@@ -113,8 +115,8 @@
 		.procname	= "t2_timeout",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_t2,
 		.extra2		= &max_t2
 	},
@@ -123,8 +125,8 @@
 		.procname	= "t3_timeout",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_t3,
 		.extra2		= &max_t3
 	},
@@ -133,8 +135,8 @@
 		.procname	= "idle_timeout",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_idle,
 		.extra2		= &max_idle
 	},
@@ -143,8 +145,8 @@
 		.procname	= "maximum_retry_count",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_n2,
 		.extra2		= &max_n2
 	},
@@ -153,8 +155,8 @@
 		.procname	= "maximum_packet_length",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_paclen,
 		.extra2		= &max_paclen
 	},
@@ -163,8 +165,8 @@
 		.procname	= "protocol",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_proto,
 		.extra2		= &max_proto
 	},
@@ -174,8 +176,8 @@
 		.procname	= "dama_slave_timeout",
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_ds_timeout,
 		.extra2		= &max_ds_timeout
 	},
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 8f9431a..744ed3f 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -41,18 +41,14 @@
 
 #include <net/bluetooth/bluetooth.h>
 
-#ifndef CONFIG_BT_SOCK_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
-#define VERSION "2.13"
+#define VERSION "2.14"
 
 /* Bluetooth sockets */
 #define BT_MAX_PROTO	8
 static struct net_proto_family *bt_proto[BT_MAX_PROTO];
+static DEFINE_RWLOCK(bt_proto_lock);
 
-static struct lock_class_key bt_slock_key[BT_MAX_PROTO];
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key bt_lock_key[BT_MAX_PROTO];
 static const char *bt_key_strings[BT_MAX_PROTO] = {
 	"sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP",
@@ -65,6 +61,7 @@
 	"sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP",
 };
 
+static struct lock_class_key bt_slock_key[BT_MAX_PROTO];
 static const char *bt_slock_key_strings[BT_MAX_PROTO] = {
 	"slock-AF_BLUETOOTH-BTPROTO_L2CAP",
 	"slock-AF_BLUETOOTH-BTPROTO_HCI",
@@ -75,7 +72,25 @@
 	"slock-AF_BLUETOOTH-BTPROTO_HIDP",
 	"slock-AF_BLUETOOTH-BTPROTO_AVDTP",
 };
-static DEFINE_RWLOCK(bt_proto_lock);
+
+static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
+{
+	struct sock *sk = sock->sk;
+
+	if (!sk)
+		return;
+
+	BUG_ON(sock_owned_by_user(sk));
+
+	sock_lock_init_class_and_name(sk,
+			bt_slock_key_strings[proto], &bt_slock_key[proto],
+				bt_key_strings[proto], &bt_lock_key[proto]);
+}
+#else
+static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
+{
+}
+#endif
 
 int bt_sock_register(int proto, struct net_proto_family *ops)
 {
@@ -117,21 +132,6 @@
 }
 EXPORT_SYMBOL(bt_sock_unregister);
 
-static void bt_reclassify_sock_lock(struct socket *sock, int proto)
-{
-	struct sock *sk = sock->sk;
-
-	if (!sk)
-		return;
-	BUG_ON(sock_owned_by_user(sk));
-
-	sock_lock_init_class_and_name(sk,
-			bt_slock_key_strings[proto],
-			&bt_slock_key[proto],
-			bt_key_strings[proto],
-			&bt_lock_key[proto]);
-}
-
 static int bt_sock_create(struct net *net, struct socket *sock, int proto)
 {
 	int err;
@@ -151,7 +151,7 @@
 
 	if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
 		err = bt_proto[proto]->create(net, sock, proto);
-		bt_reclassify_sock_lock(sock, proto);
+		bt_sock_reclassify_lock(sock, proto);
 		module_put(bt_proto[proto]->owner);
 	}
 
@@ -240,7 +240,7 @@
 	size_t copied;
 	int err;
 
-	BT_DBG("sock %p sk %p len %d", sock, sk, len);
+	BT_DBG("sock %p sk %p len %zu", sock, sk, len);
 
 	if (flags & (MSG_OOB))
 		return -EOPNOTSUPP;
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index b69bf4e..d20f8a4 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -161,7 +161,7 @@
 	struct msghdr msg;
 
 	struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS];
-	u64    mc_filter;
+	unsigned long long mc_filter;
 
 	struct socket    *sock;
 	struct net_device *dev;
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 80ba30c..70fea8b 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -52,11 +52,6 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BT_BNEP_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define VERSION "1.3"
 
 static int compress_src = 1;
@@ -311,7 +306,6 @@
 	struct sk_buff *nskb;
 	u8 type;
 
-	dev->last_rx = jiffies;
 	s->stats.rx_bytes += skb->len;
 
 	type = *(u8 *) skb->data; skb_pull(skb, 1);
@@ -566,7 +560,7 @@
 		goto failed;
 	}
 
-	s = dev->priv;
+	s = netdev_priv(dev);
 
 	/* This is rx header therefore addresses are swapped.
 	 * ie eh.h_dest is our local address. */
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
index d9fa0ab..f897da6 100644
--- a/net/bluetooth/bnep/netdev.c
+++ b/net/bluetooth/bnep/netdev.c
@@ -41,11 +41,6 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BT_BNEP_DEBUG
-#undef  BT_DBG
-#define BT_DBG( A... )
-#endif
-
 #define BNEP_TX_QUEUE_LEN 20
 
 static int bnep_net_open(struct net_device *dev)
@@ -62,14 +57,14 @@
 
 static struct net_device_stats *bnep_net_get_stats(struct net_device *dev)
 {
-	struct bnep_session *s = dev->priv;
+	struct bnep_session *s = netdev_priv(dev);
 	return &s->stats;
 }
 
 static void bnep_net_set_mc_list(struct net_device *dev)
 {
 #ifdef CONFIG_BT_BNEP_MC_FILTER
-	struct bnep_session *s = dev->priv;
+	struct bnep_session *s = netdev_priv(dev);
 	struct sock *sk = s->sock->sk;
 	struct bnep_set_filter_req *r;
 	struct sk_buff *skb;
@@ -183,7 +178,7 @@
 
 static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct bnep_session *s = dev->priv;
+	struct bnep_session *s = netdev_priv(dev);
 	struct sock *sk = s->sock->sk;
 
 	BT_DBG("skb %p, dev %p", skb, dev);
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index 8ffb57f..e857628 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -46,11 +46,6 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BT_BNEP_DEBUG
-#undef  BT_DBG
-#define BT_DBG( A... )
-#endif
-
 static int bnep_sock_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c
index 3e9d5bb..78958c0 100644
--- a/net/bluetooth/cmtp/capi.c
+++ b/net/bluetooth/cmtp/capi.c
@@ -42,11 +42,6 @@
 
 #include "cmtp.h"
 
-#ifndef CONFIG_BT_CMTP_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define CAPI_INTEROPERABILITY		0x20
 
 #define CAPI_INTEROPERABILITY_REQ	CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index ca60a45..c9cac77 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -44,11 +44,6 @@
 
 #include "cmtp.h"
 
-#ifndef CONFIG_BT_CMTP_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define VERSION "1.0"
 
 static DECLARE_RWSEM(cmtp_session_sem);
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
index 8c7f7bc..16b0fad 100644
--- a/net/bluetooth/cmtp/sock.c
+++ b/net/bluetooth/cmtp/sock.c
@@ -43,11 +43,6 @@
 
 #include "cmtp.h"
 
-#ifndef CONFIG_BT_CMTP_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 static int cmtp_sock_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index b700242..a4a789f 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -45,11 +45,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef CONFIG_BT_HCI_CORE_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 void hci_acl_connect(struct hci_conn *conn)
 {
 	struct hci_dev *hdev = conn->hdev;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 278a3ac..ba78cc1 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -48,11 +48,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef CONFIG_BT_HCI_CORE_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 static void hci_cmd_task(unsigned long arg);
 static void hci_rx_task(unsigned long arg);
 static void hci_tx_task(unsigned long arg);
@@ -205,7 +200,7 @@
 	/* Mandatory initialization */
 
 	/* Reset */
-	if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks))
+	if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks))
 			hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
 
 	/* Read Local Supported Features */
@@ -290,7 +285,7 @@
 {
 	__le16 policy = cpu_to_le16(opt);
 
-	BT_DBG("%s %x", hdev->name, opt);
+	BT_DBG("%s %x", hdev->name, policy);
 
 	/* Default link policy */
 	hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
@@ -756,7 +751,7 @@
 
 	size = sizeof(*dl) + dev_num * sizeof(*dr);
 
-	if (!(dl = kmalloc(size, GFP_KERNEL)))
+	if (!(dl = kzalloc(size, GFP_KERNEL)))
 		return -ENOMEM;
 
 	dr = dl->dev_req;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index ad7a553..f91ba69 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -45,11 +45,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef CONFIG_BT_HCI_CORE_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 /* Handle HCI Event packets */
 
 static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index d62579b..4f9621f 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -49,11 +49,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef CONFIG_BT_HCI_SOCK_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 /* ----- HCI socket interface ----- */
 
 static inline int hci_test_bit(int nr, void *addr)
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index f4f6615..1a1f916 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -6,11 +6,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef CONFIG_BT_HCI_CORE_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 struct class *bt_class = NULL;
 EXPORT_SYMBOL_GPL(bt_class);
 
@@ -113,8 +108,7 @@
 	conn->dev.class = bt_class;
 	conn->dev.parent = &hdev->dev;
 
-	snprintf(conn->dev.bus_id, BUS_ID_SIZE, "%s:%d",
-					hdev->name, conn->handle);
+	dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
 
 	dev_set_drvdata(&conn->dev, conn);
 
@@ -132,7 +126,7 @@
  */
 static int __match_tty(struct device *dev, void *data)
 {
-	return !strncmp(dev->bus_id, "rfcomm", 6);
+	return !strncmp(dev_name(dev), "rfcomm", 6);
 }
 
 static void del_conn(struct work_struct *work)
@@ -421,7 +415,7 @@
 	dev->class = bt_class;
 	dev->parent = hdev->parent;
 
-	strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE);
+	dev_set_name(dev, "%s", hdev->name);
 
 	dev_set_drvdata(dev, hdev);
 
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index acdeab3..b186768 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -47,11 +47,6 @@
 
 #include "hidp.h"
 
-#ifndef CONFIG_BT_HIDP_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define VERSION "1.2"
 
 static DECLARE_RWSEM(hidp_session_sem);
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index f4dd02c..37c9d7d 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -39,11 +39,6 @@
 
 #include "hidp.h"
 
-#ifndef CONFIG_BT_HIDP_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 static int hidp_sock_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 9610a9c..b93748e 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -50,11 +50,6 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 
-#ifndef CONFIG_BT_L2CAP_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define VERSION "2.11"
 
 static u32 l2cap_feat_mask = 0x0000;
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index ba537fa..acd84fd 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -46,11 +46,6 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/rfcomm.h>
 
-#ifndef CONFIG_BT_RFCOMM_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define VERSION "1.10"
 
 static int disable_cfc = 0;
@@ -1786,8 +1781,6 @@
 	if (err < 0)
 		return;
 
-	__module_get(nsock->ops->owner);
-
 	/* Set our callbacks */
 	nsock->sk->sk_data_ready   = rfcomm_l2data_ready;
 	nsock->sk->sk_state_change = rfcomm_l2state_change;
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 8a972b6..d3fc6fc 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -50,11 +50,6 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/rfcomm.h>
 
-#ifndef CONFIG_BT_RFCOMM_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 static const struct proto_ops rfcomm_sock_ops;
 
 static struct bt_sock_list rfcomm_sk_list = {
@@ -644,7 +639,7 @@
 
 	msg->msg_namelen = 0;
 
-	BT_DBG("sk %p size %d", sk, size);
+	BT_DBG("sk %p size %zu", sk, size);
 
 	lock_sock(sk);
 
@@ -792,7 +787,7 @@
 
 static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
-	struct sock *sk = sock->sk;
+	struct sock *sk __maybe_unused = sock->sk;
 	int err;
 
 	BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index d3340dd..d030c69 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -39,11 +39,6 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/rfcomm.h>
 
-#ifndef CONFIG_BT_RFCOMM_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define RFCOMM_TTY_MAGIC 0x6d02		/* magic number for rfcomm struct */
 #define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV	/* whole lotta rfcomm devices */
 #define RFCOMM_TTY_MAJOR 216		/* device node major id of the usb/bluetooth.c driver */
@@ -58,7 +53,7 @@
 	char			name[12];
 	int			id;
 	unsigned long		flags;
-	int			opened;
+	atomic_t		opened;
 	int			err;
 
 	bdaddr_t		src;
@@ -261,6 +256,8 @@
 	dev->flags = req->flags &
 		((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
 
+	atomic_set(&dev->opened, 0);
+
 	init_waitqueue_head(&dev->wait);
 	tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
 
@@ -301,18 +298,15 @@
 out:
 	write_unlock_bh(&rfcomm_dev_lock);
 
-	if (err < 0) {
-		kfree(dev);
-		return err;
-	}
+	if (err < 0)
+		goto free;
 
 	dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL);
 
 	if (IS_ERR(dev->tty_dev)) {
 		err = PTR_ERR(dev->tty_dev);
 		list_del(&dev->list);
-		kfree(dev);
-		return err;
+		goto free;
 	}
 
 	dev_set_drvdata(dev->tty_dev, dev);
@@ -324,16 +318,20 @@
 		BT_ERR("Failed to create channel attribute");
 
 	return dev->id;
+
+free:
+	kfree(dev);
+	return err;
 }
 
 static void rfcomm_dev_del(struct rfcomm_dev *dev)
 {
 	BT_DBG("dev %p", dev);
 
-	if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
-		BUG_ON(1);
-	else
-		set_bit(RFCOMM_TTY_RELEASED, &dev->flags);
+	BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags));
+
+	if (atomic_read(&dev->opened) > 0)
+		return;
 
 	write_lock_bh(&rfcomm_dev_lock);
 	list_del_init(&dev->list);
@@ -689,9 +687,10 @@
 	if (!dev)
 		return -ENODEV;
 
-	BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened);
+	BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst),
+				dev->channel, atomic_read(&dev->opened));
 
-	if (dev->opened++ != 0)
+	if (atomic_inc_return(&dev->opened) > 1)
 		return 0;
 
 	dlc = dev->dlc;
@@ -747,9 +746,10 @@
 	if (!dev)
 		return;
 
-	BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);
+	BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc,
+						atomic_read(&dev->opened));
 
-	if (--dev->opened == 0) {
+	if (atomic_dec_and_test(&dev->opened)) {
 		if (dev->tty_dev->parent)
 			device_move(dev->tty_dev, NULL);
 
@@ -763,6 +763,14 @@
 		tty->driver_data = NULL;
 		dev->tty = NULL;
 		rfcomm_dlc_unlock(dev->dlc);
+
+		if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
+			write_lock_bh(&rfcomm_dev_lock);
+			list_del_init(&dev->list);
+			write_unlock_bh(&rfcomm_dev_lock);
+
+			rfcomm_dev_put(dev);
+		}
 	}
 
 	rfcomm_dev_put(dev);
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 0cc91e6..46fd8bf 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -48,11 +48,6 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/sco.h>
 
-#ifndef CONFIG_BT_SCO_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 #define VERSION "0.6"
 
 static int disable_esco = 0;
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 6c023f0..18538d7 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -147,7 +147,7 @@
 	return 0;
 }
 
-static struct ethtool_ops br_ethtool_ops = {
+static const struct ethtool_ops br_ethtool_ops = {
 	.get_drvinfo    = br_getinfo,
 	.get_link	= ethtool_op_get_link,
 	.get_tx_csum	= ethtool_op_get_tx_csum,
@@ -160,21 +160,25 @@
 	.get_flags	= ethtool_op_get_flags,
 };
 
+static const struct net_device_ops br_netdev_ops = {
+	.ndo_open		 = br_dev_open,
+	.ndo_stop		 = br_dev_stop,
+	.ndo_start_xmit		 = br_dev_xmit,
+	.ndo_set_mac_address	 = br_set_mac_address,
+	.ndo_set_multicast_list	 = br_dev_set_multicast_list,
+	.ndo_change_mtu		 = br_change_mtu,
+	.ndo_do_ioctl		 = br_dev_ioctl,
+};
+
 void br_dev_setup(struct net_device *dev)
 {
 	random_ether_addr(dev->dev_addr);
 	ether_setup(dev);
 
-	dev->do_ioctl = br_dev_ioctl;
-	dev->hard_start_xmit = br_dev_xmit;
-	dev->open = br_dev_open;
-	dev->set_multicast_list = br_dev_set_multicast_list;
-	dev->change_mtu = br_change_mtu;
+	dev->netdev_ops = &br_netdev_ops;
 	dev->destructor = free_netdev;
 	SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
-	dev->stop = br_dev_stop;
 	dev->tx_queue_len = 0;
-	dev->set_mac_address = br_set_mac_address;
 	dev->priv_flags = IFF_EBRIDGE;
 
 	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 0a09ccf..727c5c5 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -373,7 +373,7 @@
 	if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER)
 		return -EINVAL;
 
-	if (dev->hard_start_xmit == br_dev_xmit)
+	if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit)
 		return -ELOOP;
 
 	if (dev->br_port != NULL)
@@ -460,7 +460,7 @@
 restart:
 	for_each_netdev(net, dev) {
 		if (dev->priv_flags & IFF_EBRIDGE) {
-			del_br(dev->priv);
+			del_br(netdev_priv(dev));
 			goto restart;
 		}
 	}
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 45f61c3..a65e43a 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -109,7 +109,6 @@
 	.family =		AF_INET,
 	.protocol =		__constant_htons(ETH_P_IP),
 	.update_pmtu =		fake_update_pmtu,
-	.entry_size =		sizeof(struct rtable),
 	.entries =		ATOMIC_INIT(0),
 };
 
@@ -370,7 +369,7 @@
 			if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev))
 				goto free_skb;
 
-			if (!ip_route_output_key(&init_net, &rt, &fl)) {
+			if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
 				/* - Bridged-and-DNAT'ed traffic doesn't
 				 *   require ip_forwarding. */
 				if (((struct dst_entry *)rt)->dev == dev) {
@@ -951,35 +950,35 @@
 		.data		= &brnf_call_arptables,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &brnf_sysctl_call_tables,
+		.proc_handler	= brnf_sysctl_call_tables,
 	},
 	{
 		.procname	= "bridge-nf-call-iptables",
 		.data		= &brnf_call_iptables,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &brnf_sysctl_call_tables,
+		.proc_handler	= brnf_sysctl_call_tables,
 	},
 	{
 		.procname	= "bridge-nf-call-ip6tables",
 		.data		= &brnf_call_ip6tables,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &brnf_sysctl_call_tables,
+		.proc_handler	= brnf_sysctl_call_tables,
 	},
 	{
 		.procname	= "bridge-nf-filter-vlan-tagged",
 		.data		= &brnf_filter_vlan_tagged,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &brnf_sysctl_call_tables,
+		.proc_handler	= brnf_sysctl_call_tables,
 	},
 	{
 		.procname	= "bridge-nf-filter-pppoe-tagged",
 		.data		= &brnf_filter_pppoe_tagged,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &brnf_sysctl_call_tables,
+		.proc_handler	= brnf_sysctl_call_tables,
 	},
 	{ .ctl_name = 0 }
 };
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 158dee8..603d892 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -22,7 +22,7 @@
 #include "br_private.h"
 
 #define to_dev(obj)	container_of(obj, struct device, kobj)
-#define to_bridge(cd)	((struct net_bridge *)(to_net_dev(cd)->priv))
+#define to_bridge(cd)	((struct net_bridge *)netdev_priv(to_net_dev(cd)))
 
 /*
  * Common code for storing bridge parameters.
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index 3d33c60..d44cbf8 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -79,7 +79,6 @@
 	}
 }
 
-#define myNIPQUAD(a) a[0], a[1], a[2], a[3]
 static void
 ebt_log_packet(u_int8_t pf, unsigned int hooknum,
    const struct sk_buff *skb, const struct net_device *in,
@@ -113,9 +112,8 @@
 			printk(" INCOMPLETE IP header");
 			goto out;
 		}
-		printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u, IP "
-		       "tos=0x%02X, IP proto=%d", NIPQUAD(ih->saddr),
-		       NIPQUAD(ih->daddr), ih->tos, ih->protocol);
+		printk(" IP SRC=%pI4 IP DST=%pI4, IP tos=0x%02X, IP proto=%d",
+		       &ih->saddr, &ih->daddr, ih->tos, ih->protocol);
 		print_ports(skb, ih->protocol, ih->ihl*4);
 		goto out;
 	}
@@ -133,10 +131,8 @@
 			printk(" INCOMPLETE IPv6 header");
 			goto out;
 		}
-		printk(" IPv6 SRC=%x:%x:%x:%x:%x:%x:%x:%x "
-		       "IPv6 DST=%x:%x:%x:%x:%x:%x:%x:%x, IPv6 "
-		       "priority=0x%01X, Next Header=%d", NIP6(ih->saddr),
-		       NIP6(ih->daddr), ih->priority, ih->nexthdr);
+		printk(" IPv6 SRC=%pI6 IPv6 DST=%pI6, IPv6 priority=0x%01X, Next Header=%d",
+		       &ih->saddr, &ih->daddr, ih->priority, ih->nexthdr);
 		nexthdr = ih->nexthdr;
 		offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr);
 		if (offset_ph == -1)
@@ -177,12 +173,10 @@
 			}
 			printk(" ARP MAC SRC=");
 			print_MAC(ap->mac_src);
-			printk(" ARP IP SRC=%u.%u.%u.%u",
-			       myNIPQUAD(ap->ip_src));
+			printk(" ARP IP SRC=%pI4", ap->ip_src);
 			printk(" ARP MAC DST=");
 			print_MAC(ap->mac_dst);
-			printk(" ARP IP DST=%u.%u.%u.%u",
-			       myNIPQUAD(ap->ip_dst));
+			printk(" ARP IP DST=%pI4", ap->ip_dst);
 		}
 	}
 out:
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index 246626b..8604dfc 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -56,29 +56,47 @@
 	int ret;
 
 	ret = ebt_do_table(NF_BR_BROUTING, skb, skb->dev, NULL,
-	   &broute_table);
+			   dev_net(skb->dev)->xt.broute_table);
 	if (ret == NF_DROP)
 		return 1; /* route it */
 	return 0; /* bridge it */
 }
 
+static int __net_init broute_net_init(struct net *net)
+{
+	net->xt.broute_table = ebt_register_table(net, &broute_table);
+	if (IS_ERR(net->xt.broute_table))
+		return PTR_ERR(net->xt.broute_table);
+	return 0;
+}
+
+static void __net_exit broute_net_exit(struct net *net)
+{
+	ebt_unregister_table(net->xt.broute_table);
+}
+
+static struct pernet_operations broute_net_ops = {
+	.init = broute_net_init,
+	.exit = broute_net_exit,
+};
+
 static int __init ebtable_broute_init(void)
 {
 	int ret;
 
-	ret = ebt_register_table(&broute_table);
+	ret = register_pernet_subsys(&broute_net_ops);
 	if (ret < 0)
 		return ret;
 	/* see br_input.c */
 	rcu_assign_pointer(br_should_route_hook, ebt_broute);
-	return ret;
+	return 0;
 }
 
 static void __exit ebtable_broute_fini(void)
 {
 	rcu_assign_pointer(br_should_route_hook, NULL);
 	synchronize_net();
-	ebt_unregister_table(&broute_table);
+	unregister_pernet_subsys(&broute_net_ops);
 }
 
 module_init(ebtable_broute_init);
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index 1a58af5..2b2e804 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -61,29 +61,36 @@
 };
 
 static unsigned int
-ebt_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in,
+ebt_in_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in,
    const struct net_device *out, int (*okfn)(struct sk_buff *))
 {
-	return ebt_do_table(hook, skb, in, out, &frame_filter);
+	return ebt_do_table(hook, skb, in, out, dev_net(in)->xt.frame_filter);
+}
+
+static unsigned int
+ebt_out_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in,
+   const struct net_device *out, int (*okfn)(struct sk_buff *))
+{
+	return ebt_do_table(hook, skb, in, out, dev_net(out)->xt.frame_filter);
 }
 
 static struct nf_hook_ops ebt_ops_filter[] __read_mostly = {
 	{
-		.hook		= ebt_hook,
+		.hook		= ebt_in_hook,
 		.owner		= THIS_MODULE,
 		.pf		= PF_BRIDGE,
 		.hooknum	= NF_BR_LOCAL_IN,
 		.priority	= NF_BR_PRI_FILTER_BRIDGED,
 	},
 	{
-		.hook		= ebt_hook,
+		.hook		= ebt_in_hook,
 		.owner		= THIS_MODULE,
 		.pf		= PF_BRIDGE,
 		.hooknum	= NF_BR_FORWARD,
 		.priority	= NF_BR_PRI_FILTER_BRIDGED,
 	},
 	{
-		.hook		= ebt_hook,
+		.hook		= ebt_out_hook,
 		.owner		= THIS_MODULE,
 		.pf		= PF_BRIDGE,
 		.hooknum	= NF_BR_LOCAL_OUT,
@@ -91,23 +98,41 @@
 	},
 };
 
+static int __net_init frame_filter_net_init(struct net *net)
+{
+	net->xt.frame_filter = ebt_register_table(net, &frame_filter);
+	if (IS_ERR(net->xt.frame_filter))
+		return PTR_ERR(net->xt.frame_filter);
+	return 0;
+}
+
+static void __net_exit frame_filter_net_exit(struct net *net)
+{
+	ebt_unregister_table(net->xt.frame_filter);
+}
+
+static struct pernet_operations frame_filter_net_ops = {
+	.init = frame_filter_net_init,
+	.exit = frame_filter_net_exit,
+};
+
 static int __init ebtable_filter_init(void)
 {
 	int ret;
 
-	ret = ebt_register_table(&frame_filter);
+	ret = register_pernet_subsys(&frame_filter_net_ops);
 	if (ret < 0)
 		return ret;
 	ret = nf_register_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter));
 	if (ret < 0)
-		ebt_unregister_table(&frame_filter);
+		unregister_pernet_subsys(&frame_filter_net_ops);
 	return ret;
 }
 
 static void __exit ebtable_filter_fini(void)
 {
 	nf_unregister_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter));
-	ebt_unregister_table(&frame_filter);
+	unregister_pernet_subsys(&frame_filter_net_ops);
 }
 
 module_init(ebtable_filter_init);
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index f60c1e7..3fe1ae8 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -61,36 +61,36 @@
 };
 
 static unsigned int
-ebt_nat_dst(unsigned int hook, struct sk_buff *skb, const struct net_device *in
+ebt_nat_in(unsigned int hook, struct sk_buff *skb, const struct net_device *in
    , const struct net_device *out, int (*okfn)(struct sk_buff *))
 {
-	return ebt_do_table(hook, skb, in, out, &frame_nat);
+	return ebt_do_table(hook, skb, in, out, dev_net(in)->xt.frame_nat);
 }
 
 static unsigned int
-ebt_nat_src(unsigned int hook, struct sk_buff *skb, const struct net_device *in
+ebt_nat_out(unsigned int hook, struct sk_buff *skb, const struct net_device *in
    , const struct net_device *out, int (*okfn)(struct sk_buff *))
 {
-	return ebt_do_table(hook, skb, in, out, &frame_nat);
+	return ebt_do_table(hook, skb, in, out, dev_net(out)->xt.frame_nat);
 }
 
 static struct nf_hook_ops ebt_ops_nat[] __read_mostly = {
 	{
-		.hook		= ebt_nat_dst,
+		.hook		= ebt_nat_out,
 		.owner		= THIS_MODULE,
 		.pf		= PF_BRIDGE,
 		.hooknum	= NF_BR_LOCAL_OUT,
 		.priority	= NF_BR_PRI_NAT_DST_OTHER,
 	},
 	{
-		.hook		= ebt_nat_src,
+		.hook		= ebt_nat_out,
 		.owner		= THIS_MODULE,
 		.pf		= PF_BRIDGE,
 		.hooknum	= NF_BR_POST_ROUTING,
 		.priority	= NF_BR_PRI_NAT_SRC,
 	},
 	{
-		.hook		= ebt_nat_dst,
+		.hook		= ebt_nat_in,
 		.owner		= THIS_MODULE,
 		.pf		= PF_BRIDGE,
 		.hooknum	= NF_BR_PRE_ROUTING,
@@ -98,23 +98,41 @@
 	},
 };
 
+static int __net_init frame_nat_net_init(struct net *net)
+{
+	net->xt.frame_nat = ebt_register_table(net, &frame_nat);
+	if (IS_ERR(net->xt.frame_nat))
+		return PTR_ERR(net->xt.frame_nat);
+	return 0;
+}
+
+static void __net_exit frame_nat_net_exit(struct net *net)
+{
+	ebt_unregister_table(net->xt.frame_nat);
+}
+
+static struct pernet_operations frame_nat_net_ops = {
+	.init = frame_nat_net_init,
+	.exit = frame_nat_net_exit,
+};
+
 static int __init ebtable_nat_init(void)
 {
 	int ret;
 
-	ret = ebt_register_table(&frame_nat);
+	ret = register_pernet_subsys(&frame_nat_net_ops);
 	if (ret < 0)
 		return ret;
 	ret = nf_register_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat));
 	if (ret < 0)
-		ebt_unregister_table(&frame_nat);
+		unregister_pernet_subsys(&frame_nat_net_ops);
 	return ret;
 }
 
 static void __exit ebtable_nat_fini(void)
 {
 	nf_unregister_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat));
-	ebt_unregister_table(&frame_nat);
+	unregister_pernet_subsys(&frame_nat_net_ops);
 }
 
 module_init(ebtable_nat_init);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 0fa208e..fa108c4 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -55,7 +55,6 @@
 
 
 static DEFINE_MUTEX(ebt_mutex);
-static LIST_HEAD(ebt_tables);
 
 static struct xt_target ebt_standard_target = {
 	.name       = "standard",
@@ -315,9 +314,11 @@
 }
 
 static inline struct ebt_table *
-find_table_lock(const char *name, int *error, struct mutex *mutex)
+find_table_lock(struct net *net, const char *name, int *error,
+		struct mutex *mutex)
 {
-	return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
+	return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
+				"ebtable_", error, mutex);
 }
 
 static inline int
@@ -944,7 +945,7 @@
 }
 
 /* replace the table */
-static int do_replace(void __user *user, unsigned int len)
+static int do_replace(struct net *net, void __user *user, unsigned int len)
 {
 	int ret, i, countersize;
 	struct ebt_table_info *newinfo;
@@ -1016,7 +1017,7 @@
 	if (ret != 0)
 		goto free_counterstmp;
 
-	t = find_table_lock(tmp.name, &ret, &ebt_mutex);
+	t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
 	if (!t) {
 		ret = -ENOENT;
 		goto free_iterate;
@@ -1097,7 +1098,7 @@
 	return ret;
 }
 
-int ebt_register_table(struct ebt_table *table)
+struct ebt_table *ebt_register_table(struct net *net, struct ebt_table *table)
 {
 	struct ebt_table_info *newinfo;
 	struct ebt_table *t;
@@ -1109,14 +1110,21 @@
 	    repl->entries_size == 0 ||
 	    repl->counters || table->private) {
 		BUGPRINT("Bad table data for ebt_register_table!!!\n");
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Don't add one table to multiple lists. */
+	table = kmemdup(table, sizeof(struct ebt_table), GFP_KERNEL);
+	if (!table) {
+		ret = -ENOMEM;
+		goto out;
 	}
 
 	countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
 	newinfo = vmalloc(sizeof(*newinfo) + countersize);
 	ret = -ENOMEM;
 	if (!newinfo)
-		return -ENOMEM;
+		goto free_table;
 
 	p = vmalloc(repl->entries_size);
 	if (!p)
@@ -1148,7 +1156,7 @@
 
 	if (table->check && table->check(newinfo, table->valid_hooks)) {
 		BUGPRINT("The table doesn't like its own initial data, lol\n");
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	table->private = newinfo;
@@ -1157,7 +1165,7 @@
 	if (ret != 0)
 		goto free_chainstack;
 
-	list_for_each_entry(t, &ebt_tables, list) {
+	list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
 		if (strcmp(t->name, table->name) == 0) {
 			ret = -EEXIST;
 			BUGPRINT("Table name already exists\n");
@@ -1170,9 +1178,9 @@
 		ret = -ENOENT;
 		goto free_unlock;
 	}
-	list_add(&table->list, &ebt_tables);
+	list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
 	mutex_unlock(&ebt_mutex);
-	return 0;
+	return table;
 free_unlock:
 	mutex_unlock(&ebt_mutex);
 free_chainstack:
@@ -1184,7 +1192,10 @@
 	vfree(newinfo->entries);
 free_newinfo:
 	vfree(newinfo);
-	return ret;
+free_table:
+	kfree(table);
+out:
+	return ERR_PTR(ret);
 }
 
 void ebt_unregister_table(struct ebt_table *table)
@@ -1198,6 +1209,10 @@
 	mutex_lock(&ebt_mutex);
 	list_del(&table->list);
 	mutex_unlock(&ebt_mutex);
+	EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
+			  ebt_cleanup_entry, NULL);
+	if (table->private->nentries)
+		module_put(table->me);
 	vfree(table->private->entries);
 	if (table->private->chainstack) {
 		for_each_possible_cpu(i)
@@ -1205,10 +1220,11 @@
 		vfree(table->private->chainstack);
 	}
 	vfree(table->private);
+	kfree(table);
 }
 
 /* userspace just supplied us with counters */
-static int update_counters(void __user *user, unsigned int len)
+static int update_counters(struct net *net, void __user *user, unsigned int len)
 {
 	int i, ret;
 	struct ebt_counter *tmp;
@@ -1228,7 +1244,7 @@
 		return -ENOMEM;
 	}
 
-	t = find_table_lock(hlp.name, &ret, &ebt_mutex);
+	t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
 	if (!t)
 		goto free_tmp;
 
@@ -1386,10 +1402,10 @@
 
 	switch(cmd) {
 	case EBT_SO_SET_ENTRIES:
-		ret = do_replace(user, len);
+		ret = do_replace(sock_net(sk), user, len);
 		break;
 	case EBT_SO_SET_COUNTERS:
-		ret = update_counters(user, len);
+		ret = update_counters(sock_net(sk), user, len);
 		break;
 	default:
 		ret = -EINVAL;
@@ -1406,7 +1422,7 @@
 	if (copy_from_user(&tmp, user, sizeof(tmp)))
 		return -EFAULT;
 
-	t = find_table_lock(tmp.name, &ret, &ebt_mutex);
+	t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
 	if (!t)
 		return ret;
 
diff --git a/net/can/raw.c b/net/can/raw.c
index 6e0663f..27aab63 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -641,17 +641,12 @@
 
 	skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT,
 				  &err);
-	if (!skb) {
-		dev_put(dev);
-		return err;
-	}
+	if (!skb)
+		goto put_dev;
 
 	err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
-	if (err < 0) {
-		kfree_skb(skb);
-		dev_put(dev);
-		return err;
-	}
+	if (err < 0)
+		goto free_skb;
 	skb->dev = dev;
 	skb->sk  = sk;
 
@@ -660,9 +655,16 @@
 	dev_put(dev);
 
 	if (err)
-		return err;
+		goto send_failed;
 
 	return size;
+
+free_skb:
+	kfree_skb(skb);
+put_dev:
+	dev_put(dev);
+send_failed:
+	return err;
 }
 
 static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
diff --git a/net/core/datagram.c b/net/core/datagram.c
index ee63184..5e2ac0c 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -209,7 +209,7 @@
 void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
 {
 	kfree_skb(skb);
-	sk_mem_reclaim(sk);
+	sk_mem_reclaim_partial(sk);
 }
 
 /**
@@ -248,8 +248,7 @@
 		spin_unlock_bh(&sk->sk_receive_queue.lock);
 	}
 
-	kfree_skb(skb);
-	sk_mem_reclaim(sk);
+	skb_free_datagram(sk, skb);
 	return err;
 }
 
diff --git a/net/core/dev.c b/net/core/dev.c
index 9174c77..4464240 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -108,7 +108,6 @@
 #include <linux/init.h>
 #include <linux/kmod.h>
 #include <linux/module.h>
-#include <linux/kallsyms.h>
 #include <linux/netpoll.h>
 #include <linux/rcupdate.h>
 #include <linux/delay.h>
@@ -130,6 +129,9 @@
 
 #include "net-sysfs.h"
 
+/* Instead of increasing this, you should create a hash table. */
+#define MAX_GRO_SKBS 8
+
 /*
  *	The list of packet types we will receive (as opposed to discard)
  *	and the routines to invoke.
@@ -281,8 +283,8 @@
 	 ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET,
 	 ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL,
 	 ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211,
-	 ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_VOID,
-	 ARPHRD_NONE};
+	 ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET,
+	 ARPHRD_PHONET_PIPE, ARPHRD_VOID, ARPHRD_NONE};
 
 static const char *netdev_lock_name[] =
 	{"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25",
@@ -298,8 +300,8 @@
 	 "_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET",
 	 "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL",
 	 "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211",
-	 "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_VOID",
-	 "_xmit_NONE"};
+	 "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET",
+	 "_xmit_PHONET_PIPE", "_xmit_VOID", "_xmit_NONE"};
 
 static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)];
 static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)];
@@ -924,10 +926,15 @@
 		strlcpy(dev->name, newname, IFNAMSIZ);
 
 rollback:
-	ret = device_rename(&dev->dev, dev->name);
-	if (ret) {
-		memcpy(dev->name, oldname, IFNAMSIZ);
-		return ret;
+	/* For now only devices in the initial network namespace
+	 * are in sysfs.
+	 */
+	if (net == &init_net) {
+		ret = device_rename(&dev->dev, dev->name);
+		if (ret) {
+			memcpy(dev->name, oldname, IFNAMSIZ);
+			return ret;
+		}
 	}
 
 	write_lock_bh(&dev_base_lock);
@@ -1055,6 +1062,7 @@
  */
 int dev_open(struct net_device *dev)
 {
+	const struct net_device_ops *ops = dev->netdev_ops;
 	int ret = 0;
 
 	ASSERT_RTNL();
@@ -1077,11 +1085,11 @@
 	 */
 	set_bit(__LINK_STATE_START, &dev->state);
 
-	if (dev->validate_addr)
-		ret = dev->validate_addr(dev);
+	if (ops->ndo_validate_addr)
+		ret = ops->ndo_validate_addr(dev);
 
-	if (!ret && dev->open)
-		ret = dev->open(dev);
+	if (!ret && ops->ndo_open)
+		ret = ops->ndo_open(dev);
 
 	/*
 	 *	If it went open OK then:
@@ -1125,6 +1133,7 @@
  */
 int dev_close(struct net_device *dev)
 {
+	const struct net_device_ops *ops = dev->netdev_ops;
 	ASSERT_RTNL();
 
 	might_sleep();
@@ -1157,8 +1166,8 @@
 	 *	We allow it to be called even after a DETACH hot-plug
 	 *	event.
 	 */
-	if (dev->stop)
-		dev->stop(dev);
+	if (ops->ndo_stop)
+		ops->ndo_stop(dev);
 
 	/*
 	 *	Device is now down.
@@ -1527,8 +1536,6 @@
 	__be16 type = skb->protocol;
 	int err;
 
-	BUG_ON(skb_shinfo(skb)->frag_list);
-
 	skb_reset_mac_header(skb);
 	skb->mac_len = skb->network_header - skb->mac_header;
 	__skb_pull(skb, skb->mac_len);
@@ -1654,6 +1661,9 @@
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 			struct netdev_queue *txq)
 {
+	const struct net_device_ops *ops = dev->netdev_ops;
+
+	prefetch(&dev->netdev_ops->ndo_start_xmit);
 	if (likely(!skb->next)) {
 		if (!list_empty(&ptype_all))
 			dev_queue_xmit_nit(skb, dev);
@@ -1665,7 +1675,7 @@
 				goto gso;
 		}
 
-		return dev->hard_start_xmit(skb, dev);
+		return ops->ndo_start_xmit(skb, dev);
 	}
 
 gso:
@@ -1675,7 +1685,7 @@
 
 		skb->next = nskb->next;
 		nskb->next = NULL;
-		rc = dev->hard_start_xmit(nskb, dev);
+		rc = ops->ndo_start_xmit(nskb, dev);
 		if (unlikely(rc)) {
 			nskb->next = skb->next;
 			skb->next = nskb;
@@ -1749,10 +1759,11 @@
 static struct netdev_queue *dev_pick_tx(struct net_device *dev,
 					struct sk_buff *skb)
 {
+	const struct net_device_ops *ops = dev->netdev_ops;
 	u16 queue_index = 0;
 
-	if (dev->select_queue)
-		queue_index = dev->select_queue(dev, skb);
+	if (ops->ndo_select_queue)
+		queue_index = ops->ndo_select_queue(dev, skb);
 	else if (dev->real_num_tx_queues > 1)
 		queue_index = simple_tx_hash(dev, skb);
 
@@ -2251,8 +2262,10 @@
 	rcu_read_lock();
 
 	/* Don't receive packets in an exiting network namespace */
-	if (!net_alive(dev_net(skb->dev)))
+	if (!net_alive(dev_net(skb->dev))) {
+		kfree_skb(skb);
 		goto out;
+	}
 
 #ifdef CONFIG_NET_CLS_ACT
 	if (skb->tc_verd & TC_NCLS) {
@@ -2325,6 +2338,125 @@
 		}
 }
 
+static int napi_gro_complete(struct sk_buff *skb)
+{
+	struct packet_type *ptype;
+	__be16 type = skb->protocol;
+	struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK];
+	int err = -ENOENT;
+
+	if (!skb_shinfo(skb)->frag_list)
+		goto out;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(ptype, head, list) {
+		if (ptype->type != type || ptype->dev || !ptype->gro_complete)
+			continue;
+
+		err = ptype->gro_complete(skb);
+		break;
+	}
+	rcu_read_unlock();
+
+	if (err) {
+		WARN_ON(&ptype->list == head);
+		kfree_skb(skb);
+		return NET_RX_SUCCESS;
+	}
+
+out:
+	__skb_push(skb, -skb_network_offset(skb));
+	return netif_receive_skb(skb);
+}
+
+void napi_gro_flush(struct napi_struct *napi)
+{
+	struct sk_buff *skb, *next;
+
+	for (skb = napi->gro_list; skb; skb = next) {
+		next = skb->next;
+		skb->next = NULL;
+		napi_gro_complete(skb);
+	}
+
+	napi->gro_list = NULL;
+}
+EXPORT_SYMBOL(napi_gro_flush);
+
+int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
+{
+	struct sk_buff **pp = NULL;
+	struct packet_type *ptype;
+	__be16 type = skb->protocol;
+	struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK];
+	int count = 0;
+	int same_flow;
+	int mac_len;
+
+	if (!(skb->dev->features & NETIF_F_GRO))
+		goto normal;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(ptype, head, list) {
+		struct sk_buff *p;
+
+		if (ptype->type != type || ptype->dev || !ptype->gro_receive)
+			continue;
+
+		skb_reset_network_header(skb);
+		mac_len = skb->network_header - skb->mac_header;
+		skb->mac_len = mac_len;
+		NAPI_GRO_CB(skb)->same_flow = 0;
+		NAPI_GRO_CB(skb)->flush = 0;
+
+		for (p = napi->gro_list; p; p = p->next) {
+			count++;
+			NAPI_GRO_CB(p)->same_flow =
+				p->mac_len == mac_len &&
+				!memcmp(skb_mac_header(p), skb_mac_header(skb),
+					mac_len);
+			NAPI_GRO_CB(p)->flush = 0;
+		}
+
+		pp = ptype->gro_receive(&napi->gro_list, skb);
+		break;
+	}
+	rcu_read_unlock();
+
+	if (&ptype->list == head)
+		goto normal;
+
+	same_flow = NAPI_GRO_CB(skb)->same_flow;
+
+	if (pp) {
+		struct sk_buff *nskb = *pp;
+
+		*pp = nskb->next;
+		nskb->next = NULL;
+		napi_gro_complete(nskb);
+		count--;
+	}
+
+	if (same_flow)
+		goto ok;
+
+	if (NAPI_GRO_CB(skb)->flush || count >= MAX_GRO_SKBS) {
+		__skb_push(skb, -skb_network_offset(skb));
+		goto normal;
+	}
+
+	NAPI_GRO_CB(skb)->count = 1;
+	skb->next = napi->gro_list;
+	napi->gro_list = skb;
+
+ok:
+	return NET_RX_SUCCESS;
+
+normal:
+	return netif_receive_skb(skb);
+}
+EXPORT_SYMBOL(napi_gro_receive);
+
 static int process_backlog(struct napi_struct *napi, int quota)
 {
 	int work = 0;
@@ -2344,9 +2476,11 @@
 		}
 		local_irq_enable();
 
-		netif_receive_skb(skb);
+		napi_gro_receive(napi, skb);
 	} while (++work < quota && jiffies == start_time);
 
+	napi_gro_flush(napi);
+
 	return work;
 }
 
@@ -2367,11 +2501,73 @@
 }
 EXPORT_SYMBOL(__napi_schedule);
 
+void __napi_complete(struct napi_struct *n)
+{
+	BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
+	BUG_ON(n->gro_list);
+
+	list_del(&n->poll_list);
+	smp_mb__before_clear_bit();
+	clear_bit(NAPI_STATE_SCHED, &n->state);
+}
+EXPORT_SYMBOL(__napi_complete);
+
+void napi_complete(struct napi_struct *n)
+{
+	unsigned long flags;
+
+	/*
+	 * don't let napi dequeue from the cpu poll list
+	 * just in case its running on a different cpu
+	 */
+	if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state)))
+		return;
+
+	napi_gro_flush(n);
+	local_irq_save(flags);
+	__napi_complete(n);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(napi_complete);
+
+void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
+		    int (*poll)(struct napi_struct *, int), int weight)
+{
+	INIT_LIST_HEAD(&napi->poll_list);
+	napi->gro_list = NULL;
+	napi->poll = poll;
+	napi->weight = weight;
+	list_add(&napi->dev_list, &dev->napi_list);
+#ifdef CONFIG_NETPOLL
+	napi->dev = dev;
+	spin_lock_init(&napi->poll_lock);
+	napi->poll_owner = -1;
+#endif
+	set_bit(NAPI_STATE_SCHED, &napi->state);
+}
+EXPORT_SYMBOL(netif_napi_add);
+
+void netif_napi_del(struct napi_struct *napi)
+{
+	struct sk_buff *skb, *next;
+
+	list_del_init(&napi->dev_list);
+
+	for (skb = napi->gro_list; skb; skb = next) {
+		next = skb->next;
+		skb->next = NULL;
+		kfree_skb(skb);
+	}
+
+	napi->gro_list = NULL;
+}
+EXPORT_SYMBOL(netif_napi_del);
+
 
 static void net_rx_action(struct softirq_action *h)
 {
 	struct list_head *list = &__get_cpu_var(softnet_data).poll_list;
-	unsigned long start_time = jiffies;
+	unsigned long time_limit = jiffies + 2;
 	int budget = netdev_budget;
 	void *have;
 
@@ -2382,13 +2578,10 @@
 		int work, weight;
 
 		/* If softirq window is exhuasted then punt.
-		 *
-		 * Note that this is a slight policy change from the
-		 * previous NAPI code, which would allow up to 2
-		 * jiffies to pass before breaking out.  The test
-		 * used to be "jiffies - start_time > 1".
+		 * Allow this to run for 2 jiffies since which will allow
+		 * an average latency of 1.5/HZ.
 		 */
-		if (unlikely(budget <= 0 || jiffies != start_time))
+		if (unlikely(budget <= 0 || time_after(jiffies, time_limit)))
 			goto softnet_break;
 
 		local_irq_enable();
@@ -2615,7 +2808,7 @@
 
 static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
 {
-	struct net_device_stats *stats = dev->get_stats(dev);
+	const struct net_device_stats *stats = dev_get_stats(dev);
 
 	seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
 		   "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
@@ -2797,31 +2990,6 @@
 	rcu_read_unlock();
 }
 
-static void ptype_seq_decode(struct seq_file *seq, void *sym)
-{
-#ifdef CONFIG_KALLSYMS
-	unsigned long offset = 0, symsize;
-	const char *symname;
-	char *modname;
-	char namebuf[128];
-
-	symname = kallsyms_lookup((unsigned long)sym, &symsize, &offset,
-				  &modname, namebuf);
-
-	if (symname) {
-		char *delim = ":";
-
-		if (!modname)
-			modname = delim = "";
-		seq_printf(seq, "%s%s%s%s+0x%lx", delim, modname, delim,
-			   symname, offset);
-		return;
-	}
-#endif
-
-	seq_printf(seq, "[%p]", sym);
-}
-
 static int ptype_seq_show(struct seq_file *seq, void *v)
 {
 	struct packet_type *pt = v;
@@ -2834,10 +3002,8 @@
 		else
 			seq_printf(seq, "%04x", ntohs(pt->type));
 
-		seq_printf(seq, " %-8s ",
-			   pt->dev ? pt->dev->name : "");
-		ptype_seq_decode(seq,  pt->func);
-		seq_putc(seq, '\n');
+		seq_printf(seq, " %-8s %pF\n",
+			   pt->dev ? pt->dev->name : "", pt->func);
 	}
 
 	return 0;
@@ -2954,13 +3120,17 @@
 
 static void dev_change_rx_flags(struct net_device *dev, int flags)
 {
-	if (dev->flags & IFF_UP && dev->change_rx_flags)
-		dev->change_rx_flags(dev, flags);
+	const struct net_device_ops *ops = dev->netdev_ops;
+
+	if ((dev->flags & IFF_UP) && ops->ndo_change_rx_flags)
+		ops->ndo_change_rx_flags(dev, flags);
 }
 
 static int __dev_set_promiscuity(struct net_device *dev, int inc)
 {
 	unsigned short old_flags = dev->flags;
+	uid_t uid;
+	gid_t gid;
 
 	ASSERT_RTNL();
 
@@ -2985,15 +3155,17 @@
 		printk(KERN_INFO "device %s %s promiscuous mode\n",
 		       dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
 							       "left");
-		if (audit_enabled)
+		if (audit_enabled) {
+			current_uid_gid(&uid, &gid);
 			audit_log(current->audit_context, GFP_ATOMIC,
 				AUDIT_ANOM_PROMISCUOUS,
 				"dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u",
 				dev->name, (dev->flags & IFF_PROMISC),
 				(old_flags & IFF_PROMISC),
 				audit_get_loginuid(current),
-				current->uid, current->gid,
+				uid, gid,
 				audit_get_sessionid(current));
+		}
 
 		dev_change_rx_flags(dev, IFF_PROMISC);
 	}
@@ -3075,6 +3247,8 @@
  */
 void __dev_set_rx_mode(struct net_device *dev)
 {
+	const struct net_device_ops *ops = dev->netdev_ops;
+
 	/* dev_open will call this function so the list will stay sane. */
 	if (!(dev->flags&IFF_UP))
 		return;
@@ -3082,8 +3256,8 @@
 	if (!netif_device_present(dev))
 		return;
 
-	if (dev->set_rx_mode)
-		dev->set_rx_mode(dev);
+	if (ops->ndo_set_rx_mode)
+		ops->ndo_set_rx_mode(dev);
 	else {
 		/* Unicast addresses changes may only happen under the rtnl,
 		 * therefore calling __dev_set_promiscuity here is safe.
@@ -3096,8 +3270,8 @@
 			dev->uc_promisc = 0;
 		}
 
-		if (dev->set_multicast_list)
-			dev->set_multicast_list(dev);
+		if (ops->ndo_set_multicast_list)
+			ops->ndo_set_multicast_list(dev);
 	}
 }
 
@@ -3456,6 +3630,7 @@
  */
 int dev_set_mtu(struct net_device *dev, int new_mtu)
 {
+	const struct net_device_ops *ops = dev->netdev_ops;
 	int err;
 
 	if (new_mtu == dev->mtu)
@@ -3469,10 +3644,11 @@
 		return -ENODEV;
 
 	err = 0;
-	if (dev->change_mtu)
-		err = dev->change_mtu(dev, new_mtu);
+	if (ops->ndo_change_mtu)
+		err = ops->ndo_change_mtu(dev, new_mtu);
 	else
 		dev->mtu = new_mtu;
+
 	if (!err && dev->flags & IFF_UP)
 		call_netdevice_notifiers(NETDEV_CHANGEMTU, dev);
 	return err;
@@ -3487,15 +3663,16 @@
  */
 int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
 {
+	const struct net_device_ops *ops = dev->netdev_ops;
 	int err;
 
-	if (!dev->set_mac_address)
+	if (!ops->ndo_set_mac_address)
 		return -EOPNOTSUPP;
 	if (sa->sa_family != dev->type)
 		return -EINVAL;
 	if (!netif_device_present(dev))
 		return -ENODEV;
-	err = dev->set_mac_address(dev, sa);
+	err = ops->ndo_set_mac_address(dev, sa);
 	if (!err)
 		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
 	return err;
@@ -3575,10 +3752,13 @@
 {
 	int err;
 	struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
+	const struct net_device_ops *ops;
 
 	if (!dev)
 		return -ENODEV;
 
+	ops = dev->netdev_ops;
+
 	switch (cmd) {
 		case SIOCSIFFLAGS:	/* Set interface flags */
 			return dev_change_flags(dev, ifr->ifr_flags);
@@ -3602,15 +3782,15 @@
 			return 0;
 
 		case SIOCSIFMAP:
-			if (dev->set_config) {
+			if (ops->ndo_set_config) {
 				if (!netif_device_present(dev))
 					return -ENODEV;
-				return dev->set_config(dev, &ifr->ifr_map);
+				return ops->ndo_set_config(dev, &ifr->ifr_map);
 			}
 			return -EOPNOTSUPP;
 
 		case SIOCADDMULTI:
-			if ((!dev->set_multicast_list && !dev->set_rx_mode) ||
+			if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) ||
 			    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
 				return -EINVAL;
 			if (!netif_device_present(dev))
@@ -3619,7 +3799,7 @@
 					  dev->addr_len, 1);
 
 		case SIOCDELMULTI:
-			if ((!dev->set_multicast_list && !dev->set_rx_mode) ||
+			if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) ||
 			    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
 				return -EINVAL;
 			if (!netif_device_present(dev))
@@ -3657,10 +3837,9 @@
 			    cmd == SIOCBRDELIF ||
 			    cmd == SIOCWANDEV) {
 				err = -EOPNOTSUPP;
-				if (dev->do_ioctl) {
+				if (ops->ndo_do_ioctl) {
 					if (netif_device_present(dev))
-						err = dev->do_ioctl(dev, ifr,
-								    cmd);
+						err = ops->ndo_do_ioctl(dev, ifr, cmd);
 					else
 						err = -ENODEV;
 				}
@@ -3921,8 +4100,8 @@
 	 */
 	dev_addr_discard(dev);
 
-	if (dev->uninit)
-		dev->uninit(dev);
+	if (dev->netdev_ops->ndo_uninit)
+		dev->netdev_ops->ndo_uninit(dev);
 
 	/* Notifier chain MUST detach us from master device. */
 	WARN_ON(dev->master);
@@ -4012,7 +4191,7 @@
 	struct hlist_head *head;
 	struct hlist_node *p;
 	int ret;
-	struct net *net;
+	struct net *net = dev_net(dev);
 
 	BUG_ON(dev_boot_phase);
 	ASSERT_RTNL();
@@ -4021,8 +4200,7 @@
 
 	/* When net_device's are persistent, this will be fatal. */
 	BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
-	BUG_ON(!dev_net(dev));
-	net = dev_net(dev);
+	BUG_ON(!net);
 
 	spin_lock_init(&dev->addr_list_lock);
 	netdev_set_addr_lockdep_class(dev);
@@ -4030,9 +4208,46 @@
 
 	dev->iflink = -1;
 
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
+	/* Netdevice_ops API compatiability support.
+	 * This is temporary until all network devices are converted.
+	 */
+	if (dev->netdev_ops) {
+		const struct net_device_ops *ops = dev->netdev_ops;
+
+		dev->init = ops->ndo_init;
+		dev->uninit = ops->ndo_uninit;
+		dev->open = ops->ndo_open;
+		dev->change_rx_flags = ops->ndo_change_rx_flags;
+		dev->set_rx_mode = ops->ndo_set_rx_mode;
+		dev->set_multicast_list = ops->ndo_set_multicast_list;
+		dev->set_mac_address = ops->ndo_set_mac_address;
+		dev->validate_addr = ops->ndo_validate_addr;
+		dev->do_ioctl = ops->ndo_do_ioctl;
+		dev->set_config = ops->ndo_set_config;
+		dev->change_mtu = ops->ndo_change_mtu;
+		dev->tx_timeout = ops->ndo_tx_timeout;
+		dev->get_stats = ops->ndo_get_stats;
+		dev->vlan_rx_register = ops->ndo_vlan_rx_register;
+		dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid;
+		dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+		dev->poll_controller = ops->ndo_poll_controller;
+#endif
+	} else {
+		char drivername[64];
+		pr_info("%s (%s): not using net_device_ops yet\n",
+			dev->name, netdev_drivername(dev, drivername, 64));
+
+		/* This works only because net_device_ops and the
+		   compatiablity structure are the same. */
+		dev->netdev_ops = (void *) &(dev->init);
+	}
+#endif
+
 	/* Init, if this function is available */
-	if (dev->init) {
-		ret = dev->init(dev);
+	if (dev->netdev_ops->ndo_init) {
+		ret = dev->netdev_ops->ndo_init(dev);
 		if (ret) {
 			if (ret > 0)
 				ret = -EIO;
@@ -4110,8 +4325,8 @@
 	return ret;
 
 err_uninit:
-	if (dev->uninit)
-		dev->uninit(dev);
+	if (dev->netdev_ops->ndo_uninit)
+		dev->netdev_ops->ndo_uninit(dev);
 	goto out;
 }
 
@@ -4267,10 +4482,24 @@
 	}
 }
 
-static struct net_device_stats *internal_stats(struct net_device *dev)
-{
-	return &dev->stats;
+/**
+ *	dev_get_stats	- get network device statistics
+ *	@dev: device to get statistics from
+ *
+ *	Get network statistics from device. The device driver may provide
+ *	its own method by setting dev->netdev_ops->get_stats; otherwise
+ *	the internal statistics structure is used.
+ */
+const struct net_device_stats *dev_get_stats(struct net_device *dev)
+ {
+	const struct net_device_ops *ops = dev->netdev_ops;
+
+	if (ops->ndo_get_stats)
+		return ops->ndo_get_stats(dev);
+	else
+		return &dev->stats;
 }
+EXPORT_SYMBOL(dev_get_stats);
 
 static void netdev_init_one_queue(struct net_device *dev,
 				  struct netdev_queue *queue,
@@ -4339,18 +4568,11 @@
 	dev->num_tx_queues = queue_count;
 	dev->real_num_tx_queues = queue_count;
 
-	if (sizeof_priv) {
-		dev->priv = ((char *)dev +
-			     ((sizeof(struct net_device) + NETDEV_ALIGN_CONST)
-			      & ~NETDEV_ALIGN_CONST));
-	}
-
 	dev->gso_max_size = GSO_MAX_SIZE;
 
 	netdev_init_queues(dev);
 
-	dev->get_stats = internal_stats;
-	netpoll_netdev_init(dev);
+	INIT_LIST_HEAD(&dev->napi_list);
 	setup(dev);
 	strcpy(dev->name, name);
 	return dev;
@@ -4367,10 +4589,15 @@
  */
 void free_netdev(struct net_device *dev)
 {
+	struct napi_struct *p, *n;
+
 	release_net(dev_net(dev));
 
 	kfree(dev->_tx);
 
+	list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
+		netif_napi_del(p);
+
 	/*  Compatibility with error handling in drivers */
 	if (dev->reg_state == NETREG_UNINITIALIZED) {
 		kfree((char *)dev - dev->padded);
@@ -4463,6 +4690,15 @@
 	if (dev->features & NETIF_F_NETNS_LOCAL)
 		goto out;
 
+#ifdef CONFIG_SYSFS
+	/* Don't allow real devices to be moved when sysfs
+	 * is enabled.
+	 */
+	err = -EINVAL;
+	if (dev->dev.parent)
+		goto out;
+#endif
+
 	/* Ensure the device has been registrered */
 	err = -EINVAL;
 	if (dev->reg_state != NETREG_REGISTERED)
@@ -4520,6 +4756,8 @@
 	 */
 	dev_addr_discard(dev);
 
+	netdev_unregister_kobject(dev);
+
 	/* Actually switch the network namespace */
 	dev_net_set(dev, net);
 
@@ -4536,7 +4774,6 @@
 	}
 
 	/* Fixup kobjects */
-	netdev_unregister_kobject(dev);
 	err = netdev_register_kobject(dev);
 	WARN_ON(err);
 
@@ -4843,6 +5080,12 @@
 		if (dev->features & NETIF_F_NETNS_LOCAL)
 			continue;
 
+		/* Delete virtual devices */
+		if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) {
+			dev->rtnl_link_ops->dellink(dev);
+			continue;
+		}
+
 		/* Push remaing network devices to init_net */
 		snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex);
 		err = dev_change_net_namespace(dev, &init_net, fb_name);
@@ -4889,9 +5132,6 @@
 	if (register_pernet_subsys(&netdev_net_ops))
 		goto out;
 
-	if (register_pernet_device(&default_device_ops))
-		goto out;
-
 	/*
 	 *	Initialise the packet receive queues.
 	 */
@@ -4906,12 +5146,28 @@
 
 		queue->backlog.poll = process_backlog;
 		queue->backlog.weight = weight_p;
+		queue->backlog.gro_list = NULL;
 	}
 
-	netdev_dma_register();
-
 	dev_boot_phase = 0;
 
+	/* The loopback device is special if any other network devices
+	 * is present in a network namespace the loopback device must
+	 * be present. Since we now dynamically allocate and free the
+	 * loopback device ensure this invariant is maintained by
+	 * keeping the loopback device as the first device on the
+	 * list of network devices.  Ensuring the loopback devices
+	 * is the first device that appears and the last network device
+	 * that disappears.
+	 */
+	if (register_pernet_device(&loopback_net_ops))
+		goto out;
+
+	if (register_pernet_device(&default_device_ops))
+		goto out;
+
+	netdev_dma_register();
+
 	open_softirq(NET_TX_SOFTIRQ, net_tx_action);
 	open_softirq(NET_RX_SOFTIRQ, net_rx_action);
 
diff --git a/net/core/dst.c b/net/core/dst.c
index 09c1530..57bc4d5 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -263,9 +263,11 @@
 void dst_release(struct dst_entry *dst)
 {
 	if (dst) {
-		WARN_ON(atomic_read(&dst->__refcnt) < 1);
+               int newrefcnt;
+
 		smp_mb__before_atomic_dec();
-		atomic_dec(&dst->__refcnt);
+               newrefcnt = atomic_dec_return(&dst->__refcnt);
+               WARN_ON(newrefcnt < 0);
 	}
 }
 EXPORT_SYMBOL(dst_release);
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 14ada53..947710a 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -528,6 +528,22 @@
 	return dev->ethtool_ops->set_tx_csum(dev, edata.data);
 }
 
+static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!dev->ethtool_ops->set_rx_csum)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	if (!edata.data && dev->ethtool_ops->set_sg)
+		dev->features &= ~NETIF_F_GRO;
+
+	return dev->ethtool_ops->set_rx_csum(dev, edata.data);
+}
+
 static int ethtool_set_sg(struct net_device *dev, char __user *useraddr)
 {
 	struct ethtool_value edata;
@@ -599,6 +615,34 @@
 	return 0;
 }
 
+static int ethtool_get_gro(struct net_device *dev, char __user *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GGRO };
+
+	edata.data = dev->features & NETIF_F_GRO;
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		 return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_gro(struct net_device *dev, char __user *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	if (edata.data) {
+		if (!dev->ethtool_ops->get_rx_csum ||
+		    !dev->ethtool_ops->get_rx_csum(dev))
+			return -EINVAL;
+		dev->features |= NETIF_F_GRO;
+	} else
+		dev->features &= ~NETIF_F_GRO;
+
+	return 0;
+}
+
 static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
 {
 	struct ethtool_test test;
@@ -932,8 +976,7 @@
 				       dev->ethtool_ops->get_rx_csum);
 		break;
 	case ETHTOOL_SRXCSUM:
-		rc = ethtool_set_value(dev, useraddr,
-				       dev->ethtool_ops->set_rx_csum);
+		rc = ethtool_set_rx_csum(dev, useraddr);
 		break;
 	case ETHTOOL_GTXCSUM:
 		rc = ethtool_get_value(dev, useraddr, ethcmd,
@@ -1014,6 +1057,12 @@
 	case ETHTOOL_SRXFH:
 		rc = ethtool_set_rxhash(dev, useraddr);
 		break;
+	case ETHTOOL_GGRO:
+		rc = ethtool_get_gro(dev, useraddr);
+		break;
+	case ETHTOOL_SGRO:
+		rc = ethtool_set_gro(dev, useraddr);
+		break;
 	default:
 		rc = -EOPNOTSUPP;
 	}
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 79de3b1..32b3a01 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -664,17 +664,18 @@
 	rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL);
 	rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule);
 
-	err = register_netdevice_notifier(&fib_rules_notifier);
+	err = register_pernet_subsys(&fib_rules_net_ops);
 	if (err < 0)
 		goto fail;
 
-	err = register_pernet_subsys(&fib_rules_net_ops);
+	err = register_netdevice_notifier(&fib_rules_notifier);
 	if (err < 0)
 		goto fail_unregister;
+
 	return 0;
 
 fail_unregister:
-	unregister_netdevice_notifier(&fib_rules_notifier);
+	unregister_pernet_subsys(&fib_rules_net_ops);
 fail:
 	rtnl_unregister(PF_UNSPEC, RTM_NEWRULE);
 	rtnl_unregister(PF_UNSPEC, RTM_DELRULE);
diff --git a/net/core/filter.c b/net/core/filter.c
index df37443..d1d779c 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -319,6 +319,25 @@
 				A = 0;
 			continue;
 		}
+		case SKF_AD_NLATTR_NEST: {
+			struct nlattr *nla;
+
+			if (skb_is_nonlinear(skb))
+				return 0;
+			if (A > skb->len - sizeof(struct nlattr))
+				return 0;
+
+			nla = (struct nlattr *)&skb->data[A];
+			if (nla->nla_len > A - skb->len)
+				return 0;
+
+			nla = nla_find_nested(nla, X);
+			if (nla)
+				A = (void *)nla - (void *)skb->data;
+			else
+				A = 0;
+			continue;
+		}
 		default:
 			return 0;
 		}
diff --git a/net/core/flow.c b/net/core/flow.c
index 5cf8105..9601587 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -165,7 +165,7 @@
 	return 0;
 }
 
-void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
+void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir,
 			flow_resolve_t resolver)
 {
 	struct flow_cache_entry *fle, **head;
@@ -225,7 +225,7 @@
 		void *obj;
 		atomic_t *obj_ref;
 
-		err = resolver(key, family, dir, &obj, &obj_ref);
+		err = resolver(net, key, family, dir, &obj, &obj_ref);
 
 		if (fle && !err) {
 			fle->genid = atomic_read(&flow_cache_genid);
@@ -307,7 +307,7 @@
 	put_online_cpus();
 }
 
-static void __devinit flow_cache_cpu_prepare(int cpu)
+static void __init flow_cache_cpu_prepare(int cpu)
 {
 	struct tasklet_struct *tasklet;
 	unsigned long order;
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index 57abe82..9cc9f95 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -31,6 +31,7 @@
 #include <linux/skbuff.h>
 #include <linux/rtnetlink.h>
 #include <linux/init.h>
+#include <linux/rbtree.h>
 #include <net/sock.h>
 #include <net/gen_stats.h>
 
@@ -89,6 +90,7 @@
 	u32			avpps;
 	u32			avbps;
 	struct rcu_head		e_rcu;
+	struct rb_node		node;
 };
 
 struct gen_estimator_head
@@ -102,6 +104,9 @@
 /* Protects against NULL dereference */
 static DEFINE_RWLOCK(est_lock);
 
+/* Protects against soft lockup during large deletion */
+static struct rb_root est_root = RB_ROOT;
+
 static void est_timer(unsigned long arg)
 {
 	int idx = (int)arg;
@@ -139,6 +144,46 @@
 	rcu_read_unlock();
 }
 
+static void gen_add_node(struct gen_estimator *est)
+{
+	struct rb_node **p = &est_root.rb_node, *parent = NULL;
+
+	while (*p) {
+		struct gen_estimator *e;
+
+		parent = *p;
+		e = rb_entry(parent, struct gen_estimator, node);
+
+		if (est->bstats > e->bstats)
+			p = &parent->rb_right;
+		else
+			p = &parent->rb_left;
+	}
+	rb_link_node(&est->node, parent, p);
+	rb_insert_color(&est->node, &est_root);
+}
+
+static
+struct gen_estimator *gen_find_node(const struct gnet_stats_basic *bstats,
+				    const struct gnet_stats_rate_est *rate_est)
+{
+	struct rb_node *p = est_root.rb_node;
+
+	while (p) {
+		struct gen_estimator *e;
+
+		e = rb_entry(p, struct gen_estimator, node);
+
+		if (bstats > e->bstats)
+			p = p->rb_right;
+		else if (bstats < e->bstats || rate_est != e->rate_est)
+			p = p->rb_left;
+		else
+			return e;
+	}
+	return NULL;
+}
+
 /**
  * gen_new_estimator - create a new rate estimator
  * @bstats: basic statistics
@@ -194,8 +239,11 @@
 		mod_timer(&elist[idx].timer, jiffies + ((HZ/4) << idx));
 
 	list_add_rcu(&est->list, &elist[idx].list);
+	gen_add_node(est);
+
 	return 0;
 }
+EXPORT_SYMBOL(gen_new_estimator);
 
 static void __gen_kill_estimator(struct rcu_head *head)
 {
@@ -209,36 +257,27 @@
  * @bstats: basic statistics
  * @rate_est: rate estimator statistics
  *
- * Removes the rate estimator specified by &bstats and &rate_est
- * and deletes the timer.
+ * Removes the rate estimator specified by &bstats and &rate_est.
  *
  * NOTE: Called under rtnl_mutex
  */
 void gen_kill_estimator(struct gnet_stats_basic *bstats,
-	struct gnet_stats_rate_est *rate_est)
+			struct gnet_stats_rate_est *rate_est)
 {
-	int idx;
-	struct gen_estimator *e, *n;
+	struct gen_estimator *e;
 
-	for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
+	while ((e = gen_find_node(bstats, rate_est))) {
+		rb_erase(&e->node, &est_root);
 
-		/* Skip non initialized indexes */
-		if (!elist[idx].timer.function)
-			continue;
+		write_lock_bh(&est_lock);
+		e->bstats = NULL;
+		write_unlock_bh(&est_lock);
 
-		list_for_each_entry_safe(e, n, &elist[idx].list, list) {
-			if (e->rate_est != rate_est || e->bstats != bstats)
-				continue;
-
-			write_lock_bh(&est_lock);
-			e->bstats = NULL;
-			write_unlock_bh(&est_lock);
-
-			list_del_rcu(&e->list);
-			call_rcu(&e->e_rcu, __gen_kill_estimator);
-		}
+		list_del_rcu(&e->list);
+		call_rcu(&e->e_rcu, __gen_kill_estimator);
 	}
 }
+EXPORT_SYMBOL(gen_kill_estimator);
 
 /**
  * gen_replace_estimator - replace rate estimator configuration
@@ -259,8 +298,20 @@
 	gen_kill_estimator(bstats, rate_est);
 	return gen_new_estimator(bstats, rate_est, stats_lock, opt);
 }
-
-
-EXPORT_SYMBOL(gen_kill_estimator);
-EXPORT_SYMBOL(gen_new_estimator);
 EXPORT_SYMBOL(gen_replace_estimator);
+
+/**
+ * gen_estimator_active - test if estimator is currently in use
+ * @bstats: basic statistics
+ * @rate_est: rate estimator statistics
+ *
+ * Returns true if estimator is active, and false if not.
+ */
+bool gen_estimator_active(const struct gnet_stats_basic *bstats,
+			  const struct gnet_stats_rate_est *rate_est)
+{
+	ASSERT_RTNL();
+
+	return gen_find_node(bstats, rate_est) != NULL;
+}
+EXPORT_SYMBOL(gen_estimator_active);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 1dc728b..9c3717a 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -531,9 +531,7 @@
 	if (!n)
 		goto out;
 
-#ifdef CONFIG_NET_NS
-	n->net = hold_net(net);
-#endif
+	write_pnet(&n->net, hold_net(net));
 	memcpy(n->key, pkey, key_len);
 	n->dev = dev;
 	if (dev)
@@ -1329,9 +1327,9 @@
 				      struct neigh_table *tbl)
 {
 	struct neigh_parms *p, *ref;
-	struct net *net;
+	struct net *net = dev_net(dev);
+	const struct net_device_ops *ops = dev->netdev_ops;
 
-	net = dev_net(dev);
 	ref = lookup_neigh_params(tbl, net, 0);
 	if (!ref)
 		return NULL;
@@ -1340,20 +1338,17 @@
 	if (p) {
 		p->tbl		  = tbl;
 		atomic_set(&p->refcnt, 1);
-		INIT_RCU_HEAD(&p->rcu_head);
 		p->reachable_time =
 				neigh_rand_reach_time(p->base_reachable_time);
 
-		if (dev->neigh_setup && dev->neigh_setup(dev, p)) {
+		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
 			kfree(p);
 			return NULL;
 		}
 
 		dev_hold(dev);
 		p->dev = dev;
-#ifdef CONFIG_NET_NS
-		p->net = hold_net(net);
-#endif
+		write_pnet(&p->net, hold_net(net));
 		p->sysctl_table = NULL;
 		write_lock_bh(&tbl->lock);
 		p->next		= tbl->parms.next;
@@ -1408,11 +1403,8 @@
 	unsigned long now = jiffies;
 	unsigned long phsize;
 
-#ifdef CONFIG_NET_NS
-	tbl->parms.net = &init_net;
-#endif
+	write_pnet(&tbl->parms.net, &init_net);
 	atomic_set(&tbl->parms.refcnt, 1);
-	INIT_RCU_HEAD(&tbl->parms.rcu_head);
 	tbl->parms.reachable_time =
 			  neigh_rand_reach_time(tbl->parms.base_reachable_time);
 
@@ -1426,9 +1418,8 @@
 		panic("cannot create neighbour cache statistics");
 
 #ifdef CONFIG_PROC_FS
-	tbl->pde = proc_create_data(tbl->id, 0, init_net.proc_net_stat,
-				    &neigh_stat_seq_fops, tbl);
-	if (!tbl->pde)
+	if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
+			      &neigh_stat_seq_fops, tbl))
 		panic("cannot create neighbour proc dir entry");
 #endif
 
@@ -2568,128 +2559,128 @@
 			.procname	= "mcast_solicit",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec,
+			.proc_handler	= proc_dointvec,
 		},
 		{
 			.ctl_name	= NET_NEIGH_UCAST_SOLICIT,
 			.procname	= "ucast_solicit",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec,
+			.proc_handler	= proc_dointvec,
 		},
 		{
 			.ctl_name	= NET_NEIGH_APP_SOLICIT,
 			.procname	= "app_solicit",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec,
+			.proc_handler	= proc_dointvec,
 		},
 		{
 			.procname	= "retrans_time",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec_userhz_jiffies,
+			.proc_handler	= proc_dointvec_userhz_jiffies,
 		},
 		{
 			.ctl_name	= NET_NEIGH_REACHABLE_TIME,
 			.procname	= "base_reachable_time",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec_jiffies,
-			.strategy	= &sysctl_jiffies,
+			.proc_handler	= proc_dointvec_jiffies,
+			.strategy	= sysctl_jiffies,
 		},
 		{
 			.ctl_name	= NET_NEIGH_DELAY_PROBE_TIME,
 			.procname	= "delay_first_probe_time",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec_jiffies,
-			.strategy	= &sysctl_jiffies,
+			.proc_handler	= proc_dointvec_jiffies,
+			.strategy	= sysctl_jiffies,
 		},
 		{
 			.ctl_name	= NET_NEIGH_GC_STALE_TIME,
 			.procname	= "gc_stale_time",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec_jiffies,
-			.strategy	= &sysctl_jiffies,
+			.proc_handler	= proc_dointvec_jiffies,
+			.strategy	= sysctl_jiffies,
 		},
 		{
 			.ctl_name	= NET_NEIGH_UNRES_QLEN,
 			.procname	= "unres_qlen",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec,
+			.proc_handler	= proc_dointvec,
 		},
 		{
 			.ctl_name	= NET_NEIGH_PROXY_QLEN,
 			.procname	= "proxy_qlen",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec,
+			.proc_handler	= proc_dointvec,
 		},
 		{
 			.procname	= "anycast_delay",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec_userhz_jiffies,
+			.proc_handler	= proc_dointvec_userhz_jiffies,
 		},
 		{
 			.procname	= "proxy_delay",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec_userhz_jiffies,
+			.proc_handler	= proc_dointvec_userhz_jiffies,
 		},
 		{
 			.procname	= "locktime",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec_userhz_jiffies,
+			.proc_handler	= proc_dointvec_userhz_jiffies,
 		},
 		{
 			.ctl_name	= NET_NEIGH_RETRANS_TIME_MS,
 			.procname	= "retrans_time_ms",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec_ms_jiffies,
-			.strategy	= &sysctl_ms_jiffies,
+			.proc_handler	= proc_dointvec_ms_jiffies,
+			.strategy	= sysctl_ms_jiffies,
 		},
 		{
 			.ctl_name	= NET_NEIGH_REACHABLE_TIME_MS,
 			.procname	= "base_reachable_time_ms",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec_ms_jiffies,
-			.strategy	= &sysctl_ms_jiffies,
+			.proc_handler	= proc_dointvec_ms_jiffies,
+			.strategy	= sysctl_ms_jiffies,
 		},
 		{
 			.ctl_name	= NET_NEIGH_GC_INTERVAL,
 			.procname	= "gc_interval",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec_jiffies,
-			.strategy	= &sysctl_jiffies,
+			.proc_handler	= proc_dointvec_jiffies,
+			.strategy	= sysctl_jiffies,
 		},
 		{
 			.ctl_name	= NET_NEIGH_GC_THRESH1,
 			.procname	= "gc_thresh1",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec,
+			.proc_handler	= proc_dointvec,
 		},
 		{
 			.ctl_name	= NET_NEIGH_GC_THRESH2,
 			.procname	= "gc_thresh2",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec,
+			.proc_handler	= proc_dointvec,
 		},
 		{
 			.ctl_name	= NET_NEIGH_GC_THRESH3,
 			.procname	= "gc_thresh3",
 			.maxlen		= sizeof(int),
 			.mode		= 0644,
-			.proc_handler	= &proc_dointvec,
+			.proc_handler	= proc_dointvec,
 		},
 		{},
 	},
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 92d6b94..6ac29a4 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -270,7 +270,6 @@
 			    unsigned long offset)
 {
 	struct net_device *dev = to_net_dev(d);
-	struct net_device_stats *stats;
 	ssize_t ret = -EINVAL;
 
 	WARN_ON(offset > sizeof(struct net_device_stats) ||
@@ -278,7 +277,7 @@
 
 	read_lock(&dev_base_lock);
 	if (dev_isalive(dev)) {
-		stats = dev->get_stats(dev);
+		const struct net_device_stats *stats = dev_get_stats(dev);
 		ret = sprintf(buf, fmt_ulong,
 			      *(unsigned long *)(((u8 *) stats) + offset));
 	}
@@ -428,6 +427,9 @@
 	struct net_device *dev = to_net_dev(d);
 	int retval;
 
+	if (!net_eq(dev_net(dev), &init_net))
+		return 0;
+
 	/* pass interface to uevent. */
 	retval = add_uevent_var(env, "INTERFACE=%s", dev->name);
 	if (retval)
@@ -476,6 +478,10 @@
 	struct device *dev = &(net->dev);
 
 	kobject_get(&dev->kobj);
+
+	if (dev_net(net) != &init_net)
+		return;
+
 	device_del(dev);
 }
 
@@ -490,7 +496,7 @@
 	dev->groups = groups;
 
 	BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ);
-	strlcpy(dev->bus_id, net->name, BUS_ID_SIZE);
+	dev_set_name(dev, net->name);
 
 #ifdef CONFIG_SYSFS
 	*groups++ = &netstat_group;
@@ -501,6 +507,9 @@
 #endif
 #endif /* CONFIG_SYSFS */
 
+	if (dev_net(net) != &init_net)
+		return 0;
+
 	return device_add(dev);
 }
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 1895a4c..55cffad 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -47,7 +47,6 @@
 		goto out;
 
 	ng->len = INITIAL_NET_GEN_PTRS;
-	INIT_RCU_HEAD(&ng->rcu);
 	rcu_assign_pointer(net->gen, ng);
 
 	error = 0;
@@ -478,7 +477,6 @@
 	 */
 
 	ng->len = id;
-	INIT_RCU_HEAD(&ng->rcu);
 	memcpy(&ng->ptr, &old_ng->ptr, old_ng->len);
 
 	rcu_assign_pointer(net->gen, ng);
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index dadac62..755414c 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -58,6 +58,7 @@
 
 	while ((skb = skb_dequeue(&npinfo->txq))) {
 		struct net_device *dev = skb->dev;
+		const struct net_device_ops *ops = dev->netdev_ops;
 		struct netdev_queue *txq;
 
 		if (!netif_device_present(dev) || !netif_running(dev)) {
@@ -71,7 +72,7 @@
 		__netif_tx_lock(txq, smp_processor_id());
 		if (netif_tx_queue_stopped(txq) ||
 		    netif_tx_queue_frozen(txq) ||
-		    dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) {
+		    ops->ndo_start_xmit(skb, dev) != NETDEV_TX_OK) {
 			skb_queue_head(&npinfo->txq, skb);
 			__netif_tx_unlock(txq);
 			local_irq_restore(flags);
@@ -174,12 +175,13 @@
 void netpoll_poll(struct netpoll *np)
 {
 	struct net_device *dev = np->dev;
+	const struct net_device_ops *ops = dev->netdev_ops;
 
-	if (!dev || !netif_running(dev) || !dev->poll_controller)
+	if (!dev || !netif_running(dev) || !ops->ndo_poll_controller)
 		return;
 
 	/* Process pending work on NIC */
-	dev->poll_controller(dev);
+	ops->ndo_poll_controller(dev);
 
 	poll_napi(dev);
 
@@ -274,6 +276,7 @@
 	int status = NETDEV_TX_BUSY;
 	unsigned long tries;
 	struct net_device *dev = np->dev;
+	const struct net_device_ops *ops = dev->netdev_ops;
 	struct netpoll_info *npinfo = np->dev->npinfo;
 
 	if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) {
@@ -294,7 +297,7 @@
 		     tries > 0; --tries) {
 			if (__netif_tx_trylock(txq)) {
 				if (!netif_tx_queue_stopped(txq))
-					status = dev->hard_start_xmit(skb, dev);
+					status = ops->ndo_start_xmit(skb, dev);
 				__netif_tx_unlock(txq);
 
 				if (status == NETDEV_TX_OK)
@@ -345,7 +348,7 @@
 	udph->check = csum_tcpudp_magic(htonl(np->local_ip),
 					htonl(np->remote_ip),
 					udp_len, IPPROTO_UDP,
-					csum_partial((unsigned char *)udph, udp_len, 0));
+					csum_partial(udph, udp_len, 0));
 	if (udph->check == 0)
 		udph->check = CSUM_MANGLED_0;
 
@@ -555,7 +558,6 @@
 
 void netpoll_print_options(struct netpoll *np)
 {
-	DECLARE_MAC_BUF(mac);
 	printk(KERN_INFO "%s: local port %d\n",
 			 np->name, np->local_port);
 	printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n",
@@ -566,8 +568,8 @@
 			 np->name, np->remote_port);
 	printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n",
 			 np->name, HIPQUAD(np->remote_ip));
-	printk(KERN_INFO "%s: remote ethernet address %s\n",
-	                 np->name, print_mac(mac, np->remote_mac));
+	printk(KERN_INFO "%s: remote ethernet address %pM\n",
+	                 np->name, np->remote_mac);
 }
 
 int netpoll_parse_options(struct netpoll *np, char *opt)
@@ -697,7 +699,7 @@
 		atomic_inc(&npinfo->refcnt);
 	}
 
-	if (!ndev->poll_controller) {
+	if (!ndev->netdev_ops->ndo_poll_controller) {
 		printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
 		       np->name, np->dev_name);
 		err = -ENOTSUPP;
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 8997e91..6549848 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -422,6 +422,7 @@
 					  const char *ifname);
 static int pktgen_device_event(struct notifier_block *, unsigned long, void *);
 static void pktgen_run_all_threads(void);
+static void pktgen_reset_all_threads(void);
 static void pktgen_stop_all_threads_ifs(void);
 static int pktgen_stop_device(struct pktgen_dev *pkt_dev);
 static void pktgen_stop(struct pktgen_thread *t);
@@ -480,6 +481,9 @@
 	else if (!strcmp(data, "start"))
 		pktgen_run_all_threads();
 
+	else if (!strcmp(data, "reset"))
+		pktgen_reset_all_threads();
+
 	else
 		printk(KERN_WARNING "pktgen: Unknown command: %s\n", data);
 
@@ -509,7 +513,6 @@
 	__u64 sa;
 	__u64 stopped;
 	__u64 now = getCurUs();
-	DECLARE_MAC_BUF(mac);
 
 	seq_printf(seq,
 		   "Params: count %llu  min_pkt_size: %u  max_pkt_size: %u\n",
@@ -554,12 +557,12 @@
 
 	seq_puts(seq, "     src_mac: ");
 
-	seq_printf(seq, "%s ",
-		   print_mac(mac, is_zero_ether_addr(pkt_dev->src_mac) ?
-			     pkt_dev->odev->dev_addr : pkt_dev->src_mac));
+	seq_printf(seq, "%pM ",
+		   is_zero_ether_addr(pkt_dev->src_mac) ?
+			     pkt_dev->odev->dev_addr : pkt_dev->src_mac);
 
 	seq_printf(seq, "dst_mac: ");
-	seq_printf(seq, "%s\n", print_mac(mac, pkt_dev->dst_mac));
+	seq_printf(seq, "%pM\n", pkt_dev->dst_mac);
 
 	seq_printf(seq,
 		   "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
@@ -2162,7 +2165,8 @@
 	struct xfrm_state *x = pkt_dev->flows[flow].x;
 	if (!x) {
 		/*slow path: we dont already have xfrm_state*/
-		x = xfrm_stateonly_find((xfrm_address_t *)&pkt_dev->cur_daddr,
+		x = xfrm_stateonly_find(&init_net,
+					(xfrm_address_t *)&pkt_dev->cur_daddr,
 					(xfrm_address_t *)&pkt_dev->cur_saddr,
 					AF_INET,
 					pkt_dev->ipsmode,
@@ -3169,6 +3173,24 @@
 	pktgen_wait_all_threads_run();
 }
 
+static void pktgen_reset_all_threads(void)
+{
+	struct pktgen_thread *t;
+
+	pr_debug("pktgen: entering pktgen_reset_all_threads.\n");
+
+	mutex_lock(&pktgen_thread_lock);
+
+	list_for_each_entry(t, &pktgen_threads, th_list)
+		t->control |= (T_REMDEVALL);
+
+	mutex_unlock(&pktgen_thread_lock);
+
+	schedule_timeout_interruptible(msecs_to_jiffies(125));	/* Propagate thread->control  */
+
+	pktgen_wait_all_threads_run();
+}
+
 static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
 {
 	__u64 total_us, bps, mbps, pps, idle;
@@ -3331,14 +3353,14 @@
 
 static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 {
-	struct net_device *odev = NULL;
+	struct net_device *odev = pkt_dev->odev;
+	int (*xmit)(struct sk_buff *, struct net_device *)
+		= odev->netdev_ops->ndo_start_xmit;
 	struct netdev_queue *txq;
 	__u64 idle_start = 0;
 	u16 queue_map;
 	int ret;
 
-	odev = pkt_dev->odev;
-
 	if (pkt_dev->delay_us || pkt_dev->delay_ns) {
 		u64 now;
 
@@ -3419,7 +3441,7 @@
 
 		atomic_inc(&(pkt_dev->skb->users));
 	      retry_now:
-		ret = odev->hard_start_xmit(pkt_dev->skb, odev);
+		ret = (*xmit)(pkt_dev->skb, odev);
 		if (likely(ret == NETDEV_TX_OK)) {
 			pkt_dev->last_ok = 1;
 			pkt_dev->sofar++;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 4dfb6b4..790dd20 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -551,7 +551,7 @@
 }
 
 static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
-				 struct net_device_stats *b)
+				 const struct net_device_stats *b)
 {
 	a->rx_packets = b->rx_packets;
 	a->tx_packets = b->tx_packets;
@@ -609,7 +609,7 @@
 	struct netdev_queue *txq;
 	struct ifinfomsg *ifm;
 	struct nlmsghdr *nlh;
-	struct net_device_stats *stats;
+	const struct net_device_stats *stats;
 	struct nlattr *attr;
 
 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
@@ -666,7 +666,7 @@
 	if (attr == NULL)
 		goto nla_put_failure;
 
-	stats = dev->get_stats(dev);
+	stats = dev_get_stats(dev);
 	copy_rtnl_link_stats(nla_data(attr), stats);
 
 	if (dev->rtnl_link_ops) {
@@ -762,6 +762,7 @@
 static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
 		      struct nlattr **tb, char *ifname, int modified)
 {
+	const struct net_device_ops *ops = dev->netdev_ops;
 	int send_addr_notify = 0;
 	int err;
 
@@ -783,7 +784,7 @@
 		struct rtnl_link_ifmap *u_map;
 		struct ifmap k_map;
 
-		if (!dev->set_config) {
+		if (!ops->ndo_set_config) {
 			err = -EOPNOTSUPP;
 			goto errout;
 		}
@@ -801,7 +802,7 @@
 		k_map.dma = (unsigned char) u_map->dma;
 		k_map.port = (unsigned char) u_map->port;
 
-		err = dev->set_config(dev, &k_map);
+		err = ops->ndo_set_config(dev, &k_map);
 		if (err < 0)
 			goto errout;
 
@@ -812,7 +813,7 @@
 		struct sockaddr *sa;
 		int len;
 
-		if (!dev->set_mac_address) {
+		if (!ops->ndo_set_mac_address) {
 			err = -EOPNOTSUPP;
 			goto errout;
 		}
@@ -831,7 +832,7 @@
 		sa->sa_family = dev->type;
 		memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
 		       dev->addr_len);
-		err = dev->set_mac_address(dev, sa);
+		err = ops->ndo_set_mac_address(dev, sa);
 		kfree(sa);
 		if (err)
 			goto errout;
diff --git a/net/core/scm.c b/net/core/scm.c
index b12303d..b7ba91b 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -44,11 +44,13 @@
 
 static __inline__ int scm_check_creds(struct ucred *creds)
 {
+	const struct cred *cred = current_cred();
+
 	if ((creds->pid == task_tgid_vnr(current) || capable(CAP_SYS_ADMIN)) &&
-	    ((creds->uid == current->uid || creds->uid == current->euid ||
-	      creds->uid == current->suid) || capable(CAP_SETUID)) &&
-	    ((creds->gid == current->gid || creds->gid == current->egid ||
-	      creds->gid == current->sgid) || capable(CAP_SETGID))) {
+	    ((creds->uid == cred->uid   || creds->uid == cred->euid ||
+	      creds->uid == cred->suid) || capable(CAP_SETUID)) &&
+	    ((creds->gid == cred->gid   || creds->gid == cred->egid ||
+	      creds->gid == cred->sgid) || capable(CAP_SETGID))) {
 	       return 0;
 	}
 	return -EPERM;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 65f7757..b8d0abb 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -501,7 +501,7 @@
 	new->network_header	= old->network_header;
 	new->mac_header		= old->mac_header;
 	new->dst		= dst_clone(old->dst);
-#ifdef CONFIG_INET
+#ifdef CONFIG_XFRM
 	new->sp			= secpath_get(old->sp);
 #endif
 	memcpy(new->cb, old->cb, sizeof(old->cb));
@@ -556,6 +556,7 @@
 	C(truesize);
 #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
 	C(do_not_encrypt);
+	C(requeue);
 #endif
 	atomic_set(&n->users, 1);
 
@@ -2017,6 +2018,148 @@
 		skb_split_no_header(skb, skb1, len, pos);
 }
 
+/* Shifting from/to a cloned skb is a no-go.
+ *
+ * Caller cannot keep skb_shinfo related pointers past calling here!
+ */
+static int skb_prepare_for_shift(struct sk_buff *skb)
+{
+	return skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+}
+
+/**
+ * skb_shift - Shifts paged data partially from skb to another
+ * @tgt: buffer into which tail data gets added
+ * @skb: buffer from which the paged data comes from
+ * @shiftlen: shift up to this many bytes
+ *
+ * Attempts to shift up to shiftlen worth of bytes, which may be less than
+ * the length of the skb, from tgt to skb. Returns number bytes shifted.
+ * It's up to caller to free skb if everything was shifted.
+ *
+ * If @tgt runs out of frags, the whole operation is aborted.
+ *
+ * Skb cannot include anything else but paged data while tgt is allowed
+ * to have non-paged data as well.
+ *
+ * TODO: full sized shift could be optimized but that would need
+ * specialized skb free'er to handle frags without up-to-date nr_frags.
+ */
+int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
+{
+	int from, to, merge, todo;
+	struct skb_frag_struct *fragfrom, *fragto;
+
+	BUG_ON(shiftlen > skb->len);
+	BUG_ON(skb_headlen(skb));	/* Would corrupt stream */
+
+	todo = shiftlen;
+	from = 0;
+	to = skb_shinfo(tgt)->nr_frags;
+	fragfrom = &skb_shinfo(skb)->frags[from];
+
+	/* Actual merge is delayed until the point when we know we can
+	 * commit all, so that we don't have to undo partial changes
+	 */
+	if (!to ||
+	    !skb_can_coalesce(tgt, to, fragfrom->page, fragfrom->page_offset)) {
+		merge = -1;
+	} else {
+		merge = to - 1;
+
+		todo -= fragfrom->size;
+		if (todo < 0) {
+			if (skb_prepare_for_shift(skb) ||
+			    skb_prepare_for_shift(tgt))
+				return 0;
+
+			/* All previous frag pointers might be stale! */
+			fragfrom = &skb_shinfo(skb)->frags[from];
+			fragto = &skb_shinfo(tgt)->frags[merge];
+
+			fragto->size += shiftlen;
+			fragfrom->size -= shiftlen;
+			fragfrom->page_offset += shiftlen;
+
+			goto onlymerged;
+		}
+
+		from++;
+	}
+
+	/* Skip full, not-fitting skb to avoid expensive operations */
+	if ((shiftlen == skb->len) &&
+	    (skb_shinfo(skb)->nr_frags - from) > (MAX_SKB_FRAGS - to))
+		return 0;
+
+	if (skb_prepare_for_shift(skb) || skb_prepare_for_shift(tgt))
+		return 0;
+
+	while ((todo > 0) && (from < skb_shinfo(skb)->nr_frags)) {
+		if (to == MAX_SKB_FRAGS)
+			return 0;
+
+		fragfrom = &skb_shinfo(skb)->frags[from];
+		fragto = &skb_shinfo(tgt)->frags[to];
+
+		if (todo >= fragfrom->size) {
+			*fragto = *fragfrom;
+			todo -= fragfrom->size;
+			from++;
+			to++;
+
+		} else {
+			get_page(fragfrom->page);
+			fragto->page = fragfrom->page;
+			fragto->page_offset = fragfrom->page_offset;
+			fragto->size = todo;
+
+			fragfrom->page_offset += todo;
+			fragfrom->size -= todo;
+			todo = 0;
+
+			to++;
+			break;
+		}
+	}
+
+	/* Ready to "commit" this state change to tgt */
+	skb_shinfo(tgt)->nr_frags = to;
+
+	if (merge >= 0) {
+		fragfrom = &skb_shinfo(skb)->frags[0];
+		fragto = &skb_shinfo(tgt)->frags[merge];
+
+		fragto->size += fragfrom->size;
+		put_page(fragfrom->page);
+	}
+
+	/* Reposition in the original skb */
+	to = 0;
+	while (from < skb_shinfo(skb)->nr_frags)
+		skb_shinfo(skb)->frags[to++] = skb_shinfo(skb)->frags[from++];
+	skb_shinfo(skb)->nr_frags = to;
+
+	BUG_ON(todo > 0 && !skb_shinfo(skb)->nr_frags);
+
+onlymerged:
+	/* Most likely the tgt won't ever need its checksum anymore, skb on
+	 * the other hand might need it if it needs to be resent
+	 */
+	tgt->ip_summed = CHECKSUM_PARTIAL;
+	skb->ip_summed = CHECKSUM_PARTIAL;
+
+	/* Yak, is it really working this way? Some helper please? */
+	skb->len -= shiftlen;
+	skb->data_len -= shiftlen;
+	skb->truesize -= shiftlen;
+	tgt->len += shiftlen;
+	tgt->data_len += shiftlen;
+	tgt->truesize += shiftlen;
+
+	return shiftlen;
+}
+
 /**
  * skb_prepare_seq_read - Prepare a sequential read of skb data
  * @skb: the buffer to read
@@ -2285,6 +2428,7 @@
 {
 	struct sk_buff *segs = NULL;
 	struct sk_buff *tail = NULL;
+	struct sk_buff *fskb = skb_shinfo(skb)->frag_list;
 	unsigned int mss = skb_shinfo(skb)->gso_size;
 	unsigned int doffset = skb->data - skb_mac_header(skb);
 	unsigned int offset = doffset;
@@ -2304,7 +2448,6 @@
 		struct sk_buff *nskb;
 		skb_frag_t *frag;
 		int hsize;
-		int k;
 		int size;
 
 		len = skb->len - offset;
@@ -2317,9 +2460,36 @@
 		if (hsize > len || !sg)
 			hsize = len;
 
-		nskb = alloc_skb(hsize + doffset + headroom, GFP_ATOMIC);
-		if (unlikely(!nskb))
-			goto err;
+		if (!hsize && i >= nfrags) {
+			BUG_ON(fskb->len != len);
+
+			pos += len;
+			nskb = skb_clone(fskb, GFP_ATOMIC);
+			fskb = fskb->next;
+
+			if (unlikely(!nskb))
+				goto err;
+
+			hsize = skb_end_pointer(nskb) - nskb->head;
+			if (skb_cow_head(nskb, doffset + headroom)) {
+				kfree_skb(nskb);
+				goto err;
+			}
+
+			nskb->truesize += skb_end_pointer(nskb) - nskb->head -
+					  hsize;
+			skb_release_head_state(nskb);
+			__skb_push(nskb, doffset);
+		} else {
+			nskb = alloc_skb(hsize + doffset + headroom,
+					 GFP_ATOMIC);
+
+			if (unlikely(!nskb))
+				goto err;
+
+			skb_reserve(nskb, headroom);
+			__skb_put(nskb, doffset);
+		}
 
 		if (segs)
 			tail->next = nskb;
@@ -2330,13 +2500,15 @@
 		__copy_skb_header(nskb, skb);
 		nskb->mac_len = skb->mac_len;
 
-		skb_reserve(nskb, headroom);
 		skb_reset_mac_header(nskb);
 		skb_set_network_header(nskb, skb->mac_len);
 		nskb->transport_header = (nskb->network_header +
 					  skb_network_header_len(skb));
-		skb_copy_from_linear_data(skb, skb_put(nskb, doffset),
-					  doffset);
+		skb_copy_from_linear_data(skb, nskb->data, doffset);
+
+		if (pos >= offset + len)
+			continue;
+
 		if (!sg) {
 			nskb->ip_summed = CHECKSUM_NONE;
 			nskb->csum = skb_copy_and_csum_bits(skb, offset,
@@ -2346,14 +2518,11 @@
 		}
 
 		frag = skb_shinfo(nskb)->frags;
-		k = 0;
 
 		skb_copy_from_linear_data_offset(skb, offset,
 						 skb_put(nskb, hsize), hsize);
 
-		while (pos < offset + len) {
-			BUG_ON(i >= nfrags);
-
+		while (pos < offset + len && i < nfrags) {
 			*frag = skb_shinfo(skb)->frags[i];
 			get_page(frag->page);
 			size = frag->size;
@@ -2363,20 +2532,39 @@
 				frag->size -= offset - pos;
 			}
 
-			k++;
+			skb_shinfo(nskb)->nr_frags++;
 
 			if (pos + size <= offset + len) {
 				i++;
 				pos += size;
 			} else {
 				frag->size -= pos + size - (offset + len);
-				break;
+				goto skip_fraglist;
 			}
 
 			frag++;
 		}
 
-		skb_shinfo(nskb)->nr_frags = k;
+		if (pos < offset + len) {
+			struct sk_buff *fskb2 = fskb;
+
+			BUG_ON(pos + fskb->len != offset + len);
+
+			pos += fskb->len;
+			fskb = fskb->next;
+
+			if (fskb2->next) {
+				fskb2 = skb_clone(fskb2, GFP_ATOMIC);
+				if (!fskb2)
+					goto err;
+			} else
+				skb_get(fskb2);
+
+			BUG_ON(skb_shinfo(nskb)->frag_list);
+			skb_shinfo(nskb)->frag_list = fskb2;
+		}
+
+skip_fraglist:
 		nskb->data_len = len - hsize;
 		nskb->len += nskb->data_len;
 		nskb->truesize += nskb->data_len;
@@ -2394,6 +2582,65 @@
 
 EXPORT_SYMBOL_GPL(skb_segment);
 
+int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
+{
+	struct sk_buff *p = *head;
+	struct sk_buff *nskb;
+	unsigned int headroom;
+	unsigned int hlen = p->data - skb_mac_header(p);
+
+	if (hlen + p->len + skb->len >= 65536)
+		return -E2BIG;
+
+	if (skb_shinfo(p)->frag_list)
+		goto merge;
+
+	headroom = skb_headroom(p);
+	nskb = netdev_alloc_skb(p->dev, headroom);
+	if (unlikely(!nskb))
+		return -ENOMEM;
+
+	__copy_skb_header(nskb, p);
+	nskb->mac_len = p->mac_len;
+
+	skb_reserve(nskb, headroom);
+
+	skb_set_mac_header(nskb, -hlen);
+	skb_set_network_header(nskb, skb_network_offset(p));
+	skb_set_transport_header(nskb, skb_transport_offset(p));
+
+	memcpy(skb_mac_header(nskb), skb_mac_header(p), hlen);
+
+	*NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);
+	skb_shinfo(nskb)->frag_list = p;
+	skb_header_release(p);
+	nskb->prev = p;
+
+	nskb->data_len += p->len;
+	nskb->truesize += p->len;
+	nskb->len += p->len;
+
+	*head = nskb;
+	nskb->next = p->next;
+	p->next = NULL;
+
+	p = nskb;
+
+merge:
+	NAPI_GRO_CB(p)->count++;
+	p->prev->next = skb;
+	p->prev = skb;
+	skb_header_release(skb);
+
+	p->data_len += skb->len;
+	p->truesize += skb->len;
+	p->len += skb->len;
+
+	NAPI_GRO_CB(skb)->same_flow = 1;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(skb_gro_receive);
+
 void __init skb_init(void)
 {
 	skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
diff --git a/net/core/sock.c b/net/core/sock.c
index edf7220..f3a0d08 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1071,7 +1071,7 @@
 		newsk->sk_sleep	 = NULL;
 
 		if (newsk->sk_prot->sockets_allocated)
-			atomic_inc(newsk->sk_prot->sockets_allocated);
+			percpu_counter_inc(newsk->sk_prot->sockets_allocated);
 	}
 out:
 	return newsk;
@@ -1463,8 +1463,12 @@
 	}
 
 	if (prot->memory_pressure) {
-		if (!*prot->memory_pressure ||
-		    prot->sysctl_mem[2] > atomic_read(prot->sockets_allocated) *
+		int alloc;
+
+		if (!*prot->memory_pressure)
+			return 1;
+		alloc = percpu_counter_read_positive(prot->sockets_allocated);
+		if (prot->sysctl_mem[2] > alloc *
 		    sk_mem_pages(sk->sk_wmem_queued +
 				 atomic_read(&sk->sk_rmem_alloc) +
 				 sk->sk_forward_alloc))
@@ -2037,7 +2041,8 @@
 {
 	if (alloc_slab) {
 		prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0,
-					       SLAB_HWCACHE_ALIGN, NULL);
+					SLAB_HWCACHE_ALIGN | prot->slab_flags,
+					NULL);
 
 		if (prot->slab == NULL) {
 			printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n",
@@ -2076,7 +2081,9 @@
 			prot->twsk_prot->twsk_slab =
 				kmem_cache_create(prot->twsk_prot->twsk_slab_name,
 						  prot->twsk_prot->twsk_obj_size,
-						  0, SLAB_HWCACHE_ALIGN,
+						  0,
+						  SLAB_HWCACHE_ALIGN |
+							prot->slab_flags,
 						  NULL);
 			if (prot->twsk_prot->twsk_slab == NULL)
 				goto out_free_timewait_sock_slab_name;
@@ -2164,7 +2171,7 @@
 			"%2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c\n",
 		   proto->name,
 		   proto->obj_size,
-		   proto->sockets_allocated != NULL ? atomic_read(proto->sockets_allocated) : -1,
+		   sock_prot_inuse_get(seq_file_net(seq), proto),
 		   proto->memory_allocated != NULL ? atomic_read(proto->memory_allocated) : -1,
 		   proto->memory_pressure != NULL ? *proto->memory_pressure ? "yes" : "no" : "NI",
 		   proto->max_header,
@@ -2218,7 +2225,8 @@
 
 static int proto_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open(file, &proto_seq_ops);
+	return seq_open_net(inode, file, &proto_seq_ops,
+			    sizeof(struct seq_net_private));
 }
 
 static const struct file_operations proto_seq_fops = {
@@ -2226,13 +2234,31 @@
 	.open		= proto_seq_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= seq_release,
+	.release	= seq_release_net,
+};
+
+static __net_init int proto_init_net(struct net *net)
+{
+	if (!proc_net_fops_create(net, "protocols", S_IRUGO, &proto_seq_fops))
+		return -ENOMEM;
+
+	return 0;
+}
+
+static __net_exit void proto_exit_net(struct net *net)
+{
+	proc_net_remove(net, "protocols");
+}
+
+
+static __net_initdata struct pernet_operations proto_net_ops = {
+	.init = proto_init_net,
+	.exit = proto_exit_net,
 };
 
 static int __init proto_init(void)
 {
-	/* register /proc/net/protocols */
-	return proc_net_fops_create(&init_net, "protocols", S_IRUGO, &proto_seq_fops) == NULL ? -ENOBUFS : 0;
+	return register_pernet_subsys(&proto_net_ops);
 }
 
 subsys_initcall(proto_init);
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index f686467..83d3398 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -12,7 +12,6 @@
 #include <linux/netdevice.h>
 #include <linux/init.h>
 #include <net/sock.h>
-#include <net/xfrm.h>
 
 static struct ctl_table net_core_table[] = {
 #ifdef CONFIG_NET
@@ -22,7 +21,7 @@
 		.data		= &sysctl_wmem_max,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_CORE_RMEM_MAX,
@@ -30,7 +29,7 @@
 		.data		= &sysctl_rmem_max,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_CORE_WMEM_DEFAULT,
@@ -38,7 +37,7 @@
 		.data		= &sysctl_wmem_default,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_CORE_RMEM_DEFAULT,
@@ -46,7 +45,7 @@
 		.data		= &sysctl_rmem_default,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_CORE_DEV_WEIGHT,
@@ -54,7 +53,7 @@
 		.data		= &weight_p,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_CORE_MAX_BACKLOG,
@@ -62,7 +61,7 @@
 		.data		= &netdev_max_backlog,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_CORE_MSG_COST,
@@ -70,8 +69,8 @@
 		.data		= &net_ratelimit_state.interval,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies,
 	},
 	{
 		.ctl_name	= NET_CORE_MSG_BURST,
@@ -79,7 +78,7 @@
 		.data		= &net_ratelimit_state.burst,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_CORE_OPTMEM_MAX,
@@ -87,42 +86,8 @@
 		.data		= &sysctl_optmem_max,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
-#ifdef CONFIG_XFRM
-	{
-		.ctl_name	= NET_CORE_AEVENT_ETIME,
-		.procname	= "xfrm_aevent_etime",
-		.data		= &sysctl_xfrm_aevent_etime,
-		.maxlen		= sizeof(u32),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
-		.ctl_name	= NET_CORE_AEVENT_RSEQTH,
-		.procname	= "xfrm_aevent_rseqth",
-		.data		= &sysctl_xfrm_aevent_rseqth,
-		.maxlen		= sizeof(u32),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
-		.ctl_name	= CTL_UNNUMBERED,
-		.procname	= "xfrm_larval_drop",
-		.data		= &sysctl_xfrm_larval_drop,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
-		.ctl_name	= CTL_UNNUMBERED,
-		.procname	= "xfrm_acq_expires",
-		.data		= &sysctl_xfrm_acq_expires,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-#endif /* CONFIG_XFRM */
 #endif /* CONFIG_NET */
 	{
 		.ctl_name	= NET_CORE_BUDGET,
@@ -130,7 +95,7 @@
 		.data		= &netdev_budget,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_CORE_WARNINGS,
@@ -138,7 +103,7 @@
 		.data		= &net_msg_warn,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{ .ctl_name = 0 }
 };
@@ -150,12 +115,12 @@
 		.data		= &init_net.core.sysctl_somaxconn,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{ .ctl_name = 0 }
 };
 
-static __net_initdata struct ctl_path net_core_path[] = {
+__net_initdata struct ctl_path net_core_path[] = {
 	{ .procname = "net", .ctl_name = CTL_NET, },
 	{ .procname = "core", .ctl_name = NET_CORE, },
 	{ },
@@ -207,8 +172,11 @@
 
 static __init int sysctl_core_init(void)
 {
+	static struct ctl_table empty[1];
+
+	register_sysctl_paths(net_core_path, empty);
 	register_net_sysctl_rotable(net_core_path, net_core_table);
 	return register_pernet_subsys(&sysctl_core_ops);
 }
 
-__initcall(sysctl_core_init);
+fs_initcall(sysctl_core_init);
diff --git a/net/dcb/Kconfig b/net/dcb/Kconfig
new file mode 100644
index 0000000..4066d59
--- /dev/null
+++ b/net/dcb/Kconfig
@@ -0,0 +1,22 @@
+config DCB
+	bool "Data Center Bridging support"
+	default n
+	---help---
+	  This enables support for configuring Data Center Bridging (DCB)
+	  features on DCB capable Ethernet adapters via rtnetlink.  Say 'Y'
+	  if you have a DCB capable Ethernet adapter which supports this
+	  interface and you are connected to a DCB capable switch.
+
+	  DCB is a collection of Ethernet enhancements which allow DCB capable
+	  NICs and switches to support network traffic with differing
+	  requirements (highly reliable, no drops vs. best effort vs. low
+	  latency) to co-exist on Ethernet.
+
+	  DCB features include:
+	    Enhanced Transmission Selection (aka Priority Grouping) - provides a
+	      framework for assigning bandwidth guarantees to traffic classes.
+	    Priority-based Flow Control (PFC) - a MAC control pause frame which
+	      works at the granularity of the 802.1p priority instead of the
+	      link (802.3x).
+
+	  If unsure, say N.
diff --git a/net/dcb/Makefile b/net/dcb/Makefile
new file mode 100644
index 0000000..9930f4c
--- /dev/null
+++ b/net/dcb/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_DCB) += dcbnl.o
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
new file mode 100644
index 0000000..5dbfe5f
--- /dev/null
+++ b/net/dcb/dcbnl.c
@@ -0,0 +1,1122 @@
+/*
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Lucy Liu <lucy.liu@intel.com>
+ */
+
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <net/netlink.h>
+#include <net/rtnetlink.h>
+#include <linux/dcbnl.h>
+#include <linux/rtnetlink.h>
+#include <net/sock.h>
+
+/**
+ * Data Center Bridging (DCB) is a collection of Ethernet enhancements
+ * intended to allow network traffic with differing requirements
+ * (highly reliable, no drops vs. best effort vs. low latency) to operate
+ * and co-exist on Ethernet.  Current DCB features are:
+ *
+ * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a
+ *   framework for assigning bandwidth guarantees to traffic classes.
+ *
+ * Priority-based Flow Control (PFC) - provides a flow control mechanism which
+ *   can work independently for each 802.1p priority.
+ *
+ * Congestion Notification - provides a mechanism for end-to-end congestion
+ *   control for protocols which do not have built-in congestion management.
+ *
+ * More information about the emerging standards for these Ethernet features
+ * can be found at: http://www.ieee802.org/1/pages/dcbridges.html
+ *
+ * This file implements an rtnetlink interface to allow configuration of DCB
+ * features for capable devices.
+ */
+
+MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>");
+MODULE_DESCRIPTION("Data Center Bridging netlink interface");
+MODULE_LICENSE("GPL");
+
+/**************** DCB attribute policies *************************************/
+
+/* DCB netlink attributes policy */
+static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
+	[DCB_ATTR_IFNAME]      = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1},
+	[DCB_ATTR_STATE]       = {.type = NLA_U8},
+	[DCB_ATTR_PFC_CFG]     = {.type = NLA_NESTED},
+	[DCB_ATTR_PG_CFG]      = {.type = NLA_NESTED},
+	[DCB_ATTR_SET_ALL]     = {.type = NLA_U8},
+	[DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
+	[DCB_ATTR_CAP]         = {.type = NLA_NESTED},
+	[DCB_ATTR_PFC_STATE]   = {.type = NLA_U8},
+	[DCB_ATTR_BCN]         = {.type = NLA_NESTED},
+};
+
+/* DCB priority flow control to User Priority nested attributes */
+static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
+	[DCB_PFC_UP_ATTR_0]   = {.type = NLA_U8},
+	[DCB_PFC_UP_ATTR_1]   = {.type = NLA_U8},
+	[DCB_PFC_UP_ATTR_2]   = {.type = NLA_U8},
+	[DCB_PFC_UP_ATTR_3]   = {.type = NLA_U8},
+	[DCB_PFC_UP_ATTR_4]   = {.type = NLA_U8},
+	[DCB_PFC_UP_ATTR_5]   = {.type = NLA_U8},
+	[DCB_PFC_UP_ATTR_6]   = {.type = NLA_U8},
+	[DCB_PFC_UP_ATTR_7]   = {.type = NLA_U8},
+	[DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
+};
+
+/* DCB priority grouping nested attributes */
+static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
+	[DCB_PG_ATTR_TC_0]      = {.type = NLA_NESTED},
+	[DCB_PG_ATTR_TC_1]      = {.type = NLA_NESTED},
+	[DCB_PG_ATTR_TC_2]      = {.type = NLA_NESTED},
+	[DCB_PG_ATTR_TC_3]      = {.type = NLA_NESTED},
+	[DCB_PG_ATTR_TC_4]      = {.type = NLA_NESTED},
+	[DCB_PG_ATTR_TC_5]      = {.type = NLA_NESTED},
+	[DCB_PG_ATTR_TC_6]      = {.type = NLA_NESTED},
+	[DCB_PG_ATTR_TC_7]      = {.type = NLA_NESTED},
+	[DCB_PG_ATTR_TC_ALL]    = {.type = NLA_NESTED},
+	[DCB_PG_ATTR_BW_ID_0]   = {.type = NLA_U8},
+	[DCB_PG_ATTR_BW_ID_1]   = {.type = NLA_U8},
+	[DCB_PG_ATTR_BW_ID_2]   = {.type = NLA_U8},
+	[DCB_PG_ATTR_BW_ID_3]   = {.type = NLA_U8},
+	[DCB_PG_ATTR_BW_ID_4]   = {.type = NLA_U8},
+	[DCB_PG_ATTR_BW_ID_5]   = {.type = NLA_U8},
+	[DCB_PG_ATTR_BW_ID_6]   = {.type = NLA_U8},
+	[DCB_PG_ATTR_BW_ID_7]   = {.type = NLA_U8},
+	[DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG},
+};
+
+/* DCB traffic class nested attributes. */
+static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
+	[DCB_TC_ATTR_PARAM_PGID]            = {.type = NLA_U8},
+	[DCB_TC_ATTR_PARAM_UP_MAPPING]      = {.type = NLA_U8},
+	[DCB_TC_ATTR_PARAM_STRICT_PRIO]     = {.type = NLA_U8},
+	[DCB_TC_ATTR_PARAM_BW_PCT]          = {.type = NLA_U8},
+	[DCB_TC_ATTR_PARAM_ALL]             = {.type = NLA_FLAG},
+};
+
+/* DCB capabilities nested attributes. */
+static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
+	[DCB_CAP_ATTR_ALL]     = {.type = NLA_FLAG},
+	[DCB_CAP_ATTR_PG]      = {.type = NLA_U8},
+	[DCB_CAP_ATTR_PFC]     = {.type = NLA_U8},
+	[DCB_CAP_ATTR_UP2TC]   = {.type = NLA_U8},
+	[DCB_CAP_ATTR_PG_TCS]  = {.type = NLA_U8},
+	[DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
+	[DCB_CAP_ATTR_GSP]     = {.type = NLA_U8},
+	[DCB_CAP_ATTR_BCN]     = {.type = NLA_U8},
+};
+
+/* DCB capabilities nested attributes. */
+static struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
+	[DCB_NUMTCS_ATTR_ALL]     = {.type = NLA_FLAG},
+	[DCB_NUMTCS_ATTR_PG]      = {.type = NLA_U8},
+	[DCB_NUMTCS_ATTR_PFC]     = {.type = NLA_U8},
+};
+
+/* DCB BCN nested attributes. */
+static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
+	[DCB_BCN_ATTR_RP_0]         = {.type = NLA_U8},
+	[DCB_BCN_ATTR_RP_1]         = {.type = NLA_U8},
+	[DCB_BCN_ATTR_RP_2]         = {.type = NLA_U8},
+	[DCB_BCN_ATTR_RP_3]         = {.type = NLA_U8},
+	[DCB_BCN_ATTR_RP_4]         = {.type = NLA_U8},
+	[DCB_BCN_ATTR_RP_5]         = {.type = NLA_U8},
+	[DCB_BCN_ATTR_RP_6]         = {.type = NLA_U8},
+	[DCB_BCN_ATTR_RP_7]         = {.type = NLA_U8},
+	[DCB_BCN_ATTR_RP_ALL]       = {.type = NLA_FLAG},
+	[DCB_BCN_ATTR_BCNA_0]       = {.type = NLA_U32},
+	[DCB_BCN_ATTR_BCNA_1]       = {.type = NLA_U32},
+	[DCB_BCN_ATTR_ALPHA]        = {.type = NLA_U32},
+	[DCB_BCN_ATTR_BETA]         = {.type = NLA_U32},
+	[DCB_BCN_ATTR_GD]           = {.type = NLA_U32},
+	[DCB_BCN_ATTR_GI]           = {.type = NLA_U32},
+	[DCB_BCN_ATTR_TMAX]         = {.type = NLA_U32},
+	[DCB_BCN_ATTR_TD]           = {.type = NLA_U32},
+	[DCB_BCN_ATTR_RMIN]         = {.type = NLA_U32},
+	[DCB_BCN_ATTR_W]            = {.type = NLA_U32},
+	[DCB_BCN_ATTR_RD]           = {.type = NLA_U32},
+	[DCB_BCN_ATTR_RU]           = {.type = NLA_U32},
+	[DCB_BCN_ATTR_WRTT]         = {.type = NLA_U32},
+	[DCB_BCN_ATTR_RI]           = {.type = NLA_U32},
+	[DCB_BCN_ATTR_C]            = {.type = NLA_U32},
+	[DCB_BCN_ATTR_ALL]          = {.type = NLA_FLAG},
+};
+
+/* standard netlink reply call */
+static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
+                       u32 seq, u16 flags)
+{
+	struct sk_buff *dcbnl_skb;
+	struct dcbmsg *dcb;
+	struct nlmsghdr *nlh;
+	int ret = -EINVAL;
+
+	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!dcbnl_skb)
+		return ret;
+
+	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);
+
+	dcb = NLMSG_DATA(nlh);
+	dcb->dcb_family = AF_UNSPEC;
+	dcb->cmd = cmd;
+	dcb->dcb_pad = 0;
+
+	ret = nla_put_u8(dcbnl_skb, attr, value);
+	if (ret)
+		goto err;
+
+	/* end the message, assign the nlmsg_len. */
+	nlmsg_end(dcbnl_skb, nlh);
+	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
+	if (ret)
+		goto err;
+
+	return 0;
+nlmsg_failure:
+err:
+	kfree(dcbnl_skb);
+	return ret;
+}
+
+static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb,
+                          u32 pid, u32 seq, u16 flags)
+{
+	int ret = -EINVAL;
+
+	/* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */
+	if (!netdev->dcbnl_ops->getstate)
+		return ret;
+
+	ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB,
+	                  DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags);
+
+	return ret;
+}
+
+static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb,
+                           u32 pid, u32 seq, u16 flags)
+{
+	struct sk_buff *dcbnl_skb;
+	struct nlmsghdr *nlh;
+	struct dcbmsg *dcb;
+	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest;
+	u8 value;
+	int ret = -EINVAL;
+	int i;
+	int getall = 0;
+
+	if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg)
+		return ret;
+
+	ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
+	                       tb[DCB_ATTR_PFC_CFG],
+	                       dcbnl_pfc_up_nest);
+	if (ret)
+		goto err_out;
+
+	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!dcbnl_skb)
+		goto err_out;
+
+	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
+
+	dcb = NLMSG_DATA(nlh);
+	dcb->dcb_family = AF_UNSPEC;
+	dcb->cmd = DCB_CMD_PFC_GCFG;
+
+	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
+	if (!nest)
+		goto err;
+
+	if (data[DCB_PFC_UP_ATTR_ALL])
+		getall = 1;
+
+	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
+		if (!getall && !data[i])
+			continue;
+
+		netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
+		                             &value);
+		ret = nla_put_u8(dcbnl_skb, i, value);
+
+		if (ret) {
+			nla_nest_cancel(dcbnl_skb, nest);
+			goto err;
+		}
+	}
+	nla_nest_end(dcbnl_skb, nest);
+
+	nlmsg_end(dcbnl_skb, nlh);
+
+	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
+	if (ret)
+		goto err;
+
+	return 0;
+nlmsg_failure:
+err:
+	kfree(dcbnl_skb);
+err_out:
+	return -EINVAL;
+}
+
+static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb,
+                                u32 pid, u32 seq, u16 flags)
+{
+	struct sk_buff *dcbnl_skb;
+	struct nlmsghdr *nlh;
+	struct dcbmsg *dcb;
+	u8 perm_addr[MAX_ADDR_LEN];
+	int ret = -EINVAL;
+
+	if (!netdev->dcbnl_ops->getpermhwaddr)
+		return ret;
+
+	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!dcbnl_skb)
+		goto err_out;
+
+	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
+
+	dcb = NLMSG_DATA(nlh);
+	dcb->dcb_family = AF_UNSPEC;
+	dcb->cmd = DCB_CMD_GPERM_HWADDR;
+
+	netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
+
+	ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr),
+	              perm_addr);
+
+	nlmsg_end(dcbnl_skb, nlh);
+
+	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
+	if (ret)
+		goto err;
+
+	return 0;
+
+nlmsg_failure:
+err:
+	kfree(dcbnl_skb);
+err_out:
+	return -EINVAL;
+}
+
+static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
+                        u32 pid, u32 seq, u16 flags)
+{
+	struct sk_buff *dcbnl_skb;
+	struct nlmsghdr *nlh;
+	struct dcbmsg *dcb;
+	struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
+	u8 value;
+	int ret = -EINVAL;
+	int i;
+	int getall = 0;
+
+	if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
+		return ret;
+
+	ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
+	                       dcbnl_cap_nest);
+	if (ret)
+		goto err_out;
+
+	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!dcbnl_skb)
+		goto err_out;
+
+	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
+
+	dcb = NLMSG_DATA(nlh);
+	dcb->dcb_family = AF_UNSPEC;
+	dcb->cmd = DCB_CMD_GCAP;
+
+	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
+	if (!nest)
+		goto err;
+
+	if (data[DCB_CAP_ATTR_ALL])
+		getall = 1;
+
+	for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
+		if (!getall && !data[i])
+			continue;
+
+		if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
+			ret = nla_put_u8(dcbnl_skb, i, value);
+
+			if (ret) {
+				nla_nest_cancel(dcbnl_skb, nest);
+				goto err;
+			}
+		}
+	}
+	nla_nest_end(dcbnl_skb, nest);
+
+	nlmsg_end(dcbnl_skb, nlh);
+
+	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
+	if (ret)
+		goto err;
+
+	return 0;
+nlmsg_failure:
+err:
+	kfree(dcbnl_skb);
+err_out:
+	return -EINVAL;
+}
+
+static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb,
+                           u32 pid, u32 seq, u16 flags)
+{
+	struct sk_buff *dcbnl_skb;
+	struct nlmsghdr *nlh;
+	struct dcbmsg *dcb;
+	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest;
+	u8 value;
+	int ret = -EINVAL;
+	int i;
+	int getall = 0;
+
+	if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs)
+		return ret;
+
+	ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
+	                       dcbnl_numtcs_nest);
+	if (ret) {
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!dcbnl_skb) {
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
+
+	dcb = NLMSG_DATA(nlh);
+	dcb->dcb_family = AF_UNSPEC;
+	dcb->cmd = DCB_CMD_GNUMTCS;
+
+	nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS);
+	if (!nest) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (data[DCB_NUMTCS_ATTR_ALL])
+		getall = 1;
+
+	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
+		if (!getall && !data[i])
+			continue;
+
+		ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value);
+		if (!ret) {
+			ret = nla_put_u8(dcbnl_skb, i, value);
+
+			if (ret) {
+				nla_nest_cancel(dcbnl_skb, nest);
+				ret = -EINVAL;
+				goto err;
+			}
+		} else {
+			goto err;
+		}
+	}
+	nla_nest_end(dcbnl_skb, nest);
+
+	nlmsg_end(dcbnl_skb, nlh);
+
+	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
+	if (ret) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	return 0;
+nlmsg_failure:
+err:
+	kfree(dcbnl_skb);
+err_out:
+	return ret;
+}
+
+static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb,
+                           u32 pid, u32 seq, u16 flags)
+{
+	struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1];
+	int ret = -EINVAL;
+	u8 value;
+	int i;
+
+	if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs)
+		return ret;
+
+	ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS],
+	                       dcbnl_numtcs_nest);
+
+	if (ret) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) {
+		if (data[i] == NULL)
+			continue;
+
+		value = nla_get_u8(data[i]);
+
+		ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value);
+
+		if (ret)
+			goto operr;
+	}
+
+operr:
+	ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS,
+	                  DCB_ATTR_NUMTCS, pid, seq, flags);
+
+err:
+	return ret;
+}
+
+static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb,
+                             u32 pid, u32 seq, u16 flags)
+{
+	int ret = -EINVAL;
+
+	if (!netdev->dcbnl_ops->getpfcstate)
+		return ret;
+
+	ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB,
+	                  DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE,
+	                  pid, seq, flags);
+
+	return ret;
+}
+
+static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb,
+                             u32 pid, u32 seq, u16 flags)
+{
+	int ret = -EINVAL;
+	u8 value;
+
+	if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate)
+		return ret;
+
+	value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]);
+
+	netdev->dcbnl_ops->setpfcstate(netdev, value);
+
+	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE,
+	                  pid, seq, flags);
+
+	return ret;
+}
+
+static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
+                             u32 pid, u32 seq, u16 flags, int dir)
+{
+	struct sk_buff *dcbnl_skb;
+	struct nlmsghdr *nlh;
+	struct dcbmsg *dcb;
+	struct nlattr *pg_nest, *param_nest, *data;
+	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
+	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
+	u8 prio, pgid, tc_pct, up_map;
+	int ret  = -EINVAL;
+	int getall = 0;
+	int i;
+
+	if (!tb[DCB_ATTR_PG_CFG] ||
+	    !netdev->dcbnl_ops->getpgtccfgtx ||
+	    !netdev->dcbnl_ops->getpgtccfgrx ||
+	    !netdev->dcbnl_ops->getpgbwgcfgtx ||
+	    !netdev->dcbnl_ops->getpgbwgcfgrx)
+		return ret;
+
+	ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
+	                       tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
+
+	if (ret)
+		goto err_out;
+
+	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!dcbnl_skb)
+		goto err_out;
+
+	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
+
+	dcb = NLMSG_DATA(nlh);
+	dcb->dcb_family = AF_UNSPEC;
+	dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG;
+
+	pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
+	if (!pg_nest)
+		goto err;
+
+	if (pg_tb[DCB_PG_ATTR_TC_ALL])
+		getall = 1;
+
+	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
+		if (!getall && !pg_tb[i])
+			continue;
+
+		if (pg_tb[DCB_PG_ATTR_TC_ALL])
+			data = pg_tb[DCB_PG_ATTR_TC_ALL];
+		else
+			data = pg_tb[i];
+		ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
+				       data, dcbnl_tc_param_nest);
+		if (ret)
+			goto err_pg;
+
+		param_nest = nla_nest_start(dcbnl_skb, i);
+		if (!param_nest)
+			goto err_pg;
+
+		pgid = DCB_ATTR_VALUE_UNDEFINED;
+		prio = DCB_ATTR_VALUE_UNDEFINED;
+		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
+		up_map = DCB_ATTR_VALUE_UNDEFINED;
+
+		if (dir) {
+			/* Rx */
+			netdev->dcbnl_ops->getpgtccfgrx(netdev,
+						i - DCB_PG_ATTR_TC_0, &prio,
+						&pgid, &tc_pct, &up_map);
+		} else {
+			/* Tx */
+			netdev->dcbnl_ops->getpgtccfgtx(netdev,
+						i - DCB_PG_ATTR_TC_0, &prio,
+						&pgid, &tc_pct, &up_map);
+		}
+
+		if (param_tb[DCB_TC_ATTR_PARAM_PGID] ||
+		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
+			ret = nla_put_u8(dcbnl_skb,
+			                 DCB_TC_ATTR_PARAM_PGID, pgid);
+			if (ret)
+				goto err_param;
+		}
+		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
+		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
+			ret = nla_put_u8(dcbnl_skb,
+			                 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
+			if (ret)
+				goto err_param;
+		}
+		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
+		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
+			ret = nla_put_u8(dcbnl_skb,
+			                 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
+			if (ret)
+				goto err_param;
+		}
+		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
+		    param_tb[DCB_TC_ATTR_PARAM_ALL]) {
+			ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
+			                 tc_pct);
+			if (ret)
+				goto err_param;
+		}
+		nla_nest_end(dcbnl_skb, param_nest);
+	}
+
+	if (pg_tb[DCB_PG_ATTR_BW_ID_ALL])
+		getall = 1;
+	else
+		getall = 0;
+
+	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
+		if (!getall && !pg_tb[i])
+			continue;
+
+		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
+
+		if (dir) {
+			/* Rx */
+			netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
+					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
+		} else {
+			/* Tx */
+			netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
+					i - DCB_PG_ATTR_BW_ID_0, &tc_pct);
+		}
+		ret = nla_put_u8(dcbnl_skb, i, tc_pct);
+
+		if (ret)
+			goto err_pg;
+	}
+
+	nla_nest_end(dcbnl_skb, pg_nest);
+
+	nlmsg_end(dcbnl_skb, nlh);
+
+	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err_param:
+	nla_nest_cancel(dcbnl_skb, param_nest);
+err_pg:
+	nla_nest_cancel(dcbnl_skb, pg_nest);
+nlmsg_failure:
+err:
+	kfree(dcbnl_skb);
+err_out:
+	ret  = -EINVAL;
+	return ret;
+}
+
+static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb,
+                             u32 pid, u32 seq, u16 flags)
+{
+	return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0);
+}
+
+static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb,
+                             u32 pid, u32 seq, u16 flags)
+{
+	return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1);
+}
+
+static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb,
+                          u32 pid, u32 seq, u16 flags)
+{
+	int ret = -EINVAL;
+	u8 value;
+
+	if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate)
+		return ret;
+
+	value = nla_get_u8(tb[DCB_ATTR_STATE]);
+
+	ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value),
+	                  RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE,
+	                  pid, seq, flags);
+
+	return ret;
+}
+
+static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb,
+                           u32 pid, u32 seq, u16 flags)
+{
+	struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1];
+	int i;
+	int ret = -EINVAL;
+	u8 value;
+
+	if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg)
+		return ret;
+
+	ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX,
+	                       tb[DCB_ATTR_PFC_CFG],
+	                       dcbnl_pfc_up_nest);
+	if (ret)
+		goto err;
+
+	for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
+		if (data[i] == NULL)
+			continue;
+		value = nla_get_u8(data[i]);
+		netdev->dcbnl_ops->setpfccfg(netdev,
+			data[i]->nla_type - DCB_PFC_UP_ATTR_0, value);
+	}
+
+	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG,
+	                  pid, seq, flags);
+err:
+	return ret;
+}
+
+static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb,
+                        u32 pid, u32 seq, u16 flags)
+{
+	int ret = -EINVAL;
+
+	if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall)
+		return ret;
+
+	ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB,
+	                  DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags);
+
+	return ret;
+}
+
+static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb,
+                             u32 pid, u32 seq, u16 flags, int dir)
+{
+	struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
+	struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
+	int ret = -EINVAL;
+	int i;
+	u8 pgid;
+	u8 up_map;
+	u8 prio;
+	u8 tc_pct;
+
+	if (!tb[DCB_ATTR_PG_CFG] ||
+	    !netdev->dcbnl_ops->setpgtccfgtx ||
+	    !netdev->dcbnl_ops->setpgtccfgrx ||
+	    !netdev->dcbnl_ops->setpgbwgcfgtx ||
+	    !netdev->dcbnl_ops->setpgbwgcfgrx)
+		return ret;
+
+	ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
+	                       tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
+	if (ret)
+		goto err;
+
+	for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
+		if (!pg_tb[i])
+			continue;
+
+		ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
+		                       pg_tb[i], dcbnl_tc_param_nest);
+		if (ret)
+			goto err;
+
+		pgid = DCB_ATTR_VALUE_UNDEFINED;
+		prio = DCB_ATTR_VALUE_UNDEFINED;
+		tc_pct = DCB_ATTR_VALUE_UNDEFINED;
+		up_map = DCB_ATTR_VALUE_UNDEFINED;
+
+		if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
+			prio =
+			    nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
+
+		if (param_tb[DCB_TC_ATTR_PARAM_PGID])
+			pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]);
+
+		if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
+			tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
+
+		if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
+			up_map =
+			     nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
+
+		/* dir: Tx = 0, Rx = 1 */
+		if (dir) {
+			/* Rx */
+			netdev->dcbnl_ops->setpgtccfgrx(netdev,
+				i - DCB_PG_ATTR_TC_0,
+				prio, pgid, tc_pct, up_map);
+		} else {
+			/* Tx */
+			netdev->dcbnl_ops->setpgtccfgtx(netdev,
+				i - DCB_PG_ATTR_TC_0,
+				prio, pgid, tc_pct, up_map);
+		}
+	}
+
+	for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
+		if (!pg_tb[i])
+			continue;
+
+		tc_pct = nla_get_u8(pg_tb[i]);
+
+		/* dir: Tx = 0, Rx = 1 */
+		if (dir) {
+			/* Rx */
+			netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
+					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
+		} else {
+			/* Tx */
+			netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
+					 i - DCB_PG_ATTR_BW_ID_0, tc_pct);
+		}
+	}
+
+	ret = dcbnl_reply(0, RTM_SETDCB,
+			  (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
+			  DCB_ATTR_PG_CFG, pid, seq, flags);
+
+err:
+	return ret;
+}
+
+static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb,
+                             u32 pid, u32 seq, u16 flags)
+{
+	return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0);
+}
+
+static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb,
+                             u32 pid, u32 seq, u16 flags)
+{
+	return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1);
+}
+
+static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb,
+                            u32 pid, u32 seq, u16 flags)
+{
+	struct sk_buff *dcbnl_skb;
+	struct nlmsghdr *nlh;
+	struct dcbmsg *dcb;
+	struct nlattr *bcn_nest;
+	struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1];
+	u8 value_byte;
+	u32 value_integer;
+	int ret  = -EINVAL;
+	bool getall = false;
+	int i;
+
+	if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp ||
+	    !netdev->dcbnl_ops->getbcncfg)
+		return ret;
+
+	ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX,
+	                       tb[DCB_ATTR_BCN], dcbnl_bcn_nest);
+
+	if (ret)
+		goto err_out;
+
+	dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!dcbnl_skb)
+		goto err_out;
+
+	nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
+
+	dcb = NLMSG_DATA(nlh);
+	dcb->dcb_family = AF_UNSPEC;
+	dcb->cmd = DCB_CMD_BCN_GCFG;
+
+	bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN);
+	if (!bcn_nest)
+		goto err;
+
+	if (bcn_tb[DCB_BCN_ATTR_ALL])
+		getall = true;
+
+	for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
+		if (!getall && !bcn_tb[i])
+			continue;
+
+		netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0,
+		                            &value_byte);
+		ret = nla_put_u8(dcbnl_skb, i, value_byte);
+		if (ret)
+			goto err_bcn;
+	}
+
+	for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
+		if (!getall && !bcn_tb[i])
+			continue;
+
+		netdev->dcbnl_ops->getbcncfg(netdev, i,
+		                             &value_integer);
+		ret = nla_put_u32(dcbnl_skb, i, value_integer);
+		if (ret)
+			goto err_bcn;
+	}
+
+	nla_nest_end(dcbnl_skb, bcn_nest);
+
+	nlmsg_end(dcbnl_skb, nlh);
+
+	ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err_bcn:
+	nla_nest_cancel(dcbnl_skb, bcn_nest);
+nlmsg_failure:
+err:
+	kfree(dcbnl_skb);
+err_out:
+	ret  = -EINVAL;
+	return ret;
+}
+
+static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb,
+                            u32 pid, u32 seq, u16 flags)
+{
+	struct nlattr *data[DCB_BCN_ATTR_MAX + 1];
+	int i;
+	int ret = -EINVAL;
+	u8 value_byte;
+	u32 value_int;
+
+	if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg
+	    || !netdev->dcbnl_ops->setbcnrp)
+		return ret;
+
+	ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX,
+	                       tb[DCB_ATTR_BCN],
+	                       dcbnl_pfc_up_nest);
+	if (ret)
+		goto err;
+
+	for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) {
+		if (data[i] == NULL)
+			continue;
+		value_byte = nla_get_u8(data[i]);
+		netdev->dcbnl_ops->setbcnrp(netdev,
+			data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte);
+	}
+
+	for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) {
+		if (data[i] == NULL)
+			continue;
+		value_int = nla_get_u32(data[i]);
+		netdev->dcbnl_ops->setbcncfg(netdev,
+	                                     i, value_int);
+	}
+
+	ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN,
+	                  pid, seq, flags);
+err:
+	return ret;
+}
+
+static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+	struct net *net = sock_net(skb->sk);
+	struct net_device *netdev;
+	struct dcbmsg  *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);
+	struct nlattr *tb[DCB_ATTR_MAX + 1];
+	u32 pid = skb ? NETLINK_CB(skb).pid : 0;
+	int ret = -EINVAL;
+
+	if (net != &init_net)
+		return -EINVAL;
+
+	ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
+			  dcbnl_rtnl_policy);
+	if (ret < 0)
+		return ret;
+
+	if (!tb[DCB_ATTR_IFNAME])
+		return -EINVAL;
+
+	netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));
+	if (!netdev)
+		return -EINVAL;
+
+	if (!netdev->dcbnl_ops)
+		goto errout;
+
+	switch (dcb->cmd) {
+	case DCB_CMD_GSTATE:
+		ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,
+		                     nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_PFC_GCFG:
+		ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
+		                      nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_GPERM_HWADDR:
+		ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq,
+		                           nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_PGTX_GCFG:
+		ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
+		                        nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_PGRX_GCFG:
+		ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
+		                        nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_BCN_GCFG:
+		ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq,
+		                       nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_SSTATE:
+		ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq,
+		                     nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_PFC_SCFG:
+		ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq,
+		                      nlh->nlmsg_flags);
+		goto out;
+
+	case DCB_CMD_SET_ALL:
+		ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq,
+		                   nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_PGTX_SCFG:
+		ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
+		                        nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_PGRX_SCFG:
+		ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
+		                        nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_GCAP:
+		ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
+		                   nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_GNUMTCS:
+		ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
+		                      nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_SNUMTCS:
+		ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq,
+		                      nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_PFC_GSTATE:
+		ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
+		                        nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_PFC_SSTATE:
+		ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq,
+		                        nlh->nlmsg_flags);
+		goto out;
+	case DCB_CMD_BCN_SCFG:
+		ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
+		                       nlh->nlmsg_flags);
+		goto out;
+	default:
+		goto errout;
+	}
+errout:
+	ret = -EINVAL;
+out:
+	dev_put(netdev);
+	return ret;
+}
+
+static int __init dcbnl_init(void)
+{
+	rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL);
+	rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL);
+
+	return 0;
+}
+module_init(dcbnl_init);
+
+static void __exit dcbnl_exit(void)
+{
+	rtnl_unregister(PF_UNSPEC, RTM_GETDCB);
+	rtnl_unregister(PF_UNSPEC, RTM_SETDCB);
+}
+module_exit(dcbnl_exit);
+
+
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 1e8be24..01e4d39 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -12,7 +12,6 @@
 #include "ackvec.h"
 #include "dccp.h"
 
-#include <linux/dccp.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -68,7 +67,7 @@
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
 	/* Figure out how many options do we need to represent the ackvec */
-	const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_MAX_ACKVEC_OPT_LEN);
+	const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
 	u16 len = av->av_vec_len + 2 * nr_opts, i;
 	u32 elapsed_time;
 	const unsigned char *tail, *from;
@@ -100,8 +99,8 @@
 	for (i = 0; i < nr_opts; ++i) {
 		int copylen = len;
 
-		if (len > DCCP_MAX_ACKVEC_OPT_LEN)
-			copylen = DCCP_MAX_ACKVEC_OPT_LEN;
+		if (len > DCCP_SINGLE_OPT_MAXLEN)
+			copylen = DCCP_SINGLE_OPT_MAXLEN;
 
 		*to++ = DCCPO_ACK_VECTOR_0;
 		*to++ = copylen + 2;
@@ -432,7 +431,7 @@
 int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
 		      u64 *ackno, const u8 opt, const u8 *value, const u8 len)
 {
-	if (len > DCCP_MAX_ACKVEC_OPT_LEN)
+	if (len > DCCP_SINGLE_OPT_MAXLEN)
 		return -1;
 
 	/* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h
index bcb64fb..4ccee03 100644
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -11,15 +11,14 @@
  *	published by the Free Software Foundation.
  */
 
+#include <linux/dccp.h>
 #include <linux/compiler.h>
 #include <linux/ktime.h>
 #include <linux/list.h>
 #include <linux/types.h>
 
-/* Read about the ECN nonce to see why it is 253 */
-#define DCCP_MAX_ACKVEC_OPT_LEN 253
 /* We can spread an ack vector across multiple options */
-#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN * 2)
+#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
 
 #define DCCP_ACKVEC_STATE_RECEIVED	0
 #define DCCP_ACKVEC_STATE_ECN_MARKED	(1 << 6)
diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c
index 8fe931a..bcc643f 100644
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -13,6 +13,13 @@
 
 #include "ccid.h"
 
+static u8 builtin_ccids[] = {
+	DCCPC_CCID2,		/* CCID2 is supported by default */
+#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
+	DCCPC_CCID3,
+#endif
+};
+
 static struct ccid_operations *ccids[CCID_MAX];
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 static atomic_t ccids_lockct = ATOMIC_INIT(0);
@@ -86,6 +93,47 @@
 	}
 }
 
+/* check that up to @array_len members in @ccid_array are supported */
+bool ccid_support_check(u8 const *ccid_array, u8 array_len)
+{
+	u8 i, j, found;
+
+	for (i = 0, found = 0; i < array_len; i++, found = 0) {
+		for (j = 0; !found && j < ARRAY_SIZE(builtin_ccids); j++)
+			found = (ccid_array[i] == builtin_ccids[j]);
+		if (!found)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * ccid_get_builtin_ccids  -  Provide copy of `builtin' CCID array
+ * @ccid_array: pointer to copy into
+ * @array_len: value to return length into
+ * This function allocates memory - caller must see that it is freed after use.
+ */
+int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
+{
+	*ccid_array = kmemdup(builtin_ccids, sizeof(builtin_ccids), gfp_any());
+	if (*ccid_array == NULL)
+		return -ENOBUFS;
+	*array_len = ARRAY_SIZE(builtin_ccids);
+	return 0;
+}
+
+int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+				    char __user *optval, int __user *optlen)
+{
+	if (len < sizeof(builtin_ccids))
+		return -EINVAL;
+
+	if (put_user(sizeof(builtin_ccids), optlen) ||
+	    copy_to_user(optval, builtin_ccids, sizeof(builtin_ccids)))
+		return -EFAULT;
+	return 0;
+}
+
 int ccid_register(struct ccid_operations *ccid_ops)
 {
 	int err = -ENOBUFS;
@@ -205,20 +253,6 @@
 
 EXPORT_SYMBOL_GPL(ccid_new);
 
-struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, gfp_t gfp)
-{
-	return ccid_new(id, sk, 1, gfp);
-}
-
-EXPORT_SYMBOL_GPL(ccid_hc_rx_new);
-
-struct ccid *ccid_hc_tx_new(unsigned char id,struct sock *sk,  gfp_t gfp)
-{
-	return ccid_new(id, sk, 0, gfp);
-}
-
-EXPORT_SYMBOL_GPL(ccid_hc_tx_new);
-
 static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx)
 {
 	struct ccid_operations *ccid_ops;
diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h
index fdeae7b..18f6942 100644
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -103,13 +103,31 @@
 	return (void *)ccid->ccid_priv;
 }
 
+extern bool ccid_support_check(u8 const *ccid_array, u8 array_len);
+extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
+extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+					  char __user *, int __user *);
+
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
-extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
-				   gfp_t gfp);
-extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
-				   gfp_t gfp);
+static inline int ccid_get_current_rx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_rx_ccid;
+
+	if (ccid == NULL || ccid->ccid_ops == NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
+static inline int ccid_get_current_tx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_tx_ccid;
+
+	if (ccid == NULL || ccid->ccid_ops == NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
 
 extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
 extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index 9a43073..c9ea19a 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -25,7 +25,7 @@
 /*
  * This implementation should follow RFC 4341
  */
-
+#include "../feat.h"
 #include "../ccid.h"
 #include "../dccp.h"
 #include "ccid2.h"
@@ -147,8 +147,8 @@
 		DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio);
 		val = max_ratio;
 	}
-	if (val > 0xFFFF)		/* RFC 4340, 11.3 */
-		val = 0xFFFF;
+	if (val > DCCPF_ACK_RATIO_MAX)
+		val = DCCPF_ACK_RATIO_MAX;
 
 	if (val == dp->dccps_l_ack_ratio)
 		return;
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index b4bc6e0..0bc4c9a 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -49,7 +49,7 @@
 
 extern struct inet_hashinfo dccp_hashinfo;
 
-extern atomic_t dccp_orphan_count;
+extern struct percpu_counter dccp_orphan_count;
 
 extern void dccp_time_wait(struct sock *sk, int state, int timeo);
 
@@ -98,9 +98,6 @@
 extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
-extern int  sysctl_dccp_feat_ack_ratio;
-extern int  sysctl_dccp_feat_send_ack_vector;
-extern int  sysctl_dccp_feat_send_ndp_count;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
@@ -252,7 +249,8 @@
 extern void dccp_set_state(struct sock *sk, const int state);
 extern void dccp_done(struct sock *sk);
 
-extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
+extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
+			    struct sk_buff const *skb);
 
 extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 
@@ -435,12 +433,19 @@
 	const struct dccp_sock *dp = dccp_sk(sk);
 	return dp->dccps_timestamp_echo != 0 ||
 #ifdef CONFIG_IP_DCCP_ACKVEC
-	       (dccp_msk(sk)->dccpms_send_ack_vector &&
+	       (dp->dccps_hc_rx_ackvec != NULL &&
 		dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
 #endif
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
+extern int  dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq);
+extern int  dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*,
+				  struct sk_buff *skb);
+extern int  dccp_feat_activate_values(struct sock *sk, struct list_head *fn);
+extern void dccp_feat_list_purge(struct list_head *fn_list);
+
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
 extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
 extern int dccp_insert_option_elapsed_time(struct sock *sk,
diff --git a/net/dccp/diag.c b/net/dccp/diag.c
index d8a3509..b21f261 100644
--- a/net/dccp/diag.c
+++ b/net/dccp/diag.c
@@ -29,11 +29,14 @@
 	info->tcpi_backoff	= icsk->icsk_backoff;
 	info->tcpi_pmtu		= icsk->icsk_pmtu_cookie;
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector)
+	if (dp->dccps_hc_rx_ackvec != NULL)
 		info->tcpi_options |= TCPI_OPT_SACK;
 
-	ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info);
-	ccid_hc_tx_get_info(dp->dccps_hc_tx_ccid, sk, info);
+	if (dp->dccps_hc_rx_ccid != NULL)
+		ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info);
+
+	if (dp->dccps_hc_tx_ccid != NULL)
+		ccid_hc_tx_get_info(dp->dccps_hc_tx_ccid, sk, info);
 }
 
 static void dccp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
@@ -45,7 +48,7 @@
 		dccp_get_info(sk, _info);
 }
 
-static struct inet_diag_handler dccp_diag_handler = {
+static const struct inet_diag_handler dccp_diag_handler = {
 	.idiag_hashinfo	 = &dccp_hashinfo,
 	.idiag_get_info	 = dccp_diag_get_info,
 	.idiag_type	 = DCCPDIAG_GETSOCK,
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 933a0ec..30f9fb7 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1,11 +1,17 @@
 /*
  *  net/dccp/feat.c
  *
- *  An implementation of the DCCP protocol
- *  Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
+ *
+ *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
+ *  Rewrote from scratch, some bits from earlier code by
+ *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
  *
  *  ASSUMPTIONS
  *  -----------
+ *  o Feature negotiation is coordinated with connection setup (as in TCP), wild
+ *    changes of parameters of an established connection are not supported.
  *  o All currently known SP features have 1-byte quantities. If in the future
  *    extensions of RFCs 4340..42 define features with item lengths larger than
  *    one byte, a feature-specific extension of the code will be required.
@@ -15,597 +21,1185 @@
  *  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 "ccid.h"
 #include "feat.h"
 
-#define DCCP_FEAT_SP_NOAGREE (-123)
-
-int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
-		     u8 *val, u8 len, gfp_t gfp)
-{
-	struct dccp_opt_pend *opt;
-
-	dccp_feat_debug(type, feature, *val);
-
-	if (len > 3) {
-		DCCP_WARN("invalid length %d\n", len);
-		return -EINVAL;
-	}
-	/* XXX add further sanity checks */
-
-	/* check if that feature is already being negotiated */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		/* ok we found a negotiation for this option already */
-		if (opt->dccpop_feat == feature && opt->dccpop_type == type) {
-			dccp_pr_debug("Replacing old\n");
-			/* replace */
-			BUG_ON(opt->dccpop_val == NULL);
-			kfree(opt->dccpop_val);
-			opt->dccpop_val	 = val;
-			opt->dccpop_len	 = len;
-			opt->dccpop_conf = 0;
-			return 0;
-		}
-	}
-
-	/* negotiation for a new feature */
-	opt = kmalloc(sizeof(*opt), gfp);
-	if (opt == NULL)
-		return -ENOMEM;
-
-	opt->dccpop_type = type;
-	opt->dccpop_feat = feature;
-	opt->dccpop_len	 = len;
-	opt->dccpop_val	 = val;
-	opt->dccpop_conf = 0;
-	opt->dccpop_sc	 = NULL;
-
-	BUG_ON(opt->dccpop_val == NULL);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending);
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_change);
-
-static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
+/*
+ * Feature activation handlers.
+ *
+ * These all use an u64 argument, to provide enough room for NN/SP features. At
+ * this stage the negotiated values have been checked to be within their range.
+ */
+static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	/* figure out if we are changing our CCID or the peer's */
-	const int rx = type == DCCPO_CHANGE_R;
-	const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid;
-	struct ccid *new_ccid;
+	struct ccid *new_ccid = ccid_new(ccid, sk, rx, gfp_any());
 
-	/* Check if nothing is being changed. */
-	if (ccid_nr == new_ccid_nr)
-		return 0;
-
-	new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC);
 	if (new_ccid == NULL)
 		return -ENOMEM;
 
 	if (rx) {
 		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
 		dp->dccps_hc_rx_ccid = new_ccid;
-		dmsk->dccpms_rx_ccid = new_ccid_nr;
 	} else {
 		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
 		dp->dccps_hc_tx_ccid = new_ccid;
-		dmsk->dccpms_tx_ccid = new_ccid_nr;
 	}
-
 	return 0;
 }
 
-static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
+static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
 {
-	dccp_feat_debug(type, feat, val);
-
-	switch (feat) {
-	case DCCPF_CCID:
-		return dccp_feat_update_ccid(sk, type, val);
-	default:
-		dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n",
-			      dccp_feat_typename(type), feat);
-		break;
-	}
+	if (!rx)
+		dccp_msk(sk)->dccpms_sequence_window = seq_win;
 	return 0;
 }
 
-static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
-			       u8 *rpref, u8 rlen)
+static int dccp_hdlr_ack_ratio(struct sock *sk, u64 ratio, bool rx)
+{
+	if (rx)
+		dccp_sk(sk)->dccps_r_ack_ratio = ratio;
+	else
+		dccp_sk(sk)->dccps_l_ack_ratio = ratio;
+	return 0;
+}
+
+static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	u8 *spref, slen, *res = NULL;
-	int i, j, rc, agree = 1;
 
-	BUG_ON(rpref == NULL);
-
-	/* check if we are the black sheep */
-	if (dp->dccps_role == DCCP_ROLE_CLIENT) {
-		spref = rpref;
-		slen  = rlen;
-		rpref = opt->dccpop_val;
-		rlen  = opt->dccpop_len;
-	} else {
-		spref = opt->dccpop_val;
-		slen  = opt->dccpop_len;
-	}
-	/*
-	 * Now we have server preference list in spref and client preference in
-	 * rpref
-	 */
-	BUG_ON(spref == NULL);
-	BUG_ON(rpref == NULL);
-
-	/* FIXME sanity check vals */
-
-	/* Are values in any order?  XXX Lame "algorithm" here */
-	for (i = 0; i < slen; i++) {
-		for (j = 0; j < rlen; j++) {
-			if (spref[i] == rpref[j]) {
-				res = &spref[i];
-				break;
-			}
+	if (rx) {
+		if (enable && dp->dccps_hc_rx_ackvec == NULL) {
+			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(gfp_any());
+			if (dp->dccps_hc_rx_ackvec == NULL)
+				return -ENOMEM;
+		} else if (!enable) {
+			dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+			dp->dccps_hc_rx_ackvec = NULL;
 		}
-		if (res)
-			break;
 	}
-
-	/* we didn't agree on anything */
-	if (res == NULL) {
-		/* confirm previous value */
-		switch (opt->dccpop_feat) {
-		case DCCPF_CCID:
-			/* XXX did i get this right? =P */
-			if (opt->dccpop_type == DCCPO_CHANGE_L)
-				res = &dccp_msk(sk)->dccpms_tx_ccid;
-			else
-				res = &dccp_msk(sk)->dccpms_rx_ccid;
-			break;
-
-		default:
-			DCCP_BUG("Fell through, feat=%d", opt->dccpop_feat);
-			/* XXX implement res */
-			return -EFAULT;
-		}
-
-		dccp_pr_debug("Don't agree... reconfirming %d\n", *res);
-		agree = 0; /* this is used for mandatory options... */
-	}
-
-	/* need to put result and our preference list */
-	rlen = 1 + opt->dccpop_len;
-	rpref = kmalloc(rlen, GFP_ATOMIC);
-	if (rpref == NULL)
-		return -ENOMEM;
-
-	*rpref = *res;
-	memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len);
-
-	/* put it in the "confirm queue" */
-	if (opt->dccpop_sc == NULL) {
-		opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC);
-		if (opt->dccpop_sc == NULL) {
-			kfree(rpref);
-			return -ENOMEM;
-		}
-	} else {
-		/* recycle the confirm slot */
-		BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
-		kfree(opt->dccpop_sc->dccpoc_val);
-		dccp_pr_debug("recycling confirm slot\n");
-	}
-	memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc));
-
-	opt->dccpop_sc->dccpoc_val = rpref;
-	opt->dccpop_sc->dccpoc_len = rlen;
-
-	/* update the option on our side [we are about to send the confirm] */
-	rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res);
-	if (rc) {
-		kfree(opt->dccpop_sc->dccpoc_val);
-		kfree(opt->dccpop_sc);
-		opt->dccpop_sc = NULL;
-		return rc;
-	}
-
-	dccp_pr_debug("Will confirm %d\n", *rpref);
-
-	/* say we want to change to X but we just got a confirm X, suppress our
-	 * change
-	 */
-	if (!opt->dccpop_conf) {
-		if (*opt->dccpop_val == *res)
-			opt->dccpop_conf = 1;
-		dccp_pr_debug("won't ask for change of same feature\n");
-	}
-
-	return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */
-}
-
-static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	struct dccp_opt_pend *opt;
-	int rc = 1;
-	u8 t;
-
-	/*
-	 * We received a CHANGE.  We gotta match it against our own preference
-	 * list.  If we got a CHANGE_R it means it's a change for us, so we need
-	 * to compare our CHANGE_L list.
-	 */
-	if (type == DCCPO_CHANGE_L)
-		t = DCCPO_CHANGE_R;
-	else
-		t = DCCPO_CHANGE_L;
-
-	/* find our preference list for this feature */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		if (opt->dccpop_type != t || opt->dccpop_feat != feature)
-			continue;
-
-		/* find the winner from the two preference lists */
-		rc = dccp_feat_reconcile(sk, opt, val, len);
-		break;
-	}
-
-	/* We didn't deal with the change.  This can happen if we have no
-	 * preference list for the feature.  In fact, it just shouldn't
-	 * happen---if we understand a feature, we should have a preference list
-	 * with at least the default value.
-	 */
-	BUG_ON(rc == 1);
-
-	return rc;
-}
-
-static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	struct dccp_opt_pend *opt;
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	u8 *copy;
-	int rc;
-
-	/* NN features must be Change L (sec. 6.3.2) */
-	if (type != DCCPO_CHANGE_L) {
-		dccp_pr_debug("received %s for NN feature %d\n",
-				dccp_feat_typename(type), feature);
-		return -EFAULT;
-	}
-
-	/* XXX sanity check opt val */
-
-	/* copy option so we can confirm it */
-	opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
-	if (opt == NULL)
-		return -ENOMEM;
-
-	copy = kmemdup(val, len, GFP_ATOMIC);
-	if (copy == NULL) {
-		kfree(opt);
-		return -ENOMEM;
-	}
-
-	opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */
-	opt->dccpop_feat = feature;
-	opt->dccpop_val	 = copy;
-	opt->dccpop_len	 = len;
-
-	/* change feature */
-	rc = dccp_feat_update(sk, type, feature, *val);
-	if (rc) {
-		kfree(opt->dccpop_val);
-		kfree(opt);
-		return rc;
-	}
-
-	dccp_feat_debug(type, feature, *copy);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
-
 	return 0;
 }
 
-static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
-				    u8 type, u8 feature)
+static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
 {
-	/* XXX check if other confirms for that are queued and recycle slot */
-	struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
-
-	if (opt == NULL) {
-		/* XXX what do we do?  Ignoring should be fine.  It's a change
-		 * after all =P
-		 */
-		return;
-	}
-
-	switch (type) {
-	case DCCPO_CHANGE_L:
-		opt->dccpop_type = DCCPO_CONFIRM_R;
-		break;
-	case DCCPO_CHANGE_R:
-		opt->dccpop_type = DCCPO_CONFIRM_L;
-		break;
-	default:
-		DCCP_WARN("invalid type %d\n", type);
-		kfree(opt);
-		return;
-	}
-	opt->dccpop_feat = feature;
-	opt->dccpop_val	 = NULL;
-	opt->dccpop_len	 = 0;
-
-	/* change feature */
-	dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
-}
-
-static void dccp_feat_flush_confirm(struct sock *sk)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	/* Check if there is anything to confirm in the first place */
-	int yes = !list_empty(&dmsk->dccpms_conf);
-
-	if (!yes) {
-		struct dccp_opt_pend *opt;
-
-		list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-			if (opt->dccpop_conf) {
-				yes = 1;
-				break;
-			}
-		}
-	}
-
-	if (!yes)
-		return;
-
-	/* OK there is something to confirm... */
-	/* XXX check if packet is in flight?  Send delayed ack?? */
-	if (sk->sk_state == DCCP_OPEN)
-		dccp_send_ack(sk);
-}
-
-int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	int rc;
-
-	dccp_feat_debug(type, feature, *val);
-
-	/* figure out if it's SP or NN feature */
-	switch (feature) {
-	/* deal with SP features */
-	case DCCPF_CCID:
-		rc = dccp_feat_sp(sk, type, feature, val, len);
-		break;
-
-	/* deal with NN features */
-	case DCCPF_ACK_RATIO:
-		rc = dccp_feat_nn(sk, type, feature, val, len);
-		break;
-
-	/* XXX implement other features */
-	default:
-		dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n",
-			      dccp_feat_typename(type), feature);
-		rc = -EFAULT;
-		break;
-	}
-
-	/* check if there were problems changing features */
-	if (rc) {
-		/* If we don't agree on SP, we sent a confirm for old value.
-		 * However we propagate rc to caller in case option was
-		 * mandatory
-		 */
-		if (rc != DCCP_FEAT_SP_NOAGREE)
-			dccp_feat_empty_confirm(dccp_msk(sk), type, feature);
-	}
-
-	/* generate the confirm [if required] */
-	dccp_feat_flush_confirm(sk);
-
-	return rc;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
-
-int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
-			   u8 *val, u8 len)
-{
-	u8 t;
-	struct dccp_opt_pend *opt;
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	int found = 0;
-	int all_confirmed = 1;
-
-	dccp_feat_debug(type, feature, *val);
-
-	/* locate our change request */
-	switch (type) {
-	case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break;
-	case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break;
-	default:	      DCCP_WARN("invalid type %d\n", type);
-			      return 1;
-
-	}
-	/* XXX sanity check feature value */
-
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		if (!opt->dccpop_conf && opt->dccpop_type == t &&
-		    opt->dccpop_feat == feature) {
-			found = 1;
-			dccp_pr_debug("feature %d found\n", opt->dccpop_feat);
-
-			/* XXX do sanity check */
-
-			opt->dccpop_conf = 1;
-
-			/* We got a confirmation---change the option */
-			dccp_feat_update(sk, opt->dccpop_type,
-					 opt->dccpop_feat, *val);
-
-			/* XXX check the return value of dccp_feat_update */
-			break;
-		}
-
-		if (!opt->dccpop_conf)
-			all_confirmed = 0;
-	}
-
-	/* fix re-transmit timer */
-	/* XXX gotta make sure that no option negotiation occurs during
-	 * connection shutdown.  Consider that the CLOSEREQ is sent and timer is
-	 * on.  if all options are confirmed it might kill timer which should
-	 * remain alive until close is received.
-	 */
-	if (all_confirmed) {
-		dccp_pr_debug("clear feat negotiation timer %p\n", sk);
-		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
-	}
-
-	if (!found)
-		dccp_pr_debug("%s(%d, ...) never requested\n",
-			      dccp_feat_typename(type), feature);
+	if (!rx)
+		dccp_sk(sk)->dccps_send_ndp_count = (enable > 0);
 	return 0;
 }
 
-EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
-
-void dccp_feat_clean(struct dccp_minisock *dmsk)
-{
-	struct dccp_opt_pend *opt, *next;
-
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending,
-				 dccpop_node) {
-		BUG_ON(opt->dccpop_val == NULL);
-		kfree(opt->dccpop_val);
-
-		if (opt->dccpop_sc != NULL) {
-			BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
-			kfree(opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc);
-		}
-
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
-		BUG_ON(opt == NULL);
-		if (opt->dccpop_val != NULL)
-			kfree(opt->dccpop_val);
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_clean);
-
-/* this is to be called only when a listening sock creates its child.  It is
- * assumed by the function---the confirm is not duplicated, but rather it is
- * "passed on".
+/*
+ * Minimum Checksum Coverage is located at the RX side (9.2.1). This means that
+ * `rx' holds when the sending peer informs about his partial coverage via a
+ * ChangeR() option. In the other case, we are the sender and the receiver
+ * announces its coverage via ChangeL() options. The policy here is to honour
+ * such communication by enabling the corresponding partial coverage - but only
+ * if it has not been set manually before; the warning here means that all
+ * packets will be dropped.
  */
-int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
+static int dccp_hdlr_min_cscov(struct sock *sk, u64 cscov, bool rx)
 {
-	struct dccp_minisock *olddmsk = dccp_msk(oldsk);
-	struct dccp_minisock *newdmsk = dccp_msk(newsk);
-	struct dccp_opt_pend *opt;
-	int rc = 0;
+	struct dccp_sock *dp = dccp_sk(sk);
 
-	INIT_LIST_HEAD(&newdmsk->dccpms_pending);
-	INIT_LIST_HEAD(&newdmsk->dccpms_conf);
+	if (rx)
+		dp->dccps_pcrlen = cscov;
+	else {
+		if (dp->dccps_pcslen == 0)
+			dp->dccps_pcslen = cscov;
+		else if (cscov > dp->dccps_pcslen)
+			DCCP_WARN("CsCov %u too small, peer requires >= %u\n",
+				  dp->dccps_pcslen, (u8)cscov);
+	}
+	return 0;
+}
 
-	list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) {
-		struct dccp_opt_pend *newopt;
-		/* copy the value of the option */
-		u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC);
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+	int (*activation_hdlr)(struct sock *sk, u64 val, bool rx);
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2,   dccp_hdlr_ccid     },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0,   NULL },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100, dccp_hdlr_seq_win  },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2,   dccp_hdlr_ack_ratio},
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_ackvec   },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0,   dccp_hdlr_ndp      },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_min_cscov},
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
 
-		if (val == NULL)
-			goto out_clean;
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
 
-		newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC);
-		if (newopt == NULL) {
-			kfree(val);
-			goto out_clean;
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
+static int dccp_feat_default_value(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+	/*
+	 * There are no default values for unknown features, so encountering a
+	 * negative index here indicates a serious problem somewhere else.
+	 */
+	DCCP_BUG_ON(idx < 0);
+
+	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
+}
+
+static int __dccp_feat_activate(struct sock *sk, const int idx,
+				const bool is_local, dccp_feat_val const *fval)
+{
+	bool rx;
+	u64 val;
+
+	if (idx < 0 || idx >= DCCP_FEAT_SUPPORTED_MAX)
+		return -1;
+	if (dccp_feat_table[idx].activation_hdlr == NULL)
+		return 0;
+
+	if (fval == NULL) {
+		val = dccp_feat_table[idx].default_value;
+	} else if (dccp_feat_table[idx].reconciliation == FEAT_SP) {
+		if (fval->sp.vec == NULL) {
+			/*
+			 * This can happen when an empty Confirm is sent
+			 * for an SP (i.e. known) feature. In this case
+			 * we would be using the default anyway.
+			 */
+			DCCP_CRIT("Feature #%d undefined: using default", idx);
+			val = dccp_feat_table[idx].default_value;
+		} else {
+			val = fval->sp.vec[0];
+		}
+	} else {
+		val = fval->nn;
+	}
+
+	/* Location is RX if this is a local-RX or remote-TX feature */
+	rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX));
+
+	return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
+}
+
+/* Test for "Req'd" feature (RFC 4340, 6.4) */
+static inline int dccp_feat_must_be_understood(u8 feat_num)
+{
+	return	feat_num == DCCPF_CCID || feat_num == DCCPF_SHORT_SEQNOS ||
+		feat_num == DCCPF_SEQUENCE_WINDOW;
+}
+
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec == NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (unlikely(val == NULL))
+		return;
+	if (dccp_feat_type(feat_num) == FEAT_SP)
+		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
+}
+
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type == FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new == NULL)
+		return NULL;
+
+	if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
+/*
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
+ */
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, bool is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node) {
+		if (entry->feat_num == feat_num && entry->is_local == is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	}
+	return NULL;
+}
+
+/**
+ * dccp_feat_entry_new  -  Central list update routine (called by all others)
+ * @head:  list to add to
+ * @feat:  feature number
+ * @local: whether the local (1) or remote feature with number @feat is meant
+ * This is the only constructor and serves to ensure the above invariants.
+ */
+static struct dccp_feat_entry *
+	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, head, node)
+		if (entry->feat_num == feat && entry->is_local == local) {
+			dccp_feat_val_destructor(entry->feat_num, &entry->val);
+			return entry;
+		} else if (entry->feat_num > feat) {
+			head = &entry->node;
+			break;
 		}
 
-		/* insert the option */
-		newopt->dccpop_val = val;
-		list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending);
-
-		/* XXX what happens with backlogs and multiple connections at
-		 * once...
-		 */
-		/* the master socket no longer needs to worry about confirms */
-		opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */
-
-		/* reset state for a new socket */
-		opt->dccpop_conf = 0;
+	entry = kmalloc(sizeof(*entry), gfp_any());
+	if (entry != NULL) {
+		entry->feat_num = feat;
+		entry->is_local = local;
+		list_add_tail(&entry->node, head);
 	}
-
-	/* XXX not doing anything about the conf queue */
-
-out:
-	return rc;
-
-out_clean:
-	dccp_feat_clean(newdmsk);
-	rc = -ENOMEM;
-	goto out;
+	return entry;
 }
 
-EXPORT_SYMBOL_GPL(dccp_feat_clone);
-
-static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
-			    u8 *val, u8 len)
+/**
+ * dccp_feat_push_change  -  Add/overwrite a Change option in the list
+ * @fn_list: feature-negotiation list to update
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @needs_mandatory: whether to use Mandatory feature negotiation options
+ * @fval: pointer to NN/SP value to be inserted (will be copied)
+ */
+static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
+				 u8 mandatory, dccp_feat_val *fval)
 {
-	int rc = -ENOMEM;
-	u8 *copy = kmemdup(val, len, GFP_KERNEL);
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
 
-	if (copy != NULL) {
-		rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
-		if (rc)
-			kfree(copy);
+	if (new == NULL)
+		return -ENOMEM;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_INITIALISING;
+	new->needs_confirm   = 0;
+	new->empty_confirm   = 0;
+	new->val	     = *fval;
+	new->needs_mandatory = mandatory;
+
+	return 0;
+}
+
+/**
+ * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
+ * @fn_list: feature-negotiation list to add to
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is being confirmed
+ * @fval: pointer to NN/SP value to be inserted or NULL
+ * Returns 0 on success, a Reset code for further processing otherwise.
+ */
+static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
+				  dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new == NULL)
+		return DCCP_RESET_CODE_TOO_BUSY;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
+	new->needs_confirm   = 1;
+	new->empty_confirm   = (fval == NULL);
+	new->val.nn	     = 0;		/* zeroes the whole structure */
+	if (!new->empty_confirm)
+		new->val     = *fval;
+	new->needs_mandatory = 0;
+
+	return 0;
+}
+
+static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
+{
+	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
+}
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
+void dccp_feat_list_purge(struct list_head *fn_list)
+{
+	struct dccp_feat_entry *entry, *next;
+
+	list_for_each_entry_safe(entry, next, fn_list, node)
+		dccp_feat_entry_destructor(entry);
+	INIT_LIST_HEAD(fn_list);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
+
+/* generate @to as full clone of @from - @to must not contain any nodes */
+int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
+{
+	struct dccp_feat_entry *entry, *new;
+
+	INIT_LIST_HEAD(to);
+	list_for_each_entry(entry, from, node) {
+		new = dccp_feat_clone_entry(entry);
+		if (new == NULL)
+			goto cloning_failed;
+		list_add_tail(&new->node, to);
 	}
+	return 0;
+
+cloning_failed:
+	dccp_feat_list_purge(to);
+	return -ENOMEM;
+}
+
+/**
+ * dccp_feat_valid_nn_length  -  Enforce length constraints on NN options
+ * Length is between 0 and %DCCP_OPTVAL_MAXLEN. Used for outgoing packets only,
+ * incoming options are accepted as long as their values are valid.
+ */
+static u8 dccp_feat_valid_nn_length(u8 feat_num)
+{
+	if (feat_num == DCCPF_ACK_RATIO)	/* RFC 4340, 11.3 and 6.6.8 */
+		return 2;
+	if (feat_num == DCCPF_SEQUENCE_WINDOW)	/* RFC 4340, 7.5.2 and 6.5  */
+		return 6;
+	return 0;
+}
+
+static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
+{
+	switch (feat_num) {
+	case DCCPF_ACK_RATIO:
+		return val <= DCCPF_ACK_RATIO_MAX;
+	case DCCPF_SEQUENCE_WINDOW:
+		return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
+	}
+	return 0;	/* feature unknown - so we can't tell */
+}
+
+/* check that SP values are within the ranges defined in RFC 4340 */
+static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
+{
+	switch (feat_num) {
+	case DCCPF_CCID:
+		return val == DCCPC_CCID2 || val == DCCPC_CCID3;
+	/* Type-check Boolean feature values: */
+	case DCCPF_SHORT_SEQNOS:
+	case DCCPF_ECN_INCAPABLE:
+	case DCCPF_SEND_ACK_VECTOR:
+	case DCCPF_SEND_NDP_COUNT:
+	case DCCPF_DATA_CHECKSUM:
+	case DCCPF_SEND_LEV_RATE:
+		return val < 2;
+	case DCCPF_MIN_CSUM_COVER:
+		return val < 16;
+	}
+	return 0;			/* feature unknown */
+}
+
+static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
+{
+	if (sp_list == NULL || sp_len < 1)
+		return 0;
+	while (sp_len--)
+		if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
+			return 0;
+	return 1;
+}
+
+/**
+ * dccp_feat_insert_opts  -  Generate FN options from current list state
+ * @skb: next sk_buff to be sent to the peer
+ * @dp: for client during handshake and general negotiation
+ * @dreq: used by the server only (all Changes/Confirms in LISTEN/RESPOND)
+ */
+int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
+			  struct sk_buff *skb)
+{
+	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
+	struct dccp_feat_entry *pos, *next;
+	u8 opt, type, len, *ptr, nn_in_nbo[DCCP_OPTVAL_MAXLEN];
+	bool rpt;
+
+	/* put entries into @skb in the order they appear in the list */
+	list_for_each_entry_safe_reverse(pos, next, fn, node) {
+		opt  = dccp_feat_genopt(pos);
+		type = dccp_feat_type(pos->feat_num);
+		rpt  = false;
+
+		if (pos->empty_confirm) {
+			len = 0;
+			ptr = NULL;
+		} else {
+			if (type == FEAT_SP) {
+				len = pos->val.sp.len;
+				ptr = pos->val.sp.vec;
+				rpt = pos->needs_confirm;
+			} else if (type == FEAT_NN) {
+				len = dccp_feat_valid_nn_length(pos->feat_num);
+				ptr = nn_in_nbo;
+				dccp_encode_value_var(pos->val.nn, ptr, len);
+			} else {
+				DCCP_BUG("unknown feature %u", pos->feat_num);
+				return -1;
+			}
+		}
+
+		if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
+			return -1;
+		if (pos->needs_mandatory && dccp_insert_option_mandatory(skb))
+			return -1;
+		/*
+		 * Enter CHANGING after transmitting the Change option (6.6.2).
+		 */
+		if (pos->state == FEAT_INITIALISING)
+			pos->state = FEAT_CHANGING;
+	}
+	return 0;
+}
+
+/**
+ * __feat_register_nn  -  Register new NN value on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an NN feature from %dccp_feature_numbers
+ * @mandatory: use Mandatory option if 1
+ * @nn_val: value to register (restricted to 4 bytes)
+ * Note that NN features are local by definition (RFC 4340, 6.3.2).
+ */
+static int __feat_register_nn(struct list_head *fn, u8 feat,
+			      u8 mandatory, u64 nn_val)
+{
+	dccp_feat_val fval = { .nn = nn_val };
+
+	if (dccp_feat_type(feat) != FEAT_NN ||
+	    !dccp_feat_is_valid_nn_val(feat, nn_val))
+		return -EINVAL;
+
+	/* Don't bother with default values, they will be activated anyway. */
+	if (nn_val - (u64)dccp_feat_default_value(feat) == 0)
+		return 0;
+
+	return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
+}
+
+/**
+ * __feat_register_sp  -  Register new SP value/list on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an SP feature from %dccp_feature_numbers
+ * @is_local: whether the local (1) or the remote (0) @feat is meant
+ * @mandatory: use Mandatory option if 1
+ * @sp_val: SP value followed by optional preference list
+ * @sp_len: length of @sp_val in bytes
+ */
+static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
+			      u8 mandatory, u8 const *sp_val, u8 sp_len)
+{
+	dccp_feat_val fval;
+
+	if (dccp_feat_type(feat) != FEAT_SP ||
+	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
+		return -EINVAL;
+
+	/* Avoid negotiating alien CCIDs by only advertising supported ones */
+	if (feat == DCCPF_CCID && !ccid_support_check(sp_val, sp_len))
+		return -EOPNOTSUPP;
+
+	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
+		return -ENOMEM;
+
+	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
+}
+
+/**
+ * dccp_feat_register_sp  -  Register requests to change SP feature values
+ * @sk: client or listening socket
+ * @feat: one of %dccp_feature_numbers
+ * @is_local: whether the local (1) or remote (0) @feat is meant
+ * @list: array of preferred values, in descending order of preference
+ * @len: length of @list in bytes
+ */
+int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
+			  u8 const *list, u8 len)
+{	 /* any changes must be registered before establishing the connection */
+	if (sk->sk_state != DCCP_CLOSED)
+		return -EISCONN;
+	if (dccp_feat_type(feat) != FEAT_SP)
+		return -EINVAL;
+	return __feat_register_sp(&dccp_sk(sk)->dccps_featneg, feat, is_local,
+				  0, list, len);
+}
+
+/* Analogous to dccp_feat_register_sp(), but for non-negotiable values */
+int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val)
+{
+	/* any changes must be registered before establishing the connection */
+	if (sk->sk_state != DCCP_CLOSED)
+		return -EISCONN;
+	if (dccp_feat_type(feat) != FEAT_NN)
+		return -EINVAL;
+	return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val);
+}
+
+/*
+ *	Tracking features whose value depend on the choice of CCID
+ *
+ * This is designed with an extension in mind so that a list walk could be done
+ * before activating any features. However, the existing framework was found to
+ * work satisfactorily up until now, the automatic verification is left open.
+ * When adding new CCIDs, add a corresponding dependency table here.
+ */
+static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
+{
+	static const struct ccid_dependency ccid2_dependencies[2][2] = {
+		/*
+		 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
+		 * feature and Send Ack Vector is an RX feature, `is_local'
+		 * needs to be reversed.
+		 */
+		{	/* Dependencies of the receiver-side (remote) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		},
+		{	/* Dependencies of the sender-side (local) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	static const struct ccid_dependency ccid3_dependencies[2][5] = {
+		{	/*
+			 * Dependencies of the receiver-side CCID3
+			 */
+			{	/* locally disable Ack Vectors */
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* see below why Send Loss Event Rate is on */
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* NDP Count is needed as per RFC 4342, 6.1.1 */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 },
+		},
+		{	/*
+			 * CCID3 at the TX side: we request that the HC-receiver
+			 * will not send Ack Vectors (they will be ignored, so
+			 * Mandatory is not set); we enable Send Loss Event Rate
+			 * (Mandatory since the implementation does not support
+			 * the Loss Intervals option of RFC 4342, 8.6).
+			 * The last two options are for peer's information only.
+			*/
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* this CCID does not support Ack Ratio */
+				.dependent_feat	= DCCPF_ACK_RATIO,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* tell receiver we are sending NDP counts */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	switch (ccid) {
+	case DCCPC_CCID2:
+		return ccid2_dependencies[is_local];
+	case DCCPC_CCID3:
+		return ccid3_dependencies[is_local];
+	default:
+		return NULL;
+	}
+}
+
+/**
+ * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
+ * @fn: feature-negotiation list to update
+ * @id: CCID number to track
+ * @is_local: whether TX CCID (1) or RX CCID (0) is meant
+ * This function needs to be called after registering all other features.
+ */
+static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
+{
+	const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
+	int i, rc = (table == NULL);
+
+	for (i = 0; rc == 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
+		if (dccp_feat_type(table[i].dependent_feat) == FEAT_SP)
+			rc = __feat_register_sp(fn, table[i].dependent_feat,
+						    table[i].is_local,
+						    table[i].is_mandatory,
+						    &table[i].val, 1);
+		else
+			rc = __feat_register_nn(fn, table[i].dependent_feat,
+						    table[i].is_mandatory,
+						    table[i].val);
 	return rc;
 }
 
-int dccp_feat_init(struct dccp_minisock *dmsk)
+/**
+ * dccp_feat_finalise_settings  -  Finalise settings before starting negotiation
+ * @dp: client or listening socket (settings will be inherited)
+ * This is called after all registrations (socket initialisation, sysctls, and
+ * sockopt calls), and before sending the first packet containing Change options
+ * (ie. client-Request or server-Response), to ensure internal consistency.
+ */
+int dccp_feat_finalise_settings(struct dccp_sock *dp)
+{
+	struct list_head *fn = &dp->dccps_featneg;
+	struct dccp_feat_entry *entry;
+	int i = 2, ccids[2] = { -1, -1 };
+
+	/*
+	 * Propagating CCIDs:
+	 * 1) not useful to propagate CCID settings if this host advertises more
+	 *    than one CCID: the choice of CCID  may still change - if this is
+	 *    the client, or if this is the server and the client sends
+	 *    singleton CCID values.
+	 * 2) since is that propagate_ccid changes the list, we defer changing
+	 *    the sorted list until after the traversal.
+	 */
+	list_for_each_entry(entry, fn, node)
+		if (entry->feat_num == DCCPF_CCID && entry->val.sp.len == 1)
+			ccids[entry->is_local] = entry->val.sp.vec[0];
+	while (i--)
+		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
+			return -1;
+	return 0;
+}
+
+/**
+ * dccp_feat_server_ccid_dependencies  -  Resolve CCID-dependent features
+ * It is the server which resolves the dependencies once the CCID has been
+ * fully negotiated. If no CCID has been negotiated, it uses the default CCID.
+ */
+int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
+{
+	struct list_head *fn = &dreq->dreq_featneg;
+	struct dccp_feat_entry *entry;
+	u8 is_local, ccid;
+
+	for (is_local = 0; is_local <= 1; is_local++) {
+		entry = dccp_feat_list_lookup(fn, DCCPF_CCID, is_local);
+
+		if (entry != NULL && !entry->empty_confirm)
+			ccid = entry->val.sp.vec[0];
+		else
+			ccid = dccp_feat_default_value(DCCPF_CCID);
+
+		if (dccp_feat_propagate_ccid(fn, ccid, is_local))
+			return -1;
+	}
+	return 0;
+}
+
+/* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */
+static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen)
+{
+	u8 c, s;
+
+	for (s = 0; s < slen; s++)
+		for (c = 0; c < clen; c++)
+			if (servlist[s] == clilist[c])
+				return servlist[s];
+	return -1;
+}
+
+/**
+ * dccp_feat_prefer  -  Move preferred entry to the start of array
+ * Reorder the @array_len elements in @array so that @preferred_value comes
+ * first. Returns >0 to indicate that @preferred_value does occur in @array.
+ */
+static u8 dccp_feat_prefer(u8 preferred_value, u8 *array, u8 array_len)
+{
+	u8 i, does_occur = 0;
+
+	if (array != NULL) {
+		for (i = 0; i < array_len; i++)
+			if (array[i] == preferred_value) {
+				array[i] = array[0];
+				does_occur++;
+			}
+		if (does_occur)
+			array[0] = preferred_value;
+	}
+	return does_occur;
+}
+
+/**
+ * dccp_feat_reconcile  -  Reconcile SP preference lists
+ *  @fval: SP list to reconcile into
+ *  @arr: received SP preference list
+ *  @len: length of @arr in bytes
+ *  @is_server: whether this side is the server (and @fv is the server's list)
+ *  @reorder: whether to reorder the list in @fv after reconciling with @arr
+ * When successful, > 0 is returned and the reconciled list is in @fval.
+ * A value of 0 means that negotiation failed (no shared entry).
+ */
+static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len,
+			       bool is_server, bool reorder)
 {
 	int rc;
 
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
+	if (!fv->sp.vec || !arr) {
+		DCCP_CRIT("NULL feature value or array");
+		return 0;
+	}
 
-	/* CCID L */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
-			      &dmsk->dccpms_tx_ccid, 1);
-	if (rc)
-		goto out;
+	if (is_server)
+		rc = dccp_feat_preflist_match(fv->sp.vec, fv->sp.len, arr, len);
+	else
+		rc = dccp_feat_preflist_match(arr, len, fv->sp.vec, fv->sp.len);
 
-	/* CCID R */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
-			      &dmsk->dccpms_rx_ccid, 1);
-	if (rc)
-		goto out;
+	if (!reorder)
+		return rc;
+	if (rc < 0)
+		return 0;
+
+	/*
+	 * Reorder list: used for activating features and in dccp_insert_fn_opt.
+	 */
+	return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len);
+}
+
+/**
+ * dccp_feat_change_recv  -  Process incoming ChangeL/R options
+ * @fn: feature-negotiation list to update
+ * @is_mandatory: whether the Change was preceded by a Mandatory option
+ * @opt: %DCCPO_CHANGE_L or %DCCPO_CHANGE_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: NN value or SP value/preference list
+ * @len: length of @val in bytes
+ * @server: whether this node is the server (1) or the client (0)
+ */
+static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
+				u8 feat, u8 *val, u8 len, const bool server)
+{
+	u8 defval, type = dccp_feat_type(feat);
+	const bool local = (opt == DCCPO_CHANGE_R);
+	struct dccp_feat_entry *entry;
+	dccp_feat_val fval;
+
+	if (len == 0 || type == FEAT_UNKNOWN)		/* 6.1 and 6.6.8 */
+		goto unknown_feature_or_value;
+
+	/*
+	 *	Negotiation of NN features: Change R is invalid, so there is no
+	 *	simultaneous negotiation; hence we do not look up in the list.
+	 */
+	if (type == FEAT_NN) {
+		if (local || len > sizeof(fval.nn))
+			goto unknown_feature_or_value;
+
+		/* 6.3.2: "The feature remote MUST accept any valid value..." */
+		fval.nn = dccp_decode_value_var(val, len);
+		if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
+			goto unknown_feature_or_value;
+
+		return dccp_feat_push_confirm(fn, feat, local, &fval);
+	}
+
+	/*
+	 *	Unidirectional/simultaneous negotiation of SP features (6.3.1)
+	 */
+	entry = dccp_feat_list_lookup(fn, feat, local);
+	if (entry == NULL) {
+		/*
+		 * No particular preferences have been registered. We deal with
+		 * this situation by assuming that all valid values are equally
+		 * acceptable, and apply the following checks:
+		 * - if the peer's list is a singleton, we accept a valid value;
+		 * - if we are the server, we first try to see if the peer (the
+		 *   client) advertises the default value. If yes, we use it,
+		 *   otherwise we accept the preferred value;
+		 * - else if we are the client, we use the first list element.
+		 */
+		if (dccp_feat_clone_sp_val(&fval, val, 1))
+			return DCCP_RESET_CODE_TOO_BUSY;
+
+		if (len > 1 && server) {
+			defval = dccp_feat_default_value(feat);
+			if (dccp_feat_preflist_match(&defval, 1, val, len) > -1)
+				fval.sp.vec[0] = defval;
+		} else if (!dccp_feat_is_valid_sp_val(feat, fval.sp.vec[0])) {
+			kfree(fval.sp.vec);
+			goto unknown_feature_or_value;
+		}
+
+		/* Treat unsupported CCIDs like invalid values */
+		if (feat == DCCPF_CCID && !ccid_support_check(fval.sp.vec, 1)) {
+			kfree(fval.sp.vec);
+			goto not_valid_or_not_known;
+		}
+
+		return dccp_feat_push_confirm(fn, feat, local, &fval);
+
+	} else if (entry->state == FEAT_UNSTABLE) {	/* 6.6.2 */
+		return 0;
+	}
+
+	if (dccp_feat_reconcile(&entry->val, val, len, server, true)) {
+		entry->empty_confirm = 0;
+	} else if (is_mandatory) {
+		return DCCP_RESET_CODE_MANDATORY_ERROR;
+	} else if (entry->state == FEAT_INITIALISING) {
+		/*
+		 * Failed simultaneous negotiation (server only): try to `save'
+		 * the connection by checking whether entry contains the default
+		 * value for @feat. If yes, send an empty Confirm to signal that
+		 * the received Change was not understood - which implies using
+		 * the default value.
+		 * If this also fails, we use Reset as the last resort.
+		 */
+		WARN_ON(!server);
+		defval = dccp_feat_default_value(feat);
+		if (!dccp_feat_reconcile(&entry->val, &defval, 1, server, true))
+			return DCCP_RESET_CODE_OPTION_ERROR;
+		entry->empty_confirm = 1;
+	}
+	entry->needs_confirm   = 1;
+	entry->needs_mandatory = 0;
+	entry->state	       = FEAT_STABLE;
+	return 0;
+
+unknown_feature_or_value:
+	if (!is_mandatory)
+		return dccp_push_empty_confirm(fn, feat, local);
+
+not_valid_or_not_known:
+	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+			    : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
+/**
+ * dccp_feat_confirm_recv  -  Process received Confirm options
+ * @fn: feature-negotiation list to update
+ * @is_mandatory: whether @opt was preceded by a Mandatory option
+ * @opt: %DCCPO_CONFIRM_L or %DCCPO_CONFIRM_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: NN value or SP value/preference list
+ * @len: length of @val in bytes
+ * @server: whether this node is server (1) or client (0)
+ */
+static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
+				 u8 feat, u8 *val, u8 len, const bool server)
+{
+	u8 *plist, plen, type = dccp_feat_type(feat);
+	const bool local = (opt == DCCPO_CONFIRM_R);
+	struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
+
+	if (entry == NULL) {	/* nothing queued: ignore or handle error */
+		if (is_mandatory && type == FEAT_UNKNOWN)
+			return DCCP_RESET_CODE_MANDATORY_ERROR;
+
+		if (!local && type == FEAT_NN)		/* 6.3.2 */
+			goto confirmation_failed;
+		return 0;
+	}
+
+	if (entry->state != FEAT_CHANGING)		/* 6.6.2 */
+		return 0;
+
+	if (len == 0) {
+		if (dccp_feat_must_be_understood(feat))	/* 6.6.7 */
+			goto confirmation_failed;
+		/*
+		 * Empty Confirm during connection setup: this means reverting
+		 * to the `old' value, which in this case is the default. Since
+		 * we handle default values automatically when no other values
+		 * have been set, we revert to the old value by removing this
+		 * entry from the list.
+		 */
+		dccp_feat_list_pop(entry);
+		return 0;
+	}
+
+	if (type == FEAT_NN) {
+		if (len > sizeof(entry->val.nn))
+			goto confirmation_failed;
+
+		if (entry->val.nn == dccp_decode_value_var(val, len))
+			goto confirmation_succeeded;
+
+		DCCP_WARN("Bogus Confirm for non-existing value\n");
+		goto confirmation_failed;
+	}
+
+	/*
+	 * Parsing SP Confirms: the first element of @val is the preferred
+	 * SP value which the peer confirms, the remainder depends on @len.
+	 * Note that only the confirmed value need to be a valid SP value.
+	 */
+	if (!dccp_feat_is_valid_sp_val(feat, *val))
+		goto confirmation_failed;
+
+	if (len == 1) {		/* peer didn't supply a preference list */
+		plist = val;
+		plen  = len;
+	} else {		/* preferred value + preference list */
+		plist = val + 1;
+		plen  = len - 1;
+	}
+
+	/* Check whether the peer got the reconciliation right (6.6.8) */
+	if (dccp_feat_reconcile(&entry->val, plist, plen, server, 0) != *val) {
+		DCCP_WARN("Confirm selected the wrong value %u\n", *val);
+		return DCCP_RESET_CODE_OPTION_ERROR;
+	}
+	entry->val.sp.vec[0] = *val;
+
+confirmation_succeeded:
+	entry->state = FEAT_STABLE;
+	return 0;
+
+confirmation_failed:
+	DCCP_WARN("Confirmation failed\n");
+	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+			    : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
+/**
+ * dccp_feat_parse_options  -  Process Feature-Negotiation Options
+ * @sk: for general use and used by the client during connection setup
+ * @dreq: used by the server during connection setup
+ * @mandatory: whether @opt was preceded by a Mandatory option
+ * @opt: %DCCPO_CHANGE_L | %DCCPO_CHANGE_R | %DCCPO_CONFIRM_L | %DCCPO_CONFIRM_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: value contents of @opt
+ * @len: length of @val in bytes
+ * Returns 0 on success, a Reset code for ending the connection otherwise.
+ */
+int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
+			    u8 mandatory, u8 opt, u8 feat, u8 *val, u8 len)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
+	bool server = false;
+
+	switch (sk->sk_state) {
+	/*
+	 *	Negotiation during connection setup
+	 */
+	case DCCP_LISTEN:
+		server = true;			/* fall through */
+	case DCCP_REQUESTING:
+		switch (opt) {
+		case DCCPO_CHANGE_L:
+		case DCCPO_CHANGE_R:
+			return dccp_feat_change_recv(fn, mandatory, opt, feat,
+						     val, len, server);
+		case DCCPO_CONFIRM_R:
+		case DCCPO_CONFIRM_L:
+			return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
+						      val, len, server);
+		}
+	}
+	return 0;	/* ignore FN options in all other states */
+}
+
+int dccp_feat_init(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_minisock *dmsk = dccp_msk(sk);
+	int rc;
+
+	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
+	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
 
 	/* Ack ratio */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
-			      &dmsk->dccpms_ack_ratio, 1);
-out:
+	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
+				dp->dccps_l_ack_ratio);
 	return rc;
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_init);
 
+int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_feat_entry *cur, *next;
+	int idx;
+	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
+		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
+	};
+
+	list_for_each_entry(cur, fn_list, node) {
+		/*
+		 * An empty Confirm means that either an unknown feature type
+		 * or an invalid value was present. In the first case there is
+		 * nothing to activate, in the other the default value is used.
+		 */
+		if (cur->empty_confirm)
+			continue;
+
+		idx = dccp_feat_index(cur->feat_num);
+		if (idx < 0) {
+			DCCP_BUG("Unknown feature %u", cur->feat_num);
+			goto activation_failed;
+		}
+		if (cur->state != FEAT_STABLE) {
+			DCCP_CRIT("Negotiation of %s %u failed in state %u",
+				  cur->is_local ? "local" : "remote",
+				  cur->feat_num, cur->state);
+			goto activation_failed;
+		}
+		fvals[idx][cur->is_local] = &cur->val;
+	}
+
+	/*
+	 * Activate in decreasing order of index, so that the CCIDs are always
+	 * activated as the last feature. This avoids the case where a CCID
+	 * relies on the initialisation of one or more features that it depends
+	 * on (e.g. Send NDP Count, Send Ack Vector, and Ack Ratio features).
+	 */
+	for (idx = DCCP_FEAT_SUPPORTED_MAX; --idx >= 0;)
+		if (__dccp_feat_activate(sk, idx, 0, fvals[idx][0]) ||
+		    __dccp_feat_activate(sk, idx, 1, fvals[idx][1])) {
+			DCCP_CRIT("Could not activate %d", idx);
+			goto activation_failed;
+		}
+
+	/* Clean up Change options which have been confirmed already */
+	list_for_each_entry_safe(cur, next, fn_list, node)
+		if (!cur->needs_confirm)
+			dccp_feat_list_pop(cur);
+
+	dccp_pr_debug("Activation OK\n");
+	return 0;
+
+activation_failed:
+	/*
+	 * We clean up everything that may have been allocated, since
+	 * it is difficult to track at which stage negotiation failed.
+	 * This is ok, since all allocation functions below are robust
+	 * against NULL arguments.
+	 */
+	ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+	ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
+	dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+	dp->dccps_hc_rx_ackvec = NULL;
+	return -1;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 const char *dccp_feat_typename(const u8 type)
 {
@@ -639,6 +1233,8 @@
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat ==  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index e272222..9b46e2a 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -3,17 +3,103 @@
 /*
  *  net/dccp/feat.h
  *
- *  An implementation of the DCCP protocol
+ *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
+ *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
  *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.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.
+ *  This program is free software; you can 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/types.h>
 #include "dccp.h"
 
+/*
+ * Known limit values
+ */
+/* Ack Ratio takes 2-byte integer values (11.3) */
+#define DCCPF_ACK_RATIO_MAX	0xFFFF
+/* Wmin=32 and Wmax=2^46-1 from 7.5.2 */
+#define DCCPF_SEQ_WMIN		32
+#define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
+/* Maximum number of SP values that fit in a single (Confirm) option */
+#define DCCP_FEAT_MAX_SP_VALS	(DCCP_SINGLE_OPT_MAXLEN - 2)
+
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @feat_num: one of %dccp_feature_numbers
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	u8                      feat_num;
+
+	bool			needs_mandatory,
+				needs_confirm,
+				empty_confirm,
+				is_local;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
+/**
+ * struct ccid_dependency  -  Track changes resulting from choosing a CCID
+ * @dependent_feat: one of %dccp_feature_numbers
+ * @is_local: local (1) or remote (0) @dependent_feat
+ * @is_mandatory: whether presence of @dependent_feat is mission-critical or not
+ * @val: corresponding default value for @dependent_feat (u8 is sufficient here)
+ */
+struct ccid_dependency {
+	u8	dependent_feat;
+	bool	is_local:1,
+		is_mandatory:1;
+	u8	val;
+};
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
@@ -27,14 +113,30 @@
 #define dccp_feat_debug(type, feat, val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
-extern int  dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
-			     u8 *val, u8 len, gfp_t gfp);
-extern int  dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
-				  u8 *val, u8 len);
-extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
-				   u8 *val, u8 len);
-extern void dccp_feat_clean(struct dccp_minisock *dmsk);
-extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
-extern int  dccp_feat_init(struct dccp_minisock *dmsk);
+extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
+				  u8 const *list, u8 len);
+extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
+extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
+				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
+extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
+extern int  dccp_feat_init(struct sock *sk);
 
+/*
+ * Encoding variable-length options and their maximum length.
+ *
+ * This affects NN options (SP options are all u8) and other variable-length
+ * options (see table 3 in RFC 4340). The limit is currently given the Sequence
+ * Window NN value (sec. 7.5.2) and the NDP count (sec. 7.7) option, all other
+ * options consume less than 6 bytes (timestamps are 4 bytes).
+ * When updating this constant (e.g. due to new internet drafts / RFCs), make
+ * sure that you also update all code which refers to it.
+ */
+#define DCCP_OPTVAL_MAXLEN	6
+
+extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
+extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
+
+extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
+extern int  dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
+			       u8 *val, u8 len, bool repeat_first);
 #endif /* _DCCP_FEAT_H */
diff --git a/net/dccp/input.c b/net/dccp/input.c
index 779d0ed..5eb443f 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -163,7 +163,7 @@
 {
 	struct dccp_sock *dp = dccp_sk(sk);
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector)
+	if (dp->dccps_hc_rx_ackvec != NULL)
 		dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk,
 					    DCCP_SKB_CB(skb)->dccpd_ack_seq);
 }
@@ -375,7 +375,7 @@
 	if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 		dccp_event_ack_recv(sk, skb);
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector &&
+	if (dp->dccps_hc_rx_ackvec != NULL &&
 	    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
 			    DCCP_SKB_CB(skb)->dccpd_seq,
 			    DCCP_ACKVEC_STATE_RECEIVED))
@@ -421,20 +421,19 @@
 			goto out_invalid_packet;
 		}
 
+		/*
+		 * If option processing (Step 8) failed, return 1 here so that
+		 * dccp_v4_do_rcv() sends a Reset. The Reset code depends on
+		 * the option type and is set in dccp_parse_options().
+		 */
 		if (dccp_parse_options(sk, NULL, skb))
-			goto out_invalid_packet;
+			return 1;
 
 		/* Obtain usec RTT sample from SYN exchange (used by CCID 3) */
 		if (likely(dp->dccps_options_received.dccpor_timestamp_echo))
 			dp->dccps_syn_rtt = dccp_sample_rtt(sk, 10 * (tstamp -
 			    dp->dccps_options_received.dccpor_timestamp_echo));
 
-		if (dccp_msk(sk)->dccpms_send_ack_vector &&
-		    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
-				    DCCP_SKB_CB(skb)->dccpd_seq,
-				    DCCP_ACKVEC_STATE_RECEIVED))
-			goto out_invalid_packet; /* FIXME: change error code */
-
 		/* Stop the REQUEST timer */
 		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
 		WARN_ON(sk->sk_send_head == NULL);
@@ -475,6 +474,15 @@
 		 */
 		dccp_set_state(sk, DCCP_PARTOPEN);
 
+		/*
+		 * If feature negotiation was successful, activate features now;
+		 * an activation failure means that this host could not activate
+		 * one ore more features (e.g. insufficient memory), which would
+		 * leave at least one feature in an undefined state.
+		 */
+		if (dccp_feat_activate_values(sk, &dp->dccps_featneg))
+			goto unable_to_proceed;
+
 		/* Make sure socket is routed, for correct metrics. */
 		icsk->icsk_af_ops->rebuild_header(sk);
 
@@ -509,6 +517,16 @@
 	/* dccp_v4_do_rcv will send a reset */
 	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
 	return 1;
+
+unable_to_proceed:
+	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_ABORTED;
+	/*
+	 * We mark this socket as no longer usable, so that the loop in
+	 * dccp_sendmsg() terminates and the application gets notified.
+	 */
+	dccp_set_state(sk, DCCP_CLOSED);
+	sk->sk_err = ECOMM;
+	return 1;
 }
 
 static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
@@ -590,8 +608,6 @@
 			if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
 								    skb) < 0)
 				return 1;
-
-			/* FIXME: do congestion control initialization */
 			goto discard;
 		}
 		if (dh->dccph_type == DCCP_PKT_RESET)
@@ -602,7 +618,7 @@
 		return 1;
 	}
 
-	if (sk->sk_state != DCCP_REQUESTING) {
+	if (sk->sk_state != DCCP_REQUESTING && sk->sk_state != DCCP_RESPOND) {
 		if (dccp_check_seqno(sk, skb))
 			goto discard;
 
@@ -615,7 +631,7 @@
 		if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 			dccp_event_ack_recv(sk, skb);
 
-		if (dccp_msk(sk)->dccpms_send_ack_vector &&
+		if (dp->dccps_hc_rx_ackvec != NULL &&
 		    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
 				    DCCP_SKB_CB(skb)->dccpd_seq,
 				    DCCP_ACKVEC_STATE_RECEIVED))
@@ -667,8 +683,6 @@
 		return 1;
 
 	case DCCP_REQUESTING:
-		/* FIXME: do congestion control initialization */
-
 		queued = dccp_rcv_request_sent_state_process(sk, skb, dh, len);
 		if (queued >= 0)
 			return queued;
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index e3dfdda..d1dd952 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -545,6 +545,7 @@
 
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	kfree(inet_rsk(req)->opt);
 }
 
@@ -595,7 +596,8 @@
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
@@ -792,12 +794,10 @@
 	DCCP_SKB_CB(skb)->dccpd_seq  = dccp_hdr_seq(dh);
 	DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
 
-	dccp_pr_debug("%8.8s "
-		      "src=%u.%u.%u.%u@%-5d "
-		      "dst=%u.%u.%u.%u@%-5d seq=%llu",
+	dccp_pr_debug("%8.8s src=%pI4@%-5d dst=%pI4@%-5d seq=%llu",
 		      dccp_packet_name(dh->dccph_type),
-		      NIPQUAD(iph->saddr), ntohs(dh->dccph_sport),
-		      NIPQUAD(iph->daddr), ntohs(dh->dccph_dport),
+		      &iph->saddr, ntohs(dh->dccph_sport),
+		      &iph->daddr, ntohs(dh->dccph_dport),
 		      (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);
 
 	if (dccp_packet_without_ack(skb)) {
@@ -938,6 +938,7 @@
 	.orphan_count		= &dccp_orphan_count,
 	.max_header		= MAX_DCCP_HEADER,
 	.obj_size		= sizeof(struct dccp_sock),
+	.slab_flags		= SLAB_DESTROY_BY_RCU,
 	.rsk_prot		= &dccp_request_sock_ops,
 	.twsk_prot		= &dccp_timewait_sock_ops,
 	.h.hashinfo		= &dccp_hashinfo,
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index d4ce122..b963f35 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -168,7 +168,7 @@
 				goto out;
 			}
 
-			err = xfrm_lookup(&dst, &fl, sk, 0);
+			err = xfrm_lookup(net, &dst, &fl, sk, 0);
 			if (err < 0) {
 				sk->sk_err_soft = -err;
 				goto out;
@@ -279,7 +279,7 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	err = xfrm_lookup(&dst, &fl, sk, 0);
+	err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0);
 	if (err < 0)
 		goto done;
 
@@ -304,6 +304,7 @@
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	if (inet6_rsk(req)->pktopts != NULL)
 		kfree_skb(inet6_rsk(req)->pktopts);
 }
@@ -342,7 +343,7 @@
 
 	/* sk = NULL, but it is safe for now. RST socket required. */
 	if (!ip6_dst_lookup(ctl_sk, &skb->dst, &fl)) {
-		if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
+		if (xfrm_lookup(net, &skb->dst, &fl, NULL, 0) >= 0) {
 			ip6_xmit(ctl_sk, skb, &fl, NULL, 0);
 			DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
 			DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
@@ -426,7 +427,8 @@
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
@@ -567,7 +569,7 @@
 		if (final_p)
 			ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-		if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+		if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
 			goto out;
 	}
 
@@ -1002,7 +1004,7 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT);
+	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
 	if (err < 0) {
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, &fl);
@@ -1138,6 +1140,7 @@
 	.orphan_count	   = &dccp_orphan_count,
 	.max_header	   = MAX_DCCP_HEADER,
 	.obj_size	   = sizeof(struct dccp6_sock),
+	.slab_flags	   = SLAB_DESTROY_BY_RCU,
 	.rsk_prot	   = &dccp6_request_sock_ops,
 	.twsk_prot	   = &dccp6_timewait_sock_ops,
 	.h.hashinfo	   = &dccp_hashinfo,
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
index e6bf99e..6821ae3 100644
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -45,11 +45,6 @@
 void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-	dmsk->dccpms_rx_ccid	     = sysctl_dccp_feat_rx_ccid;
-	dmsk->dccpms_tx_ccid	     = sysctl_dccp_feat_tx_ccid;
-	dmsk->dccpms_ack_ratio	     = sysctl_dccp_feat_ack_ratio;
-	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
-	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
 
 void dccp_time_wait(struct sock *sk, int state, int timeo)
@@ -112,7 +107,7 @@
 	struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
 
 	if (newsk != NULL) {
-		const struct dccp_request_sock *dreq = dccp_rsk(req);
+		struct dccp_request_sock *dreq = dccp_rsk(req);
 		struct inet_connection_sock *newicsk = inet_csk(newsk);
 		struct dccp_sock *newdp = dccp_sk(newsk);
 		struct dccp_minisock *newdmsk = dccp_msk(newsk);
@@ -125,35 +120,7 @@
 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
-		if (dccp_feat_clone(sk, newsk))
-			goto out_free;
-
-		if (newdmsk->dccpms_send_ack_vector) {
-			newdp->dccps_hc_rx_ackvec =
-						dccp_ackvec_alloc(GFP_ATOMIC);
-			if (unlikely(newdp->dccps_hc_rx_ackvec == NULL))
-				goto out_free;
-		}
-
-		newdp->dccps_hc_rx_ccid =
-			    ccid_hc_rx_new(newdmsk->dccpms_rx_ccid,
-					   newsk, GFP_ATOMIC);
-		newdp->dccps_hc_tx_ccid =
-			    ccid_hc_tx_new(newdmsk->dccpms_tx_ccid,
-					   newsk, GFP_ATOMIC);
-		if (unlikely(newdp->dccps_hc_rx_ccid == NULL ||
-			     newdp->dccps_hc_tx_ccid == NULL)) {
-			dccp_ackvec_free(newdp->dccps_hc_rx_ackvec);
-			ccid_hc_rx_delete(newdp->dccps_hc_rx_ccid, newsk);
-			ccid_hc_tx_delete(newdp->dccps_hc_tx_ccid, newsk);
-out_free:
-			/* It is still raw copy of parent, so invalidate
-			 * destructor and make plain sk_free() */
-			newsk->sk_destruct = NULL;
-			sk_free(newsk);
-			return NULL;
-		}
-
+		INIT_LIST_HEAD(&newdp->dccps_featneg);
 		/*
 		 * Step 3: Process LISTEN state
 		 *
@@ -184,6 +151,17 @@
 		dccp_set_seqno(&newdp->dccps_awl,
 			       max48(newdp->dccps_awl, newdp->dccps_iss));
 
+		/*
+		 * Activate features after initialising the sequence numbers,
+		 * since CCID initialisation may depend on GSS, ISR, ISS etc.
+		 */
+		if (dccp_feat_activate_values(newsk, &dreq->dreq_featneg)) {
+			/* It is still raw copy of parent, so invalidate
+			 * destructor and make plain sk_free() */
+			newsk->sk_destruct = NULL;
+			sk_free(newsk);
+			return NULL;
+		}
 		dccp_init_xmit_timers(newsk);
 
 		DCCP_INC_STATS_BH(DCCP_MIB_PASSIVEOPENS);
@@ -304,7 +282,8 @@
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
 
-void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+int dccp_reqsk_init(struct request_sock *req,
+		    struct dccp_sock const *dp, struct sk_buff const *skb)
 {
 	struct dccp_request_sock *dreq = dccp_rsk(req);
 
@@ -313,6 +292,9 @@
 	inet_rsk(req)->acked	  = 0;
 	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
+
+	/* inherit feature negotiation options from listening socket */
+	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_init);
diff --git a/net/dccp/options.c b/net/dccp/options.c
index 0809b63..7b1165c 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -26,20 +26,21 @@
 int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_ack_ratio	      = DCCPF_INITIAL_ACK_RATIO;
-int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
-int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
-static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
+u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
-	u32 value = 0;
+	u64 value = 0;
 
+	if (len >= DCCP_OPTVAL_MAXLEN)
+		value += ((u64)*bf++) << 40;
+	if (len > 4)
+		value += ((u64)*bf++) << 32;
 	if (len > 3)
-		value += *bf++ << 24;
+		value += ((u64)*bf++) << 24;
 	if (len > 2)
-		value += *bf++ << 16;
+		value += ((u64)*bf++) << 16;
 	if (len > 1)
-		value += *bf++ << 8;
+		value += ((u64)*bf++) << 8;
 	if (len > 0)
 		value += *bf;
 
@@ -64,7 +65,7 @@
 					(dh->dccph_doff * 4);
 	struct dccp_options_received *opt_recv = &dp->dccps_options_received;
 	unsigned char opt, len;
-	unsigned char *value;
+	unsigned char *uninitialized_var(value);
 	u32 elapsed_time;
 	__be32 opt_val;
 	int rc;
@@ -131,41 +132,19 @@
 			dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk),
 				      (unsigned long long)opt_recv->dccpor_ndp);
 			break;
-		case DCCPO_CHANGE_L:
-			/* fall through */
-		case DCCPO_CHANGE_R:
-			if (pkt_type == DCCP_PKT_DATA)
+		case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R:
+			if (pkt_type == DCCP_PKT_DATA)      /* RFC 4340, 6 */
 				break;
-			if (len < 2)
-				goto out_invalid_option;
-			rc = dccp_feat_change_recv(sk, opt, *value, value + 1,
-						   len - 1);
-			/*
-			 * When there is a change error, change_recv is
-			 * responsible for dealing with it.  i.e. reply with an
-			 * empty confirm.
-			 * If the change was mandatory, then we need to die.
-			 */
-			if (rc && mandatory)
-				goto out_invalid_option;
-			break;
-		case DCCPO_CONFIRM_L:
-			/* fall through */
-		case DCCPO_CONFIRM_R:
-			if (pkt_type == DCCP_PKT_DATA)
-				break;
-			if (len < 2)	/* FIXME this disallows empty confirm */
-				goto out_invalid_option;
-			if (dccp_feat_confirm_recv(sk, opt, *value,
-						   value + 1, len - 1))
-				goto out_invalid_option;
+			rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
+						    *value, value + 1, len - 1);
+			if (rc)
+				goto out_featneg_failed;
 			break;
 		case DCCPO_ACK_VECTOR_0:
 		case DCCPO_ACK_VECTOR_1:
 			if (dccp_packet_without_ack(skb))   /* RFC 4340, 11.4 */
 				break;
-
-			if (dccp_msk(sk)->dccpms_send_ack_vector &&
+			if (dp->dccps_hc_rx_ackvec != NULL &&
 			    dccp_ackvec_parse(sk, skb, &ackno, opt, value, len))
 				goto out_invalid_option;
 			break;
@@ -289,8 +268,10 @@
 
 out_invalid_option:
 	DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
-	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR;
-	DCCP_WARN("DCCP(%p): invalid option %d, len=%d", sk, opt, len);
+	rc = DCCP_RESET_CODE_OPTION_ERROR;
+out_featneg_failed:
+	DCCP_WARN("DCCP(%p): Option %d (len=%d) error=%u\n", sk, opt, len, rc);
+	DCCP_SKB_CB(skb)->dccpd_reset_code = rc;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0;
@@ -299,9 +280,12 @@
 
 EXPORT_SYMBOL_GPL(dccp_parse_options);
 
-static void dccp_encode_value_var(const u32 value, unsigned char *to,
-				  const unsigned int len)
+void dccp_encode_value_var(const u64 value, u8 *to, const u8 len)
 {
+	if (len >= DCCP_OPTVAL_MAXLEN)
+		*to++ = (value & 0xFF0000000000ull) >> 40;
+	if (len > 4)
+		*to++ = (value & 0xFF00000000ull) >> 32;
 	if (len > 3)
 		*to++ = (value & 0xFF000000) >> 24;
 	if (len > 2)
@@ -461,23 +445,61 @@
 	return 0;
 }
 
-static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
-				u8 *val, u8 len)
+/**
+ * dccp_insert_option_mandatory  -  Mandatory option (5.8.2)
+ * Note that since we are using skb_push, this function needs to be called
+ * _after_ inserting the option it is supposed to influence (stack order).
+ */
+int dccp_insert_option_mandatory(struct sk_buff *skb)
 {
-	u8 *to;
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len >= DCCP_MAX_OPT_LEN)
+		return -1;
 
-	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
-		DCCP_WARN("packet too small for feature %d option!\n", feat);
+	DCCP_SKB_CB(skb)->dccpd_opt_len++;
+	*skb_push(skb, 1) = DCCPO_MANDATORY;
+	return 0;
+}
+
+/**
+ * dccp_insert_fn_opt  -  Insert single Feature-Negotiation option into @skb
+ * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R
+ * @feat: one out of %dccp_feature_numbers
+ * @val: NN value or SP array (preferred element first) to copy
+ * @len: true length of @val in bytes (excluding first element repetition)
+ * @repeat_first: whether to copy the first element of @val twice
+ * The last argument is used to construct Confirm options, where the preferred
+ * value and the preference list appear separately (RFC 4340, 6.3.1). Preference
+ * lists are kept such that the preferred entry is always first, so we only need
+ * to copy twice, and avoid the overhead of cloning into a bigger array.
+ */
+int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
+		       u8 *val, u8 len, bool repeat_first)
+{
+	u8 tot_len, *to;
+
+	/* take the `Feature' field and possible repetition into account */
+	if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) {
+		DCCP_WARN("length %u for feature %u too large\n", len, feat);
 		return -1;
 	}
 
-	DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3;
+	if (unlikely(val == NULL || len == 0))
+		len = repeat_first = 0;
+	tot_len = 3 + repeat_first + len;
 
-	to    = skb_push(skb, len + 3);
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) {
+		DCCP_WARN("packet too small for feature %d option!\n", feat);
+		return -1;
+	}
+	DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len;
+
+	to    = skb_push(skb, tot_len);
 	*to++ = type;
-	*to++ = len + 3;
+	*to++ = tot_len;
 	*to++ = feat;
 
+	if (repeat_first)
+		*to++ = *val;
 	if (len)
 		memcpy(to, val, len);
 
@@ -487,69 +509,6 @@
 	return 0;
 }
 
-static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
-{
-	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	struct dccp_opt_pend *opt, *next;
-	int change = 0;
-
-	/* confirm any options [NN opts] */
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
-		dccp_insert_feat_opt(skb, opt->dccpop_type,
-				     opt->dccpop_feat, opt->dccpop_val,
-				     opt->dccpop_len);
-		/* fear empty confirms */
-		if (opt->dccpop_val)
-			kfree(opt->dccpop_val);
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
-
-	/* see which features we need to send */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		/* see if we need to send any confirm */
-		if (opt->dccpop_sc) {
-			dccp_insert_feat_opt(skb, opt->dccpop_type + 1,
-					     opt->dccpop_feat,
-					     opt->dccpop_sc->dccpoc_val,
-					     opt->dccpop_sc->dccpoc_len);
-
-			BUG_ON(!opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc);
-			opt->dccpop_sc = NULL;
-		}
-
-		/* any option not confirmed, re-send it */
-		if (!opt->dccpop_conf) {
-			dccp_insert_feat_opt(skb, opt->dccpop_type,
-					     opt->dccpop_feat, opt->dccpop_val,
-					     opt->dccpop_len);
-			change++;
-		}
-	}
-
-	/* Retransmit timer.
-	 * If this is the master listening sock, we don't set a timer on it.  It
-	 * should be fine because if the dude doesn't receive our RESPONSE
-	 * [which will contain the CHANGE] he will send another REQUEST which
-	 * will "retrnasmit" the change.
-	 */
-	if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
-		dccp_pr_debug("reset feat negotiation timer %p\n", sk);
-
-		/* XXX don't reset the timer on re-transmissions.  I.e. reset it
-		 * only when sending new stuff i guess.  Currently the timer
-		 * never backs off because on re-transmission it just resets it!
-		 */
-		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
-					  inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
-	}
-
-	return 0;
-}
-
 /* The length of all options needs to be a multiple of 4 (5.8) */
 static void dccp_insert_option_padding(struct sk_buff *skb)
 {
@@ -565,19 +524,31 @@
 int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
-	if (dmsk->dccpms_send_ndp_count &&
-	    dccp_insert_option_ndp(sk, skb))
+	if (dp->dccps_send_ndp_count && dccp_insert_option_ndp(sk, skb))
 		return -1;
 
-	if (!dccp_packet_without_ack(skb)) {
-		if (dmsk->dccpms_send_ack_vector &&
-		    dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
-		    dccp_insert_option_ackvec(sk, skb))
+	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
+
+		/* Feature Negotiation */
+		if (dccp_feat_insert_opts(dp, NULL, skb))
 			return -1;
+
+		if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST) {
+			/*
+			 * Obtain RTT sample from Request/Response exchange.
+			 * This is currently used in CCID 3 initialisation.
+			 */
+			if (dccp_insert_option_timestamp(sk, skb))
+				return -1;
+
+		} else if (dp->dccps_hc_rx_ackvec != NULL &&
+			   dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
+			   dccp_insert_option_ackvec(sk, skb)) {
+				return -1;
+		}
 	}
 
 	if (dp->dccps_hc_rx_insert_options) {
@@ -586,21 +557,6 @@
 		dp->dccps_hc_rx_insert_options = 0;
 	}
 
-	/* Feature negotiation */
-	/* Data packets can't do feat negotiation */
-	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA &&
-	    DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK &&
-	    dccp_insert_options_feat(sk, skb))
-		return -1;
-
-	/*
-	 * Obtain RTT sample from Request/Response exchange.
-	 * This is currently used in CCID 3 initialisation.
-	 */
-	if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST &&
-	    dccp_insert_option_timestamp(sk, skb))
-		return -1;
-
 	if (dp->dccps_timestamp_echo != 0 &&
 	    dccp_insert_option_timestamp_echo(dp, NULL, skb))
 		return -1;
@@ -613,6 +569,9 @@
 {
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
+	if (dccp_feat_insert_opts(NULL, dreq, skb))
+		return -1;
+
 	if (dreq->dreq_timestamp_echo != 0 &&
 	    dccp_insert_option_timestamp_echo(NULL, dreq, skb))
 		return -1;
diff --git a/net/dccp/output.c b/net/dccp/output.c
index 809d803..22a618a 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -175,7 +175,7 @@
 	 * make it a multiple of 4
 	 */
 
-	cur_mps -= ((5 + 6 + 10 + 6 + 6 + 6 + 3) / 4) * 4;
+	cur_mps -= roundup(5 + 6 + 10 + 6 + 6 + 6, 4);
 
 	/* And store cached results */
 	icsk->icsk_pmtu_cookie = pmtu;
@@ -339,10 +339,12 @@
 	DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
 	DCCP_SKB_CB(skb)->dccpd_seq  = dreq->dreq_iss;
 
-	if (dccp_insert_options_rsk(dreq, skb)) {
-		kfree_skb(skb);
-		return NULL;
-	}
+	/* Resolve feature dependencies resulting from choice of CCID */
+	if (dccp_feat_server_ccid_dependencies(dreq))
+		goto response_failed;
+
+	if (dccp_insert_options_rsk(dreq, skb))
+		goto response_failed;
 
 	/* Build and checksum header */
 	dh = dccp_zeroed_hdr(skb, dccp_header_size);
@@ -363,6 +365,9 @@
 	inet_rsk(req)->acked = 1;
 	DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
 	return skb;
+response_failed:
+	kfree_skb(skb);
+	return NULL;
 }
 
 EXPORT_SYMBOL_GPL(dccp_make_response);
@@ -469,6 +474,10 @@
 	struct sk_buff *skb;
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
+	/* do not connect if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dccp_sk(sk)))
+		return -EPROTO;
+
 	dccp_connect_init(sk);
 
 	skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
diff --git a/net/dccp/probe.c b/net/dccp/probe.c
index 81368a7..37731da 100644
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -74,30 +74,27 @@
 static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
 			 struct msghdr *msg, size_t size)
 {
-	const struct dccp_minisock *dmsk = dccp_msk(sk);
 	const struct inet_sock *inet = inet_sk(sk);
-	const struct ccid3_hc_tx_sock *hctx;
+	struct ccid3_hc_tx_sock *hctx = NULL;
 
-	if (dmsk->dccpms_tx_ccid == DCCPC_CCID3)
+	if (ccid_get_current_tx_ccid(dccp_sk(sk)) == DCCPC_CCID3)
 		hctx = ccid3_hc_tx_sk(sk);
-	else
-		hctx = NULL;
 
 	if (port == 0 || ntohs(inet->dport) == port ||
 	    ntohs(inet->sport) == port) {
 		if (hctx)
-			printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %d %d %d %u "
+			printl("%pI4:%u %pI4:%u %d %d %d %d %u "
 			       "%llu %llu %d\n",
-			       NIPQUAD(inet->saddr), ntohs(inet->sport),
-			       NIPQUAD(inet->daddr), ntohs(inet->dport), size,
+			       &inet->saddr, ntohs(inet->sport),
+			       &inet->daddr, ntohs(inet->dport), size,
 			       hctx->ccid3hctx_s, hctx->ccid3hctx_rtt,
 			       hctx->ccid3hctx_p, hctx->ccid3hctx_x_calc,
 			       hctx->ccid3hctx_x_recv >> 6,
 			       hctx->ccid3hctx_x >> 6, hctx->ccid3hctx_t_ipi);
 		else
-			printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d\n",
-			       NIPQUAD(inet->saddr), ntohs(inet->sport),
-			       NIPQUAD(inet->daddr), ntohs(inet->dport), size);
+			printl("%pI4:%u %pI4:%u %d\n",
+			       &inet->saddr, ntohs(inet->sport),
+			       &inet->daddr, ntohs(inet->dport), size);
 	}
 
 	jprobe_return();
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index d0bd348..d5c2bac 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -40,16 +40,10 @@
 
 EXPORT_SYMBOL_GPL(dccp_statistics);
 
-atomic_t dccp_orphan_count = ATOMIC_INIT(0);
-
+struct percpu_counter dccp_orphan_count;
 EXPORT_SYMBOL_GPL(dccp_orphan_count);
 
-struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
-	.lhash_lock	= RW_LOCK_UNLOCKED,
-	.lhash_users	= ATOMIC_INIT(0),
-	.lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait),
-};
-
+struct inet_hashinfo dccp_hashinfo;
 EXPORT_SYMBOL_GPL(dccp_hashinfo);
 
 /* the maximum queue length for tx in packets. 0 is no limit */
@@ -67,6 +61,9 @@
 	case DCCP_OPEN:
 		if (oldstate != DCCP_OPEN)
 			DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
+		/* Client retransmits all Confirm options until entering OPEN */
+		if (oldstate == DCCP_PARTOPEN)
+			dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg);
 		break;
 
 	case DCCP_CLOSED:
@@ -175,7 +172,6 @@
 int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
 	dccp_minisock_init(&dp->dccps_minisock);
@@ -193,45 +189,10 @@
 
 	dccp_init_xmit_timers(sk);
 
-	/*
-	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
-	 * the listening (master) sock get CCID control blocks, which is not
-	 * necessary, but for now, to not mess with the test userspace apps,
-	 * lets leave it here, later the real solution is to do this in a
-	 * setsockopt(CCIDs-I-want/accept). -acme
-	 */
-	if (likely(ctl_sock_initialized)) {
-		int rc = dccp_feat_init(dmsk);
-
-		if (rc)
-			return rc;
-
-		if (dmsk->dccpms_send_ack_vector) {
-			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
-			if (dp->dccps_hc_rx_ackvec == NULL)
-				return -ENOMEM;
-		}
-		dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid,
-						      sk, GFP_KERNEL);
-		dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
-						      sk, GFP_KERNEL);
-		if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
-			     dp->dccps_hc_tx_ccid == NULL)) {
-			ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
-			ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
-			if (dmsk->dccpms_send_ack_vector) {
-				dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
-				dp->dccps_hc_rx_ackvec = NULL;
-			}
-			dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
-			return -ENOMEM;
-		}
-	} else {
-		/* control socket doesn't need feat nego */
-		INIT_LIST_HEAD(&dmsk->dccpms_pending);
-		INIT_LIST_HEAD(&dmsk->dccpms_conf);
-	}
-
+	INIT_LIST_HEAD(&dp->dccps_featneg);
+	/* control socket doesn't need feat nego */
+	if (likely(ctl_sock_initialized))
+		return dccp_feat_init(sk);
 	return 0;
 }
 
@@ -240,7 +201,6 @@
 void dccp_destroy_sock(struct sock *sk)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	/*
 	 * DCCP doesn't use sk_write_queue, just sk_send_head
@@ -258,7 +218,7 @@
 	kfree(dp->dccps_service_list);
 	dp->dccps_service_list = NULL;
 
-	if (dmsk->dccpms_send_ack_vector) {
+	if (dp->dccps_hc_rx_ackvec != NULL) {
 		dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
 		dp->dccps_hc_rx_ackvec = NULL;
 	}
@@ -267,7 +227,7 @@
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
 	/* clean up feature negotiation state */
-	dccp_feat_clean(dmsk);
+	dccp_feat_list_purge(&dp->dccps_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_destroy_sock);
@@ -277,6 +237,9 @@
 	struct dccp_sock *dp = dccp_sk(sk);
 
 	dp->dccps_role = DCCP_ROLE_LISTEN;
+	/* do not start to listen if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dp))
+		return -EPROTO;
 	return inet_csk_listen_start(sk, backlog);
 }
 
@@ -466,42 +429,70 @@
 	return 0;
 }
 
-/* byte 1 is feature.  the rest is the preference list */
-static int dccp_setsockopt_change(struct sock *sk, int type,
-				  struct dccp_so_feat __user *optval)
+static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
 {
-	struct dccp_so_feat opt;
-	u8 *val;
-	int rc;
+	u8 *list, len;
+	int i, rc;
 
-	if (copy_from_user(&opt, optval, sizeof(opt)))
-		return -EFAULT;
+	if (cscov < 0 || cscov > 15)
+		return -EINVAL;
 	/*
-	 * rfc4340: 6.1. Change Options
+	 * Populate a list of permissible values, in the range cscov...15. This
+	 * is necessary since feature negotiation of single values only works if
+	 * both sides incidentally choose the same value. Since the list starts
+	 * lowest-value first, negotiation will pick the smallest shared value.
 	 */
-	if (opt.dccpsf_len < 1)
+	if (cscov == 0)
+		return 0;
+	len = 16 - cscov;
+
+	list = kmalloc(len, GFP_KERNEL);
+	if (list == NULL)
+		return -ENOBUFS;
+
+	for (i = 0; i < len; i++)
+		list[i] = cscov++;
+
+	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
+
+	if (rc == 0) {
+		if (rx)
+			dccp_sk(sk)->dccps_pcrlen = cscov;
+		else
+			dccp_sk(sk)->dccps_pcslen = cscov;
+	}
+	kfree(list);
+	return rc;
+}
+
+static int dccp_setsockopt_ccid(struct sock *sk, int type,
+				char __user *optval, int optlen)
+{
+	u8 *val;
+	int rc = 0;
+
+	if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
 		return -EINVAL;
 
-	val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
-	if (!val)
+	val = kmalloc(optlen, GFP_KERNEL);
+	if (val == NULL)
 		return -ENOMEM;
 
-	if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) {
-		rc = -EFAULT;
-		goto out_free_val;
+	if (copy_from_user(val, optval, optlen)) {
+		kfree(val);
+		return -EFAULT;
 	}
 
-	rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat,
-			      val, opt.dccpsf_len, GFP_KERNEL);
-	if (rc)
-		goto out_free_val;
+	lock_sock(sk);
+	if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
 
-out:
-	return rc;
+	if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
+	release_sock(sk);
 
-out_free_val:
 	kfree(val);
-	goto out;
+	return rc;
 }
 
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
@@ -510,7 +501,21 @@
 	struct dccp_sock *dp = dccp_sk(sk);
 	int val, err = 0;
 
-	if (optlen < sizeof(int))
+	switch (optname) {
+	case DCCP_SOCKOPT_PACKET_SIZE:
+		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
+		return 0;
+	case DCCP_SOCKOPT_CHANGE_L:
+	case DCCP_SOCKOPT_CHANGE_R:
+		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
+		return 0;
+	case DCCP_SOCKOPT_CCID:
+	case DCCP_SOCKOPT_RX_CCID:
+	case DCCP_SOCKOPT_TX_CCID:
+		return dccp_setsockopt_ccid(sk, optname, optval, optlen);
+	}
+
+	if (optlen < (int)sizeof(int))
 		return -EINVAL;
 
 	if (get_user(val, (int __user *)optval))
@@ -521,53 +526,24 @@
 
 	lock_sock(sk);
 	switch (optname) {
-	case DCCP_SOCKOPT_PACKET_SIZE:
-		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
-		err = 0;
-		break;
-	case DCCP_SOCKOPT_CHANGE_L:
-		if (optlen != sizeof(struct dccp_so_feat))
-			err = -EINVAL;
-		else
-			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
-						     (struct dccp_so_feat __user *)
-						     optval);
-		break;
-	case DCCP_SOCKOPT_CHANGE_R:
-		if (optlen != sizeof(struct dccp_so_feat))
-			err = -EINVAL;
-		else
-			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
-						     (struct dccp_so_feat __user *)
-						     optval);
-		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		if (dp->dccps_role != DCCP_ROLE_SERVER)
 			err = -EOPNOTSUPP;
 		else
 			dp->dccps_server_timewait = (val != 0);
 		break;
-	case DCCP_SOCKOPT_SEND_CSCOV:	/* sender side, RFC 4340, sec. 9.2 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else
-			dp->dccps_pcslen = val;
+	case DCCP_SOCKOPT_SEND_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, false);
 		break;
-	case DCCP_SOCKOPT_RECV_CSCOV:	/* receiver side, RFC 4340 sec. 9.2.1 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else {
-			dp->dccps_pcrlen = val;
-			/* FIXME: add feature negotiation,
-			 * ChangeL(MinimumChecksumCoverage, val) */
-		}
+	case DCCP_SOCKOPT_RECV_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, true);
 		break;
 	default:
 		err = -ENOPROTOOPT;
 		break;
 	}
-
 	release_sock(sk);
+
 	return err;
 }
 
@@ -648,6 +624,18 @@
 	case DCCP_SOCKOPT_GET_CUR_MPS:
 		val = dp->dccps_mss_cache;
 		break;
+	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
+		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
+	case DCCP_SOCKOPT_TX_CCID:
+		val = ccid_get_current_tx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
+	case DCCP_SOCKOPT_RX_CCID:
+		val = ccid_get_current_rx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;
@@ -976,7 +964,7 @@
 	state = sk->sk_state;
 	sock_hold(sk);
 	sock_orphan(sk);
-	atomic_inc(sk->sk_prot->orphan_count);
+	percpu_counter_inc(sk->sk_prot->orphan_count);
 
 	/*
 	 * It is the last release_sock in its life. It will remove backlog.
@@ -1040,17 +1028,21 @@
 {
 	unsigned long goal;
 	int ehash_order, bhash_order, i;
-	int rc = -ENOBUFS;
+	int rc;
 
 	BUILD_BUG_ON(sizeof(struct dccp_skb_cb) >
 		     FIELD_SIZEOF(struct sk_buff, cb));
-
+	rc = percpu_counter_init(&dccp_orphan_count, 0);
+	if (rc)
+		goto out;
+	rc = -ENOBUFS;
+	inet_hashinfo_init(&dccp_hashinfo);
 	dccp_hashinfo.bind_bucket_cachep =
 		kmem_cache_create("dccp_bind_bucket",
 				  sizeof(struct inet_bind_bucket), 0,
 				  SLAB_HWCACHE_ALIGN, NULL);
 	if (!dccp_hashinfo.bind_bucket_cachep)
-		goto out;
+		goto out_free_percpu;
 
 	/*
 	 * Size and allocate the main established and bind bucket
@@ -1084,8 +1076,8 @@
 	}
 
 	for (i = 0; i < dccp_hashinfo.ehash_size; i++) {
-		INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].chain);
-		INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].twchain);
+		INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].chain, i);
+		INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].twchain, i);
 	}
 
 	if (inet_ehash_locks_alloc(&dccp_hashinfo))
@@ -1143,6 +1135,8 @@
 out_free_bind_bucket_cachep:
 	kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
 	dccp_hashinfo.bind_bucket_cachep = NULL;
+out_free_percpu:
+	percpu_counter_destroy(&dccp_orphan_count);
 	goto out;
 }
 
diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c
index 2129599..018e210 100644
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -41,27 +41,6 @@
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "ack_ratio",
-		.data		= &sysctl_dccp_feat_ack_ratio,
-		.maxlen		= sizeof(sysctl_dccp_feat_ack_ratio),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
-		.procname	= "send_ackvec",
-		.data		= &sysctl_dccp_feat_send_ack_vector,
-		.maxlen		= sizeof(sysctl_dccp_feat_send_ack_vector),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
-		.procname	= "send_ndp",
-		.data		= &sysctl_dccp_feat_send_ndp_count,
-		.maxlen		= sizeof(sysctl_dccp_feat_send_ndp_count),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),
diff --git a/net/dccp/timer.c b/net/dccp/timer.c
index 54b3c7e..162d1e6 100644
--- a/net/dccp/timer.c
+++ b/net/dccp/timer.c
@@ -87,17 +87,6 @@
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
-	/* retransmit timer is used for feature negotiation throughout
-	 * connection.  In this case, no packet is re-transmitted, but rather an
-	 * ack is generated and pending changes are placed into its options.
-	 */
-	if (sk->sk_send_head == NULL) {
-		dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk);
-		if (sk->sk_state == DCCP_OPEN)
-			dccp_send_ack(sk);
-		goto backoff;
-	}
-
 	/*
 	 * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
 	 * sent, no need to retransmit, this sock is dead.
@@ -126,7 +115,6 @@
 		return;
 	}
 
-backoff:
 	icsk->icsk_backoff++;
 
 	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 3c23ab3..cf0e184 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -167,7 +167,7 @@
 	if (scp->addr.sdn_flags & SDF_WILD)
 		return hlist_empty(&dn_wild_sk) ? &dn_wild_sk : NULL;
 
-	return &dn_sk_hash[dn_ntohs(scp->addrloc) & DN_SK_HASH_MASK];
+	return &dn_sk_hash[le16_to_cpu(scp->addrloc) & DN_SK_HASH_MASK];
 }
 
 /*
@@ -181,7 +181,7 @@
 	if (port == 0)
 		return -1;
 
-	sk_for_each(sk, node, &dn_sk_hash[dn_ntohs(port) & DN_SK_HASH_MASK]) {
+	sk_for_each(sk, node, &dn_sk_hash[le16_to_cpu(port) & DN_SK_HASH_MASK]) {
 		struct dn_scp *scp = DN_SK(sk);
 		if (scp->addrloc == port)
 			return -1;
@@ -195,12 +195,12 @@
 static unsigned short port = 0x2000;
 	unsigned short i_port = port;
 
-	while(check_port(dn_htons(++port)) != 0) {
+	while(check_port(cpu_to_le16(++port)) != 0) {
 		if (port == i_port)
 			return 0;
 	}
 
-	scp->addrloc = dn_htons(port);
+	scp->addrloc = cpu_to_le16(port);
 
 	return 1;
 }
@@ -255,7 +255,7 @@
 
 	if (hash == 0) {
 		hash = addr->sdn_objnamel;
-		for(i = 0; i < dn_ntohs(addr->sdn_objnamel); i++) {
+		for(i = 0; i < le16_to_cpu(addr->sdn_objnamel); i++) {
 			hash ^= addr->sdn_objname[i];
 			hash ^= (hash << 3);
 		}
@@ -297,16 +297,16 @@
 			break;
 		case 1:
 			*buf++ = 0;
-			*buf++ = dn_ntohs(sdn->sdn_objnamel);
-			memcpy(buf, sdn->sdn_objname, dn_ntohs(sdn->sdn_objnamel));
-			len = 3 + dn_ntohs(sdn->sdn_objnamel);
+			*buf++ = le16_to_cpu(sdn->sdn_objnamel);
+			memcpy(buf, sdn->sdn_objname, le16_to_cpu(sdn->sdn_objnamel));
+			len = 3 + le16_to_cpu(sdn->sdn_objnamel);
 			break;
 		case 2:
 			memset(buf, 0, 5);
 			buf += 5;
-			*buf++ = dn_ntohs(sdn->sdn_objnamel);
-			memcpy(buf, sdn->sdn_objname, dn_ntohs(sdn->sdn_objnamel));
-			len = 7 + dn_ntohs(sdn->sdn_objnamel);
+			*buf++ = le16_to_cpu(sdn->sdn_objnamel);
+			memcpy(buf, sdn->sdn_objname, le16_to_cpu(sdn->sdn_objnamel));
+			len = 7 + le16_to_cpu(sdn->sdn_objnamel);
 			break;
 	}
 
@@ -327,7 +327,7 @@
 	int namel = 12;
 
 	sdn->sdn_objnum = 0;
-	sdn->sdn_objnamel = dn_htons(0);
+	sdn->sdn_objnamel = cpu_to_le16(0);
 	memset(sdn->sdn_objname, 0, DN_MAXOBJL);
 
 	if (len < 2)
@@ -361,13 +361,13 @@
 	if (len < 0)
 		return -1;
 
-	sdn->sdn_objnamel = dn_htons(*data++);
-	len -= dn_ntohs(sdn->sdn_objnamel);
+	sdn->sdn_objnamel = cpu_to_le16(*data++);
+	len -= le16_to_cpu(sdn->sdn_objnamel);
 
-	if ((len < 0) || (dn_ntohs(sdn->sdn_objnamel) > namel))
+	if ((len < 0) || (le16_to_cpu(sdn->sdn_objnamel) > namel))
 		return -1;
 
-	memcpy(sdn->sdn_objname, data, dn_ntohs(sdn->sdn_objnamel));
+	memcpy(sdn->sdn_objname, data, le16_to_cpu(sdn->sdn_objnamel));
 
 	return size - len;
 }
@@ -391,7 +391,7 @@
 				continue;
 			if (scp->addr.sdn_objnamel != addr->sdn_objnamel)
 				continue;
-			if (memcmp(scp->addr.sdn_objname, addr->sdn_objname, dn_ntohs(addr->sdn_objnamel)) != 0)
+			if (memcmp(scp->addr.sdn_objname, addr->sdn_objname, le16_to_cpu(addr->sdn_objnamel)) != 0)
 				continue;
 		}
 		sock_hold(sk);
@@ -419,7 +419,7 @@
 	struct dn_scp *scp;
 
 	read_lock(&dn_hash_lock);
-	sk_for_each(sk, node, &dn_sk_hash[dn_ntohs(cb->dst_port) & DN_SK_HASH_MASK]) {
+	sk_for_each(sk, node, &dn_sk_hash[le16_to_cpu(cb->dst_port) & DN_SK_HASH_MASK]) {
 		scp = DN_SK(sk);
 		if (cb->src != dn_saddr2dn(&scp->peer))
 			continue;
@@ -734,10 +734,10 @@
 	if (saddr->sdn_family != AF_DECnet)
 		return -EINVAL;
 
-	if (dn_ntohs(saddr->sdn_nodeaddrl) && (dn_ntohs(saddr->sdn_nodeaddrl) != 2))
+	if (le16_to_cpu(saddr->sdn_nodeaddrl) && (le16_to_cpu(saddr->sdn_nodeaddrl) != 2))
 		return -EINVAL;
 
-	if (dn_ntohs(saddr->sdn_objnamel) > DN_MAXOBJL)
+	if (le16_to_cpu(saddr->sdn_objnamel) > DN_MAXOBJL)
 		return -EINVAL;
 
 	if (saddr->sdn_flags & ~SDF_WILD)
@@ -748,7 +748,7 @@
 		return -EACCES;
 
 	if (!(saddr->sdn_flags & SDF_WILD)) {
-		if (dn_ntohs(saddr->sdn_nodeaddrl)) {
+		if (le16_to_cpu(saddr->sdn_nodeaddrl)) {
 			read_lock(&dev_base_lock);
 			ldev = NULL;
 			for_each_netdev(&init_net, dev) {
@@ -799,15 +799,15 @@
 	if ((scp->accessdata.acc_accl != 0) &&
 		(scp->accessdata.acc_accl <= 12)) {
 
-		scp->addr.sdn_objnamel = dn_htons(scp->accessdata.acc_accl);
-		memcpy(scp->addr.sdn_objname, scp->accessdata.acc_acc, dn_ntohs(scp->addr.sdn_objnamel));
+		scp->addr.sdn_objnamel = cpu_to_le16(scp->accessdata.acc_accl);
+		memcpy(scp->addr.sdn_objname, scp->accessdata.acc_acc, le16_to_cpu(scp->addr.sdn_objnamel));
 
 		scp->accessdata.acc_accl = 0;
 		memset(scp->accessdata.acc_acc, 0, 40);
 	}
 	/* End of compatibility stuff */
 
-	scp->addr.sdn_add.a_len = dn_htons(2);
+	scp->addr.sdn_add.a_len = cpu_to_le16(2);
 	rv = dn_dev_bind_default((__le16 *)scp->addr.sdn_add.a_addr);
 	if (rv == 0) {
 		rv = dn_hash_sock(sk);
@@ -1027,7 +1027,7 @@
 	u16 len = *ptr++; /* yes, it's 8bit on the wire */
 
 	BUG_ON(len > 16); /* we've checked the contents earlier */
-	opt->opt_optl   = dn_htons(len);
+	opt->opt_optl   = cpu_to_le16(len);
 	opt->opt_status = 0;
 	memcpy(opt->opt_data, ptr, len);
 	skb_pull(skb, len + 1);
@@ -1375,7 +1375,7 @@
 			if (optlen != sizeof(struct optdata_dn))
 				return -EINVAL;
 
-			if (dn_ntohs(u.opt.opt_optl) > 16)
+			if (le16_to_cpu(u.opt.opt_optl) > 16)
 				return -EINVAL;
 
 			memcpy(&scp->conndata_out, &u.opt, optlen);
@@ -1388,7 +1388,7 @@
 			if (optlen != sizeof(struct optdata_dn))
 				return -EINVAL;
 
-			if (dn_ntohs(u.opt.opt_optl) > 16)
+			if (le16_to_cpu(u.opt.opt_optl) > 16)
 				return -EINVAL;
 
 			memcpy(&scp->discdata_out, &u.opt, optlen);
@@ -2213,12 +2213,12 @@
 {
 	int i;
 
-	switch (dn_ntohs(dn->sdn_objnamel)) {
+	switch (le16_to_cpu(dn->sdn_objnamel)) {
 		case 0:
 			sprintf(buf, "%d", dn->sdn_objnum);
 			break;
 		default:
-			for (i = 0; i < dn_ntohs(dn->sdn_objnamel); i++) {
+			for (i = 0; i < le16_to_cpu(dn->sdn_objnamel); i++) {
 				buf[i] = dn->sdn_objname[i];
 				if (IS_NOT_PRINTABLE(buf[i]))
 					buf[i] = '.';
@@ -2281,7 +2281,7 @@
 	seq_printf(seq,
 		   "%6s/%04X %04d:%04d %04d:%04d %01d %-16s "
 		   "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
-		   dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
+		   dn_addr2asc(le16_to_cpu(dn_saddr2dn(&scp->addr)), buf1),
 		   scp->addrloc,
 		   scp->numdat,
 		   scp->numoth,
@@ -2289,7 +2289,7 @@
 		   scp->ackxmt_oth,
 		   scp->flowloc_sw,
 		   local_object,
-		   dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
+		   dn_addr2asc(le16_to_cpu(dn_saddr2dn(&scp->peer)), buf2),
 		   scp->addrrem,
 		   scp->numdat_rcv,
 		   scp->numoth_rcv,
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 28e26bd..daf2b98 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -885,7 +885,7 @@
 	memcpy(msg->tiver, dn_eco_version, 3);
 	dn_dn2eth(msg->id, ifa->ifa_local);
 	msg->iinfo   = DN_RT_INFO_ENDN;
-	msg->blksize = dn_htons(mtu2blksize(dev));
+	msg->blksize = cpu_to_le16(mtu2blksize(dev));
 	msg->area    = 0x00;
 	memset(msg->seed, 0, 8);
 	memcpy(msg->neighbor, dn_hiord, ETH_ALEN);
@@ -895,13 +895,13 @@
 		dn_dn2eth(msg->neighbor, dn->addr);
 	}
 
-	msg->timer   = dn_htons((unsigned short)dn_db->parms.t3);
+	msg->timer   = cpu_to_le16((unsigned short)dn_db->parms.t3);
 	msg->mpd     = 0x00;
 	msg->datalen = 0x02;
 	memset(msg->data, 0xAA, 2);
 
 	pktlen = (__le16 *)skb_push(skb,2);
-	*pktlen = dn_htons(skb->len - 2);
+	*pktlen = cpu_to_le16(skb->len - 2);
 
 	skb_reset_network_header(skb);
 
@@ -929,7 +929,7 @@
 	if (dn->priority != dn_db->parms.priority)
 		return 0;
 
-	if (dn_ntohs(dn->addr) < dn_ntohs(ifa->ifa_local))
+	if (le16_to_cpu(dn->addr) < le16_to_cpu(ifa->ifa_local))
 		return 1;
 
 	return 0;
@@ -973,11 +973,11 @@
 	ptr += ETH_ALEN;
 	*ptr++ = dn_db->parms.forwarding == 1 ?
 			DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
-	*((__le16 *)ptr) = dn_htons(mtu2blksize(dev));
+	*((__le16 *)ptr) = cpu_to_le16(mtu2blksize(dev));
 	ptr += 2;
 	*ptr++ = dn_db->parms.priority; /* Priority */
 	*ptr++ = 0; /* Area: Reserved */
-	*((__le16 *)ptr) = dn_htons((unsigned short)dn_db->parms.t3);
+	*((__le16 *)ptr) = cpu_to_le16((unsigned short)dn_db->parms.t3);
 	ptr += 2;
 	*ptr++ = 0; /* MPD: Reserved */
 	i1 = ptr++;
@@ -993,7 +993,7 @@
 	skb_trim(skb, (27 + *i2));
 
 	pktlen = (__le16 *)skb_push(skb, 2);
-	*pktlen = dn_htons(skb->len - 2);
+	*pktlen = cpu_to_le16(skb->len - 2);
 
 	skb_reset_network_header(skb);
 
@@ -1106,7 +1106,7 @@
 	add_timer(&dn_db->timer);
 }
 
-struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
+static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
 {
 	int i;
 	struct dn_dev_parms *p = dn_dev_list;
@@ -1401,8 +1401,8 @@
 				mtu2blksize(dev),
 				dn_db->parms.priority,
 				dn_db->parms.state, dn_db->parms.name,
-				dn_db->router ? dn_addr2asc(dn_ntohs(*(__le16 *)dn_db->router->primary_key), router_buf) : "",
-				dn_db->peer ? dn_addr2asc(dn_ntohs(*(__le16 *)dn_db->peer->primary_key), peer_buf) : "");
+				dn_db->router ? dn_addr2asc(le16_to_cpu(*(__le16 *)dn_db->router->primary_key), router_buf) : "",
+				dn_db->peer ? dn_addr2asc(le16_to_cpu(*(__le16 *)dn_db->peer->primary_key), peer_buf) : "");
 	}
 	return 0;
 }
@@ -1445,7 +1445,7 @@
 		return;
 	}
 
-	decnet_address = dn_htons((addr[0] << 10) | addr[1]);
+	decnet_address = cpu_to_le16((addr[0] << 10) | addr[1]);
 
 	dn_dev_devices_on();
 
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index 1ca13b1..05b5aa0 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -250,7 +250,7 @@
 	data = skb_push(skb, sizeof(struct dn_long_packet) + 3);
 	lp = (struct dn_long_packet *)(data+3);
 
-	*((__le16 *)data) = dn_htons(skb->len - 2);
+	*((__le16 *)data) = cpu_to_le16(skb->len - 2);
 	*(data + 2) = 1 | DN_RT_F_PF; /* Padding */
 
 	lp->msgflg   = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS));
@@ -294,7 +294,7 @@
 	}
 
 	data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
-	*((__le16 *)data) = dn_htons(skb->len - 2);
+	*((__le16 *)data) = cpu_to_le16(skb->len - 2);
 	sp = (struct dn_short_packet *)(data+2);
 
 	sp->msgflg     = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
@@ -336,12 +336,12 @@
 	}
 
 	data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
-	*((__le16 *)data) = dn_htons(skb->len - 2);
+	*((__le16 *)data) = cpu_to_le16(skb->len - 2);
 	sp = (struct dn_short_packet *)(data + 2);
 
 	sp->msgflg   = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
-	sp->dstnode  = cb->dst & dn_htons(0x03ff);
-	sp->srcnode  = cb->src & dn_htons(0x03ff);
+	sp->dstnode  = cb->dst & cpu_to_le16(0x03ff);
+	sp->srcnode  = cb->src & cpu_to_le16(0x03ff);
 	sp->forward  = cb->hops & 0x3f;
 
 	skb_reset_network_header(skb);
@@ -394,7 +394,7 @@
 			if (neigh->dev->type == ARPHRD_ETHER)
 				memcpy(neigh->ha, &eth_hdr(skb)->h_source, ETH_ALEN);
 
-			dn->blksize  = dn_ntohs(msg->blksize);
+			dn->blksize  = le16_to_cpu(msg->blksize);
 			dn->priority = msg->priority;
 
 			dn->flags &= ~DN_NDFLAG_P3;
@@ -410,7 +410,7 @@
 		}
 
 		/* Only use routers in our area */
-		if ((dn_ntohs(src)>>10) == (dn_ntohs((decnet_address))>>10)) {
+		if ((le16_to_cpu(src)>>10) == (le16_to_cpu((decnet_address))>>10)) {
 			if (!dn_db->router) {
 				dn_db->router = neigh_clone(neigh);
 			} else {
@@ -453,7 +453,7 @@
 			if (neigh->dev->type == ARPHRD_ETHER)
 				memcpy(neigh->ha, &eth_hdr(skb)->h_source, ETH_ALEN);
 			dn->flags   &= ~(DN_NDFLAG_R1 | DN_NDFLAG_R2);
-			dn->blksize  = dn_ntohs(msg->blksize);
+			dn->blksize  = le16_to_cpu(msg->blksize);
 			dn->priority = 0;
 		}
 
@@ -543,7 +543,7 @@
 
 	read_lock(&n->lock);
 	seq_printf(seq, "%-7s %s%s%s   %02x    %02d  %07ld %-8s\n",
-		   dn_addr2asc(dn_ntohs(dn->addr), buf),
+		   dn_addr2asc(le16_to_cpu(dn->addr), buf),
 		   (dn->flags&DN_NDFLAG_R1) ? "1" : "-",
 		   (dn->flags&DN_NDFLAG_R2) ? "2" : "-",
 		   (dn->flags&DN_NDFLAG_P3) ? "3" : "-",
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
index 4074a6e..5d8a2a5 100644
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -83,7 +83,9 @@
 	if (decnet_log_martians && net_ratelimit()) {
 		char *devname = skb->dev ? skb->dev->name : "???";
 		struct dn_skb_cb *cb = DN_SKB_CB(skb);
-		printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, dn_ntohs(cb->src), dn_ntohs(cb->dst), dn_ntohs(cb->src_port), dn_ntohs(cb->dst_port));
+		printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n",
+		       msg, devname, le16_to_cpu(cb->src), le16_to_cpu(cb->dst),
+		       le16_to_cpu(cb->src_port), le16_to_cpu(cb->dst_port));
 	}
 }
 
@@ -133,7 +135,7 @@
 	if (skb->len < 2)
 		return len;
 
-	if ((ack = dn_ntohs(*ptr)) & 0x8000) {
+	if ((ack = le16_to_cpu(*ptr)) & 0x8000) {
 		skb_pull(skb, 2);
 		ptr++;
 		len += 2;
@@ -147,7 +149,7 @@
 	if (skb->len < 2)
 		return len;
 
-	if ((ack = dn_ntohs(*ptr)) & 0x8000) {
+	if ((ack = le16_to_cpu(*ptr)) & 0x8000) {
 		skb_pull(skb, 2);
 		len += 2;
 		if ((ack & 0x4000) == 0) {
@@ -237,7 +239,7 @@
 	cb->dst_port = msg->dstaddr;
 	cb->services = msg->services;
 	cb->info     = msg->info;
-	cb->segsize  = dn_ntohs(msg->segsize);
+	cb->segsize  = le16_to_cpu(msg->segsize);
 
 	if (!pskb_may_pull(skb, sizeof(*msg)))
 		goto err_out;
@@ -344,7 +346,7 @@
 	ptr = skb->data;
 	cb->services = *ptr++;
 	cb->info = *ptr++;
-	cb->segsize = dn_ntohs(*(__le16 *)ptr);
+	cb->segsize = le16_to_cpu(*(__le16 *)ptr);
 
 	if ((scp->state == DN_CI) || (scp->state == DN_CD)) {
 		scp->persist = 0;
@@ -361,7 +363,7 @@
 		if (skb->len > 0) {
 			u16 dlen = *skb->data;
 			if ((dlen <= 16) && (dlen <= skb->len)) {
-				scp->conndata_in.opt_optl = dn_htons(dlen);
+				scp->conndata_in.opt_optl = cpu_to_le16(dlen);
 				skb_copy_from_linear_data_offset(skb, 1,
 					      scp->conndata_in.opt_data, dlen);
 			}
@@ -396,17 +398,17 @@
 	if (skb->len < 2)
 		goto out;
 
-	reason = dn_ntohs(*(__le16 *)skb->data);
+	reason = le16_to_cpu(*(__le16 *)skb->data);
 	skb_pull(skb, 2);
 
-	scp->discdata_in.opt_status = dn_htons(reason);
+	scp->discdata_in.opt_status = cpu_to_le16(reason);
 	scp->discdata_in.opt_optl   = 0;
 	memset(scp->discdata_in.opt_data, 0, 16);
 
 	if (skb->len > 0) {
 		u16 dlen = *skb->data;
 		if ((dlen <= 16) && (dlen <= skb->len)) {
-			scp->discdata_in.opt_optl = dn_htons(dlen);
+			scp->discdata_in.opt_optl = cpu_to_le16(dlen);
 			skb_copy_from_linear_data_offset(skb, 1, scp->discdata_in.opt_data, dlen);
 		}
 	}
@@ -463,7 +465,7 @@
 	if (skb->len != 2)
 		goto out;
 
-	reason = dn_ntohs(*(__le16 *)skb->data);
+	reason = le16_to_cpu(*(__le16 *)skb->data);
 
 	sk->sk_state = TCP_CLOSE;
 
@@ -512,7 +514,7 @@
 	if (skb->len != 4)
 		goto out;
 
-	segnum = dn_ntohs(*(__le16 *)ptr);
+	segnum = le16_to_cpu(*(__le16 *)ptr);
 	ptr += 2;
 	lsflags = *(unsigned char *)ptr++;
 	fcval = *ptr;
@@ -620,7 +622,7 @@
 	if (skb->len < 2)
 		goto out;
 
-	cb->segnum = segnum = dn_ntohs(*(__le16 *)skb->data);
+	cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data);
 	skb_pull(skb, 2);
 
 	if (seq_next(scp->numoth_rcv, segnum)) {
@@ -648,7 +650,7 @@
 	if (skb->len < 2)
 		goto out;
 
-	cb->segnum = segnum = dn_ntohs(*(__le16 *)skb->data);
+	cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data);
 	skb_pull(skb, 2);
 
 	if (seq_next(scp->numdat_rcv, segnum)) {
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index 1964faf..2013c25 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -230,7 +230,6 @@
 /**
  * dn_nsp_output - Try and send something from socket queues
  * @sk: The socket whose queues are to be investigated
- * @gfp: The memory allocation flags
  *
  * Try and send the packet on the end of the data and other data queues.
  * Other data gets priority over data, and if we retransmit a packet we
@@ -326,8 +325,8 @@
 
 	ptr = (__le16 *)dn_mk_common_header(scp, skb, msgflag, hlen);
 
-	*ptr++ = dn_htons(acknum);
-	*ptr++ = dn_htons(ackcrs);
+	*ptr++ = cpu_to_le16(acknum);
+	*ptr++ = cpu_to_le16(ackcrs);
 
 	return ptr;
 }
@@ -345,7 +344,7 @@
 		cb->segnum = scp->numdat;
 		seq_add(&scp->numdat, 1);
 	}
-	*(ptr++) = dn_htons(cb->segnum);
+	*(ptr++) = cpu_to_le16(cb->segnum);
 
 	return ptr;
 }
@@ -523,7 +522,7 @@
 	struct dn_scp *scp = DN_SK(sk);
 	struct sk_buff *skb = NULL;
 	struct nsp_conn_init_msg *msg;
-	__u8 len = (__u8)dn_ntohs(scp->conndata_out.opt_optl);
+	__u8 len = (__u8)le16_to_cpu(scp->conndata_out.opt_optl);
 
 	if ((skb = dn_alloc_skb(sk, 50 + len, gfp)) == NULL)
 		return;
@@ -534,7 +533,7 @@
 	msg->srcaddr = scp->addrloc;
 	msg->services = scp->services_loc;
 	msg->info = scp->info_loc;
-	msg->segsize = dn_htons(scp->segsize_loc);
+	msg->segsize = cpu_to_le16(scp->segsize_loc);
 
 	*skb_put(skb,1) = len;
 
@@ -560,7 +559,7 @@
 
 	if ((dst == NULL) || (rem == 0)) {
 		if (net_ratelimit())
-			printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", dn_ntohs(rem), dst);
+			printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", le16_to_cpu(rem), dst);
 		return;
 	}
 
@@ -573,7 +572,7 @@
 	msg += 2;
 	*(__le16 *)msg = loc;
 	msg += 2;
-	*(__le16 *)msg = dn_htons(reason);
+	*(__le16 *)msg = cpu_to_le16(reason);
 	msg += 2;
 	if (msgflg == NSP_DISCINIT)
 		*msg++ = ddl;
@@ -599,10 +598,10 @@
 	int ddl = 0;
 
 	if (msgflg == NSP_DISCINIT)
-		ddl = dn_ntohs(scp->discdata_out.opt_optl);
+		ddl = le16_to_cpu(scp->discdata_out.opt_optl);
 
 	if (reason == 0)
-		reason = dn_ntohs(scp->discdata_out.opt_status);
+		reason = le16_to_cpu(scp->discdata_out.opt_status);
 
 	dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->sk_dst_cache, ddl,
 		scp->discdata_out.opt_data, scp->addrrem, scp->addrloc);
@@ -676,7 +675,7 @@
 	msg->srcaddr	= scp->addrloc;
 	msg->services	= scp->services_loc;	/* Requested flow control    */
 	msg->info	= scp->info_loc;	/* Version Number            */
-	msg->segsize	= dn_htons(scp->segsize_loc);	/* Max segment size  */
+	msg->segsize	= cpu_to_le16(scp->segsize_loc);	/* Max segment size  */
 
 	if (scp->peer.sdn_objnum)
 		type = 0;
@@ -709,7 +708,7 @@
 	if (aux > 0)
 	memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux);
 
-	aux = (__u8)dn_ntohs(scp->conndata_out.opt_optl);
+	aux = (__u8)le16_to_cpu(scp->conndata_out.opt_optl);
 	*skb_put(skb, 1) = aux;
 	if (aux > 0)
 	memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux);
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 821bd1c..c754670 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -131,7 +131,6 @@
 	.negative_advice =	dn_dst_negative_advice,
 	.link_failure =		dn_dst_link_failure,
 	.update_pmtu =		dn_dst_update_pmtu,
-	.entry_size =		sizeof(struct dn_route),
 	.entries =		ATOMIC_INIT(0),
 };
 
@@ -312,7 +311,7 @@
 	return 0;
 }
 
-void dn_run_flush(unsigned long dummy)
+static void dn_run_flush(unsigned long dummy)
 {
 	int i;
 	struct dn_route *rt, *next;
@@ -476,7 +475,7 @@
 		printk(KERN_DEBUG
 			"DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n",
 			(int)cb->rt_flags, devname, skb->len,
-			dn_ntohs(cb->src), dn_ntohs(cb->dst),
+			le16_to_cpu(cb->src), le16_to_cpu(cb->dst),
 			err, skb->pkt_type);
 	}
 
@@ -576,7 +575,7 @@
 {
 	struct dn_skb_cb *cb;
 	unsigned char flags = 0;
-	__u16 len = dn_ntohs(*(__le16 *)skb->data);
+	__u16 len = le16_to_cpu(*(__le16 *)skb->data);
 	struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr;
 	unsigned char padlen = 0;
 
@@ -774,7 +773,7 @@
 		struct dn_skb_cb *cb = DN_SKB_CB(skb);
 
 		printk(KERN_DEBUG "dn_rt_bug: skb from:%04x to:%04x\n",
-				dn_ntohs(cb->src), dn_ntohs(cb->dst));
+				le16_to_cpu(cb->src), le16_to_cpu(cb->dst));
 	}
 
 	kfree_skb(skb);
@@ -817,7 +816,7 @@
 
 static inline int dn_match_addr(__le16 addr1, __le16 addr2)
 {
-	__u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2);
+	__u16 tmp = le16_to_cpu(addr1) ^ le16_to_cpu(addr2);
 	int match = 16;
 	while(tmp) {
 		tmp >>= 1;
@@ -887,8 +886,8 @@
 	if (decnet_debug_level & 16)
 		printk(KERN_DEBUG
 		       "dn_route_output_slow: dst=%04x src=%04x mark=%d"
-		       " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst),
-		       dn_ntohs(oldflp->fld_src),
+		       " iif=%d oif=%d\n", le16_to_cpu(oldflp->fld_dst),
+		       le16_to_cpu(oldflp->fld_src),
 		       oldflp->mark, init_net.loopback_dev->ifindex, oldflp->oif);
 
 	/* If we have an output interface, verify its a DECnet device */
@@ -960,7 +959,7 @@
 		printk(KERN_DEBUG
 		       "dn_route_output_slow: initial checks complete."
 		       " dst=%o4x src=%04x oif=%d try_hard=%d\n",
-		       dn_ntohs(fl.fld_dst), dn_ntohs(fl.fld_src),
+		       le16_to_cpu(fl.fld_dst), le16_to_cpu(fl.fld_src),
 		       fl.oif, try_hard);
 
 	/*
@@ -1185,7 +1184,7 @@
 
 	err = __dn_route_output_key(pprt, flp, flags);
 	if (err == 0 && flp->proto) {
-		err = xfrm_lookup(pprt, flp, NULL, 0);
+		err = xfrm_lookup(&init_net, pprt, flp, NULL, 0);
 	}
 	return err;
 }
@@ -1196,8 +1195,8 @@
 
 	err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD);
 	if (err == 0 && fl->proto) {
-		err = xfrm_lookup(pprt, fl, sk, (flags & MSG_DONTWAIT) ?
-						0 : XFRM_LOOKUP_WAIT);
+		err = xfrm_lookup(&init_net, pprt, fl, sk,
+				 (flags & MSG_DONTWAIT) ? 0 : XFRM_LOOKUP_WAIT);
 	}
 	return err;
 }
@@ -1423,7 +1422,7 @@
 	goto done;
 }
 
-int dn_route_input(struct sk_buff *skb)
+static int dn_route_input(struct sk_buff *skb)
 {
 	struct dn_route *rt;
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
@@ -1712,8 +1711,8 @@
 
 	seq_printf(seq, "%-8s %-7s %-7s %04d %04d %04d\n",
 			rt->u.dst.dev ? rt->u.dst.dev->name : "*",
-			dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1),
-			dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2),
+			dn_addr2asc(le16_to_cpu(rt->rt_daddr), buf1),
+			dn_addr2asc(le16_to_cpu(rt->rt_saddr), buf2),
 			atomic_read(&rt->u.dst.__refcnt),
 			rt->u.dst.__use,
 			(int) dst_metric(&rt->u.dst, RTAX_RTT));
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index 3a2830a..69ad928 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -85,7 +85,7 @@
 
 static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz)
 {
-	u16 h = dn_ntohs(key.datum)>>(16 - dz->dz_order);
+	u16 h = le16_to_cpu(key.datum)>>(16 - dz->dz_order);
 	h ^= (h >> 10);
 	h ^= (h >> 6);
 	h &= DZ_HASHMASK(dz);
diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c
index 36400b2..965397a 100644
--- a/net/decnet/sysctl_net_decnet.c
+++ b/net/decnet/sysctl_net_decnet.c
@@ -126,7 +126,7 @@
 	if (INVALID_END_CHAR(*str))
 		return -1;
 
-	*addr = dn_htons((area << 10) | node);
+	*addr = cpu_to_le16((area << 10) | node);
 
 	return 0;
 }
@@ -201,7 +201,7 @@
 		return 0;
 	}
 
-	dn_addr2asc(dn_ntohs(decnet_address), addr);
+	dn_addr2asc(le16_to_cpu(decnet_address), addr);
 	len = strlen(addr);
 	addr[len++] = '\n';
 
@@ -354,8 +354,8 @@
 		.data = node_name,
 		.maxlen = 7,
 		.mode = 0644,
-		.proc_handler = &proc_dostring,
-		.strategy = &sysctl_string,
+		.proc_handler = proc_dostring,
+		.strategy = sysctl_string,
 	},
 	{
 		.ctl_name = NET_DECNET_DEFAULT_DEVICE,
@@ -371,8 +371,8 @@
 		.data = &decnet_time_wait,
 		.maxlen = sizeof(int),
 		.mode = 0644,
-		.proc_handler = &proc_dointvec_minmax,
-		.strategy = &sysctl_intvec,
+		.proc_handler = proc_dointvec_minmax,
+		.strategy = sysctl_intvec,
 		.extra1 = &min_decnet_time_wait,
 		.extra2 = &max_decnet_time_wait
 	},
@@ -382,8 +382,8 @@
 		.data = &decnet_dn_count,
 		.maxlen = sizeof(int),
 		.mode = 0644,
-		.proc_handler = &proc_dointvec_minmax,
-		.strategy = &sysctl_intvec,
+		.proc_handler = proc_dointvec_minmax,
+		.strategy = sysctl_intvec,
 		.extra1 = &min_state_count,
 		.extra2 = &max_state_count
 	},
@@ -393,8 +393,8 @@
 		.data = &decnet_di_count,
 		.maxlen = sizeof(int),
 		.mode = 0644,
-		.proc_handler = &proc_dointvec_minmax,
-		.strategy = &sysctl_intvec,
+		.proc_handler = proc_dointvec_minmax,
+		.strategy = sysctl_intvec,
 		.extra1 = &min_state_count,
 		.extra2 = &max_state_count
 	},
@@ -404,8 +404,8 @@
 		.data = &decnet_dr_count,
 		.maxlen = sizeof(int),
 		.mode = 0644,
-		.proc_handler = &proc_dointvec_minmax,
-		.strategy = &sysctl_intvec,
+		.proc_handler = proc_dointvec_minmax,
+		.strategy = sysctl_intvec,
 		.extra1 = &min_state_count,
 		.extra2 = &max_state_count
 	},
@@ -415,8 +415,8 @@
 		.data = &decnet_dst_gc_interval,
 		.maxlen = sizeof(int),
 		.mode = 0644,
-		.proc_handler = &proc_dointvec_minmax,
-		.strategy = &sysctl_intvec,
+		.proc_handler = proc_dointvec_minmax,
+		.strategy = sysctl_intvec,
 		.extra1 = &min_decnet_dst_gc_interval,
 		.extra2 = &max_decnet_dst_gc_interval
 	},
@@ -426,8 +426,8 @@
 		.data = &decnet_no_fc_max_cwnd,
 		.maxlen = sizeof(int),
 		.mode = 0644,
-		.proc_handler = &proc_dointvec_minmax,
-		.strategy = &sysctl_intvec,
+		.proc_handler = proc_dointvec_minmax,
+		.strategy = sysctl_intvec,
 		.extra1 = &min_decnet_no_fc_max_cwnd,
 		.extra2 = &max_decnet_no_fc_max_cwnd
 	},
@@ -437,8 +437,8 @@
 		.data = &sysctl_decnet_mem,
 		.maxlen = sizeof(sysctl_decnet_mem),
 		.mode = 0644,
-		.proc_handler = &proc_dointvec,
-		.strategy = &sysctl_intvec,
+		.proc_handler = proc_dointvec,
+		.strategy = sysctl_intvec,
 	},
 	{
 		.ctl_name = NET_DECNET_RMEM,
@@ -446,8 +446,8 @@
 		.data = &sysctl_decnet_rmem,
 		.maxlen = sizeof(sysctl_decnet_rmem),
 		.mode = 0644,
-		.proc_handler = &proc_dointvec,
-		.strategy = &sysctl_intvec,
+		.proc_handler = proc_dointvec,
+		.strategy = sysctl_intvec,
 	},
 	{
 		.ctl_name = NET_DECNET_WMEM,
@@ -455,8 +455,8 @@
 		.data = &sysctl_decnet_wmem,
 		.maxlen = sizeof(sysctl_decnet_wmem),
 		.mode = 0644,
-		.proc_handler = &proc_dointvec,
-		.strategy = &sysctl_intvec,
+		.proc_handler = proc_dointvec,
+		.strategy = sysctl_intvec,
 	},
 	{
 		.ctl_name = NET_DECNET_DEBUG_LEVEL,
@@ -464,8 +464,8 @@
 		.data = &decnet_debug_level,
 		.maxlen = sizeof(int),
 		.mode = 0644,
-		.proc_handler = &proc_dointvec,
-		.strategy = &sysctl_intvec,
+		.proc_handler = proc_dointvec,
+		.strategy = sysctl_intvec,
 	},
 	{0}
 };
diff --git a/net/dsa/mv88e6060.c b/net/dsa/mv88e6060.c
index 54068ef..85081ae 100644
--- a/net/dsa/mv88e6060.c
+++ b/net/dsa/mv88e6060.c
@@ -222,7 +222,7 @@
 
 	for (i = 0; i < DSA_MAX_PORTS; i++) {
 		struct net_device *dev;
-		int port_status;
+		int uninitialized_var(port_status);
 		int link;
 		int speed;
 		int duplex;
@@ -273,14 +273,14 @@
 	.poll_link	= mv88e6060_poll_link,
 };
 
-int __init mv88e6060_init(void)
+static int __init mv88e6060_init(void)
 {
 	register_switch_driver(&mv88e6060_switch_driver);
 	return 0;
 }
 module_init(mv88e6060_init);
 
-void __exit mv88e6060_cleanup(void)
+static void __exit mv88e6060_cleanup(void)
 {
 	unregister_switch_driver(&mv88e6060_switch_driver);
 }
diff --git a/net/dsa/mv88e6123_61_65.c b/net/dsa/mv88e6123_61_65.c
index 555b164..ec8c6a0 100644
--- a/net/dsa/mv88e6123_61_65.c
+++ b/net/dsa/mv88e6123_61_65.c
@@ -407,14 +407,14 @@
 	.get_sset_count		= mv88e6123_61_65_get_sset_count,
 };
 
-int __init mv88e6123_61_65_init(void)
+static int __init mv88e6123_61_65_init(void)
 {
 	register_switch_driver(&mv88e6123_61_65_switch_driver);
 	return 0;
 }
 module_init(mv88e6123_61_65_init);
 
-void __exit mv88e6123_61_65_cleanup(void)
+static void __exit mv88e6123_61_65_cleanup(void)
 {
 	unregister_switch_driver(&mv88e6123_61_65_switch_driver);
 }
diff --git a/net/dsa/mv88e6131.c b/net/dsa/mv88e6131.c
index 36e01eb..374d46a 100644
--- a/net/dsa/mv88e6131.c
+++ b/net/dsa/mv88e6131.c
@@ -366,14 +366,14 @@
 	.get_sset_count		= mv88e6131_get_sset_count,
 };
 
-int __init mv88e6131_init(void)
+static int __init mv88e6131_init(void)
 {
 	register_switch_driver(&mv88e6131_switch_driver);
 	return 0;
 }
 module_init(mv88e6131_init);
 
-void __exit mv88e6131_cleanup(void)
+static void __exit mv88e6131_cleanup(void)
 {
 	unregister_switch_driver(&mv88e6131_switch_driver);
 }
diff --git a/net/dsa/mv88e6xxx.c b/net/dsa/mv88e6xxx.c
index aa6c609..4e4d8b5 100644
--- a/net/dsa/mv88e6xxx.c
+++ b/net/dsa/mv88e6xxx.c
@@ -358,7 +358,7 @@
 
 	for (i = 0; i < DSA_MAX_PORTS; i++) {
 		struct net_device *dev;
-		int port_status;
+		int uninitialized_var(port_status);
 		int link;
 		int speed;
 		int duplex;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 1af5a79..a3a410d 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -352,7 +352,7 @@
 	netif_carrier_off(slave_dev);
 
 	if (p->phy != NULL) {
-		phy_attach(slave_dev, p->phy->dev.bus_id,
+		phy_attach(slave_dev, dev_name(&p->phy->dev),
 			   0, PHY_INTERFACE_MODE_GMII);
 
 		p->phy->autoneg = AUTONEG_ENABLE;
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 3186654..f99a019 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -162,7 +162,6 @@
 	skb->pkt_type = PACKET_HOST;
 	skb->protocol = eth_type_trans(skb, skb->dev);
 
-	skb->dev->last_rx = jiffies;
 	skb->dev->stats.rx_packets++;
 	skb->dev->stats.rx_bytes += skb->len;
 
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index 9f4ce55..328ec95 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -181,7 +181,6 @@
 	skb->pkt_type = PACKET_HOST;
 	skb->protocol = eth_type_trans(skb, skb->dev);
 
-	skb->dev->last_rx = jiffies;
 	skb->dev->stats.rx_packets++;
 	skb->dev->stats.rx_bytes += skb->len;
 
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index efd2669..b591328 100644
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -98,7 +98,6 @@
 	skb->pkt_type = PACKET_HOST;
 	skb->protocol = eth_type_trans(skb, skb->dev);
 
-	skb->dev->last_rx = jiffies;
 	skb->dev->stats.rx_packets++;
 	skb->dev->stats.rx_bytes += skb->len;
 
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index b9d85af..280352a 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -165,8 +165,8 @@
 	skb_pull(skb, ETH_HLEN);
 	eth = eth_hdr(skb);
 
-	if (is_multicast_ether_addr(eth->h_dest)) {
-		if (!compare_ether_addr(eth->h_dest, dev->broadcast))
+	if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
+		if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast))
 			skb->pkt_type = PACKET_BROADCAST;
 		else
 			skb->pkt_type = PACKET_MULTICAST;
@@ -181,7 +181,7 @@
 	 */
 
 	else if (1 /*dev->flags&IFF_PROMISC */ ) {
-		if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr)))
+		if (unlikely(compare_ether_addr_64bits(eth->h_dest, dev->dev_addr)))
 			skb->pkt_type = PACKET_OTHERHOST;
 	}
 
@@ -282,7 +282,7 @@
  * This doesn't change hardware matching, so needs to be overridden
  * for most real devices.
  */
-static int eth_mac_addr(struct net_device *dev, void *p)
+int eth_mac_addr(struct net_device *dev, void *p)
 {
 	struct sockaddr *addr = p;
 
@@ -293,6 +293,7 @@
 	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
 	return 0;
 }
+EXPORT_SYMBOL(eth_mac_addr);
 
 /**
  * eth_change_mtu - set new MTU size
@@ -302,21 +303,23 @@
  * Allow changing MTU size. Needs to be overridden for devices
  * supporting jumbo frames.
  */
-static int eth_change_mtu(struct net_device *dev, int new_mtu)
+int eth_change_mtu(struct net_device *dev, int new_mtu)
 {
 	if (new_mtu < 68 || new_mtu > ETH_DATA_LEN)
 		return -EINVAL;
 	dev->mtu = new_mtu;
 	return 0;
 }
+EXPORT_SYMBOL(eth_change_mtu);
 
-static int eth_validate_addr(struct net_device *dev)
+int eth_validate_addr(struct net_device *dev)
 {
 	if (!is_valid_ether_addr(dev->dev_addr))
 		return -EADDRNOTAVAIL;
 
 	return 0;
 }
+EXPORT_SYMBOL(eth_validate_addr);
 
 const struct header_ops eth_header_ops ____cacheline_aligned = {
 	.create		= eth_header,
@@ -334,11 +337,11 @@
 void ether_setup(struct net_device *dev)
 {
 	dev->header_ops		= &eth_header_ops;
-
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
 	dev->change_mtu		= eth_change_mtu;
 	dev->set_mac_address 	= eth_mac_addr;
 	dev->validate_addr	= eth_validate_addr;
-
+#endif
 	dev->type		= ARPHRD_ETHER;
 	dev->hard_header_len 	= ETH_HLEN;
 	dev->mtu		= ETH_DATA_LEN;
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig
deleted file mode 100644
index 94ed7d3..0000000
--- a/net/ieee80211/Kconfig
+++ /dev/null
@@ -1,73 +0,0 @@
-config IEEE80211
-	tristate "Generic IEEE 802.11 Networking Stack (DEPRECATED)"
-	---help---
-	This option enables the hardware independent IEEE 802.11
-	networking stack.  This component is deprecated in favor of the
-	mac80211 component.
-
-config IEEE80211_DEBUG
-	bool "Enable full debugging output"
-	depends on IEEE80211
-	---help---
-	  This option will enable debug tracing output for the
-	  ieee80211 network stack.
-
-	  This will result in the kernel module being ~70k larger.  You
-	  can control which debug output is sent to the kernel log by
-	  setting the value in
-
-	  /proc/net/ieee80211/debug_level
-
-	  For example:
-
-	  % echo 0x00000FFO > /proc/net/ieee80211/debug_level
-
-	  For a list of values you can assign to debug_level, you
-	  can look at the bit mask values in <net/ieee80211.h>
-
-	  If you are not trying to debug or develop the ieee80211
-	  subsystem, you most likely want to say N here.
-
-config IEEE80211_CRYPT_WEP
-	tristate "IEEE 802.11 WEP encryption (802.1x)"
-	depends on IEEE80211
-	select CRYPTO
-	select CRYPTO_ARC4
-	select CRYPTO_ECB
-	select CRC32
-	---help---
-	Include software based cipher suites in support of IEEE
-	802.11's WEP.  This is needed for WEP as well as 802.1x.
-
-	This can be compiled as a module and it will be called
-	"ieee80211_crypt_wep".
-
-config IEEE80211_CRYPT_CCMP
-	tristate "IEEE 802.11i CCMP support"
-	depends on IEEE80211
-	select CRYPTO
-	select CRYPTO_AES
-	---help---
-	Include software based cipher suites in support of IEEE 802.11i
-	(aka TGi, WPA, WPA2, WPA-PSK, etc.) for use with CCMP enabled
-	networks.
-
-	This can be compiled as a module and it will be called
-	"ieee80211_crypt_ccmp".
-
-config IEEE80211_CRYPT_TKIP
-	tristate "IEEE 802.11i TKIP encryption"
-	depends on IEEE80211
-	select WIRELESS_EXT
-	select CRYPTO
-	select CRYPTO_MICHAEL_MIC
-	select CRYPTO_ECB
-	select CRC32
-	---help---
-	Include software based cipher suites in support of IEEE 802.11i
-	(aka TGi, WPA, WPA2, WPA-PSK, etc.) for use with TKIP enabled
-	networks.
-
-	This can be compiled as a module and it will be called
-	"ieee80211_crypt_tkip".
-
diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile
deleted file mode 100644
index f988417..0000000
--- a/net/ieee80211/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-obj-$(CONFIG_IEEE80211) += ieee80211.o
-obj-$(CONFIG_IEEE80211) += ieee80211_crypt.o
-obj-$(CONFIG_IEEE80211_CRYPT_WEP) += ieee80211_crypt_wep.o
-obj-$(CONFIG_IEEE80211_CRYPT_CCMP) += ieee80211_crypt_ccmp.o
-obj-$(CONFIG_IEEE80211_CRYPT_TKIP) += ieee80211_crypt_tkip.o
-ieee80211-objs := \
-	ieee80211_module.o \
-	ieee80211_tx.o \
-	ieee80211_rx.o \
-	ieee80211_wx.o \
-	ieee80211_geo.o
-
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c
deleted file mode 100644
index df5592c..0000000
--- a/net/ieee80211/ieee80211_crypt.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Host AP crypto routines
- *
- * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
- * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation. See README and COPYING for
- * more details.
- *
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <net/ieee80211.h>
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("HostAP crypto");
-MODULE_LICENSE("GPL");
-
-struct ieee80211_crypto_alg {
-	struct list_head list;
-	struct ieee80211_crypto_ops *ops;
-};
-
-static LIST_HEAD(ieee80211_crypto_algs);
-static DEFINE_SPINLOCK(ieee80211_crypto_lock);
-
-void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
-{
-	struct ieee80211_crypt_data *entry, *next;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ieee->lock, flags);
-	list_for_each_entry_safe(entry, next, &ieee->crypt_deinit_list, list) {
-		if (atomic_read(&entry->refcnt) != 0 && !force)
-			continue;
-
-		list_del(&entry->list);
-
-		if (entry->ops) {
-			entry->ops->deinit(entry->priv);
-			module_put(entry->ops->owner);
-		}
-		kfree(entry);
-	}
-	spin_unlock_irqrestore(&ieee->lock, flags);
-}
-
-/* After this, crypt_deinit_list won't accept new members */
-void ieee80211_crypt_quiescing(struct ieee80211_device *ieee)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ieee->lock, flags);
-	ieee->crypt_quiesced = 1;
-	spin_unlock_irqrestore(&ieee->lock, flags);
-}
-
-void ieee80211_crypt_deinit_handler(unsigned long data)
-{
-	struct ieee80211_device *ieee = (struct ieee80211_device *)data;
-	unsigned long flags;
-
-	ieee80211_crypt_deinit_entries(ieee, 0);
-
-	spin_lock_irqsave(&ieee->lock, flags);
-	if (!list_empty(&ieee->crypt_deinit_list) && !ieee->crypt_quiesced) {
-		printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
-		       "deletion list\n", ieee->dev->name);
-		ieee->crypt_deinit_timer.expires = jiffies + HZ;
-		add_timer(&ieee->crypt_deinit_timer);
-	}
-	spin_unlock_irqrestore(&ieee->lock, flags);
-}
-
-void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
-				    struct ieee80211_crypt_data **crypt)
-{
-	struct ieee80211_crypt_data *tmp;
-	unsigned long flags;
-
-	if (*crypt == NULL)
-		return;
-
-	tmp = *crypt;
-	*crypt = NULL;
-
-	/* must not run ops->deinit() while there may be pending encrypt or
-	 * decrypt operations. Use a list of delayed deinits to avoid needing
-	 * locking. */
-
-	spin_lock_irqsave(&ieee->lock, flags);
-	if (!ieee->crypt_quiesced) {
-		list_add(&tmp->list, &ieee->crypt_deinit_list);
-		if (!timer_pending(&ieee->crypt_deinit_timer)) {
-			ieee->crypt_deinit_timer.expires = jiffies + HZ;
-			add_timer(&ieee->crypt_deinit_timer);
-		}
-	}
-	spin_unlock_irqrestore(&ieee->lock, flags);
-}
-
-int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops)
-{
-	unsigned long flags;
-	struct ieee80211_crypto_alg *alg;
-
-	alg = kzalloc(sizeof(*alg), GFP_KERNEL);
-	if (alg == NULL)
-		return -ENOMEM;
-
-	alg->ops = ops;
-
-	spin_lock_irqsave(&ieee80211_crypto_lock, flags);
-	list_add(&alg->list, &ieee80211_crypto_algs);
-	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
-
-	printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n",
-	       ops->name);
-
-	return 0;
-}
-
-int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops)
-{
-	struct ieee80211_crypto_alg *alg;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ieee80211_crypto_lock, flags);
-	list_for_each_entry(alg, &ieee80211_crypto_algs, list) {
-		if (alg->ops == ops)
-			goto found;
-	}
-	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
-	return -EINVAL;
-
-      found:
-	printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
-	       "'%s'\n", ops->name);
-	list_del(&alg->list);
-	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
-	kfree(alg);
-	return 0;
-}
-
-struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name)
-{
-	struct ieee80211_crypto_alg *alg;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ieee80211_crypto_lock, flags);
-	list_for_each_entry(alg, &ieee80211_crypto_algs, list) {
-		if (strcmp(alg->ops->name, name) == 0)
-			goto found;
-	}
-	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
-	return NULL;
-
-      found:
-	spin_unlock_irqrestore(&ieee80211_crypto_lock, flags);
-	return alg->ops;
-}
-
-static void *ieee80211_crypt_null_init(int keyidx)
-{
-	return (void *)1;
-}
-
-static void ieee80211_crypt_null_deinit(void *priv)
-{
-}
-
-static struct ieee80211_crypto_ops ieee80211_crypt_null = {
-	.name = "NULL",
-	.init = ieee80211_crypt_null_init,
-	.deinit = ieee80211_crypt_null_deinit,
-	.owner = THIS_MODULE,
-};
-
-static int __init ieee80211_crypto_init(void)
-{
-	return ieee80211_register_crypto_ops(&ieee80211_crypt_null);
-}
-
-static void __exit ieee80211_crypto_deinit(void)
-{
-	ieee80211_unregister_crypto_ops(&ieee80211_crypt_null);
-	BUG_ON(!list_empty(&ieee80211_crypto_algs));
-}
-
-EXPORT_SYMBOL(ieee80211_crypt_deinit_entries);
-EXPORT_SYMBOL(ieee80211_crypt_deinit_handler);
-EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit);
-EXPORT_SYMBOL(ieee80211_crypt_quiescing);
-
-EXPORT_SYMBOL(ieee80211_register_crypto_ops);
-EXPORT_SYMBOL(ieee80211_unregister_crypto_ops);
-EXPORT_SYMBOL(ieee80211_get_crypto_ops);
-
-module_init(ieee80211_crypto_init);
-module_exit(ieee80211_crypto_deinit);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 1aa2dc9..743f554 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -94,6 +94,7 @@
 #include <linux/igmp.h>
 #include <linux/inetdevice.h>
 #include <linux/netdevice.h>
+#include <net/checksum.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/arp.h>
@@ -245,7 +246,7 @@
 	int hash;
 	struct net_protocol *ipprot;
 
-	if (net == &init_net)
+	if (net_eq(net, &init_net))
 		return 1;
 
 	hash = protocol & (MAX_INET_PROTOS - 1);
@@ -272,10 +273,9 @@
 	int try_loading_module = 0;
 	int err;
 
-	if (sock->type != SOCK_RAW &&
-	    sock->type != SOCK_DGRAM &&
-	    !inet_ehash_secret)
-		build_ehash_secret();
+	if (unlikely(!inet_ehash_secret))
+		if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
+			build_ehash_secret();
 
 	sock->state = SS_UNCONNECTED;
 
@@ -1070,11 +1070,8 @@
 		return 0;
 
 	if (sysctl_ip_dynaddr > 1) {
-		printk(KERN_INFO "%s(): shifting inet->"
-				 "saddr from " NIPQUAD_FMT " to " NIPQUAD_FMT "\n",
-		       __func__,
-		       NIPQUAD(old_saddr),
-		       NIPQUAD(new_saddr));
+		printk(KERN_INFO "%s(): shifting inet->saddr from %pI4 to %pI4\n",
+		       __func__, &old_saddr, &new_saddr);
 	}
 
 	inet->saddr = inet->rcv_saddr = new_saddr;
@@ -1245,6 +1242,100 @@
 	return segs;
 }
 
+static struct sk_buff **inet_gro_receive(struct sk_buff **head,
+					 struct sk_buff *skb)
+{
+	struct net_protocol *ops;
+	struct sk_buff **pp = NULL;
+	struct sk_buff *p;
+	struct iphdr *iph;
+	int flush = 1;
+	int proto;
+	int id;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
+		goto out;
+
+	iph = ip_hdr(skb);
+	proto = iph->protocol & (MAX_INET_PROTOS - 1);
+
+	rcu_read_lock();
+	ops = rcu_dereference(inet_protos[proto]);
+	if (!ops || !ops->gro_receive)
+		goto out_unlock;
+
+	if (iph->version != 4 || iph->ihl != 5)
+		goto out_unlock;
+
+	if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
+		goto out_unlock;
+
+	flush = ntohs(iph->tot_len) != skb->len ||
+		iph->frag_off != htons(IP_DF);
+	id = ntohs(iph->id);
+
+	for (p = *head; p; p = p->next) {
+		struct iphdr *iph2;
+
+		if (!NAPI_GRO_CB(p)->same_flow)
+			continue;
+
+		iph2 = ip_hdr(p);
+
+		if (iph->protocol != iph2->protocol ||
+		    iph->tos != iph2->tos ||
+		    memcmp(&iph->saddr, &iph2->saddr, 8)) {
+			NAPI_GRO_CB(p)->same_flow = 0;
+			continue;
+		}
+
+		/* All fields must match except length and checksum. */
+		NAPI_GRO_CB(p)->flush |=
+			memcmp(&iph->frag_off, &iph2->frag_off, 4) ||
+			(u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) != id;
+
+		NAPI_GRO_CB(p)->flush |= flush;
+	}
+
+	NAPI_GRO_CB(skb)->flush |= flush;
+	__skb_pull(skb, sizeof(*iph));
+	skb_reset_transport_header(skb);
+
+	pp = ops->gro_receive(head, skb);
+
+out_unlock:
+	rcu_read_unlock();
+
+out:
+	NAPI_GRO_CB(skb)->flush |= flush;
+
+	return pp;
+}
+
+static int inet_gro_complete(struct sk_buff *skb)
+{
+	struct net_protocol *ops;
+	struct iphdr *iph = ip_hdr(skb);
+	int proto = iph->protocol & (MAX_INET_PROTOS - 1);
+	int err = -ENOSYS;
+	__be16 newlen = htons(skb->len - skb_network_offset(skb));
+
+	csum_replace2(&iph->check, iph->tot_len, newlen);
+	iph->tot_len = newlen;
+
+	rcu_read_lock();
+	ops = rcu_dereference(inet_protos[proto]);
+	if (WARN_ON(!ops || !ops->gro_complete))
+		goto out_unlock;
+
+	err = ops->gro_complete(skb);
+
+out_unlock:
+	rcu_read_unlock();
+
+	return err;
+}
+
 int inet_ctl_sock_create(struct sock **sk, unsigned short family,
 			 unsigned short type, unsigned char protocol,
 			 struct net *net)
@@ -1311,6 +1402,7 @@
 #ifdef CONFIG_IP_MULTICAST
 static struct net_protocol igmp_protocol = {
 	.handler =	igmp_rcv,
+	.netns_ok =	1,
 };
 #endif
 
@@ -1319,6 +1411,8 @@
 	.err_handler =	tcp_v4_err,
 	.gso_send_check = tcp_v4_gso_send_check,
 	.gso_segment =	tcp_tso_segment,
+	.gro_receive =	tcp4_gro_receive,
+	.gro_complete =	tcp4_gro_complete,
 	.no_policy =	1,
 	.netns_ok =	1,
 };
@@ -1411,6 +1505,8 @@
 	.func = ip_rcv,
 	.gso_send_check = inet_gso_send_check,
 	.gso_segment = inet_gso_segment,
+	.gro_receive = inet_gro_receive,
+	.gro_complete = inet_gro_complete,
 };
 
 static int __init inet_init(void)
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 8219b7e..e878e49 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -201,15 +201,16 @@
 
 static void ah4_err(struct sk_buff *skb, u32 info)
 {
-	struct iphdr *iph = (struct iphdr*)skb->data;
-	struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2));
+	struct net *net = dev_net(skb->dev);
+	struct iphdr *iph = (struct iphdr *)skb->data;
+	struct ip_auth_hdr *ah = (struct ip_auth_hdr *)(skb->data+(iph->ihl<<2));
 	struct xfrm_state *x;
 
 	if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH ||
 	    icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
 		return;
 
-	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET);
+	x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET);
 	if (!x)
 		return;
 	printk(KERN_DEBUG "pmtu discovery on SA AH/%08x/%08x\n",
@@ -293,9 +294,7 @@
 		return;
 
 	kfree(ahp->work_icv);
-	ahp->work_icv = NULL;
 	crypto_free_hash(ahp->tfm);
-	ahp->tfm = NULL;
 	kfree(ahp);
 }
 
@@ -316,6 +315,7 @@
 	.handler	=	xfrm4_rcv,
 	.err_handler	=	ah4_err,
 	.no_policy	=	1,
+	.netns_ok	=	1,
 };
 
 static int __init ah4_init(void)
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 1a9dd66..29a74c0 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -506,7 +506,7 @@
 	if (dev == NULL)
 		return -EINVAL;
 	if (n == NULL) {
-		__be32 nexthop = ((struct rtable*)dst)->rt_gateway;
+		__be32 nexthop = ((struct rtable *)dst)->rt_gateway;
 		if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
 			nexthop = 0;
 		n = __neigh_lookup_errno(
@@ -640,14 +640,14 @@
 	arp_ptr=(unsigned char *)(arp+1);
 
 	memcpy(arp_ptr, src_hw, dev->addr_len);
-	arp_ptr+=dev->addr_len;
-	memcpy(arp_ptr, &src_ip,4);
-	arp_ptr+=4;
+	arp_ptr += dev->addr_len;
+	memcpy(arp_ptr, &src_ip, 4);
+	arp_ptr += 4;
 	if (target_hw != NULL)
 		memcpy(arp_ptr, target_hw, dev->addr_len);
 	else
 		memset(arp_ptr, 0, dev->addr_len);
-	arp_ptr+=dev->addr_len;
+	arp_ptr += dev->addr_len;
 	memcpy(arp_ptr, &dest_ip, 4);
 
 	return skb;
@@ -818,18 +818,18 @@
 		addr_type = rt->rt_type;
 
 		if (addr_type == RTN_LOCAL) {
-			n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
-			if (n) {
-				int dont_send = 0;
+			int dont_send = 0;
 
-				if (!dont_send)
-					dont_send |= arp_ignore(in_dev,sip,tip);
-				if (!dont_send && IN_DEV_ARPFILTER(in_dev))
-					dont_send |= arp_filter(sip,tip,dev);
-				if (!dont_send)
+			if (!dont_send)
+				dont_send |= arp_ignore(in_dev,sip,tip);
+			if (!dont_send && IN_DEV_ARPFILTER(in_dev))
+				dont_send |= arp_filter(sip,tip,dev);
+			if (!dont_send) {
+				n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
+				if (n) {
 					arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
-
-				neigh_release(n);
+					neigh_release(n);
+				}
 			}
 			goto out;
 		} else if (IN_DEV_FORWARD(in_dev)) {
@@ -1308,7 +1308,7 @@
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 	}
 #endif
-	sprintf(tbuf, NIPQUAD_FMT, NIPQUAD(*(u32*)n->primary_key));
+	sprintf(tbuf, "%pI4", n->primary_key);
 	seq_printf(seq, "%-16s 0x%-10x0x%-10x%s     *        %s\n",
 		   tbuf, hatype, arp_state_to_flags(n), hbuffer, dev->name);
 	read_unlock(&n->lock);
@@ -1321,7 +1321,7 @@
 	int hatype = dev ? dev->type : 0;
 	char tbuf[16];
 
-	sprintf(tbuf, NIPQUAD_FMT, NIPQUAD(*(u32*)n->key));
+	sprintf(tbuf, "%pI4", n->key);
 	seq_printf(seq, "%-16s 0x%-10x0x%-10x%s     *        %s\n",
 		   tbuf, hatype, ATF_PUBL | ATF_PERM, "00:00:00:00:00:00",
 		   dev ? dev->name : "*");
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 2e78f6b..e527990 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -490,7 +490,6 @@
 	}
 
 	atomic_set(&doi_def->refcount, 1);
-	INIT_RCU_HEAD(&doi_def->rcu);
 
 	spin_lock(&cipso_v4_doi_list_lock);
 	if (cipso_v4_doi_search(doi_def->doi) != NULL)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 56fce3a..309997e 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -112,13 +112,7 @@
 
 static struct in_ifaddr *inet_alloc_ifa(void)
 {
-	struct in_ifaddr *ifa = kzalloc(sizeof(*ifa), GFP_KERNEL);
-
-	if (ifa) {
-		INIT_RCU_HEAD(&ifa->rcu_head);
-	}
-
-	return ifa;
+	return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL);
 }
 
 static void inet_rcu_free_ifa(struct rcu_head *head)
@@ -161,7 +155,6 @@
 	in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL);
 	if (!in_dev)
 		goto out;
-	INIT_RCU_HEAD(&in_dev->rcu_head);
 	memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
 			sizeof(in_dev->cnf));
 	in_dev->cnf.sysctl = NULL;
@@ -1108,7 +1101,7 @@
 }
 
 static struct notifier_block ip_netdev_notifier = {
-	.notifier_call =inetdev_event,
+	.notifier_call = inetdev_event,
 };
 
 static inline size_t inet_nlmsg_size(void)
@@ -1195,7 +1188,7 @@
 	return skb->len;
 }
 
-static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
+static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
 		      u32 pid)
 {
 	struct sk_buff *skb;
@@ -1262,7 +1255,7 @@
 }
 
 static int devinet_conf_proc(ctl_table *ctl, int write,
-			     struct file* filp, void __user *buffer,
+			     struct file *filp, void __user *buffer,
 			     size_t *lenp, loff_t *ppos)
 {
 	int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
@@ -1334,7 +1327,7 @@
 }
 
 static int devinet_sysctl_forward(ctl_table *ctl, int write,
-				  struct file* filp, void __user *buffer,
+				  struct file *filp, void __user *buffer,
 				  size_t *lenp, loff_t *ppos)
 {
 	int *valp = ctl->data;
@@ -1363,7 +1356,7 @@
 }
 
 int ipv4_doint_and_flush(ctl_table *ctl, int write,
-			 struct file* filp, void __user *buffer,
+			 struct file *filp, void __user *buffer,
 			 size_t *lenp, loff_t *ppos)
 {
 	int *valp = ctl->data;
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 21515d4..18bb383 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -413,15 +413,16 @@
 
 static void esp4_err(struct sk_buff *skb, u32 info)
 {
-	struct iphdr *iph = (struct iphdr*)skb->data;
-	struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2));
+	struct net *net = dev_net(skb->dev);
+	struct iphdr *iph = (struct iphdr *)skb->data;
+	struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2));
 	struct xfrm_state *x;
 
 	if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH ||
 	    icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
 		return;
 
-	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET);
+	x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET);
 	if (!x)
 		return;
 	NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n",
@@ -618,6 +619,7 @@
 	.handler	=	xfrm4_rcv,
 	.err_handler	=	esp4_err,
 	.no_policy	=	1,
+	.netns_ok	=	1,
 };
 
 static int __init esp4_init(void)
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 65c1503..741e4fa 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -578,7 +578,7 @@
 	return err;
 }
 
-static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct net *net = sock_net(skb->sk);
 	struct fib_config cfg;
@@ -600,7 +600,7 @@
 	return err;
 }
 
-static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct net *net = sock_net(skb->sk);
 	struct fib_config cfg;
@@ -903,7 +903,7 @@
 
 static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
-	struct in_ifaddr *ifa = (struct in_ifaddr*)ptr;
+	struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
 	struct net_device *dev = ifa->ifa_dev->dev;
 
 	switch (event) {
@@ -964,11 +964,11 @@
 }
 
 static struct notifier_block fib_inetaddr_notifier = {
-	.notifier_call =fib_inetaddr_event,
+	.notifier_call = fib_inetaddr_event,
 };
 
 static struct notifier_block fib_netdev_notifier = {
-	.notifier_call =fib_netdev_event,
+	.notifier_call = fib_netdev_event,
 };
 
 static int __net_init ip_fib_net_init(struct net *net)
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index c8cac6c..ded8c44 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -247,7 +247,7 @@
 {
 	int err;
 	struct fn_zone *fz;
-	struct fn_hash *t = (struct fn_hash*)tb->tb_data;
+	struct fn_hash *t = (struct fn_hash *)tb->tb_data;
 
 	read_lock(&fib_hash_lock);
 	for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
@@ -283,7 +283,7 @@
 	struct fib_node *f;
 	struct fib_info *fi = NULL;
 	struct fib_info *last_resort;
-	struct fn_hash *t = (struct fn_hash*)tb->tb_data;
+	struct fn_hash *t = (struct fn_hash *)tb->tb_data;
 	struct fn_zone *fz = t->fn_zones[0];
 
 	if (fz == NULL)
@@ -548,7 +548,7 @@
 
 static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg)
 {
-	struct fn_hash *table = (struct fn_hash*)tb->tb_data;
+	struct fn_hash *table = (struct fn_hash *)tb->tb_data;
 	struct fib_node *f;
 	struct fib_alias *fa, *fa_to_delete;
 	struct fn_zone *fz;
@@ -748,7 +748,7 @@
 {
 	int m, s_m;
 	struct fn_zone *fz;
-	struct fn_hash *table = (struct fn_hash*)tb->tb_data;
+	struct fn_hash *table = (struct fn_hash *)tb->tb_data;
 
 	s_m = cb->args[2];
 	read_lock(&fib_hash_lock);
@@ -845,10 +845,10 @@
 			struct hlist_node *node;
 			struct fib_node *fn;
 
-			hlist_for_each_entry(fn,node,iter->hash_head,fn_hash) {
+			hlist_for_each_entry(fn, node, iter->hash_head, fn_hash) {
 				struct fib_alias *fa;
 
-				list_for_each_entry(fa,&fn->fn_alias,fa_list) {
+				list_for_each_entry(fa, &fn->fn_alias, fa_list) {
 					iter->fn = fn;
 					iter->fa = fa;
 					goto out;
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index ded2ae3..4817dea 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -63,16 +63,16 @@
 for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
 
 #define change_nexthops(fi) { int nhsel; struct fib_nh * nh; \
-for (nhsel=0, nh = (struct fib_nh*)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)
+for (nhsel=0, nh = (struct fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)
 
 #else /* CONFIG_IP_ROUTE_MULTIPATH */
 
 /* Hope, that gcc will optimize it to get rid of dummy loop */
 
-#define for_nexthops(fi) { int nhsel=0; const struct fib_nh * nh = (fi)->fib_nh; \
+#define for_nexthops(fi) { int nhsel = 0; const struct fib_nh * nh = (fi)->fib_nh; \
 for (nhsel=0; nhsel < 1; nhsel++)
 
-#define change_nexthops(fi) { int nhsel=0; struct fib_nh * nh = (struct fib_nh*)((fi)->fib_nh); \
+#define change_nexthops(fi) { int nhsel = 0; struct fib_nh * nh = (struct fib_nh *)((fi)->fib_nh); \
 for (nhsel=0; nhsel < 1; nhsel++)
 
 #endif /* CONFIG_IP_ROUTE_MULTIPATH */
@@ -358,7 +358,7 @@
 		state = n->nud_state;
 		neigh_release(n);
 	}
-	if (state==NUD_REACHABLE)
+	if (state == NUD_REACHABLE)
 		return 0;
 	if ((state&NUD_VALID) && order != dflt)
 		return 0;
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 5cb7278..ec0ae49 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2399,8 +2399,8 @@
 		__be32 prf = htonl(mask_pfx(tn->key, tn->pos));
 
 		seq_indent(seq, iter->depth-1);
-		seq_printf(seq, "  +-- " NIPQUAD_FMT "/%d %d %d %d\n",
-			   NIPQUAD(prf), tn->pos, tn->bits, tn->full_children,
+		seq_printf(seq, "  +-- %pI4/%d %d %d %d\n",
+			   &prf, tn->pos, tn->bits, tn->full_children,
 			   tn->empty_children);
 
 	} else {
@@ -2410,7 +2410,7 @@
 		__be32 val = htonl(l->key);
 
 		seq_indent(seq, iter->depth);
-		seq_printf(seq, "  |-- " NIPQUAD_FMT "\n", NIPQUAD(val));
+		seq_printf(seq, "  |-- %pI4\n", &val);
 
 		hlist_for_each_entry_rcu(li, node, &l->list, hlist) {
 			struct fib_alias *fa;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 72b2de7..705b33b 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -321,12 +321,12 @@
 }
 
 static void icmp_push_reply(struct icmp_bxm *icmp_param,
-			    struct ipcm_cookie *ipc, struct rtable *rt)
+			    struct ipcm_cookie *ipc, struct rtable **rt)
 {
 	struct sock *sk;
 	struct sk_buff *skb;
 
-	sk = icmp_sk(dev_net(rt->u.dst.dev));
+	sk = icmp_sk(dev_net((*rt)->u.dst.dev));
 	if (ip_append_data(sk, icmp_glue_bits, icmp_param,
 			   icmp_param->data_len+icmp_param->head_len,
 			   icmp_param->head_len,
@@ -392,7 +392,7 @@
 	}
 	if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type,
 			       icmp_param->data.icmph.code))
-		icmp_push_reply(icmp_param, &ipc, rt);
+		icmp_push_reply(icmp_param, &ipc, &rt);
 	ip_rt_put(rt);
 out_unlock:
 	icmp_xmit_unlock(sk);
@@ -562,7 +562,7 @@
 		/* No need to clone since we're just using its address. */
 		rt2 = rt;
 
-		err = xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0);
+		err = xfrm_lookup(net, (struct dst_entry **)&rt, &fl, NULL, 0);
 		switch (err) {
 		case 0:
 			if (rt != rt2)
@@ -601,7 +601,7 @@
 		if (err)
 			goto relookup_failed;
 
-		err = xfrm_lookup((struct dst_entry **)&rt2, &fl, NULL,
+		err = xfrm_lookup(net, (struct dst_entry **)&rt2, &fl, NULL,
 				  XFRM_LOOKUP_ICMP);
 		switch (err) {
 		case 0:
@@ -635,7 +635,7 @@
 		icmp_param.data_len = room;
 	icmp_param.head_len = sizeof(struct icmphdr);
 
-	icmp_push_reply(&icmp_param, &ipc, rt);
+	icmp_push_reply(&icmp_param, &ipc, &rt);
 ende:
 	ip_rt_put(rt);
 out_unlock:
@@ -683,10 +683,8 @@
 			break;
 		case ICMP_FRAG_NEEDED:
 			if (ipv4_config.no_pmtu_disc) {
-				LIMIT_NETDEBUG(KERN_INFO "ICMP: " NIPQUAD_FMT ": "
-							 "fragmentation needed "
-							 "and DF set.\n",
-					       NIPQUAD(iph->daddr));
+				LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: fragmentation needed and DF set.\n",
+					       &iph->daddr);
 			} else {
 				info = ip_rt_frag_needed(net, iph,
 							 ntohs(icmph->un.frag.mtu),
@@ -696,9 +694,8 @@
 			}
 			break;
 		case ICMP_SR_FAILED:
-			LIMIT_NETDEBUG(KERN_INFO "ICMP: " NIPQUAD_FMT ": Source "
-						 "Route Failed.\n",
-				       NIPQUAD(iph->daddr));
+			LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: Source Route Failed.\n",
+				       &iph->daddr);
 			break;
 		default:
 			break;
@@ -729,12 +726,12 @@
 	if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
 	    inet_addr_type(net, iph->daddr) == RTN_BROADCAST) {
 		if (net_ratelimit())
-			printk(KERN_WARNING NIPQUAD_FMT " sent an invalid ICMP "
+			printk(KERN_WARNING "%pI4 sent an invalid ICMP "
 					    "type %u, code %u "
-					    "error to a broadcast: " NIPQUAD_FMT " on %s\n",
-			       NIPQUAD(ip_hdr(skb)->saddr),
+					    "error to a broadcast: %pI4 on %s\n",
+			       &ip_hdr(skb)->saddr,
 			       icmph->type, icmph->code,
-			       NIPQUAD(iph->daddr),
+			       &iph->daddr,
 			       skb->dev->name);
 		goto out;
 	}
@@ -952,9 +949,8 @@
 				break;
 		}
 		if (!ifa && net_ratelimit()) {
-			printk(KERN_INFO "Wrong address mask " NIPQUAD_FMT " from "
-					 "%s/" NIPQUAD_FMT "\n",
-			       NIPQUAD(*mp), dev->name, NIPQUAD(rt->rt_src));
+			printk(KERN_INFO "Wrong address mask %pI4 from %s/%pI4\n",
+			       mp, dev->name, &rt->rt_src);
 		}
 	}
 	rcu_read_unlock();
@@ -976,9 +972,10 @@
 	struct net *net = dev_net(rt->u.dst.dev);
 
 	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+		struct sec_path *sp = skb_sec_path(skb);
 		int nh;
 
-		if (!(skb->sp && skb->sp->xvec[skb->sp->len - 1]->props.flags &
+		if (!(sp && sp->xvec[sp->len - 1]->props.flags &
 				 XFRM_STATE_ICMP))
 			goto drop;
 
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index a0d8645..9eb6219 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -167,7 +167,7 @@
 	spin_lock_bh(&im->lock);
 	if (del_timer(&im->timer))
 		atomic_dec(&im->refcnt);
-	im->tm_running=0;
+	im->tm_running = 0;
 	im->reporter = 0;
 	im->unsolicit_count = 0;
 	spin_unlock_bh(&im->lock);
@@ -176,9 +176,9 @@
 /* It must be called with locked im->lock */
 static void igmp_start_timer(struct ip_mc_list *im, int max_delay)
 {
-	int tv=net_random() % max_delay;
+	int tv = net_random() % max_delay;
 
-	im->tm_running=1;
+	im->tm_running = 1;
 	if (!mod_timer(&im->timer, jiffies+tv+2))
 		atomic_inc(&im->refcnt);
 }
@@ -207,7 +207,7 @@
 	if (del_timer(&im->timer)) {
 		if ((long)(im->timer.expires-jiffies) < max_delay) {
 			add_timer(&im->timer);
-			im->tm_running=1;
+			im->tm_running = 1;
 			spin_unlock_bh(&im->lock);
 			return;
 		}
@@ -358,7 +358,7 @@
 
 static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel)
 {
-	return sizeof(struct igmpv3_grec) + 4*igmp_scount(pmc,type,gdel,sdel);
+	return sizeof(struct igmpv3_grec) + 4*igmp_scount(pmc, type, gdel, sdel);
 }
 
 static struct sk_buff *add_grhead(struct sk_buff *skb, struct ip_mc_list *pmc,
@@ -653,7 +653,7 @@
 		return -1;
 	}
 
-	skb=alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
+	skb = alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
 	if (skb == NULL) {
 		ip_rt_put(rt);
 		return -1;
@@ -682,11 +682,11 @@
 	((u8*)&iph[1])[3] = 0;
 
 	ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
-	ih->type=type;
-	ih->code=0;
-	ih->csum=0;
-	ih->group=group;
-	ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr));
+	ih->type = type;
+	ih->code = 0;
+	ih->csum = 0;
+	ih->group = group;
+	ih->csum = ip_compute_csum((void *)ih, sizeof(struct igmphdr));
 
 	return ip_local_out(skb);
 }
@@ -728,7 +728,7 @@
 	struct in_device *in_dev = im->interface;
 
 	spin_lock(&im->lock);
-	im->tm_running=0;
+	im->tm_running = 0;
 
 	if (im->unsolicit_count) {
 		im->unsolicit_count--;
@@ -997,7 +997,7 @@
 	   --ANK
 	   */
 	if (arp_mc_map(addr, buf, dev, 0) == 0)
-		dev_mc_add(dev,buf,dev->addr_len,0);
+		dev_mc_add(dev, buf, dev->addr_len, 0);
 }
 
 /*
@@ -1010,7 +1010,7 @@
 	struct net_device *dev = in_dev->dev;
 
 	if (arp_mc_map(addr, buf, dev, 0) == 0)
-		dev_mc_delete(dev,buf,dev->addr_len,0);
+		dev_mc_delete(dev, buf, dev->addr_len, 0);
 }
 
 #ifdef CONFIG_IP_MULTICAST
@@ -1210,10 +1210,10 @@
 	if (!im)
 		goto out;
 
-	im->users=1;
-	im->interface=in_dev;
+	im->users = 1;
+	im->interface = in_dev;
 	in_dev_hold(in_dev);
-	im->multiaddr=addr;
+	im->multiaddr = addr;
 	/* initial mode is (EX, empty) */
 	im->sfmode = MCAST_EXCLUDE;
 	im->sfcount[MCAST_INCLUDE] = 0;
@@ -1224,7 +1224,7 @@
 	atomic_set(&im->refcnt, 1);
 	spin_lock_init(&im->lock);
 #ifdef CONFIG_IP_MULTICAST
-	im->tm_running=0;
+	im->tm_running = 0;
 	setup_timer(&im->timer, &igmp_timer_expire, (unsigned long)im);
 	im->unsolicit_count = IGMP_Unsolicited_Report_Count;
 	im->reporter = 0;
@@ -1232,8 +1232,8 @@
 #endif
 	im->loaded = 0;
 	write_lock_bh(&in_dev->mc_list_lock);
-	im->next=in_dev->mc_list;
-	in_dev->mc_list=im;
+	im->next = in_dev->mc_list;
+	in_dev->mc_list = im;
 	in_dev->mc_count++;
 	write_unlock_bh(&in_dev->mc_list_lock);
 #ifdef CONFIG_IP_MULTICAST
@@ -1279,7 +1279,7 @@
 	ASSERT_RTNL();
 
 	for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) {
-		if (i->multiaddr==addr) {
+		if (i->multiaddr == addr) {
 			if (--i->users == 0) {
 				write_lock_bh(&in_dev->mc_list_lock);
 				*ip = i->next;
@@ -1738,7 +1738,7 @@
 {
 	int err;
 	__be32 addr = imr->imr_multiaddr.s_addr;
-	struct ip_mc_socklist *iml=NULL, *i;
+	struct ip_mc_socklist *iml = NULL, *i;
 	struct in_device *in_dev;
 	struct inet_sock *inet = inet_sk(sk);
 	struct net *net = sock_net(sk);
@@ -1769,7 +1769,7 @@
 	err = -ENOBUFS;
 	if (count >= sysctl_igmp_max_memberships)
 		goto done;
-	iml = sock_kmalloc(sk,sizeof(*iml),GFP_KERNEL);
+	iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
 	if (iml == NULL)
 		goto done;
 
@@ -2275,6 +2275,7 @@
 
 #if defined(CONFIG_PROC_FS)
 struct igmp_mc_iter_state {
+	struct seq_net_private p;
 	struct net_device *dev;
 	struct in_device *in_dev;
 };
@@ -2283,11 +2284,12 @@
 
 static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
 {
+	struct net *net = seq_file_net(seq);
 	struct ip_mc_list *im = NULL;
 	struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
 
 	state->in_dev = NULL;
-	for_each_netdev(&init_net, state->dev) {
+	for_each_netdev(net, state->dev) {
 		struct in_device *in_dev;
 		in_dev = in_dev_get(state->dev);
 		if (!in_dev)
@@ -2408,7 +2410,7 @@
 
 static int igmp_mc_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &igmp_mc_seq_ops,
+	return seq_open_net(inode, file, &igmp_mc_seq_ops,
 			sizeof(struct igmp_mc_iter_state));
 }
 
@@ -2417,10 +2419,11 @@
 	.open		=	igmp_mc_seq_open,
 	.read		=	seq_read,
 	.llseek		=	seq_lseek,
-	.release	=	seq_release_private,
+	.release	=	seq_release_net,
 };
 
 struct igmp_mcf_iter_state {
+	struct seq_net_private p;
 	struct net_device *dev;
 	struct in_device *idev;
 	struct ip_mc_list *im;
@@ -2430,13 +2433,14 @@
 
 static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
 {
+	struct net *net = seq_file_net(seq);
 	struct ip_sf_list *psf = NULL;
 	struct ip_mc_list *im = NULL;
 	struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq);
 
 	state->idev = NULL;
 	state->im = NULL;
-	for_each_netdev(&init_net, state->dev) {
+	for_each_netdev(net, state->dev) {
 		struct in_device *idev;
 		idev = in_dev_get(state->dev);
 		if (unlikely(idev == NULL))
@@ -2567,7 +2571,7 @@
 
 static int igmp_mcf_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &igmp_mcf_seq_ops,
+	return seq_open_net(inode, file, &igmp_mcf_seq_ops,
 			sizeof(struct igmp_mcf_iter_state));
 }
 
@@ -2576,14 +2580,41 @@
 	.open		=	igmp_mcf_seq_open,
 	.read		=	seq_read,
 	.llseek		=	seq_lseek,
-	.release	=	seq_release_private,
+	.release	=	seq_release_net,
+};
+
+static int igmp_net_init(struct net *net)
+{
+	struct proc_dir_entry *pde;
+
+	pde = proc_net_fops_create(net, "igmp", S_IRUGO, &igmp_mc_seq_fops);
+	if (!pde)
+		goto out_igmp;
+	pde = proc_net_fops_create(net, "mcfilter", S_IRUGO, &igmp_mcf_seq_fops);
+	if (!pde)
+		goto out_mcfilter;
+	return 0;
+
+out_mcfilter:
+	proc_net_remove(net, "igmp");
+out_igmp:
+	return -ENOMEM;
+}
+
+static void igmp_net_exit(struct net *net)
+{
+	proc_net_remove(net, "mcfilter");
+	proc_net_remove(net, "igmp");
+}
+
+static struct pernet_operations igmp_net_ops = {
+	.init = igmp_net_init,
+	.exit = igmp_net_exit,
 };
 
 int __init igmp_mc_proc_init(void)
 {
-	proc_net_fops_create(&init_net, "igmp", S_IRUGO, &igmp_mc_seq_fops);
-	proc_net_fops_create(&init_net, "mcfilter", S_IRUGO, &igmp_mcf_seq_fops);
-	return 0;
+	return register_pernet_subsys(&igmp_net_ops);
 }
 #endif
 
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index bd1278a..c7cda1c 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -109,7 +109,7 @@
 					hashinfo->bhash_size)];
 			spin_lock(&head->lock);
 			inet_bind_bucket_for_each(tb, node, &head->chain)
-				if (tb->ib_net == net && tb->port == rover)
+				if (ib_net(tb) == net && tb->port == rover)
 					goto next;
 			break;
 		next:
@@ -137,7 +137,7 @@
 				hashinfo->bhash_size)];
 		spin_lock(&head->lock);
 		inet_bind_bucket_for_each(tb, node, &head->chain)
-			if (tb->ib_net == net && tb->port == snum)
+			if (ib_net(tb) == net && tb->port == snum)
 				goto tb_found;
 	}
 	tb = NULL;
@@ -323,7 +323,7 @@
 
 EXPORT_SYMBOL(inet_csk_reset_keepalive_timer);
 
-struct dst_entry* inet_csk_route_req(struct sock *sk,
+struct dst_entry *inet_csk_route_req(struct sock *sk,
 				     const struct request_sock *req)
 {
 	struct rtable *rt;
@@ -344,16 +344,17 @@
 	struct net *net = sock_net(sk);
 
 	security_req_classify_flow(req, &fl);
-	if (ip_route_output_flow(net, &rt, &fl, sk, 0)) {
-		IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
-		return NULL;
-	}
-	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) {
-		ip_rt_put(rt);
-		IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
-		return NULL;
-	}
+	if (ip_route_output_flow(net, &rt, &fl, sk, 0))
+		goto no_route;
+	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
+		goto route_err;
 	return &rt->u.dst;
+
+route_err:
+	ip_rt_put(rt);
+no_route:
+	IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
+	return NULL;
 }
 
 EXPORT_SYMBOL_GPL(inet_csk_route_req);
@@ -561,7 +562,7 @@
 
 	sk_refcnt_debug_release(sk);
 
-	atomic_dec(sk->sk_prot->orphan_count);
+	percpu_counter_dec(sk->sk_prot->orphan_count);
 	sock_put(sk);
 }
 
@@ -632,6 +633,8 @@
 
 		acc_req = req->dl_next;
 
+		percpu_counter_inc(sk->sk_prot->orphan_count);
+
 		local_bh_disable();
 		bh_lock_sock(child);
 		WARN_ON(sock_owned_by_user(child));
@@ -641,8 +644,6 @@
 
 		sock_orphan(child);
 
-		atomic_inc(sk->sk_prot->orphan_count);
-
 		inet_csk_destroy_sock(child);
 
 		bh_unlock_sock(child);
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 564230d..588a779 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -718,13 +718,15 @@
 		if (!(r->idiag_states & (TCPF_LISTEN | TCPF_SYN_RECV)))
 			goto skip_listen_ht;
 
-		inet_listen_lock(hashinfo);
 		for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
 			struct sock *sk;
-			struct hlist_node *node;
+			struct hlist_nulls_node *node;
+			struct inet_listen_hashbucket *ilb;
 
 			num = 0;
-			sk_for_each(sk, node, &hashinfo->listening_hash[i]) {
+			ilb = &hashinfo->listening_hash[i];
+			spin_lock_bh(&ilb->lock);
+			sk_nulls_for_each(sk, node, &ilb->head) {
 				struct inet_sock *inet = inet_sk(sk);
 
 				if (num < s_num) {
@@ -742,7 +744,7 @@
 					goto syn_recv;
 
 				if (inet_csk_diag_dump(sk, skb, cb) < 0) {
-					inet_listen_unlock(hashinfo);
+					spin_unlock_bh(&ilb->lock);
 					goto done;
 				}
 
@@ -751,7 +753,7 @@
 					goto next_listen;
 
 				if (inet_diag_dump_reqs(skb, sk, cb) < 0) {
-					inet_listen_unlock(hashinfo);
+					spin_unlock_bh(&ilb->lock);
 					goto done;
 				}
 
@@ -760,12 +762,12 @@
 				cb->args[4] = 0;
 				++num;
 			}
+			spin_unlock_bh(&ilb->lock);
 
 			s_num = 0;
 			cb->args[3] = 0;
 			cb->args[4] = 0;
 		}
-		inet_listen_unlock(hashinfo);
 skip_listen_ht:
 		cb->args[0] = 1;
 		s_i = num = s_num = 0;
@@ -776,20 +778,21 @@
 
 	for (i = s_i; i < hashinfo->ehash_size; i++) {
 		struct inet_ehash_bucket *head = &hashinfo->ehash[i];
-		rwlock_t *lock = inet_ehash_lockp(hashinfo, i);
+		spinlock_t *lock = inet_ehash_lockp(hashinfo, i);
 		struct sock *sk;
-		struct hlist_node *node;
+		struct hlist_nulls_node *node;
 
 		num = 0;
 
-		if (hlist_empty(&head->chain) && hlist_empty(&head->twchain))
+		if (hlist_nulls_empty(&head->chain) &&
+			hlist_nulls_empty(&head->twchain))
 			continue;
 
 		if (i > s_i)
 			s_num = 0;
 
-		read_lock_bh(lock);
-		sk_for_each(sk, node, &head->chain) {
+		spin_lock_bh(lock);
+		sk_nulls_for_each(sk, node, &head->chain) {
 			struct inet_sock *inet = inet_sk(sk);
 
 			if (num < s_num)
@@ -803,7 +806,7 @@
 			    r->id.idiag_dport)
 				goto next_normal;
 			if (inet_csk_diag_dump(sk, skb, cb) < 0) {
-				read_unlock_bh(lock);
+				spin_unlock_bh(lock);
 				goto done;
 			}
 next_normal:
@@ -825,14 +828,14 @@
 				    r->id.idiag_dport)
 					goto next_dying;
 				if (inet_twsk_diag_dump(tw, skb, cb) < 0) {
-					read_unlock_bh(lock);
+					spin_unlock_bh(lock);
 					goto done;
 				}
 next_dying:
 				++num;
 			}
 		}
-		read_unlock_bh(lock);
+		spin_unlock_bh(lock);
 	}
 
 done:
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 4498190..6a1045d 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -35,7 +35,7 @@
 	struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, GFP_ATOMIC);
 
 	if (tb != NULL) {
-		tb->ib_net       = hold_net(net);
+		write_pnet(&tb->ib_net, hold_net(net));
 		tb->port      = snum;
 		tb->fastreuse = 0;
 		INIT_HLIST_HEAD(&tb->owners);
@@ -51,7 +51,7 @@
 {
 	if (hlist_empty(&tb->owners)) {
 		__hlist_del(&tb->node);
-		release_net(tb->ib_net);
+		release_net(ib_net(tb));
 		kmem_cache_free(cachep, tb);
 	}
 }
@@ -110,33 +110,29 @@
 
 EXPORT_SYMBOL_GPL(__inet_inherit_port);
 
-/*
- * This lock without WQ_FLAG_EXCLUSIVE is good on UP and it can be very bad on SMP.
- * Look, when several writers sleep and reader wakes them up, all but one
- * immediately hit write lock and grab all the cpus. Exclusive sleep solves
- * this, _but_ remember, it adds useless work on UP machines (wake up each
- * exclusive lock release). It should be ifdefed really.
- */
-void inet_listen_wlock(struct inet_hashinfo *hashinfo)
-	__acquires(hashinfo->lhash_lock)
+static inline int compute_score(struct sock *sk, struct net *net,
+				const unsigned short hnum, const __be32 daddr,
+				const int dif)
 {
-	write_lock(&hashinfo->lhash_lock);
+	int score = -1;
+	struct inet_sock *inet = inet_sk(sk);
 
-	if (atomic_read(&hashinfo->lhash_users)) {
-		DEFINE_WAIT(wait);
-
-		for (;;) {
-			prepare_to_wait_exclusive(&hashinfo->lhash_wait,
-						  &wait, TASK_UNINTERRUPTIBLE);
-			if (!atomic_read(&hashinfo->lhash_users))
-				break;
-			write_unlock_bh(&hashinfo->lhash_lock);
-			schedule();
-			write_lock_bh(&hashinfo->lhash_lock);
+	if (net_eq(sock_net(sk), net) && inet->num == hnum &&
+			!ipv6_only_sock(sk)) {
+		__be32 rcv_saddr = inet->rcv_saddr;
+		score = sk->sk_family == PF_INET ? 1 : 0;
+		if (rcv_saddr) {
+			if (rcv_saddr != daddr)
+				return -1;
+			score += 2;
 		}
-
-		finish_wait(&hashinfo->lhash_wait, &wait);
+		if (sk->sk_bound_dev_if) {
+			if (sk->sk_bound_dev_if != dif)
+				return -1;
+			score += 2;
+		}
 	}
+	return score;
 }
 
 /*
@@ -145,72 +141,48 @@
  * remote address for the connection. So always assume those are both
  * wildcarded during the search since they can never be otherwise.
  */
-static struct sock *inet_lookup_listener_slow(struct net *net,
-					      const struct hlist_head *head,
-					      const __be32 daddr,
-					      const unsigned short hnum,
-					      const int dif)
-{
-	struct sock *result = NULL, *sk;
-	const struct hlist_node *node;
-	int hiscore = -1;
 
-	sk_for_each(sk, node, head) {
-		const struct inet_sock *inet = inet_sk(sk);
 
-		if (net_eq(sock_net(sk), net) && inet->num == hnum &&
-				!ipv6_only_sock(sk)) {
-			const __be32 rcv_saddr = inet->rcv_saddr;
-			int score = sk->sk_family == PF_INET ? 1 : 0;
-
-			if (rcv_saddr) {
-				if (rcv_saddr != daddr)
-					continue;
-				score += 2;
-			}
-			if (sk->sk_bound_dev_if) {
-				if (sk->sk_bound_dev_if != dif)
-					continue;
-				score += 2;
-			}
-			if (score == 5)
-				return sk;
-			if (score > hiscore) {
-				hiscore	= score;
-				result	= sk;
-			}
-		}
-	}
-	return result;
-}
-
-/* Optimize the common listener case. */
 struct sock *__inet_lookup_listener(struct net *net,
 				    struct inet_hashinfo *hashinfo,
 				    const __be32 daddr, const unsigned short hnum,
 				    const int dif)
 {
-	struct sock *sk = NULL;
-	const struct hlist_head *head;
+	struct sock *sk, *result;
+	struct hlist_nulls_node *node;
+	unsigned int hash = inet_lhashfn(net, hnum);
+	struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
+	int score, hiscore;
 
-	read_lock(&hashinfo->lhash_lock);
-	head = &hashinfo->listening_hash[inet_lhashfn(net, hnum)];
-	if (!hlist_empty(head)) {
-		const struct inet_sock *inet = inet_sk((sk = __sk_head(head)));
-
-		if (inet->num == hnum && !sk->sk_node.next &&
-		    (!inet->rcv_saddr || inet->rcv_saddr == daddr) &&
-		    (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) &&
-		    !sk->sk_bound_dev_if && net_eq(sock_net(sk), net))
-			goto sherry_cache;
-		sk = inet_lookup_listener_slow(net, head, daddr, hnum, dif);
+	rcu_read_lock();
+begin:
+	result = NULL;
+	hiscore = -1;
+	sk_nulls_for_each_rcu(sk, node, &ilb->head) {
+		score = compute_score(sk, net, hnum, daddr, dif);
+		if (score > hiscore) {
+			result = sk;
+			hiscore = score;
+		}
 	}
-	if (sk) {
-sherry_cache:
-		sock_hold(sk);
+	/*
+	 * if the nulls value we got at the end of this lookup is
+	 * not the expected one, we must restart lookup.
+	 * We probably met an item that was moved to another chain.
+	 */
+	if (get_nulls_value(node) != hash + LISTENING_NULLS_BASE)
+		goto begin;
+	if (result) {
+		if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt)))
+			result = NULL;
+		else if (unlikely(compute_score(result, net, hnum, daddr,
+				  dif) < hiscore)) {
+			sock_put(result);
+			goto begin;
+		}
 	}
-	read_unlock(&hashinfo->lhash_lock);
-	return sk;
+	rcu_read_unlock();
+	return result;
 }
 EXPORT_SYMBOL_GPL(__inet_lookup_listener);
 
@@ -223,35 +195,65 @@
 	INET_ADDR_COOKIE(acookie, saddr, daddr)
 	const __portpair ports = INET_COMBINED_PORTS(sport, hnum);
 	struct sock *sk;
-	const struct hlist_node *node;
+	const struct hlist_nulls_node *node;
 	/* Optimize here for direct hit, only listening connections can
 	 * have wildcards anyways.
 	 */
 	unsigned int hash = inet_ehashfn(net, daddr, hnum, saddr, sport);
-	struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash);
-	rwlock_t *lock = inet_ehash_lockp(hashinfo, hash);
+	unsigned int slot = hash & (hashinfo->ehash_size - 1);
+	struct inet_ehash_bucket *head = &hashinfo->ehash[slot];
 
-	prefetch(head->chain.first);
-	read_lock(lock);
-	sk_for_each(sk, node, &head->chain) {
+	rcu_read_lock();
+begin:
+	sk_nulls_for_each_rcu(sk, node, &head->chain) {
 		if (INET_MATCH(sk, net, hash, acookie,
-					saddr, daddr, ports, dif))
-			goto hit; /* You sunk my battleship! */
+					saddr, daddr, ports, dif)) {
+			if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt)))
+				goto begintw;
+			if (unlikely(!INET_MATCH(sk, net, hash, acookie,
+				saddr, daddr, ports, dif))) {
+				sock_put(sk);
+				goto begin;
+			}
+			goto out;
+		}
 	}
+	/*
+	 * if the nulls value we got at the end of this lookup is
+	 * not the expected one, we must restart lookup.
+	 * We probably met an item that was moved to another chain.
+	 */
+	if (get_nulls_value(node) != slot)
+		goto begin;
 
+begintw:
 	/* Must check for a TIME_WAIT'er before going to listener hash. */
-	sk_for_each(sk, node, &head->twchain) {
+	sk_nulls_for_each_rcu(sk, node, &head->twchain) {
 		if (INET_TW_MATCH(sk, net, hash, acookie,
-					saddr, daddr, ports, dif))
-			goto hit;
+					saddr, daddr, ports, dif)) {
+			if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) {
+				sk = NULL;
+				goto out;
+			}
+			if (unlikely(!INET_TW_MATCH(sk, net, hash, acookie,
+				 saddr, daddr, ports, dif))) {
+				sock_put(sk);
+				goto begintw;
+			}
+			goto out;
+		}
 	}
+	/*
+	 * if the nulls value we got at the end of this lookup is
+	 * not the expected one, we must restart lookup.
+	 * We probably met an item that was moved to another chain.
+	 */
+	if (get_nulls_value(node) != slot)
+		goto begintw;
 	sk = NULL;
 out:
-	read_unlock(lock);
+	rcu_read_unlock();
 	return sk;
-hit:
-	sock_hold(sk);
-	goto out;
 }
 EXPORT_SYMBOL_GPL(__inet_lookup_established);
 
@@ -270,16 +272,15 @@
 	struct net *net = sock_net(sk);
 	unsigned int hash = inet_ehashfn(net, daddr, lport, saddr, inet->dport);
 	struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
-	rwlock_t *lock = inet_ehash_lockp(hinfo, hash);
+	spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
 	struct sock *sk2;
-	const struct hlist_node *node;
+	const struct hlist_nulls_node *node;
 	struct inet_timewait_sock *tw;
 
-	prefetch(head->chain.first);
-	write_lock(lock);
+	spin_lock(lock);
 
 	/* Check TIME-WAIT sockets first. */
-	sk_for_each(sk2, node, &head->twchain) {
+	sk_nulls_for_each(sk2, node, &head->twchain) {
 		tw = inet_twsk(sk2);
 
 		if (INET_TW_MATCH(sk2, net, hash, acookie,
@@ -293,7 +294,7 @@
 	tw = NULL;
 
 	/* And established part... */
-	sk_for_each(sk2, node, &head->chain) {
+	sk_nulls_for_each(sk2, node, &head->chain) {
 		if (INET_MATCH(sk2, net, hash, acookie,
 					saddr, daddr, ports, dif))
 			goto not_unique;
@@ -306,9 +307,9 @@
 	inet->sport = htons(lport);
 	sk->sk_hash = hash;
 	WARN_ON(!sk_unhashed(sk));
-	__sk_add_node(sk, &head->chain);
+	__sk_nulls_add_node_rcu(sk, &head->chain);
+	spin_unlock(lock);
 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
-	write_unlock(lock);
 
 	if (twp) {
 		*twp = tw;
@@ -324,7 +325,7 @@
 	return 0;
 
 not_unique:
-	write_unlock(lock);
+	spin_unlock(lock);
 	return -EADDRNOTAVAIL;
 }
 
@@ -338,8 +339,8 @@
 void __inet_hash_nolisten(struct sock *sk)
 {
 	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
-	struct hlist_head *list;
-	rwlock_t *lock;
+	struct hlist_nulls_head *list;
+	spinlock_t *lock;
 	struct inet_ehash_bucket *head;
 
 	WARN_ON(!sk_unhashed(sk));
@@ -349,18 +350,17 @@
 	list = &head->chain;
 	lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
 
-	write_lock(lock);
-	__sk_add_node(sk, list);
+	spin_lock(lock);
+	__sk_nulls_add_node_rcu(sk, list);
+	spin_unlock(lock);
 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
-	write_unlock(lock);
 }
 EXPORT_SYMBOL_GPL(__inet_hash_nolisten);
 
 static void __inet_hash(struct sock *sk)
 {
 	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
-	struct hlist_head *list;
-	rwlock_t *lock;
+	struct inet_listen_hashbucket *ilb;
 
 	if (sk->sk_state != TCP_LISTEN) {
 		__inet_hash_nolisten(sk);
@@ -368,14 +368,12 @@
 	}
 
 	WARN_ON(!sk_unhashed(sk));
-	list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
-	lock = &hashinfo->lhash_lock;
+	ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
 
-	inet_listen_wlock(hashinfo);
-	__sk_add_node(sk, list);
+	spin_lock(&ilb->lock);
+	__sk_nulls_add_node_rcu(sk, &ilb->head);
 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
-	write_unlock(lock);
-	wake_up(&hashinfo->lhash_wait);
+	spin_unlock(&ilb->lock);
 }
 
 void inet_hash(struct sock *sk)
@@ -390,27 +388,23 @@
 
 void inet_unhash(struct sock *sk)
 {
-	rwlock_t *lock;
 	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
+	spinlock_t *lock;
+	int done;
 
 	if (sk_unhashed(sk))
-		goto out;
+		return;
 
-	if (sk->sk_state == TCP_LISTEN) {
-		local_bh_disable();
-		inet_listen_wlock(hashinfo);
-		lock = &hashinfo->lhash_lock;
-	} else {
-		lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
-		write_lock_bh(lock);
-	}
-
-	if (__sk_del_node_init(sk))
-		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
-	write_unlock_bh(lock);
-out:
 	if (sk->sk_state == TCP_LISTEN)
-		wake_up(&hashinfo->lhash_wait);
+		lock = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)].lock;
+	else
+		lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
+
+	spin_lock_bh(lock);
+	done =__sk_nulls_del_node_init_rcu(sk);
+	if (done)
+		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+	spin_unlock_bh(lock);
 }
 EXPORT_SYMBOL_GPL(inet_unhash);
 
@@ -449,7 +443,7 @@
 			 * unique enough.
 			 */
 			inet_bind_bucket_for_each(tb, node, &head->chain) {
-				if (tb->ib_net == net && tb->port == port) {
+				if (ib_net(tb) == net && tb->port == port) {
 					WARN_ON(hlist_empty(&tb->owners));
 					if (tb->fastreuse >= 0)
 						goto next_port;
@@ -524,3 +518,16 @@
 }
 
 EXPORT_SYMBOL_GPL(inet_hash_connect);
+
+void inet_hashinfo_init(struct inet_hashinfo *h)
+{
+	int i;
+
+	for (i = 0; i < INET_LHTABLE_SIZE; i++) {
+		spin_lock_init(&h->listening_hash[i].lock);
+		INIT_HLIST_NULLS_HEAD(&h->listening_hash[i].head,
+				      i + LISTENING_NULLS_BASE);
+		}
+}
+
+EXPORT_SYMBOL_GPL(inet_hashinfo_init);
diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c
index cfd034a..6a667da 100644
--- a/net/ipv4/inet_lro.c
+++ b/net/ipv4/inet_lro.c
@@ -120,7 +120,7 @@
 	iph->check = ip_fast_csum((u8 *)lro_desc->iph, iph->ihl);
 
 	tcph->check = 0;
-	tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), 0);
+	tcp_hdr_csum = csum_partial(tcph, TCP_HDR_LEN(tcph), 0);
 	lro_desc->data_csum = csum_add(lro_desc->data_csum, tcp_hdr_csum);
 	tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
 					lro_desc->ip_tot_len -
@@ -135,7 +135,7 @@
 	__wsum tcp_ps_hdr_csum;
 
 	tcp_csum = ~csum_unfold(tcph->check);
-	tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), tcp_csum);
+	tcp_hdr_csum = csum_partial(tcph, TCP_HDR_LEN(tcph), tcp_csum);
 
 	tcp_ps_hdr_csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
 					     len + TCP_HDR_LEN(tcph),
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index 1c5fd38..8554d0e 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -20,16 +20,16 @@
 	struct inet_bind_hashbucket *bhead;
 	struct inet_bind_bucket *tb;
 	/* Unlink from established hashes. */
-	rwlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash);
+	spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash);
 
-	write_lock(lock);
-	if (hlist_unhashed(&tw->tw_node)) {
-		write_unlock(lock);
+	spin_lock(lock);
+	if (hlist_nulls_unhashed(&tw->tw_node)) {
+		spin_unlock(lock);
 		return;
 	}
-	__hlist_del(&tw->tw_node);
-	sk_node_init(&tw->tw_node);
-	write_unlock(lock);
+	hlist_nulls_del_rcu(&tw->tw_node);
+	sk_nulls_node_init(&tw->tw_node);
+	spin_unlock(lock);
 
 	/* Disassociate with bind bucket. */
 	bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), tw->tw_num,
@@ -76,7 +76,7 @@
 	const struct inet_sock *inet = inet_sk(sk);
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 	struct inet_ehash_bucket *ehead = inet_ehash_bucket(hashinfo, sk->sk_hash);
-	rwlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
+	spinlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
 	struct inet_bind_hashbucket *bhead;
 	/* Step 1: Put TW into bind hash. Original socket stays there too.
 	   Note, that any socket with inet->num != 0 MUST be bound in
@@ -90,17 +90,21 @@
 	inet_twsk_add_bind_node(tw, &tw->tw_tb->owners);
 	spin_unlock(&bhead->lock);
 
-	write_lock(lock);
+	spin_lock(lock);
 
-	/* Step 2: Remove SK from established hash. */
-	if (__sk_del_node_init(sk))
+	/*
+	 * Step 2: Hash TW into TIMEWAIT chain.
+	 * Should be done before removing sk from established chain
+	 * because readers are lockless and search established first.
+	 */
+	atomic_inc(&tw->tw_refcnt);
+	inet_twsk_add_node_rcu(tw, &ehead->twchain);
+
+	/* Step 3: Remove SK from established hash. */
+	if (__sk_nulls_del_node_init_rcu(sk))
 		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
 
-	/* Step 3: Hash TW into TIMEWAIT chain. */
-	inet_twsk_add_node(tw, &ehead->twchain);
-	atomic_inc(&tw->tw_refcnt);
-
-	write_unlock(lock);
+	spin_unlock(lock);
 }
 
 EXPORT_SYMBOL_GPL(__inet_twsk_hashdance);
@@ -416,17 +420,17 @@
 {
 	struct inet_timewait_sock *tw;
 	struct sock *sk;
-	struct hlist_node *node;
+	struct hlist_nulls_node *node;
 	int h;
 
 	local_bh_disable();
 	for (h = 0; h < (hashinfo->ehash_size); h++) {
 		struct inet_ehash_bucket *head =
 			inet_ehash_bucket(hashinfo, h);
-		rwlock_t *lock = inet_ehash_lockp(hashinfo, h);
+		spinlock_t *lock = inet_ehash_lockp(hashinfo, h);
 restart:
-		write_lock(lock);
-		sk_for_each(sk, node, &head->twchain) {
+		spin_lock(lock);
+		sk_nulls_for_each(sk, node, &head->twchain) {
 
 			tw = inet_twsk(sk);
 			if (!net_eq(twsk_net(tw), net) ||
@@ -434,13 +438,13 @@
 				continue;
 
 			atomic_inc(&tw->tw_refcnt);
-			write_unlock(lock);
+			spin_unlock(lock);
 			inet_twsk_deschedule(tw, twdr);
 			inet_twsk_put(tw);
 
 			goto restart;
 		}
-		write_unlock(lock);
+		spin_unlock(lock);
 	}
 	local_bh_enable();
 }
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index a456cee..b1fbe18 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -144,7 +144,7 @@
  * _stack is known to be NULL or not at compile time,
  * so compiler will optimize the if (_stack) tests.
  */
-#define lookup(_daddr,_stack) 					\
+#define lookup(_daddr, _stack) 					\
 ({								\
 	struct inet_peer *u, **v;				\
 	if (_stack != NULL) {					\
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 450016b..df3fe50 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -106,7 +106,7 @@
 	 *	We now generate an ICMP HOST REDIRECT giving the route
 	 *	we calculated.
 	 */
-	if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb->sp)
+	if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb_sec_path(skb))
 		ip_rt_send_redirect(skb);
 
 	skb->priority = rt_tos2priority(iph->tos);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index e4f81f5..6659ac0 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -56,7 +56,7 @@
 	int			offset;
 };
 
-#define FRAG_CB(skb)	((struct ipfrag_skb_cb*)((skb)->cb))
+#define FRAG_CB(skb)	((struct ipfrag_skb_cb *)((skb)->cb))
 
 /* Describe an entry in the "incomplete datagrams" queue. */
 struct ipq {
@@ -559,9 +559,8 @@
 	goto out_fail;
 out_oversize:
 	if (net_ratelimit())
-		printk(KERN_INFO
-			"Oversized IP packet from " NIPQUAD_FMT ".\n",
-			NIPQUAD(qp->saddr));
+		printk(KERN_INFO "Oversized IP packet from %pI4.\n",
+			&qp->saddr);
 out_fail:
 	IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_REASMFAILS);
 	return err;
@@ -608,7 +607,7 @@
 		.data		= &init_net.ipv4.frags.high_thresh,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_IPFRAG_LOW_THRESH,
@@ -616,7 +615,7 @@
 		.data		= &init_net.ipv4.frags.low_thresh,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_IPFRAG_TIME,
@@ -624,8 +623,8 @@
 		.data		= &init_net.ipv4.frags.timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies
 	},
 	{ }
 };
@@ -637,15 +636,15 @@
 		.data		= &ip4_frags.secret_interval,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies
 	},
 	{
 		.procname	= "ipfrag_max_dist",
 		.data		= &sysctl_ipfrag_max_dist,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
+		.proc_handler	= proc_dointvec_minmax,
 		.extra1		= &zero
 	},
 	{ }
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 85c487b..0101521 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -126,8 +126,6 @@
 
 /* Fallback tunnel: no source, no destination, no key, no options */
 
-static int ipgre_fb_tunnel_init(struct net_device *dev);
-
 #define HASH_SIZE  16
 
 static int ipgre_net_id;
@@ -371,7 +369,7 @@
    by themself???
  */
 
-	struct iphdr *iph = (struct iphdr*)skb->data;
+	struct iphdr *iph = (struct iphdr *)skb->data;
 	__be16	     *p = (__be16*)(skb->data+(iph->ihl<<2));
 	int grehlen = (iph->ihl<<2) + 4;
 	const int type = icmp_hdr(skb)->type;
@@ -632,7 +630,7 @@
 
 	if (dev->header_ops && dev->type == ARPHRD_IPGRE) {
 		gre_hlen = 0;
-		tiph = (struct iphdr*)skb->data;
+		tiph = (struct iphdr *)skb->data;
 	} else {
 		gre_hlen = tunnel->hlen;
 		tiph = &tunnel->parms.iph;
@@ -660,7 +658,7 @@
 			if (neigh == NULL)
 				goto tx_error;
 
-			addr6 = (struct in6_addr*)&neigh->primary_key;
+			addr6 = (struct in6_addr *)&neigh->primary_key;
 			addr_type = ipv6_addr_type(addr6);
 
 			if (addr_type == IPV6_ADDR_ANY) {
@@ -726,7 +724,7 @@
 	}
 #ifdef CONFIG_IPV6
 	else if (skb->protocol == htons(ETH_P_IPV6)) {
-		struct rt6_info *rt6 = (struct rt6_info*)skb->dst;
+		struct rt6_info *rt6 = (struct rt6_info *)skb->dst;
 
 		if (rt6 && mtu < dst_mtu(skb->dst) && mtu >= IPV6_MIN_MTU) {
 			if ((tunnel->parms.iph.daddr &&
@@ -800,7 +798,7 @@
 			iph->ttl = old_iph->ttl;
 #ifdef CONFIG_IPV6
 		else if (skb->protocol == htons(ETH_P_IPV6))
-			iph->ttl = ((struct ipv6hdr*)old_iph)->hop_limit;
+			iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit;
 #endif
 		else
 			iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
@@ -962,7 +960,7 @@
 					break;
 				}
 			} else {
-				unsigned nflags=0;
+				unsigned nflags = 0;
 
 				t = netdev_priv(dev);
 
@@ -1104,7 +1102,7 @@
 
 static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
-	struct iphdr *iph = (struct iphdr*) skb_mac_header(skb);
+	struct iphdr *iph = (struct iphdr *) skb_mac_header(skb);
 	memcpy(haddr, &iph->saddr, 4);
 	return 4;
 }
@@ -1142,6 +1140,7 @@
 static int ipgre_close(struct net_device *dev)
 {
 	struct ip_tunnel *t = netdev_priv(dev);
+
 	if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
 		struct in_device *in_dev;
 		in_dev = inetdev_by_index(dev_net(dev), t->mlink);
@@ -1155,14 +1154,22 @@
 
 #endif
 
+static const struct net_device_ops ipgre_netdev_ops = {
+	.ndo_init		= ipgre_tunnel_init,
+	.ndo_uninit		= ipgre_tunnel_uninit,
+#ifdef CONFIG_NET_IPGRE_BROADCAST
+	.ndo_open		= ipgre_open,
+	.ndo_stop		= ipgre_close,
+#endif
+	.ndo_start_xmit		= ipgre_tunnel_xmit,
+	.ndo_do_ioctl		= ipgre_tunnel_ioctl,
+	.ndo_change_mtu		= ipgre_tunnel_change_mtu,
+};
+
 static void ipgre_tunnel_setup(struct net_device *dev)
 {
-	dev->init		= ipgre_tunnel_init;
-	dev->uninit		= ipgre_tunnel_uninit;
+	dev->netdev_ops		= &ipgre_netdev_ops;
 	dev->destructor 	= free_netdev;
-	dev->hard_start_xmit	= ipgre_tunnel_xmit;
-	dev->do_ioctl		= ipgre_tunnel_ioctl;
-	dev->change_mtu		= ipgre_tunnel_change_mtu;
 
 	dev->type		= ARPHRD_IPGRE;
 	dev->needed_headroom 	= LL_MAX_HEADER + sizeof(struct iphdr) + 4;
@@ -1194,8 +1201,6 @@
 				return -EINVAL;
 			dev->flags = IFF_BROADCAST;
 			dev->header_ops = &ipgre_header_ops;
-			dev->open = ipgre_open;
-			dev->stop = ipgre_close;
 		}
 #endif
 	} else
@@ -1204,7 +1209,7 @@
 	return 0;
 }
 
-static int ipgre_fb_tunnel_init(struct net_device *dev)
+static void ipgre_fb_tunnel_init(struct net_device *dev)
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
 	struct iphdr *iph = &tunnel->parms.iph;
@@ -1220,7 +1225,6 @@
 
 	dev_hold(dev);
 	ign->tunnels_wc[0]	= tunnel;
-	return 0;
 }
 
 
@@ -1264,9 +1268,9 @@
 		err = -ENOMEM;
 		goto err_alloc_dev;
 	}
-
-	ign->fb_tunnel_dev->init = ipgre_fb_tunnel_init;
 	dev_net_set(ign->fb_tunnel_dev, net);
+
+	ipgre_fb_tunnel_init(ign->fb_tunnel_dev);
 	ign->fb_tunnel_dev->rtnl_link_ops = &ipgre_link_ops;
 
 	if ((err = register_netdev(ign->fb_tunnel_dev)))
@@ -1397,16 +1401,22 @@
 	return 0;
 }
 
+static const struct net_device_ops ipgre_tap_netdev_ops = {
+	.ndo_init		= ipgre_tap_init,
+	.ndo_uninit		= ipgre_tunnel_uninit,
+	.ndo_start_xmit		= ipgre_tunnel_xmit,
+	.ndo_set_mac_address 	= eth_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= ipgre_tunnel_change_mtu,
+};
+
 static void ipgre_tap_setup(struct net_device *dev)
 {
 
 	ether_setup(dev);
 
-	dev->init		= ipgre_tap_init;
-	dev->uninit		= ipgre_tunnel_uninit;
+	dev->netdev_ops		= &ipgre_netdev_ops;
 	dev->destructor 	= free_netdev;
-	dev->hard_start_xmit	= ipgre_tunnel_xmit;
-	dev->change_mtu		= ipgre_tunnel_change_mtu;
 
 	dev->iflink		= 0;
 	dev->features		|= NETIF_F_NETNS_LOCAL;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index cfb38ac..1a58a6f 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -302,10 +302,8 @@
 			if (!IN_DEV_SOURCE_ROUTE(in_dev)) {
 				if (IN_DEV_LOG_MARTIANS(in_dev) &&
 				    net_ratelimit())
-					printk(KERN_INFO "source route option "
-					       NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
-					       NIPQUAD(iph->saddr),
-					       NIPQUAD(iph->daddr));
+					printk(KERN_INFO "source route option %pI4 -> %pI4\n",
+					       &iph->saddr, &iph->daddr);
 				in_dev_put(in_dev);
 				goto drop;
 			}
@@ -350,9 +348,9 @@
 		struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id());
 		u32 idx = skb->dst->tclassid;
 		st[idx&0xFF].o_packets++;
-		st[idx&0xFF].o_bytes+=skb->len;
+		st[idx&0xFF].o_bytes += skb->len;
 		st[(idx>>16)&0xFF].i_packets++;
-		st[(idx>>16)&0xFF].i_bytes+=skb->len;
+		st[(idx>>16)&0xFF].i_bytes += skb->len;
 	}
 #endif
 
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index d2a8f8b..8ebe86d 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -430,7 +430,7 @@
  *	single device frame, and queue such a frame for sending.
  */
 
-int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
+int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
 	struct iphdr *iph;
 	int raw = 0;
@@ -720,7 +720,7 @@
 			int getfrag(void *from, char *to, int offset, int len,
 			       int odd, struct sk_buff *skb),
 			void *from, int length, int hh_len, int fragheaderlen,
-			int transhdrlen, int mtu,unsigned int flags)
+			int transhdrlen, int mtu, unsigned int flags)
 {
 	struct sk_buff *skb;
 	int err;
@@ -741,7 +741,7 @@
 		skb_reserve(skb, hh_len);
 
 		/* create space for UDP/IP header */
-		skb_put(skb,fragheaderlen + transhdrlen);
+		skb_put(skb, fragheaderlen + transhdrlen);
 
 		/* initialize network header pointer */
 		skb_reset_network_header(skb);
@@ -778,7 +778,7 @@
 		   int getfrag(void *from, char *to, int offset, int len,
 			       int odd, struct sk_buff *skb),
 		   void *from, int length, int transhdrlen,
-		   struct ipcm_cookie *ipc, struct rtable *rt,
+		   struct ipcm_cookie *ipc, struct rtable **rtp,
 		   unsigned int flags)
 {
 	struct inet_sock *inet = inet_sk(sk);
@@ -793,6 +793,7 @@
 	int offset = 0;
 	unsigned int maxfraglen, fragheaderlen;
 	int csummode = CHECKSUM_NONE;
+	struct rtable *rt;
 
 	if (flags&MSG_PROBE)
 		return 0;
@@ -812,7 +813,11 @@
 			inet->cork.flags |= IPCORK_OPT;
 			inet->cork.addr = ipc->addr;
 		}
-		dst_hold(&rt->u.dst);
+		rt = *rtp;
+		/*
+		 * We steal reference to this route, caller should not release it
+		 */
+		*rtp = NULL;
 		inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ?
 					    rt->u.dst.dev->mtu :
 					    dst_mtu(rt->u.dst.path);
@@ -1279,7 +1284,12 @@
 
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
-	skb->dst = dst_clone(&rt->u.dst);
+	/*
+	 * Steal rt from cork.dst to avoid a pair of atomic_inc/atomic_dec
+	 * on dst refcount
+	 */
+	inet->cork.dst = NULL;
+	skb->dst = &rt->u.dst;
 
 	if (iph->protocol == IPPROTO_ICMP)
 		icmp_out_count(net, ((struct icmphdr *)
@@ -1391,7 +1401,7 @@
 	sk->sk_protocol = ip_hdr(skb)->protocol;
 	sk->sk_bound_dev_if = arg->bound_dev_if;
 	ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0,
-		       &ipc, rt, MSG_DONTWAIT);
+		       &ipc, &rt, MSG_DONTWAIT);
 	if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
 		if (arg->csumoffset >= 0)
 			*((__sum16 *)skb_transport_header(skb) +
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 465abf0..43c0585 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -48,6 +48,7 @@
 #define IP_CMSG_RECVOPTS	8
 #define IP_CMSG_RETOPTS		16
 #define IP_CMSG_PASSSEC		32
+#define IP_CMSG_ORIGDSTADDR     64
 
 /*
  *	SOL_IP control messages.
@@ -94,7 +95,7 @@
 static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
 {
 	unsigned char optbuf[sizeof(struct ip_options) + 40];
-	struct ip_options * opt = (struct ip_options*)optbuf;
+	struct ip_options * opt = (struct ip_options *)optbuf;
 
 	if (IPCB(skb)->opt.optlen == 0)
 		return;
@@ -126,6 +127,27 @@
 	security_release_secctx(secdata, seclen);
 }
 
+static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
+{
+	struct sockaddr_in sin;
+	struct iphdr *iph = ip_hdr(skb);
+	__be16 *ports = (__be16 *)skb_transport_header(skb);
+
+	if (skb_transport_offset(skb) + 4 > skb->len)
+		return;
+
+	/* All current transport protocols have the port numbers in the
+	 * first four bytes of the transport header and this function is
+	 * written with this assumption in mind.
+	 */
+
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = iph->daddr;
+	sin.sin_port = ports[1];
+	memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
+
+	put_cmsg(msg, SOL_IP, IP_ORIGDSTADDR, sizeof(sin), &sin);
+}
 
 void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 {
@@ -160,6 +182,12 @@
 
 	if (flags & 1)
 		ip_cmsg_recv_security(msg, skb);
+
+	if ((flags>>=1) == 0)
+		return;
+	if (flags & 1)
+		ip_cmsg_recv_dstaddr(msg, skb);
+
 }
 
 int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
@@ -411,7 +439,7 @@
 			    int optname, char __user *optval, int optlen)
 {
 	struct inet_sock *inet = inet_sk(sk);
-	int val=0,err;
+	int val = 0, err;
 
 	if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) |
 			     (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) |
@@ -421,7 +449,8 @@
 			     (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
 			     (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
 	    optname == IP_MULTICAST_TTL ||
-	    optname == IP_MULTICAST_LOOP) {
+	    optname == IP_MULTICAST_LOOP ||
+	    optname == IP_RECVORIGDSTADDR) {
 		if (optlen >= sizeof(int)) {
 			if (get_user(val, (int __user *) optval))
 				return -EFAULT;
@@ -437,7 +466,7 @@
 	/* If optlen==0, it is equivalent to val == 0 */
 
 	if (ip_mroute_opt(optname))
-		return ip_mroute_setsockopt(sk,optname,optval,optlen);
+		return ip_mroute_setsockopt(sk, optname, optval, optlen);
 
 	err = 0;
 	lock_sock(sk);
@@ -509,6 +538,12 @@
 		else
 			inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
 		break;
+	case IP_RECVORIGDSTADDR:
+		if (val)
+			inet->cmsg_flags |= IP_CMSG_ORIGDSTADDR;
+		else
+			inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR;
+		break;
 	case IP_TOS:	/* This sets both TOS and Precedence */
 		if (sk->sk_type == SOCK_STREAM) {
 			val &= ~3;
@@ -549,7 +584,7 @@
 			goto e_inval;
 		if (optlen<1)
 			goto e_inval;
-		if (val==-1)
+		if (val == -1)
 			val = 1;
 		if (val < 0 || val > 255)
 			goto e_inval;
@@ -573,12 +608,12 @@
 
 		err = -EFAULT;
 		if (optlen >= sizeof(struct ip_mreqn)) {
-			if (copy_from_user(&mreq,optval,sizeof(mreq)))
+			if (copy_from_user(&mreq, optval, sizeof(mreq)))
 				break;
 		} else {
 			memset(&mreq, 0, sizeof(mreq));
 			if (optlen >= sizeof(struct in_addr) &&
-			    copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr)))
+			    copy_from_user(&mreq.imr_address, optval, sizeof(struct in_addr)))
 				break;
 		}
 
@@ -626,11 +661,11 @@
 			goto e_inval;
 		err = -EFAULT;
 		if (optlen >= sizeof(struct ip_mreqn)) {
-			if (copy_from_user(&mreq,optval,sizeof(mreq)))
+			if (copy_from_user(&mreq, optval, sizeof(mreq)))
 				break;
 		} else {
 			memset(&mreq, 0, sizeof(mreq));
-			if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq)))
+			if (copy_from_user(&mreq, optval, sizeof(struct ip_mreq)))
 				break;
 		}
 
@@ -808,7 +843,7 @@
 			err = -ENOBUFS;
 			break;
 		}
-		gsf = kmalloc(optlen,GFP_KERNEL);
+		gsf = kmalloc(optlen, GFP_KERNEL);
 		if (!gsf) {
 			err = -ENOBUFS;
 			break;
@@ -828,7 +863,7 @@
 			goto mc_msf_out;
 		}
 		msize = IP_MSFILTER_SIZE(gsf->gf_numsrc);
-		msf = kmalloc(msize,GFP_KERNEL);
+		msf = kmalloc(msize, GFP_KERNEL);
 		if (!msf) {
 			err = -ENOBUFS;
 			goto mc_msf_out;
@@ -971,9 +1006,9 @@
 		return -EOPNOTSUPP;
 
 	if (ip_mroute_opt(optname))
-		return ip_mroute_getsockopt(sk,optname,optval,optlen);
+		return ip_mroute_getsockopt(sk, optname, optval, optlen);
 
-	if (get_user(len,optlen))
+	if (get_user(len, optlen))
 		return -EFAULT;
 	if (len < 0)
 		return -EINVAL;
@@ -984,7 +1019,7 @@
 	case IP_OPTIONS:
 	{
 		unsigned char optbuf[sizeof(struct ip_options)+40];
-		struct ip_options * opt = (struct ip_options*)optbuf;
+		struct ip_options * opt = (struct ip_options *)optbuf;
 		opt->optlen = 0;
 		if (inet->opt)
 			memcpy(optbuf, inet->opt,
@@ -1022,6 +1057,9 @@
 	case IP_PASSSEC:
 		val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
 		break;
+	case IP_RECVORIGDSTADDR:
+		val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0;
+		break;
 	case IP_TOS:
 		val = inet->tos;
 		break;
@@ -1154,13 +1192,13 @@
 		len = 1;
 		if (put_user(len, optlen))
 			return -EFAULT;
-		if (copy_to_user(optval,&ucval,1))
+		if (copy_to_user(optval, &ucval, 1))
 			return -EFAULT;
 	} else {
 		len = min_t(unsigned int, sizeof(int), len);
 		if (put_user(len, optlen))
 			return -EFAULT;
-		if (copy_to_user(optval,&val,len))
+		if (copy_to_user(optval, &val, len))
 			return -EFAULT;
 	}
 	return 0;
@@ -1178,7 +1216,7 @@
 			!ip_mroute_opt(optname)) {
 		int len;
 
-		if (get_user(len,optlen))
+		if (get_user(len, optlen))
 			return -EFAULT;
 
 		lock_sock(sk);
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 38ccb6d..3262ce0 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -35,12 +35,12 @@
 		return;
 
 	spi = htonl(ntohs(ipch->cpi));
-	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr,
+	x = xfrm_state_lookup(&init_net, (xfrm_address_t *)&iph->daddr,
 			      spi, IPPROTO_COMP, AF_INET);
 	if (!x)
 		return;
-	NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/" NIPQUAD_FMT "\n",
-		 spi, NIPQUAD(iph->daddr));
+	NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%pI4\n",
+		 spi, &iph->daddr);
 	xfrm_state_put(x);
 }
 
@@ -49,7 +49,7 @@
 {
 	struct xfrm_state *t;
 
-	t = xfrm_state_alloc();
+	t = xfrm_state_alloc(&init_net);
 	if (t == NULL)
 		goto out;
 
@@ -85,7 +85,7 @@
 	int err = 0;
 	struct xfrm_state *t;
 
-	t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr.a4,
+	t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr.a4,
 			      x->props.saddr.a4, IPPROTO_IPIP, AF_INET);
 	if (!t) {
 		t = ipcomp_tunnel_create(x);
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 42065ff..42a0f3d 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -374,7 +374,7 @@
 	 */
 
 	if (!ic_host_name_set)
-		sprintf(init_utsname()->nodename, NIPQUAD_FMT, NIPQUAD(ic_myaddr));
+		sprintf(init_utsname()->nodename, "%pI4", &ic_myaddr);
 
 	if (root_server_addr == NONE)
 		root_server_addr = ic_servaddr;
@@ -387,11 +387,11 @@
 		else if (IN_CLASSC(ntohl(ic_myaddr)))
 			ic_netmask = htonl(IN_CLASSC_NET);
 		else {
-			printk(KERN_ERR "IP-Config: Unable to guess netmask for address " NIPQUAD_FMT "\n",
-				NIPQUAD(ic_myaddr));
+			printk(KERN_ERR "IP-Config: Unable to guess netmask for address %pI4\n",
+				&ic_myaddr);
 			return -1;
 		}
-		printk("IP-Config: Guessing netmask " NIPQUAD_FMT "\n", NIPQUAD(ic_netmask));
+		printk("IP-Config: Guessing netmask %pI4\n", &ic_netmask);
 	}
 
 	return 0;
@@ -979,10 +979,8 @@
 				ic_myaddr = b->your_ip;
 				ic_servaddr = server_id;
 #ifdef IPCONFIG_DEBUG
-				printk("DHCP: Offered address " NIPQUAD_FMT,
-				       NIPQUAD(ic_myaddr));
-				printk(" by server " NIPQUAD_FMT "\n",
-				       NIPQUAD(ic_servaddr));
+				printk("DHCP: Offered address %pI4 by server %pI4\n",
+				       &ic_myaddr, &ic_servaddr);
 #endif
 				/* The DHCP indicated server address takes
 				 * precedence over the bootp header one if
@@ -1177,11 +1175,11 @@
 		return -1;
 	}
 
-	printk("IP-Config: Got %s answer from " NIPQUAD_FMT ", ",
+	printk("IP-Config: Got %s answer from %pI4, ",
 		((ic_got_reply & IC_RARP) ? "RARP"
 		 : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"),
-		NIPQUAD(ic_servaddr));
-	printk("my address is " NIPQUAD_FMT "\n", NIPQUAD(ic_myaddr));
+		&ic_servaddr);
+	printk("my address is %pI4\n", &ic_myaddr);
 
 	return 0;
 }
@@ -1206,14 +1204,12 @@
 			   "domain %s\n", ic_domain);
 	for (i = 0; i < CONF_NAMESERVERS_MAX; i++) {
 		if (ic_nameservers[i] != NONE)
-			seq_printf(seq,
-				   "nameserver " NIPQUAD_FMT "\n",
-				   NIPQUAD(ic_nameservers[i]));
+			seq_printf(seq, "nameserver %pI4\n",
+				   &ic_nameservers[i]);
 	}
 	if (ic_servaddr != NONE)
-		seq_printf(seq,
-			   "bootserver " NIPQUAD_FMT "\n",
-			   NIPQUAD(ic_servaddr));
+		seq_printf(seq, "bootserver %pI4\n",
+			   &ic_servaddr);
 	return 0;
 }
 
@@ -1387,13 +1383,13 @@
 	 */
 	printk("IP-Config: Complete:");
 	printk("\n     device=%s", ic_dev->name);
-	printk(", addr=" NIPQUAD_FMT, NIPQUAD(ic_myaddr));
-	printk(", mask=" NIPQUAD_FMT, NIPQUAD(ic_netmask));
-	printk(", gw=" NIPQUAD_FMT, NIPQUAD(ic_gateway));
+	printk(", addr=%pI4", &ic_myaddr);
+	printk(", mask=%pI4", &ic_netmask);
+	printk(", gw=%pI4", &ic_gateway);
 	printk(",\n     host=%s, domain=%s, nis-domain=%s",
 	       utsname()->nodename, ic_domain, utsname()->domainname);
-	printk(",\n     bootserver=" NIPQUAD_FMT, NIPQUAD(ic_servaddr));
-	printk(", rootserver=" NIPQUAD_FMT, NIPQUAD(root_server_addr));
+	printk(",\n     bootserver=%pI4", &ic_servaddr);
+	printk(", rootserver=%pI4", &root_server_addr);
 	printk(", rootpath=%s", root_server_path);
 	printk("\n");
 #endif /* !SILENT */
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 29609d2..5079dfb 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -130,8 +130,8 @@
 	struct net_device *fb_tunnel_dev;
 };
 
-static int ipip_fb_tunnel_init(struct net_device *dev);
-static int ipip_tunnel_init(struct net_device *dev);
+static void ipip_fb_tunnel_init(struct net_device *dev);
+static void ipip_tunnel_init(struct net_device *dev);
 static void ipip_tunnel_setup(struct net_device *dev);
 
 static DEFINE_RWLOCK(ipip_lock);
@@ -245,9 +245,10 @@
 	}
 
 	nt = netdev_priv(dev);
-	dev->init = ipip_tunnel_init;
 	nt->parms = *parms;
 
+	ipip_tunnel_init(dev);
+
 	if (register_netdevice(dev) < 0)
 		goto failed_free;
 
@@ -281,7 +282,7 @@
    8 bytes of packet payload. It means, that precise relaying of
    ICMP in the real Internet is absolutely infeasible.
  */
-	struct iphdr *iph = (struct iphdr*)skb->data;
+	struct iphdr *iph = (struct iphdr *)skb->data;
 	const int type = icmp_hdr(skb)->type;
 	const int code = icmp_hdr(skb)->code;
 	struct ip_tunnel *t;
@@ -691,12 +692,17 @@
 	return 0;
 }
 
+static const struct net_device_ops ipip_netdev_ops = {
+	.ndo_uninit	= ipip_tunnel_uninit,
+	.ndo_start_xmit	= ipip_tunnel_xmit,
+	.ndo_do_ioctl	= ipip_tunnel_ioctl,
+	.ndo_change_mtu	= ipip_tunnel_change_mtu,
+
+};
+
 static void ipip_tunnel_setup(struct net_device *dev)
 {
-	dev->uninit		= ipip_tunnel_uninit;
-	dev->hard_start_xmit	= ipip_tunnel_xmit;
-	dev->do_ioctl		= ipip_tunnel_ioctl;
-	dev->change_mtu		= ipip_tunnel_change_mtu;
+	dev->netdev_ops		= &ipip_netdev_ops;
 	dev->destructor		= free_netdev;
 
 	dev->type		= ARPHRD_TUNNEL;
@@ -708,11 +714,9 @@
 	dev->features		|= NETIF_F_NETNS_LOCAL;
 }
 
-static int ipip_tunnel_init(struct net_device *dev)
+static void ipip_tunnel_init(struct net_device *dev)
 {
-	struct ip_tunnel *tunnel;
-
-	tunnel = netdev_priv(dev);
+	struct ip_tunnel *tunnel = netdev_priv(dev);
 
 	tunnel->dev = dev;
 	strcpy(tunnel->parms.name, dev->name);
@@ -721,11 +725,9 @@
 	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
 
 	ipip_tunnel_bind_dev(dev);
-
-	return 0;
 }
 
-static int ipip_fb_tunnel_init(struct net_device *dev)
+static void ipip_fb_tunnel_init(struct net_device *dev)
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
 	struct iphdr *iph = &tunnel->parms.iph;
@@ -740,7 +742,6 @@
 
 	dev_hold(dev);
 	ipn->tunnels_wc[0]	= tunnel;
-	return 0;
 }
 
 static struct xfrm_tunnel ipip_handler = {
@@ -792,10 +793,10 @@
 		err = -ENOMEM;
 		goto err_alloc_dev;
 	}
-
-	ipn->fb_tunnel_dev->init = ipip_fb_tunnel_init;
 	dev_net_set(ipn->fb_tunnel_dev, net);
 
+	ipip_fb_tunnel_init(ipn->fb_tunnel_dev);
+
 	if ((err = register_netdev(ipn->fb_tunnel_dev)))
 		goto err_reg_dev;
 
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 25924b1..1466644 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -124,8 +124,8 @@
 
 	dev = __dev_get_by_name(&init_net, "tunl0");
 	if (dev) {
+		const struct net_device_ops *ops = dev->netdev_ops;
 		struct ifreq ifr;
-		mm_segment_t	oldfs;
 		struct ip_tunnel_parm p;
 
 		memset(&p, 0, sizeof(p));
@@ -137,9 +137,13 @@
 		sprintf(p.name, "dvmrp%d", v->vifc_vifi);
 		ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
 
-		oldfs = get_fs(); set_fs(KERNEL_DS);
-		dev->do_ioctl(dev, &ifr, SIOCDELTUNNEL);
-		set_fs(oldfs);
+		if (ops->ndo_do_ioctl) {
+			mm_segment_t oldfs = get_fs();
+
+			set_fs(KERNEL_DS);
+			ops->ndo_do_ioctl(dev, &ifr, SIOCDELTUNNEL);
+			set_fs(oldfs);
+		}
 	}
 }
 
@@ -151,9 +155,9 @@
 	dev = __dev_get_by_name(&init_net, "tunl0");
 
 	if (dev) {
+		const struct net_device_ops *ops = dev->netdev_ops;
 		int err;
 		struct ifreq ifr;
-		mm_segment_t	oldfs;
 		struct ip_tunnel_parm p;
 		struct in_device  *in_dev;
 
@@ -166,9 +170,14 @@
 		sprintf(p.name, "dvmrp%d", v->vifc_vifi);
 		ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
 
-		oldfs = get_fs(); set_fs(KERNEL_DS);
-		err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL);
-		set_fs(oldfs);
+		if (ops->ndo_do_ioctl) {
+			mm_segment_t oldfs = get_fs();
+
+			set_fs(KERNEL_DS);
+			err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
+			set_fs(oldfs);
+		} else
+			err = -EOPNOTSUPP;
 
 		dev = NULL;
 
@@ -213,12 +222,16 @@
 	return 0;
 }
 
+static const struct net_device_ops reg_vif_netdev_ops = {
+	.ndo_start_xmit	= reg_vif_xmit,
+};
+
 static void reg_vif_setup(struct net_device *dev)
 {
 	dev->type		= ARPHRD_PIMREG;
 	dev->mtu		= ETH_DATA_LEN - sizeof(struct iphdr) - 8;
 	dev->flags		= IFF_NOARP;
-	dev->hard_start_xmit	= reg_vif_xmit;
+	dev->netdev_ops		= &reg_vif_netdev_ops,
 	dev->destructor		= free_netdev;
 }
 
@@ -331,7 +344,7 @@
 
 	atomic_dec(&cache_resolve_queue_len);
 
-	while ((skb=skb_dequeue(&c->mfc_un.unres.unresolved))) {
+	while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved))) {
 		if (ip_hdr(skb)->version == 0) {
 			struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
 			nlh->nlmsg_type = NLMSG_ERROR;
@@ -477,13 +490,13 @@
 	/*
 	 *	Fill in the VIF structures
 	 */
-	v->rate_limit=vifc->vifc_rate_limit;
-	v->local=vifc->vifc_lcl_addr.s_addr;
-	v->remote=vifc->vifc_rmt_addr.s_addr;
-	v->flags=vifc->vifc_flags;
+	v->rate_limit = vifc->vifc_rate_limit;
+	v->local = vifc->vifc_lcl_addr.s_addr;
+	v->remote = vifc->vifc_rmt_addr.s_addr;
+	v->flags = vifc->vifc_flags;
 	if (!mrtsock)
 		v->flags |= VIFF_STATIC;
-	v->threshold=vifc->vifc_threshold;
+	v->threshold = vifc->vifc_threshold;
 	v->bytes_in = 0;
 	v->bytes_out = 0;
 	v->pkt_in = 0;
@@ -494,7 +507,7 @@
 
 	/* And finish update writing critical data */
 	write_lock_bh(&mrt_lock);
-	v->dev=dev;
+	v->dev = dev;
 #ifdef CONFIG_IP_PIMSM
 	if (v->flags&VIFF_REGISTER)
 		reg_vif_num = vifi;
@@ -507,7 +520,7 @@
 
 static struct mfc_cache *ipmr_cache_find(__be32 origin, __be32 mcastgrp)
 {
-	int line=MFC_HASH(mcastgrp,origin);
+	int line = MFC_HASH(mcastgrp, origin);
 	struct mfc_cache *c;
 
 	for (c=mfc_cache_array[line]; c; c = c->next) {
@@ -522,8 +535,8 @@
  */
 static struct mfc_cache *ipmr_cache_alloc(void)
 {
-	struct mfc_cache *c=kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
-	if (c==NULL)
+	struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
+	if (c == NULL)
 		return NULL;
 	c->mfc_un.res.minvif = MAXVIFS;
 	return c;
@@ -531,8 +544,8 @@
 
 static struct mfc_cache *ipmr_cache_alloc_unres(void)
 {
-	struct mfc_cache *c=kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
-	if (c==NULL)
+	struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
+	if (c == NULL)
 		return NULL;
 	skb_queue_head_init(&c->mfc_un.unres.unresolved);
 	c->mfc_un.unres.expires = jiffies + 10*HZ;
@@ -552,7 +565,7 @@
 	 *	Play the pending entries through our router
 	 */
 
-	while ((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) {
+	while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
 		if (ip_hdr(skb)->version == 0) {
 			struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
 
@@ -637,7 +650,7 @@
 	 *	Add our header
 	 */
 
-	igmp=(struct igmphdr *)skb_put(skb,sizeof(struct igmphdr));
+	igmp=(struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
 	igmp->type	=
 	msg->im_msgtype = assert;
 	igmp->code 	=	0;
@@ -653,7 +666,7 @@
 	/*
 	 *	Deliver to mrouted
 	 */
-	if ((ret=sock_queue_rcv_skb(mroute_socket,skb))<0) {
+	if ((ret = sock_queue_rcv_skb(mroute_socket, skb))<0) {
 		if (net_ratelimit())
 			printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n");
 		kfree_skb(skb);
@@ -685,7 +698,7 @@
 		 *	Create a new entry if allowable
 		 */
 
-		if (atomic_read(&cache_resolve_queue_len)>=10 ||
+		if (atomic_read(&cache_resolve_queue_len) >= 10 ||
 		    (c=ipmr_cache_alloc_unres())==NULL) {
 			spin_unlock_bh(&mfc_unres_lock);
 
@@ -728,7 +741,7 @@
 		kfree_skb(skb);
 		err = -ENOBUFS;
 	} else {
-		skb_queue_tail(&c->mfc_un.unres.unresolved,skb);
+		skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
 		err = 0;
 	}
 
@@ -745,7 +758,7 @@
 	int line;
 	struct mfc_cache *c, **cp;
 
-	line=MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
+	line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
 
 	for (cp=&mfc_cache_array[line]; (c=*cp) != NULL; cp = &c->next) {
 		if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
@@ -766,7 +779,7 @@
 	int line;
 	struct mfc_cache *uc, *c, **cp;
 
-	line=MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
+	line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
 
 	for (cp=&mfc_cache_array[line]; (c=*cp) != NULL; cp = &c->next) {
 		if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
@@ -787,13 +800,13 @@
 	if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
 		return -EINVAL;
 
-	c=ipmr_cache_alloc();
-	if (c==NULL)
+	c = ipmr_cache_alloc();
+	if (c == NULL)
 		return -ENOMEM;
 
-	c->mfc_origin=mfc->mfcc_origin.s_addr;
-	c->mfc_mcastgrp=mfc->mfcc_mcastgrp.s_addr;
-	c->mfc_parent=mfc->mfcc_parent;
+	c->mfc_origin = mfc->mfcc_origin.s_addr;
+	c->mfc_mcastgrp = mfc->mfcc_mcastgrp.s_addr;
+	c->mfc_parent = mfc->mfcc_parent;
 	ipmr_update_thresholds(c, mfc->mfcc_ttls);
 	if (!mrtsock)
 		c->mfc_flags |= MFC_STATIC;
@@ -846,7 +859,7 @@
 	/*
 	 *	Wipe the cache
 	 */
-	for (i=0;i<MFC_LINES;i++) {
+	for (i=0; i<MFC_LINES; i++) {
 		struct mfc_cache *c, **cp;
 
 		cp = &mfc_cache_array[i];
@@ -887,7 +900,7 @@
 		IPV4_DEVCONF_ALL(sock_net(sk), MC_FORWARDING)--;
 
 		write_lock_bh(&mrt_lock);
-		mroute_socket=NULL;
+		mroute_socket = NULL;
 		write_unlock_bh(&mrt_lock);
 
 		mroute_clean_tables(sk);
@@ -902,7 +915,7 @@
  *	MOSPF/PIM router set up we can clean this up.
  */
 
-int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int optlen)
+int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int optlen)
 {
 	int ret;
 	struct vifctl vif;
@@ -918,7 +931,7 @@
 		if (sk->sk_type != SOCK_RAW ||
 		    inet_sk(sk)->num != IPPROTO_IGMP)
 			return -EOPNOTSUPP;
-		if (optlen!=sizeof(int))
+		if (optlen != sizeof(int))
 			return -ENOPROTOOPT;
 
 		rtnl_lock();
@@ -930,7 +943,7 @@
 		ret = ip_ra_control(sk, 1, mrtsock_destruct);
 		if (ret == 0) {
 			write_lock_bh(&mrt_lock);
-			mroute_socket=sk;
+			mroute_socket = sk;
 			write_unlock_bh(&mrt_lock);
 
 			IPV4_DEVCONF_ALL(sock_net(sk), MC_FORWARDING)++;
@@ -938,19 +951,19 @@
 		rtnl_unlock();
 		return ret;
 	case MRT_DONE:
-		if (sk!=mroute_socket)
+		if (sk != mroute_socket)
 			return -EACCES;
 		return ip_ra_control(sk, 0, NULL);
 	case MRT_ADD_VIF:
 	case MRT_DEL_VIF:
-		if (optlen!=sizeof(vif))
+		if (optlen != sizeof(vif))
 			return -EINVAL;
-		if (copy_from_user(&vif,optval,sizeof(vif)))
+		if (copy_from_user(&vif, optval, sizeof(vif)))
 			return -EFAULT;
 		if (vif.vifc_vifi >= MAXVIFS)
 			return -ENFILE;
 		rtnl_lock();
-		if (optname==MRT_ADD_VIF) {
+		if (optname == MRT_ADD_VIF) {
 			ret = vif_add(&vif, sk==mroute_socket);
 		} else {
 			ret = vif_delete(vif.vifc_vifi, 0);
@@ -964,12 +977,12 @@
 		 */
 	case MRT_ADD_MFC:
 	case MRT_DEL_MFC:
-		if (optlen!=sizeof(mfc))
+		if (optlen != sizeof(mfc))
 			return -EINVAL;
-		if (copy_from_user(&mfc,optval, sizeof(mfc)))
+		if (copy_from_user(&mfc, optval, sizeof(mfc)))
 			return -EFAULT;
 		rtnl_lock();
-		if (optname==MRT_DEL_MFC)
+		if (optname == MRT_DEL_MFC)
 			ret = ipmr_mfc_delete(&mfc);
 		else
 			ret = ipmr_mfc_add(&mfc, sk==mroute_socket);
@@ -1028,12 +1041,12 @@
  *	Getsock opt support for the multicast routing system.
  */
 
-int ip_mroute_getsockopt(struct sock *sk,int optname,char __user *optval,int __user *optlen)
+int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen)
 {
 	int olr;
 	int val;
 
-	if (optname!=MRT_VERSION &&
+	if (optname != MRT_VERSION &&
 #ifdef CONFIG_IP_PIMSM
 	   optname!=MRT_PIM &&
 #endif
@@ -1047,17 +1060,17 @@
 	if (olr < 0)
 		return -EINVAL;
 
-	if (put_user(olr,optlen))
+	if (put_user(olr, optlen))
 		return -EFAULT;
-	if (optname==MRT_VERSION)
-		val=0x0305;
+	if (optname == MRT_VERSION)
+		val = 0x0305;
 #ifdef CONFIG_IP_PIMSM
-	else if (optname==MRT_PIM)
-		val=mroute_do_pim;
+	else if (optname == MRT_PIM)
+		val = mroute_do_pim;
 #endif
 	else
-		val=mroute_do_assert;
-	if (copy_to_user(optval,&val,olr))
+		val = mroute_do_assert;
+	if (copy_to_user(optval, &val, olr))
 		return -EFAULT;
 	return 0;
 }
@@ -1075,27 +1088,27 @@
 
 	switch (cmd) {
 	case SIOCGETVIFCNT:
-		if (copy_from_user(&vr,arg,sizeof(vr)))
+		if (copy_from_user(&vr, arg, sizeof(vr)))
 			return -EFAULT;
-		if (vr.vifi>=maxvif)
+		if (vr.vifi >= maxvif)
 			return -EINVAL;
 		read_lock(&mrt_lock);
 		vif=&vif_table[vr.vifi];
 		if (VIF_EXISTS(vr.vifi))	{
-			vr.icount=vif->pkt_in;
-			vr.ocount=vif->pkt_out;
-			vr.ibytes=vif->bytes_in;
-			vr.obytes=vif->bytes_out;
+			vr.icount = vif->pkt_in;
+			vr.ocount = vif->pkt_out;
+			vr.ibytes = vif->bytes_in;
+			vr.obytes = vif->bytes_out;
 			read_unlock(&mrt_lock);
 
-			if (copy_to_user(arg,&vr,sizeof(vr)))
+			if (copy_to_user(arg, &vr, sizeof(vr)))
 				return -EFAULT;
 			return 0;
 		}
 		read_unlock(&mrt_lock);
 		return -EADDRNOTAVAIL;
 	case SIOCGETSGCNT:
-		if (copy_from_user(&sr,arg,sizeof(sr)))
+		if (copy_from_user(&sr, arg, sizeof(sr)))
 			return -EFAULT;
 
 		read_lock(&mrt_lock);
@@ -1106,7 +1119,7 @@
 			sr.wrong_if = c->mfc_un.res.wrong_if;
 			read_unlock(&mrt_lock);
 
-			if (copy_to_user(arg,&sr,sizeof(sr)))
+			if (copy_to_user(arg, &sr, sizeof(sr)))
 				return -EFAULT;
 			return 0;
 		}
@@ -1130,15 +1143,15 @@
 	if (event != NETDEV_UNREGISTER)
 		return NOTIFY_DONE;
 	v=&vif_table[0];
-	for (ct=0;ct<maxvif;ct++,v++) {
-		if (v->dev==dev)
+	for (ct=0; ct<maxvif; ct++,v++) {
+		if (v->dev == dev)
 			vif_delete(ct, 1);
 	}
 	return NOTIFY_DONE;
 }
 
 
-static struct notifier_block ip_mr_notifier={
+static struct notifier_block ip_mr_notifier = {
 	.notifier_call = ipmr_device_event,
 };
 
@@ -1204,7 +1217,7 @@
 #ifdef CONFIG_IP_PIMSM
 	if (vif->flags & VIFF_REGISTER) {
 		vif->pkt_out++;
-		vif->bytes_out+=skb->len;
+		vif->bytes_out += skb->len;
 		vif->dev->stats.tx_bytes += skb->len;
 		vif->dev->stats.tx_packets++;
 		ipmr_cache_report(skb, vifi, IGMPMSG_WHOLEPKT);
@@ -1254,7 +1267,7 @@
 	}
 
 	vif->pkt_out++;
-	vif->bytes_out+=skb->len;
+	vif->bytes_out += skb->len;
 
 	dst_release(skb->dst);
 	skb->dst = &rt->u.dst;
@@ -1352,7 +1365,7 @@
 	}
 
 	vif_table[vif].pkt_in++;
-	vif_table[vif].bytes_in+=skb->len;
+	vif_table[vif].bytes_in += skb->len;
 
 	/*
 	 *	Forward the frame
@@ -1364,7 +1377,7 @@
 				if (skb2)
 					ipmr_queue_xmit(skb2, cache, psend);
 			}
-			psend=ct;
+			psend = ct;
 		}
 	}
 	if (psend != -1) {
@@ -1428,7 +1441,7 @@
 	/*
 	 *	No usable cache entry
 	 */
-	if (cache==NULL) {
+	if (cache == NULL) {
 		int vif;
 
 		if (local) {
@@ -1469,29 +1482,13 @@
 	return 0;
 }
 
-#ifdef CONFIG_IP_PIMSM_V1
-/*
- * Handle IGMP messages of PIMv1
- */
-
-int pim_rcv_v1(struct sk_buff * skb)
+#ifdef CONFIG_IP_PIMSM
+static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
 {
-	struct igmphdr *pim;
-	struct iphdr   *encap;
-	struct net_device  *reg_dev = NULL;
+	struct net_device *reg_dev = NULL;
+	struct iphdr *encap;
 
-	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
-		goto drop;
-
-	pim = igmp_hdr(skb);
-
-	if (!mroute_do_pim ||
-	    skb->len < sizeof(*pim) + sizeof(*encap) ||
-	    pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
-		goto drop;
-
-	encap = (struct iphdr *)(skb_transport_header(skb) +
-				 sizeof(struct igmphdr));
+	encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
 	/*
 	   Check that:
 	   a. packet is really destinted to a multicast group
@@ -1500,8 +1497,8 @@
 	 */
 	if (!ipv4_is_multicast(encap->daddr) ||
 	    encap->tot_len == 0 ||
-	    ntohs(encap->tot_len) + sizeof(*pim) > skb->len)
-		goto drop;
+	    ntohs(encap->tot_len) + pimlen > skb->len)
+		return 1;
 
 	read_lock(&mrt_lock);
 	if (reg_vif_num >= 0)
@@ -1511,7 +1508,7 @@
 	read_unlock(&mrt_lock);
 
 	if (reg_dev == NULL)
-		goto drop;
+		return 1;
 
 	skb->mac_header = skb->network_header;
 	skb_pull(skb, (u8*)encap - skb->data);
@@ -1527,9 +1524,33 @@
 	nf_reset(skb);
 	netif_rx(skb);
 	dev_put(reg_dev);
+
 	return 0;
- drop:
-	kfree_skb(skb);
+}
+#endif
+
+#ifdef CONFIG_IP_PIMSM_V1
+/*
+ * Handle IGMP messages of PIMv1
+ */
+
+int pim_rcv_v1(struct sk_buff * skb)
+{
+	struct igmphdr *pim;
+
+	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
+		goto drop;
+
+	pim = igmp_hdr(skb);
+
+	if (!mroute_do_pim ||
+	    pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
+		goto drop;
+
+	if (__pim_rcv(skb, sizeof(*pim))) {
+drop:
+		kfree_skb(skb);
+	}
 	return 0;
 }
 #endif
@@ -1538,10 +1559,8 @@
 static int pim_rcv(struct sk_buff * skb)
 {
 	struct pimreghdr *pim;
-	struct iphdr   *encap;
-	struct net_device  *reg_dev = NULL;
 
-	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
+	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
 		goto drop;
 
 	pim = (struct pimreghdr *)skb_transport_header(skb);
@@ -1551,41 +1570,10 @@
 	     csum_fold(skb_checksum(skb, 0, skb->len, 0))))
 		goto drop;
 
-	/* check if the inner packet is destined to mcast group */
-	encap = (struct iphdr *)(skb_transport_header(skb) +
-				 sizeof(struct pimreghdr));
-	if (!ipv4_is_multicast(encap->daddr) ||
-	    encap->tot_len == 0 ||
-	    ntohs(encap->tot_len) + sizeof(*pim) > skb->len)
-		goto drop;
-
-	read_lock(&mrt_lock);
-	if (reg_vif_num >= 0)
-		reg_dev = vif_table[reg_vif_num].dev;
-	if (reg_dev)
-		dev_hold(reg_dev);
-	read_unlock(&mrt_lock);
-
-	if (reg_dev == NULL)
-		goto drop;
-
-	skb->mac_header = skb->network_header;
-	skb_pull(skb, (u8*)encap - skb->data);
-	skb_reset_network_header(skb);
-	skb->dev = reg_dev;
-	skb->protocol = htons(ETH_P_IP);
-	skb->ip_summed = 0;
-	skb->pkt_type = PACKET_HOST;
-	dst_release(skb->dst);
-	reg_dev->stats.rx_bytes += skb->len;
-	reg_dev->stats.rx_packets++;
-	skb->dst = NULL;
-	nf_reset(skb);
-	netif_rx(skb);
-	dev_put(reg_dev);
-	return 0;
- drop:
-	kfree_skb(skb);
+	if (__pim_rcv(skb, sizeof(*pim))) {
+drop:
+		kfree_skb(skb);
+	}
 	return 0;
 }
 #endif
@@ -1602,13 +1590,13 @@
 	if (dev)
 		RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex);
 
-	mp_head = (struct rtattr*)skb_put(skb, RTA_LENGTH(0));
+	mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
 
 	for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
 		if (c->mfc_un.res.ttls[ct] < 255) {
 			if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
 				goto rtattr_failure;
-			nhp = (struct rtnexthop*)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
+			nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
 			nhp->rtnh_flags = 0;
 			nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
 			nhp->rtnh_ifindex = vif_table[ct].dev->ifindex;
@@ -1634,7 +1622,7 @@
 	read_lock(&mrt_lock);
 	cache = ipmr_cache_find(rt->rt_src, rt->rt_dst);
 
-	if (cache==NULL) {
+	if (cache == NULL) {
 		struct sk_buff *skb2;
 		struct iphdr *iph;
 		struct net_device *dev;
@@ -1866,15 +1854,16 @@
 		const struct mfc_cache *mfc = v;
 		const struct ipmr_mfc_iter *it = seq->private;
 
-		seq_printf(seq, "%08lX %08lX %-3d %8ld %8ld %8ld",
+		seq_printf(seq, "%08lX %08lX %-3hd",
 			   (unsigned long) mfc->mfc_mcastgrp,
 			   (unsigned long) mfc->mfc_origin,
-			   mfc->mfc_parent,
-			   mfc->mfc_un.res.pkt,
-			   mfc->mfc_un.res.bytes,
-			   mfc->mfc_un.res.wrong_if);
+			   mfc->mfc_parent);
 
 		if (it->cache != &mfc_unres_queue) {
+			seq_printf(seq, " %8lu %8lu %8lu",
+				   mfc->mfc_un.res.pkt,
+				   mfc->mfc_un.res.bytes,
+				   mfc->mfc_un.res.wrong_if);
 			for (n = mfc->mfc_un.res.minvif;
 			     n < mfc->mfc_un.res.maxvif; n++ ) {
 				if (VIF_EXISTS(n)
@@ -1883,6 +1872,11 @@
 					   " %2d:%-3d",
 					   n, mfc->mfc_un.res.ttls[n]);
 			}
+		} else {
+			/* unresolved mfc_caches don't contain
+			 * pkt, bytes and wrong_if values
+			 */
+			seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
 		}
 		seq_putc(seq, '\n');
 	}
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 6efdb70..fdf6811 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -66,7 +66,7 @@
 #ifdef CONFIG_XFRM
 	if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
 	    xfrm_decode_session(skb, &fl, AF_INET) == 0)
-		if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0))
+		if (xfrm_lookup(net, &skb->dst, &fl, skb->sk, 0))
 			return -1;
 #endif
 
@@ -97,7 +97,7 @@
 		dst = ((struct xfrm_dst *)dst)->route;
 	dst_hold(dst);
 
-	if (xfrm_lookup(&dst, &fl, skb->sk, 0) < 0)
+	if (xfrm_lookup(dev_net(dst->dev), &dst, &fl, skb->sk, 0) < 0)
 		return -1;
 
 	dst_release(skb->dst);
@@ -125,6 +125,7 @@
 	__be32 daddr;
 	__be32 saddr;
 	u_int8_t tos;
+	u_int32_t mark;
 };
 
 static void nf_ip_saveroute(const struct sk_buff *skb,
@@ -138,6 +139,7 @@
 		rt_info->tos = iph->tos;
 		rt_info->daddr = iph->daddr;
 		rt_info->saddr = iph->saddr;
+		rt_info->mark = skb->mark;
 	}
 }
 
@@ -150,6 +152,7 @@
 		const struct iphdr *iph = ip_hdr(skb);
 
 		if (!(iph->tos == rt_info->tos
+		      && skb->mark == rt_info->mark
 		      && iph->daddr == rt_info->daddr
 		      && iph->saddr == rt_info->saddr))
 			return ip_route_me_harder(skb, RTN_UNSPEC);
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 8d70d29..7ea88b6 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -142,15 +142,15 @@
 		  ARPT_INV_TGTIP)) {
 		dprintf("Source or target IP address mismatch.\n");
 
-		dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
-			NIPQUAD(src_ipaddr),
-			NIPQUAD(arpinfo->smsk.s_addr),
-			NIPQUAD(arpinfo->src.s_addr),
+		dprintf("SRC: %pI4. Mask: %pI4. Target: %pI4.%s\n",
+			&src_ipaddr,
+			&arpinfo->smsk.s_addr,
+			&arpinfo->src.s_addr,
 			arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : "");
-		dprintf("TGT: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
-			NIPQUAD(tgt_ipaddr),
-			NIPQUAD(arpinfo->tmsk.s_addr),
-			NIPQUAD(arpinfo->tgt.s_addr),
+		dprintf("TGT: %pI4 Mask: %pI4 Target: %pI4.%s\n",
+			&tgt_ipaddr,
+			&arpinfo->tmsk.s_addr,
+			&arpinfo->tgt.s_addr,
 			arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : "");
 		return 0;
 	}
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index bee3d11..e091187 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -75,16 +75,6 @@
 			     dev_net(out)->ipv4.arptable_filter);
 }
 
-static unsigned int arpt_forward_hook(unsigned int hook,
-				      struct sk_buff *skb,
-				      const struct net_device *in,
-				      const struct net_device *out,
-				      int (*okfn)(struct sk_buff *))
-{
-	return arpt_do_table(skb, hook, in, out,
-			     dev_net(in)->ipv4.arptable_filter);
-}
-
 static struct nf_hook_ops arpt_ops[] __read_mostly = {
 	{
 		.hook		= arpt_in_hook,
@@ -101,7 +91,7 @@
 		.priority	= NF_IP_PRI_FILTER,
 	},
 	{
-		.hook		= arpt_forward_hook,
+		.hook		= arpt_in_hook,
 		.owner		= THIS_MODULE,
 		.pf		= NFPROTO_ARP,
 		.hooknum	= NF_ARP_FORWARD,
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 213fb27..ef8b6ca 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -94,15 +94,11 @@
 		     IPT_INV_DSTIP)) {
 		dprintf("Source or dest mismatch.\n");
 
-		dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
-			NIPQUAD(ip->saddr),
-			NIPQUAD(ipinfo->smsk.s_addr),
-			NIPQUAD(ipinfo->src.s_addr),
+		dprintf("SRC: %pI4. Mask: %pI4. Target: %pI4.%s\n",
+			&ip->saddr, &ipinfo->smsk.s_addr, &ipinfo->src.s_addr,
 			ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");
-		dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
-			NIPQUAD(ip->daddr),
-			NIPQUAD(ipinfo->dmsk.s_addr),
-			NIPQUAD(ipinfo->dst.s_addr),
+		dprintf("DST: %pI4 Mask: %pI4 Target: %pI4.%s\n",
+			&ip->daddr, &ipinfo->dmsk.s_addr, &ipinfo->dst.s_addr,
 			ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");
 		return false;
 	}
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 7ac1677..2e4f98b 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -168,7 +168,7 @@
 		char buffer[16];
 
 		/* create proc dir entry */
-		sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
+		sprintf(buffer, "%pI4", &ip);
 		c->pde = proc_create_data(buffer, S_IWUSR|S_IRUSR,
 					  clusterip_procdir,
 					  &clusterip_proc_fops, c);
@@ -373,7 +373,7 @@
 	config = clusterip_config_find_get(e->ip.dst.s_addr, 1);
 	if (!config) {
 		if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) {
-			printk(KERN_WARNING "CLUSTERIP: no config found for %u.%u.%u.%u, need 'new'\n", NIPQUAD(e->ip.dst.s_addr));
+			printk(KERN_WARNING "CLUSTERIP: no config found for %pI4, need 'new'\n", &e->ip.dst.s_addr);
 			return false;
 		} else {
 			struct net_device *dev;
@@ -478,9 +478,8 @@
 	}
 	hbuffer[--k]='\0';
 
-	printk("src %u.%u.%u.%u@%s, dst %u.%u.%u.%u\n",
-		NIPQUAD(payload->src_ip), hbuffer,
-		NIPQUAD(payload->dst_ip));
+	printk("src %pI4@%s, dst %pI4\n",
+		&payload->src_ip, hbuffer, &payload->dst_ip);
 }
 #endif
 
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index fc6ce04..27a78fb 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -54,8 +54,8 @@
 	/* Important fields:
 	 * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
 	/* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
-	printk("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ",
-	       NIPQUAD(ih->saddr), NIPQUAD(ih->daddr));
+	printk("SRC=%pI4 DST=%pI4 ",
+	       &ih->saddr, &ih->daddr);
 
 	/* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
 	printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
@@ -262,8 +262,7 @@
 			break;
 		case ICMP_REDIRECT:
 			/* Max length: 24 "GATEWAY=255.255.255.255 " */
-			printk("GATEWAY=%u.%u.%u.%u ",
-			       NIPQUAD(ich->un.gateway));
+			printk("GATEWAY=%pI4 ", &ich->un.gateway);
 			/* Fall through */
 		case ICMP_DEST_UNREACH:
 		case ICMP_SOURCE_QUENCH:
@@ -340,8 +339,8 @@
 		read_lock_bh(&skb->sk->sk_callback_lock);
 		if (skb->sk->sk_socket && skb->sk->sk_socket->file)
 			printk("UID=%u GID=%u ",
-				skb->sk->sk_socket->file->f_uid,
-				skb->sk->sk_socket->file->f_gid);
+				skb->sk->sk_socket->file->f_cred->fsuid,
+				skb->sk->sk_socket->file->f_cred->fsgid);
 		read_unlock_bh(&skb->sk->sk_callback_lock);
 	}
 
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index 88762f0..3b216be 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -23,24 +23,25 @@
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
 MODULE_DESCRIPTION("Xtables: address type match for IPv4");
 
-static inline bool match_type(const struct net_device *dev, __be32 addr,
-			      u_int16_t mask)
+static inline bool match_type(struct net *net, const struct net_device *dev,
+			      __be32 addr, u_int16_t mask)
 {
-	return !!(mask & (1 << inet_dev_addr_type(&init_net, dev, addr)));
+	return !!(mask & (1 << inet_dev_addr_type(net, dev, addr)));
 }
 
 static bool
 addrtype_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 {
+	struct net *net = dev_net(par->in ? par->in : par->out);
 	const struct ipt_addrtype_info *info = par->matchinfo;
 	const struct iphdr *iph = ip_hdr(skb);
 	bool ret = true;
 
 	if (info->source)
-		ret &= match_type(NULL, iph->saddr, info->source) ^
+		ret &= match_type(net, NULL, iph->saddr, info->source) ^
 		       info->invert_source;
 	if (info->dest)
-		ret &= match_type(NULL, iph->daddr, info->dest) ^
+		ret &= match_type(net, NULL, iph->daddr, info->dest) ^
 		       info->invert_dest;
 
 	return ret;
@@ -49,6 +50,7 @@
 static bool
 addrtype_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
 {
+	struct net *net = dev_net(par->in ? par->in : par->out);
 	const struct ipt_addrtype_info_v1 *info = par->matchinfo;
 	const struct iphdr *iph = ip_hdr(skb);
 	const struct net_device *dev = NULL;
@@ -60,10 +62,10 @@
 		dev = par->out;
 
 	if (info->source)
-		ret &= match_type(dev, iph->saddr, info->source) ^
+		ret &= match_type(net, dev, iph->saddr, info->source) ^
 		       (info->flags & IPT_ADDRTYPE_INVERT_SOURCE);
 	if (ret && info->dest)
-		ret &= match_type(dev, iph->daddr, info->dest) ^
+		ret &= match_type(net, dev, iph->daddr, info->dest) ^
 		       !!(info->flags & IPT_ADDRTYPE_INVERT_DEST);
 	return ret;
 }
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 4a7c352..b2141e1 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -60,9 +60,8 @@
 static int ipv4_print_tuple(struct seq_file *s,
 			    const struct nf_conntrack_tuple *tuple)
 {
-	return seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
-			  NIPQUAD(tuple->src.u3.ip),
-			  NIPQUAD(tuple->dst.u3.ip));
+	return seq_printf(s, "src=%pI4 dst=%pI4 ",
+			  &tuple->src.u3.ip, &tuple->dst.u3.ip);
 }
 
 static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
@@ -198,7 +197,7 @@
 		.data		= &nf_conntrack_max,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_NF_CONNTRACK_COUNT,
@@ -206,7 +205,7 @@
 		.data		= &init_net.ct.count,
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_NF_CONNTRACK_BUCKETS,
@@ -214,7 +213,7 @@
 		.data		= &nf_conntrack_htable_size,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0444,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_NF_CONNTRACK_CHECKSUM,
@@ -222,7 +221,7 @@
 		.data		= &init_net.ct.sysctl_checksum,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_NF_CONNTRACK_LOG_INVALID,
@@ -230,8 +229,8 @@
 		.data		= &init_net.ct.sysctl_log_invalid,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &log_invalid_proto_min,
 		.extra2		= &log_invalid_proto_max,
 	},
@@ -284,17 +283,17 @@
 			.tuple.dst.u3.ip;
 		memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
 
-		pr_debug("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
-			 NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
+		pr_debug("SO_ORIGINAL_DST: %pI4 %u\n",
+			 &sin.sin_addr.s_addr, ntohs(sin.sin_port));
 		nf_ct_put(ct);
 		if (copy_to_user(user, &sin, sizeof(sin)) != 0)
 			return -EFAULT;
 		else
 			return 0;
 	}
-	pr_debug("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
-		 NIPQUAD(tuple.src.u3.ip), ntohs(tuple.src.u.tcp.port),
-		 NIPQUAD(tuple.dst.u3.ip), ntohs(tuple.dst.u.tcp.port));
+	pr_debug("SO_ORIGINAL_DST: Can't find %pI4/%u-%pI4/%u.\n",
+		 &tuple.src.u3.ip, ntohs(tuple.src.u.tcp.port),
+		 &tuple.dst.u3.ip, ntohs(tuple.dst.u.tcp.port));
 	return -ENOENT;
 }
 
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 4e88792..1fd3ef7 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -272,7 +272,7 @@
 		.data		= &nf_ct_icmp_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name = 0
@@ -285,7 +285,7 @@
 		.data		= &nf_ct_icmp_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name = 0
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index ee47bf2..7e8e6fc 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -119,10 +119,9 @@
 				    (ntohl(addr.ip) & 0xff000000) == 0x7f000000)
 					i = 0;
 
-				pr_debug("nf_nat_ras: set signal address "
-					 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-					 NIPQUAD(addr.ip), port,
-					 NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip),
+				pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n",
+					 &addr.ip, port,
+					 &ct->tuplehash[!dir].tuple.dst.u3.ip,
 					 info->sig_port[!dir]);
 				return set_h225_addr(skb, data, 0, &taddr[i],
 						     &ct->tuplehash[!dir].
@@ -131,10 +130,9 @@
 			} else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
 				   port == info->sig_port[dir]) {
 				/* GK->GW */
-				pr_debug("nf_nat_ras: set signal address "
-					 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-					 NIPQUAD(addr.ip), port,
-					 NIPQUAD(ct->tuplehash[!dir].tuple.src.u3.ip),
+				pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n",
+					 &addr.ip, port,
+					 &ct->tuplehash[!dir].tuple.src.u3.ip,
 					 info->sig_port[!dir]);
 				return set_h225_addr(skb, data, 0, &taddr[i],
 						     &ct->tuplehash[!dir].
@@ -162,10 +160,9 @@
 		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
 		    addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
 		    port == ct->tuplehash[dir].tuple.src.u.udp.port) {
-			pr_debug("nf_nat_ras: set rasAddress "
-				 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-				 NIPQUAD(addr.ip), ntohs(port),
-				 NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip),
+			pr_debug("nf_nat_ras: set rasAddress %pI4:%hu->%pI4:%hu\n",
+				 &addr.ip, ntohs(port),
+				 &ct->tuplehash[!dir].tuple.dst.u3.ip,
 				 ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port));
 			return set_h225_addr(skb, data, 0, &taddr[i],
 					     &ct->tuplehash[!dir].tuple.dst.u3,
@@ -257,15 +254,15 @@
 	}
 
 	/* Success */
-	pr_debug("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-		 NIPQUAD(rtp_exp->tuple.src.u3.ip),
+	pr_debug("nf_nat_h323: expect RTP %pI4:%hu->%pI4:%hu\n",
+		 &rtp_exp->tuple.src.u3.ip,
 		 ntohs(rtp_exp->tuple.src.u.udp.port),
-		 NIPQUAD(rtp_exp->tuple.dst.u3.ip),
+		 &rtp_exp->tuple.dst.u3.ip,
 		 ntohs(rtp_exp->tuple.dst.u.udp.port));
-	pr_debug("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-		 NIPQUAD(rtcp_exp->tuple.src.u3.ip),
+	pr_debug("nf_nat_h323: expect RTCP %pI4:%hu->%pI4:%hu\n",
+		 &rtcp_exp->tuple.src.u3.ip,
 		 ntohs(rtcp_exp->tuple.src.u.udp.port),
-		 NIPQUAD(rtcp_exp->tuple.dst.u3.ip),
+		 &rtcp_exp->tuple.dst.u3.ip,
 		 ntohs(rtcp_exp->tuple.dst.u.udp.port));
 
 	return 0;
@@ -307,10 +304,10 @@
 		return -1;
 	}
 
-	pr_debug("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-		 NIPQUAD(exp->tuple.src.u3.ip),
+	pr_debug("nf_nat_h323: expect T.120 %pI4:%hu->%pI4:%hu\n",
+		 &exp->tuple.src.u3.ip,
 		 ntohs(exp->tuple.src.u.tcp.port),
-		 NIPQUAD(exp->tuple.dst.u3.ip),
+		 &exp->tuple.dst.u3.ip,
 		 ntohs(exp->tuple.dst.u.tcp.port));
 
 	return 0;
@@ -361,10 +358,10 @@
 		return -1;
 	}
 
-	pr_debug("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-		 NIPQUAD(exp->tuple.src.u3.ip),
+	pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n",
+		 &exp->tuple.src.u3.ip,
 		 ntohs(exp->tuple.src.u.tcp.port),
-		 NIPQUAD(exp->tuple.dst.u3.ip),
+		 &exp->tuple.dst.u3.ip,
 		 ntohs(exp->tuple.dst.u.tcp.port));
 
 	return 0;
@@ -455,10 +452,10 @@
 	}
 
 	/* Success */
-	pr_debug("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-		 NIPQUAD(exp->tuple.src.u3.ip),
+	pr_debug("nf_nat_ras: expect Q.931 %pI4:%hu->%pI4:%hu\n",
+		 &exp->tuple.src.u3.ip,
 		 ntohs(exp->tuple.src.u.tcp.port),
-		 NIPQUAD(exp->tuple.dst.u3.ip),
+		 &exp->tuple.dst.u3.ip,
 		 ntohs(exp->tuple.dst.u.tcp.port));
 
 	return 0;
@@ -524,11 +521,10 @@
 	}
 
 	/* Success */
-	pr_debug("nf_nat_q931: expect Call Forwarding "
-		 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-		 NIPQUAD(exp->tuple.src.u3.ip),
+	pr_debug("nf_nat_q931: expect Call Forwarding %pI4:%hu->%pI4:%hu\n",
+		 &exp->tuple.src.u3.ip,
 		 ntohs(exp->tuple.src.u.tcp.port),
-		 NIPQUAD(exp->tuple.dst.u3.ip),
+		 &exp->tuple.dst.u3.ip,
 		 ntohs(exp->tuple.dst.u.tcp.port));
 
 	return 0;
diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c
index fe6f9ce..ea83a88 100644
--- a/net/ipv4/netfilter/nf_nat_irc.c
+++ b/net/ipv4/netfilter/nf_nat_irc.c
@@ -55,8 +55,8 @@
 
 	ip = ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip);
 	sprintf(buffer, "%u %u", ip, port);
-	pr_debug("nf_nat_irc: inserting '%s' == %u.%u.%u.%u, port %u\n",
-		 buffer, NIPQUAD(ip), port);
+	pr_debug("nf_nat_irc: inserting '%s' == %pI4, port %u\n",
+		 buffer, &ip, port);
 
 	ret = nf_nat_mangle_tcp_packet(skb, exp->master, ctinfo,
 				       matchoff, matchlen, buffer,
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index 8d489e7..a7eb047 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -86,25 +86,6 @@
 	return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_SRC);
 }
 
-/* Before 2.6.11 we did implicit source NAT if required. Warn about change. */
-static void warn_if_extra_mangle(struct net *net, __be32 dstip, __be32 srcip)
-{
-	static int warned = 0;
-	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } };
-	struct rtable *rt;
-
-	if (ip_route_output_key(net, &rt, &fl) != 0)
-		return;
-
-	if (rt->rt_src != srcip && !warned) {
-		printk("NAT: no longer support implicit source local NAT\n");
-		printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n",
-		       NIPQUAD(srcip), NIPQUAD(dstip));
-		warned = 1;
-	}
-	ip_rt_put(rt);
-}
-
 static unsigned int
 ipt_dnat_target(struct sk_buff *skb, const struct xt_target_param *par)
 {
@@ -120,11 +101,6 @@
 	/* Connection must be valid and new. */
 	NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
 
-	if (par->hooknum == NF_INET_LOCAL_OUT &&
-	    mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
-		warn_if_extra_mangle(dev_net(par->out), ip_hdr(skb)->daddr,
-				     mr->range[0].min_ip);
-
 	return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_DST);
 }
 
@@ -166,8 +142,7 @@
 	struct nf_nat_range range
 		= { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } };
 
-	pr_debug("Allocating NULL binding for %p (%u.%u.%u.%u)\n",
-		 ct, NIPQUAD(ip));
+	pr_debug("Allocating NULL binding for %p (%pI4)\n", ct, &ip);
 	return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
 }
 
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 1454432..07d61a5 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -74,8 +74,7 @@
 	if (newaddr == addr->ip && newport == port)
 		return 1;
 
-	buflen = sprintf(buffer, "%u.%u.%u.%u:%u",
-			 NIPQUAD(newaddr), ntohs(newport));
+	buflen = sprintf(buffer, "%pI4:%u", &newaddr, ntohs(newport));
 
 	return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
 			     buffer, buflen);
@@ -152,8 +151,8 @@
 					       &addr) > 0 &&
 		    addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
 		    addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
-			__be32 ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
-			buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
+			buflen = sprintf(buffer, "%pI4",
+					&ct->tuplehash[!dir].tuple.dst.u3.ip);
 			if (!mangle_packet(skb, dptr, datalen, poff, plen,
 					   buffer, buflen))
 				return NF_DROP;
@@ -166,8 +165,8 @@
 					       &addr) > 0 &&
 		    addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
 		    addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
-			__be32 ip = ct->tuplehash[!dir].tuple.src.u3.ip;
-			buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
+			buflen = sprintf(buffer, "%pI4",
+					&ct->tuplehash[!dir].tuple.src.u3.ip);
 			if (!mangle_packet(skb, dptr, datalen, poff, plen,
 					   buffer, buflen))
 				return NF_DROP;
@@ -279,8 +278,7 @@
 
 	if (exp->tuple.dst.u3.ip != exp->saved_ip ||
 	    exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
-		buflen = sprintf(buffer, "%u.%u.%u.%u:%u",
-				 NIPQUAD(newip), port);
+		buflen = sprintf(buffer, "%pI4:%u", &newip, port);
 		if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen,
 				   buffer, buflen))
 			goto err;
@@ -345,7 +343,7 @@
 	char buffer[sizeof("nnn.nnn.nnn.nnn")];
 	unsigned int buflen;
 
-	buflen = sprintf(buffer, NIPQUAD_FMT, NIPQUAD(addr->ip));
+	buflen = sprintf(buffer, "%pI4", &addr->ip);
 	if (mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term,
 			      buffer, buflen))
 		return 0;
@@ -380,7 +378,7 @@
 	unsigned int buflen;
 
 	/* Mangle session description owner and contact addresses */
-	buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(addr->ip));
+	buflen = sprintf(buffer, "%pI4", &addr->ip);
 	if (mangle_sdp_packet(skb, dptr, dataoff, datalen,
 			       SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA,
 			       buffer, buflen))
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index 8303e4b..182f845 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -930,8 +930,8 @@
 		}
 
 		if (debug)
-			printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to "
-			       "%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr));
+			printk(KERN_DEBUG "bsalg: mapped %pI4 to %pI4\n",
+			       &old, addr);
 	}
 }
 
@@ -1267,9 +1267,8 @@
 	 */
 	if (ntohs(udph->len) != skb->len - (iph->ihl << 2)) {
 		 if (net_ratelimit())
-			 printk(KERN_WARNING "SNMP: dropping malformed packet "
-				"src=%u.%u.%u.%u dst=%u.%u.%u.%u\n",
-				NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
+			 printk(KERN_WARNING "SNMP: dropping malformed packet src=%pI4 dst=%pI4\n",
+				&iph->saddr, &iph->daddr);
 		 return NF_DROP;
 	}
 
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index a631a1f..614958b 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -54,8 +54,9 @@
 	socket_seq_show(seq);
 	seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %d\n",
 		   sock_prot_inuse_get(net, &tcp_prot),
-		   atomic_read(&tcp_orphan_count),
-		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
+		   (int)percpu_counter_sum_positive(&tcp_orphan_count),
+		   tcp_death_row.tw_count,
+		   (int)percpu_counter_sum_positive(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
 	seq_printf(seq, "UDP: inuse %d mem %d\n",
 		   sock_prot_inuse_get(net, &udp_prot),
@@ -234,6 +235,9 @@
 	SNMP_MIB_ITEM("TCPSpuriousRTOs", LINUX_MIB_TCPSPURIOUSRTOS),
 	SNMP_MIB_ITEM("TCPMD5NotFound", LINUX_MIB_TCPMD5NOTFOUND),
 	SNMP_MIB_ITEM("TCPMD5Unexpected", LINUX_MIB_TCPMD5UNEXPECTED),
+	SNMP_MIB_ITEM("TCPSackShifted", LINUX_MIB_SACKSHIFTED),
+	SNMP_MIB_ITEM("TCPSackMerged", LINUX_MIB_SACKMERGED),
+	SNMP_MIB_ITEM("TCPSackShiftFallback", LINUX_MIB_SACKSHIFTFALLBACK),
 	SNMP_MIB_SENTINEL
 };
 
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index cd97574..dff8bc4 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -247,7 +247,7 @@
 	}
 
 	if (inet->recverr) {
-		struct iphdr *iph = (struct iphdr*)skb->data;
+		struct iphdr *iph = (struct iphdr *)skb->data;
 		u8 *payload = skb->data + (iph->ihl << 2);
 
 		if (inet->hdrincl)
@@ -465,7 +465,7 @@
 	 */
 
 	if (msg->msg_namelen) {
-		struct sockaddr_in *usin = (struct sockaddr_in*)msg->msg_name;
+		struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name;
 		err = -EINVAL;
 		if (msg->msg_namelen < sizeof(*usin))
 			goto out;
@@ -572,7 +572,7 @@
 			ipc.addr = rt->rt_dst;
 		lock_sock(sk);
 		err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0,
-					&ipc, rt, msg->msg_flags);
+					&ipc, &rt, msg->msg_flags);
 		if (err)
 			ip_flush_pending_frames(sk);
 		else if (!(msg->msg_flags & MSG_MORE))
@@ -851,7 +851,7 @@
 static struct sock *raw_get_first(struct seq_file *seq)
 {
 	struct sock *sk;
-	struct raw_iter_state* state = raw_seq_private(seq);
+	struct raw_iter_state *state = raw_seq_private(seq);
 
 	for (state->bucket = 0; state->bucket < RAW_HTABLE_SIZE;
 			++state->bucket) {
@@ -868,7 +868,7 @@
 
 static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk)
 {
-	struct raw_iter_state* state = raw_seq_private(seq);
+	struct raw_iter_state *state = raw_seq_private(seq);
 
 	do {
 		sk = sk_next(sk);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 2ea6dcc..77bfba9 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -129,6 +129,7 @@
 static int ip_rt_min_pmtu __read_mostly		= 512 + 20 + 20;
 static int ip_rt_min_advmss __read_mostly	= 256;
 static int ip_rt_secret_interval __read_mostly	= 10 * 60 * HZ;
+static int rt_chain_length_max __read_mostly	= 20;
 
 static void rt_worker_func(struct work_struct *work);
 static DECLARE_DELAYED_WORK(expires_work, rt_worker_func);
@@ -145,6 +146,7 @@
 static void		 ipv4_link_failure(struct sk_buff *skb);
 static void		 ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
 static int rt_garbage_collect(struct dst_ops *ops);
+static void rt_emergency_hash_rebuild(struct net *net);
 
 
 static struct dst_ops ipv4_dst_ops = {
@@ -158,7 +160,6 @@
 	.link_failure =		ipv4_link_failure,
 	.update_pmtu =		ip_rt_update_pmtu,
 	.local_out =		__ip_local_out,
-	.entry_size =		sizeof(struct rtable),
 	.entries =		ATOMIC_INIT(0),
 };
 
@@ -201,6 +202,7 @@
 struct rt_hash_bucket {
 	struct rtable	*chain;
 };
+
 #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \
 	defined(CONFIG_PROVE_LOCKING)
 /*
@@ -674,6 +676,20 @@
 	return score;
 }
 
+static inline bool rt_caching(const struct net *net)
+{
+	return net->ipv4.current_rt_cache_rebuild_count <=
+		net->ipv4.sysctl_rt_cache_rebuild_count;
+}
+
+static inline bool compare_hash_inputs(const struct flowi *fl1,
+					const struct flowi *fl2)
+{
+	return (__force u32)(((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) |
+		(fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) |
+		(fl1->iif ^ fl2->iif)) == 0);
+}
+
 static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
 {
 	return ((__force u32)((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) |
@@ -753,11 +769,24 @@
 	}
 }
 
+/*
+ * While freeing expired entries, we compute average chain length
+ * and standard deviation, using fixed-point arithmetic.
+ * This to have an estimation of rt_chain_length_max
+ *  rt_chain_length_max = max(elasticity, AVG + 4*SD)
+ * We use 3 bits for frational part, and 29 (or 61) for magnitude.
+ */
+
+#define FRACT_BITS 3
+#define ONE (1UL << FRACT_BITS)
+
 static void rt_check_expire(void)
 {
 	static unsigned int rover;
 	unsigned int i = rover, goal;
 	struct rtable *rth, **rthp;
+	unsigned long length = 0, samples = 0;
+	unsigned long sum = 0, sum2 = 0;
 	u64 mult;
 
 	mult = ((u64)ip_rt_gc_interval) << rt_hash_log;
@@ -766,6 +795,7 @@
 	goal = (unsigned int)mult;
 	if (goal > rt_hash_mask)
 		goal = rt_hash_mask + 1;
+	length = 0;
 	for (; goal > 0; goal--) {
 		unsigned long tmo = ip_rt_gc_timeout;
 
@@ -775,6 +805,8 @@
 		if (need_resched())
 			cond_resched();
 
+		samples++;
+
 		if (*rthp == NULL)
 			continue;
 		spin_lock_bh(rt_hash_lock_addr(i));
@@ -789,11 +821,29 @@
 				if (time_before_eq(jiffies, rth->u.dst.expires)) {
 					tmo >>= 1;
 					rthp = &rth->u.dst.rt_next;
+					/*
+					 * Only bump our length if the hash
+					 * inputs on entries n and n+1 are not
+					 * the same, we only count entries on
+					 * a chain with equal hash inputs once
+					 * so that entries for different QOS
+					 * levels, and other non-hash input
+					 * attributes don't unfairly skew
+					 * the length computation
+					 */
+					if ((*rthp == NULL) ||
+					    !compare_hash_inputs(&(*rthp)->fl,
+								 &rth->fl))
+						length += ONE;
 					continue;
 				}
 			} else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout)) {
 				tmo >>= 1;
 				rthp = &rth->u.dst.rt_next;
+				if ((*rthp == NULL) ||
+				    !compare_hash_inputs(&(*rthp)->fl,
+							 &rth->fl))
+					length += ONE;
 				continue;
 			}
 
@@ -802,6 +852,15 @@
 			rt_free(rth);
 		}
 		spin_unlock_bh(rt_hash_lock_addr(i));
+		sum += length;
+		sum2 += length*length;
+	}
+	if (samples) {
+		unsigned long avg = sum / samples;
+		unsigned long sd = int_sqrt(sum2 / samples - avg*avg);
+		rt_chain_length_max = max_t(unsigned long,
+					ip_rt_gc_elasticity,
+					(avg + 4*sd) >> FRACT_BITS);
 	}
 	rover = i;
 }
@@ -851,6 +910,26 @@
 	mod_timer(&net->ipv4.rt_secret_timer, jiffies + ip_rt_secret_interval);
 }
 
+static void rt_secret_rebuild_oneshot(struct net *net)
+{
+	del_timer_sync(&net->ipv4.rt_secret_timer);
+	rt_cache_invalidate(net);
+	if (ip_rt_secret_interval) {
+		net->ipv4.rt_secret_timer.expires += ip_rt_secret_interval;
+		add_timer(&net->ipv4.rt_secret_timer);
+	}
+}
+
+static void rt_emergency_hash_rebuild(struct net *net)
+{
+	if (net_ratelimit()) {
+		printk(KERN_WARNING "Route hash chain too long!\n");
+		printk(KERN_WARNING "Adjust your secret_interval!\n");
+	}
+
+	rt_secret_rebuild_oneshot(net);
+}
+
 /*
    Short description of GC goals.
 
@@ -989,6 +1068,7 @@
 static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp)
 {
 	struct rtable	*rth, **rthp;
+	struct rtable	*rthi;
 	unsigned long	now;
 	struct rtable *cand, **candp;
 	u32 		min_score;
@@ -1002,7 +1082,13 @@
 	candp = NULL;
 	now = jiffies;
 
+	if (!rt_caching(dev_net(rt->u.dst.dev))) {
+		rt_drop(rt);
+		return 0;
+	}
+
 	rthp = &rt_hash_table[hash].chain;
+	rthi = NULL;
 
 	spin_lock_bh(rt_hash_lock_addr(hash));
 	while ((rth = *rthp) != NULL) {
@@ -1048,6 +1134,17 @@
 		chain_length++;
 
 		rthp = &rth->u.dst.rt_next;
+
+		/*
+		 * check to see if the next entry in the chain
+		 * contains the same hash input values as rt.  If it does
+		 * This is where we will insert into the list, instead of
+		 * at the head.  This groups entries that differ by aspects not
+		 * relvant to the hash function together, which we use to adjust
+		 * our chain length
+		 */
+		if (*rthp && compare_hash_inputs(&(*rthp)->fl, &rt->fl))
+			rthi = rth;
 	}
 
 	if (cand) {
@@ -1061,6 +1158,16 @@
 			*candp = cand->u.dst.rt_next;
 			rt_free(cand);
 		}
+	} else {
+		if (chain_length > rt_chain_length_max) {
+			struct net *net = dev_net(rt->u.dst.dev);
+			int num = ++net->ipv4.current_rt_cache_rebuild_count;
+			if (!rt_caching(dev_net(rt->u.dst.dev))) {
+				printk(KERN_WARNING "%s: %d rebuilds is over limit, route caching disabled\n",
+					rt->u.dst.dev->name, num);
+			}
+			rt_emergency_hash_rebuild(dev_net(rt->u.dst.dev));
+		}
 	}
 
 	/* Try to bind route to arp only if it is output
@@ -1098,14 +1205,17 @@
 		}
 	}
 
-	rt->u.dst.rt_next = rt_hash_table[hash].chain;
+	if (rthi)
+		rt->u.dst.rt_next = rthi->u.dst.rt_next;
+	else
+		rt->u.dst.rt_next = rt_hash_table[hash].chain;
+
 #if RT_CACHE_DEBUG >= 2
 	if (rt->u.dst.rt_next) {
 		struct rtable *trt;
-		printk(KERN_DEBUG "rt_cache @%02x: " NIPQUAD_FMT, hash,
-		       NIPQUAD(rt->rt_dst));
+		printk(KERN_DEBUG "rt_cache @%02x: %pI4", hash, &rt->rt_dst);
 		for (trt = rt->u.dst.rt_next; trt; trt = trt->u.dst.rt_next)
-			printk(" . " NIPQUAD_FMT, NIPQUAD(trt->rt_dst));
+			printk(" . %pI4", &trt->rt_dst);
 		printk("\n");
 	}
 #endif
@@ -1114,7 +1224,11 @@
 	 * previous writes to rt are comitted to memory
 	 * before making rt visible to other CPUS.
 	 */
-	rcu_assign_pointer(rt_hash_table[hash].chain, rt);
+	if (rthi)
+		rcu_assign_pointer(rthi->u.dst.rt_next, rt);
+	else
+		rcu_assign_pointer(rt_hash_table[hash].chain, rt);
+
 	spin_unlock_bh(rt_hash_lock_addr(hash));
 	*rp = rt;
 	return 0;
@@ -1217,6 +1331,9 @@
 	    || ipv4_is_zeronet(new_gw))
 		goto reject_redirect;
 
+	if (!rt_caching(net))
+		goto reject_redirect;
+
 	if (!IN_DEV_SHARED_MEDIA(in_dev)) {
 		if (!inet_addr_onlink(in_dev, new_gw, old_gw))
 			goto reject_redirect;
@@ -1267,7 +1384,6 @@
 
 				/* Copy all the information. */
 				*rt = *rth;
-				INIT_RCU_HEAD(&rt->u.dst.rcu_head);
 				rt->u.dst.__use		= 1;
 				atomic_set(&rt->u.dst.__refcnt, 1);
 				rt->u.dst.child		= NULL;
@@ -1280,7 +1396,9 @@
 				rt->u.dst.path		= &rt->u.dst;
 				rt->u.dst.neighbour	= NULL;
 				rt->u.dst.hh		= NULL;
+#ifdef CONFIG_XFRM
 				rt->u.dst.xfrm		= NULL;
+#endif
 				rt->rt_genid		= rt_genid(net);
 				rt->rt_flags		|= RTCF_REDIRECTED;
 
@@ -1324,11 +1442,10 @@
 reject_redirect:
 #ifdef CONFIG_IP_ROUTE_VERBOSE
 	if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
-		printk(KERN_INFO "Redirect from " NIPQUAD_FMT " on %s about "
-			NIPQUAD_FMT " ignored.\n"
-			"  Advised path = " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
-		       NIPQUAD(old_gw), dev->name, NIPQUAD(new_gw),
-		       NIPQUAD(saddr), NIPQUAD(daddr));
+		printk(KERN_INFO "Redirect from %pI4 on %s about %pI4 ignored.\n"
+			"  Advised path = %pI4 -> %pI4\n",
+		       &old_gw, dev->name, &new_gw,
+		       &saddr, &daddr);
 #endif
 	in_dev_put(in_dev);
 }
@@ -1348,9 +1465,8 @@
 						rt->fl.oif,
 						rt_genid(dev_net(dst->dev)));
 #if RT_CACHE_DEBUG >= 1
-			printk(KERN_DEBUG "ipv4_negative_advice: redirect to "
-					  NIPQUAD_FMT "/%02x dropped\n",
-				NIPQUAD(rt->rt_dst), rt->fl.fl4_tos);
+			printk(KERN_DEBUG "ipv4_negative_advice: redirect to %pI4/%02x dropped\n",
+				&rt->rt_dst, rt->fl.fl4_tos);
 #endif
 			rt_del(hash, rt);
 			ret = NULL;
@@ -1414,10 +1530,9 @@
 		if (IN_DEV_LOG_MARTIANS(in_dev) &&
 		    rt->u.dst.rate_tokens == ip_rt_redirect_number &&
 		    net_ratelimit())
-			printk(KERN_WARNING "host " NIPQUAD_FMT "/if%d ignores "
-				"redirects for " NIPQUAD_FMT " to " NIPQUAD_FMT ".\n",
-				NIPQUAD(rt->rt_src), rt->rt_iif,
-				NIPQUAD(rt->rt_dst), NIPQUAD(rt->rt_gateway));
+			printk(KERN_WARNING "host %pI4/if%d ignores redirects for %pI4 to %pI4.\n",
+				&rt->rt_src, rt->rt_iif,
+				&rt->rt_dst, &rt->rt_gateway);
 #endif
 	}
 out:
@@ -1610,8 +1725,8 @@
 
 static int ip_rt_bug(struct sk_buff *skb)
 {
-	printk(KERN_DEBUG "ip_rt_bug: " NIPQUAD_FMT " -> " NIPQUAD_FMT ", %s\n",
-		NIPQUAD(ip_hdr(skb)->saddr), NIPQUAD(ip_hdr(skb)->daddr),
+	printk(KERN_DEBUG "ip_rt_bug: %pI4 -> %pI4, %s\n",
+		&ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr,
 		skb->dev ? skb->dev->name : "?");
 	kfree_skb(skb);
 	return 0;
@@ -1788,9 +1903,8 @@
 		 *	RFC1812 recommendation, if source is martian,
 		 *	the only hint is MAC header.
 		 */
-		printk(KERN_WARNING "martian source " NIPQUAD_FMT " from "
-			NIPQUAD_FMT", on dev %s\n",
-			NIPQUAD(daddr), NIPQUAD(saddr), dev->name);
+		printk(KERN_WARNING "martian source %pI4 from %pI4, on dev %s\n",
+			&daddr, &saddr, dev->name);
 		if (dev->hard_header_len && skb_mac_header_was_set(skb)) {
 			int i;
 			const unsigned char *p = skb_mac_header(skb);
@@ -2099,9 +2213,8 @@
 	RT_CACHE_STAT_INC(in_martian_dst);
 #ifdef CONFIG_IP_ROUTE_VERBOSE
 	if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
-		printk(KERN_WARNING "martian destination " NIPQUAD_FMT " from "
-			NIPQUAD_FMT ", dev %s\n",
-			NIPQUAD(daddr), NIPQUAD(saddr), dev->name);
+		printk(KERN_WARNING "martian destination %pI4 from %pI4, dev %s\n",
+			&daddr, &saddr, dev->name);
 #endif
 
 e_hostunreach:
@@ -2130,6 +2243,10 @@
 	struct net *net;
 
 	net = dev_net(dev);
+
+	if (!rt_caching(net))
+		goto skip_cache;
+
 	tos &= IPTOS_RT_MASK;
 	hash = rt_hash(daddr, saddr, iif, rt_genid(net));
 
@@ -2154,6 +2271,7 @@
 	}
 	rcu_read_unlock();
 
+skip_cache:
 	/* Multicast recognition logic is moved from route cache to here.
 	   The problem was that too many Ethernet cards have broken/missing
 	   hardware multicast filters :-( As result the host on multicasting
@@ -2539,6 +2657,9 @@
 	unsigned hash;
 	struct rtable *rth;
 
+	if (!rt_caching(net))
+		goto slow_output;
+
 	hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif, rt_genid(net));
 
 	rcu_read_lock_bh();
@@ -2563,6 +2684,7 @@
 	}
 	rcu_read_unlock_bh();
 
+slow_output:
 	return ip_route_output_slow(net, rp, flp);
 }
 
@@ -2578,7 +2700,6 @@
 	.destroy		=	ipv4_dst_destroy,
 	.check			=	ipv4_dst_check,
 	.update_pmtu		=	ipv4_rt_blackhole_update_pmtu,
-	.entry_size		=	sizeof(struct rtable),
 	.entries		=	ATOMIC_INIT(0),
 };
 
@@ -2640,7 +2761,7 @@
 			flp->fl4_src = (*rp)->rt_src;
 		if (!flp->fl4_dst)
 			flp->fl4_dst = (*rp)->rt_dst;
-		err = __xfrm_lookup((struct dst_entry **)rp, flp, sk,
+		err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk,
 				    flags ? XFRM_LOOKUP_WAIT : 0);
 		if (err == -EREMOTE)
 			err = ipv4_dst_blackhole(net, rp, flp);
@@ -2995,7 +3116,7 @@
 		.data		= &ipv4_dst_ops.gc_thresh,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_MAX_SIZE,
@@ -3003,7 +3124,7 @@
 		.data		= &ip_rt_max_size,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		/*  Deprecated. Use gc_min_interval_ms */
@@ -3013,8 +3134,8 @@
 		.data		= &ip_rt_gc_min_interval,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS,
@@ -3022,8 +3143,8 @@
 		.data		= &ip_rt_gc_min_interval,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_ms_jiffies,
-		.strategy	= &sysctl_ms_jiffies,
+		.proc_handler	= proc_dointvec_ms_jiffies,
+		.strategy	= sysctl_ms_jiffies,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_GC_TIMEOUT,
@@ -3031,8 +3152,8 @@
 		.data		= &ip_rt_gc_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_GC_INTERVAL,
@@ -3040,8 +3161,8 @@
 		.data		= &ip_rt_gc_interval,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_REDIRECT_LOAD,
@@ -3049,7 +3170,7 @@
 		.data		= &ip_rt_redirect_load,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_REDIRECT_NUMBER,
@@ -3057,7 +3178,7 @@
 		.data		= &ip_rt_redirect_number,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_REDIRECT_SILENCE,
@@ -3065,7 +3186,7 @@
 		.data		= &ip_rt_redirect_silence,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_ERROR_COST,
@@ -3073,7 +3194,7 @@
 		.data		= &ip_rt_error_cost,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_ERROR_BURST,
@@ -3081,7 +3202,7 @@
 		.data		= &ip_rt_error_burst,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_GC_ELASTICITY,
@@ -3089,7 +3210,7 @@
 		.data		= &ip_rt_gc_elasticity,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_MTU_EXPIRES,
@@ -3097,8 +3218,8 @@
 		.data		= &ip_rt_mtu_expires,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_MIN_PMTU,
@@ -3106,7 +3227,7 @@
 		.data		= &ip_rt_min_pmtu,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_MIN_ADVMSS,
@@ -3114,7 +3235,7 @@
 		.data		= &ip_rt_min_advmss,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_ROUTE_SECRET_INTERVAL,
@@ -3122,8 +3243,8 @@
 		.data		= &ip_rt_secret_interval,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &ipv4_sysctl_rt_secret_interval,
-		.strategy	= &ipv4_sysctl_rt_secret_interval_strategy,
+		.proc_handler	= ipv4_sysctl_rt_secret_interval,
+		.strategy	= ipv4_sysctl_rt_secret_interval_strategy,
 	},
 	{ .ctl_name = 0 }
 };
@@ -3151,8 +3272,8 @@
 		.procname	= "flush",
 		.maxlen		= sizeof(int),
 		.mode		= 0200,
-		.proc_handler	= &ipv4_sysctl_rtcache_flush,
-		.strategy	= &ipv4_sysctl_rtcache_flush_strategy,
+		.proc_handler	= ipv4_sysctl_rtcache_flush,
+		.strategy	= ipv4_sysctl_rtcache_flush_strategy,
 	},
 	{ .ctl_name = 0 },
 };
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 1bb10df..4710d21 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -195,7 +195,7 @@
 		.data		= &sysctl_tcp_timestamps,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_TCP_WINDOW_SCALING,
@@ -203,7 +203,7 @@
 		.data		= &sysctl_tcp_window_scaling,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_TCP_SACK,
@@ -211,7 +211,7 @@
 		.data		= &sysctl_tcp_sack,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_TCP_RETRANS_COLLAPSE,
@@ -219,7 +219,7 @@
 		.data		= &sysctl_tcp_retrans_collapse,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_DEFAULT_TTL,
@@ -227,8 +227,8 @@
 		.data		= &sysctl_ip_default_ttl,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &ipv4_doint_and_flush,
-		.strategy	= &ipv4_doint_and_flush_strategy,
+		.proc_handler	= ipv4_doint_and_flush,
+		.strategy	= ipv4_doint_and_flush_strategy,
 		.extra2		= &init_net,
 	},
 	{
@@ -237,7 +237,7 @@
 		.data		= &ipv4_config.no_pmtu_disc,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_NONLOCAL_BIND,
@@ -245,7 +245,7 @@
 		.data		= &sysctl_ip_nonlocal_bind,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_TCP_SYN_RETRIES,
@@ -253,7 +253,7 @@
 		.data		= &sysctl_tcp_syn_retries,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_SYNACK_RETRIES,
@@ -261,7 +261,7 @@
 		.data		= &sysctl_tcp_synack_retries,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_MAX_ORPHANS,
@@ -269,7 +269,7 @@
 		.data		= &sysctl_tcp_max_orphans,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_MAX_TW_BUCKETS,
@@ -277,7 +277,7 @@
 		.data		= &tcp_death_row.sysctl_max_tw_buckets,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_DYNADDR,
@@ -285,7 +285,7 @@
 		.data		= &sysctl_ip_dynaddr,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_TCP_KEEPALIVE_TIME,
@@ -293,8 +293,8 @@
 		.data		= &sysctl_tcp_keepalive_time,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies
 	},
 	{
 		.ctl_name	= NET_IPV4_TCP_KEEPALIVE_PROBES,
@@ -302,7 +302,7 @@
 		.data		= &sysctl_tcp_keepalive_probes,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_TCP_KEEPALIVE_INTVL,
@@ -310,8 +310,8 @@
 		.data		= &sysctl_tcp_keepalive_intvl,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies
 	},
 	{
 		.ctl_name	= NET_IPV4_TCP_RETRIES1,
@@ -319,8 +319,8 @@
 		.data		= &sysctl_tcp_retries1,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra2		= &tcp_retr1_max
 	},
 	{
@@ -329,7 +329,7 @@
 		.data		= &sysctl_tcp_retries2,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_TCP_FIN_TIMEOUT,
@@ -337,8 +337,8 @@
 		.data		= &sysctl_tcp_fin_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies
 	},
 #ifdef CONFIG_SYN_COOKIES
 	{
@@ -347,7 +347,7 @@
 		.data		= &sysctl_tcp_syncookies,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 #endif
 	{
@@ -356,7 +356,7 @@
 		.data		= &tcp_death_row.sysctl_tw_recycle,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_ABORT_ON_OVERFLOW,
@@ -364,7 +364,7 @@
 		.data		= &sysctl_tcp_abort_on_overflow,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_STDURG,
@@ -372,7 +372,7 @@
 		.data		= &sysctl_tcp_stdurg,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_RFC1337,
@@ -380,7 +380,7 @@
 		.data		= &sysctl_tcp_rfc1337,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_MAX_SYN_BACKLOG,
@@ -388,7 +388,7 @@
 		.data		= &sysctl_max_syn_backlog,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_LOCAL_PORT_RANGE,
@@ -396,8 +396,8 @@
 		.data		= &sysctl_local_ports.range,
 		.maxlen		= sizeof(sysctl_local_ports.range),
 		.mode		= 0644,
-		.proc_handler	= &ipv4_local_port_range,
-		.strategy	= &ipv4_sysctl_local_port_range,
+		.proc_handler	= ipv4_local_port_range,
+		.strategy	= ipv4_sysctl_local_port_range,
 	},
 #ifdef CONFIG_IP_MULTICAST
 	{
@@ -406,7 +406,7 @@
 		.data		= &sysctl_igmp_max_memberships,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 
 #endif
@@ -416,7 +416,7 @@
 		.data		= &sysctl_igmp_max_msf,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_INET_PEER_THRESHOLD,
@@ -424,7 +424,7 @@
 		.data		= &inet_peer_threshold,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_INET_PEER_MINTTL,
@@ -432,8 +432,8 @@
 		.data		= &inet_peer_minttl,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies
 	},
 	{
 		.ctl_name	= NET_IPV4_INET_PEER_MAXTTL,
@@ -441,8 +441,8 @@
 		.data		= &inet_peer_maxttl,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies
 	},
 	{
 		.ctl_name	= NET_IPV4_INET_PEER_GC_MINTIME,
@@ -450,8 +450,8 @@
 		.data		= &inet_peer_gc_mintime,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies
 	},
 	{
 		.ctl_name	= NET_IPV4_INET_PEER_GC_MAXTIME,
@@ -459,8 +459,8 @@
 		.data		= &inet_peer_gc_maxtime,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies
 	},
 	{
 		.ctl_name	= NET_TCP_ORPHAN_RETRIES,
@@ -468,7 +468,7 @@
 		.data		= &sysctl_tcp_orphan_retries,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_FACK,
@@ -476,7 +476,7 @@
 		.data		= &sysctl_tcp_fack,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_REORDERING,
@@ -484,7 +484,7 @@
 		.data		= &sysctl_tcp_reordering,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_ECN,
@@ -492,7 +492,7 @@
 		.data		= &sysctl_tcp_ecn,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_DSACK,
@@ -500,7 +500,7 @@
 		.data		= &sysctl_tcp_dsack,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_MEM,
@@ -508,7 +508,7 @@
 		.data		= &sysctl_tcp_mem,
 		.maxlen		= sizeof(sysctl_tcp_mem),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_WMEM,
@@ -516,7 +516,7 @@
 		.data		= &sysctl_tcp_wmem,
 		.maxlen		= sizeof(sysctl_tcp_wmem),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_RMEM,
@@ -524,7 +524,7 @@
 		.data		= &sysctl_tcp_rmem,
 		.maxlen		= sizeof(sysctl_tcp_rmem),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_APP_WIN,
@@ -532,7 +532,7 @@
 		.data		= &sysctl_tcp_app_win,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_ADV_WIN_SCALE,
@@ -540,7 +540,7 @@
 		.data		= &sysctl_tcp_adv_win_scale,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_TW_REUSE,
@@ -548,7 +548,7 @@
 		.data		= &sysctl_tcp_tw_reuse,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_FRTO,
@@ -556,7 +556,7 @@
 		.data		= &sysctl_tcp_frto,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_FRTO_RESPONSE,
@@ -564,7 +564,7 @@
 		.data		= &sysctl_tcp_frto_response,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_LOW_LATENCY,
@@ -572,7 +572,7 @@
 		.data		= &sysctl_tcp_low_latency,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_TCP_NO_METRICS_SAVE,
@@ -580,7 +580,7 @@
 		.data		= &sysctl_tcp_nometrics_save,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_TCP_MODERATE_RCVBUF,
@@ -588,7 +588,7 @@
 		.data		= &sysctl_tcp_moderate_rcvbuf,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_TCP_TSO_WIN_DIVISOR,
@@ -596,15 +596,15 @@
 		.data		= &sysctl_tcp_tso_win_divisor,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_TCP_CONG_CONTROL,
 		.procname	= "tcp_congestion_control",
 		.mode		= 0644,
 		.maxlen		= TCP_CA_NAME_MAX,
-		.proc_handler	= &proc_tcp_congestion_control,
-		.strategy	= &sysctl_tcp_congestion_control,
+		.proc_handler	= proc_tcp_congestion_control,
+		.strategy	= sysctl_tcp_congestion_control,
 	},
 	{
 		.ctl_name	= NET_TCP_ABC,
@@ -612,7 +612,7 @@
 		.data		= &sysctl_tcp_abc,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_TCP_MTU_PROBING,
@@ -620,7 +620,7 @@
 		.data		= &sysctl_tcp_mtu_probing,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_TCP_BASE_MSS,
@@ -628,7 +628,7 @@
 		.data		= &sysctl_tcp_base_mss,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS,
@@ -636,7 +636,7 @@
 		.data		= &sysctl_tcp_workaround_signed_windows,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 #ifdef CONFIG_NET_DMA
 	{
@@ -645,7 +645,7 @@
 		.data		= &sysctl_tcp_dma_copybreak,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 #endif
 	{
@@ -654,7 +654,7 @@
 		.data		= &sysctl_tcp_slow_start_after_idle,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 #ifdef CONFIG_NETLABEL
 	{
@@ -663,7 +663,7 @@
 		.data		= &cipso_v4_cache_enabled,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_CIPSOV4_CACHE_BUCKET_SIZE,
@@ -671,7 +671,7 @@
 		.data		= &cipso_v4_cache_bucketsize,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_CIPSOV4_RBM_OPTFMT,
@@ -679,7 +679,7 @@
 		.data		= &cipso_v4_rbm_optfmt,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_CIPSOV4_RBM_STRICTVALID,
@@ -687,22 +687,22 @@
 		.data		= &cipso_v4_rbm_strictvalid,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 #endif /* CONFIG_NETLABEL */
 	{
 		.procname	= "tcp_available_congestion_control",
 		.maxlen		= TCP_CA_BUF_MAX,
 		.mode		= 0444,
-		.proc_handler   = &proc_tcp_available_congestion_control,
+		.proc_handler   = proc_tcp_available_congestion_control,
 	},
 	{
 		.ctl_name	= NET_TCP_ALLOWED_CONG_CONTROL,
 		.procname	= "tcp_allowed_congestion_control",
 		.maxlen		= TCP_CA_BUF_MAX,
 		.mode		= 0644,
-		.proc_handler   = &proc_allowed_congestion_control,
-		.strategy	= &strategy_allowed_congestion_control,
+		.proc_handler   = proc_allowed_congestion_control,
+		.strategy	= strategy_allowed_congestion_control,
 	},
 	{
 		.ctl_name	= NET_TCP_MAX_SSTHRESH,
@@ -710,7 +710,7 @@
 		.data		= &sysctl_tcp_max_ssthresh,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= CTL_UNNUMBERED,
@@ -718,8 +718,8 @@
 		.data		= &sysctl_udp_mem,
 		.maxlen		= sizeof(sysctl_udp_mem),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &zero
 	},
 	{
@@ -728,8 +728,8 @@
 		.data		= &sysctl_udp_rmem_min,
 		.maxlen		= sizeof(sysctl_udp_rmem_min),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &zero
 	},
 	{
@@ -738,8 +738,8 @@
 		.data		= &sysctl_udp_wmem_min,
 		.maxlen		= sizeof(sysctl_udp_wmem_min),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &zero
 	},
 	{ .ctl_name = 0 }
@@ -752,7 +752,7 @@
 		.data		= &init_net.ipv4.sysctl_icmp_echo_ignore_all,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS,
@@ -760,7 +760,7 @@
 		.data		= &init_net.ipv4.sysctl_icmp_echo_ignore_broadcasts,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES,
@@ -768,7 +768,7 @@
 		.data		= &init_net.ipv4.sysctl_icmp_ignore_bogus_error_responses,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,
@@ -776,7 +776,7 @@
 		.data		= &init_net.ipv4.sysctl_icmp_errors_use_inbound_ifaddr,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV4_ICMP_RATELIMIT,
@@ -784,8 +784,8 @@
 		.data		= &init_net.ipv4.sysctl_icmp_ratelimit,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_ms_jiffies,
-		.strategy	= &sysctl_ms_jiffies
+		.proc_handler	= proc_dointvec_ms_jiffies,
+		.strategy	= sysctl_ms_jiffies
 	},
 	{
 		.ctl_name	= NET_IPV4_ICMP_RATEMASK,
@@ -793,7 +793,15 @@
 		.data		= &init_net.ipv4.sysctl_icmp_ratemask,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
+	},
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "rt_cache_rebuild_count",
+		.data		= &init_net.ipv4.sysctl_rt_cache_rebuild_count,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
 	},
 	{ }
 };
@@ -827,8 +835,12 @@
 			&net->ipv4.sysctl_icmp_ratelimit;
 		table[5].data =
 			&net->ipv4.sysctl_icmp_ratemask;
+		table[6].data =
+			&net->ipv4.sysctl_rt_cache_rebuild_count;
 	}
 
+	net->ipv4.sysctl_rt_cache_rebuild_count = 4;
+
 	net->ipv4.ipv4_hdr = register_net_sysctl_table(net,
 			net_ipv4_ctl_path, table);
 	if (net->ipv4.ipv4_hdr == NULL)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index c5aca0b..1f3d529 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -277,8 +277,7 @@
 
 int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT;
 
-atomic_t tcp_orphan_count = ATOMIC_INIT(0);
-
+struct percpu_counter tcp_orphan_count;
 EXPORT_SYMBOL_GPL(tcp_orphan_count);
 
 int sysctl_tcp_mem[3] __read_mostly;
@@ -290,9 +289,12 @@
 EXPORT_SYMBOL(sysctl_tcp_wmem);
 
 atomic_t tcp_memory_allocated;	/* Current allocated memory. */
-atomic_t tcp_sockets_allocated;	/* Current number of TCP sockets. */
-
 EXPORT_SYMBOL(tcp_memory_allocated);
+
+/*
+ * Current number of TCP sockets.
+ */
+struct percpu_counter tcp_sockets_allocated;
 EXPORT_SYMBOL(tcp_sockets_allocated);
 
 /*
@@ -1680,7 +1682,7 @@
 			inet_put_port(sk);
 		/* fall through */
 	default:
-		if (oldstate==TCP_ESTABLISHED)
+		if (oldstate == TCP_ESTABLISHED)
 			TCP_DEC_STATS(sock_net(sk), TCP_MIB_CURRESTAB);
 	}
 
@@ -1690,7 +1692,7 @@
 	sk->sk_state = state;
 
 #ifdef STATE_TRACE
-	SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n",sk, statename[oldstate],statename[state]);
+	SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n", sk, statename[oldstate], statename[state]);
 #endif
 }
 EXPORT_SYMBOL_GPL(tcp_set_state);
@@ -1834,7 +1836,7 @@
 	state = sk->sk_state;
 	sock_hold(sk);
 	sock_orphan(sk);
-	atomic_inc(sk->sk_prot->orphan_count);
+	percpu_counter_inc(sk->sk_prot->orphan_count);
 
 	/* It is the last release_sock in its life. It will remove backlog. */
 	release_sock(sk);
@@ -1885,9 +1887,11 @@
 		}
 	}
 	if (sk->sk_state != TCP_CLOSE) {
+		int orphan_count = percpu_counter_read_positive(
+						sk->sk_prot->orphan_count);
+
 		sk_mem_reclaim(sk);
-		if (tcp_too_many_orphans(sk,
-				atomic_read(sk->sk_prot->orphan_count))) {
+		if (tcp_too_many_orphans(sk, orphan_count)) {
 			if (net_ratelimit())
 				printk(KERN_INFO "TCP: too many of orphaned "
 				       "sockets\n");
@@ -2461,6 +2465,106 @@
 }
 EXPORT_SYMBOL(tcp_tso_segment);
 
+struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb)
+{
+	struct sk_buff **pp = NULL;
+	struct sk_buff *p;
+	struct tcphdr *th;
+	struct tcphdr *th2;
+	unsigned int thlen;
+	unsigned int flags;
+	unsigned int total;
+	unsigned int mss = 1;
+	int flush = 1;
+
+	if (!pskb_may_pull(skb, sizeof(*th)))
+		goto out;
+
+	th = tcp_hdr(skb);
+	thlen = th->doff * 4;
+	if (thlen < sizeof(*th))
+		goto out;
+
+	if (!pskb_may_pull(skb, thlen))
+		goto out;
+
+	th = tcp_hdr(skb);
+	__skb_pull(skb, thlen);
+
+	flags = tcp_flag_word(th);
+
+	for (; (p = *head); head = &p->next) {
+		if (!NAPI_GRO_CB(p)->same_flow)
+			continue;
+
+		th2 = tcp_hdr(p);
+
+		if (th->source != th2->source || th->dest != th2->dest) {
+			NAPI_GRO_CB(p)->same_flow = 0;
+			continue;
+		}
+
+		goto found;
+	}
+
+	goto out_check_final;
+
+found:
+	flush = NAPI_GRO_CB(p)->flush;
+	flush |= flags & TCP_FLAG_CWR;
+	flush |= (flags ^ tcp_flag_word(th2)) &
+		  ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH);
+	flush |= th->ack_seq != th2->ack_seq || th->window != th2->window;
+	flush |= memcmp(th + 1, th2 + 1, thlen - sizeof(*th));
+
+	total = p->len;
+	mss = total;
+	if (skb_shinfo(p)->frag_list)
+		mss = skb_shinfo(p)->frag_list->len;
+
+	flush |= skb->len > mss || skb->len <= 0;
+	flush |= ntohl(th2->seq) + total != ntohl(th->seq);
+
+	if (flush || skb_gro_receive(head, skb)) {
+		mss = 1;
+		goto out_check_final;
+	}
+
+	p = *head;
+	th2 = tcp_hdr(p);
+	tcp_flag_word(th2) |= flags & (TCP_FLAG_FIN | TCP_FLAG_PSH);
+
+out_check_final:
+	flush = skb->len < mss;
+	flush |= flags & (TCP_FLAG_URG | TCP_FLAG_PSH | TCP_FLAG_RST |
+			  TCP_FLAG_SYN | TCP_FLAG_FIN);
+
+	if (p && (!NAPI_GRO_CB(skb)->same_flow || flush))
+		pp = head;
+
+out:
+	NAPI_GRO_CB(skb)->flush |= flush;
+
+	return pp;
+}
+
+int tcp_gro_complete(struct sk_buff *skb)
+{
+	struct tcphdr *th = tcp_hdr(skb);
+
+	skb->csum_start = skb_transport_header(skb) - skb->head;
+	skb->csum_offset = offsetof(struct tcphdr, check);
+	skb->ip_summed = CHECKSUM_PARTIAL;
+
+	skb_shinfo(skb)->gso_size = skb_shinfo(skb)->frag_list->len;
+	skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
+
+	if (th->cwr)
+		skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
+
+	return 0;
+}
+
 #ifdef CONFIG_TCP_MD5SIG
 static unsigned long tcp_md5sig_users;
 static struct tcp_md5sig_pool **tcp_md5sig_pool;
@@ -2650,7 +2754,7 @@
 
 void tcp_done(struct sock *sk)
 {
-	if(sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV)
+	if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV)
 		TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_ATTEMPTFAILS);
 
 	tcp_set_state(sk, TCP_CLOSE);
@@ -2685,6 +2789,8 @@
 
 	BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));
 
+	percpu_counter_init(&tcp_sockets_allocated, 0);
+	percpu_counter_init(&tcp_orphan_count, 0);
 	tcp_hashinfo.bind_bucket_cachep =
 		kmem_cache_create("tcp_bind_bucket",
 				  sizeof(struct inet_bind_bucket), 0,
@@ -2707,8 +2813,8 @@
 					thash_entries ? 0 : 512 * 1024);
 	tcp_hashinfo.ehash_size = 1 << tcp_hashinfo.ehash_size;
 	for (i = 0; i < tcp_hashinfo.ehash_size; i++) {
-		INIT_HLIST_HEAD(&tcp_hashinfo.ehash[i].chain);
-		INIT_HLIST_HEAD(&tcp_hashinfo.ehash[i].twchain);
+		INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i);
+		INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].twchain, i);
 	}
 	if (inet_ehash_locks_alloc(&tcp_hashinfo))
 		panic("TCP: failed to alloc ehash_locks");
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
index 4a1221e..ee467ec 100644
--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -1,13 +1,23 @@
 /*
- * TCP CUBIC: Binary Increase Congestion control for TCP v2.2
+ * TCP CUBIC: Binary Increase Congestion control for TCP v2.3
  * Home page:
  *      http://netsrv.csc.ncsu.edu/twiki/bin/view/Main/BIC
  * This is from the implementation of CUBIC TCP in
- * Injong Rhee, Lisong Xu.
- *  "CUBIC: A New TCP-Friendly High-Speed TCP Variant
- *  in PFLDnet 2005
+ * Sangtae Ha, Injong Rhee and Lisong Xu,
+ *  "CUBIC: A New TCP-Friendly High-Speed TCP Variant"
+ *  in ACM SIGOPS Operating System Review, July 2008.
  * Available from:
- *  http://netsrv.csc.ncsu.edu/export/cubic-paper.pdf
+ *  http://netsrv.csc.ncsu.edu/export/cubic_a_new_tcp_2008.pdf
+ *
+ * CUBIC integrates a new slow start algorithm, called HyStart.
+ * The details of HyStart are presented in
+ *  Sangtae Ha and Injong Rhee,
+ *  "Taming the Elephants: New TCP Slow Start", NCSU TechReport 2008.
+ * Available from:
+ *  http://netsrv.csc.ncsu.edu/export/hystart_techreport_2008.pdf
+ *
+ * All testing results are available from:
+ * http://netsrv.csc.ncsu.edu/wiki/index.php/TCP_Testing
  *
  * Unless CUBIC is enabled and congestion window is large
  * this behaves the same as the original Reno.
@@ -23,12 +33,26 @@
 					 */
 #define	BICTCP_HZ		10	/* BIC HZ 2^10 = 1024 */
 
+/* Two methods of hybrid slow start */
+#define HYSTART_ACK_TRAIN	0x1
+#define HYSTART_DELAY		0x2
+
+/* Number of delay samples for detecting the increase of delay */
+#define HYSTART_MIN_SAMPLES	8
+#define HYSTART_DELAY_MIN	(2U<<3)
+#define HYSTART_DELAY_MAX	(16U<<3)
+#define HYSTART_DELAY_THRESH(x)	clamp(x, HYSTART_DELAY_MIN, HYSTART_DELAY_MAX)
+
 static int fast_convergence __read_mostly = 1;
 static int beta __read_mostly = 717;	/* = 717/1024 (BICTCP_BETA_SCALE) */
 static int initial_ssthresh __read_mostly;
 static int bic_scale __read_mostly = 41;
 static int tcp_friendliness __read_mostly = 1;
 
+static int hystart __read_mostly = 1;
+static int hystart_detect __read_mostly = HYSTART_ACK_TRAIN | HYSTART_DELAY;
+static int hystart_low_window __read_mostly = 16;
+
 static u32 cube_rtt_scale __read_mostly;
 static u32 beta_scale __read_mostly;
 static u64 cube_factor __read_mostly;
@@ -44,6 +68,13 @@
 MODULE_PARM_DESC(bic_scale, "scale (scaled by 1024) value for bic function (bic_scale/1024)");
 module_param(tcp_friendliness, int, 0644);
 MODULE_PARM_DESC(tcp_friendliness, "turn on/off tcp friendliness");
+module_param(hystart, int, 0644);
+MODULE_PARM_DESC(hystart, "turn on/off hybrid slow start algorithm");
+module_param(hystart_detect, int, 0644);
+MODULE_PARM_DESC(hystart_detect, "hyrbrid slow start detection mechanisms"
+		 " 1: packet-train 2: delay 3: both packet-train and delay");
+module_param(hystart_low_window, int, 0644);
+MODULE_PARM_DESC(hystart_low_window, "lower bound cwnd for hybrid slow start");
 
 /* BIC TCP Parameters */
 struct bictcp {
@@ -59,7 +90,13 @@
 	u32	ack_cnt;	/* number of acks */
 	u32	tcp_cwnd;	/* estimated tcp cwnd */
 #define ACK_RATIO_SHIFT	4
-	u32	delayed_ack;	/* estimate the ratio of Packets/ACKs << 4 */
+	u16	delayed_ack;	/* estimate the ratio of Packets/ACKs << 4 */
+	u8	sample_cnt;	/* number of samples to decide curr_rtt */
+	u8	found;		/* the exit point is found? */
+	u32	round_start;	/* beginning of each round */
+	u32	end_seq;	/* end_seq of the round */
+	u32	last_jiffies;	/* last time when the ACK spacing is close */
+	u32	curr_rtt;	/* the minimum rtt of current round */
 };
 
 static inline void bictcp_reset(struct bictcp *ca)
@@ -76,12 +113,28 @@
 	ca->delayed_ack = 2 << ACK_RATIO_SHIFT;
 	ca->ack_cnt = 0;
 	ca->tcp_cwnd = 0;
+	ca->found = 0;
+}
+
+static inline void bictcp_hystart_reset(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct bictcp *ca = inet_csk_ca(sk);
+
+	ca->round_start = ca->last_jiffies = jiffies;
+	ca->end_seq = tp->snd_nxt;
+	ca->curr_rtt = 0;
+	ca->sample_cnt = 0;
 }
 
 static void bictcp_init(struct sock *sk)
 {
 	bictcp_reset(inet_csk_ca(sk));
-	if (initial_ssthresh)
+
+	if (hystart)
+		bictcp_hystart_reset(sk);
+
+	if (!hystart && initial_ssthresh)
 		tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
 }
 
@@ -235,9 +288,11 @@
 	if (!tcp_is_cwnd_limited(sk, in_flight))
 		return;
 
-	if (tp->snd_cwnd <= tp->snd_ssthresh)
+	if (tp->snd_cwnd <= tp->snd_ssthresh) {
+		if (hystart && after(ack, ca->end_seq))
+			bictcp_hystart_reset(sk);
 		tcp_slow_start(tp);
-	else {
+	} else {
 		bictcp_update(ca, tp->snd_cwnd);
 
 		/* In dangerous area, increase slowly.
@@ -281,8 +336,45 @@
 
 static void bictcp_state(struct sock *sk, u8 new_state)
 {
-	if (new_state == TCP_CA_Loss)
+	if (new_state == TCP_CA_Loss) {
 		bictcp_reset(inet_csk_ca(sk));
+		bictcp_hystart_reset(sk);
+	}
+}
+
+static void hystart_update(struct sock *sk, u32 delay)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct bictcp *ca = inet_csk_ca(sk);
+
+	if (!(ca->found & hystart_detect)) {
+		u32 curr_jiffies = jiffies;
+
+		/* first detection parameter - ack-train detection */
+		if (curr_jiffies - ca->last_jiffies <= msecs_to_jiffies(2)) {
+			ca->last_jiffies = curr_jiffies;
+			if (curr_jiffies - ca->round_start >= ca->delay_min>>4)
+				ca->found |= HYSTART_ACK_TRAIN;
+		}
+
+		/* obtain the minimum delay of more than sampling packets */
+		if (ca->sample_cnt < HYSTART_MIN_SAMPLES) {
+			if (ca->curr_rtt == 0 || ca->curr_rtt > delay)
+				ca->curr_rtt = delay;
+
+			ca->sample_cnt++;
+		} else {
+			if (ca->curr_rtt > ca->delay_min +
+			    HYSTART_DELAY_THRESH(ca->delay_min>>4))
+				ca->found |= HYSTART_DELAY;
+		}
+		/*
+		 * Either one of two conditions are met,
+		 * we exit from slow start immediately.
+		 */
+		if (ca->found & hystart_detect)
+			tp->snd_ssthresh = tp->snd_cwnd;
+	}
 }
 
 /* Track delayed acknowledgment ratio using sliding window
@@ -291,6 +383,7 @@
 static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt_us)
 {
 	const struct inet_connection_sock *icsk = inet_csk(sk);
+	const struct tcp_sock *tp = tcp_sk(sk);
 	struct bictcp *ca = inet_csk_ca(sk);
 	u32 delay;
 
@@ -314,6 +407,11 @@
 	/* first time call or link delay decreases */
 	if (ca->delay_min == 0 || ca->delay_min > delay)
 		ca->delay_min = delay;
+
+	/* hystart triggers when cwnd is larger than some threshold */
+	if (hystart && tp->snd_cwnd <= tp->snd_ssthresh &&
+	    tp->snd_cwnd >= hystart_low_window)
+		hystart_update(sk, delay);
 }
 
 static struct tcp_congestion_ops cubictcp = {
@@ -372,4 +470,4 @@
 MODULE_AUTHOR("Sangtae Ha, Stephen Hemminger");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("CUBIC TCP");
-MODULE_VERSION("2.2");
+MODULE_VERSION("2.3");
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 838d491..fcbcd4f 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -34,7 +34,7 @@
 		tcp_get_info(sk, info);
 }
 
-static struct inet_diag_handler tcp_diag_handler = {
+static const struct inet_diag_handler tcp_diag_handler = {
 	.idiag_hashinfo	 = &tcp_hashinfo,
 	.idiag_get_info	 = tcp_diag_get_info,
 	.idiag_type	 = TCPDIAG_GETSOCK,
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index d77c0d2..99b7ecb 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -701,13 +701,10 @@
 	 *    all the algo is pure shit and should be replaced
 	 *    with correct one. It is exactly, which we pretend to do.
 	 */
-}
 
-/* NOTE: clamping at TCP_RTO_MIN is not required, current algo
- * guarantees that rto is higher.
- */
-static inline void tcp_bound_rto(struct sock *sk)
-{
+	/* NOTE: clamping at TCP_RTO_MIN is not required, current algo
+	 * guarantees that rto is higher.
+	 */
 	if (inet_csk(sk)->icsk_rto > TCP_RTO_MAX)
 		inet_csk(sk)->icsk_rto = TCP_RTO_MAX;
 }
@@ -928,7 +925,6 @@
 		tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk));
 	}
 	tcp_set_rto(sk);
-	tcp_bound_rto(sk);
 	if (inet_csk(sk)->icsk_rto < TCP_TIMEOUT_INIT && !tp->rx_opt.saw_tstamp)
 		goto reset;
 	tp->snd_cwnd = tcp_init_cwnd(tp, dst);
@@ -1002,7 +998,8 @@
 	}
 }
 
-void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb)
+static void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp,
+					    struct sk_buff *skb)
 {
 	tcp_verify_retransmit_hint(tp, skb);
 
@@ -1236,31 +1233,58 @@
 	return dup_sack;
 }
 
+struct tcp_sacktag_state {
+	int reord;
+	int fack_count;
+	int flag;
+};
+
 /* Check if skb is fully within the SACK block. In presence of GSO skbs,
  * the incoming SACK may not exactly match but we can find smaller MSS
  * aligned portion of it that matches. Therefore we might need to fragment
  * which may fail and creates some hassle (caller must handle error case
  * returns).
+ *
+ * FIXME: this could be merged to shift decision code
  */
 static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
 				 u32 start_seq, u32 end_seq)
 {
 	int in_sack, err;
 	unsigned int pkt_len;
+	unsigned int mss;
 
 	in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
 		  !before(end_seq, TCP_SKB_CB(skb)->end_seq);
 
 	if (tcp_skb_pcount(skb) > 1 && !in_sack &&
 	    after(TCP_SKB_CB(skb)->end_seq, start_seq)) {
-
+		mss = tcp_skb_mss(skb);
 		in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq);
 
-		if (!in_sack)
+		if (!in_sack) {
 			pkt_len = start_seq - TCP_SKB_CB(skb)->seq;
-		else
+			if (pkt_len < mss)
+				pkt_len = mss;
+		} else {
 			pkt_len = end_seq - TCP_SKB_CB(skb)->seq;
-		err = tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size);
+			if (pkt_len < mss)
+				return -EINVAL;
+		}
+
+		/* Round if necessary so that SACKs cover only full MSSes
+		 * and/or the remaining small portion (if present)
+		 */
+		if (pkt_len > mss) {
+			unsigned int new_len = (pkt_len / mss) * mss;
+			if (!in_sack && new_len < pkt_len) {
+				new_len += mss;
+				if (new_len > skb->len)
+					return 0;
+			}
+			pkt_len = new_len;
+		}
+		err = tcp_fragment(sk, skb, pkt_len, mss);
 		if (err < 0)
 			return err;
 	}
@@ -1268,24 +1292,25 @@
 	return in_sack;
 }
 
-static int tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
-			   int *reord, int dup_sack, int fack_count)
+static u8 tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
+			  struct tcp_sacktag_state *state,
+			  int dup_sack, int pcount)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	u8 sacked = TCP_SKB_CB(skb)->sacked;
-	int flag = 0;
+	int fack_count = state->fack_count;
 
 	/* Account D-SACK for retransmitted packet. */
 	if (dup_sack && (sacked & TCPCB_RETRANS)) {
 		if (after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker))
 			tp->undo_retrans--;
 		if (sacked & TCPCB_SACKED_ACKED)
-			*reord = min(fack_count, *reord);
+			state->reord = min(fack_count, state->reord);
 	}
 
 	/* Nothing to do; acked frame is about to be dropped (was ACKed). */
 	if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
-		return flag;
+		return sacked;
 
 	if (!(sacked & TCPCB_SACKED_ACKED)) {
 		if (sacked & TCPCB_SACKED_RETRANS) {
@@ -1294,10 +1319,9 @@
 			 * that retransmission is still in flight.
 			 */
 			if (sacked & TCPCB_LOST) {
-				TCP_SKB_CB(skb)->sacked &=
-					~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
-				tp->lost_out -= tcp_skb_pcount(skb);
-				tp->retrans_out -= tcp_skb_pcount(skb);
+				sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
+				tp->lost_out -= pcount;
+				tp->retrans_out -= pcount;
 			}
 		} else {
 			if (!(sacked & TCPCB_RETRANS)) {
@@ -1306,56 +1330,280 @@
 				 */
 				if (before(TCP_SKB_CB(skb)->seq,
 					   tcp_highest_sack_seq(tp)))
-					*reord = min(fack_count, *reord);
+					state->reord = min(fack_count,
+							   state->reord);
 
 				/* SACK enhanced F-RTO (RFC4138; Appendix B) */
 				if (!after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark))
-					flag |= FLAG_ONLY_ORIG_SACKED;
+					state->flag |= FLAG_ONLY_ORIG_SACKED;
 			}
 
 			if (sacked & TCPCB_LOST) {
-				TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
-				tp->lost_out -= tcp_skb_pcount(skb);
+				sacked &= ~TCPCB_LOST;
+				tp->lost_out -= pcount;
 			}
 		}
 
-		TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
-		flag |= FLAG_DATA_SACKED;
-		tp->sacked_out += tcp_skb_pcount(skb);
+		sacked |= TCPCB_SACKED_ACKED;
+		state->flag |= FLAG_DATA_SACKED;
+		tp->sacked_out += pcount;
 
-		fack_count += tcp_skb_pcount(skb);
+		fack_count += pcount;
 
 		/* Lost marker hint past SACKed? Tweak RFC3517 cnt */
 		if (!tcp_is_fack(tp) && (tp->lost_skb_hint != NULL) &&
 		    before(TCP_SKB_CB(skb)->seq,
 			   TCP_SKB_CB(tp->lost_skb_hint)->seq))
-			tp->lost_cnt_hint += tcp_skb_pcount(skb);
+			tp->lost_cnt_hint += pcount;
 
 		if (fack_count > tp->fackets_out)
 			tp->fackets_out = fack_count;
-
-		if (!before(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp)))
-			tcp_advance_highest_sack(sk, skb);
 	}
 
 	/* D-SACK. We can detect redundant retransmission in S|R and plain R
 	 * frames and clear it. undo_retrans is decreased above, L|R frames
 	 * are accounted above as well.
 	 */
-	if (dup_sack && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)) {
-		TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
-		tp->retrans_out -= tcp_skb_pcount(skb);
+	if (dup_sack && (sacked & TCPCB_SACKED_RETRANS)) {
+		sacked &= ~TCPCB_SACKED_RETRANS;
+		tp->retrans_out -= pcount;
 	}
 
-	return flag;
+	return sacked;
+}
+
+static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
+			   struct tcp_sacktag_state *state,
+			   unsigned int pcount, int shifted, int mss)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct sk_buff *prev = tcp_write_queue_prev(sk, skb);
+
+	BUG_ON(!pcount);
+
+	/* Tweak before seqno plays */
+	if (!tcp_is_fack(tp) && tcp_is_sack(tp) && tp->lost_skb_hint &&
+	    !before(TCP_SKB_CB(tp->lost_skb_hint)->seq, TCP_SKB_CB(skb)->seq))
+		tp->lost_cnt_hint += pcount;
+
+	TCP_SKB_CB(prev)->end_seq += shifted;
+	TCP_SKB_CB(skb)->seq += shifted;
+
+	skb_shinfo(prev)->gso_segs += pcount;
+	BUG_ON(skb_shinfo(skb)->gso_segs < pcount);
+	skb_shinfo(skb)->gso_segs -= pcount;
+
+	/* When we're adding to gso_segs == 1, gso_size will be zero,
+	 * in theory this shouldn't be necessary but as long as DSACK
+	 * code can come after this skb later on it's better to keep
+	 * setting gso_size to something.
+	 */
+	if (!skb_shinfo(prev)->gso_size) {
+		skb_shinfo(prev)->gso_size = mss;
+		skb_shinfo(prev)->gso_type = sk->sk_gso_type;
+	}
+
+	/* CHECKME: To clear or not to clear? Mimics normal skb currently */
+	if (skb_shinfo(skb)->gso_segs <= 1) {
+		skb_shinfo(skb)->gso_size = 0;
+		skb_shinfo(skb)->gso_type = 0;
+	}
+
+	/* We discard results */
+	tcp_sacktag_one(skb, sk, state, 0, pcount);
+
+	/* Difference in this won't matter, both ACKed by the same cumul. ACK */
+	TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS);
+
+	if (skb->len > 0) {
+		BUG_ON(!tcp_skb_pcount(skb));
+		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SACKSHIFTED);
+		return 0;
+	}
+
+	/* Whole SKB was eaten :-) */
+
+	if (skb == tp->retransmit_skb_hint)
+		tp->retransmit_skb_hint = prev;
+	if (skb == tp->scoreboard_skb_hint)
+		tp->scoreboard_skb_hint = prev;
+	if (skb == tp->lost_skb_hint) {
+		tp->lost_skb_hint = prev;
+		tp->lost_cnt_hint -= tcp_skb_pcount(prev);
+	}
+
+	TCP_SKB_CB(skb)->flags |= TCP_SKB_CB(prev)->flags;
+	if (skb == tcp_highest_sack(sk))
+		tcp_advance_highest_sack(sk, skb);
+
+	tcp_unlink_write_queue(skb, sk);
+	sk_wmem_free_skb(sk, skb);
+
+	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SACKMERGED);
+
+	return 1;
+}
+
+/* I wish gso_size would have a bit more sane initialization than
+ * something-or-zero which complicates things
+ */
+static int tcp_skb_seglen(struct sk_buff *skb)
+{
+	return tcp_skb_pcount(skb) == 1 ? skb->len : tcp_skb_mss(skb);
+}
+
+/* Shifting pages past head area doesn't work */
+static int skb_can_shift(struct sk_buff *skb)
+{
+	return !skb_headlen(skb) && skb_is_nonlinear(skb);
+}
+
+/* Try collapsing SACK blocks spanning across multiple skbs to a single
+ * skb.
+ */
+static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
+					  struct tcp_sacktag_state *state,
+					  u32 start_seq, u32 end_seq,
+					  int dup_sack)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct sk_buff *prev;
+	int mss;
+	int pcount = 0;
+	int len;
+	int in_sack;
+
+	if (!sk_can_gso(sk))
+		goto fallback;
+
+	/* Normally R but no L won't result in plain S */
+	if (!dup_sack &&
+	    (TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_RETRANS)) == TCPCB_SACKED_RETRANS)
+		goto fallback;
+	if (!skb_can_shift(skb))
+		goto fallback;
+	/* This frame is about to be dropped (was ACKed). */
+	if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
+		goto fallback;
+
+	/* Can only happen with delayed DSACK + discard craziness */
+	if (unlikely(skb == tcp_write_queue_head(sk)))
+		goto fallback;
+	prev = tcp_write_queue_prev(sk, skb);
+
+	if ((TCP_SKB_CB(prev)->sacked & TCPCB_TAGBITS) != TCPCB_SACKED_ACKED)
+		goto fallback;
+
+	in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
+		  !before(end_seq, TCP_SKB_CB(skb)->end_seq);
+
+	if (in_sack) {
+		len = skb->len;
+		pcount = tcp_skb_pcount(skb);
+		mss = tcp_skb_seglen(skb);
+
+		/* TODO: Fix DSACKs to not fragment already SACKed and we can
+		 * drop this restriction as unnecessary
+		 */
+		if (mss != tcp_skb_seglen(prev))
+			goto fallback;
+	} else {
+		if (!after(TCP_SKB_CB(skb)->end_seq, start_seq))
+			goto noop;
+		/* CHECKME: This is non-MSS split case only?, this will
+		 * cause skipped skbs due to advancing loop btw, original
+		 * has that feature too
+		 */
+		if (tcp_skb_pcount(skb) <= 1)
+			goto noop;
+
+		in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq);
+		if (!in_sack) {
+			/* TODO: head merge to next could be attempted here
+			 * if (!after(TCP_SKB_CB(skb)->end_seq, end_seq)),
+			 * though it might not be worth of the additional hassle
+			 *
+			 * ...we can probably just fallback to what was done
+			 * previously. We could try merging non-SACKed ones
+			 * as well but it probably isn't going to buy off
+			 * because later SACKs might again split them, and
+			 * it would make skb timestamp tracking considerably
+			 * harder problem.
+			 */
+			goto fallback;
+		}
+
+		len = end_seq - TCP_SKB_CB(skb)->seq;
+		BUG_ON(len < 0);
+		BUG_ON(len > skb->len);
+
+		/* MSS boundaries should be honoured or else pcount will
+		 * severely break even though it makes things bit trickier.
+		 * Optimize common case to avoid most of the divides
+		 */
+		mss = tcp_skb_mss(skb);
+
+		/* TODO: Fix DSACKs to not fragment already SACKed and we can
+		 * drop this restriction as unnecessary
+		 */
+		if (mss != tcp_skb_seglen(prev))
+			goto fallback;
+
+		if (len == mss) {
+			pcount = 1;
+		} else if (len < mss) {
+			goto noop;
+		} else {
+			pcount = len / mss;
+			len = pcount * mss;
+		}
+	}
+
+	if (!skb_shift(prev, skb, len))
+		goto fallback;
+	if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss))
+		goto out;
+
+	/* Hole filled allows collapsing with the next as well, this is very
+	 * useful when hole on every nth skb pattern happens
+	 */
+	if (prev == tcp_write_queue_tail(sk))
+		goto out;
+	skb = tcp_write_queue_next(sk, prev);
+
+	if (!skb_can_shift(skb) ||
+	    (skb == tcp_send_head(sk)) ||
+	    ((TCP_SKB_CB(skb)->sacked & TCPCB_TAGBITS) != TCPCB_SACKED_ACKED) ||
+	    (mss != tcp_skb_seglen(skb)))
+		goto out;
+
+	len = skb->len;
+	if (skb_shift(prev, skb, len)) {
+		pcount += tcp_skb_pcount(skb);
+		tcp_shifted_skb(sk, skb, state, tcp_skb_pcount(skb), len, mss);
+	}
+
+out:
+	state->fack_count += pcount;
+	return prev;
+
+noop:
+	return skb;
+
+fallback:
+	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SACKSHIFTFALLBACK);
+	return NULL;
 }
 
 static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk,
 					struct tcp_sack_block *next_dup,
+					struct tcp_sacktag_state *state,
 					u32 start_seq, u32 end_seq,
-					int dup_sack_in, int *fack_count,
-					int *reord, int *flag)
+					int dup_sack_in)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct sk_buff *tmp;
+
 	tcp_for_write_queue_from(skb, sk) {
 		int in_sack = 0;
 		int dup_sack = dup_sack_in;
@@ -1376,17 +1624,42 @@
 				dup_sack = 1;
 		}
 
-		if (in_sack <= 0)
-			in_sack = tcp_match_skb_to_sack(sk, skb, start_seq,
-							end_seq);
+		/* skb reference here is a bit tricky to get right, since
+		 * shifting can eat and free both this skb and the next,
+		 * so not even _safe variant of the loop is enough.
+		 */
+		if (in_sack <= 0) {
+			tmp = tcp_shift_skb_data(sk, skb, state,
+						 start_seq, end_seq, dup_sack);
+			if (tmp != NULL) {
+				if (tmp != skb) {
+					skb = tmp;
+					continue;
+				}
+
+				in_sack = 0;
+			} else {
+				in_sack = tcp_match_skb_to_sack(sk, skb,
+								start_seq,
+								end_seq);
+			}
+		}
+
 		if (unlikely(in_sack < 0))
 			break;
 
-		if (in_sack)
-			*flag |= tcp_sacktag_one(skb, sk, reord, dup_sack,
-						 *fack_count);
+		if (in_sack) {
+			TCP_SKB_CB(skb)->sacked = tcp_sacktag_one(skb, sk,
+								  state,
+								  dup_sack,
+								  tcp_skb_pcount(skb));
 
-		*fack_count += tcp_skb_pcount(skb);
+			if (!before(TCP_SKB_CB(skb)->seq,
+				    tcp_highest_sack_seq(tp)))
+				tcp_advance_highest_sack(sk, skb);
+		}
+
+		state->fack_count += tcp_skb_pcount(skb);
 	}
 	return skb;
 }
@@ -1395,16 +1668,17 @@
  * a normal way
  */
 static struct sk_buff *tcp_sacktag_skip(struct sk_buff *skb, struct sock *sk,
-					u32 skip_to_seq, int *fack_count)
+					struct tcp_sacktag_state *state,
+					u32 skip_to_seq)
 {
 	tcp_for_write_queue_from(skb, sk) {
 		if (skb == tcp_send_head(sk))
 			break;
 
-		if (!before(TCP_SKB_CB(skb)->end_seq, skip_to_seq))
+		if (after(TCP_SKB_CB(skb)->end_seq, skip_to_seq))
 			break;
 
-		*fack_count += tcp_skb_pcount(skb);
+		state->fack_count += tcp_skb_pcount(skb);
 	}
 	return skb;
 }
@@ -1412,18 +1686,17 @@
 static struct sk_buff *tcp_maybe_skipping_dsack(struct sk_buff *skb,
 						struct sock *sk,
 						struct tcp_sack_block *next_dup,
-						u32 skip_to_seq,
-						int *fack_count, int *reord,
-						int *flag)
+						struct tcp_sacktag_state *state,
+						u32 skip_to_seq)
 {
 	if (next_dup == NULL)
 		return skb;
 
 	if (before(next_dup->start_seq, skip_to_seq)) {
-		skb = tcp_sacktag_skip(skb, sk, next_dup->start_seq, fack_count);
-		skb = tcp_sacktag_walk(skb, sk, NULL,
-				     next_dup->start_seq, next_dup->end_seq,
-				     1, fack_count, reord, flag);
+		skb = tcp_sacktag_skip(skb, sk, state, next_dup->start_seq);
+		skb = tcp_sacktag_walk(skb, sk, NULL, state,
+				       next_dup->start_seq, next_dup->end_seq,
+				       1);
 	}
 
 	return skb;
@@ -1445,16 +1718,17 @@
 	struct tcp_sack_block_wire *sp_wire = (struct tcp_sack_block_wire *)(ptr+2);
 	struct tcp_sack_block sp[TCP_NUM_SACKS];
 	struct tcp_sack_block *cache;
+	struct tcp_sacktag_state state;
 	struct sk_buff *skb;
 	int num_sacks = min(TCP_NUM_SACKS, (ptr[1] - TCPOLEN_SACK_BASE) >> 3);
 	int used_sacks;
-	int reord = tp->packets_out;
-	int flag = 0;
 	int found_dup_sack = 0;
-	int fack_count;
 	int i, j;
 	int first_sack_index;
 
+	state.flag = 0;
+	state.reord = tp->packets_out;
+
 	if (!tp->sacked_out) {
 		if (WARN_ON(tp->fackets_out))
 			tp->fackets_out = 0;
@@ -1464,7 +1738,7 @@
 	found_dup_sack = tcp_check_dsack(sk, ack_skb, sp_wire,
 					 num_sacks, prior_snd_una);
 	if (found_dup_sack)
-		flag |= FLAG_DSACKING_ACK;
+		state.flag |= FLAG_DSACKING_ACK;
 
 	/* Eliminate too old ACKs, but take into
 	 * account more or less fresh ones, they can
@@ -1533,7 +1807,7 @@
 	}
 
 	skb = tcp_write_queue_head(sk);
-	fack_count = 0;
+	state.fack_count = 0;
 	i = 0;
 
 	if (!tp->sacked_out) {
@@ -1558,7 +1832,7 @@
 
 		/* Event "B" in the comment above. */
 		if (after(end_seq, tp->high_seq))
-			flag |= FLAG_DATA_LOST;
+			state.flag |= FLAG_DATA_LOST;
 
 		/* Skip too early cached blocks */
 		while (tcp_sack_cache_ok(tp, cache) &&
@@ -1571,13 +1845,13 @@
 
 			/* Head todo? */
 			if (before(start_seq, cache->start_seq)) {
-				skb = tcp_sacktag_skip(skb, sk, start_seq,
-						       &fack_count);
+				skb = tcp_sacktag_skip(skb, sk, &state,
+						       start_seq);
 				skb = tcp_sacktag_walk(skb, sk, next_dup,
+						       &state,
 						       start_seq,
 						       cache->start_seq,
-						       dup_sack, &fack_count,
-						       &reord, &flag);
+						       dup_sack);
 			}
 
 			/* Rest of the block already fully processed? */
@@ -1585,9 +1859,8 @@
 				goto advance_sp;
 
 			skb = tcp_maybe_skipping_dsack(skb, sk, next_dup,
-						       cache->end_seq,
-						       &fack_count, &reord,
-						       &flag);
+						       &state,
+						       cache->end_seq);
 
 			/* ...tail remains todo... */
 			if (tcp_highest_sack_seq(tp) == cache->end_seq) {
@@ -1595,13 +1868,12 @@
 				skb = tcp_highest_sack(sk);
 				if (skb == NULL)
 					break;
-				fack_count = tp->fackets_out;
+				state.fack_count = tp->fackets_out;
 				cache++;
 				goto walk;
 			}
 
-			skb = tcp_sacktag_skip(skb, sk, cache->end_seq,
-					       &fack_count);
+			skb = tcp_sacktag_skip(skb, sk, &state, cache->end_seq);
 			/* Check overlap against next cached too (past this one already) */
 			cache++;
 			continue;
@@ -1611,20 +1883,20 @@
 			skb = tcp_highest_sack(sk);
 			if (skb == NULL)
 				break;
-			fack_count = tp->fackets_out;
+			state.fack_count = tp->fackets_out;
 		}
-		skb = tcp_sacktag_skip(skb, sk, start_seq, &fack_count);
+		skb = tcp_sacktag_skip(skb, sk, &state, start_seq);
 
 walk:
-		skb = tcp_sacktag_walk(skb, sk, next_dup, start_seq, end_seq,
-				       dup_sack, &fack_count, &reord, &flag);
+		skb = tcp_sacktag_walk(skb, sk, next_dup, &state,
+				       start_seq, end_seq, dup_sack);
 
 advance_sp:
 		/* SACK enhanced FRTO (RFC4138, Appendix B): Clearing correct
 		 * due to in-order walk
 		 */
 		if (after(end_seq, tp->frto_highmark))
-			flag &= ~FLAG_ONLY_ORIG_SACKED;
+			state.flag &= ~FLAG_ONLY_ORIG_SACKED;
 
 		i++;
 	}
@@ -1641,10 +1913,10 @@
 
 	tcp_verify_left_out(tp);
 
-	if ((reord < tp->fackets_out) &&
+	if ((state.reord < tp->fackets_out) &&
 	    ((icsk->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker) &&
 	    (!tp->frto_highmark || after(tp->snd_una, tp->frto_highmark)))
-		tcp_update_reordering(sk, tp->fackets_out - reord, 0);
+		tcp_update_reordering(sk, tp->fackets_out - state.reord, 0);
 
 out:
 
@@ -1654,13 +1926,13 @@
 	WARN_ON((int)tp->retrans_out < 0);
 	WARN_ON((int)tcp_packets_in_flight(tp) < 0);
 #endif
-	return flag;
+	return state.flag;
 }
 
 /* Limits sacked_out so that sum with lost_out isn't ever larger than
  * packets_out. Returns zero if sacked_out adjustement wasn't necessary.
  */
-int tcp_limit_reno_sacked(struct tcp_sock *tp)
+static int tcp_limit_reno_sacked(struct tcp_sock *tp)
 {
 	u32 holes;
 
@@ -2336,9 +2608,9 @@
 	struct inet_sock *inet = inet_sk(sk);
 
 	if (sk->sk_family == AF_INET) {
-		printk(KERN_DEBUG "Undo %s " NIPQUAD_FMT "/%u c%u l%u ss%u/%u p%u\n",
+		printk(KERN_DEBUG "Undo %s %pI4/%u c%u l%u ss%u/%u p%u\n",
 		       msg,
-		       NIPQUAD(inet->daddr), ntohs(inet->dport),
+		       &inet->daddr, ntohs(inet->dport),
 		       tp->snd_cwnd, tcp_left_out(tp),
 		       tp->snd_ssthresh, tp->prior_ssthresh,
 		       tp->packets_out);
@@ -2346,9 +2618,9 @@
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 	else if (sk->sk_family == AF_INET6) {
 		struct ipv6_pinfo *np = inet6_sk(sk);
-		printk(KERN_DEBUG "Undo %s " NIP6_FMT "/%u c%u l%u ss%u/%u p%u\n",
+		printk(KERN_DEBUG "Undo %s %pI6/%u c%u l%u ss%u/%u p%u\n",
 		       msg,
-		       NIP6(np->daddr), ntohs(inet->dport),
+		       &np->daddr, ntohs(inet->dport),
 		       tp->snd_cwnd, tcp_left_out(tp),
 		       tp->snd_ssthresh, tp->prior_ssthresh,
 		       tp->packets_out);
@@ -2559,6 +2831,56 @@
 	tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
 }
 
+/* Do a simple retransmit without using the backoff mechanisms in
+ * tcp_timer. This is used for path mtu discovery.
+ * The socket is already locked here.
+ */
+void tcp_simple_retransmit(struct sock *sk)
+{
+	const struct inet_connection_sock *icsk = inet_csk(sk);
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct sk_buff *skb;
+	unsigned int mss = tcp_current_mss(sk, 0);
+	u32 prior_lost = tp->lost_out;
+
+	tcp_for_write_queue(skb, sk) {
+		if (skb == tcp_send_head(sk))
+			break;
+		if (tcp_skb_seglen(skb) > mss &&
+		    !(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) {
+			if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) {
+				TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
+				tp->retrans_out -= tcp_skb_pcount(skb);
+			}
+			tcp_skb_mark_lost_uncond_verify(tp, skb);
+		}
+	}
+
+	tcp_clear_retrans_hints_partial(tp);
+
+	if (prior_lost == tp->lost_out)
+		return;
+
+	if (tcp_is_reno(tp))
+		tcp_limit_reno_sacked(tp);
+
+	tcp_verify_left_out(tp);
+
+	/* Don't muck with the congestion window here.
+	 * Reason is that we do not increase amount of _data_
+	 * in network, but units changed and effective
+	 * cwnd/ssthresh really reduced now.
+	 */
+	if (icsk->icsk_ca_state != TCP_CA_Loss) {
+		tp->high_seq = tp->snd_nxt;
+		tp->snd_ssthresh = tcp_current_ssthresh(sk);
+		tp->prior_ssthresh = 0;
+		tp->undo_marker = 0;
+		tcp_set_ca_state(sk, TCP_CA_Loss);
+	}
+	tcp_xmit_retransmit_queue(sk);
+}
+
 /* Process an event, which can update packets-in-flight not trivially.
  * Main goal of this function is to calculate new estimate for left_out,
  * taking into account both packets sitting in receiver's buffer and
@@ -2730,6 +3052,13 @@
 	tcp_xmit_retransmit_queue(sk);
 }
 
+static void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt)
+{
+	tcp_rtt_estimator(sk, seq_rtt);
+	tcp_set_rto(sk);
+	inet_csk(sk)->icsk_backoff = 0;
+}
+
 /* Read draft-ietf-tcplw-high-performance before mucking
  * with this code. (Supersedes RFC1323)
  */
@@ -2751,11 +3080,8 @@
 	 * in window is lost... Voila.	 			--ANK (010210)
 	 */
 	struct tcp_sock *tp = tcp_sk(sk);
-	const __u32 seq_rtt = tcp_time_stamp - tp->rx_opt.rcv_tsecr;
-	tcp_rtt_estimator(sk, seq_rtt);
-	tcp_set_rto(sk);
-	inet_csk(sk)->icsk_backoff = 0;
-	tcp_bound_rto(sk);
+
+	tcp_valid_rtt_meas(sk, tcp_time_stamp - tp->rx_opt.rcv_tsecr);
 }
 
 static void tcp_ack_no_tstamp(struct sock *sk, u32 seq_rtt, int flag)
@@ -2772,10 +3098,7 @@
 	if (flag & FLAG_RETRANS_DATA_ACKED)
 		return;
 
-	tcp_rtt_estimator(sk, seq_rtt);
-	tcp_set_rto(sk);
-	inet_csk(sk)->icsk_backoff = 0;
-	tcp_bound_rto(sk);
+	tcp_valid_rtt_meas(sk, seq_rtt);
 }
 
 static inline void tcp_ack_update_rtt(struct sock *sk, const int flag,
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 5c8fa7f..1017248 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -97,11 +97,7 @@
 }
 #endif
 
-struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
-	.lhash_lock  = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock),
-	.lhash_users = ATOMIC_INIT(0),
-	.lhash_wait  = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait),
-};
+struct inet_hashinfo tcp_hashinfo;
 
 static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb)
 {
@@ -492,7 +488,7 @@
 		skb->csum_offset = offsetof(struct tcphdr, check);
 	} else {
 		th->check = tcp_v4_check(len, inet->saddr, inet->daddr,
-					 csum_partial((char *)th,
+					 csum_partial(th,
 						      th->doff << 2,
 						      skb->csum));
 	}
@@ -726,7 +722,7 @@
 		th->check = tcp_v4_check(skb->len,
 					 ireq->loc_addr,
 					 ireq->rmt_addr,
-					 csum_partial((char *)th, skb->len,
+					 csum_partial(th, skb->len,
 						      skb->csum));
 
 		err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr,
@@ -1139,10 +1135,9 @@
 
 	if (genhash || memcmp(hash_location, newhash, 16) != 0) {
 		if (net_ratelimit()) {
-			printk(KERN_INFO "MD5 Hash failed for "
-			       "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)%s\n",
-			       NIPQUAD(iph->saddr), ntohs(th->source),
-			       NIPQUAD(iph->daddr), ntohs(th->dest),
+			printk(KERN_INFO "MD5 Hash failed for (%pI4, %d)->(%pI4, %d)%s\n",
+			       &iph->saddr, ntohs(th->source),
+			       &iph->daddr, ntohs(th->dest),
 			       genhash ? " tcp_v4_calc_md5_hash failed" : "");
 		}
 		return 1;
@@ -1297,10 +1292,8 @@
 			 * to destinations, already remembered
 			 * to the moment of synflood.
 			 */
-			LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open "
-				       "request from " NIPQUAD_FMT "/%u\n",
-				       NIPQUAD(saddr),
-				       ntohs(tcp_hdr(skb)->source));
+			LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI4/%u\n",
+				       &saddr, ntohs(tcp_hdr(skb)->source));
 			goto drop_and_release;
 		}
 
@@ -1804,7 +1797,7 @@
 	sk->sk_sndbuf = sysctl_tcp_wmem[1];
 	sk->sk_rcvbuf = sysctl_tcp_rmem[1];
 
-	atomic_inc(&tcp_sockets_allocated);
+	percpu_counter_inc(&tcp_sockets_allocated);
 
 	return 0;
 }
@@ -1852,7 +1845,7 @@
 		sk->sk_sndmsg_page = NULL;
 	}
 
-	atomic_dec(&tcp_sockets_allocated);
+	percpu_counter_dec(&tcp_sockets_allocated);
 }
 
 EXPORT_SYMBOL(tcp_v4_destroy_sock);
@@ -1860,32 +1853,35 @@
 #ifdef CONFIG_PROC_FS
 /* Proc filesystem TCP sock list dumping. */
 
-static inline struct inet_timewait_sock *tw_head(struct hlist_head *head)
+static inline struct inet_timewait_sock *tw_head(struct hlist_nulls_head *head)
 {
-	return hlist_empty(head) ? NULL :
+	return hlist_nulls_empty(head) ? NULL :
 		list_entry(head->first, struct inet_timewait_sock, tw_node);
 }
 
 static inline struct inet_timewait_sock *tw_next(struct inet_timewait_sock *tw)
 {
-	return tw->tw_node.next ?
-		hlist_entry(tw->tw_node.next, typeof(*tw), tw_node) : NULL;
+	return !is_a_nulls(tw->tw_node.next) ?
+		hlist_nulls_entry(tw->tw_node.next, typeof(*tw), tw_node) : NULL;
 }
 
 static void *listening_get_next(struct seq_file *seq, void *cur)
 {
 	struct inet_connection_sock *icsk;
-	struct hlist_node *node;
+	struct hlist_nulls_node *node;
 	struct sock *sk = cur;
-	struct tcp_iter_state* st = seq->private;
+	struct inet_listen_hashbucket *ilb;
+	struct tcp_iter_state *st = seq->private;
 	struct net *net = seq_file_net(seq);
 
 	if (!sk) {
 		st->bucket = 0;
-		sk = sk_head(&tcp_hashinfo.listening_hash[0]);
+		ilb = &tcp_hashinfo.listening_hash[0];
+		spin_lock_bh(&ilb->lock);
+		sk = sk_nulls_head(&ilb->head);
 		goto get_sk;
 	}
-
+	ilb = &tcp_hashinfo.listening_hash[st->bucket];
 	++st->num;
 
 	if (st->state == TCP_SEQ_STATE_OPENREQ) {
@@ -1918,7 +1914,7 @@
 		sk = sk_next(sk);
 	}
 get_sk:
-	sk_for_each_from(sk, node) {
+	sk_nulls_for_each_from(sk, node) {
 		if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) {
 			cur = sk;
 			goto out;
@@ -1935,8 +1931,11 @@
 		}
 		read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
 	}
+	spin_unlock_bh(&ilb->lock);
 	if (++st->bucket < INET_LHTABLE_SIZE) {
-		sk = sk_head(&tcp_hashinfo.listening_hash[st->bucket]);
+		ilb = &tcp_hashinfo.listening_hash[st->bucket];
+		spin_lock_bh(&ilb->lock);
+		sk = sk_nulls_head(&ilb->head);
 		goto get_sk;
 	}
 	cur = NULL;
@@ -1957,28 +1956,28 @@
 
 static inline int empty_bucket(struct tcp_iter_state *st)
 {
-	return hlist_empty(&tcp_hashinfo.ehash[st->bucket].chain) &&
-		hlist_empty(&tcp_hashinfo.ehash[st->bucket].twchain);
+	return hlist_nulls_empty(&tcp_hashinfo.ehash[st->bucket].chain) &&
+		hlist_nulls_empty(&tcp_hashinfo.ehash[st->bucket].twchain);
 }
 
 static void *established_get_first(struct seq_file *seq)
 {
-	struct tcp_iter_state* st = seq->private;
+	struct tcp_iter_state *st = seq->private;
 	struct net *net = seq_file_net(seq);
 	void *rc = NULL;
 
 	for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) {
 		struct sock *sk;
-		struct hlist_node *node;
+		struct hlist_nulls_node *node;
 		struct inet_timewait_sock *tw;
-		rwlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, st->bucket);
+		spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, st->bucket);
 
 		/* Lockless fast path for the common case of empty buckets */
 		if (empty_bucket(st))
 			continue;
 
-		read_lock_bh(lock);
-		sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) {
+		spin_lock_bh(lock);
+		sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) {
 			if (sk->sk_family != st->family ||
 			    !net_eq(sock_net(sk), net)) {
 				continue;
@@ -1996,7 +1995,7 @@
 			rc = tw;
 			goto out;
 		}
-		read_unlock_bh(lock);
+		spin_unlock_bh(lock);
 		st->state = TCP_SEQ_STATE_ESTABLISHED;
 	}
 out:
@@ -2007,8 +2006,8 @@
 {
 	struct sock *sk = cur;
 	struct inet_timewait_sock *tw;
-	struct hlist_node *node;
-	struct tcp_iter_state* st = seq->private;
+	struct hlist_nulls_node *node;
+	struct tcp_iter_state *st = seq->private;
 	struct net *net = seq_file_net(seq);
 
 	++st->num;
@@ -2024,7 +2023,7 @@
 			cur = tw;
 			goto out;
 		}
-		read_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
+		spin_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
 		st->state = TCP_SEQ_STATE_ESTABLISHED;
 
 		/* Look for next non empty bucket */
@@ -2034,12 +2033,12 @@
 		if (st->bucket >= tcp_hashinfo.ehash_size)
 			return NULL;
 
-		read_lock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
-		sk = sk_head(&tcp_hashinfo.ehash[st->bucket].chain);
+		spin_lock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
+		sk = sk_nulls_head(&tcp_hashinfo.ehash[st->bucket].chain);
 	} else
-		sk = sk_next(sk);
+		sk = sk_nulls_next(sk);
 
-	sk_for_each_from(sk, node) {
+	sk_nulls_for_each_from(sk, node) {
 		if (sk->sk_family == st->family && net_eq(sock_net(sk), net))
 			goto found;
 	}
@@ -2067,14 +2066,12 @@
 static void *tcp_get_idx(struct seq_file *seq, loff_t pos)
 {
 	void *rc;
-	struct tcp_iter_state* st = seq->private;
+	struct tcp_iter_state *st = seq->private;
 
-	inet_listen_lock(&tcp_hashinfo);
 	st->state = TCP_SEQ_STATE_LISTENING;
 	rc	  = listening_get_idx(seq, &pos);
 
 	if (!rc) {
-		inet_listen_unlock(&tcp_hashinfo);
 		st->state = TCP_SEQ_STATE_ESTABLISHED;
 		rc	  = established_get_idx(seq, pos);
 	}
@@ -2084,7 +2081,7 @@
 
 static void *tcp_seq_start(struct seq_file *seq, loff_t *pos)
 {
-	struct tcp_iter_state* st = seq->private;
+	struct tcp_iter_state *st = seq->private;
 	st->state = TCP_SEQ_STATE_LISTENING;
 	st->num = 0;
 	return *pos ? tcp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
@@ -2093,7 +2090,7 @@
 static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	void *rc = NULL;
-	struct tcp_iter_state* st;
+	struct tcp_iter_state *st;
 
 	if (v == SEQ_START_TOKEN) {
 		rc = tcp_get_idx(seq, 0);
@@ -2106,7 +2103,6 @@
 	case TCP_SEQ_STATE_LISTENING:
 		rc = listening_get_next(seq, v);
 		if (!rc) {
-			inet_listen_unlock(&tcp_hashinfo);
 			st->state = TCP_SEQ_STATE_ESTABLISHED;
 			rc	  = established_get_first(seq);
 		}
@@ -2123,7 +2119,7 @@
 
 static void tcp_seq_stop(struct seq_file *seq, void *v)
 {
-	struct tcp_iter_state* st = seq->private;
+	struct tcp_iter_state *st = seq->private;
 
 	switch (st->state) {
 	case TCP_SEQ_STATE_OPENREQ:
@@ -2133,12 +2129,12 @@
 		}
 	case TCP_SEQ_STATE_LISTENING:
 		if (v != SEQ_START_TOKEN)
-			inet_listen_unlock(&tcp_hashinfo);
+			spin_unlock_bh(&tcp_hashinfo.listening_hash[st->bucket].lock);
 		break;
 	case TCP_SEQ_STATE_TIME_WAIT:
 	case TCP_SEQ_STATE_ESTABLISHED:
 		if (v)
-			read_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
+			spin_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
 		break;
 	}
 }
@@ -2284,7 +2280,7 @@
 
 static int tcp4_seq_show(struct seq_file *seq, void *v)
 {
-	struct tcp_iter_state* st;
+	struct tcp_iter_state *st;
 	int len;
 
 	if (v == SEQ_START_TOKEN) {
@@ -2350,6 +2346,41 @@
 }
 #endif /* CONFIG_PROC_FS */
 
+struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)
+{
+	struct iphdr *iph = ip_hdr(skb);
+
+	switch (skb->ip_summed) {
+	case CHECKSUM_COMPLETE:
+		if (!tcp_v4_check(skb->len, iph->saddr, iph->daddr,
+				  skb->csum)) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			break;
+		}
+
+		/* fall through */
+	case CHECKSUM_NONE:
+		NAPI_GRO_CB(skb)->flush = 1;
+		return NULL;
+	}
+
+	return tcp_gro_receive(head, skb);
+}
+EXPORT_SYMBOL(tcp4_gro_receive);
+
+int tcp4_gro_complete(struct sk_buff *skb)
+{
+	struct iphdr *iph = ip_hdr(skb);
+	struct tcphdr *th = tcp_hdr(skb);
+
+	th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb),
+				  iph->saddr, iph->daddr, 0);
+	skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+
+	return tcp_gro_complete(skb);
+}
+EXPORT_SYMBOL(tcp4_gro_complete);
+
 struct proto tcp_prot = {
 	.name			= "TCP",
 	.owner			= THIS_MODULE,
@@ -2378,6 +2409,7 @@
 	.sysctl_rmem		= sysctl_tcp_rmem,
 	.max_header		= MAX_TCP_HEADER,
 	.obj_size		= sizeof(struct tcp_sock),
+	.slab_flags		= SLAB_DESTROY_BY_RCU,
 	.twsk_prot		= &tcp_timewait_sock_ops,
 	.rsk_prot		= &tcp_request_sock_ops,
 	.h.hashinfo		= &tcp_hashinfo,
@@ -2407,6 +2439,7 @@
 
 void __init tcp_v4_init(void)
 {
+	inet_hashinfo_init(&tcp_hashinfo);
 	if (register_pernet_device(&tcp_sk_ops))
 		panic("Failed to create the TCP control socket.\n");
 }
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 779f2e9..f67effb 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -491,7 +491,7 @@
  *	as a request_sock.
  */
 
-struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
+struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
 			   struct request_sock *req,
 			   struct request_sock **prev)
 {
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index fe3b4bd..557fe16 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -42,7 +42,7 @@
 /* People can turn this off for buggy TCP's found in printers etc. */
 int sysctl_tcp_retrans_collapse __read_mostly = 1;
 
-/* People can turn this on to  work with those rare, broken TCPs that
+/* People can turn this on to work with those rare, broken TCPs that
  * interpret the window field as a signed quantity.
  */
 int sysctl_tcp_workaround_signed_windows __read_mostly = 0;
@@ -484,7 +484,7 @@
 	}
 	if (likely(sysctl_tcp_window_scaling)) {
 		opts->ws = tp->rx_opt.rcv_wscale;
-		if(likely(opts->ws))
+		if (likely(opts->ws))
 			size += TCPOLEN_WSCALE_ALIGNED;
 	}
 	if (likely(sysctl_tcp_sack)) {
@@ -526,7 +526,7 @@
 
 	if (likely(ireq->wscale_ok)) {
 		opts->ws = ireq->rcv_wscale;
-		if(likely(opts->ws))
+		if (likely(opts->ws))
 			size += TCPOLEN_WSCALE_ALIGNED;
 	}
 	if (likely(doing_ts)) {
@@ -663,10 +663,14 @@
 	th->urg_ptr		= 0;
 
 	/* The urg_mode check is necessary during a below snd_una win probe */
-	if (unlikely(tcp_urg_mode(tp) &&
-		     between(tp->snd_up, tcb->seq + 1, tcb->seq + 0xFFFF))) {
-		th->urg_ptr		= htons(tp->snd_up - tcb->seq);
-		th->urg			= 1;
+	if (unlikely(tcp_urg_mode(tp))) {
+		if (between(tp->snd_up, tcb->seq + 1, tcb->seq + 0xFFFF)) {
+			th->urg_ptr = htons(tp->snd_up - tcb->seq);
+			th->urg = 1;
+		} else if (after(tcb->seq + 0xFFFF, tp->snd_nxt)) {
+			th->urg_ptr = 0xFFFF;
+			th->urg = 1;
+		}
 	}
 
 	tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location);
@@ -1168,7 +1172,7 @@
 
 static inline int tcp_minshall_check(const struct tcp_sock *tp)
 {
-	return after(tp->snd_sml,tp->snd_una) &&
+	return after(tp->snd_sml, tp->snd_una) &&
 		!after(tp->snd_sml, tp->snd_nxt);
 }
 
@@ -1334,7 +1338,7 @@
 
 	/* Defer for less than two clock ticks. */
 	if (tp->tso_deferred &&
-	    ((jiffies << 1) >> 1) - (tp->tso_deferred >> 1) > 1)
+	    (((u32)jiffies << 1) >> 1) - (tp->tso_deferred >> 1) > 1)
 		goto send_now;
 
 	in_flight = tcp_packets_in_flight(tp);
@@ -1519,7 +1523,8 @@
  * Returns 1, if no segments are in flight and we have queued segments, but
  * cannot send anything now because of SWS or another problem.
  */
-static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle)
+static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
+			  int push_one, gfp_t gfp)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
@@ -1527,20 +1532,16 @@
 	int cwnd_quota;
 	int result;
 
-	/* If we are closed, the bytes will have to remain here.
-	 * In time closedown will finish, we empty the write queue and all
-	 * will be happy.
-	 */
-	if (unlikely(sk->sk_state == TCP_CLOSE))
-		return 0;
-
 	sent_pkts = 0;
 
-	/* Do MTU probing. */
-	if ((result = tcp_mtu_probe(sk)) == 0) {
-		return 0;
-	} else if (result > 0) {
-		sent_pkts = 1;
+	if (!push_one) {
+		/* Do MTU probing. */
+		result = tcp_mtu_probe(sk);
+		if (!result) {
+			return 0;
+		} else if (result > 0) {
+			sent_pkts = 1;
+		}
 	}
 
 	while ((skb = tcp_send_head(sk))) {
@@ -1562,7 +1563,7 @@
 						      nonagle : TCP_NAGLE_PUSH))))
 				break;
 		} else {
-			if (tcp_tso_should_defer(sk, skb))
+			if (!push_one && tcp_tso_should_defer(sk, skb))
 				break;
 		}
 
@@ -1577,7 +1578,7 @@
 
 		TCP_SKB_CB(skb)->when = tcp_time_stamp;
 
-		if (unlikely(tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC)))
+		if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
 			break;
 
 		/* Advance the send_head.  This one is sent out.
@@ -1587,6 +1588,9 @@
 
 		tcp_minshall_update(tp, mss_now, skb);
 		sent_pkts++;
+
+		if (push_one)
+			break;
 	}
 
 	if (likely(sent_pkts)) {
@@ -1605,10 +1609,18 @@
 {
 	struct sk_buff *skb = tcp_send_head(sk);
 
-	if (skb) {
-		if (tcp_write_xmit(sk, cur_mss, nonagle))
-			tcp_check_probe_timer(sk);
-	}
+	if (!skb)
+		return;
+
+	/* If we are closed, the bytes will have to remain here.
+	 * In time closedown will finish, we empty the write queue and
+	 * all will be happy.
+	 */
+	if (unlikely(sk->sk_state == TCP_CLOSE))
+		return;
+
+	if (tcp_write_xmit(sk, cur_mss, nonagle, 0, GFP_ATOMIC))
+		tcp_check_probe_timer(sk);
 }
 
 /* Send _single_ skb sitting at the send head. This function requires
@@ -1616,38 +1628,11 @@
  */
 void tcp_push_one(struct sock *sk, unsigned int mss_now)
 {
-	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb = tcp_send_head(sk);
-	unsigned int tso_segs, cwnd_quota;
 
 	BUG_ON(!skb || skb->len < mss_now);
 
-	tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
-	cwnd_quota = tcp_snd_test(sk, skb, mss_now, TCP_NAGLE_PUSH);
-
-	if (likely(cwnd_quota)) {
-		unsigned int limit;
-
-		BUG_ON(!tso_segs);
-
-		limit = mss_now;
-		if (tso_segs > 1 && !tcp_urg_mode(tp))
-			limit = tcp_mss_split_point(sk, skb, mss_now,
-						    cwnd_quota);
-
-		if (skb->len > limit &&
-		    unlikely(tso_fragment(sk, skb, limit, mss_now)))
-			return;
-
-		/* Send it out now. */
-		TCP_SKB_CB(skb)->when = tcp_time_stamp;
-
-		if (likely(!tcp_transmit_skb(sk, skb, 1, sk->sk_allocation))) {
-			tcp_event_new_data_sent(sk, skb);
-			tcp_cwnd_validate(sk);
-			return;
-		}
-	}
+	tcp_write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, sk->sk_allocation);
 }
 
 /* This function returns the amount that we can raise the
@@ -1767,46 +1752,22 @@
 	return window;
 }
 
-/* Attempt to collapse two adjacent SKB's during retransmission. */
-static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb,
-				     int mss_now)
+/* Collapses two adjacent SKB's during retransmission. */
+static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *next_skb = tcp_write_queue_next(sk, skb);
 	int skb_size, next_skb_size;
 	u16 flags;
 
-	/* The first test we must make is that neither of these two
-	 * SKB's are still referenced by someone else.
-	 */
-	if (skb_cloned(skb) || skb_cloned(next_skb))
-		return;
-
 	skb_size = skb->len;
 	next_skb_size = next_skb->len;
 	flags = TCP_SKB_CB(skb)->flags;
 
-	/* Also punt if next skb has been SACK'd. */
-	if (TCP_SKB_CB(next_skb)->sacked & TCPCB_SACKED_ACKED)
-		return;
-
-	/* Next skb is out of window. */
-	if (after(TCP_SKB_CB(next_skb)->end_seq, tcp_wnd_end(tp)))
-		return;
-
-	/* Punt if not enough space exists in the first SKB for
-	 * the data in the second, or the total combined payload
-	 * would exceed the MSS.
-	 */
-	if ((next_skb_size > skb_tailroom(skb)) ||
-	    ((skb_size + next_skb_size) > mss_now))
-		return;
-
 	BUG_ON(tcp_skb_pcount(skb) != 1 || tcp_skb_pcount(next_skb) != 1);
 
 	tcp_highest_sack_combine(sk, next_skb, skb);
 
-	/* Ok.	We will be able to collapse the packet. */
 	tcp_unlink_write_queue(next_skb, sk);
 
 	skb_copy_from_linear_data(next_skb, skb_put(skb, next_skb_size),
@@ -1848,54 +1809,60 @@
 	sk_wmem_free_skb(sk, next_skb);
 }
 
-/* Do a simple retransmit without using the backoff mechanisms in
- * tcp_timer. This is used for path mtu discovery.
- * The socket is already locked here.
- */
-void tcp_simple_retransmit(struct sock *sk)
+static int tcp_can_collapse(struct sock *sk, struct sk_buff *skb)
 {
-	const struct inet_connection_sock *icsk = inet_csk(sk);
+	if (tcp_skb_pcount(skb) > 1)
+		return 0;
+	/* TODO: SACK collapsing could be used to remove this condition */
+	if (skb_shinfo(skb)->nr_frags != 0)
+		return 0;
+	if (skb_cloned(skb))
+		return 0;
+	if (skb == tcp_send_head(sk))
+		return 0;
+	/* Some heurestics for collapsing over SACK'd could be invented */
+	if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)
+		return 0;
+
+	return 1;
+}
+
+static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
+				     int space)
+{
 	struct tcp_sock *tp = tcp_sk(sk);
-	struct sk_buff *skb;
-	unsigned int mss = tcp_current_mss(sk, 0);
-	u32 prior_lost = tp->lost_out;
+	struct sk_buff *skb = to, *tmp;
+	int first = 1;
 
-	tcp_for_write_queue(skb, sk) {
-		if (skb == tcp_send_head(sk))
-			break;
-		if (skb->len > mss &&
-		    !(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) {
-			if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) {
-				TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
-				tp->retrans_out -= tcp_skb_pcount(skb);
-			}
-			tcp_skb_mark_lost_uncond_verify(tp, skb);
-		}
-	}
-
-	tcp_clear_retrans_hints_partial(tp);
-
-	if (prior_lost == tp->lost_out)
+	if (!sysctl_tcp_retrans_collapse)
+		return;
+	if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN)
 		return;
 
-	if (tcp_is_reno(tp))
-		tcp_limit_reno_sacked(tp);
+	tcp_for_write_queue_from_safe(skb, tmp, sk) {
+		if (!tcp_can_collapse(sk, skb))
+			break;
 
-	tcp_verify_left_out(tp);
+		space -= skb->len;
 
-	/* Don't muck with the congestion window here.
-	 * Reason is that we do not increase amount of _data_
-	 * in network, but units changed and effective
-	 * cwnd/ssthresh really reduced now.
-	 */
-	if (icsk->icsk_ca_state != TCP_CA_Loss) {
-		tp->high_seq = tp->snd_nxt;
-		tp->snd_ssthresh = tcp_current_ssthresh(sk);
-		tp->prior_ssthresh = 0;
-		tp->undo_marker = 0;
-		tcp_set_ca_state(sk, TCP_CA_Loss);
+		if (first) {
+			first = 0;
+			continue;
+		}
+
+		if (space < 0)
+			break;
+		/* Punt if not enough space exists in the first SKB for
+		 * the data in the second
+		 */
+		if (skb->len > skb_tailroom(to))
+			break;
+
+		if (after(TCP_SKB_CB(skb)->end_seq, tcp_wnd_end(tp)))
+			break;
+
+		tcp_collapse_retrans(sk, to);
 	}
-	tcp_xmit_retransmit_queue(sk);
 }
 
 /* This retransmits one SKB.  Policy decisions and retransmit queue
@@ -1947,17 +1914,7 @@
 			return -ENOMEM; /* We'll try again later. */
 	}
 
-	/* Collapse two adjacent packets if worthwhile and we can. */
-	if (!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) &&
-	    (skb->len < (cur_mss >> 1)) &&
-	    (!tcp_skb_is_last(sk, skb)) &&
-	    (tcp_write_queue_next(sk, skb) != tcp_send_head(sk)) &&
-	    (skb_shinfo(skb)->nr_frags == 0 &&
-	     skb_shinfo(tcp_write_queue_next(sk, skb))->nr_frags == 0) &&
-	    (tcp_skb_pcount(skb) == 1 &&
-	     tcp_skb_pcount(tcp_write_queue_next(sk, skb)) == 1) &&
-	    (sysctl_tcp_retrans_collapse != 0))
-		tcp_retrans_try_collapse(sk, skb, cur_mss);
+	tcp_retrans_try_collapse(sk, skb, cur_mss);
 
 	/* Some Solaris stacks overoptimize and ignore the FIN on a
 	 * retransmit when old data is attached.  So strip it off
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index 7ddc30f..25524d4 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -153,12 +153,11 @@
 		= ktime_to_timespec(ktime_sub(p->tstamp, tcp_probe.start));
 
 	return snprintf(tbuf, n,
-			"%lu.%09lu " NIPQUAD_FMT ":%u " NIPQUAD_FMT ":%u"
-			" %d %#x %#x %u %u %u %u\n",
+			"%lu.%09lu %pI4:%u %pI4:%u %d %#x %#x %u %u %u %u\n",
 			(unsigned long) tv.tv_sec,
 			(unsigned long) tv.tv_nsec,
-			NIPQUAD(p->saddr), ntohs(p->sport),
-			NIPQUAD(p->daddr), ntohs(p->dport),
+			&p->saddr, ntohs(p->sport),
+			&p->daddr, ntohs(p->dport),
 			p->length, p->snd_nxt, p->snd_una,
 			p->snd_cwnd, p->ssthresh, p->snd_wnd, p->srtt);
 }
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 6b6dff1..0170e91 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -65,7 +65,7 @@
 static int tcp_out_of_resources(struct sock *sk, int do_reset)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	int orphans = atomic_read(&tcp_orphan_count);
+	int orphans = percpu_counter_read_positive(&tcp_orphan_count);
 
 	/* If peer does not open window for long time, or did not transmit
 	 * anything for long time, penalize it. */
@@ -171,7 +171,7 @@
 
 static void tcp_delack_timer(unsigned long data)
 {
-	struct sock *sk = (struct sock*)data;
+	struct sock *sk = (struct sock *)data;
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
@@ -299,15 +299,15 @@
 #ifdef TCP_DEBUG
 		struct inet_sock *inet = inet_sk(sk);
 		if (sk->sk_family == AF_INET) {
-			LIMIT_NETDEBUG(KERN_DEBUG "TCP: Treason uncloaked! Peer " NIPQUAD_FMT ":%u/%u shrinks window %u:%u. Repaired.\n",
-			       NIPQUAD(inet->daddr), ntohs(inet->dport),
+			LIMIT_NETDEBUG(KERN_DEBUG "TCP: Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n",
+			       &inet->daddr, ntohs(inet->dport),
 			       inet->num, tp->snd_una, tp->snd_nxt);
 		}
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 		else if (sk->sk_family == AF_INET6) {
 			struct ipv6_pinfo *np = inet6_sk(sk);
-			LIMIT_NETDEBUG(KERN_DEBUG "TCP: Treason uncloaked! Peer " NIP6_FMT ":%u/%u shrinks window %u:%u. Repaired.\n",
-			       NIP6(np->daddr), ntohs(inet->dport),
+			LIMIT_NETDEBUG(KERN_DEBUG "TCP: Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n",
+			       &np->daddr, ntohs(inet->dport),
 			       inet->num, tp->snd_una, tp->snd_nxt);
 		}
 #endif
@@ -396,7 +396,7 @@
 
 static void tcp_write_timer(unsigned long data)
 {
-	struct sock *sk = (struct sock*)data;
+	struct sock *sk = (struct sock *)data;
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	int event;
 
diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c
index e03b101..9ec843a 100644
--- a/net/ipv4/tcp_yeah.c
+++ b/net/ipv4/tcp_yeah.c
@@ -83,7 +83,7 @@
 	else if (!yeah->doing_reno_now) {
 		/* Scalable */
 
-		tp->snd_cwnd_cnt+=yeah->pkts_acked;
+		tp->snd_cwnd_cnt += yeah->pkts_acked;
 		if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)){
 			if (tp->snd_cwnd < tp->snd_cwnd_clamp)
 				tp->snd_cwnd++;
@@ -224,7 +224,7 @@
 
 		reduction = max( reduction, tp->snd_cwnd >> TCP_YEAH_DELTA);
 	} else
-		reduction = max(tp->snd_cwnd>>1,2U);
+		reduction = max(tp->snd_cwnd>>1, 2U);
 
 	yeah->fast_count = 0;
 	yeah->reno_count = max(yeah->reno_count>>1, 2U);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 98c1fd0..cf5ab05 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -81,6 +81,8 @@
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 #include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/swap.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/module.h>
@@ -104,12 +106,8 @@
 #include <net/xfrm.h>
 #include "udp_impl.h"
 
-/*
- *	Snmp MIB for the UDP layer
- */
-
-struct hlist_head udp_hash[UDP_HTABLE_SIZE];
-DEFINE_RWLOCK(udp_hash_lock);
+struct udp_table udp_table;
+EXPORT_SYMBOL(udp_table);
 
 int sysctl_udp_mem[3] __read_mostly;
 int sysctl_udp_rmem_min __read_mostly;
@@ -123,15 +121,15 @@
 EXPORT_SYMBOL(udp_memory_allocated);
 
 static int udp_lib_lport_inuse(struct net *net, __u16 num,
-			       const struct hlist_head udptable[],
+			       const struct udp_hslot *hslot,
 			       struct sock *sk,
 			       int (*saddr_comp)(const struct sock *sk1,
 						 const struct sock *sk2))
 {
 	struct sock *sk2;
-	struct hlist_node *node;
+	struct hlist_nulls_node *node;
 
-	sk_for_each(sk2, node, &udptable[udp_hashfn(net, num)])
+	sk_nulls_for_each(sk2, node, &hslot->head)
 		if (net_eq(sock_net(sk2), net)			&&
 		    sk2 != sk					&&
 		    sk2->sk_hash == num				&&
@@ -154,12 +152,11 @@
 		       int (*saddr_comp)(const struct sock *sk1,
 					 const struct sock *sk2 )    )
 {
-	struct hlist_head *udptable = sk->sk_prot->h.udp_hash;
+	struct udp_hslot *hslot;
+	struct udp_table *udptable = sk->sk_prot->h.udp_table;
 	int    error = 1;
 	struct net *net = sock_net(sk);
 
-	write_lock_bh(&udp_hash_lock);
-
 	if (!snum) {
 		int low, high, remaining;
 		unsigned rand;
@@ -171,26 +168,34 @@
 		rand = net_random();
 		snum = first = rand % remaining + low;
 		rand |= 1;
-		while (udp_lib_lport_inuse(net, snum, udptable, sk,
-					   saddr_comp)) {
+		for (;;) {
+			hslot = &udptable->hash[udp_hashfn(net, snum)];
+			spin_lock_bh(&hslot->lock);
+			if (!udp_lib_lport_inuse(net, snum, hslot, sk, saddr_comp))
+				break;
+			spin_unlock_bh(&hslot->lock);
 			do {
 				snum = snum + rand;
 			} while (snum < low || snum > high);
 			if (snum == first)
 				goto fail;
 		}
-	} else if (udp_lib_lport_inuse(net, snum, udptable, sk, saddr_comp))
-		goto fail;
-
+	} else {
+		hslot = &udptable->hash[udp_hashfn(net, snum)];
+		spin_lock_bh(&hslot->lock);
+		if (udp_lib_lport_inuse(net, snum, hslot, sk, saddr_comp))
+			goto fail_unlock;
+	}
 	inet_sk(sk)->num = snum;
 	sk->sk_hash = snum;
 	if (sk_unhashed(sk)) {
-		sk_add_node(sk, &udptable[udp_hashfn(net, snum)]);
+		sk_nulls_add_node_rcu(sk, &hslot->head);
 		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 	}
 	error = 0;
+fail_unlock:
+	spin_unlock_bh(&hslot->lock);
 fail:
-	write_unlock_bh(&udp_hash_lock);
 	return error;
 }
 
@@ -208,63 +213,91 @@
 	return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal);
 }
 
+static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr,
+			 unsigned short hnum,
+			 __be16 sport, __be32 daddr, __be16 dport, int dif)
+{
+	int score = -1;
+
+	if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum &&
+			!ipv6_only_sock(sk)) {
+		struct inet_sock *inet = inet_sk(sk);
+
+		score = (sk->sk_family == PF_INET ? 1 : 0);
+		if (inet->rcv_saddr) {
+			if (inet->rcv_saddr != daddr)
+				return -1;
+			score += 2;
+		}
+		if (inet->daddr) {
+			if (inet->daddr != saddr)
+				return -1;
+			score += 2;
+		}
+		if (inet->dport) {
+			if (inet->dport != sport)
+				return -1;
+			score += 2;
+		}
+		if (sk->sk_bound_dev_if) {
+			if (sk->sk_bound_dev_if != dif)
+				return -1;
+			score += 2;
+		}
+	}
+	return score;
+}
+
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
  * harder than this. -DaveM
  */
 static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
 		__be16 sport, __be32 daddr, __be16 dport,
-		int dif, struct hlist_head udptable[])
+		int dif, struct udp_table *udptable)
 {
-	struct sock *sk, *result = NULL;
-	struct hlist_node *node;
+	struct sock *sk, *result;
+	struct hlist_nulls_node *node;
 	unsigned short hnum = ntohs(dport);
-	int badness = -1;
+	unsigned int hash = udp_hashfn(net, hnum);
+	struct udp_hslot *hslot = &udptable->hash[hash];
+	int score, badness;
 
-	read_lock(&udp_hash_lock);
-	sk_for_each(sk, node, &udptable[udp_hashfn(net, hnum)]) {
-		struct inet_sock *inet = inet_sk(sk);
-
-		if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum &&
-				!ipv6_only_sock(sk)) {
-			int score = (sk->sk_family == PF_INET ? 1 : 0);
-			if (inet->rcv_saddr) {
-				if (inet->rcv_saddr != daddr)
-					continue;
-				score+=2;
-			}
-			if (inet->daddr) {
-				if (inet->daddr != saddr)
-					continue;
-				score+=2;
-			}
-			if (inet->dport) {
-				if (inet->dport != sport)
-					continue;
-				score+=2;
-			}
-			if (sk->sk_bound_dev_if) {
-				if (sk->sk_bound_dev_if != dif)
-					continue;
-				score+=2;
-			}
-			if (score == 9) {
-				result = sk;
-				break;
-			} else if (score > badness) {
-				result = sk;
-				badness = score;
-			}
+	rcu_read_lock();
+begin:
+	result = NULL;
+	badness = -1;
+	sk_nulls_for_each_rcu(sk, node, &hslot->head) {
+		score = compute_score(sk, net, saddr, hnum, sport,
+				      daddr, dport, dif);
+		if (score > badness) {
+			result = sk;
+			badness = score;
 		}
 	}
-	if (result)
-		sock_hold(result);
-	read_unlock(&udp_hash_lock);
+	/*
+	 * if the nulls value we got at the end of this lookup is
+	 * not the expected one, we must restart lookup.
+	 * We probably met an item that was moved to another chain.
+	 */
+	if (get_nulls_value(node) != hash)
+		goto begin;
+
+	if (result) {
+		if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt)))
+			result = NULL;
+		else if (unlikely(compute_score(result, net, saddr, hnum, sport,
+				  daddr, dport, dif) < badness)) {
+			sock_put(result);
+			goto begin;
+		}
+	}
+	rcu_read_unlock();
 	return result;
 }
 
 static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb,
 						 __be16 sport, __be16 dport,
-						 struct hlist_head udptable[])
+						 struct udp_table *udptable)
 {
 	struct sock *sk;
 	const struct iphdr *iph = ip_hdr(skb);
@@ -280,7 +313,7 @@
 struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
 			     __be32 daddr, __be16 dport, int dif)
 {
-	return __udp4_lib_lookup(net, saddr, sport, daddr, dport, dif, udp_hash);
+	return __udp4_lib_lookup(net, saddr, sport, daddr, dport, dif, &udp_table);
 }
 EXPORT_SYMBOL_GPL(udp4_lib_lookup);
 
@@ -289,11 +322,11 @@
 					     __be16 rmt_port, __be32 rmt_addr,
 					     int dif)
 {
-	struct hlist_node *node;
+	struct hlist_nulls_node *node;
 	struct sock *s = sk;
 	unsigned short hnum = ntohs(loc_port);
 
-	sk_for_each_from(s, node) {
+	sk_nulls_for_each_from(s, node) {
 		struct inet_sock *inet = inet_sk(s);
 
 		if (!net_eq(sock_net(s), net)				||
@@ -324,7 +357,7 @@
  * to find the appropriate port.
  */
 
-void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[])
+void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
 {
 	struct inet_sock *inet;
 	struct iphdr *iph = (struct iphdr*)skb->data;
@@ -393,7 +426,7 @@
 
 void udp_err(struct sk_buff *skb, u32 info)
 {
-	__udp4_lib_err(skb, info, udp_hash);
+	__udp4_lib_err(skb, info, &udp_table);
 }
 
 /*
@@ -686,7 +719,7 @@
 	up->len += ulen;
 	getfrag  =  is_udplite ?  udplite_getfrag : ip_generic_getfrag;
 	err = ip_append_data(sk, getfrag, msg->msg_iov, ulen,
-			sizeof(struct udphdr), &ipc, rt,
+			sizeof(struct udphdr), &ipc, &rt,
 			corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
 	if (err)
 		udp_flush_pending_frames(sk);
@@ -935,6 +968,23 @@
 	return 0;
 }
 
+void udp_lib_unhash(struct sock *sk)
+{
+	if (sk_hashed(sk)) {
+		struct udp_table *udptable = sk->sk_prot->h.udp_table;
+		unsigned int hash = udp_hashfn(sock_net(sk), sk->sk_hash);
+		struct udp_hslot *hslot = &udptable->hash[hash];
+
+		spin_lock_bh(&hslot->lock);
+		if (sk_nulls_del_node_init_rcu(sk)) {
+			inet_sk(sk)->num = 0;
+			sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+		}
+		spin_unlock_bh(&hslot->lock);
+	}
+}
+EXPORT_SYMBOL(udp_lib_unhash);
+
 static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
 	int is_udplite = IS_UDPLITE(sk);
@@ -1073,13 +1123,14 @@
 static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 				    struct udphdr  *uh,
 				    __be32 saddr, __be32 daddr,
-				    struct hlist_head udptable[])
+				    struct udp_table *udptable)
 {
 	struct sock *sk;
+	struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))];
 	int dif;
 
-	read_lock(&udp_hash_lock);
-	sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]);
+	spin_lock(&hslot->lock);
+	sk = sk_nulls_head(&hslot->head);
 	dif = skb->dev->ifindex;
 	sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif);
 	if (sk) {
@@ -1088,7 +1139,7 @@
 		do {
 			struct sk_buff *skb1 = skb;
 
-			sknext = udp_v4_mcast_next(net, sk_next(sk), uh->dest,
+			sknext = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest,
 						   daddr, uh->source, saddr,
 						   dif);
 			if (sknext)
@@ -1105,7 +1156,7 @@
 		} while (sknext);
 	} else
 		kfree_skb(skb);
-	read_unlock(&udp_hash_lock);
+	spin_unlock(&hslot->lock);
 	return 0;
 }
 
@@ -1151,7 +1202,7 @@
  *	All we need to do is get the socket, and then do a checksum.
  */
 
-int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
+int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
 		   int proto)
 {
 	struct sock *sk;
@@ -1219,13 +1270,13 @@
 	return 0;
 
 short_packet:
-	LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From " NIPQUAD_FMT ":%u %d/%d to " NIPQUAD_FMT ":%u\n",
+	LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %pI4:%u %d/%d to %pI4:%u\n",
 		       proto == IPPROTO_UDPLITE ? "-Lite" : "",
-		       NIPQUAD(saddr),
+		       &saddr,
 		       ntohs(uh->source),
 		       ulen,
 		       skb->len,
-		       NIPQUAD(daddr),
+		       &daddr,
 		       ntohs(uh->dest));
 	goto drop;
 
@@ -1234,11 +1285,11 @@
 	 * RFC1122: OK.  Discards the bad packet silently (as far as
 	 * the network is concerned, anyway) as per 4.1.3.4 (MUST).
 	 */
-	LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From " NIPQUAD_FMT ":%u to " NIPQUAD_FMT ":%u ulen %d\n",
+	LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n",
 		       proto == IPPROTO_UDPLITE ? "-Lite" : "",
-		       NIPQUAD(saddr),
+		       &saddr,
 		       ntohs(uh->source),
-		       NIPQUAD(daddr),
+		       &daddr,
 		       ntohs(uh->dest),
 		       ulen);
 drop:
@@ -1249,7 +1300,7 @@
 
 int udp_rcv(struct sk_buff *skb)
 {
-	return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP);
+	return __udp4_lib_rcv(skb, &udp_table, IPPROTO_UDP);
 }
 
 void udp_destroy_sock(struct sock *sk)
@@ -1491,7 +1542,8 @@
 	.sysctl_wmem	   = &sysctl_udp_wmem_min,
 	.sysctl_rmem	   = &sysctl_udp_rmem_min,
 	.obj_size	   = sizeof(struct udp_sock),
-	.h.udp_hash	   = udp_hash,
+	.slab_flags	   = SLAB_DESTROY_BY_RCU,
+	.h.udp_table	   = &udp_table,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udp_setsockopt,
 	.compat_getsockopt = compat_udp_getsockopt,
@@ -1501,20 +1553,23 @@
 /* ------------------------------------------------------------------------ */
 #ifdef CONFIG_PROC_FS
 
-static struct sock *udp_get_first(struct seq_file *seq)
+static struct sock *udp_get_first(struct seq_file *seq, int start)
 {
 	struct sock *sk;
 	struct udp_iter_state *state = seq->private;
 	struct net *net = seq_file_net(seq);
 
-	for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) {
-		struct hlist_node *node;
-		sk_for_each(sk, node, state->hashtable + state->bucket) {
+	for (state->bucket = start; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) {
+		struct hlist_nulls_node *node;
+		struct udp_hslot *hslot = &state->udp_table->hash[state->bucket];
+		spin_lock_bh(&hslot->lock);
+		sk_nulls_for_each(sk, node, &hslot->head) {
 			if (!net_eq(sock_net(sk), net))
 				continue;
 			if (sk->sk_family == state->family)
 				goto found;
 		}
+		spin_unlock_bh(&hslot->lock);
 	}
 	sk = NULL;
 found:
@@ -1527,21 +1582,19 @@
 	struct net *net = seq_file_net(seq);
 
 	do {
-		sk = sk_next(sk);
-try_again:
-		;
+		sk = sk_nulls_next(sk);
 	} while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family));
 
-	if (!sk && ++state->bucket < UDP_HTABLE_SIZE) {
-		sk = sk_head(state->hashtable + state->bucket);
-		goto try_again;
+	if (!sk) {
+		spin_unlock_bh(&state->udp_table->hash[state->bucket].lock);
+		return udp_get_first(seq, state->bucket + 1);
 	}
 	return sk;
 }
 
 static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos)
 {
-	struct sock *sk = udp_get_first(seq);
+	struct sock *sk = udp_get_first(seq, 0);
 
 	if (sk)
 		while (pos && (sk = udp_get_next(seq, sk)) != NULL)
@@ -1550,9 +1603,7 @@
 }
 
 static void *udp_seq_start(struct seq_file *seq, loff_t *pos)
-	__acquires(udp_hash_lock)
 {
-	read_lock(&udp_hash_lock);
 	return *pos ? udp_get_idx(seq, *pos-1) : SEQ_START_TOKEN;
 }
 
@@ -1570,9 +1621,11 @@
 }
 
 static void udp_seq_stop(struct seq_file *seq, void *v)
-	__releases(udp_hash_lock)
 {
-	read_unlock(&udp_hash_lock);
+	struct udp_iter_state *state = seq->private;
+
+	if (state->bucket < UDP_HTABLE_SIZE)
+		spin_unlock_bh(&state->udp_table->hash[state->bucket].lock);
 }
 
 static int udp_seq_open(struct inode *inode, struct file *file)
@@ -1588,7 +1641,7 @@
 
 	s = ((struct seq_file *)file->private_data)->private;
 	s->family		= afinfo->family;
-	s->hashtable		= afinfo->hashtable;
+	s->udp_table		= afinfo->udp_table;
 	return err;
 }
 
@@ -1660,7 +1713,7 @@
 static struct udp_seq_afinfo udp4_seq_afinfo = {
 	.name		= "udp",
 	.family		= AF_INET,
-	.hashtable	= udp_hash,
+	.udp_table	= &udp_table,
 	.seq_fops	= {
 		.owner	=	THIS_MODULE,
 	},
@@ -1695,16 +1748,28 @@
 }
 #endif /* CONFIG_PROC_FS */
 
+void __init udp_table_init(struct udp_table *table)
+{
+	int i;
+
+	for (i = 0; i < UDP_HTABLE_SIZE; i++) {
+		INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i);
+		spin_lock_init(&table->hash[i].lock);
+	}
+}
+
 void __init udp_init(void)
 {
-	unsigned long limit;
+	unsigned long nr_pages, limit;
 
+	udp_table_init(&udp_table);
 	/* Set the pressure threshold up by the same strategy of TCP. It is a
 	 * fraction of global memory that is up to 1/2 at 256 MB, decreasing
 	 * toward zero with the amount of memory, with a floor of 128 pages.
 	 */
-	limit = min(nr_all_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
-	limit = (limit * (nr_all_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
+	nr_pages = totalram_pages - totalhigh_pages;
+	limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
+	limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
 	limit = max(limit, 128UL);
 	sysctl_udp_mem[0] = limit / 4 * 3;
 	sysctl_udp_mem[1] = limit;
@@ -1715,8 +1780,6 @@
 }
 
 EXPORT_SYMBOL(udp_disconnect);
-EXPORT_SYMBOL(udp_hash);
-EXPORT_SYMBOL(udp_hash_lock);
 EXPORT_SYMBOL(udp_ioctl);
 EXPORT_SYMBOL(udp_prot);
 EXPORT_SYMBOL(udp_sendmsg);
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h
index 2e9bad2..9f4a616 100644
--- a/net/ipv4/udp_impl.h
+++ b/net/ipv4/udp_impl.h
@@ -5,8 +5,8 @@
 #include <net/protocol.h>
 #include <net/inet_common.h>
 
-extern int  	__udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int );
-extern void 	__udp4_lib_err(struct sk_buff *, u32, struct hlist_head []);
+extern int  	__udp4_lib_rcv(struct sk_buff *, struct udp_table *, int );
+extern void 	__udp4_lib_err(struct sk_buff *, u32, struct udp_table *);
 
 extern int	udp_v4_get_port(struct sock *sk, unsigned short snum);
 
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index 3c80796..c784891 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -12,16 +12,17 @@
  */
 #include "udp_impl.h"
 
-struct hlist_head 	udplite_hash[UDP_HTABLE_SIZE];
+struct udp_table 	udplite_table;
+EXPORT_SYMBOL(udplite_table);
 
 static int udplite_rcv(struct sk_buff *skb)
 {
-	return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE);
+	return __udp4_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE);
 }
 
 static void udplite_err(struct sk_buff *skb, u32 info)
 {
-	__udp4_lib_err(skb, info, udplite_hash);
+	__udp4_lib_err(skb, info, &udplite_table);
 }
 
 static	struct net_protocol udplite_protocol = {
@@ -50,7 +51,8 @@
 	.unhash		   = udp_lib_unhash,
 	.get_port	   = udp_v4_get_port,
 	.obj_size	   = sizeof(struct udp_sock),
-	.h.udp_hash	   = udplite_hash,
+	.slab_flags	   = SLAB_DESTROY_BY_RCU,
+	.h.udp_table	   = &udplite_table,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udp_setsockopt,
 	.compat_getsockopt = compat_udp_getsockopt,
@@ -71,7 +73,7 @@
 static struct udp_seq_afinfo udplite4_seq_afinfo = {
 	.name		= "udplite",
 	.family		= AF_INET,
-	.hashtable	= udplite_hash,
+	.udp_table 	= &udplite_table,
 	.seq_fops	= {
 		.owner	=	THIS_MODULE,
 	},
@@ -108,6 +110,7 @@
 
 void __init udplite4_register(void)
 {
+	udp_table_init(&udplite_table);
 	if (proto_register(&udplite_prot, 1))
 		goto out_register_err;
 
@@ -126,5 +129,4 @@
 	printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__);
 }
 
-EXPORT_SYMBOL(udplite_hash);
 EXPORT_SYMBOL(udplite_prot);
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 390dcb1..4ec2162 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -78,7 +78,6 @@
 	struct udphdr *uh;
 	struct iphdr *iph;
 	int iphlen, len;
-	int ret;
 
 	__u8 *udpdata;
 	__be32 *udpdata32;
@@ -152,8 +151,7 @@
 	skb_reset_transport_header(skb);
 
 	/* process ESP */
-	ret = xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);
-	return ret;
+	return xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);
 
 drop:
 	kfree_skb(skb);
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index c63de0a..2ad24ba 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -18,7 +18,8 @@
 static struct dst_ops xfrm4_dst_ops;
 static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
 
-static struct dst_entry *xfrm4_dst_lookup(int tos, xfrm_address_t *saddr,
+static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos,
+					  xfrm_address_t *saddr,
 					  xfrm_address_t *daddr)
 {
 	struct flowi fl = {
@@ -36,19 +37,20 @@
 	if (saddr)
 		fl.fl4_src = saddr->a4;
 
-	err = __ip_route_output_key(&init_net, &rt, &fl);
+	err = __ip_route_output_key(net, &rt, &fl);
 	dst = &rt->u.dst;
 	if (err)
 		dst = ERR_PTR(err);
 	return dst;
 }
 
-static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
+static int xfrm4_get_saddr(struct net *net,
+			   xfrm_address_t *saddr, xfrm_address_t *daddr)
 {
 	struct dst_entry *dst;
 	struct rtable *rt;
 
-	dst = xfrm4_dst_lookup(0, NULL, daddr);
+	dst = xfrm4_dst_lookup(net, 0, NULL, daddr);
 	if (IS_ERR(dst))
 		return -EHOSTUNREACH;
 
@@ -65,7 +67,7 @@
 
 	read_lock_bh(&policy->lock);
 	for (dst = policy->bundles; dst; dst = dst->next) {
-		struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
+		struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
 		if (xdst->u.rt.fl.oif == fl->oif &&	/*XXX*/
 		    xdst->u.rt.fl.fl4_dst == fl->fl4_dst &&
 		    xdst->u.rt.fl.fl4_src == fl->fl4_src &&
@@ -187,7 +189,7 @@
 
 static inline int xfrm4_garbage_collect(struct dst_ops *ops)
 {
-	xfrm4_policy_afinfo.garbage_collect();
+	xfrm4_policy_afinfo.garbage_collect(&init_net);
 	return (atomic_read(&xfrm4_dst_ops.entries) > xfrm4_dst_ops.gc_thresh*2);
 }
 
@@ -246,7 +248,6 @@
 	.ifdown =		xfrm4_dst_ifdown,
 	.local_out =		__ip_local_out,
 	.gc_thresh =		1024,
-	.entry_size =		sizeof(struct xfrm_dst),
 	.entries =		ATOMIC_INIT(0),
 };
 
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 55dc6be..1ef1366 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -13,8 +13,6 @@
 #include <linux/ipsec.h>
 #include <linux/netfilter_ipv4.h>
 
-static struct xfrm_state_afinfo xfrm4_state_afinfo;
-
 static int xfrm4_init_flags(struct xfrm_state *x)
 {
 	if (ipv4_config.no_pmtu_disc)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d9da5eb..e92ad84 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2031,8 +2031,8 @@
 
 #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
 	if (dev->type == ARPHRD_SIT) {
+		const struct net_device_ops *ops = dev->netdev_ops;
 		struct ifreq ifr;
-		mm_segment_t	oldfs;
 		struct ip_tunnel_parm p;
 
 		err = -EADDRNOTAVAIL;
@@ -2048,9 +2048,14 @@
 		p.iph.ttl = 64;
 		ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
 
-		oldfs = get_fs(); set_fs(KERNEL_DS);
-		err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL);
-		set_fs(oldfs);
+		if (ops->ndo_do_ioctl) {
+			mm_segment_t oldfs = get_fs();
+
+			set_fs(KERNEL_DS);
+			err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
+			set_fs(oldfs);
+		} else
+			err = -EOPNOTSUPP;
 
 		if (err == 0) {
 			err = -ENOBUFS;
@@ -2988,9 +2993,8 @@
 static int if6_seq_show(struct seq_file *seq, void *v)
 {
 	struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v;
-	seq_printf(seq,
-		   NIP6_SEQFMT " %02x %02x %02x %02x %8s\n",
-		   NIP6(ifp->addr),
+	seq_printf(seq, "%pi6 %02x %02x %02x %02x %8s\n",
+		   &ifp->addr,
 		   ifp->idev->dev->ifindex,
 		   ifp->prefix_len,
 		   ifp->scope,
@@ -4033,8 +4037,8 @@
 			.data		=	&ipv6_devconf.forwarding,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&addrconf_sysctl_forward,
-			.strategy	=	&addrconf_sysctl_forward_strategy,
+			.proc_handler	=	addrconf_sysctl_forward,
+			.strategy	=	addrconf_sysctl_forward_strategy,
 		},
 		{
 			.ctl_name	=	NET_IPV6_HOP_LIMIT,
@@ -4050,7 +4054,7 @@
 			.data		=	&ipv6_devconf.mtu6,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_ACCEPT_RA,
@@ -4058,7 +4062,7 @@
 			.data		=	&ipv6_devconf.accept_ra,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_ACCEPT_REDIRECTS,
@@ -4066,7 +4070,7 @@
 			.data		=	&ipv6_devconf.accept_redirects,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_AUTOCONF,
@@ -4074,7 +4078,7 @@
 			.data		=	&ipv6_devconf.autoconf,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_DAD_TRANSMITS,
@@ -4082,7 +4086,7 @@
 			.data		=	&ipv6_devconf.dad_transmits,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_RTR_SOLICITS,
@@ -4090,7 +4094,7 @@
 			.data		=	&ipv6_devconf.rtr_solicits,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_RTR_SOLICIT_INTERVAL,
@@ -4098,8 +4102,8 @@
 			.data		=	&ipv6_devconf.rtr_solicit_interval,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec_jiffies,
-			.strategy	=	&sysctl_jiffies,
+			.proc_handler	=	proc_dointvec_jiffies,
+			.strategy	=	sysctl_jiffies,
 		},
 		{
 			.ctl_name	=	NET_IPV6_RTR_SOLICIT_DELAY,
@@ -4107,8 +4111,8 @@
 			.data		=	&ipv6_devconf.rtr_solicit_delay,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec_jiffies,
-			.strategy	=	&sysctl_jiffies,
+			.proc_handler	=	proc_dointvec_jiffies,
+			.strategy	=	sysctl_jiffies,
 		},
 		{
 			.ctl_name	=	NET_IPV6_FORCE_MLD_VERSION,
@@ -4116,7 +4120,7 @@
 			.data		=	&ipv6_devconf.force_mld_version,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 #ifdef CONFIG_IPV6_PRIVACY
 		{
@@ -4125,7 +4129,7 @@
 			.data		=	&ipv6_devconf.use_tempaddr,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_TEMP_VALID_LFT,
@@ -4133,7 +4137,7 @@
 			.data		=	&ipv6_devconf.temp_valid_lft,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_TEMP_PREFERED_LFT,
@@ -4141,7 +4145,7 @@
 			.data		=	&ipv6_devconf.temp_prefered_lft,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_REGEN_MAX_RETRY,
@@ -4149,7 +4153,7 @@
 			.data		=	&ipv6_devconf.regen_max_retry,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_MAX_DESYNC_FACTOR,
@@ -4157,7 +4161,7 @@
 			.data		=	&ipv6_devconf.max_desync_factor,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 #endif
 		{
@@ -4166,7 +4170,7 @@
 			.data		=	&ipv6_devconf.max_addresses,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_ACCEPT_RA_DEFRTR,
@@ -4174,7 +4178,7 @@
 			.data		=	&ipv6_devconf.accept_ra_defrtr,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_ACCEPT_RA_PINFO,
@@ -4182,7 +4186,7 @@
 			.data		=	&ipv6_devconf.accept_ra_pinfo,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 #ifdef CONFIG_IPV6_ROUTER_PREF
 		{
@@ -4191,7 +4195,7 @@
 			.data		=	&ipv6_devconf.accept_ra_rtr_pref,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_RTR_PROBE_INTERVAL,
@@ -4199,8 +4203,8 @@
 			.data		=	&ipv6_devconf.rtr_probe_interval,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec_jiffies,
-			.strategy	=	&sysctl_jiffies,
+			.proc_handler	=	proc_dointvec_jiffies,
+			.strategy	=	sysctl_jiffies,
 		},
 #ifdef CONFIG_IPV6_ROUTE_INFO
 		{
@@ -4209,7 +4213,7 @@
 			.data		=	&ipv6_devconf.accept_ra_rt_info_max_plen,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 #endif
 #endif
@@ -4219,7 +4223,7 @@
 			.data		=	&ipv6_devconf.proxy_ndp,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	NET_IPV6_ACCEPT_SOURCE_ROUTE,
@@ -4227,7 +4231,7 @@
 			.data		=	&ipv6_devconf.accept_source_route,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
 		{
@@ -4236,7 +4240,7 @@
 			.data           =       &ipv6_devconf.optimistic_dad,
 			.maxlen         =       sizeof(int),
 			.mode           =       0644,
-			.proc_handler   =       &proc_dointvec,
+			.proc_handler   =       proc_dointvec,
 
 		},
 #endif
@@ -4247,7 +4251,7 @@
 			.data		=	&ipv6_devconf.mc_forwarding,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 #endif
 		{
@@ -4256,7 +4260,7 @@
 			.data		=	&ipv6_devconf.disable_ipv6,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	CTL_UNNUMBERED,
@@ -4264,7 +4268,7 @@
 			.data		=	&ipv6_devconf.accept_dad,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
-			.proc_handler	=	&proc_dointvec,
+			.proc_handler	=	proc_dointvec,
 		},
 		{
 			.ctl_name	=	0,	/* sentinel */
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index 0890903..6ff73c4 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -186,10 +186,8 @@
 	label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT;
 	rcu_read_unlock();
 
-	ADDRLABEL(KERN_DEBUG "%s(addr=" NIP6_FMT ", type=%d, ifindex=%d) => %08x\n",
-			__func__,
-			NIP6(*addr), type, ifindex,
-			label);
+	ADDRLABEL(KERN_DEBUG "%s(addr=%pI6, type=%d, ifindex=%d) => %08x\n",
+		  __func__, addr, type, ifindex, label);
 
 	return label;
 }
@@ -203,11 +201,8 @@
 	struct ip6addrlbl_entry *newp;
 	int addrtype;
 
-	ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d, label=%u)\n",
-			__func__,
-			NIP6(*prefix), prefixlen,
-			ifindex,
-			(unsigned int)label);
+	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u)\n",
+		  __func__, prefix, prefixlen, ifindex, (unsigned int)label);
 
 	addrtype = ipv6_addr_type(prefix) & (IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK);
 
@@ -294,12 +289,9 @@
 	struct ip6addrlbl_entry *newp;
 	int ret = 0;
 
-	ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n",
-			__func__,
-			NIP6(*prefix), prefixlen,
-			ifindex,
-			(unsigned int)label,
-			replace);
+	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n",
+		  __func__, prefix, prefixlen, ifindex, (unsigned int)label,
+		  replace);
 
 	newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label);
 	if (IS_ERR(newp))
@@ -321,10 +313,8 @@
 	struct hlist_node *pos, *n;
 	int ret = -ESRCH;
 
-	ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d)\n",
-			__func__,
-			NIP6(*prefix), prefixlen,
-			ifindex);
+	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n",
+		  __func__, prefix, prefixlen, ifindex);
 
 	hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
 		if (p->prefixlen == prefixlen &&
@@ -347,10 +337,8 @@
 	struct in6_addr prefix_buf;
 	int ret;
 
-	ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d)\n",
-			__func__,
-			NIP6(*prefix), prefixlen,
-			ifindex);
+	ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n",
+		  __func__, prefix, prefixlen, ifindex);
 
 	ipv6_addr_prefix(&prefix_buf, prefix, prefixlen);
 	spin_lock(&ip6addrlbl_table.lock);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 01edac8..437b750 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -637,7 +637,7 @@
 		if (final_p)
 			ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+		if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) {
 			sk->sk_err_soft = -err;
 			return err;
 		}
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 2ff0c82..52449f7 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -407,6 +407,7 @@
 static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 		    int type, int code, int offset, __be32 info)
 {
+	struct net *net = dev_net(skb->dev);
 	struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
 	struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset);
 	struct xfrm_state *x;
@@ -415,12 +416,12 @@
 	    type != ICMPV6_PKT_TOOBIG)
 		return;
 
-	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6);
+	x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6);
 	if (!x)
 		return;
 
-	NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/" NIP6_FMT "\n",
-		 ntohl(ah->spi), NIP6(iph->daddr));
+	NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/%pI6\n",
+		 ntohl(ah->spi), &iph->daddr);
 
 	xfrm_state_put(x);
 }
@@ -509,9 +510,7 @@
 		return;
 
 	kfree(ahp->work_icv);
-	ahp->work_icv = NULL;
 	crypto_free_hash(ahp->tfm);
-	ahp->tfm = NULL;
 	kfree(ahp);
 }
 
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 8336cd8..1ae58be 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -512,11 +512,9 @@
 	struct ifacaddr6 *im = (struct ifacaddr6 *)v;
 	struct ac6_iter_state *state = ac6_seq_private(seq);
 
-	seq_printf(seq,
-		   "%-4d %-15s " NIP6_SEQFMT " %5d\n",
+	seq_printf(seq, "%-4d %-15s %pi6 %5d\n",
 		   state->dev->ifindex, state->dev->name,
-		   NIP6(im->aca_addr),
-		   im->aca_users);
+		   &im->aca_addr, im->aca_users);
 	return 0;
 }
 
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index e44deb8..e2bdc6d 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -175,7 +175,8 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) {
+	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
+	if (err < 0) {
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, &fl);
 		if (err < 0)
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index b181b08..c2f2501 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -356,6 +356,7 @@
 static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 		     int type, int code, int offset, __be32 info)
 {
+	struct net *net = dev_net(skb->dev);
 	struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
 	struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset);
 	struct xfrm_state *x;
@@ -364,11 +365,11 @@
 	    type != ICMPV6_PKT_TOOBIG)
 		return;
 
-	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6);
+	x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6);
 	if (!x)
 		return;
-	printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/" NIP6_FMT "\n",
-			ntohl(esph->spi), NIP6(iph->daddr));
+	printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n",
+			ntohl(esph->spi), &iph->daddr);
 	xfrm_state_put(x);
 }
 
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 6bfffec..1c7f400 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -219,7 +219,7 @@
 
 	if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
 		LIMIT_NETDEBUG(
-			KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr));
+			KERN_DEBUG "hao is not an unicast addr: %pI6\n", &hao->addr);
 		goto discard;
 	}
 
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 9b7d19a..4f43384 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -233,7 +233,7 @@
 	icmp6h->icmp6_cksum = 0;
 
 	if (skb_queue_len(&sk->sk_write_queue) == 1) {
-		skb->csum = csum_partial((char *)icmp6h,
+		skb->csum = csum_partial(icmp6h,
 					sizeof(struct icmp6hdr), skb->csum);
 		icmp6h->icmp6_cksum = csum_ipv6_magic(&fl->fl6_src,
 						      &fl->fl6_dst,
@@ -246,7 +246,7 @@
 			tmp_csum = csum_add(tmp_csum, skb->csum);
 		}
 
-		tmp_csum = csum_partial((char *)icmp6h,
+		tmp_csum = csum_partial(icmp6h,
 					sizeof(struct icmp6hdr), tmp_csum);
 		icmp6h->icmp6_cksum = csum_ipv6_magic(&fl->fl6_src,
 						      &fl->fl6_dst,
@@ -427,7 +427,7 @@
 	/* No need to clone since we're just using its address. */
 	dst2 = dst;
 
-	err = xfrm_lookup(&dst, &fl, sk, 0);
+	err = xfrm_lookup(net, &dst, &fl, sk, 0);
 	switch (err) {
 	case 0:
 		if (dst != dst2)
@@ -446,7 +446,7 @@
 	if (ip6_dst_lookup(sk, &dst2, &fl))
 		goto relookup_failed;
 
-	err = xfrm_lookup(&dst2, &fl, sk, XFRM_LOOKUP_ICMP);
+	err = xfrm_lookup(net, &dst2, &fl, sk, XFRM_LOOKUP_ICMP);
 	switch (err) {
 	case 0:
 		dst_release(dst);
@@ -552,7 +552,7 @@
 	err = ip6_dst_lookup(sk, &dst, &fl);
 	if (err)
 		goto out;
-	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+	if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0)
 		goto out;
 
 	if (ipv6_addr_is_multicast(&fl.fl6_dst))
@@ -646,9 +646,10 @@
 	int type;
 
 	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+		struct sec_path *sp = skb_sec_path(skb);
 		int nh;
 
-		if (!(skb->sp && skb->sp->xvec[skb->sp->len - 1]->props.flags &
+		if (!(sp && sp->xvec[sp->len - 1]->props.flags &
 				 XFRM_STATE_ICMP))
 			goto drop_no_count;
 
@@ -680,8 +681,8 @@
 		skb->csum = ~csum_unfold(csum_ipv6_magic(saddr, daddr, skb->len,
 					     IPPROTO_ICMPV6, 0));
 		if (__skb_checksum_complete(skb)) {
-			LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [" NIP6_FMT " > " NIP6_FMT "]\n",
-				       NIP6(*saddr), NIP6(*daddr));
+			LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%pI6 > %pI6]\n",
+				       saddr, daddr);
 			goto discard_it;
 		}
 	}
@@ -955,8 +956,8 @@
 		.data		= &init_net.ipv6.sysctl.icmpv6_time,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_ms_jiffies,
-		.strategy	= &sysctl_ms_jiffies
+		.proc_handler	= proc_dointvec_ms_jiffies,
+		.strategy	= sysctl_ms_jiffies
 	},
 	{ .ctl_name = 0 },
 };
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 16d43f2..3c3732d 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -219,7 +219,7 @@
 		if (final_p)
 			ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+		if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) {
 			sk->sk_route_caps = 0;
 			kfree_skb(skb);
 			return err;
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 1646a56..8fe267f 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -25,26 +25,30 @@
 void __inet6_hash(struct sock *sk)
 {
 	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
-	struct hlist_head *list;
-	rwlock_t *lock;
 
 	WARN_ON(!sk_unhashed(sk));
 
 	if (sk->sk_state == TCP_LISTEN) {
-		list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
-		lock = &hashinfo->lhash_lock;
-		inet_listen_wlock(hashinfo);
+		struct inet_listen_hashbucket *ilb;
+
+		ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
+		spin_lock(&ilb->lock);
+		__sk_nulls_add_node_rcu(sk, &ilb->head);
+		spin_unlock(&ilb->lock);
 	} else {
 		unsigned int hash;
+		struct hlist_nulls_head *list;
+		spinlock_t *lock;
+
 		sk->sk_hash = hash = inet6_sk_ehashfn(sk);
 		list = &inet_ehash_bucket(hashinfo, hash)->chain;
 		lock = inet_ehash_lockp(hashinfo, hash);
-		write_lock(lock);
+		spin_lock(lock);
+		__sk_nulls_add_node_rcu(sk, list);
+		spin_unlock(lock);
 	}
 
-	__sk_add_node(sk, list);
 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
-	write_unlock(lock);
 }
 EXPORT_SYMBOL(__inet6_hash);
 
@@ -63,77 +67,122 @@
 					   const int dif)
 {
 	struct sock *sk;
-	const struct hlist_node *node;
+	const struct hlist_nulls_node *node;
 	const __portpair ports = INET_COMBINED_PORTS(sport, hnum);
 	/* Optimize here for direct hit, only listening connections can
 	 * have wildcards anyways.
 	 */
 	unsigned int hash = inet6_ehashfn(net, daddr, hnum, saddr, sport);
-	struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash);
-	rwlock_t *lock = inet_ehash_lockp(hashinfo, hash);
+	unsigned int slot = hash & (hashinfo->ehash_size - 1);
+	struct inet_ehash_bucket *head = &hashinfo->ehash[slot];
 
-	prefetch(head->chain.first);
-	read_lock(lock);
-	sk_for_each(sk, node, &head->chain) {
+
+	rcu_read_lock();
+begin:
+	sk_nulls_for_each_rcu(sk, node, &head->chain) {
 		/* For IPV6 do the cheaper port and family tests first. */
-		if (INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif))
-			goto hit; /* You sunk my battleship! */
+		if (INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif)) {
+			if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt)))
+				goto begintw;
+			if (!INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif)) {
+				sock_put(sk);
+				goto begin;
+			}
+		goto out;
+		}
 	}
-	/* Must check for a TIME_WAIT'er before going to listener hash. */
-	sk_for_each(sk, node, &head->twchain) {
-		if (INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif))
-			goto hit;
-	}
-	read_unlock(lock);
-	return NULL;
+	if (get_nulls_value(node) != slot)
+		goto begin;
 
-hit:
-	sock_hold(sk);
-	read_unlock(lock);
+begintw:
+	/* Must check for a TIME_WAIT'er before going to listener hash. */
+	sk_nulls_for_each_rcu(sk, node, &head->twchain) {
+		if (INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) {
+			if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) {
+				sk = NULL;
+				goto out;
+			}
+			if (!INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) {
+				sock_put(sk);
+				goto begintw;
+			}
+			goto out;
+		}
+	}
+	if (get_nulls_value(node) != slot)
+		goto begintw;
+	sk = NULL;
+out:
+	rcu_read_unlock();
 	return sk;
 }
 EXPORT_SYMBOL(__inet6_lookup_established);
 
+static int inline compute_score(struct sock *sk, struct net *net,
+				const unsigned short hnum,
+				const struct in6_addr *daddr,
+				const int dif)
+{
+	int score = -1;
+
+	if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum &&
+	    sk->sk_family == PF_INET6) {
+		const struct ipv6_pinfo *np = inet6_sk(sk);
+
+		score = 1;
+		if (!ipv6_addr_any(&np->rcv_saddr)) {
+			if (!ipv6_addr_equal(&np->rcv_saddr, daddr))
+				return -1;
+			score++;
+		}
+		if (sk->sk_bound_dev_if) {
+			if (sk->sk_bound_dev_if != dif)
+				return -1;
+			score++;
+		}
+	}
+	return score;
+}
+
 struct sock *inet6_lookup_listener(struct net *net,
 		struct inet_hashinfo *hashinfo, const struct in6_addr *daddr,
 		const unsigned short hnum, const int dif)
 {
 	struct sock *sk;
-	const struct hlist_node *node;
-	struct sock *result = NULL;
-	int score, hiscore = 0;
+	const struct hlist_nulls_node *node;
+	struct sock *result;
+	int score, hiscore;
+	unsigned int hash = inet_lhashfn(net, hnum);
+	struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
 
-	read_lock(&hashinfo->lhash_lock);
-	sk_for_each(sk, node,
-			&hashinfo->listening_hash[inet_lhashfn(net, hnum)]) {
-		if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum &&
-				sk->sk_family == PF_INET6) {
-			const struct ipv6_pinfo *np = inet6_sk(sk);
-
-			score = 1;
-			if (!ipv6_addr_any(&np->rcv_saddr)) {
-				if (!ipv6_addr_equal(&np->rcv_saddr, daddr))
-					continue;
-				score++;
-			}
-			if (sk->sk_bound_dev_if) {
-				if (sk->sk_bound_dev_if != dif)
-					continue;
-				score++;
-			}
-			if (score == 3) {
-				result = sk;
-				break;
-			}
-			if (score > hiscore) {
-				hiscore = score;
-				result = sk;
-			}
+	rcu_read_lock();
+begin:
+	result = NULL;
+	hiscore = -1;
+	sk_nulls_for_each(sk, node, &ilb->head) {
+		score = compute_score(sk, net, hnum, daddr, dif);
+		if (score > hiscore) {
+			hiscore = score;
+			result = sk;
 		}
 	}
-	if (result)
-		sock_hold(result);
-	read_unlock(&hashinfo->lhash_lock);
+	/*
+	 * if the nulls value we got at the end of this lookup is
+	 * not the expected one, we must restart lookup.
+	 * We probably met an item that was moved to another chain.
+	 */
+	if (get_nulls_value(node) != hash + LISTENING_NULLS_BASE)
+		goto begin;
+	if (result) {
+		if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt)))
+			result = NULL;
+		else if (unlikely(compute_score(result, net, hnum, daddr,
+				  dif) < hiscore)) {
+			sock_put(result);
+			goto begin;
+		}
+	}
+	rcu_read_unlock();
 	return result;
 }
 
@@ -170,16 +219,15 @@
 	const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr,
 						inet->dport);
 	struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
-	rwlock_t *lock = inet_ehash_lockp(hinfo, hash);
+	spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
 	struct sock *sk2;
-	const struct hlist_node *node;
+	const struct hlist_nulls_node *node;
 	struct inet_timewait_sock *tw;
 
-	prefetch(head->chain.first);
-	write_lock(lock);
+	spin_lock(lock);
 
 	/* Check TIME-WAIT sockets first. */
-	sk_for_each(sk2, node, &head->twchain) {
+	sk_nulls_for_each(sk2, node, &head->twchain) {
 		tw = inet_twsk(sk2);
 
 		if (INET6_TW_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) {
@@ -192,7 +240,7 @@
 	tw = NULL;
 
 	/* And established part... */
-	sk_for_each(sk2, node, &head->chain) {
+	sk_nulls_for_each(sk2, node, &head->chain) {
 		if (INET6_MATCH(sk2, net, hash, saddr, daddr, ports, dif))
 			goto not_unique;
 	}
@@ -203,10 +251,10 @@
 	inet->num = lport;
 	inet->sport = htons(lport);
 	WARN_ON(!sk_unhashed(sk));
-	__sk_add_node(sk, &head->chain);
+	__sk_nulls_add_node_rcu(sk, &head->chain);
 	sk->sk_hash = hash;
+	spin_unlock(lock);
 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
-	write_unlock(lock);
 
 	if (twp != NULL) {
 		*twp = tw;
@@ -221,7 +269,7 @@
 	return 0;
 
 not_unique:
-	write_unlock(lock);
+	spin_unlock(lock);
 	return -EADDRNOTAVAIL;
 }
 
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 37a4e77..c62dd24 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -388,7 +388,7 @@
 		fl->owner = current->pid;
 		break;
 	case IPV6_FL_S_USER:
-		fl->owner = current->euid;
+		fl->owner = current_euid();
 		break;
 	default:
 		err = -EINVAL;
@@ -464,7 +464,7 @@
 
 int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
 {
-	int err;
+	int uninitialized_var(err);
 	struct net *net = sock_net(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct in6_flowlabel_req freq;
@@ -696,14 +696,14 @@
 	else {
 		struct ip6_flowlabel *fl = v;
 		seq_printf(seq,
-			   "%05X %-1d %-6d %-6d %-6ld %-8ld " NIP6_SEQFMT " %-4d\n",
+			   "%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n",
 			   (unsigned)ntohl(fl->label),
 			   fl->share,
 			   (unsigned)fl->owner,
 			   atomic_read(&fl->users),
 			   fl->linger/HZ,
 			   (long)(fl->expires - jiffies)/HZ,
-			   NIP6(fl->dst),
+			   &fl->dst,
 			   fl->opt ? fl->opt->opt_nflen : 0);
 	}
 	return 0;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index c77db0b..4b15938 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -137,7 +137,8 @@
 		struct inet6_dev *idev = ip6_dst_idev(skb->dst);
 
 		if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) &&
-		    ((mroute6_socket && !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
+		    ((mroute6_socket(dev_net(dev)) &&
+		     !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
 		     ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
 					 &ipv6_hdr(skb)->saddr))) {
 			struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
@@ -490,7 +491,7 @@
 	   We don't send redirects to frames decapsulated from IPsec.
 	 */
 	if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0 &&
-	    !skb->sp) {
+	    !skb_sec_path(skb)) {
 		struct in6_addr *target = NULL;
 		struct rt6_info *rt;
 		struct neighbour *n = dst->neighbour;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 64ce3d3..58e2b0d 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -74,8 +74,8 @@
 		     (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
 		    (HASH_SIZE - 1))
 
-static int ip6_fb_tnl_dev_init(struct net_device *dev);
-static int ip6_tnl_dev_init(struct net_device *dev);
+static void ip6_fb_tnl_dev_init(struct net_device *dev);
+static void ip6_tnl_dev_init(struct net_device *dev);
 static void ip6_tnl_dev_setup(struct net_device *dev);
 
 static int ip6_tnl_net_id;
@@ -249,7 +249,7 @@
 	}
 
 	t = netdev_priv(dev);
-	dev->init = ip6_tnl_dev_init;
+	ip6_tnl_dev_init(dev);
 	t->parms = *p;
 
 	if ((err = register_netdevice(dev)) < 0)
@@ -846,6 +846,7 @@
 			 int encap_limit,
 			 __u32 *pmtu)
 {
+	struct net *net = dev_net(dev);
 	struct ip6_tnl *t = netdev_priv(dev);
 	struct net_device_stats *stats = &t->dev->stats;
 	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
@@ -861,9 +862,9 @@
 	if ((dst = ip6_tnl_dst_check(t)) != NULL)
 		dst_hold(dst);
 	else {
-		dst = ip6_route_output(dev_net(dev), NULL, fl);
+		dst = ip6_route_output(net, NULL, fl);
 
-		if (dst->error || xfrm_lookup(&dst, fl, NULL, 0) < 0)
+		if (dst->error || xfrm_lookup(net, &dst, fl, NULL, 0) < 0)
 			goto tx_err_link_failure;
 	}
 
@@ -1150,7 +1151,6 @@
  * ip6_tnl_change - update the tunnel parameters
  *   @t: tunnel to be changed
  *   @p: tunnel configuration parameters
- *   @active: != 0 if tunnel is ready for use
  *
  * Description:
  *   ip6_tnl_change() updates the tunnel parameters
@@ -1306,6 +1306,14 @@
 	return 0;
 }
 
+
+static const struct net_device_ops ip6_tnl_netdev_ops = {
+	.ndo_uninit = ip6_tnl_dev_uninit,
+	.ndo_start_xmit = ip6_tnl_xmit,
+	.ndo_do_ioctl = ip6_tnl_ioctl,
+	.ndo_change_mtu = ip6_tnl_change_mtu,
+};
+
 /**
  * ip6_tnl_dev_setup - setup virtual tunnel device
  *   @dev: virtual device associated with tunnel
@@ -1316,11 +1324,8 @@
 
 static void ip6_tnl_dev_setup(struct net_device *dev)
 {
-	dev->uninit = ip6_tnl_dev_uninit;
+	dev->netdev_ops = &ip6_tnl_netdev_ops;
 	dev->destructor = free_netdev;
-	dev->hard_start_xmit = ip6_tnl_xmit;
-	dev->do_ioctl = ip6_tnl_ioctl;
-	dev->change_mtu = ip6_tnl_change_mtu;
 
 	dev->type = ARPHRD_TUNNEL6;
 	dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
@@ -1349,13 +1354,11 @@
  *   @dev: virtual device associated with tunnel
  **/
 
-static int
-ip6_tnl_dev_init(struct net_device *dev)
+static void ip6_tnl_dev_init(struct net_device *dev)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
 	ip6_tnl_dev_init_gen(dev);
 	ip6_tnl_link_config(t);
-	return 0;
 }
 
 /**
@@ -1365,8 +1368,7 @@
  * Return: 0
  **/
 
-static int
-ip6_fb_tnl_dev_init(struct net_device *dev)
+static void ip6_fb_tnl_dev_init(struct net_device *dev)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
 	struct net *net = dev_net(dev);
@@ -1376,7 +1378,6 @@
 	t->parms.proto = IPPROTO_IPV6;
 	dev_hold(dev);
 	ip6n->tnls_wc[0] = t;
-	return 0;
 }
 
 static struct xfrm6_tunnel ip4ip6_handler = {
@@ -1428,10 +1429,10 @@
 
 	if (!ip6n->fb_tnl_dev)
 		goto err_alloc_dev;
-
-	ip6n->fb_tnl_dev->init = ip6_fb_tnl_dev_init;
 	dev_net_set(ip6n->fb_tnl_dev, net);
 
+	ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
+
 	err = register_netdev(ip6n->fb_tnl_dev);
 	if (err < 0)
 		goto err_register;
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 0524769..3c51b2d 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -49,9 +49,6 @@
 #include <net/addrconf.h>
 #include <linux/netfilter_ipv6.h>
 
-struct sock *mroute6_socket;
-
-
 /* Big lock, protecting vif table, mrt cache and mroute socket state.
    Note that the changes are semaphored via rtnl_lock.
  */
@@ -62,22 +59,9 @@
  *	Multicast router control variables
  */
 
-static struct mif_device vif6_table[MAXMIFS];		/* Devices 		*/
-static int maxvif;
-
-#define MIF_EXISTS(idx) (vif6_table[idx].dev != NULL)
-
-static int mroute_do_assert;				/* Set in PIM assert	*/
-#ifdef CONFIG_IPV6_PIMSM_V2
-static int mroute_do_pim;
-#else
-#define mroute_do_pim 0
-#endif
-
-static struct mfc6_cache *mfc6_cache_array[MFC6_LINES];	/* Forwarding cache	*/
+#define MIF_EXISTS(_net, _idx) ((_net)->ipv6.vif6_table[_idx].dev != NULL)
 
 static struct mfc6_cache *mfc_unres_queue;		/* Queue of unresolved entries */
-static atomic_t cache_resolve_queue_len;		/* Size of unresolved	*/
 
 /* Special spinlock for queue of unresolved entries */
 static DEFINE_SPINLOCK(mfc_unres_lock);
@@ -93,8 +77,10 @@
 static struct kmem_cache *mrt_cachep __read_mostly;
 
 static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache);
-static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert);
+static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt,
+			      mifi_t mifi, int assert);
 static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm);
+static void mroute_clean_tables(struct net *net);
 
 #ifdef CONFIG_IPV6_PIMSM_V2
 static struct inet6_protocol pim6_protocol;
@@ -106,19 +92,22 @@
 #ifdef CONFIG_PROC_FS
 
 struct ipmr_mfc_iter {
+	struct seq_net_private p;
 	struct mfc6_cache **cache;
 	int ct;
 };
 
 
-static struct mfc6_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos)
+static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
+					   struct ipmr_mfc_iter *it, loff_t pos)
 {
 	struct mfc6_cache *mfc;
 
-	it->cache = mfc6_cache_array;
+	it->cache = net->ipv6.mfc6_cache_array;
 	read_lock(&mrt_lock);
-	for (it->ct = 0; it->ct < ARRAY_SIZE(mfc6_cache_array); it->ct++)
-		for (mfc = mfc6_cache_array[it->ct]; mfc; mfc = mfc->next)
+	for (it->ct = 0; it->ct < MFC6_LINES; it->ct++)
+		for (mfc = net->ipv6.mfc6_cache_array[it->ct];
+		     mfc; mfc = mfc->next)
 			if (pos-- == 0)
 				return mfc;
 	read_unlock(&mrt_lock);
@@ -126,7 +115,8 @@
 	it->cache = &mfc_unres_queue;
 	spin_lock_bh(&mfc_unres_lock);
 	for (mfc = mfc_unres_queue; mfc; mfc = mfc->next)
-		if (pos-- == 0)
+		if (net_eq(mfc6_net(mfc), net) &&
+		    pos-- == 0)
 			return mfc;
 	spin_unlock_bh(&mfc_unres_lock);
 
@@ -142,17 +132,19 @@
  */
 
 struct ipmr_vif_iter {
+	struct seq_net_private p;
 	int ct;
 };
 
-static struct mif_device *ip6mr_vif_seq_idx(struct ipmr_vif_iter *iter,
+static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
+					    struct ipmr_vif_iter *iter,
 					    loff_t pos)
 {
-	for (iter->ct = 0; iter->ct < maxvif; ++iter->ct) {
-		if (!MIF_EXISTS(iter->ct))
+	for (iter->ct = 0; iter->ct < net->ipv6.maxvif; ++iter->ct) {
+		if (!MIF_EXISTS(net, iter->ct))
 			continue;
 		if (pos-- == 0)
-			return &vif6_table[iter->ct];
+			return &net->ipv6.vif6_table[iter->ct];
 	}
 	return NULL;
 }
@@ -160,23 +152,26 @@
 static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
 	__acquires(mrt_lock)
 {
+	struct net *net = seq_file_net(seq);
+
 	read_lock(&mrt_lock);
-	return (*pos ? ip6mr_vif_seq_idx(seq->private, *pos - 1)
-		: SEQ_START_TOKEN);
+	return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1)
+		: SEQ_START_TOKEN;
 }
 
 static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	struct ipmr_vif_iter *iter = seq->private;
+	struct net *net = seq_file_net(seq);
 
 	++*pos;
 	if (v == SEQ_START_TOKEN)
-		return ip6mr_vif_seq_idx(iter, 0);
+		return ip6mr_vif_seq_idx(net, iter, 0);
 
-	while (++iter->ct < maxvif) {
-		if (!MIF_EXISTS(iter->ct))
+	while (++iter->ct < net->ipv6.maxvif) {
+		if (!MIF_EXISTS(net, iter->ct))
 			continue;
-		return &vif6_table[iter->ct];
+		return &net->ipv6.vif6_table[iter->ct];
 	}
 	return NULL;
 }
@@ -189,6 +184,8 @@
 
 static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
 {
+	struct net *net = seq_file_net(seq);
+
 	if (v == SEQ_START_TOKEN) {
 		seq_puts(seq,
 			 "Interface      BytesIn  PktsIn  BytesOut PktsOut Flags\n");
@@ -198,7 +195,7 @@
 
 		seq_printf(seq,
 			   "%2td %-10s %8ld %7ld  %8ld %7ld %05X\n",
-			   vif - vif6_table,
+			   vif - net->ipv6.vif6_table,
 			   name, vif->bytes_in, vif->pkt_in,
 			   vif->bytes_out, vif->pkt_out,
 			   vif->flags);
@@ -215,8 +212,8 @@
 
 static int ip6mr_vif_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &ip6mr_vif_seq_ops,
-				sizeof(struct ipmr_vif_iter));
+	return seq_open_net(inode, file, &ip6mr_vif_seq_ops,
+			    sizeof(struct ipmr_vif_iter));
 }
 
 static struct file_operations ip6mr_vif_fops = {
@@ -224,24 +221,27 @@
 	.open    = ip6mr_vif_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release_private,
+	.release = seq_release_net,
 };
 
 static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
 {
-	return (*pos ? ipmr_mfc_seq_idx(seq->private, *pos - 1)
-		: SEQ_START_TOKEN);
+	struct net *net = seq_file_net(seq);
+
+	return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
+		: SEQ_START_TOKEN;
 }
 
 static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	struct mfc6_cache *mfc = v;
 	struct ipmr_mfc_iter *it = seq->private;
+	struct net *net = seq_file_net(seq);
 
 	++*pos;
 
 	if (v == SEQ_START_TOKEN)
-		return ipmr_mfc_seq_idx(seq->private, 0);
+		return ipmr_mfc_seq_idx(net, seq->private, 0);
 
 	if (mfc->next)
 		return mfc->next;
@@ -249,10 +249,10 @@
 	if (it->cache == &mfc_unres_queue)
 		goto end_of_list;
 
-	BUG_ON(it->cache != mfc6_cache_array);
+	BUG_ON(it->cache != net->ipv6.mfc6_cache_array);
 
-	while (++it->ct < ARRAY_SIZE(mfc6_cache_array)) {
-		mfc = mfc6_cache_array[it->ct];
+	while (++it->ct < MFC6_LINES) {
+		mfc = net->ipv6.mfc6_cache_array[it->ct];
 		if (mfc)
 			return mfc;
 	}
@@ -277,16 +277,18 @@
 static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
 {
 	struct ipmr_mfc_iter *it = seq->private;
+	struct net *net = seq_file_net(seq);
 
 	if (it->cache == &mfc_unres_queue)
 		spin_unlock_bh(&mfc_unres_lock);
-	else if (it->cache == mfc6_cache_array)
+	else if (it->cache == net->ipv6.mfc6_cache_array)
 		read_unlock(&mrt_lock);
 }
 
 static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
 {
 	int n;
+	struct net *net = seq_file_net(seq);
 
 	if (v == SEQ_START_TOKEN) {
 		seq_puts(seq,
@@ -297,23 +299,28 @@
 		const struct mfc6_cache *mfc = v;
 		const struct ipmr_mfc_iter *it = seq->private;
 
-		seq_printf(seq,
-			   NIP6_FMT " " NIP6_FMT " %-3d %8ld %8ld %8ld",
-			   NIP6(mfc->mf6c_mcastgrp), NIP6(mfc->mf6c_origin),
-			   mfc->mf6c_parent,
-			   mfc->mfc_un.res.pkt,
-			   mfc->mfc_un.res.bytes,
-			   mfc->mfc_un.res.wrong_if);
+		seq_printf(seq, "%pI6 %pI6 %-3hd",
+			   &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
+			   mfc->mf6c_parent);
 
 		if (it->cache != &mfc_unres_queue) {
+			seq_printf(seq, " %8lu %8lu %8lu",
+				   mfc->mfc_un.res.pkt,
+				   mfc->mfc_un.res.bytes,
+				   mfc->mfc_un.res.wrong_if);
 			for (n = mfc->mfc_un.res.minvif;
 			     n < mfc->mfc_un.res.maxvif; n++) {
-				if (MIF_EXISTS(n) &&
+				if (MIF_EXISTS(net, n) &&
 				    mfc->mfc_un.res.ttls[n] < 255)
 					seq_printf(seq,
 						   " %2d:%-3d",
 						   n, mfc->mfc_un.res.ttls[n]);
 			}
+		} else {
+			/* unresolved mfc_caches don't contain
+			 * pkt, bytes and wrong_if values
+			 */
+			seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
 		}
 		seq_putc(seq, '\n');
 	}
@@ -329,8 +336,8 @@
 
 static int ipmr_mfc_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &ipmr_mfc_seq_ops,
-				sizeof(struct ipmr_mfc_iter));
+	return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
+			    sizeof(struct ipmr_mfc_iter));
 }
 
 static struct file_operations ip6mr_mfc_fops = {
@@ -338,18 +345,19 @@
 	.open    = ipmr_mfc_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release_private,
+	.release = seq_release_net,
 };
 #endif
 
 #ifdef CONFIG_IPV6_PIMSM_V2
-static int reg_vif_num = -1;
 
 static int pim6_rcv(struct sk_buff *skb)
 {
 	struct pimreghdr *pim;
 	struct ipv6hdr   *encap;
 	struct net_device  *reg_dev = NULL;
+	struct net *net = dev_net(skb->dev);
+	int reg_vif_num = net->ipv6.mroute_reg_vif_num;
 
 	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
 		goto drop;
@@ -372,7 +380,7 @@
 
 	read_lock(&mrt_lock);
 	if (reg_vif_num >= 0)
-		reg_dev = vif6_table[reg_vif_num].dev;
+		reg_dev = net->ipv6.vif6_table[reg_vif_num].dev;
 	if (reg_dev)
 		dev_hold(reg_dev);
 	read_unlock(&mrt_lock);
@@ -408,25 +416,32 @@
 
 static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	struct net *net = dev_net(dev);
+
 	read_lock(&mrt_lock);
 	dev->stats.tx_bytes += skb->len;
 	dev->stats.tx_packets++;
-	ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT);
+	ip6mr_cache_report(net, skb, net->ipv6.mroute_reg_vif_num,
+			   MRT6MSG_WHOLEPKT);
 	read_unlock(&mrt_lock);
 	kfree_skb(skb);
 	return 0;
 }
 
+static const struct net_device_ops reg_vif_netdev_ops = {
+	.ndo_start_xmit	= reg_vif_xmit,
+};
+
 static void reg_vif_setup(struct net_device *dev)
 {
 	dev->type		= ARPHRD_PIMREG;
 	dev->mtu		= 1500 - sizeof(struct ipv6hdr) - 8;
 	dev->flags		= IFF_NOARP;
-	dev->hard_start_xmit	= reg_vif_xmit;
+	dev->netdev_ops		= &reg_vif_netdev_ops;
 	dev->destructor		= free_netdev;
 }
 
-static struct net_device *ip6mr_reg_vif(void)
+static struct net_device *ip6mr_reg_vif(struct net *net)
 {
 	struct net_device *dev;
 
@@ -434,6 +449,8 @@
 	if (dev == NULL)
 		return NULL;
 
+	dev_net_set(dev, net);
+
 	if (register_netdevice(dev)) {
 		free_netdev(dev);
 		return NULL;
@@ -460,14 +477,14 @@
  *	Delete a VIF entry
  */
 
-static int mif6_delete(int vifi)
+static int mif6_delete(struct net *net, int vifi)
 {
 	struct mif_device *v;
 	struct net_device *dev;
-	if (vifi < 0 || vifi >= maxvif)
+	if (vifi < 0 || vifi >= net->ipv6.maxvif)
 		return -EADDRNOTAVAIL;
 
-	v = &vif6_table[vifi];
+	v = &net->ipv6.vif6_table[vifi];
 
 	write_lock_bh(&mrt_lock);
 	dev = v->dev;
@@ -479,17 +496,17 @@
 	}
 
 #ifdef CONFIG_IPV6_PIMSM_V2
-	if (vifi == reg_vif_num)
-		reg_vif_num = -1;
+	if (vifi == net->ipv6.mroute_reg_vif_num)
+		net->ipv6.mroute_reg_vif_num = -1;
 #endif
 
-	if (vifi + 1 == maxvif) {
+	if (vifi + 1 == net->ipv6.maxvif) {
 		int tmp;
 		for (tmp = vifi - 1; tmp >= 0; tmp--) {
-			if (MIF_EXISTS(tmp))
+			if (MIF_EXISTS(net, tmp))
 				break;
 		}
-		maxvif = tmp + 1;
+		net->ipv6.maxvif = tmp + 1;
 	}
 
 	write_unlock_bh(&mrt_lock);
@@ -503,6 +520,12 @@
 	return 0;
 }
 
+static inline void ip6mr_cache_free(struct mfc6_cache *c)
+{
+	release_net(mfc6_net(c));
+	kmem_cache_free(mrt_cachep, c);
+}
+
 /* Destroy an unresolved cache entry, killing queued skbs
    and reporting error to netlink readers.
  */
@@ -510,8 +533,9 @@
 static void ip6mr_destroy_unres(struct mfc6_cache *c)
 {
 	struct sk_buff *skb;
+	struct net *net = mfc6_net(c);
 
-	atomic_dec(&cache_resolve_queue_len);
+	atomic_dec(&net->ipv6.cache_resolve_queue_len);
 
 	while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) {
 		if (ipv6_hdr(skb)->version == 0) {
@@ -520,12 +544,12 @@
 			nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
 			skb_trim(skb, nlh->nlmsg_len);
 			((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -ETIMEDOUT;
-			rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid);
+			rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
 		} else
 			kfree_skb(skb);
 	}
 
-	kmem_cache_free(mrt_cachep, c);
+	ip6mr_cache_free(c);
 }
 
 
@@ -553,7 +577,7 @@
 		ip6mr_destroy_unres(c);
 	}
 
-	if (atomic_read(&cache_resolve_queue_len))
+	if (mfc_unres_queue != NULL)
 		mod_timer(&ipmr_expire_timer, jiffies + expires);
 }
 
@@ -564,7 +588,7 @@
 		return;
 	}
 
-	if (atomic_read(&cache_resolve_queue_len))
+	if (mfc_unres_queue != NULL)
 		ipmr_do_expire_process(dummy);
 
 	spin_unlock(&mfc_unres_lock);
@@ -575,13 +599,15 @@
 static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttls)
 {
 	int vifi;
+	struct net *net = mfc6_net(cache);
 
 	cache->mfc_un.res.minvif = MAXMIFS;
 	cache->mfc_un.res.maxvif = 0;
 	memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
 
-	for (vifi = 0; vifi < maxvif; vifi++) {
-		if (MIF_EXISTS(vifi) && ttls[vifi] && ttls[vifi] < 255) {
+	for (vifi = 0; vifi < net->ipv6.maxvif; vifi++) {
+		if (MIF_EXISTS(net, vifi) &&
+		    ttls[vifi] && ttls[vifi] < 255) {
 			cache->mfc_un.res.ttls[vifi] = ttls[vifi];
 			if (cache->mfc_un.res.minvif > vifi)
 				cache->mfc_un.res.minvif = vifi;
@@ -591,15 +617,15 @@
 	}
 }
 
-static int mif6_add(struct mif6ctl *vifc, int mrtsock)
+static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
 {
 	int vifi = vifc->mif6c_mifi;
-	struct mif_device *v = &vif6_table[vifi];
+	struct mif_device *v = &net->ipv6.vif6_table[vifi];
 	struct net_device *dev;
 	int err;
 
 	/* Is vif busy ? */
-	if (MIF_EXISTS(vifi))
+	if (MIF_EXISTS(net, vifi))
 		return -EADDRINUSE;
 
 	switch (vifc->mif6c_flags) {
@@ -609,9 +635,9 @@
 		 * Special Purpose VIF in PIM
 		 * All the packets will be sent to the daemon
 		 */
-		if (reg_vif_num >= 0)
+		if (net->ipv6.mroute_reg_vif_num >= 0)
 			return -EADDRINUSE;
-		dev = ip6mr_reg_vif();
+		dev = ip6mr_reg_vif(net);
 		if (!dev)
 			return -ENOBUFS;
 		err = dev_set_allmulti(dev, 1);
@@ -623,7 +649,7 @@
 		break;
 #endif
 	case 0:
-		dev = dev_get_by_index(&init_net, vifc->mif6c_pifi);
+		dev = dev_get_by_index(net, vifc->mif6c_pifi);
 		if (!dev)
 			return -EADDRNOTAVAIL;
 		err = dev_set_allmulti(dev, 1);
@@ -657,20 +683,22 @@
 	v->dev = dev;
 #ifdef CONFIG_IPV6_PIMSM_V2
 	if (v->flags & MIFF_REGISTER)
-		reg_vif_num = vifi;
+		net->ipv6.mroute_reg_vif_num = vifi;
 #endif
-	if (vifi + 1 > maxvif)
-		maxvif = vifi + 1;
+	if (vifi + 1 > net->ipv6.maxvif)
+		net->ipv6.maxvif = vifi + 1;
 	write_unlock_bh(&mrt_lock);
 	return 0;
 }
 
-static struct mfc6_cache *ip6mr_cache_find(struct in6_addr *origin, struct in6_addr *mcastgrp)
+static struct mfc6_cache *ip6mr_cache_find(struct net *net,
+					   struct in6_addr *origin,
+					   struct in6_addr *mcastgrp)
 {
 	int line = MFC6_HASH(mcastgrp, origin);
 	struct mfc6_cache *c;
 
-	for (c = mfc6_cache_array[line]; c; c = c->next) {
+	for (c = net->ipv6.mfc6_cache_array[line]; c; c = c->next) {
 		if (ipv6_addr_equal(&c->mf6c_origin, origin) &&
 		    ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp))
 			break;
@@ -681,24 +709,24 @@
 /*
  *	Allocate a multicast cache entry
  */
-static struct mfc6_cache *ip6mr_cache_alloc(void)
+static struct mfc6_cache *ip6mr_cache_alloc(struct net *net)
 {
-	struct mfc6_cache *c = kmem_cache_alloc(mrt_cachep, GFP_KERNEL);
+	struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
 	if (c == NULL)
 		return NULL;
-	memset(c, 0, sizeof(*c));
 	c->mfc_un.res.minvif = MAXMIFS;
+	mfc6_net_set(c, net);
 	return c;
 }
 
-static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
+static struct mfc6_cache *ip6mr_cache_alloc_unres(struct net *net)
 {
-	struct mfc6_cache *c = kmem_cache_alloc(mrt_cachep, GFP_ATOMIC);
+	struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
 	if (c == NULL)
 		return NULL;
-	memset(c, 0, sizeof(*c));
 	skb_queue_head_init(&c->mfc_un.unres.unresolved);
 	c->mfc_un.unres.expires = jiffies + 10 * HZ;
+	mfc6_net_set(c, net);
 	return c;
 }
 
@@ -727,7 +755,7 @@
 				skb_trim(skb, nlh->nlmsg_len);
 				((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE;
 			}
-			err = rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid);
+			err = rtnl_unicast(skb, mfc6_net(uc), NETLINK_CB(skb).pid);
 		} else
 			ip6_mr_forward(skb, c);
 	}
@@ -740,7 +768,8 @@
  *	Called under mrt_lock.
  */
 
-static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert)
+static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
+			      int assert)
 {
 	struct sk_buff *skb;
 	struct mrt6msg *msg;
@@ -776,7 +805,7 @@
 		msg = (struct mrt6msg *)skb_transport_header(skb);
 		msg->im6_mbz = 0;
 		msg->im6_msgtype = MRT6MSG_WHOLEPKT;
-		msg->im6_mif = reg_vif_num;
+		msg->im6_mif = net->ipv6.mroute_reg_vif_num;
 		msg->im6_pad = 0;
 		ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr);
 		ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr);
@@ -813,7 +842,7 @@
 	skb_pull(skb, sizeof(struct ipv6hdr));
 	}
 
-	if (mroute6_socket == NULL) {
+	if (net->ipv6.mroute6_sk == NULL) {
 		kfree_skb(skb);
 		return -EINVAL;
 	}
@@ -821,7 +850,8 @@
 	/*
 	 *	Deliver to user space multicast routing algorithms
 	 */
-	if ((ret = sock_queue_rcv_skb(mroute6_socket, skb)) < 0) {
+	ret = sock_queue_rcv_skb(net->ipv6.mroute6_sk, skb);
+	if (ret < 0) {
 		if (net_ratelimit())
 			printk(KERN_WARNING "mroute6: pending queue full, dropping entries.\n");
 		kfree_skb(skb);
@@ -835,14 +865,15 @@
  */
 
 static int
-ip6mr_cache_unresolved(mifi_t mifi, struct sk_buff *skb)
+ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb)
 {
 	int err;
 	struct mfc6_cache *c;
 
 	spin_lock_bh(&mfc_unres_lock);
 	for (c = mfc_unres_queue; c; c = c->next) {
-		if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
+		if (net_eq(mfc6_net(c), net) &&
+		    ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
 		    ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr))
 			break;
 	}
@@ -852,8 +883,8 @@
 		 *	Create a new entry if allowable
 		 */
 
-		if (atomic_read(&cache_resolve_queue_len) >= 10 ||
-		    (c = ip6mr_cache_alloc_unres()) == NULL) {
+		if (atomic_read(&net->ipv6.cache_resolve_queue_len) >= 10 ||
+		    (c = ip6mr_cache_alloc_unres(net)) == NULL) {
 			spin_unlock_bh(&mfc_unres_lock);
 
 			kfree_skb(skb);
@@ -870,18 +901,19 @@
 		/*
 		 *	Reflect first query at pim6sd
 		 */
-		if ((err = ip6mr_cache_report(skb, mifi, MRT6MSG_NOCACHE)) < 0) {
+		err = ip6mr_cache_report(net, skb, mifi, MRT6MSG_NOCACHE);
+		if (err < 0) {
 			/* If the report failed throw the cache entry
 			   out - Brad Parker
 			 */
 			spin_unlock_bh(&mfc_unres_lock);
 
-			kmem_cache_free(mrt_cachep, c);
+			ip6mr_cache_free(c);
 			kfree_skb(skb);
 			return err;
 		}
 
-		atomic_inc(&cache_resolve_queue_len);
+		atomic_inc(&net->ipv6.cache_resolve_queue_len);
 		c->next = mfc_unres_queue;
 		mfc_unres_queue = c;
 
@@ -907,21 +939,22 @@
  *	MFC6 cache manipulation by user space
  */
 
-static int ip6mr_mfc_delete(struct mf6cctl *mfc)
+static int ip6mr_mfc_delete(struct net *net, struct mf6cctl *mfc)
 {
 	int line;
 	struct mfc6_cache *c, **cp;
 
 	line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
 
-	for (cp = &mfc6_cache_array[line]; (c = *cp) != NULL; cp = &c->next) {
+	for (cp = &net->ipv6.mfc6_cache_array[line];
+	     (c = *cp) != NULL; cp = &c->next) {
 		if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
 		    ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) {
 			write_lock_bh(&mrt_lock);
 			*cp = c->next;
 			write_unlock_bh(&mrt_lock);
 
-			kmem_cache_free(mrt_cachep, c);
+			ip6mr_cache_free(c);
 			return 0;
 		}
 	}
@@ -932,19 +965,17 @@
 			      unsigned long event, void *ptr)
 {
 	struct net_device *dev = ptr;
+	struct net *net = dev_net(dev);
 	struct mif_device *v;
 	int ct;
 
-	if (!net_eq(dev_net(dev), &init_net))
-		return NOTIFY_DONE;
-
 	if (event != NETDEV_UNREGISTER)
 		return NOTIFY_DONE;
 
-	v = &vif6_table[0];
-	for (ct = 0; ct < maxvif; ct++, v++) {
+	v = &net->ipv6.vif6_table[0];
+	for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) {
 		if (v->dev == dev)
-			mif6_delete(ct);
+			mif6_delete(net, ct);
 	}
 	return NOTIFY_DONE;
 }
@@ -957,6 +988,66 @@
  *	Setup for IP multicast routing
  */
 
+static int __net_init ip6mr_net_init(struct net *net)
+{
+	int err = 0;
+	net->ipv6.vif6_table = kcalloc(MAXMIFS, sizeof(struct mif_device),
+				       GFP_KERNEL);
+	if (!net->ipv6.vif6_table) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	/* Forwarding cache */
+	net->ipv6.mfc6_cache_array = kcalloc(MFC6_LINES,
+					     sizeof(struct mfc6_cache *),
+					     GFP_KERNEL);
+	if (!net->ipv6.mfc6_cache_array) {
+		err = -ENOMEM;
+		goto fail_mfc6_cache;
+	}
+
+#ifdef CONFIG_IPV6_PIMSM_V2
+	net->ipv6.mroute_reg_vif_num = -1;
+#endif
+
+#ifdef CONFIG_PROC_FS
+	err = -ENOMEM;
+	if (!proc_net_fops_create(net, "ip6_mr_vif", 0, &ip6mr_vif_fops))
+		goto proc_vif_fail;
+	if (!proc_net_fops_create(net, "ip6_mr_cache", 0, &ip6mr_mfc_fops))
+		goto proc_cache_fail;
+#endif
+	return 0;
+
+#ifdef CONFIG_PROC_FS
+proc_cache_fail:
+	proc_net_remove(net, "ip6_mr_vif");
+proc_vif_fail:
+	kfree(net->ipv6.mfc6_cache_array);
+#endif
+fail_mfc6_cache:
+	kfree(net->ipv6.vif6_table);
+fail:
+	return err;
+}
+
+static void __net_exit ip6mr_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+	proc_net_remove(net, "ip6_mr_cache");
+	proc_net_remove(net, "ip6_mr_vif");
+#endif
+	mroute_clean_tables(net);
+	kfree(net->ipv6.mfc6_cache_array);
+	kfree(net->ipv6.vif6_table);
+}
+
+static struct pernet_operations ip6mr_net_ops = {
+	.init = ip6mr_net_init,
+	.exit = ip6mr_net_exit,
+};
+
 int __init ip6_mr_init(void)
 {
 	int err;
@@ -968,43 +1059,32 @@
 	if (!mrt_cachep)
 		return -ENOMEM;
 
+	err = register_pernet_subsys(&ip6mr_net_ops);
+	if (err)
+		goto reg_pernet_fail;
+
 	setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
 	err = register_netdevice_notifier(&ip6_mr_notifier);
 	if (err)
 		goto reg_notif_fail;
-#ifdef CONFIG_PROC_FS
-	err = -ENOMEM;
-	if (!proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops))
-		goto proc_vif_fail;
-	if (!proc_net_fops_create(&init_net, "ip6_mr_cache",
-				     0, &ip6mr_mfc_fops))
-		goto proc_cache_fail;
-#endif
 	return 0;
-#ifdef CONFIG_PROC_FS
-proc_cache_fail:
-	proc_net_remove(&init_net, "ip6_mr_vif");
-proc_vif_fail:
-	unregister_netdevice_notifier(&ip6_mr_notifier);
-#endif
 reg_notif_fail:
 	del_timer(&ipmr_expire_timer);
+	unregister_pernet_subsys(&ip6mr_net_ops);
+reg_pernet_fail:
 	kmem_cache_destroy(mrt_cachep);
 	return err;
 }
 
 void ip6_mr_cleanup(void)
 {
-#ifdef CONFIG_PROC_FS
-	proc_net_remove(&init_net, "ip6_mr_cache");
-	proc_net_remove(&init_net, "ip6_mr_vif");
-#endif
 	unregister_netdevice_notifier(&ip6_mr_notifier);
 	del_timer(&ipmr_expire_timer);
+	unregister_pernet_subsys(&ip6mr_net_ops);
 	kmem_cache_destroy(mrt_cachep);
 }
 
-static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock)
+static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
 {
 	int line;
 	struct mfc6_cache *uc, *c, **cp;
@@ -1020,7 +1100,8 @@
 
 	line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
 
-	for (cp = &mfc6_cache_array[line]; (c = *cp) != NULL; cp = &c->next) {
+	for (cp = &net->ipv6.mfc6_cache_array[line];
+	     (c = *cp) != NULL; cp = &c->next) {
 		if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
 		    ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr))
 			break;
@@ -1039,7 +1120,7 @@
 	if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
 		return -EINVAL;
 
-	c = ip6mr_cache_alloc();
+	c = ip6mr_cache_alloc(net);
 	if (c == NULL)
 		return -ENOMEM;
 
@@ -1051,8 +1132,8 @@
 		c->mfc_flags |= MFC_STATIC;
 
 	write_lock_bh(&mrt_lock);
-	c->next = mfc6_cache_array[line];
-	mfc6_cache_array[line] = c;
+	c->next = net->ipv6.mfc6_cache_array[line];
+	net->ipv6.mfc6_cache_array[line] = c;
 	write_unlock_bh(&mrt_lock);
 
 	/*
@@ -1062,19 +1143,21 @@
 	spin_lock_bh(&mfc_unres_lock);
 	for (cp = &mfc_unres_queue; (uc = *cp) != NULL;
 	     cp = &uc->next) {
-		if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
+		if (net_eq(mfc6_net(uc), net) &&
+		    ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
 		    ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
 			*cp = uc->next;
-			if (atomic_dec_and_test(&cache_resolve_queue_len))
-				del_timer(&ipmr_expire_timer);
+			atomic_dec(&net->ipv6.cache_resolve_queue_len);
 			break;
 		}
 	}
+	if (mfc_unres_queue == NULL)
+		del_timer(&ipmr_expire_timer);
 	spin_unlock_bh(&mfc_unres_lock);
 
 	if (uc) {
 		ip6mr_cache_resolve(uc, c);
-		kmem_cache_free(mrt_cachep, uc);
+		ip6mr_cache_free(uc);
 	}
 	return 0;
 }
@@ -1083,25 +1166,25 @@
  *	Close the multicast socket, and clear the vif tables etc
  */
 
-static void mroute_clean_tables(struct sock *sk)
+static void mroute_clean_tables(struct net *net)
 {
 	int i;
 
 	/*
 	 *	Shut down all active vif entries
 	 */
-	for (i = 0; i < maxvif; i++) {
-		if (!(vif6_table[i].flags & VIFF_STATIC))
-			mif6_delete(i);
+	for (i = 0; i < net->ipv6.maxvif; i++) {
+		if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC))
+			mif6_delete(net, i);
 	}
 
 	/*
 	 *	Wipe the cache
 	 */
-	for (i = 0; i < ARRAY_SIZE(mfc6_cache_array); i++) {
+	for (i = 0; i < MFC6_LINES; i++) {
 		struct mfc6_cache *c, **cp;
 
-		cp = &mfc6_cache_array[i];
+		cp = &net->ipv6.mfc6_cache_array[i];
 		while ((c = *cp) != NULL) {
 			if (c->mfc_flags & MFC_STATIC) {
 				cp = &c->next;
@@ -1111,22 +1194,22 @@
 			*cp = c->next;
 			write_unlock_bh(&mrt_lock);
 
-			kmem_cache_free(mrt_cachep, c);
+			ip6mr_cache_free(c);
 		}
 	}
 
-	if (atomic_read(&cache_resolve_queue_len) != 0) {
-		struct mfc6_cache *c;
+	if (atomic_read(&net->ipv6.cache_resolve_queue_len) != 0) {
+		struct mfc6_cache *c, **cp;
 
 		spin_lock_bh(&mfc_unres_lock);
-		while (mfc_unres_queue != NULL) {
-			c = mfc_unres_queue;
-			mfc_unres_queue = c->next;
-			spin_unlock_bh(&mfc_unres_lock);
-
+		cp = &mfc_unres_queue;
+		while ((c = *cp) != NULL) {
+			if (!net_eq(mfc6_net(c), net)) {
+				cp = &c->next;
+				continue;
+			}
+			*cp = c->next;
 			ip6mr_destroy_unres(c);
-
-			spin_lock_bh(&mfc_unres_lock);
 		}
 		spin_unlock_bh(&mfc_unres_lock);
 	}
@@ -1135,11 +1218,12 @@
 static int ip6mr_sk_init(struct sock *sk)
 {
 	int err = 0;
+	struct net *net = sock_net(sk);
 
 	rtnl_lock();
 	write_lock_bh(&mrt_lock);
-	if (likely(mroute6_socket == NULL))
-		mroute6_socket = sk;
+	if (likely(net->ipv6.mroute6_sk == NULL))
+		net->ipv6.mroute6_sk = sk;
 	else
 		err = -EADDRINUSE;
 	write_unlock_bh(&mrt_lock);
@@ -1152,14 +1236,15 @@
 int ip6mr_sk_done(struct sock *sk)
 {
 	int err = 0;
+	struct net *net = sock_net(sk);
 
 	rtnl_lock();
-	if (sk == mroute6_socket) {
+	if (sk == net->ipv6.mroute6_sk) {
 		write_lock_bh(&mrt_lock);
-		mroute6_socket = NULL;
+		net->ipv6.mroute6_sk = NULL;
 		write_unlock_bh(&mrt_lock);
 
-		mroute_clean_tables(sk);
+		mroute_clean_tables(net);
 	} else
 		err = -EACCES;
 	rtnl_unlock();
@@ -1180,9 +1265,10 @@
 	struct mif6ctl vif;
 	struct mf6cctl mfc;
 	mifi_t mifi;
+	struct net *net = sock_net(sk);
 
 	if (optname != MRT6_INIT) {
-		if (sk != mroute6_socket && !capable(CAP_NET_ADMIN))
+		if (sk != net->ipv6.mroute6_sk && !capable(CAP_NET_ADMIN))
 			return -EACCES;
 	}
 
@@ -1207,7 +1293,7 @@
 		if (vif.mif6c_mifi >= MAXMIFS)
 			return -ENFILE;
 		rtnl_lock();
-		ret = mif6_add(&vif, sk == mroute6_socket);
+		ret = mif6_add(net, &vif, sk == net->ipv6.mroute6_sk);
 		rtnl_unlock();
 		return ret;
 
@@ -1217,7 +1303,7 @@
 		if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
 			return -EFAULT;
 		rtnl_lock();
-		ret = mif6_delete(mifi);
+		ret = mif6_delete(net, mifi);
 		rtnl_unlock();
 		return ret;
 
@@ -1233,9 +1319,10 @@
 			return -EFAULT;
 		rtnl_lock();
 		if (optname == MRT6_DEL_MFC)
-			ret = ip6mr_mfc_delete(&mfc);
+			ret = ip6mr_mfc_delete(net, &mfc);
 		else
-			ret = ip6mr_mfc_add(&mfc, sk == mroute6_socket);
+			ret = ip6mr_mfc_add(net, &mfc,
+					    sk == net->ipv6.mroute6_sk);
 		rtnl_unlock();
 		return ret;
 
@@ -1247,7 +1334,7 @@
 		int v;
 		if (get_user(v, (int __user *)optval))
 			return -EFAULT;
-		mroute_do_assert = !!v;
+		net->ipv6.mroute_do_assert = !!v;
 		return 0;
 	}
 
@@ -1260,10 +1347,10 @@
 		v = !!v;
 		rtnl_lock();
 		ret = 0;
-		if (v != mroute_do_pim) {
-			mroute_do_pim = v;
-			mroute_do_assert = v;
-			if (mroute_do_pim)
+		if (v != net->ipv6.mroute_do_pim) {
+			net->ipv6.mroute_do_pim = v;
+			net->ipv6.mroute_do_assert = v;
+			if (net->ipv6.mroute_do_pim)
 				ret = inet6_add_protocol(&pim6_protocol,
 							 IPPROTO_PIM);
 			else
@@ -1295,6 +1382,7 @@
 {
 	int olr;
 	int val;
+	struct net *net = sock_net(sk);
 
 	switch (optname) {
 	case MRT6_VERSION:
@@ -1302,11 +1390,11 @@
 		break;
 #ifdef CONFIG_IPV6_PIMSM_V2
 	case MRT6_PIM:
-		val = mroute_do_pim;
+		val = net->ipv6.mroute_do_pim;
 		break;
 #endif
 	case MRT6_ASSERT:
-		val = mroute_do_assert;
+		val = net->ipv6.mroute_do_assert;
 		break;
 	default:
 		return -ENOPROTOOPT;
@@ -1336,16 +1424,17 @@
 	struct sioc_mif_req6 vr;
 	struct mif_device *vif;
 	struct mfc6_cache *c;
+	struct net *net = sock_net(sk);
 
 	switch (cmd) {
 	case SIOCGETMIFCNT_IN6:
 		if (copy_from_user(&vr, arg, sizeof(vr)))
 			return -EFAULT;
-		if (vr.mifi >= maxvif)
+		if (vr.mifi >= net->ipv6.maxvif)
 			return -EINVAL;
 		read_lock(&mrt_lock);
-		vif = &vif6_table[vr.mifi];
-		if (MIF_EXISTS(vr.mifi)) {
+		vif = &net->ipv6.vif6_table[vr.mifi];
+		if (MIF_EXISTS(net, vr.mifi)) {
 			vr.icount = vif->pkt_in;
 			vr.ocount = vif->pkt_out;
 			vr.ibytes = vif->bytes_in;
@@ -1363,7 +1452,7 @@
 			return -EFAULT;
 
 		read_lock(&mrt_lock);
-		c = ip6mr_cache_find(&sr.src.sin6_addr, &sr.grp.sin6_addr);
+		c = ip6mr_cache_find(net, &sr.src.sin6_addr, &sr.grp.sin6_addr);
 		if (c) {
 			sr.pktcnt = c->mfc_un.res.pkt;
 			sr.bytecnt = c->mfc_un.res.bytes;
@@ -1396,7 +1485,8 @@
 static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
 {
 	struct ipv6hdr *ipv6h;
-	struct mif_device *vif = &vif6_table[vifi];
+	struct net *net = mfc6_net(c);
+	struct mif_device *vif = &net->ipv6.vif6_table[vifi];
 	struct net_device *dev;
 	struct dst_entry *dst;
 	struct flowi fl;
@@ -1410,9 +1500,8 @@
 		vif->bytes_out += skb->len;
 		vif->dev->stats.tx_bytes += skb->len;
 		vif->dev->stats.tx_packets++;
-		ip6mr_cache_report(skb, vifi, MRT6MSG_WHOLEPKT);
-		kfree_skb(skb);
-		return 0;
+		ip6mr_cache_report(net, skb, vifi, MRT6MSG_WHOLEPKT);
+		goto out_free;
 	}
 #endif
 
@@ -1425,7 +1514,7 @@
 		}
 	};
 
-	dst = ip6_route_output(&init_net, NULL, &fl);
+	dst = ip6_route_output(net, NULL, &fl);
 	if (!dst)
 		goto out_free;
 
@@ -1468,9 +1557,10 @@
 
 static int ip6mr_find_vif(struct net_device *dev)
 {
+	struct net *net = dev_net(dev);
 	int ct;
-	for (ct = maxvif - 1; ct >= 0; ct--) {
-		if (vif6_table[ct].dev == dev)
+	for (ct = net->ipv6.maxvif - 1; ct >= 0; ct--) {
+		if (net->ipv6.vif6_table[ct].dev == dev)
 			break;
 	}
 	return ct;
@@ -1480,6 +1570,7 @@
 {
 	int psend = -1;
 	int vif, ct;
+	struct net *net = mfc6_net(cache);
 
 	vif = cache->mf6c_parent;
 	cache->mfc_un.res.pkt++;
@@ -1488,29 +1579,30 @@
 	/*
 	 * Wrong interface: drop packet and (maybe) send PIM assert.
 	 */
-	if (vif6_table[vif].dev != skb->dev) {
+	if (net->ipv6.vif6_table[vif].dev != skb->dev) {
 		int true_vifi;
 
 		cache->mfc_un.res.wrong_if++;
 		true_vifi = ip6mr_find_vif(skb->dev);
 
-		if (true_vifi >= 0 && mroute_do_assert &&
+		if (true_vifi >= 0 && net->ipv6.mroute_do_assert &&
 		    /* pimsm uses asserts, when switching from RPT to SPT,
 		       so that we cannot check that packet arrived on an oif.
 		       It is bad, but otherwise we would need to move pretty
 		       large chunk of pimd to kernel. Ough... --ANK
 		     */
-		    (mroute_do_pim || cache->mfc_un.res.ttls[true_vifi] < 255) &&
+		    (net->ipv6.mroute_do_pim ||
+		     cache->mfc_un.res.ttls[true_vifi] < 255) &&
 		    time_after(jiffies,
 			       cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
 			cache->mfc_un.res.last_assert = jiffies;
-			ip6mr_cache_report(skb, true_vifi, MRT6MSG_WRONGMIF);
+			ip6mr_cache_report(net, skb, true_vifi, MRT6MSG_WRONGMIF);
 		}
 		goto dont_forward;
 	}
 
-	vif6_table[vif].pkt_in++;
-	vif6_table[vif].bytes_in += skb->len;
+	net->ipv6.vif6_table[vif].pkt_in++;
+	net->ipv6.vif6_table[vif].bytes_in += skb->len;
 
 	/*
 	 *	Forward the frame
@@ -1543,9 +1635,11 @@
 int ip6_mr_input(struct sk_buff *skb)
 {
 	struct mfc6_cache *cache;
+	struct net *net = dev_net(skb->dev);
 
 	read_lock(&mrt_lock);
-	cache = ip6mr_cache_find(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
+	cache = ip6mr_cache_find(net,
+				 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
 
 	/*
 	 *	No usable cache entry
@@ -1555,7 +1649,7 @@
 
 		vif = ip6mr_find_vif(skb->dev);
 		if (vif >= 0) {
-			int err = ip6mr_cache_unresolved(vif, skb);
+			int err = ip6mr_cache_unresolved(net, vif, skb);
 			read_unlock(&mrt_lock);
 
 			return err;
@@ -1578,7 +1672,8 @@
 {
 	int ct;
 	struct rtnexthop *nhp;
-	struct net_device *dev = vif6_table[c->mf6c_parent].dev;
+	struct net *net = mfc6_net(c);
+	struct net_device *dev = net->ipv6.vif6_table[c->mf6c_parent].dev;
 	u8 *b = skb_tail_pointer(skb);
 	struct rtattr *mp_head;
 
@@ -1594,7 +1689,7 @@
 			nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
 			nhp->rtnh_flags = 0;
 			nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
-			nhp->rtnh_ifindex = vif6_table[ct].dev->ifindex;
+			nhp->rtnh_ifindex = net->ipv6.vif6_table[ct].dev->ifindex;
 			nhp->rtnh_len = sizeof(*nhp);
 		}
 	}
@@ -1608,14 +1703,15 @@
 	return -EMSGSIZE;
 }
 
-int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait)
+int ip6mr_get_route(struct net *net,
+		    struct sk_buff *skb, struct rtmsg *rtm, int nowait)
 {
 	int err;
 	struct mfc6_cache *cache;
 	struct rt6_info *rt = (struct rt6_info *)skb->dst;
 
 	read_lock(&mrt_lock);
-	cache = ip6mr_cache_find(&rt->rt6i_src.addr, &rt->rt6i_dst.addr);
+	cache = ip6mr_cache_find(net, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
 
 	if (!cache) {
 		struct sk_buff *skb2;
@@ -1658,7 +1754,7 @@
 		ipv6_addr_copy(&iph->saddr, &rt->rt6i_src.addr);
 		ipv6_addr_copy(&iph->daddr, &rt->rt6i_dst.addr);
 
-		err = ip6mr_cache_unresolved(vif, skb2);
+		err = ip6mr_cache_unresolved(net, vif, skb2);
 		read_unlock(&mrt_lock);
 
 		return err;
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 4545e43..3a0b3be 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -63,12 +63,12 @@
 		return;
 
 	spi = htonl(ntohs(ipcomph->cpi));
-	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6);
+	x = xfrm_state_lookup(&init_net, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6);
 	if (!x)
 		return;
 
-	printk(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/" NIP6_FMT "\n",
-			spi, NIP6(iph->daddr));
+	printk(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%pI6\n",
+			spi, &iph->daddr);
 	xfrm_state_put(x);
 }
 
@@ -76,7 +76,7 @@
 {
 	struct xfrm_state *t = NULL;
 
-	t = xfrm_state_alloc();
+	t = xfrm_state_alloc(&init_net);
 	if (!t)
 		goto out;
 
@@ -114,7 +114,7 @@
 
 	spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr);
 	if (spi)
-		t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr,
+		t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr,
 					      spi, IPPROTO_IPV6, AF_INET6);
 	if (!t) {
 		t = ipcomp6_tunnel_create(x);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 2aa294b..eeeaad2 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -395,6 +395,28 @@
 		break;
 	}
 
+	case IPV6_PKTINFO:
+	{
+		struct in6_pktinfo pkt;
+
+		if (optlen == 0)
+			goto e_inval;
+		else if (optlen < sizeof(struct in6_pktinfo) || optval == NULL)
+			goto e_inval;
+
+		if (copy_from_user(&pkt, optval, optlen)) {
+				retv = -EFAULT;
+				break;
+		}
+		if (sk->sk_bound_dev_if && pkt.ipi6_ifindex != sk->sk_bound_dev_if)
+			goto e_inval;
+
+		np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex;
+		ipv6_addr_copy(&np->sticky_pktinfo.ipi6_addr, &pkt.ipi6_addr);
+		retv = 0;
+		break;
+	}
+
 	case IPV6_2292PKTOPTIONS:
 	{
 		struct ipv6_txoptions *opt = NULL;
@@ -916,8 +938,10 @@
 		} else {
 			if (np->rxopt.bits.rxinfo) {
 				struct in6_pktinfo src_info;
-				src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : sk->sk_bound_dev_if;
-				ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);
+				src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :
+					np->sticky_pktinfo.ipi6_ifindex;
+				np->mcast_oif? ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr) :
+					ipv6_addr_copy(&src_info.ipi6_addr, &(np->sticky_pktinfo.ipi6_addr));
 				put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
 			}
 			if (np->rxopt.bits.rxhlim) {
@@ -926,8 +950,10 @@
 			}
 			if (np->rxopt.bits.rxoinfo) {
 				struct in6_pktinfo src_info;
-				src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : sk->sk_bound_dev_if;
-				ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);
+				src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :
+					np->sticky_pktinfo.ipi6_ifindex;
+				np->mcast_oif? ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr) :
+					ipv6_addr_copy(&src_info.ipi6_addr, &(np->sticky_pktinfo.ipi6_addr));
 				put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
 			}
 			if (np->rxopt.bits.rxohlim) {
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index d7b3c6d..a51fb33 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -303,20 +303,23 @@
 		dev = dev_get_by_index(net, ifindex);
 
 	if (!dev)
-		return NULL;
+		goto nodev;
 	idev = in6_dev_get(dev);
-	if (!idev) {
-		dev_put(dev);
-		return NULL;
-	}
+	if (!idev)
+		goto release;
 	read_lock_bh(&idev->lock);
-	if (idev->dead) {
-		read_unlock_bh(&idev->lock);
-		in6_dev_put(idev);
-		dev_put(dev);
-		return NULL;
-	}
+	if (idev->dead)
+		goto unlock_release;
+
 	return idev;
+
+unlock_release:
+	read_unlock_bh(&idev->lock);
+	in6_dev_put(idev);
+release:
+	dev_put(dev);
+nodev:
+	return NULL;
 }
 
 void ipv6_sock_mc_close(struct sock *sk)
@@ -1466,7 +1469,7 @@
 			 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
 			 skb->dev->ifindex);
 
-	err = xfrm_lookup(&skb->dst, &fl, NULL, 0);
+	err = xfrm_lookup(net, &skb->dst, &fl, NULL, 0);
 	if (err)
 		goto err_out;
 
@@ -1817,7 +1820,7 @@
 
 	hdr->icmp6_cksum = csum_ipv6_magic(saddr, snd_addr, len,
 					   IPPROTO_ICMPV6,
-					   csum_partial((__u8 *) hdr, len, 0));
+					   csum_partial(hdr, len, 0));
 
 	idev = in6_dev_get(skb->dev);
 
@@ -1831,7 +1834,7 @@
 			 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
 			 skb->dev->ifindex);
 
-	err = xfrm_lookup(&skb->dst, &fl, NULL, 0);
+	err = xfrm_lookup(net, &skb->dst, &fl, NULL, 0);
 	if (err)
 		goto err_out;
 
@@ -2430,9 +2433,9 @@
 	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
 
 	seq_printf(seq,
-		   "%-4d %-15s " NIP6_SEQFMT " %5d %08X %ld\n",
+		   "%-4d %-15s %pi6 %5d %08X %ld\n",
 		   state->dev->ifindex, state->dev->name,
-		   NIP6(im->mca_addr),
+		   &im->mca_addr,
 		   im->mca_users, im->mca_flags,
 		   (im->mca_flags&MAF_TIMER_RUNNING) ?
 		   jiffies_to_clock_t(im->mca_timer.expires-jiffies) : 0);
@@ -2591,10 +2594,10 @@
 			   "Source Address", "INC", "EXC");
 	} else {
 		seq_printf(seq,
-			   "%3d %6.6s " NIP6_SEQFMT " " NIP6_SEQFMT " %6lu %6lu\n",
+			   "%3d %6.6s %pi6 %pi6 %6lu %6lu\n",
 			   state->dev->ifindex, state->dev->name,
-			   NIP6(state->im->mca_addr),
-			   NIP6(psf->sf_addr),
+			   &state->im->mca_addr,
+			   &psf->sf_addr,
 			   psf->sf_count[MCAST_INCLUDE],
 			   psf->sf_count[MCAST_EXCLUDE]);
 	}
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index 31295c8..f995e19 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -205,6 +205,7 @@
 
 static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, struct flowi *fl)
 {
+	struct net *net = xs_net(x);
 	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
 	struct ipv6_destopt_hao *hao = NULL;
 	struct xfrm_selector sel;
@@ -247,7 +248,7 @@
 		sel.sport_mask = htons(~0);
 	sel.ifindex = fl->oif;
 
-	err = km_report(IPPROTO_DSTOPTS, &sel,
+	err = km_report(net, IPPROTO_DSTOPTS, &sel,
 			(hao ? (xfrm_address_t *)&hao->addr : NULL));
 
  out:
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index d0f54d1..3e29708 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -437,38 +437,20 @@
 	ipv6_dev_mc_dec(dev, &maddr);
 }
 
-/*
- *	Send a Neighbour Advertisement
- */
-static void __ndisc_send(struct net_device *dev,
-			 struct neighbour *neigh,
-			 const struct in6_addr *daddr,
-			 const struct in6_addr *saddr,
-			 struct icmp6hdr *icmp6h, const struct in6_addr *target,
-			 int llinfo)
+struct sk_buff *ndisc_build_skb(struct net_device *dev,
+				const struct in6_addr *daddr,
+				const struct in6_addr *saddr,
+				struct icmp6hdr *icmp6h,
+				const struct in6_addr *target,
+				int llinfo)
 {
-	struct flowi fl;
-	struct dst_entry *dst;
 	struct net *net = dev_net(dev);
 	struct sock *sk = net->ipv6.ndisc_sk;
 	struct sk_buff *skb;
 	struct icmp6hdr *hdr;
-	struct inet6_dev *idev;
 	int len;
 	int err;
-	u8 *opt, type;
-
-	type = icmp6h->icmp6_type;
-
-	icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex);
-
-	dst = icmp6_dst_alloc(dev, neigh, daddr);
-	if (!dst)
-		return;
-
-	err = xfrm_lookup(&dst, &fl, NULL, 0);
-	if (err < 0)
-		return;
+	u8 *opt;
 
 	if (!dev->addr_len)
 		llinfo = 0;
@@ -485,8 +467,7 @@
 		ND_PRINTK0(KERN_ERR
 			   "ICMPv6 ND: %s() failed to allocate an skb.\n",
 			   __func__);
-		dst_release(dst);
-		return;
+		return NULL;
 	}
 
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
@@ -510,9 +491,45 @@
 
 	hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len,
 					   IPPROTO_ICMPV6,
-					   csum_partial((__u8 *) hdr,
+					   csum_partial(hdr,
 							len, 0));
 
+	return skb;
+}
+
+EXPORT_SYMBOL(ndisc_build_skb);
+
+void ndisc_send_skb(struct sk_buff *skb,
+		    struct net_device *dev,
+		    struct neighbour *neigh,
+		    const struct in6_addr *daddr,
+		    const struct in6_addr *saddr,
+		    struct icmp6hdr *icmp6h)
+{
+	struct flowi fl;
+	struct dst_entry *dst;
+	struct net *net = dev_net(dev);
+	struct sock *sk = net->ipv6.ndisc_sk;
+	struct inet6_dev *idev;
+	int err;
+	u8 type;
+
+	type = icmp6h->icmp6_type;
+
+	icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex);
+
+	dst = icmp6_dst_alloc(dev, neigh, daddr);
+	if (!dst) {
+		kfree_skb(skb);
+		return;
+	}
+
+	err = xfrm_lookup(net, &dst, &fl, NULL, 0);
+	if (err < 0) {
+		kfree_skb(skb);
+		return;
+	}
+
 	skb->dst = dst;
 
 	idev = in6_dev_get(dst->dev);
@@ -529,6 +546,27 @@
 		in6_dev_put(idev);
 }
 
+EXPORT_SYMBOL(ndisc_send_skb);
+
+/*
+ *	Send a Neighbour Discover packet
+ */
+static void __ndisc_send(struct net_device *dev,
+			 struct neighbour *neigh,
+			 const struct in6_addr *daddr,
+			 const struct in6_addr *saddr,
+			 struct icmp6hdr *icmp6h, const struct in6_addr *target,
+			 int llinfo)
+{
+	struct sk_buff *skb;
+
+	skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo);
+	if (!skb)
+		return;
+
+	ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h);
+}
+
 static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 			  const struct in6_addr *daddr,
 			  const struct in6_addr *solicited_addr,
@@ -647,11 +685,8 @@
 
 	if ((probes -= neigh->parms->ucast_probes) < 0) {
 		if (!(neigh->nud_state & NUD_VALID)) {
-			ND_PRINTK1(KERN_DEBUG
-				   "%s(): trying to ucast probe in NUD_INVALID: "
-				   NIP6_FMT "\n",
-				   __func__,
-				   NIP6(*target));
+			ND_PRINTK1(KERN_DEBUG "%s(): trying to ucast probe in NUD_INVALID: %pI6\n",
+				   __func__, target);
 		}
 		ndisc_send_ns(dev, neigh, target, target, saddr);
 	} else if ((probes -= neigh->parms->app_probes) < 0) {
@@ -1494,7 +1529,7 @@
 	if (dst == NULL)
 		return;
 
-	err = xfrm_lookup(&dst, &fl, NULL, 0);
+	err = xfrm_lookup(net, &dst, &fl, NULL, 0);
 	if (err)
 		return;
 
@@ -1582,7 +1617,7 @@
 
 	icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
 					     len, IPPROTO_ICMPV6,
-					     csum_partial((u8 *) icmph, len, 0));
+					     csum_partial(icmph, len, 0));
 
 	buff->dst = dst;
 	idev = in6_dev_get(dst->dev);
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index fd5b3a4..834cea6 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -29,7 +29,7 @@
 #ifdef CONFIG_XFRM
 	if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
 	    xfrm_decode_session(skb, &fl, AF_INET6) == 0)
-		if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0))
+		if (xfrm_lookup(net, &skb->dst, &fl, skb->sk, 0))
 			return -1;
 #endif
 
@@ -56,6 +56,7 @@
 struct ip6_rt_info {
 	struct in6_addr daddr;
 	struct in6_addr saddr;
+	u_int32_t mark;
 };
 
 static void nf_ip6_saveroute(const struct sk_buff *skb,
@@ -68,6 +69,7 @@
 
 		rt_info->daddr = iph->daddr;
 		rt_info->saddr = iph->saddr;
+		rt_info->mark = skb->mark;
 	}
 }
 
@@ -79,7 +81,8 @@
 	if (entry->hook == NF_INET_LOCAL_OUT) {
 		struct ipv6hdr *iph = ipv6_hdr(skb);
 		if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
-		    !ipv6_addr_equal(&iph->saddr, &rt_info->saddr))
+		    !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) ||
+		    skb->mark != rt_info->mark)
 			return ip6_route_me_harder(skb);
 	}
 	return 0;
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index caa441d..37adf5a 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -61,7 +61,7 @@
 	}
 
 	/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */
-	printk("SRC=" NIP6_FMT " DST=" NIP6_FMT " ", NIP6(ih->saddr), NIP6(ih->daddr));
+	printk("SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr);
 
 	/* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
 	printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
@@ -364,8 +364,8 @@
 		read_lock_bh(&skb->sk->sk_callback_lock);
 		if (skb->sk->sk_socket && skb->sk->sk_socket->file)
 			printk("UID=%u GID=%u ",
-				skb->sk->sk_socket->file->f_uid,
-				skb->sk->sk_socket->file->f_gid);
+				skb->sk->sk_socket->file->f_cred->fsuid,
+				skb->sk->sk_socket->file->f_cred->fsgid);
 		read_unlock_bh(&skb->sk->sk_callback_lock);
 	}
 
@@ -424,9 +424,8 @@
 			if (skb->dev->type == ARPHRD_SIT) {
 				const struct iphdr *iph =
 					(struct iphdr *)skb_mac_header(skb);
-				printk("TUNNEL=%u.%u.%u.%u->%u.%u.%u.%u ",
-				       NIPQUAD(iph->saddr),
-				       NIPQUAD(iph->daddr));
+				printk("TUNNEL=%pI4->%pI4 ",
+				       &iph->saddr, &iph->daddr);
 			}
 		} else
 			printk(" ");
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index 0981b4c..5a2d0a4 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -97,7 +97,7 @@
 	dst = ip6_route_output(net, NULL, &fl);
 	if (dst == NULL)
 		return;
-	if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0))
+	if (dst->error || xfrm_lookup(net, &dst, &fl, NULL, 0))
 		return;
 
 	hh_len = (dst->dev->hard_header_len + 15)&~15;
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index b110a8a..40d2e36 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -61,7 +61,7 @@
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
-ip6t_local_in_hook(unsigned int hook,
+ip6t_in_hook(unsigned int hook,
 		   struct sk_buff *skb,
 		   const struct net_device *in,
 		   const struct net_device *out,
@@ -72,17 +72,6 @@
 }
 
 static unsigned int
-ip6t_forward_hook(unsigned int hook,
-		  struct sk_buff *skb,
-		  const struct net_device *in,
-		  const struct net_device *out,
-		  int (*okfn)(struct sk_buff *))
-{
-	return ip6t_do_table(skb, hook, in, out,
-			     dev_net(in)->ipv6.ip6table_filter);
-}
-
-static unsigned int
 ip6t_local_out_hook(unsigned int hook,
 		   struct sk_buff *skb,
 		   const struct net_device *in,
@@ -105,14 +94,14 @@
 
 static struct nf_hook_ops ip6t_ops[] __read_mostly = {
 	{
-		.hook		= ip6t_local_in_hook,
+		.hook		= ip6t_in_hook,
 		.owner		= THIS_MODULE,
 		.pf		= PF_INET6,
 		.hooknum	= NF_INET_LOCAL_IN,
 		.priority	= NF_IP6_PRI_FILTER,
 	},
 	{
-		.hook		= ip6t_forward_hook,
+		.hook		= ip6t_in_hook,
 		.owner		= THIS_MODULE,
 		.pf		= PF_INET6,
 		.hooknum	= NF_INET_FORWARD,
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index e91db16..727b953 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -56,9 +56,8 @@
 static int ipv6_print_tuple(struct seq_file *s,
 			    const struct nf_conntrack_tuple *tuple)
 {
-	return seq_printf(s, "src=" NIP6_FMT " dst=" NIP6_FMT " ",
-			  NIP6(*((struct in6_addr *)tuple->src.u3.ip6)),
-			  NIP6(*((struct in6_addr *)tuple->dst.u3.ip6)));
+	return seq_printf(s, "src=%pI6 dst=%pI6 ",
+			  tuple->src.u3.ip6, tuple->dst.u3.ip6);
 }
 
 /*
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 0572617..bd52151 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -253,7 +253,7 @@
 		.data		= &nf_ct_icmpv6_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name	= 0
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 9967ac7..ed4d79a 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -80,7 +80,7 @@
 		.data		= &nf_init_frags.timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name	= NET_NF_CONNTRACK_FRAG6_LOW_THRESH,
@@ -88,7 +88,7 @@
 		.data		= &nf_init_frags.low_thresh,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_NF_CONNTRACK_FRAG6_HIGH_THRESH,
@@ -96,7 +96,7 @@
 		.data		= &nf_init_frags.high_thresh,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{ .ctl_name = 0 }
 };
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 2ba04d4..61f6827 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -860,7 +860,8 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) {
+	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
+	if (err < 0) {
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, &fl);
 		if (err < 0)
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index af12de0..3c57511 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -642,7 +642,7 @@
 		.data		= &init_net.ipv6.frags.high_thresh,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV6_IP6FRAG_LOW_THRESH,
@@ -650,7 +650,7 @@
 		.data		= &init_net.ipv6.frags.low_thresh,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IPV6_IP6FRAG_TIME,
@@ -658,8 +658,8 @@
 		.data		= &init_net.ipv6.frags.timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies,
 	},
 	{ }
 };
@@ -671,8 +671,8 @@
 		.data		= &ip6_frags.secret_interval,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-		.strategy	= &sysctl_jiffies
+		.proc_handler	= proc_dointvec_jiffies,
+		.strategy	= sysctl_jiffies
 	},
 	{ }
 };
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 89dc699..18c486c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -108,7 +108,6 @@
 	.link_failure		=	ip6_link_failure,
 	.update_pmtu		=	ip6_rt_update_pmtu,
 	.local_out		=	__ip6_local_out,
-	.entry_size		=	sizeof(struct rt6_info),
 	.entries		=	ATOMIC_INIT(0),
 };
 
@@ -122,7 +121,6 @@
 	.destroy		=	ip6_dst_destroy,
 	.check			=	ip6_dst_check,
 	.update_pmtu		=	ip6_rt_blackhole_update_pmtu,
-	.entry_size		=	sizeof(struct rt6_info),
 	.entries		=	ATOMIC_INIT(0),
 };
 
@@ -2196,7 +2194,7 @@
 	if (iif) {
 #ifdef CONFIG_IPV6_MROUTE
 		if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
-			int err = ip6mr_get_route(skb, rtm, nowait);
+			int err = ip6mr_get_route(net, skb, rtm, nowait);
 			if (err <= 0) {
 				if (!nowait) {
 					if (err == 0)
@@ -2408,19 +2406,16 @@
 {
 	struct seq_file *m = p_arg;
 
-	seq_printf(m, NIP6_SEQFMT " %02x ", NIP6(rt->rt6i_dst.addr),
-		   rt->rt6i_dst.plen);
+	seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
 
 #ifdef CONFIG_IPV6_SUBTREES
-	seq_printf(m, NIP6_SEQFMT " %02x ", NIP6(rt->rt6i_src.addr),
-		   rt->rt6i_src.plen);
+	seq_printf(m, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen);
 #else
 	seq_puts(m, "00000000000000000000000000000000 00 ");
 #endif
 
 	if (rt->rt6i_nexthop) {
-		seq_printf(m, NIP6_SEQFMT,
-			   NIP6(*((struct in6_addr *)rt->rt6i_nexthop->primary_key)));
+		seq_printf(m, "%pi6", rt->rt6i_nexthop->primary_key);
 	} else {
 		seq_puts(m, "00000000000000000000000000000000");
 	}
@@ -2502,7 +2497,7 @@
 		.data		=	&init_net.ipv6.sysctl.flush_delay,
 		.maxlen		=	sizeof(int),
 		.mode		=	0200,
-		.proc_handler	=	&ipv6_sysctl_rtcache_flush
+		.proc_handler	=	ipv6_sysctl_rtcache_flush
 	},
 	{
 		.ctl_name	=	NET_IPV6_ROUTE_GC_THRESH,
@@ -2510,7 +2505,7 @@
 		.data		=	&ip6_dst_ops_template.gc_thresh,
 		.maxlen		=	sizeof(int),
 		.mode		=	0644,
-		.proc_handler	=	&proc_dointvec,
+		.proc_handler	=	proc_dointvec,
 	},
 	{
 		.ctl_name	=	NET_IPV6_ROUTE_MAX_SIZE,
@@ -2518,7 +2513,7 @@
 		.data		=	&init_net.ipv6.sysctl.ip6_rt_max_size,
 		.maxlen		=	sizeof(int),
 		.mode		=	0644,
-		.proc_handler	=	&proc_dointvec,
+		.proc_handler	=	proc_dointvec,
 	},
 	{
 		.ctl_name	=	NET_IPV6_ROUTE_GC_MIN_INTERVAL,
@@ -2526,8 +2521,8 @@
 		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
 		.maxlen		=	sizeof(int),
 		.mode		=	0644,
-		.proc_handler	=	&proc_dointvec_jiffies,
-		.strategy	=	&sysctl_jiffies,
+		.proc_handler	=	proc_dointvec_jiffies,
+		.strategy	=	sysctl_jiffies,
 	},
 	{
 		.ctl_name	=	NET_IPV6_ROUTE_GC_TIMEOUT,
@@ -2535,8 +2530,8 @@
 		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_timeout,
 		.maxlen		=	sizeof(int),
 		.mode		=	0644,
-		.proc_handler	=	&proc_dointvec_jiffies,
-		.strategy	=	&sysctl_jiffies,
+		.proc_handler	=	proc_dointvec_jiffies,
+		.strategy	=	sysctl_jiffies,
 	},
 	{
 		.ctl_name	=	NET_IPV6_ROUTE_GC_INTERVAL,
@@ -2544,8 +2539,8 @@
 		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_interval,
 		.maxlen		=	sizeof(int),
 		.mode		=	0644,
-		.proc_handler	=	&proc_dointvec_jiffies,
-		.strategy	=	&sysctl_jiffies,
+		.proc_handler	=	proc_dointvec_jiffies,
+		.strategy	=	sysctl_jiffies,
 	},
 	{
 		.ctl_name	=	NET_IPV6_ROUTE_GC_ELASTICITY,
@@ -2553,8 +2548,8 @@
 		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
 		.maxlen		=	sizeof(int),
 		.mode		=	0644,
-		.proc_handler	=	&proc_dointvec_jiffies,
-		.strategy	=	&sysctl_jiffies,
+		.proc_handler	=	proc_dointvec_jiffies,
+		.strategy	=	sysctl_jiffies,
 	},
 	{
 		.ctl_name	=	NET_IPV6_ROUTE_MTU_EXPIRES,
@@ -2562,8 +2557,8 @@
 		.data		=	&init_net.ipv6.sysctl.ip6_rt_mtu_expires,
 		.maxlen		=	sizeof(int),
 		.mode		=	0644,
-		.proc_handler	=	&proc_dointvec_jiffies,
-		.strategy	=	&sysctl_jiffies,
+		.proc_handler	=	proc_dointvec_jiffies,
+		.strategy	=	sysctl_jiffies,
 	},
 	{
 		.ctl_name	=	NET_IPV6_ROUTE_MIN_ADVMSS,
@@ -2571,8 +2566,8 @@
 		.data		=	&init_net.ipv6.sysctl.ip6_rt_min_advmss,
 		.maxlen		=	sizeof(int),
 		.mode		=	0644,
-		.proc_handler	=	&proc_dointvec_jiffies,
-		.strategy	=	&sysctl_jiffies,
+		.proc_handler	=	proc_dointvec_jiffies,
+		.strategy	=	sysctl_jiffies,
 	},
 	{
 		.ctl_name	=	NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS,
@@ -2580,8 +2575,8 @@
 		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
 		.maxlen		=	sizeof(int),
 		.mode		=	0644,
-		.proc_handler	=	&proc_dointvec_ms_jiffies,
-		.strategy	=	&sysctl_ms_jiffies,
+		.proc_handler	=	proc_dointvec_ms_jiffies,
+		.strategy	=	sysctl_ms_jiffies,
 	},
 	{ .ctl_name = 0 }
 };
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index b7a50e9..d3467e5 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -62,8 +62,8 @@
 #define HASH_SIZE  16
 #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
 
-static int ipip6_fb_tunnel_init(struct net_device *dev);
-static int ipip6_tunnel_init(struct net_device *dev);
+static void ipip6_fb_tunnel_init(struct net_device *dev);
+static void ipip6_tunnel_init(struct net_device *dev);
 static void ipip6_tunnel_setup(struct net_device *dev);
 
 static int sit_net_id;
@@ -188,7 +188,8 @@
 	}
 
 	nt = netdev_priv(dev);
-	dev->init = ipip6_tunnel_init;
+	ipip6_tunnel_init(dev);
+
 	nt->parms = *parms;
 
 	if (parms->i_flags & SIT_ISATAP)
@@ -926,13 +927,17 @@
 	return 0;
 }
 
+static const struct net_device_ops ipip6_netdev_ops = {
+	.ndo_uninit	= ipip6_tunnel_uninit,
+	.ndo_start_xmit	= ipip6_tunnel_xmit,
+	.ndo_do_ioctl	= ipip6_tunnel_ioctl,
+	.ndo_change_mtu	= ipip6_tunnel_change_mtu,
+};
+
 static void ipip6_tunnel_setup(struct net_device *dev)
 {
-	dev->uninit		= ipip6_tunnel_uninit;
+	dev->netdev_ops		= &ipip6_netdev_ops;
 	dev->destructor 	= free_netdev;
-	dev->hard_start_xmit	= ipip6_tunnel_xmit;
-	dev->do_ioctl		= ipip6_tunnel_ioctl;
-	dev->change_mtu		= ipip6_tunnel_change_mtu;
 
 	dev->type		= ARPHRD_SIT;
 	dev->hard_header_len 	= LL_MAX_HEADER + sizeof(struct iphdr);
@@ -943,11 +948,9 @@
 	dev->features		|= NETIF_F_NETNS_LOCAL;
 }
 
-static int ipip6_tunnel_init(struct net_device *dev)
+static void ipip6_tunnel_init(struct net_device *dev)
 {
-	struct ip_tunnel *tunnel;
-
-	tunnel = netdev_priv(dev);
+	struct ip_tunnel *tunnel = netdev_priv(dev);
 
 	tunnel->dev = dev;
 	strcpy(tunnel->parms.name, dev->name);
@@ -956,11 +959,9 @@
 	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
 
 	ipip6_tunnel_bind_dev(dev);
-
-	return 0;
 }
 
-static int ipip6_fb_tunnel_init(struct net_device *dev)
+static void ipip6_fb_tunnel_init(struct net_device *dev)
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
 	struct iphdr *iph = &tunnel->parms.iph;
@@ -977,7 +978,6 @@
 
 	dev_hold(dev);
 	sitn->tunnels_wc[0]	= tunnel;
-	return 0;
 }
 
 static struct xfrm_tunnel sit_handler = {
@@ -1025,16 +1025,17 @@
 		err = -ENOMEM;
 		goto err_alloc_dev;
 	}
-
-	sitn->fb_tunnel_dev->init = ipip6_fb_tunnel_init;
 	dev_net_set(sitn->fb_tunnel_dev, net);
 
+	ipip6_fb_tunnel_init(sitn->fb_tunnel_dev);
+
 	if ((err = register_netdev(sitn->fb_tunnel_dev)))
 		goto err_reg_dev;
 
 	return 0;
 
 err_reg_dev:
+	dev_put(sitn->fb_tunnel_dev);
 	free_netdev(sitn->fb_tunnel_dev);
 err_alloc_dev:
 	/* nothing */
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 676c80b..711175e 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -259,7 +259,7 @@
 
 		if (final_p)
 			ipv6_addr_copy(&fl.fl6_dst, final_p);
-		if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+		if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
 			goto out_free;
 	}
 
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 587f8f6..9048fe7 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -35,7 +35,7 @@
 		.data		= &init_net.ipv6.sysctl.bindv6only,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{ .ctl_name = 0 }
 };
@@ -47,7 +47,7 @@
 		.data		= &sysctl_mld_max_msf,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{ .ctl_name = 0 }
 };
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index b6b356b..8702b06 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -260,7 +260,8 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) {
+	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
+	if (err < 0) {
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, &fl);
 		if (err < 0)
@@ -390,7 +391,7 @@
 				goto out;
 			}
 
-			if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+			if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0) {
 				sk->sk_err_soft = -err;
 				goto out;
 			}
@@ -492,7 +493,7 @@
 		goto done;
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
-	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+	if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
 		goto done;
 
 	skb = tcp_make_synack(sk, dst, req);
@@ -501,7 +502,7 @@
 
 		th->check = tcp_v6_check(th, skb->len,
 					 &treq->loc_addr, &treq->rmt_addr,
-					 csum_partial((char *)th, skb->len, skb->csum));
+					 csum_partial(th, skb->len, skb->csum));
 
 		ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
 		err = ip6_xmit(sk, skb, &fl, opt, 0);
@@ -872,12 +873,10 @@
 
 	if (genhash || memcmp(hash_location, newhash, 16) != 0) {
 		if (net_ratelimit()) {
-			printk(KERN_INFO "MD5 Hash %s for "
-			       "(" NIP6_FMT ", %u)->"
-			       "(" NIP6_FMT ", %u)\n",
+			printk(KERN_INFO "MD5 Hash %s for (%pI6, %u)->(%pI6, %u)\n",
 			       genhash ? "failed" : "mismatch",
-			       NIP6(ip6h->saddr), ntohs(th->source),
-			       NIP6(ip6h->daddr), ntohs(th->dest));
+			       &ip6h->saddr, ntohs(th->source),
+			       &ip6h->daddr, ntohs(th->dest));
 		}
 		return 1;
 	}
@@ -917,7 +916,7 @@
 		skb->csum_offset = offsetof(struct tcphdr, check);
 	} else {
 		th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
-					    csum_partial((char *)th, th->doff<<2,
+					    csum_partial(th, th->doff<<2,
 							 skb->csum));
 	}
 }
@@ -999,7 +998,7 @@
 	}
 #endif
 
-	buff->csum = csum_partial((char *)t1, tot_len, 0);
+	buff->csum = csum_partial(t1, tot_len, 0);
 
 	memset(&fl, 0, sizeof(fl));
 	ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
@@ -1020,7 +1019,7 @@
 	 * namespace
 	 */
 	if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
-		if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
+		if (xfrm_lookup(net, &buff->dst, &fl, NULL, 0) >= 0) {
 			ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
 			TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
 			if (rst)
@@ -1318,7 +1317,7 @@
 		if (final_p)
 			ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-		if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+		if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
 			goto out;
 	}
 
@@ -1831,7 +1830,7 @@
 	sk->sk_sndbuf = sysctl_tcp_wmem[1];
 	sk->sk_rcvbuf = sysctl_tcp_rmem[1];
 
-	atomic_inc(&tcp_sockets_allocated);
+	percpu_counter_inc(&tcp_sockets_allocated);
 
 	return 0;
 }
@@ -2045,6 +2044,7 @@
 	.sysctl_rmem		= sysctl_tcp_rmem,
 	.max_header		= MAX_TCP_HEADER,
 	.obj_size		= sizeof(struct tcp6_sock),
+	.slab_flags		= SLAB_DESTROY_BY_RCU,
 	.twsk_prot		= &tcp6_timewait_sock_ops,
 	.rsk_prot		= &tcp6_request_sock_ops,
 	.h.hashinfo		= &tcp_hashinfo,
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 8b48512..84b1a29 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -54,62 +54,91 @@
 	return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal);
 }
 
+static inline int compute_score(struct sock *sk, struct net *net,
+				unsigned short hnum,
+				struct in6_addr *saddr, __be16 sport,
+				struct in6_addr *daddr, __be16 dport,
+				int dif)
+{
+	int score = -1;
+
+	if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum &&
+			sk->sk_family == PF_INET6) {
+		struct ipv6_pinfo *np = inet6_sk(sk);
+		struct inet_sock *inet = inet_sk(sk);
+
+		score = 0;
+		if (inet->dport) {
+			if (inet->dport != sport)
+				return -1;
+			score++;
+		}
+		if (!ipv6_addr_any(&np->rcv_saddr)) {
+			if (!ipv6_addr_equal(&np->rcv_saddr, daddr))
+				return -1;
+			score++;
+		}
+		if (!ipv6_addr_any(&np->daddr)) {
+			if (!ipv6_addr_equal(&np->daddr, saddr))
+				return -1;
+			score++;
+		}
+		if (sk->sk_bound_dev_if) {
+			if (sk->sk_bound_dev_if != dif)
+				return -1;
+			score++;
+		}
+	}
+	return score;
+}
+
 static struct sock *__udp6_lib_lookup(struct net *net,
 				      struct in6_addr *saddr, __be16 sport,
 				      struct in6_addr *daddr, __be16 dport,
-				      int dif, struct hlist_head udptable[])
+				      int dif, struct udp_table *udptable)
 {
-	struct sock *sk, *result = NULL;
-	struct hlist_node *node;
+	struct sock *sk, *result;
+	struct hlist_nulls_node *node;
 	unsigned short hnum = ntohs(dport);
-	int badness = -1;
+	unsigned int hash = udp_hashfn(net, hnum);
+	struct udp_hslot *hslot = &udptable->hash[hash];
+	int score, badness;
 
-	read_lock(&udp_hash_lock);
-	sk_for_each(sk, node, &udptable[udp_hashfn(net, hnum)]) {
-		struct inet_sock *inet = inet_sk(sk);
-
-		if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum &&
-				sk->sk_family == PF_INET6) {
-			struct ipv6_pinfo *np = inet6_sk(sk);
-			int score = 0;
-			if (inet->dport) {
-				if (inet->dport != sport)
-					continue;
-				score++;
-			}
-			if (!ipv6_addr_any(&np->rcv_saddr)) {
-				if (!ipv6_addr_equal(&np->rcv_saddr, daddr))
-					continue;
-				score++;
-			}
-			if (!ipv6_addr_any(&np->daddr)) {
-				if (!ipv6_addr_equal(&np->daddr, saddr))
-					continue;
-				score++;
-			}
-			if (sk->sk_bound_dev_if) {
-				if (sk->sk_bound_dev_if != dif)
-					continue;
-				score++;
-			}
-			if (score == 4) {
-				result = sk;
-				break;
-			} else if (score > badness) {
-				result = sk;
-				badness = score;
-			}
+	rcu_read_lock();
+begin:
+	result = NULL;
+	badness = -1;
+	sk_nulls_for_each_rcu(sk, node, &hslot->head) {
+		score = compute_score(sk, net, hnum, saddr, sport, daddr, dport, dif);
+		if (score > badness) {
+			result = sk;
+			badness = score;
 		}
 	}
-	if (result)
-		sock_hold(result);
-	read_unlock(&udp_hash_lock);
+	/*
+	 * if the nulls value we got at the end of this lookup is
+	 * not the expected one, we must restart lookup.
+	 * We probably met an item that was moved to another chain.
+	 */
+	if (get_nulls_value(node) != hash)
+		goto begin;
+
+	if (result) {
+		if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt)))
+			result = NULL;
+		else if (unlikely(compute_score(result, net, hnum, saddr, sport,
+					daddr, dport, dif) < badness)) {
+			sock_put(result);
+			goto begin;
+		}
+	}
+	rcu_read_unlock();
 	return result;
 }
 
 static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,
 					  __be16 sport, __be16 dport,
-					  struct hlist_head udptable[])
+					  struct udp_table *udptable)
 {
 	struct sock *sk;
 	struct ipv6hdr *iph = ipv6_hdr(skb);
@@ -253,7 +282,7 @@
 
 void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 		    int type, int code, int offset, __be32 info,
-		    struct hlist_head udptable[]                    )
+		    struct udp_table *udptable)
 {
 	struct ipv6_pinfo *np;
 	struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
@@ -289,7 +318,7 @@
 				 struct inet6_skb_parm *opt, int type,
 				 int code, int offset, __be32 info     )
 {
-	__udp6_lib_err(skb, opt, type, code, offset, info, udp_hash);
+	__udp6_lib_err(skb, opt, type, code, offset, info, &udp_table);
 }
 
 int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
@@ -347,11 +376,11 @@
 				      __be16 rmt_port, struct in6_addr *rmt_addr,
 				      int dif)
 {
-	struct hlist_node *node;
+	struct hlist_nulls_node *node;
 	struct sock *s = sk;
 	unsigned short num = ntohs(loc_port);
 
-	sk_for_each_from(s, node) {
+	sk_nulls_for_each_from(s, node) {
 		struct inet_sock *inet = inet_sk(s);
 
 		if (!net_eq(sock_net(s), net))
@@ -388,14 +417,15 @@
  */
 static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 		struct in6_addr *saddr, struct in6_addr *daddr,
-		struct hlist_head udptable[])
+		struct udp_table *udptable)
 {
 	struct sock *sk, *sk2;
 	const struct udphdr *uh = udp_hdr(skb);
+	struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))];
 	int dif;
 
-	read_lock(&udp_hash_lock);
-	sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]);
+	spin_lock(&hslot->lock);
+	sk = sk_nulls_head(&hslot->head);
 	dif = inet6_iif(skb);
 	sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif);
 	if (!sk) {
@@ -404,7 +434,7 @@
 	}
 
 	sk2 = sk;
-	while ((sk2 = udp_v6_mcast_next(net, sk_next(sk2), uh->dest, daddr,
+	while ((sk2 = udp_v6_mcast_next(net, sk_nulls_next(sk2), uh->dest, daddr,
 					uh->source, saddr, dif))) {
 		struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC);
 		if (buff) {
@@ -423,7 +453,7 @@
 		sk_add_backlog(sk, skb);
 	bh_unlock_sock(sk);
 out:
-	read_unlock(&udp_hash_lock);
+	spin_unlock(&hslot->lock);
 	return 0;
 }
 
@@ -461,7 +491,7 @@
 	return 0;
 }
 
-int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
+int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
 		   int proto)
 {
 	struct sock *sk;
@@ -558,7 +588,7 @@
 
 static __inline__ int udpv6_rcv(struct sk_buff *skb)
 {
-	return __udp6_lib_rcv(skb, udp_hash, IPPROTO_UDP);
+	return __udp6_lib_rcv(skb, &udp_table, IPPROTO_UDP);
 }
 
 /*
@@ -763,6 +793,9 @@
 	if (!fl.oif)
 		fl.oif = sk->sk_bound_dev_if;
 
+	if (!fl.oif)
+		fl.oif = np->sticky_pktinfo.ipi6_ifindex;
+
 	if (msg->msg_controllen) {
 		opt = &opt_space;
 		memset(opt, 0, sizeof(struct ipv6_txoptions));
@@ -819,7 +852,8 @@
 	if (final_p)
 		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) {
+	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
+	if (err < 0) {
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, &fl);
 		if (err < 0)
@@ -1022,7 +1056,7 @@
 static struct udp_seq_afinfo udp6_seq_afinfo = {
 	.name		= "udp6",
 	.family		= AF_INET6,
-	.hashtable	= udp_hash,
+	.udp_table	= &udp_table,
 	.seq_fops	= {
 		.owner	=	THIS_MODULE,
 	},
@@ -1064,7 +1098,8 @@
 	.sysctl_wmem	   = &sysctl_udp_wmem_min,
 	.sysctl_rmem	   = &sysctl_udp_rmem_min,
 	.obj_size	   = sizeof(struct udp6_sock),
-	.h.udp_hash	   = udp_hash,
+	.slab_flags	   = SLAB_DESTROY_BY_RCU,
+	.h.udp_table	   = &udp_table,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udpv6_setsockopt,
 	.compat_getsockopt = compat_udpv6_getsockopt,
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h
index 92dd7da..2377920 100644
--- a/net/ipv6/udp_impl.h
+++ b/net/ipv6/udp_impl.h
@@ -7,9 +7,9 @@
 #include <net/inet_common.h>
 #include <net/transp_v6.h>
 
-extern int  	__udp6_lib_rcv(struct sk_buff *, struct hlist_head [], int );
+extern int  	__udp6_lib_rcv(struct sk_buff *, struct udp_table *, int );
 extern void 	__udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *,
-			       int , int , int , __be32 , struct hlist_head []);
+			       int , int , int , __be32 , struct udp_table *);
 
 extern int	udp_v6_get_port(struct sock *sk, unsigned short snum);
 
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index 3cd1a1a..ba162a8 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -15,14 +15,14 @@
 
 static int udplitev6_rcv(struct sk_buff *skb)
 {
-	return __udp6_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE);
+	return __udp6_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE);
 }
 
 static void udplitev6_err(struct sk_buff *skb,
 			  struct inet6_skb_parm *opt,
 			  int type, int code, int offset, __be32 info)
 {
-	__udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash);
+	__udp6_lib_err(skb, opt, type, code, offset, info, &udplite_table);
 }
 
 static struct inet6_protocol udplitev6_protocol = {
@@ -49,7 +49,8 @@
 	.unhash		   = udp_lib_unhash,
 	.get_port	   = udp_v6_get_port,
 	.obj_size	   = sizeof(struct udp6_sock),
-	.h.udp_hash	   = udplite_hash,
+	.slab_flags	   = SLAB_DESTROY_BY_RCU,
+	.h.udp_table	   = &udplite_table,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udpv6_setsockopt,
 	.compat_getsockopt = compat_udpv6_getsockopt,
@@ -95,7 +96,7 @@
 static struct udp_seq_afinfo udplite6_seq_afinfo = {
 	.name		= "udplite6",
 	.family		= AF_INET6,
-	.hashtable	= udplite_hash,
+	.udp_table	= &udplite_table,
 	.seq_fops	= {
 		.owner	=	THIS_MODULE,
 	},
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index a71c7dd..9084582 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -58,6 +58,7 @@
 int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 		     xfrm_address_t *saddr, u8 proto)
 {
+	struct net *net = dev_net(skb->dev);
 	struct xfrm_state *x = NULL;
 	int i = 0;
 
@@ -67,7 +68,7 @@
 
 		sp = secpath_dup(skb->sp);
 		if (!sp) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
 			goto drop;
 		}
 		if (skb->sp)
@@ -76,7 +77,7 @@
 	}
 
 	if (1 + skb->sp->len == XFRM_MAX_DEPTH) {
-		XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR);
+		XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
 		goto drop;
 	}
 
@@ -100,7 +101,7 @@
 			break;
 		}
 
-		x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6);
+		x = xfrm_state_lookup_byaddr(net, dst, src, proto, AF_INET6);
 		if (!x)
 			continue;
 
@@ -122,7 +123,7 @@
 	}
 
 	if (!x) {
-		XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES);
+		XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
 		xfrm_audit_state_notfound_simple(skb, AF_INET6);
 		goto drop;
 	}
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 08e4cbb..97ab068 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -27,7 +27,8 @@
 static struct dst_ops xfrm6_dst_ops;
 static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
 
-static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr,
+static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos,
+					  xfrm_address_t *saddr,
 					  xfrm_address_t *daddr)
 {
 	struct flowi fl = {};
@@ -38,7 +39,7 @@
 	if (saddr)
 		memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src));
 
-	dst = ip6_route_output(&init_net, NULL, &fl);
+	dst = ip6_route_output(net, NULL, &fl);
 
 	err = dst->error;
 	if (dst->error) {
@@ -49,12 +50,13 @@
 	return dst;
 }
 
-static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
+static int xfrm6_get_saddr(struct net *net,
+			   xfrm_address_t *saddr, xfrm_address_t *daddr)
 {
 	struct dst_entry *dst;
 	struct net_device *dev;
 
-	dst = xfrm6_dst_lookup(0, NULL, daddr);
+	dst = xfrm6_dst_lookup(net, 0, NULL, daddr);
 	if (IS_ERR(dst))
 		return -EHOSTUNREACH;
 
@@ -144,6 +146,7 @@
 static inline void
 _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
 {
+	int onlyproto = 0;
 	u16 offset = skb_network_header_len(skb);
 	struct ipv6hdr *hdr = ipv6_hdr(skb);
 	struct ipv6_opt_hdr *exthdr;
@@ -159,6 +162,8 @@
 		exthdr = (struct ipv6_opt_hdr *)(nh + offset);
 
 		switch (nexthdr) {
+		case NEXTHDR_FRAGMENT:
+			onlyproto = 1;
 		case NEXTHDR_ROUTING:
 		case NEXTHDR_HOP:
 		case NEXTHDR_DEST:
@@ -172,7 +177,7 @@
 		case IPPROTO_TCP:
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
-			if (pskb_may_pull(skb, nh + offset + 4 - skb->data)) {
+			if (!onlyproto && pskb_may_pull(skb, nh + offset + 4 - skb->data)) {
 				__be16 *ports = (__be16 *)exthdr;
 
 				fl->fl_ip_sport = ports[!!reverse];
@@ -182,7 +187,7 @@
 			return;
 
 		case IPPROTO_ICMPV6:
-			if (pskb_may_pull(skb, nh + offset + 2 - skb->data)) {
+			if (!onlyproto && pskb_may_pull(skb, nh + offset + 2 - skb->data)) {
 				u8 *icmp = (u8 *)exthdr;
 
 				fl->fl_icmp_type = icmp[0];
@@ -193,7 +198,7 @@
 
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
 		case IPPROTO_MH:
-			if (pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
+			if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
 				struct ip6_mh *mh;
 				mh = (struct ip6_mh *)exthdr;
 
@@ -217,7 +222,7 @@
 
 static inline int xfrm6_garbage_collect(struct dst_ops *ops)
 {
-	xfrm6_policy_afinfo.garbage_collect();
+	xfrm6_policy_afinfo.garbage_collect(&init_net);
 	return (atomic_read(&xfrm6_dst_ops.entries) > xfrm6_dst_ops.gc_thresh*2);
 }
 
@@ -274,7 +279,6 @@
 	.ifdown =		xfrm6_dst_ifdown,
 	.local_out =		__ip6_local_out,
 	.gc_thresh =		1024,
-	.entry_size =		sizeof(struct xfrm_dst),
 	.entries =		ATOMIC_INIT(0),
 };
 
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index 60c78cf..0e685b0 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -19,8 +19,6 @@
 #include <net/ipv6.h>
 #include <net/addrconf.h>
 
-static struct xfrm_state_afinfo xfrm6_state_afinfo;
-
 static void
 __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
 		     struct xfrm_tmpl *tmpl,
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index c2b2781..80193db 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -345,24 +345,23 @@
 static int __init xfrm6_tunnel_init(void)
 {
 	if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0)
-		return -EAGAIN;
-
-	if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) {
-		xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
-		return -EAGAIN;
-	}
-	if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) {
-		xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
-		xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
-		return -EAGAIN;
-	}
-	if (xfrm6_tunnel_spi_init() < 0) {
-		xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
-		xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
-		xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
-		return -EAGAIN;
-	}
+		goto err;
+	if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6))
+		goto unreg;
+	if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET))
+		goto dereg6;
+	if (xfrm6_tunnel_spi_init() < 0)
+		goto dereg46;
 	return 0;
+
+dereg46:
+	xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
+dereg6:
+	xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
+unreg:
+	xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
+err:
+	return -EAGAIN;
 }
 
 static void __exit xfrm6_tunnel_fini(void)
diff --git a/net/ipx/sysctl_net_ipx.c b/net/ipx/sysctl_net_ipx.c
index 92fef86..633fcab 100644
--- a/net/ipx/sysctl_net_ipx.c
+++ b/net/ipx/sysctl_net_ipx.c
@@ -23,7 +23,7 @@
 		.data		= &sysctl_ipx_pprop_broadcasting,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{ 0 },
 };
diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c
index 6be1ec2..42f7d96 100644
--- a/net/irda/irlan/irlan_client.c
+++ b/net/irda/irlan/irlan_client.c
@@ -436,7 +436,6 @@
 	__u16 tmp_cpu; /* Temporary value in host order */
 	__u8 *bytes;
 	int i;
-	DECLARE_MAC_BUF(mac);
 
 	IRDA_DEBUG(4, "%s(), parm=%s\n", __func__ , param);
 
@@ -521,8 +520,7 @@
 	/* FILTER_ENTRY, have we got an ethernet address? */
 	if (strcmp(param, "FILTER_ENTRY") == 0) {
 		bytes = value;
-		IRDA_DEBUG(4, "Ethernet address = %s\n",
-			   print_mac(mac, bytes));
+		IRDA_DEBUG(4, "Ethernet address = %pM\n", bytes);
 		for (i = 0; i < 6; i++)
 			self->dev->dev_addr[i] = bytes[i];
 	}
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index 9a1cd87..774d73a 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -207,7 +207,7 @@
 	if (!dev)
 		return NULL;
 
-	self = dev->priv;
+	self = netdev_priv(dev);
 	self->dev = dev;
 
 	/*
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index f17b65a..2562ebc 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -1325,6 +1325,7 @@
 	struct irlap_cb *self;
 	int command;
 	__u8 control;
+	int ret = -1;
 
 	if (!net_eq(dev_net(dev), &init_net))
 		goto out;
@@ -1333,25 +1334,21 @@
 	self = (struct irlap_cb *) dev->atalk_ptr;
 
 	/* If the net device is down, then IrLAP is gone! */
-	if (!self || self->magic != LAP_MAGIC) {
-		dev_kfree_skb(skb);
-		return -1;
-	}
+	if (!self || self->magic != LAP_MAGIC)
+		goto err;
 
 	/* We are no longer an "old" protocol, so we need to handle
 	 * share and non linear skbs. This should never happen, so
 	 * we don't need to be clever about it. Jean II */
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
 		IRDA_ERROR("%s: can't clone shared skb!\n", __func__);
-		dev_kfree_skb(skb);
-		return -1;
+		goto err;
 	}
 
 	/* Check if frame is large enough for parsing */
 	if (!pskb_may_pull(skb, 2)) {
 		IRDA_ERROR("%s: frame too short!\n", __func__);
-		dev_kfree_skb(skb);
-		return -1;
+		goto err;
 	}
 
 	command    = skb->data[0] & CMD_FRAME;
@@ -1442,7 +1439,9 @@
 		break;
 	}
 out:
+	ret = 0;
+err:
 	/* Always drop our reference on the skb */
 	dev_kfree_skb(skb);
-	return 0;
+	return ret;
 }
diff --git a/net/irda/irsysctl.c b/net/irda/irsysctl.c
index 9ab3df1..57f8817 100644
--- a/net/irda/irsysctl.c
+++ b/net/irda/irsysctl.c
@@ -118,8 +118,8 @@
 		.data		= &sysctl_discovery,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &do_discovery,
-		.strategy       = &sysctl_intvec
+		.proc_handler	= do_discovery,
+		.strategy       = sysctl_intvec
 	},
 	{
 		.ctl_name	= NET_IRDA_DEVNAME,
@@ -127,8 +127,8 @@
 		.data		= sysctl_devname,
 		.maxlen		= 65,
 		.mode		= 0644,
-		.proc_handler	= &do_devname,
-		.strategy	= &sysctl_string
+		.proc_handler	= do_devname,
+		.strategy	= sysctl_string
 	},
 #ifdef CONFIG_IRDA_DEBUG
 	{
@@ -137,7 +137,7 @@
 		.data		= &irda_debug,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 #endif
 #ifdef CONFIG_IRDA_FAST_RR
@@ -147,7 +147,7 @@
 		.data		= &sysctl_fast_poll_increase,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 #endif
 	{
@@ -156,8 +156,8 @@
 		.data		= &sysctl_discovery_slots,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_discovery_slots,
 		.extra2		= &max_discovery_slots
 	},
@@ -167,7 +167,7 @@
 		.data		= &sysctl_discovery_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{
 		.ctl_name	= NET_IRDA_SLOT_TIMEOUT,
@@ -175,8 +175,8 @@
 		.data		= &sysctl_slot_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_slot_timeout,
 		.extra2		= &max_slot_timeout
 	},
@@ -186,8 +186,8 @@
 		.data		= &sysctl_max_baud_rate,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_max_baud_rate,
 		.extra2		= &max_max_baud_rate
 	},
@@ -197,8 +197,8 @@
 		.data		= &sysctl_min_tx_turn_time,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_min_tx_turn_time,
 		.extra2		= &max_min_tx_turn_time
 	},
@@ -208,8 +208,8 @@
 		.data		= &sysctl_max_tx_data_size,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_max_tx_data_size,
 		.extra2		= &max_max_tx_data_size
 	},
@@ -219,8 +219,8 @@
 		.data		= &sysctl_max_tx_window,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_max_tx_window,
 		.extra2		= &max_max_tx_window
 	},
@@ -230,8 +230,8 @@
 		.data		= &sysctl_max_noreply_time,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_max_noreply_time,
 		.extra2		= &max_max_noreply_time
 	},
@@ -241,8 +241,8 @@
 		.data		= &sysctl_warn_noreply_time,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_warn_noreply_time,
 		.extra2		= &max_warn_noreply_time
 	},
@@ -252,8 +252,8 @@
 		.data		= &sysctl_lap_keepalive_time,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_lap_keepalive_time,
 		.extra2		= &max_lap_keepalive_time
 	},
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index 74e439e..ecf4eb2 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -201,7 +201,7 @@
  *
  *     Flushes (removes all frames) in transitt-buffer (tx_list)
  */
-void irttp_flush_queues(struct tsap_cb *self)
+static void irttp_flush_queues(struct tsap_cb *self)
 {
 	struct sk_buff* skb;
 
@@ -1266,9 +1266,9 @@
  *    Some other device is connecting to this TSAP
  *
  */
-void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
-			      __u32 max_seg_size, __u8 max_header_size,
-			      struct sk_buff *skb)
+static void irttp_connect_indication(void *instance, void *sap,
+		struct qos_info *qos, __u32 max_seg_size, __u8 max_header_size,
+		struct sk_buff *skb)
 {
 	struct tsap_cb *self;
 	struct lsap_cb *lsap;
@@ -1579,8 +1579,8 @@
  *    Disconnect indication, TSAP disconnected by peer?
  *
  */
-void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason,
-				 struct sk_buff *skb)
+static void irttp_disconnect_indication(void *instance, void *sap,
+		LM_REASON reason, struct sk_buff *skb)
 {
 	struct tsap_cb *self;
 
@@ -1664,7 +1664,7 @@
  *     Check if we have any frames to be transmitted, or if we have any
  *     available credit to give away.
  */
-void irttp_run_rx_queue(struct tsap_cb *self)
+static void irttp_run_rx_queue(struct tsap_cb *self)
 {
 	struct sk_buff *skb;
 	int more = 0;
diff --git a/net/irda/timer.c b/net/irda/timer.c
index d730099..0335ba0 100644
--- a/net/irda/timer.c
+++ b/net/irda/timer.c
@@ -219,7 +219,7 @@
  *
  *
  */
-void irlap_media_busy_expired(void* data)
+static void irlap_media_busy_expired(void *data)
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index 29f7baa..af3192d 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -8,6 +8,9 @@
  *  Author(s):	Jennifer Hunt <jenhunt@us.ibm.com>
  */
 
+#define KMSG_COMPONENT "af_iucv"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/list.h>
@@ -616,6 +619,8 @@
 	struct iucv_sock *iucv = iucv_sk(sk);
 	struct sk_buff *skb;
 	struct iucv_message txmsg;
+	char user_id[9];
+	char appl_id[9];
 	int err;
 
 	err = sock_error(sk);
@@ -651,8 +656,15 @@
 		err = iucv_message_send(iucv->path, &txmsg, 0, 0,
 					(void *) skb->data, skb->len);
 		if (err) {
-			if (err == 3)
-				printk(KERN_ERR "AF_IUCV msg limit exceeded\n");
+			if (err == 3) {
+				user_id[8] = 0;
+				memcpy(user_id, iucv->dst_user_id, 8);
+				appl_id[8] = 0;
+				memcpy(appl_id, iucv->dst_name, 8);
+				pr_err("Application %s on z/VM guest %s"
+				       " exceeds message limit\n",
+				       user_id, appl_id);
+			}
 			skb_unlink(skb, &iucv->send_skb_q);
 			err = -EPIPE;
 			goto fail;
@@ -1190,7 +1202,8 @@
 	int err;
 
 	if (!MACHINE_IS_VM) {
-		printk(KERN_ERR "AF_IUCV connection needs VM as base\n");
+		pr_err("The af_iucv module cannot be loaded"
+		       " without z/VM\n");
 		err = -EPROTONOSUPPORT;
 		goto out;
 	}
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index d7b54b5..8f57d4f 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -30,6 +30,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define KMSG_COMPONENT "iucv"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/spinlock.h>
@@ -424,8 +427,8 @@
 			err = "Paging or storage error";
 			break;
 		}
-		printk(KERN_WARNING "iucv_register: iucv_declare_buffer "
-		       "on cpu %i returned error 0x%02x (%s)\n", cpu, rc, err);
+		pr_warning("Defining an interrupt buffer on CPU %i"
+			   " failed with 0x%02x (%s)\n", cpu, rc, err);
 		return;
 	}
 
@@ -957,7 +960,52 @@
 EXPORT_SYMBOL(iucv_message_purge);
 
 /**
- * iucv_message_receive
+ * iucv_message_receive_iprmdata
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is received (IUCV_IPBUFLST)
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of data buffer
+ * @residual:
+ *
+ * Internal function used by iucv_message_receive and __iucv_message_receive
+ * to receive RMDATA data stored in struct iucv_message.
+ */
+static int iucv_message_receive_iprmdata(struct iucv_path *path,
+					 struct iucv_message *msg,
+					 u8 flags, void *buffer,
+					 size_t size, size_t *residual)
+{
+	struct iucv_array *array;
+	u8 *rmmsg;
+	size_t copy;
+
+	/*
+	 * Message is 8 bytes long and has been stored to the
+	 * message descriptor itself.
+	 */
+	if (residual)
+		*residual = abs(size - 8);
+	rmmsg = msg->rmmsg;
+	if (flags & IUCV_IPBUFLST) {
+		/* Copy to struct iucv_array. */
+		size = (size < 8) ? size : 8;
+		for (array = buffer; size > 0; array++) {
+			copy = min_t(size_t, size, array->length);
+			memcpy((u8 *)(addr_t) array->address,
+				rmmsg, copy);
+			rmmsg += copy;
+			size -= copy;
+		}
+	} else {
+		/* Copy to direct buffer. */
+		memcpy(buffer, rmmsg, min_t(size_t, size, 8));
+	}
+	return 0;
+}
+
+/**
+ * __iucv_message_receive
  * @path: address of iucv path structure
  * @msg: address of iucv msg structure
  * @flags: how the message is received (IUCV_IPBUFLST)
@@ -969,44 +1017,19 @@
  * established paths. This function will deal with RMDATA messages
  * embedded in struct iucv_message as well.
  *
+ * Locking:	no locking
+ *
  * Returns the result from the CP IUCV call.
  */
-int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
-			 u8 flags, void *buffer, size_t size, size_t *residual)
+int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
+			   u8 flags, void *buffer, size_t size, size_t *residual)
 {
 	union iucv_param *parm;
-	struct iucv_array *array;
-	u8 *rmmsg;
-	size_t copy;
 	int rc;
 
-	if (msg->flags & IUCV_IPRMDATA) {
-		/*
-		 * Message is 8 bytes long and has been stored to the
-		 * message descriptor itself.
-		 */
-		rc = (size < 8) ? 5 : 0;
-		if (residual)
-			*residual = abs(size - 8);
-		rmmsg = msg->rmmsg;
-		if (flags & IUCV_IPBUFLST) {
-			/* Copy to struct iucv_array. */
-			size = (size < 8) ? size : 8;
-			for (array = buffer; size > 0; array++) {
-				copy = min_t(size_t, size, array->length);
-				memcpy((u8 *)(addr_t) array->address,
-				       rmmsg, copy);
-				rmmsg += copy;
-				size -= copy;
-			}
-		} else {
-			/* Copy to direct buffer. */
-			memcpy(buffer, rmmsg, min_t(size_t, size, 8));
-		}
-		return 0;
-	}
-
-	local_bh_disable();
+	if (msg->flags & IUCV_IPRMDATA)
+		return iucv_message_receive_iprmdata(path, msg, flags,
+						     buffer, size, residual);
 	parm = iucv_param[smp_processor_id()];
 	memset(parm, 0, sizeof(union iucv_param));
 	parm->db.ipbfadr1 = (u32)(addr_t) buffer;
@@ -1022,6 +1045,37 @@
 		if (residual)
 			*residual = parm->db.ipbfln1f;
 	}
+	return rc;
+}
+EXPORT_SYMBOL(__iucv_message_receive);
+
+/**
+ * iucv_message_receive
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is received (IUCV_IPBUFLST)
+ * @buffer: address of data buffer or address of struct iucv_array
+ * @size: length of data buffer
+ * @residual:
+ *
+ * This function receives messages that are being sent to you over
+ * established paths. This function will deal with RMDATA messages
+ * embedded in struct iucv_message as well.
+ *
+ * Locking:	local_bh_enable/local_bh_disable
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
+			 u8 flags, void *buffer, size_t size, size_t *residual)
+{
+	int rc;
+
+	if (msg->flags & IUCV_IPRMDATA)
+		return iucv_message_receive_iprmdata(path, msg, flags,
+						     buffer, size, residual);
+	local_bh_disable();
+	rc = __iucv_message_receive(path, msg, flags, buffer, size, residual);
 	local_bh_enable();
 	return rc;
 }
@@ -1101,7 +1155,7 @@
 EXPORT_SYMBOL(iucv_message_reply);
 
 /**
- * iucv_message_send
+ * __iucv_message_send
  * @path: address of iucv path structure
  * @msg: address of iucv msg structure
  * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
@@ -1113,15 +1167,16 @@
  * transmitted is in a buffer and this is a one-way message and the
  * receiver will not reply to the message.
  *
+ * Locking:	no locking
+ *
  * Returns the result from the CP IUCV call.
  */
-int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
+int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
 		      u8 flags, u32 srccls, void *buffer, size_t size)
 {
 	union iucv_param *parm;
 	int rc;
 
-	local_bh_disable();
 	parm = iucv_param[smp_processor_id()];
 	memset(parm, 0, sizeof(union iucv_param));
 	if (flags & IUCV_IPRMDATA) {
@@ -1144,6 +1199,34 @@
 	rc = iucv_call_b2f0(IUCV_SEND, parm);
 	if (!rc)
 		msg->id = parm->db.ipmsgid;
+	return rc;
+}
+EXPORT_SYMBOL(__iucv_message_send);
+
+/**
+ * iucv_message_send
+ * @path: address of iucv path structure
+ * @msg: address of iucv msg structure
+ * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
+ * @srccls: source class of message
+ * @buffer: address of send buffer or address of struct iucv_array
+ * @size: length of send buffer
+ *
+ * This function transmits data to another application. Data to be
+ * transmitted is in a buffer and this is a one-way message and the
+ * receiver will not reply to the message.
+ *
+ * Locking:	local_bh_enable/local_bh_disable
+ *
+ * Returns the result from the CP IUCV call.
+ */
+int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
+		      u8 flags, u32 srccls, void *buffer, size_t size)
+{
+	int rc;
+
+	local_bh_disable();
+	rc = __iucv_message_send(path, msg, flags, srccls, buffer, size);
 	local_bh_enable();
 	return rc;
 }
@@ -1572,7 +1655,7 @@
 	BUG_ON(p->iptype  < 0x01 || p->iptype > 0x09);
 	work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC);
 	if (!work) {
-		printk(KERN_WARNING "iucv_external_interrupt: out of memory\n");
+		pr_warning("iucv_external_interrupt: out of memory\n");
 		return;
 	}
 	memcpy(&work->data, p, sizeof(work->data));
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 5b22e01..f8bd8df 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -27,6 +27,7 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <net/net_namespace.h>
+#include <net/netns/generic.h>
 #include <net/xfrm.h>
 
 #include <net/sock.h>
@@ -34,15 +35,16 @@
 #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x))
 #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x))
 
-
-/* List of all pfkey sockets. */
-static HLIST_HEAD(pfkey_table);
+static int pfkey_net_id;
+struct netns_pfkey {
+	/* List of all pfkey sockets. */
+	struct hlist_head table;
+	atomic_t socks_nr;
+};
 static DECLARE_WAIT_QUEUE_HEAD(pfkey_table_wait);
 static DEFINE_RWLOCK(pfkey_table_lock);
 static atomic_t pfkey_table_users = ATOMIC_INIT(0);
 
-static atomic_t pfkey_socks_nr = ATOMIC_INIT(0);
-
 struct pfkey_sock {
 	/* struct sock must be the first member of struct pfkey_sock */
 	struct sock	sk;
@@ -89,6 +91,9 @@
 
 static void pfkey_sock_destruct(struct sock *sk)
 {
+	struct net *net = sock_net(sk);
+	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
+
 	pfkey_terminate_dump(pfkey_sk(sk));
 	skb_queue_purge(&sk->sk_receive_queue);
 
@@ -100,7 +105,7 @@
 	WARN_ON(atomic_read(&sk->sk_rmem_alloc));
 	WARN_ON(atomic_read(&sk->sk_wmem_alloc));
 
-	atomic_dec(&pfkey_socks_nr);
+	atomic_dec(&net_pfkey->socks_nr);
 }
 
 static void pfkey_table_grab(void)
@@ -151,8 +156,11 @@
 
 static void pfkey_insert(struct sock *sk)
 {
+	struct net *net = sock_net(sk);
+	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
+
 	pfkey_table_grab();
-	sk_add_node(sk, &pfkey_table);
+	sk_add_node(sk, &net_pfkey->table);
 	pfkey_table_ungrab();
 }
 
@@ -171,12 +179,10 @@
 
 static int pfkey_create(struct net *net, struct socket *sock, int protocol)
 {
+	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
 	struct sock *sk;
 	int err;
 
-	if (net != &init_net)
-		return -EAFNOSUPPORT;
-
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 	if (sock->type != SOCK_RAW)
@@ -195,7 +201,7 @@
 	sk->sk_family = PF_KEY;
 	sk->sk_destruct = pfkey_sock_destruct;
 
-	atomic_inc(&pfkey_socks_nr);
+	atomic_inc(&net_pfkey->socks_nr);
 
 	pfkey_insert(sk);
 
@@ -255,8 +261,10 @@
 #define BROADCAST_REGISTERED	2
 #define BROADCAST_PROMISC_ONLY	4
 static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
-			   int broadcast_flags, struct sock *one_sk)
+			   int broadcast_flags, struct sock *one_sk,
+			   struct net *net)
 {
+	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
 	struct sock *sk;
 	struct hlist_node *node;
 	struct sk_buff *skb2 = NULL;
@@ -269,7 +277,7 @@
 		return -ENOMEM;
 
 	pfkey_lock_table();
-	sk_for_each(sk, node, &pfkey_table) {
+	sk_for_each(sk, node, &net_pfkey->table) {
 		struct pfkey_sock *pfk = pfkey_sk(sk);
 		int err2;
 
@@ -328,7 +336,7 @@
 		hdr->sadb_msg_seq = 0;
 		hdr->sadb_msg_errno = rc;
 		pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
-				&pfk->sk);
+				&pfk->sk, sock_net(&pfk->sk));
 		pfk->dump.skb = NULL;
 	}
 
@@ -367,7 +375,7 @@
 	hdr->sadb_msg_len = (sizeof(struct sadb_msg) /
 			     sizeof(uint64_t));
 
-	pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk);
+	pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk, sock_net(sk));
 
 	return 0;
 }
@@ -645,7 +653,7 @@
 				      xaddr);
 }
 
-static struct  xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **ext_hdrs)
+static struct  xfrm_state *pfkey_xfrm_state_lookup(struct net *net, struct sadb_msg *hdr, void **ext_hdrs)
 {
 	struct sadb_sa *sa;
 	struct sadb_address *addr;
@@ -683,7 +691,7 @@
 	if (!xaddr)
 		return NULL;
 
-	return xfrm_state_lookup(xaddr, sa->sadb_sa_spi, proto, family);
+	return xfrm_state_lookup(net, xaddr, sa->sadb_sa_spi, proto, family);
 }
 
 #define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1)))
@@ -1058,7 +1066,8 @@
 	return __pfkey_xfrm_state2msg(x, 0, hsc);
 }
 
-static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
+static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
+						struct sadb_msg *hdr,
 						void **ext_hdrs)
 {
 	struct xfrm_state *x;
@@ -1122,7 +1131,7 @@
 	     (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))
 		return ERR_PTR(-EINVAL);
 
-	x = xfrm_state_alloc();
+	x = xfrm_state_alloc(net);
 	if (x == NULL)
 		return ERR_PTR(-ENOBUFS);
 
@@ -1298,6 +1307,7 @@
 
 static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
+	struct net *net = sock_net(sk);
 	struct sk_buff *resp_skb;
 	struct sadb_x_sa2 *sa2;
 	struct sadb_address *saddr, *daddr;
@@ -1348,7 +1358,7 @@
 	}
 
 	if (hdr->sadb_msg_seq) {
-		x = xfrm_find_acq_byseq(hdr->sadb_msg_seq);
+		x = xfrm_find_acq_byseq(net, hdr->sadb_msg_seq);
 		if (x && xfrm_addr_cmp(&x->id.daddr, xdaddr, family)) {
 			xfrm_state_put(x);
 			x = NULL;
@@ -1356,7 +1366,7 @@
 	}
 
 	if (!x)
-		x = xfrm_find_acq(mode, reqid, proto, xdaddr, xsaddr, 1, family);
+		x = xfrm_find_acq(net, mode, reqid, proto, xdaddr, xsaddr, 1, family);
 
 	if (x == NULL)
 		return -ENOENT;
@@ -1389,13 +1399,14 @@
 
 	xfrm_state_put(x);
 
-	pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk);
+	pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk, net);
 
 	return 0;
 }
 
 static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
+	struct net *net = sock_net(sk);
 	struct xfrm_state *x;
 
 	if (hdr->sadb_msg_len != sizeof(struct sadb_msg)/8)
@@ -1404,14 +1415,14 @@
 	if (hdr->sadb_msg_seq == 0 || hdr->sadb_msg_errno == 0)
 		return 0;
 
-	x = xfrm_find_acq_byseq(hdr->sadb_msg_seq);
+	x = xfrm_find_acq_byseq(net, hdr->sadb_msg_seq);
 	if (x == NULL)
 		return 0;
 
 	spin_lock_bh(&x->lock);
 	if (x->km.state == XFRM_STATE_ACQ) {
 		x->km.state = XFRM_STATE_ERROR;
-		wake_up(&km_waitq);
+		wake_up(&net->xfrm.km_waitq);
 	}
 	spin_unlock_bh(&x->lock);
 	xfrm_state_put(x);
@@ -1476,18 +1487,19 @@
 	hdr->sadb_msg_seq = c->seq;
 	hdr->sadb_msg_pid = c->pid;
 
-	pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+	pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xs_net(x));
 
 	return 0;
 }
 
 static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
+	struct net *net = sock_net(sk);
 	struct xfrm_state *x;
 	int err;
 	struct km_event c;
 
-	x = pfkey_msg2xfrm_state(hdr, ext_hdrs);
+	x = pfkey_msg2xfrm_state(net, hdr, ext_hdrs);
 	if (IS_ERR(x))
 		return PTR_ERR(x);
 
@@ -1521,6 +1533,7 @@
 
 static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
+	struct net *net = sock_net(sk);
 	struct xfrm_state *x;
 	struct km_event c;
 	int err;
@@ -1530,7 +1543,7 @@
 				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
 		return -EINVAL;
 
-	x = pfkey_xfrm_state_lookup(hdr, ext_hdrs);
+	x = pfkey_xfrm_state_lookup(net, hdr, ext_hdrs);
 	if (x == NULL)
 		return -ESRCH;
 
@@ -1562,6 +1575,7 @@
 
 static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
+	struct net *net = sock_net(sk);
 	__u8 proto;
 	struct sk_buff *out_skb;
 	struct sadb_msg *out_hdr;
@@ -1572,7 +1586,7 @@
 				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
 		return -EINVAL;
 
-	x = pfkey_xfrm_state_lookup(hdr, ext_hdrs);
+	x = pfkey_xfrm_state_lookup(net, hdr, ext_hdrs);
 	if (x == NULL)
 		return -ESRCH;
 
@@ -1590,7 +1604,7 @@
 	out_hdr->sadb_msg_reserved = 0;
 	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
 	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
-	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk);
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk));
 
 	return 0;
 }
@@ -1691,7 +1705,7 @@
 		return -ENOBUFS;
 	}
 
-	pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk);
+	pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk, sock_net(sk));
 
 	return 0;
 }
@@ -1713,13 +1727,14 @@
 	hdr->sadb_msg_errno = (uint8_t) 0;
 	hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
 
-	pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+	pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
 
 	return 0;
 }
 
 static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
+	struct net *net = sock_net(sk);
 	unsigned proto;
 	struct km_event c;
 	struct xfrm_audit audit_info;
@@ -1732,13 +1747,14 @@
 	audit_info.loginuid = audit_get_loginuid(current);
 	audit_info.sessionid = audit_get_sessionid(current);
 	audit_info.secid = 0;
-	err = xfrm_state_flush(proto, &audit_info);
+	err = xfrm_state_flush(net, proto, &audit_info);
 	if (err)
 		return err;
 	c.data.proto = proto;
 	c.seq = hdr->sadb_msg_seq;
 	c.pid = hdr->sadb_msg_pid;
 	c.event = XFRM_MSG_FLUSHSA;
+	c.net = net;
 	km_state_notify(NULL, &c);
 
 	return 0;
@@ -1768,7 +1784,7 @@
 
 	if (pfk->dump.skb)
 		pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
-				&pfk->sk);
+				&pfk->sk, sock_net(&pfk->sk));
 	pfk->dump.skb = out_skb;
 
 	return 0;
@@ -1776,7 +1792,8 @@
 
 static int pfkey_dump_sa(struct pfkey_sock *pfk)
 {
-	return xfrm_state_walk(&pfk->dump.u.state, dump_sa, (void *) pfk);
+	struct net *net = sock_net(&pfk->sk);
+	return xfrm_state_walk(net, &pfk->dump.u.state, dump_sa, (void *) pfk);
 }
 
 static void pfkey_dump_sa_done(struct pfkey_sock *pfk)
@@ -1817,7 +1834,7 @@
 			return -EINVAL;
 		pfk->promisc = satype;
 	}
-	pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, BROADCAST_ALL, NULL);
+	pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, BROADCAST_ALL, NULL, sock_net(sk));
 	return 0;
 }
 
@@ -1833,7 +1850,7 @@
 	return 0;
 }
 
-static u32 gen_reqid(void)
+static u32 gen_reqid(struct net *net)
 {
 	struct xfrm_policy_walk walk;
 	u32 start;
@@ -1846,7 +1863,7 @@
 		if (reqid == 0)
 			reqid = IPSEC_MANUAL_REQID_MAX+1;
 		xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
-		rc = xfrm_policy_walk(&walk, check_reqid, (void*)&reqid);
+		rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid);
 		xfrm_policy_walk_done(&walk);
 		if (rc != -EEXIST)
 			return reqid;
@@ -1857,6 +1874,7 @@
 static int
 parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
 {
+	struct net *net = xp_net(xp);
 	struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr;
 	int mode;
 
@@ -1876,7 +1894,7 @@
 		t->reqid = rq->sadb_x_ipsecrequest_reqid;
 		if (t->reqid > IPSEC_MANUAL_REQID_MAX)
 			t->reqid = 0;
-		if (!t->reqid && !(t->reqid = gen_reqid()))
+		if (!t->reqid && !(t->reqid = gen_reqid(net)))
 			return -ENOBUFS;
 	}
 
@@ -2147,7 +2165,7 @@
 	out_hdr->sadb_msg_errno = 0;
 	out_hdr->sadb_msg_seq = c->seq;
 	out_hdr->sadb_msg_pid = c->pid;
-	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xp_net(xp));
 out:
 	return 0;
 
@@ -2155,6 +2173,7 @@
 
 static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
+	struct net *net = sock_net(sk);
 	int err = 0;
 	struct sadb_lifetime *lifetime;
 	struct sadb_address *sa;
@@ -2174,7 +2193,7 @@
 	if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX)
 		return -EINVAL;
 
-	xp = xfrm_policy_alloc(GFP_KERNEL);
+	xp = xfrm_policy_alloc(net, GFP_KERNEL);
 	if (xp == NULL)
 		return -ENOBUFS;
 
@@ -2275,6 +2294,7 @@
 
 static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
+	struct net *net = sock_net(sk);
 	int err;
 	struct sadb_address *sa;
 	struct sadb_x_policy *pol;
@@ -2324,7 +2344,7 @@
 			return err;
 	}
 
-	xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN,
+	xp = xfrm_policy_bysel_ctx(net, XFRM_POLICY_TYPE_MAIN,
 				   pol->sadb_x_policy_dir - 1, &sel, pol_ctx,
 				   1, &err);
 	security_xfrm_policy_free(pol_ctx);
@@ -2372,7 +2392,7 @@
 	out_hdr->sadb_msg_errno = 0;
 	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
 	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
-	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk);
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, xp_net(xp));
 	err = 0;
 
 out:
@@ -2557,6 +2577,7 @@
 
 static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
+	struct net *net = sock_net(sk);
 	unsigned int dir;
 	int err = 0, delete;
 	struct sadb_x_policy *pol;
@@ -2571,8 +2592,8 @@
 		return -EINVAL;
 
 	delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2);
-	xp = xfrm_policy_byid(XFRM_POLICY_TYPE_MAIN, dir, pol->sadb_x_policy_id,
-			      delete, &err);
+	xp = xfrm_policy_byid(net, XFRM_POLICY_TYPE_MAIN, dir,
+			      pol->sadb_x_policy_id, delete, &err);
 	if (xp == NULL)
 		return -ENOENT;
 
@@ -2625,7 +2646,7 @@
 
 	if (pfk->dump.skb)
 		pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
-				&pfk->sk);
+				&pfk->sk, sock_net(&pfk->sk));
 	pfk->dump.skb = out_skb;
 
 	return 0;
@@ -2633,7 +2654,8 @@
 
 static int pfkey_dump_sp(struct pfkey_sock *pfk)
 {
-	return xfrm_policy_walk(&pfk->dump.u.policy, dump_sp, (void *) pfk);
+	struct net *net = sock_net(&pfk->sk);
+	return xfrm_policy_walk(net, &pfk->dump.u.policy, dump_sp, (void *) pfk);
 }
 
 static void pfkey_dump_sp_done(struct pfkey_sock *pfk)
@@ -2672,13 +2694,14 @@
 	hdr->sadb_msg_version = PF_KEY_V2;
 	hdr->sadb_msg_errno = (uint8_t) 0;
 	hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
-	pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL);
+	pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
 	return 0;
 
 }
 
 static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
+	struct net *net = sock_net(sk);
 	struct km_event c;
 	struct xfrm_audit audit_info;
 	int err;
@@ -2686,13 +2709,14 @@
 	audit_info.loginuid = audit_get_loginuid(current);
 	audit_info.sessionid = audit_get_sessionid(current);
 	audit_info.secid = 0;
-	err = xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info);
+	err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info);
 	if (err)
 		return err;
 	c.data.type = XFRM_POLICY_TYPE_MAIN;
 	c.event = XFRM_MSG_FLUSHPOLICY;
 	c.pid = hdr->sadb_msg_pid;
 	c.seq = hdr->sadb_msg_seq;
+	c.net = net;
 	km_policy_notify(NULL, 0, &c);
 
 	return 0;
@@ -2732,7 +2756,7 @@
 	int err;
 
 	pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
-			BROADCAST_PROMISC_ONLY, NULL);
+			BROADCAST_PROMISC_ONLY, NULL, sock_net(sk));
 
 	memset(ext_hdrs, 0, sizeof(ext_hdrs));
 	err = parse_exthdrs(skb, hdr, ext_hdrs);
@@ -2935,13 +2959,16 @@
 	out_hdr->sadb_msg_seq = 0;
 	out_hdr->sadb_msg_pid = 0;
 
-	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x));
 	return 0;
 }
 
 static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)
 {
-	if (atomic_read(&pfkey_socks_nr) == 0)
+	struct net *net = x ? xs_net(x) : c->net;
+	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
+
+	if (atomic_read(&net_pfkey->socks_nr) == 0)
 		return 0;
 
 	switch (c->event) {
@@ -3103,12 +3130,13 @@
 		       xfrm_ctx->ctx_len);
 	}
 
-	return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
+	return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x));
 }
 
 static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
 						u8 *data, int len, int *dir)
 {
+	struct net *net = sock_net(sk);
 	struct xfrm_policy *xp;
 	struct sadb_x_policy *pol = (struct sadb_x_policy*)data;
 	struct sadb_x_sec_ctx *sec_ctx;
@@ -3141,7 +3169,7 @@
 	    (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOUND))
 		return NULL;
 
-	xp = xfrm_policy_alloc(GFP_ATOMIC);
+	xp = xfrm_policy_alloc(net, GFP_ATOMIC);
 	if (xp == NULL) {
 		*dir = -ENOBUFS;
 		return NULL;
@@ -3300,7 +3328,7 @@
 	n_port->sadb_x_nat_t_port_port = sport;
 	n_port->sadb_x_nat_t_port_reserved = 0;
 
-	return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
+	return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x));
 }
 
 #ifdef CONFIG_NET_KEY_MIGRATE
@@ -3491,7 +3519,7 @@
 	}
 
 	/* broadcast migrate message to sockets */
-	pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+	pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, &init_net);
 
 	return 0;
 
@@ -3645,6 +3673,8 @@
 
 static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos)
 {
+	struct net *net = seq_file_net(f);
+	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
 	struct sock *s;
 	struct hlist_node *node;
 	loff_t pos = *ppos;
@@ -3653,7 +3683,7 @@
 	if (pos == 0)
 		return SEQ_START_TOKEN;
 
-	sk_for_each(s, node, &pfkey_table)
+	sk_for_each(s, node, &net_pfkey->table)
 		if (pos-- == 1)
 			return s;
 
@@ -3662,9 +3692,12 @@
 
 static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos)
 {
+	struct net *net = seq_file_net(f);
+	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
+
 	++*ppos;
 	return (v == SEQ_START_TOKEN) ?
-		sk_head(&pfkey_table) :
+		sk_head(&net_pfkey->table) :
 			sk_next((struct sock *)v);
 }
 
@@ -3682,38 +3715,39 @@
 
 static int pfkey_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open(file, &pfkey_seq_ops);
+	return seq_open_net(inode, file, &pfkey_seq_ops,
+			    sizeof(struct seq_net_private));
 }
 
 static struct file_operations pfkey_proc_ops = {
 	.open	 = pfkey_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
-	.release = seq_release,
+	.release = seq_release_net,
 };
 
-static int pfkey_init_proc(void)
+static int __net_init pfkey_init_proc(struct net *net)
 {
 	struct proc_dir_entry *e;
 
-	e = proc_net_fops_create(&init_net, "pfkey", 0, &pfkey_proc_ops);
+	e = proc_net_fops_create(net, "pfkey", 0, &pfkey_proc_ops);
 	if (e == NULL)
 		return -ENOMEM;
 
 	return 0;
 }
 
-static void pfkey_exit_proc(void)
+static void pfkey_exit_proc(struct net *net)
 {
-	proc_net_remove(&init_net, "pfkey");
+	proc_net_remove(net, "pfkey");
 }
 #else
-static inline int pfkey_init_proc(void)
+static int __net_init pfkey_init_proc(struct net *net)
 {
 	return 0;
 }
 
-static inline void pfkey_exit_proc(void)
+static void pfkey_exit_proc(struct net *net)
 {
 }
 #endif
@@ -3729,10 +3763,51 @@
 	.migrate	= pfkey_send_migrate,
 };
 
+static int __net_init pfkey_net_init(struct net *net)
+{
+	struct netns_pfkey *net_pfkey;
+	int rv;
+
+	net_pfkey = kmalloc(sizeof(struct netns_pfkey), GFP_KERNEL);
+	if (!net_pfkey) {
+		rv = -ENOMEM;
+		goto out_kmalloc;
+	}
+	INIT_HLIST_HEAD(&net_pfkey->table);
+	atomic_set(&net_pfkey->socks_nr, 0);
+	rv = net_assign_generic(net, pfkey_net_id, net_pfkey);
+	if (rv < 0)
+		goto out_assign;
+	rv = pfkey_init_proc(net);
+	if (rv < 0)
+		goto out_proc;
+	return 0;
+
+out_proc:
+out_assign:
+	kfree(net_pfkey);
+out_kmalloc:
+	return rv;
+}
+
+static void __net_exit pfkey_net_exit(struct net *net)
+{
+	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
+
+	pfkey_exit_proc(net);
+	BUG_ON(!hlist_empty(&net_pfkey->table));
+	kfree(net_pfkey);
+}
+
+static struct pernet_operations pfkey_net_ops = {
+	.init = pfkey_net_init,
+	.exit = pfkey_net_exit,
+};
+
 static void __exit ipsec_pfkey_exit(void)
 {
+	unregister_pernet_gen_subsys(pfkey_net_id, &pfkey_net_ops);
 	xfrm_unregister_km(&pfkeyv2_mgr);
-	pfkey_exit_proc();
 	sock_unregister(PF_KEY);
 	proto_unregister(&key_proto);
 }
@@ -3747,16 +3822,16 @@
 	err = sock_register(&pfkey_family_ops);
 	if (err != 0)
 		goto out_unregister_key_proto;
-	err = pfkey_init_proc();
-	if (err != 0)
-		goto out_sock_unregister;
 	err = xfrm_register_km(&pfkeyv2_mgr);
 	if (err != 0)
-		goto out_remove_proc_entry;
+		goto out_sock_unregister;
+	err = register_pernet_gen_subsys(&pfkey_net_id, &pfkey_net_ops);
+	if (err != 0)
+		goto out_xfrm_unregister_km;
 out:
 	return err;
-out_remove_proc_entry:
-	pfkey_exit_proc();
+out_xfrm_unregister_km:
+	xfrm_unregister_km(&pfkeyv2_mgr);
 out_sock_unregister:
 	sock_unregister(PF_KEY);
 out_unregister_key_proto:
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 5bcc452..56fd85a 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -103,7 +103,6 @@
  *	llc_ui_send_data - send data via reliable llc2 connection
  *	@sk: Connection the socket is using.
  *	@skb: Data the user wishes to send.
- *	@addr: Source and destination fields provided by the user.
  *	@noblock: can we block waiting for data?
  *
  *	Send data via reliable llc2 connection.
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
index 48212c0..b58bd7c 100644
--- a/net/llc/llc_proc.c
+++ b/net/llc/llc_proc.c
@@ -27,8 +27,7 @@
 
 static void llc_ui_format_mac(struct seq_file *seq, u8 *addr)
 {
-	DECLARE_MAC_BUF(mac);
-	seq_printf(seq, "%s", print_mac(mac, addr));
+	seq_printf(seq, "%pM", addr);
 }
 
 static struct sock *llc_get_sk_idx(loff_t pos)
diff --git a/net/llc/sysctl_net_llc.c b/net/llc/sysctl_net_llc.c
index 5bef1dc..57b9304 100644
--- a/net/llc/sysctl_net_llc.c
+++ b/net/llc/sysctl_net_llc.c
@@ -20,8 +20,8 @@
 		.data		= &sysctl_llc2_ack_timeout,
 		.maxlen		= sizeof(long),
 		.mode		= 0644,
-		.proc_handler   = &proc_dointvec_jiffies,
-		.strategy       = &sysctl_jiffies,
+		.proc_handler   = proc_dointvec_jiffies,
+		.strategy       = sysctl_jiffies,
 	},
 	{
 		.ctl_name	= NET_LLC2_BUSY_TIMEOUT,
@@ -29,8 +29,8 @@
 		.data		= &sysctl_llc2_busy_timeout,
 		.maxlen		= sizeof(long),
 		.mode		= 0644,
-		.proc_handler   = &proc_dointvec_jiffies,
-		.strategy       = &sysctl_jiffies,
+		.proc_handler   = proc_dointvec_jiffies,
+		.strategy       = sysctl_jiffies,
 	},
 	{
 		.ctl_name	= NET_LLC2_P_TIMEOUT,
@@ -38,8 +38,8 @@
 		.data		= &sysctl_llc2_p_timeout,
 		.maxlen		= sizeof(long),
 		.mode		= 0644,
-		.proc_handler   = &proc_dointvec_jiffies,
-		.strategy       = &sysctl_jiffies,
+		.proc_handler   = proc_dointvec_jiffies,
+		.strategy       = sysctl_jiffies,
 	},
 	{
 		.ctl_name	= NET_LLC2_REJ_TIMEOUT,
@@ -47,8 +47,8 @@
 		.data		= &sysctl_llc2_rej_timeout,
 		.maxlen		= sizeof(long),
 		.mode		= 0644,
-		.proc_handler   = &proc_dointvec_jiffies,
-		.strategy       = &sysctl_jiffies,
+		.proc_handler   = proc_dointvec_jiffies,
+		.strategy       = sysctl_jiffies,
 	},
 	{ 0 },
 };
@@ -60,8 +60,8 @@
 		.data		= &sysctl_llc_station_ack_timeout,
 		.maxlen		= sizeof(long),
 		.mode		= 0644,
-		.proc_handler   = &proc_dointvec_jiffies,
-		.strategy       = &sysctl_jiffies,
+		.proc_handler   = proc_dointvec_jiffies,
+		.strategy       = sysctl_jiffies,
 	},
 	{ 0 },
 };
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 7f710a2..60c1616 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -16,20 +16,20 @@
 
 config MAC80211_RC_PID
 	bool "PID controller based rate control algorithm" if EMBEDDED
-	default y
 	---help---
 	  This option enables a TX rate control algorithm for
 	  mac80211 that uses a PID controller to select the TX
 	  rate.
 
 config MAC80211_RC_MINSTREL
-	bool "Minstrel"
+	bool "Minstrel" if EMBEDDED
+	default y
 	---help---
 	  This option enables the 'minstrel' TX rate control algorithm
 
 choice
 	prompt "Default rate control algorithm"
-	default MAC80211_RC_DEFAULT_PID
+	default MAC80211_RC_DEFAULT_MINSTREL
 	---help---
 	  This option selects the default rate control algorithm
 	  mac80211 will use. Note that this default can still be
@@ -55,8 +55,8 @@
 
 config MAC80211_RC_DEFAULT
 	string
-	default "pid" if MAC80211_RC_DEFAULT_PID
 	default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL
+	default "pid" if MAC80211_RC_DEFAULT_PID
 	default ""
 
 endmenu
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 31cfd1f..7d4971a 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -46,3 +46,5 @@
 
 mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y)
 mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 855126a..9d4e4d8 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -17,13 +17,6 @@
 #include "rate.h"
 #include "mesh.h"
 
-struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy)
-{
-	struct ieee80211_local *local = wiphy_priv(wiphy);
-	return &local->hw;
-}
-EXPORT_SYMBOL(wiphy_to_hw);
-
 static bool nl80211_type_check(enum nl80211_iftype type)
 {
 	switch (type) {
@@ -33,6 +26,8 @@
 #ifdef CONFIG_MAC80211_MESH
 	case NL80211_IFTYPE_MESH_POINT:
 #endif
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_AP_VLAN:
 	case NL80211_IFTYPE_WDS:
 		return true;
 	default:
@@ -315,12 +310,35 @@
 
 	sinfo->filled = STATION_INFO_INACTIVE_TIME |
 			STATION_INFO_RX_BYTES |
-			STATION_INFO_TX_BYTES;
+			STATION_INFO_TX_BYTES |
+			STATION_INFO_TX_BITRATE;
 
 	sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
 	sinfo->rx_bytes = sta->rx_bytes;
 	sinfo->tx_bytes = sta->tx_bytes;
 
+	if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
+		sinfo->filled |= STATION_INFO_SIGNAL;
+		sinfo->signal = (s8)sta->last_signal;
+	}
+
+	sinfo->txrate.flags = 0;
+	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
+		sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+		sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI)
+		sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+	if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) {
+		struct ieee80211_supported_band *sband;
+		sband = sta->local->hw.wiphy->bands[
+				sta->local->hw.conf.channel->band];
+		sinfo->txrate.legacy =
+			sband->bitrates[sta->last_tx_rate.idx].bitrate;
+	} else
+		sinfo->txrate.mcs = sta->last_tx_rate.idx;
+
 	if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
 		sinfo->filled |= STATION_INFO_LLID |
@@ -401,8 +419,10 @@
 	 */
 	if (params->interval) {
 		sdata->local->hw.conf.beacon_int = params->interval;
-		if (ieee80211_hw_config(sdata->local))
-			return -EINVAL;
+		err = ieee80211_hw_config(sdata->local,
+					IEEE80211_CONF_CHANGE_BEACON_INTERVAL);
+		if (err < 0)
+			return err;
 		/*
 		 * We updated some parameter so if below bails out
 		 * it's not an error.
@@ -589,6 +609,8 @@
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
 
+	sband = local->hw.wiphy->bands[local->oper_channel->band];
+
 	/*
 	 * FIXME: updating the flags is racy when this function is
 	 *	  called from ieee80211_change_station(), this will
@@ -629,7 +651,6 @@
 
 	if (params->supported_rates) {
 		rates = 0;
-		sband = local->hw.wiphy->bands[local->oper_channel->band];
 
 		for (i = 0; i < params->supported_rates_len; i++) {
 			int rate = (params->supported_rates[i] & 0x7f) * 5;
@@ -641,10 +662,10 @@
 		sta->sta.supp_rates[local->oper_channel->band] = rates;
 	}
 
-	if (params->ht_capa) {
-		ieee80211_ht_cap_ie_to_ht_info(params->ht_capa,
-					       &sta->sta.ht_info);
-	}
+	if (params->ht_capa)
+		ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
+						  params->ht_capa,
+						  &sta->sta.ht_cap);
 
 	if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
 		switch (params->plink_action) {
@@ -665,6 +686,7 @@
 	struct sta_info *sta;
 	struct ieee80211_sub_if_data *sdata;
 	int err;
+	int layer2_update;
 
 	/* Prevent a race with changing the rate control algorithm */
 	if (!netif_running(dev))
@@ -695,17 +717,25 @@
 
 	rate_control_rate_init(sta);
 
+	layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+		sdata->vif.type == NL80211_IFTYPE_AP;
+
 	rcu_read_lock();
 
 	err = sta_info_insert(sta);
 	if (err) {
 		/* STA has been freed */
+		if (err == -EEXIST && layer2_update) {
+			/* Need to update layer 2 devices on reassociation */
+			sta = sta_info_get(local, mac);
+			if (sta)
+				ieee80211_send_layer2_update(sta);
+		}
 		rcu_read_unlock();
 		return err;
 	}
 
-	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
-	    sdata->vif.type == NL80211_IFTYPE_AP)
+	if (layer2_update)
 		ieee80211_send_layer2_update(sta);
 
 	rcu_read_unlock();
@@ -957,6 +987,72 @@
 	rcu_read_unlock();
 	return 0;
 }
+
+static int ieee80211_get_mesh_params(struct wiphy *wiphy,
+				struct net_device *dev,
+				struct mesh_config *conf)
+{
+	struct ieee80211_sub_if_data *sdata;
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+		return -ENOTSUPP;
+	memcpy(conf, &(sdata->u.mesh.mshcfg), sizeof(struct mesh_config));
+	return 0;
+}
+
+static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask)
+{
+	return (mask >> (parm-1)) & 0x1;
+}
+
+static int ieee80211_set_mesh_params(struct wiphy *wiphy,
+				struct net_device *dev,
+				const struct mesh_config *nconf, u32 mask)
+{
+	struct mesh_config *conf;
+	struct ieee80211_sub_if_data *sdata;
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+		return -ENOTSUPP;
+
+	/* Set the config options which we are interested in setting */
+	conf = &(sdata->u.mesh.mshcfg);
+	if (_chg_mesh_attr(NL80211_MESHCONF_RETRY_TIMEOUT, mask))
+		conf->dot11MeshRetryTimeout = nconf->dot11MeshRetryTimeout;
+	if (_chg_mesh_attr(NL80211_MESHCONF_CONFIRM_TIMEOUT, mask))
+		conf->dot11MeshConfirmTimeout = nconf->dot11MeshConfirmTimeout;
+	if (_chg_mesh_attr(NL80211_MESHCONF_HOLDING_TIMEOUT, mask))
+		conf->dot11MeshHoldingTimeout = nconf->dot11MeshHoldingTimeout;
+	if (_chg_mesh_attr(NL80211_MESHCONF_MAX_PEER_LINKS, mask))
+		conf->dot11MeshMaxPeerLinks = nconf->dot11MeshMaxPeerLinks;
+	if (_chg_mesh_attr(NL80211_MESHCONF_MAX_RETRIES, mask))
+		conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries;
+	if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask))
+		conf->dot11MeshTTL = nconf->dot11MeshTTL;
+	if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))
+		conf->auto_open_plinks = nconf->auto_open_plinks;
+	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask))
+		conf->dot11MeshHWMPmaxPREQretries =
+			nconf->dot11MeshHWMPmaxPREQretries;
+	if (_chg_mesh_attr(NL80211_MESHCONF_PATH_REFRESH_TIME, mask))
+		conf->path_refresh_time = nconf->path_refresh_time;
+	if (_chg_mesh_attr(NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, mask))
+		conf->min_discovery_timeout = nconf->min_discovery_timeout;
+	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, mask))
+		conf->dot11MeshHWMPactivePathTimeout =
+			nconf->dot11MeshHWMPactivePathTimeout;
+	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, mask))
+		conf->dot11MeshHWMPpreqMinInterval =
+			nconf->dot11MeshHWMPpreqMinInterval;
+	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+			   mask))
+		conf->dot11MeshHWMPnetDiameterTraversalTime =
+			nconf->dot11MeshHWMPnetDiameterTraversalTime;
+	return 0;
+}
+
 #endif
 
 static int ieee80211_change_bss(struct wiphy *wiphy,
@@ -972,25 +1068,79 @@
 		return -EINVAL;
 
 	if (params->use_cts_prot >= 0) {
-		sdata->bss_conf.use_cts_prot = params->use_cts_prot;
+		sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
 		changed |= BSS_CHANGED_ERP_CTS_PROT;
 	}
 	if (params->use_short_preamble >= 0) {
-		sdata->bss_conf.use_short_preamble =
+		sdata->vif.bss_conf.use_short_preamble =
 			params->use_short_preamble;
 		changed |= BSS_CHANGED_ERP_PREAMBLE;
 	}
 	if (params->use_short_slot_time >= 0) {
-		sdata->bss_conf.use_short_slot =
+		sdata->vif.bss_conf.use_short_slot =
 			params->use_short_slot_time;
 		changed |= BSS_CHANGED_ERP_SLOT;
 	}
 
+	if (params->basic_rates) {
+		int i, j;
+		u32 rates = 0;
+		struct ieee80211_local *local = wiphy_priv(wiphy);
+		struct ieee80211_supported_band *sband =
+			wiphy->bands[local->oper_channel->band];
+
+		for (i = 0; i < params->basic_rates_len; i++) {
+			int rate = (params->basic_rates[i] & 0x7f) * 5;
+			for (j = 0; j < sband->n_bitrates; j++) {
+				if (sband->bitrates[j].bitrate == rate)
+					rates |= BIT(j);
+			}
+		}
+		sdata->vif.bss_conf.basic_rates = rates;
+		changed |= BSS_CHANGED_BASIC_RATES;
+	}
+
 	ieee80211_bss_info_change_notify(sdata, changed);
 
 	return 0;
 }
 
+static int ieee80211_set_txq_params(struct wiphy *wiphy,
+				    struct ieee80211_txq_params *params)
+{
+	struct ieee80211_local *local = wiphy_priv(wiphy);
+	struct ieee80211_tx_queue_params p;
+
+	if (!local->ops->conf_tx)
+		return -EOPNOTSUPP;
+
+	memset(&p, 0, sizeof(p));
+	p.aifs = params->aifs;
+	p.cw_max = params->cwmax;
+	p.cw_min = params->cwmin;
+	p.txop = params->txop;
+	if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) {
+		printk(KERN_DEBUG "%s: failed to set TX queue "
+		       "parameters for queue %d\n", local->mdev->name,
+		       params->queue);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ieee80211_set_channel(struct wiphy *wiphy,
+				 struct ieee80211_channel *chan,
+				 enum nl80211_channel_type channel_type)
+{
+	struct ieee80211_local *local = wiphy_priv(wiphy);
+
+	local->oper_channel = chan;
+	local->oper_channel_type = channel_type;
+
+	return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+}
+
 struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
@@ -1013,6 +1163,10 @@
 	.change_mpath = ieee80211_change_mpath,
 	.get_mpath = ieee80211_get_mpath,
 	.dump_mpath = ieee80211_dump_mpath,
+	.set_mesh_params = ieee80211_set_mesh_params,
+	.get_mesh_params = ieee80211_get_mesh_params,
 #endif
 	.change_bss = ieee80211_change_bss,
+	.set_txq_params = ieee80211_set_txq_params,
+	.set_channel = ieee80211_set_channel,
 };
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 24ce544..2697a2f 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -47,18 +47,14 @@
 
 DEBUGFS_READONLY_FILE(frequency, 20, "%d",
 		      local->hw.conf.channel->center_freq);
-DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d",
-		      local->hw.conf.antenna_sel_tx);
-DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
-		      local->hw.conf.antenna_sel_rx);
 DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
 		      local->rts_threshold);
 DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
 		      local->fragmentation_threshold);
 DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
-		      local->short_retry_limit);
+		      local->hw.conf.short_frame_max_tx_count);
 DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
-		      local->long_retry_limit);
+		      local->hw.conf.long_frame_max_tx_count);
 DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
 		      local->total_ps_buffered);
 DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x",
@@ -202,8 +198,6 @@
 	local->debugfs.keys = debugfs_create_dir("keys", phyd);
 
 	DEBUGFS_ADD(frequency);
-	DEBUGFS_ADD(antenna_sel_tx);
-	DEBUGFS_ADD(antenna_sel_rx);
 	DEBUGFS_ADD(rts_threshold);
 	DEBUGFS_ADD(fragmentation_threshold);
 	DEBUGFS_ADD(short_retry_limit);
@@ -258,8 +252,6 @@
 void debugfs_hw_del(struct ieee80211_local *local)
 {
 	DEBUGFS_DEL(frequency);
-	DEBUGFS_DEL(antenna_sel_tx);
-	DEBUGFS_DEL(antenna_sel_rx);
 	DEBUGFS_DEL(rts_threshold);
 	DEBUGFS_DEL(fragmentation_threshold);
 	DEBUGFS_DEL(short_retry_limit);
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index a3294d1..6424ac5 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -188,7 +188,6 @@
   {
 	static int keycount;
 	char buf[50];
-	DECLARE_MAC_BUF(mac);
 	struct sta_info *sta;
 
 	if (!key->local->debugfs.keys)
@@ -206,8 +205,7 @@
 	rcu_read_lock();
 	sta = rcu_dereference(key->sta);
 	if (sta)
-		sprintf(buf, "../../stations/%s",
-			print_mac(mac, sta->sta.addr));
+		sprintf(buf, "../../stations/%pM", sta->sta.addr);
 	rcu_read_unlock();
 
 	/* using sta as a boolean is fine outside RCU lock */
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 2ad504f..c542193 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -41,29 +41,6 @@
 	return ret;
 }
 
-#ifdef CONFIG_MAC80211_MESH
-static ssize_t ieee80211_if_write(
-	struct ieee80211_sub_if_data *sdata,
-	char const __user *userbuf,
-	size_t count, loff_t *ppos,
-	int (*format)(struct ieee80211_sub_if_data *, char *))
-{
-	char buf[10];
-	int buf_size;
-
-	memset(buf, 0x00, sizeof(buf));
-	buf_size = min(count, (sizeof(buf)-1));
-	if (copy_from_user(buf, userbuf, buf_size))
-		return count;
-	read_lock(&dev_base_lock);
-	if (sdata->dev->reg_state == NETREG_REGISTERED)
-		(*format)(sdata, buf);
-	read_unlock(&dev_base_lock);
-
-	return count;
-}
-#endif
-
 #define IEEE80211_IF_FMT(name, field, format_string)			\
 static ssize_t ieee80211_if_fmt_##name(					\
 	const struct ieee80211_sub_if_data *sdata, char *buf,		\
@@ -71,19 +48,6 @@
 {									\
 	return scnprintf(buf, buflen, format_string, sdata->field);	\
 }
-#define IEEE80211_IF_WFMT(name, field, type)				\
-static int ieee80211_if_wfmt_##name(					\
-	struct ieee80211_sub_if_data *sdata, char *buf)			\
-{									\
-	unsigned long tmp;						\
-	char *endp;							\
-									\
-	tmp = simple_strtoul(buf, &endp, 0);				\
-	if ((endp == buf) || ((type)tmp != tmp))			\
-		return -EINVAL;						\
-	sdata->field = tmp;						\
-	return 0;							\
-}
 #define IEEE80211_IF_FMT_DEC(name, field)				\
 		IEEE80211_IF_FMT(name, field, "%d\n")
 #define IEEE80211_IF_FMT_HEX(name, field)				\
@@ -104,8 +68,7 @@
 	const struct ieee80211_sub_if_data *sdata, char *buf,		\
 	int buflen)							\
 {									\
-	DECLARE_MAC_BUF(mac);						\
-	return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\
+	return scnprintf(buf, buflen, "%pM\n", sdata->field);		\
 }
 
 #define __IEEE80211_IF_FILE(name)					\
@@ -126,34 +89,6 @@
 		IEEE80211_IF_FMT_##format(name, field)			\
 		__IEEE80211_IF_FILE(name)
 
-#define __IEEE80211_IF_WFILE(name)					\
-static ssize_t ieee80211_if_read_##name(struct file *file,		\
-					char __user *userbuf,		\
-					size_t count, loff_t *ppos)	\
-{									\
-	return ieee80211_if_read(file->private_data,			\
-				 userbuf, count, ppos,			\
-				 ieee80211_if_fmt_##name);		\
-}									\
-static ssize_t ieee80211_if_write_##name(struct file *file,		\
-					const char __user *userbuf,	\
-					size_t count, loff_t *ppos)	\
-{									\
-	return ieee80211_if_write(file->private_data,			\
-				 userbuf, count, ppos,			\
-				 ieee80211_if_wfmt_##name);		\
-}									\
-static const struct file_operations name##_ops = {			\
-	.read = ieee80211_if_read_##name,				\
-	.write = ieee80211_if_write_##name,				\
-	.open = mac80211_open_file_generic,				\
-}
-
-#define IEEE80211_IF_WFILE(name, field, format, type)			\
-		IEEE80211_IF_FMT_##format(name, field)			\
-		IEEE80211_IF_WFMT(name, field, type)			\
-		__IEEE80211_IF_WFILE(name)
-
 /* common attributes */
 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
 IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
@@ -184,7 +119,7 @@
 		 sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
 		 sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
 		 sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
-		 sdata->bss_conf.use_cts_prot ? "CTS prot\n" : "");
+		 sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : "");
 }
 __IEEE80211_IF_FILE(flags);
 
@@ -212,30 +147,30 @@
 IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
 
 /* Mesh parameters */
-IEEE80211_IF_WFILE(dot11MeshMaxRetries,
-		u.mesh.mshcfg.dot11MeshMaxRetries, DEC, u8);
-IEEE80211_IF_WFILE(dot11MeshRetryTimeout,
-		u.mesh.mshcfg.dot11MeshRetryTimeout, DEC, u16);
-IEEE80211_IF_WFILE(dot11MeshConfirmTimeout,
-		u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC, u16);
-IEEE80211_IF_WFILE(dot11MeshHoldingTimeout,
-		u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC, u16);
-IEEE80211_IF_WFILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC, u8);
-IEEE80211_IF_WFILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC, u8);
-IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks,
-		u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
-IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout,
-		u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32);
-IEEE80211_IF_WFILE(dot11MeshHWMPpreqMinInterval,
-		u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16);
-IEEE80211_IF_WFILE(dot11MeshHWMPnetDiameterTraversalTime,
-		u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16);
-IEEE80211_IF_WFILE(dot11MeshHWMPmaxPREQretries,
-		u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8);
-IEEE80211_IF_WFILE(path_refresh_time,
-		u.mesh.mshcfg.path_refresh_time, DEC, u32);
-IEEE80211_IF_WFILE(min_discovery_timeout,
-		u.mesh.mshcfg.min_discovery_timeout, DEC, u16);
+IEEE80211_IF_FILE(dot11MeshMaxRetries,
+		u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
+IEEE80211_IF_FILE(dot11MeshRetryTimeout,
+		u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
+IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
+		u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
+IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
+		u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
+IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
+IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
+IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
+		u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
+		u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
+		u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
+		u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
+		u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
+IEEE80211_IF_FILE(path_refresh_time,
+		u.mesh.mshcfg.path_refresh_time, DEC);
+IEEE80211_IF_FILE(min_discovery_timeout,
+		u.mesh.mshcfg.min_discovery_timeout, DEC);
 #endif
 
 
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index b85c4f2..a2fbe01 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -39,13 +39,6 @@
 	.open = mac80211_open_file_generic,				\
 }
 
-#define STA_OPS_WR(name)						\
-static const struct file_operations sta_ ##name## _ops = {		\
-	.read = sta_##name##_read,					\
-	.write = sta_##name##_write,					\
-	.open = mac80211_open_file_generic,				\
-}
-
 #define STA_FILE(name, field, format)					\
 		STA_READ_##format(name, field)				\
 		STA_OPS(name)
@@ -144,7 +137,7 @@
 	p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
 	for (i = 0; i < STA_TID_NUM; i++)
 		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
-			sta->ampdu_mlme.tid_state_rx[i]?
+			sta->ampdu_mlme.tid_state_rx[i] ?
 			sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
 
 	p += scnprintf(p, sizeof(buf)+buf-p, "\n TX  :");
@@ -155,84 +148,20 @@
 	p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
 	for (i = 0; i < STA_TID_NUM; i++)
 		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
-			sta->ampdu_mlme.tid_state_tx[i]?
+			sta->ampdu_mlme.tid_state_tx[i] ?
 			sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
 
 	p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :");
 	for (i = 0; i < STA_TID_NUM; i++)
 		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
-			sta->ampdu_mlme.tid_state_tx[i]?
+			sta->ampdu_mlme.tid_state_tx[i] ?
 			sta->ampdu_mlme.tid_tx[i]->ssn : 0);
 
 	p += scnprintf(p, sizeof(buf)+buf-p, "\n");
 
 	return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
 }
-
-static ssize_t sta_agg_status_write(struct file *file,
-		const char __user *user_buf, size_t count, loff_t *ppos)
-{
-	struct sta_info *sta = file->private_data;
-	struct ieee80211_local *local = sta->sdata->local;
-	struct ieee80211_hw *hw = &local->hw;
-	u8 *da = sta->sta.addr;
-	static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0,
-					0, 0, 0, 0, 0, 0, 0, 0};
-	static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1,
-					1, 1, 1, 1, 1, 1, 1, 1};
-	char *endp;
-	char buf[32];
-	int buf_size, rs;
-	unsigned int tid_num;
-	char state[4];
-
-	memset(buf, 0x00, sizeof(buf));
-	buf_size = min(count, (sizeof(buf)-1));
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-
-	tid_num = simple_strtoul(buf, &endp, 0);
-	if (endp == buf)
-		return -EINVAL;
-
-	if ((tid_num >= 100) && (tid_num <= 115)) {
-		/* toggle Rx aggregation command */
-		tid_num = tid_num - 100;
-		if (tid_static_rx[tid_num] == 1) {
-			strcpy(state, "off");
-			ieee80211_sta_stop_rx_ba_session(sta->sdata, da, tid_num, 0,
-					WLAN_REASON_QSTA_REQUIRE_SETUP);
-			sta->ampdu_mlme.tid_state_rx[tid_num] |=
-					HT_AGG_STATE_DEBUGFS_CTL;
-			tid_static_rx[tid_num] = 0;
-		} else {
-			strcpy(state, "on ");
-			sta->ampdu_mlme.tid_state_rx[tid_num] &=
-					~HT_AGG_STATE_DEBUGFS_CTL;
-			tid_static_rx[tid_num] = 1;
-		}
-		printk(KERN_DEBUG "debugfs - try switching tid %u %s\n",
-				tid_num, state);
-	} else if ((tid_num >= 0) && (tid_num <= 15)) {
-		/* toggle Tx aggregation command */
-		if (tid_static_tx[tid_num] == 0) {
-			strcpy(state, "on ");
-			rs =  ieee80211_start_tx_ba_session(hw, da, tid_num);
-			if (rs == 0)
-				tid_static_tx[tid_num] = 1;
-		} else {
-			strcpy(state, "off");
-			rs =  ieee80211_stop_tx_ba_session(hw, da, tid_num, 1);
-			if (rs == 0)
-				tid_static_tx[tid_num] = 0;
-		}
-		printk(KERN_DEBUG "debugfs - switching tid %u %s, return=%d\n",
-				tid_num, state, rs);
-	}
-
-	return count;
-}
-STA_OPS_WR(agg_status);
+STA_OPS(agg_status);
 
 #define DEBUGFS_ADD(name) \
 	sta->debugfs.name = debugfs_create_file(#name, 0400, \
@@ -246,15 +175,14 @@
 void ieee80211_sta_debugfs_add(struct sta_info *sta)
 {
 	struct dentry *stations_dir = sta->local->debugfs.stations;
-	DECLARE_MAC_BUF(mbuf);
-	u8 *mac;
+	u8 mac[3*ETH_ALEN];
 
 	sta->debugfs.add_has_run = true;
 
 	if (!stations_dir)
 		return;
 
-	mac = print_mac(mbuf, sta->sta.addr);
+	snprintf(mac, sizeof(mac), "%pM", sta->sta.addr);
 
 	/*
 	 * This might fail due to a race condition:
diff --git a/net/mac80211/event.c b/net/mac80211/event.c
index 8de60de..0d95561 100644
--- a/net/mac80211/event.c
+++ b/net/mac80211/event.c
@@ -21,14 +21,13 @@
 {
 	union iwreq_data wrqu;
 	char *buf = kmalloc(128, GFP_ATOMIC);
-	DECLARE_MAC_BUF(mac);
 
 	if (buf) {
 		/* TODO: needed parameters: count, key type, TSC */
 		sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
-			"keyid=%d %scast addr=%s)",
+			"keyid=%d %scast addr=%pM)",
 			keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
-			print_mac(mac, hdr->addr2));
+			hdr->addr2);
 		memset(&wrqu, 0, sizeof(wrqu));
 		wrqu.data.length = strlen(buf);
 		wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index dc7d9a3..5f510a1 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -20,50 +20,138 @@
 #include "sta_info.h"
 #include "wme.h"
 
-int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
-				   struct ieee80211_ht_info *ht_info)
+void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
+				       struct ieee80211_ht_cap *ht_cap_ie,
+				       struct ieee80211_sta_ht_cap *ht_cap)
 {
+	u8 ampdu_info, tx_mcs_set_cap;
+	int i, max_tx_streams;
 
-	if (ht_info == NULL)
-		return -EINVAL;
+	BUG_ON(!ht_cap);
 
-	memset(ht_info, 0, sizeof(*ht_info));
+	memset(ht_cap, 0, sizeof(*ht_cap));
 
-	if (ht_cap_ie) {
-		u8 ampdu_info = ht_cap_ie->ampdu_params_info;
+	if (!ht_cap_ie)
+		return;
 
-		ht_info->ht_supported = 1;
-		ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
-		ht_info->ampdu_factor =
-			ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
-		ht_info->ampdu_density =
-			(ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
-		memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
-	} else
-		ht_info->ht_supported = 0;
+	ht_cap->ht_supported = true;
 
-	return 0;
+	ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap;
+	ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS;
+	ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
+
+	ampdu_info = ht_cap_ie->ampdu_params_info;
+	ht_cap->ampdu_factor =
+		ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
+	ht_cap->ampdu_density =
+		(ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
+
+	/* own MCS TX capabilities */
+	tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
+
+	/* can we TX with MCS rates? */
+	if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
+		return;
+
+	/* Counting from 0, therefore +1 */
+	if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
+		max_tx_streams =
+			((tx_mcs_set_cap & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
+				>> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
+	else
+		max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS;
+
+	/*
+	 * 802.11n D5.0 20.3.5 / 20.6 says:
+	 * - indices 0 to 7 and 32 are single spatial stream
+	 * - 8 to 31 are multiple spatial streams using equal modulation
+	 *   [8..15 for two streams, 16..23 for three and 24..31 for four]
+	 * - remainder are multiple spatial streams using unequal modulation
+	 */
+	for (i = 0; i < max_tx_streams; i++)
+		ht_cap->mcs.rx_mask[i] =
+			sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
+
+	if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
+		for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
+		     i < IEEE80211_HT_MCS_MASK_LEN; i++)
+			ht_cap->mcs.rx_mask[i] =
+				sband->ht_cap.mcs.rx_mask[i] &
+					ht_cap_ie->mcs.rx_mask[i];
+
+	/* handle MCS rate 32 too */
+	if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
+		ht_cap->mcs.rx_mask[32/8] |= 1;
 }
 
-int ieee80211_ht_addt_info_ie_to_ht_bss_info(
-			struct ieee80211_ht_addt_info *ht_add_info_ie,
-			struct ieee80211_ht_bss_info *bss_info)
+/*
+ * ieee80211_enable_ht should be called only after the operating band
+ * has been determined as ht configuration depends on the hw's
+ * HT abilities for a specific band.
+ */
+u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
+			struct ieee80211_ht_info *hti,
+			u16 ap_ht_cap_flags)
 {
-	if (bss_info == NULL)
-		return -EINVAL;
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_bss_ht_conf ht;
+	u32 changed = 0;
+	bool enable_ht = true, ht_changed;
+	enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
 
-	memset(bss_info, 0, sizeof(*bss_info));
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
-	if (ht_add_info_ie) {
-		u16 op_mode;
-		op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
+	memset(&ht, 0, sizeof(ht));
 
-		bss_info->primary_channel = ht_add_info_ie->control_chan;
-		bss_info->bss_cap = ht_add_info_ie->ht_param;
-		bss_info->bss_op_mode = (u8)(op_mode & 0xff);
+	/* HT is not supported */
+	if (!sband->ht_cap.ht_supported)
+		enable_ht = false;
+
+	/* check that channel matches the right operating channel */
+	if (local->hw.conf.channel->center_freq !=
+	    ieee80211_channel_to_frequency(hti->control_chan))
+		enable_ht = false;
+
+	if (enable_ht) {
+		channel_type = NL80211_CHAN_HT20;
+
+		if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
+		    (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
+		    (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
+			switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+				channel_type = NL80211_CHAN_HT40PLUS;
+				break;
+			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+				channel_type = NL80211_CHAN_HT40MINUS;
+				break;
+			}
+		}
 	}
 
-	return 0;
+	ht_changed = local->hw.conf.ht.enabled != enable_ht ||
+		     channel_type != local->hw.conf.ht.channel_type;
+
+	local->oper_channel_type = channel_type;
+	local->hw.conf.ht.enabled = enable_ht;
+
+	if (ht_changed)
+		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
+
+	/* disable HT */
+	if (!enable_ht)
+		return 0;
+
+	ht.operation_mode = le16_to_cpu(hti->operation_mode);
+
+	/* if bss configuration changed store the new one */
+	if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) {
+		changed |= BSS_CHANGED_HT;
+		sdata->vif.bss_conf.ht = ht;
+	}
+
+	return changed;
 }
 
 static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
@@ -241,7 +329,6 @@
 	struct ieee80211_hw *hw = &local->hw;
 	struct sta_info *sta;
 	int ret, i;
-	DECLARE_MAC_BUF(mac);
 
 	rcu_read_lock();
 
@@ -269,8 +356,8 @@
 	BUG_ON(!local->ops->ampdu_action);
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Rx BA session stop requested for %s tid %u\n",
-				print_mac(mac, ra), tid);
+	printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
+	       ra, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
 	ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
@@ -383,14 +470,13 @@
 	u16 start_seq_num;
 	u8 *state;
 	int ret;
-	DECLARE_MAC_BUF(mac);
 
-	if (tid >= STA_TID_NUM)
+	if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
 		return -EINVAL;
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Open BA session requested for %s tid %u\n",
-				print_mac(mac, ra), tid);
+	printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
+	       ra, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
 	rcu_read_lock();
@@ -442,17 +528,19 @@
 			(unsigned long)&sta->timer_to_tid[tid];
 	init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
 
-	/* create a new queue for this aggregation */
-	ret = ieee80211_ht_agg_queue_add(local, sta, tid);
+	if (hw->ampdu_queues) {
+		/* create a new queue for this aggregation */
+		ret = ieee80211_ht_agg_queue_add(local, sta, tid);
 
-	/* case no queue is available to aggregation
-	 * don't switch to aggregation */
-	if (ret) {
+		/* case no queue is available to aggregation
+		 * don't switch to aggregation */
+		if (ret) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "BA request denied - queue unavailable for"
-					" tid %d\n", tid);
+			printk(KERN_DEBUG "BA request denied - "
+			       "queue unavailable for tid %d\n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
-		goto err_unlock_queue;
+			goto err_unlock_queue;
+		}
 	}
 	sdata = sta->sdata;
 
@@ -471,7 +559,8 @@
 		/* No need to requeue the packets in the agg queue, since we
 		 * held the tx lock: no packet could be enqueued to the newly
 		 * allocated queue */
-		ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
+		if (hw->ampdu_queues)
+			ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		printk(KERN_DEBUG "BA request denied - HW unavailable for"
 					" tid %d\n", tid);
@@ -481,7 +570,8 @@
 	}
 
 	/* Will put all the packets in the new SW queue */
-	ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
+	if (hw->ampdu_queues)
+		ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
 	spin_unlock_bh(&sta->lock);
 
 	/* send an addBA request */
@@ -524,7 +614,6 @@
 	struct sta_info *sta;
 	u8 *state;
 	int ret = 0;
-	DECLARE_MAC_BUF(mac);
 
 	if (tid >= STA_TID_NUM)
 		return -EINVAL;
@@ -546,11 +635,12 @@
 	}
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Tx BA session stop requested for %s tid %u\n",
-				print_mac(mac, ra), tid);
+	printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
+	       ra, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-	ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
+	if (hw->ampdu_queues)
+		ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
 
 	*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
 		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
@@ -563,7 +653,8 @@
 	if (ret) {
 		WARN_ON(ret != -EBUSY);
 		*state = HT_AGG_STATE_OPERATIONAL;
-		ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+		if (hw->ampdu_queues)
+			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
 		goto stop_BA_exit;
 	}
 
@@ -579,7 +670,6 @@
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct sta_info *sta;
 	u8 *state;
-	DECLARE_MAC_BUF(mac);
 
 	if (tid >= STA_TID_NUM) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -594,8 +684,7 @@
 	if (!sta) {
 		rcu_read_unlock();
 #ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Could not find station: %s\n",
-				print_mac(mac, ra));
+		printk(KERN_DEBUG "Could not find station: %pM\n", ra);
 #endif
 		return;
 	}
@@ -621,7 +710,8 @@
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
 #endif
-		ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+		if (hw->ampdu_queues)
+			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
 	}
 	spin_unlock_bh(&sta->lock);
 	rcu_read_unlock();
@@ -634,7 +724,6 @@
 	struct sta_info *sta;
 	u8 *state;
 	int agg_queue;
-	DECLARE_MAC_BUF(mac);
 
 	if (tid >= STA_TID_NUM) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -645,16 +734,15 @@
 	}
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
-	printk(KERN_DEBUG "Stopping Tx BA session for %s tid %d\n",
-				print_mac(mac, ra), tid);
+	printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
+	       ra, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
 	rcu_read_lock();
 	sta = sta_info_get(local, ra);
 	if (!sta) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Could not find station: %s\n",
-				print_mac(mac, ra));
+		printk(KERN_DEBUG "Could not find station: %pM\n", ra);
 #endif
 		rcu_read_unlock();
 		return;
@@ -677,16 +765,18 @@
 		ieee80211_send_delba(sta->sdata, ra, tid,
 			WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
 
-	agg_queue = sta->tid_to_tx_q[tid];
+	if (hw->ampdu_queues) {
+		agg_queue = sta->tid_to_tx_q[tid];
+		ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
 
-	ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
-
-	/* We just requeued the all the frames that were in the
-	 * removed queue, and since we might miss a softirq we do
-	 * netif_schedule_queue.  ieee80211_wake_queue is not used
-	 * here as this queue is not necessarily stopped
-	 */
-	netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue));
+		/* We just requeued the all the frames that were in the
+		 * removed queue, and since we might miss a softirq we do
+		 * netif_schedule_queue.  ieee80211_wake_queue is not used
+		 * here as this queue is not necessarily stopped
+		 */
+		netif_schedule_queue(netdev_get_tx_queue(local->mdev,
+							 agg_queue));
+	}
 	spin_lock_bh(&sta->lock);
 	*state = HT_AGG_STATE_IDLE;
 	sta->ampdu_mlme.addba_req_num[tid] = 0;
@@ -783,7 +873,6 @@
 	u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
 	u8 dialog_token;
 	int ret = -EOPNOTSUPP;
-	DECLARE_MAC_BUF(mac);
 
 	/* extract session parameters from addba request frame */
 	dialog_token = mgmt->u.action.u.addba_req.dialog_token;
@@ -801,15 +890,16 @@
 	/* sanity check for incoming parameters:
 	 * check if configuration can support the BA policy
 	 * and if buffer size does not exceeds max value */
+	/* XXX: check own ht delayed BA capability?? */
 	if (((ba_policy != 1)
-		&& (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA)))
+		&& (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
 		|| (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
 		status = WLAN_STATUS_INVALID_QOS_PARAM;
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		if (net_ratelimit())
 			printk(KERN_DEBUG "AddBA Req with bad params from "
-				"%s on tid %u. policy %d, buffer size %d\n",
-				print_mac(mac, mgmt->sa), tid, ba_policy,
+				"%pM on tid %u. policy %d, buffer size %d\n",
+				mgmt->sa, tid, ba_policy,
 				buf_size);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 		goto end_no_lock;
@@ -820,7 +910,7 @@
 
 		sband = local->hw.wiphy->bands[conf->channel->band];
 		buf_size = IEEE80211_MIN_AMPDU_BUF;
-		buf_size = buf_size << sband->ht_info.ampdu_factor;
+		buf_size = buf_size << sband->ht_cap.ampdu_factor;
 	}
 
 
@@ -831,8 +921,8 @@
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		if (net_ratelimit())
 			printk(KERN_DEBUG "unexpected AddBA Req from "
-				"%s on tid %u\n",
-				print_mac(mac, mgmt->sa), tid);
+				"%pM on tid %u\n",
+				mgmt->sa, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 		goto end;
 	}
@@ -910,7 +1000,7 @@
 {
 	struct ieee80211_hw *hw = &local->hw;
 	u16 capab;
-	u16 tid;
+	u16 tid, start_seq_num;
 	u8 *state;
 
 	capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
@@ -943,9 +1033,18 @@
 		*state |= HT_ADDBA_RECEIVED_MSK;
 		sta->ampdu_mlme.addba_req_num[tid] = 0;
 
-		if (*state == HT_AGG_STATE_OPERATIONAL)
+		if (*state == HT_AGG_STATE_OPERATIONAL &&
+		    local->hw.ampdu_queues)
 			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
 
+		if (local->ops->ampdu_action) {
+			(void)local->ops->ampdu_action(hw,
+					       IEEE80211_AMPDU_TX_RESUME,
+					       &sta->sta, tid, &start_seq_num);
+		}
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
 		spin_unlock_bh(&sta->lock);
 	} else {
 		sta->ampdu_mlme.addba_req_num[tid]++;
@@ -964,7 +1063,6 @@
 	struct ieee80211_local *local = sdata->local;
 	u16 tid, params;
 	u16 initiator;
-	DECLARE_MAC_BUF(mac);
 
 	params = le16_to_cpu(mgmt->u.action.u.delba.params);
 	tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
@@ -972,9 +1070,8 @@
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	if (net_ratelimit())
-		printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n",
-			print_mac(mac, mgmt->sa),
-			initiator ? "initiator" : "recipient", tid,
+		printk(KERN_DEBUG "delba from %pM (%s) tid %d reason code %d\n",
+			mgmt->sa, initiator ? "initiator" : "recipient", tid,
 			mgmt->u.action.u.delba.reason_code);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 156e42a..f3eec98 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -23,6 +23,7 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/etherdevice.h>
+#include <net/cfg80211.h>
 #include <net/wireless.h>
 #include <net/iw_handler.h>
 #include <net/mac80211.h>
@@ -142,7 +143,6 @@
 #define IEEE80211_TX_FRAGMENTED		BIT(0)
 #define IEEE80211_TX_UNICAST		BIT(1)
 #define IEEE80211_TX_PS_BUFFERED	BIT(2)
-#define IEEE80211_TX_PROBE_LAST_FRAG	BIT(3)
 
 struct ieee80211_tx_data {
 	struct sk_buff *skb;
@@ -153,11 +153,6 @@
 	struct ieee80211_key *key;
 
 	struct ieee80211_channel *channel;
-	s8 rate_idx;
-	/* use this rate (if set) for last fragment; rate can
-	 * be set to lower rate for the first fragments, e.g.,
-	 * when using CTS protection with IEEE 802.11g. */
-	s8 last_frag_rate_idx;
 
 	/* Extra fragments (in addition to the first fragment
 	 * in skb) */
@@ -192,7 +187,6 @@
 	struct ieee80211_rx_status *status;
 	struct ieee80211_rate *rate;
 
-	u16 ethertype;
 	unsigned int flags;
 	int sent_ps_buffered;
 	int queue;
@@ -203,9 +197,7 @@
 struct ieee80211_tx_stored_packet {
 	struct sk_buff *skb;
 	struct sk_buff **extra_frag;
-	s8 last_frag_rate_idx;
 	int num_extra_frag;
-	bool last_frag_rate_ctrl_probe;
 };
 
 struct beacon_data {
@@ -219,9 +211,6 @@
 
 	struct list_head vlans;
 
-	u8 ssid[IEEE80211_MAX_SSID_LEN];
-	size_t ssid_len;
-
 	/* yes, this looks ugly, but guarantees that we can later use
 	 * bitmap_empty :)
 	 * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
@@ -255,26 +244,6 @@
 	u8 flags;
 };
 
-struct mesh_config {
-	/* Timeouts in ms */
-	/* Mesh plink management parameters */
-	u16 dot11MeshRetryTimeout;
-	u16 dot11MeshConfirmTimeout;
-	u16 dot11MeshHoldingTimeout;
-	u16 dot11MeshMaxPeerLinks;
-	u8  dot11MeshMaxRetries;
-	u8  dot11MeshTTL;
-	bool auto_open_plinks;
-	/* HWMP parameters */
-	u8  dot11MeshHWMPmaxPREQretries;
-	u32 path_refresh_time;
-	u16 min_discovery_timeout;
-	u32 dot11MeshHWMPactivePathTimeout;
-	u16 dot11MeshHWMPpreqMinInterval;
-	u16 dot11MeshHWMPnetDiameterTraversalTime;
-};
-
-
 /* flags used in struct ieee80211_if_sta.flags */
 #define IEEE80211_STA_SSID_SET		BIT(0)
 #define IEEE80211_STA_BSSID_SET		BIT(1)
@@ -438,8 +407,7 @@
 	struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
 	struct ieee80211_key *default_key;
 
-	/* BSS configuration for this interface. */
-	struct ieee80211_bss_conf bss_conf;
+	u16 sequence_number;
 
 	/*
 	 * AP this belongs to: self in AP mode and
@@ -570,6 +538,11 @@
 	IEEE80211_ADDBA_MSG	= 4,
 };
 
+enum queue_stop_reason {
+	IEEE80211_QUEUE_STOP_REASON_DRIVER,
+	IEEE80211_QUEUE_STOP_REASON_PS,
+};
+
 /* maximum number of hardware queues we support. */
 #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
 
@@ -586,7 +559,8 @@
 	const struct ieee80211_ops *ops;
 
 	unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)];
-
+	unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
+	spinlock_t queue_stop_reason_lock;
 	struct net_device *mdev; /* wmaster# - "master" 802.11 device */
 	int open_count;
 	int monitors, cooked_mntrs;
@@ -633,8 +607,6 @@
 
 	int rts_threshold;
 	int fragmentation_threshold;
-	int short_retry_limit; /* dot11ShortRetryLimit */
-	int long_retry_limit; /* dot11LongRetryLimit */
 
 	struct crypto_blkcipher *wep_tx_tfm;
 	struct crypto_blkcipher *wep_rx_tfm;
@@ -659,6 +631,7 @@
 	struct delayed_work scan_work;
 	struct ieee80211_sub_if_data *scan_sdata;
 	struct ieee80211_channel *oper_channel, *scan_channel;
+	enum nl80211_channel_type oper_channel_type;
 	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
 	size_t scan_ssid_len;
 	struct list_head bss_list;
@@ -722,13 +695,17 @@
 	int wifi_wme_noack_test;
 	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
+	bool powersave;
+	int dynamic_ps_timeout;
+	struct work_struct dynamic_ps_enable_work;
+	struct work_struct dynamic_ps_disable_work;
+	struct timer_list dynamic_ps_timer;
+
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct local_debugfsdentries {
 		struct dentry *rcdir;
 		struct dentry *rcname;
 		struct dentry *frequency;
-		struct dentry *antenna_sel_tx;
-		struct dentry *antenna_sel_rx;
 		struct dentry *rts_threshold;
 		struct dentry *fragmentation_threshold;
 		struct dentry *short_retry_limit;
@@ -817,7 +794,7 @@
 	u8 *wmm_info;
 	u8 *wmm_param;
 	struct ieee80211_ht_cap *ht_cap_elem;
-	struct ieee80211_ht_addt_info *ht_info_elem;
+	struct ieee80211_ht_info *ht_info_elem;
 	u8 *mesh_config;
 	u8 *mesh_id;
 	u8 *peer_link;
@@ -869,11 +846,6 @@
 	return &local->hw;
 }
 
-struct sta_attribute {
-	struct attribute attr;
-	ssize_t (*show)(const struct sta_info *, char *buf);
-	ssize_t (*store)(struct sta_info *, const char *buf, size_t count);
-};
 
 static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 {
@@ -882,12 +854,9 @@
 }
 
 
-int ieee80211_hw_config(struct ieee80211_local *local);
+int ieee80211_hw_config(struct ieee80211_local *local, u32 changed);
 int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed);
 void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
-u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
-			struct ieee80211_ht_info *req_ht_cap,
-			struct ieee80211_ht_bss_info *req_bss_cap);
 void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 				      u32 changed);
 void ieee80211_configure_filter(struct ieee80211_local *local);
@@ -906,8 +875,7 @@
 void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata,
 			    struct ieee80211_if_sta *ifsta);
 struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
-					struct sk_buff *skb, u8 *bssid,
-					u8 *addr, u64 supp_rates);
+					u8 *bssid, u8 *addr, u64 supp_rates);
 int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason);
 int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason);
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
@@ -968,11 +936,12 @@
 int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
 /* HT */
-int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
-				   struct ieee80211_ht_info *ht_info);
-int ieee80211_ht_addt_info_ie_to_ht_bss_info(
-			struct ieee80211_ht_addt_info *ht_add_info_ie,
-			struct ieee80211_ht_bss_info *bss_info);
+void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
+				       struct ieee80211_ht_cap *ht_cap_ie,
+				       struct ieee80211_sta_ht_cap *ht_cap);
+u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
+			struct ieee80211_ht_info *hti,
+			u16 ap_ht_cap_flags);
 void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn);
 
 void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
@@ -1014,6 +983,15 @@
 u64 ieee80211_mandatory_rates(struct ieee80211_local *local,
 			      enum ieee80211_band band);
 
+void ieee80211_dynamic_ps_enable_work(struct work_struct *work);
+void ieee80211_dynamic_ps_disable_work(struct work_struct *work);
+void ieee80211_dynamic_ps_timer(unsigned long data);
+
+void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
+				     enum queue_stop_reason reason);
+void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
+				     enum queue_stop_reason reason);
+
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
 #else
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8336fee..5abbc3f 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -65,7 +65,7 @@
 	struct ieee80211_if_init_conf conf;
 	u32 changed = 0;
 	int res;
-	bool need_hw_reconfig = 0;
+	u32 hw_reconf_flags = 0;
 	u8 null_addr[ETH_ALEN] = {0};
 
 	/* fail early if user set an invalid address */
@@ -152,7 +152,8 @@
 			res = local->ops->start(local_to_hw(local));
 		if (res)
 			goto err_del_bss;
-		need_hw_reconfig = 1;
+		/* we're brought up, everything changes */
+		hw_reconf_flags = ~0;
 		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
 	}
 
@@ -198,8 +199,10 @@
 
 		/* must be before the call to ieee80211_configure_filter */
 		local->monitors++;
-		if (local->monitors == 1)
+		if (local->monitors == 1) {
 			local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+			hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP;
+		}
 
 		if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
 			local->fif_fcsfail++;
@@ -226,8 +229,14 @@
 		if (res)
 			goto err_stop;
 
-		if (ieee80211_vif_is_mesh(&sdata->vif))
+		if (ieee80211_vif_is_mesh(&sdata->vif)) {
+			local->fif_other_bss++;
+			netif_addr_lock_bh(local->mdev);
+			ieee80211_configure_filter(local);
+			netif_addr_unlock_bh(local->mdev);
+
 			ieee80211_start_mesh(sdata);
+		}
 		changed |= ieee80211_reset_erp_info(sdata);
 		ieee80211_bss_info_change_notify(sdata, changed);
 		ieee80211_enable_keys(sdata);
@@ -279,8 +288,8 @@
 		atomic_inc(&local->iff_promiscs);
 
 	local->open_count++;
-	if (need_hw_reconfig) {
-		ieee80211_hw_config(local);
+	if (hw_reconf_flags) {
+		ieee80211_hw_config(local, hw_reconf_flags);
 		/*
 		 * set default queue parameters so drivers don't
 		 * need to initialise the hardware if the hardware
@@ -322,6 +331,7 @@
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_init_conf conf;
 	struct sta_info *sta;
+	u32 hw_reconf_flags = 0;
 
 	/*
 	 * Stop TX on this interface first.
@@ -405,8 +415,10 @@
 		}
 
 		local->monitors--;
-		if (local->monitors == 0)
+		if (local->monitors == 0) {
 			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+			hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP;
+		}
 
 		if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
 			local->fif_fcsfail--;
@@ -423,7 +435,11 @@
 		break;
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_ADHOC:
-		sdata->u.sta.state = IEEE80211_STA_MLME_DISABLED;
+		/* Announce that we are leaving the network. */
+		if (sdata->u.sta.state != IEEE80211_STA_MLME_DISABLED)
+			ieee80211_sta_deauthenticate(sdata,
+						WLAN_REASON_DEAUTH_LEAVING);
+
 		memset(sdata->u.sta.bssid, 0, ETH_ALEN);
 		del_timer_sync(&sdata->u.sta.timer);
 		/*
@@ -450,8 +466,15 @@
 		/* fall through */
 	case NL80211_IFTYPE_MESH_POINT:
 		if (ieee80211_vif_is_mesh(&sdata->vif)) {
-			/* allmulti is always set on mesh ifaces */
+			/* other_bss and allmulti are always set on mesh
+			 * ifaces */
+			local->fif_other_bss--;
 			atomic_dec(&local->iff_allmultis);
+
+			netif_addr_lock_bh(local->mdev);
+			ieee80211_configure_filter(local);
+			netif_addr_unlock_bh(local->mdev);
+
 			ieee80211_stop_mesh(sdata);
 		}
 		/* fall through */
@@ -504,8 +527,15 @@
 
 		tasklet_disable(&local->tx_pending_tasklet);
 		tasklet_disable(&local->tasklet);
+
+		/* no reconfiguring after stop! */
+		hw_reconf_flags = 0;
 	}
 
+	/* do after stop to avoid reconfiguring when we stop anyway */
+	if (hw_reconf_flags)
+		ieee80211_hw_config(local, hw_reconf_flags);
+
 	return 0;
 }
 
@@ -668,6 +698,10 @@
 	if (type == sdata->vif.type)
 		return 0;
 
+	/* Setting ad-hoc mode on non-IBSS channel is not supported. */
+	if (sdata->local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)
+		return -EOPNOTSUPP;
+
 	/*
 	 * We could, here, on changes between IBSS/STA/MESH modes,
 	 * invoke an MLME function instead that disassociates etc.
@@ -682,7 +716,7 @@
 	ieee80211_setup_sdata(sdata, type);
 
 	/* reset some values that shouldn't be kept across type changes */
-	sdata->bss_conf.basic_rates =
+	sdata->vif.bss_conf.basic_rates =
 		ieee80211_mandatory_rates(sdata->local,
 			sdata->local->hw.conf.channel->band);
 	sdata->drop_unencrypted = 0;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index a5b06fe..999f7aa 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -132,7 +132,6 @@
 {
 	const u8 *addr;
 	int ret;
-	DECLARE_MAC_BUF(mac);
 
 	assert_key_lock();
 	might_sleep();
@@ -154,16 +153,15 @@
 
 	if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
 		printk(KERN_ERR "mac80211-%s: failed to set key "
-		       "(%d, %s) to hardware (%d)\n",
+		       "(%d, %pM) to hardware (%d)\n",
 		       wiphy_name(key->local->hw.wiphy),
-		       key->conf.keyidx, print_mac(mac, addr), ret);
+		       key->conf.keyidx, addr, ret);
 }
 
 static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 {
 	const u8 *addr;
 	int ret;
-	DECLARE_MAC_BUF(mac);
 
 	assert_key_lock();
 	might_sleep();
@@ -186,9 +184,9 @@
 
 	if (ret)
 		printk(KERN_ERR "mac80211-%s: failed to remove key "
-		       "(%d, %s) from hardware (%d)\n",
+		       "(%d, %pM) from hardware (%d)\n",
 		       wiphy_name(key->local->hw.wiphy),
-		       key->conf.keyidx, print_mac(mac, addr), ret);
+		       key->conf.keyidx, addr, ret);
 
 	spin_lock(&todo_lock);
 	key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index ae62ad40..24b1436 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -41,6 +41,8 @@
  */
 struct ieee80211_tx_status_rtap_hdr {
 	struct ieee80211_radiotap_header hdr;
+	u8 rate;
+	u8 padding_for_rate;
 	__le16 tx_flags;
 	u8 data_retries;
 } __attribute__ ((packed));
@@ -169,19 +171,13 @@
 	conf.changed = changed;
 
 	if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-	    sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+	    sdata->vif.type == NL80211_IFTYPE_ADHOC)
 		conf.bssid = sdata->u.sta.bssid;
-		conf.ssid = sdata->u.sta.ssid;
-		conf.ssid_len = sdata->u.sta.ssid_len;
-	} else if (sdata->vif.type == NL80211_IFTYPE_AP) {
+	else if (sdata->vif.type == NL80211_IFTYPE_AP)
 		conf.bssid = sdata->dev->dev_addr;
-		conf.ssid = sdata->u.ap.ssid;
-		conf.ssid_len = sdata->u.ap.ssid_len;
-	} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+	else if (ieee80211_vif_is_mesh(&sdata->vif)) {
 		u8 zero[ETH_ALEN] = { 0 };
 		conf.bssid = zero;
-		conf.ssid = zero;
-		conf.ssid_len = 0;
 	} else {
 		WARN_ON(1);
 		return -EINVAL;
@@ -190,138 +186,75 @@
 	if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
 		return -EINVAL;
 
-	if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID)))
-		return -EINVAL;
-
 	return local->ops->config_interface(local_to_hw(local),
 					    &sdata->vif, &conf);
 }
 
-int ieee80211_hw_config(struct ieee80211_local *local)
+int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
 	struct ieee80211_channel *chan;
 	int ret = 0;
+	int power;
+	enum nl80211_channel_type channel_type;
 
-	if (local->sw_scanning)
+	might_sleep();
+
+	if (local->sw_scanning) {
 		chan = local->scan_channel;
-	else
+		channel_type = NL80211_CHAN_NO_HT;
+	} else {
 		chan = local->oper_channel;
+		channel_type = local->oper_channel_type;
+	}
 
-	local->hw.conf.channel = chan;
+	if (chan != local->hw.conf.channel ||
+	    channel_type != local->hw.conf.ht.channel_type) {
+		local->hw.conf.channel = chan;
+		local->hw.conf.ht.channel_type = channel_type;
+		switch (channel_type) {
+		case NL80211_CHAN_NO_HT:
+			local->hw.conf.ht.enabled = false;
+			break;
+		case NL80211_CHAN_HT20:
+		case NL80211_CHAN_HT40MINUS:
+		case NL80211_CHAN_HT40PLUS:
+			local->hw.conf.ht.enabled = true;
+			break;
+		}
+		changed |= IEEE80211_CONF_CHANGE_CHANNEL;
+	}
 
 	if (!local->hw.conf.power_level)
-		local->hw.conf.power_level = chan->max_power;
+		power = chan->max_power;
 	else
-		local->hw.conf.power_level = min(chan->max_power,
-					       local->hw.conf.power_level);
+		power = min(chan->max_power, local->hw.conf.power_level);
+	if (local->hw.conf.power_level != power) {
+		changed |= IEEE80211_CONF_CHANGE_POWER;
+		local->hw.conf.power_level = power;
+	}
 
-	local->hw.conf.max_antenna_gain = chan->max_antenna_gain;
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n",
-	       wiphy_name(local->hw.wiphy), chan->center_freq);
-#endif
-
-	if (local->open_count)
-		ret = local->ops->config(local_to_hw(local), &local->hw.conf);
+	if (changed && local->open_count) {
+		ret = local->ops->config(local_to_hw(local), changed);
+		/*
+		 * Goal:
+		 * HW reconfiguration should never fail, the driver has told
+		 * us what it can support so it should live up to that promise.
+		 *
+		 * Current status:
+		 * rfkill is not integrated with mac80211 and a
+		 * configuration command can thus fail if hardware rfkill
+		 * is enabled
+		 *
+		 * FIXME: integrate rfkill with mac80211 and then add this
+		 * WARN_ON() back
+		 *
+		 */
+		/* WARN_ON(ret); */
+	}
 
 	return ret;
 }
 
-/**
- * ieee80211_handle_ht should be used only after legacy configuration
- * has been determined namely band, as ht configuration depends upon
- * the hardware's HT abilities for a _specific_ band.
- */
-u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
-			   struct ieee80211_ht_info *req_ht_cap,
-			   struct ieee80211_ht_bss_info *req_bss_cap)
-{
-	struct ieee80211_conf *conf = &local->hw.conf;
-	struct ieee80211_supported_band *sband;
-	struct ieee80211_ht_info ht_conf;
-	struct ieee80211_ht_bss_info ht_bss_conf;
-	u32 changed = 0;
-	int i;
-	u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
-	u8 tx_mcs_set_cap;
-
-	sband = local->hw.wiphy->bands[conf->channel->band];
-
-	memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
-	memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
-
-	/* HT is not supported */
-	if (!sband->ht_info.ht_supported) {
-		conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
-		goto out;
-	}
-
-	/* disable HT */
-	if (!enable_ht) {
-		if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
-			changed |= BSS_CHANGED_HT;
-		conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
-		conf->ht_conf.ht_supported = 0;
-		goto out;
-	}
-
-
-	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
-		changed |= BSS_CHANGED_HT;
-
-	conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
-	ht_conf.ht_supported = 1;
-
-	ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
-	ht_conf.cap &= ~(IEEE80211_HT_CAP_SM_PS);
-	ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_SM_PS;
-	ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
-	ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
-	ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
-
-	ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
-	ht_conf.ampdu_density = req_ht_cap->ampdu_density;
-
-	/* Bits 96-100 */
-	tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
-
-	/* configure suppoerted Tx MCS according to requested MCS
-	 * (based in most cases on Rx capabilities of peer) and self
-	 * Tx MCS capabilities (as defined by low level driver HW
-	 * Tx capabilities) */
-	if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
-		goto check_changed;
-
-	/* Counting from 0 therfore + 1 */
-	if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
-		max_tx_streams = ((tx_mcs_set_cap &
-				IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
-
-	for (i = 0; i < max_tx_streams; i++)
-		ht_conf.supp_mcs_set[i] =
-			sband->ht_info.supp_mcs_set[i] &
-					req_ht_cap->supp_mcs_set[i];
-
-	if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
-		for (i = IEEE80211_SUPP_MCS_SET_UEQM;
-		     i < IEEE80211_SUPP_MCS_SET_LEN; i++)
-			ht_conf.supp_mcs_set[i] =
-				sband->ht_info.supp_mcs_set[i] &
-					req_ht_cap->supp_mcs_set[i];
-
-check_changed:
-	/* if bss configuration changed store the new one */
-	if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
-	    memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
-		changed |= BSS_CHANGED_HT;
-		memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
-		memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
-	}
-out:
-	return changed;
-}
-
 void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 				      u32 changed)
 {
@@ -336,15 +269,18 @@
 	if (local->ops->bss_info_changed)
 		local->ops->bss_info_changed(local_to_hw(local),
 					     &sdata->vif,
-					     &sdata->bss_conf,
+					     &sdata->vif.bss_conf,
 					     changed);
 }
 
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
 {
-	sdata->bss_conf.use_cts_prot = 0;
-	sdata->bss_conf.use_short_preamble = 0;
-	return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE;
+	sdata->vif.bss_conf.use_cts_prot = false;
+	sdata->vif.bss_conf.use_short_preamble = false;
+	sdata->vif.bss_conf.use_short_slot = false;
+	return BSS_CHANGED_ERP_CTS_PROT |
+	       BSS_CHANGED_ERP_PREAMBLE |
+	       BSS_CHANGED_ERP_SLOT;
 }
 
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
@@ -405,7 +341,8 @@
 			dev_kfree_skb(skb);
 			break ;
 		default:
-			WARN_ON(1);
+			WARN(1, "mac80211: Packet is of unknown type %d\n",
+			     skb->pkt_type);
 			dev_kfree_skb(skb);
 			break;
 		}
@@ -466,8 +403,6 @@
 					    struct sta_info *sta,
 					    struct sk_buff *skb)
 {
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
 	sta->tx_filtered_count++;
 
 	/*
@@ -514,10 +449,9 @@
 		return;
 	}
 
-	if (!test_sta_flags(sta, WLAN_STA_PS) &&
-	    !(info->flags & IEEE80211_TX_CTL_REQUEUE)) {
+	if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) {
 		/* Software retry the packet once */
-		info->flags |= IEEE80211_TX_CTL_REQUEUE;
+		skb->requeue = 1;
 		ieee80211_remove_tx_extra(local, sta->key, skb);
 		dev_queue_xmit(skb);
 		return;
@@ -547,13 +481,28 @@
 	struct ieee80211_sub_if_data *sdata;
 	struct net_device *prev_dev = NULL;
 	struct sta_info *sta;
+	int retry_count = -1, i;
+
+	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+		/* the HW cannot have attempted that rate */
+		if (i >= hw->max_rates) {
+			info->status.rates[i].idx = -1;
+			info->status.rates[i].count = 0;
+		}
+
+		retry_count += info->status.rates[i].count;
+	}
+	if (retry_count < 0)
+		retry_count = 0;
 
 	rcu_read_lock();
 
+	sband = local->hw.wiphy->bands[info->band];
+
 	sta = sta_info_get(local, hdr->addr1);
 
 	if (sta) {
-		if (info->status.excessive_retries &&
+		if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
 		    test_sta_flags(sta, WLAN_STA_PS)) {
 			/*
 			 * The STA is in power save mode, so assume
@@ -584,12 +533,11 @@
 			rcu_read_unlock();
 			return;
 		} else {
-			if (info->status.excessive_retries)
+			if (!(info->flags & IEEE80211_TX_STAT_ACK))
 				sta->tx_retry_failed++;
-			sta->tx_retry_count += info->status.retry_count;
+			sta->tx_retry_count += retry_count;
 		}
 
-		sband = local->hw.wiphy->bands[info->band];
 		rate_control_tx_status(local, sband, sta, skb);
 	}
 
@@ -610,9 +558,9 @@
 			local->dot11TransmittedFrameCount++;
 			if (is_multicast_ether_addr(hdr->addr1))
 				local->dot11MulticastTransmittedFrameCount++;
-			if (info->status.retry_count > 0)
+			if (retry_count > 0)
 				local->dot11RetryCount++;
-			if (info->status.retry_count > 1)
+			if (retry_count > 1)
 				local->dot11MultipleRetryCount++;
 		}
 
@@ -656,19 +604,30 @@
 	rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
 	rthdr->hdr.it_present =
 		cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
-			    (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
+			    (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
+			    (1 << IEEE80211_RADIOTAP_RATE));
 
 	if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
 	    !is_multicast_ether_addr(hdr->addr1))
 		rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
 
-	if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) &&
-	    (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
+	/*
+	 * XXX: Once radiotap gets the bitmap reset thing the vendor
+	 *	extensions proposal contains, we can actually report
+	 *	the whole set of tries we did.
+	 */
+	if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+	    (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
 		rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
-	else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+	else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
 		rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
+	if (info->status.rates[0].idx >= 0 &&
+	    !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
+		rthdr->rate = sband->bitrates[
+				info->status.rates[0].idx].bitrate / 5;
 
-	rthdr->data_retries = info->status.retry_count;
+	/* for now report the total retry_count */
+	rthdr->data_retries = retry_count;
 
 	/* XXX: is this sufficient for BPF? */
 	skb_set_mac_header(skb, 0);
@@ -753,20 +712,30 @@
 	BUG_ON(!ops->configure_filter);
 	local->ops = ops;
 
-	local->hw.queues = 1; /* default */
-
+	/* set up some defaults */
+	local->hw.queues = 1;
+	local->hw.max_rates = 1;
 	local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
 	local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
-	local->short_retry_limit = 7;
-	local->long_retry_limit = 4;
-	local->hw.conf.radio_enabled = 1;
+	local->hw.conf.long_frame_max_tx_count = 4;
+	local->hw.conf.short_frame_max_tx_count = 7;
+	local->hw.conf.radio_enabled = true;
 
 	INIT_LIST_HEAD(&local->interfaces);
 
 	spin_lock_init(&local->key_lock);
 
+	spin_lock_init(&local->queue_stop_reason_lock);
+
 	INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 
+	INIT_WORK(&local->dynamic_ps_enable_work,
+		  ieee80211_dynamic_ps_enable_work);
+	INIT_WORK(&local->dynamic_ps_disable_work,
+		  ieee80211_dynamic_ps_disable_work);
+	setup_timer(&local->dynamic_ps_timer,
+		    ieee80211_dynamic_ps_timer, (unsigned long) local);
+
 	sta_info_init(local);
 
 	tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
@@ -788,7 +757,6 @@
 int ieee80211_register_hw(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	const char *name;
 	int result;
 	enum ieee80211_band band;
 	struct net_device *mdev;
@@ -853,8 +821,8 @@
 	mdev->header_ops = &ieee80211_header_ops;
 	mdev->set_multicast_list = ieee80211_master_set_multicast_list;
 
-	name = wiphy_dev(local->hw.wiphy)->driver->name;
-	local->hw.workqueue = create_freezeable_workqueue(name);
+	local->hw.workqueue =
+		create_freezeable_workqueue(wiphy_name(local->hw.wiphy));
 	if (!local->hw.workqueue) {
 		result = -ENOMEM;
 		goto fail_workqueue;
@@ -921,12 +889,14 @@
 
 	local->mdev->select_queue = ieee80211_select_queue;
 
-	/* add one default STA interface */
-	result = ieee80211_if_add(local, "wlan%d", NULL,
-				  NL80211_IFTYPE_STATION, NULL);
-	if (result)
-		printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
-		       wiphy_name(local->hw.wiphy));
+	/* add one default STA interface if supported */
+	if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) {
+		result = ieee80211_if_add(local, "wlan%d", NULL,
+					  NL80211_IFTYPE_STATION, NULL);
+		if (result)
+			printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
+			       wiphy_name(local->hw.wiphy));
+	}
 
 	rtnl_unlock();
 
@@ -1013,7 +983,7 @@
 
 	BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb));
 	BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
-	             IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
+		     IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
 
 	ret = rc80211_minstrel_init();
 	if (ret)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 8013277..82f568e 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -238,7 +238,7 @@
 
 	pos = skb_put(skb, 21);
 	*pos++ = WLAN_EID_MESH_CONFIG;
-	*pos++ = MESH_CFG_LEN;
+	*pos++ = IEEE80211_MESH_CONFIG_LEN;
 	/* Version */
 	*pos++ = 1;
 
@@ -473,7 +473,7 @@
 					size_t len,
 					struct ieee80211_rx_status *rx_status)
 {
-	struct ieee80211_local *local= sdata->local;
+	struct ieee80211_local *local = sdata->local;
 	struct ieee802_11_elems elems;
 	struct ieee80211_channel *channel;
 	u64 supp_rates = 0;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index e10471c..c197ab5 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -145,9 +145,6 @@
 };
 
 
-/* Mesh IEs constants */
-#define MESH_CFG_LEN		19
-
 /*
  * MESH_CFG_COMP_LEN Includes:
  * 	- Active path selection protocol ID.
@@ -157,7 +154,7 @@
  * Does not include mesh capabilities, which may vary across nodes in the same
  * mesh
  */
-#define MESH_CFG_CMP_LEN 	17
+#define MESH_CFG_CMP_LEN 	(IEEE80211_MESH_CONFIG_LEN - 2)
 
 /* Default values, timeouts in ms */
 #define MESH_TTL 		5
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 501c783..71fe609 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -218,12 +218,16 @@
 
 	if (sta->fail_avg >= 100)
 		return MAX_METRIC;
+
+	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
+		return MAX_METRIC;
+
 	err = (sta->fail_avg << ARITH_SHIFT) / 100;
 
 	/* bitrate is in units of 100 Kbps, while we need rate in units of
 	 * 1Mbps. This will be corrected on tx_time computation.
 	 */
-	rate = sband->bitrates[sta->last_txrate_idx].bitrate;
+	rate = sband->bitrates[sta->last_tx_rate.idx].bitrate;
 	tx_time = (device_constant + 10 * test_frame_len / rate);
 	estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
 	result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
@@ -759,7 +763,6 @@
  *
  * @skb: 802.11 frame to be sent
  * @sdata: network subif the frame will be sent through
- * @fwd_frame: true if this frame was originally from a different host
  *
  * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is
  * found, the function will start a path discovery and queue the frame so it is
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index faac101..929ba54 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -257,9 +257,6 @@
 	struct sta_info *sta;
 	__le16 llid, plid, reason;
 	struct ieee80211_sub_if_data *sdata;
-#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
-	DECLARE_MAC_BUF(mac);
-#endif
 
 	/*
 	 * This STA is valid because sta_info_destroy() will
@@ -274,8 +271,8 @@
 		spin_unlock_bh(&sta->lock);
 		return;
 	}
-	mpl_dbg("Mesh plink timer for %s fired on state %d\n",
-			print_mac(mac, sta->sta.addr), sta->plink_state);
+	mpl_dbg("Mesh plink timer for %pM fired on state %d\n",
+		sta->sta.addr, sta->plink_state);
 	reason = 0;
 	llid = sta->llid;
 	plid = sta->plid;
@@ -287,9 +284,9 @@
 		/* retry timer */
 		if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
 			u32 rand;
-			mpl_dbg("Mesh plink for %s (retry, timeout): %d %d\n",
-					print_mac(mac, sta->sta.addr),
-					sta->plink_retries, sta->plink_timeout);
+			mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n",
+				sta->sta.addr, sta->plink_retries,
+				sta->plink_timeout);
 			get_random_bytes(&rand, sizeof(u32));
 			sta->plink_timeout = sta->plink_timeout +
 					     rand % sta->plink_timeout;
@@ -337,9 +334,6 @@
 {
 	__le16 llid;
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
-#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
-	DECLARE_MAC_BUF(mac);
-#endif
 
 	spin_lock_bh(&sta->lock);
 	get_random_bytes(&llid, 2);
@@ -351,8 +345,8 @@
 	sta->plink_state = PLINK_OPN_SNT;
 	mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
 	spin_unlock_bh(&sta->lock);
-	mpl_dbg("Mesh plink: starting establishment with %s\n",
-		print_mac(mac, sta->sta.addr));
+	mpl_dbg("Mesh plink: starting establishment with %pM\n",
+		sta->sta.addr);
 
 	return mesh_plink_frame_tx(sdata, PLINK_OPEN,
 				   sta->sta.addr, llid, 0, 0);
@@ -360,10 +354,6 @@
 
 void mesh_plink_block(struct sta_info *sta)
 {
-#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
-	DECLARE_MAC_BUF(mac);
-#endif
-
 	spin_lock_bh(&sta->lock);
 	__mesh_plink_deactivate(sta);
 	sta->plink_state = PLINK_BLOCKED;
@@ -374,12 +364,8 @@
 {
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
 	__le16 llid, plid, reason;
-#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
-	DECLARE_MAC_BUF(mac);
-#endif
 
-	mpl_dbg("Mesh plink: closing link with %s\n",
-			print_mac(mac, sta->sta.addr));
+	mpl_dbg("Mesh plink: closing link with %pM\n", sta->sta.addr);
 	spin_lock_bh(&sta->lock);
 	sta->reason = cpu_to_le16(MESH_LINK_CANCELLED);
 	reason = sta->reason;
@@ -417,9 +403,6 @@
 	u8 ie_len;
 	u8 *baseaddr;
 	__le16 plid, llid, reason;
-#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
-	DECLARE_MAC_BUF(mac);
-#endif
 
 	/* need action_code, aux */
 	if (len < IEEE80211_MIN_ACTION_SIZE + 3)
@@ -557,10 +540,10 @@
 		}
 	}
 
-	mpl_dbg("Mesh plink (peer, state, llid, plid, event): %s %d %d %d %d\n",
-			print_mac(mac, mgmt->sa), sta->plink_state,
-			le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
-			event);
+	mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %d %d %d %d\n",
+		mgmt->sa, sta->plink_state,
+		le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
+		event);
 	reason = 0;
 	switch (sta->plink_state) {
 		/* spin_unlock as soon as state is updated at each case */
@@ -660,8 +643,8 @@
 			sta->plink_state = PLINK_ESTAB;
 			mesh_plink_inc_estab_count(sdata);
 			spin_unlock_bh(&sta->lock);
-			mpl_dbg("Mesh plink with %s ESTABLISHED\n",
-					print_mac(mac, sta->sta.addr));
+			mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
+				sta->sta.addr);
 			break;
 		default:
 			spin_unlock_bh(&sta->lock);
@@ -693,8 +676,8 @@
 			sta->plink_state = PLINK_ESTAB;
 			mesh_plink_inc_estab_count(sdata);
 			spin_unlock_bh(&sta->lock);
-			mpl_dbg("Mesh plink with %s ESTABLISHED\n",
-					print_mac(mac, sta->sta.addr));
+			mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
+				sta->sta.addr);
 			mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
 					    plid, 0);
 			break;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 409bb77..5ba721b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -14,7 +14,6 @@
 #include <linux/delay.h>
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
-#include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <linux/random.h>
@@ -236,7 +235,7 @@
 	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
-	u8 *pos, *ies, *ht_add_ie;
+	u8 *pos, *ies, *ht_ie;
 	int i, len, count, rates_len, supp_rates_len;
 	u16 capab;
 	struct ieee80211_bss *bss;
@@ -310,7 +309,7 @@
 		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 						  IEEE80211_STYPE_ASSOC_REQ);
 		mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
-		mgmt->u.reassoc_req.listen_interval =
+		mgmt->u.assoc_req.listen_interval =
 				cpu_to_le16(local->hw.conf.listen_interval);
 	}
 
@@ -393,24 +392,25 @@
 
 	/* wmm support is a must to HT */
 	if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
-	    sband->ht_info.ht_supported &&
-	    (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) {
-		struct ieee80211_ht_addt_info *ht_add_info =
-			(struct ieee80211_ht_addt_info *)ht_add_ie;
-		u16 cap = sband->ht_info.cap;
+	    sband->ht_cap.ht_supported &&
+	    (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) &&
+	    ht_ie[1] >= sizeof(struct ieee80211_ht_info)) {
+		struct ieee80211_ht_info *ht_info =
+			(struct ieee80211_ht_info *)(ht_ie + 2);
+		u16 cap = sband->ht_cap.cap;
 		__le16 tmp;
 		u32 flags = local->hw.conf.channel->flags;
 
-		switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) {
-		case IEEE80211_HT_IE_CHA_SEC_ABOVE:
+		switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+		case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
 			if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
-				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 				cap &= ~IEEE80211_HT_CAP_SGI_40;
 			}
 			break;
-		case IEEE80211_HT_IE_CHA_SEC_BELOW:
+		case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
 			if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
-				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+				cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 				cap &= ~IEEE80211_HT_CAP_SGI_40;
 			}
 			break;
@@ -424,9 +424,9 @@
 		memcpy(pos, &tmp, sizeof(u16));
 		pos += sizeof(u16);
 		/* TODO: needs a define here for << 2 */
-		*pos++ = sband->ht_info.ampdu_factor |
-			 (sband->ht_info.ampdu_density << 2);
-		memcpy(pos, sband->ht_info.supp_mcs_set, 16);
+		*pos++ = sband->ht_cap.ampdu_factor |
+			 (sband->ht_cap.ampdu_density << 2);
+		memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
 	}
 
 	kfree(ifsta->assocreq_ies);
@@ -568,25 +568,35 @@
 	}
 }
 
-static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
-					   bool use_protection,
-					   bool use_short_preamble)
+static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
+					   u16 capab, bool erp_valid, u8 erp)
 {
-	struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
+	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-	DECLARE_MAC_BUF(mac);
 #endif
 	u32 changed = 0;
+	bool use_protection;
+	bool use_short_preamble;
+	bool use_short_slot;
+
+	if (erp_valid) {
+		use_protection = (erp & WLAN_ERP_USE_PROTECTION) != 0;
+		use_short_preamble = (erp & WLAN_ERP_BARKER_PREAMBLE) == 0;
+	} else {
+		use_protection = false;
+		use_short_preamble = !!(capab & WLAN_CAPABILITY_SHORT_PREAMBLE);
+	}
+
+	use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
 
 	if (use_protection != bss_conf->use_cts_prot) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
-			       "%s)\n",
+			printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n",
 			       sdata->dev->name,
 			       use_protection ? "enabled" : "disabled",
-			       print_mac(mac, ifsta->bssid));
+			       ifsta->bssid);
 		}
 #endif
 		bss_conf->use_cts_prot = use_protection;
@@ -597,40 +607,28 @@
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: switched to %s barker preamble"
-			       " (BSSID=%s)\n",
+			       " (BSSID=%pM)\n",
 			       sdata->dev->name,
 			       use_short_preamble ? "short" : "long",
-			       print_mac(mac, ifsta->bssid));
+			       ifsta->bssid);
 		}
 #endif
 		bss_conf->use_short_preamble = use_short_preamble;
 		changed |= BSS_CHANGED_ERP_PREAMBLE;
 	}
 
-	return changed;
-}
-
-static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
-				   u8 erp_value)
-{
-	bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
-	bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0;
-
-	return ieee80211_handle_protect_preamb(sdata,
-			use_protection, use_short_preamble);
-}
-
-static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
-					   struct ieee80211_bss *bss)
-{
-	u32 changed = 0;
-
-	if (bss->has_erp_value)
-		changed |= ieee80211_handle_erp_ie(sdata, bss->erp_value);
-	else {
-		u16 capab = bss->capability;
-		changed |= ieee80211_handle_protect_preamb(sdata, false,
-				(capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0);
+	if (use_short_slot != bss_conf->use_short_slot) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "%s: switched to %s slot"
+			       " (BSSID=%s)\n",
+			       sdata->dev->name,
+			       use_short_slot ? "short" : "long",
+			       ifsta->bssid);
+		}
+#endif
+		bss_conf->use_short_slot = use_short_slot;
+		changed |= BSS_CHANGED_ERP_SLOT;
 	}
 
 	return changed;
@@ -701,14 +699,15 @@
 
 
 static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
-				     struct ieee80211_if_sta *ifsta)
+				     struct ieee80211_if_sta *ifsta,
+				     u32 bss_info_changed)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_conf *conf = &local_to_hw(local)->conf;
-	u32 changed = BSS_CHANGED_ASSOC;
 
 	struct ieee80211_bss *bss;
 
+	bss_info_changed |= BSS_CHANGED_ASSOC;
 	ifsta->flags |= IEEE80211_STA_ASSOCIATED;
 
 	if (sdata->vif.type != NL80211_IFTYPE_STATION)
@@ -719,22 +718,16 @@
 				   ifsta->ssid, ifsta->ssid_len);
 	if (bss) {
 		/* set timing information */
-		sdata->bss_conf.beacon_int = bss->beacon_int;
-		sdata->bss_conf.timestamp = bss->timestamp;
-		sdata->bss_conf.dtim_period = bss->dtim_period;
+		sdata->vif.bss_conf.beacon_int = bss->beacon_int;
+		sdata->vif.bss_conf.timestamp = bss->timestamp;
+		sdata->vif.bss_conf.dtim_period = bss->dtim_period;
 
-		changed |= ieee80211_handle_bss_capability(sdata, bss);
+		bss_info_changed |= ieee80211_handle_bss_capability(sdata,
+			bss->capability, bss->has_erp_value, bss->erp_value);
 
 		ieee80211_rx_bss_put(local, bss);
 	}
 
-	if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
-		changed |= BSS_CHANGED_HT;
-		sdata->bss_conf.assoc_ht = 1;
-		sdata->bss_conf.ht_conf = &conf->ht_conf;
-		sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf;
-	}
-
 	ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
 	memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
 	ieee80211_sta_send_associnfo(sdata, ifsta);
@@ -742,14 +735,25 @@
 	ifsta->last_probe = jiffies;
 	ieee80211_led_assoc(local, 1);
 
-	sdata->bss_conf.assoc = 1;
+	sdata->vif.bss_conf.assoc = 1;
 	/*
 	 * For now just always ask the driver to update the basic rateset
 	 * when we have associated, we aren't checking whether it actually
 	 * changed or not.
 	 */
-	changed |= BSS_CHANGED_BASIC_RATES;
-	ieee80211_bss_info_change_notify(sdata, changed);
+	bss_info_changed |= BSS_CHANGED_BASIC_RATES;
+	ieee80211_bss_info_change_notify(sdata, bss_info_changed);
+
+	if (local->powersave) {
+		if (local->dynamic_ps_timeout > 0)
+			mod_timer(&local->dynamic_ps_timer, jiffies +
+				  msecs_to_jiffies(local->dynamic_ps_timeout));
+		else {
+			conf->flags |= IEEE80211_CONF_PS;
+			ieee80211_hw_config(local,
+					    IEEE80211_CONF_CHANGE_PS);
+		}
+	}
 
 	netif_tx_start_all_queues(sdata->dev);
 	netif_carrier_on(sdata->dev);
@@ -760,18 +764,17 @@
 static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
 				   struct ieee80211_if_sta *ifsta)
 {
-	DECLARE_MAC_BUF(mac);
-
 	ifsta->direct_probe_tries++;
 	if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {
-		printk(KERN_DEBUG "%s: direct probe to AP %s timed out\n",
-		       sdata->dev->name, print_mac(mac, ifsta->bssid));
+		printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
+		       sdata->dev->name, ifsta->bssid);
 		ifsta->state = IEEE80211_STA_MLME_DISABLED;
+		ieee80211_sta_send_apinfo(sdata, ifsta);
 		return;
 	}
 
-	printk(KERN_DEBUG "%s: direct probe to AP %s try %d\n",
-			sdata->dev->name, print_mac(mac, ifsta->bssid),
+	printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n",
+			sdata->dev->name, ifsta->bssid,
 			ifsta->direct_probe_tries);
 
 	ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
@@ -791,33 +794,36 @@
 static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
 				   struct ieee80211_if_sta *ifsta)
 {
-	DECLARE_MAC_BUF(mac);
-
 	ifsta->auth_tries++;
 	if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
-		printk(KERN_DEBUG "%s: authentication with AP %s"
+		printk(KERN_DEBUG "%s: authentication with AP %pM"
 		       " timed out\n",
-		       sdata->dev->name, print_mac(mac, ifsta->bssid));
+		       sdata->dev->name, ifsta->bssid);
 		ifsta->state = IEEE80211_STA_MLME_DISABLED;
+		ieee80211_sta_send_apinfo(sdata, ifsta);
 		return;
 	}
 
 	ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
-	printk(KERN_DEBUG "%s: authenticate with AP %s\n",
-	       sdata->dev->name, print_mac(mac, ifsta->bssid));
+	printk(KERN_DEBUG "%s: authenticate with AP %pM\n",
+	       sdata->dev->name, ifsta->bssid);
 
 	ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0);
 
 	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
 }
 
+/*
+ * The disassoc 'reason' argument can be either our own reason
+ * if self disconnected or a reason code from the AP.
+ */
 static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 				   struct ieee80211_if_sta *ifsta, bool deauth,
 				   bool self_disconnected, u16 reason)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
-	u32 changed = BSS_CHANGED_ASSOC;
+	u32 changed = 0, config_changed = 0;
 
 	rcu_read_lock();
 
@@ -851,21 +857,40 @@
 	ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
 	changed |= ieee80211_reset_erp_info(sdata);
 
-	if (sdata->bss_conf.assoc_ht)
-		changed |= BSS_CHANGED_HT;
-
-	sdata->bss_conf.assoc_ht = 0;
-	sdata->bss_conf.ht_conf = NULL;
-	sdata->bss_conf.ht_bss_conf = NULL;
-
 	ieee80211_led_assoc(local, 0);
-	sdata->bss_conf.assoc = 0;
+	changed |= BSS_CHANGED_ASSOC;
+	sdata->vif.bss_conf.assoc = false;
 
 	ieee80211_sta_send_apinfo(sdata, ifsta);
 
-	if (self_disconnected)
+	if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT)
 		ifsta->state = IEEE80211_STA_MLME_DISABLED;
 
+	rcu_read_unlock();
+
+	local->hw.conf.ht.enabled = false;
+	local->oper_channel_type = NL80211_CHAN_NO_HT;
+	config_changed |= IEEE80211_CONF_CHANGE_HT;
+
+	del_timer_sync(&local->dynamic_ps_timer);
+	cancel_work_sync(&local->dynamic_ps_enable_work);
+
+	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+		config_changed |= IEEE80211_CONF_CHANGE_PS;
+	}
+
+	ieee80211_hw_config(local, config_changed);
+	ieee80211_bss_info_change_notify(sdata, changed);
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, ifsta->bssid);
+	if (!sta) {
+		rcu_read_unlock();
+		return;
+	}
+
 	sta_info_unlink(&sta);
 
 	rcu_read_unlock();
@@ -914,20 +939,19 @@
 static void ieee80211_associate(struct ieee80211_sub_if_data *sdata,
 				struct ieee80211_if_sta *ifsta)
 {
-	DECLARE_MAC_BUF(mac);
-
 	ifsta->assoc_tries++;
 	if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
-		printk(KERN_DEBUG "%s: association with AP %s"
+		printk(KERN_DEBUG "%s: association with AP %pM"
 		       " timed out\n",
-		       sdata->dev->name, print_mac(mac, ifsta->bssid));
+		       sdata->dev->name, ifsta->bssid);
 		ifsta->state = IEEE80211_STA_MLME_DISABLED;
+		ieee80211_sta_send_apinfo(sdata, ifsta);
 		return;
 	}
 
 	ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;
-	printk(KERN_DEBUG "%s: associate with AP %s\n",
-	       sdata->dev->name, print_mac(mac, ifsta->bssid));
+	printk(KERN_DEBUG "%s: associate with AP %pM\n",
+	       sdata->dev->name, ifsta->bssid);
 	if (ieee80211_privacy_mismatch(sdata, ifsta)) {
 		printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
 		       "mixed-cell disabled - abort association\n", sdata->dev->name);
@@ -947,7 +971,6 @@
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	int disassoc;
-	DECLARE_MAC_BUF(mac);
 
 	/* TODO: start monitoring current AP signal quality and number of
 	 * missed beacons. Scan other channels every now and then and search
@@ -960,8 +983,8 @@
 
 	sta = sta_info_get(local, ifsta->bssid);
 	if (!sta) {
-		printk(KERN_DEBUG "%s: No STA entry for own AP %s\n",
-		       sdata->dev->name, print_mac(mac, ifsta->bssid));
+		printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n",
+		       sdata->dev->name, ifsta->bssid);
 		disassoc = 1;
 	} else {
 		disassoc = 0;
@@ -969,9 +992,9 @@
 			       sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
 			if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) {
 				printk(KERN_DEBUG "%s: No ProbeResp from "
-				       "current AP %s - assume out of "
+				       "current AP %pM - assume out of "
 				       "range\n",
-				       sdata->dev->name, print_mac(mac, ifsta->bssid));
+				       sdata->dev->name, ifsta->bssid);
 				disassoc = 1;
 			} else
 				ieee80211_send_probe_req(sdata, ifsta->bssid,
@@ -1032,7 +1055,6 @@
 				   size_t len)
 {
 	u16 auth_alg, auth_transaction, status_code;
-	DECLARE_MAC_BUF(mac);
 
 	if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
 	    sdata->vif.type != NL80211_IFTYPE_ADHOC)
@@ -1125,7 +1147,6 @@
 				     size_t len)
 {
 	u16 reason_code;
-	DECLARE_MAC_BUF(mac);
 
 	if (len < 24 + 2)
 		return;
@@ -1136,7 +1157,8 @@
 	reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
 	if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
-		printk(KERN_DEBUG "%s: deauthenticated\n", sdata->dev->name);
+		printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n",
+				sdata->dev->name, reason_code);
 
 	if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE ||
 	    ifsta->state == IEEE80211_STA_MLME_ASSOCIATE ||
@@ -1157,7 +1179,6 @@
 				       size_t len)
 {
 	u16 reason_code;
-	DECLARE_MAC_BUF(mac);
 
 	if (len < 24 + 2)
 		return;
@@ -1168,7 +1189,8 @@
 	reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
 	if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
-		printk(KERN_DEBUG "%s: disassociated\n", sdata->dev->name);
+		printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
+				sdata->dev->name, reason_code);
 
 	if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) {
 		ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;
@@ -1176,7 +1198,7 @@
 				      IEEE80211_RETRY_AUTH_INTERVAL);
 	}
 
-	ieee80211_set_disassoc(sdata, ifsta, false, false, 0);
+	ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code);
 }
 
 
@@ -1192,11 +1214,12 @@
 	u64 rates, basic_rates;
 	u16 capab_info, status_code, aid;
 	struct ieee802_11_elems elems;
-	struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
+	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
 	u8 *pos;
+	u32 changed = 0;
 	int i, j;
-	DECLARE_MAC_BUF(mac);
-	bool have_higher_than_11mbit = false;
+	bool have_higher_than_11mbit = false, newsta = false;
+	u16 ap_ht_cap_flags;
 
 	/* AssocResp and ReassocResp have identical structure, so process both
 	 * of them in this function. */
@@ -1214,9 +1237,9 @@
 	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
 	aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
 
-	printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x "
+	printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
 	       "status=%d aid=%d)\n",
-	       sdata->dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa),
+	       sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa,
 	       capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
 
 	if (status_code != WLAN_STATUS_SUCCESS) {
@@ -1259,7 +1282,8 @@
 	sta = sta_info_get(local, ifsta->bssid);
 	if (!sta) {
 		struct ieee80211_bss *bss;
-		int err;
+
+		newsta = true;
 
 		sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC);
 		if (!sta) {
@@ -1278,13 +1302,6 @@
 			ieee80211_rx_bss_put(local, bss);
 		}
 
-		err = sta_info_insert(sta);
-		if (err) {
-			printk(KERN_DEBUG "%s: failed to insert STA entry for"
-			       " the AP (error %d)\n", sdata->dev->name, err);
-			rcu_read_unlock();
-			return;
-		}
 		/* update new sta with its last rx activity */
 		sta->last_rx = jiffies;
 	}
@@ -1308,34 +1325,40 @@
 
 	for (i = 0; i < elems.supp_rates_len; i++) {
 		int rate = (elems.supp_rates[i] & 0x7f) * 5;
+		bool is_basic = !!(elems.supp_rates[i] & 0x80);
 
 		if (rate > 110)
 			have_higher_than_11mbit = true;
 
 		for (j = 0; j < sband->n_bitrates; j++) {
-			if (sband->bitrates[j].bitrate == rate)
+			if (sband->bitrates[j].bitrate == rate) {
 				rates |= BIT(j);
-			if (elems.supp_rates[i] & 0x80)
-				basic_rates |= BIT(j);
+				if (is_basic)
+					basic_rates |= BIT(j);
+				break;
+			}
 		}
 	}
 
 	for (i = 0; i < elems.ext_supp_rates_len; i++) {
 		int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
+		bool is_basic = !!(elems.supp_rates[i] & 0x80);
 
 		if (rate > 110)
 			have_higher_than_11mbit = true;
 
 		for (j = 0; j < sband->n_bitrates; j++) {
-			if (sband->bitrates[j].bitrate == rate)
+			if (sband->bitrates[j].bitrate == rate) {
 				rates |= BIT(j);
-			if (elems.ext_supp_rates[i] & 0x80)
-				basic_rates |= BIT(j);
+				if (is_basic)
+					basic_rates |= BIT(j);
+				break;
+			}
 		}
 	}
 
 	sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
-	sdata->bss_conf.basic_rates = basic_rates;
+	sdata->vif.bss_conf.basic_rates = basic_rates;
 
 	/* cf. IEEE 802.11 9.2.12 */
 	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
@@ -1344,31 +1367,43 @@
 	else
 		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
 
-	if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
-	    (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
-		struct ieee80211_ht_bss_info bss_info;
-		ieee80211_ht_cap_ie_to_ht_info(
-				elems.ht_cap_elem, &sta->sta.ht_info);
-		ieee80211_ht_addt_info_ie_to_ht_bss_info(
-				elems.ht_info_elem, &bss_info);
-		ieee80211_handle_ht(local, 1, &sta->sta.ht_info, &bss_info);
-	}
+	if (elems.ht_cap_elem)
+		ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
+				elems.ht_cap_elem, &sta->sta.ht_cap);
+
+	ap_ht_cap_flags = sta->sta.ht_cap.cap;
 
 	rate_control_rate_init(sta);
 
-	if (elems.wmm_param) {
+	if (elems.wmm_param)
 		set_sta_flags(sta, WLAN_STA_WME);
-		rcu_read_unlock();
+
+	if (newsta) {
+		int err = sta_info_insert(sta);
+		if (err) {
+			printk(KERN_DEBUG "%s: failed to insert STA entry for"
+			       " the AP (error %d)\n", sdata->dev->name, err);
+			rcu_read_unlock();
+			return;
+		}
+	}
+
+	rcu_read_unlock();
+
+	if (elems.wmm_param)
 		ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,
 					 elems.wmm_param_len);
-	} else
-		rcu_read_unlock();
+
+	if (elems.ht_info_elem && elems.wmm_param &&
+	    (ifsta->flags & IEEE80211_STA_WMM_ENABLED))
+		changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
+					       ap_ht_cap_flags);
 
 	/* set AID and assoc capability,
 	 * ieee80211_set_associated() will tell the driver */
 	bss_conf->aid = aid;
 	bss_conf->assoc_capability = capab_info;
-	ieee80211_set_associated(sdata, ifsta);
+	ieee80211_set_associated(sdata, ifsta, changed);
 
 	ieee80211_associated(sdata, ifsta);
 }
@@ -1386,6 +1421,13 @@
 	struct ieee80211_supported_band *sband;
 	union iwreq_data wrqu;
 
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
+		       "response\n", sdata->dev->name);
+		return -ENOMEM;
+	}
+
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
 	/* Remove possible STA entries from other IBSS networks. */
@@ -1411,63 +1453,62 @@
 		return res;
 
 	/* Build IBSS probe response */
-	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
-	if (skb) {
-		skb_reserve(skb, local->hw.extra_tx_headroom);
 
-		mgmt = (struct ieee80211_mgmt *)
-			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
-		memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
-		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-						  IEEE80211_STYPE_PROBE_RESP);
-		memset(mgmt->da, 0xff, ETH_ALEN);
-		memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-		mgmt->u.beacon.beacon_int =
-			cpu_to_le16(local->hw.conf.beacon_int);
-		mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp);
-		mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
+	skb_reserve(skb, local->hw.extra_tx_headroom);
 
-		pos = skb_put(skb, 2 + ifsta->ssid_len);
-		*pos++ = WLAN_EID_SSID;
-		*pos++ = ifsta->ssid_len;
-		memcpy(pos, ifsta->ssid, ifsta->ssid_len);
+	mgmt = (struct ieee80211_mgmt *)
+		skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+	memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+						IEEE80211_STYPE_PROBE_RESP);
+	memset(mgmt->da, 0xff, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+	mgmt->u.beacon.beacon_int =
+		cpu_to_le16(local->hw.conf.beacon_int);
+	mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp);
+	mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
 
-		rates = bss->supp_rates_len;
-		if (rates > 8)
-			rates = 8;
-		pos = skb_put(skb, 2 + rates);
-		*pos++ = WLAN_EID_SUPP_RATES;
-		*pos++ = rates;
-		memcpy(pos, bss->supp_rates, rates);
+	pos = skb_put(skb, 2 + ifsta->ssid_len);
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = ifsta->ssid_len;
+	memcpy(pos, ifsta->ssid, ifsta->ssid_len);
 
-		if (bss->band == IEEE80211_BAND_2GHZ) {
-			pos = skb_put(skb, 2 + 1);
-			*pos++ = WLAN_EID_DS_PARAMS;
-			*pos++ = 1;
-			*pos++ = ieee80211_frequency_to_channel(bss->freq);
-		}
+	rates = bss->supp_rates_len;
+	if (rates > 8)
+		rates = 8;
+	pos = skb_put(skb, 2 + rates);
+	*pos++ = WLAN_EID_SUPP_RATES;
+	*pos++ = rates;
+	memcpy(pos, bss->supp_rates, rates);
 
-		pos = skb_put(skb, 2 + 2);
-		*pos++ = WLAN_EID_IBSS_PARAMS;
-		*pos++ = 2;
-		/* FIX: set ATIM window based on scan results */
-		*pos++ = 0;
-		*pos++ = 0;
-
-		if (bss->supp_rates_len > 8) {
-			rates = bss->supp_rates_len - 8;
-			pos = skb_put(skb, 2 + rates);
-			*pos++ = WLAN_EID_EXT_SUPP_RATES;
-			*pos++ = rates;
-			memcpy(pos, &bss->supp_rates[8], rates);
-		}
-
-		ifsta->probe_resp = skb;
-
-		ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+	if (bss->band == IEEE80211_BAND_2GHZ) {
+		pos = skb_put(skb, 2 + 1);
+		*pos++ = WLAN_EID_DS_PARAMS;
+		*pos++ = 1;
+		*pos++ = ieee80211_frequency_to_channel(bss->freq);
 	}
 
+	pos = skb_put(skb, 2 + 2);
+	*pos++ = WLAN_EID_IBSS_PARAMS;
+	*pos++ = 2;
+	/* FIX: set ATIM window based on scan results */
+	*pos++ = 0;
+	*pos++ = 0;
+
+	if (bss->supp_rates_len > 8) {
+		rates = bss->supp_rates_len - 8;
+		pos = skb_put(skb, 2 + rates);
+		*pos++ = WLAN_EID_EXT_SUPP_RATES;
+		*pos++ = rates;
+		memcpy(pos, &bss->supp_rates[8], rates);
+	}
+
+	ifsta->probe_resp = skb;
+
+	ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+
+
 	rates = 0;
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 	for (i = 0; i < bss->supp_rates_len; i++) {
@@ -1507,8 +1548,6 @@
 	u64 beacon_timestamp, rx_timestamp;
 	u64 supp_rates = 0;
 	enum ieee80211_band band = rx_status->band;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
 
 	if (elems->ds_params && elems->ds_params_len == 1)
 		freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
@@ -1538,17 +1577,16 @@
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 			if (sta->sta.supp_rates[band] != prev_rates)
 				printk(KERN_DEBUG "%s: updated supp_rates set "
-				    "for %s based on beacon info (0x%llx | "
+				    "for %pM based on beacon info (0x%llx | "
 				    "0x%llx -> 0x%llx)\n",
 				    sdata->dev->name,
-				    print_mac(mac, sta->sta.addr),
+				    sta->sta.addr,
 				    (unsigned long long) prev_rates,
 				    (unsigned long long) supp_rates,
 				    (unsigned long long) sta->sta.supp_rates[band]);
 #endif
 		} else {
-			ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid,
-					       mgmt->sa, supp_rates);
+			ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
 		}
 
 		rcu_read_unlock();
@@ -1595,8 +1633,13 @@
 			 * e.g: at 1 MBit that means mactime is 192 usec earlier
 			 * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
 			 */
-			int rate = local->hw.wiphy->bands[band]->
+			int rate;
+			if (rx_status->flag & RX_FLAG_HT) {
+				rate = 65; /* TODO: HT rates */
+			} else {
+				rate = local->hw.wiphy->bands[band]->
 					bitrates[rx_status->rate_idx].bitrate;
+			}
 			rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
 		} else if (local && local->ops && local->ops->get_tsf)
 			/* second best option: get current TSF */
@@ -1605,10 +1648,9 @@
 			/* can't merge without knowing the TSF */
 			rx_timestamp = -1LLU;
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-		printk(KERN_DEBUG "RX beacon SA=%s BSSID="
-		       "%s TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
-		       print_mac(mac, mgmt->sa),
-		       print_mac(mac2, mgmt->bssid),
+		printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
+		       "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
+		       mgmt->sa, mgmt->bssid,
 		       (unsigned long long)rx_timestamp,
 		       (unsigned long long)beacon_timestamp,
 		       (unsigned long long)(rx_timestamp - beacon_timestamp),
@@ -1617,13 +1659,11 @@
 		if (beacon_timestamp > rx_timestamp) {
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 			printk(KERN_DEBUG "%s: beacon TSF higher than "
-			       "local TSF - IBSS merge with BSSID %s\n",
-			       sdata->dev->name, print_mac(mac, mgmt->bssid));
+			       "local TSF - IBSS merge with BSSID %pM\n",
+			       sdata->dev->name, mgmt->bssid);
 #endif
 			ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);
-			ieee80211_ibss_add_sta(sdata, NULL,
-					       mgmt->bssid, mgmt->sa,
-					       supp_rates);
+			ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
 		}
 	}
 
@@ -1671,8 +1711,9 @@
 	size_t baselen;
 	struct ieee802_11_elems elems;
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_conf *conf = &local->hw.conf;
 	u32 changed = 0;
+	bool erp_valid;
+	u8 erp_value = 0;
 
 	/* Process beacon from the current BSS */
 	baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
@@ -1694,22 +1735,49 @@
 	ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,
 				 elems.wmm_param_len);
 
-	if (elems.erp_info && elems.erp_info_len >= 1)
-		changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]);
-	else {
-		u16 capab = le16_to_cpu(mgmt->u.beacon.capab_info);
-		changed |= ieee80211_handle_protect_preamb(sdata, false,
-				(capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0);
+
+	if (elems.erp_info && elems.erp_info_len >= 1) {
+		erp_valid = true;
+		erp_value = elems.erp_info[0];
+	} else {
+		erp_valid = false;
+	}
+	changed |= ieee80211_handle_bss_capability(sdata,
+			le16_to_cpu(mgmt->u.beacon.capab_info),
+			erp_valid, erp_value);
+
+
+	if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) {
+		struct sta_info *sta;
+		struct ieee80211_supported_band *sband;
+		u16 ap_ht_cap_flags;
+
+		rcu_read_lock();
+
+		sta = sta_info_get(local, ifsta->bssid);
+		if (!sta) {
+			rcu_read_unlock();
+			return;
+		}
+
+		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+		ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
+				elems.ht_cap_elem, &sta->sta.ht_cap);
+
+		ap_ht_cap_flags = sta->sta.ht_cap.cap;
+
+		rcu_read_unlock();
+
+		changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
+					       ap_ht_cap_flags);
 	}
 
-	if (elems.ht_cap_elem && elems.ht_info_elem &&
-	    elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
-		struct ieee80211_ht_bss_info bss_info;
-
-		ieee80211_ht_addt_info_ie_to_ht_bss_info(
-				elems.ht_info_elem, &bss_info);
-		changed |= ieee80211_handle_ht(local, 1, &conf->ht_conf,
-					       &bss_info);
+	if (elems.country_elem) {
+		/* Note we are only reviewing this on beacons
+		 * for the BSSID we are associated to */
+		regulatory_hint_11d(local->hw.wiphy,
+			elems.country_elem, elems.country_elem_len);
 	}
 
 	ieee80211_bss_info_change_notify(sdata, changed);
@@ -1727,11 +1795,6 @@
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *resp;
 	u8 *pos, *end;
-	DECLARE_MAC_BUF(mac);
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-	DECLARE_MAC_BUF(mac2);
-	DECLARE_MAC_BUF(mac3);
-#endif
 
 	if (sdata->vif.type != NL80211_IFTYPE_ADHOC ||
 	    ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED ||
@@ -1744,10 +1807,10 @@
 		tx_last_beacon = 1;
 
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID="
-	       "%s (tx_last_beacon=%d)\n",
-	       sdata->dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da),
-	       print_mac(mac3, mgmt->bssid), tx_last_beacon);
+	printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
+	       " (tx_last_beacon=%d)\n",
+	       sdata->dev->name, mgmt->sa, mgmt->da,
+	       mgmt->bssid, tx_last_beacon);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
 	if (!tx_last_beacon)
@@ -1763,8 +1826,8 @@
 	    pos + 2 + pos[1] > end) {
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 		printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
-		       "from %s\n",
-		       sdata->dev->name, print_mac(mac, mgmt->sa));
+		       "from %pM\n",
+		       sdata->dev->name, mgmt->sa);
 #endif
 		return;
 	}
@@ -1783,8 +1846,8 @@
 	resp = (struct ieee80211_mgmt *) skb->data;
 	memcpy(resp->da, mgmt->sa, ETH_ALEN);
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-	printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n",
-	       sdata->dev->name, print_mac(mac, resp->da));
+	printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
+	       sdata->dev->name, resp->da);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 	ieee80211_tx_skb(sdata, skb, 0);
 }
@@ -1972,7 +2035,7 @@
 		}
 	}
 
-	if (hidden_ssid && ifsta->ssid_len == ssid_len)
+	if (hidden_ssid && (ifsta->ssid_len == ssid_len || ssid_len == 0))
 		return 1;
 
 	if (ssid_len == 1 && ssid[0] == ' ')
@@ -1990,7 +2053,6 @@
 	u8 bssid[ETH_ALEN], *pos;
 	int i;
 	int ret;
-	DECLARE_MAC_BUF(mac);
 
 #if 0
 	/* Easier testing, use fixed BSSID. */
@@ -2006,8 +2068,8 @@
 	bssid[0] |= 0x02;
 #endif
 
-	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n",
-	       sdata->dev->name, print_mac(mac, bssid));
+	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
+	       sdata->dev->name, bssid);
 
 	bss = ieee80211_rx_bss_add(local, bssid,
 				   local->hw.conf.channel->center_freq,
@@ -2050,8 +2112,6 @@
 	int found = 0;
 	u8 bssid[ETH_ALEN];
 	int active_ibss;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
 
 	if (ifsta->ssid_len == 0)
 		return -EINVAL;
@@ -2068,8 +2128,7 @@
 		    || !(bss->capability & WLAN_CAPABILITY_IBSS))
 			continue;
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-		printk(KERN_DEBUG "   bssid=%s found\n",
-		       print_mac(mac, bss->bssid));
+		printk(KERN_DEBUG "   bssid=%pM found\n", bss->bssid);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 		memcpy(bssid, bss->bssid, ETH_ALEN);
 		found = 1;
@@ -2080,9 +2139,8 @@
 
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 	if (found)
-		printk(KERN_DEBUG "   sta_find_ibss: selected %s current "
-		       "%s\n", print_mac(mac, bssid),
-		       print_mac(mac2, ifsta->bssid));
+		printk(KERN_DEBUG "   sta_find_ibss: selected %pM current "
+		       "%pM\n", bssid, ifsta->bssid);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
 	if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
@@ -2099,9 +2157,9 @@
 		if (!bss)
 			goto dont_join;
 
-		printk(KERN_DEBUG "%s: Selected IBSS BSSID %s"
+		printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
 		       " based on configured SSID\n",
-		       sdata->dev->name, print_mac(mac, bssid));
+		       sdata->dev->name, bssid);
 		ret = ieee80211_sta_join_ibss(sdata, ifsta, bss);
 		ieee80211_rx_bss_put(local, bss);
 		return ret;
@@ -2338,12 +2396,10 @@
  * must be callable in atomic context.
  */
 struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
-					struct sk_buff *skb, u8 *bssid,
-					u8 *addr, u64 supp_rates)
+					u8 *bssid,u8 *addr, u64 supp_rates)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
-	DECLARE_MAC_BUF(mac);
 	int band = local->hw.conf.channel->band;
 
 	/* TODO: Could consider removing the least recently used entry and
@@ -2351,7 +2407,7 @@
 	if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: No room for a new IBSS STA "
-			       "entry %s\n", sdata->dev->name, print_mac(mac, addr));
+			       "entry %pM\n", sdata->dev->name, addr);
 		}
 		return NULL;
 	}
@@ -2360,8 +2416,8 @@
 		return NULL;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mac, addr), sdata->dev->name);
+	printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n",
+	       wiphy_name(local->hw.wiphy), addr, sdata->dev->name);
 #endif
 
 	sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
@@ -2408,7 +2464,6 @@
 int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
 {
 	struct ieee80211_if_sta *ifsta;
-	int res;
 
 	if (len > IEEE80211_MAX_SSID_LEN)
 		return -EINVAL;
@@ -2420,19 +2475,6 @@
 		memcpy(ifsta->ssid, ssid, len);
 		ifsta->ssid_len = len;
 		ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-
-		res = 0;
-		/*
-		 * Hack! MLME code needs to be cleaned up to have different
-		 * entry points for configuration and internal selection change
-		 */
-		if (netif_running(sdata->dev))
-			res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
-		if (res) {
-			printk(KERN_DEBUG "%s: Failed to config new SSID to "
-			       "the low-level driver\n", sdata->dev->name);
-			return res;
-		}
 	}
 
 	if (len)
@@ -2560,3 +2602,39 @@
 		ieee80211_restart_sta_timer(sdata);
 	rcu_read_unlock();
 }
+
+void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
+{
+	struct ieee80211_local *local =
+		container_of(work, struct ieee80211_local,
+			     dynamic_ps_disable_work);
+
+	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+	}
+
+	ieee80211_wake_queues_by_reason(&local->hw,
+					IEEE80211_QUEUE_STOP_REASON_PS);
+}
+
+void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
+{
+	struct ieee80211_local *local =
+		container_of(work, struct ieee80211_local,
+			     dynamic_ps_enable_work);
+
+	if (local->hw.conf.flags & IEEE80211_CONF_PS)
+		return;
+
+	local->hw.conf.flags |= IEEE80211_CONF_PS;
+
+	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+}
+
+void ieee80211_dynamic_ps_timer(unsigned long data)
+{
+	struct ieee80211_local *local = (void *) data;
+
+	queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
+}
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 5d78672..3fa7ab2 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -199,48 +199,44 @@
 }
 
 void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
-			   struct ieee80211_supported_band *sband,
-			   struct sta_info *sta, struct sk_buff *skb,
-			   struct rate_selection *sel)
+			   struct sta_info *sta,
+			   struct ieee80211_tx_rate_control *txrc)
 {
 	struct rate_control_ref *ref = sdata->local->rate_ctrl;
 	void *priv_sta = NULL;
 	struct ieee80211_sta *ista = NULL;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
 	int i;
 
-	sel->rate_idx = -1;
-	sel->nonerp_idx = -1;
-	sel->probe_idx = -1;
-	sel->max_rate_idx = sdata->max_ratectrl_rateidx;
-
 	if (sta) {
 		ista = &sta->sta;
 		priv_sta = sta->rate_ctrl_priv;
 	}
 
-	if (sta && sdata->force_unicast_rateidx > -1)
-		sel->rate_idx = sdata->force_unicast_rateidx;
-	else
-		ref->ops->get_rate(ref->priv, sband, ista, priv_sta, skb, sel);
-
-	if (sdata->max_ratectrl_rateidx > -1 &&
-	    sel->rate_idx > sdata->max_ratectrl_rateidx)
-		sel->rate_idx = sdata->max_ratectrl_rateidx;
-
-	BUG_ON(sel->rate_idx < 0);
-
-	/* Select a non-ERP backup rate. */
-	if (sel->nonerp_idx < 0) {
-		for (i = 0; i < sband->n_bitrates; i++) {
-			struct ieee80211_rate *rate = &sband->bitrates[i];
-			if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
-				break;
-
-			if (rate_supported(ista, sband->band, i) &&
-			    !(rate->flags & IEEE80211_RATE_ERP_G))
-				sel->nonerp_idx = i;
-		}
+	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+		info->control.rates[i].idx = -1;
+		info->control.rates[i].flags = 0;
+		info->control.rates[i].count = 1;
 	}
+
+	if (sta && sdata->force_unicast_rateidx > -1)
+		info->control.rates[0].idx = sdata->force_unicast_rateidx;
+	else
+		ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
+
+	/*
+	 * try to enforce the maximum rate the user wanted
+	 */
+	if (sdata->max_ratectrl_rateidx > -1)
+		for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+			if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
+				continue;
+			info->control.rates[i].idx =
+				min_t(s8, info->control.rates[i].idx,
+				      sdata->max_ratectrl_rateidx);
+	}
+
+	BUG_ON(info->control.rates[0].idx < 0);
 }
 
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index d0092f8..928da62 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -31,9 +31,8 @@
 struct rate_control_ref *rate_control_alloc(const char *name,
 					    struct ieee80211_local *local);
 void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
-			   struct ieee80211_supported_band *sband,
-			   struct sta_info *sta, struct sk_buff *skb,
-			   struct rate_selection *sel);
+			   struct sta_info *sta,
+			   struct ieee80211_tx_rate_control *txrc);
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
 void rate_control_put(struct rate_control_ref *ref);
 
@@ -64,12 +63,6 @@
 }
 
 
-static inline void rate_control_clear(struct ieee80211_local *local)
-{
-	struct rate_control_ref *ref = local->rate_ctrl;
-	ref->ops->clear(ref->priv);
-}
-
 static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
 					   struct ieee80211_sta *sta,
 					   gfp_t gfp)
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index f6d69da..2b3b490 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -126,7 +126,9 @@
 			mr->adjusted_retry_count = mr->retry_count >> 1;
 			if (mr->adjusted_retry_count > 2)
 				mr->adjusted_retry_count = 2;
+			mr->sample_limit = 4;
 		} else {
+			mr->sample_limit = -1;
 			mr->adjusted_retry_count = mr->retry_count;
 		}
 		if (!mr->adjusted_retry_count)
@@ -169,30 +171,20 @@
 {
 	struct minstrel_sta_info *mi = priv_sta;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_tx_altrate *ar = info->status.retries;
-	struct minstrel_priv *mp = priv;
-	int i, ndx, tries;
-	int success = 0;
+	struct ieee80211_tx_rate *ar = info->status.rates;
+	int i, ndx;
+	int success;
 
-	if (!info->status.excessive_retries)
-		success = 1;
+	success = !!(info->flags & IEEE80211_TX_STAT_ACK);
 
-	if (!mp->has_mrr || (ar[0].rate_idx < 0)) {
-		ndx = rix_to_ndx(mi, info->tx_rate_idx);
-		tries = info->status.retry_count + 1;
-		mi->r[ndx].success += success;
-		mi->r[ndx].attempts += tries;
-		return;
-	}
-
-	for (i = 0; i < 4; i++) {
-		if (ar[i].rate_idx < 0)
+	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+		if (ar[i].idx < 0)
 			break;
 
-		ndx = rix_to_ndx(mi, ar[i].rate_idx);
-		mi->r[ndx].attempts += ar[i].limit + 1;
+		ndx = rix_to_ndx(mi, ar[i].idx);
+		mi->r[ndx].attempts += ar[i].count;
 
-		if ((i != 3) && (ar[i + 1].rate_idx < 0))
+		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
 			mi->r[ndx].success += success;
 	}
 
@@ -210,9 +202,9 @@
 {
 	unsigned int retry = mr->adjusted_retry_count;
 
-	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
 		retry = max(2U, min(mr->retry_count_rtscts, retry));
-	else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+	else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
 		retry = max(2U, min(mr->retry_count_cts, retry));
 	return retry;
 }
@@ -233,15 +225,16 @@
 	return sample_ndx;
 }
 
-void
-minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband,
-                  struct ieee80211_sta *sta, void *priv_sta,
-                  struct sk_buff *skb, struct rate_selection *sel)
+static void
+minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
+		  void *priv_sta, struct ieee80211_tx_rate_control *txrc)
 {
+	struct sk_buff *skb = txrc->skb;
+	struct ieee80211_supported_band *sband = txrc->sband;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct minstrel_sta_info *mi = priv_sta;
 	struct minstrel_priv *mp = priv;
-	struct ieee80211_tx_altrate *ar = info->control.retries;
+	struct ieee80211_tx_rate *ar = info->control.rates;
 	unsigned int ndx, sample_ndx = 0;
 	bool mrr;
 	bool sample_slower = false;
@@ -251,16 +244,12 @@
 	int sample_rate;
 
 	if (!sta || !mi || use_low_rate(skb)) {
-		sel->rate_idx = rate_lowest_index(sband, sta);
+		ar[0].idx = rate_lowest_index(sband, sta);
+		ar[0].count = mp->max_retry;
 		return;
 	}
 
-	mrr = mp->has_mrr;
-
-	/* mac80211 does not allow mrr for RTS/CTS */
-	if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
-	    (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
-		mrr = false;
+	mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot;
 
 	if (time_after(jiffies, mi->stats_update + (mp->update_interval *
 			HZ) / 1000))
@@ -278,7 +267,8 @@
 			(mi->sample_count + mi->sample_deferred / 2);
 
 	/* delta > 0: sampling required */
-	if (delta > 0) {
+	if ((delta > 0) && (mrr || !mi->prev_sample)) {
+		struct minstrel_rate *msr;
 		if (mi->packet_count >= 10000) {
 			mi->sample_deferred = 0;
 			mi->sample_count = 0;
@@ -297,13 +287,20 @@
 		}
 
 		sample_ndx = minstrel_get_next_sample(mi);
+		msr = &mi->r[sample_ndx];
 		sample = true;
-		sample_slower = mrr && (mi->r[sample_ndx].perfect_tx_time >
+		sample_slower = mrr && (msr->perfect_tx_time >
 			mi->r[ndx].perfect_tx_time);
 
 		if (!sample_slower) {
-			ndx = sample_ndx;
-			mi->sample_count++;
+			if (msr->sample_limit != 0) {
+				ndx = sample_ndx;
+				mi->sample_count++;
+				if (msr->sample_limit > 0)
+					msr->sample_limit--;
+			} else {
+				sample = false;
+			}
 		} else {
 			/* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
 			 * packets that have the sampling rate deferred to the
@@ -315,13 +312,22 @@
 			mi->sample_deferred++;
 		}
 	}
-	sel->rate_idx = mi->r[ndx].rix;
-	info->control.retry_limit = minstrel_get_retry_count(&mi->r[ndx], info);
+	mi->prev_sample = sample;
+
+	/* If we're not using MRR and the sampling rate already
+	 * has a probability of >95%, we shouldn't be attempting
+	 * to use it, as this only wastes precious airtime */
+	if (!mrr && sample && (mi->r[ndx].probability > 17100))
+		ndx = mi->max_tp_rate;
+
+	ar[0].idx = mi->r[ndx].rix;
+	ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info);
 
 	if (!mrr) {
-		ar[0].rate_idx = mi->lowest_rix;
-		ar[0].limit = mp->max_retry;
-		ar[1].rate_idx = -1;
+		if (!sample)
+			ar[0].count = mp->max_retry;
+		ar[1].idx = mi->lowest_rix;
+		ar[1].count = mp->max_retry;
 		return;
 	}
 
@@ -336,9 +342,9 @@
 	}
 	mrr_ndx[1] = mi->max_prob_rate;
 	mrr_ndx[2] = 0;
-	for (i = 0; i < 3; i++) {
-		ar[i].rate_idx = mi->r[mrr_ndx[i]].rix;
-		ar[i].limit = mi->r[mrr_ndx[i]].adjusted_retry_count;
+	for (i = 1; i < 4; i++) {
+		ar[i].idx = mi->r[mrr_ndx[i - 1]].rix;
+		ar[i].count = mi->r[mrr_ndx[i - 1]].adjusted_retry_count;
 	}
 }
 
@@ -415,6 +421,7 @@
 
 		/* calculate maximum number of retransmissions before
 		 * fallback (based on maximum segment size) */
+		mr->sample_limit = -1;
 		mr->retry_count = 1;
 		mr->retry_count_cts = 1;
 		mr->retry_count_rtscts = 1;
@@ -500,11 +507,6 @@
 	kfree(mi);
 }
 
-static void
-minstrel_clear(void *priv)
-{
-}
-
 static void *
 minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
 {
@@ -532,13 +534,13 @@
 	/* maximum time that the hw is allowed to stay in one MRR segment */
 	mp->segment_size = 6000;
 
-	if (hw->max_altrate_tries > 0)
-		mp->max_retry = hw->max_altrate_tries;
+	if (hw->max_rate_tries > 0)
+		mp->max_retry = hw->max_rate_tries;
 	else
 		/* safe default, does not necessarily have to match hw properties */
 		mp->max_retry = 7;
 
-	if (hw->max_altrates >= 3)
+	if (hw->max_rates >= 4)
 		mp->has_mrr = true;
 
 	mp->hw = hw;
@@ -558,7 +560,6 @@
 	.tx_status = minstrel_tx_status,
 	.get_rate = minstrel_get_rate,
 	.rate_init = minstrel_rate_init,
-	.clear = minstrel_clear,
 	.alloc = minstrel_alloc,
 	.free = minstrel_free,
 	.alloc_sta = minstrel_alloc_sta,
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 9a90a6a..869fe0e 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -16,6 +16,7 @@
 	unsigned int perfect_tx_time;
 	unsigned int ack_time;
 
+	int sample_limit;
 	unsigned int retry_count;
 	unsigned int retry_count_cts;
 	unsigned int retry_count_rtscts;
@@ -57,6 +58,7 @@
 
 	int n_rates;
 	struct minstrel_rate *r;
+	bool prev_sample;
 
 	/* sampling table */
 	u8 *sample_table;
diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h
index 01d64d5..1a873f0 100644
--- a/net/mac80211/rc80211_pid.h
+++ b/net/mac80211/rc80211_pid.h
@@ -49,7 +49,7 @@
 
 /* Arithmetic right shift for positive and negative values for ISO C. */
 #define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \
-	(x) < 0 ? -((-(x)) >> (y)) : (x) >> (y)
+	((x) < 0 ? -((-(x)) >> (y)) : (x) >> (y))
 
 enum rc_pid_event_type {
 	RC_PID_EVENT_TYPE_TX_STATUS,
@@ -61,6 +61,7 @@
 union rc_pid_event_data {
 	/* RC_PID_EVENT_TX_STATUS */
 	struct {
+		u32 flags;
 		struct ieee80211_tx_info tx_status;
 	};
 	/* RC_PID_EVENT_TYPE_RATE_CHANGE */
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index 86eb374..b16801c 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -241,7 +241,7 @@
 
 	/* Ignore all frames that were sent with a different rate than the rate
 	 * we currently advise mac80211 to use. */
-	if (info->tx_rate_idx != spinfo->txrate_idx)
+	if (info->status.rates[0].idx != spinfo->txrate_idx)
 		return;
 
 	spinfo->tx_num_xmit++;
@@ -253,10 +253,10 @@
 	/* We count frames that totally failed to be transmitted as two bad
 	 * frames, those that made it out but had some retries as one good and
 	 * one bad frame. */
-	if (info->status.excessive_retries) {
+	if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
 		spinfo->tx_num_failed += 2;
 		spinfo->tx_num_xmit++;
-	} else if (info->status.retry_count) {
+	} else if (info->status.rates[0].count > 1) {
 		spinfo->tx_num_failed++;
 		spinfo->tx_num_xmit++;
 	}
@@ -270,23 +270,32 @@
 }
 
 static void
-rate_control_pid_get_rate(void *priv, struct ieee80211_supported_band *sband,
-			  struct ieee80211_sta *sta, void *priv_sta,
-			  struct sk_buff *skb,
-			  struct rate_selection *sel)
+rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
+			  void *priv_sta,
+			  struct ieee80211_tx_rate_control *txrc)
 {
+	struct sk_buff *skb = txrc->skb;
+	struct ieee80211_supported_band *sband = txrc->sband;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct rc_pid_sta_info *spinfo = priv_sta;
 	int rateidx;
 	u16 fc;
 
+	if (txrc->rts)
+		info->control.rates[0].count =
+			txrc->hw->conf.long_frame_max_tx_count;
+	else
+		info->control.rates[0].count =
+			txrc->hw->conf.short_frame_max_tx_count;
+
 	/* Send management frames and broadcast/multicast data using lowest
 	 * rate. */
 	fc = le16_to_cpu(hdr->frame_control);
 	if (!sta || !spinfo ||
 	    (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
 	    is_multicast_ether_addr(hdr->addr1)) {
-		sel->rate_idx = rate_lowest_index(sband, sta);
+		info->control.rates[0].idx = rate_lowest_index(sband, sta);
 		return;
 	}
 
@@ -295,7 +304,7 @@
 	if (rateidx >= sband->n_bitrates)
 		rateidx = sband->n_bitrates - 1;
 
-	sel->rate_idx = rateidx;
+	info->control.rates[0].idx = rateidx;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
 	rate_control_pid_event_tx_rate(&spinfo->events,
@@ -394,11 +403,11 @@
 						 S_IRUSR | S_IWUSR, debugfsdir,
 						 &pinfo->sampling_period);
 	de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR,
-					 debugfsdir, &pinfo->coeff_p);
+					 debugfsdir, (u32 *)&pinfo->coeff_p);
 	de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR,
-					 debugfsdir, &pinfo->coeff_i);
+					 debugfsdir, (u32 *)&pinfo->coeff_i);
 	de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR,
-					 debugfsdir, &pinfo->coeff_d);
+					 debugfsdir, (u32 *)&pinfo->coeff_d);
 	de->smoothing_shift = debugfs_create_u32("smoothing_shift",
 						 S_IRUSR | S_IWUSR, debugfsdir,
 						 &pinfo->smoothing_shift);
@@ -437,10 +446,6 @@
 	kfree(pinfo);
 }
 
-static void rate_control_pid_clear(void *priv)
-{
-}
-
 static void *rate_control_pid_alloc_sta(void *priv, struct ieee80211_sta *sta,
 					gfp_t gfp)
 {
@@ -471,7 +476,6 @@
 	.tx_status = rate_control_pid_tx_status,
 	.get_rate = rate_control_pid_get_rate,
 	.rate_init = rate_control_pid_rate_init,
-	.clear = rate_control_pid_clear,
 	.alloc = rate_control_pid_alloc,
 	.free = rate_control_pid_free,
 	.alloc_sta = rate_control_pid_alloc_sta,
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c
index 8121d3b..a08a9b5 100644
--- a/net/mac80211/rc80211_pid_debugfs.c
+++ b/net/mac80211/rc80211_pid_debugfs.c
@@ -43,6 +43,7 @@
 {
 	union rc_pid_event_data evd;
 
+	evd.flags = stat->flags;
 	memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info));
 	rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
 }
@@ -167,8 +168,8 @@
 	switch (ev->type) {
 	case RC_PID_EVENT_TYPE_TX_STATUS:
 		p += snprintf(pb + p, length - p, "tx_status %u %u",
-			      ev->data.tx_status.status.excessive_retries,
-			      ev->data.tx_status.status.retry_count);
+			      !(ev->data.flags & IEEE80211_TX_STAT_ACK),
+			      ev->data.tx_status.status.rates[0].idx);
 		break;
 	case RC_PID_EVENT_TYPE_RATE_CHANGE:
 		p += snprintf(pb + p, length - p, "rate_change %d %d",
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index cf6b121..7175ae8 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -26,10 +26,11 @@
 #include "tkip.h"
 #include "wme.h"
 
-u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
-				struct tid_ampdu_rx *tid_agg_rx,
-				struct sk_buff *skb, u16 mpdu_seq_num,
-				int bar_req);
+static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+					   struct tid_ampdu_rx *tid_agg_rx,
+					   struct sk_buff *skb,
+					   u16 mpdu_seq_num,
+					   int bar_req);
 /*
  * monitor mode reception
  *
@@ -122,7 +123,6 @@
 	/* radiotap header, set always present flags */
 	rthdr->it_present =
 		cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
-			    (1 << IEEE80211_RADIOTAP_RATE) |
 			    (1 << IEEE80211_RADIOTAP_CHANNEL) |
 			    (1 << IEEE80211_RADIOTAP_ANTENNA) |
 			    (1 << IEEE80211_RADIOTAP_RX_FLAGS));
@@ -148,7 +148,19 @@
 	pos++;
 
 	/* IEEE80211_RADIOTAP_RATE */
-	*pos = rate->bitrate / 5;
+	if (status->flag & RX_FLAG_HT) {
+		/*
+		 * TODO: add following information into radiotap header once
+		 * suitable fields are defined for it:
+		 * - MCS index (status->rate_idx)
+		 * - HT40 (status->flag & RX_FLAG_40MHZ)
+		 * - short-GI (status->flag & RX_FLAG_SHORT_GI)
+		 */
+		*pos = 0;
+	} else {
+		rthdr->it_present |= (1 << IEEE80211_RADIOTAP_RATE);
+		*pos = rate->bitrate / 5;
+	}
 	pos++;
 
 	/* IEEE80211_RADIOTAP_CHANNEL */
@@ -653,13 +665,16 @@
 static void ap_sta_ps_start(struct sta_info *sta)
 {
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
-	DECLARE_MAC_BUF(mac);
+	struct ieee80211_local *local = sdata->local;
 
 	atomic_inc(&sdata->bss->num_sta_ps);
 	set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
+	if (local->ops->sta_notify)
+		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
+					STA_NOTIFY_SLEEP, &sta->sta);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-	printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
-	       sdata->dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid);
+	printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
+	       sdata->dev->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
@@ -669,38 +684,37 @@
 	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb;
 	int sent = 0;
-	struct ieee80211_tx_info *info;
-	DECLARE_MAC_BUF(mac);
 
 	atomic_dec(&sdata->bss->num_sta_ps);
 
 	clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
+	if (local->ops->sta_notify)
+		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
+					STA_NOTIFY_AWAKE, &sta->sta);
 
 	if (!skb_queue_empty(&sta->ps_tx_buf))
 		sta_info_clear_tim_bit(sta);
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-	printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n",
-	       sdata->dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid);
+	printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
+	       sdata->dev->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
 	/* Send all buffered frames to the station */
 	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
-		info = IEEE80211_SKB_CB(skb);
 		sent++;
-		info->flags |= IEEE80211_TX_CTL_REQUEUE;
+		skb->requeue = 1;
 		dev_queue_xmit(skb);
 	}
 	while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
-		info = IEEE80211_SKB_CB(skb);
 		local->total_ps_buffered--;
 		sent++;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "%s: STA %s aid %d send PS frame "
+		printk(KERN_DEBUG "%s: STA %pM aid %d send PS frame "
 		       "since STA not sleeping anymore\n", sdata->dev->name,
-		       print_mac(mac, sta->sta.addr), sta->sta.aid);
+		       sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-		info->flags |= IEEE80211_TX_CTL_REQUEUE;
+		skb->requeue = 1;
 		dev_queue_xmit(skb);
 	}
 
@@ -745,17 +759,29 @@
 	sta->last_qual = rx->status->qual;
 	sta->last_noise = rx->status->noise;
 
+	/*
+	 * Change STA power saving mode only at the end of a frame
+	 * exchange sequence.
+	 */
 	if (!ieee80211_has_morefrags(hdr->frame_control) &&
 	    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
 	     rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
-		/* Change STA power saving mode only in the end of a frame
-		 * exchange sequence */
-		if (test_sta_flags(sta, WLAN_STA_PS) &&
-		    !ieee80211_has_pm(hdr->frame_control))
-			rx->sent_ps_buffered += ap_sta_ps_end(sta);
-		else if (!test_sta_flags(sta, WLAN_STA_PS) &&
-			 ieee80211_has_pm(hdr->frame_control))
-			ap_sta_ps_start(sta);
+		if (test_sta_flags(sta, WLAN_STA_PS)) {
+			/*
+			 * Ignore doze->wake transitions that are
+			 * indicated by non-data frames, the standard
+			 * is unclear here, but for example going to
+			 * PS mode and then scanning would cause a
+			 * doze->wake transition for the probe request,
+			 * and that is clearly undesirable.
+			 */
+			if (ieee80211_is_data(hdr->frame_control) &&
+			    !ieee80211_has_pm(hdr->frame_control))
+				rx->sent_ps_buffered += ap_sta_ps_end(sta);
+		} else {
+			if (ieee80211_has_pm(hdr->frame_control))
+				ap_sta_ps_start(sta);
+		}
 	}
 
 	/* Drop data::nullfunc frames silently, since they are used only to
@@ -789,15 +815,12 @@
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 		struct ieee80211_hdr *hdr =
 			(struct ieee80211_hdr *) entry->skb_list.next->data;
-		DECLARE_MAC_BUF(mac);
-		DECLARE_MAC_BUF(mac2);
 		printk(KERN_DEBUG "%s: RX reassembly removed oldest "
 		       "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
-		       "addr1=%s addr2=%s\n",
+		       "addr1=%pM addr2=%pM\n",
 		       sdata->dev->name, idx,
 		       jiffies - entry->first_frag_time, entry->seq,
-		       entry->last_frag, print_mac(mac, hdr->addr1),
-		       print_mac(mac2, hdr->addr2));
+		       entry->last_frag, hdr->addr1, hdr->addr2);
 #endif
 		__skb_queue_purge(&entry->skb_list);
 	}
@@ -866,7 +889,6 @@
 	unsigned int frag, seq;
 	struct ieee80211_fragment_entry *entry;
 	struct sk_buff *skb;
-	DECLARE_MAC_BUF(mac);
 
 	hdr = (struct ieee80211_hdr *)rx->skb->data;
 	fc = hdr->frame_control;
@@ -970,7 +992,6 @@
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 	struct sk_buff *skb;
 	int no_pending_pkts;
-	DECLARE_MAC_BUF(mac);
 	__le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control;
 
 	if (likely(!rx->sta || !ieee80211_is_pspoll(fc) ||
@@ -1001,8 +1022,8 @@
 		set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
-		       print_mac(mac, rx->sta->sta.addr), rx->sta->sta.aid,
+		printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n",
+		       rx->sta->sta.addr, rx->sta->sta.aid,
 		       skb_queue_len(&rx->sta->ps_tx_buf));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
@@ -1025,9 +1046,9 @@
 		 *	  Should we send it a null-func frame indicating we
 		 *	  have nothing buffered for it?
 		 */
-		printk(KERN_DEBUG "%s: STA %s sent PS Poll even "
+		printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
 		       "though there are no buffered frames for it\n",
-		       rx->dev->name, print_mac(mac, rx->sta->sta.addr));
+		       rx->dev->name, rx->sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 	}
 
@@ -1097,10 +1118,6 @@
 	u8 src[ETH_ALEN] __aligned(2);
 	struct sk_buff *skb = rx->skb;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
-	DECLARE_MAC_BUF(mac3);
-	DECLARE_MAC_BUF(mac4);
 
 	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
 		return -1;
@@ -1279,7 +1296,6 @@
 	int remaining, err;
 	u8 dst[ETH_ALEN];
 	u8 src[ETH_ALEN];
-	DECLARE_MAC_BUF(mac);
 
 	if (unlikely(!ieee80211_is_data(fc)))
 		return RX_CONTINUE;
@@ -1552,14 +1568,6 @@
 	if (len < IEEE80211_MIN_ACTION_SIZE + 1)
 		return RX_DROP_MONITOR;
 
-	/*
-	 * FIXME: revisit this, I'm sure we should handle most
-	 *	  of these frames in other modes as well!
-	 */
-	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-	    sdata->vif.type != NL80211_IFTYPE_ADHOC)
-		return RX_CONTINUE;
-
 	switch (mgmt->u.action.category) {
 	case WLAN_CATEGORY_BACK:
 		switch (mgmt->u.action.u.addba_req.action_code) {
@@ -1632,8 +1640,6 @@
 {
 	int keyidx;
 	unsigned int hdrlen;
-	DECLARE_MAC_BUF(mac);
-	DECLARE_MAC_BUF(mac2);
 
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	if (rx->skb->len >= hdrlen + 4)
@@ -1854,10 +1860,15 @@
 			if (!(sdata->dev->flags & IFF_PROMISC))
 				return 0;
 			rx->flags &= ~IEEE80211_RX_RA_MATCH;
-		} else if (!rx->sta)
-			rx->sta = ieee80211_ibss_add_sta(sdata, rx->skb,
-						bssid, hdr->addr2,
-						BIT(rx->status->rate_idx));
+		} else if (!rx->sta) {
+			int rate_idx;
+			if (rx->status->flag & RX_FLAG_HT)
+				rate_idx = 0; /* TODO: HT rates */
+			else
+				rate_idx = rx->status->rate_idx;
+			rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2,
+				BIT(rate_idx));
+		}
 		break;
 	case NL80211_IFTYPE_MESH_POINT:
 		if (!multicast &&
@@ -2002,17 +2013,17 @@
 
 static inline int seq_less(u16 sq1, u16 sq2)
 {
-	return (((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1));
+	return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
 }
 
 static inline u16 seq_inc(u16 sq)
 {
-	return ((sq + 1) & SEQ_MASK);
+	return (sq + 1) & SEQ_MASK;
 }
 
 static inline u16 seq_sub(u16 sq1, u16 sq2)
 {
-	return ((sq1 - sq2) & SEQ_MASK);
+	return (sq1 - sq2) & SEQ_MASK;
 }
 
 
@@ -2020,10 +2031,11 @@
  * As it function blongs to Rx path it must be called with
  * the proper rcu_read_lock protection for its flow.
  */
-u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
-				struct tid_ampdu_rx *tid_agg_rx,
-				struct sk_buff *skb, u16 mpdu_seq_num,
-				int bar_req)
+static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+					   struct tid_ampdu_rx *tid_agg_rx,
+					   struct sk_buff *skb,
+					   u16 mpdu_seq_num,
+					   int bar_req)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_rx_status status;
@@ -2062,7 +2074,13 @@
 					tid_agg_rx->reorder_buf[index]->cb,
 					sizeof(status));
 				sband = local->hw.wiphy->bands[status.band];
-				rate = &sband->bitrates[status.rate_idx];
+				if (status.flag & RX_FLAG_HT) {
+					/* TODO: HT rates */
+					rate = sband->bitrates;
+				} else {
+					rate = &sband->bitrates
+						[status.rate_idx];
+				}
 				__ieee80211_rx_handle_packet(hw,
 					tid_agg_rx->reorder_buf[index],
 					&status, rate);
@@ -2106,7 +2124,10 @@
 		memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
 			sizeof(status));
 		sband = local->hw.wiphy->bands[status.band];
-		rate = &sband->bitrates[status.rate_idx];
+		if (status.flag & RX_FLAG_HT)
+			rate = sband->bitrates; /* TODO: HT rates */
+		else
+			rate = &sband->bitrates[status.rate_idx];
 		__ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
 					     &status, rate);
 		tid_agg_rx->stored_mpdu_num--;
@@ -2194,15 +2215,26 @@
 	}
 
 	sband = local->hw.wiphy->bands[status->band];
-
-	if (!sband ||
-	    status->rate_idx < 0 ||
-	    status->rate_idx >= sband->n_bitrates) {
+	if (!sband) {
 		WARN_ON(1);
 		return;
 	}
 
-	rate = &sband->bitrates[status->rate_idx];
+	if (status->flag & RX_FLAG_HT) {
+		/* rate_idx is MCS index */
+		if (WARN_ON(status->rate_idx < 0 ||
+			    status->rate_idx >= 76))
+			return;
+		/* HT rates are not in the table - use the highest legacy rate
+		 * for now since other parts of mac80211 may not yet be fully
+		 * MCS aware. */
+		rate = &sband->bitrates[sband->n_bitrates - 1];
+	} else {
+		if (WARN_ON(status->rate_idx < 0 ||
+			    status->rate_idx >= sband->n_bitrates))
+			return;
+		rate = &sband->bitrates[status->rate_idx];
+	}
 
 	/*
 	 * key references and virtual interfaces are protected using RCU
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 416bb41..f5c7c33 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -159,7 +159,7 @@
 {
 	struct ieee80211_bss *bss;
 
-	if (mesh_config_len != MESH_CFG_LEN)
+	if (mesh_config_len != IEEE80211_MESH_CONFIG_LEN)
 		return NULL;
 
 	bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
@@ -448,18 +448,17 @@
 
 	if (local->hw_scanning) {
 		local->hw_scanning = false;
-		if (ieee80211_hw_config(local))
-			printk(KERN_DEBUG "%s: failed to restore operational "
-			       "channel after scan\n", wiphy_name(local->hw.wiphy));
-
+		/*
+		 * Somebody might have requested channel change during scan
+		 * that we won't have acted upon, try now. ieee80211_hw_config
+		 * will set the flag based on actual changes.
+		 */
+		ieee80211_hw_config(local, 0);
 		goto done;
 	}
 
 	local->sw_scanning = false;
-	if (ieee80211_hw_config(local))
-		printk(KERN_DEBUG "%s: failed to restore operational "
-		       "channel after scan\n", wiphy_name(local->hw.wiphy));
-
+	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
 	netif_tx_lock_bh(local->mdev);
 	netif_addr_lock(local->mdev);
@@ -546,12 +545,9 @@
 
 		if (!skip) {
 			local->scan_channel = chan;
-			if (ieee80211_hw_config(local)) {
-				printk(KERN_DEBUG "%s: failed to set freq to "
-				       "%d MHz for scan\n", wiphy_name(local->hw.wiphy),
-				       chan->center_freq);
+			if (ieee80211_hw_config(local,
+						IEEE80211_CONF_CHANGE_CHANNEL))
 				skip = 1;
-			}
 		}
 
 		/* advance state machine to next channel/band */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index d254446..10c5539 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -137,14 +137,12 @@
 static void __sta_info_free(struct ieee80211_local *local,
 			    struct sta_info *sta)
 {
-	DECLARE_MAC_BUF(mbuf);
-
 	rate_control_free_sta(sta);
 	rate_control_put(sta->rate_ctrl);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: Destroyed STA %s\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->sta.addr));
+	printk(KERN_DEBUG "%s: Destroyed STA %pM\n",
+	       wiphy_name(local->hw.wiphy), sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 	kfree(sta);
@@ -222,7 +220,6 @@
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	int i;
-	DECLARE_MAC_BUF(mbuf);
 
 	sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
 	if (!sta)
@@ -263,8 +260,8 @@
 	skb_queue_head_init(&sta->tx_filtered);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: Allocated STA %s\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->sta.addr));
+	printk(KERN_DEBUG "%s: Allocated STA %pM\n",
+	       wiphy_name(local->hw.wiphy), sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 #ifdef CONFIG_MAC80211_MESH
@@ -281,7 +278,6 @@
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
 	unsigned long flags;
 	int err = 0;
-	DECLARE_MAC_BUF(mac);
 
 	/*
 	 * Can't be a WARN_ON because it can be triggered through a race:
@@ -294,7 +290,7 @@
 	}
 
 	if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->dev->dev_addr) == 0 ||
-	            is_multicast_ether_addr(sta->sta.addr))) {
+		    is_multicast_ether_addr(sta->sta.addr))) {
 		err = -EINVAL;
 		goto out_free;
 	}
@@ -322,8 +318,8 @@
 	}
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: Inserted STA %s\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mac, sta->sta.addr));
+	printk(KERN_DEBUG "%s: Inserted STA %pM\n",
+	       wiphy_name(local->hw.wiphy), sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 	spin_unlock_irqrestore(&local->sta_lock, flags);
@@ -423,9 +419,6 @@
 {
 	struct ieee80211_local *local = (*sta)->local;
 	struct ieee80211_sub_if_data *sdata = (*sta)->sdata;
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	DECLARE_MAC_BUF(mbuf);
-#endif
 	/*
 	 * pull caller's reference if we're already gone.
 	 */
@@ -468,8 +461,8 @@
 	}
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: Removed STA %s\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->sta.addr));
+	printk(KERN_DEBUG "%s: Removed STA %pM\n",
+	       wiphy_name(local->hw.wiphy), (*sta)->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 	/*
@@ -544,7 +537,6 @@
 	unsigned long flags;
 	struct sk_buff *skb;
 	struct ieee80211_sub_if_data *sdata;
-	DECLARE_MAC_BUF(mac);
 
 	if (skb_queue_empty(&sta->ps_tx_buf))
 		return;
@@ -564,8 +556,8 @@
 		sdata = sta->sdata;
 		local->total_ps_buffered--;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "Buffered frame expired (STA "
-		       "%s)\n", print_mac(mac, sta->sta.addr));
+		printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n",
+		       sta->sta.addr);
 #endif
 		dev_kfree_skb(skb);
 
@@ -809,15 +801,14 @@
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta, *tmp;
 	LIST_HEAD(tmp_list);
-	DECLARE_MAC_BUF(mac);
 	unsigned long flags;
 
 	spin_lock_irqsave(&local->sta_lock, flags);
 	list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
 		if (time_after(jiffies, sta->last_rx + exp_time)) {
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-			printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
-			       sdata->dev->name, print_mac(mac, sta->sta.addr));
+			printk(KERN_DEBUG "%s: expiring inactive STA %pM\n",
+			       sdata->dev->name, sta->sta.addr);
 #endif
 			__sta_info_unlink(&sta);
 			if (sta)
@@ -830,7 +821,7 @@
 }
 
 struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
-                                         const u8 *addr)
+					 const u8 *addr)
 {
 	struct sta_info *sta = sta_info_get(hw_to_local(hw), addr);
 
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 168a39a..dc2606d 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -160,18 +160,17 @@
  * @list: global linked list entry
  * @hnext: hash table linked list pointer
  * @local: pointer to the global information
- * @sdata: TBD
- * @key: TBD
- * @rate_ctrl: TBD
- * @rate_ctrl_priv: TBD
+ * @sdata: virtual interface this station belongs to
+ * @key: peer key negotiated with this station, if any
+ * @rate_ctrl: rate control algorithm reference
+ * @rate_ctrl_priv: rate control private per-STA pointer
+ * @last_tx_rate: rate used for last transmit, to report to userspace as
+ *	"the" transmit rate
  * @lock: used for locking all fields that require locking, see comments
  *	in the header file.
  * @flaglock: spinlock for flags accesses
- * @addr: MAC address of this STA
- * @aid: STA's unique AID (1..2007, 0 = not assigned yet),
- *	only used in AP (and IBSS?) mode
- * @listen_interval: TBD
- * @pin_status: TBD
+ * @listen_interval: listen interval of this station, when we're acting as AP
+ * @pin_status: used internally for pinning a STA struct into memory
  * @flags: STA flags, see &enum ieee80211_sta_info_flags
  * @ps_tx_buf: buffer of frames to transmit to this station
  *	when it leaves power saving state
@@ -180,8 +179,8 @@
  *	power saving state
  * @rx_packets: Number of MSDUs received from this STA
  * @rx_bytes: Number of bytes received from this STA
- * @wep_weak_iv_count: TBD
- * @last_rx: TBD
+ * @wep_weak_iv_count: number of weak WEP IVs received from this station
+ * @last_rx: time (in jiffies) when last frame was received from this STA
  * @num_duplicates: number of duplicate frames received from this STA
  * @rx_fragments: number of received MPDUs
  * @rx_dropped: number of dropped MPDUs from this STA
@@ -189,26 +188,26 @@
  * @last_qual: qual of last received frame from this STA
  * @last_noise: noise of last received frame from this STA
  * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue)
- * @tx_filtered_count: TBD
- * @tx_retry_failed: TBD
- * @tx_retry_count: TBD
+ * @tx_filtered_count: number of frames the hardware filtered for this STA
+ * @tx_retry_failed: number of frames that failed retry
+ * @tx_retry_count: total number of retries for frames to this STA
  * @fail_avg: moving percentage of failed MSDUs
  * @tx_packets: number of RX/TX MSDUs
- * @tx_bytes: TBD
+ * @tx_bytes: number of bytes transmitted to this STA
  * @tx_fragments: number of transmitted MPDUs
- * @last_txrate_idx: Index of the last used transmit rate
- * @tid_seq: TBD
- * @ampdu_mlme: TBD
+ * @last_txrate: description of the last used transmit rate
+ * @tid_seq: per-TID sequence numbers for sending to this STA
+ * @ampdu_mlme: A-MPDU state machine state
  * @timer_to_tid: identity mapping to ID timers
  * @tid_to_tx_q: map tid to tx queue
  * @llid: Local link ID
  * @plid: Peer link ID
  * @reason: Cancel reason on PLINK_HOLDING state
  * @plink_retries: Retries in establishment
- * @ignore_plink_timer: TBD
- * @plink_state plink_state: TBD
- * @plink_timeout: TBD
- * @plink_timer: TBD
+ * @ignore_plink_timer: ignore the peer-link timer (used internally)
+ * @plink_state: peer link state
+ * @plink_timeout: timeout of peer link
+ * @plink_timer: peer link watch timer
  * @debugfs: debug filesystem info
  * @sta: station information we share with the driver
  */
@@ -267,7 +266,7 @@
 	unsigned long tx_packets;
 	unsigned long tx_bytes;
 	unsigned long tx_fragments;
-	unsigned int last_txrate_idx;
+	struct ieee80211_tx_rate last_tx_rate;
 	u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
 
 	/*
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 34b32bc..38fa111 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -263,10 +263,9 @@
 	     (iv32 == key->u.tkip.rx[queue].iv32 &&
 	      iv16 <= key->u.tkip.rx[queue].iv16))) {
 #ifdef CONFIG_MAC80211_TKIP_DEBUG
-		DECLARE_MAC_BUF(mac);
 		printk(KERN_DEBUG "TKIP replay detected for RX frame from "
-		       "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
-		       print_mac(mac, ta),
+		       "%pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
+		       ta,
 		       iv32, iv16, key->u.tkip.rx[queue].iv32,
 		       key->u.tkip.rx[queue].iv16);
 #endif
@@ -287,9 +286,8 @@
 		{
 			int i;
 			u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY;
-			DECLARE_MAC_BUF(mac);
-			printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s"
-			       " TK=", print_mac(mac, ta));
+			printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%pM"
+			       " TK=", ta);
 			for (i = 0; i < 16; i++)
 				printk("%02x ",
 				       key->conf.key[key_offset + i]);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1460537..a4af3a124 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -46,13 +46,20 @@
 	struct ieee80211_local *local = tx->local;
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_hdr *hdr;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
+	/* assume HW handles this */
+	if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
+		return 0;
+
+	/* uh huh? */
+	if (WARN_ON_ONCE(info->control.rates[0].idx < 0))
+		return 0;
 
 	sband = local->hw.wiphy->bands[tx->channel->band];
-	txrate = &sband->bitrates[tx->rate_idx];
+	txrate = &sband->bitrates[info->control.rates[0].idx];
 
-	erp = 0;
-	if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
-		erp = txrate->flags & IEEE80211_RATE_ERP_G;
+	erp = txrate->flags & IEEE80211_RATE_ERP_G;
 
 	/*
 	 * data and mgmt (except PS Poll):
@@ -116,7 +123,7 @@
 		if (r->bitrate > txrate->bitrate)
 			break;
 
-		if (tx->sdata->bss_conf.basic_rates & BIT(i))
+		if (tx->sdata->vif.bss_conf.basic_rates & BIT(i))
 			rate = r->bitrate;
 
 		switch (sband->band) {
@@ -150,7 +157,7 @@
 	 * to closest integer */
 
 	dur = ieee80211_frame_duration(local, 10, rate, erp,
-				tx->sdata->bss_conf.use_short_preamble);
+				tx->sdata->vif.bss_conf.use_short_preamble);
 
 	if (next_frag_len) {
 		/* Frame is fragmented: duration increases with time needed to
@@ -159,7 +166,7 @@
 		/* next fragment */
 		dur += ieee80211_frame_duration(local, next_frag_len,
 				txrate->bitrate, erp,
-				tx->sdata->bss_conf.use_short_preamble);
+				tx->sdata->vif.bss_conf.use_short_preamble);
 	}
 
 	return cpu_to_le16(dur);
@@ -201,10 +208,9 @@
 			     tx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
 			     ieee80211_is_data(hdr->frame_control))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-			DECLARE_MAC_BUF(mac);
 			printk(KERN_DEBUG "%s: dropped data frame to not "
-			       "associated station %s\n",
-			       tx->dev->name, print_mac(mac, hdr->addr1));
+			       "associated station %pM\n",
+			       tx->dev->name, hdr->addr1);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 			I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
 			return TX_DROP;
@@ -331,7 +337,6 @@
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 	u32 staflags;
-	DECLARE_MAC_BUF(mac);
 
 	if (unlikely(!sta || ieee80211_is_probe_resp(hdr->frame_control)))
 		return TX_CONTINUE;
@@ -341,9 +346,9 @@
 	if (unlikely((staflags & WLAN_STA_PS) &&
 		     !(staflags & WLAN_STA_PSPOLL))) {
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-		printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
+		printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries "
 		       "before %d)\n",
-		       print_mac(mac, sta->sta.addr), sta->sta.aid,
+		       sta->sta.addr, sta->sta.aid,
 		       skb_queue_len(&sta->ps_tx_buf));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
@@ -352,9 +357,9 @@
 			struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 			if (net_ratelimit()) {
-				printk(KERN_DEBUG "%s: STA %s TX "
+				printk(KERN_DEBUG "%s: STA %pM TX "
 				       "buffer full - dropping oldest frame\n",
-				       tx->dev->name, print_mac(mac, sta->sta.addr));
+				       tx->dev->name, sta->sta.addr);
 			}
 #endif
 			dev_kfree_skb(old);
@@ -371,9 +376,9 @@
 	}
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) {
-		printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll "
+		printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll "
 		       "set -> send frame\n", tx->dev->name,
-		       print_mac(mac, sta->sta.addr));
+		       sta->sta.addr);
 	}
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 	clear_sta_flags(sta, WLAN_STA_PSPOLL);
@@ -439,47 +444,145 @@
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 {
-	struct rate_selection rsel;
-	struct ieee80211_supported_band *sband;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+	struct ieee80211_hdr *hdr = (void *)tx->skb->data;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_rate *rate;
+	int i, len;
+	bool inval = false, rts = false, short_preamble = false;
+	struct ieee80211_tx_rate_control txrc;
+
+	memset(&txrc, 0, sizeof(txrc));
 
 	sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
-	if (likely(tx->rate_idx < 0)) {
-		rate_control_get_rate(tx->sdata, sband, tx->sta,
-				      tx->skb, &rsel);
-		if (tx->sta)
-			tx->sta->last_txrate_idx = rsel.rate_idx;
-		tx->rate_idx = rsel.rate_idx;
-		if (unlikely(rsel.probe_idx >= 0)) {
-			info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
-			tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
-			info->control.retries[0].rate_idx = tx->rate_idx;
-			info->control.retries[0].limit = tx->local->hw.max_altrate_tries;
-			tx->rate_idx = rsel.probe_idx;
-		} else if (info->control.retries[0].limit == 0)
-			info->control.retries[0].rate_idx = -1;
+	len = min_t(int, tx->skb->len + FCS_LEN,
+			 tx->local->fragmentation_threshold);
 
-		if (unlikely(tx->rate_idx < 0))
-			return TX_DROP;
-	} else
-		info->control.retries[0].rate_idx = -1;
+	/* set up the tx rate control struct we give the RC algo */
+	txrc.hw = local_to_hw(tx->local);
+	txrc.sband = sband;
+	txrc.bss_conf = &tx->sdata->vif.bss_conf;
+	txrc.skb = tx->skb;
+	txrc.reported_rate.idx = -1;
+	txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx;
 
-	if (tx->sdata->bss_conf.use_cts_prot &&
-	    (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) {
-		tx->last_frag_rate_idx = tx->rate_idx;
-		if (rsel.probe_idx >= 0)
-			tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
-		else
-			tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
-		tx->rate_idx = rsel.nonerp_idx;
-		info->tx_rate_idx = rsel.nonerp_idx;
-		info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
-	} else {
-		tx->last_frag_rate_idx = tx->rate_idx;
-		info->tx_rate_idx = tx->rate_idx;
+	/* set up RTS protection if desired */
+	if (tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD &&
+	    len > tx->local->rts_threshold) {
+		txrc.rts = rts = true;
 	}
-	info->tx_rate_idx = tx->rate_idx;
+
+	/*
+	 * Use short preamble if the BSS can handle it, but not for
+	 * management frames unless we know the receiver can handle
+	 * that -- the management frame might be to a station that
+	 * just wants a probe response.
+	 */
+	if (tx->sdata->vif.bss_conf.use_short_preamble &&
+	    (ieee80211_is_data(hdr->frame_control) ||
+	     (tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
+		txrc.short_preamble = short_preamble = true;
+
+
+	rate_control_get_rate(tx->sdata, tx->sta, &txrc);
+
+	if (unlikely(info->control.rates[0].idx < 0))
+		return TX_DROP;
+
+	if (txrc.reported_rate.idx < 0)
+		txrc.reported_rate = info->control.rates[0];
+
+	if (tx->sta)
+		tx->sta->last_tx_rate = txrc.reported_rate;
+
+	if (unlikely(!info->control.rates[0].count))
+		info->control.rates[0].count = 1;
+
+	if (is_multicast_ether_addr(hdr->addr1)) {
+		/*
+		 * XXX: verify the rate is in the basic rateset
+		 */
+		return TX_CONTINUE;
+	}
+
+	/*
+	 * set up the RTS/CTS rate as the fastest basic rate
+	 * that is not faster than the data rate
+	 *
+	 * XXX: Should this check all retry rates?
+	 */
+	if (!(info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) {
+		s8 baserate = 0;
+
+		rate = &sband->bitrates[info->control.rates[0].idx];
+
+		for (i = 0; i < sband->n_bitrates; i++) {
+			/* must be a basic rate */
+			if (!(tx->sdata->vif.bss_conf.basic_rates & BIT(i)))
+				continue;
+			/* must not be faster than the data rate */
+			if (sband->bitrates[i].bitrate > rate->bitrate)
+				continue;
+			/* maximum */
+			if (sband->bitrates[baserate].bitrate <
+			     sband->bitrates[i].bitrate)
+				baserate = i;
+		}
+
+		info->control.rts_cts_rate_idx = baserate;
+	}
+
+	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+		/*
+		 * make sure there's no valid rate following
+		 * an invalid one, just in case drivers don't
+		 * take the API seriously to stop at -1.
+		 */
+		if (inval) {
+			info->control.rates[i].idx = -1;
+			continue;
+		}
+		if (info->control.rates[i].idx < 0) {
+			inval = true;
+			continue;
+		}
+
+		/*
+		 * For now assume MCS is already set up correctly, this
+		 * needs to be fixed.
+		 */
+		if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) {
+			WARN_ON(info->control.rates[i].idx > 76);
+			continue;
+		}
+
+		/* set up RTS protection if desired */
+		if (rts)
+			info->control.rates[i].flags |=
+				IEEE80211_TX_RC_USE_RTS_CTS;
+
+		/* RC is busted */
+		if (WARN_ON_ONCE(info->control.rates[i].idx >=
+				 sband->n_bitrates)) {
+			info->control.rates[i].idx = -1;
+			continue;
+		}
+
+		rate = &sband->bitrates[info->control.rates[i].idx];
+
+		/* set up short preamble */
+		if (short_preamble &&
+		    rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+			info->control.rates[i].flags |=
+				IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
+
+		/* set up G protection */
+		if (!rts && tx->sdata->vif.bss_conf.use_cts_prot &&
+		    rate->flags & IEEE80211_RATE_ERP_G)
+			info->control.rates[i].flags |=
+				IEEE80211_TX_RC_USE_CTS_PROTECT;
+	}
 
 	return TX_CONTINUE;
 }
@@ -487,91 +590,7 @@
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
-	struct ieee80211_supported_band *sband;
-
-	sband = tx->local->hw.wiphy->bands[tx->channel->band];
-
-	if (tx->sta)
-		info->control.sta = &tx->sta->sta;
-
-	if (!info->control.retry_limit) {
-		if (!is_multicast_ether_addr(hdr->addr1)) {
-			int len = min_t(int, tx->skb->len + FCS_LEN,
-					tx->local->fragmentation_threshold);
-			if (len > tx->local->rts_threshold
-			    && tx->local->rts_threshold <
-						IEEE80211_MAX_RTS_THRESHOLD) {
-				info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS;
-				info->flags |=
-					IEEE80211_TX_CTL_LONG_RETRY_LIMIT;
-				info->control.retry_limit =
-					tx->local->long_retry_limit;
-			} else {
-				info->control.retry_limit =
-					tx->local->short_retry_limit;
-			}
-		} else {
-			info->control.retry_limit = 1;
-		}
-	}
-
-	if (tx->flags & IEEE80211_TX_FRAGMENTED) {
-		/* Do not use multiple retry rates when sending fragmented
-		 * frames.
-		 * TODO: The last fragment could still use multiple retry
-		 * rates. */
-		info->control.retries[0].rate_idx = -1;
-	}
-
-	/* Use CTS protection for unicast frames sent using extended rates if
-	 * there are associated non-ERP stations and RTS/CTS is not configured
-	 * for the frame. */
-	if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
-	    (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) &&
-	    (tx->flags & IEEE80211_TX_UNICAST) &&
-	    tx->sdata->bss_conf.use_cts_prot &&
-	    !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS))
-		info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT;
-
-	/* Transmit data frames using short preambles if the driver supports
-	 * short preambles at the selected rate and short preambles are
-	 * available on the network at the current point in time. */
-	if (ieee80211_is_data(hdr->frame_control) &&
-	    (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
-	    tx->sdata->bss_conf.use_short_preamble &&
-	    (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
-		info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
-	}
-
-	if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
-	    (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
-		struct ieee80211_rate *rate;
-		s8 baserate = -1;
-		int idx;
-
-		/* Do not use multiple retry rates when using RTS/CTS */
-		info->control.retries[0].rate_idx = -1;
-
-		/* Use min(data rate, max base rate) as CTS/RTS rate */
-		rate = &sband->bitrates[tx->rate_idx];
-
-		for (idx = 0; idx < sband->n_bitrates; idx++) {
-			if (sband->bitrates[idx].bitrate > rate->bitrate)
-				continue;
-			if (tx->sdata->bss_conf.basic_rates & BIT(idx) &&
-			    (baserate < 0 ||
-			     (sband->bitrates[baserate].bitrate
-			      < sband->bitrates[idx].bitrate)))
-				baserate = idx;
-		}
-
-		if (baserate >= 0)
-			info->control.rts_cts_rate_idx = baserate;
-		else
-			info->control.rts_cts_rate_idx = 0;
-	}
 
 	if (tx->sta)
 		info->control.sta = &tx->sta->sta;
@@ -602,8 +621,18 @@
 	if (ieee80211_hdrlen(hdr->frame_control) < 24)
 		return TX_CONTINUE;
 
+	/*
+	 * Anything but QoS data that has a sequence number field
+	 * (is long enough) gets a sequence number from the global
+	 * counter.
+	 */
 	if (!ieee80211_is_data_qos(hdr->frame_control)) {
+		/* driver should assign sequence number */
 		info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
+		/* for pure STA mode without beacons, we can do it */
+		hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number);
+		tx->sdata->sequence_number += 0x10;
+		tx->sdata->sequence_number &= IEEE80211_SCTL_SEQ;
 		return TX_CONTINUE;
 	}
 
@@ -632,6 +661,7 @@
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 {
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 	size_t hdrlen, per_fragm, num_fragm, payload_len, left;
 	struct sk_buff **frags, *first, *frag;
@@ -648,9 +678,7 @@
 	 * This scenario is handled in __ieee80211_tx_prepare but extra
 	 * caution taken here as fragmented ampdu may cause Tx stop.
 	 */
-	if (WARN_ON(tx->flags & IEEE80211_TX_CTL_AMPDU ||
-		    skb_get_queue_mapping(tx->skb) >=
-			ieee80211_num_regular_queues(&tx->local->hw)))
+	if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
 		return TX_DROP;
 
 	first = tx->skb;
@@ -684,20 +712,45 @@
 				      IEEE80211_ENCRYPT_TAILROOM);
 		if (!frag)
 			goto fail;
+
 		/* Make sure that all fragments use the same priority so
 		 * that they end up using the same TX queue */
 		frag->priority = first->priority;
+
 		skb_reserve(frag, tx->local->tx_headroom +
 				  IEEE80211_ENCRYPT_HEADROOM);
+
+		/* copy TX information */
+		info = IEEE80211_SKB_CB(frag);
+		memcpy(info, first->cb, sizeof(frag->cb));
+
+		/* copy/fill in 802.11 header */
 		fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
 		memcpy(fhdr, first->data, hdrlen);
-		if (i == num_fragm - 2)
-			fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
 		fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
+
+		if (i == num_fragm - 2) {
+			/* clear MOREFRAGS bit for the last fragment */
+			fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
+		} else {
+			/*
+			 * No multi-rate retries for fragmented frames, that
+			 * would completely throw off the NAV at other STAs.
+			 */
+			info->control.rates[1].idx = -1;
+			info->control.rates[2].idx = -1;
+			info->control.rates[3].idx = -1;
+			info->control.rates[4].idx = -1;
+			BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5);
+			info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+		}
+
+		/* copy data */
 		copylen = left > per_fragm ? per_fragm : left;
 		memcpy(skb_put(frag, copylen), pos, copylen);
-		memcpy(frag->cb, first->cb, sizeof(frag->cb));
+
 		skb_copy_queue_mapping(frag, first);
+
 		frag->do_not_encrypt = first->do_not_encrypt;
 
 		pos += copylen;
@@ -757,12 +810,10 @@
 					      tx->extra_frag[0]->len);
 
 	for (i = 0; i < tx->num_extra_frag; i++) {
-		if (i + 1 < tx->num_extra_frag) {
+		if (i + 1 < tx->num_extra_frag)
 			next_len = tx->extra_frag[i + 1]->len;
-		} else {
+		else
 			next_len = 0;
-			tx->rate_idx = tx->last_frag_rate_idx;
-		}
 
 		hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data;
 		hdr->duration_id = ieee80211_duration(tx, 0, next_len);
@@ -815,7 +866,6 @@
 		(struct ieee80211_radiotap_header *) skb->data;
 	struct ieee80211_supported_band *sband;
 	int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
 	sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
@@ -829,8 +879,6 @@
 	 */
 
 	while (!ret) {
-		int i, target_rate;
-
 		ret = ieee80211_radiotap_iterator_next(&iterator);
 
 		if (ret)
@@ -844,38 +892,6 @@
 		 * get_unaligned((type *)iterator.this_arg) to dereference
 		 * iterator.this_arg for type "type" safely on all arches.
 		*/
-		case IEEE80211_RADIOTAP_RATE:
-			/*
-			 * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps
-			 * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
-			 */
-			target_rate = (*iterator.this_arg) * 5;
-			for (i = 0; i < sband->n_bitrates; i++) {
-				struct ieee80211_rate *r;
-
-				r = &sband->bitrates[i];
-
-				if (r->bitrate == target_rate) {
-					tx->rate_idx = i;
-					break;
-				}
-			}
-			break;
-
-		case IEEE80211_RADIOTAP_ANTENNA:
-			/*
-			 * radiotap uses 0 for 1st ant, mac80211 is 1 for
-			 * 1st ant
-			 */
-			info->antenna_sel_tx = (*iterator.this_arg) + 1;
-			break;
-
-#if 0
-		case IEEE80211_RADIOTAP_DBM_TX_POWER:
-			control->power_level = *iterator.this_arg;
-			break;
-#endif
-
 		case IEEE80211_RADIOTAP_FLAGS:
 			if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
 				/*
@@ -933,7 +949,8 @@
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
-	int hdrlen;
+	int hdrlen, tid;
+	u8 *qc, *state;
 
 	memset(tx, 0, sizeof(*tx));
 	tx->skb = skb;
@@ -941,8 +958,6 @@
 	tx->local = local;
 	tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	tx->channel = local->hw.conf.channel;
-	tx->rate_idx = -1;
-	tx->last_frag_rate_idx = -1;
 	/*
 	 * Set this flag (used below to indicate "automatic fragmentation"),
 	 * it will be cleared/left by radiotap as desired.
@@ -966,6 +981,15 @@
 
 	tx->sta = sta_info_get(local, hdr->addr1);
 
+	if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) {
+		qc = ieee80211_get_qos_ctl(hdr);
+		tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+
+		state = &tx->sta->ampdu_mlme.tid_state_tx[tid];
+		if (*state == HT_AGG_STATE_OPERATIONAL)
+			info->flags |= IEEE80211_TX_CTL_AMPDU;
+	}
+
 	if (is_multicast_ether_addr(hdr->addr1)) {
 		tx->flags &= ~IEEE80211_TX_UNICAST;
 		info->flags |= IEEE80211_TX_CTL_NO_ACK;
@@ -977,7 +1001,6 @@
 	if (tx->flags & IEEE80211_TX_FRAGMENTED) {
 		if ((tx->flags & IEEE80211_TX_UNICAST) &&
 		    skb->len + FCS_LEN > local->fragmentation_threshold &&
-		    !local->ops->set_frag_threshold &&
 		    !(info->flags & IEEE80211_TX_CTL_AMPDU))
 			tx->flags |= IEEE80211_TX_FRAGMENTED;
 		else
@@ -1043,23 +1066,11 @@
 			if (!tx->extra_frag[i])
 				continue;
 			info = IEEE80211_SKB_CB(tx->extra_frag[i]);
-			info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS |
-					 IEEE80211_TX_CTL_USE_CTS_PROTECT |
-					 IEEE80211_TX_CTL_CLEAR_PS_FILT |
+			info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
 					 IEEE80211_TX_CTL_FIRST_FRAGMENT);
 			if (netif_subqueue_stopped(local->mdev,
 						   tx->extra_frag[i]))
 				return IEEE80211_TX_FRAG_AGAIN;
-			if (i == tx->num_extra_frag) {
-				info->tx_rate_idx = tx->last_frag_rate_idx;
-
-				if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG)
-					info->flags |=
-						IEEE80211_TX_CTL_RATE_CTRL_PROBE;
-				else
-					info->flags &=
-						~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
-			}
 
 			ret = local->ops->tx(local_to_hw(local),
 					    tx->extra_frag[i]);
@@ -1168,7 +1179,7 @@
 		 * queues, there's no reason for a driver to reject
 		 * a frame there, warn and drop it.
 		 */
-		if (WARN_ON(queue >= ieee80211_num_regular_queues(&local->hw)))
+		if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
 			goto drop;
 
 		store = &local->pending_packet[queue];
@@ -1196,9 +1207,6 @@
 		store->skb = skb;
 		store->extra_frag = tx.extra_frag;
 		store->num_extra_frag = tx.num_extra_frag;
-		store->last_frag_rate_idx = tx.last_frag_rate_idx;
-		store->last_frag_rate_ctrl_probe =
-			!!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
 	}
  out:
 	rcu_read_unlock();
@@ -1465,6 +1473,19 @@
 		goto fail;
 	}
 
+	if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
+	    local->dynamic_ps_timeout > 0) {
+		if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+			ieee80211_stop_queues_by_reason(&local->hw,
+							IEEE80211_QUEUE_STOP_REASON_PS);
+			queue_work(local->hw.workqueue,
+				   &local->dynamic_ps_disable_work);
+		}
+
+		mod_timer(&local->dynamic_ps_timer, jiffies +
+			  msecs_to_jiffies(local->dynamic_ps_timeout));
+	}
+
 	nh_pos = skb_network_header(skb) - skb->data;
 	h_pos = skb_transport_header(skb) - skb->data;
 
@@ -1593,12 +1614,10 @@
 		       compare_ether_addr(dev->dev_addr,
 					  skb->data + ETH_ALEN) == 0))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		DECLARE_MAC_BUF(mac);
-
 		if (net_ratelimit())
-			printk(KERN_DEBUG "%s: dropped frame to %s"
+			printk(KERN_DEBUG "%s: dropped frame to %pM"
 			       " (unauthorized port)\n", dev->name,
-			       print_mac(mac, hdr.addr1));
+			       hdr.addr1);
 #endif
 
 		I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
@@ -1757,10 +1776,7 @@
 		store = &local->pending_packet[i];
 		tx.extra_frag = store->extra_frag;
 		tx.num_extra_frag = store->num_extra_frag;
-		tx.last_frag_rate_idx = store->last_frag_rate_idx;
 		tx.flags = 0;
-		if (store->last_frag_rate_ctrl_probe)
-			tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG;
 		ret = __ieee80211_tx(local, store->skb, &tx);
 		if (ret) {
 			if (ret == IEEE80211_TX_FRAG_AGAIN)
@@ -1775,8 +1791,7 @@
 
 /* functions for drivers to get certain frames */
 
-static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
-				     struct ieee80211_if_ap *bss,
+static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
 				     struct sk_buff *skb,
 				     struct beacon_data *beacon)
 {
@@ -1844,11 +1859,9 @@
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct sk_buff *skb = NULL;
 	struct ieee80211_tx_info *info;
-	struct net_device *bdev;
 	struct ieee80211_sub_if_data *sdata = NULL;
 	struct ieee80211_if_ap *ap = NULL;
 	struct ieee80211_if_sta *ifsta = NULL;
-	struct rate_selection rsel;
 	struct beacon_data *beacon;
 	struct ieee80211_supported_band *sband;
 	enum ieee80211_band band = local->hw.conf.channel->band;
@@ -1858,7 +1871,6 @@
 	rcu_read_lock();
 
 	sdata = vif_to_sdata(vif);
-	bdev = sdata->dev;
 
 	if (sdata->vif.type == NL80211_IFTYPE_AP) {
 		ap = &sdata->u.ap;
@@ -1886,12 +1898,12 @@
 			 * of the tim bitmap in mac80211 and the driver.
 			 */
 			if (local->tim_in_locked_section) {
-				ieee80211_beacon_add_tim(local, ap, skb, beacon);
+				ieee80211_beacon_add_tim(ap, skb, beacon);
 			} else {
 				unsigned long flags;
 
 				spin_lock_irqsave(&local->sta_lock, flags);
-				ieee80211_beacon_add_tim(local, ap, skb, beacon);
+				ieee80211_beacon_add_tim(ap, skb, beacon);
 				spin_unlock_irqrestore(&local->sta_lock, flags);
 			}
 
@@ -1952,33 +1964,23 @@
 	skb->do_not_encrypt = 1;
 
 	info->band = band;
-	rate_control_get_rate(sdata, sband, NULL, skb, &rsel);
-
-	if (unlikely(rsel.rate_idx < 0)) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
-			       "no rate found\n",
-			       wiphy_name(local->hw.wiphy));
-		}
-		dev_kfree_skb_any(skb);
-		skb = NULL;
-		goto out;
-	}
+	/*
+	 * XXX: For now, always use the lowest rate
+	 */
+	info->control.rates[0].idx = 0;
+	info->control.rates[0].count = 1;
+	info->control.rates[1].idx = -1;
+	info->control.rates[2].idx = -1;
+	info->control.rates[3].idx = -1;
+	info->control.rates[4].idx = -1;
+	BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5);
 
 	info->control.vif = vif;
-	info->tx_rate_idx = rsel.rate_idx;
 
 	info->flags |= IEEE80211_TX_CTL_NO_ACK;
 	info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
 	info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
-	if (sdata->bss_conf.use_short_preamble &&
-	    sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
-		info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
-
-	info->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-	info->control.retry_limit = 1;
-
-out:
+ out:
 	rcu_read_unlock();
 	return skb;
 }
@@ -2023,14 +2025,12 @@
 	struct sk_buff *skb = NULL;
 	struct sta_info *sta;
 	struct ieee80211_tx_data tx;
-	struct net_device *bdev;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_if_ap *bss = NULL;
 	struct beacon_data *beacon;
 	struct ieee80211_tx_info *info;
 
 	sdata = vif_to_sdata(vif);
-	bdev = sdata->dev;
 	bss = &sdata->u.ap;
 
 	if (!bss)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index cee4884..fb89e1d 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -239,7 +239,7 @@
 	erp = 0;
 	if (vif) {
 		sdata = vif_to_sdata(vif);
-		short_preamble = sdata->bss_conf.use_short_preamble;
+		short_preamble = sdata->vif.bss_conf.use_short_preamble;
 		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
 			erp = rate->flags & IEEE80211_RATE_ERP_G;
 	}
@@ -272,7 +272,7 @@
 	erp = 0;
 	if (vif) {
 		sdata = vif_to_sdata(vif);
-		short_preamble = sdata->bss_conf.use_short_preamble;
+		short_preamble = sdata->vif.bss_conf.use_short_preamble;
 		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
 			erp = rate->flags & IEEE80211_RATE_ERP_G;
 	}
@@ -312,7 +312,7 @@
 	erp = 0;
 	if (vif) {
 		sdata = vif_to_sdata(vif);
-		short_preamble = sdata->bss_conf.use_short_preamble;
+		short_preamble = sdata->vif.bss_conf.use_short_preamble;
 		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
 			erp = rate->flags & IEEE80211_RATE_ERP_G;
 	}
@@ -330,10 +330,20 @@
 }
 EXPORT_SYMBOL(ieee80211_ctstoself_duration);
 
-void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
+static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
+				   enum queue_stop_reason reason)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 
+	/* we don't need to track ampdu queues */
+	if (queue < ieee80211_num_regular_queues(hw)) {
+		__clear_bit(reason, &local->queue_stop_reasons[queue]);
+
+		if (local->queue_stop_reasons[queue] != 0)
+			/* someone still has this queue stopped */
+			return;
+	}
+
 	if (test_bit(queue, local->queues_pending)) {
 		set_bit(queue, local->queues_pending_run);
 		tasklet_schedule(&local->tx_pending_tasklet);
@@ -341,22 +351,74 @@
 		netif_wake_subqueue(local->mdev, queue);
 	}
 }
+
+void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
+				    enum queue_stop_reason reason)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+	__ieee80211_wake_queue(hw, queue, reason);
+	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
+{
+	ieee80211_wake_queue_by_reason(hw, queue,
+				       IEEE80211_QUEUE_STOP_REASON_DRIVER);
+}
 EXPORT_SYMBOL(ieee80211_wake_queue);
 
-void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
+static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
+				   enum queue_stop_reason reason)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 
+	/* we don't need to track ampdu queues */
+	if (queue < ieee80211_num_regular_queues(hw))
+		__set_bit(reason, &local->queue_stop_reasons[queue]);
+
 	netif_stop_subqueue(local->mdev, queue);
 }
+
+void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
+				    enum queue_stop_reason reason)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+	__ieee80211_stop_queue(hw, queue, reason);
+	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
+{
+	ieee80211_stop_queue_by_reason(hw, queue,
+				       IEEE80211_QUEUE_STOP_REASON_DRIVER);
+}
 EXPORT_SYMBOL(ieee80211_stop_queue);
 
-void ieee80211_stop_queues(struct ieee80211_hw *hw)
+void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
+				    enum queue_stop_reason reason)
 {
+	struct ieee80211_local *local = hw_to_local(hw);
+	unsigned long flags;
 	int i;
 
+	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+
 	for (i = 0; i < ieee80211_num_queues(hw); i++)
-		ieee80211_stop_queue(hw, i);
+		__ieee80211_stop_queue(hw, i, reason);
+
+	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+void ieee80211_stop_queues(struct ieee80211_hw *hw)
+{
+	ieee80211_stop_queues_by_reason(hw,
+					IEEE80211_QUEUE_STOP_REASON_DRIVER);
 }
 EXPORT_SYMBOL(ieee80211_stop_queues);
 
@@ -367,12 +429,24 @@
 }
 EXPORT_SYMBOL(ieee80211_queue_stopped);
 
-void ieee80211_wake_queues(struct ieee80211_hw *hw)
+void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
+				     enum queue_stop_reason reason)
 {
+	struct ieee80211_local *local = hw_to_local(hw);
+	unsigned long flags;
 	int i;
 
+	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+
 	for (i = 0; i < hw->queues + hw->ampdu_queues; i++)
-		ieee80211_wake_queue(hw, i);
+		__ieee80211_wake_queue(hw, i, reason);
+
+	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+void ieee80211_wake_queues(struct ieee80211_hw *hw)
+{
+	ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER);
 }
 EXPORT_SYMBOL(ieee80211_wake_queues);
 
@@ -532,8 +606,8 @@
 			if (elen >= sizeof(struct ieee80211_ht_cap))
 				elems->ht_cap_elem = (void *)pos;
 			break;
-		case WLAN_EID_HT_EXTRA_INFO:
-			if (elen >= sizeof(struct ieee80211_ht_addt_info))
+		case WLAN_EID_HT_INFORMATION:
+			if (elen >= sizeof(struct ieee80211_ht_info))
 				elems->ht_info_elem = (void *)pos;
 			break;
 		case WLAN_EID_MESH_ID:
@@ -638,19 +712,16 @@
 
 	if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
 		if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
-		    chan->flags & IEEE80211_CHAN_NO_IBSS) {
-			printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
-				"%d MHz\n", sdata->dev->name, chan->center_freq);
+		    chan->flags & IEEE80211_CHAN_NO_IBSS)
 			return ret;
-		}
 		local->oper_channel = chan;
+		local->oper_channel_type = NL80211_CHAN_NO_HT;
 
 		if (local->sw_scanning || local->hw_scanning)
 			ret = 0;
 		else
-			ret = ieee80211_hw_config(local);
-
-		rate_control_clear(local);
+			ret = ieee80211_hw_config(
+				local, IEEE80211_CONF_CHANGE_CHANNEL);
 	}
 
 	return ret;
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index f0e2d3e..7043ddc 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -17,6 +17,7 @@
 #include <linux/err.h>
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
+#include <asm/unaligned.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
@@ -49,17 +50,19 @@
 	crypto_free_blkcipher(local->wep_rx_tfm);
 }
 
-static inline int ieee80211_wep_weak_iv(u32 iv, int keylen)
+static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
 {
-	/* Fluhrer, Mantin, and Shamir have reported weaknesses in the
+	/*
+	 * Fluhrer, Mantin, and Shamir have reported weaknesses in the
 	 * key scheduling algorithm of RC4. At least IVs (KeyByte + 3,
-	 * 0xff, N) can be used to speedup attacks, so avoid using them. */
+	 * 0xff, N) can be used to speedup attacks, so avoid using them.
+	 */
 	if ((iv & 0xff00) == 0xff00) {
 		u8 B = (iv >> 16) & 0xff;
 		if (B >= 3 && B < 3 + keylen)
-			return 1;
+			return true;
 	}
-	return 0;
+	return false;
 }
 
 
@@ -123,10 +126,10 @@
 {
 	struct blkcipher_desc desc = { .tfm = tfm };
 	struct scatterlist sg;
-	__le32 *icv;
+	__le32 icv;
 
-	icv = (__le32 *)(data + data_len);
-	*icv = cpu_to_le32(~crc32_le(~0, data, data_len));
+	icv = cpu_to_le32(~crc32_le(~0, data, data_len));
+	put_unaligned(icv, (__le32 *)(data + data_len));
 
 	crypto_blkcipher_setkey(tfm, rc4key, klen);
 	sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
@@ -268,7 +271,7 @@
 }
 
 
-u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
+bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	unsigned int hdrlen;
@@ -276,16 +279,13 @@
 	u32 iv;
 
 	if (!ieee80211_has_protected(hdr->frame_control))
-		return NULL;
+		return false;
 
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	ivpos = skb->data + hdrlen;
 	iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
 
-	if (ieee80211_wep_weak_iv(iv, key->conf.keylen))
-		return ivpos;
-
-	return NULL;
+	return ieee80211_wep_weak_iv(iv, key->conf.keylen);
 }
 
 ieee80211_rx_result
@@ -329,6 +329,8 @@
 ieee80211_tx_result
 ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
 {
+	int i;
+
 	ieee80211_tx_set_protected(tx);
 
 	if (wep_encrypt_skb(tx, tx->skb) < 0) {
@@ -337,9 +339,8 @@
 	}
 
 	if (tx->extra_frag) {
-		int i;
 		for (i = 0; i < tx->num_extra_frag; i++) {
-			if (wep_encrypt_skb(tx, tx->extra_frag[i]) < 0) {
+			if (wep_encrypt_skb(tx, tx->extra_frag[i])) {
 				I802_DEBUG_INC(tx->local->
 					       tx_handlers_drop_wep);
 				return TX_DROP;
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
index e587172..d3f0db4 100644
--- a/net/mac80211/wep.h
+++ b/net/mac80211/wep.h
@@ -26,7 +26,7 @@
 			  struct ieee80211_key *key);
 int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
 			  struct ieee80211_key *key);
-u8 *ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
+bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
 
 ieee80211_rx_result
 ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx);
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index ab4ddba..7162d58 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -135,48 +135,6 @@
 	return -EOPNOTSUPP;
 }
 
-static int ieee80211_ioctl_giwname(struct net_device *dev,
-				   struct iw_request_info *info,
-				   char *name, char *extra)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_supported_band *sband;
-	u8 is_ht = 0, is_a = 0, is_b = 0, is_g = 0;
-
-
-	sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ];
-	if (sband) {
-		is_a = 1;
-		is_ht |= sband->ht_info.ht_supported;
-	}
-
-	sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ];
-	if (sband) {
-		int i;
-		/* Check for mandatory rates */
-		for (i = 0; i < sband->n_bitrates; i++) {
-			if (sband->bitrates[i].bitrate == 10)
-				is_b = 1;
-			if (sband->bitrates[i].bitrate == 60)
-				is_g = 1;
-		}
-		is_ht |= sband->ht_info.ht_supported;
-	}
-
-	strcpy(name, "IEEE 802.11");
-	if (is_a)
-		strcat(name, "a");
-	if (is_b)
-		strcat(name, "b");
-	if (is_g)
-		strcat(name, "g");
-	if (is_ht)
-		strcat(name, "n");
-
-	return 0;
-}
-
-
 static int ieee80211_ioctl_giwrange(struct net_device *dev,
 				 struct iw_request_info *info,
 				 struct iw_point *data, char *extra)
@@ -266,78 +224,6 @@
 }
 
 
-static int ieee80211_ioctl_siwmode(struct net_device *dev,
-				   struct iw_request_info *info,
-				   __u32 *mode, char *extra)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_local *local = sdata->local;
-	int type;
-
-	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-		return -EOPNOTSUPP;
-
-	switch (*mode) {
-	case IW_MODE_INFRA:
-		type = NL80211_IFTYPE_STATION;
-		break;
-	case IW_MODE_ADHOC:
-		/* Setting ad-hoc mode on non ibss channel is not
-		 * supported.
-		 */
-		if (local->oper_channel &&
-		    (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS))
-			return -EOPNOTSUPP;
-
-		type = NL80211_IFTYPE_ADHOC;
-		break;
-	case IW_MODE_REPEAT:
-		type = NL80211_IFTYPE_WDS;
-		break;
-	case IW_MODE_MONITOR:
-		type = NL80211_IFTYPE_MONITOR;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return ieee80211_if_change_type(sdata, type);
-}
-
-
-static int ieee80211_ioctl_giwmode(struct net_device *dev,
-				   struct iw_request_info *info,
-				   __u32 *mode, char *extra)
-{
-	struct ieee80211_sub_if_data *sdata;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	switch (sdata->vif.type) {
-	case NL80211_IFTYPE_AP:
-		*mode = IW_MODE_MASTER;
-		break;
-	case NL80211_IFTYPE_STATION:
-		*mode = IW_MODE_INFRA;
-		break;
-	case NL80211_IFTYPE_ADHOC:
-		*mode = IW_MODE_ADHOC;
-		break;
-	case NL80211_IFTYPE_MONITOR:
-		*mode = IW_MODE_MONITOR;
-		break;
-	case NL80211_IFTYPE_WDS:
-		*mode = IW_MODE_REPEAT;
-		break;
-	case NL80211_IFTYPE_AP_VLAN:
-		*mode = IW_MODE_SECOND;		/* FIXME */
-		break;
-	default:
-		*mode = IW_MODE_AUTO;
-		break;
-	}
-	return 0;
-}
-
 static int ieee80211_ioctl_siwfreq(struct net_device *dev,
 				   struct iw_request_info *info,
 				   struct iw_freq *freq, char *extra)
@@ -415,13 +301,6 @@
 		return 0;
 	}
 
-	if (sdata->vif.type == NL80211_IFTYPE_AP) {
-		memcpy(sdata->u.ap.ssid, ssid, len);
-		memset(sdata->u.ap.ssid + len, 0,
-		       IEEE80211_MAX_SSID_LEN - len);
-		sdata->u.ap.ssid_len = len;
-		return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
-	}
 	return -EOPNOTSUPP;
 }
 
@@ -445,15 +324,6 @@
 		return res;
 	}
 
-	if (sdata->vif.type == NL80211_IFTYPE_AP) {
-		len = sdata->u.ap.ssid_len;
-		if (len > IW_ESSID_MAX_SIZE)
-			len = IW_ESSID_MAX_SIZE;
-		memcpy(ssid, sdata->u.ap.ssid, len);
-		data->length = len;
-		data->flags = 1;
-		return 0;
-	}
 	return -EOPNOTSUPP;
 }
 
@@ -548,8 +418,7 @@
 
 	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
 	    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-	    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
-	    sdata->vif.type != NL80211_IFTYPE_AP)
+	    sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
 		return -EOPNOTSUPP;
 
 	/* if SSID was specified explicitly then use that */
@@ -644,8 +513,8 @@
 
 	sta = sta_info_get(local, sdata->u.sta.bssid);
 
-	if (sta && sta->last_txrate_idx < sband->n_bitrates)
-		rate->value = sband->bitrates[sta->last_txrate_idx].bitrate;
+	if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS))
+		rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate;
 	else
 		rate->value = 0;
 
@@ -664,45 +533,35 @@
 				      union iwreq_data *data, char *extra)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	bool need_reconfig = 0;
+	struct ieee80211_channel* chan = local->hw.conf.channel;
+	u32 reconf_flags = 0;
 	int new_power_level;
 
 	if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
 		return -EINVAL;
 	if (data->txpower.flags & IW_TXPOW_RANGE)
 		return -EINVAL;
+	if (!chan)
+		return -EINVAL;
 
-	if (data->txpower.fixed) {
-		new_power_level = data->txpower.value;
-	} else {
-		/*
-		 * Automatic power level. Use maximum power for the current
-		 * channel. Should be part of rate control.
-		 */
-		struct ieee80211_channel* chan = local->hw.conf.channel;
-		if (!chan)
-			return -EINVAL;
-
+	if (data->txpower.fixed)
+		new_power_level = min(data->txpower.value, chan->max_power);
+	else /* Automatic power level setting */
 		new_power_level = chan->max_power;
-	}
 
 	if (local->hw.conf.power_level != new_power_level) {
 		local->hw.conf.power_level = new_power_level;
-		need_reconfig = 1;
+		reconf_flags |= IEEE80211_CONF_CHANGE_POWER;
 	}
 
 	if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
 		local->hw.conf.radio_enabled = !(data->txpower.disabled);
-		need_reconfig = 1;
+		reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
 		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
 	}
 
-	if (need_reconfig) {
-		ieee80211_hw_config(local);
-		/* The return value of hw_config is not of big interest here,
-		 * as it doesn't say that it failed because of _this_ config
-		 * change or something else. Ignore it. */
-	}
+	if (reconf_flags)
+		ieee80211_hw_config(local, reconf_flags);
 
 	return 0;
 }
@@ -779,14 +638,6 @@
 		local->fragmentation_threshold = frag->value & ~0x1;
 	}
 
-	/* If the wlan card performs fragmentation in hardware/firmware,
-	 * configure it here */
-
-	if (local->ops->set_frag_threshold)
-		return local->ops->set_frag_threshold(
-			local_to_hw(local),
-			local->fragmentation_threshold);
-
 	return 0;
 }
 
@@ -814,21 +665,16 @@
 	    (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
 		return -EINVAL;
 
-	if (retry->flags & IW_RETRY_MAX)
-		local->long_retry_limit = retry->value;
-	else if (retry->flags & IW_RETRY_MIN)
-		local->short_retry_limit = retry->value;
-	else {
-		local->long_retry_limit = retry->value;
-		local->short_retry_limit = retry->value;
+	if (retry->flags & IW_RETRY_MAX) {
+		local->hw.conf.long_frame_max_tx_count = retry->value;
+	} else if (retry->flags & IW_RETRY_MIN) {
+		local->hw.conf.short_frame_max_tx_count = retry->value;
+	} else {
+		local->hw.conf.long_frame_max_tx_count = retry->value;
+		local->hw.conf.short_frame_max_tx_count = retry->value;
 	}
 
-	if (local->ops->set_retry_limit) {
-		return local->ops->set_retry_limit(
-			local_to_hw(local),
-			local->short_retry_limit,
-			local->long_retry_limit);
-	}
+	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS);
 
 	return 0;
 }
@@ -845,14 +691,15 @@
 		/* first return min value, iwconfig will ask max value
 		 * later if needed */
 		retry->flags |= IW_RETRY_LIMIT;
-		retry->value = local->short_retry_limit;
-		if (local->long_retry_limit != local->short_retry_limit)
+		retry->value = local->hw.conf.short_frame_max_tx_count;
+		if (local->hw.conf.long_frame_max_tx_count !=
+		    local->hw.conf.short_frame_max_tx_count)
 			retry->flags |= IW_RETRY_MIN;
 		return 0;
 	}
 	if (retry->flags & IW_RETRY_MAX) {
 		retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
-		retry->value = local->long_retry_limit;
+		retry->value = local->hw.conf.long_frame_max_tx_count;
 	}
 
 	return 0;
@@ -983,25 +830,56 @@
 				    struct iw_param *wrq,
 				    char *extra)
 {
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_conf *conf = &local->hw.conf;
+	int ret = 0, timeout = 0;
+	bool ps;
+
+	if (sdata->vif.type != NL80211_IFTYPE_STATION)
+		return -EINVAL;
 
 	if (wrq->disabled) {
-		conf->flags &= ~IEEE80211_CONF_PS;
-		return ieee80211_hw_config(local);
+		ps = false;
+		timeout = 0;
+		goto set;
 	}
 
 	switch (wrq->flags & IW_POWER_MODE) {
 	case IW_POWER_ON:       /* If not specified */
 	case IW_POWER_MODE:     /* If set all mask */
 	case IW_POWER_ALL_R:    /* If explicitely state all */
-		conf->flags |= IEEE80211_CONF_PS;
+		ps = true;
 		break;
-	default:                /* Otherwise we don't support it */
-		return -EINVAL;
+	default:                /* Otherwise we ignore */
+		break;
 	}
 
-	return ieee80211_hw_config(local);
+	if (wrq->flags & IW_POWER_TIMEOUT)
+		timeout = wrq->value / 1000;
+
+set:
+	if (ps == local->powersave && timeout == local->dynamic_ps_timeout)
+		return ret;
+
+	local->powersave = ps;
+	local->dynamic_ps_timeout = timeout;
+
+	if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
+		if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
+		    local->dynamic_ps_timeout > 0)
+			mod_timer(&local->dynamic_ps_timer, jiffies +
+				  msecs_to_jiffies(local->dynamic_ps_timeout));
+		else {
+			if (local->powersave)
+				conf->flags |= IEEE80211_CONF_PS;
+			else
+				conf->flags &= ~IEEE80211_CONF_PS;
+		}
+		ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+	}
+
+	return ret;
 }
 
 static int ieee80211_ioctl_giwpower(struct net_device *dev,
@@ -1010,9 +888,8 @@
 				    char *extra)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_conf *conf = &local->hw.conf;
 
-	wrqu->power.disabled = !(conf->flags & IEEE80211_CONF_PS);
+	wrqu->power.disabled = !local->powersave;
 
 	return 0;
 }
@@ -1176,13 +1053,13 @@
 static const iw_handler ieee80211_handler[] =
 {
 	(iw_handler) NULL,				/* SIOCSIWCOMMIT */
-	(iw_handler) ieee80211_ioctl_giwname,		/* SIOCGIWNAME */
+	(iw_handler) cfg80211_wext_giwname,		/* SIOCGIWNAME */
 	(iw_handler) NULL,				/* SIOCSIWNWID */
 	(iw_handler) NULL,				/* SIOCGIWNWID */
 	(iw_handler) ieee80211_ioctl_siwfreq,		/* SIOCSIWFREQ */
 	(iw_handler) ieee80211_ioctl_giwfreq,		/* SIOCGIWFREQ */
-	(iw_handler) ieee80211_ioctl_siwmode,		/* SIOCSIWMODE */
-	(iw_handler) ieee80211_ioctl_giwmode,		/* SIOCGIWMODE */
+	(iw_handler) cfg80211_wext_siwmode,		/* SIOCSIWMODE */
+	(iw_handler) cfg80211_wext_giwmode,		/* SIOCGIWMODE */
 	(iw_handler) NULL,				/* SIOCSIWSENS */
 	(iw_handler) NULL,				/* SIOCGIWSENS */
 	(iw_handler) NULL /* not used */,		/* SIOCSIWRANGE */
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 139b5f2..ac71b38 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -114,8 +114,8 @@
 {
 	struct ieee80211_master_priv *mpriv = netdev_priv(dev);
 	struct ieee80211_local *local = mpriv->local;
+	struct ieee80211_hw *hw = &local->hw;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct sta_info *sta;
 	u16 queue;
 	u8 tid;
@@ -124,21 +124,19 @@
 	if (unlikely(queue >= local->hw.queues))
 		queue = local->hw.queues - 1;
 
-	if (info->flags & IEEE80211_TX_CTL_REQUEUE) {
+	if (skb->requeue) {
+		if (!hw->ampdu_queues)
+			return queue;
+
 		rcu_read_lock();
 		sta = sta_info_get(local, hdr->addr1);
 		tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
 		if (sta) {
-			struct ieee80211_hw *hw = &local->hw;
 			int ampdu_queue = sta->tid_to_tx_q[tid];
 
 			if ((ampdu_queue < ieee80211_num_queues(hw)) &&
-			    test_bit(ampdu_queue, local->queue_pool)) {
+			    test_bit(ampdu_queue, local->queue_pool))
 				queue = ampdu_queue;
-				info->flags |= IEEE80211_TX_CTL_AMPDU;
-			} else {
-				info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-			}
 		}
 		rcu_read_unlock();
 
@@ -159,20 +157,18 @@
 		*p++ = ack_policy | tid;
 		*p = 0;
 
+		if (!hw->ampdu_queues)
+			return queue;
+
 		rcu_read_lock();
 
 		sta = sta_info_get(local, hdr->addr1);
 		if (sta) {
 			int ampdu_queue = sta->tid_to_tx_q[tid];
-			struct ieee80211_hw *hw = &local->hw;
 
 			if ((ampdu_queue < ieee80211_num_queues(hw)) &&
-			    test_bit(ampdu_queue, local->queue_pool)) {
+			    test_bit(ampdu_queue, local->queue_pool))
 				queue = ampdu_queue;
-				info->flags |= IEEE80211_TX_CTL_AMPDU;
-			} else {
-				info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-			}
 		}
 
 		rcu_read_unlock();
@@ -206,13 +202,11 @@
 			 * on the previous queue
 			 * since HT is strict in order */
 #ifdef CONFIG_MAC80211_HT_DEBUG
-			if (net_ratelimit()) {
-				DECLARE_MAC_BUF(mac);
+			if (net_ratelimit())
 				printk(KERN_DEBUG "allocated aggregation queue"
-					" %d tid %d addr %s pool=0x%lX\n",
-					i, tid, print_mac(mac, sta->sta.addr),
+					" %d tid %d addr %pM pool=0x%lX\n",
+					i, tid, sta->sta.addr,
 					local->queue_pool[0]);
-			}
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 			return 0;
 		}
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 6db6494..7aa63ca 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -49,8 +49,7 @@
 	    !(tx->flags & IEEE80211_TX_FRAGMENTED) &&
 	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) &&
 	    !wpa_test) {
-		/* hwaccel - with no need for preallocated room for Michael MIC
-		 */
+		/* hwaccel - with no need for preallocated room for MMIC */
 		return TX_CONTINUE;
 	}
 
@@ -67,8 +66,6 @@
 #else
 	authenticator = 1;
 #endif
-	/* At this point we know we're using ALG_TKIP. To get the MIC key
-	 * we now will rely on the offset from the ieee80211_key_conf::key */
 	key_offset = authenticator ?
 		NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY :
 		NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
@@ -90,11 +87,8 @@
 	u8 mic[MICHAEL_MIC_LEN];
 	struct sk_buff *skb = rx->skb;
 	int authenticator = 1, wpa_test = 0;
-	DECLARE_MAC_BUF(mac);
 
-	/*
-	 * No way to verify the MIC if the hardware stripped it
-	 */
+	/* No way to verify the MIC if the hardware stripped it */
 	if (rx->status->flag & RX_FLAG_MMIC_STRIPPED)
 		return RX_CONTINUE;
 
@@ -116,8 +110,6 @@
 #else
 	authenticator = 1;
 #endif
-	/* At this point we know we're using ALG_TKIP. To get the MIC key
-	 * we now will rely on the offset from the ieee80211_key_conf::key */
 	key_offset = authenticator ?
 		NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY :
 		NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
@@ -202,6 +194,7 @@
 ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
 {
 	struct sk_buff *skb = tx->skb;
+	int i;
 
 	ieee80211_tx_set_protected(tx);
 
@@ -209,9 +202,8 @@
 		return TX_DROP;
 
 	if (tx->extra_frag) {
-		int i;
 		for (i = 0; i < tx->num_extra_frag; i++) {
-			if (tkip_encrypt_skb(tx, tx->extra_frag[i]) < 0)
+			if (tkip_encrypt_skb(tx, tx->extra_frag[i]))
 				return TX_DROP;
 		}
 	}
@@ -227,7 +219,6 @@
 	int hdrlen, res, hwaccel = 0, wpa_test = 0;
 	struct ieee80211_key *key = rx->key;
 	struct sk_buff *skb = rx->skb;
-	DECLARE_MAC_BUF(mac);
 
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
@@ -350,7 +341,7 @@
 }
 
 
-static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr)
+static inline void ccmp_hdr2pn(u8 *pn, u8 *hdr)
 {
 	pn[0] = hdr[7];
 	pn[1] = hdr[6];
@@ -358,7 +349,6 @@
 	pn[3] = hdr[4];
 	pn[4] = hdr[1];
 	pn[5] = hdr[0];
-	return (hdr[3] >> 6) & 0x03;
 }
 
 
@@ -373,7 +363,7 @@
 
 	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
 	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
-		/* hwaccel - with no need for preallocated room for CCMP "
+		/* hwaccel - with no need for preallocated room for CCMP
 		 * header or MIC fields */
 		info->control.hw_key = &tx->key->conf;
 		return 0;
@@ -426,6 +416,7 @@
 ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
 {
 	struct sk_buff *skb = tx->skb;
+	int i;
 
 	ieee80211_tx_set_protected(tx);
 
@@ -433,9 +424,8 @@
 		return TX_DROP;
 
 	if (tx->extra_frag) {
-		int i;
 		for (i = 0; i < tx->num_extra_frag; i++) {
-			if (ccmp_encrypt_skb(tx, tx->extra_frag[i]) < 0)
+			if (ccmp_encrypt_skb(tx, tx->extra_frag[i]))
 				return TX_DROP;
 		}
 	}
@@ -453,7 +443,6 @@
 	struct sk_buff *skb = rx->skb;
 	u8 pn[CCMP_PN_LEN];
 	int data_len;
-	DECLARE_MAC_BUF(mac);
 
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
@@ -468,7 +457,7 @@
 	    (rx->status->flag & RX_FLAG_IV_STRIPPED))
 		return RX_CONTINUE;
 
-	(void) ccmp_hdr2pn(pn, skb->data + hdrlen);
+	ccmp_hdr2pn(pn, skb->data + hdrlen);
 
 	if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) {
 		key->u.ccmp.replays++;
@@ -483,9 +472,8 @@
 			    key->u.ccmp.tfm, key->u.ccmp.rx_crypto_buf,
 			    skb->data + hdrlen + CCMP_HDR_LEN, data_len,
 			    skb->data + skb->len - CCMP_MIC_LEN,
-			    skb->data + hdrlen + CCMP_HDR_LEN)) {
+			    skb->data + hdrlen + CCMP_HDR_LEN))
 			return RX_DROP_UNUSABLE;
-		}
 	}
 
 	memcpy(key->u.ccmp.rx_pn[rx->queue], pn, CCMP_PN_LEN);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 25dcef9..c2bac9c 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -373,11 +373,10 @@
 config NETFILTER_XT_TARGET_NFLOG
 	tristate '"NFLOG" target support'
 	default m if NETFILTER_ADVANCED=n
+	select NETFILTER_NETLINK_LOG
 	help
 	  This option enables the NFLOG target, which allows to LOG
-	  messages through the netfilter logging API, which can use
-	  either the old LOG target, the old ULOG target or nfnetlink_log
-	  as backend.
+	  messages through nfnetlink_log.
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index 9a24332..60aba45 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -820,13 +820,11 @@
 
 #ifdef CONFIG_IP_VS_IPV6
 		if (cp->af == AF_INET6)
-			seq_printf(seq,
-				"%-3s " NIP6_FMT " %04X " NIP6_FMT
-				" %04X " NIP6_FMT " %04X %-11s %7lu\n",
+			seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X %pI6 %04X %-11s %7lu\n",
 				ip_vs_proto_name(cp->protocol),
-				NIP6(cp->caddr.in6), ntohs(cp->cport),
-				NIP6(cp->vaddr.in6), ntohs(cp->vport),
-				NIP6(cp->daddr.in6), ntohs(cp->dport),
+				&cp->caddr.in6, ntohs(cp->cport),
+				&cp->vaddr.in6, ntohs(cp->vport),
+				&cp->daddr.in6, ntohs(cp->dport),
 				ip_vs_state_name(cp->protocol, cp->state),
 				(cp->timer.expires-jiffies)/HZ);
 		else
@@ -883,13 +881,11 @@
 
 #ifdef CONFIG_IP_VS_IPV6
 		if (cp->af == AF_INET6)
-			seq_printf(seq,
-				"%-3s " NIP6_FMT " %04X " NIP6_FMT
-				" %04X " NIP6_FMT " %04X %-11s %-6s %7lu\n",
+			seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X %pI6 %04X %-11s %-6s %7lu\n",
 				ip_vs_proto_name(cp->protocol),
-				NIP6(cp->caddr.in6), ntohs(cp->cport),
-				NIP6(cp->vaddr.in6), ntohs(cp->vport),
-				NIP6(cp->daddr.in6), ntohs(cp->dport),
+				&cp->caddr.in6, ntohs(cp->cport),
+				&cp->vaddr.in6, ntohs(cp->vport),
+				&cp->daddr.in6, ntohs(cp->dport),
 				ip_vs_state_name(cp->protocol, cp->state),
 				ip_vs_origin_name(cp->flags),
 				(cp->timer.expires-jiffies)/HZ);
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 958abf3..cb3e031 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -730,9 +730,9 @@
 	if (ic == NULL)
 		return NF_DROP;
 
-	IP_VS_DBG(12, "Outgoing ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n",
+	IP_VS_DBG(12, "Outgoing ICMP (%d,%d) %pI4->%pI4\n",
 		  ic->type, ntohs(icmp_id(ic)),
-		  NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
+		  &iph->saddr, &iph->daddr);
 
 	/*
 	 * Work through seeing if this is for us.
@@ -805,9 +805,9 @@
 	if (ic == NULL)
 		return NF_DROP;
 
-	IP_VS_DBG(12, "Outgoing ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n",
+	IP_VS_DBG(12, "Outgoing ICMPv6 (%d,%d) %pI6->%pI6\n",
 		  ic->icmp6_type, ntohs(icmpv6_id(ic)),
-		  NIP6(iph->saddr), NIP6(iph->daddr));
+		  &iph->saddr, &iph->daddr);
 
 	/*
 	 * Work through seeing if this is for us.
@@ -1070,9 +1070,9 @@
 	if (ic == NULL)
 		return NF_DROP;
 
-	IP_VS_DBG(12, "Incoming ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n",
+	IP_VS_DBG(12, "Incoming ICMP (%d,%d) %pI4->%pI4\n",
 		  ic->type, ntohs(icmp_id(ic)),
-		  NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
+		  &iph->saddr, &iph->daddr);
 
 	/*
 	 * Work through seeing if this is for us.
@@ -1127,8 +1127,8 @@
 	/* Ensure the checksum is correct */
 	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
 		/* Failed checksum! */
-		IP_VS_DBG(1, "Incoming ICMP: failed checksum from %d.%d.%d.%d!\n",
-			  NIPQUAD(iph->saddr));
+		IP_VS_DBG(1, "Incoming ICMP: failed checksum from %pI4!\n",
+			  &iph->saddr);
 		goto out;
 	}
 
@@ -1175,9 +1175,9 @@
 	if (ic == NULL)
 		return NF_DROP;
 
-	IP_VS_DBG(12, "Incoming ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n",
+	IP_VS_DBG(12, "Incoming ICMPv6 (%d,%d) %pI6->%pI6\n",
 		  ic->icmp6_type, ntohs(icmpv6_id(ic)),
-		  NIP6(iph->saddr), NIP6(iph->daddr));
+		  &iph->saddr, &iph->daddr);
 
 	/*
 	 * Work through seeing if this is for us.
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 0302cf3..e01061f 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -1168,15 +1168,9 @@
 	}
 
 #ifdef CONFIG_IP_VS_IPV6
-	if (u->af == AF_INET6) {
-		if (!sched->supports_ipv6) {
-			ret = -EAFNOSUPPORT;
-			goto out_err;
-		}
-		if ((u->netmask < 1) || (u->netmask > 128)) {
-			ret = -EINVAL;
-			goto out_err;
-		}
+	if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) {
+		ret = -EINVAL;
+		goto out_err;
 	}
 #endif
 
@@ -1272,15 +1266,9 @@
 	old_sched = sched;
 
 #ifdef CONFIG_IP_VS_IPV6
-	if (u->af == AF_INET6) {
-		if (!sched->supports_ipv6) {
-			ret = -EAFNOSUPPORT;
-			goto out;
-		}
-		if ((u->netmask < 1) || (u->netmask > 128)) {
-			ret = -EINVAL;
-			goto out;
-		}
+	if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) {
+		ret = -EINVAL;
+		goto out;
 	}
 #endif
 
@@ -1557,7 +1545,7 @@
 		.data		= &sysctl_ip_vs_amemthresh,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 #ifdef CONFIG_IP_VS_DEBUG
 	{
@@ -1565,7 +1553,7 @@
 		.data		= &sysctl_ip_vs_debug_level,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 #endif
 	{
@@ -1573,28 +1561,28 @@
 		.data		= &sysctl_ip_vs_am_droprate,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname	= "drop_entry",
 		.data		= &sysctl_ip_vs_drop_entry,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_do_defense_mode,
+		.proc_handler	= proc_do_defense_mode,
 	},
 	{
 		.procname	= "drop_packet",
 		.data		= &sysctl_ip_vs_drop_packet,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_do_defense_mode,
+		.proc_handler	= proc_do_defense_mode,
 	},
 	{
 		.procname	= "secure_tcp",
 		.data		= &sysctl_ip_vs_secure_tcp,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_do_defense_mode,
+		.proc_handler	= proc_do_defense_mode,
 	},
 #if 0
 	{
@@ -1602,84 +1590,84 @@
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "timeout_synsent",
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYN_SENT],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "timeout_synrecv",
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYN_RECV],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "timeout_finwait",
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_FIN_WAIT],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "timeout_timewait",
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_TIME_WAIT],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "timeout_close",
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "timeout_closewait",
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE_WAIT],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "timeout_lastack",
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_LAST_ACK],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "timeout_listen",
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_LISTEN],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "timeout_synack",
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYNACK],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "timeout_udp",
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_UDP],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "timeout_icmp",
 		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_ICMP],
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 #endif
 	{
@@ -1687,35 +1675,35 @@
 		.data		= &sysctl_ip_vs_cache_bypass,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname	= "expire_nodest_conn",
 		.data		= &sysctl_ip_vs_expire_nodest_conn,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname	= "expire_quiescent_template",
 		.data		= &sysctl_ip_vs_expire_quiescent_template,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.procname	= "sync_threshold",
 		.data		= &sysctl_ip_vs_sync_threshold,
 		.maxlen		= sizeof(sysctl_ip_vs_sync_threshold),
 		.mode		= 0644,
-		.proc_handler	= &proc_do_sync_threshold,
+		.proc_handler	= proc_do_sync_threshold,
 	},
 	{
 		.procname	= "nat_icmp_send",
 		.data		= &sysctl_ip_vs_nat_icmp_send,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{ .ctl_name = 0 }
 };
@@ -1867,9 +1855,9 @@
 		if (iter->table == ip_vs_svc_table) {
 #ifdef CONFIG_IP_VS_IPV6
 			if (svc->af == AF_INET6)
-				seq_printf(seq, "%s  [" NIP6_FMT "]:%04X %s ",
+				seq_printf(seq, "%s  [%pI6]:%04X %s ",
 					   ip_vs_proto_name(svc->protocol),
-					   NIP6(svc->addr.in6),
+					   &svc->addr.in6,
 					   ntohs(svc->port),
 					   svc->scheduler->name);
 			else
@@ -1895,9 +1883,9 @@
 #ifdef CONFIG_IP_VS_IPV6
 			if (dest->af == AF_INET6)
 				seq_printf(seq,
-					   "  -> [" NIP6_FMT "]:%04X"
+					   "  -> [%pI6]:%04X"
 					   "      %-7s %-6d %-10d %-10d\n",
-					   NIP6(dest->addr.in6),
+					   &dest->addr.in6,
 					   ntohs(dest->port),
 					   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
 					   atomic_read(&dest->weight),
@@ -2141,8 +2129,8 @@
 
 	/* Check for valid protocol: TCP or UDP, even for fwmark!=0 */
 	if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP) {
-		IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n",
-			  usvc.protocol, NIPQUAD(usvc.addr.ip),
+		IP_VS_ERR("set_ctl: invalid protocol: %d %pI4:%d %s\n",
+			  usvc.protocol, &usvc.addr.ip,
 			  ntohs(usvc.port), usvc.sched_name);
 		ret = -EFAULT;
 		goto out_unlock;
diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c
index a16943f..a9dac74 100644
--- a/net/netfilter/ipvs/ip_vs_dh.c
+++ b/net/netfilter/ipvs/ip_vs_dh.c
@@ -64,9 +64,16 @@
 /*
  *	Returns hash value for IPVS DH entry
  */
-static inline unsigned ip_vs_dh_hashkey(__be32 addr)
+static inline unsigned ip_vs_dh_hashkey(int af, const union nf_inet_addr *addr)
 {
-	return (ntohl(addr)*2654435761UL) & IP_VS_DH_TAB_MASK;
+	__be32 addr_fold = addr->ip;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		addr_fold = addr->ip6[0]^addr->ip6[1]^
+			    addr->ip6[2]^addr->ip6[3];
+#endif
+	return (ntohl(addr_fold)*2654435761UL) & IP_VS_DH_TAB_MASK;
 }
 
 
@@ -74,9 +81,10 @@
  *      Get ip_vs_dest associated with supplied parameters.
  */
 static inline struct ip_vs_dest *
-ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __be32 addr)
+ip_vs_dh_get(int af, struct ip_vs_dh_bucket *tbl,
+	     const union nf_inet_addr *addr)
 {
-	return (tbl[ip_vs_dh_hashkey(addr)]).dest;
+	return (tbl[ip_vs_dh_hashkey(af, addr)]).dest;
 }
 
 
@@ -202,12 +210,14 @@
 {
 	struct ip_vs_dest *dest;
 	struct ip_vs_dh_bucket *tbl;
-	struct iphdr *iph = ip_hdr(skb);
+	struct ip_vs_iphdr iph;
+
+	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
 
 	IP_VS_DBG(6, "ip_vs_dh_schedule(): Scheduling...\n");
 
 	tbl = (struct ip_vs_dh_bucket *)svc->sched_data;
-	dest = ip_vs_dh_get(tbl, iph->daddr);
+	dest = ip_vs_dh_get(svc->af, tbl, &iph.daddr);
 	if (!dest
 	    || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
 	    || atomic_read(&dest->weight) <= 0
@@ -215,11 +225,10 @@
 		return NULL;
 	}
 
-	IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u "
-		  "--> server %u.%u.%u.%u:%d\n",
-		  NIPQUAD(iph->daddr),
-		  NIPQUAD(dest->addr.ip),
-		  ntohs(dest->port));
+	IP_VS_DBG_BUF(6, "DH: destination IP address %s --> server %s:%d\n",
+		      IP_VS_DBG_ADDR(svc->af, &iph.daddr),
+		      IP_VS_DBG_ADDR(svc->af, &dest->addr),
+		      ntohs(dest->port));
 
 	return dest;
 }
@@ -234,9 +243,6 @@
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_dh_scheduler.n_list),
-#ifdef CONFIG_IP_VS_IPV6
-	.supports_ipv6 =	0,
-#endif
 	.init_service =		ip_vs_dh_init_svc,
 	.done_service =		ip_vs_dh_done_svc,
 	.update_service =	ip_vs_dh_update_svc,
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c
index 2e7dbd8..428edbf 100644
--- a/net/netfilter/ipvs/ip_vs_ftp.c
+++ b/net/netfilter/ipvs/ip_vs_ftp.c
@@ -178,10 +178,8 @@
 					   &start, &end) != 1)
 			return 1;
 
-		IP_VS_DBG(7, "PASV response (%u.%u.%u.%u:%d) -> "
-			  "%u.%u.%u.%u:%d detected\n",
-			  NIPQUAD(from.ip), ntohs(port),
-			  NIPQUAD(cp->caddr.ip), 0);
+		IP_VS_DBG(7, "PASV response (%pI4:%d) -> %pI4:%d detected\n",
+			  &from.ip, ntohs(port), &cp->caddr.ip, 0);
 
 		/*
 		 * Now update or create an connection entry for it
@@ -312,8 +310,7 @@
 				   &start, &end) != 1)
 		return 1;
 
-	IP_VS_DBG(7, "PORT %u.%u.%u.%u:%d detected\n",
-		  NIPQUAD(to.ip), ntohs(port));
+	IP_VS_DBG(7, "PORT %pI4:%d detected\n", &to.ip, ntohs(port));
 
 	/* Passive mode off */
 	cp->app_data = NULL;
@@ -321,9 +318,9 @@
 	/*
 	 * Now update or create a connection entry for it
 	 */
-	IP_VS_DBG(7, "protocol %s %u.%u.%u.%u:%d %u.%u.%u.%u:%d\n",
+	IP_VS_DBG(7, "protocol %s %pI4:%d %pI4:%d\n",
 		  ip_vs_proto_name(iph->protocol),
-		  NIPQUAD(to.ip), ntohs(port), NIPQUAD(cp->vaddr.ip), 0);
+		  &to.ip, ntohs(port), &cp->vaddr.ip, 0);
 
 	n_cp = ip_vs_conn_in_get(AF_INET, iph->protocol,
 				 &to, port,
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index 6ecef35..9394f53 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -86,7 +86,8 @@
  */
 struct ip_vs_lblc_entry {
 	struct list_head        list;
-	__be32                  addr;           /* destination IP address */
+	int			af;		/* address family */
+	union nf_inet_addr      addr;           /* destination IP address */
 	struct ip_vs_dest       *dest;          /* real server (cache) */
 	unsigned long           lastuse;        /* last used time */
 };
@@ -115,7 +116,7 @@
 		.data		= &sysctl_ip_vs_lblc_expiration,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{ .ctl_name = 0 }
 };
@@ -137,9 +138,17 @@
 /*
  *	Returns hash value for IPVS LBLC entry
  */
-static inline unsigned ip_vs_lblc_hashkey(__be32 addr)
+static inline unsigned
+ip_vs_lblc_hashkey(int af, const union nf_inet_addr *addr)
 {
-	return (ntohl(addr)*2654435761UL) & IP_VS_LBLC_TAB_MASK;
+	__be32 addr_fold = addr->ip;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		addr_fold = addr->ip6[0]^addr->ip6[1]^
+			    addr->ip6[2]^addr->ip6[3];
+#endif
+	return (ntohl(addr_fold)*2654435761UL) & IP_VS_LBLC_TAB_MASK;
 }
 
 
@@ -150,7 +159,7 @@
 static void
 ip_vs_lblc_hash(struct ip_vs_lblc_table *tbl, struct ip_vs_lblc_entry *en)
 {
-	unsigned hash = ip_vs_lblc_hashkey(en->addr);
+	unsigned hash = ip_vs_lblc_hashkey(en->af, &en->addr);
 
 	list_add(&en->list, &tbl->bucket[hash]);
 	atomic_inc(&tbl->entries);
@@ -162,13 +171,14 @@
  *  lock
  */
 static inline struct ip_vs_lblc_entry *
-ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __be32 addr)
+ip_vs_lblc_get(int af, struct ip_vs_lblc_table *tbl,
+	       const union nf_inet_addr *addr)
 {
-	unsigned hash = ip_vs_lblc_hashkey(addr);
+	unsigned hash = ip_vs_lblc_hashkey(af, addr);
 	struct ip_vs_lblc_entry *en;
 
 	list_for_each_entry(en, &tbl->bucket[hash], list)
-		if (en->addr == addr)
+		if (ip_vs_addr_equal(af, &en->addr, addr))
 			return en;
 
 	return NULL;
@@ -180,12 +190,12 @@
  * address to a server. Called under write lock.
  */
 static inline struct ip_vs_lblc_entry *
-ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, __be32 daddr,
+ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
 	       struct ip_vs_dest *dest)
 {
 	struct ip_vs_lblc_entry *en;
 
-	en = ip_vs_lblc_get(tbl, daddr);
+	en = ip_vs_lblc_get(dest->af, tbl, daddr);
 	if (!en) {
 		en = kmalloc(sizeof(*en), GFP_ATOMIC);
 		if (!en) {
@@ -193,7 +203,8 @@
 			return NULL;
 		}
 
-		en->addr = daddr;
+		en->af = dest->af;
+		ip_vs_addr_copy(dest->af, &en->addr, daddr);
 		en->lastuse = jiffies;
 
 		atomic_inc(&dest->refcnt);
@@ -369,7 +380,7 @@
 
 
 static inline struct ip_vs_dest *
-__ip_vs_lblc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+__ip_vs_lblc_schedule(struct ip_vs_service *svc)
 {
 	struct ip_vs_dest *dest, *least;
 	int loh, doh;
@@ -420,12 +431,13 @@
 		}
 	}
 
-	IP_VS_DBG(6, "LBLC: server %d.%d.%d.%d:%d "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr.ip), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
+	IP_VS_DBG_BUF(6, "LBLC: server %s:%d "
+		      "activeconns %d refcnt %d weight %d overhead %d\n",
+		      IP_VS_DBG_ADDR(least->af, &least->addr),
+		      ntohs(least->port),
+		      atomic_read(&least->activeconns),
+		      atomic_read(&least->refcnt),
+		      atomic_read(&least->weight), loh);
 
 	return least;
 }
@@ -459,15 +471,17 @@
 ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 {
 	struct ip_vs_lblc_table *tbl = svc->sched_data;
-	struct iphdr *iph = ip_hdr(skb);
+	struct ip_vs_iphdr iph;
 	struct ip_vs_dest *dest = NULL;
 	struct ip_vs_lblc_entry *en;
 
+	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
+
 	IP_VS_DBG(6, "ip_vs_lblc_schedule(): Scheduling...\n");
 
 	/* First look in our cache */
 	read_lock(&svc->sched_lock);
-	en = ip_vs_lblc_get(tbl, iph->daddr);
+	en = ip_vs_lblc_get(svc->af, tbl, &iph.daddr);
 	if (en) {
 		/* We only hold a read lock, but this is atomic */
 		en->lastuse = jiffies;
@@ -491,7 +505,7 @@
 		goto out;
 
 	/* No cache entry or it is invalid, time to schedule */
-	dest = __ip_vs_lblc_schedule(svc, iph);
+	dest = __ip_vs_lblc_schedule(svc);
 	if (!dest) {
 		IP_VS_DBG(1, "no destination available\n");
 		return NULL;
@@ -499,15 +513,13 @@
 
 	/* If we fail to create a cache entry, we'll just use the valid dest */
 	write_lock(&svc->sched_lock);
-	ip_vs_lblc_new(tbl, iph->daddr, dest);
+	ip_vs_lblc_new(tbl, &iph.daddr, dest);
 	write_unlock(&svc->sched_lock);
 
 out:
-	IP_VS_DBG(6, "LBLC: destination IP address %u.%u.%u.%u "
-		  "--> server %u.%u.%u.%u:%d\n",
-		  NIPQUAD(iph->daddr),
-		  NIPQUAD(dest->addr.ip),
-		  ntohs(dest->port));
+	IP_VS_DBG_BUF(6, "LBLC: destination IP address %s --> server %s:%d\n",
+		      IP_VS_DBG_ADDR(svc->af, &iph.daddr),
+		      IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port));
 
 	return dest;
 }
@@ -522,9 +534,6 @@
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_lblc_scheduler.n_list),
-#ifdef CONFIG_IP_VS_IPV6
-	.supports_ipv6 =	0,
-#endif
 	.init_service =		ip_vs_lblc_init_svc,
 	.done_service =		ip_vs_lblc_done_svc,
 	.schedule =		ip_vs_lblc_schedule,
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index 1f75ea8..92dc76a 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -202,12 +202,13 @@
 		}
 	}
 
-	IP_VS_DBG(6, "ip_vs_dest_set_min: server %d.%d.%d.%d:%d "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr.ip), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
+	IP_VS_DBG_BUF(6, "ip_vs_dest_set_min: server %s:%d "
+		      "activeconns %d refcnt %d weight %d overhead %d\n",
+		      IP_VS_DBG_ADDR(least->af, &least->addr),
+		      ntohs(least->port),
+		      atomic_read(&least->activeconns),
+		      atomic_read(&least->refcnt),
+		      atomic_read(&least->weight), loh);
 	return least;
 }
 
@@ -248,12 +249,12 @@
 		}
 	}
 
-	IP_VS_DBG(6, "ip_vs_dest_set_max: server %d.%d.%d.%d:%d "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(most->addr.ip), ntohs(most->port),
-		  atomic_read(&most->activeconns),
-		  atomic_read(&most->refcnt),
-		  atomic_read(&most->weight), moh);
+	IP_VS_DBG_BUF(6, "ip_vs_dest_set_max: server %s:%d "
+		      "activeconns %d refcnt %d weight %d overhead %d\n",
+		      IP_VS_DBG_ADDR(most->af, &most->addr), ntohs(most->port),
+		      atomic_read(&most->activeconns),
+		      atomic_read(&most->refcnt),
+		      atomic_read(&most->weight), moh);
 	return most;
 }
 
@@ -264,7 +265,8 @@
  */
 struct ip_vs_lblcr_entry {
 	struct list_head        list;
-	__be32                   addr;           /* destination IP address */
+	int			af;		/* address family */
+	union nf_inet_addr      addr;           /* destination IP address */
 	struct ip_vs_dest_set   set;            /* destination server set */
 	unsigned long           lastuse;        /* last used time */
 };
@@ -293,7 +295,7 @@
 		.data		= &sysctl_ip_vs_lblcr_expiration,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{ .ctl_name = 0 }
 };
@@ -311,9 +313,17 @@
 /*
  *	Returns hash value for IPVS LBLCR entry
  */
-static inline unsigned ip_vs_lblcr_hashkey(__be32 addr)
+static inline unsigned
+ip_vs_lblcr_hashkey(int af, const union nf_inet_addr *addr)
 {
-	return (ntohl(addr)*2654435761UL) & IP_VS_LBLCR_TAB_MASK;
+	__be32 addr_fold = addr->ip;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		addr_fold = addr->ip6[0]^addr->ip6[1]^
+			    addr->ip6[2]^addr->ip6[3];
+#endif
+	return (ntohl(addr_fold)*2654435761UL) & IP_VS_LBLCR_TAB_MASK;
 }
 
 
@@ -324,7 +334,7 @@
 static void
 ip_vs_lblcr_hash(struct ip_vs_lblcr_table *tbl, struct ip_vs_lblcr_entry *en)
 {
-	unsigned hash = ip_vs_lblcr_hashkey(en->addr);
+	unsigned hash = ip_vs_lblcr_hashkey(en->af, &en->addr);
 
 	list_add(&en->list, &tbl->bucket[hash]);
 	atomic_inc(&tbl->entries);
@@ -336,13 +346,14 @@
  *  read lock.
  */
 static inline struct ip_vs_lblcr_entry *
-ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __be32 addr)
+ip_vs_lblcr_get(int af, struct ip_vs_lblcr_table *tbl,
+		const union nf_inet_addr *addr)
 {
-	unsigned hash = ip_vs_lblcr_hashkey(addr);
+	unsigned hash = ip_vs_lblcr_hashkey(af, addr);
 	struct ip_vs_lblcr_entry *en;
 
 	list_for_each_entry(en, &tbl->bucket[hash], list)
-		if (en->addr == addr)
+		if (ip_vs_addr_equal(af, &en->addr, addr))
 			return en;
 
 	return NULL;
@@ -354,12 +365,12 @@
  * IP address to a server. Called under write lock.
  */
 static inline struct ip_vs_lblcr_entry *
-ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl,  __be32 daddr,
+ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr,
 		struct ip_vs_dest *dest)
 {
 	struct ip_vs_lblcr_entry *en;
 
-	en = ip_vs_lblcr_get(tbl, daddr);
+	en = ip_vs_lblcr_get(dest->af, tbl, daddr);
 	if (!en) {
 		en = kmalloc(sizeof(*en), GFP_ATOMIC);
 		if (!en) {
@@ -367,7 +378,8 @@
 			return NULL;
 		}
 
-		en->addr = daddr;
+		en->af = dest->af;
+		ip_vs_addr_copy(dest->af, &en->addr, daddr);
 		en->lastuse = jiffies;
 
 		/* initilize its dest set */
@@ -544,7 +556,7 @@
 
 
 static inline struct ip_vs_dest *
-__ip_vs_lblcr_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+__ip_vs_lblcr_schedule(struct ip_vs_service *svc)
 {
 	struct ip_vs_dest *dest, *least;
 	int loh, doh;
@@ -596,12 +608,13 @@
 		}
 	}
 
-	IP_VS_DBG(6, "LBLCR: server %d.%d.%d.%d:%d "
-		  "activeconns %d refcnt %d weight %d overhead %d\n",
-		  NIPQUAD(least->addr.ip), ntohs(least->port),
-		  atomic_read(&least->activeconns),
-		  atomic_read(&least->refcnt),
-		  atomic_read(&least->weight), loh);
+	IP_VS_DBG_BUF(6, "LBLCR: server %s:%d "
+		      "activeconns %d refcnt %d weight %d overhead %d\n",
+		      IP_VS_DBG_ADDR(least->af, &least->addr),
+		      ntohs(least->port),
+		      atomic_read(&least->activeconns),
+		      atomic_read(&least->refcnt),
+		      atomic_read(&least->weight), loh);
 
 	return least;
 }
@@ -635,15 +648,17 @@
 ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 {
 	struct ip_vs_lblcr_table *tbl = svc->sched_data;
-	struct iphdr *iph = ip_hdr(skb);
+	struct ip_vs_iphdr iph;
 	struct ip_vs_dest *dest = NULL;
 	struct ip_vs_lblcr_entry *en;
 
+	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
+
 	IP_VS_DBG(6, "ip_vs_lblcr_schedule(): Scheduling...\n");
 
 	/* First look in our cache */
 	read_lock(&svc->sched_lock);
-	en = ip_vs_lblcr_get(tbl, iph->daddr);
+	en = ip_vs_lblcr_get(svc->af, tbl, &iph.daddr);
 	if (en) {
 		/* We only hold a read lock, but this is atomic */
 		en->lastuse = jiffies;
@@ -673,7 +688,7 @@
 		}
 
 		/* The cache entry is invalid, time to schedule */
-		dest = __ip_vs_lblcr_schedule(svc, iph);
+		dest = __ip_vs_lblcr_schedule(svc);
 		if (!dest) {
 			IP_VS_DBG(1, "no destination available\n");
 			read_unlock(&svc->sched_lock);
@@ -691,7 +706,7 @@
 		goto out;
 
 	/* No cache entry, time to schedule */
-	dest = __ip_vs_lblcr_schedule(svc, iph);
+	dest = __ip_vs_lblcr_schedule(svc);
 	if (!dest) {
 		IP_VS_DBG(1, "no destination available\n");
 		return NULL;
@@ -699,15 +714,13 @@
 
 	/* If we fail to create a cache entry, we'll just use the valid dest */
 	write_lock(&svc->sched_lock);
-	ip_vs_lblcr_new(tbl, iph->daddr, dest);
+	ip_vs_lblcr_new(tbl, &iph.daddr, dest);
 	write_unlock(&svc->sched_lock);
 
 out:
-	IP_VS_DBG(6, "LBLCR: destination IP address %u.%u.%u.%u "
-		  "--> server %u.%u.%u.%u:%d\n",
-		  NIPQUAD(iph->daddr),
-		  NIPQUAD(dest->addr.ip),
-		  ntohs(dest->port));
+	IP_VS_DBG_BUF(6, "LBLCR: destination IP address %s --> server %s:%d\n",
+		      IP_VS_DBG_ADDR(svc->af, &iph.daddr),
+		      IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port));
 
 	return dest;
 }
@@ -722,9 +735,6 @@
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_lblcr_scheduler.n_list),
-#ifdef CONFIG_IP_VS_IPV6
-	.supports_ipv6 =	0,
-#endif
 	.init_service =		ip_vs_lblcr_init_svc,
 	.done_service =		ip_vs_lblcr_done_svc,
 	.schedule =		ip_vs_lblcr_schedule,
diff --git a/net/netfilter/ipvs/ip_vs_lc.c b/net/netfilter/ipvs/ip_vs_lc.c
index b69f808..51912ca 100644
--- a/net/netfilter/ipvs/ip_vs_lc.c
+++ b/net/netfilter/ipvs/ip_vs_lc.c
@@ -81,9 +81,6 @@
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_lc_scheduler.n_list),
-#ifdef CONFIG_IP_VS_IPV6
-	.supports_ipv6 =	1,
-#endif
 	.schedule =		ip_vs_lc_schedule,
 };
 
diff --git a/net/netfilter/ipvs/ip_vs_nq.c b/net/netfilter/ipvs/ip_vs_nq.c
index 9a2d803..6758ad2 100644
--- a/net/netfilter/ipvs/ip_vs_nq.c
+++ b/net/netfilter/ipvs/ip_vs_nq.c
@@ -116,9 +116,6 @@
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_nq_scheduler.n_list),
-#ifdef CONFIG_IP_VS_IPV6
-	.supports_ipv6 =	1,
-#endif
 	.schedule =		ip_vs_nq_schedule,
 };
 
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index 0791f9e..a01520e 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -164,26 +164,21 @@
 	if (ih == NULL)
 		sprintf(buf, "%s TRUNCATED", pp->name);
 	else if (ih->frag_off & htons(IP_OFFSET))
-		sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag",
-			pp->name, NIPQUAD(ih->saddr),
-			NIPQUAD(ih->daddr));
+		sprintf(buf, "%s %pI4->%pI4 frag",
+			pp->name, &ih->saddr, &ih->daddr);
 	else {
 		__be16 _ports[2], *pptr
 ;
 		pptr = skb_header_pointer(skb, offset + ih->ihl*4,
 					  sizeof(_ports), _ports);
 		if (pptr == NULL)
-			sprintf(buf, "%s TRUNCATED %u.%u.%u.%u->%u.%u.%u.%u",
-				pp->name,
-				NIPQUAD(ih->saddr),
-				NIPQUAD(ih->daddr));
+			sprintf(buf, "%s TRUNCATED %pI4->%pI4",
+				pp->name, &ih->saddr, &ih->daddr);
 		else
-			sprintf(buf, "%s %u.%u.%u.%u:%u->%u.%u.%u.%u:%u",
+			sprintf(buf, "%s %pI4:%u->%pI4:%u",
 				pp->name,
-				NIPQUAD(ih->saddr),
-				ntohs(pptr[0]),
-				NIPQUAD(ih->daddr),
-				ntohs(pptr[1]));
+				&ih->saddr, ntohs(pptr[0]),
+				&ih->daddr, ntohs(pptr[1]));
 	}
 
 	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
@@ -203,26 +198,21 @@
 	if (ih == NULL)
 		sprintf(buf, "%s TRUNCATED", pp->name);
 	else if (ih->nexthdr == IPPROTO_FRAGMENT)
-		sprintf(buf, "%s " NIP6_FMT "->" NIP6_FMT " frag",
-			pp->name, NIP6(ih->saddr),
-			NIP6(ih->daddr));
+		sprintf(buf, "%s %pI6->%pI6 frag",
+			pp->name, &ih->saddr, &ih->daddr);
 	else {
 		__be16 _ports[2], *pptr;
 
 		pptr = skb_header_pointer(skb, offset + sizeof(struct ipv6hdr),
 					  sizeof(_ports), _ports);
 		if (pptr == NULL)
-			sprintf(buf, "%s TRUNCATED " NIP6_FMT "->" NIP6_FMT,
-				pp->name,
-				NIP6(ih->saddr),
-				NIP6(ih->daddr));
+			sprintf(buf, "%s TRUNCATED %pI6->%pI6",
+				pp->name, &ih->saddr, &ih->daddr);
 		else
-			sprintf(buf, "%s " NIP6_FMT ":%u->" NIP6_FMT ":%u",
+			sprintf(buf, "%s %pI6:%u->%pI6:%u",
 				pp->name,
-				NIP6(ih->saddr),
-				ntohs(pptr[0]),
-				NIP6(ih->daddr),
-				ntohs(pptr[1]));
+				&ih->saddr, ntohs(pptr[0]),
+				&ih->daddr, ntohs(pptr[1]));
 	}
 
 	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
diff --git a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
index 80ab0c8..79f56c1 100644
--- a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
@@ -135,9 +135,8 @@
 	if (ih == NULL)
 		sprintf(buf, "%s TRUNCATED", pp->name);
 	else
-		sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u",
-			pp->name, NIPQUAD(ih->saddr),
-			NIPQUAD(ih->daddr));
+		sprintf(buf, "%s %pI4->%pI4",
+			pp->name, &ih->saddr, &ih->daddr);
 
 	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
 }
@@ -154,9 +153,8 @@
 	if (ih == NULL)
 		sprintf(buf, "%s TRUNCATED", pp->name);
 	else
-		sprintf(buf, "%s " NIP6_FMT "->" NIP6_FMT,
-			pp->name, NIP6(ih->saddr),
-			NIP6(ih->daddr));
+		sprintf(buf, "%s %pI6->%pI6",
+			pp->name, &ih->saddr, &ih->daddr);
 
 	printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
 }
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index dd4566e..8cba418 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -192,8 +192,8 @@
 	/* Adjust TCP checksums */
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
-					htonl(oldlen),
-					htonl(skb->len - tcphoff));
+					htons(oldlen),
+					htons(skb->len - tcphoff));
 	} else if (!cp->app) {
 		/* Only port and addr are changed, do fast csum update */
 		tcp_fast_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
@@ -267,8 +267,8 @@
 	 */
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr,
-					htonl(oldlen),
-					htonl(skb->len - tcphoff));
+					htons(oldlen),
+					htons(skb->len - tcphoff));
 	} else if (!cp->app) {
 		/* Only port and addr are changed, do fast csum update */
 		tcp_fast_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr,
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
index 6eb6039..d2930a7 100644
--- a/net/netfilter/ipvs/ip_vs_proto_udp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -203,8 +203,8 @@
 	 */
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
-					htonl(oldlen),
-					htonl(skb->len - udphoff));
+					htons(oldlen),
+					htons(skb->len - udphoff));
 	} else if (!cp->app && (udph->check != 0)) {
 		/* Only port and addr are changed, do fast csum update */
 		udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
@@ -279,8 +279,8 @@
 	 */
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
-					htonl(oldlen),
-					htonl(skb->len - udphoff));
+					htons(oldlen),
+					htons(skb->len - udphoff));
 	} else if (!cp->app && (udph->check != 0)) {
 		/* Only port and addr are changed, do fast csum update */
 		udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
diff --git a/net/netfilter/ipvs/ip_vs_rr.c b/net/netfilter/ipvs/ip_vs_rr.c
index a22195f..8fb51c1 100644
--- a/net/netfilter/ipvs/ip_vs_rr.c
+++ b/net/netfilter/ipvs/ip_vs_rr.c
@@ -89,9 +89,6 @@
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list),
-#ifdef CONFIG_IP_VS_IPV6
-	.supports_ipv6 =	1,
-#endif
 	.init_service =		ip_vs_rr_init_svc,
 	.update_service =	ip_vs_rr_update_svc,
 	.schedule =		ip_vs_rr_schedule,
diff --git a/net/netfilter/ipvs/ip_vs_sed.c b/net/netfilter/ipvs/ip_vs_sed.c
index 7d2f22f..691a6a0 100644
--- a/net/netfilter/ipvs/ip_vs_sed.c
+++ b/net/netfilter/ipvs/ip_vs_sed.c
@@ -118,9 +118,6 @@
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_sed_scheduler.n_list),
-#ifdef CONFIG_IP_VS_IPV6
-	.supports_ipv6 =	1,
-#endif
 	.schedule =		ip_vs_sed_schedule,
 };
 
diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c
index 1d96de2..0e53955 100644
--- a/net/netfilter/ipvs/ip_vs_sh.c
+++ b/net/netfilter/ipvs/ip_vs_sh.c
@@ -61,9 +61,16 @@
 /*
  *	Returns hash value for IPVS SH entry
  */
-static inline unsigned ip_vs_sh_hashkey(__be32 addr)
+static inline unsigned ip_vs_sh_hashkey(int af, const union nf_inet_addr *addr)
 {
-	return (ntohl(addr)*2654435761UL) & IP_VS_SH_TAB_MASK;
+	__be32 addr_fold = addr->ip;
+
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6)
+		addr_fold = addr->ip6[0]^addr->ip6[1]^
+			    addr->ip6[2]^addr->ip6[3];
+#endif
+	return (ntohl(addr_fold)*2654435761UL) & IP_VS_SH_TAB_MASK;
 }
 
 
@@ -71,9 +78,10 @@
  *      Get ip_vs_dest associated with supplied parameters.
  */
 static inline struct ip_vs_dest *
-ip_vs_sh_get(struct ip_vs_sh_bucket *tbl, __be32 addr)
+ip_vs_sh_get(int af, struct ip_vs_sh_bucket *tbl,
+	     const union nf_inet_addr *addr)
 {
-	return (tbl[ip_vs_sh_hashkey(addr)]).dest;
+	return (tbl[ip_vs_sh_hashkey(af, addr)]).dest;
 }
 
 
@@ -199,12 +207,14 @@
 {
 	struct ip_vs_dest *dest;
 	struct ip_vs_sh_bucket *tbl;
-	struct iphdr *iph = ip_hdr(skb);
+	struct ip_vs_iphdr iph;
+
+	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
 
 	IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n");
 
 	tbl = (struct ip_vs_sh_bucket *)svc->sched_data;
-	dest = ip_vs_sh_get(tbl, iph->saddr);
+	dest = ip_vs_sh_get(svc->af, tbl, &iph.saddr);
 	if (!dest
 	    || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
 	    || atomic_read(&dest->weight) <= 0
@@ -212,11 +222,10 @@
 		return NULL;
 	}
 
-	IP_VS_DBG(6, "SH: source IP address %u.%u.%u.%u "
-		  "--> server %u.%u.%u.%u:%d\n",
-		  NIPQUAD(iph->saddr),
-		  NIPQUAD(dest->addr.ip),
-		  ntohs(dest->port));
+	IP_VS_DBG_BUF(6, "SH: source IP address %s --> server %s:%d\n",
+		      IP_VS_DBG_ADDR(svc->af, &iph.saddr),
+		      IP_VS_DBG_ADDR(svc->af, &dest->addr),
+		      ntohs(dest->port));
 
 	return dest;
 }
@@ -231,9 +240,6 @@
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list	 =		LIST_HEAD_INIT(ip_vs_sh_scheduler.n_list),
-#ifdef CONFIG_IP_VS_IPV6
-	.supports_ipv6 =	0,
-#endif
 	.init_service =		ip_vs_sh_init_svc,
 	.done_service =		ip_vs_sh_done_svc,
 	.update_service =	ip_vs_sh_update_svc,
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index de5e7e1..6be5d4e 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -580,8 +580,8 @@
 		IP_VS_ERR("You probably need to specify IP address on "
 			  "multicast interface.\n");
 
-	IP_VS_DBG(7, "binding socket with (%s) %u.%u.%u.%u\n",
-		  ifname, NIPQUAD(addr));
+	IP_VS_DBG(7, "binding socket with (%s) %pI4\n",
+		  ifname, &addr);
 
 	/* Now bind the socket with the address of multicast interface */
 	sin.sin_family	     = AF_INET;
diff --git a/net/netfilter/ipvs/ip_vs_wlc.c b/net/netfilter/ipvs/ip_vs_wlc.c
index 8c596e7..57b452b 100644
--- a/net/netfilter/ipvs/ip_vs_wlc.c
+++ b/net/netfilter/ipvs/ip_vs_wlc.c
@@ -106,9 +106,6 @@
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_wlc_scheduler.n_list),
-#ifdef CONFIG_IP_VS_IPV6
-	.supports_ipv6 =	1,
-#endif
 	.schedule =		ip_vs_wlc_schedule,
 };
 
diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c
index 7ea92fe..2f618dc 100644
--- a/net/netfilter/ipvs/ip_vs_wrr.c
+++ b/net/netfilter/ipvs/ip_vs_wrr.c
@@ -213,9 +213,6 @@
 	.refcnt =		ATOMIC_INIT(0),
 	.module =		THIS_MODULE,
 	.n_list =		LIST_HEAD_INIT(ip_vs_wrr_scheduler.n_list),
-#ifdef CONFIG_IP_VS_IPV6
-	.supports_ipv6 =	1,
-#endif
 	.init_service =		ip_vs_wrr_init_svc,
 	.done_service =		ip_vs_wrr_done_svc,
 	.update_service =	ip_vs_wrr_update_svc,
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index e90d52f..425ab144 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -82,14 +82,13 @@
 
 			if (ip_route_output_key(&init_net, &rt, &fl)) {
 				spin_unlock(&dest->dst_lock);
-				IP_VS_DBG_RL("ip_route_output error, "
-					     "dest: %u.%u.%u.%u\n",
-					     NIPQUAD(dest->addr.ip));
+				IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n",
+					     &dest->addr.ip);
 				return NULL;
 			}
 			__ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst));
-			IP_VS_DBG(10, "new dst %u.%u.%u.%u, refcnt=%d, rtos=%X\n",
-				  NIPQUAD(dest->addr.ip),
+			IP_VS_DBG(10, "new dst %pI4, refcnt=%d, rtos=%X\n",
+				  &dest->addr.ip,
 				  atomic_read(&rt->u.dst.__refcnt), rtos);
 		}
 		spin_unlock(&dest->dst_lock);
@@ -104,8 +103,8 @@
 		};
 
 		if (ip_route_output_key(&init_net, &rt, &fl)) {
-			IP_VS_DBG_RL("ip_route_output error, dest: "
-				     "%u.%u.%u.%u\n", NIPQUAD(cp->daddr.ip));
+			IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n",
+				     &cp->daddr.ip);
 			return NULL;
 		}
 	}
@@ -141,14 +140,13 @@
 								 NULL, &fl);
 			if (!rt) {
 				spin_unlock(&dest->dst_lock);
-				IP_VS_DBG_RL("ip6_route_output error, "
-					     "dest: " NIP6_FMT "\n",
-					     NIP6(dest->addr.in6));
+				IP_VS_DBG_RL("ip6_route_output error, dest: %pI6\n",
+					     &dest->addr.in6);
 				return NULL;
 			}
 			__ip_vs_dst_set(dest, 0, dst_clone(&rt->u.dst));
-			IP_VS_DBG(10, "new dst " NIP6_FMT ", refcnt=%d\n",
-				  NIP6(dest->addr.in6),
+			IP_VS_DBG(10, "new dst %pI6, refcnt=%d\n",
+				  &dest->addr.in6,
 				  atomic_read(&rt->u.dst.__refcnt));
 		}
 		spin_unlock(&dest->dst_lock);
@@ -167,8 +165,8 @@
 
 		rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
 		if (!rt) {
-			IP_VS_DBG_RL("ip6_route_output error, dest: "
-				     NIP6_FMT "\n", NIP6(cp->daddr.in6));
+			IP_VS_DBG_RL("ip6_route_output error, dest: %pI6\n",
+				     &cp->daddr.in6);
 			return NULL;
 		}
 	}
@@ -237,8 +235,8 @@
 	EnterFunction(10);
 
 	if (ip_route_output_key(&init_net, &rt, &fl)) {
-		IP_VS_DBG_RL("ip_vs_bypass_xmit(): ip_route_output error, "
-			     "dest: %u.%u.%u.%u\n", NIPQUAD(iph->daddr));
+		IP_VS_DBG_RL("ip_vs_bypass_xmit(): ip_route_output error, dest: %pI4\n",
+			     &iph->daddr);
 		goto tx_error_icmp;
 	}
 
@@ -301,8 +299,8 @@
 
 	rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl);
 	if (!rt) {
-		IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): ip6_route_output error, "
-			     "dest: " NIP6_FMT "\n", NIP6(iph->daddr));
+		IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): ip6_route_output error, dest: %pI6\n",
+			     &iph->daddr);
 		goto tx_error_icmp;
 	}
 
diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c
index b92df5c..9fe8982 100644
--- a/net/netfilter/nf_conntrack_acct.c
+++ b/net/netfilter/nf_conntrack_acct.c
@@ -35,7 +35,7 @@
 		.data		= &init_net.ct.sysctl_acct,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{}
 };
diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
index 38aedee..4f8fcf4 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -30,6 +30,7 @@
 MODULE_DESCRIPTION("Amanda connection tracking module");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ip_conntrack_amanda");
+MODULE_ALIAS_NFCT_HELPER("amanda");
 
 module_param(master_timeout, uint, 0600);
 MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 233fdd2..7e83f74 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -39,13 +39,13 @@
 #include <net/netfilter/nf_conntrack_extend.h>
 #include <net/netfilter/nf_conntrack_acct.h>
 #include <net/netfilter/nf_nat.h>
+#include <net/netfilter/nf_nat_core.h>
 
 #define NF_CONNTRACK_VERSION	"0.5.0"
 
-unsigned int
-(*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
-				  enum nf_nat_manip_type manip,
-				  struct nlattr *attr) __read_mostly;
+int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
+				      enum nf_nat_manip_type manip,
+				      struct nlattr *attr) __read_mostly;
 EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook);
 
 DEFINE_SPINLOCK(nf_conntrack_lock);
@@ -181,7 +181,8 @@
 	NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
 	NF_CT_ASSERT(!timer_pending(&ct->timeout));
 
-	nf_conntrack_event(IPCT_DESTROY, ct);
+	if (!test_bit(IPS_DYING_BIT, &ct->status))
+		nf_conntrack_event(IPCT_DESTROY, ct);
 	set_bit(IPS_DYING_BIT, &ct->status);
 
 	/* To make sure we don't get any weird locking issues here:
@@ -586,14 +587,7 @@
 		nf_conntrack_get(&ct->master->ct_general);
 		NF_CT_STAT_INC(net, expect_new);
 	} else {
-		struct nf_conntrack_helper *helper;
-
-		helper = __nf_ct_helper_find(&repl_tuple);
-		if (helper) {
-			help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
-			if (help)
-				rcu_assign_pointer(help->helper, helper);
-		}
+		__nf_ct_try_assign_helper(ct, GFP_ATOMIC);
 		NF_CT_STAT_INC(net, new);
 	}
 
@@ -770,7 +764,6 @@
 			      const struct nf_conntrack_tuple *newreply)
 {
 	struct nf_conn_help *help = nfct_help(ct);
-	struct nf_conntrack_helper *helper;
 
 	/* Should be unconfirmed, so not in hash table yet */
 	NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
@@ -783,23 +776,7 @@
 		return;
 
 	rcu_read_lock();
-	helper = __nf_ct_helper_find(newreply);
-	if (helper == NULL) {
-		if (help)
-			rcu_assign_pointer(help->helper, NULL);
-		goto out;
-	}
-
-	if (help == NULL) {
-		help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
-		if (help == NULL)
-			goto out;
-	} else {
-		memset(&help->help, 0, sizeof(help->help));
-	}
-
-	rcu_assign_pointer(help->helper, helper);
-out:
+	__nf_ct_try_assign_helper(ct, GFP_ATOMIC);
 	rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
@@ -994,8 +971,20 @@
 }
 EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup);
 
+struct __nf_ct_flush_report {
+	u32 pid;
+	int report;
+};
+
 static int kill_all(struct nf_conn *i, void *data)
 {
+	struct __nf_ct_flush_report *fr = (struct __nf_ct_flush_report *)data;
+
+	/* get_next_corpse sets the dying bit for us */
+	nf_conntrack_event_report(IPCT_DESTROY,
+				  i,
+				  fr->pid,
+				  fr->report);
 	return 1;
 }
 
@@ -1009,9 +998,13 @@
 }
 EXPORT_SYMBOL_GPL(nf_ct_free_hashtable);
 
-void nf_conntrack_flush(struct net *net)
+void nf_conntrack_flush(struct net *net, u32 pid, int report)
 {
-	nf_ct_iterate_cleanup(net, kill_all, NULL);
+	struct __nf_ct_flush_report fr = {
+		.pid 	= pid,
+		.report = report,
+	};
+	nf_ct_iterate_cleanup(net, kill_all, &fr);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_flush);
 
@@ -1027,7 +1020,7 @@
 	nf_ct_event_cache_flush(net);
 	nf_conntrack_ecache_fini(net);
  i_see_dead_people:
-	nf_conntrack_flush(net);
+	nf_conntrack_flush(net, 0, 0);
 	if (atomic_read(&net->ct.count) != 0) {
 		schedule();
 		goto i_see_dead_people;
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c
index a5f5e2e..dee4190 100644
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -35,9 +35,17 @@
 __nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache)
 {
 	if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct)
-	    && ecache->events)
-		atomic_notifier_call_chain(&nf_conntrack_chain, ecache->events,
-				    ecache->ct);
+	    && ecache->events) {
+		struct nf_ct_event item = {
+			.ct 	= ecache->ct,
+			.pid	= 0,
+			.report	= 0
+		};
+
+		atomic_notifier_call_chain(&nf_conntrack_chain,
+					   ecache->events,
+					   &item);
+	}
 
 	ecache->events = 0;
 	nf_ct_put(ecache->ct);
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 37a703b..3a8a34a 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -362,7 +362,7 @@
 	return 1;
 }
 
-int nf_ct_expect_related(struct nf_conntrack_expect *expect)
+static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
 {
 	const struct nf_conntrack_expect_policy *p;
 	struct nf_conntrack_expect *i;
@@ -371,11 +371,8 @@
 	struct net *net = nf_ct_exp_net(expect);
 	struct hlist_node *n;
 	unsigned int h;
-	int ret;
+	int ret = 0;
 
-	NF_CT_ASSERT(master_help);
-
-	spin_lock_bh(&nf_conntrack_lock);
 	if (!master_help->helper) {
 		ret = -ESHUTDOWN;
 		goto out;
@@ -409,18 +406,50 @@
 			printk(KERN_WARNING
 			       "nf_conntrack: expectation table full\n");
 		ret = -EMFILE;
-		goto out;
 	}
+out:
+	return ret;
+}
+
+int nf_ct_expect_related(struct nf_conntrack_expect *expect)
+{
+	int ret;
+
+	spin_lock_bh(&nf_conntrack_lock);
+	ret = __nf_ct_expect_check(expect);
+	if (ret < 0)
+		goto out;
 
 	nf_ct_expect_insert(expect);
+	atomic_inc(&expect->use);
+	spin_unlock_bh(&nf_conntrack_lock);
 	nf_ct_expect_event(IPEXP_NEW, expect);
-	ret = 0;
+	nf_ct_expect_put(expect);
+	return ret;
 out:
 	spin_unlock_bh(&nf_conntrack_lock);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_related);
 
+int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, 
+				u32 pid, int report)
+{
+	int ret;
+
+	spin_lock_bh(&nf_conntrack_lock);
+	ret = __nf_ct_expect_check(expect);
+	if (ret < 0)
+		goto out;
+	nf_ct_expect_insert(expect);
+out:
+	spin_unlock_bh(&nf_conntrack_lock);
+	if (ret == 0)
+		nf_ct_expect_event_report(IPEXP_NEW, expect, pid, report);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
+
 #ifdef CONFIG_PROC_FS
 struct ct_expect_iter_state {
 	struct seq_net_private p;
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 4f71071..00fecc3 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -29,6 +29,7 @@
 MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
 MODULE_DESCRIPTION("ftp connection tracking helper");
 MODULE_ALIAS("ip_conntrack_ftp");
+MODULE_ALIAS_NFCT_HELPER("ftp");
 
 /* This is slow, but it's simple. --RR */
 static char *ftp_buffer;
@@ -357,7 +358,7 @@
 	int ret;
 	u32 seq;
 	int dir = CTINFO2DIR(ctinfo);
-	unsigned int matchlen, matchoff;
+	unsigned int uninitialized_var(matchlen), uninitialized_var(matchoff);
 	struct nf_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info;
 	struct nf_conntrack_expect *exp;
 	union nf_inet_addr *daddr;
@@ -427,10 +428,8 @@
 		   connection tracking, not packet filtering.
 		   However, it is necessary for accurate tracking in
 		   this case. */
-		if (net_ratelimit())
-			printk("conntrack_ftp: partial %s %u+%u\n",
-			       search[dir][i].pattern,
-			       ntohl(th->seq), datalen);
+		pr_debug("conntrack_ftp: partial %s %u+%u\n",
+			 search[dir][i].pattern,  ntohl(th->seq), datalen);
 		ret = NF_DROP;
 		goto out;
 	} else if (found == 0) { /* No match */
@@ -462,16 +461,13 @@
 		   different IP address.  Simply don't record it for
 		   NAT. */
 		if (cmd.l3num == PF_INET) {
-			pr_debug("conntrack_ftp: NOT RECORDING: " NIPQUAD_FMT
-				 " != " NIPQUAD_FMT "\n",
-				 NIPQUAD(cmd.u3.ip),
-				 NIPQUAD(ct->tuplehash[dir].tuple.src.u3.ip));
+			pr_debug("conntrack_ftp: NOT RECORDING: %pI4 != %pI4\n",
+				 &cmd.u3.ip,
+				 &ct->tuplehash[dir].tuple.src.u3.ip);
 		} else {
-			pr_debug("conntrack_ftp: NOT RECORDING: " NIP6_FMT
-				 " != " NIP6_FMT "\n",
-				 NIP6(*((struct in6_addr *)cmd.u3.ip6)),
-				 NIP6(*((struct in6_addr *)
-					ct->tuplehash[dir].tuple.src.u3.ip6)));
+			pr_debug("conntrack_ftp: NOT RECORDING: %pI6 != %pI6\n",
+				 cmd.u3.ip6,
+				 ct->tuplehash[dir].tuple.src.u3.ip6);
 		}
 
 		/* Thanks to Cristiano Lincoln Mattos
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index c1504f7..687bd63 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -850,10 +850,8 @@
 	    get_h225_addr(ct, *data, &setup->destCallSignalAddress,
 			  &addr, &port) &&
 	    memcmp(&addr, &ct->tuplehash[!dir].tuple.src.u3, sizeof(addr))) {
-		pr_debug("nf_ct_q931: set destCallSignalAddress "
-			 NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n",
-			 NIP6(*(struct in6_addr *)&addr), ntohs(port),
-			 NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.src.u3),
+		pr_debug("nf_ct_q931: set destCallSignalAddress %pI6:%hu->%pI6:%hu\n",
+			 &addr, ntohs(port), &ct->tuplehash[!dir].tuple.src.u3,
 			 ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port));
 		ret = set_h225_addr(skb, data, dataoff,
 				    &setup->destCallSignalAddress,
@@ -868,10 +866,8 @@
 	    get_h225_addr(ct, *data, &setup->sourceCallSignalAddress,
 			  &addr, &port) &&
 	    memcmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3, sizeof(addr))) {
-		pr_debug("nf_ct_q931: set sourceCallSignalAddress "
-			 NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n",
-			 NIP6(*(struct in6_addr *)&addr), ntohs(port),
-			 NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.dst.u3),
+		pr_debug("nf_ct_q931: set sourceCallSignalAddress %pI6:%hu->%pI6:%hu\n",
+			 &addr, ntohs(port), &ct->tuplehash[!dir].tuple.dst.u3,
 			 ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port));
 		ret = set_h225_addr(skb, data, dataoff,
 				    &setup->sourceCallSignalAddress,
@@ -1831,3 +1827,4 @@
 MODULE_DESCRIPTION("H.323 connection tracking helper");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ip_conntrack_h323");
+MODULE_ALIAS_NFCT_HELPER("h323");
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index c39b6a9..a51bdac 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -45,7 +45,7 @@
 		(__force __u16)tuple->src.u.all) % nf_ct_helper_hsize;
 }
 
-struct nf_conntrack_helper *
+static struct nf_conntrack_helper *
 __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
 {
 	struct nf_conntrack_helper *helper;
@@ -63,7 +63,6 @@
 	}
 	return NULL;
 }
-EXPORT_SYMBOL_GPL(__nf_ct_helper_find);
 
 struct nf_conntrack_helper *
 __nf_conntrack_helper_find_byname(const char *name)
@@ -95,6 +94,35 @@
 }
 EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
 
+int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags)
+{
+	int ret = 0;
+	struct nf_conntrack_helper *helper;
+	struct nf_conn_help *help = nfct_help(ct);
+
+	helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+	if (helper == NULL) {
+		if (help)
+			rcu_assign_pointer(help->helper, NULL);
+		goto out;
+	}
+
+	if (help == NULL) {
+		help = nf_ct_helper_ext_add(ct, flags);
+		if (help == NULL) {
+			ret = -ENOMEM;
+			goto out;
+		}
+	} else {
+		memset(&help->help, 0, sizeof(help->help));
+	}
+
+	rcu_assign_pointer(help->helper, helper);
+out:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
+
 static inline int unhelp(struct nf_conntrack_tuple_hash *i,
 			 const struct nf_conntrack_helper *me)
 {
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index 20633fd..409c8be 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -41,6 +41,7 @@
 MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ip_conntrack_irc");
+MODULE_ALIAS_NFCT_HELPER("irc");
 
 module_param_array(ports, ushort, &ports_c, 0400);
 MODULE_PARM_DESC(ports, "port numbers of IRC servers");
@@ -156,9 +157,9 @@
 		/* we have at least (19+MINMATCHLEN)-5 bytes valid data left */
 
 		iph = ip_hdr(skb);
-		pr_debug("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u\n",
-			 NIPQUAD(iph->saddr), ntohs(th->source),
-			 NIPQUAD(iph->daddr), ntohs(th->dest));
+		pr_debug("DCC found in master %pI4:%u %pI4:%u\n",
+			 &iph->saddr, ntohs(th->source),
+			 &iph->daddr, ntohs(th->dest));
 
 		for (i = 0; i < ARRAY_SIZE(dccprotos); i++) {
 			if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) {
@@ -185,10 +186,9 @@
 			    tuple->dst.u3.ip != htonl(dcc_ip)) {
 				if (net_ratelimit())
 					printk(KERN_WARNING
-						"Forged DCC command from "
-						"%u.%u.%u.%u: %u.%u.%u.%u:%u\n",
-						NIPQUAD(tuple->src.u3.ip),
-						HIPQUAD(dcc_ip), dcc_port);
+						"Forged DCC command from %pI4: %pI4:%u\n",
+						&tuple->src.u3.ip,
+						&dcc_ip, dcc_port);
 				continue;
 			}
 
diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c
index 08404e6..5af4273 100644
--- a/net/netfilter/nf_conntrack_netbios_ns.c
+++ b/net/netfilter/nf_conntrack_netbios_ns.c
@@ -37,6 +37,7 @@
 MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ip_conntrack_netbios_ns");
+MODULE_ALIAS_NFCT_HELPER("netbios_ns");
 
 static unsigned int timeout __read_mostly = 3;
 module_param(timeout, uint, 0400);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 5f4a651..00e8c27 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -105,16 +105,14 @@
 	struct nf_conntrack_l3proto *l3proto;
 	struct nf_conntrack_l4proto *l4proto;
 
-	l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);
+	l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
 	ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto);
-	nf_ct_l3proto_put(l3proto);
 
 	if (unlikely(ret < 0))
 		return ret;
 
-	l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum);
+	l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
 	ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto);
-	nf_ct_l4proto_put(l4proto);
 
 	return ret;
 }
@@ -151,11 +149,9 @@
 	struct nlattr *nest_proto;
 	int ret;
 
-	l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct));
-	if (!l4proto->to_nlattr) {
-		nf_ct_l4proto_put(l4proto);
+	l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
+	if (!l4proto->to_nlattr)
 		return 0;
-	}
 
 	nest_proto = nla_nest_start(skb, CTA_PROTOINFO | NLA_F_NESTED);
 	if (!nest_proto)
@@ -163,14 +159,11 @@
 
 	ret = l4proto->to_nlattr(skb, nest_proto, ct);
 
-	nf_ct_l4proto_put(l4proto);
-
 	nla_nest_end(skb, nest_proto);
 
 	return ret;
 
 nla_put_failure:
-	nf_ct_l4proto_put(l4proto);
 	return -1;
 }
 
@@ -184,7 +177,6 @@
 	if (!help)
 		return 0;
 
-	rcu_read_lock();
 	helper = rcu_dereference(help->helper);
 	if (!helper)
 		goto out;
@@ -199,11 +191,9 @@
 
 	nla_nest_end(skb, nest_helper);
 out:
-	rcu_read_unlock();
 	return 0;
 
 nla_put_failure:
-	rcu_read_unlock();
 	return -1;
 }
 
@@ -420,7 +410,8 @@
 	struct nlmsghdr *nlh;
 	struct nfgenmsg *nfmsg;
 	struct nlattr *nest_parms;
-	struct nf_conn *ct = (struct nf_conn *)ptr;
+	struct nf_ct_event *item = (struct nf_ct_event *)ptr;
+	struct nf_conn *ct = item->ct;
 	struct sk_buff *skb;
 	unsigned int type;
 	sk_buff_data_t b;
@@ -453,7 +444,7 @@
 	b = skb->tail;
 
 	type |= NFNL_SUBSYS_CTNETLINK << 8;
-	nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
+	nlh   = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg));
 	nfmsg = NLMSG_DATA(nlh);
 
 	nlh->nlmsg_flags    = flags;
@@ -461,6 +452,7 @@
 	nfmsg->version	= NFNETLINK_V0;
 	nfmsg->res_id	= 0;
 
+	rcu_read_lock();
 	nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);
 	if (!nest_parms)
 		goto nla_put_failure;
@@ -517,13 +509,15 @@
 	    && ctnetlink_dump_mark(skb, ct) < 0)
 		goto nla_put_failure;
 #endif
+	rcu_read_unlock();
 
 	nlh->nlmsg_len = skb->tail - b;
-	nfnetlink_send(skb, 0, group, 0);
+	nfnetlink_send(skb, item->pid, group, item->report);
 	return NOTIFY_DONE;
 
-nlmsg_failure:
 nla_put_failure:
+	rcu_read_unlock();
+nlmsg_failure:
 	kfree_skb(skb);
 	return NOTIFY_DONE;
 }
@@ -729,7 +723,9 @@
 		err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3);
 	else {
 		/* Flush the whole table */
-		nf_conntrack_flush(&init_net);
+		nf_conntrack_flush(&init_net, 
+				   NETLINK_CB(skb).pid, 
+				   nlmsg_report(nlh));
 		return 0;
 	}
 
@@ -750,6 +746,14 @@
 		}
 	}
 
+	nf_conntrack_event_report(IPCT_DESTROY,
+				  ct,
+				  NETLINK_CB(skb).pid,
+				  nlmsg_report(nlh));
+
+	/* death_by_timeout would report the event again */
+	set_bit(IPS_DYING_BIT, &ct->status);
+
 	nf_ct_kill(ct);
 	nf_ct_put(ct);
 
@@ -795,8 +799,10 @@
 		return -ENOMEM;
 	}
 
+	rcu_read_lock();
 	err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq,
 				  IPCTNL_MSG_CT_NEW, 1, ct);
+	rcu_read_unlock();
 	nf_ct_put(ct);
 	if (err <= 0)
 		goto free;
@@ -922,8 +928,22 @@
 	}
 
 	helper = __nf_conntrack_helper_find_byname(helpname);
-	if (helper == NULL)
+	if (helper == NULL) {
+#ifdef CONFIG_MODULES
+		spin_unlock_bh(&nf_conntrack_lock);
+
+		if (request_module("nfct-helper-%s", helpname) < 0) {
+			spin_lock_bh(&nf_conntrack_lock);
+			return -EOPNOTSUPP;
+		}
+
+		spin_lock_bh(&nf_conntrack_lock);
+		helper = __nf_conntrack_helper_find_byname(helpname);
+		if (helper)
+			return -EAGAIN;
+#endif
 		return -EOPNOTSUPP;
+	}
 
 	if (help) {
 		if (help->helper == helper)
@@ -1079,15 +1099,38 @@
 	return 0;
 }
 
+static inline void
+ctnetlink_event_report(struct nf_conn *ct, u32 pid, int report)
+{
+	unsigned int events = 0;
+
+	if (test_bit(IPS_EXPECTED_BIT, &ct->status))
+		events |= IPCT_RELATED;
+	else
+		events |= IPCT_NEW;
+
+	nf_conntrack_event_report(IPCT_STATUS |
+				  IPCT_HELPER |
+				  IPCT_REFRESH |
+				  IPCT_PROTOINFO |
+				  IPCT_NATSEQADJ |
+				  IPCT_MARK |
+				  events,
+				  ct,
+				  pid,
+				  report);
+}
+
 static int
 ctnetlink_create_conntrack(struct nlattr *cda[],
 			   struct nf_conntrack_tuple *otuple,
 			   struct nf_conntrack_tuple *rtuple,
-			   struct nf_conn *master_ct)
+			   struct nf_conn *master_ct,
+			   u32 pid,
+			   int report)
 {
 	struct nf_conn *ct;
 	int err = -EINVAL;
-	struct nf_conn_help *help;
 	struct nf_conntrack_helper *helper;
 
 	ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC);
@@ -1102,16 +1145,55 @@
 	ct->status |= IPS_CONFIRMED;
 
 	rcu_read_lock();
-	helper = __nf_ct_helper_find(rtuple);
-	if (helper) {
-		help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
-		if (help == NULL) {
+ 	if (cda[CTA_HELP]) {
+ 		char *helpname;
+ 
+ 		err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
+ 		if (err < 0) {
 			rcu_read_unlock();
-			err = -ENOMEM;
 			goto err;
 		}
-		/* not in hash table yet so not strictly necessary */
-		rcu_assign_pointer(help->helper, helper);
+
+		helper = __nf_conntrack_helper_find_byname(helpname);
+		if (helper == NULL) {
+			rcu_read_unlock();
+#ifdef CONFIG_MODULES
+			if (request_module("nfct-helper-%s", helpname) < 0) {
+				err = -EOPNOTSUPP;
+				goto err;
+			}
+
+			rcu_read_lock();
+			helper = __nf_conntrack_helper_find_byname(helpname);
+			if (helper) {
+				rcu_read_unlock();
+				err = -EAGAIN;
+				goto err;
+			}
+			rcu_read_unlock();
+#endif
+			err = -EOPNOTSUPP;
+			goto err;
+		} else {
+			struct nf_conn_help *help;
+
+			help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
+			if (help == NULL) {
+				rcu_read_unlock();
+				err = -ENOMEM;
+				goto err;
+			}
+
+			/* not in hash table yet so not strictly necessary */
+			rcu_assign_pointer(help->helper, helper);
+		}
+	} else {
+		/* try an implicit helper assignation */
+		err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC);
+		if (err < 0) {
+			rcu_read_unlock();
+			goto err;
+		}
 	}
 
 	if (cda[CTA_STATUS]) {
@@ -1151,9 +1233,12 @@
 		ct->master = master_ct;
 	}
 
+	nf_conntrack_get(&ct->ct_general);
 	add_timer(&ct->timeout);
 	nf_conntrack_hash_insert(ct);
 	rcu_read_unlock();
+	ctnetlink_event_report(ct, pid, report);
+	nf_ct_put(ct);
 
 	return 0;
 
@@ -1209,7 +1294,7 @@
 				goto out_unlock;
 			}
 			master_ct = nf_ct_tuplehash_to_ctrack(master_h);
-			atomic_inc(&master_ct->ct_general.use);
+			nf_conntrack_get(&master_ct->ct_general);
 		}
 
 		err = -ENOENT;
@@ -1217,9 +1302,10 @@
 			err = ctnetlink_create_conntrack(cda,
 							 &otuple,
 							 &rtuple,
-							 master_ct);
+							 master_ct,
+							 NETLINK_CB(skb).pid,
+							 nlmsg_report(nlh));
 		spin_unlock_bh(&nf_conntrack_lock);
-
 		if (err < 0 && master_ct)
 			nf_ct_put(master_ct);
 
@@ -1231,6 +1317,8 @@
 	 * so there's no need to increase the refcount */
 	err = -EEXIST;
 	if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
+		struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
+
 		/* we only allow nat config for new conntracks */
 		if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
 			err = -EOPNOTSUPP;
@@ -1241,8 +1329,19 @@
 			err = -EOPNOTSUPP;
 			goto out_unlock;
 		}
-		err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h),
-						 cda);
+
+		err = ctnetlink_change_conntrack(ct, cda);
+		if (err == 0) {
+			nf_conntrack_get(&ct->ct_general);
+			spin_unlock_bh(&nf_conntrack_lock);
+			ctnetlink_event_report(ct,
+					       NETLINK_CB(skb).pid,
+					       nlmsg_report(nlh));
+			nf_ct_put(ct);
+		} else
+			spin_unlock_bh(&nf_conntrack_lock);
+
+		return err;
 	}
 
 out_unlock:
@@ -1293,16 +1392,14 @@
 	if (!nest_parms)
 		goto nla_put_failure;
 
-	l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);
+	l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
 	ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto);
-	nf_ct_l3proto_put(l3proto);
 
 	if (unlikely(ret < 0))
 		goto nla_put_failure;
 
-	l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum);
+	l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
 	ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto);
-	nf_ct_l4proto_put(l4proto);
 	if (unlikely(ret < 0))
 		goto nla_put_failure;
 
@@ -1379,7 +1476,8 @@
 {
 	struct nlmsghdr *nlh;
 	struct nfgenmsg *nfmsg;
-	struct nf_conntrack_expect *exp = (struct nf_conntrack_expect *)ptr;
+	struct nf_exp_event *item = (struct nf_exp_event *)ptr;
+	struct nf_conntrack_expect *exp = item->exp;
 	struct sk_buff *skb;
 	unsigned int type;
 	sk_buff_data_t b;
@@ -1401,7 +1499,7 @@
 	b = skb->tail;
 
 	type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
-	nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
+	nlh   = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg));
 	nfmsg = NLMSG_DATA(nlh);
 
 	nlh->nlmsg_flags    = flags;
@@ -1409,15 +1507,18 @@
 	nfmsg->version	    = NFNETLINK_V0;
 	nfmsg->res_id	    = 0;
 
+	rcu_read_lock();
 	if (ctnetlink_exp_dump_expect(skb, exp) < 0)
 		goto nla_put_failure;
+	rcu_read_unlock();
 
 	nlh->nlmsg_len = skb->tail - b;
-	nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0);
+	nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, item->report);
 	return NOTIFY_DONE;
 
-nlmsg_failure:
 nla_put_failure:
+	rcu_read_unlock();
+nlmsg_failure:
 	kfree_skb(skb);
 	return NOTIFY_DONE;
 }
@@ -1521,9 +1622,11 @@
 	if (!skb2)
 		goto out;
 
+	rcu_read_lock();
 	err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid,
 				      nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
 				      1, exp);
+	rcu_read_unlock();
 	if (err <= 0)
 		goto free;
 
@@ -1624,7 +1727,7 @@
 }
 
 static int
-ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3)
+ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3, u32 pid, int report)
 {
 	struct nf_conntrack_tuple tuple, mask, master_tuple;
 	struct nf_conntrack_tuple_hash *h = NULL;
@@ -1653,7 +1756,7 @@
 
 	if (!help || !help->helper) {
 		/* such conntrack hasn't got any helper, abort */
-		err = -EINVAL;
+		err = -EOPNOTSUPP;
 		goto out;
 	}
 
@@ -1671,7 +1774,7 @@
 	memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3));
 	exp->mask.src.u.all = mask.src.u.all;
 
-	err = nf_ct_expect_related(exp);
+	err = nf_ct_expect_related_report(exp, pid, report);
 	nf_ct_expect_put(exp);
 
 out:
@@ -1704,8 +1807,12 @@
 	if (!exp) {
 		spin_unlock_bh(&nf_conntrack_lock);
 		err = -ENOENT;
-		if (nlh->nlmsg_flags & NLM_F_CREATE)
-			err = ctnetlink_create_expect(cda, u3);
+		if (nlh->nlmsg_flags & NLM_F_CREATE) {
+			err = ctnetlink_create_expect(cda,
+						      u3,
+						      NETLINK_CB(skb).pid,
+						      nlmsg_report(nlh));
+		}
 		return err;
 	}
 
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 1bc3001..9e169ef 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -37,6 +37,7 @@
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
 MODULE_ALIAS("ip_conntrack_pptp");
+MODULE_ALIAS_NFCT_HELPER("pptp");
 
 static DEFINE_SPINLOCK(nf_pptp_lock);
 
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index dbe680a..4be80d7 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -67,7 +67,7 @@
 		.data		= &nf_ct_generic_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name	= 0
@@ -80,7 +80,7 @@
 		.data		= &nf_ct_generic_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name	= 0
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 4ab62ad..1b279f9 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -341,7 +341,7 @@
 	return rv;
 }
 
-static void nf_ct_proto_gre_fini(void)
+static void __exit nf_ct_proto_gre_fini(void)
 {
 	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4);
 	unregister_pernet_gen_subsys(proto_gre_net_id, &proto_gre_net_ops);
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index ae8c260..74e0379 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -317,7 +317,7 @@
 		goto out;
 	}
 
-	old_state = new_state = SCTP_CONNTRACK_MAX;
+	old_state = new_state = SCTP_CONNTRACK_NONE;
 	write_lock_bh(&sctp_lock);
 	for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) {
 		/* Special cases of Verification tag check (Sec 8.5.1) */
@@ -548,49 +548,49 @@
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_CLOSED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_cookie_wait",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_COOKIE_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_cookie_echoed",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_COOKIE_ECHOED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_established",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_ESTABLISHED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_shutdown_sent",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_shutdown_recd",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_sctp_timeout_shutdown_ack_sent",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name = 0
@@ -604,49 +604,49 @@
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_CLOSED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_cookie_wait",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_COOKIE_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_cookie_echoed",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_COOKIE_ECHOED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_established",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_ESTABLISHED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_shutdown_sent",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_shutdown_recd",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_sctp_timeout_shutdown_ack_sent",
 		.data		= &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name = 0
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index f947ec4..a1edb9c 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -1192,70 +1192,70 @@
 		.data		= &tcp_timeouts[TCP_CONNTRACK_SYN_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_syn_recv",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_SYN_RECV],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_established",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_ESTABLISHED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_fin_wait",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_FIN_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_close_wait",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_CLOSE_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_last_ack",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_LAST_ACK],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_time_wait",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_TIME_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_close",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_CLOSE],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_max_retrans",
 		.data		= &nf_ct_tcp_timeout_max_retrans,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_tcp_timeout_unacknowledged",
 		.data		= &nf_ct_tcp_timeout_unacknowledged,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name	= NET_NF_CONNTRACK_TCP_LOOSE,
@@ -1263,7 +1263,7 @@
 		.data		= &nf_ct_tcp_loose,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_NF_CONNTRACK_TCP_BE_LIBERAL,
@@ -1271,7 +1271,7 @@
 		.data           = &nf_ct_tcp_be_liberal,
 		.maxlen         = sizeof(unsigned int),
 		.mode           = 0644,
-		.proc_handler   = &proc_dointvec,
+		.proc_handler   = proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_NF_CONNTRACK_TCP_MAX_RETRANS,
@@ -1279,7 +1279,7 @@
 		.data		= &nf_ct_tcp_max_retrans,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= 0
@@ -1293,63 +1293,63 @@
 		.data		= &tcp_timeouts[TCP_CONNTRACK_SYN_SENT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_syn_recv",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_SYN_RECV],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_established",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_ESTABLISHED],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_fin_wait",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_FIN_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_close_wait",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_CLOSE_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_last_ack",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_LAST_ACK],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_time_wait",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_TIME_WAIT],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_close",
 		.data		= &tcp_timeouts[TCP_CONNTRACK_CLOSE],
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_tcp_timeout_max_retrans",
 		.data		= &nf_ct_tcp_timeout_max_retrans,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_LOOSE,
@@ -1357,7 +1357,7 @@
 		.data		= &nf_ct_tcp_loose,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL,
@@ -1365,7 +1365,7 @@
 		.data		= &nf_ct_tcp_be_liberal,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS,
@@ -1373,7 +1373,7 @@
 		.data		= &nf_ct_tcp_max_retrans,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= 0
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 7c2ca48..2b8b1f5 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -143,14 +143,14 @@
 		.data		= &nf_ct_udp_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "nf_conntrack_udp_timeout_stream",
 		.data		= &nf_ct_udp_timeout_stream,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name	= 0
@@ -163,14 +163,14 @@
 		.data		= &nf_ct_udp_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.procname	= "ip_conntrack_udp_timeout_stream",
 		.data		= &nf_ct_udp_timeout_stream,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name	= 0
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
index d22d839e..4579d8d 100644
--- a/net/netfilter/nf_conntrack_proto_udplite.c
+++ b/net/netfilter/nf_conntrack_proto_udplite.c
@@ -151,7 +151,7 @@
 		.data		= &nf_ct_udplite_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name	= CTL_UNNUMBERED,
@@ -159,7 +159,7 @@
 		.data		= &nf_ct_udplite_timeout_stream,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies,
 	},
 	{
 		.ctl_name	= 0
diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c
index a94294b..dcfecbb 100644
--- a/net/netfilter/nf_conntrack_sane.c
+++ b/net/netfilter/nf_conntrack_sane.c
@@ -30,6 +30,7 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>");
 MODULE_DESCRIPTION("SANE connection tracking helper");
+MODULE_ALIAS_NFCT_HELPER("sane");
 
 static char *sane_buffer;
 
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 6813f1c..4b57216 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -28,6 +28,7 @@
 MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
 MODULE_DESCRIPTION("SIP connection tracking helper");
 MODULE_ALIAS("ip_conntrack_sip");
+MODULE_ALIAS_NFCT_HELPER("sip");
 
 #define MAX_PORTS	8
 static unsigned short ports[MAX_PORTS];
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 98106d4..f37b9b7 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -336,7 +336,7 @@
 		.data		= &nf_conntrack_max,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_NF_CONNTRACK_COUNT,
@@ -344,7 +344,7 @@
 		.data		= &init_net.ct.count,
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name       = NET_NF_CONNTRACK_BUCKETS,
@@ -352,7 +352,7 @@
 		.data           = &nf_conntrack_htable_size,
 		.maxlen         = sizeof(unsigned int),
 		.mode           = 0444,
-		.proc_handler   = &proc_dointvec,
+		.proc_handler   = proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_NF_CONNTRACK_CHECKSUM,
@@ -360,7 +360,7 @@
 		.data		= &init_net.ct.sysctl_checksum,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= NET_NF_CONNTRACK_LOG_INVALID,
@@ -368,8 +368,8 @@
 		.data		= &init_net.ct.sysctl_log_invalid,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &log_invalid_proto_min,
 		.extra2		= &log_invalid_proto_max,
 	},
@@ -379,7 +379,7 @@
 		.data		= &nf_ct_expect_max,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{ .ctl_name = 0 }
 };
@@ -393,7 +393,7 @@
 		.data		= &nf_conntrack_max,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{ .ctl_name = 0 }
 };
diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c
index f57f6e7..46e646b 100644
--- a/net/netfilter/nf_conntrack_tftp.c
+++ b/net/netfilter/nf_conntrack_tftp.c
@@ -22,6 +22,7 @@
 MODULE_DESCRIPTION("TFTP connection tracking helper");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ip_conntrack_tftp");
+MODULE_ALIAS_NFCT_HELPER("tftp");
 
 #define MAX_PORTS 8
 static unsigned short ports[MAX_PORTS];
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 41e0105..fa49dc7 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -30,6 +30,7 @@
 #include <linux/random.h>
 #include <net/sock.h>
 #include <net/netfilter/nf_log.h>
+#include <net/netfilter/nfnetlink_log.h>
 
 #include <asm/atomic.h>
 
@@ -474,8 +475,9 @@
 	if (skb->sk) {
 		read_lock_bh(&skb->sk->sk_callback_lock);
 		if (skb->sk->sk_socket && skb->sk->sk_socket->file) {
-			__be32 uid = htonl(skb->sk->sk_socket->file->f_uid);
-			__be32 gid = htonl(skb->sk->sk_socket->file->f_gid);
+			struct file *file = skb->sk->sk_socket->file;
+			__be32 uid = htonl(file->f_cred->fsuid);
+			__be32 gid = htonl(file->f_cred->fsgid);
 			/* need to unlock here since NLA_PUT may goto */
 			read_unlock_bh(&skb->sk->sk_callback_lock);
 			NLA_PUT_BE32(inst->skb, NFULA_UID, uid);
@@ -533,7 +535,7 @@
 };
 
 /* log handler for internal netfilter logging api */
-static void
+void
 nfulnl_log_packet(u_int8_t pf,
 		  unsigned int hooknum,
 		  const struct sk_buff *skb,
@@ -648,6 +650,7 @@
 	/* FIXME: statistics */
 	goto unlock_and_release;
 }
+EXPORT_SYMBOL_GPL(nfulnl_log_packet);
 
 static int
 nfulnl_rcv_nl_event(struct notifier_block *this,
diff --git a/net/netfilter/xt_NFLOG.c b/net/netfilter/xt_NFLOG.c
index 50e3a52..a57c5cf 100644
--- a/net/netfilter/xt_NFLOG.c
+++ b/net/netfilter/xt_NFLOG.c
@@ -13,6 +13,7 @@
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_NFLOG.h>
 #include <net/netfilter/nf_log.h>
+#include <net/netfilter/nfnetlink_log.h>
 
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
 MODULE_DESCRIPTION("Xtables: packet logging to netlink using NFLOG");
@@ -31,8 +32,8 @@
 	li.u.ulog.group	     = info->group;
 	li.u.ulog.qthreshold = info->threshold;
 
-	nf_log_packet(par->family, par->hooknum, skb, par->in,
-	              par->out, &li, "%s", info->prefix);
+	nfulnl_log_packet(par->family, par->hooknum, skb, par->in,
+			  par->out, &li, info->prefix);
 	return XT_CONTINUE;
 }
 
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c
index e5d3e86..0989f29a 100644
--- a/net/netfilter/xt_dccp.c
+++ b/net/netfilter/xt_dccp.c
@@ -45,10 +45,8 @@
 	unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh);
 	unsigned int i;
 
-	if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) {
-		*hotdrop = true;
-		return false;
-	}
+	if (dh->dccph_doff * 4 < __dccp_hdr_len(dh))
+		goto invalid;
 
 	if (!optlen)
 		return false;
@@ -57,9 +55,7 @@
 	op = skb_header_pointer(skb, protoff + optoff, optlen, dccp_optbuf);
 	if (op == NULL) {
 		/* If we don't have the whole header, drop packet. */
-		spin_unlock_bh(&dccp_buflock);
-		*hotdrop = true;
-		return false;
+		goto partial;
 	}
 
 	for (i = 0; i < optlen; ) {
@@ -76,6 +72,12 @@
 
 	spin_unlock_bh(&dccp_buflock);
 	return false;
+
+partial:
+	spin_unlock_bh(&dccp_buflock);
+invalid:
+	*hotdrop = true;
+	return false;
 }
 
 
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 6fc4292..f97fded 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -893,23 +893,21 @@
 
 	switch (family) {
 	case NFPROTO_IPV4:
-		return seq_printf(s, "%ld %u.%u.%u.%u:%u->"
-				     "%u.%u.%u.%u:%u %u %u %u\n",
+		return seq_printf(s, "%ld %pI4:%u->%pI4:%u %u %u %u\n",
 				 (long)(ent->expires - jiffies)/HZ,
-				 NIPQUAD(ent->dst.ip.src),
+				 &ent->dst.ip.src,
 				 ntohs(ent->dst.src_port),
-				 NIPQUAD(ent->dst.ip.dst),
+				 &ent->dst.ip.dst,
 				 ntohs(ent->dst.dst_port),
 				 ent->rateinfo.credit, ent->rateinfo.credit_cap,
 				 ent->rateinfo.cost);
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
 	case NFPROTO_IPV6:
-		return seq_printf(s, "%ld " NIP6_FMT ":%u->"
-				     NIP6_FMT ":%u %u %u %u\n",
+		return seq_printf(s, "%ld %pI6:%u->%pI6:%u %u %u %u\n",
 				 (long)(ent->expires - jiffies)/HZ,
-				 NIP6(*(struct in6_addr *)&ent->dst.ip6.src),
+				 &ent->dst.ip6.src,
 				 ntohs(ent->dst.src_port),
-				 NIP6(*(struct in6_addr *)&ent->dst.ip6.dst),
+				 &ent->dst.ip6.dst,
 				 ntohs(ent->dst.dst_port),
 				 ent->rateinfo.credit, ent->rateinfo.credit_cap,
 				 ent->rateinfo.cost);
diff --git a/net/netfilter/xt_iprange.c b/net/netfilter/xt_iprange.c
index 7ac54ea..501f9b6 100644
--- a/net/netfilter/xt_iprange.c
+++ b/net/netfilter/xt_iprange.c
@@ -26,12 +26,11 @@
 		if ((ntohl(iph->saddr) < ntohl(info->src.min_ip)
 			  || ntohl(iph->saddr) > ntohl(info->src.max_ip))
 			 ^ !!(info->flags & IPRANGE_SRC_INV)) {
-			pr_debug("src IP %u.%u.%u.%u NOT in range %s"
-				 "%u.%u.%u.%u-%u.%u.%u.%u\n",
-				 NIPQUAD(iph->saddr),
+			pr_debug("src IP %pI4 NOT in range %s%pI4-%pI4\n",
+				 &iph->saddr,
 				 info->flags & IPRANGE_SRC_INV ? "(INV) " : "",
-				 NIPQUAD(info->src.min_ip),
-				 NIPQUAD(info->src.max_ip));
+				 &info->src.min_ip,
+				 &info->src.max_ip);
 			return false;
 		}
 	}
@@ -39,12 +38,11 @@
 		if ((ntohl(iph->daddr) < ntohl(info->dst.min_ip)
 			  || ntohl(iph->daddr) > ntohl(info->dst.max_ip))
 			 ^ !!(info->flags & IPRANGE_DST_INV)) {
-			pr_debug("dst IP %u.%u.%u.%u NOT in range %s"
-				 "%u.%u.%u.%u-%u.%u.%u.%u\n",
-				 NIPQUAD(iph->daddr),
+			pr_debug("dst IP %pI4 NOT in range %s%pI4-%pI4\n",
+				 &iph->daddr,
 				 info->flags & IPRANGE_DST_INV ? "(INV) " : "",
-				 NIPQUAD(info->dst.min_ip),
-				 NIPQUAD(info->dst.max_ip));
+				 &info->dst.min_ip,
+				 &info->dst.max_ip);
 			return false;
 		}
 	}
@@ -63,12 +61,11 @@
 		m |= ntohl(iph->saddr) > ntohl(info->src_max.ip);
 		m ^= !!(info->flags & IPRANGE_SRC_INV);
 		if (m) {
-			pr_debug("src IP " NIPQUAD_FMT " NOT in range %s"
-			         NIPQUAD_FMT "-" NIPQUAD_FMT "\n",
-			         NIPQUAD(iph->saddr),
+			pr_debug("src IP %pI4 NOT in range %s%pI4-%pI4\n",
+			         &iph->saddr,
 			         (info->flags & IPRANGE_SRC_INV) ? "(INV) " : "",
-			         NIPQUAD(info->src_max.ip),
-			         NIPQUAD(info->src_max.ip));
+			         &info->src_max.ip,
+			         &info->src_max.ip);
 			return false;
 		}
 	}
@@ -77,12 +74,11 @@
 		m |= ntohl(iph->daddr) > ntohl(info->dst_max.ip);
 		m ^= !!(info->flags & IPRANGE_DST_INV);
 		if (m) {
-			pr_debug("dst IP " NIPQUAD_FMT " NOT in range %s"
-			         NIPQUAD_FMT "-" NIPQUAD_FMT "\n",
-			         NIPQUAD(iph->daddr),
+			pr_debug("dst IP %pI4 NOT in range %s%pI4-%pI4\n",
+			         &iph->daddr,
 			         (info->flags & IPRANGE_DST_INV) ? "(INV) " : "",
-			         NIPQUAD(info->dst_min.ip),
-			         NIPQUAD(info->dst_max.ip));
+			         &info->dst_min.ip,
+			         &info->dst_max.ip);
 			return false;
 		}
 	}
diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c
index f19ebd9..22b2a5e 100644
--- a/net/netfilter/xt_owner.c
+++ b/net/netfilter/xt_owner.c
@@ -34,12 +34,12 @@
 		return false;
 
 	if (info->match & IPT_OWNER_UID)
-		if ((filp->f_uid != info->uid) ^
+		if ((filp->f_cred->fsuid != info->uid) ^
 		    !!(info->invert & IPT_OWNER_UID))
 			return false;
 
 	if (info->match & IPT_OWNER_GID)
-		if ((filp->f_gid != info->gid) ^
+		if ((filp->f_cred->fsgid != info->gid) ^
 		    !!(info->invert & IPT_OWNER_GID))
 			return false;
 
@@ -60,12 +60,12 @@
 		return false;
 
 	if (info->match & IP6T_OWNER_UID)
-		if ((filp->f_uid != info->uid) ^
+		if ((filp->f_cred->fsuid != info->uid) ^
 		    !!(info->invert & IP6T_OWNER_UID))
 			return false;
 
 	if (info->match & IP6T_OWNER_GID)
-		if ((filp->f_gid != info->gid) ^
+		if ((filp->f_cred->fsgid != info->gid) ^
 		    !!(info->invert & IP6T_OWNER_GID))
 			return false;
 
@@ -93,14 +93,14 @@
 		       (XT_OWNER_UID | XT_OWNER_GID)) == 0;
 
 	if (info->match & XT_OWNER_UID)
-		if ((filp->f_uid >= info->uid_min &&
-		    filp->f_uid <= info->uid_max) ^
+		if ((filp->f_cred->fsuid >= info->uid_min &&
+		    filp->f_cred->fsuid <= info->uid_max) ^
 		    !(info->invert & XT_OWNER_UID))
 			return false;
 
 	if (info->match & XT_OWNER_GID)
-		if ((filp->f_gid >= info->gid_min &&
-		    filp->f_gid <= info->gid_max) ^
+		if ((filp->f_cred->fsgid >= info->gid_min &&
+		    filp->f_cred->fsgid <= info->gid_max) ^
 		    !(info->invert & XT_OWNER_GID))
 			return false;
 
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index 280c471..fe80b61 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -72,9 +72,6 @@
 struct recent_table {
 	struct list_head	list;
 	char			name[XT_RECENT_NAME_LEN];
-#ifdef CONFIG_PROC_FS
-	struct proc_dir_entry	*proc_old, *proc;
-#endif
 	unsigned int		refcnt;
 	unsigned int		entries;
 	struct list_head	lru_list;
@@ -284,6 +281,9 @@
 {
 	const struct xt_recent_mtinfo *info = par->matchinfo;
 	struct recent_table *t;
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *pde;
+#endif
 	unsigned i;
 	bool ret = false;
 
@@ -318,25 +318,25 @@
 	for (i = 0; i < ip_list_hash_size; i++)
 		INIT_LIST_HEAD(&t->iphash[i]);
 #ifdef CONFIG_PROC_FS
-	t->proc = proc_create_data(t->name, ip_list_perms, recent_proc_dir,
+	pde = proc_create_data(t->name, ip_list_perms, recent_proc_dir,
 		  &recent_mt_fops, t);
-	if (t->proc == NULL) {
+	if (pde == NULL) {
 		kfree(t);
 		goto out;
 	}
+	pde->uid = ip_list_uid;
+	pde->gid = ip_list_gid;
 #ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
-	t->proc_old = proc_create_data(t->name, ip_list_perms, proc_old_dir,
+	pde = proc_create_data(t->name, ip_list_perms, proc_old_dir,
 		      &recent_old_fops, t);
-	if (t->proc_old == NULL) {
+	if (pde == NULL) {
 		remove_proc_entry(t->name, proc_old_dir);
 		kfree(t);
 		goto out;
 	}
-	t->proc_old->uid   = ip_list_uid;
-	t->proc_old->gid   = ip_list_gid;
+	pde->uid = ip_list_uid;
+	pde->gid = ip_list_gid;
 #endif
-	t->proc->uid       = ip_list_uid;
-	t->proc->gid       = ip_list_gid;
 #endif
 	spin_lock_bh(&recent_lock);
 	list_add_tail(&t->list, &tables);
@@ -422,13 +422,11 @@
 
 	i = (e->index - 1) % ip_pkt_list_tot;
 	if (e->family == NFPROTO_IPV4)
-		seq_printf(seq, "src=" NIPQUAD_FMT " ttl: %u last_seen: %lu "
-			   "oldest_pkt: %u", NIPQUAD(e->addr.ip), e->ttl,
-			   e->stamps[i], e->index);
+		seq_printf(seq, "src=%pI4 ttl: %u last_seen: %lu oldest_pkt: %u",
+			   &e->addr.ip, e->ttl, e->stamps[i], e->index);
 	else
-		seq_printf(seq, "src=" NIP6_FMT " ttl: %u last_seen: %lu "
-			   "oldest_pkt: %u", NIP6(e->addr.in6), e->ttl,
-			   e->stamps[i], e->index);
+		seq_printf(seq, "src=%pI6 ttl: %u last_seen: %lu oldest_pkt: %u",
+			   &e->addr.in6, e->ttl, e->stamps[i], e->index);
 	for (i = 0; i < e->nstamps; i++)
 		seq_printf(seq, "%s %lu", i ? "," : "", e->stamps[i]);
 	seq_printf(seq, "\n");
diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c
index 249f6b9..834c6eb 100644
--- a/net/netlabel/netlabel_addrlist.c
+++ b/net/netlabel/netlabel_addrlist.c
@@ -337,7 +337,7 @@
 
 	if (dev != NULL)
 		audit_log_format(audit_buf, " netif=%s", dev);
-	audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr));
+	audit_log_format(audit_buf, " %s=%pI4", dir, &addr);
 	if (mask_val != 0xffffffff) {
 		u32 mask_len = 0;
 		while (mask_val > 0) {
@@ -371,7 +371,7 @@
 
 	if (dev != NULL)
 		audit_log_format(audit_buf, " netif=%s", dev);
-	audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, NIP6(*addr));
+	audit_log_format(audit_buf, " %s=%pI6", dir, addr);
 	if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
 		u32 mask_len = 0;
 		u32 mask_val;
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 0a0ef17..1821c5d 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -596,7 +596,6 @@
 /**
  * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
  * @skb: the skb to write to
- * @seq: the NETLINK sequence number
  * @cb: the NETLINK callback
  * @protocol: the NetLabel protocol to use in the message
  *
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 480184a..9eb895c 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -452,6 +452,10 @@
 	if (err < 0)
 		goto out_module;
 
+	local_bh_disable();
+	sock_prot_inuse_add(net, &netlink_proto, 1);
+	local_bh_enable();
+
 	nlk = nlk_sk(sock->sk);
 	nlk->module = module;
 out:
@@ -511,6 +515,9 @@
 	kfree(nlk->groups);
 	nlk->groups = NULL;
 
+	local_bh_disable();
+	sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1);
+	local_bh_enable();
 	sock_put(sk);
 	return 0;
 }
diff --git a/net/netlink/attr.c b/net/netlink/attr.c
index 2d106cf..56c3ce7 100644
--- a/net/netlink/attr.c
+++ b/net/netlink/attr.c
@@ -83,6 +83,12 @@
 		if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN + nla_len(nla))
 			return -ERANGE;
 		break;
+	case NLA_NESTED:
+		/* a nested attributes is allowed to be empty; if its not,
+		 * it must have a size of at least NLA_HDRLEN.
+		 */
+		if (attrlen == 0)
+			break;
 	default:
 		if (pt->len)
 			minlen = pt->len;
@@ -233,7 +239,7 @@
  *
  * Returns the number of bytes copied.
  */
-int nla_memcpy(void *dest, struct nlattr *src, int count)
+int nla_memcpy(void *dest, const struct nlattr *src, int count)
 {
 	int minlen = min_t(int, count, nla_len(src));
 
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 9f1ea4a..e9c05b8 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -609,7 +609,7 @@
 	} else {
 		source = &addr->fsa_ax25.sax25_call;
 
-		user = ax25_findbyuid(current->euid);
+		user = ax25_findbyuid(current_euid());
 		if (user) {
 			nr->user_addr   = user->call;
 			ax25_uid_put(user);
@@ -683,7 +683,7 @@
 		}
 		source = (ax25_address *)dev->dev_addr;
 
-		user = ax25_findbyuid(current->euid);
+		user = ax25_findbyuid(current_euid());
 		if (user) {
 			nr->user_addr   = user->call;
 			ax25_uid_put(user);
diff --git a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c
index 34c96c9..7b49591 100644
--- a/net/netrom/sysctl_net_netrom.c
+++ b/net/netrom/sysctl_net_netrom.c
@@ -41,8 +41,8 @@
 		.data		= &sysctl_netrom_default_path_quality,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_quality,
 		.extra2		= &max_quality
 	},
@@ -52,8 +52,8 @@
 		.data		= &sysctl_netrom_obsolescence_count_initialiser,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_obs,
 		.extra2		= &max_obs
 	},
@@ -63,8 +63,8 @@
 		.data		= &sysctl_netrom_network_ttl_initialiser,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_ttl,
 		.extra2		= &max_ttl
 	},
@@ -74,8 +74,8 @@
 		.data		= &sysctl_netrom_transport_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_t1,
 		.extra2		= &max_t1
 	},
@@ -85,8 +85,8 @@
 		.data		= &sysctl_netrom_transport_maximum_tries,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_n2,
 		.extra2		= &max_n2
 	},
@@ -96,8 +96,8 @@
 		.data		= &sysctl_netrom_transport_acknowledge_delay,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_t2,
 		.extra2		= &max_t2
 	},
@@ -107,8 +107,8 @@
 		.data		= &sysctl_netrom_transport_busy_delay,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_t4,
 		.extra2		= &max_t4
 	},
@@ -118,8 +118,8 @@
 		.data		= &sysctl_netrom_transport_requested_window_size,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_window,
 		.extra2		= &max_window
 	},
@@ -129,8 +129,8 @@
 		.data		= &sysctl_netrom_transport_no_activity_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_idle,
 		.extra2		= &max_idle
 	},
@@ -140,8 +140,8 @@
 		.data		= &sysctl_netrom_routing_control,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_route,
 		.extra2		= &max_route
 	},
@@ -151,8 +151,8 @@
 		.data		= &sysctl_netrom_link_fails_count,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_fails,
 		.extra2		= &max_fails
 	},
@@ -162,8 +162,8 @@
 		.data		= &sysctl_netrom_reset_circuit,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_reset,
 		.extra2		= &max_reset
 	},
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index c718e7e..5f94db2 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -872,6 +872,7 @@
 
 	write_lock_bh(&net->packet.sklist_lock);
 	sk_del_node_init(sk);
+	sock_prot_inuse_add(net, sk->sk_prot, -1);
 	write_unlock_bh(&net->packet.sklist_lock);
 
 	/*
@@ -1084,6 +1085,7 @@
 
 	write_lock_bh(&net->packet.sklist_lock);
 	sk_add_node(sk, &net->packet.sklist);
+	sock_prot_inuse_add(net, &packet_proto, 1);
 	write_unlock_bh(&net->packet.sklist_lock);
 	return(0);
 out:
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index 9d211f1..13cb323 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -67,9 +67,6 @@
 	struct phonet_protocol *pnp;
 	int err;
 
-	if (net != &init_net)
-		return -EAFNOSUPPORT;
-
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
@@ -352,9 +349,6 @@
 	struct sockaddr_pn sa;
 	u16 len;
 
-	if (dev_net(dev) != &init_net)
-		goto out;
-
 	/* check we have at least a full Phonet header */
 	if (!pskb_pull(skb, sizeof(struct phonethdr)))
 		goto out;
@@ -373,7 +367,7 @@
 	if (pn_sockaddr_get_addr(&sa) == 0)
 		goto out; /* currently, we cannot be device 0 */
 
-	sk = pn_find_sock_by_sa(&sa);
+	sk = pn_find_sock_by_sa(dev_net(dev), &sa);
 	if (sk == NULL) {
 		if (can_respond(skb)) {
 			send_obj_unreachable(skb);
diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c
index 803eeef..b0ceac2 100644
--- a/net/phonet/pep-gprs.c
+++ b/net/phonet/pep-gprs.c
@@ -40,23 +40,17 @@
 	void			(*old_data_ready)(struct sock *, int);
 	void			(*old_write_space)(struct sock *);
 
-	struct net_device	*net;
-	struct net_device_stats	stats;
-
-	struct sk_buff_head	tx_queue;
-	struct work_struct	tx_work;
-	spinlock_t		tx_lock;
-	unsigned		tx_max;
+	struct net_device	*dev;
 };
 
-static int gprs_type_trans(struct sk_buff *skb)
+static __be16 gprs_type_trans(struct sk_buff *skb)
 {
 	const u8 *pvfc;
 	u8 buf;
 
 	pvfc = skb_header_pointer(skb, 0, 1, &buf);
 	if (!pvfc)
-		return 0;
+		return htons(0);
 	/* Look at IP version field */
 	switch (*pvfc >> 4) {
 	case 4:
@@ -64,7 +58,15 @@
 	case 6:
 		return htons(ETH_P_IPV6);
 	}
-	return 0;
+	return htons(0);
+}
+
+static void gprs_writeable(struct gprs_dev *gp)
+{
+	struct net_device *dev = gp->dev;
+
+	if (pep_writeable(gp->sk))
+		netif_wake_queue(dev);
 }
 
 /*
@@ -73,18 +75,21 @@
 
 static void gprs_state_change(struct sock *sk)
 {
-	struct gprs_dev *dev = sk->sk_user_data;
+	struct gprs_dev *gp = sk->sk_user_data;
 
 	if (sk->sk_state == TCP_CLOSE_WAIT) {
-		netif_stop_queue(dev->net);
-		netif_carrier_off(dev->net);
+		struct net_device *dev = gp->dev;
+
+		netif_stop_queue(dev);
+		netif_carrier_off(dev);
 	}
 }
 
-static int gprs_recv(struct gprs_dev *dev, struct sk_buff *skb)
+static int gprs_recv(struct gprs_dev *gp, struct sk_buff *skb)
 {
+	struct net_device *dev = gp->dev;
 	int err = 0;
-	u16 protocol = gprs_type_trans(skb);
+	__be16 protocol = gprs_type_trans(skb);
 
 	if (!protocol) {
 		err = -EINVAL;
@@ -99,7 +104,7 @@
 		 * so wrap the IP packet as a single fragment of an head-less
 		 * socket buffer. The network stack will pull what it needs,
 		 * but at least, the whole IP payload is not memcpy'd. */
-		rskb = netdev_alloc_skb(dev->net, 0);
+		rskb = netdev_alloc_skb(dev, 0);
 		if (!rskb) {
 			err = -ENOBUFS;
 			goto drop;
@@ -123,9 +128,9 @@
 
 	skb->protocol = protocol;
 	skb_reset_mac_header(skb);
-	skb->dev = dev->net;
+	skb->dev = dev;
 
-	if (likely(dev->net->flags & IFF_UP)) {
+	if (likely(dev->flags & IFF_UP)) {
 		dev->stats.rx_packets++;
 		dev->stats.rx_bytes += skb->len;
 		netif_rx(skb);
@@ -143,26 +148,21 @@
 
 static void gprs_data_ready(struct sock *sk, int len)
 {
-	struct gprs_dev *dev = sk->sk_user_data;
+	struct gprs_dev *gp = sk->sk_user_data;
 	struct sk_buff *skb;
 
 	while ((skb = pep_read(sk)) != NULL) {
 		skb_orphan(skb);
-		gprs_recv(dev, skb);
+		gprs_recv(gp, skb);
 	}
 }
 
 static void gprs_write_space(struct sock *sk)
 {
-	struct gprs_dev *dev = sk->sk_user_data;
-	struct net_device *net = dev->net;
-	unsigned credits = pep_writeable(sk);
+	struct gprs_dev *gp = sk->sk_user_data;
 
-	spin_lock_bh(&dev->tx_lock);
-	dev->tx_max = credits;
-	if (credits > skb_queue_len(&dev->tx_queue) && netif_running(net))
-		netif_wake_queue(net);
-	spin_unlock_bh(&dev->tx_lock);
+	if (netif_running(gp->dev))
+		gprs_writeable(gp);
 }
 
 /*
@@ -173,22 +173,21 @@
 {
 	struct gprs_dev *gp = netdev_priv(dev);
 
-	gprs_write_space(gp->sk);
+	gprs_writeable(gp);
 	return 0;
 }
 
 static int gprs_close(struct net_device *dev)
 {
-	struct gprs_dev *gp = netdev_priv(dev);
-
 	netif_stop_queue(dev);
-	flush_work(&gp->tx_work);
 	return 0;
 }
 
-static int gprs_xmit(struct sk_buff *skb, struct net_device *net)
+static int gprs_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct gprs_dev *dev = netdev_priv(net);
+	struct gprs_dev *gp = netdev_priv(dev);
+	struct sock *sk = gp->sk;
+	int len, err;
 
 	switch (skb->protocol) {
 	case  htons(ETH_P_IP):
@@ -199,84 +198,50 @@
 		return 0;
 	}
 
-	spin_lock(&dev->tx_lock);
-	if (likely(skb_queue_len(&dev->tx_queue) < dev->tx_max)) {
-		skb_queue_tail(&dev->tx_queue, skb);
-		skb = NULL;
-	}
-	if (skb_queue_len(&dev->tx_queue) >= dev->tx_max)
-		netif_stop_queue(net);
-	spin_unlock(&dev->tx_lock);
-
-	schedule_work(&dev->tx_work);
-	if (unlikely(skb))
+	skb_orphan(skb);
+	skb_set_owner_w(skb, sk);
+	len = skb->len;
+	err = pep_write(sk, skb);
+	if (err) {
+		LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n",
+				dev->name, err);
+		dev->stats.tx_aborted_errors++;
+		dev->stats.tx_errors++;
 		dev_kfree_skb(skb);
+	} else {
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += len;
+	}
+
+	if (!pep_writeable(sk))
+		netif_stop_queue(dev);
 	return 0;
 }
 
-static void gprs_tx(struct work_struct *work)
-{
-	struct gprs_dev *dev = container_of(work, struct gprs_dev, tx_work);
-	struct sock *sk = dev->sk;
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&dev->tx_queue)) != NULL) {
-		int err;
-
-		dev->stats.tx_bytes += skb->len;
-		dev->stats.tx_packets++;
-
-		skb_orphan(skb);
-		skb_set_owner_w(skb, sk);
-
-		lock_sock(sk);
-		err = pep_write(sk, skb);
-		if (err) {
-			LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n",
-					dev->net->name, err);
-			dev->stats.tx_aborted_errors++;
-			dev->stats.tx_errors++;
-		}
-		release_sock(sk);
-	}
-
-	lock_sock(sk);
-	gprs_write_space(sk);
-	release_sock(sk);
-}
-
-static int gprs_set_mtu(struct net_device *net, int new_mtu)
+static int gprs_set_mtu(struct net_device *dev, int new_mtu)
 {
 	if ((new_mtu < 576) || (new_mtu > (PHONET_MAX_MTU - 11)))
 		return -EINVAL;
 
-	net->mtu = new_mtu;
+	dev->mtu = new_mtu;
 	return 0;
 }
 
-static struct net_device_stats *gprs_get_stats(struct net_device *net)
+static void gprs_setup(struct net_device *dev)
 {
-	struct gprs_dev *dev = netdev_priv(net);
+	dev->features		= NETIF_F_FRAGLIST;
+	dev->type		= ARPHRD_PHONET_PIPE;
+	dev->flags		= IFF_POINTOPOINT | IFF_NOARP;
+	dev->mtu		= GPRS_DEFAULT_MTU;
+	dev->hard_header_len	= 0;
+	dev->addr_len		= 0;
+	dev->tx_queue_len	= 10;
 
-	return &dev->stats;
-}
-
-static void gprs_setup(struct net_device *net)
-{
-	net->features		= NETIF_F_FRAGLIST;
-	net->type		= ARPHRD_NONE;
-	net->flags		= IFF_POINTOPOINT | IFF_NOARP;
-	net->mtu		= GPRS_DEFAULT_MTU;
-	net->hard_header_len	= 0;
-	net->addr_len		= 0;
-	net->tx_queue_len	= 10;
-
-	net->destructor		= free_netdev;
-	net->open		= gprs_open;
-	net->stop		= gprs_close;
-	net->hard_start_xmit	= gprs_xmit; /* mandatory */
-	net->change_mtu		= gprs_set_mtu;
-	net->get_stats		= gprs_get_stats;
+	dev->destructor		= free_netdev;
+	dev->open		= gprs_open;
+	dev->stop		= gprs_close;
+	dev->hard_start_xmit	= gprs_xmit; /* mandatory */
+	dev->change_mtu		= gprs_set_mtu;
 }
 
 /*
@@ -290,28 +255,25 @@
 int gprs_attach(struct sock *sk)
 {
 	static const char ifname[] = "gprs%d";
-	struct gprs_dev *dev;
-	struct net_device *net;
+	struct gprs_dev *gp;
+	struct net_device *dev;
 	int err;
 
 	if (unlikely(sk->sk_type == SOCK_STREAM))
 		return -EINVAL; /* need packet boundaries */
 
 	/* Create net device */
-	net = alloc_netdev(sizeof(*dev), ifname, gprs_setup);
-	if (!net)
+	dev = alloc_netdev(sizeof(*gp), ifname, gprs_setup);
+	if (!dev)
 		return -ENOMEM;
-	dev = netdev_priv(net);
-	dev->net = net;
-	dev->tx_max = 0;
-	spin_lock_init(&dev->tx_lock);
-	skb_queue_head_init(&dev->tx_queue);
-	INIT_WORK(&dev->tx_work, gprs_tx);
+	gp = netdev_priv(dev);
+	gp->sk = sk;
+	gp->dev = dev;
 
-	netif_stop_queue(net);
-	err = register_netdev(net);
+	netif_stop_queue(dev);
+	err = register_netdev(dev);
 	if (err) {
-		free_netdev(net);
+		free_netdev(dev);
 		return err;
 	}
 
@@ -325,40 +287,38 @@
 		err = -EINVAL;
 		goto out_rel;
 	}
-	sk->sk_user_data	= dev;
-	dev->old_state_change	= sk->sk_state_change;
-	dev->old_data_ready	= sk->sk_data_ready;
-	dev->old_write_space	= sk->sk_write_space;
+	sk->sk_user_data	= gp;
+	gp->old_state_change	= sk->sk_state_change;
+	gp->old_data_ready	= sk->sk_data_ready;
+	gp->old_write_space	= sk->sk_write_space;
 	sk->sk_state_change	= gprs_state_change;
 	sk->sk_data_ready	= gprs_data_ready;
 	sk->sk_write_space	= gprs_write_space;
 	release_sock(sk);
-
 	sock_hold(sk);
-	dev->sk = sk;
 
-	printk(KERN_DEBUG"%s: attached\n", net->name);
-	return net->ifindex;
+	printk(KERN_DEBUG"%s: attached\n", dev->name);
+	return dev->ifindex;
 
 out_rel:
 	release_sock(sk);
-	unregister_netdev(net);
+	unregister_netdev(dev);
 	return err;
 }
 
 void gprs_detach(struct sock *sk)
 {
-	struct gprs_dev *dev = sk->sk_user_data;
-	struct net_device *net = dev->net;
+	struct gprs_dev *gp = sk->sk_user_data;
+	struct net_device *dev = gp->dev;
 
 	lock_sock(sk);
 	sk->sk_user_data	= NULL;
-	sk->sk_state_change	= dev->old_state_change;
-	sk->sk_data_ready	= dev->old_data_ready;
-	sk->sk_write_space	= dev->old_write_space;
+	sk->sk_state_change	= gp->old_state_change;
+	sk->sk_data_ready	= gp->old_data_ready;
+	sk->sk_write_space	= gp->old_write_space;
 	release_sock(sk);
 
-	printk(KERN_DEBUG"%s: detached\n", net->name);
-	unregister_netdev(net);
+	printk(KERN_DEBUG"%s: detached\n", dev->name);
+	unregister_netdev(dev);
 	sock_put(sk);
 }
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index bc6d50f..bb3e678 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -225,6 +225,7 @@
 {
 	struct pep_sock *pn = pep_sk(sk);
 	struct pnpipehdr *hdr = pnp_hdr(skb);
+	int wake = 0;
 
 	if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
 		return -EINVAL;
@@ -241,16 +242,16 @@
 		case PN_LEGACY_FLOW_CONTROL:
 			switch (hdr->data[4]) {
 			case PEP_IND_BUSY:
-				pn->tx_credits = 0;
+				atomic_set(&pn->tx_credits, 0);
 				break;
 			case PEP_IND_READY:
-				pn->tx_credits = 1;
+				atomic_set(&pn->tx_credits, wake = 1);
 				break;
 			}
 			break;
 		case PN_ONE_CREDIT_FLOW_CONTROL:
 			if (hdr->data[4] == PEP_IND_READY)
-				pn->tx_credits = 1;
+				atomic_set(&pn->tx_credits, wake = 1);
 			break;
 		}
 		break;
@@ -258,10 +259,7 @@
 	case PN_PEP_IND_ID_MCFC_GRANT_CREDITS:
 		if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL)
 			break;
-		if (pn->tx_credits + hdr->data[4] > 0xff)
-			pn->tx_credits = 0xff;
-		else
-			pn->tx_credits += hdr->data[4];
+		atomic_add(wake = hdr->data[4], &pn->tx_credits);
 		break;
 
 	default:
@@ -269,7 +267,7 @@
 				(unsigned)hdr->data[1]);
 		return -EOPNOTSUPP;
 	}
-	if (pn->tx_credits)
+	if (wake)
 		sk->sk_write_space(sk);
 	return 0;
 }
@@ -343,7 +341,7 @@
 		}
 		/* fall through */
 	case PNS_PEP_DISABLE_REQ:
-		pn->tx_credits = 0;
+		atomic_set(&pn->tx_credits, 0);
 		pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
 		break;
 
@@ -390,7 +388,7 @@
 		/* fall through */
 	case PNS_PIPE_ENABLED_IND:
 		if (!pn_flow_safe(pn->tx_fc)) {
-			pn->tx_credits = 1;
+			atomic_set(&pn->tx_credits, 1);
 			sk->sk_write_space(sk);
 		}
 		if (sk->sk_state == TCP_ESTABLISHED)
@@ -504,8 +502,9 @@
 	newpn->pn_sk.resource = pn->pn_sk.resource;
 	skb_queue_head_init(&newpn->ctrlreq_queue);
 	newpn->pipe_handle = pipe_handle;
+	atomic_set(&newpn->tx_credits, 0);
 	newpn->peer_type = peer_type;
-	newpn->rx_credits = newpn->tx_credits = 0;
+	newpn->rx_credits = 0;
 	newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
 	newpn->init_enable = enabled;
 
@@ -821,14 +820,18 @@
 	struct pep_sock *pn = pep_sk(sk);
 	struct pnpipehdr *ph;
 
+	if (pn_flow_safe(pn->tx_fc) &&
+	    !atomic_add_unless(&pn->tx_credits, -1, 0)) {
+		kfree_skb(skb);
+		return -ENOBUFS;
+	}
+
 	skb_push(skb, 3);
 	skb_reset_transport_header(skb);
 	ph = pnp_hdr(skb);
 	ph->utid = 0;
 	ph->message_id = PNS_PIPE_DATA;
 	ph->pipe_handle = pn->pipe_handle;
-	if (pn_flow_safe(pn->tx_fc) && pn->tx_credits)
-		pn->tx_credits--;
 
 	return pn_skb_send(sk, skb, &pipe_srv);
 }
@@ -866,7 +869,7 @@
 	BUG_ON(sk->sk_state != TCP_ESTABLISHED);
 
 	/* Wait until flow control allows TX */
-	done = pn->tx_credits > 0;
+	done = atomic_read(&pn->tx_credits);
 	while (!done) {
 		DEFINE_WAIT(wait);
 
@@ -881,7 +884,7 @@
 
 		prepare_to_wait(&sk->sk_socket->wait, &wait,
 				TASK_INTERRUPTIBLE);
-		done = sk_wait_event(sk, &timeo, pn->tx_credits > 0);
+		done = sk_wait_event(sk, &timeo, atomic_read(&pn->tx_credits));
 		finish_wait(&sk->sk_socket->wait, &wait);
 
 		if (sk->sk_state != TCP_ESTABLISHED)
@@ -895,7 +898,8 @@
 			goto out;
 		skb_reserve(skb, MAX_PHONET_HEADER + 3);
 
-		if (sk->sk_state != TCP_ESTABLISHED || !pn->tx_credits)
+		if (sk->sk_state != TCP_ESTABLISHED ||
+		    !atomic_read(&pn->tx_credits))
 			goto disabled; /* sock_alloc_send_skb might sleep */
 	}
 
@@ -917,7 +921,7 @@
 {
 	struct pep_sock *pn = pep_sk(sk);
 
-	return (sk->sk_state == TCP_ESTABLISHED) ? pn->tx_credits : 0;
+	return atomic_read(&pn->tx_credits);
 }
 
 int pep_write(struct sock *sk, struct sk_buff *skb)
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index f93ff8e..5491bf5 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -76,7 +76,7 @@
 		dev = pnd->netdev;
 		BUG_ON(!dev);
 
-		if (dev_net(dev) == net &&
+		if (net_eq(dev_net(dev), net) &&
 			(dev->reg_state == NETREG_REGISTERED) &&
 			((pnd->netdev->flags & IFF_UP)) == IFF_UP)
 			break;
@@ -140,12 +140,14 @@
 	return addr;
 }
 
-int phonet_address_lookup(u8 addr)
+int phonet_address_lookup(struct net *net, u8 addr)
 {
 	struct phonet_device *pnd;
 
 	spin_lock_bh(&pndevs.lock);
 	list_for_each_entry(pnd, &pndevs.list, list) {
+		if (!net_eq(dev_net(pnd->netdev), net))
+			continue;
 		/* Don't allow unregistering devices! */
 		if ((pnd->netdev->reg_state != NETREG_REGISTERED) ||
 				((pnd->netdev->flags & IFF_UP)) != IFF_UP)
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index d817401..ada2a35 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -57,7 +57,7 @@
  * Find address based on socket address, match only certain fields.
  * Also grab sock if it was found. Remember to sock_put it later.
  */
-struct sock *pn_find_sock_by_sa(const struct sockaddr_pn *spn)
+struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
 {
 	struct hlist_node *node;
 	struct sock *sknode;
@@ -71,6 +71,8 @@
 		struct pn_sock *pn = pn_sk(sknode);
 		BUG_ON(!pn->sobject); /* unbound socket */
 
+		if (!net_eq(sock_net(sknode), net))
+			continue;
 		if (pn_port(obj)) {
 			/* Look up socket by port */
 			if (pn_port(pn->sobject) != pn_port(obj))
@@ -130,7 +132,7 @@
 
 	handle = pn_sockaddr_get_object((struct sockaddr_pn *)addr);
 	saddr = pn_addr(handle);
-	if (saddr && phonet_address_lookup(saddr))
+	if (saddr && phonet_address_lookup(sock_net(sk), saddr))
 		return -EADDRNOTAVAIL;
 
 	lock_sock(sk);
@@ -225,7 +227,7 @@
 	if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
 		return POLLHUP;
 
-	if (sk->sk_state == TCP_ESTABLISHED && pn->tx_credits)
+	if (sk->sk_state == TCP_ESTABLISHED && atomic_read(&pn->tx_credits))
 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 
 	return mask;
@@ -361,6 +363,7 @@
 int pn_sock_get_port(struct sock *sk, unsigned short sport)
 {
 	static int port_cur;
+	struct net *net = sock_net(sk);
 	struct pn_sock *pn = pn_sk(sk);
 	struct sockaddr_pn try_sa;
 	struct sock *tmpsk;
@@ -381,7 +384,7 @@
 				port_cur = pmin;
 
 			pn_sockaddr_set_port(&try_sa, port_cur);
-			tmpsk = pn_find_sock_by_sa(&try_sa);
+			tmpsk = pn_find_sock_by_sa(net, &try_sa);
 			if (tmpsk == NULL) {
 				sport = port_cur;
 				goto found;
@@ -391,7 +394,7 @@
 	} else {
 		/* try to find specific port */
 		pn_sockaddr_set_port(&try_sa, sport);
-		tmpsk = pn_find_sock_by_sa(&try_sa);
+		tmpsk = pn_find_sock_by_sa(net, &try_sa);
 		if (tmpsk == NULL)
 			/* No sock there! We can use that port... */
 			goto found;
diff --git a/net/phonet/sysctl.c b/net/phonet/sysctl.c
index 600a430..7b5749e 100644
--- a/net/phonet/sysctl.c
+++ b/net/phonet/sysctl.c
@@ -89,13 +89,13 @@
 		.data		= &local_port_range,
 		.maxlen		= sizeof(local_port_range),
 		.mode		= 0644,
-		.proc_handler	= &proc_local_port_range,
+		.proc_handler	= proc_local_port_range,
 		.strategy	= NULL,
 	},
 	{ .ctl_name = 0 }
 };
 
-struct ctl_path phonet_ctl_path[] = {
+static struct ctl_path phonet_ctl_path[] = {
 	{ .procname = "net", .ctl_name = CTL_NET, },
 	{ .procname = "phonet", .ctl_name = CTL_UNNUMBERED, },
 	{ },
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index bfdade7..84efde9 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -24,138 +24,318 @@
 MODULE_DESCRIPTION("Input layer to RF switch connector");
 MODULE_LICENSE("GPL");
 
-struct rfkill_task {
-	struct work_struct work;
-	enum rfkill_type type;
-	struct mutex mutex; /* ensures that task is serialized */
-	spinlock_t lock; /* for accessing last and desired state */
-	unsigned long last; /* last schedule */
-	enum rfkill_state desired_state; /* on/off */
+enum rfkill_input_master_mode {
+	RFKILL_INPUT_MASTER_DONOTHING = 0,
+	RFKILL_INPUT_MASTER_RESTORE = 1,
+	RFKILL_INPUT_MASTER_UNBLOCKALL = 2,
+	RFKILL_INPUT_MASTER_MAX,	/* marker */
 };
 
+/* Delay (in ms) between consecutive switch ops */
+#define RFKILL_OPS_DELAY 200
+
+static enum rfkill_input_master_mode rfkill_master_switch_mode =
+					RFKILL_INPUT_MASTER_UNBLOCKALL;
+module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0);
+MODULE_PARM_DESC(master_switch_mode,
+	"SW_RFKILL_ALL ON should: 0=do nothing; 1=restore; 2=unblock all");
+
+enum rfkill_global_sched_op {
+	RFKILL_GLOBAL_OP_EPO = 0,
+	RFKILL_GLOBAL_OP_RESTORE,
+	RFKILL_GLOBAL_OP_UNLOCK,
+	RFKILL_GLOBAL_OP_UNBLOCK,
+};
+
+/*
+ * Currently, the code marked with RFKILL_NEED_SWSET is inactive.
+ * If handling of EV_SW SW_WLAN/WWAN/BLUETOOTH/etc is needed in the
+ * future, when such events are added, that code will be necessary.
+ */
+
+struct rfkill_task {
+	struct delayed_work dwork;
+
+	/* ensures that task is serialized */
+	struct mutex mutex;
+
+	/* protects everything below */
+	spinlock_t lock;
+
+	/* pending regular switch operations (1=pending) */
+	unsigned long sw_pending[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
+
+#ifdef RFKILL_NEED_SWSET
+	/* set operation pending (1=pending) */
+	unsigned long sw_setpending[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
+
+	/* desired state for pending set operation (1=unblock) */
+	unsigned long sw_newstate[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
+#endif
+
+	/* should the state be complemented (1=yes) */
+	unsigned long sw_togglestate[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
+
+	bool global_op_pending;
+	enum rfkill_global_sched_op op;
+
+	/* last time it was scheduled */
+	unsigned long last_scheduled;
+};
+
+static void __rfkill_handle_global_op(enum rfkill_global_sched_op op)
+{
+	unsigned int i;
+
+	switch (op) {
+	case RFKILL_GLOBAL_OP_EPO:
+		rfkill_epo();
+		break;
+	case RFKILL_GLOBAL_OP_RESTORE:
+		rfkill_restore_states();
+		break;
+	case RFKILL_GLOBAL_OP_UNLOCK:
+		rfkill_remove_epo_lock();
+		break;
+	case RFKILL_GLOBAL_OP_UNBLOCK:
+		rfkill_remove_epo_lock();
+		for (i = 0; i < RFKILL_TYPE_MAX; i++)
+			rfkill_switch_all(i, RFKILL_STATE_UNBLOCKED);
+		break;
+	default:
+		/* memory corruption or bug, fail safely */
+		rfkill_epo();
+		WARN(1, "Unknown requested operation %d! "
+			"rfkill Emergency Power Off activated\n",
+			op);
+	}
+}
+
+#ifdef RFKILL_NEED_SWSET
+static void __rfkill_handle_normal_op(const enum rfkill_type type,
+			const bool sp, const bool s, const bool c)
+{
+	enum rfkill_state state;
+
+	if (sp)
+		state = (s) ? RFKILL_STATE_UNBLOCKED :
+			      RFKILL_STATE_SOFT_BLOCKED;
+	else
+		state = rfkill_get_global_state(type);
+
+	if (c)
+		state = rfkill_state_complement(state);
+
+	rfkill_switch_all(type, state);
+}
+#else
+static void __rfkill_handle_normal_op(const enum rfkill_type type,
+			const bool c)
+{
+	enum rfkill_state state;
+
+	state = rfkill_get_global_state(type);
+	if (c)
+		state = rfkill_state_complement(state);
+
+	rfkill_switch_all(type, state);
+}
+#endif
+
 static void rfkill_task_handler(struct work_struct *work)
 {
-	struct rfkill_task *task = container_of(work, struct rfkill_task, work);
+	struct rfkill_task *task = container_of(work,
+					struct rfkill_task, dwork.work);
+	bool doit = true;
 
 	mutex_lock(&task->mutex);
 
-	rfkill_switch_all(task->type, task->desired_state);
+	spin_lock_irq(&task->lock);
+	while (doit) {
+		if (task->global_op_pending) {
+			enum rfkill_global_sched_op op = task->op;
+			task->global_op_pending = false;
+			memset(task->sw_pending, 0, sizeof(task->sw_pending));
+			spin_unlock_irq(&task->lock);
+
+			__rfkill_handle_global_op(op);
+
+			/* make sure we do at least one pass with
+			 * !task->global_op_pending */
+			spin_lock_irq(&task->lock);
+			continue;
+		} else if (!rfkill_is_epo_lock_active()) {
+			unsigned int i = 0;
+
+			while (!task->global_op_pending &&
+						i < RFKILL_TYPE_MAX) {
+				if (test_and_clear_bit(i, task->sw_pending)) {
+					bool c;
+#ifdef RFKILL_NEED_SWSET
+					bool sp, s;
+					sp = test_and_clear_bit(i,
+							task->sw_setpending);
+					s = test_bit(i, task->sw_newstate);
+#endif
+					c = test_and_clear_bit(i,
+							task->sw_togglestate);
+					spin_unlock_irq(&task->lock);
+
+#ifdef RFKILL_NEED_SWSET
+					__rfkill_handle_normal_op(i, sp, s, c);
+#else
+					__rfkill_handle_normal_op(i, c);
+#endif
+
+					spin_lock_irq(&task->lock);
+				}
+				i++;
+			}
+		}
+		doit = task->global_op_pending;
+	}
+	spin_unlock_irq(&task->lock);
 
 	mutex_unlock(&task->mutex);
 }
 
-static void rfkill_task_epo_handler(struct work_struct *work)
+static struct rfkill_task rfkill_task = {
+	.dwork = __DELAYED_WORK_INITIALIZER(rfkill_task.dwork,
+				rfkill_task_handler),
+	.mutex = __MUTEX_INITIALIZER(rfkill_task.mutex),
+	.lock = __SPIN_LOCK_UNLOCKED(rfkill_task.lock),
+};
+
+static unsigned long rfkill_ratelimit(const unsigned long last)
 {
-	rfkill_epo();
+	const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY);
+	return (time_after(jiffies, last + delay)) ? 0 : delay;
 }
 
-static DECLARE_WORK(epo_work, rfkill_task_epo_handler);
-
-static void rfkill_schedule_epo(void)
+static void rfkill_schedule_ratelimited(void)
 {
-	schedule_work(&epo_work);
+	if (!delayed_work_pending(&rfkill_task.dwork)) {
+		schedule_delayed_work(&rfkill_task.dwork,
+				rfkill_ratelimit(rfkill_task.last_scheduled));
+		rfkill_task.last_scheduled = jiffies;
+	}
 }
 
-static void rfkill_schedule_set(struct rfkill_task *task,
+static void rfkill_schedule_global_op(enum rfkill_global_sched_op op)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&rfkill_task.lock, flags);
+	rfkill_task.op = op;
+	rfkill_task.global_op_pending = true;
+	if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) {
+		/* bypass the limiter for EPO */
+		cancel_delayed_work(&rfkill_task.dwork);
+		schedule_delayed_work(&rfkill_task.dwork, 0);
+		rfkill_task.last_scheduled = jiffies;
+	} else
+		rfkill_schedule_ratelimited();
+	spin_unlock_irqrestore(&rfkill_task.lock, flags);
+}
+
+#ifdef RFKILL_NEED_SWSET
+/* Use this if you need to add EV_SW SW_WLAN/WWAN/BLUETOOTH/etc handling */
+
+static void rfkill_schedule_set(enum rfkill_type type,
 				enum rfkill_state desired_state)
 {
 	unsigned long flags;
 
-	if (unlikely(work_pending(&epo_work)))
+	if (rfkill_is_epo_lock_active())
 		return;
 
-	spin_lock_irqsave(&task->lock, flags);
-
-	if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
-		task->desired_state = desired_state;
-		task->last = jiffies;
-		schedule_work(&task->work);
+	spin_lock_irqsave(&rfkill_task.lock, flags);
+	if (!rfkill_task.global_op_pending) {
+		set_bit(type, rfkill_task.sw_pending);
+		set_bit(type, rfkill_task.sw_setpending);
+		clear_bit(type, rfkill_task.sw_togglestate);
+		if (desired_state)
+			set_bit(type,  rfkill_task.sw_newstate);
+		else
+			clear_bit(type, rfkill_task.sw_newstate);
+		rfkill_schedule_ratelimited();
 	}
-
-	spin_unlock_irqrestore(&task->lock, flags);
+	spin_unlock_irqrestore(&rfkill_task.lock, flags);
 }
+#endif
 
-static void rfkill_schedule_toggle(struct rfkill_task *task)
+static void rfkill_schedule_toggle(enum rfkill_type type)
 {
 	unsigned long flags;
 
-	if (unlikely(work_pending(&epo_work)))
+	if (rfkill_is_epo_lock_active())
 		return;
 
-	spin_lock_irqsave(&task->lock, flags);
-
-	if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
-		task->desired_state =
-				rfkill_state_complement(task->desired_state);
-		task->last = jiffies;
-		schedule_work(&task->work);
+	spin_lock_irqsave(&rfkill_task.lock, flags);
+	if (!rfkill_task.global_op_pending) {
+		set_bit(type, rfkill_task.sw_pending);
+		change_bit(type, rfkill_task.sw_togglestate);
+		rfkill_schedule_ratelimited();
 	}
-
-	spin_unlock_irqrestore(&task->lock, flags);
+	spin_unlock_irqrestore(&rfkill_task.lock, flags);
 }
 
-#define DEFINE_RFKILL_TASK(n, t)				\
-	struct rfkill_task n = {				\
-		.work = __WORK_INITIALIZER(n.work,		\
-				rfkill_task_handler),		\
-		.type = t,					\
-		.mutex = __MUTEX_INITIALIZER(n.mutex),		\
-		.lock = __SPIN_LOCK_UNLOCKED(n.lock),		\
-		.desired_state = RFKILL_STATE_UNBLOCKED,	\
-	}
-
-static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
-static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
-static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
-static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
-static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN);
-
 static void rfkill_schedule_evsw_rfkillall(int state)
 {
-	/* EVERY radio type. state != 0 means radios ON */
-	/* handle EPO (emergency power off) through shortcut */
 	if (state) {
-		rfkill_schedule_set(&rfkill_wwan,
-				    RFKILL_STATE_UNBLOCKED);
-		rfkill_schedule_set(&rfkill_wimax,
-				    RFKILL_STATE_UNBLOCKED);
-		rfkill_schedule_set(&rfkill_uwb,
-				    RFKILL_STATE_UNBLOCKED);
-		rfkill_schedule_set(&rfkill_bt,
-				    RFKILL_STATE_UNBLOCKED);
-		rfkill_schedule_set(&rfkill_wlan,
-				    RFKILL_STATE_UNBLOCKED);
+		switch (rfkill_master_switch_mode) {
+		case RFKILL_INPUT_MASTER_UNBLOCKALL:
+			rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNBLOCK);
+			break;
+		case RFKILL_INPUT_MASTER_RESTORE:
+			rfkill_schedule_global_op(RFKILL_GLOBAL_OP_RESTORE);
+			break;
+		case RFKILL_INPUT_MASTER_DONOTHING:
+			rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNLOCK);
+			break;
+		default:
+			/* memory corruption or driver bug! fail safely */
+			rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO);
+			WARN(1, "Unknown rfkill_master_switch_mode (%d), "
+				"driver bug or memory corruption detected!\n",
+				rfkill_master_switch_mode);
+			break;
+		}
 	} else
-		rfkill_schedule_epo();
+		rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO);
 }
 
 static void rfkill_event(struct input_handle *handle, unsigned int type,
 			unsigned int code, int data)
 {
 	if (type == EV_KEY && data == 1) {
+		enum rfkill_type t;
+
 		switch (code) {
 		case KEY_WLAN:
-			rfkill_schedule_toggle(&rfkill_wlan);
+			t = RFKILL_TYPE_WLAN;
 			break;
 		case KEY_BLUETOOTH:
-			rfkill_schedule_toggle(&rfkill_bt);
+			t = RFKILL_TYPE_BLUETOOTH;
 			break;
 		case KEY_UWB:
-			rfkill_schedule_toggle(&rfkill_uwb);
+			t = RFKILL_TYPE_UWB;
 			break;
 		case KEY_WIMAX:
-			rfkill_schedule_toggle(&rfkill_wimax);
+			t = RFKILL_TYPE_WIMAX;
 			break;
 		default:
-			break;
+			return;
 		}
+		rfkill_schedule_toggle(t);
+		return;
 	} else if (type == EV_SW) {
 		switch (code) {
 		case SW_RFKILL_ALL:
 			rfkill_schedule_evsw_rfkillall(data);
-			break;
+			return;
 		default:
-			break;
+			return;
 		}
 	}
 }
@@ -256,18 +436,23 @@
 
 static int __init rfkill_handler_init(void)
 {
-	unsigned long last_run = jiffies - msecs_to_jiffies(500);
-	rfkill_wlan.last = last_run;
-	rfkill_bt.last = last_run;
-	rfkill_uwb.last = last_run;
-	rfkill_wimax.last = last_run;
+	if (rfkill_master_switch_mode >= RFKILL_INPUT_MASTER_MAX)
+		return -EINVAL;
+
+	/*
+	 * The penalty to not doing this is a possible RFKILL_OPS_DELAY delay
+	 * at the first use.  Acceptable, but if we can avoid it, why not?
+	 */
+	rfkill_task.last_scheduled =
+			jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1;
 	return input_register_handler(&rfkill_handler);
 }
 
 static void __exit rfkill_handler_exit(void)
 {
 	input_unregister_handler(&rfkill_handler);
-	flush_scheduled_work();
+	cancel_delayed_work_sync(&rfkill_task.dwork);
+	rfkill_remove_epo_lock();
 }
 
 module_init(rfkill_handler_init);
diff --git a/net/rfkill/rfkill-input.h b/net/rfkill/rfkill-input.h
index bbfa646..fe8df6b 100644
--- a/net/rfkill/rfkill-input.h
+++ b/net/rfkill/rfkill-input.h
@@ -14,5 +14,8 @@
 void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
 void rfkill_epo(void);
 void rfkill_restore_states(void);
+void rfkill_remove_epo_lock(void);
+bool rfkill_is_epo_lock_active(void);
+enum rfkill_state rfkill_get_global_state(const enum rfkill_type type);
 
 #endif /* __RFKILL_INPUT_H */
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index 25ba3bd..3c94f76 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -51,51 +51,7 @@
 
 static struct rfkill_gsw_state rfkill_global_states[RFKILL_TYPE_MAX];
 static unsigned long rfkill_states_lockdflt[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
-
-static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list);
-
-
-/**
- * register_rfkill_notifier - Add notifier to rfkill notifier chain
- * @nb: pointer to the new entry to add to the chain
- *
- * See blocking_notifier_chain_register() for return value and further
- * observations.
- *
- * Adds a notifier to the rfkill notifier chain.  The chain will be
- * called with a pointer to the relevant rfkill structure as a parameter,
- * refer to include/linux/rfkill.h for the possible events.
- *
- * Notifiers added to this chain are to always return NOTIFY_DONE.  This
- * chain is a blocking notifier chain: notifiers can sleep.
- *
- * Calls to this chain may have been done through a workqueue.  One must
- * assume unordered asynchronous behaviour, there is no way to know if
- * actions related to the event that generated the notification have been
- * carried out already.
- */
-int register_rfkill_notifier(struct notifier_block *nb)
-{
-	BUG_ON(!nb);
-	return blocking_notifier_chain_register(&rfkill_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_rfkill_notifier);
-
-/**
- * unregister_rfkill_notifier - remove notifier from rfkill notifier chain
- * @nb: pointer to the entry to remove from the chain
- *
- * See blocking_notifier_chain_unregister() for return value and further
- * observations.
- *
- * Removes a notifier from the rfkill notifier chain.
- */
-int unregister_rfkill_notifier(struct notifier_block *nb)
-{
-	BUG_ON(!nb);
-	return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_rfkill_notifier);
+static bool rfkill_epo_lock_active;
 
 
 static void rfkill_led_trigger(struct rfkill *rfkill,
@@ -123,12 +79,9 @@
 }
 #endif /* CONFIG_RFKILL_LEDS */
 
-static void notify_rfkill_state_change(struct rfkill *rfkill)
+static void rfkill_uevent(struct rfkill *rfkill)
 {
-	rfkill_led_trigger(rfkill, rfkill->state);
-	blocking_notifier_call_chain(&rfkill_notifier_list,
-			RFKILL_STATE_CHANGED,
-			rfkill);
+	kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE);
 }
 
 static void update_rfkill_state(struct rfkill *rfkill)
@@ -141,7 +94,7 @@
 			oldstate = rfkill->state;
 			rfkill->state = newstate;
 			if (oldstate != newstate)
-				notify_rfkill_state_change(rfkill);
+				rfkill_uevent(rfkill);
 		}
 		mutex_unlock(&rfkill->mutex);
 	}
@@ -219,7 +172,7 @@
 	}
 
 	if (force || rfkill->state != oldstate)
-		notify_rfkill_state_change(rfkill);
+		rfkill_uevent(rfkill);
 
 	return retval;
 }
@@ -264,11 +217,14 @@
  *
  * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state).
  * Please refer to __rfkill_switch_all() for details.
+ *
+ * Does nothing if the EPO lock is active.
  */
 void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
 {
 	mutex_lock(&rfkill_global_mutex);
-	__rfkill_switch_all(type, state);
+	if (!rfkill_epo_lock_active)
+		__rfkill_switch_all(type, state);
 	mutex_unlock(&rfkill_global_mutex);
 }
 EXPORT_SYMBOL(rfkill_switch_all);
@@ -289,6 +245,7 @@
 
 	mutex_lock(&rfkill_global_mutex);
 
+	rfkill_epo_lock_active = true;
 	list_for_each_entry(rfkill, &rfkill_list, node) {
 		mutex_lock(&rfkill->mutex);
 		rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
@@ -317,6 +274,7 @@
 
 	mutex_lock(&rfkill_global_mutex);
 
+	rfkill_epo_lock_active = false;
 	for (i = 0; i < RFKILL_TYPE_MAX; i++)
 		__rfkill_switch_all(i, rfkill_global_states[i].default_state);
 	mutex_unlock(&rfkill_global_mutex);
@@ -324,6 +282,48 @@
 EXPORT_SYMBOL_GPL(rfkill_restore_states);
 
 /**
+ * rfkill_remove_epo_lock - unlock state changes
+ *
+ * Used by rfkill-input manually unlock state changes, when
+ * the EPO switch is deactivated.
+ */
+void rfkill_remove_epo_lock(void)
+{
+	mutex_lock(&rfkill_global_mutex);
+	rfkill_epo_lock_active = false;
+	mutex_unlock(&rfkill_global_mutex);
+}
+EXPORT_SYMBOL_GPL(rfkill_remove_epo_lock);
+
+/**
+ * rfkill_is_epo_lock_active - returns true EPO is active
+ *
+ * Returns 0 (false) if there is NOT an active EPO contidion,
+ * and 1 (true) if there is an active EPO contition, which
+ * locks all radios in one of the BLOCKED states.
+ *
+ * Can be called in atomic context.
+ */
+bool rfkill_is_epo_lock_active(void)
+{
+	return rfkill_epo_lock_active;
+}
+EXPORT_SYMBOL_GPL(rfkill_is_epo_lock_active);
+
+/**
+ * rfkill_get_global_state - returns global state for a type
+ * @type: the type to get the global state of
+ *
+ * Returns the current global state for a given wireless
+ * device type.
+ */
+enum rfkill_state rfkill_get_global_state(const enum rfkill_type type)
+{
+	return rfkill_global_states[type].current_state;
+}
+EXPORT_SYMBOL_GPL(rfkill_get_global_state);
+
+/**
  * rfkill_force_state - Force the internal rfkill radio state
  * @rfkill: pointer to the rfkill class to modify.
  * @state: the current radio state the class should be forced to.
@@ -357,7 +357,7 @@
 	rfkill->state = state;
 
 	if (state != oldstate)
-		notify_rfkill_state_change(rfkill);
+		rfkill_uevent(rfkill);
 
 	mutex_unlock(&rfkill->mutex);
 
@@ -431,9 +431,15 @@
 	    state != RFKILL_STATE_SOFT_BLOCKED)
 		return -EINVAL;
 
-	if (mutex_lock_interruptible(&rfkill->mutex))
-		return -ERESTARTSYS;
-	error = rfkill_toggle_radio(rfkill, state, 0);
+	error = mutex_lock_killable(&rfkill->mutex);
+	if (error)
+		return error;
+
+	if (!rfkill_epo_lock_active)
+		error = rfkill_toggle_radio(rfkill, state, 0);
+	else
+		error = -EPERM;
+
 	mutex_unlock(&rfkill->mutex);
 
 	return error ? error : count;
@@ -472,12 +478,12 @@
 	 * Take the global lock to make sure the kernel is not in
 	 * the middle of rfkill_switch_all
 	 */
-	error = mutex_lock_interruptible(&rfkill_global_mutex);
+	error = mutex_lock_killable(&rfkill_global_mutex);
 	if (error)
 		return error;
 
 	if (rfkill->user_claim != claim) {
-		if (!claim) {
+		if (!claim && !rfkill_epo_lock_active) {
 			mutex_lock(&rfkill->mutex);
 			rfkill_toggle_radio(rfkill,
 					rfkill_global_states[rfkill->type].current_state,
@@ -511,24 +517,48 @@
 #ifdef CONFIG_PM
 static int rfkill_suspend(struct device *dev, pm_message_t state)
 {
+	struct rfkill *rfkill = to_rfkill(dev);
+
 	/* mark class device as suspended */
 	if (dev->power.power_state.event != state.event)
 		dev->power.power_state = state;
 
+	/* store state for the resume handler */
+	rfkill->state_for_resume = rfkill->state;
+
 	return 0;
 }
 
 static int rfkill_resume(struct device *dev)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
+	enum rfkill_state newstate;
 
 	if (dev->power.power_state.event != PM_EVENT_ON) {
 		mutex_lock(&rfkill->mutex);
 
 		dev->power.power_state.event = PM_EVENT_ON;
 
-		/* restore radio state AND notify everybody */
-		rfkill_toggle_radio(rfkill, rfkill->state, 1);
+		/*
+		 * rfkill->state could have been modified before we got
+		 * called, and won't be updated by rfkill_toggle_radio()
+		 * in force mode.  Sync it FIRST.
+		 */
+		if (rfkill->get_state &&
+		    !rfkill->get_state(rfkill->data, &newstate))
+			rfkill->state = newstate;
+
+		/*
+		 * If we are under EPO, kick transmitter offline,
+		 * otherwise restore to pre-suspend state.
+		 *
+		 * Issue a notification in any case
+		 */
+		rfkill_toggle_radio(rfkill,
+				rfkill_epo_lock_active ?
+					RFKILL_STATE_SOFT_BLOCKED :
+					rfkill->state_for_resume,
+				1);
 
 		mutex_unlock(&rfkill->mutex);
 	}
@@ -540,28 +570,6 @@
 #define rfkill_resume NULL
 #endif
 
-static int rfkill_blocking_uevent_notifier(struct notifier_block *nb,
-					unsigned long eventid,
-					void *data)
-{
-	struct rfkill *rfkill = (struct rfkill *)data;
-
-	switch (eventid) {
-	case RFKILL_STATE_CHANGED:
-		kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE);
-		break;
-	default:
-		break;
-	}
-
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block rfkill_blocking_uevent_nb = {
-	.notifier_call	= rfkill_blocking_uevent_notifier,
-	.priority	= 0,
-};
-
 static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
@@ -711,7 +719,7 @@
 	int error;
 
 	if (!rfkill->led_trigger.name)
-		rfkill->led_trigger.name = rfkill->dev.bus_id;
+		rfkill->led_trigger.name = dev_name(&rfkill->dev);
 	if (!rfkill->led_trigger.activate)
 		rfkill->led_trigger.activate = rfkill_led_trigger_activate;
 	error = led_trigger_register(&rfkill->led_trigger);
@@ -752,8 +760,7 @@
 			"badly initialized rfkill struct\n"))
 		return -EINVAL;
 
-	snprintf(dev->bus_id, sizeof(dev->bus_id),
-		 "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1);
+	dev_set_name(dev, "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1);
 
 	rfkill_led_trigger_register(rfkill);
 
@@ -833,6 +840,7 @@
 
 	if (!test_and_set_bit(type, rfkill_states_lockdflt)) {
 		rfkill_global_states[type].default_state = state;
+		rfkill_global_states[type].current_state = state;
 		error = 0;
 	} else
 		error = -EPERM;
@@ -864,14 +872,11 @@
 		return error;
 	}
 
-	register_rfkill_notifier(&rfkill_blocking_uevent_nb);
-
 	return 0;
 }
 
 static void __exit rfkill_exit(void)
 {
-	unregister_rfkill_notifier(&rfkill_blocking_uevent_nb);
 	class_unregister(&rfkill_class);
 }
 
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 0c1cc76..0139264 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -690,7 +690,7 @@
 
 	source = &addr->srose_call;
 
-	user = ax25_findbyuid(current->euid);
+	user = ax25_findbyuid(current_euid());
 	if (user) {
 		rose->source_call = user->call;
 		ax25_uid_put(user);
@@ -791,7 +791,7 @@
 			goto out_release;
 		}
 
-		user = ax25_findbyuid(current->euid);
+		user = ax25_findbyuid(current_euid());
 		if (!user) {
 			err = -EINVAL;
 			goto out_release;
diff --git a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c
index 20be348..3bfe504 100644
--- a/net/rose/sysctl_net_rose.c
+++ b/net/rose/sysctl_net_rose.c
@@ -31,8 +31,8 @@
 		.data		= &sysctl_rose_restart_request_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_timer,
 		.extra2		= &max_timer
 	},
@@ -42,8 +42,8 @@
 		.data		= &sysctl_rose_call_request_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_timer,
 		.extra2		= &max_timer
 	},
@@ -53,8 +53,8 @@
 		.data		= &sysctl_rose_reset_request_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_timer,
 		.extra2		= &max_timer
 	},
@@ -64,8 +64,8 @@
 		.data		= &sysctl_rose_clear_request_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_timer,
 		.extra2		= &max_timer
 	},
@@ -75,8 +75,8 @@
 		.data		= &sysctl_rose_no_activity_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_idle,
 		.extra2		= &max_idle
 	},
@@ -86,8 +86,8 @@
 		.data		= &sysctl_rose_ack_hold_back_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_timer,
 		.extra2		= &max_timer
 	},
@@ -97,8 +97,8 @@
 		.data		= &sysctl_rose_routing_control,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_route,
 		.extra2		= &max_route
 	},
@@ -108,8 +108,8 @@
 		.data		= &sysctl_rose_link_fail_timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_ftimer,
 		.extra2		= &max_ftimer
 	},
@@ -119,8 +119,8 @@
 		.data		= &sysctl_rose_maximum_vcs,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_maxvcs,
 		.extra2		= &max_maxvcs
 	},
@@ -130,8 +130,8 @@
 		.data		= &sysctl_rose_window_size,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &min_window,
 		.extra2		= &max_window
 	},
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 32e4891..d7d2bed 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -96,9 +96,9 @@
 
 	switch (srx->transport.family) {
 	case AF_INET:
-		_debug("INET: %x @ %u.%u.%u.%u",
+		_debug("INET: %x @ %pI4",
 		       ntohs(srx->transport.sin.sin_port),
-		       NIPQUAD(srx->transport.sin.sin_addr));
+		       &srx->transport.sin.sin_addr);
 		if (srx->transport_len > 8)
 			memset((void *)&srx->transport + 8, 0,
 			       srx->transport_len - 8);
diff --git a/net/rxrpc/ar-connection.c b/net/rxrpc/ar-connection.c
index 3869a58..0f1218b 100644
--- a/net/rxrpc/ar-connection.c
+++ b/net/rxrpc/ar-connection.c
@@ -826,7 +826,7 @@
 /*
  * reap dead connections
  */
-void rxrpc_connection_reaper(struct work_struct *work)
+static void rxrpc_connection_reaper(struct work_struct *work)
 {
 	struct rxrpc_connection *conn, *_p;
 	unsigned long now, earliest, reap_time;
diff --git a/net/rxrpc/ar-connevent.c b/net/rxrpc/ar-connevent.c
index 1ada43d..dc5cb1e 100644
--- a/net/rxrpc/ar-connevent.c
+++ b/net/rxrpc/ar-connevent.c
@@ -126,7 +126,7 @@
  * mark a call as being on a now-secured channel
  * - must be called with softirqs disabled
  */
-void rxrpc_call_is_secure(struct rxrpc_call *call)
+static void rxrpc_call_is_secure(struct rxrpc_call *call)
 {
 	_enter("%p", call);
 	if (call) {
diff --git a/net/rxrpc/ar-error.c b/net/rxrpc/ar-error.c
index 6cb3e88..d4d1ae2 100644
--- a/net/rxrpc/ar-error.c
+++ b/net/rxrpc/ar-error.c
@@ -49,8 +49,7 @@
 	addr = *(__be32 *)(skb_network_header(skb) + serr->addr_offset);
 	port = serr->port;
 
-	_net("Rx UDP Error from "NIPQUAD_FMT":%hu",
-	     NIPQUAD(addr), ntohs(port));
+	_net("Rx UDP Error from %pI4:%hu", &addr, ntohs(port));
 	_debug("Msg l:%d d:%d", skb->len, skb->data_len);
 
 	peer = rxrpc_find_peer(local, addr, port);
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
index 9a8ff68..ad8c7a7 100644
--- a/net/rxrpc/ar-key.c
+++ b/net/rxrpc/ar-key.c
@@ -287,6 +287,7 @@
 			      time_t expiry,
 			      u32 kvno)
 {
+	const struct cred *cred = current_cred();
 	struct key *key;
 	int ret;
 
@@ -297,7 +298,7 @@
 
 	_enter("");
 
-	key = key_alloc(&key_type_rxrpc, "x", 0, 0, current, 0,
+	key = key_alloc(&key_type_rxrpc, "x", 0, 0, cred, 0,
 			KEY_ALLOC_NOT_IN_QUOTA);
 	if (IS_ERR(key)) {
 		_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
@@ -340,10 +341,11 @@
  */
 struct key *rxrpc_get_null_key(const char *keyname)
 {
+	const struct cred *cred = current_cred();
 	struct key *key;
 	int ret;
 
-	key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current,
+	key = key_alloc(&key_type_rxrpc, keyname, 0, 0, cred,
 			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
 	if (IS_ERR(key))
 		return key;
diff --git a/net/rxrpc/ar-local.c b/net/rxrpc/ar-local.c
index f3a2bd7..807535f 100644
--- a/net/rxrpc/ar-local.c
+++ b/net/rxrpc/ar-local.c
@@ -131,10 +131,10 @@
 	struct rxrpc_local *local;
 	int ret;
 
-	_enter("{%d,%u,%u.%u.%u.%u+%hu}",
+	_enter("{%d,%u,%pI4+%hu}",
 	       srx->transport_type,
 	       srx->transport.family,
-	       NIPQUAD(srx->transport.sin.sin_addr),
+	       &srx->transport.sin.sin_addr,
 	       ntohs(srx->transport.sin.sin_port));
 
 	down_write(&rxrpc_local_sem);
@@ -143,10 +143,10 @@
 	read_lock_bh(&rxrpc_local_lock);
 
 	list_for_each_entry(local, &rxrpc_locals, link) {
-		_debug("CMP {%d,%u,%u.%u.%u.%u+%hu}",
+		_debug("CMP {%d,%u,%pI4+%hu}",
 		       local->srx.transport_type,
 		       local->srx.transport.family,
-		       NIPQUAD(local->srx.transport.sin.sin_addr),
+		       &local->srx.transport.sin.sin_addr,
 		       ntohs(local->srx.transport.sin.sin_port));
 
 		if (local->srx.transport_type != srx->transport_type ||
@@ -188,11 +188,11 @@
 
 	up_write(&rxrpc_local_sem);
 
-	_net("LOCAL new %d {%d,%u,%u.%u.%u.%u+%hu}",
+	_net("LOCAL new %d {%d,%u,%pI4+%hu}",
 	     local->debug_id,
 	     local->srx.transport_type,
 	     local->srx.transport.family,
-	     NIPQUAD(local->srx.transport.sin.sin_addr),
+	     &local->srx.transport.sin.sin_addr,
 	     ntohs(local->srx.transport.sin.sin_port));
 
 	_leave(" = %p [new]", local);
@@ -203,11 +203,11 @@
 	read_unlock_bh(&rxrpc_local_lock);
 	up_write(&rxrpc_local_sem);
 
-	_net("LOCAL old %d {%d,%u,%u.%u.%u.%u+%hu}",
+	_net("LOCAL old %d {%d,%u,%pI4+%hu}",
 	     local->debug_id,
 	     local->srx.transport_type,
 	     local->srx.transport.family,
-	     NIPQUAD(local->srx.transport.sin.sin_addr),
+	     &local->srx.transport.sin.sin_addr,
 	     ntohs(local->srx.transport.sin.sin_port));
 
 	_leave(" = %p [reuse]", local);
diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c
index 2abe208..edc026c 100644
--- a/net/rxrpc/ar-peer.c
+++ b/net/rxrpc/ar-peer.c
@@ -123,10 +123,10 @@
 	const char *new = "old";
 	int usage;
 
-	_enter("{%d,%d,%u.%u.%u.%u+%hu}",
+	_enter("{%d,%d,%pI4+%hu}",
 	       srx->transport_type,
 	       srx->transport_len,
-	       NIPQUAD(srx->transport.sin.sin_addr),
+	       &srx->transport.sin.sin_addr,
 	       ntohs(srx->transport.sin.sin_port));
 
 	/* search the peer list first */
@@ -177,12 +177,12 @@
 	new = "new";
 
 success:
-	_net("PEER %s %d {%d,%u,%u.%u.%u.%u+%hu}",
+	_net("PEER %s %d {%d,%u,%pI4+%hu}",
 	     new,
 	     peer->debug_id,
 	     peer->srx.transport_type,
 	     peer->srx.transport.family,
-	     NIPQUAD(peer->srx.transport.sin.sin_addr),
+	     &peer->srx.transport.sin.sin_addr,
 	     ntohs(peer->srx.transport.sin.sin_port));
 
 	_leave(" = %p {u=%d}", peer, atomic_read(&peer->usage));
diff --git a/net/rxrpc/ar-proc.c b/net/rxrpc/ar-proc.c
index 017322e..38047f7 100644
--- a/net/rxrpc/ar-proc.c
+++ b/net/rxrpc/ar-proc.c
@@ -61,12 +61,12 @@
 	call = list_entry(v, struct rxrpc_call, link);
 	trans = call->conn->trans;
 
-	sprintf(lbuff, NIPQUAD_FMT":%u",
-		NIPQUAD(trans->local->srx.transport.sin.sin_addr),
+	sprintf(lbuff, "%pI4:%u",
+		&trans->local->srx.transport.sin.sin_addr,
 		ntohs(trans->local->srx.transport.sin.sin_port));
 
-	sprintf(rbuff, NIPQUAD_FMT":%u",
-		NIPQUAD(trans->peer->srx.transport.sin.sin_addr),
+	sprintf(rbuff, "%pI4:%u",
+		&trans->peer->srx.transport.sin.sin_addr,
 		ntohs(trans->peer->srx.transport.sin.sin_port));
 
 	seq_printf(seq,
@@ -144,12 +144,12 @@
 	conn = list_entry(v, struct rxrpc_connection, link);
 	trans = conn->trans;
 
-	sprintf(lbuff, NIPQUAD_FMT":%u",
-		NIPQUAD(trans->local->srx.transport.sin.sin_addr),
+	sprintf(lbuff, "%pI4:%u",
+		&trans->local->srx.transport.sin.sin_addr,
 		ntohs(trans->local->srx.transport.sin.sin_port));
 
-	sprintf(rbuff, NIPQUAD_FMT":%u",
-		NIPQUAD(trans->peer->srx.transport.sin.sin_addr),
+	sprintf(rbuff, "%pI4:%u",
+		&trans->peer->srx.transport.sin.sin_addr,
 		ntohs(trans->peer->srx.transport.sin.sin_port));
 
 	seq_printf(seq,
diff --git a/net/rxrpc/ar-security.c b/net/rxrpc/ar-security.c
index 60d1d36..dc62920 100644
--- a/net/rxrpc/ar-security.c
+++ b/net/rxrpc/ar-security.c
@@ -40,7 +40,7 @@
 /*
  * look up an rxrpc security module
  */
-struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
+static struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
 {
 	struct rxrpc_security *sec = NULL;
 
diff --git a/net/rxrpc/ar-transport.c b/net/rxrpc/ar-transport.c
index 64069c8..0936e1a 100644
--- a/net/rxrpc/ar-transport.c
+++ b/net/rxrpc/ar-transport.c
@@ -78,10 +78,10 @@
 	const char *new = "old";
 	int usage;
 
-	_enter("{%u.%u.%u.%u+%hu},{%u.%u.%u.%u+%hu},",
-	       NIPQUAD(local->srx.transport.sin.sin_addr),
+	_enter("{%pI4+%hu},{%pI4+%hu},",
+	       &local->srx.transport.sin.sin_addr,
 	       ntohs(local->srx.transport.sin.sin_port),
-	       NIPQUAD(peer->srx.transport.sin.sin_addr),
+	       &peer->srx.transport.sin.sin_addr,
 	       ntohs(peer->srx.transport.sin.sin_port));
 
 	/* search the transport list first */
@@ -149,10 +149,10 @@
 {
 	struct rxrpc_transport *trans;
 
-	_enter("{%u.%u.%u.%u+%hu},{%u.%u.%u.%u+%hu},",
-	       NIPQUAD(local->srx.transport.sin.sin_addr),
+	_enter("{%pI4+%hu},{%pI4+%hu},",
+	       &local->srx.transport.sin.sin_addr,
 	       ntohs(local->srx.transport.sin.sin_port),
-	       NIPQUAD(peer->srx.transport.sin.sin_addr),
+	       &peer->srx.transport.sin.sin_addr,
 	       ntohs(peer->srx.transport.sin.sin_port));
 
 	/* search the transport list */
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index ba3f6e4..ef8f910 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -897,7 +897,7 @@
 	/* get the IPv4 address of the entity that requested the ticket */
 	memcpy(&addr, p, sizeof(addr));
 	p += 4;
-	_debug("KIV ADDR : "NIPQUAD_FMT, NIPQUAD(addr));
+	_debug("KIV ADDR : %pI4", &addr);
 
 	/* get the session key from the ticket */
 	memcpy(&key, p, sizeof(key));
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 6767e54..4f7ef0d 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -194,6 +194,17 @@
 
 	  If unsure, say N.
 
+config NET_SCH_DRR
+	tristate "Deficit Round Robin scheduler (DRR)"
+	help
+	  Say Y here if you want to use the Deficit Round Robin (DRR) packet
+	  scheduling algorithm.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sch_drr.
+
+	  If unsure, say N.
+
 config NET_SCH_INGRESS
 	tristate "Ingress Qdisc"
 	depends on NET_CLS_ACT
@@ -316,6 +327,17 @@
 	  To compile this code as a module, choose M here: the
 	  module will be called cls_flow.
 
+config NET_CLS_CGROUP
+	bool "Control Group Classifier"
+	select NET_CLS
+	depends on CGROUPS
+	---help---
+	  Say Y here if you want to classify packets based on the control
+	  cgroup of their process.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called cls_cgroup.
+
 config NET_EMATCH
 	bool "Extended Matches"
 	select NET_CLS
diff --git a/net/sched/Makefile b/net/sched/Makefile
index e60c992..54d950c 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -30,6 +30,7 @@
 obj-$(CONFIG_NET_SCH_MULTIQ)	+= sch_multiq.o
 obj-$(CONFIG_NET_SCH_ATM)	+= sch_atm.o
 obj-$(CONFIG_NET_SCH_NETEM)	+= sch_netem.o
+obj-$(CONFIG_NET_SCH_DRR)	+= sch_drr.o
 obj-$(CONFIG_NET_CLS_U32)	+= cls_u32.o
 obj-$(CONFIG_NET_CLS_ROUTE4)	+= cls_route.o
 obj-$(CONFIG_NET_CLS_FW)	+= cls_fw.o
@@ -38,6 +39,7 @@
 obj-$(CONFIG_NET_CLS_RSVP6)	+= cls_rsvp6.o
 obj-$(CONFIG_NET_CLS_BASIC)	+= cls_basic.o
 obj-$(CONFIG_NET_CLS_FLOW)	+= cls_flow.o
+obj-$(CONFIG_NET_CLS_CGROUP)	+= cls_cgroup.o
 obj-$(CONFIG_NET_EMATCH)	+= ematch.o
 obj-$(CONFIG_NET_EMATCH_CMP)	+= em_cmp.o
 obj-$(CONFIG_NET_EMATCH_NBYTE)	+= em_nbyte.o
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 8f457f1..9d03cc3 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -214,12 +214,14 @@
 }
 EXPORT_SYMBOL(tcf_hash_check);
 
-struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a, int size, int bind, u32 *idx_gen, struct tcf_hashinfo *hinfo)
+struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
+				   struct tc_action *a, int size, int bind,
+				   u32 *idx_gen, struct tcf_hashinfo *hinfo)
 {
 	struct tcf_common *p = kzalloc(size, GFP_KERNEL);
 
 	if (unlikely(!p))
-		return p;
+		return ERR_PTR(-ENOMEM);
 	p->tcfc_refcnt = 1;
 	if (bind)
 		p->tcfc_bindcnt = 1;
@@ -228,9 +230,15 @@
 	p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo);
 	p->tcfc_tm.install = jiffies;
 	p->tcfc_tm.lastuse = jiffies;
-	if (est)
-		gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est,
-				  &p->tcfc_lock, est);
+	if (est) {
+		int err = gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est,
+					    &p->tcfc_lock, est);
+		if (err) {
+			kfree(p);
+			return ERR_PTR(err);
+		}
+	}
+
 	a->priv = (void *) p;
 	return p;
 }
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index ac04289..e7f796a 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -88,8 +88,8 @@
 	if (!pc) {
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*gact),
 				     bind, &gact_idx_gen, &gact_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 		ret = ACT_P_CREATED;
 	} else {
 		if (!ovr) {
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 0453d79..082c520 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -136,8 +136,8 @@
 	if (!pc) {
 		pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind,
 				     &ipt_idx_gen, &ipt_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 		ret = ACT_P_CREATED;
 	} else {
 		if (!ovr) {
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 70341c0..b9aaab4 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -105,8 +105,8 @@
 			return -EINVAL;
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
 				     &mirred_idx_gen, &mirred_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 		ret = ACT_P_CREATED;
 	} else {
 		if (!ovr) {
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index 7b39ed4..d885ba3 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -68,8 +68,8 @@
 	if (!pc) {
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
 				     &nat_idx_gen, &nat_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 		p = to_tcf_nat(pc);
 		ret = ACT_P_CREATED;
 	} else {
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index d5f4e34..96c0ed1 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -68,8 +68,8 @@
 			return -EINVAL;
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
 				     &pedit_idx_gen, &pedit_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 		p = to_pedit(pc);
 		keys = kmalloc(ksize, GFP_KERNEL);
 		if (keys == NULL) {
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 38015b4..5c72a11 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -182,17 +182,32 @@
 		R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE]);
 		if (R_tab == NULL)
 			goto failure;
+
+		if (!est && (ret == ACT_P_CREATED ||
+			     !gen_estimator_active(&police->tcf_bstats,
+						   &police->tcf_rate_est))) {
+			err = -EINVAL;
+			goto failure;
+		}
+
 		if (parm->peakrate.rate) {
 			P_tab = qdisc_get_rtab(&parm->peakrate,
 					       tb[TCA_POLICE_PEAKRATE]);
-			if (P_tab == NULL) {
-				qdisc_put_rtab(R_tab);
+			if (P_tab == NULL)
 				goto failure;
-			}
 		}
 	}
-	/* No failure allowed after this point */
+
 	spin_lock_bh(&police->tcf_lock);
+	if (est) {
+		err = gen_replace_estimator(&police->tcf_bstats,
+					    &police->tcf_rate_est,
+					    &police->tcf_lock, est);
+		if (err)
+			goto failure_unlock;
+	}
+
+	/* No failure allowed after this point */
 	if (R_tab != NULL) {
 		qdisc_put_rtab(police->tcfp_R_tab);
 		police->tcfp_R_tab = R_tab;
@@ -217,10 +232,6 @@
 
 	if (tb[TCA_POLICE_AVRATE])
 		police->tcfp_ewma_rate = nla_get_u32(tb[TCA_POLICE_AVRATE]);
-	if (est)
-		gen_replace_estimator(&police->tcf_bstats,
-				      &police->tcf_rate_est,
-				      &police->tcf_lock, est);
 
 	spin_unlock_bh(&police->tcf_lock);
 	if (ret != ACT_P_CREATED)
@@ -238,7 +249,13 @@
 	a->priv = police;
 	return ret;
 
+failure_unlock:
+	spin_unlock_bh(&police->tcf_lock);
 failure:
+	if (P_tab)
+		qdisc_put_rtab(P_tab);
+	if (R_tab)
+		qdisc_put_rtab(R_tab);
 	if (ret == ACT_P_CREATED)
 		kfree(police);
 	return err;
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index e7851ce..8daa1eb 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -124,8 +124,8 @@
 	if (!pc) {
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
 				     &simp_idx_gen, &simp_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 
 		d = to_defact(pc);
 		ret = alloc_defdata(d, defdata);
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index fe9777e..4ab916b 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -104,8 +104,8 @@
 	if (!pc) {
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
 				     &skbedit_idx_gen, &skbedit_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 
 		d = to_skbedit(pc);
 		ret = ACT_P_CREATED;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 16e7ac9..173fcc4 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -531,7 +531,8 @@
 	if (src->action) {
 		struct tc_action *act;
 		tcf_tree_lock(tp);
-		act = xchg(&dst->action, src->action);
+		act = dst->action;
+		dst->action = src->action;
 		tcf_tree_unlock(tp);
 		if (act)
 			tcf_action_destroy(act, TCA_ACT_UNBIND);
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index 956915c..4e2bda8 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -102,7 +102,7 @@
 
 static void basic_destroy(struct tcf_proto *tp)
 {
-	struct basic_head *head = (struct basic_head *) xchg(&tp->root, NULL);
+	struct basic_head *head = tp->root;
 	struct basic_filter *f, *n;
 
 	list_for_each_entry_safe(f, n, &head->flist, link) {
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
new file mode 100644
index 0000000..0d68b19
--- /dev/null
+++ b/net/sched/cls_cgroup.c
@@ -0,0 +1,288 @@
+/*
+ * net/sched/cls_cgroup.c	Control Group Classifier
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/cgroup.h>
+#include <net/rtnetlink.h>
+#include <net/pkt_cls.h>
+
+struct cgroup_cls_state
+{
+	struct cgroup_subsys_state css;
+	u32 classid;
+};
+
+static inline struct cgroup_cls_state *net_cls_state(struct cgroup *cgrp)
+{
+	return (struct cgroup_cls_state *)
+		cgroup_subsys_state(cgrp, net_cls_subsys_id);
+}
+
+static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,
+						 struct cgroup *cgrp)
+{
+	struct cgroup_cls_state *cs;
+
+	if (!(cs = kzalloc(sizeof(*cs), GFP_KERNEL)))
+		return ERR_PTR(-ENOMEM);
+
+	if (cgrp->parent)
+		cs->classid = net_cls_state(cgrp->parent)->classid;
+
+	return &cs->css;
+}
+
+static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp)
+{
+	kfree(ss);
+}
+
+static u64 read_classid(struct cgroup *cgrp, struct cftype *cft)
+{
+	return net_cls_state(cgrp)->classid;
+}
+
+static int write_classid(struct cgroup *cgrp, struct cftype *cft, u64 value)
+{
+	if (!cgroup_lock_live_group(cgrp))
+		return -ENODEV;
+
+	net_cls_state(cgrp)->classid = (u32) value;
+
+	cgroup_unlock();
+
+	return 0;
+}
+
+static struct cftype ss_files[] = {
+	{
+		.name = "classid",
+		.read_u64 = read_classid,
+		.write_u64 = write_classid,
+	},
+};
+
+static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp)
+{
+	return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files));
+}
+
+struct cgroup_subsys net_cls_subsys = {
+	.name		= "net_cls",
+	.create		= cgrp_create,
+	.destroy	= cgrp_destroy,
+	.populate	= cgrp_populate,
+	.subsys_id	= net_cls_subsys_id,
+};
+
+struct cls_cgroup_head
+{
+	u32			handle;
+	struct tcf_exts		exts;
+	struct tcf_ematch_tree	ematches;
+};
+
+static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp,
+			       struct tcf_result *res)
+{
+	struct cls_cgroup_head *head = tp->root;
+	struct cgroup_cls_state *cs;
+	int ret = 0;
+
+	/*
+	 * Due to the nature of the classifier it is required to ignore all
+	 * packets originating from softirq context as accessing `current'
+	 * would lead to false results.
+	 *
+	 * This test assumes that all callers of dev_queue_xmit() explicitely
+	 * disable bh. Knowing this, it is possible to detect softirq based
+	 * calls by looking at the number of nested bh disable calls because
+	 * softirqs always disables bh.
+	 */
+	if (softirq_count() != SOFTIRQ_OFFSET)
+		return -1;
+
+	rcu_read_lock();
+	cs = (struct cgroup_cls_state *) task_subsys_state(current,
+							   net_cls_subsys_id);
+	if (cs->classid && tcf_em_tree_match(skb, &head->ematches, NULL)) {
+		res->classid = cs->classid;
+		res->class = 0;
+		ret = tcf_exts_exec(skb, &head->exts, res);
+	} else
+		ret = -1;
+
+	rcu_read_unlock();
+
+	return ret;
+}
+
+static unsigned long cls_cgroup_get(struct tcf_proto *tp, u32 handle)
+{
+	return 0UL;
+}
+
+static void cls_cgroup_put(struct tcf_proto *tp, unsigned long f)
+{
+}
+
+static int cls_cgroup_init(struct tcf_proto *tp)
+{
+	return 0;
+}
+
+static const struct tcf_ext_map cgroup_ext_map = {
+	.action = TCA_CGROUP_ACT,
+	.police = TCA_CGROUP_POLICE,
+};
+
+static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = {
+	[TCA_CGROUP_EMATCHES]	= { .type = NLA_NESTED },
+};
+
+static int cls_cgroup_change(struct tcf_proto *tp, unsigned long base,
+			     u32 handle, struct nlattr **tca,
+			     unsigned long *arg)
+{
+	struct nlattr *tb[TCA_CGROUP_MAX+1];
+	struct cls_cgroup_head *head = tp->root;
+	struct tcf_ematch_tree t;
+	struct tcf_exts e;
+	int err;
+
+	if (head == NULL) {
+		if (!handle)
+			return -EINVAL;
+
+		head = kzalloc(sizeof(*head), GFP_KERNEL);
+		if (head == NULL)
+			return -ENOBUFS;
+
+		head->handle = handle;
+
+		tcf_tree_lock(tp);
+		tp->root = head;
+		tcf_tree_unlock(tp);
+	}
+
+	if (handle != head->handle)
+		return -ENOENT;
+
+	err = nla_parse_nested(tb, TCA_CGROUP_MAX, tca[TCA_OPTIONS],
+			       cgroup_policy);
+	if (err < 0)
+		return err;
+
+	err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &cgroup_ext_map);
+	if (err < 0)
+		return err;
+
+	err = tcf_em_tree_validate(tp, tb[TCA_CGROUP_EMATCHES], &t);
+	if (err < 0)
+		return err;
+
+	tcf_exts_change(tp, &head->exts, &e);
+	tcf_em_tree_change(tp, &head->ematches, &t);
+
+	return 0;
+}
+
+static void cls_cgroup_destroy(struct tcf_proto *tp)
+{
+	struct cls_cgroup_head *head = tp->root;
+
+	if (head) {
+		tcf_exts_destroy(tp, &head->exts);
+		tcf_em_tree_destroy(tp, &head->ematches);
+		kfree(head);
+	}
+}
+
+static int cls_cgroup_delete(struct tcf_proto *tp, unsigned long arg)
+{
+	return -EOPNOTSUPP;
+}
+
+static void cls_cgroup_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+{
+	struct cls_cgroup_head *head = tp->root;
+
+	if (arg->count < arg->skip)
+		goto skip;
+
+	if (arg->fn(tp, (unsigned long) head, arg) < 0) {
+		arg->stop = 1;
+		return;
+	}
+skip:
+	arg->count++;
+}
+
+static int cls_cgroup_dump(struct tcf_proto *tp, unsigned long fh,
+			   struct sk_buff *skb, struct tcmsg *t)
+{
+	struct cls_cgroup_head *head = tp->root;
+	unsigned char *b = skb_tail_pointer(skb);
+	struct nlattr *nest;
+
+	t->tcm_handle = head->handle;
+
+	nest = nla_nest_start(skb, TCA_OPTIONS);
+	if (nest == NULL)
+		goto nla_put_failure;
+
+	if (tcf_exts_dump(skb, &head->exts, &cgroup_ext_map) < 0 ||
+	    tcf_em_tree_dump(skb, &head->ematches, TCA_CGROUP_EMATCHES) < 0)
+		goto nla_put_failure;
+
+	nla_nest_end(skb, nest);
+
+	if (tcf_exts_dump_stats(skb, &head->exts, &cgroup_ext_map) < 0)
+		goto nla_put_failure;
+
+	return skb->len;
+
+nla_put_failure:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static struct tcf_proto_ops cls_cgroup_ops __read_mostly = {
+	.kind		=	"cgroup",
+	.init		=	cls_cgroup_init,
+	.change		=	cls_cgroup_change,
+	.classify	=	cls_cgroup_classify,
+	.destroy	=	cls_cgroup_destroy,
+	.get		=	cls_cgroup_get,
+	.put		=	cls_cgroup_put,
+	.delete		=	cls_cgroup_delete,
+	.walk		=	cls_cgroup_walk,
+	.dump		=	cls_cgroup_dump,
+	.owner		=	THIS_MODULE,
+};
+
+static int __init init_cgroup_cls(void)
+{
+	return register_tcf_proto_ops(&cls_cgroup_ops);
+}
+
+static void __exit exit_cgroup_cls(void)
+{
+	unregister_tcf_proto_ops(&cls_cgroup_ops);
+}
+
+module_init(init_cgroup_cls);
+module_exit(exit_cgroup_cls);
+MODULE_LICENSE("GPL");
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 0ebaff6..0ef4e30 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -260,14 +260,14 @@
 static u32 flow_get_skuid(const struct sk_buff *skb)
 {
 	if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
-		return skb->sk->sk_socket->file->f_uid;
+		return skb->sk->sk_socket->file->f_cred->fsuid;
 	return 0;
 }
 
 static u32 flow_get_skgid(const struct sk_buff *skb)
 {
 	if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
-		return skb->sk->sk_socket->file->f_gid;
+		return skb->sk->sk_socket->file->f_cred->fsgid;
 	return 0;
 }
 
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index b0f90e5..6d6e875 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -148,7 +148,7 @@
 
 static void fw_destroy(struct tcf_proto *tp)
 {
-	struct fw_head *head = (struct fw_head*)xchg(&tp->root, NULL);
+	struct fw_head *head = tp->root;
 	struct fw_filter *f;
 	int h;
 
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index e3d8455..bdf1f41 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -260,7 +260,7 @@
 
 static void route4_destroy(struct tcf_proto *tp)
 {
-	struct route4_head *head = xchg(&tp->root, NULL);
+	struct route4_head *head = tp->root;
 	int h1, h2;
 
 	if (head == NULL)
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
index 7a7bff5..e806f23 100644
--- a/net/sched/cls_tcindex.c
+++ b/net/sched/cls_tcindex.c
@@ -13,12 +13,6 @@
 #include <net/netlink.h>
 #include <net/pkt_cls.h>
 
-
-/*
- * Not quite sure if we need all the xchgs Alexey uses when accessing things.
- * Can always add them later ... :)
- */
-
 /*
  * Passing parameters to the root seems to be done more awkwardly than really
  * necessary. At least, u32 doesn't seem to use such dirty hacks. To be
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 246f906..05d17800 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -387,7 +387,7 @@
 static void u32_destroy(struct tcf_proto *tp)
 {
 	struct tc_u_common *tp_c = tp->data;
-	struct tc_u_hnode *root_ht = xchg(&tp->root, NULL);
+	struct tc_u_hnode *root_ht = tp->root;
 
 	WARN_ON(root_ht == NULL);
 
@@ -479,7 +479,7 @@
 	err = -EINVAL;
 	if (tb[TCA_U32_LINK]) {
 		u32 handle = nla_get_u32(tb[TCA_U32_LINK]);
-		struct tc_u_hnode *ht_down = NULL;
+		struct tc_u_hnode *ht_down = NULL, *ht_old;
 
 		if (TC_U32_KEY(handle))
 			goto errout;
@@ -493,11 +493,12 @@
 		}
 
 		tcf_tree_lock(tp);
-		ht_down = xchg(&n->ht_down, ht_down);
+		ht_old = n->ht_down;
+		n->ht_down = ht_down;
 		tcf_tree_unlock(tp);
 
-		if (ht_down)
-			ht_down->refcnt--;
+		if (ht_old)
+			ht_old->refcnt--;
 	}
 	if (tb[TCA_U32_CLASSID]) {
 		n->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
diff --git a/net/sched/ematch.c b/net/sched/ematch.c
index e82519e..aab5940 100644
--- a/net/sched/ematch.c
+++ b/net/sched/ematch.c
@@ -71,7 +71,7 @@
  *
  *      static void __exit exit_my_ematch(void)
  *      {
- *      	return tcf_em_unregister(&my_ops);
+ *      	tcf_em_unregister(&my_ops);
  *      }
  *
  *      module_init(init_my_ematch);
@@ -154,23 +154,11 @@
  *
  * Returns -ENOENT if no matching ematch was found.
  */
-int tcf_em_unregister(struct tcf_ematch_ops *ops)
+void tcf_em_unregister(struct tcf_ematch_ops *ops)
 {
-	int err = 0;
-	struct tcf_ematch_ops *e;
-
 	write_lock(&ematch_mod_lock);
-	list_for_each_entry(e, &ematch_ops, link) {
-		if (e == ops) {
-			list_del(&e->link);
-			goto out;
-		}
-	}
-
-	err = -ENOENT;
-out:
+	list_del(&ops->link);
 	write_unlock(&ematch_mod_lock);
-	return err;
 }
 EXPORT_SYMBOL(tcf_em_unregister);
 
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 6ab4a2f..0fc4a18 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -97,10 +97,9 @@
 
    Auxiliary routines:
 
-   ---requeue
+   ---peek
 
-   requeues once dequeued packet. It is used for non-standard or
-   just buggy devices, which can defer output even if netif_queue_stopped()=0.
+   like dequeue but without removing a packet from the queue
 
    ---reset
 
@@ -147,8 +146,14 @@
 
 	if (qops->enqueue == NULL)
 		qops->enqueue = noop_qdisc_ops.enqueue;
-	if (qops->requeue == NULL)
-		qops->requeue = noop_qdisc_ops.requeue;
+	if (qops->peek == NULL) {
+		if (qops->dequeue == NULL) {
+			qops->peek = noop_qdisc_ops.peek;
+		} else {
+			rc = -EINVAL;
+			goto out;
+		}
+	}
 	if (qops->dequeue == NULL)
 		qops->dequeue = noop_qdisc_ops.dequeue;
 
@@ -184,7 +189,7 @@
    (root qdisc, all its children, children of children etc.)
  */
 
-struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
+static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
 {
 	struct Qdisc *q;
 
@@ -199,28 +204,16 @@
 	return NULL;
 }
 
-/*
- * This lock is needed until some qdiscs stop calling qdisc_tree_decrease_qlen()
- * without rtnl_lock(); currently hfsc_dequeue(), netem_dequeue(), tbf_dequeue()
- */
-static DEFINE_SPINLOCK(qdisc_list_lock);
-
 static void qdisc_list_add(struct Qdisc *q)
 {
-	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
-		spin_lock_bh(&qdisc_list_lock);
+	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
 		list_add_tail(&q->list, &qdisc_root_sleeping(q)->list);
-		spin_unlock_bh(&qdisc_list_lock);
-	}
 }
 
 void qdisc_list_del(struct Qdisc *q)
 {
-	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
-		spin_lock_bh(&qdisc_list_lock);
+	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
 		list_del(&q->list);
-		spin_unlock_bh(&qdisc_list_lock);
-	}
 }
 EXPORT_SYMBOL(qdisc_list_del);
 
@@ -229,22 +222,17 @@
 	unsigned int i;
 	struct Qdisc *q;
 
-	spin_lock_bh(&qdisc_list_lock);
-
 	for (i = 0; i < dev->num_tx_queues; i++) {
 		struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
 		struct Qdisc *txq_root = txq->qdisc_sleeping;
 
 		q = qdisc_match_from_root(txq_root, handle);
 		if (q)
-			goto unlock;
+			goto out;
 	}
 
 	q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle);
-
-unlock:
-	spin_unlock_bh(&qdisc_list_lock);
-
+out:
 	return q;
 }
 
@@ -462,7 +450,6 @@
 						 timer);
 
 	wd->qdisc->flags &= ~TCQ_F_THROTTLED;
-	smp_wmb();
 	__netif_schedule(qdisc_root(wd->qdisc));
 
 	return HRTIMER_NORESTART;
@@ -892,9 +879,12 @@
 	sch->stab = stab;
 
 	if (tca[TCA_RATE])
+		/* NB: ignores errors from replace_estimator
+		   because change can't be undone. */
 		gen_replace_estimator(&sch->bstats, &sch->rate_est,
-				      qdisc_root_sleeping_lock(sch),
-				      tca[TCA_RATE]);
+					    qdisc_root_sleeping_lock(sch),
+					    tca[TCA_RATE]);
+
 	return 0;
 }
 
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 43d3725..2a8b83a 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -62,7 +62,7 @@
 	struct atm_flow_data	link;		/* unclassified skbs go here */
 	struct atm_flow_data	*flows;		/* NB: "link" is also on this
 						   list */
-	struct tasklet_struct	task;		/* requeue tasklet */
+	struct tasklet_struct	task;		/* dequeue tasklet */
 };
 
 /* ------------------------- Class/flow operations ------------------------- */
@@ -102,7 +102,8 @@
 		return -EINVAL;
 	if (!new)
 		new = &noop_qdisc;
-	*old = xchg(&flow->q, new);
+	*old = flow->q;
+	flow->q = new;
 	if (*old)
 		qdisc_reset(*old);
 	return 0;
@@ -480,11 +481,14 @@
 		 * If traffic is properly shaped, this won't generate nasty
 		 * little bursts. Otherwise, it may ... (but that's okay)
 		 */
-		while ((skb = flow->q->dequeue(flow->q))) {
-			if (!atm_may_send(flow->vcc, skb->truesize)) {
-				(void)flow->q->ops->requeue(skb, flow->q);
+		while ((skb = flow->q->ops->peek(flow->q))) {
+			if (!atm_may_send(flow->vcc, skb->truesize))
 				break;
-			}
+
+			skb = qdisc_dequeue_peeked(flow->q);
+			if (unlikely(!skb))
+				break;
+
 			pr_debug("atm_tc_dequeue: sending on class %p\n", flow);
 			/* remove any LL header somebody else has attached */
 			skb_pull(skb, skb_network_offset(skb));
@@ -516,27 +520,19 @@
 
 	pr_debug("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p);
 	tasklet_schedule(&p->task);
-	skb = p->link.q->dequeue(p->link.q);
+	skb = qdisc_dequeue_peeked(p->link.q);
 	if (skb)
 		sch->q.qlen--;
 	return skb;
 }
 
-static int atm_tc_requeue(struct sk_buff *skb, struct Qdisc *sch)
+static struct sk_buff *atm_tc_peek(struct Qdisc *sch)
 {
 	struct atm_qdisc_data *p = qdisc_priv(sch);
-	int ret;
 
-	pr_debug("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
-	ret = p->link.q->ops->requeue(skb, p->link.q);
-	if (!ret) {
-		sch->q.qlen++;
-		sch->qstats.requeues++;
-	} else if (net_xmit_drop_count(ret)) {
-		sch->qstats.drops++;
-		p->link.qstats.drops++;
-	}
-	return ret;
+	pr_debug("atm_tc_peek(sch %p,[qdisc %p])\n", sch, p);
+
+	return p->link.q->ops->peek(p->link.q);
 }
 
 static unsigned int atm_tc_drop(struct Qdisc *sch)
@@ -694,7 +690,7 @@
 	.priv_size	= sizeof(struct atm_qdisc_data),
 	.enqueue	= atm_tc_enqueue,
 	.dequeue	= atm_tc_dequeue,
-	.requeue	= atm_tc_requeue,
+	.peek		= atm_tc_peek,
 	.drop		= atm_tc_drop,
 	.init		= atm_tc_init,
 	.reset		= atm_tc_reset,
diff --git a/net/sched/sch_blackhole.c b/net/sched/sch_blackhole.c
index 507fb48..094a874 100644
--- a/net/sched/sch_blackhole.c
+++ b/net/sched/sch_blackhole.c
@@ -33,6 +33,7 @@
 	.priv_size	= 0,
 	.enqueue	= blackhole_enqueue,
 	.dequeue	= blackhole_dequeue,
+	.peek		= blackhole_dequeue,
 	.owner		= THIS_MODULE,
 };
 
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 03e389e..9e43ed9 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -405,40 +405,6 @@
 	return ret;
 }
 
-static int
-cbq_requeue(struct sk_buff *skb, struct Qdisc *sch)
-{
-	struct cbq_sched_data *q = qdisc_priv(sch);
-	struct cbq_class *cl;
-	int ret;
-
-	if ((cl = q->tx_class) == NULL) {
-		kfree_skb(skb);
-		sch->qstats.drops++;
-		return NET_XMIT_CN;
-	}
-	q->tx_class = NULL;
-
-	cbq_mark_toplevel(q, cl);
-
-#ifdef CONFIG_NET_CLS_ACT
-	q->rx_class = cl;
-	cl->q->__parent = sch;
-#endif
-	if ((ret = cl->q->ops->requeue(skb, cl->q)) == 0) {
-		sch->q.qlen++;
-		sch->qstats.requeues++;
-		if (!cl->next_alive)
-			cbq_activate_class(cl);
-		return 0;
-	}
-	if (net_xmit_drop_count(ret)) {
-		sch->qstats.drops++;
-		cl->qstats.drops++;
-	}
-	return ret;
-}
-
 /* Overlimit actions */
 
 /* TC_CBQ_OVL_CLASSIC: (default) penalize leaf class by adding offtime */
@@ -1669,7 +1635,8 @@
 #endif
 		}
 		sch_tree_lock(sch);
-		*old = xchg(&cl->q, new);
+		*old = cl->q;
+		cl->q = new;
 		qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
 		qdisc_reset(*old);
 		sch_tree_unlock(sch);
@@ -1798,11 +1765,23 @@
 		}
 
 		if (tb[TCA_CBQ_RATE]) {
-			rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB]);
+			rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]),
+					      tb[TCA_CBQ_RTAB]);
 			if (rtab == NULL)
 				return -EINVAL;
 		}
 
+		if (tca[TCA_RATE]) {
+			err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+						    qdisc_root_sleeping_lock(sch),
+						    tca[TCA_RATE]);
+			if (err) {
+				if (rtab)
+					qdisc_put_rtab(rtab);
+				return err;
+			}
+		}
+
 		/* Change class parameters */
 		sch_tree_lock(sch);
 
@@ -1810,8 +1789,8 @@
 			cbq_deactivate_class(cl);
 
 		if (rtab) {
-			rtab = xchg(&cl->R_tab, rtab);
-			qdisc_put_rtab(rtab);
+			qdisc_put_rtab(cl->R_tab);
+			cl->R_tab = rtab;
 		}
 
 		if (tb[TCA_CBQ_LSSOPT])
@@ -1838,10 +1817,6 @@
 
 		sch_tree_unlock(sch);
 
-		if (tca[TCA_RATE])
-			gen_replace_estimator(&cl->bstats, &cl->rate_est,
-					      qdisc_root_sleeping_lock(sch),
-					      tca[TCA_RATE]);
 		return 0;
 	}
 
@@ -1888,6 +1863,17 @@
 	cl = kzalloc(sizeof(*cl), GFP_KERNEL);
 	if (cl == NULL)
 		goto failure;
+
+	if (tca[TCA_RATE]) {
+		err = gen_new_estimator(&cl->bstats, &cl->rate_est,
+					qdisc_root_sleeping_lock(sch),
+					tca[TCA_RATE]);
+		if (err) {
+			kfree(cl);
+			goto failure;
+		}
+	}
+
 	cl->R_tab = rtab;
 	rtab = NULL;
 	cl->refcnt = 1;
@@ -1929,10 +1915,6 @@
 
 	qdisc_class_hash_grow(sch, &q->clhash);
 
-	if (tca[TCA_RATE])
-		gen_new_estimator(&cl->bstats, &cl->rate_est,
-				  qdisc_root_sleeping_lock(sch), tca[TCA_RATE]);
-
 	*arg = (unsigned long)cl;
 	return 0;
 
@@ -2066,7 +2048,7 @@
 	.priv_size	=	sizeof(struct cbq_sched_data),
 	.enqueue	=	cbq_enqueue,
 	.dequeue	=	cbq_dequeue,
-	.requeue	=	cbq_requeue,
+	.peek		=	qdisc_peek_dequeued,
 	.drop		=	cbq_drop,
 	.init		=	cbq_init,
 	.reset		=	cbq_reset,
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
new file mode 100644
index 0000000..f6b4fa9
--- /dev/null
+++ b/net/sched/sch_drr.c
@@ -0,0 +1,519 @@
+/*
+ * net/sched/sch_drr.c         Deficit Round Robin scheduler
+ *
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can 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/errno.h>
+#include <linux/netdevice.h>
+#include <linux/pkt_sched.h>
+#include <net/sch_generic.h>
+#include <net/pkt_sched.h>
+#include <net/pkt_cls.h>
+
+struct drr_class {
+	struct Qdisc_class_common	common;
+	unsigned int			refcnt;
+	unsigned int			filter_cnt;
+
+	struct gnet_stats_basic		bstats;
+	struct gnet_stats_queue		qstats;
+	struct gnet_stats_rate_est	rate_est;
+	struct list_head		alist;
+	struct Qdisc			*qdisc;
+
+	u32				quantum;
+	u32				deficit;
+};
+
+struct drr_sched {
+	struct list_head		active;
+	struct tcf_proto		*filter_list;
+	struct Qdisc_class_hash		clhash;
+};
+
+static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+	struct Qdisc_class_common *clc;
+
+	clc = qdisc_class_find(&q->clhash, classid);
+	if (clc == NULL)
+		return NULL;
+	return container_of(clc, struct drr_class, common);
+}
+
+static void drr_purge_queue(struct drr_class *cl)
+{
+	unsigned int len = cl->qdisc->q.qlen;
+
+	qdisc_reset(cl->qdisc);
+	qdisc_tree_decrease_qlen(cl->qdisc, len);
+}
+
+static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = {
+	[TCA_DRR_QUANTUM]	= { .type = NLA_U32 },
+};
+
+static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
+			    struct nlattr **tca, unsigned long *arg)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+	struct drr_class *cl = (struct drr_class *)*arg;
+	struct nlattr *tb[TCA_DRR_MAX + 1];
+	u32 quantum;
+	int err;
+
+	err = nla_parse_nested(tb, TCA_DRR_MAX, tca[TCA_OPTIONS], drr_policy);
+	if (err < 0)
+		return err;
+
+	if (tb[TCA_DRR_QUANTUM]) {
+		quantum = nla_get_u32(tb[TCA_DRR_QUANTUM]);
+		if (quantum == 0)
+			return -EINVAL;
+	} else
+		quantum = psched_mtu(qdisc_dev(sch));
+
+	if (cl != NULL) {
+		if (tca[TCA_RATE]) {
+			err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+						    qdisc_root_sleeping_lock(sch),
+						    tca[TCA_RATE]);
+			if (err)
+				return err;
+		}
+
+		sch_tree_lock(sch);
+		if (tb[TCA_DRR_QUANTUM])
+			cl->quantum = quantum;
+		sch_tree_unlock(sch);
+
+		return 0;
+	}
+
+	cl = kzalloc(sizeof(struct drr_class), GFP_KERNEL);
+	if (cl == NULL)
+		return -ENOBUFS;
+
+	cl->refcnt	   = 1;
+	cl->common.classid = classid;
+	cl->quantum	   = quantum;
+	cl->qdisc	   = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+					       &pfifo_qdisc_ops, classid);
+	if (cl->qdisc == NULL)
+		cl->qdisc = &noop_qdisc;
+
+	if (tca[TCA_RATE]) {
+		err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+					    qdisc_root_sleeping_lock(sch),
+					    tca[TCA_RATE]);
+		if (err) {
+			qdisc_destroy(cl->qdisc);
+			kfree(cl);
+			return err;
+		}
+	}
+
+	sch_tree_lock(sch);
+	qdisc_class_hash_insert(&q->clhash, &cl->common);
+	sch_tree_unlock(sch);
+
+	qdisc_class_hash_grow(sch, &q->clhash);
+
+	*arg = (unsigned long)cl;
+	return 0;
+}
+
+static void drr_destroy_class(struct Qdisc *sch, struct drr_class *cl)
+{
+	gen_kill_estimator(&cl->bstats, &cl->rate_est);
+	qdisc_destroy(cl->qdisc);
+	kfree(cl);
+}
+
+static int drr_delete_class(struct Qdisc *sch, unsigned long arg)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+	struct drr_class *cl = (struct drr_class *)arg;
+
+	if (cl->filter_cnt > 0)
+		return -EBUSY;
+
+	sch_tree_lock(sch);
+
+	drr_purge_queue(cl);
+	qdisc_class_hash_remove(&q->clhash, &cl->common);
+
+	if (--cl->refcnt == 0)
+		drr_destroy_class(sch, cl);
+
+	sch_tree_unlock(sch);
+	return 0;
+}
+
+static unsigned long drr_get_class(struct Qdisc *sch, u32 classid)
+{
+	struct drr_class *cl = drr_find_class(sch, classid);
+
+	if (cl != NULL)
+		cl->refcnt++;
+
+	return (unsigned long)cl;
+}
+
+static void drr_put_class(struct Qdisc *sch, unsigned long arg)
+{
+	struct drr_class *cl = (struct drr_class *)arg;
+
+	if (--cl->refcnt == 0)
+		drr_destroy_class(sch, cl);
+}
+
+static struct tcf_proto **drr_tcf_chain(struct Qdisc *sch, unsigned long cl)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+
+	if (cl)
+		return NULL;
+
+	return &q->filter_list;
+}
+
+static unsigned long drr_bind_tcf(struct Qdisc *sch, unsigned long parent,
+				  u32 classid)
+{
+	struct drr_class *cl = drr_find_class(sch, classid);
+
+	if (cl != NULL)
+		cl->filter_cnt++;
+
+	return (unsigned long)cl;
+}
+
+static void drr_unbind_tcf(struct Qdisc *sch, unsigned long arg)
+{
+	struct drr_class *cl = (struct drr_class *)arg;
+
+	cl->filter_cnt--;
+}
+
+static int drr_graft_class(struct Qdisc *sch, unsigned long arg,
+			   struct Qdisc *new, struct Qdisc **old)
+{
+	struct drr_class *cl = (struct drr_class *)arg;
+
+	if (new == NULL) {
+		new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+					&pfifo_qdisc_ops, cl->common.classid);
+		if (new == NULL)
+			new = &noop_qdisc;
+	}
+
+	sch_tree_lock(sch);
+	drr_purge_queue(cl);
+	*old = cl->qdisc;
+	cl->qdisc = new;
+	sch_tree_unlock(sch);
+	return 0;
+}
+
+static struct Qdisc *drr_class_leaf(struct Qdisc *sch, unsigned long arg)
+{
+	struct drr_class *cl = (struct drr_class *)arg;
+
+	return cl->qdisc;
+}
+
+static void drr_qlen_notify(struct Qdisc *csh, unsigned long arg)
+{
+	struct drr_class *cl = (struct drr_class *)arg;
+
+	if (cl->qdisc->q.qlen == 0)
+		list_del(&cl->alist);
+}
+
+static int drr_dump_class(struct Qdisc *sch, unsigned long arg,
+			  struct sk_buff *skb, struct tcmsg *tcm)
+{
+	struct drr_class *cl = (struct drr_class *)arg;
+	struct nlattr *nest;
+
+	tcm->tcm_parent	= TC_H_ROOT;
+	tcm->tcm_handle	= cl->common.classid;
+	tcm->tcm_info	= cl->qdisc->handle;
+
+	nest = nla_nest_start(skb, TCA_OPTIONS);
+	if (nest == NULL)
+		goto nla_put_failure;
+	NLA_PUT_U32(skb, TCA_DRR_QUANTUM, cl->quantum);
+	return nla_nest_end(skb, nest);
+
+nla_put_failure:
+	nla_nest_cancel(skb, nest);
+	return -EMSGSIZE;
+}
+
+static int drr_dump_class_stats(struct Qdisc *sch, unsigned long arg,
+				struct gnet_dump *d)
+{
+	struct drr_class *cl = (struct drr_class *)arg;
+	struct tc_drr_stats xstats;
+
+	memset(&xstats, 0, sizeof(xstats));
+	if (cl->qdisc->q.qlen)
+		xstats.deficit = cl->deficit;
+
+	if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
+	    gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+	    gnet_stats_copy_queue(d, &cl->qdisc->qstats) < 0)
+		return -1;
+
+	return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
+}
+
+static void drr_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+	struct drr_class *cl;
+	struct hlist_node *n;
+	unsigned int i;
+
+	if (arg->stop)
+		return;
+
+	for (i = 0; i < q->clhash.hashsize; i++) {
+		hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) {
+			if (arg->count < arg->skip) {
+				arg->count++;
+				continue;
+			}
+			if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
+				arg->stop = 1;
+				return;
+			}
+			arg->count++;
+		}
+	}
+}
+
+static struct drr_class *drr_classify(struct sk_buff *skb, struct Qdisc *sch,
+				      int *qerr)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+	struct drr_class *cl;
+	struct tcf_result res;
+	int result;
+
+	if (TC_H_MAJ(skb->priority ^ sch->handle) == 0) {
+		cl = drr_find_class(sch, skb->priority);
+		if (cl != NULL)
+			return cl;
+	}
+
+	*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
+	result = tc_classify(skb, q->filter_list, &res);
+	if (result >= 0) {
+#ifdef CONFIG_NET_CLS_ACT
+		switch (result) {
+		case TC_ACT_QUEUED:
+		case TC_ACT_STOLEN:
+			*qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
+		case TC_ACT_SHOT:
+			return NULL;
+		}
+#endif
+		cl = (struct drr_class *)res.class;
+		if (cl == NULL)
+			cl = drr_find_class(sch, res.classid);
+		return cl;
+	}
+	return NULL;
+}
+
+static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+	struct drr_class *cl;
+	unsigned int len;
+	int err;
+
+	cl = drr_classify(skb, sch, &err);
+	if (cl == NULL) {
+		if (err & __NET_XMIT_BYPASS)
+			sch->qstats.drops++;
+		kfree_skb(skb);
+		return err;
+	}
+
+	len = qdisc_pkt_len(skb);
+	err = qdisc_enqueue(skb, cl->qdisc);
+	if (unlikely(err != NET_XMIT_SUCCESS)) {
+		if (net_xmit_drop_count(err)) {
+			cl->qstats.drops++;
+			sch->qstats.drops++;
+		}
+		return err;
+	}
+
+	if (cl->qdisc->q.qlen == 1) {
+		list_add_tail(&cl->alist, &q->active);
+		cl->deficit = cl->quantum;
+	}
+
+	cl->bstats.packets++;
+	cl->bstats.bytes += len;
+	sch->bstats.packets++;
+	sch->bstats.bytes += len;
+
+	sch->q.qlen++;
+	return err;
+}
+
+static struct sk_buff *drr_dequeue(struct Qdisc *sch)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+	struct drr_class *cl;
+	struct sk_buff *skb;
+	unsigned int len;
+
+	if (list_empty(&q->active))
+		goto out;
+	while (1) {
+		cl = list_first_entry(&q->active, struct drr_class, alist);
+		skb = cl->qdisc->ops->peek(cl->qdisc);
+		if (skb == NULL)
+			goto out;
+
+		len = qdisc_pkt_len(skb);
+		if (len <= cl->deficit) {
+			cl->deficit -= len;
+			skb = qdisc_dequeue_peeked(cl->qdisc);
+			if (cl->qdisc->q.qlen == 0)
+				list_del(&cl->alist);
+			sch->q.qlen--;
+			return skb;
+		}
+
+		cl->deficit += cl->quantum;
+		list_move_tail(&cl->alist, &q->active);
+	}
+out:
+	return NULL;
+}
+
+static unsigned int drr_drop(struct Qdisc *sch)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+	struct drr_class *cl;
+	unsigned int len;
+
+	list_for_each_entry(cl, &q->active, alist) {
+		if (cl->qdisc->ops->drop) {
+			len = cl->qdisc->ops->drop(cl->qdisc);
+			if (len > 0) {
+				sch->q.qlen--;
+				if (cl->qdisc->q.qlen == 0)
+					list_del(&cl->alist);
+				return len;
+			}
+		}
+	}
+	return 0;
+}
+
+static int drr_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+	int err;
+
+	err = qdisc_class_hash_init(&q->clhash);
+	if (err < 0)
+		return err;
+	INIT_LIST_HEAD(&q->active);
+	return 0;
+}
+
+static void drr_reset_qdisc(struct Qdisc *sch)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+	struct drr_class *cl;
+	struct hlist_node *n;
+	unsigned int i;
+
+	for (i = 0; i < q->clhash.hashsize; i++) {
+		hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) {
+			if (cl->qdisc->q.qlen)
+				list_del(&cl->alist);
+			qdisc_reset(cl->qdisc);
+		}
+	}
+	sch->q.qlen = 0;
+}
+
+static void drr_destroy_qdisc(struct Qdisc *sch)
+{
+	struct drr_sched *q = qdisc_priv(sch);
+	struct drr_class *cl;
+	struct hlist_node *n, *next;
+	unsigned int i;
+
+	tcf_destroy_chain(&q->filter_list);
+
+	for (i = 0; i < q->clhash.hashsize; i++) {
+		hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i],
+					  common.hnode)
+			drr_destroy_class(sch, cl);
+	}
+	qdisc_class_hash_destroy(&q->clhash);
+}
+
+static const struct Qdisc_class_ops drr_class_ops = {
+	.change		= drr_change_class,
+	.delete		= drr_delete_class,
+	.get		= drr_get_class,
+	.put		= drr_put_class,
+	.tcf_chain	= drr_tcf_chain,
+	.bind_tcf	= drr_bind_tcf,
+	.unbind_tcf	= drr_unbind_tcf,
+	.graft		= drr_graft_class,
+	.leaf		= drr_class_leaf,
+	.qlen_notify	= drr_qlen_notify,
+	.dump		= drr_dump_class,
+	.dump_stats	= drr_dump_class_stats,
+	.walk		= drr_walk,
+};
+
+static struct Qdisc_ops drr_qdisc_ops __read_mostly = {
+	.cl_ops		= &drr_class_ops,
+	.id		= "drr",
+	.priv_size	= sizeof(struct drr_sched),
+	.enqueue	= drr_enqueue,
+	.dequeue	= drr_dequeue,
+	.peek		= qdisc_peek_dequeued,
+	.drop		= drr_drop,
+	.init		= drr_init_qdisc,
+	.reset		= drr_reset_qdisc,
+	.destroy	= drr_destroy_qdisc,
+	.owner		= THIS_MODULE,
+};
+
+static int __init drr_init(void)
+{
+	return register_qdisc(&drr_qdisc_ops);
+}
+
+static void __exit drr_exit(void)
+{
+	unregister_qdisc(&drr_qdisc_ops);
+}
+
+module_init(drr_init);
+module_exit(drr_exit);
+MODULE_LICENSE("GPL");
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index ba43aab..d303daa 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -68,7 +68,8 @@
 	}
 
 	sch_tree_lock(sch);
-	*old = xchg(&p->q, new);
+	*old = p->q;
+	p->q = new;
 	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
 	qdisc_reset(*old);
 	sch_tree_unlock(sch);
@@ -313,24 +314,13 @@
 	return skb;
 }
 
-static int dsmark_requeue(struct sk_buff *skb, struct Qdisc *sch)
+static struct sk_buff *dsmark_peek(struct Qdisc *sch)
 {
 	struct dsmark_qdisc_data *p = qdisc_priv(sch);
-	int err;
 
-	pr_debug("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
+	pr_debug("dsmark_peek(sch %p,[qdisc %p])\n", sch, p);
 
-	err = p->q->ops->requeue(skb, p->q);
-	if (err != NET_XMIT_SUCCESS) {
-		if (net_xmit_drop_count(err))
-			sch->qstats.drops++;
-		return err;
-	}
-
-	sch->q.qlen++;
-	sch->qstats.requeues++;
-
-	return NET_XMIT_SUCCESS;
+	return p->q->ops->peek(p->q);
 }
 
 static unsigned int dsmark_drop(struct Qdisc *sch)
@@ -496,7 +486,7 @@
 	.priv_size	=	sizeof(struct dsmark_qdisc_data),
 	.enqueue	=	dsmark_enqueue,
 	.dequeue	=	dsmark_dequeue,
-	.requeue	=	dsmark_requeue,
+	.peek		=	dsmark_peek,
 	.drop		=	dsmark_drop,
 	.init		=	dsmark_init,
 	.reset		=	dsmark_reset,
diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c
index 23d258b..92cfc9d 100644
--- a/net/sched/sch_fifo.c
+++ b/net/sched/sch_fifo.c
@@ -83,7 +83,7 @@
 	.priv_size	=	sizeof(struct fifo_sched_data),
 	.enqueue	=	pfifo_enqueue,
 	.dequeue	=	qdisc_dequeue_head,
-	.requeue	=	qdisc_requeue,
+	.peek		=	qdisc_peek_head,
 	.drop		=	qdisc_queue_drop,
 	.init		=	fifo_init,
 	.reset		=	qdisc_reset_queue,
@@ -98,7 +98,7 @@
 	.priv_size	=	sizeof(struct fifo_sched_data),
 	.enqueue	=	bfifo_enqueue,
 	.dequeue	=	qdisc_dequeue_head,
-	.requeue	=	qdisc_requeue,
+	.peek		=	qdisc_peek_head,
 	.drop		=	qdisc_queue_drop,
 	.init		=	fifo_init,
 	.reset		=	qdisc_reset_queue,
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index cdcd16f..5f5efe4 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -224,7 +224,7 @@
 				char drivername[64];
 				WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n",
 				       dev->name, netdev_drivername(dev, drivername, 64));
-				dev->tx_timeout(dev);
+				dev->netdev_ops->ndo_tx_timeout(dev);
 			}
 			if (!mod_timer(&dev->watchdog_timer,
 				       round_jiffies(jiffies +
@@ -239,7 +239,7 @@
 
 void __netdev_watchdog_up(struct net_device *dev)
 {
-	if (dev->tx_timeout) {
+	if (dev->netdev_ops->ndo_tx_timeout) {
 		if (dev->watchdog_timeo <= 0)
 			dev->watchdog_timeo = 5*HZ;
 		if (!mod_timer(&dev->watchdog_timer,
@@ -311,21 +311,12 @@
 	return NULL;
 }
 
-static int noop_requeue(struct sk_buff *skb, struct Qdisc* qdisc)
-{
-	if (net_ratelimit())
-		printk(KERN_DEBUG "%s deferred output. It is buggy.\n",
-		       skb->dev->name);
-	kfree_skb(skb);
-	return NET_XMIT_CN;
-}
-
 struct Qdisc_ops noop_qdisc_ops __read_mostly = {
 	.id		=	"noop",
 	.priv_size	=	0,
 	.enqueue	=	noop_enqueue,
 	.dequeue	=	noop_dequeue,
-	.requeue	=	noop_requeue,
+	.peek		=	noop_dequeue,
 	.owner		=	THIS_MODULE,
 };
 
@@ -340,7 +331,6 @@
 	.flags		=	TCQ_F_BUILTIN,
 	.ops		=	&noop_qdisc_ops,
 	.list		=	LIST_HEAD_INIT(noop_qdisc.list),
-	.requeue.lock	=	__SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock),
 	.q.lock		=	__SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock),
 	.dev_queue	=	&noop_netdev_queue,
 };
@@ -351,7 +341,7 @@
 	.priv_size	=	0,
 	.enqueue	=	noop_enqueue,
 	.dequeue	=	noop_dequeue,
-	.requeue	=	noop_requeue,
+	.peek		=	noop_dequeue,
 	.owner		=	THIS_MODULE,
 };
 
@@ -367,7 +357,6 @@
 	.flags		=	TCQ_F_BUILTIN,
 	.ops		=	&noqueue_qdisc_ops,
 	.list		=	LIST_HEAD_INIT(noqueue_qdisc.list),
-	.requeue.lock	=	__SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock),
 	.q.lock		=	__SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock),
 	.dev_queue	=	&noqueue_netdev_queue,
 };
@@ -416,10 +405,17 @@
 	return NULL;
 }
 
-static int pfifo_fast_requeue(struct sk_buff *skb, struct Qdisc* qdisc)
+static struct sk_buff *pfifo_fast_peek(struct Qdisc* qdisc)
 {
-	qdisc->q.qlen++;
-	return __qdisc_requeue(skb, qdisc, prio2list(skb, qdisc));
+	int prio;
+	struct sk_buff_head *list = qdisc_priv(qdisc);
+
+	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
+		if (!skb_queue_empty(list + prio))
+			return skb_peek(list + prio);
+	}
+
+	return NULL;
 }
 
 static void pfifo_fast_reset(struct Qdisc* qdisc)
@@ -462,7 +458,7 @@
 	.priv_size	=	PFIFO_FAST_BANDS * sizeof(struct sk_buff_head),
 	.enqueue	=	pfifo_fast_enqueue,
 	.dequeue	=	pfifo_fast_dequeue,
-	.requeue	=	pfifo_fast_requeue,
+	.peek		=	pfifo_fast_peek,
 	.init		=	pfifo_fast_init,
 	.reset		=	pfifo_fast_reset,
 	.dump		=	pfifo_fast_dump,
@@ -488,7 +484,6 @@
 	sch->padded = (char *) sch - (char *) p;
 
 	INIT_LIST_HEAD(&sch->list);
-	skb_queue_head_init(&sch->requeue);
 	skb_queue_head_init(&sch->q);
 	sch->ops = ops;
 	sch->enqueue = ops->enqueue;
@@ -531,6 +526,9 @@
 
 	if (ops->reset)
 		ops->reset(qdisc);
+
+	kfree_skb(qdisc->gso_skb);
+	qdisc->gso_skb = NULL;
 }
 EXPORT_SYMBOL(qdisc_reset);
 
@@ -557,8 +555,6 @@
 	dev_put(qdisc_dev(qdisc));
 
 	kfree_skb(qdisc->gso_skb);
-	__skb_queue_purge(&qdisc->requeue);
-
 	kfree((char *) qdisc - qdisc->padded);
 }
 EXPORT_SYMBOL(qdisc_destroy);
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index c1ad6b8..40408d5 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -240,26 +240,6 @@
 	return NET_XMIT_CN;
 }
 
-static int gred_requeue(struct sk_buff *skb, struct Qdisc* sch)
-{
-	struct gred_sched *t = qdisc_priv(sch);
-	struct gred_sched_data *q;
-	u16 dp = tc_index_to_dp(skb);
-
-	if (dp >= t->DPs || (q = t->tab[dp]) == NULL) {
-		if (net_ratelimit())
-			printk(KERN_WARNING "GRED: Unable to relocate VQ 0x%x "
-			       "for requeue, screwing up backlog.\n",
-			       tc_index_to_dp(skb));
-	} else {
-		if (red_is_idling(&q->parms))
-			red_end_of_idle_period(&q->parms);
-		q->backlog += qdisc_pkt_len(skb);
-	}
-
-	return qdisc_requeue(skb, sch);
-}
-
 static struct sk_buff *gred_dequeue(struct Qdisc* sch)
 {
 	struct sk_buff *skb;
@@ -602,7 +582,7 @@
 	.priv_size	=	sizeof(struct gred_sched),
 	.enqueue	=	gred_enqueue,
 	.dequeue	=	gred_dequeue,
-	.requeue	=	gred_requeue,
+	.peek		=	qdisc_peek_head,
 	.drop		=	gred_drop,
 	.init		=	gred_init,
 	.reset		=	gred_reset,
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index c1e77da..45c31b1 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -184,7 +184,6 @@
 	struct rb_root eligible;		/* eligible tree */
 	struct list_head droplist;		/* active leaf class list (for
 						   dropping) */
-	struct sk_buff_head requeue;		/* requeued packet */
 	struct qdisc_watchdog watchdog;		/* watchdog timer */
 };
 
@@ -880,28 +879,20 @@
 	 */
 }
 
-/*
- * hack to get length of first packet in queue.
- */
 static unsigned int
 qdisc_peek_len(struct Qdisc *sch)
 {
 	struct sk_buff *skb;
 	unsigned int len;
 
-	skb = sch->dequeue(sch);
+	skb = sch->ops->peek(sch);
 	if (skb == NULL) {
 		if (net_ratelimit())
 			printk("qdisc_peek_len: non work-conserving qdisc ?\n");
 		return 0;
 	}
 	len = qdisc_pkt_len(skb);
-	if (unlikely(sch->ops->requeue(skb, sch) != NET_XMIT_SUCCESS)) {
-		if (net_ratelimit())
-			printk("qdisc_peek_len: failed to requeue\n");
-		qdisc_tree_decrease_qlen(sch, 1);
-		return 0;
-	}
+
 	return len;
 }
 
@@ -1027,6 +1018,14 @@
 		}
 		cur_time = psched_get_time();
 
+		if (tca[TCA_RATE]) {
+			err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+					      qdisc_root_sleeping_lock(sch),
+					      tca[TCA_RATE]);
+			if (err)
+				return err;
+		}
+
 		sch_tree_lock(sch);
 		if (rsc != NULL)
 			hfsc_change_rsc(cl, rsc, cur_time);
@@ -1043,10 +1042,6 @@
 		}
 		sch_tree_unlock(sch);
 
-		if (tca[TCA_RATE])
-			gen_replace_estimator(&cl->bstats, &cl->rate_est,
-					      qdisc_root_sleeping_lock(sch),
-					      tca[TCA_RATE]);
 		return 0;
 	}
 
@@ -1072,6 +1067,16 @@
 	if (cl == NULL)
 		return -ENOBUFS;
 
+	if (tca[TCA_RATE]) {
+		err = gen_new_estimator(&cl->bstats, &cl->rate_est,
+					qdisc_root_sleeping_lock(sch),
+					tca[TCA_RATE]);
+		if (err) {
+			kfree(cl);
+			return err;
+		}
+	}
+
 	if (rsc != NULL)
 		hfsc_change_rsc(cl, rsc, 0);
 	if (fsc != NULL)
@@ -1102,9 +1107,6 @@
 
 	qdisc_class_hash_grow(sch, &q->clhash);
 
-	if (tca[TCA_RATE])
-		gen_new_estimator(&cl->bstats, &cl->rate_est,
-				  qdisc_root_sleeping_lock(sch), tca[TCA_RATE]);
 	*arg = (unsigned long)cl;
 	return 0;
 }
@@ -1211,7 +1213,8 @@
 
 	sch_tree_lock(sch);
 	hfsc_purge_queue(sch, cl);
-	*old = xchg(&cl->qdisc, new);
+	*old = cl->qdisc;
+	cl->qdisc = new;
 	sch_tree_unlock(sch);
 	return 0;
 }
@@ -1440,7 +1443,6 @@
 		return err;
 	q->eligible = RB_ROOT;
 	INIT_LIST_HEAD(&q->droplist);
-	skb_queue_head_init(&q->requeue);
 
 	q->root.cl_common.classid = sch->handle;
 	q->root.refcnt  = 1;
@@ -1525,7 +1527,6 @@
 		hlist_for_each_entry(cl, n, &q->clhash.hash[i], cl_common.hnode)
 			hfsc_reset_class(cl);
 	}
-	__skb_queue_purge(&q->requeue);
 	q->eligible = RB_ROOT;
 	INIT_LIST_HEAD(&q->droplist);
 	qdisc_watchdog_cancel(&q->watchdog);
@@ -1550,7 +1551,6 @@
 			hfsc_destroy_class(sch, cl);
 	}
 	qdisc_class_hash_destroy(&q->clhash);
-	__skb_queue_purge(&q->requeue);
 	qdisc_watchdog_cancel(&q->watchdog);
 }
 
@@ -1574,7 +1574,7 @@
 hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
 	struct hfsc_class *cl;
-	int err;
+	int uninitialized_var(err);
 
 	cl = hfsc_classify(skb, sch, &err);
 	if (cl == NULL) {
@@ -1617,8 +1617,6 @@
 
 	if (sch->q.qlen == 0)
 		return NULL;
-	if ((skb = __skb_dequeue(&q->requeue)))
-		goto out;
 
 	cur_time = psched_get_time();
 
@@ -1642,7 +1640,7 @@
 		}
 	}
 
-	skb = cl->qdisc->dequeue(cl->qdisc);
+	skb = qdisc_dequeue_peeked(cl->qdisc);
 	if (skb == NULL) {
 		if (net_ratelimit())
 			printk("HFSC: Non-work-conserving qdisc ?\n");
@@ -1667,24 +1665,12 @@
 		set_passive(cl);
 	}
 
- out:
 	sch->flags &= ~TCQ_F_THROTTLED;
 	sch->q.qlen--;
 
 	return skb;
 }
 
-static int
-hfsc_requeue(struct sk_buff *skb, struct Qdisc *sch)
-{
-	struct hfsc_sched *q = qdisc_priv(sch);
-
-	__skb_queue_head(&q->requeue, skb);
-	sch->q.qlen++;
-	sch->qstats.requeues++;
-	return NET_XMIT_SUCCESS;
-}
-
 static unsigned int
 hfsc_drop(struct Qdisc *sch)
 {
@@ -1735,7 +1721,7 @@
 	.dump		= hfsc_dump_qdisc,
 	.enqueue	= hfsc_enqueue,
 	.dequeue	= hfsc_dequeue,
-	.requeue	= hfsc_requeue,
+	.peek		= qdisc_peek_dequeued,
 	.drop		= hfsc_drop,
 	.cl_ops		= &hfsc_class_ops,
 	.priv_size	= sizeof(struct hfsc_sched),
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index d14f020..5070643 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -84,12 +84,12 @@
 	unsigned int children;
 	struct htb_class *parent;	/* parent class */
 
+	int prio;		/* these two are used only by leaves... */
+	int quantum;		/* but stored for parent-to-leaf return */
+
 	union {
 		struct htb_class_leaf {
 			struct Qdisc *q;
-			int prio;
-			int aprio;
-			int quantum;
 			int deficit[TC_HTB_MAXDEPTH];
 			struct list_head drop_list;
 		} leaf;
@@ -123,19 +123,8 @@
 	psched_tdiff_t mbuffer;	/* max wait time */
 	long tokens, ctokens;	/* current number of tokens */
 	psched_time_t t_c;	/* checkpoint time */
-
-	int prio;		/* For parent to leaf return possible here */
-	int quantum;		/* we do backup. Finally full replacement  */
-				/* of un.leaf originals should be done. */
 };
 
-static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate,
-			   int size)
-{
-	long result = qdisc_l2t(rate, size);
-	return result;
-}
-
 struct htb_sched {
 	struct Qdisc_class_hash clhash;
 	struct list_head drops[TC_HTB_NUMPRIO];/* active leaves (for drops) */
@@ -152,9 +141,6 @@
 	/* time of nearest event per level (row) */
 	psched_time_t near_ev_cache[TC_HTB_MAXDEPTH];
 
-	/* whether we hit non-work conserving class during this dequeue; we use */
-	int nwc_hit;		/* this to disable mindelay complaint in dequeue */
-
 	int defcls;		/* class where unclassified flows go to */
 
 	/* filters for qdisc itself */
@@ -527,10 +513,10 @@
 	WARN_ON(cl->level || !cl->un.leaf.q || !cl->un.leaf.q->q.qlen);
 
 	if (!cl->prio_activity) {
-		cl->prio_activity = 1 << (cl->un.leaf.aprio = cl->un.leaf.prio);
+		cl->prio_activity = 1 << cl->prio;
 		htb_activate_prios(q, cl);
 		list_add_tail(&cl->un.leaf.drop_list,
-			      q->drops + cl->un.leaf.aprio);
+			      q->drops + cl->prio);
 	}
 }
 
@@ -551,7 +537,7 @@
 
 static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
-	int ret;
+	int uninitialized_var(ret);
 	struct htb_sched *q = qdisc_priv(sch);
 	struct htb_class *cl = htb_classify(skb, sch, &ret);
 
@@ -591,45 +577,30 @@
 	return NET_XMIT_SUCCESS;
 }
 
-/* TODO: requeuing packet charges it to policers again !! */
-static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
+static inline void htb_accnt_tokens(struct htb_class *cl, int bytes, long diff)
 {
-	int ret;
-	struct htb_sched *q = qdisc_priv(sch);
-	struct htb_class *cl = htb_classify(skb, sch, &ret);
-	struct sk_buff *tskb;
+	long toks = diff + cl->tokens;
 
-	if (cl == HTB_DIRECT) {
-		/* enqueue to helper queue */
-		if (q->direct_queue.qlen < q->direct_qlen) {
-			__skb_queue_head(&q->direct_queue, skb);
-		} else {
-			__skb_queue_head(&q->direct_queue, skb);
-			tskb = __skb_dequeue_tail(&q->direct_queue);
-			kfree_skb(tskb);
-			sch->qstats.drops++;
-			return NET_XMIT_CN;
-		}
-#ifdef CONFIG_NET_CLS_ACT
-	} else if (!cl) {
-		if (ret & __NET_XMIT_BYPASS)
-			sch->qstats.drops++;
-		kfree_skb(skb);
-		return ret;
-#endif
-	} else if ((ret = cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q)) !=
-		   NET_XMIT_SUCCESS) {
-		if (net_xmit_drop_count(ret)) {
-			sch->qstats.drops++;
-			cl->qstats.drops++;
-		}
-		return ret;
-	} else
-		htb_activate(q, cl);
+	if (toks > cl->buffer)
+		toks = cl->buffer;
+	toks -= (long) qdisc_l2t(cl->rate, bytes);
+	if (toks <= -cl->mbuffer)
+		toks = 1 - cl->mbuffer;
 
-	sch->q.qlen++;
-	sch->qstats.requeues++;
-	return NET_XMIT_SUCCESS;
+	cl->tokens = toks;
+}
+
+static inline void htb_accnt_ctokens(struct htb_class *cl, int bytes, long diff)
+{
+	long toks = diff + cl->ctokens;
+
+	if (toks > cl->cbuffer)
+		toks = cl->cbuffer;
+	toks -= (long) qdisc_l2t(cl->ceil, bytes);
+	if (toks <= -cl->mbuffer)
+		toks = 1 - cl->mbuffer;
+
+	cl->ctokens = toks;
 }
 
 /**
@@ -647,26 +618,20 @@
 			     int level, struct sk_buff *skb)
 {
 	int bytes = qdisc_pkt_len(skb);
-	long toks, diff;
 	enum htb_cmode old_mode;
-
-#define HTB_ACCNT(T,B,R) toks = diff + cl->T; \
-	if (toks > cl->B) toks = cl->B; \
-	toks -= L2T(cl, cl->R, bytes); \
-	if (toks <= -cl->mbuffer) toks = 1-cl->mbuffer; \
-	cl->T = toks
+	long diff;
 
 	while (cl) {
 		diff = psched_tdiff_bounded(q->now, cl->t_c, cl->mbuffer);
 		if (cl->level >= level) {
 			if (cl->level == level)
 				cl->xstats.lends++;
-			HTB_ACCNT(tokens, buffer, rate);
+			htb_accnt_tokens(cl, bytes, diff);
 		} else {
 			cl->xstats.borrows++;
 			cl->tokens += diff;	/* we moved t_c; update tokens */
 		}
-		HTB_ACCNT(ctokens, cbuffer, ceil);
+		htb_accnt_ctokens(cl, bytes, diff);
 		cl->t_c = q->now;
 
 		old_mode = cl->cmode;
@@ -733,14 +698,14 @@
 	while (n) {
 		struct htb_class *cl =
 		    rb_entry(n, struct htb_class, node[prio]);
-		if (id == cl->common.classid)
-			return n;
 
 		if (id > cl->common.classid) {
 			n = n->rb_right;
-		} else {
+		} else if (id < cl->common.classid) {
 			r = n;
 			n = n->rb_left;
+		} else {
+			return n;
 		}
 	}
 	return r;
@@ -761,7 +726,7 @@
 		u32 *pid;
 	} stk[TC_HTB_MAXDEPTH], *sp = stk;
 
-	WARN_ON(!tree->rb_node);
+	BUG_ON(!tree->rb_node);
 	sp->root = tree->rb_node;
 	sp->pptr = pptr;
 	sp->pid = pid;
@@ -781,9 +746,10 @@
 				*sp->pptr = (*sp->pptr)->rb_left;
 			if (sp > stk) {
 				sp--;
-				WARN_ON(!*sp->pptr);
-				if (!*sp->pptr)
+				if (!*sp->pptr) {
+					WARN_ON(1);
 					return NULL;
+				}
 				htb_next_rb_node(sp->pptr);
 			}
 		} else {
@@ -814,8 +780,7 @@
 
 	do {
 next:
-		WARN_ON(!cl);
-		if (!cl)
+		if (unlikely(!cl))
 			return NULL;
 
 		/* class can be empty - it is unlikely but can be true if leaf
@@ -849,7 +814,7 @@
 			       cl->common.classid);
 			cl->warned = 1;
 		}
-		q->nwc_hit++;
+
 		htb_next_rb_node((level ? cl->parent->un.inner.ptr : q->
 				  ptr[0]) + prio);
 		cl = htb_lookup_leaf(q->row[level] + prio, prio,
@@ -861,7 +826,7 @@
 	if (likely(skb != NULL)) {
 		cl->un.leaf.deficit[level] -= qdisc_pkt_len(skb);
 		if (cl->un.leaf.deficit[level] < 0) {
-			cl->un.leaf.deficit[level] += cl->un.leaf.quantum;
+			cl->un.leaf.deficit[level] += cl->quantum;
 			htb_next_rb_node((level ? cl->parent->un.inner.ptr : q->
 					  ptr[0]) + prio);
 		}
@@ -894,7 +859,7 @@
 	q->now = psched_get_time();
 
 	next_event = q->now + 5 * PSCHED_TICKS_PER_SEC;
-	q->nwc_hit = 0;
+
 	for (level = 0; level < TC_HTB_MAXDEPTH; level++) {
 		/* common case optimization - skip event handler quickly */
 		int m;
@@ -1095,8 +1060,8 @@
 	opt.buffer = cl->buffer;
 	opt.ceil = cl->ceil->rate;
 	opt.cbuffer = cl->cbuffer;
-	opt.quantum = cl->un.leaf.quantum;
-	opt.prio = cl->un.leaf.prio;
+	opt.quantum = cl->quantum;
+	opt.prio = cl->prio;
 	opt.level = cl->level;
 	NLA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt);
 
@@ -1141,7 +1106,9 @@
 		    == NULL)
 			return -ENOBUFS;
 		sch_tree_lock(sch);
-		if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) {
+		*old = cl->un.leaf.q;
+		cl->un.leaf.q = new;
+		if (*old != NULL) {
 			qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
 			qdisc_reset(*old);
 		}
@@ -1198,8 +1165,6 @@
 	memset(&parent->un.inner, 0, sizeof(parent->un.inner));
 	INIT_LIST_HEAD(&parent->un.leaf.drop_list);
 	parent->un.leaf.q = new_q ? new_q : &noop_qdisc;
-	parent->un.leaf.quantum = parent->quantum;
-	parent->un.leaf.prio = parent->prio;
 	parent->tokens = parent->buffer;
 	parent->ctokens = parent->cbuffer;
 	parent->t_c = psched_get_time();
@@ -1371,9 +1336,14 @@
 		if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL)
 			goto failure;
 
-		gen_new_estimator(&cl->bstats, &cl->rate_est,
-				  qdisc_root_sleeping_lock(sch),
-				  tca[TCA_RATE] ? : &est.nla);
+		err = gen_new_estimator(&cl->bstats, &cl->rate_est,
+					qdisc_root_sleeping_lock(sch),
+					tca[TCA_RATE] ? : &est.nla);
+		if (err) {
+			kfree(cl);
+			goto failure;
+		}
+
 		cl->refcnt = 1;
 		cl->children = 0;
 		INIT_LIST_HEAD(&cl->un.leaf.drop_list);
@@ -1425,37 +1395,36 @@
 		if (parent)
 			parent->children++;
 	} else {
-		if (tca[TCA_RATE])
-			gen_replace_estimator(&cl->bstats, &cl->rate_est,
-					      qdisc_root_sleeping_lock(sch),
-					      tca[TCA_RATE]);
+		if (tca[TCA_RATE]) {
+			err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+						    qdisc_root_sleeping_lock(sch),
+						    tca[TCA_RATE]);
+			if (err)
+				return err;
+		}
 		sch_tree_lock(sch);
 	}
 
 	/* it used to be a nasty bug here, we have to check that node
 	   is really leaf before changing cl->un.leaf ! */
 	if (!cl->level) {
-		cl->un.leaf.quantum = rtab->rate.rate / q->rate2quantum;
-		if (!hopt->quantum && cl->un.leaf.quantum < 1000) {
+		cl->quantum = rtab->rate.rate / q->rate2quantum;
+		if (!hopt->quantum && cl->quantum < 1000) {
 			printk(KERN_WARNING
 			       "HTB: quantum of class %X is small. Consider r2q change.\n",
 			       cl->common.classid);
-			cl->un.leaf.quantum = 1000;
+			cl->quantum = 1000;
 		}
-		if (!hopt->quantum && cl->un.leaf.quantum > 200000) {
+		if (!hopt->quantum && cl->quantum > 200000) {
 			printk(KERN_WARNING
 			       "HTB: quantum of class %X is big. Consider r2q change.\n",
 			       cl->common.classid);
-			cl->un.leaf.quantum = 200000;
+			cl->quantum = 200000;
 		}
 		if (hopt->quantum)
-			cl->un.leaf.quantum = hopt->quantum;
-		if ((cl->un.leaf.prio = hopt->prio) >= TC_HTB_NUMPRIO)
-			cl->un.leaf.prio = TC_HTB_NUMPRIO - 1;
-
-		/* backup for htb_parent_to_leaf */
-		cl->quantum = cl->un.leaf.quantum;
-		cl->prio = cl->un.leaf.prio;
+			cl->quantum = hopt->quantum;
+		if ((cl->prio = hopt->prio) >= TC_HTB_NUMPRIO)
+			cl->prio = TC_HTB_NUMPRIO - 1;
 	}
 
 	cl->buffer = hopt->buffer;
@@ -1565,7 +1534,7 @@
 	.priv_size	=	sizeof(struct htb_sched),
 	.enqueue	=	htb_enqueue,
 	.dequeue	=	htb_dequeue,
-	.requeue	=	htb_requeue,
+	.peek		=	qdisc_peek_dequeued,
 	.drop		=	htb_drop,
 	.init		=	htb_init,
 	.reset		=	htb_reset,
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
index 915f314..7e15186 100644
--- a/net/sched/sch_multiq.c
+++ b/net/sched/sch_multiq.c
@@ -92,40 +92,6 @@
 	return ret;
 }
 
-
-static int
-multiq_requeue(struct sk_buff *skb, struct Qdisc *sch)
-{
-	struct Qdisc *qdisc;
-	struct multiq_sched_data *q = qdisc_priv(sch);
-	int ret;
-
-	qdisc = multiq_classify(skb, sch, &ret);
-#ifdef CONFIG_NET_CLS_ACT
-	if (qdisc == NULL) {
-		if (ret & __NET_XMIT_BYPASS)
-			sch->qstats.drops++;
-		kfree_skb(skb);
-		return ret;
-	}
-#endif
-
-	ret = qdisc->ops->requeue(skb, qdisc);
-	if (ret == NET_XMIT_SUCCESS) {
-		sch->q.qlen++;
-		sch->qstats.requeues++;
-		if (q->curband)
-			q->curband--;
-		else
-			q->curband = q->bands - 1;
-		return NET_XMIT_SUCCESS;
-	}
-	if (net_xmit_drop_count(ret))
-		sch->qstats.drops++;
-	return ret;
-}
-
-
 static struct sk_buff *multiq_dequeue(struct Qdisc *sch)
 {
 	struct multiq_sched_data *q = qdisc_priv(sch);
@@ -140,7 +106,7 @@
 			q->curband = 0;
 
 		/* Check that target subqueue is available before
-		 * pulling an skb to avoid excessive requeues
+		 * pulling an skb to avoid head-of-line blocking.
 		 */
 		if (!__netif_subqueue_stopped(qdisc_dev(sch), q->curband)) {
 			qdisc = q->queues[q->curband];
@@ -155,6 +121,34 @@
 
 }
 
+static struct sk_buff *multiq_peek(struct Qdisc *sch)
+{
+	struct multiq_sched_data *q = qdisc_priv(sch);
+	unsigned int curband = q->curband;
+	struct Qdisc *qdisc;
+	struct sk_buff *skb;
+	int band;
+
+	for (band = 0; band < q->bands; band++) {
+		/* cycle through bands to ensure fairness */
+		curband++;
+		if (curband >= q->bands)
+			curband = 0;
+
+		/* Check that target subqueue is available before
+		 * pulling an skb to avoid head-of-line blocking.
+		 */
+		if (!__netif_subqueue_stopped(qdisc_dev(sch), curband)) {
+			qdisc = q->queues[curband];
+			skb = qdisc->ops->peek(qdisc);
+			if (skb)
+				return skb;
+		}
+	}
+	return NULL;
+
+}
+
 static unsigned int multiq_drop(struct Qdisc *sch)
 {
 	struct multiq_sched_data *q = qdisc_priv(sch);
@@ -220,7 +214,8 @@
 	q->bands = qopt->bands;
 	for (i = q->bands; i < q->max_bands; i++) {
 		if (q->queues[i] != &noop_qdisc) {
-			struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc);
+			struct Qdisc *child = q->queues[i];
+			q->queues[i] = &noop_qdisc;
 			qdisc_tree_decrease_qlen(child, child->q.qlen);
 			qdisc_destroy(child);
 		}
@@ -230,7 +225,7 @@
 
 	for (i = 0; i < q->bands; i++) {
 		if (q->queues[i] == &noop_qdisc) {
-			struct Qdisc *child;
+			struct Qdisc *child, *old;
 			child = qdisc_create_dflt(qdisc_dev(sch),
 						  sch->dev_queue,
 						  &pfifo_qdisc_ops,
@@ -238,12 +233,13 @@
 							    i + 1));
 			if (child) {
 				sch_tree_lock(sch);
-				child = xchg(&q->queues[i], child);
+				old = q->queues[i];
+				q->queues[i] = child;
 
-				if (child != &noop_qdisc) {
-					qdisc_tree_decrease_qlen(child,
-								 child->q.qlen);
-					qdisc_destroy(child);
+				if (old != &noop_qdisc) {
+					qdisc_tree_decrease_qlen(old,
+								 old->q.qlen);
+					qdisc_destroy(old);
 				}
 				sch_tree_unlock(sch);
 			}
@@ -451,7 +447,7 @@
 	.priv_size	=	sizeof(struct multiq_sched_data),
 	.enqueue	=	multiq_enqueue,
 	.dequeue	=	multiq_dequeue,
-	.requeue	=	multiq_requeue,
+	.peek		=	multiq_peek,
 	.drop		=	multiq_drop,
 	.init		=	multiq_init,
 	.reset		=	multiq_reset,
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 98402f0..d876b87 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -230,7 +230,11 @@
 		 */
 		cb->time_to_send = psched_get_time();
 		q->counter = 0;
-		ret = q->qdisc->ops->requeue(skb, q->qdisc);
+
+		__skb_queue_head(&q->qdisc->q, skb);
+		q->qdisc->qstats.backlog += qdisc_pkt_len(skb);
+		q->qdisc->qstats.requeues++;
+		ret = NET_XMIT_SUCCESS;
 	}
 
 	if (likely(ret == NET_XMIT_SUCCESS)) {
@@ -245,20 +249,6 @@
 	return ret;
 }
 
-/* Requeue packets but don't change time stamp */
-static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch)
-{
-	struct netem_sched_data *q = qdisc_priv(sch);
-	int ret;
-
-	if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) {
-		sch->q.qlen++;
-		sch->qstats.requeues++;
-	}
-
-	return ret;
-}
-
 static unsigned int netem_drop(struct Qdisc* sch)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
@@ -276,29 +266,25 @@
 	struct netem_sched_data *q = qdisc_priv(sch);
 	struct sk_buff *skb;
 
-	smp_mb();
 	if (sch->flags & TCQ_F_THROTTLED)
 		return NULL;
 
-	skb = q->qdisc->dequeue(q->qdisc);
+	skb = q->qdisc->ops->peek(q->qdisc);
 	if (skb) {
 		const struct netem_skb_cb *cb = netem_skb_cb(skb);
 		psched_time_t now = psched_get_time();
 
 		/* if more time remaining? */
 		if (cb->time_to_send <= now) {
+			skb = qdisc_dequeue_peeked(q->qdisc);
+			if (unlikely(!skb))
+				return NULL;
+
 			pr_debug("netem_dequeue: return skb=%p\n", skb);
 			sch->q.qlen--;
 			return skb;
 		}
 
-		if (unlikely(q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS)) {
-			qdisc_tree_decrease_qlen(q->qdisc, 1);
-			sch->qstats.drops++;
-			printk(KERN_ERR "netem: %s could not requeue\n",
-			       q->qdisc->ops->id);
-		}
-
 		qdisc_watchdog_schedule(&q->watchdog, cb->time_to_send);
 	}
 
@@ -341,14 +327,13 @@
 	root_lock = qdisc_root_sleeping_lock(sch);
 
 	spin_lock_bh(root_lock);
-	d = xchg(&q->delay_dist, d);
+	kfree(q->delay_dist);
+	q->delay_dist = d;
 	spin_unlock_bh(root_lock);
-
-	kfree(d);
 	return 0;
 }
 
-static int get_correlation(struct Qdisc *sch, const struct nlattr *attr)
+static void get_correlation(struct Qdisc *sch, const struct nlattr *attr)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
 	const struct tc_netem_corr *c = nla_data(attr);
@@ -356,27 +341,24 @@
 	init_crandom(&q->delay_cor, c->delay_corr);
 	init_crandom(&q->loss_cor, c->loss_corr);
 	init_crandom(&q->dup_cor, c->dup_corr);
-	return 0;
 }
 
-static int get_reorder(struct Qdisc *sch, const struct nlattr *attr)
+static void get_reorder(struct Qdisc *sch, const struct nlattr *attr)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
 	const struct tc_netem_reorder *r = nla_data(attr);
 
 	q->reorder = r->probability;
 	init_crandom(&q->reorder_cor, r->correlation);
-	return 0;
 }
 
-static int get_corrupt(struct Qdisc *sch, const struct nlattr *attr)
+static void get_corrupt(struct Qdisc *sch, const struct nlattr *attr)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
 	const struct tc_netem_corrupt *r = nla_data(attr);
 
 	q->corrupt = r->probability;
 	init_crandom(&q->corrupt_cor, r->correlation);
-	return 0;
 }
 
 static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
@@ -435,11 +417,8 @@
 	if (q->gap)
 		q->reorder = ~0;
 
-	if (tb[TCA_NETEM_CORR]) {
-		ret = get_correlation(sch, tb[TCA_NETEM_CORR]);
-		if (ret)
-			return ret;
-	}
+	if (tb[TCA_NETEM_CORR])
+		get_correlation(sch, tb[TCA_NETEM_CORR]);
 
 	if (tb[TCA_NETEM_DELAY_DIST]) {
 		ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]);
@@ -447,17 +426,11 @@
 			return ret;
 	}
 
-	if (tb[TCA_NETEM_REORDER]) {
-		ret = get_reorder(sch, tb[TCA_NETEM_REORDER]);
-		if (ret)
-			return ret;
-	}
+	if (tb[TCA_NETEM_REORDER])
+		get_reorder(sch, tb[TCA_NETEM_REORDER]);
 
-	if (tb[TCA_NETEM_CORRUPT]) {
-		ret = get_corrupt(sch, tb[TCA_NETEM_CORRUPT]);
-		if (ret)
-			return ret;
-	}
+	if (tb[TCA_NETEM_CORRUPT])
+		get_corrupt(sch, tb[TCA_NETEM_CORRUPT]);
 
 	return 0;
 }
@@ -538,7 +511,7 @@
 	.priv_size	=	sizeof(struct fifo_sched_data),
 	.enqueue	=	tfifo_enqueue,
 	.dequeue	=	qdisc_dequeue_head,
-	.requeue	=	qdisc_requeue,
+	.peek		=	qdisc_peek_head,
 	.drop		=	qdisc_queue_drop,
 	.init		=	tfifo_init,
 	.reset		=	qdisc_reset_queue,
@@ -621,99 +594,12 @@
 	return -1;
 }
 
-static int netem_dump_class(struct Qdisc *sch, unsigned long cl,
-			  struct sk_buff *skb, struct tcmsg *tcm)
-{
-	struct netem_sched_data *q = qdisc_priv(sch);
-
-	if (cl != 1) 	/* only one class */
-		return -ENOENT;
-
-	tcm->tcm_handle |= TC_H_MIN(1);
-	tcm->tcm_info = q->qdisc->handle;
-
-	return 0;
-}
-
-static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
-{
-	struct netem_sched_data *q = qdisc_priv(sch);
-
-	if (new == NULL)
-		new = &noop_qdisc;
-
-	sch_tree_lock(sch);
-	*old = xchg(&q->qdisc, new);
-	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-	qdisc_reset(*old);
-	sch_tree_unlock(sch);
-
-	return 0;
-}
-
-static struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
-{
-	struct netem_sched_data *q = qdisc_priv(sch);
-	return q->qdisc;
-}
-
-static unsigned long netem_get(struct Qdisc *sch, u32 classid)
-{
-	return 1;
-}
-
-static void netem_put(struct Qdisc *sch, unsigned long arg)
-{
-}
-
-static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
-			    struct nlattr **tca, unsigned long *arg)
-{
-	return -ENOSYS;
-}
-
-static int netem_delete(struct Qdisc *sch, unsigned long arg)
-{
-	return -ENOSYS;
-}
-
-static void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker)
-{
-	if (!walker->stop) {
-		if (walker->count >= walker->skip)
-			if (walker->fn(sch, 1, walker) < 0) {
-				walker->stop = 1;
-				return;
-			}
-		walker->count++;
-	}
-}
-
-static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl)
-{
-	return NULL;
-}
-
-static const struct Qdisc_class_ops netem_class_ops = {
-	.graft		=	netem_graft,
-	.leaf		=	netem_leaf,
-	.get		=	netem_get,
-	.put		=	netem_put,
-	.change		=	netem_change_class,
-	.delete		=	netem_delete,
-	.walk		=	netem_walk,
-	.tcf_chain	=	netem_find_tcf,
-	.dump		=	netem_dump_class,
-};
-
 static struct Qdisc_ops netem_qdisc_ops __read_mostly = {
 	.id		=	"netem",
-	.cl_ops		=	&netem_class_ops,
 	.priv_size	=	sizeof(struct netem_sched_data),
 	.enqueue	=	netem_enqueue,
 	.dequeue	=	netem_dequeue,
-	.requeue	=	netem_requeue,
+	.peek		=	qdisc_peek_dequeued,
 	.drop		=	netem_drop,
 	.init		=	netem_init,
 	.reset		=	netem_reset,
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 504a78c..94cecef 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -93,34 +93,20 @@
 	return ret;
 }
 
-
-static int
-prio_requeue(struct sk_buff *skb, struct Qdisc* sch)
+static struct sk_buff *prio_peek(struct Qdisc *sch)
 {
-	struct Qdisc *qdisc;
-	int ret;
+	struct prio_sched_data *q = qdisc_priv(sch);
+	int prio;
 
-	qdisc = prio_classify(skb, sch, &ret);
-#ifdef CONFIG_NET_CLS_ACT
-	if (qdisc == NULL) {
-		if (ret & __NET_XMIT_BYPASS)
-			sch->qstats.drops++;
-		kfree_skb(skb);
-		return ret;
+	for (prio = 0; prio < q->bands; prio++) {
+		struct Qdisc *qdisc = q->queues[prio];
+		struct sk_buff *skb = qdisc->ops->peek(qdisc);
+		if (skb)
+			return skb;
 	}
-#endif
-
-	if ((ret = qdisc->ops->requeue(skb, qdisc)) == NET_XMIT_SUCCESS) {
-		sch->q.qlen++;
-		sch->qstats.requeues++;
-		return NET_XMIT_SUCCESS;
-	}
-	if (net_xmit_drop_count(ret))
-		sch->qstats.drops++;
-	return ret;
+	return NULL;
 }
 
-
 static struct sk_buff *prio_dequeue(struct Qdisc* sch)
 {
 	struct prio_sched_data *q = qdisc_priv(sch);
@@ -201,7 +187,8 @@
 	memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);
 
 	for (i=q->bands; i<TCQ_PRIO_BANDS; i++) {
-		struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc);
+		struct Qdisc *child = q->queues[i];
+		q->queues[i] = &noop_qdisc;
 		if (child != &noop_qdisc) {
 			qdisc_tree_decrease_qlen(child, child->q.qlen);
 			qdisc_destroy(child);
@@ -211,18 +198,19 @@
 
 	for (i=0; i<q->bands; i++) {
 		if (q->queues[i] == &noop_qdisc) {
-			struct Qdisc *child;
+			struct Qdisc *child, *old;
 			child = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
 						  &pfifo_qdisc_ops,
 						  TC_H_MAKE(sch->handle, i + 1));
 			if (child) {
 				sch_tree_lock(sch);
-				child = xchg(&q->queues[i], child);
+				old = q->queues[i];
+				q->queues[i] = child;
 
-				if (child != &noop_qdisc) {
-					qdisc_tree_decrease_qlen(child,
-								 child->q.qlen);
-					qdisc_destroy(child);
+				if (old != &noop_qdisc) {
+					qdisc_tree_decrease_qlen(old,
+								 old->q.qlen);
+					qdisc_destroy(old);
 				}
 				sch_tree_unlock(sch);
 			}
@@ -421,7 +409,7 @@
 	.priv_size	=	sizeof(struct prio_sched_data),
 	.enqueue	=	prio_enqueue,
 	.dequeue	=	prio_dequeue,
-	.requeue	=	prio_requeue,
+	.peek		=	prio_peek,
 	.drop		=	prio_drop,
 	.init		=	prio_init,
 	.reset		=	prio_reset,
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 5da0583..2bdf241 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -108,23 +108,6 @@
 	return NET_XMIT_CN;
 }
 
-static int red_requeue(struct sk_buff *skb, struct Qdisc* sch)
-{
-	struct red_sched_data *q = qdisc_priv(sch);
-	struct Qdisc *child = q->qdisc;
-	int ret;
-
-	if (red_is_idling(&q->parms))
-		red_end_of_idle_period(&q->parms);
-
-	ret = child->ops->requeue(skb, child);
-	if (likely(ret == NET_XMIT_SUCCESS)) {
-		sch->qstats.requeues++;
-		sch->q.qlen++;
-	}
-	return ret;
-}
-
 static struct sk_buff * red_dequeue(struct Qdisc* sch)
 {
 	struct sk_buff *skb;
@@ -140,6 +123,14 @@
 	return skb;
 }
 
+static struct sk_buff * red_peek(struct Qdisc* sch)
+{
+	struct red_sched_data *q = qdisc_priv(sch);
+	struct Qdisc *child = q->qdisc;
+
+	return child->ops->peek(child);
+}
+
 static unsigned int red_drop(struct Qdisc* sch)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
@@ -211,7 +202,8 @@
 	q->limit = ctl->limit;
 	if (child) {
 		qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
-		qdisc_destroy(xchg(&q->qdisc, child));
+		qdisc_destroy(q->qdisc);
+		q->qdisc = child;
 	}
 
 	red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog,
@@ -292,7 +284,8 @@
 		new = &noop_qdisc;
 
 	sch_tree_lock(sch);
-	*old = xchg(&q->qdisc, new);
+	*old = q->qdisc;
+	q->qdisc = new;
 	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
 	qdisc_reset(*old);
 	sch_tree_unlock(sch);
@@ -361,7 +354,7 @@
 	.cl_ops		=	&red_class_ops,
 	.enqueue	=	red_enqueue,
 	.dequeue	=	red_dequeue,
-	.requeue	=	red_requeue,
+	.peek		=	red_peek,
 	.drop		=	red_drop,
 	.init		=	red_init,
 	.reset		=	red_reset,
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index fe1508e..f3965df 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -281,7 +281,7 @@
 	struct sfq_sched_data *q = qdisc_priv(sch);
 	unsigned int hash;
 	sfq_index x;
-	int ret;
+	int uninitialized_var(ret);
 
 	hash = sfq_classify(skb, sch, &ret);
 	if (hash == 0) {
@@ -329,71 +329,20 @@
 	return NET_XMIT_CN;
 }
 
-static int
-sfq_requeue(struct sk_buff *skb, struct Qdisc *sch)
+static struct sk_buff *
+sfq_peek(struct Qdisc *sch)
 {
 	struct sfq_sched_data *q = qdisc_priv(sch);
-	unsigned int hash;
-	sfq_index x;
-	int ret;
+	sfq_index a;
 
-	hash = sfq_classify(skb, sch, &ret);
-	if (hash == 0) {
-		if (ret & __NET_XMIT_BYPASS)
-			sch->qstats.drops++;
-		kfree_skb(skb);
-		return ret;
-	}
-	hash--;
+	/* No active slots */
+	if (q->tail == SFQ_DEPTH)
+		return NULL;
 
-	x = q->ht[hash];
-	if (x == SFQ_DEPTH) {
-		q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
-		q->hash[x] = hash;
-	}
-
-	sch->qstats.backlog += qdisc_pkt_len(skb);
-	__skb_queue_head(&q->qs[x], skb);
-	/* If selected queue has length q->limit+1, this means that
-	 * all another queues are empty and we do simple tail drop.
-	 * This packet is still requeued at head of queue, tail packet
-	 * is dropped.
-	 */
-	if (q->qs[x].qlen > q->limit) {
-		skb = q->qs[x].prev;
-		__skb_unlink(skb, &q->qs[x]);
-		sch->qstats.drops++;
-		sch->qstats.backlog -= qdisc_pkt_len(skb);
-		kfree_skb(skb);
-		return NET_XMIT_CN;
-	}
-
-	sfq_inc(q, x);
-	if (q->qs[x].qlen == 1) {		/* The flow is new */
-		if (q->tail == SFQ_DEPTH) {	/* It is the first flow */
-			q->tail = x;
-			q->next[x] = x;
-			q->allot[x] = q->quantum;
-		} else {
-			q->next[x] = q->next[q->tail];
-			q->next[q->tail] = x;
-			q->tail = x;
-		}
-	}
-
-	if (++sch->q.qlen <= q->limit) {
-		sch->qstats.requeues++;
-		return 0;
-	}
-
-	sch->qstats.drops++;
-	sfq_drop(sch);
-	return NET_XMIT_CN;
+	a = q->next[q->tail];
+	return skb_peek(&q->qs[a]);
 }
 
-
-
-
 static struct sk_buff *
 sfq_dequeue(struct Qdisc *sch)
 {
@@ -624,7 +573,7 @@
 	.priv_size	=	sizeof(struct sfq_sched_data),
 	.enqueue	=	sfq_enqueue,
 	.dequeue	=	sfq_dequeue,
-	.requeue	=	sfq_requeue,
+	.peek		=	sfq_peek,
 	.drop		=	sfq_drop,
 	.init		=	sfq_init,
 	.reset		=	sfq_reset,
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 94c6159..a2f93c0 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -139,19 +139,6 @@
 	return 0;
 }
 
-static int tbf_requeue(struct sk_buff *skb, struct Qdisc* sch)
-{
-	struct tbf_sched_data *q = qdisc_priv(sch);
-	int ret;
-
-	if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) {
-		sch->q.qlen++;
-		sch->qstats.requeues++;
-	}
-
-	return ret;
-}
-
 static unsigned int tbf_drop(struct Qdisc* sch)
 {
 	struct tbf_sched_data *q = qdisc_priv(sch);
@@ -169,7 +156,7 @@
 	struct tbf_sched_data *q = qdisc_priv(sch);
 	struct sk_buff *skb;
 
-	skb = q->qdisc->dequeue(q->qdisc);
+	skb = q->qdisc->ops->peek(q->qdisc);
 
 	if (skb) {
 		psched_time_t now;
@@ -192,6 +179,10 @@
 		toks -= L2T(q, len);
 
 		if ((toks|ptoks) >= 0) {
+			skb = qdisc_dequeue_peeked(q->qdisc);
+			if (unlikely(!skb))
+				return NULL;
+
 			q->t_c = now;
 			q->tokens = toks;
 			q->ptokens = ptoks;
@@ -214,12 +205,6 @@
 		   (cf. CSZ, HPFQ, HFSC)
 		 */
 
-		if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
-			/* When requeue fails skb is dropped */
-			qdisc_tree_decrease_qlen(q->qdisc, 1);
-			sch->qstats.drops++;
-		}
-
 		sch->qstats.overlimits++;
 	}
 	return NULL;
@@ -251,6 +236,7 @@
 	struct tc_tbf_qopt *qopt;
 	struct qdisc_rate_table *rtab = NULL;
 	struct qdisc_rate_table *ptab = NULL;
+	struct qdisc_rate_table *tmp;
 	struct Qdisc *child = NULL;
 	int max_size,n;
 
@@ -299,7 +285,8 @@
 	sch_tree_lock(sch);
 	if (child) {
 		qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
-		qdisc_destroy(xchg(&q->qdisc, child));
+		qdisc_destroy(q->qdisc);
+		q->qdisc = child;
 	}
 	q->limit = qopt->limit;
 	q->mtu = qopt->mtu;
@@ -307,8 +294,14 @@
 	q->buffer = qopt->buffer;
 	q->tokens = q->buffer;
 	q->ptokens = q->mtu;
-	rtab = xchg(&q->R_tab, rtab);
-	ptab = xchg(&q->P_tab, ptab);
+
+	tmp = q->R_tab;
+	q->R_tab = rtab;
+	rtab = tmp;
+
+	tmp = q->P_tab;
+	q->P_tab = ptab;
+	ptab = tmp;
 	sch_tree_unlock(sch);
 	err = 0;
 done:
@@ -398,7 +391,8 @@
 		new = &noop_qdisc;
 
 	sch_tree_lock(sch);
-	*old = xchg(&q->qdisc, new);
+	*old = q->qdisc;
+	q->qdisc = new;
 	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
 	qdisc_reset(*old);
 	sch_tree_unlock(sch);
@@ -469,7 +463,7 @@
 	.priv_size	=	sizeof(struct tbf_sched_data),
 	.enqueue	=	tbf_enqueue,
 	.dequeue	=	tbf_dequeue,
-	.requeue	=	tbf_requeue,
+	.peek		=	qdisc_peek_dequeued,
 	.drop		=	tbf_drop,
 	.init		=	tbf_init,
 	.reset		=	tbf_reset,
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index d35ef05..cfc8e7c 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -93,16 +93,6 @@
 	return NET_XMIT_DROP;
 }
 
-static int
-teql_requeue(struct sk_buff *skb, struct Qdisc* sch)
-{
-	struct teql_sched_data *q = qdisc_priv(sch);
-
-	__skb_queue_head(&q->q, skb);
-	sch->qstats.requeues++;
-	return 0;
-}
-
 static struct sk_buff *
 teql_dequeue(struct Qdisc* sch)
 {
@@ -123,6 +113,13 @@
 	return skb;
 }
 
+static struct sk_buff *
+teql_peek(struct Qdisc* sch)
+{
+	/* teql is meant to be used as root qdisc */
+	return NULL;
+}
+
 static __inline__ void
 teql_neigh_release(struct neighbour *n)
 {
@@ -433,7 +430,7 @@
 
 	ops->enqueue	=	teql_enqueue;
 	ops->dequeue	=	teql_dequeue;
-	ops->requeue	=	teql_requeue;
+	ops->peek	=	teql_peek;
 	ops->init	=	teql_qdisc_init;
 	ops->reset	=	teql_reset;
 	ops->destroy	=	teql_destroy;
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 4124bbb..ceaa4aa 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -223,10 +223,9 @@
 		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
 	}
 
-	SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
-			  "src:" NIP6_FMT " dst:" NIP6_FMT "\n",
+	SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n",
 			  __func__, skb, skb->len,
-			  NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
+			  &fl.fl6_src, &fl.fl6_dst);
 
 	SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
 
@@ -252,23 +251,19 @@
 		fl.oif = daddr->v6.sin6_scope_id;
 
 
-	SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ",
-			  __func__, NIP6(fl.fl6_dst));
+	SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl.fl6_dst);
 
 	if (saddr) {
 		ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
-		SCTP_DEBUG_PRINTK(
-			"SRC=" NIP6_FMT " - ",
-			NIP6(fl.fl6_src));
+		SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl.fl6_src);
 	}
 
 	dst = ip6_route_output(&init_net, NULL, &fl);
 	if (!dst->error) {
 		struct rt6_info *rt;
 		rt = (struct rt6_info *)dst;
-		SCTP_DEBUG_PRINTK(
-			"rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
-			NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
+		SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n",
+			&rt->rt6i_dst.addr, &rt->rt6i_src.addr);
 		return dst;
 	}
 	SCTP_DEBUG_PRINTK("NO ROUTE\n");
@@ -314,9 +309,8 @@
 	__u8 matchlen = 0;
 	__u8 bmatchlen;
 
-	SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
-			  "daddr:" NIP6_FMT " ",
-			  __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
+	SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ",
+			  __func__, asoc, dst, &daddr->v6.sin6_addr);
 
 	if (!asoc) {
 		ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)),
@@ -324,8 +318,8 @@
 				   &daddr->v6.sin6_addr,
 				   inet6_sk(&sk->inet.sk)->srcprefs,
 				   &saddr->v6.sin6_addr);
-		SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
-				  NIP6(saddr->v6.sin6_addr));
+		SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n",
+				  &saddr->v6.sin6_addr);
 		return;
 	}
 
@@ -353,12 +347,11 @@
 
 	if (baddr) {
 		memcpy(saddr, baddr, sizeof(union sctp_addr));
-		SCTP_DEBUG_PRINTK("saddr: " NIP6_FMT "\n",
-				  NIP6(saddr->v6.sin6_addr));
+		SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
 	} else {
 		printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
-		       "address for the dest:" NIP6_FMT "\n",
-		       __func__, asoc, NIP6(daddr->v6.sin6_addr));
+		       "address for the dest:%pI6\n",
+		       __func__, asoc, &daddr->v6.sin6_addr);
 	}
 
 	rcu_read_unlock();
@@ -727,7 +720,7 @@
 /* Dump the v6 addr to the seq file. */
 static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
 {
-	seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr));
+	seq_printf(seq, "%pI6 ", &addr->v6.sin6_addr);
 }
 
 static void sctp_v6_ecn_capable(struct sock *sk)
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 0b65354..b78e3be 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -102,6 +102,8 @@
 /* Set up the proc fs entry for the SCTP protocol. */
 static __init int sctp_proc_init(void)
 {
+	if (percpu_counter_init(&sctp_sockets_allocated, 0))
+		goto out_nomem;
 #ifdef CONFIG_PROC_FS
 	if (!proc_net_sctp) {
 		struct proc_dir_entry *ent;
@@ -110,7 +112,7 @@
 			ent->owner = THIS_MODULE;
 			proc_net_sctp = ent;
 		} else
-			goto out_nomem;
+			goto out_free_percpu;
 	}
 
 	if (sctp_snmp_proc_init())
@@ -135,11 +137,14 @@
 		proc_net_sctp = NULL;
 		remove_proc_entry("sctp", init_net.proc_net);
 	}
-out_nomem:
-	return -ENOMEM;
+out_free_percpu:
+	percpu_counter_destroy(&sctp_sockets_allocated);
 #else
 	return 0;
 #endif /* CONFIG_PROC_FS */
+
+out_nomem:
+	return -ENOMEM;
 }
 
 /* Clean up the proc fs entry for the SCTP protocol.
@@ -482,9 +487,8 @@
 	if (saddr)
 		fl.fl4_src = saddr->v4.sin_addr.s_addr;
 
-	SCTP_DEBUG_PRINTK("%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - ",
-			  __func__, NIPQUAD(fl.fl4_dst),
-			  NIPQUAD(fl.fl4_src));
+	SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ",
+			  __func__, &fl.fl4_dst, &fl.fl4_src);
 
 	if (!ip_route_output_key(&init_net, &rt, &fl)) {
 		dst = &rt->u.dst;
@@ -540,8 +544,8 @@
 	rcu_read_unlock();
 out:
 	if (dst)
-		SCTP_DEBUG_PRINTK("rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u\n",
-				  NIPQUAD(rt->rt_dst), NIPQUAD(rt->rt_src));
+		SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n",
+				  &rt->rt_dst, &rt->rt_src);
 	else
 		SCTP_DEBUG_PRINTK("NO ROUTE\n");
 
@@ -646,7 +650,7 @@
 /* Dump the v4 addr to the seq file. */
 static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
 {
-	seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr));
+	seq_printf(seq, "%pI4 ", &addr->v4.sin_addr);
 }
 
 static void sctp_v4_ecn_capable(struct sock *sk)
@@ -866,11 +870,10 @@
 {
 	struct inet_sock *inet = inet_sk(skb->sk);
 
-	SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
-			  "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n",
+	SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n",
 			  __func__, skb, skb->len,
-			  NIPQUAD(skb->rtable->rt_src),
-			  NIPQUAD(skb->rtable->rt_dst));
+			  &skb->rtable->rt_src,
+			  &skb->rtable->rt_dst);
 
 	inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ?
 			 IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index a6a0ea7..1c4e5d6 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -1123,19 +1123,17 @@
 		if (from_addr.sa.sa_family == AF_INET6) {
 			if (net_ratelimit())
 				printk(KERN_WARNING
-				    "%s association %p could not find address "
-				    NIP6_FMT "\n",
+				    "%s association %p could not find address %pI6\n",
 				    __func__,
 				    asoc,
-				    NIP6(from_addr.v6.sin6_addr));
+				    &from_addr.v6.sin6_addr);
 		} else {
 			if (net_ratelimit())
 				printk(KERN_WARNING
-				    "%s association %p could not find address "
-				    NIPQUAD_FMT "\n",
+				    "%s association %p could not find address %pI4\n",
 				    __func__,
 				    asoc,
-				    NIPQUAD(from_addr.v4.sin_addr.s_addr));
+				    &from_addr.v4.sin_addr.s_addr);
 		}
 		return SCTP_DISPOSITION_DISCARD;
 	}
@@ -3691,6 +3689,7 @@
 {
 	struct sctp_chunk *chunk = arg;
 	struct sctp_fwdtsn_hdr *fwdtsn_hdr;
+	struct sctp_fwdtsn_skip *skip;
 	__u16 len;
 	__u32 tsn;
 
@@ -3720,6 +3719,12 @@
 	if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0)
 		goto discard_noforce;
 
+	/* Silently discard the chunk if stream-id is not valid */
+	sctp_walk_fwdtsn(skip, chunk) {
+		if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams)
+			goto discard_noforce;
+	}
+
 	sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn));
 	if (len > sizeof(struct sctp_fwdtsn_hdr))
 		sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN,
@@ -3751,6 +3756,7 @@
 {
 	struct sctp_chunk *chunk = arg;
 	struct sctp_fwdtsn_hdr *fwdtsn_hdr;
+	struct sctp_fwdtsn_skip *skip;
 	__u16 len;
 	__u32 tsn;
 
@@ -3780,6 +3786,12 @@
 	if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0)
 		goto gen_shutdown;
 
+	/* Silently discard the chunk if stream-id is not valid */
+	sctp_walk_fwdtsn(skip, chunk) {
+		if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams)
+			goto gen_shutdown;
+	}
+
 	sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn));
 	if (len > sizeof(struct sctp_fwdtsn_hdr))
 		sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN,
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a1b9045..b14a8f3 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -114,7 +114,7 @@
 
 static int sctp_memory_pressure;
 static atomic_t sctp_memory_allocated;
-static atomic_t sctp_sockets_allocated;
+struct percpu_counter sctp_sockets_allocated;
 
 static void sctp_enter_memory_pressure(struct sock *sk)
 {
@@ -2404,9 +2404,9 @@
 		if (params.sack_delay == 0 && params.sack_freq == 0)
 			return 0;
 	} else if (optlen == sizeof(struct sctp_assoc_value)) {
-		printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info "
+		printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
 		       "in delayed_ack socket option deprecated\n");
-		printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n");
+		printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
 		if (copy_from_user(&params, optval, optlen))
 			return -EFAULT;
 
@@ -2778,32 +2778,77 @@
 }
 
 /*
- * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
- *
- * This socket option specifies the maximum size to put in any outgoing
- * SCTP chunk.  If a message is larger than this size it will be
+ * 8.1.16.  Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG)
+ * This option will get or set the maximum size to put in any outgoing
+ * SCTP DATA chunk.  If a message is larger than this size it will be
  * fragmented by SCTP into the specified size.  Note that the underlying
  * SCTP implementation may fragment into smaller sized chunks when the
  * PMTU of the underlying association is smaller than the value set by
- * the user.
+ * the user.  The default value for this option is '0' which indicates
+ * the user is NOT limiting fragmentation and only the PMTU will effect
+ * SCTP's choice of DATA chunk size.  Note also that values set larger
+ * than the maximum size of an IP datagram will effectively let SCTP
+ * control fragmentation (i.e. the same as setting this option to 0).
+ *
+ * The following structure is used to access and modify this parameter:
+ *
+ * struct sctp_assoc_value {
+ *   sctp_assoc_t assoc_id;
+ *   uint32_t assoc_value;
+ * };
+ *
+ * assoc_id:  This parameter is ignored for one-to-one style sockets.
+ *    For one-to-many style sockets this parameter indicates which
+ *    association the user is performing an action upon.  Note that if
+ *    this field's value is zero then the endpoints default value is
+ *    changed (effecting future associations only).
+ * assoc_value:  This parameter specifies the maximum size in bytes.
  */
 static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen)
 {
+	struct sctp_assoc_value params;
 	struct sctp_association *asoc;
 	struct sctp_sock *sp = sctp_sk(sk);
 	int val;
 
-	if (optlen < sizeof(int))
+	if (optlen == sizeof(int)) {
+		printk(KERN_WARNING
+		   "SCTP: Use of int in maxseg socket option deprecated\n");
+		printk(KERN_WARNING
+		   "SCTP: Use struct sctp_assoc_value instead\n");
+		if (copy_from_user(&val, optval, optlen))
+			return -EFAULT;
+		params.assoc_id = 0;
+	} else if (optlen == sizeof(struct sctp_assoc_value)) {
+		if (copy_from_user(&params, optval, optlen))
+			return -EFAULT;
+		val = params.assoc_value;
+	} else
 		return -EINVAL;
-	if (get_user(val, (int __user *)optval))
-		return -EFAULT;
+
 	if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)))
 		return -EINVAL;
-	sp->user_frag = val;
 
-	/* Update the frag_point of the existing associations. */
-	list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
-		asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu);
+	asoc = sctp_id2assoc(sk, params.assoc_id);
+	if (!asoc && params.assoc_id && sctp_style(sk, UDP))
+		return -EINVAL;
+
+	if (asoc) {
+		if (val == 0) {
+			val = asoc->pathmtu;
+			val -= sp->pf->af->net_header_len;
+			val -= sizeof(struct sctphdr) +
+					sizeof(struct sctp_data_chunk);
+		}
+
+		asoc->frag_point = val;
+	} else {
+		sp->user_frag = val;
+
+		/* Update the frag_point of the existing associations. */
+		list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
+			asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu);
+		}
 	}
 
 	return 0;
@@ -2965,14 +3010,21 @@
 }
 
 /*
- * 7.1.25.  Set or Get the sctp partial delivery point
+ * 8.1.21.  Set or Get the SCTP Partial Delivery Point
  *       (SCTP_PARTIAL_DELIVERY_POINT)
+ *
  * This option will set or get the SCTP partial delivery point.  This
  * point is the size of a message where the partial delivery API will be
  * invoked to help free up rwnd space for the peer.  Setting this to a
- * lower value will cause partial delivery's to happen more often.  The
+ * lower value will cause partial deliveries to happen more often.  The
  * calls argument is an integer that sets or gets the partial delivery
- * point.
+ * point.  Note also that the call will fail if the user attempts to set
+ * this value larger than the socket receive buffer size.
+ *
+ * Note that any single message having a length smaller than or equal to
+ * the SCTP partial delivery point will be delivered in one single read
+ * call as long as the user provided buffer is large enough to hold the
+ * message.
  */
 static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
 						  char __user *optval,
@@ -2985,6 +3037,12 @@
 	if (get_user(val, (int __user *)optval))
 		return -EFAULT;
 
+	/* Note: We double the receive buffer from what the user sets
+	 * it to be, also initial rwnd is based on rcvbuf/2.
+	 */
+	if (val > (sk->sk_rcvbuf >> 1))
+		return -EINVAL;
+
 	sctp_sk(sk)->pd_point = val;
 
 	return 0; /* is this the right error code? */
@@ -3613,7 +3671,12 @@
 	sp->hmac = NULL;
 
 	SCTP_DBG_OBJCNT_INC(sock);
-	atomic_inc(&sctp_sockets_allocated);
+	percpu_counter_inc(&sctp_sockets_allocated);
+
+	local_bh_disable();
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+	local_bh_enable();
+
 	return 0;
 }
 
@@ -3627,7 +3690,10 @@
 	/* Release our hold on the endpoint. */
 	ep = sctp_sk(sk)->ep;
 	sctp_endpoint_free(ep);
-	atomic_dec(&sctp_sockets_allocated);
+	percpu_counter_dec(&sctp_sockets_allocated);
+	local_bh_disable();
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+	local_bh_enable();
 }
 
 /* API 4.1.7 shutdown() - TCP Style Syntax
@@ -4168,9 +4234,9 @@
 		if (copy_from_user(&params, optval, len))
 			return -EFAULT;
 	} else if (len == sizeof(struct sctp_assoc_value)) {
-		printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info "
+		printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
 		       "in delayed_ack socket option deprecated\n");
-		printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n");
+		printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
 		if (copy_from_user(&params, optval, len))
 			return -EFAULT;
 	} else
@@ -5092,30 +5158,69 @@
 }
 
 /*
- * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
- *
- * This socket option specifies the maximum size to put in any outgoing
- * SCTP chunk.  If a message is larger than this size it will be
+ * 8.1.16.  Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG)
+ * This option will get or set the maximum size to put in any outgoing
+ * SCTP DATA chunk.  If a message is larger than this size it will be
  * fragmented by SCTP into the specified size.  Note that the underlying
  * SCTP implementation may fragment into smaller sized chunks when the
  * PMTU of the underlying association is smaller than the value set by
- * the user.
+ * the user.  The default value for this option is '0' which indicates
+ * the user is NOT limiting fragmentation and only the PMTU will effect
+ * SCTP's choice of DATA chunk size.  Note also that values set larger
+ * than the maximum size of an IP datagram will effectively let SCTP
+ * control fragmentation (i.e. the same as setting this option to 0).
+ *
+ * The following structure is used to access and modify this parameter:
+ *
+ * struct sctp_assoc_value {
+ *   sctp_assoc_t assoc_id;
+ *   uint32_t assoc_value;
+ * };
+ *
+ * assoc_id:  This parameter is ignored for one-to-one style sockets.
+ *    For one-to-many style sockets this parameter indicates which
+ *    association the user is performing an action upon.  Note that if
+ *    this field's value is zero then the endpoints default value is
+ *    changed (effecting future associations only).
+ * assoc_value:  This parameter specifies the maximum size in bytes.
  */
 static int sctp_getsockopt_maxseg(struct sock *sk, int len,
 				  char __user *optval, int __user *optlen)
 {
-	int val;
+	struct sctp_assoc_value params;
+	struct sctp_association *asoc;
 
-	if (len < sizeof(int))
+	if (len == sizeof(int)) {
+		printk(KERN_WARNING
+		   "SCTP: Use of int in maxseg socket option deprecated\n");
+		printk(KERN_WARNING
+		   "SCTP: Use struct sctp_assoc_value instead\n");
+		params.assoc_id = 0;
+	} else if (len >= sizeof(struct sctp_assoc_value)) {
+		len = sizeof(struct sctp_assoc_value);
+		if (copy_from_user(&params, optval, sizeof(params)))
+			return -EFAULT;
+	} else
 		return -EINVAL;
 
-	len = sizeof(int);
+	asoc = sctp_id2assoc(sk, params.assoc_id);
+	if (!asoc && params.assoc_id && sctp_style(sk, UDP))
+		return -EINVAL;
 
-	val = sctp_sk(sk)->user_frag;
+	if (asoc)
+		params.assoc_value = asoc->frag_point;
+	else
+		params.assoc_value = sctp_sk(sk)->user_frag;
+
 	if (put_user(len, optlen))
 		return -EFAULT;
-	if (copy_to_user(optval, &val, len))
-		return -EFAULT;
+	if (len == sizeof(int)) {
+		if (copy_to_user(optval, &params.assoc_value, len))
+			return -EFAULT;
+	} else {
+		if (copy_to_user(optval, &params, len))
+			return -EFAULT;
+	}
 
 	return 0;
 }
@@ -5368,6 +5473,38 @@
 	return 0;
 }
 
+/*
+ * 8.2.5.  Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER)
+ * This option gets the current number of associations that are attached
+ * to a one-to-many style socket.  The option value is an uint32_t.
+ */
+static int sctp_getsockopt_assoc_number(struct sock *sk, int len,
+				    char __user *optval, int __user *optlen)
+{
+	struct sctp_sock *sp = sctp_sk(sk);
+	struct sctp_association *asoc;
+	u32 val = 0;
+
+	if (sctp_style(sk, TCP))
+		return -EOPNOTSUPP;
+
+	if (len < sizeof(u32))
+		return -EINVAL;
+
+	len = sizeof(u32);
+
+	list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
+		val++;
+	}
+
+	if (put_user(len, optlen))
+		return -EFAULT;
+	if (copy_to_user(optval, &val, len))
+		return -EFAULT;
+
+	return 0;
+}
+
 SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
 				char __user *optval, int __user *optlen)
 {
@@ -5510,6 +5647,9 @@
 		retval = sctp_getsockopt_local_auth_chunks(sk, len, optval,
 							optlen);
 		break;
+	case SCTP_GET_ASSOC_NUMBER:
+		retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen);
+		break;
 	default:
 		retval = -ENOPROTOOPT;
 		break;
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 5291069..f58e994 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -63,8 +63,8 @@
 		.data		= &sctp_rto_initial,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1         = &one,
 		.extra2         = &timer_max
 	},
@@ -74,8 +74,8 @@
 		.data		= &sctp_rto_min,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1         = &one,
 		.extra2         = &timer_max
 	},
@@ -85,8 +85,8 @@
 		.data		= &sctp_rto_max,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1         = &one,
 		.extra2         = &timer_max
 	},
@@ -96,8 +96,8 @@
 		.data		= &sctp_valid_cookie_life,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1         = &one,
 		.extra2         = &timer_max
 	},
@@ -107,8 +107,8 @@
 		.data		= &sctp_max_burst,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &zero,
 		.extra2		= &int_max
 	},
@@ -118,8 +118,8 @@
 		.data		= &sctp_max_retrans_association,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &one,
 		.extra2		= &int_max
 	},
@@ -129,8 +129,8 @@
 		.data		= &sctp_sndbuf_policy,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-		.strategy	= &sysctl_intvec
+		.proc_handler	= proc_dointvec,
+		.strategy	= sysctl_intvec
 	},
 	{
 		.ctl_name	= NET_SCTP_RCVBUF_POLICY,
@@ -138,8 +138,8 @@
 		.data		= &sctp_rcvbuf_policy,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-		.strategy	= &sysctl_intvec
+		.proc_handler	= proc_dointvec,
+		.strategy	= sysctl_intvec
 	},
 	{
 		.ctl_name	= NET_SCTP_PATH_MAX_RETRANS,
@@ -147,8 +147,8 @@
 		.data		= &sctp_max_retrans_path,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &one,
 		.extra2		= &int_max
 	},
@@ -158,8 +158,8 @@
 		.data		= &sctp_max_retrans_init,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1		= &one,
 		.extra2		= &int_max
 	},
@@ -169,8 +169,8 @@
 		.data		= &sctp_hb_interval,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1         = &one,
 		.extra2         = &timer_max
 	},
@@ -180,8 +180,8 @@
 		.data		= &sctp_cookie_preserve_enable,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-		.strategy	= &sysctl_intvec
+		.proc_handler	= proc_dointvec,
+		.strategy	= sysctl_intvec
 	},
 	{
 		.ctl_name	= NET_SCTP_RTO_ALPHA,
@@ -189,8 +189,8 @@
 		.data		= &sctp_rto_alpha,
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
-		.proc_handler	= &proc_dointvec,
-		.strategy	= &sysctl_intvec
+		.proc_handler	= proc_dointvec,
+		.strategy	= sysctl_intvec
 	},
 	{
 		.ctl_name	= NET_SCTP_RTO_BETA,
@@ -198,8 +198,8 @@
 		.data		= &sctp_rto_beta,
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
-		.proc_handler	= &proc_dointvec,
-		.strategy	= &sysctl_intvec
+		.proc_handler	= proc_dointvec,
+		.strategy	= sysctl_intvec
 	},
 	{
 		.ctl_name	= NET_SCTP_ADDIP_ENABLE,
@@ -207,8 +207,8 @@
 		.data		= &sctp_addip_enable,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-		.strategy	= &sysctl_intvec
+		.proc_handler	= proc_dointvec,
+		.strategy	= sysctl_intvec
 	},
 	{
 		.ctl_name	= NET_SCTP_PRSCTP_ENABLE,
@@ -216,8 +216,8 @@
 		.data		= &sctp_prsctp_enable,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-		.strategy	= &sysctl_intvec
+		.proc_handler	= proc_dointvec,
+		.strategy	= sysctl_intvec
 	},
 	{
 		.ctl_name	= NET_SCTP_SACK_TIMEOUT,
@@ -225,8 +225,8 @@
 		.data		= &sctp_sack_timeout,
 		.maxlen		= sizeof(long),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.strategy	= sysctl_intvec,
 		.extra1         = &sack_timer_min,
 		.extra2         = &sack_timer_max,
 	},
@@ -236,7 +236,7 @@
 		.data		= &sysctl_sctp_mem,
 		.maxlen		= sizeof(sysctl_sctp_mem),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= CTL_UNNUMBERED,
@@ -244,7 +244,7 @@
 		.data		= &sysctl_sctp_rmem,
 		.maxlen		= sizeof(sysctl_sctp_rmem),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= CTL_UNNUMBERED,
@@ -252,7 +252,7 @@
 		.data		= &sysctl_sctp_wmem,
 		.maxlen		= sizeof(sysctl_sctp_wmem),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
+		.proc_handler	= proc_dointvec,
 	},
 	{
 		.ctl_name	= CTL_UNNUMBERED,
@@ -260,8 +260,8 @@
 		.data		= &sctp_auth_enable,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-		.strategy	= &sysctl_intvec
+		.proc_handler	= proc_dointvec,
+		.strategy	= sysctl_intvec
 	},
 	{
 		.ctl_name	= CTL_UNNUMBERED,
@@ -269,8 +269,8 @@
 		.data		= &sctp_addip_noauth,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-		.strategy	= &sysctl_intvec
+		.proc_handler	= proc_dointvec,
+		.strategy	= sysctl_intvec
 	},
 	{ .ctl_name = 0 }
 };
diff --git a/net/socket.c b/net/socket.c
index 92764d8..2c730fc 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -69,7 +69,6 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/mutex.h>
-#include <linux/thread_info.h>
 #include <linux/wanrouter.h>
 #include <linux/if_bridge.h>
 #include <linux/if_frad.h>
@@ -491,8 +490,8 @@
 	sock = SOCKET_I(inode);
 
 	inode->i_mode = S_IFSOCK | S_IRWXUGO;
-	inode->i_uid = current->fsuid;
-	inode->i_gid = current->fsgid;
+	inode->i_uid = current_fsuid();
+	inode->i_gid = current_fsgid();
 
 	get_cpu_var(sockets_in_use)++;
 	put_cpu_var(sockets_in_use);
@@ -2307,6 +2306,7 @@
 	}
 
 	(*newsock)->ops = sock->ops;
+	__module_get((*newsock)->ops->owner);
 
 done:
 	return err;
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index cb216b2..0443f83 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -350,16 +350,18 @@
 struct rpc_cred *
 rpcauth_lookupcred(struct rpc_auth *auth, int flags)
 {
-	struct auth_cred acred = {
-		.uid = current->fsuid,
-		.gid = current->fsgid,
-		.group_info = current->group_info,
-	};
+	struct auth_cred acred;
 	struct rpc_cred *ret;
+	const struct cred *cred = current_cred();
 
 	dprintk("RPC:       looking up %s cred\n",
 		auth->au_ops->au_name);
-	get_group_info(acred.group_info);
+
+	memset(&acred, 0, sizeof(acred));
+	acred.uid = cred->fsuid;
+	acred.gid = cred->fsgid;
+	acred.group_info = get_group_info(((struct cred *)cred)->group_info);
+
 	ret = auth->au_ops->lookup_cred(auth, &acred, flags);
 	put_group_info(acred.group_info);
 	return ret;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 4895c34..3ca5183 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -271,15 +271,15 @@
 		case AF_INET: {
 			struct sockaddr_in *sin =
 					(struct sockaddr_in *)args->address;
-			snprintf(servername, sizeof(servername), NIPQUAD_FMT,
-				 NIPQUAD(sin->sin_addr.s_addr));
+			snprintf(servername, sizeof(servername), "%pI4",
+				 &sin->sin_addr.s_addr);
 			break;
 		}
 		case AF_INET6: {
 			struct sockaddr_in6 *sin =
 					(struct sockaddr_in6 *)args->address;
-			snprintf(servername, sizeof(servername), NIP6_FMT,
-				 NIP6(sin->sin6_addr));
+			snprintf(servername, sizeof(servername), "%pI6",
+				 &sin->sin6_addr);
 			break;
 		}
 		default:
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 41013dd..03ae007 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -270,10 +270,9 @@
 	char buf[32];
 
 	/* Construct AF_INET universal address */
-	snprintf(buf, sizeof(buf),
-			NIPQUAD_FMT".%u.%u",
-			NIPQUAD(address_to_register->sin_addr.s_addr),
-			port >> 8, port & 0xff);
+	snprintf(buf, sizeof(buf), "%pI4.%u.%u",
+		 &address_to_register->sin_addr.s_addr,
+		 port >> 8, port & 0xff);
 	map->r_addr = buf;
 
 	dprintk("RPC:       %sregistering [%u, %u, %s, '%s'] with "
@@ -305,9 +304,9 @@
 		snprintf(buf, sizeof(buf), "::.%u.%u",
 				port >> 8, port & 0xff);
 	else
-		snprintf(buf, sizeof(buf), NIP6_FMT".%u.%u",
-				NIP6(address_to_register->sin6_addr),
-				port >> 8, port & 0xff);
+		snprintf(buf, sizeof(buf), "%pI6.%u.%u",
+			 &address_to_register->sin6_addr,
+			 port >> 8, port & 0xff);
 	map->r_addr = buf;
 
 	dprintk("RPC:       %sregistering [%u, %u, %s, '%s'] with "
@@ -422,8 +421,8 @@
 	struct rpc_clnt	*rpcb_clnt;
 	int status;
 
-	dprintk("RPC:       %s(" NIPQUAD_FMT ", %u, %u, %d)\n",
-		__func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
+	dprintk("RPC:       %s(%pI4, %u, %u, %d)\n",
+		__func__, &sin->sin_addr.s_addr, prog, vers, prot);
 
 	rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
 				sizeof(*sin), prot, RPCBVERS_2);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index f24800f..82240e6 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -162,13 +162,9 @@
 	struct ip_map *im = container_of(h, struct ip_map, h);
 
 	if (ipv6_addr_v4mapped(&(im->m_addr))) {
-		snprintf(text_addr, 20, NIPQUAD_FMT,
-				ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
-				ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
-				ntohl(im->m_addr.s6_addr32[3]) >>  8 & 0xff,
-				ntohl(im->m_addr.s6_addr32[3]) >>  0 & 0xff);
+		snprintf(text_addr, 20, "%pI4", &im->m_addr.s6_addr32[3]);
 	} else {
-		snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
+		snprintf(text_addr, 40, "%pI6", &im->m_addr);
 	}
 	qword_add(bpp, blen, im->m_class);
 	qword_add(bpp, blen, text_addr);
@@ -208,13 +204,13 @@
 	len = qword_get(&mesg, buf, mlen);
 	if (len <= 0) return -EINVAL;
 
-	if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
+	if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) == 4) {
 		addr.s6_addr32[0] = 0;
 		addr.s6_addr32[1] = 0;
 		addr.s6_addr32[2] = htonl(0xffff);
 		addr.s6_addr32[3] =
 			htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
-       } else if (sscanf(buf, NIP6_FMT "%c",
+       } else if (sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x%c",
 			&b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
 		addr.s6_addr16[0] = htons(b1);
 		addr.s6_addr16[1] = htons(b2);
@@ -278,16 +274,10 @@
 		dom = im->m_client->h.name;
 
 	if (ipv6_addr_v4mapped(&addr)) {
-		seq_printf(m, "%s " NIPQUAD_FMT " %s\n",
-			im->m_class,
-			ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
-			ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
-			ntohl(addr.s6_addr32[3]) >>  8 & 0xff,
-			ntohl(addr.s6_addr32[3]) >>  0 & 0xff,
-			dom);
+		seq_printf(m, "%s %pI4 %s\n",
+			im->m_class, &addr.s6_addr32[3], dom);
 	} else {
-		seq_printf(m, "%s " NIP6_FMT " %s\n",
-			im->m_class, NIP6(addr), dom);
+		seq_printf(m, "%s %pI6 %s\n", im->m_class, &addr, dom);
 	}
 	return 0;
 }
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index a1951dc..ef3238d 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -250,10 +250,10 @@
 
 	switch(svsk->sk_sk->sk_family) {
 	case AF_INET:
-		len = sprintf(buf, "ipv4 %s %u.%u.%u.%u %d\n",
-			      svsk->sk_sk->sk_protocol==IPPROTO_UDP?
+		len = sprintf(buf, "ipv4 %s %pI4 %d\n",
+			      svsk->sk_sk->sk_protocol == IPPROTO_UDP ?
 			      "udp" : "tcp",
-			      NIPQUAD(inet_sk(svsk->sk_sk)->rcv_saddr),
+			      &inet_sk(svsk->sk_sk)->rcv_saddr,
 			      inet_sk(svsk->sk_sk)->num);
 		break;
 	default:
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
index a475657..629a287 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
@@ -646,8 +646,7 @@
 	ret = rdma_read_xdr(rdma_xprt, rmsgp, rqstp, ctxt);
 	if (ret > 0) {
 		/* read-list posted, defer until data received from client. */
-		svc_xprt_received(xprt);
-		return 0;
+		goto defer;
 	}
 	if (ret < 0) {
 		/* Post of read-list failed, free context. */
@@ -679,6 +678,7 @@
 	 * close bit and call svc_xprt_delete
 	 */
 	set_bit(XPT_CLOSE, &xprt->xpt_flags);
+defer:
 	svc_xprt_received(xprt);
 	return 0;
 }
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index 9a7a8e7..a3334e3 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -69,7 +69,7 @@
  * array is only concerned with the reply we are assured that we have
  * on extra page for the RPCRMDA header.
  */
-int fast_reg_xdr(struct svcxprt_rdma *xprt,
+static int fast_reg_xdr(struct svcxprt_rdma *xprt,
 		 struct xdr_buf *xdr,
 		 struct svc_rdma_req_map *vec)
 {
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 6fb493c..3d810e7 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -61,7 +61,7 @@
 static void rq_cq_reap(struct svcxprt_rdma *xprt);
 static void sq_cq_reap(struct svcxprt_rdma *xprt);
 
-DECLARE_TASKLET(dto_tasklet, dto_tasklet_func, 0UL);
+static DECLARE_TASKLET(dto_tasklet, dto_tasklet_func, 0UL);
 static DEFINE_SPINLOCK(dto_lock);
 static LIST_HEAD(dto_xprt_q);
 
@@ -827,7 +827,7 @@
 	struct rdma_conn_param conn_param;
 	struct ib_qp_init_attr qp_attr;
 	struct ib_device_attr devattr;
-	int dma_mr_acc;
+	int uninitialized_var(dma_mr_acc);
 	int need_dma_mr;
 	int ret;
 	int i;
@@ -1048,21 +1048,21 @@
 
 	dprintk("svcrdma: new connection %p accepted with the following "
 		"attributes:\n"
-		"    local_ip        : %d.%d.%d.%d\n"
+		"    local_ip        : %pI4\n"
 		"    local_port	     : %d\n"
-		"    remote_ip       : %d.%d.%d.%d\n"
+		"    remote_ip       : %pI4\n"
 		"    remote_port     : %d\n"
 		"    max_sge         : %d\n"
 		"    sq_depth        : %d\n"
 		"    max_requests    : %d\n"
 		"    ord             : %d\n",
 		newxprt,
-		NIPQUAD(((struct sockaddr_in *)&newxprt->sc_cm_id->
-			 route.addr.src_addr)->sin_addr.s_addr),
+		&((struct sockaddr_in *)&newxprt->sc_cm_id->
+			 route.addr.src_addr)->sin_addr.s_addr,
 		ntohs(((struct sockaddr_in *)&newxprt->sc_cm_id->
 		       route.addr.src_addr)->sin_port),
-		NIPQUAD(((struct sockaddr_in *)&newxprt->sc_cm_id->
-			 route.addr.dst_addr)->sin_addr.s_addr),
+		&((struct sockaddr_in *)&newxprt->sc_cm_id->
+			 route.addr.dst_addr)->sin_addr.s_addr,
 		ntohs(((struct sockaddr_in *)&newxprt->sc_cm_id->
 		       route.addr.dst_addr)->sin_port),
 		newxprt->sc_max_sge,
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index 9839c3d..1dd6123 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -174,7 +174,7 @@
 
 	buf = kzalloc(20, GFP_KERNEL);
 	if (buf)
-		snprintf(buf, 20, NIPQUAD_FMT, NIPQUAD(addr->sin_addr.s_addr));
+		snprintf(buf, 20, "%pI4", &addr->sin_addr.s_addr);
 	xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
 
 	buf = kzalloc(8, GFP_KERNEL);
@@ -186,8 +186,8 @@
 
 	buf = kzalloc(48, GFP_KERNEL);
 	if (buf)
-		snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s",
-			NIPQUAD(addr->sin_addr.s_addr),
+		snprintf(buf, 48, "addr=%pI4 port=%u proto=%s",
+			&addr->sin_addr.s_addr,
 			ntohs(addr->sin_port), "rdma");
 	xprt->address_strings[RPC_DISPLAY_ALL] = buf;
 
@@ -204,8 +204,8 @@
 
 	buf = kzalloc(30, GFP_KERNEL);
 	if (buf)
-		snprintf(buf, 30, NIPQUAD_FMT".%u.%u",
-			NIPQUAD(addr->sin_addr.s_addr),
+		snprintf(buf, 30, "%pI4.%u.%u",
+			&addr->sin_addr.s_addr,
 			ntohs(addr->sin_port) >> 8,
 			ntohs(addr->sin_port) & 0xff);
 	xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
@@ -369,8 +369,8 @@
 	if (ntohs(sin->sin_port) != 0)
 		xprt_set_bound(xprt);
 
-	dprintk("RPC:       %s: %u.%u.%u.%u:%u\n", __func__,
-			NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port));
+	dprintk("RPC:       %s: %pI4:%u\n",
+		__func__, &sin->sin_addr.s_addr, ntohs(sin->sin_port));
 
 	/* Set max requests */
 	cdata.max_requests = xprt->max_reqs;
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index a5fef5e..3b21e0c 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -276,7 +276,9 @@
 	struct rpcrdma_xprt *xprt = id->context;
 	struct rpcrdma_ia *ia = &xprt->rx_ia;
 	struct rpcrdma_ep *ep = &xprt->rx_ep;
+#ifdef RPC_DEBUG
 	struct sockaddr_in *addr = (struct sockaddr_in *) &ep->rep_remote_addr;
+#endif
 	struct ib_qp_attr attr;
 	struct ib_qp_init_attr iattr;
 	int connstate = 0;
@@ -323,12 +325,11 @@
 	case RDMA_CM_EVENT_DEVICE_REMOVAL:
 		connstate = -ENODEV;
 connected:
-		dprintk("RPC:       %s: %s: %u.%u.%u.%u:%u"
-			" (ep 0x%p event 0x%x)\n",
+		dprintk("RPC:       %s: %s: %pI4:%u (ep 0x%p event 0x%x)\n",
 			__func__,
 			(event->event <= 11) ? conn[event->event] :
 						"unknown connection error",
-			NIPQUAD(addr->sin_addr.s_addr),
+			&addr->sin_addr.s_addr,
 			ntohs(addr->sin_port),
 			ep, event->event);
 		atomic_set(&rpcx_to_rdmax(ep->rep_xprt)->rx_buf.rb_credits, 1);
@@ -348,18 +349,17 @@
 	if (connstate == 1) {
 		int ird = attr.max_dest_rd_atomic;
 		int tird = ep->rep_remote_cma.responder_resources;
-		printk(KERN_INFO "rpcrdma: connection to %u.%u.%u.%u:%u "
+		printk(KERN_INFO "rpcrdma: connection to %pI4:%u "
 			"on %s, memreg %d slots %d ird %d%s\n",
-			NIPQUAD(addr->sin_addr.s_addr),
+			&addr->sin_addr.s_addr,
 			ntohs(addr->sin_port),
 			ia->ri_id->device->name,
 			ia->ri_memreg_strategy,
 			xprt->rx_buf.rb_max_requests,
 			ird, ird < 4 && ird < tird / 2 ? " (low!)" : "");
 	} else if (connstate < 0) {
-		printk(KERN_INFO "rpcrdma: connection to %u.%u.%u.%u:%u "
-			"closed (%d)\n",
-			NIPQUAD(addr->sin_addr.s_addr),
+		printk(KERN_INFO "rpcrdma: connection to %pI4:%u closed (%d)\n",
+			&addr->sin_addr.s_addr,
 			ntohs(addr->sin_port),
 			connstate);
 	}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 0a50361..5cbb404 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -284,8 +284,7 @@
 
 	buf = kzalloc(20, GFP_KERNEL);
 	if (buf) {
-		snprintf(buf, 20, NIPQUAD_FMT,
-				NIPQUAD(addr->sin_addr.s_addr));
+		snprintf(buf, 20, "%pI4", &addr->sin_addr.s_addr);
 	}
 	xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
 
@@ -300,8 +299,8 @@
 
 	buf = kzalloc(48, GFP_KERNEL);
 	if (buf) {
-		snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s",
-			NIPQUAD(addr->sin_addr.s_addr),
+		snprintf(buf, 48, "addr=%pI4 port=%u proto=%s",
+			&addr->sin_addr.s_addr,
 			ntohs(addr->sin_port),
 			protocol);
 	}
@@ -323,8 +322,8 @@
 
 	buf = kzalloc(30, GFP_KERNEL);
 	if (buf) {
-		snprintf(buf, 30, NIPQUAD_FMT".%u.%u",
-				NIPQUAD(addr->sin_addr.s_addr),
+		snprintf(buf, 30, "%pI4.%u.%u",
+				&addr->sin_addr.s_addr,
 				ntohs(addr->sin_port) >> 8,
 				ntohs(addr->sin_port) & 0xff);
 	}
@@ -342,8 +341,7 @@
 
 	buf = kzalloc(40, GFP_KERNEL);
 	if (buf) {
-		snprintf(buf, 40, NIP6_FMT,
-				NIP6(addr->sin6_addr));
+		snprintf(buf, 40, "%pI6",&addr->sin6_addr);
 	}
 	xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
 
@@ -358,18 +356,17 @@
 
 	buf = kzalloc(64, GFP_KERNEL);
 	if (buf) {
-		snprintf(buf, 64, "addr="NIP6_FMT" port=%u proto=%s",
-				NIP6(addr->sin6_addr),
+		snprintf(buf, 64, "addr=%pI6 port=%u proto=%s",
+				&addr->sin6_addr,
 				ntohs(addr->sin6_port),
 				protocol);
 	}
 	xprt->address_strings[RPC_DISPLAY_ALL] = buf;
 
 	buf = kzalloc(36, GFP_KERNEL);
-	if (buf) {
-		snprintf(buf, 36, NIP6_SEQFMT,
-				NIP6(addr->sin6_addr));
-	}
+	if (buf)
+		snprintf(buf, 36, "%pi6", &addr->sin6_addr);
+
 	xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
 
 	buf = kzalloc(8, GFP_KERNEL);
@@ -381,10 +378,10 @@
 
 	buf = kzalloc(50, GFP_KERNEL);
 	if (buf) {
-		snprintf(buf, 50, NIP6_FMT".%u.%u",
-				NIP6(addr->sin6_addr),
-				ntohs(addr->sin6_port) >> 8,
-				ntohs(addr->sin6_port) & 0xff);
+		snprintf(buf, 50, "%pI6.%u.%u",
+			 &addr->sin6_addr,
+			 ntohs(addr->sin6_port) >> 8,
+			 ntohs(addr->sin6_port) & 0xff);
 	}
 	xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
 
@@ -1415,8 +1412,8 @@
 		if (port > last)
 			nloop++;
 	} while (err == -EADDRINUSE && nloop != 2);
-	dprintk("RPC:       %s "NIPQUAD_FMT":%u: %s (%d)\n",
-			__func__, NIPQUAD(myaddr.sin_addr),
+	dprintk("RPC:       %s %pI4:%u: %s (%d)\n",
+			__func__, &myaddr.sin_addr,
 			port, err ? "failed" : "ok", err);
 	return err;
 }
@@ -1448,8 +1445,8 @@
 		if (port > last)
 			nloop++;
 	} while (err == -EADDRINUSE && nloop != 2);
-	dprintk("RPC:       xs_bind6 "NIP6_FMT":%u: %s (%d)\n",
-		NIP6(myaddr.sin6_addr), port, err ? "failed" : "ok", err);
+	dprintk("RPC:       xs_bind6 %pI6:%u: %s (%d)\n",
+		&myaddr.sin6_addr, port, err ? "failed" : "ok", err);
 	return err;
 }
 
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index fe43ef7..f72ba77 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -243,12 +243,11 @@
 static char *eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size)
 {
 	unchar *addr = (unchar *)&a->dev_addr;
-	DECLARE_MAC_BUF(mac);
 
 	if (str_size < 18)
 		*str_buf = '\0';
 	else
-		sprintf(str_buf, "%s", print_mac(mac, addr));
+		sprintf(str_buf, "%pM", addr);
 	return str_buf;
 }
 
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index cd72e22..acab41a 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -555,7 +555,7 @@
 	struct name_seq *ns;
 
 	dbg("find_seq %u,(%u,0x%x) table = %p, hash[type] = %u\n",
-	    type, ntohl(type), type, table.types, hash(type));
+	    type, htonl(type), type, table.types, hash(type));
 
 	seq_head = &table.types[hash(type)];
 	hlist_for_each_entry(ns, seq_node, seq_head, ns_list) {
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 66d5ac4..c6250d0 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -164,7 +164,7 @@
 
 static inline int unix_may_send(struct sock *sk, struct sock *osk)
 {
-	return (unix_peer(osk) == NULL || unix_our_peer(sk, osk));
+	return unix_peer(osk) == NULL || unix_our_peer(sk, osk);
 }
 
 static inline int unix_recvq_full(struct sock const *sk)
@@ -197,7 +197,7 @@
  *		- if started by zero, it is abstract name.
  */
 
-static int unix_mkname(struct sockaddr_un * sunaddr, int len, unsigned *hashp)
+static int unix_mkname(struct sockaddr_un *sunaddr, int len, unsigned *hashp)
 {
 	if (len <= sizeof(short) || len > sizeof(*sunaddr))
 		return -EINVAL;
@@ -211,12 +211,12 @@
 		 * we are guaranteed that it is a valid memory location in our
 		 * kernel address buffer.
 		 */
-		((char *)sunaddr)[len]=0;
+		((char *)sunaddr)[len] = 0;
 		len = strlen(sunaddr->sun_path)+1+sizeof(short);
 		return len;
 	}
 
-	*hashp = unix_hash_fold(csum_partial((char*)sunaddr, len, 0));
+	*hashp = unix_hash_fold(csum_partial(sunaddr, len, 0));
 	return len;
 }
 
@@ -295,8 +295,7 @@
 		if (!net_eq(sock_net(s), net))
 			continue;
 
-		if(dentry && dentry->d_inode == i)
-		{
+		if (dentry && dentry->d_inode == i) {
 			sock_hold(s);
 			goto found;
 		}
@@ -354,7 +353,7 @@
 	WARN_ON(!sk_unhashed(sk));
 	WARN_ON(sk->sk_socket);
 	if (!sock_flag(sk, SOCK_DEAD)) {
-		printk("Attempt to release alive unix socket: %p\n", sk);
+		printk(KERN_INFO "Attempt to release alive unix socket: %p\n", sk);
 		return;
 	}
 
@@ -362,12 +361,16 @@
 		unix_release_addr(u->addr);
 
 	atomic_dec(&unix_nr_socks);
+	local_bh_disable();
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+	local_bh_enable();
 #ifdef UNIX_REFCNT_DEBUG
-	printk(KERN_DEBUG "UNIX %p is destroyed, %d are still alive.\n", sk, atomic_read(&unix_nr_socks));
+	printk(KERN_DEBUG "UNIX %p is destroyed, %d are still alive.\n", sk,
+		atomic_read(&unix_nr_socks));
 #endif
 }
 
-static int unix_release_sock (struct sock *sk, int embrion)
+static int unix_release_sock(struct sock *sk, int embrion)
 {
 	struct unix_sock *u = unix_sk(sk);
 	struct dentry *dentry;
@@ -392,9 +395,9 @@
 
 	wake_up_interruptible_all(&u->peer_wait);
 
-	skpair=unix_peer(sk);
+	skpair = unix_peer(sk);
 
-	if (skpair!=NULL) {
+	if (skpair != NULL) {
 		if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) {
 			unix_state_lock(skpair);
 			/* No more writes */
@@ -414,7 +417,7 @@
 	/* Try to flush out this socket. Throw out buffers at least */
 
 	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
-		if (state==TCP_LISTEN)
+		if (state == TCP_LISTEN)
 			unix_release_sock(skb->sk, 1);
 		/* passed fds are erased in the kfree_skb hook	      */
 		kfree_skb(skb);
@@ -453,11 +456,11 @@
 	struct unix_sock *u = unix_sk(sk);
 
 	err = -EOPNOTSUPP;
-	if (sock->type!=SOCK_STREAM && sock->type!=SOCK_SEQPACKET)
-		goto out;			/* Only stream/seqpacket sockets accept */
+	if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET)
+		goto out;	/* Only stream/seqpacket sockets accept */
 	err = -EINVAL;
 	if (!u->addr)
-		goto out;			/* No listens on an unbound socket */
+		goto out;	/* No listens on an unbound socket */
 	unix_state_lock(sk);
 	if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN)
 		goto out_unlock;
@@ -467,8 +470,7 @@
 	sk->sk_state		= TCP_LISTEN;
 	/* set credentials so connect can copy them */
 	sk->sk_peercred.pid	= task_tgid_vnr(current);
-	sk->sk_peercred.uid	= current->euid;
-	sk->sk_peercred.gid	= current->egid;
+	current_euid_egid(&sk->sk_peercred.uid, &sk->sk_peercred.gid);
 	err = 0;
 
 out_unlock:
@@ -566,9 +568,9 @@
 };
 
 static struct proto unix_proto = {
-	.name	  = "UNIX",
-	.owner	  = THIS_MODULE,
-	.obj_size = sizeof(struct unix_sock),
+	.name			= "UNIX",
+	.owner			= THIS_MODULE,
+	.obj_size		= sizeof(struct unix_sock),
 };
 
 /*
@@ -579,7 +581,7 @@
  */
 static struct lock_class_key af_unix_sk_receive_queue_lock_key;
 
-static struct sock * unix_create1(struct net *net, struct socket *sock)
+static struct sock *unix_create1(struct net *net, struct socket *sock)
 {
 	struct sock *sk = NULL;
 	struct unix_sock *u;
@@ -592,7 +594,7 @@
 	if (!sk)
 		goto out;
 
-	sock_init_data(sock,sk);
+	sock_init_data(sock, sk);
 	lockdep_set_class(&sk->sk_receive_queue.lock,
 				&af_unix_sk_receive_queue_lock_key);
 
@@ -611,6 +613,11 @@
 out:
 	if (sk == NULL)
 		atomic_dec(&unix_nr_socks);
+	else {
+		local_bh_disable();
+		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+		local_bh_enable();
+	}
 	return sk;
 }
 
@@ -630,7 +637,7 @@
 		 *	nothing uses it.
 		 */
 	case SOCK_RAW:
-		sock->type=SOCK_DGRAM;
+		sock->type = SOCK_DGRAM;
 	case SOCK_DGRAM:
 		sock->ops = &unix_dgram_ops;
 		break;
@@ -653,7 +660,7 @@
 
 	sock->sk = NULL;
 
-	return unix_release_sock (sk, 0);
+	return unix_release_sock(sk, 0);
 }
 
 static int unix_autobind(struct socket *sock)
@@ -662,7 +669,7 @@
 	struct net *net = sock_net(sk);
 	struct unix_sock *u = unix_sk(sk);
 	static u32 ordernum = 1;
-	struct unix_address * addr;
+	struct unix_address *addr;
 	int err;
 
 	mutex_lock(&u->readlock);
@@ -681,7 +688,7 @@
 
 retry:
 	addr->len = sprintf(addr->name->sun_path+1, "%05x", ordernum) + 1 + sizeof(short);
-	addr->hash = unix_hash_fold(csum_partial((void*)addr->name, addr->len, 0));
+	addr->hash = unix_hash_fold(csum_partial(addr->name, addr->len, 0));
 
 	spin_lock(&unix_table_lock);
 	ordernum = (ordernum+1)&0xFFFFF;
@@ -736,14 +743,14 @@
 
 		path_put(&path);
 
-		err=-EPROTOTYPE;
+		err = -EPROTOTYPE;
 		if (u->sk_type != type) {
 			sock_put(u);
 			goto fail;
 		}
 	} else {
 		err = -ECONNREFUSED;
-		u=unix_find_socket_byname(net, sunname, len, type, hash);
+		u = unix_find_socket_byname(net, sunname, len, type, hash);
 		if (u) {
 			struct dentry *dentry;
 			dentry = unix_sk(u)->dentry;
@@ -757,7 +764,7 @@
 put_fail:
 	path_put(&path);
 fail:
-	*error=err;
+	*error = err;
 	return NULL;
 }
 
@@ -767,8 +774,8 @@
 	struct sock *sk = sock->sk;
 	struct net *net = sock_net(sk);
 	struct unix_sock *u = unix_sk(sk);
-	struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
-	struct dentry * dentry = NULL;
+	struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
+	struct dentry *dentry = NULL;
 	struct nameidata nd;
 	int err;
 	unsigned hash;
@@ -779,7 +786,7 @@
 	if (sunaddr->sun_family != AF_UNIX)
 		goto out;
 
-	if (addr_len==sizeof(short)) {
+	if (addr_len == sizeof(short)) {
 		err = unix_autobind(sock);
 		goto out;
 	}
@@ -875,8 +882,8 @@
 	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
 	path_put(&nd.path);
 out_mknod_parent:
-	if (err==-EEXIST)
-		err=-EADDRINUSE;
+	if (err == -EEXIST)
+		err = -EADDRINUSE;
 	unix_release_addr(addr);
 	goto out_up;
 }
@@ -911,7 +918,7 @@
 {
 	struct sock *sk = sock->sk;
 	struct net *net = sock_net(sk);
-	struct sockaddr_un *sunaddr=(struct sockaddr_un*)addr;
+	struct sockaddr_un *sunaddr = (struct sockaddr_un *)addr;
 	struct sock *other;
 	unsigned hash;
 	int err;
@@ -927,7 +934,7 @@
 			goto out;
 
 restart:
-		other=unix_find_other(net, sunaddr, alen, sock->type, hash, &err);
+		other = unix_find_other(net, sunaddr, alen, sock->type, hash, &err);
 		if (!other)
 			goto out;
 
@@ -961,14 +968,14 @@
 	 */
 	if (unix_peer(sk)) {
 		struct sock *old_peer = unix_peer(sk);
-		unix_peer(sk)=other;
+		unix_peer(sk) = other;
 		unix_state_double_unlock(sk, other);
 
 		if (other != old_peer)
 			unix_dgram_disconnected(sk, old_peer);
 		sock_put(old_peer);
 	} else {
-		unix_peer(sk)=other;
+		unix_peer(sk) = other;
 		unix_state_double_unlock(sk, other);
 	}
 	return 0;
@@ -1004,7 +1011,7 @@
 static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 			       int addr_len, int flags)
 {
-	struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
+	struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
 	struct sock *sk = sock->sk;
 	struct net *net = sock_net(sk);
 	struct unix_sock *u = unix_sk(sk), *newu, *otheru;
@@ -1126,8 +1133,7 @@
 	newsk->sk_state		= TCP_ESTABLISHED;
 	newsk->sk_type		= sk->sk_type;
 	newsk->sk_peercred.pid	= task_tgid_vnr(current);
-	newsk->sk_peercred.uid	= current->euid;
-	newsk->sk_peercred.gid	= current->egid;
+	current_euid_egid(&newsk->sk_peercred.uid, &newsk->sk_peercred.gid);
 	newu = unix_sk(newsk);
 	newsk->sk_sleep		= &newu->peer_wait;
 	otheru = unix_sk(other);
@@ -1179,16 +1185,17 @@
 
 static int unix_socketpair(struct socket *socka, struct socket *sockb)
 {
-	struct sock *ska=socka->sk, *skb = sockb->sk;
+	struct sock *ska = socka->sk, *skb = sockb->sk;
 
 	/* Join our sockets back to back */
 	sock_hold(ska);
 	sock_hold(skb);
-	unix_peer(ska)=skb;
-	unix_peer(skb)=ska;
+	unix_peer(ska) = skb;
+	unix_peer(skb) = ska;
 	ska->sk_peercred.pid = skb->sk_peercred.pid = task_tgid_vnr(current);
-	ska->sk_peercred.uid = skb->sk_peercred.uid = current->euid;
-	ska->sk_peercred.gid = skb->sk_peercred.gid = current->egid;
+	current_euid_egid(&skb->sk_peercred.uid, &skb->sk_peercred.gid);
+	ska->sk_peercred.uid = skb->sk_peercred.uid;
+	ska->sk_peercred.gid = skb->sk_peercred.gid;
 
 	if (ska->sk_type != SOCK_DGRAM) {
 		ska->sk_state = TCP_ESTABLISHED;
@@ -1207,7 +1214,7 @@
 	int err;
 
 	err = -EOPNOTSUPP;
-	if (sock->type!=SOCK_STREAM && sock->type!=SOCK_SEQPACKET)
+	if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET)
 		goto out;
 
 	err = -EINVAL;
@@ -1246,7 +1253,7 @@
 {
 	struct sock *sk = sock->sk;
 	struct unix_sock *u;
-	struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
+	struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
 	int err = 0;
 
 	if (peer) {
@@ -1286,7 +1293,7 @@
 	skb->destructor = sock_wfree;
 	UNIXCB(skb).fp = NULL;
 
-	for (i=scm->fp->count-1; i>=0; i--)
+	for (i = scm->fp->count-1; i >= 0; i--)
 		unix_notinflight(scm->fp->fp[i]);
 }
 
@@ -1315,7 +1322,7 @@
 	if (!UNIXCB(skb).fp)
 		return -ENOMEM;
 
-	for (i=scm->fp->count-1; i>=0; i--)
+	for (i = scm->fp->count-1; i >= 0; i--)
 		unix_inflight(scm->fp->fp[i]);
 	skb->destructor = unix_destruct_fds;
 	return 0;
@@ -1332,7 +1339,7 @@
 	struct sock *sk = sock->sk;
 	struct net *net = sock_net(sk);
 	struct unix_sock *u = unix_sk(sk);
-	struct sockaddr_un *sunaddr=msg->msg_name;
+	struct sockaddr_un *sunaddr = msg->msg_name;
 	struct sock *other = NULL;
 	int namelen = 0; /* fake GCC */
 	int err;
@@ -1374,7 +1381,7 @@
 		goto out;
 
 	skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err);
-	if (skb==NULL)
+	if (skb == NULL)
 		goto out;
 
 	memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
@@ -1386,7 +1393,7 @@
 	unix_get_secdata(siocb->scm, skb);
 
 	skb_reset_transport_header(skb);
-	err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+	err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
 	if (err)
 		goto out_free;
 
@@ -1400,7 +1407,7 @@
 
 		other = unix_find_other(net, sunaddr, namelen, sk->sk_type,
 					hash, &err);
-		if (other==NULL)
+		if (other == NULL)
 			goto out_free;
 	}
 
@@ -1420,7 +1427,7 @@
 		err = 0;
 		unix_state_lock(sk);
 		if (unix_peer(sk) == other) {
-			unix_peer(sk)=NULL;
+			unix_peer(sk) = NULL;
 			unix_state_unlock(sk);
 
 			unix_dgram_disconnected(sk, other);
@@ -1486,10 +1493,10 @@
 	struct sock_iocb *siocb = kiocb_to_siocb(kiocb);
 	struct sock *sk = sock->sk;
 	struct sock *other = NULL;
-	struct sockaddr_un *sunaddr=msg->msg_name;
-	int err,size;
+	struct sockaddr_un *sunaddr = msg->msg_name;
+	int err, size;
 	struct sk_buff *skb;
-	int sent=0;
+	int sent = 0;
 	struct scm_cookie tmp_scm;
 
 	if (NULL == siocb->scm)
@@ -1517,8 +1524,7 @@
 	if (sk->sk_shutdown & SEND_SHUTDOWN)
 		goto pipe_err;
 
-	while(sent < len)
-	{
+	while (sent < len) {
 		/*
 		 *	Optimisation for the fact that under 0.01% of X
 		 *	messages typically need breaking up.
@@ -1537,9 +1543,10 @@
 		 *	Grab a buffer
 		 */
 
-		skb=sock_alloc_send_skb(sk,size,msg->msg_flags&MSG_DONTWAIT, &err);
+		skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT,
+					  &err);
 
-		if (skb==NULL)
+		if (skb == NULL)
 			goto out_err;
 
 		/*
@@ -1560,7 +1567,8 @@
 			}
 		}
 
-		if ((err = memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) != 0) {
+		err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
+		if (err) {
 			kfree_skb(skb);
 			goto out_err;
 		}
@@ -1574,7 +1582,7 @@
 		skb_queue_tail(&other->sk_receive_queue, skb);
 		unix_state_unlock(other);
 		other->sk_data_ready(other, size);
-		sent+=size;
+		sent += size;
 	}
 
 	scm_destroy(siocb->scm);
@@ -1586,8 +1594,8 @@
 	unix_state_unlock(other);
 	kfree_skb(skb);
 pipe_err:
-	if (sent==0 && !(msg->msg_flags&MSG_NOSIGNAL))
-		send_sig(SIGPIPE,current,0);
+	if (sent == 0 && !(msg->msg_flags&MSG_NOSIGNAL))
+		send_sig(SIGPIPE, current, 0);
 	err = -EPIPE;
 out_err:
 	scm_destroy(siocb->scm);
@@ -1677,13 +1685,10 @@
 	siocb->scm->creds = *UNIXCREDS(skb);
 	unix_set_secdata(siocb->scm, skb);
 
-	if (!(flags & MSG_PEEK))
-	{
+	if (!(flags & MSG_PEEK)) {
 		if (UNIXCB(skb).fp)
 			unix_detach_fds(siocb->scm, skb);
-	}
-	else
-	{
+	} else {
 		/* It is questionable: on PEEK we could:
 		   - do not return fds - good, but too simple 8)
 		   - return fds, and do not return them on read (old strategy,
@@ -1704,7 +1709,7 @@
 	scm_recv(sock, msg, siocb->scm, flags);
 
 out_free:
-	skb_free_datagram(sk,skb);
+	skb_free_datagram(sk, skb);
 out_unlock:
 	mutex_unlock(&u->readlock);
 out:
@@ -1715,7 +1720,7 @@
  *	Sleep until data has arrive. But check for races..
  */
 
-static long unix_stream_data_wait(struct sock * sk, long timeo)
+static long unix_stream_data_wait(struct sock *sk, long timeo)
 {
 	DEFINE_WAIT(wait);
 
@@ -1753,7 +1758,7 @@
 	struct scm_cookie tmp_scm;
 	struct sock *sk = sock->sk;
 	struct unix_sock *u = unix_sk(sk);
-	struct sockaddr_un *sunaddr=msg->msg_name;
+	struct sockaddr_un *sunaddr = msg->msg_name;
 	int copied = 0;
 	int check_creds = 0;
 	int target;
@@ -1784,15 +1789,13 @@
 
 	mutex_lock(&u->readlock);
 
-	do
-	{
+	do {
 		int chunk;
 		struct sk_buff *skb;
 
 		unix_state_lock(sk);
 		skb = skb_dequeue(&sk->sk_receive_queue);
-		if (skb==NULL)
-		{
+		if (skb == NULL) {
 			if (copied >= target)
 				goto unlock;
 
@@ -1800,7 +1803,8 @@
 			 *	POSIX 1003.1g mandates this order.
 			 */
 
-			if ((err = sock_error(sk)) != 0)
+			err = sock_error(sk);
+			if (err)
 				goto unlock;
 			if (sk->sk_shutdown & RCV_SHUTDOWN)
 				goto unlock;
@@ -1827,7 +1831,8 @@
 
 		if (check_creds) {
 			/* Never glue messages from different writers */
-			if (memcmp(UNIXCREDS(skb), &siocb->scm->creds, sizeof(siocb->scm->creds)) != 0) {
+			if (memcmp(UNIXCREDS(skb), &siocb->scm->creds,
+				   sizeof(siocb->scm->creds)) != 0) {
 				skb_queue_head(&sk->sk_receive_queue, skb);
 				break;
 			}
@@ -1838,8 +1843,7 @@
 		}
 
 		/* Copy address just once */
-		if (sunaddr)
-		{
+		if (sunaddr) {
 			unix_copy_addr(msg, skb->sk);
 			sunaddr = NULL;
 		}
@@ -1855,16 +1859,14 @@
 		size -= chunk;
 
 		/* Mark read part of skb as used */
-		if (!(flags & MSG_PEEK))
-		{
+		if (!(flags & MSG_PEEK)) {
 			skb_pull(skb, chunk);
 
 			if (UNIXCB(skb).fp)
 				unix_detach_fds(siocb->scm, skb);
 
 			/* put the skb back if we didn't use it up.. */
-			if (skb->len)
-			{
+			if (skb->len) {
 				skb_queue_head(&sk->sk_receive_queue, skb);
 				break;
 			}
@@ -1873,9 +1875,7 @@
 
 			if (siocb->scm->fp)
 				break;
-		}
-		else
-		{
+		} else {
 			/* It is questionable, see note in unix_dgram_recvmsg.
 			 */
 			if (UNIXCB(skb).fp)
@@ -1903,7 +1903,7 @@
 	if (mode) {
 		unix_state_lock(sk);
 		sk->sk_shutdown |= mode;
-		other=unix_peer(sk);
+		other = unix_peer(sk);
 		if (other)
 			sock_hold(other);
 		unix_state_unlock(sk);
@@ -1938,16 +1938,15 @@
 static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
-	long amount=0;
+	long amount = 0;
 	int err;
 
-	switch(cmd)
-	{
-		case SIOCOUTQ:
-			amount = atomic_read(&sk->sk_wmem_alloc);
-			err = put_user(amount, (int __user *)arg);
-			break;
-		case SIOCINQ:
+	switch (cmd) {
+	case SIOCOUTQ:
+		amount = atomic_read(&sk->sk_wmem_alloc);
+		err = put_user(amount, (int __user *)arg);
+		break;
+	case SIOCINQ:
 		{
 			struct sk_buff *skb;
 
@@ -1964,21 +1963,21 @@
 			} else {
 				skb = skb_peek(&sk->sk_receive_queue);
 				if (skb)
-					amount=skb->len;
+					amount = skb->len;
 			}
 			spin_unlock(&sk->sk_receive_queue.lock);
 			err = put_user(amount, (int __user *)arg);
 			break;
 		}
 
-		default:
-			err = -ENOIOCTLCMD;
-			break;
+	default:
+		err = -ENOIOCTLCMD;
+		break;
 	}
 	return err;
 }
 
-static unsigned int unix_poll(struct file * file, struct socket *sock, poll_table *wait)
+static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table *wait)
 {
 	struct sock *sk = sock->sk;
 	unsigned int mask;
@@ -2000,7 +1999,8 @@
 		mask |= POLLIN | POLLRDNORM;
 
 	/* Connection-based need to check for termination and startup */
-	if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) && sk->sk_state == TCP_CLOSE)
+	if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) &&
+	    sk->sk_state == TCP_CLOSE)
 		mask |= POLLHUP;
 
 	/*
@@ -2096,6 +2096,7 @@
 	struct seq_net_private p;
 	int i;
 };
+
 static struct sock *unix_seq_idx(struct seq_file *seq, loff_t pos)
 {
 	struct unix_iter_state *iter = seq->private;
@@ -2112,7 +2113,6 @@
 	return NULL;
 }
 
-
 static void *unix_seq_start(struct seq_file *seq, loff_t *pos)
 	__acquires(unix_table_lock)
 {
@@ -2192,7 +2192,6 @@
 	.show   = unix_seq_show,
 };
 
-
 static int unix_seq_open(struct inode *inode, struct file *file)
 {
 	return seq_open_net(inode, file, &unix_seq_ops,
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index abb3ab3..19c17e4 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -106,8 +106,8 @@
 	 *	Socket ?
 	 */
 	if (S_ISSOCK(inode->i_mode)) {
-		struct socket * sock = SOCKET_I(inode);
-		struct sock * s = sock->sk;
+		struct socket *sock = SOCKET_I(inode);
+		struct sock *s = sock->sk;
 
 		/*
 		 *	PF_UNIX ?
@@ -126,7 +126,7 @@
 void unix_inflight(struct file *fp)
 {
 	struct sock *s = unix_get_socket(fp);
-	if(s) {
+	if (s) {
 		struct unix_sock *u = unix_sk(s);
 		spin_lock(&unix_gc_lock);
 		if (atomic_long_inc_return(&u->inflight) == 1) {
@@ -143,7 +143,7 @@
 void unix_notinflight(struct file *fp)
 {
 	struct sock *s = unix_get_socket(fp);
-	if(s) {
+	if (s) {
 		struct unix_sock *u = unix_sk(s);
 		spin_lock(&unix_gc_lock);
 		BUG_ON(list_empty(&u->link));
@@ -156,7 +156,7 @@
 
 static inline struct sk_buff *sock_queue_head(struct sock *sk)
 {
-	return (struct sk_buff *) &sk->sk_receive_queue;
+	return (struct sk_buff *)&sk->sk_receive_queue;
 }
 
 #define receive_queue_for_each_skb(sk, next, skb) \
@@ -370,7 +370,7 @@
 	 */
 	skb_queue_head_init(&hitlist);
 	list_for_each_entry(u, &gc_candidates, link)
-		scan_children(&u->sk, inc_inflight, &hitlist);
+	scan_children(&u->sk, inc_inflight, &hitlist);
 
 	spin_unlock(&unix_gc_lock);
 
diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c
index 77513d7..83c0930 100644
--- a/net/unix/sysctl_net_unix.c
+++ b/net/unix/sysctl_net_unix.c
@@ -21,7 +21,7 @@
 		.data		= &init_net.unx.sysctl_max_dgram_qlen,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= proc_dointvec
 	},
 	{ .ctl_name = 0 }
 };
@@ -61,4 +61,3 @@
 	unregister_sysctl_table(net->unx.ctl);
 	kfree(table);
 }
-
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 7f07152..39701de 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -60,6 +60,8 @@
 
 #define KMEM_SAFETYZONE 8
 
+#define DEV_TO_SLAVE(dev)	(*((struct net_device **)netdev_priv(dev)))
+
 /*
  * 	Function Prototypes
  */
@@ -511,7 +513,7 @@
 		if (err)
 			return err;
 		/* The above function deallocates the current dev
-		 * structure. Therefore, we cannot use dev->priv
+		 * structure. Therefore, we cannot use netdev_priv(dev)
 		 * as the next element: wandev->dev points to the
 		 * next element */
 		dev = wandev->dev;
@@ -589,10 +591,6 @@
 		err = -EPROTONOSUPPORT;
 		goto out;
 	} else {
-		dev = kzalloc(sizeof(struct net_device), GFP_KERNEL);
-		err = -ENOBUFS;
-		if (dev == NULL)
-			goto out;
 		err = wandev->new_if(wandev, dev, cnf);
 	}
 
@@ -622,10 +620,9 @@
 					wandev->dev = dev;
 				} else {
 					for (slave=wandev->dev;
-					 *((struct net_device **)slave->priv);
-				 slave = *((struct net_device **)slave->priv));
-
-				     *((struct net_device **)slave->priv) = dev;
+					     DEV_TO_SLAVE(slave);
+					     slave = DEV_TO_SLAVE(slave))
+						DEV_TO_SLAVE(slave) = dev;
 				}
 				++wandev->ndev;
 
@@ -636,15 +633,9 @@
 		}
 		if (wandev->del_if)
 			wandev->del_if(wandev, dev);
+		free_netdev(dev);
 	}
 
-	/* This code has moved from del_if() function */
-	kfree(dev->priv);
-	dev->priv = NULL;
-
-	/* Sync PPP is disabled */
-	if (cnf->config_id != WANCONFIG_MPPP)
-		kfree(dev);
 out:
 	kfree(cnf);
 	return err;
@@ -734,7 +725,7 @@
 	dev = wandev->dev;
 	prev = NULL;
 	while (dev && strcmp(name, dev->name)) {
-		struct net_device **slave = dev->priv;
+		struct net_device **slave = netdev_priv(dev);
 		prev = dev;
 		dev = *slave;
 	}
@@ -751,12 +742,12 @@
 
 	lock_adapter_irq(&wandev->lock, &smp_flags);
 	if (prev) {
-		struct net_device **prev_slave = prev->priv;
-		struct net_device **slave = dev->priv;
+		struct net_device **prev_slave = netdev_priv(prev);
+		struct net_device **slave = netdev_priv(dev);
 
 		*prev_slave = *slave;
 	} else {
-		struct net_device **slave = dev->priv;
+		struct net_device **slave = netdev_priv(dev);
 		wandev->dev = *slave;
 	}
 	--wandev->ndev;
@@ -764,11 +755,6 @@
 
 	printk(KERN_INFO "%s: unregistering '%s'\n", wandev->name, dev->name);
 
-	/* Due to new interface linking method using dev->priv,
-	 * this code has moved from del_if() function.*/
-	kfree(dev->priv);
-	dev->priv=NULL;
-
 	unregister_netdev(dev);
 
 	free_netdev(dev);
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 646c712..e28e2b8 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -1,6 +1,15 @@
 config CFG80211
         tristate "Improved wireless configuration API"
 
+config CFG80211_REG_DEBUG
+	bool "cfg80211 regulatory debugging"
+	depends on CFG80211
+	default n
+	---help---
+	  You can enable this if you want to debug regulatory changes.
+
+	  If unsure, say N.
+
 config NL80211
 	bool "nl80211 new netlink interface support"
 	depends on CFG80211
@@ -40,6 +49,8 @@
 	  ieee80211_regdom module parameter. This is being phased out and you
 	  should stop using them ASAP.
 
+	  Note: You will need CRDA if you want 802.11d support
+
 	  Say Y unless you have installed a new userspace application.
 	  Also say Y if have one currently depending on the ieee80211_regdom
 	  module parameter and cannot port it to use the new userspace
@@ -72,3 +83,22 @@
 
 	  Say Y if you have programs using it, like old versions of
 	  hal.
+
+config LIB80211
+	tristate "Common routines for IEEE802.11 drivers"
+	default n
+	help
+	  This options enables a library of common routines used
+	  by IEEE802.11 wireless LAN drivers.
+
+	  Drivers should select this themselves if needed.  Say Y if
+	  you want this built into your kernel.
+
+config LIB80211_CRYPT_WEP
+	tristate
+
+config LIB80211_CRYPT_CCMP
+	tristate
+
+config LIB80211_CRYPT_TKIP
+	tristate
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index b9f943c..938a334 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -1,5 +1,12 @@
 obj-$(CONFIG_WIRELESS_EXT) += wext.o
 obj-$(CONFIG_CFG80211) += cfg80211.o
+obj-$(CONFIG_LIB80211) += lib80211.o
+obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
+obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
+obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
 
 cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o
+cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
 cfg80211-$(CONFIG_NL80211) += nl80211.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 5031db7..b96fc0c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -19,7 +19,6 @@
 #include "nl80211.h"
 #include "core.h"
 #include "sysfs.h"
-#include "reg.h"
 
 /* name for sysfs, %d is appended */
 #define PHY_NAME "phy"
@@ -236,8 +235,7 @@
 	mutex_unlock(&cfg80211_drv_mutex);
 
 	/* give it a proper name */
-	snprintf(drv->wiphy.dev.bus_id, BUS_ID_SIZE,
-		 PHY_NAME "%d", drv->idx);
+	dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->idx);
 
 	mutex_init(&drv->mtx);
 	mutex_init(&drv->devlist_mtx);
@@ -301,13 +299,11 @@
 	/* check and set up bitrates */
 	ieee80211_set_bitrate_flags(wiphy);
 
-	/* set up regulatory info */
-	mutex_lock(&cfg80211_reg_mutex);
-	wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE);
-	mutex_unlock(&cfg80211_reg_mutex);
-
 	mutex_lock(&cfg80211_drv_mutex);
 
+	/* set up regulatory info */
+	wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE);
+
 	res = device_add(&drv->wiphy.dev);
 	if (res)
 		goto out_unlock;
@@ -351,6 +347,10 @@
 	/* unlock again before freeing */
 	mutex_unlock(&drv->mtx);
 
+	/* If this device got a regulatory hint tell core its
+	 * free to listen now to a new shiny device regulatory hint */
+	reg_device_remove(wiphy);
+
 	list_del(&drv->list);
 	device_del(&drv->wiphy.dev);
 	debugfs_remove(drv->wiphy.debugfsdir);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 771cc5c..f7fb9f4 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -11,6 +11,7 @@
 #include <net/genetlink.h>
 #include <net/wireless.h>
 #include <net/cfg80211.h>
+#include "reg.h"
 
 struct cfg80211_registered_device {
 	struct cfg80211_ops *ops;
@@ -21,6 +22,18 @@
 	 * any call is in progress */
 	struct mutex mtx;
 
+	/* ISO / IEC 3166 alpha2 for which this device is receiving
+	 * country IEs on, this can help disregard country IEs from APs
+	 * on the same alpha2 quickly. The alpha2 may differ from
+	 * cfg80211_regdomain's alpha2 when an intersection has occurred.
+	 * If the AP is reconfigured this can also be used to tell us if
+	 * the country on the country IE changed. */
+	char country_ie_alpha2[2];
+
+	/* If a Country IE has been received this tells us the environment
+	 * which its telling us its in. This defaults to ENVIRON_ANY */
+	enum environment_cap env;
+
 	/* wiphy index, internal only */
 	int idx;
 
diff --git a/net/wireless/lib80211.c b/net/wireless/lib80211.c
new file mode 100644
index 0000000..97d411f
--- /dev/null
+++ b/net/wireless/lib80211.c
@@ -0,0 +1,284 @@
+/*
+ * lib80211 -- common bits for IEEE802.11 drivers
+ *
+ * Copyright(c) 2008 John W. Linville <linville@tuxdriver.com>
+ *
+ * Portions copied from old ieee80211 component, w/ original copyright
+ * notices below:
+ *
+ * Host AP crypto routines
+ *
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
+ * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/ieee80211.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <net/lib80211.h>
+
+#define DRV_NAME        "lib80211"
+
+#define DRV_DESCRIPTION	"common routines for IEEE802.11 drivers"
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
+MODULE_LICENSE("GPL");
+
+struct lib80211_crypto_alg {
+	struct list_head list;
+	struct lib80211_crypto_ops *ops;
+};
+
+static LIST_HEAD(lib80211_crypto_algs);
+static DEFINE_SPINLOCK(lib80211_crypto_lock);
+
+const char *print_ssid(char *buf, const char *ssid, u8 ssid_len)
+{
+	const char *s = ssid;
+	char *d = buf;
+
+	ssid_len = min_t(u8, ssid_len, IEEE80211_MAX_SSID_LEN);
+	while (ssid_len--) {
+		if (isprint(*s)) {
+			*d++ = *s++;
+			continue;
+		}
+
+		*d++ = '\\';
+		if (*s == '\0')
+			*d++ = '0';
+		else if (*s == '\n')
+			*d++ = 'n';
+		else if (*s == '\r')
+			*d++ = 'r';
+		else if (*s == '\t')
+			*d++ = 't';
+		else if (*s == '\\')
+			*d++ = '\\';
+		else
+			d += snprintf(d, 3, "%03o", *s);
+		s++;
+	}
+	*d = '\0';
+	return buf;
+}
+EXPORT_SYMBOL(print_ssid);
+
+int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name,
+				spinlock_t *lock)
+{
+	memset(info, 0, sizeof(*info));
+
+	info->name = name;
+	info->lock = lock;
+
+	INIT_LIST_HEAD(&info->crypt_deinit_list);
+	setup_timer(&info->crypt_deinit_timer, lib80211_crypt_deinit_handler,
+			(unsigned long)info);
+
+	return 0;
+}
+EXPORT_SYMBOL(lib80211_crypt_info_init);
+
+void lib80211_crypt_info_free(struct lib80211_crypt_info *info)
+{
+	int i;
+
+        lib80211_crypt_quiescing(info);
+        del_timer_sync(&info->crypt_deinit_timer);
+        lib80211_crypt_deinit_entries(info, 1);
+
+        for (i = 0; i < NUM_WEP_KEYS; i++) {
+                struct lib80211_crypt_data *crypt = info->crypt[i];
+                if (crypt) {
+                        if (crypt->ops) {
+                                crypt->ops->deinit(crypt->priv);
+                                module_put(crypt->ops->owner);
+                        }
+                        kfree(crypt);
+                        info->crypt[i] = NULL;
+                }
+        }
+}
+EXPORT_SYMBOL(lib80211_crypt_info_free);
+
+void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info, int force)
+{
+	struct lib80211_crypt_data *entry, *next;
+	unsigned long flags;
+
+	spin_lock_irqsave(info->lock, flags);
+	list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) {
+		if (atomic_read(&entry->refcnt) != 0 && !force)
+			continue;
+
+		list_del(&entry->list);
+
+		if (entry->ops) {
+			entry->ops->deinit(entry->priv);
+			module_put(entry->ops->owner);
+		}
+		kfree(entry);
+	}
+	spin_unlock_irqrestore(info->lock, flags);
+}
+EXPORT_SYMBOL(lib80211_crypt_deinit_entries);
+
+/* After this, crypt_deinit_list won't accept new members */
+void lib80211_crypt_quiescing(struct lib80211_crypt_info *info)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(info->lock, flags);
+	info->crypt_quiesced = 1;
+	spin_unlock_irqrestore(info->lock, flags);
+}
+EXPORT_SYMBOL(lib80211_crypt_quiescing);
+
+void lib80211_crypt_deinit_handler(unsigned long data)
+{
+	struct lib80211_crypt_info *info = (struct lib80211_crypt_info *)data;
+	unsigned long flags;
+
+	lib80211_crypt_deinit_entries(info, 0);
+
+	spin_lock_irqsave(info->lock, flags);
+	if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) {
+		printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
+		       "deletion list\n", info->name);
+		info->crypt_deinit_timer.expires = jiffies + HZ;
+		add_timer(&info->crypt_deinit_timer);
+	}
+	spin_unlock_irqrestore(info->lock, flags);
+}
+EXPORT_SYMBOL(lib80211_crypt_deinit_handler);
+
+void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
+				    struct lib80211_crypt_data **crypt)
+{
+	struct lib80211_crypt_data *tmp;
+	unsigned long flags;
+
+	if (*crypt == NULL)
+		return;
+
+	tmp = *crypt;
+	*crypt = NULL;
+
+	/* must not run ops->deinit() while there may be pending encrypt or
+	 * decrypt operations. Use a list of delayed deinits to avoid needing
+	 * locking. */
+
+	spin_lock_irqsave(info->lock, flags);
+	if (!info->crypt_quiesced) {
+		list_add(&tmp->list, &info->crypt_deinit_list);
+		if (!timer_pending(&info->crypt_deinit_timer)) {
+			info->crypt_deinit_timer.expires = jiffies + HZ;
+			add_timer(&info->crypt_deinit_timer);
+		}
+	}
+	spin_unlock_irqrestore(info->lock, flags);
+}
+EXPORT_SYMBOL(lib80211_crypt_delayed_deinit);
+
+int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops)
+{
+	unsigned long flags;
+	struct lib80211_crypto_alg *alg;
+
+	alg = kzalloc(sizeof(*alg), GFP_KERNEL);
+	if (alg == NULL)
+		return -ENOMEM;
+
+	alg->ops = ops;
+
+	spin_lock_irqsave(&lib80211_crypto_lock, flags);
+	list_add(&alg->list, &lib80211_crypto_algs);
+	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
+
+	printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n",
+	       ops->name);
+
+	return 0;
+}
+EXPORT_SYMBOL(lib80211_register_crypto_ops);
+
+int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops)
+{
+	struct lib80211_crypto_alg *alg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lib80211_crypto_lock, flags);
+	list_for_each_entry(alg, &lib80211_crypto_algs, list) {
+		if (alg->ops == ops)
+			goto found;
+	}
+	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
+	return -EINVAL;
+
+      found:
+	printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm "
+	       "'%s'\n", ops->name);
+	list_del(&alg->list);
+	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
+	kfree(alg);
+	return 0;
+}
+EXPORT_SYMBOL(lib80211_unregister_crypto_ops);
+
+struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name)
+{
+	struct lib80211_crypto_alg *alg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lib80211_crypto_lock, flags);
+	list_for_each_entry(alg, &lib80211_crypto_algs, list) {
+		if (strcmp(alg->ops->name, name) == 0)
+			goto found;
+	}
+	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
+	return NULL;
+
+      found:
+	spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
+	return alg->ops;
+}
+EXPORT_SYMBOL(lib80211_get_crypto_ops);
+
+static void *lib80211_crypt_null_init(int keyidx)
+{
+	return (void *)1;
+}
+
+static void lib80211_crypt_null_deinit(void *priv)
+{
+}
+
+static struct lib80211_crypto_ops lib80211_crypt_null = {
+	.name = "NULL",
+	.init = lib80211_crypt_null_init,
+	.deinit = lib80211_crypt_null_deinit,
+	.owner = THIS_MODULE,
+};
+
+static int __init lib80211_init(void)
+{
+	printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION "\n");
+	return lib80211_register_crypto_ops(&lib80211_crypt_null);
+}
+
+static void __exit lib80211_exit(void)
+{
+	lib80211_unregister_crypto_ops(&lib80211_crypt_null);
+	BUG_ON(!list_empty(&lib80211_crypto_algs));
+}
+
+module_init(lib80211_init);
+module_exit(lib80211_exit);
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/wireless/lib80211_crypt_ccmp.c
similarity index 74%
rename from net/ieee80211/ieee80211_crypt_ccmp.c
rename to net/wireless/lib80211_crypt_ccmp.c
index 208bf35..db42819 100644
--- a/net/ieee80211/ieee80211_crypt_ccmp.c
+++ b/net/wireless/lib80211_crypt_ccmp.c
@@ -1,7 +1,8 @@
 /*
- * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
+ * lib80211 crypt: host-based CCMP encryption implementation for lib80211
  *
  * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008, John W. Linville <linville@tuxdriver.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
@@ -22,10 +23,12 @@
 #include <asm/string.h>
 #include <linux/wireless.h>
 
-#include <net/ieee80211.h>
+#include <linux/ieee80211.h>
 
 #include <linux/crypto.h>
 
+#include <net/lib80211.h>
+
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("Host AP crypt: CCMP");
 MODULE_LICENSE("GPL");
@@ -36,7 +39,7 @@
 #define CCMP_TK_LEN 16
 #define CCMP_PN_LEN 6
 
-struct ieee80211_ccmp_data {
+struct lib80211_ccmp_data {
 	u8 key[CCMP_TK_LEN];
 	int key_set;
 
@@ -57,15 +60,15 @@
 	u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
 };
 
-static inline void ieee80211_ccmp_aes_encrypt(struct crypto_cipher *tfm,
+static inline void lib80211_ccmp_aes_encrypt(struct crypto_cipher *tfm,
 					      const u8 pt[16], u8 ct[16])
 {
 	crypto_cipher_encrypt_one(tfm, ct, pt);
 }
 
-static void *ieee80211_ccmp_init(int key_idx)
+static void *lib80211_ccmp_init(int key_idx)
 {
-	struct ieee80211_ccmp_data *priv;
+	struct lib80211_ccmp_data *priv;
 
 	priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
 	if (priv == NULL)
@@ -74,7 +77,7 @@
 
 	priv->tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(priv->tfm)) {
-		printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate "
+		printk(KERN_DEBUG "lib80211_crypt_ccmp: could not allocate "
 		       "crypto API aes\n");
 		priv->tfm = NULL;
 		goto fail;
@@ -92,9 +95,9 @@
 	return NULL;
 }
 
-static void ieee80211_ccmp_deinit(void *priv)
+static void lib80211_ccmp_deinit(void *priv)
 {
-	struct ieee80211_ccmp_data *_priv = priv;
+	struct lib80211_ccmp_data *_priv = priv;
 	if (_priv && _priv->tfm)
 		crypto_free_cipher(_priv->tfm);
 	kfree(priv);
@@ -108,20 +111,17 @@
 }
 
 static void ccmp_init_blocks(struct crypto_cipher *tfm,
-			     struct ieee80211_hdr_4addr *hdr,
+			     struct ieee80211_hdr *hdr,
 			     u8 * pn, size_t dlen, u8 * b0, u8 * auth, u8 * s0)
 {
 	u8 *pos, qc = 0;
 	size_t aad_len;
-	u16 fc;
 	int a4_included, qc_included;
 	u8 aad[2 * AES_BLOCK_LEN];
 
-	fc = le16_to_cpu(hdr->frame_ctl);
-	a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
-		       (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS));
-	qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) &&
-		       (WLAN_FC_GET_STYPE(fc) & IEEE80211_STYPE_QOS_DATA));
+	a4_included = ieee80211_has_a4(hdr->frame_control);
+	qc_included = ieee80211_is_data_qos(hdr->frame_control);
+
 	aad_len = 22;
 	if (a4_included)
 		aad_len += 6;
@@ -158,7 +158,7 @@
 	aad[2] = pos[0] & 0x8f;
 	aad[3] = pos[1] & 0xc7;
 	memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN);
-	pos = (u8 *) & hdr->seq_ctl;
+	pos = (u8 *) & hdr->seq_ctrl;
 	aad[22] = pos[0] & 0x0f;
 	aad[23] = 0;		/* all bits masked */
 	memset(aad + 24, 0, 8);
@@ -170,20 +170,20 @@
 	}
 
 	/* Start with the first block and AAD */
-	ieee80211_ccmp_aes_encrypt(tfm, b0, auth);
+	lib80211_ccmp_aes_encrypt(tfm, b0, auth);
 	xor_block(auth, aad, AES_BLOCK_LEN);
-	ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
+	lib80211_ccmp_aes_encrypt(tfm, auth, auth);
 	xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
-	ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
+	lib80211_ccmp_aes_encrypt(tfm, auth, auth);
 	b0[0] &= 0x07;
 	b0[14] = b0[15] = 0;
-	ieee80211_ccmp_aes_encrypt(tfm, b0, s0);
+	lib80211_ccmp_aes_encrypt(tfm, b0, s0);
 }
 
-static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len,
+static int lib80211_ccmp_hdr(struct sk_buff *skb, int hdr_len,
 			      u8 *aeskey, int keylen, void *priv)
 {
-	struct ieee80211_ccmp_data *key = priv;
+	struct lib80211_ccmp_data *key = priv;
 	int i;
 	u8 *pos;
 
@@ -217,12 +217,12 @@
 	return CCMP_HDR_LEN;
 }
 
-static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
 {
-	struct ieee80211_ccmp_data *key = priv;
+	struct lib80211_ccmp_data *key = priv;
 	int data_len, i, blocks, last, len;
 	u8 *pos, *mic;
-	struct ieee80211_hdr_4addr *hdr;
+	struct ieee80211_hdr *hdr;
 	u8 *b0 = key->tx_b0;
 	u8 *b = key->tx_b;
 	u8 *e = key->tx_e;
@@ -232,13 +232,13 @@
 		return -1;
 
 	data_len = skb->len - hdr_len;
-	len = ieee80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv);
+	len = lib80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv);
 	if (len < 0)
 		return -1;
 
 	pos = skb->data + hdr_len + CCMP_HDR_LEN;
 	mic = skb_put(skb, CCMP_MIC_LEN);
-	hdr = (struct ieee80211_hdr_4addr *)skb->data;
+	hdr = (struct ieee80211_hdr *)skb->data;
 	ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
 
 	blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
@@ -248,11 +248,11 @@
 		len = (i == blocks && last) ? last : AES_BLOCK_LEN;
 		/* Authentication */
 		xor_block(b, pos, len);
-		ieee80211_ccmp_aes_encrypt(key->tfm, b, b);
+		lib80211_ccmp_aes_encrypt(key->tfm, b, b);
 		/* Encryption, with counter */
 		b0[14] = (i >> 8) & 0xff;
 		b0[15] = i & 0xff;
-		ieee80211_ccmp_aes_encrypt(key->tfm, b0, e);
+		lib80211_ccmp_aes_encrypt(key->tfm, b0, e);
 		xor_block(pos, e, len);
 		pos += len;
 	}
@@ -284,11 +284,11 @@
 	return 0;
 }
 
-static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int lib80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 {
-	struct ieee80211_ccmp_data *key = priv;
+	struct lib80211_ccmp_data *key = priv;
 	u8 keyidx, *pos;
-	struct ieee80211_hdr_4addr *hdr;
+	struct ieee80211_hdr *hdr;
 	u8 *b0 = key->rx_b0;
 	u8 *b = key->rx_b;
 	u8 *a = key->rx_a;
@@ -296,20 +296,19 @@
 	int i, blocks, last, len;
 	size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN;
 	u8 *mic = skb->data + skb->len - CCMP_MIC_LEN;
-	DECLARE_MAC_BUF(mac);
 
 	if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
 		key->dot11RSNAStatsCCMPFormatErrors++;
 		return -1;
 	}
 
-	hdr = (struct ieee80211_hdr_4addr *)skb->data;
+	hdr = (struct ieee80211_hdr *)skb->data;
 	pos = skb->data + hdr_len;
 	keyidx = pos[3];
 	if (!(keyidx & (1 << 5))) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "CCMP: received packet without ExtIV"
-			       " flag from %s\n", print_mac(mac, hdr->addr2));
+			       " flag from %pM\n", hdr->addr2);
 		}
 		key->dot11RSNAStatsCCMPFormatErrors++;
 		return -2;
@@ -322,9 +321,9 @@
 	}
 	if (!key->key_set) {
 		if (net_ratelimit()) {
-			printk(KERN_DEBUG "CCMP: received packet from %s"
+			printk(KERN_DEBUG "CCMP: received packet from %pM"
 			       " with keyid=%d that does not have a configured"
-			       " key\n", print_mac(mac, hdr->addr2), keyidx);
+			       " key\n", hdr->addr2, keyidx);
 		}
 		return -3;
 	}
@@ -338,11 +337,11 @@
 	pos += 8;
 
 	if (ccmp_replay_check(pn, key->rx_pn)) {
-		if (ieee80211_ratelimit_debug(IEEE80211_DL_DROP)) {
-			IEEE80211_DEBUG_DROP("CCMP: replay detected: STA=%s "
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "CCMP: replay detected: STA=%pM "
 				 "previous PN %02x%02x%02x%02x%02x%02x "
 				 "received PN %02x%02x%02x%02x%02x%02x\n",
-				 print_mac(mac, hdr->addr2),
+				 hdr->addr2,
 				 key->rx_pn[0], key->rx_pn[1], key->rx_pn[2],
 				 key->rx_pn[3], key->rx_pn[4], key->rx_pn[5],
 				 pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]);
@@ -362,18 +361,18 @@
 		/* Decrypt, with counter */
 		b0[14] = (i >> 8) & 0xff;
 		b0[15] = i & 0xff;
-		ieee80211_ccmp_aes_encrypt(key->tfm, b0, b);
+		lib80211_ccmp_aes_encrypt(key->tfm, b0, b);
 		xor_block(pos, b, len);
 		/* Authentication */
 		xor_block(a, pos, len);
-		ieee80211_ccmp_aes_encrypt(key->tfm, a, a);
+		lib80211_ccmp_aes_encrypt(key->tfm, a, a);
 		pos += len;
 	}
 
 	if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "CCMP: decrypt failed: STA="
-			       "%s\n", print_mac(mac, hdr->addr2));
+			       "%pM\n", hdr->addr2);
 		}
 		key->dot11RSNAStatsCCMPDecryptErrors++;
 		return -5;
@@ -389,9 +388,9 @@
 	return keyidx;
 }
 
-static int ieee80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv)
+static int lib80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv)
 {
-	struct ieee80211_ccmp_data *data = priv;
+	struct lib80211_ccmp_data *data = priv;
 	int keyidx;
 	struct crypto_cipher *tfm = data->tfm;
 
@@ -419,9 +418,9 @@
 	return 0;
 }
 
-static int ieee80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
+static int lib80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
 {
-	struct ieee80211_ccmp_data *data = priv;
+	struct lib80211_ccmp_data *data = priv;
 
 	if (len < CCMP_TK_LEN)
 		return -1;
@@ -442,9 +441,9 @@
 	return CCMP_TK_LEN;
 }
 
-static char *ieee80211_ccmp_print_stats(char *p, void *priv)
+static char *lib80211_ccmp_print_stats(char *p, void *priv)
 {
-	struct ieee80211_ccmp_data *ccmp = priv;
+	struct lib80211_ccmp_data *ccmp = priv;
 
 	p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
 		     "tx_pn=%02x%02x%02x%02x%02x%02x "
@@ -462,32 +461,32 @@
 	return p;
 }
 
-static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = {
+static struct lib80211_crypto_ops lib80211_crypt_ccmp = {
 	.name = "CCMP",
-	.init = ieee80211_ccmp_init,
-	.deinit = ieee80211_ccmp_deinit,
-	.build_iv = ieee80211_ccmp_hdr,
-	.encrypt_mpdu = ieee80211_ccmp_encrypt,
-	.decrypt_mpdu = ieee80211_ccmp_decrypt,
+	.init = lib80211_ccmp_init,
+	.deinit = lib80211_ccmp_deinit,
+	.build_iv = lib80211_ccmp_hdr,
+	.encrypt_mpdu = lib80211_ccmp_encrypt,
+	.decrypt_mpdu = lib80211_ccmp_decrypt,
 	.encrypt_msdu = NULL,
 	.decrypt_msdu = NULL,
-	.set_key = ieee80211_ccmp_set_key,
-	.get_key = ieee80211_ccmp_get_key,
-	.print_stats = ieee80211_ccmp_print_stats,
+	.set_key = lib80211_ccmp_set_key,
+	.get_key = lib80211_ccmp_get_key,
+	.print_stats = lib80211_ccmp_print_stats,
 	.extra_mpdu_prefix_len = CCMP_HDR_LEN,
 	.extra_mpdu_postfix_len = CCMP_MIC_LEN,
 	.owner = THIS_MODULE,
 };
 
-static int __init ieee80211_crypto_ccmp_init(void)
+static int __init lib80211_crypto_ccmp_init(void)
 {
-	return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp);
+	return lib80211_register_crypto_ops(&lib80211_crypt_ccmp);
 }
 
-static void __exit ieee80211_crypto_ccmp_exit(void)
+static void __exit lib80211_crypto_ccmp_exit(void)
 {
-	ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp);
+	lib80211_unregister_crypto_ops(&lib80211_crypt_ccmp);
 }
 
-module_init(ieee80211_crypto_ccmp_init);
-module_exit(ieee80211_crypto_ccmp_exit);
+module_init(lib80211_crypto_ccmp_init);
+module_exit(lib80211_crypto_ccmp_exit);
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c
similarity index 79%
rename from net/ieee80211/ieee80211_crypt_tkip.c
rename to net/wireless/lib80211_crypt_tkip.c
index bba0152..7e8e22b 100644
--- a/net/ieee80211/ieee80211_crypt_tkip.c
+++ b/net/wireless/lib80211_crypt_tkip.c
@@ -1,7 +1,8 @@
 /*
- * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
+ * lib80211 crypt: host-based TKIP encryption implementation for lib80211
  *
  * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008, John W. Linville <linville@tuxdriver.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
@@ -22,16 +23,20 @@
 #include <linux/if_arp.h>
 #include <asm/string.h>
 
-#include <net/ieee80211.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <net/iw_handler.h>
 
 #include <linux/crypto.h>
 #include <linux/crc32.h>
 
+#include <net/lib80211.h>
+
 MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Host AP crypt: TKIP");
+MODULE_DESCRIPTION("lib80211 crypt: TKIP");
 MODULE_LICENSE("GPL");
 
-struct ieee80211_tkip_data {
+struct lib80211_tkip_data {
 #define TKIP_KEY_LEN 32
 	u8 key[TKIP_KEY_LEN];
 	int key_set;
@@ -65,23 +70,23 @@
 	unsigned long flags;
 };
 
-static unsigned long ieee80211_tkip_set_flags(unsigned long flags, void *priv)
+static unsigned long lib80211_tkip_set_flags(unsigned long flags, void *priv)
 {
-	struct ieee80211_tkip_data *_priv = priv;
+	struct lib80211_tkip_data *_priv = priv;
 	unsigned long old_flags = _priv->flags;
 	_priv->flags = flags;
 	return old_flags;
 }
 
-static unsigned long ieee80211_tkip_get_flags(void *priv)
+static unsigned long lib80211_tkip_get_flags(void *priv)
 {
-	struct ieee80211_tkip_data *_priv = priv;
+	struct lib80211_tkip_data *_priv = priv;
 	return _priv->flags;
 }
 
-static void *ieee80211_tkip_init(int key_idx)
+static void *lib80211_tkip_init(int key_idx)
 {
-	struct ieee80211_tkip_data *priv;
+	struct lib80211_tkip_data *priv;
 
 	priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
 	if (priv == NULL)
@@ -92,7 +97,7 @@
 	priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
 						CRYPTO_ALG_ASYNC);
 	if (IS_ERR(priv->tx_tfm_arc4)) {
-		printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+		printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate "
 		       "crypto API arc4\n");
 		priv->tx_tfm_arc4 = NULL;
 		goto fail;
@@ -101,7 +106,7 @@
 	priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
 						 CRYPTO_ALG_ASYNC);
 	if (IS_ERR(priv->tx_tfm_michael)) {
-		printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+		printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate "
 		       "crypto API michael_mic\n");
 		priv->tx_tfm_michael = NULL;
 		goto fail;
@@ -110,7 +115,7 @@
 	priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
 						CRYPTO_ALG_ASYNC);
 	if (IS_ERR(priv->rx_tfm_arc4)) {
-		printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+		printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate "
 		       "crypto API arc4\n");
 		priv->rx_tfm_arc4 = NULL;
 		goto fail;
@@ -119,7 +124,7 @@
 	priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
 						 CRYPTO_ALG_ASYNC);
 	if (IS_ERR(priv->rx_tfm_michael)) {
-		printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
+		printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate "
 		       "crypto API michael_mic\n");
 		priv->rx_tfm_michael = NULL;
 		goto fail;
@@ -143,9 +148,9 @@
 	return NULL;
 }
 
-static void ieee80211_tkip_deinit(void *priv)
+static void lib80211_tkip_deinit(void *priv)
 {
-	struct ieee80211_tkip_data *_priv = priv;
+	struct lib80211_tkip_data *_priv = priv;
 	if (_priv) {
 		if (_priv->tx_tfm_michael)
 			crypto_free_hash(_priv->tx_tfm_michael);
@@ -305,15 +310,15 @@
 #endif
 }
 
-static int ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
+static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
 			      u8 * rc4key, int keylen, void *priv)
 {
-	struct ieee80211_tkip_data *tkey = priv;
+	struct lib80211_tkip_data *tkey = priv;
 	int len;
 	u8 *pos;
-	struct ieee80211_hdr_4addr *hdr;
+	struct ieee80211_hdr *hdr;
 
-	hdr = (struct ieee80211_hdr_4addr *)skb->data;
+	hdr = (struct ieee80211_hdr *)skb->data;
 
 	if (skb_headroom(skb) < 8 || skb->len < hdr_len)
 		return -1;
@@ -351,23 +356,21 @@
 	return 8;
 }
 
-static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
 {
-	struct ieee80211_tkip_data *tkey = priv;
+	struct lib80211_tkip_data *tkey = priv;
 	struct blkcipher_desc desc = { .tfm = tkey->tx_tfm_arc4 };
 	int len;
 	u8 rc4key[16], *pos, *icv;
 	u32 crc;
 	struct scatterlist sg;
-	DECLARE_MAC_BUF(mac);
 
 	if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
 		if (net_ratelimit()) {
-			struct ieee80211_hdr_4addr *hdr =
-			    (struct ieee80211_hdr_4addr *)skb->data;
+			struct ieee80211_hdr *hdr =
+			    (struct ieee80211_hdr *)skb->data;
 			printk(KERN_DEBUG ": TKIP countermeasures: dropped "
-			       "TX packet to %s\n",
-			       print_mac(mac, hdr->addr1));
+			       "TX packet to %pM\n", hdr->addr1);
 		}
 		return -1;
 	}
@@ -378,7 +381,7 @@
 	len = skb->len - hdr_len;
 	pos = skb->data + hdr_len;
 
-	if ((ieee80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
+	if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
 		return -1;
 
 	icv = skb_put(skb, 4);
@@ -407,28 +410,26 @@
 	return 0;
 }
 
-static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 {
-	struct ieee80211_tkip_data *tkey = priv;
+	struct lib80211_tkip_data *tkey = priv;
 	struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 };
 	u8 rc4key[16];
 	u8 keyidx, *pos;
 	u32 iv32;
 	u16 iv16;
-	struct ieee80211_hdr_4addr *hdr;
+	struct ieee80211_hdr *hdr;
 	u8 icv[4];
 	u32 crc;
 	struct scatterlist sg;
 	int plen;
-	DECLARE_MAC_BUF(mac);
 
-	hdr = (struct ieee80211_hdr_4addr *)skb->data;
+	hdr = (struct ieee80211_hdr *)skb->data;
 
 	if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG ": TKIP countermeasures: dropped "
-			       "received packet from %s\n",
-			       print_mac(mac, hdr->addr2));
+			       "received packet from %pM\n", hdr->addr2);
 		}
 		return -1;
 	}
@@ -441,7 +442,7 @@
 	if (!(keyidx & (1 << 5))) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "TKIP: received packet without ExtIV"
-			       " flag from %s\n", print_mac(mac, hdr->addr2));
+			       " flag from %pM\n", hdr->addr2);
 		}
 		return -2;
 	}
@@ -453,9 +454,9 @@
 	}
 	if (!tkey->key_set) {
 		if (net_ratelimit()) {
-			printk(KERN_DEBUG "TKIP: received packet from %s"
+			printk(KERN_DEBUG "TKIP: received packet from %pM"
 			       " with keyid=%d that does not have a configured"
-			       " key\n", print_mac(mac, hdr->addr2), keyidx);
+			       " key\n", hdr->addr2, keyidx);
 		}
 		return -3;
 	}
@@ -464,10 +465,10 @@
 	pos += 8;
 
 	if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
-		if (ieee80211_ratelimit_debug(IEEE80211_DL_DROP)) {
-			IEEE80211_DEBUG_DROP("TKIP: replay detected: STA=%s"
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
 			       " previous TSC %08x%04x received TSC "
-			       "%08x%04x\n", print_mac(mac, hdr->addr2),
+			       "%08x%04x\n", hdr->addr2,
 			       tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
 		}
 		tkey->dot11RSNAStatsTKIPReplays++;
@@ -487,8 +488,8 @@
 	if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG ": TKIP: failed to decrypt "
-			       "received packet from %s\n",
-			       print_mac(mac, hdr->addr2));
+			       "received packet from %pM\n",
+			       hdr->addr2);
 		}
 		return -7;
 	}
@@ -504,9 +505,9 @@
 			 * it needs to be recalculated for the next packet. */
 			tkey->rx_phase1_done = 0;
 		}
-		if (ieee80211_ratelimit_debug(IEEE80211_DL_DROP)) {
-			IEEE80211_DEBUG_DROP("TKIP: ICV error detected: STA="
-			       "%s\n", print_mac(mac, hdr->addr2));
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "TKIP: ICV error detected: STA="
+			       "%pM\n", hdr->addr2);
 		}
 		tkey->dot11RSNAStatsTKIPICVErrors++;
 		return -5;
@@ -549,13 +550,11 @@
 
 static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
 {
-	struct ieee80211_hdr_4addr *hdr11;
-	u16 stype;
+	struct ieee80211_hdr *hdr11;
 
-	hdr11 = (struct ieee80211_hdr_4addr *)skb->data;
-	stype  = WLAN_FC_GET_STYPE(le16_to_cpu(hdr11->frame_ctl));
+	hdr11 = (struct ieee80211_hdr *)skb->data;
 
-	switch (le16_to_cpu(hdr11->frame_ctl) &
+	switch (le16_to_cpu(hdr11->frame_control) &
 		(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
 	case IEEE80211_FCTL_TODS:
 		memcpy(hdr, hdr11->addr3, ETH_ALEN);	/* DA */
@@ -575,20 +574,19 @@
 		break;
 	}
 
-	if (stype & IEEE80211_STYPE_QOS_DATA) {
-		const struct ieee80211_hdr_3addrqos *qoshdr =
-			(struct ieee80211_hdr_3addrqos *)skb->data;
-		hdr[12] = le16_to_cpu(qoshdr->qos_ctl) & IEEE80211_QCTL_TID;
+	if (ieee80211_is_data_qos(hdr11->frame_control)) {
+		hdr[12] = le16_to_cpu(*ieee80211_get_qos_ctl(hdr11))
+			& IEEE80211_QOS_CTL_TID_MASK;
 	} else
 		hdr[12] = 0;		/* priority */
 
 	hdr[13] = hdr[14] = hdr[15] = 0;	/* reserved */
 }
 
-static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
+static int lib80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
 				     void *priv)
 {
-	struct ieee80211_tkip_data *tkey = priv;
+	struct lib80211_tkip_data *tkey = priv;
 	u8 *pos;
 
 	if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
@@ -607,8 +605,8 @@
 	return 0;
 }
 
-static void ieee80211_michael_mic_failure(struct net_device *dev,
-					  struct ieee80211_hdr_4addr *hdr,
+static void lib80211_michael_mic_failure(struct net_device *dev,
+					  struct ieee80211_hdr *hdr,
 					  int keyidx)
 {
 	union iwreq_data wrqu;
@@ -628,12 +626,11 @@
 	wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
 }
 
-static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
+static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
 					int hdr_len, void *priv)
 {
-	struct ieee80211_tkip_data *tkey = priv;
+	struct lib80211_tkip_data *tkey = priv;
 	u8 mic[8];
-	DECLARE_MAC_BUF(mac);
 
 	if (!tkey->key_set)
 		return -1;
@@ -643,14 +640,14 @@
 			skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
 		return -1;
 	if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
-		struct ieee80211_hdr_4addr *hdr;
-		hdr = (struct ieee80211_hdr_4addr *)skb->data;
+		struct ieee80211_hdr *hdr;
+		hdr = (struct ieee80211_hdr *)skb->data;
 		printk(KERN_DEBUG "%s: Michael MIC verification failed for "
-		       "MSDU from %s keyidx=%d\n",
-		       skb->dev ? skb->dev->name : "N/A", print_mac(mac, hdr->addr2),
+		       "MSDU from %pM keyidx=%d\n",
+		       skb->dev ? skb->dev->name : "N/A", hdr->addr2,
 		       keyidx);
 		if (skb->dev)
-			ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
+			lib80211_michael_mic_failure(skb->dev, hdr, keyidx);
 		tkey->dot11RSNAStatsTKIPLocalMICFailures++;
 		return -1;
 	}
@@ -665,9 +662,9 @@
 	return 0;
 }
 
-static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
+static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
 {
-	struct ieee80211_tkip_data *tkey = priv;
+	struct lib80211_tkip_data *tkey = priv;
 	int keyidx;
 	struct crypto_hash *tfm = tkey->tx_tfm_michael;
 	struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
@@ -698,9 +695,9 @@
 	return 0;
 }
 
-static int ieee80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
+static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
 {
-	struct ieee80211_tkip_data *tkey = priv;
+	struct lib80211_tkip_data *tkey = priv;
 
 	if (len < TKIP_KEY_LEN)
 		return -1;
@@ -727,9 +724,9 @@
 	return TKIP_KEY_LEN;
 }
 
-static char *ieee80211_tkip_print_stats(char *p, void *priv)
+static char *lib80211_tkip_print_stats(char *p, void *priv)
 {
-	struct ieee80211_tkip_data *tkip = priv;
+	struct lib80211_tkip_data *tkip = priv;
 	p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
 		     "tx_pn=%02x%02x%02x%02x%02x%02x "
 		     "rx_pn=%02x%02x%02x%02x%02x%02x "
@@ -753,35 +750,35 @@
 	return p;
 }
 
-static struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
+static struct lib80211_crypto_ops lib80211_crypt_tkip = {
 	.name = "TKIP",
-	.init = ieee80211_tkip_init,
-	.deinit = ieee80211_tkip_deinit,
-	.build_iv = ieee80211_tkip_hdr,
-	.encrypt_mpdu = ieee80211_tkip_encrypt,
-	.decrypt_mpdu = ieee80211_tkip_decrypt,
-	.encrypt_msdu = ieee80211_michael_mic_add,
-	.decrypt_msdu = ieee80211_michael_mic_verify,
-	.set_key = ieee80211_tkip_set_key,
-	.get_key = ieee80211_tkip_get_key,
-	.print_stats = ieee80211_tkip_print_stats,
+	.init = lib80211_tkip_init,
+	.deinit = lib80211_tkip_deinit,
+	.build_iv = lib80211_tkip_hdr,
+	.encrypt_mpdu = lib80211_tkip_encrypt,
+	.decrypt_mpdu = lib80211_tkip_decrypt,
+	.encrypt_msdu = lib80211_michael_mic_add,
+	.decrypt_msdu = lib80211_michael_mic_verify,
+	.set_key = lib80211_tkip_set_key,
+	.get_key = lib80211_tkip_get_key,
+	.print_stats = lib80211_tkip_print_stats,
 	.extra_mpdu_prefix_len = 4 + 4,	/* IV + ExtIV */
 	.extra_mpdu_postfix_len = 4,	/* ICV */
 	.extra_msdu_postfix_len = 8,	/* MIC */
-	.get_flags = ieee80211_tkip_get_flags,
-	.set_flags = ieee80211_tkip_set_flags,
+	.get_flags = lib80211_tkip_get_flags,
+	.set_flags = lib80211_tkip_set_flags,
 	.owner = THIS_MODULE,
 };
 
-static int __init ieee80211_crypto_tkip_init(void)
+static int __init lib80211_crypto_tkip_init(void)
 {
-	return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip);
+	return lib80211_register_crypto_ops(&lib80211_crypt_tkip);
 }
 
-static void __exit ieee80211_crypto_tkip_exit(void)
+static void __exit lib80211_crypto_tkip_exit(void)
 {
-	ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
+	lib80211_unregister_crypto_ops(&lib80211_crypt_tkip);
 }
 
-module_init(ieee80211_crypto_tkip_init);
-module_exit(ieee80211_crypto_tkip_exit);
+module_init(lib80211_crypto_tkip_init);
+module_exit(lib80211_crypto_tkip_exit);
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c
similarity index 74%
rename from net/ieee80211/ieee80211_crypt_wep.c
rename to net/wireless/lib80211_crypt_wep.c
index 3fa30c4..6d41e05 100644
--- a/net/ieee80211/ieee80211_crypt_wep.c
+++ b/net/wireless/lib80211_crypt_wep.c
@@ -1,7 +1,8 @@
 /*
- * Host AP crypt: host-based WEP encryption implementation for Host AP driver
+ * lib80211 crypt: host-based WEP encryption implementation for lib80211
  *
  * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008, John W. Linville <linville@tuxdriver.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
@@ -19,16 +20,16 @@
 #include <linux/mm.h>
 #include <asm/string.h>
 
-#include <net/ieee80211.h>
+#include <net/lib80211.h>
 
 #include <linux/crypto.h>
 #include <linux/crc32.h>
 
 MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Host AP crypt: WEP");
+MODULE_DESCRIPTION("lib80211 crypt: WEP");
 MODULE_LICENSE("GPL");
 
-struct prism2_wep_data {
+struct lib80211_wep_data {
 	u32 iv;
 #define WEP_KEY_LEN 13
 	u8 key[WEP_KEY_LEN + 1];
@@ -38,9 +39,9 @@
 	struct crypto_blkcipher *rx_tfm;
 };
 
-static void *prism2_wep_init(int keyidx)
+static void *lib80211_wep_init(int keyidx)
 {
-	struct prism2_wep_data *priv;
+	struct lib80211_wep_data *priv;
 
 	priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
 	if (priv == NULL)
@@ -49,7 +50,7 @@
 
 	priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(priv->tx_tfm)) {
-		printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
+		printk(KERN_DEBUG "lib80211_crypt_wep: could not allocate "
 		       "crypto API arc4\n");
 		priv->tx_tfm = NULL;
 		goto fail;
@@ -57,7 +58,7 @@
 
 	priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(priv->rx_tfm)) {
-		printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
+		printk(KERN_DEBUG "lib80211_crypt_wep: could not allocate "
 		       "crypto API arc4\n");
 		priv->rx_tfm = NULL;
 		goto fail;
@@ -78,9 +79,9 @@
 	return NULL;
 }
 
-static void prism2_wep_deinit(void *priv)
+static void lib80211_wep_deinit(void *priv)
 {
-	struct prism2_wep_data *_priv = priv;
+	struct lib80211_wep_data *_priv = priv;
 	if (_priv) {
 		if (_priv->tx_tfm)
 			crypto_free_blkcipher(_priv->tx_tfm);
@@ -91,10 +92,10 @@
 }
 
 /* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
-static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len,
+static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len,
 			       u8 *key, int keylen, void *priv)
 {
-	struct prism2_wep_data *wep = priv;
+	struct lib80211_wep_data *wep = priv;
 	u32 klen, len;
 	u8 *pos;
 
@@ -134,21 +135,21 @@
  *
  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
  */
-static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
 {
-	struct prism2_wep_data *wep = priv;
+	struct lib80211_wep_data *wep = priv;
 	struct blkcipher_desc desc = { .tfm = wep->tx_tfm };
 	u32 crc, klen, len;
 	u8 *pos, *icv;
 	struct scatterlist sg;
 	u8 key[WEP_KEY_LEN + 3];
 
-	/* other checks are in prism2_wep_build_iv */
+	/* other checks are in lib80211_wep_build_iv */
 	if (skb_tailroom(skb) < 4)
 		return -1;
 
 	/* add the IV to the frame */
-	if (prism2_wep_build_iv(skb, hdr_len, NULL, 0, priv))
+	if (lib80211_wep_build_iv(skb, hdr_len, NULL, 0, priv))
 		return -1;
 
 	/* Copy the IV into the first 3 bytes of the key */
@@ -181,9 +182,9 @@
  * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
  * failure. If frame is OK, IV and ICV will be removed.
  */
-static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 {
-	struct prism2_wep_data *wep = priv;
+	struct lib80211_wep_data *wep = priv;
 	struct blkcipher_desc desc = { .tfm = wep->rx_tfm };
 	u32 crc, klen, plen;
 	u8 key[WEP_KEY_LEN + 3];
@@ -232,9 +233,9 @@
 	return 0;
 }
 
-static int prism2_wep_set_key(void *key, int len, u8 * seq, void *priv)
+static int lib80211_wep_set_key(void *key, int len, u8 * seq, void *priv)
 {
-	struct prism2_wep_data *wep = priv;
+	struct lib80211_wep_data *wep = priv;
 
 	if (len < 0 || len > WEP_KEY_LEN)
 		return -1;
@@ -245,9 +246,9 @@
 	return 0;
 }
 
-static int prism2_wep_get_key(void *key, int len, u8 * seq, void *priv)
+static int lib80211_wep_get_key(void *key, int len, u8 * seq, void *priv)
 {
-	struct prism2_wep_data *wep = priv;
+	struct lib80211_wep_data *wep = priv;
 
 	if (len < wep->key_len)
 		return -1;
@@ -257,39 +258,39 @@
 	return wep->key_len;
 }
 
-static char *prism2_wep_print_stats(char *p, void *priv)
+static char *lib80211_wep_print_stats(char *p, void *priv)
 {
-	struct prism2_wep_data *wep = priv;
+	struct lib80211_wep_data *wep = priv;
 	p += sprintf(p, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
 	return p;
 }
 
-static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
+static struct lib80211_crypto_ops lib80211_crypt_wep = {
 	.name = "WEP",
-	.init = prism2_wep_init,
-	.deinit = prism2_wep_deinit,
-	.build_iv = prism2_wep_build_iv,
-	.encrypt_mpdu = prism2_wep_encrypt,
-	.decrypt_mpdu = prism2_wep_decrypt,
+	.init = lib80211_wep_init,
+	.deinit = lib80211_wep_deinit,
+	.build_iv = lib80211_wep_build_iv,
+	.encrypt_mpdu = lib80211_wep_encrypt,
+	.decrypt_mpdu = lib80211_wep_decrypt,
 	.encrypt_msdu = NULL,
 	.decrypt_msdu = NULL,
-	.set_key = prism2_wep_set_key,
-	.get_key = prism2_wep_get_key,
-	.print_stats = prism2_wep_print_stats,
+	.set_key = lib80211_wep_set_key,
+	.get_key = lib80211_wep_get_key,
+	.print_stats = lib80211_wep_print_stats,
 	.extra_mpdu_prefix_len = 4,	/* IV */
 	.extra_mpdu_postfix_len = 4,	/* ICV */
 	.owner = THIS_MODULE,
 };
 
-static int __init ieee80211_crypto_wep_init(void)
+static int __init lib80211_crypto_wep_init(void)
 {
-	return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
+	return lib80211_register_crypto_ops(&lib80211_crypt_wep);
 }
 
-static void __exit ieee80211_crypto_wep_exit(void)
+static void __exit lib80211_crypto_wep_exit(void)
 {
-	ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
+	lib80211_unregister_crypto_ops(&lib80211_crypt_wep);
 }
 
-module_init(ieee80211_crypto_wep_init);
-module_exit(ieee80211_crypto_wep_exit);
+module_init(lib80211_crypto_wep_init);
+module_exit(lib80211_crypto_wep_exit);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 572793c..1e728ff 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -58,6 +58,9 @@
 	[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
 	[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
 				      .len = BUS_ID_SIZE-1 },
+	[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
+	[NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
+	[NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
 
 	[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
 	[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
@@ -84,7 +87,7 @@
 					       .len = NL80211_MAX_SUPP_RATES },
 	[NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 },
 	[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
-	[NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED },
+	[NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
 	[NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
 				.len = IEEE80211_MAX_MESH_ID_LEN },
 	[NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
@@ -95,6 +98,10 @@
 	[NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
 	[NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
 	[NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
+	[NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY,
+					   .len = NL80211_MAX_SUPP_RATES },
+
+	[NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED },
 
 	[NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
 					 .len = NL80211_HT_CAPABILITY_LEN },
@@ -157,6 +164,19 @@
 		if (!nl_band)
 			goto nla_put_failure;
 
+		/* add HT info */
+		if (dev->wiphy.bands[band]->ht_cap.ht_supported) {
+			NLA_PUT(msg, NL80211_BAND_ATTR_HT_MCS_SET,
+				sizeof(dev->wiphy.bands[band]->ht_cap.mcs),
+				&dev->wiphy.bands[band]->ht_cap.mcs);
+			NLA_PUT_U16(msg, NL80211_BAND_ATTR_HT_CAPA,
+				dev->wiphy.bands[band]->ht_cap.cap);
+			NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+				dev->wiphy.bands[band]->ht_cap.ampdu_factor);
+			NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+				dev->wiphy.bands[band]->ht_cap.ampdu_density);
+		}
+
 		/* add frequencies */
 		nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
 		if (!nl_freqs)
@@ -180,6 +200,9 @@
 			if (chan->flags & IEEE80211_CHAN_RADAR)
 				NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
 
+			NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+				    DBM_TO_MBM(chan->max_power));
+
 			nla_nest_end(msg, nl_freq);
 		}
 
@@ -269,20 +292,142 @@
 	return -ENOBUFS;
 }
 
+static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
+	[NL80211_TXQ_ATTR_QUEUE]		= { .type = NLA_U8 },
+	[NL80211_TXQ_ATTR_TXOP]			= { .type = NLA_U16 },
+	[NL80211_TXQ_ATTR_CWMIN]		= { .type = NLA_U16 },
+	[NL80211_TXQ_ATTR_CWMAX]		= { .type = NLA_U16 },
+	[NL80211_TXQ_ATTR_AIFS]			= { .type = NLA_U8 },
+};
+
+static int parse_txq_params(struct nlattr *tb[],
+			    struct ieee80211_txq_params *txq_params)
+{
+	if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] ||
+	    !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
+	    !tb[NL80211_TXQ_ATTR_AIFS])
+		return -EINVAL;
+
+	txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]);
+	txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
+	txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
+	txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
+	txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
+
+	return 0;
+}
+
 static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev;
-	int result;
-
-	if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
-		return -EINVAL;
+	int result = 0, rem_txq_params = 0;
+	struct nlattr *nl_txq_params;
 
 	rdev = cfg80211_get_dev_from_info(info);
 	if (IS_ERR(rdev))
 		return PTR_ERR(rdev);
 
-	result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
+	if (info->attrs[NL80211_ATTR_WIPHY_NAME]) {
+		result = cfg80211_dev_rename(
+			rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
+		if (result)
+			goto bad_res;
+	}
 
+	if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
+		struct ieee80211_txq_params txq_params;
+		struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
+
+		if (!rdev->ops->set_txq_params) {
+			result = -EOPNOTSUPP;
+			goto bad_res;
+		}
+
+		nla_for_each_nested(nl_txq_params,
+				    info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
+				    rem_txq_params) {
+			nla_parse(tb, NL80211_TXQ_ATTR_MAX,
+				  nla_data(nl_txq_params),
+				  nla_len(nl_txq_params),
+				  txq_params_policy);
+			result = parse_txq_params(tb, &txq_params);
+			if (result)
+				goto bad_res;
+
+			result = rdev->ops->set_txq_params(&rdev->wiphy,
+							   &txq_params);
+			if (result)
+				goto bad_res;
+		}
+	}
+
+	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+		enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+		struct ieee80211_channel *chan;
+		struct ieee80211_sta_ht_cap *ht_cap;
+		u32 freq, sec_freq;
+
+		if (!rdev->ops->set_channel) {
+			result = -EOPNOTSUPP;
+			goto bad_res;
+		}
+
+		result = -EINVAL;
+
+		if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+			channel_type = nla_get_u32(info->attrs[
+					   NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+			if (channel_type != NL80211_CHAN_NO_HT &&
+			    channel_type != NL80211_CHAN_HT20 &&
+			    channel_type != NL80211_CHAN_HT40PLUS &&
+			    channel_type != NL80211_CHAN_HT40MINUS)
+				goto bad_res;
+		}
+
+		freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+		chan = ieee80211_get_channel(&rdev->wiphy, freq);
+
+		/* Primary channel not allowed */
+		if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
+			goto bad_res;
+
+		if (channel_type == NL80211_CHAN_HT40MINUS)
+			sec_freq = freq - 20;
+		else if (channel_type == NL80211_CHAN_HT40PLUS)
+			sec_freq = freq + 20;
+		else
+			sec_freq = 0;
+
+		ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
+
+		/* no HT capabilities */
+		if (channel_type != NL80211_CHAN_NO_HT &&
+		    !ht_cap->ht_supported)
+			goto bad_res;
+
+		if (sec_freq) {
+			struct ieee80211_channel *schan;
+
+			/* no 40 MHz capabilities */
+			if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
+			    (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
+				goto bad_res;
+
+			schan = ieee80211_get_channel(&rdev->wiphy, sec_freq);
+
+			/* Secondary channel not allowed */
+			if (!schan || schan->flags & IEEE80211_CHAN_DISABLED)
+				goto bad_res;
+		}
+
+		result = rdev->ops->set_channel(&rdev->wiphy, chan,
+						channel_type);
+		if (result)
+			goto bad_res;
+	}
+
+
+ bad_res:
 	cfg80211_put_dev(rdev);
 	return result;
 }
@@ -945,12 +1090,46 @@
 	return 0;
 }
 
+static u16 nl80211_calculate_bitrate(struct rate_info *rate)
+{
+	int modulation, streams, bitrate;
+
+	if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+		return rate->legacy;
+
+	/* the formula below does only work for MCS values smaller than 32 */
+	if (rate->mcs >= 32)
+		return 0;
+
+	modulation = rate->mcs & 7;
+	streams = (rate->mcs >> 3) + 1;
+
+	bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ?
+			13500000 : 6500000;
+
+	if (modulation < 4)
+		bitrate *= (modulation + 1);
+	else if (modulation == 4)
+		bitrate *= (modulation + 2);
+	else
+		bitrate *= (modulation + 3);
+
+	bitrate *= streams;
+
+	if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+		bitrate = (bitrate / 9) * 10;
+
+	/* do NOT round down here */
+	return (bitrate + 50000) / 100000;
+}
+
 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
 				int flags, struct net_device *dev,
 				u8 *mac_addr, struct station_info *sinfo)
 {
 	void *hdr;
-	struct nlattr *sinfoattr;
+	struct nlattr *sinfoattr, *txrate;
+	u16 bitrate;
 
 	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
 	if (!hdr)
@@ -980,7 +1159,29 @@
 	if (sinfo->filled & STATION_INFO_PLINK_STATE)
 		NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE,
 			    sinfo->plink_state);
+	if (sinfo->filled & STATION_INFO_SIGNAL)
+		NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL,
+			   sinfo->signal);
+	if (sinfo->filled & STATION_INFO_TX_BITRATE) {
+		txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE);
+		if (!txrate)
+			goto nla_put_failure;
 
+		/* nl80211_calculate_bitrate will return 0 for mcs >= 32 */
+		bitrate = nl80211_calculate_bitrate(&sinfo->txrate);
+		if (bitrate > 0)
+			NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
+
+		if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS)
+			NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS,
+				    sinfo->txrate.mcs);
+		if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
+			NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
+		if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI)
+			NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
+
+		nla_nest_end(msg, txrate);
+	}
 	nla_nest_end(msg, sinfoattr);
 
 	return genlmsg_end(msg, hdr);
@@ -1598,6 +1799,12 @@
 	if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
 		params.use_short_slot_time =
 		    nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
+	if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
+		params.basic_rates =
+			nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+		params.basic_rates_len =
+			nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+	}
 
 	err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
 	if (err)
@@ -1680,11 +1887,188 @@
 		return -EINVAL;
 #endif
 	mutex_lock(&cfg80211_drv_mutex);
-	r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, NULL);
+	r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
 	mutex_unlock(&cfg80211_drv_mutex);
 	return r;
 }
 
+static int nl80211_get_mesh_params(struct sk_buff *skb,
+	struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	struct mesh_config cur_params;
+	int err;
+	struct net_device *dev;
+	void *hdr;
+	struct nlattr *pinfoattr;
+	struct sk_buff *msg;
+
+	/* Look up our device */
+	err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+	if (err)
+		return err;
+
+	/* Get the mesh params */
+	rtnl_lock();
+	err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params);
+	rtnl_unlock();
+	if (err)
+		goto out;
+
+	/* Draw up a netlink message to send back */
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg) {
+		err = -ENOBUFS;
+		goto out;
+	}
+	hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+			     NL80211_CMD_GET_MESH_PARAMS);
+	if (!hdr)
+		goto nla_put_failure;
+	pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS);
+	if (!pinfoattr)
+		goto nla_put_failure;
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+	NLA_PUT_U16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
+			cur_params.dot11MeshRetryTimeout);
+	NLA_PUT_U16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
+			cur_params.dot11MeshConfirmTimeout);
+	NLA_PUT_U16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
+			cur_params.dot11MeshHoldingTimeout);
+	NLA_PUT_U16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+			cur_params.dot11MeshMaxPeerLinks);
+	NLA_PUT_U8(msg, NL80211_MESHCONF_MAX_RETRIES,
+			cur_params.dot11MeshMaxRetries);
+	NLA_PUT_U8(msg, NL80211_MESHCONF_TTL,
+			cur_params.dot11MeshTTL);
+	NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+			cur_params.auto_open_plinks);
+	NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+			cur_params.dot11MeshHWMPmaxPREQretries);
+	NLA_PUT_U32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
+			cur_params.path_refresh_time);
+	NLA_PUT_U16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+			cur_params.min_discovery_timeout);
+	NLA_PUT_U32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+			cur_params.dot11MeshHWMPactivePathTimeout);
+	NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+			cur_params.dot11MeshHWMPpreqMinInterval);
+	NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+			cur_params.dot11MeshHWMPnetDiameterTraversalTime);
+	nla_nest_end(msg, pinfoattr);
+	genlmsg_end(msg, hdr);
+	err = genlmsg_unicast(msg, info->snd_pid);
+	goto out;
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	err = -EMSGSIZE;
+out:
+	/* Cleanup */
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+#define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \
+do {\
+	if (table[attr_num]) {\
+		cfg.param = nla_fn(table[attr_num]); \
+		mask |= (1 << (attr_num - 1)); \
+	} \
+} while (0);\
+
+static struct nla_policy
+nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] __read_mostly = {
+	[NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
+	[NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
+	[NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
+	[NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
+	[NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
+	[NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
+	[NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
+
+	[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
+	[NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
+	[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
+	[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
+	[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
+	[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
+};
+
+static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
+{
+	int err;
+	u32 mask;
+	struct cfg80211_registered_device *drv;
+	struct net_device *dev;
+	struct mesh_config cfg;
+	struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
+	struct nlattr *parent_attr;
+
+	parent_attr = info->attrs[NL80211_ATTR_MESH_PARAMS];
+	if (!parent_attr)
+		return -EINVAL;
+	if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX,
+			parent_attr, nl80211_meshconf_params_policy))
+		return -EINVAL;
+
+	err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+	if (err)
+		return err;
+
+	/* This makes sure that there aren't more than 32 mesh config
+	 * parameters (otherwise our bitfield scheme would not work.) */
+	BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
+
+	/* Fill in the params struct */
+	mask = 0;
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout,
+			mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout,
+			mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout,
+			mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks,
+			mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries,
+			mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL,
+			mask, NL80211_MESHCONF_TTL, nla_get_u8);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks,
+			mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries,
+			mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+			nla_get_u8);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time,
+			mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout,
+			mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+			nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
+			mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+			nla_get_u32);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
+			mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+			nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+			dot11MeshHWMPnetDiameterTraversalTime,
+			mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+			nla_get_u16);
+
+	/* Apply changes */
+	rtnl_lock();
+	err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask);
+	rtnl_unlock();
+
+	/* cleanup */
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+#undef FILL_IN_MESH_PARAM_IF_SET
+
 static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
 {
 	struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
@@ -1743,12 +2127,9 @@
 	mutex_lock(&cfg80211_drv_mutex);
 	r = set_regdom(rd);
 	mutex_unlock(&cfg80211_drv_mutex);
-	if (r)
-		goto bad_reg;
-
 	return r;
 
-bad_reg:
+ bad_reg:
 	kfree(rd);
 	return -EINVAL;
 }
@@ -1902,6 +2283,18 @@
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 	},
+	{
+		.cmd = NL80211_CMD_GET_MESH_PARAMS,
+		.doit = nl80211_get_mesh_params,
+		.policy = nl80211_policy,
+		/* can be retrieved by unprivileged users */
+	},
+	{
+		.cmd = NL80211_CMD_SET_MESH_PARAMS,
+		.doit = nl80211_set_mesh_params,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
 };
 
 /* multicast groups */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index eb3b1a9..4f87753 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -42,17 +42,40 @@
 #include "core.h"
 #include "reg.h"
 
-/* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */
+/**
+ * struct regulatory_request - receipt of last regulatory request
+ *
+ * @wiphy: this is set if this request's initiator is
+ * 	%REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
+ * 	can be used by the wireless core to deal with conflicts
+ * 	and potentially inform users of which devices specifically
+ * 	cased the conflicts.
+ * @initiator: indicates who sent this request, could be any of
+ * 	of those set in reg_set_by, %REGDOM_SET_BY_*
+ * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested
+ * 	regulatory domain. We have a few special codes:
+ * 	00 - World regulatory domain
+ * 	99 - built by driver but a specific alpha2 cannot be determined
+ * 	98 - result of an intersection between two regulatory domains
+ * @intersect: indicates whether the wireless core should intersect
+ * 	the requested regulatory domain with the presently set regulatory
+ * 	domain.
+ * @country_ie_checksum: checksum of the last processed and accepted
+ * 	country IE
+ * @country_ie_env: lets us know if the AP is telling us we are outdoor,
+ * 	indoor, or if it doesn't matter
+ */
 struct regulatory_request {
-	struct list_head list;
 	struct wiphy *wiphy;
-	int granted;
 	enum reg_set_by initiator;
 	char alpha2[2];
+	bool intersect;
+	u32 country_ie_checksum;
+	enum environment_cap country_ie_env;
 };
 
-static LIST_HEAD(regulatory_requests);
-DEFINE_MUTEX(cfg80211_reg_mutex);
+/* Receipt of information from last regulatory request */
+static struct regulatory_request *last_request;
 
 /* To trigger userspace events */
 static struct platform_device *reg_pdev;
@@ -63,13 +86,16 @@
 	MHZ_TO_KHZ(20),
 };
 
-static struct list_head regulatory_requests;
-
 /* Central wireless core regulatory domains, we only need two,
  * the current one and a world regulatory domain in case we have no
  * information to give us an alpha2 */
 static const struct ieee80211_regdomain *cfg80211_regdomain;
 
+/* We use this as a place for the rd structure built from the
+ * last parsed country IE to rest until CRDA gets back to us with
+ * what it thinks should apply for the same country */
+static const struct ieee80211_regdomain *country_ie_regdomain;
+
 /* We keep a static world regulatory domain in case of the absence of CRDA */
 static const struct ieee80211_regdomain world_regdom = {
 	.n_reg_rules = 1,
@@ -204,7 +230,7 @@
  * core upon initialization */
 static void update_world_regdomain(const struct ieee80211_regdomain *rd)
 {
-	BUG_ON(list_empty(&regulatory_requests));
+	BUG_ON(!last_request);
 
 	reset_regdomains();
 
@@ -249,6 +275,18 @@
 	return false;
 }
 
+static bool is_intersected_alpha2(const char *alpha2)
+{
+	if (!alpha2)
+		return false;
+	/* Special case where regulatory domain is the
+	 * result of an intersection between two regulatory domain
+	 * structures */
+	if (alpha2[0] == '9' && alpha2[1] == '8')
+		return true;
+	return false;
+}
+
 static bool is_an_alpha2(const char *alpha2)
 {
 	if (!alpha2)
@@ -277,6 +315,25 @@
 	return true;
 }
 
+/**
+ * country_ie_integrity_changes - tells us if the country IE has changed
+ * @checksum: checksum of country IE of fields we are interested in
+ *
+ * If the country IE has not changed you can ignore it safely. This is
+ * useful to determine if two devices are seeing two different country IEs
+ * even on the same alpha2. Note that this will return false if no IE has
+ * been set on the wireless core yet.
+ */
+static bool country_ie_integrity_changes(u32 checksum)
+{
+	/* If no IE has been set then the checksum doesn't change */
+	if (unlikely(!last_request->country_ie_checksum))
+		return false;
+	if (unlikely(last_request->country_ie_checksum != checksum))
+		return true;
+	return false;
+}
+
 /* This lets us keep regulatory code which is updated on a regulatory
  * basis in userspace. */
 static int call_crda(const char *alpha2)
@@ -300,121 +357,13 @@
 	return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, envp);
 }
 
-/* This has the logic which determines when a new request
- * should be ignored. */
-static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
-	char *alpha2, struct ieee80211_regdomain *rd)
-{
-	struct regulatory_request *last_request = NULL;
-
-	/* All initial requests are respected */
-	if (list_empty(&regulatory_requests))
-		return 0;
-
-	last_request = list_first_entry(&regulatory_requests,
-		struct regulatory_request, list);
-
-	switch (set_by) {
-	case REGDOM_SET_BY_INIT:
-		return -EINVAL;
-	case REGDOM_SET_BY_CORE:
-		/* Always respect new wireless core hints, should only
-		 * come in for updating the world regulatory domain at init
-		 * anyway */
-		return 0;
-	case REGDOM_SET_BY_COUNTRY_IE:
-		if (last_request->initiator == set_by) {
-			if (last_request->wiphy != wiphy) {
-				/* Two cards with two APs claiming different
-				 * different Country IE alpha2s!
-				 * You're special!! */
-				if (!alpha2_equal(last_request->alpha2,
-						cfg80211_regdomain->alpha2)) {
-					/* XXX: Deal with conflict, consider
-					 * building a new one out of the
-					 * intersection */
-					WARN_ON(1);
-					return -EOPNOTSUPP;
-				}
-				return -EALREADY;
-			}
-			/* Two consecutive Country IE hints on the same wiphy */
-			if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
-				return 0;
-			return -EALREADY;
-		}
-		if (WARN(!is_alpha2_set(alpha2) || !is_an_alpha2(alpha2),
-				"Invalid Country IE regulatory hint passed "
-				"to the wireless core\n"))
-			return -EINVAL;
-		/* We ignore Country IE hints for now, as we haven't yet
-		 * added the dot11MultiDomainCapabilityEnabled flag
-		 * for wiphys */
-		return 1;
-	case REGDOM_SET_BY_DRIVER:
-		BUG_ON(!wiphy);
-		if (last_request->initiator == set_by) {
-			/* Two separate drivers hinting different things,
-			 * this is possible if you have two devices present
-			 * on a system with different EEPROM regulatory
-			 * readings. XXX: Do intersection, we support only
-			 * the first regulatory hint for now */
-			if (last_request->wiphy != wiphy)
-				return -EALREADY;
-			if (rd)
-				return -EALREADY;
-			/* Driver should not be trying to hint different
-			 * regulatory domains! */
-			BUG_ON(!alpha2_equal(alpha2,
-					cfg80211_regdomain->alpha2));
-			return -EALREADY;
-		}
-		if (last_request->initiator == REGDOM_SET_BY_CORE)
-			return 0;
-		/* XXX: Handle intersection, and add the
-		 * dot11MultiDomainCapabilityEnabled flag to wiphy. For now
-		 * we assume the driver has this set to false, following the
-		 * 802.11d dot11MultiDomainCapabilityEnabled documentation */
-		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
-			return 0;
-		return 0;
-	case REGDOM_SET_BY_USER:
-		if (last_request->initiator == set_by ||
-				last_request->initiator == REGDOM_SET_BY_CORE)
-			return 0;
-		/* Drivers can use their wiphy's reg_notifier()
-		 * to override any information */
-		if (last_request->initiator == REGDOM_SET_BY_DRIVER)
-			return 0;
-		/* XXX: Handle intersection */
-		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
-			return -EOPNOTSUPP;
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-static bool __reg_is_valid_request(const char *alpha2,
-	struct regulatory_request **request)
-{
-	struct regulatory_request *req;
-	if (list_empty(&regulatory_requests))
-		return false;
-	list_for_each_entry(req, &regulatory_requests, list) {
-		if (alpha2_equal(req->alpha2, alpha2)) {
-			*request = req;
-			return true;
-		}
-	}
-	return false;
-}
-
 /* Used by nl80211 before kmalloc'ing our regulatory domain */
 bool reg_is_valid_request(const char *alpha2)
 {
-	struct regulatory_request *request = NULL;
-	return  __reg_is_valid_request(alpha2, &request);
+	if (!last_request)
+		return false;
+
+	return alpha2_equal(last_request->alpha2, alpha2);
 }
 
 /* Sanity check on a regulatory rule */
@@ -423,7 +372,7 @@
 	const struct ieee80211_freq_range *freq_range = &rule->freq_range;
 	u32 freq_diff;
 
-	if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0)
+	if (freq_range->start_freq_khz <= 0 || freq_range->end_freq_khz <= 0)
 		return false;
 
 	if (freq_range->start_freq_khz > freq_range->end_freq_khz)
@@ -431,7 +380,7 @@
 
 	freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
 
-	if (freq_range->max_bandwidth_khz > freq_diff)
+	if (freq_diff <= 0 || freq_range->max_bandwidth_khz > freq_diff)
 		return false;
 
 	return true;
@@ -445,6 +394,9 @@
 	if (!rd->n_reg_rules)
 		return false;
 
+	if (WARN_ON(rd->n_reg_rules > NL80211_MAX_SUPP_REG_RULES))
+		return false;
+
 	for (i = 0; i < rd->n_reg_rules; i++) {
 		reg_rule = &rd->reg_rules[i];
 		if (!is_valid_reg_rule(reg_rule))
@@ -469,6 +421,311 @@
 	return 0;
 }
 
+/* Converts a country IE to a regulatory domain. A regulatory domain
+ * structure has a lot of information which the IE doesn't yet have,
+ * so for the other values we use upper max values as we will intersect
+ * with our userspace regulatory agent to get lower bounds. */
+static struct ieee80211_regdomain *country_ie_2_rd(
+				u8 *country_ie,
+				u8 country_ie_len,
+				u32 *checksum)
+{
+	struct ieee80211_regdomain *rd = NULL;
+	unsigned int i = 0;
+	char alpha2[2];
+	u32 flags = 0;
+	u32 num_rules = 0, size_of_regd = 0;
+	u8 *triplets_start = NULL;
+	u8 len_at_triplet = 0;
+	/* the last channel we have registered in a subband (triplet) */
+	int last_sub_max_channel = 0;
+
+	*checksum = 0xDEADBEEF;
+
+	/* Country IE requirements */
+	BUG_ON(country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN ||
+		country_ie_len & 0x01);
+
+	alpha2[0] = country_ie[0];
+	alpha2[1] = country_ie[1];
+
+	/*
+	 * Third octet can be:
+	 *    'I' - Indoor
+	 *    'O' - Outdoor
+	 *
+	 *  anything else we assume is no restrictions
+	 */
+	if (country_ie[2] == 'I')
+		flags = NL80211_RRF_NO_OUTDOOR;
+	else if (country_ie[2] == 'O')
+		flags = NL80211_RRF_NO_INDOOR;
+
+	country_ie += 3;
+	country_ie_len -= 3;
+
+	triplets_start = country_ie;
+	len_at_triplet = country_ie_len;
+
+	*checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8);
+
+	/* We need to build a reg rule for each triplet, but first we must
+	 * calculate the number of reg rules we will need. We will need one
+	 * for each channel subband */
+	while (country_ie_len >= 3) {
+		struct ieee80211_country_ie_triplet *triplet =
+			(struct ieee80211_country_ie_triplet *) country_ie;
+		int cur_sub_max_channel = 0, cur_channel = 0;
+
+		if (triplet->ext.reg_extension_id >=
+				IEEE80211_COUNTRY_EXTENSION_ID) {
+			country_ie += 3;
+			country_ie_len -= 3;
+			continue;
+		}
+
+		cur_channel = triplet->chans.first_channel;
+		cur_sub_max_channel = ieee80211_channel_to_frequency(
+			cur_channel + triplet->chans.num_channels);
+
+		/* Basic sanity check */
+		if (cur_sub_max_channel < cur_channel)
+			return NULL;
+
+		/* Do not allow overlapping channels. Also channels
+		 * passed in each subband must be monotonically
+		 * increasing */
+		if (last_sub_max_channel) {
+			if (cur_channel <= last_sub_max_channel)
+				return NULL;
+			if (cur_sub_max_channel <= last_sub_max_channel)
+				return NULL;
+		}
+
+		/* When dot11RegulatoryClassesRequired is supported
+		 * we can throw ext triplets as part of this soup,
+		 * for now we don't care when those change as we
+		 * don't support them */
+		*checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) |
+		  ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) |
+		  ((triplet->chans.max_power ^ cur_sub_max_channel) << 24);
+
+		last_sub_max_channel = cur_sub_max_channel;
+
+		country_ie += 3;
+		country_ie_len -= 3;
+		num_rules++;
+
+		/* Note: this is not a IEEE requirement but
+		 * simply a memory requirement */
+		if (num_rules > NL80211_MAX_SUPP_REG_RULES)
+			return NULL;
+	}
+
+	country_ie = triplets_start;
+	country_ie_len = len_at_triplet;
+
+	size_of_regd = sizeof(struct ieee80211_regdomain) +
+		(num_rules * sizeof(struct ieee80211_reg_rule));
+
+	rd = kzalloc(size_of_regd, GFP_KERNEL);
+	if (!rd)
+		return NULL;
+
+	rd->n_reg_rules = num_rules;
+	rd->alpha2[0] = alpha2[0];
+	rd->alpha2[1] = alpha2[1];
+
+	/* This time around we fill in the rd */
+	while (country_ie_len >= 3) {
+		struct ieee80211_country_ie_triplet *triplet =
+			(struct ieee80211_country_ie_triplet *) country_ie;
+		struct ieee80211_reg_rule *reg_rule = NULL;
+		struct ieee80211_freq_range *freq_range = NULL;
+		struct ieee80211_power_rule *power_rule = NULL;
+
+		/* Must parse if dot11RegulatoryClassesRequired is true,
+		 * we don't support this yet */
+		if (triplet->ext.reg_extension_id >=
+				IEEE80211_COUNTRY_EXTENSION_ID) {
+			country_ie += 3;
+			country_ie_len -= 3;
+			continue;
+		}
+
+		reg_rule = &rd->reg_rules[i];
+		freq_range = &reg_rule->freq_range;
+		power_rule = &reg_rule->power_rule;
+
+		reg_rule->flags = flags;
+
+		/* The +10 is since the regulatory domain expects
+		 * the actual band edge, not the center of freq for
+		 * its start and end freqs, assuming 20 MHz bandwidth on
+		 * the channels passed */
+		freq_range->start_freq_khz =
+			MHZ_TO_KHZ(ieee80211_channel_to_frequency(
+				triplet->chans.first_channel) - 10);
+		freq_range->end_freq_khz =
+			MHZ_TO_KHZ(ieee80211_channel_to_frequency(
+				triplet->chans.first_channel +
+					triplet->chans.num_channels) + 10);
+
+		/* Large arbitrary values, we intersect later */
+		/* Increment this if we ever support >= 40 MHz channels
+		 * in IEEE 802.11 */
+		freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40);
+		power_rule->max_antenna_gain = DBI_TO_MBI(100);
+		power_rule->max_eirp = DBM_TO_MBM(100);
+
+		country_ie += 3;
+		country_ie_len -= 3;
+		i++;
+
+		BUG_ON(i > NL80211_MAX_SUPP_REG_RULES);
+	}
+
+	return rd;
+}
+
+
+/* Helper for regdom_intersect(), this does the real
+ * mathematical intersection fun */
+static int reg_rules_intersect(
+	const struct ieee80211_reg_rule *rule1,
+	const struct ieee80211_reg_rule *rule2,
+	struct ieee80211_reg_rule *intersected_rule)
+{
+	const struct ieee80211_freq_range *freq_range1, *freq_range2;
+	struct ieee80211_freq_range *freq_range;
+	const struct ieee80211_power_rule *power_rule1, *power_rule2;
+	struct ieee80211_power_rule *power_rule;
+	u32 freq_diff;
+
+	freq_range1 = &rule1->freq_range;
+	freq_range2 = &rule2->freq_range;
+	freq_range = &intersected_rule->freq_range;
+
+	power_rule1 = &rule1->power_rule;
+	power_rule2 = &rule2->power_rule;
+	power_rule = &intersected_rule->power_rule;
+
+	freq_range->start_freq_khz = max(freq_range1->start_freq_khz,
+		freq_range2->start_freq_khz);
+	freq_range->end_freq_khz = min(freq_range1->end_freq_khz,
+		freq_range2->end_freq_khz);
+	freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz,
+		freq_range2->max_bandwidth_khz);
+
+	freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
+	if (freq_range->max_bandwidth_khz > freq_diff)
+		freq_range->max_bandwidth_khz = freq_diff;
+
+	power_rule->max_eirp = min(power_rule1->max_eirp,
+		power_rule2->max_eirp);
+	power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
+		power_rule2->max_antenna_gain);
+
+	intersected_rule->flags = (rule1->flags | rule2->flags);
+
+	if (!is_valid_reg_rule(intersected_rule))
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * regdom_intersect - do the intersection between two regulatory domains
+ * @rd1: first regulatory domain
+ * @rd2: second regulatory domain
+ *
+ * Use this function to get the intersection between two regulatory domains.
+ * Once completed we will mark the alpha2 for the rd as intersected, "98",
+ * as no one single alpha2 can represent this regulatory domain.
+ *
+ * Returns a pointer to the regulatory domain structure which will hold the
+ * resulting intersection of rules between rd1 and rd2. We will
+ * kzalloc() this structure for you.
+ */
+static struct ieee80211_regdomain *regdom_intersect(
+	const struct ieee80211_regdomain *rd1,
+	const struct ieee80211_regdomain *rd2)
+{
+	int r, size_of_regd;
+	unsigned int x, y;
+	unsigned int num_rules = 0, rule_idx = 0;
+	const struct ieee80211_reg_rule *rule1, *rule2;
+	struct ieee80211_reg_rule *intersected_rule;
+	struct ieee80211_regdomain *rd;
+	/* This is just a dummy holder to help us count */
+	struct ieee80211_reg_rule irule;
+
+	/* Uses the stack temporarily for counter arithmetic */
+	intersected_rule = &irule;
+
+	memset(intersected_rule, 0, sizeof(struct ieee80211_reg_rule));
+
+	if (!rd1 || !rd2)
+		return NULL;
+
+	/* First we get a count of the rules we'll need, then we actually
+	 * build them. This is to so we can malloc() and free() a
+	 * regdomain once. The reason we use reg_rules_intersect() here
+	 * is it will return -EINVAL if the rule computed makes no sense.
+	 * All rules that do check out OK are valid. */
+
+	for (x = 0; x < rd1->n_reg_rules; x++) {
+		rule1 = &rd1->reg_rules[x];
+		for (y = 0; y < rd2->n_reg_rules; y++) {
+			rule2 = &rd2->reg_rules[y];
+			if (!reg_rules_intersect(rule1, rule2,
+					intersected_rule))
+				num_rules++;
+			memset(intersected_rule, 0,
+					sizeof(struct ieee80211_reg_rule));
+		}
+	}
+
+	if (!num_rules)
+		return NULL;
+
+	size_of_regd = sizeof(struct ieee80211_regdomain) +
+		((num_rules + 1) * sizeof(struct ieee80211_reg_rule));
+
+	rd = kzalloc(size_of_regd, GFP_KERNEL);
+	if (!rd)
+		return NULL;
+
+	for (x = 0; x < rd1->n_reg_rules; x++) {
+		rule1 = &rd1->reg_rules[x];
+		for (y = 0; y < rd2->n_reg_rules; y++) {
+			rule2 = &rd2->reg_rules[y];
+			/* This time around instead of using the stack lets
+			 * write to the target rule directly saving ourselves
+			 * a memcpy() */
+			intersected_rule = &rd->reg_rules[rule_idx];
+			r = reg_rules_intersect(rule1, rule2,
+				intersected_rule);
+			/* No need to memset here the intersected rule here as
+			 * we're not using the stack anymore */
+			if (r)
+				continue;
+			rule_idx++;
+		}
+	}
+
+	if (rule_idx != num_rules) {
+		kfree(rd);
+		return NULL;
+	}
+
+	rd->n_reg_rules = num_rules;
+	rd->alpha2[0] = '9';
+	rd->alpha2[1] = '8';
+
+	return rd;
+}
+
 /* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may
  * want to just have the channel structure use these */
 static u32 map_regdom_flags(u32 rd_flags)
@@ -559,12 +816,23 @@
 		handle_channel(&sband->channels[i]);
 }
 
+static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
+{
+	if (!last_request)
+		return true;
+	if (setby == REGDOM_SET_BY_CORE &&
+		  wiphy->fw_handles_regulatory)
+		return true;
+	return false;
+}
+
 static void update_all_wiphy_regulatory(enum reg_set_by setby)
 {
 	struct cfg80211_registered_device *drv;
 
 	list_for_each_entry(drv, &cfg80211_drv_list, list)
-		wiphy_update_regulatory(&drv->wiphy, setby);
+		if (!ignore_reg_update(&drv->wiphy, setby))
+			wiphy_update_regulatory(&drv->wiphy, setby);
 }
 
 void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
@@ -578,78 +846,237 @@
 	}
 }
 
-/* Caller must hold &cfg80211_drv_mutex */
-int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
-		      const char *alpha2, struct ieee80211_regdomain *rd)
+/* Return value which can be used by ignore_request() to indicate
+ * it has been determined we should intersect two regulatory domains */
+#define REG_INTERSECT	1
+
+/* This has the logic which determines when a new request
+ * should be ignored. */
+static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
+			  const char *alpha2)
 {
-	struct regulatory_request *request;
-	char *rd_alpha2;
-	int r = 0;
-
-	r = ignore_request(wiphy, set_by, (char *) alpha2, rd);
-	if (r)
-		return r;
-
-	if (rd)
-		rd_alpha2 = rd->alpha2;
-	else
-		rd_alpha2 = (char *) alpha2;
+	/* All initial requests are respected */
+	if (!last_request)
+		return 0;
 
 	switch (set_by) {
+	case REGDOM_SET_BY_INIT:
+		return -EINVAL;
 	case REGDOM_SET_BY_CORE:
+		/*
+		 * Always respect new wireless core hints, should only happen
+		 * when updating the world regulatory domain at init.
+		 */
+		return 0;
 	case REGDOM_SET_BY_COUNTRY_IE:
+		if (unlikely(!is_an_alpha2(alpha2)))
+			return -EINVAL;
+		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
+			if (last_request->wiphy != wiphy) {
+				/*
+				 * Two cards with two APs claiming different
+				 * different Country IE alpha2s. We could
+				 * intersect them, but that seems unlikely
+				 * to be correct. Reject second one for now.
+				 */
+				if (!alpha2_equal(alpha2,
+						  cfg80211_regdomain->alpha2))
+					return -EOPNOTSUPP;
+				return -EALREADY;
+			}
+			/* Two consecutive Country IE hints on the same wiphy.
+			 * This should be picked up early by the driver/stack */
+			if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2,
+				  alpha2)))
+				return 0;
+			return -EALREADY;
+		}
+		return REG_INTERSECT;
 	case REGDOM_SET_BY_DRIVER:
+		if (last_request->initiator == REGDOM_SET_BY_DRIVER)
+			return -EALREADY;
+		return 0;
 	case REGDOM_SET_BY_USER:
-		request = kzalloc(sizeof(struct regulatory_request),
-			GFP_KERNEL);
-		if (!request)
-			return -ENOMEM;
-
-		request->alpha2[0] = rd_alpha2[0];
-		request->alpha2[1] = rd_alpha2[1];
-		request->initiator = set_by;
-		request->wiphy = wiphy;
-
-		list_add_tail(&request->list, &regulatory_requests);
-		if (rd)
-			break;
-		r = call_crda(alpha2);
-#ifndef CONFIG_WIRELESS_OLD_REGULATORY
-		if (r)
-			printk(KERN_ERR "cfg80211: Failed calling CRDA\n");
-#endif
-		break;
-	default:
-		r = -ENOTSUPP;
-		break;
+		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
+			return REG_INTERSECT;
+		/* If the user knows better the user should set the regdom
+		 * to their country before the IE is picked up */
+		if (last_request->initiator == REGDOM_SET_BY_USER &&
+			  last_request->intersect)
+			return -EOPNOTSUPP;
+		return 0;
 	}
 
-	return r;
+	return -EINVAL;
 }
 
-/* If rd is not NULL and if this call fails the caller must free it */
-int regulatory_hint(struct wiphy *wiphy, const char *alpha2,
-	struct ieee80211_regdomain *rd)
+/* Caller must hold &cfg80211_drv_mutex */
+int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
+			const char *alpha2,
+			u32 country_ie_checksum,
+			enum environment_cap env)
 {
-	int r;
-	BUG_ON(!rd && !alpha2);
+	struct regulatory_request *request;
+	bool intersect = false;
+	int r = 0;
+
+	r = ignore_request(wiphy, set_by, alpha2);
+
+	if (r == REG_INTERSECT)
+		intersect = true;
+	else if (r)
+		return r;
+
+	request = kzalloc(sizeof(struct regulatory_request),
+			  GFP_KERNEL);
+	if (!request)
+		return -ENOMEM;
+
+	request->alpha2[0] = alpha2[0];
+	request->alpha2[1] = alpha2[1];
+	request->initiator = set_by;
+	request->wiphy = wiphy;
+	request->intersect = intersect;
+	request->country_ie_checksum = country_ie_checksum;
+	request->country_ie_env = env;
+
+	kfree(last_request);
+	last_request = request;
+	/*
+	 * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
+	 * AND if CRDA is NOT present nothing will happen, if someone
+	 * wants to bother with 11d with OLD_REG you can add a timer.
+	 * If after x amount of time nothing happens you can call:
+	 *
+	 * return set_regdom(country_ie_regdomain);
+	 *
+	 * to intersect with the static rd
+	 */
+	return call_crda(alpha2);
+}
+
+void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
+{
+	BUG_ON(!alpha2);
 
 	mutex_lock(&cfg80211_drv_mutex);
-
-	r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, rd);
-	if (r || !rd)
-		goto unlock_and_exit;
-
-	/* If the driver passed a regulatory domain we skipped asking
-	 * userspace for one so we can now go ahead and set it */
-	r = set_regdom(rd);
-
-unlock_and_exit:
+	__regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, 0, ENVIRON_ANY);
 	mutex_unlock(&cfg80211_drv_mutex);
-	return r;
 }
 EXPORT_SYMBOL(regulatory_hint);
 
+static bool reg_same_country_ie_hint(struct wiphy *wiphy,
+			u32 country_ie_checksum)
+{
+	if (!last_request->wiphy)
+		return false;
+	if (likely(last_request->wiphy != wiphy))
+		return !country_ie_integrity_changes(country_ie_checksum);
+	/* We should not have let these through at this point, they
+	 * should have been picked up earlier by the first alpha2 check
+	 * on the device */
+	if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum)))
+		return true;
+	return false;
+}
+
+void regulatory_hint_11d(struct wiphy *wiphy,
+			u8 *country_ie,
+			u8 country_ie_len)
+{
+	struct ieee80211_regdomain *rd = NULL;
+	char alpha2[2];
+	u32 checksum = 0;
+	enum environment_cap env = ENVIRON_ANY;
+
+	if (!last_request)
+		return;
+
+	mutex_lock(&cfg80211_drv_mutex);
+
+	/* IE len must be evenly divisible by 2 */
+	if (country_ie_len & 0x01)
+		goto out;
+
+	if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
+		goto out;
+
+	/* Pending country IE processing, this can happen after we
+	 * call CRDA and wait for a response if a beacon was received before
+	 * we were able to process the last regulatory_hint_11d() call */
+	if (country_ie_regdomain)
+		goto out;
+
+	alpha2[0] = country_ie[0];
+	alpha2[1] = country_ie[1];
+
+	if (country_ie[2] == 'I')
+		env = ENVIRON_INDOOR;
+	else if (country_ie[2] == 'O')
+		env = ENVIRON_OUTDOOR;
+
+	/* We will run this for *every* beacon processed for the BSSID, so
+	 * we optimize an early check to exit out early if we don't have to
+	 * do anything */
+	if (likely(last_request->wiphy)) {
+		struct cfg80211_registered_device *drv_last_ie;
+
+		drv_last_ie = wiphy_to_dev(last_request->wiphy);
+
+		/* Lets keep this simple -- we trust the first AP
+		 * after we intersect with CRDA */
+		if (likely(last_request->wiphy == wiphy)) {
+			/* Ignore IEs coming in on this wiphy with
+			 * the same alpha2 and environment cap */
+			if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
+				  alpha2) &&
+				  env == drv_last_ie->env)) {
+				goto out;
+			}
+			/* the wiphy moved on to another BSSID or the AP
+			 * was reconfigured. XXX: We need to deal with the
+			 * case where the user suspends and goes to goes
+			 * to another country, and then gets IEs from an
+			 * AP with different settings */
+			goto out;
+		} else {
+			/* Ignore IEs coming in on two separate wiphys with
+			 * the same alpha2 and environment cap */
+			if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
+				  alpha2) &&
+				  env == drv_last_ie->env)) {
+				goto out;
+			}
+			/* We could potentially intersect though */
+			goto out;
+		}
+	}
+
+	rd = country_ie_2_rd(country_ie, country_ie_len, &checksum);
+	if (!rd)
+		goto out;
+
+	/* This will not happen right now but we leave it here for the
+	 * the future when we want to add suspend/resume support and having
+	 * the user move to another country after doing so, or having the user
+	 * move to another AP. Right now we just trust the first AP. This is why
+	 * this is marked as likley(). If we hit this before we add this support
+	 * we want to be informed of it as it would indicate a mistake in the
+	 * current design  */
+	if (likely(WARN_ON(reg_same_country_ie_hint(wiphy, checksum))))
+		goto out;
+
+	/* We keep this around for when CRDA comes back with a response so
+	 * we can intersect with that */
+	country_ie_regdomain = rd;
+
+	__regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE,
+		country_ie_regdomain->alpha2, checksum, env);
+
+out:
+	mutex_unlock(&cfg80211_drv_mutex);
+}
+EXPORT_SYMBOL(regulatory_hint_11d);
 
 static void print_rd_rules(const struct ieee80211_regdomain *rd)
 {
@@ -689,7 +1116,25 @@
 static void print_regdomain(const struct ieee80211_regdomain *rd)
 {
 
-	if (is_world_regdom(rd->alpha2))
+	if (is_intersected_alpha2(rd->alpha2)) {
+		struct wiphy *wiphy = NULL;
+		struct cfg80211_registered_device *drv;
+
+		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
+			if (last_request->wiphy) {
+				wiphy = last_request->wiphy;
+				drv = wiphy_to_dev(wiphy);
+				printk(KERN_INFO "cfg80211: Current regulatory "
+					"domain updated by AP to: %c%c\n",
+					drv->country_ie_alpha2[0],
+					drv->country_ie_alpha2[1]);
+			} else
+				printk(KERN_INFO "cfg80211: Current regulatory "
+					"domain intersected: \n");
+		} else
+				printk(KERN_INFO "cfg80211: Current regulatory "
+					"intersected: \n");
+	} else if (is_world_regdom(rd->alpha2))
 		printk(KERN_INFO "cfg80211: World regulatory "
 			"domain updated:\n");
 	else {
@@ -705,21 +1150,50 @@
 	print_rd_rules(rd);
 }
 
-void print_regdomain_info(const struct ieee80211_regdomain *rd)
+static void print_regdomain_info(const struct ieee80211_regdomain *rd)
 {
 	printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n",
 		rd->alpha2[0], rd->alpha2[1]);
 	print_rd_rules(rd);
 }
 
+#ifdef CONFIG_CFG80211_REG_DEBUG
+static void reg_country_ie_process_debug(
+	const struct ieee80211_regdomain *rd,
+	const struct ieee80211_regdomain *country_ie_regdomain,
+	const struct ieee80211_regdomain *intersected_rd)
+{
+	printk(KERN_DEBUG "cfg80211: Received country IE:\n");
+	print_regdomain_info(country_ie_regdomain);
+	printk(KERN_DEBUG "cfg80211: CRDA thinks this should applied:\n");
+	print_regdomain_info(rd);
+	if (intersected_rd) {
+		printk(KERN_DEBUG "cfg80211: We intersect both of these "
+			"and get:\n");
+		print_regdomain_info(rd);
+		return;
+	}
+	printk(KERN_DEBUG "cfg80211: Intersection between both failed\n");
+}
+#else
+static inline void reg_country_ie_process_debug(
+	const struct ieee80211_regdomain *rd,
+	const struct ieee80211_regdomain *country_ie_regdomain,
+	const struct ieee80211_regdomain *intersected_rd)
+{
+}
+#endif
+
+/* Takes ownership of rd only if it doesn't fail */
 static int __set_regdom(const struct ieee80211_regdomain *rd)
 {
-	struct regulatory_request *request = NULL;
-
+	const struct ieee80211_regdomain *intersected_rd = NULL;
+	struct cfg80211_registered_device *drv = NULL;
+	struct wiphy *wiphy = NULL;
 	/* Some basic sanity checks first */
 
 	if (is_world_regdom(rd->alpha2)) {
-		if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request)))
+		if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
 			return -EINVAL;
 		update_world_regdomain(rd);
 		return 0;
@@ -729,45 +1203,102 @@
 			!is_unknown_alpha2(rd->alpha2))
 		return -EINVAL;
 
-	if (list_empty(&regulatory_requests))
+	if (!last_request)
 		return -EINVAL;
 
-	/* allow overriding the static definitions if CRDA is present */
-	if (!is_old_static_regdom(cfg80211_regdomain) &&
-	    !regdom_changed(rd->alpha2))
-		return -EINVAL;
+	/* Lets only bother proceeding on the same alpha2 if the current
+	 * rd is non static (it means CRDA was present and was used last)
+	 * and the pending request came in from a country IE */
+	if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
+		/* If someone else asked us to change the rd lets only bother
+		 * checking if the alpha2 changes if CRDA was already called */
+		if (!is_old_static_regdom(cfg80211_regdomain) &&
+		    !regdom_changed(rd->alpha2))
+			return -EINVAL;
+	}
+
+	wiphy = last_request->wiphy;
 
 	/* Now lets set the regulatory domain, update all driver channels
 	 * and finally inform them of what we have done, in case they want
 	 * to review or adjust their own settings based on their own
 	 * internal EEPROM data */
 
-	if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request)))
+	if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
 		return -EINVAL;
 
-	reset_regdomains();
-
-	/* Country IE parsing coming soon */
-	switch (request->initiator) {
-	case REGDOM_SET_BY_CORE:
-	case REGDOM_SET_BY_DRIVER:
-	case REGDOM_SET_BY_USER:
-		if (!is_valid_rd(rd)) {
-			printk(KERN_ERR "cfg80211: Invalid "
-				"regulatory domain detected:\n");
-			print_regdomain_info(rd);
-			return -EINVAL;
-		}
-		break;
-	case REGDOM_SET_BY_COUNTRY_IE: /* Not yet */
-		WARN_ON(1);
-	default:
-		return -EOPNOTSUPP;
+	if (!is_valid_rd(rd)) {
+		printk(KERN_ERR "cfg80211: Invalid "
+			"regulatory domain detected:\n");
+		print_regdomain_info(rd);
+		return -EINVAL;
 	}
 
-	/* Tada! */
-	cfg80211_regdomain = rd;
-	request->granted = 1;
+	if (!last_request->intersect) {
+		reset_regdomains();
+		cfg80211_regdomain = rd;
+		return 0;
+	}
+
+	/* Intersection requires a bit more work */
+
+	if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
+
+		intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
+		if (!intersected_rd)
+			return -EINVAL;
+
+		/* We can trash what CRDA provided now */
+		kfree(rd);
+		rd = NULL;
+
+		reset_regdomains();
+		cfg80211_regdomain = intersected_rd;
+
+		return 0;
+	}
+
+	/*
+	 * Country IE requests are handled a bit differently, we intersect
+	 * the country IE rd with what CRDA believes that country should have
+	 */
+
+	BUG_ON(!country_ie_regdomain);
+
+	if (rd != country_ie_regdomain) {
+		/* Intersect what CRDA returned and our what we
+		 * had built from the Country IE received */
+
+		intersected_rd = regdom_intersect(rd, country_ie_regdomain);
+
+		reg_country_ie_process_debug(rd, country_ie_regdomain,
+			intersected_rd);
+
+		kfree(country_ie_regdomain);
+		country_ie_regdomain = NULL;
+	} else {
+		/* This would happen when CRDA was not present and
+		 * OLD_REGULATORY was enabled. We intersect our Country
+		 * IE rd and what was set on cfg80211 originally */
+		intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
+	}
+
+	if (!intersected_rd)
+		return -EINVAL;
+
+	drv = wiphy_to_dev(wiphy);
+
+	drv->country_ie_alpha2[0] = rd->alpha2[0];
+	drv->country_ie_alpha2[1] = rd->alpha2[1];
+	drv->env = last_request->country_ie_env;
+
+	BUG_ON(intersected_rd == rd);
+
+	kfree(rd);
+	rd = NULL;
+
+	reset_regdomains();
+	cfg80211_regdomain = intersected_rd;
 
 	return 0;
 }
@@ -775,52 +1306,41 @@
 
 /* Use this call to set the current regulatory domain. Conflicts with
  * multiple drivers can be ironed out later. Caller must've already
- * kmalloc'd the rd structure. If this calls fails you should kfree()
- * the passed rd. Caller must hold cfg80211_drv_mutex */
+ * kmalloc'd the rd structure. Caller must hold cfg80211_drv_mutex */
 int set_regdom(const struct ieee80211_regdomain *rd)
 {
-	struct regulatory_request *this_request = NULL, *prev_request = NULL;
 	int r;
 
-	if (!list_empty(&regulatory_requests))
-		prev_request = list_first_entry(&regulatory_requests,
-			struct regulatory_request, list);
-
 	/* Note that this doesn't update the wiphys, this is done below */
 	r = __set_regdom(rd);
-	if (r)
+	if (r) {
+		kfree(rd);
 		return r;
-
-	BUG_ON((!__reg_is_valid_request(rd->alpha2, &this_request)));
-
-	/* The initial standard core update of the world regulatory domain, no
-	 * need to keep that request info around if it didn't fail. */
-	if (is_world_regdom(rd->alpha2) &&
-			this_request->initiator == REGDOM_SET_BY_CORE &&
-			this_request->granted) {
-		list_del(&this_request->list);
-		kfree(this_request);
-		this_request = NULL;
-	}
-
-	/* Remove old requests, we only leave behind the last one */
-	if (prev_request) {
-		list_del(&prev_request->list);
-		kfree(prev_request);
-		prev_request = NULL;
 	}
 
 	/* This would make this whole thing pointless */
-	BUG_ON(rd != cfg80211_regdomain);
+	if (!last_request->intersect)
+		BUG_ON(rd != cfg80211_regdomain);
 
 	/* update all wiphys now with the new established regulatory domain */
-	update_all_wiphy_regulatory(this_request->initiator);
+	update_all_wiphy_regulatory(last_request->initiator);
 
-	print_regdomain(rd);
+	print_regdomain(cfg80211_regdomain);
 
 	return r;
 }
 
+/* Caller must hold cfg80211_drv_mutex */
+void reg_device_remove(struct wiphy *wiphy)
+{
+	if (!last_request || !last_request->wiphy)
+		return;
+	if (last_request->wiphy != wiphy)
+		return;
+	last_request->wiphy = NULL;
+	last_request->country_ie_env = ENVIRON_ANY;
+}
+
 int regulatory_init(void)
 {
 	int err;
@@ -838,13 +1358,13 @@
 	 * you have CRDA you get it updated, otherwise you get
 	 * stuck with the static values. We ignore "EU" code as
 	 * that is not a valid ISO / IEC 3166 alpha2 */
-	if (ieee80211_regdom[0] != 'E' && ieee80211_regdom[1] != 'U')
+	if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U')
 		err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
-					ieee80211_regdom, NULL);
+					ieee80211_regdom, 0, ENVIRON_ANY);
 #else
 	cfg80211_regdomain = cfg80211_world_regdom;
 
-	err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", NULL);
+	err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", 0, ENVIRON_ANY);
 	if (err)
 		printk(KERN_ERR "cfg80211: calling CRDA failed - "
 		       "unable to update world regulatory domain, "
@@ -856,16 +1376,15 @@
 
 void regulatory_exit(void)
 {
-	struct regulatory_request *req, *req_tmp;
-
 	mutex_lock(&cfg80211_drv_mutex);
 
 	reset_regdomains();
 
-	list_for_each_entry_safe(req, req_tmp, &regulatory_requests, list) {
-		list_del(&req->list);
-		kfree(req);
-	}
+	kfree(country_ie_regdomain);
+	country_ie_regdomain = NULL;
+
+	kfree(last_request);
+
 	platform_device_unregister(reg_pdev);
 
 	mutex_unlock(&cfg80211_drv_mutex);
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index a333628..a76ea3f 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -1,13 +1,44 @@
 #ifndef __NET_WIRELESS_REG_H
 #define __NET_WIRELESS_REG_H
 
-extern struct mutex cfg80211_reg_mutex;
 bool is_world_regdom(const char *alpha2);
 bool reg_is_valid_request(const char *alpha2);
 
+void reg_device_remove(struct wiphy *wiphy);
+
 int regulatory_init(void);
 void regulatory_exit(void);
 
 int set_regdom(const struct ieee80211_regdomain *rd);
 
+enum environment_cap {
+	ENVIRON_ANY,
+	ENVIRON_INDOOR,
+	ENVIRON_OUTDOOR,
+};
+
+
+/**
+ * __regulatory_hint - hint to the wireless core a regulatory domain
+ * @wiphy: if the hint comes from country information from an AP, this
+ *	is required to be set to the wiphy that received the information
+ * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain
+ *	should be in.
+ * @country_ie_checksum: checksum of processed country IE, set this to 0
+ * 	if the hint did not come from a country IE
+ * @country_ie_env: the environment the IE told us we are in, %ENVIRON_*
+ *
+ * The Wireless subsystem can use this function to hint to the wireless core
+ * what it believes should be the current regulatory domain by giving it an
+ * ISO/IEC 3166 alpha2 country code it knows its regulatory domain should be
+ * in.
+ *
+ * Returns zero if all went fine, %-EALREADY if a regulatory domain had
+ * already been set or other standard error codes.
+ *
+ */
+extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
+			     const char *alpha2, u32 country_ie_checksum,
+			     enum environment_cap country_ie_env);
+
 #endif  /* __NET_WIRELESS_REG_H */
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 29f820e..79a3828 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -23,25 +23,20 @@
 	return container_of(dev, struct cfg80211_registered_device, wiphy.dev);
 }
 
-static ssize_t _show_index(struct device *dev, struct device_attribute *attr,
-			   char *buf)
-{
-	return sprintf(buf, "%d\n", dev_to_rdev(dev)->idx);
+#define SHOW_FMT(name, fmt, member)					\
+static ssize_t name ## _show(struct device *dev,			\
+			      struct device_attribute *attr,		\
+			      char *buf)				\
+{									\
+	return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member);	\
 }
 
-static ssize_t _show_permaddr(struct device *dev,
-			      struct device_attribute *attr,
-			      char *buf)
-{
-	unsigned char *addr = dev_to_rdev(dev)->wiphy.perm_addr;
-
-	return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-		       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
-}
+SHOW_FMT(index, "%d", idx);
+SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
 
 static struct device_attribute ieee80211_dev_attrs[] = {
-	__ATTR(index, S_IRUGO, _show_index, NULL),
-	__ATTR(macaddress, S_IRUGO, _show_permaddr, NULL),
+	__ATTR_RO(index),
+	__ATTR_RO(macaddress),
 	{}
 };
 
diff --git a/net/wireless/util.c b/net/wireless/util.c
index f544246..e76cc28 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -7,6 +7,25 @@
 #include <asm/bitops.h>
 #include "core.h"
 
+struct ieee80211_rate *
+ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
+			    u64 basic_rates, int bitrate)
+{
+	struct ieee80211_rate *result = &sband->bitrates[0];
+	int i;
+
+	for (i = 0; i < sband->n_bitrates; i++) {
+		if (!(basic_rates & BIT(i)))
+			continue;
+		if (sband->bitrates[i].bitrate > bitrate)
+			continue;
+		result = &sband->bitrates[i];
+	}
+
+	return result;
+}
+EXPORT_SYMBOL(ieee80211_get_response_rate);
+
 int ieee80211_channel_to_frequency(int chan)
 {
 	if (chan < 14)
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
new file mode 100644
index 0000000..58e489f
--- /dev/null
+++ b/net/wireless/wext-compat.c
@@ -0,0 +1,139 @@
+/*
+ * cfg80211 - wext compat code
+ *
+ * This is temporary code until all wireless functionality is migrated
+ * into cfg80211, when that happens all the exports here go away and
+ * we directly assign the wireless handlers of wireless interfaces.
+ *
+ * Copyright 2008	Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include <linux/wireless.h>
+#include <linux/nl80211.h>
+#include <net/iw_handler.h>
+#include <net/wireless.h>
+#include <net/cfg80211.h>
+#include "core.h"
+
+int cfg80211_wext_giwname(struct net_device *dev,
+			  struct iw_request_info *info,
+			  char *name, char *extra)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct ieee80211_supported_band *sband;
+	bool is_ht = false, is_a = false, is_b = false, is_g = false;
+
+	if (!wdev)
+		return -EOPNOTSUPP;
+
+	sband = wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
+	if (sband) {
+		is_a = true;
+		is_ht |= sband->ht_cap.ht_supported;
+	}
+
+	sband = wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
+	if (sband) {
+		int i;
+		/* Check for mandatory rates */
+		for (i = 0; i < sband->n_bitrates; i++) {
+			if (sband->bitrates[i].bitrate == 10)
+				is_b = true;
+			if (sband->bitrates[i].bitrate == 60)
+				is_g = true;
+		}
+		is_ht |= sband->ht_cap.ht_supported;
+	}
+
+	strcpy(name, "IEEE 802.11");
+	if (is_a)
+		strcat(name, "a");
+	if (is_b)
+		strcat(name, "b");
+	if (is_g)
+		strcat(name, "g");
+	if (is_ht)
+		strcat(name, "n");
+
+	return 0;
+}
+EXPORT_SYMBOL(cfg80211_wext_giwname);
+
+int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
+			  u32 *mode, char *extra)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev;
+	struct vif_params vifparams;
+	enum nl80211_iftype type;
+
+	if (!wdev)
+		return -EOPNOTSUPP;
+
+	rdev = wiphy_to_dev(wdev->wiphy);
+
+	if (!rdev->ops->change_virtual_intf)
+		return -EOPNOTSUPP;
+
+	/* don't support changing VLANs, you just re-create them */
+	if (wdev->iftype == NL80211_IFTYPE_AP_VLAN)
+		return -EOPNOTSUPP;
+
+	switch (*mode) {
+	case IW_MODE_INFRA:
+		type = NL80211_IFTYPE_STATION;
+		break;
+	case IW_MODE_ADHOC:
+		type = NL80211_IFTYPE_ADHOC;
+		break;
+	case IW_MODE_REPEAT:
+		type = NL80211_IFTYPE_WDS;
+		break;
+	case IW_MODE_MONITOR:
+		type = NL80211_IFTYPE_MONITOR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	memset(&vifparams, 0, sizeof(vifparams));
+
+	return rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type,
+					      NULL, &vifparams);
+}
+EXPORT_SYMBOL(cfg80211_wext_siwmode);
+
+int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
+			  u32 *mode, char *extra)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+	if (!wdev)
+		return -EOPNOTSUPP;
+
+	switch (wdev->iftype) {
+	case NL80211_IFTYPE_AP:
+		*mode = IW_MODE_MASTER;
+		break;
+	case NL80211_IFTYPE_STATION:
+		*mode = IW_MODE_INFRA;
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		*mode = IW_MODE_ADHOC;
+		break;
+	case NL80211_IFTYPE_MONITOR:
+		*mode = IW_MODE_MONITOR;
+		break;
+	case NL80211_IFTYPE_WDS:
+		*mode = IW_MODE_REPEAT;
+		break;
+	case NL80211_IFTYPE_AP_VLAN:
+		*mode = IW_MODE_SECOND;		/* FIXME */
+		break;
+	default:
+		*mode = IW_MODE_AUTO;
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(cfg80211_wext_giwmode);
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index d98ffb7..e49a2d1 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -64,7 +64,7 @@
  *	o Remove spy_offset from struct iw_handler_def
  *	o Start deprecating dev->get_wireless_stats, output a warning
  *	o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
- *	o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
+ *	o Don't lose INVALID/DBM flags when clearing UPDATED flags (iwstats)
  *
  * v8 - 17.02.06 - Jean II
  *	o RtNetlink requests support (SET/GET)
diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
index 6ebda25..a5d3416 100644
--- a/net/x25/sysctl_net_x25.c
+++ b/net/x25/sysctl_net_x25.c
@@ -24,8 +24,8 @@
 		.data =		&sysctl_x25_restart_request_timeout,
 		.maxlen =	sizeof(int),
 		.mode =		0644,
-		.proc_handler =	&proc_dointvec_minmax,
-		.strategy =	&sysctl_intvec,
+		.proc_handler =	proc_dointvec_minmax,
+		.strategy =	sysctl_intvec,
 		.extra1 =	&min_timer,
 		.extra2 =	&max_timer,
 	},
@@ -35,8 +35,8 @@
 		.data =		&sysctl_x25_call_request_timeout,
 		.maxlen =	sizeof(int),
 		.mode =		0644,
-		.proc_handler =	&proc_dointvec_minmax,
-		.strategy =	&sysctl_intvec,
+		.proc_handler =	proc_dointvec_minmax,
+		.strategy =	sysctl_intvec,
 		.extra1 =	&min_timer,
 		.extra2 =	&max_timer,
 	},
@@ -46,8 +46,8 @@
 		.data =		&sysctl_x25_reset_request_timeout,
 		.maxlen =	sizeof(int),
 		.mode =		0644,
-		.proc_handler =	&proc_dointvec_minmax,
-		.strategy =	&sysctl_intvec,
+		.proc_handler =	proc_dointvec_minmax,
+		.strategy =	sysctl_intvec,
 		.extra1 =	&min_timer,
 		.extra2 =	&max_timer,
 	},
@@ -57,8 +57,8 @@
 		.data =		&sysctl_x25_clear_request_timeout,
 		.maxlen =	sizeof(int),
 		.mode =		0644,
-		.proc_handler =	&proc_dointvec_minmax,
-		.strategy =	&sysctl_intvec,
+		.proc_handler =	proc_dointvec_minmax,
+		.strategy =	sysctl_intvec,
 		.extra1 =	&min_timer,
 		.extra2 =	&max_timer,
 	},
@@ -68,8 +68,8 @@
 		.data =		&sysctl_x25_ack_holdback_timeout,
 		.maxlen =	sizeof(int),
 		.mode =		0644,
-		.proc_handler =	&proc_dointvec_minmax,
-		.strategy =	&sysctl_intvec,
+		.proc_handler =	proc_dointvec_minmax,
+		.strategy =	sysctl_intvec,
 		.extra1 =	&min_timer,
 		.extra2 =	&max_timer,
 	},
@@ -79,7 +79,7 @@
 		.data = 	&sysctl_x25_forward,
 		.maxlen = 	sizeof(int),
 		.mode = 	0644,
-		.proc_handler = &proc_dointvec,
+		.proc_handler = proc_dointvec,
 	},
 	{ 0, },
 };
diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile
index 0f439a7..c631047 100644
--- a/net/xfrm/Makefile
+++ b/net/xfrm/Makefile
@@ -3,8 +3,8 @@
 #
 
 obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \
-		      xfrm_input.o xfrm_output.o xfrm_algo.o
+		      xfrm_input.o xfrm_output.o xfrm_algo.o \
+		      xfrm_sysctl.o
 obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o
 obj-$(CONFIG_XFRM_USER) += xfrm_user.o
 obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o
-
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 7527940..b4a1317 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -104,6 +104,7 @@
 
 int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 {
+	struct net *net = dev_net(skb->dev);
 	int err;
 	__be32 seq;
 	struct xfrm_state *x;
@@ -127,7 +128,7 @@
 
 		sp = secpath_dup(skb->sp);
 		if (!sp) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
 			goto drop;
 		}
 		if (skb->sp)
@@ -141,19 +142,19 @@
 
 	seq = 0;
 	if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
-		XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR);
+		XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
 		goto drop;
 	}
 
 	do {
 		if (skb->sp->len == XFRM_MAX_DEPTH) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
 			goto drop;
 		}
 
-		x = xfrm_state_lookup(daddr, spi, nexthdr, family);
+		x = xfrm_state_lookup(net, daddr, spi, nexthdr, family);
 		if (x == NULL) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
 			xfrm_audit_state_notfound(skb, family, spi, seq);
 			goto drop;
 		}
@@ -162,22 +163,22 @@
 
 		spin_lock(&x->lock);
 		if (unlikely(x->km.state != XFRM_STATE_VALID)) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEINVALID);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEINVALID);
 			goto drop_unlock;
 		}
 
 		if ((x->encap ? x->encap->encap_type : 0) != encap_type) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMISMATCH);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
 			goto drop_unlock;
 		}
 
 		if (x->props.replay_window && xfrm_replay_check(x, skb, seq)) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINSTATESEQERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
 			goto drop_unlock;
 		}
 
 		if (xfrm_state_check_expire(x)) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEEXPIRED);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEEXPIRED);
 			goto drop_unlock;
 		}
 
@@ -198,7 +199,7 @@
 							 x->type->proto);
 				x->stats.integrity_failed++;
 			}
-			XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEPROTOERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
 			goto drop_unlock;
 		}
 
@@ -224,7 +225,7 @@
 		}
 
 		if (inner_mode->input(x, skb)) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMODEERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
 			goto drop;
 		}
 
@@ -242,7 +243,7 @@
 
 		err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
 		if (err < 0) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
 			goto drop;
 		}
 	} while (!err);
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index dc50f1e..c235597 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -41,6 +41,7 @@
 {
 	struct dst_entry *dst = skb->dst;
 	struct xfrm_state *x = dst->xfrm;
+	struct net *net = xs_net(x);
 
 	if (err <= 0)
 		goto resume;
@@ -48,33 +49,33 @@
 	do {
 		err = xfrm_state_check_space(x, skb);
 		if (err) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMOUTERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
 			goto error_nolock;
 		}
 
 		err = x->outer_mode->output(x, skb);
 		if (err) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATEMODEERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
 			goto error_nolock;
 		}
 
 		spin_lock_bh(&x->lock);
 		err = xfrm_state_check_expire(x);
 		if (err) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATEEXPIRED);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEEXPIRED);
 			goto error;
 		}
 
 		if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
 			XFRM_SKB_CB(skb)->seq.output = ++x->replay.oseq;
 			if (unlikely(x->replay.oseq == 0)) {
-				XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATESEQERROR);
+				XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATESEQERROR);
 				x->replay.oseq--;
 				xfrm_audit_state_replay_overflow(x, skb);
 				err = -EOVERFLOW;
 				goto error;
 			}
-			if (xfrm_aevent_is_on())
+			if (xfrm_aevent_is_on(net))
 				xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 		}
 
@@ -89,12 +90,12 @@
 
 resume:
 		if (err) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATEPROTOERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR);
 			goto error_nolock;
 		}
 
 		if (!(skb->dst = dst_pop(dst))) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMOUTERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
 			err = -EHOSTUNREACH;
 			goto error_nolock;
 		}
@@ -178,6 +179,7 @@
 
 int xfrm_output(struct sk_buff *skb)
 {
+	struct net *net = dev_net(skb->dst->dev);
 	int err;
 
 	if (skb_is_gso(skb))
@@ -186,7 +188,7 @@
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		err = skb_checksum_help(skb);
 		if (err) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMOUTERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
 			kfree_skb(skb);
 			return err;
 		}
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index fb216c9..9c068ab 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -34,28 +34,16 @@
 
 #include "xfrm_hash.h"
 
-int sysctl_xfrm_larval_drop __read_mostly = 1;
-
-#ifdef CONFIG_XFRM_STATISTICS
-DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly;
-EXPORT_SYMBOL(xfrm_statistics);
-#endif
-
 DEFINE_MUTEX(xfrm_cfg_mutex);
 EXPORT_SYMBOL(xfrm_cfg_mutex);
 
 static DEFINE_RWLOCK(xfrm_policy_lock);
 
-static struct list_head xfrm_policy_all;
-unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
-EXPORT_SYMBOL(xfrm_policy_count);
-
 static DEFINE_RWLOCK(xfrm_policy_afinfo_lock);
 static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO];
 
 static struct kmem_cache *xfrm_dst_cache __read_mostly;
 
-static struct work_struct xfrm_policy_gc_work;
 static HLIST_HEAD(xfrm_policy_gc_list);
 static DEFINE_SPINLOCK(xfrm_policy_gc_lock);
 
@@ -63,6 +51,9 @@
 static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
 static void xfrm_init_pmtu(struct dst_entry *dst);
 
+static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
+						int dir);
+
 static inline int
 __xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl)
 {
@@ -97,7 +88,7 @@
 	return 0;
 }
 
-static inline struct dst_entry *__xfrm_dst_lookup(int tos,
+static inline struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos,
 						  xfrm_address_t *saddr,
 						  xfrm_address_t *daddr,
 						  int family)
@@ -109,7 +100,7 @@
 	if (unlikely(afinfo == NULL))
 		return ERR_PTR(-EAFNOSUPPORT);
 
-	dst = afinfo->dst_lookup(tos, saddr, daddr);
+	dst = afinfo->dst_lookup(net, tos, saddr, daddr);
 
 	xfrm_policy_put_afinfo(afinfo);
 
@@ -121,6 +112,7 @@
 						xfrm_address_t *prev_daddr,
 						int family)
 {
+	struct net *net = xs_net(x);
 	xfrm_address_t *saddr = &x->props.saddr;
 	xfrm_address_t *daddr = &x->id.daddr;
 	struct dst_entry *dst;
@@ -134,7 +126,7 @@
 		daddr = x->coaddr;
 	}
 
-	dst = __xfrm_dst_lookup(tos, saddr, daddr, family);
+	dst = __xfrm_dst_lookup(net, tos, saddr, daddr, family);
 
 	if (!IS_ERR(dst)) {
 		if (prev_saddr != saddr)
@@ -229,13 +221,14 @@
  * SPD calls.
  */
 
-struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp)
+struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp)
 {
 	struct xfrm_policy *policy;
 
 	policy = kzalloc(sizeof(struct xfrm_policy), gfp);
 
 	if (policy) {
+		write_pnet(&policy->xp_net, net);
 		INIT_LIST_HEAD(&policy->walk.all);
 		INIT_HLIST_NODE(&policy->bydst);
 		INIT_HLIST_NODE(&policy->byidx);
@@ -296,6 +289,7 @@
 	hlist_for_each_entry_safe(policy, entry, tmp, &gc_list, bydst)
 		xfrm_policy_gc_kill(policy);
 }
+static DECLARE_WORK(xfrm_policy_gc_work, xfrm_policy_gc_task);
 
 /* Rule must be locked. Release descentant resources, announce
  * entry dead. The rule must be unlinked from lists to the moment.
@@ -322,38 +316,29 @@
 	schedule_work(&xfrm_policy_gc_work);
 }
 
-struct xfrm_policy_hash {
-	struct hlist_head	*table;
-	unsigned int		hmask;
-};
-
-static struct hlist_head xfrm_policy_inexact[XFRM_POLICY_MAX*2];
-static struct xfrm_policy_hash xfrm_policy_bydst[XFRM_POLICY_MAX*2] __read_mostly;
-static struct hlist_head *xfrm_policy_byidx __read_mostly;
-static unsigned int xfrm_idx_hmask __read_mostly;
 static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024;
 
-static inline unsigned int idx_hash(u32 index)
+static inline unsigned int idx_hash(struct net *net, u32 index)
 {
-	return __idx_hash(index, xfrm_idx_hmask);
+	return __idx_hash(index, net->xfrm.policy_idx_hmask);
 }
 
-static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir)
+static struct hlist_head *policy_hash_bysel(struct net *net, struct xfrm_selector *sel, unsigned short family, int dir)
 {
-	unsigned int hmask = xfrm_policy_bydst[dir].hmask;
+	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
 	unsigned int hash = __sel_hash(sel, family, hmask);
 
 	return (hash == hmask + 1 ?
-		&xfrm_policy_inexact[dir] :
-		xfrm_policy_bydst[dir].table + hash);
+		&net->xfrm.policy_inexact[dir] :
+		net->xfrm.policy_bydst[dir].table + hash);
 }
 
-static struct hlist_head *policy_hash_direct(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, int dir)
+static struct hlist_head *policy_hash_direct(struct net *net, xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, int dir)
 {
-	unsigned int hmask = xfrm_policy_bydst[dir].hmask;
+	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
 	unsigned int hash = __addr_hash(daddr, saddr, family, hmask);
 
-	return xfrm_policy_bydst[dir].table + hash;
+	return net->xfrm.policy_bydst[dir].table + hash;
 }
 
 static void xfrm_dst_hash_transfer(struct hlist_head *list,
@@ -408,12 +393,12 @@
 	return ((old_hmask + 1) << 1) - 1;
 }
 
-static void xfrm_bydst_resize(int dir)
+static void xfrm_bydst_resize(struct net *net, int dir)
 {
-	unsigned int hmask = xfrm_policy_bydst[dir].hmask;
+	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
 	unsigned int nhashmask = xfrm_new_hash_mask(hmask);
 	unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
-	struct hlist_head *odst = xfrm_policy_bydst[dir].table;
+	struct hlist_head *odst = net->xfrm.policy_bydst[dir].table;
 	struct hlist_head *ndst = xfrm_hash_alloc(nsize);
 	int i;
 
@@ -425,20 +410,20 @@
 	for (i = hmask; i >= 0; i--)
 		xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
 
-	xfrm_policy_bydst[dir].table = ndst;
-	xfrm_policy_bydst[dir].hmask = nhashmask;
+	net->xfrm.policy_bydst[dir].table = ndst;
+	net->xfrm.policy_bydst[dir].hmask = nhashmask;
 
 	write_unlock_bh(&xfrm_policy_lock);
 
 	xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
 }
 
-static void xfrm_byidx_resize(int total)
+static void xfrm_byidx_resize(struct net *net, int total)
 {
-	unsigned int hmask = xfrm_idx_hmask;
+	unsigned int hmask = net->xfrm.policy_idx_hmask;
 	unsigned int nhashmask = xfrm_new_hash_mask(hmask);
 	unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
-	struct hlist_head *oidx = xfrm_policy_byidx;
+	struct hlist_head *oidx = net->xfrm.policy_byidx;
 	struct hlist_head *nidx = xfrm_hash_alloc(nsize);
 	int i;
 
@@ -450,18 +435,18 @@
 	for (i = hmask; i >= 0; i--)
 		xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
 
-	xfrm_policy_byidx = nidx;
-	xfrm_idx_hmask = nhashmask;
+	net->xfrm.policy_byidx = nidx;
+	net->xfrm.policy_idx_hmask = nhashmask;
 
 	write_unlock_bh(&xfrm_policy_lock);
 
 	xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
 }
 
-static inline int xfrm_bydst_should_resize(int dir, int *total)
+static inline int xfrm_bydst_should_resize(struct net *net, int dir, int *total)
 {
-	unsigned int cnt = xfrm_policy_count[dir];
-	unsigned int hmask = xfrm_policy_bydst[dir].hmask;
+	unsigned int cnt = net->xfrm.policy_count[dir];
+	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
 
 	if (total)
 		*total += cnt;
@@ -473,9 +458,9 @@
 	return 0;
 }
 
-static inline int xfrm_byidx_should_resize(int total)
+static inline int xfrm_byidx_should_resize(struct net *net, int total)
 {
-	unsigned int hmask = xfrm_idx_hmask;
+	unsigned int hmask = net->xfrm.policy_idx_hmask;
 
 	if ((hmask + 1) < xfrm_policy_hashmax &&
 	    total > hmask)
@@ -487,41 +472,40 @@
 void xfrm_spd_getinfo(struct xfrmk_spdinfo *si)
 {
 	read_lock_bh(&xfrm_policy_lock);
-	si->incnt = xfrm_policy_count[XFRM_POLICY_IN];
-	si->outcnt = xfrm_policy_count[XFRM_POLICY_OUT];
-	si->fwdcnt = xfrm_policy_count[XFRM_POLICY_FWD];
-	si->inscnt = xfrm_policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX];
-	si->outscnt = xfrm_policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX];
-	si->fwdscnt = xfrm_policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX];
-	si->spdhcnt = xfrm_idx_hmask;
+	si->incnt = init_net.xfrm.policy_count[XFRM_POLICY_IN];
+	si->outcnt = init_net.xfrm.policy_count[XFRM_POLICY_OUT];
+	si->fwdcnt = init_net.xfrm.policy_count[XFRM_POLICY_FWD];
+	si->inscnt = init_net.xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX];
+	si->outscnt = init_net.xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX];
+	si->fwdscnt = init_net.xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX];
+	si->spdhcnt = init_net.xfrm.policy_idx_hmask;
 	si->spdhmcnt = xfrm_policy_hashmax;
 	read_unlock_bh(&xfrm_policy_lock);
 }
 EXPORT_SYMBOL(xfrm_spd_getinfo);
 
 static DEFINE_MUTEX(hash_resize_mutex);
-static void xfrm_hash_resize(struct work_struct *__unused)
+static void xfrm_hash_resize(struct work_struct *work)
 {
+	struct net *net = container_of(work, struct net, xfrm.policy_hash_work);
 	int dir, total;
 
 	mutex_lock(&hash_resize_mutex);
 
 	total = 0;
 	for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
-		if (xfrm_bydst_should_resize(dir, &total))
-			xfrm_bydst_resize(dir);
+		if (xfrm_bydst_should_resize(net, dir, &total))
+			xfrm_bydst_resize(net, dir);
 	}
-	if (xfrm_byidx_should_resize(total))
-		xfrm_byidx_resize(total);
+	if (xfrm_byidx_should_resize(net, total))
+		xfrm_byidx_resize(net, total);
 
 	mutex_unlock(&hash_resize_mutex);
 }
 
-static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize);
-
 /* Generate new index... KAME seems to generate them ordered by cost
  * of an absolute inpredictability of ordering of rules. This will not pass. */
-static u32 xfrm_gen_index(u8 type, int dir)
+static u32 xfrm_gen_index(struct net *net, int dir)
 {
 	static u32 idx_generator;
 
@@ -536,7 +520,7 @@
 		idx_generator += 8;
 		if (idx == 0)
 			idx = 8;
-		list = xfrm_policy_byidx + idx_hash(idx);
+		list = net->xfrm.policy_byidx + idx_hash(net, idx);
 		found = 0;
 		hlist_for_each_entry(p, entry, list, byidx) {
 			if (p->index == idx) {
@@ -566,6 +550,7 @@
 
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
 {
+	struct net *net = xp_net(policy);
 	struct xfrm_policy *pol;
 	struct xfrm_policy *delpol;
 	struct hlist_head *chain;
@@ -573,7 +558,7 @@
 	struct dst_entry *gc_list;
 
 	write_lock_bh(&xfrm_policy_lock);
-	chain = policy_hash_bysel(&policy->selector, policy->family, dir);
+	chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
 	delpol = NULL;
 	newpos = NULL;
 	hlist_for_each_entry(pol, entry, chain, bydst) {
@@ -600,27 +585,23 @@
 	else
 		hlist_add_head(&policy->bydst, chain);
 	xfrm_pol_hold(policy);
-	xfrm_policy_count[dir]++;
+	net->xfrm.policy_count[dir]++;
 	atomic_inc(&flow_cache_genid);
-	if (delpol) {
-		hlist_del(&delpol->bydst);
-		hlist_del(&delpol->byidx);
-		list_del(&delpol->walk.all);
-		xfrm_policy_count[dir]--;
-	}
-	policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir);
-	hlist_add_head(&policy->byidx, xfrm_policy_byidx+idx_hash(policy->index));
+	if (delpol)
+		__xfrm_policy_unlink(delpol, dir);
+	policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir);
+	hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index));
 	policy->curlft.add_time = get_seconds();
 	policy->curlft.use_time = 0;
 	if (!mod_timer(&policy->timer, jiffies + HZ))
 		xfrm_pol_hold(policy);
-	list_add(&policy->walk.all, &xfrm_policy_all);
+	list_add(&policy->walk.all, &net->xfrm.policy_all);
 	write_unlock_bh(&xfrm_policy_lock);
 
 	if (delpol)
 		xfrm_policy_kill(delpol);
-	else if (xfrm_bydst_should_resize(dir, NULL))
-		schedule_work(&xfrm_hash_work);
+	else if (xfrm_bydst_should_resize(net, dir, NULL))
+		schedule_work(&net->xfrm.policy_hash_work);
 
 	read_lock_bh(&xfrm_policy_lock);
 	gc_list = NULL;
@@ -654,7 +635,7 @@
 }
 EXPORT_SYMBOL(xfrm_policy_insert);
 
-struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
+struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir,
 					  struct xfrm_selector *sel,
 					  struct xfrm_sec_ctx *ctx, int delete,
 					  int *err)
@@ -665,7 +646,7 @@
 
 	*err = 0;
 	write_lock_bh(&xfrm_policy_lock);
-	chain = policy_hash_bysel(sel, sel->family, dir);
+	chain = policy_hash_bysel(net, sel, sel->family, dir);
 	ret = NULL;
 	hlist_for_each_entry(pol, entry, chain, bydst) {
 		if (pol->type == type &&
@@ -679,10 +660,7 @@
 					write_unlock_bh(&xfrm_policy_lock);
 					return pol;
 				}
-				hlist_del(&pol->bydst);
-				hlist_del(&pol->byidx);
-				list_del(&pol->walk.all);
-				xfrm_policy_count[dir]--;
+				__xfrm_policy_unlink(pol, dir);
 			}
 			ret = pol;
 			break;
@@ -698,8 +676,8 @@
 }
 EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
 
-struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete,
-				     int *err)
+struct xfrm_policy *xfrm_policy_byid(struct net *net, u8 type, int dir, u32 id,
+				     int delete, int *err)
 {
 	struct xfrm_policy *pol, *ret;
 	struct hlist_head *chain;
@@ -711,7 +689,7 @@
 
 	*err = 0;
 	write_lock_bh(&xfrm_policy_lock);
-	chain = xfrm_policy_byidx + idx_hash(id);
+	chain = net->xfrm.policy_byidx + idx_hash(net, id);
 	ret = NULL;
 	hlist_for_each_entry(pol, entry, chain, byidx) {
 		if (pol->type == type && pol->index == id) {
@@ -723,10 +701,7 @@
 					write_unlock_bh(&xfrm_policy_lock);
 					return pol;
 				}
-				hlist_del(&pol->bydst);
-				hlist_del(&pol->byidx);
-				list_del(&pol->walk.all);
-				xfrm_policy_count[dir]--;
+				__xfrm_policy_unlink(pol, dir);
 			}
 			ret = pol;
 			break;
@@ -744,7 +719,7 @@
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 static inline int
-xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
+xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audit_info)
 {
 	int dir, err = 0;
 
@@ -754,7 +729,7 @@
 		int i;
 
 		hlist_for_each_entry(pol, entry,
-				     &xfrm_policy_inexact[dir], bydst) {
+				     &net->xfrm.policy_inexact[dir], bydst) {
 			if (pol->type != type)
 				continue;
 			err = security_xfrm_policy_delete(pol->security);
@@ -766,9 +741,9 @@
 				return err;
 			}
 		}
-		for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
+		for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) {
 			hlist_for_each_entry(pol, entry,
-					     xfrm_policy_bydst[dir].table + i,
+					     net->xfrm.policy_bydst[dir].table + i,
 					     bydst) {
 				if (pol->type != type)
 					continue;
@@ -788,36 +763,33 @@
 }
 #else
 static inline int
-xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
+xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audit_info)
 {
 	return 0;
 }
 #endif
 
-int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info)
+int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
 {
 	int dir, err = 0;
 
 	write_lock_bh(&xfrm_policy_lock);
 
-	err = xfrm_policy_flush_secctx_check(type, audit_info);
+	err = xfrm_policy_flush_secctx_check(net, type, audit_info);
 	if (err)
 		goto out;
 
 	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
 		struct xfrm_policy *pol;
 		struct hlist_node *entry;
-		int i, killed;
+		int i;
 
-		killed = 0;
 	again1:
 		hlist_for_each_entry(pol, entry,
-				     &xfrm_policy_inexact[dir], bydst) {
+				     &net->xfrm.policy_inexact[dir], bydst) {
 			if (pol->type != type)
 				continue;
-			hlist_del(&pol->bydst);
-			hlist_del(&pol->byidx);
-			list_del(&pol->walk.all);
+			__xfrm_policy_unlink(pol, dir);
 			write_unlock_bh(&xfrm_policy_lock);
 
 			xfrm_audit_policy_delete(pol, 1, audit_info->loginuid,
@@ -825,22 +797,19 @@
 						 audit_info->secid);
 
 			xfrm_policy_kill(pol);
-			killed++;
 
 			write_lock_bh(&xfrm_policy_lock);
 			goto again1;
 		}
 
-		for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
+		for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) {
 	again2:
 			hlist_for_each_entry(pol, entry,
-					     xfrm_policy_bydst[dir].table + i,
+					     net->xfrm.policy_bydst[dir].table + i,
 					     bydst) {
 				if (pol->type != type)
 					continue;
-				hlist_del(&pol->bydst);
-				hlist_del(&pol->byidx);
-				list_del(&pol->walk.all);
+				__xfrm_policy_unlink(pol, dir);
 				write_unlock_bh(&xfrm_policy_lock);
 
 				xfrm_audit_policy_delete(pol, 1,
@@ -848,14 +817,12 @@
 							 audit_info->sessionid,
 							 audit_info->secid);
 				xfrm_policy_kill(pol);
-				killed++;
 
 				write_lock_bh(&xfrm_policy_lock);
 				goto again2;
 			}
 		}
 
-		xfrm_policy_count[dir] -= killed;
 	}
 	atomic_inc(&flow_cache_genid);
 out:
@@ -864,7 +831,7 @@
 }
 EXPORT_SYMBOL(xfrm_policy_flush);
 
-int xfrm_policy_walk(struct xfrm_policy_walk *walk,
+int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
 		     int (*func)(struct xfrm_policy *, int, int, void*),
 		     void *data)
 {
@@ -881,10 +848,10 @@
 
 	write_lock_bh(&xfrm_policy_lock);
 	if (list_empty(&walk->walk.all))
-		x = list_first_entry(&xfrm_policy_all, struct xfrm_policy_walk_entry, all);
+		x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all);
 	else
 		x = list_entry(&walk->walk.all, struct xfrm_policy_walk_entry, all);
-	list_for_each_entry_from(x, &xfrm_policy_all, all) {
+	list_for_each_entry_from(x, &net->xfrm.policy_all, all) {
 		if (x->dead)
 			continue;
 		pol = container_of(x, struct xfrm_policy, walk);
@@ -953,7 +920,8 @@
 	return ret;
 }
 
-static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl,
+static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
+						     struct flowi *fl,
 						     u16 family, u8 dir)
 {
 	int err;
@@ -969,7 +937,7 @@
 		return NULL;
 
 	read_lock_bh(&xfrm_policy_lock);
-	chain = policy_hash_direct(daddr, saddr, family, dir);
+	chain = policy_hash_direct(net, daddr, saddr, family, dir);
 	ret = NULL;
 	hlist_for_each_entry(pol, entry, chain, bydst) {
 		err = xfrm_policy_match(pol, fl, type, family, dir);
@@ -986,7 +954,7 @@
 			break;
 		}
 	}
-	chain = &xfrm_policy_inexact[dir];
+	chain = &net->xfrm.policy_inexact[dir];
 	hlist_for_each_entry(pol, entry, chain, bydst) {
 		err = xfrm_policy_match(pol, fl, type, family, dir);
 		if (err) {
@@ -1009,14 +977,14 @@
 	return ret;
 }
 
-static int xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir,
-			       void **objp, atomic_t **obj_refp)
+static int xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family,
+			      u8 dir, void **objp, atomic_t **obj_refp)
 {
 	struct xfrm_policy *pol;
 	int err = 0;
 
 #ifdef CONFIG_XFRM_SUB_POLICY
-	pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir);
+	pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir);
 	if (IS_ERR(pol)) {
 		err = PTR_ERR(pol);
 		pol = NULL;
@@ -1024,7 +992,7 @@
 	if (pol || err)
 		goto end;
 #endif
-	pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir);
+	pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir);
 	if (IS_ERR(pol)) {
 		err = PTR_ERR(pol);
 		pol = NULL;
@@ -1083,29 +1051,32 @@
 
 static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)
 {
-	struct hlist_head *chain = policy_hash_bysel(&pol->selector,
+	struct net *net = xp_net(pol);
+	struct hlist_head *chain = policy_hash_bysel(net, &pol->selector,
 						     pol->family, dir);
 
-	list_add(&pol->walk.all, &xfrm_policy_all);
+	list_add(&pol->walk.all, &net->xfrm.policy_all);
 	hlist_add_head(&pol->bydst, chain);
-	hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index));
-	xfrm_policy_count[dir]++;
+	hlist_add_head(&pol->byidx, net->xfrm.policy_byidx+idx_hash(net, pol->index));
+	net->xfrm.policy_count[dir]++;
 	xfrm_pol_hold(pol);
 
-	if (xfrm_bydst_should_resize(dir, NULL))
-		schedule_work(&xfrm_hash_work);
+	if (xfrm_bydst_should_resize(net, dir, NULL))
+		schedule_work(&net->xfrm.policy_hash_work);
 }
 
 static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
 						int dir)
 {
+	struct net *net = xp_net(pol);
+
 	if (hlist_unhashed(&pol->bydst))
 		return NULL;
 
 	hlist_del(&pol->bydst);
 	hlist_del(&pol->byidx);
 	list_del(&pol->walk.all);
-	xfrm_policy_count[dir]--;
+	net->xfrm.policy_count[dir]--;
 
 	return pol;
 }
@@ -1127,6 +1098,7 @@
 
 int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
 {
+	struct net *net = xp_net(pol);
 	struct xfrm_policy *old_pol;
 
 #ifdef CONFIG_XFRM_SUB_POLICY
@@ -1139,7 +1111,7 @@
 	sk->sk_policy[dir] = pol;
 	if (pol) {
 		pol->curlft.add_time = get_seconds();
-		pol->index = xfrm_gen_index(pol->type, XFRM_POLICY_MAX+dir);
+		pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir);
 		__xfrm_policy_link(pol, XFRM_POLICY_MAX+dir);
 	}
 	if (old_pol)
@@ -1154,7 +1126,7 @@
 
 static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir)
 {
-	struct xfrm_policy *newp = xfrm_policy_alloc(GFP_ATOMIC);
+	struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC);
 
 	if (newp) {
 		newp->selector = old->selector;
@@ -1194,7 +1166,7 @@
 }
 
 static int
-xfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote,
+xfrm_get_saddr(struct net *net, xfrm_address_t *local, xfrm_address_t *remote,
 	       unsigned short family)
 {
 	int err;
@@ -1202,7 +1174,7 @@
 
 	if (unlikely(afinfo == NULL))
 		return -EINVAL;
-	err = afinfo->get_saddr(local, remote);
+	err = afinfo->get_saddr(net, local, remote);
 	xfrm_policy_put_afinfo(afinfo);
 	return err;
 }
@@ -1214,6 +1186,7 @@
 		      struct xfrm_state **xfrm,
 		      unsigned short family)
 {
+	struct net *net = xp_net(policy);
 	int nx;
 	int i, error;
 	xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
@@ -1232,7 +1205,7 @@
 			local = &tmpl->saddr;
 			family = tmpl->encap_family;
 			if (xfrm_addr_any(local, family)) {
-				error = xfrm_get_saddr(&tmp, remote, family);
+				error = xfrm_get_saddr(net, &tmp, remote, family);
 				if (error)
 					goto fail;
 				local = &tmp;
@@ -1546,7 +1519,7 @@
  * At the moment we eat a raw IP route. Mostly to speed up lookups
  * on interfaces with disabled IPsec.
  */
-int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
+int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, struct flowi *fl,
 		  struct sock *sk, int flags)
 {
 	struct xfrm_policy *policy;
@@ -1576,7 +1549,7 @@
 		policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
 		err = PTR_ERR(policy);
 		if (IS_ERR(policy)) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
 			goto dropdst;
 		}
 	}
@@ -1584,14 +1557,14 @@
 	if (!policy) {
 		/* To accelerate a bit...  */
 		if ((dst_orig->flags & DST_NOXFRM) ||
-		    !xfrm_policy_count[XFRM_POLICY_OUT])
+		    !net->xfrm.policy_count[XFRM_POLICY_OUT])
 			goto nopol;
 
-		policy = flow_cache_lookup(fl, dst_orig->ops->family,
+		policy = flow_cache_lookup(net, fl, dst_orig->ops->family,
 					   dir, xfrm_policy_lookup);
 		err = PTR_ERR(policy);
 		if (IS_ERR(policy)) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
 			goto dropdst;
 		}
 	}
@@ -1614,7 +1587,7 @@
 	default:
 	case XFRM_POLICY_BLOCK:
 		/* Prohibit the flow */
-		XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLBLOCK);
+		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK);
 		err = -EPERM;
 		goto error;
 
@@ -1634,7 +1607,7 @@
 		 */
 		dst = xfrm_find_bundle(fl, policy, family);
 		if (IS_ERR(dst)) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
 			err = PTR_ERR(dst);
 			goto error;
 		}
@@ -1644,17 +1617,18 @@
 
 #ifdef CONFIG_XFRM_SUB_POLICY
 		if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
-			pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN,
+			pols[1] = xfrm_policy_lookup_bytype(net,
+							    XFRM_POLICY_TYPE_MAIN,
 							    fl, family,
 							    XFRM_POLICY_OUT);
 			if (pols[1]) {
 				if (IS_ERR(pols[1])) {
-					XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLERROR);
+					XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
 					err = PTR_ERR(pols[1]);
 					goto error;
 				}
 				if (pols[1]->action == XFRM_POLICY_BLOCK) {
-					XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLBLOCK);
+					XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK);
 					err = -EPERM;
 					goto error;
 				}
@@ -1681,27 +1655,27 @@
 
 		if (unlikely(nx<0)) {
 			err = nx;
-			if (err == -EAGAIN && sysctl_xfrm_larval_drop) {
+			if (err == -EAGAIN && net->xfrm.sysctl_larval_drop) {
 				/* EREMOTE tells the caller to generate
 				 * a one-shot blackhole route.
 				 */
-				XFRM_INC_STATS(LINUX_MIB_XFRMOUTNOSTATES);
+				XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
 				xfrm_pol_put(policy);
 				return -EREMOTE;
 			}
 			if (err == -EAGAIN && (flags & XFRM_LOOKUP_WAIT)) {
 				DECLARE_WAITQUEUE(wait, current);
 
-				add_wait_queue(&km_waitq, &wait);
+				add_wait_queue(&net->xfrm.km_waitq, &wait);
 				set_current_state(TASK_INTERRUPTIBLE);
 				schedule();
 				set_current_state(TASK_RUNNING);
-				remove_wait_queue(&km_waitq, &wait);
+				remove_wait_queue(&net->xfrm.km_waitq, &wait);
 
 				nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
 
 				if (nx == -EAGAIN && signal_pending(current)) {
-					XFRM_INC_STATS(LINUX_MIB_XFRMOUTNOSTATES);
+					XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
 					err = -ERESTART;
 					goto error;
 				}
@@ -1713,7 +1687,7 @@
 				err = nx;
 			}
 			if (err < 0) {
-				XFRM_INC_STATS(LINUX_MIB_XFRMOUTNOSTATES);
+				XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
 				goto error;
 			}
 		}
@@ -1726,7 +1700,7 @@
 		dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig);
 		err = PTR_ERR(dst);
 		if (IS_ERR(dst)) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLEGENERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR);
 			goto error;
 		}
 
@@ -1747,9 +1721,9 @@
 			dst_free(dst);
 
 			if (pol_dead)
-				XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLDEAD);
+				XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLDEAD);
 			else
-				XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
+				XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
 			err = -EHOSTUNREACH;
 			goto error;
 		}
@@ -1761,7 +1735,7 @@
 		if (unlikely(err)) {
 			write_unlock_bh(&policy->lock);
 			dst_free(dst);
-			XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
 			goto error;
 		}
 
@@ -1790,10 +1764,10 @@
 }
 EXPORT_SYMBOL(__xfrm_lookup);
 
-int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
+int xfrm_lookup(struct net *net, struct dst_entry **dst_p, struct flowi *fl,
 		struct sock *sk, int flags)
 {
-	int err = __xfrm_lookup(dst_p, fl, sk, flags);
+	int err = __xfrm_lookup(net, dst_p, fl, sk, flags);
 
 	if (err == -EREMOTE) {
 		dst_release(*dst_p);
@@ -1901,6 +1875,7 @@
 int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
 			unsigned short family)
 {
+	struct net *net = dev_net(skb->dev);
 	struct xfrm_policy *pol;
 	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
 	int npols = 0;
@@ -1916,7 +1891,7 @@
 	fl_dir = policy_to_flow_dir(dir);
 
 	if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) {
-		XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR);
+		XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
 		return 0;
 	}
 
@@ -1929,7 +1904,7 @@
 		for (i=skb->sp->len-1; i>=0; i--) {
 			struct xfrm_state *x = skb->sp->xvec[i];
 			if (!xfrm_selector_match(&x->sel, &fl, family)) {
-				XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMISMATCH);
+				XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
 				return 0;
 			}
 		}
@@ -1939,24 +1914,24 @@
 	if (sk && sk->sk_policy[dir]) {
 		pol = xfrm_sk_policy_lookup(sk, dir, &fl);
 		if (IS_ERR(pol)) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
 			return 0;
 		}
 	}
 
 	if (!pol)
-		pol = flow_cache_lookup(&fl, family, fl_dir,
+		pol = flow_cache_lookup(net, &fl, family, fl_dir,
 					xfrm_policy_lookup);
 
 	if (IS_ERR(pol)) {
-		XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR);
+		XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
 		return 0;
 	}
 
 	if (!pol) {
 		if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
 			xfrm_secpath_reject(xerr_idx, skb, &fl);
-			XFRM_INC_STATS(LINUX_MIB_XFRMINNOPOLS);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS);
 			return 0;
 		}
 		return 1;
@@ -1968,12 +1943,12 @@
 	npols ++;
 #ifdef CONFIG_XFRM_SUB_POLICY
 	if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
-		pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN,
+		pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN,
 						    &fl, family,
 						    XFRM_POLICY_IN);
 		if (pols[1]) {
 			if (IS_ERR(pols[1])) {
-				XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR);
+				XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
 				return 0;
 			}
 			pols[1]->curlft.use_time = get_seconds();
@@ -1997,11 +1972,11 @@
 		for (pi = 0; pi < npols; pi++) {
 			if (pols[pi] != pol &&
 			    pols[pi]->action != XFRM_POLICY_ALLOW) {
-				XFRM_INC_STATS(LINUX_MIB_XFRMINPOLBLOCK);
+				XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);
 				goto reject;
 			}
 			if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) {
-				XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR);
+				XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
 				goto reject_error;
 			}
 			for (i = 0; i < pols[pi]->xfrm_nr; i++)
@@ -2025,20 +2000,20 @@
 				if (k < -1)
 					/* "-2 - errored_index" returned */
 					xerr_idx = -(2+k);
-				XFRM_INC_STATS(LINUX_MIB_XFRMINTMPLMISMATCH);
+				XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH);
 				goto reject;
 			}
 		}
 
 		if (secpath_has_nontransport(sp, k, &xerr_idx)) {
-			XFRM_INC_STATS(LINUX_MIB_XFRMINTMPLMISMATCH);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH);
 			goto reject;
 		}
 
 		xfrm_pols_put(pols, npols);
 		return 1;
 	}
-	XFRM_INC_STATS(LINUX_MIB_XFRMINPOLBLOCK);
+	XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);
 
 reject:
 	xfrm_secpath_reject(xerr_idx, skb, &fl);
@@ -2050,15 +2025,16 @@
 
 int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
 {
+	struct net *net = dev_net(skb->dev);
 	struct flowi fl;
 
 	if (xfrm_decode_session(skb, &fl, family) < 0) {
 		/* XXX: we should have something like FWDHDRERROR here. */
-		XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR);
+		XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
 		return 0;
 	}
 
-	return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0;
+	return xfrm_lookup(net, &skb->dst, &fl, NULL, 0) == 0;
 }
 EXPORT_SYMBOL(__xfrm_route_forward);
 
@@ -2142,7 +2118,7 @@
 	write_unlock(&pol->lock);
 }
 
-static void xfrm_prune_bundles(int (*func)(struct dst_entry *))
+static void xfrm_prune_bundles(struct net *net, int (*func)(struct dst_entry *))
 {
 	struct dst_entry *gc_list = NULL;
 	int dir;
@@ -2155,11 +2131,11 @@
 		int i;
 
 		hlist_for_each_entry(pol, entry,
-				     &xfrm_policy_inexact[dir], bydst)
+				     &net->xfrm.policy_inexact[dir], bydst)
 			prune_one_bundle(pol, func, &gc_list);
 
-		table = xfrm_policy_bydst[dir].table;
-		for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
+		table = net->xfrm.policy_bydst[dir].table;
+		for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) {
 			hlist_for_each_entry(pol, entry, table + i, bydst)
 				prune_one_bundle(pol, func, &gc_list);
 		}
@@ -2178,14 +2154,14 @@
 	return !atomic_read(&dst->__refcnt);
 }
 
-static void __xfrm_garbage_collect(void)
+static void __xfrm_garbage_collect(struct net *net)
 {
-	xfrm_prune_bundles(unused_bundle);
+	xfrm_prune_bundles(net, unused_bundle);
 }
 
-static int xfrm_flush_bundles(void)
+static int xfrm_flush_bundles(struct net *net)
 {
-	xfrm_prune_bundles(stale_bundle);
+	xfrm_prune_bundles(net, stale_bundle);
 	return 0;
 }
 
@@ -2371,38 +2347,54 @@
 {
 	struct net_device *dev = ptr;
 
-	if (!net_eq(dev_net(dev), &init_net))
-		return NOTIFY_DONE;
-
 	switch (event) {
 	case NETDEV_DOWN:
-		xfrm_flush_bundles();
+		xfrm_flush_bundles(dev_net(dev));
 	}
 	return NOTIFY_DONE;
 }
 
 static struct notifier_block xfrm_dev_notifier = {
-	xfrm_dev_event,
-	NULL,
-	0
+	.notifier_call	= xfrm_dev_event,
 };
 
 #ifdef CONFIG_XFRM_STATISTICS
-static int __init xfrm_statistics_init(void)
+static int __net_init xfrm_statistics_init(struct net *net)
 {
-	if (snmp_mib_init((void **)xfrm_statistics,
+	int rv;
+
+	if (snmp_mib_init((void **)net->mib.xfrm_statistics,
 			  sizeof(struct linux_xfrm_mib)) < 0)
 		return -ENOMEM;
+	rv = xfrm_proc_init(net);
+	if (rv < 0)
+		snmp_mib_free((void **)net->mib.xfrm_statistics);
+	return rv;
+}
+
+static void xfrm_statistics_fini(struct net *net)
+{
+	xfrm_proc_fini(net);
+	snmp_mib_free((void **)net->mib.xfrm_statistics);
+}
+#else
+static int __net_init xfrm_statistics_init(struct net *net)
+{
 	return 0;
 }
+
+static void xfrm_statistics_fini(struct net *net)
+{
+}
 #endif
 
-static void __init xfrm_policy_init(void)
+static int __net_init xfrm_policy_init(struct net *net)
 {
 	unsigned int hmask, sz;
 	int dir;
 
-	xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
+	if (net_eq(net, &init_net))
+		xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
 					   sizeof(struct xfrm_dst),
 					   0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
 					   NULL);
@@ -2410,39 +2402,124 @@
 	hmask = 8 - 1;
 	sz = (hmask+1) * sizeof(struct hlist_head);
 
-	xfrm_policy_byidx = xfrm_hash_alloc(sz);
-	xfrm_idx_hmask = hmask;
-	if (!xfrm_policy_byidx)
-		panic("XFRM: failed to allocate byidx hash\n");
+	net->xfrm.policy_byidx = xfrm_hash_alloc(sz);
+	if (!net->xfrm.policy_byidx)
+		goto out_byidx;
+	net->xfrm.policy_idx_hmask = hmask;
 
 	for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
 		struct xfrm_policy_hash *htab;
 
-		INIT_HLIST_HEAD(&xfrm_policy_inexact[dir]);
+		net->xfrm.policy_count[dir] = 0;
+		INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
 
-		htab = &xfrm_policy_bydst[dir];
+		htab = &net->xfrm.policy_bydst[dir];
 		htab->table = xfrm_hash_alloc(sz);
-		htab->hmask = hmask;
 		if (!htab->table)
-			panic("XFRM: failed to allocate bydst hash\n");
+			goto out_bydst;
+		htab->hmask = hmask;
 	}
 
-	INIT_LIST_HEAD(&xfrm_policy_all);
-	INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);
-	register_netdevice_notifier(&xfrm_dev_notifier);
+	INIT_LIST_HEAD(&net->xfrm.policy_all);
+	INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize);
+	if (net_eq(net, &init_net))
+		register_netdevice_notifier(&xfrm_dev_notifier);
+	return 0;
+
+out_bydst:
+	for (dir--; dir >= 0; dir--) {
+		struct xfrm_policy_hash *htab;
+
+		htab = &net->xfrm.policy_bydst[dir];
+		xfrm_hash_free(htab->table, sz);
+	}
+	xfrm_hash_free(net->xfrm.policy_byidx, sz);
+out_byidx:
+	return -ENOMEM;
 }
 
+static void xfrm_policy_fini(struct net *net)
+{
+	struct xfrm_audit audit_info;
+	unsigned int sz;
+	int dir;
+
+	flush_work(&net->xfrm.policy_hash_work);
+#ifdef CONFIG_XFRM_SUB_POLICY
+	audit_info.loginuid = -1;
+	audit_info.sessionid = -1;
+	audit_info.secid = 0;
+	xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info);
+#endif
+	audit_info.loginuid = -1;
+	audit_info.sessionid = -1;
+	audit_info.secid = 0;
+	xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info);
+	flush_work(&xfrm_policy_gc_work);
+
+	WARN_ON(!list_empty(&net->xfrm.policy_all));
+
+	for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
+		struct xfrm_policy_hash *htab;
+
+		WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir]));
+
+		htab = &net->xfrm.policy_bydst[dir];
+		sz = (htab->hmask + 1);
+		WARN_ON(!hlist_empty(htab->table));
+		xfrm_hash_free(htab->table, sz);
+	}
+
+	sz = (net->xfrm.policy_idx_hmask + 1) * sizeof(struct hlist_head);
+	WARN_ON(!hlist_empty(net->xfrm.policy_byidx));
+	xfrm_hash_free(net->xfrm.policy_byidx, sz);
+}
+
+static int __net_init xfrm_net_init(struct net *net)
+{
+	int rv;
+
+	rv = xfrm_statistics_init(net);
+	if (rv < 0)
+		goto out_statistics;
+	rv = xfrm_state_init(net);
+	if (rv < 0)
+		goto out_state;
+	rv = xfrm_policy_init(net);
+	if (rv < 0)
+		goto out_policy;
+	rv = xfrm_sysctl_init(net);
+	if (rv < 0)
+		goto out_sysctl;
+	return 0;
+
+out_sysctl:
+	xfrm_policy_fini(net);
+out_policy:
+	xfrm_state_fini(net);
+out_state:
+	xfrm_statistics_fini(net);
+out_statistics:
+	return rv;
+}
+
+static void __net_exit xfrm_net_exit(struct net *net)
+{
+	xfrm_sysctl_fini(net);
+	xfrm_policy_fini(net);
+	xfrm_state_fini(net);
+	xfrm_statistics_fini(net);
+}
+
+static struct pernet_operations __net_initdata xfrm_net_ops = {
+	.init = xfrm_net_init,
+	.exit = xfrm_net_exit,
+};
+
 void __init xfrm_init(void)
 {
-#ifdef CONFIG_XFRM_STATISTICS
-	xfrm_statistics_init();
-#endif
-	xfrm_state_init();
-	xfrm_policy_init();
+	register_pernet_subsys(&xfrm_net_ops);
 	xfrm_input_init();
-#ifdef CONFIG_XFRM_STATISTICS
-	xfrm_proc_init();
-#endif
 }
 
 #ifdef CONFIG_AUDITSYSCALL
@@ -2458,25 +2535,21 @@
 
 	switch(sel->family) {
 	case AF_INET:
-		audit_log_format(audit_buf, " src=" NIPQUAD_FMT,
-				 NIPQUAD(sel->saddr.a4));
+		audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4);
 		if (sel->prefixlen_s != 32)
 			audit_log_format(audit_buf, " src_prefixlen=%d",
 					 sel->prefixlen_s);
-		audit_log_format(audit_buf, " dst=" NIPQUAD_FMT,
-				 NIPQUAD(sel->daddr.a4));
+		audit_log_format(audit_buf, " dst=%pI4", &sel->daddr.a4);
 		if (sel->prefixlen_d != 32)
 			audit_log_format(audit_buf, " dst_prefixlen=%d",
 					 sel->prefixlen_d);
 		break;
 	case AF_INET6:
-		audit_log_format(audit_buf, " src=" NIP6_FMT,
-				 NIP6(*(struct in6_addr *)sel->saddr.a6));
+		audit_log_format(audit_buf, " src=%pI6", sel->saddr.a6);
 		if (sel->prefixlen_s != 128)
 			audit_log_format(audit_buf, " src_prefixlen=%d",
 					 sel->prefixlen_s);
-		audit_log_format(audit_buf, " dst=" NIP6_FMT,
-				 NIP6(*(struct in6_addr *)sel->daddr.a6));
+		audit_log_format(audit_buf, " dst=%pI6", sel->daddr.a6);
 		if (sel->prefixlen_d != 128)
 			audit_log_format(audit_buf, " dst_prefixlen=%d",
 					 sel->prefixlen_d);
@@ -2546,7 +2619,7 @@
 	u32 priority = ~0U;
 
 	read_lock_bh(&xfrm_policy_lock);
-	chain = policy_hash_direct(&sel->daddr, &sel->saddr, sel->family, dir);
+	chain = policy_hash_direct(&init_net, &sel->daddr, &sel->saddr, sel->family, dir);
 	hlist_for_each_entry(pol, entry, chain, bydst) {
 		if (xfrm_migrate_selector_match(sel, &pol->selector) &&
 		    pol->type == type) {
@@ -2555,7 +2628,7 @@
 			break;
 		}
 	}
-	chain = &xfrm_policy_inexact[dir];
+	chain = &init_net.xfrm.policy_inexact[dir];
 	hlist_for_each_entry(pol, entry, chain, bydst) {
 		if (xfrm_migrate_selector_match(sel, &pol->selector) &&
 		    pol->type == type &&
diff --git a/net/xfrm/xfrm_proc.c b/net/xfrm/xfrm_proc.c
index 2b0db13..284eaef 100644
--- a/net/xfrm/xfrm_proc.c
+++ b/net/xfrm/xfrm_proc.c
@@ -59,17 +59,18 @@
 
 static int xfrm_statistics_seq_show(struct seq_file *seq, void *v)
 {
+	struct net *net = seq->private;
 	int i;
 	for (i=0; xfrm_mib_list[i].name; i++)
 		seq_printf(seq, "%-24s\t%lu\n", xfrm_mib_list[i].name,
-			   fold_field((void **)xfrm_statistics,
+			   fold_field((void **)net->mib.xfrm_statistics,
 				      xfrm_mib_list[i].entry));
 	return 0;
 }
 
 static int xfrm_statistics_seq_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, xfrm_statistics_seq_show, NULL);
+	return single_open_net(inode, file, xfrm_statistics_seq_show);
 }
 
 static struct file_operations xfrm_statistics_seq_fops = {
@@ -77,21 +78,18 @@
 	.open	 = xfrm_statistics_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
-	.release = single_release,
+	.release = single_release_net,
 };
 
-int __init xfrm_proc_init(void)
+int __net_init xfrm_proc_init(struct net *net)
 {
-	int rc = 0;
-
-	if (!proc_net_fops_create(&init_net, "xfrm_stat", S_IRUGO,
+	if (!proc_net_fops_create(net, "xfrm_stat", S_IRUGO,
 				  &xfrm_statistics_seq_fops))
-		goto stat_fail;
+		return -ENOMEM;
+	return 0;
+}
 
- out:
-	return rc;
-
- stat_fail:
-	rc = -ENOMEM;
-	goto out;
+void xfrm_proc_fini(struct net *net)
+{
+	proc_net_remove(net, "xfrm_stat");
 }
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 508337f..e25ff62 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -24,17 +24,6 @@
 
 #include "xfrm_hash.h"
 
-struct sock *xfrm_nl;
-EXPORT_SYMBOL(xfrm_nl);
-
-u32 sysctl_xfrm_aevent_etime __read_mostly = XFRM_AE_ETIME;
-EXPORT_SYMBOL(sysctl_xfrm_aevent_etime);
-
-u32 sysctl_xfrm_aevent_rseqth __read_mostly = XFRM_AE_SEQT_SIZE;
-EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth);
-
-u32 sysctl_xfrm_acq_expires __read_mostly = 30;
-
 /* Each xfrm_state may be linked to two tables:
 
    1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
@@ -44,19 +33,7 @@
 
 static DEFINE_SPINLOCK(xfrm_state_lock);
 
-/* Hash table to find appropriate SA towards given target (endpoint
- * of tunnel or destination of transport mode) allowed by selector.
- *
- * Main use is finding SA after policy selected tunnel or transport mode.
- * Also, it can be used by ah/esp icmp error handler to find offending SA.
- */
-static LIST_HEAD(xfrm_state_all);
-static struct hlist_head *xfrm_state_bydst __read_mostly;
-static struct hlist_head *xfrm_state_bysrc __read_mostly;
-static struct hlist_head *xfrm_state_byspi __read_mostly;
-static unsigned int xfrm_state_hmask __read_mostly;
 static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
-static unsigned int xfrm_state_num;
 static unsigned int xfrm_state_genid;
 
 static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
@@ -69,25 +46,27 @@
 #define xfrm_audit_state_replay(x, s, sq)	do { ; } while (0)
 #endif /* CONFIG_AUDITSYSCALL */
 
-static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
+static inline unsigned int xfrm_dst_hash(struct net *net,
+					 xfrm_address_t *daddr,
 					 xfrm_address_t *saddr,
 					 u32 reqid,
 					 unsigned short family)
 {
-	return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
+	return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask);
 }
 
-static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
+static inline unsigned int xfrm_src_hash(struct net *net,
+					 xfrm_address_t *daddr,
 					 xfrm_address_t *saddr,
 					 unsigned short family)
 {
-	return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);
+	return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask);
 }
 
 static inline unsigned int
-xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
+xfrm_spi_hash(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
 {
-	return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);
+	return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
 }
 
 static void xfrm_hash_transfer(struct hlist_head *list,
@@ -121,16 +100,16 @@
 	}
 }
 
-static unsigned long xfrm_hash_new_size(void)
+static unsigned long xfrm_hash_new_size(unsigned int state_hmask)
 {
-	return ((xfrm_state_hmask + 1) << 1) *
-		sizeof(struct hlist_head);
+	return ((state_hmask + 1) << 1) * sizeof(struct hlist_head);
 }
 
 static DEFINE_MUTEX(hash_resize_mutex);
 
-static void xfrm_hash_resize(struct work_struct *__unused)
+static void xfrm_hash_resize(struct work_struct *work)
 {
+	struct net *net = container_of(work, struct net, xfrm.state_hash_work);
 	struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
 	unsigned long nsize, osize;
 	unsigned int nhashmask, ohashmask;
@@ -138,7 +117,7 @@
 
 	mutex_lock(&hash_resize_mutex);
 
-	nsize = xfrm_hash_new_size();
+	nsize = xfrm_hash_new_size(net->xfrm.state_hmask);
 	ndst = xfrm_hash_alloc(nsize);
 	if (!ndst)
 		goto out_unlock;
@@ -157,19 +136,19 @@
 	spin_lock_bh(&xfrm_state_lock);
 
 	nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
-	for (i = xfrm_state_hmask; i >= 0; i--)
-		xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi,
+	for (i = net->xfrm.state_hmask; i >= 0; i--)
+		xfrm_hash_transfer(net->xfrm.state_bydst+i, ndst, nsrc, nspi,
 				   nhashmask);
 
-	odst = xfrm_state_bydst;
-	osrc = xfrm_state_bysrc;
-	ospi = xfrm_state_byspi;
-	ohashmask = xfrm_state_hmask;
+	odst = net->xfrm.state_bydst;
+	osrc = net->xfrm.state_bysrc;
+	ospi = net->xfrm.state_byspi;
+	ohashmask = net->xfrm.state_hmask;
 
-	xfrm_state_bydst = ndst;
-	xfrm_state_bysrc = nsrc;
-	xfrm_state_byspi = nspi;
-	xfrm_state_hmask = nhashmask;
+	net->xfrm.state_bydst = ndst;
+	net->xfrm.state_bysrc = nsrc;
+	net->xfrm.state_byspi = nspi;
+	net->xfrm.state_hmask = nhashmask;
 
 	spin_unlock_bh(&xfrm_state_lock);
 
@@ -182,16 +161,9 @@
 	mutex_unlock(&hash_resize_mutex);
 }
 
-static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize);
-
-DECLARE_WAIT_QUEUE_HEAD(km_waitq);
-EXPORT_SYMBOL(km_waitq);
-
 static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
 static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
 
-static struct work_struct xfrm_state_gc_work;
-static HLIST_HEAD(xfrm_state_gc_list);
 static DEFINE_SPINLOCK(xfrm_state_gc_lock);
 
 int __xfrm_state_delete(struct xfrm_state *x);
@@ -401,20 +373,21 @@
 	kfree(x);
 }
 
-static void xfrm_state_gc_task(struct work_struct *data)
+static void xfrm_state_gc_task(struct work_struct *work)
 {
+	struct net *net = container_of(work, struct net, xfrm.state_gc_work);
 	struct xfrm_state *x;
 	struct hlist_node *entry, *tmp;
 	struct hlist_head gc_list;
 
 	spin_lock_bh(&xfrm_state_gc_lock);
-	hlist_move_list(&xfrm_state_gc_list, &gc_list);
+	hlist_move_list(&net->xfrm.state_gc_list, &gc_list);
 	spin_unlock_bh(&xfrm_state_gc_lock);
 
 	hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
 		xfrm_state_gc_destroy(x);
 
-	wake_up(&km_waitq);
+	wake_up(&net->xfrm.km_waitq);
 }
 
 static inline unsigned long make_jiffies(long secs)
@@ -428,6 +401,7 @@
 static void xfrm_timer_handler(unsigned long data)
 {
 	struct xfrm_state *x = (struct xfrm_state*)data;
+	struct net *net = xs_net(x);
 	unsigned long now = get_seconds();
 	long next = LONG_MAX;
 	int warn = 0;
@@ -485,7 +459,7 @@
 expired:
 	if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
 		x->km.state = XFRM_STATE_EXPIRED;
-		wake_up(&km_waitq);
+		wake_up(&net->xfrm.km_waitq);
 		next = 2;
 		goto resched;
 	}
@@ -504,13 +478,14 @@
 
 static void xfrm_replay_timer_handler(unsigned long data);
 
-struct xfrm_state *xfrm_state_alloc(void)
+struct xfrm_state *xfrm_state_alloc(struct net *net)
 {
 	struct xfrm_state *x;
 
 	x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC);
 
 	if (x) {
+		write_pnet(&x->xs_net, net);
 		atomic_set(&x->refcnt, 1);
 		atomic_set(&x->tunnel_users, 0);
 		INIT_LIST_HEAD(&x->km.all);
@@ -537,17 +512,20 @@
 
 void __xfrm_state_destroy(struct xfrm_state *x)
 {
+	struct net *net = xs_net(x);
+
 	WARN_ON(x->km.state != XFRM_STATE_DEAD);
 
 	spin_lock_bh(&xfrm_state_gc_lock);
-	hlist_add_head(&x->gclist, &xfrm_state_gc_list);
+	hlist_add_head(&x->gclist, &net->xfrm.state_gc_list);
 	spin_unlock_bh(&xfrm_state_gc_lock);
-	schedule_work(&xfrm_state_gc_work);
+	schedule_work(&net->xfrm.state_gc_work);
 }
 EXPORT_SYMBOL(__xfrm_state_destroy);
 
 int __xfrm_state_delete(struct xfrm_state *x)
 {
+	struct net *net = xs_net(x);
 	int err = -ESRCH;
 
 	if (x->km.state != XFRM_STATE_DEAD) {
@@ -558,7 +536,7 @@
 		hlist_del(&x->bysrc);
 		if (x->id.spi)
 			hlist_del(&x->byspi);
-		xfrm_state_num--;
+		net->xfrm.state_num--;
 		spin_unlock(&xfrm_state_lock);
 
 		/* All xfrm_state objects are created by xfrm_state_alloc.
@@ -587,15 +565,15 @@
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 static inline int
-xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
+xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info)
 {
 	int i, err = 0;
 
-	for (i = 0; i <= xfrm_state_hmask; i++) {
+	for (i = 0; i <= net->xfrm.state_hmask; i++) {
 		struct hlist_node *entry;
 		struct xfrm_state *x;
 
-		hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
+		hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) {
 			if (xfrm_id_proto_match(x->id.proto, proto) &&
 			   (err = security_xfrm_state_delete(x)) != 0) {
 				xfrm_audit_state_delete(x, 0,
@@ -611,26 +589,26 @@
 }
 #else
 static inline int
-xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
+xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info)
 {
 	return 0;
 }
 #endif
 
-int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info)
+int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)
 {
 	int i, err = 0;
 
 	spin_lock_bh(&xfrm_state_lock);
-	err = xfrm_state_flush_secctx_check(proto, audit_info);
+	err = xfrm_state_flush_secctx_check(net, proto, audit_info);
 	if (err)
 		goto out;
 
-	for (i = 0; i <= xfrm_state_hmask; i++) {
+	for (i = 0; i <= net->xfrm.state_hmask; i++) {
 		struct hlist_node *entry;
 		struct xfrm_state *x;
 restart:
-		hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
+		hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) {
 			if (!xfrm_state_kern(x) &&
 			    xfrm_id_proto_match(x->id.proto, proto)) {
 				xfrm_state_hold(x);
@@ -652,7 +630,7 @@
 
 out:
 	spin_unlock_bh(&xfrm_state_lock);
-	wake_up(&km_waitq);
+	wake_up(&net->xfrm.km_waitq);
 	return err;
 }
 EXPORT_SYMBOL(xfrm_state_flush);
@@ -660,8 +638,8 @@
 void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
 {
 	spin_lock_bh(&xfrm_state_lock);
-	si->sadcnt = xfrm_state_num;
-	si->sadhcnt = xfrm_state_hmask;
+	si->sadcnt = init_net.xfrm.state_num;
+	si->sadhcnt = init_net.xfrm.state_hmask;
 	si->sadhmcnt = xfrm_state_hashmax;
 	spin_unlock_bh(&xfrm_state_lock);
 }
@@ -681,13 +659,13 @@
 	return 0;
 }
 
-static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
+static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
 {
-	unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
+	unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
 	struct xfrm_state *x;
 	struct hlist_node *entry;
 
-	hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) {
+	hlist_for_each_entry(x, entry, net->xfrm.state_byspi+h, byspi) {
 		if (x->props.family != family ||
 		    x->id.spi       != spi ||
 		    x->id.proto     != proto)
@@ -713,13 +691,13 @@
 	return NULL;
 }
 
-static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
+static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
 {
-	unsigned int h = xfrm_src_hash(daddr, saddr, family);
+	unsigned int h = xfrm_src_hash(net, daddr, saddr, family);
 	struct xfrm_state *x;
 	struct hlist_node *entry;
 
-	hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
+	hlist_for_each_entry(x, entry, net->xfrm.state_bysrc+h, bysrc) {
 		if (x->props.family != family ||
 		    x->id.proto     != proto)
 			continue;
@@ -751,21 +729,23 @@
 static inline struct xfrm_state *
 __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
 {
+	struct net *net = xs_net(x);
+
 	if (use_spi)
-		return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
+		return __xfrm_state_lookup(net, &x->id.daddr, x->id.spi,
 					   x->id.proto, family);
 	else
-		return __xfrm_state_lookup_byaddr(&x->id.daddr,
+		return __xfrm_state_lookup_byaddr(net, &x->id.daddr,
 						  &x->props.saddr,
 						  x->id.proto, family);
 }
 
-static void xfrm_hash_grow_check(int have_hash_collision)
+static void xfrm_hash_grow_check(struct net *net, int have_hash_collision)
 {
 	if (have_hash_collision &&
-	    (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
-	    xfrm_state_num > xfrm_state_hmask)
-		schedule_work(&xfrm_hash_work);
+	    (net->xfrm.state_hmask + 1) < xfrm_state_hashmax &&
+	    net->xfrm.state_num > net->xfrm.state_hmask)
+		schedule_work(&net->xfrm.state_hash_work);
 }
 
 struct xfrm_state *
@@ -774,6 +754,7 @@
 		struct xfrm_policy *pol, int *err,
 		unsigned short family)
 {
+	struct net *net = xp_net(pol);
 	unsigned int h;
 	struct hlist_node *entry;
 	struct xfrm_state *x, *x0, *to_put;
@@ -784,8 +765,8 @@
 	to_put = NULL;
 
 	spin_lock_bh(&xfrm_state_lock);
-	h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
-	hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
+	h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, family);
+	hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
 		if (x->props.family == family &&
 		    x->props.reqid == tmpl->reqid &&
 		    !(x->props.flags & XFRM_STATE_WILDRECV) &&
@@ -829,13 +810,13 @@
 	x = best;
 	if (!x && !error && !acquire_in_progress) {
 		if (tmpl->id.spi &&
-		    (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
+		    (x0 = __xfrm_state_lookup(net, daddr, tmpl->id.spi,
 					      tmpl->id.proto, family)) != NULL) {
 			to_put = x0;
 			error = -EEXIST;
 			goto out;
 		}
-		x = xfrm_state_alloc();
+		x = xfrm_state_alloc(net);
 		if (x == NULL) {
 			error = -ENOMEM;
 			goto out;
@@ -854,19 +835,19 @@
 
 		if (km_query(x, tmpl, pol) == 0) {
 			x->km.state = XFRM_STATE_ACQ;
-			list_add(&x->km.all, &xfrm_state_all);
-			hlist_add_head(&x->bydst, xfrm_state_bydst+h);
-			h = xfrm_src_hash(daddr, saddr, family);
-			hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
+			list_add(&x->km.all, &net->xfrm.state_all);
+			hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
+			h = xfrm_src_hash(net, daddr, saddr, family);
+			hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
 			if (x->id.spi) {
-				h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
-				hlist_add_head(&x->byspi, xfrm_state_byspi+h);
+				h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, family);
+				hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
 			}
-			x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
-			x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
+			x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
+			x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ;
 			add_timer(&x->timer);
-			xfrm_state_num++;
-			xfrm_hash_grow_check(x->bydst.next != NULL);
+			net->xfrm.state_num++;
+			xfrm_hash_grow_check(net, x->bydst.next != NULL);
 		} else {
 			x->km.state = XFRM_STATE_DEAD;
 			to_put = x;
@@ -886,7 +867,8 @@
 }
 
 struct xfrm_state *
-xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
+xfrm_stateonly_find(struct net *net,
+		    xfrm_address_t *daddr, xfrm_address_t *saddr,
 		    unsigned short family, u8 mode, u8 proto, u32 reqid)
 {
 	unsigned int h;
@@ -894,8 +876,8 @@
 	struct hlist_node *entry;
 
 	spin_lock(&xfrm_state_lock);
-	h = xfrm_dst_hash(daddr, saddr, reqid, family);
-	hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
+	h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
+	hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
 		if (x->props.family == family &&
 		    x->props.reqid == reqid &&
 		    !(x->props.flags & XFRM_STATE_WILDRECV) &&
@@ -919,48 +901,50 @@
 
 static void __xfrm_state_insert(struct xfrm_state *x)
 {
+	struct net *net = xs_net(x);
 	unsigned int h;
 
 	x->genid = ++xfrm_state_genid;
 
-	list_add(&x->km.all, &xfrm_state_all);
+	list_add(&x->km.all, &net->xfrm.state_all);
 
-	h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
+	h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
 			  x->props.reqid, x->props.family);
-	hlist_add_head(&x->bydst, xfrm_state_bydst+h);
+	hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
 
-	h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
-	hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
+	h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family);
+	hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
 
 	if (x->id.spi) {
-		h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
+		h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto,
 				  x->props.family);
 
-		hlist_add_head(&x->byspi, xfrm_state_byspi+h);
+		hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
 	}
 
 	mod_timer(&x->timer, jiffies + HZ);
 	if (x->replay_maxage)
 		mod_timer(&x->rtimer, jiffies + x->replay_maxage);
 
-	wake_up(&km_waitq);
+	wake_up(&net->xfrm.km_waitq);
 
-	xfrm_state_num++;
+	net->xfrm.state_num++;
 
-	xfrm_hash_grow_check(x->bydst.next != NULL);
+	xfrm_hash_grow_check(net, x->bydst.next != NULL);
 }
 
 /* xfrm_state_lock is held */
 static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
 {
+	struct net *net = xs_net(xnew);
 	unsigned short family = xnew->props.family;
 	u32 reqid = xnew->props.reqid;
 	struct xfrm_state *x;
 	struct hlist_node *entry;
 	unsigned int h;
 
-	h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family);
-	hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
+	h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family);
+	hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
 		if (x->props.family	== family &&
 		    x->props.reqid	== reqid &&
 		    !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
@@ -979,13 +963,13 @@
 EXPORT_SYMBOL(xfrm_state_insert);
 
 /* xfrm_state_lock is held */
-static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create)
+static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create)
 {
-	unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
+	unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
 	struct hlist_node *entry;
 	struct xfrm_state *x;
 
-	hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
+	hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
 		if (x->props.reqid  != reqid ||
 		    x->props.mode   != mode ||
 		    x->props.family != family ||
@@ -1017,7 +1001,7 @@
 	if (!create)
 		return NULL;
 
-	x = xfrm_state_alloc();
+	x = xfrm_state_alloc(net);
 	if (likely(x)) {
 		switch (family) {
 		case AF_INET:
@@ -1048,27 +1032,28 @@
 		x->props.family = family;
 		x->props.mode = mode;
 		x->props.reqid = reqid;
-		x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires;
+		x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
 		xfrm_state_hold(x);
-		x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
+		x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ;
 		add_timer(&x->timer);
-		list_add(&x->km.all, &xfrm_state_all);
-		hlist_add_head(&x->bydst, xfrm_state_bydst+h);
-		h = xfrm_src_hash(daddr, saddr, family);
-		hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
+		list_add(&x->km.all, &net->xfrm.state_all);
+		hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
+		h = xfrm_src_hash(net, daddr, saddr, family);
+		hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
 
-		xfrm_state_num++;
+		net->xfrm.state_num++;
 
-		xfrm_hash_grow_check(x->bydst.next != NULL);
+		xfrm_hash_grow_check(net, x->bydst.next != NULL);
 	}
 
 	return x;
 }
 
-static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
+static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq);
 
 int xfrm_state_add(struct xfrm_state *x)
 {
+	struct net *net = xs_net(x);
 	struct xfrm_state *x1, *to_put;
 	int family;
 	int err;
@@ -1089,7 +1074,7 @@
 	}
 
 	if (use_spi && x->km.seq) {
-		x1 = __xfrm_find_acq_byseq(x->km.seq);
+		x1 = __xfrm_find_acq_byseq(net, x->km.seq);
 		if (x1 && ((x1->id.proto != x->id.proto) ||
 		    xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
 			to_put = x1;
@@ -1098,7 +1083,7 @@
 	}
 
 	if (use_spi && !x1)
-		x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
+		x1 = __find_acq_core(net, family, x->props.mode, x->props.reqid,
 				     x->id.proto,
 				     &x->id.daddr, &x->props.saddr, 0);
 
@@ -1124,8 +1109,9 @@
 #ifdef CONFIG_XFRM_MIGRATE
 static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
 {
+	struct net *net = xs_net(orig);
 	int err = -ENOMEM;
-	struct xfrm_state *x = xfrm_state_alloc();
+	struct xfrm_state *x = xfrm_state_alloc(net);
 	if (!x)
 		goto error;
 
@@ -1206,9 +1192,9 @@
 	struct hlist_node *entry;
 
 	if (m->reqid) {
-		h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr,
+		h = xfrm_dst_hash(&init_net, &m->old_daddr, &m->old_saddr,
 				  m->reqid, m->old_family);
-		hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
+		hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) {
 			if (x->props.mode != m->mode ||
 			    x->id.proto != m->proto)
 				continue;
@@ -1223,9 +1209,9 @@
 			return x;
 		}
 	} else {
-		h = xfrm_src_hash(&m->old_daddr, &m->old_saddr,
+		h = xfrm_src_hash(&init_net, &m->old_daddr, &m->old_saddr,
 				  m->old_family);
-		hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) {
+		hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) {
 			if (x->props.mode != m->mode ||
 			    x->id.proto != m->proto)
 				continue;
@@ -1369,40 +1355,41 @@
 EXPORT_SYMBOL(xfrm_state_check_expire);
 
 struct xfrm_state *
-xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
+xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto,
 		  unsigned short family)
 {
 	struct xfrm_state *x;
 
 	spin_lock_bh(&xfrm_state_lock);
-	x = __xfrm_state_lookup(daddr, spi, proto, family);
+	x = __xfrm_state_lookup(net, daddr, spi, proto, family);
 	spin_unlock_bh(&xfrm_state_lock);
 	return x;
 }
 EXPORT_SYMBOL(xfrm_state_lookup);
 
 struct xfrm_state *
-xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
+xfrm_state_lookup_byaddr(struct net *net,
+			 xfrm_address_t *daddr, xfrm_address_t *saddr,
 			 u8 proto, unsigned short family)
 {
 	struct xfrm_state *x;
 
 	spin_lock_bh(&xfrm_state_lock);
-	x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
+	x = __xfrm_state_lookup_byaddr(net, daddr, saddr, proto, family);
 	spin_unlock_bh(&xfrm_state_lock);
 	return x;
 }
 EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
 
 struct xfrm_state *
-xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
+xfrm_find_acq(struct net *net, u8 mode, u32 reqid, u8 proto,
 	      xfrm_address_t *daddr, xfrm_address_t *saddr,
 	      int create, unsigned short family)
 {
 	struct xfrm_state *x;
 
 	spin_lock_bh(&xfrm_state_lock);
-	x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
+	x = __find_acq_core(net, family, mode, reqid, proto, daddr, saddr, create);
 	spin_unlock_bh(&xfrm_state_lock);
 
 	return x;
@@ -1449,15 +1436,15 @@
 
 /* Silly enough, but I'm lazy to build resolution list */
 
-static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq)
+static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq)
 {
 	int i;
 
-	for (i = 0; i <= xfrm_state_hmask; i++) {
+	for (i = 0; i <= net->xfrm.state_hmask; i++) {
 		struct hlist_node *entry;
 		struct xfrm_state *x;
 
-		hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
+		hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) {
 			if (x->km.seq == seq &&
 			    x->km.state == XFRM_STATE_ACQ) {
 				xfrm_state_hold(x);
@@ -1468,12 +1455,12 @@
 	return NULL;
 }
 
-struct xfrm_state *xfrm_find_acq_byseq(u32 seq)
+struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 seq)
 {
 	struct xfrm_state *x;
 
 	spin_lock_bh(&xfrm_state_lock);
-	x = __xfrm_find_acq_byseq(seq);
+	x = __xfrm_find_acq_byseq(net, seq);
 	spin_unlock_bh(&xfrm_state_lock);
 	return x;
 }
@@ -1494,6 +1481,7 @@
 
 int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
 {
+	struct net *net = xs_net(x);
 	unsigned int h;
 	struct xfrm_state *x0;
 	int err = -ENOENT;
@@ -1511,7 +1499,7 @@
 	err = -ENOENT;
 
 	if (minspi == maxspi) {
-		x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family);
+		x0 = xfrm_state_lookup(net, &x->id.daddr, minspi, x->id.proto, x->props.family);
 		if (x0) {
 			xfrm_state_put(x0);
 			goto unlock;
@@ -1521,7 +1509,7 @@
 		u32 spi = 0;
 		for (h=0; h<high-low+1; h++) {
 			spi = low + net_random()%(high-low+1);
-			x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
+			x0 = xfrm_state_lookup(net, &x->id.daddr, htonl(spi), x->id.proto, x->props.family);
 			if (x0 == NULL) {
 				x->id.spi = htonl(spi);
 				break;
@@ -1531,8 +1519,8 @@
 	}
 	if (x->id.spi) {
 		spin_lock_bh(&xfrm_state_lock);
-		h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
-		hlist_add_head(&x->byspi, xfrm_state_byspi+h);
+		h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
+		hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
 		spin_unlock_bh(&xfrm_state_lock);
 
 		err = 0;
@@ -1545,7 +1533,7 @@
 }
 EXPORT_SYMBOL(xfrm_alloc_spi);
 
-int xfrm_state_walk(struct xfrm_state_walk *walk,
+int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
 		    int (*func)(struct xfrm_state *, int, void*),
 		    void *data)
 {
@@ -1558,10 +1546,10 @@
 
 	spin_lock_bh(&xfrm_state_lock);
 	if (list_empty(&walk->all))
-		x = list_first_entry(&xfrm_state_all, struct xfrm_state_walk, all);
+		x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all);
 	else
 		x = list_entry(&walk->all, struct xfrm_state_walk, all);
-	list_for_each_entry_from(x, &xfrm_state_all, all) {
+	list_for_each_entry_from(x, &net->xfrm.state_all, all) {
 		if (x->state == XFRM_STATE_DEAD)
 			continue;
 		state = container_of(x, struct xfrm_state, km);
@@ -1660,7 +1648,7 @@
 	spin_lock(&x->lock);
 
 	if (x->km.state == XFRM_STATE_VALID) {
-		if (xfrm_aevent_is_on())
+		if (xfrm_aevent_is_on(xs_net(x)))
 			xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
 		else
 			x->xflags |= XFRM_TIME_DEFER;
@@ -1716,7 +1704,7 @@
 		x->replay.bitmap |= (1U << diff);
 	}
 
-	if (xfrm_aevent_is_on())
+	if (xfrm_aevent_is_on(xs_net(x)))
 		xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 }
 
@@ -1749,6 +1737,7 @@
 
 void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
 {
+	struct net *net = xs_net(x);
 	struct km_event c;
 
 	c.data.hard = hard;
@@ -1757,7 +1746,7 @@
 	km_state_notify(x, &c);
 
 	if (hard)
-		wake_up(&km_waitq);
+		wake_up(&net->xfrm.km_waitq);
 }
 
 EXPORT_SYMBOL(km_state_expired);
@@ -1800,6 +1789,7 @@
 
 void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
 {
+	struct net *net = xp_net(pol);
 	struct km_event c;
 
 	c.data.hard = hard;
@@ -1808,7 +1798,7 @@
 	km_policy_notify(pol, dir, &c);
 
 	if (hard)
-		wake_up(&km_waitq);
+		wake_up(&net->xfrm.km_waitq);
 }
 EXPORT_SYMBOL(km_policy_expired);
 
@@ -1835,7 +1825,7 @@
 EXPORT_SYMBOL(km_migrate);
 #endif
 
-int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
+int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
 {
 	int err = -EINVAL;
 	int ret;
@@ -1844,7 +1834,7 @@
 	read_lock(&xfrm_km_lock);
 	list_for_each_entry(km, &xfrm_km_list, list) {
 		if (km->report) {
-			ret = km->report(proto, sel, addr);
+			ret = km->report(net, proto, sel, addr);
 			if (!ret)
 				err = ret;
 		}
@@ -2032,8 +2022,9 @@
 		x->inner_mode = inner_mode;
 	} else {
 		struct xfrm_mode *inner_mode_iaf;
+		int iafamily = AF_INET;
 
-		inner_mode = xfrm_get_mode(x->props.mode, AF_INET);
+		inner_mode = xfrm_get_mode(x->props.mode, x->props.family);
 		if (inner_mode == NULL)
 			goto error;
 
@@ -2041,22 +2032,17 @@
 			xfrm_put_mode(inner_mode);
 			goto error;
 		}
+		x->inner_mode = inner_mode;
 
-		inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6);
-		if (inner_mode_iaf == NULL)
-			goto error;
+		if (x->props.family == AF_INET)
+			iafamily = AF_INET6;
 
-		if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) {
-			xfrm_put_mode(inner_mode_iaf);
-			goto error;
-		}
-
-		if (x->props.family == AF_INET) {
-			x->inner_mode = inner_mode;
-			x->inner_mode_iaf = inner_mode_iaf;
-		} else {
-			x->inner_mode = inner_mode_iaf;
-			x->inner_mode_iaf = inner_mode;
+		inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily);
+		if (inner_mode_iaf) {
+			if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)
+				x->inner_mode_iaf = inner_mode_iaf;
+			else
+				xfrm_put_mode(inner_mode_iaf);
 		}
 	}
 
@@ -2080,20 +2066,61 @@
 
 EXPORT_SYMBOL(xfrm_init_state);
 
-void __init xfrm_state_init(void)
+int __net_init xfrm_state_init(struct net *net)
 {
 	unsigned int sz;
 
+	INIT_LIST_HEAD(&net->xfrm.state_all);
+
 	sz = sizeof(struct hlist_head) * 8;
 
-	xfrm_state_bydst = xfrm_hash_alloc(sz);
-	xfrm_state_bysrc = xfrm_hash_alloc(sz);
-	xfrm_state_byspi = xfrm_hash_alloc(sz);
-	if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi)
-		panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes.");
-	xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
+	net->xfrm.state_bydst = xfrm_hash_alloc(sz);
+	if (!net->xfrm.state_bydst)
+		goto out_bydst;
+	net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
+	if (!net->xfrm.state_bysrc)
+		goto out_bysrc;
+	net->xfrm.state_byspi = xfrm_hash_alloc(sz);
+	if (!net->xfrm.state_byspi)
+		goto out_byspi;
+	net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
 
-	INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task);
+	net->xfrm.state_num = 0;
+	INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
+	INIT_HLIST_HEAD(&net->xfrm.state_gc_list);
+	INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task);
+	init_waitqueue_head(&net->xfrm.km_waitq);
+	return 0;
+
+out_byspi:
+	xfrm_hash_free(net->xfrm.state_bysrc, sz);
+out_bysrc:
+	xfrm_hash_free(net->xfrm.state_bydst, sz);
+out_bydst:
+	return -ENOMEM;
+}
+
+void xfrm_state_fini(struct net *net)
+{
+	struct xfrm_audit audit_info;
+	unsigned int sz;
+
+	flush_work(&net->xfrm.state_hash_work);
+	audit_info.loginuid = -1;
+	audit_info.sessionid = -1;
+	audit_info.secid = 0;
+	xfrm_state_flush(net, IPSEC_PROTO_ANY, &audit_info);
+	flush_work(&net->xfrm.state_gc_work);
+
+	WARN_ON(!list_empty(&net->xfrm.state_all));
+
+	sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
+	WARN_ON(!hlist_empty(net->xfrm.state_byspi));
+	xfrm_hash_free(net->xfrm.state_byspi, sz);
+	WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
+	xfrm_hash_free(net->xfrm.state_bysrc, sz);
+	WARN_ON(!hlist_empty(net->xfrm.state_bydst));
+	xfrm_hash_free(net->xfrm.state_bydst, sz);
 }
 
 #ifdef CONFIG_AUDITSYSCALL
@@ -2109,16 +2136,12 @@
 
 	switch(x->props.family) {
 	case AF_INET:
-		audit_log_format(audit_buf,
-				 " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT,
-				 NIPQUAD(x->props.saddr.a4),
-				 NIPQUAD(x->id.daddr.a4));
+		audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
+				 &x->props.saddr.a4, &x->id.daddr.a4);
 		break;
 	case AF_INET6:
-		audit_log_format(audit_buf,
-				 " src=" NIP6_FMT " dst=" NIP6_FMT,
-				 NIP6(*(struct in6_addr *)x->props.saddr.a6),
-				 NIP6(*(struct in6_addr *)x->id.daddr.a6));
+		audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
+				 x->props.saddr.a6, x->id.daddr.a6);
 		break;
 	}
 
@@ -2134,18 +2157,14 @@
 	switch (family) {
 	case AF_INET:
 		iph4 = ip_hdr(skb);
-		audit_log_format(audit_buf,
-				 " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT,
-				 NIPQUAD(iph4->saddr),
-				 NIPQUAD(iph4->daddr));
+		audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
+				 &iph4->saddr, &iph4->daddr);
 		break;
 	case AF_INET6:
 		iph6 = ipv6_hdr(skb);
 		audit_log_format(audit_buf,
-				 " src=" NIP6_FMT " dst=" NIP6_FMT
-				 " flowlbl=0x%x%02x%02x",
-				 NIP6(iph6->saddr),
-				 NIP6(iph6->daddr),
+				 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
+				 &iph6->saddr,&iph6->daddr,
 				 iph6->flow_lbl[0] & 0x0f,
 				 iph6->flow_lbl[1],
 				 iph6->flow_lbl[2]);
diff --git a/net/xfrm/xfrm_sysctl.c b/net/xfrm/xfrm_sysctl.c
new file mode 100644
index 0000000..2e6ffb6
--- /dev/null
+++ b/net/xfrm/xfrm_sysctl.c
@@ -0,0 +1,85 @@
+#include <linux/sysctl.h>
+#include <net/net_namespace.h>
+#include <net/xfrm.h>
+
+static void __xfrm_sysctl_init(struct net *net)
+{
+	net->xfrm.sysctl_aevent_etime = XFRM_AE_ETIME;
+	net->xfrm.sysctl_aevent_rseqth = XFRM_AE_SEQT_SIZE;
+	net->xfrm.sysctl_larval_drop = 1;
+	net->xfrm.sysctl_acq_expires = 30;
+}
+
+#ifdef CONFIG_SYSCTL
+static struct ctl_table xfrm_table[] = {
+	{
+		.ctl_name	= NET_CORE_AEVENT_ETIME,
+		.procname	= "xfrm_aevent_etime",
+		.maxlen		= sizeof(u32),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+	{
+		.ctl_name	= NET_CORE_AEVENT_RSEQTH,
+		.procname	= "xfrm_aevent_rseqth",
+		.maxlen		= sizeof(u32),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "xfrm_larval_drop",
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "xfrm_acq_expires",
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+	{}
+};
+
+int __net_init xfrm_sysctl_init(struct net *net)
+{
+	struct ctl_table *table;
+
+	__xfrm_sysctl_init(net);
+
+	table = kmemdup(xfrm_table, sizeof(xfrm_table), GFP_KERNEL);
+	if (!table)
+		goto out_kmemdup;
+	table[0].data = &net->xfrm.sysctl_aevent_etime;
+	table[1].data = &net->xfrm.sysctl_aevent_rseqth;
+	table[2].data = &net->xfrm.sysctl_larval_drop;
+	table[3].data = &net->xfrm.sysctl_acq_expires;
+
+	net->xfrm.sysctl_hdr = register_net_sysctl_table(net, net_core_path, table);
+	if (!net->xfrm.sysctl_hdr)
+		goto out_register;
+	return 0;
+
+out_register:
+	kfree(table);
+out_kmemdup:
+	return -ENOMEM;
+}
+
+void xfrm_sysctl_fini(struct net *net)
+{
+	struct ctl_table *table;
+
+	table = net->xfrm.sysctl_hdr->ctl_table_arg;
+	unregister_net_sysctl_table(net->xfrm.sysctl_hdr);
+	kfree(table);
+}
+#else
+int __net_init xfrm_sysctl_init(struct net *net)
+{
+	__xfrm_sysctl_init(net);
+	return 0;
+}
+#endif
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index a278a6f..b95a2d6 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -316,11 +316,12 @@
 		x->replay_maxdiff = nla_get_u32(rt);
 }
 
-static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
+static struct xfrm_state *xfrm_state_construct(struct net *net,
+					       struct xfrm_usersa_info *p,
 					       struct nlattr **attrs,
 					       int *errp)
 {
-	struct xfrm_state *x = xfrm_state_alloc();
+	struct xfrm_state *x = xfrm_state_alloc(net);
 	int err = -ENOMEM;
 
 	if (!x)
@@ -367,9 +368,9 @@
 		goto error;
 
 	x->km.seq = p->seq;
-	x->replay_maxdiff = sysctl_xfrm_aevent_rseqth;
+	x->replay_maxdiff = net->xfrm.sysctl_aevent_rseqth;
 	/* sysctl_xfrm_aevent_etime is in 100ms units */
-	x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M;
+	x->replay_maxage = (net->xfrm.sysctl_aevent_etime*HZ)/XFRM_AE_ETH_M;
 	x->preplay.bitmap = 0;
 	x->preplay.seq = x->replay.seq+x->replay_maxdiff;
 	x->preplay.oseq = x->replay.oseq +x->replay_maxdiff;
@@ -391,6 +392,7 @@
 static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_usersa_info *p = nlmsg_data(nlh);
 	struct xfrm_state *x;
 	int err;
@@ -403,7 +405,7 @@
 	if (err)
 		return err;
 
-	x = xfrm_state_construct(p, attrs, &err);
+	x = xfrm_state_construct(net, p, attrs, &err);
 	if (!x)
 		return err;
 
@@ -431,7 +433,8 @@
 	return err;
 }
 
-static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p,
+static struct xfrm_state *xfrm_user_state_lookup(struct net *net,
+						 struct xfrm_usersa_id *p,
 						 struct nlattr **attrs,
 						 int *errp)
 {
@@ -440,7 +443,7 @@
 
 	if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) {
 		err = -ESRCH;
-		x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
+		x = xfrm_state_lookup(net, &p->daddr, p->spi, p->proto, p->family);
 	} else {
 		xfrm_address_t *saddr = NULL;
 
@@ -451,8 +454,8 @@
 		}
 
 		err = -ESRCH;
-		x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto,
-					     p->family);
+		x = xfrm_state_lookup_byaddr(net, &p->daddr, saddr,
+					     p->proto, p->family);
 	}
 
  out:
@@ -464,6 +467,7 @@
 static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_state *x;
 	int err = -ESRCH;
 	struct km_event c;
@@ -472,7 +476,7 @@
 	u32 sessionid = NETLINK_CB(skb).sessionid;
 	u32 sid = NETLINK_CB(skb).sid;
 
-	x = xfrm_user_state_lookup(p, attrs, &err);
+	x = xfrm_user_state_lookup(net, p, attrs, &err);
 	if (x == NULL)
 		return err;
 
@@ -615,6 +619,7 @@
 
 static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
 	struct xfrm_dump_info info;
 
@@ -631,7 +636,7 @@
 		xfrm_state_walk_init(walk, 0);
 	}
 
-	(void) xfrm_state_walk(walk, dump_one_state, &info);
+	(void) xfrm_state_walk(net, walk, dump_one_state, &info);
 
 	return skb->len;
 }
@@ -703,6 +708,7 @@
 static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct sk_buff *r_skb;
 	u32 *flags = nlmsg_data(nlh);
 	u32 spid = NETLINK_CB(skb).pid;
@@ -715,7 +721,7 @@
 	if (build_spdinfo(r_skb, spid, seq, *flags) < 0)
 		BUG();
 
-	return nlmsg_unicast(xfrm_nl, r_skb, spid);
+	return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid);
 }
 
 static inline size_t xfrm_sadinfo_msgsize(void)
@@ -756,6 +762,7 @@
 static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct sk_buff *r_skb;
 	u32 *flags = nlmsg_data(nlh);
 	u32 spid = NETLINK_CB(skb).pid;
@@ -768,18 +775,19 @@
 	if (build_sadinfo(r_skb, spid, seq, *flags) < 0)
 		BUG();
 
-	return nlmsg_unicast(xfrm_nl, r_skb, spid);
+	return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid);
 }
 
 static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_usersa_id *p = nlmsg_data(nlh);
 	struct xfrm_state *x;
 	struct sk_buff *resp_skb;
 	int err = -ESRCH;
 
-	x = xfrm_user_state_lookup(p, attrs, &err);
+	x = xfrm_user_state_lookup(net, p, attrs, &err);
 	if (x == NULL)
 		goto out_noput;
 
@@ -787,7 +795,7 @@
 	if (IS_ERR(resp_skb)) {
 		err = PTR_ERR(resp_skb);
 	} else {
-		err = nlmsg_unicast(xfrm_nl, resp_skb, NETLINK_CB(skb).pid);
+		err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).pid);
 	}
 	xfrm_state_put(x);
 out_noput:
@@ -820,6 +828,7 @@
 static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_state *x;
 	struct xfrm_userspi_info *p;
 	struct sk_buff *resp_skb;
@@ -837,7 +846,7 @@
 
 	x = NULL;
 	if (p->info.seq) {
-		x = xfrm_find_acq_byseq(p->info.seq);
+		x = xfrm_find_acq_byseq(net, p->info.seq);
 		if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) {
 			xfrm_state_put(x);
 			x = NULL;
@@ -845,7 +854,7 @@
 	}
 
 	if (!x)
-		x = xfrm_find_acq(p->info.mode, p->info.reqid,
+		x = xfrm_find_acq(net, p->info.mode, p->info.reqid,
 				  p->info.id.proto, daddr,
 				  &p->info.saddr, 1,
 				  family);
@@ -863,7 +872,7 @@
 		goto out;
 	}
 
-	err = nlmsg_unicast(xfrm_nl, resp_skb, NETLINK_CB(skb).pid);
+	err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).pid);
 
 out:
 	xfrm_state_put(x);
@@ -1078,9 +1087,9 @@
 	p->share = XFRM_SHARE_ANY; /* XXX xp->share */
 }
 
-static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp)
+static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp)
 {
-	struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL);
+	struct xfrm_policy *xp = xfrm_policy_alloc(net, GFP_KERNEL);
 	int err;
 
 	if (!xp) {
@@ -1110,6 +1119,7 @@
 static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_userpolicy_info *p = nlmsg_data(nlh);
 	struct xfrm_policy *xp;
 	struct km_event c;
@@ -1126,7 +1136,7 @@
 	if (err)
 		return err;
 
-	xp = xfrm_policy_construct(p, attrs, &err);
+	xp = xfrm_policy_construct(net, p, attrs, &err);
 	if (!xp)
 		return err;
 
@@ -1263,6 +1273,7 @@
 
 static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
 	struct xfrm_dump_info info;
 
@@ -1279,7 +1290,7 @@
 		xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY);
 	}
 
-	(void) xfrm_policy_walk(walk, dump_one_policy, &info);
+	(void) xfrm_policy_walk(net, walk, dump_one_policy, &info);
 
 	return skb->len;
 }
@@ -1311,6 +1322,7 @@
 static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_policy *xp;
 	struct xfrm_userpolicy_id *p;
 	u8 type = XFRM_POLICY_TYPE_MAIN;
@@ -1330,7 +1342,7 @@
 		return err;
 
 	if (p->index)
-		xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err);
+		xp = xfrm_policy_byid(net, type, p->dir, p->index, delete, &err);
 	else {
 		struct nlattr *rt = attrs[XFRMA_SEC_CTX];
 		struct xfrm_sec_ctx *ctx;
@@ -1347,7 +1359,7 @@
 			if (err)
 				return err;
 		}
-		xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx,
+		xp = xfrm_policy_bysel_ctx(net, type, p->dir, &p->sel, ctx,
 					   delete, &err);
 		security_xfrm_policy_free(ctx);
 	}
@@ -1361,7 +1373,7 @@
 		if (IS_ERR(resp_skb)) {
 			err = PTR_ERR(resp_skb);
 		} else {
-			err = nlmsg_unicast(xfrm_nl, resp_skb,
+			err = nlmsg_unicast(net->xfrm.nlsk, resp_skb,
 					    NETLINK_CB(skb).pid);
 		}
 	} else {
@@ -1390,6 +1402,7 @@
 static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct km_event c;
 	struct xfrm_usersa_flush *p = nlmsg_data(nlh);
 	struct xfrm_audit audit_info;
@@ -1398,13 +1411,14 @@
 	audit_info.loginuid = NETLINK_CB(skb).loginuid;
 	audit_info.sessionid = NETLINK_CB(skb).sessionid;
 	audit_info.secid = NETLINK_CB(skb).sid;
-	err = xfrm_state_flush(p->proto, &audit_info);
+	err = xfrm_state_flush(net, p->proto, &audit_info);
 	if (err)
 		return err;
 	c.data.proto = p->proto;
 	c.event = nlh->nlmsg_type;
 	c.seq = nlh->nlmsg_seq;
 	c.pid = nlh->nlmsg_pid;
+	c.net = net;
 	km_state_notify(NULL, &c);
 
 	return 0;
@@ -1457,6 +1471,7 @@
 static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_state *x;
 	struct sk_buff *r_skb;
 	int err;
@@ -1468,7 +1483,7 @@
 	if (r_skb == NULL)
 		return -ENOMEM;
 
-	x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family);
+	x = xfrm_state_lookup(net, &id->daddr, id->spi, id->proto, id->family);
 	if (x == NULL) {
 		kfree_skb(r_skb);
 		return -ESRCH;
@@ -1486,7 +1501,7 @@
 
 	if (build_aevent(r_skb, x, &c) < 0)
 		BUG();
-	err = nlmsg_unicast(xfrm_nl, r_skb, NETLINK_CB(skb).pid);
+	err = nlmsg_unicast(net->xfrm.nlsk, r_skb, NETLINK_CB(skb).pid);
 	spin_unlock_bh(&x->lock);
 	xfrm_state_put(x);
 	return err;
@@ -1495,6 +1510,7 @@
 static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_state *x;
 	struct km_event c;
 	int err = - EINVAL;
@@ -1509,7 +1525,7 @@
 	if (!(nlh->nlmsg_flags&NLM_F_REPLACE))
 		return err;
 
-	x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family);
+	x = xfrm_state_lookup(net, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family);
 	if (x == NULL)
 		return -ESRCH;
 
@@ -1534,6 +1550,7 @@
 static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct km_event c;
 	u8 type = XFRM_POLICY_TYPE_MAIN;
 	int err;
@@ -1546,13 +1563,14 @@
 	audit_info.loginuid = NETLINK_CB(skb).loginuid;
 	audit_info.sessionid = NETLINK_CB(skb).sessionid;
 	audit_info.secid = NETLINK_CB(skb).sid;
-	err = xfrm_policy_flush(type, &audit_info);
+	err = xfrm_policy_flush(net, type, &audit_info);
 	if (err)
 		return err;
 	c.data.type = type;
 	c.event = nlh->nlmsg_type;
 	c.seq = nlh->nlmsg_seq;
 	c.pid = nlh->nlmsg_pid;
+	c.net = net;
 	km_policy_notify(NULL, 0, &c);
 	return 0;
 }
@@ -1560,6 +1578,7 @@
 static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_policy *xp;
 	struct xfrm_user_polexpire *up = nlmsg_data(nlh);
 	struct xfrm_userpolicy_info *p = &up->pol;
@@ -1571,7 +1590,7 @@
 		return err;
 
 	if (p->index)
-		xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err);
+		xp = xfrm_policy_byid(net, type, p->dir, p->index, 0, &err);
 	else {
 		struct nlattr *rt = attrs[XFRMA_SEC_CTX];
 		struct xfrm_sec_ctx *ctx;
@@ -1588,7 +1607,7 @@
 			if (err)
 				return err;
 		}
-		xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, 0, &err);
+		xp = xfrm_policy_bysel_ctx(net, type, p->dir, &p->sel, ctx, 0, &err);
 		security_xfrm_policy_free(ctx);
 	}
 	if (xp == NULL)
@@ -1623,12 +1642,13 @@
 static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_state *x;
 	int err;
 	struct xfrm_user_expire *ue = nlmsg_data(nlh);
 	struct xfrm_usersa_info *p = &ue->state;
 
-	x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family);
+	x = xfrm_state_lookup(net, &p->id.daddr, p->id.spi, p->id.proto, p->family);
 
 	err = -ENOENT;
 	if (x == NULL)
@@ -1657,31 +1677,27 @@
 static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct nlattr **attrs)
 {
+	struct net *net = sock_net(skb->sk);
 	struct xfrm_policy *xp;
 	struct xfrm_user_tmpl *ut;
 	int i;
 	struct nlattr *rt = attrs[XFRMA_TMPL];
 
 	struct xfrm_user_acquire *ua = nlmsg_data(nlh);
-	struct xfrm_state *x = xfrm_state_alloc();
+	struct xfrm_state *x = xfrm_state_alloc(net);
 	int err = -ENOMEM;
 
 	if (!x)
-		return err;
+		goto nomem;
 
 	err = verify_newpolicy_info(&ua->policy);
-	if (err) {
-		printk("BAD policy passed\n");
-		kfree(x);
-		return err;
-	}
+	if (err)
+		goto bad_policy;
 
 	/*   build an XP */
-	xp = xfrm_policy_construct(&ua->policy, attrs, &err);
-	if (!xp) {
-		kfree(x);
-		return err;
-	}
+	xp = xfrm_policy_construct(net, &ua->policy, attrs, &err);
+	if (!xp)
+		goto free_state;
 
 	memcpy(&x->id, &ua->id, sizeof(ua->id));
 	memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr));
@@ -1706,6 +1722,13 @@
 	kfree(xp);
 
 	return 0;
+
+bad_policy:
+	printk("BAD policy passed\n");
+free_state:
+	kfree(x);
+nomem:
+	return err;
 }
 
 #ifdef CONFIG_XFRM_MIGRATE
@@ -1869,6 +1892,7 @@
 			     struct xfrm_migrate *m, int num_migrate,
 			     struct xfrm_kmaddress *k)
 {
+	struct net *net = &init_net;
 	struct sk_buff *skb;
 
 	skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC);
@@ -1879,7 +1903,7 @@
 	if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0)
 		BUG();
 
-	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC);
+	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC);
 }
 #else
 static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
@@ -1968,6 +1992,7 @@
 
 static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
+	struct net *net = sock_net(skb->sk);
 	struct nlattr *attrs[XFRMA_MAX+1];
 	struct xfrm_link *link;
 	int type, err;
@@ -1989,7 +2014,7 @@
 		if (link->dump == NULL)
 			return -EINVAL;
 
-		return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done);
+		return netlink_dump_start(net->xfrm.nlsk, skb, nlh, link->dump, link->done);
 	}
 
 	err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,
@@ -2033,6 +2058,7 @@
 
 static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
 {
+	struct net *net = xs_net(x);
 	struct sk_buff *skb;
 
 	skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC);
@@ -2042,11 +2068,12 @@
 	if (build_expire(skb, x, c) < 0)
 		BUG();
 
-	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
+	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
 }
 
 static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c)
 {
+	struct net *net = xs_net(x);
 	struct sk_buff *skb;
 
 	skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC);
@@ -2056,11 +2083,12 @@
 	if (build_aevent(skb, x, c) < 0)
 		BUG();
 
-	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC);
+	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC);
 }
 
 static int xfrm_notify_sa_flush(struct km_event *c)
 {
+	struct net *net = c->net;
 	struct xfrm_usersa_flush *p;
 	struct nlmsghdr *nlh;
 	struct sk_buff *skb;
@@ -2081,7 +2109,7 @@
 
 	nlmsg_end(skb, nlh);
 
-	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
+	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
 }
 
 static inline size_t xfrm_sa_len(struct xfrm_state *x)
@@ -2111,6 +2139,7 @@
 
 static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c)
 {
+	struct net *net = xs_net(x);
 	struct xfrm_usersa_info *p;
 	struct xfrm_usersa_id *id;
 	struct nlmsghdr *nlh;
@@ -2155,7 +2184,7 @@
 
 	nlmsg_end(skb, nlh);
 
-	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
+	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
 
 nla_put_failure:
 	/* Somebody screwed up with xfrm_sa_len! */
@@ -2235,6 +2264,7 @@
 static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
 			     struct xfrm_policy *xp, int dir)
 {
+	struct net *net = xs_net(x);
 	struct sk_buff *skb;
 
 	skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC);
@@ -2244,7 +2274,7 @@
 	if (build_acquire(skb, x, xt, xp, dir) < 0)
 		BUG();
 
-	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC);
+	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC);
 }
 
 /* User gives us xfrm_user_policy_info followed by an array of 0
@@ -2253,6 +2283,7 @@
 static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,
 					       u8 *data, int len, int *dir)
 {
+	struct net *net = sock_net(sk);
 	struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data;
 	struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (p + 1);
 	struct xfrm_policy *xp;
@@ -2291,7 +2322,7 @@
 	if (p->dir > XFRM_POLICY_OUT)
 		return NULL;
 
-	xp = xfrm_policy_alloc(GFP_KERNEL);
+	xp = xfrm_policy_alloc(net, GFP_KERNEL);
 	if (xp == NULL) {
 		*dir = -ENOBUFS;
 		return NULL;
@@ -2344,6 +2375,7 @@
 
 static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
 {
+	struct net *net = xp_net(xp);
 	struct sk_buff *skb;
 
 	skb = nlmsg_new(xfrm_polexpire_msgsize(xp), GFP_ATOMIC);
@@ -2353,11 +2385,12 @@
 	if (build_polexpire(skb, xp, dir, c) < 0)
 		BUG();
 
-	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
+	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
 }
 
 static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c)
 {
+	struct net *net = xp_net(xp);
 	struct xfrm_userpolicy_info *p;
 	struct xfrm_userpolicy_id *id;
 	struct nlmsghdr *nlh;
@@ -2408,7 +2441,7 @@
 
 	nlmsg_end(skb, nlh);
 
-	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
+	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
 
 nlmsg_failure:
 	kfree_skb(skb);
@@ -2417,6 +2450,7 @@
 
 static int xfrm_notify_policy_flush(struct km_event *c)
 {
+	struct net *net = c->net;
 	struct nlmsghdr *nlh;
 	struct sk_buff *skb;
 
@@ -2432,7 +2466,7 @@
 
 	nlmsg_end(skb, nlh);
 
-	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
+	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
 
 nlmsg_failure:
 	kfree_skb(skb);
@@ -2488,8 +2522,8 @@
 	return -EMSGSIZE;
 }
 
-static int xfrm_send_report(u8 proto, struct xfrm_selector *sel,
-			    xfrm_address_t *addr)
+static int xfrm_send_report(struct net *net, u8 proto,
+			    struct xfrm_selector *sel, xfrm_address_t *addr)
 {
 	struct sk_buff *skb;
 
@@ -2500,7 +2534,59 @@
 	if (build_report(skb, proto, sel, addr) < 0)
 		BUG();
 
-	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC);
+	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC);
+}
+
+static inline size_t xfrm_mapping_msgsize(void)
+{
+	return NLMSG_ALIGN(sizeof(struct xfrm_user_mapping));
+}
+
+static int build_mapping(struct sk_buff *skb, struct xfrm_state *x,
+			 xfrm_address_t *new_saddr, __be16 new_sport)
+{
+	struct xfrm_user_mapping *um;
+	struct nlmsghdr *nlh;
+
+	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MAPPING, sizeof(*um), 0);
+	if (nlh == NULL)
+		return -EMSGSIZE;
+
+	um = nlmsg_data(nlh);
+
+	memcpy(&um->id.daddr, &x->id.daddr, sizeof(um->id.daddr));
+	um->id.spi = x->id.spi;
+	um->id.family = x->props.family;
+	um->id.proto = x->id.proto;
+	memcpy(&um->new_saddr, new_saddr, sizeof(um->new_saddr));
+	memcpy(&um->old_saddr, &x->props.saddr, sizeof(um->old_saddr));
+	um->new_sport = new_sport;
+	um->old_sport = x->encap->encap_sport;
+	um->reqid = x->props.reqid;
+
+	return nlmsg_end(skb, nlh);
+}
+
+static int xfrm_send_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
+			     __be16 sport)
+{
+	struct net *net = xs_net(x);
+	struct sk_buff *skb;
+
+	if (x->id.proto != IPPROTO_ESP)
+		return -EINVAL;
+
+	if (!x->encap)
+		return -EINVAL;
+
+	skb = nlmsg_new(xfrm_mapping_msgsize(), GFP_ATOMIC);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	if (build_mapping(skb, x, ipaddr, sport) < 0)
+		BUG();
+
+	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MAPPING, GFP_ATOMIC);
 }
 
 static struct xfrm_mgr netlink_mgr = {
@@ -2511,33 +2597,54 @@
 	.notify_policy	= xfrm_send_policy_notify,
 	.report		= xfrm_send_report,
 	.migrate	= xfrm_send_migrate,
+	.new_mapping	= xfrm_send_mapping,
+};
+
+static int __net_init xfrm_user_net_init(struct net *net)
+{
+	struct sock *nlsk;
+
+	nlsk = netlink_kernel_create(net, NETLINK_XFRM, XFRMNLGRP_MAX,
+				     xfrm_netlink_rcv, NULL, THIS_MODULE);
+	if (nlsk == NULL)
+		return -ENOMEM;
+	rcu_assign_pointer(net->xfrm.nlsk, nlsk);
+	return 0;
+}
+
+static void __net_exit xfrm_user_net_exit(struct net *net)
+{
+	struct sock *nlsk = net->xfrm.nlsk;
+
+	rcu_assign_pointer(net->xfrm.nlsk, NULL);
+	synchronize_rcu();
+	netlink_kernel_release(nlsk);
+}
+
+static struct pernet_operations xfrm_user_net_ops = {
+	.init = xfrm_user_net_init,
+	.exit = xfrm_user_net_exit,
 };
 
 static int __init xfrm_user_init(void)
 {
-	struct sock *nlsk;
+	int rv;
 
 	printk(KERN_INFO "Initializing XFRM netlink socket\n");
 
-	nlsk = netlink_kernel_create(&init_net, NETLINK_XFRM, XFRMNLGRP_MAX,
-				     xfrm_netlink_rcv, NULL, THIS_MODULE);
-	if (nlsk == NULL)
-		return -ENOMEM;
-	rcu_assign_pointer(xfrm_nl, nlsk);
-
-	xfrm_register_km(&netlink_mgr);
-
-	return 0;
+	rv = register_pernet_subsys(&xfrm_user_net_ops);
+	if (rv < 0)
+		return rv;
+	rv = xfrm_register_km(&netlink_mgr);
+	if (rv < 0)
+		unregister_pernet_subsys(&xfrm_user_net_ops);
+	return rv;
 }
 
 static void __exit xfrm_user_exit(void)
 {
-	struct sock *nlsk = xfrm_nl;
-
 	xfrm_unregister_km(&netlink_mgr);
-	rcu_assign_pointer(xfrm_nl, NULL);
-	synchronize_rcu();
-	netlink_kernel_release(nlsk);
+	unregister_pernet_subsys(&xfrm_user_net_ops);
 }
 
 module_init(xfrm_user_init);
diff --git a/samples/tracepoints/tp-samples-trace.h b/samples/tracepoints/tp-samples-trace.h
index 0216b55..01724e0 100644
--- a/samples/tracepoints/tp-samples-trace.h
+++ b/samples/tracepoints/tp-samples-trace.h
@@ -4,10 +4,10 @@
 #include <linux/proc_fs.h>	/* for struct inode and struct file */
 #include <linux/tracepoint.h>
 
-DEFINE_TRACE(subsys_event,
+DECLARE_TRACE(subsys_event,
 	TPPROTO(struct inode *inode, struct file *file),
 	TPARGS(inode, file));
-DEFINE_TRACE(subsys_eventb,
+DECLARE_TRACE(subsys_eventb,
 	TPPROTO(void),
 	TPARGS());
 #endif
diff --git a/samples/tracepoints/tracepoint-probe-sample.c b/samples/tracepoints/tracepoint-probe-sample.c
index 55abfdd..e3a9648 100644
--- a/samples/tracepoints/tracepoint-probe-sample.c
+++ b/samples/tracepoints/tracepoint-probe-sample.c
@@ -46,6 +46,7 @@
 {
 	unregister_trace_subsys_eventb(probe_subsys_eventb);
 	unregister_trace_subsys_event(probe_subsys_event);
+	tracepoint_synchronize_unregister();
 }
 
 module_exit(tp_sample_trace_exit);
diff --git a/samples/tracepoints/tracepoint-probe-sample2.c b/samples/tracepoints/tracepoint-probe-sample2.c
index 5e9fcf4..685a5ac 100644
--- a/samples/tracepoints/tracepoint-probe-sample2.c
+++ b/samples/tracepoints/tracepoint-probe-sample2.c
@@ -33,6 +33,7 @@
 void __exit tp_sample_trace_exit(void)
 {
 	unregister_trace_subsys_event(probe_subsys_event);
+	tracepoint_synchronize_unregister();
 }
 
 module_exit(tp_sample_trace_exit);
diff --git a/samples/tracepoints/tracepoint-sample.c b/samples/tracepoints/tracepoint-sample.c
index 4ae4b7f..00d1697 100644
--- a/samples/tracepoints/tracepoint-sample.c
+++ b/samples/tracepoints/tracepoint-sample.c
@@ -13,6 +13,9 @@
 #include <linux/proc_fs.h>
 #include "tp-samples-trace.h"
 
+DEFINE_TRACE(subsys_event);
+DEFINE_TRACE(subsys_eventb);
+
 struct proc_dir_entry *pentry_example;
 
 static int my_open(struct inode *inode, struct file *file)
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 982dcae..c29be8f 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -25,6 +25,13 @@
 escsq = $(subst $(squote),'\$(squote)',$1)
 
 ###
+# Easy method for doing a status message
+       kecho := :
+ quiet_kecho := echo
+silent_kecho := :
+kecho := $($(quiet)kecho)
+
+###
 # filechk is used to check if the content of a generated file is updated.
 # Sample usage:
 # define filechk_sample
@@ -39,22 +46,15 @@
 # - If they are equal no change, and no timestamp update
 # - stdin is piped in from the first prerequisite ($<) so one has
 #   to specify a valid file as first prerequisite (often the kbuild file)
-       chk_filechk = :
- quiet_chk_filechk = echo '  CHK     $@'
-silent_chk_filechk = :
-       upd_filechk = :
- quiet_upd_filechk = echo '  UPD     $@'
-silent_upd_filechk = :
-
 define filechk
 	$(Q)set -e;				\
-	$($(quiet)chk_filechk);			\
+	$(kecho) '  CHK     $@';		\
 	mkdir -p $(dir $@);			\
 	$(filechk_$(1)) < $< > $@.tmp;		\
 	if [ -r $@ ] && cmp -s $@ $@.tmp; then	\
 		rm -f $@.tmp;			\
 	else					\
-		$($(quiet)upd_filechk);		\
+		$(kecho) '  UPD     $@';	\
 		mv -f $@.tmp $@;		\
 	fi
 endef
@@ -144,7 +144,9 @@
 build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
 
 # Prefix -I with $(srctree) if it is not an absolute path.
-addtree = $(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1)
+# skip if -I has no parameter
+addtree = $(if $(patsubst -I%,%,$(1)), \
+$(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1))
 
 # Find all -I options and call addtree
 flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 468fbc9..5d90030 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -151,14 +151,20 @@
 $(obj)/%.i: $(src)/%.c FORCE
 	$(call if_changed_dep,cc_i_c)
 
+cmd_genksyms =                                                              \
+    $(CPP) -D__GENKSYMS__ $(c_flags) $< |                                   \
+    $(GENKSYMS) -T $@ -A -a $(ARCH)                                         \
+     $(if $(KBUILD_PRESERVE),-p)                                            \
+     $(if $(1),-r $(firstword $(wildcard $(@:.symtypes=.symref) /dev/null)))
+
 quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
-cmd_cc_symtypes_c	   = \
-		$(CPP) -D__GENKSYMS__ $(c_flags) $<			\
-		| $(GENKSYMS) -T $@ >/dev/null;				\
-		test -s $@ || rm -f $@
+cmd_cc_symtypes_c =                                                         \
+    set -e;                                                                 \
+    $(call cmd_genksyms, true) >/dev/null;                                  \
+    test -s $@ || rm -f $@
 
 $(obj)/%.symtypes : $(src)/%.c FORCE
-	$(call if_changed_dep,cc_symtypes_c)
+	$(call cmd,cc_symtypes_c)
 
 # C (.c) files
 # The C file is compiled and updated dependency information is generated.
@@ -171,43 +177,45 @@
 
 else
 # When module versioning is enabled the following steps are executed:
-# o compile a .tmp_<file>.o from <file>.c
-# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does
-#   not export symbols, we just rename .tmp_<file>.o to <file>.o and
+# o compile a .tmp_<file>.s from <file>.c
+# o if .tmp_<file>.s doesn't contain a __ksymtab version, i.e. does
+#   not export symbols, we just assemble .tmp_<file>.s to <file>.o and
 #   are done.
 # o otherwise, we calculate symbol versions using the good old
 #   genksyms on the preprocessed source and postprocess them in a way
-#   that they are usable as a linker script
-# o generate <file>.o from .tmp_<file>.o using the linker to
-#   replace the unresolved symbols __crc_exported_symbol with
-#   the actual value of the checksum generated by genksyms
+#   that they are usable as assembly source
+# o assemble <file>.o from .tmp_<file>.s forcing inclusion of directives
+#   defining the actual values of __crc_*, followed by objcopy-ing them
+#   to force these symbols to be local to permit stripping them later.
+s_file = $(@D)/.tmp_$(@F:.o=.s)
+v_file = $(@D)/.tmp_$(@F:.o=.v)
+tmp_o_file = $(@D)/.tmp_$(@F)
+no_g_c_flags = $(filter-out -g%,$(c_flags))
 
-cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
+cmd_cc_o_c = $(CC) $(c_flags) -S -o $(s_file) $<
+
 cmd_modversions =							\
-	if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then	\
-		$(CPP) -D__GENKSYMS__ $(c_flags) $<			\
-		| $(GENKSYMS) $(if $(KBUILD_SYMTYPES),			\
-			      -T $(@D)/$(@F:.o=.symtypes)) -a $(ARCH)	\
-		> $(@D)/.tmp_$(@F:.o=.ver);				\
-									\
-		$(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) 		\
-			-T $(@D)/.tmp_$(@F:.o=.ver);			\
-		rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver);	\
+	if grep -q __ksymtab $(s_file); then				\
+		if $(call cmd_genksyms, $(KBUILD_SYMTYPES)) > $(v_file) \
+		   && $(CC) $(no_g_c_flags) -c -Wa,$(v_file)		\
+			    -o $(tmp_o_file) $(s_file)			\
+		   && $(OBJCOPY) -L '__crc_*' -L '___crc_*' -w		\
+				 $(tmp_o_file) $@;			\
+		then							\
+			: ;						\
+		else							\
+			rm -f $@; exit 1;				\
+		fi;							\
 	else								\
-		mv -f $(@D)/.tmp_$(@F) $@;				\
+		rm -f $(v_file);					\
+		$(CC) $(no_g_c_flags) -c -o $@ $(s_file);		\
 	fi;
 endif
 
-ifdef CONFIG_64BIT
-arch_bits = 64
-else
-arch_bits = 32
-endif
-
 ifdef CONFIG_FTRACE_MCOUNT_RECORD
-cmd_record_mcount = perl $(srctree)/scripts/recordmcount.pl \
-	"$(ARCH)" "$(arch_bits)" "$(OBJDUMP)" "$(OBJCOPY)" "$(CC)" "$(LD)" \
-	"$(NM)" "$(RM)" "$(MV)" "$(@)";
+cmd_record_mcount = perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
+	"$(if $(CONFIG_64BIT),64,32)" \
+	"$(OBJDUMP)" "$(OBJCOPY)" "$(CC)" "$(LD)" "$(NM)" "$(RM)" "$(MV)" "$(@)";
 endif
 
 define rule_cc_o_c
@@ -217,7 +225,12 @@
 	$(cmd_record_mcount)						  \
 	scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' >    \
 	                                              $(dot-target).tmp;  \
-	rm -f $(depfile);						  \
+	if [ -r $(@D)/.tmp_$(@F:.o=.v) ]; then				  \
+		echo >> $(dot-target).tmp;				  \
+		echo '$@: $(GENKSYMS)' >> $(dot-target).tmp;		  \
+		echo '$(GENKSYMS):: ;' >> $(dot-target).tmp;		  \
+	fi;								  \
+	rm -f $(depfile) $(@D)/.tmp_$(@F:.o=.?);			  \
 	mv -f $(dot-target).tmp $(dot-target).cmd
 endef
 
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index b4ca38a..e0636577 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -104,9 +104,11 @@
 debug_flags =
 endif
 
-orig_c_flags   = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(basetarget).o)
+orig_c_flags   = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)                     \
+                 $(ccflags-y) $(CFLAGS_$(basetarget).o)
 _c_flags       = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
-_a_flags       = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(basetarget).o)
+_a_flags       = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS)                     \
+                 $(asflags-y) $(AFLAGS_$(basetarget).o)
 _cpp_flags     = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
 
 # If building the kernel in a separate objtree expand all occurrences
@@ -127,15 +129,16 @@
 __cpp_flags     =                          $(call flags,_cpp_flags)
 endif
 
-c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
-		 $(__c_flags) $(modkern_cflags) \
+c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
+		 $(__c_flags) $(modkern_cflags)                           \
 		 -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \
 		  $(debug_flags)
 
-a_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
+a_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
 		 $(__a_flags) $(modkern_aflags)
 
-cpp_flags      = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(__cpp_flags)
+cpp_flags      = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
+		 $(__cpp_flags)
 
 ld_flags       = $(LDFLAGS) $(ldflags-y)
 
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
index efa5d94..a5122dc 100644
--- a/scripts/Makefile.modinst
+++ b/scripts/Makefile.modinst
@@ -17,7 +17,8 @@
 	@:
 
 quiet_cmd_modules_install = INSTALL $@
-      cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@)
+      cmd_modules_install = mkdir -p $(2); \
+			    $(mod_strip_cmd) $@ $(2)/$(notdir $@) || cp $@ $(2)
 
 # Modules built outside the kernel source tree go into extra by default
 INSTALL_MOD_DIR ?= extra
diff --git a/scripts/bootgraph.pl b/scripts/bootgraph.pl
index d2c61ef..f0af9aa 100644
--- a/scripts/bootgraph.pl
+++ b/scripts/bootgraph.pl
@@ -78,11 +78,13 @@
 }
 
 if ($count == 0) {
-	print "No data found in the dmesg. Make sure that 'printk.time=1' and\n";
-	print "'initcall_debug' are passed on the kernel command line.\n\n";
-	print "Usage: \n";
-	print "      dmesg | perl scripts/bootgraph.pl > output.svg\n\n";
-	exit;
+    print STDERR <<END;
+No data found in the dmesg. Make sure that 'printk.time=1' and
+'initcall_debug' are passed on the kernel command line.
+Usage:
+      dmesg | perl scripts/bootgraph.pl > output.svg
+END
+    exit 1;
 }
 
 print "<?xml version=\"1.0\" standalone=\"no\"?> \n";
@@ -109,8 +111,8 @@
 my %rows;
 my $rowscount = 1;
 my @initcalls = sort { $start{$a} <=> $start{$b} } keys(%start);
-my $key;
-foreach $key (@initcalls) {
+
+foreach my $key (@initcalls) {
 	my $duration = $end{$key} - $start{$key};
 
 	if ($duration >= $threshold) {
diff --git a/scripts/decodecode b/scripts/decodecode
index 235d393..4b00647 100755
--- a/scripts/decodecode
+++ b/scripts/decodecode
@@ -7,7 +7,7 @@
 # AFLAGS=--32 decodecode < 386.oops
 
 cleanup() {
-	rm -f $T $T.s $T.o
+	rm -f $T $T.s $T.o $T.oo $T.aa  $T.aaa
 	exit 1
 }
 
@@ -44,21 +44,33 @@
 	marker=`expr index "$code" "\("`
 fi
 
+touch $T.oo
 if [ $marker -ne 0 ]; then
-	beforemark=`echo "$code" | cut -c-$((${marker} - 1))`
+	echo All code >> $T.oo
+	echo ======== >> $T.oo
+	beforemark=`echo "$code"`
 	echo -n "	.byte 0x" > $T.s
-	echo $beforemark | sed -e 's/ /,0x/g' >> $T.s
-	as $AFLAGS -o $T.o $T.s
-	objdump -S $T.o
-	rm $T.o $T.s
+	echo $beforemark | sed -e 's/ /,0x/g' | sed -e 's/<//g' | sed -e 's/>//g' >> $T.s
+	as $AFLAGS -o $T.o $T.s &> /dev/null
+	objdump -S $T.o | grep -v "/tmp" | grep -v "Disassembly" | grep -v "\.text" | grep -v "^$" &> $T.ooo
+	cat $T.ooo >> $T.oo
+	rm -f $T.o $T.s  $T.ooo
 
 # and fix code at-and-after marker
 	code=`echo "$code" | cut -c$((${marker} + 1))-`
 fi
-
+echo Code starting with the faulting instruction  > $T.aa
+echo =========================================== >> $T.aa
 code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g'`
 echo -n "	.byte 0x" > $T.s
 echo $code >> $T.s
-as $AFLAGS -o $T.o $T.s
-objdump -S $T.o
-rm $T $T.s $T.o
+as $AFLAGS -o $T.o $T.s &> /dev/null
+objdump -S $T.o | grep -v "Disassembly" | grep -v "/tmp" | grep -v "\.text" | grep -v "^$" &> $T.aaa
+cat $T.aaa >> $T.aa
+
+faultline=`cat $T.aaa | head -1 | cut -d":" -f2`
+
+cat $T.oo | sed -e "s/\($faultline\)/\*\1     <-- trapping instruction/g"
+echo
+cat $T.aa
+cleanup
diff --git a/scripts/extract-ikconfig b/scripts/extract-ikconfig
index 8187e6f..72997c3 100755
--- a/scripts/extract-ikconfig
+++ b/scripts/extract-ikconfig
@@ -8,8 +8,8 @@
 
 IKCFG_ST="0x49 0x4b 0x43 0x46 0x47 0x5f 0x53 0x54"
 IKCFG_ED="0x49 0x4b 0x43 0x46 0x47 0x5f 0x45 0x44"
-function dump_config {
-    typeset file="$1"
+dump_config() {
+    file="$1"
 
     start=`$binoffset $file $IKCFG_ST 2>/dev/null`
     [ "$?" != "0" ] && start="-1"
@@ -18,8 +18,8 @@
     fi
     end=`$binoffset $file $IKCFG_ED 2>/dev/null`
 
-    let start="$start + 8"
-    let size="$end - $start"
+    start=`expr $start + 8`
+    size=`expr $end - $start`
 
     dd if="$file" ibs=1 skip="$start" count="$size" 2>/dev/null | zcat
 
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index c249274..f8bb4ca 100644
--- a/scripts/genksyms/genksyms.c
+++ b/scripts/genksyms/genksyms.c
@@ -42,7 +42,8 @@
 int cur_line = 1;
 char *cur_filename;
 
-static int flag_debug, flag_dump_defs, flag_dump_types, flag_warnings;
+static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
+	   flag_preserve, flag_warnings, flag_asm;
 static const char *arch = "";
 static const char *mod_prefix = "";
 
@@ -58,6 +59,8 @@
 
 static int equal_list(struct string_list *a, struct string_list *b);
 static void print_list(FILE * f, struct string_list *list);
+static void print_location(void);
+static void print_type_name(enum symbol_type type, const char *name);
 
 /*----------------------------------------------------------------------*/
 
@@ -151,27 +154,83 @@
 
 	for (sym = symtab[h]; sym; sym = sym->hash_next)
 		if (map_to_ns(sym->type) == map_to_ns(ns) &&
-		    strcmp(name, sym->name) == 0)
+		    strcmp(name, sym->name) == 0 &&
+		    sym->is_declared)
 			break;
 
 	return sym;
 }
 
-struct symbol *add_symbol(const char *name, enum symbol_type type,
-			  struct string_list *defn, int is_extern)
+static int is_unknown_symbol(struct symbol *sym)
+{
+	struct string_list *defn;
+
+	return ((sym->type == SYM_STRUCT ||
+		 sym->type == SYM_UNION ||
+		 sym->type == SYM_ENUM) &&
+		(defn = sym->defn)  && defn->tag == SYM_NORMAL &&
+			strcmp(defn->string, "}") == 0 &&
+		(defn = defn->next) && defn->tag == SYM_NORMAL &&
+			strcmp(defn->string, "UNKNOWN") == 0 &&
+		(defn = defn->next) && defn->tag == SYM_NORMAL &&
+			strcmp(defn->string, "{") == 0);
+}
+
+struct symbol *__add_symbol(const char *name, enum symbol_type type,
+			    struct string_list *defn, int is_extern,
+			    int is_reference)
 {
 	unsigned long h = crc32(name) % HASH_BUCKETS;
 	struct symbol *sym;
+	enum symbol_status status = STATUS_UNCHANGED;
 
 	for (sym = symtab[h]; sym; sym = sym->hash_next) {
-		if (map_to_ns(sym->type) == map_to_ns(type)
-		    && strcmp(name, sym->name) == 0) {
-			if (!equal_list(sym->defn, defn))
+		if (map_to_ns(sym->type) == map_to_ns(type) &&
+		    strcmp(name, sym->name) == 0) {
+			if (is_reference)
+				/* fall through */ ;
+			else if (sym->type == type &&
+				 equal_list(sym->defn, defn)) {
+				if (!sym->is_declared && sym->is_override) {
+					print_location();
+					print_type_name(type, name);
+					fprintf(stderr, " modversion is "
+						"unchanged\n");
+				}
+				sym->is_declared = 1;
+				return sym;
+			} else if (!sym->is_declared) {
+				if (sym->is_override && flag_preserve) {
+					print_location();
+					fprintf(stderr, "ignoring ");
+					print_type_name(type, name);
+					fprintf(stderr, " modversion change\n");
+					sym->is_declared = 1;
+					return sym;
+				} else {
+					status = is_unknown_symbol(sym) ?
+						STATUS_DEFINED : STATUS_MODIFIED;
+				}
+			} else {
 				error_with_pos("redefinition of %s", name);
-			return sym;
+				return sym;
+			}
+			break;
 		}
 	}
 
+	if (sym) {
+		struct symbol **psym;
+
+		for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
+			if (*psym == sym) {
+				*psym = sym->hash_next;
+				break;
+			}
+		}
+		--nsyms;
+	}
+
 	sym = xmalloc(sizeof(*sym));
 	sym->name = name;
 	sym->type = type;
@@ -183,6 +242,10 @@
 	sym->hash_next = symtab[h];
 	symtab[h] = sym;
 
+	sym->is_declared = !is_reference;
+	sym->status = status;
+	sym->is_override = 0;
+
 	if (flag_debug) {
 		fprintf(debugfile, "Defn for %s %s == <",
 			symbol_type_name[type], name);
@@ -196,6 +259,18 @@
 	return sym;
 }
 
+struct symbol *add_symbol(const char *name, enum symbol_type type,
+			  struct string_list *defn, int is_extern)
+{
+	return __add_symbol(name, type, defn, is_extern, 0);
+}
+
+struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
+				    struct string_list *defn, int is_extern)
+{
+	return __add_symbol(name, type, defn, is_extern, 1);
+}
+
 /*----------------------------------------------------------------------*/
 
 void free_node(struct string_list *node)
@@ -236,6 +311,90 @@
 	return !a && !b;
 }
 
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+struct string_list *read_node(FILE *f)
+{
+	char buffer[256];
+	struct string_list node = {
+		.string = buffer,
+		.tag = SYM_NORMAL };
+	int c;
+
+	while ((c = fgetc(f)) != EOF) {
+		if (c == ' ') {
+			if (node.string == buffer)
+				continue;
+			break;
+		} else if (c == '\n') {
+			if (node.string == buffer)
+				return NULL;
+			ungetc(c, f);
+			break;
+		}
+		if (node.string >= buffer + sizeof(buffer) - 1) {
+			fprintf(stderr, "Token too long\n");
+			exit(1);
+		}
+		*node.string++ = c;
+	}
+	if (node.string == buffer)
+		return NULL;
+	*node.string = 0;
+	node.string = buffer;
+
+	if (node.string[1] == '#') {
+		int n;
+
+		for (n = 0; n < ARRAY_SIZE(symbol_type_name); n++) {
+			if (node.string[0] == symbol_type_name[n][0]) {
+				node.tag = n;
+				node.string += 2;
+				return copy_node(&node);
+			}
+		}
+		fprintf(stderr, "Unknown type %c\n", node.string[0]);
+		exit(1);
+	}
+	return copy_node(&node);
+}
+
+static void read_reference(FILE *f)
+{
+	while (!feof(f)) {
+		struct string_list *defn = NULL;
+		struct string_list *sym, *def;
+		int is_extern = 0, is_override = 0;
+		struct symbol *subsym;
+
+		sym = read_node(f);
+		if (sym && sym->tag == SYM_NORMAL &&
+		    !strcmp(sym->string, "override")) {
+			is_override = 1;
+			free_node(sym);
+			sym = read_node(f);
+		}
+		if (!sym)
+			continue;
+		def = read_node(f);
+		if (def && def->tag == SYM_NORMAL &&
+		    !strcmp(def->string, "extern")) {
+			is_extern = 1;
+			free_node(def);
+			def = read_node(f);
+		}
+		while (def) {
+			def->next = defn;
+			defn = def;
+			def = read_node(f);
+		}
+		subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
+					      defn, is_extern);
+		subsym->is_override = is_override;
+		free_node(sym);
+	}
+}
+
 static void print_node(FILE * f, struct string_list *list)
 {
 	if (list->tag != SYM_NORMAL) {
@@ -311,6 +470,7 @@
 
 		case SYM_TYPEDEF:
 			subsym = find_symbol(cur->string, cur->tag);
+			/* FIXME: Bad reference files can segfault here. */
 			if (subsym->expansion_trail) {
 				if (flag_dump_defs)
 					fprintf(debugfile, "%s ", cur->string);
@@ -347,9 +507,22 @@
 				t = n;
 
 				n = xmalloc(sizeof(*n));
-				n->string = xstrdup("{ UNKNOWN }");
+				n->string = xstrdup("{");
 				n->tag = SYM_NORMAL;
 				n->next = t;
+				t = n;
+
+				n = xmalloc(sizeof(*n));
+				n->string = xstrdup("UNKNOWN");
+				n->tag = SYM_NORMAL;
+				n->next = t;
+				t = n;
+
+				n = xmalloc(sizeof(*n));
+				n->string = xstrdup("}");
+				n->tag = SYM_NORMAL;
+				n->next = t;
+				t = n;
 
 				subsym =
 				    add_symbol(cur->string, cur->tag, n, 0);
@@ -397,37 +570,75 @@
 		error_with_pos("export undefined symbol %s", name);
 	else {
 		unsigned long crc;
+		int has_changed = 0;
 
 		if (flag_dump_defs)
 			fprintf(debugfile, "Export %s == <", name);
 
 		expansion_trail = (struct symbol *)-1L;
 
+		sym->expansion_trail = expansion_trail;
+		expansion_trail = sym;
 		crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
 
 		sym = expansion_trail;
 		while (sym != (struct symbol *)-1L) {
 			struct symbol *n = sym->expansion_trail;
+
+			if (sym->status != STATUS_UNCHANGED) {
+				if (!has_changed) {
+					print_location();
+					fprintf(stderr, "%s: %s: modversion "
+						"changed because of changes "
+						"in ", flag_preserve ? "error" :
+						       "warning", name);
+				} else
+					fprintf(stderr, ", ");
+				print_type_name(sym->type, sym->name);
+				if (sym->status == STATUS_DEFINED)
+					fprintf(stderr, " (became defined)");
+				has_changed = 1;
+				if (flag_preserve)
+					errors++;
+			}
 			sym->expansion_trail = 0;
 			sym = n;
 		}
+		if (has_changed)
+			fprintf(stderr, "\n");
 
 		if (flag_dump_defs)
 			fputs(">\n", debugfile);
 
-		/* Used as a linker script. */
-		printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
+		/* Used as assembly source or a linker script. */
+		printf(flag_asm
+		       ? ".equiv %s__crc_%s, %#08lx\n"
+		       : "%s__crc_%s = %#08lx ;\n",
+		       mod_prefix, name, crc);
 	}
 }
 
 /*----------------------------------------------------------------------*/
+
+static void print_location(void)
+{
+	fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
+}
+
+static void print_type_name(enum symbol_type type, const char *name)
+{
+	if (type != SYM_NORMAL)
+		fprintf(stderr, "%s %s", symbol_type_name[type], name);
+	else
+		fprintf(stderr, "%s", name);
+}
+
 void error_with_pos(const char *fmt, ...)
 {
 	va_list args;
 
 	if (flag_warnings) {
-		fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>",
-			cur_line);
+		print_location();
 
 		va_start(args, fmt);
 		vfprintf(stderr, fmt, args);
@@ -440,21 +651,27 @@
 
 static void genksyms_usage(void)
 {
-	fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
+	fputs("Usage:\n" "genksyms [-aAdDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
 #ifdef __GNU_LIBRARY__
 	      "  -a, --arch            Select architecture\n"
+	      "  -A, --asm             Generate assembly rather than linker script\n"
 	      "  -d, --debug           Increment the debug level (repeatable)\n"
 	      "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
-	      "  -T, --dump-types file Dump expanded types into file (for debugging only)\n"
+	      "  -r, --reference file  Read reference symbols from a file\n"
+	      "  -T, --dump-types file Dump expanded types into file\n"
+	      "  -p, --preserve        Preserve reference modversions or fail\n"
 	      "  -w, --warnings        Enable warnings\n"
 	      "  -q, --quiet           Disable warnings (default)\n"
 	      "  -h, --help            Print this message\n"
 	      "  -V, --version         Print the release version\n"
 #else				/* __GNU_LIBRARY__ */
 	      "  -a                    Select architecture\n"
+	      "  -A                    Generate assembly rather than linker script\n"
 	      "  -d                    Increment the debug level (repeatable)\n"
 	      "  -D                    Dump expanded symbol defs (for debugging only)\n"
-	      "  -T file               Dump expanded types into file (for debugging only)\n"
+	      "  -r file               Read reference symbols from a file\n"
+	      "  -T file               Dump expanded types into file\n"
+	      "  -p                    Preserve reference modversions or fail\n"
 	      "  -w                    Enable warnings\n"
 	      "  -q                    Disable warnings (default)\n"
 	      "  -h                    Print this message\n"
@@ -465,26 +682,29 @@
 
 int main(int argc, char **argv)
 {
-	FILE *dumpfile = NULL;
+	FILE *dumpfile = NULL, *ref_file = NULL;
 	int o;
 
 #ifdef __GNU_LIBRARY__
 	struct option long_opts[] = {
 		{"arch", 1, 0, 'a'},
+		{"asm", 0, 0, 'A'},
 		{"debug", 0, 0, 'd'},
 		{"warnings", 0, 0, 'w'},
 		{"quiet", 0, 0, 'q'},
 		{"dump", 0, 0, 'D'},
+		{"reference", 1, 0, 'r'},
 		{"dump-types", 1, 0, 'T'},
+		{"preserve", 0, 0, 'p'},
 		{"version", 0, 0, 'V'},
 		{"help", 0, 0, 'h'},
 		{0, 0, 0, 0}
 	};
 
-	while ((o = getopt_long(argc, argv, "a:dwqVDT:h",
+	while ((o = getopt_long(argc, argv, "a:dwqVADr:T:ph",
 				&long_opts[0], NULL)) != EOF)
 #else				/* __GNU_LIBRARY__ */
-	while ((o = getopt(argc, argv, "a:dwqVDT:h")) != EOF)
+	while ((o = getopt(argc, argv, "a:dwqVADr:T:ph")) != EOF)
 #endif				/* __GNU_LIBRARY__ */
 		switch (o) {
 		case 'a':
@@ -502,9 +722,20 @@
 		case 'V':
 			fputs("genksyms version 2.5.60\n", stderr);
 			break;
+		case 'A':
+			flag_asm = 1;
+			break;
 		case 'D':
 			flag_dump_defs = 1;
 			break;
+		case 'r':
+			flag_reference = 1;
+			ref_file = fopen(optarg, "r");
+			if (!ref_file) {
+				perror(optarg);
+				return 1;
+			}
+			break;
 		case 'T':
 			flag_dump_types = 1;
 			dumpfile = fopen(optarg, "w");
@@ -513,6 +744,9 @@
 				return 1;
 			}
 			break;
+		case 'p':
+			flag_preserve = 1;
+			break;
 		case 'h':
 			genksyms_usage();
 			return 0;
@@ -533,12 +767,17 @@
 		/* setlinebuf(debugfile); */
 	}
 
+	if (flag_reference)
+		read_reference(ref_file);
+
 	yyparse();
 
 	if (flag_dump_types && visited_symbols) {
 		while (visited_symbols != (struct symbol *)-1L) {
 			struct symbol *sym = visited_symbols;
 
+			if (sym->is_override)
+				fputs("override ", dumpfile);
 			if (sym->type != SYM_NORMAL) {
 				putc(symbol_type_name[sym->type][0], dumpfile);
 				putc('#', dumpfile);
diff --git a/scripts/genksyms/genksyms.h b/scripts/genksyms/genksyms.h
index 2668287..25c4d40 100644
--- a/scripts/genksyms/genksyms.h
+++ b/scripts/genksyms/genksyms.h
@@ -29,6 +29,10 @@
 	SYM_NORMAL, SYM_TYPEDEF, SYM_ENUM, SYM_STRUCT, SYM_UNION
 };
 
+enum symbol_status {
+	STATUS_UNCHANGED, STATUS_DEFINED, STATUS_MODIFIED
+};
+
 struct string_list {
 	struct string_list *next;
 	enum symbol_type tag;
@@ -43,6 +47,9 @@
 	struct symbol *expansion_trail;
 	struct symbol *visited;
 	int is_extern;
+	int is_declared;
+	enum symbol_status status;
+	int is_override;
 };
 
 typedef struct string_list **yystype;
diff --git a/scripts/genksyms/keywords.c_shipped b/scripts/genksyms/keywords.c_shipped
index 971e011..83484fe 100644
--- a/scripts/genksyms/keywords.c_shipped
+++ b/scripts/genksyms/keywords.c_shipped
@@ -1,4 +1,4 @@
-/* ANSI-C code produced by gperf version 3.0.2 */
+/* ANSI-C code produced by gperf version 3.0.1 */
 /* Command-line: gperf -L ANSI-C -a -C -E -g -H is_reserved_hash -k '1,3,$' -N is_reserved_word -p -t scripts/genksyms/keywords.gperf  */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
@@ -32,7 +32,7 @@
 
 #line 3 "scripts/genksyms/keywords.gperf"
 struct resword { const char *name; int token; };
-/* maximum key range = 62, duplicates = 0 */
+/* maximum key range = 64, duplicates = 0 */
 
 #ifdef __GNUC__
 __inline
@@ -46,32 +46,32 @@
 {
   static const unsigned char asso_values[] =
     {
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65,  5,
-      65, 65, 65, 65, 65, 65, 35, 65, 65, 65,
-       0, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65,  0, 65,  0, 65,  5,
-      20, 15, 10, 30, 65, 15, 65, 65, 20,  0,
-      10, 35, 20, 65, 10,  5,  0, 10,  5, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
-      65, 65, 65, 65, 65, 65
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67,  0,
+      67, 67, 67, 67, 67, 67, 15, 67, 67, 67,
+       0, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67,  0, 67,  0, 67,  5,
+      25, 20, 15, 30, 67, 15, 67, 67, 10,  0,
+      10, 40, 20, 67, 10,  5,  0, 10, 15, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+      67, 67, 67, 67, 67, 67
     };
   return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]] + asso_values[(unsigned char)str[len - 1]];
 }
@@ -84,116 +84,119 @@
 {
   enum
     {
-      TOTAL_KEYWORDS = 43,
+      TOTAL_KEYWORDS = 45,
       MIN_WORD_LENGTH = 3,
       MAX_WORD_LENGTH = 24,
       MIN_HASH_VALUE = 3,
-      MAX_HASH_VALUE = 64
+      MAX_HASH_VALUE = 66
     };
 
   static const struct resword wordlist[] =
     {
       {""}, {""}, {""},
-#line 26 "scripts/genksyms/keywords.gperf"
+#line 28 "scripts/genksyms/keywords.gperf"
       {"asm", ASM_KEYW},
       {""},
-#line 8 "scripts/genksyms/keywords.gperf"
+#line 10 "scripts/genksyms/keywords.gperf"
       {"__asm", ASM_KEYW},
       {""},
-#line 9 "scripts/genksyms/keywords.gperf"
+#line 11 "scripts/genksyms/keywords.gperf"
       {"__asm__", ASM_KEYW},
       {""}, {""},
-#line 52 "scripts/genksyms/keywords.gperf"
+#line 54 "scripts/genksyms/keywords.gperf"
       {"__typeof__", TYPEOF_KEYW},
       {""},
-#line 12 "scripts/genksyms/keywords.gperf"
-      {"__const", CONST_KEYW},
-#line 11 "scripts/genksyms/keywords.gperf"
-      {"__attribute__", ATTRIBUTE_KEYW},
-#line 13 "scripts/genksyms/keywords.gperf"
-      {"__const__", CONST_KEYW},
-#line 18 "scripts/genksyms/keywords.gperf"
-      {"__signed__", SIGNED_KEYW},
-#line 44 "scripts/genksyms/keywords.gperf"
-      {"static", STATIC_KEYW},
-#line 20 "scripts/genksyms/keywords.gperf"
-      {"__volatile__", VOLATILE_KEYW},
-#line 39 "scripts/genksyms/keywords.gperf"
-      {"int", INT_KEYW},
-#line 32 "scripts/genksyms/keywords.gperf"
-      {"char", CHAR_KEYW},
-#line 33 "scripts/genksyms/keywords.gperf"
-      {"const", CONST_KEYW},
-#line 45 "scripts/genksyms/keywords.gperf"
-      {"struct", STRUCT_KEYW},
-#line 24 "scripts/genksyms/keywords.gperf"
-      {"__restrict__", RESTRICT_KEYW},
-#line 25 "scripts/genksyms/keywords.gperf"
-      {"restrict", RESTRICT_KEYW},
-#line 23 "scripts/genksyms/keywords.gperf"
-      {"_restrict", RESTRICT_KEYW},
-#line 16 "scripts/genksyms/keywords.gperf"
-      {"__inline__", INLINE_KEYW},
-#line 10 "scripts/genksyms/keywords.gperf"
-      {"__attribute", ATTRIBUTE_KEYW},
-      {""},
 #line 14 "scripts/genksyms/keywords.gperf"
-      {"__extension__", EXTENSION_KEYW},
-#line 35 "scripts/genksyms/keywords.gperf"
-      {"enum", ENUM_KEYW},
-#line 19 "scripts/genksyms/keywords.gperf"
-      {"__volatile", VOLATILE_KEYW},
-#line 36 "scripts/genksyms/keywords.gperf"
-      {"extern", EXTERN_KEYW},
+      {"__const", CONST_KEYW},
+#line 13 "scripts/genksyms/keywords.gperf"
+      {"__attribute__", ATTRIBUTE_KEYW},
+#line 15 "scripts/genksyms/keywords.gperf"
+      {"__const__", CONST_KEYW},
+#line 20 "scripts/genksyms/keywords.gperf"
+      {"__signed__", SIGNED_KEYW},
+#line 46 "scripts/genksyms/keywords.gperf"
+      {"static", STATIC_KEYW},
       {""},
-#line 17 "scripts/genksyms/keywords.gperf"
-      {"__signed", SIGNED_KEYW},
+#line 41 "scripts/genksyms/keywords.gperf"
+      {"int", INT_KEYW},
+#line 34 "scripts/genksyms/keywords.gperf"
+      {"char", CHAR_KEYW},
+#line 35 "scripts/genksyms/keywords.gperf"
+      {"const", CONST_KEYW},
+#line 47 "scripts/genksyms/keywords.gperf"
+      {"struct", STRUCT_KEYW},
+#line 26 "scripts/genksyms/keywords.gperf"
+      {"__restrict__", RESTRICT_KEYW},
+#line 27 "scripts/genksyms/keywords.gperf"
+      {"restrict", RESTRICT_KEYW},
 #line 7 "scripts/genksyms/keywords.gperf"
       {"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW},
-      {""},
-#line 51 "scripts/genksyms/keywords.gperf"
-      {"typeof", TYPEOF_KEYW},
-#line 46 "scripts/genksyms/keywords.gperf"
-      {"typedef", TYPEDEF_KEYW},
-#line 15 "scripts/genksyms/keywords.gperf"
-      {"__inline", INLINE_KEYW},
-#line 31 "scripts/genksyms/keywords.gperf"
-      {"auto", AUTO_KEYW},
-#line 47 "scripts/genksyms/keywords.gperf"
-      {"union", UNION_KEYW},
-      {""}, {""},
-#line 48 "scripts/genksyms/keywords.gperf"
-      {"unsigned", UNSIGNED_KEYW},
-#line 49 "scripts/genksyms/keywords.gperf"
-      {"void", VOID_KEYW},
-#line 42 "scripts/genksyms/keywords.gperf"
-      {"short", SHORT_KEYW},
-      {""}, {""},
-#line 50 "scripts/genksyms/keywords.gperf"
-      {"volatile", VOLATILE_KEYW},
-      {""},
-#line 37 "scripts/genksyms/keywords.gperf"
-      {"float", FLOAT_KEYW},
-#line 34 "scripts/genksyms/keywords.gperf"
-      {"double", DOUBLE_KEYW},
-      {""},
-#line 5 "scripts/genksyms/keywords.gperf"
-      {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW},
-      {""}, {""},
-#line 38 "scripts/genksyms/keywords.gperf"
-      {"inline", INLINE_KEYW},
-#line 6 "scripts/genksyms/keywords.gperf"
-      {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
-#line 41 "scripts/genksyms/keywords.gperf"
-      {"register", REGISTER_KEYW},
+#line 18 "scripts/genksyms/keywords.gperf"
+      {"__inline__", INLINE_KEYW},
       {""},
 #line 22 "scripts/genksyms/keywords.gperf"
-      {"_Bool", BOOL_KEYW},
-#line 43 "scripts/genksyms/keywords.gperf"
-      {"signed", SIGNED_KEYW},
+      {"__volatile__", VOLATILE_KEYW},
+#line 5 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW},
+#line 25 "scripts/genksyms/keywords.gperf"
+      {"_restrict", RESTRICT_KEYW},
+      {""},
+#line 12 "scripts/genksyms/keywords.gperf"
+      {"__attribute", ATTRIBUTE_KEYW},
+#line 6 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
+#line 16 "scripts/genksyms/keywords.gperf"
+      {"__extension__", EXTENSION_KEYW},
+#line 37 "scripts/genksyms/keywords.gperf"
+      {"enum", ENUM_KEYW},
+#line 8 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_UNUSED_SYMBOL", EXPORT_SYMBOL_KEYW},
+#line 38 "scripts/genksyms/keywords.gperf"
+      {"extern", EXTERN_KEYW},
+      {""},
+#line 19 "scripts/genksyms/keywords.gperf"
+      {"__signed", SIGNED_KEYW},
+#line 9 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_UNUSED_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
+#line 49 "scripts/genksyms/keywords.gperf"
+      {"union", UNION_KEYW},
+#line 53 "scripts/genksyms/keywords.gperf"
+      {"typeof", TYPEOF_KEYW},
+#line 48 "scripts/genksyms/keywords.gperf"
+      {"typedef", TYPEDEF_KEYW},
+#line 17 "scripts/genksyms/keywords.gperf"
+      {"__inline", INLINE_KEYW},
+#line 33 "scripts/genksyms/keywords.gperf"
+      {"auto", AUTO_KEYW},
+#line 21 "scripts/genksyms/keywords.gperf"
+      {"__volatile", VOLATILE_KEYW},
       {""}, {""},
+#line 50 "scripts/genksyms/keywords.gperf"
+      {"unsigned", UNSIGNED_KEYW},
+      {""},
+#line 44 "scripts/genksyms/keywords.gperf"
+      {"short", SHORT_KEYW},
 #line 40 "scripts/genksyms/keywords.gperf"
-      {"long", LONG_KEYW}
+      {"inline", INLINE_KEYW},
+      {""},
+#line 52 "scripts/genksyms/keywords.gperf"
+      {"volatile", VOLATILE_KEYW},
+#line 42 "scripts/genksyms/keywords.gperf"
+      {"long", LONG_KEYW},
+#line 24 "scripts/genksyms/keywords.gperf"
+      {"_Bool", BOOL_KEYW},
+      {""}, {""},
+#line 43 "scripts/genksyms/keywords.gperf"
+      {"register", REGISTER_KEYW},
+#line 51 "scripts/genksyms/keywords.gperf"
+      {"void", VOID_KEYW},
+#line 39 "scripts/genksyms/keywords.gperf"
+      {"float", FLOAT_KEYW},
+#line 36 "scripts/genksyms/keywords.gperf"
+      {"double", DOUBLE_KEYW},
+      {""}, {""}, {""}, {""},
+#line 45 "scripts/genksyms/keywords.gperf"
+      {"signed", SIGNED_KEYW}
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/scripts/genksyms/keywords.gperf b/scripts/genksyms/keywords.gperf
index 5ef3733..8abe7ab 100644
--- a/scripts/genksyms/keywords.gperf
+++ b/scripts/genksyms/keywords.gperf
@@ -5,6 +5,8 @@
 EXPORT_SYMBOL, EXPORT_SYMBOL_KEYW
 EXPORT_SYMBOL_GPL, EXPORT_SYMBOL_KEYW
 EXPORT_SYMBOL_GPL_FUTURE, EXPORT_SYMBOL_KEYW
+EXPORT_UNUSED_SYMBOL, EXPORT_SYMBOL_KEYW
+EXPORT_UNUSED_SYMBOL_GPL, EXPORT_SYMBOL_KEYW
 __asm, ASM_KEYW
 __asm__, ASM_KEYW
 __attribute, ATTRIBUTE_KEYW
diff --git a/scripts/headerdep.pl b/scripts/headerdep.pl
new file mode 100755
index 0000000..97399da
--- /dev/null
+++ b/scripts/headerdep.pl
@@ -0,0 +1,193 @@
+#! /usr/bin/perl
+#
+# Detect cycles in the header file dependency graph
+# Vegard Nossum <vegardno@ifi.uio.no>
+#
+
+use strict;
+use warnings;
+
+use Getopt::Long;
+
+my $opt_all;
+my @opt_include;
+my $opt_graph;
+
+&Getopt::Long::Configure(qw(bundling pass_through));
+&GetOptions(
+	help	=> \&help,
+	version	=> \&version,
+
+	all	=> \$opt_all,
+	I	=> \@opt_include,
+	graph	=> \$opt_graph,
+);
+
+push @opt_include, 'include';
+my %deps = ();
+my %linenos = ();
+
+my @headers = grep { strip($_) } @ARGV;
+
+parse_all(@headers);
+
+if($opt_graph) {
+	graph();
+} else {
+	detect_cycles(@headers);
+}
+
+
+sub help {
+	print "Usage: $0 [options] file...\n";
+	print "\n";
+	print "Options:\n";
+	print "  --all\n";
+	print "  --graph\n";
+	print "\n";
+	print "  -I includedir\n";
+	print "\n";
+	print "To make nice graphs, try:\n";
+	print "  $0 --graph include/linux/kernel.h | dot -Tpng -o graph.png\n";
+	exit;
+}
+
+sub version {
+	print "headerdep version 2\n";
+	exit;
+}
+
+# Get a file name that is relative to our include paths
+sub strip {
+	my $filename = shift;
+
+	for my $i (@opt_include) {
+		my $stripped = $filename;
+		$stripped =~ s/^$i\///;
+
+		return $stripped if $stripped ne $filename;
+	}
+
+	return $filename;
+}
+
+# Search for the file name in the list of include paths
+sub search {
+	my $filename = shift;
+	return $filename if -f $filename;
+
+	for my $i (@opt_include) {
+		my $path = "$i/$filename";
+		return $path if -f $path;
+	}
+
+	return undef;
+}
+
+sub parse_all {
+	# Parse all the headers.
+	my @queue = @_;
+	while(@queue) {
+		my $header = pop @queue;
+		next if exists $deps{$header};
+
+		$deps{$header} = [] unless exists $deps{$header};
+
+		my $path = search($header);
+		next unless $path;
+
+		open(my $file, '<', $path) or die($!);
+		chomp(my @lines = <$file>);
+		close($file);
+
+		for my $i (0 .. $#lines) {
+			my $line = $lines[$i];
+			if(my($dep) = ($line =~ m/^#\s*include\s*<(.*?)>/)) {
+				push @queue, $dep;
+				push @{$deps{$header}}, [$i + 1, $dep];
+			}
+		}
+	}
+}
+
+sub print_cycle {
+	# $cycle[n] includes $cycle[n + 1];
+	# $cycle[-1] will be the culprit
+	my $cycle = shift;
+
+	# Adjust the line numbers
+	for my $i (0 .. $#$cycle - 1) {
+		$cycle->[$i]->[0] = $cycle->[$i + 1]->[0];
+	}
+	$cycle->[-1]->[0] = 0;
+
+	my $first = shift @$cycle;
+	my $last = pop @$cycle;
+
+	my $msg = "In file included";
+	printf "%s from %s,\n", $msg, $last->[1] if defined $last;
+
+	for my $header (reverse @$cycle) {
+		printf "%s from %s:%d%s\n",
+			" " x length $msg,
+			$header->[1], $header->[0],
+			$header->[1] eq $last->[1] ? ' <-- here' : '';
+	}
+
+	printf "%s:%d: warning: recursive header inclusion\n",
+		$first->[1], $first->[0];
+}
+
+# Find and print the smallest cycle starting in the specified node.
+sub detect_cycles {
+	my @queue = map { [[0, $_]] } @_;
+	while(@queue) {
+		my $top = pop @queue;
+		my $name = $top->[-1]->[1];
+
+		for my $dep (@{$deps{$name}}) {
+			my $chain = [@$top, [$dep->[0], $dep->[1]]];
+
+			# If the dep already exists in the chain, we have a
+			# cycle...
+			if(grep { $_->[1] eq $dep->[1] } @$top) {
+				print_cycle($chain);
+				next if $opt_all;
+				return;
+			}
+
+			push @queue, $chain;
+		}
+	}
+}
+
+sub mangle {
+	$_ = shift;
+	s/\//__/g;
+	s/\./_/g;
+	s/-/_/g;
+	$_;
+}
+
+# Output dependency graph in GraphViz language.
+sub graph {
+	print "digraph {\n";
+
+	print "\t/* vertices */\n";
+	for my $header (keys %deps) {
+		printf "\t%s [label=\"%s\"];\n",
+			mangle($header), $header;
+	}
+
+	print "\n";
+
+	print "\t/* edges */\n";
+	for my $header (keys %deps) {
+		for my $dep (@{$deps{$header}}) {
+			printf "\t%s -> %s;\n",
+				mangle($header), mangle($dep->[1]);
+		}
+	}
+
+	print "}\n";
+}
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index ad2434b..9275812 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -130,18 +130,9 @@
 static int symbol_valid(struct sym_entry *s)
 {
 	/* Symbols which vary between passes.  Passes 1 and 2 must have
-	 * identical symbol lists.  The kallsyms_* symbols below are only added
-	 * after pass 1, they would be included in pass 2 when --all-symbols is
-	 * specified so exclude them to get a stable symbol list.
+	 * identical symbol lists.
 	 */
 	static char *special_symbols[] = {
-		"kallsyms_addresses",
-		"kallsyms_num_syms",
-		"kallsyms_names",
-		"kallsyms_markers",
-		"kallsyms_token_table",
-		"kallsyms_token_index",
-
 	/* Exclude linker generated symbols which vary between passes */
 		"_SDA_BASE_",		/* ppc */
 		"_SDA2_BASE_",		/* ppc */
@@ -173,7 +164,9 @@
 	}
 
 	/* Exclude symbols which vary between passes. */
-	if (strstr((char *)s->sym + offset, "_compiled."))
+	if (strstr((char *)s->sym + offset, "_compiled.") ||
+	    strncmp((char*)s->sym + offset, "__compound_literal.", 19) == 0 ||
+	    strncmp((char*)s->sym + offset, "__compound_literal$", 19) == 0)
 		return 0;
 
 	for (i = 0; special_symbols[i]; i++)
@@ -550,8 +543,10 @@
 		usage();
 
 	read_map(stdin);
-	sort_symbols();
-	optimize_token_table();
+	if (table_cnt) {
+		sort_symbols();
+		optimize_token_table();
+	}
 	write_src();
 
 	return 0;
diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh
index 5552154..fcef0f5 100644
--- a/scripts/kconfig/lxdialog/check-lxdialog.sh
+++ b/scripts/kconfig/lxdialog/check-lxdialog.sh
@@ -52,7 +52,7 @@
 }
 
 usage() {
-	printf "Usage: $0 [-check compiler options|-header|-library]\n"
+	printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n"
 }
 
 if [ $# -eq 0 ]; then
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index d27aad7..8bb83a1 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -289,6 +289,8 @@
 my @parameterlist;
 my %sections;
 my @sectionlist;
+my $sectcheck;
+my $struct_actual;
 
 my $contents = "";
 my $section_default = "Description";	# default section
@@ -378,10 +380,12 @@
 #	print STDERR "parameter def '$1' = '$contents'\n";
 	$name = $1;
 	$parameterdescs{$name} = $contents;
+	$sectcheck = $sectcheck . $name . " ";
     } elsif ($name eq "@\.\.\.") {
 #	print STDERR "parameter def '...' = '$contents'\n";
 	$name = "...";
 	$parameterdescs{$name} = $contents;
+	$sectcheck = $sectcheck . $name . " ";
     } else {
 #	print STDERR "other section '$name' = '$contents'\n";
 	if (defined($sections{$name}) && ($sections{$name} ne "")) {
@@ -1405,21 +1409,25 @@
 sub dump_struct($$) {
     my $x = shift;
     my $file = shift;
+    my $nested;
 
     if ($x =~/(struct|union)\s+(\w+)\s*{(.*)}/) {
 	$declaration_name = $2;
 	my $members = $3;
 
 	# ignore embedded structs or unions
-	$members =~ s/{.*}//g;
+	$members =~ s/({.*})//g;
+	$nested = $1;
 
 	# ignore members marked private:
 	$members =~ s/\/\*.*?private:.*?public:.*?\*\///gos;
 	$members =~ s/\/\*.*?private:.*//gos;
 	# strip comments:
 	$members =~ s/\/\*.*?\*\///gos;
+	$nested =~ s/\/\*.*?\*\///gos;
 
 	create_parameterlist($members, ';', $file);
+	check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested);
 
 	output_declaration($declaration_name,
 			   'struct',
@@ -1505,6 +1513,14 @@
     }
 }
 
+sub save_struct_actual($) {
+    my $actual = shift;
+
+    # strip all spaces from the actual param so that it looks like one string item
+    $actual =~ s/\s*//g;
+    $struct_actual = $struct_actual . $actual . " ";
+}
+
 sub create_parameterlist($$$) {
     my $args = shift;
     my $splitter = shift;
@@ -1537,6 +1553,7 @@
 	    $param = $1;
 	    $type = $arg;
 	    $type =~ s/([^\(]+\(\*?)\s*$param/$1/;
+	    save_struct_actual($param);
 	    push_parameter($param, $type, $file);
 	} elsif ($arg) {
 	    $arg =~ s/\s*:\s*/:/g;
@@ -1561,14 +1578,17 @@
 
 	    foreach $param (@args) {
 		if ($param =~ m/^(\*+)\s*(.*)/) {
+		    save_struct_actual($2);
 		    push_parameter($2, "$type $1", $file);
 		}
 		elsif ($param =~ m/(.*?):(\d+)/) {
 		    if ($type ne "") { # skip unnamed bit-fields
+			save_struct_actual($1);
 			push_parameter($1, "$type:$2", $file)
 		    }
 		}
 		else {
+		    save_struct_actual($param);
 		    push_parameter($param, $type, $file);
 		}
 	    }
@@ -1634,6 +1654,46 @@
 	$parametertypes{$param} = $type;
 }
 
+sub check_sections($$$$$$) {
+	my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_;
+	my @sects = split ' ', $sectcheck;
+	my @prms = split ' ', $prmscheck;
+	my $err;
+	my ($px, $sx);
+	my $prm_clean;		# strip trailing "[array size]" and/or beginning "*"
+
+	foreach $sx (0 .. $#sects) {
+		$err = 1;
+		foreach $px (0 .. $#prms) {
+			$prm_clean = $prms[$px];
+			$prm_clean =~ s/\[.*\]//;
+			$prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//;
+			##$prm_clean =~ s/^\**//;
+			if ($prm_clean eq $sects[$sx]) {
+				$err = 0;
+				last;
+			}
+		}
+		if ($err) {
+			if ($decl_type eq "function") {
+				print STDERR "Warning(${file}:$.): " .
+					"Excess function parameter " .
+					"'$sects[$sx]' " .
+					"description in '$decl_name'\n";
+				++$warnings;
+			} else {
+				if ($nested !~ m/\Q$sects[$sx]\E/) {
+				    print STDERR "Warning(${file}:$.): " .
+					"Excess struct/union/enum/typedef member " .
+					"'$sects[$sx]' " .
+					"description in '$decl_name'\n";
+				    ++$warnings;
+				}
+			}
+		}
+	}
+}
+
 ##
 # takes a function prototype and the name of the current file being
 # processed and spits out all the details stored in the global
@@ -1699,6 +1759,9 @@
 	return;
     }
 
+	my $prms = join " ", @parameterlist;
+	check_sections($file, $declaration_name, "function", $sectcheck, $prms, "");
+
     output_declaration($declaration_name,
 		       'function',
 		       {'function' => $declaration_name,
@@ -1757,6 +1820,8 @@
     @parameterlist = ();
     %sections = ();
     @sectionlist = ();
+    $sectcheck = "";
+    $struct_actual = "";
     $prototype = "";
 
     $state = 0;
diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h
index a8740df..6a12dd9 100755
--- a/scripts/mkcompile_h
+++ b/scripts/mkcompile_h
@@ -4,6 +4,8 @@
 PREEMPT=$4
 CC=$5
 
+vecho() { [ "${quiet}" = "silent_" ] || echo "$@" ; }
+
 # If compile.h exists already and we don't own autoconf.h
 # (i.e. we're not the same user who did make *config), don't
 # modify compile.h
@@ -11,7 +13,7 @@
 # do "compiled by root"
 
 if [ -r $TARGET -a ! -O include/linux/autoconf.h ]; then
-  echo "  SKIPPED $TARGET"
+  vecho "  SKIPPED $TARGET"
   exit 0
 fi
 
@@ -89,7 +91,7 @@
       cmp -s .tmpver.1 .tmpver.2; then
    rm -f .tmpcompile
 else
-   echo "  UPD     $TARGET"
+   vecho "  UPD     $TARGET"
    mv -f .tmpcompile $TARGET
 fi
 rm -f .tmpver.1 .tmpver.2
diff --git a/scripts/mkmakefile b/scripts/mkmakefile
index e65d8b3..67d59c7 100644
--- a/scripts/mkmakefile
+++ b/scripts/mkmakefile
@@ -17,7 +17,9 @@
 then
 	exit 0
 fi
-echo "  GEN     $2/Makefile"
+if [ "${quiet}" != "silent_" ]; then
+	echo "  GEN     $2/Makefile"
+fi
 
 cat << EOF > $2/Makefile
 # Automatically generated by $0: don't edit
diff --git a/scripts/mksysmap b/scripts/mksysmap
index 6e133a0..1db316a 100644
--- a/scripts/mksysmap
+++ b/scripts/mksysmap
@@ -37,9 +37,6 @@
 
 # readprofile starts reading symbols when _stext is found, and
 # continue until it finds a symbol which is not either of 'T', 't',
-# 'W' or 'w'. __crc_ are 'A' and placed in the middle
-# so we just ignore them to let readprofile continue to work.
-# (At least sparc64 has __crc_ in the middle).
+# 'W' or 'w'.
 
-$NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)' > $2
-
+$NM -n $1 | grep -v '\( [aNUw] \)\|\( \$[adt]\)' > $2
diff --git a/scripts/package/Makefile b/scripts/package/Makefile
index 5e32607..8c6b7b0 100644
--- a/scripts/package/Makefile
+++ b/scripts/package/Makefile
@@ -1,10 +1,6 @@
 # Makefile for the different targets used to generate full packages of a kernel
 # It uses the generic clean infrastructure of kbuild
 
-# Ignore the following files/directories during tar operation
-TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS
-
-
 # RPM target
 # ---------------------------------------------------------------------------
 # The rpm target generates two rpm files:
@@ -47,7 +43,7 @@
 	set -e; \
 	mv -f $(objtree)/.tmp_version $(objtree)/.version
 
-	$(RPM) --target $(UTS_MACHINE) -ta ../$(KERNELPATH).tar.gz
+	$(RPM) $(RPMOPTS) --target $(UTS_MACHINE) -ta ../$(KERNELPATH).tar.gz
 	rm ../$(KERNELPATH).tar.gz
 
 clean-files := $(objtree)/kernel.spec
@@ -64,7 +60,8 @@
 	set -e; \
 	mv -f $(objtree)/.tmp_version $(objtree)/.version
 
-	$(RPM) --define "_builddir $(srctree)" --target $(UTS_MACHINE) -bb $<
+	$(RPM) $(RPMOPTS) --define "_builddir $(srctree)" --target \
+		$(UTS_MACHINE) -bb $<
 
 clean-files += $(objtree)/binkernel.spec
 
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index 6b9fe3e..fe83141 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -112,6 +112,9 @@
 # Acceptable sections to record.
 my %text_sections = (
      ".text" => 1,
+     ".sched.text" => 1,
+     ".spinlock.text" => 1,
+     ".irqentry.text" => 1,
 );
 
 $objdump = "objdump" if ((length $objdump) == 0);
@@ -130,10 +133,13 @@
 my %convert;		# List of local functions used that needs conversion
 
 my $type;
+my $nm_regex;		# Find the local functions (return function)
 my $section_regex;	# Find the start of a section
 my $function_regex;	# Find the name of a function
 			#    (return offset and func name)
 my $mcount_regex;	# Find the call site to mcount (return offset)
+my $alignment;		# The .align value to use for $mcount_section
+my $section_type;	# Section header plus possible alignment command
 
 if ($arch eq "x86") {
     if ($bits == 64) {
@@ -143,11 +149,21 @@
     }
 }
 
+#
+# We base the defaults off of i386, the other archs may
+# feel free to change them in the below if statements.
+#
+$nm_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)";
+$section_regex = "Disassembly of section\\s+(\\S+):";
+$function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:";
+$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$";
+$section_type = '@progbits';
+$type = ".long";
+
 if ($arch eq "x86_64") {
-    $section_regex = "Disassembly of section\\s+(\\S+):";
-    $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:";
     $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount([+-]0x[0-9a-zA-Z]+)?\$";
     $type = ".quad";
+    $alignment = 8;
 
     # force flags for this arch
     $ld .= " -m elf_x86_64";
@@ -156,10 +172,7 @@
     $cc .= " -m64";
 
 } elsif ($arch eq "i386") {
-    $section_regex = "Disassembly of section\\s+(\\S+):";
-    $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:";
-    $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$";
-    $type = ".long";
+    $alignment = 4;
 
     # force flags for this arch
     $ld .= " -m elf_i386";
@@ -167,6 +180,27 @@
     $objcopy .= " -O elf32-i386";
     $cc .= " -m32";
 
+} elsif ($arch eq "sh") {
+    $alignment = 2;
+
+    # force flags for this arch
+    $ld .= " -m shlelf_linux";
+    $objcopy .= " -O elf32-sh-linux";
+    $cc .= " -m32";
+
+} elsif ($arch eq "powerpc") {
+    $nm_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)";
+    $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?.*?)>:";
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s\\.?_mcount\$";
+
+    if ($bits == 64) {
+	$type = ".quad";
+    }
+
+} elsif ($arch eq "arm") {
+    $alignment = 2;
+    $section_type = '%progbits';
+
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
@@ -236,7 +270,7 @@
 #
 open (IN, "$nm $inputfile|") || die "error running $nm";
 while (<IN>) {
-    if (/^[0-9a-fA-F]+\s+t\s+(\S+)/) {
+    if (/$nm_regex/) {
 	$locals{$1} = 1;
     } elsif (/^[0-9a-fA-F]+\s+([wW])\s+(\S+)/) {
 	$weak{$2} = $1;
@@ -287,7 +321,8 @@
 	if (!$opened) {
 	    open(FILE, ">$mcount_s") || die "can't create $mcount_s\n";
 	    $opened = 1;
-	    print FILE "\t.section $mcount_section,\"a\",\@progbits\n";
+	    print FILE "\t.section $mcount_section,\"a\",$section_type\n";
+	    print FILE "\t.align $alignment\n" if (defined($alignment));
 	}
 	printf FILE "\t%s %s + %d\n", $type, $ref_func, $offsets[$i] - $offset;
     }
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 72d2335..f6946cf 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -19,6 +19,11 @@
 		fi
 	fi
 
+	# Is this git on svn?
+	if git config --get svn-remote.svn.url >/dev/null; then
+	        printf -- '-svn%s' "`git-svn find-rev $head`"
+	fi
+
 	# Are there uncommitted changes?
 	git update-index --refresh --unmerged > /dev/null
 	if git diff-index --name-only HEAD | grep -v "^scripts/package" \
@@ -51,7 +56,7 @@
 fi
 
 # Check for svn and a svn repo.
-if rev=`svn info 2>/dev/null | grep '^Revision'`; then
+if rev=`svn info 2>/dev/null | grep '^Last Changed Rev'`; then
 	rev=`echo $rev | awk '{print $NF}'`
 	changes=`svn status 2>/dev/null | grep '^[AMD]' | wc -l`
 
diff --git a/scripts/strip-symbols b/scripts/strip-symbols
new file mode 100644
index 0000000..29ee8c1
--- /dev/null
+++ b/scripts/strip-symbols
@@ -0,0 +1,22 @@
+<*>
+*.h
+__compound_literal[$.][0-9]*
+__crc_[a-zA-Z_]*
+__exitcall_[a-zA-Z_]*
+__func__[$.][0-9]*
+__FUNCTION__[$.][0-9]*
+gcc[0-9]_compiled[$.]
+__initcall_[a-zA-Z_]*
+__kcrctab_[a-zA-Z_]*
+__kstrtab_[a-zA-Z_]*
+__ksymtab_[a-zA-Z_]*
+__mod_[a-zA-Z_]*[0-9]
+__module_depends
+__param_[a-zA-Z_]*
+__pci_fixup_*PCI_ANY_IDPCI_ANY_ID*
+__pci_fixup_*PCI_ANY_IDPCI_DEVICE_ID_*
+__pci_fixup_*PCI_VENDOR_ID_*PCI_ANY_ID*
+__pci_fixup_*PCI_VENDOR_ID_*PCI_DEVICE_ID_*
+__PRETTY_FUNCTION__[$.][0-9]*
+__setup_[a-zA-Z_]*
+____versions
diff --git a/scripts/tags.sh b/scripts/tags.sh
new file mode 100755
index 0000000..4e75472
--- /dev/null
+++ b/scripts/tags.sh
@@ -0,0 +1,160 @@
+#!/bin/sh
+# Generate tags or cscope files
+# Usage tags.sh <mode>
+#
+# mode may be any of: tags, TAGS, cscope
+#
+# Uses the following environment variables:
+# ARCH, SUBARCH, srctree, src, obj
+
+if [ "$KBUILD_VERBOSE" = "1" ]; then
+	set -x
+fi
+
+# This is a duplicate of RCS_FIND_IGNORE without escaped '()'
+ignore="( -name SCCS -o -name BitKeeper -o -name .svn -o \
+          -name CVS  -o -name .pc       -o -name .hg  -o \
+          -name .git )                                   \
+          -prune -o"
+
+# Do not use full path is we do not use O=.. builds
+if [ "${KBUILD_SRC}" = "" ]; then
+	tree=
+else
+	tree=${srctree}/
+fi
+
+# find sources in arch/$ARCH
+find_arch_sources()
+{
+	find ${tree}arch/$1 $ignore -name "$2" -print;
+}
+
+# find sources in arch/$1/include
+find_arch_include_sources()
+{
+	find ${tree}arch/$1/include $ignore -name "$2" -print;
+}
+
+# find sources in include/
+find_include_sources()
+{
+	find ${tree}include $ignore -name config -prune -o -name "$1" -print;
+}
+
+# find sources in rest of tree
+# we could benefit from a list of dirs to search in here
+find_other_sources()
+{
+	find ${tree}* $ignore \
+	     \( -name include -o -name arch -o -name '.tmp_*' \) -prune -o \
+	       -name "$1" -print;
+}
+
+find_sources()
+{
+	find_arch_sources $1 "$2"
+	find_include_sources "$2"
+	find_other_sources "$2"
+}
+
+all_sources()
+{
+	find_sources $SRCARCH '*.[chS]'
+	if [ ! -z "$archinclude" ]; then
+		find_arch_include_sources $archinclude '*.[chS]'
+	fi
+}
+
+all_kconfigs()
+{
+	find_sources $SRCARCH 'Kconfig*'
+}
+
+all_defconfigs()
+{
+	find_sources $SRCARCH "defconfig"
+}
+
+docscope()
+{
+	(echo \-k; echo \-q; all_sources) > cscope.files
+	cscope -b -f cscope.out
+}
+
+exuberant()
+{
+	all_sources > all
+	all_sources | xargs $1 -a                               \
+	-I __initdata,__exitdata,__acquires,__releases          \
+	-I __read_mostly,____cacheline_aligned                  \
+	-I ____cacheline_aligned_in_smp                         \
+	-I ____cacheline_internodealigned_in_smp                \
+	-I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL                      \
+	--extra=+f --c-kinds=+px                                \
+	--regex-asm='/^ENTRY\(([^)]*)\).*/\1/'
+
+	all_kconfigs | xargs $1 -a                              \
+	--langdef=kconfig --language-force=kconfig              \
+	--regex-kconfig='/^[[:blank:]]*(menu|)config[[:blank:]]+([[:alnum:]_]+)/\2/'
+
+	all_kconfigs | xargs $1 -a                              \
+	--langdef=kconfig --language-force=kconfig              \
+	--regex-kconfig='/^[[:blank:]]*(menu|)config[[:blank:]]+([[:alnum:]_]+)/CONFIG_\2/'
+
+	all_defconfigs | xargs -r $1 -a                         \
+	--langdef=dotconfig --language-force=dotconfig          \
+	--regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'
+
+}
+
+emacs()
+{
+	all_sources | xargs $1 -a
+
+	all_kconfigs | xargs $1 -a                              \
+	--regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'
+
+	all_kconfigs | xargs $1 -a                              \
+	--regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/CONFIG_\3/'
+
+	all_defconfigs | xargs -r $1 -a                         \
+	--regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'
+}
+
+xtags()
+{
+	if $1 --version 2>&1 | grep -iq exuberant; then
+		exuberant $1
+	elif $1 --version 2>&1 | grep -iq emacs; then
+		emacs $1
+	else
+		all_sources | xargs $1 -a
+        fi
+}
+
+
+# Support um (which uses SUBARCH)
+if [ "${ARCH}" = "um" ]; then
+	if [ "$SUBARCH" = "i386" ]; then
+		archinclude=x86
+	elif [ "$SUBARCH" = "x86_64" ]; then
+		archinclude=x86
+	else
+		archinclude=${SUBARCH}
+	fi
+fi
+
+case "$1" in
+	"cscope")
+		docscope
+		;;
+
+	"tags")
+		xtags ctags
+		;;
+
+	"TAGS")
+		xtags etags
+		;;
+esac
diff --git a/scripts/trace/power.pl b/scripts/trace/power.pl
new file mode 100644
index 0000000..4f729b3
--- /dev/null
+++ b/scripts/trace/power.pl
@@ -0,0 +1,108 @@
+#!/usr/bin/perl
+
+# Copyright 2008, Intel Corporation
+#
+# This file is part of the Linux kernel
+#
+# This program file is free software; 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 in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+# Authors:
+# 	Arjan van de Ven <arjan@linux.intel.com>
+
+
+#
+# This script turns a cstate ftrace output into a SVG graphic that shows
+# historic C-state information
+#
+#
+# 	cat /sys/kernel/debug/tracing/trace | perl power.pl > out.svg
+#
+
+my @styles;
+my $base = 0;
+
+my @pstate_last;
+my @pstate_level;
+
+$styles[0] = "fill:rgb(0,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[1] = "fill:rgb(0,255,0);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[2] = "fill:rgb(255,0,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[3] = "fill:rgb(255,255,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[4] = "fill:rgb(255,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[5] = "fill:rgb(0,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[6] = "fill:rgb(0,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[7] = "fill:rgb(0,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[8] = "fill:rgb(0,25,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+
+
+print "<?xml version=\"1.0\" standalone=\"no\"?> \n";
+print "<svg width=\"10000\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n";
+
+my $scale = 30000.0;
+while (<>) {
+	my $line = $_;
+	if ($line =~ /([0-9\.]+)\] CSTATE: Going to C([0-9]) on cpu ([0-9]+) for ([0-9\.]+)/) {
+		if ($base == 0) {
+			$base = $1;
+		}
+		my $time = $1 - $base;
+		$time = $time * $scale;
+		my $C = $2;
+		my $cpu = $3;
+		my $y = 400 * $cpu;
+		my $duration = $4 * $scale;
+		my $msec = int($4 * 100000)/100.0;
+		my $height = $C * 20;
+		$style = $styles[$C];
+
+		$y = $y + 140 - $height;
+
+		$x2 = $time + 4;
+		$y2 = $y + 4;
+
+
+		print "<rect x=\"$time\" width=\"$duration\" y=\"$y\" height=\"$height\" style=\"$style\"/>\n";
+		print "<text transform=\"translate($x2,$y2) rotate(90)\">C$C $msec</text>\n";
+	}
+	if ($line =~ /([0-9\.]+)\] PSTATE: Going to P([0-9]) on cpu ([0-9]+)/) {
+		my $time = $1 - $base;
+		my $state = $2;
+		my $cpu = $3;
+
+		if (defined($pstate_last[$cpu])) {
+			my $from = $pstate_last[$cpu];
+			my $oldstate = $pstate_state[$cpu];
+			my $duration = ($time-$from) * $scale;
+
+			$from = $from * $scale;
+			my $to = $from + $duration;
+			my $height = 140 - ($oldstate * (140/8));
+
+			my $y = 400 * $cpu + 200 + $height;
+			my $y2 = $y+4;
+			my $style = $styles[8];
+
+			print "<rect x=\"$from\" y=\"$y\" width=\"$duration\" height=\"5\" style=\"$style\"/>\n";
+			print "<text transform=\"translate($from,$y2)\">P$oldstate (cpu $cpu)</text>\n";
+		};
+
+		$pstate_last[$cpu] = $time;
+		$pstate_state[$cpu] = $state;
+	}
+}
+
+
+print "</svg>\n";
diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py
new file mode 100644
index 0000000..902f9a9
--- /dev/null
+++ b/scripts/tracing/draw_functrace.py
@@ -0,0 +1,130 @@
+#!/usr/bin/python
+
+"""
+Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com>
+Licensed under the terms of the GNU GPL License version 2
+
+This script parses a trace provided by the function tracer in
+kernel/trace/trace_functions.c
+The resulted trace is processed into a tree to produce a more human
+view of the call stack by drawing textual but hierarchical tree of
+calls. Only the functions's names and the the call time are provided.
+
+Usage:
+	Be sure that you have CONFIG_FUNCTION_TRACER
+	# mkdir /debugfs
+	# mount -t debug debug /debug
+	# echo function > /debug/tracing/current_tracer
+	$ cat /debug/tracing/trace_pipe > ~/raw_trace_func
+	Wait some times but not too much, the script is a bit slow.
+	Break the pipe (Ctrl + Z)
+	$ scripts/draw_functrace.py < raw_trace_func > draw_functrace
+	Then you have your drawn trace in draw_functrace
+"""
+
+
+import sys, re
+
+class CallTree:
+	""" This class provides a tree representation of the functions
+		call stack. If a function has no parent in the kernel (interrupt,
+		syscall, kernel thread...) then it is attached to a virtual parent
+		called ROOT.
+	"""
+	ROOT = None
+
+	def __init__(self, func, time = None, parent = None):
+		self._func = func
+		self._time = time
+		if parent is None:
+			self._parent = CallTree.ROOT
+		else:
+			self._parent = parent
+		self._children = []
+
+	def calls(self, func, calltime):
+		""" If a function calls another one, call this method to insert it
+			into the tree at the appropriate place.
+			@return: A reference to the newly created child node.
+		"""
+		child = CallTree(func, calltime, self)
+		self._children.append(child)
+		return child
+
+	def getParent(self, func):
+		""" Retrieve the last parent of the current node that
+			has the name given by func. If this function is not
+			on a parent, then create it as new child of root
+			@return: A reference to the parent.
+		"""
+		tree = self
+		while tree != CallTree.ROOT and tree._func != func:
+			tree = tree._parent
+		if tree == CallTree.ROOT:
+			child = CallTree.ROOT.calls(func, None)
+			return child
+		return tree
+
+	def __repr__(self):
+		return self.__toString("", True)
+
+	def __toString(self, branch, lastChild):
+		if self._time is not None:
+			s = "%s----%s (%s)\n" % (branch, self._func, self._time)
+		else:
+			s = "%s----%s\n" % (branch, self._func)
+
+		i = 0
+		if lastChild:
+			branch = branch[:-1] + " "
+		while i < len(self._children):
+			if i != len(self._children) - 1:
+				s += "%s" % self._children[i].__toString(branch +\
+								"    |", False)
+			else:
+				s += "%s" % self._children[i].__toString(branch +\
+								"    |", True)
+			i += 1
+		return s
+
+class BrokenLineException(Exception):
+	"""If the last line is not complete because of the pipe breakage,
+	   we want to stop the processing and ignore this line.
+	"""
+	pass
+
+class CommentLineException(Exception):
+	""" If the line is a comment (as in the beginning of the trace file),
+	    just ignore it.
+	"""
+	pass
+
+
+def parseLine(line):
+	line = line.strip()
+	if line.startswith("#"):
+		raise CommentLineException
+	m = re.match("[^]]+?\\] +([0-9.]+): (\\w+) <-(\\w+)", line)
+	if m is None:
+		raise BrokenLineException
+	return (m.group(1), m.group(2), m.group(3))
+
+
+def main():
+	CallTree.ROOT = CallTree("Root (Nowhere)", None, None)
+	tree = CallTree.ROOT
+
+	for line in sys.stdin:
+		try:
+			calltime, callee, caller = parseLine(line)
+		except BrokenLineException:
+			break
+		except CommentLineException:
+			continue
+		tree = tree.getParent(caller)
+		tree = tree.calls(callee, calltime)
+
+	print CallTree.ROOT
+
+if __name__ == "__main__":
+	main()
diff --git a/security/capability.c b/security/capability.c
index 2458748..2dce66f 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -32,24 +32,19 @@
 	return 0;
 }
 
-static int cap_bprm_alloc_security(struct linux_binprm *bprm)
+static int cap_bprm_check_security (struct linux_binprm *bprm)
 {
 	return 0;
 }
 
-static void cap_bprm_free_security(struct linux_binprm *bprm)
+static void cap_bprm_committing_creds(struct linux_binprm *bprm)
 {
 }
 
-static void cap_bprm_post_apply_creds(struct linux_binprm *bprm)
+static void cap_bprm_committed_creds(struct linux_binprm *bprm)
 {
 }
 
-static int cap_bprm_check_security(struct linux_binprm *bprm)
-{
-	return 0;
-}
-
 static int cap_sb_alloc_security(struct super_block *sb)
 {
 	return 0;
@@ -64,7 +59,7 @@
 	return 0;
 }
 
-static int cap_sb_kern_mount(struct super_block *sb, void *data)
+static int cap_sb_kern_mount(struct super_block *sb, int flags, void *data)
 {
 	return 0;
 }
@@ -330,7 +325,7 @@
 	return 0;
 }
 
-static int cap_dentry_open(struct file *file)
+static int cap_dentry_open(struct file *file, const struct cred *cred)
 {
 	return 0;
 }
@@ -340,15 +335,29 @@
 	return 0;
 }
 
-static int cap_task_alloc_security(struct task_struct *p)
+static void cap_cred_free(struct cred *cred)
+{
+}
+
+static int cap_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp)
 {
 	return 0;
 }
 
-static void cap_task_free_security(struct task_struct *p)
+static void cap_cred_commit(struct cred *new, const struct cred *old)
 {
 }
 
+static int cap_kernel_act_as(struct cred *new, u32 secid)
+{
+	return 0;
+}
+
+static int cap_kernel_create_files_as(struct cred *new, struct inode *inode)
+{
+	return 0;
+}
+
 static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
 {
 	return 0;
@@ -750,7 +759,7 @@
 }
 
 #ifdef CONFIG_KEYS
-static int cap_key_alloc(struct key *key, struct task_struct *ctx,
+static int cap_key_alloc(struct key *key, const struct cred *cred,
 			 unsigned long flags)
 {
 	return 0;
@@ -760,7 +769,7 @@
 {
 }
 
-static int cap_key_permission(key_ref_t key_ref, struct task_struct *context,
+static int cap_key_permission(key_ref_t key_ref, const struct cred *cred,
 			      key_perm_t perm)
 {
 	return 0;
@@ -814,8 +823,7 @@
 	set_to_cap_if_null(ops, ptrace_may_access);
 	set_to_cap_if_null(ops, ptrace_traceme);
 	set_to_cap_if_null(ops, capget);
-	set_to_cap_if_null(ops, capset_check);
-	set_to_cap_if_null(ops, capset_set);
+	set_to_cap_if_null(ops, capset);
 	set_to_cap_if_null(ops, acct);
 	set_to_cap_if_null(ops, capable);
 	set_to_cap_if_null(ops, quotactl);
@@ -824,11 +832,9 @@
 	set_to_cap_if_null(ops, syslog);
 	set_to_cap_if_null(ops, settime);
 	set_to_cap_if_null(ops, vm_enough_memory);
-	set_to_cap_if_null(ops, bprm_alloc_security);
-	set_to_cap_if_null(ops, bprm_free_security);
-	set_to_cap_if_null(ops, bprm_apply_creds);
-	set_to_cap_if_null(ops, bprm_post_apply_creds);
-	set_to_cap_if_null(ops, bprm_set_security);
+	set_to_cap_if_null(ops, bprm_set_creds);
+	set_to_cap_if_null(ops, bprm_committing_creds);
+	set_to_cap_if_null(ops, bprm_committed_creds);
 	set_to_cap_if_null(ops, bprm_check_security);
 	set_to_cap_if_null(ops, bprm_secureexec);
 	set_to_cap_if_null(ops, sb_alloc_security);
@@ -890,10 +896,13 @@
 	set_to_cap_if_null(ops, file_receive);
 	set_to_cap_if_null(ops, dentry_open);
 	set_to_cap_if_null(ops, task_create);
-	set_to_cap_if_null(ops, task_alloc_security);
-	set_to_cap_if_null(ops, task_free_security);
+	set_to_cap_if_null(ops, cred_free);
+	set_to_cap_if_null(ops, cred_prepare);
+	set_to_cap_if_null(ops, cred_commit);
+	set_to_cap_if_null(ops, kernel_act_as);
+	set_to_cap_if_null(ops, kernel_create_files_as);
 	set_to_cap_if_null(ops, task_setuid);
-	set_to_cap_if_null(ops, task_post_setuid);
+	set_to_cap_if_null(ops, task_fix_setuid);
 	set_to_cap_if_null(ops, task_setgid);
 	set_to_cap_if_null(ops, task_setpgid);
 	set_to_cap_if_null(ops, task_getpgid);
@@ -910,7 +919,6 @@
 	set_to_cap_if_null(ops, task_wait);
 	set_to_cap_if_null(ops, task_kill);
 	set_to_cap_if_null(ops, task_prctl);
-	set_to_cap_if_null(ops, task_reparent_to_init);
 	set_to_cap_if_null(ops, task_to_inode);
 	set_to_cap_if_null(ops, ipc_permission);
 	set_to_cap_if_null(ops, ipc_getsecid);
diff --git a/security/commoncap.c b/security/commoncap.c
index 3976613..7971354 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -8,6 +8,7 @@
  */
 
 #include <linux/capability.h>
+#include <linux/audit.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -29,7 +30,7 @@
 
 int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
 {
-	NETLINK_CB(skb).eff_cap = current->cap_effective;
+	NETLINK_CB(skb).eff_cap = current_cap();
 	return 0;
 }
 
@@ -39,23 +40,41 @@
 		return -EPERM;
 	return 0;
 }
-
 EXPORT_SYMBOL(cap_netlink_recv);
 
-/*
+/**
+ * cap_capable - Determine whether a task has a particular effective capability
+ * @tsk: The task to query
+ * @cap: The capability to check for
+ * @audit: Whether to write an audit message or not
+ *
+ * Determine whether the nominated task has the specified capability amongst
+ * its effective set, returning 0 if it does, -ve if it does not.
+ *
  * NOTE WELL: cap_capable() cannot be used like the kernel's capable()
- * function.  That is, it has the reverse semantics: cap_capable()
- * returns 0 when a task has a capability, but the kernel's capable()
- * returns 1 for this case.
+ * function.  That is, it has the reverse semantics: cap_capable() returns 0
+ * when a task has a capability, but the kernel's capable() returns 1 for this
+ * case.
  */
-int cap_capable (struct task_struct *tsk, int cap)
+int cap_capable(struct task_struct *tsk, int cap, int audit)
 {
+	__u32 cap_raised;
+
 	/* Derived from include/linux/sched.h:capable. */
-	if (cap_raised(tsk->cap_effective, cap))
-		return 0;
-	return -EPERM;
+	rcu_read_lock();
+	cap_raised = cap_raised(__task_cred(tsk)->cap_effective, cap);
+	rcu_read_unlock();
+	return cap_raised ? 0 : -EPERM;
 }
 
+/**
+ * cap_settime - Determine whether the current process may set the system clock
+ * @ts: The time to set
+ * @tz: The timezone to set
+ *
+ * Determine whether the current process may set the system clock and timezone
+ * information, returning 0 if permission granted, -ve if denied.
+ */
 int cap_settime(struct timespec *ts, struct timezone *tz)
 {
 	if (!capable(CAP_SYS_TIME))
@@ -63,121 +82,157 @@
 	return 0;
 }
 
+/**
+ * cap_ptrace_may_access - Determine whether the current process may access
+ *			   another
+ * @child: The process to be accessed
+ * @mode: The mode of attachment.
+ *
+ * Determine whether a process may access another, returning 0 if permission
+ * granted, -ve if denied.
+ */
 int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)
 {
-	/* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
-	if (cap_issubset(child->cap_permitted, current->cap_permitted))
-		return 0;
-	if (capable(CAP_SYS_PTRACE))
-		return 0;
-	return -EPERM;
+	int ret = 0;
+
+	rcu_read_lock();
+	if (!cap_issubset(__task_cred(child)->cap_permitted,
+			  current_cred()->cap_permitted) &&
+	    !capable(CAP_SYS_PTRACE))
+		ret = -EPERM;
+	rcu_read_unlock();
+	return ret;
 }
 
+/**
+ * cap_ptrace_traceme - Determine whether another process may trace the current
+ * @parent: The task proposed to be the tracer
+ *
+ * Determine whether the nominated task is permitted to trace the current
+ * process, returning 0 if permission is granted, -ve if denied.
+ */
 int cap_ptrace_traceme(struct task_struct *parent)
 {
-	/* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
-	if (cap_issubset(current->cap_permitted, parent->cap_permitted))
-		return 0;
-	if (has_capability(parent, CAP_SYS_PTRACE))
-		return 0;
-	return -EPERM;
+	int ret = 0;
+
+	rcu_read_lock();
+	if (!cap_issubset(current_cred()->cap_permitted,
+			  __task_cred(parent)->cap_permitted) &&
+	    !has_capability(parent, CAP_SYS_PTRACE))
+		ret = -EPERM;
+	rcu_read_unlock();
+	return ret;
 }
 
-int cap_capget (struct task_struct *target, kernel_cap_t *effective,
-		kernel_cap_t *inheritable, kernel_cap_t *permitted)
+/**
+ * cap_capget - Retrieve a task's capability sets
+ * @target: The task from which to retrieve the capability sets
+ * @effective: The place to record the effective set
+ * @inheritable: The place to record the inheritable set
+ * @permitted: The place to record the permitted set
+ *
+ * This function retrieves the capabilities of the nominated task and returns
+ * them to the caller.
+ */
+int cap_capget(struct task_struct *target, kernel_cap_t *effective,
+	       kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
+	const struct cred *cred;
+
 	/* Derived from kernel/capability.c:sys_capget. */
-	*effective = target->cap_effective;
-	*inheritable = target->cap_inheritable;
-	*permitted = target->cap_permitted;
+	rcu_read_lock();
+	cred = __task_cred(target);
+	*effective   = cred->cap_effective;
+	*inheritable = cred->cap_inheritable;
+	*permitted   = cred->cap_permitted;
+	rcu_read_unlock();
 	return 0;
 }
 
-#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
-
-static inline int cap_block_setpcap(struct task_struct *target)
-{
-	/*
-	 * No support for remote process capability manipulation with
-	 * filesystem capability support.
-	 */
-	return (target != current);
-}
-
+/*
+ * Determine whether the inheritable capabilities are limited to the old
+ * permitted set.  Returns 1 if they are limited, 0 if they are not.
+ */
 static inline int cap_inh_is_capped(void)
 {
-	/*
-	 * Return 1 if changes to the inheritable set are limited
-	 * to the old permitted set. That is, if the current task
-	 * does *not* possess the CAP_SETPCAP capability.
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
+
+	/* they are so limited unless the current task has the CAP_SETPCAP
+	 * capability
 	 */
-	return (cap_capable(current, CAP_SETPCAP) != 0);
+	if (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
+		return 0;
+#endif
+	return 1;
 }
 
-static inline int cap_limit_ptraced_target(void) { return 1; }
-
-#else /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */
-
-static inline int cap_block_setpcap(struct task_struct *t) { return 0; }
-static inline int cap_inh_is_capped(void) { return 1; }
-static inline int cap_limit_ptraced_target(void)
+/**
+ * cap_capset - Validate and apply proposed changes to current's capabilities
+ * @new: The proposed new credentials; alterations should be made here
+ * @old: The current task's current credentials
+ * @effective: A pointer to the proposed new effective capabilities set
+ * @inheritable: A pointer to the proposed new inheritable capabilities set
+ * @permitted: A pointer to the proposed new permitted capabilities set
+ *
+ * This function validates and applies a proposed mass change to the current
+ * process's capability sets.  The changes are made to the proposed new
+ * credentials, and assuming no error, will be committed by the caller of LSM.
+ */
+int cap_capset(struct cred *new,
+	       const struct cred *old,
+	       const kernel_cap_t *effective,
+	       const kernel_cap_t *inheritable,
+	       const kernel_cap_t *permitted)
 {
-	return !capable(CAP_SETPCAP);
-}
-
-#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
-
-int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,
-		      kernel_cap_t *inheritable, kernel_cap_t *permitted)
-{
-	if (cap_block_setpcap(target)) {
-		return -EPERM;
-	}
-	if (cap_inh_is_capped()
-	    && !cap_issubset(*inheritable,
-			     cap_combine(target->cap_inheritable,
-					 current->cap_permitted))) {
+	if (cap_inh_is_capped() &&
+	    !cap_issubset(*inheritable,
+			  cap_combine(old->cap_inheritable,
+				      old->cap_permitted)))
 		/* incapable of using this inheritable set */
 		return -EPERM;
-	}
+
 	if (!cap_issubset(*inheritable,
-			   cap_combine(target->cap_inheritable,
-				       current->cap_bset))) {
+			  cap_combine(old->cap_inheritable,
+				      old->cap_bset)))
 		/* no new pI capabilities outside bounding set */
 		return -EPERM;
-	}
 
 	/* verify restrictions on target's new Permitted set */
-	if (!cap_issubset (*permitted,
-			   cap_combine (target->cap_permitted,
-					current->cap_permitted))) {
+	if (!cap_issubset(*permitted, old->cap_permitted))
 		return -EPERM;
-	}
 
 	/* verify the _new_Effective_ is a subset of the _new_Permitted_ */
-	if (!cap_issubset (*effective, *permitted)) {
+	if (!cap_issubset(*effective, *permitted))
 		return -EPERM;
-	}
 
+	new->cap_effective   = *effective;
+	new->cap_inheritable = *inheritable;
+	new->cap_permitted   = *permitted;
 	return 0;
 }
 
-void cap_capset_set (struct task_struct *target, kernel_cap_t *effective,
-		     kernel_cap_t *inheritable, kernel_cap_t *permitted)
-{
-	target->cap_effective = *effective;
-	target->cap_inheritable = *inheritable;
-	target->cap_permitted = *permitted;
-}
-
+/*
+ * Clear proposed capability sets for execve().
+ */
 static inline void bprm_clear_caps(struct linux_binprm *bprm)
 {
-	cap_clear(bprm->cap_post_exec_permitted);
+	cap_clear(bprm->cred->cap_permitted);
 	bprm->cap_effective = false;
 }
 
 #ifdef CONFIG_SECURITY_FILE_CAPABILITIES
 
+/**
+ * cap_inode_need_killpriv - Determine if inode change affects privileges
+ * @dentry: The inode/dentry in being changed with change marked ATTR_KILL_PRIV
+ *
+ * Determine if an inode having a change applied that's marked ATTR_KILL_PRIV
+ * affects the security markings on that inode, and if it is, should
+ * inode_killpriv() be invoked or the change rejected?
+ *
+ * Returns 0 if granted; +ve if granted, but inode_killpriv() is required; and
+ * -ve to deny the change.
+ */
 int cap_inode_need_killpriv(struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
@@ -192,6 +247,14 @@
 	return 1;
 }
 
+/**
+ * cap_inode_killpriv - Erase the security markings on an inode
+ * @dentry: The inode/dentry to alter
+ *
+ * Erase the privilege-enhancing security markings on an inode.
+ *
+ * Returns 0 if successful, -ve on error.
+ */
 int cap_inode_killpriv(struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
@@ -202,19 +265,75 @@
 	return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
 }
 
-static inline int cap_from_disk(struct vfs_cap_data *caps,
-				struct linux_binprm *bprm, unsigned size)
+/*
+ * Calculate the new process capability sets from the capability sets attached
+ * to a file.
+ */
+static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
+					  struct linux_binprm *bprm,
+					  bool *effective)
 {
+	struct cred *new = bprm->cred;
+	unsigned i;
+	int ret = 0;
+
+	if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
+		*effective = true;
+
+	CAP_FOR_EACH_U32(i) {
+		__u32 permitted = caps->permitted.cap[i];
+		__u32 inheritable = caps->inheritable.cap[i];
+
+		/*
+		 * pP' = (X & fP) | (pI & fI)
+		 */
+		new->cap_permitted.cap[i] =
+			(new->cap_bset.cap[i] & permitted) |
+			(new->cap_inheritable.cap[i] & inheritable);
+
+		if (permitted & ~new->cap_permitted.cap[i])
+			/* insufficient to execute correctly */
+			ret = -EPERM;
+	}
+
+	/*
+	 * For legacy apps, with no internal support for recognizing they
+	 * do not have enough capabilities, we return an error if they are
+	 * missing some "forced" (aka file-permitted) capabilities.
+	 */
+	return *effective ? ret : 0;
+}
+
+/*
+ * Extract the on-exec-apply capability sets for an executable file.
+ */
+int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
+{
+	struct inode *inode = dentry->d_inode;
 	__u32 magic_etc;
 	unsigned tocopy, i;
-	int ret;
+	int size;
+	struct vfs_cap_data caps;
+
+	memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
+
+	if (!inode || !inode->i_op || !inode->i_op->getxattr)
+		return -ENODATA;
+
+	size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps,
+				   XATTR_CAPS_SZ);
+	if (size == -ENODATA || size == -EOPNOTSUPP)
+		/* no data, that's ok */
+		return -ENODATA;
+	if (size < 0)
+		return size;
 
 	if (size < sizeof(magic_etc))
 		return -EINVAL;
 
-	magic_etc = le32_to_cpu(caps->magic_etc);
+	cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc);
 
-	switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
+	switch (magic_etc & VFS_CAP_REVISION_MASK) {
 	case VFS_CAP_REVISION_1:
 		if (size != XATTR_CAPS_SZ_1)
 			return -EINVAL;
@@ -229,77 +348,48 @@
 		return -EINVAL;
 	}
 
-	if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
-		bprm->cap_effective = true;
-	} else {
-		bprm->cap_effective = false;
-	}
-
-	ret = 0;
-
 	CAP_FOR_EACH_U32(i) {
-		__u32 value_cpu;
-
-		if (i >= tocopy) {
-			/*
-			 * Legacy capability sets have no upper bits
-			 */
-			bprm->cap_post_exec_permitted.cap[i] = 0;
-			continue;
-		}
-		/*
-		 * pP' = (X & fP) | (pI & fI)
-		 */
-		value_cpu = le32_to_cpu(caps->data[i].permitted);
-		bprm->cap_post_exec_permitted.cap[i] =
-			(current->cap_bset.cap[i] & value_cpu) |
-			(current->cap_inheritable.cap[i] &
-				le32_to_cpu(caps->data[i].inheritable));
-		if (value_cpu & ~bprm->cap_post_exec_permitted.cap[i]) {
-			/*
-			 * insufficient to execute correctly
-			 */
-			ret = -EPERM;
-		}
+		if (i >= tocopy)
+			break;
+		cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted);
+		cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
 	}
 
-	/*
-	 * For legacy apps, with no internal support for recognizing they
-	 * do not have enough capabilities, we return an error if they are
-	 * missing some "forced" (aka file-permitted) capabilities.
-	 */
-	return bprm->cap_effective ? ret : 0;
+	return 0;
 }
 
-/* Locate any VFS capabilities: */
-static int get_file_caps(struct linux_binprm *bprm)
+/*
+ * Attempt to get the on-exec apply capability sets for an executable file from
+ * its xattrs and, if present, apply them to the proposed credentials being
+ * constructed by execve().
+ */
+static int get_file_caps(struct linux_binprm *bprm, bool *effective)
 {
 	struct dentry *dentry;
 	int rc = 0;
-	struct vfs_cap_data vcaps;
-	struct inode *inode;
+	struct cpu_vfs_cap_data vcaps;
 
 	bprm_clear_caps(bprm);
 
+	if (!file_caps_enabled)
+		return 0;
+
 	if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
 		return 0;
 
 	dentry = dget(bprm->file->f_dentry);
-	inode = dentry->d_inode;
-	if (!inode->i_op || !inode->i_op->getxattr)
-		goto out;
 
-	rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps,
-				   XATTR_CAPS_SZ);
-	if (rc == -ENODATA || rc == -EOPNOTSUPP) {
-		/* no data, that's ok */
-		rc = 0;
+	rc = get_vfs_caps_from_disk(dentry, &vcaps);
+	if (rc < 0) {
+		if (rc == -EINVAL)
+			printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n",
+				__func__, rc, bprm->filename);
+		else if (rc == -ENODATA)
+			rc = 0;
 		goto out;
 	}
-	if (rc < 0)
-		goto out;
 
-	rc = cap_from_disk(&vcaps, bprm, rc);
+	rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective);
 	if (rc == -EINVAL)
 		printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
 		       __func__, rc, bprm->filename);
@@ -323,18 +413,57 @@
 	return 0;
 }
 
-static inline int get_file_caps(struct linux_binprm *bprm)
+int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
+{
+	memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
+ 	return -ENODATA;
+}
+
+static inline int get_file_caps(struct linux_binprm *bprm, bool *effective)
 {
 	bprm_clear_caps(bprm);
 	return 0;
 }
 #endif
 
-int cap_bprm_set_security (struct linux_binprm *bprm)
+/*
+ * Determine whether a exec'ing process's new permitted capabilities should be
+ * limited to just what it already has.
+ *
+ * This prevents processes that are being ptraced from gaining access to
+ * CAP_SETPCAP, unless the process they're tracing already has it, and the
+ * binary they're executing has filecaps that elevate it.
+ *
+ *  Returns 1 if they should be limited, 0 if they are not.
+ */
+static inline int cap_limit_ptraced_target(void)
 {
+#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
+	if (capable(CAP_SETPCAP))
+		return 0;
+#endif
+	return 1;
+}
+
+/**
+ * cap_bprm_set_creds - Set up the proposed credentials for execve().
+ * @bprm: The execution parameters, including the proposed creds
+ *
+ * Set up the proposed credentials for a new execution context being
+ * constructed by execve().  The proposed creds in @bprm->cred is altered,
+ * which won't take effect immediately.  Returns 0 if successful, -ve on error.
+ */
+int cap_bprm_set_creds(struct linux_binprm *bprm)
+{
+	const struct cred *old = current_cred();
+	struct cred *new = bprm->cred;
+	bool effective;
 	int ret;
 
-	ret = get_file_caps(bprm);
+	effective = false;
+	ret = get_file_caps(bprm, &effective);
+	if (ret < 0)
+		return ret;
 
 	if (!issecure(SECURE_NOROOT)) {
 		/*
@@ -342,75 +471,113 @@
 		 * executables under compatibility mode, we override the
 		 * capability sets for the file.
 		 *
-		 * If only the real uid is 0, we do not set the effective
-		 * bit.
+		 * If only the real uid is 0, we do not set the effective bit.
 		 */
-		if (bprm->e_uid == 0 || current->uid == 0) {
+		if (new->euid == 0 || new->uid == 0) {
 			/* pP' = (cap_bset & ~0) | (pI & ~0) */
-			bprm->cap_post_exec_permitted = cap_combine(
-				current->cap_bset, current->cap_inheritable
-				);
-			bprm->cap_effective = (bprm->e_uid == 0);
-			ret = 0;
+			new->cap_permitted = cap_combine(old->cap_bset,
+							 old->cap_inheritable);
 		}
+		if (new->euid == 0)
+			effective = true;
 	}
 
-	return ret;
-}
-
-void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
-{
-	if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
-	    !cap_issubset(bprm->cap_post_exec_permitted,
-			  current->cap_permitted)) {
-		set_dumpable(current->mm, suid_dumpable);
-		current->pdeath_signal = 0;
-
-		if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
-			if (!capable(CAP_SETUID)) {
-				bprm->e_uid = current->uid;
-				bprm->e_gid = current->gid;
-			}
-			if (cap_limit_ptraced_target()) {
-				bprm->cap_post_exec_permitted = cap_intersect(
-					bprm->cap_post_exec_permitted,
-					current->cap_permitted);
-			}
+	/* Don't let someone trace a set[ug]id/setpcap binary with the revised
+	 * credentials unless they have the appropriate permit
+	 */
+	if ((new->euid != old->uid ||
+	     new->egid != old->gid ||
+	     !cap_issubset(new->cap_permitted, old->cap_permitted)) &&
+	    bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
+		/* downgrade; they get no more than they had, and maybe less */
+		if (!capable(CAP_SETUID)) {
+			new->euid = new->uid;
+			new->egid = new->gid;
 		}
+		if (cap_limit_ptraced_target())
+			new->cap_permitted = cap_intersect(new->cap_permitted,
+							   old->cap_permitted);
 	}
 
-	current->suid = current->euid = current->fsuid = bprm->e_uid;
-	current->sgid = current->egid = current->fsgid = bprm->e_gid;
+	new->suid = new->fsuid = new->euid;
+	new->sgid = new->fsgid = new->egid;
 
-	/* For init, we want to retain the capabilities set
-	 * in the init_task struct. Thus we skip the usual
-	 * capability rules */
+	/* For init, we want to retain the capabilities set in the initial
+	 * task.  Thus we skip the usual capability rules
+	 */
 	if (!is_global_init(current)) {
-		current->cap_permitted = bprm->cap_post_exec_permitted;
-		if (bprm->cap_effective)
-			current->cap_effective = bprm->cap_post_exec_permitted;
+		if (effective)
+			new->cap_effective = new->cap_permitted;
 		else
-			cap_clear(current->cap_effective);
+			cap_clear(new->cap_effective);
+	}
+	bprm->cap_effective = effective;
+
+	/*
+	 * Audit candidate if current->cap_effective is set
+	 *
+	 * We do not bother to audit if 3 things are true:
+	 *   1) cap_effective has all caps
+	 *   2) we are root
+	 *   3) root is supposed to have all caps (SECURE_NOROOT)
+	 * Since this is just a normal root execing a process.
+	 *
+	 * Number 1 above might fail if you don't have a full bset, but I think
+	 * that is interesting information to audit.
+	 */
+	if (!cap_isclear(new->cap_effective)) {
+		if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
+		    new->euid != 0 || new->uid != 0 ||
+		    issecure(SECURE_NOROOT)) {
+			ret = audit_log_bprm_fcaps(bprm, new, old);
+			if (ret < 0)
+				return ret;
+		}
 	}
 
-	/* AUD: Audit candidate if current->cap_effective is set */
-
-	current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
+	new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
+	return 0;
 }
 
-int cap_bprm_secureexec (struct linux_binprm *bprm)
+/**
+ * cap_bprm_secureexec - Determine whether a secure execution is required
+ * @bprm: The execution parameters
+ *
+ * Determine whether a secure execution is required, return 1 if it is, and 0
+ * if it is not.
+ *
+ * The credentials have been committed by this point, and so are no longer
+ * available through @bprm->cred.
+ */
+int cap_bprm_secureexec(struct linux_binprm *bprm)
 {
-	if (current->uid != 0) {
+	const struct cred *cred = current_cred();
+
+	if (cred->uid != 0) {
 		if (bprm->cap_effective)
 			return 1;
-		if (!cap_isclear(bprm->cap_post_exec_permitted))
+		if (!cap_isclear(cred->cap_permitted))
 			return 1;
 	}
 
-	return (current->euid != current->uid ||
-		current->egid != current->gid);
+	return (cred->euid != cred->uid ||
+		cred->egid != cred->gid);
 }
 
+/**
+ * cap_inode_setxattr - Determine whether an xattr may be altered
+ * @dentry: The inode/dentry being altered
+ * @name: The name of the xattr to be changed
+ * @value: The value that the xattr will be changed to
+ * @size: The size of value
+ * @flags: The replacement flag
+ *
+ * Determine whether an xattr may be altered or set on an inode, returning 0 if
+ * permission is granted, -ve if denied.
+ *
+ * This is used to make sure security xattrs don't get updated or set by those
+ * who aren't privileged to do so.
+ */
 int cap_inode_setxattr(struct dentry *dentry, const char *name,
 		       const void *value, size_t size, int flags)
 {
@@ -418,28 +585,42 @@
 		if (!capable(CAP_SETFCAP))
 			return -EPERM;
 		return 0;
-	} else if (!strncmp(name, XATTR_SECURITY_PREFIX,
+	}
+
+	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof(XATTR_SECURITY_PREFIX) - 1)  &&
 	    !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	return 0;
 }
 
+/**
+ * cap_inode_removexattr - Determine whether an xattr may be removed
+ * @dentry: The inode/dentry being altered
+ * @name: The name of the xattr to be changed
+ *
+ * Determine whether an xattr may be removed from an inode, returning 0 if
+ * permission is granted, -ve if denied.
+ *
+ * This is used to make sure security xattrs don't get removed by those who
+ * aren't privileged to remove them.
+ */
 int cap_inode_removexattr(struct dentry *dentry, const char *name)
 {
 	if (!strcmp(name, XATTR_NAME_CAPS)) {
 		if (!capable(CAP_SETFCAP))
 			return -EPERM;
 		return 0;
-	} else if (!strncmp(name, XATTR_SECURITY_PREFIX,
+	}
+
+	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof(XATTR_SECURITY_PREFIX) - 1)  &&
 	    !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	return 0;
 }
 
-/* moved from kernel/sys.c. */
-/* 
+/*
  * cap_emulate_setxuid() fixes the effective / permitted capabilities of
  * a process after a call to setuid, setreuid, or setresuid.
  *
@@ -453,10 +634,10 @@
  *  3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
  *  capabilities are set to the permitted capabilities.
  *
- *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should 
+ *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should
  *  never happen.
  *
- *  -astor 
+ *  -astor
  *
  * cevans - New behaviour, Oct '99
  * A process may, via prctl(), elect to keep its capabilities when it
@@ -468,61 +649,60 @@
  * files..
  * Thanks to Olaf Kirch and Peter Benie for spotting this.
  */
-static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
-					int old_suid)
+static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
 {
-	if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
-	    (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
+	if ((old->uid == 0 || old->euid == 0 || old->suid == 0) &&
+	    (new->uid != 0 && new->euid != 0 && new->suid != 0) &&
 	    !issecure(SECURE_KEEP_CAPS)) {
-		cap_clear (current->cap_permitted);
-		cap_clear (current->cap_effective);
+		cap_clear(new->cap_permitted);
+		cap_clear(new->cap_effective);
 	}
-	if (old_euid == 0 && current->euid != 0) {
-		cap_clear (current->cap_effective);
-	}
-	if (old_euid != 0 && current->euid == 0) {
-		current->cap_effective = current->cap_permitted;
-	}
+	if (old->euid == 0 && new->euid != 0)
+		cap_clear(new->cap_effective);
+	if (old->euid != 0 && new->euid == 0)
+		new->cap_effective = new->cap_permitted;
 }
 
-int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
-			  int flags)
+/**
+ * cap_task_fix_setuid - Fix up the results of setuid() call
+ * @new: The proposed credentials
+ * @old: The current task's current credentials
+ * @flags: Indications of what has changed
+ *
+ * Fix up the results of setuid() call before the credential changes are
+ * actually applied, returning 0 to grant the changes, -ve to deny them.
+ */
+int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
 {
 	switch (flags) {
 	case LSM_SETID_RE:
 	case LSM_SETID_ID:
 	case LSM_SETID_RES:
-		/* Copied from kernel/sys.c:setreuid/setuid/setresuid. */
-		if (!issecure (SECURE_NO_SETUID_FIXUP)) {
-			cap_emulate_setxuid (old_ruid, old_euid, old_suid);
+		/* juggle the capabilities to follow [RES]UID changes unless
+		 * otherwise suppressed */
+		if (!issecure(SECURE_NO_SETUID_FIXUP))
+			cap_emulate_setxuid(new, old);
+		break;
+
+	case LSM_SETID_FS:
+		/* juggle the capabilties to follow FSUID changes, unless
+		 * otherwise suppressed
+		 *
+		 * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
+		 *          if not, we might be a bit too harsh here.
+		 */
+		if (!issecure(SECURE_NO_SETUID_FIXUP)) {
+			if (old->fsuid == 0 && new->fsuid != 0)
+				new->cap_effective =
+					cap_drop_fs_set(new->cap_effective);
+
+			if (old->fsuid != 0 && new->fsuid == 0)
+				new->cap_effective =
+					cap_raise_fs_set(new->cap_effective,
+							 new->cap_permitted);
 		}
 		break;
-	case LSM_SETID_FS:
-		{
-			uid_t old_fsuid = old_ruid;
 
-			/* Copied from kernel/sys.c:setfsuid. */
-
-			/*
-			 * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
-			 *          if not, we might be a bit too harsh here.
-			 */
-
-			if (!issecure (SECURE_NO_SETUID_FIXUP)) {
-				if (old_fsuid == 0 && current->fsuid != 0) {
-					current->cap_effective =
-						cap_drop_fs_set(
-						    current->cap_effective);
-				}
-				if (old_fsuid != 0 && current->fsuid == 0) {
-					current->cap_effective =
-						cap_raise_fs_set(
-						    current->cap_effective,
-						    current->cap_permitted);
-				}
-			}
-			break;
-		}
 	default:
 		return -EINVAL;
 	}
@@ -543,42 +723,71 @@
  */
 static int cap_safe_nice(struct task_struct *p)
 {
-	if (!cap_issubset(p->cap_permitted, current->cap_permitted) &&
-	    !capable(CAP_SYS_NICE))
+	int is_subset;
+
+	rcu_read_lock();
+	is_subset = cap_issubset(__task_cred(p)->cap_permitted,
+				 current_cred()->cap_permitted);
+	rcu_read_unlock();
+
+	if (!is_subset && !capable(CAP_SYS_NICE))
 		return -EPERM;
 	return 0;
 }
 
-int cap_task_setscheduler (struct task_struct *p, int policy,
+/**
+ * cap_task_setscheduler - Detemine if scheduler policy change is permitted
+ * @p: The task to affect
+ * @policy: The policy to effect
+ * @lp: The parameters to the scheduling policy
+ *
+ * Detemine if the requested scheduler policy change is permitted for the
+ * specified task, returning 0 if permission is granted, -ve if denied.
+ */
+int cap_task_setscheduler(struct task_struct *p, int policy,
 			   struct sched_param *lp)
 {
 	return cap_safe_nice(p);
 }
 
-int cap_task_setioprio (struct task_struct *p, int ioprio)
+/**
+ * cap_task_ioprio - Detemine if I/O priority change is permitted
+ * @p: The task to affect
+ * @ioprio: The I/O priority to set
+ *
+ * Detemine if the requested I/O priority change is permitted for the specified
+ * task, returning 0 if permission is granted, -ve if denied.
+ */
+int cap_task_setioprio(struct task_struct *p, int ioprio)
 {
 	return cap_safe_nice(p);
 }
 
-int cap_task_setnice (struct task_struct *p, int nice)
+/**
+ * cap_task_ioprio - Detemine if task priority change is permitted
+ * @p: The task to affect
+ * @nice: The nice value to set
+ *
+ * Detemine if the requested task priority change is permitted for the
+ * specified task, returning 0 if permission is granted, -ve if denied.
+ */
+int cap_task_setnice(struct task_struct *p, int nice)
 {
 	return cap_safe_nice(p);
 }
 
 /*
- * called from kernel/sys.c for prctl(PR_CABSET_DROP)
- * done without task_capability_lock() because it introduces
- * no new races - i.e. only another task doing capget() on
- * this task could get inconsistent info.  There can be no
- * racing writer bc a task can only change its own caps.
+ * Implement PR_CAPBSET_DROP.  Attempt to remove the specified capability from
+ * the current task's bounding set.  Returns 0 on success, -ve on error.
  */
-static long cap_prctl_drop(unsigned long cap)
+static long cap_prctl_drop(struct cred *new, unsigned long cap)
 {
 	if (!capable(CAP_SETPCAP))
 		return -EPERM;
 	if (!cap_valid(cap))
 		return -EINVAL;
-	cap_lower(current->cap_bset, cap);
+
+	cap_lower(new->cap_bset, cap);
 	return 0;
 }
 
@@ -598,22 +807,42 @@
 }
 #endif
 
+/**
+ * cap_task_prctl - Implement process control functions for this security module
+ * @option: The process control function requested
+ * @arg2, @arg3, @arg4, @arg5: The argument data for this function
+ *
+ * Allow process control functions (sys_prctl()) to alter capabilities; may
+ * also deny access to other functions not otherwise implemented here.
+ *
+ * Returns 0 or +ve on success, -ENOSYS if this function is not implemented
+ * here, other -ve on error.  If -ENOSYS is returned, sys_prctl() and other LSM
+ * modules will consider performing the function.
+ */
 int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
-		   unsigned long arg4, unsigned long arg5, long *rc_p)
+		   unsigned long arg4, unsigned long arg5)
 {
+	struct cred *new;
 	long error = 0;
 
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+
 	switch (option) {
 	case PR_CAPBSET_READ:
+		error = -EINVAL;
 		if (!cap_valid(arg2))
-			error = -EINVAL;
-		else
-			error = !!cap_raised(current->cap_bset, arg2);
-		break;
+			goto error;
+		error = !!cap_raised(new->cap_bset, arg2);
+		goto no_change;
+
 #ifdef CONFIG_SECURITY_FILE_CAPABILITIES
 	case PR_CAPBSET_DROP:
-		error = cap_prctl_drop(arg2);
-		break;
+		error = cap_prctl_drop(new, arg2);
+		if (error < 0)
+			goto error;
+		goto changed;
 
 	/*
 	 * The next four prctl's remain to assist with transitioning a
@@ -635,12 +864,12 @@
 	 * capability-based-privilege environment.
 	 */
 	case PR_SET_SECUREBITS:
-		if ((((current->securebits & SECURE_ALL_LOCKS) >> 1)
-		     & (current->securebits ^ arg2))                  /*[1]*/
-		    || ((current->securebits & SECURE_ALL_LOCKS
-			 & ~arg2))                                    /*[2]*/
-		    || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
-		    || (cap_capable(current, CAP_SETPCAP) != 0)) {    /*[4]*/
+		error = -EPERM;
+		if ((((new->securebits & SECURE_ALL_LOCKS) >> 1)
+		     & (new->securebits ^ arg2))			/*[1]*/
+		    || ((new->securebits & SECURE_ALL_LOCKS & ~arg2))	/*[2]*/
+		    || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS))	/*[3]*/
+		    || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/
 			/*
 			 * [1] no changing of bits that are locked
 			 * [2] no unlocking of locks
@@ -648,65 +877,80 @@
 			 * [4] doing anything requires privilege (go read about
 			 *     the "sendmail capabilities bug")
 			 */
-			error = -EPERM;  /* cannot change a locked bit */
-		} else {
-			current->securebits = arg2;
-		}
-		break;
+		    )
+			/* cannot change a locked bit */
+			goto error;
+		new->securebits = arg2;
+		goto changed;
+
 	case PR_GET_SECUREBITS:
-		error = current->securebits;
-		break;
+		error = new->securebits;
+		goto no_change;
 
 #endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
 
 	case PR_GET_KEEPCAPS:
 		if (issecure(SECURE_KEEP_CAPS))
 			error = 1;
-		break;
+		goto no_change;
+
 	case PR_SET_KEEPCAPS:
+		error = -EINVAL;
 		if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
-			error = -EINVAL;
-		else if (issecure(SECURE_KEEP_CAPS_LOCKED))
-			error = -EPERM;
-		else if (arg2)
-			current->securebits |= issecure_mask(SECURE_KEEP_CAPS);
+			goto error;
+		error = -EPERM;
+		if (issecure(SECURE_KEEP_CAPS_LOCKED))
+			goto error;
+		if (arg2)
+			new->securebits |= issecure_mask(SECURE_KEEP_CAPS);
 		else
-			current->securebits &=
-				~issecure_mask(SECURE_KEEP_CAPS);
-		break;
+			new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
+		goto changed;
 
 	default:
 		/* No functionality available - continue with default */
-		return 0;
+		error = -ENOSYS;
+		goto error;
 	}
 
 	/* Functionality provided */
-	*rc_p = error;
-	return 1;
+changed:
+	return commit_creds(new);
+
+no_change:
+	error = 0;
+error:
+	abort_creds(new);
+	return error;
 }
 
-void cap_task_reparent_to_init (struct task_struct *p)
-{
-	cap_set_init_eff(p->cap_effective);
-	cap_clear(p->cap_inheritable);
-	cap_set_full(p->cap_permitted);
-	p->securebits = SECUREBITS_DEFAULT;
-	return;
-}
-
-int cap_syslog (int type)
+/**
+ * cap_syslog - Determine whether syslog function is permitted
+ * @type: Function requested
+ *
+ * Determine whether the current process is permitted to use a particular
+ * syslog function, returning 0 if permission is granted, -ve if not.
+ */
+int cap_syslog(int type)
 {
 	if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	return 0;
 }
 
+/**
+ * cap_vm_enough_memory - Determine whether a new virtual mapping is permitted
+ * @mm: The VM space in which the new mapping is to be made
+ * @pages: The size of the mapping
+ *
+ * Determine whether the allocation of a new virtual mapping by the current
+ * task is permitted, returning 0 if permission is granted, -ve if not.
+ */
 int cap_vm_enough_memory(struct mm_struct *mm, long pages)
 {
 	int cap_sys_admin = 0;
 
-	if (cap_capable(current, CAP_SYS_ADMIN) == 0)
+	if (cap_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0)
 		cap_sys_admin = 1;
 	return __vm_enough_memory(mm, pages, cap_sys_admin);
 }
-
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 239098f..81932ab 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -12,8 +12,8 @@
 #ifndef _INTERNAL_H
 #define _INTERNAL_H
 
+#include <linux/sched.h>
 #include <linux/key-type.h>
-#include <linux/key-ui.h>
 
 static inline __attribute__((format(printf, 1, 2)))
 void no_printk(const char *fmt, ...)
@@ -26,7 +26,7 @@
 #define kleave(FMT, ...) \
 	printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
 #define kdebug(FMT, ...) \
-	printk(KERN_DEBUG "xxx" FMT"yyy\n", ##__VA_ARGS__)
+	printk(KERN_DEBUG "   "FMT"\n", ##__VA_ARGS__)
 #else
 #define kenter(FMT, ...) \
 	no_printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__)
@@ -82,6 +82,9 @@
 extern wait_queue_head_t request_key_conswq;
 
 
+extern struct key_type *key_type_lookup(const char *type);
+extern void key_type_put(struct key_type *ktype);
+
 extern int __key_link(struct key *keyring, struct key *key);
 
 extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
@@ -95,7 +98,7 @@
 typedef int (*key_match_func_t)(const struct key *, const void *);
 
 extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
-				    struct task_struct *tsk,
+				    const struct cred *cred,
 				    struct key_type *type,
 				    const void *description,
 				    key_match_func_t match);
@@ -103,13 +106,13 @@
 extern key_ref_t search_process_keyrings(struct key_type *type,
 					 const void *description,
 					 key_match_func_t match,
-					 struct task_struct *tsk);
+					 const struct cred *cred);
 
 extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check);
 
-extern int install_user_keyrings(struct task_struct *tsk);
-extern int install_thread_keyring(struct task_struct *tsk);
-extern int install_process_keyring(struct task_struct *tsk);
+extern int install_user_keyrings(void);
+extern int install_thread_keyring_to_cred(struct cred *);
+extern int install_process_keyring_to_cred(struct cred *);
 
 extern struct key *request_key_and_link(struct key_type *type,
 					const char *description,
@@ -119,12 +122,39 @@
 					struct key *dest_keyring,
 					unsigned long flags);
 
+extern key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
+				 key_perm_t perm);
+
+extern long join_session_keyring(const char *name);
+
+/*
+ * check to see whether permission is granted to use a key in the desired way
+ */
+extern int key_task_permission(const key_ref_t key_ref,
+			       const struct cred *cred,
+			       key_perm_t perm);
+
+static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
+{
+	return key_task_permission(key_ref, current_cred(), perm);
+}
+
+/* required permissions */
+#define	KEY_VIEW	0x01	/* require permission to view attributes */
+#define	KEY_READ	0x02	/* require permission to read content */
+#define	KEY_WRITE	0x04	/* require permission to update / modify */
+#define	KEY_SEARCH	0x08	/* require permission to search (keyring) or find (key) */
+#define	KEY_LINK	0x10	/* require permission to link */
+#define	KEY_SETATTR	0x20	/* require permission to change attributes */
+#define	KEY_ALL		0x3f	/* all the above permissions */
+
 /*
  * request_key authorisation
  */
 struct request_key_auth {
 	struct key		*target_key;
-	struct task_struct	*context;
+	struct key		*dest_keyring;
+	const struct cred	*cred;
 	void			*callout_info;
 	size_t			callout_len;
 	pid_t			pid;
@@ -133,7 +163,8 @@
 extern struct key_type key_type_request_key_auth;
 extern struct key *request_key_auth_new(struct key *target,
 					const void *callout_info,
-					size_t callout_len);
+					size_t callout_len,
+					struct key *dest_keyring);
 
 extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
 
diff --git a/security/keys/key.c b/security/keys/key.c
index 14948cf..f76c8a5 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -218,7 +218,7 @@
  *   instantiate the key or discard it before returning
  */
 struct key *key_alloc(struct key_type *type, const char *desc,
-		      uid_t uid, gid_t gid, struct task_struct *ctx,
+		      uid_t uid, gid_t gid, const struct cred *cred,
 		      key_perm_t perm, unsigned long flags)
 {
 	struct key_user *user = NULL;
@@ -294,7 +294,7 @@
 #endif
 
 	/* let the security module know about the key */
-	ret = security_key_alloc(key, ctx, flags);
+	ret = security_key_alloc(key, cred, flags);
 	if (ret < 0)
 		goto security_error;
 
@@ -391,7 +391,7 @@
 				      const void *data,
 				      size_t datalen,
 				      struct key *keyring,
-				      struct key *instkey)
+				      struct key *authkey)
 {
 	int ret, awaken;
 
@@ -421,8 +421,8 @@
 				ret = __key_link(keyring, key);
 
 			/* disable the authorisation key */
-			if (instkey)
-				key_revoke(instkey);
+			if (authkey)
+				key_revoke(authkey);
 		}
 	}
 
@@ -444,14 +444,14 @@
 			     const void *data,
 			     size_t datalen,
 			     struct key *keyring,
-			     struct key *instkey)
+			     struct key *authkey)
 {
 	int ret;
 
 	if (keyring)
 		down_write(&keyring->sem);
 
-	ret = __key_instantiate_and_link(key, data, datalen, keyring, instkey);
+	ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey);
 
 	if (keyring)
 		up_write(&keyring->sem);
@@ -469,7 +469,7 @@
 int key_negate_and_link(struct key *key,
 			unsigned timeout,
 			struct key *keyring,
-			struct key *instkey)
+			struct key *authkey)
 {
 	struct timespec now;
 	int ret, awaken;
@@ -504,8 +504,8 @@
 			ret = __key_link(keyring, key);
 
 		/* disable the authorisation key */
-		if (instkey)
-			key_revoke(instkey);
+		if (authkey)
+			key_revoke(authkey);
 	}
 
 	mutex_unlock(&key_construction_mutex);
@@ -743,6 +743,7 @@
 			       key_perm_t perm,
 			       unsigned long flags)
 {
+	const struct cred *cred = current_cred();
 	struct key_type *ktype;
 	struct key *keyring, *key = NULL;
 	key_ref_t key_ref;
@@ -802,8 +803,8 @@
 	}
 
 	/* allocate a new key */
-	key = key_alloc(ktype, description, current->fsuid, current->fsgid,
-			current, perm, flags);
+	key = key_alloc(ktype, description, cred->fsuid, cred->fsgid, cred,
+			perm, flags);
 	if (IS_ERR(key)) {
 		key_ref = ERR_CAST(key);
 		goto error_3;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index acc9c89..7c72baa 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -103,7 +103,7 @@
 	}
 
 	/* find the target keyring (which must be writable) */
-	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+	keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
 	if (IS_ERR(keyring_ref)) {
 		ret = PTR_ERR(keyring_ref);
 		goto error3;
@@ -185,7 +185,7 @@
 	/* get the destination keyring if specified */
 	dest_ref = NULL;
 	if (destringid) {
-		dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+		dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE);
 		if (IS_ERR(dest_ref)) {
 			ret = PTR_ERR(dest_ref);
 			goto error3;
@@ -235,7 +235,7 @@
 	key_ref_t key_ref;
 	long ret;
 
-	key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
+	key_ref = lookup_user_key(id, create, 0, KEY_SEARCH);
 	if (IS_ERR(key_ref)) {
 		ret = PTR_ERR(key_ref);
 		goto error;
@@ -308,7 +308,7 @@
 	}
 
 	/* find the target key (which must be writable) */
-	key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+	key_ref = lookup_user_key(id, 0, 0, KEY_WRITE);
 	if (IS_ERR(key_ref)) {
 		ret = PTR_ERR(key_ref);
 		goto error2;
@@ -336,7 +336,7 @@
 	key_ref_t key_ref;
 	long ret;
 
-	key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+	key_ref = lookup_user_key(id, 0, 0, KEY_WRITE);
 	if (IS_ERR(key_ref)) {
 		ret = PTR_ERR(key_ref);
 		goto error;
@@ -362,7 +362,7 @@
 	key_ref_t keyring_ref;
 	long ret;
 
-	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+	keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
 	if (IS_ERR(keyring_ref)) {
 		ret = PTR_ERR(keyring_ref);
 		goto error;
@@ -388,13 +388,13 @@
 	key_ref_t keyring_ref, key_ref;
 	long ret;
 
-	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+	keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
 	if (IS_ERR(keyring_ref)) {
 		ret = PTR_ERR(keyring_ref);
 		goto error;
 	}
 
-	key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
+	key_ref = lookup_user_key(id, 1, 0, KEY_LINK);
 	if (IS_ERR(key_ref)) {
 		ret = PTR_ERR(key_ref);
 		goto error2;
@@ -422,13 +422,13 @@
 	key_ref_t keyring_ref, key_ref;
 	long ret;
 
-	keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
+	keyring_ref = lookup_user_key(ringid, 0, 0, KEY_WRITE);
 	if (IS_ERR(keyring_ref)) {
 		ret = PTR_ERR(keyring_ref);
 		goto error;
 	}
 
-	key_ref = lookup_user_key(NULL, id, 0, 0, 0);
+	key_ref = lookup_user_key(id, 0, 0, 0);
 	if (IS_ERR(key_ref)) {
 		ret = PTR_ERR(key_ref);
 		goto error2;
@@ -464,7 +464,7 @@
 	char *tmpbuf;
 	long ret;
 
-	key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
+	key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW);
 	if (IS_ERR(key_ref)) {
 		/* viewing a key under construction is permitted if we have the
 		 * authorisation token handy */
@@ -472,7 +472,7 @@
 			instkey = key_get_instantiation_authkey(keyid);
 			if (!IS_ERR(instkey)) {
 				key_put(instkey);
-				key_ref = lookup_user_key(NULL, keyid,
+				key_ref = lookup_user_key(keyid,
 							  0, 1, 0);
 				if (!IS_ERR(key_ref))
 					goto okay;
@@ -557,7 +557,7 @@
 	}
 
 	/* get the keyring at which to begin the search */
-	keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
+	keyring_ref = lookup_user_key(ringid, 0, 0, KEY_SEARCH);
 	if (IS_ERR(keyring_ref)) {
 		ret = PTR_ERR(keyring_ref);
 		goto error2;
@@ -566,7 +566,7 @@
 	/* get the destination keyring if specified */
 	dest_ref = NULL;
 	if (destringid) {
-		dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+		dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE);
 		if (IS_ERR(dest_ref)) {
 			ret = PTR_ERR(dest_ref);
 			goto error3;
@@ -636,7 +636,7 @@
 	long ret;
 
 	/* find the key first */
-	key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);
+	key_ref = lookup_user_key(keyid, 0, 0, 0);
 	if (IS_ERR(key_ref)) {
 		ret = -ENOKEY;
 		goto error;
@@ -699,7 +699,7 @@
 	if (uid == (uid_t) -1 && gid == (gid_t) -1)
 		goto error;
 
-	key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
+	key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
 	if (IS_ERR(key_ref)) {
 		ret = PTR_ERR(key_ref);
 		goto error;
@@ -804,7 +804,7 @@
 	if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
 		goto error;
 
-	key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
+	key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
 	if (IS_ERR(key_ref)) {
 		ret = PTR_ERR(key_ref);
 		goto error;
@@ -817,7 +817,7 @@
 	down_write(&key->sem);
 
 	/* if we're not the sysadmin, we can only change a key that we own */
-	if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) {
+	if (capable(CAP_SYS_ADMIN) || key->uid == current_fsuid()) {
 		key->perm = perm;
 		ret = 0;
 	}
@@ -829,6 +829,60 @@
 
 } /* end keyctl_setperm_key() */
 
+/*
+ * get the destination keyring for instantiation
+ */
+static long get_instantiation_keyring(key_serial_t ringid,
+				      struct request_key_auth *rka,
+				      struct key **_dest_keyring)
+{
+	key_ref_t dkref;
+
+	/* just return a NULL pointer if we weren't asked to make a link */
+	if (ringid == 0) {
+		*_dest_keyring = NULL;
+		return 0;
+	}
+
+	/* if a specific keyring is nominated by ID, then use that */
+	if (ringid > 0) {
+		dkref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+		if (IS_ERR(dkref))
+			return PTR_ERR(dkref);
+		*_dest_keyring = key_ref_to_ptr(dkref);
+		return 0;
+	}
+
+	if (ringid == KEY_SPEC_REQKEY_AUTH_KEY)
+		return -EINVAL;
+
+	/* otherwise specify the destination keyring recorded in the
+	 * authorisation key (any KEY_SPEC_*_KEYRING) */
+	if (ringid >= KEY_SPEC_REQUESTOR_KEYRING) {
+		*_dest_keyring = rka->dest_keyring;
+		return 0;
+	}
+
+	return -ENOKEY;
+}
+
+/*
+ * change the request_key authorisation key on the current process
+ */
+static int keyctl_change_reqkey_auth(struct key *key)
+{
+	struct cred *new;
+
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+
+	key_put(new->request_key_auth);
+	new->request_key_auth = key_get(key);
+
+	return commit_creds(new);
+}
+
 /*****************************************************************************/
 /*
  * instantiate the key with the specified payload, and, if one is given, link
@@ -839,13 +893,15 @@
 			    size_t plen,
 			    key_serial_t ringid)
 {
+	const struct cred *cred = current_cred();
 	struct request_key_auth *rka;
-	struct key *instkey;
-	key_ref_t keyring_ref;
+	struct key *instkey, *dest_keyring;
 	void *payload;
 	long ret;
 	bool vm = false;
 
+	kenter("%d,,%zu,%d", id, plen, ringid);
+
 	ret = -EINVAL;
 	if (plen > 1024 * 1024 - 1)
 		goto error;
@@ -853,7 +909,7 @@
 	/* the appropriate instantiation authorisation key must have been
 	 * assumed before calling this */
 	ret = -EPERM;
-	instkey = current->request_key_auth;
+	instkey = cred->request_key_auth;
 	if (!instkey)
 		goto error;
 
@@ -883,28 +939,20 @@
 
 	/* find the destination keyring amongst those belonging to the
 	 * requesting task */
-	keyring_ref = NULL;
-	if (ringid) {
-		keyring_ref = lookup_user_key(rka->context, ringid, 1, 0,
-					      KEY_WRITE);
-		if (IS_ERR(keyring_ref)) {
-			ret = PTR_ERR(keyring_ref);
-			goto error2;
-		}
-	}
+	ret = get_instantiation_keyring(ringid, rka, &dest_keyring);
+	if (ret < 0)
+		goto error2;
 
 	/* instantiate the key and link it into a keyring */
 	ret = key_instantiate_and_link(rka->target_key, payload, plen,
-				       key_ref_to_ptr(keyring_ref), instkey);
+				       dest_keyring, instkey);
 
-	key_ref_put(keyring_ref);
+	key_put(dest_keyring);
 
 	/* discard the assumed authority if it's just been disabled by
 	 * instantiation of the key */
-	if (ret == 0) {
-		key_put(current->request_key_auth);
-		current->request_key_auth = NULL;
-	}
+	if (ret == 0)
+		keyctl_change_reqkey_auth(NULL);
 
 error2:
 	if (!vm)
@@ -923,15 +971,17 @@
  */
 long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
 {
+	const struct cred *cred = current_cred();
 	struct request_key_auth *rka;
-	struct key *instkey;
-	key_ref_t keyring_ref;
+	struct key *instkey, *dest_keyring;
 	long ret;
 
+	kenter("%d,%u,%d", id, timeout, ringid);
+
 	/* the appropriate instantiation authorisation key must have been
 	 * assumed before calling this */
 	ret = -EPERM;
-	instkey = current->request_key_auth;
+	instkey = cred->request_key_auth;
 	if (!instkey)
 		goto error;
 
@@ -941,27 +991,20 @@
 
 	/* find the destination keyring if present (which must also be
 	 * writable) */
-	keyring_ref = NULL;
-	if (ringid) {
-		keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-		if (IS_ERR(keyring_ref)) {
-			ret = PTR_ERR(keyring_ref);
-			goto error;
-		}
-	}
+	ret = get_instantiation_keyring(ringid, rka, &dest_keyring);
+	if (ret < 0)
+		goto error;
 
 	/* instantiate the key and link it into a keyring */
 	ret = key_negate_and_link(rka->target_key, timeout,
-				  key_ref_to_ptr(keyring_ref), instkey);
+				  dest_keyring, instkey);
 
-	key_ref_put(keyring_ref);
+	key_put(dest_keyring);
 
 	/* discard the assumed authority if it's just been disabled by
 	 * instantiation of the key */
-	if (ret == 0) {
-		key_put(current->request_key_auth);
-		current->request_key_auth = NULL;
-	}
+	if (ret == 0)
+		keyctl_change_reqkey_auth(NULL);
 
 error:
 	return ret;
@@ -975,35 +1018,56 @@
  */
 long keyctl_set_reqkey_keyring(int reqkey_defl)
 {
-	int ret;
+	struct cred *new;
+	int ret, old_setting;
+
+	old_setting = current_cred_xxx(jit_keyring);
+
+	if (reqkey_defl == KEY_REQKEY_DEFL_NO_CHANGE)
+		return old_setting;
+
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
 
 	switch (reqkey_defl) {
 	case KEY_REQKEY_DEFL_THREAD_KEYRING:
-		ret = install_thread_keyring(current);
+		ret = install_thread_keyring_to_cred(new);
 		if (ret < 0)
-			return ret;
+			goto error;
 		goto set;
 
 	case KEY_REQKEY_DEFL_PROCESS_KEYRING:
-		ret = install_process_keyring(current);
-		if (ret < 0)
-			return ret;
+		ret = install_process_keyring_to_cred(new);
+		if (ret < 0) {
+			if (ret != -EEXIST)
+				goto error;
+			ret = 0;
+		}
+		goto set;
 
 	case KEY_REQKEY_DEFL_DEFAULT:
 	case KEY_REQKEY_DEFL_SESSION_KEYRING:
 	case KEY_REQKEY_DEFL_USER_KEYRING:
 	case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
-	set:
-		current->jit_keyring = reqkey_defl;
+	case KEY_REQKEY_DEFL_REQUESTOR_KEYRING:
+		goto set;
 
 	case KEY_REQKEY_DEFL_NO_CHANGE:
-		return current->jit_keyring;
-
 	case KEY_REQKEY_DEFL_GROUP_KEYRING:
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
+		goto error;
 	}
 
+set:
+	new->jit_keyring = reqkey_defl;
+	commit_creds(new);
+	return old_setting;
+error:
+	abort_creds(new);
+	return -EINVAL;
+
 } /* end keyctl_set_reqkey_keyring() */
 
 /*****************************************************************************/
@@ -1018,7 +1082,7 @@
 	time_t expiry;
 	long ret;
 
-	key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
+	key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
 	if (IS_ERR(key_ref)) {
 		ret = PTR_ERR(key_ref);
 		goto error;
@@ -1062,9 +1126,7 @@
 
 	/* we divest ourselves of authority if given an ID of 0 */
 	if (id == 0) {
-		key_put(current->request_key_auth);
-		current->request_key_auth = NULL;
-		ret = 0;
+		ret = keyctl_change_reqkey_auth(NULL);
 		goto error;
 	}
 
@@ -1079,10 +1141,12 @@
 		goto error;
 	}
 
-	key_put(current->request_key_auth);
-	current->request_key_auth = authkey;
-	ret = authkey->serial;
+	ret = keyctl_change_reqkey_auth(authkey);
+	if (ret < 0)
+		goto error;
+	key_put(authkey);
 
+	ret = authkey->serial;
 error:
 	return ret;
 
@@ -1105,7 +1169,7 @@
 	char *context;
 	long ret;
 
-	key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
+	key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW);
 	if (IS_ERR(key_ref)) {
 		if (PTR_ERR(key_ref) != -EACCES)
 			return PTR_ERR(key_ref);
@@ -1117,7 +1181,7 @@
 			return PTR_ERR(key_ref);
 		key_put(instkey);
 
-		key_ref = lookup_user_key(NULL, keyid, 0, 1, 0);
+		key_ref = lookup_user_key(keyid, 0, 1, 0);
 		if (IS_ERR(key_ref))
 			return PTR_ERR(key_ref);
 	}
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index a9ab8af..ed85157 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -16,6 +16,7 @@
 #include <linux/security.h>
 #include <linux/seq_file.h>
 #include <linux/err.h>
+#include <keys/keyring-type.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
@@ -244,14 +245,14 @@
  * allocate a keyring and link into the destination keyring
  */
 struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
-			  struct task_struct *ctx, unsigned long flags,
+			  const struct cred *cred, unsigned long flags,
 			  struct key *dest)
 {
 	struct key *keyring;
 	int ret;
 
 	keyring = key_alloc(&key_type_keyring, description,
-			    uid, gid, ctx,
+			    uid, gid, cred,
 			    (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
 			    flags);
 
@@ -280,7 +281,7 @@
  * - we propagate the possession attribute from the keyring ref to the key ref
  */
 key_ref_t keyring_search_aux(key_ref_t keyring_ref,
-			     struct task_struct *context,
+			     const struct cred *cred,
 			     struct key_type *type,
 			     const void *description,
 			     key_match_func_t match)
@@ -303,7 +304,7 @@
 	key_check(keyring);
 
 	/* top keyring must have search permission to begin the search */
-        err = key_task_permission(keyring_ref, context, KEY_SEARCH);
+        err = key_task_permission(keyring_ref, cred, KEY_SEARCH);
 	if (err < 0) {
 		key_ref = ERR_PTR(err);
 		goto error;
@@ -376,7 +377,7 @@
 
 		/* key must have search permissions */
 		if (key_task_permission(make_key_ref(key, possessed),
-					context, KEY_SEARCH) < 0)
+					cred, KEY_SEARCH) < 0)
 			continue;
 
 		/* we set a different error code if we pass a negative key */
@@ -403,7 +404,7 @@
 			continue;
 
 		if (key_task_permission(make_key_ref(key, possessed),
-					context, KEY_SEARCH) < 0)
+					cred, KEY_SEARCH) < 0)
 			continue;
 
 		/* stack the current position */
@@ -458,7 +459,7 @@
 	if (!type->match)
 		return ERR_PTR(-ENOKEY);
 
-	return keyring_search_aux(keyring, current,
+	return keyring_search_aux(keyring, current->cred,
 				  type, description, type->match);
 
 } /* end keyring_search() */
diff --git a/security/keys/permission.c b/security/keys/permission.c
index 3b41f9b..5d9fc7b 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -14,12 +14,19 @@
 #include "internal.h"
 
 /*****************************************************************************/
-/*
- * check to see whether permission is granted to use a key in the desired way,
- * but permit the security modules to override
+/**
+ * key_task_permission - Check a key can be used
+ * @key_ref: The key to check
+ * @cred: The credentials to use
+ * @perm: The permissions to check for
+ *
+ * Check to see whether permission is granted to use a key in the desired way,
+ * but permit the security modules to override.
+ *
+ * The caller must hold either a ref on cred or must hold the RCU readlock or a
+ * spinlock.
  */
-int key_task_permission(const key_ref_t key_ref,
-			struct task_struct *context,
+int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
 			key_perm_t perm)
 {
 	struct key *key;
@@ -29,7 +36,7 @@
 	key = key_ref_to_ptr(key_ref);
 
 	/* use the second 8-bits of permissions for keys the caller owns */
-	if (key->uid == context->fsuid) {
+	if (key->uid == cred->fsuid) {
 		kperm = key->perm >> 16;
 		goto use_these_perms;
 	}
@@ -37,15 +44,12 @@
 	/* use the third 8-bits of permissions for keys the caller has a group
 	 * membership in common with */
 	if (key->gid != -1 && key->perm & KEY_GRP_ALL) {
-		if (key->gid == context->fsgid) {
+		if (key->gid == cred->fsgid) {
 			kperm = key->perm >> 8;
 			goto use_these_perms;
 		}
 
-		task_lock(context);
-		ret = groups_search(context->group_info, key->gid);
-		task_unlock(context);
-
+		ret = groups_search(cred->group_info, key->gid);
 		if (ret) {
 			kperm = key->perm >> 8;
 			goto use_these_perms;
@@ -56,6 +60,7 @@
 	kperm = key->perm;
 
 use_these_perms:
+
 	/* use the top 8-bits of permissions for keys the caller possesses
 	 * - possessor permissions are additive with other permissions
 	 */
@@ -68,7 +73,7 @@
 		return -EACCES;
 
 	/* let LSM be the final arbiter */
-	return security_key_permission(key_ref, context, perm);
+	return security_key_permission(key_ref, cred, perm);
 
 } /* end key_task_permission() */
 
diff --git a/security/keys/proc.c b/security/keys/proc.c
index f619170..7f508de 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -136,8 +136,12 @@
 	int rc;
 
 	/* check whether the current task is allowed to view the key (assuming
-	 * non-possession) */
-	rc = key_task_permission(make_key_ref(key, 0), current, KEY_VIEW);
+	 * non-possession)
+	 * - the caller holds a spinlock, and thus the RCU read lock, making our
+	 *   access to __current_cred() safe
+	 */
+	rc = key_task_permission(make_key_ref(key, 0), current_cred(),
+				 KEY_VIEW);
 	if (rc < 0)
 		return 0;
 
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 45b240a..2f5d89e 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -40,13 +40,17 @@
 /*
  * install user and user session keyrings for a particular UID
  */
-int install_user_keyrings(struct task_struct *tsk)
+int install_user_keyrings(void)
 {
-	struct user_struct *user = tsk->user;
+	struct user_struct *user;
+	const struct cred *cred;
 	struct key *uid_keyring, *session_keyring;
 	char buf[20];
 	int ret;
 
+	cred = current_cred();
+	user = cred->user;
+
 	kenter("%p{%u}", user, user->uid);
 
 	if (user->uid_keyring) {
@@ -67,7 +71,7 @@
 		uid_keyring = find_keyring_by_name(buf, true);
 		if (IS_ERR(uid_keyring)) {
 			uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
-						    tsk, KEY_ALLOC_IN_QUOTA,
+						    cred, KEY_ALLOC_IN_QUOTA,
 						    NULL);
 			if (IS_ERR(uid_keyring)) {
 				ret = PTR_ERR(uid_keyring);
@@ -83,7 +87,7 @@
 		if (IS_ERR(session_keyring)) {
 			session_keyring =
 				keyring_alloc(buf, user->uid, (gid_t) -1,
-					      tsk, KEY_ALLOC_IN_QUOTA, NULL);
+					      cred, KEY_ALLOC_IN_QUOTA, NULL);
 			if (IS_ERR(session_keyring)) {
 				ret = PTR_ERR(session_keyring);
 				goto error_release;
@@ -115,140 +119,128 @@
 	return ret;
 }
 
-/*****************************************************************************/
 /*
- * deal with the UID changing
+ * install a fresh thread keyring directly to new credentials
  */
-void switch_uid_keyring(struct user_struct *new_user)
+int install_thread_keyring_to_cred(struct cred *new)
 {
-#if 0 /* do nothing for now */
-	struct key *old;
+	struct key *keyring;
 
-	/* switch to the new user's session keyring if we were running under
-	 * root's default session keyring */
-	if (new_user->uid != 0 &&
-	    current->session_keyring == &root_session_keyring
-	    ) {
-		atomic_inc(&new_user->session_keyring->usage);
+	keyring = keyring_alloc("_tid", new->uid, new->gid, new,
+				KEY_ALLOC_QUOTA_OVERRUN, NULL);
+	if (IS_ERR(keyring))
+		return PTR_ERR(keyring);
 
-		task_lock(current);
-		old = current->session_keyring;
-		current->session_keyring = new_user->session_keyring;
-		task_unlock(current);
+	new->thread_keyring = keyring;
+	return 0;
+}
 
-		key_put(old);
-	}
-#endif
-
-} /* end switch_uid_keyring() */
-
-/*****************************************************************************/
 /*
  * install a fresh thread keyring, discarding the old one
  */
-int install_thread_keyring(struct task_struct *tsk)
+static int install_thread_keyring(void)
 {
-	struct key *keyring, *old;
-	char buf[20];
+	struct cred *new;
 	int ret;
 
-	sprintf(buf, "_tid.%u", tsk->pid);
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
 
-	keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
-				KEY_ALLOC_QUOTA_OVERRUN, NULL);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
-		goto error;
+	BUG_ON(new->thread_keyring);
+
+	ret = install_thread_keyring_to_cred(new);
+	if (ret < 0) {
+		abort_creds(new);
+		return ret;
 	}
 
-	task_lock(tsk);
-	old = tsk->thread_keyring;
-	tsk->thread_keyring = keyring;
-	task_unlock(tsk);
+	return commit_creds(new);
+}
 
-	ret = 0;
-
-	key_put(old);
-error:
-	return ret;
-
-} /* end install_thread_keyring() */
-
-/*****************************************************************************/
 /*
- * make sure a process keyring is installed
+ * install a process keyring directly to a credentials struct
+ * - returns -EEXIST if there was already a process keyring, 0 if one installed,
+ *   and other -ve on any other error
  */
-int install_process_keyring(struct task_struct *tsk)
+int install_process_keyring_to_cred(struct cred *new)
 {
 	struct key *keyring;
-	char buf[20];
 	int ret;
 
-	might_sleep();
+	if (new->tgcred->process_keyring)
+		return -EEXIST;
 
-	if (!tsk->signal->process_keyring) {
-		sprintf(buf, "_pid.%u", tsk->tgid);
+	keyring = keyring_alloc("_pid", new->uid, new->gid,
+				new, KEY_ALLOC_QUOTA_OVERRUN, NULL);
+	if (IS_ERR(keyring))
+		return PTR_ERR(keyring);
 
-		keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
-					KEY_ALLOC_QUOTA_OVERRUN, NULL);
-		if (IS_ERR(keyring)) {
-			ret = PTR_ERR(keyring);
-			goto error;
-		}
+	spin_lock_irq(&new->tgcred->lock);
+	if (!new->tgcred->process_keyring) {
+		new->tgcred->process_keyring = keyring;
+		keyring = NULL;
+		ret = 0;
+	} else {
+		ret = -EEXIST;
+	}
+	spin_unlock_irq(&new->tgcred->lock);
+	key_put(keyring);
+	return ret;
+}
 
-		/* attach keyring */
-		spin_lock_irq(&tsk->sighand->siglock);
-		if (!tsk->signal->process_keyring) {
-			tsk->signal->process_keyring = keyring;
-			keyring = NULL;
-		}
-		spin_unlock_irq(&tsk->sighand->siglock);
+/*
+ * make sure a process keyring is installed
+ * - we
+ */
+static int install_process_keyring(void)
+{
+	struct cred *new;
+	int ret;
 
-		key_put(keyring);
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+
+	ret = install_process_keyring_to_cred(new);
+	if (ret < 0) {
+		abort_creds(new);
+		return ret != -EEXIST ?: 0;
 	}
 
-	ret = 0;
-error:
-	return ret;
+	return commit_creds(new);
+}
 
-} /* end install_process_keyring() */
-
-/*****************************************************************************/
 /*
- * install a session keyring, discarding the old one
- * - if a keyring is not supplied, an empty one is invented
+ * install a session keyring directly to a credentials struct
  */
-static int install_session_keyring(struct task_struct *tsk,
-				   struct key *keyring)
+static int install_session_keyring_to_cred(struct cred *cred,
+					   struct key *keyring)
 {
 	unsigned long flags;
 	struct key *old;
-	char buf[20];
 
 	might_sleep();
 
 	/* create an empty session keyring */
 	if (!keyring) {
-		sprintf(buf, "_ses.%u", tsk->tgid);
-
 		flags = KEY_ALLOC_QUOTA_OVERRUN;
-		if (tsk->signal->session_keyring)
+		if (cred->tgcred->session_keyring)
 			flags = KEY_ALLOC_IN_QUOTA;
 
-		keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
-					flags, NULL);
+		keyring = keyring_alloc("_ses", cred->uid, cred->gid,
+					cred, flags, NULL);
 		if (IS_ERR(keyring))
 			return PTR_ERR(keyring);
-	}
-	else {
+	} else {
 		atomic_inc(&keyring->usage);
 	}
 
 	/* install the keyring */
-	spin_lock_irq(&tsk->sighand->siglock);
-	old = tsk->signal->session_keyring;
-	rcu_assign_pointer(tsk->signal->session_keyring, keyring);
-	spin_unlock_irq(&tsk->sighand->siglock);
+	spin_lock_irq(&cred->tgcred->lock);
+	old = cred->tgcred->session_keyring;
+	rcu_assign_pointer(cred->tgcred->session_keyring, keyring);
+	spin_unlock_irq(&cred->tgcred->lock);
 
 	/* we're using RCU on the pointer, but there's no point synchronising
 	 * on it if it didn't previously point to anything */
@@ -258,110 +250,29 @@
 	}
 
 	return 0;
+}
 
-} /* end install_session_keyring() */
-
-/*****************************************************************************/
 /*
- * copy the keys in a thread group for fork without CLONE_THREAD
+ * install a session keyring, discarding the old one
+ * - if a keyring is not supplied, an empty one is invented
  */
-int copy_thread_group_keys(struct task_struct *tsk)
+static int install_session_keyring(struct key *keyring)
 {
-	key_check(current->thread_group->session_keyring);
-	key_check(current->thread_group->process_keyring);
+	struct cred *new;
+	int ret;
 
-	/* no process keyring yet */
-	tsk->signal->process_keyring = NULL;
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
 
-	/* same session keyring */
-	rcu_read_lock();
-	tsk->signal->session_keyring =
-		key_get(rcu_dereference(current->signal->session_keyring));
-	rcu_read_unlock();
+	ret = install_session_keyring_to_cred(new, NULL);
+	if (ret < 0) {
+		abort_creds(new);
+		return ret;
+	}
 
-	return 0;
-
-} /* end copy_thread_group_keys() */
-
-/*****************************************************************************/
-/*
- * copy the keys for fork
- */
-int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
-{
-	key_check(tsk->thread_keyring);
-	key_check(tsk->request_key_auth);
-
-	/* no thread keyring yet */
-	tsk->thread_keyring = NULL;
-
-	/* copy the request_key() authorisation for this thread */
-	key_get(tsk->request_key_auth);
-
-	return 0;
-
-} /* end copy_keys() */
-
-/*****************************************************************************/
-/*
- * dispose of thread group keys upon thread group destruction
- */
-void exit_thread_group_keys(struct signal_struct *tg)
-{
-	key_put(tg->session_keyring);
-	key_put(tg->process_keyring);
-
-} /* end exit_thread_group_keys() */
-
-/*****************************************************************************/
-/*
- * dispose of per-thread keys upon thread exit
- */
-void exit_keys(struct task_struct *tsk)
-{
-	key_put(tsk->thread_keyring);
-	key_put(tsk->request_key_auth);
-
-} /* end exit_keys() */
-
-/*****************************************************************************/
-/*
- * deal with execve()
- */
-int exec_keys(struct task_struct *tsk)
-{
-	struct key *old;
-
-	/* newly exec'd tasks don't get a thread keyring */
-	task_lock(tsk);
-	old = tsk->thread_keyring;
-	tsk->thread_keyring = NULL;
-	task_unlock(tsk);
-
-	key_put(old);
-
-	/* discard the process keyring from a newly exec'd task */
-	spin_lock_irq(&tsk->sighand->siglock);
-	old = tsk->signal->process_keyring;
-	tsk->signal->process_keyring = NULL;
-	spin_unlock_irq(&tsk->sighand->siglock);
-
-	key_put(old);
-
-	return 0;
-
-} /* end exec_keys() */
-
-/*****************************************************************************/
-/*
- * deal with SUID programs
- * - we might want to make this invent a new session keyring
- */
-int suid_keys(struct task_struct *tsk)
-{
-	return 0;
-
-} /* end suid_keys() */
+	return commit_creds(new);
+}
 
 /*****************************************************************************/
 /*
@@ -370,10 +281,11 @@
 void key_fsuid_changed(struct task_struct *tsk)
 {
 	/* update the ownership of the thread keyring */
-	if (tsk->thread_keyring) {
-		down_write(&tsk->thread_keyring->sem);
-		tsk->thread_keyring->uid = tsk->fsuid;
-		up_write(&tsk->thread_keyring->sem);
+	BUG_ON(!tsk->cred);
+	if (tsk->cred->thread_keyring) {
+		down_write(&tsk->cred->thread_keyring->sem);
+		tsk->cred->thread_keyring->uid = tsk->cred->fsuid;
+		up_write(&tsk->cred->thread_keyring->sem);
 	}
 
 } /* end key_fsuid_changed() */
@@ -385,10 +297,11 @@
 void key_fsgid_changed(struct task_struct *tsk)
 {
 	/* update the ownership of the thread keyring */
-	if (tsk->thread_keyring) {
-		down_write(&tsk->thread_keyring->sem);
-		tsk->thread_keyring->gid = tsk->fsgid;
-		up_write(&tsk->thread_keyring->sem);
+	BUG_ON(!tsk->cred);
+	if (tsk->cred->thread_keyring) {
+		down_write(&tsk->cred->thread_keyring->sem);
+		tsk->cred->thread_keyring->gid = tsk->cred->fsgid;
+		up_write(&tsk->cred->thread_keyring->sem);
 	}
 
 } /* end key_fsgid_changed() */
@@ -404,7 +317,7 @@
 key_ref_t search_process_keyrings(struct key_type *type,
 				  const void *description,
 				  key_match_func_t match,
-				  struct task_struct *context)
+				  const struct cred *cred)
 {
 	struct request_key_auth *rka;
 	key_ref_t key_ref, ret, err;
@@ -423,10 +336,10 @@
 	err = ERR_PTR(-EAGAIN);
 
 	/* search the thread keyring first */
-	if (context->thread_keyring) {
+	if (cred->thread_keyring) {
 		key_ref = keyring_search_aux(
-			make_key_ref(context->thread_keyring, 1),
-			context, type, description, match);
+			make_key_ref(cred->thread_keyring, 1),
+			cred, type, description, match);
 		if (!IS_ERR(key_ref))
 			goto found;
 
@@ -444,10 +357,10 @@
 	}
 
 	/* search the process keyring second */
-	if (context->signal->process_keyring) {
+	if (cred->tgcred->process_keyring) {
 		key_ref = keyring_search_aux(
-			make_key_ref(context->signal->process_keyring, 1),
-			context, type, description, match);
+			make_key_ref(cred->tgcred->process_keyring, 1),
+			cred, type, description, match);
 		if (!IS_ERR(key_ref))
 			goto found;
 
@@ -465,13 +378,13 @@
 	}
 
 	/* search the session keyring */
-	if (context->signal->session_keyring) {
+	if (cred->tgcred->session_keyring) {
 		rcu_read_lock();
 		key_ref = keyring_search_aux(
 			make_key_ref(rcu_dereference(
-					     context->signal->session_keyring),
+					     cred->tgcred->session_keyring),
 				     1),
-			context, type, description, match);
+			cred, type, description, match);
 		rcu_read_unlock();
 
 		if (!IS_ERR(key_ref))
@@ -490,10 +403,10 @@
 		}
 	}
 	/* or search the user-session keyring */
-	else if (context->user->session_keyring) {
+	else if (cred->user->session_keyring) {
 		key_ref = keyring_search_aux(
-			make_key_ref(context->user->session_keyring, 1),
-			context, type, description, match);
+			make_key_ref(cred->user->session_keyring, 1),
+			cred, type, description, match);
 		if (!IS_ERR(key_ref))
 			goto found;
 
@@ -514,20 +427,20 @@
 	 * search the keyrings of the process mentioned there
 	 * - we don't permit access to request_key auth keys via this method
 	 */
-	if (context->request_key_auth &&
-	    context == current &&
+	if (cred->request_key_auth &&
+	    cred == current_cred() &&
 	    type != &key_type_request_key_auth
 	    ) {
 		/* defend against the auth key being revoked */
-		down_read(&context->request_key_auth->sem);
+		down_read(&cred->request_key_auth->sem);
 
-		if (key_validate(context->request_key_auth) == 0) {
-			rka = context->request_key_auth->payload.data;
+		if (key_validate(cred->request_key_auth) == 0) {
+			rka = cred->request_key_auth->payload.data;
 
 			key_ref = search_process_keyrings(type, description,
-							  match, rka->context);
+							  match, rka->cred);
 
-			up_read(&context->request_key_auth->sem);
+			up_read(&cred->request_key_auth->sem);
 
 			if (!IS_ERR(key_ref))
 				goto found;
@@ -544,7 +457,7 @@
 				break;
 			}
 		} else {
-			up_read(&context->request_key_auth->sem);
+			up_read(&cred->request_key_auth->sem);
 		}
 	}
 
@@ -572,93 +485,98 @@
  * - don't create special keyrings unless so requested
  * - partially constructed keys aren't found unless requested
  */
-key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
-			  int create, int partial, key_perm_t perm)
+key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
+			  key_perm_t perm)
 {
-	key_ref_t key_ref, skey_ref;
+	struct request_key_auth *rka;
+	const struct cred *cred;
 	struct key *key;
+	key_ref_t key_ref, skey_ref;
 	int ret;
 
-	if (!context)
-		context = current;
-
+try_again:
+	cred = get_current_cred();
 	key_ref = ERR_PTR(-ENOKEY);
 
 	switch (id) {
 	case KEY_SPEC_THREAD_KEYRING:
-		if (!context->thread_keyring) {
+		if (!cred->thread_keyring) {
 			if (!create)
 				goto error;
 
-			ret = install_thread_keyring(context);
+			ret = install_thread_keyring();
 			if (ret < 0) {
 				key = ERR_PTR(ret);
 				goto error;
 			}
+			goto reget_creds;
 		}
 
-		key = context->thread_keyring;
+		key = cred->thread_keyring;
 		atomic_inc(&key->usage);
 		key_ref = make_key_ref(key, 1);
 		break;
 
 	case KEY_SPEC_PROCESS_KEYRING:
-		if (!context->signal->process_keyring) {
+		if (!cred->tgcred->process_keyring) {
 			if (!create)
 				goto error;
 
-			ret = install_process_keyring(context);
+			ret = install_process_keyring();
 			if (ret < 0) {
 				key = ERR_PTR(ret);
 				goto error;
 			}
+			goto reget_creds;
 		}
 
-		key = context->signal->process_keyring;
+		key = cred->tgcred->process_keyring;
 		atomic_inc(&key->usage);
 		key_ref = make_key_ref(key, 1);
 		break;
 
 	case KEY_SPEC_SESSION_KEYRING:
-		if (!context->signal->session_keyring) {
+		if (!cred->tgcred->session_keyring) {
 			/* always install a session keyring upon access if one
 			 * doesn't exist yet */
-			ret = install_user_keyrings(context);
+			ret = install_user_keyrings();
 			if (ret < 0)
 				goto error;
 			ret = install_session_keyring(
-				context, context->user->session_keyring);
+				cred->user->session_keyring);
+
 			if (ret < 0)
 				goto error;
+			goto reget_creds;
 		}
 
 		rcu_read_lock();
-		key = rcu_dereference(context->signal->session_keyring);
+		key = rcu_dereference(cred->tgcred->session_keyring);
 		atomic_inc(&key->usage);
 		rcu_read_unlock();
 		key_ref = make_key_ref(key, 1);
 		break;
 
 	case KEY_SPEC_USER_KEYRING:
-		if (!context->user->uid_keyring) {
-			ret = install_user_keyrings(context);
+		if (!cred->user->uid_keyring) {
+			ret = install_user_keyrings();
 			if (ret < 0)
 				goto error;
 		}
 
-		key = context->user->uid_keyring;
+		key = cred->user->uid_keyring;
 		atomic_inc(&key->usage);
 		key_ref = make_key_ref(key, 1);
 		break;
 
 	case KEY_SPEC_USER_SESSION_KEYRING:
-		if (!context->user->session_keyring) {
-			ret = install_user_keyrings(context);
+		if (!cred->user->session_keyring) {
+			ret = install_user_keyrings();
 			if (ret < 0)
 				goto error;
 		}
 
-		key = context->user->session_keyring;
+		key = cred->user->session_keyring;
 		atomic_inc(&key->usage);
 		key_ref = make_key_ref(key, 1);
 		break;
@@ -669,7 +587,7 @@
 		goto error;
 
 	case KEY_SPEC_REQKEY_AUTH_KEY:
-		key = context->request_key_auth;
+		key = cred->request_key_auth;
 		if (!key)
 			goto error;
 
@@ -677,6 +595,25 @@
 		key_ref = make_key_ref(key, 1);
 		break;
 
+	case KEY_SPEC_REQUESTOR_KEYRING:
+		if (!cred->request_key_auth)
+			goto error;
+
+		down_read(&cred->request_key_auth->sem);
+		if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) {
+			key_ref = ERR_PTR(-EKEYREVOKED);
+			key = NULL;
+		} else {
+			rka = cred->request_key_auth->payload.data;
+			key = rka->dest_keyring;
+			atomic_inc(&key->usage);
+		}
+		up_read(&cred->request_key_auth->sem);
+		if (!key)
+			goto error;
+		key_ref = make_key_ref(key, 1);
+		break;
+
 	default:
 		key_ref = ERR_PTR(-EINVAL);
 		if (id < 1)
@@ -693,7 +630,7 @@
 		/* check to see if we possess the key */
 		skey_ref = search_process_keyrings(key->type, key,
 						   lookup_user_key_possessed,
-						   current);
+						   cred);
 
 		if (!IS_ERR(skey_ref)) {
 			key_put(key);
@@ -725,11 +662,12 @@
 		goto invalid_key;
 
 	/* check the permissions */
-	ret = key_task_permission(key_ref, context, perm);
+	ret = key_task_permission(key_ref, cred, perm);
 	if (ret < 0)
 		goto invalid_key;
 
 error:
+	put_cred(cred);
 	return key_ref;
 
 invalid_key:
@@ -737,6 +675,12 @@
 	key_ref = ERR_PTR(ret);
 	goto error;
 
+	/* if we attempted to install a keyring, then it may have caused new
+	 * creds to be installed */
+reget_creds:
+	put_cred(cred);
+	goto try_again;
+
 } /* end lookup_user_key() */
 
 /*****************************************************************************/
@@ -748,20 +692,33 @@
  */
 long join_session_keyring(const char *name)
 {
-	struct task_struct *tsk = current;
+	const struct cred *old;
+	struct cred *new;
 	struct key *keyring;
-	long ret;
+	long ret, serial;
+
+	/* only permit this if there's a single thread in the thread group -
+	 * this avoids us having to adjust the creds on all threads and risking
+	 * ENOMEM */
+	if (!is_single_threaded(current))
+		return -EMLINK;
+
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+	old = current_cred();
 
 	/* if no name is provided, install an anonymous keyring */
 	if (!name) {
-		ret = install_session_keyring(tsk, NULL);
+		ret = install_session_keyring_to_cred(new, NULL);
 		if (ret < 0)
 			goto error;
 
-		rcu_read_lock();
-		ret = rcu_dereference(tsk->signal->session_keyring)->serial;
-		rcu_read_unlock();
-		goto error;
+		serial = new->tgcred->session_keyring->serial;
+		ret = commit_creds(new);
+		if (ret == 0)
+			ret = serial;
+		goto okay;
 	}
 
 	/* allow the user to join or create a named keyring */
@@ -771,29 +728,33 @@
 	keyring = find_keyring_by_name(name, false);
 	if (PTR_ERR(keyring) == -ENOKEY) {
 		/* not found - try and create a new one */
-		keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk,
+		keyring = keyring_alloc(name, old->uid, old->gid, old,
 					KEY_ALLOC_IN_QUOTA, NULL);
 		if (IS_ERR(keyring)) {
 			ret = PTR_ERR(keyring);
 			goto error2;
 		}
-	}
-	else if (IS_ERR(keyring)) {
+	} else if (IS_ERR(keyring)) {
 		ret = PTR_ERR(keyring);
 		goto error2;
 	}
 
 	/* we've got a keyring - now to install it */
-	ret = install_session_keyring(tsk, keyring);
+	ret = install_session_keyring_to_cred(new, keyring);
 	if (ret < 0)
 		goto error2;
 
+	commit_creds(new);
+	mutex_unlock(&key_session_mutex);
+
 	ret = keyring->serial;
 	key_put(keyring);
+okay:
+	return ret;
 
 error2:
 	mutex_unlock(&key_session_mutex);
 error:
+	abort_creds(new);
 	return ret;
-
-} /* end join_session_keyring() */
+}
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index abea08f..0e04f72 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -19,6 +19,8 @@
 #include <linux/slab.h>
 #include "internal.h"
 
+#define key_negative_timeout	60	/* default timeout on a negative key's existence */
+
 /*
  * wait_on_bit() sleep function for uninterruptible waiting
  */
@@ -64,7 +66,7 @@
 				 const char *op,
 				 void *aux)
 {
-	struct task_struct *tsk = current;
+	const struct cred *cred = current_cred();
 	key_serial_t prkey, sskey;
 	struct key *key = cons->key, *authkey = cons->authkey, *keyring;
 	char *argv[9], *envp[3], uid_str[12], gid_str[12];
@@ -74,15 +76,17 @@
 
 	kenter("{%d},{%d},%s", key->serial, authkey->serial, op);
 
-	ret = install_user_keyrings(tsk);
+	ret = install_user_keyrings();
 	if (ret < 0)
 		goto error_alloc;
 
 	/* allocate a new session keyring */
 	sprintf(desc, "_req.%u", key->serial);
 
-	keyring = keyring_alloc(desc, current->fsuid, current->fsgid, current,
+	cred = get_current_cred();
+	keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred,
 				KEY_ALLOC_QUOTA_OVERRUN, NULL);
+	put_cred(cred);
 	if (IS_ERR(keyring)) {
 		ret = PTR_ERR(keyring);
 		goto error_alloc;
@@ -94,29 +98,24 @@
 		goto error_link;
 
 	/* record the UID and GID */
-	sprintf(uid_str, "%d", current->fsuid);
-	sprintf(gid_str, "%d", current->fsgid);
+	sprintf(uid_str, "%d", cred->fsuid);
+	sprintf(gid_str, "%d", cred->fsgid);
 
 	/* we say which key is under construction */
 	sprintf(key_str, "%d", key->serial);
 
 	/* we specify the process's default keyrings */
 	sprintf(keyring_str[0], "%d",
-		tsk->thread_keyring ? tsk->thread_keyring->serial : 0);
+		cred->thread_keyring ? cred->thread_keyring->serial : 0);
 
 	prkey = 0;
-	if (tsk->signal->process_keyring)
-		prkey = tsk->signal->process_keyring->serial;
+	if (cred->tgcred->process_keyring)
+		prkey = cred->tgcred->process_keyring->serial;
 
-	sprintf(keyring_str[1], "%d", prkey);
-
-	if (tsk->signal->session_keyring) {
-		rcu_read_lock();
-		sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
-		rcu_read_unlock();
-	} else {
-		sskey = tsk->user->session_keyring->serial;
-	}
+	if (cred->tgcred->session_keyring)
+		sskey = rcu_dereference(cred->tgcred->session_keyring)->serial;
+	else
+		sskey = cred->user->session_keyring->serial;
 
 	sprintf(keyring_str[2], "%d", sskey);
 
@@ -157,8 +156,8 @@
 	key_put(keyring);
 
 error_alloc:
-	kleave(" = %d", ret);
 	complete_request_key(cons, ret);
+	kleave(" = %d", ret);
 	return ret;
 }
 
@@ -167,7 +166,8 @@
  * - we ignore program failure and go on key status instead
  */
 static int construct_key(struct key *key, const void *callout_info,
-			 size_t callout_len, void *aux)
+			 size_t callout_len, void *aux,
+			 struct key *dest_keyring)
 {
 	struct key_construction *cons;
 	request_key_actor_t actor;
@@ -181,7 +181,8 @@
 		return -ENOMEM;
 
 	/* allocate an authorisation key */
-	authkey = request_key_auth_new(key, callout_info, callout_len);
+	authkey = request_key_auth_new(key, callout_info, callout_len,
+				       dest_keyring);
 	if (IS_ERR(authkey)) {
 		kfree(cons);
 		ret = PTR_ERR(authkey);
@@ -209,46 +210,67 @@
 }
 
 /*
- * link a key to the appropriate destination keyring
- * - the caller must hold a write lock on the destination keyring
+ * get the appropriate destination keyring for the request
+ * - we return whatever keyring we select with an extra reference upon it which
+ *   the caller must release
  */
-static void construct_key_make_link(struct key *key, struct key *dest_keyring)
+static void construct_get_dest_keyring(struct key **_dest_keyring)
 {
-	struct task_struct *tsk = current;
-	struct key *drop = NULL;
+	struct request_key_auth *rka;
+	const struct cred *cred = current_cred();
+	struct key *dest_keyring = *_dest_keyring, *authkey;
 
-	kenter("{%d},%p", key->serial, dest_keyring);
+	kenter("%p", dest_keyring);
 
 	/* find the appropriate keyring */
-	if (!dest_keyring) {
-		switch (tsk->jit_keyring) {
+	if (dest_keyring) {
+		/* the caller supplied one */
+		key_get(dest_keyring);
+	} else {
+		/* use a default keyring; falling through the cases until we
+		 * find one that we actually have */
+		switch (cred->jit_keyring) {
 		case KEY_REQKEY_DEFL_DEFAULT:
+		case KEY_REQKEY_DEFL_REQUESTOR_KEYRING:
+			if (cred->request_key_auth) {
+				authkey = cred->request_key_auth;
+				down_read(&authkey->sem);
+				rka = authkey->payload.data;
+				if (!test_bit(KEY_FLAG_REVOKED,
+					      &authkey->flags))
+					dest_keyring =
+						key_get(rka->dest_keyring);
+				up_read(&authkey->sem);
+				if (dest_keyring)
+					break;
+			}
+
 		case KEY_REQKEY_DEFL_THREAD_KEYRING:
-			dest_keyring = tsk->thread_keyring;
+			dest_keyring = key_get(cred->thread_keyring);
 			if (dest_keyring)
 				break;
 
 		case KEY_REQKEY_DEFL_PROCESS_KEYRING:
-			dest_keyring = tsk->signal->process_keyring;
+			dest_keyring = key_get(cred->tgcred->process_keyring);
 			if (dest_keyring)
 				break;
 
 		case KEY_REQKEY_DEFL_SESSION_KEYRING:
 			rcu_read_lock();
 			dest_keyring = key_get(
-				rcu_dereference(tsk->signal->session_keyring));
+				rcu_dereference(cred->tgcred->session_keyring));
 			rcu_read_unlock();
-			drop = dest_keyring;
 
 			if (dest_keyring)
 				break;
 
 		case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
-			dest_keyring = tsk->user->session_keyring;
+			dest_keyring =
+				key_get(cred->user->session_keyring);
 			break;
 
 		case KEY_REQKEY_DEFL_USER_KEYRING:
-			dest_keyring = tsk->user->uid_keyring;
+			dest_keyring = key_get(cred->user->uid_keyring);
 			break;
 
 		case KEY_REQKEY_DEFL_GROUP_KEYRING:
@@ -257,10 +279,9 @@
 		}
 	}
 
-	/* and attach the key to it */
-	__key_link(dest_keyring, key);
-	key_put(drop);
-	kleave("");
+	*_dest_keyring = dest_keyring;
+	kleave(" [dk %d]", key_serial(dest_keyring));
+	return;
 }
 
 /*
@@ -275,6 +296,7 @@
 			       struct key_user *user,
 			       struct key **_key)
 {
+	const struct cred *cred = current_cred();
 	struct key *key;
 	key_ref_t key_ref;
 
@@ -282,33 +304,28 @@
 
 	mutex_lock(&user->cons_lock);
 
-	key = key_alloc(type, description,
-			current->fsuid, current->fsgid, current, KEY_POS_ALL,
-			flags);
+	key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred,
+			KEY_POS_ALL, flags);
 	if (IS_ERR(key))
 		goto alloc_failed;
 
 	set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
 
-	if (dest_keyring)
-		down_write(&dest_keyring->sem);
+	down_write(&dest_keyring->sem);
 
 	/* attach the key to the destination keyring under lock, but we do need
 	 * to do another check just in case someone beat us to it whilst we
 	 * waited for locks */
 	mutex_lock(&key_construction_mutex);
 
-	key_ref = search_process_keyrings(type, description, type->match,
-					  current);
+	key_ref = search_process_keyrings(type, description, type->match, cred);
 	if (!IS_ERR(key_ref))
 		goto key_already_present;
 
-	if (dest_keyring)
-		construct_key_make_link(key, dest_keyring);
+	__key_link(dest_keyring, key);
 
 	mutex_unlock(&key_construction_mutex);
-	if (dest_keyring)
-		up_write(&dest_keyring->sem);
+	up_write(&dest_keyring->sem);
 	mutex_unlock(&user->cons_lock);
 	*_key = key;
 	kleave(" = 0 [%d]", key_serial(key));
@@ -346,25 +363,36 @@
 	struct key *key;
 	int ret;
 
-	user = key_user_lookup(current->fsuid);
+	kenter("");
+
+	user = key_user_lookup(current_fsuid());
 	if (!user)
 		return ERR_PTR(-ENOMEM);
 
+	construct_get_dest_keyring(&dest_keyring);
+
 	ret = construct_alloc_key(type, description, dest_keyring, flags, user,
 				  &key);
 	key_user_put(user);
 
 	if (ret == 0) {
-		ret = construct_key(key, callout_info, callout_len, aux);
-		if (ret < 0)
+		ret = construct_key(key, callout_info, callout_len, aux,
+				    dest_keyring);
+		if (ret < 0) {
+			kdebug("cons failed");
 			goto construction_failed;
+		}
 	}
 
+	key_put(dest_keyring);
+	kleave(" = key %d", key_serial(key));
 	return key;
 
 construction_failed:
 	key_negate_and_link(key, key_negative_timeout, NULL, NULL);
 	key_put(key);
+	key_put(dest_keyring);
+	kleave(" = %d", ret);
 	return ERR_PTR(ret);
 }
 
@@ -383,6 +411,7 @@
 				 struct key *dest_keyring,
 				 unsigned long flags)
 {
+	const struct cred *cred = current_cred();
 	struct key *key;
 	key_ref_t key_ref;
 
@@ -392,7 +421,7 @@
 
 	/* search all the process keyrings for a key */
 	key_ref = search_process_keyrings(type, description, type->match,
-					  current);
+					  cred);
 
 	if (!IS_ERR(key_ref)) {
 		key = key_ref_to_ptr(key_ref);
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index bd237b0..8674715 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -105,9 +105,9 @@
 
 	kenter("{%d}", key->serial);
 
-	if (rka->context) {
-		put_task_struct(rka->context);
-		rka->context = NULL;
+	if (rka->cred) {
+		put_cred(rka->cred);
+		rka->cred = NULL;
 	}
 
 } /* end request_key_auth_revoke() */
@@ -122,12 +122,13 @@
 
 	kenter("{%d}", key->serial);
 
-	if (rka->context) {
-		put_task_struct(rka->context);
-		rka->context = NULL;
+	if (rka->cred) {
+		put_cred(rka->cred);
+		rka->cred = NULL;
 	}
 
 	key_put(rka->target_key);
+	key_put(rka->dest_keyring);
 	kfree(rka->callout_info);
 	kfree(rka);
 
@@ -139,9 +140,10 @@
  * access to the caller's security data
  */
 struct key *request_key_auth_new(struct key *target, const void *callout_info,
-				 size_t callout_len)
+				 size_t callout_len, struct key *dest_keyring)
 {
 	struct request_key_auth *rka, *irka;
+	const struct cred *cred = current->cred;
 	struct key *authkey = NULL;
 	char desc[20];
 	int ret;
@@ -163,31 +165,29 @@
 
 	/* see if the calling process is already servicing the key request of
 	 * another process */
-	if (current->request_key_auth) {
+	if (cred->request_key_auth) {
 		/* it is - use that instantiation context here too */
-		down_read(&current->request_key_auth->sem);
+		down_read(&cred->request_key_auth->sem);
 
 		/* if the auth key has been revoked, then the key we're
 		 * servicing is already instantiated */
-		if (test_bit(KEY_FLAG_REVOKED,
-			     &current->request_key_auth->flags))
+		if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags))
 			goto auth_key_revoked;
 
-		irka = current->request_key_auth->payload.data;
-		rka->context = irka->context;
+		irka = cred->request_key_auth->payload.data;
+		rka->cred = get_cred(irka->cred);
 		rka->pid = irka->pid;
-		get_task_struct(rka->context);
 
-		up_read(&current->request_key_auth->sem);
+		up_read(&cred->request_key_auth->sem);
 	}
 	else {
 		/* it isn't - use this process as the context */
-		rka->context = current;
+		rka->cred = get_cred(cred);
 		rka->pid = current->pid;
-		get_task_struct(rka->context);
 	}
 
 	rka->target_key = key_get(target);
+	rka->dest_keyring = key_get(dest_keyring);
 	memcpy(rka->callout_info, callout_info, callout_len);
 	rka->callout_len = callout_len;
 
@@ -195,7 +195,7 @@
 	sprintf(desc, "%x", target->serial);
 
 	authkey = key_alloc(&key_type_request_key_auth, desc,
-			    current->fsuid, current->fsgid, current,
+			    cred->fsuid, cred->fsgid, cred,
 			    KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
 			    KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
 	if (IS_ERR(authkey)) {
@@ -203,16 +203,16 @@
 		goto error_alloc;
 	}
 
-	/* construct and attach to the keyring */
+	/* construct the auth key */
 	ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL);
 	if (ret < 0)
 		goto error_inst;
 
-	kleave(" = {%d}", authkey->serial);
+	kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage));
 	return authkey;
 
 auth_key_revoked:
-	up_read(&current->request_key_auth->sem);
+	up_read(&cred->request_key_auth->sem);
 	kfree(rka->callout_info);
 	kfree(rka);
 	kleave("= -EKEYREVOKED");
@@ -223,6 +223,7 @@
 	key_put(authkey);
 error_alloc:
 	key_put(rka->target_key);
+	key_put(rka->dest_keyring);
 	kfree(rka->callout_info);
 	kfree(rka);
 	kleave("= %d", ret);
@@ -254,6 +255,7 @@
  */
 struct key *key_get_instantiation_authkey(key_serial_t target_id)
 {
+	const struct cred *cred = current_cred();
 	struct key *authkey;
 	key_ref_t authkey_ref;
 
@@ -261,7 +263,7 @@
 		&key_type_request_key_auth,
 		(void *) (unsigned long) target_id,
 		key_get_instantiation_authkey_match,
-		current);
+		cred);
 
 	if (IS_ERR(authkey_ref)) {
 		authkey = ERR_CAST(authkey_ref);
diff --git a/security/root_plug.c b/security/root_plug.c
index c3f68b5..40fb4f1 100644
--- a/security/root_plug.c
+++ b/security/root_plug.c
@@ -55,9 +55,9 @@
 	struct usb_device *dev;
 
 	root_dbg("file %s, e_uid = %d, e_gid = %d\n",
-		 bprm->filename, bprm->e_uid, bprm->e_gid);
+		 bprm->filename, bprm->cred->euid, bprm->cred->egid);
 
-	if (bprm->e_gid == 0) {
+	if (bprm->cred->egid == 0) {
 		dev = usb_find_device(vendor_id, product_id);
 		if (!dev) {
 			root_dbg("e_gid = 0, and device not found, "
@@ -75,15 +75,12 @@
 	.ptrace_may_access =		cap_ptrace_may_access,
 	.ptrace_traceme =		cap_ptrace_traceme,
 	.capget =			cap_capget,
-	.capset_check =			cap_capset_check,
-	.capset_set =			cap_capset_set,
+	.capset =			cap_capset,
 	.capable =			cap_capable,
 
-	.bprm_apply_creds =		cap_bprm_apply_creds,
-	.bprm_set_security =		cap_bprm_set_security,
+	.bprm_set_creds =		cap_bprm_set_creds,
 
-	.task_post_setuid =		cap_task_post_setuid,
-	.task_reparent_to_init =	cap_task_reparent_to_init,
+	.task_fix_setuid =		cap_task_fix_setuid,
 	.task_prctl =			cap_task_prctl,
 
 	.bprm_check_security =		rootplug_bprm_check_security,
diff --git a/security/security.c b/security/security.c
index c0acfa7..d85dbb3 100644
--- a/security/security.c
+++ b/security/security.c
@@ -145,25 +145,23 @@
 	return security_ops->capget(target, effective, inheritable, permitted);
 }
 
-int security_capset_check(struct task_struct *target,
-			   kernel_cap_t *effective,
-			   kernel_cap_t *inheritable,
-			   kernel_cap_t *permitted)
+int security_capset(struct cred *new, const struct cred *old,
+		    const kernel_cap_t *effective,
+		    const kernel_cap_t *inheritable,
+		    const kernel_cap_t *permitted)
 {
-	return security_ops->capset_check(target, effective, inheritable, permitted);
-}
-
-void security_capset_set(struct task_struct *target,
-			  kernel_cap_t *effective,
-			  kernel_cap_t *inheritable,
-			  kernel_cap_t *permitted)
-{
-	security_ops->capset_set(target, effective, inheritable, permitted);
+	return security_ops->capset(new, old,
+				    effective, inheritable, permitted);
 }
 
 int security_capable(struct task_struct *tsk, int cap)
 {
-	return security_ops->capable(tsk, cap);
+	return security_ops->capable(tsk, cap, SECURITY_CAP_AUDIT);
+}
+
+int security_capable_noaudit(struct task_struct *tsk, int cap)
+{
+	return security_ops->capable(tsk, cap, SECURITY_CAP_NOAUDIT);
 }
 
 int security_acct(struct file *file)
@@ -215,29 +213,9 @@
 	return security_ops->vm_enough_memory(current->mm, pages);
 }
 
-int security_bprm_alloc(struct linux_binprm *bprm)
+int security_bprm_set_creds(struct linux_binprm *bprm)
 {
-	return security_ops->bprm_alloc_security(bprm);
-}
-
-void security_bprm_free(struct linux_binprm *bprm)
-{
-	security_ops->bprm_free_security(bprm);
-}
-
-void security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
-{
-	security_ops->bprm_apply_creds(bprm, unsafe);
-}
-
-void security_bprm_post_apply_creds(struct linux_binprm *bprm)
-{
-	security_ops->bprm_post_apply_creds(bprm);
-}
-
-int security_bprm_set(struct linux_binprm *bprm)
-{
-	return security_ops->bprm_set_security(bprm);
+	return security_ops->bprm_set_creds(bprm);
 }
 
 int security_bprm_check(struct linux_binprm *bprm)
@@ -245,6 +223,16 @@
 	return security_ops->bprm_check_security(bprm);
 }
 
+void security_bprm_committing_creds(struct linux_binprm *bprm)
+{
+	security_ops->bprm_committing_creds(bprm);
+}
+
+void security_bprm_committed_creds(struct linux_binprm *bprm)
+{
+	security_ops->bprm_committed_creds(bprm);
+}
+
 int security_bprm_secureexec(struct linux_binprm *bprm)
 {
 	return security_ops->bprm_secureexec(bprm);
@@ -266,9 +254,9 @@
 }
 EXPORT_SYMBOL(security_sb_copy_data);
 
-int security_sb_kern_mount(struct super_block *sb, void *data)
+int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
 {
-	return security_ops->sb_kern_mount(sb, data);
+	return security_ops->sb_kern_mount(sb, flags, data);
 }
 
 int security_sb_show_options(struct seq_file *m, struct super_block *sb)
@@ -603,9 +591,9 @@
 	return security_ops->file_receive(file);
 }
 
-int security_dentry_open(struct file *file)
+int security_dentry_open(struct file *file, const struct cred *cred)
 {
-	return security_ops->dentry_open(file);
+	return security_ops->dentry_open(file, cred);
 }
 
 int security_task_create(unsigned long clone_flags)
@@ -613,14 +601,29 @@
 	return security_ops->task_create(clone_flags);
 }
 
-int security_task_alloc(struct task_struct *p)
+void security_cred_free(struct cred *cred)
 {
-	return security_ops->task_alloc_security(p);
+	security_ops->cred_free(cred);
 }
 
-void security_task_free(struct task_struct *p)
+int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
 {
-	security_ops->task_free_security(p);
+	return security_ops->cred_prepare(new, old, gfp);
+}
+
+void security_commit_creds(struct cred *new, const struct cred *old)
+{
+	security_ops->cred_commit(new, old);
+}
+
+int security_kernel_act_as(struct cred *new, u32 secid)
+{
+	return security_ops->kernel_act_as(new, secid);
+}
+
+int security_kernel_create_files_as(struct cred *new, struct inode *inode)
+{
+	return security_ops->kernel_create_files_as(new, inode);
 }
 
 int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
@@ -628,10 +631,10 @@
 	return security_ops->task_setuid(id0, id1, id2, flags);
 }
 
-int security_task_post_setuid(uid_t old_ruid, uid_t old_euid,
-			       uid_t old_suid, int flags)
+int security_task_fix_setuid(struct cred *new, const struct cred *old,
+			     int flags)
 {
-	return security_ops->task_post_setuid(old_ruid, old_euid, old_suid, flags);
+	return security_ops->task_fix_setuid(new, old, flags);
 }
 
 int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
@@ -713,14 +716,9 @@
 }
 
 int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
-			 unsigned long arg4, unsigned long arg5, long *rc_p)
+			 unsigned long arg4, unsigned long arg5)
 {
-	return security_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
-}
-
-void security_task_reparent_to_init(struct task_struct *p)
-{
-	security_ops->task_reparent_to_init(p);
+	return security_ops->task_prctl(option, arg2, arg3, arg4, arg5);
 }
 
 void security_task_to_inode(struct task_struct *p, struct inode *inode)
@@ -1120,9 +1118,10 @@
 
 #ifdef CONFIG_KEYS
 
-int security_key_alloc(struct key *key, struct task_struct *tsk, unsigned long flags)
+int security_key_alloc(struct key *key, const struct cred *cred,
+		       unsigned long flags)
 {
-	return security_ops->key_alloc(key, tsk, flags);
+	return security_ops->key_alloc(key, cred, flags);
 }
 
 void security_key_free(struct key *key)
@@ -1131,9 +1130,9 @@
 }
 
 int security_key_permission(key_ref_t key_ref,
-			    struct task_struct *context, key_perm_t perm)
+			    const struct cred *cred, key_perm_t perm)
 {
-	return security_ops->key_permission(key_ref, context, perm);
+	return security_ops->key_permission(key_ref, cred, perm);
 }
 
 int security_key_getsecurity(struct key *key, char **_buffer)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index cb30c7e..d43bd6b 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -495,7 +495,7 @@
 				       char *name1, char *name2)
 {
 	if (!ipv6_addr_any(addr))
-		audit_log_format(ab, " %s=" NIP6_FMT, name1, NIP6(*addr));
+		audit_log_format(ab, " %s=%pI6", name1, addr);
 	if (port)
 		audit_log_format(ab, " %s=%d", name2, ntohs(port));
 }
@@ -504,7 +504,7 @@
 				       __be16 port, char *name1, char *name2)
 {
 	if (addr)
-		audit_log_format(ab, " %s=" NIPQUAD_FMT, name1, NIPQUAD(addr));
+		audit_log_format(ab, " %s=%pI4", name1, &addr);
 	if (port)
 		audit_log_format(ab, " %s=%d", name2, ntohs(port));
 }
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
index 64af2d3..c73aeaa 100644
--- a/security/selinux/exports.c
+++ b/security/selinux/exports.c
@@ -39,9 +39,13 @@
 int selinux_secmark_relabel_packet_permission(u32 sid)
 {
 	if (selinux_enabled) {
-		struct task_security_struct *tsec = current->security;
+		const struct task_security_struct *__tsec;
+		u32 tsid;
 
-		return avc_has_perm(tsec->sid, sid, SECCLASS_PACKET,
+		__tsec = current_security();
+		tsid = __tsec->sid;
+
+		return avc_has_perm(tsid, sid, SECCLASS_PACKET,
 				    PACKET__RELABELTO, NULL);
 	}
 	return 0;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f85597a..dbeaa78 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -156,33 +156,62 @@
 	return (atomic_read(&selinux_secmark_refcount) > 0);
 }
 
-/* Allocate and free functions for each kind of security blob. */
-
-static int task_alloc_security(struct task_struct *task)
+/*
+ * initialise the security for the init task
+ */
+static void cred_init_security(void)
 {
+	struct cred *cred = (struct cred *) current->real_cred;
 	struct task_security_struct *tsec;
 
 	tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
 	if (!tsec)
-		return -ENOMEM;
+		panic("SELinux:  Failed to initialize initial task.\n");
 
-	tsec->osid = tsec->sid = SECINITSID_UNLABELED;
-	task->security = tsec;
-
-	return 0;
+	tsec->osid = tsec->sid = SECINITSID_KERNEL;
+	cred->security = tsec;
 }
 
-static void task_free_security(struct task_struct *task)
+/*
+ * get the security ID of a set of credentials
+ */
+static inline u32 cred_sid(const struct cred *cred)
 {
-	struct task_security_struct *tsec = task->security;
-	task->security = NULL;
-	kfree(tsec);
+	const struct task_security_struct *tsec;
+
+	tsec = cred->security;
+	return tsec->sid;
 }
 
+/*
+ * get the objective security ID of a task
+ */
+static inline u32 task_sid(const struct task_struct *task)
+{
+	u32 sid;
+
+	rcu_read_lock();
+	sid = cred_sid(__task_cred(task));
+	rcu_read_unlock();
+	return sid;
+}
+
+/*
+ * get the subjective security ID of the current task
+ */
+static inline u32 current_sid(void)
+{
+	const struct task_security_struct *tsec = current_cred()->security;
+
+	return tsec->sid;
+}
+
+/* Allocate and free functions for each kind of security blob. */
+
 static int inode_alloc_security(struct inode *inode)
 {
-	struct task_security_struct *tsec = current->security;
 	struct inode_security_struct *isec;
+	u32 sid = current_sid();
 
 	isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
 	if (!isec)
@@ -193,7 +222,7 @@
 	isec->inode = inode;
 	isec->sid = SECINITSID_UNLABELED;
 	isec->sclass = SECCLASS_FILE;
-	isec->task_sid = tsec->sid;
+	isec->task_sid = sid;
 	inode->i_security = isec;
 
 	return 0;
@@ -215,15 +244,15 @@
 
 static int file_alloc_security(struct file *file)
 {
-	struct task_security_struct *tsec = current->security;
 	struct file_security_struct *fsec;
+	u32 sid = current_sid();
 
 	fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
 	if (!fsec)
 		return -ENOMEM;
 
-	fsec->sid = tsec->sid;
-	fsec->fown_sid = tsec->sid;
+	fsec->sid = sid;
+	fsec->fown_sid = sid;
 	file->f_security = fsec;
 
 	return 0;
@@ -338,8 +367,9 @@
 
 static int may_context_mount_sb_relabel(u32 sid,
 			struct superblock_security_struct *sbsec,
-			struct task_security_struct *tsec)
+			const struct cred *cred)
 {
+	const struct task_security_struct *tsec = cred->security;
 	int rc;
 
 	rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
@@ -354,8 +384,9 @@
 
 static int may_context_mount_inode_relabel(u32 sid,
 			struct superblock_security_struct *sbsec,
-			struct task_security_struct *tsec)
+			const struct cred *cred)
 {
+	const struct task_security_struct *tsec = cred->security;
 	int rc;
 	rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
 			  FILESYSTEM__RELABELFROM, NULL);
@@ -553,8 +584,8 @@
 static int selinux_set_mnt_opts(struct super_block *sb,
 				struct security_mnt_opts *opts)
 {
+	const struct cred *cred = current_cred();
 	int rc = 0, i;
-	struct task_security_struct *tsec = current->security;
 	struct superblock_security_struct *sbsec = sb->s_security;
 	const char *name = sb->s_type->name;
 	struct inode *inode = sbsec->sb->s_root->d_inode;
@@ -671,7 +702,7 @@
 		sbsec->proc = 1;
 
 	/* Determine the labeling behavior to use for this filesystem type. */
-	rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
+	rc = security_fs_use(sbsec->proc ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
 	if (rc) {
 		printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
 		       __func__, sb->s_type->name, rc);
@@ -680,8 +711,7 @@
 
 	/* sets the context of the superblock for the fs being mounted. */
 	if (fscontext_sid) {
-
-		rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, tsec);
+		rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
 		if (rc)
 			goto out;
 
@@ -695,12 +725,14 @@
 	 */
 	if (context_sid) {
 		if (!fscontext_sid) {
-			rc = may_context_mount_sb_relabel(context_sid, sbsec, tsec);
+			rc = may_context_mount_sb_relabel(context_sid, sbsec,
+							  cred);
 			if (rc)
 				goto out;
 			sbsec->sid = context_sid;
 		} else {
-			rc = may_context_mount_inode_relabel(context_sid, sbsec, tsec);
+			rc = may_context_mount_inode_relabel(context_sid, sbsec,
+							     cred);
 			if (rc)
 				goto out;
 		}
@@ -712,7 +744,8 @@
 	}
 
 	if (rootcontext_sid) {
-		rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, tsec);
+		rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
+						     cred);
 		if (rc)
 			goto out;
 
@@ -730,7 +763,7 @@
 
 		if (defcontext_sid != sbsec->def_sid) {
 			rc = may_context_mount_inode_relabel(defcontext_sid,
-							     sbsec, tsec);
+							     sbsec, cred);
 			if (rc)
 				goto out;
 		}
@@ -1345,18 +1378,53 @@
 	return perm;
 }
 
-/* Check permission betweeen a pair of tasks, e.g. signal checks,
-   fork check, ptrace check, etc. */
-static int task_has_perm(struct task_struct *tsk1,
-			 struct task_struct *tsk2,
+/*
+ * Check permission between a pair of credentials
+ * fork check, ptrace check, etc.
+ */
+static int cred_has_perm(const struct cred *actor,
+			 const struct cred *target,
 			 u32 perms)
 {
-	struct task_security_struct *tsec1, *tsec2;
+	u32 asid = cred_sid(actor), tsid = cred_sid(target);
 
-	tsec1 = tsk1->security;
-	tsec2 = tsk2->security;
-	return avc_has_perm(tsec1->sid, tsec2->sid,
-			    SECCLASS_PROCESS, perms, NULL);
+	return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
+}
+
+/*
+ * Check permission between a pair of tasks, e.g. signal checks,
+ * fork check, ptrace check, etc.
+ * tsk1 is the actor and tsk2 is the target
+ * - this uses the default subjective creds of tsk1
+ */
+static int task_has_perm(const struct task_struct *tsk1,
+			 const struct task_struct *tsk2,
+			 u32 perms)
+{
+	const struct task_security_struct *__tsec1, *__tsec2;
+	u32 sid1, sid2;
+
+	rcu_read_lock();
+	__tsec1 = __task_cred(tsk1)->security;	sid1 = __tsec1->sid;
+	__tsec2 = __task_cred(tsk2)->security;	sid2 = __tsec2->sid;
+	rcu_read_unlock();
+	return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
+}
+
+/*
+ * Check permission between current and another task, e.g. signal checks,
+ * fork check, ptrace check, etc.
+ * current is the actor and tsk2 is the target
+ * - this uses current's subjective creds
+ */
+static int current_has_perm(const struct task_struct *tsk,
+			    u32 perms)
+{
+	u32 sid, tsid;
+
+	sid = current_sid();
+	tsid = task_sid(tsk);
+	return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
 }
 
 #if CAP_LAST_CAP > 63
@@ -1365,14 +1433,14 @@
 
 /* Check whether a task is allowed to use a capability. */
 static int task_has_capability(struct task_struct *tsk,
-			       int cap)
+			       int cap, int audit)
 {
-	struct task_security_struct *tsec;
 	struct avc_audit_data ad;
+	struct av_decision avd;
 	u16 sclass;
+	u32 sid = task_sid(tsk);
 	u32 av = CAP_TO_MASK(cap);
-
-	tsec = tsk->security;
+	int rc;
 
 	AVC_AUDIT_DATA_INIT(&ad, CAP);
 	ad.tsk = tsk;
@@ -1390,37 +1458,39 @@
 		       "SELinux:  out of range capability %d\n", cap);
 		BUG();
 	}
-	return avc_has_perm(tsec->sid, tsec->sid, sclass, av, &ad);
+
+	rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
+	if (audit == SECURITY_CAP_AUDIT)
+		avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
+	return rc;
 }
 
 /* Check whether a task is allowed to use a system operation. */
 static int task_has_system(struct task_struct *tsk,
 			   u32 perms)
 {
-	struct task_security_struct *tsec;
+	u32 sid = task_sid(tsk);
 
-	tsec = tsk->security;
-
-	return avc_has_perm(tsec->sid, SECINITSID_KERNEL,
+	return avc_has_perm(sid, SECINITSID_KERNEL,
 			    SECCLASS_SYSTEM, perms, NULL);
 }
 
 /* Check whether a task has a particular permission to an inode.
    The 'adp' parameter is optional and allows other audit
    data to be passed (e.g. the dentry). */
-static int inode_has_perm(struct task_struct *tsk,
+static int inode_has_perm(const struct cred *cred,
 			  struct inode *inode,
 			  u32 perms,
 			  struct avc_audit_data *adp)
 {
-	struct task_security_struct *tsec;
 	struct inode_security_struct *isec;
 	struct avc_audit_data ad;
+	u32 sid;
 
 	if (unlikely(IS_PRIVATE(inode)))
 		return 0;
 
-	tsec = tsk->security;
+	sid = cred_sid(cred);
 	isec = inode->i_security;
 
 	if (!adp) {
@@ -1429,23 +1499,24 @@
 		ad.u.fs.inode = inode;
 	}
 
-	return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, adp);
+	return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
    the dentry to help the auditing code to more easily generate the
    pathname if needed. */
-static inline int dentry_has_perm(struct task_struct *tsk,
+static inline int dentry_has_perm(const struct cred *cred,
 				  struct vfsmount *mnt,
 				  struct dentry *dentry,
 				  u32 av)
 {
 	struct inode *inode = dentry->d_inode;
 	struct avc_audit_data ad;
+
 	AVC_AUDIT_DATA_INIT(&ad, FS);
 	ad.u.fs.path.mnt = mnt;
 	ad.u.fs.path.dentry = dentry;
-	return inode_has_perm(tsk, inode, av, &ad);
+	return inode_has_perm(cred, inode, av, &ad);
 }
 
 /* Check whether a task can use an open file descriptor to
@@ -1456,33 +1527,35 @@
    has the same SID as the process.  If av is zero, then
    access to the file is not checked, e.g. for cases
    where only the descriptor is affected like seek. */
-static int file_has_perm(struct task_struct *tsk,
-				struct file *file,
-				u32 av)
+static int file_has_perm(const struct cred *cred,
+			 struct file *file,
+			 u32 av)
 {
-	struct task_security_struct *tsec = tsk->security;
 	struct file_security_struct *fsec = file->f_security;
 	struct inode *inode = file->f_path.dentry->d_inode;
 	struct avc_audit_data ad;
+	u32 sid = cred_sid(cred);
 	int rc;
 
 	AVC_AUDIT_DATA_INIT(&ad, FS);
 	ad.u.fs.path = file->f_path;
 
-	if (tsec->sid != fsec->sid) {
-		rc = avc_has_perm(tsec->sid, fsec->sid,
+	if (sid != fsec->sid) {
+		rc = avc_has_perm(sid, fsec->sid,
 				  SECCLASS_FD,
 				  FD__USE,
 				  &ad);
 		if (rc)
-			return rc;
+			goto out;
 	}
 
 	/* av is zero if only checking access to the descriptor. */
+	rc = 0;
 	if (av)
-		return inode_has_perm(tsk, inode, av, &ad);
+		rc = inode_has_perm(cred, inode, av, &ad);
 
-	return 0;
+out:
+	return rc;
 }
 
 /* Check whether a task can create a file. */
@@ -1490,36 +1563,36 @@
 		      struct dentry *dentry,
 		      u16 tclass)
 {
-	struct task_security_struct *tsec;
+	const struct cred *cred = current_cred();
+	const struct task_security_struct *tsec = cred->security;
 	struct inode_security_struct *dsec;
 	struct superblock_security_struct *sbsec;
-	u32 newsid;
+	u32 sid, newsid;
 	struct avc_audit_data ad;
 	int rc;
 
-	tsec = current->security;
 	dsec = dir->i_security;
 	sbsec = dir->i_sb->s_security;
 
+	sid = tsec->sid;
+	newsid = tsec->create_sid;
+
 	AVC_AUDIT_DATA_INIT(&ad, FS);
 	ad.u.fs.path.dentry = dentry;
 
-	rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR,
+	rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
 			  DIR__ADD_NAME | DIR__SEARCH,
 			  &ad);
 	if (rc)
 		return rc;
 
-	if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
-		newsid = tsec->create_sid;
-	} else {
-		rc = security_transition_sid(tsec->sid, dsec->sid, tclass,
-					     &newsid);
+	if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+		rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
 		if (rc)
 			return rc;
 	}
 
-	rc = avc_has_perm(tsec->sid, newsid, tclass, FILE__CREATE, &ad);
+	rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
 	if (rc)
 		return rc;
 
@@ -1532,11 +1605,9 @@
 static int may_create_key(u32 ksid,
 			  struct task_struct *ctx)
 {
-	struct task_security_struct *tsec;
+	u32 sid = task_sid(ctx);
 
-	tsec = ctx->security;
-
-	return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
+	return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
 }
 
 #define MAY_LINK	0
@@ -1549,13 +1620,12 @@
 		    int kind)
 
 {
-	struct task_security_struct *tsec;
 	struct inode_security_struct *dsec, *isec;
 	struct avc_audit_data ad;
+	u32 sid = current_sid();
 	u32 av;
 	int rc;
 
-	tsec = current->security;
 	dsec = dir->i_security;
 	isec = dentry->d_inode->i_security;
 
@@ -1564,7 +1634,7 @@
 
 	av = DIR__SEARCH;
 	av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
-	rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR, av, &ad);
+	rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
 	if (rc)
 		return rc;
 
@@ -1584,7 +1654,7 @@
 		return 0;
 	}
 
-	rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, av, &ad);
+	rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
 	return rc;
 }
 
@@ -1593,14 +1663,13 @@
 			     struct inode *new_dir,
 			     struct dentry *new_dentry)
 {
-	struct task_security_struct *tsec;
 	struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
 	struct avc_audit_data ad;
+	u32 sid = current_sid();
 	u32 av;
 	int old_is_dir, new_is_dir;
 	int rc;
 
-	tsec = current->security;
 	old_dsec = old_dir->i_security;
 	old_isec = old_dentry->d_inode->i_security;
 	old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
@@ -1609,16 +1678,16 @@
 	AVC_AUDIT_DATA_INIT(&ad, FS);
 
 	ad.u.fs.path.dentry = old_dentry;
-	rc = avc_has_perm(tsec->sid, old_dsec->sid, SECCLASS_DIR,
+	rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
 			  DIR__REMOVE_NAME | DIR__SEARCH, &ad);
 	if (rc)
 		return rc;
-	rc = avc_has_perm(tsec->sid, old_isec->sid,
+	rc = avc_has_perm(sid, old_isec->sid,
 			  old_isec->sclass, FILE__RENAME, &ad);
 	if (rc)
 		return rc;
 	if (old_is_dir && new_dir != old_dir) {
-		rc = avc_has_perm(tsec->sid, old_isec->sid,
+		rc = avc_has_perm(sid, old_isec->sid,
 				  old_isec->sclass, DIR__REPARENT, &ad);
 		if (rc)
 			return rc;
@@ -1628,13 +1697,13 @@
 	av = DIR__ADD_NAME | DIR__SEARCH;
 	if (new_dentry->d_inode)
 		av |= DIR__REMOVE_NAME;
-	rc = avc_has_perm(tsec->sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
+	rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
 	if (rc)
 		return rc;
 	if (new_dentry->d_inode) {
 		new_isec = new_dentry->d_inode->i_security;
 		new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
-		rc = avc_has_perm(tsec->sid, new_isec->sid,
+		rc = avc_has_perm(sid, new_isec->sid,
 				  new_isec->sclass,
 				  (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
 		if (rc)
@@ -1645,18 +1714,16 @@
 }
 
 /* Check whether a task can perform a filesystem operation. */
-static int superblock_has_perm(struct task_struct *tsk,
+static int superblock_has_perm(const struct cred *cred,
 			       struct super_block *sb,
 			       u32 perms,
 			       struct avc_audit_data *ad)
 {
-	struct task_security_struct *tsec;
 	struct superblock_security_struct *sbsec;
+	u32 sid = cred_sid(cred);
 
-	tsec = tsk->security;
 	sbsec = sb->s_security;
-	return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
-			    perms, ad);
+	return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
 }
 
 /* Convert a Linux mode and permission mask to an access vector. */
@@ -1687,35 +1754,6 @@
 	return av;
 }
 
-/*
- * Convert a file mask to an access vector and include the correct open
- * open permission.
- */
-static inline u32 open_file_mask_to_av(int mode, int mask)
-{
-	u32 av = file_mask_to_av(mode, mask);
-
-	if (selinux_policycap_openperm) {
-		/*
-		 * lnk files and socks do not really have an 'open'
-		 */
-		if (S_ISREG(mode))
-			av |= FILE__OPEN;
-		else if (S_ISCHR(mode))
-			av |= CHR_FILE__OPEN;
-		else if (S_ISBLK(mode))
-			av |= BLK_FILE__OPEN;
-		else if (S_ISFIFO(mode))
-			av |= FIFO_FILE__OPEN;
-		else if (S_ISDIR(mode))
-			av |= DIR__OPEN;
-		else
-			printk(KERN_ERR "SELinux: WARNING: inside %s with "
-				"unknown mode:%x\n", __func__, mode);
-	}
-	return av;
-}
-
 /* Convert a Linux file to an access vector. */
 static inline u32 file_to_av(struct file *file)
 {
@@ -1739,6 +1777,36 @@
 	return av;
 }
 
+/*
+ * Convert a file to an access vector and include the correct open
+ * open permission.
+ */
+static inline u32 open_file_to_av(struct file *file)
+{
+	u32 av = file_to_av(file);
+
+	if (selinux_policycap_openperm) {
+		mode_t mode = file->f_path.dentry->d_inode->i_mode;
+		/*
+		 * lnk files and socks do not really have an 'open'
+		 */
+		if (S_ISREG(mode))
+			av |= FILE__OPEN;
+		else if (S_ISCHR(mode))
+			av |= CHR_FILE__OPEN;
+		else if (S_ISBLK(mode))
+			av |= BLK_FILE__OPEN;
+		else if (S_ISFIFO(mode))
+			av |= FIFO_FILE__OPEN;
+		else if (S_ISDIR(mode))
+			av |= DIR__OPEN;
+		else
+			printk(KERN_ERR "SELinux: WARNING: inside %s with "
+				"unknown mode:%o\n", __func__, mode);
+	}
+	return av;
+}
+
 /* Hook functions begin here. */
 
 static int selinux_ptrace_may_access(struct task_struct *child,
@@ -1751,13 +1819,12 @@
 		return rc;
 
 	if (mode == PTRACE_MODE_READ) {
-		struct task_security_struct *tsec = current->security;
-		struct task_security_struct *csec = child->security;
-		return avc_has_perm(tsec->sid, csec->sid,
-				    SECCLASS_FILE, FILE__READ, NULL);
+		u32 sid = current_sid();
+		u32 csid = task_sid(child);
+		return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
 	}
 
-	return task_has_perm(current, child, PROCESS__PTRACE);
+	return current_has_perm(child, PROCESS__PTRACE);
 }
 
 static int selinux_ptrace_traceme(struct task_struct *parent)
@@ -1776,40 +1843,37 @@
 {
 	int error;
 
-	error = task_has_perm(current, target, PROCESS__GETCAP);
+	error = current_has_perm(target, PROCESS__GETCAP);
 	if (error)
 		return error;
 
 	return secondary_ops->capget(target, effective, inheritable, permitted);
 }
 
-static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effective,
-				kernel_cap_t *inheritable, kernel_cap_t *permitted)
+static int selinux_capset(struct cred *new, const struct cred *old,
+			  const kernel_cap_t *effective,
+			  const kernel_cap_t *inheritable,
+			  const kernel_cap_t *permitted)
 {
 	int error;
 
-	error = secondary_ops->capset_check(target, effective, inheritable, permitted);
+	error = secondary_ops->capset(new, old,
+				      effective, inheritable, permitted);
 	if (error)
 		return error;
 
-	return task_has_perm(current, target, PROCESS__SETCAP);
+	return cred_has_perm(old, new, PROCESS__SETCAP);
 }
 
-static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effective,
-			       kernel_cap_t *inheritable, kernel_cap_t *permitted)
-{
-	secondary_ops->capset_set(target, effective, inheritable, permitted);
-}
-
-static int selinux_capable(struct task_struct *tsk, int cap)
+static int selinux_capable(struct task_struct *tsk, int cap, int audit)
 {
 	int rc;
 
-	rc = secondary_ops->capable(tsk, cap);
+	rc = secondary_ops->capable(tsk, cap, audit);
 	if (rc)
 		return rc;
 
-	return task_has_capability(tsk, cap);
+	return task_has_capability(tsk, cap, audit);
 }
 
 static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
@@ -1857,15 +1921,14 @@
 {
 	int error = 0;
 	u32 av;
-	struct task_security_struct *tsec;
-	u32 tsid;
+	u32 tsid, sid;
 	int rc;
 
 	rc = secondary_ops->sysctl(table, op);
 	if (rc)
 		return rc;
 
-	tsec = current->security;
+	sid = current_sid();
 
 	rc = selinux_sysctl_get_sid(table, (op == 0001) ?
 				    SECCLASS_DIR : SECCLASS_FILE, &tsid);
@@ -1877,7 +1940,7 @@
 	/* The op values are "defined" in sysctl.c, thereby creating
 	 * a bad coupling between this module and sysctl.c */
 	if (op == 001) {
-		error = avc_has_perm(tsec->sid, tsid,
+		error = avc_has_perm(sid, tsid,
 				     SECCLASS_DIR, DIR__SEARCH, NULL);
 	} else {
 		av = 0;
@@ -1886,7 +1949,7 @@
 		if (op & 002)
 			av |= FILE__WRITE;
 		if (av)
-			error = avc_has_perm(tsec->sid, tsid,
+			error = avc_has_perm(sid, tsid,
 					     SECCLASS_FILE, av, NULL);
 	}
 
@@ -1895,6 +1958,7 @@
 
 static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
 {
+	const struct cred *cred = current_cred();
 	int rc = 0;
 
 	if (!sb)
@@ -1906,14 +1970,12 @@
 	case Q_QUOTAOFF:
 	case Q_SETINFO:
 	case Q_SETQUOTA:
-		rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAMOD,
-					 NULL);
+		rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
 		break;
 	case Q_GETFMT:
 	case Q_GETINFO:
 	case Q_GETQUOTA:
-		rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAGET,
-					 NULL);
+		rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
 		break;
 	default:
 		rc = 0;  /* let the kernel handle invalid cmds */
@@ -1924,7 +1986,9 @@
 
 static int selinux_quota_on(struct dentry *dentry)
 {
-	return dentry_has_perm(current, NULL, dentry, FILE__QUOTAON);
+	const struct cred *cred = current_cred();
+
+	return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
 }
 
 static int selinux_syslog(int type)
@@ -1972,16 +2036,8 @@
 static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 {
 	int rc, cap_sys_admin = 0;
-	struct task_security_struct *tsec = current->security;
 
-	rc = secondary_ops->capable(current, CAP_SYS_ADMIN);
-	if (rc == 0)
-		rc = avc_has_perm_noaudit(tsec->sid, tsec->sid,
-					  SECCLASS_CAPABILITY,
-					  CAP_TO_MASK(CAP_SYS_ADMIN),
-					  0,
-					  NULL);
-
+	rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT);
 	if (rc == 0)
 		cap_sys_admin = 1;
 
@@ -1990,59 +2046,45 @@
 
 /* binprm security operations */
 
-static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
+static int selinux_bprm_set_creds(struct linux_binprm *bprm)
 {
-	struct bprm_security_struct *bsec;
-
-	bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
-	if (!bsec)
-		return -ENOMEM;
-
-	bsec->sid = SECINITSID_UNLABELED;
-	bsec->set = 0;
-
-	bprm->security = bsec;
-	return 0;
-}
-
-static int selinux_bprm_set_security(struct linux_binprm *bprm)
-{
-	struct task_security_struct *tsec;
-	struct inode *inode = bprm->file->f_path.dentry->d_inode;
+	const struct task_security_struct *old_tsec;
+	struct task_security_struct *new_tsec;
 	struct inode_security_struct *isec;
-	struct bprm_security_struct *bsec;
-	u32 newsid;
 	struct avc_audit_data ad;
+	struct inode *inode = bprm->file->f_path.dentry->d_inode;
 	int rc;
 
-	rc = secondary_ops->bprm_set_security(bprm);
+	rc = secondary_ops->bprm_set_creds(bprm);
 	if (rc)
 		return rc;
 
-	bsec = bprm->security;
-
-	if (bsec->set)
+	/* SELinux context only depends on initial program or script and not
+	 * the script interpreter */
+	if (bprm->cred_prepared)
 		return 0;
 
-	tsec = current->security;
+	old_tsec = current_security();
+	new_tsec = bprm->cred->security;
 	isec = inode->i_security;
 
 	/* Default to the current task SID. */
-	bsec->sid = tsec->sid;
+	new_tsec->sid = old_tsec->sid;
+	new_tsec->osid = old_tsec->sid;
 
 	/* Reset fs, key, and sock SIDs on execve. */
-	tsec->create_sid = 0;
-	tsec->keycreate_sid = 0;
-	tsec->sockcreate_sid = 0;
+	new_tsec->create_sid = 0;
+	new_tsec->keycreate_sid = 0;
+	new_tsec->sockcreate_sid = 0;
 
-	if (tsec->exec_sid) {
-		newsid = tsec->exec_sid;
+	if (old_tsec->exec_sid) {
+		new_tsec->sid = old_tsec->exec_sid;
 		/* Reset exec SID on execve. */
-		tsec->exec_sid = 0;
+		new_tsec->exec_sid = 0;
 	} else {
 		/* Check for a default transition on this program. */
-		rc = security_transition_sid(tsec->sid, isec->sid,
-					     SECCLASS_PROCESS, &newsid);
+		rc = security_transition_sid(old_tsec->sid, isec->sid,
+					     SECCLASS_PROCESS, &new_tsec->sid);
 		if (rc)
 			return rc;
 	}
@@ -2051,33 +2093,63 @@
 	ad.u.fs.path = bprm->file->f_path;
 
 	if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
-		newsid = tsec->sid;
+		new_tsec->sid = old_tsec->sid;
 
-	if (tsec->sid == newsid) {
-		rc = avc_has_perm(tsec->sid, isec->sid,
+	if (new_tsec->sid == old_tsec->sid) {
+		rc = avc_has_perm(old_tsec->sid, isec->sid,
 				  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
 		if (rc)
 			return rc;
 	} else {
 		/* Check permissions for the transition. */
-		rc = avc_has_perm(tsec->sid, newsid,
+		rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
 				  SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
 		if (rc)
 			return rc;
 
-		rc = avc_has_perm(newsid, isec->sid,
+		rc = avc_has_perm(new_tsec->sid, isec->sid,
 				  SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
 		if (rc)
 			return rc;
 
-		/* Clear any possibly unsafe personality bits on exec: */
-		current->personality &= ~PER_CLEAR_ON_SETID;
+		/* Check for shared state */
+		if (bprm->unsafe & LSM_UNSAFE_SHARE) {
+			rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+					  SECCLASS_PROCESS, PROCESS__SHARE,
+					  NULL);
+			if (rc)
+				return -EPERM;
+		}
 
-		/* Set the security field to the new SID. */
-		bsec->sid = newsid;
+		/* Make sure that anyone attempting to ptrace over a task that
+		 * changes its SID has the appropriate permit */
+		if (bprm->unsafe &
+		    (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
+			struct task_struct *tracer;
+			struct task_security_struct *sec;
+			u32 ptsid = 0;
+
+			rcu_read_lock();
+			tracer = tracehook_tracer_task(current);
+			if (likely(tracer != NULL)) {
+				sec = __task_cred(tracer)->security;
+				ptsid = sec->sid;
+			}
+			rcu_read_unlock();
+
+			if (ptsid != 0) {
+				rc = avc_has_perm(ptsid, new_tsec->sid,
+						  SECCLASS_PROCESS,
+						  PROCESS__PTRACE, NULL);
+				if (rc)
+					return -EPERM;
+			}
+		}
+
+		/* Clear any possibly unsafe personality bits on exec: */
+		bprm->per_clear |= PER_CLEAR_ON_SETID;
 	}
 
-	bsec->set = 1;
 	return 0;
 }
 
@@ -2086,35 +2158,34 @@
 	return secondary_ops->bprm_check_security(bprm);
 }
 
-
 static int selinux_bprm_secureexec(struct linux_binprm *bprm)
 {
-	struct task_security_struct *tsec = current->security;
+	const struct cred *cred = current_cred();
+	const struct task_security_struct *tsec = cred->security;
+	u32 sid, osid;
 	int atsecure = 0;
 
-	if (tsec->osid != tsec->sid) {
+	sid = tsec->sid;
+	osid = tsec->osid;
+
+	if (osid != sid) {
 		/* Enable secure mode for SIDs transitions unless
 		   the noatsecure permission is granted between
 		   the two SIDs, i.e. ahp returns 0. */
-		atsecure = avc_has_perm(tsec->osid, tsec->sid,
-					 SECCLASS_PROCESS,
-					 PROCESS__NOATSECURE, NULL);
+		atsecure = avc_has_perm(osid, sid,
+					SECCLASS_PROCESS,
+					PROCESS__NOATSECURE, NULL);
 	}
 
 	return (atsecure || secondary_ops->bprm_secureexec(bprm));
 }
 
-static void selinux_bprm_free_security(struct linux_binprm *bprm)
-{
-	kfree(bprm->security);
-	bprm->security = NULL;
-}
-
 extern struct vfsmount *selinuxfs_mount;
 extern struct dentry *selinux_null;
 
 /* Derived from fs/exec.c:flush_old_files. */
-static inline void flush_unauthorized_files(struct files_struct *files)
+static inline void flush_unauthorized_files(const struct cred *cred,
+					    struct files_struct *files)
 {
 	struct avc_audit_data ad;
 	struct file *file, *devnull = NULL;
@@ -2136,7 +2207,7 @@
 			   interested in the inode-based check here. */
 			file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
 			inode = file->f_path.dentry->d_inode;
-			if (inode_has_perm(current, inode,
+			if (inode_has_perm(cred, inode,
 					   FILE__READ | FILE__WRITE, NULL)) {
 				drop_tty = 1;
 			}
@@ -2171,7 +2242,7 @@
 				file = fget(i);
 				if (!file)
 					continue;
-				if (file_has_perm(current,
+				if (file_has_perm(cred,
 						  file,
 						  file_to_av(file))) {
 					sys_close(i);
@@ -2185,7 +2256,10 @@
 					if (devnull) {
 						get_file(devnull);
 					} else {
-						devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR);
+						devnull = dentry_open(
+							dget(selinux_null),
+							mntget(selinuxfs_mount),
+							O_RDWR, cred);
 						if (IS_ERR(devnull)) {
 							devnull = NULL;
 							put_unused_fd(fd);
@@ -2204,94 +2278,78 @@
 	spin_unlock(&files->file_lock);
 }
 
-static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+/*
+ * Prepare a process for imminent new credential changes due to exec
+ */
+static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
 {
-	struct task_security_struct *tsec;
-	struct bprm_security_struct *bsec;
-	u32 sid;
-	int rc;
+	struct task_security_struct *new_tsec;
+	struct rlimit *rlim, *initrlim;
+	int rc, i;
 
-	secondary_ops->bprm_apply_creds(bprm, unsafe);
+	secondary_ops->bprm_committing_creds(bprm);
 
-	tsec = current->security;
+	new_tsec = bprm->cred->security;
+	if (new_tsec->sid == new_tsec->osid)
+		return;
 
-	bsec = bprm->security;
-	sid = bsec->sid;
+	/* Close files for which the new task SID is not authorized. */
+	flush_unauthorized_files(bprm->cred, current->files);
 
-	tsec->osid = tsec->sid;
-	bsec->unsafe = 0;
-	if (tsec->sid != sid) {
-		/* Check for shared state.  If not ok, leave SID
-		   unchanged and kill. */
-		if (unsafe & LSM_UNSAFE_SHARE) {
-			rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
-					PROCESS__SHARE, NULL);
-			if (rc) {
-				bsec->unsafe = 1;
-				return;
-			}
+	/* Always clear parent death signal on SID transitions. */
+	current->pdeath_signal = 0;
+
+	/* Check whether the new SID can inherit resource limits from the old
+	 * SID.  If not, reset all soft limits to the lower of the current
+	 * task's hard limit and the init task's soft limit.
+	 *
+	 * Note that the setting of hard limits (even to lower them) can be
+	 * controlled by the setrlimit check.  The inclusion of the init task's
+	 * soft limit into the computation is to avoid resetting soft limits
+	 * higher than the default soft limit for cases where the default is
+	 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
+	 */
+	rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
+			  PROCESS__RLIMITINH, NULL);
+	if (rc) {
+		for (i = 0; i < RLIM_NLIMITS; i++) {
+			rlim = current->signal->rlim + i;
+			initrlim = init_task.signal->rlim + i;
+			rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
 		}
-
-		/* Check for ptracing, and update the task SID if ok.
-		   Otherwise, leave SID unchanged and kill. */
-		if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
-			struct task_struct *tracer;
-			struct task_security_struct *sec;
-			u32 ptsid = 0;
-
-			rcu_read_lock();
-			tracer = tracehook_tracer_task(current);
-			if (likely(tracer != NULL)) {
-				sec = tracer->security;
-				ptsid = sec->sid;
-			}
-			rcu_read_unlock();
-
-			if (ptsid != 0) {
-				rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
-						  PROCESS__PTRACE, NULL);
-				if (rc) {
-					bsec->unsafe = 1;
-					return;
-				}
-			}
-		}
-		tsec->sid = sid;
+		update_rlimit_cpu(rlim->rlim_cur);
 	}
 }
 
 /*
- * called after apply_creds without the task lock held
+ * Clean up the process immediately after the installation of new credentials
+ * due to exec
  */
-static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
+static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
 {
-	struct task_security_struct *tsec;
-	struct rlimit *rlim, *initrlim;
+	const struct task_security_struct *tsec = current_security();
 	struct itimerval itimer;
-	struct bprm_security_struct *bsec;
+	struct sighand_struct *psig;
+	u32 osid, sid;
 	int rc, i;
+	unsigned long flags;
 
-	tsec = current->security;
-	bsec = bprm->security;
+	secondary_ops->bprm_committed_creds(bprm);
 
-	if (bsec->unsafe) {
-		force_sig_specific(SIGKILL, current);
-		return;
-	}
-	if (tsec->osid == tsec->sid)
+	osid = tsec->osid;
+	sid = tsec->sid;
+
+	if (sid == osid)
 		return;
 
-	/* Close files for which the new task SID is not authorized. */
-	flush_unauthorized_files(current->files);
-
-	/* Check whether the new SID can inherit signal state
-	   from the old SID.  If not, clear itimers to avoid
-	   subsequent signal generation and flush and unblock
-	   signals. This must occur _after_ the task SID has
-	  been updated so that any kill done after the flush
-	  will be checked against the new SID. */
-	rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
-			  PROCESS__SIGINH, NULL);
+	/* Check whether the new SID can inherit signal state from the old SID.
+	 * If not, clear itimers to avoid subsequent signal generation and
+	 * flush and unblock signals.
+	 *
+	 * This must occur _after_ the task SID has been updated so that any
+	 * kill done after the flush will be checked against the new SID.
+	 */
+	rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
 	if (rc) {
 		memset(&itimer, 0, sizeof itimer);
 		for (i = 0; i < 3; i++)
@@ -2304,33 +2362,14 @@
 		spin_unlock_irq(&current->sighand->siglock);
 	}
 
-	/* Always clear parent death signal on SID transitions. */
-	current->pdeath_signal = 0;
-
-	/* Check whether the new SID can inherit resource limits
-	   from the old SID.  If not, reset all soft limits to
-	   the lower of the current task's hard limit and the init
-	   task's soft limit.  Note that the setting of hard limits
-	   (even to lower them) can be controlled by the setrlimit
-	   check. The inclusion of the init task's soft limit into
-	   the computation is to avoid resetting soft limits higher
-	   than the default soft limit for cases where the default
-	   is lower than the hard limit, e.g. RLIMIT_CORE or
-	   RLIMIT_STACK.*/
-	rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
-			  PROCESS__RLIMITINH, NULL);
-	if (rc) {
-		for (i = 0; i < RLIM_NLIMITS; i++) {
-			rlim = current->signal->rlim + i;
-			initrlim = init_task.signal->rlim+i;
-			rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
-		}
-		update_rlimit_cpu(rlim->rlim_cur);
-	}
-
-	/* Wake up the parent if it is waiting so that it can
-	   recheck wait permission to the new task SID. */
+	/* Wake up the parent if it is waiting so that it can recheck
+	 * wait permission to the new task SID. */
+	read_lock_irq(&tasklist_lock);
+	psig = current->parent->sighand;
+	spin_lock_irqsave(&psig->siglock, flags);
 	wake_up_interruptible(&current->parent->signal->wait_chldexit);
+	spin_unlock_irqrestore(&psig->siglock, flags);
+	read_unlock_irq(&tasklist_lock);
 }
 
 /* superblock security operations */
@@ -2435,8 +2474,9 @@
 	return rc;
 }
 
-static int selinux_sb_kern_mount(struct super_block *sb, void *data)
+static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
 {
+	const struct cred *cred = current_cred();
 	struct avc_audit_data ad;
 	int rc;
 
@@ -2444,18 +2484,23 @@
 	if (rc)
 		return rc;
 
+	/* Allow all mounts performed by the kernel */
+	if (flags & MS_KERNMOUNT)
+		return 0;
+
 	AVC_AUDIT_DATA_INIT(&ad, FS);
 	ad.u.fs.path.dentry = sb->s_root;
-	return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
+	return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
 }
 
 static int selinux_sb_statfs(struct dentry *dentry)
 {
+	const struct cred *cred = current_cred();
 	struct avc_audit_data ad;
 
 	AVC_AUDIT_DATA_INIT(&ad, FS);
 	ad.u.fs.path.dentry = dentry->d_sb->s_root;
-	return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
+	return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
 
 static int selinux_mount(char *dev_name,
@@ -2464,6 +2509,7 @@
 			 unsigned long flags,
 			 void *data)
 {
+	const struct cred *cred = current_cred();
 	int rc;
 
 	rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
@@ -2471,22 +2517,23 @@
 		return rc;
 
 	if (flags & MS_REMOUNT)
-		return superblock_has_perm(current, path->mnt->mnt_sb,
+		return superblock_has_perm(cred, path->mnt->mnt_sb,
 					   FILESYSTEM__REMOUNT, NULL);
 	else
-		return dentry_has_perm(current, path->mnt, path->dentry,
+		return dentry_has_perm(cred, path->mnt, path->dentry,
 				       FILE__MOUNTON);
 }
 
 static int selinux_umount(struct vfsmount *mnt, int flags)
 {
+	const struct cred *cred = current_cred();
 	int rc;
 
 	rc = secondary_ops->sb_umount(mnt, flags);
 	if (rc)
 		return rc;
 
-	return superblock_has_perm(current, mnt->mnt_sb,
+	return superblock_has_perm(cred, mnt->mnt_sb,
 				   FILESYSTEM__UNMOUNT, NULL);
 }
 
@@ -2506,21 +2553,22 @@
 				       char **name, void **value,
 				       size_t *len)
 {
-	struct task_security_struct *tsec;
+	const struct cred *cred = current_cred();
+	const struct task_security_struct *tsec = cred->security;
 	struct inode_security_struct *dsec;
 	struct superblock_security_struct *sbsec;
-	u32 newsid, clen;
+	u32 sid, newsid, clen;
 	int rc;
 	char *namep = NULL, *context;
 
-	tsec = current->security;
 	dsec = dir->i_security;
 	sbsec = dir->i_sb->s_security;
 
-	if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
-		newsid = tsec->create_sid;
-	} else {
-		rc = security_transition_sid(tsec->sid, dsec->sid,
+	sid = tsec->sid;
+	newsid = tsec->create_sid;
+
+	if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+		rc = security_transition_sid(sid, dsec->sid,
 					     inode_mode_to_security_class(inode->i_mode),
 					     &newsid);
 		if (rc) {
@@ -2623,21 +2671,25 @@
 
 static int selinux_inode_readlink(struct dentry *dentry)
 {
-	return dentry_has_perm(current, NULL, dentry, FILE__READ);
+	const struct cred *cred = current_cred();
+
+	return dentry_has_perm(cred, NULL, dentry, FILE__READ);
 }
 
 static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
 {
+	const struct cred *cred = current_cred();
 	int rc;
 
 	rc = secondary_ops->inode_follow_link(dentry, nameidata);
 	if (rc)
 		return rc;
-	return dentry_has_perm(current, NULL, dentry, FILE__READ);
+	return dentry_has_perm(cred, NULL, dentry, FILE__READ);
 }
 
 static int selinux_inode_permission(struct inode *inode, int mask)
 {
+	const struct cred *cred = current_cred();
 	int rc;
 
 	rc = secondary_ops->inode_permission(inode, mask);
@@ -2649,12 +2701,13 @@
 		return 0;
 	}
 
-	return inode_has_perm(current, inode,
-			       open_file_mask_to_av(inode->i_mode, mask), NULL);
+	return inode_has_perm(cred, inode,
+			      file_mask_to_av(inode->i_mode, mask), NULL);
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
+	const struct cred *cred = current_cred();
 	int rc;
 
 	rc = secondary_ops->inode_setattr(dentry, iattr);
@@ -2666,18 +2719,22 @@
 
 	if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
 			       ATTR_ATIME_SET | ATTR_MTIME_SET))
-		return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
+		return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
 
-	return dentry_has_perm(current, NULL, dentry, FILE__WRITE);
+	return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
 }
 
 static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 {
-	return dentry_has_perm(current, mnt, dentry, FILE__GETATTR);
+	const struct cred *cred = current_cred();
+
+	return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
 {
+	const struct cred *cred = current_cred();
+
 	if (!strncmp(name, XATTR_SECURITY_PREFIX,
 		     sizeof XATTR_SECURITY_PREFIX - 1)) {
 		if (!strcmp(name, XATTR_NAME_CAPS)) {
@@ -2692,18 +2749,17 @@
 
 	/* Not an attribute we recognize, so just check the
 	   ordinary setattr permission. */
-	return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
+	return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
 }
 
 static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 				  const void *value, size_t size, int flags)
 {
-	struct task_security_struct *tsec = current->security;
 	struct inode *inode = dentry->d_inode;
 	struct inode_security_struct *isec = inode->i_security;
 	struct superblock_security_struct *sbsec;
 	struct avc_audit_data ad;
-	u32 newsid;
+	u32 newsid, sid = current_sid();
 	int rc = 0;
 
 	if (strcmp(name, XATTR_NAME_SELINUX))
@@ -2719,7 +2775,7 @@
 	AVC_AUDIT_DATA_INIT(&ad, FS);
 	ad.u.fs.path.dentry = dentry;
 
-	rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
+	rc = avc_has_perm(sid, isec->sid, isec->sclass,
 			  FILE__RELABELFROM, &ad);
 	if (rc)
 		return rc;
@@ -2733,12 +2789,12 @@
 	if (rc)
 		return rc;
 
-	rc = avc_has_perm(tsec->sid, newsid, isec->sclass,
+	rc = avc_has_perm(sid, newsid, isec->sclass,
 			  FILE__RELABELTO, &ad);
 	if (rc)
 		return rc;
 
-	rc = security_validate_transition(isec->sid, newsid, tsec->sid,
+	rc = security_validate_transition(isec->sid, newsid, sid,
 					  isec->sclass);
 	if (rc)
 		return rc;
@@ -2778,12 +2834,16 @@
 
 static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
 {
-	return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
+	const struct cred *cred = current_cred();
+
+	return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_listxattr(struct dentry *dentry)
 {
-	return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
+	const struct cred *cred = current_cred();
+
+	return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
@@ -2806,7 +2866,6 @@
 	u32 size;
 	int error;
 	char *context = NULL;
-	struct task_security_struct *tsec = current->security;
 	struct inode_security_struct *isec = inode->i_security;
 
 	if (strcmp(name, XATTR_SELINUX_SUFFIX))
@@ -2821,13 +2880,7 @@
 	 * and lack of permission just means that we fall back to the
 	 * in-core context value, not a denial.
 	 */
-	error = secondary_ops->capable(current, CAP_MAC_ADMIN);
-	if (!error)
-		error = avc_has_perm_noaudit(tsec->sid, tsec->sid,
-					     SECCLASS_CAPABILITY2,
-					     CAPABILITY2__MAC_ADMIN,
-					     0,
-					     NULL);
+	error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT);
 	if (!error)
 		error = security_sid_to_context_force(isec->sid, &context,
 						      &size);
@@ -2894,6 +2947,7 @@
 
 static int selinux_revalidate_file_permission(struct file *file, int mask)
 {
+	const struct cred *cred = current_cred();
 	int rc;
 	struct inode *inode = file->f_path.dentry->d_inode;
 
@@ -2906,7 +2960,7 @@
 	if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
 		mask |= MAY_APPEND;
 
-	rc = file_has_perm(current, file,
+	rc = file_has_perm(cred, file,
 			   file_mask_to_av(inode->i_mode, mask));
 	if (rc)
 		return rc;
@@ -2917,16 +2971,16 @@
 static int selinux_file_permission(struct file *file, int mask)
 {
 	struct inode *inode = file->f_path.dentry->d_inode;
-	struct task_security_struct *tsec = current->security;
 	struct file_security_struct *fsec = file->f_security;
 	struct inode_security_struct *isec = inode->i_security;
+	u32 sid = current_sid();
 
 	if (!mask) {
 		/* No permission to check.  Existence test. */
 		return 0;
 	}
 
-	if (tsec->sid == fsec->sid && fsec->isid == isec->sid
+	if (sid == fsec->sid && fsec->isid == isec->sid
 	    && fsec->pseqno == avc_policy_seqno())
 		return selinux_netlbl_inode_permission(inode, mask);
 
@@ -2946,6 +3000,7 @@
 static int selinux_file_ioctl(struct file *file, unsigned int cmd,
 			      unsigned long arg)
 {
+	const struct cred *cred = current_cred();
 	u32 av = 0;
 
 	if (_IOC_DIR(cmd) & _IOC_WRITE)
@@ -2955,11 +3010,14 @@
 	if (!av)
 		av = FILE__IOCTL;
 
-	return file_has_perm(current, file, av);
+	return file_has_perm(cred, file, av);
 }
 
 static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
 {
+	const struct cred *cred = current_cred();
+	int rc = 0;
+
 #ifndef CONFIG_PPC32
 	if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
 		/*
@@ -2967,9 +3025,9 @@
 		 * private file mapping that will also be writable.
 		 * This has an additional check.
 		 */
-		int rc = task_has_perm(current, current, PROCESS__EXECMEM);
+		rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
 		if (rc)
-			return rc;
+			goto error;
 	}
 #endif
 
@@ -2984,9 +3042,11 @@
 		if (prot & PROT_EXEC)
 			av |= FILE__EXECUTE;
 
-		return file_has_perm(current, file, av);
+		return file_has_perm(cred, file, av);
 	}
-	return 0;
+
+error:
+	return rc;
 }
 
 static int selinux_file_mmap(struct file *file, unsigned long reqprot,
@@ -2994,7 +3054,7 @@
 			     unsigned long addr, unsigned long addr_only)
 {
 	int rc = 0;
-	u32 sid = ((struct task_security_struct *)(current->security))->sid;
+	u32 sid = current_sid();
 
 	if (addr < mmap_min_addr)
 		rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
@@ -3013,6 +3073,7 @@
 				 unsigned long reqprot,
 				 unsigned long prot)
 {
+	const struct cred *cred = current_cred();
 	int rc;
 
 	rc = secondary_ops->file_mprotect(vma, reqprot, prot);
@@ -3027,12 +3088,11 @@
 		rc = 0;
 		if (vma->vm_start >= vma->vm_mm->start_brk &&
 		    vma->vm_end <= vma->vm_mm->brk) {
-			rc = task_has_perm(current, current,
-					   PROCESS__EXECHEAP);
+			rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
 		} else if (!vma->vm_file &&
 			   vma->vm_start <= vma->vm_mm->start_stack &&
 			   vma->vm_end >= vma->vm_mm->start_stack) {
-			rc = task_has_perm(current, current, PROCESS__EXECSTACK);
+			rc = current_has_perm(current, PROCESS__EXECSTACK);
 		} else if (vma->vm_file && vma->anon_vma) {
 			/*
 			 * We are making executable a file mapping that has
@@ -3041,8 +3101,7 @@
 			 * modified content.  This typically should only
 			 * occur for text relocations.
 			 */
-			rc = file_has_perm(current, vma->vm_file,
-					   FILE__EXECMOD);
+			rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
 		}
 		if (rc)
 			return rc;
@@ -3054,12 +3113,15 @@
 
 static int selinux_file_lock(struct file *file, unsigned int cmd)
 {
-	return file_has_perm(current, file, FILE__LOCK);
+	const struct cred *cred = current_cred();
+
+	return file_has_perm(cred, file, FILE__LOCK);
 }
 
 static int selinux_file_fcntl(struct file *file, unsigned int cmd,
 			      unsigned long arg)
 {
+	const struct cred *cred = current_cred();
 	int err = 0;
 
 	switch (cmd) {
@@ -3070,7 +3132,7 @@
 		}
 
 		if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
-			err = file_has_perm(current, file, FILE__WRITE);
+			err = file_has_perm(cred, file, FILE__WRITE);
 			break;
 		}
 		/* fall through */
@@ -3080,7 +3142,7 @@
 	case F_GETOWN:
 	case F_GETSIG:
 		/* Just check FD__USE permission */
-		err = file_has_perm(current, file, 0);
+		err = file_has_perm(cred, file, 0);
 		break;
 	case F_GETLK:
 	case F_SETLK:
@@ -3094,7 +3156,7 @@
 			err = -EINVAL;
 			break;
 		}
-		err = file_has_perm(current, file, FILE__LOCK);
+		err = file_has_perm(cred, file, FILE__LOCK);
 		break;
 	}
 
@@ -3103,12 +3165,10 @@
 
 static int selinux_file_set_fowner(struct file *file)
 {
-	struct task_security_struct *tsec;
 	struct file_security_struct *fsec;
 
-	tsec = current->security;
 	fsec = file->f_security;
-	fsec->fown_sid = tsec->sid;
+	fsec->fown_sid = current_sid();
 
 	return 0;
 }
@@ -3117,14 +3177,13 @@
 				       struct fown_struct *fown, int signum)
 {
 	struct file *file;
+	u32 sid = current_sid();
 	u32 perm;
-	struct task_security_struct *tsec;
 	struct file_security_struct *fsec;
 
 	/* struct fown_struct is never outside the context of a struct file */
 	file = container_of(fown, struct file, f_owner);
 
-	tsec = tsk->security;
 	fsec = file->f_security;
 
 	if (!signum)
@@ -3132,20 +3191,23 @@
 	else
 		perm = signal_to_av(signum);
 
-	return avc_has_perm(fsec->fown_sid, tsec->sid,
+	return avc_has_perm(fsec->fown_sid, sid,
 			    SECCLASS_PROCESS, perm, NULL);
 }
 
 static int selinux_file_receive(struct file *file)
 {
-	return file_has_perm(current, file, file_to_av(file));
+	const struct cred *cred = current_cred();
+
+	return file_has_perm(cred, file, file_to_av(file));
 }
 
-static int selinux_dentry_open(struct file *file)
+static int selinux_dentry_open(struct file *file, const struct cred *cred)
 {
 	struct file_security_struct *fsec;
 	struct inode *inode;
 	struct inode_security_struct *isec;
+
 	inode = file->f_path.dentry->d_inode;
 	fsec = file->f_security;
 	isec = inode->i_security;
@@ -3166,7 +3228,7 @@
 	 * new inode label or new policy.
 	 * This check is not redundant - do not remove.
 	 */
-	return inode_has_perm(current, inode, file_to_av(file), NULL);
+	return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
 }
 
 /* task security operations */
@@ -3179,36 +3241,88 @@
 	if (rc)
 		return rc;
 
-	return task_has_perm(current, current, PROCESS__FORK);
+	return current_has_perm(current, PROCESS__FORK);
 }
 
-static int selinux_task_alloc_security(struct task_struct *tsk)
+/*
+ * detach and free the LSM part of a set of credentials
+ */
+static void selinux_cred_free(struct cred *cred)
 {
-	struct task_security_struct *tsec1, *tsec2;
-	int rc;
+	struct task_security_struct *tsec = cred->security;
+	cred->security = NULL;
+	kfree(tsec);
+}
 
-	tsec1 = current->security;
+/*
+ * prepare a new set of credentials for modification
+ */
+static int selinux_cred_prepare(struct cred *new, const struct cred *old,
+				gfp_t gfp)
+{
+	const struct task_security_struct *old_tsec;
+	struct task_security_struct *tsec;
 
-	rc = task_alloc_security(tsk);
-	if (rc)
-		return rc;
-	tsec2 = tsk->security;
+	old_tsec = old->security;
 
-	tsec2->osid = tsec1->osid;
-	tsec2->sid = tsec1->sid;
+	tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
+	if (!tsec)
+		return -ENOMEM;
 
-	/* Retain the exec, fs, key, and sock SIDs across fork */
-	tsec2->exec_sid = tsec1->exec_sid;
-	tsec2->create_sid = tsec1->create_sid;
-	tsec2->keycreate_sid = tsec1->keycreate_sid;
-	tsec2->sockcreate_sid = tsec1->sockcreate_sid;
-
+	new->security = tsec;
 	return 0;
 }
 
-static void selinux_task_free_security(struct task_struct *tsk)
+/*
+ * commit new credentials
+ */
+static void selinux_cred_commit(struct cred *new, const struct cred *old)
 {
-	task_free_security(tsk);
+	secondary_ops->cred_commit(new, old);
+}
+
+/*
+ * set the security data for a kernel service
+ * - all the creation contexts are set to unlabelled
+ */
+static int selinux_kernel_act_as(struct cred *new, u32 secid)
+{
+	struct task_security_struct *tsec = new->security;
+	u32 sid = current_sid();
+	int ret;
+
+	ret = avc_has_perm(sid, secid,
+			   SECCLASS_KERNEL_SERVICE,
+			   KERNEL_SERVICE__USE_AS_OVERRIDE,
+			   NULL);
+	if (ret == 0) {
+		tsec->sid = secid;
+		tsec->create_sid = 0;
+		tsec->keycreate_sid = 0;
+		tsec->sockcreate_sid = 0;
+	}
+	return ret;
+}
+
+/*
+ * set the file creation context in a security record to the same as the
+ * objective context of the specified inode
+ */
+static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
+{
+	struct inode_security_struct *isec = inode->i_security;
+	struct task_security_struct *tsec = new->security;
+	u32 sid = current_sid();
+	int ret;
+
+	ret = avc_has_perm(sid, isec->sid,
+			   SECCLASS_KERNEL_SERVICE,
+			   KERNEL_SERVICE__CREATE_FILES_AS,
+			   NULL);
+
+	if (ret == 0)
+		tsec->create_sid = isec->sid;
+	return 0;
 }
 
 static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
@@ -3222,9 +3336,10 @@
 	return 0;
 }
 
-static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
+static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
+				   int flags)
 {
-	return secondary_ops->task_post_setuid(id0, id1, id2, flags);
+	return secondary_ops->task_fix_setuid(new, old, flags);
 }
 
 static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
@@ -3235,23 +3350,22 @@
 
 static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
 {
-	return task_has_perm(current, p, PROCESS__SETPGID);
+	return current_has_perm(p, PROCESS__SETPGID);
 }
 
 static int selinux_task_getpgid(struct task_struct *p)
 {
-	return task_has_perm(current, p, PROCESS__GETPGID);
+	return current_has_perm(p, PROCESS__GETPGID);
 }
 
 static int selinux_task_getsid(struct task_struct *p)
 {
-	return task_has_perm(current, p, PROCESS__GETSESSION);
+	return current_has_perm(p, PROCESS__GETSESSION);
 }
 
 static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
 {
-	struct task_security_struct *tsec = p->security;
-	*secid = tsec->sid;
+	*secid = task_sid(p);
 }
 
 static int selinux_task_setgroups(struct group_info *group_info)
@@ -3268,7 +3382,7 @@
 	if (rc)
 		return rc;
 
-	return task_has_perm(current, p, PROCESS__SETSCHED);
+	return current_has_perm(p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_setioprio(struct task_struct *p, int ioprio)
@@ -3279,12 +3393,12 @@
 	if (rc)
 		return rc;
 
-	return task_has_perm(current, p, PROCESS__SETSCHED);
+	return current_has_perm(p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_getioprio(struct task_struct *p)
 {
-	return task_has_perm(current, p, PROCESS__GETSCHED);
+	return current_has_perm(p, PROCESS__GETSCHED);
 }
 
 static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
@@ -3299,9 +3413,9 @@
 	/* Control the ability to change the hard limit (whether
 	   lowering or raising it), so that the hard limit can
 	   later be used as a safe reset point for the soft limit
-	   upon context transitions. See selinux_bprm_apply_creds. */
+	   upon context transitions.  See selinux_bprm_committing_creds. */
 	if (old_rlim->rlim_max != new_rlim->rlim_max)
-		return task_has_perm(current, current, PROCESS__SETRLIMIT);
+		return current_has_perm(current, PROCESS__SETRLIMIT);
 
 	return 0;
 }
@@ -3314,17 +3428,17 @@
 	if (rc)
 		return rc;
 
-	return task_has_perm(current, p, PROCESS__SETSCHED);
+	return current_has_perm(p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_getscheduler(struct task_struct *p)
 {
-	return task_has_perm(current, p, PROCESS__GETSCHED);
+	return current_has_perm(p, PROCESS__GETSCHED);
 }
 
 static int selinux_task_movememory(struct task_struct *p)
 {
-	return task_has_perm(current, p, PROCESS__SETSCHED);
+	return current_has_perm(p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
@@ -3332,7 +3446,6 @@
 {
 	u32 perm;
 	int rc;
-	struct task_security_struct *tsec;
 
 	rc = secondary_ops->task_kill(p, info, sig, secid);
 	if (rc)
@@ -3342,11 +3455,11 @@
 		perm = PROCESS__SIGNULL; /* null signal; existence test */
 	else
 		perm = signal_to_av(sig);
-	tsec = p->security;
 	if (secid)
-		rc = avc_has_perm(secid, tsec->sid, SECCLASS_PROCESS, perm, NULL);
+		rc = avc_has_perm(secid, task_sid(p),
+				  SECCLASS_PROCESS, perm, NULL);
 	else
-		rc = task_has_perm(current, p, perm);
+		rc = current_has_perm(p, perm);
 	return rc;
 }
 
@@ -3354,13 +3467,12 @@
 			      unsigned long arg2,
 			      unsigned long arg3,
 			      unsigned long arg4,
-			      unsigned long arg5,
-			      long *rc_p)
+			      unsigned long arg5)
 {
 	/* The current prctl operations do not appear to require
 	   any SELinux controls since they merely observe or modify
 	   the state of the current process. */
-	return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
+	return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
 }
 
 static int selinux_task_wait(struct task_struct *p)
@@ -3368,27 +3480,14 @@
 	return task_has_perm(p, current, PROCESS__SIGCHLD);
 }
 
-static void selinux_task_reparent_to_init(struct task_struct *p)
-{
-	struct task_security_struct *tsec;
-
-	secondary_ops->task_reparent_to_init(p);
-
-	tsec = p->security;
-	tsec->osid = tsec->sid;
-	tsec->sid = SECINITSID_KERNEL;
-	return;
-}
-
 static void selinux_task_to_inode(struct task_struct *p,
 				  struct inode *inode)
 {
-	struct task_security_struct *tsec = p->security;
 	struct inode_security_struct *isec = inode->i_security;
+	u32 sid = task_sid(p);
 
-	isec->sid = tsec->sid;
+	isec->sid = sid;
 	isec->initialized = 1;
-	return;
 }
 
 /* Returns error only if unable to parse addresses */
@@ -3627,19 +3726,19 @@
 			   u32 perms)
 {
 	struct inode_security_struct *isec;
-	struct task_security_struct *tsec;
 	struct avc_audit_data ad;
+	u32 sid;
 	int err = 0;
 
-	tsec = task->security;
 	isec = SOCK_INODE(sock)->i_security;
 
 	if (isec->sid == SECINITSID_KERNEL)
 		goto out;
+	sid = task_sid(task);
 
 	AVC_AUDIT_DATA_INIT(&ad, NET);
 	ad.u.net.sk = sock->sk;
-	err = avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
+	err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
 
 out:
 	return err;
@@ -3648,18 +3747,20 @@
 static int selinux_socket_create(int family, int type,
 				 int protocol, int kern)
 {
+	const struct cred *cred = current_cred();
+	const struct task_security_struct *tsec = cred->security;
+	u32 sid, newsid;
+	u16 secclass;
 	int err = 0;
-	struct task_security_struct *tsec;
-	u32 newsid;
 
 	if (kern)
 		goto out;
 
-	tsec = current->security;
-	newsid = tsec->sockcreate_sid ? : tsec->sid;
-	err = avc_has_perm(tsec->sid, newsid,
-			   socket_type_to_security_class(family, type,
-			   protocol), SOCKET__CREATE, NULL);
+	sid = tsec->sid;
+	newsid = tsec->sockcreate_sid ?: sid;
+
+	secclass = socket_type_to_security_class(family, type, protocol);
+	err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
 
 out:
 	return err;
@@ -3668,18 +3769,26 @@
 static int selinux_socket_post_create(struct socket *sock, int family,
 				      int type, int protocol, int kern)
 {
-	int err = 0;
+	const struct cred *cred = current_cred();
+	const struct task_security_struct *tsec = cred->security;
 	struct inode_security_struct *isec;
-	struct task_security_struct *tsec;
 	struct sk_security_struct *sksec;
-	u32 newsid;
+	u32 sid, newsid;
+	int err = 0;
+
+	sid = tsec->sid;
+	newsid = tsec->sockcreate_sid;
 
 	isec = SOCK_INODE(sock)->i_security;
 
-	tsec = current->security;
-	newsid = tsec->sockcreate_sid ? : tsec->sid;
+	if (kern)
+		isec->sid = SECINITSID_KERNEL;
+	else if (newsid)
+		isec->sid = newsid;
+	else
+		isec->sid = sid;
+
 	isec->sclass = socket_type_to_security_class(family, type, protocol);
-	isec->sid = kern ? SECINITSID_KERNEL : newsid;
 	isec->initialized = 1;
 
 	if (sock->sk) {
@@ -3714,7 +3823,6 @@
 	if (family == PF_INET || family == PF_INET6) {
 		char *addrp;
 		struct inode_security_struct *isec;
-		struct task_security_struct *tsec;
 		struct avc_audit_data ad;
 		struct sockaddr_in *addr4 = NULL;
 		struct sockaddr_in6 *addr6 = NULL;
@@ -3722,7 +3830,6 @@
 		struct sock *sk = sock->sk;
 		u32 sid, node_perm;
 
-		tsec = current->security;
 		isec = SOCK_INODE(sock)->i_security;
 
 		if (family == PF_INET) {
@@ -4387,7 +4494,7 @@
 				  "SELinux:  unrecognized netlink message"
 				  " type=%hu for sclass=%hu\n",
 				  nlh->nlmsg_type, isec->sclass);
-			if (!selinux_enforcing)
+			if (!selinux_enforcing || security_get_allow_unknown())
 				err = 0;
 		}
 
@@ -4628,7 +4735,7 @@
 	 * as fast and as clean as possible. */
 	if (selinux_compat_net || !selinux_policycap_netpeer)
 		return selinux_ip_postroute_compat(skb, ifindex, family);
-
+#ifdef CONFIG_XFRM
 	/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
 	 * packet transformation so allow the packet to pass without any checks
 	 * since we'll have another chance to perform access control checks
@@ -4637,7 +4744,7 @@
 	 *       is NULL, in this case go ahead and apply access control. */
 	if (skb->dst != NULL && skb->dst->xfrm != NULL)
 		return NF_ACCEPT;
-
+#endif
 	secmark_active = selinux_secmark_enabled();
 	peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
 	if (!secmark_active && !peerlbl_active)
@@ -4763,15 +4870,16 @@
 			      struct kern_ipc_perm *perm,
 			      u16 sclass)
 {
-	struct task_security_struct *tsec = task->security;
 	struct ipc_security_struct *isec;
+	u32 sid;
 
 	isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
 	if (!isec)
 		return -ENOMEM;
 
+	sid = task_sid(task);
 	isec->sclass = sclass;
-	isec->sid = tsec->sid;
+	isec->sid = sid;
 	perm->security = isec;
 
 	return 0;
@@ -4809,17 +4917,16 @@
 static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
 			u32 perms)
 {
-	struct task_security_struct *tsec;
 	struct ipc_security_struct *isec;
 	struct avc_audit_data ad;
+	u32 sid = current_sid();
 
-	tsec = current->security;
 	isec = ipc_perms->security;
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = ipc_perms->key;
 
-	return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
+	return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
 }
 
 static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
@@ -4835,22 +4942,21 @@
 /* message queue security operations */
 static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
 {
-	struct task_security_struct *tsec;
 	struct ipc_security_struct *isec;
 	struct avc_audit_data ad;
+	u32 sid = current_sid();
 	int rc;
 
 	rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
 	if (rc)
 		return rc;
 
-	tsec = current->security;
 	isec = msq->q_perm.security;
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = msq->q_perm.key;
 
-	rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
+	rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
 			  MSGQ__CREATE, &ad);
 	if (rc) {
 		ipc_free_security(&msq->q_perm);
@@ -4866,17 +4972,16 @@
 
 static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
 {
-	struct task_security_struct *tsec;
 	struct ipc_security_struct *isec;
 	struct avc_audit_data ad;
+	u32 sid = current_sid();
 
-	tsec = current->security;
 	isec = msq->q_perm.security;
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = msq->q_perm.key;
 
-	return avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
+	return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
 			    MSGQ__ASSOCIATE, &ad);
 }
 
@@ -4910,13 +5015,12 @@
 
 static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
 {
-	struct task_security_struct *tsec;
 	struct ipc_security_struct *isec;
 	struct msg_security_struct *msec;
 	struct avc_audit_data ad;
+	u32 sid = current_sid();
 	int rc;
 
-	tsec = current->security;
 	isec = msq->q_perm.security;
 	msec = msg->security;
 
@@ -4928,9 +5032,7 @@
 		 * Compute new sid based on current process and
 		 * message queue this message will be stored in
 		 */
-		rc = security_transition_sid(tsec->sid,
-					     isec->sid,
-					     SECCLASS_MSG,
+		rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
 					     &msec->sid);
 		if (rc)
 			return rc;
@@ -4940,16 +5042,16 @@
 	ad.u.ipc_id = msq->q_perm.key;
 
 	/* Can this process write to the queue? */
-	rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
+	rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
 			  MSGQ__WRITE, &ad);
 	if (!rc)
 		/* Can this process send the message */
-		rc = avc_has_perm(tsec->sid, msec->sid,
-				  SECCLASS_MSG, MSG__SEND, &ad);
+		rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
+				  MSG__SEND, &ad);
 	if (!rc)
 		/* Can the message be put in the queue? */
-		rc = avc_has_perm(msec->sid, isec->sid,
-				  SECCLASS_MSGQ, MSGQ__ENQUEUE, &ad);
+		rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
+				  MSGQ__ENQUEUE, &ad);
 
 	return rc;
 }
@@ -4958,23 +5060,22 @@
 				    struct task_struct *target,
 				    long type, int mode)
 {
-	struct task_security_struct *tsec;
 	struct ipc_security_struct *isec;
 	struct msg_security_struct *msec;
 	struct avc_audit_data ad;
+	u32 sid = task_sid(target);
 	int rc;
 
-	tsec = target->security;
 	isec = msq->q_perm.security;
 	msec = msg->security;
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = msq->q_perm.key;
 
-	rc = avc_has_perm(tsec->sid, isec->sid,
+	rc = avc_has_perm(sid, isec->sid,
 			  SECCLASS_MSGQ, MSGQ__READ, &ad);
 	if (!rc)
-		rc = avc_has_perm(tsec->sid, msec->sid,
+		rc = avc_has_perm(sid, msec->sid,
 				  SECCLASS_MSG, MSG__RECEIVE, &ad);
 	return rc;
 }
@@ -4982,22 +5083,21 @@
 /* Shared Memory security operations */
 static int selinux_shm_alloc_security(struct shmid_kernel *shp)
 {
-	struct task_security_struct *tsec;
 	struct ipc_security_struct *isec;
 	struct avc_audit_data ad;
+	u32 sid = current_sid();
 	int rc;
 
 	rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
 	if (rc)
 		return rc;
 
-	tsec = current->security;
 	isec = shp->shm_perm.security;
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = shp->shm_perm.key;
 
-	rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
+	rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
 			  SHM__CREATE, &ad);
 	if (rc) {
 		ipc_free_security(&shp->shm_perm);
@@ -5013,17 +5113,16 @@
 
 static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
 {
-	struct task_security_struct *tsec;
 	struct ipc_security_struct *isec;
 	struct avc_audit_data ad;
+	u32 sid = current_sid();
 
-	tsec = current->security;
 	isec = shp->shm_perm.security;
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = shp->shm_perm.key;
 
-	return avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
+	return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
 			    SHM__ASSOCIATE, &ad);
 }
 
@@ -5081,22 +5180,21 @@
 /* Semaphore security operations */
 static int selinux_sem_alloc_security(struct sem_array *sma)
 {
-	struct task_security_struct *tsec;
 	struct ipc_security_struct *isec;
 	struct avc_audit_data ad;
+	u32 sid = current_sid();
 	int rc;
 
 	rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
 	if (rc)
 		return rc;
 
-	tsec = current->security;
 	isec = sma->sem_perm.security;
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = sma->sem_perm.key;
 
-	rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
+	rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
 			  SEM__CREATE, &ad);
 	if (rc) {
 		ipc_free_security(&sma->sem_perm);
@@ -5112,17 +5210,16 @@
 
 static int selinux_sem_associate(struct sem_array *sma, int semflg)
 {
-	struct task_security_struct *tsec;
 	struct ipc_security_struct *isec;
 	struct avc_audit_data ad;
+	u32 sid = current_sid();
 
-	tsec = current->security;
 	isec = sma->sem_perm.security;
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = sma->sem_perm.key;
 
-	return avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
+	return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
 			    SEM__ASSOCIATE, &ad);
 }
 
@@ -5212,33 +5309,35 @@
 static int selinux_getprocattr(struct task_struct *p,
 			       char *name, char **value)
 {
-	struct task_security_struct *tsec;
+	const struct task_security_struct *__tsec;
 	u32 sid;
 	int error;
 	unsigned len;
 
 	if (current != p) {
-		error = task_has_perm(current, p, PROCESS__GETATTR);
+		error = current_has_perm(p, PROCESS__GETATTR);
 		if (error)
 			return error;
 	}
 
-	tsec = p->security;
+	rcu_read_lock();
+	__tsec = __task_cred(p)->security;
 
 	if (!strcmp(name, "current"))
-		sid = tsec->sid;
+		sid = __tsec->sid;
 	else if (!strcmp(name, "prev"))
-		sid = tsec->osid;
+		sid = __tsec->osid;
 	else if (!strcmp(name, "exec"))
-		sid = tsec->exec_sid;
+		sid = __tsec->exec_sid;
 	else if (!strcmp(name, "fscreate"))
-		sid = tsec->create_sid;
+		sid = __tsec->create_sid;
 	else if (!strcmp(name, "keycreate"))
-		sid = tsec->keycreate_sid;
+		sid = __tsec->keycreate_sid;
 	else if (!strcmp(name, "sockcreate"))
-		sid = tsec->sockcreate_sid;
+		sid = __tsec->sockcreate_sid;
 	else
-		return -EINVAL;
+		goto invalid;
+	rcu_read_unlock();
 
 	if (!sid)
 		return 0;
@@ -5247,6 +5346,10 @@
 	if (error)
 		return error;
 	return len;
+
+invalid:
+	rcu_read_unlock();
+	return -EINVAL;
 }
 
 static int selinux_setprocattr(struct task_struct *p,
@@ -5254,7 +5357,8 @@
 {
 	struct task_security_struct *tsec;
 	struct task_struct *tracer;
-	u32 sid = 0;
+	struct cred *new;
+	u32 sid = 0, ptsid;
 	int error;
 	char *str = value;
 
@@ -5270,15 +5374,15 @@
 	 * above restriction is ever removed.
 	 */
 	if (!strcmp(name, "exec"))
-		error = task_has_perm(current, p, PROCESS__SETEXEC);
+		error = current_has_perm(p, PROCESS__SETEXEC);
 	else if (!strcmp(name, "fscreate"))
-		error = task_has_perm(current, p, PROCESS__SETFSCREATE);
+		error = current_has_perm(p, PROCESS__SETFSCREATE);
 	else if (!strcmp(name, "keycreate"))
-		error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
+		error = current_has_perm(p, PROCESS__SETKEYCREATE);
 	else if (!strcmp(name, "sockcreate"))
-		error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
+		error = current_has_perm(p, PROCESS__SETSOCKCREATE);
 	else if (!strcmp(name, "current"))
-		error = task_has_perm(current, p, PROCESS__SETCURRENT);
+		error = current_has_perm(p, PROCESS__SETCURRENT);
 	else
 		error = -EINVAL;
 	if (error)
@@ -5301,87 +5405,75 @@
 			return error;
 	}
 
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+
 	/* Permission checking based on the specified context is
 	   performed during the actual operation (execve,
 	   open/mkdir/...), when we know the full context of the
-	   operation.  See selinux_bprm_set_security for the execve
+	   operation.  See selinux_bprm_set_creds for the execve
 	   checks and may_create for the file creation checks. The
 	   operation will then fail if the context is not permitted. */
-	tsec = p->security;
-	if (!strcmp(name, "exec"))
+	tsec = new->security;
+	if (!strcmp(name, "exec")) {
 		tsec->exec_sid = sid;
-	else if (!strcmp(name, "fscreate"))
+	} else if (!strcmp(name, "fscreate")) {
 		tsec->create_sid = sid;
-	else if (!strcmp(name, "keycreate")) {
+	} else if (!strcmp(name, "keycreate")) {
 		error = may_create_key(sid, p);
 		if (error)
-			return error;
+			goto abort_change;
 		tsec->keycreate_sid = sid;
-	} else if (!strcmp(name, "sockcreate"))
+	} else if (!strcmp(name, "sockcreate")) {
 		tsec->sockcreate_sid = sid;
-	else if (!strcmp(name, "current")) {
-		struct av_decision avd;
-
+	} else if (!strcmp(name, "current")) {
+		error = -EINVAL;
 		if (sid == 0)
-			return -EINVAL;
-		/*
-		 * SELinux allows to change context in the following case only.
-		 *  - Single threaded processes.
-		 *  - Multi threaded processes intend to change its context into
-		 *    more restricted domain (defined by TYPEBOUNDS statement).
-		 */
-		if (atomic_read(&p->mm->mm_users) != 1) {
-			struct task_struct *g, *t;
-			struct mm_struct *mm = p->mm;
-			read_lock(&tasklist_lock);
-			do_each_thread(g, t) {
-				if (t->mm == mm && t != p) {
-					read_unlock(&tasklist_lock);
-					error = security_bounded_transition(tsec->sid, sid);
-					if (!error)
-						goto boundary_ok;
+			goto abort_change;
 
-					return error;
-				}
-			} while_each_thread(g, t);
-			read_unlock(&tasklist_lock);
+		/* Only allow single threaded processes to change context */
+		error = -EPERM;
+		if (!is_single_threaded(p)) {
+			error = security_bounded_transition(tsec->sid, sid);
+			if (error)
+				goto abort_change;
 		}
-boundary_ok:
 
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
 				     PROCESS__DYNTRANSITION, NULL);
 		if (error)
-			return error;
+			goto abort_change;
 
 		/* Check for ptracing, and update the task SID if ok.
 		   Otherwise, leave SID unchanged and fail. */
+		ptsid = 0;
 		task_lock(p);
-		rcu_read_lock();
 		tracer = tracehook_tracer_task(p);
-		if (tracer != NULL) {
-			struct task_security_struct *ptsec = tracer->security;
-			u32 ptsid = ptsec->sid;
-			rcu_read_unlock();
-			error = avc_has_perm_noaudit(ptsid, sid,
-						     SECCLASS_PROCESS,
-						     PROCESS__PTRACE, 0, &avd);
-			if (!error)
-				tsec->sid = sid;
-			task_unlock(p);
-			avc_audit(ptsid, sid, SECCLASS_PROCESS,
-				  PROCESS__PTRACE, &avd, error, NULL);
-			if (error)
-				return error;
-		} else {
-			rcu_read_unlock();
-			tsec->sid = sid;
-			task_unlock(p);
-		}
-	} else
-		return -EINVAL;
+		if (tracer)
+			ptsid = task_sid(tracer);
+		task_unlock(p);
 
+		if (tracer) {
+			error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
+					     PROCESS__PTRACE, NULL);
+			if (error)
+				goto abort_change;
+		}
+
+		tsec->sid = sid;
+	} else {
+		error = -EINVAL;
+		goto abort_change;
+	}
+
+	commit_creds(new);
 	return size;
+
+abort_change:
+	abort_creds(new);
+	return error;
 }
 
 static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
@@ -5401,22 +5493,23 @@
 
 #ifdef CONFIG_KEYS
 
-static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
+static int selinux_key_alloc(struct key *k, const struct cred *cred,
 			     unsigned long flags)
 {
-	struct task_security_struct *tsec = tsk->security;
+	const struct task_security_struct *tsec;
 	struct key_security_struct *ksec;
 
 	ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
 	if (!ksec)
 		return -ENOMEM;
 
+	tsec = cred->security;
 	if (tsec->keycreate_sid)
 		ksec->sid = tsec->keycreate_sid;
 	else
 		ksec->sid = tsec->sid;
-	k->security = ksec;
 
+	k->security = ksec;
 	return 0;
 }
 
@@ -5429,17 +5522,12 @@
 }
 
 static int selinux_key_permission(key_ref_t key_ref,
-			    struct task_struct *ctx,
-			    key_perm_t perm)
+				  const struct cred *cred,
+				  key_perm_t perm)
 {
 	struct key *key;
-	struct task_security_struct *tsec;
 	struct key_security_struct *ksec;
-
-	key = key_ref_to_ptr(key_ref);
-
-	tsec = ctx->security;
-	ksec = key->security;
+	u32 sid;
 
 	/* if no specific permissions are requested, we skip the
 	   permission check. No serious, additional covert channels
@@ -5447,8 +5535,12 @@
 	if (perm == 0)
 		return 0;
 
-	return avc_has_perm(tsec->sid, ksec->sid,
-			    SECCLASS_KEY, perm, NULL);
+	sid = cred_sid(cred);
+
+	key = key_ref_to_ptr(key_ref);
+	ksec = key->security;
+
+	return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
 }
 
 static int selinux_key_getsecurity(struct key *key, char **_buffer)
@@ -5473,8 +5565,7 @@
 	.ptrace_may_access =		selinux_ptrace_may_access,
 	.ptrace_traceme =		selinux_ptrace_traceme,
 	.capget =			selinux_capget,
-	.capset_check =			selinux_capset_check,
-	.capset_set =			selinux_capset_set,
+	.capset =			selinux_capset,
 	.sysctl =			selinux_sysctl,
 	.capable =			selinux_capable,
 	.quotactl =			selinux_quotactl,
@@ -5485,12 +5576,10 @@
 	.netlink_send =			selinux_netlink_send,
 	.netlink_recv =			selinux_netlink_recv,
 
-	.bprm_alloc_security =		selinux_bprm_alloc_security,
-	.bprm_free_security =		selinux_bprm_free_security,
-	.bprm_apply_creds =		selinux_bprm_apply_creds,
-	.bprm_post_apply_creds =	selinux_bprm_post_apply_creds,
-	.bprm_set_security =		selinux_bprm_set_security,
+	.bprm_set_creds =		selinux_bprm_set_creds,
 	.bprm_check_security =		selinux_bprm_check_security,
+	.bprm_committing_creds =	selinux_bprm_committing_creds,
+	.bprm_committed_creds =		selinux_bprm_committed_creds,
 	.bprm_secureexec =		selinux_bprm_secureexec,
 
 	.sb_alloc_security =		selinux_sb_alloc_security,
@@ -5549,10 +5638,13 @@
 	.dentry_open =			selinux_dentry_open,
 
 	.task_create =			selinux_task_create,
-	.task_alloc_security =		selinux_task_alloc_security,
-	.task_free_security =		selinux_task_free_security,
+	.cred_free =			selinux_cred_free,
+	.cred_prepare =			selinux_cred_prepare,
+	.cred_commit =			selinux_cred_commit,
+	.kernel_act_as =		selinux_kernel_act_as,
+	.kernel_create_files_as =	selinux_kernel_create_files_as,
 	.task_setuid =			selinux_task_setuid,
-	.task_post_setuid =		selinux_task_post_setuid,
+	.task_fix_setuid =		selinux_task_fix_setuid,
 	.task_setgid =			selinux_task_setgid,
 	.task_setpgid =			selinux_task_setpgid,
 	.task_getpgid =			selinux_task_getpgid,
@@ -5569,7 +5661,6 @@
 	.task_kill =			selinux_task_kill,
 	.task_wait =			selinux_task_wait,
 	.task_prctl =			selinux_task_prctl,
-	.task_reparent_to_init =	selinux_task_reparent_to_init,
 	.task_to_inode =		selinux_task_to_inode,
 
 	.ipc_permission =		selinux_ipc_permission,
@@ -5665,8 +5756,6 @@
 
 static __init int selinux_init(void)
 {
-	struct task_security_struct *tsec;
-
 	if (!security_module_enable(&selinux_ops)) {
 		selinux_enabled = 0;
 		return 0;
@@ -5680,10 +5769,7 @@
 	printk(KERN_INFO "SELinux:  Initializing.\n");
 
 	/* Set the security state for the initial task. */
-	if (task_alloc_security(current))
-		panic("SELinux:  Failed to initialize initial task.\n");
-	tsec = current->security;
-	tsec->osid = tsec->sid = SECINITSID_KERNEL;
+	cred_init_security();
 
 	sel_inode_cache = kmem_cache_create("selinux_inode_security",
 					    sizeof(struct inode_security_struct),
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index 1223b4f..c0c8854 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -176,3 +176,5 @@
    S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect")
    S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero")
    S_(SECCLASS_PEER, PEER__RECV, "recv")
+   S_(SECCLASS_KERNEL_SERVICE, KERNEL_SERVICE__USE_AS_OVERRIDE, "use_as_override")
+   S_(SECCLASS_KERNEL_SERVICE, KERNEL_SERVICE__CREATE_FILES_AS, "create_files_as")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index c4c5116..0ba79fe 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -841,3 +841,5 @@
 #define DCCP_SOCKET__NAME_CONNECT                 0x00800000UL
 #define MEMPROTECT__MMAP_ZERO                     0x00000001UL
 #define PEER__RECV                                0x00000001UL
+#define KERNEL_SERVICE__USE_AS_OVERRIDE           0x00000001UL
+#define KERNEL_SERVICE__CREATE_FILES_AS           0x00000002UL
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h
index bd813c3..21ec786 100644
--- a/security/selinux/include/class_to_string.h
+++ b/security/selinux/include/class_to_string.h
@@ -72,3 +72,8 @@
     S_(NULL)
     S_("peer")
     S_("capability2")
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_("kernel_service")
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h
index febf886..882f27d 100644
--- a/security/selinux/include/flask.h
+++ b/security/selinux/include/flask.h
@@ -52,6 +52,7 @@
 #define SECCLASS_MEMPROTECT                              61
 #define SECCLASS_PEER                                    68
 #define SECCLASS_CAPABILITY2                             69
+#define SECCLASS_KERNEL_SERVICE                          74
 
 /*
  * Security identifier indices for initial entities
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index f8be8d7..3cc4516 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -77,17 +77,6 @@
 	u32 sid;	/* SID of IPC resource */
 };
 
-struct bprm_security_struct {
-	u32 sid;		/* SID for transformed process */
-	unsigned char set;
-
-	/*
-	 * unsafe is used to share failure information from bprm_apply_creds()
-	 * to bprm_post_apply_creds().
-	 */
-	char unsafe;
-};
-
 struct netif_security_struct {
 	int ifindex;			/* device index */
 	u32 sid;			/* SID for this interface */
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index ff59c0c..4ed7bab 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -63,6 +63,9 @@
 	{ RTM_GETANYCAST,	NETLINK_ROUTE_SOCKET__NLMSG_READ  },
 	{ RTM_GETNEIGHTBL,	NETLINK_ROUTE_SOCKET__NLMSG_READ  },
 	{ RTM_SETNEIGHTBL,	NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_NEWADDRLABEL,	NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_DELADDRLABEL,	NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+	{ RTM_GETADDRLABEL,	NETLINK_ROUTE_SOCKET__NLMSG_READ  },
 };
 
 static struct nlmsg_perm nlmsg_firewall_perms[] =
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 69c9dcc..c863036 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -95,13 +95,18 @@
 static int task_has_security(struct task_struct *tsk,
 			     u32 perms)
 {
-	struct task_security_struct *tsec;
+	const struct task_security_struct *tsec;
+	u32 sid = 0;
 
-	tsec = tsk->security;
+	rcu_read_lock();
+	tsec = __task_cred(tsk)->security;
+	if (tsec)
+		sid = tsec->sid;
+	rcu_read_unlock();
 	if (!tsec)
 		return -EACCES;
 
-	return avc_has_perm(tsec->sid, SECINITSID_SECURITY,
+	return avc_has_perm(sid, SECINITSID_SECURITY,
 			    SECCLASS_SECURITY, perms, NULL);
 }
 
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 8f17f54..c0eb720 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -197,7 +197,7 @@
 	struct xfrm_user_sec_ctx *uctx, u32 sid)
 {
 	int rc = 0;
-	struct task_security_struct *tsec = current->security;
+	const struct task_security_struct *tsec = current_security();
 	struct xfrm_sec_ctx *ctx = NULL;
 	char *ctx_str = NULL;
 	u32 str_len;
@@ -333,7 +333,7 @@
  */
 int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
 {
-	struct task_security_struct *tsec = current->security;
+	const struct task_security_struct *tsec = current_security();
 	int rc = 0;
 
 	if (ctx) {
@@ -378,7 +378,7 @@
   */
 int selinux_xfrm_state_delete(struct xfrm_state *x)
 {
-	struct task_security_struct *tsec = current->security;
+	const struct task_security_struct *tsec = current_security();
 	struct xfrm_sec_ctx *ctx = x->security;
 	int rc = 0;
 
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 79ff21e..247cec3 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -164,7 +164,7 @@
 {
 	int rc;
 
-	rc = smk_access(current->security, obj_label, mode);
+	rc = smk_access(current_security(), obj_label, mode);
 	if (rc == 0)
 		return 0;
 
@@ -173,7 +173,7 @@
 	 * only one that gets privilege and current does not
 	 * have that label.
 	 */
-	if (smack_onlycap != NULL && smack_onlycap != current->security)
+	if (smack_onlycap != NULL && smack_onlycap != current->cred->security)
 		return rc;
 
 	if (capable(CAP_MAC_OVERRIDE))
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 6e2dc0b..1b5551d 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -30,6 +30,8 @@
 
 #include "smack.h"
 
+#define task_security(task)	(task_cred_xxx((task), security))
+
 /*
  * I hope these are the hokeyist lines of code in the module. Casey.
  */
@@ -102,7 +104,7 @@
 	if (rc != 0)
 		return rc;
 
-	rc = smk_access(current->security, ctp->security, MAY_READWRITE);
+	rc = smk_access(current_security(), task_security(ctp), MAY_READWRITE);
 	if (rc != 0 && capable(CAP_MAC_OVERRIDE))
 		return 0;
 	return rc;
@@ -124,7 +126,7 @@
 	if (rc != 0)
 		return rc;
 
-	rc = smk_access(ptp->security, current->security, MAY_READWRITE);
+	rc = smk_access(task_security(ptp), current_security(), MAY_READWRITE);
 	if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE))
 		return 0;
 	return rc;
@@ -141,7 +143,7 @@
 static int smack_syslog(int type)
 {
 	int rc;
-	char *sp = current->security;
+	char *sp = current_security();
 
 	rc = cap_syslog(type);
 	if (rc != 0)
@@ -248,11 +250,12 @@
 /**
  * smack_sb_kern_mount - Smack specific mount processing
  * @sb: the file system superblock
+ * @flags: the mount flags
  * @data: the smack mount options
  *
  * Returns 0 on success, an error code on failure
  */
-static int smack_sb_kern_mount(struct super_block *sb, void *data)
+static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
 {
 	struct dentry *root = sb->s_root;
 	struct inode *inode = root->d_inode;
@@ -373,7 +376,7 @@
  */
 static int smack_inode_alloc_security(struct inode *inode)
 {
-	inode->i_security = new_inode_smack(current->security);
+	inode->i_security = new_inode_smack(current_security());
 	if (inode->i_security == NULL)
 		return -ENOMEM;
 	return 0;
@@ -818,7 +821,7 @@
  */
 static int smack_file_alloc_security(struct file *file)
 {
-	file->f_security = current->security;
+	file->f_security = current_security();
 	return 0;
 }
 
@@ -916,7 +919,7 @@
  */
 static int smack_file_set_fowner(struct file *file)
 {
-	file->f_security = current->security;
+	file->f_security = current_security();
 	return 0;
 }
 
@@ -941,7 +944,7 @@
 	 * struct fown_struct is never outside the context of a struct file
 	 */
 	file = container_of(fown, struct file, f_owner);
-	rc = smk_access(file->f_security, tsk->security, MAY_WRITE);
+	rc = smk_access(file->f_security, tsk->cred->security, MAY_WRITE);
 	if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
 		return 0;
 	return rc;
@@ -973,33 +976,75 @@
  */
 
 /**
- * smack_task_alloc_security - "allocate" a task blob
- * @tsk: the task in need of a blob
- *
- * Smack isn't using copies of blobs. Everyone
- * points to an immutable list. No alloc required.
- * No data copy required.
- *
- * Always returns 0
- */
-static int smack_task_alloc_security(struct task_struct *tsk)
-{
-	tsk->security = current->security;
-
-	return 0;
-}
-
-/**
- * smack_task_free_security - "free" a task blob
- * @task: the task with the blob
+ * smack_cred_free - "free" task-level security credentials
+ * @cred: the credentials in question
  *
  * Smack isn't using copies of blobs. Everyone
  * points to an immutable list. The blobs never go away.
  * There is no leak here.
  */
-static void smack_task_free_security(struct task_struct *task)
+static void smack_cred_free(struct cred *cred)
 {
-	task->security = NULL;
+	cred->security = NULL;
+}
+
+/**
+ * smack_cred_prepare - prepare new set of credentials for modification
+ * @new: the new credentials
+ * @old: the original credentials
+ * @gfp: the atomicity of any memory allocations
+ *
+ * Prepare a new set of credentials for modification.
+ */
+static int smack_cred_prepare(struct cred *new, const struct cred *old,
+			      gfp_t gfp)
+{
+	new->security = old->security;
+	return 0;
+}
+
+/*
+ * commit new credentials
+ * @new: the new credentials
+ * @old: the original credentials
+ */
+static void smack_cred_commit(struct cred *new, const struct cred *old)
+{
+}
+
+/**
+ * smack_kernel_act_as - Set the subjective context in a set of credentials
+ * @new points to the set of credentials to be modified.
+ * @secid specifies the security ID to be set
+ *
+ * Set the security data for a kernel service.
+ */
+static int smack_kernel_act_as(struct cred *new, u32 secid)
+{
+	char *smack = smack_from_secid(secid);
+
+	if (smack == NULL)
+		return -EINVAL;
+
+	new->security = smack;
+	return 0;
+}
+
+/**
+ * smack_kernel_create_files_as - Set the file creation label in a set of creds
+ * @new points to the set of credentials to be modified
+ * @inode points to the inode to use as a reference
+ *
+ * Set the file creation context in a set of credentials to the same
+ * as the objective context of the specified inode
+ */
+static int smack_kernel_create_files_as(struct cred *new,
+					struct inode *inode)
+{
+	struct inode_smack *isp = inode->i_security;
+
+	new->security = isp->smk_inode;
+	return 0;
 }
 
 /**
@@ -1011,7 +1056,7 @@
  */
 static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
 {
-	return smk_curacc(p->security, MAY_WRITE);
+	return smk_curacc(task_security(p), MAY_WRITE);
 }
 
 /**
@@ -1022,7 +1067,7 @@
  */
 static int smack_task_getpgid(struct task_struct *p)
 {
-	return smk_curacc(p->security, MAY_READ);
+	return smk_curacc(task_security(p), MAY_READ);
 }
 
 /**
@@ -1033,7 +1078,7 @@
  */
 static int smack_task_getsid(struct task_struct *p)
 {
-	return smk_curacc(p->security, MAY_READ);
+	return smk_curacc(task_security(p), MAY_READ);
 }
 
 /**
@@ -1045,7 +1090,7 @@
  */
 static void smack_task_getsecid(struct task_struct *p, u32 *secid)
 {
-	*secid = smack_to_secid(p->security);
+	*secid = smack_to_secid(task_security(p));
 }
 
 /**
@@ -1061,7 +1106,7 @@
 
 	rc = cap_task_setnice(p, nice);
 	if (rc == 0)
-		rc = smk_curacc(p->security, MAY_WRITE);
+		rc = smk_curacc(task_security(p), MAY_WRITE);
 	return rc;
 }
 
@@ -1078,7 +1123,7 @@
 
 	rc = cap_task_setioprio(p, ioprio);
 	if (rc == 0)
-		rc = smk_curacc(p->security, MAY_WRITE);
+		rc = smk_curacc(task_security(p), MAY_WRITE);
 	return rc;
 }
 
@@ -1090,7 +1135,7 @@
  */
 static int smack_task_getioprio(struct task_struct *p)
 {
-	return smk_curacc(p->security, MAY_READ);
+	return smk_curacc(task_security(p), MAY_READ);
 }
 
 /**
@@ -1108,7 +1153,7 @@
 
 	rc = cap_task_setscheduler(p, policy, lp);
 	if (rc == 0)
-		rc = smk_curacc(p->security, MAY_WRITE);
+		rc = smk_curacc(task_security(p), MAY_WRITE);
 	return rc;
 }
 
@@ -1120,7 +1165,7 @@
  */
 static int smack_task_getscheduler(struct task_struct *p)
 {
-	return smk_curacc(p->security, MAY_READ);
+	return smk_curacc(task_security(p), MAY_READ);
 }
 
 /**
@@ -1131,7 +1176,7 @@
  */
 static int smack_task_movememory(struct task_struct *p)
 {
-	return smk_curacc(p->security, MAY_WRITE);
+	return smk_curacc(task_security(p), MAY_WRITE);
 }
 
 /**
@@ -1154,13 +1199,13 @@
 	 * can write the receiver.
 	 */
 	if (secid == 0)
-		return smk_curacc(p->security, MAY_WRITE);
+		return smk_curacc(task_security(p), MAY_WRITE);
 	/*
 	 * If the secid isn't 0 we're dealing with some USB IO
 	 * specific behavior. This is not clean. For one thing
 	 * we can't take privilege into account.
 	 */
-	return smk_access(smack_from_secid(secid), p->security, MAY_WRITE);
+	return smk_access(smack_from_secid(secid), task_security(p), MAY_WRITE);
 }
 
 /**
@@ -1173,7 +1218,7 @@
 {
 	int rc;
 
-	rc = smk_access(current->security, p->security, MAY_WRITE);
+	rc = smk_access(current_security(), task_security(p), MAY_WRITE);
 	if (rc == 0)
 		return 0;
 
@@ -1204,7 +1249,7 @@
 static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
 {
 	struct inode_smack *isp = inode->i_security;
-	isp->smk_inode = p->security;
+	isp->smk_inode = task_security(p);
 }
 
 /*
@@ -1223,7 +1268,7 @@
  */
 static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
 {
-	char *csp = current->security;
+	char *csp = current_security();
 	struct socket_smack *ssp;
 
 	ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
@@ -1448,7 +1493,7 @@
  */
 static int smack_msg_msg_alloc_security(struct msg_msg *msg)
 {
-	msg->security = current->security;
+	msg->security = current_security();
 	return 0;
 }
 
@@ -1484,7 +1529,7 @@
 {
 	struct kern_ipc_perm *isp = &shp->shm_perm;
 
-	isp->security = current->security;
+	isp->security = current_security();
 	return 0;
 }
 
@@ -1593,7 +1638,7 @@
 {
 	struct kern_ipc_perm *isp = &sma->sem_perm;
 
-	isp->security = current->security;
+	isp->security = current_security();
 	return 0;
 }
 
@@ -1697,7 +1742,7 @@
 {
 	struct kern_ipc_perm *kisp = &msq->q_perm;
 
-	kisp->security = current->security;
+	kisp->security = current_security();
 	return 0;
 }
 
@@ -1852,7 +1897,7 @@
 	struct super_block *sbp;
 	struct superblock_smack *sbsp;
 	struct inode_smack *isp;
-	char *csp = current->security;
+	char *csp = current_security();
 	char *fetched;
 	char *final;
 	struct dentry *dp;
@@ -2009,7 +2054,7 @@
 	if (strcmp(name, "current") != 0)
 		return -EINVAL;
 
-	cp = kstrdup(p->security, GFP_KERNEL);
+	cp = kstrdup(task_security(p), GFP_KERNEL);
 	if (cp == NULL)
 		return -ENOMEM;
 
@@ -2033,6 +2078,7 @@
 static int smack_setprocattr(struct task_struct *p, char *name,
 			     void *value, size_t size)
 {
+	struct cred *new;
 	char *newsmack;
 
 	/*
@@ -2055,7 +2101,11 @@
 	if (newsmack == NULL)
 		return -EINVAL;
 
-	p->security = newsmack;
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
+	new->security = newsmack;
+	commit_creds(new);
 	return size;
 }
 
@@ -2288,8 +2338,7 @@
 		return;
 
 	ssp = sk->sk_security;
-	ssp->smk_in = current->security;
-	ssp->smk_out = current->security;
+	ssp->smk_in = ssp->smk_out = current_security();
 	ssp->smk_packet[0] = '\0';
 
 	rc = smack_netlabel(sk);
@@ -2352,17 +2401,17 @@
 /**
  * smack_key_alloc - Set the key security blob
  * @key: object
- * @tsk: the task associated with the key
+ * @cred: the credentials to use
  * @flags: unused
  *
  * No allocation required
  *
  * Returns 0
  */
-static int smack_key_alloc(struct key *key, struct task_struct *tsk,
+static int smack_key_alloc(struct key *key, const struct cred *cred,
 			   unsigned long flags)
 {
-	key->security = tsk->security;
+	key->security = cred->security;
 	return 0;
 }
 
@@ -2380,14 +2429,14 @@
 /*
  * smack_key_permission - Smack access on a key
  * @key_ref: gets to the object
- * @context: task involved
+ * @cred: the credentials to use
  * @perm: unused
  *
  * Return 0 if the task has read and write to the object,
  * an error code otherwise
  */
 static int smack_key_permission(key_ref_t key_ref,
-				struct task_struct *context, key_perm_t perm)
+				const struct cred *cred, key_perm_t perm)
 {
 	struct key *keyp;
 
@@ -2403,10 +2452,10 @@
 	/*
 	 * This should not occur
 	 */
-	if (context->security == NULL)
+	if (cred->security == NULL)
 		return -EACCES;
 
-	return smk_access(context->security, keyp->security, MAY_READWRITE);
+	return smk_access(cred->security, keyp->security, MAY_READWRITE);
 }
 #endif /* CONFIG_KEYS */
 
@@ -2577,15 +2626,13 @@
 	.ptrace_may_access =		smack_ptrace_may_access,
 	.ptrace_traceme =		smack_ptrace_traceme,
 	.capget = 			cap_capget,
-	.capset_check = 		cap_capset_check,
-	.capset_set = 			cap_capset_set,
+	.capset = 			cap_capset,
 	.capable = 			cap_capable,
 	.syslog = 			smack_syslog,
 	.settime = 			cap_settime,
 	.vm_enough_memory = 		cap_vm_enough_memory,
 
-	.bprm_apply_creds = 		cap_bprm_apply_creds,
-	.bprm_set_security = 		cap_bprm_set_security,
+	.bprm_set_creds = 		cap_bprm_set_creds,
 	.bprm_secureexec = 		cap_bprm_secureexec,
 
 	.sb_alloc_security = 		smack_sb_alloc_security,
@@ -2627,9 +2674,12 @@
 	.file_send_sigiotask = 		smack_file_send_sigiotask,
 	.file_receive = 		smack_file_receive,
 
-	.task_alloc_security = 		smack_task_alloc_security,
-	.task_free_security = 		smack_task_free_security,
-	.task_post_setuid =		cap_task_post_setuid,
+	.cred_free =			smack_cred_free,
+	.cred_prepare =			smack_cred_prepare,
+	.cred_commit =			smack_cred_commit,
+	.kernel_act_as =		smack_kernel_act_as,
+	.kernel_create_files_as =	smack_kernel_create_files_as,
+	.task_fix_setuid =		cap_task_fix_setuid,
 	.task_setpgid = 		smack_task_setpgid,
 	.task_getpgid = 		smack_task_getpgid,
 	.task_getsid = 			smack_task_getsid,
@@ -2642,7 +2692,6 @@
 	.task_movememory = 		smack_task_movememory,
 	.task_kill = 			smack_task_kill,
 	.task_wait = 			smack_task_wait,
-	.task_reparent_to_init =	cap_task_reparent_to_init,
 	.task_to_inode = 		smack_task_to_inode,
 	.task_prctl =			cap_task_prctl,
 
@@ -2718,6 +2767,8 @@
  */
 static __init int smack_init(void)
 {
+	struct cred *cred;
+
 	if (!security_module_enable(&smack_ops))
 		return 0;
 
@@ -2726,7 +2777,8 @@
 	/*
 	 * Set the security state for the initial task.
 	 */
-	current->security = &smack_known_floor.smk_known;
+	cred = (struct cred *) current->cred;
+	cred->security = &smack_known_floor.smk_known;
 
 	/*
 	 * Initialize locks
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index c21d8c8..247dc9e 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -185,11 +185,15 @@
  * the subject/object pair and replaces the access that was
  * there. If the pair isn't found add it with the specified
  * access.
+ *
+ * Returns 0 if nothing goes wrong or -ENOMEM if it fails
+ * during the allocation of the new pair to add.
  */
-static void smk_set_access(struct smack_rule *srp)
+static int smk_set_access(struct smack_rule *srp)
 {
 	struct smk_list_entry *sp;
 	struct smk_list_entry *newp;
+	int ret = 0;
 
 	mutex_lock(&smack_list_lock);
 
@@ -202,14 +206,20 @@
 
 	if (sp == NULL) {
 		newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL);
+		if (newp == NULL) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
 		newp->smk_rule = *srp;
 		newp->smk_next = smack_list;
 		smack_list = newp;
 	}
 
+out:
 	mutex_unlock(&smack_list_lock);
 
-	return;
+	return ret;
 }
 
 /**
@@ -309,8 +319,10 @@
 		goto out;
 	}
 
-	smk_set_access(&rule);
-	rc = count;
+	rc = smk_set_access(&rule);
+
+	if (!rc)
+		rc = count;
 
 out:
 	kfree(data);
@@ -336,7 +348,7 @@
 
 	audit_info.loginuid = audit_get_loginuid(current);
 	audit_info.sessionid = audit_get_sessionid(current);
-	audit_info.secid = smack_to_secid(current->security);
+	audit_info.secid = smack_to_secid(current_security());
 
 	rc = netlbl_cfg_map_del(NULL, &audit_info);
 	if (rc != 0)
@@ -371,7 +383,7 @@
 
 	audit_info.loginuid = audit_get_loginuid(current);
 	audit_info.sessionid = audit_get_sessionid(current);
-	audit_info.secid = smack_to_secid(current->security);
+	audit_info.secid = smack_to_secid(current_security());
 
 	if (oldambient != NULL) {
 		rc = netlbl_cfg_map_del(oldambient, &audit_info);
@@ -843,7 +855,7 @@
 				 size_t count, loff_t *ppos)
 {
 	char in[SMK_LABELLEN];
-	char *sp = current->security;
+	char *sp = current->cred->security;
 
 	if (!capable(CAP_MAC_ADMIN))
 		return -EPERM;
diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c
index 7fa37e1..a351dd0 100644
--- a/sound/ac97_bus.c
+++ b/sound/ac97_bus.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/string.h>
+#include <sound/ac97_codec.h>
 
 /*
  * Let drivers decide whether they want to support given codec from their
diff --git a/sound/aoa/codecs/Makefile b/sound/aoa/codecs/Makefile
index 31cbe68..c3ee77f 100644
--- a/sound/aoa/codecs/Makefile
+++ b/sound/aoa/codecs/Makefile
@@ -1,3 +1,7 @@
+snd-aoa-codec-onyx-objs := onyx.o
+snd-aoa-codec-tas-objs := tas.o
+snd-aoa-codec-toonie-objs := toonie.o
+
 obj-$(CONFIG_SND_AOA_ONYX) += snd-aoa-codec-onyx.o
 obj-$(CONFIG_SND_AOA_TAS) += snd-aoa-codec-tas.o
 obj-$(CONFIG_SND_AOA_TOONIE) += snd-aoa-codec-toonie.o
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/onyx.c
similarity index 99%
rename from sound/aoa/codecs/snd-aoa-codec-onyx.c
rename to sound/aoa/codecs/onyx.c
index 6a3837d..15500b9 100644
--- a/sound/aoa/codecs/snd-aoa-codec-onyx.c
+++ b/sound/aoa/codecs/onyx.c
@@ -37,7 +37,7 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa");
 
-#include "snd-aoa-codec-onyx.h"
+#include "onyx.h"
 #include "../aoa.h"
 #include "../soundbus/soundbus.h"
 
@@ -292,7 +292,7 @@
 static struct snd_kcontrol_new capture_source_control = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	/* If we name this 'Input Source', it properly shows up in
-	 * alsamixer as a selection, * but it's shown under the 
+	 * alsamixer as a selection, * but it's shown under the
 	 * 'Playback' category.
 	 * If I name it 'Capture Source', it shows up in strange
 	 * ways (two bools of which one can be selected at a
@@ -477,7 +477,7 @@
 
 	ucontrol->value.iec958.status[3] = 0x3f;
 	ucontrol->value.iec958.status[4] = 0x0f;
-	
+
 	return 0;
 }
 
@@ -682,7 +682,7 @@
 	onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
 	spdif_enabled = !!(v & ONYX_SPDIF_ENABLE);
 	onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
-	analog_enabled = 
+	analog_enabled =
 		(v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT))
 		 != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT);
 	mutex_unlock(&onyx->mutex);
@@ -882,7 +882,7 @@
 	msleep(1);
 	onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
 	msleep(1);
-	
+
 	if (onyx_register_init(onyx)) {
 		printk(KERN_ERR PFX "failed to initialise onyx registers\n");
 		return -ENODEV;
@@ -1069,7 +1069,7 @@
 
 	/* if that didn't work, try desperate mode for older
 	 * machines that have stuff missing from the device tree */
-	
+
 	if (!of_device_is_compatible(busnode, "k2-i2c"))
 		return -ENODEV;
 
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.h b/sound/aoa/codecs/onyx.h
similarity index 100%
rename from sound/aoa/codecs/snd-aoa-codec-onyx.h
rename to sound/aoa/codecs/onyx.h
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h b/sound/aoa/codecs/tas-basstreble.h
similarity index 100%
rename from sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h
rename to sound/aoa/codecs/tas-basstreble.h
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h b/sound/aoa/codecs/tas-gain-table.h
similarity index 100%
rename from sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h
rename to sound/aoa/codecs/tas-gain-table.h
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/tas.c
similarity index 99%
rename from sound/aoa/codecs/snd-aoa-codec-tas.c
rename to sound/aoa/codecs/tas.c
index 6c515b2..008e0f8 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas.c
+++ b/sound/aoa/codecs/tas.c
@@ -71,9 +71,9 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("tas codec driver for snd-aoa");
 
-#include "snd-aoa-codec-tas.h"
-#include "snd-aoa-codec-tas-gain-table.h"
-#include "snd-aoa-codec-tas-basstreble.h"
+#include "tas.h"
+#include "tas-gain-table.h"
+#include "tas-basstreble.h"
 #include "../aoa.h"
 #include "../soundbus/soundbus.h"
 
@@ -880,7 +880,7 @@
 		return;
 	tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas);
 }
-	
+
 
 static struct i2c_driver tas_driver;
 
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.h b/sound/aoa/codecs/tas.h
similarity index 100%
rename from sound/aoa/codecs/snd-aoa-codec-tas.h
rename to sound/aoa/codecs/tas.h
diff --git a/sound/aoa/codecs/snd-aoa-codec-toonie.c b/sound/aoa/codecs/toonie.c
similarity index 98%
rename from sound/aoa/codecs/snd-aoa-codec-toonie.c
rename to sound/aoa/codecs/toonie.c
index 3c7d1d8..f13827e 100644
--- a/sound/aoa/codecs/snd-aoa-codec-toonie.c
+++ b/sound/aoa/codecs/toonie.c
@@ -131,7 +131,7 @@
 	toonie->codec.owner = THIS_MODULE;
 	toonie->codec.init = toonie_init_codec;
 	toonie->codec.exit = toonie_exit_codec;
-                                        
+
 	if (aoa_codec_register(&toonie->codec)) {
 		kfree(toonie);
 		return -EINVAL;
diff --git a/sound/aoa/core/Makefile b/sound/aoa/core/Makefile
index 62dc728..a1596e8 100644
--- a/sound/aoa/core/Makefile
+++ b/sound/aoa/core/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_SND_AOA) += snd-aoa.o
-snd-aoa-objs := snd-aoa-core.o \
-		snd-aoa-alsa.o \
-		snd-aoa-gpio-pmf.o \
-		snd-aoa-gpio-feature.o
+snd-aoa-objs := core.o \
+		alsa.o \
+		gpio-pmf.o \
+		gpio-feature.o
diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/alsa.c
similarity index 98%
rename from sound/aoa/core/snd-aoa-alsa.c
rename to sound/aoa/core/alsa.c
index 17fe689..6178504 100644
--- a/sound/aoa/core/snd-aoa-alsa.c
+++ b/sound/aoa/core/alsa.c
@@ -6,7 +6,7 @@
  * GPL v2, can be found in COPYING.
  */
 #include <linux/module.h>
-#include "snd-aoa-alsa.h"
+#include "alsa.h"
 
 static int index = -1;
 module_param(index, int, 0444);
@@ -64,7 +64,7 @@
 {
 	struct snd_card *card = aoa_get_card();
 	int err;
-	
+
 	if (!card) return -ENOMEM;
 
 	err = snd_device_new(card, type, device_data, ops);
diff --git a/sound/aoa/core/snd-aoa-alsa.h b/sound/aoa/core/alsa.h
similarity index 100%
rename from sound/aoa/core/snd-aoa-alsa.h
rename to sound/aoa/core/alsa.h
diff --git a/sound/aoa/core/snd-aoa-core.c b/sound/aoa/core/core.c
similarity index 98%
rename from sound/aoa/core/snd-aoa-core.c
rename to sound/aoa/core/core.c
index 19fdae4..10bec6c 100644
--- a/sound/aoa/core/snd-aoa-core.c
+++ b/sound/aoa/core/core.c
@@ -10,7 +10,7 @@
 #include <linux/module.h>
 #include <linux/list.h>
 #include "../aoa.h"
-#include "snd-aoa-alsa.h"
+#include "alsa.h"
 
 MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver");
 MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/gpio-feature.c
similarity index 99%
rename from sound/aoa/core/snd-aoa-gpio-feature.c
rename to sound/aoa/core/gpio-feature.c
index 805dcbf..c93ad5d 100644
--- a/sound/aoa/core/snd-aoa-gpio-feature.c
+++ b/sound/aoa/core/gpio-feature.c
@@ -5,7 +5,7 @@
  *
  * GPL v2, can be found in COPYING.
  *
- * This file contains the GPIO control routines for 
+ * This file contains the GPIO control routines for
  * direct (through feature calls) access to the GPIO
  * registers.
  */
diff --git a/sound/aoa/core/snd-aoa-gpio-pmf.c b/sound/aoa/core/gpio-pmf.c
similarity index 100%
rename from sound/aoa/core/snd-aoa-gpio-pmf.c
rename to sound/aoa/core/gpio-pmf.c
diff --git a/sound/aoa/fabrics/Makefile b/sound/aoa/fabrics/Makefile
index 55fc5e7..da37c10 100644
--- a/sound/aoa/fabrics/Makefile
+++ b/sound/aoa/fabrics/Makefile
@@ -1 +1,3 @@
+snd-aoa-fabric-layout-objs += layout.o
+
 obj-$(CONFIG_SND_AOA_FABRIC_LAYOUT) += snd-aoa-fabric-layout.o
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/layout.c
similarity index 99%
rename from sound/aoa/fabrics/snd-aoa-fabric-layout.c
rename to sound/aoa/fabrics/layout.c
index dea7abb..ad60f5d 100644
--- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c
+++ b/sound/aoa/fabrics/layout.c
@@ -66,7 +66,7 @@
 	unsigned int layout_id;
 	struct codec_connect_info codecs[MAX_CODECS_PER_BUS];
 	int flags;
-	
+
 	/* if busname is not assigned, we use 'Master' below,
 	 * so that our layout table doesn't need to be filled
 	 * too much.
diff --git a/sound/aoa/soundbus/i2sbus/Makefile b/sound/aoa/soundbus/i2sbus/Makefile
index e57a5cf..1b949b2 100644
--- a/sound/aoa/soundbus/i2sbus/Makefile
+++ b/sound/aoa/soundbus/i2sbus/Makefile
@@ -1,2 +1,2 @@
 obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += snd-aoa-i2sbus.o
-snd-aoa-i2sbus-objs := i2sbus-core.o i2sbus-pcm.o i2sbus-control.o
+snd-aoa-i2sbus-objs := core.o pcm.o control.o
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.c b/sound/aoa/soundbus/i2sbus/control.c
similarity index 100%
rename from sound/aoa/soundbus/i2sbus/i2sbus-control.c
rename to sound/aoa/soundbus/i2sbus/control.c
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/core.c
similarity index 99%
rename from sound/aoa/soundbus/i2sbus/i2sbus-core.c
rename to sound/aoa/soundbus/i2sbus/core.c
index b4590df..be468ed 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -64,7 +64,7 @@
 				       struct dbdma_command_mem *r)
 {
 	if (!r->space) return;
-	
+
 	dma_free_coherent(&macio_get_pci_dev(i2sdev->macio)->dev,
 			    r->size, r->space, r->bus_addr);
 }
@@ -247,7 +247,7 @@
 		 * but request_resource doesn't know about parents and
 		 * contained resources...
 		 */
-		dev->allocated_resource[i] = 
+		dev->allocated_resource[i] =
 			request_mem_region(dev->resources[i].start,
 					   dev->resources[i].end -
 					   dev->resources[i].start + 1,
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h
index ff29654..befefd9 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus.h
+++ b/sound/aoa/soundbus/i2sbus/i2sbus.h
@@ -18,7 +18,7 @@
 #include <asm/pmac_feature.h>
 #include <asm/dbdma.h>
 
-#include "i2sbus-interface.h"
+#include "interface.h"
 #include "../soundbus.h"
 
 struct i2sbus_control {
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-interface.h b/sound/aoa/soundbus/i2sbus/interface.h
similarity index 100%
rename from sound/aoa/soundbus/i2sbus/i2sbus-interface.h
rename to sound/aoa/soundbus/i2sbus/interface.h
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c
similarity index 100%
rename from sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
rename to sound/aoa/soundbus/i2sbus/pcm.c
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 66348c9..7bbdda0 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -95,6 +95,26 @@
 	  this will be compiled as a module. The module will be called
 	  snd-seq-oss.
 
+config SND_HRTIMER
+	tristate "HR-timer backend support"
+	depends on HIGH_RES_TIMERS
+	select SND_TIMER
+	help
+	  Say Y here to enable HR-timer backend for ALSA timer.  ALSA uses
+	  the hrtimer as a precise timing source. The ALSA sequencer code
+	  also can use this timing source.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-hrtimer.
+
+config SND_SEQ_HRTIMER_DEFAULT
+	bool "Use HR-timer as default sequencer timer"
+	depends on SND_HRTIMER && SND_SEQUENCER
+	default y
+	help
+	  Say Y here to use the HR-timer backend as the default sequencer
+	  timer.
+
 config SND_RTCTIMER
 	tristate "RTC Timer support"
 	depends on RTC
@@ -114,6 +134,7 @@
 config SND_SEQ_RTCTIMER_DEFAULT
 	bool "Use RTC as default sequencer timer"
 	depends on SND_RTCTIMER && SND_SEQUENCER
+	depends on !SND_SEQ_HRTIMER_DEFAULT
 	default y
 	help
 	  Say Y here to use the RTC timer as the default sequencer
diff --git a/sound/core/Makefile b/sound/core/Makefile
index d57125a..4229052 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -17,12 +17,14 @@
 
 snd-rawmidi-objs  := rawmidi.o
 snd-timer-objs    := timer.o
+snd-hrtimer-objs  := hrtimer.o
 snd-rtctimer-objs := rtctimer.o
 snd-hwdep-objs    := hwdep.o
 
 obj-$(CONFIG_SND) 		+= snd.o
 obj-$(CONFIG_SND_HWDEP)		+= snd-hwdep.o
 obj-$(CONFIG_SND_TIMER)		+= snd-timer.o
+obj-$(CONFIG_SND_HRTIMER)	+= snd-hrtimer.o
 obj-$(CONFIG_SND_RTCTIMER)	+= snd-rtctimer.o
 obj-$(CONFIG_SND_PCM)		+= snd-pcm.o snd-page-alloc.o
 obj-$(CONFIG_SND_RAWMIDI)	+= snd-rawmidi.o
diff --git a/sound/core/device.c b/sound/core/device.c
index c58d822..a67dfac0 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -98,7 +98,7 @@
 		kfree(dev);
 		return 0;
 	}
-	snd_printd("device free %p (from %p), not found\n", device_data,
+	snd_printd("device free %p (from %pF), not found\n", device_data,
 		   __builtin_return_address(0));
 	return -ENXIO;
 }
@@ -135,7 +135,7 @@
 		}
 		return 0;
 	}
-	snd_printd("device disconnect %p (from %p), not found\n", device_data,
+	snd_printd("device disconnect %p (from %pF), not found\n", device_data,
 		   __builtin_return_address(0));
 	return -ENXIO;
 }
diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c
new file mode 100644
index 0000000..c1d2859
--- /dev/null
+++ b/sound/core/hrtimer.c
@@ -0,0 +1,155 @@
+/*
+ * ALSA timer back-end using hrtimer
+ * Copyright (C) 2008 Takashi Iwai
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/hrtimer.h>
+#include <sound/core.h>
+#include <sound/timer.h>
+
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+MODULE_DESCRIPTION("ALSA hrtimer backend");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER));
+
+#define NANO_SEC	1000000000UL	/* 10^9 in sec */
+static unsigned int resolution;
+
+struct snd_hrtimer {
+	struct snd_timer *timer;
+	struct hrtimer hrt;
+};
+
+static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
+{
+	struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
+	struct snd_timer *t = stime->timer;
+	hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution));
+	snd_timer_interrupt(stime->timer, t->sticks);
+	return HRTIMER_RESTART;
+}
+
+static int snd_hrtimer_open(struct snd_timer *t)
+{
+	struct snd_hrtimer *stime;
+
+	stime = kmalloc(sizeof(*stime), GFP_KERNEL);
+	if (!stime)
+		return -ENOMEM;
+	hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	stime->timer = t;
+	stime->hrt.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
+	stime->hrt.function = snd_hrtimer_callback;
+	t->private_data = stime;
+	return 0;
+}
+
+static int snd_hrtimer_close(struct snd_timer *t)
+{
+	struct snd_hrtimer *stime = t->private_data;
+
+	if (stime) {
+		hrtimer_cancel(&stime->hrt);
+		kfree(stime);
+		t->private_data = NULL;
+	}
+	return 0;
+}
+
+static int snd_hrtimer_start(struct snd_timer *t)
+{
+	struct snd_hrtimer *stime = t->private_data;
+
+	hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution),
+		      HRTIMER_MODE_REL);
+	return 0;
+}
+
+static int snd_hrtimer_stop(struct snd_timer *t)
+{
+	struct snd_hrtimer *stime = t->private_data;
+
+	hrtimer_cancel(&stime->hrt);
+	return 0;
+}
+
+static struct snd_timer_hardware hrtimer_hw = {
+	.flags =	SNDRV_TIMER_HW_AUTO,
+	.open =		snd_hrtimer_open,
+	.close =	snd_hrtimer_close,
+	.start =	snd_hrtimer_start,
+	.stop =		snd_hrtimer_stop,
+};
+
+/*
+ * entry functions
+ */
+
+static struct snd_timer *mytimer;
+
+static int __init snd_hrtimer_init(void)
+{
+	struct snd_timer *timer;
+	struct timespec tp;
+	int err;
+
+	hrtimer_get_res(CLOCK_MONOTONIC, &tp);
+	if (tp.tv_sec > 0 || !tp.tv_nsec) {
+		snd_printk(KERN_ERR
+			   "snd-hrtimer: Invalid resolution %u.%09u",
+			   (unsigned)tp.tv_sec, (unsigned)tp.tv_nsec);
+		return -EINVAL;
+	}
+	resolution = tp.tv_nsec;
+
+	/* Create a new timer and set up the fields */
+	err = snd_timer_global_new("hrtimer", SNDRV_TIMER_GLOBAL_HRTIMER,
+				   &timer);
+	if (err < 0)
+		return err;
+
+	timer->module = THIS_MODULE;
+	strcpy(timer->name, "HR timer");
+	timer->hw = hrtimer_hw;
+	timer->hw.resolution = resolution;
+	timer->hw.ticks = NANO_SEC / resolution;
+
+	err = snd_timer_global_register(timer);
+	if (err < 0) {
+		snd_timer_global_free(timer);
+		return err;
+	}
+	mytimer = timer; /* remember this */
+
+	return 0;
+}
+
+static void __exit snd_hrtimer_exit(void)
+{
+	if (mytimer) {
+		snd_timer_global_free(mytimer);
+		mytimer = NULL;
+	}
+}
+
+module_init(snd_hrtimer_init);
+module_exit(snd_hrtimer_exit);
diff --git a/sound/core/info.c b/sound/core/info.c
index 527b207..70fa871 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -653,6 +653,23 @@
 }
 
 /*
+ * called on card->id change
+ */
+void snd_info_card_id_change(struct snd_card *card)
+{
+	mutex_lock(&info_mutex);
+	if (card->proc_root_link) {
+		snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
+		card->proc_root_link = NULL;
+	}
+	if (strcmp(card->id, card->proc_root->name))
+		card->proc_root_link = proc_symlink(card->id,
+						    snd_proc_root,
+						    card->proc_root->name);
+	mutex_unlock(&info_mutex);
+}
+
+/*
  * de-register the card proc file
  * called from init.c
  */
diff --git a/sound/core/init.c b/sound/core/init.c
index b47ff8b..0d5520c 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -533,6 +533,65 @@
 	}
 }
 
+#ifndef CONFIG_SYSFS_DEPRECATED
+static ssize_t
+card_id_show_attr(struct device *dev,
+		  struct device_attribute *attr, char *buf)
+{
+	struct snd_card *card = dev_get_drvdata(dev);
+	return snprintf(buf, PAGE_SIZE, "%s\n", card ? card->id : "(null)");
+}
+
+static ssize_t
+card_id_store_attr(struct device *dev, struct device_attribute *attr,
+		   const char *buf, size_t count)
+{
+	struct snd_card *card = dev_get_drvdata(dev);
+	char buf1[sizeof(card->id)];
+	size_t copy = count > sizeof(card->id) - 1 ?
+					sizeof(card->id) - 1 : count;
+	size_t idx;
+	int c;
+
+	for (idx = 0; idx < copy; idx++) {
+		c = buf[idx];
+		if (!isalnum(c) && c != '_' && c != '-')
+			return -EINVAL;
+	}
+	memcpy(buf1, buf, copy);
+	buf1[copy] = '\0';
+	mutex_lock(&snd_card_mutex);
+	if (!snd_info_check_reserved_words(buf1)) {
+	     __exist:
+		mutex_unlock(&snd_card_mutex);
+		return -EEXIST;
+	}
+	for (idx = 0; idx < snd_ecards_limit; idx++) {
+		if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1))
+			goto __exist;
+	}
+	strcpy(card->id, buf1);
+	snd_info_card_id_change(card);
+	mutex_unlock(&snd_card_mutex);
+
+	return count;
+}
+
+static struct device_attribute card_id_attrs =
+	__ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr);
+
+static ssize_t
+card_number_show_attr(struct device *dev,
+		     struct device_attribute *attr, char *buf)
+{
+	struct snd_card *card = dev_get_drvdata(dev);
+	return snprintf(buf, PAGE_SIZE, "%i\n", card ? card->number : -1);
+}
+
+static struct device_attribute card_number_attrs =
+	__ATTR(number, S_IRUGO, card_number_show_attr, NULL);
+#endif /* CONFIG_SYSFS_DEPRECATED */
+
 /**
  *  snd_card_register - register the soundcard
  *  @card: soundcard structure
@@ -553,7 +612,7 @@
 #ifndef CONFIG_SYSFS_DEPRECATED
 	if (!card->card_dev) {
 		card->card_dev = device_create(sound_class, card->dev,
-					       MKDEV(0, 0), NULL,
+					       MKDEV(0, 0), card,
 					       "card%i", card->number);
 		if (IS_ERR(card->card_dev))
 			card->card_dev = NULL;
@@ -576,6 +635,16 @@
 	if (snd_mixer_oss_notify_callback)
 		snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);
 #endif
+#ifndef CONFIG_SYSFS_DEPRECATED
+	if (card->card_dev) {
+		err = device_create_file(card->card_dev, &card_id_attrs);
+		if (err < 0)
+			return err;
+		err = device_create_file(card->card_dev, &card_number_attrs);
+		if (err < 0)
+			return err;
+	}
+#endif
 	return 0;
 }
 
diff --git a/sound/core/jack.c b/sound/core/jack.c
index bd2d9e6..dd4a12d 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -34,6 +34,7 @@
 	else
 		input_free_device(jack->input_dev);
 
+	kfree(jack->id);
 	kfree(jack);
 
 	return 0;
@@ -87,7 +88,7 @@
 	if (jack == NULL)
 		return -ENOMEM;
 
-	jack->id = id;
+	jack->id = kstrdup(id, GFP_KERNEL);
 
 	jack->input_dev = input_allocate_device();
 	if (jack->input_dev == NULL) {
@@ -102,9 +103,15 @@
 	if (type & SND_JACK_HEADPHONE)
 		input_set_capability(jack->input_dev, EV_SW,
 				     SW_HEADPHONE_INSERT);
+	if (type & SND_JACK_LINEOUT)
+		input_set_capability(jack->input_dev, EV_SW,
+				     SW_LINEOUT_INSERT);
 	if (type & SND_JACK_MICROPHONE)
 		input_set_capability(jack->input_dev, EV_SW,
 				     SW_MICROPHONE_INSERT);
+	if (type & SND_JACK_MECHANICAL)
+		input_set_capability(jack->input_dev, EV_SW,
+				     SW_JACK_PHYSICAL_INSERT);
 
 	err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
 	if (err < 0)
@@ -153,9 +160,15 @@
 	if (jack->type & SND_JACK_HEADPHONE)
 		input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT,
 				    status & SND_JACK_HEADPHONE);
+	if (jack->type & SND_JACK_LINEOUT)
+		input_report_switch(jack->input_dev, SW_LINEOUT_INSERT,
+				    status & SND_JACK_LINEOUT);
 	if (jack->type & SND_JACK_MICROPHONE)
 		input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT,
 				    status & SND_JACK_MICROPHONE);
+	if (jack->type & SND_JACK_MECHANICAL)
+		input_report_switch(jack->input_dev, SW_JACK_PHYSICAL_INSERT,
+				    status & SND_JACK_MECHANICAL);
 
 	input_sync(jack->input_dev);
 }
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 39672f6..002777b 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -151,7 +151,7 @@
 	if (!substream->opened)
 		return;
 	if (up) {
-		tasklet_hi_schedule(&substream->runtime->tasklet);
+		tasklet_schedule(&substream->runtime->tasklet);
 	} else {
 		tasklet_kill(&substream->runtime->tasklet);
 		substream->ops->trigger(substream, 0);
@@ -908,7 +908,7 @@
 	}
 	if (result > 0) {
 		if (runtime->event)
-			tasklet_hi_schedule(&runtime->tasklet);
+			tasklet_schedule(&runtime->tasklet);
 		else if (snd_rawmidi_ready(substream))
 			wake_up(&runtime->sleep);
 	}
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
index 51e64e3..0851cd1 100644
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -118,7 +118,7 @@
  */
 static void rtctimer_interrupt(void *private_data)
 {
-	tasklet_hi_schedule(private_data);
+	tasklet_schedule(private_data);
 }
 
 
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index ee0f840..bf09a5a 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -43,7 +43,9 @@
 int seq_default_timer_sclass = SNDRV_TIMER_SCLASS_NONE;
 int seq_default_timer_card = -1;
 int seq_default_timer_device =
-#ifdef CONFIG_SND_SEQ_RTCTIMER_DEFAULT
+#ifdef CONFIG_SND_SEQ_HRTIMER_DEFAULT
+	SNDRV_TIMER_GLOBAL_HRTIMER
+#elif defined(CONFIG_SND_SEQ_RTCTIMER_DEFAULT)
 	SNDRV_TIMER_GLOBAL_RTC
 #else
 	SNDRV_TIMER_GLOBAL_SYSTEM
diff --git a/sound/core/timer.c b/sound/core/timer.c
index c584408..7965320 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -743,7 +743,7 @@
 	spin_unlock_irqrestore(&timer->lock, flags);
 
 	if (use_tasklet)
-		tasklet_hi_schedule(&timer->task_queue);
+		tasklet_schedule(&timer->task_queue);
 }
 
 /*
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index 255fd18..0bcf146 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -163,7 +163,7 @@
 
 config SND_AC97_POWER_SAVE
 	bool "AC97 Power-Saving Mode"
-	depends on SND_AC97_CODEC && EXPERIMENTAL
+	depends on SND_AC97_CODEC
 	default n
 	help
 	  Say Y here to enable the aggressive power-saving support of
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
index 1899cf0..2a02f70 100644
--- a/sound/drivers/pcsp/pcsp.c
+++ b/sound/drivers/pcsp/pcsp.c
@@ -96,7 +96,7 @@
 		return -EINVAL;
 
 	hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	pcsp_chip.timer.cb_mode = HRTIMER_CB_SOFTIRQ;
+	pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
 	pcsp_chip.timer.function = pcsp_do_timer;
 
 	card = snd_card_new(index, id, THIS_MODULE, 0);
@@ -188,10 +188,8 @@
 
 static void pcsp_stop_beep(struct snd_pcsp *chip)
 {
-	spin_lock_irq(&chip->substream_lock);
-	if (!chip->playback_substream)
-		pcspkr_stop_sound();
-	spin_unlock_irq(&chip->substream_lock);
+	pcsp_sync_stop(chip);
+	pcspkr_stop_sound();
 }
 
 #ifdef CONFIG_PM
diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h
index 1d661f7..cdef266 100644
--- a/sound/drivers/pcsp/pcsp.h
+++ b/sound/drivers/pcsp/pcsp.h
@@ -62,6 +62,8 @@
 	unsigned short port, irq, dma;
 	spinlock_t substream_lock;
 	struct snd_pcm_substream *playback_substream;
+	unsigned int fmt_size;
+	unsigned int is_signed;
 	size_t playback_ptr;
 	size_t period_ptr;
 	atomic_t timer_active;
@@ -77,6 +79,7 @@
 extern struct snd_pcsp pcsp_chip;
 
 extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle);
+extern void pcsp_sync_stop(struct snd_pcsp *chip);
 
 extern int snd_pcsp_new_pcm(struct snd_pcsp *chip);
 extern int snd_pcsp_new_mixer(struct snd_pcsp *chip);
diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c
index 1f42e40..84cc265 100644
--- a/sound/drivers/pcsp/pcsp_lib.c
+++ b/sound/drivers/pcsp/pcsp_lib.c
@@ -8,6 +8,7 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/interrupt.h>
 #include <sound/pcm.h>
 #include <asm/io.h>
 #include "pcsp.h"
@@ -19,61 +20,57 @@
 
 #define DMIX_WANTS_S16	1
 
-enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
+/*
+ * Call snd_pcm_period_elapsed in a tasklet
+ * This avoids spinlock messes and long-running irq contexts
+ */
+static void pcsp_call_pcm_elapsed(unsigned long priv)
+{
+	if (atomic_read(&pcsp_chip.timer_active)) {
+		struct snd_pcm_substream *substream;
+		substream = pcsp_chip.playback_substream;
+		if (substream)
+			snd_pcm_period_elapsed(substream);
+	}
+}
+
+static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0);
+
+/* write the port and returns the next expire time in ns;
+ * called at the trigger-start and in hrtimer callback
+ */
+static unsigned long pcsp_timer_update(struct hrtimer *handle)
 {
 	unsigned char timer_cnt, val;
-	int fmt_size, periods_elapsed;
 	u64 ns;
-	size_t period_bytes, buffer_bytes;
 	struct snd_pcm_substream *substream;
 	struct snd_pcm_runtime *runtime;
 	struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
+	unsigned long flags;
 
 	if (chip->thalf) {
 		outb(chip->val61, 0x61);
 		chip->thalf = 0;
 		if (!atomic_read(&chip->timer_active))
-			return HRTIMER_NORESTART;
-		hrtimer_forward(&chip->timer, hrtimer_get_expires(&chip->timer),
-				ktime_set(0, chip->ns_rem));
-		return HRTIMER_RESTART;
+			return 0;
+		return chip->ns_rem;
 	}
 
-	spin_lock_irq(&chip->substream_lock);
-	/* Takashi Iwai says regarding this extra lock:
-
-	If the irq handler handles some data on the DMA buffer, it should
-	do snd_pcm_stream_lock().
-	That protects basically against all races among PCM callbacks, yes.
-	However, there are two remaining issues:
-	1. The substream pointer you try to lock isn't protected _before_
-	  this lock yet.
-	2. snd_pcm_period_elapsed() itself acquires the lock.
-	The requirement of another lock is because of 1.  When you get
-	chip->playback_substream, it's not protected.
-	Keeping this lock while snd_pcm_period_elapsed() assures the substream
-	is still protected (at least, not released).  And the other status is
-	handled properly inside snd_pcm_stream_lock() in
-	snd_pcm_period_elapsed().
-
-	*/
-	if (!chip->playback_substream)
-		goto exit_nr_unlock1;
-	substream = chip->playback_substream;
-	snd_pcm_stream_lock(substream);
 	if (!atomic_read(&chip->timer_active))
-		goto exit_nr_unlock2;
+		return 0;
+	substream = chip->playback_substream;
+	if (!substream)
+		return 0;
 
 	runtime = substream->runtime;
-	fmt_size = snd_pcm_format_physical_width(runtime->format) >> 3;
 	/* assume it is mono! */
-	val = runtime->dma_area[chip->playback_ptr + fmt_size - 1];
-	if (snd_pcm_format_signed(runtime->format))
+	val = runtime->dma_area[chip->playback_ptr + chip->fmt_size - 1];
+	if (chip->is_signed)
 		val ^= 0x80;
 	timer_cnt = val * CUR_DIV() / 256;
 
 	if (timer_cnt && chip->enable) {
-		spin_lock(&i8253_lock);
+		spin_lock_irqsave(&i8253_lock, flags);
 		if (!nforce_wa) {
 			outb_p(chip->val61, 0x61);
 			outb_p(timer_cnt, 0x42);
@@ -82,12 +79,39 @@
 			outb(chip->val61 ^ 2, 0x61);
 			chip->thalf = 1;
 		}
-		spin_unlock(&i8253_lock);
+		spin_unlock_irqrestore(&i8253_lock, flags);
 	}
 
+	chip->ns_rem = PCSP_PERIOD_NS();
+	ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem);
+	chip->ns_rem -= ns;
+	return ns;
+}
+
+enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
+{
+	struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
+	struct snd_pcm_substream *substream;
+	int periods_elapsed, pointer_update;
+	size_t period_bytes, buffer_bytes;
+	unsigned long ns;
+	unsigned long flags;
+
+	pointer_update = !chip->thalf;
+	ns = pcsp_timer_update(handle);
+	if (!ns)
+		return HRTIMER_NORESTART;
+
+	/* update the playback position */
+	substream = chip->playback_substream;
+	if (!substream)
+		return HRTIMER_NORESTART;
+
 	period_bytes = snd_pcm_lib_period_bytes(substream);
 	buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
-	chip->playback_ptr += PCSP_INDEX_INC() * fmt_size;
+
+	spin_lock_irqsave(&chip->substream_lock, flags);
+	chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size;
 	periods_elapsed = chip->playback_ptr - chip->period_ptr;
 	if (periods_elapsed < 0) {
 #if PCSP_DEBUG
@@ -102,41 +126,30 @@
 	 * or ALSA will BUG on us. */
 	chip->playback_ptr %= buffer_bytes;
 
-	snd_pcm_stream_unlock(substream);
-
 	if (periods_elapsed) {
-		snd_pcm_period_elapsed(substream);
 		chip->period_ptr += periods_elapsed * period_bytes;
 		chip->period_ptr %= buffer_bytes;
 	}
+	spin_unlock_irqrestore(&chip->substream_lock, flags);
 
-	spin_unlock_irq(&chip->substream_lock);
+	if (periods_elapsed)
+		tasklet_schedule(&pcsp_pcm_tasklet);
 
-	if (!atomic_read(&chip->timer_active))
-		return HRTIMER_NORESTART;
+	hrtimer_forward(handle, hrtimer_get_expires(handle), ns_to_ktime(ns));
 
-	chip->ns_rem = PCSP_PERIOD_NS();
-	ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem);
-	chip->ns_rem -= ns;
-	hrtimer_forward(&chip->timer, hrtimer_get_expires(&chip->timer),
-							ktime_set(0, ns));
 	return HRTIMER_RESTART;
-
-exit_nr_unlock2:
-	snd_pcm_stream_unlock(substream);
-exit_nr_unlock1:
-	spin_unlock_irq(&chip->substream_lock);
-	return HRTIMER_NORESTART;
 }
 
-static void pcsp_start_playing(struct snd_pcsp *chip)
+static int pcsp_start_playing(struct snd_pcsp *chip)
 {
+	unsigned long ns;
+
 #if PCSP_DEBUG
 	printk(KERN_INFO "PCSP: start_playing called\n");
 #endif
 	if (atomic_read(&chip->timer_active)) {
 		printk(KERN_ERR "PCSP: Timer already active\n");
-		return;
+		return -EIO;
 	}
 
 	spin_lock(&i8253_lock);
@@ -146,7 +159,12 @@
 	atomic_set(&chip->timer_active, 1);
 	chip->thalf = 0;
 
-	hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL);
+	ns = pcsp_timer_update(&pcsp_chip.timer);
+	if (!ns)
+		return -EIO;
+
+	hrtimer_start(&pcsp_chip.timer, ktime_set(0, ns), HRTIMER_MODE_REL);
+	return 0;
 }
 
 static void pcsp_stop_playing(struct snd_pcsp *chip)
@@ -165,26 +183,35 @@
 	spin_unlock(&i8253_lock);
 }
 
+/*
+ * Force to stop and sync the stream
+ */
+void pcsp_sync_stop(struct snd_pcsp *chip)
+{
+	local_irq_disable();
+	pcsp_stop_playing(chip);
+	local_irq_enable();
+	hrtimer_cancel(&chip->timer);
+	tasklet_kill(&pcsp_pcm_tasklet);
+}
+
 static int snd_pcsp_playback_close(struct snd_pcm_substream *substream)
 {
 	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
 #if PCSP_DEBUG
 	printk(KERN_INFO "PCSP: close called\n");
 #endif
-	if (atomic_read(&chip->timer_active)) {
-		printk(KERN_ERR "PCSP: timer still active\n");
-		pcsp_stop_playing(chip);
-	}
-	spin_lock_irq(&chip->substream_lock);
+	pcsp_sync_stop(chip);
 	chip->playback_substream = NULL;
-	spin_unlock_irq(&chip->substream_lock);
 	return 0;
 }
 
 static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream,
 				       struct snd_pcm_hw_params *hw_params)
 {
+	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
 	int err;
+	pcsp_sync_stop(chip);
 	err = snd_pcm_lib_malloc_pages(substream,
 				      params_buffer_bytes(hw_params));
 	if (err < 0)
@@ -194,9 +221,11 @@
 
 static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream)
 {
+	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
 #if PCSP_DEBUG
 	printk(KERN_INFO "PCSP: hw_free called\n");
 #endif
+	pcsp_sync_stop(chip);
 	return snd_pcm_lib_free_pages(substream);
 }
 
@@ -212,8 +241,12 @@
 			snd_pcm_lib_period_bytes(substream),
 			substream->runtime->periods);
 #endif
+	pcsp_sync_stop(chip);
 	chip->playback_ptr = 0;
 	chip->period_ptr = 0;
+	chip->fmt_size =
+		snd_pcm_format_physical_width(substream->runtime->format) >> 3;
+	chip->is_signed = snd_pcm_format_signed(substream->runtime->format);
 	return 0;
 }
 
@@ -226,8 +259,7 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
-		pcsp_start_playing(chip);
-		break;
+		return pcsp_start_playing(chip);
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 		pcsp_stop_playing(chip);
@@ -242,7 +274,11 @@
 						   *substream)
 {
 	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
-	return bytes_to_frames(substream->runtime, chip->playback_ptr);
+	unsigned int pos;
+	spin_lock(&chip->substream_lock);
+	pos = chip->playback_ptr;
+	spin_unlock(&chip->substream_lock);
+	return bytes_to_frames(substream->runtime, pos);
 }
 
 static struct snd_pcm_hardware snd_pcsp_playback = {
@@ -279,9 +315,7 @@
 		return -EBUSY;
 	}
 	runtime->hw = snd_pcsp_playback;
-	spin_lock_irq(&chip->substream_lock);
 	chip->playback_substream = substream;
-	spin_unlock_irq(&chip->substream_lock);
 	return 0;
 }
 
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index 473b07f..14e3354 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -548,7 +548,7 @@
 	    (chip->chip_status & VX_STAT_IS_STALE))
 		return IRQ_NONE;
 	if (! vx_test_and_ack(chip))
-		tasklet_hi_schedule(&chip->tq);
+		tasklet_schedule(&chip->tq);
 	return IRQ_HANDLED;
 }
 
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index 27de574..6644d00 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -823,7 +823,7 @@
 		 * we trigger the pipe using tasklet, so that the interrupts are
 		 * issued surely after the trigger is completed.
 		 */ 
-		tasklet_hi_schedule(&pipe->start_tq);
+		tasklet_schedule(&pipe->start_tq);
 		chip->pcm_running++;
 		pipe->running = 1;
 		break;
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index 667eccc..ea06877 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -140,8 +140,10 @@
 				break;
 			}
 		}
-		if (i >= ARRAY_SIZE(possible_ports))
+		if (i >= ARRAY_SIZE(possible_ports)) {
+			err = -EINVAL;
 			goto _err;
+		}
 	}
 	acard->chip = chip;
 			
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 7003711..6e3a184 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -208,7 +208,8 @@
 	   * AuzenTech X-Meridian
 	   * Bgears b-Enspirer
 	   * Club3D Theatron DTS
-	   * HT-Omega Claro
+	   * HT-Omega Claro (plus)
+	   * HT-Omega Claro halo (XT)
 	   * Razer Barracuda AC-1
 	   * Sondigo Inferno
 
@@ -497,129 +498,7 @@
 	depends on SND_FM801_TEA575X_BOOL
 	default SND_FM801
 
-config SND_HDA_INTEL
-	tristate "Intel HD Audio"
-	select SND_PCM
-	select SND_VMASTER
-	help
-	  Say Y here to include support for Intel "High Definition
-	  Audio" (Azalia) motherboard devices.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-hda-intel.
-
-config SND_HDA_HWDEP
-	bool "Build hwdep interface for HD-audio driver"
-	depends on SND_HDA_INTEL
-	select SND_HWDEP
-	help
-	  Say Y here to build a hwdep interface for HD-audio driver.
-	  This interface can be used for out-of-band communication
-	  with codecs for debugging purposes.
-
-config SND_HDA_INPUT_BEEP
-	bool "Support digital beep via input layer"
-	depends on SND_HDA_INTEL
-	depends on INPUT=y || INPUT=SND_HDA_INTEL
-	help
-	  Say Y here to build a digital beep interface for HD-audio
-	  driver. This interface is used to generate digital beeps.
-
-config SND_HDA_CODEC_REALTEK
-	bool "Build Realtek HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include Realtek HD-audio codec support in
-	  snd-hda-intel driver, such as ALC880.
-
-config SND_HDA_CODEC_ANALOG
-	bool "Build Analog Device HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include Analog Device HD-audio codec support in
-	  snd-hda-intel driver, such as AD1986A.
-
-config SND_HDA_CODEC_SIGMATEL
-	bool "Build IDT/Sigmatel HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include IDT (Sigmatel) HD-audio codec support in
-	  snd-hda-intel driver, such as STAC9200.
-
-config SND_HDA_CODEC_VIA
-	bool "Build VIA HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include VIA HD-audio codec support in
-	  snd-hda-intel driver, such as VT1708.
-
-config SND_HDA_CODEC_ATIHDMI
-	bool "Build ATI HDMI HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include ATI HDMI HD-audio codec support in
-	  snd-hda-intel driver, such as ATI RS600 HDMI.
-
-config SND_HDA_CODEC_NVHDMI
-	bool "Build NVIDIA HDMI HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include NVIDIA HDMI HD-audio codec support in
-	  snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
-
-config SND_HDA_CODEC_CONEXANT
-	bool "Build Conexant HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include Conexant HD-audio codec support in
-	  snd-hda-intel driver, such as CX20549.
-
-config SND_HDA_CODEC_CMEDIA
-	bool "Build C-Media HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include C-Media HD-audio codec support in
-	  snd-hda-intel driver, such as CMI9880.
-
-config SND_HDA_CODEC_SI3054
-	bool "Build Silicon Labs 3054 HD-modem codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include Silicon Labs 3054 HD-modem codec
-	  (and compatibles) support in snd-hda-intel driver.
-
-config SND_HDA_GENERIC
-	bool "Enable generic HD-audio codec parser"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to enable the generic HD-audio codec parser
-	  in snd-hda-intel driver.
-
-config SND_HDA_POWER_SAVE
-	bool "Aggressive power-saving on HD-audio"
-	depends on SND_HDA_INTEL && EXPERIMENTAL
-	help
-	  Say Y here to enable more aggressive power-saving mode on
-	  HD-audio driver.  The power-saving timeout can be configured
-	  via power_save option or over sysfs on-the-fly.
-
-config SND_HDA_POWER_SAVE_DEFAULT
-	int "Default time-out for HD-audio power-save mode"
-	depends on SND_HDA_POWER_SAVE
-	default 0
-	help
-	  The default time-out value in seconds for HD-audio automatic
-	  power-save mode.  0 means to disable the power-save mode.
+source "sound/pci/hda/Kconfig"
 
 config SND_HDSP
 	tristate "RME Hammerfall DSP Audio"
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index bd510ec..e2b843b 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -175,7 +175,7 @@
 { 0x574d4C04, 0xffffffff, "WM9704M,WM9704Q",	patch_wolfson04, NULL},
 { 0x574d4C05, 0xffffffff, "WM9705,WM9710",	patch_wolfson05, NULL},
 { 0x574d4C09, 0xffffffff, "WM9709",		NULL,		NULL},
-{ 0x574d4C12, 0xffffffff, "WM9711,WM9712",	patch_wolfson11, NULL},
+{ 0x574d4C12, 0xffffffff, "WM9711,WM9712,WM9715",	patch_wolfson11, NULL},
 { 0x574d4c13, 0xffffffff, "WM9713,WM9714",	patch_wolfson13, NULL, AC97_DEFAULT_POWER_OFF},
 { 0x594d4800, 0xffffffff, "YMF743",		patch_yamaha_ymf743,	NULL },
 { 0x594d4802, 0xffffffff, "YMF752",		NULL,		NULL },
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 6e831af..81bc93e 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -2054,8 +2054,9 @@
 		.get = snd_ac97_ad1888_lohpsel_get,
 		.put = snd_ac97_ad1888_lohpsel_put
 	},
-	AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, 2, 1, 1),
-	AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
+	AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, AC97_AD_VREFD_SHIFT, 1, 1),
+	AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2,
+			AC97_AD_HPFD_SHIFT, 1, 1),
 	AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -2832,6 +2833,8 @@
 			val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
 		else
 			val |= (1 << 1); /* Pin 47 is spdif input pin */
+		/* this seems missing on some hardwares */
+		ac97->ext_id |= AC97_EI_SPDIF;
 	}
 	val &= ~(1 << 12); /* vref enable */
 	snd_ac97_write_cache(ac97, 0x7a, val);
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index 74175fc..14b8d9a 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -664,10 +664,14 @@
 struct snd_ca0106_details {
         u32 serial;
         char * name;
-        int ac97;
-	int gpio_type;
-	int i2c_adc;
-	int spi_dac;
+	int ac97;	/* ac97 = 0 -> Select MIC, Line in, TAD in, AUX in.
+			   ac97 = 1 -> Default to AC97 in. */
+	int gpio_type;	/* gpio_type = 1 -> shared mic-in/line-in
+			   gpio_type = 2 -> shared side-out/line-in. */
+	int i2c_adc;	/* with i2c_adc=1, the driver adds some capture volume
+			   controls, phone, mic, line-in and aux. */
+	int spi_dac;	/* spi_dac=1 adds the mute switch for each analog
+			   output, front, rear, etc. */
 };
 
 // definition of the chip-specific record
@@ -686,11 +690,12 @@
 	spinlock_t emu_lock;
 
 	struct snd_ac97 *ac97;
-	struct snd_pcm *pcm;
+	struct snd_pcm *pcm[4];
 
 	struct snd_ca0106_channel playback_channels[4];
 	struct snd_ca0106_channel capture_channels[4];
-	u32 spdif_bits[4];             /* s/pdif out setup */
+	u32 spdif_bits[4];             /* s/pdif out default setup */
+	u32 spdif_str_bits[4];         /* s/pdif out per-stream setup */
 	int spdif_enable;
 	int capture_source;
 	int i2c_capture_source;
@@ -703,6 +708,11 @@
 	struct snd_ca_midi midi2;
 
 	u16 spi_dac_reg[16];
+
+#ifdef CONFIG_PM
+#define NUM_SAVED_VOLUMES	9
+	unsigned int saved_vol[NUM_SAVED_VOLUMES];
+#endif
 };
 
 int snd_ca0106_mixer(struct snd_ca0106 *emu);
@@ -721,3 +731,11 @@
 
 int snd_ca0106_spi_write(struct snd_ca0106 * emu,
 				   unsigned int data);
+
+#ifdef CONFIG_PM
+void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip);
+void snd_ca0106_mixer_resume(struct snd_ca0106 *chip);
+#else
+#define snd_ca0106_mixer_suspend(chip)	do { } while (0)
+#define snd_ca0106_mixer_resume(chip)	do { } while (0)
+#endif
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 88fbf28..0e62205 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -254,7 +254,7 @@
 	   .name   = "MSI K8N Diamond MB",
 	   .gpio_type = 2,
 	   .i2c_adc = 1,
-	   .spi_dac = 2 } ,
+	   .spi_dac = 1 } ,
 	 /* Shuttle XPC SD31P which has an onboard Creative Labs
 	  * Sound Blaster Live! 24-bit EAX
 	  * high-definition 7.1 audio processor".
@@ -305,9 +305,15 @@
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID),
 	.formats =		SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+#if 0 /* FIXME: looks like 44.1kHz capture causes noisy output on 48kHz */
 	.rates =		(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
 				 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000),
 	.rate_min =		44100,
+#else
+	.rates =		(SNDRV_PCM_RATE_48000 |
+				 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000),
+	.rate_min =		48000,
+#endif /* FIXME */
 	.rate_max =		192000,
 	.channels_min =		2,
 	.channels_max =		2,
@@ -479,6 +485,15 @@
 	[PCM_UNKNOWN_CHANNEL]	= SPI_DACD1_BIT,
 };
 
+static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
+{
+	if (chip->spdif_str_bits[idx] != chip->spdif_bits[idx]) {
+		chip->spdif_str_bits[idx] = chip->spdif_bits[idx];
+		snd_ca0106_ptr_write(chip, SPCS0 + idx, 0,
+				     chip->spdif_str_bits[idx]);
+	}
+}
+
 /* open_playback callback */
 static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
 						int channel_id)
@@ -524,6 +539,9 @@
 		if (err < 0)
 			return err;
 	}
+
+	restore_spdif_bits(chip, channel_id);
+
 	return 0;
 }
 
@@ -535,6 +553,8 @@
         struct snd_ca0106_pcm *epcm = runtime->private_data;
 	chip->playback_channels[epcm->channel_id].use = 0;
 
+	restore_spdif_bits(chip, epcm->channel_id);
+
 	if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) {
 		const int reg = spi_dacd_reg[epcm->channel_id];
 
@@ -847,15 +867,18 @@
         struct snd_pcm_substream *s;
 	u32 basic = 0;
 	u32 extended = 0;
-	int running=0;
+	u32 bits;
+	int running = 0;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		running=1;
+	case SNDRV_PCM_TRIGGER_RESUME:
+		running = 1;
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
 	default:
-		running=0;
+		running = 0;
 		break;
 	}
         snd_pcm_group_for_each_entry(s, substream) {
@@ -865,22 +888,32 @@
 		runtime = s->runtime;
 		epcm = runtime->private_data;
 		channel = epcm->channel_id;
-		//snd_printk("channel=%d\n",channel);
+		/* snd_printk("channel=%d\n",channel); */
 		epcm->running = running;
-		basic |= (0x1<<channel);
-		extended |= (0x10<<channel);
+		basic |= (0x1 << channel);
+		extended |= (0x10 << channel);
                 snd_pcm_trigger_done(s, substream);
         }
-	//snd_printk("basic=0x%x, extended=0x%x\n",basic, extended);
+	/* snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); */
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (extended));
-		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(basic));
+	case SNDRV_PCM_TRIGGER_RESUME:
+		bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0);
+		bits |= extended;
+		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits);
+		bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0);
+		bits |= basic;
+		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(basic));
-		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(extended));
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0);
+		bits &= ~basic;
+		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits);
+		bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0);
+		bits &= ~extended;
+		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits);
 		break;
 	default:
 		result = -EINVAL;
@@ -1103,21 +1136,13 @@
 	return snd_ac97_mixer(pbus, &ac97, &chip->ac97);
 }
 
+static void ca0106_stop_chip(struct snd_ca0106 *chip);
+
 static int snd_ca0106_free(struct snd_ca0106 *chip)
 {
-	if (chip->res_port != NULL) {    /* avoid access to already used hardware */
-		// disable interrupts
-		snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0);
-		outl(0, chip->port + INTE);
-		snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0);
-		udelay(1000);
-		// disable audio
-		//outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG);
-		outl(0, chip->port + HCFG);
-		/* FIXME: We need to stop and DMA transfers here.
-		 *        But as I am not sure how yet, we cannot from the dma pages.
-		 * So we can fix: snd-malloc: Memory leak?  pages not freed = 8
-		 */
+	if (chip->res_port != NULL) {
+		/* avoid access to already used hardware */
+		ca0106_stop_chip(chip);
 	}
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
@@ -1203,15 +1228,14 @@
 	return IRQ_HANDLED;
 }
 
-static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct snd_pcm **rpcm)
+static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
 {
 	struct snd_pcm *pcm;
 	struct snd_pcm_substream *substream;
 	int err;
   
-	if (rpcm)
-		*rpcm = NULL;
-	if ((err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm)) < 0)
+	err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm);
+	if (err < 0)
 		return err;
   
 	pcm->private_data = emu;
@@ -1238,7 +1262,6 @@
 	pcm->info_flags = 0;
 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
 	strcpy(pcm->name, "CA0106");
-	emu->pcm = pcm;
 
 	for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 
 	    substream; 
@@ -1260,8 +1283,7 @@
 			return err;
 	}
   
-	if (rpcm)
-		*rpcm = pcm;
+	emu->pcm[device] = pcm;
   
 	return 0;
 }
@@ -1301,89 +1323,10 @@
 	{ 0x15, ADC_MUX_LINEIN },  /* ADC Mixer control */
 };
 
-static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
-					 struct pci_dev *pci,
-					 struct snd_ca0106 **rchip)
+static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
 {
-	struct snd_ca0106 *chip;
-	struct snd_ca0106_details *c;
-	int err;
 	int ch;
-	static struct snd_device_ops ops = {
-		.dev_free = snd_ca0106_dev_free,
-	};
-  
-	*rchip = NULL;
-  
-	if ((err = pci_enable_device(pci)) < 0)
-		return err;
-	if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 ||
-	    pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) {
-		printk(KERN_ERR "error to set 32bit mask DMA\n");
-		pci_disable_device(pci);
-		return -ENXIO;
-	}
-  
-	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-	if (chip == NULL) {
-		pci_disable_device(pci);
-		return -ENOMEM;
-	}
-  
-	chip->card = card;
-	chip->pci = pci;
-	chip->irq = -1;
-
-	spin_lock_init(&chip->emu_lock);
-  
-	chip->port = pci_resource_start(pci, 0);
-	if ((chip->res_port = request_region(chip->port, 0x20,
-					     "snd_ca0106")) == NULL) { 
-		snd_ca0106_free(chip);
-		printk(KERN_ERR "cannot allocate the port\n");
-		return -EBUSY;
-	}
-
-	if (request_irq(pci->irq, snd_ca0106_interrupt,
-			IRQF_SHARED, "snd_ca0106", chip)) {
-		snd_ca0106_free(chip);
-		printk(KERN_ERR "cannot grab irq\n");
-		return -EBUSY;
-	}
-	chip->irq = pci->irq;
-  
- 	/* This stores the periods table. */ 
-	if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) {
-		snd_ca0106_free(chip);
-		return -ENOMEM;
-	}
-
-	pci_set_master(pci);
-	/* read serial */
-	pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
-	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
-#if 1
-	printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model,
-	       pci->revision, chip->serial);
-#endif
-	strcpy(card->driver, "CA0106");
-	strcpy(card->shortname, "CA0106");
-
-	for (c = ca0106_chip_details; c->serial; c++) {
-		if (subsystem[dev]) {
-			if (c->serial == subsystem[dev])
-				break;
-		} else if (c->serial == chip->serial)
-			break;
-	}
-	chip->details = c;
-	if (subsystem[dev]) {
-		printk(KERN_INFO "snd-ca0106: Sound card name=%s, subsystem=0x%x. Forced to subsystem=0x%x\n",
-                        c->name, chip->serial, subsystem[dev]);
-	}
-
-	sprintf(card->longname, "%s at 0x%lx irq %i",
-		c->name, chip->port, chip->irq);
+	unsigned int def_bits;
 
 	outl(0, chip->port + INTE);
 
@@ -1401,31 +1344,22 @@
 	 *  AN                = 0     (Audio data)
 	 *  P                 = 0     (Consumer)
 	 */
-	snd_ca0106_ptr_write(chip, SPCS0, 0,
-				chip->spdif_bits[0] =
-				SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
-				SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
-				SPCS_GENERATIONSTATUS | 0x00001200 |
-				0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+	def_bits =
+		SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
+		SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
+		SPCS_GENERATIONSTATUS | 0x00001200 |
+		0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT;
+	if (!resume) {
+		chip->spdif_str_bits[0] = chip->spdif_bits[0] = def_bits;
+		chip->spdif_str_bits[1] = chip->spdif_bits[1] = def_bits;
+		chip->spdif_str_bits[2] = chip->spdif_bits[2] = def_bits;
+		chip->spdif_str_bits[3] = chip->spdif_bits[3] = def_bits;
+	}
 	/* Only SPCS1 has been tested */
-	snd_ca0106_ptr_write(chip, SPCS1, 0,
-				chip->spdif_bits[1] =
-				SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
-				SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
-				SPCS_GENERATIONSTATUS | 0x00001200 |
-				0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
-	snd_ca0106_ptr_write(chip, SPCS2, 0,
-				chip->spdif_bits[2] =
-				SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
-				SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
-				SPCS_GENERATIONSTATUS | 0x00001200 |
-				0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
-	snd_ca0106_ptr_write(chip, SPCS3, 0,
-				chip->spdif_bits[3] =
-				SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
-				SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
-				SPCS_GENERATIONSTATUS | 0x00001200 |
-				0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+	snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_str_bits[1]);
+	snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_str_bits[0]);
+	snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_str_bits[2]);
+	snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_str_bits[3]);
 
         snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000);
         snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000);
@@ -1433,92 +1367,124 @@
         /* Write 0x8000 to AC97_REC_GAIN to mute it. */
         outb(AC97_REC_GAIN, chip->port + AC97ADDRESS);
         outw(0x8000, chip->port + AC97DATA);
-#if 0
+#if 0 /* FIXME: what are these? */
 	snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006);
 	snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006);
 	snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006);
 	snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006);
 #endif
 
-	//snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */
+	/* OSS drivers set this. */
+	/* snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); */
+
 	/* Analog or Digital output */
 	snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf);
-	snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */
-	chip->spdif_enable = 0; /* Set digital SPDIF output off */
-	//snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */
-	//snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */
+	/* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers.
+	 * Use 0x000f0000 for surround71
+	 */
+	snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000);
 
-	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* goes to 0x40c80000 when doing SPDIF IN/OUT */
-	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* (Mute) CAPTURE feedback into PLAYBACK volume. Only lower 16 bits matter. */
-	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume */
-	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */
+	chip->spdif_enable = 0; /* Set digital SPDIF output off */
+	/*snd_ca0106_ptr_write(chip, 0x45, 0, 0);*/ /* Analogue out */
+	/*snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00);*/ /* Digital out */
+
+	/* goes to 0x40c80000 when doing SPDIF IN/OUT */
+	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000);
+	/* (Mute) CAPTURE feedback into PLAYBACK volume.
+	 * Only lower 16 bits matter.
+	 */
+	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff);
+	/* SPDIF IN Volume */
+	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000);
+	/* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */
+	snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000);
+
 	snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410);
 	snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676);
 	snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410);
 	snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676);
-	for(ch = 0; ch < 4; ch++) {
-		snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); /* Only high 16 bits matter */
+
+	for (ch = 0; ch < 4; ch++) {
+		/* Only high 16 bits matter */
+		snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030);
 		snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030);
-		//snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); /* Mute */
-		//snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); /* Mute */
-		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */
-		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */
+#if 0 /* Mute */
+		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040);
+		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040);
+		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff);
+		snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff);
+#endif
 	}
 	if (chip->details->i2c_adc == 1) {
 	        /* Select MIC, Line in, TAD in, AUX in */
 	        snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
 		/* Default to CAPTURE_SOURCE to i2s in */
-		chip->capture_source = 3;
+		if (!resume)
+			chip->capture_source = 3;
 	} else if (chip->details->ac97 == 1) {
 	        /* Default to AC97 in */
 	        snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4);
 		/* Default to CAPTURE_SOURCE to AC97 in */
-		chip->capture_source = 4;
+		if (!resume)
+			chip->capture_source = 4;
 	} else {
 	        /* Select MIC, Line in, TAD in, AUX in */
 	        snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4);
 		/* Default to Set CAPTURE_SOURCE to i2s in */
-		chip->capture_source = 3;
+		if (!resume)
+			chip->capture_source = 3;
 	}
 
-        if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */
-		/* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
+	if (chip->details->gpio_type == 2) {
+		/* The SB0438 use GPIO differently. */
+		/* FIXME: Still need to find out what the other GPIO bits do.
+		 * E.g. For digital spdif out.
+		 */
 		outl(0x0, chip->port+GPIO);
-		//outl(0x00f0e000, chip->port+GPIO); /* Analog */
+		/* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */
 		outl(0x005f5301, chip->port+GPIO); /* Analog */
-	} else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */
-		/* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
+	} else if (chip->details->gpio_type == 1) {
+		/* The SB0410 and SB0413 use GPIO differently. */
+		/* FIXME: Still need to find out what the other GPIO bits do.
+		 * E.g. For digital spdif out.
+		 */
 		outl(0x0, chip->port+GPIO);
-		//outl(0x00f0e000, chip->port+GPIO); /* Analog */
+		/* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */
 		outl(0x005f5301, chip->port+GPIO); /* Analog */
 	} else {
 		outl(0x0, chip->port+GPIO);
 		outl(0x005f03a3, chip->port+GPIO); /* Analog */
-		//outl(0x005f02a2, chip->port+GPIO);   /* SPDIF */
+		/* outl(0x005f02a2, chip->port+GPIO); */ /* SPDIF */
 	}
 	snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */
 
-	//outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG);
-	//outl(0x00001409, chip->port+HCFG); /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */
-	//outl(0x00000009, chip->port+HCFG);
-	outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */
+	/* outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); */
+	/* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */
+	/* outl(0x00001409, chip->port+HCFG); */
+	/* outl(0x00000009, chip->port+HCFG); */
+	/* AC97 2.0, Enable outputs. */
+	outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG);
 
-        if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */
+	if (chip->details->i2c_adc == 1) {
+		/* The SB0410 and SB0413 use I2C to control ADC. */
 		int size, n;
 
 		size = ARRAY_SIZE(i2c_adc_init);
-                //snd_printk("I2C:array size=0x%x\n", size);
-		for (n=0; n < size; n++) {
-			snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]);
+		/* snd_printk("I2C:array size=0x%x\n", size); */
+		for (n = 0; n < size; n++)
+			snd_ca0106_i2c_write(chip, i2c_adc_init[n][0],
+					     i2c_adc_init[n][1]);
+		for (n = 0; n < 4; n++) {
+			chip->i2c_capture_volume[n][0] = 0xcf;
+			chip->i2c_capture_volume[n][1] = 0xcf;
 		}
-		for (n=0; n < 4; n++) {
-			chip->i2c_capture_volume[n][0]= 0xcf;
-			chip->i2c_capture_volume[n][1]= 0xcf;
-		}
-		chip->i2c_capture_source=2; /* Line in */
-	        //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */
+		chip->i2c_capture_source = 2; /* Line in */
+		/* Enable Line-in capture. MIC in currently untested. */
+		/* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */
 	}
-        if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */
+
+	if (chip->details->spi_dac == 1) {
+		/* The SB0570 use SPI to control DAC. */
 		int size, n;
 
 		size = ARRAY_SIZE(spi_dac_init);
@@ -1530,9 +1496,112 @@
 				chip->spi_dac_reg[reg] = spi_dac_init[n];
 		}
 	}
+}
 
-	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
-				  chip, &ops)) < 0) {
+static void ca0106_stop_chip(struct snd_ca0106 *chip)
+{
+	/* disable interrupts */
+	snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0);
+	outl(0, chip->port + INTE);
+	snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0);
+	udelay(1000);
+	/* disable audio */
+	/* outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); */
+	outl(0, chip->port + HCFG);
+	/* FIXME: We need to stop and DMA transfers here.
+	 *        But as I am not sure how yet, we cannot from the dma pages.
+	 * So we can fix: snd-malloc: Memory leak?  pages not freed = 8
+	 */
+}
+
+static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
+					 struct pci_dev *pci,
+					 struct snd_ca0106 **rchip)
+{
+	struct snd_ca0106 *chip;
+	struct snd_ca0106_details *c;
+	int err;
+	static struct snd_device_ops ops = {
+		.dev_free = snd_ca0106_dev_free,
+	};
+
+	*rchip = NULL;
+
+	err = pci_enable_device(pci);
+	if (err < 0)
+		return err;
+	if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) {
+		printk(KERN_ERR "error to set 32bit mask DMA\n");
+		pci_disable_device(pci);
+		return -ENXIO;
+	}
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL) {
+		pci_disable_device(pci);
+		return -ENOMEM;
+	}
+
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+
+	spin_lock_init(&chip->emu_lock);
+
+	chip->port = pci_resource_start(pci, 0);
+	chip->res_port = request_region(chip->port, 0x20, "snd_ca0106");
+	if (!chip->res_port) {
+		snd_ca0106_free(chip);
+		printk(KERN_ERR "cannot allocate the port\n");
+		return -EBUSY;
+	}
+
+	if (request_irq(pci->irq, snd_ca0106_interrupt,
+			IRQF_SHARED, "snd_ca0106", chip)) {
+		snd_ca0106_free(chip);
+		printk(KERN_ERR "cannot grab irq\n");
+		return -EBUSY;
+	}
+	chip->irq = pci->irq;
+
+	/* This stores the periods table. */
+	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
+				1024, &chip->buffer) < 0) {
+		snd_ca0106_free(chip);
+		return -ENOMEM;
+	}
+
+	pci_set_master(pci);
+	/* read serial */
+	pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
+	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
+	printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n",
+	       chip->model, pci->revision, chip->serial);
+	strcpy(card->driver, "CA0106");
+	strcpy(card->shortname, "CA0106");
+
+	for (c = ca0106_chip_details; c->serial; c++) {
+		if (subsystem[dev]) {
+			if (c->serial == subsystem[dev])
+				break;
+		} else if (c->serial == chip->serial)
+			break;
+	}
+	chip->details = c;
+	if (subsystem[dev]) {
+		printk(KERN_INFO "snd-ca0106: Sound card name=%s, "
+		       "subsystem=0x%x. Forced to subsystem=0x%x\n",
+		       c->name, chip->serial, subsystem[dev]);
+	}
+
+	sprintf(card->longname, "%s at 0x%lx irq %i",
+		c->name, chip->port, chip->irq);
+
+	ca0106_init_chip(chip, 0);
+
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+	if (err < 0) {
 		snd_ca0106_free(chip);
 		return err;
 	}
@@ -1629,7 +1698,7 @@
 	static int dev;
 	struct snd_card *card;
 	struct snd_ca0106 *chip;
-	int err;
+	int i, err;
 
 	if (dev >= SNDRV_CARDS)
 		return -ENODEV;
@@ -1642,44 +1711,31 @@
 	if (card == NULL)
 		return -ENOMEM;
 
-	if ((err = snd_ca0106_create(dev, card, pci, &chip)) < 0) {
-		snd_card_free(card);
-		return err;
+	err = snd_ca0106_create(dev, card, pci, &chip);
+	if (err < 0)
+		goto error;
+	card->private_data = chip;
+
+	for (i = 0; i < 4; i++) {
+		err = snd_ca0106_pcm(chip, i);
+		if (err < 0)
+			goto error;
 	}
 
-	if ((err = snd_ca0106_pcm(chip, 0, NULL)) < 0) {
-		snd_card_free(card);
-		return err;
+	if (chip->details->ac97 == 1) {
+		/* The SB0410 and SB0413 do not have an AC97 chip. */
+		err = snd_ca0106_ac97(chip);
+		if (err < 0)
+			goto error;
 	}
-	if ((err = snd_ca0106_pcm(chip, 1, NULL)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	if ((err = snd_ca0106_pcm(chip, 2, NULL)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	if ((err = snd_ca0106_pcm(chip, 3, NULL)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-        if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */
-		if ((err = snd_ca0106_ac97(chip)) < 0) {
-			snd_card_free(card);
-			return err;
-		}
-	}
-	if ((err = snd_ca0106_mixer(chip)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	err = snd_ca0106_mixer(chip);
+	if (err < 0)
+		goto error;
 
 	snd_printdd("ca0106: probe for MIDI channel A ...");
-	if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) {
-		snd_card_free(card);
-		snd_printdd(" failed, err=0x%x\n",err);
-		return err;
-	}
+	err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A);
+	if (err < 0)
+		goto error;
 	snd_printdd(" done.\n");
 
 #ifdef CONFIG_PROC_FS
@@ -1688,14 +1744,17 @@
 
 	snd_card_set_dev(card, &pci->dev);
 
-	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_ca0106_remove(struct pci_dev *pci)
@@ -1704,6 +1763,59 @@
 	pci_set_drvdata(pci, NULL);
 }
 
+#ifdef CONFIG_PM
+static int snd_ca0106_suspend(struct pci_dev *pci, pm_message_t state)
+{
+	struct snd_card *card = pci_get_drvdata(pci);
+	struct snd_ca0106 *chip = card->private_data;
+	int i;
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	for (i = 0; i < 4; i++)
+		snd_pcm_suspend_all(chip->pcm[i]);
+	if (chip->details->ac97)
+		snd_ac97_suspend(chip->ac97);
+	snd_ca0106_mixer_suspend(chip);
+
+	ca0106_stop_chip(chip);
+
+	pci_disable_device(pci);
+	pci_save_state(pci);
+	pci_set_power_state(pci, pci_choose_state(pci, state));
+	return 0;
+}
+
+static int snd_ca0106_resume(struct pci_dev *pci)
+{
+	struct snd_card *card = pci_get_drvdata(pci);
+	struct snd_ca0106 *chip = card->private_data;
+	int i;
+
+	pci_set_power_state(pci, PCI_D0);
+	pci_restore_state(pci);
+
+	if (pci_enable_device(pci) < 0) {
+		snd_card_disconnect(card);
+		return -EIO;
+	}
+
+	pci_set_master(pci);
+
+	ca0106_init_chip(chip, 1);
+
+	if (chip->details->ac97)
+		snd_ac97_resume(chip->ac97);
+	snd_ca0106_mixer_resume(chip);
+	if (chip->details->spi_dac) {
+		for (i = 0; i < ARRAY_SIZE(chip->spi_dac_reg); i++)
+			snd_ca0106_spi_write(chip, chip->spi_dac_reg[i]);
+	}
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	return 0;
+}
+#endif
+
 // PCI IDs
 static struct pci_device_id snd_ca0106_ids[] = {
 	{ 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	/* Audigy LS or Live 24bit */
@@ -1717,6 +1829,10 @@
 	.id_table = snd_ca0106_ids,
 	.probe = snd_ca0106_probe,
 	.remove = __devexit_p(snd_ca0106_remove),
+#ifdef CONFIG_PM
+	.suspend = snd_ca0106_suspend,
+	.resume = snd_ca0106_resume,
+#endif
 };
 
 // initialization of the module
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 3025ed1..ad28887 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -75,6 +75,84 @@
 
 #include "ca0106.h"
 
+static void ca0106_spdif_enable(struct snd_ca0106 *emu)
+{
+	unsigned int val;
+
+	if (emu->spdif_enable) {
+		/* Digital */
+		snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
+		snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000);
+		val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000;
+		snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val);
+		val = inl(emu->port + GPIO) & ~0x101;
+		outl(val, emu->port + GPIO);
+
+	} else {
+		/* Analog */
+		snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
+		snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000);
+		val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000;
+		snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val);
+		val = inl(emu->port + GPIO) | 0x101;
+		outl(val, emu->port + GPIO);
+	}
+}
+
+static void ca0106_set_capture_source(struct snd_ca0106 *emu)
+{
+	unsigned int val = emu->capture_source;
+	unsigned int source, mask;
+	source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
+	mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff;
+	snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask);
+}
+
+static void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu,
+					  unsigned int val, int force)
+{
+	unsigned int ngain, ogain;
+	u32 source;
+
+	snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
+	ngain = emu->i2c_capture_volume[val][0]; /* Left */
+	ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
+	if (force || ngain != ogain)
+		snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff);
+	ngain = emu->i2c_capture_volume[val][1]; /* Right */
+	ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
+	if (force || ngain != ogain)
+		snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff);
+	source = 1 << val;
+	snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
+	emu->i2c_capture_source = val;
+}
+
+static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu)
+{
+	u32 tmp;
+
+	if (emu->capture_mic_line_in) {
+		/* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */
+		tmp = inl(emu->port+GPIO) & ~0x400;
+		tmp = tmp | 0x400;
+		outl(tmp, emu->port+GPIO);
+		/* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */
+	} else {
+		/* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */
+		tmp = inl(emu->port+GPIO) & ~0x400;
+		outl(tmp, emu->port+GPIO);
+		/* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */
+	}
+}
+
+static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx)
+{
+	snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_str_bits[idx]);
+}
+
+/*
+ */
 static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
 static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
 
@@ -95,30 +173,12 @@
 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 	unsigned int val;
 	int change = 0;
-	u32 mask;
 
 	val = !!ucontrol->value.integer.value[0];
 	change = (emu->spdif_enable != val);
 	if (change) {
 		emu->spdif_enable = val;
-		if (val) {
-			/* Digital */
-			snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
-			snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000);
-			snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
-				snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000);
-			mask = inl(emu->port + GPIO) & ~0x101;
-			outl(mask, emu->port + GPIO);
-
-		} else {
-			/* Analog */
-			snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
-			snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000);
-			snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
-				snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000);
-			mask = inl(emu->port + GPIO) | 0x101;
-			outl(mask, emu->port + GPIO);
-		}
+		ca0106_spdif_enable(emu);
 	}
         return change;
 }
@@ -154,8 +214,6 @@
 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 	unsigned int val;
 	int change = 0;
-	u32 mask;
-	u32 source;
 
 	val = ucontrol->value.enumerated.item[0] ;
 	if (val >= 6)
@@ -163,9 +221,7 @@
 	change = (emu->capture_source != val);
 	if (change) {
 		emu->capture_source = val;
-		source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
-		mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff;
-		snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask);
+		ca0106_set_capture_source(emu);
 	}
         return change;
 }
@@ -200,9 +256,7 @@
 {
 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 	unsigned int source_id;
-	unsigned int ngain, ogain;
 	int change = 0;
-	u32 source;
 	/* If the capture source has changed,
 	 * update the capture volume from the cached value
 	 * for the particular source.
@@ -212,18 +266,7 @@
 		return -EINVAL;
 	change = (emu->i2c_capture_source != source_id);
 	if (change) {
-		snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
-		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
-		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
-		if (ngain != ogain)
-			snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
-		ngain = emu->i2c_capture_volume[source_id][1]; /* Left */
-		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */
-		if (ngain != ogain)
-			snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
-		source = 1 << source_id;
-		snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
-		emu->i2c_capture_source = source_id;
+		ca0106_set_i2c_capture_source(emu, source_id, 0);
 	}
         return change;
 }
@@ -271,7 +314,6 @@
 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 	unsigned int val;
 	int change = 0;
-	u32 tmp;
 
 	val = ucontrol->value.enumerated.item[0] ;
 	if (val > 1)
@@ -279,18 +321,7 @@
 	change = (emu->capture_mic_line_in != val);
 	if (change) {
 		emu->capture_mic_line_in = val;
-		if (val) {
-			//snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
-			tmp = inl(emu->port+GPIO) & ~0x400;
-			tmp = tmp | 0x400;
-			outl(tmp, emu->port+GPIO);
-			//snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC);
-		} else {
-			//snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
-			tmp = inl(emu->port+GPIO) & ~0x400;
-			outl(tmp, emu->port+GPIO);
-			//snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN);
-		}
+		ca0106_set_capture_mic_line_in(emu);
 	}
         return change;
 }
@@ -322,16 +353,33 @@
 	return 0;
 }
 
-static int snd_ca0106_spdif_get(struct snd_kcontrol *kcontrol,
+static void decode_spdif_bits(unsigned char *status, unsigned int bits)
+{
+	status[0] = (bits >> 0) & 0xff;
+	status[1] = (bits >> 8) & 0xff;
+	status[2] = (bits >> 16) & 0xff;
+	status[3] = (bits >> 24) & 0xff;
+}
+
+static int snd_ca0106_spdif_get_default(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 
-	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
-	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
-	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
-	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
+	decode_spdif_bits(ucontrol->value.iec958.status,
+			  emu->spdif_bits[idx]);
+        return 0;
+}
+
+static int snd_ca0106_spdif_get_stream(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+	decode_spdif_bits(ucontrol->value.iec958.status,
+			  emu->spdif_str_bits[idx]);
         return 0;
 }
 
@@ -345,24 +393,48 @@
         return 0;
 }
 
-static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol,
+static unsigned int encode_spdif_bits(unsigned char *status)
+{
+	return ((unsigned int)status[0] << 0) |
+		((unsigned int)status[1] << 8) |
+		((unsigned int)status[2] << 16) |
+		((unsigned int)status[3] << 24);
+}
+
+static int snd_ca0106_spdif_put_default(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	int change;
 	unsigned int val;
 
-	val = (ucontrol->value.iec958.status[0] << 0) |
-	      (ucontrol->value.iec958.status[1] << 8) |
-	      (ucontrol->value.iec958.status[2] << 16) |
-	      (ucontrol->value.iec958.status[3] << 24);
-	change = val != emu->spdif_bits[idx];
-	if (change) {
-		snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val);
+	val = encode_spdif_bits(ucontrol->value.iec958.status);
+	if (val != emu->spdif_bits[idx]) {
 		emu->spdif_bits[idx] = val;
+		/* FIXME: this isn't safe, but needed to keep the compatibility
+		 * with older alsa-lib config
+		 */
+		emu->spdif_str_bits[idx] = val;
+		ca0106_set_spdif_bits(emu, idx);
+		return 1;
 	}
-        return change;
+	return 0;
+}
+
+static int snd_ca0106_spdif_put_stream(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	unsigned int val;
+
+	val = encode_spdif_bits(ucontrol->value.iec958.status);
+	if (val != emu->spdif_str_bits[idx]) {
+		emu->spdif_str_bits[idx] = val;
+		ca0106_set_spdif_bits(emu, idx);
+		return 1;
+	}
+        return 0;
 }
 
 static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol,
@@ -573,8 +645,16 @@
 		.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
 		.count =	4,
 		.info =         snd_ca0106_spdif_info,
-		.get =          snd_ca0106_spdif_get,
-		.put =          snd_ca0106_spdif_put
+		.get =          snd_ca0106_spdif_get_default,
+		.put =          snd_ca0106_spdif_put_default
+	},
+	{
+		.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+		.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
+		.count =	4,
+		.info =         snd_ca0106_spdif_info,
+		.get =          snd_ca0106_spdif_get_stream,
+		.put =          snd_ca0106_spdif_put_stream
 	},
 };
 
@@ -773,3 +853,50 @@
         return 0;
 }
 
+#ifdef CONFIG_PM
+struct ca0106_vol_tbl {
+	unsigned int channel_id;
+	unsigned int reg;
+};
+
+static struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = {
+	{ CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 },
+	{ CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 },
+	{ CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 },
+	{ CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 },
+	{ CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 },
+	{ CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 },
+	{ CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 },
+	{ CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 },
+	{ 1, CAPTURE_CONTROL },
+};
+
+void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip)
+{
+	int i;
+
+	/* save volumes */
+	for (i = 0; i < NUM_SAVED_VOLUMES; i++)
+		chip->saved_vol[i] =
+			snd_ca0106_ptr_read(chip, saved_volumes[i].reg,
+					    saved_volumes[i].channel_id);
+}
+
+void snd_ca0106_mixer_resume(struct snd_ca0106  *chip)
+{
+	int i;
+
+	for (i = 0; i < NUM_SAVED_VOLUMES; i++)
+		snd_ca0106_ptr_write(chip, saved_volumes[i].reg,
+				     saved_volumes[i].channel_id,
+				     chip->saved_vol[i]);
+
+	ca0106_spdif_enable(chip);
+	ca0106_set_capture_source(chip);
+	ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1);
+	for (i = 0; i < 4; i++)
+		ca0106_set_spdif_bits(chip, i);
+	if (chip->details->i2c_adc)
+		ca0106_set_capture_mic_line_in(chip);
+}
+#endif /* CONFIG_PM */
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index fb6dc39..8ab07aa 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -3640,7 +3640,10 @@
 {
 	struct snd_card *card = pci_get_drvdata(pci);
 	struct snd_cs46xx *chip = card->private_data;
-	int i, amp_saved;
+	int amp_saved;
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	int i;
+#endif
 
 	pci_set_power_state(pci, PCI_D0);
 	pci_restore_state(pci);
diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile
index bb3d57e..fda7a94 100644
--- a/sound/pci/cs5535audio/Makefile
+++ b/sound/pci/cs5535audio/Makefile
@@ -4,6 +4,9 @@
 
 snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o
 snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o
+ifdef CONFIG_MGEODE_LX
+snd-cs5535audio-$(CONFIG_OLPC) += cs5535audio_olpc.o
+endif
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 1d8b160..826e6de 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -159,10 +159,14 @@
 		return err;
 
 	memset(&ac97, 0, sizeof(ac97));
-	ac97.scaps = AC97_SCAP_AUDIO|AC97_SCAP_SKIP_MODEM;
+	ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM
+			| AC97_SCAP_POWER_SAVE;
 	ac97.private_data = cs5535au;
 	ac97.pci = cs5535au->pci;
 
+	/* set any OLPC-specific scaps */
+	olpc_prequirks(card, &ac97);
+
 	if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) {
 		snd_printk(KERN_ERR "mixer failed\n");
 		return err;
@@ -170,6 +174,12 @@
 
 	snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk);
 
+	err = olpc_quirks(card, cs5535au->ac97);
+	if (err < 0) {
+		snd_printk(KERN_ERR "olpc quirks failed\n");
+		return err;
+	}
+
 	return 0;
 }
 
diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h
index 66bae76..7a298ac 100644
--- a/sound/pci/cs5535audio/cs5535audio.h
+++ b/sound/pci/cs5535audio/cs5535audio.h
@@ -78,6 +78,7 @@
 	unsigned int buf_addr, buf_bytes;
 	unsigned int period_bytes, periods;
 	u32 saved_prd;
+	int pcm_open_flag;
 };
 
 struct cs5535audio {
@@ -93,8 +94,46 @@
 	struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS];
 };
 
+#ifdef CONFIG_PM
 int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state);
 int snd_cs5535audio_resume(struct pci_dev *pci);
+#endif
+
+#if defined(CONFIG_OLPC) && defined(CONFIG_MGEODE_LX)
+void __devinit olpc_prequirks(struct snd_card *card,
+		struct snd_ac97_template *ac97);
+int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97);
+void olpc_analog_input(struct snd_ac97 *ac97, int on);
+void olpc_mic_bias(struct snd_ac97 *ac97, int on);
+
+static inline void olpc_capture_open(struct snd_ac97 *ac97)
+{
+	/* default to Analog Input off */
+	olpc_analog_input(ac97, 0);
+	/* enable MIC Bias for recording */
+	olpc_mic_bias(ac97, 1);
+}
+
+static inline void olpc_capture_close(struct snd_ac97 *ac97)
+{
+	/* disable Analog Input */
+	olpc_analog_input(ac97, 0);
+	/* disable the MIC Bias (so the recording LED turns off) */
+	olpc_mic_bias(ac97, 0);
+}
+#else
+static inline void olpc_prequirks(struct snd_card *card,
+		struct snd_ac97_template *ac97) { }
+static inline int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
+{
+	return 0;
+}
+static inline void olpc_analog_input(struct snd_ac97 *ac97, int on) { }
+static inline void olpc_mic_bias(struct snd_ac97 *ac97, int on) { }
+static inline void olpc_capture_open(struct snd_ac97 *ac97) { }
+static inline void olpc_capture_close(struct snd_ac97 *ac97) { }
+#endif
+
 int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio);
 
 #endif /* __SOUND_CS5535AUDIO_H */
diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c
new file mode 100644
index 0000000..5c68143
--- /dev/null
+++ b/sound/pci/cs5535audio/cs5535audio_olpc.c
@@ -0,0 +1,179 @@
+/*
+ * OLPC XO-1 additional sound features
+ *
+ * Copyright © 2006  Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright © 2007-2008  Andres Salomon <dilinger@debian.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 <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/ac97_codec.h>
+
+#include <asm/olpc.h>
+#include "cs5535audio.h"
+
+/*
+ * OLPC has an additional feature on top of the regular AD1888 codec features.
+ * It has an Analog Input mode that is switched into (after disabling the
+ * High Pass Filter) via GPIO.  It is supported on B2 and later models.
+ */
+void olpc_analog_input(struct snd_ac97 *ac97, int on)
+{
+	int err;
+
+	if (!machine_is_olpc())
+		return;
+
+	/* update the High Pass Filter (via AC97_AD_TEST2) */
+	err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
+			1 << AC97_AD_HPFD_SHIFT, on << AC97_AD_HPFD_SHIFT);
+	if (err < 0) {
+		snd_printk(KERN_ERR "setting High Pass Filter - %d\n", err);
+		return;
+	}
+
+	/* set Analog Input through GPIO */
+	if (on)
+		geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL);
+	else
+		geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL);
+}
+
+/*
+ * OLPC XO-1's V_REFOUT is a mic bias enable.
+ */
+void olpc_mic_bias(struct snd_ac97 *ac97, int on)
+{
+	int err;
+
+	if (!machine_is_olpc())
+		return;
+
+	on = on ? 0 : 1;
+	err = snd_ac97_update_bits(ac97, AC97_AD_MISC,
+			1 << AC97_AD_VREFD_SHIFT, on << AC97_AD_VREFD_SHIFT);
+	if (err < 0)
+		snd_printk(KERN_ERR "setting MIC Bias - %d\n", err);
+}
+
+static int olpc_dc_info(struct snd_kcontrol *kctl,
+		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 olpc_dc_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v)
+{
+	v->value.integer.value[0] = geode_gpio_isset(OLPC_GPIO_MIC_AC,
+			GPIO_OUTPUT_VAL);
+	return 0;
+}
+
+static int olpc_dc_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v)
+{
+	struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl);
+
+	olpc_analog_input(cs5535au->ac97, v->value.integer.value[0]);
+	return 1;
+}
+
+static int olpc_mic_info(struct snd_kcontrol *kctl,
+		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 olpc_mic_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v)
+{
+	struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl);
+	struct snd_ac97 *ac97 = cs5535au->ac97;
+	int i;
+
+	i = (snd_ac97_read(ac97, AC97_AD_MISC) >> AC97_AD_VREFD_SHIFT) & 0x1;
+	v->value.integer.value[0] = i ? 0 : 1;
+	return 0;
+}
+
+static int olpc_mic_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v)
+{
+	struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl);
+
+	olpc_mic_bias(cs5535au->ac97, v->value.integer.value[0]);
+	return 1;
+}
+
+static struct snd_kcontrol_new olpc_cs5535audio_ctls[] __devinitdata = {
+{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "DC Mode Enable",
+	.info = olpc_dc_info,
+	.get = olpc_dc_get,
+	.put = olpc_dc_put,
+	.private_value = 0,
+},
+{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "MIC Bias Enable",
+	.info = olpc_mic_info,
+	.get = olpc_mic_get,
+	.put = olpc_mic_put,
+	.private_value = 0,
+},
+};
+
+void __devinit olpc_prequirks(struct snd_card *card,
+		struct snd_ac97_template *ac97)
+{
+	if (!machine_is_olpc())
+		return;
+
+	/* invert EAPD if on an OLPC B3 or higher */
+	if (olpc_board_at_least(olpc_board_pre(0xb3)))
+		ac97->scaps |= AC97_SCAP_INV_EAPD;
+}
+
+int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
+{
+	struct snd_ctl_elem_id elem;
+	int i, err;
+
+	if (!machine_is_olpc())
+		return 0;
+
+	/* drop the original AD1888 HPF control */
+	memset(&elem, 0, sizeof(elem));
+	elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	strncpy(elem.name, "High Pass Filter Enable", sizeof(elem.name));
+	snd_ctl_remove_id(card, &elem);
+
+	/* drop the original V_REFOUT control */
+	memset(&elem, 0, sizeof(elem));
+	elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	strncpy(elem.name, "V_REFOUT Enable", sizeof(elem.name));
+	snd_ctl_remove_id(card, &elem);
+
+	/* add the OLPC-specific controls */
+	for (i = 0; i < ARRAY_SIZE(olpc_cs5535audio_ctls); i++) {
+		err = snd_ctl_add(card, snd_ctl_new1(&olpc_cs5535audio_ctls[i],
+				ac97->private_data));
+		if (err < 0)
+			return err;
+	}
+
+	/* turn off the mic by default */
+	olpc_mic_bias(ac97, 0);
+	return 0;
+}
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c
index cdcda87..0f48a87 100644
--- a/sound/pci/cs5535audio/cs5535audio_pcm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pcm.c
@@ -260,6 +260,9 @@
 	err = cs5535audio_build_dma_packets(cs5535au, dma, substream,
 					    params_periods(hw_params),
 					    params_period_bytes(hw_params));
+	if (!err)
+		dma->pcm_open_flag = 1;
+
 	return err;
 }
 
@@ -268,6 +271,15 @@
 	struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
 	struct cs5535audio_dma *dma = substream->runtime->private_data;
 
+	if (dma->pcm_open_flag) {
+		if (substream == cs5535au->playback_substream)
+			snd_ac97_update_power(cs5535au->ac97,
+					AC97_PCM_FRONT_DAC_RATE, 0);
+		else
+			snd_ac97_update_power(cs5535au->ac97,
+					AC97_PCM_LR_ADC_RATE, 0);
+		dma->pcm_open_flag = 0;
+	}
 	cs5535audio_clear_dma_packets(cs5535au, dma, substream);
 	return snd_pcm_lib_free_pages(substream);
 }
@@ -351,11 +363,14 @@
 	if ((err = snd_pcm_hw_constraint_integer(runtime,
 					 SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
 		return err;
+	olpc_capture_open(cs5535au->ac97);
 	return 0;
 }
 
 static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream)
 {
+	struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
+	olpc_capture_close(cs5535au->ac97);
 	return 0;
 }
 
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index de5ee8f..7958006 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -69,7 +69,7 @@
  * EMU10K1 init / done
  *************************************************************************/
 
-void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int ch)
+void snd_emu10k1_voice_init(struct snd_emu10k1 *emu, int ch)
 {
 	snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0);
 	snd_emu10k1_ptr_write(emu, IP, ch, 0);
@@ -151,9 +151,9 @@
 	{ 0x12, 0x32 },  /* ALC Control 3 */
 	{ 0x13, 0x00 },  /* Noise gate control */
 	{ 0x14, 0xa6 },  /* Limiter control */
-	{ 0x15, ADC_MUX_2 },  /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */
+	{ 0x15, ADC_MUX_2 },  /* ADC Mixer control. Mic for A2ZS Notebook */
 };
-	
+
 static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
 {
 	unsigned int silent_page;
@@ -161,8 +161,8 @@
 	u32 tmp;
 
 	/* disable audio and lock cache */
-	outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE,
-	     emu->port + HCFG);
+	outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK |
+		HCFG_MUTEBUTTONENABLE, emu->port + HCFG);
 
 	/* reset recording buffers */
 	snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE);
@@ -179,7 +179,7 @@
 	snd_emu10k1_ptr_write(emu, SOLEL, 0, 0);
 	snd_emu10k1_ptr_write(emu, SOLEH, 0, 0);
 
-	if (emu->audigy){
+	if (emu->audigy) {
 		/* set SPDIF bypass mode */
 		snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT);
 		/* enable rear left + rear right AC97 slots */
@@ -197,12 +197,12 @@
 
 	if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
 		/* Hacks for Alice3 to work independent of haP16V driver */
-		//Setup SRCMulti_I2S SamplingRate
+		/* Setup SRCMulti_I2S SamplingRate */
 		tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
 		tmp &= 0xfffff1ff;
 		tmp |= (0x2<<9);
 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
-		
+
 		/* Setup SRCSel (Enable Spdif,I2S SRCMulti) */
 		snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14);
 		/* Setup SRCMulti Input Audio Enable */
@@ -217,7 +217,7 @@
 	if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */
 		/* Hacks for Alice3 to work independent of haP16V driver */
 		snd_printk(KERN_INFO "Audigy2 value: Special config.\n");
-		//Setup SRCMulti_I2S SamplingRate
+		/* Setup SRCMulti_I2S SamplingRate */
 		tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
 		tmp &= 0xfffff1ff;
 		tmp |= (0x2<<9);
@@ -270,13 +270,13 @@
 		size = ARRAY_SIZE(i2c_adc_init);
 		for (n = 0; n < size; n++)
 			snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]);
-		for (n=0; n < 4; n++) {
-			emu->i2c_capture_volume[n][0]= 0xcf;
-			emu->i2c_capture_volume[n][1]= 0xcf;
+		for (n = 0; n < 4; n++) {
+			emu->i2c_capture_volume[n][0] = 0xcf;
+			emu->i2c_capture_volume[n][1] = 0xcf;
 		}
 	}
 
-	
+
 	snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);
 	snd_emu10k1_ptr_write(emu, TCB, 0, 0);	/* taken from original driver */
 	snd_emu10k1_ptr_write(emu, TCBS, 0, 4);	/* taken from original driver */
@@ -313,7 +313,7 @@
 	    (emu->model == 0x21 && emu->revision < 6))
 		outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE, emu->port + HCFG);
 	else
-		// With on-chip joystick
+		/* With on-chip joystick */
 		outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
 
 	if (enable_ir) {	/* enable IR for SB Live */
@@ -335,9 +335,9 @@
 			outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG);
 			udelay(100);
 			outl(reg, emu->port + HCFG);
- 		}
+		}
 	}
-	
+
 	if (emu->card_capabilities->emu_model) {
 		;  /* Disable all access to A_IOCFG for the emu1010 */
 	} else if (emu->card_capabilities->i2c_adc) {
@@ -364,7 +364,7 @@
 		;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */
 	} else if (emu->audigy) {
 		outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);
- 
+
 		if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
 			/* Unmute Analog now.  Set GPO6 to 1 for Apollo.
 			 * This has to be done after init ALice3 I2SOut beyond 48KHz.
@@ -378,12 +378,12 @@
 			outl(inl(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG);
 		}
 	}
-	
+
 #if 0
 	{
 	unsigned int tmp;
 	/* FIXME: the following routine disables LiveDrive-II !! */
-	// TOSLink detection
+	/* TOSLink detection */
 	emu->tos_link = 0;
 	tmp = inl(emu->port + HCFG);
 	if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) {
@@ -400,7 +400,7 @@
 	snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE);
 }
 
-int snd_emu10k1_done(struct snd_emu10k1 * emu)
+int snd_emu10k1_done(struct snd_emu10k1 *emu)
 {
 	int ch;
 
@@ -495,7 +495,7 @@
 
 #define EC_LAST_PROMFILE_ADDR	0x2f
 
-#define EC_SERIALNUM_ADDR	0x30	/* First word of serial number.  The 
+#define EC_SERIALNUM_ADDR	0x30	/* First word of serial number.  The
 					 * can be up to 30 characters in length
 					 * and is stored as a NULL-terminated
 					 * ASCII string.  Any unused bytes must be
@@ -503,8 +503,8 @@
 #define EC_CHECKSUM_ADDR	0x3f	/* Location at which checksum is stored */
 
 
-/* Most of this stuff is pretty self-evident.  According to the hardware 
- * dudes, we need to leave the ADCCAL bit low in order to avoid a DC 
+/* Most of this stuff is pretty self-evident.  According to the hardware
+ * dudes, we need to leave the ADCCAL bit low in order to avoid a DC
  * offset problem.  Weird.
  */
 #define EC_RAW_RUN_MODE		(EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | \
@@ -523,7 +523,7 @@
  *  register.
  */
 
-static void snd_emu10k1_ecard_write(struct snd_emu10k1 * emu, unsigned int value)
+static void snd_emu10k1_ecard_write(struct snd_emu10k1 *emu, unsigned int value)
 {
 	unsigned short count;
 	unsigned int data;
@@ -561,7 +561,7 @@
  * channel.
  */
 
-static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 * emu,
+static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 *emu,
 					 unsigned short gain)
 {
 	unsigned int bit;
@@ -574,7 +574,7 @@
 
 	for (bit = (1 << 15); bit; bit >>= 1) {
 		unsigned int value;
-		
+
 		value = emu->ecard_ctrl & ~(EC_TRIM_CSN | EC_TRIM_SDATA);
 
 		if (gain & bit)
@@ -589,7 +589,7 @@
 	snd_emu10k1_ecard_write(emu, emu->ecard_ctrl);
 }
 
-static int snd_emu10k1_ecard_init(struct snd_emu10k1 * emu)
+static int snd_emu10k1_ecard_init(struct snd_emu10k1 *emu)
 {
 	unsigned int hc_value;
 
@@ -598,7 +598,7 @@
 			  EC_SPDIF0_SELECT(EC_DEFAULT_SPDIF0_SEL) |
 			  EC_SPDIF1_SELECT(EC_DEFAULT_SPDIF1_SEL);
 
-	/* Step 0: Set the codec type in the hardware control register 
+	/* Step 0: Set the codec type in the hardware control register
 	 * and enable audio output */
 	hc_value = inl(emu->port + HCFG);
 	outl(hc_value | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S, emu->port + HCFG);
@@ -629,7 +629,7 @@
 	return 0;
 }
 
-static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu)
+static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu)
 {
 	unsigned long special_port;
 	unsigned int value;
@@ -656,7 +656,7 @@
 	return 0;
 }
 
-static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * filename)
+static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filename)
 {
 	int err;
 	int n, i;
@@ -666,11 +666,12 @@
 	unsigned long flags;
 	const struct firmware *fw_entry;
 
-	if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) {
-		snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err);
+	err = request_firmware(&fw_entry, filename, &emu->pci->dev);
+	if (err != 0) {
+		snd_printk(KERN_ERR "firmware: %s not found. Err = %d\n", filename, err);
 		return err;
 	}
-	snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size);
+	snd_printk(KERN_INFO "firmware size = 0x%zx\n", fw_entry->size);
 
 	/* The FPGA is a Xilinx Spartan IIE XC2S50E */
 	/* GPIO7 -> FPGA PGMN
@@ -685,13 +686,13 @@
 	outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */
 	write_post = inl(emu->port + A_IOCFG);
 	udelay(100); /* Allow FPGA memory to clean */
-	for(n = 0; n < fw_entry->size; n++) {
-		value=fw_entry->data[n];	
-		for(i = 0; i < 8; i++) {
+	for (n = 0; n < fw_entry->size; n++) {
+		value = fw_entry->data[n];
+		for (i = 0; i < 8; i++) {
 			reg = 0x80;
 			if (value & 0x1)
 				reg = reg | 0x20;
-			value = value >> 1;   
+			value = value >> 1;
 			outl(reg, emu->port + A_IOCFG);
 			write_post = inl(emu->port + A_IOCFG);
 			outl(reg | 0x40, emu->port + A_IOCFG);
@@ -703,14 +704,14 @@
 	write_post = inl(emu->port + A_IOCFG);
 	spin_unlock_irqrestore(&emu->emu_lock, flags);
 
-        release_firmware(fw_entry);
+	release_firmware(fw_entry);
 	return 0;
 }
 
 static int emu1010_firmware_thread(void *data)
 {
-	struct snd_emu10k1 * emu = data;
-	int tmp,tmp2;
+	struct snd_emu10k1 *emu = data;
+	int tmp, tmp2;
 	int reg;
 	int err;
 
@@ -719,50 +720,50 @@
 		msleep_interruptible(1000);
 		if (kthread_should_stop())
 			break;
-		snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */
-		snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg ); /* OPTIONS: Which cards are attached to the EMU */
+		snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */
+		snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg); /* OPTIONS: Which cards are attached to the EMU */
 		if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
 			/* Audio Dock attached */
 			/* Return to Audio Dock programming mode */
 			snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
-			snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK );
+			snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK);
 			if (emu->card_capabilities->emu_model ==
 			    EMU_MODEL_EMU1010) {
-				if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
+				err = snd_emu1010_load_firmware(emu, DOCK_FILENAME);
+				if (err != 0)
 					continue;
-				}
 			} else if (emu->card_capabilities->emu_model ==
 				   EMU_MODEL_EMU1010B) {
-				if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+				err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME);
+				if (err != 0)
 					continue;
-				}
 			} else if (emu->card_capabilities->emu_model ==
 				   EMU_MODEL_EMU1616) {
-				if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+				err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME);
+				if (err != 0)
 					continue;
-				}
 			}
 
-			snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, 0 );
-			snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg );
-			snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg);
+			snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
+			snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg);
+			snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", reg);
 			/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
-			snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
-			snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg);
+			snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
+			snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg);
 			if ((reg & 0x1f) != 0x15) {
 				/* FPGA failed to be programmed */
-				snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg);
+				snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", reg);
 				continue;
 			}
 			snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
-			snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp );
-			snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 );
-			snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2);
+			snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
+			snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
+			snd_printk("Audio Dock ver:%d.%d\n", tmp, tmp2);
 			/* Sync clocking between 1010 and Dock */
 			/* Allow DLL to settle */
 			msleep(10);
 			/* Unmute all. Default is muted after a firmware load */
-			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
+			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
 		}
 	}
 	snd_printk(KERN_INFO "emu1010: firmware thread stopping\n");
@@ -800,10 +801,10 @@
  *		16 x 16-bit playback - snd_emu10k1_fx8010_playback_ops
  * 		16 x 32-bit capture - snd_emu10k1_capture_efx_ops
  */
-static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
+static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
 {
 	unsigned int i;
-	int tmp,tmp2;
+	int tmp, tmp2;
 	int reg;
 	int err;
 	const char *filename = NULL;
@@ -818,7 +819,7 @@
 	 * Lock Tank Memory Cache,
 	 * Mute all codecs.
 	 */
-	outl(0x0005a004, emu->port + HCFG); 
+	outl(0x0005a004, emu->port + HCFG);
 	/* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
 	 * Mute all codecs.
 	 */
@@ -829,25 +830,25 @@
 	outl(0x0005a000, emu->port + HCFG);
 
 	/* Disable 48Volt power to Audio Dock */
-	snd_emu1010_fpga_write(emu,  EMU_HANA_DOCK_PWR,  0 );
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
 
 	/* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
-	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
-	snd_printdd("reg1=0x%x\n",reg);
+	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
+	snd_printdd("reg1 = 0x%x\n", reg);
 	if ((reg & 0x3f) == 0x15) {
 		/* FPGA netlist already present so clear it */
 		/* Return to programming mode */
 
-		snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, 0x02 );
+		snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02);
 	}
-	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
-	snd_printdd("reg2=0x%x\n",reg);
+	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
+	snd_printdd("reg2 = 0x%x\n", reg);
 	if ((reg & 0x3f) == 0x15) {
 		/* FPGA failed to return to programming mode */
 		snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n");
 		return -ENODEV;
 	}
-	snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg);
+	snd_printk(KERN_INFO "emu1010: EMU_HANA_ID = 0x%x\n", reg);
 	switch (emu->card_capabilities->emu_model) {
 	case EMU_MODEL_EMU1010:
 		filename = HANA_FILENAME;
@@ -876,25 +877,25 @@
 	}
 
 	/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
-	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
+	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
 	if ((reg & 0x3f) != 0x15) {
 		/* FPGA failed to be programmed */
-		snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg);
+		snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", reg);
 		return -ENODEV;
 	}
 
 	snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n");
-	snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp );
-	snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 );
-	snd_printk("Hana ver:%d.%d\n",tmp ,tmp2);
+	snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp);
+	snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2);
+	snd_printk("emu1010: Hana version: %d.%d\n", tmp, tmp2);
 	/* Enable 48Volt power to Audio Dock */
-	snd_emu1010_fpga_write(emu,  EMU_HANA_DOCK_PWR,  EMU_HANA_DOCK_PWR_ON );
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON);
 
-	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
-	snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg);
-	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
-	snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg);
-	snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); 
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
+	snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg);
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
+	snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg);
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp);
 	/* Optical -> ADAT I/O  */
 	/* 0 : SPDIF
 	 * 1 : ADAT
@@ -904,41 +905,42 @@
 	tmp = 0;
 	tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) |
 		(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0);
-	snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp );
-	snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp );
+	snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
+	snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp);
 	/* Set no attenuation on Audio Dock pads. */
-	snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 );
+	snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00);
 	emu->emu1010.adc_pads = 0x00;
-	snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp );
+	snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp);
 	/* Unmute Audio dock DACs, Headphone source DAC-4. */
-	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 );
-	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 );
-	snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp );
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30);
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);
+	snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp);
 	/* DAC PADs. */
-	snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f );
+	snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f);
 	emu->emu1010.dac_pads = 0x0f;
-	snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp );
-	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 );
-	snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp );
+	snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp);
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30);
+	snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp);
 	/* SPDIF Format. Set Consumer mode, 24bit, copy enable */
-	snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 );
+	snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10);
 	/* MIDI routing */
-	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 );
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19);
 	/* Unknown. */
-	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c );
-	/* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c);
+	/* IRQ Enable: Alll on */
+	/* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); */
 	/* IRQ Enable: All off */
-	snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 );
+	snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00);
 
-	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg );
-	snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg);
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
+	snd_printk(KERN_INFO "emu1010: Card options3 = 0x%x\n", reg);
 	/* Default WCLK set to 48kHz. */
-	snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 );
+	snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00);
 	/* Word Clock source, Internal 48kHz x1 */
-	snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K );
-	//snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X );
+	snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K);
+	/* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */
 	/* Audio Dock LEDs. */
-	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 );
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);
 
 #if 0
 	/* For 96kHz */
@@ -992,7 +994,7 @@
 	 * Defaults only, users will set their own values anyways, let's
 	 * just copy/paste.
 	 */
-	
+
 	snd_emu1010_fpga_link_dst_src_write(emu,
 		EMU_DST_ALICE2_EMU32_8, EMU_SRC_DOCK_MIC_A1);
 	snd_emu1010_fpga_link_dst_src_write(emu,
@@ -1037,19 +1039,19 @@
 	snd_emu1010_fpga_link_dst_src_write(emu,
 		EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2);
 #endif
-	for (i = 0;i < 0x20; i++ ) {
-		/* AudioDock Elink <-  Silence */
-		snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE);
+	for (i = 0; i < 0x20; i++) {
+		/* AudioDock Elink <- Silence */
+		snd_emu1010_fpga_link_dst_src_write(emu, 0x0100 + i, EMU_SRC_SILENCE);
 	}
-	for (i = 0;i < 4; i++) {
+	for (i = 0; i < 4; i++) {
 		/* Hana SPDIF Out <- Silence */
-		snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE);
+		snd_emu1010_fpga_link_dst_src_write(emu, 0x0200 + i, EMU_SRC_SILENCE);
 	}
-	for (i = 0;i < 7; i++) {
+	for (i = 0; i < 7; i++) {
 		/* Hamoa DAC <- Silence */
-		snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE);
+		snd_emu1010_fpga_link_dst_src_write(emu, 0x0300 + i, EMU_SRC_SILENCE);
 	}
-	for (i = 0;i < 7; i++) {
+	for (i = 0; i < 7; i++) {
 		/* Hana ADAT Out <- Silence */
 		snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE);
 	}
@@ -1065,30 +1067,30 @@
 		EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1);
 	snd_emu1010_fpga_link_dst_src_write(emu,
 		EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1);
-	snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all
+	snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01); /* Unmute all */
 
-	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp );
-	
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp);
+
 	/* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave,
 	 * Lock Sound Memory Cache, Lock Tank Memory Cache,
 	 * Mute all codecs.
 	 */
-	outl(0x0000a000, emu->port + HCFG); 
+	outl(0x0000a000, emu->port + HCFG);
 	/* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave,
 	 * Lock Sound Memory Cache, Lock Tank Memory Cache,
 	 * Un-Mute all codecs.
 	 */
 	outl(0x0000a001, emu->port + HCFG);
- 
+
 	/* Initial boot complete. Now patches */
 
-	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp );
-	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */
-	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */
-	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */
-	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */
-	snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); 
-	snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif  (or 0x11 for aes/ebu) */
+	snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp);
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */
+	snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */
+	snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp);
+	snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); /* SPDIF Format spdif  (or 0x11 for aes/ebu) */
 
 	/* Start Micro/Audio Dock firmware loader thread */
 	if (!emu->emu1010.firmware_thread) {
@@ -1218,20 +1220,20 @@
 		emu->emu1010.output_source[23] = 28;
 	}
 	/* TEMP: Select SPDIF in/out */
-	//snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */
+	/* snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); */ /* Output spdif */
 
 	/* TEMP: Select 48kHz SPDIF out */
 	snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */
 	snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */
 	/* Word Clock source, Internal 48kHz x1 */
-	snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K );
-	//snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X );
+	snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K);
+	/* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */
 	emu->emu1010.internal_clock = 1; /* 48000 */
-	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */
+	snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); /* Set LEDs on Audio Dock */
 	snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */
-	//snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */
-	//snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */
-	//snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */
+	/* snd_emu1010_fpga_write(emu, 0x7, 0x0); */ /* Mute all */
+	/* snd_emu1010_fpga_write(emu, 0x7, 0x1); */ /* Unmute all */
+	/* snd_emu1010_fpga_write(emu, 0xe, 0x12); */ /* Set LEDs on Audio Dock */
 
 	return 0;
 }
@@ -1247,13 +1249,13 @@
 static int snd_emu10k1_free(struct snd_emu10k1 *emu)
 {
 	if (emu->port) {	/* avoid access to already used hardware */
-	       	snd_emu10k1_fx8010_tram_setup(emu, 0);
+		snd_emu10k1_fx8010_tram_setup(emu, 0);
 		snd_emu10k1_done(emu);
 		snd_emu10k1_free_efx(emu);
-       	}
+	}
 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
 		/* Disable 48Volt power to Audio Dock */
-		snd_emu1010_fpga_write(emu,  EMU_HANA_DOCK_PWR,  0 );
+		snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
 	}
 	if (emu->emu1010.firmware_thread)
 		kthread_stop(emu->emu1010.firmware_thread);
@@ -1278,7 +1280,7 @@
 #endif
 	if (emu->port)
 		pci_release_regions(emu->pci);
-	if (emu->card_capabilities->ca0151_chip) /* P16V */	
+	if (emu->card_capabilities->ca0151_chip) /* P16V */
 		snd_p16v_free(emu);
 	pci_disable_device(emu->pci);
 	kfree(emu);
@@ -1292,21 +1294,6 @@
 }
 
 static struct snd_emu_chip_details emu_chip_details[] = {
-	/* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/
-	/* Tested by James@superbug.co.uk 3rd July 2005 */
-	/* DSP: CA0108-IAT
-	 * DAC: CS4382-KQ
-	 * ADC: Philips 1361T
-	 * AC97: STAC9750
-	 * CA0151: None
-	 */
-	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102,
-	 .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", 
-	 .id = "Audigy2",
-	 .emu10k2_chip = 1,
-	 .ca0108_chip = 1,
-	 .spk71 = 1,
-	 .ac97_chip = 1} ,
 	/* Audigy4 (Not PRO) SB0610 */
 	/* Tested by James@superbug.co.uk 4th April 2006 */
 	/* A_IOCFG bits
@@ -1346,20 +1333,37 @@
 	 * CA0151: None
 	 */
 	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102,
-	 .driver = "Audigy2", .name = "Audigy 4 [SB0610]", 
+	 .driver = "Audigy2", .name = "SB Audigy 4 [SB0610]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0108_chip = 1,
 	 .spk71 = 1,
 	 .adc_1361t = 1,  /* 24 bit capture instead of 16bit */
 	 .ac97_chip = 1} ,
+	/* Audigy 2 Value AC3 out does not work yet.
+	 * Need to find out how to turn off interpolators.
+	 */
+	/* Tested by James@superbug.co.uk 3rd July 2005 */
+	/* DSP: CA0108-IAT
+	 * DAC: CS4382-KQ
+	 * ADC: Philips 1361T
+	 * AC97: STAC9750
+	 * CA0151: None
+	 */
+	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102,
+	 .driver = "Audigy2", .name = "SB Audigy 2 Value [SB0400]",
+	 .id = "Audigy2",
+	 .emu10k2_chip = 1,
+	 .ca0108_chip = 1,
+	 .spk71 = 1,
+	 .ac97_chip = 1} ,
 	/* Audigy 2 ZS Notebook Cardbus card.*/
 	/* Tested by James@superbug.co.uk 6th November 2006 */
 	/* Audio output 7.1/Headphones working.
 	 * Digital output working. (AC3 not checked, only PCM)
 	 * Audio Mic/Line inputs working.
 	 * Digital input not tested.
-	 */ 
+	 */
 	/* DSP: Tina2
 	 * DAC: Wolfson WM8768/WM8568
 	 * ADC: Wolfson WM8775
@@ -1386,7 +1390,7 @@
 	 *
 	 */
 	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102,
-	 .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", 
+	 .driver = "Audigy2", .name = "SB Audigy 2 ZS Notebook [SB0530]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0108_chip = 1,
@@ -1396,7 +1400,7 @@
 	 .spk71 = 1} ,
 	/* Tested by James@superbug.co.uk 4th Nov 2007. */
 	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102,
-	 .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", 
+	 .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]",
 	 .id = "EMU1010",
 	 .emu10k2_chip = 1,
 	 .ca0108_chip = 1,
@@ -1404,47 +1408,49 @@
 	 .spk71 = 1 ,
 	 .emu_model = EMU_MODEL_EMU1616},
 	/* Tested by James@superbug.co.uk 4th Nov 2007. */
+	/* This is MAEM8960, 0202 is MAEM 8980 */
 	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102,
-	 .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", 
+	 .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM8960]",
 	 .id = "EMU1010",
 	 .emu10k2_chip = 1,
 	 .ca0108_chip = 1,
 	 .spk71 = 1,
-	 .emu_model = EMU_MODEL_EMU1010B},
+	 .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 new revision */
 	/* Tested by James@superbug.co.uk 8th July 2005. */
+	/* This is MAEM8810, 0202 is MAEM8820 */
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
-	 .driver = "Audigy2", .name = "E-mu 1010 [4001]",
+	 .driver = "Audigy2", .name = "E-mu 1010 [MAEM8810]",
 	 .id = "EMU1010",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
 	 .spk71 = 1,
-	 .emu_model = EMU_MODEL_EMU1010}, /* Emu 1010 */
+	 .emu_model = EMU_MODEL_EMU1010}, /* EMU 1010 old revision */
 	/* EMU0404b */
 	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102,
-	 .driver = "Audigy2", .name = "E-mu 0404b [4002]",
+	 .driver = "Audigy2", .name = "E-mu 0404b PCI [MAEM8852]",
 	 .id = "EMU0404",
 	 .emu10k2_chip = 1,
 	 .ca0108_chip = 1,
 	 .spk71 = 1,
-	 .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */
+	 .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 new revision */
 	/* Tested by James@superbug.co.uk 20-3-2007. */
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102,
-	 .driver = "Audigy2", .name = "E-mu 0404 [4002]",
+	 .driver = "Audigy2", .name = "E-mu 0404 [MAEM8850]",
 	 .id = "EMU0404",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
 	 .spk71 = 1,
 	 .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */
-	/* Audigy4 (Not PRO) SB0610 */
-	{.vendor = 0x1102, .device = 0x0008, 
-	 .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", 
+	/* Note that all E-mu cards require kernel 2.6 or newer. */
+	{.vendor = 0x1102, .device = 0x0008,
+	 .driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0108_chip = 1,
 	 .ac97_chip = 1} ,
 	/* Tested by James@superbug.co.uk 3rd July 2005 */
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
-	 .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", 
+	 .driver = "Audigy2", .name = "SB Audigy 4 PRO [SB0380]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
@@ -1457,7 +1463,7 @@
 	 * Just like 0x20021102
 	 */
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20061102,
-	 .driver = "Audigy2", .name = "Audigy 2 [SB0350b]", 
+	 .driver = "Audigy2", .name = "SB Audigy 2 [SB0350b]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
@@ -1467,7 +1473,7 @@
 	 .invert_shared_spdif = 1,	/* digital/analog switch swapped */
 	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102,
-	 .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]", 
+	 .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0350]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
@@ -1477,7 +1483,7 @@
 	 .invert_shared_spdif = 1,	/* digital/analog switch swapped */
 	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102,
-	 .driver = "Audigy2", .name = "Audigy 2 ZS [2001]", 
+	 .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0360]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
@@ -1495,7 +1501,7 @@
 	 * CA0151: Yes
 	 */
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102,
-	 .driver = "Audigy2", .name = "Audigy 2 [SB0240]", 
+	 .driver = "Audigy2", .name = "SB Audigy 2 [SB0240]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
@@ -1505,7 +1511,7 @@
 	 .adc_1361t = 1,  /* 24 bit capture instead of 16bit */
 	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102,
-	 .driver = "Audigy2", .name = "Audigy 2 EX [1005]", 
+	 .driver = "Audigy2", .name = "SB Audigy 2 Platinum EX [SB0280]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
@@ -1515,7 +1521,7 @@
 	/* Dell OEM/Creative Labs Audigy 2 ZS */
 	/* See ALSA bug#1365 */
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10031102,
-	 .driver = "Audigy2", .name = "Audigy 2 ZS [SB0353]",
+	 .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0353]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
@@ -1524,7 +1530,7 @@
 	 .spdif_bug = 1,
 	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102,
-	 .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]", 
+	 .driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
@@ -1535,7 +1541,7 @@
 	 .adc_1361t = 1,  /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */
 	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0004, .revision = 0x04,
-	 .driver = "Audigy2", .name = "Audigy 2 [Unknown]",
+	 .driver = "Audigy2", .name = "SB Audigy 2 [Unknown]",
 	 .id = "Audigy2",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
@@ -1543,78 +1549,79 @@
 	 .spdif_bug = 1,
 	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102,
-	 .driver = "Audigy", .name = "Audigy 1 [SB0090]", 
+	 .driver = "Audigy", .name = "SB Audigy 1 [SB0092]",
 	 .id = "Audigy",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
 	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00521102,
-	 .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", 
+	 .driver = "Audigy", .name = "SB Audigy 1 ES [SB0160]",
 	 .id = "Audigy",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
 	 .spdif_bug = 1,
 	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102,
-	 .driver = "Audigy", .name = "Audigy 1 [SB0090]", 
+	 .driver = "Audigy", .name = "SB Audigy 1 [SB0090]",
 	 .id = "Audigy",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
 	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0004,
-	 .driver = "Audigy", .name = "Audigy 1 [Unknown]", 
+	 .driver = "Audigy", .name = "Audigy 1 [Unknown]",
 	 .id = "Audigy",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
 	 .ac97_chip = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102,
-	 .driver = "EMU10K1", .name = "SBLive! [SB0105]", 
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102,
+	 .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806A1102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [SB0103]", 
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806b1102,
+	 .driver = "EMU10K1", .name = "SB Live! [SB0105]",
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806a1102,
+	 .driver = "EMU10K1", .name = "SB Live! Value [SB0103]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [SB0101]", 
+	 .driver = "EMU10K1", .name = "SB Live! Value [SB0101]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	/* Tested by ALSA bug#1680 26th December 2005 */
-	/* note: It really has SB0220 written on the card. */
+	/* note: It really has SB0220 written on the card, */
+	/* but it's SB0228 according to kx.inf */
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80661102,
-	 .driver = "EMU10K1", .name = "SB Live 5.1 Dell OEM [SB0220]", 
+	 .driver = "EMU10K1", .name = "SB Live! 5.1 Dell OEM [SB0228]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	/* Tested by Thomas Zehetbauer 27th Aug 2005 */
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80651102,
-	 .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102,
-	 .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", 
+	 .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
-	 .driver = "EMU10K1", .name = "SB Live 5.1", 
+	 .driver = "EMU10K1", .name = "SB Live! 5.1",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	/* Tested by alsa bugtrack user "hus" bug #1297 12th Aug 2005 */
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
-	 .driver = "EMU10K1", .name = "SBLive 5.1 [SB0060]",
+	 .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0060]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 2, /* ac97 is optional; both SBLive 5.1 and platinum
@@ -1622,78 +1629,78 @@
 			  */
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4850]", 
+	 .driver = "EMU10K1", .name = "SB Live! Value [CT4850]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102,
-	 .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", 
+	 .driver = "EMU10K1", .name = "SB Live! Platinum [CT4760P]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4871]", 
+	 .driver = "EMU10K1", .name = "SB Live! Value [CT4871]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4831]", 
+	 .driver = "EMU10K1", .name = "SB Live! Value [CT4831]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4870]", 
+	 .driver = "EMU10K1", .name = "SB Live! Value [CT4870]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	/* Tested by James@superbug.co.uk 3rd July 2005 */
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", 
+	 .driver = "EMU10K1", .name = "SB Live! Value [CT4832]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4830]", 
+	 .driver = "EMU10K1", .name = "SB Live! Value [CT4830]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102,
-	 .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", 
+	 .driver = "EMU10K1", .name = "SB PCI512 [CT4790]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4780]", 
+	 .driver = "EMU10K1", .name = "SB Live! Value [CT4780]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102,
-	 .driver = "EMU10K1", .name = "E-mu APS [4001]", 
+	 .driver = "EMU10K1", .name = "E-mu APS [PC545]",
 	 .id = "APS",
 	 .emu10k1_chip = 1,
 	 .ecard = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102,
-	 .driver = "EMU10K1", .name = "SBLive! [CT4620]", 
+	 .driver = "EMU10K1", .name = "SB Live! [CT4620]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4670]", 
+	 .driver = "EMU10K1", .name = "SB Live! Value [CT4670]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
 	{.vendor = 0x1102, .device = 0x0002,
-	 .driver = "EMU10K1", .name = "SB Live [Unknown]", 
+	 .driver = "EMU10K1", .name = "SB Live! [Unknown]",
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
@@ -1702,13 +1709,13 @@
 };
 
 int __devinit snd_emu10k1_create(struct snd_card *card,
-		       struct pci_dev * pci,
+		       struct pci_dev *pci,
 		       unsigned short extin_mask,
 		       unsigned short extout_mask,
 		       long max_cache_bytes,
 		       int enable_ir,
 		       uint subsystem,
-		       struct snd_emu10k1 ** remu)
+		       struct snd_emu10k1 **remu)
 {
 	struct snd_emu10k1 *emu;
 	int idx, err;
@@ -1718,11 +1725,12 @@
 	static struct snd_device_ops ops = {
 		.dev_free =	snd_emu10k1_dev_free,
 	};
-	
+
 	*remu = NULL;
 
 	/* enable PCI device */
-	if ((err = pci_enable_device(pci)) < 0)
+	err = pci_enable_device(pci);
+	if (err < 0)
 		return err;
 
 	emu = kzalloc(sizeof(*emu), GFP_KERNEL);
@@ -1749,16 +1757,17 @@
 	emu->revision = pci->revision;
 	pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
 	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model);
-	snd_printdd("vendor=0x%x, device=0x%x, subsystem_vendor_id=0x%x, subsystem_id=0x%x\n",pci->vendor, pci->device, emu->serial, emu->model);
+	snd_printdd("vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n", pci->vendor, pci->device, emu->serial, emu->model);
 
 	for (c = emu_chip_details; c->vendor; c++) {
 		if (c->vendor == pci->vendor && c->device == pci->device) {
 			if (subsystem) {
-				if (c->subsystem && (c->subsystem == subsystem) ) {
+				if (c->subsystem && (c->subsystem == subsystem))
 					break;
-				} else continue;
+				else
+					continue;
 			} else {
-				if (c->subsystem && (c->subsystem != emu->serial) )
+				if (c->subsystem && (c->subsystem != emu->serial))
 					continue;
 				if (c->revision && c->revision != emu->revision)
 					continue;
@@ -1774,14 +1783,18 @@
 	}
 	emu->card_capabilities = c;
 	if (c->subsystem && !subsystem)
-		snd_printdd("Sound card name=%s\n", c->name);
-	else if (subsystem) 
-		snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x. Forced to subsytem=0x%x\n",
-		       	c->name, pci->vendor, pci->device, emu->serial, c->subsystem);
-	else 
-		snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x.\n",
-		      	c->name, pci->vendor, pci->device, emu->serial);
-	
+		snd_printdd("Sound card name = %s\n", c->name);
+	else if (subsystem)
+		snd_printdd("Sound card name = %s, "
+			"vendor = 0x%x, device = 0x%x, subsystem = 0x%x. "
+			"Forced to subsytem = 0x%x\n",	c->name,
+			pci->vendor, pci->device, emu->serial, c->subsystem);
+	else
+		snd_printdd("Sound card name = %s, "
+			"vendor = 0x%x, device = 0x%x, subsystem = 0x%x.\n",
+			c->name, pci->vendor, pci->device,
+			emu->serial);
+
 	if (!*card->id && c->id) {
 		int i, n = 0;
 		strlcpy(card->id, c->id, sizeof(card->id));
@@ -1815,7 +1828,8 @@
 	else
 		emu->gpr_base = FXGPREGBASE;
 
-	if ((err = pci_request_regions(pci, "EMU10K1")) < 0) {
+	err = pci_request_regions(pci, "EMU10K1");
+	if (err < 0) {
 		kfree(emu);
 		pci_disable_device(pci);
 		return err;
@@ -1862,21 +1876,25 @@
 	emu->enable_ir = enable_ir;
 
 	if (emu->card_capabilities->ca_cardbus_chip) {
-		if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
+		err = snd_emu10k1_cardbus_init(emu);
+		if (err < 0)
 			goto error;
 	}
 	if (emu->card_capabilities->ecard) {
-		if ((err = snd_emu10k1_ecard_init(emu)) < 0)
+		err = snd_emu10k1_ecard_init(emu);
+		if (err < 0)
 			goto error;
 	} else if (emu->card_capabilities->emu_model) {
- 		if ((err = snd_emu10k1_emu1010_init(emu)) < 0) {
- 			snd_emu10k1_free(emu);
- 			return err;
- 		}
+		err = snd_emu10k1_emu1010_init(emu);
+		if (err < 0) {
+			snd_emu10k1_free(emu);
+			return err;
+		}
 	} else {
 		/* 5.1: Enable the additional AC97 Slots. If the emu10k1 version
 			does not support this, it shouldn't do any harm */
-		snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
+		snd_emu10k1_ptr_write(emu, AC97SLOT, 0,
+					AC97SLOT_CNTR|AC97SLOT_LFE);
 	}
 
 	/* initialize TRAM setup */
@@ -1916,7 +1934,7 @@
 		snd_emu10k1_synth_alloc(emu, 4096);
 	if (emu->reserved_page)
 		emu->reserved_page->map_locked = 1;
-	
+
 	/* Clear silent pages and set up pointers */
 	memset(emu->silent_page.area, 0, PAGE_SIZE);
 	silent_page = emu->silent_page.addr << 1;
@@ -1929,19 +1947,23 @@
 		emu->voices[idx].number = idx;
 	}
 
-	if ((err = snd_emu10k1_init(emu, enable_ir, 0)) < 0)
+	err = snd_emu10k1_init(emu, enable_ir, 0);
+	if (err < 0)
 		goto error;
 #ifdef CONFIG_PM
-	if ((err = alloc_pm_buffer(emu)) < 0)
+	err = alloc_pm_buffer(emu);
+	if (err < 0)
 		goto error;
 #endif
 
 	/*  Initialize the effect engine */
-	if ((err = snd_emu10k1_init_efx(emu)) < 0)
+	err = snd_emu10k1_init_efx(emu);
+	if (err < 0)
 		goto error;
 	snd_emu10k1_audio_enable(emu);
 
-	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops)) < 0)
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops);
+	if (err < 0)
 		goto error;
 
 #ifdef CONFIG_PROC_FS
@@ -1981,7 +2003,7 @@
 	if (emu->audigy)
 		size += ARRAY_SIZE(saved_regs_audigy);
 	emu->saved_ptr = vmalloc(4 * NUM_G * size);
-	if (! emu->saved_ptr)
+	if (!emu->saved_ptr)
 		return -ENOMEM;
 	if (snd_emu10k1_efx_alloc_pm_buffer(emu) < 0)
 		return -ENOMEM;
@@ -2026,7 +2048,7 @@
 	if (emu->card_capabilities->ecard)
 		snd_emu10k1_ecard_init(emu);
 	else if (emu->card_capabilities->emu_model)
- 		snd_emu10k1_emu1010_init(emu);
+		snd_emu10k1_emu1010_init(emu);
 	else
 		snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
 	snd_emu10k1_init(emu, emu->enable_ir, 1);
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index f34bbfb..b0fb6c9 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -1639,6 +1639,45 @@
 	.put =		snd_emu10k1_shared_spdif_put
 };
 
+/* workaround for too low volume on Audigy due to 16bit/24bit conversion */
+
+#define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
+
+static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+
+	/* FIXME: better to use a cached version */
+	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
+	ucontrol->value.integer.value[0] = !!val;
+	return 0;
+}
+
+static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+
+	if (ucontrol->value.integer.value[0])
+		val = 0x0f0f;
+	else
+		val = 0;
+	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
+}
+
+static struct snd_kcontrol_new snd_audigy_capture_boost __devinitdata =
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =		"Analog Capture Boost",
+	.info =		snd_audigy_capture_boost_info,
+	.get =		snd_audigy_capture_boost_get,
+	.put =		snd_audigy_capture_boost_put
+};
+
+
 /*
  */
 static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
@@ -2087,5 +2126,12 @@
 		}
 	}
 		
+	if (emu->card_capabilities->ac97_chip && emu->audigy) {
+		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
+						     emu));
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 20ee759..e9c3794 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -1953,7 +1953,7 @@
 	outw(inw(chip->io_port + 4) & 1, chip->io_port + 4);
 
 	if (event & ESM_HWVOL_IRQ)
-		tasklet_hi_schedule(&chip->hwvol_tq); /* we'll do this later */
+		tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */
 
 	/* else ack 'em all, i imagine */
 	outb(0xFF, chip->io_port + 0x1A);
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
new file mode 100644
index 0000000..eb2a19b
--- /dev/null
+++ b/sound/pci/hda/Kconfig
@@ -0,0 +1,188 @@
+menuconfig SND_HDA_INTEL
+	tristate "Intel HD Audio"
+	select SND_PCM
+	select SND_VMASTER
+	select SND_JACK if INPUT=y || INPUT=SND
+	help
+	  Say Y here to include support for Intel "High Definition
+	  Audio" (Azalia) and its compatible devices.
+
+	  This option enables the HD-audio controller.  Don't forget
+	  to choose the appropriate codec options below.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-hda-intel.
+
+if SND_HDA_INTEL
+
+config SND_HDA_HWDEP
+	bool "Build hwdep interface for HD-audio driver"
+	select SND_HWDEP
+	help
+	  Say Y here to build a hwdep interface for HD-audio driver.
+	  This interface can be used for out-of-band communication
+	  with codecs for debugging purposes.
+
+config SND_HDA_RECONFIG
+	bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)"
+	depends on SND_HDA_HWDEP && EXPERIMENTAL
+	help
+	  Say Y here to enable the HD-audio codec re-configuration feature.
+	  This adds the sysfs interfaces to allow user to clear the whole
+	  codec configuration, change the codec setup, add extra verbs,
+	  and re-configure the codec dynamically.
+
+config SND_HDA_INPUT_BEEP
+	bool "Support digital beep via input layer"
+	depends on INPUT=y || INPUT=SND_HDA_INTEL
+	help
+	  Say Y here to build a digital beep interface for HD-audio
+	  driver. This interface is used to generate digital beeps.
+
+config SND_HDA_CODEC_REALTEK
+	bool "Build Realtek HD-audio codec support"
+	default y
+	help
+	  Say Y here to include Realtek HD-audio codec support in
+	  snd-hda-intel driver, such as ALC880.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-realtek.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_ANALOG
+	bool "Build Analog Device HD-audio codec support"
+	default y
+	help
+	  Say Y here to include Analog Device HD-audio codec support in
+	  snd-hda-intel driver, such as AD1986A.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-analog.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_SIGMATEL
+	bool "Build IDT/Sigmatel HD-audio codec support"
+	default y
+	help
+	  Say Y here to include IDT (Sigmatel) HD-audio codec support in
+	  snd-hda-intel driver, such as STAC9200.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-idt.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_VIA
+	bool "Build VIA HD-audio codec support"
+	default y
+	help
+	  Say Y here to include VIA HD-audio codec support in
+	  snd-hda-intel driver, such as VT1708.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-via.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_ATIHDMI
+	bool "Build ATI HDMI HD-audio codec support"
+	default y
+	help
+	  Say Y here to include ATI HDMI HD-audio codec support in
+	  snd-hda-intel driver, such as ATI RS600 HDMI.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-atihdmi.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_NVHDMI
+	bool "Build NVIDIA HDMI HD-audio codec support"
+	default y
+	help
+	  Say Y here to include NVIDIA HDMI HD-audio codec support in
+	  snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-nvhdmi.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_INTELHDMI
+	bool "Build INTEL HDMI HD-audio codec support"
+	default y
+	help
+	  Say Y here to include INTEL HDMI HD-audio codec support in
+	  snd-hda-intel driver, such as Eaglelake integrated HDMI.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-intelhdmi.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_ELD
+	def_bool y
+	depends on SND_HDA_CODEC_INTELHDMI
+
+config SND_HDA_CODEC_CONEXANT
+	bool "Build Conexant HD-audio codec support"
+	default y
+	help
+	  Say Y here to include Conexant HD-audio codec support in
+	  snd-hda-intel driver, such as CX20549.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-conexant.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_CMEDIA
+	bool "Build C-Media HD-audio codec support"
+	default y
+	help
+	  Say Y here to include C-Media HD-audio codec support in
+	  snd-hda-intel driver, such as CMI9880.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-cmedia.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_SI3054
+	bool "Build Silicon Labs 3054 HD-modem codec support"
+	default y
+	help
+	  Say Y here to include Silicon Labs 3054 HD-modem codec
+	  (and compatibles) support in snd-hda-intel driver.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-si3054.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_GENERIC
+	bool "Enable generic HD-audio codec parser"
+	default y
+	help
+	  Say Y here to enable the generic HD-audio codec parser
+	  in snd-hda-intel driver.
+
+config SND_HDA_POWER_SAVE
+	bool "Aggressive power-saving on HD-audio"
+	help
+	  Say Y here to enable more aggressive power-saving mode on
+	  HD-audio driver.  The power-saving timeout can be configured
+	  via power_save option or over sysfs on-the-fly.
+
+config SND_HDA_POWER_SAVE_DEFAULT
+	int "Default time-out for HD-audio power-save mode"
+	depends on SND_HDA_POWER_SAVE
+	default 0
+	help
+	  The default time-out value in seconds for HD-audio automatic
+	  power-save mode.  0 means to disable the power-save mode.
+
+endif
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 1980c6d..50f9d09 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,20 +1,59 @@
-snd-hda-intel-y := hda_intel.o
-# since snd-hda-intel is the only driver using hda-codec,
-# merge it into a single module although it was originally
-# designed to be individual modules
-snd-hda-intel-y += hda_codec.o
-snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
-snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
-snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
-snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ANALOG) += patch_analog.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += patch_sigmatel.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3054) += patch_si3054.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o
+snd-hda-intel-objs := hda_intel.o
 
+snd-hda-codec-y := hda_codec.o
+snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
+snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
+# snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
+snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
+snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
+
+snd-hda-codec-realtek-objs :=	patch_realtek.o
+snd-hda-codec-cmedia-objs :=	patch_cmedia.o
+snd-hda-codec-analog-objs :=	patch_analog.o
+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-conexant-objs :=	patch_conexant.o
+snd-hda-codec-via-objs :=	patch_via.o
+snd-hda-codec-nvhdmi-objs :=	patch_nvhdmi.o
+snd-hda-codec-intelhdmi-objs :=	patch_intelhdmi.o hda_eld.o
+
+# common driver
+obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
+
+# codec drivers (note: CONFIG_SND_HDA_CODEC_XXX are booleans)
+ifdef CONFIG_SND_HDA_CODEC_REALTEK
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-realtek.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_CMEDIA
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cmedia.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_ANALOG
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-analog.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_SIGMATEL
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-idt.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_SI3054
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_CONEXANT
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_VIA
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_NVHDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o
+endif
+
+# this must be the last entry after codec drivers;
+# otherwise the codec patches won't be hooked before the PCI probe
+# when built in kernel
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 3ecd7e7..e00421c 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -128,6 +128,7 @@
 	INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device);
 
 void snd_hda_detach_beep_device(struct hda_codec *codec)
 {
@@ -140,3 +141,4 @@
 		kfree(beep);
 	}
 }
+EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index eb91641..e16cf63 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -31,15 +31,6 @@
 #include <sound/initval.h>
 #include "hda_local.h"
 #include <sound/hda_hwdep.h>
-#include "hda_patch.h"	/* codec presets */
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-/* define this option here to hide as static */
-static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
-module_param(power_save, int, 0644);
-MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
-		 "(in second, 0 = disable).");
-#endif
 
 /*
  * vendor / preset table
@@ -55,6 +46,7 @@
 	{ 0x1002, "ATI" },
 	{ 0x1057, "Motorola" },
 	{ 0x1095, "Silicon Image" },
+	{ 0x10de, "Nvidia" },
 	{ 0x10ec, "Realtek" },
 	{ 0x1106, "VIA" },
 	{ 0x111d, "IDT" },
@@ -66,40 +58,31 @@
 	{ 0x1854, "LG" },
 	{ 0x1aec, "Wolfson Microelectronics" },
 	{ 0x434d, "C-Media" },
+	{ 0x8086, "Intel" },
 	{ 0x8384, "SigmaTel" },
 	{} /* terminator */
 };
 
-static const struct hda_codec_preset *hda_preset_tables[] = {
-#ifdef CONFIG_SND_HDA_CODEC_REALTEK
-	snd_hda_preset_realtek,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_CMEDIA
-	snd_hda_preset_cmedia,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_ANALOG
-	snd_hda_preset_analog,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_SIGMATEL
-	snd_hda_preset_sigmatel,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_SI3054
-	snd_hda_preset_si3054,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
-	snd_hda_preset_atihdmi,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_CONEXANT
-	snd_hda_preset_conexant,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_VIA
-	snd_hda_preset_via,
-#endif
-#ifdef CONFIG_SND_HDA_CODEC_NVHDMI
-	snd_hda_preset_nvhdmi,
-#endif
-	NULL
-};
+static DEFINE_MUTEX(preset_mutex);
+static LIST_HEAD(hda_preset_tables);
+
+int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset)
+{
+	mutex_lock(&preset_mutex);
+	list_add_tail(&preset->list, &hda_preset_tables);
+	mutex_unlock(&preset_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_codec_preset);
+
+int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
+{
+	mutex_lock(&preset_mutex);
+	list_del(&preset->list);
+	mutex_unlock(&preset_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset);
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static void hda_power_work(struct work_struct *work);
@@ -108,6 +91,72 @@
 static inline void hda_keep_power_on(struct hda_codec *codec) {}
 #endif
 
+const char *snd_hda_get_jack_location(u32 cfg)
+{
+	static char *bases[7] = {
+		"N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
+	};
+	static unsigned char specials_idx[] = {
+		0x07, 0x08,
+		0x17, 0x18, 0x19,
+		0x37, 0x38
+	};
+	static char *specials[] = {
+		"Rear Panel", "Drive Bar",
+		"Riser", "HDMI", "ATAPI",
+		"Mobile-In", "Mobile-Out"
+	};
+	int i;
+	cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
+	if ((cfg & 0x0f) < 7)
+		return bases[cfg & 0x0f];
+	for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
+		if (cfg == specials_idx[i])
+			return specials[i];
+	}
+	return "UNKNOWN";
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_jack_location);
+
+const char *snd_hda_get_jack_connectivity(u32 cfg)
+{
+	static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
+
+	return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3];
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_jack_connectivity);
+
+const char *snd_hda_get_jack_type(u32 cfg)
+{
+	static char *jack_types[16] = {
+		"Line Out", "Speaker", "HP Out", "CD",
+		"SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
+		"Line In", "Aux", "Mic", "Telephony",
+		"SPDIF In", "Digitial In", "Reserved", "Other"
+	};
+
+	return jack_types[(cfg & AC_DEFCFG_DEVICE)
+				>> AC_DEFCFG_DEVICE_SHIFT];
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_jack_type);
+
+/*
+ * Compose a 32bit command word to be sent to the HD-audio controller
+ */
+static inline unsigned int
+make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
+	       unsigned int verb, unsigned int parm)
+{
+	u32 val;
+
+	val = (u32)(codec->addr & 0x0f) << 28;
+	val |= (u32)direct << 27;
+	val |= (u32)nid << 20;
+	val |= verb << 8;
+	val |= parm;
+	return val;
+}
+
 /**
  * snd_hda_codec_read - send a command and get the response
  * @codec: the HDA codec
@@ -124,17 +173,21 @@
 				int direct,
 				unsigned int verb, unsigned int parm)
 {
+	struct hda_bus *bus = codec->bus;
 	unsigned int res;
+
+	res = make_codec_cmd(codec, nid, direct, verb, parm);
 	snd_hda_power_up(codec);
-	mutex_lock(&codec->bus->cmd_mutex);
-	if (!codec->bus->ops.command(codec, nid, direct, verb, parm))
-		res = codec->bus->ops.get_response(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(&codec->bus->cmd_mutex);
+	mutex_unlock(&bus->cmd_mutex);
 	snd_hda_power_down(codec);
 	return res;
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_read);
 
 /**
  * snd_hda_codec_write - send a single command without waiting for response
@@ -151,14 +204,19 @@
 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 res;
 	int err;
+
+	res = make_codec_cmd(codec, nid, direct, verb, parm);
 	snd_hda_power_up(codec);
-	mutex_lock(&codec->bus->cmd_mutex);
-	err = codec->bus->ops.command(codec, nid, direct, verb, parm);
-	mutex_unlock(&codec->bus->cmd_mutex);
+	mutex_lock(&bus->cmd_mutex);
+	err = bus->ops.command(bus, res);
+	mutex_unlock(&bus->cmd_mutex);
 	snd_hda_power_down(codec);
 	return err;
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_write);
 
 /**
  * snd_hda_sequence_write - sequence writes
@@ -173,6 +231,7 @@
 	for (; seq->nid; seq++)
 		snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param);
 }
+EXPORT_SYMBOL_HDA(snd_hda_sequence_write);
 
 /**
  * snd_hda_get_sub_nodes - get the range of sub nodes
@@ -194,6 +253,7 @@
 	*start_id = (parm >> 16) & 0x7fff;
 	return (int)(parm & 0x7fff);
 }
+EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
 
 /**
  * snd_hda_get_connections - get connection list
@@ -282,6 +342,7 @@
 	}
 	return conns;
 }
+EXPORT_SYMBOL_HDA(snd_hda_get_connections);
 
 
 /**
@@ -316,6 +377,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_queue_unsol_event);
 
 /*
  * process queued unsolicited events
@@ -345,7 +407,7 @@
 /*
  * initialize unsolicited queue
  */
-static int __devinit init_unsol_queue(struct hda_bus *bus)
+static int init_unsol_queue(struct hda_bus *bus)
 {
 	struct hda_bus_unsolicited *unsol;
 
@@ -391,9 +453,24 @@
 static int snd_hda_bus_dev_free(struct snd_device *device)
 {
 	struct hda_bus *bus = device->device_data;
+	bus->shutdown = 1;
 	return snd_hda_bus_free(bus);
 }
 
+#ifdef CONFIG_SND_HDA_HWDEP
+static int snd_hda_bus_dev_register(struct snd_device *device)
+{
+	struct hda_bus *bus = device->device_data;
+	struct hda_codec *codec;
+	list_for_each_entry(codec, &bus->codec_list, list) {
+		snd_hda_hwdep_add_sysfs(codec);
+	}
+	return 0;
+}
+#else
+#define snd_hda_bus_dev_register	NULL
+#endif
+
 /**
  * snd_hda_bus_new - create a HDA bus
  * @card: the card entry
@@ -402,13 +479,14 @@
  *
  * Returns 0 if successful, or a negative error code.
  */
-int __devinit snd_hda_bus_new(struct snd_card *card,
+int /*__devinit*/ snd_hda_bus_new(struct snd_card *card,
 			      const struct hda_bus_template *temp,
 			      struct hda_bus **busp)
 {
 	struct hda_bus *bus;
 	int err;
 	static struct snd_device_ops dev_ops = {
+		.dev_register = snd_hda_bus_dev_register,
 		.dev_free = snd_hda_bus_dev_free,
 	};
 
@@ -430,6 +508,7 @@
 	bus->private_data = temp->private_data;
 	bus->pci = temp->pci;
 	bus->modelname = temp->modelname;
+	bus->power_save = temp->power_save;
 	bus->ops = temp->ops;
 
 	mutex_init(&bus->cmd_mutex);
@@ -444,27 +523,42 @@
 		*busp = bus;
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_bus_new);
 
 #ifdef CONFIG_SND_HDA_GENERIC
 #define is_generic_config(codec) \
-	(codec->bus->modelname && !strcmp(codec->bus->modelname, "generic"))
+	(codec->modelname && !strcmp(codec->modelname, "generic"))
 #else
 #define is_generic_config(codec)	0
 #endif
 
+#ifdef MODULE
+#define HDA_MODREQ_MAX_COUNT	2	/* two request_modules()'s */
+#else
+#define HDA_MODREQ_MAX_COUNT	0	/* all presets are statically linked */
+#endif
+
 /*
  * find a matching codec preset
  */
-static const struct hda_codec_preset __devinit *
+static const struct hda_codec_preset *
 find_codec_preset(struct hda_codec *codec)
 {
-	const struct hda_codec_preset **tbl, *preset;
+	struct hda_codec_preset_list *tbl;
+	const struct hda_codec_preset *preset;
+	int mod_requested = 0;
 
 	if (is_generic_config(codec))
 		return NULL; /* use the generic parser */
 
-	for (tbl = hda_preset_tables; *tbl; tbl++) {
-		for (preset = *tbl; preset->id; preset++) {
+ again:
+	mutex_lock(&preset_mutex);
+	list_for_each_entry(tbl, &hda_preset_tables, list) {
+		if (!try_module_get(tbl->owner)) {
+			snd_printk(KERN_ERR "hda_codec: cannot module_get\n");
+			continue;
+		}
+		for (preset = tbl->preset; preset->id; preset++) {
 			u32 mask = preset->mask;
 			if (preset->afg && preset->afg != codec->afg)
 				continue;
@@ -474,23 +568,40 @@
 				mask = ~0;
 			if (preset->id == (codec->vendor_id & mask) &&
 			    (!preset->rev ||
-			     preset->rev == codec->revision_id))
+			     preset->rev == codec->revision_id)) {
+				mutex_unlock(&preset_mutex);
+				codec->owner = tbl->owner;
 				return preset;
+			}
 		}
+		module_put(tbl->owner);
+	}
+	mutex_unlock(&preset_mutex);
+
+	if (mod_requested < HDA_MODREQ_MAX_COUNT) {
+		char name[32];
+		if (!mod_requested)
+			snprintf(name, sizeof(name), "snd-hda-codec-id:%08x",
+				 codec->vendor_id);
+		else
+			snprintf(name, sizeof(name), "snd-hda-codec-id:%04x*",
+				 (codec->vendor_id >> 16) & 0xffff);
+		request_module(name);
+		mod_requested++;
+		goto again;
 	}
 	return NULL;
 }
 
 /*
- * snd_hda_get_codec_name - store the codec name
+ * get_codec_name - store the codec name
  */
-void snd_hda_get_codec_name(struct hda_codec *codec,
-			    char *name, int namelen)
+static int get_codec_name(struct hda_codec *codec)
 {
 	const struct hda_vendor_id *c;
 	const char *vendor = NULL;
 	u16 vendor_id = codec->vendor_id >> 16;
-	char tmp[16];
+	char tmp[16], name[32];
 
 	for (c = hda_vendor_ids; c->id; c++) {
 		if (c->id == vendor_id) {
@@ -503,16 +614,21 @@
 		vendor = tmp;
 	}
 	if (codec->preset && codec->preset->name)
-		snprintf(name, namelen, "%s %s", vendor, codec->preset->name);
+		snprintf(name, sizeof(name), "%s %s", vendor,
+			 codec->preset->name);
 	else
-		snprintf(name, namelen, "%s ID %x", vendor,
+		snprintf(name, sizeof(name), "%s ID %x", vendor,
 			 codec->vendor_id & 0xffff);
+	codec->name = kstrdup(name, GFP_KERNEL);
+	if (!codec->name)
+		return -ENOMEM;
+	return 0;
 }
 
 /*
  * look for an AFG and MFG nodes
  */
-static void __devinit setup_fg_nodes(struct hda_codec *codec)
+static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec)
 {
 	int i, total_nodes;
 	hda_nid_t nid;
@@ -571,11 +687,15 @@
 	flush_scheduled_work();
 #endif
 	list_del(&codec->list);
+	snd_array_free(&codec->mixers);
 	codec->bus->caddr_tbl[codec->addr] = NULL;
 	if (codec->patch_ops.free)
 		codec->patch_ops.free(codec);
+	module_put(codec->owner);
 	free_hda_cache(&codec->amp_cache);
 	free_hda_cache(&codec->cmd_cache);
+	kfree(codec->name);
+	kfree(codec->modelname);
 	kfree(codec->wcaps);
 	kfree(codec);
 }
@@ -588,8 +708,8 @@
  *
  * Returns 0 if successful, or a negative error code.
  */
-int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
-				struct hda_codec **codecp)
+int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
+				    int do_init, struct hda_codec **codecp)
 {
 	struct hda_codec *codec;
 	char component[31];
@@ -617,6 +737,14 @@
 	mutex_init(&codec->spdif_mutex);
 	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
 	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
+	snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32);
+	if (codec->bus->modelname) {
+		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
+		if (!codec->modelname) {
+			snd_hda_codec_free(codec);
+			return -ENODEV;
+		}
+	}
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
@@ -662,12 +790,44 @@
 			snd_hda_codec_read(codec, nid, 0,
 					   AC_VERB_GET_SUBSYSTEM_ID, 0);
 	}
+	if (bus->modelname)
+		codec->modelname = kstrdup(bus->modelname, GFP_KERNEL);
+
+	if (do_init) {
+		err = snd_hda_codec_configure(codec);
+		if (err < 0) {
+			snd_hda_codec_free(codec);
+			return err;
+		}
+	}
+	snd_hda_codec_proc_new(codec);
+
+	snd_hda_create_hwdep(codec);
+
+	sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id,
+		codec->subsystem_id, codec->revision_id);
+	snd_component_add(codec->bus->card, component);
+
+	if (codecp)
+		*codecp = codec;
+	return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_new);
+
+int snd_hda_codec_configure(struct hda_codec *codec)
+{
+	int err;
 
 	codec->preset = find_codec_preset(codec);
+	if (!codec->name) {
+		err = get_codec_name(codec);
+		if (err < 0)
+			return err;
+	}
 	/* audio codec should override the mixer name */
-	if (codec->afg || !*bus->card->mixername)
-		snd_hda_get_codec_name(codec, bus->card->mixername,
-				       sizeof(bus->card->mixername));
+	if (codec->afg || !*codec->bus->card->mixername)
+		strlcpy(codec->bus->card->mixername, codec->name,
+			sizeof(codec->bus->card->mixername));
 
 	if (is_generic_config(codec)) {
 		err = snd_hda_parse_generic_codec(codec);
@@ -684,25 +844,9 @@
 		printk(KERN_ERR "hda-codec: No codec parser is available\n");
 
  patched:
-	if (err < 0) {
-		snd_hda_codec_free(codec);
-		return err;
-	}
-
-	if (codec->patch_ops.unsol_event)
-		init_unsol_queue(bus);
-
-	snd_hda_codec_proc_new(codec);
-#ifdef CONFIG_SND_HDA_HWDEP
-	snd_hda_create_hwdep(codec);
-#endif
-
-	sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id);
-	snd_component_add(codec->bus->card, component);
-
-	if (codecp)
-		*codecp = codec;
-	return 0;
+	if (!err && codec->patch_ops.unsol_event)
+		err = init_unsol_queue(codec->bus);
+	return err;
 }
 
 /**
@@ -728,6 +872,7 @@
 	msleep(1);
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format);
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream);
 
 void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
 {
@@ -741,6 +886,7 @@
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
 #endif
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream);
 
 /*
  * amp access functions
@@ -752,17 +898,17 @@
 #define INFO_AMP_VOL(ch)	(1 << (1 + (ch)))
 
 /* initialize the hash table */
-static void __devinit init_hda_cache(struct hda_cache_rec *cache,
+static void /*__devinit*/ init_hda_cache(struct hda_cache_rec *cache,
 				     unsigned int record_size)
 {
 	memset(cache, 0, sizeof(*cache));
 	memset(cache->hash, 0xff, sizeof(cache->hash));
-	cache->record_size = record_size;
+	snd_array_init(&cache->buf, record_size, 64);
 }
 
 static void free_hda_cache(struct hda_cache_rec *cache)
 {
-	kfree(cache->buffer);
+	snd_array_free(&cache->buf);
 }
 
 /* query the hash.  allocate an entry if not found. */
@@ -774,35 +920,17 @@
 	struct hda_cache_head *info;
 
 	while (cur != 0xffff) {
-		info = (struct hda_cache_head *)(cache->buffer +
-						 cur * cache->record_size);
+		info = snd_array_elem(&cache->buf, cur);
 		if (info->key == key)
 			return info;
 		cur = info->next;
 	}
 
 	/* add a new hash entry */
-	if (cache->num_entries >= cache->size) {
-		/* reallocate the array */
-		unsigned int new_size = cache->size + 64;
-		void *new_buffer;
-		new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL);
-		if (!new_buffer) {
-			snd_printk(KERN_ERR "hda_codec: "
-				   "can't malloc amp_info\n");
-			return NULL;
-		}
-		if (cache->buffer) {
-			memcpy(new_buffer, cache->buffer,
-			       cache->size * cache->record_size);
-			kfree(cache->buffer);
-		}
-		cache->size = new_size;
-		cache->buffer = new_buffer;
-	}
-	cur = cache->num_entries++;
-	info = (struct hda_cache_head *)(cache->buffer +
-					 cur * cache->record_size);
+	info = snd_array_new(&cache->buf);
+	if (!info)
+		return NULL;
+	cur = snd_array_index(&cache->buf, info);
 	info->key = key;
 	info->val = 0;
 	info->next = cache->hash[idx];
@@ -840,6 +968,7 @@
 	}
 	return info->amp_caps;
 }
+EXPORT_SYMBOL_HDA(query_amp_caps);
 
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 			      unsigned int caps)
@@ -853,6 +982,7 @@
 	info->head.val |= INFO_AMP_CAPS;
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
 
 /*
  * read the current volume to info
@@ -906,6 +1036,7 @@
 		return 0;
 	return get_vol_mute(codec, info, nid, ch, direction, index);
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read);
 
 /*
  * update the AMP value, mask = bit mask to set, val = the value
@@ -925,6 +1056,7 @@
 	put_vol_mute(codec, info, nid, ch, direction, idx, val);
 	return 1;
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update);
 
 /*
  * update the AMP stereo with the same mask and value
@@ -938,15 +1070,16 @@
 						idx, mask, val);
 	return ret;
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo);
 
 #ifdef SND_HDA_NEEDS_RESUME
 /* resume the all amp commands from the cache */
 void snd_hda_codec_resume_amp(struct hda_codec *codec)
 {
-	struct hda_amp_info *buffer = codec->amp_cache.buffer;
+	struct hda_amp_info *buffer = codec->amp_cache.buf.list;
 	int i;
 
-	for (i = 0; i < codec->amp_cache.size; i++, buffer++) {
+	for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) {
 		u32 key = buffer->head.key;
 		hda_nid_t nid;
 		unsigned int idx, dir, ch;
@@ -963,6 +1096,7 @@
 		}
 	}
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
 #endif /* SND_HDA_NEEDS_RESUME */
 
 /* volume */
@@ -990,6 +1124,7 @@
 	uinfo->value.integer.max = caps;
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
 
 int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
@@ -1009,6 +1144,7 @@
 			& HDA_AMP_VOLMASK;
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get);
 
 int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
@@ -1033,6 +1169,7 @@
 	snd_hda_power_down(codec);
 	return change;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_put);
 
 int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 			  unsigned int size, unsigned int __user *_tlv)
@@ -1059,6 +1196,7 @@
 		return -EFAULT;
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_tlv);
 
 /*
  * set (static) TLV for virtual master volume; recalculated as max 0dB
@@ -1078,6 +1216,7 @@
 	tlv[2] = -nums * step;
 	tlv[3] = step;
 }
+EXPORT_SYMBOL_HDA(snd_hda_set_vmaster_tlv);
 
 /* find a mixer control element with the given name */
 static struct snd_kcontrol *
@@ -1097,6 +1236,69 @@
 {
 	return _snd_hda_find_mixer_ctl(codec, name, 0);
 }
+EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
+
+/* Add a control element and assign to the codec */
+int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
+{
+	int err;
+	struct snd_kcontrol **knewp;
+
+	err = snd_ctl_add(codec->bus->card, kctl);
+	if (err < 0)
+		return err;
+	knewp = snd_array_new(&codec->mixers);
+	if (!knewp)
+		return -ENOMEM;
+	*knewp = kctl;
+	return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
+
+#ifdef CONFIG_SND_HDA_RECONFIG
+/* Clear all controls assigned to the given codec */
+void snd_hda_ctls_clear(struct hda_codec *codec)
+{
+	int i;
+	struct snd_kcontrol **kctls = codec->mixers.list;
+	for (i = 0; i < codec->mixers.used; i++)
+		snd_ctl_remove(codec->bus->card, kctls[i]);
+	snd_array_free(&codec->mixers);
+}
+
+void snd_hda_codec_reset(struct hda_codec *codec)
+{
+	int i;
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	cancel_delayed_work(&codec->power_work);
+	flush_scheduled_work();
+#endif
+	snd_hda_ctls_clear(codec);
+	/* relase PCMs */
+	for (i = 0; i < codec->num_pcms; i++) {
+		if (codec->pcm_info[i].pcm) {
+			snd_device_free(codec->bus->card,
+					codec->pcm_info[i].pcm);
+			clear_bit(codec->pcm_info[i].device,
+				  codec->bus->pcm_dev_bits);
+		}
+	}
+	if (codec->patch_ops.free)
+		codec->patch_ops.free(codec);
+	codec->proc_widget_hook = NULL;
+	codec->spec = NULL;
+	free_hda_cache(&codec->amp_cache);
+	free_hda_cache(&codec->cmd_cache);
+	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
+	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
+	codec->num_pcms = 0;
+	codec->pcm_info = NULL;
+	codec->preset = NULL;
+	module_put(codec->owner);
+	codec->owner = NULL;
+}
+#endif /* CONFIG_SND_HDA_RECONFIG */
 
 /* create a virtual master control and add slaves */
 int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
@@ -1115,7 +1317,7 @@
 	kctl = snd_ctl_make_virtual_master(name, tlv);
 	if (!kctl)
 		return -ENOMEM;
-	err = snd_ctl_add(codec->bus->card, kctl);
+	err = snd_hda_ctl_add(codec, kctl);
 	if (err < 0)
 		return err;
 	
@@ -1133,6 +1335,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_add_vmaster);
 
 /* switch */
 int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
@@ -1146,6 +1349,7 @@
 	uinfo->value.integer.max = 1;
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_info);
 
 int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
@@ -1165,6 +1369,7 @@
 			 HDA_AMP_MUTE) ? 0 : 1;
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get);
 
 int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
@@ -1195,6 +1400,7 @@
 	snd_hda_power_down(codec);
 	return change;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put);
 
 /*
  * bound volume controls
@@ -1220,6 +1426,7 @@
 	mutex_unlock(&codec->spdif_mutex);
 	return err;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get);
 
 int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
@@ -1243,6 +1450,7 @@
 	mutex_unlock(&codec->spdif_mutex);
 	return err < 0 ? err : change;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put);
 
 /*
  * generic bound volume/swtich controls
@@ -1262,6 +1470,7 @@
 	mutex_unlock(&codec->spdif_mutex);
 	return err;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info);
 
 int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
@@ -1278,6 +1487,7 @@
 	mutex_unlock(&codec->spdif_mutex);
 	return err;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get);
 
 int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
@@ -1300,6 +1510,7 @@
 	mutex_unlock(&codec->spdif_mutex);
 	return err < 0 ? err : change;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put);
 
 int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 			   unsigned int size, unsigned int __user *tlv)
@@ -1316,6 +1527,7 @@
 	mutex_unlock(&codec->spdif_mutex);
 	return err;
 }
+EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv);
 
 struct hda_ctl_ops snd_hda_bind_vol = {
 	.info = snd_hda_mixer_amp_volume_info,
@@ -1323,6 +1535,7 @@
 	.put = snd_hda_mixer_amp_volume_put,
 	.tlv = snd_hda_mixer_amp_tlv
 };
+EXPORT_SYMBOL_HDA(snd_hda_bind_vol);
 
 struct hda_ctl_ops snd_hda_bind_sw = {
 	.info = snd_hda_mixer_amp_switch_info,
@@ -1330,6 +1543,7 @@
 	.put = snd_hda_mixer_amp_switch_put,
 	.tlv = snd_hda_mixer_amp_tlv
 };
+EXPORT_SYMBOL_HDA(snd_hda_bind_sw);
 
 /*
  * SPDIF out controls
@@ -1577,9 +1791,11 @@
 	}
 	for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
 		kctl = snd_ctl_new1(dig_mix, codec);
+		if (!kctl)
+			return -ENOMEM;
 		kctl->id.index = idx;
 		kctl->private_value = nid;
-		err = snd_ctl_add(codec->bus->card, kctl);
+		err = snd_hda_ctl_add(codec, kctl);
 		if (err < 0)
 			return err;
 	}
@@ -1589,6 +1805,7 @@
 	codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls);
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls);
 
 /*
  * SPDIF sharing with analog output
@@ -1623,9 +1840,10 @@
 	if (!mout->dig_out_nid)
 		return 0;
 	/* ATTENTION: here mout is passed as private_data, instead of codec */
-	return snd_ctl_add(codec->bus->card,
+	return snd_hda_ctl_add(codec,
 			   snd_ctl_new1(&spdif_share_sw, mout));
 }
+EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw);
 
 /*
  * SPDIF input
@@ -1725,7 +1943,7 @@
 	for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
 		kctl = snd_ctl_new1(dig_mix, codec);
 		kctl->private_value = nid;
-		err = snd_ctl_add(codec->bus->card, kctl);
+		err = snd_hda_ctl_add(codec, kctl);
 		if (err < 0)
 			return err;
 	}
@@ -1735,6 +1953,7 @@
 		AC_DIG1_ENABLE;
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
 
 #ifdef SND_HDA_NEEDS_RESUME
 /*
@@ -1761,10 +1980,14 @@
 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;
+
+	res = make_codec_cmd(codec, nid, direct, verb, parm);
 	snd_hda_power_up(codec);
-	mutex_lock(&codec->bus->cmd_mutex);
-	err = codec->bus->ops.command(codec, nid, direct, verb, parm);
+	mutex_lock(&bus->cmd_mutex);
+	err = bus->ops.command(bus, res);
 	if (!err) {
 		struct hda_cache_head *c;
 		u32 key = build_cmd_cache_key(nid, verb);
@@ -1772,18 +1995,19 @@
 		if (c)
 			c->val = parm;
 	}
-	mutex_unlock(&codec->bus->cmd_mutex);
+	mutex_unlock(&bus->cmd_mutex);
 	snd_hda_power_down(codec);
 	return err;
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
 
 /* resume the all commands from the cache */
 void snd_hda_codec_resume_cache(struct hda_codec *codec)
 {
-	struct hda_cache_head *buffer = codec->cmd_cache.buffer;
+	struct hda_cache_head *buffer = codec->cmd_cache.buf.list;
 	int i;
 
-	for (i = 0; i < codec->cmd_cache.size; i++, buffer++) {
+	for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) {
 		u32 key = buffer->key;
 		if (!key)
 			continue;
@@ -1791,6 +2015,7 @@
 				    get_cmd_cache_cmd(key), buffer->val);
 	}
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_resume_cache);
 
 /**
  * snd_hda_sequence_write_cache - sequence writes with caching
@@ -1808,6 +2033,7 @@
 		snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb,
 					  seq->param);
 }
+EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache);
 #endif /* SND_HDA_NEEDS_RESUME */
 
 /*
@@ -1868,6 +2094,17 @@
 	}
 }
 
+#ifdef CONFIG_SND_HDA_HWDEP
+/* execute additional init verbs */
+static void hda_exec_init_verbs(struct hda_codec *codec)
+{
+	if (codec->init_verbs.list)
+		snd_hda_sequence_write(codec, codec->init_verbs.list);
+}
+#else
+static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
+#endif
+
 #ifdef SND_HDA_NEEDS_RESUME
 /*
  * call suspend and power-down; used both from PM and power-save
@@ -1894,6 +2131,7 @@
 	hda_set_power_state(codec,
 			    codec->afg ? codec->afg : codec->mfg,
 			    AC_PWRST_D0);
+	hda_exec_init_verbs(codec);
 	if (codec->patch_ops.resume)
 		codec->patch_ops.resume(codec);
 	else {
@@ -1914,28 +2152,37 @@
  *
  * Returns 0 if successful, otherwise a negative error code.
  */
-int __devinit snd_hda_build_controls(struct hda_bus *bus)
+int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)
 {
 	struct hda_codec *codec;
 
 	list_for_each_entry(codec, &bus->codec_list, list) {
-		int err = 0;
-		/* fake as if already powered-on */
-		hda_keep_power_on(codec);
-		/* then fire up */
-		hda_set_power_state(codec,
-				    codec->afg ? codec->afg : codec->mfg,
-				    AC_PWRST_D0);
-		/* continue to initialize... */
-		if (codec->patch_ops.init)
-			err = codec->patch_ops.init(codec);
-		if (!err && codec->patch_ops.build_controls)
-			err = codec->patch_ops.build_controls(codec);
-		snd_hda_power_down(codec);
+		int err = snd_hda_codec_build_controls(codec);
 		if (err < 0)
 			return err;
 	}
+	return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_build_controls);
 
+int snd_hda_codec_build_controls(struct hda_codec *codec)
+{
+	int err = 0;
+	/* fake as if already powered-on */
+	hda_keep_power_on(codec);
+	/* then fire up */
+	hda_set_power_state(codec,
+			    codec->afg ? codec->afg : codec->mfg,
+			    AC_PWRST_D0);
+	hda_exec_init_verbs(codec);
+	/* continue to initialize... */
+	if (codec->patch_ops.init)
+		err = codec->patch_ops.init(codec);
+	if (!err && codec->patch_ops.build_controls)
+		err = codec->patch_ops.build_controls(codec);
+	snd_hda_power_down(codec);
+	if (err < 0)
+		return err;
 	return 0;
 }
 
@@ -2028,6 +2275,7 @@
 
 	return val;
 }
+EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
 
 /**
  * snd_hda_query_supported_pcm - query the supported PCM rates and formats
@@ -2042,7 +2290,7 @@
  *
  * Returns 0 if successful, otherwise a negative error code.
  */
-int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
 				u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
 {
 	int i;
@@ -2207,6 +2455,7 @@
 
 	return 1;
 }
+EXPORT_SYMBOL_HDA(snd_hda_is_supported_format);
 
 /*
  * PCM stuff
@@ -2236,8 +2485,8 @@
 	return 0;
 }
 
-static int __devinit set_pcm_default_values(struct hda_codec *codec,
-					    struct hda_pcm_stream *info)
+static int set_pcm_default_values(struct hda_codec *codec,
+				  struct hda_pcm_stream *info)
 {
 	/* query support PCM information from the given NID */
 	if (info->nid && (!info->rates || !info->formats)) {
@@ -2263,6 +2512,110 @@
 	return 0;
 }
 
+/*
+ * get the empty PCM device number to assign
+ */
+static int get_empty_pcm_device(struct hda_bus *bus, int type)
+{
+	static const char *dev_name[HDA_PCM_NTYPES] = {
+		"Audio", "SPDIF", "HDMI", "Modem"
+	};
+	/* starting device index for each PCM type */
+	static int dev_idx[HDA_PCM_NTYPES] = {
+		[HDA_PCM_TYPE_AUDIO] = 0,
+		[HDA_PCM_TYPE_SPDIF] = 1,
+		[HDA_PCM_TYPE_HDMI] = 3,
+		[HDA_PCM_TYPE_MODEM] = 6
+	};
+	/* normal audio device indices; not linear to keep compatibility */
+	static int audio_idx[4] = { 0, 2, 4, 5 };
+	int i, dev;
+
+	switch (type) {
+	case HDA_PCM_TYPE_AUDIO:
+		for (i = 0; i < ARRAY_SIZE(audio_idx); i++) {
+			dev = audio_idx[i];
+			if (!test_bit(dev, bus->pcm_dev_bits))
+				break;
+		}
+		if (i >= ARRAY_SIZE(audio_idx)) {
+			snd_printk(KERN_WARNING "Too many audio devices\n");
+			return -EAGAIN;
+		}
+		break;
+	case HDA_PCM_TYPE_SPDIF:
+	case HDA_PCM_TYPE_HDMI:
+	case HDA_PCM_TYPE_MODEM:
+		dev = dev_idx[type];
+		if (test_bit(dev, bus->pcm_dev_bits)) {
+			snd_printk(KERN_WARNING "%s already defined\n",
+				   dev_name[type]);
+			return -EAGAIN;
+		}
+		break;
+	default:
+		snd_printk(KERN_WARNING "Invalid PCM type %d\n", type);
+		return -EINVAL;
+	}
+	set_bit(dev, bus->pcm_dev_bits);
+	return dev;
+}
+
+/*
+ * attach a new PCM stream
+ */
+static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
+{
+	struct hda_bus *bus = codec->bus;
+	struct hda_pcm_stream *info;
+	int stream, err;
+
+	if (snd_BUG_ON(!pcm->name))
+		return -EINVAL;
+	for (stream = 0; stream < 2; stream++) {
+		info = &pcm->stream[stream];
+		if (info->substreams) {
+			err = set_pcm_default_values(codec, info);
+			if (err < 0)
+				return err;
+		}
+	}
+	return bus->ops.attach_pcm(bus, codec, pcm);
+}
+
+/* assign all PCMs of the given codec */
+int snd_hda_codec_build_pcms(struct hda_codec *codec)
+{
+	unsigned int pcm;
+	int err;
+
+	if (!codec->num_pcms) {
+		if (!codec->patch_ops.build_pcms)
+			return 0;
+		err = codec->patch_ops.build_pcms(codec);
+		if (err < 0)
+			return err;
+	}
+	for (pcm = 0; pcm < codec->num_pcms; pcm++) {
+		struct hda_pcm *cpcm = &codec->pcm_info[pcm];
+		int dev;
+
+		if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
+			return 0; /* no substreams assigned */
+
+		if (!cpcm->pcm) {
+			dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type);
+			if (dev < 0)
+				return 0;
+			cpcm->device = dev;
+			err = snd_hda_attach_pcm(codec, cpcm);
+			if (err < 0)
+				return err;
+		}
+	}
+	return 0;
+}
+
 /**
  * snd_hda_build_pcms - build PCM information
  * @bus: the BUS
@@ -2294,27 +2647,13 @@
 	struct hda_codec *codec;
 
 	list_for_each_entry(codec, &bus->codec_list, list) {
-		unsigned int pcm, s;
-		int err;
-		if (!codec->patch_ops.build_pcms)
-			continue;
-		err = codec->patch_ops.build_pcms(codec);
+		int err = snd_hda_codec_build_pcms(codec);
 		if (err < 0)
 			return err;
-		for (pcm = 0; pcm < codec->num_pcms; pcm++) {
-			for (s = 0; s < 2; s++) {
-				struct hda_pcm_stream *info;
-				info = &codec->pcm_info[pcm].stream[s];
-				if (!info->substreams)
-					continue;
-				err = set_pcm_default_values(codec, info);
-				if (err < 0)
-					return err;
-			}
-		}
 	}
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_build_pcms);
 
 /**
  * snd_hda_check_board_config - compare the current codec with the config table
@@ -2333,11 +2672,11 @@
 			       int num_configs, const char **models,
 			       const struct snd_pci_quirk *tbl)
 {
-	if (codec->bus->modelname && models) {
+	if (codec->modelname && models) {
 		int i;
 		for (i = 0; i < num_configs; i++) {
 			if (models[i] &&
-			    !strcmp(codec->bus->modelname, models[i])) {
+			    !strcmp(codec->modelname, models[i])) {
 				snd_printd(KERN_INFO "hda_codec: model '%s' is "
 					   "selected\n", models[i]);
 				return i;
@@ -2370,6 +2709,7 @@
 	}
 	return -1;
 }
+EXPORT_SYMBOL_HDA(snd_hda_check_board_config);
 
 /**
  * snd_hda_add_new_ctls - create controls from the array
@@ -2390,7 +2730,7 @@
 		kctl = snd_ctl_new1(knew, codec);
 		if (!kctl)
 			return -ENOMEM;
-		err = snd_ctl_add(codec->bus->card, kctl);
+		err = snd_hda_ctl_add(codec, kctl);
 		if (err < 0) {
 			if (!codec->addr)
 				return err;
@@ -2398,13 +2738,14 @@
 			if (!kctl)
 				return -ENOMEM;
 			kctl->id.device = codec->addr;
-			err = snd_ctl_add(codec->bus->card, kctl);
+			err = snd_hda_ctl_add(codec, kctl);
 			if (err < 0)
 				return err;
 		}
 	}
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
@@ -2414,6 +2755,7 @@
 {
 	struct hda_codec *codec =
 		container_of(work, struct hda_codec, power_work.work);
+	struct hda_bus *bus = codec->bus;
 
 	if (!codec->power_on || codec->power_count) {
 		codec->power_transition = 0;
@@ -2421,8 +2763,8 @@
 	}
 
 	hda_call_codec_suspend(codec);
-	if (codec->bus->ops.pm_notify)
-		codec->bus->ops.pm_notify(codec);
+	if (bus->ops.pm_notify)
+		bus->ops.pm_notify(bus);
 }
 
 static void hda_keep_power_on(struct hda_codec *codec)
@@ -2433,29 +2775,39 @@
 
 void snd_hda_power_up(struct hda_codec *codec)
 {
+	struct hda_bus *bus = codec->bus;
+
 	codec->power_count++;
 	if (codec->power_on || codec->power_transition)
 		return;
 
 	codec->power_on = 1;
-	if (codec->bus->ops.pm_notify)
-		codec->bus->ops.pm_notify(codec);
+	if (bus->ops.pm_notify)
+		bus->ops.pm_notify(bus);
 	hda_call_codec_resume(codec);
 	cancel_delayed_work(&codec->power_work);
 	codec->power_transition = 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_power_up);
+
+#define power_save(codec)	\
+	((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
+
+#define power_save(codec)	\
+	((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
 
 void snd_hda_power_down(struct hda_codec *codec)
 {
 	--codec->power_count;
 	if (!codec->power_on || codec->power_count || codec->power_transition)
 		return;
-	if (power_save) {
+	if (power_save(codec)) {
 		codec->power_transition = 1; /* avoid reentrance */
 		schedule_delayed_work(&codec->power_work,
-				      msecs_to_jiffies(power_save * 1000));
+				msecs_to_jiffies(power_save(codec) * 1000));
 	}
 }
+EXPORT_SYMBOL_HDA(snd_hda_power_down);
 
 int snd_hda_check_amp_list_power(struct hda_codec *codec,
 				 struct hda_loopback_check *check,
@@ -2492,6 +2844,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power);
 #endif
 
 /*
@@ -2511,6 +2864,7 @@
 		chmode[uinfo->value.enumerated.item].channels);
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_ch_mode_info);
 
 int snd_hda_ch_mode_get(struct hda_codec *codec,
 			struct snd_ctl_elem_value *ucontrol,
@@ -2528,6 +2882,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_ch_mode_get);
 
 int snd_hda_ch_mode_put(struct hda_codec *codec,
 			struct snd_ctl_elem_value *ucontrol,
@@ -2548,6 +2903,7 @@
 		snd_hda_sequence_write_cache(codec, chmode[mode].sequence);
 	return 1;
 }
+EXPORT_SYMBOL_HDA(snd_hda_ch_mode_put);
 
 /*
  * input MUX helper
@@ -2568,6 +2924,7 @@
 	strcpy(uinfo->value.enumerated.name, imux->items[index].label);
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_input_mux_info);
 
 int snd_hda_input_mux_put(struct hda_codec *codec,
 			  const struct hda_input_mux *imux,
@@ -2589,6 +2946,7 @@
 	*cur_val = idx;
 	return 1;
 }
+EXPORT_SYMBOL_HDA(snd_hda_input_mux_put);
 
 
 /*
@@ -2641,6 +2999,7 @@
 	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_open);
 
 int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
 				  struct hda_multi_out *mout,
@@ -2653,6 +3012,7 @@
 	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare);
 
 /*
  * release the digital out
@@ -2665,6 +3025,7 @@
 	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_close);
 
 /*
  * set up more restrictions for analog out
@@ -2704,6 +3065,7 @@
 	return snd_pcm_hw_constraint_step(substream->runtime, 0,
 					  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
 }
+EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_open);
 
 /*
  * set up the i/o for analog out
@@ -2762,6 +3124,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare);
 
 /*
  * clean up the setting for analog out
@@ -2788,6 +3151,7 @@
 	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup);
 
 /*
  * Helper for automatic pin configuration
@@ -3073,11 +3437,13 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
 
 /* labels for input pins */
 const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = {
 	"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
 };
+EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
 
 
 #ifdef CONFIG_PM
@@ -3105,11 +3471,11 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_suspend);
 
 /**
  * snd_hda_resume - resume the codecs
  * @bus: the HDA bus
- * @state: resume state
  *
  * Returns 0 if successful.
  *
@@ -3126,16 +3492,79 @@
 	}
 	return 0;
 }
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-int snd_hda_codecs_inuse(struct hda_bus *bus)
-{
-	struct hda_codec *codec;
+EXPORT_SYMBOL_HDA(snd_hda_resume);
+#endif /* CONFIG_PM */
 
-	list_for_each_entry(codec, &bus->codec_list, list) {
-		if (snd_hda_codec_needs_resume(codec))
-			return 1;
+/*
+ * generic arrays
+ */
+
+/* get a new element from the given array
+ * if it exceeds the pre-allocated array size, re-allocate the array
+ */
+void *snd_array_new(struct snd_array *array)
+{
+	if (array->used >= array->alloced) {
+		int num = array->alloced + array->alloc_align;
+		void *nlist;
+		if (snd_BUG_ON(num >= 4096))
+			return NULL;
+		nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL);
+		if (!nlist)
+			return NULL;
+		if (array->list) {
+			memcpy(nlist, array->list,
+			       array->elem_size * array->alloced);
+			kfree(array->list);
+		}
+		array->list = nlist;
+		array->alloced = num;
 	}
-	return 0;
+	return snd_array_elem(array, array->used++);
 }
-#endif
-#endif
+EXPORT_SYMBOL_HDA(snd_array_new);
+
+/* free the given array elements */
+void snd_array_free(struct snd_array *array)
+{
+	kfree(array->list);
+	array->used = 0;
+	array->alloced = 0;
+	array->list = NULL;
+}
+EXPORT_SYMBOL_HDA(snd_array_free);
+
+/*
+ * used by hda_proc.c and hda_eld.c
+ */
+void snd_print_pcm_rates(int pcm, char *buf, int buflen)
+{
+	static unsigned int rates[] = {
+		8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
+		96000, 176400, 192000, 384000
+	};
+	int i, j;
+
+	for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++)
+		if (pcm & (1 << i))
+			j += snprintf(buf + j, buflen - j,  " %d", rates[i]);
+
+	buf[j] = '\0'; /* necessary when j == 0 */
+}
+EXPORT_SYMBOL_HDA(snd_print_pcm_rates);
+
+void snd_print_pcm_bits(int pcm, char *buf, int buflen)
+{
+	static unsigned int bits[] = { 8, 16, 20, 24, 32 };
+	int i, j;
+
+	for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++)
+		if (pcm & (AC_SUPPCM_BITS_8 << i))
+			j += snprintf(buf + j, buflen - j,  " %d", bits[i]);
+
+	buf[j] = '\0'; /* necessary when j == 0 */
+}
+EXPORT_SYMBOL_HDA(snd_print_pcm_bits);
+
+MODULE_DESCRIPTION("HDA codec core");
+MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 60468f5..729fc76 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -520,6 +520,36 @@
 #define HDA_MAX_CODEC_ADDRESS	0x0f
 
 /*
+ * generic arrays
+ */
+struct snd_array {
+	unsigned int used;
+	unsigned int alloced;
+	unsigned int elem_size;
+	unsigned int alloc_align;
+	void *list;
+};
+
+void *snd_array_new(struct snd_array *array);
+void snd_array_free(struct snd_array *array);
+static inline void snd_array_init(struct snd_array *array, unsigned int size,
+				  unsigned int align)
+{
+	array->elem_size = size;
+	array->alloc_align = align;
+}
+
+static inline void *snd_array_elem(struct snd_array *array, unsigned int idx)
+{
+	return array->list + idx * array->elem_size;
+}
+
+static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
+{
+	return (unsigned long)(ptr - array->list) / array->elem_size;
+}
+
+/*
  * Structures
  */
 
@@ -536,15 +566,17 @@
 /* bus operators */
 struct hda_bus_ops {
 	/* send a single command */
-	int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct,
-		       unsigned int verb, unsigned int parm);
+	int (*command)(struct hda_bus *bus, unsigned int cmd);
 	/* get a response from the last command */
-	unsigned int (*get_response)(struct hda_codec *codec);
+	unsigned int (*get_response)(struct hda_bus *bus);
 	/* free the private data */
 	void (*private_free)(struct hda_bus *);
+	/* attach a PCM stream */
+	int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec,
+			  struct hda_pcm *pcm);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	/* notify power-up/down from codec to controller */
-	void (*pm_notify)(struct hda_codec *codec);
+	void (*pm_notify)(struct hda_bus *bus);
 #endif
 };
 
@@ -553,6 +585,7 @@
 	void *private_data;
 	struct pci_dev *pci;
 	const char *modelname;
+	int *power_save;
 	struct hda_bus_ops ops;
 };
 
@@ -569,6 +602,7 @@
 	void *private_data;
 	struct pci_dev *pci;
 	const char *modelname;
+	int *power_save;
 	struct hda_bus_ops ops;
 
 	/* codec linked list */
@@ -581,10 +615,12 @@
 	/* unsolicited event queue */
 	struct hda_bus_unsolicited *unsol;
 
-	struct snd_info_entry *proc;
+	/* assigned PCMs */
+	DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
 
 	/* misc op flags */
 	unsigned int needs_damn_long_delay :1;
+	unsigned int shutdown :1;	/* being unloaded */
 };
 
 /*
@@ -604,6 +640,16 @@
 	int (*patch)(struct hda_codec *codec);
 };
 	
+struct hda_codec_preset_list {
+	const struct hda_codec_preset *preset;
+	struct module *owner;
+	struct list_head list;
+};
+
+/* initial hook */
+int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset);
+int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset);
+
 /* ops set by the preset patch */
 struct hda_codec_ops {
 	int (*build_controls)(struct hda_codec *codec);
@@ -635,10 +681,7 @@
 
 struct hda_cache_rec {
 	u16 hash[64];			/* hash table for index */
-	unsigned int num_entries;	/* number of assigned entries */
-	unsigned int size;		/* allocated size */
-	unsigned int record_size;	/* record size (including header) */
-	void *buffer;			/* hash table entries */
+	struct snd_array buf;		/* record entries */
 };
 
 /* PCM callbacks */
@@ -680,7 +723,8 @@
 	char *name;
 	struct hda_pcm_stream stream[2];
 	unsigned int pcm_type;	/* HDA_PCM_TYPE_XXX */
-	int device;	/* assigned device number */
+	int device;		/* device number to assign */
+	struct snd_pcm *pcm;	/* assigned PCM instance */
 };
 
 /* codec information */
@@ -699,6 +743,9 @@
 
 	/* detected preset */
 	const struct hda_codec_preset *preset;
+	struct module *owner;
+	const char *name;	/* codec name */
+	const char *modelname;	/* model name for preset */
 
 	/* set by patch */
 	struct hda_codec_ops patch_ops;
@@ -718,6 +765,8 @@
 	hda_nid_t start_nid;
 	u32 *wcaps;
 
+	struct snd_array mixers;	/* list of assigned mixer elements */
+
 	struct hda_cache_rec amp_cache;	/* cache for amp access */
 	struct hda_cache_rec cmd_cache;	/* cache for other commands */
 
@@ -727,7 +776,11 @@
 	unsigned int spdif_in_enable;	/* SPDIF input enable? */
 	hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
 
+#ifdef CONFIG_SND_HDA_HWDEP
 	struct snd_hwdep *hwdep;	/* assigned hwdep device */
+	struct snd_array init_verbs;	/* additional init verbs */
+	struct snd_array hints;		/* additional hints */
+#endif
 
 	/* misc flags */
 	unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
@@ -740,6 +793,10 @@
 	int power_count;	/* current (global) power refcount */
 	struct delayed_work power_work; /* delayed task for powerdown */
 #endif
+
+	/* codec-specific additional proc output */
+	void (*proc_widget_hook)(struct snd_info_buffer *buffer,
+				 struct hda_codec *codec, hda_nid_t nid);
 };
 
 /* direction */
@@ -754,7 +811,7 @@
 int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
 		    struct hda_bus **busp);
 int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
-		      struct hda_codec **codecp);
+		      int do_init, struct hda_codec **codecp);
 
 /*
  * low level functions
@@ -799,11 +856,13 @@
  * Mixer
  */
 int snd_hda_build_controls(struct hda_bus *bus);
+int snd_hda_codec_build_controls(struct hda_codec *codec);
 
 /*
  * PCM
  */
 int snd_hda_build_pcms(struct hda_bus *bus);
+int snd_hda_codec_build_pcms(struct hda_codec *codec);
 void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 				u32 stream_tag,
 				int channel_id, int format);
@@ -812,8 +871,6 @@
 					unsigned int channels,
 					unsigned int format,
 					unsigned int maxbps);
-int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
-				u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
 int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
 				unsigned int format);
 
@@ -831,18 +888,38 @@
 #endif
 
 /*
+ * get widget information
+ */
+const char *snd_hda_get_jack_connectivity(u32 cfg);
+const char *snd_hda_get_jack_type(u32 cfg);
+const char *snd_hda_get_jack_location(u32 cfg);
+
+/*
  * power saving
  */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 void snd_hda_power_up(struct hda_codec *codec);
 void snd_hda_power_down(struct hda_codec *codec);
 #define snd_hda_codec_needs_resume(codec) codec->power_count
-int snd_hda_codecs_inuse(struct hda_bus *bus);
 #else
 static inline void snd_hda_power_up(struct hda_codec *codec) {}
 static inline void snd_hda_power_down(struct hda_codec *codec) {}
 #define snd_hda_codec_needs_resume(codec) 1
-#define snd_hda_codecs_inuse(bus) 1
+#endif
+
+/*
+ * Codec modularization
+ */
+
+/* Export symbols only for communication with codec drivers;
+ * When built in kernel, all HD-audio drivers are supposed to be statically
+ * linked to the kernel.  Thus, the symbols don't have to (or shouldn't) be
+ * exported unless it's built as a module.
+ */
+#ifdef MODULE
+#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym)
+#else
+#define EXPORT_SYMBOL_HDA(sym)
 #endif
 
 #endif /* __SOUND_HDA_CODEC_H */
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
new file mode 100644
index 0000000..fcad5ec
--- /dev/null
+++ b/sound/pci/hda/hda_eld.c
@@ -0,0 +1,590 @@
+/*
+ * Generic routines and proc interface for ELD(EDID Like Data) information
+ *
+ * Copyright(c) 2008 Intel Corporation.
+ *
+ * Authors:
+ * 		Wu Fengguang <wfg@linux.intel.com>
+ *
+ *  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 <sound/core.h>
+#include <asm/unaligned.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+enum eld_versions {
+	ELD_VER_CEA_861D	= 2,
+	ELD_VER_PARTIAL		= 31,
+};
+
+enum cea_edid_versions {
+	CEA_EDID_VER_NONE	= 0,
+	CEA_EDID_VER_CEA861	= 1,
+	CEA_EDID_VER_CEA861A	= 2,
+	CEA_EDID_VER_CEA861BCD	= 3,
+	CEA_EDID_VER_RESERVED	= 4,
+};
+
+static char *cea_speaker_allocation_names[] = {
+	/*  0 */ "FL/FR",
+	/*  1 */ "LFE",
+	/*  2 */ "FC",
+	/*  3 */ "RL/RR",
+	/*  4 */ "RC",
+	/*  5 */ "FLC/FRC",
+	/*  6 */ "RLC/RRC",
+	/*  7 */ "FLW/FRW",
+	/*  8 */ "FLH/FRH",
+	/*  9 */ "TC",
+	/* 10 */ "FCH",
+};
+
+static char *eld_connection_type_names[4] = {
+	"HDMI",
+	"DisplayPort",
+	"2-reserved",
+	"3-reserved"
+};
+
+enum cea_audio_coding_types {
+	AUDIO_CODING_TYPE_REF_STREAM_HEADER	=  0,
+	AUDIO_CODING_TYPE_LPCM			=  1,
+	AUDIO_CODING_TYPE_AC3			=  2,
+	AUDIO_CODING_TYPE_MPEG1			=  3,
+	AUDIO_CODING_TYPE_MP3			=  4,
+	AUDIO_CODING_TYPE_MPEG2			=  5,
+	AUDIO_CODING_TYPE_AACLC			=  6,
+	AUDIO_CODING_TYPE_DTS			=  7,
+	AUDIO_CODING_TYPE_ATRAC			=  8,
+	AUDIO_CODING_TYPE_SACD			=  9,
+	AUDIO_CODING_TYPE_EAC3			= 10,
+	AUDIO_CODING_TYPE_DTS_HD		= 11,
+	AUDIO_CODING_TYPE_MLP			= 12,
+	AUDIO_CODING_TYPE_DST			= 13,
+	AUDIO_CODING_TYPE_WMAPRO		= 14,
+	AUDIO_CODING_TYPE_REF_CXT		= 15,
+	/* also include valid xtypes below */
+	AUDIO_CODING_TYPE_HE_AAC		= 15,
+	AUDIO_CODING_TYPE_HE_AAC2		= 16,
+	AUDIO_CODING_TYPE_MPEG_SURROUND		= 17,
+};
+
+enum cea_audio_coding_xtypes {
+	AUDIO_CODING_XTYPE_HE_REF_CT		= 0,
+	AUDIO_CODING_XTYPE_HE_AAC		= 1,
+	AUDIO_CODING_XTYPE_HE_AAC2		= 2,
+	AUDIO_CODING_XTYPE_MPEG_SURROUND	= 3,
+	AUDIO_CODING_XTYPE_FIRST_RESERVED	= 4,
+};
+
+static char *cea_audio_coding_type_names[] = {
+	/*  0 */ "undefined",
+	/*  1 */ "LPCM",
+	/*  2 */ "AC-3",
+	/*  3 */ "MPEG1",
+	/*  4 */ "MP3",
+	/*  5 */ "MPEG2",
+	/*  6 */ "AAC-LC",
+	/*  7 */ "DTS",
+	/*  8 */ "ATRAC",
+	/*  9 */ "DSD (One Bit Audio)",
+	/* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)",
+	/* 11 */ "DTS-HD",
+	/* 12 */ "MLP (Dolby TrueHD)",
+	/* 13 */ "DST",
+	/* 14 */ "WMAPro",
+	/* 15 */ "HE-AAC",
+	/* 16 */ "HE-AACv2",
+	/* 17 */ "MPEG Surround",
+};
+
+/*
+ * The following two lists are shared between
+ * 	- HDMI audio InfoFrame (source to sink)
+ * 	- CEA E-EDID Extension (sink to source)
+ */
+
+/*
+ * SS1:SS0 index => sample size
+ */
+static int cea_sample_sizes[4] = {
+	0,	 		/* 0: Refer to Stream Header */
+	AC_SUPPCM_BITS_16,	/* 1: 16 bits */
+	AC_SUPPCM_BITS_20,	/* 2: 20 bits */
+	AC_SUPPCM_BITS_24,	/* 3: 24 bits */
+};
+
+/*
+ * SF2:SF1:SF0 index => sampling frequency
+ */
+static int cea_sampling_frequencies[8] = {
+	0,			/* 0: Refer to Stream Header */
+	SNDRV_PCM_RATE_32000,	/* 1:  32000Hz */
+	SNDRV_PCM_RATE_44100,	/* 2:  44100Hz */
+	SNDRV_PCM_RATE_48000,	/* 3:  48000Hz */
+	SNDRV_PCM_RATE_88200,	/* 4:  88200Hz */
+	SNDRV_PCM_RATE_96000,	/* 5:  96000Hz */
+	SNDRV_PCM_RATE_176400,	/* 6: 176400Hz */
+	SNDRV_PCM_RATE_192000,	/* 7: 192000Hz */
+};
+
+static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid,
+					int byte_index)
+{
+	unsigned int val;
+
+	val = snd_hda_codec_read(codec, nid, 0,
+					AC_VERB_GET_HDMI_ELDD, byte_index);
+
+#ifdef BE_PARANOID
+	printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
+#endif
+
+	if ((val & AC_ELDD_ELD_VALID) == 0) {
+		snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n",
+								byte_index);
+		val = 0;
+	}
+
+	return val & AC_ELDD_ELD_DATA;
+}
+
+#define GRAB_BITS(buf, byte, lowbit, bits) 		\
+({							\
+	BUILD_BUG_ON(lowbit > 7);			\
+	BUILD_BUG_ON(bits > 8);				\
+	BUILD_BUG_ON(bits <= 0);			\
+							\
+	(buf[byte] >> (lowbit)) & ((1 << (bits)) - 1);	\
+})
+
+static void hdmi_update_short_audio_desc(struct cea_sad *a,
+					 const unsigned char *buf)
+{
+	int i;
+	int val;
+
+	val = GRAB_BITS(buf, 1, 0, 7);
+	a->rates = 0;
+	for (i = 0; i < 7; i++)
+		if (val & (1 << i))
+			a->rates |= cea_sampling_frequencies[i + 1];
+
+	a->channels = GRAB_BITS(buf, 0, 0, 3);
+	a->channels++;
+
+	a->format = GRAB_BITS(buf, 0, 3, 4);
+	switch (a->format) {
+	case AUDIO_CODING_TYPE_REF_STREAM_HEADER:
+		snd_printd(KERN_INFO
+				"HDMI: audio coding type 0 not expected\n");
+		break;
+
+	case AUDIO_CODING_TYPE_LPCM:
+		val = GRAB_BITS(buf, 2, 0, 3);
+		a->sample_bits = 0;
+		for (i = 0; i < 3; i++)
+			if (val & (1 << i))
+				a->sample_bits |= cea_sample_sizes[i + 1];
+		break;
+
+	case AUDIO_CODING_TYPE_AC3:
+	case AUDIO_CODING_TYPE_MPEG1:
+	case AUDIO_CODING_TYPE_MP3:
+	case AUDIO_CODING_TYPE_MPEG2:
+	case AUDIO_CODING_TYPE_AACLC:
+	case AUDIO_CODING_TYPE_DTS:
+	case AUDIO_CODING_TYPE_ATRAC:
+		a->max_bitrate = GRAB_BITS(buf, 2, 0, 8);
+		a->max_bitrate *= 8000;
+		break;
+
+	case AUDIO_CODING_TYPE_SACD:
+		break;
+
+	case AUDIO_CODING_TYPE_EAC3:
+		break;
+
+	case AUDIO_CODING_TYPE_DTS_HD:
+		break;
+
+	case AUDIO_CODING_TYPE_MLP:
+		break;
+
+	case AUDIO_CODING_TYPE_DST:
+		break;
+
+	case AUDIO_CODING_TYPE_WMAPRO:
+		a->profile = GRAB_BITS(buf, 2, 0, 3);
+		break;
+
+	case AUDIO_CODING_TYPE_REF_CXT:
+		a->format = GRAB_BITS(buf, 2, 3, 5);
+		if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT ||
+		    a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) {
+			snd_printd(KERN_INFO
+				"HDMI: audio coding xtype %d not expected\n",
+				a->format);
+			a->format = 0;
+		} else
+			a->format += AUDIO_CODING_TYPE_HE_AAC -
+				     AUDIO_CODING_XTYPE_HE_AAC;
+		break;
+	}
+}
+
+/*
+ * Be careful, ELD buf could be totally rubbish!
+ */
+static int hdmi_update_eld(struct hdmi_eld *e,
+			   const unsigned char *buf, int size)
+{
+	int mnl;
+	int i;
+
+	e->eld_ver = GRAB_BITS(buf, 0, 3, 5);
+	if (e->eld_ver != ELD_VER_CEA_861D &&
+	    e->eld_ver != ELD_VER_PARTIAL) {
+		snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n",
+								e->eld_ver);
+		goto out_fail;
+	}
+
+	e->eld_size = size;
+	e->baseline_len = GRAB_BITS(buf, 2, 0, 8);
+	mnl		= GRAB_BITS(buf, 4, 0, 5);
+	e->cea_edid_ver	= GRAB_BITS(buf, 4, 5, 3);
+
+	e->support_hdcp	= GRAB_BITS(buf, 5, 0, 1);
+	e->support_ai	= GRAB_BITS(buf, 5, 1, 1);
+	e->conn_type	= GRAB_BITS(buf, 5, 2, 2);
+	e->sad_count	= GRAB_BITS(buf, 5, 4, 4);
+
+	e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2;
+	e->spk_alloc	= GRAB_BITS(buf, 7, 0, 7);
+
+	e->port_id	  = get_unaligned_le64(buf + 8);
+
+	/* not specified, but the spec's tendency is little endian */
+	e->manufacture_id = get_unaligned_le16(buf + 16);
+	e->product_id	  = get_unaligned_le16(buf + 18);
+
+	if (mnl > ELD_MAX_MNL) {
+		snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl);
+		goto out_fail;
+	} else if (ELD_FIXED_BYTES + mnl > size) {
+		snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl);
+		goto out_fail;
+	} else
+		strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl);
+
+	for (i = 0; i < e->sad_count; i++) {
+		if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) {
+			snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i);
+			goto out_fail;
+		}
+		hdmi_update_short_audio_desc(e->sad + i,
+					buf + ELD_FIXED_BYTES + mnl + 3 * i);
+	}
+
+	return 0;
+
+out_fail:
+	e->eld_ver = 0;
+	return -EINVAL;
+}
+
+static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid)
+{
+	return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0);
+}
+
+static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid)
+{
+	int eldv;
+	int present;
+
+	present = hdmi_present_sense(codec, nid);
+	eldv    = (present & AC_PINSENSE_ELDV);
+	present = (present & AC_PINSENSE_PRESENCE);
+
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+	printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n",
+			!!present, !!eldv);
+#endif
+
+	return eldv && present;
+}
+
+int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
+{
+	return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
+						 AC_DIPSIZE_ELD_BUF);
+}
+
+int snd_hdmi_get_eld(struct hdmi_eld *eld,
+		     struct hda_codec *codec, hda_nid_t nid)
+{
+	int i;
+	int ret;
+	int size;
+	unsigned char *buf;
+
+	if (!hdmi_eld_valid(codec, nid))
+		return -ENOENT;
+
+	size = snd_hdmi_get_eld_size(codec, nid);
+	if (size == 0) {
+		/* wfg: workaround for ASUS P5E-VM HDMI board */
+		snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n");
+		size = 128;
+	}
+	if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) {
+		snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size);
+		return -ERANGE;
+	}
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < size; i++)
+		buf[i] = hdmi_get_eld_byte(codec, nid, i);
+
+	ret = hdmi_update_eld(eld, buf, size);
+
+	kfree(buf);
+	return ret;
+}
+
+static void hdmi_show_short_audio_desc(struct cea_sad *a)
+{
+	char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
+	char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits =";
+
+	if (!a->format)
+		return;
+
+	snd_print_pcm_rates(a->rates, buf, sizeof(buf));
+
+	if (a->format == AUDIO_CODING_TYPE_LPCM)
+		snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8));
+	else if (a->max_bitrate)
+		snprintf(buf2, sizeof(buf2),
+				", max bitrate = %d", a->max_bitrate);
+	else
+		buf2[0] = '\0';
+
+	printk(KERN_INFO "HDMI: supports coding type %s:"
+			" channels = %d, rates =%s%s\n",
+			cea_audio_coding_type_names[a->format],
+			a->channels,
+			buf,
+			buf2);
+}
+
+void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
+{
+	int i, j;
+
+	for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) {
+		if (spk_alloc & (1 << i))
+			j += snprintf(buf + j, buflen - j,  " %s",
+					cea_speaker_allocation_names[i]);
+	}
+	buf[j] = '\0';	/* necessary when j == 0 */
+}
+
+void snd_hdmi_show_eld(struct hdmi_eld *e)
+{
+	int i;
+
+	printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n",
+			e->monitor_name,
+			eld_connection_type_names[e->conn_type]);
+
+	if (e->spk_alloc) {
+		char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+		snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
+		printk(KERN_INFO "HDMI: available speakers:%s\n", buf);
+	}
+
+	for (i = 0; i < e->sad_count; i++)
+		hdmi_show_short_audio_desc(e->sad + i);
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void hdmi_print_sad_info(int i, struct cea_sad *a,
+				struct snd_info_buffer *buffer)
+{
+	char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
+
+	snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n",
+			i, a->format, cea_audio_coding_type_names[a->format]);
+	snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels);
+
+	snd_print_pcm_rates(a->rates, buf, sizeof(buf));
+	snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf);
+
+	if (a->format == AUDIO_CODING_TYPE_LPCM) {
+		snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf));
+		snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n",
+							i, a->sample_bits, buf);
+	}
+
+	if (a->max_bitrate)
+		snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n",
+							i, a->max_bitrate);
+
+	if (a->profile)
+		snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile);
+}
+
+static void hdmi_print_eld_info(struct snd_info_entry *entry,
+				struct snd_info_buffer *buffer)
+{
+	struct hdmi_eld *e = entry->private_data;
+	char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+	int i;
+	static char *eld_versoin_names[32] = {
+		"reserved",
+		"reserved",
+		"CEA-861D or below",
+		[3 ... 30] = "reserved",
+		[31] = "partial"
+	};
+	static char *cea_edid_version_names[8] = {
+		"no CEA EDID Timing Extension block present",
+		"CEA-861",
+		"CEA-861-A",
+		"CEA-861-B, C or D",
+		[4 ... 7] = "reserved"
+	};
+
+	snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
+	snd_iprintf(buffer, "connection_type\t\t%s\n",
+				eld_connection_type_names[e->conn_type]);
+	snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver,
+					eld_versoin_names[e->eld_ver]);
+	snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver,
+				cea_edid_version_names[e->cea_edid_ver]);
+	snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id);
+	snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id);
+	snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id);
+	snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp);
+	snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai);
+	snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay);
+
+	snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
+	snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf);
+
+	snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count);
+
+	for (i = 0; i < e->sad_count; i++)
+		hdmi_print_sad_info(i, e->sad + i, buffer);
+}
+
+static void hdmi_write_eld_info(struct snd_info_entry *entry,
+				struct snd_info_buffer *buffer)
+{
+	struct hdmi_eld *e = entry->private_data;
+	char line[64];
+	char name[64];
+	char *sname;
+	long long val;
+	int n;
+
+	while (!snd_info_get_line(buffer, line, sizeof(line))) {
+		if (sscanf(line, "%s %llx", name, &val) != 2)
+			continue;
+		/*
+		 * We don't allow modification to these fields:
+		 * 	monitor_name manufacture_id product_id
+		 * 	eld_version edid_version
+		 */
+		if (!strcmp(name, "connection_type"))
+			e->conn_type = val;
+		else if (!strcmp(name, "port_id"))
+			e->port_id = val;
+		else if (!strcmp(name, "support_hdcp"))
+			e->support_hdcp = val;
+		else if (!strcmp(name, "support_ai"))
+			e->support_ai = val;
+		else if (!strcmp(name, "audio_sync_delay"))
+			e->aud_synch_delay = val;
+		else if (!strcmp(name, "speakers"))
+			e->spk_alloc = val;
+		else if (!strcmp(name, "sad_count"))
+			e->sad_count = val;
+		else if (!strncmp(name, "sad", 3)) {
+			sname = name + 4;
+			n = name[3] - '0';
+			if (name[4] >= '0' && name[4] <= '9') {
+				sname++;
+				n = 10 * n + name[4] - '0';
+			}
+			if (n < 0 || n > 31) /* double the CEA limit */
+				continue;
+			if (!strcmp(sname, "_coding_type"))
+				e->sad[n].format = val;
+			else if (!strcmp(sname, "_channels"))
+				e->sad[n].channels = val;
+			else if (!strcmp(sname, "_rates"))
+				e->sad[n].rates = val;
+			else if (!strcmp(sname, "_bits"))
+				e->sad[n].sample_bits = val;
+			else if (!strcmp(sname, "_max_bitrate"))
+				e->sad[n].max_bitrate = val;
+			else if (!strcmp(sname, "_profile"))
+				e->sad[n].profile = val;
+			if (n >= e->sad_count)
+				e->sad_count = n + 1;
+		}
+	}
+}
+
+
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld)
+{
+	char name[32];
+	struct snd_info_entry *entry;
+	int err;
+
+	snprintf(name, sizeof(name), "eld#%d", codec->addr);
+	err = snd_card_proc_new(codec->bus->card, name, &entry);
+	if (err < 0)
+		return err;
+
+	snd_info_set_text_ops(entry, eld, hdmi_print_eld_info);
+	entry->c.text.write = hdmi_write_eld_info;
+	entry->mode |= S_IWUSR;
+	eld->proc_entry = entry;
+
+	return 0;
+}
+
+void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
+{
+	if (!codec->bus->shutdown && eld->proc_entry) {
+		snd_device_free(codec->bus->card, eld->proc_entry);
+		eld->proc_entry = NULL;
+	}
+}
+
+#endif /* CONFIG_PROC_FS */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 0ca3089..65745e9 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -723,7 +723,8 @@
 		if (is_loopback)
 			add_input_loopback(codec, node->nid, HDA_INPUT, index);
 		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
-		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+		if (err < 0)
 			return err;
 		created = 1;
 	} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
@@ -732,7 +733,8 @@
 		if (is_loopback)
 			add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
 		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
-		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+		if (err < 0)
 			return err;
 		created = 1;
 	}
@@ -745,14 +747,16 @@
 	    (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
 		knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
 		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
-		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+		if (err < 0)
 			return err;
 		created = 1;
 	} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
 		   (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
 		knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
 		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
-		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+		if (err < 0)
 			return err;
 		created = 1;
 	}
@@ -849,8 +853,8 @@
 	}
 
 	/* create input MUX if multiple sources are available */
-	if ((err = snd_ctl_add(codec->bus->card,
-			       snd_ctl_new1(&cap_sel, codec))) < 0)
+	err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec));
+	if (err < 0)
 		return err;
 
 	/* no volume control? */
@@ -867,8 +871,8 @@
 			HDA_CODEC_VOLUME(name, adc_node->nid,
 					 spec->input_mux.items[i].index,
 					 HDA_INPUT);
-		if ((err = snd_ctl_add(codec->bus->card,
-				       snd_ctl_new1(&knew, codec))) < 0)
+		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+		if (err < 0)
 			return err;
 	}
 
@@ -1097,3 +1101,4 @@
 	snd_hda_generic_free(codec);
 	return err;
 }
+EXPORT_SYMBOL(snd_hda_parse_generic_codec);
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 6e18a42..300ab40 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -23,10 +23,12 @@
 #include <linux/pci.h>
 #include <linux/compat.h>
 #include <linux/mutex.h>
+#include <linux/ctype.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include <sound/hda_hwdep.h>
+#include <sound/minors.h>
 
 /*
  * write/read an out-of-bound verb
@@ -95,7 +97,26 @@
 	return 0;
 }
 
-int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
+static void clear_hwdep_elements(struct hda_codec *codec)
+{
+	char **head;
+	int i;
+
+	/* clear init verbs */
+	snd_array_free(&codec->init_verbs);
+	/* clear hints */
+	head = codec->hints.list;
+	for (i = 0; i < codec->hints.used; i++, head++)
+		kfree(*head);
+	snd_array_free(&codec->hints);
+}
+
+static void hwdep_free(struct snd_hwdep *hwdep)
+{
+	clear_hwdep_elements(hwdep->private_data);
+}
+
+int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
 {
 	char hwname[16];
 	struct snd_hwdep *hwdep;
@@ -109,6 +130,7 @@
 	sprintf(hwdep->name, "HDA Codec %d", codec->addr);
 	hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
 	hwdep->private_data = codec;
+	hwdep->private_free = hwdep_free;
 	hwdep->exclusive = 1;
 
 	hwdep->ops.open = hda_hwdep_open;
@@ -117,5 +139,215 @@
 	hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
 #endif
 
+	snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
+	snd_array_init(&codec->hints, sizeof(char *), 32);
+
 	return 0;
 }
+
+#ifdef CONFIG_SND_HDA_RECONFIG
+
+/*
+ * sysfs interface
+ */
+
+static int clear_codec(struct hda_codec *codec)
+{
+	snd_hda_codec_reset(codec);
+	clear_hwdep_elements(codec);
+	return 0;
+}
+
+static int reconfig_codec(struct hda_codec *codec)
+{
+	int err;
+
+	snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
+	snd_hda_codec_reset(codec);
+	err = snd_hda_codec_configure(codec);
+	if (err < 0)
+		return err;
+	/* rebuild PCMs */
+	err = snd_hda_codec_build_pcms(codec);
+	if (err < 0)
+		return err;
+	/* rebuild mixers */
+	err = snd_hda_codec_build_controls(codec);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+/*
+ * allocate a string at most len chars, and remove the trailing EOL
+ */
+static char *kstrndup_noeol(const char *src, size_t len)
+{
+	char *s = kstrndup(src, len, GFP_KERNEL);
+	char *p;
+	if (!s)
+		return NULL;
+	p = strchr(s, '\n');
+	if (p)
+		*p = 0;
+	return s;
+}
+
+#define CODEC_INFO_SHOW(type)					\
+static ssize_t type##_show(struct device *dev,			\
+			   struct device_attribute *attr,	\
+			   char *buf)				\
+{								\
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);		\
+	struct hda_codec *codec = hwdep->private_data;		\
+	return sprintf(buf, "0x%x\n", codec->type);		\
+}
+
+#define CODEC_INFO_STR_SHOW(type)				\
+static ssize_t type##_show(struct device *dev,			\
+			     struct device_attribute *attr,	\
+					char *buf)		\
+{								\
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);		\
+	struct hda_codec *codec = hwdep->private_data;		\
+	return sprintf(buf, "%s\n",				\
+		       codec->type ? codec->type : "");		\
+}
+
+CODEC_INFO_SHOW(vendor_id);
+CODEC_INFO_SHOW(subsystem_id);
+CODEC_INFO_SHOW(revision_id);
+CODEC_INFO_SHOW(afg);
+CODEC_INFO_SHOW(mfg);
+CODEC_INFO_STR_SHOW(name);
+CODEC_INFO_STR_SHOW(modelname);
+
+#define CODEC_INFO_STORE(type)					\
+static ssize_t type##_store(struct device *dev,			\
+			    struct device_attribute *attr,	\
+			    const char *buf, size_t count)	\
+{								\
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);		\
+	struct hda_codec *codec = hwdep->private_data;		\
+	char *after;						\
+	codec->type = simple_strtoul(buf, &after, 0);		\
+	return count;						\
+}
+
+#define CODEC_INFO_STR_STORE(type)				\
+static ssize_t type##_store(struct device *dev,			\
+			    struct device_attribute *attr,	\
+			    const char *buf, size_t count)	\
+{								\
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);		\
+	struct hda_codec *codec = hwdep->private_data;		\
+	char *s = kstrndup_noeol(buf, 64);			\
+	if (!s)							\
+		return -ENOMEM;					\
+	kfree(codec->type);					\
+	codec->type = s;					\
+	return count;						\
+}
+
+CODEC_INFO_STORE(vendor_id);
+CODEC_INFO_STORE(subsystem_id);
+CODEC_INFO_STORE(revision_id);
+CODEC_INFO_STR_STORE(name);
+CODEC_INFO_STR_STORE(modelname);
+
+#define CODEC_ACTION_STORE(type)				\
+static ssize_t type##_store(struct device *dev,			\
+			    struct device_attribute *attr,	\
+			    const char *buf, size_t count)	\
+{								\
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);		\
+	struct hda_codec *codec = hwdep->private_data;		\
+	int err = 0;						\
+	if (*buf)						\
+		err = type##_codec(codec);			\
+	return err < 0 ? err : count;				\
+}
+
+CODEC_ACTION_STORE(reconfig);
+CODEC_ACTION_STORE(clear);
+
+static ssize_t init_verbs_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+	struct hda_codec *codec = hwdep->private_data;
+	char *p;
+	struct hda_verb verb, *v;
+
+	verb.nid = simple_strtoul(buf, &p, 0);
+	verb.verb = simple_strtoul(p, &p, 0);
+	verb.param = simple_strtoul(p, &p, 0);
+	if (!verb.nid || !verb.verb || !verb.param)
+		return -EINVAL;
+	v = snd_array_new(&codec->init_verbs);
+	if (!v)
+		return -ENOMEM;
+	*v = verb;
+	return count;
+}
+
+static ssize_t hints_store(struct device *dev,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+	struct hda_codec *codec = hwdep->private_data;
+	char *p;
+	char **hint;
+
+	if (!*buf || isspace(*buf) || *buf == '#' || *buf == '\n')
+		return count;
+	p = kstrndup_noeol(buf, 1024);
+	if (!p)
+		return -ENOMEM;
+	hint = snd_array_new(&codec->hints);
+	if (!hint) {
+		kfree(p);
+		return -ENOMEM;
+	}
+	*hint = p;
+	return count;
+}
+
+#define CODEC_ATTR_RW(type) \
+	__ATTR(type, 0644, type##_show, type##_store)
+#define CODEC_ATTR_RO(type) \
+	__ATTR_RO(type)
+#define CODEC_ATTR_WO(type) \
+	__ATTR(type, 0200, NULL, type##_store)
+
+static struct device_attribute codec_attrs[] = {
+	CODEC_ATTR_RW(vendor_id),
+	CODEC_ATTR_RW(subsystem_id),
+	CODEC_ATTR_RW(revision_id),
+	CODEC_ATTR_RO(afg),
+	CODEC_ATTR_RO(mfg),
+	CODEC_ATTR_RW(name),
+	CODEC_ATTR_RW(modelname),
+	CODEC_ATTR_WO(init_verbs),
+	CODEC_ATTR_WO(hints),
+	CODEC_ATTR_WO(reconfig),
+	CODEC_ATTR_WO(clear),
+};
+
+/*
+ * create sysfs files on hwdep directory
+ */
+int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
+{
+	struct snd_hwdep *hwdep = codec->hwdep;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(codec_attrs); i++)
+		snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
+					  hwdep->device, &codec_attrs[i]);
+	return 0;
+}
+
+#endif /* CONFIG_SND_HDA_RECONFIG */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 35722ec..f04de11 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -58,6 +58,7 @@
 static int position_fix[SNDRV_CARDS];
 static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
+static int probe_only[SNDRV_CARDS];
 static int single_cmd;
 static int enable_msi;
 
@@ -76,6 +77,8 @@
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
+module_param_array(probe_only, bool, NULL, 0444);
+MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization.");
 module_param(single_cmd, bool, 0444);
 MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
 		 "(for debugging only).");
@@ -83,7 +86,10 @@
 MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-/* power_save option is defined in hda_codec.c */
+static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
+module_param(power_save, int, 0644);
+MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
+		 "(in second, 0 = disable).");
 
 /* reset the HD-audio controller in power save mode.
  * this may give more power-saving, but will take longer time to
@@ -292,6 +298,8 @@
 /* Define VIA HD Audio Device ID*/
 #define VIA_HDAC_DEVICE_ID		0x3288
 
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO	0x0403
 
 /*
  */
@@ -392,6 +400,7 @@
 	unsigned int msi :1;
 	unsigned int irq_pending_warned :1;
 	unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
+	unsigned int probing :1; /* codec probing phase */
 
 	/* for debugging */
 	unsigned int last_cmd;	/* last issued command (to sync) */
@@ -414,6 +423,7 @@
 	AZX_DRIVER_ULI,
 	AZX_DRIVER_NVIDIA,
 	AZX_DRIVER_TERA,
+	AZX_DRIVER_GENERIC,
 	AZX_NUM_DRIVERS, /* keep this as last entry */
 };
 
@@ -427,6 +437,7 @@
 	[AZX_DRIVER_ULI] = "HDA ULI M5461",
 	[AZX_DRIVER_NVIDIA] = "HDA NVidia",
 	[AZX_DRIVER_TERA] = "HDA Teradici", 
+	[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
 /*
@@ -527,9 +538,9 @@
 }
 
 /* send a command */
-static int azx_corb_send_cmd(struct hda_codec *codec, u32 val)
+static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	unsigned int wp;
 
 	/* add command to corb */
@@ -577,9 +588,9 @@
 }
 
 /* receive a response */
-static unsigned int azx_rirb_get_response(struct hda_codec *codec)
+static unsigned int azx_rirb_get_response(struct hda_bus *bus)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	unsigned long timeout;
 
  again:
@@ -596,7 +607,7 @@
 		}
 		if (time_after(jiffies, timeout))
 			break;
-		if (codec->bus->needs_damn_long_delay)
+		if (bus->needs_damn_long_delay)
 			msleep(2); /* temporary workaround */
 		else {
 			udelay(10);
@@ -624,6 +635,14 @@
 		goto again;
 	}
 
+	if (chip->probing) {
+		/* If this critical timeout happens during the codec probing
+		 * phase, this is likely an access to a non-existing codec
+		 * slot.  Better to return an error and reset the system.
+		 */
+		return -1;
+	}
+
 	snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
 		   "switching to single_cmd mode: last cmd=0x%08x\n",
 		   chip->last_cmd);
@@ -646,9 +665,9 @@
  */
 
 /* send a command */
-static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
+static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	int timeout = 50;
 
 	while (timeout--) {
@@ -671,9 +690,9 @@
 }
 
 /* receive a response */
-static unsigned int azx_single_get_response(struct hda_codec *codec)
+static unsigned int azx_single_get_response(struct hda_bus *bus)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	int timeout = 50;
 
 	while (timeout--) {
@@ -696,38 +715,29 @@
  */
 
 /* send a command */
-static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid,
-			int direct, unsigned int verb,
-			unsigned int para)
+static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
 {
-	struct azx *chip = codec->bus->private_data;
-	u32 val;
+	struct azx *chip = bus->private_data;
 
-	val = (u32)(codec->addr & 0x0f) << 28;
-	val |= (u32)direct << 27;
-	val |= (u32)nid << 20;
-	val |= verb << 8;
-	val |= para;
 	chip->last_cmd = val;
-
 	if (chip->single_cmd)
-		return azx_single_send_cmd(codec, val);
+		return azx_single_send_cmd(bus, val);
 	else
-		return azx_corb_send_cmd(codec, val);
+		return azx_corb_send_cmd(bus, val);
 }
 
 /* get a response */
-static unsigned int azx_get_response(struct hda_codec *codec)
+static unsigned int azx_get_response(struct hda_bus *bus)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	if (chip->single_cmd)
-		return azx_single_get_response(codec);
+		return azx_single_get_response(bus);
 	else
-		return azx_rirb_get_response(codec);
+		return azx_rirb_get_response(bus);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static void azx_power_notify(struct hda_codec *codec);
+static void azx_power_notify(struct hda_bus *bus);
 #endif
 
 /* reset codec link */
@@ -1184,6 +1194,28 @@
 	return 0;
 }
 
+/*
+ * Probe the given codec address
+ */
+static int probe_codec(struct azx *chip, int addr)
+{
+	unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
+		(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
+	unsigned int res;
+
+	chip->probing = 1;
+	azx_send_cmd(chip->bus, cmd);
+	res = azx_get_response(chip->bus);
+	chip->probing = 0;
+	if (res == -1)
+		return -EIO;
+	snd_printdd("hda_intel: codec #%d probed OK\n", addr);
+	return 0;
+}
+
+static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
+				 struct hda_pcm *cpcm);
+static void azx_stop_chip(struct azx *chip);
 
 /*
  * Codec initialization
@@ -1194,21 +1226,13 @@
 	[AZX_DRIVER_TERA] = 1,
 };
 
-/* number of slots to probe as default
- * this can be different from azx_max_codecs[] -- e.g. some boards
- * report wrongly the non-existing 4th slot availability
- */
-static unsigned int azx_default_codecs[AZX_NUM_DRIVERS] __devinitdata = {
-	[AZX_DRIVER_ICH] = 3,
-	[AZX_DRIVER_ATI] = 3,
-};
-
 static int __devinit azx_codec_create(struct azx *chip, const char *model,
-				      unsigned int codec_probe_mask)
+				      unsigned int codec_probe_mask,
+				      int no_init)
 {
 	struct hda_bus_template bus_temp;
-	int c, codecs, audio_codecs, err;
-	int def_slots, max_slots;
+	int c, codecs, err;
+	int max_slots;
 
 	memset(&bus_temp, 0, sizeof(bus_temp));
 	bus_temp.private_data = chip;
@@ -1216,7 +1240,9 @@
 	bus_temp.pci = chip->pci;
 	bus_temp.ops.command = azx_send_cmd;
 	bus_temp.ops.get_response = azx_get_response;
+	bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
+	bus_temp.power_save = &power_save;
 	bus_temp.ops.pm_notify = azx_power_notify;
 #endif
 
@@ -1227,33 +1253,43 @@
 	if (chip->driver_type == AZX_DRIVER_NVIDIA)
 		chip->bus->needs_damn_long_delay = 1;
 
-	codecs = audio_codecs = 0;
+	codecs = 0;
 	max_slots = azx_max_codecs[chip->driver_type];
 	if (!max_slots)
 		max_slots = AZX_MAX_CODECS;
-	def_slots = azx_default_codecs[chip->driver_type];
-	if (!def_slots)
-		def_slots = max_slots;
-	for (c = 0; c < def_slots; c++) {
+
+	/* First try to probe all given codec slots */
+	for (c = 0; c < max_slots; c++) {
+		if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
+			if (probe_codec(chip, c) < 0) {
+				/* Some BIOSen give you wrong codec addresses
+				 * that don't exist
+				 */
+				snd_printk(KERN_WARNING
+					   "hda_intel: Codec #%d probe error; "
+					   "disabling it...\n", c);
+				chip->codec_mask &= ~(1 << c);
+				/* More badly, accessing to a non-existing
+				 * codec often screws up the controller chip,
+				 * and distrubs the further communications.
+				 * Thus if an error occurs during probing,
+				 * better to reset the controller chip to
+				 * get back to the sanity state.
+				 */
+				azx_stop_chip(chip);
+				azx_init_chip(chip);
+			}
+		}
+	}
+
+	/* Then create codec instances */
+	for (c = 0; c < max_slots; c++) {
 		if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
 			struct hda_codec *codec;
-			err = snd_hda_codec_new(chip->bus, c, &codec);
+			err = snd_hda_codec_new(chip->bus, c, !no_init, &codec);
 			if (err < 0)
 				continue;
 			codecs++;
-			if (codec->afg)
-				audio_codecs++;
-		}
-	}
-	if (!audio_codecs) {
-		/* probe additional slots if no codec is found */
-		for (; c < max_slots; c++) {
-			if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
-				err = snd_hda_codec_new(chip->bus, c, NULL);
-				if (err < 0)
-					continue;
-				codecs++;
-			}
 		}
 	}
 	if (!codecs) {
@@ -1722,111 +1758,59 @@
 
 static void azx_pcm_free(struct snd_pcm *pcm)
 {
-	kfree(pcm->private_data);
+	struct azx_pcm *apcm = pcm->private_data;
+	if (apcm) {
+		apcm->chip->pcm[pcm->device] = NULL;
+		kfree(apcm);
+	}
 }
 
-static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
-				      struct hda_pcm *cpcm)
+static int
+azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
+		      struct hda_pcm *cpcm)
 {
-	int err;
+	struct azx *chip = bus->private_data;
 	struct snd_pcm *pcm;
 	struct azx_pcm *apcm;
+	int pcm_dev = cpcm->device;
+	int s, err;
 
-	/* if no substreams are defined for both playback and capture,
-	 * it's just a placeholder.  ignore it.
-	 */
-	if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
-		return 0;
-
-	if (snd_BUG_ON(!cpcm->name))
+	if (pcm_dev >= AZX_MAX_PCMS) {
+		snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
+			   pcm_dev);
 		return -EINVAL;
-
-	err = snd_pcm_new(chip->card, cpcm->name, cpcm->device,
-			  cpcm->stream[0].substreams,
-			  cpcm->stream[1].substreams,
+	}
+	if (chip->pcm[pcm_dev]) {
+		snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
+		return -EBUSY;
+	}
+	err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
+			  cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
+			  cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
 			  &pcm);
 	if (err < 0)
 		return err;
 	strcpy(pcm->name, cpcm->name);
-	apcm = kmalloc(sizeof(*apcm), GFP_KERNEL);
+	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
 	if (apcm == NULL)
 		return -ENOMEM;
 	apcm->chip = chip;
 	apcm->codec = codec;
-	apcm->hinfo[0] = &cpcm->stream[0];
-	apcm->hinfo[1] = &cpcm->stream[1];
 	pcm->private_data = apcm;
 	pcm->private_free = azx_pcm_free;
-	if (cpcm->stream[0].substreams)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
-	if (cpcm->stream[1].substreams)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
+	if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
+		pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
+	chip->pcm[pcm_dev] = pcm;
+	cpcm->pcm = pcm;
+	for (s = 0; s < 2; s++) {
+		apcm->hinfo[s] = &cpcm->stream[s];
+		if (cpcm->stream[s].substreams)
+			snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
+	}
+	/* buffer pre-allocation */
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
 					      snd_dma_pci_data(chip->pci),
 					      1024 * 64, 32 * 1024 * 1024);
-	chip->pcm[cpcm->device] = pcm;
-	return 0;
-}
-
-static int __devinit azx_pcm_create(struct azx *chip)
-{
-	static const char *dev_name[HDA_PCM_NTYPES] = {
-		"Audio", "SPDIF", "HDMI", "Modem"
-	};
-	/* starting device index for each PCM type */
-	static int dev_idx[HDA_PCM_NTYPES] = {
-		[HDA_PCM_TYPE_AUDIO] = 0,
-		[HDA_PCM_TYPE_SPDIF] = 1,
-		[HDA_PCM_TYPE_HDMI] = 3,
-		[HDA_PCM_TYPE_MODEM] = 6
-	};
-	/* normal audio device indices; not linear to keep compatibility */
-	static int audio_idx[4] = { 0, 2, 4, 5 };
-	struct hda_codec *codec;
-	int c, err;
-	int num_devs[HDA_PCM_NTYPES];
-
-	err = snd_hda_build_pcms(chip->bus);
-	if (err < 0)
-		return err;
-
-	/* create audio PCMs */
-	memset(num_devs, 0, sizeof(num_devs));
-	list_for_each_entry(codec, &chip->bus->codec_list, list) {
-		for (c = 0; c < codec->num_pcms; c++) {
-			struct hda_pcm *cpcm = &codec->pcm_info[c];
-			int type = cpcm->pcm_type;
-			switch (type) {
-			case HDA_PCM_TYPE_AUDIO:
-				if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
-					snd_printk(KERN_WARNING
-						   "Too many audio devices\n");
-					continue;
-				}
-				cpcm->device = audio_idx[num_devs[type]];
-				break;
-			case HDA_PCM_TYPE_SPDIF:
-			case HDA_PCM_TYPE_HDMI:
-			case HDA_PCM_TYPE_MODEM:
-				if (num_devs[type]) {
-					snd_printk(KERN_WARNING
-						   "%s already defined\n",
-						   dev_name[type]);
-					continue;
-				}
-				cpcm->device = dev_idx[type];
-				break;
-			default:
-				snd_printk(KERN_WARNING
-					   "Invalid PCM type %d\n", type);
-				continue;
-			}
-			num_devs[type]++;
-			err = create_codec_pcm(chip, codec, cpcm);
-			if (err < 0)
-				return err;
-		}
-	}
 	return 0;
 }
 
@@ -1903,13 +1887,13 @@
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 /* power-up/down the controller */
-static void azx_power_notify(struct hda_codec *codec)
+static void azx_power_notify(struct hda_bus *bus)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	struct hda_codec *c;
 	int power_on = 0;
 
-	list_for_each_entry(c, &codec->bus->codec_list, list) {
+	list_for_each_entry(c, &bus->codec_list, list) {
 		if (c->power_on) {
 			power_on = 1;
 			break;
@@ -1926,6 +1910,18 @@
 /*
  * power management
  */
+
+static int snd_hda_codecs_inuse(struct hda_bus *bus)
+{
+	struct hda_codec *codec;
+
+	list_for_each_entry(codec, &bus->codec_list, list) {
+		if (snd_hda_codec_needs_resume(codec))
+			return 1;
+	}
+	return 0;
+}
+
 static int azx_suspend(struct pci_dev *pci, pm_message_t state)
 {
 	struct snd_card *card = pci_get_drvdata(pci);
@@ -1951,13 +1947,16 @@
 	return 0;
 }
 
+static int azx_resume_early(struct pci_dev *pci)
+{
+	return pci_restore_state(pci);
+}
+
 static int azx_resume(struct pci_dev *pci)
 {
 	struct snd_card *card = pci_get_drvdata(pci);
 	struct azx *chip = card->private_data;
 
-	pci_set_power_state(pci, PCI_D0);
-	pci_restore_state(pci);
 	if (pci_enable_device(pci) < 0) {
 		printk(KERN_ERR "hda-intel: pci_enable_device failed, "
 		       "disabling device\n");
@@ -2095,6 +2094,10 @@
 	SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01),
 	SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01),
 	SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01),
+	/* broken BIOS */
+	SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01),
+	/* including bogus ALC268 in slot#2 that conflicts with ALC888 */
+	SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01),
 	{}
 };
 
@@ -2229,6 +2232,7 @@
 			chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
 			chip->capture_streams = ATIHDMI_NUM_CAPTURE;
 			break;
+		case AZX_DRIVER_GENERIC:
 		default:
 			chip->playback_streams = ICH6_NUM_PLAYBACK;
 			chip->capture_streams = ICH6_NUM_CAPTURE;
@@ -2338,40 +2342,31 @@
 	}
 
 	err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	if (err < 0)
+		goto out_free;
 	card->private_data = chip;
 
 	/* create codec instances */
-	err = azx_codec_create(chip, model[dev], probe_mask[dev]);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	err = azx_codec_create(chip, model[dev], probe_mask[dev],
+			       probe_only[dev]);
+	if (err < 0)
+		goto out_free;
 
 	/* create PCM streams */
-	err = azx_pcm_create(chip);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	err = snd_hda_build_pcms(chip->bus);
+	if (err < 0)
+		goto out_free;
 
 	/* create mixer controls */
 	err = azx_mixer_create(chip);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	if (err < 0)
+		goto out_free;
 
 	snd_card_set_dev(card, &pci->dev);
 
 	err = snd_card_register(card);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	if (err < 0)
+		goto out_free;
 
 	pci_set_drvdata(pci, card);
 	chip->running = 1;
@@ -2380,6 +2375,9 @@
 
 	dev++;
 	return err;
+out_free:
+	snd_card_free(card);
+	return err;
 }
 
 static void __devexit azx_remove(struct pci_dev *pci)
@@ -2453,6 +2451,11 @@
 	{ PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA },
 	/* Teradici */
 	{ PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
+	/* 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,
+	  .class_mask = 0xffffff,
+	  .driver_data = AZX_DRIVER_GENERIC },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
@@ -2465,6 +2468,7 @@
 	.remove = __devexit_p(azx_remove),
 #ifdef CONFIG_PM
 	.suspend = azx_suspend,
+	.resume_early = azx_resume_early,
 	.resume = azx_resume,
 #endif
 };
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 7957fef..6f2fe0f 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -96,6 +96,8 @@
 					    const char *name);
 int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
 			unsigned int *tlv, const char **slaves);
+void snd_hda_codec_reset(struct hda_codec *codec);
+int snd_hda_codec_configure(struct hda_codec *codec);
 
 /* amp value bits */
 #define HDA_AMP_MUTE	0x80
@@ -282,6 +284,12 @@
 static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
 #endif
 
+#define SND_PRINT_RATES_ADVISED_BUFSIZE	80
+void snd_print_pcm_rates(int pcm, char *buf, int buflen);
+
+#define SND_PRINT_BITS_ADVISED_BUFSIZE	16
+void snd_print_pcm_bits(int pcm, char *buf, int buflen);
+
 /*
  * Misc
  */
@@ -364,17 +372,17 @@
 /* amp values */
 #define AMP_IN_MUTE(idx)	(0x7080 | ((idx)<<8))
 #define AMP_IN_UNMUTE(idx)	(0x7000 | ((idx)<<8))
-#define AMP_OUT_MUTE	0xb080
-#define AMP_OUT_UNMUTE	0xb000
-#define AMP_OUT_ZERO	0xb000
+#define AMP_OUT_MUTE		0xb080
+#define AMP_OUT_UNMUTE		0xb000
+#define AMP_OUT_ZERO		0xb000
 /* pinctl values */
 #define PIN_IN			(AC_PINCTL_IN_EN)
-#define PIN_VREFHIZ	(AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ)
+#define PIN_VREFHIZ		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ)
 #define PIN_VREF50		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_50)
-#define PIN_VREFGRD	(AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD)
+#define PIN_VREFGRD		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD)
 #define PIN_VREF80		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_80)
-#define PIN_VREF100	(AC_PINCTL_IN_EN | AC_PINCTL_VREF_100)
-#define PIN_OUT		(AC_PINCTL_OUT_EN)
+#define PIN_VREF100		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_100)
+#define PIN_OUT			(AC_PINCTL_OUT_EN)
 #define PIN_HP			(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
 #define PIN_HP_AMP		(AC_PINCTL_HP_EN)
 
@@ -393,10 +401,26 @@
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 			      unsigned int caps);
 
+int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl);
+void snd_hda_ctls_clear(struct hda_codec *codec);
+
 /*
  * hwdep interface
  */
+#ifdef CONFIG_SND_HDA_HWDEP
 int snd_hda_create_hwdep(struct hda_codec *codec);
+#else
+static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
+#endif
+
+#ifdef CONFIG_SND_HDA_RECONFIG
+int snd_hda_hwdep_add_sysfs(struct hda_codec *codec);
+#else
+static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
+{
+	return 0;
+}
+#endif
 
 /*
  * power-management
@@ -430,4 +454,66 @@
 #define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1)
 #define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf)
 
+/*
+ * CEA Short Audio Descriptor data
+ */
+struct cea_sad {
+	int	channels;
+	int	format;		/* (format == 0) indicates invalid SAD */
+	int	rates;
+	int	sample_bits;	/* for LPCM */
+	int	max_bitrate;	/* for AC3...ATRAC */
+	int	profile;	/* for WMAPRO */
+};
+
+#define ELD_FIXED_BYTES	20
+#define ELD_MAX_MNL	16
+#define ELD_MAX_SAD	16
+
+/*
+ * ELD: EDID Like Data
+ */
+struct hdmi_eld {
+	int	eld_size;
+	int	baseline_len;
+	int	eld_ver;	/* (eld_ver == 0) indicates invalid ELD */
+	int	cea_edid_ver;
+	char	monitor_name[ELD_MAX_MNL + 1];
+	int	manufacture_id;
+	int	product_id;
+	u64	port_id;
+	int	support_hdcp;
+	int	support_ai;
+	int	conn_type;
+	int	aud_synch_delay;
+	int	spk_alloc;
+	int	sad_count;
+	struct cea_sad sad[ELD_MAX_SAD];
+#ifdef CONFIG_PROC_FS
+	struct snd_info_entry *proc_entry;
+#endif
+};
+
+int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
+int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t);
+void snd_hdmi_show_eld(struct hdmi_eld *eld);
+
+#ifdef CONFIG_PROC_FS
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld);
+void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld);
+#else
+static inline int snd_hda_eld_proc_new(struct hda_codec *codec,
+				       struct hdmi_eld *eld)
+{
+	return 0;
+}
+static inline void snd_hda_eld_proc_free(struct hda_codec *codec,
+					 struct hdmi_eld *eld)
+{
+}
+#endif
+
+#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
+void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
+
 #endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
deleted file mode 100644
index dfbcfa8..0000000
--- a/sound/pci/hda/hda_patch.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * HDA Patches - included by hda_codec.c
- */
-
-/* Realtek codecs */
-extern struct hda_codec_preset snd_hda_preset_realtek[];
-/* C-Media codecs */
-extern struct hda_codec_preset snd_hda_preset_cmedia[];
-/* Analog Devices codecs */
-extern struct hda_codec_preset snd_hda_preset_analog[];
-/* SigmaTel codecs */
-extern struct hda_codec_preset snd_hda_preset_sigmatel[];
-/* SiLabs 3054/3055 modem codecs */
-extern struct hda_codec_preset snd_hda_preset_si3054[];
-/* ATI HDMI codecs */
-extern struct hda_codec_preset snd_hda_preset_atihdmi[];
-/* Conexant audio codec */
-extern struct hda_codec_preset snd_hda_preset_conexant[];
-/* VIA codecs */
-extern struct hda_codec_preset snd_hda_preset_via[];
-/* NVIDIA HDMI codecs */
-extern struct hda_codec_preset snd_hda_preset_nvhdmi[];
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index c39af98..7ca66d6 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -91,31 +91,21 @@
 
 static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm)
 {
-	static unsigned int rates[] = {
-		8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
-		96000, 176400, 192000, 384000
-	};
-	int i;
+	char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
 
 	pcm &= AC_SUPPCM_RATES;
 	snd_iprintf(buffer, "    rates [0x%x]:", pcm);
-	for (i = 0; i < ARRAY_SIZE(rates); i++) 
-		if (pcm & (1 << i))
-			snd_iprintf(buffer, " %d", rates[i]);
-	snd_iprintf(buffer, "\n");
+	snd_print_pcm_rates(pcm, buf, sizeof(buf));
+	snd_iprintf(buffer, "%s\n", buf);
 }
 
 static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm)
 {
-	static unsigned int bits[] = { 8, 16, 20, 24, 32 };
-	int i;
+	char buf[SND_PRINT_BITS_ADVISED_BUFSIZE];
 
-	pcm = (pcm >> 16) & 0xff;
-	snd_iprintf(buffer, "    bits [0x%x]:", pcm);
-	for (i = 0; i < ARRAY_SIZE(bits); i++)
-		if (pcm & (1 << i))
-			snd_iprintf(buffer, " %d", bits[i]);
-	snd_iprintf(buffer, "\n");
+	snd_iprintf(buffer, "    bits [0x%x]:", (pcm >> 16) & 0xff);
+	snd_print_pcm_bits(pcm, buf, sizeof(buf));
+	snd_iprintf(buffer, "%s\n", buf);
 }
 
 static void print_pcm_formats(struct snd_info_buffer *buffer,
@@ -145,32 +135,6 @@
 	print_pcm_formats(buffer, stream);
 }
 
-static const char *get_jack_location(u32 cfg)
-{
-	static char *bases[7] = {
-		"N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
-	};
-	static unsigned char specials_idx[] = {
-		0x07, 0x08,
-		0x17, 0x18, 0x19,
-		0x37, 0x38
-	};
-	static char *specials[] = {
-		"Rear Panel", "Drive Bar",
-		"Riser", "HDMI", "ATAPI",
-		"Mobile-In", "Mobile-Out"
-	};
-	int i;
-	cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
-	if ((cfg & 0x0f) < 7)
-		return bases[cfg & 0x0f];
-	for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
-		if (cfg == specials_idx[i])
-			return specials[i];
-	}
-	return "UNKNOWN";
-}
-
 static const char *get_jack_connection(u32 cfg)
 {
 	static char *names[16] = {
@@ -206,13 +170,6 @@
 			   int *supports_vref)
 {
 	static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
-	static char *jack_types[16] = {
-		"Line Out", "Speaker", "HP Out", "CD",
-		"SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
-		"Line In", "Aux", "Mic", "Telephony",
-		"SPDIF In", "Digitial In", "Reserved", "Other"
-	};
-	static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
 	unsigned int caps, val;
 
 	caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
@@ -274,9 +231,9 @@
 	caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
 	snd_iprintf(buffer, "  Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
 		    jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
-		    jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT],
-		    jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3],
-		    get_jack_location(caps));
+		    snd_hda_get_jack_type(caps),
+		    snd_hda_get_jack_connectivity(caps),
+		    snd_hda_get_jack_location(caps));
 	snd_iprintf(buffer, "    Conn = %s, Color = %s\n",
 		    get_jack_connection(caps),
 		    get_jack_color(caps));
@@ -457,17 +414,6 @@
 	}
 }
 
-static void print_realtek_coef(struct snd_info_buffer *buffer,
-			       struct hda_codec *codec, hda_nid_t nid)
-{
-	int coeff = snd_hda_codec_read(codec, nid, 0,
-				       AC_VERB_GET_PROC_COEF, 0);
-	snd_iprintf(buffer, "  Processing Coefficient: 0x%02x\n", coeff);
-	coeff = snd_hda_codec_read(codec, nid, 0,
-				   AC_VERB_GET_COEF_INDEX, 0);
-	snd_iprintf(buffer, "  Coefficient Index: 0x%02x\n", coeff);
-}
-
 static void print_gpio(struct snd_info_buffer *buffer,
 		       struct hda_codec *codec, hda_nid_t nid)
 {
@@ -500,12 +446,13 @@
 	for (i = 0; i < max; ++i)
 		snd_iprintf(buffer,
 			    "  IO[%d]: enable=%d, dir=%d, wake=%d, "
-			    "sticky=%d, data=%d\n", i,
+			    "sticky=%d, data=%d, unsol=%d\n", i,
 			    (enable & (1<<i)) ? 1 : 0,
 			    (direction & (1<<i)) ? 1 : 0,
 			    (wake & (1<<i)) ? 1 : 0,
 			    (sticky & (1<<i)) ? 1 : 0,
-			    (data & (1<<i)) ? 1 : 0);
+			    (data & (1<<i)) ? 1 : 0,
+			    (unsol & (1<<i)) ? 1 : 0);
 	/* FIXME: add GPO and GPI pin information */
 }
 
@@ -513,12 +460,11 @@
 			     struct snd_info_buffer *buffer)
 {
 	struct hda_codec *codec = entry->private_data;
-	char buf[32];
 	hda_nid_t nid;
 	int i, nodes;
 
-	snd_hda_get_codec_name(codec, buf, sizeof(buf));
-	snd_iprintf(buffer, "Codec: %s\n", buf);
+	snd_iprintf(buffer, "Codec: %s\n",
+		    codec->name ? codec->name : "Not Set");
 	snd_iprintf(buffer, "Address: %d\n", codec->addr);
 	snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
 	snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
@@ -547,6 +493,8 @@
 	}
 
 	print_gpio(buffer, codec, codec->afg);
+	if (codec->proc_widget_hook)
+		codec->proc_widget_hook(buffer, codec, codec->afg);
 
 	for (i = 0; i < nodes; i++, nid++) {
 		unsigned int wid_caps =
@@ -649,9 +597,8 @@
 		if (wid_caps & AC_WCAP_PROC_WID)
 			print_proc_caps(buffer, codec, nid);
 
-		/* NID 0x20 == Realtek Define Registers */
-		if (codec->vendor_id == 0x10ec && nid == 0x20)
-			print_realtek_coef(buffer, codec, nid);
+		if (codec->proc_widget_hook)
+			codec->proc_widget_hook(buffer, codec, nid);
 	}
 	snd_hda_power_down(codec);
 }
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 686c774..26247cf 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -27,7 +27,6 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 
 struct ad198x_spec {
 	struct snd_kcontrol_new *mixers[5];
@@ -67,8 +66,7 @@
 
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
-	unsigned int num_kctl_alloc, num_kctl_used;
-	struct snd_kcontrol_new *kctl_alloc;
+	struct snd_array kctls;
 	struct hda_input_mux private_imux;
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
@@ -154,6 +152,8 @@
 	NULL
 };
 
+static void ad198x_free_kctls(struct hda_codec *codec);
+
 static int ad198x_build_controls(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec = codec->spec;
@@ -202,6 +202,7 @@
 			return err;
 	}
 
+	ad198x_free_kctls(codec); /* no longer needed */
 	return 0;
 }
 
@@ -375,16 +376,27 @@
 	return 0;
 }
 
+static void ad198x_free_kctls(struct hda_codec *codec)
+{
+	struct ad198x_spec *spec = codec->spec;
+
+	if (spec->kctls.list) {
+		struct snd_kcontrol_new *kctl = spec->kctls.list;
+		int i;
+		for (i = 0; i < spec->kctls.used; i++)
+			kfree(kctl[i].name);
+	}
+	snd_array_free(&spec->kctls);
+}
+
 static void ad198x_free(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec = codec->spec;
-	unsigned int i;
 
-	if (spec->kctl_alloc) {
-		for (i = 0; i < spec->num_kctl_used; i++)
-			kfree(spec->kctl_alloc[i].name);
-		kfree(spec->kctl_alloc);
-	}
+	if (!spec)
+		return;
+
+	ad198x_free_kctls(codec);
 	kfree(codec->spec);
 }
 
@@ -629,6 +641,36 @@
 	HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "External Amplifier",
+		.info = ad198x_eapd_info,
+		.get = ad198x_eapd_get,
+		.put = ad198x_eapd_put,
+		.private_value = 0x1b | (1 << 8), /* port-D, inversed */
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new ad1986a_samsung_mixers[] = {
+	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
+	HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
@@ -917,6 +959,7 @@
 	AD1986A_LAPTOP_EAPD,
 	AD1986A_LAPTOP_AUTOMUTE,
 	AD1986A_ULTRA,
+	AD1986A_SAMSUNG,
 	AD1986A_MODELS
 };
 
@@ -927,6 +970,7 @@
 	[AD1986A_LAPTOP_EAPD]	= "laptop-eapd",
 	[AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
 	[AD1986A_ULTRA]		= "ultra",
+	[AD1986A_SAMSUNG]	= "samsung",
 };
 
 static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
@@ -949,9 +993,9 @@
 	SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
-	SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG),
+	SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG),
+	SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG),
 	SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
 	SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
@@ -1033,6 +1077,17 @@
 		break;
 	case AD1986A_LAPTOP_EAPD:
 		spec->mixers[0] = ad1986a_laptop_eapd_mixers;
+		spec->num_init_verbs = 2;
+		spec->init_verbs[1] = ad1986a_eapd_init_verbs;
+		spec->multiout.max_channels = 2;
+		spec->multiout.num_dacs = 1;
+		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
+		if (!is_jack_available(codec, 0x25))
+			spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1986a_laptop_eapd_capture_source;
+		break;
+	case AD1986A_SAMSUNG:
+		spec->mixers[0] = ad1986a_samsung_mixers;
 		spec->num_init_verbs = 3;
 		spec->init_verbs[1] = ad1986a_eapd_init_verbs;
 		spec->init_verbs[2] = ad1986a_automic_verbs;
@@ -2452,9 +2507,6 @@
  * Automatic parse of I/O pins from the BIOS configuration
  */
 
-#define NUM_CONTROL_ALLOC	32
-#define NUM_VERB_ALLOC		32
-
 enum {
 	AD_CTL_WIDGET_VOL,
 	AD_CTL_WIDGET_MUTE,
@@ -2472,27 +2524,15 @@
 {
 	struct snd_kcontrol_new *knew;
 
-	if (spec->num_kctl_used >= spec->num_kctl_alloc) {
-		int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
-
-		knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
-		if (! knew)
-			return -ENOMEM;
-		if (spec->kctl_alloc) {
-			memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
-			kfree(spec->kctl_alloc);
-		}
-		spec->kctl_alloc = knew;
-		spec->num_kctl_alloc = num;
-	}
-
-	knew = &spec->kctl_alloc[spec->num_kctl_used];
+	snd_array_init(&spec->kctls, sizeof(*knew), 32);
+	knew = snd_array_new(&spec->kctls);
+	if (!knew)
+		return -ENOMEM;
 	*knew = ad1988_control_templates[type];
 	knew->name = kstrdup(name, GFP_KERNEL);
 	if (! knew->name)
 		return -ENOMEM;
 	knew->private_value = val;
-	spec->num_kctl_used++;
 	return 0;
 }
 
@@ -2846,8 +2886,8 @@
 	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = AD1988_SPDIF_IN;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
 
@@ -3861,6 +3901,7 @@
 static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
 	SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
+	SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP),
 	SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP),
 	SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP),
 	SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
@@ -4267,7 +4308,7 @@
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_analog[] = {
+static struct hda_codec_preset snd_hda_preset_analog[] = {
 	{ .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
 	{ .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
 	{ .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
@@ -4285,3 +4326,26 @@
 	{ .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:11d4*");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Analog Devices HD-audio codec");
+
+static struct hda_codec_preset_list analog_list = {
+	.preset = snd_hda_preset_analog,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_analog_init(void)
+{
+	return snd_hda_add_codec_preset(&analog_list);
+}
+
+static void __exit patch_analog_exit(void)
+{
+	snd_hda_delete_codec_preset(&analog_list);
+}
+
+module_init(patch_analog_init)
+module_exit(patch_analog_exit)
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
index ba61575..233e477 100644
--- a/sound/pci/hda/patch_atihdmi.c
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -27,7 +27,6 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 
 struct atihdmi_spec {
 	struct hda_multi_out multiout;
@@ -187,13 +186,40 @@
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_atihdmi[] = {
-	{ .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi },
+static struct hda_codec_preset snd_hda_preset_atihdmi[] = {
+	{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
+	{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
+	{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
+	{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
 	{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x17e80047, .name = "Chrontel HDMI",  .patch = patch_atihdmi },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:1002793c");
+MODULE_ALIAS("snd-hda-codec-id:10027919");
+MODULE_ALIAS("snd-hda-codec-id:1002791a");
+MODULE_ALIAS("snd-hda-codec-id:1002aa01");
+MODULE_ALIAS("snd-hda-codec-id:10951390");
+MODULE_ALIAS("snd-hda-codec-id:17e80047");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ATI HDMI HD-audio codec");
+
+static struct hda_codec_preset_list atihdmi_list = {
+	.preset = snd_hda_preset_atihdmi,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_atihdmi_init(void)
+{
+	return snd_hda_add_codec_preset(&atihdmi_list);
+}
+
+static void __exit patch_atihdmi_exit(void)
+{
+	snd_hda_delete_codec_preset(&atihdmi_list);
+}
+
+module_init(patch_atihdmi_init)
+module_exit(patch_atihdmi_exit)
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index 6ef57fb..f3ebe83 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -28,7 +28,6 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 #define NUM_PINS	11
 
 
@@ -736,8 +735,32 @@
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_cmedia[] = {
+static struct hda_codec_preset snd_hda_preset_cmedia[] = {
 	{ .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
  	{ .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:13f69880");
+MODULE_ALIAS("snd-hda-codec-id:434d4980");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("C-Media HD-audio codec");
+
+static struct hda_codec_preset_list cmedia_list = {
+	.preset = snd_hda_preset_cmedia,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_cmedia_init(void)
+{
+	return snd_hda_add_codec_preset(&cmedia_list);
+}
+
+static void __exit patch_cmedia_exit(void)
+{
+	snd_hda_delete_codec_preset(&cmedia_list);
+}
+
+module_init(patch_cmedia_init)
+module_exit(patch_cmedia_exit)
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 7c1eb23..b20e1ce 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -27,7 +27,6 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 
 #define CXT_PIN_DIR_IN              0x00
 #define CXT_PIN_DIR_OUT             0x01
@@ -86,8 +85,6 @@
 
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
-	unsigned int num_kctl_alloc, num_kctl_used;
-	struct snd_kcontrol_new *kctl_alloc;
 	struct hda_input_mux private_imux;
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
@@ -344,15 +341,6 @@
 
 static void conexant_free(struct hda_codec *codec)
 {
-        struct conexant_spec *spec = codec->spec;
-        unsigned int i;
-
-        if (spec->kctl_alloc) {
-                for (i = 0; i < spec->num_kctl_used; i++)
-                        kfree(spec->kctl_alloc[i].name);
-                kfree(spec->kctl_alloc);
-        }
-
 	kfree(codec->spec);
 }
 
@@ -1782,7 +1770,7 @@
 /*
  */
 
-struct hda_codec_preset snd_hda_preset_conexant[] = {
+static struct hda_codec_preset snd_hda_preset_conexant[] = {
 	{ .id = 0x14f15045, .name = "CX20549 (Venice)",
 	  .patch = patch_cxt5045 },
 	{ .id = 0x14f15047, .name = "CX20551 (Waikiki)",
@@ -1791,3 +1779,28 @@
 	  .patch = patch_cxt5051 },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:14f15045");
+MODULE_ALIAS("snd-hda-codec-id:14f15047");
+MODULE_ALIAS("snd-hda-codec-id:14f15051");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Conexant HD-audio codec");
+
+static struct hda_codec_preset_list conexant_list = {
+	.preset = snd_hda_preset_conexant,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_conexant_init(void)
+{
+	return snd_hda_add_codec_preset(&conexant_list);
+}
+
+static void __exit patch_conexant_exit(void)
+{
+	snd_hda_delete_codec_preset(&conexant_list);
+}
+
+module_init(patch_conexant_init)
+module_exit(patch_conexant_exit)
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c
new file mode 100644
index 0000000..3564f4e
--- /dev/null
+++ b/sound/pci/hda/patch_intelhdmi.c
@@ -0,0 +1,711 @@
+/*
+ *
+ *  patch_intelhdmi.c - Patch for Intel HDMI codecs
+ *
+ *  Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ *  Authors:
+ *  			Jiang Zhe <zhe.jiang@intel.com>
+ *  			Wu Fengguang <wfg@linux.intel.com>
+ *
+ *  Maintained by:
+ *  			Wu Fengguang <wfg@linux.intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You 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 <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+#define CVT_NID		0x02	/* audio converter */
+#define PIN_NID		0x03	/* HDMI output pin */
+
+#define INTEL_HDMI_EVENT_TAG		0x08
+
+struct intel_hdmi_spec {
+	struct hda_multi_out multiout;
+	struct hda_pcm pcm_rec;
+	struct hdmi_eld sink_eld;
+};
+
+static struct hda_verb pinout_enable_verb[] = {
+	{PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{} /* terminator */
+};
+
+static struct hda_verb pinout_disable_verb[] = {
+	{PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00},
+	{}
+};
+
+static struct hda_verb unsolicited_response_verb[] = {
+	{PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN |
+						  INTEL_HDMI_EVENT_TAG},
+	{}
+};
+
+static struct hda_verb def_chan_map[] = {
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77},
+	{}
+};
+
+
+struct hdmi_audio_infoframe {
+	u8 type; /* 0x84 */
+	u8 ver;  /* 0x01 */
+	u8 len;  /* 0x0a */
+
+	u8 checksum;	/* PB0 */
+	u8 CC02_CT47;	/* CC in bits 0:2, CT in 4:7 */
+	u8 SS01_SF24;
+	u8 CXT04;
+	u8 CA;
+	u8 LFEPBL01_LSV36_DM_INH7;
+	u8 reserved[5];	/* PB6 - PB10 */
+};
+
+/*
+ * CEA speaker placement:
+ *
+ *        FLH       FCH        FRH
+ *  FLW    FL  FLC   FC   FRC   FR   FRW
+ *
+ *                                  LFE
+ *                     TC
+ *
+ *          RL  RLC   RC   RRC   RR
+ *
+ * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to
+ * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC.
+ */
+enum cea_speaker_placement {
+	FL  = (1 <<  0),	/* Front Left           */
+	FC  = (1 <<  1),	/* Front Center         */
+	FR  = (1 <<  2),	/* Front Right          */
+	FLC = (1 <<  3),	/* Front Left Center    */
+	FRC = (1 <<  4),	/* Front Right Center   */
+	RL  = (1 <<  5),	/* Rear Left            */
+	RC  = (1 <<  6),	/* Rear Center          */
+	RR  = (1 <<  7),	/* Rear Right           */
+	RLC = (1 <<  8),	/* Rear Left Center     */
+	RRC = (1 <<  9),	/* Rear Right Center    */
+	LFE = (1 << 10),	/* Low Frequency Effect */
+	FLW = (1 << 11),	/* Front Left Wide      */
+	FRW = (1 << 12),	/* Front Right Wide     */
+	FLH = (1 << 13),	/* Front Left High      */
+	FCH = (1 << 14),	/* Front Center High    */
+	FRH = (1 << 15),	/* Front Right High     */
+	TC  = (1 << 16),	/* Top Center           */
+};
+
+/*
+ * ELD SA bits in the CEA Speaker Allocation data block
+ */
+static int eld_speaker_allocation_bits[] = {
+	[0] = FL | FR,
+	[1] = LFE,
+	[2] = FC,
+	[3] = RL | RR,
+	[4] = RC,
+	[5] = FLC | FRC,
+	[6] = RLC | RRC,
+	/* the following are not defined in ELD yet */
+	[7] = FLW | FRW,
+	[8] = FLH | FRH,
+	[9] = TC,
+	[10] = FCH,
+};
+
+struct cea_channel_speaker_allocation {
+	int ca_index;
+	int speakers[8];
+
+	/* derived values, just for convenience */
+	int channels;
+	int spk_mask;
+};
+
+/*
+ * This is an ordered list!
+ *
+ * The preceding ones have better chances to be selected by
+ * hdmi_setup_channel_allocation().
+ */
+static struct cea_channel_speaker_allocation channel_allocations[] = {
+/* 			  channel:   8     7    6    5    4     3    2    1  */
+{ .ca_index = 0x00,  .speakers = {   0,    0,   0,   0,   0,    0,  FR,  FL } },
+				 /* 2.1 */
+{ .ca_index = 0x01,  .speakers = {   0,    0,   0,   0,   0,  LFE,  FR,  FL } },
+				 /* Dolby Surround */
+{ .ca_index = 0x02,  .speakers = {   0,    0,   0,   0,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x03,  .speakers = {   0,    0,   0,   0,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x04,  .speakers = {   0,    0,   0,  RC,   0,    0,  FR,  FL } },
+{ .ca_index = 0x05,  .speakers = {   0,    0,   0,  RC,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x06,  .speakers = {   0,    0,   0,  RC,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x07,  .speakers = {   0,    0,   0,  RC,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x08,  .speakers = {   0,    0,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x09,  .speakers = {   0,    0,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x0a,  .speakers = {   0,    0,  RR,  RL,  FC,    0,  FR,  FL } },
+				 /* 5.1 */
+{ .ca_index = 0x0b,  .speakers = {   0,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x0c,  .speakers = {   0,   RC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x0d,  .speakers = {   0,   RC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x0e,  .speakers = {   0,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
+				 /* 6.1 */
+{ .ca_index = 0x0f,  .speakers = {   0,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x10,  .speakers = { RRC,  RLC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x11,  .speakers = { RRC,  RLC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x12,  .speakers = { RRC,  RLC,  RR,  RL,  FC,    0,  FR,  FL } },
+				 /* 7.1 */
+{ .ca_index = 0x13,  .speakers = { RRC,  RLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x14,  .speakers = { FRC,  FLC,   0,   0,   0,    0,  FR,  FL } },
+{ .ca_index = 0x15,  .speakers = { FRC,  FLC,   0,   0,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x16,  .speakers = { FRC,  FLC,   0,   0,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x17,  .speakers = { FRC,  FLC,   0,   0,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x18,  .speakers = { FRC,  FLC,   0,  RC,   0,    0,  FR,  FL } },
+{ .ca_index = 0x19,  .speakers = { FRC,  FLC,   0,  RC,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x1a,  .speakers = { FRC,  FLC,   0,  RC,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x1b,  .speakers = { FRC,  FLC,   0,  RC,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x1c,  .speakers = { FRC,  FLC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x1d,  .speakers = { FRC,  FLC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x1e,  .speakers = { FRC,  FLC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x1f,  .speakers = { FRC,  FLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x20,  .speakers = {   0,  FCH,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x21,  .speakers = {   0,  FCH,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x22,  .speakers = {  TC,    0,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x23,  .speakers = {  TC,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x24,  .speakers = { FRH,  FLH,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x25,  .speakers = { FRH,  FLH,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x26,  .speakers = { FRW,  FLW,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x27,  .speakers = { FRW,  FLW,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x28,  .speakers = {  TC,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x29,  .speakers = {  TC,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x2a,  .speakers = { FCH,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x2b,  .speakers = { FCH,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x2c,  .speakers = {  TC,  FCH,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x2d,  .speakers = {  TC,  FCH,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x2e,  .speakers = { FRH,  FLH,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x2f,  .speakers = { FRH,  FLH,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x30,  .speakers = { FRW,  FLW,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x31,  .speakers = { FRW,  FLW,  RR,  RL,  FC,  LFE,  FR,  FL } },
+};
+
+/*
+ * HDMI routines
+ */
+
+#ifdef BE_PARANOID
+static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid,
+				int *packet_index, int *byte_index)
+{
+	int val;
+
+	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0);
+
+	*packet_index = val >> 5;
+	*byte_index = val & 0x1f;
+}
+#endif
+
+static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid,
+				int packet_index, int byte_index)
+{
+	int val;
+
+	val = (packet_index << 5) | (byte_index & 0x1f);
+
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
+}
+
+static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid,
+				unsigned char val)
+{
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
+}
+
+static void hdmi_enable_output(struct hda_codec *codec)
+{
+	/* Enable Audio InfoFrame Transmission */
+	hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
+	snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT,
+						AC_DIPXMIT_BEST);
+	/* Unmute */
+	if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
+		snd_hda_codec_write(codec, PIN_NID, 0,
+				AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+	/* Enable pin out */
+	snd_hda_sequence_write(codec, pinout_enable_verb);
+}
+
+static void hdmi_disable_output(struct hda_codec *codec)
+{
+	snd_hda_sequence_write(codec, pinout_disable_verb);
+	if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
+		snd_hda_codec_write(codec, PIN_NID, 0,
+				AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+	/*
+	 * FIXME: noises may arise when playing music after reloading the
+	 * kernel module, until the next X restart or monitor repower.
+	 */
+}
+
+static int hdmi_get_channel_count(struct hda_codec *codec)
+{
+	return 1 + snd_hda_codec_read(codec, CVT_NID, 0,
+					AC_VERB_GET_CVT_CHAN_COUNT, 0);
+}
+
+static void hdmi_set_channel_count(struct hda_codec *codec, int chs)
+{
+	snd_hda_codec_write(codec, CVT_NID, 0,
+					AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
+
+	if (chs != hdmi_get_channel_count(codec))
+		snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n",
+					chs, hdmi_get_channel_count(codec));
+}
+
+static void hdmi_debug_channel_mapping(struct hda_codec *codec)
+{
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+	int i;
+	int slot;
+
+	for (i = 0; i < 8; i++) {
+		slot = snd_hda_codec_read(codec, CVT_NID, 0,
+						AC_VERB_GET_HDMI_CHAN_SLOT, i);
+		printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
+						slot >> 4, slot & 0x7);
+	}
+#endif
+}
+
+static void hdmi_parse_eld(struct hda_codec *codec)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+	struct hdmi_eld *eld = &spec->sink_eld;
+
+	if (!snd_hdmi_get_eld(eld, codec, PIN_NID))
+		snd_hdmi_show_eld(eld);
+}
+
+
+/*
+ * Audio InfoFrame routines
+ */
+
+static void hdmi_debug_dip_size(struct hda_codec *codec)
+{
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+	int i;
+	int size;
+
+	size = snd_hdmi_get_eld_size(codec, PIN_NID);
+	printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size);
+
+	for (i = 0; i < 8; i++) {
+		size = snd_hda_codec_read(codec, PIN_NID, 0,
+						AC_VERB_GET_HDMI_DIP_SIZE, i);
+		printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size);
+	}
+#endif
+}
+
+static void hdmi_clear_dip_buffers(struct hda_codec *codec)
+{
+#ifdef BE_PARANOID
+	int i, j;
+	int size;
+	int pi, bi;
+	for (i = 0; i < 8; i++) {
+		size = snd_hda_codec_read(codec, PIN_NID, 0,
+						AC_VERB_GET_HDMI_DIP_SIZE, i);
+		if (size == 0)
+			continue;
+
+		hdmi_set_dip_index(codec, PIN_NID, i, 0x0);
+		for (j = 1; j < 1000; j++) {
+			hdmi_write_dip_byte(codec, PIN_NID, 0x0);
+			hdmi_get_dip_index(codec, PIN_NID, &pi, &bi);
+			if (pi != i)
+				snd_printd(KERN_INFO "dip index %d: %d != %d\n",
+						bi, pi, i);
+			if (bi == 0) /* byte index wrapped around */
+				break;
+		}
+		snd_printd(KERN_INFO
+			"HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
+			i, size, j);
+	}
+#endif
+}
+
+static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
+					struct hdmi_audio_infoframe *ai)
+{
+	u8 *params = (u8 *)ai;
+	int i;
+
+	hdmi_debug_dip_size(codec);
+	hdmi_clear_dip_buffers(codec); /* be paranoid */
+
+	hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
+	for (i = 0; i < sizeof(ai); i++)
+		hdmi_write_dip_byte(codec, PIN_NID, params[i]);
+}
+
+/*
+ * Compute derived values in channel_allocations[].
+ */
+static void init_channel_allocations(void)
+{
+	int i, j;
+	struct cea_channel_speaker_allocation *p;
+
+	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+		p = channel_allocations + i;
+		p->channels = 0;
+		p->spk_mask = 0;
+		for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
+			if (p->speakers[j]) {
+				p->channels++;
+				p->spk_mask |= p->speakers[j];
+			}
+	}
+}
+
+/*
+ * The transformation takes two steps:
+ *
+ * 	eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
+ * 	      spk_mask => (channel_allocations[])         => ai->CA
+ *
+ * TODO: it could select the wrong CA from multiple candidates.
+*/
+static int hdmi_setup_channel_allocation(struct hda_codec *codec,
+					 struct hdmi_audio_infoframe *ai)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+	struct hdmi_eld *eld = &spec->sink_eld;
+	int i;
+	int spk_mask = 0;
+	int channels = 1 + (ai->CC02_CT47 & 0x7);
+	char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+
+	/*
+	 * CA defaults to 0 for basic stereo audio
+	 */
+	if (!eld->eld_ver)
+		return 0;
+	if (!eld->spk_alloc)
+		return 0;
+	if (channels <= 2)
+		return 0;
+
+	/*
+	 * expand ELD's speaker allocation mask
+	 *
+	 * ELD tells the speaker mask in a compact(paired) form,
+	 * expand ELD's notions to match the ones used by Audio InfoFrame.
+	 */
+	for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
+		if (eld->spk_alloc & (1 << i))
+			spk_mask |= eld_speaker_allocation_bits[i];
+	}
+
+	/* search for the first working match in the CA table */
+	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+		if (channels == channel_allocations[i].channels &&
+		    (spk_mask & channel_allocations[i].spk_mask) ==
+				channel_allocations[i].spk_mask) {
+			ai->CA = channel_allocations[i].ca_index;
+			break;
+		}
+	}
+
+	snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
+	snd_printdd(KERN_INFO
+			"HDMI: select CA 0x%x for %d-channel allocation: %s\n",
+			ai->CA, channels, buf);
+
+	return ai->CA;
+}
+
+static void hdmi_setup_channel_mapping(struct hda_codec *codec,
+					struct hdmi_audio_infoframe *ai)
+{
+	if (!ai->CA)
+		return;
+
+	/*
+	 * TODO: adjust channel mapping if necessary
+	 * ALSA sequence is front/surr/clfe/side?
+	 */
+
+	snd_hda_sequence_write(codec, def_chan_map);
+	hdmi_debug_channel_mapping(codec);
+}
+
+
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
+					struct snd_pcm_substream *substream)
+{
+	struct hdmi_audio_infoframe ai = {
+		.type		= 0x84,
+		.ver		= 0x01,
+		.len		= 0x0a,
+		.CC02_CT47	= substream->runtime->channels - 1,
+	};
+
+	hdmi_setup_channel_allocation(codec, &ai);
+	hdmi_setup_channel_mapping(codec, &ai);
+
+	hdmi_fill_audio_infoframe(codec, &ai);
+}
+
+
+/*
+ * Unsolicited events
+ */
+
+static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
+{
+	int pind = !!(res & AC_UNSOL_RES_PD);
+	int eldv = !!(res & AC_UNSOL_RES_ELDV);
+
+	printk(KERN_INFO
+		"HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n",
+		pind, eldv);
+
+	if (pind && eldv) {
+		hdmi_parse_eld(codec);
+		/* TODO: do real things about ELD */
+	}
+}
+
+static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
+{
+	int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+	int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
+	int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
+
+	printk(KERN_INFO
+		"HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+		subtag,
+		cp_state,
+		cp_ready);
+
+	/* TODO */
+	if (cp_state)
+		;
+	if (cp_ready)
+		;
+}
+
+
+static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+	int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+
+	if (tag != INTEL_HDMI_EVENT_TAG) {
+		snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
+		return;
+	}
+
+	if (subtag == 0)
+		hdmi_intrinsic_event(codec, res);
+	else
+		hdmi_non_intrinsic_event(codec, res);
+}
+
+/*
+ * Callbacks
+ */
+
+static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					struct snd_pcm_substream *substream)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 struct snd_pcm_substream *substream)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+
+	hdmi_disable_output(codec);
+
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int intel_hdmi_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 intel_hdmi_spec *spec = codec->spec;
+
+	snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+					     format, substream);
+
+	hdmi_set_channel_count(codec, substream->runtime->channels);
+
+	hdmi_setup_audio_infoframe(codec, substream);
+
+	hdmi_enable_output(codec);
+
+	return 0;
+}
+
+static struct hda_pcm_stream intel_hdmi_pcm_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 8,
+	.nid = CVT_NID, /* NID to query formats and rates and setup streams */
+	.ops = {
+		.open    = intel_hdmi_playback_pcm_open,
+		.close   = intel_hdmi_playback_pcm_close,
+		.prepare = intel_hdmi_playback_pcm_prepare
+	},
+};
+
+static int intel_hdmi_build_pcms(struct hda_codec *codec)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+	struct hda_pcm *info = &spec->pcm_rec;
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = "INTEL HDMI";
+	info->pcm_type = HDA_PCM_TYPE_HDMI;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback;
+
+	return 0;
+}
+
+static int intel_hdmi_build_controls(struct hda_codec *codec)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+	int err;
+
+	err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int intel_hdmi_init(struct hda_codec *codec)
+{
+	/* disable audio output as early as possible */
+	hdmi_disable_output(codec);
+
+	snd_hda_sequence_write(codec, unsolicited_response_verb);
+
+	return 0;
+}
+
+static void intel_hdmi_free(struct hda_codec *codec)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+
+	snd_hda_eld_proc_free(codec, &spec->sink_eld);
+	kfree(spec);
+}
+
+static struct hda_codec_ops intel_hdmi_patch_ops = {
+	.init			= intel_hdmi_init,
+	.free			= intel_hdmi_free,
+	.build_pcms		= intel_hdmi_build_pcms,
+	.build_controls 	= intel_hdmi_build_controls,
+	.unsol_event		= intel_hdmi_unsol_event,
+};
+
+static int patch_intel_hdmi(struct hda_codec *codec)
+{
+	struct intel_hdmi_spec *spec;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	spec->multiout.num_dacs = 0;	  /* no analog */
+	spec->multiout.max_channels = 8;
+	spec->multiout.dig_out_nid = CVT_NID;
+
+	codec->spec = spec;
+	codec->patch_ops = intel_hdmi_patch_ops;
+
+	snd_hda_eld_proc_new(codec, &spec->sink_eld);
+
+	init_channel_allocations();
+
+	return 0;
+}
+
+static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
+	{ .id = 0x808629fb, .name = "G45 DEVCL",  .patch = patch_intel_hdmi },
+	{ .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi },
+	{ .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi },
+	{ .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi },
+	{ .id = 0x10951392, .name = "SiI1392 HDMI",     .patch = patch_intel_hdmi },
+	{} /* terminator */
+};
+
+MODULE_ALIAS("snd-hda-codec-id:808629fb");
+MODULE_ALIAS("snd-hda-codec-id:80862801");
+MODULE_ALIAS("snd-hda-codec-id:80862802");
+MODULE_ALIAS("snd-hda-codec-id:80862803");
+MODULE_ALIAS("snd-hda-codec-id:10951392");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel HDMI HD-audio codec");
+
+static struct hda_codec_preset_list intel_list = {
+	.preset = snd_hda_preset_intelhdmi,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_intelhdmi_init(void)
+{
+	return snd_hda_add_codec_preset(&intel_list);
+}
+
+static void __exit patch_intelhdmi_exit(void)
+{
+	snd_hda_delete_codec_preset(&intel_list);
+}
+
+module_init(patch_intelhdmi_init)
+module_exit(patch_intelhdmi_exit)
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
index 2eed2c8..0270fda 100644
--- a/sound/pci/hda/patch_nvhdmi.c
+++ b/sound/pci/hda/patch_nvhdmi.c
@@ -158,8 +158,34 @@
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
-	{ .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi },
-	{ .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi },
+static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
+	{ .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi },
+	{ .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi },
+	{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:10de0002");
+MODULE_ALIAS("snd-hda-codec-id:10de0007");
+MODULE_ALIAS("snd-hda-codec-id:10de0067");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec");
+
+static struct hda_codec_preset_list nvhdmi_list = {
+	.preset = snd_hda_preset_nvhdmi,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_nvhdmi_init(void)
+{
+	return snd_hda_add_codec_preset(&nvhdmi_list);
+}
+
+static void __exit patch_nvhdmi_exit(void)
+{
+	snd_hda_delete_codec_preset(&nvhdmi_list);
+}
+
+module_init(patch_nvhdmi_init)
+module_exit(patch_nvhdmi_exit)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index a378c01..0bd4e6b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -30,7 +30,6 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 
 #define ALC880_FRONT_EVENT		0x01
 #define ALC880_DCVOL_EVENT		0x02
@@ -114,6 +113,7 @@
 	ALC268_3ST,
 	ALC268_TOSHIBA,
 	ALC268_ACER,
+	ALC268_ACER_DMIC,
 	ALC268_ACER_ASPIRE_ONE,
 	ALC268_DELL,
 	ALC268_ZEPTO,
@@ -130,6 +130,8 @@
 	ALC269_QUANTA_FL1,
 	ALC269_ASUS_EEEPC_P703,
 	ALC269_ASUS_EEEPC_P901,
+	ALC269_FUJITSU,
+	ALC269_LIFEBOOK,
 	ALC269_AUTO,
 	ALC269_MODEL_LAST /* last tag */
 };
@@ -152,6 +154,7 @@
 enum {
 	ALC660VD_3ST,
 	ALC660VD_3ST_DIG,
+	ALC660VD_ASUS_V1S,
 	ALC861VD_3ST,
 	ALC861VD_3ST_DIG,
 	ALC861VD_6ST_DIG,
@@ -212,6 +215,7 @@
 	ALC883_TARGA_2ch_DIG,
 	ALC883_ACER,
 	ALC883_ACER_ASPIRE,
+	ALC888_ACER_ASPIRE_4930G,
 	ALC883_MEDION,
 	ALC883_MEDION_MD2,
 	ALC883_LAPTOP_EAPD,
@@ -225,9 +229,11 @@
 	ALC883_MITAC,
 	ALC883_CLEVO_M720,
 	ALC883_FUJITSU_PI2515,
+	ALC888_FUJITSU_XA3530,
 	ALC883_3ST_6ch_INTEL,
 	ALC888_ASUS_M90V,
 	ALC888_ASUS_EEE1601,
+	ALC1200_ASUS_P5Q,
 	ALC883_AUTO,
 	ALC883_MODEL_LAST,
 };
@@ -239,6 +245,7 @@
 	/* codec parameterization */
 	struct snd_kcontrol_new *mixers[5];	/* mixer arrays */
 	unsigned int num_mixers;
+	struct snd_kcontrol_new *cap_mixer;	/* capture mixer */
 
 	const struct hda_verb *init_verbs[5];	/* initialization verbs
 						 * don't forget NULL
@@ -268,6 +275,7 @@
 	hda_nid_t *adc_nids;
 	hda_nid_t *capsrc_nids;
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
+	unsigned char is_mix_capture;	/* matrix-style capture (non-mux) */
 
 	/* capture source */
 	unsigned int num_mux_defs;
@@ -284,8 +292,7 @@
 
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
-	unsigned int num_kctl_alloc, num_kctl_used;
-	struct snd_kcontrol_new *kctl_alloc;
+	struct snd_array kctls;
 	struct hda_input_mux private_imux;
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
@@ -323,6 +330,7 @@
 	struct snd_kcontrol_new *mixers[5]; /* should be identical size
 					     * with spec
 					     */
+	struct snd_kcontrol_new *cap_mixer; /* capture mixer */
 	const struct hda_verb *init_verbs[5];
 	unsigned int num_dacs;
 	hda_nid_t *dac_nids;
@@ -375,14 +383,39 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct alc_spec *spec = codec->spec;
+	const struct hda_input_mux *imux;
 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
+	unsigned int mux_idx;
 	hda_nid_t nid = spec->capsrc_nids ?
 		spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
-	return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
-				     nid, &spec->cur_mux[adc_idx]);
-}
 
+	mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
+	imux = &spec->input_mux[mux_idx];
+
+	if (spec->is_mix_capture) {
+		/* Matrix-mixer style (e.g. ALC882) */
+		unsigned int *cur_val = &spec->cur_mux[adc_idx];
+		unsigned int i, idx;
+
+		idx = ucontrol->value.enumerated.item[0];
+		if (idx >= imux->num_items)
+			idx = imux->num_items - 1;
+		if (*cur_val == idx)
+			return 0;
+		for (i = 0; i < imux->num_items; i++) {
+			unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
+			snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
+						 imux->items[i].index,
+						 HDA_AMP_MUTE, v);
+		}
+		*cur_val = idx;
+		return 1;
+	} else {
+		/* MUX style (e.g. ALC880) */
+		return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
+					     &spec->cur_mux[adc_idx]);
+	}
+}
 
 /*
  * channel mode setting
@@ -717,6 +750,43 @@
 #endif   /* CONFIG_SND_DEBUG */
 
 /*
+ */
+static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
+{
+	if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
+		return;
+	spec->mixers[spec->num_mixers++] = mix;
+}
+
+static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
+{
+	if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
+		return;
+	spec->init_verbs[spec->num_init_verbs++] = verb;
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ * hook for proc
+ */
+static void print_realtek_coef(struct snd_info_buffer *buffer,
+			       struct hda_codec *codec, hda_nid_t nid)
+{
+	int coeff;
+
+	if (nid != 0x20)
+		return;
+	coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
+	snd_iprintf(buffer, "  Processing Coefficient: 0x%02x\n", coeff);
+	coeff = snd_hda_codec_read(codec, nid, 0,
+				   AC_VERB_GET_COEF_INDEX, 0);
+	snd_iprintf(buffer, "  Coefficient Index: 0x%02x\n", coeff);
+}
+#else
+#define print_realtek_coef	NULL
+#endif
+
+/*
  * set up from the preset table
  */
 static void setup_preset(struct alc_spec *spec,
@@ -725,11 +795,11 @@
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
-		spec->mixers[spec->num_mixers++] = preset->mixers[i];
+		add_mixer(spec, preset->mixers[i]);
+	spec->cap_mixer = preset->cap_mixer;
 	for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
 	     i++)
-		spec->init_verbs[spec->num_init_verbs++] =
-			preset->init_verbs[i];
+		add_verb(spec, preset->init_verbs[i]);
 
 	spec->channel_mode = preset->channel_mode;
 	spec->num_channel_mode = preset->num_channel_mode;
@@ -1107,6 +1177,226 @@
 }
 
 /*
+ * ALC888
+ */
+
+/*
+ * 2ch mode
+ */
+static struct hda_verb alc888_4ST_ch2_intel_init[] = {
+/* Mic-in jack as mic in */
+	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+/* Line-in jack as Line in */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+/* Line-Out as Front */
+	{ 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{ } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static struct hda_verb alc888_4ST_ch4_intel_init[] = {
+/* Mic-in jack as mic in */
+	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+/* Line-in jack as Surround */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-Out as Front */
+	{ 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{ } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc888_4ST_ch6_intel_init[] = {
+/* Mic-in jack as CLFE */
+	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-in jack as Surround */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
+	{ 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+	{ } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc888_4ST_ch8_intel_init[] = {
+/* Mic-in jack as CLFE */
+	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-in jack as Surround */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+/* Line-Out as Side */
+	{ 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+	{ } /* end */
+};
+
+static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
+	{ 2, alc888_4ST_ch2_intel_init },
+	{ 4, alc888_4ST_ch4_intel_init },
+	{ 6, alc888_4ST_ch6_intel_init },
+	{ 8, alc888_4ST_ch8_intel_init },
+};
+
+/*
+ * ALC888 Fujitsu Siemens Amillo xa3530
+ */
+
+static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
+/* Front Mic: set to PIN_IN (empty by default) */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Connect Internal HP 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 Bass HP to Front */
+	{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, 0x00},
+/* 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},
+/* Enable unsolicited event for HP jack and Line-out jack */
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{}
+};
+
+static void alc888_fujitsu_xa3530_automute(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;
+	/* 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);
+}
+
+static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec,
+		unsigned int res)
+{
+	if (res >> 26 == ALC880_HP_EVENT)
+		alc888_fujitsu_xa3530_automute(codec);
+}
+
+
+/*
+ * ALC888 Acer Aspire 4930G model
+ */
+
+static struct hda_verb alc888_acer_aspire_4930g_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 HP 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 HP out to front */
+	{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, 0x00},
+	{ }
+};
+
+static struct hda_input_mux alc888_2_capture_sources[2] = {
+	/* Front mic only available on one ADC */
+	{
+		.num_items = 4,
+		.items = {
+			{ "Mic", 0x0 },
+			{ "Line", 0x2 },
+			{ "CD", 0x4 },
+			{ "Front Mic", 0xb },
+		},
+	},
+	{
+		.num_items = 3,
+		.items = {
+			{ "Mic", 0x0 },
+			{ "Line", 0x2 },
+			{ "CD", 0x4 },
+		},
+	}
+};
+
+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),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
+		HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+	{ } /* end */
+};
+
+static void alc888_acer_aspire_4930g_automute(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);
+}
+
+static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec,
+		unsigned int res)
+{
+	if (res >> 26 == ALC880_HP_EVENT)
+		alc888_acer_aspire_4930g_automute(codec);
+}
+
+/*
  * ALC880 3-stack model
  *
  * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
@@ -1205,49 +1495,126 @@
 };
 
 /* capture mixer elements */
-static struct snd_kcontrol_new alc880_capture_mixer[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 3,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
-	{ } /* end */
-};
+static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	int err;
 
-/* capture mixer elements (in case NID 0x07 not available) */
-static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
-	{ } /* end */
-};
+	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+	kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
+						      HDA_INPUT);
+	err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
+	mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
+	return err;
+}
 
+static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+			   unsigned int size, unsigned int __user *tlv)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	int err;
+
+	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+	kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
+						      HDA_INPUT);
+	err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
+	mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
+	return err;
+}
+
+typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol);
+
+static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol,
+				 getput_call_t func)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	int err;
+
+	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+	kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
+						      3, 0, HDA_INPUT);
+	err = func(kcontrol, ucontrol);
+	mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
+	return err;
+}
+
+static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	return alc_cap_getput_caller(kcontrol, ucontrol,
+				     snd_hda_mixer_amp_volume_get);
+}
+
+static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	return alc_cap_getput_caller(kcontrol, ucontrol,
+				     snd_hda_mixer_amp_volume_put);
+}
+
+/* capture mixer elements */
+#define alc_cap_sw_info		snd_ctl_boolean_stereo_info
+
+static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	return alc_cap_getput_caller(kcontrol, ucontrol,
+				     snd_hda_mixer_amp_switch_get);
+}
+
+static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	return alc_cap_getput_caller(kcontrol, ucontrol,
+				     snd_hda_mixer_amp_switch_put);
+}
+
+#define DEFINE_CAPMIX(num) \
+static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
+	{ \
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+		.name = "Capture Switch", \
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+		.count = num, \
+		.info = alc_cap_sw_info, \
+		.get = alc_cap_sw_get, \
+		.put = alc_cap_sw_put, \
+	}, \
+	{ \
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+		.name = "Capture Volume", \
+		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+			   SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+			   SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
+		.count = num, \
+		.info = alc_cap_vol_info, \
+		.get = alc_cap_vol_get, \
+		.put = alc_cap_vol_put, \
+		.tlv = { .c = alc_cap_vol_tlv }, \
+	}, \
+	{ \
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+		/* .name = "Capture Source", */ \
+		.name = "Input Source", \
+		.count = num, \
+		.info = alc_mux_enum_info, \
+		.get = alc_mux_enum_get, \
+		.put = alc_mux_enum_put, \
+	}, \
+	{ } /* end */ \
+}
+
+/* up to three ADCs */
+DEFINE_CAPMIX(1);
+DEFINE_CAPMIX(2);
+DEFINE_CAPMIX(3);
 
 
 /*
@@ -1533,18 +1900,6 @@
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -1619,6 +1974,7 @@
 	"Speaker Playback Volume",
 	"Mono Playback Volume",
 	"Line-Out Playback Volume",
+	"PCM Playback Volume",
 	NULL,
 };
 
@@ -1638,6 +1994,9 @@
 /*
  * build control elements
  */
+
+static void alc_free_kctls(struct hda_codec *codec);
+
 static int alc_build_controls(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
@@ -1649,7 +2008,11 @@
 		if (err < 0)
 			return err;
 	}
-
+	if (spec->cap_mixer) {
+		err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
+		if (err < 0)
+			return err;
+	}
 	if (spec->multiout.dig_out_nid) {
 		err = snd_hda_create_spdif_out_ctls(codec,
 						    spec->multiout.dig_out_nid);
@@ -1684,6 +2047,7 @@
 			return err;
 	}
 
+	alc_free_kctls(codec); /* no longer needed */
 	return 0;
 }
 
@@ -2774,19 +3138,27 @@
 	return 0;
 }
 
+static void alc_free_kctls(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (spec->kctls.list) {
+		struct snd_kcontrol_new *kctl = spec->kctls.list;
+		int i;
+		for (i = 0; i < spec->kctls.used; i++)
+			kfree(kctl[i].name);
+	}
+	snd_array_free(&spec->kctls);
+}
+
 static void alc_free(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	unsigned int i;
 
 	if (!spec)
 		return;
 
-	if (spec->kctl_alloc) {
-		for (i = 0; i < spec->num_kctl_used; i++)
-			kfree(spec->kctl_alloc[i].name);
-		kfree(spec->kctl_alloc);
-	}
+	alc_free_kctls(codec);
 	kfree(spec);
 	codec->spec = NULL; /* to be sure */
 }
@@ -3268,6 +3640,8 @@
 				alc880_gpio2_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc880_dac_nids),
 		.dac_nids = alc880_dac_nids,
+		.adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
+		.num_adc_nids = 1, /* single ADC */
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
 		.channel_mode = alc880_2_jack_modes,
@@ -3532,9 +3906,6 @@
  * Automatic parse of I/O pins from the BIOS configuration
  */
 
-#define NUM_CONTROL_ALLOC	32
-#define NUM_VERB_ALLOC		32
-
 enum {
 	ALC_CTL_WIDGET_VOL,
 	ALC_CTL_WIDGET_MUTE,
@@ -3552,29 +3923,15 @@
 {
 	struct snd_kcontrol_new *knew;
 
-	if (spec->num_kctl_used >= spec->num_kctl_alloc) {
-		int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
-
-		/* array + terminator */
-		knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
-		if (!knew)
-			return -ENOMEM;
-		if (spec->kctl_alloc) {
-			memcpy(knew, spec->kctl_alloc,
-			       sizeof(*knew) * spec->num_kctl_alloc);
-			kfree(spec->kctl_alloc);
-		}
-		spec->kctl_alloc = knew;
-		spec->num_kctl_alloc = num;
-	}
-
-	knew = &spec->kctl_alloc[spec->num_kctl_used];
+	snd_array_init(&spec->kctls, sizeof(*knew), 32);
+	knew = snd_array_new(&spec->kctls);
+	if (!knew)
+		return -ENOMEM;
 	*knew = alc880_control_templates[type];
 	knew->name = kstrdup(name, GFP_KERNEL);
 	if (!knew->name)
 		return -ENOMEM;
 	knew->private_value = val;
-	spec->num_kctl_used++;
 	return 0;
 }
 
@@ -3898,10 +4255,10 @@
 	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = ALC880_DIGIN_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		add_mixer(spec, spec->kctls.list);
 
-	spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
+	add_verb(spec, alc880_volume_init_verbs);
 
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
@@ -3925,6 +4282,17 @@
  * OK, here we have finally the patch for ALC880
  */
 
+static void set_capture_mixer(struct alc_spec *spec)
+{
+	static struct snd_kcontrol_new *caps[3] = {
+		alc_capture_mixer1,
+		alc_capture_mixer2,
+		alc_capture_mixer3,
+	};
+	if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3)
+		spec->cap_mixer = caps[spec->num_adc_nids - 1];
+}
+
 static int patch_alc880(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
@@ -3980,16 +4348,12 @@
 		if (wcap != AC_WID_AUD_IN) {
 			spec->adc_nids = alc880_adc_nids_alt;
 			spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
-			spec->mixers[spec->num_mixers] =
-				alc880_capture_alt_mixer;
-			spec->num_mixers++;
 		} else {
 			spec->adc_nids = alc880_adc_nids;
 			spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
-			spec->mixers[spec->num_mixers] = alc880_capture_mixer;
-			spec->num_mixers++;
 		}
 	}
+	set_capture_mixer(spec);
 
 	spec->vmaster_nid = 0x0c;
 
@@ -4000,6 +4364,7 @@
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc880_loopbacks;
 #endif
+	codec->proc_widget_hook = print_realtek_coef;
 
 	return 0;
 }
@@ -4024,11 +4389,6 @@
 	0x05,
 };
 
-static hda_nid_t alc260_hp_adc_nids[2] = {
-	/* ADC1, 0 */
-	0x05, 0x04
-};
-
 /* NIDs used when simultaneous access to both ADCs makes sense.  Note that
  * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
  */
@@ -4157,13 +4517,13 @@
 	struct alc_spec *spec = codec->spec;
 	unsigned int val = spec->master_sw ? PIN_HP : 0;
 	/* change HP and line-out pins */
-	snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+	snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 			    val);
-	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+	snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 			    val);
 	/* mono (speaker) depending on the HP jack sense */
 	val = (val && !spec->jack_present) ? PIN_OUT : 0;
-	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+	snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 			    val);
 }
 
@@ -4242,7 +4602,7 @@
 		.info = snd_ctl_boolean_mono_info,
 		.get = alc260_hp_master_sw_get,
 		.put = alc260_hp_master_sw_put,
-		.private_value = (0x10 << 16) | (0x15 << 8) | 0x11
+		.private_value = (0x15 << 16) | (0x10 << 8) | 0x11
 	},
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
@@ -4295,7 +4655,7 @@
 	present = snd_hda_codec_read(codec, 0x15, 0,
 				     AC_VERB_GET_PIN_SENSE, 0);
 	spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
-	alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
+	alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
 }
 
 static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
@@ -4427,45 +4787,6 @@
 	{ } /* end */
 };
 
-/* capture mixer elements */
-static struct snd_kcontrol_new alc260_capture_mixer[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
-	{ } /* end */
-};
-
-static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
-	{ } /* end */
-};
-
 /*
  * initialization verbs
  */
@@ -5282,7 +5603,6 @@
 static int alc260_parse_auto_config(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	unsigned int wcap;
 	int err;
 	static hda_nid_t alc260_ignore[] = { 0x17, 0 };
 
@@ -5293,7 +5613,7 @@
 	err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
 	if (err < 0)
 		return err;
-	if (!spec->kctl_alloc)
+	if (!spec->kctls.list)
 		return 0; /* can't find valid BIOS pin config */
 	err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
 	if (err < 0)
@@ -5303,28 +5623,14 @@
 
 	if (spec->autocfg.dig_out_pin)
 		spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		add_mixer(spec, spec->kctls.list);
 
-	spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
+	add_verb(spec, alc260_volume_init_verbs);
 
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
 
-	/* check whether NID 0x04 is valid */
-	wcap = get_wcaps(codec, 0x04);
-	wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
-	if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
-		spec->adc_nids = alc260_adc_nids_alt;
-		spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
-		spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
-	} else {
-		spec->adc_nids = alc260_adc_nids;
-		spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
-		spec->mixers[spec->num_mixers] = alc260_capture_mixer;
-	}
-	spec->num_mixers++;
-
 	store_pin_configs(codec);
 	return 1;
 }
@@ -5394,12 +5700,11 @@
 	[ALC260_BASIC] = {
 		.mixers = { alc260_base_output_mixer,
 			    alc260_input_mixer,
-			    alc260_pc_beep_mixer,
-			    alc260_capture_mixer },
+			    alc260_pc_beep_mixer },
 		.init_verbs = { alc260_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
 		.dac_nids = alc260_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
+		.num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
 		.adc_nids = alc260_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
@@ -5407,14 +5712,13 @@
 	},
 	[ALC260_HP] = {
 		.mixers = { alc260_hp_output_mixer,
-			    alc260_input_mixer,
-			    alc260_capture_alt_mixer },
+			    alc260_input_mixer },
 		.init_verbs = { alc260_init_verbs,
 				alc260_hp_unsol_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
 		.dac_nids = alc260_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
-		.adc_nids = alc260_hp_adc_nids,
+		.num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
+		.adc_nids = alc260_adc_nids_alt,
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_capture_source,
@@ -5423,14 +5727,13 @@
 	},
 	[ALC260_HP_DC7600] = {
 		.mixers = { alc260_hp_dc7600_mixer,
-			    alc260_input_mixer,
-			    alc260_capture_alt_mixer },
+			    alc260_input_mixer },
 		.init_verbs = { alc260_init_verbs,
 				alc260_hp_dc7600_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
 		.dac_nids = alc260_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
-		.adc_nids = alc260_hp_adc_nids,
+		.num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
+		.adc_nids = alc260_adc_nids_alt,
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_capture_source,
@@ -5439,14 +5742,13 @@
 	},
 	[ALC260_HP_3013] = {
 		.mixers = { alc260_hp_3013_mixer,
-			    alc260_input_mixer,
-			    alc260_capture_alt_mixer },
+			    alc260_input_mixer },
 		.init_verbs = { alc260_hp_3013_init_verbs,
 				alc260_hp_3013_unsol_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
 		.dac_nids = alc260_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
-		.adc_nids = alc260_hp_adc_nids,
+		.num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
+		.adc_nids = alc260_adc_nids_alt,
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_capture_source,
@@ -5454,8 +5756,7 @@
 		.init_hook = alc260_hp_3013_automute,
 	},
 	[ALC260_FUJITSU_S702X] = {
-		.mixers = { alc260_fujitsu_mixer,
-			    alc260_capture_mixer },
+		.mixers = { alc260_fujitsu_mixer },
 		.init_verbs = { alc260_fujitsu_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
 		.dac_nids = alc260_dac_nids,
@@ -5467,8 +5768,7 @@
 		.input_mux = alc260_fujitsu_capture_sources,
 	},
 	[ALC260_ACER] = {
-		.mixers = { alc260_acer_mixer,
-			    alc260_capture_mixer },
+		.mixers = { alc260_acer_mixer },
 		.init_verbs = { alc260_acer_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
 		.dac_nids = alc260_dac_nids,
@@ -5480,8 +5780,7 @@
 		.input_mux = alc260_acer_capture_sources,
 	},
 	[ALC260_WILL] = {
-		.mixers = { alc260_will_mixer,
-			    alc260_capture_mixer },
+		.mixers = { alc260_will_mixer },
 		.init_verbs = { alc260_init_verbs, alc260_will_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
 		.dac_nids = alc260_dac_nids,
@@ -5493,8 +5792,7 @@
 		.input_mux = &alc260_capture_source,
 	},
 	[ALC260_REPLACER_672V] = {
-		.mixers = { alc260_replacer_672v_mixer,
-			    alc260_capture_mixer },
+		.mixers = { alc260_replacer_672v_mixer },
 		.init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
 		.dac_nids = alc260_dac_nids,
@@ -5509,8 +5807,7 @@
 	},
 #ifdef CONFIG_SND_DEBUG
 	[ALC260_TEST] = {
-		.mixers = { alc260_test_mixer,
-			    alc260_capture_mixer },
+		.mixers = { alc260_test_mixer },
 		.init_verbs = { alc260_test_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
 		.dac_nids = alc260_test_dac_nids,
@@ -5569,6 +5866,21 @@
 	spec->stream_digital_playback = &alc260_pcm_digital_playback;
 	spec->stream_digital_capture = &alc260_pcm_digital_capture;
 
+	if (!spec->adc_nids && spec->input_mux) {
+		/* check whether NID 0x04 is valid */
+		unsigned int wcap = get_wcaps(codec, 0x04);
+		wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+		/* get type */
+		if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
+			spec->adc_nids = alc260_adc_nids_alt;
+			spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
+		} else {
+			spec->adc_nids = alc260_adc_nids;
+			spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
+		}
+	}
+	set_capture_mixer(spec);
+
 	spec->vmaster_nid = 0x08;
 
 	codec->patch_ops = alc_patch_ops;
@@ -5578,6 +5890,7 @@
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc260_loopbacks;
 #endif
+	codec->proc_widget_hook = print_realtek_coef;
 
 	return 0;
 }
@@ -5625,36 +5938,6 @@
 		{ "CD", 0x4 },
 	},
 };
-#define alc882_mux_enum_info alc_mux_enum_info
-#define alc882_mux_enum_get alc_mux_enum_get
-
-static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	const struct hda_input_mux *imux = spec->input_mux;
-	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	hda_nid_t nid = spec->capsrc_nids ?
-		spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
-	unsigned int *cur_val = &spec->cur_mux[adc_idx];
-	unsigned int i, idx;
-
-	idx = ucontrol->value.enumerated.item[0];
-	if (idx >= imux->num_items)
-		idx = imux->num_items - 1;
-	if (*cur_val == idx)
-		return 0;
-	for (i = 0; i < imux->num_items; i++) {
-		unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-		snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-					 imux->items[i].index,
-					 HDA_AMP_MUTE, v);
-	}
-	*cur_val = idx;
-	return 1;
-}
-
 /*
  * 2ch mode
  */
@@ -6337,49 +6620,6 @@
 	{ }
 };
 
-/* capture mixer elements */
-static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc882_mux_enum_info,
-		.get = alc882_mux_enum_get,
-		.put = alc882_mux_enum_put,
-	},
-	{ } /* end */
-};
-
-static struct snd_kcontrol_new alc882_capture_mixer[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 3,
-		.info = alc882_mux_enum_info,
-		.get = alc882_mux_enum_get,
-		.put = alc882_mux_enum_put,
-	},
-	{ } /* end */
-};
-
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc882_loopbacks	alc880_loopbacks
 #endif
@@ -6508,8 +6748,7 @@
 		.init_hook = alc885_imac24_init_hook,
 	},
 	[ALC882_TARGA] = {
-		.mixers = { alc882_targa_mixer, alc882_chmode_mixer,
-			    alc882_capture_mixer },
+		.mixers = { alc882_targa_mixer, alc882_chmode_mixer },
 		.init_verbs = { alc882_init_verbs, alc882_targa_verbs},
 		.num_dacs = ARRAY_SIZE(alc882_dac_nids),
 		.dac_nids = alc882_dac_nids,
@@ -6525,8 +6764,7 @@
 		.init_hook = alc882_targa_automute,
 	},
 	[ALC882_ASUS_A7J] = {
-		.mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
-			    alc882_capture_mixer },
+		.mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
 		.init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
 		.num_dacs = ARRAY_SIZE(alc882_dac_nids),
 		.dac_nids = alc882_dac_nids,
@@ -6831,6 +7069,7 @@
 	spec->stream_digital_playback = &alc882_pcm_digital_playback;
 	spec->stream_digital_capture = &alc882_pcm_digital_capture;
 
+	spec->is_mix_capture = 1; /* matrix-style capture */
 	if (!spec->adc_nids && spec->input_mux) {
 		/* check whether NID 0x07 is valid */
 		unsigned int wcap = get_wcaps(codec, 0x07);
@@ -6840,17 +7079,13 @@
 			spec->adc_nids = alc882_adc_nids_alt;
 			spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
 			spec->capsrc_nids = alc882_capsrc_nids_alt;
-			spec->mixers[spec->num_mixers] =
-				alc882_capture_alt_mixer;
-			spec->num_mixers++;
 		} else {
 			spec->adc_nids = alc882_adc_nids;
 			spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
 			spec->capsrc_nids = alc882_capsrc_nids;
-			spec->mixers[spec->num_mixers] = alc882_capture_mixer;
-			spec->num_mixers++;
 		}
 	}
+	set_capture_mixer(spec);
 
 	spec->vmaster_nid = 0x0c;
 
@@ -6861,6 +7096,7 @@
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc882_loopbacks;
 #endif
+	codec->proc_widget_hook = print_realtek_coef;
 
 	return 0;
 }
@@ -6879,6 +7115,8 @@
 #define ALC883_DIGOUT_NID	0x06
 #define ALC883_DIGIN_NID	0x0a
 
+#define ALC1200_DIGOUT_NID	0x10
+
 static hda_nid_t alc883_dac_nids[4] = {
 	/* front, rear, clfe, rear_surr */
 	0x02, 0x03, 0x04, 0x05
@@ -6889,8 +7127,20 @@
 	0x08, 0x09,
 };
 
+static hda_nid_t alc883_adc_nids_alt[1] = {
+	/* ADC1 */
+	0x08,
+};
+
+static hda_nid_t alc883_adc_nids_rev[2] = {
+	/* ADC2-1 */
+	0x09, 0x08
+};
+
 static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
 
+static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 
@@ -6957,11 +7207,6 @@
 	},
 };
 
-#define alc883_mux_enum_info alc_mux_enum_info
-#define alc883_mux_enum_get alc_mux_enum_get
-/* ALC883 has the ALC882-type input selection */
-#define alc883_mux_enum_put alc882_mux_enum_put
-
 /*
  * 2ch mode
  */
@@ -7115,19 +7360,6 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7145,19 +7377,6 @@
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7172,19 +7391,6 @@
 	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7199,19 +7405,6 @@
 	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7231,19 +7424,6 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7269,17 +7449,6 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7306,19 +7475,6 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7344,18 +7500,6 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7376,19 +7520,6 @@
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7404,19 +7535,6 @@
 	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7429,17 +7547,6 @@
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7453,19 +7560,6 @@
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7479,19 +7573,6 @@
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, 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("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7504,19 +7585,6 @@
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7544,19 +7612,6 @@
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -7587,6 +7642,10 @@
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
 	HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
 	HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
 	{
@@ -7594,9 +7653,9 @@
 		/* .name = "Capture Source", */
 		.name = "Input Source",
 		.count = 1,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
 	},
 	{ } /* end */
 };
@@ -8251,27 +8310,6 @@
 	{ }
 };
 
-/* capture mixer elements */
-static struct snd_kcontrol_new alc883_capture_mixer[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc882_mux_enum_info,
-		.get = alc882_mux_enum_get,
-		.put = alc882_mux_enum_put,
-	},
-	{ } /* end */
-};
-
 static struct hda_verb alc888_asus_m90v_verbs[] = {
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -8394,6 +8432,7 @@
 	[ALC883_TARGA_2ch_DIG]	= "targa-2ch-dig",
 	[ALC883_ACER]		= "acer",
 	[ALC883_ACER_ASPIRE]	= "acer-aspire",
+	[ALC888_ACER_ASPIRE_4930G]	= "acer-aspire-4930g",
 	[ALC883_MEDION]		= "medion",
 	[ALC883_MEDION_MD2]	= "medion-md2",
 	[ALC883_LAPTOP_EAPD]	= "laptop-eapd",
@@ -8407,7 +8446,9 @@
 	[ALC883_MITAC]		= "mitac",
 	[ALC883_CLEVO_M720]	= "clevo-m720",
 	[ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
+	[ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
 	[ALC883_3ST_6ch_INTEL]	= "3stack-6ch-intel",
+	[ALC1200_ASUS_P5Q]	= "asus-p5q",
 	[ALC883_AUTO]		= "auto",
 };
 
@@ -8418,6 +8459,8 @@
 	SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
+	SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
+		ALC888_ACER_ASPIRE_4930G),
 	SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
 	SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
 	SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
@@ -8426,6 +8469,7 @@
 	SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
 	SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
+	SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
 	SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
 	SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
@@ -8452,6 +8496,7 @@
 	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),
+	SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
 	SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
@@ -8463,6 +8508,8 @@
 	SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
 	SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
 	SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
+	SND_PCI_QUIRK(0x1734, 0x113d, "Fujitsu AMILO Xa3530",
+		ALC888_FUJITSU_XA3530),
 	SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
 	SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
 	SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
@@ -8553,6 +8600,8 @@
 		.init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
+		.adc_nids = alc883_adc_nids_alt,
+		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
 		.dig_out_nid = ALC883_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
@@ -8586,6 +8635,26 @@
 		.unsol_event = alc883_acer_aspire_unsol_event,
 		.init_hook = alc883_acer_aspire_automute,
 	},
+	[ALC888_ACER_ASPIRE_4930G] = {
+		.mixers = { alc888_base_mixer,
+				alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
+				alc888_acer_aspire_4930g_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,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+		.channel_mode = alc883_3ST_6ch_modes,
+		.need_dac_fix = 1,
+		.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,
+	},
 	[ALC883_MEDION] = {
 		.mixers = { alc883_fivestack_mixer,
 			    alc883_chmode_mixer },
@@ -8593,6 +8662,8 @@
 				alc883_medion_eapd_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
+		.adc_nids = alc883_adc_nids_alt,
+		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.channel_mode = alc883_sixstack_modes,
 		.input_mux = &alc883_capture_source,
@@ -8635,6 +8706,8 @@
 		.init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
+		.adc_nids = alc883_adc_nids_alt,
+		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_lenovo_101e_capture_source,
@@ -8725,14 +8798,30 @@
 		.unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
 		.init_hook = alc883_2ch_fujitsu_pi2515_automute,
 	},
+	[ALC888_FUJITSU_XA3530] = {
+		.mixers = { alc888_base_mixer, alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs,
+			alc888_fujitsu_xa3530_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,
+		.num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
+		.channel_mode = alc888_4ST_8ch_intel_modes,
+		.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,
+	},
 	[ALC888_LENOVO_SKY] = {
 		.mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
 		.init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.channel_mode = alc883_sixstack_modes,
 		.need_dac_fix = 1,
@@ -8756,6 +8845,7 @@
 	},
 	[ALC888_ASUS_EEE1601] = {
 		.mixers = { alc883_asus_eee1601_mixer },
+		.cap_mixer = alc883_asus_eee1601_cap_mixer,
 		.init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
@@ -8768,6 +8858,17 @@
 		.unsol_event = alc883_eee1601_unsol_event,
 		.init_hook = alc883_eee1601_inithook,
 	},
+	[ALC1200_ASUS_P5Q] = {
+		.mixers = { alc883_base_mixer, alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.dig_out_nid = ALC1200_DIGOUT_NID,
+		.dig_in_nid = ALC883_DIGIN_NID,
+		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+		.channel_mode = alc883_sixstack_modes,
+		.input_mux = &alc883_capture_source,
+	},
 };
 
 
@@ -8862,8 +8963,6 @@
 
 	/* hack - override the init verbs */
 	spec->init_verbs[0] = alc883_auto_init_verbs;
-	spec->mixers[spec->num_mixers] = alc883_capture_mixer;
-	spec->num_mixers++;
 
 	return 1; /* config found */
 }
@@ -8946,9 +9045,15 @@
 	spec->stream_digital_playback = &alc883_pcm_digital_playback;
 	spec->stream_digital_capture = &alc883_pcm_digital_capture;
 
-	spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
-	spec->adc_nids = alc883_adc_nids;
-	spec->capsrc_nids = alc883_capsrc_nids;
+	if (!spec->num_adc_nids) {
+		spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+		spec->adc_nids = alc883_adc_nids;
+	}
+	if (!spec->capsrc_nids)
+		spec->capsrc_nids = alc883_capsrc_nids;
+	spec->is_mix_capture = 1; /* matrix-style capture */
+	if (!spec->cap_mixer)
+		set_capture_mixer(spec);
 
 	spec->vmaster_nid = 0x0c;
 
@@ -8960,6 +9065,7 @@
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc883_loopbacks;
 #endif
+	codec->proc_widget_hook = print_realtek_coef;
 
 	return 0;
 }
@@ -9439,20 +9545,6 @@
 	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),
-	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -9969,7 +10061,7 @@
 	struct alc_spec *spec = codec->spec;
 	int ret;
 
-	ret = alc882_mux_enum_put(kcontrol, ucontrol);
+	ret = alc_mux_enum_put(kcontrol, ucontrol);
 	if (!ret)
 		return 0;
 	/* reprogram the HP pin as mic or HP according to the input source */
@@ -9986,8 +10078,8 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Capture Source",
-		.info = alc882_mux_enum_info,
-		.get = alc882_mux_enum_get,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
 		.put = alc262_ultra_mux_enum_put,
 	},
 	{ } /* end */
@@ -10380,10 +10472,10 @@
 	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = ALC262_DIGIN_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		add_mixer(spec, spec->kctls.list);
 
-	spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
+	add_verb(spec, alc262_volume_init_verbs);
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
 
@@ -10466,6 +10558,8 @@
 	SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
 	SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
 	SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
+	SND_PCI_QUIRK(0x104d, 0x9033, "Sony VAIO VGN-SR19XN",
+		      ALC262_SONY_ASSAMD),
 	SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
 		      ALC262_TOSHIBA_RX1),
 	SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
@@ -10624,7 +10718,8 @@
 		.init_hook = alc262_hippo_automute,
 	},
 	[ALC262_ULTRA] = {
-		.mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer },
+		.mixers = { alc262_ultra_mixer },
+		.cap_mixer = alc262_ultra_capture_mixer,
 		.init_verbs = { alc262_ultra_verbs },
 		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
 		.dac_nids = alc262_dac_nids,
@@ -10750,6 +10845,7 @@
 	spec->stream_digital_playback = &alc262_pcm_digital_playback;
 	spec->stream_digital_capture = &alc262_pcm_digital_capture;
 
+	spec->is_mix_capture = 1;
 	if (!spec->adc_nids && spec->input_mux) {
 		/* check whether NID 0x07 is valid */
 		unsigned int wcap = get_wcaps(codec, 0x07);
@@ -10760,17 +10856,14 @@
 			spec->adc_nids = alc262_adc_nids_alt;
 			spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
 			spec->capsrc_nids = alc262_capsrc_nids_alt;
-			spec->mixers[spec->num_mixers] =
-				alc262_capture_alt_mixer;
-			spec->num_mixers++;
 		} else {
 			spec->adc_nids = alc262_adc_nids;
 			spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
 			spec->capsrc_nids = alc262_capsrc_nids;
-			spec->mixers[spec->num_mixers] = alc262_capture_mixer;
-			spec->num_mixers++;
 		}
 	}
+	if (!spec->cap_mixer)
+		set_capture_mixer(spec);
 
 	spec->vmaster_nid = 0x0c;
 
@@ -10781,6 +10874,7 @@
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc262_loopbacks;
 #endif
+	codec->proc_widget_hook = print_realtek_coef;
 
 	return 0;
 }
@@ -10942,6 +11036,22 @@
 	{ }
 };
 
+static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
+	/* output mixer control */
+	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_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 = alc268_acer_master_sw_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+	},
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+	{ }
+};
+
 static struct hda_verb alc268_acer_aspire_one_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -11218,10 +11328,6 @@
 	{ }
 };
 
-#define alc268_mux_enum_info alc_mux_enum_info
-#define alc268_mux_enum_get alc_mux_enum_get
-#define alc268_mux_enum_put alc_mux_enum_put
-
 static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
@@ -11233,9 +11339,9 @@
 		/* .name = "Capture Source", */
 		.name = "Input Source",
 		.count = 1,
-		.info = alc268_mux_enum_info,
-		.get = alc268_mux_enum_get,
-		.put = alc268_mux_enum_put,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
 	},
 	{ } /* end */
 };
@@ -11253,9 +11359,9 @@
 		/* .name = "Capture Source", */
 		.name = "Input Source",
 		.count = 2,
-		.info = alc268_mux_enum_info,
-		.get = alc268_mux_enum_get,
-		.put = alc268_mux_enum_put,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
 	},
 	{ } /* end */
 };
@@ -11274,6 +11380,15 @@
 	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
+		{ "Internal Mic", 0x1 },
+		{ "Line", 0x2 },
+	},
+};
+
+static struct hda_input_mux alc268_acer_dmic_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Mic", 0x0 },
 		{ "Internal Mic", 0x6 },
 		{ "Line", 0x2 },
 	},
@@ -11512,13 +11627,13 @@
 	if (spec->autocfg.dig_out_pin)
 		spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		add_mixer(spec, spec->kctls.list);
 
 	if (spec->autocfg.speaker_pins[0] != 0x1d)
-		spec->mixers[spec->num_mixers++] = alc268_beep_mixer;
+		add_mixer(spec, alc268_beep_mixer);
 
-	spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
+	add_verb(spec, alc268_volume_init_verbs);
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
 
@@ -11554,6 +11669,7 @@
 	[ALC268_3ST]		= "3stack",
 	[ALC268_TOSHIBA]	= "toshiba",
 	[ALC268_ACER]		= "acer",
+	[ALC268_ACER_DMIC]	= "acer-dmic",
 	[ALC268_ACER_ASPIRE_ONE]	= "acer-aspire",
 	[ALC268_DELL]		= "dell",
 	[ALC268_ZEPTO]		= "zepto",
@@ -11649,6 +11765,23 @@
 		.unsol_event = alc268_acer_unsol_event,
 		.init_hook = alc268_acer_init_hook,
 	},
+	[ALC268_ACER_DMIC] = {
+		.mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
+			    alc268_beep_mixer },
+		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+				alc268_acer_verbs },
+		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
+		.dac_nids = alc268_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+		.adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
+		.hp_nid = 0x02,
+		.num_channel_mode = ARRAY_SIZE(alc268_modes),
+		.channel_mode = alc268_modes,
+		.input_mux = &alc268_acer_dmic_capture_source,
+		.unsol_event = alc268_acer_unsol_event,
+		.init_hook = alc268_acer_init_hook,
+	},
 	[ALC268_ACER_ASPIRE_ONE] = {
 		.mixers = { alc268_acer_aspire_one_mixer,
 				alc268_capture_alt_mixer },
@@ -11787,15 +11920,11 @@
 		if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
 			spec->adc_nids = alc268_adc_nids_alt;
 			spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
-			spec->mixers[spec->num_mixers] =
-					alc268_capture_alt_mixer;
-			spec->num_mixers++;
+			add_mixer(spec, alc268_capture_alt_mixer);
 		} else {
 			spec->adc_nids = alc268_adc_nids;
 			spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
-			spec->mixers[spec->num_mixers] =
-				alc268_capture_mixer;
-			spec->num_mixers++;
+			add_mixer(spec, alc268_capture_mixer);
 		}
 		spec->capsrc_nids = alc268_capsrc_nids;
 		/* set default input source */
@@ -11811,6 +11940,8 @@
 	if (board_config == ALC268_AUTO)
 		spec->init_hook = alc268_auto_init;
 
+	codec->proc_widget_hook = print_realtek_coef;
+
 	return 0;
 }
 
@@ -11893,6 +12024,31 @@
 	{ }
 };
 
+static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
+	/* output mixer control */
+	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_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 = alc268_acer_master_sw_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+	},
+	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("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	{ }
+};
+
 /* bind volumes of both NID 0x0c and 0x0d */
 static struct hda_bind_ctls alc269_epc_bind_vol = {
 	.ops = &snd_hda_bind_vol,
@@ -11911,28 +12067,18 @@
 };
 
 /* capture mixer elements */
-static struct snd_kcontrol_new alc269_capture_mixer[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
-	{ } /* end */
-};
-
-/* capture mixer elements */
 static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	{ } /* end */
+};
+
+/* FSC amilo */
+static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
 	{ } /* end */
 };
 
@@ -11953,6 +12099,20 @@
 	{ }
 };
 
+static struct hda_verb alc269_lifebook_verbs[] = {
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{ }
+};
+
 /* toggle speaker-output according to the hp-jack state */
 static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
 {
@@ -11978,6 +12138,37 @@
 			AC_VERB_SET_PROC_COEF, 0x480);
 }
 
+/* toggle speaker-output according to the hp-jacks state */
+static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	/* Check laptop headphone socket */
+	present = snd_hda_codec_read(codec, 0x15, 0,
+			AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+	/* Check port replicator headphone socket */
+	present |= snd_hda_codec_read(codec, 0x1a, 0,
+			AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+	bits = present ? AMP_IN_MUTE(0) : 0;
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
+			AMP_IN_MUTE(0), bits);
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
+			AMP_IN_MUTE(0), bits);
+
+	snd_hda_codec_write(codec, 0x20, 0,
+			AC_VERB_SET_COEF_INDEX, 0x0c);
+	snd_hda_codec_write(codec, 0x20, 0,
+			AC_VERB_SET_PROC_COEF, 0x680);
+
+	snd_hda_codec_write(codec, 0x20, 0,
+			AC_VERB_SET_COEF_INDEX, 0x0c);
+	snd_hda_codec_write(codec, 0x20, 0,
+			AC_VERB_SET_PROC_COEF, 0x480);
+}
+
 static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
 {
 	unsigned int present;
@@ -11988,6 +12179,29 @@
 			    AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
 }
 
+static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
+{
+	unsigned int present_laptop;
+	unsigned int present_dock;
+
+	present_laptop = snd_hda_codec_read(codec, 0x18, 0,
+				AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+	present_dock = snd_hda_codec_read(codec, 0x1b, 0,
+				AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+	/* Laptop mic port overrides dock mic port, design decision */
+	if (present_dock)
+		snd_hda_codec_write(codec, 0x23, 0,
+				AC_VERB_SET_CONNECT_SEL, 0x3);
+	if (present_laptop)
+		snd_hda_codec_write(codec, 0x23, 0,
+				AC_VERB_SET_CONNECT_SEL, 0x0);
+	if (!present_dock && !present_laptop)
+		snd_hda_codec_write(codec, 0x23, 0,
+				AC_VERB_SET_CONNECT_SEL, 0x1);
+}
+
 static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
 				    unsigned int res)
 {
@@ -11997,12 +12211,27 @@
 		alc269_quanta_fl1_mic_automute(codec);
 }
 
+static void alc269_lifebook_unsol_event(struct hda_codec *codec,
+					unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc269_lifebook_speaker_automute(codec);
+	if ((res >> 26) == ALC880_MIC_EVENT)
+		alc269_lifebook_mic_autoswitch(codec);
+}
+
 static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
 {
 	alc269_quanta_fl1_speaker_automute(codec);
 	alc269_quanta_fl1_mic_automute(codec);
 }
 
+static void alc269_lifebook_init_hook(struct hda_codec *codec)
+{
+	alc269_lifebook_speaker_automute(codec);
+	alc269_lifebook_mic_autoswitch(codec);
+}
+
 static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
@@ -12303,17 +12532,17 @@
 	if (spec->autocfg.dig_out_pin)
 		spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		add_mixer(spec, spec->kctls.list);
 
 	/* create a beep mixer control if the pin 0x1d isn't assigned */
 	for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
 		if (spec->autocfg.input_pins[i] == 0x1d)
 			break;
 	if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
-		spec->mixers[spec->num_mixers++] = alc269_beep_mixer;
+		add_mixer(spec, alc269_beep_mixer);
 
-	spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
+	add_verb(spec, alc269_init_verbs);
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
 	/* set default input source */
@@ -12325,8 +12554,8 @@
 	if (err < 0)
 		return err;
 
-	spec->mixers[spec->num_mixers] = alc269_capture_mixer;
-	spec->num_mixers++;
+	if (!spec->cap_mixer)
+		set_capture_mixer(spec);
 
 	store_pin_configs(codec);
 	return 1;
@@ -12355,7 +12584,9 @@
 	[ALC269_BASIC]			= "basic",
 	[ALC269_QUANTA_FL1]		= "quanta",
 	[ALC269_ASUS_EEEPC_P703]	= "eeepc-p703",
-	[ALC269_ASUS_EEEPC_P901]	= "eeepc-p901"
+	[ALC269_ASUS_EEEPC_P901]	= "eeepc-p901",
+	[ALC269_FUJITSU]		= "fujitsu",
+	[ALC269_LIFEBOOK]		= "lifebook"
 };
 
 static struct snd_pci_quirk alc269_cfg_tbl[] = {
@@ -12366,12 +12597,14 @@
 		      ALC269_ASUS_EEEPC_P901),
 	SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
 		      ALC269_ASUS_EEEPC_P901),
+	SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
+	SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
 	{}
 };
 
 static struct alc_config_preset alc269_presets[] = {
 	[ALC269_BASIC] = {
-		.mixers = { alc269_base_mixer, alc269_capture_mixer },
+		.mixers = { alc269_base_mixer },
 		.init_verbs = { alc269_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc269_dac_nids),
 		.dac_nids = alc269_dac_nids,
@@ -12393,7 +12626,8 @@
 		.init_hook = alc269_quanta_fl1_init_hook,
 	},
 	[ALC269_ASUS_EEEPC_P703] = {
-		.mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer },
+		.mixers = { alc269_eeepc_mixer },
+		.cap_mixer = alc269_epc_capture_mixer,
 		.init_verbs = { alc269_init_verbs,
 				alc269_eeepc_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc269_dac_nids),
@@ -12406,7 +12640,8 @@
 		.init_hook = alc269_eeepc_amic_inithook,
 	},
 	[ALC269_ASUS_EEEPC_P901] = {
-		.mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer},
+		.mixers = { alc269_eeepc_mixer },
+		.cap_mixer = alc269_epc_capture_mixer,
 		.init_verbs = { alc269_init_verbs,
 				alc269_eeepc_dmic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc269_dac_nids),
@@ -12418,6 +12653,32 @@
 		.unsol_event = alc269_eeepc_dmic_unsol_event,
 		.init_hook = alc269_eeepc_dmic_inithook,
 	},
+	[ALC269_FUJITSU] = {
+		.mixers = { alc269_fujitsu_mixer, alc269_beep_mixer },
+		.cap_mixer = alc269_epc_capture_mixer,
+		.init_verbs = { alc269_init_verbs,
+				alc269_eeepc_dmic_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc269_dac_nids),
+		.dac_nids = alc269_dac_nids,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc269_modes),
+		.channel_mode = alc269_modes,
+		.input_mux = &alc269_eeepc_dmic_capture_source,
+		.unsol_event = alc269_eeepc_dmic_unsol_event,
+		.init_hook = alc269_eeepc_dmic_inithook,
+	},
+	[ALC269_LIFEBOOK] = {
+		.mixers = { alc269_lifebook_mixer },
+		.init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
+		.num_dacs = ARRAY_SIZE(alc269_dac_nids),
+		.dac_nids = alc269_dac_nids,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc269_modes),
+		.channel_mode = alc269_modes,
+		.input_mux = &alc269_capture_source,
+		.unsol_event = alc269_lifebook_unsol_event,
+		.init_hook = alc269_lifebook_init_hook,
+	},
 };
 
 static int patch_alc269(struct hda_codec *codec)
@@ -12472,6 +12733,8 @@
 	spec->adc_nids = alc269_adc_nids;
 	spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
 	spec->capsrc_nids = alc269_capsrc_nids;
+	if (!spec->cap_mixer)
+		set_capture_mixer(spec);
 
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC269_AUTO)
@@ -12480,6 +12743,7 @@
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc269_loopbacks;
 #endif
+	codec->proc_widget_hook = print_realtek_coef;
 
 	return 0;
 }
@@ -12612,17 +12876,6 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
 
-        /* Capture mixer control */
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.count = 1,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
 	{ } /* end */
 };
 
@@ -12646,17 +12899,6 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
 
-	/* Capture mixer control */
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.count = 1,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
@@ -12674,18 +12916,6 @@
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
 
-        /*Capture mixer control */
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.count = 1,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
-
 	{ } /* end */
 };
 
@@ -12709,17 +12939,6 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
 
-	/* Capture mixer control */
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.count = 1,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
@@ -12751,17 +12970,6 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
 
-	/* Capture mixer control */
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.count = 1,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
@@ -13293,25 +13501,6 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new alc861_capture_mixer[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
-	{ } /* end */
-};
-
 static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
 					      hda_nid_t nid,
 					      int pin_type, int dac_idx)
@@ -13402,18 +13591,17 @@
 	if (spec->autocfg.dig_out_pin)
 		spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		add_mixer(spec, spec->kctls.list);
 
-	spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
+	add_verb(spec, alc861_auto_init_verbs);
 
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
 
 	spec->adc_nids = alc861_adc_nids;
 	spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
-	spec->mixers[spec->num_mixers] = alc861_capture_mixer;
-	spec->num_mixers++;
+	set_capture_mixer(spec);
 
 	store_pin_configs(codec);
 	return 1;
@@ -13644,6 +13832,7 @@
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc861_loopbacks;
 #endif
+	codec->proc_widget_hook = print_realtek_coef;
 
 	return 0;
 }
@@ -13709,11 +13898,6 @@
 	},
 };
 
-#define alc861vd_mux_enum_info alc_mux_enum_info
-#define alc861vd_mux_enum_get alc_mux_enum_get
-/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
-#define alc861vd_mux_enum_put alc882_mux_enum_put
-
 /*
  * 2ch mode
  */
@@ -13759,25 +13943,6 @@
 	{ } /* end */
 };
 
-static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc861vd_mux_enum_info,
-		.get = alc861vd_mux_enum_get,
-		.put = alc861vd_mux_enum_put,
-	},
-	{ } /* end */
-};
-
 /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
  */
@@ -14169,6 +14334,7 @@
 static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
 	[ALC660VD_3ST]		= "3stack-660",
 	[ALC660VD_3ST_DIG]	= "3stack-660-digout",
+	[ALC660VD_ASUS_V1S]	= "asus-v1s",
 	[ALC861VD_3ST]		= "3stack",
 	[ALC861VD_3ST_DIG]	= "3stack-digout",
 	[ALC861VD_6ST_DIG]	= "6stack-digout",
@@ -14183,7 +14349,7 @@
 	SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
 	SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
 	SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
-	SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC861VD_LENOVO),
+	SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
 	SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
 	SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
 	SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
@@ -14290,6 +14456,21 @@
 		.unsol_event = alc861vd_dallas_unsol_event,
 		.init_hook = alc861vd_dallas_automute,
 	},
+	[ALC660VD_ASUS_V1S] = {
+		.mixers = { alc861vd_lenovo_mixer },
+		.init_verbs = { alc861vd_volume_init_verbs,
+				alc861vd_3stack_init_verbs,
+				alc861vd_eapd_verbs,
+				alc861vd_lenovo_unsol_verbs },
+		.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+		.dac_nids = alc660vd_dac_nids,
+		.dig_out_nid = ALC861VD_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+		.channel_mode = alc861vd_3stack_2ch_modes,
+		.input_mux = &alc861vd_capture_source,
+		.unsol_event = alc861vd_lenovo_unsol_event,
+		.init_hook = alc861vd_lenovo_automute,
+	},
 };
 
 /*
@@ -14514,11 +14695,10 @@
 	if (spec->autocfg.dig_out_pin)
 		spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		add_mixer(spec, spec->kctls.list);
 
-	spec->init_verbs[spec->num_init_verbs++]
-		= alc861vd_volume_init_verbs;
+	add_verb(spec, alc861vd_volume_init_verbs);
 
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
@@ -14585,7 +14765,7 @@
 		spec->stream_name_analog = "ALC660-VD Analog";
 		spec->stream_name_digital = "ALC660-VD Digital";
 		/* always turn on EAPD */
-		spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs;
+		add_verb(spec, alc660vd_eapd_verbs);
 	} else {
 		spec->stream_name_analog = "ALC861VD Analog";
 		spec->stream_name_digital = "ALC861VD Digital";
@@ -14600,9 +14780,9 @@
 	spec->adc_nids = alc861vd_adc_nids;
 	spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
 	spec->capsrc_nids = alc861vd_capsrc_nids;
+	spec->is_mix_capture = 1;
 
-	spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
-	spec->num_mixers++;
+	set_capture_mixer(spec);
 
 	spec->vmaster_nid = 0x02;
 
@@ -14614,6 +14794,7 @@
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc861vd_loopbacks;
 #endif
+	codec->proc_widget_hook = print_realtek_coef;
 
 	return 0;
 }
@@ -14689,10 +14870,6 @@
 	},
 };
 
-#define alc662_mux_enum_info alc_mux_enum_info
-#define alc662_mux_enum_get alc_mux_enum_get
-#define alc662_mux_enum_put alc882_mux_enum_put
-
 /*
  * 2ch mode
  */
@@ -15278,25 +15455,6 @@
 	{}
 };
 
-/* capture mixer elements */
-static struct snd_kcontrol_new alc662_capture_mixer[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc662_mux_enum_info,
-		.get = alc662_mux_enum_get,
-		.put = alc662_mux_enum_put,
-	},
-	{ } /* end */
-};
-
 static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
@@ -15868,7 +16026,7 @@
 
 static struct alc_config_preset alc662_presets[] = {
 	[ALC662_3ST_2ch_DIG] = {
-		.mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
+		.mixers = { alc662_3ST_2ch_mixer },
 		.init_verbs = { alc662_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
@@ -15879,8 +16037,7 @@
 		.input_mux = &alc662_capture_source,
 	},
 	[ALC662_3ST_6ch_DIG] = {
-		.mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
-			    alc662_capture_mixer },
+		.mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
 		.init_verbs = { alc662_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
@@ -15892,8 +16049,7 @@
 		.input_mux = &alc662_capture_source,
 	},
 	[ALC662_3ST_6ch] = {
-		.mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
-			    alc662_capture_mixer },
+		.mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
 		.init_verbs = { alc662_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
@@ -15903,8 +16059,7 @@
 		.input_mux = &alc662_capture_source,
 	},
 	[ALC662_5ST_DIG] = {
-		.mixers = { alc662_base_mixer, alc662_chmode_mixer,
-			    alc662_capture_mixer },
+		.mixers = { alc662_base_mixer, alc662_chmode_mixer },
 		.init_verbs = { alc662_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
@@ -15915,7 +16070,7 @@
 		.input_mux = &alc662_capture_source,
 	},
 	[ALC662_LENOVO_101E] = {
-		.mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
+		.mixers = { alc662_lenovo_101e_mixer },
 		.init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
@@ -15926,7 +16081,7 @@
 		.init_hook = alc662_lenovo_101e_all_automute,
 	},
 	[ALC662_ASUS_EEEPC_P701] = {
-		.mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
+		.mixers = { alc662_eeepc_p701_mixer },
 		.init_verbs = { alc662_init_verbs,
 				alc662_eeepc_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -15938,7 +16093,7 @@
 		.init_hook = alc662_eeepc_inithook,
 	},
 	[ALC662_ASUS_EEEPC_EP20] = {
-		.mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
+		.mixers = { alc662_eeepc_ep20_mixer,
 			    alc662_chmode_mixer },
 		.init_verbs = { alc662_init_verbs,
 				alc662_eeepc_ep20_sue_init_verbs },
@@ -15951,7 +16106,7 @@
 		.init_hook = alc662_eeepc_ep20_inithook,
 	},
 	[ALC662_ECS] = {
-		.mixers = { alc662_ecs_mixer, alc662_capture_mixer },
+		.mixers = { alc662_ecs_mixer },
 		.init_verbs = { alc662_init_verbs,
 				alc662_ecs_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -15963,7 +16118,7 @@
 		.init_hook = alc662_eeepc_inithook,
 	},
 	[ALC663_ASUS_M51VA] = {
-		.mixers = { alc663_m51va_mixer, alc662_capture_mixer},
+		.mixers = { alc663_m51va_mixer },
 		.init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
@@ -15975,7 +16130,7 @@
 		.init_hook = alc663_m51va_inithook,
 	},
 	[ALC663_ASUS_G71V] = {
-		.mixers = { alc663_g71v_mixer, alc662_capture_mixer},
+		.mixers = { alc663_g71v_mixer },
 		.init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
@@ -15987,7 +16142,7 @@
 		.init_hook = alc663_g71v_inithook,
 	},
 	[ALC663_ASUS_H13] = {
-		.mixers = { alc663_m51va_mixer, alc662_capture_mixer},
+		.mixers = { alc663_m51va_mixer },
 		.init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
@@ -15998,7 +16153,7 @@
 		.init_hook = alc663_m51va_inithook,
 	},
 	[ALC663_ASUS_G50V] = {
-		.mixers = { alc663_g50v_mixer, alc662_capture_mixer},
+		.mixers = { alc663_g50v_mixer },
 		.init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
@@ -16010,7 +16165,8 @@
 		.init_hook = alc663_g50v_inithook,
 	},
 	[ALC663_ASUS_MODE1] = {
-		.mixers = { alc663_m51va_mixer, alc662_auto_capture_mixer },
+		.mixers = { alc663_m51va_mixer },
+		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 				alc663_21jd_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16024,7 +16180,8 @@
 		.init_hook = alc663_mode1_inithook,
 	},
 	[ALC662_ASUS_MODE2] = {
-		.mixers = { alc662_1bjd_mixer, alc662_auto_capture_mixer },
+		.mixers = { alc662_1bjd_mixer },
+		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 				alc662_1bjd_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16037,7 +16194,8 @@
 		.init_hook = alc662_mode2_inithook,
 	},
 	[ALC663_ASUS_MODE3] = {
-		.mixers = { alc663_two_hp_m1_mixer, alc662_auto_capture_mixer },
+		.mixers = { alc663_two_hp_m1_mixer },
+		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 				alc663_two_hp_amic_m1_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16051,8 +16209,8 @@
 		.init_hook = alc663_mode3_inithook,
 	},
 	[ALC663_ASUS_MODE4] = {
-		.mixers = { alc663_asus_21jd_clfe_mixer,
-				alc662_auto_capture_mixer},
+		.mixers = { alc663_asus_21jd_clfe_mixer },
+		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 				alc663_21jd_amic_init_verbs},
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16066,8 +16224,8 @@
 		.init_hook = alc663_mode4_inithook,
 	},
 	[ALC663_ASUS_MODE5] = {
-		.mixers = { alc663_asus_15jd_clfe_mixer,
-				alc662_auto_capture_mixer },
+		.mixers = { alc663_asus_15jd_clfe_mixer },
+		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 				alc663_15jd_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16081,7 +16239,8 @@
 		.init_hook = alc663_mode5_inithook,
 	},
 	[ALC663_ASUS_MODE6] = {
-		.mixers = { alc663_two_hp_m2_mixer, alc662_auto_capture_mixer },
+		.mixers = { alc663_two_hp_m2_mixer },
+		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 				alc663_two_hp_amic_m2_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
@@ -16342,24 +16501,20 @@
 	if (spec->autocfg.dig_out_pin)
 		spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		add_mixer(spec, spec->kctls.list);
 
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
 
-	spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
+	add_verb(spec, alc662_auto_init_verbs);
 	if (codec->vendor_id == 0x10ec0663)
-		spec->init_verbs[spec->num_init_verbs++] =
-			alc663_auto_init_verbs;
+		add_verb(spec, alc663_auto_init_verbs);
 
 	err = alc_auto_add_mic_boost(codec);
 	if (err < 0)
 		return err;
 
-	spec->mixers[spec->num_mixers] = alc662_capture_mixer;
-	spec->num_mixers++;
-
 	store_pin_configs(codec);
 	return 1;
 }
@@ -16435,6 +16590,10 @@
 	spec->adc_nids = alc662_adc_nids;
 	spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
 	spec->capsrc_nids = alc662_capsrc_nids;
+	spec->is_mix_capture = 1;
+
+	if (!spec->cap_mixer)
+		set_capture_mixer(spec);
 
 	spec->vmaster_nid = 0x02;
 
@@ -16445,6 +16604,7 @@
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc662_loopbacks;
 #endif
+	codec->proc_widget_hook = print_realtek_coef;
 
 	return 0;
 }
@@ -16452,7 +16612,7 @@
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_realtek[] = {
+static struct hda_codec_preset snd_hda_preset_realtek[] = {
 	{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
 	{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
 	{ .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
@@ -16484,3 +16644,26 @@
 	{ .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:10ec*");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek HD-audio codec");
+
+static struct hda_codec_preset_list realtek_list = {
+	.preset = snd_hda_preset_realtek,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_realtek_init(void)
+{
+	return snd_hda_add_codec_preset(&realtek_list);
+}
+
+static void __exit patch_realtek_exit(void)
+{
+	snd_hda_delete_codec_preset(&realtek_list);
+}
+
+module_init(patch_realtek_init)
+module_exit(patch_realtek_exit)
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index 9332b63..43b436c 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -28,7 +28,6 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 
 /* si3054 verbs */
 #define SI3054_VERB_READ_NODE  0x900
@@ -283,7 +282,7 @@
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_si3054[] = {
+static struct hda_codec_preset snd_hda_preset_si3054[] = {
  	{ .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
@@ -301,3 +300,35 @@
 	{}
 };
 
+MODULE_ALIAS("snd-hda-codec-id:163c3055");
+MODULE_ALIAS("snd-hda-codec-id:163c3155");
+MODULE_ALIAS("snd-hda-codec-id:11c13026");
+MODULE_ALIAS("snd-hda-codec-id:11c13055");
+MODULE_ALIAS("snd-hda-codec-id:11c13155");
+MODULE_ALIAS("snd-hda-codec-id:10573055");
+MODULE_ALIAS("snd-hda-codec-id:10573057");
+MODULE_ALIAS("snd-hda-codec-id:10573155");
+MODULE_ALIAS("snd-hda-codec-id:11063288");
+MODULE_ALIAS("snd-hda-codec-id:15433155");
+MODULE_ALIAS("snd-hda-codec-id:18540018");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Si3054 HD-audio modem codec");
+
+static struct hda_codec_preset_list si3054_list = {
+	.preset = snd_hda_preset_si3054,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_si3054_init(void)
+{
+	return snd_hda_add_codec_preset(&si3054_list);
+}
+
+static void __exit patch_si3054_exit(void)
+{
+	snd_hda_delete_codec_preset(&si3054_list);
+}
+
+module_init(patch_si3054_init)
+module_exit(patch_si3054_exit)
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 596ceab..35b83dc 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -30,17 +30,17 @@
 #include <linux/pci.h>
 #include <sound/core.h>
 #include <sound/asoundef.h>
+#include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 #include "hda_beep.h"
 
-#define NUM_CONTROL_ALLOC	32
-
-#define STAC_VREF_EVENT		0x00
-#define STAC_INSERT_EVENT	0x10
-#define STAC_PWR_EVENT		0x20
-#define STAC_HP_EVENT		0x30
+enum {
+	STAC_VREF_EVENT	= 1,
+	STAC_INSERT_EVENT,
+	STAC_PWR_EVENT,
+	STAC_HP_EVENT,
+};
 
 enum {
 	STAC_REF,
@@ -137,6 +137,19 @@
 	STAC_927X_MODELS
 };
 
+struct sigmatel_event {
+	hda_nid_t nid;
+	unsigned char type;
+	unsigned char tag;
+	int data;
+};
+
+struct sigmatel_jack {
+	hda_nid_t nid;
+	int type;
+	struct snd_jack *jack;
+};
+
 struct sigmatel_spec {
 	struct snd_kcontrol_new *mixers[4];
 	unsigned int num_mixers;
@@ -144,8 +157,6 @@
 	int board_config;
 	unsigned int eapd_switch: 1;
 	unsigned int surr_switch: 1;
-	unsigned int line_switch: 1;
-	unsigned int mic_switch: 1;
 	unsigned int alt_switch: 1;
 	unsigned int hp_detect: 1;
 	unsigned int spdif_mute: 1;
@@ -170,12 +181,20 @@
 	hda_nid_t *pwr_nids;
 	hda_nid_t *dac_list;
 
+	/* jack detection */
+	struct snd_array jacks;
+
+	/* events */
+	struct snd_array events;
+
 	/* playback */
 	struct hda_input_mux *mono_mux;
 	struct hda_input_mux *amp_mux;
 	unsigned int cur_mmux;
 	struct hda_multi_out multiout;
 	hda_nid_t dac_nids[5];
+	hda_nid_t hp_dacs[5];
+	hda_nid_t speaker_dacs[5];
 
 	/* capture */
 	hda_nid_t *adc_nids;
@@ -199,7 +218,6 @@
 	hda_nid_t *pin_nids;
 	unsigned int num_pins;
 	unsigned int *pin_configs;
-	unsigned int *bios_pin_configs;
 
 	/* codec specific stuff */
 	struct hda_verb *init;
@@ -220,15 +238,16 @@
 	/* i/o switches */
 	unsigned int io_switch[2];
 	unsigned int clfe_swap;
-	unsigned int hp_switch; /* NID of HP as line-out */
+	hda_nid_t line_switch;	/* shared line-in for input and output */
+	hda_nid_t mic_switch;	/* shared mic-in for input and output */
+	hda_nid_t hp_switch; /* NID of HP as line-out */
 	unsigned int aloopback;
 
 	struct hda_pcm pcm_rec[2];	/* PCM information */
 
 	/* dynamic controls and input_mux */
 	struct auto_pin_cfg autocfg;
-	unsigned int num_kctl_alloc, num_kctl_used;
-	struct snd_kcontrol_new *kctl_alloc;
+	struct snd_array kctls;
 	struct hda_input_mux private_dimux;
 	struct hda_input_mux private_imux;
 	struct hda_input_mux private_smux;
@@ -272,9 +291,6 @@
 };
 
 #define STAC92HD73_DAC_COUNT 5
-static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
-	0x15, 0x16, 0x17, 0x18, 0x19,
-};
 
 static hda_nid_t stac92hd73xx_mux_nids[4] = {
 	0x28, 0x29, 0x2a, 0x2b,
@@ -293,11 +309,7 @@
 	0x11, 0x12, 0
 };
 
-#define STAC92HD81_DAC_COUNT 2
 #define STAC92HD83_DAC_COUNT 3
-static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
-	0x13, 0x14, 0x22,
-};
 
 static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
 	0x17, 0x18,
@@ -339,10 +351,6 @@
 	0x24, 0x25,
 };
 
-static hda_nid_t stac92hd71bxx_dac_nids[1] = {
-	0x10, /*0x11, */
-};
-
 #define STAC92HD71BXX_NUM_DMICS	2
 static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
 	0x18, 0x19, 0
@@ -574,12 +582,12 @@
 		else
 			nid = codec->slave_dig_outs[smux_idx - 1];
 		if (spec->cur_smux[smux_idx] == smux->num_items - 1)
-			val = AMP_OUT_MUTE;
+			val = HDA_AMP_MUTE;
 		else
-			val = AMP_OUT_UNMUTE;
+			val = 0;
 		/* un/mute SPDIF out */
-		snd_hda_codec_write_cache(codec, nid, 0,
-			AC_VERB_SET_AMP_GAIN_MUTE, val);
+		snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, val);
 	}
 	return 0;
 }
@@ -744,10 +752,6 @@
 static struct hda_verb stac92hd73xx_6ch_core_init[] = {
 	/* set master volume and direct control */
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-	/* setup audio connections */
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{ 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
 	/* setup adcs to point to mixer */
 	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
 	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -766,10 +770,6 @@
 	/* set master volume to max value without distortion
 	 * and direct control */
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
-	/* setup audio connections */
-	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02},
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01},
 	/* setup adcs to point to mixer */
 	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
 	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -783,10 +783,6 @@
 
 static struct hda_verb dell_m6_core_init[] = {
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-	/* setup audio connections */
-	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
 	/* setup adcs to point to mixer */
 	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
 	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -801,13 +797,6 @@
 static struct hda_verb stac92hd73xx_8ch_core_init[] = {
 	/* set master volume and direct control */
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-	/* setup audio connections */
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
-	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{ 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
-	/* connect hp ports to dac3 */
-	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
-	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
 	/* setup adcs to point to mixer */
 	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
 	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -825,15 +814,8 @@
 static struct hda_verb stac92hd73xx_10ch_core_init[] = {
 	/* set master volume and direct control */
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-	/* setup audio connections */
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
-	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
-	{ 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
 	/* dac3 is connected to import3 mux */
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
-	/* connect hp ports to dac4 */
-	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
-	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
 	/* setup adcs to point to mixer */
 	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
 	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -859,17 +841,17 @@
 
 	/* power state controls amps */
 	{ 0x01, AC_VERB_SET_EAPD, 1 << 2},
+	{}
 };
 
 static struct hda_verb stac92hd71bxx_core_init[] = {
 	/* set master volume and direct control */
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-	/* connect headphone jack to dac1 */
-	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
 	/* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
 	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{}
 };
 
 #define HD_DISABLE_PORTF 2
@@ -884,8 +866,6 @@
 
 	/* set master volume and direct control */
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-	/* connect headphone jack to dac1 */
-	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
 	/* unmute right and left channels for nodes 0x0a, 0xd */
 	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1085,21 +1065,21 @@
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
 
-	HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT),
 
-	HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x4, HDA_INPUT),
+	HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x4, HDA_INPUT),
 
-	HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x0, HDA_INPUT),
 
-	HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
-	HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x2, HDA_INPUT),
+	HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x2, HDA_INPUT),
 
 	/*
-	HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x1, HDA_INPUT),
 	*/
 	{ } /* end */
 };
@@ -1238,9 +1218,14 @@
 	NULL
 };
 
+static void stac92xx_free_kctls(struct hda_codec *codec);
+static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type);
+
 static int stac92xx_build_controls(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	hda_nid_t nid;
 	int err;
 	int i;
 
@@ -1255,7 +1240,7 @@
 	}
 	if (spec->num_dmuxes > 0) {
 		stac_dmux_mixer.count = spec->num_dmuxes;
-		err = snd_ctl_add(codec->bus->card,
+		err = snd_hda_ctl_add(codec,
 				  snd_ctl_new1(&stac_dmux_mixer, codec));
 		if (err < 0)
 			return err;
@@ -1271,7 +1256,7 @@
 			spec->spdif_mute = 1;
 		}
 		stac_smux_mixer.count = spec->num_smuxes;
-		err = snd_ctl_add(codec->bus->card,
+		err = snd_hda_ctl_add(codec,
 				  snd_ctl_new1(&stac_smux_mixer, codec));
 		if (err < 0)
 			return err;
@@ -1310,6 +1295,37 @@
 			return err;
 	}
 
+	stac92xx_free_kctls(codec); /* no longer needed */
+
+	/* create jack input elements */
+	if (spec->hp_detect) {
+		for (i = 0; i < cfg->hp_outs; i++) {
+			int type = SND_JACK_HEADPHONE;
+			nid = cfg->hp_pins[i];
+			/* jack detection */
+			if (cfg->hp_outs == i)
+				type |= SND_JACK_LINEOUT;
+			err = stac92xx_add_jack(codec, nid, type);
+			if (err < 0)
+				return err;
+		}
+	}
+	for (i = 0; i < cfg->line_outs; i++) {
+		err = stac92xx_add_jack(codec, cfg->line_out_pins[i],
+					SND_JACK_LINEOUT);
+		if (err < 0)
+			return err;
+	}
+	for (i = 0; i < AUTO_PIN_LAST; i++) {
+		nid = cfg->input_pins[i];
+		if (nid) {
+			err = stac92xx_add_jack(codec, nid,
+						SND_JACK_MICROPHONE);
+			if (err < 0)
+				return err;
+		}
+	}
+
 	return 0;	
 }
 
@@ -1667,6 +1683,7 @@
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_92HD71BXX_REF),
+	{} /* terminator */
 };
 
 static unsigned int ref92hd71bxx_pin_configs[11] = {
@@ -1717,6 +1734,8 @@
 		      "HP dv5", STAC_HP_M4),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
 		      "HP dv7", STAC_HP_M4),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc,
+		      "HP dv7", STAC_HP_M4),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
 				"unknown HP", STAC_HP_M4),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
@@ -2200,12 +2219,11 @@
 	int i;
 	struct sigmatel_spec *spec = codec->spec;
 	
-	if (! spec->bios_pin_configs) {
-		spec->bios_pin_configs = kcalloc(spec->num_pins,
-		                                 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
-		if (! spec->bios_pin_configs)
-			return -ENOMEM;
-	}
+	kfree(spec->pin_configs);
+	spec->pin_configs = kcalloc(spec->num_pins, sizeof(*spec->pin_configs),
+				    GFP_KERNEL);
+	if (!spec->pin_configs)
+		return -ENOMEM;
 	
 	for (i = 0; i < spec->num_pins; i++) {
 		hda_nid_t nid = spec->pin_nids[i];
@@ -2215,7 +2233,7 @@
 			AC_VERB_GET_CONFIG_DEFAULT, 0x00);	
 		snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
 					nid, pin_cfg);
-		spec->bios_pin_configs[i] = pin_cfg;
+		spec->pin_configs[i] = pin_cfg;
 	}
 	
 	return 0;
@@ -2257,6 +2275,39 @@
 					spec->pin_configs[i]);
 }
 
+static int stac_save_pin_cfgs(struct hda_codec *codec, unsigned int *pins)
+{
+	struct sigmatel_spec *spec = codec->spec;
+
+	if (!pins)
+		return stac92xx_save_bios_config_regs(codec);
+
+	kfree(spec->pin_configs);
+	spec->pin_configs = kmemdup(pins,
+				    spec->num_pins * sizeof(*pins),
+				    GFP_KERNEL);
+	if (!spec->pin_configs)
+		return -ENOMEM;
+
+	stac92xx_set_config_regs(codec);
+	return 0;
+}
+
+static void stac_change_pin_config(struct hda_codec *codec, hda_nid_t nid,
+				   unsigned int cfg)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	int i;
+
+	for (i = 0; i < spec->num_pins; i++) {
+		if (spec->pin_nids[i] == nid) {
+			spec->pin_configs[i] = cfg;
+			stac92xx_set_config_reg(codec, nid, cfg);
+			break;
+		}
+	}
+}
+
 /*
  * Analog playback callbacks
  */
@@ -2334,7 +2385,7 @@
 
 	if (spec->powerdown_adcs) {
 		msleep(40);
-		snd_hda_codec_write_cache(codec, nid, 0,
+		snd_hda_codec_write(codec, nid, 0,
 			AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 	}
 	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
@@ -2350,7 +2401,7 @@
 
 	snd_hda_codec_cleanup_stream(codec, nid);
 	if (spec->powerdown_adcs)
-		snd_hda_codec_write_cache(codec, nid, 0,
+		snd_hda_codec_write(codec, nid, 0,
 			AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 	return 0;
 }
@@ -2482,6 +2533,9 @@
 	return 0;
 }
 
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
+				   unsigned char type);
+
 static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_value *ucontrol)
 {
@@ -2494,7 +2548,7 @@
 	/* check to be sure that the ports are upto date with
 	 * switch changes
 	 */
-	codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+	stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
 
 	return 1;
 }
@@ -2534,7 +2588,7 @@
 	 * appropriately according to the pin direction
 	 */
 	if (spec->hp_detect)
-		codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+		stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
 
         return 1;
 }
@@ -2629,28 +2683,16 @@
 {
 	struct snd_kcontrol_new *knew;
 
-	if (spec->num_kctl_used >= spec->num_kctl_alloc) {
-		int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
-
-		knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
-		if (! knew)
-			return -ENOMEM;
-		if (spec->kctl_alloc) {
-			memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
-			kfree(spec->kctl_alloc);
-		}
-		spec->kctl_alloc = knew;
-		spec->num_kctl_alloc = num;
-	}
-
-	knew = &spec->kctl_alloc[spec->num_kctl_used];
+	snd_array_init(&spec->kctls, sizeof(*knew), 32);
+	knew = snd_array_new(&spec->kctls);
+	if (!knew)
+		return -ENOMEM;
 	*knew = *ktemp;
 	knew->index = idx;
 	knew->name = kstrdup(name, GFP_KERNEL);
 	if (!knew->name)
 		return -ENOMEM;
 	knew->private_value = val;
-	spec->num_kctl_used++;
 	return 0;
 }
 
@@ -2671,69 +2713,52 @@
 	return stac92xx_add_control_idx(spec, type, 0, name, val);
 }
 
-/* flag inputs as additional dynamic lineouts */
-static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
+/* check whether the line-input can be used as line-out */
+static hda_nid_t check_line_out_switch(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
-	unsigned int wcaps, wtype;
-	int i, num_dacs = 0;
-	
-	/* use the wcaps cache to count all DACs available for line-outs */
-	for (i = 0; i < codec->num_nodes; i++) {
-		wcaps = codec->wcaps[i];
-		wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	hda_nid_t nid;
+	unsigned int pincap;
 
-		if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
-			num_dacs++;
-	}
-
-	snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
-	
-	switch (cfg->line_outs) {
-	case 3:
-		/* add line-in as side */
-		if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
-			cfg->line_out_pins[cfg->line_outs] =
-				cfg->input_pins[AUTO_PIN_LINE];
-			spec->line_switch = 1;
-			cfg->line_outs++;
-		}
-		break;
-	case 2:
-		/* add line-in as clfe and mic as side */
-		if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
-			cfg->line_out_pins[cfg->line_outs] =
-				cfg->input_pins[AUTO_PIN_LINE];
-			spec->line_switch = 1;
-			cfg->line_outs++;
-		}
-		if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
-			cfg->line_out_pins[cfg->line_outs] =
-				cfg->input_pins[AUTO_PIN_MIC];
-			spec->mic_switch = 1;
-			cfg->line_outs++;
-		}
-		break;
-	case 1:
-		/* add line-in as surr and mic as clfe */
-		if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
-			cfg->line_out_pins[cfg->line_outs] =
-				cfg->input_pins[AUTO_PIN_LINE];
-			spec->line_switch = 1;
-			cfg->line_outs++;
-		}
-		if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
-			cfg->line_out_pins[cfg->line_outs] =
-				cfg->input_pins[AUTO_PIN_MIC];
-			spec->mic_switch = 1;
-			cfg->line_outs++;
-		}
-		break;
-	}
-
+	if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
+		return 0;
+	nid = cfg->input_pins[AUTO_PIN_LINE];
+	pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+	if (pincap & AC_PINCAP_OUT)
+		return nid;
 	return 0;
 }
 
+/* check whether the mic-input can be used as line-out */
+static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	unsigned int def_conf, pincap;
+	unsigned int mic_pin;
+
+	if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
+		return 0;
+	mic_pin = AUTO_PIN_MIC;
+	for (;;) {
+		hda_nid_t nid = cfg->input_pins[mic_pin];
+		def_conf = snd_hda_codec_read(codec, nid, 0,
+					      AC_VERB_GET_CONFIG_DEFAULT, 0);
+		/* some laptops have an internal analog microphone
+		 * which can't be used as a output */
+		if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
+			pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+			if (pincap & AC_PINCAP_OUT)
+				return nid;
+		}
+		if (mic_pin == AUTO_PIN_MIC)
+			mic_pin = AUTO_PIN_FRONT_MIC;
+		else
+			break;
+	}
+	return 0;
+}
 
 static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
 {
@@ -2747,6 +2772,52 @@
 	return 0;
 }
 
+static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
+{
+	int i;
+	if (is_in_dac_nids(spec, nid))
+		return 1;
+	for (i = 0; i < spec->autocfg.hp_outs; i++)
+		if (spec->hp_dacs[i] == nid)
+			return 1;
+	for (i = 0; i < spec->autocfg.speaker_outs; i++)
+		if (spec->speaker_dacs[i] == nid)
+			return 1;
+	return 0;
+}
+
+static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	int j, conn_len;
+	hda_nid_t conn[HDA_MAX_CONNECTIONS];
+	unsigned int wcaps, wtype;
+
+	conn_len = snd_hda_get_connections(codec, nid, conn,
+					   HDA_MAX_CONNECTIONS);
+	for (j = 0; j < conn_len; j++) {
+		wcaps = snd_hda_param_read(codec, conn[j],
+					   AC_PAR_AUDIO_WIDGET_CAP);
+		wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+		/* we check only analog outputs */
+		if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
+			continue;
+		/* if this route has a free DAC, assign it */
+		if (!check_all_dac_nids(spec, conn[j])) {
+			if (conn_len > 1) {
+				/* select this DAC in the pin's input mux */
+				snd_hda_codec_write_cache(codec, nid, 0,
+						  AC_VERB_SET_CONNECT_SEL, j);
+			}
+			return conn[j];
+		}
+	}
+	return 0;
+}
+
+static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
+static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
+
 /*
  * Fill in the dac_nids table from the parsed pin configuration
  * This function only works when every pin in line_out_pins[]
@@ -2754,31 +2825,17 @@
  * codecs are not connected directly to a DAC, such as the 9200
  * and 9202/925x. For those, dac_nids[] must be hard-coded.
  */
-static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
-				       struct auto_pin_cfg *cfg)
+static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
-	int i, j, conn_len = 0; 
-	hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
-	unsigned int wcaps, wtype;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i;
+	hda_nid_t nid, dac;
 	
 	for (i = 0; i < cfg->line_outs; i++) {
 		nid = cfg->line_out_pins[i];
-		conn_len = snd_hda_get_connections(codec, nid, conn,
-						   HDA_MAX_CONNECTIONS);
-		for (j = 0; j < conn_len; j++) {
-			wcaps = snd_hda_param_read(codec, conn[j],
-						   AC_PAR_AUDIO_WIDGET_CAP);
-			wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-			if (wtype != AC_WID_AUD_OUT ||
-			    (wcaps & AC_WCAP_DIGITAL))
-				continue;
-			/* conn[j] is a DAC routed to this line-out */
-			if (!is_in_dac_nids(spec, conn[j]))
-				break;
-		}
-
-		if (j == conn_len) {
+		dac = get_unassigned_dac(codec, nid);
+		if (!dac) {
 			if (spec->multiout.num_dacs > 0) {
 				/* we have already working output pins,
 				 * so let's drop the broken ones again
@@ -2792,24 +2849,64 @@
 				   __func__, nid);
 			return -ENODEV;
 		}
+		add_spec_dacs(spec, dac);
+	}
 
-		spec->multiout.dac_nids[i] = conn[j];
-		spec->multiout.num_dacs++;
-		if (conn_len > 1) {
-			/* select this DAC in the pin's input mux */
-			snd_hda_codec_write_cache(codec, nid, 0,
-						  AC_VERB_SET_CONNECT_SEL, j);
-
+	/* add line-in as output */
+	nid = check_line_out_switch(codec);
+	if (nid) {
+		dac = get_unassigned_dac(codec, nid);
+		if (dac) {
+			snd_printdd("STAC: Add line-in 0x%x as output %d\n",
+				    nid, cfg->line_outs);
+			cfg->line_out_pins[cfg->line_outs] = nid;
+			cfg->line_outs++;
+			spec->line_switch = nid;
+			add_spec_dacs(spec, dac);
+		}
+	}
+	/* add mic as output */
+	nid = check_mic_out_switch(codec);
+	if (nid) {
+		dac = get_unassigned_dac(codec, nid);
+		if (dac) {
+			snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
+				    nid, cfg->line_outs);
+			cfg->line_out_pins[cfg->line_outs] = nid;
+			cfg->line_outs++;
+			spec->mic_switch = nid;
+			add_spec_dacs(spec, dac);
 		}
 	}
 
-	snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+	for (i = 0; i < cfg->hp_outs; i++) {
+		nid = cfg->hp_pins[i];
+		dac = get_unassigned_dac(codec, nid);
+		if (dac) {
+			if (!spec->multiout.hp_nid)
+				spec->multiout.hp_nid = dac;
+			else
+				add_spec_extra_dacs(spec, dac);
+		}
+		spec->hp_dacs[i] = dac;
+	}
+
+	for (i = 0; i < cfg->speaker_outs; i++) {
+		nid = cfg->speaker_pins[i];
+		dac = get_unassigned_dac(codec, nid);
+		if (dac)
+			add_spec_extra_dacs(spec, dac);
+		spec->speaker_dacs[i] = dac;
+	}
+
+	snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
 		   spec->multiout.num_dacs,
 		   spec->multiout.dac_nids[0],
 		   spec->multiout.dac_nids[1],
 		   spec->multiout.dac_nids[2],
 		   spec->multiout.dac_nids[3],
 		   spec->multiout.dac_nids[4]);
+
 	return 0;
 }
 
@@ -2834,9 +2931,7 @@
 
 static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
 {
-	if (!spec->multiout.hp_nid)
-		spec->multiout.hp_nid = nid;
-	else if (spec->multiout.num_dacs > 4) {
+	if (spec->multiout.num_dacs > 4) {
 		printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
 		return 1;
 	} else {
@@ -2846,35 +2941,47 @@
 	return 0;
 }
 
-static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
+static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
 {
-	if (is_in_dac_nids(spec, nid))
-		return 1;
+	int i;
+	for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) {
+		if (!spec->multiout.extra_out_nid[i]) {
+			spec->multiout.extra_out_nid[i] = nid;
+			return 0;
+		}
+	}
+	printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid);
+	return 1;
+}
+
+static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid)
+{
+	int i;
+
+	if (spec->autocfg.line_outs != 1)
+		return 0;
 	if (spec->multiout.hp_nid == nid)
-		return 1;
-	return 0;
+		return 0;
+	for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++)
+		if (spec->multiout.extra_out_nid[i] == nid)
+			return 0;
+	return 1;
 }
 
 /* add playback controls from the parsed DAC table */
 static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
 					       const struct auto_pin_cfg *cfg)
 {
+	struct sigmatel_spec *spec = codec->spec;
 	static const char *chname[4] = {
 		"Front", "Surround", NULL /*CLFE*/, "Side"
 	};
 	hda_nid_t nid = 0;
 	int i, err;
+	unsigned int wid_caps;
 
-	struct sigmatel_spec *spec = codec->spec;
-	unsigned int wid_caps, pincap;
-
-
-	for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
-		if (!spec->multiout.dac_nids[i])
-			continue;
-
+	for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) {
 		nid = spec->multiout.dac_nids[i];
-
 		if (i == 2) {
 			/* Center/LFE */
 			err = create_controls(spec, "Center", nid, 1);
@@ -2896,16 +3003,24 @@
 			}
 
 		} else {
-			err = create_controls(spec, chname[i], nid, 3);
+			const char *name = chname[i];
+			/* if it's a single DAC, assign a better name */
+			if (!i && is_unique_dac(spec, nid)) {
+				switch (cfg->line_out_type) {
+				case AUTO_PIN_HP_OUT:
+					name = "Headphone";
+					break;
+				case AUTO_PIN_SPEAKER_OUT:
+					name = "Speaker";
+					break;
+				}
+			}
+			err = create_controls(spec, name, nid, 3);
 			if (err < 0)
 				return err;
 		}
 	}
 
-	if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
-	    cfg->hp_outs == 1 && !spec->multiout.hp_nid)
-		spec->multiout.hp_nid = nid;
-
 	if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
 		err = stac92xx_add_control(spec,
 			STAC_CTL_WIDGET_HP_SWITCH,
@@ -2916,45 +3031,19 @@
 	}
 
 	if (spec->line_switch) {
-		nid = cfg->input_pins[AUTO_PIN_LINE];
-		pincap = snd_hda_param_read(codec, nid,
-						AC_PAR_PIN_CAP);
-		if (pincap & AC_PINCAP_OUT) {
-			err = stac92xx_add_control(spec,
-				STAC_CTL_WIDGET_IO_SWITCH,
-				"Line In as Output Switch", nid << 8);
-			if (err < 0)
-				return err;
-		}
+		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) {
-		unsigned int def_conf;
-		unsigned int mic_pin = AUTO_PIN_MIC;
-again:
-		nid = cfg->input_pins[mic_pin];
-		def_conf = snd_hda_codec_read(codec, nid, 0,
-						AC_VERB_GET_CONFIG_DEFAULT, 0);
-		/* some laptops have an internal analog microphone
-		 * which can't be used as a output */
-		if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
-			pincap = snd_hda_param_read(codec, nid,
-							AC_PAR_PIN_CAP);
-			if (pincap & AC_PINCAP_OUT) {
-				err = stac92xx_add_control(spec,
-					STAC_CTL_WIDGET_IO_SWITCH,
-					"Mic as Output Switch", (nid << 8) | 1);
-				nid = snd_hda_codec_read(codec, nid, 0,
-					 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-				if (!check_in_dac_nids(spec, nid))
-					add_spec_dacs(spec, nid);
-				if (err < 0)
-					return err;
-			}
-		} else if (mic_pin == AUTO_PIN_MIC) {
-			mic_pin = AUTO_PIN_FRONT_MIC;
-			goto again;
-		}
+		err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
+					   "Mic as Output Switch",
+					   (spec->mic_switch << 8) | 1);
+		if (err < 0)
+			return err;
 	}
 
 	return 0;
@@ -2966,55 +3055,39 @@
 {
 	struct sigmatel_spec *spec = codec->spec;
 	hda_nid_t nid;
-	int i, old_num_dacs, err;
+	int i, err, nums;
 
-	old_num_dacs = spec->multiout.num_dacs;
+	nums = 0;
 	for (i = 0; i < cfg->hp_outs; i++) {
+		static const char *pfxs[] = {
+			"Headphone", "Headphone2", "Headphone3",
+		};
 		unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
 		if (wid_caps & AC_WCAP_UNSOL_CAP)
 			spec->hp_detect = 1;
-		nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
-					 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-		if (check_in_dac_nids(spec, nid))
-			nid = 0;
-		if (! nid)
+		if (nums >= ARRAY_SIZE(pfxs))
 			continue;
-		add_spec_dacs(spec, nid);
+		nid = spec->hp_dacs[i];
+		if (!nid)
+			continue;
+		err = create_controls(spec, pfxs[nums++], nid, 3);
+		if (err < 0)
+			return err;
 	}
+	nums = 0;
 	for (i = 0; i < cfg->speaker_outs; i++) {
-		nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
-					 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-		if (check_in_dac_nids(spec, nid))
-			nid = 0;
-		if (! nid)
-			continue;
-		add_spec_dacs(spec, nid);
-	}
-	for (i = 0; i < cfg->line_outs; i++) {
-		nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
-					AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-		if (check_in_dac_nids(spec, nid))
-			nid = 0;
-		if (! nid)
-			continue;
-		add_spec_dacs(spec, nid);
-	}
-	for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
 		static const char *pfxs[] = {
 			"Speaker", "External Speaker", "Speaker2",
 		};
-		err = create_controls(spec, pfxs[i - old_num_dacs],
-				      spec->multiout.dac_nids[i], 3);
+		if (nums >= ARRAY_SIZE(pfxs))
+			continue;
+		nid = spec->speaker_dacs[i];
+		if (!nid)
+			continue;
+		err = create_controls(spec, pfxs[nums++], nid, 3);
 		if (err < 0)
 			return err;
 	}
-	if (spec->multiout.hp_nid) {
-		err = create_controls(spec, "Headphone",
-				      spec->multiout.hp_nid, 3);
-		if (err < 0)
-			return err;
-	}
-
 	return 0;
 }
 
@@ -3352,7 +3425,6 @@
 {
 	struct sigmatel_spec *spec = codec->spec;
 	int err;
-	int hp_speaker_swap = 0;
 
 	if ((err = snd_hda_parse_pin_def_config(codec,
 						&spec->autocfg,
@@ -3370,13 +3442,15 @@
 		 * speaker_outs so that the following routines can handle
 		 * HP pins as primary outputs.
 		 */
+		snd_printdd("stac92xx: Enabling multi-HPs workaround\n");
 		memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
 		       sizeof(spec->autocfg.line_out_pins));
 		spec->autocfg.speaker_outs = spec->autocfg.line_outs;
 		memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
 		       sizeof(spec->autocfg.hp_pins));
 		spec->autocfg.line_outs = spec->autocfg.hp_outs;
-		hp_speaker_swap = 1;
+		spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
+		spec->autocfg.hp_outs = 0;
 	}
 	if (spec->autocfg.mono_out_pin) {
 		int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
@@ -3428,11 +3502,11 @@
 					 AC_PINCTL_OUT_EN);
 	}
 
-	if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
-		return err;
-	if (spec->multiout.num_dacs == 0)
-		if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
+	if (!spec->multiout.num_dacs) {
+		err = stac92xx_auto_fill_dac_nids(codec);
+		if (err < 0)
 			return err;
+	}
 
 	err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
 
@@ -3470,19 +3544,6 @@
 	}
 #endif
 
-	if (hp_speaker_swap == 1) {
-		/* Restore the hp_outs and line_outs */
-		memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
-		       sizeof(spec->autocfg.line_out_pins));
-		spec->autocfg.hp_outs = spec->autocfg.line_outs;
-		memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
-		       sizeof(spec->autocfg.speaker_pins));
-		spec->autocfg.line_outs = spec->autocfg.speaker_outs;
-		memset(spec->autocfg.speaker_pins, 0,
-		       sizeof(spec->autocfg.speaker_pins));
-		spec->autocfg.speaker_outs = 0;
-	}
-
 	err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
 
 	if (err < 0)
@@ -3527,11 +3588,12 @@
 	if (dig_in && spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = dig_in;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->input_mux = &spec->private_imux;
-	spec->dinput_mux = &spec->private_dimux;
+	if (!spec->dinput_mux)
+		spec->dinput_mux = &spec->private_dimux;
 	spec->sinput_mux = &spec->private_smux;
 	spec->mono_mux = &spec->private_mono_mux;
 	spec->amp_mux = &spec->private_amp_mux;
@@ -3635,8 +3697,8 @@
 	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = 0x04;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->input_mux = &spec->private_imux;
 	spec->dinput_mux = &spec->private_dimux;
@@ -3680,13 +3742,101 @@
 			   AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
 }
 
-static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
-			      unsigned int event)
+static int stac92xx_add_jack(struct hda_codec *codec,
+		hda_nid_t nid, int type)
 {
-	if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
-		snd_hda_codec_write_cache(codec, nid, 0,
-					  AC_VERB_SET_UNSOLICITED_ENABLE,
-					  (AC_USRSP_EN | event));
+#ifdef CONFIG_SND_JACK
+	struct sigmatel_spec *spec = codec->spec;
+	struct sigmatel_jack *jack;
+	int def_conf = snd_hda_codec_read(codec, nid,
+			0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+	int connectivity = get_defcfg_connect(def_conf);
+	char name[32];
+
+	if (connectivity && connectivity != AC_JACK_PORT_FIXED)
+		return 0;
+
+	snd_array_init(&spec->jacks, sizeof(*jack), 32);
+	jack = snd_array_new(&spec->jacks);
+	if (!jack)
+		return -ENOMEM;
+	jack->nid = nid;
+	jack->type = type;
+
+	sprintf(name, "%s at %s %s Jack",
+		snd_hda_get_jack_type(def_conf),
+		snd_hda_get_jack_connectivity(def_conf),
+		snd_hda_get_jack_location(def_conf));
+
+	return snd_jack_new(codec->bus->card, name, type, &jack->jack);
+#else
+	return 0;
+#endif
+}
+
+static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
+			  unsigned char type, int data)
+{
+	struct sigmatel_event *event;
+
+	snd_array_init(&spec->events, sizeof(*event), 32);
+	event = snd_array_new(&spec->events);
+	if (!event)
+		return -ENOMEM;
+	event->nid = nid;
+	event->type = type;
+	event->tag = spec->events.used;
+	event->data = data;
+
+	return event->tag;
+}
+
+static struct sigmatel_event *stac_get_event(struct hda_codec *codec,
+					     hda_nid_t nid, unsigned char type)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct sigmatel_event *event = spec->events.list;
+	int i;
+
+	for (i = 0; i < spec->events.used; i++, event++) {
+		if (event->nid == nid && event->type == type)
+			return event;
+	}
+	return NULL;
+}
+
+static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
+						      unsigned char tag)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct sigmatel_event *event = spec->events.list;
+	int i;
+
+	for (i = 0; i < spec->events.used; i++, event++) {
+		if (event->tag == tag)
+			return event;
+	}
+	return NULL;
+}
+
+static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
+			      unsigned int type)
+{
+	struct sigmatel_event *event;
+	int tag;
+
+	if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
+		return;
+	event = stac_get_event(codec, nid, type);
+	if (event)
+		tag = event->tag;
+	else
+		tag = stac_add_event(codec->spec, nid, type, 0);
+	if (tag < 0)
+		return;
+	snd_hda_codec_write_cache(codec, nid, 0,
+				  AC_VERB_SET_UNSOLICITED_ENABLE,
+				  AC_USRSP_EN | tag);
 }
 
 static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
@@ -3706,9 +3856,8 @@
 	/* power down inactive DACs */
 	hda_nid_t *dac;
 	for (dac = spec->dac_list; *dac; dac++)
-		if (!is_in_dac_nids(spec, *dac) &&
-			spec->multiout.hp_nid != *dac)
-			snd_hda_codec_write_cache(codec, *dac, 0,
+		if (!check_all_dac_nids(spec, *dac))
+			snd_hda_codec_write(codec, *dac, 0,
 					AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 }
 
@@ -3727,7 +3876,7 @@
 	/* power down adcs initially */
 	if (spec->powerdown_adcs)
 		for (i = 0; i < spec->num_adcs; i++)
-			snd_hda_codec_write_cache(codec,
+			snd_hda_codec_write(codec,
 				spec->adc_nids[i], 0,
 				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 
@@ -3743,37 +3892,51 @@
 	/* set up pins */
 	if (spec->hp_detect) {
 		/* Enable unsolicited responses on the HP widget */
-		for (i = 0; i < cfg->hp_outs; i++)
-			enable_pin_detect(codec, cfg->hp_pins[i],
-					  STAC_HP_EVENT);
+		for (i = 0; i < cfg->hp_outs; i++) {
+			hda_nid_t nid = cfg->hp_pins[i];
+			enable_pin_detect(codec, nid, STAC_HP_EVENT);
+		}
 		/* force to enable the first line-out; the others are set up
 		 * in unsol_event
 		 */
 		stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
-					 AC_PINCTL_OUT_EN);
-		stac92xx_auto_init_hp_out(codec);
+				AC_PINCTL_OUT_EN);
 		/* fake event to set up pins */
-		codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+		stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
+				       STAC_HP_EVENT);
 	} else {
 		stac92xx_auto_init_multi_out(codec);
 		stac92xx_auto_init_hp_out(codec);
+		for (i = 0; i < cfg->hp_outs; i++)
+			stac_toggle_power_map(codec, cfg->hp_pins[i], 1);
 	}
 	for (i = 0; i < AUTO_PIN_LAST; i++) {
 		hda_nid_t nid = cfg->input_pins[i];
 		if (nid) {
-			unsigned int pinctl;
+			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 |= AC_PINCTL_IN_EN;
+				stac92xx_auto_set_pinctl(codec, nid, pinctl);
 			} else {
 				pinctl = snd_hda_codec_read(codec, nid, 0,
 					AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 				/* if PINCTL already set then skip */
-				if (pinctl & AC_PINCTL_IN_EN)
-					continue;
+				if (!(pinctl & AC_PINCTL_IN_EN)) {
+					pinctl |= AC_PINCTL_IN_EN;
+					stac92xx_auto_set_pinctl(codec, nid,
+								 pinctl);
+				}
 			}
-			pinctl |= AC_PINCTL_IN_EN;
-			stac92xx_auto_set_pinctl(codec, nid, pinctl);
+			conf = snd_hda_codec_read(codec, nid, 0,
+					      AC_VERB_GET_CONFIG_DEFAULT, 0);
+			if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
+				enable_pin_detect(codec, nid,
+						  STAC_INSERT_EVENT);
+				stac_issue_unsol_event(codec, nid,
+						       STAC_INSERT_EVENT);
+			}
 		}
 	}
 	for (i = 0; i < spec->num_dmics; i++)
@@ -3788,9 +3951,14 @@
 	for (i = 0; i < spec->num_pwrs; i++)  {
 		hda_nid_t nid = spec->pwr_nids[i];
 		int pinctl, def_conf;
-		int event = STAC_PWR_EVENT;
 
-		if (is_nid_hp_pin(cfg, nid) && spec->hp_detect)
+		/* power on when no jack detection is available */
+		if (!spec->hp_detect) {
+			stac_toggle_power_map(codec, nid, 1);
+			continue;
+		}
+
+		if (is_nid_hp_pin(cfg, nid))
 			continue; /* already has an unsol event */
 
 		pinctl = snd_hda_codec_read(codec, nid, 0,
@@ -3799,8 +3967,10 @@
 		 * any attempts on powering down a input port cause the
 		 * referenced VREF to act quirky.
 		 */
-		if (pinctl & AC_PINCTL_IN_EN)
+		if (pinctl & AC_PINCTL_IN_EN) {
+			stac_toggle_power_map(codec, nid, 1);
 			continue;
+		}
 		def_conf = snd_hda_codec_read(codec, nid, 0,
 					      AC_VERB_GET_CONFIG_DEFAULT, 0);
 		def_conf = get_defcfg_connect(def_conf);
@@ -3811,30 +3981,54 @@
 				stac_toggle_power_map(codec, nid, 1);
 			continue;
 		}
-		enable_pin_detect(codec, spec->pwr_nids[i], event | i);
-		codec->patch_ops.unsol_event(codec, (event | i) << 26);
+		if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) {
+			enable_pin_detect(codec, nid, STAC_PWR_EVENT);
+			stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT);
+		}
 	}
 	if (spec->dac_list)
 		stac92xx_power_down(codec);
 	return 0;
 }
 
+static void stac92xx_free_jacks(struct hda_codec *codec)
+{
+#ifdef CONFIG_SND_JACK
+	/* free jack instances manually when clearing/reconfiguring */
+	struct sigmatel_spec *spec = codec->spec;
+	if (!codec->bus->shutdown && spec->jacks.list) {
+		struct sigmatel_jack *jacks = spec->jacks.list;
+		int i;
+		for (i = 0; i < spec->jacks.used; i++)
+			snd_device_free(codec->bus->card, &jacks[i].jack);
+	}
+	snd_array_free(&spec->jacks);
+#endif
+}
+
+static void stac92xx_free_kctls(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+
+	if (spec->kctls.list) {
+		struct snd_kcontrol_new *kctl = spec->kctls.list;
+		int i;
+		for (i = 0; i < spec->kctls.used; i++)
+			kfree(kctl[i].name);
+	}
+	snd_array_free(&spec->kctls);
+}
+
 static void stac92xx_free(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
-	int i;
 
 	if (! spec)
 		return;
 
-	if (spec->kctl_alloc) {
-		for (i = 0; i < spec->num_kctl_used; i++)
-			kfree(spec->kctl_alloc[i].name);
-		kfree(spec->kctl_alloc);
-	}
-
-	if (spec->bios_pin_configs)
-		kfree(spec->bios_pin_configs);
+	kfree(spec->pin_configs);
+	stac92xx_free_jacks(codec);
+	snd_array_free(&spec->events);
 
 	kfree(spec);
 	snd_hda_detach_beep_device(codec);
@@ -3853,11 +4047,7 @@
 		 * "xxx as Output" mixer switch
 		 */
 		struct sigmatel_spec *spec = codec->spec;
-		struct auto_pin_cfg *cfg = &spec->autocfg;
-		if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
-		     spec->line_switch) ||
-		    (nid == cfg->input_pins[AUTO_PIN_MIC] &&
-		     spec->mic_switch))
+		if (nid == spec->line_switch || nid == spec->mic_switch)
 			return;
 	}
 
@@ -3881,20 +4071,13 @@
 			pin_ctl & ~flag);
 }
 
-static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
+static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
 {
 	if (!nid)
 		return 0;
 	if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
-	    & (1 << 31)) {
-		unsigned int pinctl;
-		pinctl = snd_hda_codec_read(codec, nid, 0,
-					    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-		if (pinctl & AC_PINCTL_IN_EN)
-			return 0; /* mic- or line-input */
-		else
-			return 1; /* HP-output */
-	}
+	    & (1 << 31))
+		return 1;
 	return 0;
 }
 
@@ -3906,11 +4089,9 @@
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 
 	/* ignore sensing of shared line and mic jacks */
-	if (spec->line_switch &&
-	    cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE])
+	if (cfg->hp_pins[i] == spec->line_switch)
 		return 1;
-	if (spec->mic_switch &&
-	    cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC])
+	if (cfg->hp_pins[i] == spec->mic_switch)
 		return 1;
 	/* ignore if the pin is set as line-out */
 	if (cfg->hp_pins[i] == spec->hp_switch)
@@ -3918,7 +4099,7 @@
 	return 0;
 }
 
-static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
+static void stac92xx_hp_detect(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
@@ -3934,7 +4115,14 @@
 			break;
 		if (no_hp_sensing(spec, i))
 			continue;
-		presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
+		presence = get_pin_presence(codec, cfg->hp_pins[i]);
+		if (presence) {
+			unsigned int pinctl;
+			pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
+					    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+			if (pinctl & AC_PINCTL_IN_EN)
+				presence = 0; /* mic- or line-input */
+		}
 	}
 
 	if (presence) {
@@ -4011,50 +4199,145 @@
 
 static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
 {
-	stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid));
+	stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid));
+}
+
+static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct sigmatel_jack *jacks = spec->jacks.list;
+
+	if (jacks) {
+		int i;
+		for (i = 0; i < spec->jacks.used; i++) {
+			if (jacks->nid == nid) {
+				unsigned int pin_ctl =
+					snd_hda_codec_read(codec, nid,
+					0, AC_VERB_GET_PIN_WIDGET_CONTROL,
+					 0x00);
+				int type = jacks->type;
+				if (type == (SND_JACK_LINEOUT
+						| SND_JACK_HEADPHONE))
+					type = (pin_ctl & AC_PINCTL_HP_EN)
+					? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
+				snd_jack_report(jacks->jack,
+					get_pin_presence(codec, nid)
+					? type : 0);
+			}
+			jacks++;
+		}
+	}
+}
+
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
+				   unsigned char type)
+{
+	struct sigmatel_event *event = stac_get_event(codec, nid, type);
+	if (!event)
+		return;
+	codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26);
 }
 
 static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
 {
 	struct sigmatel_spec *spec = codec->spec;
-	int idx = res >> 26 & 0x0f;
+	struct sigmatel_event *event;
+	int tag, data;
 
-	switch ((res >> 26) & 0x70) {
+	tag = (res >> 26) & 0x7f;
+	event = stac_get_event_from_tag(codec, tag);
+	if (!event)
+		return;
+
+	switch (event->type) {
 	case STAC_HP_EVENT:
-		stac92xx_hp_detect(codec, res);
+		stac92xx_hp_detect(codec);
 		/* fallthru */
+	case STAC_INSERT_EVENT:
 	case STAC_PWR_EVENT:
 		if (spec->num_pwrs > 0)
-			stac92xx_pin_sense(codec, idx);
+			stac92xx_pin_sense(codec, event->nid);
+		stac92xx_report_jack(codec, event->nid);
 		break;
-	case STAC_VREF_EVENT: {
-		int data = snd_hda_codec_read(codec, codec->afg, 0,
-			AC_VERB_GET_GPIO_DATA, 0);
+	case STAC_VREF_EVENT:
+		data = snd_hda_codec_read(codec, codec->afg, 0,
+					  AC_VERB_GET_GPIO_DATA, 0);
 		/* toggle VREF state based on GPIOx status */
 		snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
-			!!(data & (1 << idx)));
+				    !!(data & (1 << event->data)));
 		break;
-		}
 	}
 }
 
+#ifdef CONFIG_PROC_FS
+static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
+			       struct hda_codec *codec, hda_nid_t nid)
+{
+	if (nid == codec->afg)
+		snd_iprintf(buffer, "Power-Map: 0x%02x\n", 
+			    snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0));
+}
+
+static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
+				  struct hda_codec *codec,
+				  unsigned int verb)
+{
+	snd_iprintf(buffer, "Analog Loopback: 0x%02x\n",
+		    snd_hda_codec_read(codec, codec->afg, 0, verb, 0));
+}
+
+/* stac92hd71bxx, stac92hd73xx */
+static void stac92hd7x_proc_hook(struct snd_info_buffer *buffer,
+				 struct hda_codec *codec, hda_nid_t nid)
+{
+	stac92hd_proc_hook(buffer, codec, nid);
+	if (nid == codec->afg)
+		analog_loop_proc_hook(buffer, codec, 0xfa0);
+}
+
+static void stac9205_proc_hook(struct snd_info_buffer *buffer,
+			       struct hda_codec *codec, hda_nid_t nid)
+{
+	if (nid == codec->afg)
+		analog_loop_proc_hook(buffer, codec, 0xfe0);
+}
+
+static void stac927x_proc_hook(struct snd_info_buffer *buffer,
+			       struct hda_codec *codec, hda_nid_t nid)
+{
+	if (nid == codec->afg)
+		analog_loop_proc_hook(buffer, codec, 0xfeb);
+}
+#else
+#define stac92hd_proc_hook	NULL
+#define stac92hd7x_proc_hook	NULL
+#define stac9205_proc_hook	NULL
+#define stac927x_proc_hook	NULL
+#endif
+
 #ifdef SND_HDA_NEEDS_RESUME
 static int stac92xx_resume(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
 
 	stac92xx_set_config_regs(codec);
-	snd_hda_sequence_write(codec, spec->init);
-	stac_gpio_set(codec, spec->gpio_mask,
-		spec->gpio_dir, spec->gpio_data);
+	stac92xx_init(codec);
 	snd_hda_codec_resume_amp(codec);
 	snd_hda_codec_resume_cache(codec);
-	/* power down inactive DACs */
-	if (spec->dac_list)
-		stac92xx_power_down(codec);
-	/* invoke unsolicited event to reset the HP state */
+	/* fake event to set up pins again to override cached values */
 	if (spec->hp_detect)
-		codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+		stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
+				       STAC_HP_EVENT);
+	return 0;
+}
+
+static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	if (spec->eapd_mask)
+		stac_gpio_set(codec, spec->gpio_mask,
+				spec->gpio_dir, spec->gpio_data &
+				~spec->eapd_mask);
 	return 0;
 }
 #endif
@@ -4066,6 +4349,7 @@
 	.free = stac92xx_free,
 	.unsol_event = stac92xx_unsol_event,
 #ifdef SND_HDA_NEEDS_RESUME
+	.suspend = stac92xx_suspend,
 	.resume = stac92xx_resume,
 #endif
 };
@@ -4088,14 +4372,12 @@
 	if (spec->board_config < 0) {
 		snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
-		if (err < 0) {
-			stac92xx_free(codec);
-			return err;
-		}
-		spec->pin_configs = spec->bios_pin_configs;
-	} else {
-		spec->pin_configs = stac9200_brd_tbl[spec->board_config];
-		stac92xx_set_config_regs(codec);
+	} else
+		err = stac_save_pin_cfgs(codec,
+					 stac9200_brd_tbl[spec->board_config]);
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
 	}
 
 	spec->multiout.max_channels = 2;
@@ -4151,14 +4433,12 @@
 		snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," 
 				      "using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
-		if (err < 0) {
-			stac92xx_free(codec);
-			return err;
-		}
-		spec->pin_configs = spec->bios_pin_configs;
-	} else if (stac925x_brd_tbl[spec->board_config] != NULL){
-		spec->pin_configs = stac925x_brd_tbl[spec->board_config];
-		stac92xx_set_config_regs(codec);
+	} else
+		err = stac_save_pin_cfgs(codec,
+					 stac925x_brd_tbl[spec->board_config]);
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
 	}
 
 	spec->multiout.max_channels = 2;
@@ -4222,6 +4502,7 @@
 	struct sigmatel_spec *spec;
 	hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
 	int err = 0;
+	int num_dacs;
 
 	spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
@@ -4240,43 +4521,37 @@
 		snd_printdd(KERN_INFO "hda_codec: Unknown model for"
 			" STAC92HD73XX, using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
-		if (err < 0) {
-			stac92xx_free(codec);
-			return err;
-		}
-		spec->pin_configs = spec->bios_pin_configs;
-	} else {
-		spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
-		stac92xx_set_config_regs(codec);
+	} else
+		err = stac_save_pin_cfgs(codec,
+				stac92hd73xx_brd_tbl[spec->board_config]);
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
 	}
 
-	spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
+	num_dacs = snd_hda_get_connections(codec, 0x0a,
 			conn, STAC92HD73_DAC_COUNT + 2) - 1;
 
-	if (spec->multiout.num_dacs < 0) {
+	if (num_dacs < 3 || num_dacs > 5) {
 		printk(KERN_WARNING "hda_codec: Could not determine "
 		       "number of channels defaulting to DAC count\n");
-		spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
+		num_dacs = STAC92HD73_DAC_COUNT;
 	}
-
-	switch (spec->multiout.num_dacs) {
+	switch (num_dacs) {
 	case 0x3: /* 6 Channel */
-		spec->multiout.hp_nid = 0x17;
 		spec->mixer = stac92hd73xx_6ch_mixer;
 		spec->init = stac92hd73xx_6ch_core_init;
 		break;
 	case 0x4: /* 8 Channel */
-		spec->multiout.hp_nid = 0x18;
 		spec->mixer = stac92hd73xx_8ch_mixer;
 		spec->init = stac92hd73xx_8ch_core_init;
 		break;
 	case 0x5: /* 10 Channel */
-		spec->multiout.hp_nid = 0x19;
 		spec->mixer = stac92hd73xx_10ch_mixer;
 		spec->init = stac92hd73xx_10ch_core_init;
-	};
+	}
+	spec->multiout.dac_nids = spec->dac_nids;
 
-	spec->multiout.dac_nids = stac92hd73xx_dac_nids;
 	spec->aloopback_mask = 0x01;
 	spec->aloopback_shift = 8;
 
@@ -4307,9 +4582,8 @@
 		spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
 		spec->eapd_switch = 0;
 		spec->num_amps = 1;
-		spec->multiout.hp_nid = 0; /* dual HPs */
 
-		if (!spec->init)
+		if (spec->board_config != STAC_DELL_EQ)
 			spec->init = dell_m6_core_init;
 		switch (spec->board_config) {
 		case STAC_DELL_M6_AMIC: /* Analog Mics */
@@ -4367,6 +4641,8 @@
 
 	codec->patch_ops = stac92xx_patch_ops;
 
+	codec->proc_widget_hook = stac92hd7x_proc_hook;
+
 	return 0;
 }
 
@@ -4398,17 +4674,15 @@
 	spec->pwr_nids = stac92hd83xxx_pwr_nids;
 	spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
 	spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
-	spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
+	spec->multiout.dac_nids = spec->dac_nids;
 
 	spec->init = stac92hd83xxx_core_init;
 	switch (codec->vendor_id) {
 	case 0x111d7605:
-		spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
 		break;
 	default:
 		spec->num_pwrs--;
 		spec->init++; /* switch to config #2 */
-		spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
 	}
 
 	spec->mixer = stac92hd83xxx_mixer;
@@ -4427,14 +4701,12 @@
 		snd_printdd(KERN_INFO "hda_codec: Unknown model for"
 			" STAC92HD83XXX, using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
-		if (err < 0) {
-			stac92xx_free(codec);
-			return err;
-		}
-		spec->pin_configs = spec->bios_pin_configs;
-	} else {
-		spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config];
-		stac92xx_set_config_regs(codec);
+	} else
+		err = stac_save_pin_cfgs(codec,
+				stac92hd83xxx_brd_tbl[spec->board_config]);
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
 	}
 
 	err = stac92xx_parse_auto_config(codec, 0x1d, 0);
@@ -4455,57 +4727,11 @@
 
 	codec->patch_ops = stac92xx_patch_ops;
 
+	codec->proc_widget_hook = stac92hd_proc_hook;
+
 	return 0;
 }
 
-#ifdef SND_HDA_NEEDS_RESUME
-static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
-{
-	struct sigmatel_spec *spec = codec->spec;
-	int i;
-	snd_hda_codec_write_cache(codec, codec->afg, 0,
-		AC_VERB_SET_POWER_STATE, pwr);
-
-	msleep(1);
-	for (i = 0; i < spec->num_adcs; i++) {
-		snd_hda_codec_write_cache(codec,
-			spec->adc_nids[i], 0,
-			AC_VERB_SET_POWER_STATE, pwr);
-	}
-};
-
-static int stac92hd71xx_resume(struct hda_codec *codec)
-{
-	stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
-	return stac92xx_resume(codec);
-}
-
-static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
-{
-	struct sigmatel_spec *spec = codec->spec;
-
-	stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
-	if (spec->eapd_mask)
-		stac_gpio_set(codec, spec->gpio_mask,
-				spec->gpio_dir, spec->gpio_data &
-				~spec->eapd_mask);
-	return 0;
-};
-
-#endif
-
-static struct hda_codec_ops stac92hd71bxx_patch_ops = {
-	.build_controls = stac92xx_build_controls,
-	.build_pcms = stac92xx_build_pcms,
-	.init = stac92xx_init,
-	.free = stac92xx_free,
-	.unsol_event = stac92xx_unsol_event,
-#ifdef SND_HDA_NEEDS_RESUME
-	.resume = stac92hd71xx_resume,
-	.suspend = stac92hd71xx_suspend,
-#endif
-};
-
 static struct hda_input_mux stac92hd71bxx_dmux = {
 	.num_items = 4,
 	.items = {
@@ -4541,14 +4767,12 @@
 		snd_printdd(KERN_INFO "hda_codec: Unknown model for"
 			" STAC92HD71BXX, using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
-		if (err < 0) {
-			stac92xx_free(codec);
-			return err;
-		}
-		spec->pin_configs = spec->bios_pin_configs;
-	} else {
-		spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
-		stac92xx_set_config_regs(codec);
+	} else
+		err = stac_save_pin_cfgs(codec,
+				stac92hd71bxx_brd_tbl[spec->board_config]);
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
 	}
 
 	if (spec->board_config > STAC_92HD71BXX_REF) {
@@ -4571,21 +4795,21 @@
 		switch (spec->board_config) {
 		case STAC_HP_M4:
 			/* Enable VREF power saving on GPIO1 detect */
+			err = stac_add_event(spec, codec->afg,
+					     STAC_VREF_EVENT, 0x02);
+			if (err < 0)
+				return err;
 			snd_hda_codec_write_cache(codec, codec->afg, 0,
 				AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
 			snd_hda_codec_write_cache(codec, codec->afg, 0,
-					AC_VERB_SET_UNSOLICITED_ENABLE,
-					(AC_USRSP_EN | STAC_VREF_EVENT | 0x01));
+				AC_VERB_SET_UNSOLICITED_ENABLE,
+				AC_USRSP_EN | err);
 			spec->gpio_mask |= 0x02;
 			break;
 		}
 		if ((codec->revision_id & 0xf) == 0 ||
-				(codec->revision_id & 0xf) == 1) {
-#ifdef SND_HDA_NEEDS_RESUME
-			codec->patch_ops = stac92hd71bxx_patch_ops;
-#endif
+		    (codec->revision_id & 0xf) == 1)
 			spec->stream_delay = 40; /* 40 milliseconds */
-		}
 
 		/* no output amps */
 		spec->num_pwrs = 0;
@@ -4594,15 +4818,11 @@
 
 		/* disable VSW */
 		spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
-		stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
+		stac_change_pin_config(codec, 0xf, 0x40f000f0);
 		break;
 	case 0x111d7603: /* 6 Port with Analog Mixer */
-		if ((codec->revision_id & 0xf) == 1) {
-#ifdef SND_HDA_NEEDS_RESUME
-			codec->patch_ops = stac92hd71bxx_patch_ops;
-#endif
+		if ((codec->revision_id & 0xf) == 1)
 			spec->stream_delay = 40; /* 40 milliseconds */
-		}
 
 		/* no output amps */
 		spec->num_pwrs = 0;
@@ -4632,7 +4852,7 @@
 	switch (spec->board_config) {
 	case STAC_HP_M4:
 		/* enable internal microphone */
-		stac92xx_set_config_reg(codec, 0x0e, 0x01813040);
+		stac_change_pin_config(codec, 0x0e, 0x01813040);
 		stac92xx_auto_set_pinctl(codec, 0x0e,
 			AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
 		/* fallthru */
@@ -4653,9 +4873,7 @@
 		spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
 	};
 
-	spec->multiout.num_dacs = 1;
-	spec->multiout.hp_nid = 0x11;
-	spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+	spec->multiout.dac_nids = spec->dac_nids;
 	if (spec->dinput_mux)
 		spec->private_dimux.num_items +=
 			spec->num_dmics -
@@ -4677,6 +4895,8 @@
 		return err;
 	}
 
+	codec->proc_widget_hook = stac92hd7x_proc_hook;
+
 	return 0;
 };
 
@@ -4738,14 +4958,12 @@
 		snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
 			"using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
-		if (err < 0) {
-			stac92xx_free(codec);
-			return err;
-		}
-		spec->pin_configs = spec->bios_pin_configs;
-	} else if (stac922x_brd_tbl[spec->board_config] != NULL) {
-		spec->pin_configs = stac922x_brd_tbl[spec->board_config];
-		stac92xx_set_config_regs(codec);
+	} else
+		err = stac_save_pin_cfgs(codec,
+				stac922x_brd_tbl[spec->board_config]);
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
 	}
 
 	spec->adc_nids = stac922x_adc_nids;
@@ -4808,14 +5026,12 @@
 			snd_printdd(KERN_INFO "hda_codec: Unknown model for"
 				    "STAC927x, using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
-		if (err < 0) {
-			stac92xx_free(codec);
-			return err;
-		}
-		spec->pin_configs = spec->bios_pin_configs;
-	} else {
-		spec->pin_configs = stac927x_brd_tbl[spec->board_config];
-		stac92xx_set_config_regs(codec);
+	} else
+		err = stac_save_pin_cfgs(codec,
+				stac927x_brd_tbl[spec->board_config]);
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
 	}
 
 	spec->digbeep_nid = 0x23;
@@ -4845,15 +5061,15 @@
 		case 0x10280209:
 		case 0x1028022e:
 			/* correct the device field to SPDIF out */
-			stac92xx_set_config_reg(codec, 0x21, 0x01442070);
+			stac_change_pin_config(codec, 0x21, 0x01442070);
 			break;
 		};
 		/* configure the analog microphone on some laptops */
-		stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
+		stac_change_pin_config(codec, 0x0c, 0x90a79130);
 		/* correct the front output jack as a hp out */
-		stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
+		stac_change_pin_config(codec, 0x0f, 0x0227011f);
 		/* correct the front input jack as a mic */
-		stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
+		stac_change_pin_config(codec, 0x0e, 0x02a79130);
 		/* fallthru */
 	case STAC_DELL_3ST:
 		/* GPIO2 High = Enable EAPD */
@@ -4901,6 +5117,8 @@
 
 	codec->patch_ops = stac92xx_patch_ops;
 
+	codec->proc_widget_hook = stac927x_proc_hook;
+
 	/*
 	 * !!FIXME!!
 	 * The STAC927x seem to require fairly long delays for certain
@@ -4939,14 +5157,12 @@
 	if (spec->board_config < 0) {
 		snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
-		if (err < 0) {
-			stac92xx_free(codec);
-			return err;
-		}
-		spec->pin_configs = spec->bios_pin_configs;
-	} else {
-		spec->pin_configs = stac9205_brd_tbl[spec->board_config];
-		stac92xx_set_config_regs(codec);
+	} else
+		err = stac_save_pin_cfgs(codec,
+					 stac9205_brd_tbl[spec->board_config]);
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
 	}
 
 	spec->digbeep_nid = 0x23;
@@ -4973,15 +5189,18 @@
 	switch (spec->board_config){
 	case STAC_9205_DELL_M43:
 		/* Enable SPDIF in/out */
-		stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
-		stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
+		stac_change_pin_config(codec, 0x1f, 0x01441030);
+		stac_change_pin_config(codec, 0x20, 0x1c410030);
 
 		/* Enable unsol response for GPIO4/Dock HP connection */
+		err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01);
+		if (err < 0)
+			return err;
 		snd_hda_codec_write_cache(codec, codec->afg, 0,
 			AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
 		snd_hda_codec_write_cache(codec, codec->afg, 0,
 					  AC_VERB_SET_UNSOLICITED_ENABLE,
-					  (AC_USRSP_EN | STAC_HP_EVENT));
+					  AC_USRSP_EN | err);
 
 		spec->gpio_dir = 0x0b;
 		spec->eapd_mask = 0x01;
@@ -5019,6 +5238,8 @@
 
 	codec->patch_ops = stac92xx_patch_ops;
 
+	codec->proc_widget_hook = stac9205_proc_hook;
+
 	return 0;
 }
 
@@ -5075,29 +5296,11 @@
 	{}
 };
 
-/* bind volumes of both NID 0x02 and 0x05 */
-static struct hda_bind_ctls vaio_bind_master_vol = {
-	.ops = &snd_hda_bind_vol,
-	.values = {
-		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
-		HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
-		0
-	},
-};
-
-/* bind volumes of both NID 0x02 and 0x05 */
-static struct hda_bind_ctls vaio_bind_master_sw = {
-	.ops = &snd_hda_bind_sw,
-	.values = {
-		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
-		HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
-		0,
-	},
-};
-
 static struct snd_kcontrol_new vaio_mixer[] = {
-	HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
-	HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
 	/* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
@@ -5113,8 +5316,10 @@
 };
 
 static struct snd_kcontrol_new vaio_ar_mixer[] = {
-	HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
-	HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
 	/* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
@@ -5155,7 +5360,7 @@
 
 static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
 {
-	if (get_hp_pin_presence(codec, 0x0a)) {
+	if (get_pin_presence(codec, 0x0a)) {
 		stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
 		stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
 	} else {
@@ -5266,7 +5471,7 @@
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_sigmatel[] = {
+static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
  	{ .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
  	{ .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
  	{ .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
@@ -5330,3 +5535,27 @@
 	{ .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:8384*");
+MODULE_ALIAS("snd-hda-codec-id:111d*");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
+
+static struct hda_codec_preset_list sigmatel_list = {
+	.preset = snd_hda_preset_sigmatel,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_sigmatel_init(void)
+{
+	return snd_hda_add_codec_preset(&sigmatel_list);
+}
+
+static void __exit patch_sigmatel_exit(void)
+{
+	snd_hda_delete_codec_preset(&sigmatel_list);
+}
+
+module_init(patch_sigmatel_init)
+module_exit(patch_sigmatel_exit)
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 63e4871..c761394 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -47,15 +47,11 @@
 #include <sound/asoundef.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 
 /* amp values */
 #define AMP_VAL_IDX_SHIFT	19
 #define AMP_VAL_IDX_MASK	(0x0f<<19)
 
-#define NUM_CONTROL_ALLOC	32
-#define NUM_VERB_ALLOC		32
-
 /* Pin Widget NID */
 #define VT1708_HP_NID		0x13
 #define VT1708_DIGOUT_NID	0x14
@@ -145,8 +141,6 @@
 	AUTO_SEQ_SIDE
 };
 
-#define get_amp_nid(kc)	((kc)->private_value & 0xffff)
-
 /* Some VT1708S based boards gets the micboost setting wrong, so we have
  * to apply some brute-force and re-write the TLV's by software. */
 static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag,
@@ -227,8 +221,7 @@
 
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
-	unsigned int num_kctl_alloc, num_kctl_used;
-	struct snd_kcontrol_new *kctl_alloc;
+	struct snd_array kctls;
 	struct hda_input_mux private_imux[2];
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
@@ -272,33 +265,31 @@
 {
 	struct snd_kcontrol_new *knew;
 
-	if (spec->num_kctl_used >= spec->num_kctl_alloc) {
-		int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
-
-		/* array + terminator */
-		knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
-		if (!knew)
-			return -ENOMEM;
-		if (spec->kctl_alloc) {
-			memcpy(knew, spec->kctl_alloc,
-			       sizeof(*knew) * spec->num_kctl_alloc);
-			kfree(spec->kctl_alloc);
-		}
-		spec->kctl_alloc = knew;
-		spec->num_kctl_alloc = num;
-	}
-
-	knew = &spec->kctl_alloc[spec->num_kctl_used];
+	snd_array_init(&spec->kctls, sizeof(*knew), 32);
+	knew = snd_array_new(&spec->kctls);
+	if (!knew)
+		return -ENOMEM;
 	*knew = vt1708_control_templates[type];
 	knew->name = kstrdup(name, GFP_KERNEL);
-
 	if (!knew->name)
 		return -ENOMEM;
 	knew->private_value = val;
-	spec->num_kctl_used++;
 	return 0;
 }
 
+static void via_free_kctls(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+
+	if (spec->kctls.list) {
+		struct snd_kcontrol_new *kctl = spec->kctls.list;
+		int i;
+		for (i = 0; i < spec->kctls.used; i++)
+			kfree(kctl[i].name);
+	}
+	snd_array_free(&spec->kctls);
+}
+
 /* create input playback/capture controls for the given pin */
 static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
 				const char *ctlname, int idx, int mix_nid)
@@ -896,6 +887,7 @@
 		if (err < 0)
 			return err;
 	}
+	via_free_kctls(codec); /* no longer needed */
 	return 0;
 }
 
@@ -941,17 +933,11 @@
 static void via_free(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
-	unsigned int i;
 
 	if (!spec)
 		return;
 
-	if (spec->kctl_alloc) {
-		for (i = 0; i < spec->num_kctl_used; i++)
-			kfree(spec->kctl_alloc[i].name);
-		kfree(spec->kctl_alloc);
-	}
-
+	via_free_kctls(codec);
 	kfree(codec->spec);
 }
 
@@ -1373,8 +1359,8 @@
 	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = VT1708_DIGIN_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
 
@@ -1846,8 +1832,8 @@
 	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = VT1709_DIGIN_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->input_mux = &spec->private_imux[0];
 
@@ -2390,8 +2376,8 @@
 	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = VT1708B_DIGIN_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->input_mux = &spec->private_imux[0];
 
@@ -2855,8 +2841,8 @@
 
 	spec->extra_dig_out_nid = 0x15;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->input_mux = &spec->private_imux[0];
 
@@ -3174,8 +3160,8 @@
 
 	spec->extra_dig_out_nid = 0x1B;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->input_mux = &spec->private_imux[0];
 
@@ -3262,74 +3248,97 @@
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_via[] = {
-	{ .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
-	{ .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
-	{ .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
-	{ .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
-	{ .id = 0x1106E710, .name = "VIA VT1709 10-Ch",
+static struct hda_codec_preset snd_hda_preset_via[] = {
+	{ .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
+	{ .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
+	{ .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
+	{ .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
+	{ .id = 0x1106e710, .name = "VT1709 10-Ch",
 	  .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E711, .name = "VIA VT1709 10-Ch",
+	{ .id = 0x1106e711, .name = "VT1709 10-Ch",
 	  .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E712, .name = "VIA VT1709 10-Ch",
+	{ .id = 0x1106e712, .name = "VT1709 10-Ch",
 	  .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E713, .name = "VIA VT1709 10-Ch",
+	{ .id = 0x1106e713, .name = "VT1709 10-Ch",
 	  .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E714, .name = "VIA VT1709 6-Ch",
+	{ .id = 0x1106e714, .name = "VT1709 6-Ch",
 	  .patch = patch_vt1709_6ch},
-	{ .id = 0x1106E715, .name = "VIA VT1709 6-Ch",
+	{ .id = 0x1106e715, .name = "VT1709 6-Ch",
 	  .patch = patch_vt1709_6ch},
-	{ .id = 0x1106E716, .name = "VIA VT1709 6-Ch",
+	{ .id = 0x1106e716, .name = "VT1709 6-Ch",
 	  .patch = patch_vt1709_6ch},
-	{ .id = 0x1106E717, .name = "VIA VT1709 6-Ch",
+	{ .id = 0x1106e717, .name = "VT1709 6-Ch",
 	  .patch = patch_vt1709_6ch},
-	{ .id = 0x1106E720, .name = "VIA VT1708B 8-Ch",
+	{ .id = 0x1106e720, .name = "VT1708B 8-Ch",
 	  .patch = patch_vt1708B_8ch},
-	{ .id = 0x1106E721, .name = "VIA VT1708B 8-Ch",
+	{ .id = 0x1106e721, .name = "VT1708B 8-Ch",
 	  .patch = patch_vt1708B_8ch},
-	{ .id = 0x1106E722, .name = "VIA VT1708B 8-Ch",
+	{ .id = 0x1106e722, .name = "VT1708B 8-Ch",
 	  .patch = patch_vt1708B_8ch},
-	{ .id = 0x1106E723, .name = "VIA VT1708B 8-Ch",
+	{ .id = 0x1106e723, .name = "VT1708B 8-Ch",
 	  .patch = patch_vt1708B_8ch},
-	{ .id = 0x1106E724, .name = "VIA VT1708B 4-Ch",
+	{ .id = 0x1106e724, .name = "VT1708B 4-Ch",
 	  .patch = patch_vt1708B_4ch},
-	{ .id = 0x1106E725, .name = "VIA VT1708B 4-Ch",
+	{ .id = 0x1106e725, .name = "VT1708B 4-Ch",
 	  .patch = patch_vt1708B_4ch},
-	{ .id = 0x1106E726, .name = "VIA VT1708B 4-Ch",
+	{ .id = 0x1106e726, .name = "VT1708B 4-Ch",
 	  .patch = patch_vt1708B_4ch},
-	{ .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
+	{ .id = 0x1106e727, .name = "VT1708B 4-Ch",
 	  .patch = patch_vt1708B_4ch},
-	{ .id = 0x11060397, .name = "VIA VT1708S",
+	{ .id = 0x11060397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11061397, .name = "VIA VT1708S",
+	{ .id = 0x11061397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11062397, .name = "VIA VT1708S",
+	{ .id = 0x11062397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11063397, .name = "VIA VT1708S",
+	{ .id = 0x11063397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11064397, .name = "VIA VT1708S",
+	{ .id = 0x11064397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11065397, .name = "VIA VT1708S",
+	{ .id = 0x11065397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11066397, .name = "VIA VT1708S",
+	{ .id = 0x11066397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11067397, .name = "VIA VT1708S",
+	{ .id = 0x11067397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11060398, .name = "VIA VT1702",
+	{ .id = 0x11060398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11061398, .name = "VIA VT1702",
+	{ .id = 0x11061398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11062398, .name = "VIA VT1702",
+	{ .id = 0x11062398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11063398, .name = "VIA VT1702",
+	{ .id = 0x11063398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11064398, .name = "VIA VT1702",
+	{ .id = 0x11064398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11065398, .name = "VIA VT1702",
+	{ .id = 0x11065398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11066398, .name = "VIA VT1702",
+	{ .id = 0x11066398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11067398, .name = "VIA VT1702",
+	{ .id = 0x11067398, .name = "VT1702",
 	  .patch = patch_vt1702},
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:1106*");
+
+static struct hda_codec_preset_list via_list = {
+	.preset = snd_hda_preset_via,
+	.owner = THIS_MODULE,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VIA HD-audio codec");
+
+static int __init patch_via_init(void)
+{
+	return snd_hda_add_codec_preset(&via_list);
+}
+
+static void __exit patch_via_exit(void)
+{
+	snd_hda_delete_codec_preset(&via_list);
+}
+
+module_init(patch_via_init)
+module_exit(patch_via_exit)
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 1b3f117..0dfa054 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -382,23 +382,25 @@
 	unsigned char status_mask =
 		VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX | VT1724_IRQ_MTPCM;
 	int handled = 0;
-#ifdef CONFIG_SND_DEBUG
 	int timeout = 0;
-#endif
 
 	while (1) {
 		status = inb(ICEREG1724(ice, IRQSTAT));
 		status &= status_mask;
 		if (status == 0)
 			break;
-#ifdef CONFIG_SND_DEBUG
 		if (++timeout > 10) {
-			printk(KERN_ERR
-			       "ice1724: Too long irq loop, status = 0x%x\n",
-			       status);
+			status = inb(ICEREG1724(ice, IRQSTAT));
+			printk(KERN_ERR "ice1724: Too long irq loop, "
+			       "status = 0x%x\n", status);
+			if (status & VT1724_IRQ_MPU_TX) {
+				printk(KERN_ERR "ice1724: Disabling MPU_TX\n");
+				outb(inb(ICEREG1724(ice, IRQMASK)) |
+				     VT1724_IRQ_MPU_TX,
+				     ICEREG1724(ice, IRQMASK));
+			}
 			break;
 		}
-#endif
 		handled = 1;
 		if (status & VT1724_IRQ_MPU_TX) {
 			spin_lock(&ice->reg_lock);
@@ -2351,7 +2353,6 @@
 {
 	struct snd_ice1712 *ice;
 	int err;
-	unsigned char mask;
 	static struct snd_device_ops ops = {
 		.dev_free =	snd_vt1724_dev_free,
 	};
@@ -2412,9 +2413,9 @@
 		return -EIO;
 	}
 
-	/* unmask used interrupts */
-	mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX;
-	outb(mask, ICEREG1724(ice, IRQMASK));
+	/* MPU_RX and TX irq masks are cleared later dynamically */
+	outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK));
+
 	/* don't handle FIFO overrun/underruns (just yet),
 	 * since they cause machine lockups
 	 */
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 9ff3f9e..59bbaf8 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -1670,7 +1670,7 @@
 		return IRQ_NONE;
 
 	if (status & HV_INT_PENDING)
-		tasklet_hi_schedule(&chip->hwvol_tq);
+		tasklet_schedule(&chip->hwvol_tq);
 
 	/*
 	 * ack an assp int if its running
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index ae7601f..f23a735 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1010,7 +1010,7 @@
 		.dev_free = snd_mixart_chip_dev_free,
 	};
 
-	mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 	if (! chip) {
 		snd_printk(KERN_ERR "cannot allocate chip\n");
 		return -ENOMEM;
@@ -1025,6 +1025,7 @@
 		return err;
 	}
 
+	mgr->chip[idx] = chip;
 	snd_card_set_dev(card, &mgr->pci->dev);
 
 	return 0;
@@ -1377,6 +1378,7 @@
 		sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i);
 
 		if ((err = snd_mixart_create(mgr, card, i)) < 0) {
+			snd_card_free(card);
 			snd_mixart_free(mgr);
 			return err;
 		}
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
index b9a06c2..d3350f3 100644
--- a/sound/pci/mixart/mixart_core.c
+++ b/sound/pci/mixart/mixart_core.c
@@ -550,7 +550,7 @@
 				mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
 				mgr->msg_fifo_writeptr++;
 				mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
-				tasklet_hi_schedule(&mgr->msg_taskq);
+				tasklet_schedule(&mgr->msg_taskq);
 			}
 			spin_unlock(&mgr->msg_lock);
 			break;
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index b60f621..de999c6 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -61,6 +61,7 @@
 enum {
 	MODEL_CMEDIA_REF,	/* C-Media's reference design */
 	MODEL_MERIDIAN,		/* AuzenTech X-Meridian */
+	MODEL_HALO,		/* HT-Omega Claro halo */
 };
 
 static struct pci_device_id oxygen_ids[] __devinitdata = {
@@ -74,6 +75,7 @@
 	{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
 	{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
 	{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CMEDIA_REF },
+	{ OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_HALO },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, oxygen_ids);
@@ -301,6 +303,8 @@
 					    PLAYBACK_1_TO_SPDIF |
 					    CAPTURE_0_FROM_I2S_2 |
 					    CAPTURE_1_FROM_SPDIF;
+	}
+	if (driver_data == MODEL_MERIDIAN || driver_data == MODEL_HALO) {
 		chip->model.misc_flags = OXYGEN_MISC_MIDI;
 		chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
 	}
diff --git a/sound/pci/pcxhr/Makefile b/sound/pci/pcxhr/Makefile
index 10473c0..b06128e 100644
--- a/sound/pci/pcxhr/Makefile
+++ b/sound/pci/pcxhr/Makefile
@@ -1,2 +1,2 @@
-snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o
+snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o pcxhr_mix22.o
 obj-$(CONFIG_SND_PCXHR) += snd-pcxhr.o
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index 73de6e9..27cf2c2 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -40,18 +40,20 @@
 #include "pcxhr_mixer.h"
 #include "pcxhr_hwdep.h"
 #include "pcxhr_core.h"
+#include "pcxhr_mix22.h"
 
 #define DRIVER_NAME "pcxhr"
 
-MODULE_AUTHOR("Markus Bollinger <bollinger@digigram.com>");
+MODULE_AUTHOR("Markus Bollinger <bollinger@digigram.com>, "
+	      "Marc Titinger <titinger@digigram.com>");
 MODULE_DESCRIPTION("Digigram " DRIVER_NAME " " PCXHR_DRIVER_VERSION_STRING);
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Digigram," DRIVER_NAME "}}");
 
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;		/* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;		/* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
-static int mono[SNDRV_CARDS];					/* capture in mono only */
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
+static int mono[SNDRV_CARDS];				/* capture  mono only */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Digigram " DRIVER_NAME " soundcard");
@@ -67,18 +69,58 @@
 	PCI_ID_PCX882HR,
 	PCI_ID_VX881HR,
 	PCI_ID_PCX881HR,
+	PCI_ID_VX882E,
+	PCI_ID_PCX882E,
+	PCI_ID_VX881E,
+	PCI_ID_PCX881E,
+	PCI_ID_VX1222HR,
 	PCI_ID_PCX1222HR,
+	PCI_ID_VX1221HR,
 	PCI_ID_PCX1221HR,
+	PCI_ID_VX1222E,
+	PCI_ID_PCX1222E,
+	PCI_ID_VX1221E,
+	PCI_ID_PCX1221E,
+	PCI_ID_VX222HR,
+	PCI_ID_VX222E,
+	PCI_ID_PCX22HR,
+	PCI_ID_PCX22E,
+	PCI_ID_VX222HRMIC,
+	PCI_ID_VX222E_MIC,
+	PCI_ID_PCX924HR,
+	PCI_ID_PCX924E,
+	PCI_ID_PCX924HRMIC,
+	PCI_ID_PCX924E_MIC,
 	PCI_ID_LAST
 };
 
 static struct pci_device_id pcxhr_ids[] = {
-	{ 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, },   /* VX882HR */
-	{ 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, },  /* PCX882HR */
-	{ 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, },   /* VX881HR */
-	{ 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, },  /* PCX881HR */
-	{ 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, }, /* PCX1222HR */
-	{ 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, }, /* PCX1221HR */
+	{ 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, },
+	{ 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, },
+	{ 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, },
+	{ 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, },
+	{ 0x10b5, 0x9056, 0x1369, 0xb021, 0, 0, PCI_ID_VX882E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xb121, 0, 0, PCI_ID_PCX882E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xb221, 0, 0, PCI_ID_VX881E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xb321, 0, 0, PCI_ID_PCX881E, },
+	{ 0x10b5, 0x9656, 0x1369, 0xb401, 0, 0, PCI_ID_VX1222HR, },
+	{ 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, },
+	{ 0x10b5, 0x9656, 0x1369, 0xb601, 0, 0, PCI_ID_VX1221HR, },
+	{ 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, },
+	{ 0x10b5, 0x9056, 0x1369, 0xb421, 0, 0, PCI_ID_VX1222E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xb521, 0, 0, PCI_ID_PCX1222E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xb621, 0, 0, PCI_ID_VX1221E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xb721, 0, 0, PCI_ID_PCX1221E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xba01, 0, 0, PCI_ID_VX222HR, },
+	{ 0x10b5, 0x9056, 0x1369, 0xba21, 0, 0, PCI_ID_VX222E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xbd01, 0, 0, PCI_ID_PCX22HR, },
+	{ 0x10b5, 0x9056, 0x1369, 0xbd21, 0, 0, PCI_ID_PCX22E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xbc01, 0, 0, PCI_ID_VX222HRMIC, },
+	{ 0x10b5, 0x9056, 0x1369, 0xbc21, 0, 0, PCI_ID_VX222E_MIC, },
+	{ 0x10b5, 0x9056, 0x1369, 0xbb01, 0, 0, PCI_ID_PCX924HR, },
+	{ 0x10b5, 0x9056, 0x1369, 0xbb21, 0, 0, PCI_ID_PCX924E, },
+	{ 0x10b5, 0x9056, 0x1369, 0xbf01, 0, 0, PCI_ID_PCX924HRMIC, },
+	{ 0x10b5, 0x9056, 0x1369, 0xbf21, 0, 0, PCI_ID_PCX924E_MIC, },
 	{ 0, }
 };
 
@@ -88,27 +130,55 @@
 	char* board_name;
 	short playback_chips;
 	short capture_chips;
+	short fw_file_set;
 	short firmware_num;
 };
 static struct board_parameters pcxhr_board_params[] = {
-[PCI_ID_VX882HR] =	{ "VX882HR",   4, 4, 41, },
-[PCI_ID_PCX882HR] =	{ "PCX882HR",  4, 4, 41, },
-[PCI_ID_VX881HR] =	{ "VX881HR",   4, 4, 41, },
-[PCI_ID_PCX881HR] =	{ "PCX881HR",  4, 4, 41, },
-[PCI_ID_PCX1222HR] =	{ "PCX1222HR", 6, 1, 42, },
-[PCI_ID_PCX1221HR] =	{ "PCX1221HR", 6, 1, 42, },
+[PCI_ID_VX882HR] =      { "VX882HR",      4, 4, 0, 41 },
+[PCI_ID_PCX882HR] =     { "PCX882HR",     4, 4, 0, 41 },
+[PCI_ID_VX881HR] =      { "VX881HR",      4, 4, 0, 41 },
+[PCI_ID_PCX881HR] =     { "PCX881HR",     4, 4, 0, 41 },
+[PCI_ID_VX882E] =       { "VX882e",       4, 4, 1, 41 },
+[PCI_ID_PCX882E] =      { "PCX882e",      4, 4, 1, 41 },
+[PCI_ID_VX881E] =       { "VX881e",       4, 4, 1, 41 },
+[PCI_ID_PCX881E] =      { "PCX881e",      4, 4, 1, 41 },
+[PCI_ID_VX1222HR] =     { "VX1222HR",     6, 1, 2, 42 },
+[PCI_ID_PCX1222HR] =    { "PCX1222HR",    6, 1, 2, 42 },
+[PCI_ID_VX1221HR] =     { "VX1221HR",     6, 1, 2, 42 },
+[PCI_ID_PCX1221HR] =    { "PCX1221HR",    6, 1, 2, 42 },
+[PCI_ID_VX1222E] =      { "VX1222e",      6, 1, 3, 42 },
+[PCI_ID_PCX1222E] =     { "PCX1222e",     6, 1, 3, 42 },
+[PCI_ID_VX1221E] =      { "VX1221e",      6, 1, 3, 42 },
+[PCI_ID_PCX1221E] =     { "PCX1221e",     6, 1, 3, 42 },
+[PCI_ID_VX222HR] =      { "VX222HR",      1, 1, 4, 44 },
+[PCI_ID_VX222E] =       { "VX222e",       1, 1, 4, 44 },
+[PCI_ID_PCX22HR] =      { "PCX22HR",      1, 0, 4, 44 },
+[PCI_ID_PCX22E] =       { "PCX22e",       1, 0, 4, 44 },
+[PCI_ID_VX222HRMIC] =   { "VX222HR-Mic",  1, 1, 5, 44 },
+[PCI_ID_VX222E_MIC] =   { "VX222e-Mic",   1, 1, 5, 44 },
+[PCI_ID_PCX924HR] =     { "PCX924HR",     1, 1, 5, 44 },
+[PCI_ID_PCX924E] =      { "PCX924e",      1, 1, 5, 44 },
+[PCI_ID_PCX924HRMIC] =  { "PCX924HR-Mic", 1, 1, 5, 44 },
+[PCI_ID_PCX924E_MIC] =  { "PCX924e-Mic",  1, 1, 5, 44 },
 };
 
+/* boards without hw AES1 and SRC onboard are all using fw_file_set==4 */
+/* VX222HR, VX222e, PCX22HR and PCX22e */
+#define PCXHR_BOARD_HAS_AES1(x) (x->fw_file_set != 4)
+/* some boards do not support 192kHz on digital AES input plugs */
+#define PCXHR_BOARD_AESIN_NO_192K(x) ((x->capture_chips == 0) || \
+				      (x->fw_file_set == 0)   || \
+				      (x->fw_file_set == 2))
 
 static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg,
 				   unsigned int* realfreq)
 {
 	unsigned int reg;
 
-	if (freq < 6900 || freq > 110250)
+	if (freq < 6900 || freq > 110000)
 		return -EINVAL;
-	reg = (28224000 * 10) / freq;
-	reg = (reg + 5) / 10;
+	reg = (28224000 * 2) / freq;
+	reg = (reg - 1) / 2;
 	if (reg < 0x200)
 		*pllreg = reg + 0x800;
 	else if (reg < 0x400)
@@ -121,7 +191,7 @@
 		reg &= ~3;
 	}
 	if (realfreq)
-		*realfreq = ((28224000 * 10) / reg + 5) / 10;
+		*realfreq = (28224000 / (reg + 1));
 	return 0;
 }
 
@@ -151,11 +221,6 @@
 #define PCXHR_FREQ_AES_3		0x03
 #define PCXHR_FREQ_AES_4		0x0d
 
-#define PCXHR_MODIFY_CLOCK_S_BIT	0x04
-
-#define PCXHR_IRQ_TIMER_FREQ		92000
-#define PCXHR_IRQ_TIMER_PERIOD		48
-
 static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate,
 			       unsigned int *reg, unsigned int *freq)
 {
@@ -196,19 +261,32 @@
 			err = pcxhr_send_msg(mgr, &rmh);
 			if (err < 0) {
 				snd_printk(KERN_ERR
-					   "error CMD_ACCESS_IO_WRITE for PLL register : %x!\n",
-					   err );
+					   "error CMD_ACCESS_IO_WRITE "
+					   "for PLL register : %x!\n", err);
 				return err;
 			}
 		}
 		break;
-	case PCXHR_CLOCK_TYPE_WORD_CLOCK :	val = PCXHR_FREQ_WORD_CLOCK;	break;
-	case PCXHR_CLOCK_TYPE_AES_SYNC :	val = PCXHR_FREQ_SYNC_AES;	break;
-	case PCXHR_CLOCK_TYPE_AES_1 :		val = PCXHR_FREQ_AES_1;		break;
-	case PCXHR_CLOCK_TYPE_AES_2 :		val = PCXHR_FREQ_AES_2;		break;
-	case PCXHR_CLOCK_TYPE_AES_3 :		val = PCXHR_FREQ_AES_3;		break;
-	case PCXHR_CLOCK_TYPE_AES_4 :		val = PCXHR_FREQ_AES_4;		break;
-	default : return -EINVAL;
+	case PCXHR_CLOCK_TYPE_WORD_CLOCK:
+		val = PCXHR_FREQ_WORD_CLOCK;
+		break;
+	case PCXHR_CLOCK_TYPE_AES_SYNC:
+		val = PCXHR_FREQ_SYNC_AES;
+		break;
+	case PCXHR_CLOCK_TYPE_AES_1:
+		val = PCXHR_FREQ_AES_1;
+		break;
+	case PCXHR_CLOCK_TYPE_AES_2:
+		val = PCXHR_FREQ_AES_2;
+		break;
+	case PCXHR_CLOCK_TYPE_AES_3:
+		val = PCXHR_FREQ_AES_3;
+		break;
+	case PCXHR_CLOCK_TYPE_AES_4:
+		val = PCXHR_FREQ_AES_4;
+		break;
+	default:
+		return -EINVAL;
 	}
 	*reg = val;
 	*freq = realfreq;
@@ -216,14 +294,13 @@
 }
 
 
-int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
+static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr,
+			       unsigned int rate,
+			       int *changed)
 {
 	unsigned int val, realfreq, speed;
 	struct pcxhr_rmh rmh;
-	int err, changed;
-
-	if (rate == 0)
-		return 0; /* nothing to do */
+	int err;
 
 	err = pcxhr_get_clock_reg(mgr, rate, &val, &realfreq);
 	if (err)
@@ -237,13 +314,17 @@
 	else
 		speed = 2;	/* quad speed */
 	if (mgr->codec_speed != speed) {
-		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);	/* mute outputs */
+		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* mute outputs */
 		rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
+		if (DSP_EXT_CMD_SET(mgr)) {
+			rmh.cmd[1]  = 1;
+			rmh.cmd_len = 2;
+		}
 		err = pcxhr_send_msg(mgr, &rmh);
 		if (err)
 			return err;
 
-		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);	/* set speed ratio */
+		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set speed ratio */
 		rmh.cmd[0] |= IO_NUM_SPEED_RATIO;
 		rmh.cmd[1] = speed;
 		rmh.cmd_len = 2;
@@ -253,25 +334,57 @@
 	}
 	/* set the new frequency */
 	snd_printdd("clock register : set %x\n", val);
-	err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK, val, &changed);
+	err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK,
+					  val, changed);
 	if (err)
 		return err;
+
 	mgr->sample_rate_real = realfreq;
 	mgr->cur_clock_type = mgr->use_clock_type;
 
 	/* unmute after codec speed modes */
 	if (mgr->codec_speed != speed) {
-		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);	/* unmute outputs */
+		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* unmute outputs */
 		rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
+		if (DSP_EXT_CMD_SET(mgr)) {
+			rmh.cmd[1]  = 1;
+			rmh.cmd_len = 2;
+		}
 		err = pcxhr_send_msg(mgr, &rmh);
 		if (err)
 			return err;
-		mgr->codec_speed = speed;			/* save new codec speed */
+		mgr->codec_speed = speed;	/* save new codec speed */
 	}
 
+	snd_printdd("pcxhr_sub_set_clock to %dHz (realfreq=%d)\n",
+		    rate, realfreq);
+	return 0;
+}
+
+#define PCXHR_MODIFY_CLOCK_S_BIT	0x04
+
+#define PCXHR_IRQ_TIMER_FREQ		92000
+#define PCXHR_IRQ_TIMER_PERIOD		48
+
+int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
+{
+	struct pcxhr_rmh rmh;
+	int err, changed;
+
+	if (rate == 0)
+		return 0; /* nothing to do */
+
+	if (mgr->is_hr_stereo)
+		err = hr222_sub_set_clock(mgr, rate, &changed);
+	else
+		err = pcxhr_sub_set_clock(mgr, rate, &changed);
+
+	if (err)
+		return err;
+
 	if (changed) {
 		pcxhr_init_rmh(&rmh, CMD_MODIFY_CLOCK);
-		rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT;		/* resync fifos  */
+		rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT; /* resync fifos  */
 		if (rate < PCXHR_IRQ_TIMER_FREQ)
 			rmh.cmd[1] = PCXHR_IRQ_TIMER_PERIOD;
 		else
@@ -282,26 +395,39 @@
 		if (err)
 			return err;
 	}
-	snd_printdd("pcxhr_set_clock to %dHz (realfreq=%d)\n", rate, realfreq);
 	return 0;
 }
 
 
-int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type,
-			     int *sample_rate)
+static int pcxhr_sub_get_external_clock(struct pcxhr_mgr *mgr,
+					enum pcxhr_clock_type clock_type,
+					int *sample_rate)
 {
 	struct pcxhr_rmh rmh;
 	unsigned char reg;
 	int err, rate;
 
 	switch (clock_type) {
-	case PCXHR_CLOCK_TYPE_WORD_CLOCK :	reg = REG_STATUS_WORD_CLOCK;	break;
-	case PCXHR_CLOCK_TYPE_AES_SYNC :	reg = REG_STATUS_AES_SYNC;	break;
-	case PCXHR_CLOCK_TYPE_AES_1 :		reg = REG_STATUS_AES_1;		break;
-	case PCXHR_CLOCK_TYPE_AES_2 :		reg = REG_STATUS_AES_2;		break;
-	case PCXHR_CLOCK_TYPE_AES_3 :		reg = REG_STATUS_AES_3;		break;
-	case PCXHR_CLOCK_TYPE_AES_4 :		reg = REG_STATUS_AES_4;		break;
-	default : return -EINVAL;
+	case PCXHR_CLOCK_TYPE_WORD_CLOCK:
+		reg = REG_STATUS_WORD_CLOCK;
+		break;
+	case PCXHR_CLOCK_TYPE_AES_SYNC:
+		reg = REG_STATUS_AES_SYNC;
+		break;
+	case PCXHR_CLOCK_TYPE_AES_1:
+		reg = REG_STATUS_AES_1;
+		break;
+	case PCXHR_CLOCK_TYPE_AES_2:
+		reg = REG_STATUS_AES_2;
+		break;
+	case PCXHR_CLOCK_TYPE_AES_3:
+		reg = REG_STATUS_AES_3;
+		break;
+	case PCXHR_CLOCK_TYPE_AES_4:
+		reg = REG_STATUS_AES_4;
+		break;
+	default:
+		return -EINVAL;
 	}
 	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
 	rmh.cmd_len = 2;
@@ -311,7 +437,7 @@
 		err = pcxhr_send_msg(mgr, &rmh);
 		if (err)
 			return err;
-		udelay(100);		/* wait minimum 2 sample_frames at 32kHz ! */
+		udelay(100);	/* wait minimum 2 sample_frames at 32kHz ! */
 		mgr->last_reg_stat = reg;
 	}
 	rmh.cmd[1]  = REG_STATUS_CURRENT;
@@ -336,6 +462,18 @@
 }
 
 
+int pcxhr_get_external_clock(struct pcxhr_mgr *mgr,
+			     enum pcxhr_clock_type clock_type,
+			     int *sample_rate)
+{
+	if (mgr->is_hr_stereo)
+		return hr222_get_external_clock(mgr, clock_type,
+						sample_rate);
+	else
+		return pcxhr_sub_get_external_clock(mgr, clock_type,
+						    sample_rate);
+}
+
 /*
  *  start or stop playback/capture substream
  */
@@ -350,7 +488,8 @@
 		start = 1;
 	else {
 		if (stream->status != PCXHR_STREAM_STATUS_SCHEDULE_STOP) {
-			snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state CANNOT be stopped\n");
+			snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state "
+				   "CANNOT be stopped\n");
 			return -EINVAL;
 		}
 		start = 0;
@@ -359,11 +498,12 @@
 		return -EINVAL;
 
 	stream->timer_abs_periods = 0;
-	stream->timer_period_frag = 0;            /* reset theoretical stream pos */
+	stream->timer_period_frag = 0;	/* reset theoretical stream pos */
 	stream->timer_buf_periods = 0;
 	stream->timer_is_synced = 0;
 
-	stream_mask = stream->pipe->is_capture ? 1 : 1<<stream->substream->number;
+	stream_mask =
+	  stream->pipe->is_capture ? 1 : 1<<stream->substream->number;
 
 	pcxhr_init_rmh(&rmh, start ? CMD_START_STREAM : CMD_STOP_STREAM);
 	pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture,
@@ -373,8 +513,10 @@
 
 	err = pcxhr_send_msg(chip->mgr, &rmh);
 	if (err)
-		snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n", err);
-	stream->status = start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED;
+		snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n",
+			   err);
+	stream->status =
+	  start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED;
 	return err;
 }
 
@@ -399,13 +541,15 @@
 		header = HEADER_FMT_BASE_LIN;
 		break;
 	case SNDRV_PCM_FORMAT_S16_LE:
-		header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS | HEADER_FMT_INTEL;
+		header = HEADER_FMT_BASE_LIN |
+			 HEADER_FMT_16BITS | HEADER_FMT_INTEL;
 		break;
 	case SNDRV_PCM_FORMAT_S16_BE:
 		header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS;
 		break;
 	case SNDRV_PCM_FORMAT_S24_3LE:
-		header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS | HEADER_FMT_INTEL;
+		header = HEADER_FMT_BASE_LIN |
+			 HEADER_FMT_24BITS | HEADER_FMT_INTEL;
 		break;
 	case SNDRV_PCM_FORMAT_S24_3BE:
 		header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS;
@@ -414,7 +558,8 @@
 		header = HEADER_FMT_BASE_FLOAT | HEADER_FMT_INTEL;
 		break;
 	default:
-		snd_printk(KERN_ERR "error pcxhr_set_format() : unknown format\n");
+		snd_printk(KERN_ERR
+			   "error pcxhr_set_format() : unknown format\n");
 		return -EINVAL;
 	}
 	chip = snd_pcm_substream_chip(stream->substream);
@@ -432,14 +577,31 @@
 	is_capture = stream->pipe->is_capture;
 	stream_num = is_capture ? 0 : stream->substream->number;
 
-	pcxhr_init_rmh(&rmh, is_capture ? CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT);
-	pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0);
-	if (is_capture)
-		rmh.cmd[0] |= 1<<12;
+	pcxhr_init_rmh(&rmh, is_capture ?
+		       CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT);
+	pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio,
+				  stream_num, 0);
+	if (is_capture) {
+		/* bug with old dsp versions: */
+		/* bit 12 also sets the format of the playback stream */
+		if (DSP_EXT_CMD_SET(chip->mgr))
+			rmh.cmd[0] |= 1<<10;
+		else
+			rmh.cmd[0] |= 1<<12;
+	}
 	rmh.cmd[1] = 0;
-	rmh.cmd[2] = header >> 8;
-	rmh.cmd[3] = (header & 0xff) << 16;
-	rmh.cmd_len = 4;
+	rmh.cmd_len = 2;
+	if (DSP_EXT_CMD_SET(chip->mgr)) {
+		/* add channels and set bit 19 if channels>2 */
+		rmh.cmd[1] = stream->channels;
+		if (!is_capture) {
+			/* playback : add channel mask to command */
+			rmh.cmd[2] = (stream->channels == 1) ? 0x01 : 0x03;
+			rmh.cmd_len = 3;
+		}
+	}
+	rmh.cmd[rmh.cmd_len++] = header >> 8;
+	rmh.cmd[rmh.cmd_len++] = (header & 0xff) << 16;
 	err = pcxhr_send_msg(chip->mgr, &rmh);
 	if (err)
 		snd_printk(KERN_ERR "ERROR pcxhr_set_format err=%x;\n", err);
@@ -456,30 +618,38 @@
 	is_capture = (subs->stream == SNDRV_PCM_STREAM_CAPTURE);
 	stream_num = is_capture ? 0 : subs->number;
 
-	snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : addr(%p) bytes(%zx) subs(%d)\n",
+	snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : "
+		    "addr(%p) bytes(%zx) subs(%d)\n",
 		    is_capture ? 'c' : 'p',
 		    chip->chip_idx, (void *)(long)subs->runtime->dma_addr,
 		    subs->runtime->dma_bytes, subs->number);
 
 	pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS);
-	pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0);
+	pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio,
+				  stream_num, 0);
 
 	/* max buffer size is 2 MByte */
 	snd_BUG_ON(subs->runtime->dma_bytes >= 0x200000);
-	rmh.cmd[1] = subs->runtime->dma_bytes * 8;		/* size in bits */
-	rmh.cmd[2] = subs->runtime->dma_addr >> 24;		/* most significant byte */
-	rmh.cmd[2] |= 1<<19;					/* this is a circular buffer */
-	rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD;	/* least 3 significant bytes */
+	/* size in bits */
+	rmh.cmd[1] = subs->runtime->dma_bytes * 8;
+	/* most significant byte */
+	rmh.cmd[2] = subs->runtime->dma_addr >> 24;
+	/* this is a circular buffer */
+	rmh.cmd[2] |= 1<<19;
+	/* least 3 significant bytes */
+	rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD;
 	rmh.cmd_len = 4;
 	err = pcxhr_send_msg(chip->mgr, &rmh);
 	if (err)
-		snd_printk(KERN_ERR "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err);
+		snd_printk(KERN_ERR
+			   "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err);
 	return err;
 }
 
 
 #if 0
-static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream, snd_pcm_uframes_t *sample_count)
+static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream,
+				   snd_pcm_uframes_t *sample_count)
 {
 	struct pcxhr_rmh rmh;
 	int err;
@@ -533,8 +703,8 @@
 		for (j = 0; j < chip->nb_streams_play; j++) {
 			if (pcxhr_stream_scheduled_get_pipe(&chip->playback_stream[j], &pipe)) {
 				playback_mask |= (1 << pipe->first_audio);
-				break;	/* add only once, as all playback streams of
-					 * one chip use the same pipe
+				break;	/* add only once, as all playback
+					 * streams of one chip use the same pipe
 					 */
 			}
 		}
@@ -545,19 +715,21 @@
 		return;
 	}
 
-	snd_printdd("pcxhr_trigger_tasklet : playback_mask=%x capture_mask=%x\n",
+	snd_printdd("pcxhr_trigger_tasklet : "
+		    "playback_mask=%x capture_mask=%x\n",
 		    playback_mask, capture_mask);
 
 	/* synchronous stop of all the pipes concerned */
 	err = pcxhr_set_pipe_state(mgr,  playback_mask, capture_mask, 0);
 	if (err) {
 		mutex_unlock(&mgr->setup_mutex);
-		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error stop pipes (P%x C%x)\n",
+		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : "
+			   "error stop pipes (P%x C%x)\n",
 			   playback_mask, capture_mask);
 		return;
 	}
 
-	/* unfortunately the dsp lost format and buffer info with the stop pipe */
+	/* the dsp lost format and buffer info with the stop pipe */
 	for (i = 0; i < mgr->num_cards; i++) {
 		struct pcxhr_stream *stream;
 		chip = mgr->chip[i];
@@ -596,12 +768,15 @@
 	err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
 	if (err) {
 		mutex_unlock(&mgr->setup_mutex);
-		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error start pipes (P%x C%x)\n",
+		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : "
+			   "error start pipes (P%x C%x)\n",
 			   playback_mask, capture_mask);
 		return;
 	}
 
-	/* put the streams into the running state now (increment pointer by interrupt) */
+	/* put the streams into the running state now
+	 * (increment pointer by interrupt)
+	 */
 	spin_lock_irqsave(&mgr->lock, flags);
 	for ( i =0; i < mgr->num_cards; i++) {
 		struct pcxhr_stream *stream;
@@ -615,7 +790,7 @@
 			stream = &chip->playback_stream[j];
 			if (stream->status == PCXHR_STREAM_STATUS_STARTED) {
 				/* playback will already have advanced ! */
-				stream->timer_period_frag += PCXHR_GRANULARITY;
+				stream->timer_period_frag += mgr->granularity;
 				stream->status = PCXHR_STREAM_STATUS_RUNNING;
 			}
 		}
@@ -653,7 +828,7 @@
 					PCXHR_STREAM_STATUS_SCHEDULE_RUN;
 				snd_pcm_trigger_done(s, subs);
 			}
-			tasklet_hi_schedule(&chip->mgr->trigger_taskq);
+			tasklet_schedule(&chip->mgr->trigger_taskq);
 		} else {
 			stream = subs->runtime->private_data;
 			snd_printdd("Only one Substream %c %d\n",
@@ -697,12 +872,14 @@
 
 	pcxhr_init_rmh(&rmh, CMD_SET_TIMER_INTERRUPT);
 	if (start) {
-		mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;	/* last dsp time invalid */
-		rmh.cmd[0] |= PCXHR_GRANULARITY;
+		/* last dsp time invalid */
+		mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
+		rmh.cmd[0] |= mgr->granularity;
 	}
 	err = pcxhr_send_msg(mgr, &rmh);
 	if (err < 0)
-		snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n", err);
+		snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n",
+			   err);
 	return err;
 }
 
@@ -713,38 +890,16 @@
 {
 	struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);
 	struct pcxhr_mgr *mgr = chip->mgr;
-	/*
-	struct pcxhr_stream *stream = (pcxhr_stream_t*)subs->runtime->private_data;
-	*/
 	int err = 0;
 
 	snd_printdd("pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n",
 		    subs->runtime->period_size, subs->runtime->periods,
 		    subs->runtime->buffer_size);
 
-	/*
-	if(subs->runtime->period_size <= PCXHR_GRANULARITY) {
-		snd_printk(KERN_ERR "pcxhr_prepare : error period_size too small (%x)\n",
-			   (unsigned int)subs->runtime->period_size);
-		return -EINVAL;
-	}
-	*/
-
 	mutex_lock(&mgr->setup_mutex);
 
 	do {
-		/* if the stream was stopped before, format and buffer were reset */
-		/*
-		if(stream->status == PCXHR_STREAM_STATUS_STOPPED) {
-			err = pcxhr_set_format(stream);
-			if(err) break;
-			err = pcxhr_update_r_buffer(stream);
-			if(err) break;
-		}
-		*/
-
 		/* only the first stream can choose the sample rate */
-		/* the further opened streams will be limited to its frequency (see open) */
 		/* set the clock only once (first stream) */
 		if (mgr->sample_rate != subs->runtime->rate) {
 			err = pcxhr_set_clock(mgr, subs->runtime->rate);
@@ -787,22 +942,9 @@
 	stream->channels = channels;
 	stream->format = format;
 
-	/* set the format to the board */
-	/*
-	err = pcxhr_set_format(stream);
-	if(err) {
-		mutex_unlock(&mgr->setup_mutex);
-		return err;
-	}
-	*/
 	/* allocate buffer */
 	err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw));
 
-	/*
-	if (err > 0) {
-		err = pcxhr_update_r_buffer(stream);
-	}
-	*/
 	mutex_unlock(&mgr->setup_mutex);
 
 	return err;
@@ -820,14 +962,18 @@
  */
 static struct snd_pcm_hardware pcxhr_caps =
 {
-	.info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-			      SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-			      0 /*SNDRV_PCM_INFO_PAUSE*/),
-	.formats	  = ( SNDRV_PCM_FMTBIT_U8 |
-			      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
-			      SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
-			      SNDRV_PCM_FMTBIT_FLOAT_LE ),
-	.rates            = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+	.info             = (SNDRV_PCM_INFO_MMAP |
+			     SNDRV_PCM_INFO_INTERLEAVED |
+			     SNDRV_PCM_INFO_MMAP_VALID |
+			     SNDRV_PCM_INFO_SYNC_START),
+	.formats	  = (SNDRV_PCM_FMTBIT_U8 |
+			     SNDRV_PCM_FMTBIT_S16_LE |
+			     SNDRV_PCM_FMTBIT_S16_BE |
+			     SNDRV_PCM_FMTBIT_S24_3LE |
+			     SNDRV_PCM_FMTBIT_S24_3BE |
+			     SNDRV_PCM_FMTBIT_FLOAT_LE),
+	.rates            = (SNDRV_PCM_RATE_CONTINUOUS |
+			     SNDRV_PCM_RATE_8000_192000),
 	.rate_min         = 8000,
 	.rate_max         = 192000,
 	.channels_min     = 1,
@@ -847,6 +993,7 @@
 	struct pcxhr_mgr       *mgr = chip->mgr;
 	struct snd_pcm_runtime *runtime = subs->runtime;
 	struct pcxhr_stream    *stream;
+	int err;
 
 	mutex_lock(&mgr->setup_mutex);
 
@@ -874,6 +1021,18 @@
 		return -EBUSY;
 	}
 
+	/* float format support is in some cases buggy on stereo cards */
+	if (mgr->is_hr_stereo)
+		runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_FLOAT_LE;
+
+	/* buffer-size should better be multiple of period-size */
+	err = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (err < 0) {
+		mutex_unlock(&mgr->setup_mutex);
+		return err;
+	}
+
 	/* if a sample rate is already used or fixed by external clock,
 	 * the stream cannot change
 	 */
@@ -889,7 +1048,8 @@
 				mutex_unlock(&mgr->setup_mutex);
 				return -EBUSY;
 			}
-			runtime->hw.rate_min = runtime->hw.rate_max = external_rate;
+			runtime->hw.rate_min = external_rate;
+			runtime->hw.rate_max = external_rate;
 		}
 	}
 
@@ -899,9 +1059,11 @@
 
 	runtime->private_data = stream;
 
-	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4);
-	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
-
+	/* better get a divisor of granularity values (96 or 192) */
+	snd_pcm_hw_constraint_step(runtime, 0,
+				   SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
+	snd_pcm_hw_constraint_step(runtime, 0,
+				   SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
 	snd_pcm_set_sync(subs);
 
 	mgr->ref_count_rate++;
@@ -919,11 +1081,12 @@
 
 	mutex_lock(&mgr->setup_mutex);
 
-	snd_printdd("pcxhr_close chip%d subs%d\n", chip->chip_idx, subs->number);
+	snd_printdd("pcxhr_close chip%d subs%d\n",
+		    chip->chip_idx, subs->number);
 
 	/* sample rate released */
 	if (--mgr->ref_count_rate == 0) {
-		mgr->sample_rate = 0;		/* the sample rate is no more locked */
+		mgr->sample_rate = 0;	/* the sample rate is no more locked */
 		pcxhr_hardware_timer(mgr, 0);	/* stop the DSP-timer */
 	}
 
@@ -1016,7 +1179,8 @@
 
 /*
  */
-static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, int idx)
+static int __devinit pcxhr_create(struct pcxhr_mgr *mgr,
+				  struct snd_card *card, int idx)
 {
 	int err;
 	struct snd_pcxhr *chip;
@@ -1024,7 +1188,7 @@
 		.dev_free = pcxhr_chip_dev_free,
 	};
 
-	mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 	if (! chip) {
 		snd_printk(KERN_ERR "cannot allocate chip\n");
 		return -ENOMEM;
@@ -1040,7 +1204,7 @@
 
 	if (idx < mgr->capture_chips) {
 		if (mgr->mono_capture)
-			chip->nb_streams_capt = 2;	/* 2 mono streams (left+right) */
+			chip->nb_streams_capt = 2;	/* 2 mono streams */
 		else
 			chip->nb_streams_capt = 1;	/* or 1 stereo stream */
 	}
@@ -1050,13 +1214,15 @@
 		return err;
 	}
 
+	mgr->chip[idx] = chip;
 	snd_card_set_dev(card, &mgr->pci->dev);
 
 	return 0;
 }
 
 /* proc interface */
-static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
+static void pcxhr_proc_info(struct snd_info_entry *entry,
+			    struct snd_info_buffer *buffer)
 {
 	struct snd_pcxhr *chip = entry->private_data;
 	struct pcxhr_mgr *mgr = chip->mgr;
@@ -1069,8 +1235,10 @@
 		short ver_maj = (mgr->dsp_version >> 16) & 0xff;
 		short ver_min = (mgr->dsp_version >> 8) & 0xff;
 		short ver_build = mgr->dsp_version & 0xff;
-		snd_iprintf(buffer, "module version %s\n", PCXHR_DRIVER_VERSION_STRING);
-		snd_iprintf(buffer, "dsp version %d.%d.%d\n", ver_maj, ver_min, ver_build);
+		snd_iprintf(buffer, "module version %s\n",
+			    PCXHR_DRIVER_VERSION_STRING);
+		snd_iprintf(buffer, "dsp version %d.%d.%d\n",
+			    ver_maj, ver_min, ver_build);
 		if (mgr->board_has_analog)
 			snd_iprintf(buffer, "analog io available\n");
 		else
@@ -1084,18 +1252,22 @@
 			if (ref > 0) {
 				if (mgr->sample_rate_real != 0 &&
 				    mgr->sample_rate_real != 48000) {
-					ref = (ref * 48000) / mgr->sample_rate_real;
-					if (mgr->sample_rate_real >= PCXHR_IRQ_TIMER_FREQ)
+					ref = (ref * 48000) /
+					  mgr->sample_rate_real;
+					if (mgr->sample_rate_real >=
+					    PCXHR_IRQ_TIMER_FREQ)
 						ref *= 2;
 				}
 				cur = 100 - (100 * cur) / ref;
 				snd_iprintf(buffer, "cpu load    %d%%\n", cur);
-				snd_iprintf(buffer, "buffer pool %d/%d kWords\n",
+				snd_iprintf(buffer, "buffer pool %d/%d\n",
 					    rmh.stat[2], rmh.stat[3]);
 			}
 		}
-		snd_iprintf(buffer, "dma granularity : %d\n", PCXHR_GRANULARITY);
-		snd_iprintf(buffer, "dsp time errors : %d\n", mgr->dsp_time_err);
+		snd_iprintf(buffer, "dma granularity : %d\n",
+			    mgr->granularity);
+		snd_iprintf(buffer, "dsp time errors : %d\n",
+			    mgr->dsp_time_err);
 		snd_iprintf(buffer, "dsp async pipe xrun errors : %d\n",
 			    mgr->async_err_pipe_xrun);
 		snd_iprintf(buffer, "dsp async stream xrun errors : %d\n",
@@ -1110,33 +1282,52 @@
 		rmh.cmd_idx = CMD_LAST_INDEX;
 		if( ! pcxhr_send_msg(mgr, &rmh) ) {
 			int i;
+			if (rmh.stat_len > 8)
+				rmh.stat_len = 8;
 			for (i = 0; i < rmh.stat_len; i++)
-				snd_iprintf(buffer, "debug[%02d] = %06x\n", i,  rmh.stat[i]);
+				snd_iprintf(buffer, "debug[%02d] = %06x\n",
+					    i,  rmh.stat[i]);
 		}
 	} else
 		snd_iprintf(buffer, "no firmware loaded\n");
 	snd_iprintf(buffer, "\n");
 }
-static void pcxhr_proc_sync(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
+static void pcxhr_proc_sync(struct snd_info_entry *entry,
+			    struct snd_info_buffer *buffer)
 {
 	struct snd_pcxhr *chip = entry->private_data;
 	struct pcxhr_mgr *mgr = chip->mgr;
-	static char *texts[7] = {
-		"Internal", "Word", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4"
+	static const char *textsHR22[3] = {
+		"Internal", "AES Sync", "AES 1"
 	};
+	static const char *textsPCXHR[7] = {
+		"Internal", "Word", "AES Sync",
+		"AES 1", "AES 2", "AES 3", "AES 4"
+	};
+	const char **texts;
+	int max_clock;
+	if (mgr->is_hr_stereo) {
+		texts = textsHR22;
+		max_clock = HR22_CLOCK_TYPE_MAX;
+	} else {
+		texts = textsPCXHR;
+		max_clock = PCXHR_CLOCK_TYPE_MAX;
+	}
 
 	snd_iprintf(buffer, "\n%s\n", mgr->longname);
-	snd_iprintf(buffer, "Current Sample Clock\t: %s\n", texts[mgr->cur_clock_type]);
-	snd_iprintf(buffer, "Current Sample Rate\t= %d\n", mgr->sample_rate_real);
-
+	snd_iprintf(buffer, "Current Sample Clock\t: %s\n",
+		    texts[mgr->cur_clock_type]);
+	snd_iprintf(buffer, "Current Sample Rate\t= %d\n",
+		    mgr->sample_rate_real);
 	/* commands available when embedded DSP is running */
 	if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
 		int i, err, sample_rate;
-		for (i = PCXHR_CLOCK_TYPE_WORD_CLOCK; i< (3 + mgr->capture_chips); i++) {
+		for (i = 1; i <= max_clock; i++) {
 			err = pcxhr_get_external_clock(mgr, i, &sample_rate);
 			if (err)
 				break;
-			snd_iprintf(buffer, "%s Clock\t\t= %d\n", texts[i], sample_rate);
+			snd_iprintf(buffer, "%s Clock\t\t= %d\n",
+				    texts[i], sample_rate);
 		}
 	} else
 		snd_iprintf(buffer, "no firmware loaded\n");
@@ -1194,7 +1385,8 @@
 /*
  *    probe function - creates the card manager
  */
-static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+static int __devinit pcxhr_probe(struct pci_dev *pci,
+				 const struct pci_device_id *pci_id)
 {
 	static int dev;
 	struct pcxhr_mgr *mgr;
@@ -1217,7 +1409,8 @@
 
 	/* check if we can restrict PCI DMA transfers to 32 bits */
 	if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0) {
-		snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
+		snd_printk(KERN_ERR "architecture does not support "
+			   "32bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
 	}
@@ -1234,11 +1427,25 @@
 		pci_disable_device(pci);
 		return -ENODEV;
 	}
-	card_name = pcxhr_board_params[pci_id->driver_data].board_name;
-	mgr->playback_chips = pcxhr_board_params[pci_id->driver_data].playback_chips;
-	mgr->capture_chips  = pcxhr_board_params[pci_id->driver_data].capture_chips;
-	mgr->firmware_num  = pcxhr_board_params[pci_id->driver_data].firmware_num;
+	card_name =
+		pcxhr_board_params[pci_id->driver_data].board_name;
+	mgr->playback_chips =
+		pcxhr_board_params[pci_id->driver_data].playback_chips;
+	mgr->capture_chips  =
+		pcxhr_board_params[pci_id->driver_data].capture_chips;
+	mgr->fw_file_set =
+		pcxhr_board_params[pci_id->driver_data].fw_file_set;
+	mgr->firmware_num  =
+		pcxhr_board_params[pci_id->driver_data].firmware_num;
 	mgr->mono_capture = mono[dev];
+	mgr->is_hr_stereo = (mgr->playback_chips == 1);
+	mgr->board_has_aes1 = PCXHR_BOARD_HAS_AES1(mgr);
+	mgr->board_aes_in_192k = !PCXHR_BOARD_AESIN_NO_192K(mgr);
+
+	if (mgr->is_hr_stereo)
+		mgr->granularity = PCXHR_GRANULARITY_HR22;
+	else
+		mgr->granularity = PCXHR_GRANULARITY;
 
 	/* resource assignment */
 	if ((err = pci_request_regions(pci, card_name)) < 0) {
@@ -1261,7 +1468,8 @@
 	mgr->irq = pci->irq;
 
 	sprintf(mgr->shortname, "Digigram %s", card_name);
-	sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i", mgr->shortname,
+	sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i",
+		mgr->shortname,
 		mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq);
 
 	/* ISR spinlock  */
@@ -1272,10 +1480,14 @@
 	mutex_init(&mgr->setup_mutex);
 
 	/* init taslket */
-	tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, (unsigned long) mgr);
-	tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet, (unsigned long) mgr);
+	tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet,
+		     (unsigned long) mgr);
+	tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet,
+		     (unsigned long) mgr);
+
 	mgr->prmh = kmalloc(sizeof(*mgr->prmh) + 
-			    sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - PCXHR_SIZE_MAX_STATUS),
+			    sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS -
+					   PCXHR_SIZE_MAX_STATUS),
 			    GFP_KERNEL);
 	if (! mgr->prmh) {
 		pcxhr_free(mgr);
@@ -1296,7 +1508,8 @@
 		else
 			idx = index[dev] + i;
 
-		snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : card_name, i);
+		snprintf(tmpid, sizeof(tmpid), "%s-%d",
+			 id[dev] ? id[dev] : card_name, i);
 		card = snd_card_new(idx, tmpid, THIS_MODULE, 0);
 
 		if (! card) {
@@ -1310,6 +1523,7 @@
 		sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i);
 
 		if ((err = pcxhr_create(mgr, card, i)) < 0) {
+			snd_card_free(card);
 			pcxhr_free(mgr);
 			return err;
 		}
diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h
index 6520647..84131a9 100644
--- a/sound/pci/pcxhr/pcxhr.h
+++ b/sound/pci/pcxhr/pcxhr.h
@@ -27,15 +27,18 @@
 #include <linux/mutex.h>
 #include <sound/pcm.h>
 
-#define PCXHR_DRIVER_VERSION		0x000804	/* 0.8.4 */
-#define PCXHR_DRIVER_VERSION_STRING	"0.8.4"		/* 0.8.4 */
+#define PCXHR_DRIVER_VERSION		0x000905	/* 0.9.5 */
+#define PCXHR_DRIVER_VERSION_STRING	"0.9.5"		/* 0.9.5 */
 
 
-#define PCXHR_MAX_CARDS			6
-#define PCXHR_PLAYBACK_STREAMS		4
+#define PCXHR_MAX_CARDS		6
+#define PCXHR_PLAYBACK_STREAMS	4
 
-#define PCXHR_GRANULARITY		96	/* transfer granularity (should be min 96 and multiple of 48) */
-#define PCXHR_GRANULARITY_MIN		96	/* transfer granularity of pipes and the dsp time (MBOX4) */
+#define PCXHR_GRANULARITY	96	/* min 96 and multiple of 48 */
+/* transfer granularity of pipes and the dsp time (MBOX4) */
+#define PCXHR_GRANULARITY_MIN	96
+/* TODO : granularity could be 64 or 128 */
+#define PCXHR_GRANULARITY_HR22	192	/* granularity for stereo cards */
 
 struct snd_pcxhr;
 struct pcxhr_mgr;
@@ -51,6 +54,11 @@
 	PCXHR_CLOCK_TYPE_AES_2,
 	PCXHR_CLOCK_TYPE_AES_3,
 	PCXHR_CLOCK_TYPE_AES_4,
+	PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4,
+	HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL,
+	HR22_CLOCK_TYPE_AES_SYNC,
+	HR22_CLOCK_TYPE_AES_1,
+	HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1,
 };
 
 struct pcxhr_mgr {
@@ -61,6 +69,8 @@
 
 	int irq;
 
+	int granularity;
+
 	/* card access with 1 mem bar and 2 io bar's */
 	unsigned long port[3];
 
@@ -83,11 +93,16 @@
 	/* hardware interface */
 	unsigned int dsp_loaded;	/* bit flags of loaded dsp indices */
 	unsigned int dsp_version;	/* read from embedded once firmware is loaded */
-	int board_has_analog;		/* if 0 the board is digital only */
-	int mono_capture;		/* if 1 the board does mono capture */
-	int playback_chips;		/* 4 or 6 */
-	int capture_chips;		/* 4 or 1 */
-	int firmware_num;		/* 41 or 42 */
+	int playback_chips;
+	int capture_chips;
+	int fw_file_set;
+	int firmware_num;
+	int is_hr_stereo:1;
+	int board_has_aes1:1;	/* if 1 board has AES1 plug and SRC */
+	int board_has_analog:1;	/* if 0 the board is digital only */
+	int board_has_mic:1;	/* if 1 the board has microphone input */
+	int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */
+	int mono_capture:1;	/* if 1 the board does mono capture */
 
 	struct snd_dma_buffer hostport;
 
@@ -106,6 +121,9 @@
 	int async_err_stream_xrun;
 	int async_err_pipe_xrun;
 	int async_err_other_last;
+
+	unsigned char xlx_cfg;		/* copy of PCXHR_XLX_CFG register */
+	unsigned char xlx_selmic;	/* copy of PCXHR_XLX_SELMIC register */
 };
 
 
@@ -155,24 +173,30 @@
 
 	struct snd_pcm *pcm;		/* PCM */
 
-	struct pcxhr_pipe playback_pipe;		/* 1 stereo pipe only */
-	struct pcxhr_pipe capture_pipe[2];		/* 1 stereo pipe or 2 mono pipes */
+	struct pcxhr_pipe playback_pipe;	/* 1 stereo pipe only */
+	struct pcxhr_pipe capture_pipe[2];	/* 1 stereo or 2 mono pipes */
 
 	struct pcxhr_stream playback_stream[PCXHR_PLAYBACK_STREAMS];
-	struct pcxhr_stream capture_stream[2];	/* 1 stereo stream or 2 mono streams */
+	struct pcxhr_stream capture_stream[2];	/* 1 stereo or 2 mono streams */
 	int nb_streams_play;
 	int nb_streams_capt;
 
-	int analog_playback_active[2];		/* Mixer : Master Playback active (!mute) */
-	int analog_playback_volume[2];		/* Mixer : Master Playback Volume */
-	int analog_capture_volume[2];		/* Mixer : Master Capture Volume */
-	int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2];	/* Mixer : Digital Playback Active [streams][stereo]*/
-	int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2];	/* Mixer : Digital Playback Volume [streams][stereo]*/
-	int digital_capture_volume[2];		/* Mixer : Digital Capture Volume [stereo] */
-	int monitoring_active[2];		/* Mixer : Monitoring Active */
-	int monitoring_volume[2];		/* Mixer : Monitoring Volume */
-	int audio_capture_source;		/* Mixer : Audio Capture Source */
-	unsigned char aes_bits[5];		/* Mixer : IEC958_AES bits */
+	int analog_playback_active[2];	/* Mixer : Master Playback !mute */
+	int analog_playback_volume[2];	/* Mixer : Master Playback Volume */
+	int analog_capture_volume[2];	/* Mixer : Master Capture Volume */
+	int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2];
+	int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2];
+	int digital_capture_volume[2];	/* Mixer : Digital Capture Volume */
+	int monitoring_active[2];	/* Mixer : Monitoring Active */
+	int monitoring_volume[2];	/* Mixer : Monitoring Volume */
+	int audio_capture_source;	/* Mixer : Audio Capture Source */
+	int mic_volume;			/* used by cards with MIC only */
+	int mic_boost;			/* used by cards with MIC only */
+	int mic_active;			/* used by cards with MIC only */
+	int analog_capture_active;	/* used by cards with MIC only */
+	int phantom_power;		/* used by cards with MIC only */
+
+	unsigned char aes_bits[5];	/* Mixer : IEC958_AES bits */
 };
 
 struct pcxhr_hostport
@@ -184,6 +208,8 @@
 /* exported */
 int pcxhr_create_pcm(struct snd_pcxhr *chip);
 int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate);
-int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type, int *sample_rate);
+int pcxhr_get_external_clock(struct pcxhr_mgr *mgr,
+			     enum pcxhr_clock_type clock_type,
+			     int *sample_rate);
 
 #endif /* __SOUND_PCXHR_H */
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index 7143259..833e718 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -132,13 +132,15 @@
 		*read = PCXHR_INPB(mgr, reg);
 		if ((*read & mask) == bit) {
 			if (i > 100)
-				snd_printdd("ATTENTION! check_reg(%x) loopcount=%d\n",
+				snd_printdd("ATTENTION! check_reg(%x) "
+					    "loopcount=%d\n",
 					    reg, i);
 			return 0;
 		}
 		i++;
 	} while (time_after_eq(end_time, jiffies));
-	snd_printk(KERN_ERR "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=0x%x\n",
+	snd_printk(KERN_ERR
+		   "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n",
 		   reg, mask, *read);
 	return -EIO;
 }
@@ -159,18 +161,22 @@
 #define PCXHR_IT_TEST_XILINX		(0x0000003C | PCXHR_MASK_IT_HF1 | \
 					 PCXHR_MASK_IT_MANAGE_HF5)
 #define PCXHR_IT_DOWNLOAD_BOOT		(0x0000000C | PCXHR_MASK_IT_HF1 | \
-					 PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT)
+					 PCXHR_MASK_IT_MANAGE_HF5 | \
+					 PCXHR_MASK_IT_WAIT)
 #define PCXHR_IT_RESET_BOARD_FUNC	(0x0000000C | PCXHR_MASK_IT_HF0 | \
-					 PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT_EXTRA)
+					 PCXHR_MASK_IT_MANAGE_HF5 | \
+					 PCXHR_MASK_IT_WAIT_EXTRA)
 #define PCXHR_IT_DOWNLOAD_DSP		(0x0000000C | \
-					 PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT)
+					 PCXHR_MASK_IT_MANAGE_HF5 | \
+					 PCXHR_MASK_IT_WAIT)
 #define PCXHR_IT_DEBUG			(0x0000005A | PCXHR_MASK_IT_NO_HF0_HF1)
 #define PCXHR_IT_RESET_SEMAPHORE	(0x0000005C | PCXHR_MASK_IT_NO_HF0_HF1)
 #define PCXHR_IT_MESSAGE		(0x00000074 | PCXHR_MASK_IT_NO_HF0_HF1)
 #define PCXHR_IT_RESET_CHK		(0x00000076 | PCXHR_MASK_IT_NO_HF0_HF1)
 #define PCXHR_IT_UPDATE_RBUFFER		(0x00000078 | PCXHR_MASK_IT_NO_HF0_HF1)
 
-static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atomic)
+static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr,
+			     unsigned int itdsp, int atomic)
 {
 	int err;
 	unsigned char reg;
@@ -178,17 +184,21 @@
 	if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
 		/* clear hf5 bit */
 		PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0,
-			    PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & ~PCXHR_MBOX0_HF5);
+			    PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) &
+			    ~PCXHR_MBOX0_HF5);
 	}
 	if ((itdsp & PCXHR_MASK_IT_NO_HF0_HF1) == 0) {
-		reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ;
+		reg = (PCXHR_ICR_HI08_RREQ |
+		       PCXHR_ICR_HI08_TREQ |
+		       PCXHR_ICR_HI08_HDRQ);
 		if (itdsp & PCXHR_MASK_IT_HF0)
 			reg |= PCXHR_ICR_HI08_HF0;
 		if (itdsp & PCXHR_MASK_IT_HF1)
 			reg |= PCXHR_ICR_HI08_HF1;
 		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
 	}
-	reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) | PCXHR_CVR_HI08_HC);
+	reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) |
+			      PCXHR_CVR_HI08_HC);
 	PCXHR_OUTPB(mgr, PCXHR_DSP_CVR, reg);
 	if (itdsp & PCXHR_MASK_IT_WAIT) {
 		if (atomic)
@@ -211,10 +221,14 @@
 	}
 	if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
 		/* wait for hf5 bit */
-		err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, PCXHR_MBOX0_HF5,
-					  PCXHR_MBOX0_HF5, PCXHR_TIMEOUT_DSP, &reg);
+		err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0,
+					  PCXHR_MBOX0_HF5,
+					  PCXHR_MBOX0_HF5,
+					  PCXHR_TIMEOUT_DSP,
+					  &reg);
 		if (err) {
-			snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT HF5\n");
+			snd_printk(KERN_ERR
+				   "pcxhr_send_it_dsp : TIMEOUT HF5\n");
 			return err;
 		}
 	}
@@ -263,7 +277,8 @@
 /*
  * load the xilinx image
  */
-int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilinx, int second)
+int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr,
+			     const struct firmware *xilinx, int second)
 {
 	unsigned int i;
 	unsigned int chipsc;
@@ -274,7 +289,9 @@
 	/* test first xilinx */
 	chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC);
 	/* REV01 cards do not support the PCXHR_CHIPSC_GPI_USERI bit anymore */
-	/* this bit will always be 1; no possibility to test presence of first xilinx */
+	/* this bit will always be 1;
+	 * no possibility to test presence of first xilinx
+	 */
 	if(second) {
 		if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) {
 			snd_printk(KERN_ERR "error loading first xilinx\n");
@@ -290,7 +307,8 @@
 		data = *image;
 		mask = 0x80;
 		while (mask) {
-			chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN);
+			chipsc &= ~(PCXHR_CHIPSC_DATA_CLK |
+				    PCXHR_CHIPSC_DATA_IN);
 			if (data & mask)
 				chipsc |= PCXHR_CHIPSC_DATA_IN;
 			PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);
@@ -330,15 +348,20 @@
 		data = dsp->data + i;
 		if (i == 0) {
 			/* test data header consistency */
-			len = (unsigned int)((data[0]<<16) + (data[1]<<8) + data[2]);
-			if (len && dsp->size != (len + 2) * 3)
+			len = (unsigned int)((data[0]<<16) +
+					     (data[1]<<8) +
+					     data[2]);
+			if (len && (dsp->size != (len + 2) * 3))
 				return -EINVAL;
 		}
 		/* wait DSP ready for new transfer */
-		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
-					  PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &dummy);
+		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+					  PCXHR_ISR_HI08_TRDY,
+					  PCXHR_ISR_HI08_TRDY,
+					  PCXHR_TIMEOUT_DSP, &dummy);
 		if (err) {
-			snd_printk(KERN_ERR "dsp loading error at position %d\n", i);
+			snd_printk(KERN_ERR
+				   "dsp loading error at position %d\n", i);
 			return err;
 		}
 		/* send host data */
@@ -357,7 +380,8 @@
 /*
  * load the eeprom image
  */
-int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, const struct firmware *eeprom)
+int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr,
+			     const struct firmware *eeprom)
 {
 	int err;
 	unsigned char reg;
@@ -365,7 +389,9 @@
 	/* init value of the ICR register */
 	reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ;
 	if (PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & PCXHR_MBOX0_BOOT_HERE) {
-		/* no need to load the eeprom binary, but init the HI08 interface */
+		/* no need to load the eeprom binary,
+		 * but init the HI08 interface
+		 */
 		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg | PCXHR_ICR_HI08_INIT);
 		msleep(PCXHR_WAIT_DEFAULT);
 		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
@@ -429,8 +455,10 @@
 	if (err)
 		return err;
 	/* wait for chk bit */
-	return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,
-				   PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &dummy);
+	return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+				   PCXHR_ISR_HI08_CHK,
+				   PCXHR_ISR_HI08_CHK,
+				   PCXHR_TIMEOUT_DSP, &dummy);
 }
 
 
@@ -443,8 +471,8 @@
 /* RMH status type */
 enum {
 	RMH_SSIZE_FIXED = 0,	/* status size fix (st_length = 0..x) */
-	RMH_SSIZE_ARG = 1,	/* status size given in the LSB byte (used with st_length = 1) */
-	RMH_SSIZE_MASK = 2,	/* status size given in bitmask  (used with st_length = 1) */
+	RMH_SSIZE_ARG = 1,	/* status size given in the LSB byte */
+	RMH_SSIZE_MASK = 2,	/* status size given in bitmask */
 };
 
 /*
@@ -474,7 +502,7 @@
 [CMD_UPDATE_R_BUFFERS] =		{ 0x840000, 0, RMH_SSIZE_FIXED },
 [CMD_FORMAT_STREAM_OUT] =		{ 0x860000, 0, RMH_SSIZE_FIXED },
 [CMD_FORMAT_STREAM_IN] =		{ 0x870000, 0, RMH_SSIZE_FIXED },
-[CMD_STREAM_SAMPLE_COUNT] =		{ 0x902000, 2, RMH_SSIZE_FIXED },	/* stat_len = nb_streams * 2 */
+[CMD_STREAM_SAMPLE_COUNT] =		{ 0x902000, 2, RMH_SSIZE_FIXED },
 [CMD_AUDIO_LEVEL_ADJUST] =		{ 0xc22000, 0, RMH_SSIZE_FIXED },
 };
 
@@ -524,10 +552,13 @@
 
 	for (i = 0; i < rmh->stat_len; i++) {
 		/* wait for receiver full */
-		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF,
-					  PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, &reg);
+		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+					  PCXHR_ISR_HI08_RXDF,
+					  PCXHR_ISR_HI08_RXDF,
+					  PCXHR_TIMEOUT_DSP, &reg);
 		if (err) {
-			snd_printk(KERN_ERR "ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n",
+			snd_printk(KERN_ERR "ERROR RMH stat: "
+				   "ISR:RXDF=1 (ISR = %x; i=%d )\n",
 				   reg, i);
 			return err;
 		}
@@ -537,10 +568,10 @@
 		data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
 
 		/* need to update rmh->stat_len on the fly ?? */
-		if (i==0) {
+		if (!i) {
 			if (rmh->dsp_stat != RMH_SSIZE_FIXED) {
 				if (rmh->dsp_stat == RMH_SSIZE_ARG) {
-					rmh->stat_len = (u16)(data & 0x0000ff) + 1;
+					rmh->stat_len = (data & 0x0000ff) + 1;
 					data &= 0xffff00;
 				} else {
 					/* rmh->dsp_stat == RMH_SSIZE_MASK */
@@ -562,7 +593,8 @@
 			rmh->stat[i] = data;
 	}
 	if (rmh->stat_len > max_stat_len) {
-		snd_printdd("PCXHR : rmh->stat_len=%x too big\n", rmh->stat_len);
+		snd_printdd("PCXHR : rmh->stat_len=%x too big\n",
+			    rmh->stat_len);
 		rmh->stat_len = max_stat_len;
 	}
 	return 0;
@@ -605,7 +637,8 @@
 		data &= 0xff7fff;	/* MASK_1_WORD_COMMAND */
 #ifdef CONFIG_SND_DEBUG_VERBOSE
 	if (rmh->cmd_idx < CMD_LAST_INDEX)
-		snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]);
+		snd_printdd("MSG cmd[0]=%x (%s)\n",
+			    data, cmd_names[rmh->cmd_idx]);
 #endif
 
 	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
@@ -619,8 +652,10 @@
 	if (rmh->cmd_len > 1) {
 		/* send length */
 		data = rmh->cmd_len - 1;
-		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,
-					  PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &reg);
+		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+					  PCXHR_ISR_HI08_TRDY,
+					  PCXHR_ISR_HI08_TRDY,
+					  PCXHR_TIMEOUT_DSP, &reg);
 		if (err)
 			return err;
 		PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF);
@@ -653,8 +688,10 @@
 	/* test status ISR */
 	if (reg & PCXHR_ISR_HI08_ERR) {
 		/* ERROR, wait for receiver full */
-		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF,
-					  PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, &reg);
+		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
+					  PCXHR_ISR_HI08_RXDF,
+					  PCXHR_ISR_HI08_RXDF,
+					  PCXHR_TIMEOUT_DSP, &reg);
 		if (err) {
 			snd_printk(KERN_ERR "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg);
 			return err;
@@ -663,7 +700,8 @@
 		data  = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16;
 		data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8;
 		data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
-		snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n", rmh->cmd_idx, data);
+		snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n",
+			   rmh->cmd_idx, data);
 		err = -EINVAL;
 	} else {
 		/* read the response data */
@@ -732,8 +770,9 @@
 static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr)
 {
 	int start_mask = PCXHR_INPL(mgr, PCXHR_PLX_MBOX2);
-	/* least segnificant 12 bits are the pipe states for the playback audios */
-	/* next 12 bits are the pipe states for the capture audios
+	/* least segnificant 12 bits are the pipe states
+	 * for the playback audios
+	 * next 12 bits are the pipe states for the capture audios
 	 * (PCXHR_PIPE_STATE_CAPTURE_OFFSET)
 	 */
 	start_mask &= 0xffffff;
@@ -744,7 +783,8 @@
 #define PCXHR_PIPE_STATE_CAPTURE_OFFSET		12
 #define MAX_WAIT_FOR_DSP			20
 
-static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int *retry)
+static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr,
+				    int audio_mask, int *retry)
 {
 	struct pcxhr_rmh rmh;
 	int err;
@@ -760,17 +800,20 @@
 			} else {
 				/* can start capture pipe */
 				pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
-							  PCXHR_PIPE_STATE_CAPTURE_OFFSET,
-							  0, 0);
+						PCXHR_PIPE_STATE_CAPTURE_OFFSET,
+						0, 0);
 			}
 			err = pcxhr_send_msg(mgr, &rmh);
 			if (err) {
 				snd_printk(KERN_ERR
-					   "error pipe start (CMD_CAN_START_PIPE) err=%x!\n",
+					   "error pipe start "
+					   "(CMD_CAN_START_PIPE) err=%x!\n",
 					   err);
 				return err;
 			}
-			/* if the pipe couldn't be prepaired for start, retry it later */
+			/* if the pipe couldn't be prepaired for start,
+			 * retry it later
+			 */
 			if (rmh.stat[0] == 0)
 				*retry |= (1<<audio);
 		}
@@ -795,14 +838,14 @@
 			} else {
 				/* stop capture pipe */
 				pcxhr_set_pipe_cmd_params(&rmh, 1, audio -
-							  PCXHR_PIPE_STATE_CAPTURE_OFFSET,
-							  0, 0);
+						PCXHR_PIPE_STATE_CAPTURE_OFFSET,
+						0, 0);
 			}
 			err = pcxhr_send_msg(mgr, &rmh);
 			if (err) {
 				snd_printk(KERN_ERR
-					   "error pipe stop (CMD_STOP_PIPE) err=%x!\n",
-					   err);
+					   "error pipe stop "
+					   "(CMD_STOP_PIPE) err=%x!\n", err);
 				return err;
 			}
 		}
@@ -822,15 +865,16 @@
 		if (audio_mask & 1) {
 			pcxhr_init_rmh(&rmh, CMD_CONF_PIPE);
 			if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET)
-				pcxhr_set_pipe_cmd_params(&rmh, 0, 0, 0, 1 << audio);
+				pcxhr_set_pipe_cmd_params(&rmh, 0, 0, 0,
+							  1 << audio);
 			else
 				pcxhr_set_pipe_cmd_params(&rmh, 1, 0, 0,
 							  1 << (audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET));
 			err = pcxhr_send_msg(mgr, &rmh);
 			if (err) {
 				snd_printk(KERN_ERR
-					   "error pipe start (CMD_CONF_PIPE) err=%x!\n",
-					   err);
+					   "error pipe start "
+					   "(CMD_CONF_PIPE) err=%x!\n", err);
 				return err;
 			}
 		}
@@ -841,7 +885,9 @@
 	pcxhr_init_rmh(&rmh, CMD_SEND_IRQA);
 	err = pcxhr_send_msg(mgr, &rmh);
 	if (err) {
-		snd_printk(KERN_ERR "error pipe start (CMD_SEND_IRQA) err=%x!\n", err );
+		snd_printk(KERN_ERR
+			   "error pipe start (CMD_SEND_IRQA) err=%x!\n",
+			   err);
 		return err;
 	}
 	return 0;
@@ -849,7 +895,8 @@
 
 
 
-int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_mask, int start)
+int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
+			 int capture_mask, int start)
 {
 	int state, i, err;
 	int audio_mask;
@@ -858,21 +905,23 @@
 	struct timeval my_tv1, my_tv2;
 	do_gettimeofday(&my_tv1);
 #endif
-	audio_mask = (playback_mask | (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
+	audio_mask = (playback_mask |
+		      (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
 	/* current pipe state (playback + record) */
 	state = pcxhr_pipes_running(mgr);
 	snd_printdd("pcxhr_set_pipe_state %s (mask %x current %x)\n",
 		    start ? "START" : "STOP", audio_mask, state);
 	if (start) {
-		audio_mask &= ~state;	/* start only pipes that are not yet started */
+		/* start only pipes that are not yet started */
+		audio_mask &= ~state;
 		state = audio_mask;
 		for (i = 0; i < MAX_WAIT_FOR_DSP; i++) {
 			err = pcxhr_prepair_pipe_start(mgr, state, &state);
 			if (err)
 				return err;
 			if (state == 0)
-				break;	/* success, all pipes prepaired for start */
-			mdelay(1);		/* otherwise wait 1 millisecond and retry */
+				break;	/* success, all pipes prepaired */
+			mdelay(1);	/* wait 1 millisecond and retry */
 		}
 	} else {
 		audio_mask &= state;	/* stop only pipes that are started */
@@ -891,7 +940,7 @@
 		if ((state & audio_mask) == (start ? audio_mask : 0))
 			break;
 		if (++i >= MAX_WAIT_FOR_DSP * 100) {
-			snd_printk(KERN_ERR "error pipe start/stop (ED_NO_RESPONSE_AT_IRQA)\n");
+			snd_printk(KERN_ERR "error pipe start/stop\n");
 			return -EBUSY;
 		}
 		udelay(10);			/* wait 10 microseconds */
@@ -918,7 +967,8 @@
 
 	spin_lock_irqsave(&mgr->msg_lock, flags);
 	if ((mgr->io_num_reg_cont & mask) == value) {
-		snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n", mask, value);
+		snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n",
+			    mask, value);
 		if (changed)
 			*changed = 0;
 		spin_unlock_irqrestore(&mgr->msg_lock, flags);
@@ -971,7 +1021,8 @@
 		err = ((err >> 12) & 0xfff);
 	if (!err)
 		return 0;
-	snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n", err_src_name[err_src],
+	snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n",
+		    err_src_name[err_src],
 		    is_capture ? "Record" : "Play", pipe, err);
 	if (err == 0xe01)
 		mgr->async_err_stream_xrun++;
@@ -996,6 +1047,13 @@
 		snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occured\n");
 	if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY)
 		snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occured\n");
+	if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) {
+		/* clear events FREQ_CHANGE and TIME_CODE */
+		pcxhr_init_rmh(prmh, CMD_TEST_IT);
+		err = pcxhr_send_msg(mgr, prmh);
+		snd_printdd("CMD_TEST_IT : err=%x, stat=%x\n",
+			    err, prmh->stat[0]);
+	}
 	if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) {
 		snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occured\n");
 
@@ -1005,18 +1063,22 @@
 		prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS;
 		err = pcxhr_send_msg(mgr, prmh);
 		if (err)
-			snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n", err);
+			snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n",
+				   err);
 		i = 1;
 		while (i < prmh->stat_len) {
-			int nb_audio = (prmh->stat[i] >> FIELD_SIZE) & MASK_FIRST_FIELD;
-			int nb_stream = (prmh->stat[i] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD;
+			int nb_audio = ((prmh->stat[i] >> FIELD_SIZE) &
+					MASK_FIRST_FIELD);
+			int nb_stream = ((prmh->stat[i] >> (2*FIELD_SIZE)) &
+					 MASK_FIRST_FIELD);
 			int pipe = prmh->stat[i] & MASK_FIRST_FIELD;
 			int is_capture = prmh->stat[i] & 0x400000;
 			u32 err2;
 
 			if (prmh->stat[i] & 0x800000) {	/* if BIT_END */
 				snd_printdd("TASKLET : End%sPipe %d\n",
-					    is_capture ? "Record" : "Play", pipe);
+					    is_capture ? "Record" : "Play",
+					    pipe);
 			}
 			i++;
 			err2 = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1];
@@ -1062,7 +1124,7 @@
 	pcxhr_init_rmh(&rmh, CMD_STREAM_SAMPLE_COUNT);
 	pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture,
 				  stream->pipe->first_audio, 0, stream_mask);
-	/* rmh.stat_len = 2; */		/* 2 resp data for each stream of the pipe */
+	/* rmh.stat_len = 2; */	/* 2 resp data for each stream of the pipe */
 
 	err = pcxhr_send_msg(mgr, &rmh);
 	if (err)
@@ -1072,18 +1134,21 @@
 	hw_sample_count += (u_int64_t)rmh.stat[1];
 
 	snd_printdd("stream %c%d : abs samples real(%ld) timer(%ld)\n",
-		    stream->pipe->is_capture ? 'C':'P', stream->substream->number,
+		    stream->pipe->is_capture ? 'C' : 'P',
+		    stream->substream->number,
 		    (long unsigned int)hw_sample_count,
 		    (long unsigned int)(stream->timer_abs_periods +
-					stream->timer_period_frag + PCXHR_GRANULARITY));
-
+					stream->timer_period_frag +
+					mgr->granularity));
 	return hw_sample_count;
 }
 
 static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
-				   struct pcxhr_stream *stream, int samples_to_add)
+				   struct pcxhr_stream *stream,
+				   int samples_to_add)
 {
-	if (stream->substream && (stream->status == PCXHR_STREAM_STATUS_RUNNING)) {
+	if (stream->substream &&
+	    (stream->status == PCXHR_STREAM_STATUS_RUNNING)) {
 		u_int64_t new_sample_count;
 		int elapsed = 0;
 		int hardware_read = 0;
@@ -1092,20 +1157,22 @@
 		if (samples_to_add < 0) {
 			stream->timer_is_synced = 0;
 			/* add default if no hardware_read possible */
-			samples_to_add = PCXHR_GRANULARITY;
+			samples_to_add = mgr->granularity;
 		}
 
 		if (!stream->timer_is_synced) {
-			if (stream->timer_abs_periods != 0 ||
-			    stream->timer_period_frag + PCXHR_GRANULARITY >=
-			    runtime->period_size) {
-				new_sample_count = pcxhr_stream_read_position(mgr, stream);
+			if ((stream->timer_abs_periods != 0) ||
+			    ((stream->timer_period_frag + samples_to_add) >=
+			    runtime->period_size)) {
+				new_sample_count =
+				  pcxhr_stream_read_position(mgr, stream);
 				hardware_read = 1;
-				if (new_sample_count >= PCXHR_GRANULARITY_MIN) {
-					/* sub security offset because of jitter and
-					 * finer granularity of dsp time (MBOX4)
+				if (new_sample_count >= mgr->granularity) {
+					/* sub security offset because of
+					 * jitter and finer granularity of
+					 * dsp time (MBOX4)
 					 */
-					new_sample_count -= PCXHR_GRANULARITY_MIN;
+					new_sample_count -= mgr->granularity;
 					stream->timer_is_synced = 1;
 				}
 			}
@@ -1128,12 +1195,15 @@
 				stream->timer_buf_periods = 0;
 			stream->timer_abs_periods = new_elapse_pos;
 		}
-		if (new_sample_count >= stream->timer_abs_periods)
-			stream->timer_period_frag = (u_int32_t)(new_sample_count -
-								stream->timer_abs_periods);
-		else
-			snd_printk(KERN_ERR "ERROR new_sample_count too small ??? %lx\n",
+		if (new_sample_count >= stream->timer_abs_periods) {
+			stream->timer_period_frag =
+				(u_int32_t)(new_sample_count -
+					    stream->timer_abs_periods);
+		} else {
+			snd_printk(KERN_ERR
+				   "ERROR new_sample_count too small ??? %ld\n",
 				   (long unsigned int)new_sample_count);
+		}
 
 		if (elapsed) {
 			spin_unlock(&mgr->lock);
@@ -1143,7 +1213,6 @@
 	}
 }
 
-
 irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
 {
 	struct pcxhr_mgr *mgr = dev_id;
@@ -1156,7 +1225,8 @@
 	reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);
 	if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) {
 		spin_unlock(&mgr->lock);
-		return IRQ_NONE;	/* this device did not cause the interrupt */
+		/* this device did not cause the interrupt */
+		return IRQ_NONE;
 	}
 
 	/* clear interrupt */
@@ -1167,10 +1237,12 @@
 	if (reg & PCXHR_IRQ_TIMER) {
 		int timer_toggle = reg & PCXHR_IRQ_TIMER;
 		/* is a 24 bit counter */
-		int dsp_time_new = PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK;
+		int dsp_time_new =
+			PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK;
 		int dsp_time_diff = dsp_time_new - mgr->dsp_time_last;
 
-		if (dsp_time_diff < 0 && mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID) {
+		if ((dsp_time_diff < 0) &&
+		    (mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) {
 			snd_printdd("ERROR DSP TIME old(%d) new(%d) -> "
 				    "resynchronize all streams\n",
 				    mgr->dsp_time_last, dsp_time_new);
@@ -1178,42 +1250,51 @@
 		}
 #ifdef CONFIG_SND_DEBUG_VERBOSE
 		if (dsp_time_diff == 0)
-			snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new);
-		else if (dsp_time_diff >= (2*PCXHR_GRANULARITY))
+			snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n",
+				    dsp_time_new);
+		else if (dsp_time_diff >= (2*mgr->granularity))
 			snd_printdd("ERROR DSP TIME TOO BIG old(%d) add(%d)\n",
-				    mgr->dsp_time_last, dsp_time_new - mgr->dsp_time_last);
+				    mgr->dsp_time_last,
+				    dsp_time_new - mgr->dsp_time_last);
+		else if (dsp_time_diff % mgr->granularity)
+			snd_printdd("ERROR DSP TIME increased by %d\n",
+				    dsp_time_diff);
 #endif
 		mgr->dsp_time_last = dsp_time_new;
 
-		if (timer_toggle == mgr->timer_toggle)
+		if (timer_toggle == mgr->timer_toggle) {
 			snd_printdd("ERROR TIMER TOGGLE\n");
+			mgr->dsp_time_err++;
+		}
 		mgr->timer_toggle = timer_toggle;
 
 		reg &= ~PCXHR_IRQ_TIMER;
 		for (i = 0; i < mgr->num_cards; i++) {
 			chip = mgr->chip[i];
 			for (j = 0; j < chip->nb_streams_capt; j++)
-				pcxhr_update_timer_pos(mgr, &chip->capture_stream[j],
-						       dsp_time_diff);
+				pcxhr_update_timer_pos(mgr,
+						&chip->capture_stream[j],
+						dsp_time_diff);
 		}
 		for (i = 0; i < mgr->num_cards; i++) {
 			chip = mgr->chip[i];
 			for (j = 0; j < chip->nb_streams_play; j++)
-				pcxhr_update_timer_pos(mgr, &chip->playback_stream[j],
-						       dsp_time_diff);
+				pcxhr_update_timer_pos(mgr,
+						&chip->playback_stream[j],
+						dsp_time_diff);
 		}
 	}
 	/* other irq's handled in the tasklet */
 	if (reg & PCXHR_IRQ_MASK) {
-
-		/* as we didn't request any notifications, some kind of xrun error
-		 * will probably occured
-		 */
-		/* better resynchronize all streams next interrupt : */
-		mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
-		
+		if (reg & PCXHR_IRQ_ASYNC) {
+			/* as we didn't request any async notifications,
+			 * some kind of xrun error will probably occured
+			 */
+			/* better resynchronize all streams next interrupt : */
+			mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
+		}
 		mgr->src_it_dsp = reg;
-		tasklet_hi_schedule(&mgr->msg_taskq);
+		tasklet_schedule(&mgr->msg_taskq);
 	}
 #ifdef CONFIG_SND_DEBUG_VERBOSE
 	if (reg & PCXHR_FATAL_DSP_ERR)
diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h
index d9a4ab6..bbbd66d 100644
--- a/sound/pci/pcxhr/pcxhr_core.h
+++ b/sound/pci/pcxhr/pcxhr_core.h
@@ -65,7 +65,7 @@
 	CMD_RESYNC_AUDIO_INPUTS,	/* cmd_len = 1	stat_len = 0 */
 	CMD_GET_DSP_RESOURCES,		/* cmd_len = 1	stat_len = 4 */
 	CMD_SET_TIMER_INTERRUPT,	/* cmd_len = 1	stat_len = 0 */
-	CMD_RES_PIPE,			/* cmd_len = 2	stat_len = 0 */
+	CMD_RES_PIPE,			/* cmd_len >=2	stat_len = 0 */
 	CMD_FREE_PIPE,			/* cmd_len = 1	stat_len = 0 */
 	CMD_CONF_PIPE,			/* cmd_len = 2	stat_len = 0 */
 	CMD_STOP_PIPE,			/* cmd_len = 1	stat_len = 0 */
@@ -96,6 +96,8 @@
 void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh* rmh, int capture, unsigned int param1,
 			       unsigned int param2, unsigned int param3);
 
+#define DSP_EXT_CMD_SET(x) (x->dsp_version > 0x012800)
+
 /*
  send the rmh
  */
@@ -110,6 +112,7 @@
 #define IO_NUM_REG_STATUS		5
 #define IO_NUM_REG_CUER			10
 #define IO_NUM_UER_CHIP_REG		11
+#define IO_NUM_REG_CONFIG_SRC		12
 #define IO_NUM_REG_OUT_ANA_LEVEL	20
 #define IO_NUM_REG_IN_ANA_LEVEL		21
 
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index 96640d9..592743a 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -31,6 +31,7 @@
 #include "pcxhr_mixer.h"
 #include "pcxhr_hwdep.h"
 #include "pcxhr_core.h"
+#include "pcxhr_mix22.h"
 
 
 #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
@@ -40,10 +41,10 @@
 #endif
 
 
+static int pcxhr_sub_init(struct pcxhr_mgr *mgr);
 /*
  * get basic information and init pcxhr card
  */
-
 static int pcxhr_init_board(struct pcxhr_mgr *mgr)
 {
 	int err;
@@ -68,7 +69,7 @@
 	if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2)
 		return -EINVAL;
 	/* test 8 or 2 phys in */
-	if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) !=
+	if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) <
 	    mgr->capture_chips * 2)
 		return -EINVAL;
 	/* test max nb substream per board */
@@ -77,20 +78,34 @@
 	/* test max nb substream per pipe */
 	if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS)
 		return -EINVAL;
+	snd_printdd("supported formats : playback=%x capture=%x\n",
+		    rmh.stat[2], rmh.stat[3]);
 
 	pcxhr_init_rmh(&rmh, CMD_VERSION);
 	/* firmware num for DSP */
 	rmh.cmd[0] |= mgr->firmware_num;
 	/* transfer granularity in samples (should be multiple of 48) */
-	rmh.cmd[1] = (1<<23) + PCXHR_GRANULARITY;
+	rmh.cmd[1] = (1<<23) + mgr->granularity;
 	rmh.cmd_len = 2;
 	err = pcxhr_send_msg(mgr, &rmh);
 	if (err)
 		return err;
-	snd_printdd("PCXHR DSP version is %d.%d.%d\n",
-		    (rmh.stat[0]>>16)&0xff, (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff);
+	snd_printdd("PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff,
+		    (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff);
 	mgr->dsp_version = rmh.stat[0];
 
+	if (mgr->is_hr_stereo)
+		err = hr222_sub_init(mgr);
+	else
+		err = pcxhr_sub_init(mgr);
+	return err;
+}
+
+static int pcxhr_sub_init(struct pcxhr_mgr *mgr)
+{
+	int err;
+	struct pcxhr_rmh rmh;
+
 	/* get options */
 	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
 	rmh.cmd[0] |= IO_NUM_REG_STATUS;
@@ -100,20 +115,22 @@
 	if (err)
 		return err;
 
-	if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == REG_STATUS_OPT_ANALOG_BOARD)
-		mgr->board_has_analog = 1;	/* analog addon board available */
-	else
-		/* analog addon board not available -> no support for instance */
-		return -EINVAL;	
+	if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) ==
+	    REG_STATUS_OPT_ANALOG_BOARD)
+		mgr->board_has_analog = 1;	/* analog addon board found */
 
 	/* unmute inputs */
 	err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
 					  REG_CONT_UNMUTE_INPUTS, NULL);
 	if (err)
 		return err;
-	/* unmute outputs */
-	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* a write to IO_NUM_REG_MUTE_OUT mutes! */
+	/* unmute outputs (a write to IO_NUM_REG_MUTE_OUT mutes!) */
+	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
 	rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
+	if (DSP_EXT_CMD_SET(mgr)) {
+		rmh.cmd[1]  = 1;	/* unmute digital plugs */
+		rmh.cmd_len = 2;
+	}
 	err = pcxhr_send_msg(mgr, &rmh);
 	return err;
 }
@@ -124,19 +141,25 @@
 
 	if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
 		/* mute outputs */
+	    if (!mgr->is_hr_stereo) {
 		/* a read to IO_NUM_REG_MUTE_OUT register unmutes! */
 		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
 		rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
 		pcxhr_send_msg(mgr, &rmh);
 		/* mute inputs */
-		pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, 0, NULL);
+		pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS,
+					    0, NULL);
+	    }
+		/* stereo cards mute with reset of dsp */
 	}
 	/* reset pcxhr dsp */
-	if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX))
+	if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX))
 		pcxhr_reset_dsp(mgr);
 	/* reset second xilinx */
-	if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_XLX_COM_INDEX))
+	if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) {
 		pcxhr_reset_xilinx_com(mgr);
+		mgr->dsp_loaded = 1;
+	}
 	return;
 }
 
@@ -144,8 +167,9 @@
 /*
  *  allocate a playback/capture pipe (pcmp0/pcmc0)
  */
-static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe,
-				    int is_capture, int pin)
+static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr,
+				   struct pcxhr_pipe *pipe,
+				   int is_capture, int pin)
 {
 	int stream_count, audio_count;
 	int err;
@@ -161,15 +185,23 @@
 		stream_count = PCXHR_PLAYBACK_STREAMS;
 		audio_count = 2;	/* always stereo */
 	}
-	snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", pin, is_capture ? 'c' : 'p');
+	snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n",
+		    pin, is_capture ? 'c' : 'p');
 	pipe->is_capture = is_capture;
 	pipe->first_audio = pin;
 	/* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */
 	pcxhr_init_rmh(&rmh, CMD_RES_PIPE);
-	pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, audio_count, stream_count); 
+	pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin,
+				  audio_count, stream_count);
+	rmh.cmd[1] |= 0x020000; /* add P_PCM_ONLY_MASK */
+	if (DSP_EXT_CMD_SET(mgr)) {
+		/* add channel mask to command */
+	  rmh.cmd[rmh.cmd_len++] = (audio_count == 1) ? 0x01 : 0x03;
+	}
 	err = pcxhr_send_msg(mgr, &rmh);
 	if (err < 0) {
-		snd_printk(KERN_ERR "error pipe allocation (CMD_RES_PIPE) err=%x!\n", err );
+		snd_printk(KERN_ERR "error pipe allocation "
+			   "(CMD_RES_PIPE) err=%x!\n", err);
 		return err;
 	}
 	pipe->status = PCXHR_PIPE_DEFINED;
@@ -199,10 +231,12 @@
 		snd_printk(KERN_ERR "error stopping pipe!\n");
 	/* release the pipe */
 	pcxhr_init_rmh(&rmh, CMD_FREE_PIPE);
-	pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, 0, 0);
+	pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio,
+				  0, 0);
 	err = pcxhr_send_msg(mgr, &rmh);
 	if (err < 0)
-		snd_printk(KERN_ERR "error pipe release (CMD_FREE_PIPE) err(%x)\n", err);
+		snd_printk(KERN_ERR "error pipe release "
+			   "(CMD_FREE_PIPE) err(%x)\n", err);
 	pipe->status = PCXHR_PIPE_UNDEFINED;
 	return err;
 }
@@ -248,15 +282,16 @@
 	for (i = 0; i < mgr->num_cards; i++) {
 		chip = mgr->chip[i];
 		if (chip->nb_streams_play)
-			playback_mask |= (1 << chip->playback_pipe.first_audio);
+			playback_mask |= 1 << chip->playback_pipe.first_audio;
 		for (j = 0; j < chip->nb_streams_capt; j++)
-			capture_mask |= (1 << chip->capture_pipe[j].first_audio);
+			capture_mask |= 1 << chip->capture_pipe[j].first_audio;
 	}
 	return pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
 }
 
 
-static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, const struct firmware *dsp)
+static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
+			  const struct firmware *dsp)
 {
 	int err, card_index;
 
@@ -330,22 +365,33 @@
 
 int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
 {
-	static char *fw_files[5] = {
-		"xi_1_882.dat",
-		"xc_1_882.dat",
-		"e321_512.e56",
-		"b321_512.b56",
-		"d321_512.d56"
+	static char *fw_files[][5] = {
+	[0] = { "xlxint.dat", "xlxc882hr.dat",
+		"dspe882.e56", "dspb882hr.b56", "dspd882.d56" },
+	[1] = { "xlxint.dat", "xlxc882e.dat",
+		"dspe882.e56", "dspb882e.b56", "dspd882.d56" },
+	[2] = { "xlxint.dat", "xlxc1222hr.dat",
+		"dspe882.e56", "dspb1222hr.b56", "dspd1222.d56" },
+	[3] = { "xlxint.dat", "xlxc1222e.dat",
+		"dspe882.e56", "dspb1222e.b56", "dspd1222.d56" },
+	[4] = { NULL, "xlxc222.dat",
+		"dspe924.e56", "dspb924.b56", "dspd222.d56" },
+	[5] = { NULL, "xlxc924.dat",
+		"dspe924.e56", "dspb924.b56", "dspd222.d56" },
 	};
 	char path[32];
 
 	const struct firmware *fw_entry;
 	int i, err;
+	int fw_set = mgr->fw_file_set;
 
-	for (i = 0; i < ARRAY_SIZE(fw_files); i++) {
-		sprintf(path, "pcxhr/%s", fw_files[i]);
+	for (i = 0; i < 5; i++) {
+		if (!fw_files[fw_set][i])
+			continue;
+		sprintf(path, "pcxhr/%s", fw_files[fw_set][i]);
 		if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
-			snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", path);
+			snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n",
+				   path);
 			return -ENOENT;
 		}
 		/* fake hwdep dsp record */
@@ -358,11 +404,26 @@
 	return 0;
 }
 
-MODULE_FIRMWARE("pcxhr/xi_1_882.dat");
-MODULE_FIRMWARE("pcxhr/xc_1_882.dat");
-MODULE_FIRMWARE("pcxhr/e321_512.e56");
-MODULE_FIRMWARE("pcxhr/b321_512.b56");
-MODULE_FIRMWARE("pcxhr/d321_512.d56");
+MODULE_FIRMWARE("pcxhr/xlxint.dat");
+MODULE_FIRMWARE("pcxhr/xlxc882hr.dat");
+MODULE_FIRMWARE("pcxhr/xlxc882e.dat");
+MODULE_FIRMWARE("pcxhr/dspe882.e56");
+MODULE_FIRMWARE("pcxhr/dspb882hr.b56");
+MODULE_FIRMWARE("pcxhr/dspb882e.b56");
+MODULE_FIRMWARE("pcxhr/dspd882.d56");
+
+MODULE_FIRMWARE("pcxhr/xlxc1222hr.dat");
+MODULE_FIRMWARE("pcxhr/xlxc1222e.dat");
+MODULE_FIRMWARE("pcxhr/dspb1222hr.b56");
+MODULE_FIRMWARE("pcxhr/dspb1222e.b56");
+MODULE_FIRMWARE("pcxhr/dspd1222.d56");
+
+MODULE_FIRMWARE("pcxhr/xlxc222.dat");
+MODULE_FIRMWARE("pcxhr/xlxc924.dat");
+MODULE_FIRMWARE("pcxhr/dspe924.e56");
+MODULE_FIRMWARE("pcxhr/dspb924.b56");
+MODULE_FIRMWARE("pcxhr/dspd222.d56");
+
 
 #else /* old style firmware loading */
 
@@ -373,7 +434,8 @@
 static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw,
 				  struct snd_hwdep_dsp_status *info)
 {
-	strcpy(info->id, "pcxhr");
+	struct pcxhr_mgr *mgr = hw->private_data;
+	sprintf(info->id, "pcxhr%d", mgr->fw_file_set);
         info->num_dsps = PCXHR_FIRMWARE_FILES_MAX_INDEX;
 
 	if (hw->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX))
@@ -393,8 +455,8 @@
 	fw.size = dsp->length;
 	fw.data = vmalloc(fw.size);
 	if (! fw.data) {
-		snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image (%lu bytes)\n",
-			   (unsigned long)fw.size);
+		snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image "
+			   "(%lu bytes)\n", (unsigned long)fw.size);
 		return -ENOMEM;
 	}
 	if (copy_from_user((void *)fw.data, dsp->image, dsp->length)) {
@@ -424,8 +486,11 @@
 	int err;
 	struct snd_hwdep *hw;
 
-	/* only create hwdep interface for first cardX (see "index" module parameter)*/
-	if ((err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw)) < 0)
+	/* only create hwdep interface for first cardX
+	 * (see "index" module parameter)
+	 */
+	err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw);
+	if (err < 0)
 		return err;
 
 	hw->iface = SNDRV_HWDEP_IFACE_PCXHR;
@@ -435,10 +500,13 @@
 	hw->ops.dsp_status = pcxhr_hwdep_dsp_status;
 	hw->ops.dsp_load = pcxhr_hwdep_dsp_load;
 	hw->exclusive = 1;
+	/* stereo cards don't need fw_file_0 -> dsp_loaded = 1 */
+	hw->dsp_loaded = mgr->is_hr_stereo ? 1 : 0;
 	mgr->dsp_loaded = 0;
 	sprintf(hw->name, PCXHR_HWDEP_ID);
 
-	if ((err = snd_card_register(mgr->chip[0]->card)) < 0)
+	err = snd_card_register(mgr->chip[0]->card);
+	if (err < 0)
 		return err;
 	return 0;
 }
diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c
new file mode 100644
index 0000000..ff01912
--- /dev/null
+++ b/sound/pci/pcxhr/pcxhr_mix22.c
@@ -0,0 +1,820 @@
+/*
+ * Driver for Digigram pcxhr compatible soundcards
+ *
+ * mixer interface for stereo cards
+ *
+ * Copyright (c) 2004 by Digigram <alsa@digigram.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/delay.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <sound/asoundef.h>
+#include "pcxhr.h"
+#include "pcxhr_core.h"
+#include "pcxhr_mix22.h"
+
+
+/* registers used on the DSP and Xilinx (port 2) : HR stereo cards only */
+#define PCXHR_DSP_RESET		0x20
+#define PCXHR_XLX_CFG		0x24
+#define PCXHR_XLX_RUER		0x28
+#define PCXHR_XLX_DATA		0x2C
+#define PCXHR_XLX_STATUS	0x30
+#define PCXHR_XLX_LOFREQ	0x34
+#define PCXHR_XLX_HIFREQ	0x38
+#define PCXHR_XLX_CSUER		0x3C
+#define PCXHR_XLX_SELMIC	0x40
+
+#define PCXHR_DSP 2
+
+/* byte access only ! */
+#define PCXHR_INPB(mgr, x)	inb((mgr)->port[PCXHR_DSP] + (x))
+#define PCXHR_OUTPB(mgr, x, data) outb((data), (mgr)->port[PCXHR_DSP] + (x))
+
+
+/* values for PCHR_DSP_RESET register */
+#define PCXHR_DSP_RESET_DSP	0x01
+#define PCXHR_DSP_RESET_MUTE	0x02
+#define PCXHR_DSP_RESET_CODEC	0x08
+
+/* values for PCHR_XLX_CFG register */
+#define PCXHR_CFG_SYNCDSP_MASK		0x80
+#define PCXHR_CFG_DEPENDENCY_MASK	0x60
+#define PCXHR_CFG_INDEPENDANT_SEL	0x00
+#define PCXHR_CFG_MASTER_SEL		0x40
+#define PCXHR_CFG_SLAVE_SEL		0x20
+#define PCXHR_CFG_DATA_UER1_SEL_MASK	0x10	/* 0 (UER0), 1(UER1) */
+#define PCXHR_CFG_DATAIN_SEL_MASK	0x08	/* 0 (ana), 1 (UER) */
+#define PCXHR_CFG_SRC_MASK		0x04	/* 0 (Bypass), 1 (SRC Actif) */
+#define PCXHR_CFG_CLOCK_UER1_SEL_MASK	0x02	/* 0 (UER0), 1(UER1) */
+#define PCXHR_CFG_CLOCKIN_SEL_MASK	0x01	/* 0 (internal), 1 (AES/EBU) */
+
+/* values for PCHR_XLX_DATA register */
+#define PCXHR_DATA_CODEC	0x80
+#define AKM_POWER_CONTROL_CMD	0xA007
+#define AKM_RESET_ON_CMD	0xA100
+#define AKM_RESET_OFF_CMD	0xA103
+#define AKM_CLOCK_INF_55K_CMD	0xA240
+#define AKM_CLOCK_SUP_55K_CMD	0xA24D
+#define AKM_MUTE_CMD		0xA38D
+#define AKM_UNMUTE_CMD		0xA30D
+#define AKM_LEFT_LEVEL_CMD	0xA600
+#define AKM_RIGHT_LEVEL_CMD	0xA700
+
+/* values for PCHR_XLX_STATUS register - READ */
+#define PCXHR_STAT_SRC_LOCK		0x01
+#define PCXHR_STAT_LEVEL_IN		0x02
+#define PCXHR_STAT_MIC_CAPS		0x10
+/* values for PCHR_XLX_STATUS register - WRITE */
+#define PCXHR_STAT_FREQ_SYNC_MASK	0x01
+#define PCXHR_STAT_FREQ_UER1_MASK	0x02
+#define PCXHR_STAT_FREQ_SAVE_MASK	0x80
+
+/* values for PCHR_XLX_CSUER register */
+#define PCXHR_SUER1_BIT_U_READ_MASK	0x80
+#define PCXHR_SUER1_BIT_C_READ_MASK	0x40
+#define PCXHR_SUER1_DATA_PRESENT_MASK	0x20
+#define PCXHR_SUER1_CLOCK_PRESENT_MASK	0x10
+#define PCXHR_SUER_BIT_U_READ_MASK	0x08
+#define PCXHR_SUER_BIT_C_READ_MASK	0x04
+#define PCXHR_SUER_DATA_PRESENT_MASK	0x02
+#define PCXHR_SUER_CLOCK_PRESENT_MASK	0x01
+
+#define PCXHR_SUER_BIT_U_WRITE_MASK	0x02
+#define PCXHR_SUER_BIT_C_WRITE_MASK	0x01
+
+/* values for PCXHR_XLX_SELMIC register - WRITE */
+#define PCXHR_SELMIC_PREAMPLI_OFFSET	2
+#define PCXHR_SELMIC_PREAMPLI_MASK	0x0C
+#define PCXHR_SELMIC_PHANTOM_ALIM	0x80
+
+
+static const unsigned char g_hr222_p_level[] = {
+    0x00,   /* [000] -49.5 dB:	AKM[000] = -1.#INF dB	(mute) */
+    0x01,   /* [001] -49.0 dB:	AKM[001] = -48.131 dB	(diff=0.86920 dB) */
+    0x01,   /* [002] -48.5 dB:	AKM[001] = -48.131 dB	(diff=0.36920 dB) */
+    0x01,   /* [003] -48.0 dB:	AKM[001] = -48.131 dB	(diff=0.13080 dB) */
+    0x01,   /* [004] -47.5 dB:	AKM[001] = -48.131 dB	(diff=0.63080 dB) */
+    0x01,   /* [005] -46.5 dB:	AKM[001] = -48.131 dB	(diff=1.63080 dB) */
+    0x01,   /* [006] -47.0 dB:	AKM[001] = -48.131 dB	(diff=1.13080 dB) */
+    0x01,   /* [007] -46.0 dB:	AKM[001] = -48.131 dB	(diff=2.13080 dB) */
+    0x01,   /* [008] -45.5 dB:	AKM[001] = -48.131 dB	(diff=2.63080 dB) */
+    0x02,   /* [009] -45.0 dB:	AKM[002] = -42.110 dB	(diff=2.88980 dB) */
+    0x02,   /* [010] -44.5 dB:	AKM[002] = -42.110 dB	(diff=2.38980 dB) */
+    0x02,   /* [011] -44.0 dB:	AKM[002] = -42.110 dB	(diff=1.88980 dB) */
+    0x02,   /* [012] -43.5 dB:	AKM[002] = -42.110 dB	(diff=1.38980 dB) */
+    0x02,   /* [013] -43.0 dB:	AKM[002] = -42.110 dB	(diff=0.88980 dB) */
+    0x02,   /* [014] -42.5 dB:	AKM[002] = -42.110 dB	(diff=0.38980 dB) */
+    0x02,   /* [015] -42.0 dB:	AKM[002] = -42.110 dB	(diff=0.11020 dB) */
+    0x02,   /* [016] -41.5 dB:	AKM[002] = -42.110 dB	(diff=0.61020 dB) */
+    0x02,   /* [017] -41.0 dB:	AKM[002] = -42.110 dB	(diff=1.11020 dB) */
+    0x02,   /* [018] -40.5 dB:	AKM[002] = -42.110 dB	(diff=1.61020 dB) */
+    0x03,   /* [019] -40.0 dB:	AKM[003] = -38.588 dB	(diff=1.41162 dB) */
+    0x03,   /* [020] -39.5 dB:	AKM[003] = -38.588 dB	(diff=0.91162 dB) */
+    0x03,   /* [021] -39.0 dB:	AKM[003] = -38.588 dB	(diff=0.41162 dB) */
+    0x03,   /* [022] -38.5 dB:	AKM[003] = -38.588 dB	(diff=0.08838 dB) */
+    0x03,   /* [023] -38.0 dB:	AKM[003] = -38.588 dB	(diff=0.58838 dB) */
+    0x03,   /* [024] -37.5 dB:	AKM[003] = -38.588 dB	(diff=1.08838 dB) */
+    0x04,   /* [025] -37.0 dB:	AKM[004] = -36.090 dB	(diff=0.91040 dB) */
+    0x04,   /* [026] -36.5 dB:	AKM[004] = -36.090 dB	(diff=0.41040 dB) */
+    0x04,   /* [027] -36.0 dB:	AKM[004] = -36.090 dB	(diff=0.08960 dB) */
+    0x04,   /* [028] -35.5 dB:	AKM[004] = -36.090 dB	(diff=0.58960 dB) */
+    0x05,   /* [029] -35.0 dB:	AKM[005] = -34.151 dB	(diff=0.84860 dB) */
+    0x05,   /* [030] -34.5 dB:	AKM[005] = -34.151 dB	(diff=0.34860 dB) */
+    0x05,   /* [031] -34.0 dB:	AKM[005] = -34.151 dB	(diff=0.15140 dB) */
+    0x05,   /* [032] -33.5 dB:	AKM[005] = -34.151 dB	(diff=0.65140 dB) */
+    0x06,   /* [033] -33.0 dB:	AKM[006] = -32.568 dB	(diff=0.43222 dB) */
+    0x06,   /* [034] -32.5 dB:	AKM[006] = -32.568 dB	(diff=0.06778 dB) */
+    0x06,   /* [035] -32.0 dB:	AKM[006] = -32.568 dB	(diff=0.56778 dB) */
+    0x07,   /* [036] -31.5 dB:	AKM[007] = -31.229 dB	(diff=0.27116 dB) */
+    0x07,   /* [037] -31.0 dB:	AKM[007] = -31.229 dB	(diff=0.22884 dB) */
+    0x08,   /* [038] -30.5 dB:	AKM[008] = -30.069 dB	(diff=0.43100 dB) */
+    0x08,   /* [039] -30.0 dB:	AKM[008] = -30.069 dB	(diff=0.06900 dB) */
+    0x09,   /* [040] -29.5 dB:	AKM[009] = -29.046 dB	(diff=0.45405 dB) */
+    0x09,   /* [041] -29.0 dB:	AKM[009] = -29.046 dB	(diff=0.04595 dB) */
+    0x0a,   /* [042] -28.5 dB:	AKM[010] = -28.131 dB	(diff=0.36920 dB) */
+    0x0a,   /* [043] -28.0 dB:	AKM[010] = -28.131 dB	(diff=0.13080 dB) */
+    0x0b,   /* [044] -27.5 dB:	AKM[011] = -27.303 dB	(diff=0.19705 dB) */
+    0x0b,   /* [045] -27.0 dB:	AKM[011] = -27.303 dB	(diff=0.30295 dB) */
+    0x0c,   /* [046] -26.5 dB:	AKM[012] = -26.547 dB	(diff=0.04718 dB) */
+    0x0d,   /* [047] -26.0 dB:	AKM[013] = -25.852 dB	(diff=0.14806 dB) */
+    0x0e,   /* [048] -25.5 dB:	AKM[014] = -25.208 dB	(diff=0.29176 dB) */
+    0x0e,   /* [049] -25.0 dB:	AKM[014] = -25.208 dB	(diff=0.20824 dB) */
+    0x0f,   /* [050] -24.5 dB:	AKM[015] = -24.609 dB	(diff=0.10898 dB) */
+    0x10,   /* [051] -24.0 dB:	AKM[016] = -24.048 dB	(diff=0.04840 dB) */
+    0x11,   /* [052] -23.5 dB:	AKM[017] = -23.522 dB	(diff=0.02183 dB) */
+    0x12,   /* [053] -23.0 dB:	AKM[018] = -23.025 dB	(diff=0.02535 dB) */
+    0x13,   /* [054] -22.5 dB:	AKM[019] = -22.556 dB	(diff=0.05573 dB) */
+    0x14,   /* [055] -22.0 dB:	AKM[020] = -22.110 dB	(diff=0.11020 dB) */
+    0x15,   /* [056] -21.5 dB:	AKM[021] = -21.686 dB	(diff=0.18642 dB) */
+    0x17,   /* [057] -21.0 dB:	AKM[023] = -20.896 dB	(diff=0.10375 dB) */
+    0x18,   /* [058] -20.5 dB:	AKM[024] = -20.527 dB	(diff=0.02658 dB) */
+    0x1a,   /* [059] -20.0 dB:	AKM[026] = -19.831 dB	(diff=0.16866 dB) */
+    0x1b,   /* [060] -19.5 dB:	AKM[027] = -19.504 dB	(diff=0.00353 dB) */
+    0x1d,   /* [061] -19.0 dB:	AKM[029] = -18.883 dB	(diff=0.11716 dB) */
+    0x1e,   /* [062] -18.5 dB:	AKM[030] = -18.588 dB	(diff=0.08838 dB) */
+    0x20,   /* [063] -18.0 dB:	AKM[032] = -18.028 dB	(diff=0.02780 dB) */
+    0x22,   /* [064] -17.5 dB:	AKM[034] = -17.501 dB	(diff=0.00123 dB) */
+    0x24,   /* [065] -17.0 dB:	AKM[036] = -17.005 dB	(diff=0.00475 dB) */
+    0x26,   /* [066] -16.5 dB:	AKM[038] = -16.535 dB	(diff=0.03513 dB) */
+    0x28,   /* [067] -16.0 dB:	AKM[040] = -16.090 dB	(diff=0.08960 dB) */
+    0x2b,   /* [068] -15.5 dB:	AKM[043] = -15.461 dB	(diff=0.03857 dB) */
+    0x2d,   /* [069] -15.0 dB:	AKM[045] = -15.067 dB	(diff=0.06655 dB) */
+    0x30,   /* [070] -14.5 dB:	AKM[048] = -14.506 dB	(diff=0.00598 dB) */
+    0x33,   /* [071] -14.0 dB:	AKM[051] = -13.979 dB	(diff=0.02060 dB) */
+    0x36,   /* [072] -13.5 dB:	AKM[054] = -13.483 dB	(diff=0.01707 dB) */
+    0x39,   /* [073] -13.0 dB:	AKM[057] = -13.013 dB	(diff=0.01331 dB) */
+    0x3c,   /* [074] -12.5 dB:	AKM[060] = -12.568 dB	(diff=0.06778 dB) */
+    0x40,   /* [075] -12.0 dB:	AKM[064] = -12.007 dB	(diff=0.00720 dB) */
+    0x44,   /* [076] -11.5 dB:	AKM[068] = -11.481 dB	(diff=0.01937 dB) */
+    0x48,   /* [077] -11.0 dB:	AKM[072] = -10.984 dB	(diff=0.01585 dB) */
+    0x4c,   /* [078] -10.5 dB:	AKM[076] = -10.515 dB	(diff=0.01453 dB) */
+    0x51,   /* [079] -10.0 dB:	AKM[081] = -9.961 dB	(diff=0.03890 dB) */
+    0x55,   /* [080] -9.5 dB:	AKM[085] = -9.542 dB	(diff=0.04243 dB) */
+    0x5a,   /* [081] -9.0 dB:	AKM[090] = -9.046 dB	(diff=0.04595 dB) */
+    0x60,   /* [082] -8.5 dB:	AKM[096] = -8.485 dB	(diff=0.01462 dB) */
+    0x66,   /* [083] -8.0 dB:	AKM[102] = -7.959 dB	(diff=0.04120 dB) */
+    0x6c,   /* [084] -7.5 dB:	AKM[108] = -7.462 dB	(diff=0.03767 dB) */
+    0x72,   /* [085] -7.0 dB:	AKM[114] = -6.993 dB	(diff=0.00729 dB) */
+    0x79,   /* [086] -6.5 dB:	AKM[121] = -6.475 dB	(diff=0.02490 dB) */
+    0x80,   /* [087] -6.0 dB:	AKM[128] = -5.987 dB	(diff=0.01340 dB) */
+    0x87,   /* [088] -5.5 dB:	AKM[135] = -5.524 dB	(diff=0.02413 dB) */
+    0x8f,   /* [089] -5.0 dB:	AKM[143] = -5.024 dB	(diff=0.02408 dB) */
+    0x98,   /* [090] -4.5 dB:	AKM[152] = -4.494 dB	(diff=0.00607 dB) */
+    0xa1,   /* [091] -4.0 dB:	AKM[161] = -3.994 dB	(diff=0.00571 dB) */
+    0xaa,   /* [092] -3.5 dB:	AKM[170] = -3.522 dB	(diff=0.02183 dB) */
+    0xb5,   /* [093] -3.0 dB:	AKM[181] = -2.977 dB	(diff=0.02277 dB) */
+    0xbf,   /* [094] -2.5 dB:	AKM[191] = -2.510 dB	(diff=0.01014 dB) */
+    0xcb,   /* [095] -2.0 dB:	AKM[203] = -1.981 dB	(diff=0.01912 dB) */
+    0xd7,   /* [096] -1.5 dB:	AKM[215] = -1.482 dB	(diff=0.01797 dB) */
+    0xe3,   /* [097] -1.0 dB:	AKM[227] = -1.010 dB	(diff=0.01029 dB) */
+    0xf1,   /* [098] -0.5 dB:	AKM[241] = -0.490 dB	(diff=0.00954 dB) */
+    0xff,   /* [099] +0.0 dB:	AKM[255] = +0.000 dB	(diff=0.00000 dB) */
+};
+
+
+static void hr222_config_akm(struct pcxhr_mgr *mgr, unsigned short data)
+{
+	unsigned short mask = 0x8000;
+	/* activate access to codec registers */
+	PCXHR_INPB(mgr, PCXHR_XLX_HIFREQ);
+
+	while (mask) {
+		PCXHR_OUTPB(mgr, PCXHR_XLX_DATA,
+			    data & mask ? PCXHR_DATA_CODEC : 0);
+		mask >>= 1;
+	}
+	/* termiate access to codec registers */
+	PCXHR_INPB(mgr, PCXHR_XLX_RUER);
+}
+
+
+static int hr222_set_hw_playback_level(struct pcxhr_mgr *mgr,
+				       int idx, int level)
+{
+	unsigned short cmd;
+	if (idx > 1 ||
+	    level < 0 ||
+	    level >= ARRAY_SIZE(g_hr222_p_level))
+		return -EINVAL;
+
+	if (idx == 0)
+		cmd = AKM_LEFT_LEVEL_CMD;
+	else
+		cmd = AKM_RIGHT_LEVEL_CMD;
+
+	/* conversion from PmBoardCodedLevel to AKM nonlinear programming */
+	cmd += g_hr222_p_level[level];
+
+	hr222_config_akm(mgr, cmd);
+	return 0;
+}
+
+
+static int hr222_set_hw_capture_level(struct pcxhr_mgr *mgr,
+				      int level_l, int level_r, int level_mic)
+{
+	/* program all input levels at the same time */
+	unsigned int data;
+	int i;
+
+	if (!mgr->capture_chips)
+		return -EINVAL;	/* no PCX22 */
+
+	data  = ((level_mic & 0xff) << 24);	/* micro is mono, but apply */
+	data |= ((level_mic & 0xff) << 16);	/* level on both channels */
+	data |= ((level_r & 0xff) << 8);	/* line input right channel */
+	data |= (level_l & 0xff);		/* line input left channel */
+
+	PCXHR_INPB(mgr, PCXHR_XLX_DATA);	/* activate input codec */
+	/* send 32 bits (4 x 8 bits) */
+	for (i = 0; i < 32; i++, data <<= 1) {
+		PCXHR_OUTPB(mgr, PCXHR_XLX_DATA,
+			    (data & 0x80000000) ? PCXHR_DATA_CODEC : 0);
+	}
+	PCXHR_INPB(mgr, PCXHR_XLX_RUER);	/* close input level codec */
+	return 0;
+}
+
+static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level);
+
+int hr222_sub_init(struct pcxhr_mgr *mgr)
+{
+	unsigned char reg;
+
+	mgr->board_has_analog = 1;	/* analog always available */
+	mgr->xlx_cfg = PCXHR_CFG_SYNCDSP_MASK;
+
+	reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS);
+	if (reg & PCXHR_STAT_MIC_CAPS)
+		mgr->board_has_mic = 1;	/* microphone available */
+	snd_printdd("MIC input available = %d\n", mgr->board_has_mic);
+
+	/* reset codec */
+	PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
+		    PCXHR_DSP_RESET_DSP);
+	msleep(5);
+	PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
+		    PCXHR_DSP_RESET_DSP  |
+		    PCXHR_DSP_RESET_MUTE |
+		    PCXHR_DSP_RESET_CODEC);
+	msleep(5);
+
+	/* config AKM */
+	hr222_config_akm(mgr, AKM_POWER_CONTROL_CMD);
+	hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD);
+	hr222_config_akm(mgr, AKM_UNMUTE_CMD);
+	hr222_config_akm(mgr, AKM_RESET_OFF_CMD);
+
+	/* init micro boost */
+	hr222_micro_boost(mgr, 0);
+
+	return 0;
+}
+
+
+/* calc PLL register */
+/* TODO : there is a very similar fct in pcxhr.c */
+static int hr222_pll_freq_register(unsigned int freq,
+				   unsigned int *pllreg,
+				   unsigned int *realfreq)
+{
+	unsigned int reg;
+
+	if (freq < 6900 || freq > 219000)
+		return -EINVAL;
+	reg = (28224000 * 2) / freq;
+	reg = (reg - 1) / 2;
+	if (reg < 0x100)
+		*pllreg = reg + 0xC00;
+	else if (reg < 0x200)
+		*pllreg = reg + 0x800;
+	else if (reg < 0x400)
+		*pllreg = reg & 0x1ff;
+	else if (reg < 0x800) {
+		*pllreg = ((reg >> 1) & 0x1ff) + 0x200;
+		reg &= ~1;
+	} else {
+		*pllreg = ((reg >> 2) & 0x1ff) + 0x400;
+		reg &= ~3;
+	}
+	if (realfreq)
+		*realfreq = (28224000 / (reg + 1));
+	return 0;
+}
+
+int hr222_sub_set_clock(struct pcxhr_mgr *mgr,
+			unsigned int rate,
+			int *changed)
+{
+	unsigned int speed, pllreg = 0;
+	int err;
+	unsigned realfreq = rate;
+
+	switch (mgr->use_clock_type) {
+	case HR22_CLOCK_TYPE_INTERNAL:
+		err = hr222_pll_freq_register(rate, &pllreg, &realfreq);
+		if (err)
+			return err;
+
+		mgr->xlx_cfg &= ~(PCXHR_CFG_CLOCKIN_SEL_MASK |
+				  PCXHR_CFG_CLOCK_UER1_SEL_MASK);
+		break;
+	case HR22_CLOCK_TYPE_AES_SYNC:
+		mgr->xlx_cfg |= PCXHR_CFG_CLOCKIN_SEL_MASK;
+		mgr->xlx_cfg &= ~PCXHR_CFG_CLOCK_UER1_SEL_MASK;
+		break;
+	case HR22_CLOCK_TYPE_AES_1:
+		if (!mgr->board_has_aes1)
+			return -EINVAL;
+
+		mgr->xlx_cfg |= (PCXHR_CFG_CLOCKIN_SEL_MASK |
+				 PCXHR_CFG_CLOCK_UER1_SEL_MASK);
+		break;
+	default:
+		return -EINVAL;
+	}
+	hr222_config_akm(mgr, AKM_MUTE_CMD);
+
+	if (mgr->use_clock_type == HR22_CLOCK_TYPE_INTERNAL) {
+		PCXHR_OUTPB(mgr, PCXHR_XLX_HIFREQ, pllreg >> 8);
+		PCXHR_OUTPB(mgr, PCXHR_XLX_LOFREQ, pllreg & 0xff);
+	}
+
+	/* set clock source */
+	PCXHR_OUTPB(mgr, PCXHR_XLX_CFG, mgr->xlx_cfg);
+
+	/* codec speed modes */
+	speed = rate < 55000 ? 0 : 1;
+	if (mgr->codec_speed != speed) {
+		mgr->codec_speed = speed;
+		if (speed == 0)
+			hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD);
+		else
+			hr222_config_akm(mgr, AKM_CLOCK_SUP_55K_CMD);
+	}
+
+	mgr->sample_rate_real = realfreq;
+	mgr->cur_clock_type = mgr->use_clock_type;
+
+	if (changed)
+		*changed = 1;
+
+	hr222_config_akm(mgr, AKM_UNMUTE_CMD);
+
+	snd_printdd("set_clock to %dHz (realfreq=%d pllreg=%x)\n",
+		    rate, realfreq, pllreg);
+	return 0;
+}
+
+int hr222_get_external_clock(struct pcxhr_mgr *mgr,
+			     enum pcxhr_clock_type clock_type,
+			     int *sample_rate)
+{
+	int rate, calc_rate = 0;
+	unsigned int ticks;
+	unsigned char mask, reg;
+
+	if (clock_type == HR22_CLOCK_TYPE_AES_SYNC) {
+
+		mask = (PCXHR_SUER_CLOCK_PRESENT_MASK |
+			PCXHR_SUER_DATA_PRESENT_MASK);
+		reg = PCXHR_STAT_FREQ_SYNC_MASK;
+
+	} else if (clock_type == HR22_CLOCK_TYPE_AES_1 && mgr->board_has_aes1) {
+
+		mask = (PCXHR_SUER1_CLOCK_PRESENT_MASK |
+			PCXHR_SUER1_DATA_PRESENT_MASK);
+		reg = PCXHR_STAT_FREQ_UER1_MASK;
+
+	} else {
+		snd_printdd("get_external_clock : type %d not supported\n",
+			    clock_type);
+		return -EINVAL; /* other clocks not supported */
+	}
+
+	if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) {
+		snd_printdd("get_external_clock(%d) = 0 Hz\n", clock_type);
+		*sample_rate = 0;
+		return 0; /* no external clock locked */
+	}
+
+	PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* calculate freq */
+
+	/* save the measured clock frequency */
+	reg |= PCXHR_STAT_FREQ_SAVE_MASK;
+
+	if (mgr->last_reg_stat != reg) {
+		udelay(500);	/* wait min 2 cycles of lowest freq (8000) */
+		mgr->last_reg_stat = reg;
+	}
+
+	PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* save */
+
+	/* get the frequency */
+	ticks = (unsigned int)PCXHR_INPB(mgr, PCXHR_XLX_CFG);
+	ticks = (ticks & 0x03) << 8;
+	ticks |= (unsigned int)PCXHR_INPB(mgr, PCXHR_DSP_RESET);
+
+	if (ticks != 0)
+		calc_rate = 28224000 / ticks;
+	/* rounding */
+	if (calc_rate > 184200)
+		rate = 192000;
+	else if (calc_rate > 152200)
+		rate = 176400;
+	else if (calc_rate > 112000)
+		rate = 128000;
+	else if (calc_rate > 92100)
+		rate = 96000;
+	else if (calc_rate > 76100)
+		rate = 88200;
+	else if (calc_rate > 56000)
+		rate = 64000;
+	else if (calc_rate > 46050)
+		rate = 48000;
+	else if (calc_rate > 38050)
+		rate = 44100;
+	else if (calc_rate > 28000)
+		rate = 32000;
+	else if (calc_rate > 23025)
+		rate = 24000;
+	else if (calc_rate > 19025)
+		rate = 22050;
+	else if (calc_rate > 14000)
+		rate = 16000;
+	else if (calc_rate > 11512)
+		rate = 12000;
+	else if (calc_rate > 9512)
+		rate = 11025;
+	else if (calc_rate > 7000)
+		rate = 8000;
+	else
+		rate = 0;
+
+	snd_printdd("External clock is at %d Hz (measured %d Hz)\n",
+		    rate, calc_rate);
+	*sample_rate = rate;
+	return 0;
+}
+
+
+int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
+				    int is_capture, int channel)
+{
+	snd_printdd("hr222_update_analog_audio_level(%s chan=%d)\n",
+		    is_capture ? "capture" : "playback", channel);
+	if (is_capture) {
+		int level_l, level_r, level_mic;
+		/* we have to update all levels */
+		if (chip->analog_capture_active) {
+			level_l = chip->analog_capture_volume[0];
+			level_r = chip->analog_capture_volume[1];
+		} else {
+			level_l = HR222_LINE_CAPTURE_LEVEL_MIN;
+			level_r = HR222_LINE_CAPTURE_LEVEL_MIN;
+		}
+		if (chip->mic_active)
+			level_mic = chip->mic_volume;
+		else
+			level_mic = HR222_MICRO_CAPTURE_LEVEL_MIN;
+		return hr222_set_hw_capture_level(chip->mgr,
+						 level_l, level_r, level_mic);
+	} else {
+		int vol;
+		if (chip->analog_playback_active[channel])
+			vol = chip->analog_playback_volume[channel];
+		else
+			vol = HR222_LINE_PLAYBACK_LEVEL_MIN;
+		return hr222_set_hw_playback_level(chip->mgr, channel, vol);
+	}
+}
+
+
+/*texts[5] = {"Line", "Digital", "Digi+SRC", "Mic", "Line+Mic"}*/
+#define SOURCE_LINE	0
+#define SOURCE_DIGITAL	1
+#define SOURCE_DIGISRC	2
+#define SOURCE_MIC	3
+#define SOURCE_LINEMIC	4
+
+int hr222_set_audio_source(struct snd_pcxhr *chip)
+{
+	int digital = 0;
+	/* default analog source */
+	chip->mgr->xlx_cfg &= ~(PCXHR_CFG_SRC_MASK |
+				PCXHR_CFG_DATAIN_SEL_MASK |
+				PCXHR_CFG_DATA_UER1_SEL_MASK);
+
+	if (chip->audio_capture_source == SOURCE_DIGISRC) {
+		chip->mgr->xlx_cfg |= PCXHR_CFG_SRC_MASK;
+		digital = 1;
+	} else {
+		if (chip->audio_capture_source == SOURCE_DIGITAL)
+			digital = 1;
+	}
+	if (digital) {
+		chip->mgr->xlx_cfg |=  PCXHR_CFG_DATAIN_SEL_MASK;
+		if (chip->mgr->board_has_aes1) {
+			/* get data from the AES1 plug */
+			chip->mgr->xlx_cfg |= PCXHR_CFG_DATA_UER1_SEL_MASK;
+		}
+		/* chip->mic_active = 0; */
+		/* chip->analog_capture_active = 0; */
+	} else {
+		int update_lvl = 0;
+		chip->analog_capture_active = 0;
+		chip->mic_active = 0;
+		if (chip->audio_capture_source == SOURCE_LINE ||
+		    chip->audio_capture_source == SOURCE_LINEMIC) {
+			if (chip->analog_capture_active == 0)
+				update_lvl = 1;
+			chip->analog_capture_active = 1;
+		}
+		if (chip->audio_capture_source == SOURCE_MIC ||
+		    chip->audio_capture_source == SOURCE_LINEMIC) {
+			if (chip->mic_active == 0)
+				update_lvl = 1;
+			chip->mic_active = 1;
+		}
+		if (update_lvl) {
+			/* capture: update all 3 mutes/unmutes with one call */
+			hr222_update_analog_audio_level(chip, 1, 0);
+		}
+	}
+	/* set the source infos (max 3 bits modified) */
+	PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CFG, chip->mgr->xlx_cfg);
+	return 0;
+}
+
+
+int hr222_iec958_capture_byte(struct snd_pcxhr *chip,
+			     int aes_idx, unsigned char *aes_bits)
+{
+	unsigned char idx = (unsigned char)(aes_idx * 8);
+	unsigned char temp = 0;
+	unsigned char mask = chip->mgr->board_has_aes1 ?
+		PCXHR_SUER1_BIT_C_READ_MASK : PCXHR_SUER_BIT_C_READ_MASK;
+	int i;
+	for (i = 0; i < 8; i++) {
+		PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx++); /* idx < 192 */
+		temp <<= 1;
+		if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask)
+			temp |= 1;
+	}
+	snd_printdd("read iec958 AES %d byte %d = 0x%x\n",
+		    chip->chip_idx, aes_idx, temp);
+	*aes_bits = temp;
+	return 0;
+}
+
+
+int hr222_iec958_update_byte(struct snd_pcxhr *chip,
+			     int aes_idx, unsigned char aes_bits)
+{
+	int i;
+	unsigned char new_bits = aes_bits;
+	unsigned char old_bits = chip->aes_bits[aes_idx];
+	unsigned char idx = (unsigned char)(aes_idx * 8);
+	for (i = 0; i < 8; i++) {
+		if ((old_bits & 0x01) != (new_bits & 0x01)) {
+			/* idx < 192 */
+			PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx);
+			/* write C and U bit */
+			PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CSUER, new_bits&0x01 ?
+				    PCXHR_SUER_BIT_C_WRITE_MASK : 0);
+		}
+		idx++;
+		old_bits >>= 1;
+		new_bits >>= 1;
+	}
+	chip->aes_bits[aes_idx] = aes_bits;
+	return 0;
+}
+
+static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level)
+{
+	unsigned char boost_mask;
+	boost_mask = (unsigned char) (level << PCXHR_SELMIC_PREAMPLI_OFFSET);
+	if (boost_mask & (~PCXHR_SELMIC_PREAMPLI_MASK))
+		return; /* only values form 0 to 3 accepted */
+
+	mgr->xlx_selmic &= ~PCXHR_SELMIC_PREAMPLI_MASK;
+	mgr->xlx_selmic |= boost_mask;
+
+	PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
+
+	snd_printdd("hr222_micro_boost : set %x\n", boost_mask);
+}
+
+static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power)
+{
+	if (power)
+		mgr->xlx_selmic |= PCXHR_SELMIC_PHANTOM_ALIM;
+	else
+		mgr->xlx_selmic &= ~PCXHR_SELMIC_PHANTOM_ALIM;
+
+	PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
+
+	snd_printdd("hr222_phantom_power : set %d\n", power);
+}
+
+
+/* mic level */
+static const DECLARE_TLV_DB_SCALE(db_scale_mic_hr222, -9850, 50, 650);
+
+static int hr222_mic_vol_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = HR222_MICRO_CAPTURE_LEVEL_MIN; /* -98 dB */
+	/* gains from 9 dB to 31.5 dB not recommended; use micboost instead */
+	uinfo->value.integer.max = HR222_MICRO_CAPTURE_LEVEL_MAX; /*  +7 dB */
+	return 0;
+}
+
+static int hr222_mic_vol_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+	mutex_lock(&chip->mgr->mixer_mutex);
+	ucontrol->value.integer.value[0] = chip->mic_volume;
+	mutex_unlock(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	mutex_lock(&chip->mgr->mixer_mutex);
+	if (chip->mic_volume != ucontrol->value.integer.value[0]) {
+		changed = 1;
+		chip->mic_volume = ucontrol->value.integer.value[0];
+		hr222_update_analog_audio_level(chip, 1, 0);
+	}
+	mutex_unlock(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static struct snd_kcontrol_new hr222_control_mic_level = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access =	(SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+	.name =		"Mic Capture Volume",
+	.info =		hr222_mic_vol_info,
+	.get =		hr222_mic_vol_get,
+	.put =		hr222_mic_vol_put,
+	.tlv = { .p = db_scale_mic_hr222 },
+};
+
+
+/* mic boost level */
+static const DECLARE_TLV_DB_SCALE(db_scale_micboost_hr222, 0, 1800, 5400);
+
+static int hr222_mic_boost_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;	/*  0 dB */
+	uinfo->value.integer.max = 3;	/* 54 dB */
+	return 0;
+}
+
+static int hr222_mic_boost_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+	mutex_lock(&chip->mgr->mixer_mutex);
+	ucontrol->value.integer.value[0] = chip->mic_boost;
+	mutex_unlock(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	mutex_lock(&chip->mgr->mixer_mutex);
+	if (chip->mic_boost != ucontrol->value.integer.value[0]) {
+		changed = 1;
+		chip->mic_boost = ucontrol->value.integer.value[0];
+		hr222_micro_boost(chip->mgr, chip->mic_boost);
+	}
+	mutex_unlock(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static struct snd_kcontrol_new hr222_control_mic_boost = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access =	(SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+	.name =		"MicBoost Capture Volume",
+	.info =		hr222_mic_boost_info,
+	.get =		hr222_mic_boost_get,
+	.put =		hr222_mic_boost_put,
+	.tlv = { .p = db_scale_micboost_hr222 },
+};
+
+
+/******************* Phantom power switch *******************/
+#define hr222_phantom_power_info	snd_ctl_boolean_mono_info
+
+static int hr222_phantom_power_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+	mutex_lock(&chip->mgr->mixer_mutex);
+	ucontrol->value.integer.value[0] = chip->phantom_power;
+	mutex_unlock(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+	int power, changed = 0;
+
+	mutex_lock(&chip->mgr->mixer_mutex);
+	power = !!ucontrol->value.integer.value[0];
+	if (chip->phantom_power != power) {
+		hr222_phantom_power(chip->mgr, power);
+		chip->phantom_power = power;
+		changed = 1;
+	}
+	mutex_unlock(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static struct snd_kcontrol_new hr222_phantom_power_switch = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Phantom Power Switch",
+	.info = hr222_phantom_power_info,
+	.get = hr222_phantom_power_get,
+	.put = hr222_phantom_power_put,
+};
+
+
+int hr222_add_mic_controls(struct snd_pcxhr *chip)
+{
+	int err;
+	if (!chip->mgr->board_has_mic)
+		return 0;
+
+	/* controls */
+	err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_level,
+						   chip));
+	if (err < 0)
+		return err;
+
+	err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_boost,
+						   chip));
+	if (err < 0)
+		return err;
+
+	err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_phantom_power_switch,
+						   chip));
+	return err;
+}
diff --git a/sound/pci/pcxhr/pcxhr_mix22.h b/sound/pci/pcxhr/pcxhr_mix22.h
new file mode 100644
index 0000000..6b318b2
--- /dev/null
+++ b/sound/pci/pcxhr/pcxhr_mix22.h
@@ -0,0 +1,56 @@
+/*
+ * Driver for Digigram pcxhr compatible soundcards
+ *
+ * low level interface with interrupt ans message handling
+ *
+ * Copyright (c) 2004 by Digigram <alsa@digigram.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 __SOUND_PCXHR_MIX22_H
+#define __SOUND_PCXHR_MIX22_H
+
+struct pcxhr_mgr;
+
+int hr222_sub_init(struct pcxhr_mgr *mgr);
+int hr222_sub_set_clock(struct pcxhr_mgr *mgr, unsigned int rate,
+			int *changed);
+int hr222_get_external_clock(struct pcxhr_mgr *mgr,
+			     enum pcxhr_clock_type clock_type,
+			     int *sample_rate);
+
+#define HR222_LINE_PLAYBACK_LEVEL_MIN		0	/* -25.5 dB */
+#define HR222_LINE_PLAYBACK_ZERO_LEVEL		51	/* 0.0 dB */
+#define HR222_LINE_PLAYBACK_LEVEL_MAX		99	/* +24.0 dB */
+
+#define HR222_LINE_CAPTURE_LEVEL_MIN		0	/* -111.5 dB */
+#define HR222_LINE_CAPTURE_ZERO_LEVEL		223	/* 0.0 dB */
+#define HR222_LINE_CAPTURE_LEVEL_MAX		255	/* +16 dB */
+#define HR222_MICRO_CAPTURE_LEVEL_MIN		0	/* -98.5 dB */
+#define HR222_MICRO_CAPTURE_LEVEL_MAX		210	/* +6.5 dB */
+
+int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
+				    int is_capture,
+				    int channel);
+int hr222_set_audio_source(struct snd_pcxhr *chip);
+int hr222_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx,
+			      unsigned char *aes_bits);
+int hr222_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx,
+			     unsigned char aes_bits);
+
+int hr222_add_mic_controls(struct snd_pcxhr *chip);
+
+#endif /* __SOUND_PCXHR_MIX22_H */
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
index aabc7bc..2436e37 100644
--- a/sound/pci/pcxhr/pcxhr_mixer.c
+++ b/sound/pci/pcxhr/pcxhr_mixer.c
@@ -33,20 +33,24 @@
 #include <sound/tlv.h>
 #include <sound/asoundef.h>
 #include "pcxhr_mixer.h"
+#include "pcxhr_mix22.h"
 
+#define PCXHR_LINE_CAPTURE_LEVEL_MIN   0	/* -112.0 dB */
+#define PCXHR_LINE_CAPTURE_LEVEL_MAX   255	/* +15.5 dB */
+#define PCXHR_LINE_CAPTURE_ZERO_LEVEL  224	/* 0.0 dB ( 0 dBu -> 0 dBFS ) */
 
-#define PCXHR_ANALOG_CAPTURE_LEVEL_MIN   0	/* -96.0 dB */
-#define PCXHR_ANALOG_CAPTURE_LEVEL_MAX   255	/* +31.5 dB */
-#define PCXHR_ANALOG_CAPTURE_ZERO_LEVEL  224	/* +16.0 dB ( +31.5 dB - fix level +15.5 dB ) */
+#define PCXHR_LINE_PLAYBACK_LEVEL_MIN  0	/* -104.0 dB */
+#define PCXHR_LINE_PLAYBACK_LEVEL_MAX  128	/* +24.0 dB */
+#define PCXHR_LINE_PLAYBACK_ZERO_LEVEL 104	/* 0.0 dB ( 0 dBFS -> 0 dBu ) */
 
-#define PCXHR_ANALOG_PLAYBACK_LEVEL_MIN  0	/* -128.0 dB */
-#define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX  128	/*    0.0 dB */
-#define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104	/*  -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */
-
-static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 3150);
+static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -11200, 50, 1550);
 static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400);
 
-static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel)
+static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_capture, -11150, 50, 1600);
+static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_playback, -2550, 50, 2400);
+
+static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip,
+					   int is_capture, int channel)
 {
 	int err, vol;
 	struct pcxhr_rmh rmh;
@@ -60,15 +64,17 @@
 		if (chip->analog_playback_active[channel])
 			vol = chip->analog_playback_volume[channel];
 		else
-			vol = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN;
-		rmh.cmd[2] = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX - vol;	/* playback analog levels are inversed */
+			vol = PCXHR_LINE_PLAYBACK_LEVEL_MIN;
+		/* playback analog levels are inversed */
+		rmh.cmd[2] = PCXHR_LINE_PLAYBACK_LEVEL_MAX - vol;
 	}
 	rmh.cmd[1]  = 1 << ((2 * chip->chip_idx) + channel);	/* audio mask */
 	rmh.cmd_len = 3;
 	err = pcxhr_send_msg(chip->mgr, &rmh);
 	if (err < 0) {
-		snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d) "
-			   "is_capture(%d) err(%x)\n", chip->chip_idx, is_capture, err);
+		snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)"
+			   " is_capture(%d) err(%x)\n",
+			   chip->chip_idx, is_capture, err);
 		return -EINVAL;
 	}
 	return 0;
@@ -80,14 +86,34 @@
 static int pcxhr_analog_vol_info(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_info *uinfo)
 {
+	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
+
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 2;
 	if (kcontrol->private_value == 0) {	/* playback */
-		uinfo->value.integer.min = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN;	/* -128 dB */
-		uinfo->value.integer.max = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX;	/* 0 dB */
+	    if (chip->mgr->is_hr_stereo) {
+		uinfo->value.integer.min =
+			HR222_LINE_PLAYBACK_LEVEL_MIN;	/* -25 dB */
+		uinfo->value.integer.max =
+			HR222_LINE_PLAYBACK_LEVEL_MAX;	/* +24 dB */
+	    } else {
+		uinfo->value.integer.min =
+			PCXHR_LINE_PLAYBACK_LEVEL_MIN;	/*-104 dB */
+		uinfo->value.integer.max =
+			PCXHR_LINE_PLAYBACK_LEVEL_MAX;	/* +24 dB */
+	    }
 	} else {				/* capture */
-		uinfo->value.integer.min = PCXHR_ANALOG_CAPTURE_LEVEL_MIN;	/* -96 dB */
-		uinfo->value.integer.max = PCXHR_ANALOG_CAPTURE_LEVEL_MAX;	/* 31.5 dB */
+	    if (chip->mgr->is_hr_stereo) {
+		uinfo->value.integer.min =
+			HR222_LINE_CAPTURE_LEVEL_MIN;	/*-112 dB */
+		uinfo->value.integer.max =
+			HR222_LINE_CAPTURE_LEVEL_MAX;	/* +15.5 dB */
+	    } else {
+		uinfo->value.integer.min =
+			PCXHR_LINE_CAPTURE_LEVEL_MIN;	/*-112 dB */
+		uinfo->value.integer.max =
+			PCXHR_LINE_CAPTURE_LEVEL_MAX;	/* +15.5 dB */
+	    }
 	}
 	return 0;
 }
@@ -98,11 +124,11 @@
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 	mutex_lock(&chip->mgr->mixer_mutex);
 	if (kcontrol->private_value == 0) {	/* playback */
-		ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
-		ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
+	  ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
+	  ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
 	} else {				/* capture */
-		ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
-		ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
+	  ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
+	  ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
 	}
 	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
@@ -123,18 +149,35 @@
 			&chip->analog_capture_volume[i] :
 			&chip->analog_playback_volume[i];
 		if (is_capture) {
-			if (new_volume < PCXHR_ANALOG_CAPTURE_LEVEL_MIN ||
-			    new_volume > PCXHR_ANALOG_CAPTURE_LEVEL_MAX)
-				continue;
+			if (chip->mgr->is_hr_stereo) {
+				if (new_volume < HR222_LINE_CAPTURE_LEVEL_MIN ||
+				    new_volume > HR222_LINE_CAPTURE_LEVEL_MAX)
+					continue;
+			} else {
+				if (new_volume < PCXHR_LINE_CAPTURE_LEVEL_MIN ||
+				    new_volume > PCXHR_LINE_CAPTURE_LEVEL_MAX)
+					continue;
+			}
 		} else {
-			if (new_volume < PCXHR_ANALOG_PLAYBACK_LEVEL_MIN ||
-			    new_volume > PCXHR_ANALOG_PLAYBACK_LEVEL_MAX)
-				continue;
+			if (chip->mgr->is_hr_stereo) {
+				if (new_volume < HR222_LINE_PLAYBACK_LEVEL_MIN ||
+				    new_volume > HR222_LINE_PLAYBACK_LEVEL_MAX)
+					continue;
+			} else {
+				if (new_volume < PCXHR_LINE_PLAYBACK_LEVEL_MIN ||
+				    new_volume > PCXHR_LINE_PLAYBACK_LEVEL_MAX)
+					continue;
+			}
 		}
 		if (*stored_volume != new_volume) {
 			*stored_volume = new_volume;
 			changed = 1;
-			pcxhr_update_analog_audio_level(chip, is_capture, i);
+			if (chip->mgr->is_hr_stereo)
+				hr222_update_analog_audio_level(chip,
+								is_capture, i);
+			else
+				pcxhr_update_analog_audio_level(chip,
+								is_capture, i);
 		}
 	}
 	mutex_unlock(&chip->mgr->mixer_mutex);
@@ -153,6 +196,7 @@
 };
 
 /* shared */
+
 #define pcxhr_sw_info		snd_ctl_boolean_stereo_info
 
 static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol,
@@ -180,7 +224,10 @@
 				!!ucontrol->value.integer.value[i];
 			changed = 1;
 			/* update playback levels */
-			pcxhr_update_analog_audio_level(chip, 0, i);
+			if (chip->mgr->is_hr_stereo)
+				hr222_update_analog_audio_level(chip, 0, i);
+			else
+				pcxhr_update_analog_audio_level(chip, 0, i);
 		}
 	}
 	mutex_unlock(&chip->mgr->mixer_mutex);
@@ -251,7 +298,8 @@
 #define VALID_AUDIO_IO_MUTE_LEVEL	0x000004
 #define VALID_AUDIO_IO_MUTE_MONITOR_1	0x000008
 
-static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, int channel)
+static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip,
+					 int capture, int channel)
 {
 	int err;
 	struct pcxhr_rmh rmh;
@@ -264,18 +312,20 @@
 
 	pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST);
 	/* add channel mask */
-	pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, 1 << (channel + pipe->first_audio));
-	/* TODO : if mask (3 << pipe->first_audio) is used, left and right channel
-	 * will be programmed to the same params
-	 */
+	pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0,
+				  1 << (channel + pipe->first_audio));
+	/* TODO : if mask (3 << pipe->first_audio) is used, left and right
+	 * channel will be programmed to the same params */
 	if (capture) {
 		rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL;
-		/* VALID_AUDIO_IO_MUTE_LEVEL not yet handled (capture pipe level) */
+		/* VALID_AUDIO_IO_MUTE_LEVEL not yet handled
+		 * (capture pipe level) */
 		rmh.cmd[2] = chip->digital_capture_volume[channel];
 	} else {
-		rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | VALID_AUDIO_IO_MUTE_MONITOR_1;
-		/* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL not yet
-		 * handled (playback pipe level)
+		rmh.cmd[0] |=	VALID_AUDIO_IO_MONITOR_LEVEL |
+				VALID_AUDIO_IO_MUTE_MONITOR_1;
+		/* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL
+		 * not yet handled (playback pipe level)
 		 */
 		rmh.cmd[2] = chip->monitoring_volume[channel] << 10;
 		if (chip->monitoring_active[channel] == 0)
@@ -284,8 +334,8 @@
 	rmh.cmd_len = 3;
 
 	err = pcxhr_send_msg(chip->mgr, &rmh);
-	if(err<0) {
-		snd_printk(KERN_DEBUG "error update_audio_level card(%d) err(%x)\n",
+	if (err < 0) {
+		snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n",
 			   chip->chip_idx, err);
 		return -EINVAL;
 	}
@@ -309,15 +359,15 @@
 			     struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
-	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);		/* index */
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);	/* index */
 	int *stored_volume;
 	int is_capture = kcontrol->private_value;
 
 	mutex_lock(&chip->mgr->mixer_mutex);
-	if (is_capture)
-		stored_volume = chip->digital_capture_volume;		/* digital capture */
-	else
-		stored_volume = chip->digital_playback_volume[idx];	/* digital playback */
+	if (is_capture)		/* digital capture */
+		stored_volume = chip->digital_capture_volume;
+	else			/* digital playback */
+		stored_volume = chip->digital_playback_volume[idx];
 	ucontrol->value.integer.value[0] = stored_volume[0];
 	ucontrol->value.integer.value[1] = stored_volume[1];
 	mutex_unlock(&chip->mgr->mixer_mutex);
@@ -328,7 +378,7 @@
 			     struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
-	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);		/* index */
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);	/* index */
 	int changed = 0;
 	int is_capture = kcontrol->private_value;
 	int *stored_volume;
@@ -384,7 +434,8 @@
 	return 0;
 }
 
-static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 	int changed = 0;
@@ -444,8 +495,8 @@
 		if (chip->monitoring_volume[i] !=
 		    ucontrol->value.integer.value[i]) {
 			chip->monitoring_volume[i] =
-				!!ucontrol->value.integer.value[i];
-			if(chip->monitoring_active[i])
+				ucontrol->value.integer.value[i];
+			if (chip->monitoring_active[i])
 				/* update monitoring volume and mute */
 				/* do only when monitoring is unmuted */
 				pcxhr_update_audio_pipe_level(chip, 0, i);
@@ -460,7 +511,7 @@
 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
 	.access =	(SNDRV_CTL_ELEM_ACCESS_READWRITE |
 			 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-	.name =         "Monitoring Volume",
+	.name =         "Monitoring Playback Volume",
 	.info =		pcxhr_digital_vol_info,		/* shared */
 	.get =		pcxhr_monitor_vol_get,
 	.put =		pcxhr_monitor_vol_put,
@@ -511,7 +562,7 @@
 
 static struct snd_kcontrol_new pcxhr_control_monitor_sw = {
 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name =         "Monitoring Switch",
+	.name =         "Monitoring Playback Switch",
 	.info =         pcxhr_sw_info,		/* shared */
 	.get =          pcxhr_monitor_sw_get,
 	.put =          pcxhr_monitor_sw_put
@@ -533,7 +584,7 @@
 	struct pcxhr_rmh rmh;
 	unsigned int mask, reg;
 	unsigned int codec;
-	int err, use_src, changed;
+	int err, changed;
 
 	switch (chip->chip_idx) {
 	case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break;
@@ -542,13 +593,10 @@
 	case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break;
 	default: return -EINVAL;
 	}
-	reg = 0;	/* audio source from analog plug */
-	use_src = 0;	/* do not activate codec SRC */
-
 	if (chip->audio_capture_source != 0) {
 		reg = mask;	/* audio source from digital plug */
-		if (chip->audio_capture_source == 2)
-			use_src = 1;
+	} else {
+		reg = 0;	/* audio source from analog plug */
 	}
 	/* set the input source */
 	pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed);
@@ -560,29 +608,61 @@
 		if (err)
 			return err;
 	}
-	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);	/* set codec SRC on off */
-	rmh.cmd_len = 3;
-	rmh.cmd[0] |= IO_NUM_UER_CHIP_REG;
-	rmh.cmd[1] = codec;
-	rmh.cmd[2] = (CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x54);
-	err = pcxhr_send_msg(chip->mgr, &rmh);
-	if(err)
-		return err;
-	rmh.cmd[2] = (CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x49);
-	err = pcxhr_send_msg(chip->mgr, &rmh);
+	if (chip->mgr->board_aes_in_192k) {
+		int i;
+		unsigned int src_config = 0xC0;
+		/* update all src configs with one call */
+		for (i = 0; (i < 4) && (i < chip->mgr->capture_chips); i++) {
+			if (chip->mgr->chip[i]->audio_capture_source == 2)
+				src_config |= (1 << (3 - i));
+		}
+		/* set codec SRC on off */
+		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
+		rmh.cmd_len = 2;
+		rmh.cmd[0] |= IO_NUM_REG_CONFIG_SRC;
+		rmh.cmd[1] = src_config;
+		err = pcxhr_send_msg(chip->mgr, &rmh);
+	} else {
+		int use_src = 0;
+		if (chip->audio_capture_source == 2)
+			use_src = 1;
+		/* set codec SRC on off */
+		pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
+		rmh.cmd_len = 3;
+		rmh.cmd[0] |= IO_NUM_UER_CHIP_REG;
+		rmh.cmd[1] = codec;
+		rmh.cmd[2] = ((CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) |
+			      (use_src ? 0x41 : 0x54));
+		err = pcxhr_send_msg(chip->mgr, &rmh);
+		if (err)
+			return err;
+		rmh.cmd[2] = ((CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) |
+			      (use_src ? 0x41 : 0x49));
+		err = pcxhr_send_msg(chip->mgr, &rmh);
+	}
 	return err;
 }
 
 static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[3] = {"Analog", "Digital", "Digi+SRC"};
+	static const char *texts[5] = {
+		"Line", "Digital", "Digi+SRC", "Mic", "Line+Mic"
+	};
+	int i;
+	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 
+	i = 2;			/* no SRC, no Mic available */
+	if (chip->mgr->board_has_aes1) {
+		i = 3;		/* SRC available */
+		if (chip->mgr->board_has_mic)
+			i = 5;	/* Mic and MicroMix available */
+	}
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
-	uinfo->value.enumerated.items = 3;
-	if (uinfo->value.enumerated.item > 2)
-		uinfo->value.enumerated.item = 2;
+	uinfo->value.enumerated.items = i;
+	if (uinfo->value.enumerated.item > (i-1))
+		uinfo->value.enumerated.item = i-1;
 	strcpy(uinfo->value.enumerated.name,
 		texts[uinfo->value.enumerated.item]);
 	return 0;
@@ -601,13 +681,21 @@
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 	int ret = 0;
-
-	if (ucontrol->value.enumerated.item[0] >= 3)
+	int i = 2;		/* no SRC, no Mic available */
+	if (chip->mgr->board_has_aes1) {
+		i = 3;		/* SRC available */
+		if (chip->mgr->board_has_mic)
+			i = 5;	/* Mic and MicroMix available */
+	}
+	if (ucontrol->value.enumerated.item[0] >= i)
 		return -EINVAL;
 	mutex_lock(&chip->mgr->mixer_mutex);
 	if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) {
 		chip->audio_capture_source = ucontrol->value.enumerated.item[0];
-		pcxhr_set_audio_source(chip);
+		if (chip->mgr->is_hr_stereo)
+			hr222_set_audio_source(chip);
+		else
+			pcxhr_set_audio_source(chip);
 		ret = 1;
 	}
 	mutex_unlock(&chip->mgr->mixer_mutex);
@@ -626,25 +714,46 @@
 /*
  * clock type selection
  * enum pcxhr_clock_type {
- *		PCXHR_CLOCK_TYPE_INTERNAL = 0,
- *		PCXHR_CLOCK_TYPE_WORD_CLOCK,
- *		PCXHR_CLOCK_TYPE_AES_SYNC,
- *		PCXHR_CLOCK_TYPE_AES_1,
- *		PCXHR_CLOCK_TYPE_AES_2,
- *		PCXHR_CLOCK_TYPE_AES_3,
- *		PCXHR_CLOCK_TYPE_AES_4,
- *	};
+ *	PCXHR_CLOCK_TYPE_INTERNAL = 0,
+ *	PCXHR_CLOCK_TYPE_WORD_CLOCK,
+ *	PCXHR_CLOCK_TYPE_AES_SYNC,
+ *	PCXHR_CLOCK_TYPE_AES_1,
+ *	PCXHR_CLOCK_TYPE_AES_2,
+ *	PCXHR_CLOCK_TYPE_AES_3,
+ *	PCXHR_CLOCK_TYPE_AES_4,
+ *	PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4,
+ *	HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL,
+ *	HR22_CLOCK_TYPE_AES_SYNC,
+ *	HR22_CLOCK_TYPE_AES_1,
+ *	HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1,
+ * };
  */
 
 static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[7] = {
-		"Internal", "WordClock", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4"
+	static const char *textsPCXHR[7] = {
+		"Internal", "WordClock", "AES Sync",
+		"AES 1", "AES 2", "AES 3", "AES 4"
 	};
+	static const char *textsHR22[3] = {
+		"Internal", "AES Sync", "AES 1"
+	};
+	const char **texts;
 	struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol);
-	int clock_items = 3 + mgr->capture_chips;
-
+	int clock_items = 2;	/* at least Internal and AES Sync clock */
+	if (mgr->board_has_aes1) {
+		clock_items += mgr->capture_chips;	/* add AES x */
+		if (!mgr->is_hr_stereo)
+			clock_items += 1;		/* add word clock */
+	}
+	if (mgr->is_hr_stereo) {
+		texts = textsHR22;
+		snd_BUG_ON(clock_items > (HR22_CLOCK_TYPE_MAX+1));
+	} else {
+		texts = textsPCXHR;
+		snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1));
+	}
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
 	uinfo->value.enumerated.items = clock_items;
@@ -667,9 +776,13 @@
 				struct snd_ctl_elem_value *ucontrol)
 {
 	struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol);
-	unsigned int clock_items = 3 + mgr->capture_chips;
 	int rate, ret = 0;
-
+	unsigned int clock_items = 2; /* at least Internal and AES Sync clock */
+	if (mgr->board_has_aes1) {
+		clock_items += mgr->capture_chips;	/* add AES x */
+		if (!mgr->is_hr_stereo)
+			clock_items += 1;		/* add word clock */
+	}
 	if (ucontrol->value.enumerated.item[0] >= clock_items)
 		return -EINVAL;
 	mutex_lock(&mgr->mixer_mutex);
@@ -677,7 +790,8 @@
 		mutex_lock(&mgr->setup_mutex);
 		mgr->use_clock_type = ucontrol->value.enumerated.item[0];
 		if (mgr->use_clock_type)
-			pcxhr_get_external_clock(mgr, mgr->use_clock_type, &rate);
+			pcxhr_get_external_clock(mgr, mgr->use_clock_type,
+						 &rate);
 		else
 			rate = mgr->sample_rate;
 		if (rate) {
@@ -686,7 +800,7 @@
 				mgr->sample_rate = rate;
 		}
 		mutex_unlock(&mgr->setup_mutex);
-		ret = 1;	/* return 1 even if the set was not done. ok ? */
+		ret = 1; /* return 1 even if the set was not done. ok ? */
 	}
 	mutex_unlock(&mgr->mixer_mutex);
 	return ret;
@@ -747,14 +861,16 @@
 /*
  * IEC958 status bits
  */
-static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int pcxhr_iec958_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 pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char* aes_bits)
+static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip,
+				     int aes_idx, unsigned char *aes_bits)
 {
 	int i, err;
 	unsigned char temp;
@@ -763,39 +879,61 @@
 	pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
 	rmh.cmd[0] |= IO_NUM_UER_CHIP_REG;
 	switch (chip->chip_idx) {
-	case 0:	rmh.cmd[1] = CS8420_01_CS; break;	/* use CS8416_01_CS for AES SYNC plug */
+	  /* instead of CS8420_01_CS use CS8416_01_CS for AES SYNC plug */
+	case 0:	rmh.cmd[1] = CS8420_01_CS; break;
 	case 1:	rmh.cmd[1] = CS8420_23_CS; break;
 	case 2:	rmh.cmd[1] = CS8420_45_CS; break;
 	case 3:	rmh.cmd[1] = CS8420_67_CS; break;
 	default: return -EINVAL;
 	}
-	switch (aes_idx) {
-	case 0:	rmh.cmd[2] = CS8420_CSB0; break;	/* use CS8416_CSBx for AES SYNC plug */
-	case 1:	rmh.cmd[2] = CS8420_CSB1; break;
-	case 2:	rmh.cmd[2] = CS8420_CSB2; break;
-	case 3:	rmh.cmd[2] = CS8420_CSB3; break;
-	case 4:	rmh.cmd[2] = CS8420_CSB4; break;
-	default: return -EINVAL;
+	if (chip->mgr->board_aes_in_192k) {
+		switch (aes_idx) {
+		case 0:	rmh.cmd[2] = CS8416_CSB0; break;
+		case 1:	rmh.cmd[2] = CS8416_CSB1; break;
+		case 2:	rmh.cmd[2] = CS8416_CSB2; break;
+		case 3:	rmh.cmd[2] = CS8416_CSB3; break;
+		case 4:	rmh.cmd[2] = CS8416_CSB4; break;
+		default: return -EINVAL;
+		}
+	} else {
+		switch (aes_idx) {
+		  /* instead of CS8420_CSB0 use CS8416_CSBx for AES SYNC plug */
+		case 0:	rmh.cmd[2] = CS8420_CSB0; break;
+		case 1:	rmh.cmd[2] = CS8420_CSB1; break;
+		case 2:	rmh.cmd[2] = CS8420_CSB2; break;
+		case 3:	rmh.cmd[2] = CS8420_CSB3; break;
+		case 4:	rmh.cmd[2] = CS8420_CSB4; break;
+		default: return -EINVAL;
+		}
 	}
-	rmh.cmd[1] &= 0x0fffff;			/* size and code the chip id for the fpga */
-	rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI;	/* chip signature + map for spi read */
+	/* size and code the chip id for the fpga */
+	rmh.cmd[1] &= 0x0fffff;
+	/* chip signature + map for spi read */
+	rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI;
 	rmh.cmd_len = 3;
 	err = pcxhr_send_msg(chip->mgr, &rmh);
 	if (err)
 		return err;
-	temp = 0;
-	for (i = 0; i < 8; i++) {
-		/* attention : reversed bit order (not with CS8416_01_CS) */
-		temp <<= 1;
-		if (rmh.stat[1] & (1 << i))
-			temp |= 1;
+
+	if (chip->mgr->board_aes_in_192k) {
+		temp = (unsigned char)rmh.stat[1];
+	} else {
+		temp = 0;
+		/* reversed bit order (not with CS8416_01_CS) */
+		for (i = 0; i < 8; i++) {
+			temp <<= 1;
+			if (rmh.stat[1] & (1 << i))
+				temp |= 1;
+		}
 	}
-	snd_printdd("read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp);
+	snd_printdd("read iec958 AES %d byte %d = 0x%x\n",
+		    chip->chip_idx, aes_idx, temp);
 	*aes_bits = temp;
 	return 0;
 }
 
-static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 	unsigned char aes_bits;
@@ -806,7 +944,12 @@
 		if (kcontrol->private_value == 0)	/* playback */
 			aes_bits = chip->aes_bits[i];
 		else {				/* capture */
-			err = pcxhr_iec958_capture_byte(chip, i, &aes_bits);
+			if (chip->mgr->is_hr_stereo)
+				err = hr222_iec958_capture_byte(chip, i,
+								&aes_bits);
+			else
+				err = pcxhr_iec958_capture_byte(chip, i,
+								&aes_bits);
 			if (err)
 				break;
 		}
@@ -825,7 +968,8 @@
         return 0;
 }
 
-static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char aes_bits)
+static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip,
+				    int aes_idx, unsigned char aes_bits)
 {
 	int i, err, cmd;
 	unsigned char new_bits = aes_bits;
@@ -834,12 +978,12 @@
 
 	for (i = 0; i < 8; i++) {
 		if ((old_bits & 0x01) != (new_bits & 0x01)) {
-			cmd = chip->chip_idx & 0x03;		/* chip index 0..3 */
-			if(chip->chip_idx > 3)
+			cmd = chip->chip_idx & 0x03;      /* chip index 0..3 */
+			if (chip->chip_idx > 3)
 				/* new bit used if chip_idx>3 (PCX1222HR) */
 				cmd |= 1 << 22;
-			cmd |= ((aes_idx << 3) + i) << 2;	/* add bit offset */
-			cmd |= (new_bits & 0x01) << 23;		/* add bit value */
+			cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */
+			cmd |= (new_bits & 0x01) << 23;   /* add bit value */
 			pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
 			rmh.cmd[0] |= IO_NUM_REG_CUER;
 			rmh.cmd[1] = cmd;
@@ -867,7 +1011,12 @@
 	mutex_lock(&chip->mgr->mixer_mutex);
 	for (i = 0; i < 5; i++) {
 		if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) {
-			pcxhr_iec958_update_byte(chip, i, ucontrol->value.iec958.status[i]);
+			if (chip->mgr->is_hr_stereo)
+				hr222_iec958_update_byte(chip, i,
+					ucontrol->value.iec958.status[i]);
+			else
+				pcxhr_iec958_update_byte(chip, i,
+					ucontrol->value.iec958.status[i]);
 			changed = 1;
 		}
 	}
@@ -917,29 +1066,53 @@
 			/* at boot time the digital volumes are unmuted 0dB */
 			for (j = 0; j < PCXHR_PLAYBACK_STREAMS; j++) {
 				chip->digital_playback_active[j][i] = 1;
-				chip->digital_playback_volume[j][i] = PCXHR_DIGITAL_ZERO_LEVEL;
+				chip->digital_playback_volume[j][i] =
+					PCXHR_DIGITAL_ZERO_LEVEL;
 			}
-			/* after boot, only two bits are set on the uer interface */
-			chip->aes_bits[0] = IEC958_AES0_PROFESSIONAL | IEC958_AES0_PRO_FS_48000;
-/* only for test purpose, remove later */
+			/* after boot, only two bits are set on the uer
+			 * interface
+			 */
+			chip->aes_bits[0] = (IEC958_AES0_PROFESSIONAL |
+					     IEC958_AES0_PRO_FS_48000);
 #ifdef CONFIG_SND_DEBUG
-			/* analog volumes for playback (is LEVEL_MIN after boot) */
+			/* analog volumes for playback
+			 * (is LEVEL_MIN after boot)
+			 */
 			chip->analog_playback_active[i] = 1;
-			chip->analog_playback_volume[i] = PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL;
-			pcxhr_update_analog_audio_level(chip, 0, i);
+			if (chip->mgr->is_hr_stereo)
+				chip->analog_playback_volume[i] =
+					HR222_LINE_PLAYBACK_ZERO_LEVEL;
+			else {
+				chip->analog_playback_volume[i] =
+					PCXHR_LINE_PLAYBACK_ZERO_LEVEL;
+				pcxhr_update_analog_audio_level(chip, 0, i);
+			}
 #endif
-/* test end */
+			/* stereo cards need to be initialised after boot */
+			if (chip->mgr->is_hr_stereo)
+				hr222_update_analog_audio_level(chip, 0, i);
 		}
 		if (chip->nb_streams_capt) {
 			/* at boot time the digital volumes are unmuted 0dB */
-			chip->digital_capture_volume[i] = PCXHR_DIGITAL_ZERO_LEVEL;
-/* only for test purpose, remove later */
+			chip->digital_capture_volume[i] =
+				PCXHR_DIGITAL_ZERO_LEVEL;
+			chip->analog_capture_active = 1;
 #ifdef CONFIG_SND_DEBUG
-			/* analog volumes for playback (is LEVEL_MIN after boot) */
-			chip->analog_capture_volume[i]  = PCXHR_ANALOG_CAPTURE_ZERO_LEVEL;
-			pcxhr_update_analog_audio_level(chip, 1, i);
+			/* analog volumes for playback
+			 * (is LEVEL_MIN after boot)
+			 */
+			if (chip->mgr->is_hr_stereo)
+				chip->analog_capture_volume[i] =
+					HR222_LINE_CAPTURE_ZERO_LEVEL;
+			else {
+				chip->analog_capture_volume[i] =
+					PCXHR_LINE_CAPTURE_ZERO_LEVEL;
+				pcxhr_update_analog_audio_level(chip, 1, i);
+			}
 #endif
-/* test end */
+			/* stereo cards need to be initialised after boot */
+			if (chip->mgr->is_hr_stereo)
+				hr222_update_analog_audio_level(chip, 1, i);
 		}
 	}
 
@@ -963,90 +1136,125 @@
 			temp = pcxhr_control_analog_level;
 			temp.name = "Master Playback Volume";
 			temp.private_value = 0; /* playback */
-			temp.tlv.p = db_scale_analog_playback;
-			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+			if (mgr->is_hr_stereo)
+				temp.tlv.p = db_scale_a_hr222_playback;
+			else
+				temp.tlv.p = db_scale_analog_playback;
+			err = snd_ctl_add(chip->card,
+					  snd_ctl_new1(&temp, chip));
+			if (err < 0)
 				return err;
+
 			/* output mute controls */
-			if ((err = snd_ctl_add(chip->card,
-					       snd_ctl_new1(&pcxhr_control_output_switch,
-							    chip))) < 0)
+			err = snd_ctl_add(chip->card,
+				snd_ctl_new1(&pcxhr_control_output_switch,
+					     chip));
+			if (err < 0)
 				return err;
-			
+
 			temp = snd_pcxhr_pcm_vol;
 			temp.name = "PCM Playback Volume";
 			temp.count = PCXHR_PLAYBACK_STREAMS;
 			temp.private_value = 0; /* playback */
-			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+			err = snd_ctl_add(chip->card,
+					  snd_ctl_new1(&temp, chip));
+			if (err < 0)
 				return err;
 
-			if ((err = snd_ctl_add(chip->card,
-					       snd_ctl_new1(&pcxhr_control_pcm_switch,
-							    chip))) < 0)
+			err = snd_ctl_add(chip->card,
+				snd_ctl_new1(&pcxhr_control_pcm_switch, chip));
+			if (err < 0)
 				return err;
 
 			/* IEC958 controls */
-			if ((err = snd_ctl_add(chip->card,
-					       snd_ctl_new1(&pcxhr_control_playback_iec958_mask,
-							    chip))) < 0)
+			err = snd_ctl_add(chip->card,
+				snd_ctl_new1(&pcxhr_control_playback_iec958_mask,
+					     chip));
+			if (err < 0)
 				return err;
-			if ((err = snd_ctl_add(chip->card,
-					       snd_ctl_new1(&pcxhr_control_playback_iec958,
-							    chip))) < 0)
+
+			err = snd_ctl_add(chip->card,
+				snd_ctl_new1(&pcxhr_control_playback_iec958,
+					     chip));
+			if (err < 0)
 				return err;
 		}
 		if (chip->nb_streams_capt) {
-			/* analog input level control only on first two chips !*/
+			/* analog input level control */
 			temp = pcxhr_control_analog_level;
-			temp.name = "Master Capture Volume";
+			temp.name = "Line Capture Volume";
 			temp.private_value = 1; /* capture */
-			temp.tlv.p = db_scale_analog_capture;
-			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+			if (mgr->is_hr_stereo)
+				temp.tlv.p = db_scale_a_hr222_capture;
+			else
+				temp.tlv.p = db_scale_analog_capture;
+
+			err = snd_ctl_add(chip->card,
+					  snd_ctl_new1(&temp, chip));
+			if (err < 0)
 				return err;
 
 			temp = snd_pcxhr_pcm_vol;
 			temp.name = "PCM Capture Volume";
 			temp.count = 1;
 			temp.private_value = 1; /* capture */
-			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+
+			err = snd_ctl_add(chip->card,
+					  snd_ctl_new1(&temp, chip));
+			if (err < 0)
 				return err;
+
 			/* Audio source */
-			if ((err = snd_ctl_add(chip->card,
-					       snd_ctl_new1(&pcxhr_control_audio_src,
-							    chip))) < 0)
+			err = snd_ctl_add(chip->card,
+				snd_ctl_new1(&pcxhr_control_audio_src, chip));
+			if (err < 0)
 				return err;
+
 			/* IEC958 controls */
-			if ((err = snd_ctl_add(chip->card,
-					       snd_ctl_new1(&pcxhr_control_capture_iec958_mask,
-							    chip))) < 0)
+			err = snd_ctl_add(chip->card,
+				snd_ctl_new1(&pcxhr_control_capture_iec958_mask,
+					     chip));
+			if (err < 0)
 				return err;
-			if ((err = snd_ctl_add(chip->card,
-					       snd_ctl_new1(&pcxhr_control_capture_iec958,
-							    chip))) < 0)
+
+			err = snd_ctl_add(chip->card,
+				snd_ctl_new1(&pcxhr_control_capture_iec958,
+					     chip));
+			if (err < 0)
 				return err;
+
+			if (mgr->is_hr_stereo) {
+				err = hr222_add_mic_controls(chip);
+				if (err < 0)
+					return err;
+			}
 		}
 		/* monitoring only if playback and capture device available */
 		if (chip->nb_streams_capt > 0 && chip->nb_streams_play > 0) {
 			/* monitoring */
-			if ((err = snd_ctl_add(chip->card,
-					       snd_ctl_new1(&pcxhr_control_monitor_vol,
-							    chip))) < 0)
+			err = snd_ctl_add(chip->card,
+				snd_ctl_new1(&pcxhr_control_monitor_vol, chip));
+			if (err < 0)
 				return err;
-			if ((err = snd_ctl_add(chip->card,
-					       snd_ctl_new1(&pcxhr_control_monitor_sw,
-							    chip))) < 0)
+
+			err = snd_ctl_add(chip->card,
+				snd_ctl_new1(&pcxhr_control_monitor_sw, chip));
+			if (err < 0)
 				return err;
 		}
 
 		if (i == 0) {
 			/* clock mode only one control per pcxhr */
-			if ((err = snd_ctl_add(chip->card,
-					       snd_ctl_new1(&pcxhr_control_clock_type,
-							    mgr))) < 0)
+			err = snd_ctl_add(chip->card,
+				snd_ctl_new1(&pcxhr_control_clock_type, mgr));
+			if (err < 0)
 				return err;
-			/* non standard control used to scan the external clock presence/frequencies */
-			if ((err = snd_ctl_add(chip->card,
-					       snd_ctl_new1(&pcxhr_control_clock_rate,
-							    mgr))) < 0)
+			/* non standard control used to scan
+			 * the external clock presence/frequencies
+			 */
+			err = snd_ctl_add(chip->card,
+				snd_ctl_new1(&pcxhr_control_clock_rate, mgr));
+			if (err < 0)
 				return err;
 		}
 
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index e9f0706..3caacfb 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -172,7 +172,7 @@
 
 #define MAX_WRITE_RETRY  10	/* cmd interface limits */
 #define MAX_ERROR_COUNT  10
-#define CMDIF_TIMEOUT    500000
+#define CMDIF_TIMEOUT    50000
 #define RESET_TRIES      5
 
 #define READ_PORT_ULONG(p)     inl((unsigned long)&(p))
@@ -1754,7 +1754,7 @@
 		if (IS_EOBIRQ(cif->hwport) || IS_EOSIRQ(cif->hwport) ||
 		    IS_EOCIRQ(cif->hwport)) {
 			chip->handled_irqs++;
-			tasklet_hi_schedule(&chip->riptide_tq);
+			tasklet_schedule(&chip->riptide_tq);
 		}
 		if (chip->rmidi && IS_MPUIRQ(cif->hwport)) {
 			chip->handled_irqs++;
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 736246f..44d0c15 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -1452,7 +1452,7 @@
 	if (snd_rawmidi_new (card, buf, id, 1, 1, &hdsp->midi[id].rmidi) < 0)
 		return -1;
 
-	sprintf (hdsp->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1);
+	sprintf(hdsp->midi[id].rmidi->name, "HDSP MIDI %d", id+1);
 	hdsp->midi[id].rmidi->private_data = &hdsp->midi[id];
 
 	snd_rawmidi_set_ops (hdsp->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdsp_midi_output);
@@ -3750,7 +3750,7 @@
 		}
 	}
 	if (hdsp->use_midi_tasklet && schedule)
-		tasklet_hi_schedule(&hdsp->midi_tasklet);
+		tasklet_schedule(&hdsp->midi_tasklet);
 	return IRQ_HANDLED;
 }
 
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 98762f9..71231cf 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -1293,7 +1293,7 @@
 	if (err < 0)
 		return err;
 
-	sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1);
+	sprintf(hdspm->midi[id].rmidi->name, "HDSPM MIDI %d", id+1);
 	hdspm->midi[id].rmidi->private_data = &hdspm->midi[id];
 
 	snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
@@ -3476,7 +3476,7 @@
 		schedule = 1;
 	}
 	if (schedule)
-		tasklet_hi_schedule(&hdspm->midi_tasklet);
+		tasklet_schedule(&hdspm->midi_tasklet);
 	return IRQ_HANDLED;
 }
 
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
index fa4b113..ea903c8 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
@@ -41,7 +41,7 @@
 		if (stat & PDAUDIOCF_IRQOVR)	/* should never happen */
 			snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
 		if (chip->pcm_substream)
-			tasklet_hi_schedule(&chip->tq);
+			tasklet_schedule(&chip->tq);
 		if (!(stat & PDAUDIOCF_IRQAKM))
 			stat |= PDAUDIOCF_IRQAKM;	/* check rate */
 	}
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index a38c0c7..af76ee8 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -1033,7 +1033,7 @@
 	}
 	if (of_device_is_compatible(sound, "tumbler")) {
 		chip->model = PMAC_TUMBLER;
-		chip->can_capture = 0;  /* no capture */
+		chip->can_capture = machine_is_compatible("PowerMac4,2");
 		chip->can_duplex = 0;
 		// chip->can_byte_swap = 0; /* FIXME: check this */
 		chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index f746e15..3eb2233 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -875,7 +875,8 @@
 	  .put = tumbler_put_master_switch
 	},
 	DEFINE_SNAPPER_MIX("PCM Playback Volume", 0, VOL_IDX_PCM),
-	DEFINE_SNAPPER_MIX("PCM Playback Volume", 1, VOL_IDX_PCM2),
+	/* Alternative PCM is assigned to Mic analog loopback on iBook G4 */
+	DEFINE_SNAPPER_MIX("Mic Playback Volume", 0, VOL_IDX_PCM2),
 	DEFINE_SNAPPER_MIX("Monitor Mix Volume", 0, VOL_IDX_ADC),
 	DEFINE_SNAPPER_MONO("Tone Control - Bass", bass),
 	DEFINE_SNAPPER_MONO("Tone Control - Treble", treble),
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 4dfda66..ef025c6 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -22,17 +22,16 @@
 config SND_SOC_AC97_BUS
 	bool
 
-# All the supported Soc's
-source "sound/soc/at32/Kconfig"
-source "sound/soc/at91/Kconfig"
+# All the supported SoCs
+source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
+source "sound/soc/blackfin/Kconfig"
+source "sound/soc/davinci/Kconfig"
+source "sound/soc/fsl/Kconfig"
+source "sound/soc/omap/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
 source "sound/soc/sh/Kconfig"
-source "sound/soc/fsl/Kconfig"
-source "sound/soc/davinci/Kconfig"
-source "sound/soc/omap/Kconfig"
-source "sound/soc/blackfin/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index d849349..86a9b1f 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,5 +1,13 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o
 
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
-obj-$(CONFIG_SND_SOC)	+= codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/
-obj-$(CONFIG_SND_SOC)	+= omap/ au1x/ blackfin/
+obj-$(CONFIG_SND_SOC)	+= codecs/
+obj-$(CONFIG_SND_SOC)	+= atmel/
+obj-$(CONFIG_SND_SOC)	+= au1x/
+obj-$(CONFIG_SND_SOC)	+= blackfin/
+obj-$(CONFIG_SND_SOC)	+= davinci/
+obj-$(CONFIG_SND_SOC)	+= fsl/
+obj-$(CONFIG_SND_SOC)	+= omap/
+obj-$(CONFIG_SND_SOC)	+= pxa/
+obj-$(CONFIG_SND_SOC)	+= s3c24xx/
+obj-$(CONFIG_SND_SOC)	+= sh/
diff --git a/sound/soc/at32/Kconfig b/sound/soc/at32/Kconfig
deleted file mode 100644
index b0765e8..0000000
--- a/sound/soc/at32/Kconfig
+++ /dev/null
@@ -1,34 +0,0 @@
-config SND_AT32_SOC
-        tristate "SoC Audio for the Atmel AT32 System-on-a-Chip"
-        depends on AVR32 && SND_SOC
-        help
-          Say Y or M if you want to add support for codecs attached to 
-          the AT32 SSC interface.  You will also need to
-          to select the audio interfaces to support below.
-
-
-config SND_AT32_SOC_SSC
-        tristate
-
-
-
-config SND_AT32_SOC_PLAYPAQ
-        tristate "SoC Audio support for PlayPaq with WM8510"
-        depends on SND_AT32_SOC && BOARD_PLAYPAQ
-        select SND_AT32_SOC_SSC
-        select SND_SOC_WM8510
-        help
-          Say Y or M here if you want to add support for SoC audio
-          on the LRS PlayPaq.
-
-
-
-config SND_AT32_SOC_PLAYPAQ_SLAVE
-        bool "Run CODEC on PlayPaq in slave mode"
-        depends on SND_AT32_SOC_PLAYPAQ
-        default n
-        help
-          Say Y if you want to run with the AT32 SSC generating the BCLK
-          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.
diff --git a/sound/soc/at32/Makefile b/sound/soc/at32/Makefile
deleted file mode 100644
index c03e55e..0000000
--- a/sound/soc/at32/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# AT32 Platform Support
-snd-soc-at32-objs := at32-pcm.o
-snd-soc-at32-ssc-objs := at32-ssc.o
-
-obj-$(CONFIG_SND_AT32_SOC) += snd-soc-at32.o
-obj-$(CONFIG_SND_AT32_SOC_SSC) += snd-soc-at32-ssc.o
-
-# AT32 Machine Support
-snd-soc-playpaq-objs := playpaq_wm8510.o
-
-obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
diff --git a/sound/soc/at32/at32-pcm.c b/sound/soc/at32/at32-pcm.c
deleted file mode 100644
index c83584f..0000000
--- a/sound/soc/at32/at32-pcm.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/* sound/soc/at32/at32-pcm.c
- * ASoC PCM interface for Atmel AT32 SoC
- *
- * Copyright (C) 2008 Long Range Systems
- *    Geoffrey Wossum <gwossum@acm.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.
- *
- * Note that this is basically a port of the sound/soc/at91-pcm.c to
- * the AVR32 kernel.  Thanks to Frank Mandarino for that code.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-#include <linux/atmel_pdc.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "at32-pcm.h"
-
-
-
-/*--------------------------------------------------------------------------*\
- * Hardware definition
-\*--------------------------------------------------------------------------*/
-/* TODO: These values were taken from the AT91 platform driver, check
- *	 them against real values for AT32
- */
-static const struct snd_pcm_hardware at32_pcm_hardware = {
-	.info = (SNDRV_PCM_INFO_MMAP |
-		 SNDRV_PCM_INFO_MMAP_VALID |
-		 SNDRV_PCM_INFO_INTERLEAVED |
-		 SNDRV_PCM_INFO_BLOCK_TRANSFER |
-		 SNDRV_PCM_INFO_PAUSE),
-
-	.formats = SNDRV_PCM_FMTBIT_S16,
-	.period_bytes_min = 32,
-	.period_bytes_max = 8192,	/* 512 frames * 16 bytes / frame */
-	.periods_min = 2,
-	.periods_max = 1024,
-	.buffer_bytes_max = 32 * 1024,
-};
-
-
-
-/*--------------------------------------------------------------------------*\
- * Data types
-\*--------------------------------------------------------------------------*/
-struct at32_runtime_data {
-	struct at32_pcm_dma_params *params;
-	dma_addr_t dma_buffer;	/* physical address of DMA buffer */
-	dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */
-	size_t period_size;
-
-	dma_addr_t period_ptr;	/* physical address of next period */
-	int periods;		/* period index of period_ptr */
-
-	/* Save PDC registers (for power management) */
-	u32 pdc_xpr_save;
-	u32 pdc_xcr_save;
-	u32 pdc_xnpr_save;
-	u32 pdc_xncr_save;
-};
-
-
-
-/*--------------------------------------------------------------------------*\
- * Helper functions
-\*--------------------------------------------------------------------------*/
-static int at32_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_dma_buffer *dmabuf = &substream->dma_buffer;
-	size_t size = at32_pcm_hardware.buffer_bytes_max;
-
-	dmabuf->dev.type = SNDRV_DMA_TYPE_DEV;
-	dmabuf->dev.dev = pcm->card->dev;
-	dmabuf->private_data = NULL;
-	dmabuf->area = dma_alloc_coherent(pcm->card->dev, size,
-					  &dmabuf->addr, GFP_KERNEL);
-	pr_debug("at32_pcm: preallocate_dma_buffer: "
-		 "area=%p, addr=%p, size=%ld\n",
-		 (void *)dmabuf->area, (void *)dmabuf->addr, size);
-
-	if (!dmabuf->area)
-		return -ENOMEM;
-
-	dmabuf->bytes = size;
-	return 0;
-}
-
-
-
-/*--------------------------------------------------------------------------*\
- * ISR
-\*--------------------------------------------------------------------------*/
-static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *rtd = substream->runtime;
-	struct at32_runtime_data *prtd = rtd->private_data;
-	struct at32_pcm_dma_params *params = prtd->params;
-	static int count;
-
-	count++;
-	if (ssc_sr & params->mask->ssc_endbuf) {
-		pr_warning("at32-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
-			   substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-			   "underrun" : "overrun", params->name, ssc_sr, count);
-
-		/* re-start the PDC */
-		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
-			   params->mask->pdc_disable);
-		prtd->period_ptr += prtd->period_size;
-		if (prtd->period_ptr >= prtd->dma_buffer_end)
-			prtd->period_ptr = prtd->dma_buffer;
-
-
-		ssc_writex(params->ssc->regs, params->pdc->xpr,
-			   prtd->period_ptr);
-		ssc_writex(params->ssc->regs, params->pdc->xcr,
-			   prtd->period_size / params->pdc_xfer_size);
-		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
-			   params->mask->pdc_enable);
-	}
-
-
-	if (ssc_sr & params->mask->ssc_endx) {
-		/* Load the PDC next pointer and counter registers */
-		prtd->period_ptr += prtd->period_size;
-		if (prtd->period_ptr >= prtd->dma_buffer_end)
-			prtd->period_ptr = prtd->dma_buffer;
-		ssc_writex(params->ssc->regs, params->pdc->xnpr,
-			   prtd->period_ptr);
-		ssc_writex(params->ssc->regs, params->pdc->xncr,
-			   prtd->period_size / params->pdc_xfer_size);
-	}
-
-
-	snd_pcm_period_elapsed(substream);
-}
-
-
-
-/*--------------------------------------------------------------------------*\
- * PCM operations
-\*--------------------------------------------------------------------------*/
-static int at32_pcm_hw_params(struct snd_pcm_substream *substream,
-			      struct snd_pcm_hw_params *params)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct at32_runtime_data *prtd = runtime->private_data;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-	/* this may get called several times by oss emulation
-	 * with different params
-	 */
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-	runtime->dma_bytes = params_buffer_bytes(params);
-
-	prtd->params = rtd->dai->cpu_dai->dma_data;
-	prtd->params->dma_intr_handler = at32_pcm_dma_irq;
-
-	prtd->dma_buffer = runtime->dma_addr;
-	prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
-	prtd->period_size = params_period_bytes(params);
-
-	pr_debug("hw_params: DMA for %s initialized "
-		 "(dma_bytes=%ld, period_size=%ld)\n",
-		 prtd->params->name, runtime->dma_bytes, prtd->period_size);
-
-	return 0;
-}
-
-
-
-static int at32_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	struct at32_runtime_data *prtd = substream->runtime->private_data;
-	struct at32_pcm_dma_params *params = prtd->params;
-
-	if (params != NULL) {
-		ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
-			   params->mask->pdc_disable);
-		prtd->params->dma_intr_handler = NULL;
-	}
-
-	return 0;
-}
-
-
-
-static int at32_pcm_prepare(struct snd_pcm_substream *substream)
-{
-	struct at32_runtime_data *prtd = substream->runtime->private_data;
-	struct at32_pcm_dma_params *params = prtd->params;
-
-	ssc_writex(params->ssc->regs, SSC_IDR,
-		   params->mask->ssc_endx | params->mask->ssc_endbuf);
-	ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
-		   params->mask->pdc_disable);
-
-	return 0;
-}
-
-
-static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct snd_pcm_runtime *rtd = substream->runtime;
-	struct at32_runtime_data *prtd = rtd->private_data;
-	struct at32_pcm_dma_params *params = prtd->params;
-	int ret = 0;
-
-	pr_debug("at32_pcm_trigger: buffer_size = %ld, "
-		 "dma_area = %p, dma_bytes = %ld\n",
-		 rtd->buffer_size, rtd->dma_area, rtd->dma_bytes);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		prtd->period_ptr = prtd->dma_buffer;
-
-		ssc_writex(params->ssc->regs, params->pdc->xpr,
-			   prtd->period_ptr);
-		ssc_writex(params->ssc->regs, params->pdc->xcr,
-			   prtd->period_size / params->pdc_xfer_size);
-
-		prtd->period_ptr += prtd->period_size;
-		ssc_writex(params->ssc->regs, params->pdc->xnpr,
-			   prtd->period_ptr);
-		ssc_writex(params->ssc->regs, params->pdc->xncr,
-			   prtd->period_size / params->pdc_xfer_size);
-
-		pr_debug("trigger: period_ptr=%lx, xpr=%x, "
-			 "xcr=%d, xnpr=%x, xncr=%d\n",
-			 (unsigned long)prtd->period_ptr,
-			 ssc_readx(params->ssc->regs, params->pdc->xpr),
-			 ssc_readx(params->ssc->regs, params->pdc->xcr),
-			 ssc_readx(params->ssc->regs, params->pdc->xnpr),
-			 ssc_readx(params->ssc->regs, params->pdc->xncr));
-
-		ssc_writex(params->ssc->regs, SSC_IER,
-			   params->mask->ssc_endx | params->mask->ssc_endbuf);
-		ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
-			   params->mask->pdc_enable);
-
-		pr_debug("sr=%x, imr=%x\n",
-			 ssc_readx(params->ssc->regs, SSC_SR),
-			 ssc_readx(params->ssc->regs, SSC_IER));
-		break;		/* SNDRV_PCM_TRIGGER_START */
-
-
-
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
-			   params->mask->pdc_disable);
-		break;
-
-
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
-			   params->mask->pdc_enable);
-		break;
-
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-
-
-static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct at32_runtime_data *prtd = runtime->private_data;
-	struct at32_pcm_dma_params *params = prtd->params;
-	dma_addr_t ptr;
-	snd_pcm_uframes_t x;
-
-	ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr);
-	x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
-
-	if (x == runtime->buffer_size)
-		x = 0;
-
-	return x;
-}
-
-
-
-static int at32_pcm_open(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct at32_runtime_data *prtd;
-	int ret = 0;
-
-	snd_soc_set_runtime_hwparams(substream, &at32_pcm_hardware);
-
-	/* ensure that buffer size is a multiple of period size */
-	ret = snd_pcm_hw_constraint_integer(runtime,
-					    SNDRV_PCM_HW_PARAM_PERIODS);
-	if (ret < 0)
-		goto out;
-
-	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
-	if (prtd == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	runtime->private_data = prtd;
-
-
-out:
-	return ret;
-}
-
-
-
-static int at32_pcm_close(struct snd_pcm_substream *substream)
-{
-	struct at32_runtime_data *prtd = substream->runtime->private_data;
-
-	kfree(prtd);
-	return 0;
-}
-
-
-static int at32_pcm_mmap(struct snd_pcm_substream *substream,
-			 struct vm_area_struct *vma)
-{
-	return remap_pfn_range(vma, vma->vm_start,
-			       substream->dma_buffer.addr >> PAGE_SHIFT,
-			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
-}
-
-
-
-static struct snd_pcm_ops at32_pcm_ops = {
-	.open = at32_pcm_open,
-	.close = at32_pcm_close,
-	.ioctl = snd_pcm_lib_ioctl,
-	.hw_params = at32_pcm_hw_params,
-	.hw_free = at32_pcm_hw_free,
-	.prepare = at32_pcm_prepare,
-	.trigger = at32_pcm_trigger,
-	.pointer = at32_pcm_pointer,
-	.mmap = at32_pcm_mmap,
-};
-
-
-
-/*--------------------------------------------------------------------------*\
- * ASoC platform driver
-\*--------------------------------------------------------------------------*/
-static u64 at32_pcm_dmamask = 0xffffffff;
-
-static int at32_pcm_new(struct snd_card *card,
-			struct snd_soc_dai *dai,
-			struct snd_pcm *pcm)
-{
-	int ret = 0;
-
-	if (!card->dev->dma_mask)
-		card->dev->dma_mask = &at32_pcm_dmamask;
-	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = 0xffffffff;
-
-	if (dai->playback.channels_min) {
-		ret = at32_pcm_preallocate_dma_buffer(
-			  pcm, SNDRV_PCM_STREAM_PLAYBACK);
-		if (ret)
-			goto out;
-	}
-
-	if (dai->capture.channels_min) {
-		pr_debug("at32-pcm: Allocating PCM capture DMA buffer\n");
-		ret = at32_pcm_preallocate_dma_buffer(
-			  pcm, SNDRV_PCM_STREAM_CAPTURE);
-		if (ret)
-			goto out;
-	}
-
-
-out:
-	return ret;
-}
-
-
-
-static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-	int stream;
-
-	for (stream = 0; stream < 2; stream++) {
-		substream = pcm->streams[stream].substream;
-		if (substream == NULL)
-			continue;
-
-		buf = &substream->dma_buffer;
-		if (!buf->area)
-			continue;
-		dma_free_coherent(pcm->card->dev, buf->bytes,
-				  buf->area, buf->addr);
-		buf->area = NULL;
-	}
-}
-
-
-
-#ifdef CONFIG_PM
-static int at32_pcm_suspend(struct platform_device *pdev,
-			    struct snd_soc_dai *dai)
-{
-	struct snd_pcm_runtime *runtime = dai->runtime;
-	struct at32_runtime_data *prtd;
-	struct at32_pcm_dma_params *params;
-
-	if (runtime == NULL)
-		return 0;
-	prtd = runtime->private_data;
-	params = prtd->params;
-
-	/* Disable the PDC and save the PDC registers */
-	ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
-		   params->mask->pdc_disable);
-
-	prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
-	prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
-	prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr);
-	prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr);
-
-	return 0;
-}
-
-
-
-static int at32_pcm_resume(struct platform_device *pdev,
-			   struct snd_soc_dai *dai)
-{
-	struct snd_pcm_runtime *runtime = dai->runtime;
-	struct at32_runtime_data *prtd;
-	struct at32_pcm_dma_params *params;
-
-	if (runtime == NULL)
-		return 0;
-	prtd = runtime->private_data;
-	params = prtd->params;
-
-	/* Restore the PDC registers and enable the PDC */
-	ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save);
-	ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save);
-	ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
-	ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
-
-	ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, params->mask->pdc_enable);
-	return 0;
-}
-#else /* CONFIG_PM */
-#  define at32_pcm_suspend	NULL
-#  define at32_pcm_resume	NULL
-#endif /* CONFIG_PM */
-
-
-
-struct snd_soc_platform at32_soc_platform = {
-	.name = "at32-audio",
-	.pcm_ops = &at32_pcm_ops,
-	.pcm_new = at32_pcm_new,
-	.pcm_free = at32_pcm_free_dma_buffers,
-	.suspend = at32_pcm_suspend,
-	.resume = at32_pcm_resume,
-};
-EXPORT_SYMBOL_GPL(at32_soc_platform);
-
-
-
-MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>");
-MODULE_DESCRIPTION("Atmel AT32 PCM module");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/at32/at32-pcm.h b/sound/soc/at32/at32-pcm.h
deleted file mode 100644
index 2a52430..0000000
--- a/sound/soc/at32/at32-pcm.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* sound/soc/at32/at32-pcm.h
- * ASoC PCM interface for Atmel AT32 SoC
- *
- * Copyright (C) 2008 Long Range Systems
- *    Geoffrey Wossum <gwossum@acm.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __SOUND_SOC_AT32_AT32_PCM_H
-#define __SOUND_SOC_AT32_AT32_PCM_H __FILE__
-
-#include <linux/atmel-ssc.h>
-
-
-/*
- * Registers and status bits that are required by the PCM driver
- * TODO: Is ptcr really used?
- */
-struct at32_pdc_regs {
-	u32 xpr;		/* PDC RX/TX pointer */
-	u32 xcr;		/* PDC RX/TX counter */
-	u32 xnpr;		/* PDC next RX/TX pointer */
-	u32 xncr;		/* PDC next RX/TX counter */
-	u32 ptcr;		/* PDC transfer control */
-};
-
-
-
-/*
- * SSC mask info
- */
-struct at32_ssc_mask {
-	u32 ssc_enable;		/* SSC RX/TX enable */
-	u32 ssc_disable;	/* SSC RX/TX disable */
-	u32 ssc_endx;		/* SSC ENDTX or ENDRX */
-	u32 ssc_endbuf;		/* SSC TXBUFF or RXBUFF */
-	u32 pdc_enable;		/* PDC RX/TX enable */
-	u32 pdc_disable;	/* PDC RX/TX disable */
-};
-
-
-
-/*
- * This structure, shared between the PCM driver and the interface,
- * contains all information required by the PCM driver to perform the
- * PDC DMA operation.  All fields except dma_intr_handler() are initialized
- * by the interface.  The dms_intr_handler() pointer is set by the PCM
- * driver and called by the interface SSC interrupt handler if it is
- * non-NULL.
- */
-struct at32_pcm_dma_params {
-	char *name;		/* stream identifier */
-	int pdc_xfer_size;	/* PDC counter increment in bytes */
-	struct ssc_device *ssc;	/* SSC device for stream */
-	struct at32_pdc_regs *pdc;	/* PDC register info */
-	struct at32_ssc_mask *mask;	/* SSC mask info */
-	struct snd_pcm_substream *substream;
-	void (*dma_intr_handler) (u32, struct snd_pcm_substream *);
-};
-
-
-
-/*
- * The AT32 ASoC platform driver
- */
-extern struct snd_soc_platform at32_soc_platform;
-
-
-
-/*
- * SSC register access (since ssc_writel() / ssc_readl() require literal name)
- */
-#define ssc_readx(base, reg)            (__raw_readl((base) + (reg)))
-#define ssc_writex(base, reg, value)    __raw_writel((value), (base) + (reg))
-
-#endif /* __SOUND_SOC_AT32_AT32_PCM_H */
diff --git a/sound/soc/at32/at32-ssc.c b/sound/soc/at32/at32-ssc.c
deleted file mode 100644
index 4ef6492..0000000
--- a/sound/soc/at32/at32-ssc.c
+++ /dev/null
@@ -1,849 +0,0 @@
-/* sound/soc/at32/at32-ssc.c
- * ASoC platform driver for AT32 using SSC as DAI
- *
- * Copyright (C) 2008 Long Range Systems
- *    Geoffrey Wossum <gwossum@acm.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.
- *
- * Note that this is basically a port of the sound/soc/at91-ssc.c to
- * the AVR32 kernel.  Thanks to Frank Mandarino for that code.
- */
-
-/* #define DEBUG */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/atmel_pdc.h>
-#include <linux/atmel-ssc.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include "at32-pcm.h"
-#include "at32-ssc.h"
-
-
-
-/*-------------------------------------------------------------------------*\
- * Constants
-\*-------------------------------------------------------------------------*/
-#define NUM_SSC_DEVICES		3
-
-/*
- * SSC direction masks
- */
-#define SSC_DIR_MASK_UNUSED	0
-#define SSC_DIR_MASK_PLAYBACK	1
-#define SSC_DIR_MASK_CAPTURE	2
-
-/*
- * SSC register values that Atmel left out of <linux/atmel-ssc.h>.  These
- * are expected to be used with SSC_BF
- */
-/* START bit field values */
-#define SSC_START_CONTINUOUS	0
-#define SSC_START_TX_RX		1
-#define SSC_START_LOW_RF	2
-#define SSC_START_HIGH_RF	3
-#define SSC_START_FALLING_RF	4
-#define SSC_START_RISING_RF	5
-#define SSC_START_LEVEL_RF	6
-#define SSC_START_EDGE_RF	7
-#define SSS_START_COMPARE_0	8
-
-/* CKI bit field values */
-#define SSC_CKI_FALLING		0
-#define SSC_CKI_RISING		1
-
-/* CKO bit field values */
-#define SSC_CKO_NONE		0
-#define SSC_CKO_CONTINUOUS	1
-#define SSC_CKO_TRANSFER	2
-
-/* CKS bit field values */
-#define SSC_CKS_DIV		0
-#define SSC_CKS_CLOCK		1
-#define SSC_CKS_PIN		2
-
-/* FSEDGE bit field values */
-#define SSC_FSEDGE_POSITIVE	0
-#define SSC_FSEDGE_NEGATIVE	1
-
-/* FSOS bit field values */
-#define SSC_FSOS_NONE		0
-#define SSC_FSOS_NEGATIVE	1
-#define SSC_FSOS_POSITIVE	2
-#define SSC_FSOS_LOW		3
-#define SSC_FSOS_HIGH		4
-#define SSC_FSOS_TOGGLE		5
-
-#define START_DELAY		1
-
-
-
-/*-------------------------------------------------------------------------*\
- * Module data
-\*-------------------------------------------------------------------------*/
-/*
- * SSC PDC registered required by the PCM DMA engine
- */
-static struct at32_pdc_regs pdc_tx_reg = {
-	.xpr = SSC_PDC_TPR,
-	.xcr = SSC_PDC_TCR,
-	.xnpr = SSC_PDC_TNPR,
-	.xncr = SSC_PDC_TNCR,
-};
-
-
-
-static struct at32_pdc_regs pdc_rx_reg = {
-	.xpr = SSC_PDC_RPR,
-	.xcr = SSC_PDC_RCR,
-	.xnpr = SSC_PDC_RNPR,
-	.xncr = SSC_PDC_RNCR,
-};
-
-
-
-/*
- * SSC and PDC status bits for transmit and receive
- */
-static struct at32_ssc_mask ssc_tx_mask = {
-	.ssc_enable = SSC_BIT(CR_TXEN),
-	.ssc_disable = SSC_BIT(CR_TXDIS),
-	.ssc_endx = SSC_BIT(SR_ENDTX),
-	.ssc_endbuf = SSC_BIT(SR_TXBUFE),
-	.pdc_enable = SSC_BIT(PDC_PTCR_TXTEN),
-	.pdc_disable = SSC_BIT(PDC_PTCR_TXTDIS),
-};
-
-
-
-static struct at32_ssc_mask ssc_rx_mask = {
-	.ssc_enable = SSC_BIT(CR_RXEN),
-	.ssc_disable = SSC_BIT(CR_RXDIS),
-	.ssc_endx = SSC_BIT(SR_ENDRX),
-	.ssc_endbuf = SSC_BIT(SR_RXBUFF),
-	.pdc_enable = SSC_BIT(PDC_PTCR_RXTEN),
-	.pdc_disable = SSC_BIT(PDC_PTCR_RXTDIS),
-};
-
-
-
-/*
- * DMA parameters for each SSC
- */
-static struct at32_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
-	{
-	 {
-	  .name = "SSC0 PCM out",
-	  .pdc = &pdc_tx_reg,
-	  .mask = &ssc_tx_mask,
-	  },
-	 {
-	  .name = "SSC0 PCM in",
-	  .pdc = &pdc_rx_reg,
-	  .mask = &ssc_rx_mask,
-	  },
-	 },
-	{
-	 {
-	  .name = "SSC1 PCM out",
-	  .pdc = &pdc_tx_reg,
-	  .mask = &ssc_tx_mask,
-	  },
-	 {
-	  .name = "SSC1 PCM in",
-	  .pdc = &pdc_rx_reg,
-	  .mask = &ssc_rx_mask,
-	  },
-	 },
-	{
-	 {
-	  .name = "SSC2 PCM out",
-	  .pdc = &pdc_tx_reg,
-	  .mask = &ssc_tx_mask,
-	  },
-	 {
-	  .name = "SSC2 PCM in",
-	  .pdc = &pdc_rx_reg,
-	  .mask = &ssc_rx_mask,
-	  },
-	 },
-};
-
-
-
-static struct at32_ssc_info ssc_info[NUM_SSC_DEVICES] = {
-	{
-	 .name = "ssc0",
-	 .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
-	 .dir_mask = SSC_DIR_MASK_UNUSED,
-	 .initialized = 0,
-	 },
-	{
-	 .name = "ssc1",
-	 .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
-	 .dir_mask = SSC_DIR_MASK_UNUSED,
-	 .initialized = 0,
-	 },
-	{
-	 .name = "ssc2",
-	 .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
-	 .dir_mask = SSC_DIR_MASK_UNUSED,
-	 .initialized = 0,
-	 },
-};
-
-
-
-
-/*-------------------------------------------------------------------------*\
- * ISR
-\*-------------------------------------------------------------------------*/
-/*
- * SSC interrupt handler.  Passes PDC interrupts to the DMA interrupt
- * handler in the PCM driver.
- */
-static irqreturn_t at32_ssc_interrupt(int irq, void *dev_id)
-{
-	struct at32_ssc_info *ssc_p = dev_id;
-	struct at32_pcm_dma_params *dma_params;
-	u32 ssc_sr;
-	u32 ssc_substream_mask;
-	int i;
-
-	ssc_sr = (ssc_readl(ssc_p->ssc->regs, SR) &
-		  ssc_readl(ssc_p->ssc->regs, IMR));
-
-	/*
-	 * Loop through substreams attached to this SSC.  If a DMA-related
-	 * interrupt occured on that substream, call the DMA interrupt
-	 * handler function, if one has been registered in the dma_param
-	 * structure by the PCM driver.
-	 */
-	for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
-		dma_params = ssc_p->dma_params[i];
-
-		if ((dma_params != NULL) &&
-		    (dma_params->dma_intr_handler != NULL)) {
-			ssc_substream_mask = (dma_params->mask->ssc_endx |
-					      dma_params->mask->ssc_endbuf);
-			if (ssc_sr & ssc_substream_mask) {
-				dma_params->dma_intr_handler(ssc_sr,
-							     dma_params->
-							     substream);
-			}
-		}
-	}
-
-
-	return IRQ_HANDLED;
-}
-
-/*-------------------------------------------------------------------------*\
- * DAI functions
-\*-------------------------------------------------------------------------*/
-/*
- * Startup.  Only that one substream allowed in each direction.
- */
-static int at32_ssc_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-	int dir_mask;
-
-	dir_mask = ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-		    SSC_DIR_MASK_PLAYBACK : SSC_DIR_MASK_CAPTURE);
-
-	spin_lock_irq(&ssc_p->lock);
-	if (ssc_p->dir_mask & dir_mask) {
-		spin_unlock_irq(&ssc_p->lock);
-		return -EBUSY;
-	}
-	ssc_p->dir_mask |= dir_mask;
-	spin_unlock_irq(&ssc_p->lock);
-
-	return 0;
-}
-
-
-
-/*
- * Shutdown.  Clear DMA parameters and shutdown the SSC if there
- * are no other substreams open.
- */
-static void at32_ssc_shutdown(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-	struct at32_pcm_dma_params *dma_params;
-	int dir_mask;
-
-	dma_params = ssc_p->dma_params[substream->stream];
-
-	if (dma_params != NULL) {
-		ssc_writel(dma_params->ssc->regs, CR,
-			   dma_params->mask->ssc_disable);
-		pr_debug("%s disabled SSC_SR=0x%08x\n",
-			 (substream->stream ? "receiver" : "transmit"),
-			 ssc_readl(ssc_p->ssc->regs, SR));
-
-		dma_params->ssc = NULL;
-		dma_params->substream = NULL;
-		ssc_p->dma_params[substream->stream] = NULL;
-	}
-
-
-	dir_mask = 1 << substream->stream;
-	spin_lock_irq(&ssc_p->lock);
-	ssc_p->dir_mask &= ~dir_mask;
-	if (!ssc_p->dir_mask) {
-		/* Shutdown the SSC clock */
-		pr_debug("at32-ssc: Stopping user %d clock\n",
-			 ssc_p->ssc->user);
-		clk_disable(ssc_p->ssc->clk);
-
-		if (ssc_p->initialized) {
-			free_irq(ssc_p->ssc->irq, ssc_p);
-			ssc_p->initialized = 0;
-		}
-
-		/* Reset the SSC */
-		ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
-
-		/* clear the SSC dividers */
-		ssc_p->cmr_div = 0;
-		ssc_p->tcmr_period = 0;
-		ssc_p->rcmr_period = 0;
-	}
-	spin_unlock_irq(&ssc_p->lock);
-}
-
-
-
-/*
- * Set the SSC system clock rate
- */
-static int at32_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
-				   int clk_id, unsigned int freq, int dir)
-{
-	/* TODO: What the heck do I do here? */
-	return 0;
-}
-
-
-
-/*
- * Record DAI format for use by hw_params()
- */
-static int at32_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
-				unsigned int fmt)
-{
-	struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
-
-	ssc_p->daifmt = fmt;
-	return 0;
-}
-
-
-
-/*
- * Record SSC clock dividers for use in hw_params()
- */
-static int at32_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
-				   int div_id, int div)
-{
-	struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
-
-	switch (div_id) {
-	case AT32_SSC_CMR_DIV:
-		/*
-		 * The same master clock divider is used for both
-		 * transmit and receive, so if a value has already
-		 * been set, it must match this value
-		 */
-		if (ssc_p->cmr_div == 0)
-			ssc_p->cmr_div = div;
-		else if (div != ssc_p->cmr_div)
-			return -EBUSY;
-		break;
-
-	case AT32_SSC_TCMR_PERIOD:
-		ssc_p->tcmr_period = div;
-		break;
-
-	case AT32_SSC_RCMR_PERIOD:
-		ssc_p->rcmr_period = div;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-
-
-/*
- * Configure the SSC
- */
-static int at32_ssc_hw_params(struct snd_pcm_substream *substream,
-			      struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	int id = rtd->dai->cpu_dai->id;
-	struct at32_ssc_info *ssc_p = &ssc_info[id];
-	struct at32_pcm_dma_params *dma_params;
-	int channels, bits;
-	u32 tfmr, rfmr, tcmr, rcmr;
-	int start_event;
-	int ret;
-
-
-	/*
-	 * Currently, there is only one set of dma_params for each direction.
-	 * If more are added, this code will have to be changed to select
-	 * the proper set
-	 */
-	dma_params = &ssc_dma_params[id][substream->stream];
-	dma_params->ssc = ssc_p->ssc;
-	dma_params->substream = substream;
-
-	ssc_p->dma_params[substream->stream] = dma_params;
-
-
-	/*
-	 * The cpu_dai->dma_data field is only used to communicate the
-	 * appropriate DMA parameters to the PCM driver's hw_params()
-	 * function.  It should not be used for other purposes as it
-	 * is common to all substreams.
-	 */
-	rtd->dai->cpu_dai->dma_data = dma_params;
-
-	channels = params_channels(params);
-
-
-	/*
-	 * Determine sample size in bits and the PDC increment
-	 */
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S8:
-		bits = 8;
-		dma_params->pdc_xfer_size = 1;
-		break;
-
-	case SNDRV_PCM_FORMAT_S16:
-		bits = 16;
-		dma_params->pdc_xfer_size = 2;
-		break;
-
-	case SNDRV_PCM_FORMAT_S24:
-		bits = 24;
-		dma_params->pdc_xfer_size = 4;
-		break;
-
-	case SNDRV_PCM_FORMAT_S32:
-		bits = 32;
-		dma_params->pdc_xfer_size = 4;
-		break;
-
-	default:
-		pr_warning("at32-ssc: Unsupported PCM format %d",
-			   params_format(params));
-		return -EINVAL;
-	}
-	pr_debug("at32-ssc: bits = %d, pdc_xfer_size = %d, channels = %d\n",
-		 bits, dma_params->pdc_xfer_size, channels);
-
-
-	/*
-	 * The SSC only supports up to 16-bit samples in I2S format, due
-	 * to the size of the Frame Mode Register FSLEN field.
-	 */
-	if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
-		if (bits > 16) {
-			pr_warning("at32-ssc: "
-				   "sample size %d is too large for I2S\n",
-				   bits);
-			return -EINVAL;
-		}
-
-
-	/*
-	 * Compute the SSC register settings
-	 */
-	switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK |
-				 SND_SOC_DAIFMT_MASTER_MASK)) {
-	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
-		/*
-		 * I2S format, SSC provides BCLK and LRS clocks.
-		 *
-		 * The SSC transmit and receive clocks are generated from the
-		 * MCK divider, and the BCLK signal is output on the SSC TK line
-		 */
-		pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME master\n");
-		rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) |
-			SSC_BF(RCMR_STTDLY, START_DELAY) |
-			SSC_BF(RCMR_START, SSC_START_FALLING_RF) |
-			SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
-			SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
-			SSC_BF(RCMR_CKS, SSC_CKS_DIV));
-
-		rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-			SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) |
-			SSC_BF(RFMR_FSLEN, bits - 1) |
-			SSC_BF(RFMR_DATNB, channels - 1) |
-			SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1));
-
-		tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) |
-			SSC_BF(TCMR_STTDLY, START_DELAY) |
-			SSC_BF(TCMR_START, SSC_START_FALLING_RF) |
-			SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
-			SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) |
-			SSC_BF(TCMR_CKS, SSC_CKS_DIV));
-
-		tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-			SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) |
-			SSC_BF(TFMR_FSLEN, bits - 1) |
-			SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) |
-			SSC_BF(TFMR_DATLEN, bits - 1));
-		break;
-
-
-	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
-		/*
-		 * I2S format, CODEC supplies BCLK and LRC clock.
-		 *
-		 * The SSC transmit clock is obtained from the BCLK signal
-		 * on the TK line, and the SSC receive clock is generated from
-		 * the transmit clock.
-		 *
-		 * For single channel data, one sample is transferred on the
-		 * falling edge of the LRC clock.  For two channel data, one
-		 * sample is transferred on both edges of the LRC clock.
-		 */
-		pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME slave\n");
-		start_event = ((channels == 1) ?
-			       SSC_START_FALLING_RF : SSC_START_EDGE_RF);
-
-		rcmr = (SSC_BF(RCMR_STTDLY, START_DELAY) |
-			SSC_BF(RCMR_START, start_event) |
-			SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
-			SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
-			SSC_BF(RCMR_CKS, SSC_CKS_CLOCK));
-
-		rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-			SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) |
-			SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1));
-
-		tcmr = (SSC_BF(TCMR_STTDLY, START_DELAY) |
-			SSC_BF(TCMR_START, start_event) |
-			SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
-			SSC_BF(TCMR_CKO, SSC_CKO_NONE) |
-			SSC_BF(TCMR_CKS, SSC_CKS_PIN));
-
-		tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-			SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) |
-			SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1));
-		break;
-
-
-	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
-		/*
-		 * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
-		 *
-		 * The SSC transmit and receive clocks are generated from the
-		 * MCK divider, and the BCLK signal is output on the SSC TK line
-		 */
-		pr_debug("at32-ssc: SSC mode is DSP A BCLK / FRAME master\n");
-		rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) |
-			SSC_BF(RCMR_STTDLY, 1) |
-			SSC_BF(RCMR_START, SSC_START_RISING_RF) |
-			SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
-			SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
-			SSC_BF(RCMR_CKS, SSC_CKS_DIV));
-
-		rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-			SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) |
-			SSC_BF(RFMR_DATNB, channels - 1) |
-			SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1));
-
-		tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) |
-			SSC_BF(TCMR_STTDLY, 1) |
-			SSC_BF(TCMR_START, SSC_START_RISING_RF) |
-			SSC_BF(TCMR_CKI, SSC_CKI_RISING) |
-			SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) |
-			SSC_BF(TCMR_CKS, SSC_CKS_DIV));
-
-		tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
-			SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) |
-			SSC_BF(TFMR_DATNB, channels - 1) |
-			SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1));
-		break;
-
-
-	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
-	default:
-		pr_warning("at32-ssc: unsupported DAI format 0x%x\n",
-			   ssc_p->daifmt);
-		return -EINVAL;
-		break;
-	}
-	pr_debug("at32-ssc: RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
-		 rcmr, rfmr, tcmr, tfmr);
-
-
-	if (!ssc_p->initialized) {
-		/* enable peripheral clock */
-		pr_debug("at32-ssc: Starting clock\n");
-		clk_enable(ssc_p->ssc->clk);
-
-		/* Reset the SSC and its PDC registers */
-		ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
-
-		ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
-
-		ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
-
-		ret = request_irq(ssc_p->ssc->irq, at32_ssc_interrupt, 0,
-				  ssc_p->name, ssc_p);
-		if (ret < 0) {
-			pr_warning("at32-ssc: request irq failed (%d)\n", ret);
-			pr_debug("at32-ssc: Stopping clock\n");
-			clk_disable(ssc_p->ssc->clk);
-			return ret;
-		}
-
-		ssc_p->initialized = 1;
-	}
-
-	/* Set SSC clock mode register */
-	ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div);
-
-	/* set receive clock mode and format */
-	ssc_writel(ssc_p->ssc->regs, RCMR, rcmr);
-	ssc_writel(ssc_p->ssc->regs, RFMR, rfmr);
-
-	/* set transmit clock mode and format */
-	ssc_writel(ssc_p->ssc->regs, TCMR, tcmr);
-	ssc_writel(ssc_p->ssc->regs, TFMR, tfmr);
-
-	pr_debug("at32-ssc: SSC initialized\n");
-	return 0;
-}
-
-
-
-static int at32_ssc_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-	struct at32_pcm_dma_params *dma_params;
-
-	dma_params = ssc_p->dma_params[substream->stream];
-
-	ssc_writel(dma_params->ssc->regs, CR, dma_params->mask->ssc_enable);
-
-	return 0;
-}
-
-
-
-#ifdef CONFIG_PM
-static int at32_ssc_suspend(struct platform_device *pdev,
-			    struct snd_soc_dai *cpu_dai)
-{
-	struct at32_ssc_info *ssc_p;
-
-	if (!cpu_dai->active)
-		return 0;
-
-	ssc_p = &ssc_info[cpu_dai->id];
-
-	/* Save the status register before disabling transmit and receive */
-	ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR);
-	ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS));
-
-	/* Save the current interrupt mask, then disable unmasked interrupts */
-	ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR);
-	ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr);
-
-	ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR);
-	ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR);
-	ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR);
-	ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR);
-	ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR);
-
-	return 0;
-}
-
-
-
-static int at32_ssc_resume(struct platform_device *pdev,
-			   struct snd_soc_dai *cpu_dai)
-{
-	struct at32_ssc_info *ssc_p;
-	u32 cr;
-
-	if (!cpu_dai->active)
-		return 0;
-
-	ssc_p = &ssc_info[cpu_dai->id];
-
-	/* restore SSC register settings */
-	ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);
-	ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr);
-	ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr);
-	ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr);
-	ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr);
-
-	/* re-enable interrupts */
-	ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr);
-
-	/* Re-enable recieve and transmit as appropriate */
-	cr = 0;
-	cr |=
-	    (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0;
-	cr |=
-	    (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0;
-	ssc_writel(ssc_p->ssc->regs, CR, cr);
-
-	return 0;
-}
-#else /* CONFIG_PM */
-#  define at32_ssc_suspend	NULL
-#  define at32_ssc_resume	NULL
-#endif /* CONFIG_PM */
-
-
-#define AT32_SSC_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 AT32_SSC_FORMATS \
-    (SNDRV_PCM_FMTBIT_S8  | SNDRV_PCM_FMTBIT_S16 | \
-     SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32)
-
-
-struct snd_soc_dai at32_ssc_dai[NUM_SSC_DEVICES] = {
-	{
-	 .name = "at32-ssc0",
-	 .id = 0,
-	 .type = SND_SOC_DAI_PCM,
-	 .suspend = at32_ssc_suspend,
-	 .resume = at32_ssc_resume,
-	 .playback = {
-		      .channels_min = 1,
-		      .channels_max = 2,
-		      .rates = AT32_SSC_RATES,
-		      .formats = AT32_SSC_FORMATS,
-		      },
-	 .capture = {
-		     .channels_min = 1,
-		     .channels_max = 2,
-		     .rates = AT32_SSC_RATES,
-		     .formats = AT32_SSC_FORMATS,
-		     },
-	 .ops = {
-		 .startup = at32_ssc_startup,
-		 .shutdown = at32_ssc_shutdown,
-		 .prepare = at32_ssc_prepare,
-		 .hw_params = at32_ssc_hw_params,
-		 },
-	 .dai_ops = {
-		     .set_sysclk = at32_ssc_set_dai_sysclk,
-		     .set_fmt = at32_ssc_set_dai_fmt,
-		     .set_clkdiv = at32_ssc_set_dai_clkdiv,
-		     },
-	 .private_data = &ssc_info[0],
-	 },
-	{
-	 .name = "at32-ssc1",
-	 .id = 1,
-	 .type = SND_SOC_DAI_PCM,
-	 .suspend = at32_ssc_suspend,
-	 .resume = at32_ssc_resume,
-	 .playback = {
-		      .channels_min = 1,
-		      .channels_max = 2,
-		      .rates = AT32_SSC_RATES,
-		      .formats = AT32_SSC_FORMATS,
-		      },
-	 .capture = {
-		     .channels_min = 1,
-		     .channels_max = 2,
-		     .rates = AT32_SSC_RATES,
-		     .formats = AT32_SSC_FORMATS,
-		     },
-	 .ops = {
-		 .startup = at32_ssc_startup,
-		 .shutdown = at32_ssc_shutdown,
-		 .prepare = at32_ssc_prepare,
-		 .hw_params = at32_ssc_hw_params,
-		 },
-	 .dai_ops = {
-		     .set_sysclk = at32_ssc_set_dai_sysclk,
-		     .set_fmt = at32_ssc_set_dai_fmt,
-		     .set_clkdiv = at32_ssc_set_dai_clkdiv,
-		     },
-	 .private_data = &ssc_info[1],
-	 },
-	{
-	 .name = "at32-ssc2",
-	 .id = 2,
-	 .type = SND_SOC_DAI_PCM,
-	 .suspend = at32_ssc_suspend,
-	 .resume = at32_ssc_resume,
-	 .playback = {
-		      .channels_min = 1,
-		      .channels_max = 2,
-		      .rates = AT32_SSC_RATES,
-		      .formats = AT32_SSC_FORMATS,
-		      },
-	 .capture = {
-		     .channels_min = 1,
-		     .channels_max = 2,
-		     .rates = AT32_SSC_RATES,
-		     .formats = AT32_SSC_FORMATS,
-		     },
-	 .ops = {
-		 .startup = at32_ssc_startup,
-		 .shutdown = at32_ssc_shutdown,
-		 .prepare = at32_ssc_prepare,
-		 .hw_params = at32_ssc_hw_params,
-		 },
-	 .dai_ops = {
-		     .set_sysclk = at32_ssc_set_dai_sysclk,
-		     .set_fmt = at32_ssc_set_dai_fmt,
-		     .set_clkdiv = at32_ssc_set_dai_clkdiv,
-		     },
-	 .private_data = &ssc_info[2],
-	 },
-};
-EXPORT_SYMBOL_GPL(at32_ssc_dai);
-
-
-MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>");
-MODULE_DESCRIPTION("AT32 SSC ASoC Interface");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/at32/at32-ssc.h b/sound/soc/at32/at32-ssc.h
deleted file mode 100644
index 3c052db..0000000
--- a/sound/soc/at32/at32-ssc.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* sound/soc/at32/at32-ssc.h
- * ASoC SSC interface for Atmel AT32 SoC
- *
- * Copyright (C) 2008 Long Range Systems
- *    Geoffrey Wossum <gwossum@acm.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __SOUND_SOC_AT32_AT32_SSC_H
-#define __SOUND_SOC_AT32_AT32_SSC_H __FILE__
-
-#include <linux/types.h>
-#include <linux/atmel-ssc.h>
-
-#include "at32-pcm.h"
-
-
-
-struct at32_ssc_state {
-	u32 ssc_cmr;
-	u32 ssc_rcmr;
-	u32 ssc_rfmr;
-	u32 ssc_tcmr;
-	u32 ssc_tfmr;
-	u32 ssc_sr;
-	u32 ssc_imr;
-};
-
-
-
-struct at32_ssc_info {
-	char *name;
-	struct ssc_device *ssc;
-	spinlock_t lock;	/* lock for dir_mask */
-	unsigned short dir_mask;	/* 0=unused, 1=playback, 2=capture */
-	unsigned short initialized;	/* true if SSC has been initialized */
-	unsigned short daifmt;
-	unsigned short cmr_div;
-	unsigned short tcmr_period;
-	unsigned short rcmr_period;
-	struct at32_pcm_dma_params *dma_params[2];
-	struct at32_ssc_state ssc_state;
-};
-
-
-/* SSC divider ids */
-#define AT32_SSC_CMR_DIV        0	/* MCK divider for BCLK */
-#define AT32_SSC_TCMR_PERIOD    1	/* BCLK divider for transmit FS */
-#define AT32_SSC_RCMR_PERIOD    2	/* BCLK divider for receive FS */
-
-
-extern struct snd_soc_dai at32_ssc_dai[];
-
-
-
-#endif /* __SOUND_SOC_AT32_AT32_SSC_H */
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig
deleted file mode 100644
index 85a8832..0000000
--- a/sound/soc/at91/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-config SND_AT91_SOC
-	tristate "SoC Audio for the Atmel AT91 System-on-Chip"
-	depends on ARCH_AT91
-	help
-	  Say Y or M if you want to add support for codecs attached to
-	  the AT91 SSC interface. You will also need
-	  to select the audio interfaces to support below.
-
-config SND_AT91_SOC_SSC
-	tristate
diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile
deleted file mode 100644
index b817f11..0000000
--- a/sound/soc/at91/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# AT91 Platform Support
-snd-soc-at91-objs := at91-pcm.o
-snd-soc-at91-ssc-objs := at91-ssc.o
-
-obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o
-obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o
diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c
deleted file mode 100644
index 7ab48bd..0000000
--- a/sound/soc/at91/at91-pcm.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC
- *
- * Author:	Frank Mandarino <fmandarino@endrelia.com>
- *		Endrelia Technologies Inc.
- * Created:	Mar 3, 2006
- *
- * Based on pxa2xx-pcm.c by:
- *
- * Author:	Nicolas Pitre
- * Created:	Nov 30, 2004
- * Copyright:	(C) 2004 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-#include <linux/atmel_pdc.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <mach/hardware.h>
-#include <mach/at91_ssc.h>
-
-#include "at91-pcm.h"
-
-#if 0
-#define	DBG(x...)	printk(KERN_INFO "at91-pcm: " x)
-#else
-#define	DBG(x...)
-#endif
-
-static const struct snd_pcm_hardware at91_pcm_hardware = {
-	.info			= SNDRV_PCM_INFO_MMAP |
-				  SNDRV_PCM_INFO_MMAP_VALID |
-				  SNDRV_PCM_INFO_INTERLEAVED |
-				  SNDRV_PCM_INFO_PAUSE,
-	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
-	.period_bytes_min	= 32,
-	.period_bytes_max	= 8192,
-	.periods_min		= 2,
-	.periods_max		= 1024,
-	.buffer_bytes_max	= 32 * 1024,
-};
-
-struct at91_runtime_data {
-	struct at91_pcm_dma_params *params;
-	dma_addr_t dma_buffer;			/* physical address of dma buffer */
-	dma_addr_t dma_buffer_end;		/* first address beyond DMA buffer */
-	size_t period_size;
-	dma_addr_t period_ptr;			/* physical address of next period */
-	u32 pdc_xpr_save;			/* PDC register save */
-	u32 pdc_xcr_save;
-	u32 pdc_xnpr_save;
-	u32 pdc_xncr_save;
-};
-
-static void at91_pcm_dma_irq(u32 ssc_sr,
-	struct snd_pcm_substream *substream)
-{
-	struct at91_runtime_data *prtd = substream->runtime->private_data;
-	struct at91_pcm_dma_params *params = prtd->params;
-	static int count = 0;
-
-	count++;
-
-	if (ssc_sr & params->mask->ssc_endbuf) {
-
-		printk(KERN_WARNING
-			"at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
-			substream->stream == SNDRV_PCM_STREAM_PLAYBACK
-				? "underrun" : "overrun",
-			params->name, ssc_sr, count);
-
-		/* re-start the PDC */
-		at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
-
-		prtd->period_ptr += prtd->period_size;
-		if (prtd->period_ptr >= prtd->dma_buffer_end) {
-			prtd->period_ptr = prtd->dma_buffer;
-		}
-
-		at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
-		at91_ssc_write(params->ssc_base + params->pdc->xcr,
-				prtd->period_size / params->pdc_xfer_size);
-
-		at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
-	}
-
-	if (ssc_sr & params->mask->ssc_endx) {
-
-		/* Load the PDC next pointer and counter registers */
-		prtd->period_ptr += prtd->period_size;
-		if (prtd->period_ptr >= prtd->dma_buffer_end) {
-			prtd->period_ptr = prtd->dma_buffer;
-		}
-		at91_ssc_write(params->ssc_base + params->pdc->xnpr,
-			       prtd->period_ptr);
-		at91_ssc_write(params->ssc_base + params->pdc->xncr,
-				prtd->period_size / params->pdc_xfer_size);
-	}
-
-	snd_pcm_period_elapsed(substream);
-}
-
-static int at91_pcm_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct at91_runtime_data *prtd = runtime->private_data;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-	/* this may get called several times by oss emulation
-	 * with different params */
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-	runtime->dma_bytes = params_buffer_bytes(params);
-
-	prtd->params = rtd->dai->cpu_dai->dma_data;
-	prtd->params->dma_intr_handler = at91_pcm_dma_irq;
-
-	prtd->dma_buffer = runtime->dma_addr;
-	prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
-	prtd->period_size = params_period_bytes(params);
-
-	DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n",
-		prtd->params->name, runtime->dma_bytes, prtd->period_size);
-	return 0;
-}
-
-static int at91_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	struct at91_runtime_data *prtd = substream->runtime->private_data;
-	struct at91_pcm_dma_params *params = prtd->params;
-
-	if (params != NULL) {
-		at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
-		prtd->params->dma_intr_handler = NULL;
-	}
-
-	return 0;
-}
-
-static int at91_pcm_prepare(struct snd_pcm_substream *substream)
-{
-	struct at91_runtime_data *prtd = substream->runtime->private_data;
-	struct at91_pcm_dma_params *params = prtd->params;
-
-	at91_ssc_write(params->ssc_base + AT91_SSC_IDR,
-			params->mask->ssc_endx | params->mask->ssc_endbuf);
-
-	at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
-	return 0;
-}
-
-static int at91_pcm_trigger(struct snd_pcm_substream *substream,
-	int cmd)
-{
-	struct at91_runtime_data *prtd = substream->runtime->private_data;
-	struct at91_pcm_dma_params *params = prtd->params;
-	int ret = 0;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		prtd->period_ptr = prtd->dma_buffer;
-
-		at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
-		at91_ssc_write(params->ssc_base + params->pdc->xcr,
-				prtd->period_size / params->pdc_xfer_size);
-
-		prtd->period_ptr += prtd->period_size;
-		at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
-		at91_ssc_write(params->ssc_base + params->pdc->xncr,
-				prtd->period_size / params->pdc_xfer_size);
-
-		DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n",
-			(unsigned long) prtd->period_ptr,
-			at91_ssc_read(params->ssc_base + params->pdc->xpr),
-			at91_ssc_read(params->ssc_base + params->pdc->xcr),
-			at91_ssc_read(params->ssc_base + params->pdc->xnpr),
-			at91_ssc_read(params->ssc_base + params->pdc->xncr));
-
-		at91_ssc_write(params->ssc_base + AT91_SSC_IER,
-			params->mask->ssc_endx | params->mask->ssc_endbuf);
-
-		at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR,
-			params->mask->pdc_enable);
-
-		DBG("sr=%lx imr=%lx\n",
-		    at91_ssc_read(params->ssc_base + AT91_SSC_SR),
-		    at91_ssc_read(params->ssc_base + AT91_SSC_IMR));
-		break;
-
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
-		break;
-
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
-		break;
-
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static snd_pcm_uframes_t at91_pcm_pointer(
-	struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct at91_runtime_data *prtd = runtime->private_data;
-	struct at91_pcm_dma_params *params = prtd->params;
-	dma_addr_t ptr;
-	snd_pcm_uframes_t x;
-
-	ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr);
-	x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
-
-	if (x == runtime->buffer_size)
-		x = 0;
-	return x;
-}
-
-static int at91_pcm_open(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct at91_runtime_data *prtd;
-	int ret = 0;
-
-	snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware);
-
-	/* ensure that buffer size is a multiple of period size */
-	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-	if (ret < 0)
-		goto out;
-
-	prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL);
-	if (prtd == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	runtime->private_data = prtd;
-
- out:
-	return ret;
-}
-
-static int at91_pcm_close(struct snd_pcm_substream *substream)
-{
-	struct at91_runtime_data *prtd = substream->runtime->private_data;
-
-	kfree(prtd);
-	return 0;
-}
-
-static int at91_pcm_mmap(struct snd_pcm_substream *substream,
-	struct vm_area_struct *vma)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-				     runtime->dma_area,
-				     runtime->dma_addr,
-				     runtime->dma_bytes);
-}
-
-struct snd_pcm_ops at91_pcm_ops = {
-	.open		= at91_pcm_open,
-	.close		= at91_pcm_close,
-	.ioctl		= snd_pcm_lib_ioctl,
-	.hw_params	= at91_pcm_hw_params,
-	.hw_free	= at91_pcm_hw_free,
-	.prepare	= at91_pcm_prepare,
-	.trigger	= at91_pcm_trigger,
-	.pointer	= at91_pcm_pointer,
-	.mmap		= at91_pcm_mmap,
-};
-
-static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
-	int stream)
-{
-	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size = at91_pcm_hardware.buffer_bytes_max;
-
-	buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	buf->dev.dev = pcm->card->dev;
-	buf->private_data = NULL;
-	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-					   &buf->addr, GFP_KERNEL);
-
-	DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
-		(void *) buf->area,
-		(void *) buf->addr,
-		size);
-
-	if (!buf->area)
-		return -ENOMEM;
-
-	buf->bytes = size;
-	return 0;
-}
-
-static u64 at91_pcm_dmamask = 0xffffffff;
-
-static int at91_pcm_new(struct snd_card *card,
-	struct snd_soc_dai *dai, struct snd_pcm *pcm)
-{
-	int ret = 0;
-
-	if (!card->dev->dma_mask)
-		card->dev->dma_mask = &at91_pcm_dmamask;
-	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = 0xffffffff;
-
-	if (dai->playback.channels_min) {
-		ret = at91_pcm_preallocate_dma_buffer(pcm,
-			SNDRV_PCM_STREAM_PLAYBACK);
-		if (ret)
-			goto out;
-	}
-
-	if (dai->capture.channels_min) {
-		ret = at91_pcm_preallocate_dma_buffer(pcm,
-			SNDRV_PCM_STREAM_CAPTURE);
-		if (ret)
-			goto out;
-	}
- out:
-	return ret;
-}
-
-static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-	struct snd_pcm_substream *substream;
-	struct snd_dma_buffer *buf;
-	int stream;
-
-	for (stream = 0; stream < 2; stream++) {
-		substream = pcm->streams[stream].substream;
-		if (!substream)
-			continue;
-
-		buf = &substream->dma_buffer;
-		if (!buf->area)
-			continue;
-
-		dma_free_writecombine(pcm->card->dev, buf->bytes,
-				      buf->area, buf->addr);
-		buf->area = NULL;
-	}
-}
-
-#ifdef CONFIG_PM
-static int at91_pcm_suspend(struct platform_device *pdev,
-	struct snd_soc_dai *dai)
-{
-	struct snd_pcm_runtime *runtime = dai->runtime;
-	struct at91_runtime_data *prtd;
-	struct at91_pcm_dma_params *params;
-
-	if (!runtime)
-		return 0;
-
-	prtd = runtime->private_data;
-	params = prtd->params;
-
-	/* disable the PDC and save the PDC registers */
-
-	at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
-
-	prtd->pdc_xpr_save  = at91_ssc_read(params->ssc_base + params->pdc->xpr);
-	prtd->pdc_xcr_save  = at91_ssc_read(params->ssc_base + params->pdc->xcr);
-	prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr);
-	prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr);
-
-	return 0;
-}
-
-static int at91_pcm_resume(struct platform_device *pdev,
-	struct snd_soc_dai *dai)
-{
-	struct snd_pcm_runtime *runtime = dai->runtime;
-	struct at91_runtime_data *prtd;
-	struct at91_pcm_dma_params *params;
-
-	if (!runtime)
-		return 0;
-
-	prtd = runtime->private_data;
-	params = prtd->params;
-
-	/* restore the PDC registers and enable the PDC */
-	at91_ssc_write(params->ssc_base + params->pdc->xpr,  prtd->pdc_xpr_save);
-	at91_ssc_write(params->ssc_base + params->pdc->xcr,  prtd->pdc_xcr_save);
-	at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save);
-	at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save);
-
-	at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
-	return 0;
-}
-#else
-#define at91_pcm_suspend	NULL
-#define at91_pcm_resume		NULL
-#endif
-
-struct snd_soc_platform at91_soc_platform = {
-	.name		= "at91-audio",
-	.pcm_ops 	= &at91_pcm_ops,
-	.pcm_new	= at91_pcm_new,
-	.pcm_free	= at91_pcm_free_dma_buffers,
-	.suspend	= at91_pcm_suspend,
-	.resume		= at91_pcm_resume,
-};
-
-EXPORT_SYMBOL_GPL(at91_soc_platform);
-
-MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
-MODULE_DESCRIPTION("Atmel AT91 PCM module");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h
deleted file mode 100644
index e5aada2..0000000
--- a/sound/soc/at91/at91-pcm.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC
- *
- * Author:	Frank Mandarino <fmandarino@endrelia.com>
- *		Endrelia Technologies Inc.
- * Created:	Mar 3, 2006
- *
- * Based on pxa2xx-pcm.h by:
- *
- * Author:	Nicolas Pitre
- * Created:	Nov 30, 2004
- * Copyright:	MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _AT91_PCM_H
-#define _AT91_PCM_H
-
-#include <mach/hardware.h>
-
-struct at91_ssc_periph {
-	void __iomem	*base;
-	u32		pid;
-};
-
-/*
- * Registers and status bits that are required by the PCM driver.
- */
-struct at91_pdc_regs {
-	unsigned int	xpr;		/* PDC recv/trans pointer */
-	unsigned int	xcr;		/* PDC recv/trans counter */
-	unsigned int	xnpr;		/* PDC next recv/trans pointer */
-	unsigned int	xncr;		/* PDC next recv/trans counter */
-	unsigned int	ptcr;		/* PDC transfer control */
-};
-
-struct at91_ssc_mask {
-	u32	ssc_enable;		/* SSC recv/trans enable */
-	u32	ssc_disable;		/* SSC recv/trans disable */
-	u32	ssc_endx;		/* SSC ENDTX or ENDRX */
-	u32	ssc_endbuf;		/* SSC TXBUFE or RXBUFF */
-	u32	pdc_enable;		/* PDC recv/trans enable */
-	u32	pdc_disable;		/* PDC recv/trans disable */
-};
-
-/*
- * This structure, shared between the PCM driver and the interface,
- * contains all information required by the PCM driver to perform the
- * PDC DMA operation.  All fields except dma_intr_handler() are initialized
- * by the interface.  The dms_intr_handler() pointer is set by the PCM
- * driver and called by the interface SSC interrupt handler if it is
- * non-NULL.
- */
-struct at91_pcm_dma_params {
-	char *name;			/* stream identifier */
-	int pdc_xfer_size;		/* PDC counter increment in bytes */
-	void __iomem *ssc_base;		/* SSC base address */
-	struct at91_pdc_regs *pdc; /* PDC receive or transmit registers */
-	struct at91_ssc_mask *mask;/* SSC & PDC status bits */
-	struct snd_pcm_substream *substream;
-	void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
-};
-
-extern struct snd_soc_platform at91_soc_platform;
-
-#define at91_ssc_read(a)	((unsigned long) __raw_readl(a))
-#define at91_ssc_write(a,v)	__raw_writel((v),(a))
-
-#endif /* _AT91_PCM_H */
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c
deleted file mode 100644
index 1b61cc4..0000000
--- a/sound/soc/at91/at91-ssc.c
+++ /dev/null
@@ -1,791 +0,0 @@
-/*
- * at91-ssc.c  --  ALSA SoC AT91 SSC Audio Layer Platform driver
- *
- * Author: Frank Mandarino <fmandarino@endrelia.com>
- *         Endrelia Technologies Inc.
- *
- * Based on pxa2xx Platform drivers by
- * 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 as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/atmel_pdc.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include <mach/hardware.h>
-#include <mach/at91_pmc.h>
-#include <mach/at91_ssc.h>
-
-#include "at91-pcm.h"
-#include "at91-ssc.h"
-
-#if 0
-#define	DBG(x...)	printk(KERN_DEBUG "at91-ssc:" x)
-#else
-#define	DBG(x...)
-#endif
-
-#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
-#define NUM_SSC_DEVICES		1
-#else
-#define NUM_SSC_DEVICES		3
-#endif
-
-
-/*
- * SSC PDC registers required by the PCM DMA engine.
- */
-static struct at91_pdc_regs pdc_tx_reg = {
-	.xpr		= ATMEL_PDC_TPR,
-	.xcr		= ATMEL_PDC_TCR,
-	.xnpr		= ATMEL_PDC_TNPR,
-	.xncr		= ATMEL_PDC_TNCR,
-};
-
-static struct at91_pdc_regs pdc_rx_reg = {
-	.xpr		= ATMEL_PDC_RPR,
-	.xcr		= ATMEL_PDC_RCR,
-	.xnpr		= ATMEL_PDC_RNPR,
-	.xncr		= ATMEL_PDC_RNCR,
-};
-
-/*
- * SSC & PDC status bits for transmit and receive.
- */
-static struct at91_ssc_mask ssc_tx_mask = {
-	.ssc_enable	= AT91_SSC_TXEN,
-	.ssc_disable	= AT91_SSC_TXDIS,
-	.ssc_endx	= AT91_SSC_ENDTX,
-	.ssc_endbuf	= AT91_SSC_TXBUFE,
-	.pdc_enable	= ATMEL_PDC_TXTEN,
-	.pdc_disable	= ATMEL_PDC_TXTDIS,
-};
-
-static struct at91_ssc_mask ssc_rx_mask = {
-	.ssc_enable	= AT91_SSC_RXEN,
-	.ssc_disable	= AT91_SSC_RXDIS,
-	.ssc_endx	= AT91_SSC_ENDRX,
-	.ssc_endbuf	= AT91_SSC_RXBUFF,
-	.pdc_enable	= ATMEL_PDC_RXTEN,
-	.pdc_disable	= ATMEL_PDC_RXTDIS,
-};
-
-
-/*
- * DMA parameters.
- */
-static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
-	{{
-	.name		= "SSC0 PCM out",
-	.pdc		= &pdc_tx_reg,
-	.mask		= &ssc_tx_mask,
-	},
-	{
-	.name		= "SSC0 PCM in",
-	.pdc		= &pdc_rx_reg,
-	.mask		= &ssc_rx_mask,
-	}},
-#if NUM_SSC_DEVICES == 3
-	{{
-	.name		= "SSC1 PCM out",
-	.pdc		= &pdc_tx_reg,
-	.mask		= &ssc_tx_mask,
-	},
-	{
-	.name		= "SSC1 PCM in",
-	.pdc		= &pdc_rx_reg,
-	.mask		= &ssc_rx_mask,
-	}},
-	{{
-	.name		= "SSC2 PCM out",
-	.pdc		= &pdc_tx_reg,
-	.mask		= &ssc_tx_mask,
-	},
-	{
-	.name		= "SSC2 PCM in",
-	.pdc		= &pdc_rx_reg,
-	.mask		= &ssc_rx_mask,
-	}},
-#endif
-};
-
-struct at91_ssc_state {
-	u32	ssc_cmr;
-	u32	ssc_rcmr;
-	u32	ssc_rfmr;
-	u32	ssc_tcmr;
-	u32	ssc_tfmr;
-	u32	ssc_sr;
-	u32	ssc_imr;
-};
-
-static struct at91_ssc_info {
-	char		*name;
-	struct at91_ssc_periph ssc;
-	spinlock_t 	lock;		/* lock for dir_mask */
-	unsigned short	dir_mask;	/* 0=unused, 1=playback, 2=capture */
-	unsigned short	initialized;	/* 1=SSC has been initialized */
-	unsigned short	daifmt;
-	unsigned short	cmr_div;
-	unsigned short	tcmr_period;
-	unsigned short	rcmr_period;
-	struct at91_pcm_dma_params *dma_params[2];
-	struct at91_ssc_state ssc_state;
-
-} ssc_info[NUM_SSC_DEVICES] = {
-	{
-	.name		= "ssc0",
-	.lock		= __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
-	.dir_mask	= 0,
-	.initialized	= 0,
-	},
-#if NUM_SSC_DEVICES == 3
-	{
-	.name		= "ssc1",
-	.lock		= __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
-	.dir_mask	= 0,
-	.initialized	= 0,
-	},
-	{
-	.name		= "ssc2",
-	.lock		= __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
-	.dir_mask	= 0,
-	.initialized	= 0,
-	},
-#endif
-};
-
-static unsigned int at91_ssc_sysclk;
-
-/*
- * SSC interrupt handler.  Passes PDC interrupts to the DMA
- * interrupt handler in the PCM driver.
- */
-static irqreturn_t at91_ssc_interrupt(int irq, void *dev_id)
-{
-	struct at91_ssc_info *ssc_p = dev_id;
-	struct at91_pcm_dma_params *dma_params;
-	u32 ssc_sr;
-	int i;
-
-	ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)
-			& at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
-
-	/*
-	 * Loop through the substreams attached to this SSC.  If
-	 * a DMA-related interrupt occurred on that substream, call
-	 * the DMA interrupt handler function, if one has been
-	 * registered in the dma_params structure by the PCM driver.
-	 */
-	for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
-		dma_params = ssc_p->dma_params[i];
-
-		if (dma_params != NULL && dma_params->dma_intr_handler != NULL &&
-			(ssc_sr &
-			(dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf)))
-
-			dma_params->dma_intr_handler(ssc_sr, dma_params->substream);
-	}
-
-	return IRQ_HANDLED;
-}
-
-/*
- * Startup.  Only that one substream allowed in each direction.
- */
-static int at91_ssc_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-	int dir_mask;
-
-	DBG("ssc_startup: SSC_SR=0x%08lx\n",
-			at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
-	dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2;
-
-	spin_lock_irq(&ssc_p->lock);
-	if (ssc_p->dir_mask & dir_mask) {
-		spin_unlock_irq(&ssc_p->lock);
-		return -EBUSY;
-	}
-	ssc_p->dir_mask |= dir_mask;
-	spin_unlock_irq(&ssc_p->lock);
-
-	return 0;
-}
-
-/*
- * Shutdown.  Clear DMA parameters and shutdown the SSC if there
- * are no other substreams open.
- */
-static void at91_ssc_shutdown(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-	struct at91_pcm_dma_params *dma_params;
-	int dir, dir_mask;
-
-	dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
-	dma_params = ssc_p->dma_params[dir];
-
-	if (dma_params != NULL) {
-		at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
-				dma_params->mask->ssc_disable);
-		DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"),
-			at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
-
-		dma_params->ssc_base = NULL;
-		dma_params->substream = NULL;
-		ssc_p->dma_params[dir] = NULL;
-	}
-
-	dir_mask = 1 << dir;
-
-	spin_lock_irq(&ssc_p->lock);
-	ssc_p->dir_mask &= ~dir_mask;
-	if (!ssc_p->dir_mask) {
-		/* Shutdown the SSC clock. */
-		DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
-		at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid);
-
-		if (ssc_p->initialized) {
-			free_irq(ssc_p->ssc.pid, ssc_p);
-			ssc_p->initialized = 0;
-		}
-
-		/* Reset the SSC */
-		at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
-
-		/* Clear the SSC dividers */
-		ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
-	}
-	spin_unlock_irq(&ssc_p->lock);
-}
-
-/*
- * Record the SSC system clock rate.
- */
-static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
-		int clk_id, unsigned int freq, int dir)
-{
-	/*
-	 * The only clock supplied to the SSC is the AT91 master clock,
-	 * which is only used if the SSC is generating BCLK and/or
-	 * LRC clocks.
-	 */
-	switch (clk_id) {
-	case AT91_SYSCLK_MCK:
-		at91_ssc_sysclk = freq;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/*
- * Record the DAI format for use in hw_params().
- */
-static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
-		unsigned int fmt)
-{
-	struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
-
-	ssc_p->daifmt = fmt;
-	return 0;
-}
-
-/*
- * Record SSC clock dividers for use in hw_params().
- */
-static int at91_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
-	int div_id, int div)
-{
-	struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
-
-	switch (div_id) {
-	case AT91SSC_CMR_DIV:
-		/*
-		 * The same master clock divider is used for both
-		 * transmit and receive, so if a value has already
-		 * been set, it must match this value.
-		 */
-		if (ssc_p->cmr_div == 0)
-			ssc_p->cmr_div = div;
-		else
-			if (div != ssc_p->cmr_div)
-				return -EBUSY;
-		break;
-
-	case AT91SSC_TCMR_PERIOD:
-		ssc_p->tcmr_period = div;
-		break;
-
-	case AT91SSC_RCMR_PERIOD:
-		ssc_p->rcmr_period = div;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/*
- * Configure the SSC.
- */
-static int at91_ssc_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	int id = rtd->dai->cpu_dai->id;
-	struct at91_ssc_info *ssc_p = &ssc_info[id];
-	struct at91_pcm_dma_params *dma_params;
-	int dir, channels, bits;
-	u32 tfmr, rfmr, tcmr, rcmr;
-	int start_event;
-	int ret;
-
-	/*
-	 * Currently, there is only one set of dma params for
-	 * each direction.  If more are added, this code will
-	 * have to be changed to select the proper set.
-	 */
-	dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
-
-	dma_params = &ssc_dma_params[id][dir];
-	dma_params->ssc_base = ssc_p->ssc.base;
-	dma_params->substream = substream;
-
-	ssc_p->dma_params[dir] = dma_params;
-
-	/*
-	 * The cpu_dai->dma_data field is only used to communicate the
-	 * appropriate DMA parameters to the pcm driver hw_params()
-	 * function.  It should not be used for other purposes
-	 * as it is common to all substreams.
-	 */
-	rtd->dai->cpu_dai->dma_data = dma_params;
-
-	channels = params_channels(params);
-
-	/*
-	 * Determine sample size in bits and the PDC increment.
-	 */
-	switch(params_format(params)) {
-	case SNDRV_PCM_FORMAT_S8:
-		bits = 8;
-		dma_params->pdc_xfer_size = 1;
-		break;
-	case SNDRV_PCM_FORMAT_S16_LE:
-		bits = 16;
-		dma_params->pdc_xfer_size = 2;
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		bits = 24;
-		dma_params->pdc_xfer_size = 4;
-		break;
-	case SNDRV_PCM_FORMAT_S32_LE:
-		bits = 32;
-		dma_params->pdc_xfer_size = 4;
-		break;
-	default:
-		printk(KERN_WARNING "at91-ssc: unsupported PCM format\n");
-		return -EINVAL;
-	}
-
-	/*
-	 * The SSC only supports up to 16-bit samples in I2S format, due
-	 * to the size of the Frame Mode Register FSLEN field.
-	 */
-	if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S
-		&& bits > 16) {
-		printk(KERN_WARNING
-			"at91-ssc: sample size %d is too large for I2S\n", bits);
-		return -EINVAL;
-	}
-
-	/*
-	 * Compute SSC register settings.
-	 */
-	switch (ssc_p->daifmt
-		& (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
-
-	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
-		/*
-		 * I2S format, SSC provides BCLK and LRC clocks.
-		 *
-		 * The SSC transmit and receive clocks are generated from the
-		 * MCK divider, and the BCLK signal is output on the SSC TK line.
-		 */
-		rcmr =	  (( ssc_p->rcmr_period		<< 24) & AT91_SSC_PERIOD)
-			| (( 1				<< 16) & AT91_SSC_STTDLY)
-			| (( AT91_SSC_START_FALLING_RF	     ) & AT91_SSC_START)
-			| (( AT91_SSC_CK_RISING		     ) & AT91_SSC_CKI)
-			| (( AT91_SSC_CKO_NONE		     ) & AT91_SSC_CKO)
-			| (( AT91_SSC_CKS_DIV		     ) & AT91_SSC_CKS);
-
-		rfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)
-			| (( AT91_SSC_FSOS_NEGATIVE	     ) & AT91_SSC_FSOS)
-			| (((bits - 1)			<< 16) & AT91_SSC_FSLEN)
-			| (((channels - 1)		<<  8) & AT91_SSC_DATNB)
-			| (( 1				<<  7) & AT91_SSC_MSBF)
-			| (( 0				<<  5) & AT91_SSC_LOOP)
-			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);
-
-		tcmr =	  (( ssc_p->tcmr_period		<< 24) & AT91_SSC_PERIOD)
-			| (( 1				<< 16) & AT91_SSC_STTDLY)
-			| (( AT91_SSC_START_FALLING_RF       ) & AT91_SSC_START)
-			| (( AT91_SSC_CKI_FALLING	     ) & AT91_SSC_CKI)
-			| (( AT91_SSC_CKO_CONTINUOUS	     ) & AT91_SSC_CKO)
-			| (( AT91_SSC_CKS_DIV		     ) & AT91_SSC_CKS);
-
-		tfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)
-			| (( 0				<< 23) & AT91_SSC_FSDEN)
-			| (( AT91_SSC_FSOS_NEGATIVE	     ) & AT91_SSC_FSOS)
-			| (((bits - 1)			<< 16) & AT91_SSC_FSLEN)
-			| (((channels - 1)		<<  8) & AT91_SSC_DATNB)
-			| (( 1				<<  7) & AT91_SSC_MSBF)
-			| (( 0				<<  5) & AT91_SSC_DATDEF)
-			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);
-		break;
-
-	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
-		/*
-		 * I2S format, CODEC supplies BCLK and LRC clocks.
-		 *
-		 * The SSC transmit clock is obtained from the BCLK signal on
-		 * on the TK line, and the SSC receive clock is generated from the
-		 * transmit clock.
-		 *
-		 * For single channel data, one sample is transferred on the falling
-		 * edge of the LRC clock.  For two channel data, one sample is
-		 * transferred on both edges of the LRC clock.
-		 */
-		start_event = channels == 1
-				? AT91_SSC_START_FALLING_RF
-				: AT91_SSC_START_EDGE_RF;
-
-		rcmr =	  (( 0				<< 24) & AT91_SSC_PERIOD)
-			| (( 1				<< 16) & AT91_SSC_STTDLY)
-			| (( start_event		     ) & AT91_SSC_START)
-			| (( AT91_SSC_CK_RISING		     ) & AT91_SSC_CKI)
-			| (( AT91_SSC_CKO_NONE		     ) & AT91_SSC_CKO)
-			| (( AT91_SSC_CKS_CLOCK		     ) & AT91_SSC_CKS);
-
-		rfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)
-			| (( AT91_SSC_FSOS_NONE		     ) & AT91_SSC_FSOS)
-			| (( 0				<< 16) & AT91_SSC_FSLEN)
-			| (( 0				<<  8) & AT91_SSC_DATNB)
-			| (( 1				<<  7) & AT91_SSC_MSBF)
-			| (( 0				<<  5) & AT91_SSC_LOOP)
-			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);
-
-		tcmr =	  (( 0				<< 24) & AT91_SSC_PERIOD)
-			| (( 1				<< 16) & AT91_SSC_STTDLY)
-			| (( start_event		     ) & AT91_SSC_START)
-			| (( AT91_SSC_CKI_FALLING	     ) & AT91_SSC_CKI)
-			| (( AT91_SSC_CKO_NONE		     ) & AT91_SSC_CKO)
-			| (( AT91_SSC_CKS_PIN		     ) & AT91_SSC_CKS);
-
-		tfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)
-			| (( 0				<< 23) & AT91_SSC_FSDEN)
-			| (( AT91_SSC_FSOS_NONE		     ) & AT91_SSC_FSOS)
-			| (( 0				<< 16) & AT91_SSC_FSLEN)
-			| (( 0				<<  8) & AT91_SSC_DATNB)
-			| (( 1				<<  7) & AT91_SSC_MSBF)
-			| (( 0				<<  5) & AT91_SSC_DATDEF)
-			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);
-		break;
-
-	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
-		/*
-		 * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
-		 *
-		 * The SSC transmit and receive clocks are generated from the
-		 * MCK divider, and the BCLK signal is output on the SSC TK line.
-		 */
-		rcmr =	  (( ssc_p->rcmr_period		<< 24) & AT91_SSC_PERIOD)
-			| (( 1				<< 16) & AT91_SSC_STTDLY)
-			| (( AT91_SSC_START_RISING_RF	     ) & AT91_SSC_START)
-			| (( AT91_SSC_CK_RISING		     ) & AT91_SSC_CKI)
-			| (( AT91_SSC_CKO_NONE		     ) & AT91_SSC_CKO)
-			| (( AT91_SSC_CKS_DIV		     ) & AT91_SSC_CKS);
-
-		rfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)
-			| (( AT91_SSC_FSOS_POSITIVE	     ) & AT91_SSC_FSOS)
-			| (( 0				<< 16) & AT91_SSC_FSLEN)
-			| (((channels - 1)		<<  8) & AT91_SSC_DATNB)
-			| (( 1				<<  7) & AT91_SSC_MSBF)
-			| (( 0				<<  5) & AT91_SSC_LOOP)
-			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);
-
-		tcmr =	  (( ssc_p->tcmr_period		<< 24) & AT91_SSC_PERIOD)
-			| (( 1				<< 16) & AT91_SSC_STTDLY)
-			| (( AT91_SSC_START_RISING_RF        ) & AT91_SSC_START)
-			| (( AT91_SSC_CK_RISING		     ) & AT91_SSC_CKI)
-			| (( AT91_SSC_CKO_CONTINUOUS	     ) & AT91_SSC_CKO)
-			| (( AT91_SSC_CKS_DIV		     ) & AT91_SSC_CKS);
-
-		tfmr =	  (( AT91_SSC_FSEDGE_POSITIVE	     ) & AT91_SSC_FSEDGE)
-			| (( 0				<< 23) & AT91_SSC_FSDEN)
-			| (( AT91_SSC_FSOS_POSITIVE	     ) & AT91_SSC_FSOS)
-			| (( 0				<< 16) & AT91_SSC_FSLEN)
-			| (((channels - 1)		<<  8) & AT91_SSC_DATNB)
-			| (( 1				<<  7) & AT91_SSC_MSBF)
-			| (( 0				<<  5) & AT91_SSC_DATDEF)
-			| (((bits - 1)			<<  0) & AT91_SSC_DATALEN);
-
-
-
-			break;
-
-	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
-	default:
-		printk(KERN_WARNING "at91-ssc: unsupported DAI format 0x%x.\n",
-			ssc_p->daifmt);
-		return -EINVAL;
-		break;
-	}
-	DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr);
-
-	if (!ssc_p->initialized) {
-
-		/* Enable PMC peripheral clock for this SSC */
-		DBG("Starting pid %d clock\n", ssc_p->ssc.pid);
-		at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);
-
-		/* Reset the SSC and its PDC registers */
-		at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
-
-		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RPR, 0);
-		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RCR, 0);
-		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNPR, 0);
-		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNCR, 0);
-		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TPR, 0);
-		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TCR, 0);
-		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNPR, 0);
-		at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNCR, 0);
-
-		if ((ret = request_irq(ssc_p->ssc.pid, at91_ssc_interrupt,
-					0, ssc_p->name, ssc_p)) < 0) {
-			printk(KERN_WARNING "at91-ssc: request_irq failure\n");
-
-			DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
-			at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid);
-			return ret;
-		}
-
-		ssc_p->initialized = 1;
-	}
-
-	/* set SSC clock mode register */
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div);
-
-	/* set receive clock mode and format */
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr);
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr);
-
-	/* set transmit clock mode and format */
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr);
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr);
-
-	DBG("hw_params: SSC initialized\n");
-	return 0;
-}
-
-
-static int at91_ssc_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
-	struct at91_pcm_dma_params *dma_params;
-	int dir;
-
-	dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
-	dma_params = ssc_p->dma_params[dir];
-
-	at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
-			dma_params->mask->ssc_enable);
-
-	DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit",
-		at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR));
-	return 0;
-}
-
-
-#ifdef CONFIG_PM
-static int at91_ssc_suspend(struct platform_device *pdev,
-	struct snd_soc_dai *cpu_dai)
-{
-	struct at91_ssc_info *ssc_p;
-
-	if(!cpu_dai->active)
-		return 0;
-
-	ssc_p = &ssc_info[cpu_dai->id];
-
-	/* Save the status register before disabling transmit and receive. */
-	ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR);
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
-			AT91_SSC_TXDIS | AT91_SSC_RXDIS);
-
-	/* Save the current interrupt mask, then disable unmasked interrupts. */
-	ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr);
-
-	ssc_p->ssc_state.ssc_cmr  = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR);
-	ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR);
-	ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR);
-	ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR);
-	ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR);
-
-	return 0;
-}
-
-static int at91_ssc_resume(struct platform_device *pdev,
-	struct snd_soc_dai *cpu_dai)
-{
-	struct at91_ssc_info *ssc_p;
-
-	if(!cpu_dai->active)
-		return 0;
-
-	ssc_p = &ssc_info[cpu_dai->id];
-
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr);
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr);
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr);
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr);
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR,  ssc_p->ssc_state.ssc_cmr);
-
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER,  ssc_p->ssc_state.ssc_imr);
-
-	at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
-		((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) |
-		((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0));
-
-	return 0;
-}
-
-#else
-#define at91_ssc_suspend	NULL
-#define at91_ssc_resume		NULL
-#endif
-
-#define AT91_SSC_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 AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_LE |\
-			  SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
-
-struct snd_soc_dai at91_ssc_dai[NUM_SSC_DEVICES] = {
-	{	.name = "at91-ssc0",
-		.id = 0,
-		.type = SND_SOC_DAI_PCM,
-		.suspend = at91_ssc_suspend,
-		.resume = at91_ssc_resume,
-		.playback = {
-			.channels_min = 1,
-			.channels_max = 2,
-			.rates = AT91_SSC_RATES,
-			.formats = AT91_SSC_FORMATS,},
-		.capture = {
-			.channels_min = 1,
-			.channels_max = 2,
-			.rates = AT91_SSC_RATES,
-			.formats = AT91_SSC_FORMATS,},
-		.ops = {
-			.startup = at91_ssc_startup,
-			.shutdown = at91_ssc_shutdown,
-			.prepare = at91_ssc_prepare,
-			.hw_params = at91_ssc_hw_params,},
-		.dai_ops = {
-			.set_sysclk = at91_ssc_set_dai_sysclk,
-			.set_fmt = at91_ssc_set_dai_fmt,
-			.set_clkdiv = at91_ssc_set_dai_clkdiv,},
-		.private_data = &ssc_info[0].ssc,
-	},
-#if NUM_SSC_DEVICES == 3
-	{	.name = "at91-ssc1",
-		.id = 1,
-		.type = SND_SOC_DAI_PCM,
-		.suspend = at91_ssc_suspend,
-		.resume = at91_ssc_resume,
-		.playback = {
-			.channels_min = 1,
-			.channels_max = 2,
-			.rates = AT91_SSC_RATES,
-			.formats = AT91_SSC_FORMATS,},
-		.capture = {
-			.channels_min = 1,
-			.channels_max = 2,
-			.rates = AT91_SSC_RATES,
-			.formats = AT91_SSC_FORMATS,},
-		.ops = {
-			.startup = at91_ssc_startup,
-			.shutdown = at91_ssc_shutdown,
-			.prepare = at91_ssc_prepare,
-			.hw_params = at91_ssc_hw_params,},
-		.dai_ops = {
-			.set_sysclk = at91_ssc_set_dai_sysclk,
-			.set_fmt = at91_ssc_set_dai_fmt,
-			.set_clkdiv = at91_ssc_set_dai_clkdiv,},
-		.private_data = &ssc_info[1].ssc,
-	},
-	{	.name = "at91-ssc2",
-		.id = 2,
-		.type = SND_SOC_DAI_PCM,
-		.suspend = at91_ssc_suspend,
-		.resume = at91_ssc_resume,
-		.playback = {
-			.channels_min = 1,
-			.channels_max = 2,
-			.rates = AT91_SSC_RATES,
-			.formats = AT91_SSC_FORMATS,},
-		.capture = {
-			.channels_min = 1,
-			.channels_max = 2,
-			.rates = AT91_SSC_RATES,
-			.formats = AT91_SSC_FORMATS,},
-		.ops = {
-			.startup = at91_ssc_startup,
-			.shutdown = at91_ssc_shutdown,
-			.prepare = at91_ssc_prepare,
-			.hw_params = at91_ssc_hw_params,},
-		.dai_ops = {
-			.set_sysclk = at91_ssc_set_dai_sysclk,
-			.set_fmt = at91_ssc_set_dai_fmt,
-			.set_clkdiv = at91_ssc_set_dai_clkdiv,},
-		.private_data = &ssc_info[2].ssc,
-	},
-#endif
-};
-
-EXPORT_SYMBOL_GPL(at91_ssc_dai);
-
-/* Module information */
-MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com");
-MODULE_DESCRIPTION("AT91 SSC ASoC Interface");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/at91/at91-ssc.h b/sound/soc/at91/at91-ssc.h
deleted file mode 100644
index 6b7bf38..0000000
--- a/sound/soc/at91/at91-ssc.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * at91-ssc.h - ALSA SSC interface for the Atmel AT91 SoC
- *
- * Author:	Frank Mandarino <fmandarino@endrelia.com>
- *		Endrelia Technologies Inc.
- * Created:	Jan 9, 2007
- *
- * This program is free software; you can 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 _AT91_SSC_H
-#define _AT91_SSC_H
-
-/* SSC system clock ids */
-#define AT91_SYSCLK_MCK		0 /* SSC uses AT91 MCK as system clock */
-
-/* SSC divider ids */
-#define AT91SSC_CMR_DIV		0 /* MCK divider for BCLK */
-#define AT91SSC_TCMR_PERIOD	1 /* BCLK divider for transmit FS */
-#define AT91SSC_RCMR_PERIOD	2 /* BCLK divider for receive FS */
-
-extern struct snd_soc_dai at91_ssc_dai[];
-
-#endif /* _AT91_SSC_H */
-
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
new file mode 100644
index 0000000..a608d70
--- /dev/null
+++ b/sound/soc/atmel/Kconfig
@@ -0,0 +1,43 @@
+config SND_ATMEL_SOC
+	tristate "SoC Audio for the Atmel System-on-Chip"
+	depends on ARCH_AT91 || AVR32
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the ATMEL SSC interface. You will also need
+	  to select the audio interfaces to support below.
+
+config SND_ATMEL_SOC_SSC
+	tristate
+	depends on SND_ATMEL_SOC
+	help
+	  Say Y or M if you want to add support for codecs the
+	  ATMEL SSC interface. You will also needs to select the individual
+	  machine drivers to support below.
+
+config SND_AT91_SOC_SAM9G20_WM8731
+	tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
+	depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC
+	select SND_ATMEL_SOC_SSC
+	select SND_SOC_WM8731
+	help
+	  Say Y if you want to add support for SoC audio on WM8731-based
+	  AT91sam9g20 evaluation board.
+
+config SND_AT32_SOC_PLAYPAQ
+        tristate "SoC Audio support for PlayPaq with WM8510"
+        depends on SND_ATMEL_SOC && BOARD_PLAYPAQ
+        select SND_ATMEL_SOC_SSC
+        select SND_SOC_WM8510
+        help
+          Say Y or M here if you want to add support for SoC audio
+          on the LRS PlayPaq.
+
+config SND_AT32_SOC_PLAYPAQ_SLAVE
+        bool "Run CODEC on PlayPaq in slave mode"
+        depends on SND_AT32_SOC_PLAYPAQ
+        default n
+        help
+          Say Y if you want to run with the AT32 SSC generating the BCLK
+          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.
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
new file mode 100644
index 0000000..f54a7cc
--- /dev/null
+++ b/sound/soc/atmel/Makefile
@@ -0,0 +1,15 @@
+# AT91 Platform Support
+snd-soc-atmel-pcm-objs := atmel-pcm.o
+snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
+
+obj-$(CONFIG_SND_ATMEL_SOC) += snd-soc-atmel-pcm.o
+obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
+
+# AT91 Machine Support
+snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
+
+# AT32 Machine Support
+snd-soc-playpaq-objs := playpaq_wm8510.o
+
+obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
+obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
new file mode 100644
index 0000000..1fac5ef
--- /dev/null
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -0,0 +1,494 @@
+/*
+ * atmel-pcm.c  --  ALSA PCM interface for the Atmel atmel SoC.
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2008 Atmel
+ *
+ * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *
+ * Based on at91-pcm. by:
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Copyright 2006 Endrelia Technologies Inc.
+ *
+ * Based on pxa2xx-pcm.c by:
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Nov 30, 2004
+ * Copyright:	(C) 2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/atmel_pdc.h>
+#include <linux/atmel-ssc.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/hardware.h>
+
+#include "atmel-pcm.h"
+
+
+/*--------------------------------------------------------------------------*\
+ * Hardware definition
+\*--------------------------------------------------------------------------*/
+/* TODO: These values were taken from the AT91 platform driver, check
+ *	 them against real values for AT32
+ */
+static const struct snd_pcm_hardware atmel_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_PAUSE,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 8192,
+	.periods_min		= 2,
+	.periods_max		= 1024,
+	.buffer_bytes_max	= 32 * 1024,
+};
+
+
+/*--------------------------------------------------------------------------*\
+ * Data types
+\*--------------------------------------------------------------------------*/
+struct atmel_runtime_data {
+	struct atmel_pcm_dma_params *params;
+	dma_addr_t dma_buffer;		/* physical address of dma buffer */
+	dma_addr_t dma_buffer_end;	/* first address beyond DMA buffer */
+	size_t period_size;
+
+	dma_addr_t period_ptr;		/* physical address of next period */
+	int periods;			/* period index of period_ptr */
+
+	/* PDC register save */
+	u32 pdc_xpr_save;
+	u32 pdc_xcr_save;
+	u32 pdc_xnpr_save;
+	u32 pdc_xncr_save;
+};
+
+
+/*--------------------------------------------------------------------------*\
+ * Helper functions
+\*--------------------------------------------------------------------------*/
+static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+	int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = atmel_pcm_hardware.buffer_bytes_max;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+					  &buf->addr, GFP_KERNEL);
+	pr_debug("atmel-pcm:"
+		"preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
+		(void *) buf->area,
+		(void *) buf->addr,
+		size);
+
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->bytes = size;
+	return 0;
+}
+/*--------------------------------------------------------------------------*\
+ * ISR
+\*--------------------------------------------------------------------------*/
+static void atmel_pcm_dma_irq(u32 ssc_sr,
+	struct snd_pcm_substream *substream)
+{
+	struct atmel_runtime_data *prtd = substream->runtime->private_data;
+	struct atmel_pcm_dma_params *params = prtd->params;
+	static int count;
+
+	count++;
+
+	if (ssc_sr & params->mask->ssc_endbuf) {
+		pr_warning("atmel-pcm: buffer %s on %s"
+				" (SSC_SR=%#x, count=%d)\n",
+				substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+				? "underrun" : "overrun",
+				params->name, ssc_sr, count);
+
+		/* re-start the PDC */
+		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+			   params->mask->pdc_disable);
+		prtd->period_ptr += prtd->period_size;
+		if (prtd->period_ptr >= prtd->dma_buffer_end)
+			prtd->period_ptr = prtd->dma_buffer;
+
+		ssc_writex(params->ssc->regs, params->pdc->xpr,
+			   prtd->period_ptr);
+		ssc_writex(params->ssc->regs, params->pdc->xcr,
+			   prtd->period_size / params->pdc_xfer_size);
+		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+			   params->mask->pdc_enable);
+	}
+
+	if (ssc_sr & params->mask->ssc_endx) {
+		/* Load the PDC next pointer and counter registers */
+		prtd->period_ptr += prtd->period_size;
+		if (prtd->period_ptr >= prtd->dma_buffer_end)
+			prtd->period_ptr = prtd->dma_buffer;
+
+		ssc_writex(params->ssc->regs, params->pdc->xnpr,
+			   prtd->period_ptr);
+		ssc_writex(params->ssc->regs, params->pdc->xncr,
+			   prtd->period_size / params->pdc_xfer_size);
+	}
+
+	snd_pcm_period_elapsed(substream);
+}
+
+
+/*--------------------------------------------------------------------------*\
+ * PCM operations
+\*--------------------------------------------------------------------------*/
+static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct atmel_runtime_data *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	/* this may get called several times by oss emulation
+	 * with different params */
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	runtime->dma_bytes = params_buffer_bytes(params);
+
+	prtd->params = rtd->dai->cpu_dai->dma_data;
+	prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
+
+	prtd->dma_buffer = runtime->dma_addr;
+	prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
+	prtd->period_size = params_period_bytes(params);
+
+	pr_debug("atmel-pcm: "
+		"hw_params: DMA for %s initialized "
+		"(dma_bytes=%u, period_size=%u)\n",
+		prtd->params->name,
+		runtime->dma_bytes,
+		prtd->period_size);
+	return 0;
+}
+
+static int atmel_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct atmel_runtime_data *prtd = substream->runtime->private_data;
+	struct atmel_pcm_dma_params *params = prtd->params;
+
+	if (params != NULL) {
+		ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
+			   params->mask->pdc_disable);
+		prtd->params->dma_intr_handler = NULL;
+	}
+
+	return 0;
+}
+
+static int atmel_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct atmel_runtime_data *prtd = substream->runtime->private_data;
+	struct atmel_pcm_dma_params *params = prtd->params;
+
+	ssc_writex(params->ssc->regs, SSC_IDR,
+		   params->mask->ssc_endx | params->mask->ssc_endbuf);
+	ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+		   params->mask->pdc_disable);
+	return 0;
+}
+
+static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
+	int cmd)
+{
+	struct snd_pcm_runtime *rtd = substream->runtime;
+	struct atmel_runtime_data *prtd = rtd->private_data;
+	struct atmel_pcm_dma_params *params = prtd->params;
+	int ret = 0;
+
+	pr_debug("atmel-pcm:buffer_size = %ld,"
+		"dma_area = %p, dma_bytes = %u\n",
+		rtd->buffer_size, rtd->dma_area, rtd->dma_bytes);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		prtd->period_ptr = prtd->dma_buffer;
+
+		ssc_writex(params->ssc->regs, params->pdc->xpr,
+			   prtd->period_ptr);
+		ssc_writex(params->ssc->regs, params->pdc->xcr,
+			   prtd->period_size / params->pdc_xfer_size);
+
+		prtd->period_ptr += prtd->period_size;
+		ssc_writex(params->ssc->regs, params->pdc->xnpr,
+			   prtd->period_ptr);
+		ssc_writex(params->ssc->regs, params->pdc->xncr,
+			   prtd->period_size / params->pdc_xfer_size);
+
+		pr_debug("atmel-pcm: trigger: "
+			"period_ptr=%lx, xpr=%u, "
+			"xcr=%u, xnpr=%u, xncr=%u\n",
+			(unsigned long)prtd->period_ptr,
+			ssc_readx(params->ssc->regs, params->pdc->xpr),
+			ssc_readx(params->ssc->regs, params->pdc->xcr),
+			ssc_readx(params->ssc->regs, params->pdc->xnpr),
+			ssc_readx(params->ssc->regs, params->pdc->xncr));
+
+		ssc_writex(params->ssc->regs, SSC_IER,
+			   params->mask->ssc_endx | params->mask->ssc_endbuf);
+		ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
+			   params->mask->pdc_enable);
+
+		pr_debug("sr=%u imr=%u\n",
+			ssc_readx(params->ssc->regs, SSC_SR),
+			ssc_readx(params->ssc->regs, SSC_IER));
+		break;		/* SNDRV_PCM_TRIGGER_START */
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+			   params->mask->pdc_disable);
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+			   params->mask->pdc_enable);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t atmel_pcm_pointer(
+	struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct atmel_runtime_data *prtd = runtime->private_data;
+	struct atmel_pcm_dma_params *params = prtd->params;
+	dma_addr_t ptr;
+	snd_pcm_uframes_t x;
+
+	ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr);
+	x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
+
+	if (x == runtime->buffer_size)
+		x = 0;
+
+	return x;
+}
+
+static int atmel_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct atmel_runtime_data *prtd;
+	int ret = 0;
+
+	snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware);
+
+	/* ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+						SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		goto out;
+
+	prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL);
+	if (prtd == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	runtime->private_data = prtd;
+
+ out:
+	return ret;
+}
+
+static int atmel_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct atmel_runtime_data *prtd = substream->runtime->private_data;
+
+	kfree(prtd);
+	return 0;
+}
+
+static int atmel_pcm_mmap(struct snd_pcm_substream *substream,
+	struct vm_area_struct *vma)
+{
+	return remap_pfn_range(vma, vma->vm_start,
+		       substream->dma_buffer.addr >> PAGE_SHIFT,
+		       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+struct snd_pcm_ops atmel_pcm_ops = {
+	.open		= atmel_pcm_open,
+	.close		= atmel_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= atmel_pcm_hw_params,
+	.hw_free	= atmel_pcm_hw_free,
+	.prepare	= atmel_pcm_prepare,
+	.trigger	= atmel_pcm_trigger,
+	.pointer	= atmel_pcm_pointer,
+	.mmap		= atmel_pcm_mmap,
+};
+
+
+/*--------------------------------------------------------------------------*\
+ * ASoC platform driver
+\*--------------------------------------------------------------------------*/
+static u64 atmel_pcm_dmamask = 0xffffffff;
+
+static int atmel_pcm_new(struct snd_card *card,
+	struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &atmel_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (dai->playback.channels_min) {
+		ret = atmel_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (dai->capture.channels_min) {
+		pr_debug("at32-pcm:"
+				"Allocating PCM capture DMA buffer\n");
+		ret = atmel_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+ out:
+	return ret;
+}
+
+static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+		dma_free_coherent(pcm->card->dev, buf->bytes,
+				  buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+#ifdef CONFIG_PM
+static int atmel_pcm_suspend(struct snd_soc_dai *dai)
+{
+	struct snd_pcm_runtime *runtime = dai->runtime;
+	struct atmel_runtime_data *prtd;
+	struct atmel_pcm_dma_params *params;
+
+	if (!runtime)
+		return 0;
+
+	prtd = runtime->private_data;
+	params = prtd->params;
+
+	/* disable the PDC and save the PDC registers */
+
+	ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable);
+
+	prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
+	prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
+	prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr);
+	prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr);
+
+	return 0;
+}
+
+static int atmel_pcm_resume(struct snd_soc_dai *dai)
+{
+	struct snd_pcm_runtime *runtime = dai->runtime;
+	struct atmel_runtime_data *prtd;
+	struct atmel_pcm_dma_params *params;
+
+	if (!runtime)
+		return 0;
+
+	prtd = runtime->private_data;
+	params = prtd->params;
+
+	/* restore the PDC registers and enable the PDC */
+	ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save);
+	ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save);
+	ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
+	ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
+
+	ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable);
+	return 0;
+}
+#else
+#define atmel_pcm_suspend	NULL
+#define atmel_pcm_resume	NULL
+#endif
+
+struct snd_soc_platform atmel_soc_platform = {
+	.name		= "atmel-audio",
+	.pcm_ops 	= &atmel_pcm_ops,
+	.pcm_new	= atmel_pcm_new,
+	.pcm_free	= atmel_pcm_free_dma_buffers,
+	.suspend	= atmel_pcm_suspend,
+	.resume		= atmel_pcm_resume,
+};
+EXPORT_SYMBOL_GPL(atmel_soc_platform);
+
+static int __init atmel_pcm_modinit(void)
+{
+	return snd_soc_register_platform(&atmel_soc_platform);
+}
+module_init(atmel_pcm_modinit);
+
+static void __exit atmel_pcm_modexit(void)
+{
+	snd_soc_unregister_platform(&atmel_soc_platform);
+}
+module_exit(atmel_pcm_modexit);
+
+MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
+MODULE_DESCRIPTION("Atmel PCM module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h
new file mode 100644
index 0000000..ec9b282
--- /dev/null
+++ b/sound/soc/atmel/atmel-pcm.h
@@ -0,0 +1,86 @@
+/*
+ * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC.
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2008 Atmel
+ *
+ * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *
+ * Based on at91-pcm. by:
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Copyright 2006 Endrelia Technologies Inc.
+ *
+ * Based on pxa2xx-pcm.c by:
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Nov 30, 2004
+ * Copyright:	(C) 2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _ATMEL_PCM_H
+#define _ATMEL_PCM_H
+
+#include <linux/atmel-ssc.h>
+
+/*
+ * Registers and status bits that are required by the PCM driver.
+ */
+struct atmel_pdc_regs {
+	unsigned int	xpr;		/* PDC recv/trans pointer */
+	unsigned int	xcr;		/* PDC recv/trans counter */
+	unsigned int	xnpr;		/* PDC next recv/trans pointer */
+	unsigned int	xncr;		/* PDC next recv/trans counter */
+	unsigned int	ptcr;		/* PDC transfer control */
+};
+
+struct atmel_ssc_mask {
+	u32	ssc_enable;		/* SSC recv/trans enable */
+	u32	ssc_disable;		/* SSC recv/trans disable */
+	u32	ssc_endx;		/* SSC ENDTX or ENDRX */
+	u32	ssc_endbuf;		/* SSC TXBUFE or RXBUFF */
+	u32	pdc_enable;		/* PDC recv/trans enable */
+	u32	pdc_disable;		/* PDC recv/trans disable */
+};
+
+/*
+ * This structure, shared between the PCM driver and the interface,
+ * contains all information required by the PCM driver to perform the
+ * PDC DMA operation.  All fields except dma_intr_handler() are initialized
+ * by the interface.  The dms_intr_handler() pointer is set by the PCM
+ * driver and called by the interface SSC interrupt handler if it is
+ * non-NULL.
+ */
+struct atmel_pcm_dma_params {
+	char *name;			/* stream identifier */
+	int pdc_xfer_size;		/* PDC counter increment in bytes */
+	struct ssc_device *ssc;		/* SSC device for stream */
+	struct atmel_pdc_regs *pdc;	/* PDC receive or transmit registers */
+	struct atmel_ssc_mask *mask;	/* SSC & PDC status bits */
+	struct snd_pcm_substream *substream;
+	void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
+};
+
+extern struct snd_soc_platform atmel_soc_platform;
+
+
+/*
+ * SSC register access (since ssc_writel() / ssc_readl() require literal name)
+ */
+#define ssc_readx(base, reg)            (__raw_readl((base) + (reg)))
+#define ssc_writex(base, reg, value)    __raw_writel((value), (base) + (reg))
+
+#endif /* _ATMEL_PCM_H */
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
new file mode 100644
index 0000000..c5d6790
--- /dev/null
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -0,0 +1,790 @@
+/*
+ * atmel_ssc_dai.c  --  ALSA SoC ATMEL SSC Audio Layer Platform driver
+ *
+ * Copyright (C) 2005 SAN People
+ * Copyright (C) 2008 Atmel
+ *
+ * Author: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *         ATMEL CORP.
+ *
+ * Based on at91-ssc.c by
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Based on pxa2xx Platform drivers by
+ * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/atmel_pdc.h>
+
+#include <linux/atmel-ssc.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <mach/hardware.h>
+
+#include "atmel-pcm.h"
+#include "atmel_ssc_dai.h"
+
+
+#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
+#define NUM_SSC_DEVICES		1
+#else
+#define NUM_SSC_DEVICES		3
+#endif
+
+/*
+ * SSC PDC registers required by the PCM DMA engine.
+ */
+static struct atmel_pdc_regs pdc_tx_reg = {
+	.xpr		= ATMEL_PDC_TPR,
+	.xcr		= ATMEL_PDC_TCR,
+	.xnpr		= ATMEL_PDC_TNPR,
+	.xncr		= ATMEL_PDC_TNCR,
+};
+
+static struct atmel_pdc_regs pdc_rx_reg = {
+	.xpr		= ATMEL_PDC_RPR,
+	.xcr		= ATMEL_PDC_RCR,
+	.xnpr		= ATMEL_PDC_RNPR,
+	.xncr		= ATMEL_PDC_RNCR,
+};
+
+/*
+ * SSC & PDC status bits for transmit and receive.
+ */
+static struct atmel_ssc_mask ssc_tx_mask = {
+	.ssc_enable	= SSC_BIT(CR_TXEN),
+	.ssc_disable	= SSC_BIT(CR_TXDIS),
+	.ssc_endx	= SSC_BIT(SR_ENDTX),
+	.ssc_endbuf	= SSC_BIT(SR_TXBUFE),
+	.pdc_enable	= ATMEL_PDC_TXTEN,
+	.pdc_disable	= ATMEL_PDC_TXTDIS,
+};
+
+static struct atmel_ssc_mask ssc_rx_mask = {
+	.ssc_enable	= SSC_BIT(CR_RXEN),
+	.ssc_disable	= SSC_BIT(CR_RXDIS),
+	.ssc_endx	= SSC_BIT(SR_ENDRX),
+	.ssc_endbuf	= SSC_BIT(SR_RXBUFF),
+	.pdc_enable	= ATMEL_PDC_RXTEN,
+	.pdc_disable	= ATMEL_PDC_RXTDIS,
+};
+
+
+/*
+ * DMA parameters.
+ */
+static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
+	{{
+	.name		= "SSC0 PCM out",
+	.pdc		= &pdc_tx_reg,
+	.mask		= &ssc_tx_mask,
+	},
+	{
+	.name		= "SSC0 PCM in",
+	.pdc		= &pdc_rx_reg,
+	.mask		= &ssc_rx_mask,
+	} },
+#if NUM_SSC_DEVICES == 3
+	{{
+	.name		= "SSC1 PCM out",
+	.pdc		= &pdc_tx_reg,
+	.mask		= &ssc_tx_mask,
+	},
+	{
+	.name		= "SSC1 PCM in",
+	.pdc		= &pdc_rx_reg,
+	.mask		= &ssc_rx_mask,
+	} },
+	{{
+	.name		= "SSC2 PCM out",
+	.pdc		= &pdc_tx_reg,
+	.mask		= &ssc_tx_mask,
+	},
+	{
+	.name		= "SSC2 PCM in",
+	.pdc		= &pdc_rx_reg,
+	.mask		= &ssc_rx_mask,
+	} },
+#endif
+};
+
+
+static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
+	{
+	.name		= "ssc0",
+	.lock		= __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
+	.dir_mask	= SSC_DIR_MASK_UNUSED,
+	.initialized	= 0,
+	},
+#if NUM_SSC_DEVICES == 3
+	{
+	.name		= "ssc1",
+	.lock		= __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
+	.dir_mask	= SSC_DIR_MASK_UNUSED,
+	.initialized	= 0,
+	},
+	{
+	.name		= "ssc2",
+	.lock		= __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
+	.dir_mask	= SSC_DIR_MASK_UNUSED,
+	.initialized	= 0,
+	},
+#endif
+};
+
+
+/*
+ * SSC interrupt handler.  Passes PDC interrupts to the DMA
+ * interrupt handler in the PCM driver.
+ */
+static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
+{
+	struct atmel_ssc_info *ssc_p = dev_id;
+	struct atmel_pcm_dma_params *dma_params;
+	u32 ssc_sr;
+	u32 ssc_substream_mask;
+	int i;
+
+	ssc_sr = (unsigned long)ssc_readl(ssc_p->ssc->regs, SR)
+			& (unsigned long)ssc_readl(ssc_p->ssc->regs, IMR);
+
+	/*
+	 * Loop through the substreams attached to this SSC.  If
+	 * a DMA-related interrupt occurred on that substream, call
+	 * the DMA interrupt handler function, if one has been
+	 * registered in the dma_params structure by the PCM driver.
+	 */
+	for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
+		dma_params = ssc_p->dma_params[i];
+
+		if ((dma_params != NULL) &&
+			(dma_params->dma_intr_handler != NULL)) {
+			ssc_substream_mask = (dma_params->mask->ssc_endx |
+					dma_params->mask->ssc_endbuf);
+			if (ssc_sr & ssc_substream_mask) {
+				dma_params->dma_intr_handler(ssc_sr,
+						dma_params->
+						substream);
+			}
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+/*-------------------------------------------------------------------------*\
+ * DAI functions
+\*-------------------------------------------------------------------------*/
+/*
+ * Startup.  Only that one substream allowed in each direction.
+ */
+static int atmel_ssc_startup(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+	int dir_mask;
+
+	pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
+		ssc_readl(ssc_p->ssc->regs, SR));
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir_mask = SSC_DIR_MASK_PLAYBACK;
+	else
+		dir_mask = SSC_DIR_MASK_CAPTURE;
+
+	spin_lock_irq(&ssc_p->lock);
+	if (ssc_p->dir_mask & dir_mask) {
+		spin_unlock_irq(&ssc_p->lock);
+		return -EBUSY;
+	}
+	ssc_p->dir_mask |= dir_mask;
+	spin_unlock_irq(&ssc_p->lock);
+
+	return 0;
+}
+
+/*
+ * Shutdown.  Clear DMA parameters and shutdown the SSC if there
+ * are no other substreams open.
+ */
+static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+	struct atmel_pcm_dma_params *dma_params;
+	int dir, dir_mask;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = 0;
+	else
+		dir = 1;
+
+	dma_params = ssc_p->dma_params[dir];
+
+	if (dma_params != NULL) {
+		ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);
+		pr_debug("atmel_ssc_shutdown: %s disabled SSC_SR=0x%08x\n",
+			(dir ? "receive" : "transmit"),
+			ssc_readl(ssc_p->ssc->regs, SR));
+
+		dma_params->ssc = NULL;
+		dma_params->substream = NULL;
+		ssc_p->dma_params[dir] = NULL;
+	}
+
+	dir_mask = 1 << dir;
+
+	spin_lock_irq(&ssc_p->lock);
+	ssc_p->dir_mask &= ~dir_mask;
+	if (!ssc_p->dir_mask) {
+		if (ssc_p->initialized) {
+			/* Shutdown the SSC clock. */
+			pr_debug("atmel_ssc_dau: Stopping clock\n");
+			clk_disable(ssc_p->ssc->clk);
+
+			free_irq(ssc_p->ssc->irq, ssc_p);
+			ssc_p->initialized = 0;
+		}
+
+		/* Reset the SSC */
+		ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+		/* Clear the SSC dividers */
+		ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
+	}
+	spin_unlock_irq(&ssc_p->lock);
+}
+
+
+/*
+ * Record the DAI format for use in hw_params().
+ */
+static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+		unsigned int fmt)
+{
+	struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+
+	ssc_p->daifmt = fmt;
+	return 0;
+}
+
+/*
+ * Record SSC clock dividers for use in hw_params().
+ */
+static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
+	int div_id, int div)
+{
+	struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+
+	switch (div_id) {
+	case ATMEL_SSC_CMR_DIV:
+		/*
+		 * The same master clock divider is used for both
+		 * transmit and receive, so if a value has already
+		 * been set, it must match this value.
+		 */
+		if (ssc_p->cmr_div == 0)
+			ssc_p->cmr_div = div;
+		else
+			if (div != ssc_p->cmr_div)
+				return -EBUSY;
+		break;
+
+	case ATMEL_SSC_TCMR_PERIOD:
+		ssc_p->tcmr_period = div;
+		break;
+
+	case ATMEL_SSC_RCMR_PERIOD:
+		ssc_p->rcmr_period = div;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Configure the SSC.
+ */
+static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	int id = rtd->dai->cpu_dai->id;
+	struct atmel_ssc_info *ssc_p = &ssc_info[id];
+	struct atmel_pcm_dma_params *dma_params;
+	int dir, channels, bits;
+	u32 tfmr, rfmr, tcmr, rcmr;
+	int start_event;
+	int ret;
+
+	/*
+	 * Currently, there is only one set of dma params for
+	 * each direction.  If more are added, this code will
+	 * have to be changed to select the proper set.
+	 */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = 0;
+	else
+		dir = 1;
+
+	dma_params = &ssc_dma_params[id][dir];
+	dma_params->ssc = ssc_p->ssc;
+	dma_params->substream = substream;
+
+	ssc_p->dma_params[dir] = dma_params;
+
+	/*
+	 * The cpu_dai->dma_data field is only used to communicate the
+	 * appropriate DMA parameters to the pcm driver hw_params()
+	 * function.  It should not be used for other purposes
+	 * as it is common to all substreams.
+	 */
+	rtd->dai->cpu_dai->dma_data = dma_params;
+
+	channels = params_channels(params);
+
+	/*
+	 * Determine sample size in bits and the PDC increment.
+	 */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		bits = 8;
+		dma_params->pdc_xfer_size = 1;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		bits = 16;
+		dma_params->pdc_xfer_size = 2;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		bits = 24;
+		dma_params->pdc_xfer_size = 4;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		bits = 32;
+		dma_params->pdc_xfer_size = 4;
+		break;
+	default:
+		printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format");
+		return -EINVAL;
+	}
+
+	/*
+	 * The SSC only supports up to 16-bit samples in I2S format, due
+	 * to the size of the Frame Mode Register FSLEN field.
+	 */
+	if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S
+		&& bits > 16) {
+		printk(KERN_WARNING
+				"atmel_ssc_dai: sample size %d"
+				"is too large for I2S\n", bits);
+		return -EINVAL;
+	}
+
+	/*
+	 * Compute SSC register settings.
+	 */
+	switch (ssc_p->daifmt
+		& (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
+
+	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+		/*
+		 * I2S format, SSC provides BCLK and LRC clocks.
+		 *
+		 * The SSC transmit and receive clocks are generated
+		 * from the MCK divider, and the BCLK signal
+		 * is output on the SSC TK line.
+		 */
+		rcmr =	  SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
+			| SSC_BF(RCMR_STTDLY, START_DELAY)
+			| SSC_BF(RCMR_START, SSC_START_FALLING_RF)
+			| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+			| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+			| SSC_BF(RCMR_CKS, SSC_CKS_DIV);
+
+		rfmr =	  SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+			| SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE)
+			| SSC_BF(RFMR_FSLEN, (bits - 1))
+			| SSC_BF(RFMR_DATNB, (channels - 1))
+			| SSC_BIT(RFMR_MSBF)
+			| SSC_BF(RFMR_LOOP, 0)
+			| SSC_BF(RFMR_DATLEN, (bits - 1));
+
+		tcmr =	  SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
+			| SSC_BF(TCMR_STTDLY, START_DELAY)
+			| SSC_BF(TCMR_START, SSC_START_FALLING_RF)
+			| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
+			| SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS)
+			| SSC_BF(TCMR_CKS, SSC_CKS_DIV);
+
+		tfmr =	  SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+			| SSC_BF(TFMR_FSDEN, 0)
+			| SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE)
+			| SSC_BF(TFMR_FSLEN, (bits - 1))
+			| SSC_BF(TFMR_DATNB, (channels - 1))
+			| SSC_BIT(TFMR_MSBF)
+			| SSC_BF(TFMR_DATDEF, 0)
+			| SSC_BF(TFMR_DATLEN, (bits - 1));
+		break;
+
+	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+		/*
+		 * I2S format, CODEC supplies BCLK and LRC clocks.
+		 *
+		 * The SSC transmit clock is obtained from the BCLK signal on
+		 * on the TK line, and the SSC receive clock is
+		 * generated from the transmit clock.
+		 *
+		 *  For single channel data, one sample is transferred
+		 * on the falling edge of the LRC clock.
+		 * For two channel data, one sample is
+		 * transferred on both edges of the LRC clock.
+		 */
+		start_event = ((channels == 1)
+				? SSC_START_FALLING_RF
+				: SSC_START_EDGE_RF);
+
+		rcmr =	  SSC_BF(RCMR_PERIOD, 0)
+			| SSC_BF(RCMR_STTDLY, START_DELAY)
+			| SSC_BF(RCMR_START, start_event)
+			| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+			| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+			| SSC_BF(RCMR_CKS, SSC_CKS_CLOCK);
+
+		rfmr =	  SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+			| SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
+			| SSC_BF(RFMR_FSLEN, 0)
+			| SSC_BF(RFMR_DATNB, 0)
+			| SSC_BIT(RFMR_MSBF)
+			| SSC_BF(RFMR_LOOP, 0)
+			| SSC_BF(RFMR_DATLEN, (bits - 1));
+
+		tcmr =	  SSC_BF(TCMR_PERIOD, 0)
+			| SSC_BF(TCMR_STTDLY, START_DELAY)
+			| SSC_BF(TCMR_START, start_event)
+			| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
+			| SSC_BF(TCMR_CKO, SSC_CKO_NONE)
+			| SSC_BF(TCMR_CKS, SSC_CKS_PIN);
+
+		tfmr =	  SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+			| SSC_BF(TFMR_FSDEN, 0)
+			| SSC_BF(TFMR_FSOS, SSC_FSOS_NONE)
+			| SSC_BF(TFMR_FSLEN, 0)
+			| SSC_BF(TFMR_DATNB, 0)
+			| SSC_BIT(TFMR_MSBF)
+			| SSC_BF(TFMR_DATDEF, 0)
+			| SSC_BF(TFMR_DATLEN, (bits - 1));
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
+		/*
+		 * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
+		 *
+		 * The SSC transmit and receive clocks are generated from the
+		 * MCK divider, and the BCLK signal is output
+		 * on the SSC TK line.
+		 */
+		rcmr =	  SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
+			| SSC_BF(RCMR_STTDLY, 1)
+			| SSC_BF(RCMR_START, SSC_START_RISING_RF)
+			| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+			| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+			| SSC_BF(RCMR_CKS, SSC_CKS_DIV);
+
+		rfmr =	  SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+			| SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE)
+			| SSC_BF(RFMR_FSLEN, 0)
+			| SSC_BF(RFMR_DATNB, (channels - 1))
+			| SSC_BIT(RFMR_MSBF)
+			| SSC_BF(RFMR_LOOP, 0)
+			| SSC_BF(RFMR_DATLEN, (bits - 1));
+
+		tcmr =	  SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
+			| SSC_BF(TCMR_STTDLY, 1)
+			| SSC_BF(TCMR_START, SSC_START_RISING_RF)
+			| SSC_BF(TCMR_CKI, SSC_CKI_RISING)
+			| SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS)
+			| SSC_BF(TCMR_CKS, SSC_CKS_DIV);
+
+		tfmr =	  SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+			| SSC_BF(TFMR_FSDEN, 0)
+			| SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE)
+			| SSC_BF(TFMR_FSLEN, 0)
+			| SSC_BF(TFMR_DATNB, (channels - 1))
+			| SSC_BIT(TFMR_MSBF)
+			| SSC_BF(TFMR_DATDEF, 0)
+			| SSC_BF(TFMR_DATLEN, (bits - 1));
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+	default:
+		printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
+			ssc_p->daifmt);
+		return -EINVAL;
+		break;
+	}
+	pr_debug("atmel_ssc_hw_params: "
+			"RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
+			rcmr, rfmr, tcmr, tfmr);
+
+	if (!ssc_p->initialized) {
+
+		/* Enable PMC peripheral clock for this SSC */
+		pr_debug("atmel_ssc_dai: Starting clock\n");
+		clk_enable(ssc_p->ssc->clk);
+
+		/* Reset the SSC and its PDC registers */
+		ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+
+		ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
+		ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
+		ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
+		ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
+
+		ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
+		ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
+		ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
+		ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
+
+		ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0,
+				ssc_p->name, ssc_p);
+		if (ret < 0) {
+			printk(KERN_WARNING
+					"atmel_ssc_dai: request_irq failure\n");
+			pr_debug("Atmel_ssc_dai: Stoping clock\n");
+			clk_disable(ssc_p->ssc->clk);
+			return ret;
+		}
+
+		ssc_p->initialized = 1;
+	}
+
+	/* set SSC clock mode register */
+	ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div);
+
+	/* set receive clock mode and format */
+	ssc_writel(ssc_p->ssc->regs, RCMR, rcmr);
+	ssc_writel(ssc_p->ssc->regs, RFMR, rfmr);
+
+	/* set transmit clock mode and format */
+	ssc_writel(ssc_p->ssc->regs, TCMR, tcmr);
+	ssc_writel(ssc_p->ssc->regs, TFMR, tfmr);
+
+	pr_debug("atmel_ssc_dai,hw_params: SSC initialized\n");
+	return 0;
+}
+
+
+static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+	struct atmel_pcm_dma_params *dma_params;
+	int dir;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = 0;
+	else
+		dir = 1;
+
+	dma_params = ssc_p->dma_params[dir];
+
+	ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);
+
+	pr_debug("%s enabled SSC_SR=0x%08x\n",
+			dir ? "receive" : "transmit",
+			ssc_readl(ssc_p->ssc->regs, SR));
+	return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
+{
+	struct atmel_ssc_info *ssc_p;
+
+	if (!cpu_dai->active)
+		return 0;
+
+	ssc_p = &ssc_info[cpu_dai->id];
+
+	/* Save the status register before disabling transmit and receive */
+	ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR);
+	ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS));
+
+	/* Save the current interrupt mask, then disable unmasked interrupts */
+	ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR);
+	ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr);
+
+	ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR);
+	ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR);
+	ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR);
+	ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR);
+	ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR);
+
+	return 0;
+}
+
+
+
+static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
+{
+	struct atmel_ssc_info *ssc_p;
+	u32 cr;
+
+	if (!cpu_dai->active)
+		return 0;
+
+	ssc_p = &ssc_info[cpu_dai->id];
+
+	/* restore SSC register settings */
+	ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);
+	ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr);
+	ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr);
+	ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr);
+	ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr);
+
+	/* re-enable interrupts */
+	ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr);
+
+	/* Re-enable recieve and transmit as appropriate */
+	cr = 0;
+	cr |=
+	    (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0;
+	cr |=
+	    (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0;
+	ssc_writel(ssc_p->ssc->regs, CR, cr);
+
+	return 0;
+}
+#else /* CONFIG_PM */
+#  define atmel_ssc_suspend	NULL
+#  define atmel_ssc_resume	NULL
+#endif /* CONFIG_PM */
+
+
+#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
+
+#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_LE |\
+			  SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
+	{	.name = "atmel-ssc0",
+		.id = 0,
+		.suspend = atmel_ssc_suspend,
+		.resume = atmel_ssc_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ATMEL_SSC_RATES,
+			.formats = ATMEL_SSC_FORMATS,},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ATMEL_SSC_RATES,
+			.formats = ATMEL_SSC_FORMATS,},
+		.ops = {
+			.startup = atmel_ssc_startup,
+			.shutdown = atmel_ssc_shutdown,
+			.prepare = atmel_ssc_prepare,
+			.hw_params = atmel_ssc_hw_params,
+			.set_fmt = atmel_ssc_set_dai_fmt,
+			.set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+		.private_data = &ssc_info[0],
+	},
+#if NUM_SSC_DEVICES == 3
+	{	.name = "atmel-ssc1",
+		.id = 1,
+		.suspend = atmel_ssc_suspend,
+		.resume = atmel_ssc_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ATMEL_SSC_RATES,
+			.formats = ATMEL_SSC_FORMATS,},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ATMEL_SSC_RATES,
+			.formats = ATMEL_SSC_FORMATS,},
+		.ops = {
+			.startup = atmel_ssc_startup,
+			.shutdown = atmel_ssc_shutdown,
+			.prepare = atmel_ssc_prepare,
+			.hw_params = atmel_ssc_hw_params,
+			.set_fmt = atmel_ssc_set_dai_fmt,
+			.set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+		.private_data = &ssc_info[1],
+	},
+	{	.name = "atmel-ssc2",
+		.id = 2,
+		.suspend = atmel_ssc_suspend,
+		.resume = atmel_ssc_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ATMEL_SSC_RATES,
+			.formats = ATMEL_SSC_FORMATS,},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ATMEL_SSC_RATES,
+			.formats = ATMEL_SSC_FORMATS,},
+		.ops = {
+			.startup = atmel_ssc_startup,
+			.shutdown = atmel_ssc_shutdown,
+			.prepare = atmel_ssc_prepare,
+			.hw_params = atmel_ssc_hw_params,
+			.set_fmt = atmel_ssc_set_dai_fmt,
+			.set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+		.private_data = &ssc_info[2],
+	},
+#endif
+};
+EXPORT_SYMBOL_GPL(atmel_ssc_dai);
+
+static int __init atmel_ssc_modinit(void)
+{
+	return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+}
+module_init(atmel_ssc_modinit);
+
+static void __exit atmel_ssc_modexit(void)
+{
+	snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+}
+module_exit(atmel_ssc_modexit);
+
+/* Module information */
+MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");
+MODULE_DESCRIPTION("ATMEL SSC ASoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h
new file mode 100644
index 0000000..a828746
--- /dev/null
+++ b/sound/soc/atmel/atmel_ssc_dai.h
@@ -0,0 +1,121 @@
+/*
+ * atmel_ssc_dai.h - ALSA SSC interface for the Atmel  SoC
+ *
+ * Copyright (C) 2005 SAN People
+ * Copyright (C) 2008 Atmel
+ *
+ * Author: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *         ATMEL CORP.
+ *
+ * Based on at91-ssc.c by
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Based on pxa2xx Platform drivers by
+ * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 _ATMEL_SSC_DAI_H
+#define _ATMEL_SSC_DAI_H
+
+#include <linux/types.h>
+#include <linux/atmel-ssc.h>
+
+#include "atmel-pcm.h"
+
+/* SSC system clock ids */
+#define ATMEL_SYSCLK_MCK	0 /* SSC uses AT91 MCK as system clock */
+
+/* SSC divider ids */
+#define ATMEL_SSC_CMR_DIV	0 /* MCK divider for BCLK */
+#define ATMEL_SSC_TCMR_PERIOD	1 /* BCLK divider for transmit FS */
+#define ATMEL_SSC_RCMR_PERIOD	2 /* BCLK divider for receive FS */
+/*
+ * SSC direction masks
+ */
+#define SSC_DIR_MASK_UNUSED	0
+#define SSC_DIR_MASK_PLAYBACK	1
+#define SSC_DIR_MASK_CAPTURE	2
+
+/*
+ * SSC register values that Atmel left out of <linux/atmel-ssc.h>.  These
+ * are expected to be used with SSC_BF
+ */
+/* START bit field values */
+#define SSC_START_CONTINUOUS	0
+#define SSC_START_TX_RX		1
+#define SSC_START_LOW_RF	2
+#define SSC_START_HIGH_RF	3
+#define SSC_START_FALLING_RF	4
+#define SSC_START_RISING_RF	5
+#define SSC_START_LEVEL_RF	6
+#define SSC_START_EDGE_RF	7
+#define SSS_START_COMPARE_0	8
+
+/* CKI bit field values */
+#define SSC_CKI_FALLING		0
+#define SSC_CKI_RISING		1
+
+/* CKO bit field values */
+#define SSC_CKO_NONE		0
+#define SSC_CKO_CONTINUOUS	1
+#define SSC_CKO_TRANSFER	2
+
+/* CKS bit field values */
+#define SSC_CKS_DIV		0
+#define SSC_CKS_CLOCK		1
+#define SSC_CKS_PIN		2
+
+/* FSEDGE bit field values */
+#define SSC_FSEDGE_POSITIVE	0
+#define SSC_FSEDGE_NEGATIVE	1
+
+/* FSOS bit field values */
+#define SSC_FSOS_NONE		0
+#define SSC_FSOS_NEGATIVE	1
+#define SSC_FSOS_POSITIVE	2
+#define SSC_FSOS_LOW		3
+#define SSC_FSOS_HIGH		4
+#define SSC_FSOS_TOGGLE		5
+
+#define START_DELAY		1
+
+struct atmel_ssc_state {
+	u32 ssc_cmr;
+	u32 ssc_rcmr;
+	u32 ssc_rfmr;
+	u32 ssc_tcmr;
+	u32 ssc_tfmr;
+	u32 ssc_sr;
+	u32 ssc_imr;
+};
+
+
+struct atmel_ssc_info {
+	char *name;
+	struct ssc_device *ssc;
+	spinlock_t lock;	/* lock for dir_mask */
+	unsigned short dir_mask;	/* 0=unused, 1=playback, 2=capture */
+	unsigned short initialized;	/* true if SSC has been initialized */
+	unsigned short daifmt;
+	unsigned short cmr_div;
+	unsigned short tcmr_period;
+	unsigned short rcmr_period;
+	struct atmel_pcm_dma_params *dma_params[2];
+	struct atmel_ssc_state ssc_state;
+};
+extern struct snd_soc_dai atmel_ssc_dai[];
+
+#endif /* _AT91_SSC_DAI_H */
diff --git a/sound/soc/at32/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c
similarity index 98%
rename from sound/soc/at32/playpaq_wm8510.c
rename to sound/soc/atmel/playpaq_wm8510.c
index b1966e4..43dd8ce 100644
--- a/sound/soc/at32/playpaq_wm8510.c
+++ b/sound/soc/atmel/playpaq_wm8510.c
@@ -22,7 +22,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/clk.h>
@@ -40,8 +39,8 @@
 #include <mach/portmux.h>
 
 #include "../codecs/wm8510.h"
-#include "at32-pcm.h"
-#include "at32-ssc.h"
+#include "atmel-pcm.h"
+#include "atmel_ssc_dai.h"
 
 
 /*-------------------------------------------------------------------------*\
@@ -362,8 +361,9 @@
 
 
 
-static struct snd_soc_machine snd_soc_machine_playpaq = {
+static struct snd_soc_card snd_soc_playpaq = {
 	.name = "LRS_PlayPaq_WM8510",
+	.platform = &at32_soc_platform,
 	.dai_link = &playpaq_wm8510_dai,
 	.num_links = 1,
 };
@@ -378,8 +378,7 @@
 
 
 static struct snd_soc_device playpaq_wm8510_snd_devdata = {
-	.machine = &snd_soc_machine_playpaq,
-	.platform = &at32_soc_platform,
+	.card = &snd_soc_playpaq,
 	.codec_dev = &soc_codec_dev_wm8510,
 	.codec_data = &playpaq_wm8510_setup,
 };
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
new file mode 100644
index 0000000..1fb59a9
--- /dev/null
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -0,0 +1,328 @@
+/*
+ * sam9g20_wm8731  --  SoC audio for AT91SAM9G20-based
+ * 			ATMEL AT91SAM9G20ek board.
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2008 Atmel
+ *
+ * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *
+ * Based on ati_b1_wm8731.c by:
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Copyright 2006 Endrelia Technologies Inc.
+ * Based on corgi.c by:
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand 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
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <linux/interrupt.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 <mach/hardware.h>
+#include <mach/gpio.h>
+
+#include "../codecs/wm8731.h"
+#include "atmel-pcm.h"
+#include "atmel_ssc_dai.h"
+
+
+static int at91sam9g20ek_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	int ret;
+
+	/* codec system clock is supplied by PCK0, set to 12MHz */
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+		12000000, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void at91sam9g20ek_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	dev_dbg(rtd->socdev->dev, "shutdown");
+}
+
+static int at91sam9g20ek_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;
+	struct atmel_ssc_info *ssc_p = cpu_dai->private_data;
+	struct ssc_device *ssc = ssc_p->ssc;
+	int ret;
+
+	unsigned int rate;
+	int cmr_div, period;
+
+	if (ssc == NULL) {
+		printk(KERN_INFO "at91sam9g20ek_hw_params: ssc is NULL!\n");
+		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_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * The SSC clock dividers depend on the sample rate.  The CMR.DIV
+	 * field divides the system master clock MCK to drive the SSC TK
+	 * signal which provides the codec BCLK.  The TCMR.PERIOD and
+	 * RCMR.PERIOD fields further divide the BCLK signal to drive
+	 * the SSC TF and RF signals which provide the codec DACLRC and
+	 * ADCLRC clocks.
+	 *
+	 * The dividers were determined through trial and error, where a
+	 * CMR.DIV value is chosen such that the resulting BCLK value is
+	 * divisible, or almost divisible, by (2 * sample rate), and then
+	 * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
+	 */
+	rate = params_rate(params);
+
+	switch (rate) {
+	case 8000:
+		cmr_div = 55;	/* BCLK = 133MHz/(2*55) = 1.209MHz */
+		period = 74;	/* LRC = BCLK/(2*(74+1)) ~= 8060,6Hz */
+		break;
+	case 11025:
+		cmr_div = 67;	/* BCLK = 133MHz/(2*60) = 1.108MHz */
+		period = 45;	/* LRC = BCLK/(2*(49+1)) = 11083,3Hz */
+		break;
+	case 16000:
+		cmr_div = 63;	/* BCLK = 133MHz/(2*63) = 1.055MHz */
+		period = 32;	/* LRC = BCLK/(2*(32+1)) = 15993,2Hz */
+		break;
+	case 22050:
+		cmr_div = 52;	/* BCLK = 133MHz/(2*52) = 1.278MHz */
+		period = 28;	/* LRC = BCLK/(2*(28+1)) = 22049Hz */
+		break;
+	case 32000:
+		cmr_div = 66;	/* BCLK = 133MHz/(2*66) = 1.007MHz */
+		period = 15;	/* LRC = BCLK/(2*(15+1)) = 31486,742Hz */
+		break;
+	case 44100:
+		cmr_div = 29;	/* BCLK = 133MHz/(2*29) = 2.293MHz */
+		period = 25;	/* LRC = BCLK/(2*(25+1)) = 44098Hz */
+		break;
+	case 48000:
+		cmr_div = 33;	/* BCLK = 133MHz/(2*33) = 2.015MHz */
+		period = 20;	/* LRC = BCLK/(2*(20+1)) = 47979,79Hz */
+		break;
+	case 88200:
+		cmr_div = 29;	/* BCLK = 133MHz/(2*29) = 2.293MHz */
+		period = 12;	/* LRC = BCLK/(2*(12+1)) = 88196Hz */
+		break;
+	case 96000:
+		cmr_div = 23;	/* BCLK = 133MHz/(2*23) = 2.891MHz */
+		period = 14;	/* LRC = BCLK/(2*(14+1)) = 96376Hz */
+		break;
+	default:
+		printk(KERN_WARNING "unsupported rate %d"
+				" on at91sam9g20ek board\n", rate);
+		return -EINVAL;
+	}
+
+	/* set the MCK divider for BCLK */
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cmr_div);
+	if (ret < 0)
+		return ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		/* set the BCLK divider for DACLRC */
+		ret = snd_soc_dai_set_clkdiv(cpu_dai,
+						ATMEL_SSC_TCMR_PERIOD, period);
+	} else {
+		/* set the BCLK divider for ADCLRC */
+		ret = snd_soc_dai_set_clkdiv(cpu_dai,
+						ATMEL_SSC_RCMR_PERIOD, period);
+	}
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops at91sam9g20ek_ops = {
+	.startup = at91sam9g20ek_startup,
+	.hw_params = at91sam9g20ek_hw_params,
+	.shutdown = at91sam9g20ek_shutdown,
+};
+
+
+static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("Int Mic", NULL),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+
+	/* speaker connected to LHPOUT */
+	{"Ext Spk", NULL, "LHPOUT"},
+
+	/* mic is connected to Mic Jack, with WM8731 Mic Bias */
+	{"MICIN", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Int Mic"},
+};
+
+/*
+ * Logic for a wm8731 as connected on a at91sam9g20ek board.
+ */
+static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
+{
+	printk(KERN_DEBUG
+			"at91sam9g20ek_wm8731 "
+			": at91sam9g20ek_wm8731_init() called\n");
+
+	/* Add specific widgets */
+	snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets,
+				  ARRAY_SIZE(at91sam9g20ek_dapm_widgets));
+	/* Set up specific audio path interconnects */
+	snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+	/* not connected */
+	snd_soc_dapm_disable_pin(codec, "RLINEIN");
+	snd_soc_dapm_disable_pin(codec, "LLINEIN");
+
+	/* always connected */
+	snd_soc_dapm_enable_pin(codec, "Int Mic");
+	snd_soc_dapm_enable_pin(codec, "Ext Spk");
+
+	snd_soc_dapm_sync(codec);
+
+	return 0;
+}
+
+static struct snd_soc_dai_link at91sam9g20ek_dai = {
+	.name = "WM8731",
+	.stream_name = "WM8731 PCM",
+	.cpu_dai = &atmel_ssc_dai[0],
+	.codec_dai = &wm8731_dai,
+	.init = at91sam9g20ek_wm8731_init,
+	.ops = &at91sam9g20ek_ops,
+};
+
+static struct snd_soc_card snd_soc_at91sam9g20ek = {
+	.name = "WM8731",
+	.platform = &atmel_soc_platform,
+	.dai_link = &at91sam9g20ek_dai,
+	.num_links = 1,
+};
+
+static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = {
+	.i2c_bus = 0,
+	.i2c_address = 0x1b,
+};
+
+static struct snd_soc_device at91sam9g20ek_snd_devdata = {
+	.card = &snd_soc_at91sam9g20ek,
+	.codec_dev = &soc_codec_dev_wm8731,
+	.codec_data = &at91sam9g20ek_wm8731_setup,
+};
+
+static struct platform_device *at91sam9g20ek_snd_device;
+
+static int __init at91sam9g20ek_init(void)
+{
+	struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
+	struct ssc_device *ssc = NULL;
+	int ret;
+
+	/*
+	 * Request SSC device
+	 */
+	ssc = ssc_request(0);
+	if (IS_ERR(ssc)) {
+		ret = PTR_ERR(ssc);
+		ssc = NULL;
+		goto err_ssc;
+	}
+	ssc_p->ssc = ssc;
+
+	at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!at91sam9g20ek_snd_device) {
+		printk(KERN_DEBUG
+				"platform device allocation failed\n");
+		ret = -ENOMEM;
+	}
+
+	platform_set_drvdata(at91sam9g20ek_snd_device,
+			&at91sam9g20ek_snd_devdata);
+	at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev;
+
+	ret = platform_device_add(at91sam9g20ek_snd_device);
+	if (ret) {
+		printk(KERN_DEBUG
+				"platform device allocation failed\n");
+		platform_device_put(at91sam9g20ek_snd_device);
+	}
+
+	return ret;
+
+err_ssc:
+	return ret;
+}
+
+static void __exit at91sam9g20ek_exit(void)
+{
+	struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
+	struct ssc_device *ssc;
+
+	if (ssc_p != NULL) {
+		ssc = ssc_p->ssc;
+		if (ssc != NULL)
+			ssc_free(ssc);
+		ssc_p->ssc = NULL;
+	}
+
+	platform_device_unregister(at91sam9g20ek_snd_device);
+	at91sam9g20ek_snd_device = NULL;
+}
+
+module_init(at91sam9g20ek_init);
+module_exit(at91sam9g20ek_exit);
+
+/* Module information */
+MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
+MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 1466d93..74c823d 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -406,11 +406,12 @@
 {
 	au1xpsc_audio_pcmdma[PCM_TX] = NULL;
 	au1xpsc_audio_pcmdma[PCM_RX] = NULL;
-	return 0;
+	return snd_soc_register_platform(&au1xpsc_soc_platform);
 }
 
 static void __exit au1xpsc_audio_dbdma_exit(void)
 {
+	snd_soc_unregister_platform(&au1xpsc_soc_platform);
 }
 
 module_init(au1xpsc_audio_dbdma_init);
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 57facba..f0e30ae 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -160,7 +160,8 @@
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
-				  struct snd_pcm_hw_params *params)
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
 {
 	/* FIXME */
 	struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
@@ -210,7 +211,7 @@
 }
 
 static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
-				int cmd)
+				int cmd, struct snd_soc_dai *dai)
 {
 	/* FIXME */
 	struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
@@ -313,8 +314,7 @@
 	au1xpsc_ac97_workdata = NULL;
 }
 
-static int au1xpsc_ac97_suspend(struct platform_device *pdev,
-				struct snd_soc_dai *dai)
+static int au1xpsc_ac97_suspend(struct snd_soc_dai *dai)
 {
 	/* save interesting registers and disable PSC */
 	au1xpsc_ac97_workdata->pm[0] =
@@ -328,8 +328,7 @@
 	return 0;
 }
 
-static int au1xpsc_ac97_resume(struct platform_device *pdev,
-			       struct snd_soc_dai *dai)
+static int au1xpsc_ac97_resume(struct snd_soc_dai *dai)
 {
 	/* restore PSC clock config */
 	au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE,
@@ -345,7 +344,7 @@
 
 struct snd_soc_dai au1xpsc_ac97_dai = {
 	.name			= "au1xpsc_ac97",
-	.type			= SND_SOC_DAI_AC97,
+	.ac97_control		= 1,
 	.probe			= au1xpsc_ac97_probe,
 	.remove			= au1xpsc_ac97_remove,
 	.suspend		= au1xpsc_ac97_suspend,
@@ -372,11 +371,12 @@
 static int __init au1xpsc_ac97_init(void)
 {
 	au1xpsc_ac97_workdata = NULL;
-	return 0;
+	return snd_soc_register_dai(&au1xpsc_ac97_dai);
 }
 
 static void __exit au1xpsc_ac97_exit(void)
 {
+	snd_soc_unregister_dai(&au1xpsc_ac97_dai);
 }
 
 module_init(au1xpsc_ac97_init);
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index 9384702..f916de4 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -116,7 +116,8 @@
 }
 
 static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream,
-				 struct snd_pcm_hw_params *params)
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
 {
 	struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
 
@@ -240,7 +241,8 @@
 	return 0;
 }
 
-static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
 {
 	struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
 	int ret, stype = SUBSTREAM_TYPE(substream);
@@ -337,8 +339,7 @@
 	au1xpsc_i2s_workdata = NULL;
 }
 
-static int au1xpsc_i2s_suspend(struct platform_device *pdev,
-			       struct snd_soc_dai *cpu_dai)
+static int au1xpsc_i2s_suspend(struct snd_soc_dai *cpu_dai)
 {
 	/* save interesting register and disable PSC */
 	au1xpsc_i2s_workdata->pm[0] =
@@ -352,8 +353,7 @@
 	return 0;
 }
 
-static int au1xpsc_i2s_resume(struct platform_device *pdev,
-			      struct snd_soc_dai *cpu_dai)
+static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai)
 {
 	/* select I2S mode and PSC clock */
 	au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
@@ -369,7 +369,6 @@
 
 struct snd_soc_dai au1xpsc_i2s_dai = {
 	.name			= "au1xpsc_i2s",
-	.type			= SND_SOC_DAI_I2S,
 	.probe			= au1xpsc_i2s_probe,
 	.remove			= au1xpsc_i2s_remove,
 	.suspend		= au1xpsc_i2s_suspend,
@@ -389,8 +388,6 @@
 	.ops = {
 		.trigger	= au1xpsc_i2s_trigger,
 		.hw_params	= au1xpsc_i2s_hw_params,
-	},
-	.dai_ops = {
 		.set_fmt	= au1xpsc_i2s_set_fmt,
 	},
 };
@@ -399,11 +396,12 @@
 static int __init au1xpsc_i2s_init(void)
 {
 	au1xpsc_i2s_workdata = NULL;
-	return 0;
+	return snd_soc_register_dai(&au1xpsc_i2s_dai);
 }
 
 static void __exit au1xpsc_i2s_exit(void)
 {
+	snd_soc_unregister_dai(&au1xpsc_i2s_dai);
 }
 
 module_init(au1xpsc_i2s_init);
diff --git a/sound/soc/au1x/sample-ac97.c b/sound/soc/au1x/sample-ac97.c
index f75ae7f..27683eb 100644
--- a/sound/soc/au1x/sample-ac97.c
+++ b/sound/soc/au1x/sample-ac97.c
@@ -42,14 +42,14 @@
 	.ops		= NULL,
 };
 
-static struct snd_soc_machine au1xpsc_sample_ac97_machine = {
+static struct snd_soc_card au1xpsc_sample_ac97_machine = {
 	.name		= "Au1xxx PSC AC97 Audio",
 	.dai_link	= &au1xpsc_sample_ac97_dai,
 	.num_links	= 1,
 };
 
 static struct snd_soc_device au1xpsc_sample_ac97_devdata = {
-	.machine	= &au1xpsc_sample_ac97_machine,
+	.card		= &au1xpsc_sample_ac97_machine,
 	.platform	= &au1xpsc_soc_platform, /* see dbdma2.c */
 	.codec_dev	= &soc_codec_dev_ac97,
 };
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index dc00620..0a2f8f9 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -1,6 +1,6 @@
 config SND_BF5XX_I2S
 	tristate "SoC I2S Audio for the ADI BF5xx chip"
-	depends on BLACKFIN && SND_SOC
+	depends on BLACKFIN
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the Blackfin SPORT (synchronous serial ports) interface in I2S
@@ -13,7 +13,6 @@
 	select SND_BF5XX_SOC_I2S
 	select SND_SOC_SSM2602
 	select I2C
-	select I2C_BLACKFIN_TWI
 	help
 	  Say Y if you want to add support for SoC audio on BF527-EZKIT.
 
@@ -35,7 +34,7 @@
 
 config SND_BF5XX_AC97
 	tristate "SoC AC97 Audio for the ADI BF5xx chip"
-	depends on BLACKFIN && SND_SOC
+	depends on BLACKFIN
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the Blackfin SPORT (synchronous serial ports) interface in slot 16
@@ -47,7 +46,7 @@
 	  properly with this driver. This driver is known to work with the
 	  Analog Devices line of AC97 codecs.
 
-config SND_MMAP_SUPPORT
+config SND_BF5XX_MMAP_SUPPORT
 	bool "Enable MMAP Support"
 	depends on SND_BF5XX_AC97
 	default y
@@ -55,9 +54,17 @@
 	  Say y if you want AC97 driver to support mmap mode.
 	  We introduce an intermediate buffer to simulate mmap.
 
+config SND_BF5XX_MULTICHAN_SUPPORT
+	bool "Enable Multichannel Support"
+	depends on SND_BF5XX_AC97
+	default n
+	help
+	  Say y if you want AC97 driver to support up to 5.1 channel audio.
+	  this mode will consume much more memory for DMA.
+
 config SND_BF5XX_SOC_SPORT
 	tristate
-	
+
 config SND_BF5XX_SOC_I2S
 	tristate
 	select SND_BF5XX_SOC_SPORT
@@ -80,7 +87,7 @@
 	int "Set a SPORT for Sound chip"
 	depends on (SND_BF5XX_I2S || SND_BF5XX_AC97)
 	range 0 3 if BF54x
-	range 0 1 if (BF53x || BF561)
+	range 0 1 if !BF54x
 	default 0
 	help
 	  Set the correct SPORT for sound chip.
@@ -90,12 +97,13 @@
 	depends on SND_BF5XX_AC97
 	default y if BFIN548_EZKIT
 	default n if !BFIN548_EZKIT
-	
+
 config SND_BF5XX_RESET_GPIO_NUM
 	int "Set a GPIO for cold reset"
 	depends on SND_BF5XX_HAVE_COLD_RESET
 	range 0 159
 	default 19 if BFIN548_EZKIT
 	default 5 if BFIN537_STAMP
+	default 0
 	help
 	  Set the correct GPIO for RESET the sound chip.
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 25e50d2..8067cfa 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -43,24 +43,34 @@
 #include "bf5xx-ac97.h"
 #include "bf5xx-sport.h"
 
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+static unsigned int ac97_chan_mask[] = {
+	SP_FL, /* Mono */
+	SP_STEREO, /* Stereo */
+	SP_2DOT1, /* 2.1*/
+	SP_QUAD,/*Quadraquic*/
+	SP_FL | SP_FR | SP_FC | SP_SL | SP_SR,/*5 channels */
+	SP_5DOT1, /* 5.1 */
+};
+
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
 	 snd_pcm_uframes_t count)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct sport_device *sport = runtime->private_data;
+	unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1];
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		bf5xx_pcm_to_ac97(
-			(struct ac97_frame *)sport->tx_dma_buf + sport->tx_pos,
-			(__u32 *)runtime->dma_area + sport->tx_pos, count);
+		bf5xx_pcm_to_ac97((struct ac97_frame *)sport->tx_dma_buf +
+		sport->tx_pos, (__u16 *)runtime->dma_area + sport->tx_pos *
+		runtime->channels, count, chan_mask);
 		sport->tx_pos += runtime->period_size;
 		if (sport->tx_pos >= runtime->buffer_size)
 			sport->tx_pos %= runtime->buffer_size;
 		sport->tx_delay_pos = sport->tx_pos;
 	} else {
-		bf5xx_ac97_to_pcm(
-			(struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos,
-			(__u32 *)runtime->dma_area + sport->rx_pos, count);
+		bf5xx_ac97_to_pcm((struct ac97_frame *)sport->rx_dma_buf +
+		sport->rx_pos, (__u16 *)runtime->dma_area + sport->rx_pos *
+		runtime->channels, count);
 		sport->rx_pos += runtime->period_size;
 		if (sport->rx_pos >= runtime->buffer_size)
 			sport->rx_pos %= runtime->buffer_size;
@@ -71,7 +81,7 @@
 static void bf5xx_dma_irq(void *data)
 {
 	struct snd_pcm_substream *pcm = data;
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 	struct snd_pcm_runtime *runtime = pcm->runtime;
 	struct sport_device *sport = runtime->private_data;
 	bf5xx_mmap_copy(pcm, runtime->period_size);
@@ -90,17 +100,14 @@
  * The total rx/tx buffer is for ac97 frame to hold all pcm data
  * is  0x20000 * sizeof(struct ac97_frame) / 4.
  */
-#ifdef CONFIG_SND_MMAP_SUPPORT
 static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
 	.info			= SNDRV_PCM_INFO_INTERLEAVED |
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 				   SNDRV_PCM_INFO_MMAP |
 				   SNDRV_PCM_INFO_MMAP_VALID |
-				   SNDRV_PCM_INFO_BLOCK_TRANSFER,
-#else
-static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
-	.info			= SNDRV_PCM_INFO_INTERLEAVED |
-				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
 #endif
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER,
+
 	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
 	.period_bytes_min	= 32,
 	.period_bytes_max	= 0x10000,
@@ -123,10 +130,20 @@
 
 static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sport_device *sport = runtime->private_data;
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-	memset(runtime->dma_area, 0, runtime->buffer_size);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		sport->once = 0;
+		if (runtime->dma_area)
+			memset(runtime->dma_area, 0, runtime->buffer_size);
+		memset(sport->tx_dma_buf, 0, runtime->buffer_size *
+			sizeof(struct ac97_frame));
+	} else
+		memset(sport->rx_dma_buf, 0, runtime->buffer_size *
+			sizeof(struct ac97_frame));
+#endif
 	snd_pcm_lib_free_pages(substream);
 	return 0;
 }
@@ -139,7 +156,7 @@
 	/* An intermediate buffer is introduced for implementing mmap for
 	 * SPORT working in TMD mode(include AC97).
 	 */
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
 		sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
@@ -173,24 +190,24 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 			bf5xx_mmap_copy(substream, runtime->period_size);
-			snd_pcm_period_elapsed(substream);
 			sport->tx_delay_pos = 0;
+#endif
 			sport_tx_start(sport);
-		}
-		else
+		} else
 			sport_rx_start(sport);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 			sport->tx_pos = 0;
 #endif
 			sport_tx_stop(sport);
 		} else {
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 			sport->rx_pos = 0;
 #endif
 			sport_rx_stop(sport);
@@ -208,7 +225,7 @@
 	struct sport_device *sport = runtime->private_data;
 	unsigned int curr;
 
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		curr = sport->tx_delay_pos;
 	else
@@ -249,22 +266,7 @@
 	return ret;
 }
 
-static int bf5xx_pcm_close(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct sport_device *sport = runtime->private_data;
-
-	pr_debug("%s enter\n", __func__);
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		sport->once = 0;
-		memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
-	} else
-		memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
-
-	return 0;
-}
-
-#ifdef CONFIG_SND_MMAP_SUPPORT
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
 	struct vm_area_struct *vma)
 {
@@ -281,32 +283,29 @@
 		    void __user *buf, snd_pcm_uframes_t count)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-
+	unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1];
 	pr_debug("%s copy pos:0x%lx count:0x%lx\n",
 			substream->stream ? "Capture" : "Playback", pos, count);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		bf5xx_pcm_to_ac97(
-				(struct ac97_frame *)runtime->dma_area + pos,
-				buf, count);
+		bf5xx_pcm_to_ac97((struct ac97_frame *)runtime->dma_area + pos,
+			(__u16 *)buf, count, chan_mask);
 	else
-		bf5xx_ac97_to_pcm(
-				(struct ac97_frame *)runtime->dma_area + pos,
-				buf, count);
+		bf5xx_ac97_to_pcm((struct ac97_frame *)runtime->dma_area + pos,
+			(__u16 *)buf, count);
 	return 0;
 }
 #endif
 
 struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
 	.open		= bf5xx_pcm_open,
-	.close		= bf5xx_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= bf5xx_pcm_hw_params,
 	.hw_free	= bf5xx_pcm_hw_free,
 	.prepare	= bf5xx_pcm_prepare,
 	.trigger	= bf5xx_pcm_trigger,
 	.pointer	= bf5xx_pcm_pointer,
-#ifdef CONFIG_SND_MMAP_SUPPORT
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 	.mmap		= bf5xx_pcm_mmap,
 #else
 	.copy		= bf5xx_pcm_copy,
@@ -344,7 +343,7 @@
  * Need to allocate local buffer when enable
  * MMAP for SPORT working in TMD mode (include AC97).
  */
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (!sport_handle->tx_dma_buf) {
 			sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \
@@ -381,7 +380,7 @@
 	struct snd_pcm_substream *substream;
 	struct snd_dma_buffer *buf;
 	int stream;
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
 		sizeof(struct ac97_frame) / 4;
 #endif
@@ -395,7 +394,7 @@
 			continue;
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		buf->area = NULL;
-#if defined(CONFIG_SND_MMAP_SUPPORT)
+#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (sport_handle->tx_dma_buf)
 			dma_free_coherent(NULL, size, \
@@ -452,6 +451,18 @@
 };
 EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform);
 
+static int __init bfin_ac97_init(void)
+{
+	return snd_soc_register_platform(&bf5xx_ac97_soc_platform);
+}
+module_init(bfin_ac97_init);
+
+static void __exit bfin_ac97_exit(void)
+{
+	snd_soc_unregister_platform(&bf5xx_ac97_soc_platform);
+}
+module_exit(bfin_ac97_exit);
+
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index 5e5aafb..3be2be6 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -54,71 +54,103 @@
 static int *cmd_count;
 static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
 
-#if defined(CONFIG_BF54x)
+static u16 sport_req[][7] = {
+		PIN_REQ_SPORT_0,
+#ifdef PIN_REQ_SPORT_1
+		PIN_REQ_SPORT_1,
+#endif
+#ifdef PIN_REQ_SPORT_2
+		PIN_REQ_SPORT_2,
+#endif
+#ifdef PIN_REQ_SPORT_3
+		PIN_REQ_SPORT_3,
+#endif
+	};
+
 static struct sport_param sport_params[4] = {
 	{
 		.dma_rx_chan	= CH_SPORT0_RX,
 		.dma_tx_chan	= CH_SPORT0_TX,
-		.err_irq	= IRQ_SPORT0_ERR,
-		.regs		= (struct sport_register *)SPORT0_TCR1,
-	},
-	{
-		.dma_rx_chan	= CH_SPORT1_RX,
-		.dma_tx_chan	= CH_SPORT1_TX,
-		.err_irq	= IRQ_SPORT1_ERR,
-		.regs		= (struct sport_register *)SPORT1_TCR1,
-	},
-	{
-		.dma_rx_chan	= CH_SPORT2_RX,
-		.dma_tx_chan	= CH_SPORT2_TX,
-		.err_irq	= IRQ_SPORT2_ERR,
-		.regs		= (struct sport_register *)SPORT2_TCR1,
-	},
-	{
-		.dma_rx_chan	= CH_SPORT3_RX,
-		.dma_tx_chan	= CH_SPORT3_TX,
-		.err_irq	= IRQ_SPORT3_ERR,
-		.regs		= (struct sport_register *)SPORT3_TCR1,
-	}
-};
-#else
-static struct sport_param sport_params[2] = {
-	{
-		.dma_rx_chan	= CH_SPORT0_RX,
-		.dma_tx_chan	= CH_SPORT0_TX,
 		.err_irq	= IRQ_SPORT0_ERROR,
 		.regs		= (struct sport_register *)SPORT0_TCR1,
 	},
+#ifdef PIN_REQ_SPORT_1
 	{
 		.dma_rx_chan	= CH_SPORT1_RX,
 		.dma_tx_chan	= CH_SPORT1_TX,
 		.err_irq	= IRQ_SPORT1_ERROR,
 		.regs		= (struct sport_register *)SPORT1_TCR1,
-	}
-};
+	},
 #endif
+#ifdef PIN_REQ_SPORT_2
+	{
+		.dma_rx_chan	= CH_SPORT2_RX,
+		.dma_tx_chan	= CH_SPORT2_TX,
+		.err_irq	= IRQ_SPORT2_ERROR,
+		.regs		= (struct sport_register *)SPORT2_TCR1,
+	},
+#endif
+#ifdef PIN_REQ_SPORT_3
+	{
+		.dma_rx_chan	= CH_SPORT3_RX,
+		.dma_tx_chan	= CH_SPORT3_TX,
+		.err_irq	= IRQ_SPORT3_ERROR,
+		.regs		= (struct sport_register *)SPORT3_TCR1,
+	}
+#endif
+};
 
-void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \
-		size_t count)
+void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
+		size_t count, unsigned int chan_mask)
 {
 	while (count--) {
-		dst->ac97_tag = TAG_VALID | TAG_PCM;
-		(dst++)->ac97_pcm = *src++;
+		dst->ac97_tag = TAG_VALID;
+		if (chan_mask & SP_FL) {
+			dst->ac97_pcm_r = *src++;
+			dst->ac97_tag |= TAG_PCM_RIGHT;
+		}
+		if (chan_mask & SP_FR) {
+			dst->ac97_pcm_l = *src++;
+			dst->ac97_tag |= TAG_PCM_LEFT;
+
+		}
+#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
+		if (chan_mask & SP_SR) {
+			dst->ac97_sl = *src++;
+			dst->ac97_tag |= TAG_PCM_SL;
+		}
+		if (chan_mask & SP_SL) {
+			dst->ac97_sr = *src++;
+			dst->ac97_tag |= TAG_PCM_SR;
+		}
+		if (chan_mask & SP_LFE) {
+			dst->ac97_lfe = *src++;
+			dst->ac97_tag |= TAG_PCM_LFE;
+		}
+		if (chan_mask & SP_FC) {
+			dst->ac97_center = *src++;
+			dst->ac97_tag |= TAG_PCM_CENTER;
+		}
+#endif
+		dst++;
 	}
 }
 EXPORT_SYMBOL(bf5xx_pcm_to_ac97);
 
-void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \
+void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst,
 		size_t count)
 {
-	while (count--)
-		*(dst++) = (src++)->ac97_pcm;
+	while (count--) {
+		*(dst++) = src->ac97_pcm_l;
+		*(dst++) = src->ac97_pcm_r;
+		src++;
+	}
 }
 EXPORT_SYMBOL(bf5xx_ac97_to_pcm);
 
 static unsigned int sport_tx_curr_frag(struct sport_device *sport)
 {
-	return sport->tx_curr_frag = sport_curr_offset_tx(sport) / \
+	return sport->tx_curr_frag = sport_curr_offset_tx(sport) /
 			sport->tx_fragsize;
 }
 
@@ -130,7 +162,7 @@
 
 	sport_incfrag(sport, &nextfrag, 1);
 
-	nextwrite = (struct ac97_frame *)(sport->tx_buf + \
+	nextwrite = (struct ac97_frame *)(sport->tx_buf +
 			nextfrag * sport->tx_fragsize);
 	pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n",
 		sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]);
@@ -237,8 +269,7 @@
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 #ifdef CONFIG_PM
-static int bf5xx_ac97_suspend(struct platform_device *pdev,
-	struct snd_soc_dai *dai)
+static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
 {
 	struct sport_device *sport =
 		(struct sport_device *)dai->private_data;
@@ -253,8 +284,7 @@
 	return 0;
 }
 
-static int bf5xx_ac97_resume(struct platform_device *pdev,
-	struct snd_soc_dai *dai)
+static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 {
 	int ret;
 	struct sport_device *sport =
@@ -297,20 +327,15 @@
 static int bf5xx_ac97_probe(struct platform_device *pdev,
 			    struct snd_soc_dai *dai)
 {
-	int ret;
-#if defined(CONFIG_BF54x)
-	u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1,
-				 PIN_REQ_SPORT_2, PIN_REQ_SPORT_3};
-#else
-	u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1};
-#endif
+	int ret = 0;
 	cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
 	if (cmd_count == NULL)
 		return -ENOMEM;
 
 	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
 		pr_err("Requesting Peripherals failed\n");
-		return -EFAULT;
+		ret =  -EFAULT;
+		goto peripheral_err;
 		}
 
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
@@ -318,54 +343,54 @@
 	if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) {
 		pr_err("Failed to request GPIO_%d for reset\n",
 				CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-		peripheral_free_list(&sport_req[sport_num][0]);
-		return -1;
+		ret =  -1;
+		goto gpio_err;
 	}
 	gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
 #endif
 	sport_handle = sport_init(&sport_params[sport_num], 2, \
 			sizeof(struct ac97_frame), NULL);
 	if (!sport_handle) {
-		peripheral_free_list(&sport_req[sport_num][0]);
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
-		gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
-		return -ENODEV;
+		ret = -ENODEV;
+		goto sport_err;
 	}
 	/*SPORT works in TDM mode to simulate AC97 transfers*/
 	ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1);
 	if (ret) {
 		pr_err("SPORT is busy!\n");
-		kfree(sport_handle);
-		peripheral_free_list(&sport_req[sport_num][0]);
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
-		gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
-		return -EBUSY;
+		ret = -EBUSY;
+		goto sport_config_err;
 	}
 
 	ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
 	if (ret) {
 		pr_err("SPORT is busy!\n");
-		kfree(sport_handle);
-		peripheral_free_list(&sport_req[sport_num][0]);
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
-		gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
-		return -EBUSY;
+		ret = -EBUSY;
+		goto sport_config_err;
 	}
 
 	ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
 	if (ret) {
 		pr_err("SPORT is busy!\n");
-		kfree(sport_handle);
-		peripheral_free_list(&sport_req[sport_num][0]);
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
-		gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
-		return -EBUSY;
+		ret = -EBUSY;
+		goto sport_config_err;
 	}
+
 	return 0;
+
+sport_config_err:
+	kfree(sport_handle);
+sport_err:
+#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
+	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
+#endif
+gpio_err:
+	peripheral_free_list(&sport_req[sport_num][0]);
+peripheral_err:
+	free_page((unsigned long)cmd_count);
+	cmd_count = NULL;
+
+	return ret;
 }
 
 static void bf5xx_ac97_remove(struct platform_device *pdev,
@@ -373,6 +398,7 @@
 {
 	free_page((unsigned long)cmd_count);
 	cmd_count = NULL;
+	peripheral_free_list(&sport_req[sport_num][0]);
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 #endif
@@ -381,7 +407,7 @@
 struct snd_soc_dai bfin_ac97_dai = {
 	.name = "bf5xx-ac97",
 	.id = 0,
-	.type = SND_SOC_DAI_AC97,
+	.ac97_control = 1,
 	.probe = bf5xx_ac97_probe,
 	.remove = bf5xx_ac97_remove,
 	.suspend = bf5xx_ac97_suspend,
@@ -389,7 +415,11 @@
 	.playback = {
 		.stream_name = "AC97 Playback",
 		.channels_min = 2,
+#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
+		.channels_max = 6,
+#else
 		.channels_max = 2,
+#endif
 		.rates = SNDRV_PCM_RATE_48000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
 	.capture = {
@@ -401,6 +431,18 @@
 };
 EXPORT_SYMBOL_GPL(bfin_ac97_dai);
 
+static int __init bfin_ac97_init(void)
+{
+	return snd_soc_register_dai(&bfin_ac97_dai);
+}
+module_init(bfin_ac97_init);
+
+static void __exit bfin_ac97_exit(void)
+{
+	snd_soc_unregister_dai(&bfin_ac97_dai);
+}
+module_exit(bfin_ac97_exit);
+
 MODULE_AUTHOR("Roy Huang");
 MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h
index 3f77cc5..3f2a911 100644
--- a/sound/soc/blackfin/bf5xx-ac97.h
+++ b/sound/soc/blackfin/bf5xx-ac97.h
@@ -16,21 +16,46 @@
 	u16 ac97_tag;		/* slot 0 */
 	u16 ac97_addr;		/* slot 1 */
 	u16 ac97_data;		/* slot 2 */
-	u32 ac97_pcm;		/* slot 3 and 4: left and right pcm data */
+	u16 ac97_pcm_l;		/*slot 3:front left*/
+	u16 ac97_pcm_r;		/*slot 4:front left*/
+#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
+	u16 ac97_mdm_l1;
+	u16 ac97_center;	/*slot 6:center*/
+	u16 ac97_sl;		/*slot 7:surround left*/
+	u16 ac97_sr;		/*slot 8:surround right*/
+	u16 ac97_lfe;		/*slot 9:lfe*/
+#endif
 } __attribute__ ((packed));
 
+/* Speaker location */
+#define SP_FL		0x0001
+#define SP_FR		0x0010
+#define SP_FC		0x0002
+#define SP_LFE		0x0020
+#define SP_SL		0x0004
+#define SP_SR		0x0040
+
+#define SP_STEREO	(SP_FL | SP_FR)
+#define SP_2DOT1	(SP_FL | SP_FR | SP_LFE)
+#define SP_QUAD		(SP_FL | SP_FR | SP_SL | SP_SR)
+#define SP_5DOT1	(SP_FL | SP_FR | SP_FC | SP_LFE | SP_SL | SP_SR)
+
 #define TAG_VALID		0x8000
 #define TAG_CMD			0x6000
 #define TAG_PCM_LEFT		0x1000
 #define TAG_PCM_RIGHT		0x0800
-#define TAG_PCM			(TAG_PCM_LEFT | TAG_PCM_RIGHT)
+#define TAG_PCM_MDM_L1		0x0400
+#define TAG_PCM_CENTER		0x0200
+#define TAG_PCM_SL		0x0100
+#define TAG_PCM_SR		0x0080
+#define TAG_PCM_LFE		0x0040
 
 extern struct snd_soc_dai bfin_ac97_dai;
 
-void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \
-		size_t count);
+void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
+		size_t count, unsigned int chan_mask);
 
-void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \
+void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, \
 		size_t count);
 
 #endif
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c
index 124425d..d8f5912 100644
--- a/sound/soc/blackfin/bf5xx-ad1980.c
+++ b/sound/soc/blackfin/bf5xx-ad1980.c
@@ -43,7 +43,7 @@
 #include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97.h"
 
-static struct snd_soc_machine bf5xx_board;
+static struct snd_soc_card bf5xx_board;
 
 static int bf5xx_board_startup(struct snd_pcm_substream *substream)
 {
@@ -67,15 +67,15 @@
 	.ops = &bf5xx_board_ops,
 };
 
-static struct snd_soc_machine bf5xx_board = {
+static struct snd_soc_card bf5xx_board = {
 	.name = "bf5xx-board",
+	.platform = &bf5xx_ac97_soc_platform,
 	.dai_link = &bf5xx_board_dai,
 	.num_links = 1,
 };
 
 static struct snd_soc_device bf5xx_board_snd_devdata = {
-	.machine = &bf5xx_board,
-	.platform = &bf5xx_ac97_soc_platform,
+	.card = &bf5xx_board,
 	.codec_dev = &soc_codec_dev_ad1980,
 };
 
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
index 622c9b9..7f2a5e1 100644
--- a/sound/soc/blackfin/bf5xx-ad73311.c
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -65,7 +65,7 @@
 
 #define GPIO_SE CONFIG_SND_BFIN_AD73311_SE
 
-static struct snd_soc_machine bf5xx_ad73311;
+static struct snd_soc_card bf5xx_ad73311;
 
 static int snd_ad73311_startup(void)
 {
@@ -168,7 +168,7 @@
 		params_format(params));
 
 	/* set cpu DAI configuration */
-	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
 		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
 	if (ret < 0)
 		return ret;
@@ -190,16 +190,16 @@
 	.ops = &bf5xx_ad73311_ops,
 };
 
-static struct snd_soc_machine bf5xx_ad73311 = {
+static struct snd_soc_card bf5xx_ad73311 = {
 	.name = "bf5xx_ad73311",
+	.platform = &bf5xx_i2s_soc_platform,
 	.probe = bf5xx_probe,
 	.dai_link = &bf5xx_ad73311_dai,
 	.num_links = 1,
 };
 
 static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
-	.machine = &bf5xx_ad73311,
-	.platform = &bf5xx_i2s_soc_platform,
+	.card = &bf5xx_ad73311,
 	.codec_dev = &soc_codec_dev_ad73311,
 };
 
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index 61fccf9..53d290b 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -283,6 +283,18 @@
 };
 EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform);
 
+static int __init bfin_i2s_init(void)
+{
+	return snd_soc_register_platform(&bf5xx_i2s_soc_platform);
+}
+module_init(bfin_i2s_init);
+
+static void __exit bfin_i2s_exit(void)
+{
+	snd_soc_unregister_platform(&bf5xx_i2s_soc_platform);
+}
+module_exit(bfin_i2s_exit);
+
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index e020c16..d1d95d2 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -132,7 +132,8 @@
 	return ret;
 }
 
-static int bf5xx_i2s_startup(struct snd_pcm_substream *substream)
+static int bf5xx_i2s_startup(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
 {
 	pr_debug("%s enter\n", __func__);
 
@@ -142,7 +143,8 @@
 }
 
 static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
 {
 	int ret = 0;
 
@@ -193,7 +195,8 @@
 	return 0;
 }
 
-static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream)
+static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
 {
 	pr_debug("%s enter\n", __func__);
 	bf5xx_i2s.counter--;
@@ -219,16 +222,14 @@
 	return 0;
 }
 
-static void bf5xx_i2s_remove(struct platform_device *pdev,
-			   struct snd_soc_dai *dai)
+static void bf5xx_i2s_remove(struct snd_soc_dai *dai)
 {
 	pr_debug("%s enter\n", __func__);
 	peripheral_free_list(&sport_req[sport_num][0]);
 }
 
 #ifdef CONFIG_PM
-static int bf5xx_i2s_suspend(struct platform_device *dev,
-			     struct snd_soc_dai *dai)
+static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 {
 	struct sport_device *sport =
 		(struct sport_device *)dai->private_data;
@@ -289,7 +290,6 @@
 struct snd_soc_dai bf5xx_i2s_dai = {
 	.name = "bf5xx-i2s",
 	.id = 0,
-	.type = SND_SOC_DAI_I2S,
 	.probe = bf5xx_i2s_probe,
 	.remove = bf5xx_i2s_remove,
 	.suspend = bf5xx_i2s_suspend,
@@ -307,13 +307,24 @@
 	.ops = {
 		.startup   = bf5xx_i2s_startup,
 		.shutdown  = bf5xx_i2s_shutdown,
-		.hw_params = bf5xx_i2s_hw_params,},
-	.dai_ops = {
+		.hw_params = bf5xx_i2s_hw_params,
 		.set_fmt = bf5xx_i2s_set_dai_fmt,
 	},
 };
 EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
 
+static int __init bfin_i2s_init(void)
+{
+	return snd_soc_register_dai(&bf5xx_i2s_dai);
+}
+module_init(bfin_i2s_init);
+
+static void __exit bfin_i2s_exit(void)
+{
+	snd_soc_unregister_dai(&bf5xx_i2s_dai);
+}
+module_exit(bfin_i2s_exit);
+
 /* Module information */
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("I2S driver for ADI Blackfin");
diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h
index fcadcc0..2e63dea 100644
--- a/sound/soc/blackfin/bf5xx-sport.h
+++ b/sound/soc/blackfin/bf5xx-sport.h
@@ -116,7 +116,7 @@
 	void *err_data;
 	unsigned char *tx_dma_buf;
 	unsigned char *rx_dma_buf;
-#ifdef CONFIG_SND_MMAP_SUPPORT
+#ifdef CONFIG_SND_BF5XX_MMAP_SUPPORT
 	dma_addr_t tx_dma_phy;
 	dma_addr_t rx_dma_phy;
 	int tx_pos;/*pcm sample count*/
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c
index e15f67f..bc0cdde 100644
--- a/sound/soc/blackfin/bf5xx-ssm2602.c
+++ b/sound/soc/blackfin/bf5xx-ssm2602.c
@@ -44,7 +44,7 @@
 #include "bf5xx-i2s-pcm.h"
 #include "bf5xx-i2s.h"
 
-static struct snd_soc_machine bf5xx_ssm2602;
+static struct snd_soc_card bf5xx_ssm2602;
 
 static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
 {
@@ -92,17 +92,17 @@
 	 */
 
 	/* set codec DAI configuration */
-	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
 		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
 	if (ret < 0)
 		return ret;
 	/* set cpu DAI configuration */
-	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
 		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
 	if (ret < 0)
 		return ret;
 
-	ret = codec_dai->dai_ops.set_sysclk(codec_dai, SSM2602_SYSCLK, clk,
+	ret = snd_soc_dai_set_sysclk(codec_dai, SSM2602_SYSCLK, clk,
 		SND_SOC_CLOCK_IN);
 	if (ret < 0)
 		return ret;
@@ -135,15 +135,15 @@
 	.i2c_address = 0x1b,
 };
 
-static struct snd_soc_machine bf5xx_ssm2602 = {
+static struct snd_soc_card bf5xx_ssm2602 = {
 	.name = "bf5xx_ssm2602",
+	.platform = &bf5xx_i2s_soc_platform,
 	.dai_link = &bf5xx_ssm2602_dai,
 	.num_links = 1,
 };
 
 static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
-	.machine = &bf5xx_ssm2602,
-	.platform = &bf5xx_i2s_soc_platform,
+	.card = &bf5xx_ssm2602,
 	.codec_dev = &soc_codec_dev_ssm2602,
 	.codec_data = &bf5xx_ssm2602_setup,
 };
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 38a0e3b..c41289b 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1,31 +1,40 @@
 config SND_SOC_ALL_CODECS
 	tristate "Build all ASoC CODEC drivers"
-	depends on I2C
-	select SPI
-	select SPI_MASTER
-	select SND_SOC_AD73311
-	select SND_SOC_AK4535
-	select SND_SOC_CS4270
-	select SND_SOC_SSM2602
-	select SND_SOC_TLV320AIC23
-	select SND_SOC_TLV320AIC26
-	select SND_SOC_TLV320AIC3X
-	select SND_SOC_UDA1380
-	select SND_SOC_WM8510
-	select SND_SOC_WM8580
-	select SND_SOC_WM8731
-	select SND_SOC_WM8750
-	select SND_SOC_WM8753
-	select SND_SOC_WM8900
-	select SND_SOC_WM8903
-	select SND_SOC_WM8971
-	select SND_SOC_WM8990
+	select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
+	select SND_SOC_AD1980 if SND_SOC_AC97_BUS
+	select SND_SOC_AD73311 if I2C
+	select SND_SOC_AK4535 if I2C
+	select SND_SOC_CS4270 if I2C
+	select SND_SOC_PCM3008
+	select SND_SOC_SSM2602 if I2C
+	select SND_SOC_TLV320AIC23 if I2C
+	select SND_SOC_TLV320AIC26 if SPI_MASTER
+	select SND_SOC_TLV320AIC3X if I2C
+	select SND_SOC_TWL4030 if TWL4030_CORE
+	select SND_SOC_UDA134X
+	select SND_SOC_UDA1380 if I2C
+	select SND_SOC_WM8350 if MFD_WM8350
+	select SND_SOC_WM8510 if (I2C || SPI_MASTER)
+	select SND_SOC_WM8580 if I2C
+	select SND_SOC_WM8728 if (I2C || SPI_MASTER)
+	select SND_SOC_WM8731 if (I2C || SPI_MASTER)
+	select SND_SOC_WM8750 if (I2C || SPI_MASTER)
+	select SND_SOC_WM8753 if (I2C || SPI_MASTER)
+	select SND_SOC_WM8900 if I2C
+	select SND_SOC_WM8903 if I2C
+	select SND_SOC_WM8971 if I2C
+	select SND_SOC_WM8990 if I2C
+	select SND_SOC_WM9712 if SND_SOC_AC97_BUS
+	select SND_SOC_WM9713 if SND_SOC_AC97_BUS
         help
           Normally ASoC codec drivers are only built if a machine driver which
           uses them is also built since they are only usable with a machine
           driver.  Selecting this option will allow these drivers to be built
           without an explicit machine driver for test and development purposes.
 
+	  Support for the bus types used to access the codecs to be built must
+	  be selected separately.
+
           If unsure select "N".
 
 
@@ -60,6 +69,12 @@
 	bool
 	depends on SND_SOC_CS4270
 
+config SND_SOC_L3
+       tristate
+
+config SND_SOC_PCM3008
+       tristate
+
 config SND_SOC_SSM2602
 	tristate
 
@@ -75,15 +90,29 @@
 	tristate
 	depends on I2C
 
+config SND_SOC_TWL4030
+	tristate
+	depends on TWL4030_CORE
+
+config SND_SOC_UDA134X
+       tristate
+       select SND_SOC_L3
+
 config SND_SOC_UDA1380
         tristate
 
+config SND_SOC_WM8350
+	tristate
+
 config SND_SOC_WM8510
 	tristate
 
 config SND_SOC_WM8580
 	tristate
 
+config SND_SOC_WM8728
+	tristate
+
 config SND_SOC_WM8731
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 90f0a58..c4ddc9a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -3,13 +3,19 @@
 snd-soc-ad73311-objs := ad73311.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-cs4270-objs := cs4270.o
+snd-soc-l3-objs := l3.o
+snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-twl4030-objs := twl4030.o
+snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
+snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8510-objs := wm8510.o
 snd-soc-wm8580-objs := wm8580.o
+snd-soc-wm8728-objs := wm8728.o
 snd-soc-wm8731-objs := wm8731.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
@@ -25,13 +31,19 @@
 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
 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_SSM2602)	+= snd-soc-ssm2602.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
+obj-$(CONFIG_SND_SOC_TWL4030)	+= snd-soc-twl4030.o
+obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8510)	+= snd-soc-wm8510.o
 obj-$(CONFIG_SND_SOC_WM8580)	+= snd-soc-wm8580.o
+obj-$(CONFIG_SND_SOC_WM8728)	+= snd-soc-wm8728.o
 obj-$(CONFIG_SND_SOC_WM8731)	+= snd-soc-wm8731.o
 obj-$(CONFIG_SND_SOC_WM8750)	+= snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)	+= snd-soc-wm8753.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index bd1ebdc..fb53e65 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -24,7 +24,8 @@
 
 #define AC97_VERSION "0.6"
 
-static int ac97_prepare(struct snd_pcm_substream *substream)
+static int ac97_prepare(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -42,7 +43,7 @@
 
 struct snd_soc_dai ac97_dai = {
 	.name = "AC97 HiFi",
-	.type = SND_SOC_DAI_AC97,
+	.ac97_control = 1,
 	.playback = {
 		.stream_name = "AC97 Playback",
 		.channels_min = 1,
@@ -113,7 +114,7 @@
 	if (ret < 0)
 		goto bus_err;
 
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0)
 		goto bus_err;
 	return 0;
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 1397b8e..73fdbb4 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -85,6 +85,9 @@
 SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
 SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1),
 
+SOC_DOUBLE("Center/LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 0, 31, 1),
+SOC_DOUBLE("Center/LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 7, 1, 1),
+
 SOC_ENUM("Capture Source", ad1980_cap_src),
 
 SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0),
@@ -142,10 +145,11 @@
 
 struct snd_soc_dai ad1980_dai = {
 	.name = "AC97",
+	.ac97_control = 1,
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 2,
-		.channels_max = 2,
+		.channels_max = 6,
 		.rates = SNDRV_PCM_RATE_48000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
 	.capture = {
@@ -192,6 +196,7 @@
 	struct snd_soc_codec *codec;
 	int ret = 0;
 	u16 vendor_id2;
+	u16 ext_status;
 
 	printk(KERN_INFO "AD1980 SoC Audio Codec\n");
 
@@ -234,7 +239,7 @@
 
 	ret = ad1980_reset(codec, 0);
 	if (ret < 0) {
-		printk(KERN_ERR "AC97 link error\n");
+		printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
 		goto reset_err;
 	}
 
@@ -253,12 +258,19 @@
 				"supported\n");
 	}
 
-	ac97_write(codec, AC97_MASTER, 0x0000); /* unmute line out volume */
-	ac97_write(codec, AC97_PCM, 0x0000);	/* unmute PCM out volume */
-	ac97_write(codec, AC97_REC_GAIN, 0x0000);/* unmute record volume */
+	/* unmute captures and playbacks volume */
+	ac97_write(codec, AC97_MASTER, 0x0000);
+	ac97_write(codec, AC97_PCM, 0x0000);
+	ac97_write(codec, AC97_REC_GAIN, 0x0000);
+	ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
+	ac97_write(codec, AC97_SURROUND_MASTER, 0x0000);
+
+	/*power on LFE/CENTER/Surround DACs*/
+	ext_status = ac97_read(codec, AC97_EXTENDED_STATUS);
+	ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
 
 	ad1980_add_controls(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "ad1980: failed to register card\n");
 		goto reset_err;
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index 37af860..b09289a 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -8,14 +8,10 @@
  *  under  the terms of  the GNU General  Public License as published by the
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
- *
- *  Revision history
- *    25th Sep 2008   Initial version.
  */
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <sound/core.h>
@@ -68,7 +64,7 @@
 		goto pcm_err;
 	}
 
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "ad73311: failed to register card\n");
 		goto register_err;
@@ -102,6 +98,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
 
+static int __init ad73311_init(void)
+{
+	return snd_soc_register_dai(&ad73311_dai);
+}
+module_init(ad73311_init);
+
+static void __exit ad73311_exit(void)
+{
+	snd_soc_unregister_dai(&ad73311_dai);
+}
+module_exit(ad73311_exit);
+
 MODULE_DESCRIPTION("ASoC ad73311 driver");
 MODULE_AUTHOR("Cliff Cai ");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 2a89b58..81300d8 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -339,7 +339,8 @@
 }
 
 static int ak4535_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+			    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;
@@ -451,8 +452,6 @@
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
 	.ops = {
 		.hw_params = ak4535_hw_params,
-	},
-	.dai_ops = {
 		.set_fmt = ak4535_set_dai_fmt,
 		.digital_mute = ak4535_mute,
 		.set_sysclk = ak4535_set_dai_sysclk,
@@ -513,7 +512,7 @@
 
 	ak4535_add_controls(codec);
 	ak4535_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "ak4535: failed to register card\n");
 		goto card_err;
@@ -689,6 +688,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535);
 
+static int __init ak4535_modinit(void)
+{
+	return snd_soc_register_dai(&ak4535_dai);
+}
+module_init(ak4535_modinit);
+
+static void __exit ak4535_exit(void)
+{
+	snd_soc_unregister_dai(&ak4535_dai);
+}
+module_exit(ak4535_exit);
+
 MODULE_DESCRIPTION("Soc AK4535 driver");
 MODULE_AUTHOR("Richard Purdie");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 0bbd945..f1aa0c3 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -360,13 +360,14 @@
 /*
  * Program the CS4270 with the given hardware parameters.
  *
- * The .dai_ops functions are used to provide board-specific data, like
+ * The .ops functions are used to provide board-specific data, like
  * input frequencies, to this driver.  This function takes that information,
  * combines it with the hardware parameters provided, and programs the
  * hardware accordingly.
  */
 static int cs4270_hw_params(struct snd_pcm_substream *substream,
-			    struct snd_pcm_hw_params *params)
+			    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;
@@ -450,6 +451,19 @@
 		return ret;
 	}
 
+	/* Disable automatic volume control.  It's enabled by default, and
+	 * it causes volume change commands to be delayed, sometimes until
+	 * after playback has started.
+	 */
+
+	reg = cs4270_read_reg_cache(codec, CS4270_TRANS);
+	reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
+	ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
+	if (ret < 0) {
+		printk(KERN_ERR "I2C write failed\n");
+		return ret;
+	}
+
 	/* Thaw and power-up the codec */
 
 	ret = snd_soc_write(codec, CS4270_PWRCTL, 0);
@@ -697,10 +711,10 @@
 	if (codec->control_data) {
 		/* Initialize codec ops */
 		cs4270_dai.ops.hw_params = cs4270_hw_params;
-		cs4270_dai.dai_ops.set_sysclk = cs4270_set_dai_sysclk;
-		cs4270_dai.dai_ops.set_fmt = cs4270_set_dai_fmt;
+		cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk;
+		cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt;
 #ifdef CONFIG_SND_SOC_CS4270_HWMUTE
-		cs4270_dai.dai_ops.digital_mute = cs4270_mute;
+		cs4270_dai.ops.digital_mute = cs4270_mute;
 #endif
 	} else
 		printk(KERN_INFO "cs4270: no I2C device found, "
@@ -709,7 +723,7 @@
 	printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n");
 #endif
 
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "cs4270: failed to register card\n");
 		goto error_del_driver;
@@ -760,6 +774,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
 
+static int __init cs4270_init(void)
+{
+	return snd_soc_register_dai(&cs4270_dai);
+}
+module_init(cs4270_init);
+
+static void __exit cs4270_exit(void)
+{
+	snd_soc_unregister_dai(&cs4270_dai);
+}
+module_exit(cs4270_exit);
+
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c
new file mode 100644
index 0000000..5353af5
--- /dev/null
+++ b/sound/soc/codecs/l3.c
@@ -0,0 +1,91 @@
+/*
+ * L3 code
+ *
+ *  Copyright (C) 2008, Christian Pellegrin <chripell@evolware.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.
+ *
+ *
+ * based on:
+ *
+ * L3 bus algorithm module.
+ *
+ *  Copyright (C) 2001 Russell King, All Rights Reserved.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <sound/l3.h>
+
+/*
+ * Send one byte of data to the chip.  Data is latched into the chip on
+ * the rising edge of the clock.
+ */
+static void sendbyte(struct l3_pins *adap, unsigned int byte)
+{
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		adap->setclk(0);
+		udelay(adap->data_hold);
+		adap->setdat(byte & 1);
+		udelay(adap->data_setup);
+		adap->setclk(1);
+		udelay(adap->clock_high);
+		byte >>= 1;
+	}
+}
+
+/*
+ * Send a set of bytes to the chip.  We need to pulse the MODE line
+ * between each byte, but never at the start nor at the end of the
+ * transfer.
+ */
+static void sendbytes(struct l3_pins *adap, const u8 *buf,
+		      int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++) {
+		if (i) {
+			udelay(adap->mode_hold);
+			adap->setmode(0);
+			udelay(adap->mode);
+		}
+		adap->setmode(1);
+		udelay(adap->mode_setup);
+		sendbyte(adap, buf[i]);
+	}
+}
+
+int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len)
+{
+	adap->setclk(1);
+	adap->setdat(1);
+	adap->setmode(1);
+	udelay(adap->mode);
+
+	adap->setmode(0);
+	udelay(adap->mode_setup);
+	sendbyte(adap, addr);
+	udelay(adap->mode_hold);
+
+	sendbytes(adap, data, len);
+
+	adap->setclk(1);
+	adap->setdat(1);
+	adap->setmode(0);
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(l3_write);
+
+MODULE_DESCRIPTION("L3 bit-banging driver");
+MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
new file mode 100644
index 0000000..9a3e67e
--- /dev/null
+++ b/sound/soc/codecs/pcm3008.c
@@ -0,0 +1,212 @@
+/*
+ * ALSA Soc PCM3008 codec support
+ *
+ * Author:	Hugo Villeneuve
+ * Copyright (C) 2008 Lyrtech inc
+ *
+ * Based on AC97 Soc codec, original copyright follow:
+ * Copyright 2005 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 as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ * Generic PCM3008 support.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "pcm3008.h"
+
+#define PCM3008_VERSION "0.2"
+
+#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |	\
+		       SNDRV_PCM_RATE_48000)
+
+struct snd_soc_dai pcm3008_dai = {
+	.name = "PCM3008 HiFi",
+	.playback = {
+		.stream_name = "PCM3008 Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = PCM3008_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "PCM3008 Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = PCM3008_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+};
+EXPORT_SYMBOL_GPL(pcm3008_dai);
+
+static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
+{
+	gpio_free(setup->dem0_pin);
+	gpio_free(setup->dem1_pin);
+	gpio_free(setup->pdad_pin);
+	gpio_free(setup->pdda_pin);
+}
+
+static int pcm3008_soc_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	struct pcm3008_setup_data *setup = socdev->codec_data;
+	int ret = 0;
+
+	printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
+
+	socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (!socdev->codec)
+		return -ENOMEM;
+
+	codec = socdev->codec;
+	mutex_init(&codec->mutex);
+
+	codec->name = "PCM3008";
+	codec->owner = THIS_MODULE;
+	codec->dai = &pcm3008_dai;
+	codec->num_dai = 1;
+	codec->write = NULL;
+	codec->read = NULL;
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	/* Register PCMs. */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "pcm3008: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	/* Register Card. */
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "pcm3008: failed to register card\n");
+		goto card_err;
+	}
+
+	/* DEM1  DEM0  DE-EMPHASIS_MODE
+	 * Low   Low   De-emphasis 44.1 kHz ON
+	 * Low   High  De-emphasis OFF
+	 * High  Low   De-emphasis 48 kHz ON
+	 * High  High  De-emphasis 32 kHz ON
+	 */
+
+	/* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
+	ret = gpio_request(setup->dem0_pin, "codec_dem0");
+	if (ret == 0)
+		ret = gpio_direction_output(setup->dem0_pin, 1);
+	if (ret != 0)
+		goto gpio_err;
+
+	/* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
+	ret = gpio_request(setup->dem1_pin, "codec_dem1");
+	if (ret == 0)
+		ret = gpio_direction_output(setup->dem1_pin, 0);
+	if (ret != 0)
+		goto gpio_err;
+
+	/* Configure PDAD GPIO. */
+	ret = gpio_request(setup->pdad_pin, "codec_pdad");
+	if (ret == 0)
+		ret = gpio_direction_output(setup->pdad_pin, 1);
+	if (ret != 0)
+		goto gpio_err;
+
+	/* Configure PDDA GPIO. */
+	ret = gpio_request(setup->pdda_pin, "codec_pdda");
+	if (ret == 0)
+		ret = gpio_direction_output(setup->pdda_pin, 1);
+	if (ret != 0)
+		goto gpio_err;
+
+	return ret;
+
+gpio_err:
+	pcm3008_gpio_free(setup);
+card_err:
+	snd_soc_free_pcms(socdev);
+pcm_err:
+	kfree(socdev->codec);
+
+	return ret;
+}
+
+static int pcm3008_soc_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	struct pcm3008_setup_data *setup = socdev->codec_data;
+
+	if (!codec)
+		return 0;
+
+	pcm3008_gpio_free(setup);
+	snd_soc_free_pcms(socdev);
+	kfree(socdev->codec);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct pcm3008_setup_data *setup = socdev->codec_data;
+
+	gpio_set_value(setup->pdad_pin, 0);
+	gpio_set_value(setup->pdda_pin, 0);
+
+	return 0;
+}
+
+static int pcm3008_soc_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct pcm3008_setup_data *setup = socdev->codec_data;
+
+	gpio_set_value(setup->pdad_pin, 1);
+	gpio_set_value(setup->pdda_pin, 1);
+
+	return 0;
+}
+#else
+#define pcm3008_soc_suspend NULL
+#define pcm3008_soc_resume NULL
+#endif
+
+struct snd_soc_codec_device soc_codec_dev_pcm3008 = {
+	.probe = 	pcm3008_soc_probe,
+	.remove = 	pcm3008_soc_remove,
+	.suspend =	pcm3008_soc_suspend,
+	.resume =	pcm3008_soc_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008);
+
+static int __init pcm3008_init(void)
+{
+	return snd_soc_register_dai(&pcm3008_dai);
+}
+module_init(pcm3008_init);
+
+static void __exit pcm3008_exit(void)
+{
+	snd_soc_unregister_dai(&pcm3008_dai);
+}
+module_exit(pcm3008_exit);
+
+MODULE_DESCRIPTION("Soc PCM3008 driver");
+MODULE_AUTHOR("Hugo Villeneuve");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm3008.h b/sound/soc/codecs/pcm3008.h
new file mode 100644
index 0000000..d04e87d
--- /dev/null
+++ b/sound/soc/codecs/pcm3008.h
@@ -0,0 +1,25 @@
+/*
+ * PCM3008 ALSA SoC Layer
+ *
+ * Author:	Hugo Villeneuve
+ * Copyright (C) 2008 Lyrtech inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_SOC_PCM3008_H
+#define __LINUX_SND_SOC_PCM3008_H
+
+struct pcm3008_setup_data {
+	unsigned dem0_pin;
+	unsigned dem1_pin;
+	unsigned pdad_pin;
+	unsigned pdda_pin;
+};
+
+extern struct snd_soc_codec_device soc_codec_dev_pcm3008;
+extern struct snd_soc_dai pcm3008_dai;
+
+#endif
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 44ef0da..cac3736 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -285,16 +285,23 @@
 }
 
 static int ssm2602_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
 {
 	u16 srate;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->codec;
 	struct ssm2602_priv *ssm2602 = codec->private_data;
+	struct i2c_client *i2c = codec->control_data;
 	u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
 	int i = get_coeff(ssm2602->sysclk, params_rate(params));
 
+	if (substream == ssm2602->slave_substream) {
+		dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+		return 0;
+	}
+
 	/*no match is found*/
 	if (i == ARRAY_SIZE(coeff_div))
 		return -EINVAL;
@@ -324,19 +331,26 @@
 	return 0;
 }
 
-static int ssm2602_startup(struct snd_pcm_substream *substream)
+static int ssm2602_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->codec;
 	struct ssm2602_priv *ssm2602 = codec->private_data;
+	struct i2c_client *i2c = codec->control_data;
 	struct snd_pcm_runtime *master_runtime;
 
 	/* The DAI has shared clocks so if we already have a playback or
 	 * capture going then constrain this substream to match it.
+	 * TODO: the ssm2602 allows pairs of non-matching PB/REC rates
 	 */
 	if (ssm2602->master_substream) {
 		master_runtime = ssm2602->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,
@@ -354,7 +368,8 @@
 	return 0;
 }
 
-static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream)
+static int ssm2602_pcm_prepare(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;
@@ -365,14 +380,21 @@
 	return 0;
 }
 
-static void ssm2602_shutdown(struct snd_pcm_substream *substream)
+static void ssm2602_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->codec;
+	struct ssm2602_priv *ssm2602 = codec->private_data;
 	/* deactivate */
 	if (!codec->active)
 		ssm2602_write(codec, SSM2602_ACTIVE, 0);
+
+	if (ssm2602->master_substream == substream)
+		ssm2602->master_substream = ssm2602->slave_substream;
+
+	ssm2602->slave_substream = NULL;
 }
 
 static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
@@ -432,10 +454,10 @@
 		iface |= 0x0001;
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
-		iface |= 0x0003;
+		iface |= 0x0013;
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
-		iface |= 0x0013;
+		iface |= 0x0003;
 		break;
 	default:
 		return -EINVAL;
@@ -496,6 +518,9 @@
 		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)
+
 struct snd_soc_dai ssm2602_dai = {
 	.name = "SSM2602",
 	.playback = {
@@ -503,20 +528,18 @@
 		.channels_min = 2,
 		.channels_max = 2,
 		.rates = SSM2602_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S32_LE,},
+		.formats = SSM2602_FORMATS,},
 	.capture = {
 		.stream_name = "Capture",
 		.channels_min = 2,
 		.channels_max = 2,
 		.rates = SSM2602_RATES,
-		.formats = SNDRV_PCM_FMTBIT_S32_LE,},
+		.formats = SSM2602_FORMATS,},
 	.ops = {
 		.startup = ssm2602_startup,
 		.prepare = ssm2602_pcm_prepare,
 		.hw_params = ssm2602_hw_params,
 		.shutdown = ssm2602_shutdown,
-	},
-	.dai_ops = {
 		.digital_mute = ssm2602_mute,
 		.set_sysclk = ssm2602_set_dai_sysclk,
 		.set_fmt = ssm2602_set_dai_fmt,
@@ -601,7 +624,7 @@
 
 	ssm2602_add_controls(codec);
 	ssm2602_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		pr_err("ssm2602: failed to register card\n");
 		goto card_err;
@@ -770,6 +793,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602);
 
+static int __init ssm2602_modinit(void)
+{
+	return snd_soc_register_dai(&ssm2602_dai);
+}
+module_init(ssm2602_modinit);
+
+static void __exit ssm2602_exit(void)
+{
+	snd_soc_unregister_dai(&ssm2602_dai);
+}
+module_exit(ssm2602_exit);
+
 MODULE_DESCRIPTION("ASoC ssm2602 driver");
 MODULE_AUTHOR("Cliff Cai");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 44308da..cfdea00 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -37,12 +37,6 @@
 
 #define AIC23_VERSION "0.1"
 
-struct tlv320aic23_srate_reg_info {
-	u32 sample_rate;
-	u8 control;		/* SR3, SR2, SR1, SR0 and BOSR */
-	u8 divider;		/* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
-};
-
 /*
  * AIC23 register cache
  */
@@ -261,20 +255,156 @@
 
 };
 
-/* tlv320aic23 related */
-static const struct tlv320aic23_srate_reg_info srate_reg_info[] = {
-	{4000, 0x06, 1},	/*  4000 */
-	{8000, 0x06, 0},	/*  8000 */
-	{16000, 0x0C, 1},	/* 16000 */
-	{22050, 0x11, 1},	/* 22050 */
-	{24000, 0x00, 1},	/* 24000 */
-	{32000, 0x0C, 0},	/* 32000 */
-	{44100, 0x11, 0},	/* 44100 */
-	{48000, 0x00, 0},	/* 48000 */
-	{88200, 0x1F, 0},	/* 88200 */
-	{96000, 0x0E, 0},	/* 96000 */
+/* AIC23 driver data */
+struct aic23 {
+	struct snd_soc_codec codec;
+	int mclk;
+	int requested_adc;
+	int requested_dac;
 };
 
+/*
+ * Common Crystals used
+ * 11.2896 Mhz /128 = *88.2k  /192 = 58.8k
+ * 12.0000 Mhz /125 = *96k    /136 = 88.235K
+ * 12.2880 Mhz /128 = *96k    /192 = 64k
+ * 16.9344 Mhz /128 = 132.3k /192 = *88.2k
+ * 18.4320 Mhz /128 = 144k   /192 = *96k
+ */
+
+/*
+ * Normal BOSR 0-256/2 = 128, 1-384/2 = 192
+ * USB BOSR 0-250/2 = 125, 1-272/2 = 136
+ */
+static const int bosr_usb_divisor_table[] = {
+	128, 125, 192, 136
+};
+#define LOWER_GROUP ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<6) | (1<<7))
+#define UPPER_GROUP ((1<<8) | (1<<9) | (1<<10) | (1<<11)        | (1<<15))
+static const unsigned short sr_valid_mask[] = {
+	LOWER_GROUP|UPPER_GROUP,	/* Normal, bosr - 0*/
+	LOWER_GROUP|UPPER_GROUP,	/* Normal, bosr - 1*/
+	LOWER_GROUP,			/* Usb, bosr - 0*/
+	UPPER_GROUP,			/* Usb, bosr - 1*/
+};
+/*
+ * Every divisor is a factor of 11*12
+ */
+#define SR_MULT (11*12)
+#define A(x) (x) ? (SR_MULT/x) : 0
+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)
+};
+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)
+};
+
+static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc,
+		int dac, int dac_l, int dac_h, int need_dac)
+{
+	if ((adc >= adc_l) && (adc <= adc_h) &&
+			(dac >= dac_l) && (dac <= dac_h)) {
+		int diff_adc = need_adc - adc;
+		int diff_dac = need_dac - dac;
+		return abs(diff_adc) + abs(diff_dac);
+	}
+	return UINT_MAX;
+}
+
+static int find_rate(int mclk, u32 need_adc, u32 need_dac)
+{
+	int i, j;
+	int best_i = -1;
+	int best_j = -1;
+	int best_div = 0;
+	unsigned best_score = UINT_MAX;
+	int adc_l, adc_h, dac_l, dac_h;
+
+	need_adc *= SR_MULT;
+	need_dac *= SR_MULT;
+	/*
+	 * rates given are +/- 1/32
+	 */
+	adc_l = need_adc - (need_adc >> 5);
+	adc_h = need_adc + (need_adc >> 5);
+	dac_l = need_dac - (need_dac >> 5);
+	dac_h = need_dac + (need_dac >> 5);
+	for (i = 0; i < ARRAY_SIZE(bosr_usb_divisor_table); i++) {
+		int base = mclk / bosr_usb_divisor_table[i];
+		int mask = sr_valid_mask[i];
+		for (j = 0; j < ARRAY_SIZE(sr_adc_mult_table);
+				j++, mask >>= 1) {
+			int adc;
+			int dac;
+			int score;
+			if ((mask & 1) == 0)
+				continue;
+			adc = base * sr_adc_mult_table[j];
+			dac = base * sr_dac_mult_table[j];
+			score = get_score(adc, adc_l, adc_h, need_adc,
+					dac, dac_l, dac_h, need_dac);
+			if (best_score > score) {
+				best_score = score;
+				best_i = i;
+				best_j = j;
+				best_div = 0;
+			}
+			score = get_score((adc >> 1), adc_l, adc_h, need_adc,
+					(dac >> 1), dac_l, dac_h, need_dac);
+			/* prefer to have a /2 */
+			if ((score != UINT_MAX) && (best_score >= score)) {
+				best_score = score;
+				best_i = i;
+				best_j = j;
+				best_div = 1;
+			}
+		}
+	}
+	return (best_j << 2) | best_i | (best_div << TLV320AIC23_CLKIN_SHIFT);
+}
+
+#ifdef DEBUG
+static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk,
+		u32 *sample_rate_adc, u32 *sample_rate_dac)
+{
+	int src = tlv320aic23_read_reg_cache(codec, TLV320AIC23_SRATE);
+	int sr = (src >> 2) & 0x0f;
+	int val = (mclk / bosr_usb_divisor_table[src & 3]);
+	int adc = (val * sr_adc_mult_table[sr]) / SR_MULT;
+	int dac = (val * sr_dac_mult_table[sr]) / SR_MULT;
+	if (src & TLV320AIC23_CLKIN_HALF) {
+		adc >>= 1;
+		dac >>= 1;
+	}
+	*sample_rate_adc = adc;
+	*sample_rate_dac = dac;
+}
+#endif
+
+static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
+		u32 sample_rate_adc, u32 sample_rate_dac)
+{
+	/* Search for the right sample rate */
+	int data = find_rate(mclk, sample_rate_adc, sample_rate_dac);
+	if (data < 0) {
+		printk(KERN_ERR "%s:Invalid rate %u,%u requested\n",
+				__func__, sample_rate_adc, sample_rate_dac);
+		return -EINVAL;
+	}
+	tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
+#ifdef DEBUG
+	{
+		u32 adc, dac;
+		get_current_sample_rates(codec, mclk, &adc, &dac);
+		printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n",
+			adc, dac, data);
+	}
+#endif
+	return 0;
+}
+
 static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
 {
 	snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
@@ -288,32 +418,36 @@
 }
 
 static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
-				 struct snd_pcm_hw_params *params)
+				 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->codec;
-	u16 iface_reg, data;
-	u8 count = 0;
+	u16 iface_reg;
+	int ret;
+	struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+	u32 sample_rate_adc = aic23->requested_adc;
+	u32 sample_rate_dac = aic23->requested_dac;
+	u32 sample_rate = params_rate(params);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		aic23->requested_dac = sample_rate_dac = sample_rate;
+		if (!sample_rate_adc)
+			sample_rate_adc = sample_rate;
+	} else {
+		aic23->requested_adc = sample_rate_adc = sample_rate;
+		if (!sample_rate_dac)
+			sample_rate_dac = sample_rate;
+	}
+	ret = set_sample_rate_control(codec, aic23->mclk, sample_rate_adc,
+			sample_rate_dac);
+	if (ret < 0)
+		return ret;
 
 	iface_reg =
 	    tlv320aic23_read_reg_cache(codec,
 				       TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
-
-	/* Search for the right sample rate */
-	/* Verify what happens if the rate is not supported
-	 * now it goes to 96Khz */
-	while ((srate_reg_info[count].sample_rate != params_rate(params)) &&
-	       (count < ARRAY_SIZE(srate_reg_info))) {
-		count++;
-	}
-
-	data =  (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) |
-		(srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) |
-		TLV320AIC23_USB_CLK_ON;
-
-	tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
-
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
 		break;
@@ -332,7 +466,8 @@
 	return 0;
 }
 
-static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream)
+static int tlv320aic23_pcm_prepare(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;
@@ -344,17 +479,23 @@
 	return 0;
 }
 
-static void tlv320aic23_shutdown(struct snd_pcm_substream *substream)
+static void tlv320aic23_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->codec;
+	struct aic23 *aic23 = container_of(codec, struct aic23, codec);
 
 	/* deactivate */
 	if (!codec->active) {
 		udelay(50);
 		tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
 	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		aic23->requested_dac = 0;
+	else
+		aic23->requested_adc = 0;
 }
 
 static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
@@ -400,7 +541,7 @@
 	case SND_SOC_DAIFMT_I2S:
 		iface_reg |= TLV320AIC23_FOR_I2S;
 		break;
-	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
 		iface_reg |= TLV320AIC23_FOR_DSP;
 		break;
 	case SND_SOC_DAIFMT_RIGHT_J:
@@ -422,12 +563,9 @@
 				      int clk_id, unsigned int freq, int dir)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-
-	switch (freq) {
-	case 12000000:
-		return 0;
-	}
-	return -EINVAL;
+	struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+	aic23->mclk = freq;
+	return 0;
 }
 
 static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
@@ -478,12 +616,10 @@
 		.prepare = tlv320aic23_pcm_prepare,
 		.hw_params = tlv320aic23_hw_params,
 		.shutdown = tlv320aic23_shutdown,
-		},
-	.dai_ops = {
-		    .digital_mute = tlv320aic23_mute,
-		    .set_fmt = tlv320aic23_set_dai_fmt,
-		    .set_sysclk = tlv320aic23_set_dai_sysclk,
-		    }
+		.digital_mute = tlv320aic23_mute,
+		.set_fmt = tlv320aic23_set_dai_fmt,
+		.set_sysclk = tlv320aic23_set_dai_sysclk,
+	}
 };
 EXPORT_SYMBOL_GPL(tlv320aic23_dai);
 
@@ -584,7 +720,7 @@
 
 	tlv320aic23_add_controls(codec);
 	tlv320aic23_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "tlv320aic23: failed to register card\n");
 		goto card_err;
@@ -659,14 +795,15 @@
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 	struct snd_soc_codec *codec;
+	struct aic23 *aic23;
 	int ret = 0;
 
 	printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
 
-	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (codec == NULL)
+	aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
+	if (aic23 == NULL)
 		return -ENOMEM;
-
+	codec = &aic23->codec;
 	socdev->codec = codec;
 	mutex_init(&codec->mutex);
 	INIT_LIST_HEAD(&codec->dapm_widgets);
@@ -687,6 +824,7 @@
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 	struct snd_soc_codec *codec = socdev->codec;
+	struct aic23 *aic23 = container_of(codec, struct aic23, codec);
 
 	if (codec->control_data)
 		tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -697,7 +835,7 @@
 	i2c_del_driver(&tlv320aic23_i2c_driver);
 #endif
 	kfree(codec->reg_cache);
-	kfree(codec);
+	kfree(aic23);
 
 	return 0;
 }
@@ -709,6 +847,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
 
+static int __init tlv320aic23_modinit(void)
+{
+	return snd_soc_register_dai(&tlv320aic23_dai);
+}
+module_init(tlv320aic23_modinit);
+
+static void __exit tlv320aic23_exit(void)
+{
+	snd_soc_unregister_dai(&tlv320aic23_dai);
+}
+module_exit(tlv320aic23_exit);
+
 MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
 MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index bed8a9e..29f2f1a 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -125,7 +125,8 @@
  * Digital Audio Interface Operations
  */
 static int aic26_hw_params(struct snd_pcm_substream *substream,
-			   struct snd_pcm_hw_params *params)
+			   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;
@@ -287,8 +288,6 @@
 	},
 	.ops = {
 		.hw_params = aic26_hw_params,
-	},
-	.dai_ops = {
 		.digital_mute = aic26_mute,
 		.set_sysclk = aic26_set_sysclk,
 		.set_fmt = aic26_set_fmt,
@@ -360,7 +359,7 @@
 
 	/* CODEC is setup, we can register the card now */
 	dev_dbg(&pdev->dev, "Registering card\n");
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "aic26: failed to register card\n");
 		goto card_err;
@@ -427,7 +426,7 @@
 static int aic26_spi_probe(struct spi_device *spi)
 {
 	struct aic26 *aic26;
-	int rc, i, reg;
+	int ret, i, reg;
 
 	dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
 
@@ -457,6 +456,14 @@
 	aic26->codec.reg_cache_size = AIC26_NUM_REGS;
 	aic26->codec.reg_cache = aic26->reg_cache;
 
+	aic26_dai.dev = &spi->dev;
+	ret = snd_soc_register_dai(&aic26_dai);
+	if (ret != 0) {
+		dev_err(&spi->dev, "Failed to register DAI: %d\n", ret);
+		kfree(aic26);
+		return ret;
+	}
+
 	/* Reset the codec to power on defaults */
 	aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00);
 
@@ -475,8 +482,8 @@
 
 	/* Register the sysfs files for debugging */
 	/* Create SysFS files */
-	rc = device_create_file(&spi->dev, &dev_attr_keyclick);
-	if (rc)
+	ret = device_create_file(&spi->dev, &dev_attr_keyclick);
+	if (ret)
 		dev_info(&spi->dev, "error creating sysfs files\n");
 
 #if defined(CONFIG_SND_SOC_OF_SIMPLE)
@@ -493,6 +500,7 @@
 {
 	struct aic26 *aic26 = dev_get_drvdata(&spi->dev);
 
+	snd_soc_unregister_dai(&aic26_dai);
 	kfree(aic26);
 
 	return 0;
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index cff276e..b47a749 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -253,11 +253,17 @@
 
 	SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL,
 		     DACR1_2_RLOPM_VOL, 0, 0x7f, 1),
-	SOC_DOUBLE_R("Line DAC Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
-		     0x01, 0),
-	SOC_DOUBLE_R("Line PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL,
-		     PGAR_2_RLOPM_VOL, 0, 0x7f, 1),
-	SOC_DOUBLE_R("Line Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL,
+	SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0),
+	SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0),
+	SOC_DOUBLE_R("LineL DAC Playback Volume", DACL1_2_LLOPM_VOL,
+		     DACR1_2_LLOPM_VOL, 0, 0x7f, 1),
+	SOC_SINGLE("LineL Left PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL,
+		     0, 0x7f, 1),
+	SOC_SINGLE("LineR Right PGA Bypass Playback Volume", PGAR_2_RLOPM_VOL,
+		     0, 0x7f, 1),
+	SOC_DOUBLE_R("LineL Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL,
+		     LINE2R_2_LLOPM_VOL, 0, 0x7f, 1),
+	SOC_DOUBLE_R("LineR Line2 Bypass Playback Volume", LINE2L_2_RLOPM_VOL,
 		     LINE2R_2_RLOPM_VOL, 0, 0x7f, 1),
 
 	SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL,
@@ -272,8 +278,12 @@
 		     DACR1_2_HPROUT_VOL, 0, 0x7f, 1),
 	SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
 		     0x01, 0),
-	SOC_DOUBLE_R("HP PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL,
+	SOC_DOUBLE_R("HP Right PGA Bypass Playback Volume", PGAR_2_HPLOUT_VOL,
 		     PGAR_2_HPROUT_VOL, 0, 0x7f, 1),
+	SOC_SINGLE("HPL PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL,
+		     0, 0x7f, 1),
+	SOC_SINGLE("HPR PGA Bypass Playback Volume", PGAL_2_HPROUT_VOL,
+		     0, 0x7f, 1),
 	SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL,
 		     LINE2R_2_HPROUT_VOL, 0, 0x7f, 1),
 
@@ -281,8 +291,10 @@
 		     DACR1_2_HPRCOM_VOL, 0, 0x7f, 1),
 	SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
 		     0x01, 0),
-	SOC_DOUBLE_R("HPCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL,
-		     PGAR_2_HPRCOM_VOL, 0, 0x7f, 1),
+	SOC_SINGLE("HPLCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL,
+		     0, 0x7f, 1),
+	SOC_SINGLE("HPRCOM PGA Bypass Playback Volume", PGAL_2_HPRCOM_VOL,
+		     0, 0x7f, 1),
 	SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL,
 		     LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1),
 
@@ -333,7 +345,8 @@
 
 /* Left DAC_L1 Mixer */
 static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
@@ -341,7 +354,8 @@
 
 /* Right DAC_R1 Mixer */
 static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
@@ -350,14 +364,18 @@
 /* Left PGA Mixer */
 static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = {
 	SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1),
 	SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1),
 	SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1),
 };
 
 /* Right PGA Mixer */
 static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
 	SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1),
 	SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1),
 	SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
 };
 
@@ -379,34 +397,42 @@
 
 /* Left PGA Bypass Mixer */
 static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("HP Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("HPCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
 };
 
 /* Right PGA Bypass Mixer */
 static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("HP Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("HPCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
 };
 
 /* Left Line2 Bypass Mixer */
 static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("HPCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
 };
 
 /* Right Line2 Bypass Mixer */
 static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = {
-	SOC_DAPM_SINGLE("Line Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
 	SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
-	SOC_DAPM_SINGLE("HPCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
 };
 
 static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
@@ -439,22 +465,26 @@
 	/* Mono Output */
 	SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
 
-	/* Left Inputs to Left ADC */
+	/* Inputs to Left ADC */
 	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
 	SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
 			   &aic3x_left_pga_mixer_controls[0],
 			   ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
 	SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0,
 			 &aic3x_left_line1_mux_controls),
+	SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_left_line1_mux_controls),
 	SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
 			 &aic3x_left_line2_mux_controls),
 
-	/* Right Inputs to Right ADC */
+	/* Inputs to Right ADC */
 	SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
 			 LINE1R_2_RADC_CTRL, 2, 0),
 	SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
 			   &aic3x_right_pga_mixer_controls[0],
 			   ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
+	SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_right_line1_mux_controls),
 	SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0,
 			 &aic3x_right_line1_mux_controls),
 	SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
@@ -531,7 +561,8 @@
 	{"Left DAC Mux", "DAC_L2", "Left DAC"},
 	{"Left DAC Mux", "DAC_L3", "Left DAC"},
 
-	{"Left DAC_L1 Mixer", "Line Switch", "Left DAC Mux"},
+	{"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"},
+	{"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"},
 	{"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"},
 	{"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"},
 	{"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"},
@@ -557,7 +588,8 @@
 	{"Right DAC Mux", "DAC_R2", "Right DAC"},
 	{"Right DAC Mux", "DAC_R3", "Right DAC"},
 
-	{"Right DAC_R1 Mixer", "Line Switch", "Right DAC Mux"},
+	{"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"},
+	{"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"},
 	{"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"},
 	{"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"},
 	{"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"},
@@ -592,8 +624,10 @@
 	{"Left Line2L Mux", "differential", "LINE2L"},
 
 	{"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"},
+	{"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"},
 	{"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
 	{"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
+	{"Left PGA Mixer", "Mic3R Switch", "MIC3R"},
 
 	{"Left ADC", NULL, "Left PGA Mixer"},
 	{"Left ADC", NULL, "GPIO1 dmic modclk"},
@@ -605,18 +639,23 @@
 	{"Right Line2R Mux", "single-ended", "LINE2R"},
 	{"Right Line2R Mux", "differential", "LINE2R"},
 
+	{"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"},
 	{"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"},
 	{"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
+	{"Right PGA Mixer", "Mic3L Switch", "MIC3L"},
 	{"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
 
 	{"Right ADC", NULL, "Right PGA Mixer"},
 	{"Right ADC", NULL, "GPIO1 dmic modclk"},
 
 	/* Left PGA Bypass */
-	{"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"},
+	{"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"},
+	{"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"},
 	{"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"},
-	{"Left PGA Bypass Mixer", "HP Switch", "Left PGA Mixer"},
-	{"Left PGA Bypass Mixer", "HPCOM Switch", "Left PGA Mixer"},
+	{"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"},
+	{"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"},
+	{"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"},
+	{"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"},
 
 	{"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"},
 	{"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"},
@@ -627,10 +666,13 @@
 	{"Left HP Out", NULL, "Left PGA Bypass Mixer"},
 
 	/* Right PGA Bypass */
-	{"Right PGA Bypass Mixer", "Line Switch", "Right PGA Mixer"},
+	{"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"},
+	{"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"},
 	{"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"},
-	{"Right PGA Bypass Mixer", "HP Switch", "Right PGA Mixer"},
-	{"Right PGA Bypass Mixer", "HPCOM Switch", "Right PGA Mixer"},
+	{"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"},
+	{"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"},
+	{"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"},
+	{"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"},
 
 	{"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"},
 	{"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"},
@@ -643,10 +685,11 @@
 	{"Right HP Out", NULL, "Right PGA Bypass Mixer"},
 
 	/* Left Line2 Bypass */
-	{"Left Line2 Bypass Mixer", "Line Switch", "Left Line2L Mux"},
+	{"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"},
+	{"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"},
 	{"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"},
 	{"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"},
-	{"Left Line2 Bypass Mixer", "HPCOM Switch", "Left Line2L Mux"},
+	{"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"},
 
 	{"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"},
 	{"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"},
@@ -657,10 +700,11 @@
 	{"Left HP Out", NULL, "Left Line2 Bypass Mixer"},
 
 	/* Right Line2 Bypass */
-	{"Right Line2 Bypass Mixer", "Line Switch", "Right Line2R Mux"},
+	{"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"},
+	{"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"},
 	{"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"},
 	{"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"},
-	{"Right Line2 Bypass Mixer", "HPCOM Switch", "Right Line2R Mux"},
+	{"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"},
 
 	{"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"},
 	{"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"},
@@ -694,7 +738,8 @@
 }
 
 static int aic3x_hw_params(struct snd_pcm_substream *substream,
-			   struct snd_pcm_hw_params *params)
+			   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;
@@ -846,6 +891,7 @@
 	struct snd_soc_codec *codec = codec_dai->codec;
 	struct aic3x_priv *aic3x = codec->private_data;
 	u8 iface_areg, iface_breg;
+	int delay = 0;
 
 	iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
 	iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
@@ -871,6 +917,8 @@
 		       SND_SOC_DAIFMT_INV_MASK)) {
 	case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
 		break;
+	case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF):
+		delay = 1;
 	case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF):
 		iface_breg |= (0x01 << 6);
 		break;
@@ -887,6 +935,7 @@
 	/* set iface */
 	aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
 	aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
+	aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
 
 	return 0;
 }
@@ -981,14 +1030,41 @@
 }
 EXPORT_SYMBOL_GPL(aic3x_get_gpio);
 
+void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
+				 int headset_debounce, int button_debounce)
+{
+	u8 val;
+
+	val = ((detect & AIC3X_HEADSET_DETECT_MASK)
+		<< AIC3X_HEADSET_DETECT_SHIFT) |
+	      ((headset_debounce & AIC3X_HEADSET_DEBOUNCE_MASK)
+		<< AIC3X_HEADSET_DEBOUNCE_SHIFT) |
+	      ((button_debounce & AIC3X_BUTTON_DEBOUNCE_MASK)
+		<< AIC3X_BUTTON_DEBOUNCE_SHIFT);
+
+	if (detect & AIC3X_HEADSET_DETECT_MASK)
+		val |= AIC3X_HEADSET_DETECT_ENABLED;
+
+	aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
+}
+EXPORT_SYMBOL_GPL(aic3x_set_headset_detection);
+
 int aic3x_headset_detected(struct snd_soc_codec *codec)
 {
 	u8 val;
-	aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val);
-	return (val >> 2) & 1;
+	aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val);
+	return (val >> 4) & 1;
 }
 EXPORT_SYMBOL_GPL(aic3x_headset_detected);
 
+int aic3x_button_pressed(struct snd_soc_codec *codec)
+{
+	u8 val;
+	aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val);
+	return (val >> 5) & 1;
+}
+EXPORT_SYMBOL_GPL(aic3x_button_pressed);
+
 #define AIC3X_RATES	SNDRV_PCM_RATE_8000_96000
 #define AIC3X_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -1009,8 +1085,6 @@
 		.formats = AIC3X_FORMATS,},
 	.ops = {
 		.hw_params = aic3x_hw_params,
-	},
-	.dai_ops = {
 		.digital_mute = aic3x_mute,
 		.set_sysclk = aic3x_set_dai_sysclk,
 		.set_fmt = aic3x_set_dai_fmt,
@@ -1152,7 +1226,7 @@
 
 	aic3x_add_controls(codec);
 	aic3x_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "aic3x: failed to register card\n");
 		goto card_err;
@@ -1341,6 +1415,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x);
 
+static int __init aic3x_modinit(void)
+{
+	return snd_soc_register_dai(&aic3x_dai);
+}
+module_init(aic3x_modinit);
+
+static void __exit aic3x_exit(void)
+{
+	snd_soc_unregister_dai(&aic3x_dai);
+}
+module_exit(aic3x_exit);
+
 MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver");
 MODULE_AUTHOR("Vladimir Barinov");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index 00a195a..ac827e5 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -35,11 +35,15 @@
 #define AIC3X_ASD_INTF_CTRLA		8
 /* Audio serial data interface control register B */
 #define AIC3X_ASD_INTF_CTRLB		9
+/* Audio serial data interface control register C */
+#define AIC3X_ASD_INTF_CTRLC		10
 /* Audio overflow status and PLL R value programming register */
 #define AIC3X_OVRF_STATUS_AND_PLLR_REG	11
 /* Audio codec digital filter control register */
 #define AIC3X_CODEC_DFILT_CTRL		12
-
+/* Headset/button press detection register */
+#define AIC3X_HEADSET_DETECT_CTRL_A	13
+#define AIC3X_HEADSET_DETECT_CTRL_B	14
 /* ADC PGA Gain control registers */
 #define LADC_VOL			15
 #define RADC_VOL			16
@@ -48,7 +52,9 @@
 #define MIC3LR_2_RADC_CTRL		18
 /* Line1 Input control registers */
 #define LINE1L_2_LADC_CTRL		19
+#define LINE1R_2_LADC_CTRL		21
 #define LINE1R_2_RADC_CTRL		22
+#define LINE1L_2_RADC_CTRL		24
 /* Line2 Input control registers */
 #define LINE2L_2_LADC_CTRL		20
 #define LINE2R_2_RADC_CTRL		23
@@ -79,6 +85,8 @@
 #define LINE2L_2_HPLOUT_VOL		45
 #define LINE2R_2_HPROUT_VOL		62
 #define PGAL_2_HPLOUT_VOL		46
+#define PGAL_2_HPROUT_VOL		60
+#define PGAR_2_HPLOUT_VOL		49
 #define PGAR_2_HPROUT_VOL		63
 #define DACL1_2_HPLOUT_VOL		47
 #define DACR1_2_HPROUT_VOL		64
@@ -88,6 +96,8 @@
 #define LINE2L_2_HPLCOM_VOL		52
 #define LINE2R_2_HPRCOM_VOL		69
 #define PGAL_2_HPLCOM_VOL		53
+#define PGAR_2_HPLCOM_VOL		56
+#define PGAL_2_HPRCOM_VOL		67
 #define PGAR_2_HPRCOM_VOL		70
 #define DACL1_2_HPLCOM_VOL		54
 #define DACR1_2_HPRCOM_VOL		71
@@ -103,11 +113,17 @@
 #define MONOLOPM_CTRL			79
 /* Line Output Plus/Minus control registers */
 #define LINE2L_2_LLOPM_VOL		80
+#define LINE2L_2_RLOPM_VOL		87
+#define LINE2R_2_LLOPM_VOL		83
 #define LINE2R_2_RLOPM_VOL		90
 #define PGAL_2_LLOPM_VOL		81
+#define PGAL_2_RLOPM_VOL		88
+#define PGAR_2_LLOPM_VOL		84
 #define PGAR_2_RLOPM_VOL		91
 #define DACL1_2_LLOPM_VOL		82
+#define DACL1_2_RLOPM_VOL		89
 #define DACR1_2_RLOPM_VOL		92
+#define DACR1_2_LLOPM_VOL		85
 #define LLOPM_CTRL			86
 #define RLOPM_CTRL			93
 /* GPIO/IRQ registers */
@@ -221,7 +237,49 @@
 
 void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state);
 int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio);
+
+/* headset detection / button API */
+
+/* The AIC3x supports detection of stereo headsets (GND + left + right signal)
+ * and cellular headsets (GND + speaker output + microphone input).
+ * It is recommended to enable MIC bias for this function to work properly.
+ * For more information, please refer to the datasheet. */
+enum {
+	AIC3X_HEADSET_DETECT_OFF	= 0,
+	AIC3X_HEADSET_DETECT_STEREO	= 1,
+	AIC3X_HEADSET_DETECT_CELLULAR   = 2,
+	AIC3X_HEADSET_DETECT_BOTH	= 3
+};
+
+enum {
+	AIC3X_HEADSET_DEBOUNCE_16MS	= 0,
+	AIC3X_HEADSET_DEBOUNCE_32MS	= 1,
+	AIC3X_HEADSET_DEBOUNCE_64MS	= 2,
+	AIC3X_HEADSET_DEBOUNCE_128MS	= 3,
+	AIC3X_HEADSET_DEBOUNCE_256MS	= 4,
+	AIC3X_HEADSET_DEBOUNCE_512MS	= 5
+};
+
+enum {
+	AIC3X_BUTTON_DEBOUNCE_0MS	= 0,
+	AIC3X_BUTTON_DEBOUNCE_8MS	= 1,
+	AIC3X_BUTTON_DEBOUNCE_16MS	= 2,
+	AIC3X_BUTTON_DEBOUNCE_32MS	= 3
+};
+
+#define AIC3X_HEADSET_DETECT_ENABLED	0x80
+#define AIC3X_HEADSET_DETECT_SHIFT	5
+#define AIC3X_HEADSET_DETECT_MASK	3
+#define AIC3X_HEADSET_DEBOUNCE_SHIFT	2
+#define AIC3X_HEADSET_DEBOUNCE_MASK	7
+#define AIC3X_BUTTON_DEBOUNCE_SHIFT 	0
+#define AIC3X_BUTTON_DEBOUNCE_MASK	3
+
+/* see the enums above for valid parameters to this function */
+void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
+				 int headset_debounce, int button_debounce);
 int aic3x_headset_detected(struct snd_soc_codec *codec);
+int aic3x_button_pressed(struct snd_soc_codec *codec);
 
 struct aic3x_setup_data {
 	int i2c_bus;
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
new file mode 100644
index 0000000..5184888
--- /dev/null
+++ b/sound/soc/codecs/twl4030.c
@@ -0,0 +1,1317 @@
+/*
+ * ALSA SoC TWL4030 codec driver
+ *
+ * Author:      Steve Sakoman, <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.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 "twl4030.h"
+
+/*
+ * twl4030 register cache & default register settings
+ */
+static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
+	0x00, /* this register not used		*/
+	0x93, /* REG_CODEC_MODE		(0x1)	*/
+	0xc3, /* REG_OPTION		(0x2)	*/
+	0x00, /* REG_UNKNOWN		(0x3)	*/
+	0x00, /* REG_MICBIAS_CTL	(0x4)	*/
+	0x20, /* REG_ANAMICL		(0x5)	*/
+	0x00, /* REG_ANAMICR		(0x6)	*/
+	0x00, /* REG_AVADC_CTL		(0x7)	*/
+	0x00, /* REG_ADCMICSEL		(0x8)	*/
+	0x00, /* REG_DIGMIXING		(0x9)	*/
+	0x0c, /* REG_ATXL1PGA		(0xA)	*/
+	0x0c, /* REG_ATXR1PGA		(0xB)	*/
+	0x00, /* REG_AVTXL2PGA		(0xC)	*/
+	0x00, /* REG_AVTXR2PGA		(0xD)	*/
+	0x01, /* REG_AUDIO_IF		(0xE)	*/
+	0x00, /* REG_VOICE_IF		(0xF)	*/
+	0x00, /* REG_ARXR1PGA		(0x10)	*/
+	0x00, /* REG_ARXL1PGA		(0x11)	*/
+	0x6c, /* REG_ARXR2PGA		(0x12)	*/
+	0x6c, /* REG_ARXL2PGA		(0x13)	*/
+	0x00, /* REG_VRXPGA		(0x14)	*/
+	0x00, /* REG_VSTPGA		(0x15)	*/
+	0x00, /* REG_VRX2ARXPGA		(0x16)	*/
+	0x0c, /* REG_AVDAC_CTL		(0x17)	*/
+	0x00, /* REG_ARX2VTXPGA		(0x18)	*/
+	0x00, /* REG_ARXL1_APGA_CTL	(0x19)	*/
+	0x00, /* REG_ARXR1_APGA_CTL	(0x1A)	*/
+	0x4b, /* REG_ARXL2_APGA_CTL	(0x1B)	*/
+	0x4b, /* REG_ARXR2_APGA_CTL	(0x1C)	*/
+	0x00, /* REG_ATX2ARXPGA		(0x1D)	*/
+	0x00, /* REG_BT_IF		(0x1E)	*/
+	0x00, /* REG_BTPGA		(0x1F)	*/
+	0x00, /* REG_BTSTPGA		(0x20)	*/
+	0x00, /* REG_EAR_CTL		(0x21)	*/
+	0x24, /* REG_HS_SEL		(0x22)	*/
+	0x0a, /* REG_HS_GAIN_SET	(0x23)	*/
+	0x00, /* REG_HS_POPN_SET	(0x24)	*/
+	0x00, /* REG_PREDL_CTL		(0x25)	*/
+	0x00, /* REG_PREDR_CTL		(0x26)	*/
+	0x00, /* REG_PRECKL_CTL		(0x27)	*/
+	0x00, /* REG_PRECKR_CTL		(0x28)	*/
+	0x00, /* REG_HFL_CTL		(0x29)	*/
+	0x00, /* REG_HFR_CTL		(0x2A)	*/
+	0x00, /* REG_ALC_CTL		(0x2B)	*/
+	0x00, /* REG_ALC_SET1		(0x2C)	*/
+	0x00, /* REG_ALC_SET2		(0x2D)	*/
+	0x00, /* REG_BOOST_CTL		(0x2E)	*/
+	0x00, /* REG_SOFTVOL_CTL	(0x2F)	*/
+	0x00, /* REG_DTMF_FREQSEL	(0x30)	*/
+	0x00, /* REG_DTMF_TONEXT1H	(0x31)	*/
+	0x00, /* REG_DTMF_TONEXT1L	(0x32)	*/
+	0x00, /* REG_DTMF_TONEXT2H	(0x33)	*/
+	0x00, /* REG_DTMF_TONEXT2L	(0x34)	*/
+	0x00, /* REG_DTMF_TONOFF	(0x35)	*/
+	0x00, /* REG_DTMF_WANONOFF	(0x36)	*/
+	0x00, /* REG_I2S_RX_SCRAMBLE_H	(0x37)	*/
+	0x00, /* REG_I2S_RX_SCRAMBLE_M	(0x38)	*/
+	0x00, /* REG_I2S_RX_SCRAMBLE_L	(0x39)	*/
+	0x16, /* REG_APLL_CTL		(0x3A)	*/
+	0x00, /* REG_DTMF_CTL		(0x3B)	*/
+	0x00, /* REG_DTMF_PGA_CTL2	(0x3C)	*/
+	0x00, /* REG_DTMF_PGA_CTL1	(0x3D)	*/
+	0x00, /* REG_MISC_SET_1		(0x3E)	*/
+	0x00, /* REG_PCMBTMUX		(0x3F)	*/
+	0x00, /* not used		(0x40)	*/
+	0x00, /* not used		(0x41)	*/
+	0x00, /* not used		(0x42)	*/
+	0x00, /* REG_RX_PATH_SEL	(0x43)	*/
+	0x00, /* REG_VDL_APGA_CTL	(0x44)	*/
+	0x00, /* REG_VIBRA_CTL		(0x45)	*/
+	0x00, /* REG_VIBRA_SET		(0x46)	*/
+	0x00, /* REG_VIBRA_PWM_SET	(0x47)	*/
+	0x00, /* REG_ANAMIC_GAIN	(0x48)	*/
+	0x00, /* REG_MISC_SET_2		(0x49)	*/
+};
+
+/*
+ * read twl4030 register cache
+ */
+static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u8 *cache = codec->reg_cache;
+
+	return cache[reg];
+}
+
+/*
+ * write twl4030 register cache
+ */
+static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec,
+						u8 reg, u8 value)
+{
+	u8 *cache = codec->reg_cache;
+
+	if (reg >= TWL4030_CACHEREGNUM)
+		return;
+	cache[reg] = value;
+}
+
+/*
+ * write to the twl4030 register space
+ */
+static int twl4030_write(struct snd_soc_codec *codec,
+			unsigned int reg, unsigned int value)
+{
+	twl4030_write_reg_cache(codec, reg, value);
+	return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
+}
+
+static void twl4030_clear_codecpdz(struct snd_soc_codec *codec)
+{
+	u8 mode;
+
+	mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
+	twl4030_write(codec, TWL4030_REG_CODEC_MODE,
+		mode & ~TWL4030_CODECPDZ);
+
+	/* REVISIT: this delay is present in TI sample drivers */
+	/* but there seems to be no TRM requirement for it     */
+	udelay(10);
+}
+
+static void twl4030_set_codecpdz(struct snd_soc_codec *codec)
+{
+	u8 mode;
+
+	mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
+	twl4030_write(codec, TWL4030_REG_CODEC_MODE,
+		mode | TWL4030_CODECPDZ);
+
+	/* REVISIT: this delay is present in TI sample drivers */
+	/* but there seems to be no TRM requirement for it     */
+	udelay(10);
+}
+
+static void twl4030_init_chip(struct snd_soc_codec *codec)
+{
+	int i;
+
+	/* clear CODECPDZ prior to setting register defaults */
+	twl4030_clear_codecpdz(codec);
+
+	/* 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]);
+
+}
+
+/* Earpiece */
+static const char *twl4030_earpiece_texts[] =
+		{"Off", "DACL1", "DACL2", "Invalid", "DACR1"};
+
+static const struct soc_enum twl4030_earpiece_enum =
+	SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1,
+			ARRAY_SIZE(twl4030_earpiece_texts),
+			twl4030_earpiece_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_earpiece_control =
+SOC_DAPM_ENUM("Route", twl4030_earpiece_enum);
+
+/* PreDrive Left */
+static const char *twl4030_predrivel_texts[] =
+		{"Off", "DACL1", "DACL2", "Invalid", "DACR2"};
+
+static const struct soc_enum twl4030_predrivel_enum =
+	SOC_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1,
+			ARRAY_SIZE(twl4030_predrivel_texts),
+			twl4030_predrivel_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_predrivel_control =
+SOC_DAPM_ENUM("Route", twl4030_predrivel_enum);
+
+/* PreDrive Right */
+static const char *twl4030_predriver_texts[] =
+		{"Off", "DACR1", "DACR2", "Invalid", "DACL2"};
+
+static const struct soc_enum twl4030_predriver_enum =
+	SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1,
+			ARRAY_SIZE(twl4030_predriver_texts),
+			twl4030_predriver_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_predriver_control =
+SOC_DAPM_ENUM("Route", twl4030_predriver_enum);
+
+/* 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);
+
+/* 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);
+
+/* 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);
+
+/* 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);
+
+/* Handsfree Left */
+static const char *twl4030_handsfreel_texts[] =
+		{"Voice", "DACL1", "DACL2", "DACR2"};
+
+static const struct soc_enum twl4030_handsfreel_enum =
+	SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0,
+			ARRAY_SIZE(twl4030_handsfreel_texts),
+			twl4030_handsfreel_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control =
+SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
+
+/* Handsfree Right */
+static const char *twl4030_handsfreer_texts[] =
+		{"Voice", "DACR1", "DACR2", "DACL2"};
+
+static const struct soc_enum twl4030_handsfreer_enum =
+	SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0,
+			ARRAY_SIZE(twl4030_handsfreer_texts),
+			twl4030_handsfreer_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control =
+SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
+
+static int outmixer_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int ret = 0;
+	int val;
+
+	switch (e->reg) {
+	case TWL4030_REG_PREDL_CTL:
+	case TWL4030_REG_PREDR_CTL:
+	case TWL4030_REG_EAR_CTL:
+		val = w->value >> e->shift_l;
+		if (val == 3) {
+			printk(KERN_WARNING
+			"Invalid MUX setting for register 0x%02x (%d)\n",
+			      e->reg, val);
+			ret = -1;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+static int handsfree_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	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);
+
+	if (hs_ctl & TWL4030_HF_CTL_REF_EN) {
+		hs_ctl |= TWL4030_HF_CTL_RAMP_EN;
+		twl4030_write(w->codec, e->reg, hs_ctl);
+		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);
+	} 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);
+	}
+
+	return 0;
+}
+
+/*
+ * Some of the gain controls in TWL (mostly those which are associated with
+ * the outputs) are implemented in an interesting way:
+ * 0x0 : Power down (mute)
+ * 0x1 : 6dB
+ * 0x2 : 0 dB
+ * 0x3 : -6 dB
+ * Inverting not going to help with these.
+ * Custom volsw and volsw_2r get/put functions to handle these gain bits.
+ */
+#define SOC_DOUBLE_TLV_TWL4030(xname, xreg, shift_left, shift_right, xmax,\
+			       xinvert, tlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.tlv.p = (tlv_array), \
+	.info = snd_soc_info_volsw, \
+	.get = snd_soc_get_volsw_twl4030, \
+	.put = snd_soc_put_volsw_twl4030, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg, .shift = shift_left, .rshift = shift_right,\
+		 .max = xmax, .invert = xinvert} }
+#define SOC_DOUBLE_R_TLV_TWL4030(xname, reg_left, reg_right, xshift, xmax,\
+				 xinvert, tlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+		 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.tlv.p = (tlv_array), \
+	.info = snd_soc_info_volsw_2r, \
+	.get = snd_soc_get_volsw_r2_twl4030,\
+	.put = snd_soc_put_volsw_r2_twl4030, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
+		 .rshift = xshift, .max = xmax, .invert = xinvert} }
+#define SOC_SINGLE_TLV_TWL4030(xname, xreg, xshift, xmax, xinvert, tlv_array) \
+	SOC_DOUBLE_TLV_TWL4030(xname, xreg, xshift, xshift, xmax, \
+			       xinvert, tlv_array)
+
+static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	int mask = (1 << fls(max)) - 1;
+
+	ucontrol->value.integer.value[0] =
+		(snd_soc_read(codec, reg) >> shift) & mask;
+	if (ucontrol->value.integer.value[0])
+		ucontrol->value.integer.value[0] =
+			max + 1 - ucontrol->value.integer.value[0];
+
+	if (shift != rshift) {
+		ucontrol->value.integer.value[1] =
+			(snd_soc_read(codec, reg) >> rshift) & mask;
+		if (ucontrol->value.integer.value[1])
+			ucontrol->value.integer.value[1] =
+				max + 1 - ucontrol->value.integer.value[1];
+	}
+
+	return 0;
+}
+
+static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	int mask = (1 << fls(max)) - 1;
+	unsigned short val, val2, val_mask;
+
+	val = (ucontrol->value.integer.value[0] & mask);
+
+	val_mask = mask << shift;
+	if (val)
+		val = max + 1 - val;
+	val = val << shift;
+	if (shift != rshift) {
+		val2 = (ucontrol->value.integer.value[1] & mask);
+		val_mask |= mask << rshift;
+		if (val2)
+			val2 = max + 1 - val2;
+		val |= val2 << rshift;
+	}
+	return snd_soc_update_bits(codec, reg, val_mask, val);
+}
+
+static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	int max = mc->max;
+	int mask = (1<<fls(max))-1;
+
+	ucontrol->value.integer.value[0] =
+		(snd_soc_read(codec, reg) >> shift) & mask;
+	ucontrol->value.integer.value[1] =
+		(snd_soc_read(codec, reg2) >> shift) & mask;
+
+	if (ucontrol->value.integer.value[0])
+		ucontrol->value.integer.value[0] =
+			max + 1 - ucontrol->value.integer.value[0];
+	if (ucontrol->value.integer.value[1])
+		ucontrol->value.integer.value[1] =
+			max + 1 - ucontrol->value.integer.value[1];
+
+	return 0;
+}
+
+static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	int max = mc->max;
+	int mask = (1 << fls(max)) - 1;
+	int err;
+	unsigned short val, val2, val_mask;
+
+	val_mask = mask << shift;
+	val = (ucontrol->value.integer.value[0] & mask);
+	val2 = (ucontrol->value.integer.value[1] & mask);
+
+	if (val)
+		val = max + 1 - val;
+	if (val2)
+		val2 = max + 1 - val2;
+
+	val = val << shift;
+	val2 = val2 << shift;
+
+	err = snd_soc_update_bits(codec, reg, val_mask, val);
+	if (err < 0)
+		return err;
+
+	err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+	return err;
+}
+
+static int twl4030_get_left_input(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = kcontrol->private_data;
+	u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+	int result = 0;
+
+	/* one bit must be set a time */
+	reg &= TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN
+			| TWL4030_MAINMIC_EN;
+	if (reg != 0) {
+		result++;
+		while ((reg & 1) == 0) {
+			result++;
+			reg >>= 1;
+		}
+	}
+
+	ucontrol->value.integer.value[0] = result;
+	return 0;
+}
+
+static int twl4030_put_left_input(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = kcontrol->private_data;
+	int value = ucontrol->value.integer.value[0];
+	u8 anamicl, micbias, avadc_ctl;
+
+	anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+	anamicl &= ~(TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN
+			| TWL4030_MAINMIC_EN);
+	micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL);
+	micbias &= ~(TWL4030_HSMICBIAS_EN | TWL4030_MICBIAS1_EN);
+	avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL);
+
+	switch (value) {
+	case 1:
+		anamicl |= TWL4030_MAINMIC_EN;
+		micbias |= TWL4030_MICBIAS1_EN;
+		break;
+	case 2:
+		anamicl |= TWL4030_HSMIC_EN;
+		micbias |= TWL4030_HSMICBIAS_EN;
+		break;
+	case 3:
+		anamicl |= TWL4030_AUXL_EN;
+		break;
+	case 4:
+		anamicl |= TWL4030_CKMIC_EN;
+		break;
+	default:
+		break;
+	}
+
+	/* If some input is selected, enable amp and ADC */
+	if (value != 0) {
+		anamicl |= TWL4030_MICAMPL_EN;
+		avadc_ctl |= TWL4030_ADCL_EN;
+	} else {
+		anamicl &= ~TWL4030_MICAMPL_EN;
+		avadc_ctl &= ~TWL4030_ADCL_EN;
+	}
+
+	twl4030_write(codec, TWL4030_REG_ANAMICL, anamicl);
+	twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias);
+	twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl);
+
+	return 1;
+}
+
+static int twl4030_get_right_input(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = kcontrol->private_data;
+	u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR);
+	int value = 0;
+
+	reg &= TWL4030_SUBMIC_EN|TWL4030_AUXR_EN;
+	switch (reg) {
+	case TWL4030_SUBMIC_EN:
+		value = 1;
+		break;
+	case TWL4030_AUXR_EN:
+		value = 2;
+		break;
+	default:
+		break;
+	}
+
+	ucontrol->value.integer.value[0] = value;
+	return 0;
+}
+
+static int twl4030_put_right_input(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = kcontrol->private_data;
+	int value = ucontrol->value.integer.value[0];
+	u8 anamicr, micbias, avadc_ctl;
+
+	anamicr = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR);
+	anamicr &= ~(TWL4030_SUBMIC_EN|TWL4030_AUXR_EN);
+	micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL);
+	micbias &= ~TWL4030_MICBIAS2_EN;
+	avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL);
+
+	switch (value) {
+	case 1:
+		anamicr |= TWL4030_SUBMIC_EN;
+		micbias |= TWL4030_MICBIAS2_EN;
+		break;
+	case 2:
+		anamicr |= TWL4030_AUXR_EN;
+		break;
+	default:
+		break;
+	}
+
+	if (value != 0) {
+		anamicr |= TWL4030_MICAMPR_EN;
+		avadc_ctl |= TWL4030_ADCR_EN;
+	} else {
+		anamicr &= ~TWL4030_MICAMPR_EN;
+		avadc_ctl &= ~TWL4030_ADCR_EN;
+	}
+
+	twl4030_write(codec, TWL4030_REG_ANAMICR, anamicr);
+	twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias);
+	twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl);
+
+	return 1;
+}
+
+static const char *twl4030_left_in_sel[] = {
+	"None",
+	"Main Mic",
+	"Headset Mic",
+	"Line In",
+	"Carkit Mic",
+};
+
+static const char *twl4030_right_in_sel[] = {
+	"None",
+	"Sub Mic",
+	"Line In",
+};
+
+static const struct soc_enum twl4030_left_input_mux =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_left_in_sel),
+		twl4030_left_in_sel);
+
+static const struct soc_enum twl4030_right_input_mux =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_right_in_sel),
+		twl4030_right_in_sel);
+
+/*
+ * FGAIN volume control:
+ * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB)
+ */
+static DECLARE_TLV_DB_SCALE(digital_fine_tlv, -6300, 100, 1);
+
+/*
+ * CGAIN volume control:
+ * 0 dB to 12 dB in 6 dB steps
+ * value 2 and 3 means 12 dB
+ */
+static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0);
+
+/*
+ * Analog playback gain
+ * -24 dB to 12 dB in 2 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(analog_tlv, -2400, 200, 0);
+
+/*
+ * Gain controls tied to outputs
+ * -6 dB to 6 dB in 6 dB steps (mute instead of -12)
+ */
+static DECLARE_TLV_DB_SCALE(output_tvl, -1200, 600, 1);
+
+/*
+ * Capture gain after the ADCs
+ * from 0 dB to 31 dB in 1 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0);
+
+/*
+ * Gain control for input amplifiers
+ * 0 dB to 30 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new twl4030_snd_controls[] = {
+	/* Common playback gain controls */
+	SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume",
+		TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA,
+		0, 0x3f, 0, digital_fine_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Digital Fine Playback Volume",
+		TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA,
+		0, 0x3f, 0, digital_fine_tlv),
+
+	SOC_DOUBLE_R_TLV("DAC1 Digital Coarse Playback Volume",
+		TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA,
+		6, 0x2, 0, digital_coarse_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Digital Coarse Playback Volume",
+		TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA,
+		6, 0x2, 0, digital_coarse_tlv),
+
+	SOC_DOUBLE_R_TLV("DAC1 Analog Playback Volume",
+		TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL,
+		3, 0x12, 1, analog_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Analog Playback Volume",
+		TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL,
+		3, 0x12, 1, analog_tlv),
+	SOC_DOUBLE_R("DAC1 Analog Playback Switch",
+		TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL,
+		1, 1, 0),
+	SOC_DOUBLE_R("DAC2 Analog Playback Switch",
+		TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_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,
+		4, 3, 0, output_tvl),
+
+	SOC_DOUBLE_TLV_TWL4030("Headset Playback Volume",
+		TWL4030_REG_HS_GAIN_SET, 0, 2, 3, 0, output_tvl),
+
+	SOC_DOUBLE_R_TLV_TWL4030("Carkit Playback Volume",
+		TWL4030_REG_PRECKL_CTL, TWL4030_REG_PRECKR_CTL,
+		4, 3, 0, output_tvl),
+
+	SOC_SINGLE_TLV_TWL4030("Earpiece Playback Volume",
+		TWL4030_REG_EAR_CTL, 4, 3, 0, output_tvl),
+
+	/* Common capture gain controls */
+	SOC_DOUBLE_R_TLV("Capture Volume",
+		TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA,
+		0, 0x1f, 0, digital_capture_tlv),
+
+	SOC_DOUBLE_TLV("Input Boost Volume", TWL4030_REG_ANAMIC_GAIN,
+		0, 3, 5, 0, input_gain_tlv),
+
+	/* Input source controls */
+	SOC_ENUM_EXT("Left Input Source", twl4030_left_input_mux,
+		twl4030_get_left_input, twl4030_put_left_input),
+	SOC_ENUM_EXT("Right Input Source", twl4030_right_input_mux,
+		twl4030_get_right_input, twl4030_put_right_input),
+};
+
+/* add non dapm controls */
+static int twl4030_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(twl4030_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				  snd_soc_cnew(&twl4030_snd_controls[i],
+						codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("INL"),
+	SND_SOC_DAPM_INPUT("INR"),
+
+	SND_SOC_DAPM_OUTPUT("OUTL"),
+	SND_SOC_DAPM_OUTPUT("OUTR"),
+	SND_SOC_DAPM_OUTPUT("EARPIECE"),
+	SND_SOC_DAPM_OUTPUT("PREDRIVEL"),
+	SND_SOC_DAPM_OUTPUT("PREDRIVER"),
+	SND_SOC_DAPM_OUTPUT("HSOL"),
+	SND_SOC_DAPM_OUTPUT("HSOR"),
+	SND_SOC_DAPM_OUTPUT("CARKITL"),
+	SND_SOC_DAPM_OUTPUT("CARKITR"),
+	SND_SOC_DAPM_OUTPUT("HFL"),
+	SND_SOC_DAPM_OUTPUT("HFR"),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback",
+			TWL4030_REG_AVDAC_CTL, 0, 0),
+	SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback",
+			TWL4030_REG_AVDAC_CTL, 1, 0),
+	SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback",
+			TWL4030_REG_AVDAC_CTL, 2, 0),
+	SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback",
+			TWL4030_REG_AVDAC_CTL, 3, 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),
+
+	/* Output MUX controls */
+	/* Earpiece */
+	SND_SOC_DAPM_MUX_E("Earpiece Mux", SND_SOC_NOPM, 0, 0,
+		&twl4030_dapm_earpiece_control, outmixer_event,
+		SND_SOC_DAPM_PRE_REG),
+	/* PreDrivL/R */
+	SND_SOC_DAPM_MUX_E("PredriveL Mux", SND_SOC_NOPM, 0, 0,
+		&twl4030_dapm_predrivel_control, outmixer_event,
+		SND_SOC_DAPM_PRE_REG),
+	SND_SOC_DAPM_MUX_E("PredriveR Mux", SND_SOC_NOPM, 0, 0,
+		&twl4030_dapm_predriver_control, outmixer_event,
+		SND_SOC_DAPM_PRE_REG),
+	/* HeadsetL/R */
+	SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0,
+		&twl4030_dapm_hsol_control),
+	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_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	{"ARXL1_APGA", NULL, "DAC Left1"},
+	{"ARXR1_APGA", NULL, "DAC Right1"},
+	{"ARXL2_APGA", NULL, "DAC Left2"},
+	{"ARXR2_APGA", NULL, "DAC Right2"},
+
+	/* Internal playback routings */
+	/* Earpiece */
+	{"Earpiece Mux", "DACL1", "ARXL1_APGA"},
+	{"Earpiece Mux", "DACL2", "ARXL2_APGA"},
+	{"Earpiece Mux", "DACR1", "ARXR1_APGA"},
+	/* PreDrivL */
+	{"PredriveL Mux", "DACL1", "ARXL1_APGA"},
+	{"PredriveL Mux", "DACL2", "ARXL2_APGA"},
+	{"PredriveL Mux", "DACR2", "ARXR2_APGA"},
+	/* PreDrivR */
+	{"PredriveR Mux", "DACR1", "ARXR1_APGA"},
+	{"PredriveR Mux", "DACR2", "ARXR2_APGA"},
+	{"PredriveR Mux", "DACL2", "ARXL2_APGA"},
+	/* HeadsetL */
+	{"HeadsetL Mux", "DACL1", "ARXL1_APGA"},
+	{"HeadsetL Mux", "DACL2", "ARXL2_APGA"},
+	/* HeadsetR */
+	{"HeadsetR Mux", "DACR1", "ARXR1_APGA"},
+	{"HeadsetR Mux", "DACR2", "ARXR2_APGA"},
+	/* CarkitL */
+	{"CarkitL Mux", "DACL1", "ARXL1_APGA"},
+	{"CarkitL Mux", "DACL2", "ARXL2_APGA"},
+	/* CarkitR */
+	{"CarkitR Mux", "DACR1", "ARXR1_APGA"},
+	{"CarkitR Mux", "DACR2", "ARXR2_APGA"},
+	/* HandsfreeL */
+	{"HandsfreeL Mux", "DACL1", "ARXL1_APGA"},
+	{"HandsfreeL Mux", "DACL2", "ARXL2_APGA"},
+	{"HandsfreeL Mux", "DACR2", "ARXR2_APGA"},
+	/* HandsfreeR */
+	{"HandsfreeR Mux", "DACR1", "ARXR1_APGA"},
+	{"HandsfreeR Mux", "DACR2", "ARXR2_APGA"},
+	{"HandsfreeR Mux", "DACL2", "ARXL2_APGA"},
+
+	/* 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"},
+
+	/* inputs */
+	{"ADCL", NULL, "INL"},
+	{"ADCR", NULL, "INR"},
+};
+
+static int twl4030_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, twl4030_dapm_widgets,
+				 ARRAY_SIZE(twl4030_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+	snd_soc_dapm_new_widgets(codec);
+	return 0;
+}
+
+static void twl4030_power_up(struct snd_soc_codec *codec)
+{
+	u8 anamicl, regmisc1, byte, popn;
+	int i = 0;
+
+	/* set CODECPDZ to turn on codec */
+	twl4030_set_codecpdz(codec);
+
+	/* initiate offset cancellation */
+	anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+	twl4030_write(codec, TWL4030_REG_ANAMICL,
+		anamicl | TWL4030_CNCL_OFFSET_START);
+
+	/* wait for offset cancellation to complete */
+	do {
+		/* this takes a little while, so don't slam i2c */
+		udelay(2000);
+		twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
+				    TWL4030_REG_ANAMICL);
+	} while ((i++ < 100) &&
+		 ((byte & TWL4030_CNCL_OFFSET_START) ==
+		  TWL4030_CNCL_OFFSET_START));
+
+	/* anti-pop when changing analog gain */
+	regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
+	twl4030_write(codec, TWL4030_REG_MISC_SET_1,
+		regmisc1 | TWL4030_SMOOTH_ANAVOL_EN);
+
+	/* toggle CODECPDZ as per TRM */
+	twl4030_clear_codecpdz(codec);
+	twl4030_set_codecpdz(codec);
+
+	/* program anti-pop with bias ramp delay */
+	popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+	popn &= TWL4030_RAMP_DELAY;
+	popn |=	TWL4030_RAMP_DELAY_645MS;
+	twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
+	popn |=	TWL4030_VMID_EN;
+	twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
+
+	/* enable anti-pop ramp */
+	popn |= TWL4030_RAMP_EN;
+	twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
+}
+
+static void twl4030_power_down(struct snd_soc_codec *codec)
+{
+	u8 popn;
+
+	/* disable anti-pop ramp */
+	popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+	popn &= ~TWL4030_RAMP_EN;
+	twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
+
+	/* disable bias out */
+	popn &= ~TWL4030_VMID_EN;
+	twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
+
+	/* power down */
+	twl4030_clear_codecpdz(codec);
+}
+
+static int twl4030_set_bias_level(struct snd_soc_codec *codec,
+				  enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		twl4030_power_up(codec);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* TODO: develop a twl4030_prepare function */
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* TODO: develop a twl4030_standby function */
+		twl4030_power_down(codec);
+		break;
+	case SND_SOC_BIAS_OFF:
+		twl4030_power_down(codec);
+		break;
+	}
+	codec->bias_level = level;
+
+	return 0;
+}
+
+static int twl4030_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->codec;
+	u8 mode, old_mode, format, old_format;
+
+
+	/* bit rate */
+	old_mode = twl4030_read_reg_cache(codec,
+			TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
+	mode = old_mode & ~TWL4030_APLL_RATE;
+
+	switch (params_rate(params)) {
+	case 8000:
+		mode |= TWL4030_APLL_RATE_8000;
+		break;
+	case 11025:
+		mode |= TWL4030_APLL_RATE_11025;
+		break;
+	case 12000:
+		mode |= TWL4030_APLL_RATE_12000;
+		break;
+	case 16000:
+		mode |= TWL4030_APLL_RATE_16000;
+		break;
+	case 22050:
+		mode |= TWL4030_APLL_RATE_22050;
+		break;
+	case 24000:
+		mode |= TWL4030_APLL_RATE_24000;
+		break;
+	case 32000:
+		mode |= TWL4030_APLL_RATE_32000;
+		break;
+	case 44100:
+		mode |= TWL4030_APLL_RATE_44100;
+		break;
+	case 48000:
+		mode |= TWL4030_APLL_RATE_48000;
+		break;
+	default:
+		printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	if (mode != old_mode) {
+		/* change rate and set CODECPDZ */
+		twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+		twl4030_set_codecpdz(codec);
+	}
+
+	/* sample size */
+	old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+	format = old_format;
+	format &= ~TWL4030_DATA_WIDTH;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		format |= TWL4030_DATA_WIDTH_16S_16W;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		format |= TWL4030_DATA_WIDTH_32S_24W;
+		break;
+	default:
+		printk(KERN_ERR "TWL4030 hw params: unknown format %d\n",
+			params_format(params));
+		return -EINVAL;
+	}
+
+	if (format != old_format) {
+
+		/* clear CODECPDZ before changing format (codec requirement) */
+		twl4030_clear_codecpdz(codec);
+
+		/* change format */
+		twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+
+		/* set CODECPDZ afterwards */
+		twl4030_set_codecpdz(codec);
+	}
+	return 0;
+}
+
+static int twl4030_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 19200000:
+		infreq = TWL4030_APLL_INFREQ_19200KHZ;
+		break;
+	case 26000000:
+		infreq = TWL4030_APLL_INFREQ_26000KHZ;
+		break;
+	case 38400000:
+		infreq = TWL4030_APLL_INFREQ_38400KHZ;
+		break;
+	default:
+		printk(KERN_ERR "TWL4030 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_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_AUDIO_IF);
+	format = old_format;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		format &= ~(TWL4030_AIF_SLAVE_EN);
+		format &= ~(TWL4030_CLK256FS_EN);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		format |= TWL4030_AIF_SLAVE_EN;
+		format |= TWL4030_CLK256FS_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	format &= ~TWL4030_AIF_FORMAT;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format |= TWL4030_AIF_FORMAT_CODEC;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (format != old_format) {
+
+		/* clear CODECPDZ before changing format (codec requirement) */
+		twl4030_clear_codecpdz(codec);
+
+		/* change format */
+		twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+
+		/* set CODECPDZ afterwards */
+		twl4030_set_codecpdz(codec);
+	}
+
+	return 0;
+}
+
+#define TWL4030_RATES	 (SNDRV_PCM_RATE_8000_48000)
+#define TWL4030_FORMATS	 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
+
+struct snd_soc_dai twl4030_dai = {
+	.name = "twl4030",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = TWL4030_RATES,
+		.formats = TWL4030_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = TWL4030_RATES,
+		.formats = TWL4030_FORMATS,},
+	.ops = {
+		.hw_params = twl4030_hw_params,
+		.set_sysclk = twl4030_set_dai_sysclk,
+		.set_fmt = twl4030_set_dai_fmt,
+	}
+};
+EXPORT_SYMBOL_GPL(twl4030_dai);
+
+static int twl4030_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int twl4030_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	twl4030_set_bias_level(codec, codec->suspend_bias_level);
+	return 0;
+}
+
+/*
+ * initialize the driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+
+static int twl4030_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret = 0;
+
+	printk(KERN_INFO "TWL4030 Audio Codec init \n");
+
+	codec->name = "twl4030";
+	codec->owner = THIS_MODULE;
+	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->reg_cache_size = sizeof(twl4030_reg);
+	codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
+					GFP_KERNEL);
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "twl4030: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	twl4030_init_chip(codec);
+
+	/* power on device */
+	twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	twl4030_add_controls(codec);
+	twl4030_add_widgets(codec);
+
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "twl4030: failed to register card\n");
+		goto card_err;
+	}
+
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+
+static struct snd_soc_device *twl4030_socdev;
+
+static int twl4030_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	twl4030_socdev = socdev;
+	twl4030_init(socdev);
+
+	return 0;
+}
+
+static int twl4030_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	printk(KERN_INFO "TWL4030 Audio Codec remove\n");
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_twl4030 = {
+	.probe = twl4030_probe,
+	.remove = twl4030_remove,
+	.suspend = twl4030_suspend,
+	.resume = twl4030_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
+
+static int __init twl4030_modinit(void)
+{
+	return snd_soc_register_dai(&twl4030_dai);
+}
+module_init(twl4030_modinit);
+
+static void __exit twl4030_exit(void)
+{
+	snd_soc_unregister_dai(&twl4030_dai);
+}
+module_exit(twl4030_exit);
+
+MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
+MODULE_AUTHOR("Steve Sakoman");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
new file mode 100644
index 0000000..54615c7
--- /dev/null
+++ b/sound/soc/codecs/twl4030.h
@@ -0,0 +1,219 @@
+/*
+ * ALSA SoC TWL4030 codec driver
+ *
+ * Author: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TWL4030_AUDIO_H__
+#define __TWL4030_AUDIO_H__
+
+#define TWL4030_REG_CODEC_MODE		0x1
+#define TWL4030_REG_OPTION		0x2
+#define TWL4030_REG_UNKNOWN		0x3
+#define TWL4030_REG_MICBIAS_CTL		0x4
+#define TWL4030_REG_ANAMICL		0x5
+#define TWL4030_REG_ANAMICR		0x6
+#define TWL4030_REG_AVADC_CTL		0x7
+#define TWL4030_REG_ADCMICSEL		0x8
+#define TWL4030_REG_DIGMIXING		0x9
+#define TWL4030_REG_ATXL1PGA		0xA
+#define TWL4030_REG_ATXR1PGA		0xB
+#define TWL4030_REG_AVTXL2PGA		0xC
+#define TWL4030_REG_AVTXR2PGA		0xD
+#define TWL4030_REG_AUDIO_IF		0xE
+#define TWL4030_REG_VOICE_IF		0xF
+#define TWL4030_REG_ARXR1PGA		0x10
+#define TWL4030_REG_ARXL1PGA		0x11
+#define TWL4030_REG_ARXR2PGA		0x12
+#define TWL4030_REG_ARXL2PGA		0x13
+#define TWL4030_REG_VRXPGA		0x14
+#define TWL4030_REG_VSTPGA		0x15
+#define TWL4030_REG_VRX2ARXPGA		0x16
+#define TWL4030_REG_AVDAC_CTL		0x17
+#define TWL4030_REG_ARX2VTXPGA		0x18
+#define TWL4030_REG_ARXL1_APGA_CTL	0x19
+#define TWL4030_REG_ARXR1_APGA_CTL	0x1A
+#define TWL4030_REG_ARXL2_APGA_CTL	0x1B
+#define TWL4030_REG_ARXR2_APGA_CTL	0x1C
+#define TWL4030_REG_ATX2ARXPGA		0x1D
+#define TWL4030_REG_BT_IF		0x1E
+#define TWL4030_REG_BTPGA		0x1F
+#define TWL4030_REG_BTSTPGA		0x20
+#define TWL4030_REG_EAR_CTL		0x21
+#define TWL4030_REG_HS_SEL		0x22
+#define TWL4030_REG_HS_GAIN_SET		0x23
+#define TWL4030_REG_HS_POPN_SET		0x24
+#define TWL4030_REG_PREDL_CTL		0x25
+#define TWL4030_REG_PREDR_CTL		0x26
+#define TWL4030_REG_PRECKL_CTL		0x27
+#define TWL4030_REG_PRECKR_CTL		0x28
+#define TWL4030_REG_HFL_CTL		0x29
+#define TWL4030_REG_HFR_CTL		0x2A
+#define TWL4030_REG_ALC_CTL		0x2B
+#define TWL4030_REG_ALC_SET1		0x2C
+#define TWL4030_REG_ALC_SET2		0x2D
+#define TWL4030_REG_BOOST_CTL		0x2E
+#define TWL4030_REG_SOFTVOL_CTL		0x2F
+#define TWL4030_REG_DTMF_FREQSEL	0x30
+#define TWL4030_REG_DTMF_TONEXT1H	0x31
+#define TWL4030_REG_DTMF_TONEXT1L	0x32
+#define TWL4030_REG_DTMF_TONEXT2H	0x33
+#define TWL4030_REG_DTMF_TONEXT2L	0x34
+#define TWL4030_REG_DTMF_TONOFF		0x35
+#define TWL4030_REG_DTMF_WANONOFF	0x36
+#define TWL4030_REG_I2S_RX_SCRAMBLE_H	0x37
+#define TWL4030_REG_I2S_RX_SCRAMBLE_M	0x38
+#define TWL4030_REG_I2S_RX_SCRAMBLE_L	0x39
+#define TWL4030_REG_APLL_CTL		0x3A
+#define TWL4030_REG_DTMF_CTL		0x3B
+#define TWL4030_REG_DTMF_PGA_CTL2	0x3C
+#define TWL4030_REG_DTMF_PGA_CTL1	0x3D
+#define TWL4030_REG_MISC_SET_1		0x3E
+#define TWL4030_REG_PCMBTMUX		0x3F
+#define TWL4030_REG_RX_PATH_SEL		0x43
+#define TWL4030_REG_VDL_APGA_CTL	0x44
+#define TWL4030_REG_VIBRA_CTL		0x45
+#define TWL4030_REG_VIBRA_SET		0x46
+#define TWL4030_REG_VIBRA_PWM_SET	0x47
+#define TWL4030_REG_ANAMIC_GAIN		0x48
+#define TWL4030_REG_MISC_SET_2		0x49
+
+#define TWL4030_CACHEREGNUM	(TWL4030_REG_MISC_SET_2 + 1)
+
+/* Bitfield Definitions */
+
+/* TWL4030_CODEC_MODE (0x01) Fields */
+
+#define TWL4030_APLL_RATE		0xF0
+#define TWL4030_APLL_RATE_8000		0x00
+#define TWL4030_APLL_RATE_11025		0x10
+#define TWL4030_APLL_RATE_12000		0x20
+#define TWL4030_APLL_RATE_16000		0x40
+#define TWL4030_APLL_RATE_22050		0x50
+#define TWL4030_APLL_RATE_24000		0x60
+#define TWL4030_APLL_RATE_32000		0x80
+#define TWL4030_APLL_RATE_44100		0x90
+#define TWL4030_APLL_RATE_48000		0xA0
+#define TWL4030_SEL_16K			0x04
+#define TWL4030_CODECPDZ		0x02
+#define TWL4030_OPT_MODE		0x01
+
+/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */
+
+#define TWL4030_MICBIAS2_CTL		0x40
+#define TWL4030_MICBIAS1_CTL		0x20
+#define TWL4030_HSMICBIAS_EN		0x04
+#define TWL4030_MICBIAS2_EN		0x02
+#define TWL4030_MICBIAS1_EN		0x01
+
+/* ANAMICL (0x05) Fields */
+
+#define TWL4030_CNCL_OFFSET_START	0x80
+#define TWL4030_OFFSET_CNCL_SEL		0x60
+#define TWL4030_OFFSET_CNCL_SEL_ARX1	0x00
+#define TWL4030_OFFSET_CNCL_SEL_ARX2	0x20
+#define TWL4030_OFFSET_CNCL_SEL_VRX	0x40
+#define TWL4030_OFFSET_CNCL_SEL_ALL	0x60
+#define TWL4030_MICAMPL_EN		0x10
+#define TWL4030_CKMIC_EN		0x08
+#define TWL4030_AUXL_EN			0x04
+#define TWL4030_HSMIC_EN		0x02
+#define TWL4030_MAINMIC_EN		0x01
+
+/* ANAMICR (0x06) Fields */
+
+#define TWL4030_MICAMPR_EN		0x10
+#define TWL4030_AUXR_EN			0x04
+#define TWL4030_SUBMIC_EN		0x01
+
+/* AVADC_CTL (0x07) Fields */
+
+#define TWL4030_ADCL_EN			0x08
+#define TWL4030_AVADC_CLK_PRIORITY	0x04
+#define TWL4030_ADCR_EN			0x02
+
+/* AUDIO_IF (0x0E) Fields */
+
+#define TWL4030_AIF_SLAVE_EN		0x80
+#define TWL4030_DATA_WIDTH		0x60
+#define TWL4030_DATA_WIDTH_16S_16W	0x00
+#define TWL4030_DATA_WIDTH_32S_16W	0x40
+#define TWL4030_DATA_WIDTH_32S_24W	0x60
+#define TWL4030_AIF_FORMAT		0x18
+#define TWL4030_AIF_FORMAT_CODEC	0x00
+#define TWL4030_AIF_FORMAT_LEFT		0x08
+#define TWL4030_AIF_FORMAT_RIGHT	0x10
+#define TWL4030_AIF_FORMAT_TDM		0x18
+#define TWL4030_AIF_TRI_EN		0x04
+#define TWL4030_CLK256FS_EN		0x02
+#define TWL4030_AIF_EN			0x01
+
+/* HS_GAIN_SET (0x23) Fields */
+
+#define TWL4030_HSR_GAIN		0x0C
+#define TWL4030_HSR_GAIN_PWR_DOWN	0x00
+#define TWL4030_HSR_GAIN_PLUS_6DB	0x04
+#define TWL4030_HSR_GAIN_0DB		0x08
+#define TWL4030_HSR_GAIN_MINUS_6DB	0x0C
+#define TWL4030_HSL_GAIN		0x03
+#define TWL4030_HSL_GAIN_PWR_DOWN	0x00
+#define TWL4030_HSL_GAIN_PLUS_6DB	0x01
+#define TWL4030_HSL_GAIN_0DB		0x02
+#define TWL4030_HSL_GAIN_MINUS_6DB	0x03
+
+/* HS_POPN_SET (0x24) Fields */
+
+#define TWL4030_VMID_EN			0x40
+#define	TWL4030_EXTMUTE			0x20
+#define TWL4030_RAMP_DELAY		0x1C
+#define TWL4030_RAMP_DELAY_20MS		0x00
+#define TWL4030_RAMP_DELAY_40MS		0x04
+#define TWL4030_RAMP_DELAY_81MS		0x08
+#define TWL4030_RAMP_DELAY_161MS	0x0C
+#define TWL4030_RAMP_DELAY_323MS	0x10
+#define TWL4030_RAMP_DELAY_645MS	0x14
+#define TWL4030_RAMP_DELAY_1291MS	0x18
+#define TWL4030_RAMP_DELAY_2581MS	0x1C
+#define TWL4030_RAMP_EN			0x02
+
+/* HFL_CTL (0x29, 0x2A) Fields */
+#define TWL4030_HF_CTL_HB_EN		0x04
+#define TWL4030_HF_CTL_LOOP_EN		0x08
+#define TWL4030_HF_CTL_RAMP_EN		0x10
+#define TWL4030_HF_CTL_REF_EN		0x20
+
+/* APLL_CTL (0x3A) Fields */
+
+#define TWL4030_APLL_EN			0x10
+#define TWL4030_APLL_INFREQ		0x0F
+#define TWL4030_APLL_INFREQ_19200KHZ	0x05
+#define TWL4030_APLL_INFREQ_26000KHZ	0x06
+#define TWL4030_APLL_INFREQ_38400KHZ	0x0F
+
+/* REG_MISC_SET_1 (0x3E) Fields */
+
+#define TWL4030_CLK64_EN		0x80
+#define TWL4030_SCRAMBLE_EN		0x40
+#define TWL4030_FMLOOP_EN		0x20
+#define TWL4030_SMOOTH_ANAVOL_EN	0x02
+#define TWL4030_DIGMIC_LR_SWAP_EN	0x01
+
+extern struct snd_soc_dai twl4030_dai;
+extern struct snd_soc_codec_device soc_codec_dev_twl4030;
+
+#endif	/* End of __TWL4030_AUDIO_H__ */
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
new file mode 100644
index 0000000..a2c5064
--- /dev/null
+++ b/sound/soc/codecs/uda134x.c
@@ -0,0 +1,668 @@
+/*
+ * uda134x.c  --  UDA134X ALSA SoC Codec driver
+ *
+ * Modifications by Christian Pellegrin <chripell@evolware.org>
+ *
+ * Copyright 2007 Dension Audio Systems Ltd.
+ * Author: Zoltan Devai
+ *
+ * Based on the WM87xx drivers by Liam Girdwood and 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/module.h>
+#include <linux/delay.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/uda134x.h>
+#include <sound/l3.h>
+
+#include "uda134x.h"
+
+
+#define POWER_OFF_ON_STANDBY 1
+/*
+  ALSA SOC usually puts the device in standby mode when it's not used
+  for sometime. If you define POWER_OFF_ON_STANDBY the driver will
+  turn off the ADC/DAC when this callback is invoked and turn it back
+  on when needed. Unfortunately this will result in a very light bump
+  (it can be audible only with good earphones). If this bothers you
+  just comment this line, you will have slightly higher power
+  consumption . Please note that sending the L3 command for ADC is
+  enough to make the bump, so it doesn't make difference if you
+  completely take off power from the codec.
+ */
+
+#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000
+#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
+		SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
+
+struct uda134x_priv {
+	int sysclk;
+	int dai_fmt;
+
+	struct snd_pcm_substream *master_substream;
+	struct snd_pcm_substream *slave_substream;
+};
+
+/* In-data addresses are hard-coded into the reg-cache values */
+static const char uda134x_reg[UDA134X_REGS_NUM] = {
+	/* Extended address registers */
+	0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* Status, data regs */
+	0x00, 0x83, 0x00, 0x40, 0x80, 0x00,
+};
+
+/*
+ * The codec has no support for reading its registers except for peak level...
+ */
+static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u8 *cache = codec->reg_cache;
+
+	if (reg >= UDA134X_REGS_NUM)
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * Write the register cache
+ */
+static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec,
+	u8 reg, unsigned int value)
+{
+	u8 *cache = codec->reg_cache;
+
+	if (reg >= UDA134X_REGS_NUM)
+		return;
+	cache[reg] = value;
+}
+
+/*
+ * Write to the uda134x registers
+ *
+ */
+static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	int ret;
+	u8 addr;
+	u8 data = value;
+	struct uda134x_platform_data *pd = codec->control_data;
+
+	pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value);
+
+	if (reg >= UDA134X_REGS_NUM) {
+		printk(KERN_ERR "%s unkown register: reg: %d",
+		       __func__, reg);
+		return -EINVAL;
+	}
+
+	uda134x_write_reg_cache(codec, reg, value);
+
+	switch (reg) {
+	case UDA134X_STATUS0:
+	case UDA134X_STATUS1:
+		addr = UDA134X_STATUS_ADDR;
+		break;
+	case UDA134X_DATA000:
+	case UDA134X_DATA001:
+	case UDA134X_DATA010:
+		addr = UDA134X_DATA0_ADDR;
+		break;
+	case UDA134X_DATA1:
+		addr = UDA134X_DATA1_ADDR;
+		break;
+	default:
+		/* It's an extended address register */
+		addr =  (reg | UDA134X_EXTADDR_PREFIX);
+
+		ret = l3_write(&pd->l3,
+			       UDA134X_DATA0_ADDR, &addr, 1);
+		if (ret != 1)
+			return -EIO;
+
+		addr = UDA134X_DATA0_ADDR;
+		data = (value | UDA134X_EXTDATA_PREFIX);
+		break;
+	}
+
+	ret = l3_write(&pd->l3,
+		       addr, &data, 1);
+	if (ret != 1)
+		return -EIO;
+
+	return 0;
+}
+
+static inline void uda134x_reset(struct snd_soc_codec *codec)
+{
+	u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
+	uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6));
+	msleep(1);
+	uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6));
+}
+
+static int uda134x_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010);
+
+	pr_debug("%s mute: %d\n", __func__, mute);
+
+	if (mute)
+		mute_reg |= (1<<2);
+	else
+		mute_reg &= ~(1<<2);
+
+	uda134x_write(codec, UDA134X_DATA010, mute_reg & ~(1<<2));
+
+	return 0;
+}
+
+static int uda134x_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->codec;
+	struct uda134x_priv *uda134x = codec->private_data;
+	struct snd_pcm_runtime *master_runtime;
+
+	if (uda134x->master_substream) {
+		master_runtime = uda134x->master_substream->runtime;
+
+		pr_debug("%s constraining to %d bits at %d\n", __func__,
+			 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);
+
+		snd_pcm_hw_constraint_minmax(substream->runtime,
+					     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+					     master_runtime->sample_bits,
+					     master_runtime->sample_bits);
+
+		uda134x->slave_substream = substream;
+	} else
+		uda134x->master_substream = substream;
+
+	return 0;
+}
+
+static void uda134x_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->codec;
+	struct uda134x_priv *uda134x = codec->private_data;
+
+	if (uda134x->master_substream == substream)
+		uda134x->master_substream = uda134x->slave_substream;
+
+	uda134x->slave_substream = NULL;
+}
+
+static int uda134x_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->codec;
+	struct uda134x_priv *uda134x = codec->private_data;
+	u8 hw_params;
+
+	if (substream == uda134x->slave_substream) {
+		pr_debug("%s ignoring hw_params for slave substream\n",
+			 __func__);
+		return 0;
+	}
+
+	hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
+	hw_params &= STATUS0_SYSCLK_MASK;
+	hw_params &= STATUS0_DAIFMT_MASK;
+
+	pr_debug("%s sysclk: %d, rate:%d\n", __func__,
+		 uda134x->sysclk, params_rate(params));
+
+	/* set SYSCLK / fs ratio */
+	switch (uda134x->sysclk / params_rate(params)) {
+	case 512:
+		break;
+	case 384:
+		hw_params |= (1<<4);
+		break;
+	case 256:
+		hw_params |= (1<<5);
+		break;
+	default:
+		printk(KERN_ERR "%s unsupported fs\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__,
+		 uda134x->dai_fmt, params_format(params));
+
+	/* set DAI format and word length */
+	switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (params_format(params)) {
+		case SNDRV_PCM_FORMAT_S16_LE:
+			hw_params |= (1<<1);
+			break;
+		case SNDRV_PCM_FORMAT_S18_3LE:
+			hw_params |= (1<<2);
+			break;
+		case SNDRV_PCM_FORMAT_S20_3LE:
+			hw_params |= ((1<<2) | (1<<1));
+			break;
+		default:
+			printk(KERN_ERR "%s unsupported format (right)\n",
+			       __func__);
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		hw_params |= (1<<3);
+		break;
+	default:
+		printk(KERN_ERR "%s unsupported format\n", __func__);
+		return -EINVAL;
+	}
+
+	uda134x_write(codec, UDA134X_STATUS0, hw_params);
+
+	return 0;
+}
+
+static int uda134x_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 uda134x_priv *uda134x = codec->private_data;
+
+	pr_debug("%s clk_id: %d, freq: %d, dir: %d\n", __func__,
+		 clk_id, freq, dir);
+
+	/* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
+	   because the codec is slave. Of course limitations of the clock
+	   master (the IIS controller) apply.
+	   We'll error out on set_hw_params if it's not OK */
+	if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
+		uda134x->sysclk = freq;
+		return 0;
+	}
+
+	printk(KERN_ERR "%s unsupported sysclk\n", __func__);
+	return -EINVAL;
+}
+
+static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			       unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct uda134x_priv *uda134x = codec->private_data;
+
+	pr_debug("%s fmt: %08X\n", __func__, fmt);
+
+	/* codec supports only full slave mode */
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+		printk(KERN_ERR "%s unsupported slave mode\n", __func__);
+		return -EINVAL;
+	}
+
+	/* no support for clock inversion */
+	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
+		printk(KERN_ERR "%s unsupported clock inversion\n", __func__);
+		return -EINVAL;
+	}
+
+	/* We can't setup DAI format here as it depends on the word bit num */
+	/* so let's just store the value for later */
+	uda134x->dai_fmt = fmt;
+
+	return 0;
+}
+
+static int uda134x_set_bias_level(struct snd_soc_codec *codec,
+				  enum snd_soc_bias_level level)
+{
+	u8 reg;
+	struct uda134x_platform_data *pd = codec->control_data;
+	int i;
+	u8 *cache = codec->reg_cache;
+
+	pr_debug("%s bias level %d\n", __func__, level);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* ADC, DAC on */
+		reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
+		uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* power on */
+		if (pd->power) {
+			pd->power(1);
+			/* Sync reg_cache with the hardware */
+			for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
+				codec->write(codec, i, *cache++);
+		}
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* ADC, DAC power off */
+		reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
+		uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03));
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* power off */
+		if (pd->power)
+			pd->power(0);
+		break;
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1",
+					    "Minimum2", "Maximum"};
+static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+static const char *uda134x_mixmode[] = {"Differential", "Analog1",
+					"Analog2", "Both"};
+
+static const struct soc_enum uda134x_mixer_enum[] = {
+SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting),
+SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph),
+SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode),
+};
+
+static const struct snd_kcontrol_new uda1341_snd_controls[] = {
+SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
+SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0),
+SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1),
+SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1),
+
+SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0),
+SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0),
+
+SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
+SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
+
+SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
+SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
+SOC_ENUM("Input Mux", uda134x_mixer_enum[2]),
+
+SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0),
+SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1),
+SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0),
+
+SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0),
+SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0),
+SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0),
+SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0),
+SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0),
+SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new uda1340_snd_controls[] = {
+SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
+
+SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
+SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
+
+SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
+SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
+
+SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
+};
+
+static int uda134x_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i, n;
+	const struct snd_kcontrol_new *ctrls;
+	struct uda134x_platform_data *pd = codec->control_data;
+
+	switch (pd->model) {
+	case UDA134X_UDA1340:
+	case UDA134X_UDA1344:
+		n = ARRAY_SIZE(uda1340_snd_controls);
+		ctrls = uda1340_snd_controls;
+		break;
+	case UDA134X_UDA1341:
+		n = ARRAY_SIZE(uda1341_snd_controls);
+		ctrls = uda1341_snd_controls;
+		break;
+	default:
+		printk(KERN_ERR "%s unkown codec type: %d",
+		       __func__, pd->model);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < n; i++) {
+		err = snd_ctl_add(codec->card,
+				  snd_soc_cnew(&ctrls[i],
+					       codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+struct snd_soc_dai uda134x_dai = {
+	.name = "UDA134X",
+	/* playback capabilities */
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = UDA134X_RATES,
+		.formats = UDA134X_FORMATS,
+	},
+	/* capture capabilities */
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = UDA134X_RATES,
+		.formats = UDA134X_FORMATS,
+	},
+	/* pcm operations */
+	.ops = {
+		.startup = uda134x_startup,
+		.shutdown = uda134x_shutdown,
+		.hw_params = uda134x_hw_params,
+		.digital_mute = uda134x_mute,
+		.set_sysclk = uda134x_set_dai_sysclk,
+		.set_fmt = uda134x_set_dai_fmt,
+	}
+};
+EXPORT_SYMBOL(uda134x_dai);
+
+
+static int uda134x_soc_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	struct uda134x_priv *uda134x;
+	void *codec_setup_data = socdev->codec_data;
+	int ret = -ENOMEM;
+	struct uda134x_platform_data *pd;
+
+	printk(KERN_INFO "UDA134X SoC Audio Codec\n");
+
+	if (!codec_setup_data) {
+		printk(KERN_ERR "UDA134X SoC codec: "
+		       "missing L3 bitbang function\n");
+		return -ENODEV;
+	}
+
+	pd = codec_setup_data;
+	switch (pd->model) {
+	case UDA134X_UDA1340:
+	case UDA134X_UDA1341:
+	case UDA134X_UDA1344:
+		break;
+	default:
+		printk(KERN_ERR "UDA134X SoC codec: "
+		       "unsupported model %d\n",
+			pd->model);
+		return -EINVAL;
+	}
+
+	socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (socdev->codec == NULL)
+		return ret;
+
+	codec = socdev->codec;
+
+	uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
+	if (uda134x == NULL)
+		goto priv_err;
+	codec->private_data = uda134x;
+
+	codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg),
+				   GFP_KERNEL);
+	if (codec->reg_cache == NULL)
+		goto reg_err;
+
+	mutex_init(&codec->mutex);
+
+	codec->reg_cache_size = sizeof(uda134x_reg);
+	codec->reg_cache_step = 1;
+
+	codec->name = "UDA134X";
+	codec->owner = THIS_MODULE;
+	codec->dai = &uda134x_dai;
+	codec->num_dai = 1;
+	codec->read = uda134x_read_reg_cache;
+	codec->write = uda134x_write;
+#ifdef POWER_OFF_ON_STANDBY
+	codec->set_bias_level = uda134x_set_bias_level;
+#endif
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->control_data = codec_setup_data;
+
+	if (pd->power)
+		pd->power(1);
+
+	uda134x_reset(codec);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "UDA134X: failed to register pcms\n");
+		goto pcm_err;
+	}
+
+	ret = uda134x_add_controls(codec);
+	if (ret < 0) {
+		printk(KERN_ERR "UDA134X: failed to register controls\n");
+		goto pcm_err;
+	}
+
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "UDA134X: failed to register card\n");
+		goto card_err;
+	}
+
+	return 0;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+reg_err:
+	kfree(codec->private_data);
+priv_err:
+	kfree(codec);
+	return ret;
+}
+
+/* power down chip */
+static int uda134x_soc_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+
+	kfree(codec->private_data);
+	kfree(codec->reg_cache);
+	kfree(codec);
+
+	return 0;
+}
+
+#if defined(CONFIG_PM)
+static int uda134x_soc_suspend(struct platform_device *pdev,
+						pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int uda134x_soc_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+	uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
+	return 0;
+}
+#else
+#define uda134x_soc_suspend NULL
+#define uda134x_soc_resume NULL
+#endif /* CONFIG_PM */
+
+struct snd_soc_codec_device soc_codec_dev_uda134x = {
+	.probe =        uda134x_soc_probe,
+	.remove =       uda134x_soc_remove,
+	.suspend =      uda134x_soc_suspend,
+	.resume =       uda134x_soc_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x);
+
+static int __init uda134x_init(void)
+{
+	return snd_soc_register_dai(&uda134x_dai);
+}
+module_init(uda134x_init);
+
+static void __exit uda134x_exit(void)
+{
+	snd_soc_unregister_dai(&uda134x_dai);
+}
+module_exit(uda134x_exit);
+
+MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
+MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h
new file mode 100644
index 0000000..94f4404
--- /dev/null
+++ b/sound/soc/codecs/uda134x.h
@@ -0,0 +1,36 @@
+#ifndef _UDA134X_CODEC_H
+#define _UDA134X_CODEC_H
+
+#define UDA134X_L3ADDR	5
+#define UDA134X_DATA0_ADDR	((UDA134X_L3ADDR << 2) | 0)
+#define UDA134X_DATA1_ADDR	((UDA134X_L3ADDR << 2) | 1)
+#define UDA134X_STATUS_ADDR	((UDA134X_L3ADDR << 2) | 2)
+
+#define UDA134X_EXTADDR_PREFIX	0xC0
+#define UDA134X_EXTDATA_PREFIX	0xE0
+
+/* UDA134X registers */
+#define UDA134X_EA000	0
+#define UDA134X_EA001	1
+#define UDA134X_EA010	2
+#define UDA134X_EA011	3
+#define UDA134X_EA100	4
+#define UDA134X_EA101	5
+#define UDA134X_EA110	6
+#define UDA134X_EA111	7
+#define UDA134X_STATUS0 8
+#define UDA134X_STATUS1 9
+#define UDA134X_DATA000 10
+#define UDA134X_DATA001 11
+#define UDA134X_DATA010 12
+#define UDA134X_DATA1	13
+
+#define UDA134X_REGS_NUM 14
+
+#define STATUS0_DAIFMT_MASK (~(7<<1))
+#define STATUS0_SYSCLK_MASK (~(3<<4))
+
+extern struct snd_soc_dai uda134x_dai;
+extern struct snd_soc_codec_device soc_codec_dev_uda134x;
+
+#endif
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index a69ee72..e6bf084 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -407,7 +407,8 @@
  * when the DAI is being clocked by the CPU DAI. It's up to the
  * machine and cpu DAI driver to do this before we are called.
  */
-static int uda1380_pcm_prepare(struct snd_pcm_substream *substream)
+static int uda1380_pcm_prepare(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;
@@ -439,7 +440,8 @@
 }
 
 static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+				 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;
@@ -477,7 +479,8 @@
 	return 0;
 }
 
-static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream)
+static void uda1380_pcm_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;
@@ -560,8 +563,6 @@
 		.hw_params = uda1380_pcm_hw_params,
 		.shutdown = uda1380_pcm_shutdown,
 		.prepare = uda1380_pcm_prepare,
-	},
-	.dai_ops = {
 		.digital_mute = uda1380_mute,
 		.set_fmt = uda1380_set_dai_fmt,
 	},
@@ -579,8 +580,6 @@
 		.hw_params = uda1380_pcm_hw_params,
 		.shutdown = uda1380_pcm_shutdown,
 		.prepare = uda1380_pcm_prepare,
-	},
-	.dai_ops = {
 		.digital_mute = uda1380_mute,
 		.set_fmt = uda1380_set_dai_fmt,
 	},
@@ -598,8 +597,6 @@
 		.hw_params = uda1380_pcm_hw_params,
 		.shutdown = uda1380_pcm_shutdown,
 		.prepare = uda1380_pcm_prepare,
-	},
-	.dai_ops = {
 		.set_fmt = uda1380_set_dai_fmt,
 	},
 },
@@ -680,7 +677,7 @@
 	/* uda1380 init */
 	uda1380_add_controls(codec);
 	uda1380_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		pr_err("uda1380: failed to register card\n");
 		goto card_err;
@@ -844,6 +841,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
 
+static int __init uda1380_modinit(void)
+{
+	return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
+}
+module_init(uda1380_modinit);
+
+static void __exit uda1380_exit(void)
+{
+	snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
+}
+module_exit(uda1380_exit);
+
 MODULE_AUTHOR("Giorgio Padrin");
 MODULE_DESCRIPTION("Audio support for codec Philips UDA1380");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
new file mode 100644
index 0000000..e3989d4
--- /dev/null
+++ b/sound/soc/codecs/wm8350.c
@@ -0,0 +1,1583 @@
+/*
+ * wm8350.c -- WM8350 ALSA SoC audio driver
+ *
+ * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <lg@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/platform_device.h>
+#include <linux/mfd/wm8350/audio.h>
+#include <linux/mfd/wm8350/core.h>
+#include <linux/regulator/consumer.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 "wm8350.h"
+
+#define WM8350_OUTn_0dB 0x39
+
+#define WM8350_RAMP_NONE	0
+#define WM8350_RAMP_UP		1
+#define WM8350_RAMP_DOWN	2
+
+/* We only include the analogue supplies here; the digital supplies
+ * need to be available well before this driver can be probed.
+ */
+static const char *supply_names[] = {
+	"AVDD",
+	"HPVDD",
+};
+
+struct wm8350_output {
+	u16 active;
+	u16 left_vol;
+	u16 right_vol;
+	u16 ramp;
+	u16 mute;
+};
+
+struct wm8350_data {
+	struct snd_soc_codec codec;
+	struct wm8350_output out1;
+	struct wm8350_output out2;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+};
+
+static unsigned int wm8350_codec_cache_read(struct snd_soc_codec *codec,
+					    unsigned int reg)
+{
+	struct wm8350 *wm8350 = codec->control_data;
+	return wm8350->reg_cache[reg];
+}
+
+static unsigned int wm8350_codec_read(struct snd_soc_codec *codec,
+				      unsigned int reg)
+{
+	struct wm8350 *wm8350 = codec->control_data;
+	return wm8350_reg_read(wm8350, reg);
+}
+
+static int wm8350_codec_write(struct snd_soc_codec *codec, unsigned int reg,
+			      unsigned int value)
+{
+	struct wm8350 *wm8350 = codec->control_data;
+	return wm8350_reg_write(wm8350, reg, value);
+}
+
+/*
+ * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown.
+ */
+static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec)
+{
+	struct wm8350_data *wm8350_data = codec->private_data;
+	struct wm8350_output *out1 = &wm8350_data->out1;
+	struct wm8350 *wm8350 = codec->control_data;
+	int left_complete = 0, right_complete = 0;
+	u16 reg, val;
+
+	/* left channel */
+	reg = wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME);
+	val = (reg & WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
+
+	if (out1->ramp == WM8350_RAMP_UP) {
+		/* ramp step up */
+		if (val < out1->left_vol) {
+			val++;
+			reg &= ~WM8350_OUT1L_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME,
+					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
+		} else
+			left_complete = 1;
+	} else if (out1->ramp == WM8350_RAMP_DOWN) {
+		/* ramp step down */
+		if (val > 0) {
+			val--;
+			reg &= ~WM8350_OUT1L_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME,
+					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
+		} else
+			left_complete = 1;
+	} else
+		return 1;
+
+	/* right channel */
+	reg = wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME);
+	val = (reg & WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
+	if (out1->ramp == WM8350_RAMP_UP) {
+		/* ramp step up */
+		if (val < out1->right_vol) {
+			val++;
+			reg &= ~WM8350_OUT1R_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME,
+					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
+		} else
+			right_complete = 1;
+	} else if (out1->ramp == WM8350_RAMP_DOWN) {
+		/* ramp step down */
+		if (val > 0) {
+			val--;
+			reg &= ~WM8350_OUT1R_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME,
+					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
+		} else
+			right_complete = 1;
+	}
+
+	/* only hit the update bit if either volume has changed this step */
+	if (!left_complete || !right_complete)
+		wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME, WM8350_OUT1_VU);
+
+	return left_complete & right_complete;
+}
+
+/*
+ * Ramp OUT2 PGA volume to minimise pops at stream startup and shutdown.
+ */
+static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec)
+{
+	struct wm8350_data *wm8350_data = codec->private_data;
+	struct wm8350_output *out2 = &wm8350_data->out2;
+	struct wm8350 *wm8350 = codec->control_data;
+	int left_complete = 0, right_complete = 0;
+	u16 reg, val;
+
+	/* left channel */
+	reg = wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME);
+	val = (reg & WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
+	if (out2->ramp == WM8350_RAMP_UP) {
+		/* ramp step up */
+		if (val < out2->left_vol) {
+			val++;
+			reg &= ~WM8350_OUT2L_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME,
+					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
+		} else
+			left_complete = 1;
+	} else if (out2->ramp == WM8350_RAMP_DOWN) {
+		/* ramp step down */
+		if (val > 0) {
+			val--;
+			reg &= ~WM8350_OUT2L_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME,
+					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
+		} else
+			left_complete = 1;
+	} else
+		return 1;
+
+	/* right channel */
+	reg = wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME);
+	val = (reg & WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
+	if (out2->ramp == WM8350_RAMP_UP) {
+		/* ramp step up */
+		if (val < out2->right_vol) {
+			val++;
+			reg &= ~WM8350_OUT2R_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME,
+					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
+		} else
+			right_complete = 1;
+	} else if (out2->ramp == WM8350_RAMP_DOWN) {
+		/* ramp step down */
+		if (val > 0) {
+			val--;
+			reg &= ~WM8350_OUT2R_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME,
+					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
+		} else
+			right_complete = 1;
+	}
+
+	/* only hit the update bit if either volume has changed this step */
+	if (!left_complete || !right_complete)
+		wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME, WM8350_OUT2_VU);
+
+	return left_complete & right_complete;
+}
+
+/*
+ * This work ramps both output PGAs at stream start/stop time to
+ * minimise pop associated with DAPM power switching.
+ * It's best to enable Zero Cross when ramping occurs to minimise any
+ * zipper noises.
+ */
+static void wm8350_pga_work(struct work_struct *work)
+{
+	struct snd_soc_codec *codec =
+	    container_of(work, struct snd_soc_codec, delayed_work.work);
+	struct wm8350_data *wm8350_data = codec->private_data;
+	struct wm8350_output *out1 = &wm8350_data->out1,
+	    *out2 = &wm8350_data->out2;
+	int i, out1_complete, out2_complete;
+
+	/* do we need to ramp at all ? */
+	if (out1->ramp == WM8350_RAMP_NONE && out2->ramp == WM8350_RAMP_NONE)
+		return;
+
+	/* PGA volumes have 6 bits of resolution to ramp */
+	for (i = 0; i <= 63; i++) {
+		out1_complete = 1, out2_complete = 1;
+		if (out1->ramp != WM8350_RAMP_NONE)
+			out1_complete = wm8350_out1_ramp_step(codec);
+		if (out2->ramp != WM8350_RAMP_NONE)
+			out2_complete = wm8350_out2_ramp_step(codec);
+
+		/* ramp finished ? */
+		if (out1_complete && out2_complete)
+			break;
+
+		/* we need to delay longer on the up ramp */
+		if (out1->ramp == WM8350_RAMP_UP ||
+		    out2->ramp == WM8350_RAMP_UP) {
+			/* delay is longer over 0dB as increases are larger */
+			if (i >= WM8350_OUTn_0dB)
+				schedule_timeout_interruptible(msecs_to_jiffies
+							       (2));
+			else
+				schedule_timeout_interruptible(msecs_to_jiffies
+							       (1));
+		} else
+			udelay(50);	/* doesn't matter if we delay longer */
+	}
+
+	out1->ramp = WM8350_RAMP_NONE;
+	out2->ramp = WM8350_RAMP_NONE;
+}
+
+/*
+ * WM8350 Controls
+ */
+
+static int pga_event(struct snd_soc_dapm_widget *w,
+		     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct wm8350_data *wm8350_data = codec->private_data;
+	struct wm8350_output *out;
+
+	switch (w->shift) {
+	case 0:
+	case 1:
+		out = &wm8350_data->out1;
+		break;
+	case 2:
+	case 3:
+		out = &wm8350_data->out2;
+		break;
+
+	default:
+		BUG();
+		return -1;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		out->ramp = WM8350_RAMP_UP;
+		out->active = 1;
+
+		if (!delayed_work_pending(&codec->delayed_work))
+			schedule_delayed_work(&codec->delayed_work,
+					      msecs_to_jiffies(1));
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		out->ramp = WM8350_RAMP_DOWN;
+		out->active = 0;
+
+		if (!delayed_work_pending(&codec->delayed_work))
+			schedule_delayed_work(&codec->delayed_work,
+					      msecs_to_jiffies(1));
+		break;
+	}
+
+	return 0;
+}
+
+static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8350_data *wm8350_priv = codec->private_data;
+	struct wm8350_output *out = NULL;
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	int ret;
+	unsigned int reg = mc->reg;
+	u16 val;
+
+	/* For OUT1 and OUT2 we shadow the values and only actually write
+	 * them out when active in order to ensure the amplifier comes on
+	 * as quietly as possible. */
+	switch (reg) {
+	case WM8350_LOUT1_VOLUME:
+		out = &wm8350_priv->out1;
+		break;
+	case WM8350_LOUT2_VOLUME:
+		out = &wm8350_priv->out2;
+		break;
+	default:
+		break;
+	}
+
+	if (out) {
+		out->left_vol = ucontrol->value.integer.value[0];
+		out->right_vol = ucontrol->value.integer.value[1];
+		if (!out->active)
+			return 1;
+	}
+
+	ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
+	if (ret < 0)
+		return ret;
+
+	/* now hit the volume update bits (always bit 8) */
+	val = wm8350_codec_read(codec, reg);
+	wm8350_codec_write(codec, reg, val | WM8350_OUT1_VU);
+	return 1;
+}
+
+static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8350_data *wm8350_priv = codec->private_data;
+	struct wm8350_output *out1 = &wm8350_priv->out1;
+	struct wm8350_output *out2 = &wm8350_priv->out2;
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int reg = mc->reg;
+
+	/* If these are cached registers use the cache */
+	switch (reg) {
+	case WM8350_LOUT1_VOLUME:
+		ucontrol->value.integer.value[0] = out1->left_vol;
+		ucontrol->value.integer.value[1] = out1->right_vol;
+		return 0;
+
+	case WM8350_LOUT2_VOLUME:
+		ucontrol->value.integer.value[0] = out2->left_vol;
+		ucontrol->value.integer.value[1] = out2->right_vol;
+		return 0;
+
+	default:
+		break;
+	}
+
+	return snd_soc_get_volsw_2r(kcontrol, ucontrol);
+}
+
+/* double control with volume update */
+#define SOC_WM8350_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, \
+				xinvert, tlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+		SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+	.tlv.p = (tlv_array), \
+	.info = snd_soc_info_volsw_2r, \
+	.get = wm8350_get_volsw_2r, .put = wm8350_put_volsw_2r_vu, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
+		 .rshift = xshift, .max = xmax, .invert = xinvert}, }
+
+static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
+static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" };
+static const char *wm8350_dacmutem[] = { "Normal", "Soft" };
+static const char *wm8350_dacmutes[] = { "Fast", "Slow" };
+static const char *wm8350_dacfilter[] = { "Normal", "Sloping" };
+static const char *wm8350_adcfilter[] = { "None", "High Pass" };
+static const char *wm8350_adchp[] = { "44.1kHz", "8kHz", "16kHz", "32kHz" };
+static const char *wm8350_lr[] = { "Left", "Right" };
+
+static const struct soc_enum wm8350_enum[] = {
+	SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 4, 4, wm8350_deemp),
+	SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 0, 4, wm8350_pol),
+	SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 14, 2, wm8350_dacmutem),
+	SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 13, 2, wm8350_dacmutes),
+	SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 12, 2, wm8350_dacfilter),
+	SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 15, 2, wm8350_adcfilter),
+	SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 8, 4, wm8350_adchp),
+	SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 0, 4, wm8350_pol),
+	SOC_ENUM_SINGLE(WM8350_INPUT_MIXER_VOLUME, 15, 2, wm8350_lr),
+};
+
+static DECLARE_TLV_DB_LINEAR(pre_amp_tlv, -1200, 3525);
+static DECLARE_TLV_DB_LINEAR(out_pga_tlv, -5700, 600);
+static DECLARE_TLV_DB_SCALE(dac_pcm_tlv, -7163, 36, 1);
+static DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -12700, 50, 1);
+static DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 1);
+
+static const unsigned int capture_sd_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0, 12, TLV_DB_SCALE_ITEM(-3600, 300, 1),
+	13, 15, TLV_DB_SCALE_ITEM(0, 0, 0),
+};
+
+static const struct snd_kcontrol_new wm8350_snd_controls[] = {
+	SOC_ENUM("Playback Deemphasis", wm8350_enum[0]),
+	SOC_ENUM("Playback DAC Inversion", wm8350_enum[1]),
+	SOC_WM8350_DOUBLE_R_TLV("Playback PCM Volume",
+				WM8350_DAC_DIGITAL_VOLUME_L,
+				WM8350_DAC_DIGITAL_VOLUME_R,
+				0, 255, 0, dac_pcm_tlv),
+	SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]),
+	SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]),
+	SOC_ENUM("Playback PCM Filter", wm8350_enum[4]),
+	SOC_ENUM("Capture PCM Filter", wm8350_enum[5]),
+	SOC_ENUM("Capture PCM HP Filter", wm8350_enum[6]),
+	SOC_ENUM("Capture ADC Inversion", wm8350_enum[7]),
+	SOC_WM8350_DOUBLE_R_TLV("Capture PCM Volume",
+				WM8350_ADC_DIGITAL_VOLUME_L,
+				WM8350_ADC_DIGITAL_VOLUME_R,
+				0, 255, 0, adc_pcm_tlv),
+	SOC_DOUBLE_TLV("Capture Sidetone Volume",
+		       WM8350_ADC_DIVIDER,
+		       8, 4, 15, 1, capture_sd_tlv),
+	SOC_WM8350_DOUBLE_R_TLV("Capture Volume",
+				WM8350_LEFT_INPUT_VOLUME,
+				WM8350_RIGHT_INPUT_VOLUME,
+				2, 63, 0, pre_amp_tlv),
+	SOC_DOUBLE_R("Capture ZC Switch",
+		     WM8350_LEFT_INPUT_VOLUME,
+		     WM8350_RIGHT_INPUT_VOLUME, 13, 1, 0),
+	SOC_SINGLE_TLV("Left Input Left Sidetone Volume",
+		       WM8350_OUTPUT_LEFT_MIXER_VOLUME, 1, 7, 0, out_mix_tlv),
+	SOC_SINGLE_TLV("Left Input Right Sidetone Volume",
+		       WM8350_OUTPUT_LEFT_MIXER_VOLUME,
+		       5, 7, 0, out_mix_tlv),
+	SOC_SINGLE_TLV("Left Input Bypass Volume",
+		       WM8350_OUTPUT_LEFT_MIXER_VOLUME,
+		       9, 7, 0, out_mix_tlv),
+	SOC_SINGLE_TLV("Right Input Left Sidetone Volume",
+		       WM8350_OUTPUT_RIGHT_MIXER_VOLUME,
+		       1, 7, 0, out_mix_tlv),
+	SOC_SINGLE_TLV("Right Input Right Sidetone Volume",
+		       WM8350_OUTPUT_RIGHT_MIXER_VOLUME,
+		       5, 7, 0, out_mix_tlv),
+	SOC_SINGLE_TLV("Right Input Bypass Volume",
+		       WM8350_OUTPUT_RIGHT_MIXER_VOLUME,
+		       13, 7, 0, out_mix_tlv),
+	SOC_SINGLE("Left Input Mixer +20dB Switch",
+		   WM8350_INPUT_MIXER_VOLUME_L, 0, 1, 0),
+	SOC_SINGLE("Right Input Mixer +20dB Switch",
+		   WM8350_INPUT_MIXER_VOLUME_R, 0, 1, 0),
+	SOC_SINGLE_TLV("Out4 Capture Volume",
+		       WM8350_INPUT_MIXER_VOLUME,
+		       1, 7, 0, out_mix_tlv),
+	SOC_WM8350_DOUBLE_R_TLV("Out1 Playback Volume",
+				WM8350_LOUT1_VOLUME,
+				WM8350_ROUT1_VOLUME,
+				2, 63, 0, out_pga_tlv),
+	SOC_DOUBLE_R("Out1 Playback ZC Switch",
+		     WM8350_LOUT1_VOLUME,
+		     WM8350_ROUT1_VOLUME, 13, 1, 0),
+	SOC_WM8350_DOUBLE_R_TLV("Out2 Playback Volume",
+				WM8350_LOUT2_VOLUME,
+				WM8350_ROUT2_VOLUME,
+				2, 63, 0, out_pga_tlv),
+	SOC_DOUBLE_R("Out2 Playback ZC Switch", WM8350_LOUT2_VOLUME,
+		     WM8350_ROUT2_VOLUME, 13, 1, 0),
+	SOC_SINGLE("Out2 Right Invert Switch", WM8350_ROUT2_VOLUME, 10, 1, 0),
+	SOC_SINGLE_TLV("Out2 Beep Volume", WM8350_BEEP_VOLUME,
+		       5, 7, 0, out_mix_tlv),
+
+	SOC_DOUBLE_R("Out1 Playback Switch",
+		     WM8350_LOUT1_VOLUME,
+		     WM8350_ROUT1_VOLUME,
+		     14, 1, 1),
+	SOC_DOUBLE_R("Out2 Playback Switch",
+		     WM8350_LOUT2_VOLUME,
+		     WM8350_ROUT2_VOLUME,
+		     14, 1, 1),
+};
+
+/*
+ * DAPM Controls
+ */
+
+/* Left Playback Mixer */
+static const struct snd_kcontrol_new wm8350_left_play_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Playback Switch",
+			WM8350_LEFT_MIXER_CONTROL, 11, 1, 0),
+	SOC_DAPM_SINGLE("Left Bypass Switch",
+			WM8350_LEFT_MIXER_CONTROL, 2, 1, 0),
+	SOC_DAPM_SINGLE("Right Playback Switch",
+			WM8350_LEFT_MIXER_CONTROL, 12, 1, 0),
+	SOC_DAPM_SINGLE("Left Sidetone Switch",
+			WM8350_LEFT_MIXER_CONTROL, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right Sidetone Switch",
+			WM8350_LEFT_MIXER_CONTROL, 1, 1, 0),
+};
+
+/* Right Playback Mixer */
+static const struct snd_kcontrol_new wm8350_right_play_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Playback Switch",
+			WM8350_RIGHT_MIXER_CONTROL, 12, 1, 0),
+	SOC_DAPM_SINGLE("Right Bypass Switch",
+			WM8350_RIGHT_MIXER_CONTROL, 3, 1, 0),
+	SOC_DAPM_SINGLE("Left Playback Switch",
+			WM8350_RIGHT_MIXER_CONTROL, 11, 1, 0),
+	SOC_DAPM_SINGLE("Left Sidetone Switch",
+			WM8350_RIGHT_MIXER_CONTROL, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right Sidetone Switch",
+			WM8350_RIGHT_MIXER_CONTROL, 1, 1, 0),
+};
+
+/* Out4 Mixer */
+static const struct snd_kcontrol_new wm8350_out4_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Right Playback Switch",
+			WM8350_OUT4_MIXER_CONTROL, 12, 1, 0),
+	SOC_DAPM_SINGLE("Left Playback Switch",
+			WM8350_OUT4_MIXER_CONTROL, 11, 1, 0),
+	SOC_DAPM_SINGLE("Right Capture Switch",
+			WM8350_OUT4_MIXER_CONTROL, 9, 1, 0),
+	SOC_DAPM_SINGLE("Out3 Playback Switch",
+			WM8350_OUT4_MIXER_CONTROL, 2, 1, 0),
+	SOC_DAPM_SINGLE("Right Mixer Switch",
+			WM8350_OUT4_MIXER_CONTROL, 1, 1, 0),
+	SOC_DAPM_SINGLE("Left Mixer Switch",
+			WM8350_OUT4_MIXER_CONTROL, 0, 1, 0),
+};
+
+/* Out3 Mixer */
+static const struct snd_kcontrol_new wm8350_out3_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left Playback Switch",
+			WM8350_OUT3_MIXER_CONTROL, 11, 1, 0),
+	SOC_DAPM_SINGLE("Left Capture Switch",
+			WM8350_OUT3_MIXER_CONTROL, 8, 1, 0),
+	SOC_DAPM_SINGLE("Out4 Playback Switch",
+			WM8350_OUT3_MIXER_CONTROL, 3, 1, 0),
+	SOC_DAPM_SINGLE("Left Mixer Switch",
+			WM8350_OUT3_MIXER_CONTROL, 0, 1, 0),
+};
+
+/* Left Input Mixer */
+static const struct snd_kcontrol_new wm8350_left_capt_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("L2 Capture Volume",
+			    WM8350_INPUT_MIXER_VOLUME_L, 1, 7, 0, out_mix_tlv),
+	SOC_DAPM_SINGLE_TLV("L3 Capture Volume",
+			    WM8350_INPUT_MIXER_VOLUME_L, 9, 7, 0, out_mix_tlv),
+	SOC_DAPM_SINGLE("PGA Capture Switch",
+			WM8350_LEFT_INPUT_VOLUME, 14, 1, 0),
+};
+
+/* Right Input Mixer */
+static const struct snd_kcontrol_new wm8350_right_capt_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("L2 Capture Volume",
+			    WM8350_INPUT_MIXER_VOLUME_R, 5, 7, 0, out_mix_tlv),
+	SOC_DAPM_SINGLE_TLV("L3 Capture Volume",
+			    WM8350_INPUT_MIXER_VOLUME_R, 13, 7, 0, out_mix_tlv),
+	SOC_DAPM_SINGLE("PGA Capture Switch",
+			WM8350_RIGHT_INPUT_VOLUME, 14, 1, 0),
+};
+
+/* Left Mic Mixer */
+static const struct snd_kcontrol_new wm8350_left_mic_mixer_controls[] = {
+	SOC_DAPM_SINGLE("INN Capture Switch", WM8350_INPUT_CONTROL, 1, 1, 0),
+	SOC_DAPM_SINGLE("INP Capture Switch", WM8350_INPUT_CONTROL, 0, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Capture Switch", WM8350_INPUT_CONTROL, 2, 1, 0),
+};
+
+/* Right Mic Mixer */
+static const struct snd_kcontrol_new wm8350_right_mic_mixer_controls[] = {
+	SOC_DAPM_SINGLE("INN Capture Switch", WM8350_INPUT_CONTROL, 9, 1, 0),
+	SOC_DAPM_SINGLE("INP Capture Switch", WM8350_INPUT_CONTROL, 8, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Capture Switch", WM8350_INPUT_CONTROL, 10, 1, 0),
+};
+
+/* Beep Switch */
+static const struct snd_kcontrol_new wm8350_beep_switch_controls =
+SOC_DAPM_SINGLE("Switch", WM8350_BEEP_VOLUME, 15, 1, 1);
+
+/* Out4 Capture Mux */
+static const struct snd_kcontrol_new wm8350_out4_capture_controls =
+SOC_DAPM_ENUM("Route", wm8350_enum[8]);
+
+static const struct snd_soc_dapm_widget wm8350_dapm_widgets[] = {
+
+	SND_SOC_DAPM_PGA("IN3R PGA", WM8350_POWER_MGMT_2, 11, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IN3L PGA", WM8350_POWER_MGMT_2, 10, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_E("Right Out2 PGA", WM8350_POWER_MGMT_3, 3, 0, NULL,
+			   0, pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("Left Out2 PGA", WM8350_POWER_MGMT_3, 2, 0, NULL, 0,
+			   pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("Right Out1 PGA", WM8350_POWER_MGMT_3, 1, 0, NULL,
+			   0, pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("Left Out1 PGA", WM8350_POWER_MGMT_3, 0, 0, NULL, 0,
+			   pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MIXER("Right Capture Mixer", WM8350_POWER_MGMT_2,
+			   7, 0, &wm8350_right_capt_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_right_capt_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Capture Mixer", WM8350_POWER_MGMT_2,
+			   6, 0, &wm8350_left_capt_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_left_capt_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Out4 Mixer", WM8350_POWER_MGMT_2, 5, 0,
+			   &wm8350_out4_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_out4_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Out3 Mixer", WM8350_POWER_MGMT_2, 4, 0,
+			   &wm8350_out3_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_out3_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Playback Mixer", WM8350_POWER_MGMT_2, 1, 0,
+			   &wm8350_right_play_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_right_play_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Playback Mixer", WM8350_POWER_MGMT_2, 0, 0,
+			   &wm8350_left_play_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_left_play_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Mic Mixer", WM8350_POWER_MGMT_2, 8, 0,
+			   &wm8350_left_mic_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_left_mic_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Mic Mixer", WM8350_POWER_MGMT_2, 9, 0,
+			   &wm8350_right_mic_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_right_mic_mixer_controls)),
+
+	/* virtual mixer for Beep and Out2R */
+	SND_SOC_DAPM_MIXER("Out2 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("Beep", WM8350_POWER_MGMT_3, 7, 0,
+			    &wm8350_beep_switch_controls),
+
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
+			 WM8350_POWER_MGMT_4, 3, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture",
+			 WM8350_POWER_MGMT_4, 2, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback",
+			 WM8350_POWER_MGMT_4, 5, 0),
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback",
+			 WM8350_POWER_MGMT_4, 4, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8350_POWER_MGMT_1, 4, 0),
+
+	SND_SOC_DAPM_MUX("Out4 Capture Channel", SND_SOC_NOPM, 0, 0,
+			 &wm8350_out4_capture_controls),
+
+	SND_SOC_DAPM_OUTPUT("OUT1R"),
+	SND_SOC_DAPM_OUTPUT("OUT1L"),
+	SND_SOC_DAPM_OUTPUT("OUT2R"),
+	SND_SOC_DAPM_OUTPUT("OUT2L"),
+	SND_SOC_DAPM_OUTPUT("OUT3"),
+	SND_SOC_DAPM_OUTPUT("OUT4"),
+
+	SND_SOC_DAPM_INPUT("IN1RN"),
+	SND_SOC_DAPM_INPUT("IN1RP"),
+	SND_SOC_DAPM_INPUT("IN2R"),
+	SND_SOC_DAPM_INPUT("IN1LP"),
+	SND_SOC_DAPM_INPUT("IN1LN"),
+	SND_SOC_DAPM_INPUT("IN2L"),
+	SND_SOC_DAPM_INPUT("IN3R"),
+	SND_SOC_DAPM_INPUT("IN3L"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+
+	/* left playback mixer */
+	{"Left Playback Mixer", "Playback Switch", "Left DAC"},
+	{"Left Playback Mixer", "Left Bypass Switch", "IN3L PGA"},
+	{"Left Playback Mixer", "Right Playback Switch", "Right DAC"},
+	{"Left Playback Mixer", "Left Sidetone Switch", "Left Mic Mixer"},
+	{"Left Playback Mixer", "Right Sidetone Switch", "Right Mic Mixer"},
+
+	/* right playback mixer */
+	{"Right Playback Mixer", "Playback Switch", "Right DAC"},
+	{"Right Playback Mixer", "Right Bypass Switch", "IN3R PGA"},
+	{"Right Playback Mixer", "Left Playback Switch", "Left DAC"},
+	{"Right Playback Mixer", "Left Sidetone Switch", "Left Mic Mixer"},
+	{"Right Playback Mixer", "Right Sidetone Switch", "Right Mic Mixer"},
+
+	/* out4 playback mixer */
+	{"Out4 Mixer", "Right Playback Switch", "Right DAC"},
+	{"Out4 Mixer", "Left Playback Switch", "Left DAC"},
+	{"Out4 Mixer", "Right Capture Switch", "Right Capture Mixer"},
+	{"Out4 Mixer", "Out3 Playback Switch", "Out3 Mixer"},
+	{"Out4 Mixer", "Right Mixer Switch", "Right Playback Mixer"},
+	{"Out4 Mixer", "Left Mixer Switch", "Left Playback Mixer"},
+	{"OUT4", NULL, "Out4 Mixer"},
+
+	/* out3 playback mixer */
+	{"Out3 Mixer", "Left Playback Switch", "Left DAC"},
+	{"Out3 Mixer", "Left Capture Switch", "Left Capture Mixer"},
+	{"Out3 Mixer", "Left Mixer Switch", "Left Playback Mixer"},
+	{"Out3 Mixer", "Out4 Playback Switch", "Out4 Mixer"},
+	{"OUT3", NULL, "Out3 Mixer"},
+
+	/* out2 */
+	{"Right Out2 PGA", NULL, "Right Playback Mixer"},
+	{"Left Out2 PGA", NULL, "Left Playback Mixer"},
+	{"OUT2L", NULL, "Left Out2 PGA"},
+	{"OUT2R", NULL, "Right Out2 PGA"},
+
+	/* out1 */
+	{"Right Out1 PGA", NULL, "Right Playback Mixer"},
+	{"Left Out1 PGA", NULL, "Left Playback Mixer"},
+	{"OUT1L", NULL, "Left Out1 PGA"},
+	{"OUT1R", NULL, "Right Out1 PGA"},
+
+	/* ADCs */
+	{"Left ADC", NULL, "Left Capture Mixer"},
+	{"Right ADC", NULL, "Right Capture Mixer"},
+
+	/* Left capture mixer */
+	{"Left Capture Mixer", "L2 Capture Volume", "IN2L"},
+	{"Left Capture Mixer", "L3 Capture Volume", "IN3L PGA"},
+	{"Left Capture Mixer", "PGA Capture Switch", "Left Mic Mixer"},
+	{"Left Capture Mixer", NULL, "Out4 Capture Channel"},
+
+	/* Right capture mixer */
+	{"Right Capture Mixer", "L2 Capture Volume", "IN2R"},
+	{"Right Capture Mixer", "L3 Capture Volume", "IN3R PGA"},
+	{"Right Capture Mixer", "PGA Capture Switch", "Right Mic Mixer"},
+	{"Right Capture Mixer", NULL, "Out4 Capture Channel"},
+
+	/* L3 Inputs */
+	{"IN3L PGA", NULL, "IN3L"},
+	{"IN3R PGA", NULL, "IN3R"},
+
+	/* Left Mic mixer */
+	{"Left Mic Mixer", "INN Capture Switch", "IN1LN"},
+	{"Left Mic Mixer", "INP Capture Switch", "IN1LP"},
+	{"Left Mic Mixer", "IN2 Capture Switch", "IN2L"},
+
+	/* Right Mic mixer */
+	{"Right Mic Mixer", "INN Capture Switch", "IN1RN"},
+	{"Right Mic Mixer", "INP Capture Switch", "IN1RP"},
+	{"Right Mic Mixer", "IN2 Capture Switch", "IN2R"},
+
+	/* out 4 capture */
+	{"Out4 Capture Channel", NULL, "Out4 Mixer"},
+
+	/* Beep */
+	{"Beep", NULL, "IN3R PGA"},
+};
+
+static int wm8350_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8350_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				  snd_soc_cnew(&wm8350_snd_controls[i],
+					       codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int wm8350_add_widgets(struct snd_soc_codec *codec)
+{
+	int ret;
+
+	ret = snd_soc_dapm_new_controls(codec,
+					wm8350_dapm_widgets,
+					ARRAY_SIZE(wm8350_dapm_widgets));
+	if (ret != 0) {
+		dev_err(codec->dev, "dapm control register failed\n");
+		return ret;
+	}
+
+	/* set up audio paths */
+	ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+	if (ret != 0) {
+		dev_err(codec->dev, "DAPM route register failed\n");
+		return ret;
+	}
+
+	return snd_soc_dapm_new_widgets(codec);
+}
+
+static int wm8350_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 wm8350 *wm8350 = codec->control_data;
+	u16 fll_4;
+
+	switch (clk_id) {
+	case WM8350_MCLK_SEL_MCLK:
+		wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_1,
+				  WM8350_MCLK_SEL);
+		break;
+	case WM8350_MCLK_SEL_PLL_MCLK:
+	case WM8350_MCLK_SEL_PLL_DAC:
+	case WM8350_MCLK_SEL_PLL_ADC:
+	case WM8350_MCLK_SEL_PLL_32K:
+		wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_1,
+				WM8350_MCLK_SEL);
+		fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) &
+		    ~WM8350_FLL_CLK_SRC_MASK;
+		wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, fll_4 | clk_id);
+		break;
+	}
+
+	/* MCLK direction */
+	if (dir == WM8350_MCLK_DIR_OUT)
+		wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2,
+				WM8350_MCLK_DIR);
+	else
+		wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_2,
+				  WM8350_MCLK_DIR);
+
+	return 0;
+}
+
+static int wm8350_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 val;
+
+	switch (div_id) {
+	case WM8350_ADC_CLKDIV:
+		val = wm8350_codec_read(codec, WM8350_ADC_DIVIDER) &
+		    ~WM8350_ADC_CLKDIV_MASK;
+		wm8350_codec_write(codec, WM8350_ADC_DIVIDER, val | div);
+		break;
+	case WM8350_DAC_CLKDIV:
+		val = wm8350_codec_read(codec, WM8350_DAC_CLOCK_CONTROL) &
+		    ~WM8350_DAC_CLKDIV_MASK;
+		wm8350_codec_write(codec, WM8350_DAC_CLOCK_CONTROL, val | div);
+		break;
+	case WM8350_BCLK_CLKDIV:
+		val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+		    ~WM8350_BCLK_DIV_MASK;
+		wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+		break;
+	case WM8350_OPCLK_CLKDIV:
+		val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+		    ~WM8350_OPCLK_DIV_MASK;
+		wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+		break;
+	case WM8350_SYS_CLKDIV:
+		val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+		    ~WM8350_MCLK_DIV_MASK;
+		wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+		break;
+	case WM8350_DACLR_CLKDIV:
+		val = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) &
+		    ~WM8350_DACLRC_RATE_MASK;
+		wm8350_codec_write(codec, WM8350_DAC_LR_RATE, val | div);
+		break;
+	case WM8350_ADCLR_CLKDIV:
+		val = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) &
+		    ~WM8350_ADCLRC_RATE_MASK;
+		wm8350_codec_write(codec, WM8350_ADC_LR_RATE, val | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) &
+	    ~(WM8350_AIF_BCLK_INV | WM8350_AIF_LRCLK_INV | WM8350_AIF_FMT_MASK);
+	u16 master = wm8350_codec_read(codec, WM8350_AI_DAC_CONTROL) &
+	    ~WM8350_BCLK_MSTR;
+	u16 dac_lrc = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) &
+	    ~WM8350_DACLRC_ENA;
+	u16 adc_lrc = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) &
+	    ~WM8350_ADCLRC_ENA;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		master |= WM8350_BCLK_MSTR;
+		dac_lrc |= WM8350_DACLRC_ENA;
+		adc_lrc |= WM8350_ADCLRC_ENA;
+		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 |= 0x2 << 8;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x1 << 8;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x3 << 8;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x3 << 8;	/* lg not sure which mode */
+		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 |= WM8350_AIF_LRCLK_INV | WM8350_AIF_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= WM8350_AIF_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= WM8350_AIF_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8350_codec_write(codec, WM8350_AI_FORMATING, iface);
+	wm8350_codec_write(codec, WM8350_AI_DAC_CONTROL, master);
+	wm8350_codec_write(codec, WM8350_DAC_LR_RATE, dac_lrc);
+	wm8350_codec_write(codec, WM8350_ADC_LR_RATE, adc_lrc);
+	return 0;
+}
+
+static int wm8350_pcm_trigger(struct snd_pcm_substream *substream,
+			      int cmd, struct snd_soc_dai *codec_dai)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	int master = wm8350_codec_cache_read(codec, WM8350_AI_DAC_CONTROL) &
+	    WM8350_BCLK_MSTR;
+	int enabled = 0;
+
+	/* Check that the DACs or ADCs are enabled since they are
+	 * required for LRC in master mode. The DACs or ADCs need a
+	 * valid audio path i.e. pin -> ADC or DAC -> pin before
+	 * the LRC will be enabled in master mode. */
+	if (!master && cmd != SNDRV_PCM_TRIGGER_START)
+		return 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) &
+		    (WM8350_ADCR_ENA | WM8350_ADCL_ENA);
+	} else {
+		enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) &
+		    (WM8350_DACR_ENA | WM8350_DACL_ENA);
+	}
+
+	if (!enabled) {
+		dev_err(codec->dev,
+		       "%s: invalid audio path - no clocks available\n",
+		       __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *codec_dai)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) &
+	    ~WM8350_AIF_WL_MASK;
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		iface |= 0x1 << 10;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		iface |= 0x2 << 10;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		iface |= 0x3 << 10;
+		break;
+	}
+
+	wm8350_codec_write(codec, WM8350_AI_FORMATING, iface);
+	return 0;
+}
+
+static int wm8350_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct wm8350 *wm8350 = codec->control_data;
+
+	if (mute)
+		wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
+	else
+		wm8350_clear_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
+	return 0;
+}
+
+/* FLL divisors */
+struct _fll_div {
+	int div;		/* FLL_OUTDIV */
+	int n;
+	int k;
+	int ratio;		/* FLL_FRATIO */
+};
+
+/* The size in bits of the fll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static inline int fll_factors(struct _fll_div *fll_div, unsigned int input,
+			      unsigned int output)
+{
+	u64 Kpart;
+	unsigned int t1, t2, K, Nmod;
+
+	if (output >= 2815250 && output <= 3125000)
+		fll_div->div = 0x4;
+	else if (output >= 5625000 && output <= 6250000)
+		fll_div->div = 0x3;
+	else if (output >= 11250000 && output <= 12500000)
+		fll_div->div = 0x2;
+	else if (output >= 22500000 && output <= 25000000)
+		fll_div->div = 0x1;
+	else {
+		printk(KERN_ERR "wm8350: fll freq %d out of range\n", output);
+		return -EINVAL;
+	}
+
+	if (input > 48000)
+		fll_div->ratio = 1;
+	else
+		fll_div->ratio = 8;
+
+	t1 = output * (1 << (fll_div->div + 1));
+	t2 = input * fll_div->ratio;
+
+	fll_div->n = t1 / t2;
+	Nmod = t1 % t2;
+
+	if (Nmod) {
+		Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+		do_div(Kpart, t2);
+		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;
+		fll_div->k = K;
+	} else
+		fll_div->k = 0;
+
+	return 0;
+}
+
+static int wm8350_set_fll(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;
+	struct wm8350 *wm8350 = codec->control_data;
+	struct _fll_div fll_div;
+	int ret = 0;
+	u16 fll_1, fll_4;
+
+	/* power down FLL - we need to do this for reconfiguration */
+	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4,
+			  WM8350_FLL_ENA | WM8350_FLL_OSC_ENA);
+
+	if (freq_out == 0 || freq_in == 0)
+		return ret;
+
+	ret = fll_factors(&fll_div, freq_in, freq_out);
+	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",
+		freq_in, freq_out, fll_div.n, fll_div.k, fll_div.div,
+		fll_div.ratio);
+
+	/* set up N.K & dividers */
+	fll_1 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_1) &
+	    ~(WM8350_FLL_OUTDIV_MASK | WM8350_FLL_RSP_RATE_MASK | 0xc000);
+	wm8350_codec_write(codec, WM8350_FLL_CONTROL_1,
+			   fll_1 | (fll_div.div << 8) | 0x50);
+	wm8350_codec_write(codec, WM8350_FLL_CONTROL_2,
+			   (fll_div.ratio << 11) | (fll_div.
+						    n & WM8350_FLL_N_MASK));
+	wm8350_codec_write(codec, WM8350_FLL_CONTROL_3, fll_div.k);
+	fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) &
+	    ~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF);
+	wm8350_codec_write(codec, WM8350_FLL_CONTROL_4,
+			   fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) |
+			   (fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0));
+
+	/* power FLL on */
+	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA);
+	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA);
+
+	return 0;
+}
+
+static int wm8350_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8350 *wm8350 = codec->control_data;
+	struct wm8350_data *priv = codec->private_data;
+	struct wm8350_audio_platform_data *platform =
+		wm8350->codec.platform_data;
+	u16 pm1;
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
+		    ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
+		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+				 pm1 | WM8350_VMID_50K |
+				 platform->codec_current_on << 14);
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1);
+		pm1 &= ~WM8350_VMID_MASK;
+		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+				 pm1 | WM8350_VMID_50K);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
+						    priv->supplies);
+			if (ret != 0)
+				return ret;
+
+			/* Enable the system clock */
+			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4,
+					WM8350_SYSCLK_ENA);
+
+			/* mute DAC & outputs */
+			wm8350_set_bits(wm8350, WM8350_DAC_MUTE,
+					WM8350_DAC_MUTE_ENA);
+
+			/* discharge cap memory */
+			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
+					 platform->dis_out1 |
+					 (platform->dis_out2 << 2) |
+					 (platform->dis_out3 << 4) |
+					 (platform->dis_out4 << 6));
+
+			/* wait for discharge */
+			schedule_timeout_interruptible(msecs_to_jiffies
+						       (platform->
+							cap_discharge_msecs));
+
+			/* enable antipop */
+			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
+					 (platform->vmid_s_curve << 8));
+
+			/* ramp up vmid */
+			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+					 (platform->
+					  codec_current_charge << 14) |
+					 WM8350_VMID_5K | WM8350_VMIDEN |
+					 WM8350_VBUFEN);
+
+			/* wait for vmid */
+			schedule_timeout_interruptible(msecs_to_jiffies
+						       (platform->
+							vmid_charge_msecs));
+
+			/* turn on vmid 300k  */
+			pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
+			    ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
+			pm1 |= WM8350_VMID_300K |
+				(platform->codec_current_standby << 14);
+			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+					 pm1);
+
+
+			/* enable analogue bias */
+			pm1 |= WM8350_BIASEN;
+			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);
+
+			/* disable antipop */
+			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0);
+
+		} else {
+			/* turn on vmid 300k and reduce current */
+			pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
+			    ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
+			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+					 pm1 | WM8350_VMID_300K |
+					 (platform->
+					  codec_current_standby << 14));
+
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+
+		/* mute DAC & enable outputs */
+		wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
+
+		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_3,
+				WM8350_OUT1L_ENA | WM8350_OUT1R_ENA |
+				WM8350_OUT2L_ENA | WM8350_OUT2R_ENA);
+
+		/* enable anti pop S curve */
+		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
+				 (platform->vmid_s_curve << 8));
+
+		/* turn off vmid  */
+		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
+		    ~WM8350_VMIDEN;
+		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);
+
+		/* wait */
+		schedule_timeout_interruptible(msecs_to_jiffies
+					       (platform->
+						vmid_discharge_msecs));
+
+		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
+				 (platform->vmid_s_curve << 8) |
+				 platform->dis_out1 |
+				 (platform->dis_out2 << 2) |
+				 (platform->dis_out3 << 4) |
+				 (platform->dis_out4 << 6));
+
+		/* turn off VBuf and drain */
+		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
+		    ~(WM8350_VBUFEN | WM8350_VMID_MASK);
+		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+				 pm1 | WM8350_OUTPUT_DRAIN_EN);
+
+		/* wait */
+		schedule_timeout_interruptible(msecs_to_jiffies
+					       (platform->drain_msecs));
+
+		pm1 &= ~WM8350_BIASEN;
+		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);
+
+		/* disable anti-pop */
+		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0);
+
+		wm8350_clear_bits(wm8350, WM8350_LOUT1_VOLUME,
+				  WM8350_OUT1L_ENA);
+		wm8350_clear_bits(wm8350, WM8350_ROUT1_VOLUME,
+				  WM8350_OUT1R_ENA);
+		wm8350_clear_bits(wm8350, WM8350_LOUT2_VOLUME,
+				  WM8350_OUT2L_ENA);
+		wm8350_clear_bits(wm8350, WM8350_ROUT2_VOLUME,
+				  WM8350_OUT2R_ENA);
+
+		/* disable clock gen */
+		wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4,
+				  WM8350_SYSCLK_ENA);
+
+		regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
+				       priv->supplies);
+		break;
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+static int wm8350_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int wm8350_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
+		wm8350_set_bias_level(codec, SND_SOC_BIAS_ON);
+
+	return 0;
+}
+
+static struct snd_soc_codec *wm8350_codec;
+
+static int wm8350_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	struct wm8350 *wm8350;
+	struct wm8350_data *priv;
+	int ret;
+	struct wm8350_output *out1;
+	struct wm8350_output *out2;
+
+	BUG_ON(!wm8350_codec);
+
+	socdev->codec = wm8350_codec;
+	codec = socdev->codec;
+	wm8350 = codec->control_data;
+	priv = codec->private_data;
+
+	/* Enable the codec */
+	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
+
+	/* Enable robust clocking mode in ADC */
+	wm8350_codec_write(codec, WM8350_SECURITY, 0xa7);
+	wm8350_codec_write(codec, 0xde, 0x13);
+	wm8350_codec_write(codec, WM8350_SECURITY, 0);
+
+	/* read OUT1 & OUT2 volumes */
+	out1 = &priv->out1;
+	out2 = &priv->out2;
+	out1->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME) &
+			  WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
+	out1->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME) &
+			   WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
+	out2->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME) &
+			  WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
+	out2->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME) &
+			   WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
+	wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, 0);
+	wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, 0);
+	wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, 0);
+	wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, 0);
+
+	/* Latch VU bits & mute */
+	wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME,
+			WM8350_OUT1_VU | WM8350_OUT1L_MUTE);
+	wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME,
+			WM8350_OUT2_VU | WM8350_OUT2L_MUTE);
+	wm8350_set_bits(wm8350, WM8350_ROUT1_VOLUME,
+			WM8350_OUT1_VU | WM8350_OUT1R_MUTE);
+	wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME,
+			WM8350_OUT2_VU | WM8350_OUT2R_MUTE);
+
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to create pcms\n");
+		return ret;
+	}
+
+	wm8350_add_controls(codec);
+	wm8350_add_widgets(codec);
+
+	wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register card\n");
+		goto card_err;
+	}
+
+	return 0;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+	return ret;
+}
+
+static int wm8350_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+	struct wm8350 *wm8350 = codec->control_data;
+	int ret;
+
+	/* cancel any work waiting to be queued. */
+	ret = cancel_delayed_work(&codec->delayed_work);
+
+	/* if there was any work waiting then we run it now and
+	 * wait for its completion */
+	if (ret) {
+		schedule_delayed_work(&codec->delayed_work, 0);
+		flush_scheduled_work();
+	}
+
+	wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
+
+	return 0;
+}
+
+#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
+
+#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_dai wm8350_dai = {
+	.name = "WM8350",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8350_RATES,
+		.formats = WM8350_FORMATS,
+	},
+	.capture = {
+		 .stream_name = "Capture",
+		 .channels_min = 1,
+		 .channels_max = 2,
+		 .rates = WM8350_RATES,
+		 .formats = WM8350_FORMATS,
+	 },
+	.ops = {
+		 .hw_params = wm8350_pcm_hw_params,
+		 .digital_mute = wm8350_mute,
+		 .trigger = wm8350_pcm_trigger,
+		 .set_fmt = wm8350_set_dai_fmt,
+		 .set_sysclk = wm8350_set_dai_sysclk,
+		 .set_pll = wm8350_set_fll,
+		 .set_clkdiv = wm8350_set_clkdiv,
+	 },
+};
+EXPORT_SYMBOL_GPL(wm8350_dai);
+
+struct snd_soc_codec_device soc_codec_dev_wm8350 = {
+	.probe = 	wm8350_probe,
+	.remove = 	wm8350_remove,
+	.suspend = 	wm8350_suspend,
+	.resume =	wm8350_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350);
+
+static int wm8350_codec_probe(struct platform_device *pdev)
+{
+	struct wm8350 *wm8350 = platform_get_drvdata(pdev);
+	struct wm8350_data *priv;
+	struct snd_soc_codec *codec;
+	int ret, i;
+
+	if (wm8350->codec.platform_data == NULL) {
+		dev_err(&pdev->dev, "No audio platform data supplied\n");
+		return -EINVAL;
+	}
+
+	priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+		priv->supplies[i].supply = supply_names[i];
+
+	ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
+				 priv->supplies);
+	if (ret != 0)
+		goto err_priv;
+
+	codec = &priv->codec;
+	wm8350->codec.codec = codec;
+
+	wm8350_dai.dev = &pdev->dev;
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+	codec->dev = &pdev->dev;
+	codec->name = "WM8350";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8350_codec_read;
+	codec->write = wm8350_codec_write;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->set_bias_level = wm8350_set_bias_level;
+	codec->dai = &wm8350_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = WM8350_MAX_REGISTER;
+	codec->private_data = priv;
+	codec->control_data = wm8350;
+
+	/* Put the codec into reset if it wasn't already */
+	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
+
+	INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0)
+		goto err_supply;
+
+	wm8350_codec = codec;
+
+	ret = snd_soc_register_dai(&wm8350_dai);
+	if (ret != 0)
+		goto err_codec;
+	return 0;
+
+err_codec:
+	snd_soc_unregister_codec(codec);
+err_supply:
+	regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
+err_priv:
+	kfree(priv);
+	wm8350_codec = NULL;
+	return ret;
+}
+
+static int __devexit wm8350_codec_remove(struct platform_device *pdev)
+{
+	struct wm8350 *wm8350 = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = wm8350->codec.codec;
+	struct wm8350_data *priv = codec->private_data;
+
+	snd_soc_unregister_dai(&wm8350_dai);
+	snd_soc_unregister_codec(codec);
+	regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
+	kfree(priv);
+	wm8350_codec = NULL;
+	return 0;
+}
+
+static struct platform_driver wm8350_codec_driver = {
+	.driver = {
+		   .name = "wm8350-codec",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = wm8350_codec_probe,
+	.remove = __devexit_p(wm8350_codec_remove),
+};
+
+static __init int wm8350_init(void)
+{
+	return platform_driver_register(&wm8350_codec_driver);
+}
+module_init(wm8350_init);
+
+static __exit void wm8350_exit(void)
+{
+	platform_driver_unregister(&wm8350_codec_driver);
+}
+module_exit(wm8350_exit);
+
+MODULE_DESCRIPTION("ASoC WM8350 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8350-codec");
diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h
new file mode 100644
index 0000000..cc2887a
--- /dev/null
+++ b/sound/soc/codecs/wm8350.h
@@ -0,0 +1,20 @@
+/*
+ * wm8350.h - WM8903 audio codec interface
+ *
+ * Copyright 2008 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 as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _WM8350_H
+#define _WM8350_H
+
+#include <sound/soc.h>
+
+extern struct snd_soc_dai wm8350_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8350;
+
+#endif
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index d8ca2da..40f8238 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -463,7 +463,8 @@
 }
 
 static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+				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;
@@ -585,8 +586,6 @@
 		.formats = WM8510_FORMATS,},
 	.ops = {
 		.hw_params = wm8510_pcm_hw_params,
-	},
-	.dai_ops = {
 		.digital_mute = wm8510_mute,
 		.set_fmt = wm8510_set_dai_fmt,
 		.set_clkdiv = wm8510_set_dai_clkdiv,
@@ -659,7 +658,7 @@
 	wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	wm8510_add_controls(codec);
 	wm8510_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8510: failed to register card\n");
 		goto card_err;
@@ -890,6 +889,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510);
 
+static int __init wm8510_modinit(void)
+{
+	return snd_soc_register_dai(&wm8510_dai);
+}
+module_init(wm8510_modinit);
+
+static void __exit wm8510_exit(void)
+{
+	snd_soc_unregister_dai(&wm8510_dai);
+}
+module_exit(wm8510_exit);
+
 MODULE_DESCRIPTION("ASoC WM8510 driver");
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 627ebfb..d004e58 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -548,13 +548,13 @@
  * Set PCM DAI bit size and sample rate.
  */
 static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai_link *dai = rtd->dai;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->codec;
-	u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->codec_dai->id);
+	u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id);
 
 	paifb &= ~WM8580_AIF_LENGTH_MASK;
 	/* bit size */
@@ -574,7 +574,7 @@
 		return -EINVAL;
 	}
 
-	wm8580_write(codec, WM8580_PAIF3 + dai->codec_dai->id, paifb);
+	wm8580_write(codec, WM8580_PAIF3 + dai->id, paifb);
 	return 0;
 }
 
@@ -798,8 +798,6 @@
 		},
 		.ops = {
 			 .hw_params = wm8580_paif_hw_params,
-		 },
-		.dai_ops = {
 			 .set_fmt = wm8580_set_paif_dai_fmt,
 			 .set_clkdiv = wm8580_set_dai_clkdiv,
 			 .set_pll = wm8580_set_dai_pll,
@@ -818,8 +816,6 @@
 		},
 		.ops = {
 			 .hw_params = wm8580_paif_hw_params,
-		 },
-		.dai_ops = {
 			 .set_fmt = wm8580_set_paif_dai_fmt,
 			 .set_clkdiv = wm8580_set_dai_clkdiv,
 			 .set_pll = wm8580_set_dai_pll,
@@ -873,7 +869,7 @@
 	wm8580_add_controls(codec);
 	wm8580_add_widgets(codec);
 
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8580: failed to register card\n");
 		goto card_err;
@@ -900,85 +896,85 @@
  *    low  = 0x1a
  *    high = 0x1b
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
 
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8580_i2c_driver;
-static struct i2c_client client_template;
-
-static int wm8580_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8580_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
 {
 	struct snd_soc_device *socdev = wm8580_socdev;
-	struct wm8580_setup_data *setup = socdev->codec_data;
 	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c;
 	int ret;
 
-	if (addr != setup->i2c_address)
-		return -ENODEV;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	i2c =  kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-	if (i2c == NULL) {
-		kfree(codec);
-		return -ENOMEM;
-	}
 	i2c_set_clientdata(i2c, codec);
 	codec->control_data = i2c;
 
-	ret = i2c_attach_client(i2c);
-	if (ret < 0) {
-		dev_err(&i2c->dev, "failed to attach codec at addr %x\n", addr);
-		goto err;
-	}
-
 	ret = wm8580_init(socdev);
-	if (ret < 0) {
+	if (ret < 0)
 		dev_err(&i2c->dev, "failed to initialise WM8580\n");
-		goto err;
-	}
-
-	return ret;
-
-err:
-	kfree(codec);
-	kfree(i2c);
 	return ret;
 }
 
-static int wm8580_i2c_detach(struct i2c_client *client)
+static int wm8580_i2c_remove(struct i2c_client *client)
 {
 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	i2c_detach_client(client);
 	kfree(codec->reg_cache);
-	kfree(client);
 	return 0;
 }
 
-static int wm8580_i2c_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, wm8580_codec_probe);
-}
+static const struct i2c_device_id wm8580_i2c_id[] = {
+	{ "wm8580", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
 
-/* corgi i2c codec control layer */
 static struct i2c_driver wm8580_i2c_driver = {
 	.driver = {
 		.name = "WM8580 I2C Codec",
 		.owner = THIS_MODULE,
 	},
-	.attach_adapter = wm8580_i2c_attach,
-	.detach_client =  wm8580_i2c_detach,
-	.command =        NULL,
+	.probe =    wm8580_i2c_probe,
+	.remove =   wm8580_i2c_remove,
+	.id_table = wm8580_i2c_id,
 };
 
-static struct i2c_client client_template = {
-	.name =   "WM8580",
-	.driver = &wm8580_i2c_driver,
-};
+static int wm8580_add_i2c_device(struct platform_device *pdev,
+				 const struct wm8580_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&wm8580_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "wm8580", I2C_NAME_SIZE);
+
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+			setup->i2c_bus);
+		goto err_driver;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+			(unsigned int)info.addr);
+		goto err_driver;
+	}
+
+	return 0;
+
+err_driver:
+	i2c_del_driver(&wm8580_i2c_driver);
+	return -ENODEV;
+}
 #endif
 
 static int wm8580_probe(struct platform_device *pdev)
@@ -1011,11 +1007,8 @@
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	if (setup->i2c_address) {
-		normal_i2c[0] = setup->i2c_address;
 		codec->hw_write = (hw_write_t)i2c_master_send;
-		ret = i2c_add_driver(&wm8580_i2c_driver);
-		if (ret != 0)
-			printk(KERN_ERR "can't add i2c driver");
+		ret = wm8580_add_i2c_device(pdev, setup);
 	}
 #else
 		/* Add other interfaces here */
@@ -1034,6 +1027,7 @@
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&wm8580_i2c_driver);
 #endif
 	kfree(codec->private_data);
@@ -1048,6 +1042,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
 
+static int __init wm8580_modinit(void)
+{
+	return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
+}
+module_init(wm8580_modinit);
+
+static void __exit wm8580_exit(void)
+{
+	snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
+}
+module_exit(wm8580_exit);
+
 MODULE_DESCRIPTION("ASoC WM8580 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h
index 589ddab..09e4422 100644
--- a/sound/soc/codecs/wm8580.h
+++ b/sound/soc/codecs/wm8580.h
@@ -29,6 +29,7 @@
 #define WM8580_CLKSRC_NONE 5
 
 struct wm8580_setup_data {
+	int i2c_bus;
 	unsigned short i2c_address;
 };
 
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
new file mode 100644
index 0000000..80b1198
--- /dev/null
+++ b/sound/soc/codecs/wm8728.c
@@ -0,0 +1,585 @@
+/*
+ * wm8728.c  --  WM8728 ALSA SoC Audio driver
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/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 "wm8728.h"
+
+struct snd_soc_codec_device soc_codec_dev_wm8728;
+
+/*
+ * We can't read the WM8728 register space so we cache them instead.
+ * Note that the defaults here aren't the physical defaults, we latch
+ * the volume update bits, mute the output and enable infinite zero
+ * detect.
+ */
+static const u16 wm8728_reg_defaults[] = {
+	0x1ff,
+	0x1ff,
+	0x001,
+	0x100,
+};
+
+static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults));
+	return cache[reg];
+}
+
+static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec,
+	u16 reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults));
+	cache[reg] = value;
+}
+
+/*
+ * write to the WM8728 register space
+ */
+static int wm8728_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	u8 data[2];
+
+	/* data is
+	 *   D15..D9 WM8728 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	wm8728_write_reg_cache(codec, reg, value);
+
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
+
+static const struct snd_kcontrol_new wm8728_snd_controls[] = {
+
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL,
+		 0, 255, 0, wm8728_tlv),
+
+SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0),
+};
+
+static int wm8728_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8728_snd_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				  snd_soc_cnew(&wm8728_snd_controls[i],
+						codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+/*
+ * DAPM controls.
+ */
+static const struct snd_soc_dapm_widget wm8728_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("VOUTL"),
+SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	{"VOUTL", NULL, "DAC"},
+	{"VOUTR", NULL, "DAC"},
+};
+
+static int wm8728_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, wm8728_dapm_widgets,
+				  ARRAY_SIZE(wm8728_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+	snd_soc_dapm_new_widgets(codec);
+
+	return 0;
+}
+
+static int wm8728_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u16 mute_reg = wm8728_read_reg_cache(codec, WM8728_DACCTL);
+
+	if (mute)
+		wm8728_write(codec, WM8728_DACCTL, mute_reg | 1);
+	else
+		wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1);
+
+	return 0;
+}
+
+static int wm8728_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->codec;
+	u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL);
+
+	dac &= ~0x18;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		dac |= 0x10;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		dac |= 0x08;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8728_write(codec, WM8728_DACCTL, dac);
+
+	return 0;
+}
+
+static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u16 iface = wm8728_read_reg_cache(codec, WM8728_IFCTL);
+
+	/* Currently only I2S is supported by the driver, though the
+	 * hardware is more flexible.
+	 */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* The hardware only support full slave mode */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		iface &= ~0x22;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |=  0x20;
+		iface &= ~0x02;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x02;
+		iface &= ~0x20;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x22;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8728_write(codec, WM8728_IFCTL, iface);
+	return 0;
+}
+
+static int wm8728_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	u16 reg;
+	int i;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			/* Power everything up... */
+			reg = wm8728_read_reg_cache(codec, WM8728_DACCTL);
+			wm8728_write(codec, WM8728_DACCTL, reg & ~0x4);
+
+			/* ..then sync in the register cache. */
+			for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++)
+				wm8728_write(codec, i,
+					     wm8728_read_reg_cache(codec, i));
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		reg = wm8728_read_reg_cache(codec, WM8728_DACCTL);
+		wm8728_write(codec, WM8728_DACCTL, reg | 0x4);
+		break;
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+#define WM8728_RATES (SNDRV_PCM_RATE_8000_192000)
+
+#define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_dai wm8728_dai = {
+	.name = "WM8728",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8728_RATES,
+		.formats = WM8728_FORMATS,
+	},
+	.ops = {
+		 .hw_params = wm8728_hw_params,
+		 .digital_mute = wm8728_mute,
+		 .set_fmt = wm8728_set_dai_fmt,
+	}
+};
+EXPORT_SYMBOL_GPL(wm8728_dai);
+
+static int wm8728_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int wm8728_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	wm8728_set_bias_level(codec, codec->suspend_bias_level);
+
+	return 0;
+}
+
+/*
+ * initialise the WM8728 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8728_init(struct snd_soc_device *socdev)
+{
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret = 0;
+
+	codec->name = "WM8728";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8728_read_reg_cache;
+	codec->write = wm8728_write;
+	codec->set_bias_level = wm8728_set_bias_level;
+	codec->dai = &wm8728_dai;
+	codec->num_dai = 1;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults);
+	codec->reg_cache = kmemdup(wm8728_reg_defaults,
+				   sizeof(wm8728_reg_defaults),
+				   GFP_KERNEL);
+	if (codec->reg_cache == NULL)
+		return -ENOMEM;
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8728: failed to create pcms\n");
+		goto pcm_err;
+	}
+
+	/* power on device */
+	wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	wm8728_add_controls(codec);
+	wm8728_add_widgets(codec);
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8728: failed to register card\n");
+		goto card_err;
+	}
+
+	return ret;
+
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+pcm_err:
+	kfree(codec->reg_cache);
+	return ret;
+}
+
+static struct snd_soc_device *wm8728_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+/*
+ * WM8728 2 wire address is determined by GPIO5
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+
+static int wm8728_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct snd_soc_device *socdev = wm8728_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
+	ret = wm8728_init(socdev);
+	if (ret < 0)
+		pr_err("failed to initialise WM8728\n");
+
+	return ret;
+}
+
+static int wm8728_i2c_remove(struct i2c_client *client)
+{
+	struct snd_soc_codec *codec = i2c_get_clientdata(client);
+	kfree(codec->reg_cache);
+	return 0;
+}
+
+static const struct i2c_device_id wm8728_i2c_id[] = {
+	{ "wm8728", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
+
+static struct i2c_driver wm8728_i2c_driver = {
+	.driver = {
+		.name = "WM8728 I2C Codec",
+		.owner = THIS_MODULE,
+	},
+	.probe =    wm8728_i2c_probe,
+	.remove =   wm8728_i2c_remove,
+	.id_table = wm8728_i2c_id,
+};
+
+static int wm8728_add_i2c_device(struct platform_device *pdev,
+				 const struct wm8728_setup_data *setup)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	int ret;
+
+	ret = i2c_add_driver(&wm8728_i2c_driver);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "can't add i2c driver\n");
+		return ret;
+	}
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = setup->i2c_address;
+	strlcpy(info.type, "wm8728", I2C_NAME_SIZE);
+
+	adapter = i2c_get_adapter(setup->i2c_bus);
+	if (!adapter) {
+		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+			setup->i2c_bus);
+		goto err_driver;
+	}
+
+	client = i2c_new_device(adapter, &info);
+	i2c_put_adapter(adapter);
+	if (!client) {
+		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+			(unsigned int)info.addr);
+		goto err_driver;
+	}
+
+	return 0;
+
+err_driver:
+	i2c_del_driver(&wm8728_i2c_driver);
+	return -ENODEV;
+}
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8728_spi_probe(struct spi_device *spi)
+{
+	struct snd_soc_device *socdev = wm8728_socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	int ret;
+
+	codec->control_data = spi;
+
+	ret = wm8728_init(socdev);
+	if (ret < 0)
+		dev_err(&spi->dev, "failed to initialise WM8728\n");
+
+	return ret;
+}
+
+static int __devexit wm8728_spi_remove(struct spi_device *spi)
+{
+	return 0;
+}
+
+static struct spi_driver wm8728_spi_driver = {
+	.driver = {
+		.name	= "wm8728",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm8728_spi_probe,
+	.remove		= __devexit_p(wm8728_spi_remove),
+};
+
+static int wm8728_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;
+}
+#endif /* CONFIG_SPI_MASTER */
+
+static int wm8728_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct wm8728_setup_data *setup;
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	setup = socdev->codec_data;
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	wm8728_socdev = socdev;
+	ret = -ENODEV;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	if (setup->i2c_address) {
+		codec->hw_write = (hw_write_t)i2c_master_send;
+		ret = wm8728_add_i2c_device(pdev, setup);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	if (setup->spi) {
+		codec->hw_write = (hw_write_t)wm8728_spi_write;
+		ret = spi_register_driver(&wm8728_spi_driver);
+		if (ret != 0)
+			printk(KERN_ERR "can't add spi driver");
+	}
+#endif
+
+	if (ret != 0)
+		kfree(codec);
+
+	return ret;
+}
+
+/* power down chip */
+static int wm8728_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->codec;
+
+	if (codec->control_data)
+		wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_unregister_device(codec->control_data);
+	i2c_del_driver(&wm8728_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8728_spi_driver);
+#endif
+	kfree(codec);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8728 = {
+	.probe = 	wm8728_probe,
+	.remove = 	wm8728_remove,
+	.suspend = 	wm8728_suspend,
+	.resume =	wm8728_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728);
+
+static int __init wm8728_modinit(void)
+{
+	return snd_soc_register_dai(&wm8728_dai);
+}
+module_init(wm8728_modinit);
+
+static void __exit wm8728_exit(void)
+{
+	snd_soc_unregister_dai(&wm8728_dai);
+}
+module_exit(wm8728_exit);
+
+MODULE_DESCRIPTION("ASoC WM8728 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8728.h b/sound/soc/codecs/wm8728.h
new file mode 100644
index 0000000..d269c13
--- /dev/null
+++ b/sound/soc/codecs/wm8728.h
@@ -0,0 +1,30 @@
+/*
+ * wm8728.h  --  WM8728 ASoC codec driver
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8728_H
+#define _WM8728_H
+
+#define WM8728_DACLVOL   0x00
+#define WM8728_DACRVOL   0x01
+#define WM8728_DACCTL    0x02
+#define WM8728_IFCTL     0x03
+
+struct wm8728_setup_data {
+	int            spi;
+	int            i2c_bus;
+	unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai wm8728_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8728;
+
+#endif
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 7f8a7e3..c444b9f 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -264,7 +264,8 @@
 }
 
 static int wm8731_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+			    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;
@@ -293,7 +294,8 @@
 	return 0;
 }
 
-static int wm8731_pcm_prepare(struct snd_pcm_substream *substream)
+static int wm8731_pcm_prepare(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;
@@ -305,7 +307,8 @@
 	return 0;
 }
 
-static void wm8731_shutdown(struct snd_pcm_substream *substream)
+static void wm8731_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;
@@ -461,8 +464,6 @@
 		.prepare = wm8731_pcm_prepare,
 		.hw_params = wm8731_hw_params,
 		.shutdown = wm8731_shutdown,
-	},
-	.dai_ops = {
 		.digital_mute = wm8731_mute,
 		.set_sysclk = wm8731_set_dai_sysclk,
 		.set_fmt = wm8731_set_dai_fmt,
@@ -544,7 +545,7 @@
 
 	wm8731_add_controls(codec);
 	wm8731_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8731: failed to register card\n");
 		goto card_err;
@@ -792,6 +793,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
 
+static int __init wm8731_modinit(void)
+{
+	return snd_soc_register_dai(&wm8731_dai);
+}
+module_init(wm8731_modinit);
+
+static void __exit wm8731_exit(void)
+{
+	snd_soc_unregister_dai(&wm8731_dai);
+}
+module_exit(wm8731_exit);
+
 MODULE_DESCRIPTION("ASoC WM8731 driver");
 MODULE_AUTHOR("Richard Purdie");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 9b7296e..5997fa6 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -614,7 +614,8 @@
 }
 
 static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+				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;
@@ -709,8 +710,6 @@
 		.formats = WM8750_FORMATS,},
 	.ops = {
 		.hw_params = wm8750_pcm_hw_params,
-	},
-	.dai_ops = {
 		.digital_mute = wm8750_mute,
 		.set_fmt = wm8750_set_dai_fmt,
 		.set_sysclk = wm8750_set_dai_sysclk,
@@ -819,7 +818,7 @@
 
 	wm8750_add_controls(codec);
 	wm8750_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8750: failed to register card\n");
 		goto card_err;
@@ -1086,6 +1085,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750);
 
+static int __init wm8750_modinit(void)
+{
+	return snd_soc_register_dai(&wm8750_dai);
+}
+module_init(wm8750_modinit);
+
+static void __exit wm8750_exit(void)
+{
+	snd_soc_unregister_dai(&wm8750_dai);
+}
+module_exit(wm8750_exit);
+
 MODULE_DESCRIPTION("ASoC WM8750 driver");
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index d426eaa..6c21b50 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -922,7 +922,8 @@
  * Set PCM DAI bit size and sample rate.
  */
 static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+				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;
@@ -1155,7 +1156,8 @@
  * Set PCM DAI bit size and sample rate.
  */
 static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+				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;
@@ -1323,16 +1325,15 @@
 		.channels_min = 1,
 		.channels_max = 2,
 		.rates = WM8753_RATES,
-		.formats = WM8753_FORMATS,},
+		.formats = WM8753_FORMATS},
 	.capture = { /* dummy for fast DAI switching */
 		.stream_name = "Capture",
 		.channels_min = 1,
 		.channels_max = 2,
 		.rates = WM8753_RATES,
-		.formats = WM8753_FORMATS,},
+		.formats = WM8753_FORMATS},
 	.ops = {
-		.hw_params = wm8753_i2s_hw_params,},
-	.dai_ops = {
+		.hw_params = wm8753_i2s_hw_params,
 		.digital_mute = wm8753_mute,
 		.set_fmt = wm8753_mode1h_set_dai_fmt,
 		.set_clkdiv = wm8753_set_dai_clkdiv,
@@ -1356,8 +1357,7 @@
 		.rates = WM8753_RATES,
 		.formats = WM8753_FORMATS,},
 	.ops = {
-		.hw_params = wm8753_pcm_hw_params,},
-	.dai_ops = {
+		.hw_params = wm8753_pcm_hw_params,
 		.digital_mute = wm8753_mute,
 		.set_fmt = wm8753_mode1v_set_dai_fmt,
 		.set_clkdiv = wm8753_set_dai_clkdiv,
@@ -1385,8 +1385,7 @@
 		.rates = WM8753_RATES,
 		.formats = WM8753_FORMATS,},
 	.ops = {
-		.hw_params = wm8753_pcm_hw_params,},
-	.dai_ops = {
+		.hw_params = wm8753_pcm_hw_params,
 		.digital_mute = wm8753_mute,
 		.set_fmt = wm8753_mode2_set_dai_fmt,
 		.set_clkdiv = wm8753_set_dai_clkdiv,
@@ -1410,8 +1409,7 @@
 		.rates = WM8753_RATES,
 		.formats = WM8753_FORMATS,},
 	.ops = {
-		.hw_params = wm8753_i2s_hw_params,},
-	.dai_ops = {
+		.hw_params = wm8753_i2s_hw_params,
 		.digital_mute = wm8753_mute,
 		.set_fmt = wm8753_mode3_4_set_dai_fmt,
 		.set_clkdiv = wm8753_set_dai_clkdiv,
@@ -1439,8 +1437,7 @@
 		.rates = WM8753_RATES,
 		.formats = WM8753_FORMATS,},
 	.ops = {
-		.hw_params = wm8753_i2s_hw_params,},
-	.dai_ops = {
+		.hw_params = wm8753_i2s_hw_params,
 		.digital_mute = wm8753_mute,
 		.set_fmt = wm8753_mode3_4_set_dai_fmt,
 		.set_clkdiv = wm8753_set_dai_clkdiv,
@@ -1608,7 +1605,7 @@
 
 	wm8753_add_controls(codec);
 	wm8753_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8753: failed to register card\n");
 		goto card_err;
@@ -1877,6 +1874,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
 
+static int __init wm8753_modinit(void)
+{
+	return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai));
+}
+module_init(wm8753_modinit);
+
+static void __exit wm8753_exit(void)
+{
+	snd_soc_unregister_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai));
+}
+module_exit(wm8753_exit);
+
 MODULE_DESCRIPTION("ASoC WM8753 driver");
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 3b326c9..6767de1 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -138,6 +138,10 @@
 struct snd_soc_codec_device soc_codec_dev_wm8900;
 
 struct wm8900_priv {
+	struct snd_soc_codec codec;
+
+	u16 reg_cache[WM8900_MAXREG];
+
 	u32 fll_in; /* FLL input frequency */
 	u32 fll_out; /* FLL output frequency */
 };
@@ -727,7 +731,8 @@
 }
 
 static int wm8900_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+	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;
@@ -1117,8 +1122,6 @@
 	 },
 	.ops = {
 		.hw_params = wm8900_hw_params,
-	 },
-	.dai_ops = {
 		 .set_clkdiv = wm8900_set_dai_clkdiv,
 		 .set_pll = wm8900_set_dai_pll,
 		 .set_fmt = wm8900_set_dai_fmt,
@@ -1283,16 +1286,28 @@
 	return 0;
 }
 
-/*
- * initialise the WM8900 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8900_init(struct snd_soc_device *socdev)
+static struct snd_soc_codec *wm8900_codec;
+
+static int wm8900_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
 {
-	struct snd_soc_codec *codec = socdev->codec;
-	int ret = 0;
+	struct wm8900_priv *wm8900;
+	struct snd_soc_codec *codec;
 	unsigned int reg;
-	struct i2c_client *i2c_client = socdev->codec->control_data;
+	int ret;
+
+	wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+	if (wm8900 == NULL)
+		return -ENOMEM;
+
+	codec = &wm8900->codec;
+	codec->private_data = wm8900;
+	codec->reg_cache = &wm8900->reg_cache[0];
+	codec->reg_cache_size = WM8900_MAXREG;
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
 
 	codec->name = "WM8900";
 	codec->owner = THIS_MODULE;
@@ -1300,33 +1315,28 @@
 	codec->write = wm8900_write;
 	codec->dai = &wm8900_dai;
 	codec->num_dai = 1;
-	codec->reg_cache_size = WM8900_MAXREG;
-	codec->reg_cache = kmemdup(wm8900_reg_defaults,
-				   sizeof(wm8900_reg_defaults), GFP_KERNEL);
-
-	if (codec->reg_cache == NULL)
-		return -ENOMEM;
+	codec->hw_write = (hw_write_t)i2c_master_send;
+	codec->control_data = i2c;
+	codec->set_bias_level = wm8900_set_bias_level;
+	codec->dev = &i2c->dev;
 
 	reg = wm8900_read(codec, WM8900_REG_ID);
 	if (reg != 0x8900) {
-		dev_err(&i2c_client->dev, "Device is not a WM8900 - ID %x\n",
-			reg);
-		return -ENODEV;
-	}
-
-	codec->private_data = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
-	if (codec->private_data == NULL) {
-		ret = -ENOMEM;
-		goto priv_err;
+		dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg);
+		ret = -ENODEV;
+		goto err;
 	}
 
 	/* Read back from the chip */
 	reg = wm8900_chip_read(codec, WM8900_REG_POWER1);
 	reg = (reg >> 12) & 0xf;
-	dev_info(&i2c_client->dev, "WM8900 revision %d\n", reg);
+	dev_info(&i2c->dev, "WM8900 revision %d\n", reg);
 
 	wm8900_reset(codec);
 
+	/* Turn the chip on */
+	wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
 	/* Latch the volume update bits */
 	wm8900_write(codec, WM8900_REG_LINVOL,
 		     wm8900_read(codec, WM8900_REG_LINVOL) | 0x100);
@@ -1352,160 +1362,98 @@
 	/* Set the DAC and mixer output bias */
 	wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
 
+	wm8900_dai.dev = &i2c->dev;
+
+	wm8900_codec = codec;
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		goto err;
+	}
+
+	ret = snd_soc_register_dai(&wm8900_dai);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
+		goto err_codec;
+	}
+
+	return ret;
+
+err_codec:
+	snd_soc_unregister_codec(codec);
+err:
+	kfree(wm8900);
+	wm8900_codec = NULL;
+	return ret;
+}
+
+static int wm8900_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_dai(&wm8900_dai);
+	snd_soc_unregister_codec(wm8900_codec);
+
+	wm8900_set_bias_level(wm8900_codec, SND_SOC_BIAS_OFF);
+
+	wm8900_dai.dev = NULL;
+	kfree(wm8900_codec->private_data);
+	wm8900_codec = NULL;
+
+	return 0;
+}
+
+static const struct i2c_device_id wm8900_i2c_id[] = {
+	{ "wm8900", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id);
+
+static struct i2c_driver wm8900_i2c_driver = {
+	.driver = {
+		.name = "WM8900",
+		.owner = THIS_MODULE,
+	},
+	.probe = wm8900_i2c_probe,
+	.remove = wm8900_i2c_remove,
+	.id_table = wm8900_i2c_id,
+};
+
+static int wm8900_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	if (!wm8900_codec) {
+		dev_err(&pdev->dev, "I2C client not yet instantiated\n");
+		return -ENODEV;
+	}
+
+	codec = wm8900_codec;
+	socdev->codec = codec;
+
 	/* Register pcms */
 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 	if (ret < 0) {
-		dev_err(&i2c_client->dev, "Failed to register new PCMs\n");
+		dev_err(&pdev->dev, "Failed to register new PCMs\n");
 		goto pcm_err;
 	}
 
-	/* Turn the chip on */
-	codec->bias_level = SND_SOC_BIAS_OFF;
-	wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	wm8900_add_controls(codec);
 	wm8900_add_widgets(codec);
 
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
-		dev_err(&i2c_client->dev, "Failed to register card\n");
+		dev_err(&pdev->dev, "Failed to register card\n");
 		goto card_err;
 	}
+
 	return ret;
 
 card_err:
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
 pcm_err:
-	kfree(codec->reg_cache);
-priv_err:
-	kfree(codec->private_data);
-	return ret;
-}
-
-static struct snd_soc_device *wm8900_socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver wm8900_i2c_driver;
-static struct i2c_client client_template;
-
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static int wm8900_codec_probe(struct i2c_adapter *adap, int addr, int kind)
-{
-	struct snd_soc_device *socdev = wm8900_socdev;
-	struct wm8900_setup_data *setup = socdev->codec_data;
-	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c;
-	int ret;
-
-	if (addr != setup->i2c_address)
-		return -ENODEV;
-
-	dev_err(&adap->dev, "Probe on %x\n", addr);
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-	if (i2c == NULL) {
-		kfree(codec);
-		return -ENOMEM;
-	}
-	i2c_set_clientdata(i2c, codec);
-	codec->control_data = i2c;
-
-	ret = i2c_attach_client(i2c);
-	if (ret < 0) {
-		dev_err(&adap->dev,
-			"failed to attach codec at addr %x\n", addr);
-		goto err;
-	}
-
-	ret = wm8900_init(socdev);
-	if (ret < 0) {
-		dev_err(&adap->dev, "failed to initialise WM8900\n");
-		goto err;
-	}
-	return ret;
-
-err:
-	kfree(codec);
-	kfree(i2c);
-	return ret;
-}
-
-static int wm8900_i2c_detach(struct i2c_client *client)
-{
-	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	i2c_detach_client(client);
-	kfree(codec->reg_cache);
-	kfree(client);
-	return 0;
-}
-
-static int wm8900_i2c_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, wm8900_codec_probe);
-}
-
-/* corgi i2c codec control layer */
-static struct i2c_driver wm8900_i2c_driver = {
-	.driver = {
-		.name = "WM8900 I2C codec",
-		.owner = THIS_MODULE,
-	},
-	.attach_adapter = wm8900_i2c_attach,
-	.detach_client =  wm8900_i2c_detach,
-	.command =        NULL,
-};
-
-static struct i2c_client client_template = {
-	.name =   "WM8900",
-	.driver = &wm8900_i2c_driver,
-};
-#endif
-
-static int wm8900_probe(struct platform_device *pdev)
-{
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct wm8900_setup_data *setup;
-	struct snd_soc_codec *codec;
-	int ret = 0;
-
-	dev_info(&pdev->dev, "WM8900 Audio Codec\n");
-
-	setup = socdev->codec_data;
-	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (codec == NULL)
-		return -ENOMEM;
-
-	mutex_init(&codec->mutex);
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-
-	socdev->codec = codec;
-
-	codec->set_bias_level = wm8900_set_bias_level;
-
-	wm8900_socdev = socdev;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	if (setup->i2c_address) {
-		normal_i2c[0] = setup->i2c_address;
-		codec->hw_write = (hw_write_t)i2c_master_send;
-		ret = i2c_add_driver(&wm8900_i2c_driver);
-		if (ret != 0)
-			printk(KERN_ERR "can't add i2c driver");
-	}
-#else
-#error Non-I2C interfaces not yet supported
-#endif
 	return ret;
 }
 
@@ -1513,17 +1461,9 @@
 static int wm8900_remove(struct platform_device *pdev)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->codec;
-
-	if (codec->control_data)
-		wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	i2c_del_driver(&wm8900_i2c_driver);
-#endif
-	kfree(codec);
 
 	return 0;
 }
@@ -1536,6 +1476,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900);
 
+static int __init wm8900_modinit(void)
+{
+	return i2c_add_driver(&wm8900_i2c_driver);
+}
+module_init(wm8900_modinit);
+
+static void __exit wm8900_exit(void)
+{
+	i2c_del_driver(&wm8900_i2c_driver);
+}
+module_exit(wm8900_exit);
+
 MODULE_DESCRIPTION("ASoC WM8900 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h
index ba450d9..fd15007 100644
--- a/sound/soc/codecs/wm8900.h
+++ b/sound/soc/codecs/wm8900.h
@@ -52,12 +52,6 @@
 #define WM8900_DAC_CLKDIV_5_5 0x14
 #define WM8900_DAC_CLKDIV_6   0x18
 
-#define WM8900_
-
-struct wm8900_setup_data {
-	unsigned short i2c_address;
-};
-
 extern struct snd_soc_dai wm8900_dai;
 extern struct snd_soc_codec_device soc_codec_dev_wm8900;
 
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index ce40d78..bde7454 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -33,19 +33,6 @@
 
 #include "wm8903.h"
 
-struct wm8903_priv {
-	int sysclk;
-
-	/* Reference counts */
-	int charge_pump_users;
-	int class_w_users;
-	int playback_active;
-	int capture_active;
-
-	struct snd_pcm_substream *master_substream;
-	struct snd_pcm_substream *slave_substream;
-};
-
 /* Register defaults at reset */
 static u16 wm8903_reg_defaults[] = {
 	0x8903,     /* R0   - SW Reset and ID */
@@ -223,6 +210,23 @@
 	0x0000,     /* R172 - Analogue Output Bias 0 */
 };
 
+struct wm8903_priv {
+	struct snd_soc_codec codec;
+	u16 reg_cache[ARRAY_SIZE(wm8903_reg_defaults)];
+
+	int sysclk;
+
+	/* Reference counts */
+	int charge_pump_users;
+	int class_w_users;
+	int playback_active;
+	int capture_active;
+
+	struct snd_pcm_substream *master_substream;
+	struct snd_pcm_substream *slave_substream;
+};
+
+
 static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec,
 						 unsigned int reg)
 {
@@ -360,6 +364,8 @@
 static void wm8903_reset(struct snd_soc_codec *codec)
 {
 	wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0);
+	memcpy(codec->reg_cache, wm8903_reg_defaults,
+	       sizeof(wm8903_reg_defaults));
 }
 
 #define WM8903_OUTPUT_SHORT 0x8
@@ -392,6 +398,7 @@
 		break;
 	default:
 		BUG();
+		return -EINVAL;  /* Spurious warning from some compilers */
 	}
 
 	switch (w->shift) {
@@ -403,6 +410,7 @@
 		break;
 	default:
 		BUG();
+		return -EINVAL;  /* Spurious warning from some compilers */
 	}
 
 	if (event & SND_SOC_DAPM_PRE_PMU) {
@@ -773,14 +781,14 @@
 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),
 SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0),
-SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0),
+SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 0, 1, 0),
 };
 
 static const struct snd_kcontrol_new right_output_mixer[] = {
 SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 3, 1, 0),
 SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 2, 1, 0),
 SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0),
-SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0),
+SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 0, 1, 0),
 };
 
 static const struct snd_kcontrol_new left_speaker_mixer[] = {
@@ -788,7 +796,7 @@
 SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 2, 1, 0),
 SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 1, 1, 0),
 SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0,
-		1, 1, 0),
+		0, 1, 0),
 };
 
 static const struct snd_kcontrol_new right_speaker_mixer[] = {
@@ -797,7 +805,7 @@
 SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0,
 		1, 1, 0),
 SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0,
-		1, 1, 0),
+		0, 1, 0),
 };
 
 static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = {
@@ -989,6 +997,9 @@
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			wm8903_write(codec, WM8903_CLOCK_RATES_2,
+				     WM8903_CLK_SYS_ENA);
+
 			wm8903_run_sequence(codec, 0);
 			wm8903_sync_reg_cache(codec, codec->reg_cache);
 
@@ -1019,6 +1030,9 @@
 
 	case SND_SOC_BIAS_OFF:
 		wm8903_run_sequence(codec, 32);
+		reg = wm8903_read(codec, WM8903_CLOCK_RATES_2);
+		reg &= ~WM8903_CLK_SYS_ENA;
+		wm8903_write(codec, WM8903_CLOCK_RATES_2, reg);
 		break;
 	}
 
@@ -1257,7 +1271,8 @@
 	{ 0,      0 },
 };
 
-static int wm8903_startup(struct snd_pcm_substream *substream)
+static int wm8903_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;
@@ -1298,7 +1313,8 @@
 	return 0;
 }
 
-static void wm8903_shutdown(struct snd_pcm_substream *substream)
+static void wm8903_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;
@@ -1317,7 +1333,8 @@
 }
 
 static int wm8903_hw_params(struct snd_pcm_substream *substream,
-			    struct snd_pcm_hw_params *params)
+			    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;
@@ -1515,8 +1532,6 @@
 		 .startup = wm8903_startup,
 		 .shutdown = wm8903_shutdown,
 		 .hw_params = wm8903_hw_params,
-	},
-	.dai_ops = {
 		 .digital_mute = wm8903_digital_mute,
 		 .set_fmt = wm8903_set_dai_fmt,
 		 .set_sysclk = wm8903_set_dai_sysclk
@@ -1560,17 +1575,43 @@
 	return 0;
 }
 
-/*
- * initialise the WM8903 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8903_init(struct snd_soc_device *socdev)
+static struct snd_soc_codec *wm8903_codec;
+
+static int wm8903_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
 {
-	struct snd_soc_codec *codec = socdev->codec;
-	struct i2c_client *i2c = codec->control_data;
-	int ret = 0;
+	struct wm8903_priv *wm8903;
+	struct snd_soc_codec *codec;
+	int ret;
 	u16 val;
 
+	wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
+	if (wm8903 == NULL)
+		return -ENOMEM;
+
+	codec = &wm8903->codec;
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->dev = &i2c->dev;
+	codec->name = "WM8903";
+	codec->owner = THIS_MODULE;
+	codec->read = wm8903_read;
+	codec->write = wm8903_write;
+	codec->hw_write = (hw_write_t)i2c_master_send;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->set_bias_level = wm8903_set_bias_level;
+	codec->dai = &wm8903_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache);
+	codec->reg_cache = &wm8903->reg_cache[0];
+	codec->private_data = wm8903;
+
+	i2c_set_clientdata(i2c, codec);
+	codec->control_data = i2c;
+
 	val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID);
 	if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) {
 		dev_err(&i2c->dev,
@@ -1578,39 +1619,12 @@
 		return -ENODEV;
 	}
 
-	codec->name = "WM8903";
-	codec->owner = THIS_MODULE;
-	codec->read = wm8903_read;
-	codec->write = wm8903_write;
-	codec->bias_level = SND_SOC_BIAS_OFF;
-	codec->set_bias_level = wm8903_set_bias_level;
-	codec->dai = &wm8903_dai;
-	codec->num_dai = 1;
-	codec->reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults);
-	codec->reg_cache = kmemdup(wm8903_reg_defaults,
-				   sizeof(wm8903_reg_defaults),
-				   GFP_KERNEL);
-	if (codec->reg_cache == NULL) {
-		dev_err(&i2c->dev, "Failed to allocate register cache\n");
-		return -ENOMEM;
-	}
-
 	val = wm8903_read(codec, WM8903_REVISION_NUMBER);
 	dev_info(&i2c->dev, "WM8903 revision %d\n",
 		 val & WM8903_CHIP_REV_MASK);
 
 	wm8903_reset(codec);
 
-	/* register pcms */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if (ret < 0) {
-		dev_err(&i2c->dev, "failed to create pcms\n");
-		goto pcm_err;
-	}
-
-	/* SYSCLK is required for pretty much anything */
-	wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA);
-
 	/* power on device */
 	wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -1645,47 +1659,45 @@
 	val |= WM8903_DAC_MUTEMODE;
 	wm8903_write(codec, WM8903_DAC_DIGITAL_1, val);
 
-	wm8903_add_controls(codec);
-	wm8903_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
-	if (ret < 0) {
-		dev_err(&i2c->dev, "wm8903: failed to register card\n");
-		goto card_err;
+	wm8903_dai.dev = &i2c->dev;
+	wm8903_codec = codec;
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		goto err;
+	}
+
+	ret = snd_soc_register_dai(&wm8903_dai);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
+		goto err_codec;
 	}
 
 	return ret;
 
-card_err:
-	snd_soc_free_pcms(socdev);
-	snd_soc_dapm_free(socdev);
-pcm_err:
-	kfree(codec->reg_cache);
-	return ret;
-}
-
-static struct snd_soc_device *wm8903_socdev;
-
-static int wm8903_i2c_probe(struct i2c_client *i2c,
-			    const struct i2c_device_id *id)
-{
-	struct snd_soc_device *socdev = wm8903_socdev;
-	struct snd_soc_codec *codec = socdev->codec;
-	int ret;
-
-	i2c_set_clientdata(i2c, codec);
-	codec->control_data = i2c;
-
-	ret = wm8903_init(socdev);
-	if (ret < 0)
-		dev_err(&i2c->dev, "Device initialisation failed\n");
-
+err_codec:
+	snd_soc_unregister_codec(codec);
+err:
+	wm8903_codec = NULL;
+	kfree(wm8903);
 	return ret;
 }
 
 static int wm8903_i2c_remove(struct i2c_client *client)
 {
 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	kfree(codec->reg_cache);
+
+	snd_soc_unregister_dai(&wm8903_dai);
+	snd_soc_unregister_codec(codec);
+
+	wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	kfree(codec->private_data);
+
+	wm8903_codec = NULL;
+	wm8903_dai.dev = NULL;
+
 	return 0;
 }
 
@@ -1709,75 +1721,37 @@
 static int wm8903_probe(struct platform_device *pdev)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct wm8903_setup_data *setup;
-	struct snd_soc_codec *codec;
-	struct wm8903_priv *wm8903;
-	struct i2c_board_info board_info;
-	struct i2c_adapter *adapter;
-	struct i2c_client *i2c_client;
 	int ret = 0;
 
-	setup = socdev->codec_data;
-
-	if (!setup->i2c_address) {
-		dev_err(&pdev->dev, "No codec address provided\n");
-		return -ENODEV;
+	if (!wm8903_codec) {
+		dev_err(&pdev->dev, "I2C device not yet probed\n");
+		goto err;
 	}
 
-	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (codec == NULL)
-		return -ENOMEM;
+	socdev->codec = wm8903_codec;
 
-	wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
-	if (wm8903 == NULL) {
-		ret = -ENOMEM;
-		goto err_codec;
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to create pcms\n");
+		goto err;
 	}
 
-	codec->private_data = wm8903;
-	socdev->codec = codec;
-	mutex_init(&codec->mutex);
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
+	wm8903_add_controls(socdev->codec);
+	wm8903_add_widgets(socdev->codec);
 
-	wm8903_socdev = socdev;
-
-	codec->hw_write = (hw_write_t)i2c_master_send;
-	ret = i2c_add_driver(&wm8903_i2c_driver);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "can't add i2c driver\n");
-		goto err_priv;
-	} else {
-		memset(&board_info, 0, sizeof(board_info));
-		strlcpy(board_info.type, "wm8903", I2C_NAME_SIZE);
-		board_info.addr = setup->i2c_address;
-
-		adapter = i2c_get_adapter(setup->i2c_bus);
-		if (!adapter) {
-			dev_err(&pdev->dev, "Can't get I2C bus %d\n",
-				setup->i2c_bus);
-			ret = -ENODEV;
-			goto err_adapter;
-		}
-
-		i2c_client = i2c_new_device(adapter, &board_info);
-		i2c_put_adapter(adapter);
-		if (i2c_client == NULL) {
-			dev_err(&pdev->dev,
-				"I2C driver registration failed\n");
-			ret = -ENODEV;
-			goto err_adapter;
-		}
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "wm8903: failed to register card\n");
+		goto card_err;
 	}
 
 	return ret;
 
-err_adapter:
-	i2c_del_driver(&wm8903_i2c_driver);
-err_priv:
-	kfree(codec->private_data);
-err_codec:
-	kfree(codec);
+card_err:
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+err:
 	return ret;
 }
 
@@ -1792,10 +1766,6 @@
 
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
-	i2c_unregister_device(socdev->codec->control_data);
-	i2c_del_driver(&wm8903_i2c_driver);
-	kfree(codec->private_data);
-	kfree(codec);
 
 	return 0;
 }
@@ -1808,6 +1778,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903);
 
+static int __init wm8903_modinit(void)
+{
+	return i2c_add_driver(&wm8903_i2c_driver);
+}
+module_init(wm8903_modinit);
+
+static void __exit wm8903_exit(void)
+{
+	i2c_del_driver(&wm8903_i2c_driver);
+}
+module_exit(wm8903_exit);
+
 MODULE_DESCRIPTION("ASoC WM8903 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h
index cec622f..0ea27e2 100644
--- a/sound/soc/codecs/wm8903.h
+++ b/sound/soc/codecs/wm8903.h
@@ -18,11 +18,6 @@
 extern struct snd_soc_dai wm8903_dai;
 extern struct snd_soc_codec_device soc_codec_dev_wm8903;
 
-struct wm8903_setup_data {
-	int i2c_bus;
-	int i2c_address;
-};
-
 #define WM8903_MCLK_DIV_2 1
 #define WM8903_CLK_SYS    2
 #define WM8903_BCLK       3
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index f41a578..88ead7f 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -541,7 +541,8 @@
 }
 
 static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+	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;
@@ -634,8 +635,6 @@
 		.formats = WM8971_FORMATS,},
 	.ops = {
 		.hw_params = wm8971_pcm_hw_params,
-	},
-	.dai_ops = {
 		.digital_mute = wm8971_mute,
 		.set_fmt = wm8971_set_dai_fmt,
 		.set_sysclk = wm8971_set_dai_sysclk,
@@ -748,7 +747,7 @@
 
 	wm8971_add_controls(codec);
 	wm8971_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8971: failed to register card\n");
 		goto card_err;
@@ -936,6 +935,18 @@
 
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971);
 
+static int __init wm8971_modinit(void)
+{
+	return snd_soc_register_dai(&wm8971_dai);
+}
+module_init(wm8971_modinit);
+
+static void __exit wm8971_exit(void)
+{
+	snd_soc_unregister_dai(&wm8971_dai);
+}
+module_exit(wm8971_exit);
+
 MODULE_DESCRIPTION("ASoC WM8971 driver");
 MODULE_AUTHOR("Lab126");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 572d22b..5b5afc1 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -106,6 +106,7 @@
 	0x0008,     /* R60 - PLL1 */
 	0x0031,     /* R61 - PLL2 */
 	0x0026,     /* R62 - PLL3 */
+	0x0000,	    /* R63 - Driver internal */
 };
 
 /*
@@ -126,10 +127,9 @@
 	unsigned int reg, unsigned int value)
 {
 	u16 *cache = codec->reg_cache;
-	BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1);
 
-	/* Reset register is uncached */
-	if (reg == 0)
+	/* Reset register and reserved registers are uncached */
+	if (reg == 0 || reg > ARRAY_SIZE(wm8990_reg) - 1)
 		return;
 
 	cache[reg] = value;
@@ -1172,7 +1172,8 @@
  * Set PCM DAI bit size and sample rate.
  */
 static int wm8990_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+			    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;
@@ -1222,8 +1223,14 @@
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
+
 	case SND_SOC_BIAS_PREPARE:
+		/* VMID=2*50k */
+		val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) &
+			~WM8990_VMID_MODE_MASK;
+		wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2);
 		break;
+
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->bias_level == SND_SOC_BIAS_OFF) {
 			/* Enable all output discharge bits */
@@ -1272,10 +1279,17 @@
 
 			/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
 			wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN);
-		} else {
-			/* ON -> standby */
 
+			/* Enable workaround for ADC clocking issue. */
+			wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2);
+			wm8990_write(codec, WM8990_EXT_CTL1, 0xa003);
+			wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0);
 		}
+
+		/* VMID=2*250k */
+		val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) &
+			~WM8990_VMID_MODE_MASK;
+		wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4);
 		break;
 
 	case SND_SOC_BIAS_OFF:
@@ -1349,8 +1363,7 @@
 		.rates = WM8990_RATES,
 		.formats = WM8990_FORMATS,},
 	.ops = {
-		.hw_params = wm8990_hw_params,},
-	.dai_ops = {
+		.hw_params = wm8990_hw_params,
 		.digital_mute = wm8990_mute,
 		.set_fmt = wm8990_set_dai_fmt,
 		.set_clkdiv = wm8990_set_dai_clkdiv,
@@ -1449,7 +1462,7 @@
 
 	wm8990_add_controls(codec);
 	wm8990_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8990: failed to register card\n");
 		goto card_err;
@@ -1630,6 +1643,18 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990);
 
+static int __init wm8990_modinit(void)
+{
+	return snd_soc_register_dai(&wm8990_dai);
+}
+module_init(wm8990_modinit);
+
+static void __exit wm8990_exit(void)
+{
+	snd_soc_unregister_dai(&wm8990_dai);
+}
+module_exit(wm8990_exit);
+
 MODULE_DESCRIPTION("ASoC WM8990 driver");
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h
index 0e192f3..7114ddc 100644
--- a/sound/soc/codecs/wm8990.h
+++ b/sound/soc/codecs/wm8990.h
@@ -80,8 +80,8 @@
 #define WM8990_PLL3                             0x3E
 #define WM8990_INTDRIVBITS			0x3F
 
-#define WM8990_REGISTER_COUNT                   60
-#define WM8990_MAX_REGISTER                     0x3F
+#define WM8990_EXT_ACCESS_ENA			0x75
+#define WM8990_EXT_CTL1				0x7a
 
 /*
  * Field Definitions.
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index ffb471e..af83d62 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -487,7 +487,8 @@
 	return 0;
 }
 
-static int ac97_prepare(struct snd_pcm_substream *substream)
+static int ac97_prepare(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -507,7 +508,8 @@
 	return ac97_write(codec, reg, runtime->rate);
 }
 
-static int ac97_aux_prepare(struct snd_pcm_substream *substream)
+static int ac97_aux_prepare(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -533,7 +535,7 @@
 struct snd_soc_dai wm9712_dai[] = {
 {
 	.name = "AC97 HiFi",
-	.type = SND_SOC_DAI_AC97_BUS,
+	.ac97_control = 1,
 	.playback = {
 		.stream_name = "HiFi Playback",
 		.channels_min = 1,
@@ -688,7 +690,7 @@
 
 	ret = wm9712_reset(codec, 0);
 	if (ret < 0) {
-		printk(KERN_ERR "AC97 link error\n");
+		printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n");
 		goto reset_err;
 	}
 
@@ -698,7 +700,7 @@
 	wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	wm9712_add_controls(codec);
 	wm9712_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
 		printk(KERN_ERR "wm9712: failed to register card\n");
 		goto reset_err;
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 945b32e..f3ca8aa 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -928,11 +928,10 @@
 }
 
 static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+				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->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xfff3;
 
 	switch (params_format(params)) {
@@ -954,11 +953,10 @@
 	return 0;
 }
 
-static void wm9713_voiceshutdown(struct snd_pcm_substream *substream)
+static void wm9713_voiceshutdown(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->codec;
+	struct snd_soc_codec *codec = dai->codec;
 	u16 status;
 
 	/* Gracefully shut down the voice interface. */
@@ -969,12 +967,11 @@
 	ac97_write(codec, AC97_EXTENDED_MID, status);
 }
 
-static int ac97_hifi_prepare(struct snd_pcm_substream *substream)
+static int ac97_hifi_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;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_device *socdev = rtd->socdev;
-	struct snd_soc_codec *codec = socdev->codec;
 	int reg;
 	u16 vra;
 
@@ -989,12 +986,11 @@
 	return ac97_write(codec, reg, runtime->rate);
 }
 
-static int ac97_aux_prepare(struct snd_pcm_substream *substream)
+static int ac97_aux_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;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_device *socdev = rtd->socdev;
-	struct snd_soc_codec *codec = socdev->codec;
 	u16 vra, xsle;
 
 	vra = ac97_read(codec, AC97_EXTENDED_STATUS);
@@ -1028,7 +1024,7 @@
 struct snd_soc_dai wm9713_dai[] = {
 {
 	.name = "AC97 HiFi",
-	.type = SND_SOC_DAI_AC97_BUS,
+	.ac97_control = 1,
 	.playback = {
 		.stream_name = "HiFi Playback",
 		.channels_min = 1,
@@ -1042,8 +1038,7 @@
 		.rates = WM9713_RATES,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
 	.ops = {
-		.prepare = ac97_hifi_prepare,},
-	.dai_ops = {
+		.prepare = ac97_hifi_prepare,
 		.set_clkdiv = wm9713_set_dai_clkdiv,
 		.set_pll = wm9713_set_dai_pll,},
 	},
@@ -1056,8 +1051,7 @@
 		.rates = WM9713_RATES,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
 	.ops = {
-		.prepare = ac97_aux_prepare,},
-	.dai_ops = {
+		.prepare = ac97_aux_prepare,
 		.set_clkdiv = wm9713_set_dai_clkdiv,
 		.set_pll = wm9713_set_dai_pll,},
 	},
@@ -1077,8 +1071,7 @@
 		.formats = WM9713_PCM_FORMATS,},
 	.ops = {
 		.hw_params = wm9713_pcm_hw_params,
-		.shutdown = wm9713_voiceshutdown,},
-	.dai_ops = {
+		.shutdown = wm9713_voiceshutdown,
 		.set_clkdiv = wm9713_set_dai_clkdiv,
 		.set_pll = wm9713_set_dai_pll,
 		.set_fmt = wm9713_set_dai_fmt,
@@ -1097,6 +1090,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) != wm9713_reg[0])
 		return -EIO;
 	return 0;
@@ -1240,7 +1235,7 @@
 	wm9713_reset(codec, 0);
 	ret = wm9713_reset(codec, 1);
 	if (ret < 0) {
-		printk(KERN_ERR "AC97 link error\n");
+		printk(KERN_ERR "Failed to reset WM9713: AC97 link error\n");
 		goto reset_err;
 	}
 
@@ -1252,7 +1247,7 @@
 
 	wm9713_add_controls(codec);
 	wm9713_add_widgets(codec);
-	ret = snd_soc_register_card(socdev);
+	ret = snd_soc_init_card(socdev);
 	if (ret < 0)
 		goto reset_err;
 	return 0;
@@ -1288,7 +1283,6 @@
 	snd_soc_free_ac97_codec(codec);
 	kfree(codec->private_data);
 	kfree(codec->reg_cache);
-	kfree(codec->dai);
 	kfree(codec);
 	return 0;
 }
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 8f7e338..b502741 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -17,3 +17,13 @@
 	help
 	  Say Y if you want to add support for SoC audio on TI
 	  DaVinci EVM platform.
+
+config SND_DAVINCI_SOC_SFFSDR
+	tristate "SoC Audio support for SFFSDR"
+	depends on SND_DAVINCI_SOC && MACH_DAVINCI_SFFSDR
+	select SND_DAVINCI_SOC_I2S
+	select SND_SOC_PCM3008
+	select SFFSDR_FPGA
+	help
+	  Say Y if you want to add support for SoC audio on
+	  Lyrtech SFFSDR board.
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
index ca772e5..ca8bae1 100644
--- a/sound/soc/davinci/Makefile
+++ b/sound/soc/davinci/Makefile
@@ -7,5 +7,7 @@
 
 # DAVINCI Machine Support
 snd-soc-evm-objs := davinci-evm.o
+snd-soc-sffsdr-objs := davinci-sffsdr.o
 
 obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o
+obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 9e6062c..01b948b 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -28,6 +28,8 @@
 
 #define EVM_CODEC_CLOCK 22579200
 
+#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
+		SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
 static int evm_hw_params(struct snd_pcm_substream *substream,
 			 struct snd_pcm_hw_params *params)
 {
@@ -37,14 +39,12 @@
 	int ret = 0;
 
 	/* set codec DAI configuration */
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-					 SND_SOC_DAIFMT_CBM_CFM);
+	ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT);
 	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_IB_NF);
+	ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
 	if (ret < 0)
 		return ret;
 
@@ -128,8 +128,9 @@
 };
 
 /* davinci-evm audio machine driver */
-static struct snd_soc_machine snd_soc_machine_evm = {
+static struct snd_soc_card snd_soc_card_evm = {
 	.name = "DaVinci EVM",
+	.platform = &davinci_soc_platform,
 	.dai_link = &evm_dai,
 	.num_links = 1,
 };
@@ -142,8 +143,7 @@
 
 /* evm audio subsystem */
 static struct snd_soc_device evm_snd_devdata = {
-	.machine = &snd_soc_machine_evm,
-	.platform = &davinci_soc_platform,
+	.card = &snd_soc_card_evm,
 	.codec_dev = &soc_codec_dev_aic3x,
 	.codec_data = &evm_aic3x_setup,
 };
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index abb5fed..0fee779 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -59,6 +59,7 @@
 #define DAVINCI_MCBSP_PCR_CLKXP		(1 << 1)
 #define DAVINCI_MCBSP_PCR_FSRP		(1 << 2)
 #define DAVINCI_MCBSP_PCR_FSXP		(1 << 3)
+#define DAVINCI_MCBSP_PCR_SCLKME	(1 << 7)
 #define DAVINCI_MCBSP_PCR_CLKRM		(1 << 8)
 #define DAVINCI_MCBSP_PCR_CLKXM		(1 << 9)
 #define DAVINCI_MCBSP_PCR_FSRM		(1 << 10)
@@ -110,17 +111,60 @@
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_platform *platform = socdev->card->platform;
 	u32 w;
+	int ret;
 
 	/* Start the sample generator and enable transmitter/receiver */
 	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
 	MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1);
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1);
-	else
-		MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1);
 	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
 
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		/* Stop the DMA to avoid data loss */
+		/* while the transmitter is out of reset to handle XSYNCERR */
+		if (platform->pcm_ops->trigger) {
+			ret = platform->pcm_ops->trigger(substream,
+				SNDRV_PCM_TRIGGER_STOP);
+			if (ret < 0)
+				printk(KERN_DEBUG "Playback DMA stop failed\n");
+		}
+
+		/* Enable the transmitter */
+		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+		MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1);
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+
+		/* wait for any unexpected frame sync error to occur */
+		udelay(100);
+
+		/* Disable the transmitter to clear any outstanding XSYNCERR */
+		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+		MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0);
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+
+		/* Restart the DMA */
+		if (platform->pcm_ops->trigger) {
+			ret = platform->pcm_ops->trigger(substream,
+				SNDRV_PCM_TRIGGER_START);
+			if (ret < 0)
+				printk(KERN_DEBUG "Playback DMA start failed\n");
+		}
+		/* Enable the transmitter */
+		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+		MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1);
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+
+	} else {
+
+		/* Enable the reciever */
+		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+		MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1);
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+	}
+
+
 	/* Start frame sync */
 	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
 	MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_FRST, 1);
@@ -144,7 +188,8 @@
 	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
 }
 
-static int davinci_i2s_startup(struct snd_pcm_substream *substream)
+static int davinci_i2s_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -155,61 +200,138 @@
 	return 0;
 }
 
+#define DEFAULT_BITPERSAMPLE	16
+
 static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 				   unsigned int fmt)
 {
 	struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
-	u32 w;
+	unsigned int pcr;
+	unsigned int srgr;
+	unsigned int rcr;
+	unsigned int xcr;
+	srgr = DAVINCI_MCBSP_SRGR_FSGM |
+		DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) |
+		DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
-		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG,
-					DAVINCI_MCBSP_PCR_FSXM |
-					DAVINCI_MCBSP_PCR_FSRM |
-					DAVINCI_MCBSP_PCR_CLKXM |
-					DAVINCI_MCBSP_PCR_CLKRM);
-		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG,
-					DAVINCI_MCBSP_SRGR_FSGM);
+		/* cpu is master */
+		pcr = DAVINCI_MCBSP_PCR_FSXM |
+			DAVINCI_MCBSP_PCR_FSRM |
+			DAVINCI_MCBSP_PCR_CLKXM |
+			DAVINCI_MCBSP_PCR_CLKRM;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		/* McBSP CLKR pin is the input for the Sample Rate Generator.
+		 * McBSP FSR and FSX are driven by the Sample Rate Generator. */
+		pcr = DAVINCI_MCBSP_PCR_SCLKME |
+			DAVINCI_MCBSP_PCR_FSXM |
+			DAVINCI_MCBSP_PCR_FSRM;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM:
-		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0);
+		/* codec is master */
+		pcr = 0;
 		break;
 	default:
+		printk(KERN_ERR "%s:bad master\n", __func__);
+		return -EINVAL;
+	}
+
+	rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1);
+	xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1);
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_B:
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		/* Davinci doesn't support TRUE I2S, but some codecs will have
+		 * the left and right channels contiguous. This allows
+		 * dsp_a mode to be used with an inverted normal frame clk.
+		 * If your codec is master and does not have contiguous
+		 * channels, then you will have sound on only one channel.
+		 * Try using a different mode, or codec as slave.
+		 *
+		 * The TLV320AIC33 is an example of a codec where this works.
+		 * It has a variable bit clock frequency allowing it to have
+		 * valid data on every bit clock.
+		 *
+		 * The TLV320AIC23 is an example of a codec where this does not
+		 * work. It has a fixed bit clock frequency with progressively
+		 * more empty bit clock slots between channels as the sample
+		 * rate is lowered.
+		 */
+		fmt ^= SND_SOC_DAIFMT_NB_IF;
+	case SND_SOC_DAIFMT_DSP_A:
+		rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1);
+		xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
+		break;
+	default:
+		printk(KERN_ERR "%s:bad format\n", __func__);
 		return -EINVAL;
 	}
 
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_IB_NF:
-		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG);
-		MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP |
-			       DAVINCI_MCBSP_PCR_CLKRP, 1);
-		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w);
-		break;
-	case SND_SOC_DAIFMT_NB_IF:
-		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG);
-		MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_FSXP |
-			       DAVINCI_MCBSP_PCR_FSRP, 1);
-		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w);
+	case SND_SOC_DAIFMT_NB_NF:
+		/* CLKRP Receive clock polarity,
+		 *	1 - sampled on rising edge of CLKR
+		 *	valid on rising edge
+		 * CLKXP Transmit clock polarity,
+		 *	1 - clocked on falling edge of CLKX
+		 *	valid on rising edge
+		 * FSRP  Receive frame sync pol, 0 - active high
+		 * FSXP  Transmit frame sync pol, 0 - active high
+		 */
+		pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP);
 		break;
 	case SND_SOC_DAIFMT_IB_IF:
-		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG);
-		MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP |
-			       DAVINCI_MCBSP_PCR_CLKRP |
-			       DAVINCI_MCBSP_PCR_FSXP |
-			       DAVINCI_MCBSP_PCR_FSRP, 1);
-		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w);
+		/* CLKRP Receive clock polarity,
+		 *	0 - sampled on falling edge of CLKR
+		 *	valid on falling edge
+		 * CLKXP Transmit clock polarity,
+		 *	0 - clocked on rising edge of CLKX
+		 *	valid on falling edge
+		 * FSRP  Receive frame sync pol, 1 - active low
+		 * FSXP  Transmit frame sync pol, 1 - active low
+		 */
+		pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
 		break;
-	case SND_SOC_DAIFMT_NB_NF:
+	case SND_SOC_DAIFMT_NB_IF:
+		/* CLKRP Receive clock polarity,
+		 *	1 - sampled on rising edge of CLKR
+		 *	valid on rising edge
+		 * CLKXP Transmit clock polarity,
+		 *	1 - clocked on falling edge of CLKX
+		 *	valid on rising edge
+		 * FSRP  Receive frame sync pol, 1 - active low
+		 * FSXP  Transmit frame sync pol, 1 - active low
+		 */
+		pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP |
+			DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		/* CLKRP Receive clock polarity,
+		 *	0 - sampled on falling edge of CLKR
+		 *	valid on falling edge
+		 * CLKXP Transmit clock polarity,
+		 *	0 - clocked on rising edge of CLKX
+		 *	valid on falling edge
+		 * FSRP  Receive frame sync pol, 0 - active high
+		 * FSXP  Transmit frame sync pol, 0 - active high
+		 */
 		break;
 	default:
 		return -EINVAL;
 	}
-
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr);
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
+	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);
 	return 0;
 }
 
 static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
-				 struct snd_pcm_hw_params *params)
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
@@ -219,25 +341,20 @@
 	u32 w;
 
 	/* general line settings */
-	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG,
-				DAVINCI_MCBSP_SPCR_RINTM(3) |
-				DAVINCI_MCBSP_SPCR_XINTM(3) |
-				DAVINCI_MCBSP_SPCR_FREE);
-	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG,
-				DAVINCI_MCBSP_RCR_RFRLEN1(1) |
-				DAVINCI_MCBSP_RCR_RDATDLY(1));
-	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG,
-				DAVINCI_MCBSP_XCR_XFRLEN1(1) |
-				DAVINCI_MCBSP_XCR_XDATDLY(1) |
-				DAVINCI_MCBSP_XCR_XFIG);
+	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		w |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+	} else {
+		w |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+	}
 
 	i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
-	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG);
+	w = DAVINCI_MCBSP_SRGR_FSGM;
 	MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1), 1);
-	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w);
 
 	i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS);
-	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG);
 	MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1), 1);
 	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w);
 
@@ -260,20 +377,24 @@
 		return -EINVAL;
 	}
 
-	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG);
-	MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
-		       DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1);
-	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w);
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG);
+		MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
+			       DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1);
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w);
 
-	w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG);
-	MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
-		       DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1);
-	davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w);
+	} else {
+		w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG);
+		MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
+			       DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1);
+		davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w);
 
+	}
 	return 0;
 }
 
-static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
 {
 	int ret = 0;
 
@@ -299,8 +420,8 @@
 			     struct snd_soc_dai *dai)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_machine *machine = socdev->machine;
-	struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai;
+	struct snd_soc_card *card = socdev->card;
+	struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai;
 	struct davinci_mcbsp_dev *dev;
 	struct resource *mem, *ioarea;
 	struct evm_snd_platform_data *pdata;
@@ -361,8 +482,8 @@
 			       struct snd_soc_dai *dai)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_machine *machine = socdev->machine;
-	struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai;
+	struct snd_soc_card *card = socdev->card;
+	struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai;
 	struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
 	struct resource *mem;
 
@@ -381,7 +502,6 @@
 struct snd_soc_dai davinci_i2s_dai = {
 	.name = "davinci-i2s",
 	.id = 0,
-	.type = SND_SOC_DAI_I2S,
 	.probe = davinci_i2s_probe,
 	.remove = davinci_i2s_remove,
 	.playback = {
@@ -397,13 +517,24 @@
 	.ops = {
 		.startup = davinci_i2s_startup,
 		.trigger = davinci_i2s_trigger,
-		.hw_params = davinci_i2s_hw_params,},
-	.dai_ops = {
+		.hw_params = davinci_i2s_hw_params,
 		.set_fmt = davinci_i2s_set_dai_fmt,
 	},
 };
 EXPORT_SYMBOL_GPL(davinci_i2s_dai);
 
+static int __init davinci_i2s_init(void)
+{
+	return snd_soc_register_dai(&davinci_i2s_dai);
+}
+module_init(davinci_i2s_init);
+
+static void __exit davinci_i2s_exit(void)
+{
+	snd_soc_unregister_dai(&davinci_i2s_dai);
+}
+module_exit(davinci_i2s_exit);
+
 MODULE_AUTHOR("Vladimir Barinov");
 MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 76feaa6..74abc9b 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
+#include <linux/kernel.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -24,13 +25,6 @@
 
 #include "davinci-pcm.h"
 
-#define DAVINCI_PCM_DEBUG 0
-#if DAVINCI_PCM_DEBUG
-#define DPRINTK(x...) printk(KERN_DEBUG x)
-#else
-#define DPRINTK(x...)
-#endif
-
 static struct snd_pcm_hardware davinci_pcm_hardware = {
 	.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
 		 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
@@ -78,8 +72,8 @@
 	dma_offset = prtd->period * period_size;
 	dma_pos = runtime->dma_addr + dma_offset;
 
-	DPRINTK("audio_set_dma_params_play channel = %d dma_ptr = %x "
-		"period_size=%x\n", lch, dma_pos, period_size);
+	pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d "
+		"dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size);
 
 	data_type = prtd->params->data_type;
 	count = period_size / data_type;
@@ -112,7 +106,7 @@
 	struct snd_pcm_substream *substream = data;
 	struct davinci_runtime_data *prtd = substream->runtime->private_data;
 
-	DPRINTK("lch=%d, status=0x%x\n", lch, ch_status);
+	pr_debug("davinci_pcm: lch=%d, status=0x%x\n", lch, ch_status);
 
 	if (unlikely(ch_status != DMA_COMPLETE))
 		return;
@@ -316,8 +310,8 @@
 	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
 					   &buf->addr, GFP_KERNEL);
 
-	DPRINTK("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
-		(void *) buf->area, (void *) buf->addr, size);
+	pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, "
+		"size=%d\n", (void *) buf->area, (void *) buf->addr, size);
 
 	if (!buf->area)
 		return -ENOMEM;
@@ -384,6 +378,18 @@
 };
 EXPORT_SYMBOL_GPL(davinci_soc_platform);
 
+static int __init davinci_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&davinci_soc_platform);
+}
+module_init(davinci_soc_platform_init);
+
+static void __exit davinci_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&davinci_soc_platform);
+}
+module_exit(davinci_soc_platform_exit);
+
 MODULE_AUTHOR("Vladimir Barinov");
 MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c
new file mode 100644
index 0000000..f67579d
--- /dev/null
+++ b/sound/soc/davinci/davinci-sffsdr.c
@@ -0,0 +1,157 @@
+/*
+ * ASoC driver for Lyrtech SFFSDR board.
+ *
+ * Author:	Hugo Villeneuve
+ * Copyright (C) 2008 Lyrtech inc
+ *
+ * Based on ASoC driver for TI DAVINCI EVM platform, original copyright follow:
+ * Copyright:   (C) 2007 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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/dma.h>
+#include <asm/plat-sffsdr/sffsdr-fpga.h>
+
+#include <mach/mcbsp.h>
+#include <mach/edma.h>
+
+#include "../codecs/pcm3008.h"
+#include "davinci-pcm.h"
+#include "davinci-i2s.h"
+
+static int sffsdr_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_dai *cpu_dai = rtd->dai->cpu_dai;
+	int fs;
+	int ret = 0;
+
+	/* Set cpu DAI configuration:
+	 * CLKX and CLKR are the inputs for the Sample Rate Generator.
+	 * FSX and FSR are outputs, driven by the sample Rate Generator. */
+	ret = snd_soc_dai_set_fmt(cpu_dai,
+				  SND_SOC_DAIFMT_RIGHT_J |
+				  SND_SOC_DAIFMT_CBM_CFS |
+				  SND_SOC_DAIFMT_IB_NF);
+	if (ret < 0)
+		return ret;
+
+	/* Fsref can be 32000, 44100 or 48000. */
+	fs = params_rate(params);
+
+	pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs);
+
+	return sffsdr_fpga_set_codec_fs(fs);
+}
+
+static struct snd_soc_ops sffsdr_ops = {
+	.hw_params = sffsdr_hw_params,
+};
+
+/* davinci-sffsdr digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link sffsdr_dai = {
+	.name = "PCM3008", /* Codec name */
+	.stream_name = "PCM3008 HiFi",
+	.cpu_dai = &davinci_i2s_dai,
+	.codec_dai = &pcm3008_dai,
+	.ops = &sffsdr_ops,
+};
+
+/* davinci-sffsdr audio machine driver */
+static struct snd_soc_card snd_soc_sffsdr = {
+	.name = "DaVinci SFFSDR",
+	.platform = &davinci_soc_platform,
+	.dai_link = &sffsdr_dai,
+	.num_links = 1,
+};
+
+/* sffsdr audio private data */
+static struct pcm3008_setup_data sffsdr_pcm3008_setup = {
+	.dem0_pin = GPIO(45),
+	.dem1_pin = GPIO(46),
+	.pdad_pin = GPIO(47),
+	.pdda_pin = GPIO(38),
+};
+
+/* sffsdr audio subsystem */
+static struct snd_soc_device sffsdr_snd_devdata = {
+	.card = &snd_soc_sffsdr,
+	.codec_dev = &soc_codec_dev_pcm3008,
+	.codec_data = &sffsdr_pcm3008_setup,
+};
+
+static struct resource sffsdr_snd_resources[] = {
+	{
+		.start = DAVINCI_MCBSP_BASE,
+		.end = DAVINCI_MCBSP_BASE + SZ_8K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct evm_snd_platform_data sffsdr_snd_data = {
+	.tx_dma_ch	= DAVINCI_DMA_MCBSP_TX,
+	.rx_dma_ch	= DAVINCI_DMA_MCBSP_RX,
+};
+
+static struct platform_device *sffsdr_snd_device;
+
+static int __init sffsdr_init(void)
+{
+	int ret;
+
+	sffsdr_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!sffsdr_snd_device) {
+		printk(KERN_ERR "platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata);
+	sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev;
+	sffsdr_snd_device->dev.platform_data = &sffsdr_snd_data;
+
+	ret = platform_device_add_resources(sffsdr_snd_device,
+					    sffsdr_snd_resources,
+					    ARRAY_SIZE(sffsdr_snd_resources));
+	if (ret) {
+		printk(KERN_ERR "platform device add ressources failed\n");
+		goto error;
+	}
+
+	ret = platform_device_add(sffsdr_snd_device);
+	if (ret)
+		goto error;
+
+	return ret;
+
+error:
+	platform_device_put(sffsdr_snd_device);
+	return ret;
+}
+
+static void __exit sffsdr_exit(void)
+{
+	platform_device_unregister(sffsdr_snd_device);
+}
+
+module_init(sffsdr_init);
+module_exit(sffsdr_exit);
+
+MODULE_AUTHOR("Hugo Villeneuve");
+MODULE_DESCRIPTION("Lyrtech SFFSDR ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 8d73edc..95c12b2 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -20,7 +20,7 @@
 
 config SND_SOC_MPC5200_I2S
 	tristate "Freescale MPC5200 PSC in I2S mode driver"
-	depends on SND_SOC && PPC_MPC52xx && PPC_BESTCOMM
+	depends on PPC_MPC52xx && PPC_BESTCOMM
 	select SND_SOC_OF_SIMPLE
 	select PPC_BESTCOMM_GEN_BD
 	help
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index d2d3da9..64993ed 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -284,7 +284,7 @@
  * fsl_dma_new: initialize this PCM driver.
  *
  * This function is called when the codec driver calls snd_soc_new_pcms(),
- * once for each .dai_link in the machine driver's snd_soc_machine
+ * once for each .dai_link in the machine driver's snd_soc_card
  * structure.
  */
 static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
@@ -853,6 +853,18 @@
 }
 EXPORT_SYMBOL_GPL(fsl_dma_configure);
 
+static int __init fsl_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&fsl_soc_platform);
+}
+module_init(fsl_soc_platform_init);
+
+static void __exit fsl_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&fsl_soc_platform);
+}
+module_exit(fsl_soc_platform_exit);
+
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 157a789..c6d6eb7 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -266,7 +266,8 @@
  * If this is the first stream open, then grab the IRQ and program most of
  * the SSI registers.
  */
-static int fsl_ssi_startup(struct snd_pcm_substream *substream)
+static int fsl_ssi_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
@@ -411,7 +412,8 @@
  * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the
  * clock master.
  */
-static int fsl_ssi_prepare(struct snd_pcm_substream *substream)
+static int fsl_ssi_prepare(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -441,7 +443,8 @@
  * The DMA channel is in external master start and pause mode, which
  * means the SSI completely controls the flow of data.
  */
-static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd)
+static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
+			   struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
@@ -490,7 +493,8 @@
  *
  * Shutdown the SSI if there are no other substreams open.
  */
-static void fsl_ssi_shutdown(struct snd_pcm_substream *substream)
+static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
@@ -578,8 +582,6 @@
 		.prepare = fsl_ssi_prepare,
 		.shutdown = fsl_ssi_shutdown,
 		.trigger = fsl_ssi_trigger,
-	},
-	.dai_ops = {
 		.set_sysclk = fsl_ssi_set_sysclk,
 		.set_fmt = fsl_ssi_set_fmt,
 	},
@@ -671,6 +673,14 @@
 	fsl_ssi_dai->private_data = ssi_private;
 	fsl_ssi_dai->name = ssi_private->name;
 	fsl_ssi_dai->id = ssi_info->id;
+	fsl_ssi_dai->dev = ssi_info->dev;
+
+	ret = snd_soc_register_dai(fsl_ssi_dai);
+	if (ret != 0) {
+		dev_err(ssi_info->dev, "failed to register DAI: %d\n", ret);
+		kfree(fsl_ssi_dai);
+		return NULL;
+	}
 
 	return fsl_ssi_dai;
 }
@@ -688,6 +698,8 @@
 
 	device_remove_file(ssi_private->dev, &ssi_private->dev_attr);
 
+	snd_soc_unregister_dai(&ssi_private->cpu_dai);
+
 	kfree(ssi_private);
 }
 EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 94a02ea..9eb1ce1 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -187,7 +187,8 @@
  * 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)
+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;
@@ -220,7 +221,8 @@
 }
 
 static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
-				 struct snd_pcm_hw_params *params)
+				 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;
@@ -256,7 +258,8 @@
 	return 0;
 }
 
-static int psc_i2s_hw_free(struct snd_pcm_substream *substream)
+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;
@@ -268,7 +271,8 @@
  * 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)
+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;
@@ -383,7 +387,8 @@
  *
  * Shutdown the PSC if there are no other substreams open.
  */
-static void psc_i2s_shutdown(struct snd_pcm_substream *substream)
+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;
@@ -464,7 +469,6 @@
  * psc_i2s_dai_template: template CPU Digital Audio Interface
  */
 static struct snd_soc_dai psc_i2s_dai_template = {
-	.type = SND_SOC_DAI_I2S,
 	.playback = {
 		.channels_min = 2,
 		.channels_max = 2,
@@ -483,8 +487,6 @@
 		.hw_free = psc_i2s_hw_free,
 		.shutdown = psc_i2s_shutdown,
 		.trigger = psc_i2s_trigger,
-	},
-	.dai_ops = {
 		.set_sysclk = psc_i2s_set_sysclk,
 		.set_fmt = psc_i2s_set_fmt,
 	},
@@ -826,6 +828,8 @@
 	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);
@@ -839,6 +843,8 @@
 
 	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);
 
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 94f89de..bcec3f6 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -29,7 +29,7 @@
 struct mpc8610_hpcd_data {
 	struct snd_soc_device sound_devdata;
 	struct snd_soc_dai_link dai;
-	struct snd_soc_machine machine;
+	struct snd_soc_card machine;
 	unsigned int dai_format;
 	unsigned int codec_clk_direction;
 	unsigned int cpu_clk_direction;
@@ -185,7 +185,7 @@
 /**
  * mpc8610_hpcd_machine: ASoC machine data
  */
-static struct snd_soc_machine mpc8610_hpcd_machine = {
+static struct snd_soc_card mpc8610_hpcd_machine = {
 	.probe = mpc8610_hpcd_machine_probe,
 	.remove = mpc8610_hpcd_machine_remove,
 	.name = "MPC8610 HPCD",
@@ -465,9 +465,9 @@
 		goto error;
 	}
 
-	machine_data->sound_devdata.machine = &mpc8610_hpcd_machine;
+	machine_data->sound_devdata.card = &mpc8610_hpcd_machine;
 	machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270;
-	machine_data->sound_devdata.platform = &fsl_soc_platform;
+	machine_data->machine.platform = &fsl_soc_platform;
 
 	sound_device->dev.platform_data = machine_data;
 
diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c
index 0382fda..8bc5cd9 100644
--- a/sound/soc/fsl/soc-of-simple.c
+++ b/sound/soc/fsl/soc-of-simple.c
@@ -31,7 +31,7 @@
 	int id;
 	struct list_head list;
 	struct snd_soc_device device;
-	struct snd_soc_machine machine;
+	struct snd_soc_card card;
 	struct snd_soc_dai_link dai_link;
 	struct platform_device *pdev;
 	struct device_node *platform_node;
@@ -58,9 +58,9 @@
 	/* Initialize the structure and add it to the global list */
 	of_soc->codec_node = codec_node;
 	of_soc->id = of_snd_soc_next_index++;
-	of_soc->machine.dai_link = &of_soc->dai_link;
-	of_soc->machine.num_links = 1;
-	of_soc->device.machine = &of_soc->machine;
+	of_soc->card.dai_link = &of_soc->dai_link;
+	of_soc->card.num_links = 1;
+	of_soc->device.card = &of_soc->card;
 	of_soc->dai_link.ops = &of_snd_soc_ops;
 	list_add(&of_soc->list, &of_snd_soc_device_list);
 
@@ -158,8 +158,8 @@
 
 	of_soc->platform_node = node;
 	of_soc->dai_link.cpu_dai = cpu_dai;
-	of_soc->device.platform = platform;
-	of_soc->machine.name = of_soc->dai_link.cpu_dai->name;
+	of_soc->card.platform = platform;
+	of_soc->card.name = of_soc->dai_link.cpu_dai->name;
 
 	/* Now try to register the SoC device */
 	of_snd_soc_register_device(of_soc);
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 8b7766b..a7b1d77 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -1,6 +1,6 @@
 config SND_OMAP_SOC
 	tristate "SoC Audio for the Texas Instruments OMAP chips"
-	depends on ARCH_OMAP && SND_SOC
+	depends on ARCH_OMAP
 
 config SND_OMAP_SOC_MCBSP
 	tristate
@@ -21,3 +21,36 @@
 	select SND_SOC_TLV320AIC23
 	help
 	  Say Y if you want to add support for SoC audio on osk5912.
+
+config SND_OMAP_SOC_OVERO
+	tristate "SoC Audio support for Gumstix Overo"
+	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OVERO
+	select SND_OMAP_SOC_MCBSP
+	select SND_SOC_TWL4030
+	help
+	  Say Y if you want to add support for SoC audio on the Gumstix Overo.
+
+config SND_OMAP_SOC_OMAP2EVM
+	tristate "SoC Audio support for OMAP2EVM board"
+	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP2EVM
+	select SND_OMAP_SOC_MCBSP
+	select SND_SOC_TWL4030
+	help
+	  Say Y if you want to add support for SoC audio on the omap2evm board.
+
+config SND_OMAP_SOC_SDP3430
+	tristate "SoC Audio support for Texas Instruments SDP3430"
+	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP
+	select SND_OMAP_SOC_MCBSP
+	select SND_SOC_TWL4030
+	help
+	  Say Y if you want to add support for SoC audio on Texas Instruments
+	  SDP3430.
+
+config SND_OMAP_SOC_OMAP3_PANDORA
+	tristate "SoC Audio support for OMAP3 Pandora"
+	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA
+	select SND_OMAP_SOC_MCBSP
+	select SND_SOC_TWL4030
+	help
+	  Say Y if you want to add support for SoC audio on the OMAP3 Pandora.
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index e09d1f2..76fedd9 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -8,6 +8,14 @@
 # OMAP Machine Support
 snd-soc-n810-objs := n810.o
 snd-soc-osk5912-objs := osk5912.o
+snd-soc-overo-objs := overo.o
+snd-soc-omap2evm-objs := omap2evm.o
+snd-soc-sdp3430-objs := sdp3430.o
+snd-soc-omap3pandora-objs := omap3pandora.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
 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_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
+obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index fae3ad3..25593fe 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -70,9 +70,13 @@
 
 static int n810_startup(struct snd_pcm_substream *substream)
 {
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_codec *codec = rtd->socdev->codec;
 
+	snd_pcm_hw_constraint_minmax(runtime,
+				     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
+
 	n810_ext_control(codec);
 	return clk_enable(sys_clkout2);
 }
@@ -282,8 +286,9 @@
 };
 
 /* Audio machine driver */
-static struct snd_soc_machine snd_soc_machine_n810 = {
+static struct snd_soc_card snd_soc_n810 = {
 	.name = "N810",
+	.platform = &omap_soc_platform,
 	.dai_link = &n810_dai,
 	.num_links = 1,
 };
@@ -298,8 +303,7 @@
 
 /* Audio subsystem */
 static struct snd_soc_device n810_snd_devdata = {
-	.machine = &snd_soc_machine_n810,
-	.platform = &omap_soc_platform,
+	.card = &snd_soc_n810,
 	.codec_dev = &soc_codec_dev_aic3x,
 	.codec_data = &n810_aic33_setup,
 };
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 8485a8a..ec5e18a 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -36,9 +36,7 @@
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
 
-#define OMAP_MCBSP_RATES	(SNDRV_PCM_RATE_44100 | \
-				 SNDRV_PCM_RATE_48000 | \
-				 SNDRV_PCM_RATE_KNOT)
+#define OMAP_MCBSP_RATES	(SNDRV_PCM_RATE_8000_96000)
 
 struct omap_mcbsp_data {
 	unsigned int			bus_id;
@@ -140,7 +138,8 @@
 static const unsigned long omap34xx_mcbsp_port[][2] = {};
 #endif
 
-static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
+static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -153,7 +152,8 @@
 	return err;
 }
 
-static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream)
+static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -165,7 +165,8 @@
 	}
 }
 
-static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd)
+static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+				  struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -194,14 +195,15 @@
 }
 
 static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
-				    struct snd_pcm_hw_params *params)
+				    struct snd_pcm_hw_params *params,
+				    struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 	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;
+	int wlen, channels;
 	unsigned long port;
 
 	if (cpu_class_is_omap1()) {
@@ -230,12 +232,17 @@
 		return 0;
 	}
 
-	switch (params_channels(params)) {
+	channels = params_channels(params);
+	switch (channels) {
 	case 2:
-		/* Set 1 word per (McBPSP) frame and use dual-phase frames */
-		regs->rcr2	|= RFRLEN2(1 - 1) | RPHASE;
+		/* Use dual-phase frames */
+		regs->rcr2	|= RPHASE;
+		regs->xcr2	|= XPHASE;
+	case 1:
+		/* Set 1 word per (McBSP) frame */
+		regs->rcr2	|= RFRLEN2(1 - 1);
 		regs->rcr1	|= RFRLEN1(1 - 1);
-		regs->xcr2	|= XFRLEN2(1 - 1) | XPHASE;
+		regs->xcr2	|= XFRLEN2(1 - 1);
 		regs->xcr1	|= XFRLEN1(1 - 1);
 		break;
 	default:
@@ -263,9 +270,9 @@
 		regs->srgr2	|= FPER(wlen * 2 - 1);
 		regs->srgr1	|= FWID(wlen - 1);
 		break;
-	case SND_SOC_DAIFMT_DSP_A:
-		regs->srgr2	|= FPER(wlen * 2 - 1);
-		regs->srgr1	|= FWID(wlen * 2 - 2);
+	case SND_SOC_DAIFMT_DSP_B:
+		regs->srgr2	|= FPER(wlen * channels - 1);
+		regs->srgr1	|= FWID(wlen * channels - 2);
 		break;
 	}
 
@@ -302,7 +309,7 @@
 		regs->rcr2	|= RDATDLY(1);
 		regs->xcr2	|= XDATDLY(1);
 		break;
-	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
 		/* 0-bit data delay */
 		regs->rcr2      |= RDATDLY(0);
 		regs->xcr2      |= XDATDLY(0);
@@ -452,17 +459,16 @@
 
 #define OMAP_MCBSP_DAI_BUILDER(link_id)				\
 {								\
-	.name = "omap-mcbsp-dai-(link_id)",			\
+	.name = "omap-mcbsp-dai-"#link_id,			\
 	.id = (link_id),					\
-	.type = SND_SOC_DAI_I2S,				\
 	.playback = {						\
-		.channels_min = 2,				\
+		.channels_min = 1,				\
 		.channels_max = 2,				\
 		.rates = OMAP_MCBSP_RATES,			\
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,		\
 	},							\
 	.capture = {						\
-		.channels_min = 2,				\
+		.channels_min = 1,				\
 		.channels_max = 2,				\
 		.rates = OMAP_MCBSP_RATES,			\
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,		\
@@ -472,8 +478,6 @@
 		.shutdown = omap_mcbsp_dai_shutdown,		\
 		.trigger = omap_mcbsp_dai_trigger,		\
 		.hw_params = omap_mcbsp_dai_hw_params,		\
-	},							\
-	.dai_ops = {						\
 		.set_fmt = omap_mcbsp_dai_set_dai_fmt,		\
 		.set_clkdiv = omap_mcbsp_dai_set_clkdiv,	\
 		.set_sysclk = omap_mcbsp_dai_set_dai_sysclk,	\
@@ -495,6 +499,19 @@
 
 EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
 
+static int __init snd_omap_mcbsp_init(void)
+{
+	return snd_soc_register_dais(omap_mcbsp_dai,
+				     ARRAY_SIZE(omap_mcbsp_dai));
+}
+module_init(snd_omap_mcbsp_init);
+
+static void __exit snd_omap_mcbsp_exit(void)
+{
+	snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai));
+}
+module_exit(snd_omap_mcbsp_exit);
+
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
 MODULE_DESCRIPTION("OMAP I2S SoC Interface");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index acd68ef..b0362df 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -97,7 +97,7 @@
 	prtd->dma_data = dma_data;
 	err = omap_request_dma(dma_data->dma_req, dma_data->name,
 			       omap_pcm_dma_irq, substream, &prtd->dma_ch);
-	if (!err & !cpu_is_omap1510()) {
+	if (!err && !cpu_is_omap1510()) {
 		/*
 		 * Link channel with itself so DMA doesn't need any
 		 * reprogramming while looping the buffer
@@ -354,6 +354,18 @@
 };
 EXPORT_SYMBOL_GPL(omap_soc_platform);
 
+static int __init omap_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&omap_soc_platform);
+}
+module_init(omap_soc_platform_init);
+
+static void __exit omap_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&omap_soc_platform);
+}
+module_exit(omap_soc_platform_exit);
+
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
 MODULE_DESCRIPTION("OMAP PCM DMA module");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c
new file mode 100644
index 0000000..0c2322d
--- /dev/null
+++ b/sound/soc/omap/omap2evm.c
@@ -0,0 +1,151 @@
+/*
+ * omap2evm.c  --  SoC audio machine driver for omap2evm board
+ *
+ * Author: Arun KS <arunks@mistralsolutions.com>
+ *
+ * Based on sound/soc/omap/overo.c by Steve Sakoman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <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 omap2evm_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_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 omap2evm_ops = {
+	.hw_params = omap2evm_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link omap2evm_dai = {
+	.name = "TWL4030",
+	.stream_name = "TWL4030",
+	.cpu_dai = &omap_mcbsp_dai[0],
+	.codec_dai = &twl4030_dai,
+	.ops = &omap2evm_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_omap2evm = {
+	.name = "omap2evm",
+	.platform = &omap_soc_platform,
+	.dai_link = &omap2evm_dai,
+	.num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device omap2evm_snd_devdata = {
+	.card = &snd_soc_omap2evm,
+	.codec_dev = &soc_codec_dev_twl4030,
+};
+
+static struct platform_device *omap2evm_snd_device;
+
+static int __init omap2evm_soc_init(void)
+{
+	int ret;
+
+	if (!machine_is_omap2evm()) {
+		pr_debug("Not omap2evm!\n");
+		return -ENODEV;
+	}
+	printk(KERN_INFO "omap2evm SoC init\n");
+
+	omap2evm_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!omap2evm_snd_device) {
+		printk(KERN_ERR "Platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(omap2evm_snd_device, &omap2evm_snd_devdata);
+	omap2evm_snd_devdata.dev = &omap2evm_snd_device->dev;
+	*(unsigned int *)omap2evm_dai.cpu_dai->private_data = 1; /* McBSP2 */
+
+	ret = platform_device_add(omap2evm_snd_device);
+	if (ret)
+		goto err1;
+
+	return 0;
+
+err1:
+	printk(KERN_ERR "Unable to add platform device\n");
+	platform_device_put(omap2evm_snd_device);
+
+	return ret;
+}
+module_init(omap2evm_soc_init);
+
+static void __exit omap2evm_soc_exit(void)
+{
+	platform_device_unregister(omap2evm_snd_device);
+}
+module_exit(omap2evm_soc_exit);
+
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_DESCRIPTION("ALSA SoC omap2evm");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
new file mode 100644
index 0000000..fd24a4a
--- /dev/null
+++ b/sound/soc/omap/omap3beagle.c
@@ -0,0 +1,149 @@
+/*
+ * omap3beagle.c  --  SoC audio for OMAP3 Beagle
+ *
+ * Author: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <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 omap3beagle_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 omap3beagle_ops = {
+	.hw_params = omap3beagle_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link omap3beagle_dai = {
+	.name = "TWL4030",
+	.stream_name = "TWL4030",
+	.cpu_dai = &omap_mcbsp_dai[0],
+	.codec_dai = &twl4030_dai,
+	.ops = &omap3beagle_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_omap3beagle = {
+	.name = "omap3beagle",
+	.platform = &omap_soc_platform,
+	.dai_link = &omap3beagle_dai,
+	.num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device omap3beagle_snd_devdata = {
+	.card = &snd_soc_omap3beagle,
+	.codec_dev = &soc_codec_dev_twl4030,
+};
+
+static struct platform_device *omap3beagle_snd_device;
+
+static int __init omap3beagle_soc_init(void)
+{
+	int ret;
+
+	if (!machine_is_omap3_beagle()) {
+		pr_debug("Not OMAP3 Beagle!\n");
+		return -ENODEV;
+	}
+	pr_info("OMAP3 Beagle SoC init\n");
+
+	omap3beagle_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!omap3beagle_snd_device) {
+		printk(KERN_ERR "Platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(omap3beagle_snd_device, &omap3beagle_snd_devdata);
+	omap3beagle_snd_devdata.dev = &omap3beagle_snd_device->dev;
+	*(unsigned int *)omap3beagle_dai.cpu_dai->private_data = 1; /* McBSP2 */
+
+	ret = platform_device_add(omap3beagle_snd_device);
+	if (ret)
+		goto err1;
+
+	return 0;
+
+err1:
+	printk(KERN_ERR "Unable to add platform device\n");
+	platform_device_put(omap3beagle_snd_device);
+
+	return ret;
+}
+
+static void __exit omap3beagle_soc_exit(void)
+{
+	platform_device_unregister(omap3beagle_snd_device);
+}
+
+module_init(omap3beagle_soc_init);
+module_exit(omap3beagle_soc_exit);
+
+MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>");
+MODULE_DESCRIPTION("ALSA SoC OMAP3 Beagle");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
new file mode 100644
index 0000000..bd91594
--- /dev/null
+++ b/sound/soc/omap/omap3pandora.c
@@ -0,0 +1,311 @@
+/*
+ * omap3pandora.c  --  SoC audio for Pandora Handheld Console
+ *
+ * Author: Gražvydas Ignotas <notasas@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/twl4030.h"
+
+#define OMAP3_PANDORA_DAC_POWER_GPIO	118
+#define OMAP3_PANDORA_AMP_POWER_GPIO	14
+
+#define PREFIX "ASoC omap3pandora: "
+
+static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai,
+	struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+	int ret;
+
+	/* Set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+	if (ret < 0) {
+		pr_err(PREFIX "can't set codec DAI configuration\n");
+		return ret;
+	}
+
+	/* Set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+	if (ret < 0) {
+		pr_err(PREFIX "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) {
+		pr_err(PREFIX "can't set codec system clock\n");
+		return ret;
+	}
+
+	/* Set McBSP clock to external */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, 0,
+					    SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		pr_err(PREFIX "can't set cpu system clock\n");
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8);
+	if (ret < 0) {
+		pr_err(PREFIX "can't set SRG clock divider\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int omap3pandora_out_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;
+
+	return omap3pandora_cmn_hw_params(codec_dai, cpu_dai,
+					  SND_SOC_DAIFMT_I2S |
+					  SND_SOC_DAIFMT_IB_NF |
+					  SND_SOC_DAIFMT_CBS_CFS);
+}
+
+static int omap3pandora_in_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;
+
+	return omap3pandora_cmn_hw_params(codec_dai, cpu_dai,
+					  SND_SOC_DAIFMT_I2S |
+					  SND_SOC_DAIFMT_NB_NF |
+					  SND_SOC_DAIFMT_CBS_CFS);
+}
+
+static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
+		gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1);
+	} else {
+		gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
+		mdelay(1);
+		gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
+	}
+
+	return 0;
+}
+
+/*
+ * Audio paths on Pandora board:
+ *
+ *  |O| ---> PCM DAC +-> AMP -> Headphone Jack
+ *  |M|         A    +--------> Line Out
+ *  |A| <~~clk~~+
+ *  |P| <--- TWL4030 <--------- Line In and MICs
+ */
+static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("PCM DAC", "Playback", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
+			   0, 0, NULL, 0, omap3pandora_hp_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_LINE("Line Out", NULL),
+};
+
+static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+	SND_SOC_DAPM_MIC("Mic (external)", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route omap3pandora_out_map[] = {
+	{"Headphone Amplifier", NULL, "PCM DAC"},
+	{"Line Out", NULL, "PCM DAC"},
+	{"Headphone Jack", NULL, "Headphone Amplifier"},
+};
+
+static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
+	{"INL", NULL, "Line In"},
+	{"INR", NULL, "Line In"},
+	{"INL", NULL, "Mic (Internal)"},
+	{"INR", NULL, "Mic (external)"},
+};
+
+static int omap3pandora_out_init(struct snd_soc_codec *codec)
+{
+	int ret;
+
+	ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets,
+				ARRAY_SIZE(omap3pandora_out_dapm_widgets));
+	if (ret < 0)
+		return ret;
+
+	snd_soc_dapm_add_routes(codec, omap3pandora_out_map,
+		ARRAY_SIZE(omap3pandora_out_map));
+
+	return snd_soc_dapm_sync(codec);
+}
+
+static int omap3pandora_in_init(struct snd_soc_codec *codec)
+{
+	int ret;
+
+	ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets,
+				ARRAY_SIZE(omap3pandora_in_dapm_widgets));
+	if (ret < 0)
+		return ret;
+
+	snd_soc_dapm_add_routes(codec, omap3pandora_in_map,
+		ARRAY_SIZE(omap3pandora_in_map));
+
+	return snd_soc_dapm_sync(codec);
+}
+
+static struct snd_soc_ops omap3pandora_out_ops = {
+	.hw_params = omap3pandora_out_hw_params,
+};
+
+static struct snd_soc_ops omap3pandora_in_ops = {
+	.hw_params = omap3pandora_in_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link omap3pandora_dai[] = {
+	{
+		.name = "PCM1773",
+		.stream_name = "HiFi Out",
+		.cpu_dai = &omap_mcbsp_dai[0],
+		.codec_dai = &twl4030_dai,
+		.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,
+		.ops = &omap3pandora_in_ops,
+		.init = omap3pandora_in_init,
+	}
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_omap3pandora = {
+	.name = "omap3pandora",
+	.platform = &omap_soc_platform,
+	.dai_link = omap3pandora_dai,
+	.num_links = ARRAY_SIZE(omap3pandora_dai),
+};
+
+/* Audio subsystem */
+static struct snd_soc_device omap3pandora_snd_data = {
+	.card = &snd_soc_card_omap3pandora,
+	.codec_dev = &soc_codec_dev_twl4030,
+};
+
+static struct platform_device *omap3pandora_snd_device;
+
+static int __init omap3pandora_soc_init(void)
+{
+	int ret;
+
+	if (!machine_is_omap3_pandora()) {
+		pr_debug(PREFIX "Not OMAP3 Pandora\n");
+		return -ENODEV;
+	}
+	pr_info("OMAP3 Pandora SoC init\n");
+
+	ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power");
+	if (ret) {
+		pr_err(PREFIX "Failed to get DAC power GPIO\n");
+		return ret;
+	}
+
+	ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
+	if (ret) {
+		pr_err(PREFIX "Failed to set DAC power GPIO direction\n");
+		goto fail0;
+	}
+
+	ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power");
+	if (ret) {
+		pr_err(PREFIX "Failed to get amp power GPIO\n");
+		goto fail0;
+	}
+
+	ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
+	if (ret) {
+		pr_err(PREFIX "Failed to set amp power GPIO direction\n");
+		goto fail1;
+	}
+
+	omap3pandora_snd_device = platform_device_alloc("soc-audio", -1);
+	if (omap3pandora_snd_device == NULL) {
+		pr_err(PREFIX "Platform device allocation failed\n");
+		ret = -ENOMEM;
+		goto fail1;
+	}
+
+	platform_set_drvdata(omap3pandora_snd_device, &omap3pandora_snd_data);
+	omap3pandora_snd_data.dev = &omap3pandora_snd_device->dev;
+	*(unsigned int *)omap_mcbsp_dai[0].private_data = 1; /* McBSP2 */
+	*(unsigned int *)omap_mcbsp_dai[1].private_data = 3; /* McBSP4 */
+
+	ret = platform_device_add(omap3pandora_snd_device);
+	if (ret) {
+		pr_err(PREFIX "Unable to add platform device\n");
+		goto fail2;
+	}
+
+	return 0;
+
+fail2:
+	platform_device_put(omap3pandora_snd_device);
+fail1:
+	gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
+fail0:
+	gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
+	return ret;
+}
+module_init(omap3pandora_soc_init);
+
+static void __exit omap3pandora_soc_exit(void)
+{
+	platform_device_unregister(omap3pandora_snd_device);
+	gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
+	gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
+}
+module_exit(omap3pandora_soc_exit);
+
+MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index 0fe7337..cd41a94 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -61,7 +61,7 @@
 
 	/* Set codec DAI configuration */
 	err = snd_soc_dai_set_fmt(codec_dai,
-				  SND_SOC_DAIFMT_DSP_A |
+				  SND_SOC_DAIFMT_DSP_B |
 				  SND_SOC_DAIFMT_NB_IF |
 				  SND_SOC_DAIFMT_CBM_CFM);
 	if (err < 0) {
@@ -71,7 +71,7 @@
 
 	/* Set cpu DAI configuration */
 	err = snd_soc_dai_set_fmt(cpu_dai,
-				  SND_SOC_DAIFMT_DSP_A |
+				  SND_SOC_DAIFMT_DSP_B |
 				  SND_SOC_DAIFMT_NB_IF |
 				  SND_SOC_DAIFMT_CBM_CFM);
 	if (err < 0) {
@@ -143,16 +143,16 @@
 };
 
 /* Audio machine driver */
-static struct snd_soc_machine snd_soc_machine_osk = {
+static struct snd_soc_card snd_soc_card_osk = {
 	.name = "OSK5912",
+	.platform = &omap_soc_platform,
 	.dai_link = &osk_dai,
 	.num_links = 1,
 };
 
 /* Audio subsystem */
 static struct snd_soc_device osk_snd_devdata = {
-	.machine = &snd_soc_machine_osk,
-	.platform = &omap_soc_platform,
+	.card = &snd_soc_card_osk,
 	.codec_dev = &soc_codec_dev_tlv320aic23,
 };
 
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
new file mode 100644
index 0000000..a72dc4e
--- /dev/null
+++ b/sound/soc/omap/overo.c
@@ -0,0 +1,148 @@
+/*
+ * overo.c  --  SoC audio for Gumstix Overo
+ *
+ * Author: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <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 overo_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 overo_ops = {
+	.hw_params = overo_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link overo_dai = {
+	.name = "TWL4030",
+	.stream_name = "TWL4030",
+	.cpu_dai = &omap_mcbsp_dai[0],
+	.codec_dai = &twl4030_dai,
+	.ops = &overo_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_card_overo = {
+	.name = "overo",
+	.platform = &omap_soc_platform,
+	.dai_link = &overo_dai,
+	.num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device overo_snd_devdata = {
+	.card = &snd_soc_card_overo,
+	.codec_dev = &soc_codec_dev_twl4030,
+};
+
+static struct platform_device *overo_snd_device;
+
+static int __init overo_soc_init(void)
+{
+	int ret;
+
+	if (!machine_is_overo()) {
+		pr_debug("Not Overo!\n");
+		return -ENODEV;
+	}
+	printk(KERN_INFO "overo SoC init\n");
+
+	overo_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!overo_snd_device) {
+		printk(KERN_ERR "Platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(overo_snd_device, &overo_snd_devdata);
+	overo_snd_devdata.dev = &overo_snd_device->dev;
+	*(unsigned int *)overo_dai.cpu_dai->private_data = 1; /* McBSP2 */
+
+	ret = platform_device_add(overo_snd_device);
+	if (ret)
+		goto err1;
+
+	return 0;
+
+err1:
+	printk(KERN_ERR "Unable to add platform device\n");
+	platform_device_put(overo_snd_device);
+
+	return ret;
+}
+module_init(overo_soc_init);
+
+static void __exit overo_soc_exit(void)
+{
+	platform_device_unregister(overo_snd_device);
+}
+module_exit(overo_soc_exit);
+
+MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>");
+MODULE_DESCRIPTION("ALSA SoC overo");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
new file mode 100644
index 0000000..ad97836
--- /dev/null
+++ b/sound/soc/omap/sdp3430.c
@@ -0,0 +1,152 @@
+/*
+ * sdp3430.c  --  SoC audio for TI OMAP3430 SDP
+ *
+ * Author: Misael Lopez Cruz <x0052729@ti.com>
+ *
+ * Based on:
+ * Author: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <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 sdp3430_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 sdp3430_ops = {
+	.hw_params = sdp3430_hw_params,
+};
+
+/* 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,
+	.ops = &sdp3430_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_machine snd_soc_machine_sdp3430 = {
+	.name = "SDP3430",
+	.platform = &omap_soc_platform,
+	.dai_link = &sdp3430_dai,
+	.num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device sdp3430_snd_devdata = {
+	.machine = &snd_soc_machine_sdp3430,
+	.codec_dev = &soc_codec_dev_twl4030,
+};
+
+static struct platform_device *sdp3430_snd_device;
+
+static int __init sdp3430_soc_init(void)
+{
+	int ret;
+
+	if (!machine_is_omap_3430sdp()) {
+		pr_debug("Not SDP3430!\n");
+		return -ENODEV;
+	}
+	printk(KERN_INFO "SDP3430 SoC init\n");
+
+	sdp3430_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!sdp3430_snd_device) {
+		printk(KERN_ERR "Platform device allocation failed\n");
+		return -ENOMEM;
+	}
+
+	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 */
+
+	ret = platform_device_add(sdp3430_snd_device);
+	if (ret)
+		goto err1;
+
+	return 0;
+
+err1:
+	printk(KERN_ERR "Unable to add platform device\n");
+	platform_device_put(sdp3430_snd_device);
+
+	return ret;
+}
+module_init(sdp3430_soc_init);
+
+static void __exit sdp3430_soc_exit(void)
+{
+	platform_device_unregister(sdp3430_snd_device);
+}
+module_exit(sdp3430_soc_exit);
+
+MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
+MODULE_DESCRIPTION("ALSA SoC SDP3430");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index f8c1cdd..f82e106 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -21,6 +21,9 @@
 config SND_PXA2XX_SOC_I2S
 	tristate
 
+config SND_PXA_SOC_SSP
+	tristate
+
 config SND_PXA2XX_SOC_CORGI
 	tristate "SoC Audio support for Sharp Zaurus SL-C7x0"
 	depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx
@@ -75,3 +78,22 @@
 	help
 	  Say Y if you want to add support for SoC audio on
 	  CompuLab EM-x270.
+
+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)
+	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.
+
+config SND_SOC_ZYLONITE
+	tristate "SoC Audio support for Marvell Zylonite"
+	depends on SND_PXA2XX_SOC && MACH_ZYLONITE
+	select SND_PXA2XX_SOC_AC97
+	select SND_PXA_SOC_SSP
+	select SND_SOC_WM9713
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  Marvell Zylonite reference platform.
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index 5bc8edf..08a9f27 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -2,10 +2,12 @@
 snd-soc-pxa2xx-objs := pxa2xx-pcm.o
 snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
 snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
+snd-soc-pxa-ssp-objs := pxa-ssp.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
 obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
 obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
+obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o
 
 # PXA Machine Support
 snd-soc-corgi-objs := corgi.o
@@ -14,6 +16,8 @@
 snd-soc-e800-objs := e800_wm9712.o
 snd-soc-spitz-objs := spitz.o
 snd-soc-em-x270-objs := em-x270.o
+snd-soc-palm27x-objs := palm27x.o
+snd-soc-zylonite-objs := zylonite.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
 obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
@@ -21,3 +25,5 @@
 obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
 obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
 obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
+obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
+obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 2718eaf..1ba25a5 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -108,15 +108,11 @@
 }
 
 /* we need to unmute the HP at shutdown as the mute burns power on corgi */
-static int corgi_shutdown(struct snd_pcm_substream *substream)
+static void corgi_shutdown(struct snd_pcm_substream *substream)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->socdev->codec;
-
 	/* set = unmute headphone */
 	gpio_set_value(CORGI_GPIO_MUTE_L, 1);
 	gpio_set_value(CORGI_GPIO_MUTE_R, 1);
-	return 0;
 }
 
 static int corgi_hw_params(struct snd_pcm_substream *substream,
@@ -314,8 +310,9 @@
 };
 
 /* corgi audio machine driver */
-static struct snd_soc_machine snd_soc_machine_corgi = {
+static struct snd_soc_card snd_soc_corgi = {
 	.name = "Corgi",
+	.platform = &pxa2xx_soc_platform,
 	.dai_link = &corgi_dai,
 	.num_links = 1,
 };
@@ -328,8 +325,7 @@
 
 /* corgi audio subsystem */
 static struct snd_soc_device corgi_snd_devdata = {
-	.machine = &snd_soc_machine_corgi,
-	.platform = &pxa2xx_soc_platform,
+	.card = &snd_soc_corgi,
 	.codec_dev = &soc_codec_dev_wm8731,
 	.codec_data = &corgi_wm8731_setup,
 };
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c
index 6781c5b..2e3386d 100644
--- a/sound/soc/pxa/e800_wm9712.c
+++ b/sound/soc/pxa/e800_wm9712.c
@@ -29,7 +29,7 @@
 #include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
-static struct snd_soc_machine e800;
+static struct snd_soc_card e800;
 
 static struct snd_soc_dai_link e800_dai[] = {
 {
@@ -40,15 +40,15 @@
 },
 };
 
-static struct snd_soc_machine e800 = {
+static struct snd_soc_card e800 = {
 	.name = "Toshiba e800",
+	.platform = &pxa2xx_soc_platform,
 	.dai_link = e800_dai,
 	.num_links = ARRAY_SIZE(e800_dai),
 };
 
 static struct snd_soc_device e800_snd_devdata = {
-	.machine = &e800,
-	.platform = &pxa2xx_soc_platform,
+	.card = &e800,
 	.codec_dev = &soc_codec_dev_wm9712,
 };
 
diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c
index e6ff692..fe4a729 100644
--- a/sound/soc/pxa/em-x270.c
+++ b/sound/soc/pxa/em-x270.c
@@ -23,7 +23,6 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
@@ -53,15 +52,15 @@
 	},
 };
 
-static struct snd_soc_machine em_x270 = {
+static struct snd_soc_card em_x270 = {
 	.name = "EM-X270",
+	.platform = &pxa2xx_soc_platform,
 	.dai_link = em_x270_dai,
 	.num_links = ARRAY_SIZE(em_x270_dai),
 };
 
 static struct snd_soc_device em_x270_snd_devdata = {
-	.machine = &em_x270,
-	.platform = &pxa2xx_soc_platform,
+	.card = &em_x270,
 	.codec_dev = &soc_codec_dev_wm9712,
 };
 
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c
new file mode 100644
index 0000000..4a9cf30
--- /dev/null
+++ b/sound/soc/pxa/palm27x.c
@@ -0,0 +1,269 @@
+/*
+ * linux/sound/soc/pxa/palm27x.c
+ *
+ * SoC Audio driver for Palm T|X, T5 and LifeDrive
+ *
+ * based on tosa.c
+ *
+ * Copyright (C) 2008 Marek Vasut <marek.vasut@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/moduleparam.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.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/audio.h>
+#include <mach/palmasoc.h>
+
+#include "../codecs/wm9712.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+static int palm27x_jack_func = 1;
+static int palm27x_spk_func = 1;
+static int palm27x_ep_gpio = -1;
+
+static void palm27x_ext_control(struct snd_soc_codec *codec)
+{
+	if (!palm27x_spk_func)
+		snd_soc_dapm_enable_pin(codec, "Speaker");
+	else
+		snd_soc_dapm_disable_pin(codec, "Speaker");
+
+	if (!palm27x_jack_func)
+		snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+	else
+		snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+
+	snd_soc_dapm_sync(codec);
+}
+
+static int palm27x_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->socdev->codec;
+
+	/* check the jack status at stream startup */
+	palm27x_ext_control(codec);
+	return 0;
+}
+
+static struct snd_soc_ops palm27x_ops = {
+	.startup = palm27x_startup,
+};
+
+static irqreturn_t palm27x_interrupt(int irq, void *v)
+{
+	palm27x_spk_func = gpio_get_value(palm27x_ep_gpio);
+	palm27x_jack_func = !palm27x_spk_func;
+	return IRQ_HANDLED;
+}
+
+static int palm27x_get_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = palm27x_jack_func;
+	return 0;
+}
+
+static int palm27x_set_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	if (palm27x_jack_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	palm27x_jack_func = ucontrol->value.integer.value[0];
+	palm27x_ext_control(codec);
+	return 1;
+}
+
+static int palm27x_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = palm27x_spk_func;
+	return 0;
+}
+
+static int palm27x_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+	if (palm27x_spk_func == ucontrol->value.integer.value[0])
+		return 0;
+
+	palm27x_spk_func = ucontrol->value.integer.value[0];
+	palm27x_ext_control(codec);
+	return 1;
+}
+
+/* PalmTX machine dapm widgets */
+static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+/* PalmTX audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* headphone connected to HPOUTL, HPOUTR */
+	{"Headphone Jack", NULL, "HPOUTL"},
+	{"Headphone Jack", NULL, "HPOUTR"},
+
+	/* ext speaker connected to ROUT2, LOUT2 */
+	{"Speaker", NULL, "LOUT2"},
+	{"Speaker", NULL, "ROUT2"},
+};
+
+static const char *jack_function[] = {"Headphone", "Off"};
+static const char *spk_function[] = {"On", "Off"};
+static const struct soc_enum palm27x_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, jack_function),
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new palm27x_controls[] = {
+	SOC_ENUM_EXT("Jack Function", palm27x_enum[0], palm27x_get_jack,
+		palm27x_set_jack),
+	SOC_ENUM_EXT("Speaker Function", palm27x_enum[1], palm27x_get_spk,
+		palm27x_set_spk),
+};
+
+static int palm27x_ac97_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	snd_soc_dapm_nc_pin(codec, "OUT3");
+	snd_soc_dapm_nc_pin(codec, "MONOOUT");
+
+	/* add palm27x specific controls */
+	for (i = 0; i < ARRAY_SIZE(palm27x_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&palm27x_controls[i],
+						codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	/* add palm27x specific widgets */
+	snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets,
+				ARRAY_SIZE(palm27x_dapm_widgets));
+
+	/* set up palm27x specific audio path audio_map */
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+	snd_soc_dapm_sync(codec);
+	return 0;
+}
+
+static struct snd_soc_dai_link palm27x_dai[] = {
+{
+	.name = "AC97 HiFi",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+	.init = palm27x_ac97_init,
+	.ops = &palm27x_ops,
+},
+{
+	.name = "AC97 Aux",
+	.stream_name = "AC97 Aux",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+	.ops = &palm27x_ops,
+},
+};
+
+static struct snd_soc_card palm27x_asoc = {
+	.name = "Palm/PXA27x",
+	.platform = &pxa2xx_soc_platform,
+	.dai_link = palm27x_dai,
+	.num_links = ARRAY_SIZE(palm27x_dai),
+};
+
+static struct snd_soc_device palm27x_snd_devdata = {
+	.card = &palm27x_asoc,
+	.codec_dev = &soc_codec_dev_wm9712,
+};
+
+static struct platform_device *palm27x_snd_device;
+
+static int __init palm27x_asoc_init(void)
+{
+	int ret;
+
+	if (!(machine_is_palmtx() || machine_is_palmt5() ||
+		machine_is_palmld()))
+		return -ENODEV;
+
+	ret = gpio_request(palm27x_ep_gpio, "Headphone Jack");
+	if (ret)
+		return ret;
+	ret = gpio_direction_input(palm27x_ep_gpio);
+	if (ret)
+		goto err_alloc;
+
+	if (request_irq(gpio_to_irq(palm27x_ep_gpio), palm27x_interrupt,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			"Headphone jack", NULL))
+		goto err_alloc;
+
+	palm27x_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!palm27x_snd_device) {
+		ret = -ENOMEM;
+		goto err_dev;
+	}
+
+	platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata);
+	palm27x_snd_devdata.dev = &palm27x_snd_device->dev;
+	ret = platform_device_add(palm27x_snd_device);
+
+	if (ret != 0)
+		goto put_device;
+
+	return 0;
+
+put_device:
+	platform_device_put(palm27x_snd_device);
+err_dev:
+	free_irq(gpio_to_irq(palm27x_ep_gpio), NULL);
+err_alloc:
+	gpio_free(palm27x_ep_gpio);
+
+	return ret;
+}
+
+static void __exit palm27x_asoc_exit(void)
+{
+	free_irq(gpio_to_irq(palm27x_ep_gpio), NULL);
+	gpio_free(palm27x_ep_gpio);
+	platform_device_unregister(palm27x_snd_device);
+}
+
+void __init palm27x_asoc_set_pdata(struct palm27x_asoc_info *data)
+{
+	palm27x_ep_gpio = data->jack_gpio;
+}
+
+module_init(palm27x_asoc_init);
+module_exit(palm27x_asoc_exit);
+
+/* Module information */
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index 4d9930c..6e98271 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -276,8 +276,9 @@
 };
 
 /* poodle audio machine driver */
-static struct snd_soc_machine snd_soc_machine_poodle = {
+static struct snd_soc_card snd_soc_poodle = {
 	.name = "Poodle",
+	.platform = &pxa2xx_soc_platform,
 	.dai_link = &poodle_dai,
 	.num_links = 1,
 };
@@ -290,8 +291,7 @@
 
 /* poodle audio subsystem */
 static struct snd_soc_device poodle_snd_devdata = {
-	.machine = &snd_soc_machine_poodle,
-	.platform = &pxa2xx_soc_platform,
+	.card = &snd_soc_poodle,
 	.codec_dev = &soc_codec_dev_wm8731,
 	.codec_data = &poodle_wm8731_setup,
 };
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
new file mode 100644
index 0000000..73cb6b4
--- /dev/null
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -0,0 +1,931 @@
+#define DEBUG
+/*
+ * pxa-ssp.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2005,2008 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ * TODO:
+ *  o Test network mode for > 16bit sample size
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
+
+#include <mach/hardware.h>
+#include <mach/pxa-regs.h>
+#include <mach/regs-ssp.h>
+#include <mach/audio.h>
+#include <mach/ssp.h>
+
+#include "pxa2xx-pcm.h"
+#include "pxa-ssp.h"
+
+/*
+ * SSP audio private data
+ */
+struct ssp_priv {
+	struct ssp_dev dev;
+	unsigned int sysclk;
+	int dai_fmt;
+#ifdef CONFIG_PM
+	struct ssp_state state;
+#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",
+		 ssp_read_reg(ssp, SSCR0), ssp_read_reg(ssp, SSCR1),
+		 ssp_read_reg(ssp, SSTO));
+
+	dev_dbg(&ssp->pdev->dev, "SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x\n",
+		 ssp_read_reg(ssp, SSPSP), ssp_read_reg(ssp, SSSR),
+		 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,
+	},
+};
+
+static int pxa_ssp_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct ssp_priv *priv = cpu_dai->private_data;
+	int ret = 0;
+
+	if (!cpu_dai->active) {
+		ret = ssp_init(&priv->dev, cpu_dai->id + 1, SSP_NO_IRQ);
+		if (ret < 0)
+			return ret;
+		ssp_disable(&priv->dev);
+	}
+	return ret;
+}
+
+static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct ssp_priv *priv = cpu_dai->private_data;
+
+	if (!cpu_dai->active) {
+		ssp_disable(&priv->dev);
+		ssp_exit(&priv->dev);
+	}
+}
+
+#ifdef CONFIG_PM
+
+static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
+{
+	struct ssp_priv *priv = cpu_dai->private_data;
+
+	if (!cpu_dai->active)
+		return 0;
+
+	ssp_save_state(&priv->dev, &priv->state);
+	clk_disable(priv->dev.ssp->clk);
+	return 0;
+}
+
+static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
+{
+	struct ssp_priv *priv = cpu_dai->private_data;
+
+	if (!cpu_dai->active)
+		return 0;
+
+	clk_enable(priv->dev.ssp->clk);
+	ssp_restore_state(&priv->dev, &priv->state);
+	ssp_enable(&priv->dev);
+
+	return 0;
+}
+
+#else
+#define pxa_ssp_suspend	NULL
+#define pxa_ssp_resume	NULL
+#endif
+
+/**
+ * ssp_set_clkdiv - set SSP clock divider
+ * @div: serial clock rate divider
+ */
+static void ssp_set_scr(struct ssp_dev *dev, u32 div)
+{
+	struct ssp_device *ssp = dev->ssp;
+	u32 sscr0 = ssp_read_reg(dev->ssp, SSCR0) & ~SSCR0_SCR;
+
+	ssp_write_reg(ssp, SSCR0, (sscr0 | SSCR0_SerClkDiv(div)));
+}
+
+/*
+ * Set the SSP ports SYSCLK.
+ */
+static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+	int clk_id, unsigned int freq, int dir)
+{
+	struct ssp_priv *priv = cpu_dai->private_data;
+	struct ssp_device *ssp = priv->dev.ssp;
+	int val;
+
+	u32 sscr0 = ssp_read_reg(ssp, SSCR0) &
+		~(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ADC);
+
+	dev_dbg(&ssp->pdev->dev,
+		"pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n",
+		cpu_dai->id, clk_id, freq);
+
+	switch (clk_id) {
+	case PXA_SSP_CLK_NET_PLL:
+		sscr0 |= SSCR0_MOD;
+		break;
+	case PXA_SSP_CLK_PLL:
+		/* Internal PLL is fixed */
+		if (cpu_is_pxa25x())
+			priv->sysclk = 1843200;
+		else
+			priv->sysclk = 13000000;
+		break;
+	case PXA_SSP_CLK_EXT:
+		priv->sysclk = freq;
+		sscr0 |= SSCR0_ECS;
+		break;
+	case PXA_SSP_CLK_NET:
+		priv->sysclk = freq;
+		sscr0 |= SSCR0_NCS | SSCR0_MOD;
+		break;
+	case PXA_SSP_CLK_AUDIO:
+		priv->sysclk = 0;
+		ssp_set_scr(&priv->dev, 1);
+		sscr0 |= SSCR0_ADC;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	/* The SSP clock must be disabled when changing SSP clock mode
+	 * on PXA2xx.  On PXA3xx it must be enabled when doing so. */
+	if (!cpu_is_pxa3xx())
+		clk_disable(priv->dev.ssp->clk);
+	val = ssp_read_reg(ssp, SSCR0) | sscr0;
+	ssp_write_reg(ssp, SSCR0, val);
+	if (!cpu_is_pxa3xx())
+		clk_enable(priv->dev.ssp->clk);
+
+	return 0;
+}
+
+/*
+ * Set the SSP clock dividers.
+ */
+static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
+	int div_id, int div)
+{
+	struct ssp_priv *priv = cpu_dai->private_data;
+	struct ssp_device *ssp = priv->dev.ssp;
+	int val;
+
+	switch (div_id) {
+	case PXA_SSP_AUDIO_DIV_ACDS:
+		val = (ssp_read_reg(ssp, SSACD) & ~0x7) | SSACD_ACDS(div);
+		ssp_write_reg(ssp, SSACD, val);
+		break;
+	case PXA_SSP_AUDIO_DIV_SCDB:
+		val = ssp_read_reg(ssp, SSACD);
+		val &= ~SSACD_SCDB;
+#if defined(CONFIG_PXA3xx)
+		if (cpu_is_pxa3xx())
+			val &= ~SSACD_SCDX8;
+#endif
+		switch (div) {
+		case PXA_SSP_CLK_SCDB_1:
+			val |= SSACD_SCDB;
+			break;
+		case PXA_SSP_CLK_SCDB_4:
+			break;
+#if defined(CONFIG_PXA3xx)
+		case PXA_SSP_CLK_SCDB_8:
+			if (cpu_is_pxa3xx())
+				val |= SSACD_SCDX8;
+			else
+				return -EINVAL;
+			break;
+#endif
+		default:
+			return -EINVAL;
+		}
+		ssp_write_reg(ssp, SSACD, val);
+		break;
+	case PXA_SSP_DIV_SCR:
+		ssp_set_scr(&priv->dev, div);
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/*
+ * Configure the PLL frequency pxa27x and (afaik - pxa320 only)
+ */
+static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai,
+	int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+	struct ssp_priv *priv = cpu_dai->private_data;
+	struct ssp_device *ssp = priv->dev.ssp;
+	u32 ssacd = ssp_read_reg(ssp, SSACD) & ~0x70;
+
+#if defined(CONFIG_PXA3xx)
+	if (cpu_is_pxa3xx())
+		ssp_write_reg(ssp, SSACDD, 0);
+#endif
+
+	switch (freq_out) {
+	case 5622000:
+		break;
+	case 11345000:
+		ssacd |= (0x1 << 4);
+		break;
+	case 12235000:
+		ssacd |= (0x2 << 4);
+		break;
+	case 14857000:
+		ssacd |= (0x3 << 4);
+		break;
+	case 32842000:
+		ssacd |= (0x4 << 4);
+		break;
+	case 48000000:
+		ssacd |= (0x5 << 4);
+		break;
+	case 0:
+		/* Disable */
+		break;
+
+	default:
+#ifdef CONFIG_PXA3xx
+		/* PXA3xx has a clock ditherer which can be used to generate
+		 * a wider range of frequencies - calculate a value for it.
+		 */
+		if (cpu_is_pxa3xx()) {
+			u32 val;
+			u64 tmp = 19968;
+			tmp *= 1000000;
+			do_div(tmp, freq_out);
+			val = tmp;
+
+			val = (val << 16) | 64;;
+			ssp_write_reg(ssp, SSACDD, val);
+
+			ssacd |= (0x6 << 4);
+
+			dev_dbg(&ssp->pdev->dev,
+				"Using SSACDD %x to supply %dHz\n",
+				val, freq_out);
+			break;
+		}
+#endif
+
+		return -EINVAL;
+	}
+
+	ssp_write_reg(ssp, SSACD, ssacd);
+
+	return 0;
+}
+
+/*
+ * Set the active slots in TDM/Network mode
+ */
+static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
+	unsigned int mask, int slots)
+{
+	struct ssp_priv *priv = cpu_dai->private_data;
+	struct ssp_device *ssp = priv->dev.ssp;
+	u32 sscr0;
+
+	sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7);
+
+	/* set number of active slots */
+	sscr0 |= SSCR0_SlotsPerFrm(slots);
+	ssp_write_reg(ssp, SSCR0, sscr0);
+
+	/* set active slot mask */
+	ssp_write_reg(ssp, SSTSA, mask);
+	ssp_write_reg(ssp, SSRSA, mask);
+	return 0;
+}
+
+/*
+ * Tristate the SSP DAI lines
+ */
+static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
+	int tristate)
+{
+	struct ssp_priv *priv = cpu_dai->private_data;
+	struct ssp_device *ssp = priv->dev.ssp;
+	u32 sscr1;
+
+	sscr1 = ssp_read_reg(ssp, SSCR1);
+	if (tristate)
+		sscr1 &= ~SSCR1_TTE;
+	else
+		sscr1 |= SSCR1_TTE;
+	ssp_write_reg(ssp, SSCR1, sscr1);
+
+	return 0;
+}
+
+/*
+ * Set up the SSP DAI format.
+ * The SSP Port must be inactive before calling this function as the
+ * physical interface format is changed.
+ */
+static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+		unsigned int fmt)
+{
+	struct ssp_priv *priv = cpu_dai->private_data;
+	struct ssp_device *ssp = priv->dev.ssp;
+	u32 sscr0;
+	u32 sscr1;
+	u32 sspsp;
+
+	/* reset port settings */
+	sscr0 = ssp_read_reg(ssp, SSCR0) &
+		(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ADC);
+	sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
+	sspsp = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		sscr1 |= SSCR1_SCLKDIR;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ssp_write_reg(ssp, SSCR0, sscr0);
+	ssp_write_reg(ssp, SSCR1, sscr1);
+	ssp_write_reg(ssp, SSPSP, sspsp);
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		sscr0 |= SSCR0_MOD | SSCR0_PSP;
+		sscr1 |= SSCR1_RWOT | SSCR1_TRAIL;
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			sspsp |= SSPSP_FSRT;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			sspsp |= SSPSP_SFRMP | SSPSP_FSRT;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			sspsp |= SSPSP_SFRMP;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A:
+		sspsp |= SSPSP_FSRT;
+	case SND_SOC_DAIFMT_DSP_B:
+		sscr0 |= SSCR0_MOD | SSCR0_PSP;
+		sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			sspsp |= SSPSP_SFRMP;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	ssp_write_reg(ssp, SSCR0, sscr0);
+	ssp_write_reg(ssp, SSCR1, sscr1);
+	ssp_write_reg(ssp, SSPSP, sspsp);
+
+	dump_registers(ssp);
+
+	/* Since we are configuring the timings for the format by hand
+	 * we have to defer some things until hw_params() where we
+	 * know parameters like the sample size.
+	 */
+	priv->dai_fmt = fmt;
+
+	return 0;
+}
+
+/*
+ * Set the SSP audio DMA parameters and sample size.
+ * Can be called multiple times by oss emulation.
+ */
+static int pxa_ssp_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_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);
+	u32 sscr0;
+	u32 sspsp;
+	int width = snd_pcm_format_physical_width(params_format(params));
+
+	/* select correct DMA params */
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		dma = 1; /* capture DMA offset is 1,3 */
+	if (chn == 2)
+		dma += 2; /* stereo DMA offset is 2, mono 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);
+
+	/* we can only change the settings if the port is not in use */
+	if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
+		return 0;
+
+	/* clear selected SSP bits */
+	sscr0 = ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
+	ssp_write_reg(ssp, SSCR0, sscr0);
+
+	/* bit size */
+	sscr0 = ssp_read_reg(ssp, SSCR0);
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+#ifdef CONFIG_PXA3xx
+		if (cpu_is_pxa3xx())
+			sscr0 |= SSCR0_FPCKE;
+#endif
+		sscr0 |= SSCR0_DataSize(16);
+		if (params_channels(params) > 1)
+			sscr0 |= SSCR0_EDSS;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8));
+		/* we must be in network mode (2 slots) for 24 bit stereo */
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16));
+		/* we must be in network mode (2 slots) for 32 bit stereo */
+		break;
+	}
+	ssp_write_reg(ssp, SSCR0, sscr0);
+
+	switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		/* Cleared when the DAI format is set */
+		sspsp = ssp_read_reg(ssp, SSPSP) | SSPSP_SFRMWDTH(width);
+		ssp_write_reg(ssp, SSPSP, sspsp);
+		break;
+	default:
+		break;
+	}
+
+	/* We always use a network mode so we always require TDM slots
+	 * - complain loudly and fail if they've not been set up yet.
+	 */
+	if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) {
+		dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n");
+		return -EINVAL;
+	}
+
+	dump_registers(ssp);
+
+	return 0;
+}
+
+static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret = 0;
+	struct ssp_priv *priv = cpu_dai->private_data;
+	struct ssp_device *ssp = priv->dev.ssp;
+	int val;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_RESUME:
+		ssp_enable(&priv->dev);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		val = ssp_read_reg(ssp, SSCR1);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			val |= SSCR1_TSRE;
+		else
+			val |= SSCR1_RSRE;
+		ssp_write_reg(ssp, SSCR1, val);
+		val = ssp_read_reg(ssp, SSSR);
+		ssp_write_reg(ssp, SSSR, val);
+		break;
+	case SNDRV_PCM_TRIGGER_START:
+		val = ssp_read_reg(ssp, SSCR1);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			val |= SSCR1_TSRE;
+		else
+			val |= SSCR1_RSRE;
+		ssp_write_reg(ssp, SSCR1, val);
+		ssp_enable(&priv->dev);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		val = ssp_read_reg(ssp, SSCR1);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			val &= ~SSCR1_TSRE;
+		else
+			val &= ~SSCR1_RSRE;
+		ssp_write_reg(ssp, SSCR1, val);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		ssp_disable(&priv->dev);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		val = ssp_read_reg(ssp, SSCR1);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			val &= ~SSCR1_TSRE;
+		else
+			val &= ~SSCR1_RSRE;
+		ssp_write_reg(ssp, SSCR1, val);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	dump_registers(ssp);
+
+	return ret;
+}
+
+static int pxa_ssp_probe(struct platform_device *pdev,
+			    struct snd_soc_dai *dai)
+{
+	struct ssp_priv *priv;
+	int ret;
+
+	priv = kzalloc(sizeof(struct ssp_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev.ssp = ssp_request(dai->id, "SoC audio");
+	if (priv->dev.ssp == NULL) {
+		ret = -ENODEV;
+		goto err_priv;
+	}
+
+	dai->private_data = priv;
+
+	return 0;
+
+err_priv:
+	kfree(priv);
+	return ret;
+}
+
+static void pxa_ssp_remove(struct platform_device *pdev,
+			      struct snd_soc_dai *dai)
+{
+	struct ssp_priv *priv = dai->private_data;
+	ssp_free(priv->dev.ssp);
+}
+
+#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+			  SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |	\
+			  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |	\
+			  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			    SNDRV_PCM_FMTBIT_S24_LE |	\
+			    SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai pxa_ssp_dai[] = {
+	{
+		.name = "pxa2xx-ssp1",
+		.id = 0,
+		.probe = pxa_ssp_probe,
+		.remove = pxa_ssp_remove,
+		.suspend = pxa_ssp_suspend,
+		.resume = pxa_ssp_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA_SSP_RATES,
+			.formats = PXA_SSP_FORMATS,
+		},
+		.capture = {
+			 .channels_min = 1,
+			 .channels_max = 2,
+			.rates = PXA_SSP_RATES,
+			.formats = PXA_SSP_FORMATS,
+		 },
+		.ops = {
+			.startup = pxa_ssp_startup,
+			.shutdown = pxa_ssp_shutdown,
+			.trigger = pxa_ssp_trigger,
+			.hw_params = pxa_ssp_hw_params,
+			.set_sysclk = pxa_ssp_set_dai_sysclk,
+			.set_clkdiv = pxa_ssp_set_dai_clkdiv,
+			.set_pll = pxa_ssp_set_dai_pll,
+			.set_fmt = pxa_ssp_set_dai_fmt,
+			.set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
+			.set_tristate = pxa_ssp_set_dai_tristate,
+		},
+	},
+	{	.name = "pxa2xx-ssp2",
+		.id = 1,
+		.probe = pxa_ssp_probe,
+		.remove = pxa_ssp_remove,
+		.suspend = pxa_ssp_suspend,
+		.resume = pxa_ssp_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA_SSP_RATES,
+			.formats = PXA_SSP_FORMATS,
+		},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA_SSP_RATES,
+			.formats = PXA_SSP_FORMATS,
+		 },
+		.ops = {
+			.startup = pxa_ssp_startup,
+			.shutdown = pxa_ssp_shutdown,
+			.trigger = pxa_ssp_trigger,
+			.hw_params = pxa_ssp_hw_params,
+			.set_sysclk = pxa_ssp_set_dai_sysclk,
+			.set_clkdiv = pxa_ssp_set_dai_clkdiv,
+			.set_pll = pxa_ssp_set_dai_pll,
+			.set_fmt = pxa_ssp_set_dai_fmt,
+			.set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
+			.set_tristate = pxa_ssp_set_dai_tristate,
+		},
+	},
+	{
+		.name = "pxa2xx-ssp3",
+		.id = 2,
+		.probe = pxa_ssp_probe,
+		.remove = pxa_ssp_remove,
+		.suspend = pxa_ssp_suspend,
+		.resume = pxa_ssp_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA_SSP_RATES,
+			.formats = PXA_SSP_FORMATS,
+		},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA_SSP_RATES,
+			.formats = PXA_SSP_FORMATS,
+		 },
+		.ops = {
+			.startup = pxa_ssp_startup,
+			.shutdown = pxa_ssp_shutdown,
+			.trigger = pxa_ssp_trigger,
+			.hw_params = pxa_ssp_hw_params,
+			.set_sysclk = pxa_ssp_set_dai_sysclk,
+			.set_clkdiv = pxa_ssp_set_dai_clkdiv,
+			.set_pll = pxa_ssp_set_dai_pll,
+			.set_fmt = pxa_ssp_set_dai_fmt,
+			.set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
+			.set_tristate = pxa_ssp_set_dai_tristate,
+		},
+	},
+	{
+		.name = "pxa2xx-ssp4",
+		.id = 3,
+		.probe = pxa_ssp_probe,
+		.remove = pxa_ssp_remove,
+		.suspend = pxa_ssp_suspend,
+		.resume = pxa_ssp_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA_SSP_RATES,
+			.formats = PXA_SSP_FORMATS,
+		},
+		.capture = {
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = PXA_SSP_RATES,
+			.formats = PXA_SSP_FORMATS,
+		 },
+		.ops = {
+			.startup = pxa_ssp_startup,
+			.shutdown = pxa_ssp_shutdown,
+			.trigger = pxa_ssp_trigger,
+			.hw_params = pxa_ssp_hw_params,
+			.set_sysclk = pxa_ssp_set_dai_sysclk,
+			.set_clkdiv = pxa_ssp_set_dai_clkdiv,
+			.set_pll = pxa_ssp_set_dai_pll,
+			.set_fmt = pxa_ssp_set_dai_fmt,
+			.set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
+			.set_tristate = pxa_ssp_set_dai_tristate,
+		},
+	},
+};
+EXPORT_SYMBOL_GPL(pxa_ssp_dai);
+
+static int __init pxa_ssp_init(void)
+{
+	return snd_soc_register_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai));
+}
+module_init(pxa_ssp_init);
+
+static void __exit pxa_ssp_exit(void)
+{
+	snd_soc_unregister_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai));
+}
+module_exit(pxa_ssp_exit);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa-ssp.h b/sound/soc/pxa/pxa-ssp.h
new file mode 100644
index 0000000..91deadd
--- /dev/null
+++ b/sound/soc/pxa/pxa-ssp.h
@@ -0,0 +1,47 @@
+/*
+ * ASoC PXA SSP port support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PXA_SSP_H
+#define _PXA_SSP_H
+
+/* pxa DAI SSP IDs */
+#define PXA_DAI_SSP1			0
+#define PXA_DAI_SSP2			1
+#define PXA_DAI_SSP3			2
+#define PXA_DAI_SSP4			3
+
+/* SSP clock sources */
+#define PXA_SSP_CLK_PLL	0
+#define PXA_SSP_CLK_EXT	1
+#define PXA_SSP_CLK_NET	2
+#define PXA_SSP_CLK_AUDIO	3
+#define PXA_SSP_CLK_NET_PLL	4
+
+/* SSP audio dividers */
+#define PXA_SSP_AUDIO_DIV_ACDS		0
+#define PXA_SSP_AUDIO_DIV_SCDB		1
+#define PXA_SSP_DIV_SCR				2
+
+/* SSP ACDS audio dividers values */
+#define PXA_SSP_CLK_AUDIO_DIV_1		0
+#define PXA_SSP_CLK_AUDIO_DIV_2		1
+#define PXA_SSP_CLK_AUDIO_DIV_4		2
+#define PXA_SSP_CLK_AUDIO_DIV_8		3
+#define PXA_SSP_CLK_AUDIO_DIV_16	4
+#define PXA_SSP_CLK_AUDIO_DIV_32	5
+
+/* SSP divider bypass */
+#define PXA_SSP_CLK_SCDB_4		0
+#define PXA_SSP_CLK_SCDB_1		1
+#define PXA_SSP_CLK_SCDB_8		2
+
+#define PXA_SSP_PLL_OUT  0
+
+extern struct snd_soc_dai pxa_ssp_dai[4];
+
+#endif
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index a7a3a9c..780db67 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -87,14 +87,12 @@
 };
 
 #ifdef CONFIG_PM
-static int pxa2xx_ac97_suspend(struct platform_device *pdev,
-	struct snd_soc_dai *dai)
+static int pxa2xx_ac97_suspend(struct snd_soc_dai *dai)
 {
 	return pxa2xx_ac97_hw_suspend();
 }
 
-static int pxa2xx_ac97_resume(struct platform_device *pdev,
-	struct snd_soc_dai *dai)
+static int pxa2xx_ac97_resume(struct snd_soc_dai *dai)
 {
 	return pxa2xx_ac97_hw_resume();
 }
@@ -117,7 +115,8 @@
 }
 
 static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -131,7 +130,8 @@
 }
 
 static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+				     struct snd_pcm_hw_params *params,
+				     struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -145,7 +145,8 @@
 }
 
 static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+				     struct snd_pcm_hw_params *params,
+				     struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -170,7 +171,7 @@
 {
 	.name = "pxa2xx-ac97",
 	.id = 0,
-	.type = SND_SOC_DAI_AC97,
+	.ac97_control = 1,
 	.probe = pxa2xx_ac97_probe,
 	.remove = pxa2xx_ac97_remove,
 	.suspend = pxa2xx_ac97_suspend,
@@ -193,7 +194,7 @@
 {
 	.name = "pxa2xx-ac97-aux",
 	.id = 1,
-	.type = SND_SOC_DAI_AC97,
+	.ac97_control = 1,
 	.playback = {
 		.stream_name = "AC97 Aux Playback",
 		.channels_min = 1,
@@ -212,7 +213,7 @@
 {
 	.name = "pxa2xx-ac97-mic",
 	.id = 2,
-	.type = SND_SOC_DAI_AC97,
+	.ac97_control = 1,
 	.capture = {
 		.stream_name = "AC97 Mic Capture",
 		.channels_min = 1,
@@ -227,6 +228,18 @@
 EXPORT_SYMBOL_GPL(pxa_ac97_dai);
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
+static int __init pxa_ac97_init(void)
+{
+	return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
+}
+module_init(pxa_ac97_init);
+
+static void __exit pxa_ac97_exit(void)
+{
+	snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
+}
+module_exit(pxa_ac97_exit);
+
 MODULE_AUTHOR("Nicolas Pitre");
 MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index e758034..517991f 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -121,7 +121,8 @@
 	},
 };
 
-static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream)
+static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -187,7 +188,8 @@
 }
 
 static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -248,7 +250,8 @@
 	return 0;
 }
 
-static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			      struct snd_soc_dai *dai)
 {
 	int ret = 0;
 
@@ -269,7 +272,8 @@
 	return ret;
 }
 
-static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream)
+static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
 {
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		SACR1 |= SACR1_DRPL;
@@ -289,8 +293,7 @@
 }
 
 #ifdef CONFIG_PM
-static int pxa2xx_i2s_suspend(struct platform_device *dev,
-	struct snd_soc_dai *dai)
+static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai)
 {
 	if (!dai->active)
 		return 0;
@@ -307,8 +310,7 @@
 	return 0;
 }
 
-static int pxa2xx_i2s_resume(struct platform_device *pdev,
-	struct snd_soc_dai *dai)
+static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
 {
 	if (!dai->active)
 		return 0;
@@ -336,7 +338,6 @@
 struct snd_soc_dai pxa_i2s_dai = {
 	.name = "pxa2xx-i2s",
 	.id = 0,
-	.type = SND_SOC_DAI_I2S,
 	.suspend = pxa2xx_i2s_suspend,
 	.resume = pxa2xx_i2s_resume,
 	.playback = {
@@ -353,8 +354,7 @@
 		.startup = pxa2xx_i2s_startup,
 		.shutdown = pxa2xx_i2s_shutdown,
 		.trigger = pxa2xx_i2s_trigger,
-		.hw_params = pxa2xx_i2s_hw_params,},
-	.dai_ops = {
+		.hw_params = pxa2xx_i2s_hw_params,
 		.set_fmt = pxa2xx_i2s_set_dai_fmt,
 		.set_sysclk = pxa2xx_i2s_set_dai_sysclk,
 	},
@@ -364,12 +364,23 @@
 
 static int pxa2xx_i2s_probe(struct platform_device *dev)
 {
+	int ret;
+
 	clk_i2s = clk_get(&dev->dev, "I2SCLK");
-	return IS_ERR(clk_i2s) ? PTR_ERR(clk_i2s) : 0;
+	if (IS_ERR(clk_i2s))
+		return PTR_ERR(clk_i2s);
+
+	pxa_i2s_dai.dev = &dev->dev;
+	ret = snd_soc_register_dai(&pxa_i2s_dai);
+	if (ret != 0)
+		clk_put(clk_i2s);
+
+	return ret;
 }
 
 static int __devexit pxa2xx_i2s_remove(struct platform_device *dev)
 {
+	snd_soc_unregister_dai(&pxa_i2s_dai);
 	clk_put(clk_i2s);
 	clk_i2s = ERR_PTR(-ENOENT);
 	return 0;
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index afcd892..c670d08 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -69,7 +69,7 @@
 	return 0;
 }
 
-struct snd_pcm_ops pxa2xx_pcm_ops = {
+static struct snd_pcm_ops pxa2xx_pcm_ops = {
 	.open		= __pxa2xx_pcm_open,
 	.close		= __pxa2xx_pcm_close,
 	.ioctl		= snd_pcm_lib_ioctl,
@@ -118,6 +118,18 @@
 };
 EXPORT_SYMBOL_GPL(pxa2xx_soc_platform);
 
+static int __init pxa2xx_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&pxa2xx_soc_platform);
+}
+module_init(pxa2xx_soc_platform_init);
+
+static void __exit pxa2xx_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&pxa2xx_soc_platform);
+}
+module_exit(pxa2xx_soc_platform_exit);
+
 MODULE_AUTHOR("Nicolas Pitre");
 MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index d307b67..a3b9e6b 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -319,8 +319,9 @@
 };
 
 /* spitz audio machine driver */
-static struct snd_soc_machine snd_soc_machine_spitz = {
+static struct snd_soc_card snd_soc_spitz = {
 	.name = "Spitz",
+	.platform = &pxa2xx_soc_platform,
 	.dai_link = &spitz_dai,
 	.num_links = 1,
 };
@@ -333,8 +334,7 @@
 
 /* spitz audio subsystem */
 static struct snd_soc_device spitz_snd_devdata = {
-	.machine = &snd_soc_machine_spitz,
-	.platform = &pxa2xx_soc_platform,
+	.card = &snd_soc_spitz,
 	.codec_dev = &soc_codec_dev_wm8750,
 	.codec_data = &spitz_wm8750_setup,
 };
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index afefe41..c77194f 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -38,7 +38,7 @@
 #include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
-static struct snd_soc_machine tosa;
+static struct snd_soc_card tosa;
 
 #define TOSA_HP        0
 #define TOSA_MIC_INT   1
@@ -230,15 +230,37 @@
 },
 };
 
-static struct snd_soc_machine tosa = {
+static int tosa_probe(struct platform_device *dev)
+{
+	int ret;
+
+	ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack");
+	if (ret)
+		return ret;
+	ret = gpio_direction_output(TOSA_GPIO_L_MUTE, 0);
+	if (ret)
+		gpio_free(TOSA_GPIO_L_MUTE);
+
+	return ret;
+}
+
+static int tosa_remove(struct platform_device *dev)
+{
+	gpio_free(TOSA_GPIO_L_MUTE);
+	return 0;
+}
+
+static struct snd_soc_card tosa = {
 	.name = "Tosa",
+	.platform = &pxa2xx_soc_platform,
 	.dai_link = tosa_dai,
 	.num_links = ARRAY_SIZE(tosa_dai),
+	.probe = tosa_probe,
+	.remove = tosa_remove,
 };
 
 static struct snd_soc_device tosa_snd_devdata = {
-	.machine = &tosa,
-	.platform = &pxa2xx_soc_platform,
+	.card = &tosa,
 	.codec_dev = &soc_codec_dev_wm9712,
 };
 
@@ -251,11 +273,6 @@
 	if (!machine_is_tosa())
 		return -ENODEV;
 
-	ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack");
-	if (ret)
-		return ret;
-	gpio_direction_output(TOSA_GPIO_L_MUTE, 0);
-
 	tosa_snd_device = platform_device_alloc("soc-audio", -1);
 	if (!tosa_snd_device) {
 		ret = -ENOMEM;
@@ -272,15 +289,12 @@
 	platform_device_put(tosa_snd_device);
 
 err_alloc:
-	gpio_free(TOSA_GPIO_L_MUTE);
-
 	return ret;
 }
 
 static void __exit tosa_exit(void)
 {
 	platform_device_unregister(tosa_snd_device);
-	gpio_free(TOSA_GPIO_L_MUTE);
 }
 
 module_init(tosa_init);
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
new file mode 100644
index 0000000..f8e9ecd
--- /dev/null
+++ b/sound/soc/pxa/zylonite.c
@@ -0,0 +1,219 @@
+/*
+ * zylonite.c  --  SoC audio for Zylonite
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/wm9713.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+#include "pxa-ssp.h"
+
+static struct snd_soc_card zylonite;
+
+static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("Headset Microphone", NULL),
+	SND_SOC_DAPM_MIC("Handset Microphone", NULL),
+	SND_SOC_DAPM_SPK("Multiactor", NULL),
+	SND_SOC_DAPM_SPK("Headset Earpiece", NULL),
+};
+
+/* Currently supported audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+
+	/* Headphone output connected to HPL/HPR */
+	{ "Headphone", NULL,  "HPL" },
+	{ "Headphone", NULL,  "HPR" },
+
+	/* On-board earpiece */
+	{ "Headset Earpiece", NULL, "OUT3" },
+
+	/* Headphone mic */
+	{ "MIC2A", NULL, "Mic Bias" },
+	{ "Mic Bias", NULL, "Headset Microphone" },
+
+	/* On-board mic */
+	{ "MIC1", NULL, "Mic Bias" },
+	{ "Mic Bias", NULL, "Handset Microphone" },
+
+	/* Multiactor differentially connected over SPKL/SPKR */
+	{ "Multiactor", NULL, "SPKL" },
+	{ "Multiactor", NULL, "SPKR" },
+};
+
+static int zylonite_wm9713_init(struct snd_soc_codec *codec)
+{
+	/* Currently we only support use of the AC97 clock here.  If
+	 * CLK_POUT is selected by SW15 then the clock API will need
+	 * to be used to request and enable it here.
+	 */
+
+	snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets,
+				  ARRAY_SIZE(zylonite_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+	/* Static setup for now */
+	snd_soc_dapm_enable_pin(codec, "Headphone");
+	snd_soc_dapm_enable_pin(codec, "Headset Earpiece");
+
+	snd_soc_dapm_sync(codec);
+	return 0;
+}
+
+static int zylonite_voice_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 pll_out = 0;
+	unsigned int acds = 0;
+	unsigned int wm9713_div = 0;
+	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+		wm9713_div = 12;
+		pll_out = 2048000;
+		break;
+	case 16000:
+		wm9713_div = 6;
+		pll_out = 4096000;
+		break;
+	case 48000:
+	default:
+		wm9713_div = 2;
+		pll_out = 12288000;
+		acds = 1;
+		break;
+	}
+
+	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;
+
+	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_tdm_slot(cpu_dai,
+				       params_channels(params),
+				       params_channels(params));
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, pll_out);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_AUDIO_DIV_ACDS, acds);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Note that if the PLL is in use the WM9713_PCMCLK_PLL_DIV needs
+	 * to be set instead.
+	 */
+	ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV,
+				     WM9713_PCMDIV(wm9713_div));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops zylonite_voice_ops = {
+	.hw_params = zylonite_voice_hw_params,
+};
+
+static struct snd_soc_dai_link zylonite_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+	.codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+	.init = zylonite_wm9713_init,
+},
+{
+	.name = "AC97 Aux",
+	.stream_name = "AC97 Aux",
+	.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+	.codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+},
+{
+	.name = "WM9713 Voice",
+	.stream_name = "WM9713 Voice",
+	.cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP3],
+	.codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE],
+	.ops = &zylonite_voice_ops,
+},
+};
+
+static struct snd_soc_card zylonite = {
+	.name = "Zylonite",
+	.platform = &pxa2xx_soc_platform,
+	.dai_link = zylonite_dai,
+	.num_links = ARRAY_SIZE(zylonite_dai),
+};
+
+static struct snd_soc_device zylonite_snd_ac97_devdata = {
+	.card = &zylonite,
+	.codec_dev = &soc_codec_dev_wm9713,
+};
+
+static struct platform_device *zylonite_snd_ac97_device;
+
+static int __init zylonite_init(void)
+{
+	int ret;
+
+	zylonite_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+	if (!zylonite_snd_ac97_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(zylonite_snd_ac97_device,
+			     &zylonite_snd_ac97_devdata);
+	zylonite_snd_ac97_devdata.dev = &zylonite_snd_ac97_device->dev;
+
+	ret = platform_device_add(zylonite_snd_ac97_device);
+	if (ret != 0)
+		platform_device_put(zylonite_snd_ac97_device);
+
+	return ret;
+}
+
+static void __exit zylonite_exit(void)
+{
+	platform_device_unregister(zylonite_snd_ac97_device);
+}
+
+module_init(zylonite_init);
+module_exit(zylonite_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("ALSA SoC WM9713 Zylonite");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index b9f2353..fcd03ac 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -44,3 +44,8 @@
 	  Say Y if you want to add support for SoC audio on ln2440sbc
 	  with the ALC650.
 
+config SND_S3C24XX_SOC_S3C24XX_UDA134X
+	tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
+       	depends on SND_S3C24XX_SOC
+       	select SND_S3C24XX_SOC_I2S
+       	select SND_SOC_UDA134X
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 0aa5fb0..96b3f3f 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -13,7 +13,9 @@
 snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
 snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
 snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
+snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
 obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
 obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
+obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
index 4eab2c1..12c7148 100644
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -27,7 +27,7 @@
 #include "s3c24xx-pcm.h"
 #include "s3c24xx-ac97.h"
 
-static struct snd_soc_machine ln2440sbc;
+static struct snd_soc_card ln2440sbc;
 
 static struct snd_soc_dai_link ln2440sbc_dai[] = {
 {
@@ -38,15 +38,15 @@
 },
 };
 
-static struct snd_soc_machine ln2440sbc = {
+static struct snd_soc_card ln2440sbc = {
 	.name = "LN2440SBC",
+	.platform = &s3c24xx_soc_platform,
 	.dai_link = ln2440sbc_dai,
 	.num_links = ARRAY_SIZE(ln2440sbc_dai),
 };
 
 static struct snd_soc_device ln2440sbc_snd_ac97_devdata = {
-	.machine = &ln2440sbc,
-	.platform = &s3c24xx_soc_platform,
+	.card = &ln2440sbc,
 	.codec_dev = &soc_codec_dev_ac97,
 };
 
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 87ddfef..45bb12e 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -59,7 +59,7 @@
 #define NEO_CAPTURE_HEADSET		7
 #define NEO_CAPTURE_BLUETOOTH		8
 
-static struct snd_soc_machine neo1973;
+static struct snd_soc_card neo1973;
 static struct i2c_client *i2c;
 
 static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
@@ -548,7 +548,6 @@
 static struct snd_soc_dai bt_dai = {
 	.name = "Bluetooth",
 	.id = 0,
-	.type = SND_SOC_DAI_PCM,
 	.playback = {
 		.channels_min = 1,
 		.channels_max = 1,
@@ -579,8 +578,9 @@
 },
 };
 
-static struct snd_soc_machine neo1973 = {
+static struct snd_soc_card neo1973 = {
 	.name = "neo1973",
+	.platform = &s3c24xx_soc_platform,
 	.dai_link = neo1973_dai,
 	.num_links = ARRAY_SIZE(neo1973_dai),
 };
@@ -591,8 +591,7 @@
 };
 
 static struct snd_soc_device neo1973_snd_devdata = {
-	.machine = &neo1973,
-	.platform = &s3c24xx_soc_platform,
+	.card = &neo1973,
 	.codec_dev = &soc_codec_dev_wm8753,
 	.codec_data = &neo1973_wm8753_setup,
 };
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index ded7d99..f3fc0ab 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -343,7 +343,8 @@
 }
 
 static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
-				 struct snd_pcm_hw_params *params)
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	u32 iismod;
@@ -373,7 +374,8 @@
 	return 0;
 }
 
-static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
 {
 	int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
 	unsigned long irqs;
@@ -647,8 +649,7 @@
 }
 
 #ifdef CONFIG_PM
-static int s3c2412_i2s_suspend(struct platform_device *dev,
-			      struct snd_soc_dai *dai)
+static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
 {
 	struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
 	u32 iismod;
@@ -663,25 +664,24 @@
 		iismod = readl(i2s->regs + S3C2412_IISMOD);
 
 		if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
-			dev_warn(&dev->dev, "%s: RXDMA active?\n", __func__);
+			pr_warning("%s: RXDMA active?\n", __func__);
 
 		if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
-			dev_warn(&dev->dev, "%s: TXDMA active?\n", __func__);
+			pr_warning("%s: TXDMA active?\n", __func__);
 
 		if (iismod & S3C2412_IISCON_IIS_ACTIVE)
-			dev_warn(&dev->dev, "%s: IIS active\n", __func__);
+			pr_warning("%s: IIS active\n", __func__);
 	}
 
 	return 0;
 }
 
-static int s3c2412_i2s_resume(struct platform_device *pdev,
-			      struct snd_soc_dai *dai)
+static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
 {
 	struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
 
-	dev_info(&pdev->dev, "dai_active %d, IISMOD %08x, IISCON %08x\n",
-		 dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
+	pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
+		dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
 
 	if (dai->active) {
 		writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
@@ -711,7 +711,6 @@
 struct snd_soc_dai s3c2412_i2s_dai = {
 	.name	= "s3c2412-i2s",
 	.id	= 0,
-	.type	= SND_SOC_DAI_I2S,
 	.probe	= s3c2412_i2s_probe,
 	.suspend = s3c2412_i2s_suspend,
 	.resume = s3c2412_i2s_resume,
@@ -730,8 +729,6 @@
 	.ops = {
 		.trigger	= s3c2412_i2s_trigger,
 		.hw_params	= s3c2412_i2s_hw_params,
-	},
-	.dai_ops = {
 		.set_fmt	= s3c2412_i2s_set_fmt,
 		.set_clkdiv	= s3c2412_i2s_set_clkdiv,
 		.set_sysclk	= s3c2412_i2s_set_sysclk,
@@ -739,6 +736,19 @@
 };
 EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
 
+static int __init s3c2412_i2s_init(void)
+{
+	return snd_soc_register_dai(&s3c2412_i2s_dai);
+}
+module_init(s3c2412_i2s_init);
+
+static void __exit s3c2412_i2s_exit(void)
+{
+	snd_soc_unregister_dai(&s3c2412_i2s_dai);
+}
+module_exit(s3c2412_i2s_exit);
+
+
 /* Module information */
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
index 19c5c3c..1bfce40 100644
--- a/sound/soc/s3c24xx/s3c2443-ac97.c
+++ b/sound/soc/s3c24xx/s3c2443-ac97.c
@@ -271,7 +271,8 @@
 }
 
 static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -284,7 +285,8 @@
 	return 0;
 }
 
-static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd)
+static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
 {
 	u32 ac_glbctrl;
 
@@ -313,7 +315,8 @@
 }
 
 static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+				      struct snd_pcm_hw_params *params,
+				      struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -327,7 +330,7 @@
 }
 
 static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
-	int cmd)
+				    int cmd, struct snd_soc_dai *dai)
 {
 	u32 ac_glbctrl;
 
@@ -356,7 +359,7 @@
 {
 	.name = "s3c2443-ac97",
 	.id = 0,
-	.type = SND_SOC_DAI_AC97,
+	.ac97_control = 1,
 	.probe = s3c2443_ac97_probe,
 	.remove = s3c2443_ac97_remove,
 	.playback = {
@@ -378,7 +381,7 @@
 {
 	.name = "pxa2xx-ac97-mic",
 	.id = 1,
-	.type = SND_SOC_DAI_AC97,
+	.ac97_control = 1,
 	.capture = {
 		.stream_name = "AC97 Mic Capture",
 		.channels_min = 1,
@@ -393,6 +396,21 @@
 EXPORT_SYMBOL_GPL(s3c2443_ac97_dai);
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
+static int __init s3c2443_ac97_init(void)
+{
+	return snd_soc_register_dais(s3c2443_ac97_dai,
+				     ARRAY_SIZE(s3c2443_ac97_dai));
+}
+module_init(s3c2443_ac97_init);
+
+static void __exit s3c2443_ac97_exit(void)
+{
+	snd_soc_unregister_dais(s3c2443_ac97_dai,
+				ARRAY_SIZE(s3c2443_ac97_dai));
+}
+module_exit(s3c2443_ac97_exit);
+
+
 MODULE_AUTHOR("Graeme Gregory");
 MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index ba4476b..6f4d439 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -243,7 +243,8 @@
 }
 
 static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	u32 iismod;
@@ -261,10 +262,17 @@
 
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S8:
+		iismod &= ~S3C2410_IISMOD_16BIT;
+		((struct s3c24xx_pcm_dma_params *)
+		  rtd->dai->cpu_dai->dma_data)->dma_size = 1;
 		break;
 	case SNDRV_PCM_FORMAT_S16_LE:
 		iismod |= S3C2410_IISMOD_16BIT;
+		((struct s3c24xx_pcm_dma_params *)
+		  rtd->dai->cpu_dai->dma_data)->dma_size = 2;
 		break;
+	default:
+		return -EINVAL;
 	}
 
 	writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -272,7 +280,8 @@
 	return 0;
 }
 
-static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
 {
 	int ret = 0;
 
@@ -410,8 +419,7 @@
 }
 
 #ifdef CONFIG_PM
-static int s3c24xx_i2s_suspend(struct platform_device *pdev,
-		struct snd_soc_dai *cpu_dai)
+static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
 {
 	DBG("Entered %s\n", __func__);
 
@@ -425,8 +433,7 @@
 	return 0;
 }
 
-static int s3c24xx_i2s_resume(struct platform_device *pdev,
-		struct snd_soc_dai *cpu_dai)
+static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
 {
 	DBG("Entered %s\n", __func__);
 	clk_enable(s3c24xx_i2s.iis_clk);
@@ -452,7 +459,6 @@
 struct snd_soc_dai s3c24xx_i2s_dai = {
 	.name = "s3c24xx-i2s",
 	.id = 0,
-	.type = SND_SOC_DAI_I2S,
 	.probe = s3c24xx_i2s_probe,
 	.suspend = s3c24xx_i2s_suspend,
 	.resume = s3c24xx_i2s_resume,
@@ -468,8 +474,7 @@
 		.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
 	.ops = {
 		.trigger = s3c24xx_i2s_trigger,
-		.hw_params = s3c24xx_i2s_hw_params,},
-	.dai_ops = {
+		.hw_params = s3c24xx_i2s_hw_params,
 		.set_fmt = s3c24xx_i2s_set_fmt,
 		.set_clkdiv = s3c24xx_i2s_set_clkdiv,
 		.set_sysclk = s3c24xx_i2s_set_sysclk,
@@ -477,6 +482,18 @@
 };
 EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai);
 
+static int __init s3c24xx_i2s_init(void)
+{
+	return snd_soc_register_dai(&s3c24xx_i2s_dai);
+}
+module_init(s3c24xx_i2s_init);
+
+static void __exit s3c24xx_i2s_exit(void)
+{
+	snd_soc_unregister_dai(&s3c24xx_i2s_dai);
+}
+module_exit(s3c24xx_i2s_exit);
+
 /* Module information */
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c
index e13e614..7c64d31 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.c
+++ b/sound/soc/s3c24xx/s3c24xx-pcm.c
@@ -465,6 +465,18 @@
 };
 EXPORT_SYMBOL_GPL(s3c24xx_soc_platform);
 
+static int __init s3c24xx_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&s3c24xx_soc_platform);
+}
+module_init(s3c24xx_soc_platform_init);
+
+static void __exit s3c24xx_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&s3c24xx_soc_platform);
+}
+module_exit(s3c24xx_soc_platform_exit);
+
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("Samsung S3C24XX PCM DMA module");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
new file mode 100644
index 0000000..a0a4d18
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c
@@ -0,0 +1,373 @@
+/*
+ * Modifications by Christian Pellegrin <chripell@evolware.org>
+ *
+ * s3c24xx_uda134x.c  --  S3C24XX_UDA134X ALSA SoC Audio board driver
+ *
+ * Copyright 2007 Dension Audio Systems Ltd.
+ * Author: Zoltan Devai
+ *
+ * This program is free software; you can 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/clk.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/s3c24xx_uda134x.h>
+#include <sound/uda134x.h>
+
+#include <asm/plat-s3c24xx/regs-iis.h>
+
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda134x.h"
+
+
+/* #define ENFORCE_RATES 1 */
+/*
+  Unfortunately the S3C24XX in master mode has a limited capacity of
+  generating the clock for the codec. If you define this only rates
+  that are really available will be enforced. But be careful, most
+  user level application just want the usual sampling frequencies (8,
+  11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
+  operation for embedded systems. So if you aren't very lucky or your
+  hardware engineer wasn't very forward-looking it's better to leave
+  this undefined. If you do so an approximate value for the requested
+  sampling rate in the range -/+ 5% will be chosen. If this in not
+  possible an error will be returned.
+*/
+
+static struct clk *xtal;
+static struct clk *pclk;
+/* this is need because we don't have a place where to keep the
+ * pointers to the clocks in each substream. We get the clocks only
+ * when we are actually using them so we don't block stuff like
+ * frequency change or oscillator power-off */
+static int clk_users;
+static DEFINE_MUTEX(clk_lock);
+
+static unsigned int rates[33 * 2];
+#ifdef ENFORCE_RATES
+static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+	.count	= ARRAY_SIZE(rates),
+	.list	= rates,
+	.mask	= 0,
+};
+#endif
+
+static struct platform_device *s3c24xx_uda134x_snd_device;
+
+static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+#ifdef ENFORCE_RATES
+	struct snd_pcm_runtime *runtime = substream->runtime;;
+#endif
+
+	mutex_lock(&clk_lock);
+	pr_debug("%s %d\n", __func__, clk_users);
+	if (clk_users == 0) {
+		xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal");
+		if (!xtal) {
+			printk(KERN_ERR "%s cannot get xtal\n", __func__);
+			ret = -EBUSY;
+		} else {
+			pclk = clk_get(&s3c24xx_uda134x_snd_device->dev,
+				       "pclk");
+			if (!pclk) {
+				printk(KERN_ERR "%s cannot get pclk\n",
+				       __func__);
+				clk_put(xtal);
+				ret = -EBUSY;
+			}
+		}
+		if (!ret) {
+			int i, j;
+
+			for (i = 0; i < 2; i++) {
+				int fs = i ? 256 : 384;
+
+				rates[i*33] = clk_get_rate(xtal) / fs;
+				for (j = 1; j < 33; j++)
+					rates[i*33 + j] = clk_get_rate(pclk) /
+						(j * fs);
+			}
+		}
+	}
+	clk_users += 1;
+	mutex_unlock(&clk_lock);
+	if (!ret) {
+#ifdef ENFORCE_RATES
+		ret = snd_pcm_hw_constraint_list(runtime, 0,
+						 SNDRV_PCM_HW_PARAM_RATE,
+						 &hw_constraints_rates);
+		if (ret < 0)
+			printk(KERN_ERR "%s cannot set constraints\n",
+			       __func__);
+#endif
+	}
+	return ret;
+}
+
+static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
+{
+	mutex_lock(&clk_lock);
+	pr_debug("%s %d\n", __func__, clk_users);
+	clk_users -= 1;
+	if (clk_users == 0) {
+		clk_put(xtal);
+		xtal = NULL;
+		clk_put(pclk);
+		pclk = NULL;
+	}
+	mutex_unlock(&clk_lock);
+}
+
+static int s3c24xx_uda134x_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 = 0;
+	int clk_source, fs_mode;
+	unsigned long rate = params_rate(params);
+	long err, cerr;
+	unsigned int div;
+	int i, bi;
+
+	err = 999999;
+	bi = 0;
+	for (i = 0; i < 2*33; i++) {
+		cerr = rates[i] - rate;
+		if (cerr < 0)
+			cerr = -cerr;
+		if (cerr < err) {
+			err = cerr;
+			bi = i;
+		}
+	}
+	if (bi / 33 == 1)
+		fs_mode = S3C2410_IISMOD_256FS;
+	else
+		fs_mode = S3C2410_IISMOD_384FS;
+	if (bi % 33 == 0) {
+		clk_source = S3C24XX_CLKSRC_MPLL;
+		div = 1;
+	} else {
+		clk_source = S3C24XX_CLKSRC_PCLK;
+		div = bi % 33;
+	}
+	pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi);
+
+	clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
+	pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__,
+		 fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
+		 clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
+		 div, clk, err);
+
+	if ((err * 100 / rate) > 5) {
+		printk(KERN_ERR "S3C24XX_UDA134X: effective frequency "
+		       "too different from desired (%ld%%)\n",
+		       err * 100 / rate);
+		return -EINVAL;
+	}
+
+	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;
+
+	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(cpu_dai, clk_source , clk,
+			SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+			S3C2410_IISMOD_32FS);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+			S3C24XX_PRESCALE(div, div));
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
+			SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops s3c24xx_uda134x_ops = {
+	.startup = s3c24xx_uda134x_startup,
+	.shutdown = s3c24xx_uda134x_shutdown,
+	.hw_params = s3c24xx_uda134x_hw_params,
+};
+
+static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
+	.name = "UDA134X",
+	.stream_name = "UDA134X",
+	.codec_dai = &uda134x_dai,
+	.cpu_dai = &s3c24xx_i2s_dai,
+	.ops = &s3c24xx_uda134x_ops,
+};
+
+static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
+	.name = "S3C24XX_UDA134X",
+	.platform = &s3c24xx_soc_platform,
+	.dai_link = &s3c24xx_uda134x_dai_link,
+	.num_links = 1,
+};
+
+static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins;
+
+static void setdat(int v)
+{
+	gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0);
+}
+
+static void setclk(int v)
+{
+	gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0);
+}
+
+static void setmode(int v)
+{
+	gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
+}
+
+static struct uda134x_platform_data s3c24xx_uda134x = {
+	.l3 = {
+		.setdat = setdat,
+		.setclk = setclk,
+		.setmode = setmode,
+		.data_hold = 1,
+		.data_setup = 1,
+		.clock_high = 1,
+		.mode_hold = 1,
+		.mode = 1,
+		.mode_setup = 1,
+	},
+};
+
+static struct snd_soc_device s3c24xx_uda134x_snd_devdata = {
+	.card = &snd_soc_s3c24xx_uda134x,
+	.codec_dev = &soc_codec_dev_uda134x,
+	.codec_data = &s3c24xx_uda134x,
+};
+
+static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
+{
+	if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
+		printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
+		       "l3 %s pin already in use", fun);
+		return -EBUSY;
+	}
+	gpio_direction_output(pin, 0);
+	return 0;
+}
+
+static int s3c24xx_uda134x_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n");
+
+	s3c24xx_uda134x_l3_pins = pdev->dev.platform_data;
+	if (s3c24xx_uda134x_l3_pins == NULL) {
+		printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
+		       "unable to find platform data\n");
+		return -ENODEV;
+	}
+	s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power;
+	s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model;
+
+	if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data,
+				      "data") < 0)
+		return -EBUSY;
+	if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,
+				      "clk") < 0) {
+		gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
+		return -EBUSY;
+	}
+	if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode,
+				      "mode") < 0) {
+		gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
+		gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
+		return -EBUSY;
+	}
+
+	s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!s3c24xx_uda134x_snd_device) {
+		printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
+		       "Unable to register\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(s3c24xx_uda134x_snd_device,
+			     &s3c24xx_uda134x_snd_devdata);
+	s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev;
+	ret = platform_device_add(s3c24xx_uda134x_snd_device);
+	if (ret) {
+		printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
+		platform_device_put(s3c24xx_uda134x_snd_device);
+	}
+
+	return ret;
+}
+
+static int s3c24xx_uda134x_remove(struct platform_device *pdev)
+{
+	platform_device_unregister(s3c24xx_uda134x_snd_device);
+	gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
+	gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
+	gpio_free(s3c24xx_uda134x_l3_pins->l3_mode);
+	return 0;
+}
+
+static struct platform_driver s3c24xx_uda134x_driver = {
+	.probe  = s3c24xx_uda134x_probe,
+	.remove = s3c24xx_uda134x_remove,
+	.driver = {
+		.name = "s3c24xx_uda134x",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init s3c24xx_uda134x_init(void)
+{
+	return platform_driver_register(&s3c24xx_uda134x_driver);
+}
+
+static void __exit s3c24xx_uda134x_exit(void)
+{
+	platform_driver_unregister(&s3c24xx_uda134x_driver);
+}
+
+
+module_init(s3c24xx_uda134x_init);
+module_exit(s3c24xx_uda134x_exit);
+
+MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
+MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
index 8515d6f..a2a4f53 100644
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -23,7 +23,7 @@
 #include "s3c24xx-pcm.h"
 #include "s3c24xx-ac97.h"
 
-static struct snd_soc_machine smdk2443;
+static struct snd_soc_card smdk2443;
 
 static struct snd_soc_dai_link smdk2443_dai[] = {
 {
@@ -34,15 +34,15 @@
 },
 };
 
-static struct snd_soc_machine smdk2443 = {
+static struct snd_soc_card smdk2443 = {
 	.name = "SMDK2443",
+	.platform = &s3c24xx_soc_platform,
 	.dai_link = smdk2443_dai,
 	.num_links = ARRAY_SIZE(smdk2443_dai),
 };
 
 static struct snd_soc_device smdk2443_snd_ac97_devdata = {
-	.machine = &smdk2443,
-	.platform = &s3c24xx_soc_platform,
+	.card = &smdk2443,
 	.codec_dev = &soc_codec_dev_ac97,
 };
 
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index 9faa126..0dad3a0 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -348,6 +348,18 @@
 };
 EXPORT_SYMBOL_GPL(sh7760_soc_platform);
 
+static int __init sh7760_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&sh7760_soc_platform);
+}
+module_init(sh7760_soc_platform_init);
+
+static void __exit sh7760_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&sh7760_soc_platform);
+}
+module_exit(sh7760_soc_platform_exit);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index df7bc34..eab3183 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -236,7 +236,8 @@
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static int hac_hw_params(struct snd_pcm_substream *substream,
-			 struct snd_pcm_hw_params *params)
+			 struct snd_pcm_hw_params *params,
+			 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id];
@@ -270,7 +271,7 @@
 {
 	.name			= "HAC0",
 	.id			= 0,
-	.type			= SND_SOC_DAI_AC97,
+	.ac97_control		= 1,
 	.playback = {
 		.rates		= AC97_RATES,
 		.formats	= AC97_FMTS,
@@ -290,8 +291,8 @@
 #ifdef CONFIG_CPU_SUBTYPE_SH7760
 {
 	.name			= "HAC1",
+	.ac97_control		= 1,
 	.id			= 1,
-	.type			= SND_SOC_DAI_AC97,
 	.playback = {
 		.rates		= AC97_RATES,
 		.formats	= AC97_FMTS,
@@ -313,6 +314,18 @@
 };
 EXPORT_SYMBOL_GPL(sh4_hac_dai);
 
+static int __init sh4_hac_init(void)
+{
+	return snd_soc_register_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
+}
+module_init(sh4_hac_init);
+
+static void __exit sh4_hac_exit(void)
+{
+	snd_soc_unregister_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
+}
+module_exit(sh4_hac_exit);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
index 92bfaf4..ce7f95b 100644
--- a/sound/soc/sh/sh7760-ac97.c
+++ b/sound/soc/sh/sh7760-ac97.c
@@ -38,15 +38,15 @@
 	.ops = NULL,
 };
 
-static struct snd_soc_machine sh7760_ac97_soc_machine  = {
+static struct snd_soc_card sh7760_ac97_soc_machine  = {
 	.name = "SH7760 AC97",
+	.platform = &sh7760_soc_platform,
 	.dai_link = &sh7760_ac97_dai,
 	.num_links = 1,
 };
 
 static struct snd_soc_device sh7760_ac97_snd_devdata = {
-	.machine = &sh7760_ac97_soc_machine,
-	.platform = &sh7760_soc_platform,
+	.card = &sh7760_ac97_soc_machine,
 	.codec_dev = &soc_codec_dev_ac97,
 };
 
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
index 55c3464..d1e5390 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/sh/ssi.c
@@ -89,7 +89,8 @@
  * track usage of the SSI; it is simplex-only so prevent attempts of
  * concurrent playback + capture. FIXME: any locking required?
  */
-static int ssi_startup(struct snd_pcm_substream *substream)
+static int ssi_startup(struct snd_pcm_substream *substream,
+		       struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
@@ -101,7 +102,8 @@
 	return 0;
 }
 
-static void ssi_shutdown(struct snd_pcm_substream *substream)
+static void ssi_shutdown(struct snd_pcm_substream *substream,
+			 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
@@ -109,7 +111,8 @@
 	ssi->inuse = 0;
 }
 
-static int ssi_trigger(struct snd_pcm_substream *substream, int cmd)
+static int ssi_trigger(struct snd_pcm_substream *substream, int cmd,
+		       struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
@@ -129,7 +132,8 @@
 }
 
 static int ssi_hw_params(struct snd_pcm_substream *substream,
-			 struct snd_pcm_hw_params *params)
+			 struct snd_pcm_hw_params *params,
+			 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
@@ -336,7 +340,6 @@
 {
 	.name			= "SSI0",
 	.id			= 0,
-	.type			= SND_SOC_DAI_I2S,
 	.playback = {
 		.rates		= SSI_RATES,
 		.formats	= SSI_FMTS,
@@ -354,8 +357,6 @@
 		.shutdown	= ssi_shutdown,
 		.trigger	= ssi_trigger,
 		.hw_params	= ssi_hw_params,
-	},
-	.dai_ops = {
 		.set_sysclk	= ssi_set_sysclk,
 		.set_clkdiv	= ssi_set_clkdiv,
 		.set_fmt	= ssi_set_fmt,
@@ -365,7 +366,6 @@
 {
 	.name			= "SSI1",
 	.id			= 1,
-	.type			= SND_SOC_DAI_I2S,
 	.playback = {
 		.rates		= SSI_RATES,
 		.formats	= SSI_FMTS,
@@ -383,8 +383,6 @@
 		.shutdown	= ssi_shutdown,
 		.trigger	= ssi_trigger,
 		.hw_params	= ssi_hw_params,
-	},
-	.dai_ops = {
 		.set_sysclk	= ssi_set_sysclk,
 		.set_clkdiv	= ssi_set_clkdiv,
 		.set_fmt	= ssi_set_fmt,
@@ -394,6 +392,18 @@
 };
 EXPORT_SYMBOL_GPL(sh4_ssi_dai);
 
+static int __init sh4_ssi_init(void)
+{
+	return snd_soc_register_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
+}
+module_init(sh4_ssi_init);
+
+static void __exit sh4_ssi_exit(void)
+{
+	snd_soc_unregister_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
+}
+module_exit(sh4_ssi_exit);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 16c7453..b098c0b 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/bitops.h>
+#include <linux/debugfs.h>
 #include <linux/platform_device.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -34,18 +35,23 @@
 #include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
-/* debug */
-#define SOC_DEBUG 0
-#if SOC_DEBUG
-#define dbg(format, arg...) printk(format, ## arg)
-#else
-#define dbg(format, arg...)
-#endif
-
 static DEFINE_MUTEX(pcm_mutex);
 static DEFINE_MUTEX(io_mutex);
 static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
 
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_root;
+#endif
+
+static DEFINE_MUTEX(client_mutex);
+static LIST_HEAD(card_list);
+static LIST_HEAD(dai_list);
+static LIST_HEAD(platform_list);
+static LIST_HEAD(codec_list);
+
+static int snd_soc_register_card(struct snd_soc_card *card);
+static int snd_soc_unregister_card(struct snd_soc_card *card);
+
 /*
  * This is a timeout to do a DAPM powerdown after a stream is closed().
  * It can be used to eliminate pops between different playback streams, e.g.
@@ -107,20 +113,6 @@
 }
 #endif
 
-static inline const char *get_dai_name(int type)
-{
-	switch (type) {
-	case SND_SOC_DAI_AC97_BUS:
-	case SND_SOC_DAI_AC97:
-		return "AC97";
-	case SND_SOC_DAI_I2S:
-		return "I2S";
-	case SND_SOC_DAI_PCM:
-		return "PCM";
-	}
-	return NULL;
-}
-
 /*
  * 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
@@ -130,9 +122,10 @@
 {
 	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_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_dai_link *machine = rtd->dai;
-	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_platform *platform = card->platform;
 	struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 	struct snd_soc_dai *codec_dai = machine->codec_dai;
 	int ret = 0;
@@ -141,7 +134,7 @@
 
 	/* startup the audio subsystem */
 	if (cpu_dai->ops.startup) {
-		ret = cpu_dai->ops.startup(substream);
+		ret = cpu_dai->ops.startup(substream, cpu_dai);
 		if (ret < 0) {
 			printk(KERN_ERR "asoc: can't open interface %s\n",
 				cpu_dai->name);
@@ -158,7 +151,7 @@
 	}
 
 	if (codec_dai->ops.startup) {
-		ret = codec_dai->ops.startup(substream);
+		ret = codec_dai->ops.startup(substream, codec_dai);
 		if (ret < 0) {
 			printk(KERN_ERR "asoc: can't open codec %s\n",
 				codec_dai->name);
@@ -228,12 +221,12 @@
 		goto machine_err;
 	}
 
-	dbg("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
-	dbg("asoc: rate mask 0x%x\n", runtime->hw.rates);
-	dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
-		runtime->hw.channels_max);
-	dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
-		runtime->hw.rate_max);
+	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,
+		 runtime->hw.channels_max);
+	pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
+		 runtime->hw.rate_max);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		cpu_dai->playback.active = codec_dai->playback.active = 1;
@@ -255,7 +248,7 @@
 
 platform_err:
 	if (cpu_dai->ops.shutdown)
-		cpu_dai->ops.shutdown(substream);
+		cpu_dai->ops.shutdown(substream, cpu_dai);
 out:
 	mutex_unlock(&pcm_mutex);
 	return ret;
@@ -268,8 +261,9 @@
  */
 static void close_delayed_work(struct work_struct *work)
 {
-	struct snd_soc_device *socdev =
-		container_of(work, struct snd_soc_device, delayed_work.work);
+	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 = socdev->codec;
 	struct snd_soc_dai *codec_dai;
 	int i;
@@ -278,18 +272,18 @@
 	for (i = 0; i < codec->num_dai; i++) {
 		codec_dai = &codec->dai[i];
 
-		dbg("pop wq checking: %s status: %s waiting: %s\n",
-			codec_dai->playback.stream_name,
-			codec_dai->playback.active ? "active" : "inactive",
-			codec_dai->pop_wait ? "yes" : "no");
+		pr_debug("pop wq checking: %s status: %s waiting: %s\n",
+			 codec_dai->playback.stream_name,
+			 codec_dai->playback.active ? "active" : "inactive",
+			 codec_dai->pop_wait ? "yes" : "no");
 
 		/* are we waiting on this codec DAI stream */
 		if (codec_dai->pop_wait == 1) {
 
 			/* Reduce power if no longer active */
 			if (codec->active == 0) {
-				dbg("pop wq D1 %s %s\n", codec->name,
-					codec_dai->playback.stream_name);
+				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);
 			}
@@ -301,8 +295,8 @@
 
 			/* Fall into standby if no longer active */
 			if (codec->active == 0) {
-				dbg("pop wq D3 %s %s\n", codec->name,
-					codec_dai->playback.stream_name);
+				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);
 			}
@@ -320,8 +314,9 @@
 {
 	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_platform *platform = socdev->platform;
+	struct snd_soc_platform *platform = card->platform;
 	struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 	struct snd_soc_dai *codec_dai = machine->codec_dai;
 	struct snd_soc_codec *codec = socdev->codec;
@@ -346,10 +341,10 @@
 		snd_soc_dai_digital_mute(codec_dai, 1);
 
 	if (cpu_dai->ops.shutdown)
-		cpu_dai->ops.shutdown(substream);
+		cpu_dai->ops.shutdown(substream, cpu_dai);
 
 	if (codec_dai->ops.shutdown)
-		codec_dai->ops.shutdown(substream);
+		codec_dai->ops.shutdown(substream, codec_dai);
 
 	if (machine->ops && machine->ops->shutdown)
 		machine->ops->shutdown(substream);
@@ -361,7 +356,7 @@
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		/* start delayed pop wq here for playback streams */
 		codec_dai->pop_wait = 1;
-		schedule_delayed_work(&socdev->delayed_work,
+		schedule_delayed_work(&card->delayed_work,
 			msecs_to_jiffies(pmdown_time));
 	} else {
 		/* capture streams can be powered down now */
@@ -387,8 +382,9 @@
 {
 	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_platform *platform = socdev->platform;
+	struct snd_soc_platform *platform = card->platform;
 	struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 	struct snd_soc_dai *codec_dai = machine->codec_dai;
 	struct snd_soc_codec *codec = socdev->codec;
@@ -413,7 +409,7 @@
 	}
 
 	if (codec_dai->ops.prepare) {
-		ret = codec_dai->ops.prepare(substream);
+		ret = codec_dai->ops.prepare(substream, codec_dai);
 		if (ret < 0) {
 			printk(KERN_ERR "asoc: codec DAI prepare error\n");
 			goto out;
@@ -421,58 +417,49 @@
 	}
 
 	if (cpu_dai->ops.prepare) {
-		ret = cpu_dai->ops.prepare(substream);
+		ret = cpu_dai->ops.prepare(substream, cpu_dai);
 		if (ret < 0) {
 			printk(KERN_ERR "asoc: cpu DAI prepare error\n");
 			goto out;
 		}
 	}
 
-	/* we only want to start a DAPM playback stream if we are not waiting
-	 * on an existing one stopping */
-	if (codec_dai->pop_wait) {
-		/* we are waiting for the delayed work to start */
-		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-				snd_soc_dapm_stream_event(socdev->codec,
+	/* cancel any delayed stream shutdown that is pending */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+	    codec_dai->pop_wait) {
+		codec_dai->pop_wait = 0;
+		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);
-		else {
-			codec_dai->pop_wait = 0;
-			cancel_delayed_work(&socdev->delayed_work);
-			snd_soc_dai_digital_mute(codec_dai, 0);
-		}
+
+		snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON);
+		snd_soc_dai_digital_mute(codec_dai, 0);
+
 	} else {
-		/* no 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 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,
+		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:
@@ -491,7 +478,8 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_dai_link *machine = rtd->dai;
-	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_card *card = socdev->card;
+	struct snd_soc_platform *platform = card->platform;
 	struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 	struct snd_soc_dai *codec_dai = machine->codec_dai;
 	int ret = 0;
@@ -507,7 +495,7 @@
 	}
 
 	if (codec_dai->ops.hw_params) {
-		ret = codec_dai->ops.hw_params(substream, params);
+		ret = codec_dai->ops.hw_params(substream, params, codec_dai);
 		if (ret < 0) {
 			printk(KERN_ERR "asoc: can't set codec %s hw params\n",
 				codec_dai->name);
@@ -516,7 +504,7 @@
 	}
 
 	if (cpu_dai->ops.hw_params) {
-		ret = cpu_dai->ops.hw_params(substream, params);
+		ret = cpu_dai->ops.hw_params(substream, params, cpu_dai);
 		if (ret < 0) {
 			printk(KERN_ERR "asoc: interface %s hw params failed\n",
 				cpu_dai->name);
@@ -539,11 +527,11 @@
 
 platform_err:
 	if (cpu_dai->ops.hw_free)
-		cpu_dai->ops.hw_free(substream);
+		cpu_dai->ops.hw_free(substream, cpu_dai);
 
 interface_err:
 	if (codec_dai->ops.hw_free)
-		codec_dai->ops.hw_free(substream);
+		codec_dai->ops.hw_free(substream, codec_dai);
 
 codec_err:
 	if (machine->ops && machine->ops->hw_free)
@@ -561,7 +549,8 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_dai_link *machine = rtd->dai;
-	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_card *card = socdev->card;
+	struct snd_soc_platform *platform = card->platform;
 	struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 	struct snd_soc_dai *codec_dai = machine->codec_dai;
 	struct snd_soc_codec *codec = socdev->codec;
@@ -582,10 +571,10 @@
 
 	/* now free hw params for the DAI's  */
 	if (codec_dai->ops.hw_free)
-		codec_dai->ops.hw_free(substream);
+		codec_dai->ops.hw_free(substream, codec_dai);
 
 	if (cpu_dai->ops.hw_free)
-		cpu_dai->ops.hw_free(substream);
+		cpu_dai->ops.hw_free(substream, cpu_dai);
 
 	mutex_unlock(&pcm_mutex);
 	return 0;
@@ -595,14 +584,15 @@
 {
 	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_platform *platform = socdev->platform;
+	struct snd_soc_platform *platform = card->platform;
 	struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 	struct snd_soc_dai *codec_dai = machine->codec_dai;
 	int ret;
 
 	if (codec_dai->ops.trigger) {
-		ret = codec_dai->ops.trigger(substream, cmd);
+		ret = codec_dai->ops.trigger(substream, cmd, codec_dai);
 		if (ret < 0)
 			return ret;
 	}
@@ -614,7 +604,7 @@
 	}
 
 	if (cpu_dai->ops.trigger) {
-		ret = cpu_dai->ops.trigger(substream, cmd);
+		ret = cpu_dai->ops.trigger(substream, cmd, cpu_dai);
 		if (ret < 0)
 			return ret;
 	}
@@ -636,8 +626,8 @@
 static int soc_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_machine *machine = socdev->machine;
-	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_card *card = socdev->card;
+	struct snd_soc_platform *platform = card->platform;
 	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
 	struct snd_soc_codec *codec = socdev->codec;
 	int i;
@@ -653,29 +643,29 @@
 	snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot);
 
 	/* mute any active DAC's */
-	for (i = 0; i < machine->num_links; i++) {
-		struct snd_soc_dai *dai = machine->dai_link[i].codec_dai;
-		if (dai->dai_ops.digital_mute && dai->playback.active)
-			dai->dai_ops.digital_mute(dai, 1);
+	for (i = 0; i < card->num_links; i++) {
+		struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
+		if (dai->ops.digital_mute && dai->playback.active)
+			dai->ops.digital_mute(dai, 1);
 	}
 
 	/* suspend all pcms */
-	for (i = 0; i < machine->num_links; i++)
-		snd_pcm_suspend_all(machine->dai_link[i].pcm);
+	for (i = 0; i < card->num_links; i++)
+		snd_pcm_suspend_all(card->dai_link[i].pcm);
 
-	if (machine->suspend_pre)
-		machine->suspend_pre(pdev, state);
+	if (card->suspend_pre)
+		card->suspend_pre(pdev, state);
 
-	for (i = 0; i < machine->num_links; i++) {
-		struct snd_soc_dai  *cpu_dai = machine->dai_link[i].cpu_dai;
-		if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97)
-			cpu_dai->suspend(pdev, cpu_dai);
+	for (i = 0; i < card->num_links; i++) {
+		struct snd_soc_dai  *cpu_dai = card->dai_link[i].cpu_dai;
+		if (cpu_dai->suspend && !cpu_dai->ac97_control)
+			cpu_dai->suspend(cpu_dai);
 		if (platform->suspend)
-			platform->suspend(pdev, cpu_dai);
+			platform->suspend(cpu_dai);
 	}
 
 	/* close any waiting streams and save state */
-	run_delayed_work(&socdev->delayed_work);
+	run_delayed_work(&card->delayed_work);
 	codec->suspend_bias_level = codec->bias_level;
 
 	for (i = 0; i < codec->num_dai; i++) {
@@ -692,14 +682,14 @@
 	if (codec_dev->suspend)
 		codec_dev->suspend(pdev, state);
 
-	for (i = 0; i < machine->num_links; i++) {
-		struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
-		if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97)
-			cpu_dai->suspend(pdev, cpu_dai);
+	for (i = 0; i < card->num_links; i++) {
+		struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+		if (cpu_dai->suspend && cpu_dai->ac97_control)
+			cpu_dai->suspend(cpu_dai);
 	}
 
-	if (machine->suspend_post)
-		machine->suspend_post(pdev, state);
+	if (card->suspend_post)
+		card->suspend_post(pdev, state);
 
 	return 0;
 }
@@ -709,11 +699,11 @@
  */
 static void soc_resume_deferred(struct work_struct *work)
 {
-	struct snd_soc_device *socdev = container_of(work,
-						     struct snd_soc_device,
-						     deferred_resume_work);
-	struct snd_soc_machine *machine = socdev->machine;
-	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_card *card = container_of(work,
+						 struct snd_soc_card,
+						 deferred_resume_work);
+	struct snd_soc_device *socdev = card->socdev;
+	struct snd_soc_platform *platform = card->platform;
 	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
 	struct snd_soc_codec *codec = socdev->codec;
 	struct platform_device *pdev = to_platform_device(socdev->dev);
@@ -723,15 +713,15 @@
 	 * so userspace apps are blocked from touching us
 	 */
 
-	dev_info(socdev->dev, "starting resume work\n");
+	dev_dbg(socdev->dev, "starting resume work\n");
 
-	if (machine->resume_pre)
-		machine->resume_pre(pdev);
+	if (card->resume_pre)
+		card->resume_pre(pdev);
 
-	for (i = 0; i < machine->num_links; i++) {
-		struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
-		if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97)
-			cpu_dai->resume(pdev, cpu_dai);
+	for (i = 0; i < card->num_links; i++) {
+		struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+		if (cpu_dai->resume && cpu_dai->ac97_control)
+			cpu_dai->resume(cpu_dai);
 	}
 
 	if (codec_dev->resume)
@@ -749,24 +739,24 @@
 	}
 
 	/* unmute any active DACs */
-	for (i = 0; i < machine->num_links; i++) {
-		struct snd_soc_dai *dai = machine->dai_link[i].codec_dai;
-		if (dai->dai_ops.digital_mute && dai->playback.active)
-			dai->dai_ops.digital_mute(dai, 0);
+	for (i = 0; i < card->num_links; i++) {
+		struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
+		if (dai->ops.digital_mute && dai->playback.active)
+			dai->ops.digital_mute(dai, 0);
 	}
 
-	for (i = 0; i < machine->num_links; i++) {
-		struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
-		if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97)
-			cpu_dai->resume(pdev, cpu_dai);
+	for (i = 0; i < card->num_links; i++) {
+		struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+		if (cpu_dai->resume && !cpu_dai->ac97_control)
+			cpu_dai->resume(cpu_dai);
 		if (platform->resume)
-			platform->resume(pdev, cpu_dai);
+			platform->resume(cpu_dai);
 	}
 
-	if (machine->resume_post)
-		machine->resume_post(pdev);
+	if (card->resume_post)
+		card->resume_post(pdev);
 
-	dev_info(socdev->dev, "resume work completed\n");
+	dev_dbg(socdev->dev, "resume work completed\n");
 
 	/* userspace can access us now we are back as we were before */
 	snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0);
@@ -776,11 +766,12 @@
 static int soc_resume(struct platform_device *pdev)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_card *card = socdev->card;
 
-	dev_info(socdev->dev, "scheduling resume work\n");
+	dev_dbg(socdev->dev, "scheduling resume work\n");
 
-	if (!schedule_work(&socdev->deferred_resume_work))
-		dev_err(socdev->dev, "work item may be lost\n");
+	if (!schedule_work(&card->deferred_resume_work))
+		dev_err(socdev->dev, "resume work item may be lost\n");
 
 	return 0;
 }
@@ -790,23 +781,83 @@
 #define soc_resume	NULL
 #endif
 
-/* probes a new socdev */
-static int soc_probe(struct platform_device *pdev)
+static void snd_soc_instantiate_card(struct snd_soc_card *card)
 {
-	int ret = 0, i;
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_machine *machine = socdev->machine;
-	struct snd_soc_platform *platform = socdev->platform;
-	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+	struct platform_device *pdev = container_of(card->dev,
+						    struct platform_device,
+						    dev);
+	struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev;
+	struct snd_soc_platform *platform;
+	struct snd_soc_dai *dai;
+	int i, found, ret, ac97;
 
-	if (machine->probe) {
-		ret = machine->probe(pdev);
-		if (ret < 0)
-			return ret;
+	if (card->instantiated)
+		return;
+
+	found = 0;
+	list_for_each_entry(platform, &platform_list, list)
+		if (card->platform == platform) {
+			found = 1;
+			break;
+		}
+	if (!found) {
+		dev_dbg(card->dev, "Platform %s not registered\n",
+			card->platform->name);
+		return;
 	}
 
-	for (i = 0; i < machine->num_links; i++) {
-		struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+	ac97 = 0;
+	for (i = 0; i < card->num_links; i++) {
+		found = 0;
+		list_for_each_entry(dai, &dai_list, list)
+			if (card->dai_link[i].cpu_dai == dai) {
+				found = 1;
+				break;
+			}
+		if (!found) {
+			dev_dbg(card->dev, "DAI %s not registered\n",
+				card->dai_link[i].cpu_dai->name);
+			return;
+		}
+
+		if (card->dai_link[i].cpu_dai->ac97_control)
+			ac97 = 1;
+	}
+
+	/* If we have AC97 in the system then don't wait for the
+	 * codec.  This will need revisiting if we have to handle
+	 * systems with mixed AC97 and non-AC97 parts.  Only check for
+	 * DAIs currently; we can't do this per link since some AC97
+	 * codecs have non-AC97 DAIs.
+	 */
+	if (!ac97)
+		for (i = 0; i < card->num_links; i++) {
+			found = 0;
+			list_for_each_entry(dai, &dai_list, list)
+				if (card->dai_link[i].codec_dai == dai) {
+					found = 1;
+					break;
+				}
+			if (!found) {
+				dev_dbg(card->dev, "DAI %s not registered\n",
+					card->dai_link[i].codec_dai->name);
+				return;
+			}
+		}
+
+	/* Note that we do not current check for codec components */
+
+	dev_dbg(card->dev, "All components present, instantiating\n");
+
+	/* Found everything, bring it up */
+	if (card->probe) {
+		ret = card->probe(pdev);
+		if (ret < 0)
+			return;
+	}
+
+	for (i = 0; i < card->num_links; i++) {
+		struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
 		if (cpu_dai->probe) {
 			ret = cpu_dai->probe(pdev, cpu_dai);
 			if (ret < 0)
@@ -827,13 +878,15 @@
 	}
 
 	/* DAPM stream work */
-	INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work);
+	INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work);
 #ifdef CONFIG_PM
 	/* deferred resume work */
-	INIT_WORK(&socdev->deferred_resume_work, soc_resume_deferred);
+	INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
 #endif
 
-	return 0;
+	card->instantiated = 1;
+
+	return;
 
 platform_err:
 	if (codec_dev->remove)
@@ -841,15 +894,45 @@
 
 cpu_dai_err:
 	for (i--; i >= 0; i--) {
-		struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+		struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
 		if (cpu_dai->remove)
 			cpu_dai->remove(pdev, cpu_dai);
 	}
 
-	if (machine->remove)
-		machine->remove(pdev);
+	if (card->remove)
+		card->remove(pdev);
+}
 
-	return ret;
+/*
+ * Attempt to initialise any uninitalised cards.  Must be called with
+ * client_mutex.
+ */
+static void snd_soc_instantiate_cards(void)
+{
+	struct snd_soc_card *card;
+	list_for_each_entry(card, &card_list, list)
+		snd_soc_instantiate_card(card);
+}
+
+/* probes a new socdev */
+static int soc_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_card *card = socdev->card;
+
+	/* Bodge while we push things out of socdev */
+	card->socdev = socdev;
+
+	/* Bodge while we unpick instantiation */
+	card->dev = &pdev->dev;
+	ret = snd_soc_register_card(card);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to register card\n");
+		return ret;
+	}
+
+	return 0;
 }
 
 /* removes a socdev */
@@ -857,11 +940,11 @@
 {
 	int i;
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_machine *machine = socdev->machine;
-	struct snd_soc_platform *platform = socdev->platform;
+	struct snd_soc_card *card = socdev->card;
+	struct snd_soc_platform *platform = card->platform;
 	struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
 
-	run_delayed_work(&socdev->delayed_work);
+	run_delayed_work(&card->delayed_work);
 
 	if (platform->remove)
 		platform->remove(pdev);
@@ -869,14 +952,16 @@
 	if (codec_dev->remove)
 		codec_dev->remove(pdev);
 
-	for (i = 0; i < machine->num_links; i++) {
-		struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+	for (i = 0; i < card->num_links; i++) {
+		struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
 		if (cpu_dai->remove)
 			cpu_dai->remove(pdev, cpu_dai);
 	}
 
-	if (machine->remove)
-		machine->remove(pdev);
+	if (card->remove)
+		card->remove(pdev);
+
+	snd_soc_unregister_card(card);
 
 	return 0;
 }
@@ -898,6 +983,8 @@
 	struct snd_soc_dai_link *dai_link, int num)
 {
 	struct snd_soc_codec *codec = socdev->codec;
+	struct snd_soc_card *card = socdev->card;
+	struct snd_soc_platform *platform = card->platform;
 	struct snd_soc_dai *codec_dai = dai_link->codec_dai;
 	struct snd_soc_dai *cpu_dai = dai_link->cpu_dai;
 	struct snd_soc_pcm_runtime *rtd;
@@ -914,8 +1001,8 @@
 	codec_dai->codec = socdev->codec;
 
 	/* check client and interface hw capabilities */
-	sprintf(new_name, "%s %s-%s-%d", dai_link->stream_name, codec_dai->name,
-		get_dai_name(cpu_dai->type), num);
+	sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name,
+		num);
 
 	if (codec_dai->playback.channels_min)
 		playback = 1;
@@ -933,13 +1020,13 @@
 
 	dai_link->pcm = pcm;
 	pcm->private_data = rtd;
-	soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap;
-	soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer;
-	soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl;
-	soc_pcm_ops.copy = socdev->platform->pcm_ops->copy;
-	soc_pcm_ops.silence = socdev->platform->pcm_ops->silence;
-	soc_pcm_ops.ack = socdev->platform->pcm_ops->ack;
-	soc_pcm_ops.page = socdev->platform->pcm_ops->page;
+	soc_pcm_ops.mmap = platform->pcm_ops->mmap;
+	soc_pcm_ops.pointer = platform->pcm_ops->pointer;
+	soc_pcm_ops.ioctl = platform->pcm_ops->ioctl;
+	soc_pcm_ops.copy = platform->pcm_ops->copy;
+	soc_pcm_ops.silence = platform->pcm_ops->silence;
+	soc_pcm_ops.ack = platform->pcm_ops->ack;
+	soc_pcm_ops.page = platform->pcm_ops->page;
 
 	if (playback)
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
@@ -947,24 +1034,22 @@
 	if (capture)
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
 
-	ret = socdev->platform->pcm_new(codec->card, codec_dai, pcm);
+	ret = platform->pcm_new(codec->card, codec_dai, pcm);
 	if (ret < 0) {
 		printk(KERN_ERR "asoc: platform pcm constructor failed\n");
 		kfree(rtd);
 		return ret;
 	}
 
-	pcm->private_free = socdev->platform->pcm_free;
+	pcm->private_free = platform->pcm_free;
 	printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
 		cpu_dai->name);
 	return ret;
 }
 
 /* codec register dump */
-static ssize_t codec_reg_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
+static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf)
 {
-	struct snd_soc_device *devdata = dev_get_drvdata(dev);
 	struct snd_soc_codec *codec = devdata->codec;
 	int i, step = 1, count = 0;
 
@@ -1001,8 +1086,110 @@
 
 	return count;
 }
+static ssize_t codec_reg_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct snd_soc_device *devdata = dev_get_drvdata(dev);
+	return soc_codec_reg_show(devdata, buf);
+}
+
 static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
 
+#ifdef CONFIG_DEBUG_FS
+static int codec_reg_open_file(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+	struct snd_soc_codec *codec = file->private_data;
+	struct device *card_dev = codec->card->dev;
+	struct snd_soc_device *devdata = card_dev->driver_data;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+	ret = soc_codec_reg_show(devdata, buf);
+	if (ret >= 0)
+		ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t codec_reg_write_file(struct file *file,
+		const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[32];
+	int buf_size;
+	char *start = buf;
+	unsigned long reg, value;
+	int step = 1;
+	struct snd_soc_codec *codec = file->private_data;
+
+	buf_size = min(count, (sizeof(buf)-1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+	buf[buf_size] = 0;
+
+	if (codec->reg_cache_step)
+		step = codec->reg_cache_step;
+
+	while (*start == ' ')
+		start++;
+	reg = simple_strtoul(start, &start, 16);
+	if ((reg >= codec->reg_cache_size) || (reg % step))
+		return -EINVAL;
+	while (*start == ' ')
+		start++;
+	if (strict_strtoul(start, 16, &value))
+		return -EINVAL;
+	codec->write(codec, reg, value);
+	return buf_size;
+}
+
+static const struct file_operations codec_reg_fops = {
+	.open = codec_reg_open_file,
+	.read = codec_reg_read_file,
+	.write = codec_reg_write_file,
+};
+
+static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
+{
+	codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
+						 debugfs_root, codec,
+						 &codec_reg_fops);
+	if (!codec->debugfs_reg)
+		printk(KERN_WARNING
+		       "ASoC: Failed to create codec register debugfs file\n");
+
+	codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744,
+						     debugfs_root,
+						     &codec->pop_time);
+	if (!codec->debugfs_pop_time)
+		printk(KERN_WARNING
+		       "Failed to create pop time debugfs file\n");
+}
+
+static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
+{
+	debugfs_remove(codec->debugfs_pop_time);
+	debugfs_remove(codec->debugfs_reg);
+}
+
+#else
+
+static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
+{
+}
+
+static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
+{
+}
+#endif
+
 /**
  * snd_soc_new_ac97_codec - initailise AC97 device
  * @codec: audio codec
@@ -1121,7 +1308,7 @@
 int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
 {
 	struct snd_soc_codec *codec = socdev->codec;
-	struct snd_soc_machine *machine = socdev->machine;
+	struct snd_soc_card *card = socdev->card;
 	int ret = 0, i;
 
 	mutex_lock(&codec->mutex);
@@ -1140,11 +1327,11 @@
 	strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
 
 	/* create the pcms */
-	for (i = 0; i < machine->num_links; i++) {
-		ret = soc_new_pcm(socdev, &machine->dai_link[i], i);
+	for (i = 0; i < card->num_links; i++) {
+		ret = soc_new_pcm(socdev, &card->dai_link[i], i);
 		if (ret < 0) {
 			printk(KERN_ERR "asoc: can't create pcm %s\n",
-				machine->dai_link[i].stream_name);
+				card->dai_link[i].stream_name);
 			mutex_unlock(&codec->mutex);
 			return ret;
 		}
@@ -1156,7 +1343,7 @@
 EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
 
 /**
- * snd_soc_register_card - register sound card
+ * snd_soc_init_card - register sound card
  * @socdev: the SoC audio device
  *
  * Register a SoC sound card. Also registers an AC97 device if the
@@ -1164,29 +1351,28 @@
  *
  * Returns 0 for success, else error.
  */
-int snd_soc_register_card(struct snd_soc_device *socdev)
+int snd_soc_init_card(struct snd_soc_device *socdev)
 {
 	struct snd_soc_codec *codec = socdev->codec;
-	struct snd_soc_machine *machine = socdev->machine;
+	struct snd_soc_card *card = socdev->card;
 	int ret = 0, i, ac97 = 0, err = 0;
 
-	for (i = 0; i < machine->num_links; i++) {
-		if (socdev->machine->dai_link[i].init) {
-			err = socdev->machine->dai_link[i].init(codec);
+	for (i = 0; i < card->num_links; i++) {
+		if (card->dai_link[i].init) {
+			err = card->dai_link[i].init(codec);
 			if (err < 0) {
 				printk(KERN_ERR "asoc: failed to init %s\n",
-					socdev->machine->dai_link[i].stream_name);
+					card->dai_link[i].stream_name);
 				continue;
 			}
 		}
-		if (socdev->machine->dai_link[i].codec_dai->type ==
-			SND_SOC_DAI_AC97_BUS)
+		if (card->dai_link[i].codec_dai->ac97_control)
 			ac97 = 1;
 	}
 	snprintf(codec->card->shortname, sizeof(codec->card->shortname),
-		 "%s", machine->name);
+		 "%s",  card->name);
 	snprintf(codec->card->longname, sizeof(codec->card->longname),
-		 "%s (%s)", machine->name, codec->name);
+		 "%s (%s)", card->name, codec->name);
 
 	ret = snd_card_register(codec->card);
 	if (ret < 0) {
@@ -1216,12 +1402,13 @@
 	if (err < 0)
 		printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
 
+	soc_init_codec_debugfs(socdev->codec);
 	mutex_unlock(&codec->mutex);
 
 out:
 	return ret;
 }
-EXPORT_SYMBOL_GPL(snd_soc_register_card);
+EXPORT_SYMBOL_GPL(snd_soc_init_card);
 
 /**
  * snd_soc_free_pcms - free sound card and pcms
@@ -1239,10 +1426,11 @@
 #endif
 
 	mutex_lock(&codec->mutex);
+	soc_cleanup_codec_debugfs(socdev->codec);
 #ifdef CONFIG_SND_SOC_AC97_BUS
 	for (i = 0; i < codec->num_dai; i++) {
 		codec_dai = &codec->dai[i];
-		if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) {
+		if (codec_dai->ac97_control && codec->ac97) {
 			soc_ac97_dev_unregister(codec);
 			goto free_card;
 		}
@@ -1756,8 +1944,8 @@
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	unsigned int freq, int dir)
 {
-	if (dai->dai_ops.set_sysclk)
-		return dai->dai_ops.set_sysclk(dai, clk_id, freq, dir);
+	if (dai->ops.set_sysclk)
+		return dai->ops.set_sysclk(dai, clk_id, freq, dir);
 	else
 		return -EINVAL;
 }
@@ -1776,8 +1964,8 @@
 int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
 	int div_id, int div)
 {
-	if (dai->dai_ops.set_clkdiv)
-		return dai->dai_ops.set_clkdiv(dai, div_id, div);
+	if (dai->ops.set_clkdiv)
+		return dai->ops.set_clkdiv(dai, div_id, div);
 	else
 		return -EINVAL;
 }
@@ -1795,8 +1983,8 @@
 int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
 	int pll_id, unsigned int freq_in, unsigned int freq_out)
 {
-	if (dai->dai_ops.set_pll)
-		return dai->dai_ops.set_pll(dai, pll_id, freq_in, freq_out);
+	if (dai->ops.set_pll)
+		return dai->ops.set_pll(dai, pll_id, freq_in, freq_out);
 	else
 		return -EINVAL;
 }
@@ -1805,15 +1993,14 @@
 /**
  * snd_soc_dai_set_fmt - configure DAI hardware audio format.
  * @dai: DAI
- * @clk_id: DAI specific clock ID
  * @fmt: SND_SOC_DAIFMT_ format value.
  *
  * Configures the DAI hardware format and clocking.
  */
 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	if (dai->dai_ops.set_fmt)
-		return dai->dai_ops.set_fmt(dai, fmt);
+	if (dai->ops.set_fmt)
+		return dai->ops.set_fmt(dai, fmt);
 	else
 		return -EINVAL;
 }
@@ -1831,8 +2018,8 @@
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int mask, int slots)
 {
-	if (dai->dai_ops.set_sysclk)
-		return dai->dai_ops.set_tdm_slot(dai, mask, slots);
+	if (dai->ops.set_sysclk)
+		return dai->ops.set_tdm_slot(dai, mask, slots);
 	else
 		return -EINVAL;
 }
@@ -1847,8 +2034,8 @@
  */
 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-	if (dai->dai_ops.set_sysclk)
-		return dai->dai_ops.set_tristate(dai, tristate);
+	if (dai->ops.set_sysclk)
+		return dai->ops.set_tristate(dai, tristate);
 	else
 		return -EINVAL;
 }
@@ -1863,21 +2050,242 @@
  */
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	if (dai->dai_ops.digital_mute)
-		return dai->dai_ops.digital_mute(dai, mute);
+	if (dai->ops.digital_mute)
+		return dai->ops.digital_mute(dai, mute);
 	else
 		return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
 
-static int __devinit snd_soc_init(void)
+/**
+ * snd_soc_register_card - Register a card with the ASoC core
+ *
+ * @param card Card to register
+ *
+ * Note that currently this is an internal only function: it will be
+ * exposed to machine drivers after further backporting of ASoC v2
+ * registration APIs.
+ */
+static int snd_soc_register_card(struct snd_soc_card *card)
 {
-	printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION);
+	if (!card->name || !card->dev)
+		return -EINVAL;
+
+	INIT_LIST_HEAD(&card->list);
+	card->instantiated = 0;
+
+	mutex_lock(&client_mutex);
+	list_add(&card->list, &card_list);
+	snd_soc_instantiate_cards();
+	mutex_unlock(&client_mutex);
+
+	dev_dbg(card->dev, "Registered card '%s'\n", card->name);
+
+	return 0;
+}
+
+/**
+ * snd_soc_unregister_card - Unregister a card with the ASoC core
+ *
+ * @param card Card to unregister
+ *
+ * Note that currently this is an internal only function: it will be
+ * exposed to machine drivers after further backporting of ASoC v2
+ * registration APIs.
+ */
+static int snd_soc_unregister_card(struct snd_soc_card *card)
+{
+	mutex_lock(&client_mutex);
+	list_del(&card->list);
+	mutex_unlock(&client_mutex);
+
+	dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
+
+	return 0;
+}
+
+/**
+ * snd_soc_register_dai - Register a DAI with the ASoC core
+ *
+ * @param dai DAI to register
+ */
+int snd_soc_register_dai(struct snd_soc_dai *dai)
+{
+	if (!dai->name)
+		return -EINVAL;
+
+	/* The device should become mandatory over time */
+	if (!dai->dev)
+		printk(KERN_WARNING "No device for DAI %s\n", dai->name);
+
+	INIT_LIST_HEAD(&dai->list);
+
+	mutex_lock(&client_mutex);
+	list_add(&dai->list, &dai_list);
+	snd_soc_instantiate_cards();
+	mutex_unlock(&client_mutex);
+
+	pr_debug("Registered DAI '%s'\n", dai->name);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_dai);
+
+/**
+ * snd_soc_unregister_dai - Unregister a DAI from the ASoC core
+ *
+ * @param dai DAI to unregister
+ */
+void snd_soc_unregister_dai(struct snd_soc_dai *dai)
+{
+	mutex_lock(&client_mutex);
+	list_del(&dai->list);
+	mutex_unlock(&client_mutex);
+
+	pr_debug("Unregistered DAI '%s'\n", dai->name);
+}
+EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
+
+/**
+ * snd_soc_register_dais - Register multiple DAIs with the ASoC core
+ *
+ * @param dai Array of DAIs to register
+ * @param count Number of DAIs
+ */
+int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count)
+{
+	int i, ret;
+
+	for (i = 0; i < count; i++) {
+		ret = snd_soc_register_dai(&dai[i]);
+		if (ret != 0)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	for (i--; i >= 0; i--)
+		snd_soc_unregister_dai(&dai[i]);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_dais);
+
+/**
+ * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core
+ *
+ * @param dai Array of DAIs to unregister
+ * @param count Number of DAIs
+ */
+void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		snd_soc_unregister_dai(&dai[i]);
+}
+EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
+
+/**
+ * snd_soc_register_platform - Register a platform with the ASoC core
+ *
+ * @param platform platform to register
+ */
+int snd_soc_register_platform(struct snd_soc_platform *platform)
+{
+	if (!platform->name)
+		return -EINVAL;
+
+	INIT_LIST_HEAD(&platform->list);
+
+	mutex_lock(&client_mutex);
+	list_add(&platform->list, &platform_list);
+	snd_soc_instantiate_cards();
+	mutex_unlock(&client_mutex);
+
+	pr_debug("Registered platform '%s'\n", platform->name);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_platform);
+
+/**
+ * snd_soc_unregister_platform - Unregister a platform from the ASoC core
+ *
+ * @param platform platform to unregister
+ */
+void snd_soc_unregister_platform(struct snd_soc_platform *platform)
+{
+	mutex_lock(&client_mutex);
+	list_del(&platform->list);
+	mutex_unlock(&client_mutex);
+
+	pr_debug("Unregistered platform '%s'\n", platform->name);
+}
+EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
+
+/**
+ * snd_soc_register_codec - Register a codec with the ASoC core
+ *
+ * @param codec codec to register
+ */
+int snd_soc_register_codec(struct snd_soc_codec *codec)
+{
+	if (!codec->name)
+		return -EINVAL;
+
+	/* The device should become mandatory over time */
+	if (!codec->dev)
+		printk(KERN_WARNING "No device for codec %s\n", codec->name);
+
+	INIT_LIST_HEAD(&codec->list);
+
+	mutex_lock(&client_mutex);
+	list_add(&codec->list, &codec_list);
+	snd_soc_instantiate_cards();
+	mutex_unlock(&client_mutex);
+
+	pr_debug("Registered codec '%s'\n", codec->name);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_codec);
+
+/**
+ * snd_soc_unregister_codec - Unregister a codec from the ASoC core
+ *
+ * @param codec codec to unregister
+ */
+void snd_soc_unregister_codec(struct snd_soc_codec *codec)
+{
+	mutex_lock(&client_mutex);
+	list_del(&codec->list);
+	mutex_unlock(&client_mutex);
+
+	pr_debug("Unregistered codec '%s'\n", codec->name);
+}
+EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
+
+static int __init snd_soc_init(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	debugfs_root = debugfs_create_dir("asoc", NULL);
+	if (IS_ERR(debugfs_root) || !debugfs_root) {
+		printk(KERN_WARNING
+		       "ASoC: Failed to create debugfs directory\n");
+		debugfs_root = NULL;
+	}
+#endif
+
 	return platform_driver_register(&soc_driver);
 }
 
-static void snd_soc_exit(void)
+static void __exit snd_soc_exit(void)
 {
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove_recursive(debugfs_root);
+#endif
 	platform_driver_unregister(&soc_driver);
 }
 
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7351db9..8863edd 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -37,7 +37,6 @@
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
 #include <linux/jiffies.h>
-#include <linux/debugfs.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -67,17 +66,13 @@
 module_param(dapm_status, int, 0);
 MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
 
-static struct dentry *asoc_debugfs;
-
-static u32 pop_time;
-
-static void pop_wait(void)
+static void pop_wait(u32 pop_time)
 {
 	if (pop_time)
 		schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
 }
 
-static void pop_dbg(const char *fmt, ...)
+static void pop_dbg(u32 pop_time, const char *fmt, ...)
 {
 	va_list args;
 
@@ -85,7 +80,7 @@
 
 	if (pop_time) {
 		vprintk(fmt, args);
-		pop_wait();
+		pop_wait(pop_time);
 	}
 
 	va_end(args);
@@ -230,10 +225,11 @@
 
 	change = old != new;
 	if (change) {
-		pop_dbg("pop test %s : %s in %d ms\n", widget->name,
-			widget->power ? "on" : "off", pop_time);
+		pop_dbg(codec->pop_time, "pop test %s : %s in %d ms\n",
+			widget->name, widget->power ? "on" : "off",
+			codec->pop_time);
 		snd_soc_write(codec, widget->reg, new);
-		pop_wait();
+		pop_wait(codec->pop_time);
 	}
 	pr_debug("reg %x old %x new %x change %d\n", widget->reg,
 		 old, new, change);
@@ -293,7 +289,7 @@
 	struct snd_soc_dapm_widget *w)
 {
 	int i, ret = 0;
-	char name[32];
+	size_t name_len;
 	struct snd_soc_dapm_path *path;
 
 	/* add kcontrol */
@@ -307,11 +303,16 @@
 				continue;
 
 			/* add dapm control with long name */
-			snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name);
-			path->long_name = kstrdup (name, GFP_KERNEL);
+			name_len = 2 + strlen(w->name)
+				+ strlen(w->kcontrols[i].name);
+			path->long_name = kmalloc(name_len, GFP_KERNEL);
 			if (path->long_name == NULL)
 				return -ENOMEM;
 
+			snprintf(path->long_name, name_len, "%s %s",
+				 w->name, w->kcontrols[i].name);
+			path->long_name[name_len - 1] = '\0';
+
 			path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
 				path->long_name);
 			ret = snd_ctl_add(codec->card, path->kcontrol);
@@ -821,23 +822,9 @@
 
 int snd_soc_dapm_sys_add(struct device *dev)
 {
-	int ret = 0;
-
 	if (!dapm_status)
 		return 0;
-
-	ret = device_create_file(dev, &dev_attr_dapm_widget);
-	if (ret != 0)
-		return ret;
-
-	asoc_debugfs = debugfs_create_dir("asoc", NULL);
-	if (!IS_ERR(asoc_debugfs) && asoc_debugfs)
-		debugfs_create_u32("dapm_pop_time", 0744, asoc_debugfs,
-				   &pop_time);
-	else
-		asoc_debugfs = NULL;
-
-	return 0;
+	return device_create_file(dev, &dev_attr_dapm_widget);
 }
 
 static void snd_soc_dapm_sys_remove(struct device *dev)
@@ -845,9 +832,6 @@
 	if (dapm_status) {
 		device_remove_file(dev, &dev_attr_dapm_widget);
 	}
-
-	if (asoc_debugfs)
-		debugfs_remove_recursive(asoc_debugfs);
 }
 
 /* free all dapm widgets and resources */
@@ -1007,28 +991,6 @@
 }
 
 /**
- * snd_soc_dapm_connect_input - connect dapm widgets
- * @codec: audio codec
- * @sink: name of target widget
- * @control: mixer control name
- * @source: name of source name
- *
- * Connects 2 dapm widgets together via a named audio path. The sink is
- * the widget receiving the audio signal, whilst the source is the sender
- * of the audio signal.
- *
- * This function has been deprecated in favour of snd_soc_dapm_add_routes().
- *
- * Returns 0 for success else error.
- */
-int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
-	const char *control, const char *source)
-{
-	return snd_soc_dapm_add_route(codec, sink, control, source);
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input);
-
-/**
  * snd_soc_dapm_add_routes - Add routes between DAPM widgets
  * @codec: codec
  * @route: audio routes
@@ -1358,8 +1320,12 @@
 
 	for (i = 0; i < num; i++) {
 		ret = snd_soc_dapm_new_control(codec, widget);
-		if (ret < 0)
+		if (ret < 0) {
+			printk(KERN_ERR
+			       "ASoC: Failed to create DAPM control %s: %d\n",
+			       widget->name, ret);
 			return ret;
+		}
 		widget++;
 	}
 	return 0;
@@ -1440,11 +1406,11 @@
 				enum snd_soc_bias_level level)
 {
 	struct snd_soc_codec *codec = socdev->codec;
-	struct snd_soc_machine *machine = socdev->machine;
+	struct snd_soc_card *card = socdev->card;
 	int ret = 0;
 
-	if (machine->set_bias_level)
-		ret = machine->set_bias_level(machine, level);
+	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);
 
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 10ba421..2b302bb 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/err.h>
+#include <sound/core.h>
 
 #ifdef CONFIG_SOUND_OSS_CORE
 static int __init init_oss_soundcore(void);
diff --git a/sound/usb/caiaq/caiaq-control.c b/sound/usb/caiaq/caiaq-control.c
index 798ca12..ccd763d 100644
--- a/sound/usb/caiaq/caiaq-control.c
+++ b/sound/usb/caiaq/caiaq-control.c
@@ -247,69 +247,56 @@
 	{ "Software lock", 			40 		}
 };
 
+static int __devinit add_controls(struct caiaq_controller *c, int num,
+				  struct snd_usb_caiaqdev *dev)
+{
+	int i, ret;
+	struct snd_kcontrol *kc;
+
+	for (i = 0; i < num; i++, c++) {
+		kcontrol_template.name = c->name;
+		kcontrol_template.private_value = c->index;
+		kc = snd_ctl_new1(&kcontrol_template, dev);
+		ret = snd_ctl_add(dev->chip.card, kc);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
 int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
 {
-	int i;
-	struct snd_kcontrol *kc;
+	int ret = 0;
 
 	switch (dev->chip.usb_id) {
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
-		for (i = 0; i < ARRAY_SIZE(ak1_controller); i++) {
-			struct caiaq_controller *c = ak1_controller + i;
-			kcontrol_template.name = c->name;
-			kcontrol_template.private_value = c->index;
-			kc = snd_ctl_new1(&kcontrol_template, dev);
-			snd_ctl_add(dev->chip.card, kc);
-		}
-
+		ret = add_controls(ak1_controller,
+			ARRAY_SIZE(ak1_controller), dev);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
-		for (i = 0; i < ARRAY_SIZE(rk2_controller); i++) {
-			struct caiaq_controller *c = rk2_controller + i;
-			kcontrol_template.name = c->name;
-			kcontrol_template.private_value = c->index;
-			kc = snd_ctl_new1(&kcontrol_template, dev);
-			snd_ctl_add(dev->chip.card, kc);
-		}
-
+		ret = add_controls(rk2_controller,
+			ARRAY_SIZE(rk2_controller), dev);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
-		for (i = 0; i < ARRAY_SIZE(rk3_controller); i++) {
-			struct caiaq_controller *c = rk3_controller + i;
-			kcontrol_template.name = c->name;
-			kcontrol_template.private_value = c->index;
-			kc = snd_ctl_new1(&kcontrol_template, dev);
-			snd_ctl_add(dev->chip.card, kc);
-		}
-
+		ret = add_controls(rk3_controller,
+			ARRAY_SIZE(rk3_controller), dev);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
-		for (i = 0; i < ARRAY_SIZE(kore_controller); i++) {
-			struct caiaq_controller *c = kore_controller + i;
-			kcontrol_template.name = c->name;
-			kcontrol_template.private_value = c->index;
-			kc = snd_ctl_new1(&kcontrol_template, dev);
-			snd_ctl_add(dev->chip.card, kc);
-		}
-
+		ret = add_controls(kore_controller,
+			ARRAY_SIZE(kore_controller), dev);
 		break;
 
 	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
-		for (i = 0; i < ARRAY_SIZE(a8dj_controller); i++) {
-			struct caiaq_controller *c = a8dj_controller + i;
-			kcontrol_template.name = c->name;
-			kcontrol_template.private_value = c->index;
-			kc = snd_ctl_new1(&kcontrol_template, dev);
-			snd_ctl_add(dev->chip.card, kc);
-		}
-
+		ret = add_controls(a8dj_controller,
+			ARRAY_SIZE(a8dj_controller), dev);
 		break;
 	}
 
-	return 0;
+	return ret;
 }
 
diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c
index 8317508..b143ef7 100644
--- a/sound/usb/caiaq/caiaq-device.c
+++ b/sound/usb/caiaq/caiaq-device.c
@@ -42,7 +42,7 @@
 #endif
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.8");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.9");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
 			 "{Native Instruments, RigKontrol3},"
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index 5962e4b..6d9f9b1 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -880,7 +880,7 @@
 				snd_rawmidi_transmit_ack(substream, 1);
 			return;
 		}
-		tasklet_hi_schedule(&port->ep->tasklet);
+		tasklet_schedule(&port->ep->tasklet);
 	}
 }
 
diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c
index ff23cc1..70b9635 100644
--- a/sound/usb/usx2y/usb_stream.c
+++ b/sound/usb/usx2y/usb_stream.c
@@ -276,7 +276,8 @@
 	}
 }
 
-int usb_stream_prepare_playback(struct usb_stream_kernel *sk, struct urb *inurb)
+static int usb_stream_prepare_playback(struct usb_stream_kernel *sk,
+		struct urb *inurb)
 {
 	struct usb_stream *s = sk->s;
 	struct urb *io;
diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c
index 7abc07f..f1d3fe3 100644
--- a/usr/gen_init_cpio.c
+++ b/usr/gen_init_cpio.c
@@ -370,6 +370,30 @@
 	return rc;
 }
 
+static char *cpio_replace_env(char *new_location)
+{
+       char expanded[PATH_MAX + 1];
+       char env_var[PATH_MAX + 1];
+       char *start;
+       char *end;
+
+       for (start = NULL; (start = strstr(new_location, "${")); ) {
+               end = strchr(start, '}');
+               if (start < end) {
+                       *env_var = *expanded = '\0';
+                       strncat(env_var, start + 2, end - start - 2);
+                       strncat(expanded, new_location, start - new_location);
+                       strncat(expanded, getenv(env_var), PATH_MAX);
+                       strncat(expanded, end + 1, PATH_MAX);
+                       strncpy(new_location, expanded, PATH_MAX);
+               } else
+                       break;
+       }
+
+       return new_location;
+}
+
+
 static int cpio_mkfile_line(const char *line)
 {
 	char name[PATH_MAX + 1];
@@ -415,7 +439,8 @@
 	} else {
 		dname = name;
 	}
-	rc = cpio_mkfile(dname, location, mode, uid, gid, nlinks);
+	rc = cpio_mkfile(dname, cpio_replace_env(location),
+	                 mode, uid, gid, nlinks);
  fail:
 	if (dname_len) free(dname);
 	return rc;
@@ -439,6 +464,7 @@
 		"\n"
 		"<name>       name of the file/dir/nod/etc in the archive\n"
 		"<location>   location of the file in the current filesystem\n"
+		"             expands shell variables quoted with ${}\n"
 		"<target>     link target\n"
 		"<mode>       mode/permissions of the file\n"
 		"<uid>        user id (0=root)\n"